diff --git a/CLOBBER b/CLOBBER index f9f115aed883..11705caa5fab 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,4 +22,4 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 1356927 - Mac builds in automation require a clobber for a change in which ranlib they use +Bug 1340627 - clobber for Skia update diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla index 64e4d65f898b..330768bfb7b0 100644 --- a/browser/extensions/pdfjs/README.mozilla +++ b/browser/extensions/pdfjs/README.mozilla @@ -1,5 +1,5 @@ This is the PDF.js project output, https://github.com/mozilla/pdf.js -Current extension version is: 1.8.331 +Current extension version is: 1.8.346 -Taken from upstream commit: 0dbc68a6 +Taken from upstream commit: 15425d5b diff --git a/browser/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js index 61b5d486475f..6deb9c8591de 100644 --- a/browser/extensions/pdfjs/content/build/pdf.js +++ b/browser/extensions/pdfjs/content/build/pdf.js @@ -101,12 +101,17 @@ return /******/ (function(modules) { // webpackBootstrap Object.defineProperty(exports, "__esModule", { value: true }); -exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isInt = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.isArray = exports.info = exports.globalScope = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.error = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.StatTimer = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; +exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isInt = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.isArray = exports.info = exports.globalScope = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.error = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.StatTimer = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; __w_pdfjs_require__(14); var globalScope = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : undefined; var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; +const NativeImageDecoding = { + NONE: 'none', + DECODE: 'decode', + DISPLAY: 'display' +}; var TextRenderingMode = { FILL: 0, STROKE: 1, @@ -1125,6 +1130,7 @@ exports.InvalidPDFException = InvalidPDFException; exports.MessageHandler = MessageHandler; exports.MissingDataException = MissingDataException; exports.MissingPDFException = MissingPDFException; +exports.NativeImageDecoding = NativeImageDecoding; exports.NotImplementedException = NotImplementedException; exports.PageViewport = PageViewport; exports.PasswordException = PasswordException; @@ -2170,9 +2176,16 @@ function getDocument(src, pdfDataRangeTransport, passwordCallback, progressCallb params[key] = source[key]; } params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE; - params.disableNativeImageDecoder = params.disableNativeImageDecoder === true; params.ignoreErrors = params.stopAtErrors !== true; var CMapReaderFactory = params.CMapReaderFactory || _dom_utils.DOMCMapReaderFactory; + if (params.disableNativeImageDecoder !== undefined) { + (0, _util.deprecated)('parameter disableNativeImageDecoder, ' + 'use nativeImageDecoderSupport instead'); + } + params.nativeImageDecoderSupport = params.nativeImageDecoderSupport || (params.disableNativeImageDecoder === true ? _util.NativeImageDecoding.NONE : _util.NativeImageDecoding.DECODE); + if (params.nativeImageDecoderSupport !== _util.NativeImageDecoding.DECODE && params.nativeImageDecoderSupport !== _util.NativeImageDecoding.NONE && params.nativeImageDecoderSupport !== _util.NativeImageDecoding.DISPLAY) { + (0, _util.warn)('Invalid parameter nativeImageDecoderSupport: ' + 'need a state of enum {NativeImageDecoding}'); + params.nativeImageDecoderSupport = _util.NativeImageDecoding.DECODE; + } if (!worker) { var workerPort = (0, _dom_utils.getDefaultSetting)('workerPort'); worker = workerPort ? new PDFWorker(null, workerPort) : new PDFWorker(); @@ -2215,7 +2228,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { disableCreateObjectURL: (0, _dom_utils.getDefaultSetting)('disableCreateObjectURL'), postMessageTransfers: (0, _dom_utils.getDefaultSetting)('postMessageTransfers') && !isPostMessageTransfersDisabled, docBaseUrl: source.docBaseUrl, - disableNativeImageDecoder: source.disableNativeImageDecoder, + nativeImageDecoderSupport: source.nativeImageDecoderSupport, ignoreErrors: source.ignoreErrors }).then(function (workerId) { if (worker.destroyed) { @@ -3392,8 +3405,8 @@ var _UnsupportedManager = function UnsupportedManagerClosure() { }(); var version, build; { - exports.version = version = '1.8.331'; - exports.build = build = '0dbc68a6'; + exports.version = version = '1.8.346'; + exports.build = build = '15425d5b'; } exports.getDocument = getDocument; exports.LoopbackPort = LoopbackPort; @@ -4395,8 +4408,8 @@ if (!_util.globalScope.PDFJS) { } var PDFJS = _util.globalScope.PDFJS; { - PDFJS.version = '1.8.331'; - PDFJS.build = '0dbc68a6'; + PDFJS.version = '1.8.346'; + PDFJS.build = '15425d5b'; } PDFJS.pdfBug = false; if (PDFJS.verbosity !== undefined) { @@ -6710,8 +6723,8 @@ exports.TilingPattern = TilingPattern; "use strict"; -var pdfjsVersion = '1.8.331'; -var pdfjsBuild = '0dbc68a6'; +var pdfjsVersion = '1.8.346'; +var pdfjsBuild = '15425d5b'; var pdfjsSharedUtil = __w_pdfjs_require__(0); var pdfjsDisplayGlobal = __w_pdfjs_require__(8); var pdfjsDisplayAPI = __w_pdfjs_require__(3); @@ -6734,6 +6747,7 @@ exports.PasswordResponses = pdfjsSharedUtil.PasswordResponses; exports.InvalidPDFException = pdfjsSharedUtil.InvalidPDFException; exports.MissingPDFException = pdfjsSharedUtil.MissingPDFException; exports.SVGGraphics = pdfjsDisplaySVG.SVGGraphics; +exports.NativeImageDecoding = pdfjsSharedUtil.NativeImageDecoding; exports.UnexpectedResponseException = pdfjsSharedUtil.UnexpectedResponseException; exports.OPS = pdfjsSharedUtil.OPS; exports.UNSUPPORTED_FEATURES = pdfjsSharedUtil.UNSUPPORTED_FEATURES; diff --git a/browser/extensions/pdfjs/content/build/pdf.worker.js b/browser/extensions/pdfjs/content/build/pdf.worker.js index a4277642a438..b91d11f24b44 100644 --- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -101,12 +101,17 @@ return /******/ (function(modules) { // webpackBootstrap Object.defineProperty(exports, "__esModule", { value: true }); -exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isInt = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.isArray = exports.info = exports.globalScope = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.error = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.StatTimer = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; +exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isInt = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.isArray = exports.info = exports.globalScope = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.error = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.StatTimer = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; __w_pdfjs_require__(36); var globalScope = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : undefined; var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; +const NativeImageDecoding = { + NONE: 'none', + DECODE: 'decode', + DISPLAY: 'display' +}; var TextRenderingMode = { FILL: 0, STROKE: 1, @@ -1125,6 +1130,7 @@ exports.InvalidPDFException = InvalidPDFException; exports.MessageHandler = MessageHandler; exports.MissingDataException = MissingDataException; exports.MissingPDFException = MissingPDFException; +exports.NativeImageDecoding = NativeImageDecoding; exports.NotImplementedException = NotImplementedException; exports.PageViewport = PageViewport; exports.PasswordException = PasswordException; @@ -16390,6 +16396,7 @@ var IDENTITY_MATRIX = sharedUtil.IDENTITY_MATRIX; var UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES; var ImageKind = sharedUtil.ImageKind; var OPS = sharedUtil.OPS; +var NativeImageDecoding = sharedUtil.NativeImageDecoding; var TextRenderingMode = sharedUtil.TextRenderingMode; var CMapCompressionType = sharedUtil.CMapCompressionType; var Util = sharedUtil.Util; @@ -16450,7 +16457,7 @@ var PartialEvaluator = function PartialEvaluatorClosure() { forceDataSchema: false, maxImageSize: -1, disableFontFace: false, - disableNativeImageDecoder: false, + nativeImageDecoderSupport: NativeImageDecoding.DECODE, ignoreErrors: false }; function NativeImageDecoder(xref, resources, handler, forceDataSchema) { @@ -16724,17 +16731,17 @@ var PartialEvaluator = function PartialEvaluatorClosure() { operatorList.addOp(OPS.paintInlineImageXObject, [imgData]); return; } - var useNativeImageDecoder = !this.options.disableNativeImageDecoder; + var nativeImageDecoderSupport = this.options.nativeImageDecoderSupport; var objId = 'img_' + this.idFactory.createObjId(); operatorList.addDependency(objId); args = [objId, w, h]; - if (useNativeImageDecoder && !softMask && !mask && image instanceof JpegStream && NativeImageDecoder.isSupported(image, this.xref, resources)) { + if (nativeImageDecoderSupport !== NativeImageDecoding.NONE && !softMask && !mask && image instanceof JpegStream && NativeImageDecoder.isSupported(image, this.xref, resources)) { operatorList.addOp(OPS.paintJpegXObject, args); this.handler.send('obj', [objId, this.pageIndex, 'JpegStream', image.getIR(this.options.forceDataSchema)]); return; } var nativeImageDecoder = null; - if (useNativeImageDecoder && (image instanceof JpegStream || mask instanceof JpegStream || softMask instanceof JpegStream)) { + if (nativeImageDecoderSupport === NativeImageDecoding.DECODE && (image instanceof JpegStream || mask instanceof JpegStream || softMask instanceof JpegStream)) { nativeImageDecoder = new NativeImageDecoder(this.xref, resources, this.handler, this.options.forceDataSchema); } PDFImage.buildImage(this.handler, this.xref, resources, image, inline, nativeImageDecoder).then(imageObj => { @@ -23864,7 +23871,7 @@ var WorkerMessageHandler = { forceDataSchema: data.disableCreateObjectURL, maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize, disableFontFace: data.disableFontFace, - disableNativeImageDecoder: data.disableNativeImageDecoder, + nativeImageDecoderSupport: data.nativeImageDecoderSupport, ignoreErrors: data.ignoreErrors }; getPdfManager(data, evaluatorOptions).then(function (newPdfManager) { @@ -36632,8 +36639,8 @@ exports.Type1Parser = Type1Parser; "use strict"; -var pdfjsVersion = '1.8.331'; -var pdfjsBuild = '0dbc68a6'; +var pdfjsVersion = '1.8.346'; +var pdfjsBuild = '15425d5b'; var pdfjsCoreWorker = __w_pdfjs_require__(17); ; exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler; diff --git a/browser/extensions/pdfjs/content/web/viewer.js b/browser/extensions/pdfjs/content/web/viewer.js index c11d4f510d4f..a2e3fdc57e17 100644 --- a/browser/extensions/pdfjs/content/web/viewer.js +++ b/browser/extensions/pdfjs/content/web/viewer.js @@ -951,104 +951,103 @@ var PDFViewerApplication = { })]).catch(function (reason) {}); }, _initializeViewerComponents() { - var self = this; - var appConfig = this.appConfig; + let appConfig = this.appConfig; return new Promise((resolve, reject) => { - var eventBus = appConfig.eventBus || (0, _dom_events.getGlobalEventBus)(); + let eventBus = appConfig.eventBus || (0, _dom_events.getGlobalEventBus)(); this.eventBus = eventBus; - var pdfRenderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); - pdfRenderingQueue.onIdle = self.cleanup.bind(self); - self.pdfRenderingQueue = pdfRenderingQueue; - var pdfLinkService = new _pdf_link_service.PDFLinkService({ eventBus }); - self.pdfLinkService = pdfLinkService; - var downloadManager = self.externalServices.createDownloadManager(); - self.downloadManager = downloadManager; - var container = appConfig.mainContainer; - var viewer = appConfig.viewerContainer; - self.pdfViewer = new _pdf_viewer.PDFViewer({ + let pdfRenderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); + pdfRenderingQueue.onIdle = this.cleanup.bind(this); + this.pdfRenderingQueue = pdfRenderingQueue; + let pdfLinkService = new _pdf_link_service.PDFLinkService({ eventBus }); + this.pdfLinkService = pdfLinkService; + let downloadManager = this.externalServices.createDownloadManager(); + this.downloadManager = downloadManager; + let container = appConfig.mainContainer; + let viewer = appConfig.viewerContainer; + this.pdfViewer = new _pdf_viewer.PDFViewer({ container, viewer, eventBus, renderingQueue: pdfRenderingQueue, linkService: pdfLinkService, downloadManager, - renderer: self.viewerPrefs['renderer'], - enhanceTextSelection: self.viewerPrefs['enhanceTextSelection'], - renderInteractiveForms: self.viewerPrefs['renderInteractiveForms'], - enablePrintAutoRotate: self.viewerPrefs['enablePrintAutoRotate'] + renderer: this.viewerPrefs['renderer'], + enhanceTextSelection: this.viewerPrefs['enhanceTextSelection'], + renderInteractiveForms: this.viewerPrefs['renderInteractiveForms'], + enablePrintAutoRotate: this.viewerPrefs['enablePrintAutoRotate'] }); - pdfRenderingQueue.setViewer(self.pdfViewer); - pdfLinkService.setViewer(self.pdfViewer); - var thumbnailContainer = appConfig.sidebar.thumbnailView; - self.pdfThumbnailViewer = new _pdf_thumbnail_viewer.PDFThumbnailViewer({ + pdfRenderingQueue.setViewer(this.pdfViewer); + pdfLinkService.setViewer(this.pdfViewer); + let thumbnailContainer = appConfig.sidebar.thumbnailView; + this.pdfThumbnailViewer = new _pdf_thumbnail_viewer.PDFThumbnailViewer({ container: thumbnailContainer, renderingQueue: pdfRenderingQueue, linkService: pdfLinkService }); - pdfRenderingQueue.setThumbnailViewer(self.pdfThumbnailViewer); - self.pdfHistory = new _pdf_history.PDFHistory({ + pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer); + this.pdfHistory = new _pdf_history.PDFHistory({ linkService: pdfLinkService, eventBus }); - pdfLinkService.setHistory(self.pdfHistory); - self.findController = new _pdf_find_controller.PDFFindController({ pdfViewer: self.pdfViewer }); - self.findController.onUpdateResultsCount = function (matchCount) { - if (self.supportsIntegratedFind) { + pdfLinkService.setHistory(this.pdfHistory); + this.findController = new _pdf_find_controller.PDFFindController({ pdfViewer: this.pdfViewer }); + this.findController.onUpdateResultsCount = matchCount => { + if (this.supportsIntegratedFind) { return; } - self.findBar.updateResultsCount(matchCount); + this.findBar.updateResultsCount(matchCount); }; - self.findController.onUpdateState = function (state, previous, matchCount) { - if (self.supportsIntegratedFind) { - self.externalServices.updateFindControlState({ + this.findController.onUpdateState = (state, previous, matchCount) => { + if (this.supportsIntegratedFind) { + this.externalServices.updateFindControlState({ result: state, findPrevious: previous }); } else { - self.findBar.updateUIState(state, previous, matchCount); + this.findBar.updateUIState(state, previous, matchCount); } }; - self.pdfViewer.setFindController(self.findController); - var findBarConfig = Object.create(appConfig.findBar); - findBarConfig.findController = self.findController; + this.pdfViewer.setFindController(this.findController); + let findBarConfig = Object.create(appConfig.findBar); + findBarConfig.findController = this.findController; findBarConfig.eventBus = eventBus; - self.findBar = new _pdf_find_bar.PDFFindBar(findBarConfig); - self.overlayManager = _overlay_manager.OverlayManager; - self.handTool = new _hand_tool.HandTool({ + this.findBar = new _pdf_find_bar.PDFFindBar(findBarConfig); + this.overlayManager = _overlay_manager.OverlayManager; + this.handTool = new _hand_tool.HandTool({ container, eventBus, preferences: this.preferences }); - self.pdfDocumentProperties = new _pdf_document_properties.PDFDocumentProperties(appConfig.documentProperties); - self.toolbar = new _toolbar.Toolbar(appConfig.toolbar, container, eventBus); - self.secondaryToolbar = new _secondary_toolbar.SecondaryToolbar(appConfig.secondaryToolbar, container, eventBus); - if (self.supportsFullscreen) { - self.pdfPresentationMode = new _pdf_presentation_mode.PDFPresentationMode({ + this.pdfDocumentProperties = new _pdf_document_properties.PDFDocumentProperties(appConfig.documentProperties); + this.toolbar = new _toolbar.Toolbar(appConfig.toolbar, container, eventBus); + this.secondaryToolbar = new _secondary_toolbar.SecondaryToolbar(appConfig.secondaryToolbar, container, eventBus); + if (this.supportsFullscreen) { + this.pdfPresentationMode = new _pdf_presentation_mode.PDFPresentationMode({ container, viewer, - pdfViewer: self.pdfViewer, + pdfViewer: this.pdfViewer, eventBus, contextMenuItems: appConfig.fullscreen }); } - self.passwordPrompt = new _password_prompt.PasswordPrompt(appConfig.passwordOverlay); - self.pdfOutlineViewer = new _pdf_outline_viewer.PDFOutlineViewer({ + this.passwordPrompt = new _password_prompt.PasswordPrompt(appConfig.passwordOverlay); + this.pdfOutlineViewer = new _pdf_outline_viewer.PDFOutlineViewer({ container: appConfig.sidebar.outlineView, eventBus, linkService: pdfLinkService }); - self.pdfAttachmentViewer = new _pdf_attachment_viewer.PDFAttachmentViewer({ + this.pdfAttachmentViewer = new _pdf_attachment_viewer.PDFAttachmentViewer({ container: appConfig.sidebar.attachmentsView, eventBus, downloadManager }); - var sidebarConfig = Object.create(appConfig.sidebar); - sidebarConfig.pdfViewer = self.pdfViewer; - sidebarConfig.pdfThumbnailViewer = self.pdfThumbnailViewer; - sidebarConfig.pdfOutlineViewer = self.pdfOutlineViewer; + let sidebarConfig = Object.create(appConfig.sidebar); + sidebarConfig.pdfViewer = this.pdfViewer; + sidebarConfig.pdfThumbnailViewer = this.pdfThumbnailViewer; + sidebarConfig.pdfOutlineViewer = this.pdfOutlineViewer; sidebarConfig.eventBus = eventBus; - self.pdfSidebar = new _pdf_sidebar.PDFSidebar(sidebarConfig); - self.pdfSidebar.onToggled = self.forceRendering.bind(self); + this.pdfSidebar = new _pdf_sidebar.PDFSidebar(sidebarConfig); + this.pdfSidebar.onToggled = this.forceRendering.bind(this); resolve(undefined); }); }, @@ -1193,14 +1192,14 @@ var PDFViewerApplication = { } return promise; }, - open: function pdfViewOpen(file, args) { + open(file, args) { if (this.pdfLoadingTask) { return this.close().then(() => { this.preferences.reload(); return this.open(file, args); }); } - var parameters = Object.create(null), + let parameters = Object.create(null), scale; if (typeof file === 'string') { this.setTitleUsingUrl(file); @@ -1213,7 +1212,7 @@ var PDFViewerApplication = { } parameters.docBaseUrl = this.baseUrl; if (args) { - for (var prop in args) { + for (let prop in args) { parameters[prop] = args[prop]; } if (args.scale) { @@ -1223,23 +1222,22 @@ var PDFViewerApplication = { this.pdfDocumentProperties.setFileSize(args.length); } } - var self = this; - self.downloadComplete = false; - var loadingTask = (0, _pdfjs.getDocument)(parameters); + this.downloadComplete = false; + let loadingTask = (0, _pdfjs.getDocument)(parameters); this.pdfLoadingTask = loadingTask; - loadingTask.onPassword = function passwordNeeded(updateCallback, reason) { - self.passwordPrompt.setUpdateCallback(updateCallback, reason); - self.passwordPrompt.open(); + loadingTask.onPassword = (updateCallback, reason) => { + this.passwordPrompt.setUpdateCallback(updateCallback, reason); + this.passwordPrompt.open(); }; - loadingTask.onProgress = function getDocumentProgress(progressData) { - self.progress(progressData.loaded / progressData.total); + loadingTask.onProgress = ({ loaded, total }) => { + this.progress(loaded / total); }; loadingTask.onUnsupportedFeature = this.fallback.bind(this); - return loadingTask.promise.then(function getDocumentCallback(pdfDocument) { - self.load(pdfDocument, scale); - }, function getDocumentError(exception) { - var message = exception && exception.message; - var loadingErrorMessage = _ui_utils.mozL10n.get('loading_error', null, 'An error occurred while loading the PDF.'); + return loadingTask.promise.then(pdfDocument => { + this.load(pdfDocument, scale); + }, exception => { + let message = exception && exception.message; + let loadingErrorMessage = _ui_utils.mozL10n.get('loading_error', null, 'An error occurred while loading the PDF.'); if (exception instanceof _pdfjs.InvalidPDFException) { loadingErrorMessage = _ui_utils.mozL10n.get('invalid_file_error', null, 'Invalid or corrupted PDF file.'); } else if (exception instanceof _pdfjs.MissingPDFException) { @@ -1247,8 +1245,7 @@ var PDFViewerApplication = { } else if (exception instanceof _pdfjs.UnexpectedResponseException) { loadingErrorMessage = _ui_utils.mozL10n.get('unexpected_response_error', null, 'Unexpected server response.'); } - var moreInfo = { message }; - self.error(loadingErrorMessage, moreInfo); + this.error(loadingErrorMessage, { message }); throw new Error(loadingErrorMessage); }); }, @@ -1328,54 +1325,53 @@ var PDFViewerApplication = { } } }, - load: function pdfViewLoad(pdfDocument, scale) { - var self = this; + load(pdfDocument, scale) { scale = scale || _ui_utils.UNKNOWN_SCALE; this.pdfDocument = pdfDocument; - var downloadedPromise = pdfDocument.getDownloadInfo().then(function () { - self.downloadComplete = true; - self.loadingBar.hide(); + pdfDocument.getDownloadInfo().then(() => { + this.downloadComplete = true; + this.loadingBar.hide(); + firstPagePromise.then(() => { + this.eventBus.dispatch('documentload', { source: this }); + }); }); this.toolbar.setPagesCount(pdfDocument.numPages, false); this.secondaryToolbar.setPagesCount(pdfDocument.numPages); - var id = this.documentFingerprint = pdfDocument.fingerprint; - var store = this.store = new _view_history.ViewHistory(id); - var baseDocumentUrl; + let id = this.documentFingerprint = pdfDocument.fingerprint; + let store = this.store = new _view_history.ViewHistory(id); + let baseDocumentUrl; baseDocumentUrl = this.baseUrl; this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl); this.pdfDocumentProperties.setDocument(pdfDocument, this.url); - var pdfViewer = this.pdfViewer; + let pdfViewer = this.pdfViewer; pdfViewer.currentScale = scale; pdfViewer.setDocument(pdfDocument); - var firstPagePromise = pdfViewer.firstPagePromise; - var pagesPromise = pdfViewer.pagesPromise; - var onePageRendered = pdfViewer.onePageRendered; + let firstPagePromise = pdfViewer.firstPagePromise; + let pagesPromise = pdfViewer.pagesPromise; + let onePageRendered = pdfViewer.onePageRendered; this.pageRotation = 0; - var pdfThumbnailViewer = this.pdfThumbnailViewer; + let pdfThumbnailViewer = this.pdfThumbnailViewer; pdfThumbnailViewer.setDocument(pdfDocument); firstPagePromise.then(pdfPage => { - downloadedPromise.then(function () { - self.eventBus.dispatch('documentload', { source: self }); - }); - self.loadingBar.setWidth(self.appConfig.viewerContainer); - if (!_pdfjs.PDFJS.disableHistory && !self.isViewerEmbedded) { - if (!self.viewerPrefs['showPreviousViewOnLoad']) { - self.pdfHistory.clearHistoryState(); + this.loadingBar.setWidth(this.appConfig.viewerContainer); + if (!_pdfjs.PDFJS.disableHistory && !this.isViewerEmbedded) { + if (!this.viewerPrefs['showPreviousViewOnLoad']) { + this.pdfHistory.clearHistoryState(); } - self.pdfHistory.initialize(self.documentFingerprint); - if (self.pdfHistory.initialDestination) { - self.initialDestination = self.pdfHistory.initialDestination; - } else if (self.pdfHistory.initialBookmark) { - self.initialBookmark = self.pdfHistory.initialBookmark; + this.pdfHistory.initialize(this.documentFingerprint); + if (this.pdfHistory.initialDestination) { + this.initialDestination = this.pdfHistory.initialDestination; + } else if (this.pdfHistory.initialBookmark) { + this.initialBookmark = this.pdfHistory.initialBookmark; } } - var initialParams = { + let initialParams = { destination: this.initialDestination, bookmark: this.initialBookmark, hash: null }; - var storedHash = this.viewerPrefs['defaultZoomValue'] ? 'zoom=' + this.viewerPrefs['defaultZoomValue'] : null; - var sidebarView = this.viewerPrefs['sidebarViewOnLoad']; + let storedHash = this.viewerPrefs['defaultZoomValue'] ? 'zoom=' + this.viewerPrefs['defaultZoomValue'] : null; + let sidebarView = this.viewerPrefs['sidebarViewOnLoad']; new Promise((resolve, reject) => { if (!this.viewerPrefs['showPreviousViewOnLoad']) { resolve(); @@ -1422,13 +1418,13 @@ var PDFViewerApplication = { this.setInitialView(initialParams.hash); }); }); - pdfDocument.getPageLabels().then(function (labels) { - if (!labels || self.viewerPrefs['disablePageLabels']) { + pdfDocument.getPageLabels().then(labels => { + if (!labels || this.viewerPrefs['disablePageLabels']) { return; } - var i = 0, + let i = 0, numLabels = labels.length; - if (numLabels !== self.pagesCount) { + if (numLabels !== this.pagesCount) { console.error('The number of Page Labels does not match ' + 'the number of pages in the document.'); return; } @@ -1440,46 +1436,45 @@ var PDFViewerApplication = { } pdfViewer.setPageLabels(labels); pdfThumbnailViewer.setPageLabels(labels); - self.toolbar.setPagesCount(pdfDocument.numPages, true); - self.toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); + this.toolbar.setPagesCount(pdfDocument.numPages, true); + this.toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); }); - pagesPromise.then(function () { - if (self.supportsPrinting) { - pdfDocument.getJavaScript().then(function (javaScript) { - if (javaScript.length) { - console.warn('Warning: JavaScript is not supported'); - self.fallback(_pdfjs.UNSUPPORTED_FEATURES.javaScript); - } - var regex = /\bprint\s*\(/; - for (var i = 0, ii = javaScript.length; i < ii; i++) { - var js = javaScript[i]; - if (js && regex.test(js)) { - setTimeout(function () { - window.print(); - }); - return; - } - } - }); + pagesPromise.then(() => { + if (!this.supportsPrinting) { + return; } - }); - Promise.all([onePageRendered, _ui_utils.animationStarted]).then(function () { - pdfDocument.getOutline().then(function (outline) { - self.pdfOutlineViewer.render({ outline }); - }); - pdfDocument.getAttachments().then(function (attachments) { - self.pdfAttachmentViewer.render({ attachments }); + pdfDocument.getJavaScript().then(javaScript => { + if (javaScript.length) { + console.warn('Warning: JavaScript is not supported'); + this.fallback(_pdfjs.UNSUPPORTED_FEATURES.javaScript); + } + let regex = /\bprint\s*\(/; + for (let i = 0, ii = javaScript.length; i < ii; i++) { + let js = javaScript[i]; + if (js && regex.test(js)) { + setTimeout(function () { + window.print(); + }); + return; + } + } }); }); - pdfDocument.getMetadata().then(function (data) { - var info = data.info, - metadata = data.metadata; - self.documentInfo = info; - self.metadata = metadata; + Promise.all([onePageRendered, _ui_utils.animationStarted]).then(() => { + pdfDocument.getOutline().then(outline => { + this.pdfOutlineViewer.render({ outline }); + }); + pdfDocument.getAttachments().then(attachments => { + this.pdfAttachmentViewer.render({ attachments }); + }); + }); + pdfDocument.getMetadata().then(({ info, metadata }) => { + this.documentInfo = info; + this.metadata = metadata; console.log('PDF ' + pdfDocument.fingerprint + ' [' + info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() + ' / ' + (info.Creator || '-').trim() + ']' + ' (PDF.js: ' + (_pdfjs.version || '-') + (!_pdfjs.PDFJS.disableWebGL ? ' [WebGL]' : '') + ')'); - var pdfTitle; + let pdfTitle; if (metadata && metadata.has('dc:title')) { - var title = metadata.get('dc:title'); + let title = metadata.get('dc:title'); if (title !== 'Untitled') { pdfTitle = title; } @@ -1488,15 +1483,15 @@ var PDFViewerApplication = { pdfTitle = info['Title']; } if (pdfTitle) { - self.setTitle(pdfTitle + ' - ' + document.title); + this.setTitle(pdfTitle + ' - ' + document.title); } if (info.IsAcroFormPresent) { console.warn('Warning: AcroForm/XFA is not supported'); - self.fallback(_pdfjs.UNSUPPORTED_FEATURES.forms); + this.fallback(_pdfjs.UNSUPPORTED_FEATURES.forms); } - var versionId = String(info.PDFFormatVersion).slice(-1) | 0; - var generatorId = 0; - var KNOWN_GENERATORS = ['acrobat distiller', 'acrobat pdfwriter', 'adobe livecycle', 'adobe pdf library', 'adobe photoshop', 'ghostscript', 'tcpdf', 'cairo', 'dvipdfm', 'dvips', 'pdftex', 'pdfkit', 'itext', 'prince', 'quarkxpress', 'mac os x', 'microsoft', 'openoffice', 'oracle', 'luradocument', 'pdf-xchange', 'antenna house', 'aspose.cells', 'fpdf']; + let versionId = String(info.PDFFormatVersion).slice(-1) | 0; + let generatorId = 0; + const KNOWN_GENERATORS = ['acrobat distiller', 'acrobat pdfwriter', 'adobe livecycle', 'adobe pdf library', 'adobe photoshop', 'ghostscript', 'tcpdf', 'cairo', 'dvipdfm', 'dvips', 'pdftex', 'pdfkit', 'itext', 'prince', 'quarkxpress', 'mac os x', 'microsoft', 'openoffice', 'oracle', 'luradocument', 'pdf-xchange', 'antenna house', 'aspose.cells', 'fpdf']; if (info.Producer) { KNOWN_GENERATORS.some(function (generator, s, i) { if (generator.indexOf(s) < 0) { @@ -1506,8 +1501,8 @@ var PDFViewerApplication = { return true; }.bind(null, info.Producer.toLowerCase())); } - var formType = !info.IsAcroFormPresent ? null : info.IsXFAPresent ? 'xfa' : 'acroform'; - self.externalServices.reportTelemetry({ + let formType = !info.IsAcroFormPresent ? null : info.IsXFAPresent ? 'xfa' : 'acroform'; + this.externalServices.reportTelemetry({ type: 'documentInfo', version: versionId, generator: generatorId, @@ -2702,6 +2697,8 @@ Object.defineProperty(exports, "__esModule", { }); exports.PDFFindController = exports.FindStates = undefined; +var _pdfjs = __webpack_require__(1); + var _ui_utils = __webpack_require__(0); var FindStates = { @@ -2870,35 +2867,28 @@ var PDFFindController = function PDFFindControllerClosure() { this.updateUIResultsCount(); } }, - extractText: function PDFFindController_extractText() { + extractText() { if (this.startedTextExtraction) { return; } this.startedTextExtraction = true; - this.pageContents = []; - var extractTextPromisesResolves = []; - var numPages = this.pdfViewer.pagesCount; - for (var i = 0; i < numPages; i++) { - this.extractTextPromises.push(new Promise(function (resolve) { - extractTextPromisesResolves.push(resolve); - })); - } - var self = this; - function extractPageText(pageIndex) { - self.pdfViewer.getPageTextContent(pageIndex).then(function textContentResolved(textContent) { - var textItems = textContent.items; - var str = []; - for (var i = 0, len = textItems.length; i < len; i++) { - str.push(textItems[i].str); - } - self.pageContents.push(str.join('')); - extractTextPromisesResolves[pageIndex](pageIndex); - if (pageIndex + 1 < self.pdfViewer.pagesCount) { - extractPageText(pageIndex + 1); - } + this.pageContents.length = 0; + let promise = Promise.resolve(); + for (let i = 0, ii = this.pdfViewer.pagesCount; i < ii; i++) { + let extractTextCapability = (0, _pdfjs.createPromiseCapability)(); + this.extractTextPromises[i] = extractTextCapability.promise; + promise = promise.then(() => { + return this.pdfViewer.getPageTextContent(i).then(textContent => { + let textItems = textContent.items; + let strBuf = []; + for (let j = 0, jj = textItems.length; j < jj; j++) { + strBuf.push(textItems[j].str); + } + this.pageContents[i] = strBuf.join(''); + extractTextCapability.resolve(i); + }); }); } - extractPageText(0); }, executeCommand: function PDFFindController_executeCommand(cmd, state) { if (this.state === null || cmd !== 'findagain') { @@ -2940,14 +2930,13 @@ var PDFFindController = function PDFFindControllerClosure() { this.pageMatches = []; this.matchCount = 0; this.pageMatchesLength = null; - var self = this; - for (var i = 0; i < numPages; i++) { + for (let i = 0; i < numPages; i++) { this.updatePage(i); if (!(i in this.pendingFindMatches)) { this.pendingFindMatches[i] = true; - this.extractTextPromises[i].then(function (pageIdx) { - delete self.pendingFindMatches[pageIdx]; - self.calcFindMatch(pageIdx); + this.extractTextPromises[i].then(pageIdx => { + delete this.pendingFindMatches[pageIdx]; + this.calcFindMatch(pageIdx); }); } } @@ -3602,11 +3591,10 @@ var _grab_to_pan = __webpack_require__(11); var _ui_utils = __webpack_require__(0); -var HandTool = function HandToolClosure() { - function HandTool(options) { - this.container = options.container; - this.eventBus = options.eventBus; - var preferences = options.preferences; +class HandTool { + constructor({ container, eventBus, preferences }) { + this.container = container; + this.eventBus = eventBus; this.wasActive = false; this.handTool = new _grab_to_pan.GrabToPan({ element: this.container, @@ -3615,11 +3603,12 @@ var HandTool = function HandToolClosure() { } }); this.eventBus.on('togglehandtool', this.toggle.bind(this)); - Promise.all([_ui_utils.localized, preferences.get('enableHandToolOnLoad')]).then(values => { + let enableOnLoad = preferences.get('enableHandToolOnLoad'); + Promise.all([_ui_utils.localized, enableOnLoad]).then(values => { if (values[1] === true) { this.handTool.activate(); } - }).catch(function rejected(reason) {}); + }).catch(function (reason) {}); this.eventBus.on('presentationmodechanged', evt => { if (evt.switchInProgress) { return; @@ -3631,28 +3620,25 @@ var HandTool = function HandToolClosure() { } }); } - HandTool.prototype = { - get isActive() { - return !!this.handTool.active; - }, - toggle: function HandTool_toggle() { - this.handTool.toggle(); - }, - enterPresentationMode: function HandTool_enterPresentationMode() { - if (this.isActive) { - this.wasActive = true; - this.handTool.deactivate(); - } - }, - exitPresentationMode: function HandTool_exitPresentationMode() { - if (this.wasActive) { - this.wasActive = false; - this.handTool.activate(); - } + get isActive() { + return !!this.handTool.active; + } + toggle() { + this.handTool.toggle(); + } + enterPresentationMode() { + if (this.isActive) { + this.wasActive = true; + this.handTool.deactivate(); } - }; - return HandTool; -}(); + } + exitPresentationMode() { + if (this.wasActive) { + this.wasActive = false; + this.handTool.activate(); + } + } +} exports.HandTool = HandTool; /***/ }), @@ -6948,8 +6934,8 @@ exports.SecondaryToolbar = undefined; var _ui_utils = __webpack_require__(0); -var SecondaryToolbar = function SecondaryToolbarClosure() { - function SecondaryToolbar(options, mainContainer, eventBus) { +class SecondaryToolbar { + constructor(options, mainContainer, eventBus) { this.toolbar = options.toolbar; this.toggleButton = options.toggleButton; this.toolbarButtonContainer = options.toolbarButtonContainer; @@ -7014,98 +7000,94 @@ var SecondaryToolbar = function SecondaryToolbarClosure() { this._bindHandToolListener(options.toggleHandToolButton); this.eventBus.on('resize', this._setMaxHeight.bind(this)); } - SecondaryToolbar.prototype = { - get isOpen() { - return this.opened; - }, - setPageNumber: function SecondaryToolbar_setPageNumber(pageNumber) { - this.pageNumber = pageNumber; - this._updateUIState(); - }, - setPagesCount: function SecondaryToolbar_setPagesCount(pagesCount) { - this.pagesCount = pagesCount; - this._updateUIState(); - }, - reset: function SecondaryToolbar_reset() { - this.pageNumber = 0; - this.pagesCount = 0; - this._updateUIState(); - }, - _updateUIState: function SecondaryToolbar_updateUIState() { - var items = this.items; - items.firstPage.disabled = this.pageNumber <= 1; - items.lastPage.disabled = this.pageNumber >= this.pagesCount; - items.pageRotateCw.disabled = this.pagesCount === 0; - items.pageRotateCcw.disabled = this.pagesCount === 0; - }, - _bindClickListeners: function SecondaryToolbar_bindClickListeners() { - this.toggleButton.addEventListener('click', this.toggle.bind(this)); - for (let button in this.buttons) { - let { element, eventName, close } = this.buttons[button]; - element.addEventListener('click', evt => { - if (eventName !== null) { - this.eventBus.dispatch(eventName, { source: this }); - } - if (close) { - this.close(); - } - }); - } - }, - _bindHandToolListener: function SecondaryToolbar_bindHandToolListener(toggleHandToolButton) { - var isHandToolActive = false; - this.eventBus.on('handtoolchanged', function (e) { - if (isHandToolActive === e.isActive) { - return; + get isOpen() { + return this.opened; + } + setPageNumber(pageNumber) { + this.pageNumber = pageNumber; + this._updateUIState(); + } + setPagesCount(pagesCount) { + this.pagesCount = pagesCount; + this._updateUIState(); + } + reset() { + this.pageNumber = 0; + this.pagesCount = 0; + this._updateUIState(); + } + _updateUIState() { + this.items.firstPage.disabled = this.pageNumber <= 1; + this.items.lastPage.disabled = this.pageNumber >= this.pagesCount; + this.items.pageRotateCw.disabled = this.pagesCount === 0; + this.items.pageRotateCcw.disabled = this.pagesCount === 0; + } + _bindClickListeners() { + this.toggleButton.addEventListener('click', this.toggle.bind(this)); + for (let button in this.buttons) { + let { element, eventName, close } = this.buttons[button]; + element.addEventListener('click', evt => { + if (eventName !== null) { + this.eventBus.dispatch(eventName, { source: this }); } - isHandToolActive = e.isActive; - if (isHandToolActive) { - toggleHandToolButton.title = _ui_utils.mozL10n.get('hand_tool_disable.title', null, 'Disable hand tool'); - toggleHandToolButton.firstElementChild.textContent = _ui_utils.mozL10n.get('hand_tool_disable_label', null, 'Disable hand tool'); - } else { - toggleHandToolButton.title = _ui_utils.mozL10n.get('hand_tool_enable.title', null, 'Enable hand tool'); - toggleHandToolButton.firstElementChild.textContent = _ui_utils.mozL10n.get('hand_tool_enable_label', null, 'Enable hand tool'); + if (close) { + this.close(); } }); - }, - open: function SecondaryToolbar_open() { - if (this.opened) { - return; - } - this.opened = true; - this._setMaxHeight(); - this.toggleButton.classList.add('toggled'); - this.toolbar.classList.remove('hidden'); - }, - close: function SecondaryToolbar_close() { - if (!this.opened) { - return; - } - this.opened = false; - this.toolbar.classList.add('hidden'); - this.toggleButton.classList.remove('toggled'); - }, - toggle: function SecondaryToolbar_toggle() { - if (this.opened) { - this.close(); - } else { - this.open(); - } - }, - _setMaxHeight: function SecondaryToolbar_setMaxHeight() { - if (!this.opened) { - return; - } - this.containerHeight = this.mainContainer.clientHeight; - if (this.containerHeight === this.previousContainerHeight) { - return; - } - this.toolbarButtonContainer.setAttribute('style', 'max-height: ' + (this.containerHeight - _ui_utils.SCROLLBAR_PADDING) + 'px;'); - this.previousContainerHeight = this.containerHeight; } - }; - return SecondaryToolbar; -}(); + } + _bindHandToolListener(toggleHandToolButton) { + let isHandToolActive = false; + this.eventBus.on('handtoolchanged', function (evt) { + if (isHandToolActive === evt.isActive) { + return; + } + isHandToolActive = evt.isActive; + if (isHandToolActive) { + toggleHandToolButton.title = _ui_utils.mozL10n.get('hand_tool_disable.title', null, 'Disable hand tool'); + toggleHandToolButton.firstElementChild.textContent = _ui_utils.mozL10n.get('hand_tool_disable_label', null, 'Disable hand tool'); + } else { + toggleHandToolButton.title = _ui_utils.mozL10n.get('hand_tool_enable.title', null, 'Enable hand tool'); + toggleHandToolButton.firstElementChild.textContent = _ui_utils.mozL10n.get('hand_tool_enable_label', null, 'Enable hand tool'); + } + }); + } + open() { + if (this.opened) { + return; + } + this.opened = true; + this._setMaxHeight(); + this.toggleButton.classList.add('toggled'); + this.toolbar.classList.remove('hidden'); + } + close() { + if (!this.opened) { + return; + } + this.opened = false; + this.toolbar.classList.add('hidden'); + this.toggleButton.classList.remove('toggled'); + } + toggle() { + if (this.opened) { + this.close(); + } else { + this.open(); + } + } + _setMaxHeight() { + if (!this.opened) { + return; + } + this.containerHeight = this.mainContainer.clientHeight; + if (this.containerHeight === this.previousContainerHeight) { + return; + } + this.toolbarButtonContainer.setAttribute('style', 'max-height: ' + (this.containerHeight - _ui_utils.SCROLLBAR_PADDING) + 'px;'); + this.previousContainerHeight = this.containerHeight; + } +} exports.SecondaryToolbar = SecondaryToolbar; /***/ }), diff --git a/devtools/client/inspector/markup/utils.js b/devtools/client/inspector/markup/utils.js index 8fab9d963d18..68f106a3f8de 100644 --- a/devtools/client/inspector/markup/utils.js +++ b/devtools/client/inspector/markup/utils.js @@ -4,6 +4,33 @@ "use strict"; +const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + +function* getNames(x) { + yield* Object.getOwnPropertyNames(x); + yield* Object.getOwnPropertySymbols(x); +} + +// Utility function to get own properties descriptor map. +function getOwnPropertyDescriptors(...objects) { + let descriptors = {}; + for (let object of objects) { + for (let name of getNames(object)) { + descriptors[name] = getOwnPropertyDescriptor(object, name); + } + } + return descriptors; +} + +/** + * Returns a frozen object with that inherits from the given `prototype` and + * implements all own properties of the given `properties` object. + */ +function extend(prototype, properties) { + return Object.create(prototype, + getOwnPropertyDescriptors(properties)); +} + /** * Apply a 'flashed' background and foreground color to elements. Intended * to be used with flashElementOff as a way of drawing attention to an element. @@ -127,6 +154,7 @@ function truncateString(str, maxLength) { } module.exports = { + extend, flashElementOn, flashElementOff, getAutocompleteMaxWidth, diff --git a/devtools/client/inspector/markup/views/element-container.js b/devtools/client/inspector/markup/views/element-container.js index 7308432f7423..08625d09cd9b 100644 --- a/devtools/client/inspector/markup/views/element-container.js +++ b/devtools/client/inspector/markup/views/element-container.js @@ -8,7 +8,6 @@ const PREVIEW_MAX_DIM_PREF = "devtools.inspector.imagePreviewTooltipSize"; const promise = require("promise"); const Services = require("Services"); -const Heritage = require("sdk/core/heritage"); const {Task} = require("devtools/shared/task"); const nodeConstants = require("devtools/shared/dom-node-constants"); const clipboardHelper = require("devtools/shared/platform/clipboard"); @@ -16,6 +15,7 @@ const {setImageTooltip, setBrokenImageTooltip} = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper"); const MarkupContainer = require("devtools/client/inspector/markup/views/markup-container"); const ElementEditor = require("devtools/client/inspector/markup/views/element-editor"); +const {extend} = require("devtools/client/inspector/markup/utils"); // Lazy load this module as _buildEventTooltipContent is only called on click loader.lazyRequireGetter(this, "setEventTooltip", @@ -44,7 +44,7 @@ function MarkupElementContainer(markupView, node) { this.tagLine.appendChild(this.editor.elt); } -MarkupElementContainer.prototype = Heritage.extend(MarkupContainer.prototype, { +MarkupElementContainer.prototype = extend(MarkupContainer.prototype, { _buildEventTooltipContent: Task.async(function* (target, tooltip) { if (target.hasAttribute("data-event")) { yield tooltip.hide(); diff --git a/devtools/client/inspector/markup/views/read-only-container.js b/devtools/client/inspector/markup/views/read-only-container.js index fd645baacf25..06eab7313595 100644 --- a/devtools/client/inspector/markup/views/read-only-container.js +++ b/devtools/client/inspector/markup/views/read-only-container.js @@ -4,9 +4,9 @@ "use strict"; -const Heritage = require("sdk/core/heritage"); const ReadOnlyEditor = require("devtools/client/inspector/markup/views/read-only-editor"); const MarkupContainer = require("devtools/client/inspector/markup/views/markup-container"); +const {extend} = require("devtools/client/inspector/markup/utils"); /** * An implementation of MarkupContainer for Pseudo Elements, @@ -28,6 +28,6 @@ function MarkupReadOnlyContainer(markupView, node) { } MarkupReadOnlyContainer.prototype = - Heritage.extend(MarkupContainer.prototype, {}); + extend(MarkupContainer.prototype, {}); module.exports = MarkupReadOnlyContainer; diff --git a/devtools/client/inspector/markup/views/text-container.js b/devtools/client/inspector/markup/views/text-container.js index 357f177786a1..e63960a109ae 100644 --- a/devtools/client/inspector/markup/views/text-container.js +++ b/devtools/client/inspector/markup/views/text-container.js @@ -4,10 +4,10 @@ "use strict"; -const Heritage = require("sdk/core/heritage"); const nodeConstants = require("devtools/shared/dom-node-constants"); const TextEditor = require("devtools/client/inspector/markup/views/text-editor"); const MarkupContainer = require("devtools/client/inspector/markup/views/markup-container"); +const {extend} = require("devtools/client/inspector/markup/utils"); /** * An implementation of MarkupContainer for text node and comment nodes. @@ -35,6 +35,6 @@ function MarkupTextContainer(markupView, node) { this.tagLine.appendChild(this.editor.elt); } -MarkupTextContainer.prototype = Heritage.extend(MarkupContainer.prototype, {}); +MarkupTextContainer.prototype = extend(MarkupContainer.prototype, {}); module.exports = MarkupTextContainer; diff --git a/devtools/client/jsonview/converter-child.js b/devtools/client/jsonview/converter-child.js index fac0cd52aca0..5e7e1789b9e4 100644 --- a/devtools/client/jsonview/converter-child.js +++ b/devtools/client/jsonview/converter-child.js @@ -308,8 +308,11 @@ Converter.prototype = { break; case "save": + // The window ID is needed when the JSON Viewer is inside an iframe. + let windowID = win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils).outerWindowID; childProcessMessageManager.sendAsyncMessage( - "devtools:jsonview:save", value); + "devtools:jsonview:save", {url: value, windowID: windowID}); } }, diff --git a/devtools/client/jsonview/json-viewer.js b/devtools/client/jsonview/json-viewer.js index b8208291a381..22ef1c53bae4 100644 --- a/devtools/client/jsonview/json-viewer.js +++ b/devtools/client/jsonview/json-viewer.js @@ -15,6 +15,7 @@ define(function (require, exports, module) { const headers = document.getElementById("headers"); let jsonData; + let prettyURL; try { jsonData = JSON.parse(json.textContent); @@ -45,7 +46,10 @@ define(function (require, exports, module) { }, onSaveJson: function () { - dispatchEvent("save", input.prettified ? input.jsonPretty : input.jsonText); + if (input.prettified && !prettyURL) { + prettyURL = URL.createObjectURL(new window.Blob([input.jsonPretty])); + } + dispatchEvent("save", input.prettified ? prettyURL : null); }, onCopyHeaders: function () { diff --git a/devtools/client/jsonview/main.js b/devtools/client/jsonview/main.js index 4164ca00d58c..b2bed7f333ff 100644 --- a/devtools/client/jsonview/main.js +++ b/devtools/client/jsonview/main.js @@ -7,11 +7,17 @@ "use strict"; -const { Cu } = require("chrome"); +const { Cu, Cc, Ci } = require("chrome"); const Services = require("Services"); const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); +XPCOMUtils.defineLazyGetter(this, "chrome", function () { + return Cc["@mozilla.org/appshell/window-mediator;1"] + .getService(Ci.nsIWindowMediator) + .getMostRecentWindow("navigator:browser"); +}); + XPCOMUtils.defineLazyGetter(this, "JsonViewUtils", function () { return require("devtools/client/jsonview/utils"); }); @@ -50,9 +56,28 @@ var JsonView = { * in the parent process. */ onSave: function (message) { - JsonViewUtils.getTargetFile().then(file => { - JsonViewUtils.saveToFile(file, message.data); - }, () => {}); + let browser = chrome.gBrowser.selectedBrowser; + if (message.data.url === null) { + // Save original contents + chrome.saveBrowser(browser, false, message.data.windowID); + } else { + // The following code emulates saveBrowser, but: + // - Uses the given blob URL containing the custom contents to save. + // - Obtains the file name from the URL of the document, not the blob. + let persistable = browser.QueryInterface(Ci.nsIFrameLoaderOwner) + .frameLoader.QueryInterface(Ci.nsIWebBrowserPersistable); + persistable.startPersistence(message.data.windowID, { + onDocumentReady(doc) { + let uri = chrome.makeURI(doc.documentURI, doc.characterSet); + let filename = chrome.getDefaultFileName(undefined, uri, doc, null); + chrome.internalSave(message.data.url, doc, filename, null, doc.contentType, + false, null, null, null, doc, false, null, undefined); + }, + onError(status) { + throw new Error("JSON Viewer's onSave failed in startPersistence"); + } + }); + } } }; diff --git a/devtools/client/jsonview/utils.js b/devtools/client/jsonview/utils.js index 5c2bffe57067..fce7a5b0ce8a 100644 --- a/devtools/client/jsonview/utils.js +++ b/devtools/client/jsonview/utils.js @@ -6,86 +6,9 @@ "use strict"; -const { Cu, Cc, Ci } = require("chrome"); +const { Cu } = require("chrome"); const Services = require("Services"); -const OPEN_FLAGS = { - RDONLY: parseInt("0x01", 16), - WRONLY: parseInt("0x02", 16), - CREATE_FILE: parseInt("0x08", 16), - APPEND: parseInt("0x10", 16), - TRUNCATE: parseInt("0x20", 16), - EXCL: parseInt("0x80", 16) -}; - -let filePickerShown = false; - -/** - * Open File Save As dialog and let the user to pick proper file location. - */ -exports.getTargetFile = function () { - return new Promise((resolve, reject) => { - if (filePickerShown) { - reject(null); - return; - } - - filePickerShown = true; - - let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); - - let win = Services.wm.getMostRecentWindow("navigator:browser"); - fp.init(win, null, Ci.nsIFilePicker.modeSave); - fp.appendFilter("JSON Files", "*.json; *.jsonp;"); - fp.appendFilters(Ci.nsIFilePicker.filterText); - fp.appendFilters(Ci.nsIFilePicker.filterAll); - fp.filterIndex = 0; - - fp.open(rv => { - filePickerShown = false; - - if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) { - resolve(fp.file); - } else { - reject(null); - } - }); - }); -}; - -/** - * Save JSON to a file - */ -exports.saveToFile = function (file, jsonString) { - let foStream = Cc["@mozilla.org/network/file-output-stream;1"] - .createInstance(Ci.nsIFileOutputStream); - - // write, create, truncate - let openFlags = OPEN_FLAGS.WRONLY | OPEN_FLAGS.CREATE_FILE | - OPEN_FLAGS.TRUNCATE; - - let permFlags = parseInt("0666", 8); - foStream.init(file, openFlags, permFlags, 0); - - let converter = Cc["@mozilla.org/intl/converter-output-stream;1"] - .createInstance(Ci.nsIConverterOutputStream); - - converter.init(foStream, "UTF-8", 0, 0); - - // The entire jsonString can be huge so, write the data in chunks. - let chunkLength = 1024 * 1204; - for (let i = 0; i <= jsonString.length; i++) { - let data = jsonString.substr(i, chunkLength + 1); - if (data) { - converter.writeString(data); - } - i = i + chunkLength; - } - - // this closes foStream - converter.close(); -}; - /** * Get the current theme from preferences. */ diff --git a/devtools/client/netmonitor/src/components/toolbar.js b/devtools/client/netmonitor/src/components/toolbar.js index 343b34d563e1..f3148d141b9f 100644 --- a/devtools/client/netmonitor/src/components/toolbar.js +++ b/devtools/client/netmonitor/src/components/toolbar.js @@ -12,7 +12,7 @@ const { } = require("devtools/client/shared/vendor/react"); const { connect } = require("devtools/client/shared/vendor/react-redux"); const Actions = require("../actions/index"); -const { FILTER_SEARCH_DELAY } = require("../constants"); +const { FILTER_SEARCH_DELAY, FILTER_FLAGS } = require("../constants"); const { getDisplayedRequestsSummary, getRequestFilterTypes, @@ -109,6 +109,7 @@ const Toolbar = createClass({ placeholder: SEARCH_PLACE_HOLDER, type: "filter", onChange: setRequestFilterText, + autocompleteList: FILTER_FLAGS.map((item) => `${item}:`), }), button({ className: toggleButtonClassName.join(" "), diff --git a/devtools/client/netmonitor/src/constants.js b/devtools/client/netmonitor/src/constants.js index b74f29f58ac5..d6e069371607 100644 --- a/devtools/client/netmonitor/src/constants.js +++ b/devtools/client/netmonitor/src/constants.js @@ -158,6 +158,19 @@ const HEADERS = [ } ]; +const HEADER_FILTERS = HEADERS + .filter(h => h.canFilter) + .map(h => h.filterKey || h.name); + +const FILTER_FLAGS = [ + ...HEADER_FILTERS, + "mime-type", + "larger-than", + "is", + "has-response-header", + "regexp", +]; + const REQUESTS_WATERFALL = { BACKGROUND_TICKS_MULTIPLE: 5, // ms BACKGROUND_TICKS_SCALES: 3, @@ -180,6 +193,7 @@ const general = { EVENTS, FILTER_SEARCH_DELAY: 200, HEADERS, + FILTER_FLAGS, SOURCE_EDITOR_SYNTAX_HIGHLIGHT_MAX_SIZE: 51200, // 50 KB in bytes REQUESTS_WATERFALL, }; diff --git a/devtools/client/netmonitor/src/utils/filter-text-utils.js b/devtools/client/netmonitor/src/utils/filter-text-utils.js index 280e5d085359..7a0972b53592 100644 --- a/devtools/client/netmonitor/src/utils/filter-text-utils.js +++ b/devtools/client/netmonitor/src/utils/filter-text-utils.js @@ -30,23 +30,8 @@ "use strict"; -const { HEADERS } = require("../constants"); +const { FILTER_FLAGS } = require("../constants"); const { getFormattedIPAndPort } = require("./format-utils"); -const HEADER_FILTERS = HEADERS - .filter(h => h.canFilter) - .map(h => h.filterKey || h.name); - -const FILTER_FLAGS = [ - ...HEADER_FILTERS, - "set-cookie-domain", - "set-cookie-name", - "set-cookie-value", - "mime-type", - "larger-than", - "is", - "has-response-header", - "regexp", -]; /* The function `parseFilters` is from: diff --git a/devtools/client/netmonitor/webpack.config.js b/devtools/client/netmonitor/webpack.config.js index 059c249fa2de..f0c7fb0dd03a 100644 --- a/devtools/client/netmonitor/webpack.config.js +++ b/devtools/client/netmonitor/webpack.config.js @@ -42,6 +42,7 @@ let webpackConfig = { "devtools/client/framework/menu": "devtools-modules/src/menu", "devtools/client/framework/menu-item": path.join(__dirname, "../../client/framework/menu-item"), "devtools/client/locales": path.join(__dirname, "../../client/locales/en-US"), + "devtools/client/shared/components/autocomplete-popup": path.join(__dirname, "../../client/shared/components/autocomplete-popup"), "devtools/client/shared/components/reps/reps": path.join(__dirname, "../../client/shared/components/reps/reps"), "devtools/client/shared/components/search-box": path.join(__dirname, "../../client/shared/components/search-box"), "devtools/client/shared/components/splitter/draggable": path.join(__dirname, "../../client/shared/components/splitter/draggable"), diff --git a/devtools/client/shared/components/autocomplete-popup.js b/devtools/client/shared/components/autocomplete-popup.js new file mode 100644 index 000000000000..17e6b03541e4 --- /dev/null +++ b/devtools/client/shared/components/autocomplete-popup.js @@ -0,0 +1,122 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react"); + +module.exports = createClass({ + displayName: "AutocompletePopup", + + propTypes: { + list: PropTypes.array.isRequired, + filter: PropTypes.string.isRequired, + onItemSelected: PropTypes.func.isRequired, + }, + + getInitialState() { + return this.computeState(this.props); + }, + + componentWillReceiveProps(nextProps) { + if (this.props.filter === nextProps.filter) { + return; + } + this.setState(this.computeState(nextProps)); + }, + + componentDidUpdate() { + if (this.refs.selected) { + this.refs.selected.scrollIntoView(false); + } + }, + + computeState({ filter, list }) { + let filteredList = list.filter((item) => { + return item.toLowerCase().startsWith(filter.toLowerCase()) + && item.toLowerCase() !== filter.toLowerCase(); + }).sort(); + let selectedIndex = filteredList.length == 1 ? 0 : -1; + + return { filteredList, selectedIndex }; + }, + + /** + * Use this method to select the top-most item + * This method is public, called outside of the autocomplete-popup component. + */ + jumpToTop() { + this.setState({ selectedIndex: 0 }); + }, + + /** + * Use this method to select the bottom-most item + * This method is public. + */ + jumpToBottom() { + let selectedIndex = this.state.filteredList.length - 1; + this.setState({ selectedIndex }); + }, + + /** + * Increment the selected index with the provided increment value. Will cycle to the + * beginning/end of the list if the index exceeds the list boundaries. + * This method is public. + * + * @param {number} increment - No. of hops in the direction + */ + jumpBy(increment = 1) { + let { filteredList, selectedIndex } = this.state; + let nextIndex = selectedIndex + increment; + if (increment > 0) { + // Positive cycling + nextIndex = nextIndex > filteredList.length - 1 ? 0 : nextIndex; + } else if (increment < 0) { + // Inverse cycling + nextIndex = nextIndex < 0 ? filteredList.length - 1 : nextIndex; + } + this.setState({selectedIndex: nextIndex}); + }, + + /** + * Submit the currently selected item to the onItemSelected callback + * This method is public. + */ + select() { + if (this.refs.selected) { + this.props.onItemSelected(this.refs.selected.textContent); + } + }, + + onMouseDown(e) { + e.preventDefault(); + this.setState({ selectedIndex: Number(e.target.dataset.index) }, this.select); + }, + + render() { + let { filteredList } = this.state; + + return filteredList.length > 0 && dom.div( + { className: "devtools-autocomplete-popup devtools-monospace" }, + dom.ul( + { className: "devtools-autocomplete-listbox" }, + filteredList.map((item, i) => { + let isSelected = this.state.selectedIndex == i; + let itemClassList = ["autocomplete-item"]; + + if (isSelected) { + itemClassList.push("autocomplete-selected"); + } + return dom.li({ + key: i, + "data-index": i, + className: itemClassList.join(" "), + ref: isSelected ? "selected" : null, + onMouseDown: this.onMouseDown, + }, item); + }) + ) + ); + } +}); diff --git a/devtools/client/shared/components/moz.build b/devtools/client/shared/components/moz.build index 0d67e90b553a..c19c20153fd3 100644 --- a/devtools/client/shared/components/moz.build +++ b/devtools/client/shared/components/moz.build @@ -12,6 +12,7 @@ DIRS += [ ] DevToolsModules( + 'autocomplete-popup.js', 'frame.js', 'h-split-box.js', 'notification-box.css', diff --git a/devtools/client/shared/components/search-box.js b/devtools/client/shared/components/search-box.js index 159865e9fc8b..3e085707aaf8 100644 --- a/devtools/client/shared/components/search-box.js +++ b/devtools/client/shared/components/search-box.js @@ -6,8 +6,9 @@ "use strict"; -const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react"); +const { DOM: dom, createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react"); const KeyShortcuts = require("devtools/client/shared/key-shortcuts"); +const AutocompletePopup = createFactory(require("devtools/client/shared/components/autocomplete-popup")); /** * A generic search box component for use across devtools @@ -20,12 +21,20 @@ module.exports = createClass({ keyShortcut: PropTypes.string, onChange: PropTypes.func, placeholder: PropTypes.string, - type: PropTypes.string + type: PropTypes.string, + autocompleteList: PropTypes.array, + }, + + getDefaultProps() { + return { + autocompleteList: [], + }; }, getInitialState() { return { - value: "" + value: "", + focused: false, }; }, @@ -56,7 +65,9 @@ module.exports = createClass({ onChange() { if (this.state.value !== this.refs.input.value) { - this.setState({ value: this.refs.input.value }); + this.setState({ + value: this.refs.input.value, + }); } if (!this.props.delay) { @@ -82,8 +93,59 @@ module.exports = createClass({ this.onChange(); }, + onFocus() { + this.setState({ focused: true }); + }, + + onBlur() { + this.setState({ focused: false }); + }, + + onKeyDown(e) { + let { autocompleteList } = this.props; + let { autocomplete } = this.refs; + + if (autocompleteList.length == 0) { + return; + } + + switch (e.key) { + case "ArrowDown": + autocomplete.jumpBy(1); + break; + case "ArrowUp": + autocomplete.jumpBy(-1); + break; + case "PageDown": + autocomplete.jumpBy(5); + break; + case "PageUp": + autocomplete.jumpBy(-5); + break; + case "Enter": + case "Tab": + e.preventDefault(); + autocomplete.select(); + break; + case "Escape": + e.preventDefault(); + this.onBlur(); + break; + case "Home": + autocomplete.jumpToTop(); + break; + case "End": + autocomplete.jumpToBottom(); + break; + } + }, + render() { - let { type = "search", placeholder } = this.props; + let { + type = "search", + placeholder, + autocompleteList + } = this.props; let { value } = this.state; let divClassList = ["devtools-searchbox", "has-clear-btn"]; let inputClassList = [`devtools-${type}input`]; @@ -96,14 +158,27 @@ module.exports = createClass({ dom.input({ className: inputClassList.join(" "), onChange: this.onChange, + onFocus: this.onFocus, + onBlur: this.onBlur, + onKeyDown: this.onKeyDown, placeholder, ref: "input", - value + value, }), dom.button({ className: "devtools-searchinput-clear", hidden: value == "", onClick: this.onClearButtonClick + }), + autocompleteList.length > 0 && this.state.focused && + AutocompletePopup({ + list: autocompleteList, + filter: value, + ref: "autocomplete", + onItemSelected: (itemValue) => { + this.setState({ value: itemValue }); + this.onChange(); + } }) ); } diff --git a/devtools/client/shared/widgets/tooltip/ImageTooltipHelper.js b/devtools/client/shared/widgets/tooltip/ImageTooltipHelper.js index 37e2e0917d83..cf6a28ea2672 100644 --- a/devtools/client/shared/widgets/tooltip/ImageTooltipHelper.js +++ b/devtools/client/shared/widgets/tooltip/ImageTooltipHelper.js @@ -132,7 +132,7 @@ function setBrokenImageTooltip(tooltip, doc) { div.className = "theme-comment devtools-tooltip-image-broken"; let message = L10N.getStr("previewTooltip.image.brokenImage"); div.textContent = message; - tooltip.setContent(div, {width: 150, height: 30}); + tooltip.setContent(div); } module.exports.getImageDimensions = getImageDimensions; diff --git a/devtools/client/themes/common.css b/devtools/client/themes/common.css index 1d9d05ef17bb..8f9550156532 100644 --- a/devtools/client/themes/common.css +++ b/devtools/client/themes/common.css @@ -82,35 +82,13 @@ html|button, html|select { background-color: transparent; border-radius: 4px; padding: 1px 0; -} - -.devtools-autocomplete-listbox .autocomplete-selected { - background-color: rgba(0,0,0,0.2); -} - -.devtools-autocomplete-listbox.dark-theme .autocomplete-selected, -.devtools-autocomplete-listbox.dark-theme .autocomplete-item:hover { - background-color: rgba(0,0,0,0.5); -} - -.devtools-autocomplete-listbox.dark-theme .autocomplete-selected > .autocomplete-value, -.devtools-autocomplete-listbox:focus.dark-theme .autocomplete-selected > .initial-value { - color: hsl(208,100%,60%); -} - -.devtools-autocomplete-listbox.dark-theme .autocomplete-selected > span { - color: #eee; -} - -.devtools-autocomplete-listbox.dark-theme .autocomplete-item > span { - color: #ccc; + cursor: default; } .devtools-autocomplete-listbox .autocomplete-item > .initial-value, .devtools-autocomplete-listbox .autocomplete-item > .autocomplete-value { margin: 0; padding: 0; - cursor: default; } .devtools-autocomplete-listbox .autocomplete-item > .autocomplete-count { @@ -120,52 +98,60 @@ html|button, html|select { /* Rest of the dark and light theme */ .devtools-autocomplete-popup, +.CodeMirror-hints, +.CodeMirror-Tern-tooltip { + border: 1px solid hsl(210,24%,90%); + background-image: linear-gradient(to bottom, hsla(209,18%,100%,0.9), hsl(210,24%,95%)); + box-shadow: 0 1px 0 hsla(209,29%,90%,.25) inset; +} + +.theme-dark .devtools-autocomplete-popup, .theme-dark .CodeMirror-hints, .theme-dark .CodeMirror-Tern-tooltip { border: 1px solid hsl(210,11%,10%); background-image: linear-gradient(to bottom, hsla(209,18%,18%,0.9), hsl(210,11%,16%)); -} - -.devtools-autocomplete-popup.light-theme, -.light-theme .CodeMirror-hints, -.light-theme .CodeMirror-Tern-tooltip { - border: 1px solid hsl(210,24%,90%); - background-image: linear-gradient(to bottom, hsla(209,18%,100%,0.9), hsl(210,24%,95%)); -} - -.devtools-autocomplete-popup.light-theme { - box-shadow: 0 1px 0 hsla(209,29%,90%,.25) inset; + box-shadow: none; } .theme-firebug .devtools-autocomplete-popup { border-color: var(--theme-splitter-color); border-radius: 5px; font-size: var(--theme-autompletion-font-size); -} - -.devtools-autocomplete-popup.firebug-theme { background: var(--theme-body-background); } -.devtools-autocomplete-listbox.firebug-theme .autocomplete-selected, -.devtools-autocomplete-listbox.firebug-theme .autocomplete-item:hover, -.devtools-autocomplete-listbox.light-theme .autocomplete-selected, -.devtools-autocomplete-listbox.light-theme .autocomplete-item:hover { +.devtools-autocomplete-listbox .autocomplete-selected, +.devtools-autocomplete-listbox .autocomplete-item:hover { background-color: rgba(128,128,128,0.3); } -.devtools-autocomplete-listbox.firebug-theme .autocomplete-selected > .autocomplete-value, -.devtools-autocomplete-listbox:focus.firebug-theme .autocomplete-selected > .initial-value, -.devtools-autocomplete-listbox.light-theme .autocomplete-selected > .autocomplete-value, -.devtools-autocomplete-listbox:focus.light-theme .autocomplete-selected > .initial-value { +.theme-dark .devtools-autocomplete-listbox .autocomplete-selected, +.theme-dark .devtools-autocomplete-listbox .autocomplete-item:hover { + background-color: rgba(0,0,0,0.5); +} + +.devtools-autocomplete-listbox .autocomplete-selected > .autocomplete-value, +.devtools-autocomplete-listbox:focus .autocomplete-selected > .initial-value { color: #222; } -.devtools-autocomplete-listbox.firebug-theme .autocomplete-item > span, -.devtools-autocomplete-listbox.light-theme .autocomplete-item > span { +.theme-dark .devtools-autocomplete-listbox .autocomplete-selected > .autocomplete-value, +.theme-dark .devtools-autocomplete-listbox:focus .autocomplete-selected > .initial-value { + color: hsl(208,100%,60%); +} + +.devtools-autocomplete-listbox .autocomplete-item > span { color: #666; } +.theme-dark .devtools-autocomplete-listbox .autocomplete-item > span { + color: #ccc; +} + +.theme-dark .devtools-autocomplete-listbox .autocomplete-selected > span { + color: #eee; +} + /* Autocomplete list clone used for accessibility. */ .devtools-autocomplete-list-aria-clone { @@ -493,6 +479,14 @@ checkbox:-moz-focusring { outline: none; } +.devtools-searchbox .devtools-autocomplete-popup { + position: absolute; + top: 100%; + width: 100%; + line-height: initial !important; + z-index: 999; +} + /* Don't add 'double spacing' for inputs that are at beginning / end of a toolbar (since the toolbar has it's own spacing). */ .devtools-toolbar > .devtools-textinput:first-child, diff --git a/devtools/client/themes/tooltips.css b/devtools/client/themes/tooltips.css index 170d44e679fa..b8f2f5648348 100644 --- a/devtools/client/themes/tooltips.css +++ b/devtools/client/themes/tooltips.css @@ -452,6 +452,5 @@ .devtools-tooltip-image-broken { box-sizing: border-box; height: 100%; - text-align: center; - line-height: 30px; + padding: 7px; } diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 44f770584d1e..b7f320bf5035 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -6883,6 +6883,34 @@ nsContentUtils::WidgetForDocument(const nsIDocument* aDoc) return nullptr; } +nsIWidget* +nsContentUtils::WidgetForContent(const nsIContent* aContent) +{ + nsIFrame* frame = aContent->GetPrimaryFrame(); + if (frame) { + frame = nsLayoutUtils::GetDisplayRootFrame(frame); + + nsView* view = frame->GetView(); + if (view) { + return view->GetWidget(); + } + } + + return nullptr; +} + +already_AddRefed +nsContentUtils::LayerManagerForContent(const nsIContent *aContent) +{ + nsIWidget* widget = nsContentUtils::WidgetForContent(aContent); + if (widget) { + RefPtr manager = widget->GetLayerManager(); + return manager.forget(); + } + + return nullptr; +} + static already_AddRefed LayerManagerForDocumentInternal(const nsIDocument *aDoc, bool aRequirePersistent) { diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index f69cbc5dabb0..e30ec88f4527 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2037,15 +2037,29 @@ public: * Returns the widget for this document if there is one. Looks at all ancestor * documents to try to find a widget, so for example this can still find a * widget for documents in display:none frames that have no presentation. + * + * You should probably use WidgetForContent() instead of this, unless you have + * a good reason to do otherwise. */ static nsIWidget* WidgetForDocument(const nsIDocument* aDoc); + /** + * Returns the appropriate widget for this element, if there is one. Unlike + * WidgetForDocument(), this returns the correct widget for content in popups. + * + * You should probably use this instead of WidgetForDocument(). + */ + static nsIWidget* WidgetForContent(const nsIContent* aContent); + /** * Returns a layer manager to use for the given document. Basically we * look up the document hierarchy for the first document which has * a presentation with an associated widget, and use that widget's * layer manager. * + * You should probably use LayerManagerForContent() instead of this, unless + * you have a good reason to do otherwise. + * * @param aDoc the document for which to return a layer manager. * @param aAllowRetaining an outparam that states whether the returned * layer manager should be used for retained layers @@ -2053,6 +2067,16 @@ public: static already_AddRefed LayerManagerForDocument(const nsIDocument *aDoc); + /** + * Returns a layer manager to use for the given content. Unlike + * LayerManagerForDocument(), this returns the correct layer manager for + * content in popups. + * + * You should probably use this instead of LayerManagerForDocument(). + */ + static already_AddRefed + LayerManagerForContent(const nsIContent *aContent); + /** * Returns a layer manager to use for the given document. Basically we * look up the document hierarchy for the first document which has diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 01e3301840c5..04820685d307 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -57,6 +57,7 @@ #include "nsLayoutUtils.h" #include "nsMappedAttributes.h" #include "nsView.h" +#include "nsBaseWidget.h" #include "GroupedSHistory.h" #include "PartialSHistory.h" @@ -1259,9 +1260,18 @@ nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size, return false; } - RefPtr layerManager = - nsContentUtils::LayerManagerForDocument(mOwnerContent->GetComposedDoc()); - if (!layerManager) { + // We never want to host remote frameloaders in simple popups, like menus. + nsIWidget* widget = nsContentUtils::WidgetForContent(mOwnerContent); + if (!widget || static_cast(widget)->IsSmallPopup()) { + return false; + } + + RenderFrameParent* rfp = GetCurrentRenderFrame(); + if (!rfp) { + return false; + } + + if (!rfp->AttachLayerManager()) { // This is just not going to work. return false; } diff --git a/dom/canvas/test/reftest/reftest.list b/dom/canvas/test/reftest/reftest.list index 2e8dbb169c57..509449d33bc3 100644 --- a/dom/canvas/test/reftest/reftest.list +++ b/dom/canvas/test/reftest/reftest.list @@ -151,7 +151,7 @@ skip-if(!winWidget) pref(webgl.disable-angle,true) == webgl-color-test.html?nat # Bug 1255062 == clip-multiple-move-1.html clip-multiple-move-1-ref.html -== clip-multiple-move-2.html clip-multiple-move-2-ref.html +fuzzy-if(skiaContent,1,150) == clip-multiple-move-2.html clip-multiple-move-2-ref.html # Bug 815648 == stroketext-shadow.html stroketext-shadow-ref.html diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 2e9ff5f76f2b..670e7839ed04 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2293,7 +2293,7 @@ TabParent::RecvGetDPI(float* aValue) { TryCacheDPIAndScale(); - MOZ_ASSERT(mDPI > 0, + MOZ_ASSERT(mDPI > 0 || mFrameElement, "Must not ask for DPI before OwnerElement is received!"); *aValue = mDPI; return IPC_OK(); @@ -2304,7 +2304,7 @@ TabParent::RecvGetDefaultScale(double* aValue) { TryCacheDPIAndScale(); - MOZ_ASSERT(mDefaultScale.scale > 0, + MOZ_ASSERT(mDefaultScale.scale > 0 || mFrameElement, "Must not ask for scale before OwnerElement is received!"); *aValue = mDefaultScale.scale; return IPC_OK(); @@ -2315,7 +2315,7 @@ TabParent::RecvGetWidgetRounding(int32_t* aValue) { TryCacheDPIAndScale(); - MOZ_ASSERT(mRounding > 0, + MOZ_ASSERT(mRounding > 0 || mFrameElement, "Must not ask for rounding before OwnerElement is received!"); *aValue = mRounding; return IPC_OK(); @@ -2581,7 +2581,7 @@ TabParent::GetWidget() const if (!mFrameElement) { return nullptr; } - nsCOMPtr widget = nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc()); + nsCOMPtr widget = nsContentUtils::WidgetForContent(mFrameElement); return widget.forget(); } diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index ea4dee09c3e0..7431879ed401 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -1972,6 +1972,13 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest *request, nsISupports *ctxt) channel->SetContentType(NS_ConvertUTF16toUTF8(mOverrideMimeType)); } + // Fallback to 'application/octet-stream' + nsAutoCString type; + channel->GetContentType(type); + if (type.Equals(UNKNOWN_CONTENT_TYPE)) { + channel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_OCTET_STREAM)); + } + DetectCharset(); // Set up arraybuffer @@ -2696,12 +2703,13 @@ XMLHttpRequestMainThread::InitiateFetch(nsIInputStream* aUploadStream, // Since we expect XML data, set the type hint accordingly // if the channel doesn't know any content type. // This means that we always try to parse local files as XML - // ignoring return value, as this is not critical + // ignoring return value, as this is not critical. Use text/xml as fallback + // MIME type. nsAutoCString contentType; if (NS_FAILED(mChannel->GetContentType(contentType)) || contentType.IsEmpty() || contentType.Equals(UNKNOWN_CONTENT_TYPE)) { - mChannel->SetContentType(NS_LITERAL_CSTRING("application/xml")); + mChannel->SetContentType(NS_LITERAL_CSTRING("text/xml")); } // Set up the preflight if needed diff --git a/editor/reftests/reftest.list b/editor/reftests/reftest.list index 1447abce951f..421d0a9dc59d 100644 --- a/editor/reftests/reftest.list +++ b/editor/reftests/reftest.list @@ -60,7 +60,7 @@ random-if(Android) needs-focus fails-if(stylo) != spellcheck-textarea-property-d needs-focus == caret_on_focus.html caret_on_focus-ref.html needs-focus fails-if(stylo) != caret_on_textarea_lastline.html caret_on_textarea_lastline-ref.html needs-focus == input-text-onfocus-reframe.html input-text-onfocus-reframe-ref.html -needs-focus == input-text-notheme-onfocus-reframe.html input-text-notheme-onfocus-reframe-ref.html +fuzzy-if(skiaContent,3,1) needs-focus == input-text-notheme-onfocus-reframe.html input-text-notheme-onfocus-reframe-ref.html needs-focus == caret_after_reframe.html caret_after_reframe-ref.html == nobogusnode-1.html nobogusnode-ref.html == nobogusnode-2.html nobogusnode-ref.html diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp index 9af151485cde..407fa93818d0 100644 --- a/extensions/cookie/nsPermissionManager.cpp +++ b/extensions/cookie/nsPermissionManager.cpp @@ -84,10 +84,15 @@ LogToConsole(const nsAString& aMsg) namespace { +// The number of permissions from the kPreloadPermissions list which are present +// in the permission manager. Used to determine if the permission manager should +// be checked for one of these preload permissions in nsContentBlocker. +static int32_t sPreloadPermissionCount = 0; + // These permissions are special permissions which must be transmitted to the // content process before documents with their principals have loaded within -// that process. For example, the permissions which are used for content -// blocking are sent using this mechanism. +// that process. This is because these permissions are used for content +// blocking in nsContentBlocker. // // Permissions which are in this list are considered to have a "" permission // key, even if their principal would not normally have that key. @@ -118,7 +123,6 @@ static const char* kPreloadPermissions[] = { "fetch", "image", "manifest" - // ------------------------------------------ }; // NOTE: nullptr can be passed as aType - if it is this function will return @@ -1781,6 +1785,12 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal, aExpireType, aExpireTime, aModificationTime)); + // Record a count of the number of preload permissions present in the + // content process. + if (IsPreloadPermission(mTypeArray[typeIndex].get())) { + sPreloadPermissionCount++; + } + if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION) { UpdateDB(op, mStmtInsert, id, origin, aType, aPermission, aExpireType, aExpireTime, aModificationTime); } @@ -1803,6 +1813,12 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal, id = oldPermissionEntry.mID; entry->GetPermissions().RemoveElementAt(index); + // Record a count of the number of preload permissions present in the + // content process. + if (IsPreloadPermission(mTypeArray[typeIndex].get())) { + sPreloadPermissionCount--; + } + if (aDBOperation == eWriteToDB) // We care only about the id here so we pass dummy values for all other // parameters. @@ -3248,3 +3264,10 @@ nsPermissionManager::WhenPermissionsAvailable(nsIPrincipal* aPrincipal, }); return NS_OK; } + +NS_IMETHODIMP +nsPermissionManager::GetHasPreloadPermissions(bool* aResult) +{ + *aResult = sPreloadPermissionCount > 0; + return NS_OK; +} diff --git a/extensions/permissions/nsContentBlocker.cpp b/extensions/permissions/nsContentBlocker.cpp index 9fdbda9c67e6..3a628b7d99ce 100644 --- a/extensions/permissions/nsContentBlocker.cpp +++ b/extensions/permissions/nsContentBlocker.cpp @@ -267,6 +267,7 @@ nsContentBlocker::TestPermission(nsIURI *aCurrentURI, bool *aFromPrefs) { *aFromPrefs = false; + nsresult rv; if (!*kTypeString[aContentType - 1]) { // Disallow internal content policy types, they should not be used here. @@ -282,11 +283,16 @@ nsContentBlocker::TestPermission(nsIURI *aCurrentURI, // default prefs. // Don't forget the aContentType ranges from 1..8, while the // array is indexed 0..7 - uint32_t permission; - nsresult rv = mPermissionManager->TestPermission(aCurrentURI, - kTypeString[aContentType - 1], - &permission); - NS_ENSURE_SUCCESS(rv, rv); + // All permissions tested by this method are preload permissions, so don't + // bother actually checking with the permission manager unless we have a + // preload permission. + uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION; + if (mPermissionManager->GetHasPreloadPermissions()) { + rv = mPermissionManager->TestPermission(aCurrentURI, + kTypeString[aContentType - 1], + &permission); + NS_ENSURE_SUCCESS(rv, rv); + } // If there is nothing on the list, use the default. if (!permission) { diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 3a95ee2d6772..8d4ae72dcdb1 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -7,7 +7,6 @@ #include "SourceSurfaceSkia.h" #include "ScaledFontBase.h" #include "ScaledFontCairo.h" -#include "skia/include/core/SkBitmapDevice.h" #include "FilterNodeSoftware.h" #include "HelpersSkia.h" @@ -19,7 +18,7 @@ #include "skia/include/core/SkColorFilter.h" #include "skia/include/effects/SkBlurImageFilter.h" #include "skia/include/effects/SkLayerRasterizer.h" -#include "skia/src/core/SkSpecialImage.h" +#include "skia/src/core/SkDevice.h" #include "Blur.h" #include "Logging.h" #include "Tools.h" @@ -30,10 +29,9 @@ #ifdef USE_SKIA_GPU #include "GLDefs.h" -#include "skia/include/gpu/SkGr.h" #include "skia/include/gpu/GrContext.h" -#include "skia/include/gpu/GrDrawContext.h" #include "skia/include/gpu/gl/GrGLInterface.h" +#include "skia/src/gpu/GrRenderTargetContext.h" #include "skia/src/image/SkImage_Gpu.h" #endif @@ -270,6 +268,7 @@ DrawTargetSkia::DrawTargetSkia() , mColorSpace(nullptr) , mCanvasData(nullptr) , mCGSize(0, 0) + , mNeedLayer(false) #endif { } @@ -302,7 +301,7 @@ DrawTargetSkia::Snapshot() if (mSurface->peekPixels(&pixmap)) { image = SkImage::MakeFromRaster(pixmap, nullptr, nullptr); } else { - image = mSurface->makeImageSnapshot(SkBudgeted::kNo); + image = mSurface->makeImageSnapshot(); } if (!snapshot->InitFromImage(image, mFormat, this)) { return nullptr; @@ -318,23 +317,13 @@ DrawTargetSkia::LockBits(uint8_t** aData, IntSize* aSize, int32_t* aStride, SurfaceFormat* aFormat, IntPoint* aOrigin) { - // Ensure the layer is at the origin if required. - SkIPoint origin = mCanvas->getTopDevice()->getOrigin(); - if (!aOrigin && !origin.isZero()) { - return false; - } - - /* Test if the canvas' device has accessible pixels first, as actually - * accessing the pixels may trigger side-effects, even if it fails. - */ - if (!mCanvas->peekPixels(nullptr)) { - return false; - } - SkImageInfo info; size_t rowBytes; - void* pixels = mCanvas->accessTopLayerPixels(&info, &rowBytes); - if (!pixels) { + SkIPoint origin; + void* pixels = mCanvas->accessTopLayerPixels(&info, &rowBytes, &origin); + if (!pixels || + // Ensure the layer is at the origin if required. + (!aOrigin && !origin.isZero())) { return false; } @@ -459,7 +448,11 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0, Po &stops->mPositions.front(), stops->mCount, mode, 0, &mat); - aPaint.setShader(shader); + if (shader) { + aPaint.setShader(shader); + } else { + aPaint.setColor(SK_ColorTRANSPARENT); + } } break; } @@ -487,7 +480,11 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0, Po &stops->mPositions.front(), stops->mCount, mode, 0, &mat); - aPaint.setShader(shader); + if (shader) { + aPaint.setShader(shader); + } else { + aPaint.setColor(SK_ColorTRANSPARENT); + } } break; } @@ -528,7 +525,7 @@ GetClipBounds(SkCanvas *aCanvas) // getClipBounds because getClipBounds inflates the the bounds // by a pixel in each direction to compensate for antialiasing. SkIRect deviceBounds; - if (!aCanvas->getClipDeviceBounds(&deviceBounds)) { + if (!aCanvas->getDeviceClipBounds(&deviceBounds)) { return Rect(); } SkMatrix inverseCTM; @@ -631,7 +628,7 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface, bool forceGroup = SkImageIsMask(image) && aOptions.mCompositionOp != CompositionOp::OP_OVER; - AutoPaintSetup paint(mCanvas.get(), aOptions, &aDest, forceGroup); + AutoPaintSetup paint(mCanvas, aOptions, &aDest, forceGroup); if (aSurfOptions.mSamplingFilter == SamplingFilter::POINT) { paint.mPaint.setFilterQuality(kNone_SkFilterQuality); } @@ -774,7 +771,7 @@ DrawTargetSkia::FillRect(const Rect &aRect, MarkChanged(); SkRect rect = RectToSkRect(aRect); - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern, &aRect, Point(0, 0), &aRect); + AutoPaintSetup paint(mCanvas, aOptions, aPattern, &aRect, Point(0, 0), &aRect); mCanvas->drawRect(rect, paint.mPaint); } @@ -794,7 +791,7 @@ DrawTargetSkia::Stroke(const Path *aPath, const PathSkia *skiaPath = static_cast(aPath); - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + AutoPaintSetup paint(mCanvas, aOptions, aPattern); if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) { return; } @@ -883,7 +880,7 @@ DrawTargetSkia::StrokeRect(const Rect &aRect, if (aStrokeOptions.mDashLength > 0 && !rect.IsEmpty()) { IntRect deviceClip(IntPoint(0, 0), mSize); SkIRect clipBounds; - if (mCanvas->getClipDeviceBounds(&clipBounds)) { + if (mCanvas->getDeviceClipBounds(&clipBounds)) { deviceClip = SkIRectToIntRect(clipBounds); } rect = ShrinkClippedStrokedRect(rect, deviceClip, mTransform, aStrokeOptions); @@ -893,7 +890,7 @@ DrawTargetSkia::StrokeRect(const Rect &aRect, } MarkChanged(); - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + AutoPaintSetup paint(mCanvas, aOptions, aPattern); if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) { return; } @@ -909,7 +906,7 @@ DrawTargetSkia::StrokeLine(const Point &aStart, const DrawOptions &aOptions) { MarkChanged(); - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + AutoPaintSetup paint(mCanvas, aOptions, aPattern); if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) { return; } @@ -931,7 +928,7 @@ DrawTargetSkia::Fill(const Path *aPath, const PathSkia *skiaPath = static_cast(aPath); - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + AutoPaintSetup paint(mCanvas, aOptions, aPattern); if (!skiaPath->GetPath().isFinite()) { return; @@ -964,116 +961,6 @@ DrawTargetSkia::ShouldLCDRenderText(FontType aFontType, AntialiasMode aAntialias } #ifdef MOZ_WIDGET_COCOA -class CGClipApply : public SkCanvas::ClipVisitor { -public: - explicit CGClipApply(CGContextRef aCGContext) - : mCG(aCGContext) {} - void clipRect(const SkRect& aRect, SkCanvas::ClipOp op, bool antialias) override { - CGRect rect = CGRectMake(aRect.x(), aRect.y(), aRect.width(), aRect.height()); - CGContextClipToRect(mCG, rect); - } - - void clipRRect(const SkRRect& rrect, SkCanvas::ClipOp op, bool antialias) override { - SkPath path; - path.addRRect(rrect); - clipPath(path, op, antialias); - } - - void clipPath(const SkPath& aPath, SkCanvas::ClipOp, bool antialias) override { - SkPath::Iter iter(aPath, true); - SkPoint source[4]; - SkPath::Verb verb; - - if (!aPath.isFinite()) { - return; - } - - if (aPath.isEmpty()) { - // Weirdly, CoreGraphics clips empty paths as all shown - // but empty rects as all clipped. We detect this situation and - // workaround it appropriately - CGContextClipToRect(mCG, CGRectZero); - return; - } - - CGMutablePathRef cgPath = CGPathCreateMutable(); - MOZ_ASSERT(cgPath); - - while ((verb = iter.next(source)) != SkPath::kDone_Verb) { - switch (verb) { - case SkPath::kMove_Verb: - { - SkPoint dest = source[0]; - CGPathMoveToPoint(cgPath, nullptr, dest.fX, dest.fY); - break; - } - case SkPath::kLine_Verb: - { - // The first point should be the end point of whatever - // verb we got to get here. - SkPoint second = source[1]; - MOZ_ASSERT(!CGPathIsEmpty(cgPath)); - CGPathAddLineToPoint(cgPath, nullptr, second.fX, second.fY); - break; - } - case SkPath::kQuad_Verb: - { - SkPoint second = source[1]; - SkPoint third = source[2]; - - MOZ_ASSERT(!CGPathIsEmpty(cgPath)); - CGPathAddQuadCurveToPoint(cgPath, nullptr, - second.fX, second.fY, - third.fX, third.fY); - break; - } - case SkPath::kCubic_Verb: - { - SkPoint second = source[1]; - SkPoint third = source[2]; - SkPoint fourth = source[2]; - - MOZ_ASSERT(!CGPathIsEmpty(cgPath)); - CGPathAddCurveToPoint(cgPath, nullptr, - second.fX, second.fY, - third.fX, third.fY, - fourth.fX, fourth.fY); - break; - } - case SkPath::kClose_Verb: - { - if (!CGPathIsEmpty(cgPath)) { - CGPathCloseSubpath(cgPath); - } - break; - } - default: - { - SkDEBUGFAIL("unknown verb"); - break; - } - } // end switch - } // end while - - MOZ_ASSERT(!CGPathIsEmpty(cgPath)); - - CGContextBeginPath(mCG); - CGContextAddPath(mCG, cgPath); - - FillRule fillRule = GetFillRule(aPath.getFillType()); - if (fillRule == FillRule::FILL_EVEN_ODD) { - CGContextEOClip(mCG); - } else { - CGContextClip(mCG); - } - - CGPathRelease(cgPath); - } - -private: - CGContextRef mCG; -}; - static inline CGAffineTransform GfxMatrixToCGAffineTransform(const Matrix &m) { @@ -1142,7 +1029,7 @@ GfxMatrixToCGAffineTransform(const Matrix &m) static bool SetupCGContext(DrawTargetSkia* aDT, CGContextRef aCGContext, - sk_sp aCanvas, + SkCanvas* aCanvas, const IntPoint& aOrigin, const IntSize& aSize) { @@ -1157,10 +1044,15 @@ SetupCGContext(DrawTargetSkia* aDT, // Want to apply clips BEFORE the transform since the transform // will apply to the clips we apply. - // CGClipApply applies clips in device space, so it would be a mistake - // to transform these clips. - CGClipApply clipApply(aCGContext); - aCanvas->replayClips(&clipApply); + SkIRect clipBounds; + if (!aCanvas->getDeviceClipBounds(&clipBounds)) { + clipBounds = SkIRect::MakeXYWH(aOrigin.x, aOrigin.y, + aSize.width, aSize.height); + } + + CGContextClipToRect(aCGContext, + CGRectMake(clipBounds.x(), clipBounds.y(), + clipBounds.width(), clipBounds.height())); CGContextConcatCTM(aCGContext, GfxMatrixToCGAffineTransform(aDT->GetTransform())); return true; @@ -1196,24 +1088,34 @@ SetupCGGlyphs(CGContextRef aCGContext, // next to each other. // The context returned from this method will have the origin -// in the top left and will hvae applied all the neccessary clips +// in the top left and will have applied all the neccessary clips // and transforms to the CGContext. See the comment above // SetupCGContext. CGContextRef DrawTargetSkia::BorrowCGContext(const DrawOptions &aOptions) { + // Since we can't replay Skia clips, we have to use a layer if we have a complex clip. + // After saving a layer, the SkCanvas queries for needing a layer change so save if we + // pushed a layer. + mNeedLayer = !mCanvas->isClipEmpty() && !mCanvas->isClipRect(); + if (mNeedLayer) { + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); + SkCanvas::SaveLayerRec rec(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag); + mCanvas->saveLayer(rec); + } + + uint8_t* data = nullptr; int32_t stride; SurfaceFormat format; IntSize size; IntPoint origin; - - uint8_t* aSurfaceData = nullptr; - if (!LockBits(&aSurfaceData, &size, &stride, &format, &origin)) { + if (!LockBits(&data, &size, &stride, &format, &origin)) { NS_WARNING("Could not lock skia bits to wrap CG around"); return nullptr; } - if ((aSurfaceData == mCanvasData) && mCG && (mCGSize == size)) { + if (!mNeedLayer && (data == mCanvasData) && mCG && (mCGSize == size)) { // If our canvas data still points to the same data, // we can reuse the CG Context CGContextSaveGState(mCG); @@ -1232,7 +1134,7 @@ DrawTargetSkia::BorrowCGContext(const DrawOptions &aOptions) CGContextRelease(mCG); } - mCanvasData = aSurfaceData; + mCanvasData = data; mCGSize = size; uint32_t bitmapInfo = (format == SurfaceFormat::A8) ? @@ -1249,6 +1151,9 @@ DrawTargetSkia::BorrowCGContext(const DrawOptions &aOptions) NULL, /* Callback when released */ NULL); if (!mCG) { + if (mNeedLayer) { + mCanvas->restore(); + } ReleaseBits(mCanvasData); NS_WARNING("Could not create bitmap around skia data\n"); return nullptr; @@ -1269,6 +1174,17 @@ DrawTargetSkia::ReturnCGContext(CGContextRef aCGContext) MOZ_ASSERT(aCGContext == mCG); ReleaseBits(mCanvasData); CGContextRestoreGState(aCGContext); + + if (mNeedLayer) { + // A layer was used for clipping and is about to be popped by the restore. + // Make sure the CG context referencing it is released first so the popped + // layer doesn't accidentally get used. + if (mCG) { + CGContextRelease(mCG); + mCG = nullptr; + } + mCanvas->restore(); + } } CGContextRef @@ -1432,7 +1348,7 @@ DrawTargetSkia::DrawGlyphs(ScaledFont* aFont, return; } - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + AutoPaintSetup paint(mCanvas, aOptions, aPattern); if (aStrokeOptions && !StrokeOptionsToPaint(paint.mPaint, *aStrokeOptions)) { return; @@ -1552,7 +1468,7 @@ DrawTargetSkia::Mask(const Pattern &aSource, const DrawOptions &aOptions) { MarkChanged(); - AutoPaintSetup paint(mCanvas.get(), aOptions, aSource); + AutoPaintSetup paint(mCanvas, aOptions, aSource); SkPaint maskPaint; SetPaintPattern(maskPaint, aMask); @@ -1572,7 +1488,7 @@ DrawTargetSkia::MaskSurface(const Pattern &aSource, const DrawOptions &aOptions) { MarkChanged(); - AutoPaintSetup paint(mCanvas.get(), aOptions, aSource, nullptr, -aOffset); + AutoPaintSetup paint(mCanvas, aOptions, aSource, nullptr, -aOffset); sk_sp alphaMask = ExtractAlphaForSurface(aMask); if (!alphaMask) { @@ -1618,8 +1534,8 @@ DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& a if (!dstSurf) { return false; } - sk_sp dstCanvas( - SkCanvas::NewRasterDirect( + std::unique_ptr dstCanvas( + SkCanvas::MakeRasterDirect( SkImageInfo::Make(xformBounds.width, xformBounds.height, GfxFormatToSkiaColorType(dstSurf->GetFormat()), kPremul_SkAlphaType), @@ -1716,7 +1632,7 @@ DrawTargetSkia::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFor #endif #ifdef DEBUG - if (!IsBackedByPixels(mCanvas.get())) { + if (!IsBackedByPixels(mCanvas)) { // If our canvas is backed by vector storage such as PDF then we want to // create a new DrawTarget with similar storage to avoid losing fidelity // (fidelity will be lost if the returned DT is Snapshot()'ed and drawn @@ -1753,7 +1669,7 @@ DrawTargetSkia::OptimizeGPUSourceSurface(SourceSurface *aSurface) const } // Upload the SkImage to a GrTexture otherwise. - sk_sp texture = image->makeTextureImage(mGrContext.get()); + sk_sp texture = image->makeTextureImage(mGrContext.get(), nullptr); if (texture) { // Create a new SourceSurfaceSkia whose SkImage contains the GrTexture. RefPtr surface = new SourceSurfaceSkia(); @@ -1870,7 +1786,7 @@ DrawTargetSkia::CopySurface(SourceSurface *aSurface, mCanvas->save(); mCanvas->setMatrix(SkMatrix::MakeTrans(SkIntToScalar(aDestination.x), SkIntToScalar(aDestination.y))); - mCanvas->clipRect(SkRect::MakeIWH(aSourceRect.width, aSourceRect.height), kReplace_SkClipOp); + mCanvas->clipRect(SkRect::MakeIWH(aSourceRect.width, aSourceRect.height), SkClipOp::kReplace_deprecated); SkPaint paint; if (!image->isOpaque()) { @@ -1904,7 +1820,7 @@ DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat) mSize = aSize; mFormat = aFormat; - mCanvas = sk_ref_sp(mSurface->getCanvas()); + mCanvas = mSurface->getCanvas(); SetPermitSubpixelAA(IsOpaque(mFormat)); if (info.isOpaque()) { @@ -1916,13 +1832,13 @@ DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat) bool DrawTargetSkia::Init(SkCanvas* aCanvas) { - mCanvas = sk_ref_sp(aCanvas); + mCanvas = aCanvas; SkImageInfo imageInfo = mCanvas->imageInfo(); // If the canvas is backed by pixels we clear it to be on the safe side. If // it's not (for example, for PDF output) we don't. - if (IsBackedByPixels(mCanvas.get())) { + if (IsBackedByPixels(mCanvas)) { SkColor clearColor = imageInfo.isOpaque() ? SK_ColorBLACK : SK_ColorTRANSPARENT; mCanvas->clear(clearColor); } @@ -1969,7 +1885,7 @@ DrawTargetSkia::InitWithGrContext(GrContext* aGrContext, } // Create a GPU rendertarget/texture using the supplied GrContext. - // NewRenderTarget also implicitly clears the underlying texture on creation. + // MakeRenderTarget also implicitly clears the underlying texture on creation. mSurface = SkSurface::MakeRenderTarget(aGrContext, SkBudgeted(aCached), @@ -1981,7 +1897,7 @@ DrawTargetSkia::InitWithGrContext(GrContext* aGrContext, mGrContext = sk_ref_sp(aGrContext); mSize = aSize; mFormat = aFormat; - mCanvas = sk_ref_sp(mSurface->getCanvas()); + mCanvas = mSurface->getCanvas(); SetPermitSubpixelAA(IsOpaque(mFormat)); return true; } @@ -2001,7 +1917,7 @@ DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride mSize = aSize; mFormat = aFormat; - mCanvas = sk_ref_sp(mSurface->getCanvas()); + mCanvas = mSurface->getCanvas(); SetPermitSubpixelAA(IsOpaque(mFormat)); return true; } @@ -2041,7 +1957,7 @@ DrawTargetSkia::ClearRect(const Rect &aRect) { MarkChanged(); mCanvas->save(); - mCanvas->clipRect(RectToSkRect(aRect), kIntersect_SkClipOp, true); + mCanvas->clipRect(RectToSkRect(aRect), SkClipOp::kIntersect, true); SkColor clearColor = (mFormat == SurfaceFormat::B8G8R8X8) ? SK_ColorBLACK : SK_ColorTRANSPARENT; mCanvas->clear(clearColor); mCanvas->restore(); @@ -2056,7 +1972,7 @@ DrawTargetSkia::PushClip(const Path *aPath) const PathSkia *skiaPath = static_cast(aPath); mCanvas->save(); - mCanvas->clipPath(skiaPath->GetPath(), kIntersect_SkClipOp, true); + mCanvas->clipPath(skiaPath->GetPath(), SkClipOp::kIntersect, true); } void @@ -2072,7 +1988,7 @@ DrawTargetSkia::PushDeviceSpaceClipRects(const IntRect* aRects, uint32_t aCount) // this region by the current transform, unlike the other SkCanvas // clip methods, so it is just passed through in device-space. mCanvas->save(); - mCanvas->clipRegion(region, kIntersect_SkClipOp); + mCanvas->clipRegion(region, SkClipOp::kIntersect); } void @@ -2081,7 +1997,7 @@ DrawTargetSkia::PushClipRect(const Rect& aRect) SkRect rect = RectToSkRect(aRect); mCanvas->save(); - mCanvas->clipRect(rect, kIntersect_SkClipOp, true); + mCanvas->clipRect(rect, SkClipOp::kIntersect, true); } void @@ -2090,40 +2006,6 @@ DrawTargetSkia::PopClip() mCanvas->restore(); } -// Image filter that just passes the source through to the result unmodified. -class CopyLayerImageFilter : public SkImageFilter -{ -public: - CopyLayerImageFilter() - : SkImageFilter(nullptr, 0, nullptr) - {} - - sk_sp onFilterImage(SkSpecialImage* source, - const Context& ctx, - SkIPoint* offset) const override { - offset->set(0, 0); - return sk_ref_sp(source); - } - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(CopyLayerImageFilter) -}; - -sk_sp -CopyLayerImageFilter::CreateProc(SkReadBuffer& buffer) -{ - SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0); - return sk_make_sp(); -} - -#ifndef SK_IGNORE_TO_STRING -void -CopyLayerImageFilter::toString(SkString* str) const -{ - str->append("CopyLayerImageFilter: ()"); -} -#endif - void DrawTargetSkia::PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask, const Matrix& aMaskTransform, const IntRect& aBounds, @@ -2150,13 +2032,11 @@ DrawTargetSkia::PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask, } } - sk_sp backdrop(aCopyBackground ? new CopyLayerImageFilter : nullptr); - SkCanvas::SaveLayerRec saveRec(aBounds.IsEmpty() ? nullptr : &bounds, &paint, - backdrop.get(), SkCanvas::kPreserveLCDText_SaveLayerFlag | - (aOpaque ? SkCanvas::kIsOpaque_SaveLayerFlag : 0)); + (aOpaque ? SkCanvas::kIsOpaque_SaveLayerFlag : 0) | + (aCopyBackground ? SkCanvas::kInitWithPrevious_SaveLayerFlag : 0)); mCanvas->saveLayer(saveRec); @@ -2190,10 +2070,10 @@ DrawTargetSkia::PopLayer() if (layerDevice->peekPixels(&layerPixmap)) { layerImage = SkImage::MakeFromRaster(layerPixmap, nullptr, nullptr); #ifdef USE_SKIA_GPU - } else if (GrDrawContext* drawCtx = mCanvas->internal_private_accessTopLayerDrawContext()) { + } else if (GrRenderTargetContext* drawCtx = mCanvas->internal_private_accessTopLayerRenderTargetContext()) { drawCtx->prepareForExternalIO(); - if (GrTexture* tex = drawCtx->accessRenderTarget()->asTexture()) { - layerImage = sk_make_sp(layerBounds.width(), layerBounds.height(), + if (sk_sp tex = drawCtx->asTextureProxyRef()) { + layerImage = sk_make_sp(mGrContext.get(), kNeedNewImageUniqueID, layerDevice->imageInfo().alphaType(), tex, nullptr, SkBudgeted::kNo); diff --git a/gfx/2d/DrawTargetSkia.h b/gfx/2d/DrawTargetSkia.h index 91e17bd041f2..7e6028d1dcdd 100644 --- a/gfx/2d/DrawTargetSkia.h +++ b/gfx/2d/DrawTargetSkia.h @@ -205,7 +205,7 @@ private: IntSize mSize; sk_sp mSurface; - sk_sp mCanvas; + SkCanvas* mCanvas; SourceSurfaceSkia* mSnapshot; #ifdef MOZ_WIDGET_COCOA @@ -223,6 +223,7 @@ private: CGColorSpaceRef mColorSpace; uint8_t* mCanvasData; IntSize mCGSize; + bool mNeedLayer; #endif }; diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index e9aff64e95f9..771f543387e9 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -594,6 +594,7 @@ GLContext::InitWithPrefixImpl(const char* prefix, bool trygl) { (PRFuncPtr*) &mSymbols.fLoadIdentity, { "LoadIdentity", nullptr } }, { (PRFuncPtr*) &mSymbols.fLoadMatrixf, { "LoadMatrixf", nullptr } }, { (PRFuncPtr*) &mSymbols.fMatrixMode, { "MatrixMode", nullptr } }, + { (PRFuncPtr*) &mSymbols.fPolygonMode, { "PolygonMode", nullptr } }, { (PRFuncPtr*) &mSymbols.fTexGeni, { "TexGeni", nullptr } }, { (PRFuncPtr*) &mSymbols.fTexGenf, { "TexGenf", nullptr } }, { (PRFuncPtr*) &mSymbols.fTexGenfv, { "TexGenfv", nullptr } }, diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index a93faa573fc2..5cd81e2116ab 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -1459,6 +1459,12 @@ public: AFTER_GL_CALL; } + void fPolygonMode(GLenum face, GLenum mode) { + BEFORE_GL_CALL; + mSymbols.fPolygonMode(face, mode); + AFTER_GL_CALL; + } + void fPolygonOffset(GLfloat factor, GLfloat bias) { BEFORE_GL_CALL; mSymbols.fPolygonOffset(factor, bias); diff --git a/gfx/gl/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h index 61069e3f7369..5a4cda8369ad 100644 --- a/gfx/gl/GLContextSymbols.h +++ b/gfx/gl/GLContextSymbols.h @@ -203,6 +203,8 @@ struct GLContextSymbols PFNGLPIXELSTOREIPROC fPixelStorei; typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); PFNGLPOINTPARAMETERFPROC fPointParameterf; + typedef void (GLAPIENTRY * PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode); + PFNGLPOLYGONMODEPROC fPolygonMode; typedef void (GLAPIENTRY * PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat bias); PFNGLPOLYGONOFFSETPROC fPolygonOffset; typedef void (GLAPIENTRY * PFNGLREADBUFFERPROC) (GLenum); diff --git a/gfx/gl/SkiaGLGlue.cpp b/gfx/gl/SkiaGLGlue.cpp index 8cf7a448570a..9e29de7c9895 100755 --- a/gfx/gl/SkiaGLGlue.cpp +++ b/gfx/gl/SkiaGLGlue.cpp @@ -221,6 +221,7 @@ static GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context) i->fFunctions.fLineWidth = WrapGL(context, &GLContext::fLineWidth); i->fFunctions.fLinkProgram = WrapGL(context, &GLContext::fLinkProgram); i->fFunctions.fPixelStorei = WrapGL(context, &GLContext::fPixelStorei); + i->fFunctions.fPolygonMode = WrapGL(context, &GLContext::fPolygonMode); i->fFunctions.fReadPixels = WrapGL(context, &GLContext::fReadPixels); i->fFunctions.fRenderbufferStorage = WrapGL(context, &GLContext::fRenderbufferStorage); i->fFunctions.fScissor = WrapGL(context, &GLContext::fScissor); diff --git a/gfx/layers/apz/test/reftest/reftest.list b/gfx/layers/apz/test/reftest/reftest.list index d1ce8c233663..d0c1951ba26b 100644 --- a/gfx/layers/apz/test/reftest/reftest.list +++ b/gfx/layers/apz/test/reftest/reftest.list @@ -11,7 +11,7 @@ fuzzy-if(Android,3,7) skip-if(!Android) pref(apz.allow_zooming,true) fails-if(st # compositor, the border-radius ends of the scrollthumb are going to be a little # off, hence the fuzzy-if clauses. fuzzy-if(Android,54,18) skip-if(!Android) pref(apz.allow_zooming,true) == async-scrollbar-zoom-1.html async-scrollbar-zoom-1-ref.html -fuzzy-if(Android,45,21) skip-if(!Android) pref(apz.allow_zooming,true) == async-scrollbar-zoom-2.html async-scrollbar-zoom-2-ref.html +fuzzy-if(Android,45,22) skip-if(!Android) pref(apz.allow_zooming,true) == async-scrollbar-zoom-2.html async-scrollbar-zoom-2-ref.html # Meta-viewport tag support skip-if(!Android) pref(apz.allow_zooming,true) == initial-scale-1.html initial-scale-1-ref.html diff --git a/gfx/layers/composite/PaintCounter.cpp b/gfx/layers/composite/PaintCounter.cpp index 56e57aab45a3..a8f619fed9c3 100644 --- a/gfx/layers/composite/PaintCounter.cpp +++ b/gfx/layers/composite/PaintCounter.cpp @@ -29,9 +29,9 @@ PaintCounter::PaintCounter() mSurface = Factory::CreateDataSourceSurface(mRect.Size(), mFormat); mStride = mSurface->Stride(); - mCanvas.reset( - SkCanvas::NewRasterDirect(MakeSkiaImageInfo(mRect.Size(), mFormat), - mSurface->GetData(), mStride)); + mCanvas = + SkCanvas::MakeRasterDirect(MakeSkiaImageInfo(mRect.Size(), mFormat), + mSurface->GetData(), mStride); mCanvas->clear(SK_ColorWHITE); } diff --git a/gfx/layers/composite/PaintCounter.h b/gfx/layers/composite/PaintCounter.h index b5296939fc2f..c4429d409de4 100644 --- a/gfx/layers/composite/PaintCounter.h +++ b/gfx/layers/composite/PaintCounter.h @@ -33,7 +33,7 @@ private: virtual ~PaintCounter(); SurfaceFormat mFormat; - sk_sp mCanvas; + std::unique_ptr mCanvas; IntSize mSize; int mStride; diff --git a/gfx/skia/README_MOZILLA b/gfx/skia/README_MOZILLA index bf5989d0da47..17b6048208c0 100644 --- a/gfx/skia/README_MOZILLA +++ b/gfx/skia/README_MOZILLA @@ -2,9 +2,9 @@ This is an import of Skia. See skia/include/core/SkMilestone.h for the milestone To update to a new version of Skia: -- Clone Skia from upstream using the instructions here: https://sites.google.com/site/skiadocs/user-documentation/downloading +- Clone Skia from upstream using the instructions here: https://skia.org/user/download - Copy the entire source tree from a Skia clone to mozilla-central/gfx/skia/skia -- cd gfx/skia && ./gyp_mozbuild +- cd gfx/skia && ./generate_mozbuild.py Once that's done, use git status to view the files that have changed. Keep an eye on GrUserConfig.h and SkUserConfig.h as those probably don't want to be overwritten by upstream versions. diff --git a/gfx/skia/dump_mozbuild.py b/gfx/skia/dump_mozbuild.py deleted file mode 100644 index b5d40a65dcc7..000000000000 --- a/gfx/skia/dump_mozbuild.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (c) 2012 Google Inc. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import collections -import os -import gyp -import gyp.common -import gyp.msvs_emulation -import json -import sys - -generator_supports_multiple_toolsets = True - -generator_wants_static_library_dependencies_adjusted = False - -generator_default_variables = { -} -for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR', - 'LIB_DIR', 'SHARED_LIB_DIR']: - # Some gyp steps fail if these are empty(!). - generator_default_variables[dirname] = 'dir' -for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME', - 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT', - 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX', - 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX', - 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX', - 'CONFIGURATION_NAME']: - generator_default_variables[unused] = '' - - -def CalculateVariables(default_variables, params): - generator_flags = params.get('generator_flags', {}) - for key, val in generator_flags.items(): - default_variables.setdefault(key, val) - default_variables.setdefault('OS', gyp.common.GetFlavor(params)) - - flavor = gyp.common.GetFlavor(params) - if flavor =='win': - # Copy additional generator configuration data from VS, which is shared - # by the Windows Ninja generator. - import gyp.generator.msvs as msvs_generator - generator_additional_non_configuration_keys = getattr(msvs_generator, - 'generator_additional_non_configuration_keys', []) - generator_additional_path_sections = getattr(msvs_generator, - 'generator_additional_path_sections', []) - - gyp.msvs_emulation.CalculateCommonVariables(default_variables, params) - - -def CalculateGeneratorInputInfo(params): - """Calculate the generator specific info that gets fed to input (called by - gyp).""" - generator_flags = params.get('generator_flags', {}) - if generator_flags.get('adjust_static_libraries', False): - global generator_wants_static_library_dependencies_adjusted - generator_wants_static_library_dependencies_adjusted = True - -def GetOS(params): - for d in params['defines']: - pass - -def GenerateOutput(target_list, target_dicts, data, params): - # Map of target -> list of targets it depends on. - edges = {} - - # Queue of targets to visit. - targets_to_visit = target_list[:] - - sources = []; - - while len(targets_to_visit) > 0: - target = targets_to_visit.pop() - if target in edges: - continue - edges[target] = [] - - target_sources = target_dicts[target].get('sources') - if target_sources: - for source in target_sources: - if source.endswith('.cpp'): - sources.append(source) - - for dep in target_dicts[target].get('dependencies', []): - edges[target].append(dep) - targets_to_visit.append(dep) - - skia_os = data['gyp/core.gyp']['variables']['skia_os%'] - - f = open('sources.json', 'w') - json.dump(sources, f) - f.close() \ No newline at end of file diff --git a/gfx/skia/generate_mozbuild.py b/gfx/skia/generate_mozbuild.py index e06ae3457a47..e5f85fa73eed 100755 --- a/gfx/skia/generate_mozbuild.py +++ b/gfx/skia/generate_mozbuild.py @@ -1,8 +1,7 @@ #!/usr/bin/env python -import os - import locale +import subprocess from collections import defaultdict locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') @@ -44,7 +43,6 @@ LOCAL_INCLUDES += [ 'skia/include/core', 'skia/include/effects', 'skia/include/gpu', - 'skia/include/images', 'skia/include/pathops', 'skia/include/ports', 'skia/include/private', @@ -55,27 +53,17 @@ LOCAL_INCLUDES += [ 'skia/src/gpu', 'skia/src/gpu/effects', 'skia/src/gpu/gl', + 'skia/src/gpu/glsl', 'skia/src/image', 'skia/src/lazy', 'skia/src/opts', 'skia/src/sfnt', + 'skia/src/sksl', 'skia/src/utils', 'skia/src/utils/mac', 'skia/src/utils/win', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android'): - DEFINES['SK_FONTHOST_CAIRO_STANDALONE'] = 0 - -if CONFIG['MOZ_WIDGET_TOOLKIT'] in { - 'android', - 'cocoa', - 'gtk2', - 'gtk3', - 'uikit', - }: - DEFINES['SK_FONTHOST_DOES_NOT_USE_FONTMGR'] = 1 - if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': DEFINES['UNICODE'] = True DEFINES['_UNICODE'] = True @@ -86,19 +74,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': # We should autogenerate these SSE related flags. -if CONFIG['_MSC_VER']: - # MSVC doesn't need special compiler flags, but Skia needs to be told that these files should - # be built with the required SSE level or it will simply compile in stubs and cause runtime crashes - SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20'] - SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20'] - SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=31'] - SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20'] - SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=31'] - SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=41'] - SOURCES['skia/src/opts/SkOpts_sse42.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=42'] - SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=51'] if CONFIG['INTEL_ARCHITECTURE'] and (CONFIG['GNU_CC'] or CONFIG['CLANG_CL']): - SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-mssse3'] SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] @@ -106,8 +82,20 @@ if CONFIG['INTEL_ARCHITECTURE'] and (CONFIG['GNU_CC'] or CONFIG['CLANG_CL']): SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-msse4.1'] SOURCES['skia/src/opts/SkOpts_sse42.cpp'].flags += ['-msse4.2'] SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-mavx'] -elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC'] and CONFIG['BUILD_ARM_NEON']: - DEFINES['SK_ARM_HAS_OPTIONAL_NEON'] = 1 + SOURCES['skia/src/opts/SkOpts_hsw.cpp'].flags += ['-mavx2'] +elif CONFIG['_MSC_VER']: + # MSVC doesn't need special compiler flags, but Skia needs to be told that these files should + # be built with the required SSE level or it will simply compile in stubs and cause runtime crashes + SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20'] + SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=31'] + SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20'] + SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=31'] + SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=41'] + SOURCES['skia/src/opts/SkOpts_sse42.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=42'] + SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=51'] + SOURCES['skia/src/opts/SkOpts_hsw.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=52'] +elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']: + CXXFLAGS += CONFIG['NEON_FLAGS'] DEFINES['SKIA_IMPLEMENTATION'] = 1 @@ -158,12 +146,22 @@ import json platforms = ['linux', 'mac', 'android', 'win'] +def parse_sources(output): + return set(v.replace('//', 'skia/') for v in output.split() if v.endswith('.cpp') or v.endswith('.S')) + def generate_opt_sources(): - opt_sources = {'opts': {''}} - for root, dirs, files in os.walk('skia/src/opts'): - for name in files: - if name.endswith('.cpp'): - opt_sources['opts'].add(os.path.join(root, name)) + cpus = [('intel', 'x86', [':sse2', ':ssse3', ':sse41', ':sse42', ':avx', ':hsw']), + ('arm', 'arm', [':armv7']), + ('none', 'none', [':none'])] + + opt_sources = {} + for key, cpu, deps in cpus: + subprocess.check_output('cd skia && bin/gn gen out/{0} --args=\'target_cpu="{1}"\''.format(key, cpu), shell=True) + opt_sources[key] = set() + for dep in deps: + output = subprocess.check_output('cd skia && bin/gn desc out/{0} {1} sources'.format(key, dep), shell=True) + if output: + opt_sources[key].update(parse_sources(output)) return opt_sources @@ -171,33 +169,25 @@ def generate_platform_sources(): sources = {} for plat in platforms: - if os.system("cd skia && GYP_GENERATORS=dump_mozbuild ./gyp_skia -D OS=%s -D host_os=linux gyp/skia_lib.gyp" % plat) != 0: - print 'Failed to generate sources for ' + plat - continue + output = subprocess.check_output('cd skia && bin/gn gen out/{0} --args=\'target_os="{0}"\' > /dev/null && bin/gn desc out/{0} :skia sources'.format(plat), shell=True) + if output: + sources[plat] = parse_sources(output) - - f = open('skia/sources.json'); - sources[plat] = set(v.replace('../', 'skia/') for v in json.load(f)); - f.close() + deps = {':effects' : 'common', ':gpu' : 'gpu', ':pdf' : 'pdf'} + for dep, key in deps.items(): + output = subprocess.check_output('cd skia && bin/gn desc out/linux {} sources'.format(dep), shell=True) + if output: + sources[key] = parse_sources(output) return dict(sources.items() + generate_opt_sources().items()) def generate_separated_sources(platform_sources): blacklist = [ - 'experimental', - 'SkXML', 'GrGLCreateNativeInterface', 'GrGLCreateNullInterface', 'GrGLAssembleInterface', 'GrGLTestInterface', - 'fontconfig', - 'FontConfig', - 'SkThreadUtils_pthread_', - 'SkFontMgr_android', - 'SkFontMgr_custom', - 'SkFontHost_FreeType.cpp', - 'Movie', 'ImageEncoder', 'skia/src/c/', 'skia/src/effects/Gr', @@ -205,7 +195,6 @@ def generate_separated_sources(platform_sources): 'skia/src/fonts/', 'skia/src/images/', 'skia/src/ports/SkImageGenerator', - 'skia/src/sksl/', 'skia/src/gpu/vk/', 'SkBitmapRegion', 'SkLight', @@ -216,11 +205,7 @@ def generate_separated_sources(platform_sources): 'codec', 'SkWGL', 'SkMemory_malloc', - 'SkOpts_', - 'opts_check_x86', 'third_party', - # unused in skia/src/utils - 'SkBoundaryPatch', 'SkCamera', 'SkCanvasStack', 'SkCanvasStateUtils', @@ -229,19 +214,17 @@ def generate_separated_sources(platform_sources): 'SkDumpCanvas', 'SkFrontBufferedStream', 'SkInterpolator', - 'SkLayer', - 'SkMeshUtils', 'SkMD5', 'SkMultiPictureDocument', - 'SkNinePatch', 'SkNullCanvas', 'SkNWayCanvas', + 'SkOverdrawCanvas', 'SkPaintFilterCanvas', 'SkParseColor', - 'SkPatchGrid', - 'SkRTConf', 'SkTextBox', 'SkWhitelistTypefaces', + 'SkXPS', + 'SkCreateCGImageRef', ] def isblacklisted(value): @@ -268,30 +251,20 @@ def generate_separated_sources(platform_sources): # 'skia/src/ports/SkDebug_android.cpp', 'skia/src/ports/SkFontHost_cairo.cpp', # 'skia/src/ports/SkFontHost_FreeType.cpp', - # 'skia/src/ports/SkFontHost_FreeType_common.cpp', + 'skia/src/ports/SkFontHost_FreeType_common.cpp', # 'skia/src/ports/SkTime_Unix.cpp', # 'skia/src/utils/SkThreadUtils_pthread.cpp', }, 'linux': { 'skia/src/ports/SkFontHost_cairo.cpp', + 'skia/src/ports/SkFontHost_FreeType_common.cpp', }, - 'intel': { - # There is currently no x86-specific opt for SkTextureCompression - 'skia/src/opts/opts_check_x86.cpp', - 'skia/src/opts/SkOpts_ssse3.cpp', - 'skia/src/opts/SkOpts_sse41.cpp', - 'skia/src/opts/SkOpts_sse42.cpp', - 'skia/src/opts/SkOpts_avx.cpp', - 'skia/src/opts/SkOpts_hsw.cpp', - }, - 'arm': { - 'skia/src/core/SkUtilsArm.cpp', - }, - 'neon': { - 'skia/src/opts/SkOpts_neon.cpp', - }, + 'intel': set(), + 'arm': set(), 'none': set(), - 'pdf': set(), + 'pdf': { + 'skia/src/core/SkMD5.cpp', + }, 'gpu': set() }) @@ -305,30 +278,12 @@ def generate_separated_sources(platform_sources): key = plat - if '_SSE' in value or '_SSSE' in value: - key = 'intel' - elif '_neon' in value: - key = 'neon' - elif '_arm' in value: - key = 'arm' - elif '_none' in value: - key = 'none' - elif 'gpu' in value or 'Gpu' in value: - key = 'gpu' - elif all(value in platform_sources.get(p, {}) - for p in platforms if p != plat): + if all(value in platform_sources.get(p, {}) + for p in platforms if p != plat): key = 'common' separated[key].add(value) - if os.system("cd skia && GYP_GENERATORS=dump_mozbuild ./gyp_skia -D OS=linux -D host_os=linux -R pdf gyp/pdf.gyp") != 0: - print 'Failed to generate sources for Skia PDF' - else: - f = open('skia/sources.json'); - separated['pdf'].add('skia/src/core/SkMD5.cpp'); - separated['pdf'].update(filter(lambda x: 'pdf' in x, set(v.replace('../', 'skia/') for v in json.load(f)))); - f.close() - return separated def uniq(seq): @@ -383,16 +338,18 @@ unified_blacklist = [ 'SkBlitter_RGB16.cpp', 'SkBlitter_Sprite.cpp', 'SkScan_Antihair.cpp', + 'SkScan_AntiPath.cpp', 'SkParse.cpp', 'SkPDFFont.cpp', 'SkPictureData.cpp', - 'GrDrawContext', 'GrResourceCache', + 'GrResourceProvider', 'GrAA', 'GrGL', - 'GrBatchAtlas.cpp', 'GrMSAAPathRenderer.cpp', 'GrNonAAFillRect', + 'GrPathUtils', + 'GrShadowRRectOp', 'SkColorSpace', 'SkImage_Gpu.cpp', 'SkPathOpsDebug.cpp', @@ -401,6 +358,10 @@ unified_blacklist = [ 'SkMiniRecorder.cpp', 'SkXfermode', 'SkMatrix44.cpp', + 'SkRTree.cpp', + 'SkVertices.cpp', + 'SkJumper', + 'lex.layout.cpp', ] + opt_whitelist def write_sources(f, values, indent): @@ -458,13 +419,13 @@ def write_mozbuild(sources): f.write("if CONFIG['MOZ_ENABLE_SKIA_GPU']:\n") write_sources(f, sources['gpu'], 4) - f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android'):\n") + f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':\n") write_sources(f, sources['android'], 4) - f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in {'cocoa', 'uikit'}:\n") + f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'):\n") write_sources(f, sources['mac'], 4) - f.write("if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:\n") + f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):\n") write_sources(f, sources['linux'], 4) f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':\n") @@ -479,15 +440,6 @@ def write_mozbuild(sources): f.write("elif CONFIG['CPU_ARCH'] in ('arm', 'aarch64') and CONFIG['GNU_CC']:\n") write_sources(f, sources['arm'], 4) write_cflags(f, sources['arm'], opt_whitelist, 'skia_opt_flags', 4) - - f.write(" if CONFIG['CPU_ARCH'] == 'aarch64':\n") - write_sources(f, sources['neon'], 8) - f.write(" elif CONFIG['BUILD_ARM_NEON']:\n") - write_list(f, 'SOURCES', sources['neon'], 8) - write_cflags(f, sources['neon'], 'neon', "CONFIG['NEON_FLAGS']", 8) - - f.write(" if CONFIG['CPU_ARCH'] == 'aarch64' or CONFIG['BUILD_ARM_NEON']:\n") - write_cflags(f, sources['neon'], opt_whitelist, 'skia_opt_flags', 8) f.write("else:\n") write_sources(f, sources['none'], 4) diff --git a/gfx/skia/gyp_mozbuild b/gfx/skia/gyp_mozbuild deleted file mode 100644 index 0cec5f9a6ce0..000000000000 --- a/gfx/skia/gyp_mozbuild +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# Install our generator -cp dump_mozbuild.py skia/third_party/externals/gyp/pylib/gyp/generator - -# pushd skia -# for OS in win linux mac; do -# GYP_GENERATORS=dump_mozbuild ./gyp_skia -D OS=$OS -D arm_neon=0 gyp/effects.gyp -# done -# popd - -./generate_mozbuild.py - diff --git a/gfx/skia/moz.build b/gfx/skia/moz.build index 2118677ca3a8..63f1b2e9c98d 100644 --- a/gfx/skia/moz.build +++ b/gfx/skia/moz.build @@ -25,7 +25,10 @@ if CONFIG['MOZ_OPTIMIZE']: UNIFIED_SOURCES += [ 'skia/src/core/SkAAClip.cpp', 'skia/src/core/SkAlphaRuns.cpp', + 'skia/src/core/SkAnalyticEdge.cpp', 'skia/src/core/SkAnnotation.cpp', + 'skia/src/core/SkArenaAlloc.cpp', + 'skia/src/core/SkATrace.cpp', 'skia/src/core/SkAutoPixmapStorage.cpp', 'skia/src/core/SkBBHFactory.cpp', 'skia/src/core/SkBigPicture.cpp', @@ -40,16 +43,17 @@ UNIFIED_SOURCES += [ 'skia/src/core/SkBuffer.cpp', 'skia/src/core/SkCachedData.cpp', 'skia/src/core/SkCanvas.cpp', - 'skia/src/core/SkChunkAlloc.cpp', 'skia/src/core/SkClipStack.cpp', + 'skia/src/core/SkClipStackDevice.cpp', 'skia/src/core/SkColor.cpp', 'skia/src/core/SkColorFilter.cpp', 'skia/src/core/SkColorFilterShader.cpp', + 'skia/src/core/SkColorLookUpTable.cpp', 'skia/src/core/SkColorMatrixFilterRowMajor255.cpp', 'skia/src/core/SkColorShader.cpp', 'skia/src/core/SkColorTable.cpp', 'skia/src/core/SkComposeShader.cpp', - 'skia/src/core/SkConfig8888.cpp', + 'skia/src/core/SkConvertPixels.cpp', 'skia/src/core/SkConvolver.cpp', 'skia/src/core/SkCpu.cpp', 'skia/src/core/SkCubicClipper.cpp', @@ -69,7 +73,7 @@ UNIFIED_SOURCES += [ 'skia/src/core/SkEdge.cpp', 'skia/src/core/SkEdgeBuilder.cpp', 'skia/src/core/SkEdgeClipper.cpp', - 'skia/src/core/SkError.cpp', + 'skia/src/core/SkExecutor.cpp', 'skia/src/core/SkFilterProc.cpp', 'skia/src/core/SkFlattenable.cpp', 'skia/src/core/SkFlattenableSerialization.cpp', @@ -79,13 +83,13 @@ UNIFIED_SOURCES += [ 'skia/src/core/SkFontMgr.cpp', 'skia/src/core/SkFontStream.cpp', 'skia/src/core/SkFontStyle.cpp', - 'skia/src/core/SkForceCPlusPlusLinking.cpp', 'skia/src/core/SkGeometry.cpp', 'skia/src/core/SkGlobalInitialization_core.cpp', 'skia/src/core/SkGlyphCache.cpp', 'skia/src/core/SkGpuBlurUtils.cpp', 'skia/src/core/SkGraphics.cpp', 'skia/src/core/SkHalf.cpp', + 'skia/src/core/SkICC.cpp', 'skia/src/core/SkImageCacherator.cpp', 'skia/src/core/SkImageFilter.cpp', 'skia/src/core/SkImageFilterCache.cpp', @@ -144,12 +148,11 @@ UNIFIED_SOURCES += [ 'skia/src/core/SkRegion_path.cpp', 'skia/src/core/SkResourceCache.cpp', 'skia/src/core/SkRRect.cpp', - 'skia/src/core/SkRTree.cpp', 'skia/src/core/SkRWBuffer.cpp', 'skia/src/core/SkScalar.cpp', 'skia/src/core/SkScalerContext.cpp', 'skia/src/core/SkScan.cpp', - 'skia/src/core/SkScan_AntiPath.cpp', + 'skia/src/core/SkScan_AAAPath.cpp', 'skia/src/core/SkScan_Hairline.cpp', 'skia/src/core/SkScan_Path.cpp', 'skia/src/core/SkSemaphore.cpp', @@ -169,6 +172,7 @@ UNIFIED_SOURCES += [ 'skia/src/core/SkSwizzle.cpp', 'skia/src/core/SkTaskGroup.cpp', 'skia/src/core/SkTextBlob.cpp', + 'skia/src/core/SkThreadedBMPDevice.cpp', 'skia/src/core/SkThreadID.cpp', 'skia/src/core/SkTime.cpp', 'skia/src/core/SkTLS.cpp', @@ -192,6 +196,9 @@ UNIFIED_SOURCES += [ 'skia/src/effects/gradients/SkRadialGradient.cpp', 'skia/src/effects/gradients/SkSweepGradient.cpp', 'skia/src/effects/gradients/SkTwoPointConicalGradient.cpp', + 'skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp', + 'skia/src/effects/shadows/SkAmbientShadowMaskFilter.cpp', + 'skia/src/effects/shadows/SkSpotShadowMaskFilter.cpp', 'skia/src/effects/SkDashPathEffect.cpp', 'skia/src/effects/SkImageSource.cpp', 'skia/src/effects/SkLayerRasterizer.cpp', @@ -202,7 +209,6 @@ UNIFIED_SOURCES += [ 'skia/src/image/SkSurface.cpp', 'skia/src/image/SkSurface_Raster.cpp', 'skia/src/lazy/SkDiscardableMemoryPool.cpp', - 'skia/src/lazy/SkDiscardablePixelRef.cpp', 'skia/src/pathops/SkAddIntersections.cpp', 'skia/src/pathops/SkDConicLineIntersection.cpp', 'skia/src/pathops/SkDCubicLineIntersection.cpp', @@ -244,18 +250,23 @@ UNIFIED_SOURCES += [ 'skia/src/ports/SkOSFile_stdio.cpp', 'skia/src/sfnt/SkOTTable_name.cpp', 'skia/src/sfnt/SkOTUtils.cpp', + 'skia/src/utils/mac/SkStream_mac.cpp', 'skia/src/utils/SkBase64.cpp', 'skia/src/utils/SkBitmapSourceDeserializer.cpp', 'skia/src/utils/SkDashPath.cpp', 'skia/src/utils/SkEventTracer.cpp', + 'skia/src/utils/SkInsetConvexPolygon.cpp', 'skia/src/utils/SkMatrix22.cpp', - 'skia/src/utils/SkOSFile.cpp', + 'skia/src/utils/SkOSPath.cpp', 'skia/src/utils/SkPatchUtils.cpp', 'skia/src/utils/SkRGBAToYUV.cpp', - 'skia/src/utils/SkTextureCompressor.cpp', - 'skia/src/utils/SkTextureCompressor_ASTC.cpp', - 'skia/src/utils/SkTextureCompressor_LATC.cpp', - 'skia/src/utils/SkTextureCompressor_R11EAC.cpp', + 'skia/src/utils/SkThreadUtils_win.cpp', + 'skia/src/utils/win/SkAutoCoInitialize.cpp', + 'skia/src/utils/win/SkDWrite.cpp', + 'skia/src/utils/win/SkDWriteFontFileStream.cpp', + 'skia/src/utils/win/SkDWriteGeometrySink.cpp', + 'skia/src/utils/win/SkHRESULT.cpp', + 'skia/src/utils/win/SkIStream.cpp', ] SOURCES += [ 'skia/src/core/SkBitmapProcState.cpp', @@ -270,23 +281,33 @@ SOURCES += [ 'skia/src/core/SkBlitter_RGB16.cpp', 'skia/src/core/SkBlitter_Sprite.cpp', 'skia/src/core/SkColorSpace.cpp', + 'skia/src/core/SkColorSpace_A2B.cpp', 'skia/src/core/SkColorSpace_ICC.cpp', + 'skia/src/core/SkColorSpace_XYZ.cpp', 'skia/src/core/SkColorSpaceXform.cpp', + 'skia/src/core/SkColorSpaceXform_A2B.cpp', + 'skia/src/core/SkColorSpaceXformCanvas.cpp', + 'skia/src/core/SkColorSpaceXformer.cpp', 'skia/src/core/SkMatrix.cpp', 'skia/src/core/SkMatrix44.cpp', 'skia/src/core/SkMiniRecorder.cpp', 'skia/src/core/SkOpts.cpp', 'skia/src/core/SkPictureData.cpp', 'skia/src/core/SkRecorder.cpp', + 'skia/src/core/SkRTree.cpp', 'skia/src/core/SkScan_Antihair.cpp', + 'skia/src/core/SkScan_AntiPath.cpp', 'skia/src/core/SkSpriteBlitter4f.cpp', 'skia/src/core/SkSpriteBlitter_ARGB32.cpp', 'skia/src/core/SkSpriteBlitter_RGB16.cpp', + 'skia/src/core/SkVertices.cpp', 'skia/src/core/SkXfermode.cpp', 'skia/src/core/SkXfermode4f.cpp', 'skia/src/core/SkXfermodeF16.cpp', 'skia/src/core/SkXfermodeInterpretation.cpp', 'skia/src/gpu/gl/GrGLCreateNativeInterface_none.cpp', + 'skia/src/jumper/SkJumper.cpp', + 'skia/src/jumper/SkJumper_stages.cpp', 'skia/src/pathops/SkPathOpsDebug.cpp', 'skia/src/utils/SkParse.cpp', 'skia/src/utils/SkParsePath.cpp', @@ -333,52 +354,34 @@ if CONFIG['MOZ_ENABLE_SKIA_PDF']: ] if CONFIG['MOZ_ENABLE_SKIA_GPU']: UNIFIED_SOURCES += [ - 'skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp', - 'skia/src/gpu/batches/GrAnalyticRectBatch.cpp', - 'skia/src/gpu/batches/GrAtlasTextBatch.cpp', - 'skia/src/gpu/batches/GrBatch.cpp', - 'skia/src/gpu/batches/GrCopySurfaceBatch.cpp', - 'skia/src/gpu/batches/GrDashLinePathRenderer.cpp', - 'skia/src/gpu/batches/GrDefaultPathRenderer.cpp', - 'skia/src/gpu/batches/GrDrawAtlasBatch.cpp', - 'skia/src/gpu/batches/GrDrawBatch.cpp', - 'skia/src/gpu/batches/GrDrawPathBatch.cpp', - 'skia/src/gpu/batches/GrDrawVerticesBatch.cpp', - 'skia/src/gpu/batches/GrNinePatch.cpp', - 'skia/src/gpu/batches/GrNonAAStrokeRectBatch.cpp', - 'skia/src/gpu/batches/GrPLSPathRenderer.cpp', - 'skia/src/gpu/batches/GrRectBatchFactory.cpp', - 'skia/src/gpu/batches/GrRegionBatch.cpp', - 'skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp', - 'skia/src/gpu/batches/GrTessellatingPathRenderer.cpp', - 'skia/src/gpu/batches/GrVertexBatch.cpp', 'skia/src/gpu/effects/GrBezierEffect.cpp', 'skia/src/gpu/effects/GrBicubicEffect.cpp', 'skia/src/gpu/effects/GrBitmapTextGeoProc.cpp', + 'skia/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp', 'skia/src/gpu/effects/GrConfigConversionEffect.cpp', 'skia/src/gpu/effects/GrConstColorProcessor.cpp', 'skia/src/gpu/effects/GrConvexPolyEffect.cpp', - 'skia/src/gpu/effects/GrConvolutionEffect.cpp', 'skia/src/gpu/effects/GrCoverageSetOpXP.cpp', 'skia/src/gpu/effects/GrCustomXfermode.cpp', - 'skia/src/gpu/effects/GrDashingEffect.cpp', 'skia/src/gpu/effects/GrDisableColorXP.cpp', 'skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp', 'skia/src/gpu/effects/GrDitherEffect.cpp', - 'skia/src/gpu/effects/GrGammaEffect.cpp', + 'skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp', 'skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp', + 'skia/src/gpu/effects/GrNonlinearColorSpaceXformEffect.cpp', 'skia/src/gpu/effects/GrOvalEffect.cpp', 'skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp', 'skia/src/gpu/effects/GrRRectEffect.cpp', + 'skia/src/gpu/effects/GrShadowGeoProc.cpp', 'skia/src/gpu/effects/GrSimpleTextureEffect.cpp', 'skia/src/gpu/effects/GrSingleTextureEffect.cpp', + 'skia/src/gpu/effects/GrSRGBEffect.cpp', 'skia/src/gpu/effects/GrTextureDomain.cpp', 'skia/src/gpu/effects/GrTextureStripAtlas.cpp', 'skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp', 'skia/src/gpu/effects/GrYUVEffect.cpp', 'skia/src/gpu/GrAuditTrail.cpp', - 'skia/src/gpu/GrBatchFlushState.cpp', - 'skia/src/gpu/GrBatchTest.cpp', + 'skia/src/gpu/GrBitmapTextureMaker.cpp', 'skia/src/gpu/GrBlend.cpp', 'skia/src/gpu/GrBlurUtils.cpp', 'skia/src/gpu/GrBuffer.cpp', @@ -389,8 +392,10 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']: 'skia/src/gpu/GrContext.cpp', 'skia/src/gpu/GrCoordTransform.cpp', 'skia/src/gpu/GrDefaultGeoProcFactory.cpp', + 'skia/src/gpu/GrDistanceFieldGenFromVector.cpp', 'skia/src/gpu/GrDrawingManager.cpp', - 'skia/src/gpu/GrDrawTarget.cpp', + 'skia/src/gpu/GrDrawOpAtlas.cpp', + 'skia/src/gpu/GrDrawOpTest.cpp', 'skia/src/gpu/GrFixedClip.cpp', 'skia/src/gpu/GrFragmentProcessor.cpp', 'skia/src/gpu/GrGpu.cpp', @@ -398,10 +403,10 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']: 'skia/src/gpu/GrGpuFactory.cpp', 'skia/src/gpu/GrGpuResource.cpp', 'skia/src/gpu/GrGpuResourceRef.cpp', - 'skia/src/gpu/GrImageIDTextureAdjuster.cpp', - 'skia/src/gpu/GrInvariantOutput.cpp', + 'skia/src/gpu/GrImageTextureMaker.cpp', 'skia/src/gpu/GrMemoryPool.cpp', - 'skia/src/gpu/GrOvalRenderer.cpp', + 'skia/src/gpu/GrOpFlushState.cpp', + 'skia/src/gpu/GrOpList.cpp', 'skia/src/gpu/GrPaint.cpp', 'skia/src/gpu/GrPath.cpp', 'skia/src/gpu/GrPathProcessor.cpp', @@ -409,37 +414,43 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']: 'skia/src/gpu/GrPathRenderer.cpp', 'skia/src/gpu/GrPathRendererChain.cpp', 'skia/src/gpu/GrPathRendering.cpp', - 'skia/src/gpu/GrPathRenderingDrawContext.cpp', - 'skia/src/gpu/GrPathUtils.cpp', + 'skia/src/gpu/GrPathRenderingRenderTargetContext.cpp', 'skia/src/gpu/GrPipeline.cpp', - 'skia/src/gpu/GrPipelineBuilder.cpp', + 'skia/src/gpu/GrPreFlushResourceProvider.cpp', 'skia/src/gpu/GrPrimitiveProcessor.cpp', 'skia/src/gpu/GrProcessor.cpp', + 'skia/src/gpu/GrProcessorAnalysis.cpp', + 'skia/src/gpu/GrProcessorSet.cpp', 'skia/src/gpu/GrProcessorUnitTest.cpp', - 'skia/src/gpu/GrProcOptInfo.cpp', 'skia/src/gpu/GrProgramDesc.cpp', - 'skia/src/gpu/GrProgramElement.cpp', 'skia/src/gpu/GrRectanizer_pow2.cpp', 'skia/src/gpu/GrRectanizer_skyline.cpp', 'skia/src/gpu/GrReducedClip.cpp', 'skia/src/gpu/GrRenderTarget.cpp', + 'skia/src/gpu/GrRenderTargetContext.cpp', + 'skia/src/gpu/GrRenderTargetOpList.cpp', 'skia/src/gpu/GrRenderTargetProxy.cpp', - 'skia/src/gpu/GrResourceProvider.cpp', + 'skia/src/gpu/GrShaderCaps.cpp', + 'skia/src/gpu/GrShaderVar.cpp', 'skia/src/gpu/GrShape.cpp', 'skia/src/gpu/GrSoftwarePathRenderer.cpp', 'skia/src/gpu/GrStencilAttachment.cpp', 'skia/src/gpu/GrStencilSettings.cpp', 'skia/src/gpu/GrStyle.cpp', 'skia/src/gpu/GrSurface.cpp', + 'skia/src/gpu/GrSurfaceContext.cpp', 'skia/src/gpu/GrSurfaceProxy.cpp', 'skia/src/gpu/GrSWMaskHelper.cpp', 'skia/src/gpu/GrTessellator.cpp', 'skia/src/gpu/GrTestUtils.cpp', 'skia/src/gpu/GrTexture.cpp', - 'skia/src/gpu/GrTextureAccess.cpp', - 'skia/src/gpu/GrTextureParamsAdjuster.cpp', - 'skia/src/gpu/GrTextureProvider.cpp', + 'skia/src/gpu/GrTextureAdjuster.cpp', + 'skia/src/gpu/GrTextureContext.cpp', + 'skia/src/gpu/GrTextureMaker.cpp', + 'skia/src/gpu/GrTextureOpList.cpp', + 'skia/src/gpu/GrTextureProducer.cpp', 'skia/src/gpu/GrTextureProxy.cpp', + 'skia/src/gpu/GrTextureRenderTargetProxy.cpp', 'skia/src/gpu/GrTextureToYUVPlanes.cpp', 'skia/src/gpu/GrTraceMarker.cpp', 'skia/src/gpu/GrXferProcessor.cpp', @@ -447,30 +458,50 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']: 'skia/src/gpu/instanced/GLInstancedRendering.cpp', 'skia/src/gpu/instanced/InstancedRendering.cpp', 'skia/src/gpu/instanced/InstanceProcessor.cpp', + 'skia/src/gpu/ops/GrAnalyticRectOp.cpp', + 'skia/src/gpu/ops/GrAtlasTextOp.cpp', + 'skia/src/gpu/ops/GrCopySurfaceOp.cpp', + 'skia/src/gpu/ops/GrDashLinePathRenderer.cpp', + 'skia/src/gpu/ops/GrDashOp.cpp', + 'skia/src/gpu/ops/GrDefaultPathRenderer.cpp', + 'skia/src/gpu/ops/GrDrawAtlasOp.cpp', + 'skia/src/gpu/ops/GrDrawPathOp.cpp', + 'skia/src/gpu/ops/GrDrawVerticesOp.cpp', + 'skia/src/gpu/ops/GrLatticeOp.cpp', + 'skia/src/gpu/ops/GrMeshDrawOp.cpp', + 'skia/src/gpu/ops/GrNonAAStrokeRectOp.cpp', + 'skia/src/gpu/ops/GrOp.cpp', + 'skia/src/gpu/ops/GrOvalOpFactory.cpp', + 'skia/src/gpu/ops/GrRectOpFactory.cpp', + 'skia/src/gpu/ops/GrRegionOp.cpp', + 'skia/src/gpu/ops/GrSemaphoreOp.cpp', + 'skia/src/gpu/ops/GrSmallPathRenderer.cpp', + 'skia/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp', + 'skia/src/gpu/ops/GrTessellatingPathRenderer.cpp', 'skia/src/gpu/SkGpuDevice.cpp', 'skia/src/gpu/SkGpuDevice_drawTexture.cpp', 'skia/src/gpu/SkGr.cpp', + 'skia/src/gpu/text/GrAtlasGlyphCache.cpp', 'skia/src/gpu/text/GrAtlasTextBlob.cpp', - 'skia/src/gpu/text/GrAtlasTextBlob_regenInBatch.cpp', + 'skia/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp', 'skia/src/gpu/text/GrAtlasTextContext.cpp', - 'skia/src/gpu/text/GrBatchFontCache.cpp', 'skia/src/gpu/text/GrDistanceFieldAdjustTable.cpp', 'skia/src/gpu/text/GrStencilAndCoverTextContext.cpp', 'skia/src/gpu/text/GrTextBlobCache.cpp', 'skia/src/gpu/text/GrTextUtils.cpp', 'skia/src/image/SkSurface_Gpu.cpp', + 'skia/src/sksl/ir/SkSLSymbolTable.cpp', + 'skia/src/sksl/ir/SkSLType.cpp', + 'skia/src/sksl/SkSLCFGGenerator.cpp', + 'skia/src/sksl/SkSLCompiler.cpp', + 'skia/src/sksl/SkSLGLSLCodeGenerator.cpp', + 'skia/src/sksl/SkSLIRGenerator.cpp', + 'skia/src/sksl/SkSLParser.cpp', + 'skia/src/sksl/SkSLSPIRVCodeGenerator.cpp', + 'skia/src/sksl/SkSLString.cpp', + 'skia/src/sksl/SkSLUtil.cpp', ] SOURCES += [ - 'skia/src/gpu/batches/GrAAConvexPathRenderer.cpp', - 'skia/src/gpu/batches/GrAAConvexTessellator.cpp', - 'skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp', - 'skia/src/gpu/batches/GrAAFillRectBatch.cpp', - 'skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp', - 'skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp', - 'skia/src/gpu/batches/GrAAStrokeRectBatch.cpp', - 'skia/src/gpu/batches/GrMSAAPathRenderer.cpp', - 'skia/src/gpu/batches/GrNonAAFillRectBatch.cpp', - 'skia/src/gpu/batches/GrNonAAFillRectPerspectiveBatch.cpp', 'skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp', 'skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp', 'skia/src/gpu/gl/builders/GrGLSLPrettyPrint.cpp', @@ -479,6 +510,7 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']: 'skia/src/gpu/gl/GrGLContext.cpp', 'skia/src/gpu/gl/GrGLDefaultInterface_native.cpp', 'skia/src/gpu/gl/GrGLExtensions.cpp', + 'skia/src/gpu/gl/GrGLExternalTextureData.cpp', 'skia/src/gpu/gl/GrGLGLSL.cpp', 'skia/src/gpu/gl/GrGLGpu.cpp', 'skia/src/gpu/gl/GrGLGpuProgramCache.cpp', @@ -498,7 +530,6 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']: 'skia/src/gpu/gl/GrGLVertexArray.cpp', 'skia/src/gpu/glsl/GrGLSL.cpp', 'skia/src/gpu/glsl/GrGLSLBlend.cpp', - 'skia/src/gpu/glsl/GrGLSLCaps.cpp', 'skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp', 'skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp', 'skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp', @@ -511,12 +542,23 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']: 'skia/src/gpu/glsl/GrGLSLVarying.cpp', 'skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp', 'skia/src/gpu/glsl/GrGLSLXferProcessor.cpp', - 'skia/src/gpu/GrBatchAtlas.cpp', - 'skia/src/gpu/GrDrawContext.cpp', + 'skia/src/gpu/GrPathUtils.cpp', 'skia/src/gpu/GrResourceCache.cpp', + 'skia/src/gpu/GrResourceProvider.cpp', + 'skia/src/gpu/ops/GrAAConvexPathRenderer.cpp', + 'skia/src/gpu/ops/GrAAConvexTessellator.cpp', + 'skia/src/gpu/ops/GrAAFillRectOp.cpp', + 'skia/src/gpu/ops/GrAAHairLinePathRenderer.cpp', + 'skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp', + 'skia/src/gpu/ops/GrAAStrokeRectOp.cpp', + 'skia/src/gpu/ops/GrMSAAPathRenderer.cpp', + 'skia/src/gpu/ops/GrNonAAFillRectOp.cpp', + 'skia/src/gpu/ops/GrNonAAFillRectPerspectiveOp.cpp', + 'skia/src/gpu/ops/GrShadowRRectOp.cpp', 'skia/src/image/SkImage_Gpu.cpp', + 'skia/src/sksl/lex.layout.cpp', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android'): +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': UNIFIED_SOURCES += [ 'skia/src/ports/SkDebug_android.cpp', 'skia/src/ports/SkOSFile_posix.cpp', @@ -525,23 +567,23 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android'): 'skia/src/utils/SkThreadUtils_pthread.cpp', ] SOURCES += [ + 'skia/src/jumper/SkJumper_generated.S', 'skia/src/ports/SkFontHost_cairo.cpp', 'skia/src/ports/SkFontHost_FreeType_common.cpp', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] in {'cocoa', 'uikit'}: +if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'): UNIFIED_SOURCES += [ 'skia/src/ports/SkDebug_stdio.cpp', 'skia/src/ports/SkOSFile_posix.cpp', 'skia/src/ports/SkOSLibrary_posix.cpp', 'skia/src/ports/SkTLS_pthread.cpp', - 'skia/src/utils/mac/SkCreateCGImageRef.cpp', - 'skia/src/utils/mac/SkStream_mac.cpp', 'skia/src/utils/SkThreadUtils_pthread.cpp', ] SOURCES += [ + 'skia/src/jumper/SkJumper_generated.S', 'skia/src/ports/SkFontHost_mac.cpp', ] -if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: +if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'): UNIFIED_SOURCES += [ 'skia/src/ports/SkDebug_stdio.cpp', 'skia/src/ports/SkOSFile_posix.cpp', @@ -550,35 +592,28 @@ if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: 'skia/src/utils/SkThreadUtils_pthread.cpp', ] SOURCES += [ + 'skia/src/jumper/SkJumper_generated.S', 'skia/src/ports/SkFontHost_cairo.cpp', 'skia/src/ports/SkFontHost_FreeType_common.cpp', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': SOURCES += [ + 'skia/src/jumper/SkJumper_generated_win.S', 'skia/src/ports/SkDebug_win.cpp', 'skia/src/ports/SkFontHost_win.cpp', 'skia/src/ports/SkFontMgr_win_dw.cpp', 'skia/src/ports/SkFontMgr_win_dw_factory.cpp', 'skia/src/ports/SkOSFile_win.cpp', 'skia/src/ports/SkOSLibrary_win.cpp', - 'skia/src/ports/SkRemotableFontMgr_win_dw.cpp', 'skia/src/ports/SkScalerContext_win_dw.cpp', 'skia/src/ports/SkTLS_win.cpp', 'skia/src/ports/SkTypeface_win_dw.cpp', - 'skia/src/utils/SkThreadUtils_win.cpp', - 'skia/src/utils/win/SkAutoCoInitialize.cpp', - 'skia/src/utils/win/SkDWrite.cpp', - 'skia/src/utils/win/SkDWriteFontFileStream.cpp', - 'skia/src/utils/win/SkDWriteGeometrySink.cpp', - 'skia/src/utils/win/SkHRESULT.cpp', - 'skia/src/utils/win/SkIStream.cpp', ] if CONFIG['INTEL_ARCHITECTURE']: UNIFIED_SOURCES += [ 'skia/src/opts/opts_check_x86.cpp', ] SOURCES += [ - 'skia/src/opts/SkBitmapFilter_opts_SSE2.cpp', 'skia/src/opts/SkBitmapProcState_opts_SSE2.cpp', 'skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp', 'skia/src/opts/SkBlitRow_opts_SSE2.cpp', @@ -588,7 +623,6 @@ if CONFIG['INTEL_ARCHITECTURE']: 'skia/src/opts/SkOpts_sse42.cpp', 'skia/src/opts/SkOpts_ssse3.cpp', ] - SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += skia_opt_flags SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += skia_opt_flags SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += skia_opt_flags SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += skia_opt_flags @@ -598,44 +632,22 @@ if CONFIG['INTEL_ARCHITECTURE']: SOURCES['skia/src/opts/SkOpts_sse42.cpp'].flags += skia_opt_flags SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += skia_opt_flags elif CONFIG['CPU_ARCH'] in ('arm', 'aarch64') and CONFIG['GNU_CC']: - UNIFIED_SOURCES += [ - 'skia/src/core/SkUtilsArm.cpp', - ] SOURCES += [ - 'skia/src/opts/SkBitmapProcState_opts_arm.cpp', + 'skia/src/opts/SkBitmapProcState_arm_neon.cpp', + 'skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp', + 'skia/src/opts/SkBitmapProcState_opts_none.cpp', 'skia/src/opts/SkBlitMask_opts_arm.cpp', + 'skia/src/opts/SkBlitMask_opts_arm_neon.cpp', 'skia/src/opts/SkBlitRow_opts_arm.cpp', + 'skia/src/opts/SkBlitRow_opts_arm_neon.cpp', ] - SOURCES['skia/src/opts/SkBitmapProcState_opts_arm.cpp'].flags += skia_opt_flags + SOURCES['skia/src/opts/SkBitmapProcState_arm_neon.cpp'].flags += skia_opt_flags + SOURCES['skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp'].flags += skia_opt_flags + SOURCES['skia/src/opts/SkBitmapProcState_opts_none.cpp'].flags += skia_opt_flags SOURCES['skia/src/opts/SkBlitMask_opts_arm.cpp'].flags += skia_opt_flags + SOURCES['skia/src/opts/SkBlitMask_opts_arm_neon.cpp'].flags += skia_opt_flags SOURCES['skia/src/opts/SkBlitRow_opts_arm.cpp'].flags += skia_opt_flags - if CONFIG['CPU_ARCH'] == 'aarch64': - SOURCES += [ - 'skia/src/opts/SkBitmapProcState_arm_neon.cpp', - 'skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp', - 'skia/src/opts/SkBlitMask_opts_arm_neon.cpp', - 'skia/src/opts/SkBlitRow_opts_arm_neon.cpp', - 'skia/src/opts/SkOpts_neon.cpp', - ] - elif CONFIG['BUILD_ARM_NEON']: - SOURCES += [ - 'skia/src/opts/SkBitmapProcState_arm_neon.cpp', - 'skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp', - 'skia/src/opts/SkBlitMask_opts_arm_neon.cpp', - 'skia/src/opts/SkBlitRow_opts_arm_neon.cpp', - 'skia/src/opts/SkOpts_neon.cpp', - ] - SOURCES['skia/src/opts/SkBitmapProcState_arm_neon.cpp'].flags += CONFIG['NEON_FLAGS'] - SOURCES['skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp'].flags += CONFIG['NEON_FLAGS'] - SOURCES['skia/src/opts/SkBlitMask_opts_arm_neon.cpp'].flags += CONFIG['NEON_FLAGS'] - SOURCES['skia/src/opts/SkBlitRow_opts_arm_neon.cpp'].flags += CONFIG['NEON_FLAGS'] - SOURCES['skia/src/opts/SkOpts_neon.cpp'].flags += CONFIG['NEON_FLAGS'] - if CONFIG['CPU_ARCH'] == 'aarch64' or CONFIG['BUILD_ARM_NEON']: - SOURCES['skia/src/opts/SkBitmapProcState_arm_neon.cpp'].flags += skia_opt_flags - SOURCES['skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp'].flags += skia_opt_flags - SOURCES['skia/src/opts/SkBlitMask_opts_arm_neon.cpp'].flags += skia_opt_flags - SOURCES['skia/src/opts/SkBlitRow_opts_arm_neon.cpp'].flags += skia_opt_flags - SOURCES['skia/src/opts/SkOpts_neon.cpp'].flags += skia_opt_flags + SOURCES['skia/src/opts/SkBlitRow_opts_arm_neon.cpp'].flags += skia_opt_flags else: SOURCES += [ 'skia/src/opts/SkBitmapProcState_opts_none.cpp', @@ -654,7 +666,6 @@ LOCAL_INCLUDES += [ 'skia/include/core', 'skia/include/effects', 'skia/include/gpu', - 'skia/include/images', 'skia/include/pathops', 'skia/include/ports', 'skia/include/private', @@ -665,27 +676,17 @@ LOCAL_INCLUDES += [ 'skia/src/gpu', 'skia/src/gpu/effects', 'skia/src/gpu/gl', + 'skia/src/gpu/glsl', 'skia/src/image', 'skia/src/lazy', 'skia/src/opts', 'skia/src/sfnt', + 'skia/src/sksl', 'skia/src/utils', 'skia/src/utils/mac', 'skia/src/utils/win', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android'): - DEFINES['SK_FONTHOST_CAIRO_STANDALONE'] = 0 - -if CONFIG['MOZ_WIDGET_TOOLKIT'] in { - 'android', - 'cocoa', - 'gtk2', - 'gtk3', - 'uikit', - }: - DEFINES['SK_FONTHOST_DOES_NOT_USE_FONTMGR'] = 1 - if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': DEFINES['UNICODE'] = True DEFINES['_UNICODE'] = True @@ -696,19 +697,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': # We should autogenerate these SSE related flags. -if CONFIG['_MSC_VER']: - # MSVC doesn't need special compiler flags, but Skia needs to be told that these files should - # be built with the required SSE level or it will simply compile in stubs and cause runtime crashes - SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20'] - SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20'] - SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=31'] - SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20'] - SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=31'] - SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=41'] - SOURCES['skia/src/opts/SkOpts_sse42.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=42'] - SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=51'] if CONFIG['INTEL_ARCHITECTURE'] and (CONFIG['GNU_CC'] or CONFIG['CLANG_CL']): - SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-mssse3'] SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] @@ -716,8 +705,20 @@ if CONFIG['INTEL_ARCHITECTURE'] and (CONFIG['GNU_CC'] or CONFIG['CLANG_CL']): SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-msse4.1'] SOURCES['skia/src/opts/SkOpts_sse42.cpp'].flags += ['-msse4.2'] SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-mavx'] -elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC'] and CONFIG['BUILD_ARM_NEON']: - DEFINES['SK_ARM_HAS_OPTIONAL_NEON'] = 1 + SOURCES['skia/src/opts/SkOpts_hsw.cpp'].flags += ['-mavx2'] +elif CONFIG['_MSC_VER']: + # MSVC doesn't need special compiler flags, but Skia needs to be told that these files should + # be built with the required SSE level or it will simply compile in stubs and cause runtime crashes + SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20'] + SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=31'] + SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20'] + SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=31'] + SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=41'] + SOURCES['skia/src/opts/SkOpts_sse42.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=42'] + SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=51'] + SOURCES['skia/src/opts/SkOpts_hsw.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=52'] +elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']: + CXXFLAGS += CONFIG['NEON_FLAGS'] DEFINES['SKIA_IMPLEMENTATION'] = 1 diff --git a/gfx/skia/skia/include/android/SkBitmapRegionDecoder.h b/gfx/skia/skia/include/android/SkBitmapRegionDecoder.h index b8922d469771..841bf8d4156f 100644 --- a/gfx/skia/skia/include/android/SkBitmapRegionDecoder.h +++ b/gfx/skia/skia/include/android/SkBitmapRegionDecoder.h @@ -10,7 +10,7 @@ #include "SkBitmap.h" #include "SkBRDAllocator.h" -#include "SkEncodedFormat.h" +#include "SkEncodedImageFormat.h" #include "SkStream.h" /* @@ -55,18 +55,21 @@ public: * if this color type is unsupported. * @param requireUnpremul If the image is not opaque, we will use this to determine the * alpha type to use. + * @param prefColorSpace If non-null and supported, this is the color space that we will + * decode into. Otherwise, we will choose a default. * */ virtual bool decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator, const SkIRect& desiredSubset, int sampleSize, - SkColorType colorType, bool requireUnpremul) = 0; + SkColorType colorType, bool requireUnpremul, + sk_sp prefColorSpace = nullptr) = 0; /* * @param Requested destination color type * @return true if we support the requested color type and false otherwise */ virtual bool conversionSupported(SkColorType colorType) = 0; - virtual SkEncodedFormat getEncodedFormat() = 0; + virtual SkEncodedImageFormat getEncodedFormat() = 0; int width() const { return fWidth; } int height() const { return fHeight; } diff --git a/gfx/skia/skia/include/animator/SkAnimator.h b/gfx/skia/skia/include/animator/SkAnimator.h deleted file mode 100644 index 0fe787c5262c..000000000000 --- a/gfx/skia/skia/include/animator/SkAnimator.h +++ /dev/null @@ -1,501 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkAnimator_DEFINED -#define SkAnimator_DEFINED - -#include "SkScalar.h" -#include "SkKey.h" -#include "SkEventSink.h" - -class SkAnimateMaker; -class SkCanvas; -class SkDisplayable; -class SkEvent; -class SkExtras; -struct SkMemberInfo; -class SkPaint; -struct SkRect; -class SkStream; -class SkTypedArray; -class SkXMLParserError; -class SkDOM; -struct SkDOMNode; - -/** SkElementType is the type of element: a rectangle, a color, an animator, and so on. - This enum is incomplete and will be fleshed out in a future release */ -enum SkElementType { - kElementDummyType -}; -/** SkFieldType is the type of field: a scalar, a string, an integer, a boolean, and so on. - This enum is incomplete and will be fleshed out in a future release */ -enum SkFieldType { - kFieldDummyType -}; - -/** \class SkAnimator - - The SkAnimator class decodes an XML stream into a display list. The - display list can be drawn statically as a picture, or can drawn - different elements at different times to form a moving animation. - - SkAnimator does not read the system time on its own; it relies on the - caller to pass the current time. The caller can pause, speed up, or - reverse the animation by varying the time passed in. - - The XML describing the display list must conform to the schema - described by SkAnimateSchema.xsd. - - The XML must contain an element to draw. Usually, it contains - an block to add some drawing elements to the - display list when the document is first decoded. - - Here's an "Hello World" XML sample: - - - - - - - - To read and draw this sample: - - // choose one of these two - SkAnimator animator; // declare an animator instance on the stack - // SkAnimator* animator = new SkAnimator() // or one could instantiate the class - - // choose one of these three - animator.decodeMemory(buffer, size); // to read from RAM - animator.decodeStream(stream); // to read from a user-defined stream (e.g., a zip file) - animator.decodeURI(filename); // to read from a web location, or from a local text file - - // to draw to the current window: - SkCanvas canvas(getBitmap()); // create a canvas - animator.draw(canvas, &paint, 0); // draw the scene -*/ -class SkAnimator : public SkEventSink { -public: - SkAnimator(); - virtual ~SkAnimator(); - - /** Add a drawable extension to the graphics engine. Experimental. - @param extras A derived class that implements methods that identify and instantiate the class - */ - void addExtras(SkExtras* extras); - - /** Read in XML from a stream, and append it to the current - animator. Returns false if an error was encountered. - Error diagnostics are stored in fErrorCode and fLineNumber. - @param stream The stream to append. - @return true if the XML was parsed successfully. - */ - bool appendStream(SkStream* stream); - - /** Read in XML from memory. Returns true if the file can be - read without error. Returns false if an error was encountered. - Error diagnostics are stored in fErrorCode and fLineNumber. - @param buffer The XML text as UTF-8 characters. - @param size The XML text length in bytes. - @return true if the XML was parsed successfully. - */ - bool decodeMemory(const void* buffer, size_t size); - - /** Read in XML from a stream. Returns true if the file can be - read without error. Returns false if an error was encountered. - Error diagnostics are stored in fErrorCode and fLineNumber. - @param stream The stream containg the XML text as UTF-8 characters. - @return true if the XML was parsed successfully. - */ - virtual bool decodeStream(SkStream* stream); - - /** Parse the DOM tree starting at the specified node. Returns true if it can be - parsed without error. Returns false if an error was encountered. - Error diagnostics are stored in fErrorCode and fLineNumber. - @return true if the DOM was parsed successfully. - */ - virtual bool decodeDOM(const SkDOM&, const SkDOMNode*); - - /** Read in XML from a URI. Returns true if the file can be - read without error. Returns false if an error was encountered. - Error diagnostics are stored in fErrorCode and fLineNumber. - @param uri The complete url path to be read (either ftp, http or https). - @return true if the XML was parsed successfully. - */ - bool decodeURI(const char uri[]); - - /** Pass a char event, usually a keyboard symbol, to the animator. - This triggers events of the form - and other mouse events. - @param state The mouse state, described by SkView::Click::State : values are - down == 0, moved == 1, up == 2 - @param x The x-position of the mouse - @param y The y-position of the mouse - @return true if the event was dispatched successfully. - */ - bool doClickEvent(int state, SkScalar x, SkScalar y); - - /** Pass a meta-key event, such as an arrow , to the animator. - This triggers events of the form element that specifies a minimal - redraw area. - */ - DifferenceType draw(SkCanvas* canvas, SkPaint* paint, SkMSec time); - - /** Draws one frame of the animation, using a new Paint each time. - The first call to draw always - draws the initial frame of the animation. Subsequent calls draw - the offset into the animation by - subtracting the initial time from the current time. - @param canvas The canvas to draw into. - @param time The offset into the current animation. - @return kNotDifferent if there are no active animations; kDifferent if there are active animations; and - kPartiallyDifferent if the document contains an active element that specifies a minimal - redraw area. - */ - DifferenceType draw(SkCanvas* canvas, SkMSec time); - - /** Experimental: - Helper to choose whether to return a SkView::Click handler. - @param x ignored - @param y ignored - @return true if a mouseDown event handler is enabled. - */ - bool findClickEvent(SkScalar x, SkScalar y); - - - /** Get the nested animator associated with this element, if any. - Use this to access a movie's event sink, to send events to movies. - @param element the value returned by getElement - @return the internal animator. - */ - const SkAnimator* getAnimator(const SkDisplayable* element) const; - - /** Returns the scalar value of the specified element's attribute[index] - @param element the value returned by getElement - @param field the value returned by getField - @param index the array entry - @return the integer value to retrieve, or SK_NaN32 if unsuccessful - */ - int32_t getArrayInt(const SkDisplayable* element, const SkMemberInfo* field, int index); - - /** Returns the scalar value of the specified element's attribute[index] - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @param index the array entry - @return the integer value to retrieve, or SK_NaN32 if unsuccessful - */ - int32_t getArrayInt(const char* elementID, const char* fieldName, int index); - - /** Returns the scalar value of the specified element's attribute[index] - @param element the value returned by getElement - @param field the value returned by getField - @param index the array entry - @return the scalar value to retrieve, or SK_ScalarNaN if unsuccessful - */ - SkScalar getArrayScalar(const SkDisplayable* element, const SkMemberInfo* field, int index); - - /** Returns the scalar value of the specified element's attribute[index] - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @param index the array entry - @return the scalar value to retrieve, or SK_ScalarNaN if unsuccessful - */ - SkScalar getArrayScalar(const char* elementID, const char* fieldName, int index); - - /** Returns the string value of the specified element's attribute[index] - @param element is a value returned by getElement - @param field is a value returned by getField - @param index the array entry - @return the string value to retrieve, or null if unsuccessful - */ - const char* getArrayString(const SkDisplayable* element, const SkMemberInfo* field, int index); - - /** Returns the string value of the specified element's attribute[index] - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @param index the array entry - @return the string value to retrieve, or null if unsuccessful - */ - const char* getArrayString(const char* elementID, const char* fieldName, int index); - - /** Returns the XML element corresponding to the given ID. - @param elementID is the value of the id attribute in the XML of this element - @return the element matching the ID, or null if the element can't be found - */ - const SkDisplayable* getElement(const char* elementID); - - /** Returns the element type corresponding to the XML element. - The element type matches the element name; for instance, returns kElement_LineType - @param element is a value returned by getElement - @return element type, or 0 if the element can't be found - */ - SkElementType getElementType(const SkDisplayable* element); - - /** Returns the element type corresponding to the given ID. - @param elementID is the value of the id attribute in the XML of this element - @return element type, or 0 if the element can't be found - */ - SkElementType getElementType(const char* elementID); - - /** Returns the XML field of the named attribute in the XML element. - @param element is a value returned by getElement - @param fieldName is the attribute to return - @return the attribute matching the fieldName, or null if the element can't be found - */ - const SkMemberInfo* getField(const SkDisplayable* element, const char* fieldName); - - /** Returns the XML field of the named attribute in the XML element matching the elementID. - @param elementID is the value of the id attribute in the XML of this element - @param fieldName is the attribute to return - @return the attribute matching the fieldName, or null if the element can't be found - */ - const SkMemberInfo* getField(const char* elementID, const char* fieldName); - - /** Returns the value type coresponding to the element's attribute. - The value type matches the XML schema: and may be kField_BooleanType, kField_ScalarType, etc. - @param field is a value returned by getField - @return the attribute type, or 0 if the element can't be found - */ - SkFieldType getFieldType(const SkMemberInfo* field); - - /** Returns the value type coresponding to the element's attribute. - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @return the attribute type, or 0 if the element can't be found - */ - SkFieldType getFieldType(const char* elementID, const char* fieldName); - - /** Returns the recommended animation interval. Returns zero if no - interval is specified. - */ - SkMSec getInterval(); - - /** Returns the partial rectangle to invalidate after drawing. Call after draw() returns - kIsPartiallyDifferent to do a mimimal inval(). */ - void getInvalBounds(SkRect* inval); - - /** Returns the details of any error encountered while parsing the XML. - */ - const SkXMLParserError* getParserError(); - - /** Returns the details of any error encountered while parsing the XML as string. - */ - const char* getParserErrorString(); - - /** Returns the scalar value of the specified element's attribute - @param element is a value returned by getElement - @param field is a value returned by getField - @return the integer value to retrieve, or SK_NaN32 if not found - */ - int32_t getInt(const SkDisplayable* element, const SkMemberInfo* field); - - /** Returns the scalar value of the specified element's attribute - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @return the integer value to retrieve, or SK_NaN32 if not found - */ - int32_t getInt(const char* elementID, const char* fieldName); - - /** Returns the scalar value of the specified element's attribute - @param element is a value returned by getElement - @param field is a value returned by getField - @return the scalar value to retrieve, or SK_ScalarNaN if not found - */ - SkScalar getScalar(const SkDisplayable* element, const SkMemberInfo* field); - - /** Returns the scalar value of the specified element's attribute - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @return the scalar value to retrieve, or SK_ScalarNaN if not found - */ - SkScalar getScalar(const char* elementID, const char* fieldName); - - /** Returns the string value of the specified element's attribute - @param element is a value returned by getElement - @param field is a value returned by getField - @return the string value to retrieve, or null if not found - */ - const char* getString(const SkDisplayable* element, const SkMemberInfo* field); - - /** Returns the string value of the specified element's attribute - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @return the string value to retrieve, or null if not found - */ - const char* getString(const char* elementID, const char* fieldName); - - /** Gets the file default directory of the URL base path set explicitly or by reading the last URL. */ - const char* getURIBase(); - - /** Resets the animator to a newly created state with no animation data. */ - void initialize(); - - /** Experimental. Resets any active animations so that the next time passed is treated as - time zero. */ - void reset(); - - /** Sets the scalar value of the specified element's attribute - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @param array is the c-style array of integers - @param count is the length of the array - @return true if the value was set successfully - */ - bool setArrayInt(const char* elementID, const char* fieldName, const int* array, int count); - - /** Sets the scalar value of the specified element's attribute - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @param array is the c-style array of strings - @param count is the length of the array - @return true if the value was set successfully - */ - bool setArrayString(const char* elementID, const char* fieldName, const char** array, int count); - - /** Sets the scalar value of the specified element's attribute - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @param data the integer value to set - @return true if the value was set successfully - */ - bool setInt(const char* elementID, const char* fieldName, int32_t data); - - /** Sets the scalar value of the specified element's attribute - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @param data the scalar value to set - @return true if the value was set successfully - */ - bool setScalar(const char* elementID, const char* fieldName, SkScalar data); - - /** Sets the string value of the specified element's attribute - @param elementID is the value of the id attribute in the XML of this element - @param fieldName specifies the name of the attribute - @param data the string value to set - @return true if the value was set successfully - */ - bool setString(const char* elementID, const char* fieldName, const char* data); - - /** Sets the file default directory of the URL base path - @param path the directory path - */ - void setURIBase(const char* path); - - typedef void* Handler; - // This guy needs to be exported to java, so don't make it virtual - void setHostHandler(Handler handler) { - this->onSetHostHandler(handler); - } - - /** \class Timeline - Returns current time to animator. To return a custom timeline, create a child - class and override the getMSecs method. - */ - class Timeline { - public: - virtual ~Timeline() {} - - /** Returns the current time in milliseconds */ - virtual SkMSec getMSecs() const = 0; - }; - - /** Sets a user class to return the current time to the animator. - Optional; if not called, the system clock will be used by calling - SkEvent::GetMSecsSinceStartup instead. - @param callBack the time function - */ - void setTimeline(const Timeline& ); - - static void Init(bool runUnitTests); - static void Term(); - - /** The event sink events generated by the animation are posted to. - Screenplay also posts an inval event to this event sink after processing an - event to force a redraw. - @param target the event sink id - */ - void setHostEventSinkID(SkEventSinkID hostID); - SkEventSinkID getHostEventSinkID() const; - - // helper - void setHostEventSink(SkEventSink* sink) { - this->setHostEventSinkID(sink ? sink->getSinkID() : 0); - } - - virtual void setJavaOwner(Handler owner); - -#ifdef SK_DEBUG - virtual void eventDone(const SkEvent& evt); - virtual bool isTrackingEvents(); - static bool NoLeaks(); -#endif - -protected: - virtual void onSetHostHandler(Handler handler); - virtual void onEventPost(SkEvent*, SkEventSinkID); - virtual void onEventPostTime(SkEvent*, SkEventSinkID, SkMSec time); - -private: -// helper functions for setters - bool setArray(SkDisplayable* element, const SkMemberInfo* field, SkTypedArray array); - bool setArray(const char* elementID, const char* fieldName, SkTypedArray array); - bool setInt(SkDisplayable* element, const SkMemberInfo* field, int32_t data); - bool setScalar(SkDisplayable* element, const SkMemberInfo* field, SkScalar data); - bool setString(SkDisplayable* element, const SkMemberInfo* field, const char* data); - - virtual bool onEvent(const SkEvent&); - SkAnimateMaker* fMaker; - friend class SkAnimateMaker; - friend class SkAnimatorScript; - friend class SkAnimatorScript2; - friend class SkApply; - friend class SkDisplayMovie; - friend class SkDisplayType; - friend class SkPost; - friend class SkXMLAnimatorWriter; -}; - -#endif diff --git a/gfx/skia/skia/include/animator/SkAnimatorView.h b/gfx/skia/skia/include/animator/SkAnimatorView.h deleted file mode 100644 index 2b2c61b5d844..000000000000 --- a/gfx/skia/skia/include/animator/SkAnimatorView.h +++ /dev/null @@ -1,39 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkAnimatorView_DEFINED -#define SkAnimatorView_DEFINED - -#include "SkView.h" -#include "SkAnimator.h" - -class SkAnimatorView : public SkView { -public: - SkAnimatorView(); - virtual ~SkAnimatorView(); - - SkAnimator* getAnimator() const { return fAnimator; } - - bool decodeFile(const char path[]); - bool decodeMemory(const void* buffer, size_t size); - bool decodeStream(SkStream* stream); - -protected: - // overrides - virtual bool onEvent(const SkEvent&); - virtual void onDraw(SkCanvas*); - virtual void onInflate(const SkDOM&, const SkDOM::Node*); - -private: - SkAnimator* fAnimator; - - typedef SkView INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/c/sk_data.h b/gfx/skia/skia/include/c/sk_data.h index 90333bba5f77..863c619ff5c0 100644 --- a/gfx/skia/skia/include/c/sk_data.h +++ b/gfx/skia/skia/include/c/sk_data.h @@ -19,7 +19,7 @@ SK_C_PLUS_PLUS_BEGIN_GUARD Returns a new empty sk_data_t. This call must be balanced with a call to sk_data_unref(). */ -SK_API sk_data_t* sk_data_new_empty(); +SK_API sk_data_t* sk_data_new_empty(void); /** Returns a new sk_data_t by copying the specified source data. This call must be balanced with a call to sk_data_unref(). diff --git a/gfx/skia/skia/include/c/sk_paint.h b/gfx/skia/skia/include/c/sk_paint.h index e0886ad34965..ef7e624aa500 100644 --- a/gfx/skia/skia/include/c/sk_paint.h +++ b/gfx/skia/skia/include/c/sk_paint.h @@ -28,7 +28,7 @@ SK_C_PLUS_PLUS_BEGIN_GUARD maskfilter : NULL xfermode_mode : SRCOVER_SK_XFERMODE_MODE */ -SK_API sk_paint_t* sk_paint_new(); +SK_API sk_paint_t* sk_paint_new(void); /** Release the memory storing the sk_paint_t and unref() all associated objects. diff --git a/gfx/skia/skia/include/c/sk_path.h b/gfx/skia/skia/include/c/sk_path.h index 6b4e83d3b2a6..74abca0d500e 100644 --- a/gfx/skia/skia/include/c/sk_path.h +++ b/gfx/skia/skia/include/c/sk_path.h @@ -21,7 +21,7 @@ typedef enum { } sk_path_direction_t; /** Create a new, empty path. */ -SK_API sk_path_t* sk_path_new(); +SK_API sk_path_t* sk_path_new(void); /** Release the memory used by a sk_path_t. */ SK_API void sk_path_delete(sk_path_t*); diff --git a/gfx/skia/skia/include/c/sk_picture.h b/gfx/skia/skia/include/c/sk_picture.h index 338b7d906ac8..7a0321412932 100644 --- a/gfx/skia/skia/include/c/sk_picture.h +++ b/gfx/skia/skia/include/c/sk_picture.h @@ -19,7 +19,7 @@ SK_C_PLUS_PLUS_BEGIN_GUARD Create a new sk_picture_recorder_t. Its resources should be released with a call to sk_picture_recorder_delete(). */ -sk_picture_recorder_t* sk_picture_recorder_new(); +sk_picture_recorder_t* sk_picture_recorder_new(void); /** Release the memory and other resources used by this sk_picture_recorder_t. diff --git a/gfx/skia/skia/include/c/sk_types.h b/gfx/skia/skia/include/c/sk_types.h index baa3ac9ce6ec..679e106e33f5 100644 --- a/gfx/skia/skia/include/c/sk_types.h +++ b/gfx/skia/skia/include/c/sk_types.h @@ -81,7 +81,7 @@ typedef enum { /** Return the default sk_colortype_t; this is operating-system dependent. */ -SK_API sk_colortype_t sk_colortype_get_default_8888(); +SK_API sk_colortype_t sk_colortype_get_default_8888(void); typedef struct { int32_t width; @@ -113,6 +113,59 @@ typedef struct { float bottom; } sk_rect_t; +/** + The sk_matrix_t struct holds a 3x3 perspective matrix for + transforming coordinates: + + (X,Y) = T[M]((x,y)) + X = (M[0] * x + M[1] * y + M[2]) / (M[6] * x + M[7] * y + M[8]); + Y = (M[3] * x + M[4] * y + M[5]) / (M[6] * x + M[7] * y + M[8]); + + Therefore, the identity matrix is + + sk_matrix_t identity = {{1, 0, 0, + 0, 1, 0, + 0, 0, 1}}; + + A matrix that scales by sx and sy is: + + sk_matrix_t scale = {{sx, 0, 0, + 0, sy, 0, + 0, 0, 1}}; + + A matrix that translates by tx and ty is: + + sk_matrix_t translate = {{1, 0, tx, + 0, 1, ty, + 0, 0, 1}}; + + A matrix that rotates around the origin by A radians: + + sk_matrix_t rotate = {{cos(A), -sin(A), 0, + sin(A), cos(A), 0, + 0, 0, 1}}; + + Two matrixes can be concatinated by: + + void concat_matrices(sk_matrix_t* dst, + const sk_matrix_t* matrixU, + const sk_matrix_t* matrixV) { + const float* u = matrixU->mat; + const float* v = matrixV->mat; + sk_matrix_t result = {{ + u[0] * v[0] + u[1] * v[3] + u[2] * v[6], + u[0] * v[1] + u[1] * v[4] + u[2] * v[7], + u[0] * v[2] + u[1] * v[5] + u[2] * v[8], + u[3] * v[0] + u[4] * v[3] + u[5] * v[6], + u[3] * v[1] + u[4] * v[4] + u[5] * v[7], + u[3] * v[2] + u[4] * v[5] + u[5] * v[8], + u[6] * v[0] + u[7] * v[3] + u[8] * v[6], + u[6] * v[1] + u[7] * v[4] + u[8] * v[7], + u[6] * v[2] + u[7] * v[5] + u[8] * v[8] + }}; + *dst = result; + } +*/ typedef struct { float mat[9]; } sk_matrix_t; diff --git a/gfx/skia/skia/include/codec/SkAndroidCodec.h b/gfx/skia/skia/include/codec/SkAndroidCodec.h index c7587b62e98a..87d514dfffd6 100644 --- a/gfx/skia/skia/include/codec/SkAndroidCodec.h +++ b/gfx/skia/skia/include/codec/SkAndroidCodec.h @@ -9,7 +9,7 @@ #define SkAndroidCodec_DEFINED #include "SkCodec.h" -#include "SkEncodedFormat.h" +#include "SkEncodedImageFormat.h" #include "SkStream.h" #include "SkTypes.h" @@ -51,14 +51,18 @@ public: /** * Format of the encoded data. */ - SkEncodedFormat getEncodedFormat() const { return fCodec->getEncodedFormat(); } + SkEncodedImageFormat getEncodedFormat() const { return fCodec->getEncodedFormat(); } /** * @param requestedColorType Color type requested by the client * - * If it is possible to decode to requestedColorType, this returns - * requestedColorType. Otherwise, this returns whichever color type - * is suggested by the codec as the best match for the encoded data. + * |requestedColorType| may be overriden. We will default to kF16 + * for high precision images and kIndex8 for GIF and WBMP. + * + * In the general case, if it is possible to decode to + * |requestedColorType|, this returns |requestedColorType|. + * Otherwise, this returns a color type that is an appropriate + * match for the the encoded data. */ SkColorType computeOutputColorType(SkColorType requestedColorType); @@ -71,6 +75,19 @@ public: */ SkAlphaType computeOutputAlphaType(bool requestedUnpremul); + /** + * @param outputColorType Color type that the client will decode to. + * @param prefColorSpace Preferred color space to decode to. + * This may not return |prefColorSpace| for a couple reasons. + * (1) Android Principles: 565 must be sRGB, F16 must be + * linear sRGB, transfer function must be parametric. + * (2) Codec Limitations: F16 requires a linear color space. + * + * Returns the appropriate color space to decode to. + */ + sk_sp computeOutputColorSpace(SkColorType outputColorType, + sk_sp prefColorSpace = nullptr); + /** * Returns the dimensions of the scaled output image, for an input * sampleSize. @@ -154,7 +171,7 @@ public: * * Must be within the bounds returned by getInfo(). * - * If the EncodedFormat is kWEBP_SkEncodedFormat, the top and left + * If the EncodedFormat is SkEncodedImageFormat::kWEBP, the top and left * values must be even. * * The default is NULL, meaning a decode of the entire image. @@ -260,6 +277,6 @@ private: // embedded SkCodec. const SkImageInfo& fInfo; - SkAutoTDelete fCodec; + std::unique_ptr fCodec; }; #endif // SkAndroidCodec_DEFINED diff --git a/gfx/skia/skia/include/codec/SkCodec.h b/gfx/skia/skia/include/codec/SkCodec.h index 363347dd72c0..aadcb059fe16 100644 --- a/gfx/skia/skia/include/codec/SkCodec.h +++ b/gfx/skia/skia/include/codec/SkCodec.h @@ -10,7 +10,7 @@ #include "../private/SkTemplates.h" #include "SkColor.h" -#include "SkEncodedFormat.h" +#include "SkEncodedImageFormat.h" #include "SkEncodedInfo.h" #include "SkImageInfo.h" #include "SkSize.h" @@ -18,7 +18,10 @@ #include "SkTypes.h" #include "SkYUVSizeInfo.h" +#include + class SkColorSpace; +class SkColorSpaceXform; class SkData; class SkPngChunkReader; class SkSampler; @@ -32,7 +35,7 @@ class ColorCodecBench; /** * Abstraction layer directly on top of an image codec. */ -class SkCodec : SkNoncopyable { +class SK_API SkCodec : SkNoncopyable { public: /** * Minimum number of bytes that must be buffered in SkStream input. @@ -173,7 +176,7 @@ public: /** * Format of the encoded data. */ - SkEncodedFormat getEncodedFormat() const { return this->onGetEncodedFormat(); } + SkEncodedImageFormat getEncodedFormat() const { return this->onGetEncodedFormat(); } /** * Used to describe the result of a call to getPixels(). @@ -243,14 +246,17 @@ public: struct Options { Options() : fZeroInitialized(kNo_ZeroInitialized) - , fSubset(NULL) + , fSubset(nullptr) + , fFrameIndex(0) + , fHasPriorFrame(false) + , fPremulBehavior(SkTransferFunctionBehavior::kRespect) {} - ZeroInitialized fZeroInitialized; + ZeroInitialized fZeroInitialized; /** * If not NULL, represents a subset of the original image to decode. * Must be within the bounds returned by getInfo(). - * If the EncodedFormat is kWEBP_SkEncodedFormat (the only one which + * If the EncodedFormat is SkEncodedImageFormat::kWEBP (the only one which * currently supports subsets), the top and left values must be even. * * In getPixels and incremental decode, we will attempt to decode the @@ -264,7 +270,41 @@ public: * subset left and subset width to decode partial scanlines on calls * to getScanlines(). */ - SkIRect* fSubset; + const SkIRect* fSubset; + + /** + * The frame to decode. + * + * Only meaningful for multi-frame images. + */ + size_t fFrameIndex; + + /** + * If true, the dst already contains the prior frame. + * + * Only meaningful for multi-frame images. + * + * If fFrameIndex needs to be blended with a prior frame (as reported by + * getFrameInfo[fFrameIndex].fRequiredFrame), the client can set this to + * either true or false: + * + * true means that the prior frame is already in the dst, and this + * codec only needs to decode fFrameIndex and blend it with the dst. + * Options.fZeroInitialized is ignored in this case. + * + * false means that the dst does not contain the prior frame, so this + * codec needs to first decode the prior frame (which in turn may need + * to decode its prior frame). + */ + bool fHasPriorFrame; + + /** + * Indicates whether we should do a linear premultiply or a legacy premultiply. + * + * In the case where the dst SkColorSpace is nullptr, this flag is ignored and + * we will always do a legacy premultiply. + */ + SkTransferFunctionBehavior fPremulBehavior; }; /** @@ -522,19 +562,6 @@ public: * Upside down bmps are an example. */ kBottomUp_SkScanlineOrder, - - /* - * This indicates that the scanline decoder reliably outputs rows, but - * they will not be in logical order. If the scanline format is - * kOutOfOrder, the nextScanline() API should be used to determine the - * actual y-coordinate of the next output row. - * - * For this scanline ordering, it is advisable to get and skip - * scanlines one at a time. - * - * Interlaced gifs are an example. - */ - kOutOfOrder_SkScanlineOrder, }; /** @@ -550,7 +577,7 @@ public: * decoder. * * This will equal fCurrScanline, except in the case of strangely - * encoded image types (bottom-up bmps, interlaced gifs). + * encoded image types (bottom-up bmps). * * Results are undefined when not in scanline decoding mode. */ @@ -566,6 +593,87 @@ public: */ int outputScanline(int inputScanline) const; + /** + * Return the number of frames in the image. + * + * May require reading through the stream. + */ + size_t getFrameCount() { + return this->onGetFrameCount(); + } + + // The required frame for an independent frame is marked as + // kNone. + static constexpr size_t kNone = static_cast(-1); + + /** + * Information about individual frames in a multi-framed image. + */ + struct FrameInfo { + /** + * The frame that this frame needs to be blended with, or + * kNone. + */ + size_t fRequiredFrame; + + /** + * Number of milliseconds to show this frame. + */ + size_t fDuration; + + /** + * Whether the end marker for this frame is contained in the stream. + * + * Note: this does not guarantee that an attempt to decode will be complete. + * There could be an error in the stream. + */ + bool fFullyReceived; + + /** + * This is conservative; it will still return non-opaque if e.g. a + * color index-based frame has a color with alpha but does not use it. + */ + SkAlphaType fAlphaType; + }; + + /** + * Return info about a single frame. + * + * Only supported by multi-frame images. Does not read through the stream, + * so it should be called after getFrameCount() to parse any frames that + * have not already been parsed. + */ + bool getFrameInfo(size_t index, FrameInfo* info) const { + return this->onGetFrameInfo(index, info); + } + + /** + * Return info about all the frames in the image. + * + * May require reading through the stream to determine info about the + * frames (including the count). + * + * As such, future decoding calls may require a rewind. + * + * For single-frame images, this will return an empty vector. + */ + std::vector getFrameInfo(); + + static constexpr int kRepetitionCountInfinite = -1; + + /** + * Return the number of times to repeat, if this image is animated. + * + * May require reading the stream to find the repetition count. + * + * As such, future decoding calls may require a rewind. + * + * For single-frame images, this will return 0. + */ + int getRepetitionCount() { + return this->onGetRepetitionCount(); + } + protected: /** * Takes ownership of SkStream* @@ -574,7 +682,7 @@ protected: int height, const SkEncodedInfo&, SkStream*, - sk_sp = nullptr, + sk_sp, Origin = kTopLeft_Origin); /** @@ -600,7 +708,7 @@ protected: return false; } - virtual SkEncodedFormat onGetEncodedFormat() const = 0; + virtual SkEncodedImageFormat onGetEncodedFormat() const = 0; /** * @param rowsDecoded When the encoded image stream is incomplete, this function @@ -706,25 +814,42 @@ protected: virtual int onOutputScanline(int inputScanline) const; - /** - * Used for testing with qcms. - * FIXME: Remove this when we are done comparing with qcms. - */ - virtual sk_sp getICCData() const { return nullptr; } -private: - const SkEncodedInfo fEncodedInfo; - const SkImageInfo fSrcInfo; - SkAutoTDelete fStream; - bool fNeedsRewind; - const Origin fOrigin; + bool initializeColorXform(const SkImageInfo& dstInfo, + SkTransferFunctionBehavior premulBehavior); + SkColorSpaceXform* colorXform() const { return fColorXform.get(); } - SkImageInfo fDstInfo; - SkCodec::Options fOptions; + virtual size_t onGetFrameCount() { + return 1; + } + + virtual bool onGetFrameInfo(size_t, FrameInfo*) const { + return false; + } + + virtual int onGetRepetitionCount() { + return 0; + } + + void setUnsupportedICC(bool SkDEBUGCODE(value)) { SkDEBUGCODE(fUnsupportedICC = value); } + +private: + const SkEncodedInfo fEncodedInfo; + const SkImageInfo fSrcInfo; + std::unique_ptr fStream; + bool fNeedsRewind; + const Origin fOrigin; + + SkImageInfo fDstInfo; + SkCodec::Options fOptions; + std::unique_ptr fColorXform; // Only meaningful during scanline decodes. - int fCurrScanline; + int fCurrScanline; - bool fStartedIncrementalDecode; + bool fStartedIncrementalDecode; +#ifdef SK_DEBUG + bool fUnsupportedICC = false; +#endif /** * Return whether these dimensions are supported as a scale. @@ -782,17 +907,14 @@ private: * May create a sampler, if one is not currently being used. Otherwise, does * not affect ownership. * - * Only valid during scanline decoding. + * Only valid during scanline decoding or incremental decoding. */ virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; } - // For testing with qcms - // FIXME: Remove these when we are done comparing with qcms. - friend class DM::ColorCodecSrc; - friend class ColorCodecBench; - friend class DM::CodecSrc; // for fillIncompleteImage friend class SkSampledCodec; friend class SkIcoCodec; + friend struct Sniffer; // for fUnsupportedICC + friend class AutoCleanPng; // for setUnsupportedICC() }; #endif // SkCodec_DEFINED diff --git a/gfx/skia/skia/include/codec/SkEncodedFormat.h b/gfx/skia/skia/include/codec/SkEncodedFormat.h deleted file mode 100644 index c097e088f231..000000000000 --- a/gfx/skia/skia/include/codec/SkEncodedFormat.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkEncodedFormat_DEFINED -#define SkEncodedFormat_DEFINED - -/** - * Enum describing format of encoded data. - */ -enum SkEncodedFormat { - kUnknown_SkEncodedFormat, - kBMP_SkEncodedFormat, - kGIF_SkEncodedFormat, - kICO_SkEncodedFormat, - kJPEG_SkEncodedFormat, - kPNG_SkEncodedFormat, - kWBMP_SkEncodedFormat, - kWEBP_SkEncodedFormat, - kPKM_SkEncodedFormat, - kKTX_SkEncodedFormat, - kASTC_SkEncodedFormat, - kDNG_SkEncodedFormat, -}; -#endif // SkEncodedFormat_DEFINED diff --git a/gfx/skia/skia/include/config/SkUserConfig.h b/gfx/skia/skia/include/config/SkUserConfig.h index 18e77ada5b82..cb028dd23ca7 100644 --- a/gfx/skia/skia/include/config/SkUserConfig.h +++ b/gfx/skia/skia/include/config/SkUserConfig.h @@ -93,10 +93,6 @@ */ //#define SK_DEFAULT_IMAGE_CACHE_LIMIT (1024 * 1024) -/* Define this to provide font subsetter in PDF generation. - */ -//#define SK_SFNTLY_SUBSETTER "sample/chromium/font_subsetter.h" - /* Define this to set the upper limit for text to support LCD. Values that are very large increase the cost in the font cache and draw slower, without improving readability. If this is undefined, Skia will use its default @@ -161,8 +157,6 @@ #define SK_DISABLE_SLOW_DEBUG_VALIDATION 1 -#define MOZ_SKIA 1 - #ifndef MOZ_IMPLICIT # ifdef MOZ_CLANG_PLUGIN # define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) @@ -171,4 +165,6 @@ # endif #endif +#define MOZ_SKIA + #endif diff --git a/gfx/skia/skia/include/core/SkBitmap.h b/gfx/skia/skia/include/core/SkBitmap.h index ce1b56e7bf0e..0fcfa2b24c15 100644 --- a/gfx/skia/skia/include/core/SkBitmap.h +++ b/gfx/skia/skia/include/core/SkBitmap.h @@ -20,8 +20,6 @@ struct SkIRect; struct SkRect; class SkPaint; class SkPixelRef; -class SkPixelRefFactory; -class SkRegion; class SkString; /** \class SkBitmap @@ -33,6 +31,8 @@ class SkString; A const SkBitmap exposes getAddr(), which lets a caller write its pixels; the constness is considered to apply to the bitmap's configuration, not its contents. + + SkBitmap is not thread safe. Each thread must use its own (shallow) copy. */ class SK_API SkBitmap { public: @@ -85,6 +85,7 @@ public: SkColorType colorType() const { return fInfo.colorType(); } SkAlphaType alphaType() const { return fInfo.alphaType(); } SkColorSpace* colorSpace() const { return fInfo.colorSpace(); } + sk_sp refColorSpace() const { return fInfo.refColorSpace(); } /** * Return the number of bytes per pixel based on the colortype. If the colortype is @@ -117,7 +118,7 @@ public: * dimensions of the bitmap are > 0 (see empty()). * Hey! Before you use this, see if you really want to know drawsNothing() instead. */ - bool isNull() const { return NULL == fPixelRef; } + bool isNull() const { return nullptr == fPixelRef; } /** Return true iff drawing this bitmap has no effect. */ @@ -215,7 +216,10 @@ public: * this (isOpaque). Only call this if you need to compute this value from * "unknown" pixels. */ - static bool ComputeIsOpaque(const SkBitmap&); + static bool ComputeIsOpaque(const SkBitmap& bm) { + SkAutoPixmapUnlock result; + return bm.requestLock(&result) && result.pixmap().computeIsOpaque(); + } /** * Return the bitmap's bounds [0, 0, width, height] as an SkRect @@ -233,16 +237,20 @@ public: bool setInfo(const SkImageInfo&, size_t rowBytes = 0); + enum AllocFlags { + kZeroPixels_AllocFlag = 1 << 0, + }; /** * Allocate the bitmap's pixels to match the requested image info. If the Factory * is non-null, call it to allcoate the pixelref. If the ImageInfo requires - * a colortable, then ColorTable must be non-null, and will be ref'd. + * a colortable, then ColorTable must be non-null. + * * On failure, the bitmap will be set to empty and return false. */ - bool SK_WARN_UNUSED_RESULT tryAllocPixels(const SkImageInfo&, SkPixelRefFactory*, SkColorTable*); - - void allocPixels(const SkImageInfo& info, SkPixelRefFactory* factory, SkColorTable* ctable) { - if (!this->tryAllocPixels(info, factory, ctable)) { + bool SK_WARN_UNUSED_RESULT tryAllocPixels(const SkImageInfo& info, sk_sp ctable, + uint32_t flags = 0); + void allocPixels(const SkImageInfo& info, sk_sp ctable, uint32_t flags = 0) { + if (!this->tryAllocPixels(info, std::move(ctable), flags)) { sk_throw(); } } @@ -283,6 +291,11 @@ public: this->allocPixels(info); } + // TEMPORARY -- remove after updating Android BitmapTests.cpp:35 + void allocPixels(const SkImageInfo& info, std::nullptr_t, SkColorTable* ctable) { + this->allocPixels(info, sk_ref_sp(ctable)); + } + /** * Install a pixelref that wraps the specified pixels and rowBytes, and * optional ReleaseProc and context. When the pixels are no longer @@ -332,27 +345,6 @@ public: */ void setPixels(void* p, SkColorTable* ctable = NULL); - /** Copies the bitmap's pixels to the location pointed at by dst and returns - true if possible, returns false otherwise. - - In the case when the dstRowBytes matches the bitmap's rowBytes, the copy - may be made faster by copying over the dst's per-row padding (for all - rows but the last). By setting preserveDstPad to true the caller can - disable this optimization and ensure that pixels in the padding are not - overwritten. - - Always returns false for RLE formats. - - @param dst Location of destination buffer. - @param dstSize Size of destination buffer. Must be large enough to hold - pixels using indicated stride. - @param dstRowBytes Width of each line in the buffer. If 0, uses - bitmap's internal stride. - @param preserveDstPad Must we preserve padding in the dst - */ - bool copyPixelsTo(void* const dst, size_t dstSize, size_t dstRowBytes = 0, - bool preserveDstPad = false) const; - /** Use the standard HeapAllocator to create the pixelref that manages the pixel memory. It will be sized based on the current ImageInfo. If this is called multiple times, a new pixelref object will be created @@ -404,7 +396,7 @@ public: * Return the current pixelref object or NULL if there is none. This does * not affect the refcount of the pixelref. */ - SkPixelRef* pixelRef() const { return fPixelRef; } + SkPixelRef* pixelRef() const { return fPixelRef.get(); } /** * A bitmap can reference a subset of a pixelref's pixels. That means the @@ -420,21 +412,12 @@ public: SkIPoint pixelRefOrigin() const { return fPixelRefOrigin; } /** - * Assign a pixelref and origin to the bitmap. Pixelrefs are reference, - * so the existing one (if any) will be unref'd and the new one will be - * ref'd. (x,y) specify the offset within the pixelref's pixels for the - * top/left corner of the bitmap. For a bitmap that encompases the entire - * pixels of the pixelref, these will be (0,0). + * Assign a pixelref and origin to the bitmap. (dx,dy) specify the offset + * within the pixelref's pixels for the top/left corner of the bitmap. For + * a bitmap that encompases the entire pixels of the pixelref, these will + * be (0,0). */ - SkPixelRef* setPixelRef(SkPixelRef* pr, int dx, int dy); - - SkPixelRef* setPixelRef(SkPixelRef* pr, const SkIPoint& origin) { - return this->setPixelRef(pr, origin.fX, origin.fY); - } - - SkPixelRef* setPixelRef(SkPixelRef* pr) { - return this->setPixelRef(pr, 0, 0); - } + void setPixelRef(sk_sp, int dx, int dy); /** Call this to ensure that the bitmap points to the current pixel address in the pixelref. Balance it with a call to unlockPixels(). These calls @@ -448,15 +431,6 @@ public: */ void unlockPixels() const; - /** - * Some bitmaps can return a copy of their pixels for lockPixels(), but - * that copy, if modified, will not be pushed back. These bitmaps should - * not be used as targets for a raster device/canvas (since all pixels - * modifications will be lost when unlockPixels() is called.) - */ - // DEPRECATED - bool lockPixelsAreWritable() const; - bool requestLock(SkAutoPixmapUnlock* result) const; /** Call this to be sure that the bitmap is valid enough to be drawn (i.e. @@ -525,13 +499,19 @@ public: } /** - * Return the SkColor of the specified pixel. In most cases this will - * require un-premultiplying the color. Alpha only colortypes (e.g. kAlpha_8_SkColorType) - * return black with the appropriate alpha set. The value is undefined - * for kUnknown_SkColorType or if x or y are out of bounds, or if the bitmap - * does not have any pixels (or has not be locked with lockPixels()). + * Converts the pixel at the specified coordinate to an unpremultiplied + * SkColor. Note: this ignores any SkColorSpace information, and may return + * lower precision data than is actually in the pixel. Alpha only + * colortypes (e.g. kAlpha_8_SkColorType) return black with the appropriate + * alpha set. The value is undefined for kUnknown_SkColorType or if x or y + * are out of bounds, or if the bitmap does not have any pixels (or has not + * be locked with lockPixels()).. */ - SkColor getColor(int x, int y) const; + SkColor getColor(int x, int y) const { + SkPixmap pixmap; + SkAssertResult(this->peekPixels(&pixmap)); + return pixmap.getColor(x, y); + } /** Returns the address of the specified pixel. This performs a runtime check to know the size of the pixels, and will return the same answer @@ -586,6 +566,7 @@ public: */ bool extractSubset(SkBitmap* dst, const SkIRect& subset) const; +#ifdef SK_BUILD_FOR_ANDROID /** Makes a deep copy of this bitmap, respecting the requested colorType, * and allocating the dst pixels on the cpu. * Returns false if either there is an error (i.e. the src does not have @@ -598,11 +579,26 @@ public: * will be used. * @return true if the copy was made. */ - bool copyTo(SkBitmap* dst, SkColorType ct, Allocator* = NULL) const; + bool copyTo(SkBitmap* dst, SkColorType ct, Allocator*) const; - bool copyTo(SkBitmap* dst, Allocator* allocator = NULL) const { + bool copyTo(SkBitmap* dst, Allocator* allocator) const { return this->copyTo(dst, this->colorType(), allocator); } +#endif + + /** Makes a deep copy of this bitmap, respecting the requested colorType. + * Returns false if either there is an error (i.e. the src does not have + * pixels) or the request cannot be satisfied (e.g. the src has per-pixel + * alpha, and the requested colortype does not support alpha). + * @param dst The bitmap to be sized and allocated + * @param ct The desired colorType for dst + * @return true if the copy was made. + */ + bool copyTo(SkBitmap* dst, SkColorType ct) const; + + bool copyTo(SkBitmap* dst) const { + return this->copyTo(dst, this->colorType()); + } /** * Copy the bitmap's pixels into the specified buffer (pixels + rowBytes), @@ -625,6 +621,23 @@ public: */ bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY) const; + bool readPixels(const SkPixmap& dst, int srcX, int srcY) const; + bool readPixels(const SkPixmap& dst) const { + return this->readPixels(dst, 0, 0); + } + + /** + * Copy the src pixmap's pixels into this bitmap, offset by dstX, dstY. + * + * This is logically the same as creating a bitmap around src, and calling readPixels on it + * with this bitmap as the dst. + */ + bool writePixels(const SkPixmap& src, int dstX, int dstY) { + return this->writePixels(src, dstX, dstY, SkTransferFunctionBehavior::kRespect); + } + bool writePixels(const SkPixmap& src) { + return this->writePixels(src, 0, 0); + } /** * Returns true if this bitmap's pixels can be converted into the requested @@ -715,37 +728,16 @@ public: bool allocPixelRef(SkBitmap*, SkColorTable*) override; }; - class RLEPixels { - public: - RLEPixels(int width, int height); - virtual ~RLEPixels(); - - uint8_t* packedAtY(int y) const { - SkASSERT((unsigned)y < (unsigned)fHeight); - return fYPtrs[y]; - } - - // called by subclasses during creation - void setPackedAtY(int y, uint8_t* addr) { - SkASSERT((unsigned)y < (unsigned)fHeight); - fYPtrs[y] = addr; - } - - private: - uint8_t** fYPtrs; - int fHeight; - }; - SK_TO_STRING_NONVIRT() private: - mutable SkPixelRef* fPixelRef; - mutable int fPixelLockCount; + mutable sk_sp fPixelRef; + mutable int fPixelLockCount; // These are just caches from the locked pixelref - mutable void* fPixels; - mutable SkColorTable* fColorTable; // only meaningful for kIndex8 + mutable void* fPixels; + mutable SkColorTable* fColorTable; // only meaningful for kIndex8 - SkIPoint fPixelRefOrigin; + SkIPoint fPixelRefOrigin; enum Flags { kImageIsVolatile_Flag = 0x02, @@ -758,9 +750,13 @@ private: #endif }; - SkImageInfo fInfo; - uint32_t fRowBytes; - uint8_t fFlags; + SkImageInfo fInfo; + uint32_t fRowBytes; + uint8_t fFlags; + + bool writePixels(const SkPixmap& src, int x, int y, SkTransferFunctionBehavior behavior); + + bool internalCopyTo(SkBitmap* dst, SkColorType ct, Allocator*) const; /* Unreference any pixelrefs or colortables */ @@ -770,6 +766,7 @@ private: static void WriteRawPixels(SkWriteBuffer*, const SkBitmap&); static bool ReadRawPixels(SkReadBuffer*, SkBitmap*); + friend class SkImage_Raster; friend class SkReadBuffer; // unflatten, rawpixels friend class SkBinaryWriteBuffer; // rawpixels friend struct SkBitmapProcState; diff --git a/gfx/skia/skia/include/core/SkBlendMode.h b/gfx/skia/skia/include/core/SkBlendMode.h index eb3469f25600..3f8f30c51051 100644 --- a/gfx/skia/skia/include/core/SkBlendMode.h +++ b/gfx/skia/skia/include/core/SkBlendMode.h @@ -8,6 +8,8 @@ #ifndef SkBlendMode_DEFINED #define SkBlendMode_DEFINED +#include "SkTypes.h" + enum class SkBlendMode { kClear, //!< [0, 0] kSrc, //!< [Sa, Sc] @@ -48,4 +50,9 @@ enum class SkBlendMode { kLastMode = kLuminosity }; +/** + * Return the (c-string) name of the blendmode. + */ +SK_API const char* SkBlendMode_Name(SkBlendMode); + #endif diff --git a/gfx/skia/skia/include/core/SkCanvas.h b/gfx/skia/skia/include/core/SkCanvas.h index 5078f4255ce2..a8d332cca88a 100644 --- a/gfx/skia/skia/include/core/SkCanvas.h +++ b/gfx/skia/skia/include/core/SkCanvas.h @@ -8,42 +8,41 @@ #ifndef SkCanvas_DEFINED #define SkCanvas_DEFINED -#include "SkTypes.h" #include "SkBlendMode.h" -#include "SkBitmap.h" #include "SkClipOp.h" #include "SkDeque.h" -#include "SkImage.h" #include "SkPaint.h" -#include "SkRefCnt.h" -#include "SkRegion.h" +#include "SkRasterHandleAllocator.h" #include "SkSurfaceProps.h" -#include "SkXfermode.h" #include "SkLights.h" #include "../private/SkShadowParams.h" class GrContext; -class GrDrawContext; +class GrRenderTargetContext; class SkBaseDevice; +class SkBitmap; +#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP class SkCanvasClipVisitor; +#endif class SkClipStack; class SkData; class SkDraw; class SkDrawable; class SkDrawFilter; +class SkImage; class SkImageFilter; class SkMetaData; class SkPath; class SkPicture; class SkPixmap; class SkRasterClip; +class SkRegion; class SkRRect; struct SkRSXform; class SkSurface; class SkSurface_Base; class SkTextBlob; - -//#define SK_SUPPORT_LEGACY_CLIP_REGIONOPS +class SkVertices; /** \class SkCanvas @@ -60,31 +59,12 @@ class SkTextBlob; color, typeface, textSize, strokeWidth, shader (e.g. gradients, patterns), etc. */ -class SK_API SkCanvas : public SkRefCnt { +class SK_API SkCanvas : SkNoncopyable { enum PrivateSaveLayerFlags { kDontClipToLayer_PrivateSaveLayerFlag = 1U << 31, }; public: -#ifdef SK_SUPPORT_LEGACY_CLIP_REGIONOPS - typedef SkRegion::Op ClipOp; - - static const ClipOp kDifference_Op = SkRegion::kDifference_Op; - static const ClipOp kIntersect_Op = SkRegion::kIntersect_Op; - static const ClipOp kUnion_Op = SkRegion::kUnion_Op; - static const ClipOp kXOR_Op = SkRegion::kXOR_Op; - static const ClipOp kReverseDifference_Op = SkRegion::kReverseDifference_Op; - static const ClipOp kReplace_Op = SkRegion::kReplace_Op; -#else - typedef SkClipOp ClipOp; - - static const ClipOp kDifference_Op = kDifference_SkClipOp; - static const ClipOp kIntersect_Op = kIntersect_SkClipOp; - static const ClipOp kUnion_Op = kUnion_SkClipOp; - static const ClipOp kXOR_Op = kXOR_SkClipOp; - static const ClipOp kReverseDifference_Op = kReverseDifference_SkClipOp; - static const ClipOp kReplace_Op = kReplace_SkClipOp; -#endif /** * Attempt to allocate raster canvas, matching the ImageInfo, that will draw directly into the * specified pixels. To access the pixels after drawing to them, the caller should call @@ -100,10 +80,11 @@ public: * Note: it is valid to request a supported ImageInfo, but with zero * dimensions. */ - static SkCanvas* NewRasterDirect(const SkImageInfo&, void*, size_t); + static std::unique_ptr MakeRasterDirect(const SkImageInfo&, void*, size_t); - static SkCanvas* NewRasterDirectN32(int width, int height, SkPMColor* pixels, size_t rowBytes) { - return NewRasterDirect(SkImageInfo::MakeN32Premul(width, height), pixels, rowBytes); + static std::unique_ptr MakeRasterDirectN32(int width, int height, SkPMColor* pixels, + size_t rowBytes) { + return MakeRasterDirect(SkImageInfo::MakeN32Premul(width, height), pixels, rowBytes); } /** @@ -131,6 +112,19 @@ public: */ explicit SkCanvas(const SkBitmap& bitmap); +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + enum class ColorBehavior { + kLegacy, + }; + + /** + * Android framework only constructor. + * Allows the creation of a legacy SkCanvas even though the |bitmap| + * and its pixel ref may have an SkColorSpace. + */ + SkCanvas(const SkBitmap& bitmap, ColorBehavior); +#endif + /** Construct a canvas with the specified bitmap to draw into. @param bitmap Specifies a bitmap for the canvas to draw into. Its structure are copied to the canvas. @@ -171,45 +165,6 @@ public: */ virtual SkISize getBaseLayerSize() const; - /** - * DEPRECATED: call getBaseLayerSize - */ - SkISize getDeviceSize() const { return this->getBaseLayerSize(); } - - /** - * DEPRECATED. - * Return the canvas' device object, which may be null. The device holds - * the bitmap of the pixels that the canvas draws into. The reference count - * of the returned device is not changed by this call. - */ -#ifndef SK_SUPPORT_LEGACY_GETDEVICE -protected: // Can we make this private? -#endif - SkBaseDevice* getDevice() const; -public: - SkBaseDevice* getDevice_just_for_deprecated_compatibility_testing() const { - return this->getDevice(); - } - - /** - * saveLayer() can create another device (which is later drawn onto - * the previous device). getTopDevice() returns the top-most device current - * installed. Note that this can change on other calls like save/restore, - * so do not access this device after subsequent canvas calls. - * The reference count of the device is not changed. - * - * @param updateMatrixClip If this is true, then before the device is - * returned, we ensure that its has been notified about the current - * matrix and clip. Note: this happens automatically when the device - * is drawn to, but is optional here, as there is a small perf hit - * sometimes. - */ -#ifndef SK_SUPPORT_LEGACY_GETTOPDEVICE -private: -#endif - SkBaseDevice* getTopDevice(bool updateMatrixClip = false) const; -public: - /** * Create a new surface matching the specified info, one that attempts to * be maximally compatible when used with this canvas. If there is no matching Surface type, @@ -220,9 +175,6 @@ public: * surface, then the new surface is created with default properties. */ sk_sp makeSurface(const SkImageInfo&, const SkSurfaceProps* = nullptr); -#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API - SkSurface* newSurface(const SkImageInfo& info, const SkSurfaceProps* props = NULL); -#endif /** * Return the GPU context of the device that is associated with the canvas. @@ -245,6 +197,8 @@ public: */ void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = NULL); + SkRasterHandleAllocator::Handle accessTopRasterHandle() const; + /** * If the canvas has readable pixels in its base layer (and is not recording to a picture * or other non-raster target) and has direct access to its pixels (i.e. they are in @@ -258,10 +212,6 @@ public: */ bool peekPixels(SkPixmap*); -#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS - const void* peekPixels(SkImageInfo* info, size_t* rowBytes); -#endif - /** * Copy the pixels from the base-layer into the specified buffer (pixels + rowBytes), * converting them into the requested format (SkImageInfo). The base-layer pixels are read @@ -379,6 +329,9 @@ public: kIsOpaque_SaveLayerFlag = 1 << 0, kPreserveLCDText_SaveLayerFlag = 1 << 1, + /** initialize the new layer with the contents of the previous layer */ + kInitWithPrevious_SaveLayerFlag = 1 << 2, + #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG kDontClipToLayer_Legacy_SaveLayerFlag = kDontClipToLayer_PrivateSaveLayerFlag, #endif @@ -500,26 +453,37 @@ public: * @param op The region op to apply to the current clip * @param doAntiAlias true if the clip should be antialiased */ - void clipRect(const SkRect& rect, ClipOp, bool doAntiAlias); - void clipRect(const SkRect& rect, ClipOp op) { + void clipRect(const SkRect& rect, SkClipOp, bool doAntiAlias); + void clipRect(const SkRect& rect, SkClipOp op) { this->clipRect(rect, op, false); } void clipRect(const SkRect& rect, bool doAntiAlias = false) { - this->clipRect(rect, kIntersect_Op, doAntiAlias); + this->clipRect(rect, SkClipOp::kIntersect, doAntiAlias); } + /** + * Sets the max clip rectangle, which can be set by clipRect, clipRRect and + * clipPath and intersect the current clip with the specified rect. + * The max clip affects only future ops (it is not retroactive). + * We DON'T record the clip restriction in pictures. + * This is private API to be used only by Android framework. + * @param rect The maximum allowed clip in device coordinates. + * Empty rect means max clip is not enforced. + */ + void androidFramework_setDeviceClipRestriction(const SkIRect& rect); + /** * Modify the current clip with the specified SkRRect. * @param rrect The rrect to combine with the current clip * @param op The region op to apply to the current clip * @param doAntiAlias true if the clip should be antialiased */ - void clipRRect(const SkRRect& rrect, ClipOp op, bool doAntiAlias); - void clipRRect(const SkRRect& rrect, ClipOp op) { + void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias); + void clipRRect(const SkRRect& rrect, SkClipOp op) { this->clipRRect(rrect, op, false); } void clipRRect(const SkRRect& rrect, bool doAntiAlias = false) { - this->clipRRect(rrect, kIntersect_Op, doAntiAlias); + this->clipRRect(rrect, SkClipOp::kIntersect, doAntiAlias); } /** @@ -528,12 +492,12 @@ public: * @param op The region op to apply to the current clip * @param doAntiAlias true if the clip should be antialiased */ - void clipPath(const SkPath& path, ClipOp op, bool doAntiAlias); - void clipPath(const SkPath& path, ClipOp op) { + void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias); + void clipPath(const SkPath& path, SkClipOp op) { this->clipPath(path, op, false); } void clipPath(const SkPath& path, bool doAntiAlias = false) { - this->clipPath(path, kIntersect_Op, doAntiAlias); + this->clipPath(path, SkClipOp::kIntersect, doAntiAlias); } /** EXPERIMENTAL -- only used for testing @@ -550,7 +514,7 @@ public: @param deviceRgn The region to apply to the current clip @param op The region op to apply to the current clip */ - void clipRegion(const SkRegion& deviceRgn, ClipOp op = kIntersect_Op); + void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect); /** Return true if the specified rectangle, after being transformed by the current matrix, would lie completely outside of the current clip. Call @@ -574,34 +538,33 @@ public: */ bool quickReject(const SkPath& path) const; - /** Return the bounds of the current clip (in local coordinates) in the - bounds parameter, and return true if it is non-empty. This can be useful - in a way similar to quickReject, in that it tells you that drawing - outside of these bounds will be clipped out. - */ - virtual bool getClipBounds(SkRect* bounds) const; + /** + * Return the bounds of the current clip in local coordinates. If the clip is empty, + * return { 0, 0, 0, 0 }. + */ + SkRect getLocalClipBounds() const { return this->onGetLocalClipBounds(); } - /** Return the bounds of the current clip, in device coordinates; returns - true if non-empty. Maybe faster than getting the clip explicitly and - then taking its bounds. - */ - virtual bool getClipDeviceBounds(SkIRect* bounds) const; - - - /** Fill the entire canvas' bitmap (restricted to the current clip) with the - specified ARGB color, using the specified mode. - @param a the alpha component (0..255) of the color to fill the canvas - @param r the red component (0..255) of the color to fill the canvas - @param g the green component (0..255) of the color to fill the canvas - @param b the blue component (0..255) of the color to fill the canvas - @param mode the mode to apply the color in (defaults to SrcOver) - */ - void drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode = SkBlendMode::kSrcOver); -#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT - void drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkXfermode::Mode mode) { - this->drawARGB(a, r, g, b, (SkBlendMode)mode); + /** + * Returns true if the clip bounds are non-empty. + */ + bool getLocalClipBounds(SkRect* bounds) const { + *bounds = this->onGetLocalClipBounds(); + return !bounds->isEmpty(); + } + + /** + * Return the bounds of the current clip in device coordinates. If the clip is empty, + * return { 0, 0, 0, 0 }. + */ + SkIRect getDeviceClipBounds() const { return this->onGetDeviceClipBounds(); } + + /** + * Returns true if the clip bounds are non-empty. + */ + bool getDeviceClipBounds(SkIRect* bounds) const { + *bounds = this->onGetDeviceClipBounds(); + return !bounds->isEmpty(); } -#endif /** Fill the entire canvas' bitmap (restricted to the current clip) with the specified color and mode. @@ -609,11 +572,6 @@ public: @param mode the mode to apply the color in (defaults to SrcOver) */ void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver); -#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT - void drawColor(SkColor color, SkXfermode::Mode mode) { - this->drawColor(color, (SkBlendMode)mode); - } -#endif /** * Helper method for drawing a color in SRC mode, completely replacing all the pixels @@ -676,18 +634,10 @@ public: */ void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint); - /** Helper method for drawing a single point. See drawPoints() for a more - details. - */ + /** Helper method for drawing a single point. See drawPoints() for more details. + */ void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint); - /** Draws a single pixel in the specified color. - @param x The X coordinate of which pixel to draw - @param y The Y coordiante of which pixel to draw - @param color The color to draw - */ - void drawPoint(SkScalar x, SkScalar y, SkColor color); - /** Draw a line segment with the specified start and stop x,y coordinates, using the specified paint. NOTE: since a line is always "framed", the paint's Style is ignored. @@ -697,8 +647,7 @@ public: @param y1 The y-coordinate of the end point of the line @param paint The paint used to draw the line */ - void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, - const SkPaint& paint); + void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint); /** Draw the specified rectangle using the specified paint. The rectangle will be filled or stroked based on the Style in the paint. @@ -718,17 +667,6 @@ public: this->drawRect(r, paint); } - /** Draw the specified rectangle using the specified paint. The rectangle - will be filled or framed based on the Style in the paint. - @param left The left side of the rectangle to be drawn - @param top The top side of the rectangle to be drawn - @param right The right side of the rectangle to be drawn - @param bottom The bottom side of the rectangle to be drawn - @param paint The paint used to draw the rect - */ - void drawRectCoords(SkScalar left, SkScalar top, SkScalar right, - SkScalar bottom, const SkPaint& paint); - /** Draw the outline of the specified region using the specified paint. @param region The region to be drawn @param paint The paint used to draw the region @@ -765,8 +703,7 @@ public: @param radius The radius of the cirle to be drawn @param paint The paint used to draw the circle */ - void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, - const SkPaint& paint); + void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint); /** Draw the specified arc, which will be scaled to fit inside the specified oval. Sweep angles are not treated as modulo 360 and thus can @@ -792,8 +729,7 @@ public: @param ry The y-radius of the oval used to round the corners @param paint The paint used to draw the roundRect */ - void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, - const SkPaint& paint); + void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint); /** Draw the specified path using the specified paint. The path will be filled or framed based on the Style in the paint. @@ -1176,48 +1112,16 @@ public: } #endif - enum VertexMode { - kTriangles_VertexMode, - kTriangleStrip_VertexMode, - kTriangleFan_VertexMode - }; + /** Draw vertices from an immutable SkVertices object. - /** Draw the array of vertices, interpreted as triangles (based on mode). - - If both textures and vertex-colors are NULL, it strokes hairlines with - the paint's color. This behavior is a useful debugging mode to visualize - the mesh. - - @param vmode How to interpret the array of vertices - @param vertexCount The number of points in the vertices array (and - corresponding texs and colors arrays if non-null) - @param vertices Array of vertices for the mesh - @param texs May be null. If not null, specifies the coordinate - in _texture_ space (not uv space) for each vertex. - @param colors May be null. If not null, specifies a color for each - vertex, to be interpolated across the triangle. - @param xmode Used if both texs and colors are present. In this - case the colors are combined with the texture using mode, - before being drawn using the paint. If mode is null, then - kModulate_Mode is used. - @param indices If not null, array of indices to reference into the - vertex (texs, colors) array. - @param indexCount number of entries in the indices array (if not null) + @param vertices The mesh to draw. + @param mode Used if both texs and colors are present and paint has a + shader. In this case the colors are combined with the texture + using mode, before being drawn using the paint. @param paint Specifies the shader/texture if present. - */ - void drawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint); - void drawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], const sk_sp& xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { - this->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode.get(), - indices, indexCount, paint); - } + */ + void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint); + void drawVertices(const sk_sp& vertices, SkBlendMode mode, const SkPaint& paint); /** Draw a cubic coons patch @@ -1228,15 +1132,15 @@ public: their order is clockwise starting at the top left corner. @param texCoords specifies the texture coordinates that will be bilerp across the patch, their order is the same as the colors. - @param xmode specifies how are the colors and the textures combined if both of them are + @param mode specifies how are the colors and the textures combined if both of them are present. @param paint Specifies the shader/texture if present. */ void drawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint); - void drawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], - const sk_sp& xmode, const SkPaint& paint) { - this->drawPatch(cubics, colors, texCoords, xmode.get(), paint); + const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint); + void drawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], const SkPaint& paint) { + this->drawPatch(cubics, colors, texCoords, SkBlendMode::kModulate, paint); } /** @@ -1247,32 +1151,30 @@ public: * xform maps [0, 0, tex.width, tex.height] -> quad * * The color array is optional. When specified, each color modulates the pixels in its - * corresponding quad (via the specified SkXfermode::Mode). + * corresponding quad (via the specified SkBlendMode). * * The cullRect is optional. When specified, it must be a conservative bounds of all of the * resulting transformed quads, allowing the canvas to skip drawing if the cullRect does not * intersect the current clip. * * The paint is optional. If specified, its antialiasing, alpha, color-filter, image-filter - * and xfermode are used to affect each of the quads. + * and blendmode are used to affect each of the quads. */ void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], - const SkColor colors[], int count, SkXfermode::Mode, const SkRect* cullRect, + const SkColor colors[], int count, SkBlendMode, const SkRect* cullRect, const SkPaint* paint); - + void drawAtlas(const sk_sp& atlas, const SkRSXform xform[], const SkRect tex[], + const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect, + const SkPaint* paint) { + this->drawAtlas(atlas.get(), xform, tex, colors, count, mode, cullRect, paint); + } void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count, const SkRect* cullRect, const SkPaint* paint) { - this->drawAtlas(atlas, xform, tex, NULL, count, SkXfermode::kDst_Mode, cullRect, paint); - } - - void drawAtlas(const sk_sp& atlas, const SkRSXform xform[], const SkRect tex[], - const SkColor colors[], int count, SkXfermode::Mode mode, const SkRect* cull, - const SkPaint* paint) { - this->drawAtlas(atlas.get(), xform, tex, colors, count, mode, cull, paint); + this->drawAtlas(atlas, xform, tex, nullptr, count, SkBlendMode::kDst, cullRect, paint); } void drawAtlas(const sk_sp& atlas, const SkRSXform xform[], const SkRect tex[], int count, const SkRect* cullRect, const SkPaint* paint) { - this->drawAtlas(atlas.get(), xform, tex, nullptr, count, SkXfermode::kDst_Mode, + this->drawAtlas(atlas.get(), xform, tex, nullptr, count, SkBlendMode::kDst, cullRect, paint); } @@ -1351,15 +1253,7 @@ public: */ const SkMatrix& getTotalMatrix() const; - /** Return the clip stack. The clip stack stores all the individual - * clips organized by the save/restore frame in which they were - * added. - * @return the current clip stack ("list" of individual clip elements) - */ - const SkClipStack* getClipStack() const { - return fClipStack; - } - +#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP typedef SkCanvasClipVisitor ClipVisitor; /** * Replays the clip operations, back to front, that have been applied to @@ -1367,11 +1261,12 @@ public: * clip. All clips have already been transformed into device space. */ void replayClips(ClipVisitor*) const; +#endif /////////////////////////////////////////////////////////////////////////// // don't call - GrDrawContext* internal_private_accessTopLayerDrawContext(); + GrRenderTargetContext* internal_private_accessTopLayerRenderTargetContext(); // don't call static void Internal_Private_SetIgnoreSaveLayerBounds(bool); @@ -1393,6 +1288,12 @@ public: */ void temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds); + /** + * Returns the global clip as a region. If the clip contains AA, then only the bounds + * of the clip may be returned. + */ + void temporary_internal_getRgnClip(SkRegion*); + protected: #ifdef SK_EXPERIMENTAL_SHADOWING /** Returns the current (cumulative) draw depth of the canvas. @@ -1437,6 +1338,10 @@ protected: virtual void didTranslateZ(SkScalar) {} #endif + virtual SkRect onGetLocalClipBounds() const; + virtual SkIRect onGetDeviceClipBounds() const; + + virtual void onDrawAnnotation(const SkRect&, const char key[], SkData* value); virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&); @@ -1460,7 +1365,7 @@ protected: const SkPaint& paint); virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint); + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint); virtual void onDrawDrawable(SkDrawable*, const SkMatrix*); @@ -1472,12 +1377,9 @@ protected: const SkPaint&); virtual void onDrawRRect(const SkRRect&, const SkPaint&); virtual void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&); - virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[], - const SkPoint texs[], const SkColor colors[], SkXfermode*, - const uint16_t indices[], int indexCount, const SkPaint&); - + virtual void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&); virtual void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], - int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*); + int count, SkBlendMode, const SkRect* cull, const SkPaint*); virtual void onDrawPath(const SkPath&, const SkPaint&); virtual void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*); virtual void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*, @@ -1500,10 +1402,10 @@ protected: kSoft_ClipEdgeStyle }; - virtual void onClipRect(const SkRect& rect, ClipOp, ClipEdgeStyle); - virtual void onClipRRect(const SkRRect& rrect, ClipOp, ClipEdgeStyle); - virtual void onClipPath(const SkPath& path, ClipOp, ClipEdgeStyle); - virtual void onClipRegion(const SkRegion& deviceRgn, ClipOp); + virtual void onClipRect(const SkRect& rect, SkClipOp, ClipEdgeStyle); + virtual void onClipRRect(const SkRRect& rrect, SkClipOp, ClipEdgeStyle); + virtual void onClipPath(const SkPath& path, SkClipOp, ClipEdgeStyle); + virtual void onClipRegion(const SkRegion& deviceRgn, SkClipOp); virtual void onDiscard(); @@ -1515,12 +1417,6 @@ protected: const SkPaint*, const SkShadowParams& params); #endif - - // Returns the canvas to be used by DrawIter. Default implementation - // returns this. Subclasses that encapsulate an indirect canvas may - // need to overload this method. The impl must keep track of this, as it - // is not released or deleted by the caller. - virtual SkCanvas* canvasForDrawIter(); // Clip rectangle bounds. Called internally by saveLayer. // returns false if the entire rectangle is entirely clipped out @@ -1551,7 +1447,7 @@ private: SkBaseDevice* device() const; const SkMatrix& matrix() const; - const SkRasterClip& clip() const; + void clip(SkRegion*) const; const SkPaint& paint() const; int x() const; int y() const; @@ -1567,13 +1463,13 @@ private: SkPaint fDefaultPaint; bool fDone; }; - + static bool BoundsAffectsClip(SaveLayerFlags); static SaveLayerFlags LegacySaveFlagsToSaveLayerFlags(uint32_t legacySaveFlags); static void DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter, - SkBaseDevice* dst, const SkMatrix& ctm, - const SkClipStack* clipStack); + SkBaseDevice* dst, const SkIPoint& dstOrigin, + const SkMatrix& ctm); enum ShaderOverrideOpacity { kNone_ShaderOverrideOpacity, //!< there is no overriding shader (bitmap or image) @@ -1590,9 +1486,13 @@ private: : kNotOpaque_ShaderOverrideOpacity); } +public: + SkBaseDevice* getDevice() const; + SkBaseDevice* getTopDevice() const; +private: + class MCRec; - SkAutoTUnref fClipStack; SkDeque fMCStack; // points to top of stack MCRec* fMCRec; @@ -1600,7 +1500,7 @@ private: enum { kMCRecSize = 128, // most recent measurement kMCRecCount = 32, // common depth for save/restores - kDeviceCMSize = 176, // most recent measurement + kDeviceCMSize = 184, // most recent measurement }; intptr_t fMCRecStorage[kMCRecSize * kMCRecCount / sizeof(intptr_t)]; intptr_t fDeviceCMStorage[kDeviceCMSize / sizeof(intptr_t)]; @@ -1610,6 +1510,7 @@ private: int fSaveCount; // value returned by getSaveCount() SkMetaData* fMetaData; + std::unique_ptr fAllocator; SkSurface_Base* fSurfaceBase; SkSurface_Base* getSurfaceBase() const { return fSurfaceBase; } @@ -1619,8 +1520,7 @@ private: friend class SkSurface_Base; friend class SkSurface_Gpu; - bool fDeviceCMDirty; // cleared by updateDeviceCMCache() - void updateDeviceCMCache(); + SkIRect fClipRestrictionRect = SkIRect::MakeEmpty(); void doSave(); void checkForDeferredSave(); @@ -1628,15 +1528,17 @@ private: friend class SkDrawIter; // needs setupDrawForLayerDevice() friend class AutoDrawLooper; - friend class SkLua; // needs top layer size and offset friend class SkDebugCanvas; // needs experimental fAllowSimplifyClip friend class SkSurface_Raster; // needs getDevice() - friend class SkRecorder; // InitFlags - friend class SkLiteRecorder; // InitFlags - friend class SkNoSaveLayerCanvas; // InitFlags + friend class SkRecorder; // resetForNextPicture + friend class SkLiteRecorder; // resetForNextPicture + friend class SkNoDrawCanvas; // InitFlags friend class SkPictureImageFilter; // SkCanvas(SkBaseDevice*, SkSurfaceProps*, InitFlags) friend class SkPictureRecord; // predrawNotify (why does it need it? ) friend class SkPicturePlayback; // SaveFlagsToSaveLayerFlags + friend class SkDeferredCanvas; // For use of resetForNextPicture + friend class SkOverdrawCanvas; + friend class SkRasterHandleAllocator; enum InitFlags { kDefault_InitFlags = 0, @@ -1644,6 +1546,8 @@ private: }; SkCanvas(const SkIRect& bounds, InitFlags); SkCanvas(SkBaseDevice* device, InitFlags); + SkCanvas(const SkBitmap&, std::unique_ptr, + SkRasterHandleAllocator::Handle); void resetForNextPicture(const SkIRect& bounds); @@ -1673,14 +1577,6 @@ private: // shared by save() and saveLayer() void internalSave(); void internalRestore(); - static void DrawRect(const SkDraw& draw, const SkPaint& paint, - const SkRect& r, SkScalar textSize); - static void DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, - const char text[], size_t byteLength, - SkScalar x, SkScalar y); - - // only for canvasutils - const SkRegion& internal_private_getTotalClip() const; /* * Returns true if drawing the specified rect (or all if it is null) with the specified @@ -1694,6 +1590,11 @@ private: */ bool canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint&); + /** + * Returns true if the clip (for any active layer) contains antialiasing. + * If the clip is empty, this will return false. + */ + bool androidFramework_isClipAA() const; /** * Keep track of the device clip bounds and if the matrix is scale-translate. This allows @@ -1704,7 +1605,6 @@ private: bool fAllowSoftClip; bool fAllowSimplifyClip; - const bool fConservativeRasterClip; class AutoValidateClip : ::SkNoncopyable { public: @@ -1763,12 +1663,14 @@ private: }; #define SkAutoCanvasRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoCanvasRestore) +#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP class SkCanvasClipVisitor { public: virtual ~SkCanvasClipVisitor(); - virtual void clipRect(const SkRect&, SkCanvas::ClipOp, bool antialias) = 0; - virtual void clipRRect(const SkRRect&, SkCanvas::ClipOp, bool antialias) = 0; - virtual void clipPath(const SkPath&, SkCanvas::ClipOp, bool antialias) = 0; + virtual void clipRect(const SkRect&, SkClipOp, bool antialias) = 0; + virtual void clipRRect(const SkRRect&, SkClipOp, bool antialias) = 0; + virtual void clipPath(const SkPath&, SkClipOp, bool antialias) = 0; }; +#endif #endif diff --git a/gfx/skia/skia/include/core/SkChunkAlloc.h b/gfx/skia/skia/include/core/SkChunkAlloc.h deleted file mode 100644 index bb4ec8faecad..000000000000 --- a/gfx/skia/skia/include/core/SkChunkAlloc.h +++ /dev/null @@ -1,89 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkChunkAlloc_DEFINED -#define SkChunkAlloc_DEFINED - -#include "SkTypes.h" - -class SkChunkAlloc : SkNoncopyable { -public: - SkChunkAlloc(size_t minSize); - ~SkChunkAlloc(); - - /** - * Free up all allocated blocks. This invalidates all returned - * pointers. - */ - void reset(); - /** - * Reset to 0 used bytes preserving as much memory as possible. - * This invalidates all returned pointers. - */ - void rewind(); - - enum AllocFailType { - kReturnNil_AllocFailType, - kThrow_AllocFailType - }; - - /** - * Allocates a memory block of size bytes. - * On success: returns a pointer to beginning of memory block that is - * 8 byte aligned. The content of allocated block is not initialized. - * On failure: calls abort() if called with kThrow_AllocFailType, - * otherwise returns NULL pointer. - */ - void* alloc(size_t bytes, AllocFailType); - - /** - * Shortcut for calling alloc with kThrow_AllocFailType. - */ - void* allocThrow(size_t bytes) { - return this->alloc(bytes, kThrow_AllocFailType); - } - - /** Call this to unalloc the most-recently allocated ptr by alloc(). On - success, the number of bytes freed is returned, or 0 if the block could - not be unallocated. This is a hint to the underlying allocator that - the previous allocation may be reused, but the implementation is free - to ignore this call (and return 0). - */ - size_t unalloc(void* ptr); - - size_t totalCapacity() const { return fTotalCapacity; } - size_t totalUsed() const { return fTotalUsed; } - SkDEBUGCODE(int blockCount() const { return fBlockCount; }) - SkDEBUGCODE(size_t totalLost() const { return fTotalLost; }) - - /** - * Returns true if the specified address is within one of the chunks, and - * has at least 1-byte following the address (i.e. if addr points to the - * end of a chunk, then contains() will return false). - */ - bool contains(const void* addr) const; - -private: - struct Block; - - Block* fBlock; - size_t fMinSize; - size_t fChunkSize; - size_t fTotalCapacity; - size_t fTotalUsed; // will be <= fTotalCapacity - SkDEBUGCODE(int fBlockCount;) - SkDEBUGCODE(size_t fTotalLost;) // will be <= fTotalCapacity - - Block* newBlock(size_t bytes, AllocFailType ftype); - Block* addBlockIfNecessary(size_t bytes, AllocFailType ftype); - - SkDEBUGCODE(void validate();) -}; - -#endif diff --git a/gfx/skia/skia/include/core/SkClipOp.h b/gfx/skia/skia/include/core/SkClipOp.h index 2e4fbbf86806..f230654efe53 100644 --- a/gfx/skia/skia/include/core/SkClipOp.h +++ b/gfx/skia/skia/include/core/SkClipOp.h @@ -10,17 +10,20 @@ #include "SkTypes.h" -// these kept in SkRegion::Op order for now ... -enum SkClipOp { - kDifference_SkClipOp = 0, - kIntersect_SkClipOp = 1, +// SkClipOp enum values always match the corresponding values in SkRegion::Op + +enum class SkClipOp { + kDifference = 0, + kIntersect = 1, // Goal: remove these, since they can grow the current clip - kUnion_SkClipOp = 2, - kXOR_SkClipOp = 3, - kReverseDifference_SkClipOp = 4, - kReplace_SkClipOp = 5, + kUnion_deprecated = 2, + kXOR_deprecated = 3, + kReverseDifference_deprecated = 4, + kReplace_deprecated = 5, + + kMax_EnumValue = kReplace_deprecated, }; #endif diff --git a/gfx/skia/skia/include/core/SkColor.h b/gfx/skia/skia/include/core/SkColor.h index 8f2776da61b1..5ee86fbee6c6 100644 --- a/gfx/skia/skia/include/core/SkColor.h +++ b/gfx/skia/skia/include/core/SkColor.h @@ -67,7 +67,7 @@ static inline SkColor SkColorSetARGBInline(U8CPU a, U8CPU r, U8CPU g, U8CPU b) /** return the blue byte from a SkColor value */ #define SkColorGetB(color) (((color) >> 0) & 0xFF) -static inline SkColor SkColorSetA(SkColor c, U8CPU a) { +static constexpr inline SkColor SkColorSetA(SkColor c, U8CPU a) { return (c & 0x00FFFFFF) | (a << 24); } @@ -183,6 +183,7 @@ struct SkColor4f { float* vec() { return &fR; } static SkColor4f Pin(float r, float g, float b, float a); + /** Convert to SkColor4f, assuming SkColor is sRGB */ static SkColor4f FromColor(SkColor); static SkColor4f FromColor3f(SkColor3f, float a); diff --git a/gfx/skia/skia/include/core/SkColorFilter.h b/gfx/skia/skia/include/core/SkColorFilter.h index 5a23a343a28c..a59308774f82 100644 --- a/gfx/skia/skia/include/core/SkColorFilter.h +++ b/gfx/skia/skia/include/core/SkColorFilter.h @@ -8,14 +8,16 @@ #ifndef SkColorFilter_DEFINED #define SkColorFilter_DEFINED +#include "SkBlendMode.h" #include "SkColor.h" #include "SkFlattenable.h" #include "SkRefCnt.h" -#include "SkXfermode.h" class GrContext; class GrFragmentProcessor; +class SkArenaAlloc; class SkBitmap; +class SkColorSpace; class SkRasterPipeline; /** @@ -33,7 +35,7 @@ public: * returns true, and sets (if not NULL) the color and mode appropriately. * If not, this returns false and ignores the parameters. */ - virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode) const; + virtual bool asColorMode(SkColor* color, SkBlendMode* bmode) const; /** * If the filter can be represented by a 5x4 matrix, this @@ -71,7 +73,8 @@ public: virtual void filterSpan4f(const SkPM4f src[], int count, SkPM4f result[]) const; - bool appendStages(SkRasterPipeline*) const; + bool appendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + bool shaderIsOpaque) const; enum Flags { /** If set the filter methods will not change the alpha channel of the colors. @@ -109,15 +112,12 @@ public: If the Mode is DST, this function will return NULL (since that mode will have no effect on the result). @param c The source color used with the specified mode - @param mode The xfermode mode that is applied to each color in + @param mode The blend that is applied to each color in the colorfilter's filterSpan[16,32] methods @return colorfilter object that applies the src color and mode, or NULL if the mode will have no effect. */ - static sk_sp MakeModeFilter(SkColor c, SkXfermode::Mode mode); - static sk_sp MakeModeFilter(SkColor c, SkBlendMode mode) { - return MakeModeFilter(c, (SkXfermode::Mode)mode); - } + static sk_sp MakeModeFilter(SkColor c, SkBlendMode mode); /** Construct a colorfilter whose effect is to first apply the inner filter and then apply * the outer filter to the result of the inner's. @@ -134,21 +134,6 @@ public: */ static sk_sp MakeMatrixFilterRowMajor255(const SkScalar array[20]); -#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR - static SkColorFilter* CreateModeFilter(SkColor c, SkXfermode::Mode mode) { - return MakeModeFilter(c, mode).release(); - } - static SkColorFilter* CreateComposeFilter(SkColorFilter* outer, SkColorFilter* inner) { - return MakeComposeFilter(sk_ref_sp(outer), sk_ref_sp(inner)).release(); - } - static SkColorFilter* CreateMatrixFilterRowMajor255(const SkScalar array[20]) { - return MakeMatrixFilterRowMajor255(array).release(); - } - virtual SkColorFilter* newComposed(const SkColorFilter* inner) const { - return this->makeComposed(sk_ref_sp(const_cast(inner))).release(); - } -#endif - #if SK_SUPPORT_GPU /** * A subclass may implement this factory function to work with the GPU backend. It returns @@ -159,7 +144,8 @@ public: * * A null return indicates that the color filter isn't implemented for the GPU backend. */ - virtual sk_sp asFragmentProcessor(GrContext*) const; + virtual sk_sp asFragmentProcessor(GrContext*, + SkColorSpace* dstColorSpace) const; #endif bool affectsTransparentBlack() const { @@ -174,7 +160,8 @@ public: protected: SkColorFilter() {} - virtual bool onAppendStages(SkRasterPipeline*) const; + virtual bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + bool shaderIsOpaque) const; private: /* diff --git a/gfx/skia/skia/include/core/SkColorPriv.h b/gfx/skia/skia/include/core/SkColorPriv.h index 694d32472f79..12c227765632 100644 --- a/gfx/skia/skia/include/core/SkColorPriv.h +++ b/gfx/skia/skia/include/core/SkColorPriv.h @@ -204,12 +204,8 @@ static inline unsigned Sk255To256(U8CPU value) { * for [0,255] value and [0,256] alpha256. */ static inline U16CPU SkAlphaMulInv256(U16CPU value, U16CPU alpha256) { -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - return SkAlpha255To256(255 - SkAlphaMul(value, alpha256)); -#else unsigned prod = 0xFFFF - value * alpha256; return (prod + (prod >> 8)) >> 8; -#endif } // The caller may want negative values, so keep all params signed (int) @@ -584,22 +580,13 @@ static inline SkPMColor SkPMSrcOver(SkPMColor src, SkPMColor dst) { * Interpolates between colors src and dst using [0,256] scale. */ static inline SkPMColor SkPMLerp(SkPMColor src, SkPMColor dst, unsigned scale) { -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - return SkAlphaMulQ(src, scale) + SkAlphaMulQ(dst, 256 - scale); -#else return SkFastFourByteInterp256(src, dst, scale); -#endif } static inline SkPMColor SkBlendARGB32(SkPMColor src, SkPMColor dst, U8CPU aa) { SkASSERT((unsigned)aa <= 255); unsigned src_scale = SkAlpha255To256(aa); -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - unsigned dst_scale = SkAlpha255To256(255 - SkAlphaMul(SkGetPackedA32(src), src_scale)); - - return SkAlphaMulQ(src, src_scale) + SkAlphaMulQ(dst, dst_scale); -#else unsigned dst_scale = SkAlphaMulInv256(SkGetPackedA32(src), src_scale); const uint32_t mask = 0xFF00FF; @@ -611,7 +598,6 @@ static inline SkPMColor SkBlendARGB32(SkPMColor src, SkPMColor dst, U8CPU aa) { uint32_t dst_ag = ((dst >> 8) & mask) * dst_scale; return (((src_rb + dst_rb) >> 8) & mask) | ((src_ag + dst_ag) & ~mask); -#endif } //////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/include/core/SkColorSpace.h b/gfx/skia/skia/include/core/SkColorSpace.h index a96f6220951a..6a4919b73304 100644 --- a/gfx/skia/skia/include/core/SkColorSpace.h +++ b/gfx/skia/skia/include/core/SkColorSpace.h @@ -13,31 +13,62 @@ class SkData; +/** + * Describes a color gamut with primaries and a white point. + */ +struct SK_API SkColorSpacePrimaries { + float fRX, fRY; + float fGX, fGY; + float fBX, fBY; + float fWX, fWY; + + /** + * Convert primaries and a white point to a toXYZD50 matrix, the preferred color gamut + * representation of SkColorSpace. + */ + bool toXYZD50(SkMatrix44* toXYZD50) const; +}; + +/** + * Contains the coefficients for a common transfer function equation, specified as + * a transformation from a curved space to linear. + * + * LinearVal = C*InputVal + F , for 0.0f <= InputVal < D + * LinearVal = (A*InputVal + B)^G + E, for D <= InputVal <= 1.0f + * + * Function is undefined if InputVal is not in [ 0.0f, 1.0f ]. + * Resulting LinearVals must be in [ 0.0f, 1.0f ]. + * Function must be positive and increasing. + */ +struct SK_API SkColorSpaceTransferFn { + float fG; + float fA; + float fB; + float fC; + float fD; + float fE; + float fF; + + /** + * Produces a new parametric transfer function equation that is the mathematical inverse of + * this one. + */ + SkColorSpaceTransferFn invert() const; +}; + class SK_API SkColorSpace : public SkRefCnt { public: /** - * Common, named profiles that we can recognize. + * Create the sRGB color space. */ - enum Named : uint8_t { - /** - * By far the most common color space. - * This is the default space for images, unmarked content, and monitors. - */ - kSRGB_Named, + static sk_sp MakeSRGB(); - /** - * Very common wide gamut color space. - * Often used by images and monitors. - */ - kAdobeRGB_Named, - - /** - * Colorspace with the sRGB primaries, but a linear (1.0) gamma. Commonly used for - * half-float surfaces, and high precision individual colors (gradient stops, etc...) - */ - kSRGBLinear_Named, - }; + /** + * Colorspace with the sRGB primaries, but a linear (1.0) gamma. Commonly used for + * half-float surfaces, and high precision individual colors (gradient stops, etc...) + */ + static sk_sp MakeSRGBLinear(); enum RenderTargetGamma : uint8_t { kLinear_RenderTargetGamma, @@ -49,28 +80,34 @@ public: kSRGB_RenderTargetGamma, }; - /** - * Create an SkColorSpace from a transfer function and a color gamut transform to D50 XYZ. - */ - static sk_sp NewRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50); + enum Gamut { + kSRGB_Gamut, + kAdobeRGB_Gamut, + kDCIP3_D65_Gamut, + kRec2020_Gamut, + }; /** - * Create a common, named SkColorSpace. + * Create an SkColorSpace from a transfer function and a color gamut. + * + * Transfer function can be specified as an enum or as the coefficients to an equation. + * Gamut can be specified as an enum or as the matrix transformation to XYZ D50. */ - static sk_sp NewNamed(Named); + static sk_sp MakeRGB(RenderTargetGamma gamma, Gamut gamut); + static sk_sp MakeRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50); + static sk_sp MakeRGB(const SkColorSpaceTransferFn& coeffs, Gamut gamut); + static sk_sp MakeRGB(const SkColorSpaceTransferFn& coeffs, + const SkMatrix44& toXYZD50); /** * Create an SkColorSpace from an ICC profile. */ - static sk_sp NewICC(const void*, size_t); - - /** - * Create an SkColorSpace with the same gamut as this color space, but with linear gamma. - */ - sk_sp makeLinearGamma(); + static sk_sp MakeICC(const void*, size_t); /** * Returns true if the color space gamma is near enough to be approximated as sRGB. + * This includes the canonical sRGB transfer function as well as a 2.2f exponential + * transfer function. */ bool gammaCloseToSRGB() const; @@ -79,6 +116,34 @@ public: */ bool gammaIsLinear() const; + /** + * If the transfer function can be represented as coefficients to the standard + * equation, returns true and sets |fn| to the proper values. + * + * If not, returns false. + */ + bool isNumericalTransferFn(SkColorSpaceTransferFn* fn) const; + + /** + * Returns true and sets |toXYZD50| if the color gamut can be described as a matrix. + * Returns false otherwise. + */ + bool toXYZD50(SkMatrix44* toXYZD50) const; + + /** + * Returns true if the color space is sRGB. + * Returns false otherwise. + * + * This allows a little bit of tolerance, given that we might see small numerical error + * in some cases: converting ICC fixed point to float, converting white point to D50, + * rounding decisions on transfer function and matrix. + * + * This does not consider a 2.2f exponential transfer function to be sRGB. While these + * functions are similar (and it is sometimes useful to consider them together), this + * function checks for logical equality. + */ + bool isSRGB() const; + /** * Returns nullptr on failure. Fails when we fallback to serializing ICC data and * the data is too large to serialize. @@ -103,4 +168,17 @@ protected: SkColorSpace() {} }; +enum class SkTransferFunctionBehavior { + /** + * Converts to a linear space before premultiplying, unpremultiplying, or blending. + */ + kRespect, + + /** + * Premultiplies, unpremultiplies, and blends ignoring the transfer function. Pixels are + * treated as if they are linear, regardless of their transfer function encoding. + */ + kIgnore, +}; + #endif diff --git a/gfx/skia/skia/include/core/SkColorSpaceXform.h b/gfx/skia/skia/include/core/SkColorSpaceXform.h new file mode 100644 index 000000000000..ccd36bc128d2 --- /dev/null +++ b/gfx/skia/skia/include/core/SkColorSpaceXform.h @@ -0,0 +1,67 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpaceXform_DEFINED +#define SkColorSpaceXform_DEFINED + +#include "SkImageInfo.h" + +class SkColorSpace; + +class SK_API SkColorSpaceXform : SkNoncopyable { +public: + + /** + * Create an object to handle color space conversions. + * + * @param srcSpace The encoded color space. + * @param dstSpace The destination color space. + * + */ + static std::unique_ptr New(SkColorSpace* srcSpace, SkColorSpace* dstSpace); + + enum ColorFormat { + kRGBA_8888_ColorFormat, + kBGRA_8888_ColorFormat, + + // Unsigned, big-endian, 16-bit integer + kRGB_U16_BE_ColorFormat, // Src only + kRGBA_U16_BE_ColorFormat, // Src only + + kRGBA_F16_ColorFormat, + kRGBA_F32_ColorFormat, + + kBGR_565_ColorFormat, // Dst only, kOpaque only + }; + + /** + * Apply the color conversion to a |src| buffer, storing the output in the |dst| buffer. + * + * F16 and F32 are only supported when the color space is linear. This function will return + * false in unsupported cases. + * + * @param dst Stored in the format described by |dstColorFormat| + * @param src Stored in the format described by |srcColorFormat| + * @param len Number of pixels in the buffers + * @param dstColorFormat Describes color format of |dst| + * @param srcColorFormat Describes color format of |src| + * @param alphaType Describes alpha properties of the |dst| (and |src|) + * kUnpremul preserves input alpha values + * kPremul performs a premultiplication and also preserves alpha values + * kOpaque optimization hint, |dst| alphas set to 1 + * + */ + bool apply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat, const void* src, int count, + SkAlphaType alphaType) const; + + virtual ~SkColorSpaceXform() {} + +protected: + SkColorSpaceXform() {} +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkColorSpaceXformCanvas.h b/gfx/skia/skia/include/core/SkColorSpaceXformCanvas.h new file mode 100644 index 000000000000..6bca6c705e48 --- /dev/null +++ b/gfx/skia/skia/include/core/SkColorSpaceXformCanvas.h @@ -0,0 +1,20 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpaceXformCanvas_DEFINED +#define SkColorSpaceXformCanvas_DEFINED + +#include +#include +#include + +// Proxy SkCanvas calls to unowned target, transforming colors into targetCS as it goes. +// May return nullptr if |targetCS| is unsupported. +std::unique_ptr SK_API SkCreateColorSpaceXformCanvas(SkCanvas* target, + sk_sp targetCS); + +#endif //SkColorSpaceXformCanvas_DEFINED diff --git a/gfx/skia/skia/include/core/SkColorTable.h b/gfx/skia/skia/include/core/SkColorTable.h index 07dfd675b2c3..40919d3bace5 100644 --- a/gfx/skia/skia/include/core/SkColorTable.h +++ b/gfx/skia/skia/include/core/SkColorTable.h @@ -24,10 +24,12 @@ */ class SK_API SkColorTable : public SkRefCnt { public: + static sk_sp Make(const SkPMColor colors[], int count); + /** Copy up to 256 colors into a new SkColorTable. */ SkColorTable(const SkPMColor colors[], int count); - virtual ~SkColorTable(); + ~SkColorTable() override; /** Returns the number of colors in the table. */ @@ -52,7 +54,7 @@ public: void writeToBuffer(SkWriteBuffer&) const; // may return null - static SkColorTable* Create(SkReadBuffer&); + static sk_sp Create(SkReadBuffer&); private: enum AllocatedWithMalloc { diff --git a/gfx/skia/skia/include/core/SkCrossContextImageData.h b/gfx/skia/skia/include/core/SkCrossContextImageData.h new file mode 100644 index 000000000000..bbee6e742b92 --- /dev/null +++ b/gfx/skia/skia/include/core/SkCrossContextImageData.h @@ -0,0 +1,68 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkCrossContextImageData_DEFINED +#define SkCrossContextImageData_DEFINED + +#include "SkImage.h" + +#if SK_SUPPORT_GPU +#include "GrExternalTextureData.h" +#endif + +class SK_API SkCrossContextImageData : SkNoncopyable { +public: + /** + * Decodes and uploads the encoded data to a texture using the supplied GrContext, then + * returns an instance of SkCrossContextImageData that can be used to transport that texture + * to a different GrContext, across thread boundaries. The GrContext used here, and the one + * used to reconstruct the texture-backed image later must be in the same GL share group, + * or otherwise be able to share resources. After calling this, you *must* construct exactly + * one SkImage from the returned value, using SkImage::MakeFromCrossContextImageData. + * + * The texture will be decoded and uploaded to be suitable for use with surfaces that have the + * supplied destination color space. The color space of the texture itself will be determined + * from the encoded data. + */ + static std::unique_ptr MakeFromEncoded( + GrContext*, sk_sp, SkColorSpace* dstColorSpace); + +private: + SkCrossContextImageData(sk_sp image) : fImage(std::move(image)) { + SkASSERT(!fImage->isTextureBacked()); + } + +#if SK_SUPPORT_GPU + SkCrossContextImageData(const GrBackendTextureDesc& desc, + std::unique_ptr textureData, + SkAlphaType alphaType, sk_sp colorSpace) + : fAlphaType(alphaType) + , fColorSpace(std::move(colorSpace)) + , fDesc(desc) + , fTextureData(std::move(textureData)) { + // Point our texture desc at our copy of the backend information + fDesc.fTextureHandle = fTextureData->getBackendObject(); + } +#endif + + // For non-GPU backed images + sk_sp fImage; + +#if SK_SUPPORT_GPU + // GPU-backed images store some generic information (needed to reconstruct the SkImage), + // and some backend-specific info (to reconstruct the texture). + SkAlphaType fAlphaType; + sk_sp fColorSpace; + GrBackendTextureDesc fDesc; + std::unique_ptr fTextureData; +#endif + + friend class SkImage; +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkData.h b/gfx/skia/skia/include/core/SkData.h index 76c9c9ebec2b..0622c9f0fab2 100644 --- a/gfx/skia/skia/include/core/SkData.h +++ b/gfx/skia/skia/include/core/SkData.h @@ -168,14 +168,8 @@ private: explicit SkData(size_t size); // inplace new/delete ~SkData(); - - // Objects of this type are sometimes created in a custom fashion using sk_malloc_throw and - // therefore must be sk_freed. We overload new to also call sk_malloc_throw so that memory - // can be unconditionally released using sk_free in an overloaded delete. Overloading regular - // new means we must also overload placement new. - void* operator new(size_t size) { return sk_malloc_throw(size); } - void* operator new(size_t, void* p) { return p; } - void operator delete(void* p) { sk_free(p); } + // Ensure the unsized delete is called. + void operator delete(void* p) { ::operator delete(p); } // Called the first time someone calls NewEmpty to initialize the singleton. friend SkData* sk_new_empty_data(); diff --git a/gfx/skia/skia/include/core/SkDataTable.h b/gfx/skia/skia/include/core/SkDataTable.h index 2ec2d0f2e232..f8aba9a55919 100644 --- a/gfx/skia/skia/include/core/SkDataTable.h +++ b/gfx/skia/skia/include/core/SkDataTable.h @@ -9,7 +9,6 @@ #define SkDataTable_DEFINED #include "../private/SkTDArray.h" -#include "SkChunkAlloc.h" #include "SkData.h" #include "SkString.h" @@ -117,58 +116,4 @@ private: typedef SkRefCnt INHERITED; }; -/** - * Helper class that allows for incrementally building up the data needed to - * create a SkDataTable. - */ -class SK_API SkDataTableBuilder : SkNoncopyable { -public: - SkDataTableBuilder(size_t minChunkSize); - ~SkDataTableBuilder(); - - int count() const { return fDir.count(); } - size_t minChunkSize() const { return fMinChunkSize; } - - /** - * Forget any previously appended entries, setting count() back to 0. - */ - void reset(size_t minChunkSize); - void reset() { - this->reset(fMinChunkSize); - } - - /** - * Copy size-bytes from data, and append it to the growing SkDataTable. - */ - void append(const void* data, size_t size); - - /** - * Helper version of append() passes strlen() + 1 for the size, - * so the trailing-zero will be copied as well. - */ - void appendStr(const char str[]) { - this->append(str, strlen(str) + 1); - } - - /** - * Helper version of append() passes string.size() + 1 for the size, - * so the trailing-zero will be copied as well. - */ - void appendString(const SkString& string) { - this->append(string.c_str(), string.size() + 1); - } - - /** - * Return an SkDataTable from the accumulated entries that were added by - * calls to append(). This call also clears any accumluated entries from - * this builder, so its count() will be 0 after this call. - */ - sk_sp detachDataTable(); - -private: - SkTDArray fDir; - SkChunkAlloc* fHeap; - size_t fMinChunkSize; -}; - #endif diff --git a/gfx/skia/skia/include/core/SkDocument.h b/gfx/skia/skia/include/core/SkDocument.h index 418a8374370c..6594511df807 100644 --- a/gfx/skia/skia/include/core/SkDocument.h +++ b/gfx/skia/skia/include/core/SkDocument.h @@ -19,6 +19,10 @@ class SkCanvas; class SkWStream; +#ifdef SK_BUILD_FOR_WIN +struct IXpsOMObjectFactory; +#endif + /** SK_ScalarDefaultDPI is 72 DPI. */ #define SK_ScalarDefaultRasterDPI 72.0f @@ -46,7 +50,7 @@ public: */ struct PDFMetadata { /** - * The document’s title. + * The document's title. */ SkString fTitle; /** @@ -141,19 +145,34 @@ public: static sk_sp MakePDF(const char outputFilePath[], SkScalar dpi = SK_ScalarDefaultRasterDPI); +#ifdef SK_BUILD_FOR_WIN /** * Create a XPS-backed document, writing the results into the stream. - * Returns NULL if XPS is not supported. + * + * @param stream A XPS document will be written to this stream. The + * document may write to the stream at anytime during its + * lifetime, until either close() or abort() are called or + * the document is deleted. + * @param xpsFactory A pointer to a COM XPS factory. Must be non-null. + * The document will take a ref to the factory. See + * dm/DMSrcSink.cpp for an example. + * @param dpi The DPI (pixels-per-inch) at which features without + * native XPS support will be rasterized (e.g. draw image + * with perspective, draw text with perspective, ...) A + * larger DPI would create a XPS that reflects the + * original intent with better fidelity, but it can make + * for larger XPS files too, which would use more memory + * while rendering, and it would be slower to be processed + * or sent online or to printer. + * + * @returns nullptr if XPS is not supported. */ static sk_sp MakeXPS(SkWStream* stream, + IXpsOMObjectFactory* xpsFactory, SkScalar dpi = SK_ScalarDefaultRasterDPI); - - /** - * Create a XPS-backed document, writing the results into a file. - * Returns NULL if XPS is not supported. - */ - static sk_sp MakeXPS(const char path[], - SkScalar dpi = SK_ScalarDefaultRasterDPI); +#endif + // DEPRECATED; TODO(halcanary): remove this function after Chromium switches to new API. + static sk_sp MakeXPS(SkWStream*) { return nullptr; } /** * Begin a new page for the document, returning the canvas that will draw diff --git a/gfx/skia/skia/include/core/SkDrawLooper.h b/gfx/skia/skia/include/core/SkDrawLooper.h index 28d7d8beef27..6d9a871ca325 100644 --- a/gfx/skia/skia/include/core/SkDrawLooper.h +++ b/gfx/skia/skia/include/core/SkDrawLooper.h @@ -15,10 +15,12 @@ #include "SkPoint.h" #include "SkColor.h" -class SkCanvas; -class SkPaint; +class SkArenaAlloc; +class SkCanvas; +class SkColorSpaceXformer; +class SkPaint; struct SkRect; -class SkString; +class SkString; /** \class SkDrawLooper Subclasses of SkDrawLooper can be attached to a SkPaint. Where they are, @@ -61,19 +63,8 @@ public: /** * Called right before something is being drawn. Returns a Context * whose next() method should be called until it returns false. - * The caller has to ensure that the storage pointer provides enough - * memory for the Context. The required size can be queried by calling - * contextSize(). It is also the caller's responsibility to destroy the - * object after use. */ - virtual Context* createContext(SkCanvas*, void* storage) const = 0; - - /** - * Returns the number of bytes needed to store subclasses of Context (belonging to the - * corresponding SkDrawLooper subclass). - */ - virtual size_t contextSize() const = 0; - + virtual Context* makeContext(SkCanvas*, SkArenaAlloc*) const = 0; /** * The fast bounds functions are used to enable the paint to be culled early @@ -110,9 +101,16 @@ public: SK_DEFINE_FLATTENABLE_TYPE(SkDrawLooper) protected: + sk_sp makeColorSpace(SkColorSpaceXformer* xformer) const { + return this->onMakeColorSpace(xformer); + } + virtual sk_sp onMakeColorSpace(SkColorSpaceXformer*) const = 0; + SkDrawLooper() {} private: + friend class SkColorSpaceXformer; + typedef SkFlattenable INHERITED; }; diff --git a/gfx/skia/skia/include/core/SkDrawable.h b/gfx/skia/skia/include/core/SkDrawable.h index 6fec3fcf9398..c5053a847d95 100644 --- a/gfx/skia/skia/include/core/SkDrawable.h +++ b/gfx/skia/skia/include/core/SkDrawable.h @@ -9,6 +9,7 @@ #define SkDrawable_DEFINED #include "SkFlattenable.h" +#include "SkScalar.h" class SkCanvas; class SkMatrix; diff --git a/gfx/skia/skia/include/core/SkEncodedImageFormat.h b/gfx/skia/skia/include/core/SkEncodedImageFormat.h new file mode 100644 index 000000000000..8f7923668909 --- /dev/null +++ b/gfx/skia/skia/include/core/SkEncodedImageFormat.h @@ -0,0 +1,33 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEncodedImageFormat_DEFINED +#define SkEncodedImageFormat_DEFINED + +#include + +/** + * Enum describing format of encoded data. + */ +enum class SkEncodedImageFormat { +#ifdef GOOGLE3 + kUnknown, +#endif + kBMP, + kGIF, + kICO, + kJPEG, + kPNG, + kWBMP, + kWEBP, + kPKM, + kKTX, + kASTC, + kDNG, +}; + +#endif // SkEncodedImageFormat_DEFINED diff --git a/gfx/skia/skia/include/core/SkError.h b/gfx/skia/skia/include/core/SkError.h deleted file mode 100644 index 678c910253cd..000000000000 --- a/gfx/skia/skia/include/core/SkError.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkError_DEFINED -#define SkError_DEFINED - - -/** \file SkError.h -*/ - -enum SkError { - /** All is well - */ - kNoError_SkError=0, - - /** User argument passed to Skia function was invalid: NULL when that’s - * not allowed, out of numeric range, bad enum, or violating some - * other general precondition. - */ - kInvalidArgument_SkError, - - /** User tried to perform some operation in a state when the operation - * was not legal, or the operands make no sense (e.g., asking for - * pixels from an SkPictureCanvas). Other examples might be - * inset()’ing a rectangle to make it degenerate (negative width/height). - */ - kInvalidOperation_SkError, - - /** Probably not needed right now, but in the future we could have opaque - * handles for SkPictures floating around, and it would be a good idea - * to anticipate this kind of issue. - */ - kInvalidHandle_SkError, - - /** This is probably not possible because paint surely has defaults for - * everything, but perhaps a paint can get into a bad state somehow. - */ - kInvalidPaint_SkError, - - /** Skia was unable to allocate memory to perform some task. - */ - kOutOfMemory_SkError, - - /** Skia failed while trying to consume some external resource. - */ - kParseError_SkError, - - /** Something went wrong internally; could be resource exhaustion but - * will often be a bug. - */ - kInternalError_SkError -}; - -/** Return the current per-thread error code. Error codes are "sticky"; they - * are not not reset by subsequent successful operations. - */ -SkError SkGetLastError(); - -/** Clear the current per-thread error code back to kNoError_SkError. - */ -void SkClearLastError(); - -/** Type for callback functions to be invoked whenever an error is registered. - * Callback functions take the error code being set, as well as a context - * argument that is provided when the callback is registered. - */ -typedef void (*SkErrorCallbackFunction)(SkError, void *); - -/** Set the current per-thread error callback. - * - * @param cb The callback function to be invoked. Passing NULL - * for cb will revert to the default error callback which - * does nothing on release builds, but on debug builds will - * print an informative error message to the screen. - * @param context An arbitrary pointer that will be passed to - * the provided callback function. - */ -void SkSetErrorCallback(SkErrorCallbackFunction cb, void *context); - -/** Get a human-readable description of the last (per-thread) error that - * occurred. The returned error message will include not only a human - * readable version of the error code, but also information about the - * conditions that led to the error itself. - */ -const char *SkGetLastErrorString(); - -#endif /* SkError_DEFINED */ diff --git a/gfx/skia/skia/include/core/SkExecutor.h b/gfx/skia/skia/include/core/SkExecutor.h new file mode 100644 index 000000000000..303f9e3f54bf --- /dev/null +++ b/gfx/skia/skia/include/core/SkExecutor.h @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkExecutor_DEFINED +#define SkExecutor_DEFINED + +#include +#include + +class SkExecutor { +public: + virtual ~SkExecutor(); + + // Create a thread pool SkExecutor with a fixed thread count, by default the number of cores. + static std::unique_ptr MakeThreadPool(int threads = 0); + + // There is always a default SkExecutor available by calling SkExecutor::GetDefault(). + static SkExecutor& GetDefault(); + static void SetDefault(SkExecutor*); // Does not take ownership. Not thread safe. + + // Add work to execute. + virtual void add(std::function) = 0; + + // If it makes sense for this executor, use this thread to execute work for a little while. + virtual void borrow() {} +}; + +#endif//SkExecutor_DEFINED diff --git a/gfx/skia/skia/include/core/SkFlattenableSerialization.h b/gfx/skia/skia/include/core/SkFlattenableSerialization.h index ffb1b5ae9723..c6fd53dbe31c 100644 --- a/gfx/skia/skia/include/core/SkFlattenableSerialization.h +++ b/gfx/skia/skia/include/core/SkFlattenableSerialization.h @@ -11,9 +11,12 @@ #include "SkFlattenable.h" class SkData; +class SkImageFilter; SK_API SkData* SkValidatingSerializeFlattenable(SkFlattenable*); SK_API SkFlattenable* SkValidatingDeserializeFlattenable(const void* data, size_t size, SkFlattenable::Type type); +SK_API sk_sp SkValidatingDeserializeImageFilter(const void* data, size_t size); + #endif diff --git a/gfx/skia/skia/include/core/SkFontArguments.h b/gfx/skia/skia/include/core/SkFontArguments.h new file mode 100644 index 000000000000..473798fb8403 --- /dev/null +++ b/gfx/skia/skia/include/core/SkFontArguments.h @@ -0,0 +1,79 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontAgruments_DEFINED +#define SkFontAgruments_DEFINED + +#include "SkScalar.h" +#include "SkTypes.h" + +/** Represents a set of actual arguments for a font. */ +struct SkFontArguments { + struct VariationPosition { + struct Coordinate { + SkFourByteTag axis; + SkScalar value; + }; + const Coordinate* coordinates; + int coordinateCount; + }; + // deprecated, use VariationCoordinate instead + struct Axis { + SkFourByteTag fTag; + SkScalar fStyleValue; + }; + + SkFontArguments() : fCollectionIndex(0), fVariationDesignPosition{nullptr, 0} {} + + /** Specify the index of the desired font. + * + * Font formats like ttc, dfont, cff, cid, pfr, t42, t1, and fon may actually be indexed + * collections of fonts. + */ + SkFontArguments& setCollectionIndex(int collectionIndex) { + fCollectionIndex = collectionIndex; + return *this; + } + + // deprecated, use setVariationDesignPosition instead. + SkFontArguments& setAxes(const Axis* axes, int axisCount) { + fVariationDesignPosition.coordinates = + reinterpret_cast(axes); + fVariationDesignPosition.coordinateCount = axisCount; + return *this; + } + + /** Specify a position in the variation design space. + * + * Any axis not specified will use the default value. + * Any specified axis not actually present in the font will be ignored. + * + * @param position not copied. The value must remain valid for life of SkFontArguments. + */ + SkFontArguments& setVariationDesignPosition(VariationPosition position) { + fVariationDesignPosition.coordinates = position.coordinates; + fVariationDesignPosition.coordinateCount = position.coordinateCount; + return *this; + } + + int getCollectionIndex() const { + return fCollectionIndex; + } + // deprecated, use getVariationDesignPosition instead. + const Axis* getAxes(int* axisCount) const { + *axisCount = fVariationDesignPosition.coordinateCount; + return reinterpret_cast(fVariationDesignPosition.coordinates); + } + VariationPosition getVariationDesignPosition() const { + return fVariationDesignPosition; + } +private: + int fCollectionIndex; + VariationPosition fVariationDesignPosition; +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkGraphics.h b/gfx/skia/skia/include/core/SkGraphics.h index d5a730d9e0fc..4b62e55efcfc 100644 --- a/gfx/skia/skia/include/core/SkGraphics.h +++ b/gfx/skia/skia/include/core/SkGraphics.h @@ -8,7 +8,7 @@ #ifndef SkGraphics_DEFINED #define SkGraphics_DEFINED -#include "SkTypes.h" +#include "SkRefCnt.h" class SkData; class SkImageGenerator; @@ -157,7 +157,8 @@ public: */ static void SetTLSFontCacheLimit(size_t bytes); - typedef SkImageGenerator* (*ImageGeneratorFromEncodedFactory)(SkData*); + typedef std::unique_ptr + (*ImageGeneratorFromEncodedDataFactory)(sk_sp); /** * To instantiate images from encoded data, first looks at this runtime function-ptr. If it @@ -166,8 +167,8 @@ public: * * Returns the previous factory (which could be NULL). */ - static ImageGeneratorFromEncodedFactory - SetImageGeneratorFromEncodedFactory(ImageGeneratorFromEncodedFactory); + static ImageGeneratorFromEncodedDataFactory + SetImageGeneratorFromEncodedDataFactory(ImageGeneratorFromEncodedDataFactory); }; class SkAutoGraphics { diff --git a/gfx/skia/skia/include/core/SkICC.h b/gfx/skia/skia/include/core/SkICC.h new file mode 100644 index 000000000000..8c5ec566b7fe --- /dev/null +++ b/gfx/skia/skia/include/core/SkICC.h @@ -0,0 +1,109 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkICC_DEFINED +#define SkICC_DEFINED + +#include "SkData.h" +#include "SkRefCnt.h" + +struct SkColorSpaceTransferFn; +class SkColorSpace; +class SkData; +class SkMatrix44; + +class SK_API SkICC : public SkRefCnt { +public: + + /** + * Parse an ICC profile. + * + * Returns nullptr if the data is not a valid ICC profile or if the profile + * input space is not RGB. + */ + static sk_sp Make(const void*, size_t); + + /** + * If the gamut can be represented as transformation into XYZ D50, returns + * true and sets the proper values in |toXYZD50|. + * + * If not, returns false. This indicates that the ICC data is too complex + * to isolate a simple gamut transformation. + */ + bool toXYZD50(SkMatrix44* toXYZD50) const; + + /** + * If the transfer function can be represented as coefficients to the standard + * equation, returns true and sets |fn| to the proper values. + * + * If not, returns false. This indicates one of the following: + * (1) The R, G, and B transfer functions are not the same. + * (2) The transfer function is represented as a table that we have not managed + * to match to a standard curve. + * (3) The ICC data is too complex to isolate a single transfer function. + */ + bool isNumericalTransferFn(SkColorSpaceTransferFn* fn) const; + + /** + * Please do not call this unless isNumericalTransferFn() has been called and it + * fails. SkColorSpaceTransferFn is the preferred representation. + * + * If it is not possible to represent the R, G, and B transfer functions numerically + * and it is still necessary to get the transfer function, this will return the + * transfer functions as three tables (R, G, and B). + * + * If possible, this will return tables of the same length as they were specified in + * the ICC profile. This means that the lengths of the three tables are not + * guaranteed to be the same. If the ICC representation was not a table, the length + * will be chosen arbitrarily. + * + * The lengths of the tables are all guaranteed to be at least 2. Entries in the + * tables are guaranteed to be in [0, 1]. + * + * This API may be deleted in favor of a numerical approximation of the raw data. + * + * This function may fail, indicating that the ICC profile does not have transfer + * functions. + */ + struct Channel { + // Byte offset of the start of the table in |fStorage| + size_t fOffset; + int fCount; + }; + struct Tables { + Channel fRed; + Channel fGreen; + Channel fBlue; + + const float* red() { + return (const float*) (fStorage->bytes() + fRed.fOffset); + } + const float* green() { + return (const float*) (fStorage->bytes() + fGreen.fOffset); + } + const float* blue() { + return (const float*) (fStorage->bytes() + fBlue.fOffset); + } + + sk_sp fStorage; + }; + bool rawTransferFnData(Tables* tables) const; + + /** + * Write an ICC profile with transfer function |fn| and gamut |toXYZD50|. + */ + static sk_sp WriteToICC(const SkColorSpaceTransferFn& fn, const SkMatrix44& toXYZD50); + +private: + SkICC(sk_sp colorSpace); + + sk_sp fColorSpace; + + friend class ICCTest; +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkImage.h b/gfx/skia/skia/include/core/SkImage.h index f55b679c0b13..ace4fe71eb52 100644 --- a/gfx/skia/skia/include/core/SkImage.h +++ b/gfx/skia/skia/include/core/SkImage.h @@ -18,6 +18,7 @@ class SkData; class SkCanvas; class SkColorTable; +class SkCrossContextImageData; class SkImageGenerator; class SkPaint; class SkPicture; @@ -73,7 +74,8 @@ public: * * If a subset is specified, it must be contained within the generator's bounds. */ - static sk_sp MakeFromGenerator(SkImageGenerator*, const SkIRect* subset = nullptr); + static sk_sp MakeFromGenerator(std::unique_ptr, + const SkIRect* subset = nullptr); /** * Construct a new SkImage based on the specified encoded data. Returns NULL on failure, @@ -154,10 +156,18 @@ public: const SkISize nv12Sizes[2], GrSurfaceOrigin, sk_sp = nullptr); - static sk_sp MakeFromPicture(sk_sp, const SkISize& dimensions, - const SkMatrix*, const SkPaint*); + enum class BitDepth { + kU8, + kF16, + }; - static sk_sp MakeTextureFromPixmap(GrContext*, const SkPixmap&, SkBudgeted budgeted); + /** + * Create a new image from the specified picture. + * On creation of the SkImage, snap the SkPicture to a particular BitDepth and SkColorSpace. + */ + static sk_sp MakeFromPicture(sk_sp, const SkISize& dimensions, + const SkMatrix*, const SkPaint*, BitDepth, + sk_sp); /////////////////////////////////////////////////////////////////////////////////////////////// @@ -167,6 +177,21 @@ public: SkIRect bounds() const { return SkIRect::MakeWH(fWidth, fHeight); } uint32_t uniqueID() const { return fUniqueID; } SkAlphaType alphaType() const; + + /** + * Returns the color space of the SkImage. + * + * This is the color space that was supplied on creation of the SkImage or a color + * space that was parsed from encoded data. This color space is not guaranteed to be + * renderable. Can return nullptr if the SkImage was created without a color space. + */ + SkColorSpace* colorSpace() const; + sk_sp refColorSpace() const; + + /** + * Returns true fi the image will be drawn as a mask, with no intrinsic color of its own. + */ + bool isAlphaOnly() const; bool isOpaque() const { return SkAlphaTypeIsOpaque(this->alphaType()); } /** @@ -176,11 +201,6 @@ public: bool readYUV8Planes(const SkISize[3], void* const planes[3], const size_t rowBytes[3], SkYUVColorSpace) const; -#ifdef SK_SUPPORT_LEGACY_CREATESHADER_PTR - SkShader* newShader(SkShader::TileMode, SkShader::TileMode, - const SkMatrix* localMatrix = nullptr) const; -#endif - sk_sp makeShader(SkShader::TileMode, SkShader::TileMode, const SkMatrix* localMatrix = nullptr) const; @@ -193,35 +213,6 @@ public: */ bool peekPixels(SkPixmap* pixmap) const; -#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS - /** - * If the image has direct access to its pixels (i.e. they are in local - * RAM) return the (const) address of those pixels, and if not null, return - * the ImageInfo and rowBytes. The returned address is only valid while - * the image object is in scope. - * - * On failure, returns NULL and the info and rowBytes parameters are - * ignored. - * - * DEPRECATED -- use the SkPixmap variant instead - */ - const void* peekPixels(SkImageInfo* info, size_t* rowBytes) const; -#endif - - /** - * Some images have to perform preliminary work in preparation for drawing. This can be - * decoding, uploading to a GPU, or other tasks. These happen automatically when an image - * is drawn, and often they are cached so that the cost is only paid the first time. - * - * Preroll() can be called before drawing to try to perform this prepatory work ahead of time. - * For images that have no such work, this returns instantly. Others may do some thing to - * prepare their cache and then return. - * - * If the image will drawn to a GPU-backed canvas or surface, pass the associated GrContext. - * If the image will be drawn to any other type of canvas or surface, pass null. - */ - void preroll(GrContext* = nullptr) const; - // DEPRECATED - currently used by Canvas2DLayerBridge in Chromium. GrTexture* getTexture() const; @@ -234,8 +225,11 @@ public: * Retrieves the backend API handle of the texture. If flushPendingGrContextIO then the * GrContext will issue to the backend API any deferred IO operations on the texture before * returning. + * If 'origin' is supplied it will be filled in with the origin of the content drawn + * into the image. */ - GrBackendObject getTextureHandle(bool flushPendingGrContextIO) const; + GrBackendObject getTextureHandle(bool flushPendingGrContextIO, + GrSurfaceOrigin* origin = nullptr) const; /** * Hints to image calls where the system might cache computed intermediates (e.g. the results @@ -290,7 +284,7 @@ public: * Note: this will attempt to encode the image's pixels in the specified format, * even if the image returns a data from refEncoded(). That data will be ignored. */ - SkData* encode(SkImageEncoder::Type, int quality) const; + SkData* encode(SkEncodedImageFormat, int quality) const; /** * Encode the image and return the result as a caller-managed SkData. This will @@ -331,11 +325,20 @@ public: sk_sp makeSubset(const SkIRect& subset) const; /** - * Ensures that an image is backed by a texture (when GrContext is non-null). If no - * transformation is required, the returned image may be the same as this image. If the this - * image is from a different GrContext, this will fail. + * Ensures that an image is backed by a texture (when GrContext is non-null), suitable for use + * with surfaces that have the supplied destination color space. If no transformation is + * required, the returned image may be the same as this image. If this image is from a + * different GrContext, this will fail. */ - sk_sp makeTextureImage(GrContext*) const; + sk_sp makeTextureImage(GrContext*, SkColorSpace* dstColorSpace) const; + + /** + * Constructs a texture backed image from data that was previously uploaded on another thread + * and GrContext. The GrContext used to upload the data must be in the same GL share group as + * the one passed in here, or otherwise be able to share resources with the passed in context. + */ + static sk_sp MakeFromCrossContextImageData(GrContext*, + std::unique_ptr); /** * If the image is texture-backed this will make a raster copy of it (or nullptr if reading back @@ -392,13 +395,16 @@ public: * When buffer is not null this fills in the deferred texture data for this image in the * provided buffer (assuming this is an appropriate candidate image and the buffer is * appropriately aligned). Upon success the size written is returned, otherwise 0. + * + * dstColorSpace is the color space of the surface where this texture will ultimately be used. + * If the method determines that mip-maps are needed, this helps determine the correct strategy + * for building them (gamma-correct or not). */ size_t getDeferredTextureImageData(const GrContextThreadSafeProxy&, const DeferredTextureImageUsageParams[], int paramCnt, void* buffer, - SkSourceGammaTreatment treatment = - SkSourceGammaTreatment::kIgnore) const; + SkColorSpace* dstColorSpace = nullptr) const; /** * Returns a texture-backed image from data produced in SkImage::getDeferredTextureImageData. @@ -431,39 +437,21 @@ public: */ bool isLazyGenerated() const; - -#ifdef SK_SUPPORT_LEGACY_IMAGEFACTORY - static SkImage* NewRasterCopy(const Info&, const void* pixels, size_t rowBytes, - SkColorTable* ctable = nullptr); - static SkImage* NewRasterData(const Info&, SkData* pixels, size_t rowBytes); - static SkImage* NewFromRaster(const Info&, const void* pixels, size_t rowBytes, - RasterReleaseProc, ReleaseContext); - static SkImage* NewFromBitmap(const SkBitmap&); - static SkImage* NewFromGenerator(SkImageGenerator*, const SkIRect* subset = nullptr); - static SkImage* NewFromEncoded(SkData* encoded, const SkIRect* subset = nullptr); - static SkImage* NewFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc) { - return NewFromTexture(ctx, desc, kPremul_SkAlphaType, nullptr, nullptr); - } - - static SkImage* NewFromTexture(GrContext* ctx, const GrBackendTextureDesc& de, SkAlphaType at) { - return NewFromTexture(ctx, de, at, nullptr, nullptr); - } - static SkImage* NewFromTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType, - TextureReleaseProc, ReleaseContext); - static SkImage* NewFromAdoptedTexture(GrContext*, const GrBackendTextureDesc&, - SkAlphaType = kPremul_SkAlphaType); - static SkImage* NewFromYUVTexturesCopy(GrContext*, SkYUVColorSpace, - const GrBackendObject yuvTextureHandles[3], - const SkISize yuvSizes[3], - GrSurfaceOrigin); - static SkImage* NewFromPicture(const SkPicture*, const SkISize& dimensions, - const SkMatrix*, const SkPaint*); - static SkImage* NewTextureFromPixmap(GrContext*, const SkPixmap&, SkBudgeted budgeted); - static SkImage* NewFromDeferredTextureImageData(GrContext*, const void*, SkBudgeted); - - SkImage* newSubset(const SkIRect& subset) const { return this->makeSubset(subset).release(); } - SkImage* newTextureImage(GrContext* ctx) const { return this->makeTextureImage(ctx).release(); } -#endif + /** + * If |target| is supported, returns an SkImage in the |target| color space. + * Otherwise, returns nullptr. + * + * This will leave the image as is if it already in the |target| color space. + * Otherwise, it will convert the pixels from the src color space to the |target| + * color space. If this->colorSpace() is nullptr, the src color space will be + * treated as sRGB. + * + * If |premulBehavior| is kIgnore, any premultiplication or unpremultiplication will + * be performed in the gamma encoded space. If it is kRespect, premultiplication is + * assumed to be linear. + */ + sk_sp makeColorSpace(sk_sp target, + SkTransferFunctionBehavior premulBehavior) const; protected: SkImage(int width, int height, uint32_t uniqueID); @@ -471,7 +459,7 @@ protected: private: static sk_sp MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMipLevel* texels, int mipLevelCount, - SkBudgeted, SkSourceGammaTreatment); + SkBudgeted, SkDestinationSurfaceColorMode); const int fWidth; const int fHeight; diff --git a/gfx/skia/skia/include/core/SkImageEncoder.h b/gfx/skia/skia/include/core/SkImageEncoder.h index 7d15250917cf..e4f746ab9650 100644 --- a/gfx/skia/skia/include/core/SkImageEncoder.h +++ b/gfx/skia/skia/include/core/SkImageEncoder.h @@ -8,112 +8,35 @@ #ifndef SkImageEncoder_DEFINED #define SkImageEncoder_DEFINED -#include "SkImageInfo.h" -#include "SkTRegistry.h" +#include "SkBitmap.h" +#include "SkEncodedImageFormat.h" +#include "SkStream.h" -class SkBitmap; -class SkPixelSerializer; -class SkPixmap; -class SkData; -class SkWStream; +/** + * Encode SkPixmap in the given binary image format. + * + * @param dst results are written to this stream. + * @param src source pixels. + * @param format image format, not all formats are supported. + * @param quality range from 0-100, not all formats respect quality. + * + * @return false iff input is bad or format is unsupported. + * + * Will always return false if Skia is compiled without image + * encoders. + * + * For examples of encoding an image to a file or to a block of memory, + * see tools/sk_tool_utils.h. + */ +SK_API bool SkEncodeImage(SkWStream* dst, const SkPixmap& src, + SkEncodedImageFormat format, int quality); +/** + * The following helper function wraps SkEncodeImage(). + */ +inline bool SkEncodeImage(SkWStream* dst, const SkBitmap& src, SkEncodedImageFormat f, int q) { + SkAutoLockPixels autoLockPixels(src); + SkPixmap pixmap; + return src.peekPixels(&pixmap) && SkEncodeImage(dst, pixmap, f, q); +} -class SkImageEncoder { -public: - // TODO (scroggo): Merge with SkEncodedFormat. - enum Type { - kUnknown_Type, - kBMP_Type, - kGIF_Type, - kICO_Type, - kJPEG_Type, - kPNG_Type, - kWBMP_Type, - kWEBP_Type, - kKTX_Type, - }; - static SkImageEncoder* Create(Type); - - virtual ~SkImageEncoder(); - - /* Quality ranges from 0..100 */ - enum { - kDefaultQuality = 80 - }; - - /** - * Encode bitmap 'bm', returning the results in an SkData, at quality level - * 'quality' (which can be in range 0-100). If the bitmap cannot be - * encoded, return null. On success, the caller is responsible for - * calling unref() on the data when they are finished. - */ - SkData* encodeData(const SkBitmap&, int quality); - - /** - * Encode bitmap 'bm' in the desired format, writing results to - * file 'file', at quality level 'quality' (which can be in range - * 0-100). Returns false on failure. - */ - bool encodeFile(const char file[], const SkBitmap& bm, int quality); - - /** - * Encode bitmap 'bm' in the desired format, writing results to - * stream 'stream', at quality level 'quality' (which can be in - * range 0-100). Returns false on failure. - */ - bool encodeStream(SkWStream* stream, const SkBitmap& bm, int quality); - - static SkData* EncodeData(const SkImageInfo&, const void* pixels, size_t rowBytes, - Type, int quality); - static SkData* EncodeData(const SkBitmap&, Type, int quality); - - static SkData* EncodeData(const SkPixmap&, Type, int quality); - - static bool EncodeFile(const char file[], const SkBitmap&, Type, - int quality); - static bool EncodeStream(SkWStream*, const SkBitmap&, Type, - int quality); - - /** Uses SkImageEncoder to serialize images that are not already - encoded as SkImageEncoder::kPNG_Type images. */ - static SkPixelSerializer* CreatePixelSerializer(); - -protected: - /** - * Encode bitmap 'bm' in the desired format, writing results to - * stream 'stream', at quality level 'quality' (which can be in - * range 0-100). - * - * This must be overridden by each SkImageEncoder implementation. - */ - virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) = 0; -}; - -// This macro declares a global (i.e., non-class owned) creation entry point -// for each encoder (e.g., CreateJPEGImageEncoder) -#define DECLARE_ENCODER_CREATOR(codec) \ - SK_API SkImageEncoder *Create ## codec (); - -// This macro defines the global creation entry point for each encoder. Each -// encoder implementation that registers with the encoder factory must call it. -#define DEFINE_ENCODER_CREATOR(codec) \ - SkImageEncoder* Create##codec() { return new Sk##codec; } - -// All the encoders known by Skia. Note that, depending on the compiler settings, -// not all of these will be available -DECLARE_ENCODER_CREATOR(JPEGImageEncoder); -DECLARE_ENCODER_CREATOR(PNGImageEncoder); -DECLARE_ENCODER_CREATOR(KTXImageEncoder); -DECLARE_ENCODER_CREATOR(WEBPImageEncoder); - -#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) -SkImageEncoder* CreateImageEncoder_CG(SkImageEncoder::Type type); -#endif - -#if defined(SK_BUILD_FOR_WIN) -SkImageEncoder* CreateImageEncoder_WIC(SkImageEncoder::Type type); -#endif - -// Typedef to make registering encoder callback easier -// This has to be defined outside SkImageEncoder. :( -typedef SkTRegistry SkImageEncoder_EncodeReg; -#endif +#endif // SkImageEncoder_DEFINED diff --git a/gfx/skia/skia/include/core/SkImageFilter.h b/gfx/skia/skia/include/core/SkImageFilter.h index 9188a89e274f..ee24d96964f5 100644 --- a/gfx/skia/skia/include/core/SkImageFilter.h +++ b/gfx/skia/skia/include/core/SkImageFilter.h @@ -20,6 +20,7 @@ class GrContext; class GrFragmentProcessor; class SkColorFilter; +class SkColorSpaceXformer; struct SkIPoint; class SkSpecialImage; class SkImageFilterCache; @@ -223,12 +224,6 @@ public: */ sk_sp makeWithLocalMatrix(const SkMatrix&) const; -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - SkImageFilter* newWithLocalMatrix(const SkMatrix& matrix) const { - return this->makeWithLocalMatrix(matrix).release(); - } -#endif - /** * ImageFilters can natively handle scaling and translate components in the CTM. Only some of * them can handle affine (or more complex) matrices. This call returns true iff the filter @@ -243,14 +238,6 @@ public: SkFilterQuality quality, sk_sp input); -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* CreateMatrixFilter(const SkMatrix& matrix, - SkFilterQuality filterQuality, - SkImageFilter* input = nullptr) { - return MakeMatrixFilter(matrix, filterQuality, sk_ref_sp(input)).release(); - } -#endif - SK_TO_STRING_PUREVIRT() SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter) SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() @@ -284,7 +271,7 @@ protected: SkImageFilter(sk_sp* inputs, int inputCount, const CropRect* cropRect); - virtual ~SkImageFilter(); + ~SkImageFilter() override; /** * Constructs a new SkImageFilter read from an SkReadBuffer object. @@ -297,6 +284,10 @@ protected: void flatten(SkWriteBuffer&) const override; + const CropRect* getCropRectIfSet() const { + return this->cropRectIsSet() ? &fCropRect : nullptr; + } + /** * This is the virtual which should be overridden by the derived class * to perform image filtering. @@ -400,8 +391,46 @@ protected: */ Context mapContext(const Context& ctx) const; +#if SK_SUPPORT_GPU + /** + * Returns a version of the passed-in image (possibly the original), that is in a colorspace + * with the same gamut as the one from the OutputProperties. This allows filters that do many + * texture samples to guarantee that any color space conversion has happened before running. + */ + static sk_sp ImageToColorSpace(SkSpecialImage* src, const OutputProperties&); +#endif + + /** + * Returns an image filter transformed into a new color space via the |xformer|. + */ + sk_sp makeColorSpace(SkColorSpaceXformer* xformer) const { + return this->onMakeColorSpace(xformer); + } + virtual sk_sp onMakeColorSpace(SkColorSpaceXformer*) const { + return sk_ref_sp(const_cast(this)); + } + private: + // For makeColorSpace(). + friend class ArithmeticImageFilterImpl; + friend class SkAlphaThresholdFilterImpl; + friend class SkBlurImageFilterImpl; + friend class SkColorFilterImageFilter; + friend class SkColorSpaceXformer; + friend class SkComposeImageFilter; + friend class SkDisplacementMapEffect; + friend class SkDropShadowImageFilter; + friend class SkImageSource; + friend class SkMagnifierImageFilter; + friend class SkMatrixConvolutionImageFilter; + friend class SkMergeImageFilter; + friend class SkMorphologyImageFilter; + friend class SkOffsetImageFilter; + friend class SkTileImageFilter; + friend class SkXfermodeImageFilter_Base; + friend class SkGraphics; + static void PurgeCache(); void init(sk_sp* inputs, int inputCount, const CropRect* cropRect); diff --git a/gfx/skia/skia/include/core/SkImageGenerator.h b/gfx/skia/skia/include/core/SkImageGenerator.h index 3712a924a55f..846c380851db 100644 --- a/gfx/skia/skia/include/core/SkImageGenerator.h +++ b/gfx/skia/skia/include/core/SkImageGenerator.h @@ -10,55 +10,20 @@ #include "SkBitmap.h" #include "SkColor.h" +#include "SkImage.h" #include "SkImageInfo.h" #include "SkYUVSizeInfo.h" class GrContext; -class GrTexture; -class GrTextureParams; +class GrContextThreadSafeProxy; +class GrTextureProxy; +class GrSamplerParams; class SkBitmap; class SkData; -class SkImageGenerator; class SkMatrix; class SkPaint; class SkPicture; -#ifdef SK_SUPPORT_LEGACY_REFENCODEDDATA_NOCTX - #define SK_REFENCODEDDATA_CTXPARAM -#else - #define SK_REFENCODEDDATA_CTXPARAM GrContext* ctx -#endif - -/** - * Takes ownership of SkImageGenerator. If this method fails for - * whatever reason, it will return false and immediatetely delete - * the generator. If it succeeds, it will modify destination - * bitmap. - * - * If generator is NULL, will safely return false. - * - * If this fails or when the SkDiscardablePixelRef that is - * installed into destination is destroyed, it will - * delete the generator. Therefore, generator should be - * allocated with new. - * - * @param destination Upon success, this bitmap will be - * configured and have a pixelref installed. - * - * @return true iff successful. - */ -SK_API bool SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator*, SkBitmap* destination); - -/** - * On success, installs a discardable pixelref into destination, based on encoded data. - * Regardless of success or failure, the caller must still balance their ownership of encoded. - */ -SK_API bool SkDEPRECATED_InstallDiscardablePixelRef(SkData* encoded, SkBitmap* destination); - -/** - * An interface that allows a purgeable PixelRef (such as a - * SkDiscardablePixelRef) to decode and re-decode an image as needed. - */ class SK_API SkImageGenerator : public SkNoncopyable { public: /** @@ -79,11 +44,7 @@ public: * unref() on the data when it is finished. */ SkData* refEncodedData(GrContext* ctx = nullptr) { -#ifdef SK_SUPPORT_LEGACY_REFENCODEDDATA_NOCTX - return this->onRefEncodedData(); -#else return this->onRefEncodedData(ctx); -#endif } /** @@ -151,104 +112,49 @@ public: */ bool getYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]); +#if SK_SUPPORT_GPU /** * If the generator can natively/efficiently return its pixels as a GPU image (backed by a * texture) this will return that image. If not, this will return NULL. * - * Regarding the GrContext parameter: + * This routine also supports retrieving only a subset of the pixels. That subset is specified + * by the following rectangle: * - * The caller may pass NULL for the context. In that case the generator may assume that its - * internal context is current. If it has no internal context, then it should just return - * null. + * subset = SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()) * - * If the caller passes a non-null context, then the generator should only succeed if: - * - it has no intrinsic context, and will use the caller's - * - its internal context is the same - * - it can somehow convert its texture into one that is valid for the provided context. + * If subset is not contained inside the generator's bounds, this returns false. * - * Regarding the GrTextureParams parameter: - * - * If the context (the provided one or the generator's intrinsic one) determines that to - * support the specified usage, it must return a different sized texture it may, - * so the caller must inspect the texture's width/height and compare them to the generator's - * getInfo() width/height. For readback usage use GrTextureParams::ClampNoFilter() - */ - GrTexture* generateTexture(GrContext*, const SkIRect* subset = nullptr); - - struct SupportedSizes { - SkISize fSizes[2]; - }; - - /** - * Some generators can efficiently scale their contents. If this is supported, the generator - * may only support certain scaled dimensions. Call this with the desired scale factor, - * and it will return true if scaling is supported, and in supportedSizes[] it will return - * the nearest supported dimensions. - * - * If no native scaling is supported, or scale is invalid (e.g. scale <= 0 || scale > 1) - * this will return false, and the supportedsizes will be undefined. - */ - bool computeScaledDimensions(SkScalar scale, SupportedSizes*); - - /** - * Scale the generator's pixels to fit into scaledSize. - * This routine also support retrieving only a subset of the pixels. That subset is specified - * by the following rectangle (in the scaled space): - * - * subset = SkIRect::MakeXYWH(subsetOrigin.x(), subsetOrigin.y(), - * subsetPixels.width(), subsetPixels.height()) - * - * If subset is not contained inside the scaledSize, this returns false. - * - * whole = SkIRect::MakeWH(scaledSize.width(), scaledSize.height()) + * whole = SkIRect::MakeWH(getInfo().width(), getInfo().height()) * if (!whole.contains(subset)) { * return false; * } * - * If the requested colortype/alphatype in pixels is not supported, - * or the requested scaledSize is not supported, or the generator encounters an error, - * this returns false. + * Regarding the GrContext parameter: + * + * It must be non-NULL. The generator should only succeed if: + * - its internal context is the same + * - it can somehow convert its texture into one that is valid for the provided context. */ - bool generateScaledPixels(const SkISize& scaledSize, const SkIPoint& subsetOrigin, - const SkPixmap& subsetPixels); - - bool generateScaledPixels(const SkPixmap& scaledPixels) { - return this->generateScaledPixels(SkISize::Make(scaledPixels.width(), - scaledPixels.height()), - SkIPoint::Make(0, 0), scaledPixels); - } + sk_sp generateTexture(GrContext*, const SkImageInfo& info, + const SkIPoint& origin); +#endif /** * If the default image decoder system can interpret the specified (encoded) data, then * this returns a new ImageGenerator for it. Otherwise this returns NULL. Either way * the caller is still responsible for managing their ownership of the data. */ - static SkImageGenerator* NewFromEncoded(SkData*); + static std::unique_ptr MakeFromEncoded(sk_sp); /** Return a new image generator backed by the specified picture. If the size is empty or * the picture is NULL, this returns NULL. * The optional matrix and paint arguments are passed to drawPicture() at rasterization * time. */ - static SkImageGenerator* NewFromPicture(const SkISize&, const SkPicture*, const SkMatrix*, - const SkPaint*); - - bool tryGenerateBitmap(SkBitmap* bm) { - return this->tryGenerateBitmap(bm, nullptr, nullptr); - } - bool tryGenerateBitmap(SkBitmap* bm, const SkImageInfo& info, SkBitmap::Allocator* allocator) { - return this->tryGenerateBitmap(bm, &info, allocator); - } - void generateBitmap(SkBitmap* bm) { - if (!this->tryGenerateBitmap(bm, nullptr, nullptr)) { - sk_throw(); - } - } - void generateBitmap(SkBitmap* bm, const SkImageInfo& info) { - if (!this->tryGenerateBitmap(bm, &info, nullptr)) { - sk_throw(); - } - } + static std::unique_ptr MakeFromPicture(const SkISize&, sk_sp, + const SkMatrix*, const SkPaint*, + SkImage::BitDepth, + sk_sp); protected: enum { @@ -257,7 +163,7 @@ protected: SkImageGenerator(const SkImageInfo& info, uint32_t uniqueId = kNeedNewImageUniqueID); - virtual SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM); + virtual SkData* onRefEncodedData(GrContext* ctx); virtual bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount); @@ -269,27 +175,38 @@ protected: return false; } - virtual GrTexture* onGenerateTexture(GrContext*, const SkIRect*) { - return nullptr; + struct Options { + Options() + : fColorTable(nullptr) + , fColorTableCount(nullptr) + , fBehavior(SkTransferFunctionBehavior::kRespect) + {} + + SkPMColor* fColorTable; + int* fColorTableCount; + SkTransferFunctionBehavior fBehavior; + }; + bool getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options* opts); + virtual bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + const Options& opts) { + return this->onGetPixels(info, pixels, rowBytes, opts.fColorTable, opts.fColorTableCount); } - virtual bool onComputeScaledDimensions(SkScalar, SupportedSizes*) { - return false; - } - virtual bool onGenerateScaledPixels(const SkISize&, const SkIPoint&, const SkPixmap&) { - return false; - } - - bool tryGenerateBitmap(SkBitmap* bm, const SkImageInfo* optionalInfo, SkBitmap::Allocator*); +#if SK_SUPPORT_GPU + virtual sk_sp onGenerateTexture(GrContext*, const SkImageInfo&, + const SkIPoint&); +#endif private: const SkImageInfo fInfo; const uint32_t fUniqueID; + friend class SkImageCacherator; + // This is our default impl, which may be different on different platforms. // It is called from NewFromEncoded() after it has checked for any runtime factory. // The SkData will never be NULL, as that will have been checked by NewFromEncoded. - static SkImageGenerator* NewFromEncodedImpl(SkData*); + static std::unique_ptr MakeFromEncodedImpl(sk_sp); }; #endif // SkImageGenerator_DEFINED diff --git a/gfx/skia/skia/include/core/SkImageInfo.h b/gfx/skia/skia/include/core/SkImageInfo.h index cf50acacae43..4a8c2860fc06 100644 --- a/gfx/skia/skia/include/core/SkImageInfo.h +++ b/gfx/skia/skia/include/core/SkImageInfo.h @@ -169,9 +169,9 @@ enum SkYUVColorSpace { /////////////////////////////////////////////////////////////////////////////// -enum class SkSourceGammaTreatment { - kRespect, - kIgnore, +enum class SkDestinationSurfaceColorMode { + kLegacy, + kGammaAndColorSpaceAware, }; /** @@ -234,6 +234,7 @@ public: SkColorType colorType() const { return fColorType; } SkAlphaType alphaType() const { return fAlphaType; } SkColorSpace* colorSpace() const { return fColorSpace.get(); } + sk_sp refColorSpace() const { return fColorSpace; } bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; } @@ -277,7 +278,11 @@ public: } size_t minRowBytes() const { - return (size_t)this->minRowBytes64(); + uint64_t minRowBytes = this->minRowBytes64(); + if (!sk_64_isS32(minRowBytes)) { + return 0; + } + return sk_64_asS32(minRowBytes); } size_t computeOffset(int x, int y, size_t rowBytes) const { @@ -302,7 +307,7 @@ public: if (0 == fHeight) { return 0; } - return sk_64_mul(fHeight - 1, rowBytes) + fWidth * this->bytesPerPixel(); + return sk_64_mul(fHeight - 1, rowBytes) + sk_64_mul(fWidth, this->bytesPerPixel()); } size_t getSafeSize(size_t rowBytes) const { @@ -344,16 +349,4 @@ private: {} }; -/////////////////////////////////////////////////////////////////////////////// - -static inline bool SkColorAndColorSpaceAreGammaCorrect(SkColorType ct, SkColorSpace* cs) { - // Anything with a color-space attached is gamma-correct, as is F16. - // To get legacy behavior, you need to ask for non-F16, with a nullptr color space. - return (cs != nullptr) || kRGBA_F16_SkColorType == ct; -} - -static inline bool SkImageInfoIsGammaCorrect(const SkImageInfo& info) { - return SkColorAndColorSpaceAreGammaCorrect(info.colorType(), info.colorSpace()); -} - #endif diff --git a/gfx/skia/skia/include/core/SkLights.h b/gfx/skia/skia/include/core/SkLights.h index 954168de4d1e..d91d91935d95 100644 --- a/gfx/skia/skia/include/core/SkLights.h +++ b/gfx/skia/skia/include/core/SkLights.h @@ -10,12 +10,12 @@ #define SkLights_DEFINED #include "../private/SkTArray.h" +#include "SkImage.h" #include "SkPoint3.h" #include "SkRefCnt.h" class SkReadBuffer; class SkWriteBuffer; -class SkImage; class SK_API SkLights : public SkRefCnt { public: diff --git a/gfx/skia/skia/include/core/SkMallocPixelRef.h b/gfx/skia/skia/include/core/SkMallocPixelRef.h index ab337b9241ec..a62da0e46b46 100644 --- a/gfx/skia/skia/include/core/SkMallocPixelRef.h +++ b/gfx/skia/skia/include/core/SkMallocPixelRef.h @@ -22,12 +22,10 @@ public: * lifetime of the pixel storage buffer, as this pixelref will not try * to delete it. * - * The pixelref will ref() the colortable (if not NULL). - * * Returns NULL on failure. */ - static SkMallocPixelRef* NewDirect(const SkImageInfo&, void* addr, - size_t rowBytes, SkColorTable*); + static sk_sp MakeDirect(const SkImageInfo&, void* addr, + size_t rowBytes, sk_sp); /** * Return a new SkMallocPixelRef, automatically allocating storage for the @@ -39,22 +37,18 @@ public: * * Returns NULL on failure. */ - static SkMallocPixelRef* NewAllocate(const SkImageInfo& info, - size_t rowBytes, SkColorTable*); + static sk_sp MakeAllocate(const SkImageInfo&, size_t rowBytes, sk_sp); /** - * Identical to NewAllocate, except all pixel bytes are zeroed. + * Identical to MakeAllocate, except all pixel bytes are zeroed. */ - static SkMallocPixelRef* NewZeroed(const SkImageInfo& info, - size_t rowBytes, SkColorTable*); + static sk_sp MakeZeroed(const SkImageInfo&, size_t rowBytes, sk_sp); /** * Return a new SkMallocPixelRef with the provided pixel storage, * rowBytes, and optional colortable. On destruction, ReleaseProc * will be called. * - * This pixelref will ref() the specified colortable (if not NULL). - * * If ReleaseProc is NULL, the pixels will never be released. This * can be useful if the pixels were stack allocated. However, such an * SkMallocPixelRef must not live beyond its pixels (e.g. by copying @@ -63,10 +57,10 @@ public: * Returns NULL on failure. */ typedef void (*ReleaseProc)(void* addr, void* context); - static SkMallocPixelRef* NewWithProc(const SkImageInfo& info, - size_t rowBytes, SkColorTable*, - void* addr, ReleaseProc proc, - void* context); + static sk_sp MakeWithProc(const SkImageInfo& info, + size_t rowBytes, sk_sp, + void* addr, ReleaseProc proc, + void* context); /** * Return a new SkMallocPixelRef that will use the provided @@ -74,51 +68,56 @@ public: * The SkData will be ref()ed and on destruction of the PielRef, * the SkData will be unref()ed. * - * This pixelref will ref() the specified colortable (if not NULL). - * * Returns NULL on failure. */ + static sk_sp MakeWithData(const SkImageInfo& info, + size_t rowBytes, + sk_sp, + sk_sp data); + +#ifdef SK_SUPPORT_LEGACY_PIXELREFFACTORY + static SkMallocPixelRef* NewDirect(const SkImageInfo& info, void* addr, + size_t rowBytes, SkColorTable* ctable) { + return (SkMallocPixelRef*)MakeDirect(info, addr, rowBytes, sk_ref_sp(ctable)).release(); + } + static SkMallocPixelRef* NewAllocate(const SkImageInfo& info, size_t rb, SkColorTable* ct) { + return (SkMallocPixelRef*)MakeAllocate(info, rb, sk_ref_sp(ct)).release(); + } + static SkMallocPixelRef* NewZeroed(const SkImageInfo& info, size_t rowBytes, SkColorTable* ct) { + return (SkMallocPixelRef*)MakeZeroed(info, rowBytes, sk_ref_sp(ct)).release(); + } + static SkMallocPixelRef* NewWithProc(const SkImageInfo& info, + size_t rowBytes, SkColorTable* ctable, + void* addr, ReleaseProc proc, + void* ctx) { + return (SkMallocPixelRef*)MakeWithProc(info, rowBytes, sk_ref_sp(ctable), addr, proc, ctx).release(); + } static SkMallocPixelRef* NewWithData(const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable, SkData* data); - - void* getAddr() const { return fStorage; } - - class PRFactory : public SkPixelRefFactory { - public: - SkPixelRef* create(const SkImageInfo&, size_t rowBytes, SkColorTable*) override; - }; - - class ZeroedPRFactory : public SkPixelRefFactory { - public: - SkPixelRef* create(const SkImageInfo&, size_t rowBytes, SkColorTable*) override; - }; +#endif protected: - // The ownPixels version of this constructor is deprecated. - SkMallocPixelRef(const SkImageInfo&, void* addr, size_t rb, SkColorTable*, - bool ownPixels); - virtual ~SkMallocPixelRef(); + ~SkMallocPixelRef() override; +#ifdef SK_SUPPORT_LEGACY_NO_ADDR_PIXELREF bool onNewLockPixels(LockRec*) override; void onUnlockPixels() override; +#endif size_t getAllocatedSizeInBytes() const override; private: // Uses alloc to implement NewAllocate or NewZeroed. - static SkMallocPixelRef* NewUsing(void*(*alloc)(size_t), - const SkImageInfo&, - size_t rowBytes, - SkColorTable*); + static sk_sp MakeUsing(void*(*alloc)(size_t), + const SkImageInfo&, + size_t rowBytes, + sk_sp); - void* fStorage; - SkColorTable* fCTable; - size_t fRB; - ReleaseProc fReleaseProc; - void* fReleaseProcContext; + ReleaseProc fReleaseProc; + void* fReleaseProcContext; - SkMallocPixelRef(const SkImageInfo&, void* addr, size_t rb, SkColorTable*, + SkMallocPixelRef(const SkImageInfo&, void* addr, size_t rb, sk_sp, ReleaseProc proc, void* context); typedef SkPixelRef INHERITED; diff --git a/gfx/skia/skia/include/core/SkMaskFilter.h b/gfx/skia/skia/include/core/SkMaskFilter.h index 95a663d56db2..5cd553590427 100644 --- a/gfx/skia/skia/include/core/SkMaskFilter.h +++ b/gfx/skia/skia/include/core/SkMaskFilter.h @@ -18,10 +18,13 @@ class GrClip; class GrContext; -class GrDrawContext; +class GrRenderTargetContext; class GrPaint; +class GrFragmentProcessor; class GrRenderTarget; -class GrTextureProvider; +class GrResourceProvider; +class GrTexture; +class GrTextureProxy; class SkBitmap; class SkBlitter; class SkCachedData; @@ -109,23 +112,23 @@ public: SkRect* maskRect) const; /** - * Try to directly render the mask filter into the target. Returns - * true if drawing was successful. + * Try to directly render the mask filter into the target. Returns true if drawing was + * successful. If false is returned then paint is unmodified. */ - virtual bool directFilterMaskGPU(GrTextureProvider* texProvider, - GrDrawContext* drawContext, - GrPaint* grp, + virtual bool directFilterMaskGPU(GrContext*, + GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, const GrClip&, const SkMatrix& viewMatrix, const SkStrokeRec& strokeRec, const SkPath& path) const; /** * Try to directly render a rounded rect mask filter into the target. Returns - * true if drawing was successful. + * true if drawing was successful. If false is returned then paint is unmodified. */ virtual bool directFilterRRectMaskGPU(GrContext*, - GrDrawContext* drawContext, - GrPaint* grp, + GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, const GrClip&, const SkMatrix& viewMatrix, const SkStrokeRec& strokeRec, @@ -139,10 +142,10 @@ public: * Implementations are free to get the GrContext from the src texture in order to create * additional textures and perform multiple passes. */ - virtual bool filterMaskGPU(GrTexture* src, - const SkMatrix& ctm, - const SkIRect& maskRect, - GrTexture** result) const; + virtual sk_sp filterMaskGPU(GrContext*, + sk_sp srcProxy, + const SkMatrix& ctm, + const SkIRect& maskRect) const; #endif /** diff --git a/gfx/skia/skia/include/core/SkMatrix.h b/gfx/skia/skia/include/core/SkMatrix.h index f565a537ba42..d408fb12b005 100644 --- a/gfx/skia/skia/include/core/SkMatrix.h +++ b/gfx/skia/skia/include/core/SkMatrix.h @@ -21,6 +21,8 @@ class SkString; SkMatrix does not have a constructor, so it must be explicitly initialized using either reset() - to construct an identity matrix, or one of the set functions (e.g. setTranslate, setRotate, etc.). + + SkMatrix is not thread safe unless you've first called SkMatrix::getType(). */ SK_BEGIN_REQUIRE_DENSE class SK_API SkMatrix { @@ -461,8 +463,7 @@ public: /** Like mapPoints but with custom byte stride between the points. */ - void mapPointsWithStride(SkPoint dst[], SkPoint src[], - size_t stride, int count) const { + void mapPointsWithStride(SkPoint dst[], const SkPoint src[], size_t stride, int count) const { SkASSERT(stride >= sizeof(SkPoint)); SkASSERT(0 == stride % sizeof(SkScalar)); for (int i = 0; i < count; ++i) { @@ -815,6 +816,14 @@ private: return ((fTypeMask & 0xF) == 0); } + inline void updateTranslateMask() { + if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) { + fTypeMask |= kTranslate_Mask; + } else { + fTypeMask &= ~kTranslate_Mask; + } + } + bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const; static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); diff --git a/gfx/skia/skia/include/core/SkMatrix44.h b/gfx/skia/skia/include/core/SkMatrix44.h index 9820ee58cd6e..c1b74582cbd8 100644 --- a/gfx/skia/skia/include/core/SkMatrix44.h +++ b/gfx/skia/skia/include/core/SkMatrix44.h @@ -126,6 +126,12 @@ struct SkVector4 { } }; +/** \class SkMatrix44 + + The SkMatrix44 class holds a 4x4 matrix. + + SkMatrix44 is not thread safe unless you've first called SkMatrix44::getType(). +*/ class SK_API SkMatrix44 { public: @@ -491,7 +497,10 @@ private: return 0 == fTypeMask; } + inline const SkMScalar* values() const { return &fMat[0][0]; } + friend class SkColorSpace; + friend class SkColorSpace_XYZ; }; #endif diff --git a/gfx/skia/skia/include/core/SkMilestone.h b/gfx/skia/skia/include/core/SkMilestone.h index 4c7988ecda44..4a4fad67ce7e 100644 --- a/gfx/skia/skia/include/core/SkMilestone.h +++ b/gfx/skia/skia/include/core/SkMilestone.h @@ -5,5 +5,5 @@ * found in the LICENSE file. */ #ifndef SK_MILESTONE -#define SK_MILESTONE 55 +#define SK_MILESTONE 59 #endif diff --git a/gfx/skia/skia/include/core/SkMultiPictureDraw.h b/gfx/skia/skia/include/core/SkMultiPictureDraw.h index cd46a303ae11..9995721ab952 100644 --- a/gfx/skia/skia/include/core/SkMultiPictureDraw.h +++ b/gfx/skia/skia/include/core/SkMultiPictureDraw.h @@ -57,7 +57,7 @@ public: private: struct DrawData { - SkCanvas* fCanvas; // reffed + SkCanvas* fCanvas; const SkPicture* fPicture; // reffed SkMatrix fMatrix; SkPaint* fPaint; // owned diff --git a/gfx/skia/skia/include/core/SkPaint.h b/gfx/skia/skia/include/core/SkPaint.h index ddc90ae19c78..72a8a7440704 100644 --- a/gfx/skia/skia/include/core/SkPaint.h +++ b/gfx/skia/skia/include/core/SkPaint.h @@ -12,9 +12,7 @@ #include "SkColor.h" #include "SkFilterQuality.h" #include "SkMatrix.h" -#include "SkXfermode.h" - -//#define SK_SUPPORT_LEGACY_XFERMODE_OBJECT +#include "SkRefCnt.h" class SkAutoDescriptor; class SkAutoGlyphCache; @@ -39,8 +37,6 @@ class SkSurfaceProps; class SkTextBlob; class SkTypeface; -#define kBicubicFilterBitmap_Flag kHighQualityFilterBitmap_Flag - /** \class SkPaint The SkPaint class holds the style and color information about how to draw @@ -105,8 +101,6 @@ public: enum Flags { kAntiAlias_Flag = 0x01, //!< mask to enable antialiasing kDither_Flag = 0x04, //!< mask to enable dithering - kUnderlineText_Flag = 0x08, //!< mask to enable underline text - kStrikeThruText_Flag = 0x10, //!< mask to enable strike-thru text kFakeBoldText_Flag = 0x20, //!< mask to enable fake-bold text kLinearText_Flag = 0x40, //!< mask to enable linear-text kSubpixelText_Flag = 0x80, //!< mask to enable subpixel text positioning @@ -119,9 +113,18 @@ public: // when adding extra flags, note that the fFlags member is specified // with a bit-width and you'll have to expand it. - kAllFlags = 0xFFFF + kAllFlags = 0xFFFF, }; +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + enum ReserveFlags { + // These are not used by paint, but the bits are reserved for private use by the + // android framework. + kUnderlineText_ReserveFlag = 0x08, //!< mask to enable underline text + kStrikeThruText_ReserveFlag = 0x10, //!< mask to enable strike-thru text + }; +#endif + /** Return the paint's flags. Use the Flag enum to test flag values. @return the paint's flags (see enums ending in _Flag for bit masks) */ @@ -230,32 +233,6 @@ public: */ void setVerticalText(bool); - /** Helper for getFlags(), returning true if kUnderlineText_Flag bit is set - @return true if the underlineText bit is set in the paint's flags. - */ - bool isUnderlineText() const { - return SkToBool(this->getFlags() & kUnderlineText_Flag); - } - - /** Helper for setFlags(), setting or clearing the kUnderlineText_Flag bit - @param underlineText true to set the underlineText bit in the paint's - flags, false to clear it. - */ - void setUnderlineText(bool underlineText); - - /** Helper for getFlags(), returns true if kStrikeThruText_Flag bit is set - @return true if the strikeThruText bit is set in the paint's flags. - */ - bool isStrikeThruText() const { - return SkToBool(this->getFlags() & kStrikeThruText_Flag); - } - - /** Helper for setFlags(), setting or clearing the kStrikeThruText_Flag bit - @param strikeThruText true to set the strikeThruText bit in the - paint's flags, false to clear it. - */ - void setStrikeThruText(bool strikeThruText); - /** Helper for getFlags(), returns true if kFakeBoldText_Flag bit is set @return true if the kFakeBoldText_Flag bit is set in the paint's flags. */ @@ -483,6 +460,7 @@ public: @return the paint's shader (or NULL) */ SkShader* getShader() const { return fShader.get(); } + sk_sp refShader() const; /** Set or clear the shader object. * Shaders specify the source color(s) for what is being drawn. If a paint @@ -503,61 +481,24 @@ public: * If a previous shader exists, its reference count is decremented. * If shader is not NULL, its reference count is incremented. * @param shader May be NULL. The shader to be installed in the paint - * @return shader */ void setShader(sk_sp); -#ifdef SK_SUPPORT_LEGACY_CREATESHADER_PTR - SkShader* setShader(SkShader* shader); -#endif /** Get the paint's colorfilter. If there is a colorfilter, its reference count is not changed. @return the paint's colorfilter (or NULL) */ SkColorFilter* getColorFilter() const { return fColorFilter.get(); } + sk_sp refColorFilter() const; - /** Set or clear the paint's colorfilter, returning the parameter. + /** Set or clear the paint's colorfilter.

If the paint already has a filter, its reference count is decremented. If filter is not NULL, its reference count is incremented. @param filter May be NULL. The filter to be installed in the paint - @return filter */ -#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR - SkColorFilter* setColorFilter(SkColorFilter* filter); -#endif void setColorFilter(sk_sp); -#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT - /** Get the paint's xfermode object. -

- The xfermode's reference count is not affected. - @return the paint's xfermode (or NULL) - */ - SkXfermode* getXfermode() const; - - /** Set or clear the xfermode object. -

- Pass NULL to clear any previous xfermode. - As a convenience, the parameter passed is also returned. - If a previous xfermode exists, its reference count is decremented. - If xfermode is not NULL, its reference count is incremented. - @param xfermode May be NULL. The new xfermode to be installed in the - paint - @return xfermode - */ - void setXfermode(sk_sp); -#ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR - SkXfermode* setXfermode(SkXfermode* xfermode); -#endif - - /** Create an xfermode based on the specified Mode, and assign it into the - paint, returning the mode that was set. If the Mode is SrcOver, then - the paint's xfermode is set to null. - */ - SkXfermode* setXfermodeMode(SkXfermode::Mode); -#endif - SkBlendMode getBlendMode() const { return (SkBlendMode)fBlendMode; } bool isSrcOver() const { return (SkBlendMode)fBlendMode == SkBlendMode::kSrcOver; } void setBlendMode(SkBlendMode mode) { fBlendMode = (unsigned)mode; } @@ -568,6 +509,7 @@ public: @return the paint's patheffect (or NULL) */ SkPathEffect* getPathEffect() const { return fPathEffect.get(); } + sk_sp refPathEffect() const; /** Set or clear the patheffect object.

@@ -580,9 +522,6 @@ public: @return effect */ void setPathEffect(sk_sp); -#ifdef SK_SUPPORT_LEGACY_PATHEFFECT_PTR - SkPathEffect* setPathEffect(SkPathEffect* effect); -#endif /** Get the paint's maskfilter object.

@@ -590,6 +529,7 @@ public: @return the paint's maskfilter (or NULL) */ SkMaskFilter* getMaskFilter() const { return fMaskFilter.get(); } + sk_sp refMaskFilter() const; /** Set or clear the maskfilter object.

@@ -601,9 +541,6 @@ public: the paint @return maskfilter */ -#ifdef SK_SUPPORT_LEGACY_MASKFILTER_PTR - SkMaskFilter* setMaskFilter(SkMaskFilter* maskfilter); -#endif void setMaskFilter(sk_sp); // These attributes are for text/fonts @@ -615,6 +552,7 @@ public: @return the paint's typeface (or NULL) */ SkTypeface* getTypeface() const { return fTypeface.get(); } + sk_sp refTypeface() const; /** Set or clear the typeface object.

@@ -627,9 +565,6 @@ public: @return typeface */ void setTypeface(sk_sp); -#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR - SkTypeface* setTypeface(SkTypeface* typeface); -#endif /** Get the paint's rasterizer (or NULL).

@@ -637,6 +572,7 @@ public: @return the paint's rasterizer (or NULL) */ SkRasterizer* getRasterizer() const { return fRasterizer.get(); } + sk_sp refRasterizer() const; /** Set or clear the rasterizer object.

@@ -649,13 +585,10 @@ public: the paint. @return rasterizer */ -#ifdef SK_SUPPORT_LEGACY_MINOR_EFFECT_PTR - SkRasterizer* setRasterizer(SkRasterizer* rasterizer); -#endif void setRasterizer(sk_sp); SkImageFilter* getImageFilter() const { return fImageFilter.get(); } - SkImageFilter* setImageFilter(SkImageFilter*); + sk_sp refImageFilter() const; void setImageFilter(sk_sp); /** @@ -663,6 +596,8 @@ public: * reference count. */ SkDrawLooper* getDrawLooper() const { return fDrawLooper.get(); } + sk_sp refDrawLooper() const; + SkDrawLooper* getLooper() const { return fDrawLooper.get(); } /** * Set or clear the looper object. @@ -674,9 +609,7 @@ public: * @param looper May be NULL. The new looper to be installed in the paint. */ void setDrawLooper(sk_sp); -#ifdef SK_SUPPORT_LEGACY_MINOR_EFFECT_PTR - SkDrawLooper* setLooper(SkDrawLooper* looper); -#endif + void setLooper(sk_sp); enum Align { @@ -755,7 +688,7 @@ public: A set flag indicates that the metric may be trusted. */ enum FontMetricsFlags { - kUnderlineThinknessIsValid_Flag = 1 << 0, + kUnderlineThicknessIsValid_Flag = 1 << 0, kUnderlinePositionIsValid_Flag = 1 << 1, }; @@ -781,21 +714,21 @@ public: */ SkScalar fUnderlinePosition; //!< underline position, or 0 if cannot be determined - /** If the fontmetrics has a valid underlinethickness, return true, and set the + /** If the fontmetrics has a valid underline thickness, return true, and set the thickness param to that value. If it doesn't return false and ignore the thickness param. */ bool hasUnderlineThickness(SkScalar* thickness) const { - if (SkToBool(fFlags & kUnderlineThinknessIsValid_Flag)) { + if (SkToBool(fFlags & kUnderlineThicknessIsValid_Flag)) { *thickness = fUnderlineThickness; return true; } return false; } - /** If the fontmetrics has a valid underlineposition, return true, and set the - thickness param to that value. If it doesn't return false and ignore the - thickness param. + /** If the fontmetrics has a valid underline position, return true, and set the + position param to that value. If it doesn't return false and ignore the + position param. */ bool hasUnderlinePosition(SkScalar* position) const { if (SkToBool(fFlags & kUnderlinePositionIsValid_Flag)) { @@ -1111,7 +1044,7 @@ private: SkColor fColor; SkScalar fWidth; SkScalar fMiterLimit; - uint32_t fBlendMode; // just need 5-6 bits for SkXfermode::Mode + uint32_t fBlendMode; // just need 5-6 bits union { struct { // all of these bitfields should add up to 32 diff --git a/gfx/skia/skia/include/core/SkPath.h b/gfx/skia/skia/include/core/SkPath.h index d1af4f31b659..d5b02c015689 100644 --- a/gfx/skia/skia/include/core/SkPath.h +++ b/gfx/skia/skia/include/core/SkPath.h @@ -23,6 +23,8 @@ class SkWStream; The SkPath class encapsulates compound (multiple contour) geometric paths consisting of straight line segments, quadratic curves, and cubic curves. + + SkPath is not thread safe unless you've first called SkPath::updateBoundsCache(). */ class SK_API SkPath { public: @@ -357,6 +359,19 @@ public: this->getBounds(); } + /** + * Computes a bounds that is conservatively "snug" around the path. This assumes that the + * path will be filled. It does not attempt to collapse away contours that are logically + * empty (e.g. moveTo(x, y) + lineTo(x, y)) but will include them in the calculation. + * + * It differs from getBounds() in that it will look at the snug bounds of curves, whereas + * getBounds() just returns the bounds of the control-points. Thus computing this may be + * slower than just calling getBounds(). + * + * If the path is empty (i.e. no points or verbs), it will return SkRect::MakeEmpty(). + */ + SkRect computeTightBounds() const; + /** * Does a conservative test to see whether a rectangle is inside a path. Currently it only * will ever return true for single convex contour paths. The empty-status of the rect is not @@ -1121,12 +1136,12 @@ private: kCurrent_Version = 2 }; - SkAutoTUnref fPathRef; + sk_sp fPathRef; int fLastMoveToIndex; uint8_t fFillType; mutable uint8_t fConvexity; mutable SkAtomic fFirstDirection;// SkPathPriv::FirstDirection - mutable SkBool8 fIsVolatile; + SkBool8 fIsVolatile; /** Resets all fields other than fPathRef to their initial 'empty' values. * Assumes the caller has already emptied fPathRef. @@ -1190,6 +1205,8 @@ private: friend class SkAutoPathBoundsUpdate; friend class SkAutoDisableOvalCheck; friend class SkAutoDisableDirectionCheck; + friend class SkPathWriter; + friend class SkOpBuilder; friend class SkBench_AddPathTest; // perf test reversePathTo friend class PathTest_Private; // unit test reversePathTo friend class ForceIsRRect_Private; // unit test isRRect diff --git a/gfx/skia/skia/include/core/SkPathEffect.h b/gfx/skia/skia/include/core/SkPathEffect.h index f5ca9183a3ae..65adb33f3c3f 100644 --- a/gfx/skia/skia/include/core/SkPathEffect.h +++ b/gfx/skia/skia/include/core/SkPathEffect.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,7 +5,6 @@ * found in the LICENSE file. */ - #ifndef SkPathEffect_DEFINED #define SkPathEffect_DEFINED @@ -28,6 +26,23 @@ class SkStrokeRec; */ class SK_API SkPathEffect : public SkFlattenable { public: + /** + * Returns a patheffect that apples each effect (first and second) to the original path, + * and returns a path with the sum of these. + * + * result = first(path) + second(path) + * + */ + static sk_sp MakeSum(sk_sp first, sk_sp second); + + /** + * Returns a patheffect that applies the inner effect to the path, and then applies the + * outer effect to the result of the inner's. + * + * result = outer(inner(path)) + */ + static sk_sp MakeCompose(sk_sp outer, sk_sp inner); + /** * Given a src path (input) and a stroke-rec (input and output), apply * this effect to the src path, returning the new path in dst, and return @@ -138,6 +153,8 @@ public: virtual bool exposedInAndroidJavaAPI() const { return false; } #endif + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() + protected: SkPathEffect() {} @@ -149,125 +166,4 @@ private: typedef SkFlattenable INHERITED; }; -/** \class SkPairPathEffect - - Common baseclass for Compose and Sum. This subclass manages two pathEffects, - including flattening them. It does nothing in filterPath, and is only useful - for managing the lifetimes of its two arguments. -*/ -class SK_API SkPairPathEffect : public SkPathEffect { -protected: - SkPairPathEffect(sk_sp pe0, sk_sp pe1); - - void flatten(SkWriteBuffer&) const override; - - // these are visible to our subclasses - sk_sp fPE0; - sk_sp fPE1; - - SK_TO_STRING_OVERRIDE() - -private: - typedef SkPathEffect INHERITED; -}; - -/** \class SkComposePathEffect - - This subclass of SkPathEffect composes its two arguments, to create - a compound pathEffect. -*/ -class SK_API SkComposePathEffect : public SkPairPathEffect { -public: - /** Construct a pathEffect whose effect is to apply first the inner pathEffect - and the the outer pathEffect (e.g. outer(inner(path))) - The reference counts for outer and inner are both incremented in the constructor, - and decremented in the destructor. - */ - static sk_sp Make(sk_sp outer, sk_sp inner) { - if (!outer) { - return inner; - } - if (!inner) { - return outer; - } - return sk_sp(new SkComposePathEffect(outer, inner)); - } - -#ifdef SK_SUPPORT_LEGACY_PATHEFFECT_PTR - static SkPathEffect* Create(SkPathEffect* outer, SkPathEffect* inner) { - return Make(sk_ref_sp(outer), sk_ref_sp(inner)).release(); - } -#endif - - virtual bool filterPath(SkPath* dst, const SkPath& src, - SkStrokeRec*, const SkRect*) const override; - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposePathEffect) - -#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK - bool exposedInAndroidJavaAPI() const override { return true; } -#endif - -protected: - SkComposePathEffect(sk_sp outer, sk_sp inner) - : INHERITED(outer, inner) {} - -private: - // illegal - SkComposePathEffect(const SkComposePathEffect&); - SkComposePathEffect& operator=(const SkComposePathEffect&); - - typedef SkPairPathEffect INHERITED; -}; - -/** \class SkSumPathEffect - - This subclass of SkPathEffect applies two pathEffects, one after the other. - Its filterPath() returns true if either of the effects succeeded. -*/ -class SK_API SkSumPathEffect : public SkPairPathEffect { -public: - /** Construct a pathEffect whose effect is to apply two effects, in sequence. - (e.g. first(path) + second(path)) - The reference counts for first and second are both incremented in the constructor, - and decremented in the destructor. - */ - static sk_sp Make(sk_sp first, sk_sp second) { - if (!first) { - return second; - } - if (!second) { - return first; - } - return sk_sp(new SkSumPathEffect(first, second)); - } - -#ifdef SK_SUPPORT_LEGACY_PATHEFFECT_PTR - static SkPathEffect* Create(SkPathEffect* first, SkPathEffect* second) { - return Make(sk_ref_sp(first), sk_ref_sp(second)).release(); - } -#endif - virtual bool filterPath(SkPath* dst, const SkPath& src, - SkStrokeRec*, const SkRect*) const override; - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSumPathEffect) - -#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK - bool exposedInAndroidJavaAPI() const override { return true; } -#endif - -protected: - SkSumPathEffect(sk_sp first, sk_sp second) - : INHERITED(first, second) {} - -private: - // illegal - SkSumPathEffect(const SkSumPathEffect&); - SkSumPathEffect& operator=(const SkSumPathEffect&); - - typedef SkPairPathEffect INHERITED; -}; - #endif diff --git a/gfx/skia/skia/include/core/SkPathRef.h b/gfx/skia/skia/include/core/SkPathRef.h index 9b15c3e4f2f4..5e6fda7d85b2 100644 --- a/gfx/skia/skia/include/core/SkPathRef.h +++ b/gfx/skia/skia/include/core/SkPathRef.h @@ -26,8 +26,8 @@ class SkWBuffer; * modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an * SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs * copy-on-write if the SkPathRef is shared by multiple SkPaths. The caller passes the Editor's - * constructor a SkAutoTUnref, which may be updated to point to a new SkPathRef after the editor's - * constructor returns. + * constructor a pointer to a sk_sp, which may be updated to point to a new SkPathRef + * after the editor's constructor returns. * * The points and verbs are stored in a single allocation. The points are at the begining of the * allocation while the verbs are stored at end of the allocation, in reverse order. Thus the points @@ -40,7 +40,7 @@ class SK_API SkPathRef final : public SkNVRefCnt { public: class Editor { public: - Editor(SkAutoTUnref* pathRef, + Editor(sk_sp* pathRef, int incReserveVerbs = 0, int incReservePoints = 0); @@ -230,7 +230,7 @@ public: /** * Transforms a path ref by a matrix, allocating a new one only if necessary. */ - static void CreateTransformedCopy(SkAutoTUnref* dst, + static void CreateTransformedCopy(sk_sp* dst, const SkPathRef& src, const SkMatrix& matrix); @@ -241,7 +241,7 @@ public: * repopulated with approximately the same number of verbs and points. A new path ref is created * only if necessary. */ - static void Rewind(SkAutoTUnref* pathRef); + static void Rewind(sk_sp* pathRef); ~SkPathRef(); int countPoints() const { SkDEBUGCODE(this->validate();) return fPointCnt; } diff --git a/gfx/skia/skia/include/core/SkPicture.h b/gfx/skia/skia/include/core/SkPicture.h index c2d05f9c41ef..133d3c92c029 100644 --- a/gfx/skia/skia/include/core/SkPicture.h +++ b/gfx/skia/skia/include/core/SkPicture.h @@ -52,21 +52,6 @@ public: */ typedef bool (*InstallPixelRefProc)(const void* src, size_t length, SkBitmap* dst); -#ifdef SK_SUPPORT_LEGACY_PICTUREINSTALLPIXELREF - /** - * Recreate a picture that was serialized into a stream. - * @param SkStream Serialized picture data. Ownership is unchanged by this call. - * @param proc Function pointer for installing pixelrefs on SkBitmaps representing the - * encoded bitmap data from the stream. - * @return A new SkPicture representing the serialized data, or NULL if the stream is - * invalid. - */ - static sk_sp MakeFromStream(SkStream*, InstallPixelRefProc proc); - static sk_sp MakeFromStream(SkStream* stream, std::nullptr_t) { - return MakeFromStream(stream); - } -#endif - /** * Recreate a picture that was serialized into a stream. * @@ -182,18 +167,6 @@ public: static void SetPictureIOSecurityPrecautionsEnabled_Dangerous(bool set); static bool PictureIOSecurityPrecautionsEnabled(); -#ifdef SK_SUPPORT_LEGACY_PICTURE_PTR - static SkPicture* CreateFromStream(SkStream* stream, InstallPixelRefProc proc) { - return MakeFromStream(stream, proc).release(); - } - static SkPicture* CreateFromStream(SkStream* stream) { - return MakeFromStream(stream).release(); - } - static SkPicture* CreateFromBuffer(SkReadBuffer& rbuf) { - return MakeFromBuffer(rbuf).release(); - } -#endif - private: // Subclass whitelist. SkPicture(); @@ -225,10 +198,12 @@ private: // V48: Read and write extended SkTextBlobs. // V49: Gradients serialized as SkColor4f + SkColorSpace // V50: SkXfermode -> SkBlendMode + // V51: more SkXfermode -> SkBlendMode + // V52: Remove SkTextBlob::fRunCount // Only SKPs within the min/current picture version range (inclusive) can be read. static const uint32_t MIN_PICTURE_VERSION = 35; // Produced by Chrome M39. - static const uint32_t CURRENT_PICTURE_VERSION = 50; + static const uint32_t CURRENT_PICTURE_VERSION = 52; static_assert(MIN_PICTURE_VERSION <= 41, "Remove kFontFileName and related code from SkFontDescriptor.cpp."); diff --git a/gfx/skia/skia/include/core/SkPictureAnalyzer.h b/gfx/skia/skia/include/core/SkPictureAnalyzer.h index 62dac30f0104..52db8334d43e 100644 --- a/gfx/skia/skia/include/core/SkPictureAnalyzer.h +++ b/gfx/skia/skia/include/core/SkPictureAnalyzer.h @@ -37,7 +37,7 @@ public: /** * Process an explicit clipPath op. */ - void analyzeClipPath(const SkPath&, SkCanvas::ClipOp, bool doAntiAlias); + void analyzeClipPath(const SkPath&, SkClipOp, bool doAntiAlias); /** * Reset all accumulated stats. diff --git a/gfx/skia/skia/include/core/SkPictureRecorder.h b/gfx/skia/skia/include/core/SkPictureRecorder.h index c824189300b1..d898b91cca54 100644 --- a/gfx/skia/skia/include/core/SkPictureRecorder.h +++ b/gfx/skia/skia/include/core/SkPictureRecorder.h @@ -38,7 +38,6 @@ public: }; enum FinishFlags { - kReturnNullForEmpty_FinishFlag = 1 << 0, // no draw-ops will return nullptr }; /** Returns the canvas that records the drawing commands. @@ -78,7 +77,7 @@ public: /** * Signal that the caller is done recording, and update the cull rect to use for bounding * box hierarchy (BBH) generation. The behavior is the same as calling - * endRecordingAsPicture(), except that this method updates the cull rect initially passed + * finishRecordingAsPicture(), except that this method updates the cull rect initially passed * into beginRecording. * @param cullRect the new culling rectangle to use as the overall bound for BBH generation * and subsequent culling operations. @@ -92,26 +91,13 @@ public: * beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who * must call unref() when they are done using it. * - * Unlike endRecordingAsPicture(), which returns an immutable picture, the returned drawable + * Unlike finishRecordingAsPicture(), which returns an immutable picture, the returned drawable * may contain live references to other drawables (if they were added to the recording canvas) * and therefore this drawable will reflect the current state of those nested drawables anytime * it is drawn or a new picture is snapped from it (by calling drawable->newPictureSnapshot()). */ sk_sp finishRecordingAsDrawable(uint32_t endFlags = 0); -#ifdef SK_SUPPORT_LEGACY_PICTURE_PTR - SkPicture* SK_WARN_UNUSED_RESULT endRecordingAsPicture() { - return this->finishRecordingAsPicture().release(); - } - SkPicture* SK_WARN_UNUSED_RESULT endRecordingAsPicture(const SkRect& cullRect) { - return this->finishRecordingAsPictureWithCull(cullRect).release(); - } - SkDrawable* SK_WARN_UNUSED_RESULT endRecordingAsDrawable() { - return this->finishRecordingAsDrawable().release(); - } - SkPicture* SK_WARN_UNUSED_RESULT endRecording() { return this->endRecordingAsPicture(); } -#endif - private: void reset(); @@ -124,13 +110,13 @@ private: friend class SkPictureRecorderReplayTester; // for unit testing void partialReplay(SkCanvas* canvas) const; - bool fActivelyRecording; - uint32_t fFlags; - SkRect fCullRect; - SkAutoTUnref fBBH; - SkAutoTUnref fRecorder; - SkAutoTUnref fRecord; - SkMiniRecorder fMiniRecorder; + bool fActivelyRecording; + uint32_t fFlags; + SkRect fCullRect; + sk_sp fBBH; + std::unique_ptr fRecorder; + sk_sp fRecord; + SkMiniRecorder fMiniRecorder; typedef SkNoncopyable INHERITED; }; diff --git a/gfx/skia/skia/include/core/SkPixelRef.h b/gfx/skia/skia/include/core/SkPixelRef.h index 2677e5f22d72..97aca19c6f15 100644 --- a/gfx/skia/skia/include/core/SkPixelRef.h +++ b/gfx/skia/skia/include/core/SkPixelRef.h @@ -18,10 +18,8 @@ #include "SkRefCnt.h" #include "SkSize.h" #include "SkString.h" -#include "SkYUVSizeInfo.h" class SkColorTable; -class SkData; struct SkIRect; class GrTexture; @@ -37,7 +35,11 @@ class SkDiscardableMemory; */ class SK_API SkPixelRef : public SkRefCnt { public: +#ifdef SK_SUPPORT_LEGACY_NO_ADDR_PIXELREF explicit SkPixelRef(const SkImageInfo&); +#endif + explicit SkPixelRef(const SkImageInfo&, void* addr, size_t rowBytes, + sk_sp = nullptr); virtual ~SkPixelRef(); const SkImageInfo& info() const { @@ -96,14 +98,6 @@ public: */ void unlockPixels(); - /** - * Some bitmaps can return a copy of their pixels for lockPixels(), but - * that copy, if modified, will not be pushed back. These bitmaps should - * not be used as targets for a raster device/canvas (since all pixels - * modifications will be lost when unlockPixels() is called.) - */ - bool lockPixelsAreWritable() const; - /** Returns a non-zero, unique value corresponding to the pixels in this pixelref. Each time the pixels are changed (and notifyPixelsChanged is called), a different generation ID will be returned. @@ -147,39 +141,6 @@ public: */ void setImmutable(); - /** Return the optional URI string associated with this pixelref. May be - null. - */ - const char* getURI() const { return fURI.size() ? fURI.c_str() : NULL; } - - /** Copy a URI string to this pixelref, or clear the URI if the uri is null - */ - void setURI(const char uri[]) { - fURI.set(uri); - } - - /** Copy a URI string to this pixelref - */ - void setURI(const char uri[], size_t len) { - fURI.set(uri, len); - } - - /** Assign a URI string to this pixelref. - */ - void setURI(const SkString& uri) { fURI = uri; } - - /** - * If the pixelRef has an encoded (i.e. compressed) representation, - * return a ref to its data. If the pixelRef - * is uncompressed or otherwise does not have this form, return NULL. - * - * If non-null is returned, the caller is responsible for calling unref() - * on the data when it is finished. - */ - SkData* refEncodedData() { - return this->onRefEncodedData(); - } - struct LockRequest { SkISize fSize; SkFilterQuality fQuality; @@ -206,34 +167,6 @@ public: bool requestLock(const LockRequest&, LockResult*); - /** - * If this can efficiently return YUV data, this should return true. - * Otherwise this returns false and does not modify any of the parameters. - * - * @param sizeInfo Output parameter indicating the sizes and required - * allocation widths of the Y, U, and V planes. - * @param colorSpace Output parameter. - */ - bool queryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const { - return this->onQueryYUV8(sizeInfo, colorSpace); - } - - /** - * Returns true on success and false on failure. - * Copies YUV data into the provided YUV planes. - * - * @param sizeInfo Needs to exactly match the values returned by the - * query, except the WidthBytes may be larger than the - * recommendation (but not smaller). - * @param planes Memory for each of the Y, U, and V planes. - */ - bool getYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) { - return this->onGetYUV8Planes(sizeInfo, planes); - } - - /** Populates dst with the pixels of this pixelRef, converting them to colorType. */ - bool readPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subset = NULL); - // Register a listener that may be called the next time our generation ID changes. // // We'll only call the listener if we're confident that we are the only SkPixelRef with this @@ -258,12 +191,10 @@ public: virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return NULL; } - /** - * Returns true if the pixels are generated on-the-fly (when required). - */ - bool isLazyGenerated() const { return this->onIsLazyGenerated(); } - protected: +#ifdef SK_SUPPORT_LEGACY_NO_ADDR_PIXELREF + virtual +#endif /** * On success, returns true and fills out the LockRec for the pixels. On * failure returns false and ignores the LockRec parameter. @@ -271,8 +202,14 @@ protected: * The caller will have already acquired a mutex for thread safety, so this * method need not do that. */ - virtual bool onNewLockPixels(LockRec*) = 0; + bool onNewLockPixels(LockRec*) { + SkASSERT(false); // should never be called + return true; + } +#ifdef SK_SUPPORT_LEGACY_NO_ADDR_PIXELREF + virtual +#endif /** * Balancing the previous successful call to onNewLockPixels. The locked * pixel address will no longer be referenced, so the subclass is free to @@ -281,32 +218,13 @@ protected: * The caller will have already acquired a mutex for thread safety, so this * method need not do that. */ - virtual void onUnlockPixels() = 0; - - /** Default impl returns true */ - virtual bool onLockPixelsAreWritable() const; - - /** - * For pixelrefs that don't have access to their raw pixels, they may be - * able to make a copy of them (e.g. if the pixels are on the GPU). - * - * The base class implementation returns false; - */ - virtual bool onReadPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subsetOrNull); - - // default impl returns NULL. - virtual SkData* onRefEncodedData(); + void onUnlockPixels() { + SkASSERT(false); // should never be called + } // default impl does nothing. virtual void onNotifyPixelsChanged(); - virtual bool onQueryYUV8(SkYUVSizeInfo*, SkYUVColorSpace*) const { - return false; - } - virtual bool onGetYUV8Planes(const SkYUVSizeInfo&, void*[3] /*planes*/) { - return false; - } - /** * Returns the size (in bytes) of the internally allocated memory. * This should be implemented in all serializable SkPixelRef derived classes. @@ -317,31 +235,36 @@ protected: */ virtual size_t getAllocatedSizeInBytes() const; - virtual bool onRequestLock(const LockRequest&, LockResult*); - - virtual bool onIsLazyGenerated() const { return false; } +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + // This is undefined if there are clients in-flight trying to use us + void android_only_reset(const SkImageInfo&, size_t rowBytes, sk_sp); +#endif /** Return the mutex associated with this pixelref. This value is assigned in the constructor, and cannot change during the lifetime of the object. */ SkBaseMutex* mutex() const { return &fMutex; } +#ifdef SK_SUPPORT_LEGACY_NO_ADDR_PIXELREF // only call from constructor. Flags this to always be locked, removing // the need to grab the mutex and call onLockPixels/onUnlockPixels. // Performance tweak to avoid those calls (esp. in multi-thread use case). void setPreLocked(void*, size_t rowBytes, SkColorTable*); +#endif private: mutable SkMutex fMutex; // mostly const. fInfo.fAlpahType can be changed at runtime. const SkImageInfo fInfo; + sk_sp fCTable; // duplicated in LockRec, will unify later // LockRec is only valid if we're in a locked state (isLocked()) LockRec fRec; int fLockCount; bool lockPixelsInsideMutex(); + bool internalRequestLock(const LockRequest&, LockResult*); // Bottom bit indicates the Gen ID is unique. bool genIDIsUnique() const { return SkToBool(fTaggedGenID.load() & 1); } @@ -353,8 +276,6 @@ private: SkTDArray fGenIDChangeListeners; // pointers are owned - SkString fURI; - // Set true by caches when they cache content that's derived from the current pixels. SkAtomic fAddedToCache; @@ -387,19 +308,9 @@ private: friend class SkImage_Gpu; friend class SkImageCacherator; friend class SkSpecialImage_Gpu; + friend void SkBitmapCache_setImmutableWithID(SkPixelRef*, uint32_t); typedef SkRefCnt INHERITED; }; -class SkPixelRefFactory : public SkRefCnt { -public: - /** - * Allocate a new pixelref matching the specified ImageInfo, allocating - * the memory for the pixels. If the ImageInfo requires a ColorTable, - * the pixelref will ref() the colortable. - * On failure return NULL. - */ - virtual SkPixelRef* create(const SkImageInfo&, size_t rowBytes, SkColorTable*) = 0; -}; - #endif diff --git a/gfx/skia/skia/include/core/SkPixmap.h b/gfx/skia/skia/include/core/SkPixmap.h index 699ddb4d4495..6cf948e601f2 100644 --- a/gfx/skia/skia/include/core/SkPixmap.h +++ b/gfx/skia/skia/include/core/SkPixmap.h @@ -70,6 +70,7 @@ public: int height() const { return fInfo.height(); } SkColorType colorType() const { return fInfo.colorType(); } SkAlphaType alphaType() const { return fInfo.alphaType(); } + SkColorSpace* colorSpace() const { return fInfo.colorSpace(); } bool isOpaque() const { return fInfo.isOpaque(); } SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); } @@ -89,6 +90,22 @@ public: uint64_t getSafeSize64() const { return fInfo.getSafeSize64(fRowBytes); } size_t getSafeSize() const { return fInfo.getSafeSize(fRowBytes); } + /** + * This will brute-force return true if all of the pixels in the pixmap + * are opaque. If there are no pixels, or encounters an error, returns false. + */ + bool computeIsOpaque() const; + + /** + * Converts the pixel at the specified coordinate to an unpremultiplied + * SkColor. Note: this ignores any SkColorSpace information, and may return + * lower precision data than is actually in the pixel. Alpha only + * colortypes (e.g. kAlpha_8_SkColorType) return black with the appropriate + * alpha set. The value is undefined for kUnknown_SkColorType or if x or y + * are out of bounds, or if the pixtap does not have any pixels. + */ + SkColor getColor(int x, int y) const; + const void* addr(int x, int y) const { return (const char*)fPixels + fInfo.computeOffset(x, y, fRowBytes); } diff --git a/gfx/skia/skia/include/core/SkPostConfig.h b/gfx/skia/skia/include/core/SkPostConfig.h index 1b1cb3e751e7..c34397cde64c 100644 --- a/gfx/skia/skia/include/core/SkPostConfig.h +++ b/gfx/skia/skia/include/core/SkPostConfig.h @@ -77,15 +77,6 @@ # endif #endif -// As usual, there are two ways to increase alignment... the MSVC way and the everyone-else way. -#ifndef SK_STRUCT_ALIGN - #ifdef _MSC_VER - #define SK_STRUCT_ALIGN(N) __declspec(align(N)) - #else - #define SK_STRUCT_ALIGN(N) __attribute__((aligned(N))) - #endif -#endif - #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 #define SK_VECTORCALL __vectorcall #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) diff --git a/gfx/skia/skia/include/core/SkPreConfig.h b/gfx/skia/skia/include/core/SkPreConfig.h index cb7eb3f3e684..0e6f787aee6b 100644 --- a/gfx/skia/skia/include/core/SkPreConfig.h +++ b/gfx/skia/skia/include/core/SkPreConfig.h @@ -84,7 +84,7 @@ defined(__s390__) || \ (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ (defined(__ia64) && defined(__BIG_ENDIAN__)) - #define SK_CPU_BENDIAN + #define SK_CPU_BENDIAN #else #define SK_CPU_LENDIAN #endif diff --git a/gfx/skia/skia/include/core/SkRSXform.h b/gfx/skia/skia/include/core/SkRSXform.h index 7af6e67c128d..dffbc59d39ee 100644 --- a/gfx/skia/skia/include/core/SkRSXform.h +++ b/gfx/skia/skia/include/core/SkRSXform.h @@ -8,7 +8,8 @@ #ifndef SkRSXform_DEFINED #define SkRSXform_DEFINED -#include "SkScalar.h" +#include "SkPoint.h" +#include "SkSize.h" /** * A compressed form of a rotation+scale matrix. diff --git a/gfx/skia/skia/include/core/SkRasterHandleAllocator.h b/gfx/skia/skia/include/core/SkRasterHandleAllocator.h new file mode 100644 index 000000000000..e1cc83040e23 --- /dev/null +++ b/gfx/skia/skia/include/core/SkRasterHandleAllocator.h @@ -0,0 +1,87 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRasterHandleAllocator_DEFINED +#define SkRasterHandleAllocator_DEFINED + +#include "SkImageInfo.h" + +class SkBitmap; +class SkCanvas; +class SkMatrix; + +/** + * If a client wants to control the allocation of raster layers in a canvas, it should subclass + * SkRasterHandleAllocator. This allocator performs two tasks: + * 1. controls how the memory for the pixels is allocated + * 2. associates a "handle" to a private object that can track the matrix/clip of the SkCanvas + * + * This example allocates a canvas, and defers to the allocator to create the base layer. + * + * std::unique_ptr canvas = SkRasterHandleAllocator::MakeCanvas( + * SkImageInfo::Make(...), + * skstd::make_unique(...), + * nullptr); + * + * If you have already allocated the base layer (and its handle, release-proc etc.) then you + * can pass those in using the last parameter to MakeCanvas(). + * + * Regardless of how the base layer is allocated, each time canvas->saveLayer() is called, + * your allocator's allocHandle() will be called. + */ +class SK_API SkRasterHandleAllocator { +public: + virtual ~SkRasterHandleAllocator() {} + + // The value that is returned to clients of the canvas that has this allocator installed. + typedef void* Handle; + + struct Rec { + // When the allocation goes out of scope, this proc is called to free everything associated + // with it: the pixels, the "handle", etc. This is passed the pixel address and fReleaseCtx. + void (*fReleaseProc)(void* pixels, void* ctx); + void* fReleaseCtx; // context passed to fReleaseProc + void* fPixels; // pixels for this allocation + size_t fRowBytes; // rowbytes for these pixels + Handle fHandle; // public handle returned by SkCanvas::accessTopRasterHandle() + }; + + /** + * Given a requested info, allocate the corresponding pixels/rowbytes, and whatever handle + * is desired to give clients access to those pixels. The rec also contains a proc and context + * which will be called when this allocation goes out of scope. + * + * e.g. + * when canvas->saveLayer() is called, the allocator will be called to allocate the pixels + * for the layer. When canvas->restore() is called, the fReleaseProc will be called. + */ + virtual bool allocHandle(const SkImageInfo&, Rec*) = 0; + + /** + * Clients access the handle for a given layer by calling SkCanvas::accessTopRasterHandle(). + * To allow the handle to reflect the current matrix/clip in the canvs, updateHandle() is + * is called. The subclass is responsible to update the handle as it sees fit. + */ + virtual void updateHandle(Handle, const SkMatrix&, const SkIRect&) = 0; + + /** + * This creates a canvas which will use the allocator to manage pixel allocations, including + * all calls to saveLayer(). + * + * If rec is non-null, then it will be used as the base-layer of pixels/handle. + * If rec is null, then the allocator will be called for the base-layer as well. + */ + static std::unique_ptr MakeCanvas(std::unique_ptr, + const SkImageInfo&, const Rec* rec = nullptr); + +private: + friend class SkBitmapDevice; + + Handle allocBitmap(const SkImageInfo&, SkBitmap*); +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkRect.h b/gfx/skia/skia/include/core/SkRect.h index 27a648feeb93..b8cf8464046e 100644 --- a/gfx/skia/skia/include/core/SkRect.h +++ b/gfx/skia/skia/include/core/SkRect.h @@ -280,7 +280,7 @@ struct SK_API SkIRect { intersection, otherwise return false and do not change this rectangle. If either rectangle is empty, do nothing and return false. */ - bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& r) { + bool intersect(const SkIRect& r) { return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom); } @@ -327,8 +327,7 @@ struct SK_API SkIRect { otherwise return false and do not change this rectangle. If either rectangle is empty, do nothing and return false. */ - bool SK_WARN_UNUSED_RESULT intersect(int32_t left, int32_t top, - int32_t right, int32_t bottom) { + bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) { if (left < right && top < bottom && !this->isEmpty() && fLeft < right && left < fRight && fTop < bottom && top < fBottom) { if (fLeft < left) fLeft = left; @@ -676,15 +675,14 @@ struct SK_API SkRect { intersection, otherwise return false and do not change this rectangle. If either rectangle is empty, do nothing and return false. */ - bool SK_WARN_UNUSED_RESULT intersect(const SkRect& r); + bool intersect(const SkRect& r); /** If this rectangle intersects the rectangle specified by left, top, right, bottom, return true and set this rectangle to that intersection, otherwise return false and do not change this rectangle. If either rectangle is empty, do nothing and return false. */ - bool SK_WARN_UNUSED_RESULT intersect(SkScalar left, SkScalar top, - SkScalar right, SkScalar bottom); + bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); /** * If rectangles a and b intersect, return true and set this rectangle to diff --git a/gfx/skia/skia/include/core/SkRefCnt.h b/gfx/skia/skia/include/core/SkRefCnt.h index 7e39125b763c..147fcf6f4c20 100644 --- a/gfx/skia/skia/include/core/SkRefCnt.h +++ b/gfx/skia/skia/include/core/SkRefCnt.h @@ -16,8 +16,6 @@ #include #include -#define SK_SUPPORT_TRANSITION_TO_SP_INTERFACES - /** \class SkRefCntBase SkRefCntBase is the base class for objects that may be shared by multiple @@ -71,15 +69,7 @@ public: /** Increment the reference count. Must be balanced by a call to unref(). */ void ref() const { -#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK - // Android employs some special subclasses that enable the fRefCnt to - // go to zero, but not below, prior to reusing the object. This breaks - // the use of unique() on such objects and as such should be removed - // once the Android code is fixed. - SkASSERT(getRefCnt() >= 0); -#else SkASSERT(getRefCnt() > 0); -#endif // No barrier required. (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); } @@ -147,6 +137,28 @@ class SK_API SkRefCnt : public SkRefCntBase { null in on each side of the assignment, and ensuring that ref() is called before unref(), in case the two pointers point to the same object. */ + +#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) +// This version heuristically detects data races, since those otherwise result +// in redundant reference count decrements, which are exceedingly +// difficult to debug. + +#define SkRefCnt_SafeAssign(dst, src) \ + do { \ + typedef typename std::remove_reference::type \ + SkRefCntPtrT; \ + SkRefCntPtrT old_dst = *const_cast(&dst); \ + if (src) src->ref(); \ + if (old_dst) old_dst->unref(); \ + if (old_dst != *const_cast(&dst)) { \ + SkDebugf("Detected racing Skia calls at %s:%d\n", \ + __FILE__, __LINE__); \ + } \ + dst = src; \ + } while (0) + +#else /* !SK_BUILD_FOR_ANDROID_FRAMEWORK */ + #define SkRefCnt_SafeAssign(dst, src) \ do { \ if (src) src->ref(); \ @@ -154,6 +166,8 @@ class SK_API SkRefCnt : public SkRefCntBase { dst = src; \ } while (0) +#endif + /** Call obj->ref() and return obj. The obj must not be nullptr. */ @@ -189,32 +203,6 @@ template static inline void SkSafeSetNull(T*& obj) { /////////////////////////////////////////////////////////////////////////////// -template struct SkTUnref { - void operator()(T* t) { t->unref(); } -}; - -/** - * Utility class that simply unref's its argument in the destructor. - */ -template class SkAutoTUnref : public std::unique_ptr> { -public: - explicit SkAutoTUnref(T* obj = nullptr) : std::unique_ptr>(obj) {} - - operator T*() const { return this->get(); } - -#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) - // Need to update graphics/Shader.cpp. - T* detach() { return this->release(); } -#endif -}; -// Can't use the #define trick below to guard a bare SkAutoTUnref(...) because it's templated. :( - -class SkAutoUnref : public SkAutoTUnref { -public: - SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref(obj) {} -}; -#define SkAutoUnref(...) SK_REQUIRE_LOCAL_VAR(SkAutoUnref) - // This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead of 8 or 16. // There's only benefit to using this if the deriving class does not otherwise need a vtable. template @@ -447,20 +435,14 @@ sk_sp sk_make_sp(Args&&... args) { return sk_sp(new T(std::forward(args)...)); } -#ifdef SK_SUPPORT_TRANSITION_TO_SP_INTERFACES - /* * Returns a sk_sp wrapping the provided ptr AND calls ref on it (if not null). * * This is different than the semantics of the constructor for sk_sp, which just wraps the ptr, * effectively "adopting" it. - * - * This function may be helpful while we convert callers from ptr-based to sk_sp-based parameters. */ template sk_sp sk_ref_sp(T* obj) { return sk_sp(SkSafeRef(obj)); } #endif - -#endif diff --git a/gfx/skia/skia/include/core/SkRegion.h b/gfx/skia/skia/include/core/SkRegion.h index a0f0e4ad3c68..49e5a19dbb72 100644 --- a/gfx/skia/skia/include/core/SkRegion.h +++ b/gfx/skia/skia/include/core/SkRegion.h @@ -436,6 +436,8 @@ private: int count_runtype_values(int* itop, int* ibot) const; + bool isValid() const; + static void BuildRectRuns(const SkIRect& bounds, RunType runs[kRectRegionRuns]); diff --git a/gfx/skia/skia/include/core/SkScalar.h b/gfx/skia/skia/include/core/SkScalar.h index 922840fd1af5..2c409c407b3b 100644 --- a/gfx/skia/skia/include/core/SkScalar.h +++ b/gfx/skia/skia/include/core/SkScalar.h @@ -10,14 +10,9 @@ #include "../private/SkFloatingPoint.h" -// TODO: move this sort of check into SkPostConfig.h -#define SK_SCALAR_IS_DOUBLE 0 #undef SK_SCALAR_IS_FLOAT #define SK_SCALAR_IS_FLOAT 1 - -#if SK_SCALAR_IS_FLOAT - typedef float SkScalar; #define SK_Scalar1 1.0f @@ -56,48 +51,6 @@ typedef float SkScalar; #define SkScalarLog(x) (float)sk_float_log(x) #define SkScalarLog2(x) (float)sk_float_log2(x) -#else // SK_SCALAR_IS_DOUBLE - -typedef double SkScalar; - -#define SK_Scalar1 1.0 -#define SK_ScalarHalf 0.5 -#define SK_ScalarSqrt2 1.414213562373095 -#define SK_ScalarPI 3.141592653589793 -#define SK_ScalarTanPIOver8 0.4142135623731 -#define SK_ScalarRoot2Over2 0.70710678118655 -#define SK_ScalarMax 1.7976931348623157+308 -#define SK_ScalarInfinity SK_DoubleInfinity -#define SK_ScalarNegativeInfinity SK_DoubleNegativeInfinity -#define SK_ScalarNaN SK_DoubleNaN - -#define SkScalarFloorToScalar(x) floor(x) -#define SkScalarCeilToScalar(x) ceil(x) -#define SkScalarRoundToScalar(x) floor((x) + 0.5) -#define SkScalarTruncToScalar(x) trunc(x) - -#define SkScalarFloorToInt(x) (int)floor(x) -#define SkScalarCeilToInt(x) (int)ceil(x) -#define SkScalarRoundToInt(x) (int)floor((x) + 0.5) - -#define SkScalarAbs(x) abs(x) -#define SkScalarCopySign(x, y) copysign(x, y) -#define SkScalarMod(x, y) fmod(x,y) -#define SkScalarSqrt(x) sqrt(x) -#define SkScalarPow(b, e) pow(b, e) - -#define SkScalarSin(radians) sin(radians) -#define SkScalarCos(radians) cos(radians) -#define SkScalarTan(radians) tan(radians) -#define SkScalarASin(val) asin(val) -#define SkScalarACos(val) acos(val) -#define SkScalarATan2(y, x) atan2(y,x) -#define SkScalarExp(x) exp(x) -#define SkScalarLog(x) log(x) -#define SkScalarLog2(x) log2(x) - -#endif - ////////////////////////////////////////////////////////////////////////////////////////////////// #define SkIntToScalar(x) static_cast(x) @@ -181,9 +134,6 @@ SkScalar SkScalarSinCos(SkScalar radians, SkScalar* cosValue); static inline SkScalar SkScalarSquare(SkScalar x) { return x * x; } -#define SkScalarMul(a, b) ((SkScalar)(a) * (b)) -#define SkScalarMulAdd(a, b, c) ((SkScalar)(a) * (b) + (c)) -#define SkScalarMulDiv(a, b, c) ((SkScalar)(a) * (b) / (c)) #define SkScalarInvert(x) (SK_Scalar1 / (x)) #define SkScalarFastInvert(x) (SK_Scalar1 / (x)) #define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf) diff --git a/gfx/skia/skia/include/core/SkShader.h b/gfx/skia/skia/include/core/SkShader.h index efd9aa075937..e49ad5f6a6b0 100644 --- a/gfx/skia/skia/include/core/SkShader.h +++ b/gfx/skia/skia/include/core/SkShader.h @@ -9,6 +9,7 @@ #define SkShader_DEFINED #include "SkBitmap.h" +#include "SkFilterQuality.h" #include "SkFlattenable.h" #include "SkImageInfo.h" #include "SkMask.h" @@ -16,12 +17,13 @@ #include "SkPaint.h" #include "../gpu/GrColor.h" +class SkArenaAlloc; class SkColorFilter; class SkColorSpace; class SkImage; class SkPath; class SkPicture; -class SkXfermode; +class SkRasterPipeline; class GrContext; class GrFragmentProcessor; @@ -38,7 +40,7 @@ class GrFragmentProcessor; class SK_API SkShader : public SkFlattenable { public: SkShader(const SkMatrix* localMatrix = NULL); - virtual ~SkShader(); + ~SkShader() override; /** * Returns the local matrix. @@ -98,6 +100,12 @@ public: */ virtual bool isOpaque() const { return false; } + /** + * Returns true if the shader is guaranteed to produce only a single color. + * Subclasses can override this to allow loop-hoisting optimization. + */ + virtual bool isConstant() const { return false; } + /** * ContextRec acts as a parameter bundle for creating Contexts. */ @@ -108,16 +116,18 @@ public: }; ContextRec(const SkPaint& paint, const SkMatrix& matrix, const SkMatrix* localM, - DstType dstType) + DstType dstType, SkColorSpace* dstColorSpace) : fPaint(&paint) , fMatrix(&matrix) , fLocalMatrix(localM) - , fPreferredDstType(dstType) {} + , fPreferredDstType(dstType) + , fDstColorSpace(dstColorSpace) {} const SkPaint* fPaint; // the current paint associated with the draw const SkMatrix* fMatrix; // the current matrix in the canvas const SkMatrix* fLocalMatrix; // optional local matrix const DstType fPreferredDstType; // the "natural" client dest type + SkColorSpace* fDstColorSpace; // the color space of the dest surface (if any) }; class Context : public ::SkNoncopyable { @@ -153,7 +163,7 @@ public: struct BlitState { // inputs Context* fCtx; - SkXfermode* fXfer; + SkBlendMode fMode; // outputs enum { N = 2 }; @@ -219,15 +229,11 @@ public: }; /** - * Create the actual object that does the shading. - * Size of storage must be >= contextSize. + * Make a context using the memory provided by the arena. + * + * @return pointer to context or nullptr if can't be created */ - Context* createContext(const ContextRec&, void* storage) const; - - /** - * Return the size of a Context returned by createContext. - */ - size_t contextSize(const ContextRec&) const; + Context* makeContext(const ContextRec&, SkArenaAlloc*) const; #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP /** @@ -320,32 +326,30 @@ public: struct ComposeRec { const SkShader* fShaderA; const SkShader* fShaderB; - const SkXfermode* fMode; + SkBlendMode fBlendMode; }; virtual bool asACompose(ComposeRec*) const { return false; } #if SK_SUPPORT_GPU struct AsFPArgs { + AsFPArgs() {} AsFPArgs(GrContext* context, const SkMatrix* viewMatrix, const SkMatrix* localMatrix, SkFilterQuality filterQuality, - SkColorSpace* dstColorSpace, - SkSourceGammaTreatment gammaTreatment) + SkColorSpace* dstColorSpace) : fContext(context) , fViewMatrix(viewMatrix) , fLocalMatrix(localMatrix) , fFilterQuality(filterQuality) - , fDstColorSpace(dstColorSpace) - , fGammaTreatment(gammaTreatment) {} + , fDstColorSpace(dstColorSpace) {} - GrContext* fContext; - const SkMatrix* fViewMatrix; - const SkMatrix* fLocalMatrix; - SkFilterQuality fFilterQuality; - SkColorSpace* fDstColorSpace; - SkSourceGammaTreatment fGammaTreatment; + GrContext* fContext; + const SkMatrix* fViewMatrix; + const SkMatrix* fLocalMatrix; + SkFilterQuality fFilterQuality; + SkColorSpace* fDstColorSpace; }; /** @@ -374,14 +378,6 @@ public: */ bool asLuminanceColor(SkColor*) const; -#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK - /** - * If the shader is a custom shader which has data the caller might want, call this function - * to get that data. - */ - virtual bool asACustomShader(void** /* customData */) const { return false; } -#endif - ////////////////////////////////////////////////////////////////////////// // Methods to create combinations or variants of shaders @@ -399,7 +395,7 @@ public: ////////////////////////////////////////////////////////////////////////// // Factory methods for stock shaders - + /** * Call this to create a new "empty" shader, that will not draw anything. */ @@ -419,40 +415,7 @@ public: */ static sk_sp MakeColorShader(const SkColor4f&, sk_sp); - static sk_sp MakeComposeShader(sk_sp dst, sk_sp src, - SkXfermode::Mode); - -#ifdef SK_SUPPORT_LEGACY_CREATESHADER_PTR - static SkShader* CreateEmptyShader() { return MakeEmptyShader().release(); } - static SkShader* CreateColorShader(SkColor c) { return MakeColorShader(c).release(); } - static SkShader* CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, - const SkMatrix* localMatrix = nullptr) { - return MakeBitmapShader(src, tmx, tmy, localMatrix).release(); - } - static SkShader* CreateComposeShader(SkShader* dst, SkShader* src, SkXfermode::Mode mode); - static SkShader* CreateComposeShader(SkShader* dst, SkShader* src, SkXfermode* xfer); - static SkShader* CreatePictureShader(const SkPicture* src, TileMode tmx, TileMode tmy, - const SkMatrix* localMatrix, const SkRect* tile); - - SkShader* newWithLocalMatrix(const SkMatrix& matrix) const { - return this->makeWithLocalMatrix(matrix).release(); - } - SkShader* newWithColorFilter(SkColorFilter* filter) const; -#endif - - /** - * Create a new compose shader, given shaders dst, src, and a combining xfermode mode. - * The xfermode is called with the output of the two shaders, and its output is returned. - * If xfer is null, SkXfermode::kSrcOver_Mode is assumed. - * - * The caller is responsible for managing its reference-count for the xfer (if not null). - */ - static sk_sp MakeComposeShader(sk_sp dst, sk_sp src, - sk_sp xfer); -#ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR - static sk_sp MakeComposeShader(sk_sp dst, sk_sp src, - SkXfermode* xfer); -#endif + static sk_sp MakeComposeShader(sk_sp dst, sk_sp src, SkBlendMode); /** Call this to create a new shader that will draw with the specified bitmap. * @@ -491,34 +454,30 @@ public: const SkMatrix* localMatrix, const SkRect* tile); /** - * If this shader can be represented by another shader + a localMatrix, return that shader - * and, if not NULL, the localMatrix. If not, return NULL and ignore the localMatrix parameter. - * - * Note: the returned shader (if not NULL) will have been ref'd, and it is the responsibility - * of the caller to balance that with unref() when they are done. + * If this shader can be represented by another shader + a localMatrix, return that shader and + * the localMatrix. If not, return nullptr and ignore the localMatrix parameter. */ - virtual SkShader* refAsALocalMatrixShader(SkMatrix* localMatrix) const; + virtual sk_sp makeAsALocalMatrixShader(SkMatrix* localMatrix) const; SK_TO_STRING_VIRT() SK_DEFINE_FLATTENABLE_TYPE(SkShader) SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() + bool appendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + const SkMatrix& ctm, const SkPaint&) const; + protected: void flatten(SkWriteBuffer&) const override; bool computeTotalInverse(const ContextRec&, SkMatrix* totalInverse) const; /** - * Your subclass must also override contextSize() if it overrides onCreateContext(). - * Base class impl returns NULL. + * Specialize creating a SkShader context using the supplied allocator. + * @return pointer to context owned by the arena allocator. */ - virtual Context* onCreateContext(const ContextRec&, void* storage) const; - - /** - * Override this if your subclass overrides createContext, to return the correct size of - * your subclass' context. - */ - virtual size_t onContextSize(const ContextRec&) const; + virtual Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const { + return nullptr; + } virtual bool onAsLuminanceColor(SkColor*) const { return false; @@ -534,6 +493,10 @@ protected: return nullptr; } + virtual bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + const SkMatrix&, const SkPaint&, + const SkMatrix* /*local matrix*/) const; + private: // This is essentially const, but not officially so it can be modified in // constructors. diff --git a/gfx/skia/skia/include/core/SkSize.h b/gfx/skia/skia/include/core/SkSize.h index 7bc8c7165d7b..061e3c4ca263 100644 --- a/gfx/skia/skia/include/core/SkSize.h +++ b/gfx/skia/skia/include/core/SkSize.h @@ -10,101 +10,83 @@ #include "SkScalar.h" -template struct SkTSize { - T fWidth; - T fHeight; +struct SkISize { + int32_t fWidth; + int32_t fHeight; - static SkTSize Make(T w, T h) { - SkTSize s; - s.fWidth = w; - s.fHeight = h; - return s; - } + static SkISize Make(int32_t w, int32_t h) { return {w, h}; } - void set(T w, T h) { - fWidth = w; - fHeight = h; - } + static SkISize MakeEmpty() { return {0, 0}; } + + void set(int32_t w, int32_t h) { *this = SkISize{w, h}; } /** Returns true iff fWidth == 0 && fHeight == 0 */ - bool isZero() const { - return 0 == fWidth && 0 == fHeight; - } + bool isZero() const { return 0 == fWidth && 0 == fHeight; } /** Returns true if either widht or height are <= 0 */ - bool isEmpty() const { - return fWidth <= 0 || fHeight <= 0; - } + bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; } /** Set the width and height to 0 */ - void setEmpty() { - fWidth = fHeight = 0; - } + void setEmpty() { fWidth = fHeight = 0; } - T width() const { return fWidth; } - T height() const { return fHeight; } + int32_t width() const { return fWidth; } + int32_t height() const { return fHeight; } - /** If width or height is < 0, it is set to 0 */ - void clampNegToZero() { - if (fWidth < 0) { - fWidth = 0; - } - if (fHeight < 0) { - fHeight = 0; - } - } - - bool equals(T w, T h) const { - return fWidth == w && fHeight == h; - } + bool equals(int32_t w, int32_t h) const { return fWidth == w && fHeight == h; } }; -template -static inline bool operator==(const SkTSize& a, const SkTSize& b) { +static inline bool operator==(const SkISize& a, const SkISize& b) { return a.fWidth == b.fWidth && a.fHeight == b.fHeight; } -template -static inline bool operator!=(const SkTSize& a, const SkTSize& b) { - return !(a == b); -} +static inline bool operator!=(const SkISize& a, const SkISize& b) { return !(a == b); } /////////////////////////////////////////////////////////////////////////////// -typedef SkTSize SkISize; +struct SkSize { + SkScalar fWidth; + SkScalar fHeight; -struct SkSize : public SkTSize { - static SkSize Make(SkScalar w, SkScalar h) { - SkSize s; - s.fWidth = w; - s.fHeight = h; - return s; + static SkSize Make(SkScalar w, SkScalar h) { return {w, h}; } + + static SkSize Make(const SkISize& src) { + return {SkIntToScalar(src.width()), SkIntToScalar(src.height())}; } - SkSize& operator=(const SkISize& src) { - this->set(SkIntToScalar(src.fWidth), SkIntToScalar(src.fHeight)); - return *this; + return *this = SkSize{SkIntToScalar(src.fWidth), SkIntToScalar(src.fHeight)}; } - SkISize toRound() const { - SkISize s; - s.set(SkScalarRoundToInt(fWidth), SkScalarRoundToInt(fHeight)); - return s; - } + static SkSize MakeEmpty() { return {0, 0}; } - SkISize toCeil() const { - SkISize s; - s.set(SkScalarCeilToInt(fWidth), SkScalarCeilToInt(fHeight)); - return s; - } + void set(SkScalar w, SkScalar h) { *this = SkSize{w, h}; } - SkISize toFloor() const { - SkISize s; - s.set(SkScalarFloorToInt(fWidth), SkScalarFloorToInt(fHeight)); - return s; - } + /** Returns true iff fWidth == 0 && fHeight == 0 + */ + bool isZero() const { return 0 == fWidth && 0 == fHeight; } + + /** Returns true if either widht or height are <= 0 */ + bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; } + + /** Set the width and height to 0 */ + void setEmpty() { *this = SkSize{0, 0}; } + + SkScalar width() const { return fWidth; } + SkScalar height() const { return fHeight; } + + bool equals(SkScalar w, SkScalar h) const { return fWidth == w && fHeight == h; } + + SkISize toRound() const { return {SkScalarRoundToInt(fWidth), SkScalarRoundToInt(fHeight)}; } + + SkISize toCeil() const { return {SkScalarCeilToInt(fWidth), SkScalarCeilToInt(fHeight)}; } + + SkISize toFloor() const { return {SkScalarFloorToInt(fWidth), SkScalarFloorToInt(fHeight)}; } }; +static inline bool operator==(const SkSize& a, const SkSize& b) { + return a.fWidth == b.fWidth && a.fHeight == b.fHeight; +} + +static inline bool operator!=(const SkSize& a, const SkSize& b) { return !(a == b); } #endif diff --git a/gfx/skia/skia/include/core/SkStream.h b/gfx/skia/skia/include/core/SkStream.h index 7afce712401c..428f247fc551 100644 --- a/gfx/skia/skia/include/core/SkStream.h +++ b/gfx/skia/skia/include/core/SkStream.h @@ -12,6 +12,8 @@ #include "SkRefCnt.h" #include "SkScalar.h" +#include + class SkStream; class SkStreamRewindable; class SkStreamSeekable; @@ -187,21 +189,31 @@ public: @return true on success */ virtual bool write(const void* buffer, size_t size) = 0; - virtual void newline(); virtual void flush(); virtual size_t bytesWritten() const = 0; // helpers - bool write8(U8CPU); - bool write16(U16CPU); - bool write32(uint32_t); + bool write8(U8CPU value) { + uint8_t v = SkToU8(value); + return this->write(&v, 1); + } + bool write16(U16CPU value) { + uint16_t v = SkToU16(value); + return this->write(&v, 2); + } + bool write32(uint32_t v) { + return this->write(&v, 4); + } - bool writeText(const char text[]) { + bool writeText(const char text[]) { SkASSERT(text); return this->write(text, strlen(text)); } + + bool newline() { return this->write("\n", strlen("\n")); } + bool writeDecAsText(int32_t); bool writeBigDecAsText(int64_t, int minDigits = 0); bool writeHexAsText(uint32_t, int minDigits = 0); @@ -220,9 +232,20 @@ public: static int SizeOfPackedUInt(size_t value); }; +class SK_API SkNullWStream : public SkWStream { +public: + SkNullWStream() : fBytesWritten(0) {} + + bool write(const void*, size_t n) override { fBytesWritten += n; return true; } + void flush() override {} + size_t bytesWritten() const override { return fBytesWritten; } + +private: + size_t fBytesWritten; +}; + //////////////////////////////////////////////////////////////////////////////////////// -#include "SkString.h" #include /** A stream that wraps a C FILE* file stream. */ @@ -231,28 +254,20 @@ public: /** Initialize the stream by calling sk_fopen on the specified path. * This internal stream will be closed in the destructor. */ - explicit SkFILEStream(const char path[] = NULL); + explicit SkFILEStream(const char path[] = nullptr); - enum Ownership { - kCallerPasses_Ownership, - kCallerRetains_Ownership - }; /** Initialize the stream with an existing C file stream. - * While this stream exists, it assumes exclusive access to the C file stream. - * The C file stream will be closed in the destructor unless the caller specifies - * kCallerRetains_Ownership. + * The C file stream will be closed in the destructor. */ - explicit SkFILEStream(FILE* file, Ownership ownership = kCallerPasses_Ownership); + explicit SkFILEStream(FILE* file); - virtual ~SkFILEStream(); + ~SkFILEStream() override; /** Returns true if the current path could be opened. */ - bool isValid() const { return fFILE != NULL; } + bool isValid() const { return fFILE != nullptr; } - /** Close the current file, and open a new file with the specified path. - * If path is NULL, just close the current file. - */ - void setPath(const char path[]); + /** Close this SkFILEStream. */ + void close(); size_t read(void* buffer, size_t size) override; bool isAtEnd() const override; @@ -270,11 +285,14 @@ public: const void* getMemoryBase() override; private: - FILE* fFILE; - SkString fName; - Ownership fOwnership; - // fData is lazilly initialized when needed. - mutable sk_sp fData; + explicit SkFILEStream(std::shared_ptr, size_t size, size_t offset); + explicit SkFILEStream(std::shared_ptr, size_t size, size_t offset, size_t originalOffset); + + std::shared_ptr fFILE; + // My own council will I keep on sizes and offsets. + size_t fSize; + size_t fOffset; + size_t fOriginalOffset; typedef SkStreamAsset INHERITED; }; @@ -289,14 +307,6 @@ public: /** If copyData is true, the stream makes a private copy of the data. */ SkMemoryStream(const void* data, size_t length, bool copyData = false); -#ifdef SK_SUPPORT_LEGACY_STREAM_DATA - /** Use the specified data as the memory for this stream. - * The stream will call ref() on the data (assuming it is not NULL). - * DEPRECATED - */ - SkMemoryStream(SkData*); -#endif - /** Creates the stream to read from the specified data */ SkMemoryStream(sk_sp); @@ -314,22 +324,6 @@ public: sk_sp asData() const { return fData; } void setData(sk_sp); -#ifdef SK_SUPPORT_LEGACY_STREAM_DATA - /** Return the stream's data in a SkData. - * The caller must call unref() when it is finished using the data. - */ - SkData* copyToData() const { return asData().release(); } - - /** - * Use the specified data as the memory for this stream. - * The stream will call ref() on the data (assuming it is not NULL). - * The function returns the data parameter as a convenience. - */ - SkData* setData(SkData* data) { - this->setData(sk_ref_sp(data)); - return data; - } -#endif void skipToAlign4(); const void* getAtPos(); @@ -363,7 +357,7 @@ private: class SK_API SkFILEWStream : public SkWStream { public: SkFILEWStream(const char path[]); - virtual ~SkFILEWStream(); + ~SkFILEWStream() override; /** Returns true if the current path could be opened. */ @@ -380,52 +374,28 @@ private: typedef SkWStream INHERITED; }; -class SK_API SkMemoryWStream : public SkWStream { -public: - SkMemoryWStream(void* buffer, size_t size); - bool write(const void* buffer, size_t size) override; - size_t bytesWritten() const override { return fBytesWritten; } - -private: - char* fBuffer; - size_t fMaxLength; - size_t fBytesWritten; - - typedef SkWStream INHERITED; -}; - class SK_API SkDynamicMemoryWStream : public SkWStream { public: SkDynamicMemoryWStream(); - virtual ~SkDynamicMemoryWStream(); + ~SkDynamicMemoryWStream() override; bool write(const void* buffer, size_t size) override; - size_t bytesWritten() const override { return fBytesWritten; } - // random access write - // modifies stream and returns true if offset + size is less than or equal to getOffset() - bool write(const void* buffer, size_t offset, size_t size); - bool read(void* buffer, size_t offset, size_t size); - size_t getOffset() const { return fBytesWritten; } + size_t bytesWritten() const override; - // copy what has been written to the stream into dst + bool read(void* buffer, size_t offset, size_t size); + + /** More efficient version of read(dst, 0, bytesWritten()). */ void copyTo(void* dst) const; void writeToStream(SkWStream* dst) const; - sk_sp snapshotAsData() const; - // Return the contents as SkData, and then reset the stream. + /** Equivalent to copyTo() followed by reset(), but may save memory use. */ + void copyToAndReset(void* dst); + + /** Return the contents as SkData, and then reset the stream. */ sk_sp detachAsData(); -#ifdef SK_SUPPORT_LEGACY_STREAM_DATA - /** - * Return a copy of the data written so far. This call is responsible for - * calling unref() when they are finished with the data. - */ - SkData* copyToData() const { - return snapshotAsData().release(); - } -#endif /** Reset, returning a reader stream with the current content. */ - SkStreamAsset* detachAsStream(); + std::unique_ptr detachAsStream(); /** Reset the stream to its original, empty, state. */ void reset(); @@ -434,10 +404,13 @@ private: struct Block; Block* fHead; Block* fTail; - size_t fBytesWritten; - mutable sk_sp fCopy; // is invalidated if we write after it is created + size_t fBytesWrittenBeforeTail; - void invalidateCopy(); +#ifdef SK_DEBUG + void validate() const; +#else + void validate() const {} +#endif // For access to the Block type. friend class SkBlockMemoryStream; @@ -446,22 +419,4 @@ private: typedef SkWStream INHERITED; }; - -class SK_API SkDebugWStream : public SkWStream { -public: - SkDebugWStream() : fBytesWritten(0) {} - - // overrides - bool write(const void* buffer, size_t size) override; - void newline() override; - size_t bytesWritten() const override { return fBytesWritten; } - -private: - size_t fBytesWritten; - typedef SkWStream INHERITED; -}; - -// for now -typedef SkFILEStream SkURLStream; - #endif diff --git a/gfx/skia/skia/include/core/SkSurface.h b/gfx/skia/skia/include/core/SkSurface.h index 8e7e148cb9ee..0e2239a4ad61 100644 --- a/gfx/skia/skia/include/core/SkSurface.h +++ b/gfx/skia/skia/include/core/SkSurface.h @@ -18,12 +18,11 @@ class GrContext; class GrRenderTarget; /** - * SkSurface represents the backend/results of drawing to a canvas. For raster - * drawing, the surface will be pixels, but (for example) when drawing into - * a PDF or Picture canvas, the surface stores the recorded commands. + * SkSurface is responsible for managing the pixels that a canvas draws into. The pixels can be + * allocated either in CPU memory (a Raster surface) or on the GPU (a RenderTarget surface). * - * To draw into a canvas, first create the appropriate type of Surface, and - * then request the canvas from the surface. + * SkSurface takes care of allocating a SkCanvas that will draw into the surface. Call + * surface->getCanvas() to use that canvas (but don't delete it, it is owned by the surface). * * SkSurface always has non-zero dimensions. If there is a request for a new surface, and either * of the requested dimensions are zero, then NULL will be returned. @@ -51,14 +50,10 @@ public: void* context, const SkSurfaceProps* = nullptr); /** - * Return a new surface, with the memory for the pixels automatically allocated but respecting - * the specified rowBytes. If rowBytes==0, then a default value will be chosen. If a non-zero - * rowBytes is specified, then any images snapped off of this surface (via makeImageSnapshot()) - * are guaranteed to have the same rowBytes. - * - * If the requested alpha type is not opaque, then the surface's pixel memory will be - * zero-initialized. If it is opaque, then it will be left uninitialized, and the caller is - * responsible for initially clearing the surface. + * Return a new surface, with the memory for the pixels automatically allocated and + * zero-initialized, but respecting the specified rowBytes. If rowBytes==0, then a default + * value will be chosen. If a non-zero rowBytes is specified, then any images snapped off of + * this surface (via makeImageSnapshot()) are guaranteed to have the same rowBytes. * * If the requested surface cannot be created, or the request is not a * supported configuration, NULL will be returned. @@ -150,60 +145,12 @@ public: } static sk_sp MakeRenderTarget(GrContext* gr, SkBudgeted b, const SkImageInfo& info) { + if (!info.width() || !info.height()) { + return nullptr; + } return MakeRenderTarget(gr, b, info, 0, kBottomLeft_GrSurfaceOrigin, nullptr); } -#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API - static SkSurface* NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes, - const SkSurfaceProps* props = NULL) { - return MakeRasterDirect(info, pixels, rowBytes, props).release(); - } - static SkSurface* NewRasterDirectReleaseProc(const SkImageInfo& info, void* pixels, - size_t rowBytes, - void (*releaseProc)(void* pixels, void* context), - void* context, const SkSurfaceProps* props = NULL){ - return MakeRasterDirectReleaseProc(info, pixels, rowBytes, releaseProc, context, - props).release(); - } - static SkSurface* NewRaster(const SkImageInfo& info, size_t rowBytes, - const SkSurfaceProps* props) { - return MakeRaster(info, rowBytes, props).release(); - } - static SkSurface* NewRaster(const SkImageInfo& info, const SkSurfaceProps* props = NULL) { - return MakeRaster(info, props).release(); - } - static SkSurface* NewRasterN32Premul(int width, int height, - const SkSurfaceProps* props = NULL) { - return NewRaster(SkImageInfo::MakeN32Premul(width, height), props); - } - static SkSurface* NewFromBackendTexture(GrContext* ctx, const GrBackendTextureDesc& desc, - const SkSurfaceProps* props) { - return MakeFromBackendTexture(ctx, desc, props).release(); - } - // Legacy alias - static SkSurface* NewWrappedRenderTarget(GrContext* ctx, const GrBackendTextureDesc& desc, - const SkSurfaceProps* props) { - return NewFromBackendTexture(ctx, desc, props); - } - static SkSurface* NewFromBackendRenderTarget(GrContext* ctx, const GrBackendRenderTargetDesc& d, - const SkSurfaceProps* props) { - return MakeFromBackendRenderTarget(ctx, d, props).release(); - } - static SkSurface* NewFromBackendTextureAsRenderTarget(GrContext* ctx, - const GrBackendTextureDesc& desc, - const SkSurfaceProps* props) { - return MakeFromBackendTextureAsRenderTarget(ctx, desc, props).release(); - } - static SkSurface* NewRenderTarget(GrContext* ctx, SkBudgeted b, const SkImageInfo& info, - int sampleCount, const SkSurfaceProps* props = NULL) { - return MakeRenderTarget(ctx, b, info, sampleCount, props).release(); - } - static SkSurface* NewRenderTarget(GrContext* gr, SkBudgeted b, const SkImageInfo& info) { - return NewRenderTarget(gr, b, info, 0); - } - SkSurface* newSurface(const SkImageInfo& info) { return this->makeSurface(info).release(); } -#endif - int width() const { return fWidth; } int height() const { return fHeight; } @@ -302,32 +249,10 @@ public: /** * Returns an image of the current state of the surface pixels up to this * point. Subsequent changes to the surface (by drawing into its canvas) - * will not be reflected in this image. If a copy must be made the Budgeted - * parameter controls whether it counts against the resource budget - * (currently for the gpu backend only). + * will not be reflected in this image. For the GPU-backend, the budgeting + * decision for the snapped image will match that of the surface. */ - sk_sp makeImageSnapshot(SkBudgeted = SkBudgeted::kYes); - - /** - * In rare instances a client may want a unique copy of the SkSurface's contents in an image - * snapshot. This enum can be used to enforce that the image snapshot's backing store is not - * shared with another image snapshot or the surface's backing store. This is generally more - * expensive. This was added for Chromium bug 585250. - */ - enum ForceUnique { - kNo_ForceUnique, - kYes_ForceUnique - }; - sk_sp makeImageSnapshot(SkBudgeted, ForceUnique); - -#ifdef SK_SUPPORT_LEGACY_IMAGEFACTORY - SkImage* newImageSnapshot(SkBudgeted budgeted = SkBudgeted::kYes) { - return this->makeImageSnapshot(budgeted).release(); - } - SkImage* newImageSnapshot(SkBudgeted budgeted, ForceUnique force) { - return this->makeImageSnapshot(budgeted, force).release(); - } -#endif + sk_sp makeImageSnapshot(); /** * Though the caller could get a snapshot image explicitly, and draw that, @@ -349,10 +274,6 @@ public: */ bool peekPixels(SkPixmap*); -#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS - const void* peekPixels(SkImageInfo* info, size_t* rowBytes); -#endif - /** * Copy the pixels from the surface into the specified buffer (pixels + rowBytes), * converting them into the requested format (dstInfo). The surface pixels are read diff --git a/gfx/skia/skia/include/core/SkTRegistry.h b/gfx/skia/skia/include/core/SkTRegistry.h deleted file mode 100644 index 0994c990dccb..000000000000 --- a/gfx/skia/skia/include/core/SkTRegistry.h +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * Copyright 2009 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkTRegistry_DEFINED -#define SkTRegistry_DEFINED - -#include "SkTypes.h" - -/** Template class that registers itself (in the constructor) into a linked-list - and provides a function-pointer. This can be used to auto-register a set of - services, e.g. a set of image codecs. - */ -template class SkTRegistry : SkNoncopyable { -public: - typedef T Factory; - - explicit SkTRegistry(T fact) : fFact(fact) { -#ifdef SK_BUILD_FOR_ANDROID - // work-around for double-initialization bug - { - SkTRegistry* reg = gHead; - while (reg) { - if (reg == this) { - return; - } - reg = reg->fChain; - } - } -#endif - fChain = gHead; - gHead = this; - } - - static const SkTRegistry* Head() { return gHead; } - - const SkTRegistry* next() const { return fChain; } - const Factory& factory() const { return fFact; } - -private: - Factory fFact; - SkTRegistry* fChain; - - static SkTRegistry* gHead; -}; - -// The caller still needs to declare an instance of this somewhere -template SkTRegistry* SkTRegistry::gHead; - -#endif diff --git a/gfx/skia/skia/include/core/SkTextBlob.h b/gfx/skia/skia/include/core/SkTextBlob.h index 35d5dc41738f..956c6a092dfd 100644 --- a/gfx/skia/skia/include/core/SkTextBlob.h +++ b/gfx/skia/skia/include/core/SkTextBlob.h @@ -9,6 +9,7 @@ #define SkTextBlob_DEFINED #include "../private/SkTemplates.h" +#include "../private/SkAtomics.h" #include "SkPaint.h" #include "SkString.h" #include "SkRefCnt.h" @@ -60,7 +61,7 @@ private: friend class SkNVRefCnt; class RunRecord; - SkTextBlob(int runCount, const SkRect& bounds); + explicit SkTextBlob(const SkRect& bounds); ~SkTextBlob(); @@ -75,12 +76,19 @@ private: static unsigned ScalarsPerGlyph(GlyphPositioning pos); + // Call when this blob is part of the key to a cache entry. This allows the cache + // to know automatically those entries can be purged when this SkTextBlob is deleted. + void notifyAddedToCache() const { + fAddedToCache.store(true); + } + + friend class GrTextBlobCache; friend class SkTextBlobBuilder; friend class SkTextBlobRunIterator; - const int fRunCount; - const SkRect fBounds; - const uint32_t fUniqueID; + const SkRect fBounds; + const uint32_t fUniqueID; + mutable SkAtomic fAddedToCache; SkDEBUGCODE(size_t fStorageSize;) @@ -101,17 +109,13 @@ public: ~SkTextBlobBuilder(); /** - * Returns an immutable SkTextBlob for the current runs/glyphs. The builder is reset and - * can be reused. + * Returns an immutable SkTextBlob for the current runs/glyphs, + * or nullptr if no runs were allocated. + * + * The builder is reset and can be reused. */ sk_sp make(); -#ifdef SK_SUPPORT_LEGACY_TEXTBLOB_BUILDER - const SkTextBlob* build() { - return this->make().release(); - } -#endif - /** * Glyph and position buffers associated with a run. * diff --git a/gfx/skia/skia/include/core/SkTypeface.h b/gfx/skia/skia/include/core/SkTypeface.h index c25552a2d001..9083b9edb1df 100644 --- a/gfx/skia/skia/include/core/SkTypeface.h +++ b/gfx/skia/skia/include/core/SkTypeface.h @@ -11,6 +11,7 @@ #include "../private/SkBitmaskEnum.h" #include "../private/SkOnce.h" #include "../private/SkWeakRefCnt.h" +#include "SkFontArguments.h" #include "SkFontStyle.h" #include "SkRect.h" #include "SkString.h" @@ -77,6 +78,20 @@ public: */ bool isFixedPitch() const { return fIsFixedPitch; } + /** Copy into 'coordinates' (allocated by the caller) the design variation coordinates. + * + * @param coordinates the buffer into which to write the design variation coordinates. + * @param coordinateCount the number of entries available through 'coordinates'. + * + * @return The number of axes, or -1 if there is an error. + * If 'coordinates != nullptr' and 'coordinateCount >= numAxes' then 'coordinates' will be + * filled with the variation coordinates describing the position of this typeface in design + * variation space. It is possible the number of axes can be retrieved but actual position + * cannot. + */ + int getVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const; + /** Return a 32bit value for this typeface, unique for the underlying font data. Will never return 0. */ @@ -95,28 +110,17 @@ public: /** Returns the default typeface, which is never nullptr. */ static sk_sp MakeDefault(Style style = SkTypeface::kNormal); -#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR - static SkTypeface* RefDefault(Style style = SkTypeface::kNormal) { - return MakeDefault(style).release(); - } -#endif - /** Creates a new reference to the typeface that most closely matches the - requested familyName and fontStyle. This method allows extended font - face specifiers as in the SkFontStyle type. Will never return null. + /** Creates a new reference to the typeface that most closely matches the + requested familyName and fontStyle. This method allows extended font + face specifiers as in the SkFontStyle type. Will never return null. - @param familyName May be NULL. The name of the font family. - @param fontStyle The style of the typeface. - @return reference to the closest-matching typeface. Call must call + @param familyName May be NULL. The name of the font family. + @param fontStyle The style of the typeface. + @return reference to the closest-matching typeface. Call must call unref() when they are done. */ - static sk_sp MakeFromName(const char familyName[], SkFontStyle fontStyle); - -#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR - static SkTypeface* CreateFromName(const char familyName[], Style style) { - return MakeFromName(familyName, SkFontStyle::FromOldStyle(style)).release(); - } -#endif + static sk_sp MakeFromName(const char familyName[], SkFontStyle fontStyle); /** Return the typeface that most closely matches the requested typeface and style. Use this to pick a new style from the same family of the existing typeface. @@ -132,22 +136,12 @@ public: not a valid font file, returns nullptr. */ static sk_sp MakeFromFile(const char path[], int index = 0); -#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR - static SkTypeface* CreateFromFile(const char path[], int index = 0) { - return MakeFromFile(path, index).release(); - } -#endif /** Return a new typeface given a stream. If the stream is not a valid font file, returns nullptr. Ownership of the stream is transferred, so the caller must not reference it again. */ static sk_sp MakeFromStream(SkStreamAsset* stream, int index = 0); -#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR - static SkTypeface* CreateFromStream(SkStreamAsset* stream, int index = 0) { - return MakeFromStream(stream, index).release(); - } -#endif /** Return a new typeface given font data and configuration. If the data is not valid font data, returns nullptr. @@ -308,8 +302,9 @@ public: * if allowFailure is true, this returns NULL, else it returns a * dummy scalercontext that will not crash, but will draw nothing. */ - SkScalerContext* createScalerContext(const SkScalerContextEffects&, const SkDescriptor*, - bool allowFailure = false) const; + std::unique_ptr createScalerContext(const SkScalerContextEffects&, + const SkDescriptor*, + bool allowFailure = false) const; /** * Return a rectangle (scaled to 1-pt) that represents the union of the bounds of all @@ -367,6 +362,10 @@ protected: // TODO: make pure virtual. virtual std::unique_ptr onMakeFontData() const; + virtual int onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const = 0; + virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0; virtual int onCharsToGlyphs(const void* chars, Encoding, SkGlyphID glyphs[], diff --git a/gfx/skia/skia/include/core/SkTypes.h b/gfx/skia/skia/include/core/SkTypes.h index 0cef8a125702..beb2be51432b 100644 --- a/gfx/skia/skia/include/core/SkTypes.h +++ b/gfx/skia/skia/include/core/SkTypes.h @@ -34,28 +34,12 @@ // IWYU pragma: end_exports #include +// TODO(herb): remove after chromuim skia/ext/SkMemory_new_handler.cpp +// has been updated to point to private/SkMalloc.h +#include "../private/SkMalloc.h" -/** - * sk_careful_memcpy() is just like memcpy(), but guards against undefined behavior. - * - * It is undefined behavior to call memcpy() with null dst or src, even if len is 0. - * If an optimizer is "smart" enough, it can exploit this to do unexpected things. - * memcpy(dst, src, 0); - * if (src) { - * printf("%x\n", *src); - * } - * In this code the compiler can assume src is not null and omit the if (src) {...} check, - * unconditionally running the printf, crashing the program if src really is null. - * Of the compilers we pay attention to only GCC performs this optimization in practice. - */ -static inline void* sk_careful_memcpy(void* dst, const void* src, size_t len) { - // When we pass >0 len we had better already be passing valid pointers. - // So we just need to skip calling memcpy when len == 0. - if (len) { - memcpy(dst,src,len); - } - return dst; -} +// enable to test new device-base clipping +//#define SK_USE_DEVICE_CLIPPING /** \file SkTypes.h */ @@ -66,57 +50,13 @@ static inline void* sk_careful_memcpy(void* dst, const void* src, size_t len) { #define SKIA_VERSION_MINOR 0 #define SKIA_VERSION_PATCH 0 -/* - memory wrappers to be implemented by the porting layer (platform) -*/ -/** Called internally if we run out of memory. The platform implementation must - not return, but should either throw an exception or otherwise exit. -*/ -SK_API extern void sk_out_of_memory(void); /** Called internally if we hit an unrecoverable error. The platform implementation must not return, but should either throw an exception or otherwise exit. */ SK_API extern void sk_abort_no_print(void); -enum { - SK_MALLOC_TEMP = 0x01, //!< hint to sk_malloc that the requested memory will be freed in the scope of the stack frame - SK_MALLOC_THROW = 0x02 //!< instructs sk_malloc to call sk_throw if the memory cannot be allocated. -}; -/** Return a block of memory (at least 4-byte aligned) of at least the - specified size. If the requested memory cannot be returned, either - return null (if SK_MALLOC_TEMP bit is clear) or throw an exception - (if SK_MALLOC_TEMP bit is set). To free the memory, call sk_free(). -*/ -SK_API extern void* sk_malloc_flags(size_t size, unsigned flags); -/** Same as sk_malloc(), but hard coded to pass SK_MALLOC_THROW as the flag -*/ -SK_API extern void* sk_malloc_throw(size_t size); -/** Same as standard realloc(), but this one never returns null on failure. It will throw - an exception if it fails. -*/ -SK_API extern void* sk_realloc_throw(void* buffer, size_t size); -/** Free memory returned by sk_malloc(). It is safe to pass null. -*/ -SK_API extern void sk_free(void*); - -/** Much like calloc: returns a pointer to at least size zero bytes, or NULL on failure. - */ -SK_API extern void* sk_calloc(size_t size); - -/** Same as sk_calloc, but throws an exception instead of returning NULL on failure. - */ -SK_API extern void* sk_calloc_throw(size_t size); - -// bzero is safer than memset, but we can't rely on it, so... sk_bzero() -static inline void sk_bzero(void* buffer, size_t size) { - // Please c.f. sk_careful_memcpy. It's undefined behavior to call memset(null, 0, 0). - if (size) { - memset(buffer, 0, size); - } -} - /////////////////////////////////////////////////////////////////////////////// #ifdef override_GLOBAL_NEW @@ -395,10 +335,10 @@ static inline constexpr int Sk32ToBool(uint32_t n) { /** Generic swap function. Classes with efficient swaps should specialize this function to take their fast path. This function is used by SkTSort. */ -template inline void SkTSwap(T& a, T& b) { - T c(a); - a = b; - b = c; +template static inline void SkTSwap(T& a, T& b) { + T c(std::move(a)); + a = std::move(b); + b = std::move(c); } static inline int32_t SkAbs32(int32_t value) { @@ -409,7 +349,7 @@ static inline int32_t SkAbs32(int32_t value) { return value; } -template inline T SkTAbs(T value) { +template static inline T SkTAbs(T value) { if (value < 0) { value = -value; } @@ -509,222 +449,6 @@ private: SkNoncopyable& operator=(const SkNoncopyable&); }; -class SkAutoFree : SkNoncopyable { -public: - SkAutoFree() : fPtr(NULL) {} - explicit SkAutoFree(void* ptr) : fPtr(ptr) {} - ~SkAutoFree() { sk_free(fPtr); } - - /** Return the currently allocate buffer, or null - */ - void* get() const { return fPtr; } - - /** Assign a new ptr allocated with sk_malloc (or null), and return the - previous ptr. Note it is the caller's responsibility to sk_free the - returned ptr. - */ - void* set(void* ptr) { - void* prev = fPtr; - fPtr = ptr; - return prev; - } - - /** Transfer ownership of the current ptr to the caller, setting the - internal reference to null. Note the caller is reponsible for calling - sk_free on the returned address. - */ - void* release() { return this->set(NULL); } - - /** Free the current buffer, and set the internal reference to NULL. Same - as calling sk_free(release()) - */ - void reset() { - sk_free(fPtr); - fPtr = NULL; - } - -private: - void* fPtr; - // illegal - SkAutoFree(const SkAutoFree&); - SkAutoFree& operator=(const SkAutoFree&); -}; -#define SkAutoFree(...) SK_REQUIRE_LOCAL_VAR(SkAutoFree) - -/** - * Manage an allocated block of heap memory. This object is the sole manager of - * the lifetime of the block, so the caller must not call sk_free() or delete - * on the block, unless release() was called. - */ -class SkAutoMalloc : SkNoncopyable { -public: - explicit SkAutoMalloc(size_t size = 0) { - fPtr = size ? sk_malloc_throw(size) : NULL; - fSize = size; - } - - ~SkAutoMalloc() { - sk_free(fPtr); - } - - /** - * Passed to reset to specify what happens if the requested size is smaller - * than the current size (and the current block was dynamically allocated). - */ - enum OnShrink { - /** - * If the requested size is smaller than the current size, and the - * current block is dynamically allocated, free the old block and - * malloc a new block of the smaller size. - */ - kAlloc_OnShrink, - - /** - * If the requested size is smaller than the current size, and the - * current block is dynamically allocated, just return the old - * block. - */ - kReuse_OnShrink - }; - - /** - * Reallocates the block to a new size. The ptr may or may not change. - */ - void* reset(size_t size = 0, OnShrink shrink = kAlloc_OnShrink, bool* didChangeAlloc = NULL) { - if (size == fSize || (kReuse_OnShrink == shrink && size < fSize)) { - if (didChangeAlloc) { - *didChangeAlloc = false; - } - return fPtr; - } - - sk_free(fPtr); - fPtr = size ? sk_malloc_throw(size) : NULL; - fSize = size; - if (didChangeAlloc) { - *didChangeAlloc = true; - } - - return fPtr; - } - - /** - * Return the allocated block. - */ - void* get() { return fPtr; } - const void* get() const { return fPtr; } - - /** Transfer ownership of the current ptr to the caller, setting the - internal reference to null. Note the caller is reponsible for calling - sk_free on the returned address. - */ - void* release() { - void* ptr = fPtr; - fPtr = NULL; - fSize = 0; - return ptr; - } - -private: - void* fPtr; - size_t fSize; // can be larger than the requested size (see kReuse) -}; -#define SkAutoMalloc(...) SK_REQUIRE_LOCAL_VAR(SkAutoMalloc) - -/** - * Manage an allocated block of memory. If the requested size is <= kSizeRequested (or slightly - * more), then the allocation will come from the stack rather than the heap. This object is the - * sole manager of the lifetime of the block, so the caller must not call sk_free() or delete on - * the block. - */ -template class SkAutoSMalloc : SkNoncopyable { -public: - /** - * Creates initially empty storage. get() returns a ptr, but it is to a zero-byte allocation. - * Must call reset(size) to return an allocated block. - */ - SkAutoSMalloc() { - fPtr = fStorage; - fSize = kSize; - } - - /** - * Allocate a block of the specified size. If size <= kSizeRequested (or slightly more), then - * the allocation will come from the stack, otherwise it will be dynamically allocated. - */ - explicit SkAutoSMalloc(size_t size) { - fPtr = fStorage; - fSize = kSize; - this->reset(size); - } - - /** - * Free the allocated block (if any). If the block was small enough to have been allocated on - * the stack, then this does nothing. - */ - ~SkAutoSMalloc() { - if (fPtr != (void*)fStorage) { - sk_free(fPtr); - } - } - - /** - * Return the allocated block. May return non-null even if the block is of zero size. Since - * this may be on the stack or dynamically allocated, the caller must not call sk_free() on it, - * but must rely on SkAutoSMalloc to manage it. - */ - void* get() const { return fPtr; } - - /** - * Return a new block of the requested size, freeing (as necessary) any previously allocated - * block. As with the constructor, if size <= kSizeRequested (or slightly more) then the return - * block may be allocated locally, rather than from the heap. - */ - void* reset(size_t size, - SkAutoMalloc::OnShrink shrink = SkAutoMalloc::kAlloc_OnShrink, - bool* didChangeAlloc = NULL) { - size = (size < kSize) ? kSize : size; - bool alloc = size != fSize && (SkAutoMalloc::kAlloc_OnShrink == shrink || size > fSize); - if (didChangeAlloc) { - *didChangeAlloc = alloc; - } - if (alloc) { - if (fPtr != (void*)fStorage) { - sk_free(fPtr); - } - - if (size == kSize) { - SkASSERT(fPtr != fStorage); // otherwise we lied when setting didChangeAlloc. - fPtr = fStorage; - } else { - fPtr = sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_TEMP); - } - - fSize = size; - } - SkASSERT(fSize >= size && fSize >= kSize); - SkASSERT((fPtr == fStorage) || fSize > kSize); - return fPtr; - } - -private: - // Align up to 32 bits. - static const size_t kSizeAlign4 = SkAlign4(kSizeRequested); -#if defined(GOOGLE3) - // Stack frame size is limited for GOOGLE3. 4k is less than the actual max, but some functions - // have multiple large stack allocations. - static const size_t kMaxBytes = 4 * 1024; - static const size_t kSize = kSizeRequested > kMaxBytes ? kMaxBytes : kSizeAlign4; -#else - static const size_t kSize = kSizeAlign4; -#endif - - void* fPtr; - size_t fSize; // can be larger than the requested size (see kReuse) - uint32_t fStorage[kSize >> 2]; -}; -// Can't guard the constructor because it's a template class. - #endif /* C++ */ #endif diff --git a/gfx/skia/skia/include/core/SkVertices.h b/gfx/skia/skia/include/core/SkVertices.h new file mode 100644 index 000000000000..a245c18502d1 --- /dev/null +++ b/gfx/skia/skia/include/core/SkVertices.h @@ -0,0 +1,139 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkVertices_DEFINED +#define SkVertices_DEFINED + +#include "SkColor.h" +#include "SkData.h" +#include "SkPoint.h" +#include "SkRect.h" +#include "SkRefCnt.h" + +/** + * An immutable set of vertex data that can be used with SkCanvas::drawVertices. + */ +class SkVertices : public SkNVRefCnt { +public: + enum VertexMode { + kTriangles_VertexMode, + kTriangleStrip_VertexMode, + kTriangleFan_VertexMode, + }; + + /** + * Create a vertices by copying the specified arrays. texs and colors may be nullptr, + * and indices is ignored if indexCount == 0. + */ + static sk_sp MakeCopy(VertexMode mode, int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const SkColor colors[], + int indexCount, + const uint16_t indices[]); + + static sk_sp MakeCopy(VertexMode mode, int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const SkColor colors[]) { + return MakeCopy(mode, vertexCount, positions, texs, colors, 0, nullptr); + } + + struct Sizes; + + enum BuilderFlags { + kHasTexCoords_BuilderFlag = 1 << 0, + kHasColors_BuilderFlag = 1 << 1, + }; + class Builder { + public: + Builder(VertexMode mode, int vertexCount, int indexCount, uint32_t flags); + + bool isValid() const { return fVertices != nullptr; } + + // if the builder is invalid, these will return 0 + int vertexCount() const; + int indexCount() const; + SkPoint* positions(); + SkPoint* texCoords(); // returns null if there are no texCoords + SkColor* colors(); // returns null if there are no colors + uint16_t* indices(); // returns null if there are no indices + + // Detach the built vertices object. After the first call, this will always return null. + sk_sp detach(); + + private: + Builder(VertexMode mode, int vertexCount, int indexCount, const Sizes&); + + void init(VertexMode mode, int vertexCount, int indexCount, const Sizes&); + + // holds a partially complete object. only completed in detach() + sk_sp fVertices; + + friend class SkVertices; + }; + + uint32_t uniqueID() const { return fUniqueID; } + VertexMode mode() const { return fMode; } + const SkRect& bounds() const { return fBounds; } + + bool hasColors() const { return SkToBool(this->colors()); } + bool hasTexCoords() const { return SkToBool(this->texCoords()); } + bool hasIndices() const { return SkToBool(this->indices()); } + + int vertexCount() const { return fVertexCnt; } + const SkPoint* positions() const { return fPositions; } + const SkPoint* texCoords() const { return fTexs; } + const SkColor* colors() const { return fColors; } + + int indexCount() const { return fIndexCnt; } + const uint16_t* indices() const { return fIndices; } + + // returns approximate byte size of the vertices object + size_t approximateSize() const; + + /** + * Recreate a vertices from a buffer previously created by calling encode(). + * Returns null if the data is corrupt or the length is incorrect for the contents. + */ + static sk_sp Decode(const void* buffer, size_t length); + + /** + * Pack the vertices object into a byte buffer. This can be used to recreate the vertices + * by calling Decode() with the buffer. + */ + sk_sp encode() const; + +private: + SkVertices() {} + + // these are needed since we've manually sized our allocation (see Builder::init) + friend class SkNVRefCnt; + void operator delete(void* p) { ::operator delete(p); } + + static sk_sp Alloc(int vCount, int iCount, uint32_t builderFlags, + size_t* arraySize); + + // we store this first, to pair with the refcnt in our base-class, so we don't have an + // unnecessary pad between it and the (possibly 8-byte aligned) ptrs. + uint32_t fUniqueID; + + // these point inside our allocation, so none of these can be "freed" + SkPoint* fPositions; + SkPoint* fTexs; + SkColor* fColors; + uint16_t* fIndices; + + SkRect fBounds; // computed to be the union of the fPositions[] + int fVertexCnt; + int fIndexCnt; + + VertexMode fMode; + // below here is where the actual array data is stored. +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkWriteBuffer.h b/gfx/skia/skia/include/core/SkWriteBuffer.h index 29f923fedd18..12d5d3b022b6 100644 --- a/gfx/skia/skia/include/core/SkWriteBuffer.h +++ b/gfx/skia/skia/include/core/SkWriteBuffer.h @@ -81,7 +81,7 @@ public: SkBinaryWriteBuffer(uint32_t flags = 0); SkBinaryWriteBuffer(void* initialStorage, size_t storageSize, uint32_t flags = 0); - ~SkBinaryWriteBuffer(); + ~SkBinaryWriteBuffer() override; bool isCrossProcess() const override { return SkToBool(fFlags & kCrossProcess_Flag); @@ -134,12 +134,10 @@ public: * Set an SkPixelSerializer to store an encoded representation of pixels, * e.g. SkBitmaps. * - * Calls ref() on the serializer. - * * TODO: Encode SkImage pixels as well. */ - void setPixelSerializer(SkPixelSerializer*); - SkPixelSerializer* getPixelSerializer() const { return fPixelSerializer; } + void setPixelSerializer(sk_sp); + SkPixelSerializer* getPixelSerializer() const { return fPixelSerializer.get(); } private: const uint32_t fFlags; @@ -148,7 +146,7 @@ private: SkRefCntSet* fTFSet; - SkAutoTUnref fPixelSerializer; + sk_sp fPixelSerializer; // Only used if we do not have an fFactorySet SkTHashMap fFlattenableDict; diff --git a/gfx/skia/skia/include/core/SkYUVSizeInfo.h b/gfx/skia/skia/include/core/SkYUVSizeInfo.h index 2c5a51d794b0..19b5a8e89c23 100644 --- a/gfx/skia/skia/include/core/SkYUVSizeInfo.h +++ b/gfx/skia/skia/include/core/SkYUVSizeInfo.h @@ -8,6 +8,8 @@ #ifndef SkYUVSizeInfo_DEFINED #define SkYUVSizeInfo_DEFINED +#include "SkSize.h" + struct SkYUVSizeInfo { enum { kY = 0, diff --git a/gfx/skia/skia/include/effects/Sk1DPathEffect.h b/gfx/skia/skia/include/effects/Sk1DPathEffect.h index d5315a8735e5..252326457016 100644 --- a/gfx/skia/skia/include/effects/Sk1DPathEffect.h +++ b/gfx/skia/skia/include/effects/Sk1DPathEffect.h @@ -58,12 +58,6 @@ public: */ static sk_sp Make(const SkPath& path, SkScalar advance, SkScalar phase, Style); -#ifdef SK_SUPPORT_LEGACY_PATHEFFECT_PTR - static SkPathEffect* Create(const SkPath& path, SkScalar advance, SkScalar phase, Style s) { - return Make(path, advance, phase, s).release(); - } -#endif - virtual bool filterPath(SkPath*, const SkPath&, SkStrokeRec*, const SkRect*) const override; diff --git a/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h b/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h index 18b760fc9f81..9bb69f004d1f 100644 --- a/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h +++ b/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h @@ -26,13 +26,6 @@ public: const SkImageFilter::CropRect* cropRect = nullptr); -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(const SkRegion& region, SkScalar innerMin, - SkScalar outerMax, SkImageFilter* input = nullptr) { - return Make(region, innerMin, outerMax, sk_ref_sp(input)).release(); - } -#endif - SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP(); }; diff --git a/gfx/skia/skia/include/effects/SkArithmeticImageFilter.h b/gfx/skia/skia/include/effects/SkArithmeticImageFilter.h new file mode 100644 index 000000000000..ef596030a7e1 --- /dev/null +++ b/gfx/skia/skia/include/effects/SkArithmeticImageFilter.h @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkArithmeticImageFilter_DEFINED +#define SkArithmeticImageFilter_DEFINED + +#include "SkImageFilter.h" + +class SK_API SkArithmeticImageFilter { +public: + static sk_sp Make(float k1, float k2, float k3, float k4, bool enforcePMColor, + sk_sp background, + sk_sp foreground, + const SkImageFilter::CropRect* cropRect); + static sk_sp Make(float k1, float k2, float k3, float k4, bool enforcePMColor, + sk_sp background) { + return Make(k1, k2, k3, k4, enforcePMColor, std::move(background), nullptr, nullptr); + } + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP(); + +private: + SkArithmeticImageFilter(); // can't instantiate +}; + +#endif diff --git a/gfx/skia/skia/include/effects/SkArithmeticMode.h b/gfx/skia/skia/include/effects/SkArithmeticMode.h deleted file mode 100644 index 81b9f85394d0..000000000000 --- a/gfx/skia/skia/include/effects/SkArithmeticMode.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkArithmeticMode_DEFINED -#define SkArithmeticMode_DEFINED - -#include "SkFlattenable.h" -#include "SkScalar.h" -#include "SkXfermode.h" - -#ifdef SK_SUPPORT_LEGACY_ARITHMETICMODE - -class SK_API SkArithmeticMode { -public: - /** - * result = clamp[k1 * src * dst + k2 * src + k3 * dst + k4] - * - * k1=k2=k3=0, k4=1.0 results in returning opaque white - * k1=k3=k4=0, k2=1.0 results in returning the src - * k1=k2=k4=0, k3=1.0 results in returning the dst - */ - static sk_sp Make(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, - bool enforcePMColor = true); -#ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR - static SkXfermode* Create(SkScalar k1, SkScalar k2, - SkScalar k3, SkScalar k4, - bool enforcePMColor = true) { - return Make(k1, k2, k3, k4, enforcePMColor).release(); - } -#endif - - SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP(); - -private: - SkArithmeticMode(); // can't be instantiated -}; - -#endif - -#endif diff --git a/gfx/skia/skia/include/effects/SkBlurDrawLooper.h b/gfx/skia/skia/include/effects/SkBlurDrawLooper.h index 9b87683f0485..45289c8941ee 100644 --- a/gfx/skia/skia/include/effects/SkBlurDrawLooper.h +++ b/gfx/skia/skia/include/effects/SkBlurDrawLooper.h @@ -10,85 +10,13 @@ #define SkBlurDrawLooper_DEFINED #include "SkDrawLooper.h" -#include "SkColor.h" -class SkMaskFilter; -class SkColorFilter; - -/** \class SkBlurDrawLooper - This class draws a shadow of the object (possibly offset), and then draws - the original object in its original position. - should there be an option to just draw the shadow/blur layer? webkit? -*/ -class SK_API SkBlurDrawLooper : public SkDrawLooper { -public: - enum BlurFlags { - kNone_BlurFlag = 0x00, - /** - The blur layer's dx/dy/radius aren't affected by the canvas - transform. - */ - kIgnoreTransform_BlurFlag = 0x01, - kOverrideColor_BlurFlag = 0x02, - kHighQuality_BlurFlag = 0x04, - /** mask for all blur flags */ - kAll_BlurFlag = 0x07 - }; - - static sk_sp Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy, - uint32_t flags = kNone_BlurFlag) { - return sk_sp(new SkBlurDrawLooper(color, sigma, dx, dy, flags)); - } -#ifdef SK_SUPPORT_LEGACY_MINOR_EFFECT_PTR - static SkDrawLooper* Create(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy, - uint32_t flags = kNone_BlurFlag) { - return Make(color, sigma, dx, dy, flags).release(); - } -#endif - - SkDrawLooper::Context* createContext(SkCanvas*, void* storage) const override; - - size_t contextSize() const override { return sizeof(BlurDrawLooperContext); } - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurDrawLooper) - -protected: - SkBlurDrawLooper(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy, - uint32_t flags); - - void flatten(SkWriteBuffer&) const override; - - bool asABlurShadow(BlurShadowRec*) const override; - -private: - sk_sp fBlur; - sk_sp fColorFilter; - SkScalar fDx, fDy, fSigma; - SkColor fBlurColor; - uint32_t fBlurFlags; - - enum State { - kBeforeEdge, - kAfterEdge, - kDone - }; - - class BlurDrawLooperContext : public SkDrawLooper::Context { - public: - explicit BlurDrawLooperContext(const SkBlurDrawLooper* looper); - - bool next(SkCanvas* canvas, SkPaint* paint) override; - - private: - const SkBlurDrawLooper* fLooper; - State fState; - }; - - void init(SkScalar sigma, SkScalar dx, SkScalar dy, SkColor color, uint32_t flags); - void initEffects(); - - typedef SkDrawLooper INHERITED; +/** + * Draws a shadow of the object (possibly offset), and then draws the original object in + * its original position. + */ +namespace SkBlurDrawLooper { + sk_sp Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy); }; #endif diff --git a/gfx/skia/skia/include/effects/SkBlurImageFilter.h b/gfx/skia/skia/include/effects/SkBlurImageFilter.h index e2109d05616a..085a13b5b328 100644 --- a/gfx/skia/skia/include/effects/SkBlurImageFilter.h +++ b/gfx/skia/skia/include/effects/SkBlurImageFilter.h @@ -17,15 +17,6 @@ public: const SkImageFilter::CropRect* cropRect = nullptr) { return SkImageFilter::MakeBlur(sigmaX, sigmaY, input, cropRect); } - -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(SkScalar sigmaX, SkScalar sigmaY, - SkImageFilter * input = nullptr, - const SkImageFilter::CropRect* cropRect = nullptr) { - return SkImageFilter::MakeBlur(sigmaX, sigmaY, sk_ref_sp(input), - cropRect).release(); - } -#endif }; #endif diff --git a/gfx/skia/skia/include/effects/SkBlurMaskFilter.h b/gfx/skia/skia/include/effects/SkBlurMaskFilter.h index dfbae6b689a2..8b032e50ee1b 100644 --- a/gfx/skia/skia/include/effects/SkBlurMaskFilter.h +++ b/gfx/skia/skia/include/effects/SkBlurMaskFilter.h @@ -22,13 +22,13 @@ public: static SkScalar ConvertRadiusToSigma(SkScalar radius); enum BlurFlags { - kNone_BlurFlag = 0x00, + kNone_BlurFlag = 0x00, /** The blur layer's radius is not affected by transforms */ kIgnoreTransform_BlurFlag = 0x01, /** Use a smother, higher qulity blur algorithm */ kHighQuality_BlurFlag = 0x02, /** mask for all blur flags */ - kAll_BlurFlag = 0x03 + kAll_BlurFlag = 0x03 }; /** Create a blur maskfilter. @@ -48,6 +48,7 @@ public: return Make(style, sigma, SkRect::MakeEmpty(), flags); } +#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER /** Create an emboss maskfilter @param blurSigma standard deviation of the Gaussian blur to apply before applying lighting (e.g. 3) @@ -58,19 +59,6 @@ public: */ static sk_sp MakeEmboss(SkScalar blurSigma, const SkScalar direction[3], SkScalar ambient, SkScalar specular); - -#ifdef SK_SUPPORT_LEGACY_MASKFILTER_PTR - static SkMaskFilter* Create(SkBlurStyle style, SkScalar sigma, uint32_t flags = kNone_BlurFlag){ - return Make(style, sigma, flags).release(); - } - static SkMaskFilter* CreateEmboss(SkScalar blurSigma, const SkScalar direction[3], - SkScalar ambient, SkScalar specular) { - return MakeEmboss(blurSigma, direction, ambient, specular).release(); - } - SK_ATTR_DEPRECATED("use sigma version") - static SkMaskFilter* CreateEmboss(const SkScalar direction[3], - SkScalar ambient, SkScalar specular, - SkScalar blurRadius); #endif static const int kMaxDivisions = 6; diff --git a/gfx/skia/skia/include/effects/SkColorCubeFilter.h b/gfx/skia/skia/include/effects/SkColorCubeFilter.h deleted file mode 100644 index fbfe698ba812..000000000000 --- a/gfx/skia/skia/include/effects/SkColorCubeFilter.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkColorCubeFilter_DEFINED -#define SkColorCubeFilter_DEFINED - -#include "SkColorFilter.h" -#include "SkData.h" -#include "../private/SkOnce.h" -#include "../private/SkTemplates.h" - -class SK_API SkColorCubeFilter : public SkColorFilter { -public: - /** cubeData must containt a 3D data in the form of cube of the size: - * cubeDimension * cubeDimension * cubeDimension * sizeof(SkColor) - * This cube contains a transform where (x,y,z) maps to the (r,g,b). - * The alpha components of the colors must be 0xFF. - */ - static sk_sp Make(sk_sp cubeData, int cubeDimension); - -#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR - static SkColorFilter* Create(SkData* cubeData, int cubeDimension); -#endif - - void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override; - uint32_t getFlags() const override; - -#if SK_SUPPORT_GPU - sk_sp asFragmentProcessor(GrContext*) const override; -#endif - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorCubeFilter) - -protected: - SkColorCubeFilter(sk_sp cubeData, int cubeDimension); - void flatten(SkWriteBuffer&) const override; - -private: - /** The cache is initialized on-demand when getProcessingLuts is called. - */ - class ColorCubeProcesingCache { - public: - ColorCubeProcesingCache(int cubeDimension); - - void getProcessingLuts(const int* (*colorToIndex)[2], - const SkScalar* (*colorToFactors)[2], - const SkScalar** colorToScalar); - - int cubeDimension() const { return fCubeDimension; } - - private: - // Working pointers. If any of these is NULL, - // we need to recompute the corresponding cache values. - int* fColorToIndex[2]; - SkScalar* fColorToFactors[2]; - SkScalar* fColorToScalar; - - SkAutoTMalloc fLutStorage; - - const int fCubeDimension; - - // Make sure we only initialize the caches once. - SkOnce fLutsInitOnce; - - static void initProcessingLuts(ColorCubeProcesingCache* cache); - }; - - sk_sp fCubeData; - int32_t fUniqueID; - - mutable ColorCubeProcesingCache fCache; - - typedef SkColorFilter INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h b/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h index 4d438e351972..e9af51c4d99c 100644 --- a/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h +++ b/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h @@ -21,20 +21,11 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorFilterImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(SkColorFilter* cf, - SkImageFilter* input = NULL, - const CropRect* cropRect = NULL) { - return Make(sk_ref_sp(cf), - sk_ref_sp(input), - cropRect).release(); - } -#endif - protected: void flatten(SkWriteBuffer&) const override; sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; bool onIsColorFilterNode(SkColorFilter**) const override; bool onCanHandleComplexCTM() const override { return true; } bool affectsTransparentBlack() const override; diff --git a/gfx/skia/skia/include/effects/SkColorMatrixFilter.h b/gfx/skia/skia/include/effects/SkColorMatrixFilter.h index 6e74bee315c3..c2937176cc83 100644 --- a/gfx/skia/skia/include/effects/SkColorMatrixFilter.h +++ b/gfx/skia/skia/include/effects/SkColorMatrixFilter.h @@ -20,18 +20,6 @@ public: * are ignored. */ static sk_sp MakeLightingFilter(SkColor mul, SkColor add); - -#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR - static SkColorFilter* Create(const SkColorMatrix& cm) { - return SkColorFilter::MakeMatrixFilterRowMajor255(cm.fMat).release(); - } - static SkColorFilter* Create(const SkScalar array[20]) { - return SkColorFilter::MakeMatrixFilterRowMajor255(array).release(); - } - static SkColorFilter* CreateLightingFilter(SkColor mul, SkColor add) { - return MakeLightingFilter(mul, add).release(); - } -#endif }; #endif diff --git a/gfx/skia/skia/include/effects/SkComposeImageFilter.h b/gfx/skia/skia/include/effects/SkComposeImageFilter.h index 378b90471b87..02200117fb3c 100644 --- a/gfx/skia/skia/include/effects/SkComposeImageFilter.h +++ b/gfx/skia/skia/include/effects/SkComposeImageFilter.h @@ -19,13 +19,6 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(SkImageFilter* outer, SkImageFilter* inner) { - return Make(sk_ref_sp(outer), - sk_ref_sp(inner)).release(); - } -#endif - protected: explicit SkComposeImageFilter(sk_sp inputs[2]) : INHERITED(inputs, 2, nullptr) { SkASSERT(inputs[0].get()); @@ -33,6 +26,7 @@ protected: } sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const override; bool onCanHandleComplexCTM() const override { return true; } diff --git a/gfx/skia/skia/include/effects/SkCornerPathEffect.h b/gfx/skia/skia/include/effects/SkCornerPathEffect.h index cf03463530db..c252943fbeb0 100644 --- a/gfx/skia/skia/include/effects/SkCornerPathEffect.h +++ b/gfx/skia/skia/include/effects/SkCornerPathEffect.h @@ -24,12 +24,6 @@ public: return sk_sp(new SkCornerPathEffect(radius)); } -#ifdef SK_SUPPORT_LEGACY_PATHEFFECT_PTR - static SkPathEffect* Create(SkScalar radius) { - return Make(radius).release(); - } -#endif - virtual bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override; @@ -41,7 +35,7 @@ public: #endif protected: - virtual ~SkCornerPathEffect(); + ~SkCornerPathEffect() override; explicit SkCornerPathEffect(SkScalar radius); void flatten(SkWriteBuffer&) const override; diff --git a/gfx/skia/skia/include/effects/SkDashPathEffect.h b/gfx/skia/skia/include/effects/SkDashPathEffect.h index ccb1a4e44073..13cbb4def048 100644 --- a/gfx/skia/skia/include/effects/SkDashPathEffect.h +++ b/gfx/skia/skia/include/effects/SkDashPathEffect.h @@ -38,12 +38,6 @@ public: */ static sk_sp Make(const SkScalar intervals[], int count, SkScalar phase); -#ifdef SK_SUPPORT_LEGACY_PATHEFFECT_PTR - static SkPathEffect* Create(const SkScalar intervals[], int count, SkScalar phase) { - return Make(intervals, count, phase).release(); - } -#endif - virtual bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override; @@ -61,7 +55,7 @@ public: #endif protected: - virtual ~SkDashPathEffect(); + ~SkDashPathEffect() override; SkDashPathEffect(const SkScalar intervals[], int count, SkScalar phase); void flatten(SkWriteBuffer&) const override; diff --git a/gfx/skia/skia/include/effects/SkDiscretePathEffect.h b/gfx/skia/skia/include/effects/SkDiscretePathEffect.h index 78d4516ee6fe..6709676a8bc3 100644 --- a/gfx/skia/skia/include/effects/SkDiscretePathEffect.h +++ b/gfx/skia/skia/include/effects/SkDiscretePathEffect.h @@ -31,12 +31,6 @@ public: */ static sk_sp Make(SkScalar segLength, SkScalar dev, uint32_t seedAssist = 0); -#ifdef SK_SUPPORT_LEGACY_PATHEFFECT_PTR - static SkPathEffect* Create(SkScalar segLength, SkScalar deviation, uint32_t seedAssist = 0) { - return Make(segLength, deviation, seedAssist).release(); - } -#endif - virtual bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override; diff --git a/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h b/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h index f93f2c445481..c5442799f97c 100644 --- a/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h +++ b/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h @@ -35,23 +35,11 @@ public: virtual SkIRect onFilterBounds(const SkIRect& src, const SkMatrix&, MapDirection) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const override; SK_TO_STRING_OVERRIDE() -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(ChannelSelectorType xChannelSelector, - ChannelSelectorType yChannelSelector, - SkScalar scale, SkImageFilter* displacement, - SkImageFilter* color = nullptr, - const CropRect* cropRect = nullptr) { - return Make(xChannelSelector, yChannelSelector, scale, - sk_ref_sp(displacement), - sk_ref_sp(color), - cropRect).release(); - } -#endif - protected: sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; diff --git a/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h b/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h index 87e74068298b..b041c0efc657 100644 --- a/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h +++ b/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h @@ -32,20 +32,11 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDropShadowImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, - SkColor color, ShadowMode shadowMode, - SkImageFilter* input = nullptr, - const CropRect* cropRect = nullptr) { - return Make(dx, dy, sigmaX, sigmaY, color, shadowMode, - sk_ref_sp(input), cropRect).release(); - } -#endif - protected: void flatten(SkWriteBuffer&) const override; sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; SkIRect onFilterNodeBounds(const SkIRect& src, const SkMatrix&, MapDirection) const override; private: diff --git a/gfx/skia/skia/include/effects/SkGammaColorFilter.h b/gfx/skia/skia/include/effects/SkGammaColorFilter.h deleted file mode 100644 index 308926a3ab49..000000000000 --- a/gfx/skia/skia/include/effects/SkGammaColorFilter.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkGammaColorFilter_DEFINED -#define SkGammaColorFilter_DEFINED - -#include "SkColorFilter.h" -#include "SkRefCnt.h" - -// This colorfilter can be used to perform pixel-by-pixel conversion between linear and -// power-law color spaces. A gamma of 2.2 is interpreted to mean convert from sRGB to linear -// while a gamma of 1/2.2 is interpreted to mean convert from linear to sRGB. Any other -// values are just directly applied (i.e., out = in^gamma) -// -// More complicated color space mapping (i.e., ICC profiles) should be handled via the -// SkColorSpace object. -class SK_API SkGammaColorFilter : public SkColorFilter { -public: - static sk_sp Make(SkScalar gamma); - -#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR - static SkColorFilter* Create(SkScalar gamma) { return Make(gamma).release(); } -#endif - - void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override; - -#if SK_SUPPORT_GPU - sk_sp asFragmentProcessor(GrContext*) const override; -#endif - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLumaColorFilter) - -protected: - void flatten(SkWriteBuffer&) const override; - -private: - SkGammaColorFilter(SkScalar gamma); - - SkScalar fGamma; - typedef SkColorFilter INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/effects/SkGradientShader.h b/gfx/skia/skia/include/effects/SkGradientShader.h index 2fcce75c30ec..393749be6554 100644 --- a/gfx/skia/skia/include/effects/SkGradientShader.h +++ b/gfx/skia/skia/include/effects/SkGradientShader.h @@ -198,60 +198,6 @@ public: return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, 0, NULL); } -#ifdef SK_SUPPORT_LEGACY_CREATESHADER_PTR - static SkShader* CreateLinear(const SkPoint pts[2], - const SkColor colors[], const SkScalar pos[], int count, - SkShader::TileMode mode, - uint32_t flags, const SkMatrix* localMatrix) { - return MakeLinear(pts, colors, pos, count, mode, flags, localMatrix).release(); - } - static SkShader* CreateLinear(const SkPoint pts[2], - const SkColor colors[], const SkScalar pos[], int count, - SkShader::TileMode mode) { - return CreateLinear(pts, colors, pos, count, mode, 0, NULL); - } - - static SkShader* CreateRadial(const SkPoint& center, SkScalar radius, - const SkColor colors[], const SkScalar pos[], int count, - SkShader::TileMode mode, - uint32_t flags, const SkMatrix* localMatrix) { - return MakeRadial(center, radius, colors, pos, count, mode, flags, localMatrix).release(); - } - - static SkShader* CreateRadial(const SkPoint& center, SkScalar radius, - const SkColor colors[], const SkScalar pos[], int count, - SkShader::TileMode mode) { - return CreateRadial(center, radius, colors, pos, count, mode, 0, NULL); - } - - static SkShader* CreateTwoPointConical(const SkPoint& start, SkScalar startRadius, - const SkPoint& end, SkScalar endRadius, - const SkColor colors[], const SkScalar pos[], int count, - SkShader::TileMode mode, - uint32_t flags, const SkMatrix* localMatrix) { - return MakeTwoPointConical(start, startRadius, end, endRadius, colors, pos, count, mode, - flags, localMatrix).release(); - } - static SkShader* CreateTwoPointConical(const SkPoint& start, SkScalar startRadius, - const SkPoint& end, SkScalar endRadius, - const SkColor colors[], const SkScalar pos[], int count, - SkShader::TileMode mode) { - return CreateTwoPointConical(start, startRadius, end, endRadius, colors, pos, count, mode, - 0, NULL); - } - - static SkShader* CreateSweep(SkScalar cx, SkScalar cy, - const SkColor colors[], const SkScalar pos[], int count, - uint32_t flags, const SkMatrix* localMatrix) { - return MakeSweep(cx, cy, colors, pos, count, flags, localMatrix).release(); - } - static SkShader* CreateSweep(SkScalar cx, SkScalar cy, - const SkColor colors[], const SkScalar pos[], int count) { - return CreateSweep(cx, cy, colors, pos, count, 0, NULL); - } -#endif - - SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() }; diff --git a/gfx/skia/skia/include/effects/SkHighContrastFilter.h b/gfx/skia/skia/include/effects/SkHighContrastFilter.h new file mode 100644 index 000000000000..2ac37e7975fe --- /dev/null +++ b/gfx/skia/skia/include/effects/SkHighContrastFilter.h @@ -0,0 +1,81 @@ +/* +* Copyright 2017 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#ifndef SkHighContrastFilter_DEFINED +#define SkHighContrastFilter_DEFINED + +#include "SkColorFilter.h" +#include "SkPaint.h" + +/** + * Configuration struct for SkHighContrastFilter. + * + * Provides transformations to improve contrast for users with low vision. + */ +struct SkHighContrastConfig { + enum class InvertStyle { + kNoInvert, + kInvertBrightness, + kInvertLightness, + }; + + SkHighContrastConfig() { + fGrayscale = false; + fInvertStyle = InvertStyle::kNoInvert; + fContrast = 0.0f; + } + + SkHighContrastConfig(bool grayscale, + InvertStyle invertStyle, + SkScalar contrast) + : fGrayscale(grayscale), + fInvertStyle(invertStyle), + fContrast(contrast) {} + + // Returns true if all of the fields are set within the valid range. + bool isValid() const { + return fInvertStyle >= InvertStyle::kNoInvert && + fInvertStyle <= InvertStyle::kInvertLightness && + fContrast >= -1.0 && + fContrast <= 1.0; + } + + // If true, the color will be converted to grayscale. + bool fGrayscale; + + // Whether to invert brightness, lightness, or neither. + InvertStyle fInvertStyle; + + // After grayscale and inverting, the contrast can be adjusted linearly. + // The valid range is -1.0 through 1.0, where 0.0 is no adjustment. + SkScalar fContrast; +}; + +/** + * Color filter that provides transformations to improve contrast + * for users with low vision. + * + * Applies the following transformations in this order. Each of these + * can be configured using SkHighContrastConfig. + * + * - Conversion to grayscale + * - Color inversion (either in RGB or HSL space) + * - Increasing the resulting contrast. + * + * Calling SkHighContrastFilter::Make will return nullptr if the config is + * not valid, e.g. if you try to call it with a contrast outside the range of + * -1.0 to 1.0. + */ +class SK_API SkHighContrastFilter { +public: + // Returns the filter, or nullptr if the config is invalid. + static sk_sp Make(const SkHighContrastConfig& config); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() +}; + +#endif diff --git a/gfx/skia/skia/include/effects/SkImageSource.h b/gfx/skia/skia/include/effects/SkImageSource.h index 4ceff95668ee..04348c68e887 100644 --- a/gfx/skia/skia/include/effects/SkImageSource.h +++ b/gfx/skia/skia/include/effects/SkImageSource.h @@ -24,23 +24,12 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkImageSource) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(SkImage* image) { - return Make(sk_ref_sp(image)).release(); - } - static SkImageFilter* Create(SkImage* image, - const SkRect& srcRect, - const SkRect& dstRect, - SkFilterQuality filterQuality) { - return Make(sk_ref_sp(image), srcRect, dstRect, filterQuality).release(); - } -#endif - protected: void flatten(SkWriteBuffer&) const override; sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; private: explicit SkImageSource(sk_sp); diff --git a/gfx/skia/skia/include/effects/SkLayerDrawLooper.h b/gfx/skia/skia/include/effects/SkLayerDrawLooper.h index 186d44a656d0..f71b93a706b3 100644 --- a/gfx/skia/skia/include/effects/SkLayerDrawLooper.h +++ b/gfx/skia/skia/include/effects/SkLayerDrawLooper.h @@ -11,11 +11,11 @@ #include "SkDrawLooper.h" #include "SkPaint.h" #include "SkPoint.h" -#include "SkXfermode.h" +#include "SkBlendMode.h" class SK_API SkLayerDrawLooper : public SkDrawLooper { public: - virtual ~SkLayerDrawLooper(); + ~SkLayerDrawLooper() override; /** * Bits specifies which aspects of the layer's paint should replace the @@ -51,15 +51,15 @@ public: * The layer's paint's color is treated as the SRC * The draw's paint's color is treated as the DST * final-color = Mode(layers-color, draws-color); - * Any SkXfermode::Mode will work. Two common choices are: - * kSrc_Mode: to use the layer's color, ignoring the draw's - * kDst_Mode: to just keep the draw's color, ignoring the layer's + * Any SkBlendMode will work. Two common choices are: + * kSrc: to use the layer's color, ignoring the draw's + * kDst: to just keep the draw's color, ignoring the layer's */ struct SK_API LayerInfo { - BitFlags fPaintBits; - SkXfermode::Mode fColorMode; - SkVector fOffset; - bool fPostTranslate; //!< applies to fOffset + BitFlags fPaintBits; + SkBlendMode fColorMode; + SkVector fOffset; + bool fPostTranslate; //!< applies to fOffset /** * Initial the LayerInfo. Defaults to settings that will draw the @@ -71,9 +71,7 @@ public: LayerInfo(); }; - SkDrawLooper::Context* createContext(SkCanvas*, void* storage) const override; - - size_t contextSize() const override { return sizeof(LayerDrawLooperContext); } + SkDrawLooper::Context* makeContext(SkCanvas*, SkArenaAlloc*) const override; bool asABlurShadow(BlurShadowRec* rec) const override; @@ -83,6 +81,8 @@ public: static sk_sp CreateProc(SkReadBuffer& buffer); protected: + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + SkLayerDrawLooper(); void flatten(SkWriteBuffer&) const override; @@ -143,11 +143,6 @@ public: * also reset the builder, so it can be used to build another looper. */ sk_sp detach(); -#ifdef SK_SUPPORT_LEGACY_MINOR_EFFECT_PTR - SkLayerDrawLooper* detachLooper() { - return (SkLayerDrawLooper*)this->detach().release(); - } -#endif private: Rec* fRecs; diff --git a/gfx/skia/skia/include/effects/SkLayerRasterizer.h b/gfx/skia/skia/include/effects/SkLayerRasterizer.h index 9ddcd4e6c3f0..7fcfd6b2f0ac 100644 --- a/gfx/skia/skia/include/effects/SkLayerRasterizer.h +++ b/gfx/skia/skia/include/effects/SkLayerRasterizer.h @@ -16,7 +16,7 @@ class SkPaint; class SK_API SkLayerRasterizer : public SkRasterizer { public: - virtual ~SkLayerRasterizer(); + ~SkLayerRasterizer() override; class SK_API Builder { public: @@ -58,15 +58,6 @@ public: */ sk_sp snapshot() const; -#ifdef SK_SUPPORT_LEGACY_MINOR_EFFECT_PTR - SkLayerRasterizer* detachRasterizer() { - return this->detach().release(); - } - SkLayerRasterizer* snapshotRasterizer() const { - return this->snapshot().release(); - } -#endif - private: SkDeque* fLayers; }; diff --git a/gfx/skia/skia/include/effects/SkLightingImageFilter.h b/gfx/skia/skia/include/effects/SkLightingImageFilter.h index 4d4785da2eb6..19aca62bb601 100644 --- a/gfx/skia/skia/include/effects/SkLightingImageFilter.h +++ b/gfx/skia/skia/include/effects/SkLightingImageFilter.h @@ -41,49 +41,6 @@ public: SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* CreateDistantLitDiffuse(const SkPoint3& direction, - SkColor lightColor, SkScalar surfaceScale, SkScalar kd, - SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { - return MakeDistantLitDiffuse(direction, lightColor, surfaceScale, kd, - sk_ref_sp(input), cropRect).release(); - } - static SkImageFilter* CreatePointLitDiffuse(const SkPoint3& location, - SkColor lightColor, SkScalar surfaceScale, SkScalar kd, - SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { - return MakePointLitDiffuse(location, lightColor, surfaceScale, kd, - sk_ref_sp(input), cropRect).release(); - } - static SkImageFilter* CreateSpotLitDiffuse(const SkPoint3& location, - const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, - SkColor lightColor, SkScalar surfaceScale, SkScalar kd, - SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { - return MakeSpotLitDiffuse(location, target, specularExponent, cutoffAngle, - lightColor, surfaceScale, kd, - sk_ref_sp(input), cropRect).release(); - } - static SkImageFilter* CreateDistantLitSpecular(const SkPoint3& direction, - SkColor lightColor, SkScalar surfaceScale, SkScalar ks, - SkScalar shininess, SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { - return MakeDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess, - sk_ref_sp(input), cropRect).release(); - } - static SkImageFilter* CreatePointLitSpecular(const SkPoint3& location, - SkColor lightColor, SkScalar surfaceScale, SkScalar ks, - SkScalar shininess, SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { - return MakePointLitSpecular(location, lightColor, surfaceScale, ks, shininess, - sk_ref_sp(input), cropRect).release(); - } - static SkImageFilter* CreateSpotLitSpecular(const SkPoint3& location, - const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, - SkColor lightColor, SkScalar surfaceScale, SkScalar ks, - SkScalar shininess, SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { - return MakeSpotLitSpecular(location, target, specularExponent, cutoffAngle, - lightColor, surfaceScale, ks, shininess, - sk_ref_sp(input), cropRect).release(); - } -#endif - protected: SkLightingImageFilter(sk_sp light, SkScalar surfaceScale, diff --git a/gfx/skia/skia/include/effects/SkLumaColorFilter.h b/gfx/skia/skia/include/effects/SkLumaColorFilter.h index 1ffaa733b2f3..209394490d22 100644 --- a/gfx/skia/skia/include/effects/SkLumaColorFilter.h +++ b/gfx/skia/skia/include/effects/SkLumaColorFilter.h @@ -11,6 +11,8 @@ #include "SkColorFilter.h" #include "SkRefCnt.h" +class SkRasterPipeline; + /** * Luminance-to-alpha color filter, as defined in * http://www.w3.org/TR/SVG/masking.html#Masking @@ -26,14 +28,10 @@ class SK_API SkLumaColorFilter : public SkColorFilter { public: static sk_sp Make(); -#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR - static SkColorFilter* Create() { return Make().release(); } -#endif - void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override; #if SK_SUPPORT_GPU - sk_sp asFragmentProcessor(GrContext*) const override; + sk_sp asFragmentProcessor(GrContext*, SkColorSpace*) const override; #endif SK_TO_STRING_OVERRIDE() @@ -44,6 +42,8 @@ protected: private: SkLumaColorFilter(); + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + bool shaderIsOpaque) const override; typedef SkColorFilter INHERITED; }; diff --git a/gfx/skia/skia/include/effects/SkMagnifierImageFilter.h b/gfx/skia/skia/include/effects/SkMagnifierImageFilter.h index 6e20297ff4a6..fa9a996298ae 100644 --- a/gfx/skia/skia/include/effects/SkMagnifierImageFilter.h +++ b/gfx/skia/skia/include/effects/SkMagnifierImageFilter.h @@ -14,20 +14,13 @@ class SK_API SkMagnifierImageFilter : public SkImageFilter { public: - static sk_sp Make(const SkRect& src, SkScalar inset, + static sk_sp Make(const SkRect& srcRect, SkScalar inset, sk_sp input, const CropRect* cropRect = nullptr); SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMagnifierImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(const SkRect& src, SkScalar inset, - SkImageFilter* input = nullptr) { - return Make(src, inset, sk_ref_sp(input)).release(); - } -#endif - protected: SkMagnifierImageFilter(const SkRect& srcRect, SkScalar inset, @@ -37,10 +30,12 @@ protected: sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; private: - SkRect fSrcRect; + SkRect fSrcRect; SkScalar fInset; + typedef SkImageFilter INHERITED; }; diff --git a/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h b/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h index 9a45486d8896..5615469e07d2 100644 --- a/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h +++ b/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h @@ -67,21 +67,6 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMatrixConvolutionImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(const SkISize& kernelSize, - const SkScalar* kernel, - SkScalar gain, - SkScalar bias, - const SkIPoint& kernelOffset, - TileMode tileMode, - bool convolveAlpha, - SkImageFilter* input = NULL, - const CropRect* cropRect = NULL) { - return Make(kernelSize, kernel, gain, bias, kernelOffset, tileMode, convolveAlpha, - sk_ref_sp(input), cropRect).release(); - } -#endif - protected: SkMatrixConvolutionImageFilter(const SkISize& kernelSize, const SkScalar* kernel, @@ -96,6 +81,7 @@ protected: sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const override; bool affectsTransparentBlack() const override; diff --git a/gfx/skia/skia/include/effects/SkMergeImageFilter.h b/gfx/skia/skia/include/effects/SkMergeImageFilter.h index 20620d6d7e75..03f0cea4e04b 100644 --- a/gfx/skia/skia/include/effects/SkMergeImageFilter.h +++ b/gfx/skia/skia/include/effects/SkMergeImageFilter.h @@ -8,63 +8,40 @@ #ifndef SkMergeImageFilter_DEFINED #define SkMergeImageFilter_DEFINED +#include "SkBlendMode.h" #include "SkImageFilter.h" -#include "SkXfermode.h" - class SK_API SkMergeImageFilter : public SkImageFilter { public: ~SkMergeImageFilter() override; static sk_sp Make(sk_sp first, sk_sp second, - SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode, - const CropRect* cropRect = nullptr); - static sk_sp Make(sk_sp filters[], - int count, - const SkXfermode::Mode modes[] = nullptr, + SkBlendMode, const CropRect* cropRect = nullptr); + static sk_sp MakeN(sk_sp[], int count, const SkBlendMode[], const CropRect* cropRect = nullptr); SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMergeImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(SkImageFilter* first, SkImageFilter* second, - SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode, - const CropRect* cropRect = nullptr) { - return Make(sk_ref_sp(first), - sk_ref_sp(second), - mode, cropRect).release(); - } - - static SkImageFilter* Create(SkImageFilter* filters[], int count, - const SkXfermode::Mode modes[] = nullptr, - const CropRect* cropRect = nullptr) { - SkAutoTDeleteArray> temp(new sk_sp[count]); - for (int i = 0; i < count; ++i) { - temp[i] = sk_ref_sp(filters[i]); - } - return Make(temp.get(), count, modes, cropRect).release(); - } -#endif - protected: void flatten(SkWriteBuffer&) const override; sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; bool onCanHandleComplexCTM() const override { return true; } private: - SkMergeImageFilter(sk_sp filters[], int count, const SkXfermode::Mode modes[], + SkMergeImageFilter(sk_sp filters[], int count, const SkBlendMode modes[], const CropRect* cropRect); - uint8_t* fModes; // SkXfermode::Mode + uint8_t* fModes; // SkBlendMode // private storage, to avoid dynamically allocating storage for our copy // of the modes (unless the count is so large we can't fit). intptr_t fStorage[16]; void initAllocModes(); - void initModes(const SkXfermode::Mode []); + void initModes(const SkBlendMode[]); typedef SkImageFilter INHERITED; }; diff --git a/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h b/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h index fbbbe207ab02..978509188877 100644 --- a/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h +++ b/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h @@ -42,6 +42,7 @@ protected: sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; void flatten(SkWriteBuffer&) const override; SkISize radius() const { return fRadius; } @@ -62,16 +63,6 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDilateImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(int radiusX, int radiusY, - SkImageFilter* input = nullptr, - const CropRect* cropRect = nullptr) { - return Make(radiusX, radiusY, - sk_ref_sp(input), - cropRect).release(); - } -#endif - protected: Op op() const override { return kDilate_Op; } @@ -94,16 +85,6 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkErodeImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(int radiusX, int radiusY, - SkImageFilter* input = nullptr, - const CropRect* cropRect = nullptr) { - return Make(radiusX, radiusY, - sk_ref_sp(input), - cropRect).release(); - } -#endif - protected: Op op() const override { return kErode_Op; } diff --git a/gfx/skia/skia/include/effects/SkOffsetImageFilter.h b/gfx/skia/skia/include/effects/SkOffsetImageFilter.h index c1005ef78081..5d1f70397b56 100644 --- a/gfx/skia/skia/include/effects/SkOffsetImageFilter.h +++ b/gfx/skia/skia/include/effects/SkOffsetImageFilter.h @@ -22,17 +22,11 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkOffsetImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(SkScalar dx, SkScalar dy, SkImageFilter* input = nullptr, - const CropRect* cropRect = nullptr) { - return Make(dx, dy, sk_ref_sp(input), cropRect).release(); - } -#endif - protected: void flatten(SkWriteBuffer&) const override; sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const override; private: diff --git a/gfx/skia/skia/include/effects/SkPaintImageFilter.h b/gfx/skia/skia/include/effects/SkPaintImageFilter.h index 8a59da6c664f..435b677a72b2 100644 --- a/gfx/skia/skia/include/effects/SkPaintImageFilter.h +++ b/gfx/skia/skia/include/effects/SkPaintImageFilter.h @@ -29,16 +29,11 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPaintImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(const SkPaint& paint, const CropRect* rect = nullptr) { - return Make(paint, rect).release(); - } -#endif - protected: void flatten(SkWriteBuffer&) const override; sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer* xformer) const override; private: SkPaintImageFilter(const SkPaint& paint, const CropRect* rect); diff --git a/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h b/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h index 60dc53a6a2b1..a86c89ba392e 100644 --- a/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h +++ b/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h @@ -62,28 +62,10 @@ public: int numOctaves, SkScalar seed, const SkISize* tileSize = nullptr); -#ifdef SK_SUPPORT_LEGACY_CREATESHADER_PTR - static SkShader* CreateFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, - int numOctaves, SkScalar seed, - const SkISize* tileSize = NULL) { - return MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed, tileSize).release(); - } - static SkShader* CreateTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, - int numOctaves, SkScalar seed, - const SkISize* tileSize = NULL) { - return MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed, tileSize).release(); - } - static SkShader* CreateTubulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, - int numOctaves, SkScalar seed, - const SkISize* tileSize = NULL) { - return CreateTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed, tileSize); - } -#endif - class PerlinNoiseShaderContext : public SkShader::Context { public: PerlinNoiseShaderContext(const SkPerlinNoiseShader& shader, const ContextRec&); - virtual ~PerlinNoiseShaderContext(); + ~PerlinNoiseShaderContext() override; void shadeSpan(int x, int y, SkPMColor[], int count) override; @@ -110,14 +92,13 @@ public: protected: void flatten(SkWriteBuffer&) const override; - Context* onCreateContext(const ContextRec&, void* storage) const override; - size_t onContextSize(const ContextRec&) const override; + Context* onMakeContext(const ContextRec&, SkArenaAlloc* storage) const override; private: SkPerlinNoiseShader(SkPerlinNoiseShader::Type type, SkScalar baseFrequencyX, SkScalar baseFrequencyY, int numOctaves, SkScalar seed, const SkISize* tileSize); - virtual ~SkPerlinNoiseShader(); + ~SkPerlinNoiseShader() override; const SkPerlinNoiseShader::Type fType; const SkScalar fBaseFrequencyX; diff --git a/gfx/skia/skia/include/effects/SkPictureImageFilter.h b/gfx/skia/skia/include/effects/SkPictureImageFilter.h index 2ca1c5b4fde4..2782532ad00c 100644 --- a/gfx/skia/skia/include/effects/SkPictureImageFilter.h +++ b/gfx/skia/skia/include/effects/SkPictureImageFilter.h @@ -35,22 +35,6 @@ public: const SkRect& cropRect, SkFilterQuality filterQuality); -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(const SkPicture* picture) { - return Make(sk_ref_sp(const_cast(picture))).release(); - } - static SkImageFilter* Create(const SkPicture* picture, const SkRect& cropRect) { - return Make(sk_ref_sp(const_cast(picture)), cropRect).release(); - } - static SkImageFilter* CreateForLocalSpace(const SkPicture* picture, - const SkRect& cropRect, - SkFilterQuality filterQuality) { - return MakeForLocalSpace(sk_ref_sp(const_cast(picture)), - cropRect, - filterQuality).release(); - } -#endif - SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPictureImageFilter) diff --git a/gfx/skia/skia/include/effects/SkRRectsGaussianEdgeMaskFilter.h b/gfx/skia/skia/include/effects/SkRRectsGaussianEdgeMaskFilter.h new file mode 100644 index 000000000000..14e17b3deb7a --- /dev/null +++ b/gfx/skia/skia/include/effects/SkRRectsGaussianEdgeMaskFilter.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRRectsGaussianEdgeMaskFilter_DEFINED +#define SkRRectsGaussianEdgeMaskFilter_DEFINED + +#include "SkMaskFilter.h" + +class SkRRect; + +class SK_API SkRRectsGaussianEdgeMaskFilter { +public: + /** Returns a mask filter that applies a Gaussian blur depending on distance to the edge + * of the intersection of two round rects. + * Currently this is only useable with round rects that have the same radii at + * all the corners and for which the x & y radii are equal. + * + * In order to minimize fill the coverage geometry that should be drawn should be no larger + * than the intersection of the bounding boxes of the two round rects. Ambitious users can + * omit the center area of the coverage geometry if it is known to be occluded. + */ + static sk_sp Make(const SkRRect& first, + const SkRRect& second, + SkScalar radius); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() + +private: + SkRRectsGaussianEdgeMaskFilter(); // can't be instantiated +}; + +#endif diff --git a/gfx/skia/skia/include/effects/SkRRectsGaussianEdgeShader.h b/gfx/skia/skia/include/effects/SkRRectsGaussianEdgeShader.h deleted file mode 100644 index 087e7c25f63a..000000000000 --- a/gfx/skia/skia/include/effects/SkRRectsGaussianEdgeShader.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkRRectsGaussianEdgeShader_DEFINED -#define SkRRectsGaussianEdgeShader_DEFINED - -#include "SkShader.h" - -class SkRRect; - -class SK_API SkRRectsGaussianEdgeShader { -public: - /** Returns a shader that applies a Gaussian blur depending on distance to the edge - * of the intersection of two round rects. - * Currently this is only useable with round rects that have the same radii at - * all the corners and for which the x & y radii are equal. - * Raster will draw nothing. - * - * The coverage geometry that should be drawn should be no larger than the intersection - * of the bounding boxes of the two round rects. Ambitious users can omit the center - * area of the coverage geometry if it is known to be occluded. - */ - static sk_sp Make(const SkRRect& first, - const SkRRect& second, - SkScalar radius, SkScalar unused = 0.0f); - - SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() - -private: - SkRRectsGaussianEdgeShader(); // can't be instantiated -}; - -#endif diff --git a/gfx/skia/skia/include/effects/SkTableColorFilter.h b/gfx/skia/skia/include/effects/SkTableColorFilter.h index fe31149464dc..2695f4235761 100644 --- a/gfx/skia/skia/include/effects/SkTableColorFilter.h +++ b/gfx/skia/skia/include/effects/SkTableColorFilter.h @@ -36,18 +36,6 @@ public: const uint8_t tableG[256], const uint8_t tableB[256]); -#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR - static SkColorFilter* Create(const uint8_t table[256]) { - return Make(table).release(); - } - static SkColorFilter* CreateARGB(const uint8_t tableA[256], - const uint8_t tableR[256], - const uint8_t tableG[256], - const uint8_t tableB[256]) { - return MakeARGB(tableA, tableR, tableG, tableB).release(); - } -#endif - SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() }; diff --git a/gfx/skia/skia/include/effects/SkTableMaskFilter.h b/gfx/skia/skia/include/effects/SkTableMaskFilter.h index 757ddf208489..f226dd176014 100644 --- a/gfx/skia/skia/include/effects/SkTableMaskFilter.h +++ b/gfx/skia/skia/include/effects/SkTableMaskFilter.h @@ -50,7 +50,7 @@ public: SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTableMaskFilter) protected: - virtual ~SkTableMaskFilter(); + ~SkTableMaskFilter() override; void flatten(SkWriteBuffer&) const override; diff --git a/gfx/skia/skia/include/effects/SkTileImageFilter.h b/gfx/skia/skia/include/effects/SkTileImageFilter.h index ae951e318b7b..2707741ec89a 100644 --- a/gfx/skia/skia/include/effects/SkTileImageFilter.h +++ b/gfx/skia/skia/include/effects/SkTileImageFilter.h @@ -28,17 +28,12 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTileImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(const SkRect& src, const SkRect& dst, SkImageFilter* input) { - return Make(src, dst, sk_ref_sp(input)).release(); - } -#endif - protected: void flatten(SkWriteBuffer& buffer) const override; sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; private: SkTileImageFilter(const SkRect& srcRect, const SkRect& dstRect, sk_sp input) diff --git a/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h b/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h index fa9c857a7ea3..5e8b587241a8 100644 --- a/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h +++ b/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h @@ -8,15 +8,13 @@ #ifndef SkXfermodeImageFilter_DEFINED #define SkXfermodeImageFilter_DEFINED +#include "SkArithmeticImageFilter.h" #include "SkBlendMode.h" #include "SkImageFilter.h" -class SkXfermode; - /** - * This filter takes an xfermode, and uses it to composite the foreground - * over the background. If foreground or background is NULL, the input - * bitmap (src) is used instead. + * This filter takes a SkBlendMode, and uses it to composite the foreground over the background. + * If foreground or background is NULL, the input bitmap (src) is used instead. */ class SK_API SkXfermodeImageFilter { public: @@ -27,52 +25,21 @@ public: return Make(mode, std::move(background), nullptr, nullptr); } + // Arithmetic image filtering used to be implemented using SkXfermode. Some clients still rely + // on these factories existing in this class. static sk_sp MakeArithmetic(float k1, float k2, float k3, float k4, - bool enforcePMColor, - sk_sp background, + bool enforcePMColor, sk_sp background, sk_sp foreground, - const SkImageFilter::CropRect* cropRect); + const SkImageFilter::CropRect* cropRect) { + return SkArithmeticImageFilter::Make(k1, k2, k3, k4, enforcePMColor, std::move(background), + std::move(foreground), cropRect); + } static sk_sp MakeArithmetic(float k1, float k2, float k3, float k4, bool enforcePMColor, sk_sp background) { - return MakeArithmetic(k1, k2, k3, k4, enforcePMColor, std::move(background), - nullptr, nullptr); + return SkArithmeticImageFilter::Make(k1, k2, k3, k4, enforcePMColor, std::move(background)); } -#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT - static sk_sp Make(sk_sp mode, sk_sp background, - sk_sp foreground, - const SkImageFilter::CropRect* cropRect); - static sk_sp Make(sk_sp mode, sk_sp background) { - return Make(std::move(mode), std::move(background), nullptr, nullptr); - } - -#endif - -#ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR - static SkImageFilter* Create(SkXfermode* mode, SkImageFilter* background, - SkImageFilter* foreground = NULL, - const SkImageFilter::CropRect* cropRect = NULL) { - return Make(sk_ref_sp(mode), - sk_ref_sp(background), - sk_ref_sp(foreground), - cropRect).release(); - } -#endif -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static sk_sp Make(sk_sp mode, SkImageFilter* background, - SkImageFilter* foreground, - const SkImageFilter::CropRect* cropRect) { - return Make(std::move(mode), - sk_ref_sp(background), - sk_ref_sp(foreground), - cropRect); - } - static sk_sp Make(sk_sp mode, SkImageFilter* background) { - return Make(std::move(mode), sk_ref_sp(background)); - } -#endif - SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP(); private: diff --git a/gfx/skia/skia/include/gpu/GrBlend.h b/gfx/skia/skia/include/gpu/GrBlend.h index 5100bb05396b..30b0b9b6e0cb 100644 --- a/gfx/skia/skia/include/gpu/GrBlend.h +++ b/gfx/skia/skia/include/gpu/GrBlend.h @@ -73,121 +73,38 @@ enum GrBlendCoeff { static const int kGrBlendCoeffCnt = kLast_GrBlendCoeff + 1; -/** - * Given a known blend equation in the form of srcCoeff * srcColor + dstCoeff * dstColor where - * there may be partial knowledge of the srcColor and dstColor component values, determine what - * components of the blended output color are known. Coeffs must not refer to the constant or - * secondary src color. - */ -void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff, - GrColor srcColor, - GrColorComponentFlags srcColorFlags, - GrColor dstColor, - GrColorComponentFlags dstColorFlags, - GrColor* outColor, - GrColorComponentFlags* outFlags); - -template -struct GrTBlendCoeffRefsSrc : skstd::bool_constant {}; - -#define GR_BLEND_COEFF_REFS_SRC(COEFF) \ - GrTBlendCoeffRefsSrc::value - -inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) { - switch (coeff) { - case kSC_GrBlendCoeff: - case kISC_GrBlendCoeff: - case kSA_GrBlendCoeff: - case kISA_GrBlendCoeff: - return true; - default: - return false; - } +static constexpr bool GrBlendCoeffRefsSrc(const GrBlendCoeff coeff) { + return kSC_GrBlendCoeff == coeff || kISC_GrBlendCoeff == coeff || kSA_GrBlendCoeff == coeff || + kISA_GrBlendCoeff == coeff; } -template -struct GrTBlendCoeffRefsDst : skstd::bool_constant {}; - -#define GR_BLEND_COEFF_REFS_DST(COEFF) \ - GrTBlendCoeffRefsDst::value - -inline bool GrBlendCoeffRefsDst(GrBlendCoeff coeff) { - switch (coeff) { - case kDC_GrBlendCoeff: - case kIDC_GrBlendCoeff: - case kDA_GrBlendCoeff: - case kIDA_GrBlendCoeff: - return true; - default: - return false; - } +static constexpr bool GrBlendCoeffRefsDst(const GrBlendCoeff coeff) { + return kDC_GrBlendCoeff == coeff || kIDC_GrBlendCoeff == coeff || kDA_GrBlendCoeff == coeff || + kIDA_GrBlendCoeff == coeff; } - -template -struct GrTBlendCoeffRefsSrc2 : skstd::bool_constant {}; - -#define GR_BLEND_COEFF_REFS_SRC2(COEFF) \ - GrTBlendCoeffRefsSrc2::value - -inline bool GrBlendCoeffRefsSrc2(GrBlendCoeff coeff) { - switch (coeff) { - case kS2C_GrBlendCoeff: - case kIS2C_GrBlendCoeff: - case kS2A_GrBlendCoeff: - case kIS2A_GrBlendCoeff: - return true; - default: - return false; - } +static constexpr bool GrBlendCoeffRefsSrc2(const GrBlendCoeff coeff) { + return kS2C_GrBlendCoeff == coeff || kIS2C_GrBlendCoeff == coeff || + kS2A_GrBlendCoeff == coeff || kIS2A_GrBlendCoeff == coeff; } +static constexpr bool GrBlendCoeffsUseSrcColor(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { + return kZero_GrBlendCoeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff); +} -template -struct GrTBlendCoeffsUseSrcColor : skstd::bool_constant {}; +static constexpr bool GrBlendCoeffsUseDstColor(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { + return GrBlendCoeffRefsDst(srcCoeff) || kZero_GrBlendCoeff != dstCoeff; +} -#define GR_BLEND_COEFFS_USE_SRC_COLOR(SRC_COEFF, DST_COEFF) \ - GrTBlendCoeffsUseSrcColor::value - - -template -struct GrTBlendCoeffsUseDstColor : skstd::bool_constant {}; - -#define GR_BLEND_COEFFS_USE_DST_COLOR(SRC_COEFF, DST_COEFF) \ - GrTBlendCoeffsUseDstColor::value - - -template -struct GrTBlendEquationIsAdvanced : skstd::bool_constant= kFirstAdvancedGrBlendEquation> {}; - -#define GR_BLEND_EQUATION_IS_ADVANCED(EQUATION) \ - GrTBlendEquationIsAdvanced::value - -inline bool GrBlendEquationIsAdvanced(GrBlendEquation equation) { +static constexpr bool GrBlendEquationIsAdvanced(GrBlendEquation equation) { return equation >= kFirstAdvancedGrBlendEquation; } - -template -struct GrTBlendModifiesDst : skstd::bool_constant< - (kAdd_GrBlendEquation != BlendEquation && kReverseSubtract_GrBlendEquation != BlendEquation) || - kZero_GrBlendCoeff != SrcCoeff || - kOne_GrBlendCoeff != DstCoeff> {}; - -#define GR_BLEND_MODIFIES_DST(EQUATION, SRC_COEFF, DST_COEFF) \ - GrTBlendModifiesDst::value - +static constexpr bool GrBlendModifiesDst(GrBlendEquation equation, GrBlendCoeff srcCoeff, + GrBlendCoeff dstCoeff) { + return (kAdd_GrBlendEquation != equation && kReverseSubtract_GrBlendEquation != equation) || + kZero_GrBlendCoeff != srcCoeff || kOne_GrBlendCoeff != dstCoeff; +} /** * Advanced blend equations can always tweak alpha for coverage. (See GrCustomXfermode.cpp) @@ -212,17 +129,19 @@ struct GrTBlendModifiesDst : skstd::bool_constant< * * By inspection we can see this will work as long as dstCoeff has a 1, and any other term in * dstCoeff references S. + * + * Moreover, if the blend doesn't modify the dst at all then it is ok to arbitrarily modify the src + * color so folding in coverage is allowed. */ -template -struct GrTBlendCanTweakAlphaForCoverage : skstd::bool_constant< - GR_BLEND_EQUATION_IS_ADVANCED(Equation) || - ((kAdd_GrBlendEquation == Equation || kReverseSubtract_GrBlendEquation == Equation) && - !GR_BLEND_COEFF_REFS_SRC(SrcCoeff) && - (kOne_GrBlendCoeff == DstCoeff || - kISC_GrBlendCoeff == DstCoeff || - kISA_GrBlendCoeff == DstCoeff))> {}; - -#define GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(EQUATION, SRC_COEFF, DST_COEFF) \ - GrTBlendCanTweakAlphaForCoverage::value +static constexpr bool GrBlendAllowsCoverageAsAlpha(GrBlendEquation equation, + GrBlendCoeff srcCoeff, + GrBlendCoeff dstCoeff) { + return GrBlendEquationIsAdvanced(equation) || + !GrBlendModifiesDst(equation, srcCoeff, dstCoeff) || + ((kAdd_GrBlendEquation == equation || kReverseSubtract_GrBlendEquation == equation) && + !GrBlendCoeffRefsSrc(srcCoeff) && + (kOne_GrBlendCoeff == dstCoeff || kISC_GrBlendCoeff == dstCoeff || + kISA_GrBlendCoeff == dstCoeff)); +} #endif diff --git a/gfx/skia/skia/include/gpu/GrBufferAccess.h b/gfx/skia/skia/include/gpu/GrBufferAccess.h deleted file mode 100644 index a5d8f0a684b6..000000000000 --- a/gfx/skia/skia/include/gpu/GrBufferAccess.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrBufferAccess_DEFINED -#define GrBufferAccess_DEFINED - -#include "GrBuffer.h" -#include "GrGpuResourceRef.h" - -/** - * Used to represent a texel buffer that will be read in a GrProcessor. It holds a GrBuffer along - * with an associated offset and texel config. - */ -class GrBufferAccess : public SkNoncopyable { -public: - /** - * Must be initialized before adding to a GrProcessor's buffer access list. - */ - void reset(GrPixelConfig texelConfig, GrBuffer* buffer, - GrShaderFlags visibility = kFragment_GrShaderFlag) { - fTexelConfig = texelConfig; - fBuffer.set(SkRef(buffer), kRead_GrIOType); - fVisibility = visibility; - } - - bool operator==(const GrBufferAccess& that) const { - return fTexelConfig == that.fTexelConfig && - this->buffer() == that.buffer() && - fVisibility == that.fVisibility; - } - - bool operator!=(const GrBufferAccess& that) const { return !(*this == that); } - - GrPixelConfig texelConfig() const { return fTexelConfig; } - GrBuffer* buffer() const { return fBuffer.get(); } - GrShaderFlags visibility() const { return fVisibility; } - - /** - * For internal use by GrProcessor. - */ - const GrGpuResourceRef* getProgramBuffer() const { return &fBuffer;} - -private: - GrPixelConfig fTexelConfig; - GrTGpuResourceRef fBuffer; - GrShaderFlags fVisibility; - - typedef SkNoncopyable INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/gpu/GrCaps.h b/gfx/skia/skia/include/gpu/GrCaps.h index a97be72c3ff5..0d05d4730dc8 100644 --- a/gfx/skia/skia/include/gpu/GrCaps.h +++ b/gfx/skia/skia/include/gpu/GrCaps.h @@ -12,117 +12,12 @@ #include "GrTypesPriv.h" #include "GrBlend.h" #include "GrShaderVar.h" +#include "GrShaderCaps.h" #include "SkRefCnt.h" #include "SkString.h" struct GrContextOptions; - -class GrShaderCaps : public SkRefCnt { -public: - /** Info about shader variable precision within a given shader stage. That is, this info - is relevant to a float (or vecNf) variable declared with a GrSLPrecision - in a given GrShaderType. The info here is hoisted from the OpenGL spec. */ - struct PrecisionInfo { - PrecisionInfo() { - fLogRangeLow = 0; - fLogRangeHigh = 0; - fBits = 0; - } - - /** Is this precision level allowed in the shader stage? */ - bool supported() const { return 0 != fBits; } - - bool operator==(const PrecisionInfo& that) const { - return fLogRangeLow == that.fLogRangeLow && fLogRangeHigh == that.fLogRangeHigh && - fBits == that.fBits; - } - bool operator!=(const PrecisionInfo& that) const { return !(*this == that); } - - /** floor(log2(|min_value|)) */ - int fLogRangeLow; - /** floor(log2(|max_value|)) */ - int fLogRangeHigh; - /** Number of bits of precision. As defined in OpenGL (with names modified to reflect this - struct) : - """ - If the smallest representable value greater than 1 is 1 + e, then fBits will - contain floor(log2(e)), and every value in the range [2^fLogRangeLow, - 2^fLogRangeHigh] can be represented to at least one part in 2^fBits. - """ - */ - int fBits; - }; - - GrShaderCaps(); - - virtual SkString dump() const; - - bool shaderDerivativeSupport() const { return fShaderDerivativeSupport; } - bool geometryShaderSupport() const { return fGeometryShaderSupport; } - bool pathRenderingSupport() const { return fPathRenderingSupport; } - bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; } - bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; } - bool integerSupport() const { return fIntegerSupport; } - bool texelBufferSupport() const { return fTexelBufferSupport; } - - /** - * Get the precision info for a variable of type kFloat_GrSLType, kVec2f_GrSLType, etc in a - * given shader type. If the shader type is not supported or the precision level is not - * supported in that shader type then the returned struct will report false when supported() is - * called. - */ - const PrecisionInfo& getFloatShaderPrecisionInfo(GrShaderType shaderType, - GrSLPrecision precision) const { - return fFloatPrecisions[shaderType][precision]; - } - - /** - * Is there any difference between the float shader variable precision types? If this is true - * then unless the shader type is not supported, any call to getFloatShaderPrecisionInfo() would - * report the same info for all precisions in all shader types. - */ - bool floatPrecisionVaries() const { return fShaderPrecisionVaries; } - - /** - * PLS storage size in bytes (0 when not supported). The PLS spec defines a minimum size of 16 - * bytes whenever PLS is supported. - */ - int pixelLocalStorageSize() const { return fPixelLocalStorageSize; } - - /** - * True if this context supports the necessary extensions and features to enable the PLS path - * renderer. - */ - bool plsPathRenderingSupport() const { -#if GR_ENABLE_PLS_PATH_RENDERING - return fPLSPathRenderingSupport; -#else - return false; -#endif - } - -protected: - /** Subclasses must call this after initialization in order to apply caps overrides requested by - the client. Note that overrides will only reduce the caps never expand them. */ - void applyOptionsOverrides(const GrContextOptions& options); - - bool fShaderDerivativeSupport : 1; - bool fGeometryShaderSupport : 1; - bool fPathRenderingSupport : 1; - bool fDstReadInShaderSupport : 1; - bool fDualSourceBlendingSupport : 1; - bool fIntegerSupport : 1; - bool fTexelBufferSupport : 1; - - bool fShaderPrecisionVaries; - PrecisionInfo fFloatPrecisions[kGrShaderTypeCount][kGrSLPrecisionCount]; - int fPixelLocalStorageSize; - bool fPLSPathRenderingSupport; - -private: - virtual void onApplyOptionsOverrides(const GrContextOptions&) {} - typedef SkRefCnt INHERITED; -}; +class GrRenderTargetProxy; /** * Represents the capabilities of a GrContext. @@ -133,7 +28,7 @@ public: virtual SkString dump() const; - GrShaderCaps* shaderCaps() const { return fShaderCaps; } + const GrShaderCaps* shaderCaps() const { return fShaderCaps.get(); } bool npotTextureTileSupport() const { return fNPOTTextureTileSupport; } /** To avoid as-yet-unnecessary complexity we don't allow any partial support of MIP Maps (e.g. @@ -268,6 +163,7 @@ public: virtual bool isConfigTexturable(GrPixelConfig config) const = 0; virtual bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const = 0; + virtual bool canConfigBeImageStorage(GrPixelConfig config) const = 0; bool suppressPrints() const { return fSuppressPrints; } @@ -287,6 +183,18 @@ public: bool sampleShadingSupport() const { return fSampleShadingSupport; } bool fenceSyncSupport() const { return fFenceSyncSupport; } + bool crossContextTextureSupport() const { return fCrossContextTextureSupport; } + + /** + * This is can be called before allocating a texture to be a dst for copySurface. This is only + * used for doing dst copies needed in blends, thus the src is always a GrRenderTargetProxy. It + * will populate the origin, config, and flags fields of the desc such that copySurface can + * efficiently succeed. rectsMustMatch will be set to true if the copy operation must ensure + * that the src and dest rects are identical. disallowSubrect will be set to true if copy rect + * must equal src's bounds. + */ + virtual bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, + bool* rectsMustMatch, bool* disallowSubrect) const = 0; protected: /** Subclasses must call this at the end of their constructors in order to apply caps @@ -294,7 +202,7 @@ protected: expand them. */ void applyOptionsOverrides(const GrContextOptions& options); - SkAutoTUnref fShaderCaps; + sk_sp fShaderCaps; bool fNPOTTextureTileSupport : 1; bool fMipMapSupport : 1; @@ -329,6 +237,9 @@ protected: // TODO: this may need to be an enum to support different fence types bool fFenceSyncSupport : 1; + // Vulkan doesn't support this (yet) and some drivers have issues, too + bool fCrossContextTextureSupport : 1; + InstancedSupport fInstancedSupport; BlendEquationSupport fBlendEquationSupport; diff --git a/gfx/skia/skia/include/gpu/GrColor.h b/gfx/skia/skia/include/gpu/GrColor.h index f52671732a8e..ad66523bcb96 100644 --- a/gfx/skia/skia/include/gpu/GrColor.h +++ b/gfx/skia/skia/include/gpu/GrColor.h @@ -185,6 +185,24 @@ struct GrColor4f { fRGBA[3] = a; } + enum Illegal_Constructor { + kIllegalConstructor + }; + GrColor4f(Illegal_Constructor) { + fRGBA[0] = SK_FloatNaN; + fRGBA[1] = SK_FloatNaN; + fRGBA[2] = SK_FloatNaN; + fRGBA[3] = SK_FloatNaN; + } + + static GrColor4f OpaqueWhite() { + return GrColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } + + static GrColor4f TransparentBlack() { + return GrColor4f(0.0f, 0.0f, 0.0f, 0.0f); + } + static GrColor4f FromGrColor(GrColor color) { GrColor4f result; GrColorToRGBAFloat(color, result.fRGBA); @@ -195,6 +213,17 @@ struct GrColor4f { return GrColor4f(color.fR, color.fG, color.fB, color.fA); } + GrColor4f modulate(const GrColor4f& x) const { + return GrColor4f(fRGBA[0] * x.fRGBA[0], + fRGBA[1] * x.fRGBA[1], + fRGBA[2] * x.fRGBA[2], + fRGBA[3] * x.fRGBA[3]); + } + + GrColor4f mulByScalar(float x) const { + return GrColor4f(fRGBA[0] * x, fRGBA[1] * x, fRGBA[2] * x, fRGBA[3] * x); + } + bool operator==(const GrColor4f& other) const { return fRGBA[0] == other.fRGBA[0] && @@ -222,10 +251,23 @@ struct GrColor4f { return GrColor4f(fRGBA[0], fRGBA[1], fRGBA[2], 1.0f); } + bool isOpaque() const { + return fRGBA[3] >= 1.f; // just in case precision causes a superopaque value. + } + GrColor4f premul() const { float a = fRGBA[3]; return GrColor4f(fRGBA[0] * a, fRGBA[1] * a, fRGBA[2] * a, a); } + + GrColor4f unpremul() const { + float a = fRGBA[3]; + if (a <= 0.0f) { + return GrColor4f(0.0f, 0.0f, 0.0f, 0.0f); + } + float invAlpha = 1.0f / a; + return GrColor4f(fRGBA[0] * invAlpha, fRGBA[1] * invAlpha, fRGBA[2] * invAlpha, a); + } }; /** @@ -249,61 +291,4 @@ enum GrColorComponentFlags { GR_MAKE_BITFIELD_OPS(GrColorComponentFlags) -static inline char GrColorComponentFlagToChar(GrColorComponentFlags component) { - SkASSERT(SkIsPow2(component)); - switch (component) { - case kR_GrColorComponentFlag: - return 'r'; - case kG_GrColorComponentFlag: - return 'g'; - case kB_GrColorComponentFlag: - return 'b'; - case kA_GrColorComponentFlag: - return 'a'; - default: - SkFAIL("Invalid color component flag."); - return '\0'; - } -} - -static inline uint32_t GrPixelConfigComponentMask(GrPixelConfig config) { - static const uint32_t kFlags[] = { - 0, // kUnknown_GrPixelConfig - kA_GrColorComponentFlag, // kAlpha_8_GrPixelConfig - kRGBA_GrColorComponentFlags, // kIndex_8_GrPixelConfig - kRGB_GrColorComponentFlags, // kRGB_565_GrPixelConfig - kRGBA_GrColorComponentFlags, // kRGBA_4444_GrPixelConfig - kRGBA_GrColorComponentFlags, // kRGBA_8888_GrPixelConfig - kRGBA_GrColorComponentFlags, // kBGRA_8888_GrPixelConfig - kRGBA_GrColorComponentFlags, // kSRGBA_8888_GrPixelConfig - kRGBA_GrColorComponentFlags, // kSBGRA_8888_GrPixelConfig - kRGB_GrColorComponentFlags, // kETC1_GrPixelConfig - kA_GrColorComponentFlag, // kLATC_GrPixelConfig - kA_GrColorComponentFlag, // kR11_EAC_GrPixelConfig - kRGBA_GrColorComponentFlags, // kASTC_12x12_GrPixelConfig - kRGBA_GrColorComponentFlags, // kRGBA_float_GrPixelConfig - kA_GrColorComponentFlag, // kAlpha_16_GrPixelConfig - kRGBA_GrColorComponentFlags, // kRGBA_half_GrPixelConfig - }; - return kFlags[config]; - - GR_STATIC_ASSERT(0 == kUnknown_GrPixelConfig); - GR_STATIC_ASSERT(1 == kAlpha_8_GrPixelConfig); - GR_STATIC_ASSERT(2 == kIndex_8_GrPixelConfig); - GR_STATIC_ASSERT(3 == kRGB_565_GrPixelConfig); - GR_STATIC_ASSERT(4 == kRGBA_4444_GrPixelConfig); - GR_STATIC_ASSERT(5 == kRGBA_8888_GrPixelConfig); - GR_STATIC_ASSERT(6 == kBGRA_8888_GrPixelConfig); - GR_STATIC_ASSERT(7 == kSRGBA_8888_GrPixelConfig); - GR_STATIC_ASSERT(8 == kSBGRA_8888_GrPixelConfig); - GR_STATIC_ASSERT(9 == kETC1_GrPixelConfig); - GR_STATIC_ASSERT(10 == kLATC_GrPixelConfig); - GR_STATIC_ASSERT(11 == kR11_EAC_GrPixelConfig); - GR_STATIC_ASSERT(12 == kASTC_12x12_GrPixelConfig); - GR_STATIC_ASSERT(13 == kRGBA_float_GrPixelConfig); - GR_STATIC_ASSERT(14 == kAlpha_half_GrPixelConfig); - GR_STATIC_ASSERT(15 == kRGBA_half_GrPixelConfig); - GR_STATIC_ASSERT(SK_ARRAY_COUNT(kFlags) == kGrPixelConfigCnt); -} - #endif diff --git a/gfx/skia/skia/include/gpu/GrColorSpaceXform.h b/gfx/skia/skia/include/gpu/GrColorSpaceXform.h index 7c88c628507c..68cd3b0563bc 100644 --- a/gfx/skia/skia/include/gpu/GrColorSpaceXform.h +++ b/gfx/skia/skia/include/gpu/GrColorSpaceXform.h @@ -21,7 +21,7 @@ class GrColorSpaceXform : public SkRefCnt { public: GrColorSpaceXform(const SkMatrix44& srcToDst); - static sk_sp Make(SkColorSpace* src, SkColorSpace* dst); + static sk_sp Make(const SkColorSpace* src, const SkColorSpace* dst); const SkMatrix44& srcToDst() const { return fSrcToDst; } @@ -29,7 +29,7 @@ public: * GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in its * computed key. */ - static uint32_t XformKey(GrColorSpaceXform* xform) { + static uint32_t XformKey(const GrColorSpaceXform* xform) { // Code generation changes if there is an xform, but it otherwise constant return SkToBool(xform) ? 1 : 0; } diff --git a/gfx/skia/skia/include/gpu/GrConfig.h b/gfx/skia/skia/include/gpu/GrConfig.h index acdff3af2bcf..6febd8ac0050 100644 --- a/gfx/skia/skia/include/gpu/GrConfig.h +++ b/gfx/skia/skia/include/gpu/GrConfig.h @@ -173,11 +173,4 @@ typedef unsigned __int64 uint64_t; */ #define GR_STATIC_ASSERT(CONDITION) static_assert(CONDITION, "bug") -/** - * Set to 1 to enable pixel local storage path rendering on supported devices. - */ -#if !defined(GR_ENABLE_PLS_PATH_RENDERING) - #define GR_ENABLE_PLS_PATH_RENDERING 0 -#endif - #endif diff --git a/gfx/skia/skia/include/gpu/GrContext.h b/gfx/skia/skia/include/gpu/GrContext.h index 996b77f2dbf0..d820202ca8cf 100644 --- a/gfx/skia/skia/include/gpu/GrContext.h +++ b/gfx/skia/skia/include/gpu/GrContext.h @@ -9,25 +9,21 @@ #define GrContext_DEFINED #include "GrCaps.h" -#include "GrClip.h" #include "GrColor.h" -#include "GrPaint.h" #include "GrRenderTarget.h" -#include "GrTextureProvider.h" #include "SkMatrix.h" #include "SkPathEffect.h" #include "SkTypes.h" #include "../private/GrAuditTrail.h" #include "../private/GrSingleOwner.h" -#include "../private/SkMutex.h" -struct GrBatchAtlasConfig; -class GrBatchFontCache; +class GrAtlasGlyphCache; struct GrContextOptions; class GrContextPriv; class GrContextThreadSafeProxy; class GrDrawingManager; -class GrDrawContext; +struct GrDrawOpAtlasConfig; +class GrRenderTargetContext; class GrFragmentProcessor; class GrGpu; class GrIndexBuffer; @@ -37,14 +33,18 @@ class GrPipelineBuilder; class GrResourceEntry; class GrResourceCache; class GrResourceProvider; -class GrTestTarget; +class GrSamplerParams; +class GrSurfaceProxy; class GrTextBlobCache; class GrTextContext; -class GrTextureParams; +class GrTextureProxy; class GrVertexBuffer; class GrSwizzle; class SkTraceMemoryDump; +class SkImage; +class SkSurfaceProps; + class SK_API GrContext : public SkRefCnt { public: /** @@ -60,7 +60,7 @@ public: virtual ~GrContext(); - GrContextThreadSafeProxy* threadSafeProxy(); + sk_sp threadSafeProxy(); /** * The GrContext normally assumes that no outsider is setting state @@ -148,9 +148,6 @@ public: */ void setResourceCacheLimits(int maxResources, size_t maxResourceBytes); - GrTextureProvider* textureProvider() { return fTextureProvider; } - const GrTextureProvider* textureProvider() const { return fTextureProvider; } - /** * Frees GPU created by the context. Can be called to reduce GPU memory * pressure. @@ -164,6 +161,12 @@ public: */ void purgeAllUnlockedResources(); + /** + * Purge GPU resources that haven't been used in the past 'ms' milliseconds, regardless of + * whether the context is currently under budget. + */ + void purgeResourcesNotUsedInMs(std::chrono::milliseconds ms); + /** Access the context capabilities */ const GrCaps* caps() const { return fCaps; } @@ -181,32 +184,56 @@ public: int getRecommendedSampleCount(GrPixelConfig config, SkScalar dpi) const; /** - * Create both a GrRenderTarget and a matching GrDrawContext to wrap it. - * We guarantee that "asTexture" will succeed for drawContexts created + * Create both a GrRenderTarget and a matching GrRenderTargetContext to wrap it. + * We guarantee that "asTexture" will succeed for renderTargetContexts created * via this entry point. */ - sk_sp makeDrawContext(SkBackingFit fit, - int width, int height, - GrPixelConfig config, - sk_sp colorSpace, - int sampleCnt = 0, - GrSurfaceOrigin origin = kDefault_GrSurfaceOrigin, - const SkSurfaceProps* surfaceProps = nullptr, - SkBudgeted = SkBudgeted::kYes); - - /* - * This method will attempt to create a drawContext that has, at least, the number of - * channels and precision per channel as requested in 'config' (e.g., A8 and 888 can be - * converted to 8888). It may also swizzle the channels (e.g., BGRA -> RGBA). - * SRGB-ness will be preserved. - */ - sk_sp makeDrawContextWithFallback( + sk_sp makeRenderTargetContext( SkBackingFit fit, int width, int height, GrPixelConfig config, sk_sp colorSpace, int sampleCnt = 0, - GrSurfaceOrigin origin = kDefault_GrSurfaceOrigin, + GrSurfaceOrigin origin = kBottomLeft_GrSurfaceOrigin, + const SkSurfaceProps* surfaceProps = nullptr, + SkBudgeted = SkBudgeted::kYes); + + // Create a new render target context as above but have it backed by a deferred-style + // GrRenderTargetProxy rather than one that is backed by an actual GrRenderTarget + sk_sp makeDeferredRenderTargetContext( + SkBackingFit fit, + int width, int height, + GrPixelConfig config, + sk_sp colorSpace, + int sampleCnt = 0, + GrSurfaceOrigin origin = kBottomLeft_GrSurfaceOrigin, + const SkSurfaceProps* surfaceProps = nullptr, + SkBudgeted = SkBudgeted::kYes); + /* + * This method will attempt to create a renderTargetContext that has, at least, the number of + * channels and precision per channel as requested in 'config' (e.g., A8 and 888 can be + * converted to 8888). It may also swizzle the channels (e.g., BGRA -> RGBA). + * SRGB-ness will be preserved. + */ + sk_sp makeRenderTargetContextWithFallback( + SkBackingFit fit, + int width, int height, + GrPixelConfig config, + sk_sp colorSpace, + int sampleCnt = 0, + GrSurfaceOrigin origin = kBottomLeft_GrSurfaceOrigin, + const SkSurfaceProps* surfaceProps = nullptr, + SkBudgeted budgeted = SkBudgeted::kYes); + + // Create a new render target context as above but have it backed by a deferred-style + // GrRenderTargetProxy rather than one that is backed by an actual GrRenderTarget + sk_sp makeDeferredRenderTargetContextWithFallback( + SkBackingFit fit, + int width, int height, + GrPixelConfig config, + sk_sp colorSpace, + int sampleCnt = 0, + GrSurfaceOrigin origin = kBottomLeft_GrSurfaceOrigin, const SkSurfaceProps* surfaceProps = nullptr, SkBudgeted budgeted = SkBudgeted::kYes); @@ -219,104 +246,6 @@ public: */ void flush(); - /** - * These flags can be used with the read/write pixels functions below. - */ - enum PixelOpsFlags { - /** The GrContext will not be flushed before the surface read or write. This means that - the read or write may occur before previous draws have executed. */ - kDontFlush_PixelOpsFlag = 0x1, - /** Any surface writes should be flushed to the backend 3D API after the surface operation - is complete */ - kFlushWrites_PixelOp = 0x2, - /** The src for write or dst read is unpremultiplied. This is only respected if both the - config src and dst configs are an RGBA/BGRA 8888 format. */ - kUnpremul_PixelOpsFlag = 0x4, - }; - - /** - * Reads a rectangle of pixels from a surface. - * @param surface the surface to read from. - * @param left left edge of the rectangle to read (inclusive) - * @param top top edge of the rectangle to read (inclusive) - * @param width width of rectangle to read in pixels. - * @param height height of rectangle to read in pixels. - * @param config the pixel config of the destination buffer - * @param buffer memory to read the rectangle into. - * @param rowBytes number of bytes bewtween consecutive rows. Zero means rows are tightly - * packed. - * @param pixelOpsFlags see PixelOpsFlags enum above. - * - * @return true if the read succeeded, false if not. The read can fail because of an unsupported - * pixel configs - */ - bool readSurfacePixels(GrSurface* surface, - int left, int top, int width, int height, - GrPixelConfig config, void* buffer, - size_t rowBytes = 0, - uint32_t pixelOpsFlags = 0); - - /** - * Writes a rectangle of pixels to a surface. - * @param surface the surface to write to. - * @param left left edge of the rectangle to write (inclusive) - * @param top top edge of the rectangle to write (inclusive) - * @param width width of rectangle to write in pixels. - * @param height height of rectangle to write in pixels. - * @param config the pixel config of the source buffer - * @param buffer memory to read pixels from - * @param rowBytes number of bytes between consecutive rows. Zero - * means rows are tightly packed. - * @param pixelOpsFlags see PixelOpsFlags enum above. - * @return true if the write succeeded, false if not. The write can fail because of an - * unsupported combination of surface and src configs. - */ - bool writeSurfacePixels(GrSurface* surface, - int left, int top, int width, int height, - GrPixelConfig config, const void* buffer, - size_t rowBytes, - uint32_t pixelOpsFlags = 0); - - /** - * Copies a rectangle of texels from src to dst. - * @param dst the surface to copy to. - * @param src the surface to copy from. - * @param srcRect the rectangle of the src that should be copied. - * @param dstPoint the translation applied when writing the srcRect's pixels to the dst. - */ - bool copySurface(GrSurface* dst, - GrSurface* src, - const SkIRect& srcRect, - const SkIPoint& dstPoint); - - /** Helper that copies the whole surface but fails when the two surfaces are not identically - sized. */ - bool copySurface(GrSurface* dst, GrSurface* src) { - return this->copySurface(dst, src, SkIRect::MakeWH(dst->width(), dst->height()), - SkIPoint::Make(0,0)); - } - - /** - * After this returns any pending writes to the surface will have been issued to the backend 3D API. - */ - void flushSurfaceWrites(GrSurface* surface); - - /** - * After this returns any pending reads or writes to the surface will have been issued to the - * backend 3D API. - */ - void flushSurfaceIO(GrSurface* surface); - - /** - * Finalizes all pending reads and writes to the surface and also performs an MSAA resolve - * if necessary. - * - * It is not necessary to call this before reading the render target via Skia/GrContext. - * GrContext will detect when it must perform a resolve before reading pixels back from the - * surface or using it as a texture. - */ - void prepareSurfaceForExternalIO(GrSurface*); - /** * An ID associated with this context, guaranteed to be unique. */ @@ -326,16 +255,13 @@ public: // Functions intended for internal use only. GrGpu* getGpu() { return fGpu; } const GrGpu* getGpu() const { return fGpu; } - GrBatchFontCache* getBatchFontCache() { return fBatchFontCache; } - GrTextBlobCache* getTextBlobCache() { return fTextBlobCache; } + GrAtlasGlyphCache* getAtlasGlyphCache() { return fAtlasGlyphCache; } + GrTextBlobCache* getTextBlobCache() { return fTextBlobCache.get(); } bool abandoned() const; GrResourceProvider* resourceProvider() { return fResourceProvider; } const GrResourceProvider* resourceProvider() const { return fResourceProvider; } GrResourceCache* getResourceCache() { return fResourceCache; } - // Called by tests that draw directly to the context via GrDrawContext - void getTestTarget(GrTestTarget*, sk_sp); - /** Reset GPU stats */ void resetGpuStats() const ; @@ -355,13 +281,15 @@ public: /** Specify the sizes of the GrAtlasTextContext atlases. The configs pointer below should be to an array of 3 entries */ - void setTextContextAtlasSizes_ForTesting(const GrBatchAtlasConfig* configs); + void setTextContextAtlasSizes_ForTesting(const GrDrawOpAtlasConfig* configs); /** Enumerates all cached GPU resources and dumps their memory to traceMemoryDump. */ void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; - /** Get pointer to atlas texture for given mask format */ - GrTexture* getFontAtlasTexture(GrMaskFormat format); + /** Get pointer to atlas texture for given mask format. Note that this wraps an + actively mutating texture in an SkImage. This could yield unexpected results + if it gets cached or used more generally. */ + sk_sp getFontAtlasImage_ForTesting(GrMaskFormat format); GrAuditTrail* getAuditTrail() { return &fAuditTrail; } @@ -376,37 +304,21 @@ private: GrGpu* fGpu; const GrCaps* fCaps; GrResourceCache* fResourceCache; - // this union exists because the inheritance of GrTextureProvider->GrResourceProvider - // is in a private header. - union { - GrResourceProvider* fResourceProvider; - GrTextureProvider* fTextureProvider; - }; + GrResourceProvider* fResourceProvider; - SkAutoTUnref fThreadSafeProxy; + sk_sp fThreadSafeProxy; - GrBatchFontCache* fBatchFontCache; - SkAutoTDelete fTextBlobCache; + GrAtlasGlyphCache* fAtlasGlyphCache; + std::unique_ptr fTextBlobCache; + bool fDisableGpuYUVConversion; bool fDidTestPMConversions; int fPMToUPMConversion; int fUPMToPMConversion; - // The sw backend may call GrContext::readSurfacePixels on multiple threads - // We may transfer the responsibilty for using a mutex to the sw backend - // when there are fewer code paths that lead to a readSurfacePixels call - // from the sw backend. readSurfacePixels is reentrant in one case - when performing - // the PM conversions test. To handle this we do the PM conversions test outside - // of fReadPixelsMutex and use a separate mutex to guard it. When it re-enters - // readSurfacePixels it will grab fReadPixelsMutex and release it before the outer - // readSurfacePixels proceeds to grab it. - // TODO: Stop pretending to make GrContext thread-safe for sw rasterization and provide - // a mechanism to make a SkPicture safe for multithreaded sw rasterization. - SkMutex fReadPixelsMutex; - SkMutex fTestPMConversionsMutex; // In debug builds we guard against improper thread handling // This guard is passed to the GrDrawingManager and, from there to all the - // GrDrawContexts. It is also passed to the GrTextureProvider and SkGpuDevice. + // GrRenderTargetContexts. It is also passed to the GrResourceProvider and SkGpuDevice. mutable GrSingleOwner fSingleOwner; struct CleanUpData { @@ -418,11 +330,11 @@ private: const uint32_t fUniqueID; - SkAutoTDelete fDrawingManager; + std::unique_ptr fDrawingManager; GrAuditTrail fAuditTrail; - // TODO: have the GrClipStackClip use drawContexts and rm this friending + // TODO: have the GrClipStackClip use renderTargetContexts and rm this friending friend class GrContextPriv; GrContext(); // init must be called after the constructor. @@ -436,17 +348,14 @@ private: * of effects that make a readToUPM->writeToPM->readToUPM cycle invariant. Otherwise, they * return NULL. They also can perform a swizzle as part of the draw. */ - sk_sp createPMToUPMEffect(GrTexture*, const GrSwizzle&, - const SkMatrix&) const; - sk_sp createUPMToPMEffect(GrTexture*, const GrSwizzle&, - const SkMatrix&) const; + sk_sp createPMToUPMEffect(sk_sp, GrPixelConfig); + sk_sp createUPMToPMEffect(sk_sp, GrPixelConfig); /** Called before either of the above two functions to determine the appropriate fragment - processors for conversions. This must be called by readSurfacePixels before a mutex is - taken, since testingvPM conversions itself will call readSurfacePixels */ + processors for conversions. */ void testPMConversionsIfNecessary(uint32_t flags); - /** Returns true if we've already determined that createPMtoUPMEffect and createUPMToPMEffect - will fail. In such cases fall back to SW conversion. */ - bool didFailPMUPMConversionTest() const; + /** Returns true if we've determined that createPMtoUPMEffect and createUPMToPMEffect will + succeed for the passed in config. Otherwise we fall back to SW conversion. */ + bool validPMUPMConversionExists(GrPixelConfig) const; /** * A callback similar to the above for use by the TextBlobCache @@ -463,12 +372,12 @@ private: */ class GrContextThreadSafeProxy : public SkRefCnt { private: - GrContextThreadSafeProxy(const GrCaps* caps, uint32_t uniqueID) - : fCaps(SkRef(caps)) + GrContextThreadSafeProxy(sk_sp caps, uint32_t uniqueID) + : fCaps(std::move(caps)) , fContextUniqueID(uniqueID) {} - SkAutoTUnref fCaps; - uint32_t fContextUniqueID; + sk_sp fCaps; + uint32_t fContextUniqueID; friend class GrContext; friend class SkImage; diff --git a/gfx/skia/skia/include/gpu/GrContextOptions.h b/gfx/skia/skia/include/gpu/GrContextOptions.h index 0522b9d20bc5..8b61c9c1bcd5 100644 --- a/gfx/skia/skia/include/gpu/GrContextOptions.h +++ b/gfx/skia/skia/include/gpu/GrContextOptions.h @@ -9,6 +9,7 @@ #define GrContextOptions_DEFINED #include "SkTypes.h" +#include "GrTypes.h" struct GrContextOptions { GrContextOptions() {} @@ -39,19 +40,10 @@ struct GrContextOptions { immediately. Intended to ease debugging. */ bool fImmediateMode = false; - /** For debugging purposes turn each GrBatch's bounds into a clip rect. This is used to - verify that the clip bounds are conservative. */ - bool fClipBatchToBounds = false; - - /** For debugging purposes draw a wireframe device bounds rect for each GrBatch. The wire - frame rect is draw before the GrBatch in order to visualize batches that draw outside - of their dev bounds. */ - bool fDrawBatchBounds = false; - - /** For debugging, override the default maximum look-back or look-ahead window for GrBatch + /** For debugging, override the default maximum look-back or look-ahead window for GrOp combining. */ - int fMaxBatchLookback = -1; - int fMaxBatchLookahead = -1; + int fMaxOpCombineLookback = -1; + int fMaxOpCombineLookahead = -1; /** Force us to do all swizzling manually in the shader and don't rely on extensions to do swizzling. */ @@ -66,10 +58,6 @@ struct GrContextOptions { Instanced rendering is still experimental at this point and disabled by default. */ bool fEnableInstancedRendering = false; - /** Disables distance field rendering for paths. Distance field computation can be expensive - and yields no benefit if a path is not rendered multiple times with different transforms */ - bool fDisableDistanceFieldPaths = false; - /** * If true this allows path mask textures to be cached. This is only really useful if paths * are commonly rendered at the same scale and fractional translation. @@ -77,11 +65,48 @@ struct GrContextOptions { bool fAllowPathMaskCaching = false; /** - * Force all path draws to go through through the sw-rasterize-to-texture code path (assuming - * the path is not recognized as a simpler shape (e.g. a rrect). This is intended for testing - * purposes. + * If true, sRGB support will not be enabled unless sRGB decoding can be disabled (via an + * extension). If mixed use of "legacy" mode and sRGB/color-correct mode is not required, this + * can be set to false, which will significantly expand the number of devices that qualify for + * sRGB support. */ - bool fForceSWPathMasks = false; + bool fRequireDecodeDisableForSRGB = true; + + /** + * If true, the GPU will not be used to perform YUV -> RGB conversion when generating + * textures from codec-backed images. + */ + bool fDisableGpuYUVConversion = false; + + /** + * If true, the caps will never report driver support for path rendering. + */ + bool fSuppressPathRendering = false; + + /** + * Allows the client to include or exclude specific GPU path renderers. + */ + enum class GpuPathRenderers { + kNone = 0, // Always use sofware masks. + kDashLine = 1 << 0, + kStencilAndCover = 1 << 1, + kMSAA = 1 << 2, + kAAHairline = 1 << 3, + kAAConvex = 1 << 4, + kAALinearizing = 1 << 5, + kSmall = 1 << 6, + kTessellating = 1 << 7, + kDefault = 1 << 8, + + kAll = kDefault | (kDefault - 1), + + // For legacy. To be removed when updated in Android. + kDistanceField = kSmall + }; + + GpuPathRenderers fGpuPathRenderers = GpuPathRenderers::kAll; }; +GR_MAKE_BITFIELD_CLASS_OPS(GrContextOptions::GpuPathRenderers) + #endif diff --git a/gfx/skia/skia/include/gpu/GrCoordTransform.h b/gfx/skia/skia/include/gpu/GrCoordTransform.h index 3080523ebdcf..54c21b7472a3 100644 --- a/gfx/skia/skia/include/gpu/GrCoordTransform.h +++ b/gfx/skia/skia/include/gpu/GrCoordTransform.h @@ -8,11 +8,11 @@ #ifndef GrCoordTransform_DEFINED #define GrCoordTransform_DEFINED -#include "GrProcessor.h" #include "SkMatrix.h" #include "GrTexture.h" -#include "GrTypes.h" -#include "GrShaderVar.h" + +class GrResourceProvider; +class GrTextureProxy; /** * A class representing a linear transformation of local coordinates. GrFragnentProcessors @@ -20,52 +20,58 @@ */ class GrCoordTransform : SkNoncopyable { public: - GrCoordTransform() { SkDEBUGCODE(fInProcessor = false); } - - /** - * Create a transformation that maps [0, 1] to a texture's boundaries. The precision is inferred - * from the texture size and filter. The texture origin also implies whether a y-reversal should - * be performed. - */ - GrCoordTransform(const GrTexture* texture, GrTextureParams::FilterMode filter) { - SkASSERT(texture); + GrCoordTransform() + : fTexture(nullptr) + , fNormalize(false) + , fReverseY(false) { SkDEBUGCODE(fInProcessor = false); - this->reset(texture, filter); } /** - * Create a transformation from a matrix. The precision is inferred from the texture size and - * filter. The texture origin also implies whether a y-reversal should be performed. + * Create a transformation that maps [0, 1] to a proxy's boundaries. The proxy origin also + * implies whether a y-reversal should be performed. */ - GrCoordTransform(const SkMatrix& m, const GrTexture* texture, - GrTextureParams::FilterMode filter) { + GrCoordTransform(GrResourceProvider* resourceProvider, GrTextureProxy* proxy) { + SkASSERT(proxy); SkDEBUGCODE(fInProcessor = false); - SkASSERT(texture); - this->reset(m, texture, filter); + this->reset(resourceProvider, SkMatrix::I(), proxy); + } + + /** + * Create a transformation from a matrix. The proxy origin also implies whether a y-reversal + * should be performed. + */ + GrCoordTransform(GrResourceProvider* resourceProvider, const SkMatrix& m, + GrTextureProxy* proxy) { + SkASSERT(proxy); + SkDEBUGCODE(fInProcessor = false); + this->reset(resourceProvider, m, proxy); } /** * Create a transformation that applies the matrix to a coord set. */ - GrCoordTransform(const SkMatrix& m, GrSLPrecision precision = kDefault_GrSLPrecision) { + GrCoordTransform(const SkMatrix& m) { SkDEBUGCODE(fInProcessor = false); - this->reset(m, precision); + this->reset(m); } - void reset(const GrTexture* texture, GrTextureParams::FilterMode filter) { + void reset(GrResourceProvider*, const SkMatrix&, GrTextureProxy*, bool normalize = true); + + void reset(const SkMatrix& m) { SkASSERT(!fInProcessor); - SkASSERT(texture); - this->reset(MakeDivByTextureWHMatrix(texture), texture, filter); + fMatrix = m; + fTexture = nullptr; + fNormalize = false; + fReverseY = false; } - void reset(const SkMatrix&, const GrTexture*, GrTextureParams::FilterMode filter); - void reset(const SkMatrix& m, GrSLPrecision precision = kDefault_GrSLPrecision); - GrCoordTransform& operator= (const GrCoordTransform& that) { SkASSERT(!fInProcessor); fMatrix = that.fMatrix; + fTexture = that.fTexture; + fNormalize = that.fNormalize; fReverseY = that.fReverseY; - fPrecision = that.fPrecision; return *this; } @@ -78,31 +84,37 @@ public: return &fMatrix; } - bool operator==(const GrCoordTransform& that) const { - return fMatrix.cheapEqualTo(that.fMatrix) && - fReverseY == that.fReverseY && - fPrecision == that.fPrecision; - } + bool hasSameEffectAs(const GrCoordTransform& that) const { + if (fNormalize != that.fNormalize || + fReverseY != that.fReverseY || + !fMatrix.cheapEqualTo(that.fMatrix)) { + return false; + } - bool operator!=(const GrCoordTransform& that) const { return !(*this == that); } + if (fNormalize) { + SkASSERT(fTexture && that.fTexture); + return fTexture->width() == that.fTexture->width() && + fTexture->height() == that.fTexture->height(); + } + + return true; + } const SkMatrix& getMatrix() const { return fMatrix; } + const GrTexture* texture() const { return fTexture; } + bool normalize() const { return fNormalize; } bool reverseY() const { return fReverseY; } - GrSLPrecision precision() const { return fPrecision; } - - /** Useful for effects that want to insert a texture matrix that is implied by the texture - dimensions */ - static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) { - SkASSERT(texture); - SkMatrix mat; - (void)mat.setIDiv(texture->width(), texture->height()); - return mat; - } private: + // The textures' effect is to optionally normalize the final matrix, so a blind + // equality check could be misleading + bool operator==(const GrCoordTransform& that) const; + bool operator!=(const GrCoordTransform& that) const; + SkMatrix fMatrix; + const GrTexture* fTexture; + bool fNormalize; bool fReverseY; - GrSLPrecision fPrecision; typedef SkNoncopyable INHERITED; #ifdef SK_DEBUG diff --git a/gfx/skia/skia/include/gpu/GrDrawContext.h b/gfx/skia/skia/include/gpu/GrDrawContext.h deleted file mode 100644 index 72de15deae60..000000000000 --- a/gfx/skia/skia/include/gpu/GrDrawContext.h +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrDrawContext_DEFINED -#define GrDrawContext_DEFINED - -#include "GrColor.h" -#include "GrContext.h" -#include "GrPaint.h" -#include "GrRenderTarget.h" -#include "SkRefCnt.h" -#include "SkRegion.h" -#include "SkSurfaceProps.h" -#include "../private/GrInstancedPipelineInfo.h" -#include "../private/GrSingleOwner.h" - -class GrAuditTrail; -class GrClip; -class GrDrawBatch; -class GrDrawContextPriv; -class GrDrawPathBatchBase; -class GrDrawingManager; -class GrDrawTarget; -class GrFixedClip; -class GrPaint; -class GrPathProcessor; -class GrPipelineBuilder; -class GrRenderTarget; -class GrStyle; -class GrSurface; -struct GrUserStencilSettings; -class SkDrawFilter; -struct SkIPoint; -struct SkIRect; -class SkLatticeIter; -class SkMatrix; -class SkPaint; -class SkPath; -struct SkPoint; -struct SkRect; -class SkRRect; -struct SkRSXform; -class SkTextBlob; - -/* - * A helper object to orchestrate draws - */ -class SK_API GrDrawContext : public SkRefCnt { -public: - ~GrDrawContext() override; - - bool copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint); - - // TODO: it is odd that we need both the SkPaint in the following 3 methods. - // We should extract the text parameters from SkPaint and pass them separately - // akin to GrStyle (GrTextInfo?) - virtual void drawText(const GrClip&, const GrPaint&, const SkPaint&, - const SkMatrix& viewMatrix, const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkIRect& clipBounds); - virtual void drawPosText(const GrClip&, const GrPaint&, const SkPaint&, - const SkMatrix& viewMatrix, const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkIRect& clipBounds); - virtual void drawTextBlob(const GrClip&, const SkPaint&, - const SkMatrix& viewMatrix, const SkTextBlob*, - SkScalar x, SkScalar y, - SkDrawFilter*, const SkIRect& clipBounds); - - /** - * Provides a perfomance hint that the render target's contents are allowed - * to become undefined. - */ - void discard(); - - /** - * Clear the entire or rect of the render target, ignoring any clips. - * @param rect the rect to clear or the whole thing if rect is NULL. - * @param color the color to clear to. - * @param canIgnoreRect allows partial clears to be converted to whole - * clears on platforms for which that is cheap - */ - void clear(const SkIRect* rect, GrColor color, bool canIgnoreRect); - - /** - * Draw everywhere (respecting the clip) with the paint. - */ - void drawPaint(const GrClip&, const GrPaint&, const SkMatrix& viewMatrix); - - /** - * Draw the rect using a paint. - * @param paint describes how to color pixels. - * @param viewMatrix transformation matrix - * @param style The style to apply. Null means fill. Currently path effects are not - * allowed. - * The rects coords are used to access the paint (through texture matrix) - */ - void drawRect(const GrClip&, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect&, - const GrStyle* style = nullptr); - - /** - * Maps a rectangle of shader coordinates to a rectangle and fills that rectangle. - * - * @param paint describes how to color pixels. - * @param viewMatrix transformation matrix which applies to rectToDraw - * @param rectToDraw the rectangle to draw - * @param localRect the rectangle of shader coordinates applied to rectToDraw - */ - void fillRectToRect(const GrClip&, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& rectToDraw, - const SkRect& localRect); - - /** - * Fills a rect with a paint and a localMatrix. - */ - void fillRectWithLocalMatrix(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkMatrix& localMatrix); - - /** - * Draw a roundrect using a paint. - * - * @param paint describes how to color pixels. - * @param viewMatrix transformation matrix - * @param rrect the roundrect to draw - * @param style style to apply to the rrect. Currently path effects are not allowed. - */ - void drawRRect(const GrClip&, - const GrPaint&, - const SkMatrix& viewMatrix, - const SkRRect& rrect, - const GrStyle& style); - - /** - * Shortcut for drawing an SkPath consisting of nested rrects using a paint. - * Does not support stroking. The result is undefined if outer does not contain - * inner. - * - * @param paint describes how to color pixels. - * @param viewMatrix transformation matrix - * @param outer the outer roundrect - * @param inner the inner roundrect - */ - void drawDRRect(const GrClip&, - const GrPaint&, - const SkMatrix& viewMatrix, - const SkRRect& outer, - const SkRRect& inner); - - /** - * Draws a path. - * - * @param paint describes how to color pixels. - * @param viewMatrix transformation matrix - * @param path the path to draw - * @param style style to apply to the path. - */ - void drawPath(const GrClip&, - const GrPaint&, - const SkMatrix& viewMatrix, - const SkPath&, - const GrStyle& style); - - /** - * Draws vertices with a paint. - * - * @param paint describes how to color pixels. - * @param viewMatrix transformation matrix - * @param primitiveType primitives type to draw. - * @param vertexCount number of vertices. - * @param positions array of vertex positions, required. - * @param texCoords optional array of texture coordinates used - * to access the paint. - * @param colors optional array of per-vertex colors, supercedes - * the paint's color field. - * @param indices optional array of indices. If NULL vertices - * are drawn non-indexed. - * @param indexCount if indices is non-null then this is the - * number of indices. - */ - void drawVertices(const GrClip&, - const GrPaint& paint, - const SkMatrix& viewMatrix, - GrPrimitiveType primitiveType, - int vertexCount, - const SkPoint positions[], - const SkPoint texs[], - const GrColor colors[], - const uint16_t indices[], - int indexCount); - - /** - * Draws textured sprites from an atlas with a paint. - * - * @param paint describes how to color pixels. - * @param viewMatrix transformation matrix - * @param spriteCount number of sprites. - * @param xform array of compressed transformation data, required. - * @param texRect array of texture rectangles used to access the paint. - * @param colors optional array of per-sprite colors, supercedes - * the paint's color field. - */ - void drawAtlas(const GrClip&, - const GrPaint& paint, - const SkMatrix& viewMatrix, - int spriteCount, - const SkRSXform xform[], - const SkRect texRect[], - const SkColor colors[]); - - /** - * Draws a region. - * - * @param paint describes how to color pixels - * @param viewMatrix transformation matrix - * @param region the region to be drawn - * @param style style to apply to the region - */ - void drawRegion(const GrClip&, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRegion& region, - const GrStyle& style); - - /** - * Draws an oval. - * - * @param paint describes how to color pixels. - * @param viewMatrix transformation matrix - * @param oval the bounding rect of the oval. - * @param style style to apply to the oval. Currently path effects are not allowed. - */ - void drawOval(const GrClip&, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& oval, - const GrStyle& style); - /** - * Draws a partial arc of an oval. - * - * @param paint describes how to color pixels. - * @param viewMatrix transformation matrix. - * @param oval the bounding rect of the oval. - * @param startAngle starting angle in degrees. - * @param sweepAngle angle to sweep in degrees. Must be in (-360, 360) - * @param useCenter true means that the implied path begins at the oval center, connects as a - * line to the point indicated by the start contains the arc indicated by - * the sweep angle. If false the line beginning at the center point is - * omitted. - * @param style style to apply to the oval. - */ - void drawArc(const GrClip&, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& oval, - SkScalar startAngle, - SkScalar sweepAngle, - bool useCenter, - const GrStyle& style); - - /** - * Draw the image as a set of rects, specified by |iter|. - */ - void drawImageLattice(const GrClip&, - const GrPaint& paint, - const SkMatrix& viewMatrix, - int imageWidth, - int imageHeight, - std::unique_ptr iter, - const SkRect& dst); - - /** - * After this returns any pending surface IO will be issued to the backend 3D API and - * if the surface has MSAA it will be resolved. - */ - void prepareForExternalIO(); - - /** - * Reads a rectangle of pixels from the draw context. - * @param dstInfo image info for the destination - * @param dstBuffer destination pixels for the read - * @param dstRowBytes bytes in a row of 'dstBuffer' - * @param x x offset w/in the draw context from which to read - * @param y y offset w/in the draw context from which to read - * - * @return true if the read succeeded, false if not. The read can fail because of an - * unsupported pixel config. - */ - bool readPixels(const SkImageInfo& dstInfo, void* dstBuffer, size_t dstRowBytes, int x, int y); - - /** - * Writes a rectangle of pixels [srcInfo, srcBuffer, srcRowbytes] into the - * drawContext at the specified position. - * @param srcInfo image info for the source pixels - * @param srcBuffer source for the write - * @param srcRowBytes bytes in a row of 'srcBuffer' - * @param x x offset w/in the draw context at which to write - * @param y y offset w/in the draw context at which to write - * - * @return true if the write succeeded, false if not. The write can fail because of an - * unsupported pixel config. - */ - bool writePixels(const SkImageInfo& srcInfo, const void* srcBuffer, size_t srcRowBytes, - int x, int y); - - bool isStencilBufferMultisampled() const { - return fRenderTarget->isStencilBufferMultisampled(); - } - bool isUnifiedMultisampled() const { return fRenderTarget->isUnifiedMultisampled(); } - bool hasMixedSamples() const { return fRenderTarget->isMixedSampled(); } - - bool mustUseHWAA(const GrPaint& paint) const { - return paint.isAntiAlias() && fRenderTarget->isUnifiedMultisampled(); - } - - const GrCaps* caps() const { return fContext->caps(); } - const GrSurfaceDesc& desc() const { return fRenderTarget->desc(); } - int width() const { return fRenderTarget->width(); } - int height() const { return fRenderTarget->height(); } - GrPixelConfig config() const { return fRenderTarget->config(); } - int numColorSamples() const { return fRenderTarget->numColorSamples(); } - bool isGammaCorrect() const { return SkToBool(fColorSpace.get()); } - SkSourceGammaTreatment sourceGammaTreatment() const { - return this->isGammaCorrect() ? SkSourceGammaTreatment::kRespect - : SkSourceGammaTreatment::kIgnore; - } - const SkSurfaceProps& surfaceProps() const { return fSurfaceProps; } - SkColorSpace* getColorSpace() const { return fColorSpace.get(); } - GrColorSpaceXform* getColorXformFromSRGB() const { return fColorXformFromSRGB.get(); } - GrSurfaceOrigin origin() const { return fRenderTarget->origin(); } - - bool wasAbandoned() const; - - GrRenderTarget* accessRenderTarget() { return fRenderTarget.get(); } - - sk_sp asTexture() { return sk_ref_sp(fRenderTarget->asTexture()); } - - // Provides access to functions that aren't part of the public API. - GrDrawContextPriv drawContextPriv(); - const GrDrawContextPriv drawContextPriv() const; - - GrAuditTrail* auditTrail() { return fAuditTrail; } - -protected: - GrDrawContext(GrContext*, GrDrawingManager*, sk_sp, sk_sp, - const SkSurfaceProps* surfaceProps, GrAuditTrail*, GrSingleOwner*); - - GrDrawingManager* drawingManager() { return fDrawingManager; } - - SkDEBUGCODE(GrSingleOwner* singleOwner() { return fSingleOwner; }) - SkDEBUGCODE(void validate() const;) - -private: - friend class GrAtlasTextBlob; // for access to drawBatch - friend class GrStencilAndCoverTextContext; // for access to drawBatch - - friend class GrDrawingManager; // for ctor - friend class GrDrawContextPriv; - friend class GrTestTarget; // for access to getDrawTarget - friend class GrSWMaskHelper; // for access to drawBatch - - // All the path renderers currently make their own batches - friend class GrSoftwarePathRenderer; // for access to drawBatch - friend class GrAAConvexPathRenderer; // for access to drawBatch - friend class GrDashLinePathRenderer; // for access to drawBatch - friend class GrAAHairLinePathRenderer; // for access to drawBatch - friend class GrAALinearizingConvexPathRenderer; // for access to drawBatch - friend class GrAADistanceFieldPathRenderer; // for access to drawBatch - friend class GrDefaultPathRenderer; // for access to drawBatch - friend class GrPLSPathRenderer; // for access to drawBatch - friend class GrMSAAPathRenderer; // for access to drawBatch - friend class GrStencilAndCoverPathRenderer; // for access to drawBatch - friend class GrTessellatingPathRenderer; // for access to drawBatch - - void internalClear(const GrFixedClip&, const GrColor, bool canIgnoreClip); - - bool drawFilledDRRect(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRRect& origOuter, - const SkRRect& origInner); - - bool drawFilledRect(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& rect, - const GrUserStencilSettings* ss); - - void drawNonAAFilledRect(const GrClip&, - const GrPaint&, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect* localRect, - const SkMatrix* localMatrix, - const GrUserStencilSettings* ss, - bool useHWAA); - - void internalDrawPath(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkPath& path, - const GrStyle& style); - - // This entry point allows the GrTextContext-derived classes to add their batches to - // the drawTarget. - void drawBatch(const GrPipelineBuilder& pipelineBuilder, const GrClip&, GrDrawBatch* batch); - - GrDrawTarget* getDrawTarget(); - - GrDrawingManager* fDrawingManager; - sk_sp fRenderTarget; - - // In MDB-mode the drawTarget can be closed by some other drawContext that has picked - // it up. For this reason, the drawTarget should only ever be accessed via 'getDrawTarget'. - GrDrawTarget* fDrawTarget; - GrContext* fContext; - GrInstancedPipelineInfo fInstancedPipelineInfo; - - sk_sp fColorSpace; - sk_sp fColorXformFromSRGB; - SkSurfaceProps fSurfaceProps; - GrAuditTrail* fAuditTrail; - - // In debug builds we guard against improper thread handling - SkDEBUGCODE(mutable GrSingleOwner* fSingleOwner;) -}; - -#endif diff --git a/gfx/skia/skia/include/gpu/GrExternalTextureData.h b/gfx/skia/skia/include/gpu/GrExternalTextureData.h new file mode 100644 index 000000000000..5943fd8c5866 --- /dev/null +++ b/gfx/skia/skia/include/gpu/GrExternalTextureData.h @@ -0,0 +1,28 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef GrExternalTextureData_DEFINED +#define GrExternalTextureData_DEFINED + +#include "GrTypes.h" + +class GrContext; + +class SK_API GrExternalTextureData : SkNoncopyable { +public: + virtual ~GrExternalTextureData() {} + virtual GrBackend getBackend() const = 0; +protected: + virtual GrBackendObject getBackendObject() const = 0; + virtual void attachToContext(GrContext*) = 0; + + friend class SkCrossContextImageData; + friend class SkImage; +}; + +#endif diff --git a/gfx/skia/skia/include/gpu/GrFragmentProcessor.h b/gfx/skia/skia/include/gpu/GrFragmentProcessor.h index d7011f826c84..00f2dbd9d856 100644 --- a/gfx/skia/skia/include/gpu/GrFragmentProcessor.h +++ b/gfx/skia/skia/include/gpu/GrFragmentProcessor.h @@ -11,18 +11,19 @@ #include "GrProcessor.h" class GrCoordTransform; -class GrGLSLCaps; class GrGLSLFragmentProcessor; class GrInvariantOutput; class GrPipeline; class GrProcessorKeyBuilder; +class GrShaderCaps; +class GrSwizzle; /** Provides custom fragment shader code. Fragment processors receive an input color (vec4f) and produce an output color. They may reference textures and uniforms. They may use GrCoordTransforms to receive a transformation of the local coordinates that map from local space to the fragment being processed. */ -class GrFragmentProcessor : public GrProcessor { +class GrFragmentProcessor : public GrResourceIOProcessor, public GrProgramElement { public: /** * In many instances (e.g. SkShader::asFragmentProcessor() implementations) it is desirable to @@ -35,11 +36,12 @@ public: static sk_sp MulOutputByInputAlpha(sk_sp); /** - * Similar to the above but it modulates the output r,g,b of the child processor by the input - * rgb and then multiplies all the components by the input alpha. This effectively modulates - * the child processor's premul color by a unpremul'ed input and produces a premul output + * This assumes that the input color to the returned processor will be unpremul and that the + * passed processor (which becomes the returned processor's child) produces a premul output. + * The result of the returned processor is a premul of its input color modulated by the child + * processor's premul output. */ - static sk_sp MulOutputByInputUnpremulColor(sk_sp); + static sk_sp MakeInputPremulAndMulByOutput(sk_sp); /** * Returns a parent fragment processor that adopts the passed fragment processor as a child. @@ -54,6 +56,24 @@ public: */ static sk_sp PremulInput(sk_sp); + /** + * Returns a fragment processor that calls the passed in fragment processor, and then premuls + * the output. + */ + static sk_sp PremulOutput(sk_sp); + + /** + * Returns a fragment processor that calls the passed in fragment processor, and then unpremuls + * the output. + */ + static sk_sp UnpremulOutput(sk_sp); + + /** + * Returns a fragment processor that calls the passed in fragment processor, and then swizzles + * the output. + */ + static sk_sp SwizzleOutput(sk_sp, const GrSwizzle&); + /** * Returns a fragment processor that runs the passed in array of fragment processors in a * series. The original input is passed to the first, the first's output is passed to the @@ -64,16 +84,11 @@ public: */ static sk_sp RunInSeries(sk_sp*, int cnt); - GrFragmentProcessor() - : INHERITED() - , fUsesDistanceVectorField(false) - , fUsesLocalCoords(false) {} - ~GrFragmentProcessor() override; GrGLSLFragmentProcessor* createGLSLInstance() const; - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { this->onGetGLSLProcessorKey(caps, b); for (int i = 0; i < fChildProcessors.count(); ++i) { fChildProcessors[i]->getGLSLProcessorKey(caps, b); @@ -95,10 +110,51 @@ public: const GrFragmentProcessor& childProcessor(int index) const { return *fChildProcessors[index]; } /** Do any of the coordtransforms for this processor require local coords? */ - bool usesLocalCoords() const { return fUsesLocalCoords; } + bool usesLocalCoords() const { return SkToBool(fFlags & kUsesLocalCoords_Flag); } /** Does this FP need a vector to the nearest edge? */ - bool usesDistanceVectorField() const { return fUsesDistanceVectorField; } + bool usesDistanceVectorField() const { + return SkToBool(fFlags & kUsesDistanceVectorField_Flag); + } + + /** + * A GrDrawOp may premultiply its antialiasing coverage into its GrGeometryProcessor's color + * output under the following scenario: + * * all the color fragment processors report true to this query, + * * all the coverage fragment processors report true to this query, + * * the blend mode arithmetic allows for it it. + * To be compatible a fragment processor's output must be a modulation of its input color or + * alpha with a computed premultiplied color or alpha that is in 0..1 range. The computed color + * or alpha that is modulated against the input cannot depend on the input's alpha. The computed + * value cannot depend on the input's color channels unless it unpremultiplies the input color + * channels by the input alpha. + */ + bool compatibleWithCoverageAsAlpha() const { + return SkToBool(fFlags & kCompatibleWithCoverageAsAlpha_OptimizationFlag); + } + + /** + * If this is true then all opaque input colors to the processor produce opaque output colors. + */ + bool preservesOpaqueInput() const { + return SkToBool(fFlags & kPreservesOpaqueInput_OptimizationFlag); + } + + /** + * Tests whether given a constant input color the processor produces a constant output color + * (for all fragments). If true outputColor will contain the constant color produces for + * inputColor. + */ + bool hasConstantOutputForConstantInput(GrColor4f inputColor, GrColor4f* outputColor) const { + if (fFlags & kConstantOutputForConstantInput_OptimizationFlag) { + *outputColor = this->constantOutputForConstantInput(inputColor); + return true; + } + return false; + } + bool hasConstantOutputForConstantInput() const { + return SkToBool(fFlags & kConstantOutputForConstantInput_OptimizationFlag); + } /** Returns true if this and other processor conservatively draw identically. It can only return true when the two processor are of the same subclass (i.e. they return the same object from @@ -109,18 +165,6 @@ public: */ bool isEqual(const GrFragmentProcessor& that) const; - /** - * This function is used to perform optimizations. When called the invarientOuput param - * indicate whether the input components to this processor in the FS will have known values. - * In inout the validFlags member is a bitfield of GrColorComponentFlags. The isSingleComponent - * member indicates whether the input will be 1 or 4 bytes. The function updates the members of - * inout to indicate known values of its output. A component of the color member only has - * meaning if the corresponding bit in validFlags is set. - */ - void computeInvariantOutput(GrInvariantOutput* inout) const { - this->onComputeInvariantOutput(inout); - } - /** * Pre-order traversal of a FP hierarchy, or of the forest of FPs in a GrPipeline. In the latter * case the tree rooted at each FP in the GrPipeline is visited successively. @@ -183,14 +227,41 @@ public: &GrFragmentProcessor::numCoordTransforms, &GrFragmentProcessor::coordTransform>; - using TextureAccessIter = FPItemIter; + using TextureAccessIter = FPItemIter; protected: - void addTextureAccess(const GrTextureAccess* textureAccess) override; - void addBufferAccess(const GrBufferAccess*) override; + enum OptimizationFlags : uint32_t { + kNone_OptimizationFlags, + kCompatibleWithCoverageAsAlpha_OptimizationFlag = 0x1, + kPreservesOpaqueInput_OptimizationFlag = 0x2, + kConstantOutputForConstantInput_OptimizationFlag = 0x4, + kAll_OptimizationFlags = kCompatibleWithCoverageAsAlpha_OptimizationFlag | + kPreservesOpaqueInput_OptimizationFlag | + kConstantOutputForConstantInput_OptimizationFlag + }; + GR_DECL_BITFIELD_OPS_FRIENDS(OptimizationFlags) + + GrFragmentProcessor(OptimizationFlags optimizationFlags) : fFlags(optimizationFlags) { + SkASSERT((fFlags & ~kAll_OptimizationFlags) == 0); + } + + OptimizationFlags optimizationFlags() const { + return static_cast(kAll_OptimizationFlags & fFlags); + } + + /** + * This allows one subclass to access another subclass's implementation of + * constantOutputForConstantInput. It must only be called when + * hasConstantOutputForConstantInput() is known to be true. + */ + static GrColor4f ConstantOutputForConstantInput(const GrFragmentProcessor& fp, + GrColor4f input) { + SkASSERT(fp.hasConstantOutputForConstantInput()); + return fp.constantOutputForConstantInput(input); + } /** * Fragment Processor subclasses call this from their constructor to register coordinate @@ -223,29 +294,30 @@ protected: int registerChildProcessor(sk_sp child); /** - * Subclass implements this to support getConstantColorComponents(...). - * - * Note: it's up to the subclass implementation to do any recursive call to compute the child - * procs' output invariants; computeInvariantOutput will not be recursive. - */ - virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const = 0; - - /* Sub-classes should set this to true in their constructors if they need access to a distance + * Sub-classes should call this in their constructors if they need access to a distance * vector field to the nearest edge */ - bool fUsesDistanceVectorField; + void setWillUseDistanceVectorField() { fFlags |= kUsesDistanceVectorField_Flag; } private: + void addPendingIOs() const override { GrResourceIOProcessor::addPendingIOs(); } + void removeRefs() const override { GrResourceIOProcessor::removeRefs(); } + void pendingIOComplete() const override { GrResourceIOProcessor::pendingIOComplete(); } + void notifyRefCntIsZero() const final; + virtual GrColor4f constantOutputForConstantInput(GrColor4f /* inputColor */) const { + SkFAIL("Subclass must override this if advertising this optimization."); + return GrColor4f::TransparentBlack(); + } + /** Returns a new instance of the appropriate *GL* implementation class for the given GrFragmentProcessor; caller is responsible for deleting the object. */ virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const = 0; /** Implemented using GLFragmentProcessor::GenKey as described in this class's comment. */ - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const = 0; + virtual void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0; /** * Subclass implements this to support isEqual(). It will only be called if it is known that @@ -257,7 +329,13 @@ private: bool hasSameTransforms(const GrFragmentProcessor&) const; - bool fUsesLocalCoords; + enum PrivateFlags { + kFirstPrivateFlag = kAll_OptimizationFlags + 1, + kUsesLocalCoords_Flag = kFirstPrivateFlag, + kUsesDistanceVectorField_Flag = kFirstPrivateFlag << 1, + }; + + mutable uint32_t fFlags = 0; SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms; @@ -265,9 +343,11 @@ private: * This is not SkSTArray<1, sk_sp> because this class holds strong * references until notifyRefCntIsZero and then it holds pending executions. */ - SkSTArray<1, GrFragmentProcessor*, true> fChildProcessors; + SkSTArray<1, GrFragmentProcessor*, true> fChildProcessors; typedef GrProcessor INHERITED; }; +GR_MAKE_BITFIELD_OPS(GrFragmentProcessor::OptimizationFlags) + #endif diff --git a/gfx/skia/skia/include/gpu/GrGpuResource.h b/gfx/skia/skia/include/gpu/GrGpuResource.h index 364a886408cf..2d84c633eeb9 100644 --- a/gfx/skia/skia/include/gpu/GrGpuResource.h +++ b/gfx/skia/skia/include/gpu/GrGpuResource.h @@ -23,7 +23,7 @@ class SkTraceMemoryDump; * * Gpu resources can have three types of refs: * 1) Normal ref (+ by ref(), - by unref()): These are used by code that is issuing draw calls - * that read and write the resource via GrDrawTarget and by any object that must own a + * that read and write the resource via GrOpList and by any object that must own a * GrGpuResource and is itself owned (directly or indirectly) by Skia-client code. * 2) Pending read (+ by addPendingRead(), - by completedRead()): GrContext has scheduled a read * of the resource by the GPU as a result of a skia API call but hasn't executed it yet. @@ -46,7 +46,7 @@ class SkTraceMemoryDump; template class GrIORef : public SkNoncopyable { public: // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with - // templated helper classes (e.g. SkAutoTUnref). However, we have different categories of + // templated helper classes (e.g. sk_sp). However, we have different categories of // refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are // not intended to cross thread boundaries. void ref() const { @@ -93,6 +93,11 @@ protected: bool internalHasRef() const { return SkToBool(fRefCnt); } private: + friend class GrIORefProxy; // needs to forward on wrapped IO calls + // This is for a unit test. + template + friend void testingOnly_getIORefCnts(const T*, int* refCnt, int* readCnt, int* writeCnt); + void addPendingRead() const { this->validate(); ++fPendingReads; @@ -175,12 +180,38 @@ public: return fGpuMemorySize; } + class UniqueID { + public: + static UniqueID InvalidID() { + return UniqueID(uint32_t(SK_InvalidUniqueID)); + } + + UniqueID() {} + + explicit UniqueID(uint32_t id) : fID(id) {} + + uint32_t asUInt() const { return fID; } + + bool operator==(const UniqueID& other) const { + return fID == other.fID; + } + bool operator!=(const UniqueID& other) const { + return !(*this == other); + } + + void makeInvalid() { fID = SK_InvalidUniqueID; } + bool isInvalid() const { return SK_InvalidUniqueID == fID; } + + protected: + uint32_t fID; + }; + /** * Gets an id that is unique for this GrGpuResource object. It is static in that it does * not change when the content of the GrGpuResource object changes. This will never return * 0. */ - uint32_t uniqueID() const { return fUniqueID; } + UniqueID uniqueID() const { return fUniqueID; } /** Returns the current unique key for the resource. It will be invalid if the resource has no associated unique key. */ @@ -229,6 +260,11 @@ protected: // final class). void registerWithCacheWrapped(); + // This is only called by resources that are being exported from Ganesh to client code. It + // ensures that the cache can no longer reach this resource, and that it no longer counts + // against the budget. + void detachFromCache(); + GrGpuResource(GrGpu*); virtual ~GrGpuResource(); @@ -279,28 +315,30 @@ private: void makeUnbudgeted(); #ifdef SK_DEBUG - friend class GrGpu; // for assert in GrGpu to access getGpu + friend class GrGpu; // for assert in GrGpu to access getGpu #endif + // An index into a heap when this resource is purgeable or an array when not. This is maintained // by the cache. - int fCacheArrayIndex; + int fCacheArrayIndex; // This value reflects how recently this resource was accessed in the cache. This is maintained // by the cache. - uint32_t fTimestamp; - uint32_t fExternalFlushCntWhenBecamePurgeable; + uint32_t fTimestamp; + uint32_t fExternalFlushCntWhenBecamePurgeable; + GrStdSteadyClock::time_point fTimeWhenBecamePurgeable; static const size_t kInvalidGpuMemorySize = ~static_cast(0); - GrScratchKey fScratchKey; - GrUniqueKey fUniqueKey; + GrScratchKey fScratchKey; + GrUniqueKey fUniqueKey; // This is not ref'ed but abandon() or release() will be called before the GrGpu object // is destroyed. Those calls set will this to NULL. - GrGpu* fGpu; - mutable size_t fGpuMemorySize; + GrGpu* fGpu; + mutable size_t fGpuMemorySize; - SkBudgeted fBudgeted; - bool fRefsWrappedObjects; - const uint32_t fUniqueID; + SkBudgeted fBudgeted; + bool fRefsWrappedObjects; + const UniqueID fUniqueID; typedef GrIORef INHERITED; friend class GrIORef; // to access notifyAllCntsAreZero and notifyRefCntIsZero. diff --git a/gfx/skia/skia/include/gpu/GrGpuResourceRef.h b/gfx/skia/skia/include/gpu/GrGpuResourceRef.h index 4511adce6823..d6ef6c13a95f 100644 --- a/gfx/skia/skia/include/gpu/GrGpuResourceRef.h +++ b/gfx/skia/skia/include/gpu/GrGpuResourceRef.h @@ -28,7 +28,7 @@ * state 2 to state 3. Calling pendingIOComplete() moves from state 2 to state 1. There is no * valid way of going from state 3 back to 2 or 1. * - * Like SkAutoTUnref, its constructor and setter adopt a ref from their caller. + * Like sk_sp, its constructor and setter adopt a ref from their caller. * * TODO: Once GrDODrawState no longer exists and therefore GrDrawState and GrOptDrawState no * longer share an instance of this class, attempt to make the resource owned by GrGpuResourceRef @@ -43,6 +43,10 @@ public: /** Does this object own a pending read or write on the resource it is wrapping. */ bool ownsPendingIO() const { return fPendingIO; } + /** What type of IO does this represent? This is independent of whether a normal ref or a + pending IO is currently held. */ + GrIOType ioType() const { return fIOType; } + /** Shortcut for calling setResource() with NULL. It cannot be called after markingPendingIO is called. */ void reset(); @@ -63,7 +67,7 @@ private: execution. It can only be called once. */ void markPendingIO() const; - /** Called when the program element/draw state is no longer owned by GrDrawTarget-client code. + /** Called when the program element/draw state is no longer owned by GrOpList-client code. This lets the cache know that the drawing code will no longer schedule additional reads or writes to the resource using the program element or draw state. It can only be called once. */ @@ -75,7 +79,7 @@ private: called. */ void pendingIOComplete() const; - friend class GrProgramElement; + friend class GrResourceIOProcessor; GrGpuResource* fResource; mutable bool fOwnRef; diff --git a/gfx/skia/skia/include/gpu/GrInvariantOutput.h b/gfx/skia/skia/include/gpu/GrInvariantOutput.h deleted file mode 100644 index 6e2cbe84f9a0..000000000000 --- a/gfx/skia/skia/include/gpu/GrInvariantOutput.h +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrInvariantOutput_DEFINED -#define GrInvariantOutput_DEFINED - -#include "GrColor.h" - -struct GrInitInvariantOutput { - GrInitInvariantOutput() - : fValidFlags(kNone_GrColorComponentFlags) - , fColor(0) - , fIsSingleComponent(false) - , fIsLCDCoverage(false) {} - - void setKnownFourComponents(GrColor color) { - fColor = color; - fValidFlags = kRGBA_GrColorComponentFlags; - fIsSingleComponent = false; - } - - void setUnknownFourComponents() { - fValidFlags = kNone_GrColorComponentFlags; - fIsSingleComponent = false; - } - - void setUnknownOpaqueFourComponents() { - fColor = 0xffU << GrColor_SHIFT_A; - fValidFlags = kA_GrColorComponentFlag; - fIsSingleComponent = false; - } - - void setKnownSingleComponent(uint8_t alpha) { - fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha); - fValidFlags = kRGBA_GrColorComponentFlags; - fIsSingleComponent = true; - } - - void setUnknownSingleComponent() { - fValidFlags = kNone_GrColorComponentFlags; - fIsSingleComponent = true; - } - - void setUsingLCDCoverage() { fIsLCDCoverage = true; } - - GrColorComponentFlags fValidFlags; - GrColor fColor; - bool fIsSingleComponent; - bool fIsLCDCoverage; // Temorary data member until texture pixel configs are - // updated -}; - -class GrInvariantOutput { -public: - GrInvariantOutput(GrColor color, GrColorComponentFlags flags, bool isSingleComponent) - : fColor(color) - , fValidFlags(flags) - , fIsSingleComponent(isSingleComponent) - , fNonMulStageFound(false) - , fWillUseInputColor(true) - , fIsLCDCoverage(false) {} - - GrInvariantOutput(const GrInitInvariantOutput& io) - : fColor(io.fColor) - , fValidFlags(io.fValidFlags) - , fIsSingleComponent(io.fIsSingleComponent) - , fNonMulStageFound(false) - , fWillUseInputColor(false) - , fIsLCDCoverage(io.fIsLCDCoverage) {} - - virtual ~GrInvariantOutput() {} - - enum ReadInput { - kWill_ReadInput, - kWillNot_ReadInput, - }; - - void mulByUnknownOpaqueFourComponents() { - SkDEBUGCODE(this->validate()); - if (this->isOpaque()) { - fValidFlags = kA_GrColorComponentFlag; - fIsSingleComponent = false; - } else { - // Since the current state is not opaque we no longer care if the color being - // multiplied is opaque. - this->mulByUnknownFourComponents(); - } - SkDEBUGCODE(this->validate()); - } - - void mulByUnknownFourComponents() { - SkDEBUGCODE(this->validate()); - if (this->hasZeroAlpha()) { - this->internalSetToTransparentBlack(); - } else { - this->internalSetToUnknown(); - } - SkDEBUGCODE(this->validate()); - } - - void mulByUnknownSingleComponent() { - SkDEBUGCODE(this->validate()); - if (this->hasZeroAlpha()) { - this->internalSetToTransparentBlack(); - } else { - // We don't need to change fIsSingleComponent in this case - fValidFlags = kNone_GrColorComponentFlags; - } - SkDEBUGCODE(this->validate()); - } - - void mulByKnownSingleComponent(uint8_t alpha) { - SkDEBUGCODE(this->validate()); - if (this->hasZeroAlpha() || 0 == alpha) { - this->internalSetToTransparentBlack(); - } else { - if (alpha != 255) { - // Multiply color by alpha - fColor = GrColorPackRGBA(SkMulDiv255Round(GrColorUnpackR(fColor), alpha), - SkMulDiv255Round(GrColorUnpackG(fColor), alpha), - SkMulDiv255Round(GrColorUnpackB(fColor), alpha), - SkMulDiv255Round(GrColorUnpackA(fColor), alpha)); - // We don't need to change fIsSingleComponent in this case - } - } - SkDEBUGCODE(this->validate()); - } - - void mulByKnownFourComponents(GrColor color) { - SkDEBUGCODE(this->validate()); - uint32_t a; - if (GetAlphaAndCheckSingleChannel(color, &a)) { - this->mulByKnownSingleComponent(a); - } else { - if (color != 0xffffffff) { - fColor = GrColorPackRGBA( - SkMulDiv255Round(GrColorUnpackR(fColor), GrColorUnpackR(color)), - SkMulDiv255Round(GrColorUnpackG(fColor), GrColorUnpackG(color)), - SkMulDiv255Round(GrColorUnpackB(fColor), GrColorUnpackB(color)), - SkMulDiv255Round(GrColorUnpackA(fColor), a)); - if (kRGBA_GrColorComponentFlags == fValidFlags) { - fIsSingleComponent = GetAlphaAndCheckSingleChannel(fColor, &a); - } - } - } - SkDEBUGCODE(this->validate()); - } - - // Ignores the incoming color's RGB and muls its alpha by color. - void mulAlphaByKnownFourComponents(GrColor color) { - SkDEBUGCODE(this->validate()); - uint32_t a; - if (GetAlphaAndCheckSingleChannel(color, &a)) { - this->mulAlphaByKnownSingleComponent(a); - } else if (fValidFlags & kA_GrColorComponentFlag) { - GrColor preAlpha = GrColorUnpackA(fColor); - if (0 == preAlpha) { - this->internalSetToTransparentBlack(); - } else { - // We know that color has different component values - fIsSingleComponent = false; - fColor = GrColorPackRGBA( - SkMulDiv255Round(preAlpha, GrColorUnpackR(color)), - SkMulDiv255Round(preAlpha, GrColorUnpackG(color)), - SkMulDiv255Round(preAlpha, GrColorUnpackB(color)), - SkMulDiv255Round(preAlpha, a)); - fValidFlags = kRGBA_GrColorComponentFlags; - } - } else { - fIsSingleComponent = false; - fValidFlags = kNone_GrColorComponentFlags; - } - SkDEBUGCODE(this->validate()); - } - - // Ignores the incoming color's RGB and muls its alpha by the alpha param and sets all channels - // equal to that value. - void mulAlphaByKnownSingleComponent(uint8_t alpha) { - SkDEBUGCODE(this->validate()); - if (0 == alpha || this->hasZeroAlpha()) { - this->internalSetToTransparentBlack(); - } else { - if (fValidFlags & kA_GrColorComponentFlag) { - GrColor a = GrColorUnpackA(fColor); - a = SkMulDiv255Round(alpha, a); - fColor = GrColorPackRGBA(a, a, a, a); - fValidFlags = kRGBA_GrColorComponentFlags; - } else { - fValidFlags = kNone_GrColorComponentFlags; - } - fIsSingleComponent = true; - } - SkDEBUGCODE(this->validate()); - } - - void premulFourChannelColor() { - SkDEBUGCODE(this->validate()); - SkASSERT(!fIsSingleComponent); - fNonMulStageFound = true; - if (!(fValidFlags & kA_GrColorComponentFlag)) { - fValidFlags = kNone_GrColorComponentFlags; - } else { - fColor = GrPremulColor(fColor); - } - SkDEBUGCODE(this->validate()); - } - - void invalidateComponents(GrColorComponentFlags invalidateFlags, ReadInput readsInput) { - SkDEBUGCODE(this->validate()); - fValidFlags = (fValidFlags & ~invalidateFlags); - fIsSingleComponent = false; - fNonMulStageFound = true; - if (kWillNot_ReadInput == readsInput) { - fWillUseInputColor = false; - } - SkDEBUGCODE(this->validate()); - } - - void setToOther(GrColorComponentFlags validFlags, GrColor color, ReadInput readsInput) { - SkDEBUGCODE(this->validate()); - fValidFlags = validFlags; - fColor = color; - fIsSingleComponent = false; - fNonMulStageFound = true; - if (kWillNot_ReadInput == readsInput) { - fWillUseInputColor = false; - } - if (kRGBA_GrColorComponentFlags == fValidFlags) { - uint32_t a; - if (GetAlphaAndCheckSingleChannel(color, &a)) { - fIsSingleComponent = true; - } - } - SkDEBUGCODE(this->validate()); - } - - void setToUnknown(ReadInput readsInput) { - SkDEBUGCODE(this->validate()); - this->internalSetToUnknown(); - fNonMulStageFound= true; - if (kWillNot_ReadInput == readsInput) { - fWillUseInputColor = false; - } - SkDEBUGCODE(this->validate()); - } - - // Temporary setter to handle LCD text correctly until we improve texture pixel config queries - // and thus can rely solely on number of coverage components for RGA vs single channel coverage. - void setUsingLCDCoverage() { - fIsLCDCoverage = true; - } - - GrColor color() const { return fColor; } - GrColorComponentFlags validFlags() const { return fValidFlags; } - bool willUseInputColor() const { return fWillUseInputColor; } - - /** - * If isSingleComponent is true, then the flag values for r, g, b, and a must all be the - * same. If the flags are all set then all color components must be equal. - */ - SkDEBUGCODE(void validate() const;) - -private: - friend class GrProcOptInfo; - - /** Extracts the alpha channel and returns true if r,g,b == a. */ - static bool GetAlphaAndCheckSingleChannel(GrColor color, uint32_t* alpha) { - *alpha = GrColorUnpackA(color); - return *alpha == GrColorUnpackR(color) && *alpha == GrColorUnpackG(color) && - *alpha == GrColorUnpackB(color); - } - - void reset(GrColor color, GrColorComponentFlags flags, bool isSingleComponent) { - fColor = color; - fValidFlags = flags; - fIsSingleComponent = isSingleComponent; - fNonMulStageFound = false; - fWillUseInputColor = true; - } - - void reset(const GrInitInvariantOutput& io) { - fColor = io.fColor; - fValidFlags = io.fValidFlags; - fIsSingleComponent = io.fIsSingleComponent; - fNonMulStageFound = false; - fWillUseInputColor = true; - fIsLCDCoverage = io.fIsLCDCoverage; - } - - void internalSetToTransparentBlack() { - fValidFlags = kRGBA_GrColorComponentFlags; - fColor = 0; - fIsSingleComponent = true; - } - - void internalSetToUnknown() { - fValidFlags = kNone_GrColorComponentFlags; - fIsSingleComponent = false; - } - - bool hasZeroAlpha() const { - return ((fValidFlags & kA_GrColorComponentFlag) && 0 == GrColorUnpackA(fColor)); - } - - bool isOpaque() const { - return ((fValidFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(fColor)); - } - - bool isSolidWhite() const { - return (fValidFlags == kRGBA_GrColorComponentFlags && 0xFFFFFFFF == fColor); - } - - bool isSingleComponent() const { return fIsSingleComponent; } - - void resetWillUseInputColor() { fWillUseInputColor = true; } - - bool allStagesMulInput() const { return !fNonMulStageFound; } - void resetNonMulStageFound() { fNonMulStageFound = false; } - - bool isLCDCoverage() const { return fIsLCDCoverage; } - - SkDEBUGCODE(bool colorComponentsAllEqual() const;) - /** - * If alpha is valid, check that any valid R,G,B values are <= A - */ - SkDEBUGCODE(bool validPreMulColor() const;) - - GrColor fColor; - GrColorComponentFlags fValidFlags; - bool fIsSingleComponent; - bool fNonMulStageFound; - bool fWillUseInputColor; - bool fIsLCDCoverage; // Temorary data member until texture pixel configs are updated - -}; - -#endif - diff --git a/gfx/skia/skia/include/gpu/GrProcessor.h b/gfx/skia/skia/include/gpu/GrProcessor.h index d374a7f3d0e5..d10136846a8d 100644 --- a/gfx/skia/skia/include/gpu/GrProcessor.h +++ b/gfx/skia/skia/include/gpu/GrProcessor.h @@ -9,10 +9,12 @@ #define GrProcessor_DEFINED #include "GrColor.h" +#include "GrBuffer.h" +#include "GrGpuResourceRef.h" #include "GrProcessorUnitTest.h" #include "GrProgramElement.h" -#include "GrTextureAccess.h" -#include "GrBufferAccess.h" +#include "GrSamplerParams.h" +#include "GrShaderVar.h" #include "SkMath.h" #include "SkString.h" #include "../private/SkAtomics.h" @@ -20,6 +22,8 @@ class GrContext; class GrCoordTransform; class GrInvariantOutput; +class GrResourceProvider; +class GrTextureProxy; /** * Used by processors to build their keys. It incorporates each per-processor key into a larger @@ -57,45 +61,27 @@ private: Dynamically allocated GrProcessors are managed by a per-thread memory pool. The ref count of an processor must reach 0 before the thread terminates and the pool is destroyed. */ -class GrProcessor : public GrProgramElement { +class GrProcessor { public: - virtual ~GrProcessor(); + virtual ~GrProcessor() = default; - /** Human-meaningful string to identify this prcoessor; may be embedded - in generated shader code. */ + /** Human-meaningful string to identify this prcoessor; may be embedded in generated shader + code. */ virtual const char* name() const = 0; - // Human-readable dump of all information + /** Human-readable dump of all information */ virtual SkString dumpInfo() const { SkString str; str.appendf("Missing data"); return str; } - int numTextures() const { return fTextureAccesses.count(); } - - /** Returns the access pattern for the texture at index. index must be valid according to - numTextures(). */ - const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; } - - /** Shortcut for textureAccess(index).texture(); */ - GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); } - - int numBuffers() const { return fBufferAccesses.count(); } - - /** Returns the access pattern for the buffer at index. index must be valid according to - numBuffers(). */ - const GrBufferAccess& bufferAccess(int index) const { - return *fBufferAccesses[index]; - } - /** * Platform specific built-in features that a processor can request for the fragment shader. */ enum RequiredFeatures { kNone_RequiredFeatures = 0, - kFragmentPosition_RequiredFeature = 1 << 0, - kSampleLocations_RequiredFeature = 1 << 1 + kSampleLocations_RequiredFeature = 1 << 0 }; GR_DECL_BITFIELD_OPS_FRIENDS(RequiredFeatures); @@ -112,9 +98,7 @@ public: ::operator delete(target, placement); } - /** - * Helper for down-casting to a GrProcessor subclass - */ + /** Helper for down-casting to a GrProcessor subclass */ template const T& cast() const { return *static_cast(this); } uint32_t classID() const { SkASSERT(kIllegalProcessorClassID != fClassID); return fClassID; } @@ -122,24 +106,11 @@ public: protected: GrProcessor() : fClassID(kIllegalProcessorClassID), fRequiredFeatures(kNone_RequiredFeatures) {} - /** - * Subclasses call these from their constructor to register sampler sources. The processor - * subclass manages the lifetime of the objects (these functions only store pointers). The - * GrTextureAccess and/or GrBufferAccess instances are typically member fields of the - * GrProcessor subclass. These must only be called from the constructor because GrProcessors - * are immutable. - */ - virtual void addTextureAccess(const GrTextureAccess* textureAccess); - virtual void addBufferAccess(const GrBufferAccess* bufferAccess); - - bool hasSameSamplers(const GrProcessor&) const; - /** * If the prcoessor will generate code that uses platform specific built-in features, then it * must call these methods from its constructor. Otherwise, requests to use these features will * be denied. */ - void setWillReadFragmentPosition() { fRequiredFeatures |= kFragmentPosition_RequiredFeature; } void setWillUseSampleLocations() { fRequiredFeatures |= kSampleLocations_RequiredFeature; } void combineRequiredFeatures(const GrProcessor& other) { @@ -151,11 +122,10 @@ protected: fClassID = kClassID; } - uint32_t fClassID; - SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses; - SkSTArray<2, const GrBufferAccess*, true> fBufferAccesses; - private: + GrProcessor(const GrProcessor&) = delete; + GrProcessor& operator=(const GrProcessor&) = delete; + static uint32_t GenClassID() { // fCurrProcessorClassID has been initialized to kIllegalProcessorClassID. The // atomic inc returns the old value not the incremented value. So we add @@ -173,11 +143,214 @@ private: }; static int32_t gCurrProcessorClassID; - RequiredFeatures fRequiredFeatures; - - typedef GrProgramElement INHERITED; + uint32_t fClassID; + RequiredFeatures fRequiredFeatures; }; GR_MAKE_BITFIELD_OPS(GrProcessor::RequiredFeatures); +/** A GrProcessor with the ability to access textures, buffers, and image storages. */ +class GrResourceIOProcessor : public GrProcessor { +public: + class TextureSampler; + class BufferAccess; + class ImageStorageAccess; + + int numTextureSamplers() const { return fTextureSamplers.count(); } + + /** Returns the access pattern for the texture at index. index must be valid according to + numTextureSamplers(). */ + const TextureSampler& textureSampler(int index) const { return *fTextureSamplers[index]; } + + int numBuffers() const { return fBufferAccesses.count(); } + + /** Returns the access pattern for the buffer at index. index must be valid according to + numBuffers(). */ + const BufferAccess& bufferAccess(int index) const { return *fBufferAccesses[index]; } + + int numImageStorages() const { return fImageStorageAccesses.count(); } + + /** Returns the access object for the image at index. index must be valid according to + numImages(). */ + const ImageStorageAccess& imageStorageAccess(int index) const { + return *fImageStorageAccesses[index]; + } + +protected: + GrResourceIOProcessor() = default; + + /** + * Subclasses call these from their constructor to register sampler/image sources. The processor + * subclass manages the lifetime of the objects (these functions only store pointers). The + * TextureSampler and/or BufferAccess instances are typically member fields of the GrProcessor + * subclass. These must only be called from the constructor because GrProcessors are immutable. + */ + void addTextureSampler(const TextureSampler*); + void addBufferAccess(const BufferAccess*); + void addImageStorageAccess(const ImageStorageAccess*); + + bool hasSameSamplersAndAccesses(const GrResourceIOProcessor&) const; + + // These methods can be used by derived classes that also derive from GrProgramElement. + void addPendingIOs() const; + void removeRefs() const; + void pendingIOComplete() const; + +private: + SkSTArray<4, const TextureSampler*, true> fTextureSamplers; + SkSTArray<1, const BufferAccess*, true> fBufferAccesses; + SkSTArray<1, const ImageStorageAccess*, true> fImageStorageAccesses; + + typedef GrProcessor INHERITED; +}; + +/** + * Used to represent a texture that is required by a GrResourceIOProcessor. It holds a GrTexture + * along with an associated GrSamplerParams. TextureSamplers don't perform any coord manipulation to + * account for texture origin. + */ +class GrResourceIOProcessor::TextureSampler : public SkNoncopyable { +public: + /** + * Must be initialized before adding to a GrProcessor's texture access list. + */ + TextureSampler(); + + TextureSampler(GrTexture*, const GrSamplerParams&); + explicit TextureSampler(GrTexture*, + GrSamplerParams::FilterMode = GrSamplerParams::kNone_FilterMode, + SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode, + GrShaderFlags visibility = kFragment_GrShaderFlag); + void reset(GrTexture*, const GrSamplerParams&, + GrShaderFlags visibility = kFragment_GrShaderFlag); + void reset(GrTexture*, + GrSamplerParams::FilterMode = GrSamplerParams::kNone_FilterMode, + SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode, + GrShaderFlags visibility = kFragment_GrShaderFlag); + + // MDB TODO: ultimately we shouldn't need the resource provider parameter + TextureSampler(GrResourceProvider*, sk_sp, const GrSamplerParams&); + explicit TextureSampler(GrResourceProvider*, sk_sp, + GrSamplerParams::FilterMode = GrSamplerParams::kNone_FilterMode, + SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode, + GrShaderFlags visibility = kFragment_GrShaderFlag); + void reset(GrResourceProvider*, sk_sp, const GrSamplerParams&, + GrShaderFlags visibility = kFragment_GrShaderFlag); + void reset(GrResourceProvider*, sk_sp, + GrSamplerParams::FilterMode = GrSamplerParams::kNone_FilterMode, + SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode, + GrShaderFlags visibility = kFragment_GrShaderFlag); + + bool operator==(const TextureSampler& that) const { + return this->texture() == that.texture() && + fParams == that.fParams && + fVisibility == that.fVisibility; + } + + bool operator!=(const TextureSampler& other) const { return !(*this == other); } + + GrTexture* texture() const { return fTexture.get(); } + GrShaderFlags visibility() const { return fVisibility; } + const GrSamplerParams& params() const { return fParams; } + + /** + * For internal use by GrProcessor. + */ + const GrGpuResourceRef* programTexture() const { return &fTexture; } + +private: + + typedef GrTGpuResourceRef ProgramTexture; + + ProgramTexture fTexture; + GrSamplerParams fParams; + GrShaderFlags fVisibility; + + typedef SkNoncopyable INHERITED; +}; + +/** + * Used to represent a texel buffer that will be read in a GrResourceIOProcessor. It holds a + * GrBuffer along with an associated offset and texel config. + */ +class GrResourceIOProcessor::BufferAccess : public SkNoncopyable { +public: + BufferAccess() = default; + BufferAccess(GrPixelConfig texelConfig, GrBuffer* buffer, + GrShaderFlags visibility = kFragment_GrShaderFlag) { + this->reset(texelConfig, buffer, visibility); + } + /** + * Must be initialized before adding to a GrProcessor's buffer access list. + */ + void reset(GrPixelConfig texelConfig, GrBuffer* buffer, + GrShaderFlags visibility = kFragment_GrShaderFlag) { + fTexelConfig = texelConfig; + fBuffer.set(SkRef(buffer), kRead_GrIOType); + fVisibility = visibility; + } + + bool operator==(const BufferAccess& that) const { + return fTexelConfig == that.fTexelConfig && + this->buffer() == that.buffer() && + fVisibility == that.fVisibility; + } + + bool operator!=(const BufferAccess& that) const { return !(*this == that); } + + GrPixelConfig texelConfig() const { return fTexelConfig; } + GrBuffer* buffer() const { return fBuffer.get(); } + GrShaderFlags visibility() const { return fVisibility; } + + /** + * For internal use by GrProcessor. + */ + const GrGpuResourceRef* programBuffer() const { return &fBuffer;} + +private: + GrPixelConfig fTexelConfig; + GrTGpuResourceRef fBuffer; + GrShaderFlags fVisibility; + + typedef SkNoncopyable INHERITED; +}; + +/** + * This is used by a GrProcessor to access a texture using image load/store in its shader code. + * ImageStorageAccesses don't perform any coord manipulation to account for texture origin. + * Currently the format of the load/store data in the shader is inferred from the texture config, + * though it could be made explicit. + */ +class GrResourceIOProcessor::ImageStorageAccess : public SkNoncopyable { +public: + ImageStorageAccess(sk_sp texture, GrIOType ioType, GrSLMemoryModel, GrSLRestrict, + GrShaderFlags visibility = kFragment_GrShaderFlag); + + bool operator==(const ImageStorageAccess& that) const { + return this->texture() == that.texture() && fVisibility == that.fVisibility; + } + + bool operator!=(const ImageStorageAccess& that) const { return !(*this == that); } + + GrTexture* texture() const { return fTexture.get(); } + GrShaderFlags visibility() const { return fVisibility; } + GrIOType ioType() const { return fTexture.ioType(); } + GrImageStorageFormat format() const { return fFormat; } + GrSLMemoryModel memoryModel() const { return fMemoryModel; } + GrSLRestrict restrict() const { return fRestrict; } + + /** + * For internal use by GrProcessor. + */ + const GrGpuResourceRef* programTexture() const { return &fTexture; } + +private: + GrTGpuResourceRef fTexture; + GrShaderFlags fVisibility; + GrImageStorageFormat fFormat; + GrSLMemoryModel fMemoryModel; + GrSLRestrict fRestrict; + typedef SkNoncopyable INHERITED; +}; + #endif diff --git a/gfx/skia/skia/include/gpu/GrProcessorUnitTest.h b/gfx/skia/skia/include/gpu/GrProcessorUnitTest.h index 4f26665cbeac..d6269c85bd59 100644 --- a/gfx/skia/skia/include/gpu/GrProcessorUnitTest.h +++ b/gfx/skia/skia/include/gpu/GrProcessorUnitTest.h @@ -8,15 +8,21 @@ #ifndef GrProcessorUnitTest_DEFINED #define GrProcessorUnitTest_DEFINED +#include "SkTypes.h" + +#if GR_TEST_UTILS + +#include "../private/GrTextureProxy.h" #include "../private/SkTArray.h" #include "GrTestUtils.h" -#include "SkTypes.h" class SkMatrix; class GrCaps; class GrContext; -class GrDrawContext; +class GrRenderTargetContext; struct GrProcessorTestData; +class GrTexture; +class GrXPFactory; namespace GrProcessorUnitTest { @@ -35,28 +41,32 @@ sk_sp MakeChildFP(GrProcessorTestData*); /* * GrProcessorTestData is an argument struct to TestCreate functions * fTextures are valid textures that can optionally be used to construct - * GrTextureAccesses. The first texture has config kSkia8888_GrPixelConfig and the second has + * TextureSampler. The first texture has config kSkia8888_GrPixelConfig and the second has * kAlpha_8_GrPixelConfig. TestCreate functions are also free to create additional textures using * the GrContext. */ struct GrProcessorTestData { GrProcessorTestData(SkRandom* random, GrContext* context, - const GrCaps* caps, - const GrDrawContext* drawContext, - GrTexture* textures[2]) - : fRandom(random) - , fContext(context) - , fCaps(caps) - , fDrawContext(drawContext) { - fTextures[0] = textures[0]; - fTextures[1] = textures[1]; + const GrRenderTargetContext* renderTargetContext, + sk_sp proxies[2]) + : fRandom(random) + , fRenderTargetContext(renderTargetContext) + , fContext(context) { + fProxies[0] = proxies[0]; + fProxies[1] = proxies[1]; } SkRandom* fRandom; + const GrRenderTargetContext* fRenderTargetContext; + + GrContext* context() { return fContext; } + GrResourceProvider* resourceProvider(); + const GrCaps* caps(); + sk_sp textureProxy(int index) { return fProxies[index]; } + +private: GrContext* fContext; - const GrCaps* fCaps; - const GrDrawContext* fDrawContext; - GrTexture* fTextures[2]; + sk_sp fProxies[2]; }; #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS @@ -64,7 +74,7 @@ struct GrProcessorTestData { class GrProcessor; class GrTexture; -template class GrProcessorTestFactory : SkNoncopyable { +template class GrProcessorTestFactory : private SkNoncopyable { public: typedef sk_sp (*MakeProc)(GrProcessorTestData*); @@ -87,20 +97,44 @@ public: /** Use factory function at Index idx to create a processor. */ static sk_sp MakeIdx(int idx, GrProcessorTestData* data) { GrProcessorTestFactory* factory = (*GetFactories())[idx]; - return factory->fMakeProc(data); + sk_sp processor = factory->fMakeProc(data); + SkASSERT(processor); + return processor; } - /* +private: + /** * A test function which verifies the count of factories. */ static void VerifyFactoryCount(); -private: MakeProc fMakeProc; static SkTArray*, true>* GetFactories(); }; +class GrXPFactoryTestFactory : private SkNoncopyable { +public: + using GetFn = const GrXPFactory*(GrProcessorTestData*); + + GrXPFactoryTestFactory(GetFn* getProc) : fGetProc(getProc) { GetFactories()->push_back(this); } + + static const GrXPFactory* Get(GrProcessorTestData* data) { + VerifyFactoryCount(); + SkASSERT(GetFactories()->count()); + uint32_t idx = data->fRandom->nextRangeU(0, GetFactories()->count() - 1); + const GrXPFactory* xpf = (*GetFactories())[idx]->fGetProc(data); + SkASSERT(xpf); + return xpf; + } + +private: + static void VerifyFactoryCount(); + + GetFn* fGetProc; + static SkTArray* GetFactories(); +}; + /** GrProcessor subclasses should insert this macro in their declaration to be included in the * program generation unit test. */ @@ -113,21 +147,21 @@ private: static sk_sp TestCreate(GrProcessorTestData*) #define GR_DECLARE_XP_FACTORY_TEST \ - static GrProcessorTestFactory gTestFactory SK_UNUSED; \ - static sk_sp TestCreate(GrProcessorTestData*) + static GrXPFactoryTestFactory gTestFactory SK_UNUSED; \ + static const GrXPFactory* TestGet(GrProcessorTestData*) /** GrProcessor subclasses should insert this macro in their implementation file. They must then * also implement this static function: * GrProcessor* TestCreate(GrProcessorTestData*); */ #define GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Effect) \ - GrProcessorTestFactory Effect :: gTestFactory(Effect :: TestCreate) - -#define GR_DEFINE_XP_FACTORY_TEST(Factory) \ - GrProcessorTestFactory Factory :: gTestFactory(Factory :: TestCreate) + GrProcessorTestFactory Effect::gTestFactory(Effect::TestCreate) #define GR_DEFINE_GEOMETRY_PROCESSOR_TEST(Effect) \ - GrProcessorTestFactory Effect :: gTestFactory(Effect :: TestCreate) + GrProcessorTestFactory Effect::gTestFactory(Effect::TestCreate) + +#define GR_DEFINE_XP_FACTORY_TEST(Factory) \ + GrXPFactoryTestFactory Factory::gTestFactory(Factory::TestGet) #else // !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS @@ -137,17 +171,31 @@ private: static sk_sp TestCreate(GrProcessorTestData*) #define GR_DEFINE_FRAGMENT_PROCESSOR_TEST(X) -// The unit test relies on static initializers. Just declare the TestCreate function so that -// its definitions will compile. -#define GR_DECLARE_XP_FACTORY_TEST \ - static sk_sp TestCreate(GrProcessorTestData*) -#define GR_DEFINE_XP_FACTORY_TEST(X) - // The unit test relies on static initializers. Just declare the TestCreate function so that // its definitions will compile. #define GR_DECLARE_GEOMETRY_PROCESSOR_TEST \ static sk_sp TestCreate(GrProcessorTestData*) #define GR_DEFINE_GEOMETRY_PROCESSOR_TEST(X) -#endif // !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS -#endif +// The unit test relies on static initializers. Just declare the TestGet function so that +// its definitions will compile. +#define GR_DECLARE_XP_FACTORY_TEST \ + const GrXPFactory* TestGet(GrProcessorTestData*) +#define GR_DEFINE_XP_FACTORY_TEST(X) + +#endif // !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS +#else // GR_TEST_UTILS + #define GR_DECLARE_GEOMETRY_PROCESSOR_TEST + #define GR_DECLARE_FRAGMENT_PROCESSOR_TEST + #define GR_DECLARE_XP_FACTORY_TEST + #define GR_DEFINE_FRAGMENT_PROCESSOR_TEST(...) + #define GR_DEFINE_GEOMETRY_PROCESSOR_TEST(...) + #define GR_DEFINE_XP_FACTORY_TEST(...) + #define GR_DECLARE_FRAGMENT_PROCESSOR_TEST + #define GR_DEFINE_FRAGMENT_PROCESSOR_TEST(...) + #define GR_DECLARE_GEOMETRY_PROCESSOR_TEST + #define GR_DEFINE_GEOMETRY_PROCESSOR_TEST(...) + #define GR_DECLARE_XP_FACTORY_TEST + #define GR_DEFINE_XP_FACTORY_TEST(...) +#endif // GR_TEST_UTILS +#endif // GrProcessorUnitTest_DEFINED diff --git a/gfx/skia/skia/include/gpu/GrProgramElement.h b/gfx/skia/skia/include/gpu/GrProgramElement.h index ba9daf71541c..425f57a59d5f 100644 --- a/gfx/skia/skia/include/gpu/GrProgramElement.h +++ b/gfx/skia/skia/include/gpu/GrProgramElement.h @@ -14,32 +14,30 @@ class GrGpuResourceRef; /** - * Base class for GrProcessor. This exists to manage transitioning a GrProcessor from being owned by - * a client to being scheduled for execution. While a GrProcessor is ref'ed by drawing code its - * GrGpu resources must also be ref'ed to prevent incorrectly recycling them through the cache. - * However, once the GrProcessor is baked into a GrPipeline and the drawing code has stopped ref'ing - * it, it's internal resources can be recycled in some cases. + * Note: We are converting GrProcessor from ref counting to a single owner model using move + * semantics. This class will be removed. * - * We track this using two types of refs on GrProgramElement. A regular ref is owned by any client - * that may continue to issue draws that use the GrProgramElement. The GrPipeline owns "pending - * executions" instead of refs. A pending execution is cleared by ~GrPipeline(). + * This is used to track "refs" for two separate types GrProcessor ownership. A regular ref is owned + * by any client that may continue to issue draws that use the GrProgramElement. A recorded op or + * GrPipeline uses "pending executions" instead of refs. A pending execution is cleared after the + * draw is executed (or aborted). * * While a GrProgramElement is ref'ed any resources it owns are also ref'ed. However, once it gets * into the state where it has pending executions AND no refs then it converts its ownership of * its GrGpuResources from refs to pending IOs. The pending IOs allow the cache to track when it is - * safe to recycle a resource even though we still have buffered GrBatches that read or write to the + * safe to recycle a resource even though we still have buffered GrOps that read or write to the * the resource. * - * To make this work all GrGpuResource objects owned by a GrProgramElement or derived classes - * (either directly or indirectly) must be wrapped in a GrGpuResourceRef and registered with the - * GrProgramElement using addGpuResource(). This allows the regular refs to be converted to pending - * IO events when the program element is scheduled for deferred execution. + * To make this work the subclass GrProcessor implements addPendingIOs, removeRefs, and + * pendingIOComplete. addPendingIOs adds pending reads/writes to GrGpuResources owned by the + * processor as appropriate when the processor is recorded in a GrOpList. removeRefs is called when + * the ref count reaches 0 and the GrProcessor is only owned by "pending executions". + * pendingIOComplete occurs if the resource is still owned by a ref but all recorded draws have been + * completed. Whenever pending executions and refs reach zero the processor is deleted. * - * Moreover, a GrProgramElement that in turn owns other GrProgramElements must convert its ownership - * of its children to pending executions when its ref count reaches zero so that the GrGpuResources - * owned by the children GrProgramElements are correctly converted from ownership by ref to - * ownership by pending IO. Any GrProgramElement hierarchy is managed by subclasses which must - * implement notifyRefCntIsZero() in order to convert refs of children to pending executions. + * The GrProcessor may also implement notifyRefCntIsZero in order to change its ownership of child + * processors from ref to pending execution when the processor is first owned exclusively in pending + * execution mode. */ class GrProgramElement : public SkNoncopyable { public: @@ -73,11 +71,6 @@ public: this->validate(); } - /** - * Gets an id that is unique for this GrProgramElement object. This will never return 0. - */ - uint32_t getUniqueID() const { return fUniqueID; } - void validate() const { #ifdef SK_DEBUG SkASSERT(fRefCnt >= 0); @@ -87,19 +80,10 @@ public: } protected: - GrProgramElement() : fRefCnt(1), fPendingExecutions(0), fUniqueID(CreateUniqueID()) {} - - /** Subclasses registers their resources using this function. It is assumed the GrProgramResouce - is and will remain owned by the subclass and this function will retain a raw ptr. Once a - GrGpuResourceRef is registered its setResource must not be called. - */ - void addGpuResource(const GrGpuResourceRef* res) { - fGpuResources.push_back(res); - } + GrProgramElement() : fRefCnt(1), fPendingExecutions(0) {} void addPendingExecution() const { this->validate(); - SkASSERT(fRefCnt > 0); if (0 == fPendingExecutions) { this->addPendingIOs(); } @@ -122,25 +106,21 @@ protected: } private: + virtual void addPendingIOs() const = 0; + virtual void removeRefs() const = 0; + virtual void pendingIOComplete() const = 0; + /** This will be called when the ref cnt is zero. The object may or may not have pending executions. */ virtual void notifyRefCntIsZero() const = 0; - static uint32_t CreateUniqueID(); - - void removeRefs() const; - void addPendingIOs() const; - void pendingIOComplete() const; - mutable int32_t fRefCnt; // Count of deferred executions not yet issued to the 3D API. mutable int32_t fPendingExecutions; - uint32_t fUniqueID; - SkSTArray<4, const GrGpuResourceRef*, true> fGpuResources; - - // Only this class can access addPendingExecution() and completedExecution(). + // Only these classes can access addPendingExecution() and completedExecution(). template friend class GrPendingProgramElement; + friend class GrProcessorSet; typedef SkNoncopyable INHERITED; }; diff --git a/gfx/skia/skia/include/gpu/GrRenderTarget.h b/gfx/skia/skia/include/gpu/GrRenderTarget.h index 1f87787d45dc..05d1239f849e 100644 --- a/gfx/skia/skia/include/gpu/GrRenderTarget.h +++ b/gfx/skia/skia/include/gpu/GrRenderTarget.h @@ -12,9 +12,9 @@ #include "SkRect.h" class GrCaps; -class GrDrawTarget; -class GrStencilAttachment; +class GrRenderTargetOpList; class GrRenderTargetPriv; +class GrStencilAttachment; /** * GrRenderTarget represents a 2D buffer of pixels that can be rendered to. @@ -86,12 +86,6 @@ public: */ const SkIRect& getResolveRect() const { return fResolveRect; } - /** - * Provide a performance hint that the render target's contents are allowed - * to become undefined. - */ - void discard(); - // a MSAA RT may require explicit resolving , it may auto-resolve (e.g. FBO // 0 in GL), or be unresolvable because the client didn't give us the // resolve destination. @@ -115,9 +109,6 @@ public: GrRenderTargetPriv renderTargetPriv(); const GrRenderTargetPriv renderTargetPriv() const; - void setLastDrawTarget(GrDrawTarget* dt); - GrDrawTarget* getLastDrawTarget() { return fLastDrawTarget; } - protected: enum class Flags { kNone = 0, @@ -129,7 +120,6 @@ protected: GrRenderTarget(GrGpu*, const GrSurfaceDesc&, Flags = Flags::kNone, GrStencilAttachment* = nullptr); - ~GrRenderTarget() override; // override of GrResource void onAbandon() override; @@ -143,6 +133,7 @@ private: virtual bool completeStencilAttachment() = 0; friend class GrRenderTargetPriv; + friend class GrRenderTargetProxy; // for Flags GrStencilAttachment* fStencilAttachment; uint8_t fMultisampleSpecsID; @@ -150,14 +141,6 @@ private: SkIRect fResolveRect; - // The last drawTarget that wrote to or is currently going to write to this renderTarget - // The drawTarget can be closed (e.g., no draw context is currently bound - // to this renderTarget). - // This back-pointer is required so that we can add a dependancy between - // the drawTarget used to create the current contents of this renderTarget - // and the drawTarget of a destination renderTarget to which this one is being drawn. - GrDrawTarget* fLastDrawTarget; - typedef GrSurface INHERITED; }; diff --git a/gfx/skia/skia/include/gpu/GrResourceKey.h b/gfx/skia/skia/include/gpu/GrResourceKey.h index 0ead35ea3f79..2e7edab5774b 100644 --- a/gfx/skia/skia/include/gpu/GrResourceKey.h +++ b/gfx/skia/skia/include/gpu/GrResourceKey.h @@ -9,10 +9,11 @@ #ifndef GrResourceKey_DEFINED #define GrResourceKey_DEFINED +#include "../private/SkOnce.h" #include "../private/SkTemplates.h" #include "GrTypes.h" #include "SkData.h" -#include "../private/SkOnce.h" +#include "SkString.h" uint32_t GrResourceKeyHash(const uint32_t* data, size_t size); @@ -138,8 +139,9 @@ private: friend class TestResource; // For unit test to access kMetaDataCnt. - // bmp textures require 5 uint32_t values. - SkAutoSTMalloc fKey; + // bmp textures require 7 uint32_t values (5 for the base key, and two more for image + // cacherator's decode format. + SkAutoSTMalloc fKey; }; /** @@ -239,6 +241,7 @@ public: GrUniqueKey& operator=(const GrUniqueKey& that) { this->INHERITED::operator=(that); this->setCustomData(sk_ref_sp(that.getCustomData())); + SkDEBUGCODE(fTag = that.fTag;) return *this; } @@ -254,21 +257,28 @@ public: return fData.get(); } + SkDEBUGCODE(const char* tag() const { return fTag.c_str(); }) + class Builder : public INHERITED::Builder { public: - Builder(GrUniqueKey* key, Domain domain, int data32Count) - : INHERITED::Builder(key, domain, data32Count) {} + Builder(GrUniqueKey* key, Domain type, int data32Count, const char* tag = nullptr) + : INHERITED::Builder(key, type, data32Count) { + SkDEBUGCODE(key->fTag = tag;) + (void) tag; // suppress unused named param warning. + } /** Used to build a key that wraps another key and adds additional data. */ - Builder(GrUniqueKey* key, const GrUniqueKey& innerKey, Domain domain, - int extraData32Cnt) - : INHERITED::Builder(key, domain, Data32CntForInnerKey(innerKey) + extraData32Cnt) { + Builder(GrUniqueKey* key, const GrUniqueKey& innerKey, Domain domain, int extraData32Cnt, + const char* tag = nullptr) + : INHERITED::Builder(key, domain, Data32CntForInnerKey(innerKey) + extraData32Cnt) { SkASSERT(&innerKey != key); // add the inner key to the end of the key so that op[] can be indexed normally. uint32_t* innerKeyData = &this->operator[](extraData32Cnt); const uint32_t* srcData = innerKey.data(); (*innerKeyData++) = innerKey.domain(); memcpy(innerKeyData, srcData, innerKey.dataSize()); + SkDEBUGCODE(key->fTag = tag;) + (void) tag; // suppress unused named param warning. } private: @@ -280,6 +290,7 @@ public: private: sk_sp fData; + SkDEBUGCODE(SkString fTag;) }; /** diff --git a/gfx/skia/skia/include/gpu/GrTextureParams.h b/gfx/skia/skia/include/gpu/GrSamplerParams.h similarity index 78% rename from gfx/skia/skia/include/gpu/GrTextureParams.h rename to gfx/skia/skia/include/gpu/GrSamplerParams.h index 3186b1b02718..512340e7bd42 100644 --- a/gfx/skia/skia/include/gpu/GrTextureParams.h +++ b/gfx/skia/skia/include/gpu/GrSamplerParams.h @@ -5,8 +5,8 @@ * found in the LICENSE file. */ -#ifndef GrTextureParams_DEFINED -#define GrTextureParams_DEFINED +#ifndef GrSamplerParams_DEFINED +#define GrSamplerParams_DEFINED #include "GrTypes.h" #include "SkShader.h" @@ -14,18 +14,18 @@ /** * Represents the filtering and tile modes used to access a texture. */ -class GrTextureParams { +class GrSamplerParams { public: - static const GrTextureParams& ClampNoFilter() { - static const GrTextureParams gParams; + static const GrSamplerParams& ClampNoFilter() { + static const GrSamplerParams gParams; return gParams; } - static const GrTextureParams& ClampBilerp() { - static const GrTextureParams gParams(SkShader::kClamp_TileMode, kBilerp_FilterMode); + static const GrSamplerParams& ClampBilerp() { + static const GrSamplerParams gParams(SkShader::kClamp_TileMode, kBilerp_FilterMode); return gParams; } - GrTextureParams() { + GrSamplerParams() { this->reset(); } @@ -35,19 +35,19 @@ public: kMipMap_FilterMode }; - GrTextureParams(SkShader::TileMode tileXAndY, FilterMode filterMode) { + GrSamplerParams(SkShader::TileMode tileXAndY, FilterMode filterMode) { this->reset(tileXAndY, filterMode); } - GrTextureParams(const SkShader::TileMode tileModes[2], FilterMode filterMode) { + GrSamplerParams(const SkShader::TileMode tileModes[2], FilterMode filterMode) { this->reset(tileModes, filterMode); } - GrTextureParams(const GrTextureParams& params) { + GrSamplerParams(const GrSamplerParams& params) { *this = params; } - GrTextureParams& operator= (const GrTextureParams& params) { + GrSamplerParams& operator= (const GrSamplerParams& params) { fTileModes[0] = params.fTileModes[0]; fTileModes[1] = params.fTileModes[1]; fFilterMode = params.fFilterMode; @@ -95,13 +95,13 @@ public: FilterMode filterMode() const { return fFilterMode; } - bool operator== (const GrTextureParams& other) const { + bool operator== (const GrSamplerParams& other) const { return fTileModes[0] == other.fTileModes[0] && fTileModes[1] == other.fTileModes[1] && fFilterMode == other.fFilterMode; } - bool operator!= (const GrTextureParams& other) const { return !(*this == other); } + bool operator!= (const GrSamplerParams& other) const { return !(*this == other); } private: SkShader::TileMode fTileModes[2]; diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.h b/gfx/skia/skia/include/gpu/GrShaderCaps.h similarity index 63% rename from gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.h rename to gfx/skia/skia/include/gpu/GrShaderCaps.h index ac409a36ba88..e52bcf1c8123 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.h +++ b/gfx/skia/skia/include/gpu/GrShaderCaps.h @@ -6,16 +6,52 @@ */ -#ifndef GrGLSLCaps_DEFINED -#define GrGLSLCaps_DEFINED +#ifndef GrShaderCaps_DEFINED +#define GrShaderCaps_DEFINED -#include "GrCaps.h" -#include "GrGLSL.h" -#include "GrSwizzle.h" +#include "../private/GrSwizzle.h" +#include "../private/GrGLSL.h" -class GrGLSLCaps : public GrShaderCaps { +namespace SkSL { + class ShaderCapsFactory; +} +struct GrContextOptions; + +class GrShaderCaps : public SkRefCnt { public: + /** Info about shader variable precision within a given shader stage. That is, this info + is relevant to a float (or vecNf) variable declared with a GrSLPrecision + in a given GrShaderType. The info here is hoisted from the OpenGL spec. */ + struct PrecisionInfo { + PrecisionInfo() { + fLogRangeLow = 0; + fLogRangeHigh = 0; + fBits = 0; + } + /** Is this precision level allowed in the shader stage? */ + bool supported() const { return 0 != fBits; } + + bool operator==(const PrecisionInfo& that) const { + return fLogRangeLow == that.fLogRangeLow && fLogRangeHigh == that.fLogRangeHigh && + fBits == that.fBits; + } + bool operator!=(const PrecisionInfo& that) const { return !(*this == that); } + + /** floor(log2(|min_value|)) */ + int fLogRangeLow; + /** floor(log2(|max_value|)) */ + int fLogRangeHigh; + /** Number of bits of precision. As defined in OpenGL (with names modified to reflect this + struct) : + """ + If the smallest representable value greater than 1 is 1 + e, then fBits will + contain floor(log2(e)), and every value in the range [2^fLogRangeLow, + 2^fLogRangeHigh] can be represented to at least one part in 2^fBits. + """ + */ + int fBits; + }; /** * Indicates how GLSL must interact with advanced blend equations. The KHR extension requires @@ -30,10 +66,36 @@ public: kLast_AdvBlendEqInteraction = kSpecificEnables_AdvBlendEqInteraction }; + GrShaderCaps(const GrContextOptions&); + + SkString dump() const; + + bool shaderDerivativeSupport() const { return fShaderDerivativeSupport; } + bool geometryShaderSupport() const { return fGeometryShaderSupport; } + bool pathRenderingSupport() const { return fPathRenderingSupport; } + bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; } + bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; } + bool integerSupport() const { return fIntegerSupport; } + bool texelBufferSupport() const { return fTexelBufferSupport; } + int imageLoadStoreSupport() const { return fImageLoadStoreSupport; } + /** - * Initializes the GrGLSLCaps to a default set of features - */ - GrGLSLCaps(const GrContextOptions&); + * Get the precision info for a variable of type kFloat_GrSLType, kVec2f_GrSLType, etc in a + * given shader type. If the shader type is not supported or the precision level is not + * supported in that shader type then the returned struct will report false when supported() is + * called. + */ + const PrecisionInfo& getFloatShaderPrecisionInfo(GrShaderType shaderType, + GrSLPrecision precision) const { + return fFloatPrecisions[shaderType][precision]; + } + + /** + * Is there any difference between the float shader variable precision types? If this is true + * then unless the shader type is not supported, any call to getFloatShaderPrecisionInfo() would + * report the same info for all precisions in all shader types. + */ + bool floatPrecisionVaries() const { return fShaderPrecisionVaries; } /** * Some helper functions for encapsulating various extensions to read FB Buffer on openglES @@ -84,15 +146,21 @@ public: bool usesPrecisionModifiers() const { return fUsesPrecisionModifiers; } - // Returns whether we can use the glsl funciton any() in our shader code. + // Returns whether we can use the glsl function any() in our shader code. bool canUseAnyFunctionInShader() const { return fCanUseAnyFunctionInShader; } bool canUseMinAndAbsTogether() const { return fCanUseMinAndAbsTogether; } bool mustForceNegatedAtanParamToFloat() const { return fMustForceNegatedAtanParamToFloat; } + // Returns whether a device incorrectly implements atan(y,x) as atan(y/x) + bool atan2ImplementedAsAtanYOverX() const { return fAtan2ImplementedAsAtanYOverX; } + bool requiresLocalOutputColorForFBFetch() const { return fRequiresLocalOutputColorForFBFetch; } + // On MacBook, geometry shaders break if they have more than one invocation. + bool mustImplementGSInvocationsWithLoop() const { return fMustImplementGSInvocationsWithLoop; } + // Returns the string of an extension that must be enabled in the shader to support // derivatives. If nullptr is returned then no extension needs to be enabled. Before calling // this function, the caller should check that shaderDerivativeSupport exists. @@ -142,6 +210,11 @@ public: return fSampleVariablesExtensionString; } + const char* imageLoadStoreExtensionString() const { + SkASSERT(this->imageLoadStoreSupport()); + return fImageLoadStoreExtensionString; + } + int maxVertexSamplers() const { return fMaxVertexSamplers; } int maxGeometrySamplers() const { return fMaxGeometrySamplers; } @@ -150,6 +223,14 @@ public: int maxCombinedSamplers() const { return fMaxCombinedSamplers; } + int maxVertexImageStorages() const { return fMaxVertexImageStorages; } + + int maxGeometryImageStorages() const { return fMaxGeometryImageStorages; } + + int maxFragmentImageStorages() const { return fMaxFragmentImageStorages; } + + int maxCombinedImageStorages() const { return fMaxCombinedImageStorages; } + /** * Given a texture's config, this determines what swizzle must be appended to accesses to the * texture in generated shader code. Swizzling may be implemented in texture parameters or a @@ -171,19 +252,23 @@ public: GrGLSLGeneration generation() const { return fGLSLGeneration; } - /** - * Returns a string containing the caps info. - */ - SkString dump() const override; - private: /** GrCaps subclasses must call this after filling in the shader precision table. */ void initSamplerPrecisionTable(); - void onApplyOptionsOverrides(const GrContextOptions& options) override; + void applyOptionsOverrides(const GrContextOptions& options); GrGLSLGeneration fGLSLGeneration; + bool fShaderDerivativeSupport : 1; + bool fGeometryShaderSupport : 1; + bool fPathRenderingSupport : 1; + bool fDstReadInShaderSupport : 1; + bool fDualSourceBlendingSupport : 1; + bool fIntegerSupport : 1; + bool fTexelBufferSupport : 1; + bool fImageLoadStoreSupport : 1; + bool fShaderPrecisionVaries : 1; bool fDropsTileOnZeroDivide : 1; bool fFBFetchSupport : 1; bool fFBFetchNeedsCustomOutput : 1; @@ -201,7 +286,11 @@ private: // Used for specific driver bug work arounds bool fCanUseMinAndAbsTogether : 1; bool fMustForceNegatedAtanParamToFloat : 1; + bool fAtan2ImplementedAsAtanYOverX : 1; bool fRequiresLocalOutputColorForFBFetch : 1; + bool fMustImplementGSInvocationsWithLoop : 1; + + PrecisionInfo fFloatPrecisions[kGrShaderTypeCount][kGrSLPrecisionCount]; const char* fVersionDeclString; @@ -213,6 +302,7 @@ private: const char* fNoPerspectiveInterpolationExtensionString; const char* fMultisampleInterpolationExtensionString; const char* fSampleVariablesExtensionString; + const char* fImageLoadStoreExtensionString; const char* fFBFetchColorName; const char* fFBFetchExtensionString; @@ -222,6 +312,11 @@ private: int fMaxFragmentSamplers; int fMaxCombinedSamplers; + int fMaxVertexImageStorages; + int fMaxGeometryImageStorages; + int fMaxFragmentImageStorages; + int fMaxCombinedImageStorages; + AdvBlendEqInteraction fAdvBlendEqInteraction; GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt]; @@ -231,8 +326,7 @@ private: friend class GrGLCaps; // For initialization. friend class GrVkCaps; - - typedef GrShaderCaps INHERITED; + friend class SkSL::ShaderCapsFactory; }; #endif diff --git a/gfx/skia/skia/include/gpu/GrShaderVar.h b/gfx/skia/skia/include/gpu/GrShaderVar.h index 78e08e0d9ab6..7f09f8cbf707 100644 --- a/gfx/skia/skia/include/gpu/GrShaderVar.h +++ b/gfx/skia/skia/include/gpu/GrShaderVar.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 Google Inc. + * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. @@ -8,104 +8,199 @@ #ifndef GrShaderVar_DEFINED #define GrShaderVar_DEFINED -#include "GrTypesPriv.h" #include "SkString.h" +#include "GrTypesPriv.h" +class GrShaderCaps; + +#define USE_UNIFORM_FLOAT_ARRAYS true + +/** + * Represents a variable in a shader + */ class GrShaderVar { public: - /** - * Early versions of GLSL have Varying and Attribute; those are later - * deprecated, but we still need to know whether a Varying variable - * should be treated as In or Out. - * - * TODO This really shouldn't live here, but until we have c++11, there is really no good way - * to write extensible enums. In reality, only none, out, in, inout, and uniform really - * make sense on this base class - */ enum TypeModifier { kNone_TypeModifier, kOut_TypeModifier, kIn_TypeModifier, kInOut_TypeModifier, kUniform_TypeModifier, - // GL Specific types below - kAttribute_TypeModifier, - kVaryingIn_TypeModifier, - kVaryingOut_TypeModifier }; /** - * Defaults to a float with no precision specifier - */ - GrShaderVar() - : fType(kFloat_GrSLType) - , fTypeModifier(kNone_TypeModifier) - , fCount(kNonArray) - , fPrecision(kDefault_GrSLPrecision) { - } - - GrShaderVar(const SkString& name, GrSLType type, int arrayCount = kNonArray, - GrSLPrecision precision = kDefault_GrSLPrecision) - : fType(type) - , fTypeModifier(kNone_TypeModifier) - , fName(name) - , fCount(arrayCount) - , fPrecision(precision) { - SkASSERT(kVoid_GrSLType != type); - } - - GrShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray, - GrSLPrecision precision = kDefault_GrSLPrecision) - : fType(type) - , fTypeModifier(kNone_TypeModifier) - , fName(name) - , fCount(arrayCount) - , fPrecision(precision) { - SkASSERT(kVoid_GrSLType != type); - } - - GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier, - int arrayCount = kNonArray, GrSLPrecision precision = kDefault_GrSLPrecision) - : fType(type) - , fTypeModifier(typeModifier) - , fName(name) - , fCount(arrayCount) - , fPrecision(precision) { - SkASSERT(kVoid_GrSLType != type); - } - - /** - * Values for array count that have special meaning. We allow 1-sized arrays. + * Values for array count that have special meaning. We allow 1-sized arrays.git */ enum { kNonArray = 0, // not an array kUnsizedArray = -1, // an unsized array (declared with []) }; + /** + * Defaults to a non-arry float with no precision specifier, type modifier, or layout qualifier. + */ + GrShaderVar() + : fType(kFloat_GrSLType) + , fTypeModifier(kNone_TypeModifier) + , fCount(kNonArray) + , fPrecision(kDefault_GrSLPrecision) + , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) { + } + + GrShaderVar(const SkString& name, GrSLType type, int arrayCount = kNonArray, + GrSLPrecision precision = kDefault_GrSLPrecision) + : fType(type) + , fTypeModifier(kNone_TypeModifier) + , fCount(arrayCount) + , fPrecision(precision) + , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) + , fName(name) { + SkASSERT(kVoid_GrSLType != type); + fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS; + } + + GrShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray, + GrSLPrecision precision = kDefault_GrSLPrecision) + : fType(type) + , fTypeModifier(kNone_TypeModifier) + , fCount(arrayCount) + , fPrecision(precision) + , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) + , fName(name) { + SkASSERT(kVoid_GrSLType != type); + fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS; + } + + GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier, + GrSLPrecision precision = kDefault_GrSLPrecision) + : fType(type) + , fTypeModifier(typeModifier) + , fCount(kNonArray) + , fPrecision(precision) + , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) + , fName(name) { + SkASSERT(kVoid_GrSLType != type); + } + + GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier, + int arrayCount, GrSLPrecision precision = kDefault_GrSLPrecision) + : fType(type) + , fTypeModifier(typeModifier) + , fCount(arrayCount) + , fPrecision(precision) + , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) + , fName(name) { + SkASSERT(kVoid_GrSLType != type); + } + + GrShaderVar(const GrShaderVar& that) + : fType(that.fType) + , fTypeModifier(that.fTypeModifier) + , fCount(that.fCount) + , fPrecision(that.fPrecision) + , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) + , fName(that.fName) + , fLayoutQualifier(that.fLayoutQualifier) + , fExtraModifiers(that.fExtraModifiers) { + SkASSERT(kVoid_GrSLType != that.getType()); + } + + /** + * Sets as a non-array. + */ void set(GrSLType type, const SkString& name, TypeModifier typeModifier = kNone_TypeModifier, GrSLPrecision precision = kDefault_GrSLPrecision, - int count = kNonArray) { + const char* layoutQualifier = nullptr, + const char* extraModifiers = nullptr, + bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { SkASSERT(kVoid_GrSLType != type); + SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type)); fType = type; fTypeModifier = typeModifier; fName = name; - fCount = count; + fCount = kNonArray; fPrecision = precision; + fLayoutQualifier = layoutQualifier; + if (extraModifiers) { + fExtraModifiers.printf("%s ", extraModifiers); + } + fUseUniformFloatArrays = useUniformFloatArrays; } + /** + * Sets as a non-array. + */ void set(GrSLType type, const char* name, TypeModifier typeModifier = kNone_TypeModifier, GrSLPrecision precision = kDefault_GrSLPrecision, - int count = kNonArray) { + const char* layoutQualifier = nullptr, + const char* extraModifiers = nullptr, + bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { SkASSERT(kVoid_GrSLType != type); + SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type)); + fType = type; + fTypeModifier = typeModifier; + fName = name; + fCount = kNonArray; + fPrecision = precision; + fLayoutQualifier = layoutQualifier; + if (extraModifiers) { + fExtraModifiers.printf("%s ", extraModifiers); + } + fUseUniformFloatArrays = useUniformFloatArrays; + } + + /** + * Set all var options + */ + void set(GrSLType type, + const SkString& name, + int count, + TypeModifier typeModifier, + GrSLPrecision precision = kDefault_GrSLPrecision, + const char* layoutQualifier = nullptr, + const char* extraModifiers = nullptr, + bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { + SkASSERT(kVoid_GrSLType != type); + SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type)); fType = type; fTypeModifier = typeModifier; fName = name; fCount = count; fPrecision = precision; + fLayoutQualifier = layoutQualifier; + if (extraModifiers) { + fExtraModifiers.printf("%s ", extraModifiers); + } + fUseUniformFloatArrays = useUniformFloatArrays; + } + + /** + * Set all var options + */ + void set(GrSLType type, + const char* name, + int count, + TypeModifier typeModifier, + GrSLPrecision precision = kDefault_GrSLPrecision, + const char* layoutQualifier = nullptr, + const char* extraModifiers = nullptr, + bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { + SkASSERT(kVoid_GrSLType != type); + SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type)); + fType = type; + fTypeModifier = typeModifier; + fName = name; + fCount = count; + fPrecision = precision; + fLayoutQualifier = layoutQualifier; + if (extraModifiers) { + fExtraModifiers.printf("%s ", extraModifiers); + } + fUseUniformFloatArrays = useUniformFloatArrays; } /** @@ -175,12 +270,65 @@ public: */ void setPrecision(GrSLPrecision p) { fPrecision = p; } -protected: + /** + * Appends to the layout qualifier + */ + void addLayoutQualifier(const char* layoutQualifier) { + if (!layoutQualifier || !strlen(layoutQualifier)) { + return; + } + if (fLayoutQualifier.isEmpty()) { + fLayoutQualifier = layoutQualifier; + } else { + fLayoutQualifier.appendf(", %s", layoutQualifier); + } + } + + void setImageStorageFormat(GrImageStorageFormat format); + + void setMemoryModel(GrSLMemoryModel); + + void setRestrict(GrSLRestrict); + + void setIOType(GrIOType); + + void addModifier(const char* modifier) { + if (modifier) { + fExtraModifiers.appendf("%s ", modifier); + } + } + + /** + * Write a declaration of this variable to out. + */ + void appendDecl(const GrShaderCaps*, SkString* out) const; + + void appendArrayAccess(int index, SkString* out) const { + out->appendf("%s[%d]%s", + this->getName().c_str(), + index, + fUseUniformFloatArrays ? "" : ".x"); + } + + void appendArrayAccess(const char* indexName, SkString* out) const { + out->appendf("%s[%s]%s", + this->getName().c_str(), + indexName, + fUseUniformFloatArrays ? "" : ".x"); + } + +private: GrSLType fType; TypeModifier fTypeModifier; - SkString fName; int fCount; GrSLPrecision fPrecision; + /// Work around driver bugs on some hardware that don't correctly + /// support uniform float [] + bool fUseUniformFloatArrays; + + SkString fName; + SkString fLayoutQualifier; + SkString fExtraModifiers; }; #endif diff --git a/gfx/skia/skia/include/gpu/GrSurface.h b/gfx/skia/skia/include/gpu/GrSurface.h index ac5c5fa1bbcd..81bc215c0180 100644 --- a/gfx/skia/skia/include/gpu/GrSurface.h +++ b/gfx/skia/skia/include/gpu/GrSurface.h @@ -14,6 +14,7 @@ #include "SkImageInfo.h" #include "SkRect.h" +class GrOpList; class GrRenderTarget; class GrSurfacePriv; class GrTexture; @@ -65,54 +66,6 @@ public: virtual GrRenderTarget* asRenderTarget() { return NULL; } virtual const GrRenderTarget* asRenderTarget() const { return NULL; } - /** - * Reads a rectangle of pixels from the surface. - * @param left left edge of the rectangle to read (inclusive) - * @param top top edge of the rectangle to read (inclusive) - * @param width width of rectangle to read in pixels. - * @param height height of rectangle to read in pixels. - * @param config the pixel config of the destination buffer - * @param buffer memory to read the rectangle into. - * @param rowBytes number of bytes between consecutive rows. Zero means rows are tightly - * packed. - * @param pixelOpsFlags See the GrContext::PixelOpsFlags enum. - * - * @return true if the read succeeded, false if not. The read can fail because of an unsupported - * pixel config. - */ - bool readPixels(int left, int top, int width, int height, - GrPixelConfig config, - void* buffer, - size_t rowBytes = 0, - uint32_t pixelOpsFlags = 0); - - /** - * Copy the src pixels [buffer, rowbytes, pixelconfig] into the surface at the specified - * rectangle. - * @param left left edge of the rectangle to write (inclusive) - * @param top top edge of the rectangle to write (inclusive) - * @param width width of rectangle to write in pixels. - * @param height height of rectangle to write in pixels. - * @param config the pixel config of the source buffer - * @param buffer memory to read the rectangle from. - * @param rowBytes number of bytes between consecutive rows. Zero means rows are tightly - * packed. - * @param pixelOpsFlags See the GrContext::PixelOpsFlags enum. - * - * @return true if the write succeeded, false if not. The write can fail because of an - * unsupported pixel config. - */ - bool writePixels(int left, int top, int width, int height, - GrPixelConfig config, - const void* buffer, - size_t rowBytes = 0, - uint32_t pixelOpsFlags = 0); - - /** - * After this returns any pending writes to the surface will be issued to the backend 3D API. - */ - void flushWrites(); - /** Access methods that are only to be used within Skia code. */ inline GrSurfacePriv surfacePriv(); inline const GrSurfacePriv surfacePriv() const; @@ -125,11 +78,15 @@ public: fReleaseCtx = ctx; } - static size_t WorstCaseSize(const GrSurfaceDesc& desc); + void setLastOpList(GrOpList* opList); + GrOpList* getLastOpList() { return fLastOpList; } + + static size_t WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2 = false); + static size_t ComputeSize(const GrSurfaceDesc& desc, int colorSamplesPerPixel, + bool hasMIPMaps, bool useNextPow2 = false); protected: // Methods made available via GrSurfacePriv - bool savePixels(const char* filename); bool hasPendingRead() const; bool hasPendingWrite() const; bool hasPendingIO() const; @@ -142,12 +99,9 @@ protected: , fDesc(desc) , fReleaseProc(NULL) , fReleaseCtx(NULL) - {} - - ~GrSurface() override { - // check that invokeReleaseProc has been called (if needed) - SkASSERT(NULL == fReleaseProc); + , fLastOpList(nullptr) { } + ~GrSurface() override; GrSurfaceDesc fDesc; @@ -165,6 +119,14 @@ private: ReleaseProc fReleaseProc; ReleaseCtx fReleaseCtx; + // The last opList that wrote to or is currently going to write to this surface + // The opList can be closed (e.g., no render target or texture context is currently bound + // to this renderTarget or texture). + // This back-pointer is required so that we can add a dependancy between + // the opList used to create the current contents of this surface + // and the opList of a destination surface to which this one is being drawn or copied. + GrOpList* fLastOpList; + typedef GrGpuResource INHERITED; }; diff --git a/gfx/skia/skia/include/gpu/GrTestUtils.h b/gfx/skia/skia/include/gpu/GrTestUtils.h index 17bf12af30cc..5bb1cc173807 100644 --- a/gfx/skia/skia/include/gpu/GrTestUtils.h +++ b/gfx/skia/skia/include/gpu/GrTestUtils.h @@ -10,15 +10,17 @@ #include "SkTypes.h" -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS #include "GrColor.h" #include "GrColorSpaceXform.h" #include "SkPathEffect.h" #include "SkRandom.h" +#include "SkShader.h" #include "SkStrokeRec.h" #include "../private/SkTemplates.h" +struct GrProcessorTestData; class GrStyle; class SkMatrix; class SkPath; @@ -45,6 +47,17 @@ void TestStyle(SkRandom*, GrStyle*); sk_sp TestColorSpace(SkRandom*); sk_sp TestColorXform(SkRandom*); +class TestAsFPArgs { +public: + TestAsFPArgs(GrProcessorTestData*); + const SkShader::AsFPArgs& args() const { return fArgs; } + +private: + SkShader::AsFPArgs fArgs; + SkMatrix fViewMatrixStorage; + sk_sp fColorSpaceStorage; +}; + // We have a simplified dash path effect here to avoid relying on SkDashPathEffect which // is in the optional build target effects. class TestDashPathEffect : public SkPathEffect { diff --git a/gfx/skia/skia/include/gpu/GrTexture.h b/gfx/skia/skia/include/gpu/GrTexture.h index 211f1937da72..1f63958d2825 100644 --- a/gfx/skia/skia/include/gpu/GrTexture.h +++ b/gfx/skia/skia/include/gpu/GrTexture.h @@ -10,17 +10,17 @@ #define GrTexture_DEFINED #include "GrSurface.h" +#include "GrSamplerParams.h" #include "SkPoint.h" #include "SkRefCnt.h" -class GrTextureParams; +class GrExternalTextureData; class GrTexturePriv; class GrTexture : virtual public GrSurface { public: GrTexture* asTexture() override { return this; } const GrTexture* asTexture() const override { return this; } - GrSLType samplerType() const { return fSamplerType; } /** * Return the native ID or handle to the texture, depending on the @@ -46,9 +46,11 @@ public: inline const GrTexturePriv texturePriv() const; protected: - GrTexture(GrGpu*, const GrSurfaceDesc&, GrSLType, bool wasMipMapDataProvided); + GrTexture(GrGpu*, const GrSurfaceDesc&, GrSLType samplerType, + GrSamplerParams::FilterMode highestFilterMode, bool wasMipMapDataProvided); void validateDesc() const; + virtual std::unique_ptr detachBackendTexture() = 0; private: void computeScratchKey(GrScratchKey*) const override; @@ -61,11 +63,11 @@ private: kValid_MipMapsStatus }; - GrSLType fSamplerType; - MipMapsStatus fMipMapsStatus; - int fMaxMipMapLevel; - SkSourceGammaTreatment fGammaTreatment; - + GrSLType fSamplerType; + GrSamplerParams::FilterMode fHighestFilterMode; + MipMapsStatus fMipMapsStatus; + int fMaxMipMapLevel; + SkDestinationSurfaceColorMode fMipColorMode; friend class GrTexturePriv; typedef GrSurface INHERITED; diff --git a/gfx/skia/skia/include/gpu/GrTextureAccess.h b/gfx/skia/skia/include/gpu/GrTextureAccess.h deleted file mode 100644 index 1b5de0ce99cc..000000000000 --- a/gfx/skia/skia/include/gpu/GrTextureAccess.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrTextureAccess_DEFINED -#define GrTextureAccess_DEFINED - -#include "GrGpuResourceRef.h" -#include "GrTexture.h" -#include "GrTextureParams.h" -#include "SkRefCnt.h" -#include "SkShader.h" - -/** - * Used to represent a texture that is required by a GrProcessor. It holds a GrTexture along with - * an associated GrTextureParams - */ -class GrTextureAccess : public SkNoncopyable { -public: - /** - * Must be initialized before adding to a GrProcessor's texture access list. - */ - GrTextureAccess(); - - GrTextureAccess(GrTexture*, const GrTextureParams&); - - explicit GrTextureAccess(GrTexture*, - GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, - SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode, - GrShaderFlags visibility = kFragment_GrShaderFlag); - - void reset(GrTexture*, const GrTextureParams&, - GrShaderFlags visibility = kFragment_GrShaderFlag); - void reset(GrTexture*, - GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, - SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode, - GrShaderFlags visibility = kFragment_GrShaderFlag); - - bool operator==(const GrTextureAccess& that) const { - return this->getTexture() == that.getTexture() && - fParams == that.fParams && - fVisibility == that.fVisibility; - } - - bool operator!=(const GrTextureAccess& other) const { return !(*this == other); } - - GrTexture* getTexture() const { return fTexture.get(); } - GrShaderFlags getVisibility() const { return fVisibility; } - - /** - * For internal use by GrProcessor. - */ - const GrGpuResourceRef* getProgramTexture() const { return &fTexture; } - - const GrTextureParams& getParams() const { return fParams; } - -private: - - typedef GrTGpuResourceRef ProgramTexture; - - ProgramTexture fTexture; - GrTextureParams fParams; - GrShaderFlags fVisibility; - - typedef SkNoncopyable INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/gpu/GrTextureProvider.h b/gfx/skia/skia/include/gpu/GrTextureProvider.h deleted file mode 100644 index e013bfff0fa7..000000000000 --- a/gfx/skia/skia/include/gpu/GrTextureProvider.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrTextureProvider_DEFINED -#define GrTextureProvider_DEFINED - -#include "GrTexture.h" -#include "GrTypes.h" - -class GrSingleOwner; - -class SK_API GrTextureProvider { -public: - /////////////////////////////////////////////////////////////////////////// - // Textures - - /** - * Creates a new texture in the resource cache and returns it. The caller owns a - * ref on the returned texture which must be balanced by a call to unref. - * - * @param desc Description of the texture properties. - * @param budgeted Does the texture count against the resource cache budget? - * @param texels A contiguous array of mipmap levels - * @param mipLevelCount The amount of elements in the texels array - */ - GrTexture* createMipMappedTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, - const GrMipLevel* texels, int mipLevelCount); - - /** - * This function is a shim which creates a SkTArray of size 1. - * It then calls createTexture with that SkTArray. - * - * @param srcData Pointer to the pixel values (optional). - * @param rowBytes The number of bytes between rows of the texture. Zero - * implies tightly packed rows. For compressed pixel configs, this - * field is ignored. - */ - GrTexture* createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, const void* srcData, - size_t rowBytes); - - /** Shortcut for creating a texture with no initial data to upload. */ - GrTexture* createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted) { - return this->createTexture(desc, budgeted, nullptr, 0); - } - - /** Assigns a unique key to the texture. The texture will be findable via this key using - findTextureByUniqueKey(). If an existing texture has this key, it's key will be removed. */ - void assignUniqueKeyToTexture(const GrUniqueKey& key, GrTexture* texture) { - this->assignUniqueKeyToResource(key, texture); - } - - /** Finds a texture by unique key. If the texture is found it is ref'ed and returned. */ - GrTexture* findAndRefTextureByUniqueKey(const GrUniqueKey& key); - - /** - * Determines whether a texture is associated with the unique key. If the texture is found it - * will not be locked or returned. This call does not affect the priority of the resource for - * deletion. - */ - bool existsTextureWithUniqueKey(const GrUniqueKey& key) const { - return this->existsResourceWithUniqueKey(key); - } - - /** - * Finds a texture that approximately matches the descriptor. Will be at least as large in width - * and height as desc specifies. If desc specifies that the texture should be a render target - * then result will be a render target. Format and sample count will always match the request. - * The contents of the texture are undefined. The caller owns a ref on the returned texture and - * must balance with a call to unref. - */ - GrTexture* createApproxTexture(const GrSurfaceDesc&); - - /** Legacy function that no longer should be used. */ - enum ScratchTexMatch { - kExact_ScratchTexMatch, - kApprox_ScratchTexMatch - }; - GrTexture* refScratchTexture(const GrSurfaceDesc& desc, ScratchTexMatch match) { - if (kApprox_ScratchTexMatch == match) { - return this->createApproxTexture(desc); - } else { - return this->createTexture(desc, SkBudgeted::kYes); - } - } - - /////////////////////////////////////////////////////////////////////////// - // Wrapped Backend Surfaces - - /** - * Wraps an existing texture with a GrTexture object. - * - * OpenGL: if the object is a texture Gr may change its GL texture params - * when it is drawn. - * - * @return GrTexture object or NULL on failure. - */ - GrTexture* wrapBackendTexture(const GrBackendTextureDesc& desc, - GrWrapOwnership = kBorrow_GrWrapOwnership); - - /** - * Wraps an existing render target with a GrRenderTarget object. It is - * similar to wrapBackendTexture but can be used to draw into surfaces - * that are not also textures (e.g. FBO 0 in OpenGL, or an MSAA buffer that - * the client will resolve to a texture). Currently wrapped render targets - * always use the kBorrow_GrWrapOwnership semantics. - * - * @return GrRenderTarget object or NULL on failure. - */ - GrRenderTarget* wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc); - -protected: - GrTextureProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* singleOwner); - - /** - * Assigns a unique key to a resource. If the key is associated with another resource that - * association is removed and replaced by this resource. - */ - void assignUniqueKeyToResource(const GrUniqueKey&, GrGpuResource*); - - /** - * Finds a resource in the cache, based on the specified key. This is intended for use in - * conjunction with addResourceToCache(). The return value will be NULL if not found. The - * caller must balance with a call to unref(). - */ - GrGpuResource* findAndRefResourceByUniqueKey(const GrUniqueKey&); - - /** - * Determines whether a resource is in the cache. If the resource is found it - * will not be locked or returned. This call does not affect the priority of - * the resource for deletion. - */ - bool existsResourceWithUniqueKey(const GrUniqueKey& key) const; - - enum ScratchTextureFlags { - kExact_ScratchTextureFlag = 0x1, - kNoPendingIO_ScratchTextureFlag = 0x2, // (http://skbug.com/4156) - kNoCreate_ScratchTextureFlag = 0x4, - }; - - /** A common impl for GrTextureProvider and GrResourceProvider variants. */ - GrTexture* internalCreateApproxTexture(const GrSurfaceDesc& desc, uint32_t scratchTextureFlags); - - GrTexture* refScratchTexture(const GrSurfaceDesc&, uint32_t scratchTextureFlags); - - void abandon() { - fCache = NULL; - fGpu = NULL; - } - - GrResourceCache* cache() { return fCache; } - const GrResourceCache* cache() const { return fCache; } - - GrGpu* gpu() { return fGpu; } - const GrGpu* gpu() const { return fGpu; } - - bool isAbandoned() const { - SkASSERT(SkToBool(fGpu) == SkToBool(fCache)); - return !SkToBool(fCache); - } - -private: - GrResourceCache* fCache; - GrGpu* fGpu; - - // In debug builds we guard against improper thread handling - SkDEBUGCODE(mutable GrSingleOwner* fSingleOwner;) -}; - -#endif diff --git a/gfx/skia/skia/include/gpu/GrTypes.h b/gfx/skia/skia/include/gpu/GrTypes.h index 6b73f3c073de..62e8a791b318 100644 --- a/gfx/skia/skia/include/gpu/GrTypes.h +++ b/gfx/skia/skia/include/gpu/GrTypes.h @@ -19,56 +19,109 @@ * bitfield. */ #define GR_MAKE_BITFIELD_OPS(X) \ - inline X operator | (X a, X b) { \ + inline X operator |(X a, X b) { \ return (X) (+a | +b); \ } \ - inline X& operator |= (X& a, X b) { \ + inline X& operator |=(X& a, X b) { \ return (a = a | b); \ } \ - \ - inline X operator & (X a, X b) { \ + inline X operator &(X a, X b) { \ + return (X) (+a & +b); \ + } \ + inline X& operator &=(X& a, X b) { \ + return (a = a & b); \ + } \ + template \ + inline X operator &(T a, X b) { \ return (X) (+a & +b); \ } \ template \ - inline X operator & (T a, X b) { \ - return (X) (+a & +b); \ - } \ - template \ - inline X operator & (X a, T b) { \ + inline X operator &(X a, T b) { \ return (X) (+a & +b); \ } \ #define GR_DECL_BITFIELD_OPS_FRIENDS(X) \ - friend X operator | (X a, X b); \ - friend X& operator |= (X& a, X b); \ + friend X operator |(X a, X b); \ + friend X& operator |=(X& a, X b); \ \ - friend X operator & (X a, X b); \ + friend X operator &(X a, X b); \ + friend X& operator &=(X& a, X b); \ \ template \ - friend X operator & (T a, X b); \ + friend X operator &(T a, X b); \ \ template \ - friend X operator & (X a, T b); \ + friend X operator &(X a, T b); \ + +/** + * Wraps a C++11 enum that we use as a bitfield, and enables a limited amount of + * masking with type safety. Instantiated with the ~ operator. + */ +template class GrTFlagsMask { +public: + constexpr explicit GrTFlagsMask(TFlags value) : GrTFlagsMask(static_cast(value)) {} + constexpr explicit GrTFlagsMask(int value) : fValue(value) {} + constexpr int value() const { return fValue; } +private: + const int fValue; +}; + +// Or-ing a mask always returns another mask. +template constexpr GrTFlagsMask operator|(GrTFlagsMask a, + GrTFlagsMask b) { + return GrTFlagsMask(a.value() | b.value()); +} +template constexpr GrTFlagsMask operator|(GrTFlagsMask a, + TFlags b) { + return GrTFlagsMask(a.value() | static_cast(b)); +} +template constexpr GrTFlagsMask operator|(TFlags a, + GrTFlagsMask b) { + return GrTFlagsMask(static_cast(a) | b.value()); +} +template inline GrTFlagsMask& operator|=(GrTFlagsMask& a, + GrTFlagsMask b) { + return (a = a | b); +} + +// And-ing two masks returns another mask; and-ing one with regular flags returns flags. +template constexpr GrTFlagsMask operator&(GrTFlagsMask a, + GrTFlagsMask b) { + return GrTFlagsMask(a.value() & b.value()); +} +template constexpr TFlags operator&(GrTFlagsMask a, TFlags b) { + return static_cast(a.value() & static_cast(b)); +} +template constexpr TFlags operator&(TFlags a, GrTFlagsMask b) { + return static_cast(static_cast(a) & b.value()); +} +template inline TFlags& operator&=(TFlags& a, GrTFlagsMask b) { + return (a = a & b); +} /** * Defines bitwise operators that make it possible to use an enum class as a - * very basic bitfield. + * basic bitfield. */ #define GR_MAKE_BITFIELD_CLASS_OPS(X) \ - inline X operator | (X a, X b) { \ - return (X) ((int)a | (int)b); \ + constexpr GrTFlagsMask operator~(X a) { \ + return GrTFlagsMask(~static_cast(a)); \ } \ - inline X& operator |= (X& a, X b) { \ + constexpr X operator|(X a, X b) { \ + return static_cast(static_cast(a) | static_cast(b)); \ + } \ + inline X& operator|=(X& a, X b) { \ return (a = a | b); \ } \ - inline bool operator & (X a, X b) { \ - return SkToBool((int)a & (int)b); \ - } + constexpr bool operator&(X a, X b) { \ + return SkToBool(static_cast(a) & static_cast(b)); \ + } \ #define GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(X) \ - friend X operator | (X a, X b); \ - friend X& operator |= (X& a, X b); \ - friend bool operator & (X a, X b); + friend constexpr GrTFlagsMask operator ~(X); \ + friend constexpr X operator |(X, X); \ + friend X& operator |=(X&, X); \ + friend constexpr bool operator &(X, X); //////////////////////////////////////////////////////////////////////////////// @@ -148,6 +201,18 @@ typedef intptr_t GrBackendContext; /////////////////////////////////////////////////////////////////////////////// +/** + * Used to control antialiasing in draw calls. + */ +enum class GrAA { + kYes, + kNo +}; + +static inline GrAA GrBoolToAA(bool aa) { return aa ? GrAA::kYes : GrAA::kNo; } + +/////////////////////////////////////////////////////////////////////////////// + /** * Geometric primitives used for drawing. */ @@ -207,7 +272,7 @@ static inline int GrMaskFormatBytesPerPixel(GrMaskFormat format) { enum GrPixelConfig { kUnknown_GrPixelConfig, kAlpha_8_GrPixelConfig, - kIndex_8_GrPixelConfig, + kGray_8_GrPixelConfig, kRGB_565_GrPixelConfig, /** * Premultiplied @@ -229,36 +294,22 @@ enum GrPixelConfig { * Premultiplied and sRGB. Byte order is b,g,r,a. */ kSBGRA_8888_GrPixelConfig, + /** + * 8 bit signed integers per-channel. Byte order is b,g,r,a. + */ + kRGBA_8888_sint_GrPixelConfig, /** * ETC1 Compressed Data */ kETC1_GrPixelConfig, - /** - * LATC/RGTC/3Dc/BC4 Compressed Data - */ - kLATC_GrPixelConfig, - /** - * R11 EAC Compressed Data - * (Corresponds to section C.3.5 of the OpenGL 4.4 core profile spec) - */ - kR11_EAC_GrPixelConfig, - - /** - * 12x12 ASTC Compressed Data - * ASTC stands for Adaptive Scalable Texture Compression. It is a technique - * that allows for a lot of customization in the compressed representataion - * of a block. The only thing fixed in the representation is the block size, - * which means that a texture that contains ASTC data must be treated as - * having RGBA values. However, there are single-channel encodings which set - * the alpha to opaque and all three RGB channels equal effectively making the - * compression format a single channel such as R11 EAC and LATC. - */ - kASTC_12x12_GrPixelConfig, - /** * Byte order is r, g, b, a. This color format is 32 bits per channel */ kRGBA_float_GrPixelConfig, + /** + * Byte order is r, g. This color format is 32 bits per channel + */ + kRG_float_GrPixelConfig, /** * This color format is a single 16 bit float channel @@ -280,10 +331,8 @@ static const int kGrPixelConfigCnt = kLast_GrPixelConfig + 1; #endif #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A) static const GrPixelConfig kSkia8888_GrPixelConfig = kBGRA_8888_GrPixelConfig; - static const GrPixelConfig kSkiaGamma8888_GrPixelConfig = kSBGRA_8888_GrPixelConfig; #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A) static const GrPixelConfig kSkia8888_GrPixelConfig = kRGBA_8888_GrPixelConfig; - static const GrPixelConfig kSkiaGamma8888_GrPixelConfig = kSRGBA_8888_GrPixelConfig; #else #error "SK_*32_SHIFT values must correspond to GL_BGRA or GL_RGBA format." #endif @@ -292,44 +341,77 @@ static const int kGrPixelConfigCnt = kLast_GrPixelConfig + 1; // representation. static inline bool GrPixelConfigIsCompressed(GrPixelConfig config) { switch (config) { - case kIndex_8_GrPixelConfig: case kETC1_GrPixelConfig: - case kLATC_GrPixelConfig: - case kR11_EAC_GrPixelConfig: - case kASTC_12x12_GrPixelConfig: return true; - default: + case kUnknown_GrPixelConfig: + case kAlpha_8_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kRGBA_half_GrPixelConfig: return false; } + SkFAIL("Invalid pixel config"); + return false; } /** If the pixel config is compressed, return an equivalent uncompressed format. */ static inline GrPixelConfig GrMakePixelConfigUncompressed(GrPixelConfig config) { switch (config) { - case kIndex_8_GrPixelConfig: case kETC1_GrPixelConfig: - case kASTC_12x12_GrPixelConfig: return kRGBA_8888_GrPixelConfig; - case kLATC_GrPixelConfig: - case kR11_EAC_GrPixelConfig: - return kAlpha_8_GrPixelConfig; - default: + case kUnknown_GrPixelConfig: + case kAlpha_8_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kRGBA_half_GrPixelConfig: SkASSERT(!GrPixelConfigIsCompressed(config)); return config; } + SkFAIL("Invalid pixel config"); + return config; } // Returns true if the pixel config is 32 bits per pixel -static inline bool GrPixelConfigIs8888(GrPixelConfig config) { +static inline bool GrPixelConfigIs8888Unorm(GrPixelConfig config) { switch (config) { case kRGBA_8888_GrPixelConfig: case kBGRA_8888_GrPixelConfig: case kSRGBA_8888_GrPixelConfig: case kSBGRA_8888_GrPixelConfig: return true; - default: + case kUnknown_GrPixelConfig: + case kAlpha_8_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: + case kETC1_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kRGBA_half_GrPixelConfig: return false; } + SkFAIL("Invalid pixel config"); + return false; } // Returns true if the color (non-alpha) components represent sRGB values. It does NOT indicate that @@ -339,9 +421,23 @@ static inline bool GrPixelConfigIsSRGB(GrPixelConfig config) { case kSRGBA_8888_GrPixelConfig: case kSBGRA_8888_GrPixelConfig: return true; - default: + case kUnknown_GrPixelConfig: + case kAlpha_8_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: + case kETC1_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kRGBA_half_GrPixelConfig: return false; } + SkFAIL("Invalid pixel config"); + return false; } // Takes a config and returns the equivalent config with the R and B order @@ -356,15 +452,28 @@ static inline GrPixelConfig GrPixelConfigSwapRAndB(GrPixelConfig config) { return kSRGBA_8888_GrPixelConfig; case kSRGBA_8888_GrPixelConfig: return kSBGRA_8888_GrPixelConfig; - default: + case kUnknown_GrPixelConfig: + case kAlpha_8_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: + case kETC1_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kRGBA_half_GrPixelConfig: return kUnknown_GrPixelConfig; } + SkFAIL("Invalid pixel config"); + return kUnknown_GrPixelConfig; } static inline size_t GrBytesPerPixel(GrPixelConfig config) { SkASSERT(!GrPixelConfigIsCompressed(config)); switch (config) { case kAlpha_8_GrPixelConfig: + case kGray_8_GrPixelConfig: return 1; case kRGB_565_GrPixelConfig: case kRGBA_4444_GrPixelConfig: @@ -374,48 +483,96 @@ static inline size_t GrBytesPerPixel(GrPixelConfig config) { case kBGRA_8888_GrPixelConfig: case kSRGBA_8888_GrPixelConfig: case kSBGRA_8888_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: return 4; case kRGBA_half_GrPixelConfig: return 8; case kRGBA_float_GrPixelConfig: return 16; - default: + case kRG_float_GrPixelConfig: + return 8; + case kUnknown_GrPixelConfig: + case kETC1_GrPixelConfig: return 0; } + SkFAIL("Invalid pixel config"); + return 0; } static inline bool GrPixelConfigIsOpaque(GrPixelConfig config) { switch (config) { case kETC1_GrPixelConfig: case kRGB_565_GrPixelConfig: + case kGray_8_GrPixelConfig: return true; - default: + case kAlpha_8_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: + case kRGBA_half_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kUnknown_GrPixelConfig: return false; } + SkFAIL("Invalid pixel config"); + return false; } static inline bool GrPixelConfigIsAlphaOnly(GrPixelConfig config) { switch (config) { - case kR11_EAC_GrPixelConfig: - case kLATC_GrPixelConfig: - case kASTC_12x12_GrPixelConfig: case kAlpha_8_GrPixelConfig: case kAlpha_half_GrPixelConfig: return true; - default: + case kUnknown_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: + case kETC1_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kRGBA_half_GrPixelConfig: return false; } + SkFAIL("Invalid pixel config."); + return false; } static inline bool GrPixelConfigIsFloatingPoint(GrPixelConfig config) { switch (config) { case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: case kAlpha_half_GrPixelConfig: case kRGBA_half_GrPixelConfig: return true; - default: + case kUnknown_GrPixelConfig: + case kAlpha_8_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: + case kETC1_GrPixelConfig: return false; } + SkFAIL("Invalid pixel config"); + return false; +} + +static inline bool GrPixelConfigIsSint(GrPixelConfig config) { + return config == kRGBA_8888_sint_GrPixelConfig; } /** @@ -519,6 +676,9 @@ enum GrWrapOwnership { /** Skia will assume ownership of the resource and free it. */ kAdopt_GrWrapOwnership, + + /** Skia will assume ownership of the resource, free it, and reuse it within the cache. */ + kAdoptAndCache_GrWrapOwnership, }; /** @@ -637,27 +797,33 @@ enum GrGLBackendState { static inline size_t GrCompressedFormatDataSize(GrPixelConfig config, int width, int height) { SkASSERT(GrPixelConfigIsCompressed(config)); - static const int kGrIndex8TableSize = 256 * 4; // 4 == sizeof(GrColor) switch (config) { - case kIndex_8_GrPixelConfig: - return width * height + kGrIndex8TableSize; - case kR11_EAC_GrPixelConfig: - case kLATC_GrPixelConfig: case kETC1_GrPixelConfig: SkASSERT((width & 3) == 0); SkASSERT((height & 3) == 0); return (width >> 2) * (height >> 2) * 8; - case kASTC_12x12_GrPixelConfig: - SkASSERT((width % 12) == 0); - SkASSERT((height % 12) == 0); - return (width / 12) * (height / 12) * 16; - - default: + case kUnknown_GrPixelConfig: + case kAlpha_8_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kRGBA_half_GrPixelConfig: SkFAIL("Unknown compressed pixel config"); return 4 * width * height; } + + SkFAIL("Invalid pixel config"); + return 4 * width * height; } /** diff --git a/gfx/skia/skia/include/gpu/GrTypesPriv.h b/gfx/skia/skia/include/gpu/GrTypesPriv.h index 636e72a019af..0ab5ff2c8ed4 100644 --- a/gfx/skia/skia/include/gpu/GrTypesPriv.h +++ b/gfx/skia/skia/include/gpu/GrTypesPriv.h @@ -8,35 +8,99 @@ #ifndef GrTypesPriv_DEFINED #define GrTypesPriv_DEFINED +#include #include "GrTypes.h" #include "SkRefCnt.h" - /** - * Types of shader-language-specific boxed variables we can create. (Currently only GrGLShaderVars, - * but should be applicable to other shader languages.) - */ +#ifdef MOZ_SKIA +#include "mozilla/TimeStamp.h" + +struct GrStdSteadyClock +{ + typedef mozilla::TimeStamp time_point; + + static time_point now() { + return mozilla::TimeStamp::NowLoRes(); + } +}; + +static inline GrStdSteadyClock::time_point +operator-(GrStdSteadyClock::time_point t, std::chrono::milliseconds ms) { + return t - mozilla::TimeDuration::FromMilliseconds(ms.count()); +} + +#else + +// The old libstdc++ uses the draft name "monotonic_clock" rather than "steady_clock". This might +// not actually be monotonic, depending on how libstdc++ was built. However, this is only currently +// used for idle resource purging so it shouldn't cause a correctness problem. +#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20130000) +using GrStdSteadyClock = std::chrono::monotonic_clock; +#else +using GrStdSteadyClock = std::chrono::steady_clock; +#endif + +#endif + +/** This enum indicates the type of antialiasing to be performed. */ +enum class GrAAType : unsigned { + /** No antialiasing */ + kNone, + /** Use fragment shader code to compute a fractional pixel coverage. */ + kCoverage, + /** Use normal MSAA. */ + kMSAA, + /** + * Use "mixed samples" MSAA such that the stencil buffer is multisampled but the color buffer is + * not. + */ + kMixedSamples +}; + +static inline bool GrAATypeIsHW(GrAAType type) { + switch (type) { + case GrAAType::kNone: + return false; + case GrAAType::kCoverage: + return false; + case GrAAType::kMSAA: + return true; + case GrAAType::kMixedSamples: + return true; + } + SkFAIL("Unknown AA Type"); + return false; +} + +/** + * Types of shader-language-specific boxed variables we can create. (Currently only GrGLShaderVars, + * but should be applicable to other shader languages.) + */ enum GrSLType { kVoid_GrSLType, + kBool_GrSLType, + kInt_GrSLType, + kUint_GrSLType, kFloat_GrSLType, kVec2f_GrSLType, kVec3f_GrSLType, kVec4f_GrSLType, + kVec2i_GrSLType, + kVec3i_GrSLType, + kVec4i_GrSLType, kMat22f_GrSLType, kMat33f_GrSLType, kMat44f_GrSLType, kTexture2DSampler_GrSLType, + kITexture2DSampler_GrSLType, kTextureExternalSampler_GrSLType, kTexture2DRectSampler_GrSLType, - kTextureBufferSampler_GrSLType, - kBool_GrSLType, - kInt_GrSLType, - kUint_GrSLType, + kBufferSampler_GrSLType, kTexture2D_GrSLType, kSampler_GrSLType, - - kLast_GrSLType = kSampler_GrSLType + kImageStorage2D_GrSLType, + kIImageStorage2D_GrSLType, }; -static const int kGrSLTypeCount = kLast_GrSLType + 1; enum GrShaderType { kVertex_GrShaderType, @@ -73,175 +137,182 @@ enum GrSLPrecision { kMedium_GrSLPrecision, kHigh_GrSLPrecision, - // Default precision is medium. This is because on OpenGL ES 2 highp support is not - // guaranteed. On (non-ES) OpenGL the specifiers have no effect on precision. - kDefault_GrSLPrecision = kMedium_GrSLPrecision, + // Default precision is a special tag that means "whatever the default for the program/type + // combination is". In other words, it maps to the empty string in shader code. There are some + // scenarios where kDefault is not allowed (as the default precision for a program, or for + // varyings, for example). + kDefault_GrSLPrecision, - kLast_GrSLPrecision = kHigh_GrSLPrecision + // We only consider the "real" precisions here + kLast_GrSLPrecision = kHigh_GrSLPrecision, }; static const int kGrSLPrecisionCount = kLast_GrSLPrecision + 1; -/** - * Gets the vector size of the SLType. Returns -1 for void, matrices, and samplers. - */ -static inline int GrSLTypeVectorCount(GrSLType type) { - SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); - static const int kCounts[] = { -1, 1, 2, 3, 4, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1 }; - return kCounts[type]; - - GR_STATIC_ASSERT(0 == kVoid_GrSLType); - GR_STATIC_ASSERT(1 == kFloat_GrSLType); - GR_STATIC_ASSERT(2 == kVec2f_GrSLType); - GR_STATIC_ASSERT(3 == kVec3f_GrSLType); - GR_STATIC_ASSERT(4 == kVec4f_GrSLType); - GR_STATIC_ASSERT(5 == kMat22f_GrSLType); - GR_STATIC_ASSERT(6 == kMat33f_GrSLType); - GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); - GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); - GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); - GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); - GR_STATIC_ASSERT(12 == kBool_GrSLType); - GR_STATIC_ASSERT(13 == kInt_GrSLType); - GR_STATIC_ASSERT(14 == kUint_GrSLType); - GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); - GR_STATIC_ASSERT(16 == kSampler_GrSLType); - GR_STATIC_ASSERT(SK_ARRAY_COUNT(kCounts) == kGrSLTypeCount); -} - -/** Return the type enum for a vector of floats of length n (1..4), - e.g. 1 -> kFloat_GrSLType, 2 -> kVec2_GrSLType, ... */ -static inline GrSLType GrSLFloatVectorType(int count) { - SkASSERT(count > 0 && count <= 4); - return (GrSLType)(count); - - GR_STATIC_ASSERT(kFloat_GrSLType == 1); - GR_STATIC_ASSERT(kVec2f_GrSLType == 2); - GR_STATIC_ASSERT(kVec3f_GrSLType == 3); - GR_STATIC_ASSERT(kVec4f_GrSLType == 4); -} - /** Is the shading language type float (including vectors/matrices)? */ static inline bool GrSLTypeIsFloatType(GrSLType type) { - SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); - return type >= kFloat_GrSLType && type <= kMat44f_GrSLType; + switch (type) { + case kFloat_GrSLType: + case kVec2f_GrSLType: + case kVec3f_GrSLType: + case kVec4f_GrSLType: + case kMat22f_GrSLType: + case kMat33f_GrSLType: + case kMat44f_GrSLType: + return true; - GR_STATIC_ASSERT(0 == kVoid_GrSLType); - GR_STATIC_ASSERT(1 == kFloat_GrSLType); - GR_STATIC_ASSERT(2 == kVec2f_GrSLType); - GR_STATIC_ASSERT(3 == kVec3f_GrSLType); - GR_STATIC_ASSERT(4 == kVec4f_GrSLType); - GR_STATIC_ASSERT(5 == kMat22f_GrSLType); - GR_STATIC_ASSERT(6 == kMat33f_GrSLType); - GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); - GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); - GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); - GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); - GR_STATIC_ASSERT(12 == kBool_GrSLType); - GR_STATIC_ASSERT(13 == kInt_GrSLType); - GR_STATIC_ASSERT(14 == kUint_GrSLType); - GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); - GR_STATIC_ASSERT(16 == kSampler_GrSLType); - GR_STATIC_ASSERT(17 == kGrSLTypeCount); -} - -/** Is the shading language type integral (including vectors/matrices)? */ -static inline bool GrSLTypeIsIntType(GrSLType type) { - SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); - return type >= kInt_GrSLType && type <= kUint_GrSLType; - - GR_STATIC_ASSERT(0 == kVoid_GrSLType); - GR_STATIC_ASSERT(1 == kFloat_GrSLType); - GR_STATIC_ASSERT(2 == kVec2f_GrSLType); - GR_STATIC_ASSERT(3 == kVec3f_GrSLType); - GR_STATIC_ASSERT(4 == kVec4f_GrSLType); - GR_STATIC_ASSERT(5 == kMat22f_GrSLType); - GR_STATIC_ASSERT(6 == kMat33f_GrSLType); - GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); - GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); - GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); - GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); - GR_STATIC_ASSERT(12 == kBool_GrSLType); - GR_STATIC_ASSERT(13 == kInt_GrSLType); - GR_STATIC_ASSERT(14 == kUint_GrSLType); - GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); - GR_STATIC_ASSERT(16 == kSampler_GrSLType); - GR_STATIC_ASSERT(17 == kGrSLTypeCount); -} - -/** Is the shading language type numeric (including vectors/matrices)? */ -static inline bool GrSLTypeIsNumeric(GrSLType type) { - return GrSLTypeIsFloatType(type) || GrSLTypeIsIntType(type); -} - -/** Returns the size in bytes for floating point GrSLTypes. For non floating point type returns 0 */ -static inline size_t GrSLTypeSize(GrSLType type) { - SkASSERT(GrSLTypeIsFloatType(type)); - static const size_t kSizes[] = { - 0, // kVoid_GrSLType - sizeof(float), // kFloat_GrSLType - 2 * sizeof(float), // kVec2f_GrSLType - 3 * sizeof(float), // kVec3f_GrSLType - 4 * sizeof(float), // kVec4f_GrSLType - 2 * 2 * sizeof(float), // kMat22f_GrSLType - 3 * 3 * sizeof(float), // kMat33f_GrSLType - 4 * 4 * sizeof(float), // kMat44f_GrSLType - 0, // kTexture2DSampler_GrSLType - 0, // kTextureExternalSampler_GrSLType - 0, // kTexture2DRectSampler_GrSLType - 0, // kTextureBufferSampler_GrSLType - 0, // kBool_GrSLType - 0, // kInt_GrSLType - 0, // kUint_GrSLType - 0, // kTexture2D_GrSLType - 0, // kSampler_GrSLType - }; - return kSizes[type]; - - GR_STATIC_ASSERT(0 == kVoid_GrSLType); - GR_STATIC_ASSERT(1 == kFloat_GrSLType); - GR_STATIC_ASSERT(2 == kVec2f_GrSLType); - GR_STATIC_ASSERT(3 == kVec3f_GrSLType); - GR_STATIC_ASSERT(4 == kVec4f_GrSLType); - GR_STATIC_ASSERT(5 == kMat22f_GrSLType); - GR_STATIC_ASSERT(6 == kMat33f_GrSLType); - GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); - GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); - GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); - GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); - GR_STATIC_ASSERT(12 == kBool_GrSLType); - GR_STATIC_ASSERT(13 == kInt_GrSLType); - GR_STATIC_ASSERT(14 == kUint_GrSLType); - GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); - GR_STATIC_ASSERT(16 == kSampler_GrSLType); - GR_STATIC_ASSERT(17 == kGrSLTypeCount); + case kVoid_GrSLType: + case kTexture2DSampler_GrSLType: + case kITexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + case kBufferSampler_GrSLType: + case kBool_GrSLType: + case kInt_GrSLType: + case kUint_GrSLType: + case kVec2i_GrSLType: + case kVec3i_GrSLType: + case kVec4i_GrSLType: + case kTexture2D_GrSLType: + case kSampler_GrSLType: + case kImageStorage2D_GrSLType: + case kIImageStorage2D_GrSLType: + return false; + } + SkFAIL("Unexpected type"); + return false; } static inline bool GrSLTypeIs2DCombinedSamplerType(GrSLType type) { - SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); - return type >= kTexture2DSampler_GrSLType && type <= kTexture2DRectSampler_GrSLType; + switch (type) { + case kTexture2DSampler_GrSLType: + case kITexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + return true; - GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); - GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); - GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); + case kVoid_GrSLType: + case kFloat_GrSLType: + case kVec2f_GrSLType: + case kVec3f_GrSLType: + case kVec4f_GrSLType: + case kVec2i_GrSLType: + case kVec3i_GrSLType: + case kVec4i_GrSLType: + case kMat22f_GrSLType: + case kMat33f_GrSLType: + case kMat44f_GrSLType: + case kBufferSampler_GrSLType: + case kInt_GrSLType: + case kUint_GrSLType: + case kBool_GrSLType: + case kTexture2D_GrSLType: + case kSampler_GrSLType: + case kImageStorage2D_GrSLType: + case kIImageStorage2D_GrSLType: + return false; + } + SkFAIL("Unexpected type"); + return false; } static inline bool GrSLTypeIsCombinedSamplerType(GrSLType type) { - SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); - return type >= kTexture2DSampler_GrSLType && type <= kTextureBufferSampler_GrSLType; + switch (type) { + case kTexture2DSampler_GrSLType: + case kITexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + case kBufferSampler_GrSLType: + return true; - GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); - GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); - GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); - GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); + case kVoid_GrSLType: + case kFloat_GrSLType: + case kVec2f_GrSLType: + case kVec3f_GrSLType: + case kVec4f_GrSLType: + case kVec2i_GrSLType: + case kVec3i_GrSLType: + case kVec4i_GrSLType: + case kMat22f_GrSLType: + case kMat33f_GrSLType: + case kMat44f_GrSLType: + case kInt_GrSLType: + case kUint_GrSLType: + case kBool_GrSLType: + case kTexture2D_GrSLType: + case kSampler_GrSLType: + case kImageStorage2D_GrSLType: + case kIImageStorage2D_GrSLType: + return false; + } + SkFAIL("Unexpected type"); + return false; +} + +static inline bool GrSLTypeIsImageStorage(GrSLType type) { + switch (type) { + case kImageStorage2D_GrSLType: + case kIImageStorage2D_GrSLType: + return true; + + case kVoid_GrSLType: + case kFloat_GrSLType: + case kVec2f_GrSLType: + case kVec3f_GrSLType: + case kVec4f_GrSLType: + case kVec2i_GrSLType: + case kVec3i_GrSLType: + case kVec4i_GrSLType: + case kMat22f_GrSLType: + case kMat33f_GrSLType: + case kMat44f_GrSLType: + case kInt_GrSLType: + case kUint_GrSLType: + case kBool_GrSLType: + case kTexture2D_GrSLType: + case kSampler_GrSLType: + case kTexture2DSampler_GrSLType: + case kITexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + case kBufferSampler_GrSLType: + return false; + } + SkFAIL("Unexpected type"); + return false; } static inline bool GrSLTypeAcceptsPrecision(GrSLType type) { - return type != kVoid_GrSLType && type != kBool_GrSLType; + switch (type) { + case kInt_GrSLType: + case kUint_GrSLType: + case kFloat_GrSLType: + case kVec2f_GrSLType: + case kVec3f_GrSLType: + case kVec4f_GrSLType: + case kVec2i_GrSLType: + case kVec3i_GrSLType: + case kVec4i_GrSLType: + case kMat22f_GrSLType: + case kMat33f_GrSLType: + case kMat44f_GrSLType: + case kTexture2DSampler_GrSLType: + case kITexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + case kBufferSampler_GrSLType: + case kTexture2D_GrSLType: + case kSampler_GrSLType: + case kImageStorage2D_GrSLType: + case kIImageStorage2D_GrSLType: + return true; + + case kVoid_GrSLType: + case kBool_GrSLType: + return false; + } + SkFAIL("Unexpected type"); + return false; } ////////////////////////////////////////////////////////////////////////////// @@ -255,6 +326,10 @@ enum GrVertexAttribType { kVec3f_GrVertexAttribType, kVec4f_GrVertexAttribType, + kVec2i_GrVertexAttribType, // vector of 2 32-bit ints + kVec3i_GrVertexAttribType, // vector of 3 32-bit ints + kVec4i_GrVertexAttribType, // vector of 4 32-bit ints + kUByte_GrVertexAttribType, // unsigned byte, e.g. coverage kVec4ub_GrVertexAttribType, // vector of 4 unsigned bytes, e.g. colors @@ -267,72 +342,73 @@ enum GrVertexAttribType { }; static const int kGrVertexAttribTypeCount = kLast_GrVertexAttribType + 1; -/** - * Returns the vector size of the type. - */ -static inline int GrVertexAttribTypeVectorCount(GrVertexAttribType type) { - SkASSERT(type >= 0 && type < kGrVertexAttribTypeCount); - static const int kCounts[] = { 1, 2, 3, 4, 1, 4, 2, 1, 1 }; - return kCounts[type]; - - GR_STATIC_ASSERT(0 == kFloat_GrVertexAttribType); - GR_STATIC_ASSERT(1 == kVec2f_GrVertexAttribType); - GR_STATIC_ASSERT(2 == kVec3f_GrVertexAttribType); - GR_STATIC_ASSERT(3 == kVec4f_GrVertexAttribType); - GR_STATIC_ASSERT(4 == kUByte_GrVertexAttribType); - GR_STATIC_ASSERT(5 == kVec4ub_GrVertexAttribType); - GR_STATIC_ASSERT(6 == kVec2us_GrVertexAttribType); - GR_STATIC_ASSERT(7 == kInt_GrVertexAttribType); - GR_STATIC_ASSERT(8 == kUint_GrVertexAttribType); - GR_STATIC_ASSERT(SK_ARRAY_COUNT(kCounts) == kGrVertexAttribTypeCount); -} /** * Returns the size of the attrib type in bytes. */ static inline size_t GrVertexAttribTypeSize(GrVertexAttribType type) { - static const size_t kSizes[] = { - sizeof(float), // kFloat_GrVertexAttribType - 2*sizeof(float), // kVec2f_GrVertexAttribType - 3*sizeof(float), // kVec3f_GrVertexAttribType - 4*sizeof(float), // kVec4f_GrVertexAttribType - 1*sizeof(char), // kUByte_GrVertexAttribType - 4*sizeof(char), // kVec4ub_GrVertexAttribType - 2*sizeof(int16_t), // kVec2us_GrVertexAttribType - sizeof(int32_t), // kInt_GrVertexAttribType - sizeof(uint32_t) // kUint_GrVertexAttribType - }; - return kSizes[type]; - - GR_STATIC_ASSERT(0 == kFloat_GrVertexAttribType); - GR_STATIC_ASSERT(1 == kVec2f_GrVertexAttribType); - GR_STATIC_ASSERT(2 == kVec3f_GrVertexAttribType); - GR_STATIC_ASSERT(3 == kVec4f_GrVertexAttribType); - GR_STATIC_ASSERT(4 == kUByte_GrVertexAttribType); - GR_STATIC_ASSERT(5 == kVec4ub_GrVertexAttribType); - GR_STATIC_ASSERT(6 == kVec2us_GrVertexAttribType); - GR_STATIC_ASSERT(7 == kInt_GrVertexAttribType); - GR_STATIC_ASSERT(8 == kUint_GrVertexAttribType); - GR_STATIC_ASSERT(SK_ARRAY_COUNT(kSizes) == kGrVertexAttribTypeCount); + switch (type) { + case kFloat_GrVertexAttribType: + return sizeof(float); + case kVec2f_GrVertexAttribType: + return 2*sizeof(float); + case kVec3f_GrVertexAttribType: + return 3*sizeof(float); + case kVec4f_GrVertexAttribType: + return 4*sizeof(float); + case kVec2i_GrVertexAttribType: + return 2*sizeof(int32_t); + case kVec3i_GrVertexAttribType: + return 3*sizeof(int32_t); + case kVec4i_GrVertexAttribType: + return 4*sizeof(int32_t); + case kUByte_GrVertexAttribType: + return 1*sizeof(char); + case kVec4ub_GrVertexAttribType: + return 4*sizeof(char); + case kVec2us_GrVertexAttribType: + return 2*sizeof(int16_t); + case kInt_GrVertexAttribType: + return sizeof(int32_t); + case kUint_GrVertexAttribType: + return sizeof(uint32_t); + } + SkFAIL("Unexpected attribute type"); + return 0; } /** * Is the attrib type integral? */ static inline bool GrVertexAttribTypeIsIntType(GrVertexAttribType type) { - SkASSERT(type >= 0 && type < static_cast(kGrVertexAttribTypeCount)); - return type >= kInt_GrVertexAttribType; - - GR_STATIC_ASSERT(0 == kFloat_GrVertexAttribType); - GR_STATIC_ASSERT(1 == kVec2f_GrVertexAttribType); - GR_STATIC_ASSERT(2 == kVec3f_GrVertexAttribType); - GR_STATIC_ASSERT(3 == kVec4f_GrVertexAttribType); - GR_STATIC_ASSERT(4 == kUByte_GrVertexAttribType); - GR_STATIC_ASSERT(5 == kVec4ub_GrVertexAttribType); - GR_STATIC_ASSERT(6 == kVec2us_GrVertexAttribType); - GR_STATIC_ASSERT(7 == kInt_GrVertexAttribType); - GR_STATIC_ASSERT(8 == kUint_GrVertexAttribType); - GR_STATIC_ASSERT(9 == kGrVertexAttribTypeCount); + switch (type) { + case kFloat_GrVertexAttribType: + return false; + case kVec2f_GrVertexAttribType: + return false; + case kVec3f_GrVertexAttribType: + return false; + case kVec4f_GrVertexAttribType: + return false; + case kVec2i_GrVertexAttribType: + return true; + case kVec3i_GrVertexAttribType: + return true; + case kVec4i_GrVertexAttribType: + return true; + case kUByte_GrVertexAttribType: + return false; + case kVec4ub_GrVertexAttribType: + return false; + case kVec2us_GrVertexAttribType: + return false; + case kInt_GrVertexAttribType: + return true; + case kUint_GrVertexAttribType: + return true; + } + SkFAIL("Unexpected attribute type"); + return false; } /** @@ -340,9 +416,6 @@ static inline bool GrVertexAttribTypeIsIntType(GrVertexAttribType type) { */ static inline GrSLType GrVertexAttribTypeToSLType(GrVertexAttribType type) { switch (type) { - default: - SkFAIL("Unsupported type conversion"); - return kVoid_GrSLType; case kUByte_GrVertexAttribType: case kFloat_GrVertexAttribType: return kFloat_GrSLType; @@ -354,15 +427,57 @@ static inline GrSLType GrVertexAttribTypeToSLType(GrVertexAttribType type) { case kVec4ub_GrVertexAttribType: case kVec4f_GrVertexAttribType: return kVec4f_GrSLType; + case kVec2i_GrVertexAttribType: + return kVec2i_GrSLType; + case kVec3i_GrVertexAttribType: + return kVec3i_GrSLType; + case kVec4i_GrVertexAttribType: + return kVec4i_GrSLType; case kInt_GrVertexAttribType: return kInt_GrSLType; case kUint_GrVertexAttribType: return kUint_GrSLType; } + SkFAIL("Unsupported type conversion"); + return kVoid_GrSLType; } ////////////////////////////////////////////////////////////////////////////// +enum class GrImageStorageFormat { + kRGBA8, + kRGBA8i, + kRGBA16f, + kRGBA32f, +}; + +/** + * Describes types of caching and compiler optimizations allowed for certain variable types + * (currently only image storages). + **/ +enum class GrSLMemoryModel { + /** No special restrctions on memory accesses or compiler optimizations */ + kNone, + /** Cache coherent across shader invocations */ + kCoherent, + /** + * Disallows compiler from eliding loads or stores that appear redundant in a single + * invocation. Implies coherent. + */ + kVolatile +}; + +/** + * If kYes then the memory backing the varialble is only accessed via the variable. This is + * currently only used with image storages. + */ +enum class GrSLRestrict { + kYes, + kNo, +}; + +////////////////////////////////////////////////////////////////////////////// + /** * We have coverage effects that clip rendering to the edge of some geometric primitive. * This enum specifies how that clipping is performed. Not all factories that take a @@ -460,7 +575,7 @@ enum GrAccessPattern { #ifdef SK_DEBUG // Takes a pointer to a GrCaps, and will suppress prints if required #define GrCapsDebugf(caps, ...) \ - if (!caps->suppressPrints()) { \ + if (!(caps)->suppressPrints()) { \ SkDebugf(__VA_ARGS__); \ } #else @@ -485,6 +600,6 @@ template T * const * sk_sp_address_as_pointer_address(sk_sp cons /* * Object for CPU-GPU synchronization */ -typedef intptr_t GrFence; +typedef uint64_t GrFence; #endif diff --git a/gfx/skia/skia/include/gpu/GrXferProcessor.h b/gfx/skia/skia/include/gpu/GrXferProcessor.h deleted file mode 100644 index 1d4717e1569d..000000000000 --- a/gfx/skia/skia/include/gpu/GrXferProcessor.h +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrXferProcessor_DEFINED -#define GrXferProcessor_DEFINED - -#include "GrBlend.h" -#include "GrColor.h" -#include "GrProcessor.h" -#include "GrTexture.h" -#include "GrTypes.h" -#include "SkXfermode.h" - -class GrShaderCaps; -class GrGLSLCaps; -class GrGLSLXferProcessor; -class GrProcOptInfo; -struct GrPipelineOptimizations; - -/** - * Barriers for blending. When a shader reads the dst directly, an Xfer barrier is sometimes - * required after a pixel has been written, before it can be safely read again. - */ -enum GrXferBarrierType { - kNone_GrXferBarrierType = 0, // fTexture; - SkIPoint fOffset; - }; - - /** - * Sets a unique key on the GrProcessorKeyBuilder calls onGetGLSLProcessorKey(...) to get the - * specific subclass's key. - */ - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const; - - /** Returns a new instance of the appropriate *GL* implementation class - for the given GrXferProcessor; caller is responsible for deleting - the object. */ - virtual GrGLSLXferProcessor* createGLSLInstance() const = 0; - - /** - * Optimizations for blending / coverage that an OptDrawState should apply to itself. - */ - enum OptFlags { - /** - * The draw can be skipped completely. - */ - kSkipDraw_OptFlag = 0x1, - /** - * GrXferProcessor will ignore color, thus no need to provide - */ - kIgnoreColor_OptFlag = 0x2, - /** - * GrXferProcessor will ignore coverage, thus no need to provide - */ - kIgnoreCoverage_OptFlag = 0x4, - /** - * Clear color stages and override input color to that returned by getOptimizations - */ - kOverrideColor_OptFlag = 0x8, - /** - * Can tweak alpha for coverage. Currently this flag should only be used by a batch - */ - kCanTweakAlphaForCoverage_OptFlag = 0x20, - }; - - static const OptFlags kNone_OptFlags = (OptFlags)0; - - GR_DECL_BITFIELD_OPS_FRIENDS(OptFlags); - - /** - * Determines which optimizations (as described by the ptFlags above) can be performed by - * the draw with this xfer processor. If this function is called, the xfer processor may change - * its state to reflected the given blend optimizations. If the XP needs to see a specific input - * color to blend correctly, it will set the OverrideColor flag and the output parameter - * overrideColor will be the required value that should be passed into the XP. - * A caller who calls this function on a XP is required to honor the returned OptFlags - * and color values for its draw. - */ - OptFlags getOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const; - - /** - * Returns whether this XP will require an Xfer barrier on the given rt. If true, outBarrierType - * is updated to contain the type of barrier needed. - */ - GrXferBarrierType xferBarrierType(const GrRenderTarget* rt, const GrCaps& caps) const; - - struct BlendInfo { - void reset() { - fEquation = kAdd_GrBlendEquation; - fSrcBlend = kOne_GrBlendCoeff; - fDstBlend = kZero_GrBlendCoeff; - fBlendConstant = 0; - fWriteColor = true; - } - - SkDEBUGCODE(SkString dump() const;) - - GrBlendEquation fEquation; - GrBlendCoeff fSrcBlend; - GrBlendCoeff fDstBlend; - GrColor fBlendConstant; - bool fWriteColor; - }; - - void getBlendInfo(BlendInfo* blendInfo) const; - - bool willReadDstColor() const { return fWillReadDstColor; } - - /** - * Returns the texture to be used as the destination when reading the dst in the fragment - * shader. If the returned texture is NULL then the XP is either not reading the dst or we have - * extentions that support framebuffer fetching and thus don't need a copy of the dst texture. - */ - const GrTexture* getDstTexture() const { return fDstTexture.getTexture(); } - - /** - * Returns the offset in device coords to use when accessing the dst texture to get the dst - * pixel color in the shader. This value is only valid if getDstTexture() != NULL. - */ - const SkIPoint& dstTextureOffset() const { - SkASSERT(this->getDstTexture()); - return fDstTextureOffset; - } - - /** - * If we are performing a dst read, returns whether the base class will use mixed samples to - * antialias the shader's final output. If not doing a dst read, the subclass is responsible - * for antialiasing and this returns false. - */ - bool dstReadUsesMixedSamples() const { return fDstReadUsesMixedSamples; } - - /** - * Returns whether or not this xferProcossor will set a secondary output to be used with dual - * source blending. - */ - bool hasSecondaryOutput() const; - - /** Returns true if this and other processor conservatively draw identically. It can only return - true when the two processor are of the same subclass (i.e. they return the same object from - from getFactory()). - - A return value of true from isEqual() should not be used to test whether the processor would - generate the same shader code. To test for identical code generation use getGLSLProcessorKey - */ - - bool isEqual(const GrXferProcessor& that) const { - if (this->classID() != that.classID()) { - return false; - } - if (this->fWillReadDstColor != that.fWillReadDstColor) { - return false; - } - if (this->fDstTexture.getTexture() != that.fDstTexture.getTexture()) { - return false; - } - if (this->fDstTextureOffset != that.fDstTextureOffset) { - return false; - } - if (this->fDstReadUsesMixedSamples != that.fDstReadUsesMixedSamples) { - return false; - } - return this->onIsEqual(that); - } - -protected: - GrXferProcessor(); - GrXferProcessor(const DstTexture*, bool willReadDstColor, bool hasMixedSamples); - -private: - void notifyRefCntIsZero() const final {} - - virtual OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const = 0; - - /** - * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this xfer - * processor's GL backend implementation. - */ - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const = 0; - - /** - * Determines the type of barrier (if any) required by the subclass. Note that the possibility - * that a kTexture type barrier is required is handled by the base class and need not be - * considered by subclass overrides of this function. - */ - virtual GrXferBarrierType onXferBarrier(const GrRenderTarget*, const GrCaps&) const { - return kNone_GrXferBarrierType; - } - - /** - * If we are not performing a dst read, returns whether the subclass will set a secondary - * output. When using dst reads, the base class controls the secondary output and this method - * will not be called. - */ - virtual bool onHasSecondaryOutput() const { return false; } - - /** - * If we are not performing a dst read, retrieves the fixed-function blend state required by the - * subclass. When using dst reads, the base class controls the fixed-function blend state and - * this method will not be called. The BlendInfo struct comes initialized to "no blending". - */ - virtual void onGetBlendInfo(BlendInfo*) const {} - - virtual bool onIsEqual(const GrXferProcessor&) const = 0; - - bool fWillReadDstColor; - bool fDstReadUsesMixedSamples; - SkIPoint fDstTextureOffset; - GrTextureAccess fDstTexture; - - typedef GrFragmentProcessor INHERITED; -}; - -GR_MAKE_BITFIELD_OPS(GrXferProcessor::OptFlags); - -/////////////////////////////////////////////////////////////////////////////// - -/** - * We install a GrXPFactory (XPF) early on in the pipeline before all the final draw information is - * known (e.g. whether there is fractional pixel coverage, will coverage be 1 or 4 channel, is the - * draw opaque, etc.). Once the state of the draw is finalized, we use the XPF along with all the - * draw information to create a GrXferProcessor (XP) which can implement the desired blending for - * the draw. - * - * Before the XP is created, the XPF is able to answer queries about what functionality the XPs it - * creates will have. For example, can it create an XP that supports RGB coverage or will the XP - * blend with the destination color. - */ -class GrXPFactory : public SkRefCnt { -public: - typedef GrXferProcessor::DstTexture DstTexture; - GrXferProcessor* createXferProcessor(const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture*, - const GrCaps& caps) const; - /** - * Known color information after blending, but before accounting for any coverage. - */ - struct InvariantBlendedColor { - bool fWillBlendWithDst; - GrColor fKnownColor; - GrColorComponentFlags fKnownColorFlags; - }; - - /** - * Returns information about the output color, produced by XPs from this factory, that will be - * known after blending. Note that we can conflate coverage and color, so the actual values - * written to pixels with partial coverage may not always seem consistent with the invariant - * information returned by this function. - */ - virtual void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - InvariantBlendedColor*) const = 0; - - bool willNeedDstTexture(const GrCaps& caps, const GrPipelineOptimizations& optimizations) const; - - bool isEqual(const GrXPFactory& that) const { - if (this->classID() != that.classID()) { - return false; - } - return this->onIsEqual(that); - } - - /** - * Helper for down-casting to a GrXPFactory subclass - */ - template const T& cast() const { return *static_cast(this); } - - uint32_t classID() const { SkASSERT(kIllegalXPFClassID != fClassID); return fClassID; } - -protected: - GrXPFactory() : fClassID(kIllegalXPFClassID) {} - - template void initClassID() { - static uint32_t kClassID = GenClassID(); - fClassID = kClassID; - } - - uint32_t fClassID; - -private: - virtual GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture*) const = 0; - - virtual bool onIsEqual(const GrXPFactory&) const = 0; - - bool willReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const; - /** - * Returns true if the XP generated by this factory will explicitly read dst in the fragment - * shader. - */ - virtual bool onWillReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const = 0; - - static uint32_t GenClassID() { - // fCurrXPFactoryID has been initialized to kIllegalXPFactoryID. The - // atomic inc returns the old value not the incremented value. So we add - // 1 to the returned value. - uint32_t id = static_cast(sk_atomic_inc(&gCurrXPFClassID)) + 1; - if (!id) { - SkFAIL("This should never wrap as it should only be called once for each GrXPFactory " - "subclass."); - } - return id; - } - - enum { - kIllegalXPFClassID = 0, - }; - static int32_t gCurrXPFClassID; - - typedef GrProgramElement INHERITED; -}; - -#endif - diff --git a/gfx/skia/skia/include/gpu/SkGr.h b/gfx/skia/skia/include/gpu/SkGr.h deleted file mode 100644 index 43d61e250bcb..000000000000 --- a/gfx/skia/skia/include/gpu/SkGr.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkGr_DEFINED -#define SkGr_DEFINED - -#include "GrColor.h" -#include "GrTextureAccess.h" -#include "SkColor.h" -#include "SkColorPriv.h" -#include "SkFilterQuality.h" -#include "SkImageInfo.h" - -class GrCaps; -class GrColorSpaceXform; -class GrContext; -class GrTexture; -class GrTextureParams; -class SkBitmap; - -//////////////////////////////////////////////////////////////////////////////// -// Sk to Gr Type conversions - -static inline GrColor SkColorToPremulGrColor(SkColor c) { - SkPMColor pm = SkPreMultiplyColor(c); - unsigned r = SkGetPackedR32(pm); - unsigned g = SkGetPackedG32(pm); - unsigned b = SkGetPackedB32(pm); - unsigned a = SkGetPackedA32(pm); - return GrColorPackRGBA(r, g, b, a); -} - -static inline GrColor SkColorToUnpremulGrColor(SkColor c) { - unsigned r = SkColorGetR(c); - unsigned g = SkColorGetG(c); - unsigned b = SkColorGetB(c); - unsigned a = SkColorGetA(c); - return GrColorPackRGBA(r, g, b, a); -} - -GrColor4f SkColorToPremulGrColor4f(SkColor c, bool gammaCorrect, GrColorSpaceXform* gamutXform); -GrColor4f SkColorToUnpremulGrColor4f(SkColor c, bool gammaCorrect, GrColorSpaceXform* gamutXform); - -static inline GrColor SkColorToOpaqueGrColor(SkColor c) { - unsigned r = SkColorGetR(c); - unsigned g = SkColorGetG(c); - unsigned b = SkColorGetB(c); - return GrColorPackRGBA(r, g, b, 0xFF); -} - -/** Replicates the SkColor's alpha to all four channels of the GrColor. */ -static inline GrColor SkColorAlphaToGrColor(SkColor c) { - U8CPU a = SkColorGetA(c); - return GrColorPackRGBA(a, a, a, a); -} - -static inline SkPMColor GrColorToSkPMColor(GrColor c) { - GrColorIsPMAssert(c); - return SkPackARGB32(GrColorUnpackA(c), GrColorUnpackR(c), GrColorUnpackG(c), GrColorUnpackB(c)); -} - -static inline GrColor SkPMColorToGrColor(SkPMColor c) { - return GrColorPackRGBA(SkGetPackedR32(c), SkGetPackedG32(c), SkGetPackedB32(c), - SkGetPackedA32(c)); -} - -//////////////////////////////////////////////////////////////////////////////// -/** Returns a texture representing the bitmap that is compatible with the GrTextureParams. The - texture is inserted into the cache (unless the bitmap is marked volatile) and can be - retrieved again via this function. */ -GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams&, - SkSourceGammaTreatment); - -sk_sp GrMakeCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams&, - SkSourceGammaTreatment); - -// TODO: Move SkImageInfo2GrPixelConfig to SkGrPriv.h (requires cleanup to SkWindow its subclasses). -GrPixelConfig SkImageInfo2GrPixelConfig(SkColorType, SkAlphaType, const SkColorSpace*, - const GrCaps&); - -static inline GrPixelConfig SkImageInfo2GrPixelConfig(const SkImageInfo& info, const GrCaps& caps) { - return SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType(), info.colorSpace(), caps); -} - -GrTextureParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality, - const SkMatrix& viewM, - const SkMatrix& localM, - bool* doBicubic); - -#endif diff --git a/gfx/skia/skia/include/gpu/effects/GrBlurredEdgeFragmentProcessor.h b/gfx/skia/skia/include/gpu/effects/GrBlurredEdgeFragmentProcessor.h new file mode 100644 index 000000000000..d0864ed8649c --- /dev/null +++ b/gfx/skia/skia/include/gpu/effects/GrBlurredEdgeFragmentProcessor.h @@ -0,0 +1,68 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrBlurredEdgeFragmentProcessor_DEFINED +#define GrBlurredEdgeFragmentProcessor_DEFINED + +#include "GrFragmentProcessor.h" + +/** + * Shader for managing a blurred edge for a shadow. + * + * There are two blurring modes supported: Gaussian blur function and smoothstep function. + * + * If the primitive supports an implicit distance to the edge, the radius of the blur is specified + * by r & g values of the color in 14.2 fixed point. For spot shadows, we increase the stroke width + * to set the shadow against the shape. This pad is specified by b, also in 6.2 fixed point. + * The a value represents the max final alpha. + * + * When not using implicit distance, then b in the input color represents the input to the + * blur function, and r the max final alpha. + * + */ +class GrBlurredEdgeFP : public GrFragmentProcessor { +public: + enum Mode { + kGaussian_Mode, + kSmoothstep_Mode, + + kLastMode = kSmoothstep_Mode + }; + static const int kModeCnt = kLastMode + 1; + + static sk_sp Make(Mode mode = kGaussian_Mode) { + return sk_sp(new GrBlurredEdgeFP(mode)); + } + + const char* name() const override { return "BlurredEdge"; } + + Mode mode() const { return fMode; } + +private: + GrBlurredEdgeFP(Mode mode) + : INHERITED(kNone_OptimizationFlags) + , fMode(mode) { + // enable output of distance information for shape + this->setWillUseDistanceVectorField(); + + this->initClassID(); + } + + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; + + bool onIsEqual(const GrFragmentProcessor&) const override; + + GR_DECLARE_FRAGMENT_PROCESSOR_TEST; + + Mode fMode; + + typedef GrFragmentProcessor INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/include/gpu/effects/GrConstColorProcessor.h b/gfx/skia/skia/include/gpu/effects/GrConstColorProcessor.h index e9781bb22a33..b543aa50693d 100644 --- a/gfx/skia/skia/include/gpu/effects/GrConstColorProcessor.h +++ b/gfx/skia/skia/include/gpu/effects/GrConstColorProcessor.h @@ -26,7 +26,7 @@ public: }; static const int kInputModeCnt = kLastInputMode + 1; - static sk_sp Make(GrColor color, InputMode mode) { + static sk_sp Make(GrColor4f color, InputMode mode) { return sk_sp(new GrConstColorProcessor(color, mode)); } @@ -34,30 +34,42 @@ public: SkString dumpInfo() const override { SkString str; - str.appendf("Color: 0x%08x", fColor); + str.appendf("Color: 0x%08x", fColor.toGrColor()); return str; } - GrColor color() const { return fColor; } + GrColor4f color() const { return fColor; } InputMode inputMode() const { return fMode; } private: - GrConstColorProcessor(GrColor color, InputMode mode) : fColor(color), fMode(mode) { + static OptimizationFlags OptFlags(GrColor4f color, InputMode mode) { + OptimizationFlags flags = kConstantOutputForConstantInput_OptimizationFlag; + if (mode != kIgnore_InputMode) { + flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag; + } + if (color.isOpaque()) { + flags |= kPreservesOpaqueInput_OptimizationFlag; + } + return flags; + } + + GrConstColorProcessor(GrColor4f color, InputMode mode) + : INHERITED(OptFlags(color, mode)), fColor(color), fMode(mode) { this->initClassID(); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; + GrColor4f constantOutputForConstantInput(GrColor4f input) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - GrColor fColor; + GrColor4f fColor; InputMode fMode; typedef GrFragmentProcessor INHERITED; diff --git a/gfx/skia/skia/include/gpu/effects/GrCoverageSetOpXP.h b/gfx/skia/skia/include/gpu/effects/GrCoverageSetOpXP.h deleted file mode 100644 index e5d197f33827..000000000000 --- a/gfx/skia/skia/include/gpu/effects/GrCoverageSetOpXP.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrCoverageSetOpXP_DEFINED -#define GrCoverageSetOpXP_DEFINED - -#include "GrTypes.h" -#include "GrXferProcessor.h" -#include "SkRegion.h" - -class GrProcOptInfo; - -/** - * This xfer processor directly blends the the src coverage with the dst using a set operator. It is - * useful for rendering coverage masks using CSG. It can optionally invert the src coverage before - * applying the set operator. - */ -class GrCoverageSetOpXPFactory : public GrXPFactory { -public: - static sk_sp Make(SkRegion::Op regionOp, bool invertCoverage = false); - - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - GrXPFactory::InvariantBlendedColor*) const override; - -private: - GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage); - - GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture*) const override; - - bool onWillReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const override { - return false; - } - - bool onIsEqual(const GrXPFactory& xpfBase) const override { - const GrCoverageSetOpXPFactory& xpf = xpfBase.cast(); - return fRegionOp == xpf.fRegionOp; - } - - GR_DECLARE_XP_FACTORY_TEST; - - SkRegion::Op fRegionOp; - bool fInvertCoverage; - - typedef GrXPFactory INHERITED; -}; -#endif - diff --git a/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h b/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h deleted file mode 100644 index 6777d76046f4..000000000000 --- a/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrPorterDuffXferProcessor_DEFINED -#define GrPorterDuffXferProcessor_DEFINED - -#include "GrTypes.h" -#include "GrXferProcessor.h" -#include "SkXfermode.h" - -class GrProcOptInfo; - -class GrPorterDuffXPFactory : public GrXPFactory { -public: - static sk_sp Make(SkXfermode::Mode mode); - static sk_sp Make(SkBlendMode mode) { - return Make((SkXfermode::Mode)mode); - } - - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - GrXPFactory::InvariantBlendedColor*) const override; - - - /** Because src-over is so common we special case it for performance reasons. If this returns - null then the SimpleSrcOverXP() below should be used. */ - static GrXferProcessor* CreateSrcOverXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const GrXferProcessor::DstTexture*); - /** This XP implements non-LCD src-over using hw blend with no optimizations. It is returned - by reference because it is global and its ref-cnting methods are not thread safe. */ - static const GrXferProcessor& SimpleSrcOverXP(); - - static inline void SrcOverInvariantBlendedColor( - GrColor inputColor, - GrColorComponentFlags validColorFlags, - bool isOpaque, - GrXPFactory::InvariantBlendedColor* blendedColor) { - if (!isOpaque) { - blendedColor->fWillBlendWithDst = true; - blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; - return; - } - blendedColor->fWillBlendWithDst = false; - - blendedColor->fKnownColor = inputColor; - blendedColor->fKnownColorFlags = validColorFlags; - } - - static bool SrcOverWillNeedDstTexture(const GrCaps&, const GrPipelineOptimizations&); - -private: - GrPorterDuffXPFactory(SkXfermode::Mode); - - GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture*) const override; - - bool onWillReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const override; - - bool onIsEqual(const GrXPFactory& xpfBase) const override { - const GrPorterDuffXPFactory& xpf = xpfBase.cast(); - return fXfermode == xpf.fXfermode; - } - - GR_DECLARE_XP_FACTORY_TEST; - static void TestGetXPOutputTypes(const GrXferProcessor*, int* outPrimary, int* outSecondary); - - SkXfermode::Mode fXfermode; - - friend class GrPorterDuffTest; // for TestGetXPOutputTypes() - typedef GrXPFactory INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/gpu/effects/GrXfermodeFragmentProcessor.h b/gfx/skia/skia/include/gpu/effects/GrXfermodeFragmentProcessor.h index 0e2435ea93ec..edc5ae71e11e 100644 --- a/gfx/skia/skia/include/gpu/effects/GrXfermodeFragmentProcessor.h +++ b/gfx/skia/skia/include/gpu/effects/GrXfermodeFragmentProcessor.h @@ -8,7 +8,8 @@ #ifndef GrXfermodeFragmentProcessor_DEFINED #define GrXfermodeFragmentProcessor_DEFINED -#include "SkXfermode.h" +#include "SkRefCnt.h" +#include "SkBlendMode.h" class GrFragmentProcessor; @@ -16,19 +17,19 @@ namespace GrXfermodeFragmentProcessor { /** The color input to the returned processor is treated as the src and the passed in processor is the dst. */ sk_sp MakeFromDstProcessor(sk_sp dst, - SkXfermode::Mode mode); + SkBlendMode mode); /** The color input to the returned processor is treated as the dst and the passed in processor is the src. */ sk_sp MakeFromSrcProcessor(sk_sp src, - SkXfermode::Mode mode); + SkBlendMode mode); /** Takes the input color, which is assumed to be unpremultiplied, passes it as an opaque color to both src and dst. The outputs of a src and dst are blended using mode and the original input's alpha is applied to the blended color to produce a premul output. */ sk_sp MakeFromTwoProcessors(sk_sp src, sk_sp dst, - SkXfermode::Mode mode); + SkBlendMode mode); }; #endif diff --git a/gfx/skia/skia/include/gpu/gl/GrGLExtensions.h b/gfx/skia/skia/include/gpu/gl/GrGLExtensions.h index dd088de671cc..faf73fd36cb4 100644 --- a/gfx/skia/skia/include/gpu/gl/GrGLExtensions.h +++ b/gfx/skia/skia/include/gpu/gl/GrGLExtensions.h @@ -68,7 +68,7 @@ public: private: bool fInitialized; - SkAutoTDelete > fStrings; + std::unique_ptr> fStrings; }; #endif diff --git a/gfx/skia/skia/include/gpu/gl/GrGLFunctions.h b/gfx/skia/skia/include/gpu/gl/GrGLFunctions.h index eccd1bf002e6..9cb7ddc26166 100644 --- a/gfx/skia/skia/include/gpu/gl/GrGLFunctions.h +++ b/gfx/skia/skia/include/gpu/gl/GrGLFunctions.h @@ -24,6 +24,7 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindAttribLocationProc)(GrGLuint prog typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindBufferProc)(GrGLenum target, GrGLuint buffer); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindFramebufferProc)(GrGLenum target, GrGLuint framebuffer); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindRenderbufferProc)(GrGLenum target, GrGLuint renderbuffer); +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindImageTextureProc)(GrGLuint unit, GrGLuint texture, GrGLint level, GrGLboolean layered, GrGLint layer, GrGLenum access, GrGLenum format); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindTextureProc)(GrGLenum target, GrGLuint texture); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindFragDataLocationProc)(GrGLuint program, GrGLuint colorNumber, const GrGLchar* name); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindFragDataLocationIndexedProc)(GrGLuint program, GrGLuint colorNumber, GrGLuint index, const GrGLchar * name); @@ -118,7 +119,10 @@ typedef GrGLvoid* (GR_GL_FUNCTION_TYPE* GrGLMapBufferProc)(GrGLenum target, GrGL typedef GrGLvoid* (GR_GL_FUNCTION_TYPE* GrGLMapBufferRangeProc)(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length, GrGLbitfield access); typedef GrGLvoid* (GR_GL_FUNCTION_TYPE* GrGLMapBufferSubDataProc)(GrGLuint target, GrGLintptr offset, GrGLsizeiptr size, GrGLenum access); typedef GrGLvoid* (GR_GL_FUNCTION_TYPE* GrGLMapTexSubImage2DProc)(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLenum access); +typedef GrGLvoid* (GR_GL_FUNCTION_TYPE* GrGLMemoryBarrierProc)(GrGLbitfield barriers); +typedef GrGLvoid* (GR_GL_FUNCTION_TYPE* GrGLMemoryBarrierByRegionProc)(GrGLbitfield barriers); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPixelStoreiProc)(GrGLenum pname, GrGLint param); +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPolygonModeProc)(GrGLenum face, GrGLenum mode); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPopGroupMarkerProc)(); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPushGroupMarkerProc)(GrGLsizei length, const char* marker); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLQueryCounterProc)(GrGLuint id, GrGLenum target); @@ -348,6 +352,7 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTextureBufferProc)(GrGLuint texture, /* ARB_sync */ typedef GrGLsync (GR_GL_FUNCTION_TYPE* GrGLFenceSyncProc)(GrGLenum condition, GrGLbitfield flags); typedef GrGLenum (GR_GL_FUNCTION_TYPE* GrGLClientWaitSyncProc)(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout); +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLWaitSyncProc)(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteSyncProc)(GrGLsync sync); /* KHR_debug */ diff --git a/gfx/skia/skia/include/gpu/gl/GrGLInterface.h b/gfx/skia/skia/include/gpu/gl/GrGLInterface.h index 60109ec18770..c84eca28c640 100644 --- a/gfx/skia/skia/include/gpu/gl/GrGLInterface.h +++ b/gfx/skia/skia/include/gpu/gl/GrGLInterface.h @@ -55,10 +55,6 @@ typedef intptr_t GrGLInterfaceCallbackData; */ const SK_API GrGLInterface* GrGLCreateNullInterface(bool enableNVPR = false); -/** Function that returns a new interface identical to "interface" but without support for - GL_NV_path_rendering. */ -const GrGLInterface* GrGLInterfaceRemoveNVPR(const GrGLInterface*); - /** Function that returns a new interface identical to "interface" but with support for test version of GL_EXT_debug_marker. */ const GrGLInterface* GrGLInterfaceAddTestDebugMarker(const GrGLInterface*, @@ -116,6 +112,7 @@ public: GrGLFunction fBindFramebuffer; GrGLFunction fBindRenderbuffer; GrGLFunction fBindTexture; + GrGLFunction fBindImageTexture; GrGLFunction fBindVertexArray; GrGLFunction fBlendBarrier; GrGLFunction fBlendColor; @@ -207,9 +204,12 @@ public: GrGLFunction fMapBufferRange; GrGLFunction fMapBufferSubData; GrGLFunction fMapTexSubImage2D; + GrGLFunction fMemoryBarrier; + GrGLFunction fMemoryBarrierByRegion; GrGLFunction fMultiDrawArraysIndirect; GrGLFunction fMultiDrawElementsIndirect; GrGLFunction fPixelStorei; + GrGLFunction fPolygonMode; GrGLFunction fPopGroupMarker; GrGLFunction fPushGroupMarker; GrGLFunction fQueryCounter; @@ -455,6 +455,7 @@ public: /* ARB_sync */ GrGLFunction fFenceSync; GrGLFunction fClientWaitSync; + GrGLFunction fWaitSync; GrGLFunction fDeleteSync; /* KHR_debug */ diff --git a/gfx/skia/skia/include/gpu/gl/GrGLTypes.h b/gfx/skia/skia/include/gpu/gl/GrGLTypes.h index 5b9e31de1a44..f2b339eccc74 100644 --- a/gfx/skia/skia/include/gpu/gl/GrGLTypes.h +++ b/gfx/skia/skia/include/gpu/gl/GrGLTypes.h @@ -9,7 +9,9 @@ #ifndef GrGLTypes_DEFINED #define GrGLTypes_DEFINED +#include "GrExternalTextureData.h" #include "GrGLConfig.h" +#include "SkRefCnt.h" /** * Classifies GL contexts by which standard they implement (currently as OpenGL vs. OpenGL ES). @@ -58,7 +60,7 @@ typedef signed long int GrGLintptr; typedef signed long int GrGLsizeiptr; #endif typedef void* GrGLeglImage; -typedef void* GrGLsync; +typedef struct __GLsync* GrGLsync; struct GrGLDrawArraysIndirectCommand { GrGLuint fCount; @@ -112,6 +114,25 @@ struct GrGLTextureInfo { GrGLuint fID; }; +class GrSemaphore; + +class GrGLExternalTextureData : public GrExternalTextureData { +public: + GrGLExternalTextureData(const GrGLTextureInfo& info, sk_sp semaphore, GrContext*); + GrBackend getBackend() const override { return kOpenGL_GrBackend; } + +protected: + GrBackendObject getBackendObject() const override { + return reinterpret_cast(&fInfo); + } + void attachToContext(GrContext*) override; + + GrGLTextureInfo fInfo; + sk_sp fSemaphore; + + typedef GrExternalTextureData INHERITED; +}; + GR_STATIC_ASSERT(sizeof(GrBackendObject) >= sizeof(const GrGLTextureInfo*)); #endif diff --git a/gfx/skia/skia/include/gpu/vk/GrVkBackendContext.h b/gfx/skia/skia/include/gpu/vk/GrVkBackendContext.h index 9942016927f2..5ae7b31656a0 100644 --- a/gfx/skia/skia/include/gpu/vk/GrVkBackendContext.h +++ b/gfx/skia/skia/include/gpu/vk/GrVkBackendContext.h @@ -11,8 +11,7 @@ #include "SkRefCnt.h" #include "vk/GrVkDefines.h" - -struct GrVkInterface; +#include "vk/GrVkInterface.h" enum GrVkExtensionFlags { kEXT_debug_report_GrVkExtensionFlag = 0x0001, @@ -37,24 +36,27 @@ enum GrVkFeatureFlags { // creation, and any GrBackendObjects handed to us (e.g., for wrapped textures) need to be created // in or transitioned to that family. struct GrVkBackendContext : public SkRefCnt { - VkInstance fInstance; - VkPhysicalDevice fPhysicalDevice; - VkDevice fDevice; - VkQueue fQueue; - uint32_t fGraphicsQueueIndex; - uint32_t fMinAPIVersion; - uint32_t fExtensions; - uint32_t fFeatures; - SkAutoTUnref fInterface; + VkInstance fInstance; + VkPhysicalDevice fPhysicalDevice; + VkDevice fDevice; + VkQueue fQueue; + uint32_t fGraphicsQueueIndex; + uint32_t fMinAPIVersion; + uint32_t fExtensions; + uint32_t fFeatures; + sk_sp fInterface; using CanPresentFn = std::function; // Helper function to create the default Vulkan objects needed by the GrVkGpu object + // If getProc is NULL, a default getProc will be constructed if we are statically linking + // against Vulkan. // If presentQueueIndex is non-NULL, will try to set up presentQueue as part of device // creation using the platform-specific canPresent() function. static const GrVkBackendContext* Create(uint32_t* presentQueueIndex = nullptr, - CanPresentFn = CanPresentFn()); + CanPresentFn = CanPresentFn(), + GrVkInterface::GetProc getProc = nullptr); ~GrVkBackendContext() override; }; diff --git a/gfx/skia/skia/include/gpu/vk/GrVkDefines.h b/gfx/skia/skia/include/gpu/vk/GrVkDefines.h index 9caf2d75e524..ff8f2131f661 100644 --- a/gfx/skia/skia/include/gpu/vk/GrVkDefines.h +++ b/gfx/skia/skia/include/gpu/vk/GrVkDefines.h @@ -10,11 +10,23 @@ #define GrVkDefines_DEFINED #if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_WIN32) -# define VK_USE_PLATFORM_WIN32_KHR +# if !defined(VK_USE_PLATFORM_WIN32_KHR) +# define VK_USE_PLATFORM_WIN32_KHR +# endif #elif defined(SK_BUILD_FOR_ANDROID) -# define VK_USE_PLATFORM_ANDROID_KHR +# if !defined(VK_USE_PLATFORM_ANDROID_KHR) +# define VK_USE_PLATFORM_ANDROID_KHR +# endif #elif defined(SK_BUILD_FOR_UNIX) -# define VK_USE_PLATFORM_XCB_KHR +# if defined(__Fuchsia__) +# if !defined(VK_USE_PLATFORM_MAGMA_KHR) +# define VK_USE_PLATFORM_MAGMA_KHR +# endif +# else +# if !defined(VK_USE_PLATFORM_XCB_KHR) +# define VK_USE_PLATFORM_XCB_KHR +# endif +# endif #endif #if defined(Bool) || defined(Status) || defined(True) || defined(False) diff --git a/gfx/skia/skia/include/gpu/vk/GrVkInterface.h b/gfx/skia/skia/include/gpu/vk/GrVkInterface.h index 1f17865166b3..dca47ffc4ce7 100644 --- a/gfx/skia/skia/include/gpu/vk/GrVkInterface.h +++ b/gfx/skia/skia/include/gpu/vk/GrVkInterface.h @@ -14,20 +14,6 @@ //////////////////////////////////////////////////////////////////////////////// -/** - * The default interface is returned by GrVkCreateInterface. This function's - * implementation is platform-specific. - */ - -struct GrVkInterface; - -/** - * Creates a GrVkInterface. - */ -const GrVkInterface* GrVkCreateInterface(VkInstance instance, VkDevice device, - uint32_t extensionFlags); - - /** * GrContext uses the following interface to make all calls into Vulkan. When a * GrContext is created it is given a GrVkInterface. All functions that should be @@ -49,11 +35,19 @@ private: typedef SkRefCnt INHERITED; public: - GrVkInterface(); + using GetProc = std::function; + GrVkInterface(GetProc getProc, + VkInstance instance, + VkDevice device, + uint32_t extensionFlags); // Validates that the GrVkInterface supports its advertised standard. This means the necessary // function pointers have been initialized for Vulkan version. - bool validate() const; + bool validate(uint32_t extensionFlags) const; /** * The function pointers are in a struct so that we can have a compiler generated assignment diff --git a/gfx/skia/skia/include/gpu/vk/GrVkTypes.h b/gfx/skia/skia/include/gpu/vk/GrVkTypes.h index aa1334adca09..c98a94aa9259 100644 --- a/gfx/skia/skia/include/gpu/vk/GrVkTypes.h +++ b/gfx/skia/skia/include/gpu/vk/GrVkTypes.h @@ -9,6 +9,7 @@ #ifndef GrVkTypes_DEFINED #define GrVkTypes_DEFINED +#include "GrExternalTextureData.h" #include "GrTypes.h" #include "vk/GrVkDefines.h" @@ -59,6 +60,24 @@ struct GrVkImageInfo { void updateImageLayout(VkImageLayout layout) { fImageLayout = layout; } }; +class GrVkExternalTextureData : public GrExternalTextureData { +public: + GrVkExternalTextureData(const GrVkImageInfo& info) : fInfo(info) {} + GrBackend getBackend() const override { return kVulkan_GrBackend; } + +protected: + GrBackendObject getBackendObject() const override { + return reinterpret_cast(&fInfo); + } + void attachToContext(GrContext*) override { + // TODO: Implement this + } + + GrVkImageInfo fInfo; + + typedef GrExternalTextureData INHERITED; +}; + GR_STATIC_ASSERT(sizeof(GrBackendObject) >= sizeof(const GrVkImageInfo*)); #endif diff --git a/gfx/skia/skia/include/images/SkForceLinking.h b/gfx/skia/skia/include/images/SkForceLinking.h deleted file mode 100644 index 5de8918e6f62..000000000000 --- a/gfx/skia/skia/include/images/SkForceLinking.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTypes.h" - -/** - * This function's sole purpose is to trick the linker into not discarding - * SkImageDecoder subclasses just because we do not directly call them. - * This is necessary in applications that will create image decoders from - * a stream. - * Call this function with an expression that evaluates to false to ensure - * that the linker includes the subclasses. - * Passing true will result in leaked objects. - */ -int SkForceLinking(bool doNotPassTrue); - -#define __SK_FORCE_IMAGE_DECODER_LINKING \ -SK_UNUSED static int linking_forced = SkForceLinking(false) diff --git a/gfx/skia/skia/include/images/SkMovie.h b/gfx/skia/skia/include/images/SkMovie.h deleted file mode 100644 index 00dad6788554..000000000000 --- a/gfx/skia/skia/include/images/SkMovie.h +++ /dev/null @@ -1,80 +0,0 @@ - -/* - * Copyright 2008 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkMovie_DEFINED -#define SkMovie_DEFINED - -#include "SkRefCnt.h" -#include "SkCanvas.h" - -class SkStreamRewindable; - -class SkMovie : public SkRefCnt { -public: - - - /** Try to create a movie from the stream. If the stream format is not - supported, return NULL. - */ - static SkMovie* DecodeStream(SkStreamRewindable*); - /** Try to create a movie from the specified file path. If the file is not - found, or the format is not supported, return NULL. If a movie is - returned, the stream may be retained by the movie (via ref()) until - the movie is finished with it (by calling unref()). - */ - static SkMovie* DecodeFile(const char path[]); - /** Try to create a movie from the specified memory. - If the format is not supported, return NULL. If a movie is returned, - the data will have been read or copied, and so the caller may free - it. - */ - static SkMovie* DecodeMemory(const void* data, size_t length); - - SkMSec duration(); - int width(); - int height(); - int isOpaque(); - - /** Specify the time code (between 0...duration) to sample a bitmap - from the movie. Returns true if this time code generated a different - bitmap/frame from the previous state (i.e. true means you need to - redraw). - */ - bool setTime(SkMSec); - - // return the right bitmap for the current time code - const SkBitmap& bitmap(); - -protected: - struct Info { - SkMSec fDuration; - int fWidth; - int fHeight; - bool fIsOpaque; - }; - - virtual bool onGetInfo(Info*) = 0; - virtual bool onSetTime(SkMSec) = 0; - virtual bool onGetBitmap(SkBitmap*) = 0; - - // visible for subclasses - SkMovie(); - -private: - Info fInfo; - SkMSec fCurrTime; - SkBitmap fBitmap; - bool fNeedBitmap; - - void ensureInfo(); - - typedef SkRefCnt INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/pathops/SkPathOps.h b/gfx/skia/skia/include/pathops/SkPathOps.h index fa0178839462..1e8093f2a813 100644 --- a/gfx/skia/skia/include/pathops/SkPathOps.h +++ b/gfx/skia/skia/include/pathops/SkPathOps.h @@ -91,6 +91,8 @@ private: SkTArray fPathRefs; SkTDArray fOps; + static bool FixWinding(SkPath* path); + static void ReversePath(SkPath* path); void reset(); }; diff --git a/gfx/skia/skia/include/ports/SkFontConfigInterface.h b/gfx/skia/skia/include/ports/SkFontConfigInterface.h index 74f766f52e8a..ff80e5fb386e 100644 --- a/gfx/skia/skia/include/ports/SkFontConfigInterface.h +++ b/gfx/skia/skia/include/ports/SkFontConfigInterface.h @@ -109,9 +109,6 @@ public: */ static SkFontConfigInterface* GetSingletonDirectInterface(); - // New APIS, which have default impls for now (which do nothing) - - virtual sk_sp getFamilyNames() { return SkDataTable::MakeEmpty(); } typedef SkRefCnt INHERITED; }; diff --git a/gfx/skia/skia/include/ports/SkFontMgr.h b/gfx/skia/skia/include/ports/SkFontMgr.h index afadeaaa9785..b5879d35b822 100644 --- a/gfx/skia/skia/include/ports/SkFontMgr.h +++ b/gfx/skia/skia/include/ports/SkFontMgr.h @@ -8,9 +8,9 @@ #ifndef SkFontMgr_DEFINED #define SkFontMgr_DEFINED +#include "SkFontArguments.h" #include "SkFontStyle.h" #include "SkRefCnt.h" -#include "SkScalar.h" #include "SkTypes.h" class SkData; @@ -102,51 +102,10 @@ public: */ SkTypeface* createFromStream(SkStreamAsset*, int ttcIndex = 0) const; - struct FontParameters { - struct Axis { - SkFourByteTag fTag; - SkScalar fStyleValue; - }; - - FontParameters() : fCollectionIndex(0), fAxisCount(0), fAxes(nullptr) {} - - /** Specify the index of the desired font. - * - * Font formats like ttc, dfont, cff, cid, pfr, t42, t1, and fon may actually be indexed - * collections of fonts. - */ - FontParameters& setCollectionIndex(int collectionIndex) { - fCollectionIndex = collectionIndex; - return *this; - } - - /** Specify the GX variation axis values. - * - * Any axes not specified will use the default value. Specified axes not present in the - * font will be ignored. - * - * @param axes not copied. This pointer must remain valid for life of FontParameters. - */ - FontParameters& setAxes(const Axis* axes, int axisCount) { - fAxisCount = axisCount; - fAxes = axes; - return *this; - } - - int getCollectionIndex() const { - return fCollectionIndex; - } - const Axis* getAxes(int* axisCount) const { - *axisCount = fAxisCount; - return fAxes; - } - private: - int fCollectionIndex; - int fAxisCount; - const Axis* fAxes; - }; + // deprecated, use SkFontArguments instead. + using FontParameters = SkFontArguments; /* Experimental, API subject to change. */ - SkTypeface* createFromStream(SkStreamAsset*, const FontParameters&) const; + SkTypeface* createFromStream(SkStreamAsset*, const SkFontArguments&) const; /** * Create a typeface from the specified font data. @@ -165,11 +124,8 @@ public: SkTypeface* legacyCreateTypeface(const char familyName[], SkFontStyle style) const; - /** - * Return a ref to the default fontmgr. The caller must call unref() on - * the returned object. - */ - static SkFontMgr* RefDefault(); + /** Return the default fontmgr. */ + static sk_sp RefDefault(); protected: virtual int onCountFamilies() const = 0; @@ -190,14 +146,16 @@ protected: virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) const = 0; virtual SkTypeface* onCreateFromStream(SkStreamAsset*, int ttcIndex) const = 0; // TODO: make pure virtual. - virtual SkTypeface* onCreateFromStream(SkStreamAsset*, const FontParameters&) const; + virtual SkTypeface* onCreateFromStream(SkStreamAsset*, const SkFontArguments&) const; virtual SkTypeface* onCreateFromFontData(std::unique_ptr) const; virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const = 0; virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle) const = 0; private: - static SkFontMgr* Factory(); // implemented by porting layer + + /** Implemented by porting layer to return the default factory. */ + static sk_sp Factory(); typedef SkRefCnt INHERITED; }; diff --git a/gfx/skia/skia/include/ports/SkFontMgr_FontConfigInterface.h b/gfx/skia/skia/include/ports/SkFontMgr_FontConfigInterface.h index 356e54c87d0b..9dccb7bed7a4 100644 --- a/gfx/skia/skia/include/ports/SkFontMgr_FontConfigInterface.h +++ b/gfx/skia/skia/include/ports/SkFontMgr_FontConfigInterface.h @@ -15,6 +15,6 @@ class SkFontMgr; class SkFontConfigInterface; /** Creates a SkFontMgr which wraps a SkFontConfigInterface. */ -SK_API SkFontMgr* SkFontMgr_New_FCI(sk_sp fci); +SK_API sk_sp SkFontMgr_New_FCI(sk_sp fci); #endif // #ifndef SkFontMgr_FontConfigInterface_DEFINED diff --git a/gfx/skia/skia/include/ports/SkFontMgr_android.h b/gfx/skia/skia/include/ports/SkFontMgr_android.h index f12f51f36afc..050faddbb1bb 100644 --- a/gfx/skia/skia/include/ports/SkFontMgr_android.h +++ b/gfx/skia/skia/include/ports/SkFontMgr_android.h @@ -8,17 +8,10 @@ #ifndef SkFontMgr_android_DEFINED #define SkFontMgr_android_DEFINED -#include "SkTypes.h" +#include "SkRefCnt.h" class SkFontMgr; -/** - * For test only -- this only affects the default factory. - * Load font config from given xml files, instead of those from Android system. - */ -SK_API void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf, - const char* fontsdir); - struct SkFontMgr_Android_CustomFonts { /** When specifying custom fonts, indicates how to use system fonts. */ enum SystemFontUse { @@ -47,6 +40,6 @@ struct SkFontMgr_Android_CustomFonts { }; /** Create a font manager for Android. If 'custom' is NULL, use only system fonts. */ -SK_API SkFontMgr* SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom); +SK_API sk_sp SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom); #endif // SkFontMgr_android_DEFINED diff --git a/gfx/skia/skia/include/ports/SkFontMgr_custom.h b/gfx/skia/skia/include/ports/SkFontMgr_custom.h deleted file mode 100644 index 53be63db1b4d..000000000000 --- a/gfx/skia/skia/include/ports/SkFontMgr_custom.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkFontMgr_custom_DEFINED -#define SkFontMgr_custom_DEFINED - -#include "SkTypes.h" - -class SkFontMgr; - -/** Create a custom font manager which scans a given directory for font files. */ -SK_API SkFontMgr* SkFontMgr_New_Custom_Directory(const char* dir); - -/** Create a custom font manager that contains no built-in fonts. */ -SK_API SkFontMgr* SkFontMgr_New_Custom_Empty(); - -#endif // SkFontMgr_custom_DEFINED diff --git a/gfx/skia/skia/include/ports/SkFontMgr_directory.h b/gfx/skia/skia/include/ports/SkFontMgr_directory.h new file mode 100644 index 000000000000..8f79a7f5605d --- /dev/null +++ b/gfx/skia/skia/include/ports/SkFontMgr_directory.h @@ -0,0 +1,21 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_directory_DEFINED +#define SkFontMgr_directory_DEFINED + +#include "SkRefCnt.h" +#include "SkTypes.h" + +class SkFontMgr; + +/** Create a custom font manager which scans a given directory for font files. + * This font manager uses FreeType for rendering. + */ +SK_API sk_sp SkFontMgr_New_Custom_Directory(const char* dir); + +#endif // SkFontMgr_directory_DEFINED diff --git a/gfx/skia/skia/include/ports/SkFontMgr_empty.h b/gfx/skia/skia/include/ports/SkFontMgr_empty.h new file mode 100644 index 000000000000..dbeef586cb61 --- /dev/null +++ b/gfx/skia/skia/include/ports/SkFontMgr_empty.h @@ -0,0 +1,21 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_empty_DEFINED +#define SkFontMgr_empty_DEFINED + +#include "SkRefCnt.h" +#include "SkTypes.h" + +class SkFontMgr; + +/** Create a custom font manager that contains no built-in fonts. + * This font manager uses FreeType for rendering. + */ +SK_API sk_sp SkFontMgr_New_Custom_Empty(); + +#endif // SkFontMgr_empty_DEFINED diff --git a/gfx/skia/skia/include/ports/SkFontMgr_fontconfig.h b/gfx/skia/skia/include/ports/SkFontMgr_fontconfig.h index 7a59ff0c469e..e0f41089d51d 100644 --- a/gfx/skia/skia/include/ports/SkFontMgr_fontconfig.h +++ b/gfx/skia/skia/include/ports/SkFontMgr_fontconfig.h @@ -8,7 +8,7 @@ #ifndef SkFontMgr_fontconfig_DEFINED #define SkFontMgr_fontconfig_DEFINED -#include "SkTypes.h" +#include "SkRefCnt.h" #include class SkFontMgr; @@ -17,6 +17,6 @@ class SkFontMgr; * If 'fc' is NULL, will use a new default config. * Takes ownership of 'fc' and will call FcConfigDestroy on it. */ -SK_API SkFontMgr* SkFontMgr_New_FontConfig(FcConfig* fc); +SK_API sk_sp SkFontMgr_New_FontConfig(FcConfig* fc); #endif // #ifndef SkFontMgr_fontconfig_DEFINED diff --git a/gfx/skia/skia/include/ports/SkFontMgr_indirect.h b/gfx/skia/skia/include/ports/SkFontMgr_indirect.h index 406a75a7ee35..b9ab3ba913bc 100644 --- a/gfx/skia/skia/include/ports/SkFontMgr_indirect.h +++ b/gfx/skia/skia/include/ports/SkFontMgr_indirect.h @@ -11,7 +11,6 @@ #include "../private/SkMutex.h" #include "../private/SkOnce.h" #include "../private/SkTArray.h" -#include "SkDataTable.h" #include "SkFontMgr.h" #include "SkRefCnt.h" #include "SkRemotableFontMgr.h" @@ -28,8 +27,8 @@ public: // TODO: The SkFontMgr is only used for createFromStream/File/Data. // In the future these calls should be broken out into their own interface // with a name like SkFontRenderer. - SkFontMgr_Indirect(SkFontMgr* impl, SkRemotableFontMgr* proxy) - : fImpl(SkRef(impl)), fProxy(SkRef(proxy)) + SkFontMgr_Indirect(sk_sp impl, sk_sp proxy) + : fImpl(std::move(impl)), fProxy(std::move(proxy)) { } protected: @@ -60,8 +59,8 @@ protected: private: SkTypeface* createTypefaceFromFontId(const SkFontIdentity& fontId) const; - SkAutoTUnref fImpl; - SkAutoTUnref fProxy; + sk_sp fImpl; + sk_sp fProxy; struct DataEntry { uint32_t fDataId; // key1 @@ -95,10 +94,6 @@ private: mutable SkTArray fDataCache; mutable SkMutex fDataCacheMutex; - mutable sk_sp fFamilyNames; - mutable SkOnce fFamilyNamesInitOnce; - static void set_up_family_names(const SkFontMgr_Indirect* self); - friend class SkStyleSet_Indirect; }; diff --git a/gfx/skia/skia/include/ports/SkRemotableFontMgr.h b/gfx/skia/skia/include/ports/SkRemotableFontMgr.h index 2e028cee2620..12050c7e07ab 100644 --- a/gfx/skia/skia/include/ports/SkRemotableFontMgr.h +++ b/gfx/skia/skia/include/ports/SkRemotableFontMgr.h @@ -55,15 +55,6 @@ private: class SK_API SkRemotableFontMgr : public SkRefCnt { public: - /** - * Returns the names of the known fonts on the system. - * Will not return NULL, will return an empty table if no families exist. - * - * The indexes may be used with getIndex(int) and - * matchIndexStyle(int, SkFontStyle). - */ - virtual sk_sp getFamilyNames() const = 0; - /** * Returns all of the fonts with the given familyIndex. * Returns NULL if the index is out of bounds. diff --git a/gfx/skia/skia/include/ports/SkTypeface_win.h b/gfx/skia/skia/include/ports/SkTypeface_win.h index 87dd60c37344..cb760ae31b58 100644 --- a/gfx/skia/skia/include/ports/SkTypeface_win.h +++ b/gfx/skia/skia/include/ports/SkTypeface_win.h @@ -55,12 +55,12 @@ SK_API SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFactory* aFactory, SkFontStyle aStyle, bool aForceGDI); -SK_API SkFontMgr* SkFontMgr_New_GDI(); -SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory = NULL, - IDWriteFontCollection* collection = NULL); -SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory, - IDWriteFontCollection* collection, - IDWriteFontFallback* fallback); +SK_API sk_sp SkFontMgr_New_GDI(); +SK_API sk_sp SkFontMgr_New_DirectWrite(IDWriteFactory* factory = NULL, + IDWriteFontCollection* collection = NULL); +SK_API sk_sp SkFontMgr_New_DirectWrite(IDWriteFactory* factory, + IDWriteFontCollection* collection, + IDWriteFontFallback* fallback); /** * Creates an SkFontMgr which renders using DirectWrite and obtains its data @@ -68,7 +68,7 @@ SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory, * * If DirectWrite could not be initialized, will return NULL. */ -SK_API SkFontMgr* SkFontMgr_New_DirectWriteRenderer(SkRemotableFontMgr*); +SK_API sk_sp SkFontMgr_New_DirectWriteRenderer(sk_sp); /** * Creates an SkRemotableFontMgr backed by DirectWrite using the default @@ -76,7 +76,7 @@ SK_API SkFontMgr* SkFontMgr_New_DirectWriteRenderer(SkRemotableFontMgr*); * * If DirectWrite could not be initialized, will return NULL. */ -SK_API SkRemotableFontMgr* SkRemotableFontMgr_New_DirectWrite(); +SK_API sk_sp SkRemotableFontMgr_New_DirectWrite(); #endif // SK_BUILD_FOR_WIN #endif // SkTypeface_win_DEFINED diff --git a/gfx/skia/skia/include/private/GrAuditTrail.h b/gfx/skia/skia/include/private/GrAuditTrail.h index 3bb7bea43503..9fdae30f8f32 100644 --- a/gfx/skia/skia/include/private/GrAuditTrail.h +++ b/gfx/skia/skia/include/private/GrAuditTrail.h @@ -9,12 +9,14 @@ #define GrAuditTrail_DEFINED #include "GrConfig.h" +#include "GrGpuResource.h" +#include "GrRenderTargetProxy.h" #include "SkRect.h" #include "SkString.h" #include "SkTArray.h" #include "SkTHash.h" -class GrBatch; +class GrOp; /* * GrAuditTrail collects a list of draw ops, detailed information about those ops, and can dump them @@ -48,31 +50,26 @@ public: GrAuditTrail* fAuditTrail; }; - class AutoManageBatchList { + class AutoManageOpList { public: - AutoManageBatchList(GrAuditTrail* auditTrail) - : fAutoEnable(auditTrail) - , fAuditTrail(auditTrail) { - } + AutoManageOpList(GrAuditTrail* auditTrail) + : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {} - ~AutoManageBatchList() { - fAuditTrail->fullReset(); - } + ~AutoManageOpList() { fAuditTrail->fullReset(); } private: AutoEnable fAutoEnable; GrAuditTrail* fAuditTrail; }; - class AutoCollectBatches { + class AutoCollectOps { public: - AutoCollectBatches(GrAuditTrail* auditTrail, int clientID) - : fAutoEnable(auditTrail) - , fAuditTrail(auditTrail) { + AutoCollectOps(GrAuditTrail* auditTrail, int clientID) + : fAutoEnable(auditTrail), fAuditTrail(auditTrail) { fAuditTrail->setClientID(clientID); } - ~AutoCollectBatches() { fAuditTrail->setClientID(kGrAuditTrailInvalidID); } + ~AutoCollectOps() { fAuditTrail->setClientID(kGrAuditTrailInvalidID); } private: AutoEnable fAutoEnable; @@ -84,19 +81,21 @@ public: fCurrentStackTrace.push_back(SkString(framename)); } - void addBatch(const GrBatch* batch); + void addOp(const GrOp*, + GrGpuResource::UniqueID resourceID, + GrRenderTargetProxy::UniqueID proxyID); - void batchingResultCombined(const GrBatch* consumer, const GrBatch* consumed); + void opsCombined(const GrOp* consumer, const GrOp* consumed); - // Because batching is heavily dependent on sequence of draw calls, these calls will only - // produce valid information for the given draw sequence which preceeded them. - // Specifically, future draw calls may change the batching and thus would invalidate - // the json. What this means is that for some sequence of draw calls N, the below toJson - // calls will only produce JSON which reflects N draw calls. This JSON may or may not be - // accurate for N + 1 or N - 1 draws depending on the actual batching algorithm used. + // Because op combining is heavily dependent on sequence of draw calls, these calls will only + // produce valid information for the given draw sequence which preceeded them. Specifically, ops + // of future draw calls may combine with previous ops and thus would invalidate the json. What + // this means is that for some sequence of draw calls N, the below toJson calls will only + // produce JSON which reflects N draw calls. This JSON may or may not be accurate for N + 1 or + // N - 1 draws depending on the actual combining algorithm used. SkString toJson(bool prettyPrint = false) const; - // returns a json string of all of the batches associated with a given client id + // returns a json string of all of the ops associated with a given client id SkString toJson(int clientID, bool prettyPrint = false) const; bool isEnabled() { return fEnabled; } @@ -106,18 +105,28 @@ public: // We could just return our internal bookkeeping struct if copying the data out becomes // a performance issue, but until then its nice to decouple - struct BatchInfo { - SkRect fBounds; - uint32_t fRenderTargetUniqueID; - struct Batch { - int fClientID; + struct OpInfo { + // Will the resourceID comparison yield the same decision as the proxyID comparison? + bool sameDecision(GrGpuResource::UniqueID resourceUniqueID, + GrSurfaceProxy::UniqueID proxyUniqueID) const { + return (fResourceUniqueID == resourceUniqueID) == + (fProxyUniqueID == proxyUniqueID); + } + + struct Op { + int fClientID; SkRect fBounds; }; - SkTArray fBatches; + + SkRect fBounds; + // MDB TODO: remove fResourceUniqueID + GrGpuResource::UniqueID fResourceUniqueID; + GrSurfaceProxy::UniqueID fProxyUniqueID; + SkTArray fOps; }; - void getBoundsByClientID(SkTArray* outInfo, int clientID); - void getBoundsByBatchListID(BatchInfo* outInfo, int batchListID); + void getBoundsByClientID(SkTArray* outInfo, int clientID); + void getBoundsByOpListID(OpInfo* outInfo, int opListID); void fullReset(); @@ -125,40 +134,46 @@ public: private: // TODO if performance becomes an issue, we can move to using SkVarAlloc - struct Batch { + struct Op { SkString toJson() const; SkString fName; SkTArray fStackTrace; SkRect fBounds; int fClientID; - int fBatchListID; + int fOpListID; int fChildID; }; - typedef SkTArray, true> BatchPool; + typedef SkTArray, true> OpPool; - typedef SkTArray Batches; + typedef SkTArray Ops; - struct BatchNode { + struct OpNode { + OpNode(const GrGpuResource::UniqueID& resourceID, const GrSurfaceProxy::UniqueID& proxyID) + : fResourceUniqueID(resourceID) + , fProxyUniqueID(proxyID) { + } SkString toJson() const; - SkRect fBounds; - Batches fChildren; - uint32_t fRenderTargetUniqueID; - }; - typedef SkTArray, true> BatchList; - void copyOutFromBatchList(BatchInfo* outBatchInfo, int batchListID); + SkRect fBounds; + Ops fChildren; + const GrGpuResource::UniqueID fResourceUniqueID; + const GrSurfaceProxy::UniqueID fProxyUniqueID; + }; + typedef SkTArray, true> OpList; + + void copyOutFromOpList(OpInfo* outOpInfo, int opListID); template static void JsonifyTArray(SkString* json, const char* name, const T& array, bool addComma); - - BatchPool fBatchPool; + + OpPool fOpPool; SkTHashMap fIDLookup; - SkTHashMap fClientIDLookup; - BatchList fBatchList; + SkTHashMap fClientIDLookup; + OpList fOpList; SkTArray fCurrentStackTrace; - // The client cas pass in an optional client ID which we will use to mark the batches + // The client can pass in an optional client ID which we will use to mark the ops int fClientID; bool fEnabled; }; @@ -174,13 +189,12 @@ private: #define GR_AUDIT_TRAIL_RESET(audit_trail) \ //GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, fullReset); -#define GR_AUDIT_TRAIL_ADDBATCH(audit_trail, batch) \ - GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addBatch, batch); +#define GR_AUDIT_TRAIL_ADD_OP(audit_trail, op, resource_id, proxy_id) \ + GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addOp, op, resource_id, proxy_id); -#define GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(audit_trail, combineWith, batch) \ - GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, batchingResultCombined, combineWith, batch); +#define GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(audit_trail, combineWith, op) \ + GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, opsCombined, combineWith, op); -#define GR_AUDIT_TRAIL_BATCHING_RESULT_NEW(audit_trail, batch) \ - // Doesn't do anything now, one day... +#define GR_AUDIT_TRAIL_OP_RESULT_NEW(audit_trail, op) // Doesn't do anything now, one day... #endif diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSL.h b/gfx/skia/skia/include/private/GrGLSL.h similarity index 86% rename from gfx/skia/skia/src/gpu/glsl/GrGLSL.h rename to gfx/skia/skia/include/private/GrGLSL.h index e4e165b284b0..66f7be84d143 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSL.h +++ b/gfx/skia/skia/include/private/GrGLSL.h @@ -11,7 +11,7 @@ #include "GrTypesPriv.h" #include "SkString.h" -class GrGLSLCaps; +class GrShaderCaps; // Limited set of GLSL versions we build shaders for. Caller should round // down the GLSL version to one of these enums. @@ -40,6 +40,10 @@ enum GrGLSLGeneration { * Desktop GLSL 4.00 */ k400_GrGLSLGeneration, + /** + * Desktop GLSL 4.20 + */ + k420_GrGLSLGeneration, /** * ES GLSL 3.10 only TODO Make GLSLCap objects to make this more granular */ @@ -52,36 +56,11 @@ enum GrGLSLGeneration { bool GrGLSLSupportsNamedFragmentShaderOutputs(GrGLSLGeneration); -/** - * Gets the name of the function that should be used to sample a 2D texture. Coord type is used - * to indicate whether the texture is sampled using projective textured (kVec3f) or not (kVec2f). - */ -inline const char* GrGLSLTexture2DFunctionName(GrSLType coordType, GrSLType samplerType, - GrGLSLGeneration glslGen) { - SkASSERT(GrSLTypeIs2DCombinedSamplerType(samplerType)); - SkASSERT(kVec2f_GrSLType == coordType || kVec3f_GrSLType == coordType); - // GL_TEXTURE_RECTANGLE_ARB is written against OpenGL 2.0/GLSL 1.10. At that time there were - // separate texture*() functions. In OpenGL 3.0/GLSL 1.30 the different texture*() functions - // were deprecated in favor or the unified texture() function. RECTANGLE textures became - // standard in OpenGL 3.2/GLSL 1.50 and use texture(). It isn't completely clear what function - // should be used for RECTANGLE textures in GLSL versions >= 1.30 && < 1.50. We're going with - // using texture(). - if (glslGen >= k130_GrGLSLGeneration) { - return (kVec2f_GrSLType == coordType) ? "texture" : "textureProj"; - } - if (kVec2f_GrSLType == coordType) { - return (samplerType == kTexture2DRectSampler_GrSLType) ? "texture2DRect" : "texture2D"; - } else { - return (samplerType == kTexture2DRectSampler_GrSLType) ? "texture2DRectProj" - : "texture2DProj"; - } -} - /** * Adds a line of GLSL code to declare the default precision for float types. */ void GrGLSLAppendDefaultFloatPrecisionDeclaration(GrSLPrecision, - const GrGLSLCaps& glslCaps, + const GrShaderCaps&, SkString* out); /** @@ -95,6 +74,8 @@ static inline const char* GrGLSLPrecisionString(GrSLPrecision p) { return "mediump"; case kHigh_GrSLPrecision: return "highp"; + case kDefault_GrSLPrecision: + return ""; default: SkFAIL("Unexpected precision type."); return ""; @@ -116,6 +97,12 @@ static inline const char* GrGLSLTypeString(GrSLType t) { return "vec3"; case kVec4f_GrSLType: return "vec4"; + case kVec2i_GrSLType: + return "ivec2"; + case kVec3i_GrSLType: + return "ivec3"; + case kVec4i_GrSLType: + return "ivec4"; case kMat22f_GrSLType: return "mat2"; case kMat33f_GrSLType: @@ -124,11 +111,13 @@ static inline const char* GrGLSLTypeString(GrSLType t) { return "mat4"; case kTexture2DSampler_GrSLType: return "sampler2D"; + case kITexture2DSampler_GrSLType: + return "isampler2D"; case kTextureExternalSampler_GrSLType: return "samplerExternalOES"; case kTexture2DRectSampler_GrSLType: return "sampler2DRect"; - case kTextureBufferSampler_GrSLType: + case kBufferSampler_GrSLType: return "samplerBuffer"; case kBool_GrSLType: return "bool"; @@ -140,10 +129,13 @@ static inline const char* GrGLSLTypeString(GrSLType t) { return "texture2D"; case kSampler_GrSLType: return "sampler"; - default: - SkFAIL("Unknown shader var type."); - return ""; // suppress warning + case kImageStorage2D_GrSLType: + return "image2D"; + case kIImageStorage2D_GrSLType: + return "iimage2D"; } + SkFAIL("Unknown shader var type."); + return ""; // suppress warning } /** A generic base-class representing a GLSL expression. diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSL_impl.h b/gfx/skia/skia/include/private/GrGLSL_impl.h similarity index 100% rename from gfx/skia/skia/src/gpu/glsl/GrGLSL_impl.h rename to gfx/skia/skia/include/private/GrGLSL_impl.h diff --git a/gfx/skia/skia/include/private/GrInstancedPipelineInfo.h b/gfx/skia/skia/include/private/GrInstancedPipelineInfo.h index 7e6482da9014..196c35b96f98 100644 --- a/gfx/skia/skia/include/private/GrInstancedPipelineInfo.h +++ b/gfx/skia/skia/include/private/GrInstancedPipelineInfo.h @@ -8,42 +8,23 @@ #ifndef GrGrInstancedPipelineInfo_DEFINED #define GrGrInstancedPipelineInfo_DEFINED -#include "GrRenderTarget.h" +#include "GrRenderTargetProxy.h" /** * Provides info about the pipeline that GrInstancedRendering needs in order to select appropriate * drawing algorithms. */ struct GrInstancedPipelineInfo { - GrInstancedPipelineInfo(const GrRenderTarget* rt) - : fIsMultisampled(rt->isStencilBufferMultisampled()), - fIsMixedSampled(rt->isMixedSampled()), - fIsRenderingToFloat(GrPixelConfigIsFloatingPoint(rt->desc().fConfig)), - fColorDisabled(false), - fDrawingShapeToStencil(false), - fCanDiscard(false) { - } + GrInstancedPipelineInfo(const GrRenderTargetProxy* rtp) + : fIsMultisampled(rtp->isStencilBufferMultisampled()) + , fIsMixedSampled(rtp->isMixedSampled()) + , fIsRenderingToFloat(GrPixelConfigIsFloatingPoint(rtp->desc().fConfig)) {} - bool canUseCoverageAA() const { - return !fIsMultisampled || (fIsMixedSampled && !fDrawingShapeToStencil); - } + bool canUseCoverageAA() const { return !fIsMultisampled || fIsMixedSampled; } bool fIsMultisampled : 1; bool fIsMixedSampled : 1; bool fIsRenderingToFloat : 1; - bool fColorDisabled : 1; - /** - * Indicates that the instanced renderer should take extra precautions to ensure the shape gets - * drawn correctly to the stencil buffer (e.g. no coverage AA). NOTE: this does not mean a - * stencil test is or is not active. - */ - bool fDrawingShapeToStencil : 1; - /** - * Indicates that the instanced renderer can use processors with discard instructions. This - * should not be set if the shader will use derivatives, automatic mipmap LOD, or other features - * that depend on neighboring pixels. Some draws will fail to create if this is not set. - */ - bool fCanDiscard : 1; }; #endif diff --git a/gfx/skia/skia/include/private/GrRenderTargetProxy.h b/gfx/skia/skia/include/private/GrRenderTargetProxy.h index e4bc70f21273..adc755394152 100644 --- a/gfx/skia/skia/include/private/GrRenderTargetProxy.h +++ b/gfx/skia/skia/include/private/GrRenderTargetProxy.h @@ -9,33 +9,22 @@ #define GrRenderTargetProxy_DEFINED #include "GrRenderTarget.h" -#include "GrRenderTargetPriv.h" #include "GrSurfaceProxy.h" #include "GrTypes.h" -class GrTextureProvider; +class GrResourceProvider; // This class delays the acquisition of RenderTargets until they are actually // required // Beware: the uniqueID of the RenderTargetProxy will usually be different than // the uniqueID of the RenderTarget it represents! -class GrRenderTargetProxy : public GrSurfaceProxy { +class GrRenderTargetProxy : virtual public GrSurfaceProxy { public: - /** - * The caller gets the creation ref. - */ - static sk_sp Make(const GrCaps&, const GrSurfaceDesc&, - SkBackingFit, SkBudgeted); - static sk_sp Make(const GrCaps&, sk_sp); - - ~GrRenderTargetProxy() override; - - // TODO: add asTextureProxy variants GrRenderTargetProxy* asRenderTargetProxy() override { return this; } const GrRenderTargetProxy* asRenderTargetProxy() const override { return this; } // Actually instantiate the backing rendertarget, if necessary. - GrRenderTarget* instantiate(GrTextureProvider* texProvider); + GrRenderTarget* instantiate(GrResourceProvider* resourceProvider); bool isStencilBufferMultisampled() const { return fDesc.fSampleCnt > 0; } @@ -43,7 +32,7 @@ public: * For our purposes, "Mixed Sampled" means the stencil buffer is multisampled but the color * buffer is not. */ - bool isMixedSampled() const { return fFlags & GrRenderTargetPriv::Flags::kMixedSampled; } + bool isMixedSampled() const { return fRenderTargetFlags & GrRenderTarget::Flags::kMixedSampled; } /** * "Unified Sampled" means the stencil and color buffers are both multisampled. @@ -60,36 +49,36 @@ public: */ int numColorSamples() const { return this->isMixedSampled() ? 0 : fDesc.fSampleCnt; } - void setLastDrawTarget(GrDrawTarget* dt); - GrDrawTarget* getLastDrawTarget() { return fLastDrawTarget; } + int maxWindowRectangles(const GrCaps& caps) const; - GrRenderTargetPriv::Flags testingOnly_getFlags() const; + GrRenderTarget::Flags testingOnly_getFlags() const; + + // TODO: move this to a priv class! + bool refsWrappedObjects() const; + +protected: + friend class GrSurfaceProxy; // for ctors -private: // Deferred version - GrRenderTargetProxy(const GrCaps&, const GrSurfaceDesc&, SkBackingFit, SkBudgeted); + GrRenderTargetProxy(const GrCaps&, const GrSurfaceDesc&, + SkBackingFit, SkBudgeted, uint32_t flags); // Wrapped version - GrRenderTargetProxy(const GrCaps&, sk_sp rt); + GrRenderTargetProxy(sk_sp); - // For wrapped render targets we store it here. - // For deferred proxies we will fill this in when we need to instantiate the deferred resource - sk_sp fTarget; +private: + size_t onGpuMemorySize() const override; + + // For wrapped render targets the actual GrRenderTarget is stored in the GrIORefProxy class. + // For deferred proxies that pointer is filled in when we need to instantiate the + // deferred resource. // These don't usually get computed until the render target is instantiated, but the render // target proxy may need to answer queries about it before then. And since in the deferred case // we know the newly created render target will be internal, we are able to precompute what the // flags will ultimately end up being. In the wrapped case we just copy the wrapped // rendertarget's info here. - GrRenderTargetPriv::Flags fFlags; - - // The last drawTarget that wrote to or is currently going to write to this renderTarget - // The drawTarget can be closed (e.g., no draw context is currently bound - // to this renderTarget). - // This back-pointer is required so that we can add a dependancy between - // the drawTarget used to create the current contents of this renderTarget - // and the drawTarget of a destination renderTarget to which this one is being drawn. - GrDrawTarget* fLastDrawTarget; + GrRenderTarget::Flags fRenderTargetFlags; typedef GrSurfaceProxy INHERITED; }; diff --git a/gfx/skia/skia/include/private/GrSurfaceProxy.h b/gfx/skia/skia/include/private/GrSurfaceProxy.h index 69656fe4f57c..8d5a0caf1035 100644 --- a/gfx/skia/skia/include/private/GrSurfaceProxy.h +++ b/gfx/skia/skia/include/private/GrSurfaceProxy.h @@ -9,13 +9,189 @@ #define GrSurfaceProxy_DEFINED #include "GrGpuResource.h" +#include "GrSurface.h" + #include "SkRect.h" -class GrTextureProxy; +class GrCaps; +class GrRenderTargetOpList; class GrRenderTargetProxy; +class GrResourceProvider; +class GrSurfaceContext; +class GrSurfaceProxyPriv; +class GrTextureOpList; +class GrTextureProxy; -class GrSurfaceProxy : public GrIORef { +//#define SK_DISABLE_DEFERRED_PROXIES 1 + +// This class replicates the functionality GrIORef but tracks the +// utilitization for later resource allocation (for the deferred case) and +// forwards on the utilization in the wrapped case +class GrIORefProxy : public SkNoncopyable { public: + void ref() const { + this->validate(); + + ++fRefCnt; + if (fTarget) { + fTarget->ref(); + } + } + + void unref() const { + this->validate(); + + if (fTarget) { + fTarget->unref(); + } + + if (!(--fRefCnt)) { + delete this; + return; + } + + this->validate(); + } + + void validate() const { +#ifdef SK_DEBUG + SkASSERT(fRefCnt >= 1); + SkASSERT(fPendingReads >= 0); + SkASSERT(fPendingWrites >= 0); + SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 1); + + if (fTarget) { + SkASSERT(!fPendingReads && !fPendingWrites); + // The backing GrSurface can have more refs than the proxy if the proxy + // started off wrapping an external resource (that came in with refs). + // The GrSurface should never have fewer refs than the proxy however. + SkASSERT(fTarget->fRefCnt >= fRefCnt); + } +#endif + } + + int32_t getProxyRefCnt_TestOnly() const; + int32_t getBackingRefCnt_TestOnly() const; + int32_t getPendingReadCnt_TestOnly() const; + int32_t getPendingWriteCnt_TestOnly() const; + +protected: + GrIORefProxy() : fTarget(nullptr), fRefCnt(1), fPendingReads(0), fPendingWrites(0) {} + GrIORefProxy(sk_sp surface) : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { + // Since we're manually forwarding on refs & unrefs we don't want sk_sp doing + // anything extra. + fTarget = surface.release(); + } + virtual ~GrIORefProxy() { + // We don't unref 'fTarget' here since the 'unref' method will already + // have forwarded on the unref call that got use here. + } + + // This GrIORefProxy was deferred before but has just been instantiated. To + // make all the reffing & unreffing work out we now need to transfer any deferred + // refs & unrefs to the new GrSurface + void transferRefs() { + SkASSERT(fTarget); + + fTarget->fRefCnt += (fRefCnt-1); // don't xfer the proxy's creation ref + fTarget->fPendingReads += fPendingReads; + fTarget->fPendingWrites += fPendingWrites; + + fPendingReads = 0; + fPendingWrites = 0; + } + + bool internalHasPendingIO() const { + if (fTarget) { + return fTarget->internalHasPendingIO(); + } + + return SkToBool(fPendingWrites | fPendingReads); + } + + bool internalHasPendingWrite() const { + if (fTarget) { + return fTarget->internalHasPendingWrite(); + } + + return SkToBool(fPendingWrites); + } + + // For deferred proxies this will be null. For wrapped proxies it will point to the + // wrapped resource. + GrSurface* fTarget; + +private: + // This class is used to manage conversion of refs to pending reads/writes. + friend class GrGpuResourceRef; + template friend class GrPendingIOResource; + + void addPendingRead() const { + this->validate(); + + if (fTarget) { + fTarget->addPendingRead(); + return; + } + + ++fPendingReads; + } + + void completedRead() const { + this->validate(); + + if (fTarget) { + fTarget->completedRead(); + return; + } + + SkFAIL("How was the read completed if the Proxy hasn't been instantiated?"); + } + + void addPendingWrite() const { + this->validate(); + + if (fTarget) { + fTarget->addPendingWrite(); + return; + } + + ++fPendingWrites; + } + + void completedWrite() const { + this->validate(); + + if (fTarget) { + fTarget->completedWrite(); + return; + } + + SkFAIL("How was the write completed if the Proxy hasn't been instantiated?"); + } + + mutable int32_t fRefCnt; + mutable int32_t fPendingReads; + mutable int32_t fPendingWrites; +}; + +class GrSurfaceProxy : public GrIORefProxy { +public: + static sk_sp MakeWrapped(sk_sp); + static sk_sp MakeWrapped(sk_sp); + + static sk_sp MakeDeferred(GrResourceProvider*, + const GrSurfaceDesc&, SkBackingFit, + SkBudgeted, uint32_t flags = 0); + + // TODO: need to refine ownership semantics of 'srcData' if we're in completely + // deferred mode + static sk_sp MakeDeferred(GrResourceProvider*, + const GrSurfaceDesc&, SkBudgeted, + const void* srcData, size_t rowBytes); + + static sk_sp MakeWrappedBackend(GrContext*, GrBackendTextureDesc&); + const GrSurfaceDesc& desc() const { return fDesc; } GrSurfaceOrigin origin() const { @@ -24,16 +200,65 @@ public: return fDesc.fOrigin; } int width() const { return fDesc.fWidth; } - int height() const { return fDesc.fWidth; } + int height() const { return fDesc.fHeight; } GrPixelConfig config() const { return fDesc.fConfig; } - uint32_t uniqueID() const { return fUniqueID; } + class UniqueID { + public: + static UniqueID InvalidID() { + return UniqueID(uint32_t(SK_InvalidUniqueID)); + } + + // wrapped + explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { } + // deferred + UniqueID() : fID(GrGpuResource::CreateUniqueID()) { } + + uint32_t asUInt() const { return fID; } + + bool operator==(const UniqueID& other) const { + return fID == other.fID; + } + bool operator!=(const UniqueID& other) const { + return !(*this == other); + } + + void makeInvalid() { fID = SK_InvalidUniqueID; } + bool isInvalid() const { return SK_InvalidUniqueID == fID; } + + private: + explicit UniqueID(uint32_t id) : fID(id) {} + + uint32_t fID; + }; + + /* + * The contract for the uniqueID is: + * for wrapped resources: + * the uniqueID will match that of the wrapped resource + * + * for deferred resources: + * the uniqueID will be different from the real resource, when it is allocated + * the proxy's uniqueID will not change across the instantiate call + * + * the uniqueIDs of the proxies and the resources draw from the same pool + * + * What this boils down to is that the uniqueID of a proxy can be used to consistently + * track/identify a proxy but should never be used to distinguish between + * resources and proxies - beware! + */ + UniqueID uniqueID() const { return fUniqueID; } + + GrSurface* instantiate(GrResourceProvider* resourceProvider); /** * Helper that gets the width and height of the surface as a bounding rectangle. */ SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); } - + + int worstCaseWidth(const GrCaps& caps) const; + int worstCaseHeight(const GrCaps& caps) const; + /** * @return the texture proxy associated with the surface proxy, may be NULL. */ @@ -51,42 +276,113 @@ public: */ SkBudgeted isBudgeted() const { return fBudgeted; } + void setLastOpList(GrOpList* opList); + GrOpList* getLastOpList() { return fLastOpList; } + + GrRenderTargetOpList* getLastRenderTargetOpList(); + GrTextureOpList* getLastTextureOpList(); + + /** + * Retrieves the amount of GPU memory that will be or currently is used by this resource + * in bytes. It is approximate since we aren't aware of additional padding or copies made + * by the driver. + * + * @return the amount of GPU memory used in bytes + */ + size_t gpuMemorySize() const { + if (kInvalidGpuMemorySize == fGpuMemorySize) { + fGpuMemorySize = this->onGpuMemorySize(); + SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); + } + return fGpuMemorySize; + } + + // Helper function that creates a temporary SurfaceContext to perform the copy + // It always returns a kExact-backed proxy bc it is used when converting an SkSpecialImage + // to an SkImage. + static sk_sp Copy(GrContext*, GrSurfaceProxy* src, + SkIRect srcRect, SkBudgeted); + + // Copy the entire 'src' + // It always returns a kExact-backed proxy bc it is used in SkGpuDevice::snapSpecial + static sk_sp Copy(GrContext* context, GrSurfaceProxy* src, + SkBudgeted budgeted); + + // Test-only entry point - should decrease in use as proxies propagate + static sk_sp TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc, + GrSurfaceProxy* srcProxy); + + bool isWrapped_ForTesting() const; + + SkDEBUGCODE(void validate(GrContext*) const;) + + // Provides access to functions that aren't part of the public API. + GrSurfaceProxyPriv priv(); + const GrSurfaceProxyPriv priv() const; + protected: // Deferred version - GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted) + GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted, uint32_t flags) : fDesc(desc) , fFit(fit) , fBudgeted(budgeted) - , fUniqueID(GrGpuResource::CreateUniqueID()) { + , fFlags(flags) + // fMipColorMode is only valid for texturable proxies + , fMipColorMode(SkDestinationSurfaceColorMode::kLegacy) + , fGpuMemorySize(kInvalidGpuMemorySize) + , fLastOpList(nullptr) { + // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources } // Wrapped version - GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, - SkBudgeted budgeted, uint32_t uniqueID) - : fDesc(desc) - , fFit(fit) - , fBudgeted(budgeted) - , fUniqueID(uniqueID) { + GrSurfaceProxy(sk_sp surface, SkBackingFit fit); + + virtual ~GrSurfaceProxy(); + + friend class GrSurfaceProxyPriv; + + // Methods made available via GrSurfaceProxyPriv + bool hasPendingIO() const { + return this->internalHasPendingIO(); } - virtual ~GrSurfaceProxy() {} + bool hasPendingWrite() const { + return this->internalHasPendingWrite(); + } // For wrapped resources, 'fDesc' will always be filled in from the wrapped resource. - const GrSurfaceDesc fDesc; - const SkBackingFit fFit; // always exact for wrapped resources - const SkBudgeted fBudgeted; // set from the backing resource for wrapped resources - const uint32_t fUniqueID; // set from the backing resource for wrapped resources + GrSurfaceDesc fDesc; + SkBackingFit fFit; // always exact for wrapped resources + mutable SkBudgeted fBudgeted; // set from the backing resource for wrapped resources + // mutable bc of SkSurface/SkImage wishy-washiness + const uint32_t fFlags; + + SkDestinationSurfaceColorMode fMipColorMode; + + const UniqueID fUniqueID; // set from the backing resource for wrapped resources + + static const size_t kInvalidGpuMemorySize = ~static_cast(0); + SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; }) private: + virtual size_t onGpuMemorySize() const = 0; - // See comment in GrGpuResource.h. - void notifyAllCntsAreZero(CntType) const { delete this; } - bool notifyRefCountIsZero() const { return true; } + // This entry is lazily evaluated so, when the proxy wraps a resource, the resource + // will be called but, when the proxy is deferred, it will compute the answer itself. + // If the proxy computes its own answer that answer is checked (in debug mode) in + // the instantiation method. + mutable size_t fGpuMemorySize; - typedef GrIORef INHERITED; + // The last opList that wrote to or is currently going to write to this surface + // The opList can be closed (e.g., no render target context is currently bound + // to this renderTarget). + // This back-pointer is required so that we can add a dependancy between + // the opList used to create the current contents of this surface + // and the opList of a destination surface to which this one is being drawn or copied. + GrOpList* fLastOpList; - // to access notifyAllCntsAreZero and notifyRefCntIsZero. - friend class GrIORef; + + typedef GrIORefProxy INHERITED; }; #endif diff --git a/gfx/skia/skia/src/gpu/GrSwizzle.h b/gfx/skia/skia/include/private/GrSwizzle.h similarity index 60% rename from gfx/skia/skia/src/gpu/GrSwizzle.h rename to gfx/skia/skia/include/private/GrSwizzle.h index c2288b2fe418..391740be721f 100644 --- a/gfx/skia/skia/src/gpu/GrSwizzle.h +++ b/gfx/skia/skia/include/private/GrSwizzle.h @@ -15,6 +15,32 @@ Currently there is no way to specify an arbitrary swizzle, just some static swizzles and an assignment operator. That could be relaxed. */ class GrSwizzle { +private: + char fSwiz[5]; + uint8_t fKey; + + static constexpr int CToI(char c) { + return ('r' == c) ? (GrColor_SHIFT_R / 8) : + ('g' == c) ? (GrColor_SHIFT_G / 8) : + ('b' == c) ? (GrColor_SHIFT_B / 8) : + ('a' == c) ? (GrColor_SHIFT_A / 8) : -1; + } + + static constexpr char IToC(int idx) { + return (8 * idx) == GrColor_SHIFT_R ? 'r' : + (8 * idx) == GrColor_SHIFT_G ? 'g' : + (8 * idx) == GrColor_SHIFT_B ? 'b' : + (8 * idx) == GrColor_SHIFT_A ? 'a' : 'x'; + } + + constexpr GrSwizzle(const char c[4]) + : fSwiz{c[0], c[1], c[2], c[3], 0} + , fKey((CToI(c[0]) << 0) | (CToI(c[1]) << 2) | (CToI(c[2]) << 4) | (CToI(c[3]) << 6)) {} + + GR_STATIC_ASSERT(sizeof(char[4]) == sizeof(uint32_t)); + uint32_t* asUIntPtr() { return SkTCast(fSwiz); } + uint32_t asUInt() const { return *SkTCast(fSwiz); } + public: GrSwizzle() { *this = RGBA(); } @@ -29,7 +55,7 @@ public: void setFromKey(uint8_t key) { fKey = key; for (int i = 0; i < 4; ++i) { - fSwiz[i] = IdxToChar(key & 3); + fSwiz[i] = IToC(key & 3); key >>= 2; } SkASSERT(fSwiz[4] == 0); @@ -64,27 +90,32 @@ public: return GrColorPackRGBA(outR, outG, outB, outA); } - static const GrSwizzle& RGBA() { - static GrSwizzle gRGBA("rgba"); - return gRGBA; + /** Applies this swizzle to the input color and returns the swizzled color. */ + GrColor4f applyTo(const GrColor4f& color) const { + int idx; + uint32_t key = fKey; + // Index of the input color that should be mapped to output r. + idx = (key & 3); + float outR = color.fRGBA[idx]; + key >>= 2; + idx = (key & 3); + float outG = color.fRGBA[idx]; + key >>= 2; + idx = (key & 3); + float outB = color.fRGBA[idx]; + key >>= 2; + idx = (key & 3); + float outA = color.fRGBA[idx]; + return GrColor4f(outR, outG, outB, outA); } - static const GrSwizzle& AAAA() { - static GrSwizzle gAAAA("aaaa"); - return gAAAA; - } + static GrSwizzle RGBA() { return GrSwizzle("rgba"); } + static GrSwizzle AAAA() { return GrSwizzle("aaaa"); } + static GrSwizzle RRRR() { return GrSwizzle("rrrr"); } + static GrSwizzle RRRA() { return GrSwizzle("rrra"); } + static GrSwizzle BGRA() { return GrSwizzle("bgra"); } - static const GrSwizzle& RRRR() { - static GrSwizzle gRRRR("rrrr"); - return gRRRR; - } - - static const GrSwizzle& BGRA() { - static GrSwizzle gBGRA("bgra"); - return gBGRA; - } - - static const GrSwizzle& CreateRandom(SkRandom* random) { + static GrSwizzle CreateRandom(SkRandom* random) { switch (random->nextU() % 4) { case 0: return RGBA(); @@ -99,54 +130,6 @@ public: return RGBA(); } } - -private: - char fSwiz[5]; - uint8_t fKey; - - static int CharToIdx(char c) { - switch (c) { - case 'r': - return (GrColor_SHIFT_R / 8); - case 'g': - return (GrColor_SHIFT_G / 8); - case 'b': - return (GrColor_SHIFT_B / 8); - case 'a': - return (GrColor_SHIFT_A / 8); - default: - SkFAIL("Invalid swizzle char"); - return 0; - } - } - - static /* constexpr */ char IToC(int idx) { - return (8*idx) == GrColor_SHIFT_R ? 'r' : - (8*idx) == GrColor_SHIFT_G ? 'g' : - (8*idx) == GrColor_SHIFT_B ? 'b' : 'a'; - } - - static char IdxToChar(int c) { - // Hopefully this array gets computed at compile time. - static const char gStr[4] = { IToC(0), IToC(1), IToC(2), IToC(3) }; - return gStr[c]; - } - - explicit GrSwizzle(const char* str) { - SkASSERT(strlen(str) == 4); - fSwiz[0] = str[0]; - fSwiz[1] = str[1]; - fSwiz[2] = str[2]; - fSwiz[3] = str[3]; - fSwiz[4] = 0; - fKey = SkToU8(CharToIdx(fSwiz[0]) | (CharToIdx(fSwiz[1]) << 2) | - (CharToIdx(fSwiz[2]) << 4) | (CharToIdx(fSwiz[3]) << 6)); - } - - uint32_t* asUIntPtr() { return SkTCast(fSwiz); } - uint32_t asUInt() const { return *SkTCast(fSwiz); } - - GR_STATIC_ASSERT(sizeof(char[4]) == sizeof(uint32_t)); }; #endif diff --git a/gfx/skia/skia/include/private/GrTextureProxy.h b/gfx/skia/skia/include/private/GrTextureProxy.h index 63cb3c8359d6..ee954dcede74 100644 --- a/gfx/skia/skia/include/private/GrTextureProxy.h +++ b/gfx/skia/skia/include/private/GrTextureProxy.h @@ -11,34 +11,36 @@ #include "GrSurfaceProxy.h" #include "GrTexture.h" -class GrTextureProvider; +class GrCaps; +class GrResourceProvider; +class GrTextureOpList; // This class delays the acquisition of textures until they are actually required -class GrTextureProxy : public GrSurfaceProxy { +class GrTextureProxy : virtual public GrSurfaceProxy { public: - // TODO: need to refine ownership semantics of 'srcData' if we're in completely - // deferred mode - static sk_sp Make(const GrSurfaceDesc&, SkBackingFit, SkBudgeted, - const void* srcData = nullptr, size_t rowBytes = 0); - static sk_sp Make(sk_sp); - - // TODO: add asRenderTargetProxy variants GrTextureProxy* asTextureProxy() override { return this; } const GrTextureProxy* asTextureProxy() const override { return this; } // Actually instantiate the backing texture, if necessary - GrTexture* instantiate(GrTextureProvider* texProvider); + GrTexture* instantiate(GrResourceProvider*); + + void setMipColorMode(SkDestinationSurfaceColorMode colorMode); + +protected: + friend class GrSurfaceProxy; // for ctors -private: // Deferred version GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit, SkBudgeted, - const void* srcData, size_t srcRowBytes); + const void* srcData, size_t srcRowBytes, uint32_t flags); // Wrapped version - GrTextureProxy(sk_sp tex); + GrTextureProxy(sk_sp); - // For wrapped textures we store it here. - // For deferred proxies we will fill this in when we need to instantiate the deferred resource - sk_sp fTexture; +private: + size_t onGpuMemorySize() const override; + + // For wrapped proxies the GrTexture pointer is stored in GrIORefProxy. + // For deferred proxies that pointer will be filled in when we need to instantiate + // the deferred resource typedef GrSurfaceProxy INHERITED; }; diff --git a/gfx/skia/skia/include/private/GrTextureRenderTargetProxy.h b/gfx/skia/skia/include/private/GrTextureRenderTargetProxy.h new file mode 100644 index 000000000000..09aef756e1bd --- /dev/null +++ b/gfx/skia/skia/include/private/GrTextureRenderTargetProxy.h @@ -0,0 +1,42 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTextureRenderTargetProxy_DEFINED +#define GrTextureRenderTargetProxy_DEFINED + +#include "GrRenderTargetProxy.h" +#include "GrTextureProxy.h" + +#ifdef SK_BUILD_FOR_WIN +// Windows gives warnings about inheriting asTextureProxy/asRenderTargetProxy via dominance. +#pragma warning(push) +#pragma warning(disable: 4250) +#endif + +// This class delays the acquisition of RenderTargets that are also textures until +// they are actually required +// Beware: the uniqueID of the TextureRenderTargetProxy will usually be different than +// the uniqueID of the RenderTarget/Texture it represents! +class GrTextureRenderTargetProxy : public GrTextureProxy, public GrRenderTargetProxy { +private: + friend class GrSurfaceProxy; // for ctors + + // Deferred version + GrTextureRenderTargetProxy(const GrCaps&, const GrSurfaceDesc&, + SkBackingFit, SkBudgeted, uint32_t flags); + + // Wrapped version + GrTextureRenderTargetProxy(sk_sp); + + size_t onGpuMemorySize() const override; +}; + +#ifdef SK_BUILD_FOR_WIN +#pragma warning(pop) +#endif + +#endif diff --git a/gfx/skia/skia/include/private/SkFixed.h b/gfx/skia/skia/include/private/SkFixed.h index be3bb5d6045d..b2eea5f6240d 100644 --- a/gfx/skia/skia/include/private/SkFixed.h +++ b/gfx/skia/skia/include/private/SkFixed.h @@ -9,7 +9,7 @@ #define SkFixed_DEFINED #include "SkScalar.h" -#include "math.h" +#include "SkSafe_math.h" #include "SkTypes.h" @@ -69,9 +69,15 @@ typedef int32_t SkFixed; #define SkFixedCeilToInt(x) (((x) + SK_Fixed1 - 1) >> 16) #define SkFixedFloorToInt(x) ((x) >> 16) -#define SkFixedRoundToFixed(x) (((x) + SK_FixedHalf) & 0xFFFF0000) -#define SkFixedCeilToFixed(x) (((x) + SK_Fixed1 - 1) & 0xFFFF0000) -#define SkFixedFloorToFixed(x) ((x) & 0xFFFF0000) +static inline SkFixed SkFixedRoundToFixed(SkFixed x) { + return (x + SK_FixedHalf) & 0xFFFF0000; +} +static inline SkFixed SkFixedCeilToFixed(SkFixed x) { + return (x + SK_Fixed1 - 1) & 0xFFFF0000; +} +static inline SkFixed SkFixedFloorToFixed(SkFixed x) { + return x & 0xFFFF0000; +} #define SkFixedAbs(x) SkAbs32(x) #define SkFixedAve(a, b) (((a) + (b)) >> 1) @@ -132,27 +138,22 @@ inline SkFixed SkFixedMul_longlong(SkFixed a, SkFixed b) { /////////////////////////////////////////////////////////////////////////////// -#if SK_SCALAR_IS_FLOAT - #define SkFixedToScalar(x) SkFixedToFloat(x) #define SkScalarToFixed(x) SkFloatToFixed(x) -#else // SK_SCALAR_IS_DOUBLE - -#define SkFixedToScalar(x) SkFixedToDouble(x) -#define SkScalarToFixed(x) SkDoubleToFixed(x) - -#endif - /////////////////////////////////////////////////////////////////////////////// typedef int64_t SkFixed3232; // 32.32 +#define SkFixed3232Max (0x7FFFFFFFFFFFFFFFLL) +#define SkFixed3232Min (-SkFixed3232Max) + #define SkIntToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 32)) #define SkFixed3232ToInt(x) ((int)((x) >> 32)) #define SkFixedToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 16)) #define SkFixed3232ToFixed(x) ((SkFixed)((x) >> 16)) #define SkFloatToFixed3232(x) ((SkFixed3232)((x) * (65536.0f * 65536.0f))) +#define SkFixed3232ToFloat(x) (x * (1 / (65536.0f * 65536.0f))) #define SkScalarToFixed3232(x) SkFloatToFixed3232(x) diff --git a/gfx/skia/skia/include/private/SkFloatBits.h b/gfx/skia/skia/include/private/SkFloatBits.h index 7aa13cf67b7d..4909926f131d 100644 --- a/gfx/skia/skia/include/private/SkFloatBits.h +++ b/gfx/skia/skia/include/private/SkFloatBits.h @@ -10,7 +10,7 @@ #define SkFloatBits_DEFINED #include "SkTypes.h" -#include +#include "SkSafe_math.h" /** Convert a sign-bit int (i.e. float interpreted as int) into a 2s compliement int. This also converts -0 (0x80000000) to 0. Doing this to a float allows diff --git a/gfx/skia/skia/include/private/SkFloatingPoint.h b/gfx/skia/skia/include/private/SkFloatingPoint.h index 6a6edf36519d..f3acf4806ca3 100644 --- a/gfx/skia/skia/include/private/SkFloatingPoint.h +++ b/gfx/skia/skia/include/private/SkFloatingPoint.h @@ -11,8 +11,7 @@ #define SkFloatingPoint_DEFINED #include "SkTypes.h" - -#include +#include "SkSafe_math.h" #include #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1 diff --git a/gfx/skia/skia/include/private/SkMalloc.h b/gfx/skia/skia/include/private/SkMalloc.h new file mode 100644 index 000000000000..ee5590063bc8 --- /dev/null +++ b/gfx/skia/skia/include/private/SkMalloc.h @@ -0,0 +1,84 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkMalloc_DEFINED +#define SkMalloc_DEFINED + +#include +#include + +#include "SkPreConfig.h" + +/* + memory wrappers to be implemented by the porting layer (platform) +*/ + +enum { + SK_MALLOC_TEMP = 0x01, //!< hint to sk_malloc that the requested memory will be freed in the scope of the stack frame + SK_MALLOC_THROW = 0x02 //!< instructs sk_malloc to call sk_throw if the memory cannot be allocated. +}; +/** Return a block of memory (at least 4-byte aligned) of at least the + specified size. If the requested memory cannot be returned, either + return null (if SK_MALLOC_TEMP bit is clear) or throw an exception + (if SK_MALLOC_TEMP bit is set). To free the memory, call sk_free(). +*/ +SK_API extern void* sk_malloc_flags(size_t size, unsigned flags); +/** Same as sk_malloc(), but hard coded to pass SK_MALLOC_THROW as the flag +*/ +SK_API extern void* sk_malloc_throw(size_t size); +/** Same as standard realloc(), but this one never returns null on failure. It will throw + an exception if it fails. +*/ +SK_API extern void* sk_realloc_throw(void* buffer, size_t size); +/** Free memory returned by sk_malloc(). It is safe to pass null. +*/ +SK_API extern void sk_free(void*); + +/** Much like calloc: returns a pointer to at least size zero bytes, or NULL on failure. + */ +SK_API extern void* sk_calloc(size_t size); + +/** Same as sk_calloc, but throws an exception instead of returning NULL on failure. + */ +SK_API extern void* sk_calloc_throw(size_t size); + +/** Called internally if we run out of memory. The platform implementation must + not return, but should either throw an exception or otherwise exit. +*/ +SK_API extern void sk_out_of_memory(void); + +// bzero is safer than memset, but we can't rely on it, so... sk_bzero() +static inline void sk_bzero(void* buffer, size_t size) { + // Please c.f. sk_careful_memcpy. It's undefined behavior to call memset(null, 0, 0). + if (size) { + memset(buffer, 0, size); + } +} + +/** + * sk_careful_memcpy() is just like memcpy(), but guards against undefined behavior. + * + * It is undefined behavior to call memcpy() with null dst or src, even if len is 0. + * If an optimizer is "smart" enough, it can exploit this to do unexpected things. + * memcpy(dst, src, 0); + * if (src) { + * printf("%x\n", *src); + * } + * In this code the compiler can assume src is not null and omit the if (src) {...} check, + * unconditionally running the printf, crashing the program if src really is null. + * Of the compilers we pay attention to only GCC performs this optimization in practice. + */ +static inline void* sk_careful_memcpy(void* dst, const void* src, size_t len) { + // When we pass >0 len we had better already be passing valid pointers. + // So we just need to skip calling memcpy when len == 0. + if (len) { + memcpy(dst,src,len); + } + return dst; +} + +#endif // SkMalloc_DEFINED diff --git a/gfx/skia/skia/src/core/SkMessageBus.h b/gfx/skia/skia/include/private/SkMessageBus.h similarity index 100% rename from gfx/skia/skia/src/core/SkMessageBus.h rename to gfx/skia/skia/include/private/SkMessageBus.h diff --git a/gfx/skia/skia/include/private/SkMiniRecorder.h b/gfx/skia/skia/include/private/SkMiniRecorder.h index 6365ebc65b9f..06b35ca71492 100644 --- a/gfx/skia/skia/include/private/SkMiniRecorder.h +++ b/gfx/skia/skia/include/private/SkMiniRecorder.h @@ -29,7 +29,7 @@ public: // Flush anything we've recorded to the canvas, resetting this SkMiniRecorder. // This is logically the same as but rather more efficient than: - // SkAutoTUnref pic(this->detachAsPicture(SkRect::MakeEmpty())); + // sk_sp pic(this->detachAsPicture(SkRect::MakeEmpty())); // pic->playback(canvas); void flushAndReset(SkCanvas*); diff --git a/gfx/skia/skia/include/private/SkRecords.h b/gfx/skia/skia/include/private/SkRecords.h index 05f935b3ced9..ac492ec0eabe 100644 --- a/gfx/skia/skia/include/private/SkRecords.h +++ b/gfx/skia/skia/include/private/SkRecords.h @@ -16,10 +16,12 @@ #include "SkPath.h" #include "SkPicture.h" #include "SkRect.h" +#include "SkRegion.h" #include "SkRRect.h" #include "SkRSXform.h" #include "SkString.h" #include "SkTextBlob.h" +#include "SkVertices.h" // Windows.h, will pull in all of the GDI defines. GDI #defines // DrawText to DrawTextA or DrawTextW, but SkRecord has a struct @@ -192,9 +194,14 @@ RECORD(TranslateZ, 0, SkScalar z); struct ClipOpAndAA { ClipOpAndAA() {} - ClipOpAndAA(SkCanvas::ClipOp op, bool aa) : op(op), aa(aa) {} - SkCanvas::ClipOp op : 31; // This really only needs to be 3, but there's no win today to do so. - unsigned aa : 1; // MSVC won't pack an enum with an bool, so we call this an unsigned. + ClipOpAndAA(SkClipOp op, bool aa) : fOp(static_cast(op)), fAA(aa) {} + + SkClipOp op() const { return static_cast(fOp); } + bool aa() const { return fAA != 0; } + +private: + unsigned fOp : 31; // This really only needs to be 3, but there's no win today to do so. + unsigned fAA : 1; // MSVC won't pack an enum with an bool, so we call this an unsigned. }; static_assert(sizeof(ClipOpAndAA) == 4, "ClipOpAndAASize"); @@ -213,7 +220,7 @@ RECORD(ClipRect, 0, RECORD(ClipRegion, 0, SkIRect devBounds; SkRegion region; - SkCanvas::ClipOp op); + SkClipOp op); // While not strictly required, if you have an SkPaint, it's fastest to put it first. RECORD(DrawArc, kDraw_Tag|kHasPaint_Tag, @@ -327,7 +334,7 @@ RECORD(DrawPatch, kDraw_Tag|kHasPaint_Tag, PODArray cubics; PODArray colors; PODArray texCoords; - sk_sp xmode); + SkBlendMode bmode); RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional paint; sk_sp atlas; @@ -335,18 +342,12 @@ RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, PODArray texs; PODArray colors; int count; - SkXfermode::Mode mode; + SkBlendMode mode; Optional cull); RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag, SkPaint paint; - SkCanvas::VertexMode vmode; - int vertexCount; - PODArray vertices; - PODArray texs; - PODArray colors; - sk_sp xmode; - PODArray indices; - int indexCount); + sk_sp vertices; + SkBlendMode bmode); RECORD(DrawAnnotation, 0, // TODO: kDraw_Tag, skia:5548 SkRect rect; SkString key; diff --git a/gfx/skia/skia/include/private/SkSafe_math.h b/gfx/skia/skia/include/private/SkSafe_math.h new file mode 100644 index 000000000000..144b28a4a3b3 --- /dev/null +++ b/gfx/skia/skia/include/private/SkSafe_math.h @@ -0,0 +1,52 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSafe_math_DEFINED +#define SkSafe_math_DEFINED + +// This file protects against known bugs in ucrt\math.h. +// Namely, that header defines inline methods without marking them static, +// which makes it very easy to cause ODR violations and ensuing chaos. +// +// TODO: other headers? Here are some potential problem headers: +// $ grep -R __inline * | grep -v static | cut -f 1 -d: | sort | uniq +// corecrt.h +// corecrt_stdio_config.h +// ctype.h +// fenv.h +// locale.h +// malloc.h +// math.h +// tchar.h +// wchar.h +// I took a quick look through other headers outside math.h. +// Nothing looks anywhere near as likely to be used by Skia as math.h. + +#if defined(_MSC_VER) && !defined(_INC_MATH) + // Our strategy here is to simply inject "static" into the headers + // where it should have been written, just before __inline. + // + // Most inline-but-not-static methods in math.h are 32-bit only, + // but not all of them (see frexpf, hypothf, ldexpf...). So to + // be safe, 32- and 64-bit builds both get this treatment. + + #define __inline static __inline + #include + #undef __inline + + #if !defined(_INC_MATH) + #error Hmm. Looks like math.h has changed its header guards. + #endif + + #define INC_MATH_IS_SAFE_NOW + +#else + #include + +#endif + +#endif//SkSafe_math_DEFINED diff --git a/gfx/skia/skia/include/private/SkSemaphore.h b/gfx/skia/skia/include/private/SkSemaphore.h index 3da2b99ab4a9..aeca9729dc87 100644 --- a/gfx/skia/skia/include/private/SkSemaphore.h +++ b/gfx/skia/skia/include/private/SkSemaphore.h @@ -22,9 +22,12 @@ public: void signal(int n = 1); // Decrement the counter by 1, - // then if the counter is <= 0, sleep this thread until the counter is > 0. + // then if the counter is < 0, sleep this thread until the counter is >= 0. void wait(); + // If the counter is positive, decrement it by 1 and return true, otherwise return false. + bool try_wait(); + // SkBaseSemaphore has no destructor. Call this to clean it up. void cleanup(); @@ -37,7 +40,7 @@ private: // // We wrap an OS-provided semaphore with a user-space atomic counter that // lets us avoid interacting with the OS semaphore unless strictly required: - // moving the count from >0 to <=0 or vice-versa, i.e. sleeping or waking threads. + // moving the count from >=0 to <0 or vice-versa, i.e. sleeping or waking threads. struct OSSemaphore; void osSignal(int n); @@ -58,7 +61,7 @@ inline void SkBaseSemaphore::signal(int n) { int prev = fCount.fetch_add(n, std::memory_order_release); // We only want to call the OS semaphore when our logical count crosses - // from <= 0 to >0 (when we need to wake sleeping threads). + // from <0 to >=0 (when we need to wake sleeping threads). // // This is easiest to think about with specific examples of prev and n. // If n == 5 and prev == -3, there are 3 threads sleeping and we signal diff --git a/gfx/skia/skia/include/private/SkShadowFlags.h b/gfx/skia/skia/include/private/SkShadowFlags.h new file mode 100644 index 000000000000..0caa01060d5a --- /dev/null +++ b/gfx/skia/skia/include/private/SkShadowFlags.h @@ -0,0 +1,25 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkShadowFlags_DEFINED +#define SkShadowFlags_DEFINED + +// A set of flags shared between the SkAmbientShadowMaskFilter and the SkSpotShadowMaskFilter +enum SkShadowFlags { + kNone_ShadowFlag = 0x00, + /** The occluding object is not opaque. Knowing that the occluder is opaque allows + * us to cull shadow geometry behind it and improve performance. */ + kTransparentOccluder_ShadowFlag = 0x01, + /** Use a larger umbra for a darker shadow */ + kLargerUmbra_ShadowFlag = 0x02, + /** Use a Gaussian for the edge function rather than smoothstep */ + kGaussianEdge_ShadowFlag = 0x04, + /** mask for all shadow flags */ + kAll_ShadowFlag = 0x07 +}; + +#endif diff --git a/gfx/skia/skia/include/private/SkShadowParams.h b/gfx/skia/skia/include/private/SkShadowParams.h index 3df0a442796a..65d6c06b869f 100644 --- a/gfx/skia/skia/include/private/SkShadowParams.h +++ b/gfx/skia/skia/include/private/SkShadowParams.h @@ -7,6 +7,8 @@ #ifndef SkShadowParams_DEFINED #define SkShadowParams_DEFINED +#include "SkScalar.h" + /** \struct SkShadowParams This struct holds information needed for drawing shadows. diff --git a/gfx/skia/skia/include/private/SkSpinlock.h b/gfx/skia/skia/include/private/SkSpinlock.h index a5d378289ffa..669a926c7eaa 100644 --- a/gfx/skia/skia/include/private/SkSpinlock.h +++ b/gfx/skia/skia/include/private/SkSpinlock.h @@ -23,6 +23,16 @@ public: } } + // Acquire the lock or fail (quickly). Lets the caller decide to do something other than wait. + bool tryAcquire() { + // To act as a mutex, we need an acquire barrier when we acquire the lock. + if (fLocked.exchange(true, std::memory_order_acquire)) { + // Lock was contended. Let the caller decide what to do. + return false; + } + return true; + } + void release() { // To act as a mutex, we need a release barrier when we release the lock. fLocked.store(false, std::memory_order_release); diff --git a/gfx/skia/skia/include/private/SkTArray.h b/gfx/skia/skia/include/private/SkTArray.h index f7c18be40fbc..2cb7c4de8153 100644 --- a/gfx/skia/skia/include/private/SkTArray.h +++ b/gfx/skia/skia/include/private/SkTArray.h @@ -15,41 +15,35 @@ #include #include -/** When MEM_COPY is true T will be bit copied when moved. - When MEM_COPY is false, T will be copy constructed / destructed. +/** When MEM_MOVE is true T will be bit copied when moved. + When MEM_MOVE is false, T will be copy constructed / destructed. In all cases T will be default-initialized on allocation, and its destructor will be called from this object's destructor. */ -template class SkTArray { +template class SkTArray { public: /** * Creates an empty array with no initial storage */ - SkTArray() { - fCount = 0; - fReserveCount = gMIN_ALLOC_COUNT; - fAllocCount = 0; - fMemArray = NULL; - fPreAllocMemArray = NULL; - } + SkTArray() { this->init(); } /** * Creates an empty array that will preallocate space for reserveCount * elements. */ - explicit SkTArray(int reserveCount) { - this->init(0, NULL, reserveCount); - } + explicit SkTArray(int reserveCount) { this->init(0, reserveCount); } /** * Copies one array to another. The new array will be heap allocated. */ explicit SkTArray(const SkTArray& that) { - this->init(that.fCount, NULL, 0); + this->init(that.fCount); this->copy(that.fItemArray); } + SkTArray(SkTArray&& that) { - this->init(that.fCount, NULL, 0); + // TODO: If 'that' owns its memory why don't we just steal the pointer? + this->init(that.fCount); that.move(fMemArray); that.fCount = 0; } @@ -60,14 +54,14 @@ public: * when you really want the (void*, int) version. */ SkTArray(const T* array, int count) { - this->init(count, NULL, 0); + this->init(count); this->copy(array); } - /** - * assign copy of array to this - */ - SkTArray& operator =(const SkTArray& that) { + SkTArray& operator=(const SkTArray& that) { + if (this == &that) { + return *this; + } for (int i = 0; i < fCount; ++i) { fItemArray[i].~T(); } @@ -77,7 +71,10 @@ public: this->copy(that.fItemArray); return *this; } - SkTArray& operator =(SkTArray&& that) { + SkTArray& operator=(SkTArray&& that) { + if (this == &that) { + return *this; + } for (int i = 0; i < fCount; ++i) { fItemArray[i].~T(); } @@ -93,7 +90,7 @@ public: for (int i = 0; i < fCount; ++i) { fItemArray[i].~T(); } - if (fMemArray != fPreAllocMemArray) { + if (fOwnMemory) { sk_free(fMemArray); } } @@ -293,9 +290,7 @@ public: if (this == that) { return; } - if (this->fPreAllocMemArray != this->fItemArray && - that->fPreAllocMemArray != that->fItemArray) { - // If neither is using a preallocated array then just swap. + if (fOwnMemory && that->fOwnMemory) { SkTSwap(fItemArray, that->fItemArray); SkTSwap(fCount, that->fCount); SkTSwap(fAllocCount, that->fAllocCount); @@ -364,7 +359,7 @@ public: return fItemArray[fCount - i - 1]; } - bool operator==(const SkTArray& right) const { + bool operator==(const SkTArray& right) const { int leftCount = this->count(); if (leftCount != right.count()) { return false; @@ -377,10 +372,12 @@ public: return true; } - bool operator!=(const SkTArray& right) const { + bool operator!=(const SkTArray& right) const { return !(*this == right); } + inline int allocCntForTest() const; + protected: /** * Creates an empty array that will use the passed storage block until it @@ -388,7 +385,7 @@ protected: */ template SkTArray(SkAlignedSTStorage* storage) { - this->init(0, storage->get(), N); + this->initWithPreallocatedStorage(0, storage->get(), N); } /** @@ -398,10 +395,22 @@ protected: */ template SkTArray(const SkTArray& array, SkAlignedSTStorage* storage) { - this->init(array.fCount, storage->get(), N); + this->initWithPreallocatedStorage(array.fCount, storage->get(), N); this->copy(array.fItemArray); } + /** + * Move another array, using preallocated storage if preAllocCount >= + * array.count(). Otherwise storage will only be used when array shrinks + * to fit. + */ + template + SkTArray(SkTArray&& array, SkAlignedSTStorage* storage) { + this->initWithPreallocatedStorage(array.fCount, storage->get(), N); + array.move(fMemArray); + array.fCount = 0; + } + /** * Copy a C array, using preallocated storage if preAllocCount >= * count. Otherwise storage will only be used when array shrinks @@ -409,59 +418,75 @@ protected: */ template SkTArray(const T* array, int count, SkAlignedSTStorage* storage) { - this->init(count, storage->get(), N); + this->initWithPreallocatedStorage(count, storage->get(), N); this->copy(array); } - void init(int count, void* preAllocStorage, int preAllocOrReserveCount) { +private: + void init(int count = 0, int reserveCount = 0) { SkASSERT(count >= 0); - SkASSERT(preAllocOrReserveCount >= 0); - fCount = count; - fReserveCount = (preAllocOrReserveCount > 0) ? - preAllocOrReserveCount : - gMIN_ALLOC_COUNT; - fPreAllocMemArray = preAllocStorage; - if (fReserveCount >= fCount && - preAllocStorage) { - fAllocCount = fReserveCount; - fMemArray = preAllocStorage; + SkASSERT(reserveCount >= 0); + fCount = count; + if (!count && !reserveCount) { + fAllocCount = 0; + fMemArray = nullptr; + fOwnMemory = false; } else { - fAllocCount = SkMax32(fCount, fReserveCount); + fAllocCount = SkTMax(count, SkTMax(kMinHeapAllocCount, reserveCount)); fMemArray = sk_malloc_throw(fAllocCount * sizeof(T)); + fOwnMemory = true; + } + } + + void initWithPreallocatedStorage(int count, void* preallocStorage, int preallocCount) { + SkASSERT(count >= 0); + SkASSERT(preallocCount > 0); + SkASSERT(preallocStorage); + fCount = count; + fMemArray = nullptr; + if (count > preallocCount) { + fAllocCount = SkTMax(count, kMinHeapAllocCount); + fMemArray = sk_malloc_throw(fAllocCount * sizeof(T)); + fOwnMemory = true; + } else { + fAllocCount = preallocCount; + fMemArray = preallocStorage; + fOwnMemory = false; } } -private: /** In the following move and copy methods, 'dst' is assumed to be uninitialized raw storage. * In the following move methods, 'src' is destroyed leaving behind uninitialized raw storage. */ - template SK_WHEN(E, void) copy(const T* src) { - sk_careful_memcpy(fMemArray, src, fCount * sizeof(T)); - } - template SK_WHEN(E, void) move(int dst, int src) { - memcpy(&fItemArray[dst], &fItemArray[src], sizeof(T)); - } - template SK_WHEN(E, void) move(void* dst) { - sk_careful_memcpy(dst, fMemArray, fCount * sizeof(T)); - } - - template SK_WHEN(!E, void) copy(const T* src) { + void copy(const T* src) { + // Some types may be trivially copyable, in which case we *could* use memcopy; but + // MEM_MOVE == true implies that the type is trivially movable, and not necessarily + // trivially copyable (think sk_sp<>). So short of adding another template arg, we + // must be conservative and use copy construction. for (int i = 0; i < fCount; ++i) { new (fItemArray + i) T(src[i]); } } - template SK_WHEN(!E, void) move(int dst, int src) { + + template SK_WHEN(E, void) move(int dst, int src) { + memcpy(&fItemArray[dst], &fItemArray[src], sizeof(T)); + } + template SK_WHEN(E, void) move(void* dst) { + sk_careful_memcpy(dst, fMemArray, fCount * sizeof(T)); + } + + template SK_WHEN(!E, void) move(int dst, int src) { new (&fItemArray[dst]) T(std::move(fItemArray[src])); fItemArray[src].~T(); } - template SK_WHEN(!E, void) move(void* dst) { + template SK_WHEN(!E, void) move(void* dst) { for (int i = 0; i < fCount; ++i) { new (static_cast(dst) + sizeof(T) * i) T(std::move(fItemArray[i])); fItemArray[i].~T(); } } - static const int gMIN_ALLOC_COUNT = 8; + static constexpr int kMinHeapAllocCount = 8; // Helper function that makes space for n objects, adjusts the count, but does not initialize // the new objects. @@ -472,57 +497,60 @@ private: return ptr; } - inline void checkRealloc(int delta) { + void checkRealloc(int delta) { SkASSERT(fCount >= 0); SkASSERT(fAllocCount >= 0); - SkASSERT(-delta <= fCount); int newCount = fCount + delta; - int newAllocCount = fAllocCount; - if (newCount > fAllocCount || newCount < (fAllocCount / 3)) { - // whether we're growing or shrinking, we leave at least 50% extra space for future - // growth (clamped to the reserve count). - newAllocCount = SkMax32(newCount + ((newCount + 1) >> 1), fReserveCount); + // We allow fAllocCount to be in the range [newCount, 3*newCount]. We also never shrink + // when we're currently using preallocated memory or would allocate less than + // kMinHeapAllocCount. + bool mustGrow = newCount > fAllocCount; + bool shouldShrink = fAllocCount > 3 * newCount && fOwnMemory; + if (!mustGrow && !shouldShrink) { + return; } - if (newAllocCount != fAllocCount) { - fAllocCount = newAllocCount; - void* newMemArray; - - if (fAllocCount == fReserveCount && fPreAllocMemArray) { - newMemArray = fPreAllocMemArray; - } else { - newMemArray = sk_malloc_throw(fAllocCount*sizeof(T)); - } - - this->move(newMemArray); - - if (fMemArray != fPreAllocMemArray) { - sk_free(fMemArray); - } - fMemArray = newMemArray; + // Whether we're growing or shrinking, we leave at least 50% extra space for future growth. + int newAllocCount = newCount + ((newCount + 1) >> 1); + // Align the new allocation count to kMinHeapAllocCount. + static_assert(SkIsPow2(kMinHeapAllocCount), "min alloc count not power of two."); + newAllocCount = (newAllocCount + (kMinHeapAllocCount - 1)) & ~(kMinHeapAllocCount - 1); + // At small sizes the old and new alloc count can both be kMinHeapAllocCount. + if (newAllocCount == fAllocCount) { + return; } + fAllocCount = newAllocCount; + void* newMemArray = sk_malloc_throw(fAllocCount * sizeof(T)); + this->move(newMemArray); + if (fOwnMemory) { + sk_free(fMemArray); + + } + fMemArray = newMemArray; + fOwnMemory = true; } - int fReserveCount; - int fCount; - int fAllocCount; - void* fPreAllocMemArray; + int fCount; + int fAllocCount; + bool fOwnMemory; union { T* fItemArray; void* fMemArray; }; }; +template constexpr int SkTArray::kMinHeapAllocCount; + /** * Subclass of SkTArray that contains a preallocated memory block for the array. */ -template -class SkSTArray : public SkTArray { +template +class SkSTArray : public SkTArray { private: - typedef SkTArray INHERITED; + typedef SkTArray INHERITED; public: SkSTArray() : INHERITED(&fStorage) { @@ -532,10 +560,18 @@ public: : INHERITED(array, &fStorage) { } + SkSTArray(SkSTArray&& array) + : INHERITED(std::move(array), &fStorage) { + } + explicit SkSTArray(const INHERITED& array) : INHERITED(array, &fStorage) { } + explicit SkSTArray(INHERITED&& array) + : INHERITED(std::move(array), &fStorage) { + } + explicit SkSTArray(int reserveCount) : INHERITED(reserveCount) { } @@ -544,15 +580,26 @@ public: : INHERITED(array, count, &fStorage) { } - SkSTArray& operator= (const SkSTArray& array) { - return *this = *(const INHERITED*)&array; + SkSTArray& operator=(const SkSTArray& array) { + INHERITED::operator=(array); + return *this; } - SkSTArray& operator= (const INHERITED& array) { + SkSTArray& operator=(SkSTArray&& array) { + INHERITED::operator=(std::move(array)); + return *this; + } + + SkSTArray& operator=(const INHERITED& array) { INHERITED::operator=(array); return *this; } + SkSTArray& operator=(INHERITED&& array) { + INHERITED::operator=(std::move(array)); + return *this; + } + private: SkAlignedSTStorage fStorage; }; diff --git a/gfx/skia/skia/include/private/SkTDArray.h b/gfx/skia/skia/include/private/SkTDArray.h index f71d3570056b..4c58d478fe63 100644 --- a/gfx/skia/skia/include/private/SkTDArray.h +++ b/gfx/skia/skia/include/private/SkTDArray.h @@ -11,6 +11,7 @@ #define SkTDArray_DEFINED #include "SkTypes.h" +#include "SkMalloc.h" template class SkTDArray { public: @@ -72,6 +73,12 @@ public: SkTSwap(fCount, other.fCount); } + // The deleter that ought to be used for a std:: smart pointer that takes ownership from + // release(). + struct Deleter { + void operator()(const void* p) { sk_free((void*)p); } + }; + /** Return a ptr to the array of data, to be freed with sk_free. This also resets the SkTDArray to be empty. */ @@ -228,7 +235,7 @@ public: } return -1; } - + int find(const T& elem) const { const T* iter = fArray; const T* stop = fArray + fCount; diff --git a/gfx/skia/skia/include/private/SkTDict.h b/gfx/skia/skia/include/private/SkTDict.h deleted file mode 100644 index 106cace2f268..000000000000 --- a/gfx/skia/skia/include/private/SkTDict.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkTDict_DEFINED -#define SkTDict_DEFINED - -#include "SkChunkAlloc.h" -#include "SkTSearch.h" -#include "SkTDArray.h" - -template class SkTDict : SkNoncopyable { -public: - SkTDict(size_t minStringAlloc) : fStrings(minStringAlloc) {} - - void reset() { - fArray.reset(); - fStrings.reset(); - } - - int count() const { return fArray.count(); } - - bool set(const char name[], const T& value) { - return set(name, strlen(name), value); - } - - bool set(const char name[], size_t len, const T& value) { - SkASSERT(name); - - int index = this->find_index(name, len); - - if (index >= 0) { - fArray[index].fValue = value; - return false; - } else { - Pair* pair = fArray.insert(~index); - char* copy = (char*)fStrings.alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType); - memcpy(copy, name, len); - copy[len] = '\0'; - pair->fName = copy; - pair->fValue = value; - return true; - } - } - - bool find(const char name[]) const { - return this->find_index(name) >= 0; - } - - bool find(const char name[], size_t len) const { - return this->find_index(name, len) >= 0; - } - - bool find(const char name[], T* value) const { - return find(name, strlen(name), value); - } - - bool find(const char name[], size_t len, T* value) const { - int index = this->find_index(name, len); - - if (index >= 0) { - if (value) { - *value = fArray[index].fValue; - } - return true; - } - return false; - } - - bool findKey(T& value, const char** name) const { - const Pair* end = fArray.end(); - for (const Pair* pair = fArray.begin(); pair < end; pair++) { - if (pair->fValue != value) { - continue; - } - *name = pair->fName; - return true; - } - return false; - } - -public: - struct Pair { - const char* fName; - T fValue; - - friend int operator<(const Pair& a, const Pair& b) { - return strcmp(a.fName, b.fName); - } - - friend int operator!=(const Pair& a, const Pair& b) { - return strcmp(a.fName, b.fName); - } - }; - friend class Iter; - -public: - class Iter { - public: - Iter(const SkTDict& dict) { - fIter = dict.fArray.begin(); - fStop = dict.fArray.end(); - } - - const char* next(T* value) { - const char* name = NULL; - if (fIter < fStop) { - name = fIter->fName; - if (value) { - *value = fIter->fValue; - } - fIter += 1; - } - return name; - } - private: - const Pair* fIter; - const Pair* fStop; - }; - -private: - SkTDArray fArray; - SkChunkAlloc fStrings; - - int find_index(const char name[]) const { - return find_index(name, strlen(name)); - } - - int find_index(const char name[], size_t len) const { - SkASSERT(name); - - int count = fArray.count(); - int index = ~0; - - if (count) { - index = SkStrSearch(&fArray.begin()->fName, count, name, len, sizeof(Pair)); - } - return index; - } - friend class Iter; -}; - -#endif diff --git a/gfx/skia/skia/include/private/SkTHash.h b/gfx/skia/skia/include/private/SkTHash.h index 8a644e3b0197..2388905c38c6 100644 --- a/gfx/skia/skia/include/private/SkTHash.h +++ b/gfx/skia/skia/include/private/SkTHash.h @@ -24,7 +24,7 @@ template class SkTHashTable : SkNoncopyable { public: - SkTHashTable() : fCount(0), fRemoved(0), fCapacity(0) {} + SkTHashTable() : fCount(0), fCapacity(0) {} // Clear the table. void reset() { @@ -50,29 +50,29 @@ public: // Copy val into the hash table, returning a pointer to the copy now in the table. // If there already is an entry in the table with the same key, we overwrite it. - T* set(const T& val) { - if (4 * (fCount+fRemoved) >= 3 * fCapacity) { + T* set(T val) { + if (4 * fCount >= 3 * fCapacity) { this->resize(fCapacity > 0 ? fCapacity * 2 : 4); } - return this->uncheckedSet(val); + return this->uncheckedSet(std::move(val)); } - // If there is an entry in the table with this key, return a pointer to it. If not, NULL. + // If there is an entry in the table with this key, return a pointer to it. If not, null. T* find(const K& key) const { uint32_t hash = Hash(key); int index = hash & (fCapacity-1); for (int n = 0; n < fCapacity; n++) { Slot& s = fSlots[index]; if (s.empty()) { - return NULL; + return nullptr; } - if (!s.removed() && hash == s.hash && key == Traits::GetKey(s.val)) { + if (hash == s.hash && key == Traits::GetKey(s.val)) { return &s.val; } - index = this->next(index, n); + index = this->next(index); } SkASSERT(fCapacity == 0); - return NULL; + return nullptr; } // Remove the value with this key from the hash table. @@ -84,22 +84,47 @@ public: for (int n = 0; n < fCapacity; n++) { Slot& s = fSlots[index]; SkASSERT(!s.empty()); - if (!s.removed() && hash == s.hash && key == Traits::GetKey(s.val)) { - fRemoved++; + if (hash == s.hash && key == Traits::GetKey(s.val)) { fCount--; - s.markRemoved(); - return; + break; } - index = this->next(index, n); + index = this->next(index); + } + + // Rearrange elements to restore the invariants for linear probing. + for (;;) { + Slot& emptySlot = fSlots[index]; + int emptyIndex = index; + int originalIndex; + // Look for an element that can be moved into the empty slot. + // If the empty slot is in between where an element landed, and its native slot, then + // move it to the empty slot. Don't move it if its native slot is in between where + // the element landed and the empty slot. + // [native] <= [empty] < [candidate] == GOOD, can move candidate to empty slot + // [empty] < [native] < [candidate] == BAD, need to leave candidate where it is + do { + index = this->next(index); + Slot& s = fSlots[index]; + if (s.empty()) { + // We're done shuffling elements around. Clear the last empty slot. + emptySlot = Slot(); + return; + } + originalIndex = s.hash & (fCapacity - 1); + } while ((index <= originalIndex && originalIndex < emptyIndex) + || (originalIndex < emptyIndex && emptyIndex < index) + || (emptyIndex < index && index <= originalIndex)); + // Move the element to the empty slot. + Slot& moveFrom = fSlots[index]; + emptySlot = std::move(moveFrom); } - SkASSERT(fCapacity == 0); } // Call fn on every entry in the table. You may mutate the entries, but be very careful. template // f(T*) void foreach(Fn&& fn) { for (int i = 0; i < fCapacity; i++) { - if (!fSlots[i].empty() && !fSlots[i].removed()) { + if (!fSlots[i].empty()) { fn(&fSlots[i].val); } } @@ -109,25 +134,22 @@ public: template // f(T) or f(const T&) void foreach(Fn&& fn) const { for (int i = 0; i < fCapacity; i++) { - if (!fSlots[i].empty() && !fSlots[i].removed()) { + if (!fSlots[i].empty()) { fn(fSlots[i].val); } } } private: - T* uncheckedSet(const T& val) { + T* uncheckedSet(T&& val) { const K& key = Traits::GetKey(val); uint32_t hash = Hash(key); int index = hash & (fCapacity-1); for (int n = 0; n < fCapacity; n++) { Slot& s = fSlots[index]; - if (s.empty() || s.removed()) { + if (s.empty()) { // New entry. - if (s.removed()) { - fRemoved--; - } - s.val = val; + s.val = std::move(val); s.hash = hash; fCount++; return &s.val; @@ -135,57 +157,62 @@ private: if (hash == s.hash && key == Traits::GetKey(s.val)) { // Overwrite previous entry. // Note: this triggers extra copies when adding the same value repeatedly. - s.val = val; + s.val = std::move(val); return &s.val; } - index = this->next(index, n); + + index = this->next(index); } SkASSERT(false); - return NULL; + return nullptr; } void resize(int capacity) { int oldCapacity = fCapacity; SkDEBUGCODE(int oldCount = fCount); - fCount = fRemoved = 0; + fCount = 0; fCapacity = capacity; SkAutoTArray oldSlots(capacity); oldSlots.swap(fSlots); for (int i = 0; i < oldCapacity; i++) { - const Slot& s = oldSlots[i]; - if (!s.empty() && !s.removed()) { - this->uncheckedSet(s.val); + Slot& s = oldSlots[i]; + if (!s.empty()) { + this->uncheckedSet(std::move(s.val)); } } SkASSERT(fCount == oldCount); } - int next(int index, int n) const { - // A valid strategy explores all slots in [0, fCapacity) as n walks from 0 to fCapacity-1. - // Both of these strategies are valid: - //return (index + 0 + 1) & (fCapacity-1); // Linear probing. - return (index + n + 1) & (fCapacity-1); // Quadratic probing. + int next(int index) const { + index--; + if (index < 0) { index += fCapacity; } + return index; } static uint32_t Hash(const K& key) { uint32_t hash = Traits::Hash(key); - return hash < 2 ? hash+2 : hash; // We reserve hash 0 and 1 to mark empty or removed slots. + return hash ? hash : 1; // We reserve hash 0 to mark empty. } struct Slot { Slot() : hash(0) {} - bool empty() const { return this->hash == 0; } - bool removed() const { return this->hash == 1; } + Slot(T&& v, uint32_t h) : val(std::move(v)), hash(h) {} + Slot(Slot&& o) { *this = std::move(o); } + Slot& operator=(Slot&& o) { + val = std::move(o.val); + hash = o.hash; + return *this; + } - void markRemoved() { this->hash = 1; } + bool empty() const { return this->hash == 0; } - T val; + T val; uint32_t hash; }; - int fCount, fRemoved, fCapacity; + int fCount, fCapacity; SkAutoTArray fSlots; }; @@ -209,19 +236,18 @@ public: // Set key to val in the table, replacing any previous value with the same key. // We copy both key and val, and return a pointer to the value copy now in the table. - V* set(const K& key, const V& val) { - Pair in = { key, val }; - Pair* out = fTable.set(in); + V* set(K key, V val) { + Pair* out = fTable.set({std::move(key), std::move(val)}); return &out->val; } // If there is key/value entry in the table with this key, return a pointer to the value. - // If not, return NULL. + // If not, return null. V* find(const K& key) const { if (Pair* p = fTable.find(key)) { return &p->val; } - return NULL; + return nullptr; } // Remove the key/value entry in the table with this key. @@ -269,7 +295,7 @@ public: size_t approxBytesUsed() const { return fTable.approxBytesUsed(); } // Copy an item into the set. - void add(const T& item) { fTable.set(item); } + void add(T item) { fTable.set(std::move(item)); } // Is this item in the set? bool contains(const T& item) const { return SkToBool(this->find(item)); } diff --git a/gfx/skia/skia/include/private/SkTLogic.h b/gfx/skia/skia/include/private/SkTLogic.h index 2b12434d0dc7..484bc09436fd 100644 --- a/gfx/skia/skia/include/private/SkTLogic.h +++ b/gfx/skia/skia/include/private/SkTLogic.h @@ -58,8 +58,10 @@ template using common_type_t = typename std::common_type:: template struct underlying_type { using type = __underlying_type(T); }; +template using is_trivially_destructible = std::has_trivial_destructor; #else template using underlying_type = std::underlying_type; +template using is_trivially_destructible = std::is_trivially_destructible; #endif template using underlying_type_t = typename skstd::underlying_type::type; diff --git a/gfx/skia/skia/include/private/SkTemplates.h b/gfx/skia/skia/include/private/SkTemplates.h index 01a8ec0c3bd9..919d160d0db1 100644 --- a/gfx/skia/skia/include/private/SkTemplates.h +++ b/gfx/skia/skia/include/private/SkTemplates.h @@ -11,6 +11,7 @@ #define SkTemplates_DEFINED #include "SkMath.h" +#include "SkMalloc.h" #include "SkTLogic.h" #include "SkTypes.h" #include @@ -81,33 +82,6 @@ public: operator T*() const { return this->get(); } }; -/** \class SkAutoTDelete - An SkAutoTDelete is like a T*, except that the destructor of SkAutoTDelete - automatically deletes the pointer it holds (if any). That is, SkAutoTDelete - owns the T object that it points to. Like a T*, an SkAutoTDelete may hold - either NULL or a pointer to a T object. Also like T*, SkAutoTDelete is - thread-compatible, and once you dereference it, you get the threadsafety - guarantees of T. - - The size of a SkAutoTDelete is small: sizeof(SkAutoTDelete) == sizeof(T*) -*/ -template class SkAutoTDelete : public std::unique_ptr { -public: - SkAutoTDelete(T* obj = NULL) : std::unique_ptr(obj) {} - - operator T*() const { return this->get(); } - -#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) - // Need to update graphics/BitmapRegionDecoder.cpp. - T* detach() { return this->release(); } -#endif -}; - -template class SkAutoTDeleteArray : public std::unique_ptr { -public: - SkAutoTDeleteArray(T array[]) : std::unique_ptr(array) {} -}; - /** Allocate an array of T elements, and free the array in the destructor */ template class SkAutoTArray : SkNoncopyable { @@ -231,6 +205,14 @@ public: */ T* get() const { return fArray; } + T* begin() { return fArray; } + + const T* begin() const { return fArray; } + + T* end() { return fArray + fCount; } + + const T* end() const { return fArray + fCount; } + /** Return the nth element in the array */ T& operator[](int index) const { @@ -271,6 +253,8 @@ public: fPtr = count ? (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW) : nullptr; } + SkAutoTMalloc(SkAutoTMalloc&& that) : fPtr(that.release()) {} + ~SkAutoTMalloc() { sk_free(fPtr); } @@ -309,6 +293,14 @@ public: return fPtr[index]; } + SkAutoTMalloc& operator=(SkAutoTMalloc&& that) { + if (this != &that) { + sk_free(fPtr); + fPtr = that.release(); + } + return *this; + } + /** * Transfer ownership of the ptr to the caller, setting the internal * pointer to NULL. Note that this differs from get(), which also returns @@ -489,4 +481,6 @@ private: SkAlignedSStorage fStorage; }; +using SkAutoFree = std::unique_ptr>; + #endif diff --git a/gfx/skia/skia/include/private/SkWeakRefCnt.h b/gfx/skia/skia/include/private/SkWeakRefCnt.h index d6631e946f95..c65ea9e7f172 100644 --- a/gfx/skia/skia/include/private/SkWeakRefCnt.h +++ b/gfx/skia/skia/include/private/SkWeakRefCnt.h @@ -60,7 +60,7 @@ public: /** Destruct, asserting that the weak reference count is 1. */ - virtual ~SkWeakRefCnt() { + ~SkWeakRefCnt() override { #ifdef SK_DEBUG SkASSERT(getWeakCnt() == 1); fWeakCnt.store(0, std::memory_order_relaxed); diff --git a/gfx/skia/skia/include/svg/SkSVGCanvas.h b/gfx/skia/skia/include/svg/SkSVGCanvas.h index e285faa45960..f544f64e1da1 100644 --- a/gfx/skia/skia/include/svg/SkSVGCanvas.h +++ b/gfx/skia/skia/include/svg/SkSVGCanvas.h @@ -25,7 +25,7 @@ public: * The 'bounds' parameter defines an initial SVG viewport (viewBox attribute on the root * SVG element). */ - static SkCanvas* Create(const SkRect& bounds, SkXMLWriter*); + static std::unique_ptr Make(const SkRect& bounds, SkXMLWriter*); }; #endif diff --git a/gfx/skia/skia/include/utils/SkBoundaryPatch.h b/gfx/skia/skia/include/utils/SkBoundaryPatch.h deleted file mode 100644 index f8edd594b951..000000000000 --- a/gfx/skia/skia/include/utils/SkBoundaryPatch.h +++ /dev/null @@ -1,66 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkBoundaryPatch_DEFINED -#define SkBoundaryPatch_DEFINED - -#include "SkPoint.h" -#include "SkRefCnt.h" - -class SkBoundary : public SkRefCnt { -public: - - - // These must be 0, 1, 2, 3 for efficiency in the subclass implementations - enum Edge { - kTop = 0, - kRight = 1, - kBottom = 2, - kLeft = 3 - }; - // Edge index goes clockwise around the boundary, beginning at the "top" - virtual SkPoint eval(Edge, SkScalar unitInterval) = 0; - -private: - typedef SkRefCnt INHERITED; -}; - -class SkBoundaryPatch { -public: - SkBoundaryPatch(); - ~SkBoundaryPatch(); - - SkBoundary* getBoundary() const { return fBoundary; } - SkBoundary* setBoundary(SkBoundary*); - - SkPoint eval(SkScalar unitU, SkScalar unitV); - bool evalPatch(SkPoint verts[], int rows, int cols); - -private: - SkBoundary* fBoundary; -}; - -//////////////////////////////////////////////////////////////////////// - -class SkLineBoundary : public SkBoundary { -public: - SkPoint fPts[4]; - - // override - virtual SkPoint eval(Edge, SkScalar); -}; - -class SkCubicBoundary : public SkBoundary { -public: - // the caller sets the first 12 entries. The 13th is used by the impl. - SkPoint fPts[13]; - - // override - virtual SkPoint eval(Edge, SkScalar); -}; - -#endif diff --git a/gfx/skia/skia/include/utils/SkCamera.h b/gfx/skia/skia/include/utils/SkCamera.h index 4b77ec685d38..3cb13fc19bd6 100644 --- a/gfx/skia/skia/include/utils/SkCamera.h +++ b/gfx/skia/skia/include/utils/SkCamera.h @@ -103,10 +103,10 @@ public: void update(); void patchToMatrix(const SkPatch3D&, SkMatrix* matrix) const; - SkPoint3D fLocation; - SkPoint3D fAxis; - SkPoint3D fZenith; - SkPoint3D fObserver; + SkPoint3D fLocation; // origin of the camera's space + SkPoint3D fAxis; // view direction + SkPoint3D fZenith; // up direction + SkPoint3D fObserver; // eye position (may not be the same as the origin) private: mutable SkMatrix fOrientation; diff --git a/gfx/skia/skia/include/utils/SkCanvasStateUtils.h b/gfx/skia/skia/include/utils/SkCanvasStateUtils.h index 3071c7547ce7..23cada8e2f54 100644 --- a/gfx/skia/skia/include/utils/SkCanvasStateUtils.h +++ b/gfx/skia/skia/include/utils/SkCanvasStateUtils.h @@ -62,7 +62,7 @@ public: * identical to the captured canvas. The caller is responsible for * calling unref on the SkCanvas. */ - static SkCanvas* CreateFromCanvasState(const SkCanvasState* state); + static std::unique_ptr MakeFromCanvasState(const SkCanvasState* state); /** * Free the memory associated with the captured canvas state. The state diff --git a/gfx/skia/skia/include/utils/SkDumpCanvas.h b/gfx/skia/skia/include/utils/SkDumpCanvas.h index e11185336973..727c5797d776 100644 --- a/gfx/skia/skia/include/utils/SkDumpCanvas.h +++ b/gfx/skia/skia/include/utils/SkDumpCanvas.h @@ -9,6 +9,7 @@ #define SkDumpCanvas_DEFINED #include "SkCanvas.h" +#include "SkVertices.h" /** This class overrides all the draw methods on SkCanvas, and formats them as text, and then sends that to a Dumper helper object. @@ -21,7 +22,7 @@ public: class Dumper; explicit SkDumpCanvas(Dumper* = 0); - virtual ~SkDumpCanvas(); + ~SkDumpCanvas() override; enum Verb { kNULL_Verb, @@ -93,7 +94,7 @@ protected: virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) override; virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) override; void onDrawPaint(const SkPaint&) override; @@ -111,16 +112,12 @@ protected: const SkPaint*, SrcRectConstraint) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; - void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; - void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, ClipOp) override; + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; void onDrawAnnotation(const SkRect&, const char key[], SkData* value) override; diff --git a/gfx/skia/skia/include/utils/SkFrontBufferedStream.h b/gfx/skia/skia/include/utils/SkFrontBufferedStream.h index bfc2728ef0d9..3532fc5259fc 100644 --- a/gfx/skia/skia/include/utils/SkFrontBufferedStream.h +++ b/gfx/skia/skia/include/utils/SkFrontBufferedStream.h @@ -5,6 +5,9 @@ * found in the LICENSE file. */ +#ifndef SkFrontBufferedStream_DEFINED +#define SkFrontBufferedStream_DEFINED + #include "SkTypes.h" class SkStream; @@ -35,3 +38,4 @@ public: */ static SkStreamRewindable* Create(SkStream* stream, size_t minBufferSize); }; +#endif // SkFrontBufferedStream_DEFINED diff --git a/gfx/skia/skia/include/utils/SkLayer.h b/gfx/skia/skia/include/utils/SkLayer.h deleted file mode 100644 index 25bc32886eba..000000000000 --- a/gfx/skia/skia/include/utils/SkLayer.h +++ /dev/null @@ -1,130 +0,0 @@ - -/* - * Copyright 2010 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkLayer_DEFINED -#define SkLayer_DEFINED - -#include "../private/SkTDArray.h" -#include "SkRefCnt.h" -#include "SkColor.h" -#include "SkMatrix.h" -#include "SkPoint.h" -#include "SkRect.h" -#include "SkSize.h" - -class SkCanvas; - -class SkLayer : public SkRefCnt { - -public: - - - SkLayer(); - SkLayer(const SkLayer&); - virtual ~SkLayer(); - - bool isInheritFromRootTransform() const; - SkScalar getOpacity() const { return m_opacity; } - const SkSize& getSize() const { return m_size; } - const SkPoint& getPosition() const { return m_position; } - const SkPoint& getAnchorPoint() const { return m_anchorPoint; } - const SkMatrix& getMatrix() const { return fMatrix; } - const SkMatrix& getChildrenMatrix() const { return fChildrenMatrix; } - - SkScalar getWidth() const { return m_size.width(); } - SkScalar getHeight() const { return m_size.height(); } - - void setInheritFromRootTransform(bool); - void setOpacity(SkScalar opacity) { m_opacity = opacity; } - void setSize(SkScalar w, SkScalar h) { m_size.set(w, h); } - void setPosition(SkScalar x, SkScalar y) { m_position.set(x, y); } - void setAnchorPoint(SkScalar x, SkScalar y) { m_anchorPoint.set(x, y); } - void setMatrix(const SkMatrix&); - void setChildrenMatrix(const SkMatrix&); - - // children - - /** Return the number of layers in our child list. - */ - int countChildren() const; - - /** Return the child at the specified index (starting at 0). This does not - affect the reference count of the child. - */ - SkLayer* getChild(int index) const; - - /** Add this layer to our child list at the end (top-most), and ref() it. - If it was already in another hierarchy, remove it from that list. - Return the new child. - */ - SkLayer* addChild(SkLayer* child); - - /** Remove this layer from its parent's list (or do nothing if it has no - parent.) If it had a parent, then unref() is called. - */ - void detachFromParent(); - - /** Remove, and unref(), all of the layers in our child list. - */ - void removeChildren(); - - /** Return our parent layer, or NULL if we have none. - */ - SkLayer* getParent() const { return fParent; } - - /** Return the root layer in this hiearchy. If this layer is the root - (i.e. has no parent), then this returns itself. - */ - SkLayer* getRootLayer() const; - - // coordinate system transformations - - /** Return, in matrix, the matix transfomations that are applied locally - when this layer draws (i.e. its position and matrix/anchorPoint). - This does not include the childrenMatrix, since that is only applied - after this layer draws (but before its children draw). - */ - void getLocalTransform(SkMatrix* matrix) const; - - /** Return, in matrix, the concatenation of transforms that are applied - from this layer's root parent to the layer itself. - This is the matrix that is applied to the layer during drawing. - */ - void localToGlobal(SkMatrix* matrix) const; - - // paint method - - void draw(SkCanvas*, SkScalar opacity); - void draw(SkCanvas* canvas) { - this->draw(canvas, SK_Scalar1); - } - -protected: - virtual void onDraw(SkCanvas*, SkScalar opacity); - -private: - enum Flags { - kInheritFromRootTransform_Flag = 0x01 - }; - - SkLayer* fParent; - SkScalar m_opacity; - SkSize m_size; - SkPoint m_position; - SkPoint m_anchorPoint; - SkMatrix fMatrix; - SkMatrix fChildrenMatrix; - uint32_t fFlags; - - SkTDArray m_children; - - typedef SkRefCnt INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/utils/SkLua.h b/gfx/skia/skia/include/utils/SkLua.h index ad6f996ac3fe..ea3e166b04f8 100644 --- a/gfx/skia/skia/include/utils/SkLua.h +++ b/gfx/skia/skia/include/utils/SkLua.h @@ -8,7 +8,6 @@ #ifndef SkLua_DEFINED #define SkLua_DEFINED -#include "SkClipStack.h" #include "SkColor.h" #include "SkPathEffect.h" #include "SkScalar.h" @@ -59,13 +58,8 @@ public: void pushPaint(const SkPaint&, const char tableKey[] = NULL); void pushPath(const SkPath&, const char tableKey[] = NULL); void pushCanvas(SkCanvas*, const char tableKey[] = NULL); - void pushClipStack(const SkClipStack&, const char tableKey[] = NULL); - void pushClipStackElement(const SkClipStack::Element& element, const char tableKey[] = NULL); void pushTextBlob(const SkTextBlob*, const char tableKey[] = NULL); - // This SkCanvas lua methods is declared here to benefit from SkLua's friendship with SkCanvas. - static int lcanvas_getReducedClipStack(lua_State* L); - private: lua_State* fL; SkString fTermCode; diff --git a/gfx/skia/skia/include/utils/SkLuaCanvas.h b/gfx/skia/skia/include/utils/SkLuaCanvas.h index ac29f6f27214..7653b45366bd 100644 --- a/gfx/skia/skia/include/utils/SkLuaCanvas.h +++ b/gfx/skia/skia/include/utils/SkLuaCanvas.h @@ -10,6 +10,7 @@ #include "SkCanvas.h" #include "SkString.h" +#include "SkVertices.h" struct lua_State; @@ -18,7 +19,7 @@ public: void pushThis(); SkLuaCanvas(int width, int height, lua_State*, const char function[]); - virtual ~SkLuaCanvas(); + ~SkLuaCanvas() override; protected: void willSave() override; @@ -57,16 +58,12 @@ protected: const SkPaint*, SrcRectConstraint) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; - void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; - void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, ClipOp) override; + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; diff --git a/gfx/skia/skia/include/utils/SkMeshUtils.h b/gfx/skia/skia/include/utils/SkMeshUtils.h deleted file mode 100644 index 7e0e8f4de260..000000000000 --- a/gfx/skia/skia/include/utils/SkMeshUtils.h +++ /dev/null @@ -1,50 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkMeshUtils_DEFINED -#define SkMeshUtils_DEFINED - -#include "SkPoint.h" -#include "SkColor.h" - -class SkBitmap; -class SkCanvas; -class SkPaint; - -class SkMeshIndices { -public: - SkMeshIndices(); - ~SkMeshIndices(); - - bool init(int texW, int texH, int rows, int cols) { - return this->init(NULL, NULL, texW, texH, rows, cols); - } - - bool init(SkPoint tex[], uint16_t indices[], - int texW, int texH, int rows, int cols); - - int indexCount() const { return fIndexCount; } - const uint16_t* indices() const { return fIndices; } - - size_t texCount() const { return fTexCount; } - const SkPoint* tex() const { return fTex; } - -private: - int fIndexCount, fTexCount; - SkPoint* fTex; - uint16_t* fIndices; - void* fStorage; // may be null -}; - -class SkMeshUtils { -public: - static void Draw(SkCanvas*, const SkBitmap&, int rows, int cols, - const SkPoint verts[], const SkColor colors[], - const SkPaint& paint); -}; - -#endif diff --git a/gfx/skia/skia/include/utils/SkNWayCanvas.h b/gfx/skia/skia/include/utils/SkNWayCanvas.h index 4e7f4224f8c8..ba0745e42004 100644 --- a/gfx/skia/skia/include/utils/SkNWayCanvas.h +++ b/gfx/skia/skia/include/utils/SkNWayCanvas.h @@ -10,12 +10,12 @@ #define SkNWayCanvas_DEFINED #include "../private/SkTDArray.h" -#include "SkCanvas.h" +#include "SkNoDrawCanvas.h" -class SK_API SkNWayCanvas : public SkCanvas { +class SK_API SkNWayCanvas : public SkNoDrawCanvas { public: SkNWayCanvas(int width, int height); - virtual ~SkNWayCanvas(); + ~SkNWayCanvas() override; virtual void addCanvas(SkCanvas*); virtual void removeCanvas(SkCanvas*); @@ -52,7 +52,7 @@ protected: void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], const SkRect* cull, const SkPaint& paint) override; virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) override; void onDrawPaint(const SkPaint&) override; @@ -70,16 +70,12 @@ protected: const SkPaint*, SrcRectConstraint) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; - void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; - void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, ClipOp) override; + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; void onDrawAnnotation(const SkRect&, const char[], SkData*) override; @@ -87,7 +83,7 @@ protected: class Iter; private: - typedef SkCanvas INHERITED; + typedef SkNoDrawCanvas INHERITED; }; diff --git a/gfx/skia/skia/include/utils/SkNoDrawCanvas.h b/gfx/skia/skia/include/utils/SkNoDrawCanvas.h new file mode 100644 index 000000000000..d21d678f165c --- /dev/null +++ b/gfx/skia/skia/include/utils/SkNoDrawCanvas.h @@ -0,0 +1,77 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkNoDrawCanvas_DEFINED +#define SkNoDrawCanvas_DEFINED + +#include "SkCanvas.h" +#include "SkVertices.h" + +struct SkIRect; + +// SkNoDrawCanvas is a helper for SkCanvas subclasses which do not need to +// actually rasterize (e.g., analysis of the draw calls). +// +// It provides the following simplifications: +// +// * not backed by any device/pixels +// * conservative clipping (clipping calls only use rectangles) +// +class SK_API SkNoDrawCanvas : public SkCanvas { +public: + SkNoDrawCanvas(int width, int height); + + // TODO: investigate the users of this ctor. + SkNoDrawCanvas(const SkIRect&); + +protected: + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override; + + // No-op overrides for aborting rasterization earlier than SkNullBlitter. + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override {} + void onDrawDrawable(SkDrawable*, const SkMatrix*) override {} + void onDrawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {} + void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint&) override {} + void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override {} + void onDrawTextOnPath(const void*, size_t, const SkPath&, const SkMatrix*, + const SkPaint&) override {} + void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, + const SkPaint&) override {} + void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override {} + void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, + const SkPaint&) override {} + + void onDrawPaint(const SkPaint&) override {} + void onDrawPoints(PointMode, size_t, const SkPoint[], const SkPaint&) override {} + void onDrawRect(const SkRect&, const SkPaint&) override {} + void onDrawRegion(const SkRegion&, const SkPaint&) override {} + void onDrawOval(const SkRect&, const SkPaint&) override {} + void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override {} + void onDrawRRect(const SkRRect&, const SkPaint&) override {} + void onDrawPath(const SkPath&, const SkPaint&) override {} + void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override {} + void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, + SrcRectConstraint) override {} + void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override {} + void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*, + SrcRectConstraint) override {} + void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override {} + void onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect&, + const SkPaint*) override {} + void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, + const SkPaint*) override {} + void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, + const SkPaint*) override {} + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override {} + void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], + int, SkBlendMode, const SkRect*, const SkPaint*) override {} + +private: + typedef SkCanvas INHERITED; +}; + +#endif // SkNoDrawCanvas_DEFINED diff --git a/gfx/skia/skia/include/utils/SkNoSaveLayerCanvas.h b/gfx/skia/skia/include/utils/SkNoSaveLayerCanvas.h deleted file mode 100644 index 3d786c532c25..000000000000 --- a/gfx/skia/skia/include/utils/SkNoSaveLayerCanvas.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkNoSaveLayerCanvas_DEFINED -#define SkNoSaveLayerCanvas_DEFINED - -#include "SkCanvas.h" -#include "SkRRect.h" - -// The NoSaveLayerCanvas is used to play back SkPictures when the saveLayer -// functionality isn't required (e.g., during analysis of the draw calls). -// It also simplifies the clipping calls to only use rectangles. -class SK_API SkNoSaveLayerCanvas : public SkCanvas { -public: - SkNoSaveLayerCanvas(SkBaseDevice* device) - : INHERITED(device, kConservativeRasterClip_InitFlag) - {} - -protected: - SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override { - (void)this->INHERITED::getSaveLayerStrategy(rec); - return kNoLayer_SaveLayerStrategy; - } - -private: - typedef SkCanvas INHERITED; -}; - -#endif // SkNoSaveLayerCanvas_DEFINED diff --git a/gfx/skia/skia/include/utils/SkNullCanvas.h b/gfx/skia/skia/include/utils/SkNullCanvas.h index 99a26dafddb4..8e5e0acd86c5 100644 --- a/gfx/skia/skia/include/utils/SkNullCanvas.h +++ b/gfx/skia/skia/include/utils/SkNullCanvas.h @@ -8,13 +8,11 @@ #ifndef SkNullCanvas_DEFINED #define SkNullCanvas_DEFINED -#include "SkBitmap.h" - -class SkCanvas; +#include "SkCanvas.h" /** * Creates a canvas that draws nothing. This is useful for performance testing. */ -SK_API SkCanvas* SkCreateNullCanvas(); +SK_API std::unique_ptr SkMakeNullCanvas(); #endif diff --git a/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h b/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h index 63eaaa2fbcd6..31b366373024 100644 --- a/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h +++ b/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h @@ -17,11 +17,6 @@ */ class SK_API SkPaintFilterCanvas : public SkNWayCanvas { public: - /** - * DEPRECATED: use the variant below. - */ - SkPaintFilterCanvas(int width, int height); - /** * The new SkPaintFilterCanvas is configured for forwarding to the * specified canvas. Also copies the target canvas matrix and clip bounds. @@ -79,13 +74,9 @@ protected: const SkPaint*, SrcRectConstraint) override; void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; diff --git a/gfx/skia/skia/include/utils/SkPictureUtils.h b/gfx/skia/skia/include/utils/SkPictureUtils.h deleted file mode 100644 index b65a64d57924..000000000000 --- a/gfx/skia/skia/include/utils/SkPictureUtils.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkPictureUtils_DEFINED -#define SkPictureUtils_DEFINED - -#include "SkPicture.h" - -// TODO: remove this file? - -class SK_API SkPictureUtils { -public: - /** - * How many bytes are allocated to hold the SkPicture. - * Includes operations, parameters, bounding data, deletion listeners; - * includes nested SkPictures, but does not include large objects that - * SkRecord holds a reference to (e.g. paths, or pixels backing bitmaps). - */ - static size_t ApproximateBytesUsed(const SkPicture* pict) { - return pict->approximateBytesUsed(); - } -}; - -#endif diff --git a/gfx/skia/skia/include/utils/SkShadowUtils.h b/gfx/skia/skia/include/utils/SkShadowUtils.h new file mode 100644 index 000000000000..01514a46ff50 --- /dev/null +++ b/gfx/skia/skia/include/utils/SkShadowUtils.h @@ -0,0 +1,71 @@ + +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkShadowUtils_DEFINED +#define SkShadowUtils_DEFINED + +#include "SkColor.h" +#include "SkScalar.h" +#include "../private/SkShadowFlags.h" +#include + +class SkCanvas; +class SkPath; +class SkResourceCache; + +class SkShadowUtils { +public: + /** + * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc + * light. + * + * @param canvas The canvas on which to draw the shadows. + * @param path The occluder used to generate the shadows. + * @param occluderHeight The vertical offset of the occluder from the canvas. This is + * independent of the canvas's current matrix. + * @param lightPos The 3D position of the light relative to the canvas plane. This is + * independent of the canvas's current matrix. + * @param lightRadius The radius of the disc light. + * @param ambientAlpha The maximum alpha of the ambient shadow. + * @param spotAlpha The maxium alpha of the spot shadow. + * @param color The shadow color. + * @param flags Options controlling opaque occluder optimizations and shadow appearance. See + * SkShadowFlags. + * @param cache Used for testing purposes. Clients should pass nullptr (default). + */ + static void DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight, + const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha, + SkScalar spotAlpha, SkColor color, + uint32_t flags = SkShadowFlags::kNone_ShadowFlag, + SkResourceCache* cache = nullptr); + + /** + * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc + * light. Takes a function to vary the z value based on the transformed x and y position. + * This shadow will not be cached, as the assumption is that this will be used for animation. + * + * @param canvas The canvas on which to draw the shadows. + * @param path The occluder used to generate the shadows. + * @param heightFunc A function which returns the vertical offset of the occluder from the + * canvas based on local x and y values (the current matrix is not applied). + * @param lightPos The 3D position of the light relative to the canvas plane. This is + * independent of the canvas's current matrix. + * @param lightRadius The radius of the disc light. + * @param ambientAlpha The maximum alpha of the ambient shadow. + * @param spotAlpha The maxium alpha of the spot shadow. + * @param color The shadow color. + * @param flags Options controlling opaque occluder optimizations and shadow appearance. See + * SkShadowFlags. + */ + static void DrawUncachedShadow(SkCanvas* canvas, const SkPath& path, + std::function heightFunc, + const SkPoint3& lightPos, SkScalar lightRadius, + SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color, + uint32_t flags = SkShadowFlags::kNone_ShadowFlag); +}; + +#endif diff --git a/gfx/skia/skia/include/utils/mac/SkCGUtils.h b/gfx/skia/skia/include/utils/mac/SkCGUtils.h index 29df8b81a889..2dcbb965b4b7 100644 --- a/gfx/skia/skia/include/utils/mac/SkCGUtils.h +++ b/gfx/skia/skia/include/utils/mac/SkCGUtils.h @@ -10,6 +10,7 @@ #include "SkSize.h" #include "SkImageInfo.h" +#include "SkImage.h" #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) @@ -23,8 +24,11 @@ class SkBitmap; class SkData; +class SkPixmap; class SkStreamRewindable; +SK_API CGContextRef SkCreateCGContext(const SkPixmap&); + /** * Given a CGImage, allocate an SkBitmap and copy the image's pixels into it. If scaleToFit is not * null, use it to determine the size of the bitmap, and scale the image to fill the bitmap. @@ -32,7 +36,9 @@ class SkStreamRewindable; * * On failure, return false, and leave bitmap unchanged. */ -SK_API bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef src, SkISize* scaleToFit = NULL); +SK_API bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef src); + +SK_API sk_sp SkMakeImageFromCGImage(CGImageRef); /** * Copy the pixels from src into the memory specified by info/rowBytes/dstPixels. On failure, diff --git a/gfx/skia/skia/include/views/SkEvent.h b/gfx/skia/skia/include/views/SkEvent.h index 649553000660..b78fd6fc1df8 100644 --- a/gfx/skia/skia/include/views/SkEvent.h +++ b/gfx/skia/skia/include/views/SkEvent.h @@ -8,10 +8,12 @@ #ifndef SkEvent_DEFINED #define SkEvent_DEFINED -#include "SkDOM.h" #include "SkMetaData.h" #include "SkString.h" +class SkDOM; +struct SkDOMNode; + #include "../private/SkLeanWindows.h" /** Unique 32bit id used to identify an instance of SkEventSink. When events are @@ -180,7 +182,7 @@ public: const SkMetaData& getMetaData() const { return fMeta; } /** Call this to initialize the event from the specified XML node */ - void inflate(const SkDOM&, const SkDOM::Node*); + void inflate(const SkDOM&, const SkDOMNode*); SkDEBUGCODE(void dump(const char title[] = NULL);) diff --git a/gfx/skia/skia/include/views/SkOSWindow_SDL.h b/gfx/skia/skia/include/views/SkOSWindow_SDL.h deleted file mode 100644 index 65685d1d2114..000000000000 --- a/gfx/skia/skia/include/views/SkOSWindow_SDL.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkOSWindow_SDL_DEFINED -#define SkOSWindow_SDL_DEFINED - -#include "SDL.h" -#include "SDL_opengl.h" -#include "SkWindow.h" - -class SkOSWindow : public SkWindow { -public: - SkOSWindow(void*); - virtual ~SkOSWindow(); - - enum SkBackEndTypes { - kNone_BackEndType, // TODO: remove this, it's not a real option. - kNativeGL_BackEndType, -#if SK_ANGLE - kANGLE_BackEndType, -#endif // SK_ANGLE - }; - - void release(); - bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, AttachmentInfo*); - void present(); - bool makeFullscreen(); - void setVsync(bool); - void closeWindow(); - static void RunEventLoop(); - -protected: - void onSetTitle(const char title[]) override; - -private: - void createWindow(int msaaSampleCount); - void destroyWindow(); - void updateWindowTitle(); - static SkOSWindow* GetInstanceForWindowID(Uint32 windowID); - static bool HasDirtyWindows(); - static void UpdateDirtyWindows(); - static void HandleEvent(const SDL_Event&); - - SDL_Window* fWindow; - SDL_GLContext fGLContext; - int fWindowMSAASampleCount; - typedef SkWindow INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/views/SkOSWindow_Unix.h b/gfx/skia/skia/include/views/SkOSWindow_Unix.h index 9d1b8e039296..48838e764ce8 100644 --- a/gfx/skia/skia/include/views/SkOSWindow_Unix.h +++ b/gfx/skia/skia/include/views/SkOSWindow_Unix.h @@ -26,7 +26,7 @@ struct SkUnixWindow { class SkOSWindow : public SkWindow { public: SkOSWindow(void*); - ~SkOSWindow(); + ~SkOSWindow() override; void* getHWND() const { return (void*)fUnixWindow.fWin; } void* getDisplay() const { return (void*)fUnixWindow.fDisplay; } diff --git a/gfx/skia/skia/include/views/SkOSWindow_Win.h b/gfx/skia/skia/include/views/SkOSWindow_Win.h index 7ed22a651459..774244400c9a 100644 --- a/gfx/skia/skia/include/views/SkOSWindow_Win.h +++ b/gfx/skia/skia/include/views/SkOSWindow_Win.h @@ -91,11 +91,11 @@ private: #if SK_SUPPORT_GPU void* fHGLRC; #if SK_ANGLE - EGLDisplay fDisplay; - EGLContext fContext; - EGLSurface fSurface; - EGLConfig fConfig; - SkAutoTUnref fANGLEInterface; + EGLDisplay fDisplay; + EGLContext fContext; + EGLSurface fSurface; + EGLConfig fConfig; + sk_sp fANGLEInterface; #endif // SK_ANGLE #endif // SK_SUPPORT_GPU diff --git a/gfx/skia/skia/include/views/SkOSWindow_iOS.h b/gfx/skia/skia/include/views/SkOSWindow_iOS.h index c0b2fc3f0ae3..3b540cff3f15 100644 --- a/gfx/skia/skia/include/views/SkOSWindow_iOS.h +++ b/gfx/skia/skia/include/views/SkOSWindow_iOS.h @@ -37,7 +37,7 @@ protected: virtual void onHandleInval(const SkIRect&); // overrides from SkView virtual void onAddMenu(const SkOSMenu*); - virtual void onUpdateMenu(SkOSMenu*); + virtual void onUpdateMenu(const SkOSMenu*); virtual void onSetTitle(const char[]); private: diff --git a/gfx/skia/skia/include/views/SkView.h b/gfx/skia/skia/include/views/SkView.h index 17eb3800f474..43f86f501edf 100644 --- a/gfx/skia/skia/include/views/SkView.h +++ b/gfx/skia/skia/include/views/SkView.h @@ -12,13 +12,13 @@ #include "SkEventSink.h" #include "SkRect.h" -#include "SkDOM.h" -#include "../private/SkTDict.h" #include "SkMatrix.h" #include "SkMetaData.h" class SkCanvas; class SkLayerView; +class SkDOM; +struct SkDOMNode; /** \class SkView @@ -258,13 +258,13 @@ public: */ class Artist : public SkRefCnt { public: - + void draw(SkView*, SkCanvas*); - void inflate(const SkDOM&, const SkDOM::Node*); + void inflate(const SkDOM&, const SkDOMNode*); protected: virtual void onDraw(SkView*, SkCanvas*) = 0; - virtual void onInflate(const SkDOM&, const SkDOM::Node*); + virtual void onInflate(const SkDOM&, const SkDOMNode*); private: typedef SkRefCnt INHERITED; }; @@ -286,13 +286,13 @@ public: */ class Layout : public SkRefCnt { public: - + void layoutChildren(SkView* parent); - void inflate(const SkDOM&, const SkDOM::Node*); + void inflate(const SkDOM&, const SkDOMNode*); protected: virtual void onLayoutChildren(SkView* parent) = 0; - virtual void onInflate(const SkDOM&, const SkDOM::Node*); + virtual void onInflate(const SkDOM&, const SkDOMNode*); private: typedef SkRefCnt INHERITED; }; @@ -312,15 +312,7 @@ public: /** Call this to initialize this view based on the specified XML node */ - void inflate(const SkDOM& dom, const SkDOM::Node* node); - /** After a view hierarchy is inflated, this may be called with a dictionary - containing pairs of , where the name string was the view's - "id" attribute when it was inflated. - - This will call the virtual onPostInflate for this view, and the recursively - call postInflate on all of the view's children. - */ - void postInflate(const SkTDict& ids); + void inflate(const SkDOM& dom, const SkDOMNode* node); SkDEBUGCODE(void dump(bool recurse) const;) @@ -358,11 +350,10 @@ protected: */ virtual bool onClick(Click*); /** Override this to initialize your subclass from the XML node. Be sure to call the inherited version too */ - virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + virtual void onInflate(const SkDOM& dom, const SkDOMNode* node); /** Override this if you want to perform post initialization work based on the ID dictionary built during XML parsing. Be sure to call the inherited version too. */ - virtual void onPostInflate(const SkTDict&); public: #ifdef SK_DEBUG diff --git a/gfx/skia/skia/include/views/SkWindow.h b/gfx/skia/skia/include/views/SkWindow.h index e964fc681b5a..8b6c29186b9c 100644 --- a/gfx/skia/skia/include/views/SkWindow.h +++ b/gfx/skia/skia/include/views/SkWindow.h @@ -80,6 +80,11 @@ public: virtual sk_sp makeSurface(); +#if SK_SUPPORT_GPU + sk_sp makeGpuBackedSurface(const AttachmentInfo& attachmentInfo, + const GrGLInterface* , GrContext* grContext); +#endif + protected: virtual bool onEvent(const SkEvent&); virtual bool onDispatchClick(int x, int y, Click::State, void* owner, unsigned modi); @@ -88,8 +93,8 @@ protected: virtual bool onHandleChar(SkUnichar); virtual bool onHandleKey(SkKey); virtual bool onHandleKeyUp(SkKey); - virtual void onAddMenu(const SkOSMenu*) {}; - virtual void onUpdateMenu(const SkOSMenu*) {}; + virtual void onAddMenu(const SkOSMenu*) {} + virtual void onUpdateMenu(const SkOSMenu*) {} virtual void onSetTitle(const char title[]) {} // overrides from SkView @@ -97,11 +102,6 @@ protected: virtual bool onGetFocusView(SkView** focus) const; virtual bool onSetFocusView(SkView* focus); -#if SK_SUPPORT_GPU - sk_sp makeGpuBackedSurface(const AttachmentInfo& attachmentInfo, - const GrGLInterface* , GrContext* grContext); -#endif - private: SkSurfaceProps fSurfaceProps; SkBitmap fBitmap; @@ -122,9 +122,7 @@ private: //////////////////////////////////////////////////////////////////////////////// -#if defined(SK_USE_SDL) - #include "SkOSWindow_SDL.h" -#elif defined(SK_BUILD_FOR_MAC) +#if defined(SK_BUILD_FOR_MAC) #include "SkOSWindow_Mac.h" #elif defined(SK_BUILD_FOR_WIN) #include "SkOSWindow_Win.h" diff --git a/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp b/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp index df0a32ca311b..7ce9d26b4d3e 100644 --- a/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp +++ b/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp @@ -18,7 +18,7 @@ SkBitmapRegionCodec::SkBitmapRegionCodec(SkAndroidCodec* codec) bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator, const SkIRect& desiredSubset, int sampleSize, SkColorType prefColorType, - bool requireUnpremul) { + bool requireUnpremul, sk_sp prefColorSpace) { // Fix the input sampleSize if necessary. if (sampleSize < 1) { @@ -52,15 +52,13 @@ bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocat // Create the image info for the decode SkColorType dstColorType = fCodec->computeOutputColorType(prefColorType); SkAlphaType dstAlphaType = fCodec->computeOutputAlphaType(requireUnpremul); - - // Enable legacy behavior to avoid any gamma correction. Android's assets are - // adjusted to expect a non-gamma correct premultiply. - sk_sp colorSpace = nullptr; + sk_sp dstColorSpace = fCodec->computeOutputColorSpace(dstColorType, + prefColorSpace); SkImageInfo decodeInfo = SkImageInfo::Make(scaledSize.width(), scaledSize.height(), - dstColorType, dstAlphaType, colorSpace); + dstColorType, dstAlphaType, dstColorSpace); // Construct a color table for the decode if necessary - SkAutoTUnref colorTable(nullptr); + sk_sp colorTable(nullptr); int maxColors = 256; SkPMColor colors[256]; if (kIndex_8_SkColorType == dstColorType) { @@ -135,8 +133,6 @@ bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocat } bool SkBitmapRegionCodec::conversionSupported(SkColorType colorType) { - // Enable legacy behavior. - sk_sp colorSpace = nullptr; - SkImageInfo dstInfo = fCodec->getInfo().makeColorType(colorType).makeColorSpace(colorSpace); - return conversion_possible_ignore_color_space(dstInfo, fCodec->getInfo()); + SkImageInfo dstInfo = fCodec->getInfo().makeColorType(colorType); + return conversion_possible(dstInfo, fCodec->getInfo()); } diff --git a/gfx/skia/skia/src/android/SkBitmapRegionCodec.h b/gfx/skia/skia/src/android/SkBitmapRegionCodec.h index 79774173b0e3..baaecc937a6f 100644 --- a/gfx/skia/skia/src/android/SkBitmapRegionCodec.h +++ b/gfx/skia/skia/src/android/SkBitmapRegionCodec.h @@ -5,6 +5,9 @@ * found in the LICENSE file. */ +#ifndef SkBitmapRegionCodec_DEFINED +#define SkBitmapRegionCodec_DEFINED + #include "SkBitmap.h" #include "SkBitmapRegionDecoder.h" #include "SkAndroidCodec.h" @@ -22,16 +25,18 @@ public: bool decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator, const SkIRect& desiredSubset, int sampleSize, - SkColorType colorType, bool requireUnpremul) override; + SkColorType colorType, bool requireUnpremul, + sk_sp prefColorSpace) override; bool conversionSupported(SkColorType colorType) override; - SkEncodedFormat getEncodedFormat() override { return fCodec->getEncodedFormat(); } + SkEncodedImageFormat getEncodedFormat() override { return fCodec->getEncodedFormat(); } private: - SkAutoTDelete fCodec; + std::unique_ptr fCodec; typedef SkBitmapRegionDecoder INHERITED; }; +#endif // SkBitmapRegionCodec_DEFINED diff --git a/gfx/skia/skia/src/android/SkBitmapRegionDecoder.cpp b/gfx/skia/skia/src/android/SkBitmapRegionDecoder.cpp index 6dd48c5f8828..8298fb5298d3 100644 --- a/gfx/skia/skia/src/android/SkBitmapRegionDecoder.cpp +++ b/gfx/skia/skia/src/android/SkBitmapRegionDecoder.cpp @@ -19,21 +19,20 @@ SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create( SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create( SkStreamRewindable* stream, Strategy strategy) { - SkAutoTDelete streamDeleter(stream); + std::unique_ptr streamDeleter(stream); switch (strategy) { case kAndroidCodec_Strategy: { - SkAutoTDelete codec = - SkAndroidCodec::NewFromStream(streamDeleter.release()); + std::unique_ptr codec( + SkAndroidCodec::NewFromStream(streamDeleter.release())); if (nullptr == codec) { SkCodecPrintf("Error: Failed to create codec.\n"); return NULL; } - SkEncodedFormat format = codec->getEncodedFormat(); - switch (format) { - case SkEncodedFormat::kJPEG_SkEncodedFormat: - case SkEncodedFormat::kPNG_SkEncodedFormat: - case SkEncodedFormat::kWEBP_SkEncodedFormat: + switch ((SkEncodedImageFormat)codec->getEncodedFormat()) { + case SkEncodedImageFormat::kJPEG: + case SkEncodedImageFormat::kPNG: + case SkEncodedImageFormat::kWEBP: break; default: return nullptr; diff --git a/gfx/skia/skia/src/android/SkBitmapRegionDecoderPriv.h b/gfx/skia/skia/src/android/SkBitmapRegionDecoderPriv.h index baa891e9c313..db7bd420519b 100644 --- a/gfx/skia/skia/src/android/SkBitmapRegionDecoderPriv.h +++ b/gfx/skia/skia/src/android/SkBitmapRegionDecoderPriv.h @@ -8,6 +8,8 @@ #ifndef SkBitmapRegionDecoderPriv_DEFINED #define SkBitmapRegionDecoderPriv_DEFINED +#include "SkRect.h" + enum SubsetType { kFullyInside_SubsetType, kPartiallyInside_SubsetType, diff --git a/gfx/skia/skia/src/animator/SkADrawable.cpp b/gfx/skia/skia/src/animator/SkADrawable.cpp deleted file mode 100644 index 9ac4095e12b5..000000000000 --- a/gfx/skia/skia/src/animator/SkADrawable.cpp +++ /dev/null @@ -1,24 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkADrawable.h" - -bool SkADrawable::doEvent(SkDisplayEvent::Kind , SkEventState* ) { - return false; -} - -bool SkADrawable::isDrawable() const { - return true; -} - -void SkADrawable::initialize() { -} - -void SkADrawable::setSteps(int steps) { -} diff --git a/gfx/skia/skia/src/animator/SkADrawable.h b/gfx/skia/skia/src/animator/SkADrawable.h deleted file mode 100644 index 26be50d3e964..000000000000 --- a/gfx/skia/skia/src/animator/SkADrawable.h +++ /dev/null @@ -1,28 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkADrawable_DEFINED -#define SkADrawable_DEFINED - -#include "SkDisplayable.h" -#include "SkDisplayEvent.h" -#include "SkMath.h" - -struct SkEventState; - -class SkADrawable : public SkDisplayable { -public: - virtual bool doEvent(SkDisplayEvent::Kind , SkEventState* state ); - virtual bool draw(SkAnimateMaker& ) = 0; - virtual void initialize(); - virtual bool isDrawable() const; - virtual void setSteps(int steps); -}; - -#endif // SkADrawable_DEFINED diff --git a/gfx/skia/skia/src/animator/SkAnimate.h b/gfx/skia/skia/src/animator/SkAnimate.h deleted file mode 100644 index ee391fcd93fb..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimate.h +++ /dev/null @@ -1,34 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkAnimate_DEFINED -#define SkAnimate_DEFINED - -#include "SkAnimateBase.h" -#include "SkDisplayType.h" -#include "SkIntArray.h" -#include "SkUtils.h" - -class SkAnimate : public SkAnimateBase { - DECLARE_MEMBER_INFO(Animate); - SkAnimate(); - virtual ~SkAnimate(); - int components() override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - void onEndElement(SkAnimateMaker& maker) override; -protected: - bool resolveCommon(SkAnimateMaker& ); - int fComponents; -private: - typedef SkAnimateBase INHERITED; -}; - -#endif // SkAnimateField_DEFINED diff --git a/gfx/skia/skia/src/animator/SkAnimate3DSchema.xsd b/gfx/skia/skia/src/animator/SkAnimate3DSchema.xsd deleted file mode 100644 index 5063b75722ec..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimate3DSchema.xsd +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gfx/skia/skia/src/animator/SkAnimate3DSchema.xsx b/gfx/skia/skia/src/animator/SkAnimate3DSchema.xsx deleted file mode 100644 index ceb7d890c9a2..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimate3DSchema.xsx +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/gfx/skia/skia/src/animator/SkAnimateActive.cpp b/gfx/skia/skia/src/animator/SkAnimateActive.cpp deleted file mode 100644 index 0dbe9c9f0f18..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateActive.cpp +++ /dev/null @@ -1,504 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkAnimateActive.h" -#include "SkAnimateBase.h" -#include "SkAnimateMaker.h" -#include "SkAnimateSet.h" -#include "SkDrawGroup.h" -#ifdef SK_DEBUG -#include "SkTime.h" -#endif - -// SkActive holds array of interpolators - -SkActive::SkActive(SkApply& apply, SkAnimateMaker& maker) : fApply(apply), - fMaxTime(0), fMaker(maker), fDrawIndex(0), fDrawMax(0) { -} - -void SkActive::init() -{ - fAnimators = fApply.fAnimators; - int animators = fAnimators.count(); - fInterpolators.setCount(animators); - memset(fInterpolators.begin(), 0, animators * sizeof(SkOperandInterpolator*)); - fState.setCount(animators); - int index; - for (index = 0; index < animators; index++) - fInterpolators[index] = new SkOperandInterpolator; - initState(&fApply, 0); -// for (index = 0; index < animators; index++) -// fState[index].bumpSave(); - SkASSERT(fInterpolators.count() == fAnimators.count()); -} - -SkActive::~SkActive() { - int index; - for (index = 0; index < fSaveRestore.count(); index++) - delete[] fSaveRestore[index]; - for (index = 0; index < fSaveInterpolators.count(); index++) - delete[] fSaveInterpolators[index]; - for (index = 0; index < fInterpolators.count(); index++) - delete fInterpolators[index]; -} - -void SkActive::advance() { - if (fDrawMax < fDrawIndex) - fDrawMax = fDrawIndex; - fDrawIndex += fAnimators.count(); -} - -void SkActive::append(SkApply* apply) { - int oldCount = fAnimators.count(); - SkTDAnimateArray& animates = apply->fAnimators; - int newCount = animates.count(); - int index; - int total = oldCount + newCount; - if (total == 0) - return; - fInterpolators.setCount(total); - memset(&fInterpolators.begin()[oldCount], 0, newCount * sizeof(SkOperandInterpolator*)); - for (index = oldCount; index < total; index++) - fInterpolators[index] = new SkOperandInterpolator; - fAnimators.setCount(total); - memcpy(&fAnimators[oldCount], animates.begin(), sizeof(fAnimators[0]) * - newCount); - fState.setCount(total); - initState(apply, oldCount); - SkASSERT(fApply.scope == apply->scope); - for (index = 0; index < newCount; index++) { - SkAnimateBase* test = animates[index]; -// SkASSERT(fApply.scope == test->fTarget || fApply.scope->contains(test->fTarget)); - SkActive::SkState& testState = fState[oldCount + index]; - for (int inner = 0; inner < oldCount; inner++) { - SkAnimateBase* oldGuard = fAnimators[inner]; - SkActive::SkState& oldState = fState[inner]; - if (oldGuard->fTarget == test->fTarget && oldGuard->fFieldInfo == test->fFieldInfo && - testState.fBegin == oldState.fBegin) { - delete fInterpolators[inner]; - fInterpolators.remove(inner); - fAnimators.remove(inner); - testState.fSave = oldState.fSave; - if (oldState.fUnpostedEndEvent) { -// SkDEBUGF(("%8x %8x active append: post on end\n", this, oldGuard)); - fMaker.postOnEnd(oldGuard, oldState.fBegin + oldState.fDuration); - } - fState.remove(inner); - if (fApply.restore) { - int saveIndex = fSaveRestore.count(); - SkASSERT(fSaveInterpolators.count() == saveIndex); - saveIndex += inner; - do { - saveIndex -= oldCount; - delete[] fSaveRestore[saveIndex]; - fSaveRestore.remove(saveIndex); - delete[] fSaveInterpolators[saveIndex]; - fSaveInterpolators.remove(saveIndex); - } while (saveIndex > 0); - } - oldCount--; - break; - } - } - } -// total = oldCount + newCount; -// for (index = oldCount; index < total; index++) -// fState[index].bumpSave(); - SkASSERT(fInterpolators.count() == fAnimators.count()); -} - -void SkActive::appendSave(int oldCount) { - SkASSERT(fDrawMax == 0); // if true, we can optimize below quite a bit - int newCount = fAnimators.count(); - int saveIndex = fSaveRestore.count(); - SkASSERT(fSaveInterpolators.count() == saveIndex); - int records = saveIndex / oldCount; - int newTotal = records * newCount; - fSaveRestore.setCount(newTotal); - do { - saveIndex -= oldCount; - newTotal -= newCount; - SkASSERT(saveIndex >= 0); - SkASSERT(newTotal >= 0); - memmove(&fSaveRestore[newTotal], &fSaveRestore[saveIndex], oldCount); - memset(&fSaveRestore[newTotal + oldCount], 0, - sizeof(fSaveRestore[0]) * (newCount - oldCount)); - memmove(&fSaveInterpolators[newTotal], - &fSaveInterpolators[saveIndex], oldCount); - memset(&fSaveInterpolators[newTotal + oldCount], 0, - sizeof(fSaveRestore[0]) * (newCount - oldCount)); - } while (saveIndex > 0); - SkASSERT(newTotal == 0); -} - -void SkActive::calcDurations(int index) -{ - SkAnimateBase* animate = fAnimators[index]; - SkMSec duration = animate->dur; - SkState& state = fState[index]; - switch (state.fMode) { - case SkApply::kMode_immediate: - case SkApply::kMode_create: - duration = state.fSteps ? state.fSteps * SK_MSec1 : 1; - break; -// case SkApply::kMode_hold: { -// int entries = animate->entries(); -// SkScriptValue value; -// value.fOperand = animate->getValues()[entries - 1]; -// value.fType = animate->getValuesType(); -// bool result = SkScriptEngine::ConvertTo(nullptr, SkType_Int, &value); -// SkASSERT(result); -// duration = value.fOperand.fS32 * SK_MSec1; -// break; -// } - } - state.fDuration = duration; - SkMSec maxTime = state.fBegin + duration; - if (fMaxTime < maxTime) - fMaxTime = maxTime; -} - -void SkActive::create(SkADrawable* drawable, SkMSec time) { - fApply.fLastTime = time; - fApply.refresh(fMaker); - for (int index = 0; index < fAnimators.count(); index++) { - SkAnimateBase* animate = fAnimators[index]; - SkOperandInterpolator& interpolator = *fInterpolators[index]; - int count = animate->components(); - if (animate->formula.size() > 0) { - SkTDOperandArray values; - values.setCount(count); - SkDEBUGCODE(bool success = ) animate->fFieldInfo->setValue(fMaker, &values, 0, 0, nullptr, - animate->getValuesType(), animate->formula); - SkASSERT(success); - fApply.applyValues(index, values.begin(), count, animate->getValuesType(), time); - } else { - SkAutoSTMalloc<16, SkOperand> values(count); - interpolator.timeToValues(time, values.get()); - fApply.applyValues(index, values.get(), count, animate->getValuesType(), time); - } - } - drawable->enable(fMaker); - SkASSERT(fAnimators.count() == fInterpolators.count()); -} - -bool SkActive::immediate(bool enable) { - SkMSec time = 0; - bool result = false; - SkADrawable* drawable = fApply.scope; - SkMSec final = fMaxTime; - do { - bool applied = fAnimators.count() == 0; - fApply.fLastTime = time; - fApply.refresh(fMaker); - for (int index = 0; index < fAnimators.count(); index++) { - SkAnimateBase* animate = fAnimators[index]; - SkState& state = fState[index]; - if (state.fMode != SkApply::kMode_immediate) - continue; - if (state.fBegin > time) - continue; - if (time > state.fBegin + state.fDuration) - continue; - applied = true; - SkOperandInterpolator& interpolator = *fInterpolators[index]; - int count = animate->components(); - if (animate->formula.size() > 0) { - SkTDOperandArray values; - values.setCount(count); - SkDEBUGCODE(bool success = ) animate->fFieldInfo->setValue(fMaker, &values, 0, 0, nullptr, - animate->getValuesType(), animate->formula); - SkASSERT(success); - fApply.applyValues(index, values.begin(), count, animate->getValuesType(), time); - } else { - SkAutoSTMalloc<16, SkOperand> values(count); - interpolator.timeToValues(time, values.get()); - fApply.applyValues(index, values.get(), count, animate->getValuesType(), time); - } - } - if (enable) - drawable->enable(fMaker); - else if (applied) - result |= drawable->draw(fMaker); - time += SK_MSec1; - } while (time <= final); - return result; -} - -void SkActive::fixInterpolator(SkBool save) { - int animators = fAnimators.count(); - for (int index = 0; index < animators; index++) { - SkAnimateBase* animate = fAnimators[index]; - if (save) { // saved slots increased - animate->refresh(fMaker); - SkOperand* values = animate->getValues(); - setInterpolator(index, values); - saveInterpolatorValues(index); - } else - restoreInterpolatorValues(index); - } -} - -SkMSec SkActive::getTime(SkMSec inTime, int animatorIndex) { - fState[animatorIndex].fTicks = inTime; - return inTime - fState[animatorIndex].fStartTime; -} - -bool SkActive::initializeSave() { - int animators = fAnimators.count(); - int activeTotal = fDrawIndex + animators; - int oldCount = fSaveRestore.count(); - if (oldCount < activeTotal) { - fSaveRestore.setCount(activeTotal); - memset(&fSaveRestore[oldCount], 0, sizeof(fSaveRestore[0]) * (activeTotal - oldCount)); - SkASSERT(fSaveInterpolators.count() == oldCount); - fSaveInterpolators.setCount(activeTotal); - memset(&fSaveInterpolators[oldCount], 0, - sizeof(fSaveInterpolators[0]) * (activeTotal - oldCount)); - return true; - } - return false; -} - -void SkActive::initState(SkApply* apply, int offset) { - int count = fState.count(); - for (int index = offset; index < count; index++) { - SkState& state = fState[index]; - SkAnimateBase* animate = fAnimators[index]; -#if 0 // def SK_DEBUG - if (animate->fHasEndEvent) - SkDebugf("%8x %8x active initState:\n", this, animate); -#endif - SkOperand* from = animate->getValues(); - state.fStartTime = state.fBegin = apply->begin + animate->begin; - state.fMode = apply->mode; - state.fTransition = apply->transition; -#if 0 - state.fPickup = (SkBool8) apply->pickup; -#endif - state.fRestore = (SkBool8) apply->restore; - state.fSave = apply->begin; - state.fStarted = false; - state.fSteps = apply->steps; - state.fTicks = 0; - state.fUnpostedEndEvent = (SkBool8) animate->fHasEndEvent; - calcDurations(index); - setInterpolator(index, from); - } - if (count == 0 && (apply->mode == SkApply::kMode_immediate || apply->mode == SkApply::kMode_create)) - fMaxTime = apply->begin + apply->steps * SK_MSec1; -} - -void SkActive::pickUp(SkActive* existing) { - SkTDOperandArray existingValues; - for (int index = 0; index < fAnimators.count(); index++) { - SkAnimateBase* animate = fAnimators[index]; - SkASSERT(animate->getValuesType() == SkType_Float); - int components = animate->components(); - SkOperand* from = animate->getValues(); - SkOperand* to = &from[animate->components()]; - existingValues.setCount(components); - existing->fInterpolators[index]->timeToValues( - existing->fState[index].fTicks - existing->fState[index].fStartTime, existingValues.begin()); - SkScalar originalSum = 0; - SkScalar workingSum = 0; - for (int cIndex = 0; cIndex < components; cIndex++) { - SkScalar delta = to[cIndex].fScalar - from[cIndex].fScalar; - originalSum += SkScalarMul(delta, delta); - delta = to[cIndex].fScalar - existingValues[cIndex].fScalar; - workingSum += SkScalarMul(delta, delta); - } - if (workingSum < originalSum) { - SkScalar originalDistance = SkScalarSqrt(originalSum); - SkScalar workingDistance = SkScalarSqrt(workingSum); - existing->fState[index].fDuration = (SkMSec) SkScalarMulDiv(fState[index].fDuration, - workingDistance, originalDistance); - } - fInterpolators[index]->reset(components, 2, SkType_Float); - fInterpolators[index]->setKeyFrame(0, 0, existingValues.begin(), animate->blend[0]); - fInterpolators[index]->setKeyFrame(1, fState[index].fDuration, to, animate->blend[0]); - } -} - -void SkActive::resetInterpolators() { - int animators = fAnimators.count(); - for (int index = 0; index < animators; index++) { - SkAnimateBase* animate = fAnimators[index]; - SkOperand* values = animate->getValues(); - setInterpolator(index, values); - } -} - -void SkActive::resetState() { - fDrawIndex = 0; - int count = fState.count(); - for (int index = 0; index < count; index++) { - SkState& state = fState[index]; - SkAnimateBase* animate = fAnimators[index]; -#if 0 // def SK_DEBUG - if (animate->fHasEndEvent) - SkDebugf("%8x %8x active resetState: has end event\n", this, animate); -#endif - state.fStartTime = state.fBegin = fApply.begin + animate->begin; - state.fStarted = false; - state.fTicks = 0; - } -} - -void SkActive::restoreInterpolatorValues(int index) { - SkOperandInterpolator& interpolator = *fInterpolators[index]; - index += fDrawIndex ; - int count = interpolator.getValuesCount(); - memcpy(interpolator.getValues(), fSaveInterpolators[index], count * sizeof(SkOperand)); -} - -void SkActive::saveInterpolatorValues(int index) { - SkOperandInterpolator& interpolator = *fInterpolators[index]; - index += fDrawIndex ; - int count = interpolator.getValuesCount(); - SkOperand* cache = new SkOperand[count]; // this should use sk_malloc/sk_free since SkOperand does not have a constructor/destructor - fSaveInterpolators[index] = cache; - memcpy(cache, interpolator.getValues(), count * sizeof(SkOperand)); -} - -void SkActive::setInterpolator(int index, SkOperand* from) { - if (from == nullptr) // legitimate for set string - return; - SkAnimateBase* animate = fAnimators[index]; - int entries = animate->entries(); - SkASSERT(entries > 0); - SkMSec duration = fState[index].fDuration; - int components = animate->components(); - SkOperandInterpolator& interpolator = *fInterpolators[index]; - interpolator.reset(components, entries == 1 ? 2 : entries, animate->getValuesType()); - interpolator.setMirror(SkToBool(animate->fMirror)); - interpolator.setReset(SkToBool(animate->fReset)); - interpolator.setRepeatCount(animate->repeat); - if (entries == 1) { - interpolator.setKeyFrame(0, 0, from, animate->blend[0]); - interpolator.setKeyFrame(1, duration, from, animate->blend[0]); - return; - } - for (int entry = 0; entry < entries; entry++) { - int blendIndex = SkMin32(animate->blend.count() - 1, entry); - interpolator.setKeyFrame(entry, entry * duration / (entries - 1), from, - animate->blend[blendIndex]); - from += components; - } -} - -void SkActive::setSteps(int steps) { - int count = fState.count(); - fMaxTime = 0; - for (int index = 0; index < count; index++) { - SkState& state = fState[index]; - state.fSteps = steps; - calcDurations(index); - } -} - -void SkActive::start() { - int count = fState.count(); - SkASSERT(count == fAnimators.count()); - SkASSERT(count == fInterpolators.count()); - for (int index = 0; index < count; index++) { - SkState& state = fState[index]; - if (state.fStarted) - continue; - state.fStarted = true; -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - SkString debugOut; - SkMSec time = fMaker.getAppTime(); - debugOut.appendS32(time - fMaker.fDebugTimeBase); - debugOut.append(" active start adjust delay id="); - debugOut.append(fApply._id); - debugOut.append("; "); - debugOut.append(fAnimators[index]->_id); - debugOut.append("="); - debugOut.appendS32(fAnimators[index]->fStart - fMaker.fDebugTimeBase); - debugOut.append(":"); - debugOut.appendS32(state.fStartTime); -#endif - if (state.fStartTime > 0) { - SkMSec future = fAnimators[index]->fStart + state.fStartTime; - if (future > fMaker.fEnableTime) - fMaker.notifyInvalTime(future); - else - fMaker.notifyInval(); -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - debugOut.append(":"); - debugOut.appendS32(future - fMaker.fDebugTimeBase); -#endif - } - if (state.fStartTime >= fMaker.fAdjustedStart) { - state.fStartTime -= fMaker.fAdjustedStart; -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - debugOut.append(" (less adjust = "); - debugOut.appendS32(fMaker.fAdjustedStart); -#endif - } - state.fStartTime += fAnimators[index]->fStart; -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - debugOut.append(") new start = "); - debugOut.appendS32(state.fStartTime - fMaker.fDebugTimeBase); - SkDebugf("%s\n", debugOut.c_str()); -// SkASSERT((int) (state.fStartTime - fMaker.fDebugTimeBase) >= 0); -#endif - } - SkASSERT(fAnimators.count() == fInterpolators.count()); -} - -#ifdef SK_DEBUG -void SkActive::validate() { - int count = fState.count(); - SkASSERT(count == fAnimators.count()); - SkASSERT(count == fInterpolators.count()); - for (int index = 0; index < count; index++) { - SkASSERT(fAnimators[index]); - SkASSERT(fInterpolators[index]); -// SkAnimateBase* test = fAnimators[index]; -// SkASSERT(fApply.scope == test->fTarget || fApply.scope->contains(test->fTarget)); - } -} -#endif - -// think about this -// there should only be one animate object, not two, to go up and down -// when the apply with reverse came into play, it needs to pick up the value -// of the existing animate object then remove it from the list -// the code below should only be bumping fSave, and there shouldn't be anything -// it needs to be synchronized with - -// however, if there are two animates both operating on the same field, then -// when one replaces the other, it may make sense to pick up the old value as a starting -// value for the new one somehow. - -//void SkActive::SkState::bumpSave() { -// if (fMode != SkApply::kMode_hold) -// return; -// if (fTransition == SkApply::kTransition_reverse) { -// if (fSave > 0) -// fSave -= SK_MSec1; -// } else if (fSave < fDuration) -// fSave += SK_MSec1; -//} - -SkMSec SkActive::SkState::getRelativeTime(SkMSec time) { - SkMSec result = time; -// if (fMode == SkApply::kMode_hold) -// result = fSave; -// else - if (fTransition == SkApply::kTransition_reverse) { - if (SkMSec_LT(fDuration, time)) - result = 0; - else - result = fDuration - time; - } - return result; -} diff --git a/gfx/skia/skia/src/animator/SkAnimateActive.h b/gfx/skia/skia/src/animator/SkAnimateActive.h deleted file mode 100644 index 2bc458bae0b3..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateActive.h +++ /dev/null @@ -1,79 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkAnimateActive_DEFINED -#define SkAnimateActive_DEFINED - -#include "SkDisplayApply.h" -#include "SkOperandInterpolator.h" -#include "SkIntArray.h" - -class SkAnimateMaker; - -class SkActive { -public: - SkActive(SkApply& , SkAnimateMaker& ); - ~SkActive(); - void advance(); - void append(SkApply* ); - void calcDurations(int index); - void create(SkADrawable* scope, SkMSec time); - bool draw() { return immediate(false); } - bool enable() { return immediate(true); } - void init( ); - SkMSec getTime(SkMSec inTime, int animatorIndex); - void pickUp(SkActive* existing); - void reset() { fDrawIndex = 0; } - void setInterpolator(int index, SkOperand* from); - void start(); -#ifdef SK_DEBUG - void validate(); -#endif -private: - void appendSave(int oldCount); - void fixInterpolator(SkBool save); - bool immediate(bool enable); - bool initializeSave(); - void initState(SkApply* , int offset); - void resetInterpolators(); - void resetState(); - void restoreInterpolatorValues(int index); - void saveInterpolatorValues(int index); - void setSteps(int steps); - struct SkState { -// void bumpSave(); - SkMSec getRelativeTime(SkMSec time); - SkApply::Mode fMode; - SkApply::Transition fTransition; - SkBool8 fPickup; - SkBool8 fRestore; - SkBool8 fStarted; - SkBool8 fUnpostedEndEvent; - int32_t fSteps; - SkMSec fBegin; - SkMSec fStartTime; - SkMSec fDuration; - SkMSec fSave; - SkMSec fTicks; - }; - SkActive& operator= (const SkActive& ); - SkTDArray fInterpolators; - SkApply& fApply; - SkTDArray fState; // one per animator - SkTDOperandPtrArray fSaveRestore; // if apply has restore="true" - SkTDOperandPtrArray fSaveInterpolators; - SkTDAnimateArray fAnimators; - SkMSec fMaxTime; // greatest of all animation durations; only used by immediate mode - SkAnimateMaker& fMaker; - int fDrawIndex; - int fDrawMax; - friend class SkApply; -}; - -#endif // SkAnimateActive_DEFINED diff --git a/gfx/skia/skia/src/animator/SkAnimateBase.cpp b/gfx/skia/skia/src/animator/SkAnimateBase.cpp deleted file mode 100644 index a4b2c64d1eb8..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateBase.cpp +++ /dev/null @@ -1,235 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkAnimateBase.h" -#include "SkAnimateMaker.h" -#include "SkAnimateProperties.h" -#include "SkAnimatorScript.h" -#include "SkDisplayApply.h" -#include "SkADrawable.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkAnimateBase::fInfo[] = { - SK_MEMBER(begin, MSec), - SK_MEMBER_ARRAY(blend, Float), - SK_MEMBER(dur, MSec), - SK_MEMBER_PROPERTY(dynamic, Boolean), - SK_MEMBER(field, String), // name of member info in target - SK_MEMBER(formula, DynamicString), - SK_MEMBER(from, DynamicString), - SK_MEMBER(lval, DynamicString), - SK_MEMBER_PROPERTY(mirror, Boolean), - SK_MEMBER(repeat, Float), - SK_MEMBER_PROPERTY(reset, Boolean), - SK_MEMBER_PROPERTY(step, Int), - SK_MEMBER(target, DynamicString), - SK_MEMBER(to, DynamicString), - SK_MEMBER_PROPERTY(values, DynamicString) -}; - -#endif - -DEFINE_GET_MEMBER(SkAnimateBase); - -SkAnimateBase::SkAnimateBase() : begin(0), dur(1), repeat(SK_Scalar1), - fApply(nullptr), fFieldInfo(nullptr), fFieldOffset(0), fStart((SkMSec) -1), fTarget(nullptr), - fChanged(0), fDelayed(0), fDynamic(0), fHasEndEvent(0), fHasValues(0), - fMirror(0), fReset(0), fResetPending(0), fTargetIsScope(0) { - blend.setCount(1); - blend[0] = SK_Scalar1; -} - -SkAnimateBase::~SkAnimateBase() { - SkDisplayTypes type = fValues.getType(); - if (type == SkType_String || type == SkType_DynamicString) { - SkASSERT(fValues.count() == 1); - delete fValues[0].fString; - } -} - -int SkAnimateBase::components() { - return 1; -} - -SkDisplayable* SkAnimateBase::deepCopy(SkAnimateMaker* maker) { - SkAnimateBase* result = (SkAnimateBase*) INHERITED::deepCopy(maker); - result->fApply = fApply; - result->fFieldInfo =fFieldInfo; - result->fHasValues = false; - return result; -} - -void SkAnimateBase::dirty() { - fChanged = true; -} - -#ifdef SK_DUMP_ENABLED -void SkAnimateBase::dump(SkAnimateMaker* maker) { - dumpBase(maker); - if (target.size() > 0) - SkDebugf("target=\"%s\" ", target.c_str()); - else if (fTarget && strcmp(fTarget->id, "")) - SkDebugf("target=\"%s\" ", fTarget->id); - if (lval.size() > 0) - SkDebugf("lval=\"%s\" ", lval.c_str()); - if (field.size() > 0) - SkDebugf("field=\"%s\" ", field.c_str()); - else if (fFieldInfo) - SkDebugf("field=\"%s\" ", fFieldInfo->fName); - if (formula.size() > 0) - SkDebugf("formula=\"%s\" ", formula.c_str()); - else { - if (from.size() > 0) - SkDebugf("from=\"%s\" ", from.c_str()); - SkDebugf("to=\"%s\" ", to.c_str()); - } - if (begin != 0) { - SkDebugf("begin=\"%g\" ", begin * 0.001); - } -} -#endif - -SkDisplayable* SkAnimateBase::getParent() const { - return (SkDisplayable*) fApply; -} - -bool SkAnimateBase::getProperty(int index, SkScriptValue* value) const { - int boolResult; - switch (index) { - case SK_PROPERTY(dynamic): - boolResult = fDynamic; - goto returnBool; - case SK_PROPERTY(mirror): - boolResult = fMirror; - goto returnBool; - case SK_PROPERTY(reset): - boolResult = fReset; -returnBool: - value->fOperand.fS32 = SkToBool(boolResult); - value->fType = SkType_Boolean; - break; - case SK_PROPERTY(step): - if (fApply == nullptr) - return false; // !!! notify there's an error? - fApply->getStep(value); - break; - case SK_PROPERTY(values): - value->fOperand.fString = (SkString*) &to; - value->fType = SkType_String; - break; - default: - SkASSERT(0); - return false; - } - return true; -} - -bool SkAnimateBase::hasExecute() const -{ - return false; -} - -void SkAnimateBase::onEndElement(SkAnimateMaker& maker) { - fChanged = false; - setTarget(maker); - if (field.size()) { - SkASSERT(fTarget); - fFieldInfo = fTarget->getMember(field.c_str()); - field.reset(); - } - if (lval.size()) { - // lval must be of the form x[y] - const char* lvalStr = lval.c_str(); - const char* arrayEnd = strchr(lvalStr, '['); - if (arrayEnd == nullptr) - return; //should this return an error? - size_t arrayNameLen = arrayEnd - lvalStr; - SkString arrayStr(lvalStr, arrayNameLen); - SkASSERT(fTarget); //this return an error? - fFieldInfo = fTarget->getMember(arrayStr.c_str()); - SkString scriptStr(arrayEnd + 1, lval.size() - arrayNameLen - 2); - SkAnimatorScript::EvaluateInt(maker, this, scriptStr.c_str(), &fFieldOffset); - } -} - -void SkAnimateBase::packARGB(SkScalar array[], int count, SkTDOperandArray* converted) -{ - SkASSERT(count == 4); - converted->setCount(1); - SkColor color = SkColorSetARGB(SkScalarRoundToInt(array[0]), - SkScalarRoundToInt(array[1]), - SkScalarRoundToInt(array[2]), - SkScalarRoundToInt(array[3])); - (*converted)[0].fS32 = color; -} - - - -void SkAnimateBase::refresh(SkAnimateMaker& ) { -} - -bool SkAnimateBase::setParent(SkDisplayable* apply) { - SkASSERT(apply->isApply()); - fApply = (SkApply*) apply; - return false; -} - -bool SkAnimateBase::setProperty(int index, SkScriptValue& value) { - bool boolValue = SkToBool(value.fOperand.fS32); - switch (index) { - case SK_PROPERTY(dynamic): - fDynamic = boolValue; - goto checkForBool; - case SK_PROPERTY(values): - fHasValues = true; - SkASSERT(value.fType == SkType_String); - to = *value.fOperand.fString; - break; - case SK_PROPERTY(mirror): - fMirror = boolValue; - goto checkForBool; - case SK_PROPERTY(reset): - fReset = boolValue; -checkForBool: - SkASSERT(value.fType == SkType_Boolean); - break; - default: - return false; - } - return true; -} - -void SkAnimateBase::setTarget(SkAnimateMaker& maker) { - if (target.size()) { - SkAnimatorScript engine(maker, this, SkType_Displayable); - const char* script = target.c_str(); - SkScriptValue scriptValue; - bool success = engine.evaluateScript(&script, &scriptValue); - if (success && scriptValue.fType == SkType_Displayable) - fTarget = scriptValue.fOperand.fDrawable; - else if (maker.find(target.c_str(), (SkDisplayable**) &fTarget) == false) { - if (fApply->getMode() == SkApply::kMode_create) - return; // may not be an error - if (engine.getError() != SkScriptEngine::kNoError) - maker.setScriptError(engine); - else { - maker.setErrorNoun(target); - maker.setErrorCode(SkDisplayXMLParserError::kTargetIDNotFound); - } - return; - } - if (fApply && fApply->getMode() != SkApply::kMode_create) - target.reset(); - } -} - -bool SkAnimateBase::targetNeedsInitialization() const { - return false; -} diff --git a/gfx/skia/skia/src/animator/SkAnimateBase.h b/gfx/skia/skia/src/animator/SkAnimateBase.h deleted file mode 100644 index 0da4af1173c3..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateBase.h +++ /dev/null @@ -1,83 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkAnimateBase_DEFINED -#define SkAnimateBase_DEFINED - -#include "SkDisplayable.h" -#include "SkMath.h" -#include "SkMemberInfo.h" -#include "SkTypedArray.h" - -class SkApply; -class SkADrawable; - -class SkAnimateBase : public SkDisplayable { -public: - DECLARE_MEMBER_INFO(AnimateBase); - SkAnimateBase(); - virtual ~SkAnimateBase(); - virtual int components(); - SkDisplayable* deepCopy(SkAnimateMaker* ) override; - void dirty() override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - int entries() { return fValues.count() / components(); } - virtual bool hasExecute() const; - bool isDynamic() const { return SkToBool(fDynamic); } - SkDisplayable* getParent() const override; - bool getProperty(int index, SkScriptValue* value) const override; - SkMSec getStart() const { return fStart; } - SkOperand* getValues() { return fValues.begin(); } - SkDisplayTypes getValuesType() { return fValues.getType(); } - void onEndElement(SkAnimateMaker& ) override; - void packARGB(SkScalar [], int count, SkTDOperandArray* ); - virtual void refresh(SkAnimateMaker& ); - void setChanged(bool changed) { fChanged = changed; } - void setHasEndEvent() { fHasEndEvent = true; } - bool setParent(SkDisplayable* ) override; - bool setProperty(int index, SkScriptValue& value) override; - void setTarget(SkAnimateMaker& ); - virtual bool targetNeedsInitialization() const; -protected: - SkMSec begin; - SkTDScalarArray blend; - SkMSec dur; - // !!! make field part of a union with fFieldInfo, or fValues, something known later? - SkString field; // temporary; once target is known, this is reset - SkString formula; - SkString from; - SkString lval; - SkScalar repeat; - SkString target; // temporary; once target is known, this is reset - SkString to; - SkApply* fApply; - const SkMemberInfo* fFieldInfo; - int fFieldOffset; - SkMSec fStart; // corrected time when this apply was enabled - SkADrawable* fTarget; - SkTypedArray fValues; - unsigned fChanged : 1; // true when value referenced by script has changed - unsigned fDelayed : 1; // enabled, but undrawn pending delay - unsigned fDynamic : 1; - unsigned fHasEndEvent : 1; - unsigned fHasValues : 1; // set if 'values' passed instead of 'to' - unsigned fMirror : 1; - unsigned fReset : 1; - unsigned fResetPending : 1; - unsigned fTargetIsScope : 1; -private: - typedef SkDisplayable INHERITED; - friend class SkActive; - friend class SkApply; - friend class SkDisplayList; -}; - -#endif // SkAnimateBase_DEFINED diff --git a/gfx/skia/skia/src/animator/SkAnimateField.cpp b/gfx/skia/skia/src/animator/SkAnimateField.cpp deleted file mode 100644 index 00113823eec3..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateField.cpp +++ /dev/null @@ -1,111 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkAnimate.h" -#include "SkAnimateMaker.h" -#include "SkADrawable.h" -#include "SkParse.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkAnimate::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkAnimate); - -SkAnimate::SkAnimate() : fComponents(0) { -} - -SkAnimate::~SkAnimate() { -} - -int SkAnimate::components() { - return fComponents; -} - -#ifdef SK_DUMP_ENABLED -void SkAnimate::dump(SkAnimateMaker* maker) { - INHERITED::dump(maker); //from animateBase - //SkSet inherits from this class - if (getType() != SkType_Set) { - if (fMirror) - SkDebugf("mirror=\"true\" "); - if (fReset) - SkDebugf("reset=\"true\" "); - SkDebugf("dur=\"%g\" ", dur * 0.001); - if (repeat != SK_Scalar1) - SkDebugf("repeat=\"%g\" ", SkScalarToFloat(repeat)); - //if (fHasValues) - // SkDebugf("values=\"%s\" ", values); - if (blend.count() != 1 || blend[0] != SK_Scalar1) { - SkDebugf("blend=\"["); - bool firstElem = true; - for (int i = 0; i < blend.count(); i++) { - if (!firstElem) - SkDebugf(","); - firstElem = false; - SkDebugf("%g", SkScalarToFloat(blend[i])); - } - SkDebugf("]\" "); - } - SkDebugf("/>\n");//i assume that if it IS, we will do it separately - } -} -#endif - -bool SkAnimate::resolveCommon(SkAnimateMaker& maker) { - if (fTarget == nullptr) // if nullptr, recall onEndElement after apply closes and sets target to scope - return false; - INHERITED::onEndElement(maker); - return maker.hasError() == false; -} - -void SkAnimate::onEndElement(SkAnimateMaker& maker) { - bool resolved = resolveCommon(maker); - if (resolved && fFieldInfo == nullptr) { - maker.setErrorNoun(field); - maker.setErrorCode(SkDisplayXMLParserError::kFieldNotInTarget); - } - if (resolved == false || fFieldInfo == nullptr) - return; - SkDisplayTypes outType = fFieldInfo->getType(); - if (fHasValues) { - SkASSERT(to.size() > 0); - fFieldInfo->setValue(maker, &fValues, 0, 0, nullptr, outType, to); - SkASSERT(0); - // !!! this needs to set fComponents - return; - } - fComponents = fFieldInfo->getCount(); - if (fFieldInfo->fType == SkType_Array) { - SkTypedArray* array = (SkTypedArray*) fFieldInfo->memberData(fTarget); - int count = array->count(); - if (count > 0) - fComponents = count; - } - if (outType == SkType_ARGB) { - fComponents <<= 2; // four color components - outType = SkType_Float; - } - fValues.setType(outType); - if (formula.size() > 0){ - fComponents = 1; - from.set("0"); - to.set("dur"); - outType = SkType_MSec; - } - int max = fComponents * 2; - fValues.setCount(max); - memset(fValues.begin(), 0, max * sizeof(fValues.begin()[0])); - fFieldInfo->setValue(maker, &fValues, fFieldOffset, max, this, outType, from); - fFieldInfo->setValue(maker, &fValues, fComponents + fFieldOffset, max, this, outType, to); -} diff --git a/gfx/skia/skia/src/animator/SkAnimateMaker.cpp b/gfx/skia/skia/src/animator/SkAnimateMaker.cpp deleted file mode 100644 index 066f877a9b50..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateMaker.cpp +++ /dev/null @@ -1,372 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkAnimateMaker.h" -#include "SkAnimator.h" -#include "SkAnimatorScript.h" -#include "SkDisplayable.h" -#include "SkDisplayApply.h" -#include "SkDisplayList.h" -#include "SkDisplayMovie.h" -#include "SkDisplayType.h" -#include "SkExtras.h" -#include "SkMemberInfo.h" -#include "SkStream.h" -#include "SkSystemEventTypes.h" -#include "SkTime.h" - -class DefaultTimeline : public SkAnimator::Timeline { - virtual SkMSec getMSecs() const { - return SkEvent::GetMSecsSinceStartup(); - } -} gDefaultTimeline; - -SkAnimateMaker::SkAnimateMaker(SkAnimator* animator, SkCanvas* canvas, SkPaint* paint) - : fActiveEvent(nullptr), fAdjustedStart(0), fCanvas(canvas), fEnableTime(0), - fHostEventSinkID(0), fMinimumInterval((SkMSec) -1), fPaint(paint), fParentMaker(nullptr), - fTimeline(&gDefaultTimeline), fInInclude(false), fInMovie(false), - fFirstScriptError(false), fLoaded(false), fIDs(256), fAnimator(animator) -{ - fScreenplay.time = 0; -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - fDebugTimeBase = (SkMSec) -1; -#endif -#ifdef SK_DUMP_ENABLED - fDumpEvents = fDumpGConditions = fDumpPosts = false; -#endif -} - -SkAnimateMaker::~SkAnimateMaker() { - deleteMembers(); -} - -#if 0 -SkMSec SkAnimateMaker::adjustDelay(SkMSec expectedBase, SkMSec delay) { - SkMSec appTime = (*fTimeCallBack)(); - if (appTime) - delay -= appTime - expectedBase; - if (delay < 0) - delay = 0; - return delay; -} -#endif - -void SkAnimateMaker::appendActive(SkActive* active) { - fDisplayList.append(active); -} - -void SkAnimateMaker::clearExtraPropertyCallBack(SkDisplayTypes type) { - SkExtras** end = fExtras.end(); - for (SkExtras** extraPtr = fExtras.begin(); extraPtr < end; extraPtr++) { - SkExtras* extra = *extraPtr; - if (extra->definesType(type)) { - extra->fExtraCallBack = nullptr; - extra->fExtraStorage = nullptr; - break; - } - } -} - -bool SkAnimateMaker::computeID(SkDisplayable* displayable, SkDisplayable* parent, SkString* newID) { - const char* script; - if (findKey(displayable, &script) == false) - return true; - return SkAnimatorScript::EvaluateString(*this, displayable, parent, script, newID); -} - -SkDisplayable* SkAnimateMaker::createInstance(const char name[], size_t len) { - SkDisplayTypes type = SkDisplayType::GetType(this, name, len ); - if ((int)type >= 0) - return SkDisplayType::CreateInstance(this, type); - return nullptr; -} - -// differs from SkAnimator::decodeStream in that it does not reset error state -bool SkAnimateMaker::decodeStream(SkStream* stream) -{ - SkDisplayXMLParser parser(*this); - return parser.parse(*stream); -} - -// differs from SkAnimator::decodeURI in that it does not set URI base -bool SkAnimateMaker::decodeURI(const char uri[]) { -// SkDebugf("animator decode %s\n", uri); - -// SkStream* stream = SkStream::GetURIStream(fPrefix.c_str(), uri); - std::unique_ptr stream = SkStream::MakeFromFile(uri); - if (stream) { - bool success = decodeStream(stream.get()); - if (hasError() && fError.hasNoun() == false) - fError.setNoun(uri); - return success; - } else { - return false; - } -} - -#if defined SK_DEBUG && 0 -//used for the if'd out section of deleteMembers -#include "SkTSearch.h" - -extern "C" { - int compare_disp(const void* a, const void* b) { - return *(const SkDisplayable**)a - *(const SkDisplayable**)b; - } -} -#endif - -void SkAnimateMaker::delayEnable(SkApply* apply, SkMSec time) { - int index = fDelayed.find(apply); - if (index < 0) { - *fDelayed.append() = apply; - } - - (new SkEvent(SK_EventType_Delay, fAnimator->getSinkID()))->postTime(time); -} - -void SkAnimateMaker::deleteMembers() { - int index; -#if defined SK_DEBUG && 0 - //this code checks to see if helpers are among the children, but it is not complete - - //it should check the children of the children - int result; - SkTDArray children(fChildren.begin(), fChildren.count()); - SkQSort(children.begin(), children.count(), sizeof(SkDisplayable*),compare_disp); - for (index = 0; index < fHelpers.count(); index++) { - SkDisplayable* helper = fHelpers[index]; - result = SkTSearch(children.begin(), children.count(), helper, sizeof(SkDisplayable*)); - SkASSERT(result < 0); - } -#endif - for (index = 0; index < fChildren.count(); index++) { - SkDisplayable* child = fChildren[index]; - delete child; - } - for (index = 0; index < fHelpers.count(); index++) { - SkDisplayable* helper = fHelpers[index]; - delete helper; - } - for (index = 0; index < fExtras.count(); index++) { - SkExtras* extras = fExtras[index]; - delete extras; - } -} - -void SkAnimateMaker::doDelayedEvent() { - fEnableTime = getAppTime(); - for (int index = 0; index < fDelayed.count(); ) { - SkDisplayable* child = fDelayed[index]; - SkASSERT(child->isApply()); - SkApply* apply = (SkApply*) child; - apply->interpolate(*this, fEnableTime); - if (apply->hasDelayedAnimator()) - index++; - else - fDelayed.remove(index); - } -} - -bool SkAnimateMaker::doEvent(const SkEvent& event) { - return (!fInMovie || fLoaded) && fAnimator->doEvent(event); -} - -#ifdef SK_DUMP_ENABLED -void SkAnimateMaker::dump(const char* match) { - SkTDict::Iter iter(fIDs); - const char* name; - SkDisplayable* result; - while ((name = iter.next(&result)) != nullptr) { - if (strcmp(match,name) == 0) - result->dump(this); - } -} -#endif - -int SkAnimateMaker::dynamicProperty(SkString& nameStr, SkDisplayable** displayablePtr ) { - const char* name = nameStr.c_str(); - const char* dot = strchr(name, '.'); - SkASSERT(dot); - SkDisplayable* displayable; - if (find(name, dot - name, &displayable) == false) { - SkASSERT(0); - return 0; - } - const char* fieldName = dot + 1; - const SkMemberInfo* memberInfo = displayable->getMember(fieldName); - *displayablePtr = displayable; - return (int) memberInfo->fOffset; -} - -SkMSec SkAnimateMaker::getAppTime() const { - return fTimeline->getMSecs(); -} - -#ifdef SK_DEBUG -SkAnimator* SkAnimateMaker::getRoot() -{ - SkAnimateMaker* maker = this; - while (maker->fParentMaker) - maker = maker->fParentMaker; - return maker == this ? nullptr : maker->fAnimator; -} -#endif - -void SkAnimateMaker::helperAdd(SkDisplayable* trackMe) { - SkASSERT(fHelpers.find(trackMe) < 0); - *fHelpers.append() = trackMe; -} - -void SkAnimateMaker::helperRemove(SkDisplayable* alreadyTracked) { - int helperIndex = fHelpers.find(alreadyTracked); - if (helperIndex >= 0) - fHelpers.remove(helperIndex); -} - -#if 0 -void SkAnimateMaker::loadMovies() { - for (SkDisplayable** dispPtr = fMovies.begin(); dispPtr < fMovies.end(); dispPtr++) { - SkDisplayable* displayable = *dispPtr; - SkASSERT(displayable->getType() == SkType_Movie); - SkDisplayMovie* movie = (SkDisplayMovie*) displayable; - SkAnimateMaker* movieMaker = movie->fMovie.fMaker; - movieMaker->fEvents.doEvent(*movieMaker, SkDisplayEvent::kOnload, nullptr); - movieMaker->fEvents.removeEvent(SkDisplayEvent::kOnload, nullptr); - movieMaker->loadMovies(); - } -} -#endif - -void SkAnimateMaker::notifyInval() { - if (fHostEventSinkID) - fAnimator->onEventPost(new SkEvent(SK_EventType_Inval), fHostEventSinkID); -} - -void SkAnimateMaker::notifyInvalTime(SkMSec time) { - if (fHostEventSinkID) - fAnimator->onEventPostTime(new SkEvent(SK_EventType_Inval), fHostEventSinkID, time); -} - -void SkAnimateMaker::postOnEnd(SkAnimateBase* animate, SkMSec end) { - SkEvent evt; - evt.setS32("time", animate->getStart() + end); - evt.setPtr("anim", animate); - evt.setType(SK_EventType_OnEnd); - SkEventSinkID sinkID = fAnimator->getSinkID(); - fAnimator->onEventPost(new SkEvent(evt), sinkID); -} - -void SkAnimateMaker::reset() { - deleteMembers(); - fChildren.reset(); - fHelpers.reset(); - fIDs.reset(); - fEvents.reset(); - fDisplayList.hardReset(); -} - -void SkAnimateMaker::removeActive(SkActive* active) { - if (active == nullptr) - return; - fDisplayList.remove(active); -} - -bool SkAnimateMaker::resolveID(SkDisplayable* displayable, SkDisplayable* original) { - SkString newID; - bool success = computeID(original, nullptr, &newID); - if (success) - setID(displayable, newID); - return success; -} - -void SkAnimateMaker::setErrorString() { - fErrorString.reset(); - if (fError.hasError()) { - SkString err; - if (fFileName.size() > 0) - fErrorString.set(fFileName.c_str()); - else - fErrorString.set("screenplay error"); - int line = fError.getLineNumber(); - if (line >= 0) { - fErrorString.append(", "); - fErrorString.append("line "); - fErrorString.appendS32(line); - } - fErrorString.append(": "); - fError.getErrorString(&err); - fErrorString.append(err); -#if defined SK_DEBUG - SkDebugf("%s\n", fErrorString.c_str()); -#endif - } -} - -void SkAnimateMaker::setEnableTime(SkMSec appTime, SkMSec expectedTime) { -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - SkString debugOut; - SkMSec time = getAppTime(); - debugOut.appendS32(time - fDebugTimeBase); - debugOut.append(" set enable old enable="); - debugOut.appendS32(fEnableTime - fDebugTimeBase); - debugOut.append(" old adjust="); - debugOut.appendS32(fAdjustedStart); - debugOut.append(" new enable="); - debugOut.appendS32(expectedTime - fDebugTimeBase); - debugOut.append(" new adjust="); - debugOut.appendS32(appTime - expectedTime); - SkDebugf("%s\n", debugOut.c_str()); -#endif - fAdjustedStart = appTime - expectedTime; - fEnableTime = expectedTime; - SkDisplayable** firstMovie = fMovies.begin(); - SkDisplayable** endMovie = fMovies.end(); - for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) { - SkDisplayMovie* movie = (SkDisplayMovie*) *ptr; - movie->fMovie.fMaker->setEnableTime(appTime, expectedTime); - } -} - -void SkAnimateMaker::setExtraPropertyCallBack(SkDisplayTypes type, - SkScriptEngine::_propertyCallBack callBack, void* userStorage) { - SkExtras** end = fExtras.end(); - for (SkExtras** extraPtr = fExtras.begin(); extraPtr < end; extraPtr++) { - SkExtras* extra = *extraPtr; - if (extra->definesType(type)) { - extra->fExtraCallBack = callBack; - extra->fExtraStorage = userStorage; - break; - } - } -} - -void SkAnimateMaker::setID(SkDisplayable* displayable, const SkString& newID) { - fIDs.set(newID.c_str(), displayable); -#ifdef SK_DEBUG - displayable->_id.set(newID); - displayable->id = displayable->_id.c_str(); -#endif -} - -void SkAnimateMaker::setScriptError(const SkScriptEngine& engine) { - SkString errorString; -#ifdef SK_DEBUG - engine.getErrorString(&errorString); -#endif - setErrorNoun(errorString); - setErrorCode(SkDisplayXMLParserError::kErrorInScript); -} - -bool SkAnimateMaker::GetStep(const char* token, size_t len, void* stepPtr, SkScriptValue* value) { - if (SK_LITERAL_STR_EQUAL("step", token, len)) { - value->fOperand.fS32 = *(int32_t*) stepPtr; - value->fType = SkType_Int; - return true; - } - return false; -} diff --git a/gfx/skia/skia/src/animator/SkAnimateMaker.h b/gfx/skia/skia/src/animator/SkAnimateMaker.h deleted file mode 100644 index 035affa56117..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateMaker.h +++ /dev/null @@ -1,160 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkAnimateMaker_DEFINED -#define SkAnimateMaker_DEFINED - -// #define SK_DEBUG_ANIMATION_TIMING - -#include "SkAnimator.h" -#include "SkBitmap.h" -#include "SkIntArray.h" -#include "SkDisplayEvents.h" -#include "SkDisplayList.h" -#include "SkDisplayScreenplay.h" -#include "SkDisplayXMLParser.h" -#include "SkScript.h" -#include "SkString.h" -#include "SkTDict.h" - -// not sure where this little helper macro should go - - -class SkActive; -class SkAnimate; -class SkCanvas; -class SkDisplayable; -class SkADrawable; -class SkDump; -class SkEvent; -class SkEventSink; -class SkExtras; -class SkGroup; -class SkPaint; -class SkStream; - -class SkAnimateMaker { -public: - SkAnimateMaker(SkAnimator* animator, SkCanvas* canvas, SkPaint* paint); - ~SkAnimateMaker(); - void appendActive(SkActive* ); - void childrenAdd(SkDisplayable* child) { *fChildren.append() = child; } - void clearExtraPropertyCallBack(SkDisplayTypes type); - bool computeID(SkDisplayable* displayable, SkDisplayable* parent, SkString* newID); - SkDisplayable* createInstance(const char name[], size_t len); - bool decodeStream(SkStream* stream); - bool decodeURI(const char uri[]); - void delayEnable(SkApply* apply, SkMSec time); - void doDelayedEvent(); - bool doEvent(const SkEvent& event); -#ifdef SK_DUMP_ENABLED - void dump(const char* match); -#endif - int dynamicProperty(SkString& nameStr, SkDisplayable** ); - bool find(const char* str, SkDisplayable** displayablePtr) const { - return fIDs.find(str, displayablePtr); - } - bool find(const char* str, size_t len, SkDisplayable** displayablePtr) const { - return fIDs.find(str, len, displayablePtr); - } - bool findKey(SkDisplayable* displayable, const char** string) const { - return fIDs.findKey(displayable, string); - } -// bool find(SkString& string, SkDisplayable** displayablePtr) { -// return fIDs.find(string.c_str(), displayablePtr); -// } - SkAnimator* getAnimator() { return fAnimator; } - SkMSec getAppTime() const; // call caller to get current time -#ifdef SK_DEBUG - SkAnimator* getRoot(); -#endif - SkXMLParserError::ErrorCode getErrorCode() const { return fError.getErrorCode(); } - SkMSec getInTime() { return fDisplayList.getTime(); } - int getNativeCode() const { return fError.getNativeCode(); } - bool hasError() { return fError.hasError(); } - void helperAdd(SkDisplayable* trackMe); - void helperRemove(SkDisplayable* alreadyTracked); - void idsSet(const char* attrValue, size_t len, SkDisplayable* displayable) { - fIDs.set(attrValue, len, displayable); } -// void loadMovies(); - void notifyInval(); - void notifyInvalTime(SkMSec time); - void postOnEnd(SkAnimateBase* animate, SkMSec end); - void removeActive(SkActive* ); - void reset(); - bool resolveID(SkDisplayable* displayable, SkDisplayable* original); - void setEnableTime(SkMSec appTime, SkMSec expectedTime); - void setErrorCode(SkXMLParserError::ErrorCode err) { if (fError.hasError() == false) fError.INHERITED::setCode(err); } - void setErrorCode(SkDisplayXMLParserError::ErrorCode err) { if (fError.hasError() == false) fError.setCode(err); } - void setErrorNoun(const SkString& str) { if (fError.hasError() == false) fError.setNoun(str); } - void setErrorString(); - void setExtraPropertyCallBack(SkDisplayTypes type, SkScriptEngine::_propertyCallBack , void* userStorage); - void setID(SkDisplayable* displayable, const SkString& newID); - void setInnerError(SkAnimateMaker* maker, const SkString& str) { fError.setInnerError(maker, str); } - void setScriptError(const SkScriptEngine& ); -#ifdef SK_DEBUG - void validate() { fDisplayList.validate(); } -#else - void validate() {} -#endif - SkDisplayEvent* fActiveEvent; - SkMSec fAdjustedStart; - SkCanvas* fCanvas; - SkMSec fEnableTime; - int fEndDepth; // passed parameter to onEndElement - SkEvents fEvents; - SkDisplayList fDisplayList; - SkEventSinkID fHostEventSinkID; - SkMSec fMinimumInterval; - SkPaint* fPaint; - SkAnimateMaker* fParentMaker; - SkString fPrefix; - SkDisplayScreenplay fScreenplay; - const SkAnimator::Timeline* fTimeline; - SkBool8 fInInclude; - SkBool8 fInMovie; - SkBool8 fFirstScriptError; -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - SkMSec fDebugTimeBase; -#endif -#ifdef SK_DUMP_ENABLED - SkString fDumpAnimated; - SkBool8 fDumpEvents; - SkBool8 fDumpGConditions; - SkBool8 fDumpPosts; -#endif -private: - void deleteMembers(); - static bool GetStep(const char* token, size_t len, void* stepPtr, SkScriptValue* ); - SkAnimateMaker& operator=(SkAnimateMaker& ); - SkTDDisplayableArray fChildren; - SkTDDisplayableArray fDelayed; // SkApply that contain delayed enable events - SkDisplayXMLParserError fError; - SkString fErrorString; - SkTDArray fExtras; - SkString fFileName; - SkTDDisplayableArray fHelpers; // helper displayables - SkBool8 fLoaded; - SkTDDisplayableArray fMovies; - SkTDict fIDs; - SkAnimator* fAnimator; - friend class SkAdd; - friend class SkAnimateBase; - friend class SkDisplayXMLParser; - friend class SkAnimator; - friend class SkAnimatorScript; - friend class SkApply; - friend class SkDisplayMovie; - friend class SkDisplayType; - friend class SkEvents; - friend class SkGroup; - friend struct SkMemberInfo; -}; - -#endif // SkAnimateMaker_DEFINED diff --git a/gfx/skia/skia/src/animator/SkAnimateProperties.h b/gfx/skia/skia/src/animator/SkAnimateProperties.h deleted file mode 100644 index b0706405ac55..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateProperties.h +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkAnimateProperties_DEFINED -#define SkAnimateProperties_DEFINED - -enum SkAnimateBase_Properties { - SK_PROPERTY(dynamic), - SK_PROPERTY(mirror), - SK_PROPERTY(reset), - SK_PROPERTY(step), - SK_PROPERTY(values) -}; - -#endif // SkAnimateProperties_DEFINED diff --git a/gfx/skia/skia/src/animator/SkAnimateSchema.xsd b/gfx/skia/skia/src/animator/SkAnimateSchema.xsd deleted file mode 100644 index f7af332cfabc..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateSchema.xsd +++ /dev/null @@ -1,2787 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gfx/skia/skia/src/animator/SkAnimateSchema.xsx b/gfx/skia/skia/src/animator/SkAnimateSchema.xsx deleted file mode 100644 index ceb7d890c9a2..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateSchema.xsx +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/gfx/skia/skia/src/animator/SkAnimateSet.cpp b/gfx/skia/skia/src/animator/SkAnimateSet.cpp deleted file mode 100644 index c05e0299d83c..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateSet.cpp +++ /dev/null @@ -1,87 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkAnimateSet.h" -#include "SkAnimateMaker.h" -#include "SkAnimateProperties.h" -#include "SkParse.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkSet::fInfo[] = { - SK_MEMBER(begin, MSec), - SK_MEMBER(dur, MSec), - SK_MEMBER_PROPERTY(dynamic, Boolean), - SK_MEMBER(field, String), -// SK_MEMBER(formula, DynamicString), - SK_MEMBER(lval, DynamicString), -// SK_MEMBER_PROPERTY(reset, Boolean), - SK_MEMBER_PROPERTY(step, Int), - SK_MEMBER(target, DynamicString), - SK_MEMBER(to, DynamicString) -}; - -#endif - -DEFINE_GET_MEMBER(SkSet); - -SkSet::SkSet() { - dur = 1; -} - -#ifdef SK_DUMP_ENABLED -void SkSet::dump(SkAnimateMaker* maker) { - INHERITED::dump(maker); - if (dur != 1) { - SkDebugf("dur=\"%g\" ", dur * 0.001); - } - //don't want double />\n's - SkDebugf("/>\n"); - -} -#endif - -void SkSet::refresh(SkAnimateMaker& maker) { - fFieldInfo->setValue(maker, &fValues, 0, fFieldInfo->fCount, nullptr, - fFieldInfo->getType(), to); -} - -void SkSet::onEndElement(SkAnimateMaker& maker) { - if (resolveCommon(maker) == false) - return; - if (fFieldInfo == nullptr) { - maker.setErrorCode(SkDisplayXMLParserError::kFieldNotInTarget); - return; - } - fReset = dur != 1; - SkDisplayTypes outType = fFieldInfo->getType(); - int comps = outType == SkType_String || outType == SkType_DynamicString ? 1 : - (int)fFieldInfo->getSize((const SkDisplayable*) fTarget) / sizeof(int); - if (fValues.getType() == SkType_Unknown) { - fValues.setType(outType); - fValues.setCount(comps); - if (outType == SkType_String || outType == SkType_DynamicString) - fValues[0].fString = new SkString; - else - memset(fValues.begin(), 0, fValues.count() * sizeof(fValues.begin()[0])); - } else { - SkASSERT(fValues.getType() == outType); - if (fFieldInfo->fType == SkType_Array) - comps = fValues.count(); - else { - SkASSERT(fValues.count() == comps); - } - } - if (formula.size() > 0) { - comps = 1; - outType = SkType_MSec; - } - fFieldInfo->setValue(maker, &fValues, fFieldOffset, comps, this, outType, formula.size() > 0 ? formula : to); - fComponents = fValues.count(); -} diff --git a/gfx/skia/skia/src/animator/SkAnimateSet.h b/gfx/skia/skia/src/animator/SkAnimateSet.h deleted file mode 100644 index 32a91979e7ac..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimateSet.h +++ /dev/null @@ -1,27 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkAnimateSet_DEFINED -#define SkAnimateSet_DEFINED - -#include "SkAnimate.h" - -class SkSet : public SkAnimate { - DECLARE_MEMBER_INFO(Set); - SkSet(); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - void onEndElement(SkAnimateMaker& ) override; - void refresh(SkAnimateMaker& ) override; -private: - typedef SkAnimate INHERITED; -}; - -#endif // SkAnimateSet_DEFINED diff --git a/gfx/skia/skia/src/animator/SkAnimator.cpp b/gfx/skia/skia/src/animator/SkAnimator.cpp deleted file mode 100644 index c5aabbba4bdc..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimator.cpp +++ /dev/null @@ -1,704 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkAnimator.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkDisplayApply.h" -#include "SkDisplayMovie.h" -#include "SkDisplayTypes.h" -#include "SkDisplayXMLParser.h" -#include "SkStream.h" -#include "SkScript.h" -#include "SkScript2.h" // compiled script experiment -#include "SkSystemEventTypes.h" -#include "SkTypedArray.h" -#ifdef SK_BUILD_FOR_ANDROID -#include "SkDrawExtraPathEffect.h" -#endif -#ifdef SK_DEBUG -#include "SkTime.h" -#endif - -#if defined SK_BUILD_FOR_WIN32 && defined SK_DEBUG - #define _static - extern const char gMathPrimerText[]; - extern const char gMathPrimerBinary[]; -#else - #define _static static -#endif - -_static const char gMathPrimerText[] = -"" - "" - "" -""; - -#define gMathPrimer gMathPrimerText - -SkAnimator::SkAnimator() : fMaker(nullptr) { - initialize(); -} - -SkAnimator::~SkAnimator() { delete fMaker; } - -void SkAnimator::addExtras(SkExtras* extras) { - *fMaker->fExtras.append() = extras; -} - -bool SkAnimator::appendStream(SkStream* stream) { - return decodeStream(stream); -} - -bool SkAnimator::decodeMemory(const void* buffer, size_t size) -{ - fMaker->fFileName.reset(); - SkDisplayXMLParser parser(*fMaker); - return parser.parse((const char*)buffer, size); -} - -bool SkAnimator::decodeStream(SkStream* stream) -{ - SkDisplayXMLParser parser(*fMaker); - bool result = parser.parse(*stream); - fMaker->setErrorString(); - return result; -} - -bool SkAnimator::decodeDOM(const SkDOM& dom, const SkDOMNode* node) -{ - fMaker->fFileName.reset(); - SkDisplayXMLParser parser(*fMaker); - return parser.parse(dom, node); -} - -bool SkAnimator::decodeURI(const char uri[]) { -// SkDebugf("animator decode %s\n", uri); - -// SkStream* stream = SkStream::GetURIStream(fMaker->fPrefix.c_str(), uri); - std::unique_ptr stream = SkStream::MakeFromFile(uri); - if (stream) { - this->setURIBase(uri); - return decodeStream(stream.get()); - } else { - return false; - } -} - -bool SkAnimator::doCharEvent(SkUnichar code) { - if (code == 0) - return false; - struct SkEventState state; - state.fCode = code; - fMaker->fEnableTime = fMaker->getAppTime(); - bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyChar, &state); - fMaker->notifyInval(); - return result; -} - -bool SkAnimator::doClickEvent(int clickState, SkScalar x, SkScalar y) { - SkASSERT(clickState >= 0 && clickState <= 2); - struct SkEventState state; - state.fX = x; - state.fY = y; - fMaker->fEnableTime = fMaker->getAppTime(); - bool result = fMaker->fEvents.doEvent(*fMaker, - clickState == 0 ? SkDisplayEvent::kMouseDown : - clickState == 1 ? SkDisplayEvent::kMouseDrag : - SkDisplayEvent::kMouseUp, &state); - fMaker->notifyInval(); - return result; -} - -bool SkAnimator::doKeyEvent(SkKey code) { - if (code == 0) - return false; - struct SkEventState state; - state.fCode = code; - fMaker->fEnableTime = fMaker->getAppTime(); - bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyPress, &state); - fMaker->notifyInval(); - return result; -} - -bool SkAnimator::doKeyUpEvent(SkKey code) { - if (code == 0) - return false; - struct SkEventState state; - state.fCode = code; - fMaker->fEnableTime = fMaker->getAppTime(); - bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyPressUp, &state); - fMaker->notifyInval(); - return result; -} - -bool SkAnimator::doUserEvent(const SkEvent& evt) { - fMaker->fEnableTime = fMaker->getAppTime(); - return onEvent(evt); -} - -SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkPaint* paint, SkMSec time) { - if (paint == nullptr) - return draw(canvas, time); - fMaker->fScreenplay.time = time; - fMaker->fCanvas = canvas; - fMaker->fPaint = paint; - fMaker->fDisplayList.fHasUnion = false; - int result = fMaker->fDisplayList.draw(*fMaker, time); - if (result) - result += fMaker->fDisplayList.fHasUnion; - return (DifferenceType) result; -} - -SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkMSec time) { - SkPaint paint; - return draw(canvas, &paint, time); -} - -#ifdef SK_DEBUG -void SkAnimator::eventDone(const SkEvent& ) { -} -#endif - -bool SkAnimator::findClickEvent(SkScalar x, SkScalar y) { - struct SkEventState state; - state.fDisable = true; - state.fX = x; - state.fY = y; - fMaker->fEnableTime = fMaker->getAppTime(); - bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kMouseDown, &state); - fMaker->notifyInval(); - return result; -} - -const SkAnimator* SkAnimator::getAnimator(const SkDisplayable* displayable) const { - if (displayable->getType() != SkType_Movie) - return nullptr; - const SkDisplayMovie* movie = (const SkDisplayMovie*) displayable; - return movie->getAnimator(); -} - -const SkDisplayable* SkAnimator::getElement(const char* id) { - SkDisplayable* element; - if (fMaker->find(id, &element) == false) - return nullptr; - return (const SkDisplayable*) element; -} - -SkElementType SkAnimator::getElementType(const SkDisplayable* ae) { - SkDisplayable* element = (SkDisplayable*) ae; - const SkMemberInfo* info = SkDisplayType::GetMembers(fMaker, element->getType(), nullptr); - return (SkElementType) SkDisplayType::Find(fMaker, info); -} - -SkElementType SkAnimator::getElementType(const char* id) { - const SkDisplayable* element = getElement(id); - return getElementType(element); -} - -const SkMemberInfo* SkAnimator::getField(const SkDisplayable* ae, const char* field) { - SkDisplayable* element = (SkDisplayable*) ae; - const SkMemberInfo* info = element->getMember(field); - return (const SkMemberInfo*) info; -} - -const SkMemberInfo* SkAnimator::getField(const char* elementID, const char* field) { - const SkDisplayable* element = getElement(elementID); - return getField(element, field); -} - -SkFieldType SkAnimator::getFieldType(const SkMemberInfo* ai) { - const SkMemberInfo* info = (const SkMemberInfo*) ai; - return (SkFieldType) info->getType(); -} - -SkFieldType SkAnimator::getFieldType(const char* id, const char* fieldID) { - const SkMemberInfo* field = getField(id, fieldID); - return getFieldType(field); -} - -static bool getArrayCommon(const SkDisplayable* ae, const SkMemberInfo* ai, - int index, SkOperand* operand) { - const SkDisplayable* element = (const SkDisplayable*) ae; - const SkMemberInfo* info = (const SkMemberInfo*) ai; - SkASSERT(info->fType == SkType_Array); - return info->getArrayValue(element, index, operand); -} - -int32_t SkAnimator::getArrayInt(const SkDisplayable* ae, - const SkMemberInfo* ai, int index) { - SkOperand operand; - bool result = getArrayCommon(ae, ai, index, &operand); - return result ? operand.fS32 : SK_NaN32; -} - -int32_t SkAnimator::getArrayInt(const char* id, const char* fieldID, int index) { - const SkDisplayable* element = getElement(id); - if (element == nullptr) - return SK_NaN32; - const SkMemberInfo* field = getField(element, fieldID); - if (field == nullptr) - return SK_NaN32; - return getArrayInt(element, field, index); -} - -SkScalar SkAnimator::getArrayScalar(const SkDisplayable* ae, - const SkMemberInfo* ai, int index) { - SkOperand operand; - bool result = getArrayCommon(ae, ai, index, &operand); - return result ? operand.fScalar : SK_ScalarNaN; -} - -SkScalar SkAnimator::getArrayScalar(const char* id, const char* fieldID, int index) { - const SkDisplayable* element = getElement(id); - if (element == nullptr) - return SK_ScalarNaN; - const SkMemberInfo* field = getField(element, fieldID); - if (field == nullptr) - return SK_ScalarNaN; - return getArrayScalar(element, field, index); -} - -const char* SkAnimator::getArrayString(const SkDisplayable* ae, - const SkMemberInfo* ai, int index) { - SkOperand operand; - bool result = getArrayCommon(ae, ai, index, &operand); - return result ? operand.fString->c_str() : nullptr; -} - -const char* SkAnimator::getArrayString(const char* id, const char* fieldID, int index) { - const SkDisplayable* element = getElement(id); - if (element == nullptr) - return nullptr; - const SkMemberInfo* field = getField(element, fieldID); - if (field == nullptr) - return nullptr; - return getArrayString(element, field, index); -} - -SkMSec SkAnimator::getInterval() { - return fMaker->fMinimumInterval == (SkMSec) -1 ? 0 : fMaker->fMinimumInterval; -} - -void SkAnimator::getInvalBounds(SkRect* inval) { - if (fMaker->fDisplayList.fHasUnion) { - inval->fLeft = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fLeft); - inval->fTop = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fTop); - inval->fRight = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fRight); - inval->fBottom = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fBottom); - } else { - inval->fLeft = inval->fTop = -SK_ScalarMax; - inval->fRight = inval->fBottom = SK_ScalarMax; - } -} - -const SkXMLParserError* SkAnimator::getParserError() { - return &fMaker->fError; -} - -const char* SkAnimator::getParserErrorString() { - if (fMaker->fErrorString.size() == 0 && fMaker->fError.hasError()) - fMaker->setErrorString(); - return fMaker->fErrorString.c_str(); -} - -int32_t SkAnimator::getInt(const SkDisplayable* element, const SkMemberInfo* info) { - if (info->fType != SkType_MemberProperty) { - SkOperand operand; - if (info->getType() == SkType_Int) { - info->getValue(element, &operand, 1); - return operand.fS32; - } - return SK_NaN32; - } - SkScriptValue scriptValue; - bool success = element->getProperty(info->propertyIndex(), &scriptValue); - if (success && scriptValue.fType == SkType_Int) - return scriptValue.fOperand.fS32; - return SK_NaN32; -} - -int32_t SkAnimator::getInt(const char* id, const char* fieldID) { - const SkDisplayable* element = getElement(id); - if (element == nullptr) - return SK_NaN32; - const SkMemberInfo* field = getField(element, fieldID); - if (field == nullptr) - return SK_NaN32; - return getInt(element, field); -} - -SkScalar SkAnimator::getScalar(const SkDisplayable* element, const SkMemberInfo* info) { - if (info->fType != SkType_MemberProperty) { - SkOperand operand; - if (info->getType() == SkType_Float) { - info->getValue(element, &operand, 1); - return operand.fScalar; - } - return SK_ScalarNaN; - } - SkScriptValue scriptValue; - bool success = element->getProperty(info->propertyIndex(), &scriptValue); - if (success && scriptValue.fType == SkType_Float) - return scriptValue.fOperand.fScalar; - return SK_ScalarNaN; -} - -SkScalar SkAnimator::getScalar(const char* id, const char* fieldID) { - const SkDisplayable* element = getElement(id); - if (element == nullptr) - return SK_ScalarNaN; - const SkMemberInfo* field = getField(element, fieldID); - if (field == nullptr) - return SK_ScalarNaN; - return getScalar(element, field); -} - -const char* SkAnimator::getString(const SkDisplayable* ae, - const SkMemberInfo* ai) { - const SkDisplayable* element = (const SkDisplayable*) ae; - const SkMemberInfo* info = (const SkMemberInfo*) ai; - SkString* temp; - info->getString(element, &temp); - return temp->c_str(); -} - -const char* SkAnimator::getString(const char* id, const char* fieldID) { - const SkDisplayable* element = getElement(id); - if (element == nullptr) - return nullptr; - const SkMemberInfo* field = getField(element, fieldID); - if (field == nullptr) - return nullptr; - return getString(element, field); -} - -const char* SkAnimator::getURIBase() { - return fMaker->fPrefix.c_str(); -} - -void SkAnimator::initialize() { - delete fMaker; - fMaker = new SkAnimateMaker(this, nullptr, nullptr); - decodeMemory(gMathPrimer, sizeof(gMathPrimer)-1); -#ifdef SK_BUILD_FOR_ANDROID - InitializeSkExtraPathEffects(this); -#endif -} - - -#ifdef SK_DEBUG -bool SkAnimator::isTrackingEvents() { - return false; -} -#endif - -bool SkAnimator::onEvent(const SkEvent& evt) { -#ifdef SK_DEBUG - SkAnimator* root = fMaker->getRoot(); - if (root == nullptr) - root = this; - if (root->isTrackingEvents()) - root->eventDone(evt); -#endif - if (evt.isType(SK_EventType_OnEnd)) { - SkEventState eventState; - SkDEBUGCODE(bool success =) evt.findPtr("anim", (void**) &eventState.fDisplayable); - SkASSERT(success); - SkDEBUGCODE(success =) evt.findS32("time", (int32_t*) &fMaker->fEnableTime); - SkASSERT(success); - fMaker->fAdjustedStart = fMaker->getAppTime() - fMaker->fEnableTime; - fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kOnEnd, &eventState); - fMaker->fAdjustedStart = 0; - goto inval; - } - if (evt.isType(SK_EventType_Delay)) { - fMaker->doDelayedEvent(); - goto inval; - } - { - const char* id = evt.findString("id"); - if (id == nullptr) - return false; - SkDisplayable** firstMovie = fMaker->fMovies.begin(); - SkDisplayable** endMovie = fMaker->fMovies.end(); - for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) { - SkDisplayMovie* movie = (SkDisplayMovie*) *ptr; - movie->doEvent(evt); - } - { - SkDisplayable* event; - if (fMaker->find(id, &event) == false) - return false; - #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - SkString debugOut; - SkMSec realTime = fMaker->getAppTime(); - debugOut.appendS32(realTime - fMaker->fDebugTimeBase); - debugOut.append(" onEvent id="); - debugOut.append(id); - #endif - SkMSec time = evt.getFast32(); - if (time != 0) { - SkMSec app = fMaker->getAppTime(); - fMaker->setEnableTime(app, time); - #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - debugOut.append(" time="); - debugOut.appendS32(time - fMaker->fDebugTimeBase); - debugOut.append(" adjust="); - debugOut.appendS32(fMaker->fAdjustedStart); - #endif - } - #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - SkDebugf("%s\n", debugOut.c_str()); - #endif - SkASSERT(event->isEvent()); - SkDisplayEvent* displayEvent = (SkDisplayEvent*) event; - displayEvent->populateInput(*fMaker, evt); - displayEvent->enableEvent(*fMaker); - } - } -inval: - fMaker->notifyInval(); - return true; -} - -void SkAnimator::onEventPost(SkEvent* evt, SkEventSinkID sinkID) -{ -#ifdef SK_DEBUG - SkAnimator* root = fMaker->getRoot(); - if (root) { - root->onEventPost(evt, sinkID); - return; - } -#else - SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID); -#endif - evt->setTargetID(sinkID)->post(); -} - -void SkAnimator::onEventPostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time) -{ -#ifdef SK_DEBUG - SkAnimator* root = fMaker->getRoot(); - if (root) { - root->onEventPostTime(evt, sinkID, time); - return; - } -#else - SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID); -#endif - evt->setTargetID(sinkID)->postTime(time); -} - -void SkAnimator::reset() { - fMaker->fDisplayList.reset(); -} - -SkEventSinkID SkAnimator::getHostEventSinkID() const { - return fMaker->fHostEventSinkID; -} - -void SkAnimator::setHostEventSinkID(SkEventSinkID target) { - fMaker->fHostEventSinkID = target; -} - -void SkAnimator::onSetHostHandler(Handler ) { -} - -void SkAnimator::setJavaOwner(Handler ) { -} - -bool SkAnimator::setArrayString(const char* id, const char* fieldID, const char** array, int num) -{ - SkTypedArray tArray(SkType_String); - tArray.setCount(num); - for (int i = 0; i < num; i++) { - SkOperand op; - op.fString = new SkString(array[i]); - tArray[i] = op; - } - return setArray(id, fieldID, tArray); -} -bool SkAnimator::setArrayInt(const char* id, const char* fieldID, const int* array, int num) -{ - SkTypedArray tArray(SkType_Int); - tArray.setCount(num); - for (int i = 0; i < num; i++) { - SkOperand op; - op.fS32 = array[i]; - tArray[i] = op; - } - return setArray(id, fieldID, tArray); -} - -bool SkAnimator::setArray(SkDisplayable* element, const SkMemberInfo* info, SkTypedArray array) { - if (info->fType != SkType_Array) - return false; //the field is not an array - //i think we can handle the case where the displayable itself is an array differently from the - //case where it has an array - for one thing, if it is an array, i think we can change its type - //if it's not, we cannot - SkDisplayTypes type = element->getType(); - if (type == SkType_Array) { - SkDisplayArray* dispArray = (SkDisplayArray*) element; - dispArray->values = array; - return true; - } - else - return false; //currently i don't care about this case -} - -bool SkAnimator::setArray(const char* id, const char* fieldID, SkTypedArray array) { - SkDisplayable* element = (SkDisplayable*) getElement(id); - //should I go ahead and change all 'nullptr's to 'nullptr'? - if (element == nullptr) - return false; - const SkMemberInfo* field = getField(element, fieldID); - if (field == nullptr) - return false; - return setArray(element, field, array); -} - -bool SkAnimator::setInt(SkDisplayable* element, const SkMemberInfo* info, int32_t s32) { - if (info->fType != SkType_MemberProperty) { - SkOperand operand; - operand.fS32 = s32; - SkASSERT(info->getType() == SkType_Int); - info->setValue(element, &operand, 1); - } else { - SkScriptValue scriptValue; - scriptValue.fType = SkType_Int; - scriptValue.fOperand.fS32 = s32; - element->setProperty(info->propertyIndex(), scriptValue); - } - return true; -} - -bool SkAnimator::setInt(const char* id, const char* fieldID, int32_t s32) { - SkDisplayable* element = (SkDisplayable*) getElement(id); - if (element == nullptr) - return false; - const SkMemberInfo* field = getField(element, fieldID); - if (field == nullptr) - return false; - return setInt(element, field, s32); -} - -bool SkAnimator::setScalar(SkDisplayable* element, const SkMemberInfo* info, SkScalar scalar) { - if (info->fType != SkType_MemberProperty) { - SkOperand operand; - operand.fScalar = scalar; - SkASSERT(info->getType() == SkType_Float); - info->setValue(element, &operand, 1); - } else { - SkScriptValue scriptValue; - scriptValue.fType = SkType_Float; - scriptValue.fOperand.fScalar = scalar; - element->setProperty(info->propertyIndex(), scriptValue); - } - return true; -} - -bool SkAnimator::setScalar(const char* id, const char* fieldID, SkScalar scalar) { - SkDisplayable* element = (SkDisplayable*) getElement(id); - if (element == nullptr) - return false; - const SkMemberInfo* field = getField(element, fieldID); - if (field == nullptr) - return false; - return setScalar(element, field, scalar); -} - -bool SkAnimator::setString(SkDisplayable* element, - const SkMemberInfo* info, const char* str) { - // !!! until this is fixed, can't call script with global references from here - info->setValue(*fMaker, nullptr, 0, info->fCount, element, info->getType(), str, strlen(str)); - return true; -} - -bool SkAnimator::setString(const char* id, const char* fieldID, const char* str) { - SkDisplayable* element = (SkDisplayable*) getElement(id); - if (element == nullptr) - return false; - const SkMemberInfo* field = getField(element, fieldID); - if (field == nullptr) - return false; - return setString(element, field, str); -} - -void SkAnimator::setTimeline(const Timeline& timeline) { - fMaker->fTimeline = &timeline; -} - -void SkAnimator::setURIBase(const char* uri) { - if (uri) - { - const char* tail = strrchr(uri, '/'); - if (tail) { - SkString prefix(uri, tail - uri + 1); - if (uri[0] != '.' /*SkStream::IsAbsoluteURI(uri)*/) - fMaker->fPrefix.reset(); - fMaker->fPrefix.append(prefix); - fMaker->fFileName.set(tail + 1); - } else - fMaker->fFileName.set(uri); - } -} - -#ifdef SK_DEBUG -bool SkAnimator::NoLeaks() { -#ifdef SK_BUILD_FOR_MAC - if (SkDisplayable::fAllocations.count() == 0) - return true; -// return SkDisplayable::fAllocationCount == 0; - SkDebugf("!!! leaked %d displayables:\n", SkDisplayable::fAllocations.count()); - for (SkDisplayable** leak = SkDisplayable::fAllocations.begin(); leak < SkDisplayable::fAllocations.end(); leak++) - SkDebugf("%08x %s\n", *leak, (*leak)->id); -#endif - return false; -} -#endif - -#ifdef SK_SUPPORT_UNITTEST -#include "SkAnimatorScript.h" -#include "SkBase64.h" -#include "SkParse.h" -#include "SkMemberInfo.h" - -#define unittestline(type) { #type , type::UnitTest } -#endif - - -#ifdef SK_SUPPORT_UNITTEST -void SkAnimator::Init(bool runUnitTests) { - if (runUnitTests == false) - return; - static const struct { - const char* fTypeName; - void (*fUnitTest)( ); - } gUnitTests[] = { - unittestline(SkBase64), - unittestline(SkDisplayType), - unittestline(SkParse), - unittestline(SkScriptEngine), -// unittestline(SkScriptEngine2), // compiled script experiment - unittestline(SkAnimatorScript) - }; - for (int i = 0; i < (int)SK_ARRAY_COUNT(gUnitTests); i++) - { - SkDebugf("SkAnimator: Running UnitTest for %s\n", gUnitTests[i].fTypeName); - gUnitTests[i].fUnitTest(); - SkDebugf("SkAnimator: End UnitTest for %s\n", gUnitTests[i].fTypeName); - } -} -#else -void SkAnimator::Init(bool) {} -#endif - -void SkAnimator::Term() { -} diff --git a/gfx/skia/skia/src/animator/SkAnimatorScript.cpp b/gfx/skia/skia/src/animator/SkAnimatorScript.cpp deleted file mode 100644 index cbe1d04b1ed1..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimatorScript.cpp +++ /dev/null @@ -1,594 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkAnimatorScript.h" -#include "SkAnimateBase.h" -#include "SkAnimateMaker.h" -#include "SkDisplayTypes.h" -#include "SkExtras.h" -#include "SkMemberInfo.h" -#include "SkParse.h" - -static const SkDisplayEnumMap gEnumMaps[] = { - { SkType_AddMode, "indirect|immediate" }, - { SkType_Align, "left|center|right" }, - { SkType_ApplyMode, "create|immediate|once" }, - { SkType_ApplyTransition, "normal|reverse" }, - { SkType_BitmapEncoding, "jpeg|png" }, - { SkType_BitmapFormat, "none|A1|A8|Index8|RGB16|RGB32" }, - { SkType_Boolean, "false|true" }, - { SkType_Cap, "butt|round|square" }, - { SkType_EventCode, "none|leftSoftKey|rightSoftKey|home|back|send|end|key0|key1|key2|key3|key4|key5|key6|key7|key8|key9|star|hash|up|down|left|right|OK|volUp|volDown|camera" }, - { SkType_EventKind, "none|keyChar|keyPress|keyPressUp|mouseDown|mouseDrag|mouseMove|mouseUp|onEnd|onLoad|user" }, - { SkType_EventMode, "deferred|immediate" }, - { SkType_FillType, "winding|evenOdd" }, - { SkType_FilterType, "none|bilinear" }, - { SkType_FontStyle, "normal|bold|italic|boldItalic" }, - { SkType_FromPathMode, "normal|angle|position" }, - { SkType_Join, "miter|round|blunt" }, - { SkType_MaskFilterBlurStyle, "normal|solid|outer|inner" }, - { SkType_PathDirection, "cw|ccw" }, - { SkType_Style, "fill|stroke|strokeAndFill" }, - { SkType_TextBoxAlign, "start|center|end" }, - { SkType_TextBoxMode, "oneLine|lineBreak" }, - { SkType_TileMode, "clamp|repeat|mirror" }, - { SkType_Xfermode, "clear|src|dst|srcOver|dstOver|srcIn|dstIn|srcOut|dstOut|" - "srcATop|dstATop|xor|darken|lighten" }, -}; - -static int gEnumMapCount = SK_ARRAY_COUNT(gEnumMaps); - -SkAnimatorScript::SkAnimatorScript(SkAnimateMaker& maker, SkDisplayable* working, SkDisplayTypes type) - : SkScriptEngine(SkScriptEngine::ToOpType(type)), fMaker(maker), fParent(nullptr), fWorking(working) -{ - memberCallBack(EvalMember, (void*) this); - memberFunctionCallBack(EvalMemberFunction, (void*) this); - boxCallBack(Box, (void*) this); - unboxCallBack(Unbox, (void*) &maker); - propertyCallBack(EvalID, (void*) this); // must be first (entries are prepended, will be last), since it never fails - propertyCallBack(Infinity, (void*) this); - propertyCallBack(NaN, (void*) this); - functionCallBack(Eval, (void*) this); - functionCallBack(IsFinite, (void*) this); - functionCallBack(IsNaN, (void*) this); - if (type == SkType_ARGB) { - functionCallBack(EvalRGB, (void*) this); - propertyCallBack(EvalNamedColor, (void*) &maker.fIDs); - } - if (SkDisplayType::IsEnum(&maker, type)) { - // !!! for SpiderMonkey, iterate through the enum values, and map them to globals - const SkDisplayEnumMap& map = GetEnumValues(type); - propertyCallBack(EvalEnum, (void*) map.fValues); - } - for (SkExtras** extraPtr = maker.fExtras.begin(); extraPtr < maker.fExtras.end(); extraPtr++) { - SkExtras* extra = *extraPtr; - if (extra->fExtraCallBack) - propertyCallBack(extra->fExtraCallBack, extra->fExtraStorage); - } -} - -SkAnimatorScript::~SkAnimatorScript() { - for (SkDisplayable** dispPtr = fTrackDisplayable.begin(); dispPtr < fTrackDisplayable.end(); dispPtr++) - delete *dispPtr; -} - -bool SkAnimatorScript::evaluate(const char* original, SkScriptValue* result, SkDisplayTypes type) { - const char* script = original; - bool success = evaluateScript(&script, result); - if (success == false || result->fType != type) { - fMaker.setScriptError(*this); - return false; - } - return true; -} - -bool SkAnimatorScript::Box(void* user, SkScriptValue* scriptValue) { - SkAnimatorScript* engine = (SkAnimatorScript*) user; - SkDisplayTypes type = scriptValue->fType; - SkDisplayable* displayable; - switch (type) { - case SkType_Array: { - SkDisplayArray* boxedValue = new SkDisplayArray(*scriptValue->fOperand.fArray); - displayable = boxedValue; - } break; - case SkType_Boolean: { - SkDisplayBoolean* boxedValue = new SkDisplayBoolean; - displayable = boxedValue; - boxedValue->value = !! scriptValue->fOperand.fS32; - } break; - case SkType_Int: { - SkDisplayInt* boxedValue = new SkDisplayInt; - displayable = boxedValue; - boxedValue->value = scriptValue->fOperand.fS32; - } break; - case SkType_Float: { - SkDisplayFloat* boxedValue = new SkDisplayFloat; - displayable = boxedValue; - boxedValue->value = scriptValue->fOperand.fScalar; - } break; - case SkType_String: { - SkDisplayString* boxedValue = new SkDisplayString(*scriptValue->fOperand.fString); - displayable = boxedValue; - } break; - case SkType_Displayable: - scriptValue->fOperand.fObject = scriptValue->fOperand.fDisplayable; - scriptValue->fType = SkType_Displayable; - return true; - default: - SkASSERT(0); - return false; - } - engine->track(displayable); - scriptValue->fOperand.fObject = displayable; - scriptValue->fType = SkType_Displayable; - return true; -} - -bool SkAnimatorScript::Eval(const char* function, size_t len, SkTDArray& params, - void* eng, SkScriptValue* value) { - if (SK_LITERAL_STR_EQUAL("eval", function, len) == false) - return false; - if (params.count() != 1) - return false; - SkAnimatorScript* host = (SkAnimatorScript*) eng; - SkAnimatorScript engine(host->fMaker, host->fWorking, SkScriptEngine::ToDisplayType(host->fReturnType)); - SkScriptValue* scriptValue = params.begin(); - bool success = true; - if (scriptValue->fType == SkType_String) { - const char* script = scriptValue->fOperand.fString->c_str(); - success = engine.evaluateScript(&script, value); - } else - *value = *scriptValue; - return success; -} - -bool SkAnimatorScript::EvalEnum(const char* token, size_t len, void* callBack, SkScriptValue* value) { - const char* tokens = (const char*) callBack; - value->fType = SkType_Int; - if (MapEnums(tokens, token, len, (int*)&value->fOperand.fS32)) - return true; - return false; -} - -bool SkAnimatorScript::EvalID(const char* token, size_t len, void* user, SkScriptValue* value) { - SkAnimatorScript* engine = (SkAnimatorScript*) user; - SkTDict* ids = &engine->fMaker.fIDs; - SkDisplayable* displayable; - bool success = ids->find(token, len, &displayable); - if (success == false) { - displayable = engine->fWorking; - if (SK_LITERAL_STR_EQUAL("parent", token, len)) { - SkDisplayable* parent = displayable->getParent(); - if (parent == nullptr) - parent = engine->fParent; - if (parent) { - value->fOperand.fDisplayable = parent; - value->fType = SkType_Displayable; - return true; - } - } - if (displayable && EvalMember(token, len, displayable, engine, value)) - return true; - value->fOperand.fString = nullptr; - value->fType = SkType_String; - } else { - SkDisplayable* working = engine->fWorking; - value->fOperand.fDisplayable = displayable; - value->fType = SkType_Displayable; - if (displayable->canContainDependents() && working && working->isAnimate()) { - SkAnimateBase* animator = (SkAnimateBase*) working; - if (animator->isDynamic()) { - SkDisplayDepend* depend = (SkDisplayDepend* ) displayable; - depend->addDependent(working); - } - } - } - return true; -} - -bool SkAnimatorScript::EvalNamedColor(const char* token, size_t len, void* callback, SkScriptValue* value) { - value->fType = SkType_Int; - if (SkParse::FindNamedColor(token, len, (SkColor*) &value->fOperand.fS32) != nullptr) - return true; - return false; -} - -bool SkAnimatorScript::EvalRGB(const char* function, size_t len, SkTDArray& params, - void* eng, SkScriptValue* value) { - if (SK_LITERAL_STR_EQUAL("rgb", function, len) == false) - return false; - if (params.count() != 3) - return false; - SkScriptEngine* engine = (SkScriptEngine*) eng; - unsigned result = 0xFF000000; - int shift = 16; - for (SkScriptValue* valuePtr = params.begin(); valuePtr < params.end(); valuePtr++) { - engine->convertTo(SkType_Int, valuePtr); - result |= SkClampMax(valuePtr->fOperand.fS32, 255) << shift; - shift -= 8; - } - value->fOperand.fS32 = result; - value->fType = SkType_Int; - return true; -} - -bool SkAnimatorScript::EvalMemberCommon(SkScriptEngine* engine, const SkMemberInfo* info, - SkDisplayable* displayable, SkScriptValue* value) { - SkDisplayTypes original; - SkDisplayTypes type = original = (SkDisplayTypes) info->getType(); - if (info->fType == SkType_Array) - type = SkType_Array; - switch (type) { - case SkType_ARGB: - type = SkType_Int; - case SkType_Boolean: - case SkType_Int: - case SkType_MSec: - case SkType_Float: - SkASSERT(info->getCount() == 1); - if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) - value->fOperand.fS32 = *(int32_t*) info->memberData(displayable); // OK for SkScalar too - if (type == SkType_MSec) { - value->fOperand.fScalar = value->fOperand.fS32 * 0.001f; - type = SkType_Float; - } - break; - case SkType_String: { - SkString* displayableString; - if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) { - info->getString(displayable, &displayableString); - value->fOperand.fString = new SkString(*displayableString); - } - } break; - case SkType_Array: { - SkASSERT(info->fType != SkType_MemberProperty); // !!! incomplete - SkTDOperandArray* displayableArray = (SkTDOperandArray*) info->memberData(displayable); - if (displayable->getType() == SkType_Array) { - SkDisplayArray* typedArray = (SkDisplayArray*) displayable; - original = typedArray->values.getType(); - } - SkASSERT(original != SkType_Unknown); - SkTypedArray* array = value->fOperand.fArray = new SkTypedArray(original); - engine->track(array); - int count = displayableArray->count(); - if (count > 0) { - array->setCount(count); - memcpy(array->begin(), displayableArray->begin(), count * sizeof(SkOperand)); - } - } break; - default: - SkASSERT(0); // unimplemented - } - value->fType = type; - return true; -} - -bool SkAnimatorScript::EvalMember(const char* member, size_t len, void* object, void* eng, - SkScriptValue* value) { - SkScriptEngine* engine = (SkScriptEngine*) eng; - SkDisplayable* displayable = (SkDisplayable*) object; - SkString name(member, len); - SkDisplayable* named = displayable->contains(name); - if (named) { - value->fOperand.fDisplayable = named; - value->fType = SkType_Displayable; - return true; - } - const SkMemberInfo* info = displayable->getMember(name.c_str()); - if (info == nullptr) - return false; - if (info->fType == SkType_MemberProperty) { - if (displayable->getProperty(info->propertyIndex(), value) == false) { - SkASSERT(0); - return false; - } - } - return EvalMemberCommon(engine, info, displayable, value); -} - -bool SkAnimatorScript::EvalMemberFunction(const char* member, size_t len, void* object, - SkTDArray& params, void* eng, SkScriptValue* value) { - SkScriptEngine* engine = (SkScriptEngine*) eng; - SkDisplayable* displayable = (SkDisplayable*) object; - SkString name(member, len); - const SkMemberInfo* info = displayable->getMember(name.c_str()); - SkASSERT(info != nullptr); /* !!! error handling unimplemented */ - if (info->fType != SkType_MemberFunction) { - SkASSERT(0); - return false; - } - displayable->executeFunction(displayable, info->functionIndex(), params, info->getType(), - value); - return EvalMemberCommon(engine, info, displayable, value); -} - -bool SkAnimatorScript::EvaluateDisplayable(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, SkDisplayable** result) { - SkAnimatorScript engine(maker, displayable, SkType_Displayable); - SkScriptValue value; - bool success = engine.evaluate(script, &value, SkType_Displayable); - if (success) - *result = value.fOperand.fDisplayable; - return success; -} - -bool SkAnimatorScript::EvaluateInt(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, int32_t* result) { - SkAnimatorScript engine(maker, displayable, SkType_Int); - SkScriptValue value; - bool success = engine.evaluate(script, &value, SkType_Int); - if (success) - *result = value.fOperand.fS32; - return success; -} - -bool SkAnimatorScript::EvaluateFloat(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, SkScalar* result) { - SkAnimatorScript engine(maker, displayable, SkType_Float); - SkScriptValue value; - bool success = engine.evaluate(script, &value, SkType_Float); - if (success) - *result = value.fOperand.fScalar; - return success; -} - -bool SkAnimatorScript::EvaluateString(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, SkString* result) { - SkAnimatorScript engine(maker, displayable, SkType_String); - SkScriptValue value; - bool success = engine.evaluate(script, &value, SkType_String); - if (success) - result->set(*(value.fOperand.fString)); - return success; -} - -bool SkAnimatorScript::EvaluateString(SkAnimateMaker& maker, SkDisplayable* displayable, SkDisplayable* parent, const char* script, SkString* result) { - SkAnimatorScript engine(maker, displayable, SkType_String); - engine.fParent = parent; - SkScriptValue value; - bool success = engine.evaluate(script, &value, SkType_String); - if (success) - result->set(*(value.fOperand.fString)); - return success; -} - -const SkDisplayEnumMap& SkAnimatorScript::GetEnumValues(SkDisplayTypes type) { - int index = SkTSearch(&gEnumMaps[0].fType, gEnumMapCount, type, - sizeof(SkDisplayEnumMap)); - SkASSERT(index >= 0); - return gEnumMaps[index]; -} - -bool SkAnimatorScript::Infinity(const char* token, size_t len, void* user, SkScriptValue* value) { - if (SK_LITERAL_STR_EQUAL("Infinity", token, len) == false) - return false; - value->fType = SkType_Float; - value->fOperand.fScalar = SK_ScalarInfinity; - return true; -} - -bool SkAnimatorScript::IsFinite(const char* function, size_t len, SkTDArray& params, - void* eng, SkScriptValue* value) { - if (SK_LITERAL_STR_EQUAL(function, "isFinite", len) == false) - return false; - if (params.count() != 1) - return false; - SkScriptValue* scriptValue = params.begin(); - SkDisplayTypes type = scriptValue->fType; - SkScalar scalar = scriptValue->fOperand.fScalar; - value->fType = SkType_Int; - value->fOperand.fS32 = type == SkType_Float ? SkScalarIsNaN(scalar) == false && - SkScalarAbs(scalar) != SK_ScalarInfinity : type == SkType_Int; - return true; -} - -bool SkAnimatorScript::IsNaN(const char* function, size_t len, SkTDArray& params, - void* eng, SkScriptValue* value) { - if (SK_LITERAL_STR_EQUAL("isNaN", function, len) == false) - return false; - if (params.count() != 1) - return false; - SkScriptValue* scriptValue = params.begin(); - value->fType = SkType_Int; - value->fOperand.fS32 = scriptValue->fType == SkType_Float ? SkScalarIsNaN(scriptValue->fOperand.fScalar) : 0; - return true; -} - -bool SkAnimatorScript::MapEnums(const char* ptr, const char* match, size_t len, int* value) { - int index = 0; - bool more = true; - do { - const char* last = strchr(ptr, '|'); - if (last == nullptr) { - last = &ptr[strlen(ptr)]; - more = false; - } - size_t length = last - ptr; - if (len == length && strncmp(ptr, match, length) == 0) { - *value = index; - return true; - } - index++; - ptr = last + 1; - } while (more); - return false; -} - -bool SkAnimatorScript::NaN(const char* token, size_t len, void* user, SkScriptValue* value) { - if (SK_LITERAL_STR_EQUAL("NaN", token, len) == false) - return false; - value->fType = SkType_Float; - value->fOperand.fScalar = SK_ScalarNaN; - return true; -} - -#if 0 -bool SkAnimatorScript::ObjectToString(void* object, void* user, SkScriptValue* value) { - SkTDict* ids = (SkTDict*) user; - SkDisplayable* displayable = (SkDisplayable*) object; - const char* key; - bool success = ids->findKey(displayable, &key); - if (success == false) - return false; - value->fOperand.fString = new SkString(key); - value->fType = SkType_String; - return true; -} -#endif - -bool SkAnimatorScript::Unbox(void* m, SkScriptValue* scriptValue) { - SkAnimateMaker* maker = (SkAnimateMaker*) m; - SkASSERT((unsigned) scriptValue->fType == (unsigned) SkType_Displayable); - SkDisplayable* displayable = (SkDisplayable*) scriptValue->fOperand.fObject; - SkDisplayTypes type = displayable->getType(); - switch (displayable->getType()) { - case SkType_Array: { - SkDisplayArray* boxedValue = (SkDisplayArray*) displayable; - scriptValue->fOperand.fArray = &boxedValue->values; - } break; - case SkType_Boolean: { - SkDisplayBoolean* boxedValue = (SkDisplayBoolean*) displayable; - scriptValue->fOperand.fS32 = boxedValue->value; - } break; - case SkType_Int: { - SkDisplayInt* boxedValue = (SkDisplayInt*) displayable; - scriptValue->fOperand.fS32 = boxedValue->value; - } break; - case SkType_Float: { - SkDisplayFloat* boxedValue = (SkDisplayFloat*) displayable; - scriptValue->fOperand.fScalar = boxedValue->value; - } break; - case SkType_String: { - SkDisplayString* boxedValue = (SkDisplayString*) displayable; - scriptValue->fOperand.fString = new SkString(boxedValue->value); - } break; - default: { - const char* id = nullptr; - SkDEBUGCODE(bool success = ) maker->findKey(displayable, &id); - SkASSERT(success); - scriptValue->fOperand.fString = new SkString(id); - type = SkType_String; - } - } - scriptValue->fType = type; - return true; -} - -#if defined SK_SUPPORT_UNITTEST - -#include "SkAnimator.h" - -static const char scriptTestSetup[] = -"\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" -""; - -#define DEFAULT_ANSWER , 0 - -static const SkScriptNAnswer scriptTests[] = { - { "label.text.length == 4", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, -// { "labelPaint.measureText(label.text) > 0 ? labelPaint.measureText(label.text)+10 : 40", SkType_Float, 0, SkIntToScalar(0x23) }, - { "Number.POSITIVE_INFINITY >= Number.MAX_VALUE ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "Infinity >= Number.MAX_VALUE ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "Number.NEGATIVE_INFINITY <= -Number.MAX_VALUE ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "Number.MIN_VALUE > 0 ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "isNaN(Number.NaN)", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "isNaN(NaN)", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "Math.sin(0)", SkType_Float, 0, SkIntToScalar(0) DEFAULT_ANSWER }, - { "alpha+alpha", SkType_String, 0, 0, "abcabc" }, - { "intArray[4]", SkType_Unknown DEFAULT_ANSWER DEFAULT_ANSWER DEFAULT_ANSWER }, - { "emptyArray[4]", SkType_Unknown DEFAULT_ANSWER DEFAULT_ANSWER DEFAULT_ANSWER }, - { "idx", SkType_Int, 2 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "intArray.length", SkType_Int, 3 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "intArray.values[0]", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "intArray[0]", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "idx.value", SkType_Int, 2 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "alpha.value", SkType_String, 0, 0, "abc" }, - { "alpha", SkType_String, 0, 0, "abc" }, - { "alpha.value+alpha.value", SkType_String, 0, 0, "abcabc" }, - { "alpha+idx", SkType_String, 0, 0, "abc2" }, - { "idx+alpha", SkType_String, 0, 0, "2abc" }, - { "intArray[idx]", SkType_Int, 6 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "alpha.slice(1,2)", SkType_String, 0, 0, "b" }, - { "alpha.value.slice(1,2)", SkType_String, 0, 0, "b" }, - { "testRect.left+2", SkType_Float, 0, SkIntToScalar(3) DEFAULT_ANSWER }, - { "0 ? Math.sin(0) : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "0 ? intArray[0] : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "0 ? intArray.values[0] : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "0 ? idx : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "0 ? idx.value : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "0 ? alpha.slice(1,2) : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "0 ? alpha.value.slice(1,2) : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, - { "idy", SkType_Int, 3 DEFAULT_ANSWER DEFAULT_ANSWER } -}; - -#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) - -void SkAnimatorScript::UnitTest() { -#if defined(SK_SUPPORT_UNITTEST) - SkAnimator animator; - SkASSERT(animator.decodeMemory(scriptTestSetup, sizeof(scriptTestSetup)-1)); - SkEvent evt; - evt.setString("id", "evt"); - evt.setS32("x", 3); - animator.doUserEvent(evt); - // set up animator with memory script above, then run value tests - for (unsigned index = 0; index < SkScriptNAnswer_testCount; index++) { - SkAnimatorScript engine(*animator.fMaker, nullptr, scriptTests[index].fType); - SkScriptValue value; - const char* script = scriptTests[index].fScript; - bool success = engine.evaluateScript(&script, &value); - if (success == false) { - SkDebugf("script failed: %s\n", scriptTests[index].fScript); - SkASSERT(scriptTests[index].fType == SkType_Unknown); - continue; - } - SkASSERT(value.fType == scriptTests[index].fType); - SkScalar error; - switch (value.fType) { - case SkType_Int: - SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); - break; - case SkType_Float: - error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); - SkASSERT(error < SK_Scalar1 / 10000); - break; - case SkType_String: - SkASSERT(strcmp(value.fOperand.fString->c_str(), scriptTests[index].fStringAnswer) == 0); - break; - default: - SkASSERT(0); - } - } -#endif -} - -#endif diff --git a/gfx/skia/skia/src/animator/SkAnimatorScript.h b/gfx/skia/skia/src/animator/SkAnimatorScript.h deleted file mode 100644 index 8589388e113e..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimatorScript.h +++ /dev/null @@ -1,75 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkAnimatorScript_DEFINED -#define SkAnimatorScript_DEFINED - -#include "SkDisplayable.h" -#include "SkScript.h" -#include "SkTypedArray.h" - -class SkAnimateMaker; -struct SkMemberInfo; - -struct SkDisplayEnumMap { - SkDisplayTypes fType; - const char* fValues; -}; - -class SkAnimatorScript : public SkScriptEngine { -public: - SkAnimatorScript(SkAnimateMaker& , SkDisplayable* , SkDisplayTypes type); - ~SkAnimatorScript(); - bool evaluate(const char* script, SkScriptValue* , SkDisplayTypes type); - void track(SkDisplayable* displayable) { - SkASSERT(fTrackDisplayable.find(displayable) < 0); - *fTrackDisplayable.append() = displayable; } - static bool EvaluateDisplayable(SkAnimateMaker& , SkDisplayable* , const char* script, SkDisplayable** ); - static bool EvaluateFloat(SkAnimateMaker& , SkDisplayable* , const char* script, SkScalar* ); - static bool EvaluateInt(SkAnimateMaker& , SkDisplayable* , const char* script, int32_t* ); - static bool EvaluateString(SkAnimateMaker& , SkDisplayable* , const char* script, SkString* ); - static bool EvaluateString(SkAnimateMaker& , SkDisplayable* , SkDisplayable* parent, const char* script, SkString* ); - static bool MapEnums(const char* ptr, const char* match, size_t len, int* value); -protected: - static bool Box(void* user, SkScriptValue* ); - static bool Eval(const char* function, size_t len, SkTDArray& params, - void* callBack, SkScriptValue* ); - static bool EvalEnum(const char* token, size_t len, void* callBack, SkScriptValue* ); - static bool EvalID(const char* token, size_t len, void* callBack, SkScriptValue* ); - static bool EvalMember(const char* member, size_t len, void* object, void* eng, - SkScriptValue* value); - static bool EvalMemberCommon(SkScriptEngine* , const SkMemberInfo* info, - SkDisplayable* displayable, SkScriptValue* value); - static bool EvalMemberFunction(const char* member, size_t len, void* object, - SkTDArray& params, void* user, SkScriptValue* value); - static bool EvalNamedColor(const char* token, size_t len, void* callBack, SkScriptValue* ); - static bool EvalRGB(const char* function, size_t len, SkTDArray& params, - void* callBack, SkScriptValue* ); - static const SkDisplayEnumMap& GetEnumValues(SkDisplayTypes type); - static bool Infinity(const char* token, size_t len, void* callBack, SkScriptValue* ); - static bool IsFinite(const char* function, size_t len, SkTDArray& params, - void* callBack, SkScriptValue* ); - static bool IsNaN(const char* function, size_t len, SkTDArray& params, - void* callBack, SkScriptValue* ); - static bool NaN(const char* token, size_t len, void* callBack, SkScriptValue* ); - static bool Unbox(void* , SkScriptValue* scriptValue); - SkTDDisplayableArray fTrackDisplayable; - SkAnimateMaker& fMaker; - SkDisplayable* fParent; - SkDisplayable* fWorking; -private: - friend class SkDump; - friend struct SkScriptNAnswer; -#ifdef SK_SUPPORT_UNITTEST -public: - static void UnitTest(); -#endif -}; - -#endif // SkAnimatorScript_DEFINED diff --git a/gfx/skia/skia/src/animator/SkAnimatorScript2.cpp b/gfx/skia/skia/src/animator/SkAnimatorScript2.cpp deleted file mode 100644 index d246130fbe3f..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimatorScript2.cpp +++ /dev/null @@ -1,622 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkAnimatorScript2.h" -#include "SkAnimateBase.h" -#include "SkAnimateMaker.h" -#include "SkDisplayTypes.h" -#include "SkExtras.h" -#include "SkMemberInfo.h" -#include "SkOpArray.h" -#include "SkParse.h" -#include "SkScript2.h" -#include "SkScriptCallBack.h" - -static const SkDisplayEnumMap gEnumMaps[] = { - { SkType_AddMode, "indirect|immediate" }, - { SkType_Align, "left|center|right" }, - { SkType_ApplyMode, "immediate|once" }, - { SkType_ApplyTransition, "reverse" }, - { SkType_BitmapEncoding, "jpeg|png" }, - { SkType_BitmapFormat, "none|A1|A8|Index8|RGB16|RGB32" }, - { SkType_Boolean, "false|true" }, - { SkType_Cap, "butt|round|square" }, - { SkType_EventCode, "none|up|down|left|right|back|end|OK|send|leftSoftKey|rightSoftKey|key0|key1|key2|key3|key4|key5|key6|key7|key8|key9|star|hash" }, - { SkType_EventKind, "none|keyChar|keyPress|mouseDown|mouseDrag|mouseMove|mouseUp|onEnd|onLoad|user" }, - { SkType_EventMode, "deferred|immediate" }, - { SkType_FillType, "winding|evenOdd" }, - { SkType_FilterType, "none|bilinear" }, - { SkType_FromPathMode, "normal|angle|position" }, - { SkType_Join, "miter|round|blunt" }, - { SkType_MaskFilterBlurStyle, "normal|solid|outer|inner" }, - { SkType_PathDirection, "cw|ccw" }, - { SkType_Style, "fill|stroke|strokeAndFill" }, - { SkType_TextBoxAlign, "start|center|end" }, - { SkType_TextBoxMode, "oneLine|lineBreak" }, - { SkType_TileMode, "clamp|repeat|mirror" }, - { SkType_Xfermode, "clear|src|dst|srcOver|dstOver|srcIn|dstIn|srcOut|dstOut|" - "srcATop|dstATop|xor|darken|lighten" }, -}; - -static int gEnumMapCount = SK_ARRAY_COUNT(gEnumMaps); - - -class SkAnimatorScript_Box : public SkScriptCallBackConvert { -public: - SkAnimatorScript_Box() {} - - ~SkAnimatorScript_Box() { - for (SkDisplayable** dispPtr = fTrackDisplayable.begin(); dispPtr < fTrackDisplayable.end(); dispPtr++) - delete *dispPtr; - } - - virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) { - SkDisplayable* displayable; - switch (type) { - case SkOperand2::kArray: { - SkDisplayArray* boxedValue = new SkDisplayArray(*operand->fArray); - displayable = boxedValue; - } break; - case SkOperand2::kS32: { - SkDisplayInt* boxedValue = new SkDisplayInt; - displayable = boxedValue; - boxedValue->value = operand->fS32; - } break; - case SkOperand2::kScalar: { - SkDisplayFloat* boxedValue = new SkDisplayFloat; - displayable = boxedValue; - boxedValue->value = operand->fScalar; - } break; - case SkOperand2::kString: { - SkDisplayString* boxedValue = new SkDisplayString(*operand->fString); - displayable = boxedValue; - } break; - case SkOperand2::kObject: - return true; - default: - SkASSERT(0); - return false; - } - track(displayable); - operand->fObject = (void*) displayable; - return true; - } - - virtual SkOperand2::OpType getReturnType(int index) { - return SkOperand2::kObject; - } - - virtual Type getType() const { - return kBox; - } - - void track(SkDisplayable* displayable) { - SkASSERT(fTrackDisplayable.find(displayable) < 0); - *fTrackDisplayable.append() = displayable; - } - - SkTDDisplayableArray fTrackDisplayable; -}; - - -class SkAnimatorScript_Enum : public SkScriptCallBackProperty { -public: - SkAnimatorScript_Enum(const char* tokens) : fTokens(tokens) {} - - virtual bool getConstValue(const char* name, int len, SkOperand2* value) { - return SkAnimatorScript2::MapEnums(fTokens, name, len, &value->fS32); - } - -private: - const char* fTokens; -}; - - // !!! if type is string, call invoke - // if any other type, return original value - // distinction is undone: could do this by returning index == 0 only if param is string - // still, caller of getParamTypes will attempt to convert param to string (I guess) -class SkAnimatorScript_Eval : public SkScriptCallBackFunction { -public: - SkAnimatorScript_Eval(SkAnimatorScript2* engine) : fEngine(engine) {} - - virtual bool getIndex(const char* name, int len, size_t* result) { - if (SK_LITERAL_STR_EQUAL("eval", name, len) != 0) - return false; - *result = 0; - return true; - } - - virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { - types->setCount(1); - SkOperand2::OpType* type = types->begin(); - type[0] = SkOperand2::kString; - } - - virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) { - SkAnimatorScript2 engine(fEngine->getMaker(), fEngine->getWorking(), - SkAnimatorScript2::ToDisplayType(fEngine->getReturnType())); - SkOperand2* op = params->begin(); - const char* script = op->fString->c_str(); - SkScriptValue2 value; - return engine.evaluateScript(&script, &value); - SkASSERT(value.fType == fEngine->getReturnType()); - *answer = value.fOperand; - // !!! incomplete ? - return true; - } - -private: - SkAnimatorScript2* fEngine; -}; - -class SkAnimatorScript_ID : public SkScriptCallBackProperty { -public: - SkAnimatorScript_ID(SkAnimatorScript2* engine) : fEngine(engine) {} - - virtual bool getIndex(const char* token, int len, size_t* result) { - SkDisplayable* displayable; - bool success = fEngine->getMaker().find(token, len, &displayable); - if (success == false) { - *result = 0; - } else { - *result = (size_t) displayable; - SkDisplayable* working = fEngine->getWorking(); - if (displayable->canContainDependents() && working && working->isAnimate()) { - SkAnimateBase* animator = (SkAnimateBase*) working; - if (animator->isDynamic()) { - SkDisplayDepend* depend = (SkDisplayDepend* ) displayable; - depend->addDependent(working); - } - } - } - return true; - } - - virtual bool getResult(size_t ref, SkOperand2* answer) { - answer->fObject = (void*) ref; - return true; - } - - virtual SkOperand2::OpType getReturnType(size_t index) { - return index == 0 ? SkOperand2::kString : SkOperand2::kObject; - } - -private: - SkAnimatorScript2* fEngine; -}; - - -class SkAnimatorScript_Member : public SkScriptCallBackMember { -public: - - SkAnimatorScript_Member(SkAnimatorScript2* engine) : fEngine(engine) {} - - bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) { - SkDisplayable* displayable = (SkDisplayable*) object; - SkString name(member, len); - SkDisplayable* named = displayable->contains(name); - if (named) { - ref->fType = SkOperand2::kObject; - ref->fOperand.fObject = named; - return true; - } - const SkMemberInfo* info = displayable->getMember(name.c_str()); - if (info == nullptr) - return false; // !!! add additional error info? - ref->fType = SkAnimatorScript2::ToOpType(info->getType()); - ref->fOperand.fObject = (void*) info; - return true; - } - - bool invoke(size_t ref, void* object, SkOperand2* value) { - const SkMemberInfo* info = (const SkMemberInfo* ) ref; - SkDisplayable* displayable = (SkDisplayable*) object; - if (info->fType == SkType_MemberProperty) { - if (displayable->getProperty2(info->propertyIndex(), value) == false) { - return false; - } - } - return fEngine->evalMemberCommon(info, displayable, value); - } - - SkAnimatorScript2* fEngine; -}; - - -class SkAnimatorScript_MemberFunction : public SkScriptCallBackMemberFunction { -public: - SkAnimatorScript_MemberFunction(SkAnimatorScript2* engine) : fEngine(engine) {} - - bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) { - SkDisplayable* displayable = (SkDisplayable*) object; - SkString name(member, len); - const SkMemberInfo* info = displayable->getMember(name.c_str()); - if (info == nullptr || info->fType != SkType_MemberFunction) - return false; // !!! add additional error info? - ref->fType = SkAnimatorScript2::ToOpType(info->getType()); - ref->fOperand.fObject = (void*) info; - return true; - } - - virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { - types->setCount(3); - SkOperand2::OpType* type = types->begin(); - type[0] = type[1] = type[2] = SkOperand2::kS32; - } - - bool invoke(size_t ref, void* object, SkOpArray* params, SkOperand2* value) - { - const SkMemberInfo* info = (const SkMemberInfo* ) ref; - SkDisplayable* displayable = (SkDisplayable*) object; - displayable->executeFunction2(displayable, info->functionIndex(), params, info->getType(), - value); - return fEngine->evalMemberCommon(info, displayable, value); - } - - SkAnimatorScript2* fEngine; -}; - - -class SkAnimatorScript_NamedColor : public SkScriptCallBackProperty { -public: - virtual bool getConstValue(const char* name, int len, SkOperand2* value) { - return SkParse::FindNamedColor(name, len, (SkColor*) &value->fS32) != nullptr; - } -}; - - -class SkAnimatorScript_RGB : public SkScriptCallBackFunction { -public: - virtual bool getIndex(const char* name, int len, size_t* result) { - if (SK_LITERAL_STR_EQUAL("rgb", name, len) != 0) - return false; - *result = 0; - return true; - } - - virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { - types->setCount(3); - SkOperand2::OpType* type = types->begin(); - type[0] = type[1] = type[2] = SkOperand2::kS32; - } - - virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) { - SkASSERT(index == 0); - unsigned result = 0xFF000000; - int shift = 16; - for (int index = 0; index < 3; index++) { - result |= SkClampMax(params->begin()[index].fS32, 255) << shift; - shift -= 8; - } - answer->fS32 = result; - return true; - } - -}; - - -class SkAnimatorScript_Unbox : public SkScriptCallBackConvert { -public: - SkAnimatorScript_Unbox(SkAnimatorScript2* engine) : fEngine(engine) {} - - virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) { - SkASSERT(type == SkOperand2::kObject); - SkDisplayable* displayable = (SkDisplayable*) operand->fObject; - switch (displayable->getType()) { - case SkType_Array: { - SkDisplayArray* boxedValue = (SkDisplayArray*) displayable; - operand->fArray = new SkOpArray(SkAnimatorScript2::ToOpType(boxedValue->values.getType())); - int count = boxedValue->values.count(); - operand->fArray->setCount(count); - memcpy(operand->fArray->begin(), boxedValue->values.begin(), count * sizeof(SkOperand2)); - fEngine->track(operand->fArray); - } break; - case SkType_Boolean: { - SkDisplayBoolean* boxedValue = (SkDisplayBoolean*) displayable; - operand->fS32 = boxedValue->value; - } break; - case SkType_Int: { - SkDisplayInt* boxedValue = (SkDisplayInt*) displayable; - operand->fS32 = boxedValue->value; - } break; - case SkType_Float: { - SkDisplayFloat* boxedValue = (SkDisplayFloat*) displayable; - operand->fScalar = boxedValue->value; - } break; - case SkType_String: { - SkDisplayString* boxedValue = (SkDisplayString*) displayable; - operand->fString = new SkString(boxedValue->value); - } break; - default: { - const char* id; - bool success = fEngine->getMaker().findKey(displayable, &id); - SkASSERT(success); - operand->fString = new SkString(id); - } - } - return true; - } - - virtual SkOperand2::OpType getReturnType(int /*index*/, SkOperand2* operand) { - SkDisplayable* displayable = (SkDisplayable*) operand->fObject; - switch (displayable->getType()) { - case SkType_Array: - return SkOperand2::kArray; - case SkType_Int: - return SkOperand2::kS32; - case SkType_Float: - return SkOperand2::kScalar; - case SkType_String: - default: - return SkOperand2::kString; - } - } - - virtual Type getType() const { - return kUnbox; - } - - SkAnimatorScript2* fEngine; -}; - -SkAnimatorScript2::SkAnimatorScript2(SkAnimateMaker& maker, SkDisplayable* working, SkDisplayTypes type) : - SkScriptEngine2(ToOpType(type)), fMaker(maker), fWorking(working) { - *fCallBackArray.append() = new SkAnimatorScript_Member(this); - *fCallBackArray.append() = new SkAnimatorScript_MemberFunction(this); - *fCallBackArray.append() = new SkAnimatorScript_Box(); - *fCallBackArray.append() = new SkAnimatorScript_Unbox(this); - *fCallBackArray.append() = new SkAnimatorScript_ID(this); - if (type == SkType_ARGB) { - *fCallBackArray.append() = new SkAnimatorScript_RGB(); - *fCallBackArray.append() = new SkAnimatorScript_NamedColor(); - } - if (SkDisplayType::IsEnum(&maker, type)) { - // !!! for SpiderMonkey, iterate through the enum values, and map them to globals - const SkDisplayEnumMap& map = GetEnumValues(type); - *fCallBackArray.append() = new SkAnimatorScript_Enum(map.fValues); - } - *fCallBackArray.append() = new SkAnimatorScript_Eval(this); -#if 0 // !!! no extra support for now - for (SkExtras** extraPtr = maker.fExtras.begin(); extraPtr < maker.fExtras.end(); extraPtr++) { - SkExtras* extra = *extraPtr; - if (extra->fExtraCallBack) - *fCallBackArray.append() = new propertyCallBack(extra->fExtraCallBack, extra->fExtraStorage); - } -#endif -} - -SkAnimatorScript2::~SkAnimatorScript2() { - SkScriptCallBack** end = fCallBackArray.end(); - for (SkScriptCallBack** ptr = fCallBackArray.begin(); ptr < end; ptr++) - delete *ptr; -} - -bool SkAnimatorScript2::evalMemberCommon(const SkMemberInfo* info, - SkDisplayable* displayable, SkOperand2* value) { - SkDisplayTypes original; - SkDisplayTypes type = original = (SkDisplayTypes) info->getType(); - if (info->fType == SkType_Array) - type = SkType_Array; - switch (type) { - case SkType_ARGB: - type = SkType_Int; - case SkType_Boolean: - case SkType_Int: - case SkType_MSec: - case SkType_Float: - SkASSERT(info->getCount() == 1); - if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) - value->fS32 = *(int32_t*) info->memberData(displayable); // OK for SkScalar too - if (type == SkType_MSec) { - value->fScalar = value->fS32 * 0.001f; - type = SkType_Float; - } - break; - case SkType_String: { - SkString* displayableString; - if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) { - info->getString(displayable, &displayableString); - value->fString = new SkString(*displayableString); - } - } break; - case SkType_Array: { - SkASSERT(info->fType != SkType_MemberProperty); // !!! incomplete - SkTDOperandArray* displayableArray = (SkTDOperandArray*) info->memberData(displayable); - if (displayable->getType() == SkType_Array) { - SkDisplayArray* typedArray = (SkDisplayArray*) displayable; - original = typedArray->values.getType(); - } - SkASSERT(original != SkType_Unknown); - SkOpArray* array = value->fArray = new SkOpArray(ToOpType(original)); - track(array); - int count = displayableArray->count(); - if (count > 0) { - array->setCount(count); - memcpy(array->begin(), displayableArray->begin(), count * sizeof(SkOperand2)); - } - } break; - default: - SkASSERT(0); // unimplemented - } - return true; -} - -const SkDisplayEnumMap& SkAnimatorScript2::GetEnumValues(SkDisplayTypes type) { - int index = SkTSearch(&gEnumMaps[0].fType, gEnumMapCount, type, - sizeof(SkDisplayEnumMap)); - SkASSERT(index >= 0); - return gEnumMaps[index]; -} - -SkDisplayTypes SkAnimatorScript2::ToDisplayType(SkOperand2::OpType type) { - int val = type; - switch (val) { - case SkOperand2::kNoType: - return SkType_Unknown; - case SkOperand2::kS32: - return SkType_Int; - case SkOperand2::kScalar: - return SkType_Float; - case SkOperand2::kString: - return SkType_String; - case SkOperand2::kArray: - return SkType_Array; - case SkOperand2::kObject: - return SkType_Displayable; - default: - SkASSERT(0); - return SkType_Unknown; - } -} - -SkOperand2::OpType SkAnimatorScript2::ToOpType(SkDisplayTypes type) { - if (SkDisplayType::IsDisplayable(nullptr /* fMaker */, type)) - return SkOperand2::kObject; - if (SkDisplayType::IsEnum(nullptr /* fMaker */, type)) - return SkOperand2::kS32; - switch (type) { - case SkType_ARGB: - case SkType_MSec: - case SkType_Int: - return SkOperand2::kS32; - case SkType_Float: - case SkType_Point: - case SkType_3D_Point: - return SkOperand2::kScalar; - case SkType_Base64: - case SkType_DynamicString: - case SkType_String: - return SkOperand2::kString; - case SkType_Array: - return SkOperand2::kArray; - case SkType_Unknown: - return SkOperand2::kNoType; - default: - SkASSERT(0); - return SkOperand2::kNoType; - } -} - -bool SkAnimatorScript2::MapEnums(const char* ptr, const char* match, size_t len, int* value) { - int index = 0; - bool more = true; - do { - const char* last = strchr(ptr, '|'); - if (last == nullptr) { - last = &ptr[strlen(ptr)]; - more = false; - } - size_t length = last - ptr; - if (len == length && strncmp(ptr, match, length) == 0) { - *value = index; - return true; - } - index++; - ptr = last + 1; - } while (more); - return false; -} - -#if defined SK_DEBUG - -#include "SkAnimator.h" - -static const char scriptTestSetup[] = -"" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" -""; - -static const SkScriptNAnswer scriptTests[] = { - { "alpha+alpha", SkType_String, 0, 0, "abcabc" }, - { "0 ? Math.sin(0) : 1", SkType_Int, 1 }, - { "intArray[4]", SkType_Unknown }, - { "emptyArray[4]", SkType_Unknown }, - { "idx", SkType_Int, 2 }, - { "intArray.length", SkType_Int, 3 }, - { "intArray.values[0]", SkType_Int, 1 }, - { "intArray[0]", SkType_Int, 1 }, - { "idx.value", SkType_Int, 2 }, - { "alpha.value", SkType_String, 0, 0, "abc" }, - { "alpha", SkType_String, 0, 0, "abc" }, - { "alpha.value+alpha.value", SkType_String, 0, 0, "abcabc" }, - { "alpha+idx", SkType_String, 0, 0, "abc2" }, - { "idx+alpha", SkType_String, 0, 0, "2abc" }, - { "intArray[idx]", SkType_Int, 6 }, - { "alpha.slice(1,2)", SkType_String, 0, 0, "b" }, - { "alpha.value.slice(1,2)", SkType_String, 0, 0, "b" }, - { "Math.sin(0)", SkType_Float, 0, SkIntToScalar(0) }, - { "testRect.left+2", SkType_Float, 0, SkIntToScalar(3) }, - { "0 ? intArray[0] : 1", SkType_Int, 1 }, - { "0 ? intArray.values[0] : 1", SkType_Int, 1 }, - { "0 ? idx : 1", SkType_Int, 1 }, - { "0 ? idx.value : 1", SkType_Int, 1 }, - { "0 ? alpha.slice(1,2) : 1", SkType_Int, 1 }, - { "0 ? alpha.value.slice(1,2) : 1", SkType_Int, 1 }, - { "idy", SkType_Int, 3 } -}; - -#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) - -void SkAnimatorScript2::UnitTest() { -#if defined(SK_SUPPORT_UNITTEST) - SkAnimator animator; - SkASSERT(animator.decodeMemory(scriptTestSetup, sizeof(scriptTestSetup)-1)); - SkEvent evt; - evt.setString("id", "evt"); - evt.setS32("x", 3); - animator.doUserEvent(evt); - // set up animator with memory script above, then run value tests - for (int index = 0; index < SkScriptNAnswer_testCount; index++) { - SkAnimatorScript2 engine(*animator.fMaker, nullptr, scriptTests[index].fType); - SkScriptValue2 value; - const char* script = scriptTests[index].fScript; - bool success = engine.evaluateScript(&script, &value); - if (success == false) { - SkASSERT(scriptTests[index].fType == SkType_Unknown); - continue; - } - SkASSERT(value.fType == ToOpType(scriptTests[index].fType)); - SkScalar error; - switch (value.fType) { - case SkOperand2::kS32: - SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); - break; - case SkOperand2::kScalar: - error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); - SkASSERT(error < SK_Scalar1 / 10000); - break; - case SkOperand2::kString: - SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer)); - break; - default: - SkASSERT(0); - } - } -#endif -} - -#endif diff --git a/gfx/skia/skia/src/animator/SkAnimatorScript2.h b/gfx/skia/skia/src/animator/SkAnimatorScript2.h deleted file mode 100644 index c3995f6fd812..000000000000 --- a/gfx/skia/skia/src/animator/SkAnimatorScript2.h +++ /dev/null @@ -1,50 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkAnimatorScript2_DEFINED -#define SkAnimatorScript2_DEFINED - -#include "SkDisplayable.h" -#include "SkScript2.h" -#include "SkTypedArray.h" - -class SkAnimateMaker; -struct SkMemberInfo; - -#ifndef SkAnimatorScript_DEFINED -struct SkDisplayEnumMap { - SkDisplayTypes fType; - const char* fValues; -}; -#endif - -class SkAnimatorScript2 : public SkScriptEngine2 { -public: - SkAnimatorScript2(SkAnimateMaker& , SkDisplayable* working, SkDisplayTypes type); - ~SkAnimatorScript2(); - bool evalMemberCommon(const SkMemberInfo* info, - SkDisplayable* displayable, SkOperand2* value); - SkAnimateMaker& getMaker() { return fMaker; } - SkDisplayable* getWorking() { return fWorking; } - static bool MapEnums(const char* ptr, const char* match, size_t len, int* value); - static const SkDisplayEnumMap& GetEnumValues(SkDisplayTypes type); - static SkDisplayTypes ToDisplayType(SkOperand2::OpType type); - static SkOperand2::OpType ToOpType(SkDisplayTypes type); -private: - SkAnimateMaker& fMaker; - SkDisplayable* fWorking; - friend class SkDump; - friend struct SkScriptNAnswer; - // illegal - SkAnimatorScript2& operator=(const SkAnimatorScript2&); -#ifdef SK_DEBUG -public: - static void UnitTest(); -#endif -}; - -#endif // SkAnimatorScript2_DEFINED diff --git a/gfx/skia/skia/src/animator/SkBoundable.cpp b/gfx/skia/skia/src/animator/SkBoundable.cpp deleted file mode 100644 index e784e9f6d0e1..000000000000 --- a/gfx/skia/skia/src/animator/SkBoundable.cpp +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkBoundable.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" - -SkBoundable::SkBoundable() { - clearBounds(); - fBounds.fTop = 0; - fBounds.fRight = 0; - fBounds.fBottom = 0; -} - -void SkBoundable::clearBounder() { - fBounds.fLeft = 0x7fff; -} - -void SkBoundable::getBounds(SkRect* rect) { - SkASSERT(rect); - if (fBounds.fLeft == (int16_t)0x8000U) { - INHERITED::getBounds(rect); - return; - } - rect->fLeft = SkIntToScalar(fBounds.fLeft); - rect->fTop = SkIntToScalar(fBounds.fTop); - rect->fRight = SkIntToScalar(fBounds.fRight); - rect->fBottom = SkIntToScalar(fBounds.fBottom); -} - -void SkBoundable::enableBounder() { - fBounds.fLeft = 0; -} - - -SkBoundableAuto::SkBoundableAuto(SkBoundable* boundable, - SkAnimateMaker& maker) : fBoundable(boundable), fMaker(maker) { - if (fBoundable->hasBounds()) { -// fMaker.fCanvas->setBounder(&maker.fDisplayList); - fMaker.fDisplayList.fBounds.setEmpty(); - } -} - -SkBoundableAuto::~SkBoundableAuto() { - if (fBoundable->hasBounds() == false) - return; -// fMaker.fCanvas->setBounder(nullptr); - fBoundable->setBounds(fMaker.fDisplayList.fBounds); -} diff --git a/gfx/skia/skia/src/animator/SkBoundable.h b/gfx/skia/skia/src/animator/SkBoundable.h deleted file mode 100644 index 48d1306235bf..000000000000 --- a/gfx/skia/skia/src/animator/SkBoundable.h +++ /dev/null @@ -1,41 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkBoundable_DEFINED -#define SkBoundable_DEFINED - -#include "SkADrawable.h" -#include "SkRect.h" - -class SkBoundable : public SkADrawable { -public: - SkBoundable(); - virtual void clearBounder(); - virtual void enableBounder(); - virtual void getBounds(SkRect* ); - bool hasBounds() { return fBounds.fLeft != (int16_t)0x8000U; } - void setBounds(SkIRect& bounds) { fBounds = bounds; } -protected: - void clearBounds() { fBounds.fLeft = (int16_t) SkToU16(0x8000); }; // mark bounds as unset - SkIRect fBounds; -private: - typedef SkADrawable INHERITED; -}; - -class SkBoundableAuto { -public: - SkBoundableAuto(SkBoundable* boundable, SkAnimateMaker& maker); - ~SkBoundableAuto(); -private: - SkBoundable* fBoundable; - SkAnimateMaker& fMaker; - SkBoundableAuto& operator= (const SkBoundableAuto& ); -}; - -#endif // SkBoundable_DEFINED diff --git a/gfx/skia/skia/src/animator/SkBuildCondensedInfo.cpp b/gfx/skia/skia/src/animator/SkBuildCondensedInfo.cpp deleted file mode 100644 index 84a591f2c7dc..000000000000 --- a/gfx/skia/skia/src/animator/SkBuildCondensedInfo.cpp +++ /dev/null @@ -1,282 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkTypes.h" -#if defined SK_BUILD_CONDENSED -#include "SkMemberInfo.h" -#if SK_USE_CONDENSED_INFO == 1 -#error "SK_USE_CONDENSED_INFO must be zero to build condensed info" -#endif -#if !defined SK_BUILD_FOR_WIN32 -#error "SK_BUILD_FOR_WIN32 must be defined to build condensed info" -#endif -#include "SkDisplayType.h" -#include "SkIntArray.h" -#include - -SkTDMemberInfoArray gInfos; -SkTDIntArray gInfosCounts; -SkTDDisplayTypesArray gInfosTypeIDs; -SkTDMemberInfoArray gUnknowns; -SkTDIntArray gUnknownsCounts; - -static void AddInfo(SkDisplayTypes type, const SkMemberInfo* info, int infoCount) { - SkASSERT(gInfos[type] == nullptr); - gInfos[type] = info; - gInfosCounts[type] = infoCount; - *gInfosTypeIDs.append() = type; - size_t allStrs = 0; - for (int inner = 0; inner < infoCount; inner++) { - SkASSERT(info[inner].fCount < 256); - int offset = (int) info[inner].fOffset; - SkASSERT(offset < 128 && offset > -129); - SkASSERT(allStrs < 256); - if (info[inner].fType == SkType_BaseClassInfo) { - const SkMemberInfo* innerInfo = (const SkMemberInfo*) info[inner].fName; - if (gUnknowns.find(innerInfo) == -1) { - *gUnknowns.append() = innerInfo; - *gUnknownsCounts.append() = info[inner].fCount; - } - } - if (info[inner].fType != SkType_BaseClassInfo && info[inner].fName) - allStrs += strlen(info[inner].fName); - allStrs += 1; - SkASSERT(info[inner].fType < 256); - } -} - -static void WriteInfo(FILE* condensed, const SkMemberInfo* info, int infoCount, - const char* typeName, bool draw, bool display) { - fprintf(condensed, "static const char g%sStrings[] = \n", typeName); - int inner; - // write strings - for (inner = 0; inner < infoCount; inner++) { - const char* name = (info[inner].fType != SkType_BaseClassInfo && info[inner].fName) ? - info[inner].fName : ""; - const char* zero = inner < infoCount - 1 ? "\\0" : ""; - fprintf(condensed, "\t\"%s%s\"\n", name, zero); - } - fprintf(condensed, ";\n\nstatic const SkMemberInfo g%s", draw ? "Draw" : display ? "Display" : ""); - fprintf(condensed, "%sInfo[] = {", typeName); - size_t nameOffset = 0; - // write info tables - for (inner = 0; inner < infoCount; inner++) { - size_t offset = info[inner].fOffset; - if (info[inner].fType == SkType_BaseClassInfo) { - offset = (size_t) gInfos.find((const SkMemberInfo* ) info[inner].fName); - SkASSERT((int) offset >= 0); - offset = gInfosTypeIDs.find((SkDisplayTypes) offset); - SkASSERT((int) offset >= 0); - } - fprintf(condensed, "\n\t{%d, %d, %d, %d}", nameOffset, offset, - info[inner].fType, info[inner].fCount); - if (inner < infoCount - 1) - putc(',', condensed); - if (info[inner].fType != SkType_BaseClassInfo && info[inner].fName) - nameOffset += strlen(info[inner].fName); - nameOffset += 1; - } - fprintf(condensed, "\n};\n\n"); -} - -static void Get3DName(char* scratch, const char* name) { - if (strncmp("skia3d:", name, sizeof("skia3d:") - 1) == 0) { - strcpy(scratch, "3D_"); - scratch[3]= name[7] & ~0x20; - strcpy(&scratch[4], &name[8]); - } else { - scratch[0] = name[0] & ~0x20; - strcpy(&scratch[1], &name[1]); - } -} - -int type_compare(const void* a, const void* b) { - SkDisplayTypes first = *(SkDisplayTypes*) a; - SkDisplayTypes second = *(SkDisplayTypes*) b; - return first < second ? -1 : first == second ? 0 : 1; -} - -void SkDisplayType::BuildCondensedInfo(SkAnimateMaker* maker) { - gInfos.setCount(kNumberOfTypes); - memset(gInfos.begin(), 0, sizeof(gInfos[0]) * kNumberOfTypes); - gInfosCounts.setCount(kNumberOfTypes); - memset(gInfosCounts.begin(), -1, sizeof(gInfosCounts[0]) * kNumberOfTypes); - // check to see if it is condensable - int index, infoCount; - for (index = 0; index < kTypeNamesSize; index++) { - const SkMemberInfo* info = GetMembers(maker, gTypeNames[index].fType, &infoCount); - if (info == nullptr) - continue; - AddInfo(gTypeNames[index].fType, info, infoCount); - } - const SkMemberInfo* extraInfo = - SkDisplayType::GetMembers(maker, SkType_3D_Point, &infoCount); - AddInfo(SkType_Point, extraInfo, infoCount); - AddInfo(SkType_3D_Point, extraInfo, infoCount); -// int baseInfos = gInfos.count(); - do { - SkTDMemberInfoArray oldRefs = gUnknowns; - SkTDIntArray oldRefCounts = gUnknownsCounts; - gUnknowns.reset(); - gUnknownsCounts.reset(); - for (index = 0; index < oldRefs.count(); index++) { - const SkMemberInfo* info = oldRefs[index]; - if (gInfos.find(info) == -1) { - int typeIndex = 0; - for (; typeIndex < kNumberOfTypes; typeIndex++) { - const SkMemberInfo* temp = SkDisplayType::GetMembers( - maker, (SkDisplayTypes) typeIndex, nullptr); - if (temp == info) - break; - } - SkASSERT(typeIndex < kNumberOfTypes); - AddInfo((SkDisplayTypes) typeIndex, info, oldRefCounts[index]); - } - } - } while (gUnknowns.count() > 0); - qsort(gInfosTypeIDs.begin(), gInfosTypeIDs.count(), sizeof(gInfosTypeIDs[0]), &type_compare); -#ifdef SK_DEBUG - FILE* condensed = fopen("../../src/animator/SkCondensedDebug.inc", "w+"); - fprintf(condensed, "#include \"SkTypes.h\"\n"); - fprintf(condensed, "#ifdef SK_DEBUG\n"); -#else - FILE* condensed = fopen("../../src/animator/SkCondensedRelease.inc", "w+"); - fprintf(condensed, "#include \"SkTypes.h\"\n"); - fprintf(condensed, "#ifdef SK_RELEASE\n"); -#endif - // write header - fprintf(condensed, "// This file was automatically generated.\n"); - fprintf(condensed, "// To change it, edit the file with the matching debug info.\n"); - fprintf(condensed, "// Then execute SkDisplayType::BuildCondensedInfo() to " - "regenerate this file.\n\n"); - // write name of memberInfo - int typeNameIndex = 0; - int unknown = 1; - for (index = 0; index < gInfos.count(); index++) { - const SkMemberInfo* info = gInfos[index]; - if (info == nullptr) - continue; - char scratch[64]; - bool drawPrefix, displayPrefix; - while (gTypeNames[typeNameIndex].fType < index) - typeNameIndex++; - if (gTypeNames[typeNameIndex].fType == index) { - Get3DName(scratch, gTypeNames[typeNameIndex].fName); - drawPrefix = gTypeNames[typeNameIndex].fDrawPrefix; - displayPrefix = gTypeNames[typeNameIndex].fDisplayPrefix; - } else { - sprintf(scratch, "Unknown%d", unknown++); - drawPrefix = displayPrefix = false; - } - WriteInfo(condensed, info, gInfosCounts[index], scratch, drawPrefix, displayPrefix); - } - // write array of table pointers -// start here; - fprintf(condensed, "static const SkMemberInfo* const gInfoTables[] = {"); - typeNameIndex = 0; - unknown = 1; - for (index = 0; index < gInfos.count(); index++) { - const SkMemberInfo* info = gInfos[index]; - if (info == nullptr) - continue; - char scratch[64]; - bool drawPrefix, displayPrefix; - while (gTypeNames[typeNameIndex].fType < index) - typeNameIndex++; - if (gTypeNames[typeNameIndex].fType == index) { - Get3DName(scratch, gTypeNames[typeNameIndex].fName); - drawPrefix = gTypeNames[typeNameIndex].fDrawPrefix; - displayPrefix = gTypeNames[typeNameIndex].fDisplayPrefix; - } else { - sprintf(scratch, "Unknown%d", unknown++); - drawPrefix = displayPrefix = false; - } - fprintf(condensed, "\n\tg"); - if (drawPrefix) - fprintf(condensed, "Draw"); - if (displayPrefix) - fprintf(condensed, "Display"); - fprintf(condensed, "%sInfo", scratch); - if (index < gInfos.count() - 1) - putc(',', condensed); - } - fprintf(condensed, "\n};\n\n"); - // write the array of number of entries in the info table - fprintf(condensed, "static const unsigned char gInfoCounts[] = {\n\t"); - int written = 0; - for (index = 0; index < gInfosCounts.count(); index++) { - int count = gInfosCounts[index]; - if (count < 0) - continue; - if (written > 0) - putc(',', condensed); - if (written % 20 == 19) - fprintf(condensed, "\n\t"); - fprintf(condensed, "%d",count); - written++; - } - fprintf(condensed, "\n};\n\n"); - // write array of type ids table entries correspond to - fprintf(condensed, "static const unsigned char gTypeIDs[] = {\n\t"); - int typeIDCount = 0; - typeNameIndex = 0; - unknown = 1; - for (index = 0; index < gInfosCounts.count(); index++) { - const SkMemberInfo* info = gInfos[index]; - if (info == nullptr) - continue; - typeIDCount++; - char scratch[64]; - while (gTypeNames[typeNameIndex].fType < index) - typeNameIndex++; - if (gTypeNames[typeNameIndex].fType == index) { - Get3DName(scratch, gTypeNames[typeNameIndex].fName); - } else - sprintf(scratch, "Unknown%d", unknown++); - fprintf(condensed, "%d%c // %s\n\t", index, - index < gInfosCounts.count() ? ',' : ' ', scratch); - } - fprintf(condensed, "\n};\n\n"); - fprintf(condensed, "static const int kTypeIDs = %d;\n\n", typeIDCount); - // write the array of string pointers - fprintf(condensed, "static const char* const gInfoNames[] = {"); - typeNameIndex = 0; - unknown = 1; - written = 0; - for (index = 0; index < gInfosCounts.count(); index++) { - const SkMemberInfo* info = gInfos[index]; - if (info == nullptr) - continue; - if (written > 0) - putc(',', condensed); - written++; - fprintf(condensed, "\n\tg"); - char scratch[64]; - while (gTypeNames[typeNameIndex].fType < index) - typeNameIndex++; - if (gTypeNames[typeNameIndex].fType == index) { - Get3DName(scratch, gTypeNames[typeNameIndex].fName); - } else - sprintf(scratch, "Unknown%d", unknown++); - fprintf(condensed, "%sStrings", scratch); - } - fprintf(condensed, "\n};\n\n"); - fprintf(condensed, "#endif\n"); - fclose(condensed); - gInfos.reset(); - gInfosCounts.reset(); - gInfosTypeIDs.reset(); - gUnknowns.reset(); - gUnknownsCounts.reset(); -} - -#elif defined SK_DEBUG -#include "SkDisplayType.h" -void SkDisplayType::BuildCondensedInfo(SkAnimateMaker* ) {} -#endif diff --git a/gfx/skia/skia/src/animator/SkCondensedDebug.inc b/gfx/skia/skia/src/animator/SkCondensedDebug.inc deleted file mode 100644 index dcebe00469ce..000000000000 --- a/gfx/skia/skia/src/animator/SkCondensedDebug.inc +++ /dev/null @@ -1,1387 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkTypes.h" -#ifndef SK_BUILD_FOR_UNIX -#ifdef SK_DEBUG -// This file was automatically generated. -// To change it, edit the file with the matching debug info. -// Then execute SkDisplayType::BuildCondensedInfo() to regenerate this file. - -static const char gMathStrings[] = - "E\0" - "LN10\0" - "LN2\0" - "LOG10E\0" - "LOG2E\0" - "PI\0" - "SQRT1_2\0" - "SQRT2\0" - "abs\0" - "acos\0" - "asin\0" - "atan\0" - "atan2\0" - "ceil\0" - "cos\0" - "exp\0" - "floor\0" - "log\0" - "max\0" - "min\0" - "pow\0" - "random\0" - "round\0" - "sin\0" - "sqrt\0" - "tan" -; - -static const SkMemberInfo gMathInfo[] = { - {0, -1, 67, 98}, - {2, -2, 67, 98}, - {7, -3, 67, 98}, - {11, -4, 67, 98}, - {18, -5, 67, 98}, - {24, -6, 67, 98}, - {27, -7, 67, 98}, - {35, -8, 67, 98}, - {41, -1, 66, 98}, - {45, -2, 66, 98}, - {50, -3, 66, 98}, - {55, -4, 66, 98}, - {60, -5, 66, 98}, - {66, -6, 66, 98}, - {71, -7, 66, 98}, - {75, -8, 66, 98}, - {79, -9, 66, 98}, - {85, -10, 66, 98}, - {89, -11, 66, 98}, - {93, -12, 66, 98}, - {97, -13, 66, 98}, - {101, -14, 66, 98}, - {108, -15, 66, 98}, - {114, -16, 66, 98}, - {118, -17, 66, 98}, - {123, -18, 66, 98} -}; - -static const char gAddStrings[] = - "inPlace\0" - "offset\0" - "use\0" - "where" -; - -static const SkMemberInfo gAddInfo[] = { - {0, 16, 26, 1}, - {8, 20, 96, 1}, - {15, 24, 37, 1}, - {19, 28, 37, 1} -}; - -static const char gAddCircleStrings[] = - "\0" - "radius\0" - "x\0" - "y" -; - -static const SkMemberInfo gAddCircleInfo[] = { - {0, 3, 18, 1}, - {1, 24, 98, 1}, - {8, 28, 98, 1}, - {10, 32, 98, 1} -}; - -static const char gUnknown1Strings[] = - "direction" -; - -static const SkMemberInfo gUnknown1Info[] = { - {0, 20, 75, 1} -}; - -static const char gAddOvalStrings[] = - "" -; - -static const SkMemberInfo gAddOvalInfo[] = { - {0, 6, 18, 5} -}; - -static const char gAddPathStrings[] = - "matrix\0" - "path" -; - -static const SkMemberInfo gAddPathInfo[] = { - {0, 20, 65, 1}, - {7, 24, 74, 1} -}; - -static const char gAddRectangleStrings[] = - "\0" - "bottom\0" - "left\0" - "right\0" - "top" -; - -static const SkMemberInfo gAddRectangleInfo[] = { - {0, 3, 18, 1}, - {1, 36, 98, 1}, - {8, 24, 98, 1}, - {13, 32, 98, 1}, - {19, 28, 98, 1} -}; - -static const char gAddRoundRectStrings[] = - "\0" - "rx\0" - "ry" -; - -static const SkMemberInfo gAddRoundRectInfo[] = { - {0, 6, 18, 5}, - {1, 40, 98, 1}, - {4, 44, 98, 1} -}; - -static const char gUnknown2Strings[] = - "begin\0" - "blend\0" - "dur\0" - "dynamic\0" - "field\0" - "formula\0" - "from\0" - "mirror\0" - "repeat\0" - "reset\0" - "target\0" - "to\0" - "values" -; - -static const SkMemberInfo gUnknown2Info[] = { - {0, 16, 71, 1}, - {6, 20, 119, 98}, - {12, 36, 71, 1}, - {16, -1, 67, 26}, - {24, 40, 108, 2}, - {30, 48, 40, 2}, - {38, 56, 40, 2}, - {43, -2, 67, 26}, - {50, 64, 98, 1}, - {57, -3, 67, 26}, - {63, 68, 40, 2}, - {70, 76, 40, 2}, - {73, -4, 67, 40} -}; - -static const char gAnimateFieldStrings[] = - "" -; - -static const SkMemberInfo gAnimateFieldInfo[] = { - {0, 8, 18, 13} -}; - -static const char gApplyStrings[] = - "animator\0" - "begin\0" - "dontDraw\0" - "dynamicScope\0" - "interval\0" - "mode\0" - "pickup\0" - "restore\0" - "scope\0" - "step\0" - "steps\0" - "time\0" - "transition" -; - -static const SkMemberInfo gApplyInfo[] = { - {0, -1, 67, 10}, - {9, 16, 71, 1}, - {15, 20, 26, 1}, - {24, 24, 108, 2}, - {37, 32, 71, 1}, - {46, 36, 13, 1}, - {51, 40, 26, 1}, - {58, 44, 26, 1}, - {66, 48, 37, 1}, - {72, -2, 67, 96}, - {77, 52, 96, 1}, - {83, -3, 67, 71}, - {88, 56, 14, 1} -}; - -static const char gUnknown3Strings[] = - "x\0" - "y" -; - -static const SkMemberInfo gUnknown3Info[] = { - {0, 48, 98, 1}, - {2, 52, 98, 1} -}; - -static const char gBitmapStrings[] = - "\0" - "erase\0" - "format\0" - "height\0" - "rowBytes\0" - "width" -; - -static const SkMemberInfo gDrawBitmapInfo[] = { - {0, 11, 18, 2}, - {1, -1, 67, 15}, - {7, 56, 21, 1}, - {14, 60, 96, 1}, - {21, 64, 96, 1}, - {30, 68, 96, 1} -}; - -static const char gBitmapShaderStrings[] = - "\0" - "filterType\0" - "image" -; - -static const SkMemberInfo gDrawBitmapShaderInfo[] = { - {0, 67, 18, 2}, - {1, 28, 47, 1}, - {12, 32, 17, 1} -}; - -static const char gBlurStrings[] = - "blurStyle\0" - "radius" -; - -static const SkMemberInfo gDrawBlurInfo[] = { - {0, 24, 63, 1}, - {10, 20, 98, 1} -}; - -static const char gBoundsStrings[] = - "\0" - "inval" -; - -static const SkMemberInfo gDisplayBoundsInfo[] = { - {0, 58, 18, 7}, - {1, 44, 26, 1} -}; - -static const char gClipStrings[] = - "path\0" - "rectangle" -; - -static const SkMemberInfo gDrawClipInfo[] = { - {0, 20, 74, 1}, - {5, 16, 91, 1} -}; - -static const char gColorStrings[] = - "alpha\0" - "blue\0" - "color\0" - "green\0" - "hue\0" - "red\0" - "saturation\0" - "value" -; - -static const SkMemberInfo gDrawColorInfo[] = { - {0, -1, 67, 98}, - {6, -2, 67, 98}, - {11, 20, 15, 1}, - {17, -3, 67, 98}, - {23, -4, 67, 98}, - {27, -5, 67, 98}, - {31, -6, 67, 98}, - {42, -7, 67, 98} -}; - -static const char gCubicToStrings[] = - "x1\0" - "x2\0" - "x3\0" - "y1\0" - "y2\0" - "y3" -; - -static const SkMemberInfo gCubicToInfo[] = { - {0, 20, 98, 1}, - {3, 28, 98, 1}, - {6, 36, 98, 1}, - {9, 24, 98, 1}, - {12, 32, 98, 1}, - {15, 40, 98, 1} -}; - -static const char gDashStrings[] = - "intervals\0" - "phase" -; - -static const SkMemberInfo gDashInfo[] = { - {0, 20, 119, 98}, - {10, 36, 98, 1} -}; - -static const char gDataStrings[] = - "\0" - "name" -; - -static const SkMemberInfo gDataInfo[] = { - {0, 33, 18, 3}, - {1, 32, 108, 2} -}; - -static const char gDiscreteStrings[] = - "deviation\0" - "segLength" -; - -static const SkMemberInfo gDiscreteInfo[] = { - {0, 20, 98, 1}, - {10, 24, 98, 1} -}; - -static const char gDrawToStrings[] = - "drawOnce\0" - "use" -; - -static const SkMemberInfo gDrawToInfo[] = { - {0, 72, 26, 1}, - {9, 76, 19, 1} -}; - -static const char gDumpStrings[] = - "displayList\0" - "eventList\0" - "events\0" - "groups\0" - "name\0" - "posts" -; - -static const SkMemberInfo gDumpInfo[] = { - {0, 16, 26, 1}, - {12, 20, 26, 1}, - {22, 24, 26, 1}, - {29, 36, 26, 1}, - {36, 28, 108, 2}, - {41, 40, 26, 1} -}; - -static const char gEmbossStrings[] = - "ambient\0" - "direction\0" - "radius\0" - "specular" -; - -static const SkMemberInfo gDrawEmbossInfo[] = { - {0, -1, 67, 98}, - {8, 20, 119, 98}, - {18, 36, 98, 1}, - {25, -2, 67, 98} -}; - -static const char gEventStrings[] = - "code\0" - "disable\0" - "key\0" - "keys\0" - "kind\0" - "target\0" - "x\0" - "y" -; - -static const SkMemberInfo gDisplayEventInfo[] = { - {0, 16, 43, 1}, - {5, 20, 26, 1}, - {13, -1, 67, 108}, - {17, -2, 67, 108}, - {22, 24, 44, 1}, - {27, 28, 108, 2}, - {34, 36, 98, 1}, - {36, 40, 98, 1} -}; - -static const char gFromPathStrings[] = - "mode\0" - "offset\0" - "path" -; - -static const SkMemberInfo gFromPathInfo[] = { - {0, 20, 49, 1}, - {5, 24, 98, 1}, - {12, 28, 74, 1} -}; - -static const char gUnknown4Strings[] = - "\0" - "offsets\0" - "unitMapper" -; - -static const SkMemberInfo gUnknown4Info[] = { - {0, 67, 18, 2}, - {1, 28, 119, 98}, - {9, 44, 108, 2} -}; - -static const char gGStrings[] = - "condition\0" - "enableCondition" -; - -static const SkMemberInfo gGInfo[] = { - {0, 16, 40, 2}, - {10, 24, 40, 2} -}; - -static const char gHitClearStrings[] = - "targets" -; - -static const SkMemberInfo gHitClearInfo[] = { - {0, 16, 119, 36} -}; - -static const char gHitTestStrings[] = - "bullets\0" - "hits\0" - "targets\0" - "value" -; - -static const SkMemberInfo gHitTestInfo[] = { - {0, 16, 119, 36}, - {8, 32, 119, 96}, - {13, 48, 119, 36}, - {21, 64, 26, 1} -}; - -static const char gImageStrings[] = - "\0" - "base64\0" - "src" -; - -static const SkMemberInfo gImageInfo[] = { - {0, 11, 18, 2}, - {1, 56, 16, 2}, - {8, 64, 108, 2} -}; - -static const char gIncludeStrings[] = - "src" -; - -static const SkMemberInfo gIncludeInfo[] = { - {0, 16, 108, 2} -}; - -static const char gInputStrings[] = - "s32\0" - "scalar\0" - "string" -; - -static const SkMemberInfo gInputInfo[] = { - {0, 16, 96, 1}, - {4, 20, 98, 1}, - {11, 24, 108, 2} -}; - -static const char gLineStrings[] = - "x1\0" - "x2\0" - "y1\0" - "y2" -; - -static const SkMemberInfo gLineInfo[] = { - {0, 24, 98, 1}, - {3, 28, 98, 1}, - {6, 32, 98, 1}, - {9, 36, 98, 1} -}; - -static const char gLineToStrings[] = - "x\0" - "y" -; - -static const SkMemberInfo gLineToInfo[] = { - {0, 20, 98, 1}, - {2, 24, 98, 1} -}; - -static const char gLinearGradientStrings[] = - "\0" - "points" -; - -static const SkMemberInfo gLinearGradientInfo[] = { - {0, 27, 18, 3}, - {1, 88, 77, 4} -}; - -static const char gMatrixStrings[] = - "matrix\0" - "perspectX\0" - "perspectY\0" - "rotate\0" - "scale\0" - "scaleX\0" - "scaleY\0" - "skewX\0" - "skewY\0" - "translate\0" - "translateX\0" - "translateY" -; - -static const SkMemberInfo gDrawMatrixInfo[] = { - {0, 16, 119, 98}, - {7, -1, 67, 98}, - {17, -2, 67, 98}, - {27, -3, 67, 98}, - {34, -4, 67, 98}, - {40, -5, 67, 98}, - {47, -6, 67, 98}, - {54, -7, 67, 98}, - {60, -8, 67, 98}, - {66, -9, 67, 77}, - {76, -10, 67, 98}, - {87, -11, 67, 98} -}; - -static const char gMoveStrings[] = - "" -; - -static const SkMemberInfo gMoveInfo[] = { - {0, 1, 18, 4} -}; - -static const char gMoveToStrings[] = - "x\0" - "y" -; - -static const SkMemberInfo gMoveToInfo[] = { - {0, 20, 98, 1}, - {2, 24, 98, 1} -}; - -static const char gMovieStrings[] = - "src" -; - -static const SkMemberInfo gMovieInfo[] = { - {0, 16, 108, 2} -}; - -static const char gOvalStrings[] = - "" -; - -static const SkMemberInfo gOvalInfo[] = { - {0, 58, 18, 7} -}; - -static const char gPaintStrings[] = - "antiAlias\0" - "ascent\0" - "color\0" - "descent\0" - "filterType\0" - "linearText\0" - "maskFilter\0" - "measureText\0" - "pathEffect\0" - "shader\0" - "strikeThru\0" - "stroke\0" - "strokeCap\0" - "strokeJoin\0" - "strokeMiter\0" - "strokeWidth\0" - "style\0" - "textAlign\0" - "textScaleX\0" - "textSize\0" - "textSkewX\0" - "textTracking\0" - "typeface\0" - "underline\0" - "xfermode" -; - -static const SkMemberInfo gDrawPaintInfo[] = { - {0, 16, 26, 1}, - {10, -1, 67, 98}, - {17, 20, 31, 1}, - {23, -2, 67, 98}, - {31, 24, 47, 1}, - {42, 28, 26, 1}, - {53, 32, 62, 1}, - {64, -1, 66, 98}, - {76, 36, 76, 1}, - {87, 40, 102, 1}, - {94, 44, 26, 1}, - {105, 48, 26, 1}, - {112, 52, 27, 1}, - {122, 56, 58, 1}, - {133, 60, 98, 1}, - {145, 64, 98, 1}, - {157, 68, 109, 1}, - {163, 72, 9, 1}, - {173, 76, 98, 1}, - {184, 80, 98, 1}, - {193, 84, 98, 1}, - {203, 88, 98, 1}, - {216, 92, 120, 1}, - {225, 96, 26, 1}, - {235, 100, 121, 1} -}; - -static const char gPathStrings[] = - "d\0" - "fillType\0" - "length" -; - -static const SkMemberInfo gDrawPathInfo[] = { - {0, 52, 108, 2}, - {2, -1, 67, 46}, - {11, -2, 67, 98} -}; - -static const char gUnknown5Strings[] = - "x\0" - "y\0" - "z" -; - -static const SkMemberInfo gUnknown5Info[] = { - {0, 0, 98, 1}, - {2, 4, 98, 1}, - {4, 8, 98, 1} -}; - -static const char gPointStrings[] = - "x\0" - "y" -; - -static const SkMemberInfo gDrawPointInfo[] = { - {0, 16, 98, 1}, - {2, 20, 98, 1} -}; - -static const char gPolyToPolyStrings[] = - "destination\0" - "source" -; - -static const SkMemberInfo gPolyToPolyInfo[] = { - {0, 24, 80, 1}, - {12, 20, 80, 1} -}; - -static const char gPolygonStrings[] = - "" -; - -static const SkMemberInfo gPolygonInfo[] = { - {0, 48, 18, 1} -}; - -static const char gPolylineStrings[] = - "points" -; - -static const SkMemberInfo gPolylineInfo[] = { - {0, 88, 119, 98} -}; - -static const char gPostStrings[] = - "delay\0" - "initialized\0" - "mode\0" - "sink\0" - "target\0" - "type" -; - -static const SkMemberInfo gPostInfo[] = { - {0, 16, 71, 1}, - {6, 20, 26, 1}, - {18, 24, 45, 1}, - {23, -1, 67, 108}, - {28, -2, 67, 108}, - {35, -3, 67, 108} -}; - -static const char gQuadToStrings[] = - "x1\0" - "x2\0" - "y1\0" - "y2" -; - -static const SkMemberInfo gQuadToInfo[] = { - {0, 20, 98, 1}, - {3, 28, 98, 1}, - {6, 24, 98, 1}, - {9, 32, 98, 1} -}; - -static const char gRCubicToStrings[] = - "" -; - -static const SkMemberInfo gRCubicToInfo[] = { - {0, 18, 18, 6} -}; - -static const char gRLineToStrings[] = - "" -; - -static const SkMemberInfo gRLineToInfo[] = { - {0, 35, 18, 2} -}; - -static const char gRMoveToStrings[] = - "" -; - -static const SkMemberInfo gRMoveToInfo[] = { - {0, 39, 18, 2} -}; - -static const char gRQuadToStrings[] = - "" -; - -static const SkMemberInfo gRQuadToInfo[] = { - {0, 50, 18, 4} -}; - -static const char gRadialGradientStrings[] = - "\0" - "center\0" - "radius" -; - -static const SkMemberInfo gRadialGradientInfo[] = { - {0, 27, 18, 3}, - {1, 88, 77, 2}, - {8, 96, 98, 1} -}; - -static const char gRandomStrings[] = - "blend\0" - "max\0" - "min\0" - "random\0" - "seed" -; - -static const SkMemberInfo gDisplayRandomInfo[] = { - {0, 16, 98, 1}, - {6, 24, 98, 1}, - {10, 20, 98, 1}, - {14, 1, 67, 98}, - {21, -2, 67, 96} -}; - -static const char gRectToRectStrings[] = - "destination\0" - "source" -; - -static const SkMemberInfo gRectToRectInfo[] = { - {0, 24, 91, 1}, - {12, 20, 91, 1} -}; - -static const char gRectangleStrings[] = - "bottom\0" - "height\0" - "left\0" - "needsRedraw\0" - "right\0" - "top\0" - "width" -; - -static const SkMemberInfo gRectangleInfo[] = { - {0, 36, 98, 1}, - {7, -1, 67, 98}, - {14, 24, 98, 1}, - {19, -2, 67, 26}, - {31, 32, 98, 1}, - {37, 28, 98, 1}, - {41, -3, 67, 98} -}; - -static const char gRemoveStrings[] = - "offset\0" - "where" -; - -static const SkMemberInfo gRemoveInfo[] = { - {0, 20, 96, 1}, - {7, 28, 37, 1} -}; - -static const char gReplaceStrings[] = - "" -; - -static const SkMemberInfo gReplaceInfo[] = { - {0, 1, 18, 4} -}; - -static const char gRotateStrings[] = - "center\0" - "degrees" -; - -static const SkMemberInfo gRotateInfo[] = { - {0, 24, 77, 2}, - {7, 20, 98, 1} -}; - -static const char gRoundRectStrings[] = - "\0" - "rx\0" - "ry" -; - -static const SkMemberInfo gRoundRectInfo[] = { - {0, 58, 18, 7}, - {1, 44, 98, 1}, - {4, 48, 98, 1} -}; - -static const char gS32Strings[] = - "value" -; - -static const SkMemberInfo gS32Info[] = { - {0, 16, 96, 1} -}; - -static const char gScalarStrings[] = - "value" -; - -static const SkMemberInfo gScalarInfo[] = { - {0, 16, 98, 1} -}; - -static const char gScaleStrings[] = - "center\0" - "x\0" - "y" -; - -static const SkMemberInfo gScaleInfo[] = { - {0, 28, 77, 2}, - {7, 20, 98, 1}, - {9, 24, 98, 1} -}; - -static const char gSetStrings[] = - "begin\0" - "dur\0" - "dynamic\0" - "field\0" - "formula\0" - "reset\0" - "target\0" - "to" -; - -static const SkMemberInfo gSetInfo[] = { - {0, 16, 71, 1}, - {6, 36, 71, 1}, - {10, -1, 67, 26}, - {18, 40, 108, 2}, - {24, 48, 40, 2}, - {32, -3, 67, 26}, - {38, 68, 40, 2}, - {45, 76, 40, 2} -}; - -static const char gShaderStrings[] = - "matrix\0" - "tileMode" -; - -static const SkMemberInfo gShaderInfo[] = { - {0, 20, 65, 1}, - {7, 24, 116, 1} -}; - -static const char gSkewStrings[] = - "center\0" - "x\0" - "y" -; - -static const SkMemberInfo gSkewInfo[] = { - {0, 28, 77, 2}, - {7, 20, 98, 1}, - {9, 24, 98, 1} -}; - -static const char g3D_CameraStrings[] = - "axis\0" - "hackHeight\0" - "hackWidth\0" - "location\0" - "observer\0" - "patch\0" - "zenith" -; - -static const SkMemberInfo g3D_CameraInfo[] = { - {0, 36, 106, 3}, - {5, 20, 98, 1}, - {16, 16, 98, 1}, - {26, 24, 106, 3}, - {35, 60, 106, 3}, - {44, 108, 105, 1}, - {50, 48, 106, 3} -}; - -static const char g3D_PatchStrings[] = - "origin\0" - "rotateDegrees\0" - "u\0" - "v" -; - -static const SkMemberInfo g3D_PatchInfo[] = { - {0, 40, 106, 3}, - {7, -1, 66, 98}, - {21, 16, 106, 3}, - {23, 28, 106, 3} -}; - -static const char gUnknown6Strings[] = - "x\0" - "y\0" - "z" -; - -static const SkMemberInfo gUnknown6Info[] = { - {0, 0, 98, 1}, - {2, 4, 98, 1}, - {4, 8, 98, 1} -}; - -static const char gSnapshotStrings[] = - "filename\0" - "quality\0" - "sequence\0" - "type" -; - -static const SkMemberInfo gSnapshotInfo[] = { - {0, 16, 108, 2}, - {9, 24, 98, 1}, - {17, 28, 26, 1}, - {26, 32, 20, 1} -}; - -static const char gStringStrings[] = - "length\0" - "slice\0" - "value" -; - -static const SkMemberInfo gStringInfo[] = { - {0, -1, 67, 96}, - {7, -1, 66, 108}, - {13, 16, 108, 2} -}; - -static const char gTextStrings[] = - "length\0" - "text\0" - "x\0" - "y" -; - -static const SkMemberInfo gTextInfo[] = { - {0, -1, 67, 96}, - {7, 24, 108, 2}, - {12, 32, 98, 1}, - {14, 36, 98, 1} -}; - -static const char gTextBoxStrings[] = - "\0" - "mode\0" - "spacingAdd\0" - "spacingAlign\0" - "spacingMul\0" - "text" -; - -static const SkMemberInfo gTextBoxInfo[] = { - {0, 58, 18, 7}, - {1, 60, 113, 1}, - {6, 56, 98, 1}, - {17, 64, 112, 1}, - {30, 52, 98, 1}, - {41, 44, 108, 2} -}; - -static const char gTextOnPathStrings[] = - "offset\0" - "path\0" - "text" -; - -static const SkMemberInfo gTextOnPathInfo[] = { - {0, 24, 98, 1}, - {7, 28, 74, 1}, - {12, 32, 110, 1} -}; - -static const char gTextToPathStrings[] = - "path\0" - "text" -; - -static const SkMemberInfo gTextToPathInfo[] = { - {0, 16, 74, 1}, - {5, 20, 110, 1} -}; - -static const char gTranslateStrings[] = - "x\0" - "y" -; - -static const SkMemberInfo gTranslateInfo[] = { - {0, 20, 98, 1}, - {2, 24, 98, 1} -}; - -static const char gTypedArrayStrings[] = - "length\0" - "values" -; - -static const SkMemberInfo gTypedArrayInfo[] = { - {0, -1, 67, 96}, - {7, 16, 119, 0} -}; - -static const char gTypefaceStrings[] = - "fontName" -; - -static const SkMemberInfo gTypefaceInfo[] = { - {0, 20, 108, 2} -}; - -static const SkMemberInfo* const gInfoTables[] = { - gMathInfo, - gAddInfo, - gAddCircleInfo, - gUnknown1Info, - gAddOvalInfo, - gAddPathInfo, - gAddRectangleInfo, - gAddRoundRectInfo, - gUnknown2Info, - gAnimateFieldInfo, - gApplyInfo, - gUnknown3Info, - gDrawBitmapInfo, - gDrawBitmapShaderInfo, - gDrawBlurInfo, - gDisplayBoundsInfo, - gDrawClipInfo, - gDrawColorInfo, - gCubicToInfo, - gDashInfo, - gDataInfo, - gDiscreteInfo, - gDrawToInfo, - gDumpInfo, - gDrawEmbossInfo, - gDisplayEventInfo, - gFromPathInfo, - gUnknown4Info, - gGInfo, - gHitClearInfo, - gHitTestInfo, - gImageInfo, - gIncludeInfo, - gInputInfo, - gLineInfo, - gLineToInfo, - gLinearGradientInfo, - gDrawMatrixInfo, - gMoveInfo, - gMoveToInfo, - gMovieInfo, - gOvalInfo, - gDrawPaintInfo, - gDrawPathInfo, - gUnknown5Info, - gDrawPointInfo, - gPolyToPolyInfo, - gPolygonInfo, - gPolylineInfo, - gPostInfo, - gQuadToInfo, - gRCubicToInfo, - gRLineToInfo, - gRMoveToInfo, - gRQuadToInfo, - gRadialGradientInfo, - gDisplayRandomInfo, - gRectToRectInfo, - gRectangleInfo, - gRemoveInfo, - gReplaceInfo, - gRotateInfo, - gRoundRectInfo, - gS32Info, - gScalarInfo, - gScaleInfo, - gSetInfo, - gShaderInfo, - gSkewInfo, - g3D_CameraInfo, - g3D_PatchInfo, - gUnknown6Info, - gSnapshotInfo, - gStringInfo, - gTextInfo, - gTextBoxInfo, - gTextOnPathInfo, - gTextToPathInfo, - gTranslateInfo, - gTypedArrayInfo, - gTypefaceInfo, -}; - -static const unsigned char gInfoCounts[] = { - 26,4,4,1,1,2,5,3,13,1,13,2,6,3,2,2,2,8,6, - 2,2,2,2,6,4,8,3,3,2,1,4,3,1,3,4,2,2,12,1, - 2,1,1,25,3,3,2,2,1,1,6,4,1,1,1,1,3,5,2,7, - 2,1,2,3,1,1,3,8,2,3,7,4,3,4,3,4,6,3,2,2, - 2,1 -}; - -static const unsigned char gTypeIDs[] = { - 1, // Math - 2, // Add - 3, // AddCircle - 4, // Unknown1 - 5, // AddOval - 6, // AddPath - 7, // AddRectangle - 8, // AddRoundRect - 10, // Unknown2 - 11, // AnimateField - 12, // Apply - 17, // Unknown3 - 19, // Bitmap - 22, // BitmapShader - 23, // Blur - 25, // Bounds - 29, // Clip - 31, // Color - 32, // CubicTo - 33, // Dash - 34, // Data - 35, // Discrete - 38, // DrawTo - 39, // Dump - 41, // Emboss - 42, // Event - 48, // FromPath - 51, // Unknown4 - 52, // G - 53, // HitClear - 54, // HitTest - 55, // Image - 56, // Include - 57, // Input - 59, // Line - 60, // LineTo - 61, // LinearGradient - 65, // Matrix - 68, // Move - 69, // MoveTo - 70, // Movie - 72, // Oval - 73, // Paint - 74, // Path - 77, // Unknown5 - 78, // Point - 79, // PolyToPoly - 80, // Polygon - 81, // Polyline - 82, // Post - 83, // QuadTo - 84, // RCubicTo - 85, // RLineTo - 86, // RMoveTo - 87, // RQuadTo - 88, // RadialGradient - 89, // Random - 90, // RectToRect - 91, // Rectangle - 92, // Remove - 93, // Replace - 94, // Rotate - 95, // RoundRect - 96, // S32 - 98, // Scalar - 99, // Scale - 101, // Set - 102, // Shader - 103, // Skew - 104, // 3D_Camera - 105, // 3D_Patch - 106, // Unknown6 - 107, // Snapshot - 108, // String - 110, // Text - 111, // TextBox - 114, // TextOnPath - 115, // TextToPath - 117, // Translate - 119, // TypedArray - 120, // Typeface - -}; - -static const int kTypeIDs = 81; - -static const char* const gInfoNames[] = { - gMathStrings, - gAddStrings, - gAddCircleStrings, - gUnknown1Strings, - gAddOvalStrings, - gAddPathStrings, - gAddRectangleStrings, - gAddRoundRectStrings, - gUnknown2Strings, - gAnimateFieldStrings, - gApplyStrings, - gUnknown3Strings, - gBitmapStrings, - gBitmapShaderStrings, - gBlurStrings, - gBoundsStrings, - gClipStrings, - gColorStrings, - gCubicToStrings, - gDashStrings, - gDataStrings, - gDiscreteStrings, - gDrawToStrings, - gDumpStrings, - gEmbossStrings, - gEventStrings, - gFromPathStrings, - gUnknown4Strings, - gGStrings, - gHitClearStrings, - gHitTestStrings, - gImageStrings, - gIncludeStrings, - gInputStrings, - gLineStrings, - gLineToStrings, - gLinearGradientStrings, - gMatrixStrings, - gMoveStrings, - gMoveToStrings, - gMovieStrings, - gOvalStrings, - gPaintStrings, - gPathStrings, - gUnknown5Strings, - gPointStrings, - gPolyToPolyStrings, - gPolygonStrings, - gPolylineStrings, - gPostStrings, - gQuadToStrings, - gRCubicToStrings, - gRLineToStrings, - gRMoveToStrings, - gRQuadToStrings, - gRadialGradientStrings, - gRandomStrings, - gRectToRectStrings, - gRectangleStrings, - gRemoveStrings, - gReplaceStrings, - gRotateStrings, - gRoundRectStrings, - gS32Strings, - gScalarStrings, - gScaleStrings, - gSetStrings, - gShaderStrings, - gSkewStrings, - g3D_CameraStrings, - g3D_PatchStrings, - gUnknown6Strings, - gSnapshotStrings, - gStringStrings, - gTextStrings, - gTextBoxStrings, - gTextOnPathStrings, - gTextToPathStrings, - gTranslateStrings, - gTypedArrayStrings, - gTypefaceStrings -}; - -#endif -#endif diff --git a/gfx/skia/skia/src/animator/SkCondensedRelease.inc b/gfx/skia/skia/src/animator/SkCondensedRelease.inc deleted file mode 100644 index 1222496051b6..000000000000 --- a/gfx/skia/skia/src/animator/SkCondensedRelease.inc +++ /dev/null @@ -1,1365 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkTypes.h" -#ifndef SK_BUILD_FOR_UNIX -#ifdef SK_RELEASE -// This file was automatically generated. -// To change it, edit the file with the matching debug info. -// Then execute SkDisplayType::BuildCondensedInfo() to regenerate this file. - -static const char gMathStrings[] = - "E\0" - "LN10\0" - "LN2\0" - "LOG10E\0" - "LOG2E\0" - "PI\0" - "SQRT1_2\0" - "SQRT2\0" - "abs\0" - "acos\0" - "asin\0" - "atan\0" - "atan2\0" - "ceil\0" - "cos\0" - "exp\0" - "floor\0" - "log\0" - "max\0" - "min\0" - "pow\0" - "random\0" - "round\0" - "sin\0" - "sqrt\0" - "tan" -; - -static const SkMemberInfo gMathInfo[] = { - {0, -1, 67, 98}, - {2, -2, 67, 98}, - {7, -3, 67, 98}, - {11, -4, 67, 98}, - {18, -5, 67, 98}, - {24, -6, 67, 98}, - {27, -7, 67, 98}, - {35, -8, 67, 98}, - {41, -1, 66, 98}, - {45, -2, 66, 98}, - {50, -3, 66, 98}, - {55, -4, 66, 98}, - {60, -5, 66, 98}, - {66, -6, 66, 98}, - {71, -7, 66, 98}, - {75, -8, 66, 98}, - {79, -9, 66, 98}, - {85, -10, 66, 98}, - {89, -11, 66, 98}, - {93, -12, 66, 98}, - {97, -13, 66, 98}, - {101, -14, 66, 98}, - {108, -15, 66, 98}, - {114, -16, 66, 98}, - {118, -17, 66, 98}, - {123, -18, 66, 98} -}; - -static const char gAddStrings[] = - "inPlace\0" - "offset\0" - "use\0" - "where" -; - -static const SkMemberInfo gAddInfo[] = { - {0, 4, 26, 1}, - {8, 8, 96, 1}, - {15, 12, 37, 1}, - {19, 16, 37, 1} -}; - -static const char gAddCircleStrings[] = - "\0" - "radius\0" - "x\0" - "y" -; - -static const SkMemberInfo gAddCircleInfo[] = { - {0, 3, 18, 1}, - {1, 12, 98, 1}, - {8, 16, 98, 1}, - {10, 20, 98, 1} -}; - -static const char gUnknown1Strings[] = - "direction" -; - -static const SkMemberInfo gUnknown1Info[] = { - {0, 8, 75, 1} -}; - -static const char gAddOvalStrings[] = - "" -; - -static const SkMemberInfo gAddOvalInfo[] = { - {0, 6, 18, 5} -}; - -static const char gAddPathStrings[] = - "matrix\0" - "path" -; - -static const SkMemberInfo gAddPathInfo[] = { - {0, 8, 65, 1}, - {7, 12, 74, 1} -}; - -static const char gAddRectangleStrings[] = - "\0" - "bottom\0" - "left\0" - "right\0" - "top" -; - -static const SkMemberInfo gAddRectangleInfo[] = { - {0, 3, 18, 1}, - {1, 24, 98, 1}, - {8, 12, 98, 1}, - {13, 20, 98, 1}, - {19, 16, 98, 1} -}; - -static const char gAddRoundRectStrings[] = - "\0" - "rx\0" - "ry" -; - -static const SkMemberInfo gAddRoundRectInfo[] = { - {0, 6, 18, 5}, - {1, 28, 98, 1}, - {4, 32, 98, 1} -}; - -static const char gUnknown2Strings[] = - "begin\0" - "blend\0" - "dur\0" - "dynamic\0" - "field\0" - "formula\0" - "from\0" - "mirror\0" - "repeat\0" - "reset\0" - "target\0" - "to\0" - "values" -; - -static const SkMemberInfo gUnknown2Info[] = { - {0, 4, 71, 1}, - {6, 8, 119, 98}, - {12, 16, 71, 1}, - {16, -1, 67, 26}, - {24, 20, 108, 1}, - {30, 24, 40, 1}, - {38, 28, 40, 1}, - {43, -2, 67, 26}, - {50, 32, 98, 1}, - {57, -3, 67, 26}, - {63, 36, 40, 1}, - {70, 40, 40, 1}, - {73, -4, 67, 40} -}; - -static const char gAnimateFieldStrings[] = - "" -; - -static const SkMemberInfo gAnimateFieldInfo[] = { - {0, 8, 18, 13} -}; - -static const char gApplyStrings[] = - "animator\0" - "begin\0" - "dontDraw\0" - "dynamicScope\0" - "interval\0" - "mode\0" - "pickup\0" - "restore\0" - "scope\0" - "step\0" - "steps\0" - "time\0" - "transition" -; - -static const SkMemberInfo gApplyInfo[] = { - {0, -1, 67, 10}, - {9, 4, 71, 1}, - {15, 8, 26, 1}, - {24, 12, 108, 1}, - {37, 16, 71, 1}, - {46, 20, 13, 1}, - {51, 24, 26, 1}, - {58, 28, 26, 1}, - {66, 32, 37, 1}, - {72, -2, 67, 96}, - {77, 36, 96, 1}, - {83, -3, 67, 71}, - {88, 40, 14, 1} -}; - -static const char gUnknown3Strings[] = - "x\0" - "y" -; - -static const SkMemberInfo gUnknown3Info[] = { - {0, 36, 98, 1}, - {2, 40, 98, 1} -}; - -static const char gBitmapStrings[] = - "\0" - "erase\0" - "format\0" - "height\0" - "rowBytes\0" - "width" -; - -static const SkMemberInfo gDrawBitmapInfo[] = { - {0, 11, 18, 2}, - {1, -1, 67, 15}, - {7, 44, 21, 1}, - {14, 48, 96, 1}, - {21, 52, 96, 1}, - {30, 56, 96, 1} -}; - -static const char gBitmapShaderStrings[] = - "\0" - "filterType\0" - "image" -; - -static const SkMemberInfo gDrawBitmapShaderInfo[] = { - {0, 66, 18, 2}, - {1, 16, 47, 1}, - {12, 20, 17, 1} -}; - -static const char gBlurStrings[] = - "blurStyle\0" - "radius" -; - -static const SkMemberInfo gDrawBlurInfo[] = { - {0, 12, 63, 1}, - {10, 8, 98, 1} -}; - -static const char gBoundsStrings[] = - "\0" - "inval" -; - -static const SkMemberInfo gDisplayBoundsInfo[] = { - {0, 57, 18, 7}, - {1, 32, 26, 1} -}; - -static const char gClipStrings[] = - "path\0" - "rectangle" -; - -static const SkMemberInfo gDrawClipInfo[] = { - {0, 8, 74, 1}, - {5, 4, 91, 1} -}; - -static const char gColorStrings[] = - "alpha\0" - "blue\0" - "color\0" - "green\0" - "hue\0" - "red\0" - "saturation\0" - "value" -; - -static const SkMemberInfo gDrawColorInfo[] = { - {0, -1, 67, 98}, - {6, -2, 67, 98}, - {11, 8, 15, 1}, - {17, -3, 67, 98}, - {23, -4, 67, 98}, - {27, -5, 67, 98}, - {31, -6, 67, 98}, - {42, -7, 67, 98} -}; - -static const char gCubicToStrings[] = - "x1\0" - "x2\0" - "x3\0" - "y1\0" - "y2\0" - "y3" -; - -static const SkMemberInfo gCubicToInfo[] = { - {0, 8, 98, 1}, - {3, 16, 98, 1}, - {6, 24, 98, 1}, - {9, 12, 98, 1}, - {12, 20, 98, 1}, - {15, 28, 98, 1} -}; - -static const char gDashStrings[] = - "intervals\0" - "phase" -; - -static const SkMemberInfo gDashInfo[] = { - {0, 8, 119, 98}, - {10, 16, 98, 1} -}; - -static const char gDataStrings[] = - "\0" - "name" -; - -static const SkMemberInfo gDataInfo[] = { - {0, 32, 18, 3}, - {1, 16, 108, 1} -}; - -static const char gDiscreteStrings[] = - "deviation\0" - "segLength" -; - -static const SkMemberInfo gDiscreteInfo[] = { - {0, 8, 98, 1}, - {10, 12, 98, 1} -}; - -static const char gDrawToStrings[] = - "drawOnce\0" - "use" -; - -static const SkMemberInfo gDrawToInfo[] = { - {0, 36, 26, 1}, - {9, 40, 19, 1} -}; - -static const char gEmbossStrings[] = - "ambient\0" - "direction\0" - "radius\0" - "specular" -; - -static const SkMemberInfo gDrawEmbossInfo[] = { - {0, -1, 67, 98}, - {8, 8, 119, 98}, - {18, 16, 98, 1}, - {25, -2, 67, 98} -}; - -static const char gEventStrings[] = - "code\0" - "disable\0" - "key\0" - "keys\0" - "kind\0" - "target\0" - "x\0" - "y" -; - -static const SkMemberInfo gDisplayEventInfo[] = { - {0, 4, 43, 1}, - {5, 8, 26, 1}, - {13, -1, 67, 108}, - {17, -2, 67, 108}, - {22, 12, 44, 1}, - {27, 16, 108, 1}, - {34, 20, 98, 1}, - {36, 24, 98, 1} -}; - -static const char gFromPathStrings[] = - "mode\0" - "offset\0" - "path" -; - -static const SkMemberInfo gFromPathInfo[] = { - {0, 8, 49, 1}, - {5, 12, 98, 1}, - {12, 16, 74, 1} -}; - -static const char gUnknown4Strings[] = - "\0" - "offsets\0" - "unitMapper" -; - -static const SkMemberInfo gUnknown4Info[] = { - {0, 66, 18, 2}, - {1, 16, 119, 98}, - {9, 24, 108, 1} -}; - -static const char gGStrings[] = - "condition\0" - "enableCondition" -; - -static const SkMemberInfo gGInfo[] = { - {0, 4, 40, 1}, - {10, 8, 40, 1} -}; - -static const char gHitClearStrings[] = - "targets" -; - -static const SkMemberInfo gHitClearInfo[] = { - {0, 4, 119, 36} -}; - -static const char gHitTestStrings[] = - "bullets\0" - "hits\0" - "targets\0" - "value" -; - -static const SkMemberInfo gHitTestInfo[] = { - {0, 4, 119, 36}, - {8, 12, 119, 96}, - {13, 20, 119, 36}, - {21, 28, 26, 1} -}; - -static const char gImageStrings[] = - "\0" - "base64\0" - "src" -; - -static const SkMemberInfo gImageInfo[] = { - {0, 11, 18, 2}, - {1, 44, 16, 2}, - {8, 52, 108, 1} -}; - -static const char gIncludeStrings[] = - "src" -; - -static const SkMemberInfo gIncludeInfo[] = { - {0, 4, 108, 1} -}; - -static const char gInputStrings[] = - "s32\0" - "scalar\0" - "string" -; - -static const SkMemberInfo gInputInfo[] = { - {0, 4, 96, 1}, - {4, 8, 98, 1}, - {11, 12, 108, 1} -}; - -static const char gLineStrings[] = - "x1\0" - "x2\0" - "y1\0" - "y2" -; - -static const SkMemberInfo gLineInfo[] = { - {0, 12, 98, 1}, - {3, 16, 98, 1}, - {6, 20, 98, 1}, - {9, 24, 98, 1} -}; - -static const char gLineToStrings[] = - "x\0" - "y" -; - -static const SkMemberInfo gLineToInfo[] = { - {0, 8, 98, 1}, - {2, 12, 98, 1} -}; - -static const char gLinearGradientStrings[] = - "\0" - "points" -; - -static const SkMemberInfo gLinearGradientInfo[] = { - {0, 26, 18, 3}, - {1, 48, 77, 4} -}; - -static const char gMatrixStrings[] = - "matrix\0" - "perspectX\0" - "perspectY\0" - "rotate\0" - "scale\0" - "scaleX\0" - "scaleY\0" - "skewX\0" - "skewY\0" - "translate\0" - "translateX\0" - "translateY" -; - -static const SkMemberInfo gDrawMatrixInfo[] = { - {0, 4, 119, 98}, - {7, -1, 67, 98}, - {17, -2, 67, 98}, - {27, -3, 67, 98}, - {34, -4, 67, 98}, - {40, -5, 67, 98}, - {47, -6, 67, 98}, - {54, -7, 67, 98}, - {60, -8, 67, 98}, - {66, -9, 67, 77}, - {76, -10, 67, 98}, - {87, -11, 67, 98} -}; - -static const char gMoveStrings[] = - "" -; - -static const SkMemberInfo gMoveInfo[] = { - {0, 1, 18, 4} -}; - -static const char gMoveToStrings[] = - "x\0" - "y" -; - -static const SkMemberInfo gMoveToInfo[] = { - {0, 8, 98, 1}, - {2, 12, 98, 1} -}; - -static const char gMovieStrings[] = - "src" -; - -static const SkMemberInfo gMovieInfo[] = { - {0, 4, 108, 1} -}; - -static const char gOvalStrings[] = - "" -; - -static const SkMemberInfo gOvalInfo[] = { - {0, 57, 18, 7} -}; - -static const char gPaintStrings[] = - "antiAlias\0" - "ascent\0" - "color\0" - "descent\0" - "filterType\0" - "linearText\0" - "maskFilter\0" - "measureText\0" - "pathEffect\0" - "shader\0" - "strikeThru\0" - "stroke\0" - "strokeCap\0" - "strokeJoin\0" - "strokeMiter\0" - "strokeWidth\0" - "style\0" - "textAlign\0" - "textScaleX\0" - "textSize\0" - "textSkewX\0" - "textTracking\0" - "typeface\0" - "underline\0" - "xfermode" -; - -static const SkMemberInfo gDrawPaintInfo[] = { - {0, 4, 26, 1}, - {10, -1, 67, 98}, - {17, 8, 31, 1}, - {23, -2, 67, 98}, - {31, 12, 47, 1}, - {42, 16, 26, 1}, - {53, 20, 62, 1}, - {64, -1, 66, 98}, - {76, 24, 76, 1}, - {87, 28, 102, 1}, - {94, 32, 26, 1}, - {105, 36, 26, 1}, - {112, 40, 27, 1}, - {122, 44, 58, 1}, - {133, 48, 98, 1}, - {145, 52, 98, 1}, - {157, 56, 109, 1}, - {163, 60, 9, 1}, - {173, 64, 98, 1}, - {184, 68, 98, 1}, - {193, 72, 98, 1}, - {203, 76, 98, 1}, - {216, 80, 120, 1}, - {225, 84, 26, 1}, - {235, 88, 121, 1} -}; - -static const char gPathStrings[] = - "d\0" - "fillType\0" - "length" -; - -static const SkMemberInfo gDrawPathInfo[] = { - {0, 32, 108, 1}, - {2, -1, 67, 46}, - {11, -2, 67, 98} -}; - -static const char gUnknown5Strings[] = - "x\0" - "y\0" - "z" -; - -static const SkMemberInfo gUnknown5Info[] = { - {0, 0, 98, 1}, - {2, 4, 98, 1}, - {4, 8, 98, 1} -}; - -static const char gPointStrings[] = - "x\0" - "y" -; - -static const SkMemberInfo gDrawPointInfo[] = { - {0, 4, 98, 1}, - {2, 8, 98, 1} -}; - -static const char gPolyToPolyStrings[] = - "destination\0" - "source" -; - -static const SkMemberInfo gPolyToPolyInfo[] = { - {0, 12, 80, 1}, - {12, 8, 80, 1} -}; - -static const char gPolygonStrings[] = - "" -; - -static const SkMemberInfo gPolygonInfo[] = { - {0, 47, 18, 1} -}; - -static const char gPolylineStrings[] = - "points" -; - -static const SkMemberInfo gPolylineInfo[] = { - {0, 56, 119, 98} -}; - -static const char gPostStrings[] = - "delay\0" - "initialized\0" - "mode\0" - "sink\0" - "target\0" - "type" -; - -static const SkMemberInfo gPostInfo[] = { - {0, 4, 71, 1}, - {6, 8, 26, 1}, - {18, 12, 45, 1}, - {23, -1, 67, 108}, - {28, -2, 67, 108}, - {35, -3, 67, 108} -}; - -static const char gQuadToStrings[] = - "x1\0" - "x2\0" - "y1\0" - "y2" -; - -static const SkMemberInfo gQuadToInfo[] = { - {0, 8, 98, 1}, - {3, 16, 98, 1}, - {6, 12, 98, 1}, - {9, 20, 98, 1} -}; - -static const char gRCubicToStrings[] = - "" -; - -static const SkMemberInfo gRCubicToInfo[] = { - {0, 18, 18, 6} -}; - -static const char gRLineToStrings[] = - "" -; - -static const SkMemberInfo gRLineToInfo[] = { - {0, 34, 18, 2} -}; - -static const char gRMoveToStrings[] = - "" -; - -static const SkMemberInfo gRMoveToInfo[] = { - {0, 38, 18, 2} -}; - -static const char gRQuadToStrings[] = - "" -; - -static const SkMemberInfo gRQuadToInfo[] = { - {0, 49, 18, 4} -}; - -static const char gRadialGradientStrings[] = - "\0" - "center\0" - "radius" -; - -static const SkMemberInfo gRadialGradientInfo[] = { - {0, 26, 18, 3}, - {1, 48, 77, 2}, - {8, 56, 98, 1} -}; - -static const char gRandomStrings[] = - "blend\0" - "max\0" - "min\0" - "random\0" - "seed" -; - -static const SkMemberInfo gDisplayRandomInfo[] = { - {0, 4, 98, 1}, - {6, 12, 98, 1}, - {10, 8, 98, 1}, - {14, 1, 67, 98}, - {21, -2, 67, 96} -}; - -static const char gRectToRectStrings[] = - "destination\0" - "source" -; - -static const SkMemberInfo gRectToRectInfo[] = { - {0, 12, 91, 1}, - {12, 8, 91, 1} -}; - -static const char gRectangleStrings[] = - "bottom\0" - "height\0" - "left\0" - "needsRedraw\0" - "right\0" - "top\0" - "width" -; - -static const SkMemberInfo gRectangleInfo[] = { - {0, 24, 98, 1}, - {7, -1, 67, 98}, - {14, 12, 98, 1}, - {19, -2, 67, 26}, - {31, 20, 98, 1}, - {37, 16, 98, 1}, - {41, -3, 67, 98} -}; - -static const char gRemoveStrings[] = - "offset\0" - "where" -; - -static const SkMemberInfo gRemoveInfo[] = { - {0, 8, 96, 1}, - {7, 16, 37, 1} -}; - -static const char gReplaceStrings[] = - "" -; - -static const SkMemberInfo gReplaceInfo[] = { - {0, 1, 18, 4} -}; - -static const char gRotateStrings[] = - "center\0" - "degrees" -; - -static const SkMemberInfo gRotateInfo[] = { - {0, 12, 77, 2}, - {7, 8, 98, 1} -}; - -static const char gRoundRectStrings[] = - "\0" - "rx\0" - "ry" -; - -static const SkMemberInfo gRoundRectInfo[] = { - {0, 57, 18, 7}, - {1, 32, 98, 1}, - {4, 36, 98, 1} -}; - -static const char gS32Strings[] = - "value" -; - -static const SkMemberInfo gS32Info[] = { - {0, 4, 96, 1} -}; - -static const char gScalarStrings[] = - "value" -; - -static const SkMemberInfo gScalarInfo[] = { - {0, 4, 98, 1} -}; - -static const char gScaleStrings[] = - "center\0" - "x\0" - "y" -; - -static const SkMemberInfo gScaleInfo[] = { - {0, 16, 77, 2}, - {7, 8, 98, 1}, - {9, 12, 98, 1} -}; - -static const char gSetStrings[] = - "begin\0" - "dur\0" - "dynamic\0" - "field\0" - "formula\0" - "reset\0" - "target\0" - "to" -; - -static const SkMemberInfo gSetInfo[] = { - {0, 4, 71, 1}, - {6, 16, 71, 1}, - {10, -1, 67, 26}, - {18, 20, 108, 1}, - {24, 24, 40, 1}, - {32, -3, 67, 26}, - {38, 36, 40, 1}, - {45, 40, 40, 1} -}; - -static const char gShaderStrings[] = - "matrix\0" - "tileMode" -; - -static const SkMemberInfo gShaderInfo[] = { - {0, 8, 65, 1}, - {7, 12, 116, 1} -}; - -static const char gSkewStrings[] = - "center\0" - "x\0" - "y" -; - -static const SkMemberInfo gSkewInfo[] = { - {0, 16, 77, 2}, - {7, 8, 98, 1}, - {9, 12, 98, 1} -}; - -static const char g3D_CameraStrings[] = - "axis\0" - "hackHeight\0" - "hackWidth\0" - "location\0" - "observer\0" - "patch\0" - "zenith" -; - -static const SkMemberInfo g3D_CameraInfo[] = { - {0, 24, 106, 3}, - {5, 8, 98, 1}, - {16, 4, 98, 1}, - {26, 12, 106, 3}, - {35, 48, 106, 3}, - {44, 96, 105, 1}, - {50, 36, 106, 3} -}; - -static const char g3D_PatchStrings[] = - "origin\0" - "rotateDegrees\0" - "u\0" - "v" -; - -static const SkMemberInfo g3D_PatchInfo[] = { - {0, 28, 106, 3}, - {7, -1, 66, 98}, - {21, 4, 106, 3}, - {23, 16, 106, 3} -}; - -static const char gUnknown6Strings[] = - "x\0" - "y\0" - "z" -; - -static const SkMemberInfo gUnknown6Info[] = { - {0, 0, 98, 1}, - {2, 4, 98, 1}, - {4, 8, 98, 1} -}; - -static const char gSnapshotStrings[] = - "filename\0" - "quality\0" - "sequence\0" - "type" -; - -static const SkMemberInfo gSnapshotInfo[] = { - {0, 4, 108, 1}, - {9, 8, 98, 1}, - {17, 12, 26, 1}, - {26, 16, 20, 1} -}; - -static const char gStringStrings[] = - "length\0" - "slice\0" - "value" -; - -static const SkMemberInfo gStringInfo[] = { - {0, -1, 67, 96}, - {7, -1, 66, 108}, - {13, 4, 108, 1} -}; - -static const char gTextStrings[] = - "length\0" - "text\0" - "x\0" - "y" -; - -static const SkMemberInfo gTextInfo[] = { - {0, -1, 67, 96}, - {7, 12, 108, 1}, - {12, 16, 98, 1}, - {14, 20, 98, 1} -}; - -static const char gTextBoxStrings[] = - "\0" - "mode\0" - "spacingAdd\0" - "spacingAlign\0" - "spacingMul\0" - "text" -; - -static const SkMemberInfo gTextBoxInfo[] = { - {0, 57, 18, 7}, - {1, 44, 113, 1}, - {6, 40, 98, 1}, - {17, 48, 112, 1}, - {30, 36, 98, 1}, - {41, 32, 108, 1} -}; - -static const char gTextOnPathStrings[] = - "offset\0" - "path\0" - "text" -; - -static const SkMemberInfo gTextOnPathInfo[] = { - {0, 12, 98, 1}, - {7, 16, 74, 1}, - {12, 20, 110, 1} -}; - -static const char gTextToPathStrings[] = - "path\0" - "text" -; - -static const SkMemberInfo gTextToPathInfo[] = { - {0, 4, 74, 1}, - {5, 8, 110, 1} -}; - -static const char gTranslateStrings[] = - "x\0" - "y" -; - -static const SkMemberInfo gTranslateInfo[] = { - {0, 8, 98, 1}, - {2, 12, 98, 1} -}; - -static const char gTypedArrayStrings[] = - "length\0" - "values" -; - -static const SkMemberInfo gTypedArrayInfo[] = { - {0, -1, 67, 96}, - {7, 4, 119, 0} -}; - -static const char gTypefaceStrings[] = - "fontName" -; - -static const SkMemberInfo gTypefaceInfo[] = { - {0, 8, 108, 1} -}; - -static const SkMemberInfo* const gInfoTables[] = { - gMathInfo, - gAddInfo, - gAddCircleInfo, - gUnknown1Info, - gAddOvalInfo, - gAddPathInfo, - gAddRectangleInfo, - gAddRoundRectInfo, - gUnknown2Info, - gAnimateFieldInfo, - gApplyInfo, - gUnknown3Info, - gDrawBitmapInfo, - gDrawBitmapShaderInfo, - gDrawBlurInfo, - gDisplayBoundsInfo, - gDrawClipInfo, - gDrawColorInfo, - gCubicToInfo, - gDashInfo, - gDataInfo, - gDiscreteInfo, - gDrawToInfo, - gDrawEmbossInfo, - gDisplayEventInfo, - gFromPathInfo, - gUnknown4Info, - gGInfo, - gHitClearInfo, - gHitTestInfo, - gImageInfo, - gIncludeInfo, - gInputInfo, - gLineInfo, - gLineToInfo, - gLinearGradientInfo, - gDrawMatrixInfo, - gMoveInfo, - gMoveToInfo, - gMovieInfo, - gOvalInfo, - gDrawPaintInfo, - gDrawPathInfo, - gUnknown5Info, - gDrawPointInfo, - gPolyToPolyInfo, - gPolygonInfo, - gPolylineInfo, - gPostInfo, - gQuadToInfo, - gRCubicToInfo, - gRLineToInfo, - gRMoveToInfo, - gRQuadToInfo, - gRadialGradientInfo, - gDisplayRandomInfo, - gRectToRectInfo, - gRectangleInfo, - gRemoveInfo, - gReplaceInfo, - gRotateInfo, - gRoundRectInfo, - gS32Info, - gScalarInfo, - gScaleInfo, - gSetInfo, - gShaderInfo, - gSkewInfo, - g3D_CameraInfo, - g3D_PatchInfo, - gUnknown6Info, - gSnapshotInfo, - gStringInfo, - gTextInfo, - gTextBoxInfo, - gTextOnPathInfo, - gTextToPathInfo, - gTranslateInfo, - gTypedArrayInfo, - gTypefaceInfo, -}; - -static const unsigned char gInfoCounts[] = { - 26,4,4,1,1,2,5,3,13,1,13,2,6,3,2,2,2,8,6, - 2,2,2,2,4,8,3,3,2,1,4,3,1,3,4,2,2,12,1,2, - 1,1,25,3,3,2,2,1,1,6,4,1,1,1,1,3,5,2,7,2, - 1,2,3,1,1,3,8,2,3,7,4,3,4,3,4,6,3,2,2,2, - 1 -}; - -static const unsigned char gTypeIDs[] = { - 1, // Math - 2, // Add - 3, // AddCircle - 4, // Unknown1 - 5, // AddOval - 6, // AddPath - 7, // AddRectangle - 8, // AddRoundRect - 10, // Unknown2 - 11, // AnimateField - 12, // Apply - 17, // Unknown3 - 19, // Bitmap - 22, // BitmapShader - 23, // Blur - 25, // Bounds - 29, // Clip - 31, // Color - 32, // CubicTo - 33, // Dash - 34, // Data - 35, // Discrete - 38, // DrawTo - 41, // Emboss - 42, // Event - 48, // FromPath - 51, // Unknown4 - 52, // G - 53, // HitClear - 54, // HitTest - 55, // Image - 56, // Include - 57, // Input - 59, // Line - 60, // LineTo - 61, // LinearGradient - 65, // Matrix - 68, // Move - 69, // MoveTo - 70, // Movie - 72, // Oval - 73, // Paint - 74, // Path - 77, // Unknown5 - 78, // Point - 79, // PolyToPoly - 80, // Polygon - 81, // Polyline - 82, // Post - 83, // QuadTo - 84, // RCubicTo - 85, // RLineTo - 86, // RMoveTo - 87, // RQuadTo - 88, // RadialGradient - 89, // Random - 90, // RectToRect - 91, // Rectangle - 92, // Remove - 93, // Replace - 94, // Rotate - 95, // RoundRect - 96, // S32 - 98, // Scalar - 99, // Scale - 101, // Set - 102, // Shader - 103, // Skew - 104, // 3D_Camera - 105, // 3D_Patch - 106, // Unknown6 - 107, // Snapshot - 108, // String - 110, // Text - 111, // TextBox - 114, // TextOnPath - 115, // TextToPath - 117, // Translate - 119, // TypedArray - 120, // Typeface - -}; - -static const int kTypeIDs = 80; - -static const char* const gInfoNames[] = { - gMathStrings, - gAddStrings, - gAddCircleStrings, - gUnknown1Strings, - gAddOvalStrings, - gAddPathStrings, - gAddRectangleStrings, - gAddRoundRectStrings, - gUnknown2Strings, - gAnimateFieldStrings, - gApplyStrings, - gUnknown3Strings, - gBitmapStrings, - gBitmapShaderStrings, - gBlurStrings, - gBoundsStrings, - gClipStrings, - gColorStrings, - gCubicToStrings, - gDashStrings, - gDataStrings, - gDiscreteStrings, - gDrawToStrings, - gEmbossStrings, - gEventStrings, - gFromPathStrings, - gUnknown4Strings, - gGStrings, - gHitClearStrings, - gHitTestStrings, - gImageStrings, - gIncludeStrings, - gInputStrings, - gLineStrings, - gLineToStrings, - gLinearGradientStrings, - gMatrixStrings, - gMoveStrings, - gMoveToStrings, - gMovieStrings, - gOvalStrings, - gPaintStrings, - gPathStrings, - gUnknown5Strings, - gPointStrings, - gPolyToPolyStrings, - gPolygonStrings, - gPolylineStrings, - gPostStrings, - gQuadToStrings, - gRCubicToStrings, - gRLineToStrings, - gRMoveToStrings, - gRQuadToStrings, - gRadialGradientStrings, - gRandomStrings, - gRectToRectStrings, - gRectangleStrings, - gRemoveStrings, - gReplaceStrings, - gRotateStrings, - gRoundRectStrings, - gS32Strings, - gScalarStrings, - gScaleStrings, - gSetStrings, - gShaderStrings, - gSkewStrings, - g3D_CameraStrings, - g3D_PatchStrings, - gUnknown6Strings, - gSnapshotStrings, - gStringStrings, - gTextStrings, - gTextBoxStrings, - gTextOnPathStrings, - gTextToPathStrings, - gTranslateStrings, - gTypedArrayStrings, - gTypefaceStrings -}; -#endif -#endif diff --git a/gfx/skia/skia/src/animator/SkDisplayAdd.cpp b/gfx/skia/skia/src/animator/SkDisplayAdd.cpp deleted file mode 100644 index f5788a3869a0..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayAdd.cpp +++ /dev/null @@ -1,245 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayAdd.h" -#include "SkAnimateMaker.h" -#include "SkDisplayApply.h" -#include "SkDisplayList.h" -#include "SkADrawable.h" -#include "SkDrawGroup.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkAdd::fInfo[] = { - SK_MEMBER(mode, AddMode), - SK_MEMBER(offset, Int), - SK_MEMBER(use, Drawable), - SK_MEMBER(where, Drawable) -}; - -#endif - -// start here; -// add onEndElement to turn where string into f_Where -// probably need new SkAnimateMaker::resolve flavor that takes -// where="id", where="event-target" or not-specified -// offset="#" (implements before, after, and index if no 'where') - -DEFINE_GET_MEMBER(SkAdd); - -SkAdd::SkAdd() : mode(kMode_indirect), - offset(SK_MaxS32), use(nullptr), where(nullptr) { -} - -SkDisplayable* SkAdd::deepCopy(SkAnimateMaker* maker) { - SkADrawable* saveUse = use; - SkADrawable* saveWhere = where; - use = nullptr; - where = nullptr; - SkAdd* copy = (SkAdd*) INHERITED::deepCopy(maker); - copy->use = use = saveUse; - copy->where = where = saveWhere; - return copy; -} - -bool SkAdd::draw(SkAnimateMaker& maker) { - SkASSERT(use); - SkASSERT(use->isDrawable()); - if (mode == kMode_indirect) - use->draw(maker); - return false; -} - -#ifdef SK_DUMP_ENABLED -void SkAdd::dump(SkAnimateMaker* maker) { - dumpBase(maker); - dumpAttrs(maker); - if (where) - SkDebugf("where=\"%s\" ", where->id); - if (mode == kMode_immediate) - SkDebugf("mode=\"immediate\" "); - SkDebugf(">\n"); - SkDisplayList::fIndent += 4; - int save = SkDisplayList::fDumpIndex; - if (use) //just in case - use->dump(maker); - SkDisplayList::fIndent -= 4; - SkDisplayList::fDumpIndex = save; - dumpEnd(maker); -} -#endif - -bool SkAdd::enable(SkAnimateMaker& maker ) { - SkDisplayTypes type = getType(); - SkDisplayList& displayList = maker.fDisplayList; - SkTDDrawableArray* parentList = displayList.getDrawList(); - if (type == SkType_Add) { - if (use == nullptr) // not set in apply yet - return true; - } - bool skipAddToParent = true; - SkASSERT(type != SkType_Replace || where); - SkTDDrawableArray* grandList SK_INIT_TO_AVOID_WARNING; - SkGroup* parentGroup = nullptr; - SkGroup* thisGroup = nullptr; - int index = where ? displayList.findGroup(where, &parentList, &parentGroup, - &thisGroup, &grandList) : 0; - if (index < 0) - return true; - int max = parentList->count(); - if (where == nullptr && type == SkType_Move) - index = max; - if (offset != SK_MaxS32) { - index += offset; - if (index > max) { - maker.setErrorCode(SkDisplayXMLParserError::kIndexOutOfRange); - return true; // caller should not add - } - } - if (offset < 0 && where == nullptr) - index += max + 1; - switch (type) { - case SkType_Add: - if (offset == SK_MaxS32 && where == nullptr) { - if (use->isDrawable()) { - skipAddToParent = mode == kMode_immediate; - if (skipAddToParent) { - if (where == nullptr) { - SkTDDrawableArray* useParentList; - index = displayList.findGroup(this, &useParentList, &parentGroup, - &thisGroup, &grandList); - if (index >= 0) { - parentGroup->markCopySize(index); - parentGroup->markCopySet(index); - useParentList->begin()[index] = use; - break; - } - } - *parentList->append() = use; - } - } - break; - } else { - if (thisGroup) - thisGroup->markCopySize(index); - *parentList->insert(index) = use; - if (thisGroup) - thisGroup->markCopySet(index); - if (use->isApply()) - ((SkApply*) use)->setEmbedded(); - } - break; - case SkType_Move: { - int priorLocation = parentList->find(use); - if (priorLocation < 0) - break; - *parentList->insert(index) = use; - if (index < priorLocation) - priorLocation++; - parentList->remove(priorLocation); - } break; - case SkType_Remove: { - SkDisplayable* old = (*parentList)[index]; - if (((SkRemove*)(this))->fDelete) { - delete old; - goto noHelperNeeded; - } - for (int inner = 0; inner < maker.fChildren.count(); inner++) { - SkDisplayable* child = maker.fChildren[inner]; - if (child == old || child->contains(old)) - goto noHelperNeeded; - } - if (maker.fHelpers.find(old) < 0) - maker.helperAdd(old); -noHelperNeeded: - parentList->remove(index); - } break; - case SkType_Replace: - if (thisGroup) { - thisGroup->markCopySize(index); - if (thisGroup->markedForDelete(index)) { - SkDisplayable* old = (*parentList)[index]; - if (maker.fHelpers.find(old) < 0) - maker.helperAdd(old); - } - } - (*parentList)[index] = use; - if (thisGroup) - thisGroup->markCopySet(index); - break; - default: - SkASSERT(0); - } - if (type == SkType_Remove) - return true; - if (use->hasEnable()) - use->enable(maker); - return skipAddToParent; // append if indirect: *parentList->append() = this; -} - -bool SkAdd::hasEnable() const { - return true; -} - -void SkAdd::initialize() { - if (use) - use->initialize(); -} - -bool SkAdd::isDrawable() const { - return getType() == SkType_Add && mode == kMode_indirect && offset == SK_MaxS32 && - where == nullptr && use != nullptr && use->isDrawable(); -} - -//SkDisplayable* SkAdd::resolveTarget(SkAnimateMaker& maker) { -// return use; -//} - - -bool SkClear::enable(SkAnimateMaker& maker ) { - SkDisplayList& displayList = maker.fDisplayList; - displayList.clear(); - return true; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkMove::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkMove); - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkRemove::fInfo[] = { - SK_MEMBER_ALIAS(delete, fDelete, Boolean), // !!! experimental - SK_MEMBER(offset, Int), - SK_MEMBER(where, Drawable) -}; - -#endif - -DEFINE_GET_MEMBER(SkRemove); - -SkRemove::SkRemove() : fDelete(false) { -} - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkReplace::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkReplace); diff --git a/gfx/skia/skia/src/animator/SkDisplayAdd.h b/gfx/skia/skia/src/animator/SkDisplayAdd.h deleted file mode 100644 index eb4610b39f5d..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayAdd.h +++ /dev/null @@ -1,71 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayAdd_DEFINED -#define SkDisplayAdd_DEFINED - -#include "SkADrawable.h" -#include "SkMemberInfo.h" - -class SkAdd : public SkADrawable { - DECLARE_MEMBER_INFO(Add); - SkAdd(); - - enum Mode { - kMode_indirect, - kMode_immediate - }; - - SkDisplayable* deepCopy(SkAnimateMaker* ) override; - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - bool enable(SkAnimateMaker& ) override; - bool hasEnable() const override; - void initialize() override; - bool isDrawable() const override; -protected: -// struct _A { - Mode mode; - int32_t offset; - SkADrawable* use; - SkADrawable* where; // if nullptr, offset becomes index -// } A; -private: - typedef SkADrawable INHERITED; -}; - -class SkClear : public SkDisplayable { - virtual bool enable(SkAnimateMaker& ); -}; - -class SkMove : public SkAdd { - DECLARE_MEMBER_INFO(Move); -private: - typedef SkAdd INHERITED; -}; - -class SkRemove : public SkAdd { - DECLARE_MEMBER_INFO(Remove); - SkRemove(); -protected: - SkBool fDelete; -private: - friend class SkAdd; - typedef SkAdd INHERITED; -}; - -class SkReplace : public SkAdd { - DECLARE_MEMBER_INFO(Replace); -private: - typedef SkAdd INHERITED; -}; - -#endif // SkDisplayAdd_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayApply.cpp b/gfx/skia/skia/src/animator/SkDisplayApply.cpp deleted file mode 100644 index 0d5f09d342f6..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayApply.cpp +++ /dev/null @@ -1,804 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayApply.h" -#include "SkAnimateActive.h" -#include "SkAnimateMaker.h" -#include "SkAnimateSet.h" -#include "SkAnimatorScript.h" -#include "SkDisplayType.h" -#include "SkDrawGroup.h" -#include "SkParse.h" -#include "SkScript.h" -#include "SkSystemEventTypes.h" -#ifdef SK_DEBUG -#include "SkTime.h" -#endif -#include - -enum SkApply_Properties { - SK_PROPERTY(animator), - SK_PROPERTY(step), - SK_PROPERTY(steps), - SK_PROPERTY(time) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -// if no attibutes, enclosed displayable is both scope & target -// only if both scope & target are specified, or if target and enclosed displayable, are scope and target different -const SkMemberInfo SkApply::fInfo[] = { - SK_MEMBER_PROPERTY(animator, Animate), - SK_MEMBER(begin, MSec), - SK_MEMBER(dontDraw, Boolean), - SK_MEMBER(dynamicScope, String), - SK_MEMBER(interval, MSec), // recommended redraw interval - SK_MEMBER(mode, ApplyMode), -#if 0 - SK_MEMBER(pickup, Boolean), -#endif - SK_MEMBER(restore, Boolean), - SK_MEMBER(scope, Drawable), // thing that scopes animation (unnamed enclosed displayable goes here) - SK_MEMBER_PROPERTY(step, Int), - SK_MEMBER_PROPERTY(steps, Int), - SK_MEMBER_PROPERTY(time, MSec), - SK_MEMBER(transition, ApplyTransition) -}; - -#endif - -DEFINE_GET_MEMBER(SkApply); - -SkApply::SkApply() : begin(0), dontDraw(false), interval((SkMSec) -1), mode((Mode) -1), /*pickup(false), */ - restore(false), scope(nullptr), steps(-1), transition((Transition) -1), fActive(nullptr), /*fCurrentScope(nullptr),*/ - fLastTime(0), fAppended(false), fContainsScope(false), fDeleteScope(false), fEmbedded(false), - fEnabled(false), fEnabling(false) { -} - -SkApply::~SkApply() { - for (SkADrawable** curPtr = fScopes.begin(); curPtr < fScopes.end(); curPtr++) - delete *curPtr; - if (fDeleteScope) - delete scope; - // !!! caller must call maker.removeActive(fActive) - delete fActive; -} - -void SkApply::activate(SkAnimateMaker& maker) { - if (fActive != nullptr) { - if (fActive->fDrawIndex == 0 && fActive->fDrawMax == 0) - return; // if only one use, nothing more to do - if (restore == false) - return; // all share same state, regardless of instance number - bool save = fActive->initializeSave(); - fActive->fixInterpolator(save); - } else { - fActive = new SkActive(*this, maker); - fActive->init(); - maker.appendActive(fActive); - if (restore) { - fActive->initializeSave(); - int animators = fAnimators.count(); - for (int index = 0; index < animators; index++) - fActive->saveInterpolatorValues(index); - } - } -} - -void SkApply::append(SkApply* apply) { - if (fActive == nullptr) - return; - int oldCount = fActive->fAnimators.count(); - fActive->append(apply); - if (restore) { - fActive->appendSave(oldCount); - int newCount = fActive->fAnimators.count(); - for (int index = oldCount; index < newCount; index++) - fActive->saveInterpolatorValues(index); - } -} - -void SkApply::applyValues(int animatorIndex, SkOperand* values, int count, - SkDisplayTypes valuesType, SkMSec time) -{ - SkAnimateBase* animator = fActive->fAnimators[animatorIndex]; - const SkMemberInfo * info = animator->fFieldInfo; - SkASSERT(animator); - SkASSERT(info != nullptr); - SkDisplayTypes type = (SkDisplayTypes) info->fType; - SkDisplayable* target = getTarget(animator); - if (animator->hasExecute() || type == SkType_MemberFunction || type == SkType_MemberProperty) { - SkDisplayable* executor = animator->hasExecute() ? animator : target; - if (type != SkType_MemberProperty) { - SkTDArray typedValues; - for (int index = 0; index < count; index++) { - SkScriptValue temp; - temp.fType = valuesType; - temp.fOperand = values[index]; - *typedValues.append() = temp; - } - executor->executeFunction(target, info->functionIndex(), typedValues, info->getType(), nullptr); - } else { - SkScriptValue scriptValue; - scriptValue.fOperand = values[0]; - scriptValue.fType = info->getType(); - target->setProperty(info->propertyIndex(), scriptValue); - } - } else { - SkTypedArray converted; - if (type == SkType_ARGB) { - if (count == 4) { - // !!! assert that it is SkType_Float ? - animator->packARGB(&values->fScalar, count, &converted); - values = converted.begin(); - count = converted.count(); - } else { - SkASSERT(count == 1); - } - } -// SkASSERT(type == SkType_ARGB || type == SkType_String ||info->isSettable()); - if (type == SkType_String || type == SkType_DynamicString) - info->setString(target, values->fString); - else if (type == SkType_Drawable || type == SkType_Displayable) - target->setReference(info, values->fDisplayable); - else - info->setValue(target, values, count); - } -} - -bool SkApply::contains(SkDisplayable* child) { - for (SkADrawable** curPtr = fScopes.begin(); curPtr < fScopes.end(); curPtr++) { - if (*curPtr == child || (*curPtr)->contains(child)) - return true; - } - return fDeleteScope && scope == child; -} - -SkDisplayable* SkApply::deepCopy(SkAnimateMaker* maker) { - SkADrawable* saveScope = scope; - scope = nullptr; - SkApply* result = (SkApply*) INHERITED::deepCopy(maker); - result->scope = scope = saveScope; - SkAnimateBase** end = fAnimators.end(); - for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < end; animPtr++) { - SkAnimateBase* anim = (SkAnimateBase*) (*animPtr)->deepCopy(maker); - *result->fAnimators.append() = anim; - maker->helperAdd(anim); - } - return result; -} - -void SkApply::disable() { - //!!! this is the right thing to do, but has bad side effects because of other problems - // currently, if an apply is in a g and scopes a statement in another g, it ends up as members - // of both containers. The disabling here incorrectly disables both instances - // maybe the fEnabled flag needs to be moved to the fActive data so that both - // instances are not affected. -// fEnabled = false; -} - -bool SkApply::draw(SkAnimateMaker& maker) { - if (scope ==nullptr) - return false; - if (scope->isApply() || scope->isDrawable() == false) - return false; - if (fEnabled == false) - enable(maker); - SkASSERT(scope); - activate(maker); - if (mode == kMode_immediate) - return fActive->draw(); - bool result = interpolate(maker, maker.getInTime()); - if (dontDraw == false) { -// if (scope->isDrawable()) - result |= scope->draw(maker); - } - if (restore) { - for (int index = 0; index < fActive->fAnimators.count(); index++) - endSave(index); - fActive->advance(); - } - return result; -} - -#ifdef SK_DUMP_ENABLED -void SkApply::dump(SkAnimateMaker* maker) { - dumpBase(maker); - if (dynamicScope.isEmpty() == false) - SkDebugf("dynamicScope=\"%s\" ", dynamicScope.c_str()); - if (dontDraw) - SkDebugf("dontDraw=\"true\" "); - if (begin != 0) //perhaps we want this no matter what? - SkDebugf("begin=\"%g\" ", (float) begin/1000.0f); //is this correct? - if (interval != (SkMSec) -1) - SkDebugf("interval=\"%g\" ", (float) interval/1000.0f); - if (steps != -1) - SkDebugf("steps=\"%d\" ", steps); - if (restore) - SkDebugf("restore=\"true\" "); - if (transition == kTransition_reverse) - SkDebugf("transition=\"reverse\" "); - if (mode == kMode_immediate) { - SkDebugf("mode=\"immediate\" "); - } - else if (mode == kMode_create) { - SkDebugf("mode=\"create\" "); - } - bool closedYet = false; - SkDisplayList::fIndent += 4; - int save = SkDisplayList::fDumpIndex; - if (scope) { - if (closedYet == false) { - SkDebugf(">\n"); - closedYet = true; - } - scope->dump(maker); - } - int index; -// if (fActive) { - for (index = 0; index < fAnimators.count(); index++) { - if (closedYet == false) { - SkDebugf(">\n"); - closedYet = true; - } - SkAnimateBase* animator = fAnimators[index]; - animator->dump(maker); -// } - } - SkDisplayList::fIndent -= 4; - SkDisplayList::fDumpIndex = save; - if (closedYet) - dumpEnd(maker); - else - SkDebugf("/>\n"); -} -#endif - -bool SkApply::enable(SkAnimateMaker& maker) { - fEnabled = true; - bool initialized = fActive != nullptr; - if (dynamicScope.size() > 0) - enableDynamic(maker); - if (maker.fError.hasError()) - return false; - int animators = fAnimators.count(); - int index; - for (index = 0; index < animators; index++) { - SkAnimateBase* animator = fAnimators[index]; - animator->fStart = maker.fEnableTime; - animator->fResetPending = animator->fReset; - } - if (scope && scope->isApply()) - ((SkApply*) scope)->setEmbedded(); -/* if (mode == kMode_once) { - if (scope) { - activate(maker); - interpolate(maker, maker.fEnableTime); - inactivate(maker); - } - return true; - }*/ - if ((mode == kMode_immediate || mode == kMode_create) && scope == nullptr) - return false; // !!! error? - bool enableMe = scope && (scope->hasEnable() || scope->isApply() || scope->isDrawable() == false); - if ((mode == kMode_immediate && enableMe) || mode == kMode_create) - activate(maker); // for non-drawables like post, prime them here - if (mode == kMode_immediate && enableMe) - fActive->enable(); - if (mode == kMode_create && scope != nullptr) { - enableCreate(maker); - return true; - } - if (mode == kMode_immediate) { - return scope->isApply() || scope->isDrawable() == false; - } - refresh(maker); - SkDisplayList& displayList = maker.fDisplayList; - SkADrawable* drawable; -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - SkString debugOut; - SkMSec time = maker.getAppTime(); - debugOut.appendS32(time - maker.fDebugTimeBase); - debugOut.append(" apply enable id="); - debugOut.append(_id); - debugOut.append("; start="); - debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase); - SkDebugf("%s\n", debugOut.c_str()); -#endif - if (scope == nullptr || scope->isApply() || scope->getType() == SkType_Movie || scope->isDrawable() == false) { - activate(maker); // for non-drawables like post, prime them here - if (initialized) { - append(this); - } - fEnabling = true; - interpolate(maker, maker.fEnableTime); - fEnabling = false; - if (scope != nullptr && dontDraw == false) - scope->enable(maker); - return true; - } else if (initialized && restore == false) - append(this); -#if 0 - bool wasActive = inactivate(maker); // start fresh - if (wasActive) { - activate(maker); - interpolate(maker, maker.fEnableTime); - return true; - } -#endif -// start here; - // now that one apply might embed another, only the parent apply should replace the scope - // or get appended to the display list - // similarly, an apply added by an add immediate has already been located in the display list - // and should not get moved or added again here - if (fEmbedded) { - return false; // already added to display list by embedder - } - drawable = (SkADrawable*) scope; - SkTDDrawableArray* parentList; - SkTDDrawableArray* grandList; - SkGroup* parentGroup; - SkGroup* thisGroup; - int old = displayList.findGroup(drawable, &parentList, &parentGroup, &thisGroup, &grandList); - if (old < 0) - goto append; - else if (fContainsScope) { - if ((*parentList)[old] != this || restore) { -append: - if (parentGroup) - parentGroup->markCopySize(old); - if (parentList->count() < 10000) { - fAppended = true; - *parentList->append() = this; - } else - maker.setErrorCode(SkDisplayXMLParserError::kDisplayTreeTooDeep); - old = -1; - } else - reset(); - } else { - SkASSERT(old < parentList->count()); - if ((*parentList)[old]->isApply()) { - SkApply* apply = (SkApply*) (*parentList)[old]; - if (apply != this && apply->fActive == nullptr) - apply->activate(maker); - apply->append(this); - parentGroup = nullptr; - } else { - if (parentGroup) - parentGroup->markCopySize(old); - SkADrawable** newApplyLocation = &(*parentList)[old]; - SkGroup* pGroup; - int oldApply = displayList.findGroup(this, &parentList, &pGroup, &thisGroup, &grandList); - if (oldApply >= 0) { - (*parentList)[oldApply] = (SkADrawable*) SkDisplayType::CreateInstance(&maker, SkType_Apply); - parentGroup = nullptr; - fDeleteScope = true; - } - *newApplyLocation = this; - } - } - if (parentGroup) { - parentGroup->markCopySet(old); - fDeleteScope = dynamicScope.size() == 0; - } - return true; -} - -void SkApply::enableCreate(SkAnimateMaker& maker) { - SkString newID; - for (int step = 0; step <= steps; step++) { - fLastTime = step * SK_MSec1; - bool success = maker.computeID(scope, this, &newID); - if (success == false) - return; - if (maker.find(newID.c_str(), nullptr)) - continue; - SkApply* copy = (SkApply*) deepCopy(&maker); // work on copy of animator state - if (mode == kMode_create) - copy->mode = (Mode) -1; - SkADrawable* copyScope = copy->scope = (SkADrawable*) scope->deepCopy(&maker); - *fScopes.append() = copyScope; - if (copyScope->resolveIDs(maker, scope, this)) { - step = steps; // quit - goto next; // resolveIDs failed - } - if (newID.size() > 0) - maker.setID(copyScope, newID); - if (copy->resolveIDs(maker, this, this)) { // fix up all fields, including target - step = steps; // quit - goto next; // resolveIDs failed - } - copy->activate(maker); - copy->interpolate(maker, step * SK_MSec1); - maker.removeActive(copy->fActive); - next: - delete copy; - } -} - -void SkApply::enableDynamic(SkAnimateMaker& maker) { - SkASSERT(mode != kMode_create); // create + dynamic are not currently compatible - SkDisplayable* newScope; - bool success = SkAnimatorScript::EvaluateDisplayable(maker, this, dynamicScope.c_str(), - &newScope); - if (success && scope != newScope) { - SkTDDrawableArray* pList, * gList; - SkGroup* pGroup = nullptr, * found = nullptr; - int old = maker.fDisplayList.findGroup(scope, &pList, &pGroup, &found, &gList); - if (pList && old >= 0 && (*pList)[old]->isApply() && (*pList)[old] != this) { - if (fAppended == false) { - if (found != nullptr) { - SkDisplayable* oldChild = (*pList)[old]; - if (oldChild->isApply() && found->copySet(old)) { - found->markCopyClear(old); - // delete oldChild; - } - } - (*pList)[old] = scope; - } else - pList->remove(old); - } - scope = (SkADrawable*) newScope; - onEndElement(maker); - } - maker.removeActive(fActive); - delete fActive; - fActive = nullptr; -} - -void SkApply::endSave(int index) { - SkAnimateBase* animate = fActive->fAnimators[index]; - const SkMemberInfo* info = animate->fFieldInfo; - SkDisplayTypes type = (SkDisplayTypes) info->fType; - if (type == SkType_MemberFunction) - return; - SkDisplayable* target = getTarget(animate); - size_t size = info->getSize(target); - int count = (int) (size / sizeof(SkScalar)); - int activeIndex = fActive->fDrawIndex + index; - SkOperand* last = new SkOperand[count]; - SkAutoTDelete autoLast(last); - if (type != SkType_MemberProperty) { - info->getValue(target, last, count); - SkOperand* saveOperand = fActive->fSaveRestore[activeIndex]; - if (saveOperand) - info->setValue(target, fActive->fSaveRestore[activeIndex], count); - } else { - SkScriptValue scriptValue; - SkDEBUGCODE(bool success = ) target->getProperty(info->propertyIndex(), &scriptValue); - SkASSERT(success == true); - last[0] = scriptValue.fOperand; - scriptValue.fOperand = fActive->fSaveRestore[activeIndex][0]; - target->setProperty(info->propertyIndex(), scriptValue); - } - SkOperand* save = fActive->fSaveRestore[activeIndex]; - if (save) - memcpy(save, last, count * sizeof(SkOperand)); -} - -bool SkApply::getProperty(int index, SkScriptValue* value) const { - switch (index) { - case SK_PROPERTY(step): - value->fType = SkType_Int; - value->fOperand.fS32 = fLastTime / SK_MSec1; - break; - case SK_PROPERTY(steps): - value->fType = SkType_Int; - value->fOperand.fS32 = steps; - break; - case SK_PROPERTY(time): - value->fType = SkType_MSec; - value->fOperand.fS32 = fLastTime; - break; - default: - // SkASSERT(0); - return false; - } - return true; -} - -void SkApply::getStep(SkScriptValue* value) { - getProperty(SK_PROPERTY(step), value); -} - -SkADrawable* SkApply::getTarget(SkAnimateBase* animate) { - if (animate->fTargetIsScope == false || mode != kMode_create) - return animate->fTarget; - return scope; -} - -bool SkApply::hasDelayedAnimator() const { - SkAnimateBase* const* animEnd = fAnimators.end(); - for (SkAnimateBase* const* animPtr = fAnimators.begin(); animPtr < animEnd; animPtr++) { - SkAnimateBase* const animator = *animPtr; - if (animator->fDelayed) - return true; - } - return false; -} - -bool SkApply::hasEnable() const { - return true; -} - -bool SkApply::inactivate(SkAnimateMaker& maker) { - if (fActive == nullptr) - return false; - maker.removeActive(fActive); - delete fActive; - fActive = nullptr; - return true; -} - -#ifdef SK_DEBUG -SkMSec lastTime = (SkMSec) -1; -#endif - -bool SkApply::interpolate(SkAnimateMaker& maker, SkMSec rawTime) { - if (fActive == nullptr) - return false; - bool result = false; -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - SkMSec time = maker.getAppTime(); - if (lastTime == (SkMSec) -1) - lastTime = rawTime - 1; - if (fActive != nullptr && - strcmp(id, "a3") == 0 && rawTime > lastTime) { - lastTime += 1000; - SkString debugOut; - debugOut.appendS32(time - maker.fDebugTimeBase); - debugOut.append(" apply id="); - debugOut.append(_id); - debugOut.append("; "); - debugOut.append(fActive->fAnimators[0]->_id); - debugOut.append("="); - debugOut.appendS32(rawTime - fActive->fState[0].fStartTime); - debugOut.append(")"); - SkDebugf("%s\n", debugOut.c_str()); - } -#endif - fActive->start(); - if (restore) - fActive->initializeSave(); - int animators = fActive->fAnimators.count(); - for (int inner = 0; inner < animators; inner++) { - SkAnimateBase* animate = fActive->fAnimators[inner]; - if (animate->fChanged) { - animate->fChanged = false; - animate->fStart = rawTime; - // SkTypedArray values; - // int count = animate->fValues.count(); - // values.setCount(count); - // memcpy(values.begin(), animate->fValues.begin(), sizeof(SkOperand) * count); - animate->onEndElement(maker); - // if (memcmp(values.begin(), animate->fValues.begin(), sizeof(SkOperand) * count) != 0) { - fActive->append(this); - fActive->start(); - // } - } - SkMSec time = fActive->getTime(rawTime, inner); - SkActive::SkState& state = fActive->fState[inner]; - if (SkMSec_LT(rawTime, state.fStartTime)) { - if (fEnabling) { - animate->fDelayed = true; - maker.delayEnable(this, state.fStartTime); - } - continue; - } else - animate->fDelayed = false; - SkMSec innerTime = fLastTime = state.getRelativeTime(time); - if (restore) - fActive->restoreInterpolatorValues(inner); - if (animate->fReset) { - if (transition != SkApply::kTransition_reverse) { - if (SkMSec_LT(state.fBegin + state.fDuration, innerTime)) { - if (animate->fResetPending) { - innerTime = 0; - animate->fResetPending = false; - } else - continue; - } - } else if (innerTime == 0) { - if (animate->fResetPending) { - innerTime = state.fBegin + state.fDuration; - animate->fResetPending = false; - } else - continue; - } - } - int count = animate->components(); - SkAutoSTMalloc<16, SkOperand> values(count); - SkInterpolatorBase::Result interpResult = fActive->fInterpolators[inner]->timeToValues( - innerTime, values.get()); - result |= (interpResult != SkInterpolatorBase::kFreezeEnd_Result); - if (((transition != SkApply::kTransition_reverse && interpResult == SkInterpolatorBase::kFreezeEnd_Result) || - (transition == SkApply::kTransition_reverse && fLastTime == 0)) && state.fUnpostedEndEvent) { -// SkDEBUGF(("interpolate: post on end\n")); - state.fUnpostedEndEvent = false; - maker.postOnEnd(animate, state.fBegin + state.fDuration); - maker.fAdjustedStart = 0; // !!! left over from synchronizing animation days, undoubtably out of date (and broken) - } - if (animate->formula.size() > 0) { - if (fLastTime > animate->dur) - fLastTime = animate->dur; - SkTypedArray formulaValues; - formulaValues.setCount(count); - SkDEBUGCODE(bool success = ) animate->fFieldInfo->setValue(maker, &formulaValues, 0, 0, nullptr, - animate->getValuesType(), animate->formula); - SkASSERT(success); - if (restore) - save(inner); // save existing value - applyValues(inner, formulaValues.begin(), count, animate->getValuesType(), innerTime); - } else { - if (restore) - save(inner); // save existing value - applyValues(inner, values.get(), count, animate->getValuesType(), innerTime); - } - } - return result; -} - -void SkApply::initialize() { - if (scope == nullptr) - return; - if (scope->isApply() || scope->isDrawable() == false) - return; - scope->initialize(); -} - -void SkApply::onEndElement(SkAnimateMaker& maker) -{ - SkADrawable* scopePtr = scope; - while (scopePtr && scopePtr->isApply()) { - SkApply* scopedApply = (SkApply*) scopePtr; - if (scopedApply->scope == this) { - maker.setErrorCode(SkDisplayXMLParserError::kApplyScopesItself); - return; - } - scopePtr = scopedApply->scope; - } - if (mode == kMode_create) - return; - if (scope != nullptr && steps >= 0 && scope->isApply() == false && scope->isDrawable()) - scope->setSteps(steps); - for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < fAnimators.end(); animPtr++) { - SkAnimateBase* anim = *animPtr; - //for reusing apply statements with dynamic scope - if (anim->fTarget == nullptr || anim->fTargetIsScope) { - anim->fTargetIsScope = true; - if (scope) - anim->fTarget = scope; - else - anim->setTarget(maker); - anim->onEndElement(maker); // allows animate->fFieldInfo to be set - } - if (scope != nullptr && steps >= 0 && anim->fTarget != scope && anim->fTarget->isDrawable()) - anim->fTarget->setSteps(steps); - } -} - -const SkMemberInfo* SkApply::preferredChild(SkDisplayTypes type) { - SkASSERT(SkDisplayType::IsAnimate(type) == false); - fContainsScope = true; - return getMember("scope"); // !!! cwap! need to refer to member through enum like kScope instead -} - -void SkApply::refresh(SkAnimateMaker& maker) { - for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < fAnimators.end(); animPtr++) { - SkAnimateBase* animate = *animPtr; - animate->onEndElement(maker); - } - if (fActive) - fActive->resetInterpolators(); -} - -void SkApply::reset() { - if (fActive) - fActive->resetState(); -} - -bool SkApply::resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply) { // replace to/formula strings in animators of the form xxx.step with the step value, if xxx.step is in scope - if (resolveField(maker, apply, &dynamicScope) == false) - return true; // failed - SkAnimateBase** endPtr = fAnimators.end(); - SkAnimateBase** origPtr = ((SkApply*) original)->fAnimators.begin(); - for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < endPtr; ) { - SkAnimateBase* animator = *animPtr++; - maker.resolveID(animator, *origPtr++); - if (resolveField(maker, this, &animator->target) == false) - return true; - if (resolveField(maker, this, &animator->from) == false) - return true; - if (resolveField(maker, this, &animator->to) == false) - return true; - if (resolveField(maker, this, &animator->formula) == false) - return true; - } -// setEmbedded(); - onEndElement(maker); - return false; // succeeded -} - -bool SkApply::resolveField(SkAnimateMaker& maker, SkDisplayable* parent, SkString* str) { - const char* script = str->c_str(); - if (str->startsWith("#string:") == false) - return true; - script += sizeof("#string:") - 1; - return SkAnimatorScript::EvaluateString(maker, this, parent, script, str); -} - -void SkApply::save(int index) { - SkAnimateBase* animate = fActive->fAnimators[index]; - const SkMemberInfo * info = animate->fFieldInfo; - SkDisplayable* target = getTarget(animate); -// if (animate->hasExecute()) -// info = animate->getResolvedInfo(); - SkDisplayTypes type = (SkDisplayTypes) info->fType; - if (type == SkType_MemberFunction) - return; // nothing to save - size_t size = info->getSize(target); - int count = (int) (size / sizeof(SkScalar)); - bool useLast = true; -// !!! this all may be unneeded, at least in the dynamic case ?? - int activeIndex = fActive->fDrawIndex + index; - SkTDOperandArray last; - if (fActive->fSaveRestore[activeIndex] == nullptr) { - fActive->fSaveRestore[activeIndex] = new SkOperand[count]; - useLast = false; - } else { - last.setCount(count); - memcpy(last.begin(), fActive->fSaveRestore[activeIndex], count * sizeof(SkOperand)); - } - if (type != SkType_MemberProperty) { - info->getValue(target, fActive->fSaveRestore[activeIndex], count); - if (useLast) - info->setValue(target, last.begin(), count); - } else { - SkScriptValue scriptValue; - SkDEBUGCODE(bool success = ) target->getProperty(info->propertyIndex(), &scriptValue); - SkASSERT(success == true); - SkASSERT(scriptValue.fType == SkType_Float); - fActive->fSaveRestore[activeIndex][0] = scriptValue.fOperand; - if (useLast) { - SkScriptValue scriptValue; - scriptValue.fType = type; - scriptValue.fOperand = last[0]; - target->setProperty(info->propertyIndex(), scriptValue); - } - } -// !!! end of unneeded -} - -bool SkApply::setProperty(int index, SkScriptValue& scriptValue) { - switch (index) { - case SK_PROPERTY(animator): { - SkAnimateBase* animate = (SkAnimateBase*) scriptValue.fOperand.fDisplayable; - SkASSERT(animate->isAnimate()); - *fAnimators.append() = animate; - return true; - } - case SK_PROPERTY(steps): - steps = scriptValue.fOperand.fS32; - if (fActive) - fActive->setSteps(steps); - return true; - } - return false; -} - -void SkApply::setSteps(int _steps) { - steps = _steps; -} - -#ifdef SK_DEBUG -void SkApply::validate() { - if (fActive) - fActive->validate(); -} -#endif diff --git a/gfx/skia/skia/src/animator/SkDisplayApply.h b/gfx/skia/skia/src/animator/SkDisplayApply.h deleted file mode 100644 index 12cf6cee7a96..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayApply.h +++ /dev/null @@ -1,106 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayApply_DEFINED -#define SkDisplayApply_DEFINED - -#include "SkAnimateBase.h" -#include "SkADrawable.h" -#include "SkIntArray.h" - -class SkActive; - -class SkApply : public SkADrawable { - DECLARE_MEMBER_INFO(Apply); -public: - - SkApply(); - virtual ~SkApply(); - - enum Transition { - kTransition_normal, - kTransition_reverse - }; - - enum Mode { - kMode_create, - kMode_immediate, - //kMode_once - }; - void activate(SkAnimateMaker& ); - void append(SkApply* apply); - void appendActive(SkActive* ); - void applyValues(int animatorIndex, SkOperand* values, int count, - SkDisplayTypes , SkMSec time); - bool contains(SkDisplayable*) override; -// void createActive(SkAnimateMaker& ); - SkDisplayable* deepCopy(SkAnimateMaker* ) override; - void disable(); - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - bool enable(SkAnimateMaker& ) override; - void enableCreate(SkAnimateMaker& ); - void enableDynamic(SkAnimateMaker& ); - void endSave(int index); - Mode getMode() { return mode; } - bool getProperty(int index, SkScriptValue* value) const override; - SkADrawable* getScope() { return scope; } - void getStep(SkScriptValue* ); - SkADrawable* getTarget(SkAnimateBase* ); - bool hasDelayedAnimator() const; - bool hasEnable() const override; - bool inactivate(SkAnimateMaker& maker); - void initialize() override; - bool interpolate(SkAnimateMaker& , SkMSec time); - void onEndElement(SkAnimateMaker& ) override; - const SkMemberInfo* preferredChild(SkDisplayTypes type) override; - void refresh(SkAnimateMaker& ); - void reset(); - bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* ) override; - bool resolveField(SkAnimateMaker& , SkDisplayable* parent, SkString* str); - void save(int index); - void setEmbedded() { fEmbedded = true; } - bool setProperty(int index, SkScriptValue& ) override; - void setSteps(int _steps) override; -// virtual void setTime(SkMSec time); -#ifdef SK_DEBUG - void validate() override; -#endif -private: - SkMSec begin; - SkBool dontDraw; - SkString dynamicScope; - SkMSec interval; - Mode mode; -#if 0 - SkBool pickup; -#endif - SkBool restore; - SkADrawable* scope; - int32_t steps; - Transition transition; - SkActive* fActive; - SkTDAnimateArray fAnimators; -// SkADrawable* fCurrentScope; - SkMSec fLastTime; // used only to return script property time - SkTDDrawableArray fScopes; - SkBool fAppended : 1; - SkBool fContainsScope : 1; - SkBool fDeleteScope : 1; - SkBool fEmbedded : 1; - SkBool fEnabled : 1; - SkBool fEnabling : 1; // set if calling interpolate from enable - friend class SkActive; - friend class SkDisplayList; - typedef SkADrawable INHERITED; -}; - -#endif // SkDisplayApply_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayBounds.cpp b/gfx/skia/skia/src/animator/SkDisplayBounds.cpp deleted file mode 100644 index 49ec9b96a29a..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayBounds.cpp +++ /dev/null @@ -1,43 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayBounds.h" -#include "SkAnimateMaker.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayBounds::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER(inval, Boolean) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayBounds); - -SkDisplayBounds::SkDisplayBounds() : inval(false) { -} - -bool SkDisplayBounds::draw(SkAnimateMaker& maker) { - maker.fDisplayList.fUnionBounds = SkToBool(inval); - maker.fDisplayList.fDrawBounds = false; - fBounds.setEmpty(); - bool result = INHERITED::draw(maker); - maker.fDisplayList.fUnionBounds = false; - maker.fDisplayList.fDrawBounds = true; - if (inval && fBounds.isEmpty() == false) { - SkIRect& rect = maker.fDisplayList.fInvalBounds; - maker.fDisplayList.fHasUnion = true; - if (rect.isEmpty()) - rect = fBounds; - else - rect.join(fBounds); - } - return result; -} diff --git a/gfx/skia/skia/src/animator/SkDisplayBounds.h b/gfx/skia/skia/src/animator/SkDisplayBounds.h deleted file mode 100644 index 547a29e810de..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayBounds.h +++ /dev/null @@ -1,24 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayBounds_DEFINED -#define SkDisplayBounds_DEFINED - -#include "SkDrawRectangle.h" - -class SkDisplayBounds : public SkDrawRect { - DECLARE_DISPLAY_MEMBER_INFO(Bounds); - SkDisplayBounds(); - bool draw(SkAnimateMaker& ) override; -private: - SkBool inval; - typedef SkDrawRect INHERITED; -}; - -#endif // SkDisplayBounds_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayEvent.cpp b/gfx/skia/skia/src/animator/SkDisplayEvent.cpp deleted file mode 100644 index 746780df1c30..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayEvent.cpp +++ /dev/null @@ -1,252 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayEvent.h" -#include "SkAnimateMaker.h" -#include "SkDisplayApply.h" -#include "SkDisplayInput.h" -#include "SkDisplayList.h" -#ifdef SK_DEBUG -#include "SkDump.h" -#endif -#include "SkEvent.h" -#include "SkDisplayInput.h" -#include "SkKey.h" -#include "SkMetaData.h" -#include "SkScript.h" -#include "SkUtils.h" - -enum SkDisplayEvent_Properties { - SK_PROPERTY(key), - SK_PROPERTY(keys) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayEvent::fInfo[] = { - SK_MEMBER(code, EventCode), - SK_MEMBER(disable, Boolean), - SK_MEMBER_PROPERTY(key, String), // a single key (also last key pressed) - SK_MEMBER_PROPERTY(keys, String), // a single key or dash-delimited range of keys - SK_MEMBER(kind, EventKind), - SK_MEMBER(target, String), - SK_MEMBER(x, Float), - SK_MEMBER(y, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayEvent); - -SkDisplayEvent::SkDisplayEvent() : code((SkKey) -1), disable(false), - kind(kUser), x(0), y(0), fLastCode((SkKey) -1), fMax((SkKey) -1), fTarget(nullptr) { -} - -SkDisplayEvent::~SkDisplayEvent() { - deleteMembers(); -} - -bool SkDisplayEvent::addChild(SkAnimateMaker& , SkDisplayable* child) { - *fChildren.append() = child; - return true; -} - -bool SkDisplayEvent::contains(SkDisplayable* match) { - for (int index = 0; index < fChildren.count(); index++) { - if (fChildren[index] == match || fChildren[index]->contains(match)) - return true; - } - return false; -} - -SkDisplayable* SkDisplayEvent::contains(const SkString& match) { - for (int index = 0; index < fChildren.count(); index++) { - SkDisplayable* child = fChildren[index]; - if (child->contains(match)) - return child; - } - return nullptr; -} - -void SkDisplayEvent::deleteMembers() { - for (int index = 0; index < fChildren.count(); index++) { - SkDisplayable* evt = fChildren[index]; - delete evt; - } -} - -#ifdef SK_DUMP_ENABLED -void SkDisplayEvent::dumpEvent(SkAnimateMaker* maker) { - dumpBase(maker); - SkString str; - SkDump::GetEnumString(SkType_EventKind, kind, &str); - SkDebugf("kind=\"%s\" ", str.c_str()); - if (kind == SkDisplayEvent::kKeyPress || kind == SkDisplayEvent::kKeyPressUp) { - if (code >= 0) - SkDump::GetEnumString(SkType_EventCode, code, &str); - else - str.set("none"); - SkDebugf("code=\"%s\" ", str.c_str()); - } - if (kind == SkDisplayEvent::kKeyChar) { - if (fMax != (SkKey) -1 && fMax != code) - SkDebugf("keys=\"%c - %c\" ", code, fMax); - else - SkDebugf("key=\"%c\" ", code); - } - if (fTarget != nullptr) { - SkDebugf("target=\"%s\" ", fTarget->id); - } - if (kind >= SkDisplayEvent::kMouseDown && kind <= SkDisplayEvent::kMouseUp) { - SkDebugf("x=\"%g\" y=\"%g\" ", SkScalarToFloat(x), SkScalarToFloat(y)); - } - if (disable) - SkDebugf("disable=\"true\" "); - SkDebugf("/>\n"); -} -#endif - -bool SkDisplayEvent::enableEvent(SkAnimateMaker& maker) -{ - maker.fActiveEvent = this; - if (fChildren.count() == 0) - return false; - if (disable) - return false; -#ifdef SK_DUMP_ENABLED - if (maker.fDumpEvents) { - SkDebugf("enable: "); - dumpEvent(&maker); - } -#endif - SkDisplayList& displayList = maker.fDisplayList; - for (int index = 0; index < fChildren.count(); index++) { - SkDisplayable* displayable = fChildren[index]; - if (displayable->isGroup()) { - SkTDDrawableArray* parentList = displayList.getDrawList(); - *parentList->append() = (SkADrawable*) displayable; // make it findable before children are enabled - } - if (displayable->enable(maker)) - continue; - if (maker.hasError()) - return true; - if (displayable->isDrawable() == false) - return true; // error - SkADrawable* drawable = (SkADrawable*) displayable; - SkTDDrawableArray* parentList = displayList.getDrawList(); - *parentList->append() = drawable; - } - return false; -} - -bool SkDisplayEvent::getProperty(int index, SkScriptValue* value) const { - switch (index) { - case SK_PROPERTY(key): - case SK_PROPERTY(keys): { - value->fType = SkType_String; - char scratch[8]; - SkKey convert = index == SK_PROPERTY(keys) ? code : fLastCode; - size_t size = convert > 0 ? SkUTF8_FromUnichar(convert, scratch) : 0; - fKeyString.set(scratch, size); - value->fOperand.fString = &fKeyString; - if (index != SK_PROPERTY(keys) || fMax == (SkKey) -1 || fMax == code) - break; - value->fOperand.fString->append("-"); - size = SkUTF8_FromUnichar(fMax, scratch); - value->fOperand.fString->append(scratch, size); - } break; - default: - SkASSERT(0); - return false; - } - return true; -} - -void SkDisplayEvent::onEndElement(SkAnimateMaker& maker) -{ - if (kind == kUser) - return; - maker.fEvents.addEvent(this); - if (kind == kOnEnd) { - SkDEBUGCODE(bool found = ) maker.find(target.c_str(), &fTarget); - SkASSERT(found); - SkASSERT(fTarget && fTarget->isAnimate()); - SkAnimateBase* animate = (SkAnimateBase*) fTarget; - animate->setHasEndEvent(); - } -} - -void SkDisplayEvent::populateInput(SkAnimateMaker& maker, const SkEvent& fEvent) { - const SkMetaData& meta = fEvent.getMetaData(); - SkMetaData::Iter iter(meta); - SkMetaData::Type type; - int number; - const char* name; - while ((name = iter.next(&type, &number)) != nullptr) { - if (name[0] == '\0') - continue; - SkDisplayable* displayable; - SkInput* input; - for (int index = 0; index < fChildren.count(); index++) { - displayable = fChildren[index]; - if (displayable->getType() != SkType_Input) - continue; - input = (SkInput*) displayable; - if (input->name.equals(name)) - goto found; - } - if (!maker.find(name, &displayable) || displayable->getType() != SkType_Input) - continue; - input = (SkInput*) displayable; - found: - switch (type) { - case SkMetaData::kS32_Type: - meta.findS32(name, &input->fInt); - break; - case SkMetaData::kScalar_Type: - meta.findScalar(name, &input->fFloat); - break; - case SkMetaData::kPtr_Type: - SkASSERT(0); - break; // !!! not handled for now - case SkMetaData::kString_Type: - input->string.set(meta.findString(name)); - break; - default: - SkASSERT(0); - } - } - // re-evaluate all animators that may have built their values from input strings - for (SkDisplayable** childPtr = fChildren.begin(); childPtr < fChildren.end(); childPtr++) { - SkDisplayable* displayable = *childPtr; - if (displayable->isApply() == false) - continue; - SkApply* apply = (SkApply*) displayable; - apply->refresh(maker); - } -} - -bool SkDisplayEvent::setProperty(int index, SkScriptValue& value) { - SkASSERT(index == SK_PROPERTY(key) || index == SK_PROPERTY(keys)); - SkASSERT(value.fType == SkType_String); - SkString* string = value.fOperand.fString; - const char* chars = string->c_str(); - int count = SkUTF8_CountUnichars(chars); - SkASSERT(count >= 1); - code = (SkKey) SkUTF8_NextUnichar(&chars); - fMax = code; - SkASSERT(count == 1 || index == SK_PROPERTY(keys)); - if (--count > 0) { - SkASSERT(*chars == '-'); - chars++; - fMax = (SkKey) SkUTF8_NextUnichar(&chars); - SkASSERT(fMax >= code); - } - return true; -} diff --git a/gfx/skia/skia/src/animator/SkDisplayEvent.h b/gfx/skia/skia/src/animator/SkDisplayEvent.h deleted file mode 100644 index d223771a7d60..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayEvent.h +++ /dev/null @@ -1,66 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayEvent_DEFINED -#define SkDisplayEvent_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" -#include "SkIntArray.h" -#include "SkKey.h" - -class SkEvent; - -class SkDisplayEvent : public SkDisplayable { - DECLARE_DISPLAY_MEMBER_INFO(Event); - enum Kind { - kNo_kind, - kKeyChar, - kKeyPress, - kKeyPressUp, //i assume the order here is intended to match with skanimatorscript.cpp - kMouseDown, - kMouseDrag, - kMouseMove, - kMouseUp, - kOnEnd, - kOnload, - kUser - }; - SkDisplayEvent(); - virtual ~SkDisplayEvent(); - bool addChild(SkAnimateMaker& , SkDisplayable* child) override; - bool contains(SkDisplayable*) override; - SkDisplayable* contains(const SkString& ) override; -#ifdef SK_DEBUG - void dumpEvent(SkAnimateMaker* ); -#endif - bool enableEvent(SkAnimateMaker& ); - bool getProperty(int index, SkScriptValue* ) const override; - void onEndElement(SkAnimateMaker& maker) override; - void populateInput(SkAnimateMaker& , const SkEvent& fEvent); - bool setProperty(int index, SkScriptValue& ) override; -protected: - SkKey code; - SkBool disable; - Kind kind; - SkString target; - SkScalar x; - SkScalar y; - SkTDDisplayableArray fChildren; - mutable SkString fKeyString; - SkKey fLastCode; // last key to trigger this event - SkKey fMax; // if the code expresses a range - SkDisplayable* fTarget; // used by onEnd -private: - void deleteMembers(); - friend class SkEvents; - typedef SkDisplayable INHERITED; -}; - -#endif // SkDisplayEvent_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayEvents.cpp b/gfx/skia/skia/src/animator/SkDisplayEvents.cpp deleted file mode 100644 index d367cf11c30e..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayEvents.cpp +++ /dev/null @@ -1,113 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayEvents.h" -#include "SkAnimateMaker.h" -#include "SkAnimator.h" -#include "SkDisplayEvent.h" -#include "SkDisplayMovie.h" -#include "SkADrawable.h" -#ifdef SK_DEBUG -#include "SkDump.h" -#endif - -SkEventState::SkEventState() : fCode(0), fDisable(false), fDisplayable(0), fX(0), fY(0) { -} - -SkEvents::SkEvents() { -} - -SkEvents::~SkEvents() { -} - -bool SkEvents::doEvent(SkAnimateMaker& maker, SkDisplayEvent::Kind kind, SkEventState* state) { -/*#ifdef SK_DUMP_ENABLED - if (maker.fDumpEvents) { - SkDebugf("doEvent: "); - SkString str; - SkDump::GetEnumString(SkType_EventKind, kind, &str); - SkDebugf("kind=%s ", str.c_str()); - if (state && state->fDisplayable) - state->fDisplayable->SkDisplayable::dump(&maker); - else - SkDebugf("\n"); - } -#endif*/ - bool handled = false; - SkDisplayable** firstMovie = maker.fMovies.begin(); - SkDisplayable** endMovie = maker.fMovies.end(); - for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) { - SkDisplayMovie* movie = (SkDisplayMovie*) *ptr; - if (kind != SkDisplayEvent::kOnload) - movie->doEvent(kind, state); - } - SkDisplayable* displayable = state ? state->fDisplayable : nullptr; - int keyCode = state ? state->fCode : 0; - int count = fEvents.count(); - for (int index = 0; index < count; index++) { - SkDisplayEvent* evt = fEvents[index]; - if (evt->disable) - continue; - if (evt->kind != kind) - continue; - if (evt->code != (SkKey) -1) { - if ((int) evt->code > keyCode || (int) (evt->fMax != (SkKey) -1 ? evt->fMax : evt->code) < keyCode) - continue; - evt->fLastCode = (SkKey) keyCode; - } - if (evt->fTarget != nullptr && evt->fTarget != displayable) - continue; - if (state == nullptr || state->fDisable == 0) { - if (kind >= SkDisplayEvent::kMouseDown && kind <= SkDisplayEvent::kMouseUp) { - evt->x = state->fX; - evt->y = state->fY; - } - if (evt->enableEvent(maker)) - fError = true; - } - handled = true; - } - return handled; -} - -#ifdef SK_DUMP_ENABLED -void SkEvents::dump(SkAnimateMaker& maker) { - int index; - SkTDDrawableArray& drawArray = maker.fDisplayList.fDrawList; - int count = drawArray.count(); - for (index = 0; index < count; index++) { - SkADrawable* drawable = drawArray[index]; - drawable->dumpEvents(); - } - count = fEvents.count(); - for (index = 0; index < count; index++) { - SkDisplayEvent* evt = fEvents[index]; - evt->dumpEvent(&maker); - } -} -#endif - -// currently this only removes onLoad events -void SkEvents::removeEvent(SkDisplayEvent::Kind kind, SkEventState* state) { - int keyCode = state ? state->fCode : 0; - SkDisplayable* displayable = state ? state->fDisplayable : nullptr; - for (SkDisplayEvent** evtPtr = fEvents.begin(); evtPtr < fEvents.end(); evtPtr++) { - SkDisplayEvent* evt = *evtPtr; - if (evt->kind != kind) - continue; - if (evt->code != (SkKey) -1) { - if ((int) evt->code > keyCode || (int) (evt->fMax != (SkKey) -1 ? evt->fMax : evt->code) < keyCode) - continue; - } - if (evt->fTarget != nullptr && evt->fTarget != displayable) - continue; - int index = fEvents.find(evt); - fEvents.remove(index); - } -} diff --git a/gfx/skia/skia/src/animator/SkDisplayEvents.h b/gfx/skia/skia/src/animator/SkDisplayEvents.h deleted file mode 100644 index 276955ba6c12..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayEvents.h +++ /dev/null @@ -1,42 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayEvents_DEFINED -#define SkDisplayEvents_DEFINED - -#include "SkEvent.h" -#include "SkDisplayEvent.h" - -struct SkEventState { - SkEventState(); - int fCode; - SkBool fDisable; - SkDisplayable* fDisplayable; - SkScalar fX; - SkScalar fY; -}; - -class SkEvents { -public: - SkEvents(); - ~SkEvents(); - void addEvent(SkDisplayEvent* evt) { *fEvents.append() = evt; } - bool doEvent(SkAnimateMaker& , SkDisplayEvent::Kind , SkEventState* ); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker& ); -#endif - void reset() { fEvents.reset(); } - void removeEvent(SkDisplayEvent::Kind kind, SkEventState* ); -private: - SkTDDisplayEventArray fEvents; - SkBool fError; - friend class SkDisplayXMLParser; -}; - -#endif // SkDisplayEvents_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayInclude.cpp b/gfx/skia/skia/src/animator/SkDisplayInclude.cpp deleted file mode 100644 index 023b3913a5c9..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayInclude.cpp +++ /dev/null @@ -1,52 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayInclude.h" -#include "SkAnimateMaker.h" -#include "SkAnimator.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkInclude::fInfo[] = { - SK_MEMBER(src, String) -}; - -#endif - -DEFINE_GET_MEMBER(SkInclude); - -//SkInclude::SkInclude() { -// src.init(); -//} - -//SkInclude::~SkInclude() { -// src.unref(); -//} - -bool SkInclude::enable(SkAnimateMaker & ) { - return true; -} - -bool SkInclude::hasEnable() const { - return true; -} - -void SkInclude::onEndElement(SkAnimateMaker& maker) { - maker.fInInclude = true; - if (src.size() == 0 || maker.decodeURI(src.c_str()) == false) { - if (maker.getErrorCode() != SkXMLParserError::kNoError || maker.getNativeCode() != -1) { - maker.setInnerError(&maker, src); - maker.setErrorCode(SkDisplayXMLParserError::kInInclude); - } else { - maker.setErrorNoun(src); - maker.setErrorCode(SkDisplayXMLParserError::kIncludeNameUnknownOrMissing); - } - } - maker.fInInclude = false; -} diff --git a/gfx/skia/skia/src/animator/SkDisplayInclude.h b/gfx/skia/skia/src/animator/SkDisplayInclude.h deleted file mode 100644 index cc87dfa7cf67..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayInclude.h +++ /dev/null @@ -1,25 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayInclude_DEFINED -#define SkDisplayInclude_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" - -class SkInclude : public SkDisplayable { - DECLARE_MEMBER_INFO(Include); - void onEndElement(SkAnimateMaker & ) override; - bool enable(SkAnimateMaker & ) override; - bool hasEnable() const override; -protected: - SkString src; -}; - -#endif // SkDisplayInclude_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayInput.cpp b/gfx/skia/skia/src/animator/SkDisplayInput.cpp deleted file mode 100644 index facc7039767a..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayInput.cpp +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayInput.h" - -enum SkInput_Properties { - SK_PROPERTY(initialized) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkInput::fInfo[] = { - SK_MEMBER_ALIAS(float, fFloat, Float), - SK_MEMBER_PROPERTY(initialized, Boolean), - SK_MEMBER_ALIAS(int, fInt, Int), - SK_MEMBER(name, String), - SK_MEMBER(string, String) -}; - -#endif - -DEFINE_GET_MEMBER(SkInput); - -SkInput::SkInput() : fInt((int) SK_NaN32), fFloat(SK_ScalarNaN) {} - -SkDisplayable* SkInput::contains(const SkString& string) { - return string.equals(name) ? this : nullptr; -} - -bool SkInput::enable(SkAnimateMaker & ) { - return true; -} - -bool SkInput::getProperty(int index, SkScriptValue* value) const { - switch (index) { - case SK_PROPERTY(initialized): - value->fType = SkType_Boolean; - value->fOperand.fS32 = fInt != (int) SK_NaN32 || - SkScalarIsNaN(fFloat) == false || string.size() > 0; - break; - default: - return false; - } - return true; -} - -bool SkInput::hasEnable() const { - return true; -} diff --git a/gfx/skia/skia/src/animator/SkDisplayInput.h b/gfx/skia/skia/src/animator/SkDisplayInput.h deleted file mode 100644 index b9a1bac91baf..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayInput.h +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayInput_DEFINED -#define SkDisplayInput_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" - -class SkInput : public SkDisplayable { - DECLARE_MEMBER_INFO(Input); - SkInput(); - SkDisplayable* contains(const SkString& ) override; - bool getProperty(int index, SkScriptValue* value) const override; - bool enable(SkAnimateMaker & ) override; - bool hasEnable() const override; -protected: - SkString name; - int32_t fInt; - SkScalar fFloat; - SkString string; -private: - friend class SkDisplayEvent; - friend class SkPost; -}; - -#endif // SkDisplayInput_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayList.cpp b/gfx/skia/skia/src/animator/SkDisplayList.cpp deleted file mode 100644 index fbba83f4f051..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayList.cpp +++ /dev/null @@ -1,158 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayList.h" -#include "SkAnimateActive.h" -#include "SkAnimateBase.h" -#include "SkAnimateMaker.h" -#include "SkDisplayApply.h" -#include "SkADrawable.h" -#include "SkDrawGroup.h" -#include "SkDrawMatrix.h" -#include "SkInterpolator.h" -#include "SkTime.h" - -SkDisplayList::SkDisplayList() : fDrawBounds(true), fUnionBounds(false), fInTime(0) { -} - -SkDisplayList::~SkDisplayList() { -} - -void SkDisplayList::append(SkActive* active) { - *fActiveList.append() = active; -} - -bool SkDisplayList::draw(SkAnimateMaker& maker, SkMSec inTime) { - validate(); - fInTime = inTime; - bool result = false; - fInvalBounds.setEmpty(); - if (fDrawList.count()) { - for (SkActive** activePtr = fActiveList.begin(); activePtr < fActiveList.end(); activePtr++) { - SkActive* active = *activePtr; - active->reset(); - } - for (int index = 0; index < fDrawList.count(); index++) { - SkADrawable* draw = fDrawList[index]; - draw->initialize(); // allow matrices to reset themselves - SkASSERT(draw->isDrawable()); - validate(); - result |= draw->draw(maker); - } - } - validate(); - return result; -} - -int SkDisplayList::findGroup(SkADrawable* match, SkTDDrawableArray** list, - SkGroup** parent, SkGroup** found, SkTDDrawableArray**grandList) { - *parent = nullptr; - *list = &fDrawList; - *grandList = &fDrawList; - return SearchForMatch(match, list, parent, found, grandList); -} - -void SkDisplayList::hardReset() { - fDrawList.reset(); - fActiveList.reset(); -} - -bool SkDisplayList::onIRect(const SkIRect& r) { - fBounds = r; - return fDrawBounds; -} - -int SkDisplayList::SearchForMatch(SkADrawable* match, SkTDDrawableArray** list, - SkGroup** parent, SkGroup** found, SkTDDrawableArray**grandList) { - *found = nullptr; - for (int index = 0; index < (*list)->count(); index++) { - SkADrawable* draw = (**list)[index]; - if (draw == match) - return index; - if (draw->isApply()) { - SkApply* apply = (SkApply*) draw; - if (apply->scope == match) - return index; - if (apply->scope->isGroup() && SearchGroupForMatch(apply->scope, match, list, parent, found, grandList, index)) - return index; - if (apply->mode == SkApply::kMode_create) { - for (SkADrawable** ptr = apply->fScopes.begin(); ptr < apply->fScopes.end(); ptr++) { - SkADrawable* scope = *ptr; - if (scope == match) - return index; - //perhaps should call SearchGroupForMatch here as well (on scope) - } - } - } - if (draw->isGroup() && SearchGroupForMatch(draw, match, list, parent, found, grandList, index)) - return index; - - } - return -1; -} - -bool SkDisplayList::SearchGroupForMatch(SkADrawable* draw, SkADrawable* match, SkTDDrawableArray** list, - SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList, int &index) { - SkGroup* group = (SkGroup*) draw; - if (group->getOriginal() == match) - return true; - SkTDDrawableArray* saveList = *list; - int groupIndex = group->findGroup(match, list, parent, found, grandList); - if (groupIndex >= 0) { - *found = group; - index = groupIndex; - return true; - } - *list = saveList; - return false; - } - -void SkDisplayList::reset() { - for (int index = 0; index < fDrawList.count(); index++) { - SkADrawable* draw = fDrawList[index]; - if (draw->isApply() == false) - continue; - SkApply* apply = (SkApply*) draw; - apply->reset(); - } -} - -void SkDisplayList::remove(SkActive* active) { - int index = fActiveList.find(active); - SkASSERT(index >= 0); - fActiveList.remove(index); // !!! could use shuffle instead - SkASSERT(fActiveList.find(active) < 0); -} - -#ifdef SK_DUMP_ENABLED -int SkDisplayList::fDumpIndex; -int SkDisplayList::fIndent; - -void SkDisplayList::dump(SkAnimateMaker* maker) { - fIndent = 0; - dumpInner(maker); -} - -void SkDisplayList::dumpInner(SkAnimateMaker* maker) { - for (int index = 0; index < fDrawList.count(); index++) { - fDumpIndex = index; - fDrawList[fDumpIndex]->dump(maker); - } -} - -#endif - -#ifdef SK_DEBUG -void SkDisplayList::validate() { - for (int index = 0; index < fDrawList.count(); index++) { - SkADrawable* draw = fDrawList[index]; - draw->validate(); - } -} -#endif diff --git a/gfx/skia/skia/src/animator/SkDisplayList.h b/gfx/skia/skia/src/animator/SkDisplayList.h deleted file mode 100644 index 2beba3e1df4a..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayList.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkDisplayList_DEFINED -#define SkDisplayList_DEFINED - -#include "SkOperand.h" -#include "SkIntArray.h" -#include "SkRect.h" -#include "SkRefCnt.h" - -class SkAnimateMaker; -class SkActive; -class SkApply; -class SkADrawable; -class SkGroup; - -class SkDisplayList : public SkRefCnt { -public: - SkDisplayList(); - virtual ~SkDisplayList(); - void append(SkActive* ); - void clear() { fDrawList.reset(); } - int count() { return fDrawList.count(); } - bool draw(SkAnimateMaker& , SkMSec time); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* maker); - void dumpInner(SkAnimateMaker* maker); - static int fIndent; - static int fDumpIndex; -#endif - int findGroup(SkADrawable* match, SkTDDrawableArray** list, - SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList); - SkADrawable* get(int index) { return fDrawList[index]; } - SkMSec getTime() { return fInTime; } - SkTDDrawableArray* getDrawList() { return &fDrawList; } - void hardReset(); - virtual bool onIRect(const SkIRect& r); - void reset(); - void remove(SkActive* ); -#ifdef SK_DEBUG - void validate(); -#else - void validate() {} -#endif - static int SearchForMatch(SkADrawable* match, SkTDDrawableArray** list, - SkGroup** parent, SkGroup** found, SkTDDrawableArray**grandList); - static bool SearchGroupForMatch(SkADrawable* draw, SkADrawable* match, - SkTDDrawableArray** list, SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList, - int &index); -public: - SkIRect fBounds; - SkIRect fInvalBounds; - bool fDrawBounds; - bool fHasUnion; - bool fUnionBounds; -private: - SkTDDrawableArray fDrawList; - SkTDActiveArray fActiveList; - SkMSec fInTime; - friend class SkEvents; -}; - -#endif // SkDisplayList_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayMath.cpp b/gfx/skia/skia/src/animator/SkDisplayMath.cpp deleted file mode 100644 index f52cf19371c6..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayMath.cpp +++ /dev/null @@ -1,229 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayMath.h" - -enum SkDisplayMath_Properties { - SK_PROPERTY(E), - SK_PROPERTY(LN10), - SK_PROPERTY(LN2), - SK_PROPERTY(LOG10E), - SK_PROPERTY(LOG2E), - SK_PROPERTY(PI), - SK_PROPERTY(SQRT1_2), - SK_PROPERTY(SQRT2) -}; - -const SkScalar SkDisplayMath::gConstants[] = { - 2.718281828f, // E - 2.302585093f, // LN10 - 0.693147181f, // LN2 - 0.434294482f, // LOG10E - 1.442695041f, // LOG2E - 3.141592654f, // PI - 0.707106781f, // SQRT1_2 - 1.414213562f // SQRT2 -}; - -enum SkDisplayMath_Functions { - SK_FUNCTION(abs), - SK_FUNCTION(acos), - SK_FUNCTION(asin), - SK_FUNCTION(atan), - SK_FUNCTION(atan2), - SK_FUNCTION(ceil), - SK_FUNCTION(cos), - SK_FUNCTION(exp), - SK_FUNCTION(floor), - SK_FUNCTION(log), - SK_FUNCTION(max), - SK_FUNCTION(min), - SK_FUNCTION(pow), - SK_FUNCTION(random), - SK_FUNCTION(round), - SK_FUNCTION(sin), - SK_FUNCTION(sqrt), - SK_FUNCTION(tan) -}; - -const SkFunctionParamType SkDisplayMath::fFunctionParameters[] = { - (SkFunctionParamType) SkType_Float, // abs - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // acos - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // asin - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // atan - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // atan2 - (SkFunctionParamType) SkType_Float, - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // ceil - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // cos - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // exp - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // floor - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // log - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Array, // max - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Array, // min - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // pow - (SkFunctionParamType) SkType_Float, - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // random - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // round - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // sin - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // sqrt - (SkFunctionParamType) 0, - (SkFunctionParamType) SkType_Float, // tan - (SkFunctionParamType) 0 -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayMath::fInfo[] = { - SK_MEMBER_PROPERTY(E, Float), - SK_MEMBER_PROPERTY(LN10, Float), - SK_MEMBER_PROPERTY(LN2, Float), - SK_MEMBER_PROPERTY(LOG10E, Float), - SK_MEMBER_PROPERTY(LOG2E, Float), - SK_MEMBER_PROPERTY(PI, Float), - SK_MEMBER_PROPERTY(SQRT1_2, Float), - SK_MEMBER_PROPERTY(SQRT2, Float), - SK_MEMBER_FUNCTION(abs, Float), - SK_MEMBER_FUNCTION(acos, Float), - SK_MEMBER_FUNCTION(asin, Float), - SK_MEMBER_FUNCTION(atan, Float), - SK_MEMBER_FUNCTION(atan2, Float), - SK_MEMBER_FUNCTION(ceil, Float), - SK_MEMBER_FUNCTION(cos, Float), - SK_MEMBER_FUNCTION(exp, Float), - SK_MEMBER_FUNCTION(floor, Float), - SK_MEMBER_FUNCTION(log, Float), - SK_MEMBER_FUNCTION(max, Float), - SK_MEMBER_FUNCTION(min, Float), - SK_MEMBER_FUNCTION(pow, Float), - SK_MEMBER_FUNCTION(random, Float), - SK_MEMBER_FUNCTION(round, Float), - SK_MEMBER_FUNCTION(sin, Float), - SK_MEMBER_FUNCTION(sqrt, Float), - SK_MEMBER_FUNCTION(tan, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayMath); - -void SkDisplayMath::executeFunction(SkDisplayable* target, int index, - SkTDArray& parameters, SkDisplayTypes type, - SkScriptValue* scriptValue) { - if (scriptValue == nullptr) - return; - SkASSERT(target == this); - SkScriptValue* array = parameters.begin(); - SkScriptValue* end = parameters.end(); - SkScalar input = parameters[0].fOperand.fScalar; - SkScalar scalarResult; - switch (index) { - case SK_FUNCTION(abs): - scalarResult = SkScalarAbs(input); - break; - case SK_FUNCTION(acos): - scalarResult = SkScalarACos(input); - break; - case SK_FUNCTION(asin): - scalarResult = SkScalarASin(input); - break; - case SK_FUNCTION(atan): - scalarResult = SkScalarATan2(input, SK_Scalar1); - break; - case SK_FUNCTION(atan2): - scalarResult = SkScalarATan2(input, parameters[1].fOperand.fScalar); - break; - case SK_FUNCTION(ceil): - scalarResult = SkScalarCeilToScalar(input); - break; - case SK_FUNCTION(cos): - scalarResult = SkScalarCos(input); - break; - case SK_FUNCTION(exp): - scalarResult = SkScalarExp(input); - break; - case SK_FUNCTION(floor): - scalarResult = SkScalarFloorToScalar(input); - break; - case SK_FUNCTION(log): - scalarResult = SkScalarLog(input); - break; - case SK_FUNCTION(max): - scalarResult = -SK_ScalarMax; - while (array < end) { - scalarResult = SkMaxScalar(scalarResult, array->fOperand.fScalar); - array++; - } - break; - case SK_FUNCTION(min): - scalarResult = SK_ScalarMax; - while (array < end) { - scalarResult = SkMinScalar(scalarResult, array->fOperand.fScalar); - array++; - } - break; - case SK_FUNCTION(pow): - // not the greatest -- but use x^y = e^(y * ln(x)) - scalarResult = SkScalarLog(input); - scalarResult = SkScalarMul(parameters[1].fOperand.fScalar, scalarResult); - scalarResult = SkScalarExp(scalarResult); - break; - case SK_FUNCTION(random): - scalarResult = fRandom.nextUScalar1(); - break; - case SK_FUNCTION(round): - scalarResult = SkScalarRoundToScalar(input); - break; - case SK_FUNCTION(sin): - scalarResult = SkScalarSin(input); - break; - case SK_FUNCTION(sqrt): { - SkASSERT(parameters.count() == 1); - SkASSERT(type == SkType_Float); - scalarResult = SkScalarSqrt(input); - } break; - case SK_FUNCTION(tan): - scalarResult = SkScalarTan(input); - break; - default: - SkASSERT(0); - scalarResult = SK_ScalarNaN; - } - scriptValue->fOperand.fScalar = scalarResult; - scriptValue->fType = SkType_Float; -} - -const SkFunctionParamType* SkDisplayMath::getFunctionsParameters() { - return fFunctionParameters; -} - -bool SkDisplayMath::getProperty(int index, SkScriptValue* value) const { - if ((unsigned)index < SK_ARRAY_COUNT(gConstants)) { - value->fOperand.fScalar = gConstants[index]; - value->fType = SkType_Float; - return true; - } - SkASSERT(0); - return false; -} diff --git a/gfx/skia/skia/src/animator/SkDisplayMath.h b/gfx/skia/skia/src/animator/SkDisplayMath.h deleted file mode 100644 index 0311a7c1411e..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayMath.h +++ /dev/null @@ -1,31 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayMath_DEFINED -#define SkDisplayMath_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" -#include "SkRandom.h" - -class SkDisplayMath : public SkDisplayable { - DECLARE_DISPLAY_MEMBER_INFO(Math); - void executeFunction(SkDisplayable* , int index, - SkTDArray& parameters, SkDisplayTypes type, - SkScriptValue* ) override; - const SkFunctionParamType* getFunctionsParameters() override; - bool getProperty(int index, SkScriptValue* value) const override; -private: - mutable SkRandom fRandom; - static const SkScalar gConstants[]; - static const SkFunctionParamType fFunctionParameters[]; - -}; - -#endif // SkDisplayMath_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayMovie.cpp b/gfx/skia/skia/src/animator/SkDisplayMovie.cpp deleted file mode 100644 index 797d853be684..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayMovie.cpp +++ /dev/null @@ -1,128 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayMovie.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkPaint.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayMovie::fInfo[] = { - SK_MEMBER(src, String) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayMovie); - -SkDisplayMovie::SkDisplayMovie() : fDecodedSuccessfully(false), fLoaded(false), fMovieBuilt(false) { - fMovie.fMaker->fInMovie = true; -} - -SkDisplayMovie::~SkDisplayMovie() { -} - -void SkDisplayMovie::buildMovie() { - if (fMovieBuilt) - return; - SkAnimateMaker* movieMaker = fMovie.fMaker; - SkAnimateMaker* parentMaker = movieMaker->fParentMaker; - if (src.size() == 0 || parentMaker == nullptr) - return; - movieMaker->fPrefix.set(parentMaker->fPrefix); - fDecodedSuccessfully = fMovie.fMaker->decodeURI(src.c_str()); - if (fDecodedSuccessfully == false) { - - if (movieMaker->getErrorCode() != SkXMLParserError::kNoError || movieMaker->getNativeCode() != -1) { - movieMaker->setInnerError(parentMaker, src); - parentMaker->setErrorCode(SkDisplayXMLParserError::kInMovie); - } else { - parentMaker->setErrorNoun(src); - parentMaker->setErrorCode(SkDisplayXMLParserError::kMovieNameUnknownOrMissing); - } - } - fMovieBuilt = true; -} - -SkDisplayable* SkDisplayMovie::deepCopy(SkAnimateMaker* maker) { - SkDisplayMovie* copy = (SkDisplayMovie*) INHERITED::deepCopy(maker); - copy->fMovie.fMaker->fParentMaker = fMovie.fMaker->fParentMaker; - copy->fMovie.fMaker->fHostEventSinkID = fMovie.fMaker->fHostEventSinkID; - copy->fMovieBuilt = false; - *fMovie.fMaker->fParentMaker->fMovies.append() = copy; - return copy; -} - -void SkDisplayMovie::dirty() { - buildMovie(); -} - -bool SkDisplayMovie::doEvent(SkDisplayEvent::Kind kind, SkEventState* state) { - if (fLoaded == false) - return false; - fMovie.fMaker->fEnableTime = fMovie.fMaker->fParentMaker->fEnableTime; - return fMovie.fMaker->fEvents.doEvent(*fMovie.fMaker, kind, state); -} - -bool SkDisplayMovie::draw(SkAnimateMaker& maker) { - if (fDecodedSuccessfully == false) - return false; - if (fLoaded == false) - enable(maker); - maker.fCanvas->save(); - SkPaint local = SkPaint(*maker.fPaint); - bool result = fMovie.draw(maker.fCanvas, &local, - maker.fDisplayList.getTime()) != SkAnimator::kNotDifferent; - maker.fDisplayList.fInvalBounds.join(fMovie.fMaker->fDisplayList.fInvalBounds); - maker.fCanvas->restore(); - return result; -} - -#ifdef SK_DUMP_ENABLED -void SkDisplayMovie::dump(SkAnimateMaker* maker) { - dumpBase(maker); - SkDebugf("src=\"%s\"/>\n", src.c_str()); - SkAnimateMaker* movieMaker = fMovie.fMaker; - SkDisplayList::fIndent += 4; - movieMaker->fDisplayList.dumpInner(movieMaker); - SkDisplayList::fIndent -= 4; - dumpEnd(maker); -} - -void SkDisplayMovie::dumpEvents() { - fMovie.fMaker->fEvents.dump(*fMovie.fMaker); -} -#endif - -bool SkDisplayMovie::enable(SkAnimateMaker&) { - if (fDecodedSuccessfully == false) - return false; - SkAnimateMaker* movieMaker = fMovie.fMaker; - movieMaker->fEvents.doEvent(*movieMaker, SkDisplayEvent::kOnload, nullptr); - movieMaker->fEvents.removeEvent(SkDisplayEvent::kOnload, nullptr); - fLoaded = true; - movieMaker->fLoaded = true; - return false; -} - -bool SkDisplayMovie::hasEnable() const { - return true; -} - -void SkDisplayMovie::onEndElement(SkAnimateMaker& maker) { -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - fMovie.fMaker->fDebugTimeBase = maker.fDebugTimeBase; -#endif - fMovie.fMaker->fPrefix.set(maker.fPrefix); - fMovie.fMaker->fHostEventSinkID = maker.fHostEventSinkID; - fMovie.fMaker->fParentMaker = &maker; - buildMovie(); - *maker.fMovies.append() = this; -} diff --git a/gfx/skia/skia/src/animator/SkDisplayMovie.h b/gfx/skia/skia/src/animator/SkDisplayMovie.h deleted file mode 100644 index 76e2d9ccc7c8..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayMovie.h +++ /dev/null @@ -1,51 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayMovie_DEFINED -#define SkDisplayMovie_DEFINED - -#include "SkAnimator.h" -#include "SkADrawable.h" -#include "SkMemberInfo.h" - -struct SkEventState; - -class SkDisplayMovie : public SkADrawable { - DECLARE_DISPLAY_MEMBER_INFO(Movie); - SkDisplayMovie(); - virtual ~SkDisplayMovie(); - void buildMovie(); - SkDisplayable* deepCopy(SkAnimateMaker* ) override; - void dirty() override; - bool doEvent(const SkEvent& evt) { - return fLoaded && fMovie.doEvent(evt); - } - bool doEvent(SkDisplayEvent::Kind , SkEventState* state ) override; - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; - void dumpEvents() override; -#endif - bool enable(SkAnimateMaker& ) override; - const SkAnimator* getAnimator() const { return &fMovie; } - bool hasEnable() const override; - void onEndElement(SkAnimateMaker& ) override; -protected: - SkString src; - SkAnimator fMovie; - SkBool8 fDecodedSuccessfully; - SkBool8 fLoaded; - SkBool8 fMovieBuilt; - friend class SkAnimateMaker; - friend class SkPost; -private: - typedef SkADrawable INHERITED; -}; - -#endif // SkDisplayMovie_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayNumber.cpp b/gfx/skia/skia/src/animator/SkDisplayNumber.cpp deleted file mode 100644 index 82b658f7bed0..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayNumber.cpp +++ /dev/null @@ -1,70 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayNumber.h" - -enum SkDisplayNumber_Properties { - SK_PROPERTY(MAX_VALUE), - SK_PROPERTY(MIN_VALUE), - SK_PROPERTY(NEGATIVE_INFINITY), - SK_PROPERTY(NaN), - SK_PROPERTY(POSITIVE_INFINITY) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayNumber::fInfo[] = { - SK_MEMBER_PROPERTY(MAX_VALUE, Float), - SK_MEMBER_PROPERTY(MIN_VALUE, Float), - SK_MEMBER_PROPERTY(NEGATIVE_INFINITY, Float), - SK_MEMBER_PROPERTY(NaN, Float), - SK_MEMBER_PROPERTY(POSITIVE_INFINITY, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayNumber); - -#if defined _WIN32 -#pragma warning ( push ) -// we are intentionally causing an overflow here -// (warning C4756: overflow in constant arithmetic) -#pragma warning ( disable : 4756 ) -#endif - -bool SkDisplayNumber::getProperty(int index, SkScriptValue* value) const { - SkScalar constant; - switch (index) { - case SK_PROPERTY(MAX_VALUE): - constant = SK_ScalarMax; - break; - case SK_PROPERTY(MIN_VALUE): - constant = SK_ScalarMin; - break; - case SK_PROPERTY(NEGATIVE_INFINITY): - constant = -SK_ScalarInfinity; - break; - case SK_PROPERTY(NaN): - constant = SK_ScalarNaN; - break; - case SK_PROPERTY(POSITIVE_INFINITY): - constant = SK_ScalarInfinity; - break; - default: - SkASSERT(0); - return false; - } - value->fOperand.fScalar = constant; - value->fType = SkType_Float; - return true; -} - -#if defined _WIN32 -#pragma warning ( pop ) -#endif diff --git a/gfx/skia/skia/src/animator/SkDisplayNumber.h b/gfx/skia/skia/src/animator/SkDisplayNumber.h deleted file mode 100644 index b92c31143932..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayNumber.h +++ /dev/null @@ -1,22 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayNumber_DEFINED -#define SkDisplayNumber_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" - -class SkDisplayNumber : public SkDisplayable { - DECLARE_DISPLAY_MEMBER_INFO(Number); - bool getProperty(int index, SkScriptValue* value) const override; -private: -}; - -#endif // SkDisplayNumber_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayPost.cpp b/gfx/skia/skia/src/animator/SkDisplayPost.cpp deleted file mode 100644 index a30fd4442f0a..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayPost.cpp +++ /dev/null @@ -1,298 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayPost.h" -#include "SkAnimateMaker.h" -#include "SkAnimator.h" -#include "SkDisplayMovie.h" -#include "SkPostParts.h" -#include "SkScript.h" -#ifdef SK_DEBUG -#include "SkDump.h" -#include "SkTime.h" -#endif - -enum SkPost_Properties { - SK_PROPERTY(target), - SK_PROPERTY(type) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkPost::fInfo[] = { - SK_MEMBER(delay, MSec), -// SK_MEMBER(initialized, Boolean), - SK_MEMBER(mode, EventMode), - SK_MEMBER(sink, String), - SK_MEMBER_PROPERTY(target, String), - SK_MEMBER_PROPERTY(type, String) -}; - -#endif - -DEFINE_GET_MEMBER(SkPost); - -SkPost::SkPost() : delay(0), /*initialized(SkBool(-1)), */ mode(kImmediate), fMaker(nullptr), - fSinkID(0), fTargetMaker(nullptr), fChildHasID(false), fDirty(false) { -} - -SkPost::~SkPost() { - for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) - delete *part; -} - -bool SkPost::addChild(SkAnimateMaker& , SkDisplayable* child) { - SkASSERT(child && child->isDataInput()); - SkDataInput* part = (SkDataInput*) child; - *fParts.append() = part; - return true; -} - -bool SkPost::childrenNeedDisposing() const { - return false; -} - -void SkPost::dirty() { - fDirty = true; -} - -#ifdef SK_DUMP_ENABLED -void SkPost::dump(SkAnimateMaker* maker) { - dumpBase(maker); - SkString* eventType = new SkString(); - fEvent.getType(eventType); - if (eventType->equals("user")) { - const char* target = fEvent.findString("id"); - SkDebugf("target=\"%s\" ", target); - } - else - SkDebugf("type=\"%s\" ", eventType->c_str()); - delete eventType; - - if (delay > 0) { - SkDebugf("delay=\"%g\" ", delay * 0.001); - } -// if (initialized == false) -// SkDebugf("(uninitialized) "); - SkString string; - SkDump::GetEnumString(SkType_EventMode, mode, &string); - if (!string.equals("immediate")) - SkDebugf("mode=\"%s\" ", string.c_str()); - // !!! could enhance this to search through make hierarchy to show name of sink - if (sink.size() > 0) { - SkDebugf("sink=\"%s\" sinkID=\"%d\" ", sink.c_str(), fSinkID); - } else if (fSinkID != maker->getAnimator()->getSinkID() && fSinkID != 0) { - SkDebugf("sinkID=\"%d\" ", fSinkID); - } - const SkMetaData& meta = fEvent.getMetaData(); - SkMetaData::Iter iter(meta); - SkMetaData::Type type; - int number; - const char* name; - bool closedYet = false; - SkDisplayList::fIndent += 4; - //this seems to work, but kinda hacky - //for some reason the last part is id, which i don't want - //and the parts seem to be in the reverse order from the one in which we find the - //data itself - //SkDataInput** ptr = fParts.end(); - //SkDataInput* data; - //const char* ID; - while ((name = iter.next(&type, &number)) != nullptr) { - //ptr--; - if (strcmp(name, "id") == 0) - continue; - if (closedYet == false) { - SkDebugf(">\n"); - closedYet = true; - } - //data = *ptr; - //if (data->id) - // ID = data->id; - //else - // ID = ""; - SkDebugf("%*s\n"); - //ptr++; -/* perhaps this should only be done in the case of a pointer? - SkDisplayable* displayable; - if (maker->find(name, &displayable)) - displayable->dump(maker); - else - SkDebugf("\n");*/ - } - SkDisplayList::fIndent -= 4; - if (closedYet) - dumpEnd(maker); - else - SkDebugf("/>\n"); - -} -#endif - -bool SkPost::enable(SkAnimateMaker& maker ) { - if (maker.hasError()) - return true; - if (fDirty) { - if (sink.size() > 0) - findSinkID(); - if (fChildHasID) { - SkString preserveID(fEvent.findString("id")); - fEvent.getMetaData().reset(); - if (preserveID.size() > 0) - fEvent.setString("id", preserveID); - for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) { - if ((*part)->add()) - maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingDataToPost); - } - } - fDirty = false; - } -#ifdef SK_DUMP_ENABLED - if (maker.fDumpPosts) { - SkDebugf("post enable: "); - dump(&maker); - } -#if defined SK_DEBUG_ANIMATION_TIMING - SkString debugOut; - SkMSec time = maker.getAppTime(); - debugOut.appendS32(time - maker.fDebugTimeBase); - debugOut.append(" post id="); - debugOut.append(_id); - debugOut.append(" enable="); - debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase); - debugOut.append(" delay="); - debugOut.appendS32(delay); -#endif -#endif -// SkMSec adjustedDelay = maker.adjustDelay(maker.fEnableTime, delay); - SkMSec futureTime = maker.fEnableTime + delay; - fEvent.setFast32(futureTime); -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - debugOut.append(" future="); - debugOut.appendS32(futureTime - maker.fDebugTimeBase); - SkDebugf("%s\n", debugOut.c_str()); -#endif - SkEventSinkID targetID = fSinkID; - bool isAnimatorEvent = true; - SkAnimator* anim = maker.getAnimator(); - if (targetID == 0) { - isAnimatorEvent = fEvent.findString("id") != nullptr; - if (isAnimatorEvent) - targetID = anim->getSinkID(); - else if (maker.fHostEventSinkID) - targetID = maker.fHostEventSinkID; - else - return true; - } else - anim = fTargetMaker->getAnimator(); - if (delay == 0) { - if (isAnimatorEvent && mode == kImmediate) - fTargetMaker->doEvent(fEvent); - else - anim->onEventPost(new SkEvent(fEvent), targetID); - } else - anim->onEventPostTime(new SkEvent(fEvent), targetID, futureTime); - return true; -} - -void SkPost::findSinkID() { - // get the next delimiter '.' if any - fTargetMaker = fMaker; - const char* ch = sink.c_str(); - do { - const char* end = strchr(ch, '.'); - size_t len = end ? (size_t) (end - ch) : strlen(ch); - SkDisplayable* displayable = nullptr; - if (SK_LITERAL_STR_EQUAL("parent", ch, len)) { - if (fTargetMaker->fParentMaker) - fTargetMaker = fTargetMaker->fParentMaker; - else { - fTargetMaker->setErrorCode(SkDisplayXMLParserError::kNoParentAvailable); - return; - } - } else { - fTargetMaker->find(ch, len, &displayable); - if (displayable == nullptr || displayable->getType() != SkType_Movie) { - fTargetMaker->setErrorCode(SkDisplayXMLParserError::kExpectedMovie); - return; - } - SkDisplayMovie* movie = (SkDisplayMovie*) displayable; - fTargetMaker = movie->fMovie.fMaker; - } - if (end == nullptr) - break; - ch = ++end; - } while (true); - SkAnimator* anim = fTargetMaker->getAnimator(); - fSinkID = anim->getSinkID(); -} - -bool SkPost::hasEnable() const { - return true; -} - -void SkPost::onEndElement(SkAnimateMaker& maker) { - fTargetMaker = fMaker = &maker; - if (fChildHasID == false) { - for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) - delete *part; - fParts.reset(); - } -} - -void SkPost::setChildHasID() { - fChildHasID = true; -} - -bool SkPost::setProperty(int index, SkScriptValue& value) { - SkASSERT(value.fType == SkType_String); - SkString* string = value.fOperand.fString; - switch(index) { - case SK_PROPERTY(target): { - fEvent.setType("user"); - fEvent.setString("id", *string); - mode = kImmediate; - } break; - case SK_PROPERTY(type): - fEvent.setType(*string); - break; - default: - SkASSERT(0); - return false; - } - return true; -} diff --git a/gfx/skia/skia/src/animator/SkDisplayPost.h b/gfx/skia/skia/src/animator/SkDisplayPost.h deleted file mode 100644 index 80fdcfcdd830..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayPost.h +++ /dev/null @@ -1,59 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayPost_DEFINED -#define SkDisplayPost_DEFINED - -#include "SkDisplayable.h" -#include "SkEvent.h" -#include "SkEventSink.h" -#include "SkMemberInfo.h" -#include "SkIntArray.h" - -class SkDataInput; -class SkAnimateMaker; - -class SkPost : public SkDisplayable { - DECLARE_MEMBER_INFO(Post); - enum Mode { - kDeferred, - kImmediate - }; - SkPost(); - virtual ~SkPost(); - bool addChild(SkAnimateMaker& , SkDisplayable* child) override; - bool childrenNeedDisposing() const override; - void dirty() override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - bool enable(SkAnimateMaker& ) override; - bool hasEnable() const override; - void onEndElement(SkAnimateMaker& ) override; - void setChildHasID() override; - bool setProperty(int index, SkScriptValue& ) override; -protected: - SkMSec delay; - SkString sink; -// SkBool initialized; - Mode mode; - SkEvent fEvent; - SkAnimateMaker* fMaker; - SkTDDataArray fParts; - SkEventSinkID fSinkID; - SkAnimateMaker* fTargetMaker; - SkBool8 fChildHasID; - SkBool8 fDirty; -private: - void findSinkID(); - friend class SkDataInput; - typedef SkDisplayable INHERITED; -}; - -#endif //SkDisplayPost_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayRandom.cpp b/gfx/skia/skia/src/animator/SkDisplayRandom.cpp deleted file mode 100644 index 2efe8dc92cfb..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayRandom.cpp +++ /dev/null @@ -1,65 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayRandom.h" -#include "SkInterpolator.h" - -enum SkDisplayRandom_Properties { - SK_PROPERTY(random), - SK_PROPERTY(seed) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayRandom::fInfo[] = { - SK_MEMBER(blend, Float), - SK_MEMBER(max, Float), - SK_MEMBER(min, Float), - SK_MEMBER_DYNAMIC_PROPERTY(random, Float), - SK_MEMBER_PROPERTY(seed, Int) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayRandom); - -SkDisplayRandom::SkDisplayRandom() : blend(0), min(0), max(SK_Scalar1) { -} - -#ifdef SK_DUMP_ENABLED -void SkDisplayRandom::dump(SkAnimateMaker* maker) { - dumpBase(maker); - SkDebugf("min=\"%g\" ", SkScalarToFloat(min)); - SkDebugf("max=\"%g\" ", SkScalarToFloat(max)); - SkDebugf("blend=\"%g\" ", SkScalarToFloat(blend)); - SkDebugf("/>\n"); -} -#endif - -bool SkDisplayRandom::getProperty(int index, SkScriptValue* value) const { - switch(index) { - case SK_PROPERTY(random): { - SkScalar random = fRandom.nextUScalar1(); - SkScalar relativeT = SkUnitCubicInterp(random, SK_Scalar1 - blend, 0, 0, SK_Scalar1 - blend); - value->fOperand.fScalar = min + SkScalarMul(max - min, relativeT); - value->fType = SkType_Float; - return true; - } - default: - SkASSERT(0); - } - return false; -} - -bool SkDisplayRandom::setProperty(int index, SkScriptValue& value) { - SkASSERT(index == SK_PROPERTY(seed)); - SkASSERT(value.fType == SkType_Int); - fRandom.setSeed(value.fOperand.fS32); - return true; -} diff --git a/gfx/skia/skia/src/animator/SkDisplayRandom.h b/gfx/skia/skia/src/animator/SkDisplayRandom.h deleted file mode 100644 index 2999156268fc..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayRandom.h +++ /dev/null @@ -1,40 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayRandom_DEFINED -#define SkDisplayRandom_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" -#include "SkRandom.h" - -#ifdef min -#undef min -#endif - -#ifdef max -#undef max -#endif - -class SkDisplayRandom : public SkDisplayable { - DECLARE_DISPLAY_MEMBER_INFO(Random); - SkDisplayRandom(); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - bool getProperty(int index, SkScriptValue* value) const override; - bool setProperty(int index, SkScriptValue& ) override; -private: - SkScalar blend; - SkScalar min; - SkScalar max; - mutable SkRandom fRandom; -}; - -#endif // SkDisplayRandom_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayScreenplay.cpp b/gfx/skia/skia/src/animator/SkDisplayScreenplay.cpp deleted file mode 100644 index 2663b43149d3..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayScreenplay.cpp +++ /dev/null @@ -1,20 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayScreenplay.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayScreenplay::fInfo[] = { - SK_MEMBER(time, MSec) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayScreenplay); diff --git a/gfx/skia/skia/src/animator/SkDisplayScreenplay.h b/gfx/skia/skia/src/animator/SkDisplayScreenplay.h deleted file mode 100644 index 0265548ed1de..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayScreenplay.h +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayScreenplay_DEFINED -#define SkDisplayScreenplay_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" - -class SkDisplayScreenplay : public SkDisplayable { - DECLARE_DISPLAY_MEMBER_INFO(Screenplay); - SkMSec time; -}; - -#endif // SkDisplayScreenplay_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayType.cpp b/gfx/skia/skia/src/animator/SkDisplayType.cpp deleted file mode 100644 index 92d120eb9669..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayType.cpp +++ /dev/null @@ -1,761 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayType.h" -#include "SkAnimateMaker.h" -#include "SkAnimateSet.h" -#include "SkDisplayAdd.h" -#include "SkDisplayApply.h" -#include "SkDisplayBounds.h" -#include "SkDisplayEvent.h" -#include "SkDisplayInclude.h" -#ifdef SK_DEBUG -#include "SkDisplayList.h" -#endif -#include "SkDisplayMath.h" -#include "SkDisplayMovie.h" -#include "SkDisplayNumber.h" -#include "SkDisplayPost.h" -#include "SkDisplayRandom.h" -#include "SkDisplayTypes.h" -#include "SkDraw3D.h" -#include "SkDrawBitmap.h" -#include "SkDrawClip.h" -#include "SkDrawDash.h" -#include "SkDrawDiscrete.h" -#include "SkDrawEmboss.h" -#include "SkDrawFull.h" -#include "SkDrawGradient.h" -#include "SkDrawLine.h" -#include "SkDrawMatrix.h" -#include "SkDrawOval.h" -#include "SkDrawPaint.h" -#include "SkDrawPath.h" -#include "SkDrawPoint.h" -#include "SkDrawSaveLayer.h" -#include "SkDrawText.h" -#include "SkDrawTextBox.h" -#include "SkDrawTo.h" -#include "SkDump.h" -#include "SkExtras.h" -#include "SkHitClear.h" -#include "SkHitTest.h" -#include "SkMatrixParts.h" -#include "SkPathParts.h" -#include "SkPostParts.h" -#include "SkSnapshot.h" -#include "SkTextOnPath.h" -#include "SkTextToPath.h" -#include "SkTSearch.h" - -#define CASE_NEW(_class) \ - case SkType_##_class: result = new Sk##_class(); break -#define CASE_DRAW_NEW(_class) \ - case SkType_##_class: result = new SkDraw##_class(); break -#define CASE_DISPLAY_NEW(_class) \ - case SkType_##_class: result = new SkDisplay##_class(); break -#ifdef SK_DEBUG - #define CASE_DEBUG_RETURN_NIL(_class) \ - case SkType_##_class: return nullptr -#else - #define CASE_DEBUG_RETURN_NIL(_class) -#endif - - -SkDisplayTypes SkDisplayType::gNewTypes = kNumberOfTypes; - -SkDisplayable* SkDisplayType::CreateInstance(SkAnimateMaker* maker, SkDisplayTypes type) { - SkDisplayable* result = nullptr; - switch (type) { - // unknown - CASE_DISPLAY_NEW(Math); - CASE_DISPLAY_NEW(Number); - CASE_NEW(Add); - CASE_NEW(AddCircle); - // addgeom - CASE_DEBUG_RETURN_NIL(AddMode); - CASE_NEW(AddOval); - CASE_NEW(AddPath); - CASE_NEW(AddRect); - CASE_NEW(AddRoundRect); - CASE_DEBUG_RETURN_NIL(Align); - CASE_NEW(Animate); - // animatebase - CASE_NEW(Apply); - CASE_DEBUG_RETURN_NIL(ApplyMode); - CASE_DEBUG_RETURN_NIL(ApplyTransition); - CASE_DISPLAY_NEW(Array); - // argb - // base64 - // basebitmap - // baseclassinfo - CASE_DRAW_NEW(Bitmap); - // bitmapencoding - // bitmapformat - CASE_DRAW_NEW(BitmapShader); - CASE_DRAW_NEW(Blur); - CASE_DISPLAY_NEW(Boolean); - // boundable - CASE_DISPLAY_NEW(Bounds); - CASE_DEBUG_RETURN_NIL(Cap); - CASE_NEW(Clear); - CASE_DRAW_NEW(Clip); - CASE_NEW(Close); - CASE_DRAW_NEW(Color); - CASE_NEW(CubicTo); - CASE_NEW(Dash); - CASE_NEW(DataInput); - CASE_NEW(Discrete); - // displayable - // drawable - CASE_NEW(DrawTo); - CASE_NEW(Dump); - // dynamicstring - CASE_DRAW_NEW(Emboss); - CASE_DISPLAY_NEW(Event); - CASE_DEBUG_RETURN_NIL(EventCode); - CASE_DEBUG_RETURN_NIL(EventKind); - CASE_DEBUG_RETURN_NIL(EventMode); - // filltype - // filtertype - CASE_DISPLAY_NEW(Float); - CASE_NEW(FromPath); - CASE_DEBUG_RETURN_NIL(FromPathMode); - CASE_NEW(Full); - // gradient - CASE_NEW(Group); - CASE_NEW(HitClear); - CASE_NEW(HitTest); - CASE_NEW(ImageBaseBitmap); - CASE_NEW(Include); - CASE_NEW(Input); - CASE_DISPLAY_NEW(Int); - CASE_DEBUG_RETURN_NIL(Join); - CASE_NEW(Line); - CASE_NEW(LineTo); - CASE_NEW(DrawLinearGradient); - CASE_DRAW_NEW(MaskFilter); - CASE_DEBUG_RETURN_NIL(MaskFilterBlurStyle); - // maskfilterlight - CASE_DRAW_NEW(Matrix); - // memberfunction - // memberproperty - CASE_NEW(Move); - CASE_NEW(MoveTo); - CASE_DISPLAY_NEW(Movie); - // msec - CASE_NEW(Oval); - CASE_DRAW_NEW(Paint); - CASE_DRAW_NEW(Path); - // pathdirection - CASE_DRAW_NEW(PathEffect); - // point - CASE_NEW(DrawPoint); - CASE_NEW(PolyToPoly); - CASE_NEW(Polygon); - CASE_NEW(Polyline); - CASE_NEW(Post); - CASE_NEW(QuadTo); - CASE_NEW(RCubicTo); - CASE_NEW(RLineTo); - CASE_NEW(RMoveTo); - CASE_NEW(RQuadTo); - CASE_NEW(DrawRadialGradient); - CASE_DISPLAY_NEW(Random); - CASE_DRAW_NEW(Rect); - CASE_NEW(RectToRect); - CASE_NEW(Remove); - CASE_NEW(Replace); - CASE_NEW(Rotate); - CASE_NEW(RoundRect); - CASE_NEW(Save); - CASE_NEW(SaveLayer); - CASE_NEW(Scale); - // screenplay - CASE_NEW(Set); - CASE_DRAW_NEW(Shader); - CASE_NEW(Skew); - CASE_NEW(3D_Camera); - CASE_NEW(3D_Patch); - // 3dpoint - CASE_NEW(Snapshot); - CASE_DISPLAY_NEW(String); - // style - CASE_NEW(Text); - CASE_DRAW_NEW(TextBox); - // textboxalign - // textboxmode - CASE_NEW(TextOnPath); - CASE_NEW(TextToPath); - CASE_DEBUG_RETURN_NIL(TileMode); - CASE_NEW(Translate); - CASE_DRAW_NEW(Typeface); - CASE_DEBUG_RETURN_NIL(Xfermode); - default: - SkExtras** end = maker->fExtras.end(); - for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) { - if ((result = (*extraPtr)->createInstance(type)) != nullptr) - return result; - } - SkASSERT(0); - } - return result; -} - -#undef CASE_NEW -#undef CASE_DRAW_NEW -#undef CASE_DISPLAY_NEW - -#if SK_USE_CONDENSED_INFO == 0 - -#define CASE_GET_INFO(_class) case SkType_##_class: \ - info = Sk##_class::fInfo; infoCount = Sk##_class::fInfoCount; break -#define CASE_GET_DRAW_INFO(_class) case SkType_##_class: \ - info = SkDraw##_class::fInfo; infoCount = SkDraw##_class::fInfoCount; break -#define CASE_GET_DISPLAY_INFO(_class) case SkType_##_class: \ - info = SkDisplay##_class::fInfo; infoCount = SkDisplay##_class::fInfoCount; \ - break - -const SkMemberInfo* SkDisplayType::GetMembers(SkAnimateMaker* maker, - SkDisplayTypes type, int* infoCountPtr) { - const SkMemberInfo* info = nullptr; - int infoCount = 0; - switch (type) { - // unknown - CASE_GET_DISPLAY_INFO(Math); - CASE_GET_DISPLAY_INFO(Number); - CASE_GET_INFO(Add); - CASE_GET_INFO(AddCircle); - CASE_GET_INFO(AddGeom); - // addmode - CASE_GET_INFO(AddOval); - CASE_GET_INFO(AddPath); - CASE_GET_INFO(AddRect); - CASE_GET_INFO(AddRoundRect); - // align - CASE_GET_INFO(Animate); - CASE_GET_INFO(AnimateBase); - CASE_GET_INFO(Apply); - // applymode - // applytransition - CASE_GET_DISPLAY_INFO(Array); - // argb - // base64 - CASE_GET_INFO(BaseBitmap); - // baseclassinfo - CASE_GET_DRAW_INFO(Bitmap); - // bitmapencoding - // bitmapformat - CASE_GET_DRAW_INFO(BitmapShader); - CASE_GET_DRAW_INFO(Blur); - CASE_GET_DISPLAY_INFO(Boolean); - // boundable - CASE_GET_DISPLAY_INFO(Bounds); - // cap - // clear - CASE_GET_DRAW_INFO(Clip); - // close - CASE_GET_DRAW_INFO(Color); - CASE_GET_INFO(CubicTo); - CASE_GET_INFO(Dash); - CASE_GET_INFO(DataInput); - CASE_GET_INFO(Discrete); - // displayable - // drawable - CASE_GET_INFO(DrawTo); - CASE_GET_INFO(Dump); - // dynamicstring - CASE_GET_DRAW_INFO(Emboss); - CASE_GET_DISPLAY_INFO(Event); - // eventcode - // eventkind - // eventmode - // filltype - // filtertype - CASE_GET_DISPLAY_INFO(Float); - CASE_GET_INFO(FromPath); - // frompathmode - // full - CASE_GET_INFO(DrawGradient); - CASE_GET_INFO(Group); - CASE_GET_INFO(HitClear); - CASE_GET_INFO(HitTest); - CASE_GET_INFO(ImageBaseBitmap); - CASE_GET_INFO(Include); - CASE_GET_INFO(Input); - CASE_GET_DISPLAY_INFO(Int); - // join - CASE_GET_INFO(Line); - CASE_GET_INFO(LineTo); - CASE_GET_INFO(DrawLinearGradient); - // maskfilter - // maskfilterblurstyle - // maskfilterlight - CASE_GET_DRAW_INFO(Matrix); - // memberfunction - // memberproperty - CASE_GET_INFO(Move); - CASE_GET_INFO(MoveTo); - CASE_GET_DISPLAY_INFO(Movie); - // msec - CASE_GET_INFO(Oval); - CASE_GET_DRAW_INFO(Path); - CASE_GET_DRAW_INFO(Paint); - // pathdirection - // patheffect - case SkType_Point: info = Sk_Point::fInfo; infoCount = Sk_Point::fInfoCount; break; // no virtual flavor - CASE_GET_INFO(DrawPoint); // virtual flavor - CASE_GET_INFO(PolyToPoly); - CASE_GET_INFO(Polygon); - CASE_GET_INFO(Polyline); - CASE_GET_INFO(Post); - CASE_GET_INFO(QuadTo); - CASE_GET_INFO(RCubicTo); - CASE_GET_INFO(RLineTo); - CASE_GET_INFO(RMoveTo); - CASE_GET_INFO(RQuadTo); - CASE_GET_INFO(DrawRadialGradient); - CASE_GET_DISPLAY_INFO(Random); - CASE_GET_DRAW_INFO(Rect); - CASE_GET_INFO(RectToRect); - CASE_GET_INFO(Remove); - CASE_GET_INFO(Replace); - CASE_GET_INFO(Rotate); - CASE_GET_INFO(RoundRect); - CASE_GET_INFO(Save); - CASE_GET_INFO(SaveLayer); - CASE_GET_INFO(Scale); - // screenplay - CASE_GET_INFO(Set); - CASE_GET_DRAW_INFO(Shader); - CASE_GET_INFO(Skew); - CASE_GET_INFO(3D_Camera); - CASE_GET_INFO(3D_Patch); - CASE_GET_INFO(3D_Point); - CASE_GET_INFO(Snapshot); - CASE_GET_DISPLAY_INFO(String); - // style - CASE_GET_INFO(Text); - CASE_GET_DRAW_INFO(TextBox); - // textboxalign - // textboxmode - CASE_GET_INFO(TextOnPath); - CASE_GET_INFO(TextToPath); - // tilemode - CASE_GET_INFO(Translate); - CASE_GET_DRAW_INFO(Typeface); - // xfermode - // knumberoftypes - default: - if (maker) { - SkExtras** end = maker->fExtras.end(); - for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) { - if ((info = (*extraPtr)->getMembers(type, infoCountPtr)) != nullptr) - return info; - } - } - return nullptr; - } - if (infoCountPtr) - *infoCountPtr = infoCount; - return info; -} - -const SkMemberInfo* SkDisplayType::GetMember(SkAnimateMaker* maker, - SkDisplayTypes type, const char** matchPtr ) { - int infoCount = 0; // Initialize to remove a warning. - const SkMemberInfo* info = GetMembers(maker, type, &infoCount); - info = SkMemberInfo::Find(info, infoCount, matchPtr); -// SkASSERT(info); - return info; -} - -#undef CASE_GET_INFO -#undef CASE_GET_DRAW_INFO -#undef CASE_GET_DISPLAY_INFO - -#endif // SK_USE_CONDENSED_INFO == 0 - -#if defined SK_DEBUG || defined SK_BUILD_CONDENSED - #define DRAW_NAME(_name, _type) {_name, _type, true, false } - #define DISPLAY_NAME(_name, _type) {_name, _type, false, true } - #define INIT_BOOL_FIELDS , false, false -#else - #define DRAW_NAME(_name, _type) {_name, _type } - #define DISPLAY_NAME(_name, _type) {_name, _type } - #define INIT_BOOL_FIELDS -#endif - -const TypeNames gTypeNames[] = { - // unknown - { "Math", SkType_Math INIT_BOOL_FIELDS }, - { "Number", SkType_Number INIT_BOOL_FIELDS }, - { "add", SkType_Add INIT_BOOL_FIELDS }, - { "addCircle", SkType_AddCircle INIT_BOOL_FIELDS }, - // addgeom - // addmode - { "addOval", SkType_AddOval INIT_BOOL_FIELDS }, - { "addPath", SkType_AddPath INIT_BOOL_FIELDS }, - { "addRect", SkType_AddRect INIT_BOOL_FIELDS }, - { "addRoundRect", SkType_AddRoundRect INIT_BOOL_FIELDS }, - // align - { "animate", SkType_Animate INIT_BOOL_FIELDS }, - // animateBase - { "apply", SkType_Apply INIT_BOOL_FIELDS }, - // applymode - // applytransition - { "array", SkType_Array INIT_BOOL_FIELDS }, - // argb - // base64 - // basebitmap - // baseclassinfo - DRAW_NAME("bitmap", SkType_Bitmap), - // bitmapencoding - // bitmapformat - DRAW_NAME("bitmapShader", SkType_BitmapShader), - DRAW_NAME("blur", SkType_Blur), - { "boolean", SkType_Boolean INIT_BOOL_FIELDS }, - // boundable - DISPLAY_NAME("bounds", SkType_Bounds), - // cap - { "clear", SkType_Clear INIT_BOOL_FIELDS }, - DRAW_NAME("clip", SkType_Clip), - { "close", SkType_Close INIT_BOOL_FIELDS }, - DRAW_NAME("color", SkType_Color), - { "cubicTo", SkType_CubicTo INIT_BOOL_FIELDS }, - { "dash", SkType_Dash INIT_BOOL_FIELDS }, - { "data", SkType_DataInput INIT_BOOL_FIELDS }, - { "discrete", SkType_Discrete INIT_BOOL_FIELDS }, - // displayable - // drawable - { "drawTo", SkType_DrawTo INIT_BOOL_FIELDS }, - { "dump", SkType_Dump INIT_BOOL_FIELDS }, - // dynamicstring - DRAW_NAME("emboss", SkType_Emboss), - DISPLAY_NAME("event", SkType_Event), - // eventcode - // eventkind - // eventmode - // filltype - // filtertype - { "float", SkType_Float INIT_BOOL_FIELDS }, - { "fromPath", SkType_FromPath INIT_BOOL_FIELDS }, - // frompathmode - { "full", SkType_Full INIT_BOOL_FIELDS }, - // gradient - { "group", SkType_Group INIT_BOOL_FIELDS }, - { "hitClear", SkType_HitClear INIT_BOOL_FIELDS }, - { "hitTest", SkType_HitTest INIT_BOOL_FIELDS }, - { "image", SkType_ImageBaseBitmap INIT_BOOL_FIELDS }, - { "include", SkType_Include INIT_BOOL_FIELDS }, - { "input", SkType_Input INIT_BOOL_FIELDS }, - { "int", SkType_Int INIT_BOOL_FIELDS }, - // join - { "line", SkType_Line INIT_BOOL_FIELDS }, - { "lineTo", SkType_LineTo INIT_BOOL_FIELDS }, - { "linearGradient", SkType_DrawLinearGradient INIT_BOOL_FIELDS }, - { "maskFilter", SkType_MaskFilter INIT_BOOL_FIELDS }, - // maskfilterblurstyle - // maskfilterlight - DRAW_NAME("matrix", SkType_Matrix), - // memberfunction - // memberproperty - { "move", SkType_Move INIT_BOOL_FIELDS }, - { "moveTo", SkType_MoveTo INIT_BOOL_FIELDS }, - { "movie", SkType_Movie INIT_BOOL_FIELDS }, - // msec - { "oval", SkType_Oval INIT_BOOL_FIELDS }, - DRAW_NAME("paint", SkType_Paint), - DRAW_NAME("path", SkType_Path), - // pathdirection - { "pathEffect", SkType_PathEffect INIT_BOOL_FIELDS }, - // point - DRAW_NAME("point", SkType_DrawPoint), - { "polyToPoly", SkType_PolyToPoly INIT_BOOL_FIELDS }, - { "polygon", SkType_Polygon INIT_BOOL_FIELDS }, - { "polyline", SkType_Polyline INIT_BOOL_FIELDS }, - { "post", SkType_Post INIT_BOOL_FIELDS }, - { "quadTo", SkType_QuadTo INIT_BOOL_FIELDS }, - { "rCubicTo", SkType_RCubicTo INIT_BOOL_FIELDS }, - { "rLineTo", SkType_RLineTo INIT_BOOL_FIELDS }, - { "rMoveTo", SkType_RMoveTo INIT_BOOL_FIELDS }, - { "rQuadTo", SkType_RQuadTo INIT_BOOL_FIELDS }, - { "radialGradient", SkType_DrawRadialGradient INIT_BOOL_FIELDS }, - DISPLAY_NAME("random", SkType_Random), - { "rect", SkType_Rect INIT_BOOL_FIELDS }, - { "rectToRect", SkType_RectToRect INIT_BOOL_FIELDS }, - { "remove", SkType_Remove INIT_BOOL_FIELDS }, - { "replace", SkType_Replace INIT_BOOL_FIELDS }, - { "rotate", SkType_Rotate INIT_BOOL_FIELDS }, - { "roundRect", SkType_RoundRect INIT_BOOL_FIELDS }, - { "save", SkType_Save INIT_BOOL_FIELDS }, - { "saveLayer", SkType_SaveLayer INIT_BOOL_FIELDS }, - { "scale", SkType_Scale INIT_BOOL_FIELDS }, - // screenplay - { "set", SkType_Set INIT_BOOL_FIELDS }, - { "shader", SkType_Shader INIT_BOOL_FIELDS }, - { "skew", SkType_Skew INIT_BOOL_FIELDS }, - { "skia3d:camera", SkType_3D_Camera INIT_BOOL_FIELDS }, - { "skia3d:patch", SkType_3D_Patch INIT_BOOL_FIELDS }, - // point - { "snapshot", SkType_Snapshot INIT_BOOL_FIELDS }, - { "string", SkType_String INIT_BOOL_FIELDS }, - // style - { "text", SkType_Text INIT_BOOL_FIELDS }, - { "textBox", SkType_TextBox INIT_BOOL_FIELDS }, - // textboxalign - // textboxmode - { "textOnPath", SkType_TextOnPath INIT_BOOL_FIELDS }, - { "textToPath", SkType_TextToPath INIT_BOOL_FIELDS }, - // tilemode - { "translate", SkType_Translate INIT_BOOL_FIELDS }, - { "typeface", SkType_Typeface INIT_BOOL_FIELDS } - // xfermode - // knumberoftypes -}; - -const int kTypeNamesSize = SK_ARRAY_COUNT(gTypeNames); - -SkDisplayTypes SkDisplayType::Find(SkAnimateMaker* maker, const SkMemberInfo* match) { - for (int index = 0; index < kTypeNamesSize; index++) { - SkDisplayTypes type = gTypeNames[index].fType; - const SkMemberInfo* info = SkDisplayType::GetMembers(maker, type, nullptr); - if (info == match) - return type; - } - return (SkDisplayTypes) -1; -} - -// !!! optimize this by replacing function with a byte-sized lookup table -SkDisplayTypes SkDisplayType::GetParent(SkAnimateMaker* maker, SkDisplayTypes base) { - if (base == SkType_Group || base == SkType_Save || base == SkType_SaveLayer) //!!! cheat a little until we have a lookup table - return SkType_Displayable; - if (base == SkType_Set) - return SkType_Animate; // another cheat until we have a lookup table - const SkMemberInfo* info = GetMembers(maker, base, nullptr); // get info for this type - SkASSERT(info); - if (info->fType != SkType_BaseClassInfo) - return SkType_Unknown; // if no base, done - // !!! could change SK_MEMBER_INHERITED macro to take type, stuff in offset, so that - // this (and table builder) could know type without the following steps: - const SkMemberInfo* inherited = info->getInherited(); - SkDisplayTypes result = (SkDisplayTypes) (SkType_Unknown + 1); - for (; result <= SkType_Xfermode; result = (SkDisplayTypes) (result + 1)) { - const SkMemberInfo* match = GetMembers(maker, result, nullptr); - if (match == inherited) - break; - } - SkASSERT(result <= SkType_Xfermode); - return result; -} - -SkDisplayTypes SkDisplayType::GetType(SkAnimateMaker* maker, const char match[], size_t len ) { - int index = SkStrSearch(&gTypeNames[0].fName, kTypeNamesSize, match, - len, sizeof(gTypeNames[0])); - if (index >= 0 && index < kTypeNamesSize) - return gTypeNames[index].fType; - SkExtras** end = maker->fExtras.end(); - for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) { - SkDisplayTypes result = (*extraPtr)->getType(match, len); - if (result != SkType_Unknown) - return result; - } - return (SkDisplayTypes) -1; -} - -bool SkDisplayType::IsEnum(SkAnimateMaker* , SkDisplayTypes type) { - switch (type) { - case SkType_AddMode: - case SkType_Align: - case SkType_ApplyMode: - case SkType_ApplyTransition: - case SkType_BitmapEncoding: - case SkType_BitmapFormat: - case SkType_Boolean: - case SkType_Cap: - case SkType_EventCode: - case SkType_EventKind: - case SkType_EventMode: - case SkType_FillType: - case SkType_FilterType: - case SkType_FontStyle: - case SkType_FromPathMode: - case SkType_Join: - case SkType_MaskFilterBlurStyle: - case SkType_PathDirection: - case SkType_Style: - case SkType_TextBoxAlign: - case SkType_TextBoxMode: - case SkType_TileMode: - case SkType_Xfermode: - return true; - default: // to avoid warnings - break; - } - return false; -} - -bool SkDisplayType::IsDisplayable(SkAnimateMaker* , SkDisplayTypes type) { - switch (type) { - case SkType_Add: - case SkType_AddCircle: - case SkType_AddOval: - case SkType_AddPath: - case SkType_AddRect: - case SkType_AddRoundRect: - case SkType_Animate: - case SkType_AnimateBase: - case SkType_Apply: - case SkType_BaseBitmap: - case SkType_Bitmap: - case SkType_BitmapShader: - case SkType_Blur: - case SkType_Clear: - case SkType_Clip: - case SkType_Close: - case SkType_Color: - case SkType_CubicTo: - case SkType_Dash: - case SkType_DataInput: - case SkType_Discrete: - case SkType_Displayable: - case SkType_Drawable: - case SkType_DrawTo: - case SkType_Emboss: - case SkType_Event: - case SkType_FromPath: - case SkType_Full: - case SkType_Group: - case SkType_ImageBaseBitmap: - case SkType_Input: - case SkType_Line: - case SkType_LineTo: - case SkType_DrawLinearGradient: - case SkType_Matrix: - case SkType_Move: - case SkType_MoveTo: - case SkType_Movie: - case SkType_Oval: - case SkType_Paint: - case SkType_Path: - case SkType_PolyToPoly: - case SkType_Polygon: - case SkType_Polyline: - case SkType_Post: - case SkType_QuadTo: - case SkType_RCubicTo: - case SkType_RLineTo: - case SkType_RMoveTo: - case SkType_RQuadTo: - case SkType_DrawRadialGradient: - case SkType_Random: - case SkType_Rect: - case SkType_RectToRect: - case SkType_Remove: - case SkType_Replace: - case SkType_Rotate: - case SkType_RoundRect: - case SkType_Save: - case SkType_SaveLayer: - case SkType_Scale: - case SkType_Set: - case SkType_Shader: - case SkType_Skew: - case SkType_3D_Camera: - case SkType_3D_Patch: - case SkType_Snapshot: - case SkType_Text: - case SkType_TextBox: - case SkType_TextOnPath: - case SkType_TextToPath: - case SkType_Translate: - return true; - default: // to avoid warnings - break; - } - return false; -} - -bool SkDisplayType::IsStruct(SkAnimateMaker* , SkDisplayTypes type) { - switch (type) { - case SkType_Point: - case SkType_3D_Point: - return true; - default: // to avoid warnings - break; - } - return false; -} - - -SkDisplayTypes SkDisplayType::RegisterNewType() { - gNewTypes = (SkDisplayTypes) (gNewTypes + 1); - return gNewTypes; -} - - - -#ifdef SK_DEBUG -const char* SkDisplayType::GetName(SkAnimateMaker* maker, SkDisplayTypes type) { - for (int index = 0; index < kTypeNamesSize - 1; index++) { - if (gTypeNames[index].fType == type) - return gTypeNames[index].fName; - } - SkExtras** end = maker->fExtras.end(); - for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) { - const char* result = (*extraPtr)->getName(type); - if (result != nullptr) - return result; - } - return nullptr; -} -#endif - -#ifdef SK_SUPPORT_UNITTEST -void SkDisplayType::UnitTest() { - SkAnimator animator; - SkAnimateMaker* maker = animator.fMaker; - int index; - for (index = 0; index < kTypeNamesSize - 1; index++) { - SkASSERT(strcmp(gTypeNames[index].fName, gTypeNames[index + 1].fName) < 0); - SkASSERT(gTypeNames[index].fType < gTypeNames[index + 1].fType); - } - for (index = 0; index < kTypeNamesSize; index++) { - SkDisplayable* test = CreateInstance(maker, gTypeNames[index].fType); - if (test == nullptr) - continue; -#if defined _WIN32 && defined _INC_CRTDBG // only on windows, only if using "crtdbg.h" - // we know that crtdbg puts 0xfdfdfdfd at the end of the block - // look for unitialized memory, signature 0xcdcdcdcd prior to that - int* start = (int*) test; - while (*start != 0xfdfdfdfd) { - SkASSERT(*start != 0xcdcdcdcd); - start++; - } -#endif - delete test; - } - for (index = 0; index < kTypeNamesSize; index++) { - int infoCount; - const SkMemberInfo* info = GetMembers(maker, gTypeNames[index].fType, &infoCount); - if (info == nullptr) - continue; -#if SK_USE_CONDENSED_INFO == 0 - for (int inner = 0; inner < infoCount - 1; inner++) { - if (info[inner].fType == SkType_BaseClassInfo) - continue; - SkASSERT(strcmp(info[inner].fName, info[inner + 1].fName) < 0); - } -#endif - } -#if defined SK_DEBUG || defined SK_BUILD_CONDENSED - BuildCondensedInfo(maker); -#endif -} -#endif diff --git a/gfx/skia/skia/src/animator/SkDisplayType.h b/gfx/skia/skia/src/animator/SkDisplayType.h deleted file mode 100644 index 8ffcd75feaa2..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayType.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkDisplayType_DEFINED -#define SkDisplayType_DEFINED - -#include "SkMath.h" -#include "SkScalar.h" - -typedef int SkBool; - -#ifdef SK_DEBUG - #define SK_DUMP_ENABLED - #ifdef SK_BUILD_FOR_MAC - #define SK_FIND_LEAKS - #endif -#endif - -#define SK_LITERAL_STR_EQUAL(str, token, len) (sizeof(str) - 1 == len \ - && strncmp(str, token, sizeof(str) - 1) == 0) - -class SkAnimateMaker; -class SkDisplayable; -struct SkMemberInfo; - -enum SkDisplayTypes { - SkType_Unknown, - SkType_Math, // for ecmascript compatible Math functions and constants - SkType_Number, // for for ecmascript compatible Number functions and constants - SkType_Add, - SkType_AddCircle, - SkType_AddGeom, - SkType_AddMode, - SkType_AddOval, - SkType_AddPath, - SkType_AddRect, // path part - SkType_AddRoundRect, - SkType_Align, - SkType_Animate, - SkType_AnimateBase, // base type for animate, set - SkType_Apply, - SkType_ApplyMode, - SkType_ApplyTransition, - SkType_Array, - SkType_ARGB, - SkType_Base64, - SkType_BaseBitmap, - SkType_BaseClassInfo, - SkType_Bitmap, - SkType_BitmapEncoding, - SkType_BitmapFormat, - SkType_BitmapShader, - SkType_Blur, - SkType_Boolean, // can have values -1 (uninitialized), 0, 1 - SkType_Boundable, - SkType_Bounds, - SkType_Cap, - SkType_Clear, - SkType_Clip, - SkType_Close, - SkType_Color, - SkType_CubicTo, - SkType_Dash, - SkType_DataInput, - SkType_Discrete, - SkType_Displayable, - SkType_Drawable, - SkType_DrawTo, - SkType_Dump, - SkType_DynamicString, // evaluate at draw time - SkType_Emboss, - SkType_Event, - SkType_EventCode, - SkType_EventKind, - SkType_EventMode, - SkType_FillType, - SkType_FilterType, - SkType_Float, - SkType_FontStyle, - SkType_FromPath, - SkType_FromPathMode, - SkType_Full, - SkType_DrawGradient, - SkType_Group, - SkType_HitClear, - SkType_HitTest, - SkType_ImageBaseBitmap, - SkType_Include, - SkType_Input, - SkType_Int, - SkType_Join, - SkType_Line, // simple line primitive - SkType_LineTo, // used as part of path construction - SkType_DrawLinearGradient, - SkType_MaskFilter, - SkType_MaskFilterBlurStyle, - SkType_MaskFilterLight, - SkType_Matrix, - SkType_MemberFunction, - SkType_MemberProperty, - SkType_Move, - SkType_MoveTo, - SkType_Movie, - SkType_MSec, - SkType_Oval, - SkType_Paint, - SkType_Path, - SkType_PathDirection, - SkType_PathEffect, - SkType_Point, // used inside other structures, no vtable - SkType_DrawPoint, // used to draw points, has a vtable - SkType_PolyToPoly, - SkType_Polygon, - SkType_Polyline, - SkType_Post, - SkType_QuadTo, - SkType_RCubicTo, - SkType_RLineTo, - SkType_RMoveTo, - SkType_RQuadTo, - SkType_DrawRadialGradient, - SkType_Random, - SkType_Rect, - SkType_RectToRect, - SkType_Remove, - SkType_Replace, - SkType_Rotate, - SkType_RoundRect, - SkType_Save, - SkType_SaveLayer, - SkType_Scale, - SkType_Screenplay, - SkType_Set, - SkType_Shader, - SkType_Skew, - SkType_3D_Camera, - SkType_3D_Patch, - SkType_3D_Point, - SkType_Snapshot, - SkType_String, // pointer to SkString - SkType_Style, - SkType_Text, - SkType_TextBox, - SkType_TextBoxAlign, - SkType_TextBoxMode, - SkType_TextOnPath, - SkType_TextToPath, - SkType_TileMode, - SkType_Translate, - SkType_TransparentShader, - SkType_Typeface, - SkType_Xfermode, - kNumberOfTypes -}; - -struct TypeNames { - const char* fName; - SkDisplayTypes fType; -#if defined SK_DEBUG || defined SK_BUILD_CONDENSED - bool fDrawPrefix; - bool fDisplayPrefix; -#endif -}; - -#ifdef SK_DEBUG -typedef SkDisplayTypes SkFunctionParamType; -#else -typedef unsigned char SkFunctionParamType; -#endif - -extern const TypeNames gTypeNames[]; -extern const int kTypeNamesSize; - -class SkDisplayType { -public: - static SkDisplayTypes Find(SkAnimateMaker* , const SkMemberInfo* ); - static const SkMemberInfo* GetMember(SkAnimateMaker* , SkDisplayTypes , const char** ); - static const SkMemberInfo* GetMembers(SkAnimateMaker* , SkDisplayTypes , int* infoCountPtr); - static SkDisplayTypes GetParent(SkAnimateMaker* , SkDisplayTypes ); - static bool IsDisplayable(SkAnimateMaker* , SkDisplayTypes ); - static bool IsEnum(SkAnimateMaker* , SkDisplayTypes ); - static bool IsStruct(SkAnimateMaker* , SkDisplayTypes ); - static SkDisplayTypes RegisterNewType(); - static SkDisplayTypes Resolve(const char[] , const SkMemberInfo** ); -#ifdef SK_DEBUG - static bool IsAnimate(SkDisplayTypes type ) { return type == SkType_Animate || - type == SkType_Set; } - static const char* GetName(SkAnimateMaker* , SkDisplayTypes ); -#endif -#ifdef SK_SUPPORT_UNITTEST - static void UnitTest(); -#endif -#if defined SK_DEBUG || defined SK_BUILD_CONDENSED - static void BuildCondensedInfo(SkAnimateMaker* ); -#endif - static SkDisplayTypes GetType(SkAnimateMaker* , const char[] , size_t len); - static SkDisplayable* CreateInstance(SkAnimateMaker* , SkDisplayTypes ); -private: - static SkDisplayTypes gNewTypes; -}; - -#endif // SkDisplayType_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayTypes.cpp b/gfx/skia/skia/src/animator/SkDisplayTypes.cpp deleted file mode 100644 index d3d8c68146f7..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayTypes.cpp +++ /dev/null @@ -1,214 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayTypes.h" -#include "SkAnimateBase.h" - -bool SkDisplayDepend::canContainDependents() const { - return true; -} - -void SkDisplayDepend::dirty() { - SkDisplayable** last = fDependents.end(); - for (SkDisplayable** depPtr = fDependents.begin(); depPtr < last; depPtr++) { - SkAnimateBase* animate = (SkAnimateBase* ) *depPtr; - animate->setChanged(true); - } -} - -// Boolean -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayBoolean::fInfo[] = { - SK_MEMBER(value, Boolean) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayBoolean); - -SkDisplayBoolean::SkDisplayBoolean() : value(false) { -} - -#ifdef SK_DUMP_ENABLED -void SkDisplayBoolean::dump(SkAnimateMaker* maker){ - dumpBase(maker); - SkDebugf("value=\"%s\" />\n", value ? "true" : "false"); -} -#endif - -// int32_t -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayInt::fInfo[] = { - SK_MEMBER(value, Int) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayInt); - -SkDisplayInt::SkDisplayInt() : value(0) { -} - -#ifdef SK_DUMP_ENABLED -void SkDisplayInt::dump(SkAnimateMaker* maker){ - dumpBase(maker); - SkDebugf("value=\"%d\" />\n", value); -} -#endif - -// SkScalar -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayFloat::fInfo[] = { - SK_MEMBER(value, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayFloat); - -SkDisplayFloat::SkDisplayFloat() : value(0) { -} - -#ifdef SK_DUMP_ENABLED -void SkDisplayFloat::dump(SkAnimateMaker* maker) { - dumpBase(maker); - SkDebugf("value=\"%g\" />\n", SkScalarToFloat(value)); -} -#endif - -// SkString -enum SkDisplayString_Functions { - SK_FUNCTION(slice) -}; - -enum SkDisplayString_Properties { - SK_PROPERTY(length) -}; - -const SkFunctionParamType SkDisplayString::fFunctionParameters[] = { - (SkFunctionParamType) SkType_Int, // slice - (SkFunctionParamType) SkType_Int, - (SkFunctionParamType) 0 -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayString::fInfo[] = { - SK_MEMBER_PROPERTY(length, Int), - SK_MEMBER_FUNCTION(slice, String), - SK_MEMBER(value, String) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayString); - -SkDisplayString::SkDisplayString() { -} - -SkDisplayString::SkDisplayString(SkString& copyFrom) : value(copyFrom) { -} - -void SkDisplayString::executeFunction(SkDisplayable* target, int index, - SkTDArray& parameters, SkDisplayTypes type, - SkScriptValue* scriptValue) { - if (scriptValue == nullptr) - return; - SkASSERT(target == this); - switch (index) { - case SK_FUNCTION(slice): - scriptValue->fType = SkType_String; - SkASSERT(parameters[0].fType == SkType_Int); - int start = parameters[0].fOperand.fS32; - if (start < 0) - start = (int) (value.size() - start); - int end = (int) value.size(); - if (parameters.count() > 1) { - SkASSERT(parameters[1].fType == SkType_Int); - end = parameters[1].fOperand.fS32; - } - //if (end >= 0 && end < (int) value.size()) - if (end >= 0 && end <= (int) value.size()) - scriptValue->fOperand.fString = new SkString(&value.c_str()[start], end - start); - else - scriptValue->fOperand.fString = new SkString(value); - break; - } -} - -const SkFunctionParamType* SkDisplayString::getFunctionsParameters() { - return fFunctionParameters; -} - -bool SkDisplayString::getProperty(int index, SkScriptValue* scriptValue) const { - switch (index) { - case SK_PROPERTY(length): - scriptValue->fType = SkType_Int; - scriptValue->fOperand.fS32 = (int32_t) value.size(); - break; - default: - SkASSERT(0); - return false; - } - return true; -} - - -// SkArray -#if 0 // !!! reason enough to qualify enum with class name or move typedArray into its own file -enum SkDisplayArray_Properties { - SK_PROPERTY(length) -}; -#endif - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDisplayArray::fInfo[] = { - SK_MEMBER_PROPERTY(length, Int), - SK_MEMBER_ARRAY(values, Unknown) -}; - -#endif - -DEFINE_GET_MEMBER(SkDisplayArray); - -SkDisplayArray::SkDisplayArray() { -} - -SkDisplayArray::SkDisplayArray(SkTypedArray& copyFrom) : values(copyFrom) { - -} - -SkDisplayArray::~SkDisplayArray() { - if (values.getType() == SkType_String) { - for (int index = 0; index < values.count(); index++) - delete values[index].fString; - return; - } - if (values.getType() == SkType_Array) { - for (int index = 0; index < values.count(); index++) - delete values[index].fArray; - } -} - -bool SkDisplayArray::getProperty(int index, SkScriptValue* value) const { - switch (index) { - case SK_PROPERTY(length): - value->fType = SkType_Int; - value->fOperand.fS32 = values.count(); - break; - default: - SkASSERT(0); - return false; - } - return true; -} diff --git a/gfx/skia/skia/src/animator/SkDisplayTypes.h b/gfx/skia/skia/src/animator/SkDisplayTypes.h deleted file mode 100644 index c24091f39895..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayTypes.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkDisplayTypes_DEFINED -#define SkDisplayTypes_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" -#include "SkTypedArray.h" - -class SkOpArray; // compiled script experiment - - -class SkDisplayDepend : public SkDisplayable { -public: - virtual bool canContainDependents() const; - void addDependent(SkDisplayable* displayable) { - if (fDependents.find(displayable) < 0) - *fDependents.append() = displayable; - } - virtual void dirty(); -private: - SkTDDisplayableArray fDependents; - typedef SkDisplayable INHERITED; -}; - -class SkDisplayBoolean : public SkDisplayDepend { - DECLARE_DISPLAY_MEMBER_INFO(Boolean); - SkDisplayBoolean(); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - SkBool value; - friend class SkAnimatorScript; - friend class SkAnimatorScript_Box; - friend class SkAnimatorScript_Unbox; - typedef SkDisplayDepend INHERITED; -}; - -class SkDisplayInt : public SkDisplayDepend { - DECLARE_DISPLAY_MEMBER_INFO(Int); - SkDisplayInt(); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif -private: - int32_t value; - friend class SkAnimatorScript; - friend class SkAnimatorScript_Box; - friend class SkAnimatorScript_Unbox; - typedef SkDisplayDepend INHERITED; -}; - -class SkDisplayFloat : public SkDisplayDepend { - DECLARE_DISPLAY_MEMBER_INFO(Float); - SkDisplayFloat(); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif -private: - SkScalar value; - friend class SkAnimatorScript; - friend class SkAnimatorScript_Box; - friend class SkAnimatorScript_Unbox; - typedef SkDisplayDepend INHERITED; -}; - -class SkDisplayString : public SkDisplayDepend { - DECLARE_DISPLAY_MEMBER_INFO(String); - SkDisplayString(); - SkDisplayString(SkString& ); - void executeFunction(SkDisplayable* , int index, - SkTDArray& parameters, SkDisplayTypes type, - SkScriptValue* ) override; - const SkFunctionParamType* getFunctionsParameters() override; - bool getProperty(int index, SkScriptValue* ) const override; - SkString value; -private: - static const SkFunctionParamType fFunctionParameters[]; -}; - -class SkDisplayArray : public SkDisplayDepend { - DECLARE_DISPLAY_MEMBER_INFO(Array); - SkDisplayArray(); - SkDisplayArray(SkTypedArray& ); - SkDisplayArray(SkOpArray& ); // compiled script experiment - virtual ~SkDisplayArray(); - bool getProperty(int index, SkScriptValue* ) const override; -private: - SkTypedArray values; - friend class SkAnimator; - friend class SkAnimatorScript; - friend class SkAnimatorScript2; - friend class SkAnimatorScript_Unbox; - friend class SkDisplayable; - friend struct SkMemberInfo; - friend class SkScriptEngine; -}; - -#endif // SkDisplayTypes_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayXMLParser.cpp b/gfx/skia/skia/src/animator/SkDisplayXMLParser.cpp deleted file mode 100644 index 1c8b67b6af10..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayXMLParser.cpp +++ /dev/null @@ -1,316 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayXMLParser.h" -#include "SkAnimateMaker.h" -#include "SkDisplayApply.h" -#include "SkUtils.h" -#ifdef SK_DEBUG -#include "SkTime.h" -#endif - -static char const* const gErrorStrings[] = { - "unknown error ", - "apply scopes itself", - "display tree too deep (circular reference?) ", - "element missing parent ", - "element type not allowed in parent ", - "error adding to ", - "error adding to ", - "error adding to ", - "error adding to ", - "error in attribute value ", - "error in script ", - "expected movie in sink attribute ", - "field not in target ", - "number of offsets in gradient must match number of colors", - "no offset in gradient may be greater than one", - "last offset in gradient must be one", - "offsets in gradient must be increasing", - "first offset in gradient must be zero", - "gradient attribute \"points\" must have length of four", - "in include ", - "in movie ", - "include name unknown or missing ", - "index out of range ", - "movie name unknown or missing ", - "no parent available to resolve sink attribute ", - "parent element can't contain ", - "saveLayer must specify a bounds", - "target id not found ", - "unexpected type " -}; - -SkDisplayXMLParserError::~SkDisplayXMLParserError() { -} - -void SkDisplayXMLParserError::getErrorString(SkString* str) const { - if (fCode > kUnknownError) - str->set(gErrorStrings[fCode - kUnknownError]); - else - str->reset(); - INHERITED::getErrorString(str); -} - -void SkDisplayXMLParserError::setInnerError(SkAnimateMaker* parent, const SkString& src) { - SkString inner; - getErrorString(&inner); - inner.prepend(": "); - inner.prependS32(getLineNumber()); - inner.prepend(", line "); - inner.prepend(src); - parent->setErrorNoun(inner); -} - - -SkDisplayXMLParser::SkDisplayXMLParser(SkAnimateMaker& maker) - : INHERITED(&maker.fError), fMaker(maker), fInInclude(maker.fInInclude), - fInSkia(maker.fInInclude), fCurrDisplayable(nullptr) -{ -} - -SkDisplayXMLParser::~SkDisplayXMLParser() { - if (fCurrDisplayable && fMaker.fChildren.find(fCurrDisplayable) < 0) - delete fCurrDisplayable; - for (Parent* parPtr = fParents.begin() + 1; parPtr < fParents.end(); parPtr++) { - SkDisplayable* displayable = parPtr->fDisplayable; - if (displayable == fCurrDisplayable) - continue; - SkASSERT(fMaker.fChildren.find(displayable) < 0); - if (fMaker.fHelpers.find(displayable) < 0) - delete displayable; - } -} - - - -bool SkDisplayXMLParser::onAddAttribute(const char name[], const char value[]) { - return onAddAttributeLen(name, value, strlen(value)); -} - -bool SkDisplayXMLParser::onAddAttributeLen(const char attrName[], const char attrValue[], - size_t attrValueLen) -{ - if (fCurrDisplayable == nullptr) // this signals we should ignore attributes for this element - return strncmp(attrName, "xmlns", sizeof("xmlns") - 1) != 0; - SkDisplayable* displayable = fCurrDisplayable; - SkDisplayTypes type = fCurrType; - - if (strcmp(attrName, "id") == 0) { - if (fMaker.find(attrValue, attrValueLen, nullptr)) { - fError->setNoun(attrValue, attrValueLen); - fError->setCode(SkXMLParserError::kDuplicateIDs); - return true; - } -#ifdef SK_DEBUG - displayable->_id.set(attrValue, attrValueLen); - displayable->id = displayable->_id.c_str(); -#endif - fMaker.idsSet(attrValue, attrValueLen, displayable); - int parentIndex = fParents.count() - 1; - if (parentIndex > 0) { - SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable; - parent->setChildHasID(); - } - return false; - } - const char* name = attrName; - const SkMemberInfo* info = SkDisplayType::GetMember(&fMaker, type, &name); - if (info == nullptr) { - fError->setNoun(name); - fError->setCode(SkXMLParserError::kUnknownAttributeName); - return true; - } - if (info->setValue(fMaker, nullptr, 0, info->getCount(), displayable, info->getType(), attrValue, - attrValueLen)) - return false; - if (fMaker.fError.hasError()) { - fError->setNoun(attrValue, attrValueLen); - return true; - } - SkDisplayable* ref = nullptr; - if (fMaker.find(attrValue, attrValueLen, &ref) == false) { - ref = fMaker.createInstance(attrValue, attrValueLen); - if (ref == nullptr) { - fError->setNoun(attrValue, attrValueLen); - fError->setCode(SkXMLParserError::kErrorInAttributeValue); - return true; - } else - fMaker.helperAdd(ref); - } - if (info->fType != SkType_MemberProperty) { - fError->setNoun(name); - fError->setCode(SkXMLParserError::kUnknownAttributeName); - return true; - } - SkScriptValue scriptValue; - scriptValue.fOperand.fDisplayable = ref; - scriptValue.fType = ref->getType(); - displayable->setProperty(info->propertyIndex(), scriptValue); - return false; -} - -#if defined(SK_BUILD_FOR_WIN32) - #define SK_strcasecmp _stricmp - #define SK_strncasecmp _strnicmp -#else - #define SK_strcasecmp strcasecmp - #define SK_strncasecmp strncasecmp -#endif - -bool SkDisplayXMLParser::onEndElement(const char elem[]) -{ - int parentIndex = fParents.count() - 1; - if (parentIndex >= 0) { - Parent& container = fParents[parentIndex]; - SkDisplayable* displayable = container.fDisplayable; - fMaker.fEndDepth = parentIndex; - displayable->onEndElement(fMaker); - if (fMaker.fError.hasError()) - return true; - if (parentIndex > 0) { - SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable; - bool result = parent->addChild(fMaker, displayable); - if (fMaker.hasError()) - return true; - if (result == false) { - int infoCount; - const SkMemberInfo* info = - SkDisplayType::GetMembers(&fMaker, fParents[parentIndex - 1].fType, &infoCount); - const SkMemberInfo* foundInfo; - if ((foundInfo = searchContainer(info, infoCount)) != nullptr) { - parent->setReference(foundInfo, displayable); - // if (displayable->isHelper() == false) - fMaker.helperAdd(displayable); - } else { - fMaker.setErrorCode(SkDisplayXMLParserError::kElementTypeNotAllowedInParent); - return true; - } - } - if (parent->childrenNeedDisposing()) - delete displayable; - } - fParents.remove(parentIndex); - } - fCurrDisplayable = nullptr; - if (fInInclude == false && SK_strcasecmp(elem, "screenplay") == 0) { - if (fMaker.fInMovie == false) { - fMaker.fEnableTime = fMaker.getAppTime(); -#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING - if (fMaker.fDebugTimeBase == (SkMSec) -1) - fMaker.fDebugTimeBase = fMaker.fEnableTime; - SkString debugOut; - SkMSec time = fMaker.getAppTime(); - debugOut.appendS32(time - fMaker.fDebugTimeBase); - debugOut.append(" onLoad enable="); - debugOut.appendS32(fMaker.fEnableTime - fMaker.fDebugTimeBase); - SkDebugf("%s\n", debugOut.c_str()); -#endif - fMaker.fEvents.doEvent(fMaker, SkDisplayEvent::kOnload, nullptr); - if (fMaker.fError.hasError()) - return true; - fMaker.fEvents.removeEvent(SkDisplayEvent::kOnload, nullptr); - - } - fInSkia = false; - } - return false; -} - -bool SkDisplayXMLParser::onStartElement(const char name[]) -{ - return onStartElementLen(name, strlen(name)); -} - -bool SkDisplayXMLParser::onStartElementLen(const char name[], size_t len) { - fCurrDisplayable = nullptr; // init so we'll ignore attributes if we exit early - - if (SK_strncasecmp(name, "screenplay", len) == 0) { - fInSkia = true; - if (fInInclude == false) - fMaker.idsSet(name, len, &fMaker.fScreenplay); - return false; - } - if (fInSkia == false) - return false; - - SkDisplayable* displayable = fMaker.createInstance(name, len); - if (displayable == nullptr) { - fError->setNoun(name, len); - fError->setCode(SkXMLParserError::kUnknownElement); - return true; - } - SkDisplayTypes type = displayable->getType(); - Parent record = { displayable, type }; - *fParents.append() = record; - if (fParents.count() == 1) - fMaker.childrenAdd(displayable); - else { - Parent* parent = fParents.end() - 2; - if (displayable->setParent(parent->fDisplayable)) { - fError->setNoun(name, len); - getError()->setCode(SkDisplayXMLParserError::kParentElementCantContain); - return true; - } - } - - // set these for subsequent calls to addAttribute() - fCurrDisplayable = displayable; - fCurrType = type; - return false; -} - -const SkMemberInfo* SkDisplayXMLParser::searchContainer(const SkMemberInfo* infoBase, - int infoCount) { - const SkMemberInfo* bestDisplayable = nullptr; - const SkMemberInfo* lastResort = nullptr; - for (int index = 0; index < infoCount; index++) { - const SkMemberInfo* info = &infoBase[index]; - if (info->fType == SkType_BaseClassInfo) { - const SkMemberInfo* inherited = info->getInherited(); - const SkMemberInfo* result = searchContainer(inherited, info->fCount); - if (result != nullptr) - return result; - continue; - } - Parent* container = fParents.end() - 1; - SkDisplayTypes type = (SkDisplayTypes) info->fType; - if (type == SkType_MemberProperty) - type = info->propertyType(); - SkDisplayTypes containerType = container->fType; - if (type == containerType && (type == SkType_Rect || type == SkType_Polygon || - type == SkType_Array || type == SkType_Int || type == SkType_Bitmap)) - goto rectNext; - while (type != containerType) { - if (containerType == SkType_Displayable) - goto next; - containerType = SkDisplayType::GetParent(&fMaker, containerType); - if (containerType == SkType_Unknown) - goto next; - } - return info; -next: - if (type == SkType_Drawable || (type == SkType_Displayable && - container->fDisplayable->isDrawable())) { -rectNext: - if (fParents.count() > 1) { - Parent* parent = fParents.end() - 2; - if (info == parent->fDisplayable->preferredChild(type)) - bestDisplayable = info; - else - lastResort = info; - } - } - } - if (bestDisplayable) - return bestDisplayable; - if (lastResort) - return lastResort; - return nullptr; -} diff --git a/gfx/skia/skia/src/animator/SkDisplayXMLParser.h b/gfx/skia/skia/src/animator/SkDisplayXMLParser.h deleted file mode 100644 index 9c561eda08d3..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayXMLParser.h +++ /dev/null @@ -1,91 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayXMLParser_DEFINED -#define SkDisplayXMLParser_DEFINED - -#include "SkIntArray.h" -#include "SkTDict.h" -#include "SkDisplayType.h" -#include "SkXMLParser.h" - -class SkAnimateMaker; -class SkDisplayable; - -class SkDisplayXMLParserError : public SkXMLParserError { -public: - enum ErrorCode { - kApplyScopesItself = kUnknownError + 1, - kDisplayTreeTooDeep, - kElementMissingParent, - kElementTypeNotAllowedInParent, - kErrorAddingDataToPost, - kErrorAddingToMatrix, - kErrorAddingToPaint, - kErrorAddingToPath, - kErrorInAttributeValue, - kErrorInScript, - kExpectedMovie, - kFieldNotInTarget, - kGradientOffsetsDontMatchColors, - kGradientOffsetsMustBeNoMoreThanOne, - kGradientOffsetsMustEndWithOne, - kGradientOffsetsMustIncrease, - kGradientOffsetsMustStartWithZero, - kGradientPointsLengthMustBeFour, - kInInclude, - kInMovie, - kIncludeNameUnknownOrMissing, - kIndexOutOfRange, - kMovieNameUnknownOrMissing, - kNoParentAvailable, - kParentElementCantContain, - kSaveLayerNeedsBounds, - kTargetIDNotFound, - kUnexpectedType - }; - virtual ~SkDisplayXMLParserError(); - virtual void getErrorString(SkString* str) const; - void setCode(ErrorCode code) { INHERITED::setCode((INHERITED::ErrorCode) code); } - void setInnerError(SkAnimateMaker* maker, const SkString& str); - typedef SkXMLParserError INHERITED; - friend class SkDisplayXMLParser; -}; - -class SkDisplayXMLParser : public SkXMLParser { -public: - SkDisplayXMLParser(SkAnimateMaker& maker); - virtual ~SkDisplayXMLParser(); -protected: - virtual bool onAddAttribute(const char name[], const char value[]); - bool onAddAttributeLen(const char name[], const char value[], size_t len); - virtual bool onEndElement(const char elem[]); - virtual bool onStartElement(const char elem[]); - bool onStartElementLen(const char elem[], size_t len); -private: - struct Parent { - SkDisplayable* fDisplayable; - SkDisplayTypes fType; - }; - SkTDArray fParents; - SkDisplayXMLParser& operator= (const SkDisplayXMLParser& ); - SkDisplayXMLParserError* getError() { return (SkDisplayXMLParserError*) fError; } - const SkMemberInfo* searchContainer(const SkMemberInfo* , - int infoCount); - SkAnimateMaker& fMaker; - SkBool fInInclude; - SkBool fInSkia; - // local state between onStartElement and onAddAttribute - SkDisplayable* fCurrDisplayable; - SkDisplayTypes fCurrType; - friend class SkXMLAnimatorWriter; - typedef SkXMLParser INHERITED; -}; - -#endif // SkDisplayXMLParser_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDisplayable.cpp b/gfx/skia/skia/src/animator/SkDisplayable.cpp deleted file mode 100644 index dc3cecfdbae2..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayable.cpp +++ /dev/null @@ -1,540 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDisplayable.h" -#include "SkDisplayApply.h" -#include "SkParse.h" -#ifdef SK_DEBUG -#include "SkDisplayList.h" -#endif -#include "SkDisplayTypes.h" - -#ifdef SK_FIND_LEAKS -// int SkDisplayable::fAllocationCount; -SkTDDisplayableArray SkDisplayable::fAllocations; -#endif - -#ifdef SK_DEBUG -SkDisplayable::SkDisplayable() { - id = _id.c_str(); -#ifdef SK_FIND_LEAKS - // fAllocationCount++; - *fAllocations.append() = this; -#endif -} -#endif - -SkDisplayable::~SkDisplayable() { -#ifdef SK_FIND_LEAKS - // fAllocationCount--; - int index = fAllocations.find(this); - SkASSERT(index >= 0); - fAllocations.remove(index); -#endif -} - -bool SkDisplayable::addChild(SkAnimateMaker& , SkDisplayable* child) { - return false; -} - -//void SkDisplayable::apply(SkAnimateMaker& , const SkMemberInfo* , -// SkDisplayable* , SkScalar [], int count) { -// SkASSERT(0); -//} - -bool SkDisplayable::canContainDependents() const { - return false; -} - -bool SkDisplayable::childrenNeedDisposing() const { - return false; -} - -void SkDisplayable::clearBounder() { -} - -bool SkDisplayable::contains(SkDisplayable* ) { - return false; -} - -SkDisplayable* SkDisplayable::contains(const SkString& ) { - return nullptr; -} - -SkDisplayable* SkDisplayable::deepCopy(SkAnimateMaker* maker) { - SkDisplayTypes type = getType(); - if (type == SkType_Unknown) { - SkASSERT(0); - return nullptr; - } - SkDisplayable* copy = SkDisplayType::CreateInstance(maker, type); - int index = -1; - int propIndex = 0; - const SkMemberInfo* info; - do { - info = copy->getMember(++index); - if (info == nullptr) - break; - if (info->fType == SkType_MemberProperty) { - SkScriptValue value; - if (getProperty(propIndex, &value)) - copy->setProperty(propIndex, value); - propIndex++; - continue; - } - if (info->fType == SkType_MemberFunction) - continue; - if (info->fType == SkType_Array) { - SkTDOperandArray* array = (SkTDOperandArray*) info->memberData(this); - int arrayCount; - if (array == nullptr || (arrayCount = array->count()) == 0) - continue; - SkTDOperandArray* copyArray = (SkTDOperandArray*) info->memberData(copy); - copyArray->setCount(arrayCount); - SkDisplayTypes elementType; - if (type == SkType_Array) { - SkDisplayArray* dispArray = (SkDisplayArray*) this; - elementType = dispArray->values.getType(); - } else - elementType = info->arrayType(); - size_t elementSize = SkMemberInfo::GetSize(elementType); - size_t byteSize = elementSize * arrayCount; - memcpy(copyArray->begin(), array->begin(), byteSize); - continue; - } - if (SkDisplayType::IsDisplayable(maker, info->fType)) { - SkDisplayable** displayable = (SkDisplayable**) info->memberData(this); - if (*displayable == nullptr || *displayable == (SkDisplayable*) -1) - continue; - SkDisplayable* deeper = (*displayable)->deepCopy(maker); - info->setMemberData(copy, deeper, sizeof(deeper)); - continue; - } - if (info->fType == SkType_String || info->fType == SkType_DynamicString) { - SkString* string; - info->getString(this, &string); - info->setString(copy, string); - continue; - } - void* data = info->memberData(this); - size_t size = SkMemberInfo::GetSize(info->fType); - info->setMemberData(copy, data, size); - } while (true); - copy->dirty(); - return copy; -} - -void SkDisplayable::dirty() { -} - -#ifdef SK_DUMP_ENABLED -void SkDisplayable::dump(SkAnimateMaker* maker) { - dumpBase(maker); -#if SK_USE_CONDENSED_INFO == 0 - this->dumpAttrs(maker); - this->dumpChildren(maker); -#endif -} - -void SkDisplayable::dumpAttrs(SkAnimateMaker* maker) { - SkDisplayTypes type = getType(); - if (type == SkType_Unknown) { - //SkDebugf("/>\n"); - return; - } - SkDisplayable* blankCopy = SkDisplayType::CreateInstance(maker, type); - - int index = -1; - int propIndex = 0; - const SkMemberInfo* info; - const SkMemberInfo* blankInfo; - SkScriptValue value; - SkScriptValue blankValue; - SkOperand values[2]; - SkOperand blankValues[2]; - do { - info = this->getMember(++index); - if (nullptr == info) { - //SkDebugf("\n"); - break; - } - if (SkType_MemberProperty == info->fType) { - if (getProperty(propIndex, &value)) { - blankCopy->getProperty(propIndex, &blankValue); - //last two are dummies - dumpValues(info, value.fType, value.fOperand, blankValue.fOperand, value.fOperand, blankValue.fOperand); - } - - propIndex++; - continue; - } - if (SkDisplayType::IsDisplayable(maker, info->fType)) { - continue; - } - - if (info->fType == SkType_MemberFunction) - continue; - - - if (info->fType == SkType_Array) { - SkTDOperandArray* array = (SkTDOperandArray*) info->memberData(this); - int arrayCount; - if (array == nullptr || (arrayCount = array->count()) == 0) - continue; - SkDisplayTypes elementType; - if (type == SkType_Array) { - SkDisplayArray* dispArray = (SkDisplayArray*) this; - elementType = dispArray->values.getType(); - } else - elementType = info->arrayType(); - bool firstElem = true; - SkDebugf("%s=\"[", info->fName); - for (SkOperand* op = array->begin(); op < array->end(); op++) { - if (!firstElem) SkDebugf(","); - switch (elementType) { - case SkType_Displayable: - SkDebugf("%s", op->fDisplayable->id); - break; - case SkType_Int: - SkDebugf("%d", op->fS32); - break; - case SkType_Float: - SkDebugf("%g", SkScalarToFloat(op->fScalar)); - break; - case SkType_String: - case SkType_DynamicString: - SkDebugf("%s", op->fString->c_str()); - break; - default: - break; - } - firstElem = false; - } - SkDebugf("]\" "); - continue; - } - - if (info->fType == SkType_String || info->fType == SkType_DynamicString) { - SkString* string; - info->getString(this, &string); - if (string->isEmpty() == false) - SkDebugf("%s=\"%s\"\t", info->fName, string->c_str()); - continue; - } - - - blankInfo = blankCopy->getMember(index); - int i = info->fCount; - info->getValue(this, values, i); - blankInfo->getValue(blankCopy, blankValues, i); - dumpValues(info, info->fType, values[0], blankValues[0], values[1], blankValues[1]); - } while (true); - delete blankCopy; -} - -void SkDisplayable::dumpBase(SkAnimateMaker* maker) { - SkDisplayTypes type = getType(); - const char* elementName = "(unknown)"; - if (type != SkType_Unknown && type != SkType_Screenplay) - elementName = SkDisplayType::GetName(maker, type); - SkDebugf("%*s", SkDisplayList::fIndent, ""); - if (SkDisplayList::fDumpIndex != 0 && SkDisplayList::fIndent == 0) - SkDebugf("%d: ", SkDisplayList::fDumpIndex); - SkDebugf("<%s ", elementName); - if (strcmp(id,"") != 0) - SkDebugf("id=\"%s\" ", id); -} - -void SkDisplayable::dumpChildren(SkAnimateMaker* maker, bool closedAngle) { - - int index = -1; - const SkMemberInfo* info; - index = -1; - SkDisplayList::fIndent += 4; - do { - info = this->getMember(++index); - if (nullptr == info) { - break; - } - if (SkDisplayType::IsDisplayable(maker, info->fType)) { - SkDisplayable** displayable = (SkDisplayable**) info->memberData(this); - if (*displayable == nullptr || *displayable == (SkDisplayable*) -1) - continue; - if (closedAngle == false) { - SkDebugf(">\n"); - closedAngle = true; - } - (*displayable)->dump(maker); - } - } while (true); - SkDisplayList::fIndent -= 4; - if (closedAngle) - dumpEnd(maker); - else - SkDebugf("/>\n"); -} - -void SkDisplayable::dumpEnd(SkAnimateMaker* maker) { - SkDisplayTypes type = getType(); - const char* elementName = "(unknown)"; - if (type != SkType_Unknown && type != SkType_Screenplay) - elementName = SkDisplayType::GetName(maker, type); - SkDebugf("%*s", SkDisplayList::fIndent, ""); - SkDebugf("\n", elementName); -} - -void SkDisplayable::dumpEvents() { -} - -void SkDisplayable::dumpValues(const SkMemberInfo* info, SkDisplayTypes type, SkOperand op, SkOperand blankOp, - SkOperand op2, SkOperand blankOp2) { - switch (type) { - case SkType_BitmapEncoding: - switch (op.fS32) { - case 0 : SkDebugf("type=\"jpeg\" "); - break; - case 1 : SkDebugf("type=\"png\" "); - break; - default: SkDebugf("type=\"UNDEFINED\" "); - } - break; - //should make this a separate case in dump attrs, rather than make dump values have a larger signature - case SkType_Point: - if (op.fScalar != blankOp.fScalar || op2.fScalar != blankOp.fScalar) { - SkDebugf("%s=\"[%g,%g]\" ", info->fName, SkScalarToFloat(op.fScalar), SkScalarToFloat(op2.fScalar)); - } - break; - case SkType_FromPathMode: - switch (op.fS32) { - case 0: - //don't want to print anything for 0, just adding it to remove it from default: - break; - case 1: - SkDebugf("%s=\"%s\" ", info->fName, "angle"); - break; - case 2: - SkDebugf("%s=\"%s\" ", info->fName, "position"); - break; - default: - SkDebugf("%s=\"INVALID\" ", info->fName); - } - break; - case SkType_MaskFilterBlurStyle: - switch (op.fS32) { - case 0: - break; - case 1: - SkDebugf("%s=\"%s\" ", info->fName, "solid"); - break; - case 2: - SkDebugf("%s=\"%s\" ", info->fName, "outer"); - break; - case 3: - SkDebugf("%s=\"%s\" ", info->fName, "inner"); - break; - default: - SkDebugf("%s=\"INVALID\" ", info->fName); - } - break; - case SkType_FilterType: - if (op.fS32 == 1) - SkDebugf("%s=\"%s\" ", info->fName, "bilinear"); - break; - case SkType_PathDirection: - SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "cw" : "ccw"); - break; - case SkType_FillType: - SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "winding" : "evenOdd"); - break; - case SkType_TileMode: - //correct to look at the S32? - if (op.fS32 != blankOp.fS32) - SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "clamp" : op.fS32 == 1 ? "repeat" : "mirror"); - break; - case SkType_Boolean: - if (op.fS32 != blankOp.fS32) - SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "false" : "true"); - break; - case SkType_Int: - if (op.fS32 != blankOp.fS32) - SkDebugf(" %s=\"%d\" ", info->fName, op.fS32); - break; - case SkType_Float: - if (op.fScalar != blankOp.fScalar) { //or /65536? - SkDebugf("%s=\"%g\" ", info->fName, SkScalarToFloat(op.fScalar)); - } - break; - case SkType_String: - case SkType_DynamicString: - if (op.fString->size() > 0) - SkDebugf("%s=\"%s\" ", info->fName, op.fString->c_str()); - break; - case SkType_MSec: - if (op.fS32 != blankOp.fS32) { - SkDebugf(" %s=\"%g\" ", info->fName, op.fS32 * 0.001); - } - default: - SkDebugf(""); - } -} - -#endif - -bool SkDisplayable::enable( SkAnimateMaker& ) { - return false; -} - -void SkDisplayable::enableBounder() { -} - -void SkDisplayable::executeFunction(SkDisplayable* , int index, - SkTDArray& , SkDisplayTypes, SkScriptValue* ) { - SkASSERT(0); -} - -void SkDisplayable::executeFunction(SkDisplayable* target, - const SkMemberInfo* info, SkTypedArray* values, SkScriptValue* value) { - SkTDArray typedValues; - for (SkOperand* op = values->begin(); op < values->end(); op++) { - SkScriptValue temp; - temp.fType = values->getType(); - temp.fOperand = *op; - *typedValues.append() = temp; - } - executeFunction(target, info->functionIndex(), typedValues, info->getType(), value); -} - -void SkDisplayable::executeFunction2(SkDisplayable* , int index, - SkOpArray* params, SkDisplayTypes, SkOperand2* ) { - SkASSERT(0); -} - -void SkDisplayable::getBounds(SkRect* rect) { - SkASSERT(rect); - rect->fLeft = rect->fTop = SK_ScalarMax; - rect->fRight= rect->fBottom = -SK_ScalarMax; -} - -const SkFunctionParamType* SkDisplayable::getFunctionsParameters() { - return nullptr; -} - -const SkMemberInfo* SkDisplayable::getMember(int index) { - return nullptr; -} - -const SkMemberInfo* SkDisplayable::getMember(const char name[]) { - return nullptr; -} - -const SkFunctionParamType* SkDisplayable::getParameters(const SkMemberInfo* info, - int* paramCount) { - const SkFunctionParamType* params = getFunctionsParameters(); - SkASSERT(params != nullptr); - int funcIndex = info->functionIndex(); - // !!! eventually break traversing params into an external function (maybe this whole function) - int index = funcIndex; - int offset = 0; - while (--index >= 0) { - while (params[offset] != 0) - offset++; - offset++; - } - int count = 0; - while (params[offset] != 0) { - count++; - offset++; - } - *paramCount = count; - return ¶ms[offset - count]; -} - -SkDisplayable* SkDisplayable::getParent() const { - return nullptr; -} - -bool SkDisplayable::getProperty(int index, SkScriptValue* ) const { -// SkASSERT(0); - return false; -} - -bool SkDisplayable::getProperty2(int index, SkOperand2* value) const { - SkASSERT(0); - return false; -} - -SkDisplayTypes SkDisplayable::getType() const { - return SkType_Unknown; -} - -bool SkDisplayable::hasEnable() const { - return false; -} - -bool SkDisplayable::isDrawable() const { - return false; -} - -void SkDisplayable::onEndElement(SkAnimateMaker& ) {} - -const SkMemberInfo* SkDisplayable::preferredChild(SkDisplayTypes type) { - return nullptr; -} - -bool SkDisplayable::resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply) { - return false; -} - -//SkDisplayable* SkDisplayable::resolveTarget(SkAnimateMaker& ) { -// return this; -//} - -void SkDisplayable::setChildHasID() { -} - -bool SkDisplayable::setParent(SkDisplayable* ) { - return false; -} - -bool SkDisplayable::setProperty(int index, SkScriptValue& ) { - //SkASSERT(0); - return false; -} - -void SkDisplayable::setReference(const SkMemberInfo* info, SkDisplayable* displayable) { - if (info->fType == SkType_MemberProperty) { - SkScriptValue scriptValue; - scriptValue.fOperand.fDisplayable = displayable; - scriptValue.fType = displayable->getType(); - setProperty(info->propertyIndex(), scriptValue); - } else if (info->fType == SkType_Array) { - SkASSERT(displayable->getType() == SkType_Array); - SkDisplayArray* dispArray = (SkDisplayArray*) displayable; - SkTDScalarArray* array = (SkTDScalarArray* ) info->memberData(this); - array->setCount(dispArray->values.count()); - memcpy(array->begin(), dispArray->values.begin(), dispArray->values.count() * sizeof(int)); - // - - // !!! need a way for interpreter engine to own array - // !!! probably need to replace all scriptable arrays with single bigger array - // that has operand and type on every element -- or - // when array is dirtied, need to get parent to reparse to local array - } else { - void* storage = info->memberData(this); - memcpy(storage, &displayable, sizeof(SkDisplayable*)); - } -// !!! unclear why displayable is dirtied here -// if this is called, this breaks fromPath.xml -// displayable->dirty(); -} - -#ifdef SK_DEBUG -void SkDisplayable::validate() { -} -#endif diff --git a/gfx/skia/skia/src/animator/SkDisplayable.h b/gfx/skia/skia/src/animator/SkDisplayable.h deleted file mode 100644 index 4fd47abc3724..000000000000 --- a/gfx/skia/skia/src/animator/SkDisplayable.h +++ /dev/null @@ -1,112 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDisplayable_DEFINED -#define SkDisplayable_DEFINED - -#include "SkOperand.h" -#ifdef SK_DEBUG -#include "SkString.h" -#endif -#include "SkIntArray.h" -#include "SkRect.h" -#include "SkTDArray.h" - -class SkAnimateMaker; -class SkApply; -class SkEvents; -struct SkMemberInfo; -struct SkScriptValue; -class SkOpArray; // compiled scripting experiment -union SkOperand2; // compiled scripting experiment - -class SkDisplayable { -public: -#ifdef SK_DEBUG - SkDisplayable(); -#endif - virtual ~SkDisplayable(); - virtual bool addChild(SkAnimateMaker& , SkDisplayable* child); - virtual bool canContainDependents() const; - virtual bool childrenNeedDisposing() const; - virtual void clearBounder(); - virtual bool contains(SkDisplayable* ); - virtual SkDisplayable* contains(const SkString& ); - virtual SkDisplayable* deepCopy(SkAnimateMaker* ); - virtual void dirty(); -#ifdef SK_DUMP_ENABLED - virtual void dump(SkAnimateMaker* ); - void dumpAttrs(SkAnimateMaker* ); - void dumpBase(SkAnimateMaker* ); - void dumpChildren(SkAnimateMaker* maker, bool closedAngle = false ); - void dumpEnd(SkAnimateMaker* ); - virtual void dumpEvents(); -#endif - virtual bool enable( SkAnimateMaker& ); - virtual void enableBounder(); - virtual void executeFunction(SkDisplayable* , int functionIndex, - SkTDArray& , SkDisplayTypes , SkScriptValue* ); - void executeFunction(SkDisplayable* , const SkMemberInfo* , - SkTypedArray* , SkScriptValue* ); - virtual void executeFunction2(SkDisplayable* , int functionIndex, - SkOpArray* params , SkDisplayTypes , SkOperand2* ); // compiled scripting experiment - virtual void getBounds(SkRect* ); - virtual const SkFunctionParamType* getFunctionsParameters(); - virtual const SkMemberInfo* getMember(int index); - virtual const SkMemberInfo* getMember(const char name[]); - const SkFunctionParamType* getParameters(const SkMemberInfo* info, - int* paramCount); - virtual SkDisplayable* getParent() const; - virtual bool getProperty(int index, SkScriptValue* value) const; - virtual bool getProperty2(int index, SkOperand2* value) const; // compiled scripting experiment - virtual SkDisplayTypes getType() const; - virtual bool hasEnable() const; - bool isAnimate() const { - SkDisplayTypes type = getType(); - return type == SkType_Animate || type == SkType_Set; } - bool isApply() const { return getType() == SkType_Apply; } - bool isColor() const { return getType() == SkType_Color; } - virtual bool isDrawable() const; - bool isGroup() const { return getType() == SkType_Group || - getType() == SkType_Save || getType() == SkType_DrawTo || - getType() == SkType_SaveLayer; } - bool isMatrix() const { return getType() == SkType_Matrix; } - virtual bool isPaint() const { return getType() == SkType_Paint; } - virtual bool isPath() const { return false; } - bool isPost() const { return getType() == SkType_Post; } - virtual void onEndElement(SkAnimateMaker& ); - virtual const SkMemberInfo* preferredChild(SkDisplayTypes type); - virtual bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* ); - virtual void setChildHasID(); - virtual bool setParent(SkDisplayable* ); - virtual bool setProperty(int index, SkScriptValue& ); - void setReference(const SkMemberInfo* info, SkDisplayable* ref); -#ifdef SK_DEBUG - bool isDataInput() const { return getType() == SkType_DataInput; }; - bool isEvent() const { return getType() == SkType_Event; } - virtual bool isMatrixPart() const { return false; } - bool isPatch() const { return getType() == SkType_3D_Patch; } - virtual bool isPaintPart() const { return false; } - virtual bool isPathPart() const { return false; } - virtual void validate(); - SkString _id; - const char* id; -// static int fAllocationCount; - static SkTDDisplayableArray fAllocations; -#else - void validate() {} -#endif -#ifdef SK_DUMP_ENABLED -private: - void dumpValues(const SkMemberInfo* info, SkDisplayTypes type, SkOperand op, SkOperand blankOp, - SkOperand op2, SkOperand blankOp2); -#endif -}; - -#endif // SkDisplayable_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDraw3D.cpp b/gfx/skia/skia/src/animator/SkDraw3D.cpp deleted file mode 100644 index e7e92df3e30c..000000000000 --- a/gfx/skia/skia/src/animator/SkDraw3D.cpp +++ /dev/null @@ -1,106 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDraw3D.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkTypedArray.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo Sk3D_Point::fInfo[] = { - SK_MEMBER_ALIAS(x, fPoint.fX, Float), - SK_MEMBER_ALIAS(y, fPoint.fY, Float), - SK_MEMBER_ALIAS(z, fPoint.fZ, Float) -}; - -#endif - -DEFINE_NO_VIRTUALS_GET_MEMBER(Sk3D_Point); - -Sk3D_Point::Sk3D_Point() { - fPoint.set(0, 0, 0); -} - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo Sk3D_Camera::fInfo[] = { - SK_MEMBER_ALIAS(axis, fCamera.fAxis, 3D_Point), - SK_MEMBER(hackHeight, Float), - SK_MEMBER(hackWidth, Float), - SK_MEMBER_ALIAS(location, fCamera.fLocation, 3D_Point), - SK_MEMBER_ALIAS(observer, fCamera.fObserver, 3D_Point), - SK_MEMBER(patch, 3D_Patch), - SK_MEMBER_ALIAS(zenith, fCamera.fZenith, 3D_Point), -}; - -#endif - -DEFINE_GET_MEMBER(Sk3D_Camera); - -Sk3D_Camera::Sk3D_Camera() : hackWidth(0), hackHeight(0), patch(nullptr) { -} - -Sk3D_Camera::~Sk3D_Camera() { -} - -bool Sk3D_Camera::draw(SkAnimateMaker& maker) { - fCamera.update(); - SkMatrix matrix; - fCamera.patchToMatrix(patch->fPatch, &matrix); - matrix.preTranslate(hackWidth / 2, -hackHeight / 2); - matrix.postTranslate(hackWidth / 2, hackHeight / 2); - maker.fCanvas->concat(matrix); - return false; -} - - -enum Sk3D_Patch_Functions { - SK_FUNCTION(rotateDegrees) -}; - -const SkFunctionParamType Sk3D_Patch::fFunctionParameters[] = { - (SkFunctionParamType) SkType_Float, - (SkFunctionParamType) SkType_Float, - (SkFunctionParamType) SkType_Float, - (SkFunctionParamType) 0 // terminator for parameter list (there may be multiple parameter lists) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo Sk3D_Patch::fInfo[] = { - SK_MEMBER_ALIAS(origin, fPatch.fOrigin, 3D_Point), - SK_MEMBER_FUNCTION(rotateDegrees, Float), - SK_MEMBER_ALIAS(u, fPatch.fU, 3D_Point), - SK_MEMBER_ALIAS(v, fPatch.fV, 3D_Point) -}; - -#endif - -DEFINE_GET_MEMBER(Sk3D_Patch); - -void Sk3D_Patch::executeFunction(SkDisplayable* target, int index, - SkTDArray& parameters, SkDisplayTypes type, - SkScriptValue* ) { - SkASSERT(target == this); - switch (index) { - case SK_FUNCTION(rotateDegrees): - SkASSERT(parameters.count() == 3); - SkASSERT(type == SkType_Float); - fPatch.rotateDegrees(parameters[0].fOperand.fScalar, - parameters[1].fOperand.fScalar, parameters[2].fOperand.fScalar); - break; - default: - SkASSERT(0); - } -} - -const SkFunctionParamType* Sk3D_Patch::getFunctionsParameters() { - return fFunctionParameters; -} diff --git a/gfx/skia/skia/src/animator/SkDraw3D.h b/gfx/skia/skia/src/animator/SkDraw3D.h deleted file mode 100644 index 8c79b5e7b30f..000000000000 --- a/gfx/skia/skia/src/animator/SkDraw3D.h +++ /dev/null @@ -1,50 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDraw3D_DEFINED -#define SkDraw3D_DEFINED - -#include "SkCamera.h" -#include "SkADrawable.h" -#include "SkMemberInfo.h" - -class Sk3D_Patch; - -struct Sk3D_Point { - DECLARE_NO_VIRTUALS_MEMBER_INFO(3D_Point); - Sk3D_Point(); -private: - SkPoint3D fPoint; -}; - -class Sk3D_Camera : public SkADrawable { - DECLARE_MEMBER_INFO(3D_Camera); - Sk3D_Camera(); - virtual ~Sk3D_Camera(); - bool draw(SkAnimateMaker& ) override; -private: - SkScalar hackWidth; - SkScalar hackHeight; - SkCamera3D fCamera; - Sk3D_Patch* patch; -}; - -class Sk3D_Patch : public SkDisplayable { - DECLARE_MEMBER_INFO(3D_Patch); -private: - void executeFunction(SkDisplayable* , int index, - SkTDArray& parameters, SkDisplayTypes type, - SkScriptValue* ) override; - const SkFunctionParamType* getFunctionsParameters() override; - SkPatch3D fPatch; - static const SkFunctionParamType fFunctionParameters[]; - friend class Sk3D_Camera; -}; - -#endif // SkDraw3D_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawBitmap.cpp b/gfx/skia/skia/src/animator/SkDrawBitmap.cpp deleted file mode 100644 index 191240855c9d..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawBitmap.cpp +++ /dev/null @@ -1,201 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawBitmap.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkData.h" -#include "SkImage.h" -#include "SkPaint.h" -#include "SkStream.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkBaseBitmap::fInfo[] = { - SK_MEMBER(x, Float), - SK_MEMBER(y, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkBaseBitmap); - -SkBaseBitmap::SkBaseBitmap() : x(0), y(0) { -} - -SkBaseBitmap::~SkBaseBitmap() { -} - -bool SkBaseBitmap::draw(SkAnimateMaker& maker) { - SkBoundableAuto boundable(this, maker); - maker.fCanvas->drawBitmap(fBitmap, x, y, maker.fPaint); - return false; -} - -enum SkDrawBitmap_Properties { - SK_PROPERTY(erase) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawBitmap::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER_PROPERTY(erase, ARGB), - SK_MEMBER(format, BitmapFormat), - SK_MEMBER(height, Int), - SK_MEMBER(rowBytes, Int), - SK_MEMBER(width, Int), -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawBitmap); - -SkDrawBitmap::SkDrawBitmap() : format((SkColorType) -1), height(-1), - rowBytes(0), width(-1), fColor(0), fColorSet(false) { -} - -SkDrawBitmap::~SkDrawBitmap() { -} - -#ifdef SK_DUMP_ENABLED -void SkDrawBitmap::dump(SkAnimateMaker* maker) { - dumpBase(maker); - dumpAttrs(maker); - if (fColorSet) - SkDebugf("erase=\"argb(%d,%d,%d,%d)\" ", SkColorGetA(fColor)/255, SkColorGetR(fColor), - SkColorGetG(fColor), SkColorGetB(fColor)); - if (rowBytes > 0) - SkDebugf("rowBytes=\"%d\" ", rowBytes); - const char* formatName SK_INIT_TO_AVOID_WARNING; - switch (format) { - case 0: formatName = "none"; break; - case 1: formatName = "A8"; break; - case 2: formatName = "Index8"; break; - case 3: formatName = "RGB16"; break; - case 4: formatName = "RGB32"; break; - } - SkDebugf("format=\"%s\" />\n", formatName); -} -#endif - -void SkDrawBitmap::onEndElement(SkAnimateMaker&) { - SkASSERT(width != -1); - SkASSERT(height != -1); - SkASSERT(rowBytes >= 0); - SkColorType colorType = SkColorType(format); - fBitmap.allocPixels(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType), - rowBytes); - if (fColorSet) - fBitmap.eraseColor(fColor); -} - -bool SkDrawBitmap::setProperty(int index, SkScriptValue& value) -{ - switch (index) { - case SK_PROPERTY(erase): - SkASSERT(value.fType == SkType_ARGB); - fColor = value.fOperand.fS32; - fColorSet = true; - break; - default: - SkASSERT(0); - return false; - } - return true; -} - - -enum SkImageBaseBitmap_Properties { - SK_PROPERTY(height), - SK_PROPERTY(width) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkImageBaseBitmap::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER(base64, Base64), - SK_MEMBER_PROPERTY(height, Int), - SK_MEMBER(src, String), - SK_MEMBER_PROPERTY(width, Int) -}; - -#endif - -DEFINE_GET_MEMBER(SkImageBaseBitmap); - -SkImageBaseBitmap::SkImageBaseBitmap() : fDirty(true), fUriBase(nullptr) { - base64.fData = nullptr; - base64.fLength = 0; -} - -SkImageBaseBitmap::~SkImageBaseBitmap() { - delete[] base64.fData; -} - -SkDisplayable* SkImageBaseBitmap::deepCopy(SkAnimateMaker* maker) { - SkDisplayable* copy = INHERITED::deepCopy(maker); - ((SkImageBaseBitmap*) copy)->fUriBase = ((SkImageBaseBitmap*) this)->fUriBase; - return copy; -} - -void SkImageBaseBitmap::dirty() { - fDirty = true; -} - -bool SkImageBaseBitmap::draw(SkAnimateMaker& maker) { - if (fDirty) - resolve(); - return INHERITED::draw(maker); -} - -bool SkImageBaseBitmap::getProperty(int index, SkScriptValue* value) const { - if (fDirty) - resolve(); - switch (index) { - case SK_PROPERTY(height): - value->fOperand.fS32 = fBitmap.height(); - break; - case SK_PROPERTY(width): - value->fOperand.fS32 = fBitmap.width(); - break; - default: - SkASSERT(0); - return false; - } - value->fType = SkType_Int; - return true; -} - -void SkImageBaseBitmap::onEndElement(SkAnimateMaker& maker) { - fUriBase = maker.fPrefix.c_str(); -} - -void SkImageBaseBitmap::resolve() { - fDirty = false; - if (base64.fData) { - fBitmap.reset(); - sk_sp data = SkData::MakeWithoutCopy(base64.fData, base64.fLength); - sk_sp image = SkImage::MakeFromEncoded(data); - image->asLegacyBitmap(&fBitmap, SkImage::kRO_LegacyBitmapMode); - } else if (src.size()) { - if (fLast.equals(src)) - return; - fLast.set(src); - fBitmap.reset(); - - //SkStream* stream = SkStream::GetURIStream(fUriBase, src.c_str()); - sk_sp data = SkData::MakeFromFileName(src.c_str()); - if (data) { - sk_sp image = SkImage::MakeFromEncoded(data); - image->asLegacyBitmap(&fBitmap, SkImage::kRO_LegacyBitmapMode); - } - } -} diff --git a/gfx/skia/skia/src/animator/SkDrawBitmap.h b/gfx/skia/skia/src/animator/SkDrawBitmap.h deleted file mode 100644 index 9fd25d604a27..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawBitmap.h +++ /dev/null @@ -1,73 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawBitmap_DEFINED -#define SkDrawBitmap_DEFINED - -#include "SkBoundable.h" -#include "SkBase64.h" -#include "SkBitmap.h" -#include "SkMemberInfo.h" - -class SkBaseBitmap : public SkBoundable { - DECLARE_MEMBER_INFO(BaseBitmap); - SkBaseBitmap(); - virtual ~SkBaseBitmap(); - bool draw(SkAnimateMaker& ) override; -protected: - SkBitmap fBitmap; - SkScalar x; - SkScalar y; -private: - friend class SkDrawTo; - friend class SkDrawBitmapShader; - typedef SkBoundable INHERITED; -}; - -class SkDrawBitmap : public SkBaseBitmap { - DECLARE_DRAW_MEMBER_INFO(Bitmap); - SkDrawBitmap(); - virtual ~SkDrawBitmap(); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - void onEndElement(SkAnimateMaker& ) override; - bool setProperty(int index, SkScriptValue& value) override; -protected: - int /*SkBitmap::Config*/ format; - int32_t height; - int32_t rowBytes; - int32_t width; - SkColor fColor; - SkBool fColorSet; - typedef SkBaseBitmap INHERITED; -}; - -class SkImageBaseBitmap : public SkBaseBitmap { - DECLARE_MEMBER_INFO(ImageBaseBitmap); - SkImageBaseBitmap(); - virtual ~SkImageBaseBitmap(); - SkDisplayable* deepCopy(SkAnimateMaker* ) override; - void dirty() override; - bool draw(SkAnimateMaker& ) override; - bool getProperty(int index, SkScriptValue* value) const override; - void onEndElement(SkAnimateMaker& maker) override; -private: - void resolve() const { (const_cast(this))->resolve(); } - void resolve(); -protected: - SkBase64 base64; - SkString src; - SkString fLast; // cache of src so that stream isn't unnecessarily decoded - SkBool fDirty; - const char* fUriBase; - typedef SkBaseBitmap INHERITED; -}; - -#endif // SkDrawBitmap_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawBlur.cpp b/gfx/skia/skia/src/animator/SkDrawBlur.cpp deleted file mode 100644 index 0acb13ec5a9d..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawBlur.cpp +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawBlur.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawBlur::fInfo[] = { - SK_MEMBER(fBlurStyle, MaskFilterBlurStyle), - SK_MEMBER(fSigma, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawBlur); - -SkDrawBlur::SkDrawBlur() - : fSigma(-1) - , fBlurStyle(kNormal_SkBlurStyle) { -} - -SkMaskFilter* SkDrawBlur::getMaskFilter() { - if (fSigma <= 0) { - return nullptr; - } - return SkBlurMaskFilter::Make((SkBlurStyle)fBlurStyle, fSigma).release(); -} diff --git a/gfx/skia/skia/src/animator/SkDrawBlur.h b/gfx/skia/skia/src/animator/SkDrawBlur.h deleted file mode 100644 index d3a528c22fa9..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawBlur.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkDrawBlur_DEFINED -#define SkDrawBlur_DEFINED - -#include "SkPaintPart.h" -#include "SkBlurMaskFilter.h" - -class SkDrawBlur : public SkDrawMaskFilter { - DECLARE_DRAW_MEMBER_INFO(Blur); - SkDrawBlur(); - SkMaskFilter* getMaskFilter() override; -protected: - SkScalar fSigma; - int /*SkBlurStyle*/ fBlurStyle; - - typedef SkDrawMaskFilter INHERITED; -}; - -#endif // SkDrawBlur_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawClip.cpp b/gfx/skia/skia/src/animator/SkDrawClip.cpp deleted file mode 100644 index bca816f6371b..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawClip.cpp +++ /dev/null @@ -1,39 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawClip.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkDrawRectangle.h" -#include "SkDrawPath.h" - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawClip::fInfo[] = { - SK_MEMBER(path, Path), - SK_MEMBER(rect, Rect) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawClip); - -SkDrawClip::SkDrawClip() : rect(nullptr), path(nullptr) { -} - -bool SkDrawClip::draw(SkAnimateMaker& maker ) { - if (rect != nullptr) - maker.fCanvas->clipRect(rect->fRect); - else { - SkASSERT(path != nullptr); - maker.fCanvas->clipPath(path->fPath); - } - return false; -} diff --git a/gfx/skia/skia/src/animator/SkDrawClip.h b/gfx/skia/skia/src/animator/SkDrawClip.h deleted file mode 100644 index 6c64f93f22a2..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawClip.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawClip_DEFINED -#define SkDrawClip_DEFINED - -#include "SkADrawable.h" -#include "SkMemberInfo.h" -#include "SkRegion.h" - -class SkDrawPath; -class SkDrawRect; - -class SkDrawClip : public SkADrawable { - DECLARE_DRAW_MEMBER_INFO(Clip); - SkDrawClip(); - bool draw(SkAnimateMaker& ) override; -private: - SkDrawRect* rect; - SkDrawPath* path; -}; - -#endif // SkDrawClip_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawColor.cpp b/gfx/skia/skia/src/animator/SkDrawColor.cpp deleted file mode 100644 index 529d9a5954c4..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawColor.cpp +++ /dev/null @@ -1,265 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawColor.h" -#ifdef SK_DEBUG -#include "SkDisplayList.h" -#endif -#include "SkDrawPaint.h" -#include "SkParse.h" -#include "SkScript.h" - -enum HSV_Choice { - kGetHue, - kGetSaturation, - kGetValue -}; - -static SkScalar RGB_to_HSV(SkColor color, HSV_Choice choice) { - SkScalar red = SkIntToScalar(SkColorGetR(color)); - SkScalar green = SkIntToScalar(SkColorGetG(color)); - SkScalar blue = SkIntToScalar(SkColorGetB(color)); - SkScalar min = SkMinScalar(SkMinScalar(red, green), blue); - SkScalar value = SkMaxScalar(SkMaxScalar(red, green), blue); - if (choice == kGetValue) - return value/255; - SkScalar delta = value - min; - SkScalar saturation = value == 0 ? 0 : delta / value; - if (choice == kGetSaturation) - return saturation; - SkScalar hue; - if (saturation == 0) - hue = 0; - else { - SkScalar part60 = 60 / delta; - if (red == value) { - hue = SkScalarMul(green - blue, part60); - if (hue < 0) - hue += 360 * SK_Scalar1; - } - else if (green == value) - hue = 120 * SK_Scalar1 + SkScalarMul(blue - red, part60); - else // blue == value - hue = 240 * SK_Scalar1 + SkScalarMul(red - green, part60); - } - SkASSERT(choice == kGetHue); - return hue; -} - -#if defined _WIN32 // disable 'red', etc. may be used without having been initialized -#pragma warning ( push ) -#pragma warning ( disable : 4701 ) -#endif - -static SkColor HSV_to_RGB(SkColor color, HSV_Choice choice, SkScalar hsv) { - SkScalar hue = choice == kGetHue ? hsv : RGB_to_HSV(color, kGetHue); - SkScalar saturation = choice == kGetSaturation ? hsv : RGB_to_HSV(color, kGetSaturation); - SkScalar value = choice == kGetValue ? hsv : RGB_to_HSV(color, kGetValue); - value *= 255; - SkScalar red SK_INIT_TO_AVOID_WARNING; - SkScalar green SK_INIT_TO_AVOID_WARNING; - SkScalar blue SK_INIT_TO_AVOID_WARNING; - if (saturation == 0) // color is on black-and-white center line - red = green = blue = value; - else { - //SkScalar fraction = SkScalarMod(hue, 60 * SK_Scalar1); - int sextant = SkScalarFloorToInt(hue / 60); - SkScalar fraction = hue / 60 - SkIntToScalar(sextant); - SkScalar p = SkScalarMul(value , SK_Scalar1 - saturation); - SkScalar q = SkScalarMul(value, SK_Scalar1 - SkScalarMul(saturation, fraction)); - SkScalar t = SkScalarMul(value, SK_Scalar1 - - SkScalarMul(saturation, SK_Scalar1 - fraction)); - switch (sextant % 6) { - case 0: red = value; green = t; blue = p; break; - case 1: red = q; green = value; blue = p; break; - case 2: red = p; green = value; blue = t; break; - case 3: red = p; green = q; blue = value; break; - case 4: red = t; green = p; blue = value; break; - case 5: red = value; green = p; blue = q; break; - } - } - //used to say SkToU8((U8CPU) red) etc - return SkColorSetARGB(SkColorGetA(color), SkScalarRoundToInt(red), - SkScalarRoundToInt(green), SkScalarRoundToInt(blue)); -} - -#if defined _WIN32 -#pragma warning ( pop ) -#endif - -enum SkDrawColor_Properties { - SK_PROPERTY(alpha), - SK_PROPERTY(blue), - SK_PROPERTY(green), - SK_PROPERTY(hue), - SK_PROPERTY(red), - SK_PROPERTY(saturation), - SK_PROPERTY(value) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawColor::fInfo[] = { - SK_MEMBER_PROPERTY(alpha, Float), - SK_MEMBER_PROPERTY(blue, Float), - SK_MEMBER(color, ARGB), - SK_MEMBER_PROPERTY(green, Float), - SK_MEMBER_PROPERTY(hue, Float), - SK_MEMBER_PROPERTY(red, Float), - SK_MEMBER_PROPERTY(saturation, Float), - SK_MEMBER_PROPERTY(value, Float), -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawColor); - -SkDrawColor::SkDrawColor() : fDirty(false) { - color = SK_ColorBLACK; - fHue = fSaturation = fValue = SK_ScalarNaN; -} - -bool SkDrawColor::add() { - if (fPaint->color != nullptr) - return true; // error (probably color in paint as attribute as well) - fPaint->color = this; - fPaint->fOwnsColor = true; - return false; -} - -SkDisplayable* SkDrawColor::deepCopy(SkAnimateMaker*) { - SkDrawColor* copy = new SkDrawColor(); - copy->color = color; - copy->fHue = fHue; - copy->fSaturation = fSaturation; - copy->fValue = fValue; - copy->fDirty = fDirty; - return copy; -} - -void SkDrawColor::dirty(){ - fDirty = true; -} - -#ifdef SK_DUMP_ENABLED -void SkDrawColor::dump(SkAnimateMaker* maker) { - dumpBase(maker); - SkDebugf("alpha=\"%d\" red=\"%d\" green=\"%d\" blue=\"%d\" />\n", - SkColorGetA(color)/255, SkColorGetR(color), - SkColorGetG(color), SkColorGetB(color)); -} -#endif - -SkColor SkDrawColor::getColor() { - if (fDirty) { - if (SkScalarIsNaN(fValue) == false) - color = HSV_to_RGB(color, kGetValue, fValue); - if (SkScalarIsNaN(fSaturation) == false) - color = HSV_to_RGB(color, kGetSaturation, fSaturation); - if (SkScalarIsNaN(fHue) == false) - color = HSV_to_RGB(color, kGetHue, fHue); - fDirty = false; - } - return color; -} - -SkDisplayable* SkDrawColor::getParent() const { - return fPaint; -} - -bool SkDrawColor::getProperty(int index, SkScriptValue* value) const { - value->fType = SkType_Float; - SkScalar result; - switch(index) { - case SK_PROPERTY(alpha): - result = SkIntToScalar(SkColorGetA(color)) / 255; - break; - case SK_PROPERTY(blue): - result = SkIntToScalar(SkColorGetB(color)); - break; - case SK_PROPERTY(green): - result = SkIntToScalar(SkColorGetG(color)); - break; - case SK_PROPERTY(hue): - result = RGB_to_HSV(color, kGetHue); - break; - case SK_PROPERTY(red): - result = SkIntToScalar(SkColorGetR(color)); - break; - case SK_PROPERTY(saturation): - result = RGB_to_HSV(color, kGetSaturation); - break; - case SK_PROPERTY(value): - result = RGB_to_HSV(color, kGetValue); - break; - default: - SkASSERT(0); - return false; - } - value->fOperand.fScalar = result; - return true; -} - -void SkDrawColor::onEndElement(SkAnimateMaker&) { - fDirty = true; -} - -bool SkDrawColor::setParent(SkDisplayable* parent) { - SkASSERT(parent != nullptr); - if (parent->getType() == SkType_DrawLinearGradient || parent->getType() == SkType_DrawRadialGradient) - return false; - if (parent->isPaint() == false) - return true; - fPaint = (SkDrawPaint*) parent; - return false; -} - -bool SkDrawColor::setProperty(int index, SkScriptValue& value) { - SkASSERT(value.fType == SkType_Float); - SkScalar scalar = value.fOperand.fScalar; - switch (index) { - case SK_PROPERTY(alpha): - uint8_t alpha; - alpha = scalar == SK_Scalar1 ? 255 : SkToU8((U8CPU) (scalar * 256)); - color = SkColorSetARGB(alpha, SkColorGetR(color), - SkColorGetG(color), SkColorGetB(color)); - break; - case SK_PROPERTY(blue): - scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1); - color = SkColorSetARGB(SkColorGetA(color), SkColorGetR(color), - SkColorGetG(color), SkToU8((U8CPU) scalar)); - break; - case SK_PROPERTY(green): - scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1); - color = SkColorSetARGB(SkColorGetA(color), SkColorGetR(color), - SkToU8((U8CPU) scalar), SkColorGetB(color)); - break; - case SK_PROPERTY(hue): - fHue = scalar;//RGB_to_HSV(color, kGetHue); - fDirty = true; - break; - case SK_PROPERTY(red): - scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1); - color = SkColorSetARGB(SkColorGetA(color), SkToU8((U8CPU) scalar), - SkColorGetG(color), SkColorGetB(color)); - break; - case SK_PROPERTY(saturation): - fSaturation = scalar;//RGB_to_HSV(color, kGetSaturation); - fDirty = true; - break; - case SK_PROPERTY(value): - fValue = scalar;//RGB_to_HSV(color, kGetValue); - fDirty = true; - break; - default: - SkASSERT(0); - return false; - } - return true; -} diff --git a/gfx/skia/skia/src/animator/SkDrawColor.h b/gfx/skia/skia/src/animator/SkDrawColor.h deleted file mode 100644 index 14788e45baa6..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawColor.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkDrawColor_DEFINED -#define SkDrawColor_DEFINED - -#include "SkPaintPart.h" -#include "SkColor.h" - -class SkDrawColor : public SkPaintPart { - DECLARE_DRAW_MEMBER_INFO(Color); - SkDrawColor(); - bool add() override; - void dirty() override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - SkColor getColor(); - SkDisplayable* deepCopy(SkAnimateMaker* ) override; - SkDisplayable* getParent() const override; - bool getProperty(int index, SkScriptValue* value) const override; - void onEndElement(SkAnimateMaker& ) override; - bool setParent(SkDisplayable* parent) override; - bool setProperty(int index, SkScriptValue&) override; -protected: - SkColor color; - SkScalar fHue; - SkScalar fSaturation; - SkScalar fValue; - SkBool fDirty; -private: - friend class SkDrawGradient; - typedef SkPaintPart INHERITED; -}; - -#endif // SkDrawColor_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawDash.cpp b/gfx/skia/skia/src/animator/SkDrawDash.cpp deleted file mode 100644 index e7fcc84107b0..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawDash.cpp +++ /dev/null @@ -1,35 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawDash.h" -#include "SkDashPathEffect.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDash::fInfo[] = { - SK_MEMBER_ARRAY(intervals, Float), - SK_MEMBER(phase, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDash); - -SkDash::SkDash() : phase(0) { -} - -SkDash::~SkDash() { -} - -SkPathEffect* SkDash::getPathEffect() { - int count = intervals.count(); - if (count == 0) - return nullptr; - return SkDashPathEffect::Make(intervals.begin(), count, phase).release(); -} diff --git a/gfx/skia/skia/src/animator/SkDrawDash.h b/gfx/skia/skia/src/animator/SkDrawDash.h deleted file mode 100644 index 3083fe8124d2..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawDash.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkDrawDash_DEFINED -#define SkDrawDash_DEFINED - -#include "SkPaintPart.h" -#include "SkIntArray.h" - -class SkDash : public SkDrawPathEffect { - DECLARE_MEMBER_INFO(Dash); - SkDash(); - virtual ~SkDash(); - SkPathEffect* getPathEffect() override; -private: - SkTDScalarArray intervals; - SkScalar phase; -}; - -#endif // SkDrawDash_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawDiscrete.cpp b/gfx/skia/skia/src/animator/SkDrawDiscrete.cpp deleted file mode 100644 index 11963a1d2f73..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawDiscrete.cpp +++ /dev/null @@ -1,34 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawDiscrete.h" -#include "SkAnimateMaker.h" -#include "SkPaint.h" -#include "SkDiscretePathEffect.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDiscrete::fInfo[] = { - SK_MEMBER(deviation, Float), - SK_MEMBER(segLength, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDiscrete); - -SkDiscrete::SkDiscrete() : deviation(0), segLength(0) { -} - -SkPathEffect* SkDiscrete::getPathEffect() { - if (deviation <= 0 || segLength <= 0) - return nullptr; - else - return SkDiscretePathEffect::Make(segLength, deviation).release(); -} diff --git a/gfx/skia/skia/src/animator/SkDrawDiscrete.h b/gfx/skia/skia/src/animator/SkDrawDiscrete.h deleted file mode 100644 index fe13f268b28e..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawDiscrete.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkDrawDiscrete_DEFINED -#define SkDrawDiscrete_DEFINED - -#include "SkPaintPart.h" - -class SkDiscrete : public SkDrawPathEffect { - DECLARE_MEMBER_INFO(Discrete); - SkDiscrete(); - SkPathEffect* getPathEffect() override; -private: - SkScalar deviation; - SkScalar segLength; -}; - -#endif //SkDrawDiscrete_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawEmboss.cpp b/gfx/skia/skia/src/animator/SkDrawEmboss.cpp deleted file mode 100644 index 9f50f2449ee7..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawEmboss.cpp +++ /dev/null @@ -1,34 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawEmboss.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawEmboss::fInfo[] = { - SK_MEMBER(fAmbient, Float), - SK_MEMBER_ARRAY(fDirection, Float), - SK_MEMBER(fSigma, Float), - SK_MEMBER(fSpecular, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawEmboss); - -SkDrawEmboss::SkDrawEmboss() : fSigma(-1) { - fDirection.setCount(3); -} - -SkMaskFilter* SkDrawEmboss::getMaskFilter() { - if (fSigma < 0 || fDirection.count() !=3) - return nullptr; - return SkBlurMaskFilter::MakeEmboss(fSigma, fDirection.begin(), - fAmbient, fSpecular).release(); -} diff --git a/gfx/skia/skia/src/animator/SkDrawEmboss.h b/gfx/skia/skia/src/animator/SkDrawEmboss.h deleted file mode 100644 index 941be61e20b3..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawEmboss.h +++ /dev/null @@ -1,28 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawEmboss_DEFINED -#define SkDrawEmboss_DEFINED - -#include "SkDrawBlur.h" - -class SkDrawEmboss : public SkDrawMaskFilter { - DECLARE_DRAW_MEMBER_INFO(Emboss); - SkDrawEmboss(); - SkMaskFilter* getMaskFilter() override; -protected: - SkTDScalarArray fDirection; - SkScalar fSigma; - SkScalar fAmbient; - SkScalar fSpecular; - - typedef SkDrawMaskFilter INHERITED; -}; - -#endif // SkDrawEmboss_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawExtraPathEffect.cpp b/gfx/skia/skia/src/animator/SkDrawExtraPathEffect.cpp deleted file mode 100644 index a444bc1cb334..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawExtraPathEffect.cpp +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkDrawExtraPathEffect.h" -#include "SkDrawPath.h" -#include "Sk1DPathEffect.h" -#include "Sk2DPathEffect.h" -#include "SkMemberInfo.h" -#include "SkPaintPart.h" -#include "SkPathEffect.h" -#include "SkCornerPathEffect.h" - -#include "SkDashPathEffect.h" - -class SkDrawShapePathEffect : public SkDrawPathEffect { - DECLARE_PRIVATE_MEMBER_INFO(DrawShapePathEffect); - SkDrawShapePathEffect(); - virtual ~SkDrawShapePathEffect(); - bool addChild(SkAnimateMaker& , SkDisplayable* ) override; - SkPathEffect* getPathEffect() override; -protected: - SkADrawable* addPath; - SkADrawable* addMatrix; - SkDrawPath* path; - SkPathEffect* fPathEffect; - friend class SkShape1DPathEffect; - friend class SkShape2DPathEffect; -}; - -class SkDrawShape1DPathEffect : public SkDrawShapePathEffect { - DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape1DPathEffect); - SkDrawShape1DPathEffect(SkDisplayTypes ); - virtual ~SkDrawShape1DPathEffect(); - void onEndElement(SkAnimateMaker& ) override; -private: - SkString phase; - SkString spacing; - friend class SkShape1DPathEffect; - typedef SkDrawShapePathEffect INHERITED; -}; - -class SkDrawShape2DPathEffect : public SkDrawShapePathEffect { - DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape2DPathEffect); - SkDrawShape2DPathEffect(SkDisplayTypes ); - virtual ~SkDrawShape2DPathEffect(); - void onEndElement(SkAnimateMaker& ) override; -private: - SkDrawMatrix* matrix; - friend class SkShape2DPathEffect; - typedef SkDrawShapePathEffect INHERITED; -}; - -class SkDrawComposePathEffect : public SkDrawPathEffect { - DECLARE_EXTRAS_MEMBER_INFO(SkDrawComposePathEffect); - SkDrawComposePathEffect(SkDisplayTypes ); - virtual ~SkDrawComposePathEffect(); - bool addChild(SkAnimateMaker& , SkDisplayable* ) override; - SkPathEffect* getPathEffect() override; - bool isPaint() const override; -private: - SkDrawPathEffect* effect1; - SkDrawPathEffect* effect2; -}; - -class SkDrawCornerPathEffect : public SkDrawPathEffect { - DECLARE_EXTRAS_MEMBER_INFO(SkDrawCornerPathEffect); - SkDrawCornerPathEffect(SkDisplayTypes ); - virtual ~SkDrawCornerPathEffect(); - SkPathEffect* getPathEffect() override; -private: - SkScalar radius; -}; - -//////////// SkShape1DPathEffect - -#include "SkAnimateMaker.h" -#include "SkAnimatorScript.h" -#include "SkDisplayApply.h" -#include "SkDrawMatrix.h" -#include "SkPaint.h" - -class SkShape1DPathEffect : public Sk1DPathEffect { -public: - SkShape1DPathEffect(SkDrawShape1DPathEffect* draw, SkAnimateMaker* maker) : - fDraw(draw), fMaker(maker) { - } - - // For serialization. This will never be called. - Factory getFactory() const override { sk_throw(); return nullptr; } - -protected: - SkScalar begin(SkScalar contourLength) const override { - SkScriptValue value; - SkAnimatorScript engine(*fMaker, nullptr, SkType_Float); - engine.propertyCallBack(GetContourLength, &contourLength); - value.fOperand.fScalar = 0; - engine.evaluate(fDraw->phase.c_str(), &value, SkType_Float); - return value.fOperand.fScalar; - } - - SkScalar next(SkPath* dst, SkScalar distance, SkPathMeasure&) const override { - fMaker->setExtraPropertyCallBack(fDraw->fType, GetDistance, &distance); - SkDrawPath* drawPath = nullptr; - if (fDraw->addPath->isPath()) { - drawPath = (SkDrawPath*) fDraw->addPath; - } else { - SkApply* apply = (SkApply*) fDraw->addPath; - apply->refresh(*fMaker); - apply->activate(*fMaker); - apply->interpolate(*fMaker, SkScalarRoundToInt(distance * 1000)); - drawPath = (SkDrawPath*) apply->getScope(); - } - SkMatrix m; - m.reset(); - if (fDraw->addMatrix) { - SkDrawMatrix* matrix; - if (fDraw->addMatrix->getType() == SkType_Matrix) - matrix = (SkDrawMatrix*) fDraw->addMatrix; - else { - SkApply* apply = (SkApply*) fDraw->addMatrix; - apply->refresh(*fMaker); - apply->activate(*fMaker); - apply->interpolate(*fMaker, SkScalarRoundToInt(distance * 1000)); - matrix = (SkDrawMatrix*) apply->getScope(); - } - if (matrix) { - m = matrix->getMatrix(); - } - } - SkScalar result = 0; - SkAnimatorScript::EvaluateFloat(*fMaker, nullptr, fDraw->spacing.c_str(), &result); - if (drawPath) - dst->addPath(drawPath->getPath(), m); - fMaker->clearExtraPropertyCallBack(fDraw->fType); - return result; - } - -#ifndef SK_IGNORE_TO_STRING - void toString(SkString* str) const override { - str->appendf("SkShape1DPathEffect: ("); - // TODO: fill in - str->appendf(")"); - } -#endif - -private: - static bool GetContourLength(const char* token, size_t len, void* clen, SkScriptValue* value) { - if (SK_LITERAL_STR_EQUAL("contourLength", token, len)) { - value->fOperand.fScalar = *(SkScalar*) clen; - value->fType = SkType_Float; - return true; - } - return false; - } - - static bool GetDistance(const char* token, size_t len, void* dist, SkScriptValue* value) { - if (SK_LITERAL_STR_EQUAL("distance", token, len)) { - value->fOperand.fScalar = *(SkScalar*) dist; - value->fType = SkType_Float; - return true; - } - return false; - } - - SkDrawShape1DPathEffect* fDraw; - SkAnimateMaker* fMaker; -}; - -//////////// SkDrawShapePathEffect - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawShapePathEffect::fInfo[] = { - SK_MEMBER(addMatrix, Drawable), // either matrix or apply - SK_MEMBER(addPath, Drawable), // either path or apply - SK_MEMBER(path, Path), -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawShapePathEffect); - -SkDrawShapePathEffect::SkDrawShapePathEffect() : - addPath(nullptr), addMatrix(nullptr), path(nullptr), fPathEffect(nullptr) { -} - -SkDrawShapePathEffect::~SkDrawShapePathEffect() { - SkSafeUnref(fPathEffect); -} - -bool SkDrawShapePathEffect::addChild(SkAnimateMaker& , SkDisplayable* child) { - path = (SkDrawPath*) child; - return true; -} - -SkPathEffect* SkDrawShapePathEffect::getPathEffect() { - fPathEffect->ref(); - return fPathEffect; -} - -//////////// SkDrawShape1DPathEffect - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawShape1DPathEffect::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER(phase, String), - SK_MEMBER(spacing, String), -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawShape1DPathEffect); - -SkDrawShape1DPathEffect::SkDrawShape1DPathEffect(SkDisplayTypes type) : fType(type) { -} - -SkDrawShape1DPathEffect::~SkDrawShape1DPathEffect() { -} - -void SkDrawShape1DPathEffect::onEndElement(SkAnimateMaker& maker) { - if (addPath == nullptr || (addPath->isPath() == false && addPath->isApply() == false)) - maker.setErrorCode(SkDisplayXMLParserError::kUnknownError); // !!! add error - else - fPathEffect = new SkShape1DPathEffect(this, &maker); -} - -////////// SkShape2DPathEffect - -class SkShape2DPathEffect : public Sk2DPathEffect { -public: - SkShape2DPathEffect(SkDrawShape2DPathEffect* draw, SkAnimateMaker* maker, - const SkMatrix& matrix) : Sk2DPathEffect(matrix), fDraw(draw), fMaker(maker) { - } - - // For serialization. This will never be called. - Factory getFactory() const override { sk_throw(); return nullptr; } - -protected: - void begin(const SkIRect& uvBounds, SkPath*) const override { - const_cast(this)->setUVBounds(uvBounds); - } - - void next(const SkPoint& loc, int u, int v, SkPath* dst) const override { - const_cast(this)->addPath(loc, u, v, dst); - } - -private: - void setUVBounds(const SkIRect& uvBounds) { - fUVBounds.set(SkIntToScalar(uvBounds.fLeft), SkIntToScalar(uvBounds.fTop), - SkIntToScalar(uvBounds.fRight), SkIntToScalar(uvBounds.fBottom)); - } - - void addPath(const SkPoint& loc, int u, int v, SkPath* dst) { - fLoc = loc; - fU = u; - fV = v; - SkDrawPath* drawPath; - fMaker->setExtraPropertyCallBack(fDraw->fType, Get2D, this); - if (fDraw->addPath->isPath()) { - drawPath = (SkDrawPath*) fDraw->addPath; - } else { - SkApply* apply = (SkApply*) fDraw->addPath; - apply->refresh(*fMaker); - apply->activate(*fMaker); - apply->interpolate(*fMaker, v); - drawPath = (SkDrawPath*) apply->getScope(); - } - if (drawPath == nullptr) - goto clearCallBack; - if (fDraw->matrix) { - SkDrawMatrix* matrix; - if (fDraw->matrix->getType() == SkType_Matrix) - matrix = (SkDrawMatrix*) fDraw->matrix; - else { - SkApply* apply = (SkApply*) fDraw->matrix; - apply->activate(*fMaker); - apply->interpolate(*fMaker, v); - matrix = (SkDrawMatrix*) apply->getScope(); - } - if (matrix) { - dst->addPath(drawPath->getPath(), matrix->getMatrix()); - goto clearCallBack; - } - } - dst->addPath(drawPath->getPath()); -clearCallBack: - fMaker->clearExtraPropertyCallBack(fDraw->fType); - } - - static bool Get2D(const char* token, size_t len, void* s2D, SkScriptValue* value) { - static const char match[] = "locX|locY|left|top|right|bottom|u|v" ; - SkShape2DPathEffect* shape2D = (SkShape2DPathEffect*) s2D; - int index; - if (SkAnimatorScript::MapEnums(match, token, len, &index) == false) - return false; - SkASSERT((sizeof(SkPoint) + sizeof(SkRect)) / sizeof(SkScalar) == 6); - if (index < 6) { - value->fType = SkType_Float; - value->fOperand.fScalar = (&shape2D->fLoc.fX)[index]; - } else { - value->fType = SkType_Int; - value->fOperand.fS32 = (&shape2D->fU)[index - 6]; - } - return true; - } - - SkPoint fLoc; - SkRect fUVBounds; - int32_t fU; - int32_t fV; - SkDrawShape2DPathEffect* fDraw; - SkAnimateMaker* fMaker; - - // illegal - SkShape2DPathEffect(const SkShape2DPathEffect&); - SkShape2DPathEffect& operator=(const SkShape2DPathEffect&); -}; - -////////// SkDrawShape2DPathEffect - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawShape2DPathEffect::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER(matrix, Matrix) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawShape2DPathEffect); - -SkDrawShape2DPathEffect::SkDrawShape2DPathEffect(SkDisplayTypes type) : fType(type) { -} - -SkDrawShape2DPathEffect::~SkDrawShape2DPathEffect() { -} - -void SkDrawShape2DPathEffect::onEndElement(SkAnimateMaker& maker) { - if (addPath == nullptr || (addPath->isPath() == false && addPath->isApply() == false) || - matrix == nullptr) - maker.setErrorCode(SkDisplayXMLParserError::kUnknownError); // !!! add error - else - fPathEffect = new SkShape2DPathEffect(this, &maker, matrix->getMatrix()); -} - -////////// SkDrawComposePathEffect - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawComposePathEffect::fInfo[] = { - SK_MEMBER(effect1, PathEffect), - SK_MEMBER(effect2, PathEffect) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawComposePathEffect); - -SkDrawComposePathEffect::SkDrawComposePathEffect(SkDisplayTypes type) : fType(type), - effect1(nullptr), effect2(nullptr) { -} - -SkDrawComposePathEffect::~SkDrawComposePathEffect() { - delete effect1; - delete effect2; -} - -bool SkDrawComposePathEffect::addChild(SkAnimateMaker& , SkDisplayable* child) { - if (effect1 == nullptr) - effect1 = (SkDrawPathEffect*) child; - else - effect2 = (SkDrawPathEffect*) child; - return true; -} - -SkPathEffect* SkDrawComposePathEffect::getPathEffect() { - auto e1 = sk_sp(effect1->getPathEffect()); - auto e2 = sk_sp(effect2->getPathEffect()); - return SkComposePathEffect::Make(e1, e2).release(); -} - -bool SkDrawComposePathEffect::isPaint() const { - return true; -} - -//////////// SkDrawCornerPathEffect - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawCornerPathEffect::fInfo[] = { - SK_MEMBER(radius, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawCornerPathEffect); - -SkDrawCornerPathEffect::SkDrawCornerPathEffect(SkDisplayTypes type): - fType(type), radius(0) { -} - -SkDrawCornerPathEffect::~SkDrawCornerPathEffect() { -} - -SkPathEffect* SkDrawCornerPathEffect::getPathEffect() { - return SkCornerPathEffect::Make(radius).release(); -} - -///////// - -#include "SkExtras.h" - -const char kDrawShape1DPathEffectName[] = "pathEffect:shape1D"; -const char kDrawShape2DPathEffectName[] = "pathEffect:shape2D"; -const char kDrawComposePathEffectName[] = "pathEffect:compose"; -const char kDrawCornerPathEffectName[] = "pathEffect:corner"; - -class SkExtraPathEffects : public SkExtras { -public: - SkExtraPathEffects() : - skDrawShape1DPathEffectType(SkType_Unknown), - skDrawShape2DPathEffectType(SkType_Unknown), - skDrawComposePathEffectType(SkType_Unknown), - skDrawCornerPathEffectType(SkType_Unknown) { - } - - virtual SkDisplayable* createInstance(SkDisplayTypes type) { - SkDisplayable* result = nullptr; - if (skDrawShape1DPathEffectType == type) - result = new SkDrawShape1DPathEffect(type); - else if (skDrawShape2DPathEffectType == type) - result = new SkDrawShape2DPathEffect(type); - else if (skDrawComposePathEffectType == type) - result = new SkDrawComposePathEffect(type); - else if (skDrawCornerPathEffectType == type) - result = new SkDrawCornerPathEffect(type); - return result; - } - - virtual bool definesType(SkDisplayTypes type) { - return type == skDrawShape1DPathEffectType || - type == skDrawShape2DPathEffectType || - type == skDrawComposePathEffectType || - type == skDrawCornerPathEffectType; - } - -#if SK_USE_CONDENSED_INFO == 0 - virtual const SkMemberInfo* getMembers(SkDisplayTypes type, int* infoCountPtr) { - const SkMemberInfo* info = nullptr; - int infoCount = 0; - if (skDrawShape1DPathEffectType == type) { - info = SkDrawShape1DPathEffect::fInfo; - infoCount = SkDrawShape1DPathEffect::fInfoCount; - } else if (skDrawShape2DPathEffectType == type) { - info = SkDrawShape2DPathEffect::fInfo; - infoCount = SkDrawShape2DPathEffect::fInfoCount; - } else if (skDrawComposePathEffectType == type) { - info = SkDrawComposePathEffect::fInfo; - infoCount = SkDrawShape1DPathEffect::fInfoCount; - } else if (skDrawCornerPathEffectType == type) { - info = SkDrawCornerPathEffect::fInfo; - infoCount = SkDrawCornerPathEffect::fInfoCount; - } - if (infoCountPtr) - *infoCountPtr = infoCount; - return info; - } -#endif - -#ifdef SK_DEBUG - virtual const char* getName(SkDisplayTypes type) { - if (skDrawShape1DPathEffectType == type) - return kDrawShape1DPathEffectName; - else if (skDrawShape2DPathEffectType == type) - return kDrawShape2DPathEffectName; - else if (skDrawComposePathEffectType == type) - return kDrawComposePathEffectName; - else if (skDrawCornerPathEffectType == type) - return kDrawCornerPathEffectName; - return nullptr; - } -#endif - - virtual SkDisplayTypes getType(const char name[], size_t len ) { - SkDisplayTypes* type = nullptr; - if (SK_LITERAL_STR_EQUAL(kDrawShape1DPathEffectName, name, len)) - type = &skDrawShape1DPathEffectType; - else if (SK_LITERAL_STR_EQUAL(kDrawShape2DPathEffectName, name, len)) - type = &skDrawShape2DPathEffectType; - else if (SK_LITERAL_STR_EQUAL(kDrawComposePathEffectName, name, len)) - type = &skDrawComposePathEffectType; - else if (SK_LITERAL_STR_EQUAL(kDrawCornerPathEffectName, name, len)) - type = &skDrawCornerPathEffectType; - if (type) { - if (*type == SkType_Unknown) - *type = SkDisplayType::RegisterNewType(); - return *type; - } - return SkType_Unknown; - } - -private: - SkDisplayTypes skDrawShape1DPathEffectType; - SkDisplayTypes skDrawShape2DPathEffectType; - SkDisplayTypes skDrawComposePathEffectType; - SkDisplayTypes skDrawCornerPathEffectType; -}; - -void InitializeSkExtraPathEffects(SkAnimator* animator) { - animator->addExtras(new SkExtraPathEffects()); -} - -//////////////// - - -SkExtras::SkExtras() : fExtraCallBack(nullptr), fExtraStorage(nullptr) { -} diff --git a/gfx/skia/skia/src/animator/SkDrawExtraPathEffect.h b/gfx/skia/skia/src/animator/SkDrawExtraPathEffect.h deleted file mode 100644 index 392a46b8c3fa..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawExtraPathEffect.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2008 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SK_DRAW_EXTRA_PATH_EFFECT_H -#define SK_DRAW_EXTRA_PATH_EFFECT_H - -class SkAnimator; - -void InitializeSkExtraPathEffects(SkAnimator* animator); - -#endif diff --git a/gfx/skia/skia/src/animator/SkDrawFull.cpp b/gfx/skia/skia/src/animator/SkDrawFull.cpp deleted file mode 100644 index a1a5fc9f16fd..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawFull.cpp +++ /dev/null @@ -1,18 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawFull.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" - -bool SkFull::draw(SkAnimateMaker& maker) { - SkBoundableAuto boundable(this, maker); - maker.fCanvas->drawPaint(*maker.fPaint); - return false; -} diff --git a/gfx/skia/skia/src/animator/SkDrawFull.h b/gfx/skia/skia/src/animator/SkDrawFull.h deleted file mode 100644 index 8a79c4dbae23..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawFull.h +++ /dev/null @@ -1,22 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawFull_DEFINED -#define SkDrawFull_DEFINED - -#include "SkBoundable.h" - -class SkFull : public SkBoundable { - DECLARE_EMPTY_MEMBER_INFO(Full); - bool draw(SkAnimateMaker& ) override; -private: - typedef SkBoundable INHERITED; -}; - -#endif // SkDrawFull_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawGradient.cpp b/gfx/skia/skia/src/animator/SkDrawGradient.cpp deleted file mode 100644 index 2fa4502f6bc9..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawGradient.cpp +++ /dev/null @@ -1,168 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawGradient.h" -#include "SkAnimateMaker.h" -#include "SkAnimatorScript.h" -#include "SkGradientShader.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawGradient::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER_ARRAY(offsets, Float), - SK_MEMBER(unitMapper, String) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawGradient); - -SkDrawGradient::SkDrawGradient() { -} - -SkDrawGradient::~SkDrawGradient() { - for (int index = 0; index < fDrawColors.count(); index++) - delete fDrawColors[index]; -} - -bool SkDrawGradient::addChild(SkAnimateMaker& , SkDisplayable* child) { - SkASSERT(child); - if (child->isColor()) { - SkDrawColor* color = (SkDrawColor*) child; - *fDrawColors.append() = color; - return true; - } - return false; -} - -int SkDrawGradient::addPrelude() { - int count = fDrawColors.count(); - fColors.setCount(count); - for (int index = 0; index < count; index++) - fColors[index] = fDrawColors[index]->color; - return count; -} - -#ifdef SK_DUMP_ENABLED -void SkDrawGradient::dumpRest(SkAnimateMaker* maker) { - dumpAttrs(maker); - //can a gradient have no colors? - bool closedYet = false; - SkDisplayList::fIndent += 4; - for (SkDrawColor** ptr = fDrawColors.begin(); ptr < fDrawColors.end(); ptr++) { - if (closedYet == false) { - SkDebugf(">\n"); - closedYet = true; - } - SkDrawColor* color = *ptr; - color->dump(maker); - } - SkDisplayList::fIndent -= 4; - dumpChildren(maker, closedYet); //dumps the matrix if it has one -} -#endif - -void SkDrawGradient::onEndElement(SkAnimateMaker& maker) { - if (offsets.count() != 0) { - if (offsets.count() != fDrawColors.count()) { - maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsDontMatchColors); - return; - } - if (offsets[0] != 0) { - maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustStartWithZero); - return; - } - if (offsets[offsets.count()-1] != SK_Scalar1) { - maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustEndWithOne); - return; - } - for (int i = 1; i < offsets.count(); i++) { - if (offsets[i] <= offsets[i-1]) { - maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustIncrease); - return; - } - if (offsets[i] > SK_Scalar1) { - maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustBeNoMoreThanOne); - return; - } - } - } - INHERITED::onEndElement(maker); -} - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawLinearGradient::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER_ARRAY(points, Float), -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawLinearGradient); - -SkDrawLinearGradient::SkDrawLinearGradient() { -} - -void SkDrawLinearGradient::onEndElement(SkAnimateMaker& maker) -{ - if (points.count() != 4) - maker.setErrorCode(SkDisplayXMLParserError::kGradientPointsLengthMustBeFour); - INHERITED::onEndElement(maker); -} - -#ifdef SK_DUMP_ENABLED -void SkDrawLinearGradient::dump(SkAnimateMaker* maker) { - dumpBase(maker); - dumpRest(maker); - } -#endif - -SkShader* SkDrawLinearGradient::getShader() { - if (addPrelude() == 0 || points.count() != 4) { - return nullptr; - } - return SkGradientShader::MakeLinear((SkPoint*)points.begin(), - fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, - 0, getMatrix()).release(); -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawRadialGradient::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER(center, Point), - SK_MEMBER(radius, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawRadialGradient); - -SkDrawRadialGradient::SkDrawRadialGradient() : radius(0) { - center.set(0, 0); -} - -#ifdef SK_DUMP_ENABLED -void SkDrawRadialGradient::dump(SkAnimateMaker* maker) { - dumpBase(maker); - dumpRest(maker); -} -#endif - -SkShader* SkDrawRadialGradient::getShader() { - if (addPrelude() == 0) { - return nullptr; - } - return SkGradientShader::MakeRadial(center, - radius, fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, - 0, getMatrix()).release(); -} diff --git a/gfx/skia/skia/src/animator/SkDrawGradient.h b/gfx/skia/skia/src/animator/SkDrawGradient.h deleted file mode 100644 index 87df37624c83..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawGradient.h +++ /dev/null @@ -1,64 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawGradient_DEFINED -#define SkDrawGradient_DEFINED - -#include "SkDrawColor.h" -#include "SkDrawShader.h" -#include "SkIntArray.h" - -class SkDrawGradient : public SkDrawShader { - DECLARE_PRIVATE_MEMBER_INFO(DrawGradient); - SkDrawGradient(); - virtual ~SkDrawGradient(); - bool addChild(SkAnimateMaker& , SkDisplayable* child) override; -#ifdef SK_DUMP_ENABLED - virtual void dumpRest(SkAnimateMaker*); -#endif - void onEndElement(SkAnimateMaker& ) override; -protected: - SkTDScalarArray offsets; - SkString unitMapper; - SkTDColorArray fColors; - SkTDDrawColorArray fDrawColors; - int addPrelude(); -private: - typedef SkDrawShader INHERITED; -}; - -class SkDrawLinearGradient : public SkDrawGradient { - DECLARE_MEMBER_INFO(DrawLinearGradient); - SkDrawLinearGradient(); - void onEndElement(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker*) override; -#endif - SkShader* getShader() override; -protected: - SkTDScalarArray points; -private: - typedef SkDrawGradient INHERITED; -}; - -class SkDrawRadialGradient : public SkDrawGradient { - DECLARE_MEMBER_INFO(DrawRadialGradient); - SkDrawRadialGradient(); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker*) override; -#endif - SkShader* getShader() override; -protected: - SkPoint center; - SkScalar radius; -private: - typedef SkDrawGradient INHERITED; -}; - -#endif // SkDrawGradient_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawGroup.cpp b/gfx/skia/skia/src/animator/SkDrawGroup.cpp deleted file mode 100644 index 76807bf5913a..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawGroup.cpp +++ /dev/null @@ -1,321 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawGroup.h" -#include "SkAnimateMaker.h" -#include "SkAnimatorScript.h" -#include "SkCanvas.h" -#include "SkDisplayApply.h" -#include "SkPaint.h" -#ifdef SK_DEBUG -#include "SkDisplayList.h" -#endif - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkGroup::fInfo[] = { - SK_MEMBER(condition, String), - SK_MEMBER(enableCondition, String) -}; - -#endif - -DEFINE_GET_MEMBER(SkGroup); - -SkGroup::SkGroup() : fParentList(nullptr), fOriginal(nullptr) { -} - -SkGroup::~SkGroup() { - if (fOriginal) // has been copied - return; - int index = 0; - int max = fCopies.count() << 5; - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - if (index >= max || markedForDelete(index)) - delete *ptr; -// else { -// SkApply* apply = (SkApply*) *ptr; -// SkASSERT(apply->isApply()); -// SkASSERT(apply->getScope()); -// delete apply->getScope(); -// } - index++; - } -} - -bool SkGroup::addChild(SkAnimateMaker& , SkDisplayable* child) { - SkASSERT(child); -// SkASSERT(child->isDrawable()); - *fChildren.append() = (SkADrawable*) child; - if (child->isGroup()) { - SkGroup* groupie = (SkGroup*) child; - SkASSERT(groupie->fParentList == nullptr); - groupie->fParentList = &fChildren; - } - return true; -} - -bool SkGroup::contains(SkDisplayable* match) { - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - SkADrawable* drawable = *ptr; - if (drawable == match || drawable->contains(match)) - return true; - } - return false; -} - -SkGroup* SkGroup::copy() { - SkGroup* result = new SkGroup(); - result->fOriginal = this; - result->fChildren = fChildren; - return result; -} - -SkBool SkGroup::copySet(int index) { - return (fCopies[index >> 5] & 1 << (index & 0x1f)) != 0; -} - -SkDisplayable* SkGroup::deepCopy(SkAnimateMaker* maker) { - SkDisplayable* copy = INHERITED::deepCopy(maker); - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - SkDisplayable* displayable = (SkDisplayable*)*ptr; - SkDisplayable* deeperCopy = displayable->deepCopy(maker); - ((SkGroup*)copy)->addChild(*maker, deeperCopy); - } - return copy; -} - -bool SkGroup::doEvent(SkDisplayEvent::Kind kind, SkEventState* state) { - bool handled = false; - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - SkADrawable* drawable = *ptr; - if (drawable->isDrawable() == false) - continue; - handled |= drawable->doEvent(kind, state); - } - return handled; -} - -bool SkGroup::draw(SkAnimateMaker& maker) { - bool conditionTrue = ifCondition(maker, this, condition); - bool result = false; - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - SkADrawable* drawable = *ptr; - if (drawable->isDrawable() == false) - continue; - if (conditionTrue == false) { - if (drawable->isApply()) - ((SkApply*) drawable)->disable(); - continue; - } - maker.validate(); - result |= drawable->draw(maker); - maker.validate(); - } - return result; -} - -#ifdef SK_DUMP_ENABLED -void SkGroup::dump(SkAnimateMaker* maker) { - dumpBase(maker); - if (condition.size() > 0) - SkDebugf("condition=\"%s\" ", condition.c_str()); - if (enableCondition.size() > 0) - SkDebugf("enableCondition=\"%s\" ", enableCondition.c_str()); - dumpDrawables(maker); -} - -void SkGroup::dumpDrawables(SkAnimateMaker* maker) { - SkDisplayList::fIndent += 4; - int save = SkDisplayList::fDumpIndex; - SkDisplayList::fDumpIndex = 0; - bool closedYet = false; - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - if (closedYet == false) { - closedYet = true; - SkDebugf(">\n"); - } - SkADrawable* drawable = *ptr; - drawable->dump(maker); - SkDisplayList::fDumpIndex++; - } - SkDisplayList::fIndent -= 4; - SkDisplayList::fDumpIndex = save; - if (closedYet) //we had children, now it's time to close the group - dumpEnd(maker); - else //no children - SkDebugf("/>\n"); -} - -void SkGroup::dumpEvents() { - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - SkADrawable* drawable = *ptr; - drawable->dumpEvents(); - } -} -#endif - -bool SkGroup::enable(SkAnimateMaker& maker ) { - reset(); - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - SkADrawable* drawable = *ptr; - if (ifCondition(maker, drawable, enableCondition) == false) - continue; - drawable->enable(maker); - } - return true; // skip add; already added so that scope is findable by children -} - -int SkGroup::findGroup(SkADrawable* match, SkTDDrawableArray** list, - SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList) { - *list = &fChildren; - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - SkADrawable* drawable = *ptr; - if (drawable->isGroup()) { - SkGroup* childGroup = (SkGroup*) drawable; - if (childGroup->fOriginal == match) - goto foundMatch; - } - if (drawable == match) { -foundMatch: - *parent = this; - return (int) (ptr - fChildren.begin()); - } - } - *grandList = &fChildren; - return SkDisplayList::SearchForMatch(match, list, parent, found, grandList); -} - -bool SkGroup::hasEnable() const { - return true; -} - -bool SkGroup::ifCondition(SkAnimateMaker& maker, SkADrawable*, - SkString& conditionString) { - if (conditionString.size() == 0) - return true; - int32_t result; - bool success = SkAnimatorScript::EvaluateInt(maker, this, conditionString.c_str(), &result); -#ifdef SK_DUMP_ENABLED - if (maker.fDumpGConditions) { - SkDebugf("group: "); - dumpBase(&maker); - SkDebugf("condition=%s ", conditionString.c_str()); - if (success == false) - SkDebugf("(script failed)\n"); - else - SkDebugf("success=%s\n", result != 0 ? "true" : "false"); - } -#endif - return success && result != 0; -} - -void SkGroup::initialize() { - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - SkADrawable* drawable = *ptr; - if (drawable->isDrawable() == false) - continue; - drawable->initialize(); - } -} - -void SkGroup::markCopyClear(int index) { - if (index < 0) - index = fChildren.count(); - fCopies[index >> 5] &= ~(1 << (index & 0x1f)); -} - -void SkGroup::markCopySet(int index) { - if (index < 0) - index = fChildren.count(); - fCopies[index >> 5] |= 1 << (index & 0x1f); -} - -void SkGroup::markCopySize(int index) { - if (index < 0) - index = fChildren.count() + 1; - int oldLongs = fCopies.count(); - int newLongs = (index >> 5) + 1; - if (oldLongs < newLongs) { - fCopies.setCount(newLongs); - memset(&fCopies[oldLongs], 0, (newLongs - oldLongs) << 2); - } -} - -void SkGroup::reset() { - if (fOriginal) // has been copied - return; - int index = 0; - int max = fCopies.count() << 5; - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - if (index >= max || copySet(index) == false) - continue; - SkApply* apply = (SkApply*) *ptr; - SkASSERT(apply->isApply()); - SkASSERT(apply->getScope()); - *ptr = apply->getScope(); - markCopyClear(index); - index++; - } -} - -bool SkGroup::resolveIDs(SkAnimateMaker& maker, SkDisplayable* orig, SkApply* apply) { - SkGroup* original = (SkGroup*) orig; - SkTDDrawableArray& originalChildren = original->fChildren; - SkADrawable** originalPtr = originalChildren.begin(); - SkADrawable** ptr = fChildren.begin(); - SkADrawable** end = fChildren.end(); - SkADrawable** origChild = ((SkGroup*) orig)->fChildren.begin(); - while (ptr < end) { - SkADrawable* drawable = *ptr++; - maker.resolveID(drawable, *origChild++); - if (drawable->resolveIDs(maker, *originalPtr++, apply) == true) - return true; // failed - } - return false; -} - -void SkGroup::setSteps(int steps) { - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - SkADrawable* drawable = *ptr; - if (drawable->isDrawable() == false) - continue; - drawable->setSteps(steps); - } -} - -#ifdef SK_DEBUG -void SkGroup::validate() { - for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { - SkADrawable* drawable = *ptr; - drawable->validate(); - } -} -#endif - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkSave::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkSave); - -bool SkSave::draw(SkAnimateMaker& maker) { - maker.fCanvas->save(); - SkPaint* save = maker.fPaint; - SkPaint local = SkPaint(*maker.fPaint); - maker.fPaint = &local; - bool result = INHERITED::draw(maker); - maker.fPaint = save; - maker.fCanvas->restore(); - return result; -} diff --git a/gfx/skia/skia/src/animator/SkDrawGroup.h b/gfx/skia/skia/src/animator/SkDrawGroup.h deleted file mode 100644 index f1b7bb6e28c4..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawGroup.h +++ /dev/null @@ -1,72 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawGroup_DEFINED -#define SkDrawGroup_DEFINED - -#include "SkADrawable.h" -#include "SkIntArray.h" -#include "SkMemberInfo.h" - -class SkGroup : public SkADrawable { //interface for schema element -public: - DECLARE_MEMBER_INFO(Group); - SkGroup(); - virtual ~SkGroup(); - bool addChild(SkAnimateMaker& , SkDisplayable* child) override; - bool contains(SkDisplayable* ) override; - SkGroup* copy(); - SkBool copySet(int index); - SkDisplayable* deepCopy(SkAnimateMaker* ) override; - bool doEvent(SkDisplayEvent::Kind , SkEventState* state ) override; - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; - virtual void dumpDrawables(SkAnimateMaker* ); - void dumpEvents() override; -#endif - int findGroup(SkADrawable* drawable, SkTDDrawableArray** list, - SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList); - bool enable(SkAnimateMaker& ) override; - SkTDDrawableArray* getChildren() { return &fChildren; } - SkGroup* getOriginal() { return fOriginal; } - bool hasEnable() const override; - void initialize() override; - SkBool isACopy() { return fOriginal != nullptr; } - void markCopyClear(int index); - void markCopySet(int index); - void markCopySize(int index); - bool markedForDelete(int index) const { return (fCopies[index >> 5] & 1 << (index & 0x1f)) == 0; } - void reset(); - bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* ) override; - void setSteps(int steps) override; -#ifdef SK_DEBUG - void validate() override; -#endif -protected: - bool ifCondition(SkAnimateMaker& maker, SkADrawable* drawable, - SkString& conditionString); - SkString condition; - SkString enableCondition; - SkTDDrawableArray fChildren; - SkTDDrawableArray* fParentList; - SkTDIntArray fCopies; - SkGroup* fOriginal; -private: - typedef SkADrawable INHERITED; -}; - -class SkSave: public SkGroup { - DECLARE_MEMBER_INFO(Save); - bool draw(SkAnimateMaker& ) override; -private: - typedef SkGroup INHERITED; -}; - -#endif // SkDrawGroup_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawLine.cpp b/gfx/skia/skia/src/animator/SkDrawLine.cpp deleted file mode 100644 index d0ae7d92973c..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawLine.cpp +++ /dev/null @@ -1,35 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawLine.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkPaint.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkLine::fInfo[] = { - SK_MEMBER(x1, Float), - SK_MEMBER(x2, Float), - SK_MEMBER(y1, Float), - SK_MEMBER(y2, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkLine); - -SkLine::SkLine() : x1(0), x2(0), y1(0), y2(0) { -} - -bool SkLine::draw(SkAnimateMaker& maker) { - SkBoundableAuto boundable(this, maker); - maker.fCanvas->drawLine(x1, y1, x2, y2, *maker.fPaint); - return false; -} diff --git a/gfx/skia/skia/src/animator/SkDrawLine.h b/gfx/skia/skia/src/animator/SkDrawLine.h deleted file mode 100644 index 996964a89a4f..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawLine.h +++ /dev/null @@ -1,28 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawLine_DEFINED -#define SkDrawLine_DEFINED - -#include "SkBoundable.h" -#include "SkMemberInfo.h" - -class SkLine : public SkBoundable { - DECLARE_MEMBER_INFO(Line); - SkLine(); - bool draw(SkAnimateMaker& ) override; -private: - SkScalar x1; - SkScalar x2; - SkScalar y1; - SkScalar y2; - typedef SkBoundable INHERITED; -}; - -#endif // SkDrawLine_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawMatrix.cpp b/gfx/skia/skia/src/animator/SkDrawMatrix.cpp deleted file mode 100644 index 890a3296a3b4..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawMatrix.cpp +++ /dev/null @@ -1,268 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawMatrix.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkPaint.h" -#include "SkParse.h" -#include "SkMatrixParts.h" -#include "SkScript.h" -#include "SkTypedArray.h" - -enum SkDrawMatrix_Properties { - SK_PROPERTY(perspectX), - SK_PROPERTY(perspectY), - SK_PROPERTY(rotate), - SK_PROPERTY(scale), - SK_PROPERTY(scaleX), - SK_PROPERTY(scaleY), - SK_PROPERTY(skewX), - SK_PROPERTY(skewY), - SK_PROPERTY(translate), - SK_PROPERTY(translateX), - SK_PROPERTY(translateY) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawMatrix::fInfo[] = { - SK_MEMBER_ARRAY(matrix, Float), - SK_MEMBER_PROPERTY(perspectX, Float), - SK_MEMBER_PROPERTY(perspectY, Float), - SK_MEMBER_PROPERTY(rotate, Float), - SK_MEMBER_PROPERTY(scale, Float), - SK_MEMBER_PROPERTY(scaleX, Float), - SK_MEMBER_PROPERTY(scaleY, Float), - SK_MEMBER_PROPERTY(skewX, Float), - SK_MEMBER_PROPERTY(skewY, Float), - SK_MEMBER_PROPERTY(translate, Point), - SK_MEMBER_PROPERTY(translateX, Float), - SK_MEMBER_PROPERTY(translateY, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawMatrix); - -SkDrawMatrix::SkDrawMatrix() : fChildHasID(false), fDirty(false) { - fConcat.reset(); - fMatrix.reset(); -} - -SkDrawMatrix::~SkDrawMatrix() { - for (SkMatrixPart** part = fParts.begin(); part < fParts.end(); part++) - delete *part; -} - -bool SkDrawMatrix::addChild(SkAnimateMaker& maker, SkDisplayable* child) { - SkASSERT(child && child->isMatrixPart()); - SkMatrixPart* part = (SkMatrixPart*) child; - *fParts.append() = part; - if (part->add()) - maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingToMatrix); - return true; -} - -bool SkDrawMatrix::childrenNeedDisposing() const { - return false; -} - -SkDisplayable* SkDrawMatrix::deepCopy(SkAnimateMaker* maker) { - SkDrawMatrix* copy = (SkDrawMatrix*) - SkDisplayType::CreateInstance(maker, SkType_Matrix); - SkASSERT(fParts.count() == 0); - copy->fMatrix = fMatrix; - copy->fConcat = fConcat; - return copy; -} - -void SkDrawMatrix::dirty() { - fDirty = true; -} - -bool SkDrawMatrix::draw(SkAnimateMaker& maker) { - SkMatrix& concat = getMatrix(); - maker.fCanvas->concat(concat); - return false; -} - -#ifdef SK_DUMP_ENABLED -void SkDrawMatrix::dump(SkAnimateMaker* maker) { - dumpBase(maker); - if (fMatrix.isIdentity()) { - SkDebugf("matrix=\"identity\"/>\n"); - return; - } - SkScalar result; - result = fMatrix[SkMatrix::kMScaleX]; - if (result != SK_Scalar1) - SkDebugf("sx=\"%g\" ", SkScalarToFloat(result)); - result = fMatrix.getScaleY(); - if (result != SK_Scalar1) - SkDebugf("sy=\"%g\" ", SkScalarToFloat(result)); - result = fMatrix.getSkewX(); - if (result) - SkDebugf("skew-x=\"%g\" ", SkScalarToFloat(result)); - result = fMatrix.getSkewY(); - if (result) - SkDebugf("skew-y=\"%g\" ", SkScalarToFloat(result)); - result = fMatrix.getTranslateX(); - if (result) - SkDebugf("tx=\"%g\" ", SkScalarToFloat(result)); - result = fMatrix.getTranslateY(); - if (result) - SkDebugf("ty=\"%g\" ", SkScalarToFloat(result)); - result = fMatrix.getPerspX(); - if (result) - SkDebugf("perspect-x=\"%g\" ", SkScalarToFloat(result)); - result = fMatrix.getPerspY(); - if (result) - SkDebugf("perspect-y=\"%g\" ", SkScalarToFloat(result)); - SkDebugf("/>\n"); -} -#endif - -SkMatrix& SkDrawMatrix::getMatrix() { - if (fDirty == false) - return fConcat; - fMatrix.reset(); - for (SkMatrixPart** part = fParts.begin(); part < fParts.end(); part++) { - (*part)->add(); - fConcat = fMatrix; - } - fDirty = false; - return fConcat; -} - -bool SkDrawMatrix::getProperty(int index, SkScriptValue* value) const { - value->fType = SkType_Float; - SkScalar result; - switch (index) { - case SK_PROPERTY(perspectX): - result = fMatrix.getPerspX(); - break; - case SK_PROPERTY(perspectY): - result = fMatrix.getPerspY(); - break; - case SK_PROPERTY(scaleX): - result = fMatrix.getScaleX(); - break; - case SK_PROPERTY(scaleY): - result = fMatrix.getScaleY(); - break; - case SK_PROPERTY(skewX): - result = fMatrix.getSkewX(); - break; - case SK_PROPERTY(skewY): - result = fMatrix.getSkewY(); - break; - case SK_PROPERTY(translateX): - result = fMatrix.getTranslateX(); - break; - case SK_PROPERTY(translateY): - result = fMatrix.getTranslateY(); - break; - default: -// SkASSERT(0); - return false; - } - value->fOperand.fScalar = result; - return true; -} - -void SkDrawMatrix::initialize() { - fConcat = fMatrix; -} - -void SkDrawMatrix::onEndElement(SkAnimateMaker& ) { - if (matrix.count() > 0) { - SkScalar* vals = matrix.begin(); - fMatrix.setScaleX(vals[0]); - fMatrix.setSkewX(vals[1]); - fMatrix.setTranslateX(vals[2]); - fMatrix.setSkewY(vals[3]); - fMatrix.setScaleY(vals[4]); - fMatrix.setTranslateY(vals[5]); - fMatrix.setPerspX(vals[6]); - fMatrix.setPerspY(vals[7]); -// fMatrix.setPerspW(vals[8]); - goto setConcat; - } - if (fChildHasID == false) { - { - for (SkMatrixPart** part = fParts.begin(); part < fParts.end(); part++) - delete *part; - } - fParts.reset(); -setConcat: - fConcat = fMatrix; - fDirty = false; - } -} - -void SkDrawMatrix::setChildHasID() { - fChildHasID = true; -} - -bool SkDrawMatrix::setProperty(int index, SkScriptValue& scriptValue) { - SkScalar number = scriptValue.fOperand.fScalar; - switch (index) { - case SK_PROPERTY(translate): - // SkScalar xy[2]; - SkASSERT(scriptValue.fType == SkType_Array); - SkASSERT(scriptValue.fOperand.fArray->getType() == SkType_Float); - SkASSERT(scriptValue.fOperand.fArray->count() == 2); - // SkParse::FindScalars(scriptValue.fOperand.fString->c_str(), xy, 2); - fMatrix.setTranslateX((*scriptValue.fOperand.fArray)[0].fScalar); - fMatrix.setTranslateY((*scriptValue.fOperand.fArray)[1].fScalar); - return true; - case SK_PROPERTY(perspectX): - fMatrix.setPerspX(number); - break; - case SK_PROPERTY(perspectY): - fMatrix.setPerspY(number); - break; - case SK_PROPERTY(rotate): { - SkMatrix temp; - temp.setRotate(number, 0, 0); - fMatrix.setScaleX(temp.getScaleX()); - fMatrix.setScaleY(temp.getScaleY()); - fMatrix.setSkewX(temp.getSkewX()); - fMatrix.setSkewY(temp.getSkewY()); - } break; - case SK_PROPERTY(scale): - fMatrix.setScaleX(number); - fMatrix.setScaleY(number); - break; - case SK_PROPERTY(scaleX): - fMatrix.setScaleX(number); - break; - case SK_PROPERTY(scaleY): - fMatrix.setScaleY(number); - break; - case SK_PROPERTY(skewX): - fMatrix.setSkewX(number); - break; - case SK_PROPERTY(skewY): - fMatrix.setSkewY(number); - break; - case SK_PROPERTY(translateX): - fMatrix.setTranslateX(number); - break; - case SK_PROPERTY(translateY): - fMatrix.setTranslateY(number); - break; - default: - SkASSERT(0); - return false; - } - fConcat = fMatrix; - return true; -} diff --git a/gfx/skia/skia/src/animator/SkDrawMatrix.h b/gfx/skia/skia/src/animator/SkDrawMatrix.h deleted file mode 100644 index df17a9b75714..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawMatrix.h +++ /dev/null @@ -1,74 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawMatrix_DEFINED -#define SkDrawMatrix_DEFINED - -#include "SkADrawable.h" -#include "SkMatrix.h" -#include "SkMemberInfo.h" -#include "SkIntArray.h" - -class SkMatrixPart; - -class SkDrawMatrix : public SkADrawable { - DECLARE_DRAW_MEMBER_INFO(Matrix); - SkDrawMatrix(); - virtual ~SkDrawMatrix(); - bool addChild(SkAnimateMaker& , SkDisplayable* child) override; - bool childrenNeedDisposing() const override; - void dirty() override; - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - SkMatrix& getMatrix(); - bool getProperty(int index, SkScriptValue* value) const override; - void initialize() override; - void onEndElement(SkAnimateMaker& ) override; - void setChildHasID() override; - bool setProperty(int index, SkScriptValue& ) override; - - void concat(SkMatrix& inMatrix) { - fConcat.preConcat(inMatrix); - } - - SkDisplayable* deepCopy(SkAnimateMaker* ) override; - - - void rotate(SkScalar degrees, SkPoint& center) { - fMatrix.preRotate(degrees, center.fX, center.fY); - } - - void set(SkMatrix& src) { - fMatrix.preConcat(src); - } - - void scale(SkScalar scaleX, SkScalar scaleY, SkPoint& center) { - fMatrix.preScale(scaleX, scaleY, center.fX, center.fY); - } - - void skew(SkScalar skewX, SkScalar skewY, SkPoint& center) { - fMatrix.preSkew(skewX, skewY, center.fX, center.fY); - } - - void translate(SkScalar x, SkScalar y) { - fMatrix.preTranslate(x, y); - } -private: - SkTDScalarArray matrix; - SkMatrix fConcat; - SkMatrix fMatrix; - SkTDMatrixPartArray fParts; - SkBool8 fChildHasID; - SkBool8 fDirty; - typedef SkADrawable INHERITED; -}; - -#endif // SkDrawMatrix_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawOval.cpp b/gfx/skia/skia/src/animator/SkDrawOval.cpp deleted file mode 100644 index e5efa7d5380f..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawOval.cpp +++ /dev/null @@ -1,28 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawOval.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkOval::fInfo[] = { - SK_MEMBER_INHERITED, -}; - -#endif - -DEFINE_GET_MEMBER(SkOval); - -bool SkOval::draw(SkAnimateMaker& maker) { - SkBoundableAuto boundable(this, maker); - maker.fCanvas->drawOval(fRect, *maker.fPaint); - return false; -} diff --git a/gfx/skia/skia/src/animator/SkDrawOval.h b/gfx/skia/skia/src/animator/SkDrawOval.h deleted file mode 100644 index e4d47122230c..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawOval.h +++ /dev/null @@ -1,22 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawOval_DEFINED -#define SkDrawOval_DEFINED - -#include "SkDrawRectangle.h" - -class SkOval : public SkDrawRect { - DECLARE_MEMBER_INFO(Oval); - bool draw(SkAnimateMaker& ) override; -private: - typedef SkDrawRect INHERITED; -}; - -#endif // SkDrawOval_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawPaint.cpp b/gfx/skia/skia/src/animator/SkDrawPaint.cpp deleted file mode 100644 index 1026630eb11f..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawPaint.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkDrawPaint.h" -#include "SkAnimateMaker.h" -#include "SkDrawColor.h" -#include "SkDrawShader.h" -#include "SkMaskFilter.h" -#include "SkPaintPart.h" -#include "SkPathEffect.h" - -enum SkPaint_Functions { - SK_FUNCTION(measureText) -}; - -enum SkPaint_Properties { - SK_PROPERTY(ascent), - SK_PROPERTY(descent) -}; - -// !!! in the future, this could be compiled by build-condensed-info into an array of parameters -// with a lookup table to find the first parameter -- for now, it is iteratively searched through -const SkFunctionParamType SkDrawPaint::fFunctionParameters[] = { - (SkFunctionParamType) SkType_String, - (SkFunctionParamType) 0 // terminator for parameter list (there may be multiple parameter lists) -}; - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawPaint::fInfo[] = { - SK_MEMBER(antiAlias, Boolean), - SK_MEMBER_PROPERTY(ascent, Float), - SK_MEMBER(color, Color), - SK_MEMBER_PROPERTY(descent, Float), - SK_MEMBER(fakeBold, Boolean), - SK_MEMBER(filterBitmap, Boolean), - SK_MEMBER(linearText, Boolean), - SK_MEMBER(maskFilter, MaskFilter), - SK_MEMBER_FUNCTION(measureText, Float), - SK_MEMBER(pathEffect, PathEffect), - SK_MEMBER(shader, Shader), - SK_MEMBER(strikeThru, Boolean), - SK_MEMBER(stroke, Boolean), - SK_MEMBER(strokeCap, Cap), - SK_MEMBER(strokeJoin, Join), - SK_MEMBER(strokeMiter, Float), - SK_MEMBER(strokeWidth, Float), - SK_MEMBER(style, Style), - SK_MEMBER(textAlign, Align), - SK_MEMBER(textScaleX, Float), - SK_MEMBER(textSize, Float), - SK_MEMBER(textSkewX, Float), - SK_MEMBER(typeface, Typeface), - SK_MEMBER(underline, Boolean), - SK_MEMBER(xfermode, Xfermode) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawPaint); - -SkDrawPaint::SkDrawPaint() : antiAlias(-1), color(nullptr), fakeBold(-1), filterBitmap(-1), - linearText(-1), maskFilter((SkDrawMaskFilter*) -1), pathEffect((SkDrawPathEffect*) -1), - shader((SkDrawShader*) -1), strikeThru(-1), stroke(-1), - strokeCap((SkPaint::Cap) -1), strokeJoin((SkPaint::Join) -1), strokeMiter(SK_ScalarNaN), - strokeWidth(SK_ScalarNaN), style((SkPaint::Style) -1), - textAlign((SkPaint::Align) -1), textScaleX(SK_ScalarNaN), textSize(SK_ScalarNaN), - textSkewX(SK_ScalarNaN), typeface((SkDrawTypeface*) -1), - underline(-1), xfermode((SkXfermode::Mode) -1), fOwnsColor(false), fOwnsMaskFilter(false), - fOwnsPathEffect(false), fOwnsShader(false), fOwnsTypeface(false) { -} - -SkDrawPaint::~SkDrawPaint() { - if (fOwnsColor) - delete color; - if (fOwnsMaskFilter) - delete maskFilter; - if (fOwnsPathEffect) - delete pathEffect; - if (fOwnsShader) - delete shader; - if (fOwnsTypeface) - delete typeface; -} - -bool SkDrawPaint::add(SkAnimateMaker* maker, SkDisplayable* child) { - SkASSERT(child && child->isPaintPart()); - SkPaintPart* part = (SkPaintPart*) child; - if (part->add() && maker) - maker->setErrorCode(SkDisplayXMLParserError::kErrorAddingToPaint); - return true; -} - -SkDisplayable* SkDrawPaint::deepCopy(SkAnimateMaker* maker) { - SkDrawColor* tempColor = color; - color = nullptr; - SkDrawPaint* copy = (SkDrawPaint*) INHERITED::deepCopy(maker); - color = tempColor; - tempColor = (SkDrawColor*) color->deepCopy(maker); - tempColor->setParent(copy); - tempColor->add(); - copy->fOwnsColor = true; - return copy; -} - -bool SkDrawPaint::draw(SkAnimateMaker& maker) { - SkPaint* paint = maker.fPaint; - setupPaint(paint); - return false; -} - -#ifdef SK_DUMP_ENABLED -void SkDrawPaint::dump(SkAnimateMaker* maker) { - dumpBase(maker); - dumpAttrs(maker); - bool closedYet = false; - SkDisplayList::fIndent +=4; - //should i say if (maskFilter && ...? - if (maskFilter != (SkDrawMaskFilter*)-1) { - SkDebugf(">\n"); - maskFilter->dump(maker); - closedYet = true; - } - if (pathEffect != (SkDrawPathEffect*) -1) { - if (closedYet == false) { - SkDebugf(">\n"); - closedYet = true; - } - pathEffect->dump(maker); - } - if (fOwnsTypeface) { - if (closedYet == false) { - SkDebugf(">\n"); - closedYet = true; - } - typeface->dump(maker); - } - SkDisplayList::fIndent -= 4; - dumpChildren(maker, closedYet); -} -#endif - -void SkDrawPaint::executeFunction(SkDisplayable* target, int index, - SkTDArray& parameters, SkDisplayTypes type, - SkScriptValue* scriptValue) { - if (scriptValue == nullptr) - return; - SkASSERT(target == this); - switch (index) { - case SK_FUNCTION(measureText): { - SkASSERT(parameters.count() == 1); - SkASSERT(type == SkType_Float); - SkPaint paint; - setupPaint(&paint); - scriptValue->fType = SkType_Float; - SkASSERT(parameters[0].fType == SkType_String); - scriptValue->fOperand.fScalar = paint.measureText(parameters[0].fOperand.fString->c_str(), - parameters[0].fOperand.fString->size()); -// SkDebugf("measureText: %s = %g\n", parameters[0].fOperand.fString->c_str(), -// scriptValue->fOperand.fScalar / 65536.0f); - } break; - default: - SkASSERT(0); - } -} - -const SkFunctionParamType* SkDrawPaint::getFunctionsParameters() { - return fFunctionParameters; -} - -bool SkDrawPaint::getProperty(int index, SkScriptValue* value) const { - SkPaint::FontMetrics metrics; - SkPaint paint; - setupPaint(&paint); - paint.getFontMetrics(&metrics); - switch (index) { - case SK_PROPERTY(ascent): - value->fOperand.fScalar = metrics.fAscent; - break; - case SK_PROPERTY(descent): - value->fOperand.fScalar = metrics.fDescent; - break; - // should consider returning fLeading as well (or roll it into ascent/descent somehow - default: - SkASSERT(0); - return false; - } - value->fType = SkType_Float; - return true; -} - -bool SkDrawPaint::resolveIDs(SkAnimateMaker& maker, SkDisplayable* origDisp, SkApply* ) { - SkASSERT(origDisp->isPaint()); - SkDrawPaint* original = (SkDrawPaint*) origDisp; - if (fOwnsColor && maker.resolveID(color, original->color) == false) - return true; - if (fOwnsMaskFilter && maker.resolveID(maskFilter, original->maskFilter) == false) - return true; - if (fOwnsPathEffect && maker.resolveID(pathEffect, original->pathEffect) == false) - return true; - if (fOwnsShader && maker.resolveID(shader, original->shader) == false) - return true; - if (fOwnsTypeface && maker.resolveID(typeface, original->typeface) == false) - return true; - return false; // succeeded -} - -void SkDrawPaint::setupPaint(SkPaint* paint) const { - if (antiAlias != -1) - paint->setAntiAlias(SkToBool(antiAlias)); - if (color != nullptr) - paint->setColor(color->getColor()); - if (fakeBold != -1) - paint->setFakeBoldText(SkToBool(fakeBold)); - if (filterBitmap != -1) - paint->setFilterQuality(filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality); - // stroke is legacy; style setting if present overrides stroke - if (stroke != -1) - paint->setStyle(SkToBool(stroke) ? SkPaint::kStroke_Style : SkPaint::kFill_Style); - if (style != -1) - paint->setStyle((SkPaint::Style) style); - if (linearText != -1) - paint->setLinearText(SkToBool(linearText)); - if (maskFilter == nullptr) - paint->setMaskFilter(nullptr); - else if (maskFilter != (SkDrawMaskFilter*) -1) - paint->setMaskFilter(sk_sp(maskFilter->getMaskFilter())); - if (pathEffect == nullptr) - paint->setPathEffect(nullptr); - else if (pathEffect != (SkDrawPathEffect*) -1) - paint->setPathEffect(sk_ref_sp(pathEffect->getPathEffect())); - if (shader == nullptr) - paint->setShader(nullptr); - else if (shader != (SkDrawShader*) -1) - paint->setShader(sk_ref_sp(shader->getShader())); - if (strikeThru != -1) - paint->setStrikeThruText(SkToBool(strikeThru)); - if (strokeCap != -1) - paint->setStrokeCap((SkPaint::Cap) strokeCap); - if (strokeJoin != -1) - paint->setStrokeJoin((SkPaint::Join) strokeJoin); - if (SkScalarIsNaN(strokeMiter) == false) - paint->setStrokeMiter(strokeMiter); - if (SkScalarIsNaN(strokeWidth) == false) - paint->setStrokeWidth(strokeWidth); - if (textAlign != -1) - paint->setTextAlign((SkPaint::Align) textAlign); - if (SkScalarIsNaN(textScaleX) == false) - paint->setTextScaleX(textScaleX); - if (SkScalarIsNaN(textSize) == false) - paint->setTextSize(textSize); - if (SkScalarIsNaN(textSkewX) == false) - paint->setTextSkewX(textSkewX); - if (typeface == nullptr) - paint->setTypeface(nullptr); - else if (typeface != (SkDrawTypeface*) -1) - paint->setTypeface(typeface->getTypeface()); - if (underline != -1) - paint->setUnderlineText(SkToBool(underline)); - if (xfermode != -1) - paint->setXfermodeMode((SkXfermode::Mode) xfermode); -} diff --git a/gfx/skia/skia/src/animator/SkDrawPaint.h b/gfx/skia/skia/src/animator/SkDrawPaint.h deleted file mode 100644 index bef52527b1d0..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawPaint.h +++ /dev/null @@ -1,79 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawPaint_DEFINED -#define SkDrawPaint_DEFINED - -#include "SkADrawable.h" -#include "SkIntArray.h" -#include "SkMemberInfo.h" -#include "SkPaint.h" -#include "SkXfermode.h" - -class SkDrawMaskFilter; -class SkDrawPathEffect; -class SkDrawShader; -class SkTransferMode; -class SkDrawTypeface; - -class SkDrawPaint : public SkADrawable { - DECLARE_DRAW_MEMBER_INFO(Paint); - SkDrawPaint(); - virtual ~SkDrawPaint(); - virtual bool add(SkAnimateMaker* , SkDisplayable* child); - SkDisplayable* deepCopy(SkAnimateMaker* ) override; - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - void executeFunction(SkDisplayable* target, int index, - SkTDArray& parameters, SkDisplayTypes type, - SkScriptValue* ) override; - const SkFunctionParamType* getFunctionsParameters() override; - bool getProperty(int index, SkScriptValue* value) const override; - bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply) override; -protected: - static const SkFunctionParamType fFunctionParameters[]; - void setupPaint(SkPaint* paint) const; -public: - SkBool antiAlias; - SkDrawColor* color; - SkBool fakeBold; - SkBool filterBitmap; - SkBool linearText; - SkDrawMaskFilter* maskFilter; - SkDrawPathEffect* pathEffect; - SkDrawShader* shader; - SkBool strikeThru; - SkBool stroke; - int /*SkPaint::Cap*/ strokeCap; - int /*SkPaint::Join */ strokeJoin; - SkScalar strokeMiter; - SkScalar strokeWidth; - int /* SkPaint::Style */ style; - int /* SkPaint::Align */ textAlign; - SkScalar textScaleX; - SkScalar textSize; - SkScalar textSkewX; - SkDrawTypeface* typeface; - SkBool underline; - int /*SkXfermode::Modes*/ xfermode; - SkBool8 fOwnsColor; - SkBool8 fOwnsMaskFilter; - SkBool8 fOwnsPathEffect; - SkBool8 fOwnsShader; - SkBool8 fOwnsTransferMode; - SkBool8 fOwnsTypeface; -private: - typedef SkADrawable INHERITED; - friend class SkTextToPath; - friend class SkSaveLayer; -}; - -#endif // SkDrawPaint_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawPath.cpp b/gfx/skia/skia/src/animator/SkDrawPath.cpp deleted file mode 100644 index c4c6f5caf59b..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawPath.cpp +++ /dev/null @@ -1,220 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawPath.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkMath.h" -#include "SkMatrixParts.h" -#include "SkPaint.h" -#include "SkPathParts.h" - -enum SkPath_Properties { - SK_PROPERTY(fillType), - SK_PROPERTY(length) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawPath::fInfo[] = { - SK_MEMBER(d, String), - SK_MEMBER_PROPERTY(fillType, FillType), - SK_MEMBER_PROPERTY(length, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawPath); - -SkDrawPath::SkDrawPath() -{ - fParent = nullptr; - fLength = SK_ScalarNaN; - fChildHasID = false; - fDirty = false; -} - -SkDrawPath::~SkDrawPath() { - for (SkPathPart** part = fParts.begin(); part < fParts.end(); part++) - delete *part; -} - -bool SkDrawPath::addChild(SkAnimateMaker& maker, SkDisplayable* child) { - SkASSERT(child && child->isPathPart()); - SkPathPart* part = (SkPathPart*) child; - *fParts.append() = part; - if (part->add()) - maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingToPath); - fDirty = false; - return true; -} - -bool SkDrawPath::childrenNeedDisposing() const { - return false; -} - -void SkDrawPath::dirty() { - fDirty = true; - fLength = SK_ScalarNaN; - if (fParent) - fParent->dirty(); -} - -bool SkDrawPath::draw(SkAnimateMaker& maker) { - SkPath& path = getPath(); - SkBoundableAuto boundable(this, maker); - maker.fCanvas->drawPath(path, *maker.fPaint); - return false; -} - -SkDisplayable* SkDrawPath::getParent() const { - return fParent; -} - -#ifdef SK_DUMP_ENABLED -void SkDrawPath::dump(SkAnimateMaker* maker) { - dumpBase(maker); - dumpAttrs(maker); - bool closedYet = false; - SkDisplayList::fIndent += 4; - for(SkPathPart** part = fParts.begin(); part < fParts.end(); part++) { - if (closedYet == false) { - SkDebugf(">\n"); - closedYet = true; - } - (*part)->dump(maker); - } - SkDisplayList::fIndent -= 4; - if (closedYet) - dumpEnd(maker); - else - SkDebugf("/>\n"); -} -#endif - -SkPath& SkDrawPath::getPath() { - if (fDirty == false) - return fPath; - if (d.size() > 0) - { - parseSVG(); - d.reset(); - } - else - { - fPath.reset(); - for (SkPathPart** part = fParts.begin(); part < fParts.end(); part++) - (*part)->add(); - } - fDirty = false; - return fPath; -} - -void SkDrawPath::onEndElement(SkAnimateMaker& ) { - if (d.size() > 0) { - parseSVG(); - d.reset(); - fDirty = false; - return; - } - if (fChildHasID == false) { - for (SkPathPart** part = fParts.begin(); part < fParts.end(); part++) - delete *part; - fParts.reset(); - fDirty = false; - } -} - -bool SkDrawPath::getProperty(int index, SkScriptValue* value) const { - switch (index) { - case SK_PROPERTY(length): - if (SkScalarIsNaN(fLength)) { - const SkPath& path = ((SkDrawPath*) this)->getPath(); - SkPathMeasure pathMeasure(path, false); - fLength = pathMeasure.getLength(); - } - value->fType = SkType_Float; - value->fOperand.fScalar = fLength; - break; - case SK_PROPERTY(fillType): - value->fType = SkType_FillType; - value->fOperand.fS32 = (int) fPath.getFillType(); - break; - default: - SkASSERT(0); - return false; - } - return true; -} - -void SkDrawPath::setChildHasID() { - fChildHasID = true; -} - -bool SkDrawPath::setParent(SkDisplayable* parent) { - fParent = parent; - return false; -} - -bool SkDrawPath::setProperty(int index, SkScriptValue& value) -{ - switch (index) { - case SK_PROPERTY(fillType): - SkASSERT(value.fType == SkType_FillType); - SkASSERT(value.fOperand.fS32 >= SkPath::kWinding_FillType && - value.fOperand.fS32 <= SkPath::kEvenOdd_FillType); - fPath.setFillType((SkPath::FillType) value.fOperand.fS32); - break; - default: - SkASSERT(0); - return false; - } - return true; -} - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkPolyline::fInfo[] = { - SK_MEMBER_ARRAY(points, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkPolyline); - -bool SkPolyline::addChild(SkAnimateMaker& , SkDisplayable*) { - return false; -} - -void SkPolyline::onEndElement(SkAnimateMaker& maker) { - INHERITED::onEndElement(maker); - if (points.count() <= 0) - return; - fPath.reset(); - fPath.moveTo(points[0], points[1]); - int count = points.count(); - for (int index = 2; index < count; index += 2) - fPath.lineTo(points[index], points[index+1]); -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkPolygon::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkPolygon); - -void SkPolygon::onEndElement(SkAnimateMaker& maker) { - INHERITED::onEndElement(maker); - fPath.close(); -} diff --git a/gfx/skia/skia/src/animator/SkDrawPath.h b/gfx/skia/skia/src/animator/SkDrawPath.h deleted file mode 100644 index 81978fb7d001..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawPath.h +++ /dev/null @@ -1,69 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawPath_DEFINED -#define SkDrawPath_DEFINED - -#include "SkBoundable.h" -#include "SkIntArray.h" -#include "SkMemberInfo.h" -#include "SkPath.h" - -class SkDrawPath : public SkBoundable { - DECLARE_DRAW_MEMBER_INFO(Path); - SkDrawPath(); - virtual ~SkDrawPath(); - bool addChild(SkAnimateMaker& , SkDisplayable* child) override; - bool childHasID() { return SkToBool(fChildHasID); } - bool childrenNeedDisposing() const override; - void dirty() override; - bool draw(SkAnimateMaker& ) override; - SkDisplayable* getParent() const override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - SkPath& getPath(); - bool getProperty(int index, SkScriptValue* value) const override; - bool setProperty(int index, SkScriptValue& value) override; - void onEndElement(SkAnimateMaker& ) override; - void setChildHasID() override; - bool setParent(SkDisplayable* parent) override; - bool isPath() const override { return true; } -public: - SkPath fPath; -protected: - void parseSVG(); - SkString d; - SkTDPathPartArray fParts; - mutable SkScalar fLength; - SkDisplayable* fParent; // SkPolyToPoly or SkFromPath, for instance - SkBool8 fChildHasID; - SkBool8 fDirty; -private: - typedef SkBoundable INHERITED; -}; - -class SkPolyline : public SkDrawPath { - DECLARE_MEMBER_INFO(Polyline); - bool addChild(SkAnimateMaker& , SkDisplayable*) override; - void onEndElement(SkAnimateMaker& ) override; -protected: - SkTDScalarArray points; -private: - typedef SkDrawPath INHERITED; -}; - -class SkPolygon : public SkPolyline { - DECLARE_MEMBER_INFO(Polygon); - void onEndElement(SkAnimateMaker& ) override; -private: - typedef SkPolyline INHERITED; -}; - -#endif // SkDrawPath_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawPoint.cpp b/gfx/skia/skia/src/animator/SkDrawPoint.cpp deleted file mode 100644 index 41a6be4ba5c8..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawPoint.cpp +++ /dev/null @@ -1,44 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawPoint.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkPaint.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo Sk_Point::fInfo[] = { - SK_MEMBER_ALIAS(x, fPoint.fX, Float), - SK_MEMBER_ALIAS(y, fPoint.fY, Float) -}; - -#endif - -DEFINE_NO_VIRTUALS_GET_MEMBER(Sk_Point); - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawPoint::fInfo[] = { - SK_MEMBER_ALIAS(x, fPoint.fX, Float), - SK_MEMBER_ALIAS(y, fPoint.fY, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawPoint); - -SkDrawPoint::SkDrawPoint() { - fPoint.set(0, 0); -} - -void SkDrawPoint::getBounds(SkRect* rect ) { - rect->fLeft = rect->fRight = fPoint.fX; - rect->fTop = rect->fBottom = fPoint.fY; -} diff --git a/gfx/skia/skia/src/animator/SkDrawPoint.h b/gfx/skia/skia/src/animator/SkDrawPoint.h deleted file mode 100644 index 03c8521bdf80..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawPoint.h +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawPoint_DEFINED -#define SkDrawPoint_DEFINED - -#include "SkBoundable.h" -#include "SkMemberInfo.h" -#include "SkPoint.h" - -struct Sk_Point { - DECLARE_NO_VIRTUALS_MEMBER_INFO(_Point); - Sk_Point(); -private: - SkPoint fPoint; -}; - -class SkDrawPoint : public SkDisplayable { - DECLARE_MEMBER_INFO(DrawPoint); - SkDrawPoint(); - void getBounds(SkRect* ) override; -private: - SkPoint fPoint; - typedef SkDisplayable INHERITED; -}; - -#endif // SkDrawPoint_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawRectangle.cpp b/gfx/skia/skia/src/animator/SkDrawRectangle.cpp deleted file mode 100644 index a89b67cfdf44..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawRectangle.cpp +++ /dev/null @@ -1,142 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawRectangle.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkMatrixParts.h" -#include "SkPaint.h" -#include "SkScript.h" - -enum SkRectangle_Properties { - SK_PROPERTY(height), - SK_PROPERTY(needsRedraw), - SK_PROPERTY(width) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawRect::fInfo[] = { - SK_MEMBER_ALIAS(bottom, fRect.fBottom, Float), - SK_MEMBER_PROPERTY(height, Float), - SK_MEMBER_ALIAS(left, fRect.fLeft, Float), - SK_MEMBER_PROPERTY(needsRedraw, Boolean), - SK_MEMBER_ALIAS(right, fRect.fRight, Float), - SK_MEMBER_ALIAS(top, fRect.fTop, Float), - SK_MEMBER_PROPERTY(width, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawRect); - -SkDrawRect::SkDrawRect() : fParent(nullptr) { - fRect.setEmpty(); -} - -void SkDrawRect::dirty() { - if (fParent) - fParent->dirty(); -} - -bool SkDrawRect::draw(SkAnimateMaker& maker) { - SkBoundableAuto boundable(this, maker); - maker.fCanvas->drawRect(fRect, *maker.fPaint); - return false; -} - -#ifdef SK_DUMP_ENABLED -void SkDrawRect::dump(SkAnimateMaker* maker) { - dumpBase(maker); - SkDebugf("left=\"%g\" top=\"%g\" right=\"%g\" bottom=\"%g\" />\n", - SkScalarToFloat(fRect.fLeft), SkScalarToFloat(fRect.fTop), SkScalarToFloat(fRect.fRight), - SkScalarToFloat(fRect.fBottom)); -} -#endif - -SkDisplayable* SkDrawRect::getParent() const { - return fParent; -} - -bool SkDrawRect::getProperty(int index, SkScriptValue* value) const { - SkScalar result; - switch (index) { - case SK_PROPERTY(height): - result = fRect.height(); - break; - case SK_PROPERTY(needsRedraw): - value->fType = SkType_Boolean; - value->fOperand.fS32 = fBounds.isEmpty() == false; - return true; - case SK_PROPERTY(width): - result = fRect.width(); - break; - default: - SkASSERT(0); - return false; - } - value->fType = SkType_Float; - value->fOperand.fScalar = result; - return true; -} - - -bool SkDrawRect::setParent(SkDisplayable* parent) { - fParent = parent; - return false; -} - -bool SkDrawRect::setProperty(int index, SkScriptValue& value) { - SkScalar scalar = value.fOperand.fScalar; - switch (index) { - case SK_PROPERTY(height): - SkASSERT(value.fType == SkType_Float); - fRect.fBottom = scalar + fRect.fTop; - return true; - case SK_PROPERTY(needsRedraw): - return false; - case SK_PROPERTY(width): - SkASSERT(value.fType == SkType_Float); - fRect.fRight = scalar + fRect.fLeft; - return true; - default: - SkASSERT(0); - } - return false; -} - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkRoundRect::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER(rx, Float), - SK_MEMBER(ry, Float), -}; - -#endif - -DEFINE_GET_MEMBER(SkRoundRect); - -SkRoundRect::SkRoundRect() : rx(0), ry(0) { -} - -bool SkRoundRect::draw(SkAnimateMaker& maker) { - SkBoundableAuto boundable(this, maker); - maker.fCanvas->drawRoundRect(fRect, rx, ry, *maker.fPaint); - return false; -} - -#ifdef SK_DUMP_ENABLED -void SkRoundRect::dump(SkAnimateMaker* maker) { - dumpBase(maker); - SkDebugf("left=\"%g\" top=\"%g\" right=\"%g\" bottom=\"%g\" rx=\"%g\" ry=\"%g\" />\n", - SkScalarToFloat(fRect.fLeft), SkScalarToFloat(fRect.fTop), SkScalarToFloat(fRect.fRight), - SkScalarToFloat(fRect.fBottom), SkScalarToFloat(rx), SkScalarToFloat(ry)); -} -#endif diff --git a/gfx/skia/skia/src/animator/SkDrawRectangle.h b/gfx/skia/skia/src/animator/SkDrawRectangle.h deleted file mode 100644 index 036d52ed6286..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawRectangle.h +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawRectangle_DEFINED -#define SkDrawRectangle_DEFINED - -#include "SkBoundable.h" -#include "SkMemberInfo.h" -#include "SkRect.h" - -class SkRectToRect; - -class SkDrawRect : public SkBoundable { - DECLARE_DRAW_MEMBER_INFO(Rect); - SkDrawRect(); - void dirty() override; - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - SkDisplayable* getParent() const override; - bool getProperty(int index, SkScriptValue* value) const override; - bool setParent(SkDisplayable* parent) override; - bool setProperty(int index, SkScriptValue& ) override; -protected: - SkRect fRect; - SkDisplayable* fParent; -private: - friend class SkDrawClip; - friend class SkRectToRect; - friend class SkSaveLayer; - typedef SkBoundable INHERITED; -}; - -class SkRoundRect : public SkDrawRect { - DECLARE_MEMBER_INFO(RoundRect); - SkRoundRect(); - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif -protected: - SkScalar rx; - SkScalar ry; -private: - typedef SkDrawRect INHERITED; -}; - -#endif // SkDrawRectangle_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawSaveLayer.cpp b/gfx/skia/skia/src/animator/SkDrawSaveLayer.cpp deleted file mode 100644 index c9a4d9feadf0..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawSaveLayer.cpp +++ /dev/null @@ -1,76 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawSaveLayer.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkDrawPaint.h" -#include "SkDrawRectangle.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkSaveLayer::fInfo[] = { - SK_MEMBER(bounds, Rect), - SK_MEMBER(paint, Paint) -}; - -#endif - -DEFINE_GET_MEMBER(SkSaveLayer); - -SkSaveLayer::SkSaveLayer() : paint(nullptr), bounds(nullptr) { -} - -SkSaveLayer::~SkSaveLayer(){ -} - -bool SkSaveLayer::draw(SkAnimateMaker& maker) -{ - if (!bounds) { - return false; - } - SkPaint* save = maker.fPaint; - //paint is an SkDrawPaint - if (paint) - { - SkPaint realPaint; - paint->setupPaint(&realPaint); - maker.fCanvas->saveLayer(&bounds->fRect, &realPaint); - } - else - maker.fCanvas->saveLayer(&bounds->fRect, save); - SkPaint local = SkPaint(*maker.fPaint); - maker.fPaint = &local; - bool result = INHERITED::draw(maker); - maker.fPaint = save; - maker.fCanvas->restore(); - return result; -} - -#ifdef SK_DUMP_ENABLED -void SkSaveLayer::dump(SkAnimateMaker* maker) -{ - dumpBase(maker); - //would dump enabled be defined but not debug? -#ifdef SK_DEBUG - if (paint) - SkDebugf("paint=\"%s\" ", paint->id); - if (bounds) - SkDebugf("bounds=\"%s\" ", bounds->id); -#endif - dumpDrawables(maker); -} -#endif - -void SkSaveLayer::onEndElement(SkAnimateMaker& maker) -{ - if (!bounds) - maker.setErrorCode(SkDisplayXMLParserError::kSaveLayerNeedsBounds); - INHERITED::onEndElement(maker); -} diff --git a/gfx/skia/skia/src/animator/SkDrawSaveLayer.h b/gfx/skia/skia/src/animator/SkDrawSaveLayer.h deleted file mode 100644 index cb9c9a908e7d..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawSaveLayer.h +++ /dev/null @@ -1,36 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawSaveLayer_DEFINED -#define SkDrawSaveLayer_DEFINED - -#include "SkDrawGroup.h" -#include "SkMemberInfo.h" - -class SkDrawPaint; -class SkDrawRect; - -class SkSaveLayer : public SkGroup { - DECLARE_MEMBER_INFO(SaveLayer); - SkSaveLayer(); - virtual ~SkSaveLayer(); - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - void onEndElement(SkAnimateMaker& ) override; -protected: - SkDrawPaint* paint; - SkDrawRect* bounds; -private: - typedef SkGroup INHERITED; - -}; - -#endif //SkDrawSaveLayer_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawShader.cpp b/gfx/skia/skia/src/animator/SkDrawShader.cpp deleted file mode 100644 index 2868b9f4efe7..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawShader.cpp +++ /dev/null @@ -1,78 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawShader.h" -#include "SkDrawBitmap.h" -#include "SkDrawMatrix.h" -#include "SkDrawPaint.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawShader::fInfo[] = { - SK_MEMBER(matrix, Matrix), - SK_MEMBER(tileMode, TileMode) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawShader); - -SkDrawShader::SkDrawShader() : matrix(nullptr), - tileMode(SkShader::kClamp_TileMode) { -} - -bool SkDrawShader::add() { - if (fPaint->shader != (SkDrawShader*) -1) - return true; - fPaint->shader = this; - fPaint->fOwnsShader = true; - return false; -} - -SkMatrix* SkDrawShader::getMatrix() { - return matrix ? &matrix->getMatrix() : nullptr; -} - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawBitmapShader::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER(filterBitmap, Boolean), - SK_MEMBER(image, BaseBitmap) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawBitmapShader); - -SkDrawBitmapShader::SkDrawBitmapShader() : filterBitmap(-1), image(nullptr) {} - -bool SkDrawBitmapShader::add() { - if (fPaint->shader != (SkDrawShader*) -1) - return true; - fPaint->shader = this; - fPaint->fOwnsShader = true; - return false; -} - -SkShader* SkDrawBitmapShader::getShader() { - if (image == nullptr) - return nullptr; - - // note: bitmap shader now supports independent tile modes for X and Y - // we pass the same to both, but later we should extend this flexibility - // to the xml (e.g. tileModeX="repeat" tileModeY="clmap") - // - // oops, bitmapshader no longer takes filterBitmap, but deduces it at - // draw-time from the paint - return SkShader::MakeBitmapShader(image->fBitmap, - (SkShader::TileMode) tileMode, - (SkShader::TileMode) tileMode, - getMatrix()).release(); -} diff --git a/gfx/skia/skia/src/animator/SkDrawShader.h b/gfx/skia/skia/src/animator/SkDrawShader.h deleted file mode 100644 index f7ef29d7d350..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawShader.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkDrawShader_DEFINED -#define SkDrawShader_DEFINED - -#include "SkPaintPart.h" -#include "SkShader.h" - -class SkBaseBitmap; - -class SkDrawBitmapShader : public SkDrawShader { - DECLARE_DRAW_MEMBER_INFO(BitmapShader); - SkDrawBitmapShader(); - bool add() override; - SkShader* getShader() override; -protected: - SkBool filterBitmap; - SkBaseBitmap* image; -private: - typedef SkDrawShader INHERITED; -}; - -#endif // SkDrawShader_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawText.cpp b/gfx/skia/skia/src/animator/SkDrawText.cpp deleted file mode 100644 index e7e5facabb0a..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawText.cpp +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawText.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkPaint.h" - -enum SkText_Properties { - SK_PROPERTY(length) -}; - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkText::fInfo[] = { - SK_MEMBER_PROPERTY(length, Int), - SK_MEMBER(text, String), - SK_MEMBER(x, Float), - SK_MEMBER(y, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkText); - -SkText::SkText() : x(0), y(0) { -} - -SkText::~SkText() { -} - -bool SkText::draw(SkAnimateMaker& maker) { - SkBoundableAuto boundable(this, maker); - maker.fCanvas->drawText(text.c_str(), text.size(), x, y, *maker.fPaint); - return false; -} - -#ifdef SK_DUMP_ENABLED -void SkText::dump(SkAnimateMaker* maker) { - INHERITED::dump(maker); -} -#endif - -bool SkText::getProperty(int index, SkScriptValue* value) const { - SkASSERT(index == SK_PROPERTY(length)); - value->fType = SkType_Int; - value->fOperand.fS32 = (int32_t) text.size(); - return true; -} diff --git a/gfx/skia/skia/src/animator/SkDrawText.h b/gfx/skia/skia/src/animator/SkDrawText.h deleted file mode 100644 index e7632d0cefdb..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawText.h +++ /dev/null @@ -1,36 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawText_DEFINED -#define SkDrawText_DEFINED - -#include "SkBoundable.h" -#include "SkMemberInfo.h" - -class SkText : public SkBoundable { - DECLARE_MEMBER_INFO(Text); - SkText(); - virtual ~SkText(); - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - bool getProperty(int index, SkScriptValue* value) const override; - const char* getText() { return text.c_str(); } - size_t getSize() { return text.size(); } -protected: - SkString text; - SkScalar x; - SkScalar y; -private: - friend class SkTextToPath; - typedef SkBoundable INHERITED; -}; - -#endif // SkDrawText_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawTextBox.cpp b/gfx/skia/skia/src/animator/SkDrawTextBox.cpp deleted file mode 100644 index 7a3251a26f45..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawTextBox.cpp +++ /dev/null @@ -1,80 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawTextBox.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkPaint.h" - -enum SkDrawTextBox_Properties { - foo = 100, - SK_PROPERTY(spacingAlign), - SK_PROPERTY(mode) -}; - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawTextBox::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER(mode, TextBoxMode), - SK_MEMBER_ALIAS(spacingAdd, fSpacingAdd, Float), - SK_MEMBER(spacingAlign, TextBoxAlign), - SK_MEMBER_ALIAS(spacingMul, fSpacingMul, Float), - SK_MEMBER_ALIAS(text, fText, String) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawTextBox); - -SkDrawTextBox::SkDrawTextBox() -{ - fSpacingMul = SK_Scalar1; - fSpacingAdd = 0; - spacingAlign = SkTextBox::kStart_SpacingAlign; - mode = SkTextBox::kLineBreak_Mode; -} - -#ifdef SK_DUMP_ENABLED -void SkDrawTextBox::dump(SkAnimateMaker* maker) -{ - dumpBase(maker); - dumpAttrs(maker); - if (mode == 0) - SkDebugf("mode=\"oneLine\" "); - if (spacingAlign == 1) - SkDebugf("spacingAlign=\"center\" "); - else if (spacingAlign == 2) - SkDebugf("spacingAlign=\"end\" "); - SkDebugf("/>\n"); -} -#endif - -bool SkDrawTextBox::getProperty(int index, SkScriptValue* value) const -{ - return this->INHERITED::getProperty(index, value); -} - -bool SkDrawTextBox::setProperty(int index, SkScriptValue& scriptValue) -{ - return this->INHERITED::setProperty(index, scriptValue); -} - -bool SkDrawTextBox::draw(SkAnimateMaker& maker) -{ - SkTextBox box; - box.setMode((SkTextBox::Mode) mode); - box.setSpacingAlign((SkTextBox::SpacingAlign) spacingAlign); - box.setBox(fRect); - box.setSpacing(fSpacingMul, fSpacingAdd); - SkBoundableAuto boundable(this, maker); - box.draw(maker.fCanvas, fText.c_str(), fText.size(), *maker.fPaint); - return false; -} diff --git a/gfx/skia/skia/src/animator/SkDrawTextBox.h b/gfx/skia/skia/src/animator/SkDrawTextBox.h deleted file mode 100644 index 8f99c73d13b5..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawTextBox.h +++ /dev/null @@ -1,38 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawTextBox_DEFINED -#define SkDrawTextBox_DEFINED - -#include "SkDrawRectangle.h" -#include "SkTextBox.h" - -class SkDrawTextBox : public SkDrawRect { - DECLARE_DRAW_MEMBER_INFO(TextBox); - SkDrawTextBox(); - - // overrides - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - bool getProperty(int index, SkScriptValue* value) const override; - bool setProperty(int index, SkScriptValue& ) override; - -private: - SkString fText; - SkScalar fSpacingMul; - SkScalar fSpacingAdd; - int /*SkTextBox::Mode*/ mode; - int /*SkTextBox::SpacingAlign*/ spacingAlign; - - typedef SkDrawRect INHERITED; -}; - -#endif // SkDrawTextBox_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDrawTo.cpp b/gfx/skia/skia/src/animator/SkDrawTo.cpp deleted file mode 100644 index 7ae9ca58d479..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawTo.cpp +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDrawTo.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkDrawBitmap.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawTo::fInfo[] = { - SK_MEMBER(drawOnce, Boolean), - SK_MEMBER(use, Bitmap) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawTo); - -SkDrawTo::SkDrawTo() : drawOnce(false), use(nullptr), fDrawnOnce(false) { -} - -#if 0 -SkDrawTo::~SkDrawTo() { - SkASSERT(0); -} -#endif - -bool SkDrawTo::draw(SkAnimateMaker& maker) { - if (fDrawnOnce) - return false; - SkCanvas canvas(use->fBitmap); - SkCanvas* save = maker.fCanvas; - maker.fCanvas = &canvas; - INHERITED::draw(maker); - maker.fCanvas = save; - fDrawnOnce = drawOnce; - return false; -} - -#ifdef SK_DUMP_ENABLED -void SkDrawTo::dump(SkAnimateMaker* maker) { - dumpBase(maker); - dumpAttrs(maker); - if (use) - SkDebugf("use=\"%s\" ", use->id); - dumpDrawables(maker); -} -#endif diff --git a/gfx/skia/skia/src/animator/SkDrawTo.h b/gfx/skia/skia/src/animator/SkDrawTo.h deleted file mode 100644 index 29f6b6303d22..000000000000 --- a/gfx/skia/skia/src/animator/SkDrawTo.h +++ /dev/null @@ -1,34 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDrawTo_DEFINED -#define SkDrawTo_DEFINED - -#include "SkDrawGroup.h" -#include "SkMemberInfo.h" - -class SkDrawBitmap; - -class SkDrawTo : public SkGroup { - DECLARE_MEMBER_INFO(DrawTo); - SkDrawTo(); -// virtual ~SkDrawTo(); - bool draw(SkAnimateMaker& ) override; -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif -protected: - SkBool drawOnce; - SkDrawBitmap* use; -private: - typedef SkGroup INHERITED; - SkBool fDrawnOnce; -}; - -#endif // SkDrawTo_DEFINED diff --git a/gfx/skia/skia/src/animator/SkDump.cpp b/gfx/skia/skia/src/animator/SkDump.cpp deleted file mode 100644 index 346b30daf7e1..000000000000 --- a/gfx/skia/skia/src/animator/SkDump.cpp +++ /dev/null @@ -1,150 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkDump.h" - -#ifdef SK_DUMP_ENABLED - -#include "SkAnimateMaker.h" -#include "SkAnimatorScript.h" -#include "SkDisplayEvents.h" -#include "SkDisplayList.h" -#include "SkString.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDump::fInfo[] = { - SK_MEMBER(displayList, Boolean), - SK_MEMBER(eventList, Boolean), - SK_MEMBER(events, Boolean), - SK_MEMBER(groups, Boolean), - SK_MEMBER(name, String), - SK_MEMBER(posts, Boolean), - SK_MEMBER(script, String) -}; - -#endif - -DEFINE_GET_MEMBER(SkDump); - -SkDump::SkDump() : displayList(-1), eventList(-1), events(-1), groups(-1), posts(-1) { -} - -bool SkDump::enable(SkAnimateMaker& maker ) { - if (script.size() > 0) - return evaluate(maker); - bool hasAttr = false; - if (events > 0) - hasAttr |= maker.fDumpEvents = true; - if (posts > 0) - hasAttr |= maker.fDumpPosts = true; - if (groups > 0) - hasAttr |= maker.fDumpGConditions = true; - if ((hasAttr |= (eventList > 0)) == true) - maker.fEvents.dump(maker); - if ((hasAttr |= (name.size() > 0)) == true) - maker.dump(name.c_str()); - if (displayList > 0 || (displayList != 0 && hasAttr == false)) - maker.fDisplayList.dump(&maker); - return true; -} - -bool SkDump::evaluate(SkAnimateMaker &maker) { - SkAnimatorScript scriptEngine(maker, nullptr, SkType_Int); - SkScriptValue value; - const char* cScript = script.c_str(); - bool success = scriptEngine.evaluateScript(&cScript, &value); - SkDebugf("%*s\n"); - return false; - } - switch (value.fType) { - case SkType_Float: - SkDebugf("%g\" />\n", SkScalarToFloat(value.fOperand.fScalar)); - break; - case SkType_Int: - SkDebugf("%d\" />\n", value.fOperand.fS32); - break; - case SkType_String: - SkDebugf("%s\" />\n", value.fOperand.fString->c_str()); - break; - default: - return false; - } - return true; -} - -bool SkDump::hasEnable() const { - return true; -} - -void SkDump::GetEnumString(SkDisplayTypes type, int index, SkString* result) { - int badEnum = index; - const SkDisplayEnumMap& map = SkAnimatorScript::GetEnumValues(type); - const char* str = map.fValues; - while (--index >= 0) { - str = strchr(str, '|'); - if (str == nullptr) { - result->reset(); - result->appendS32(badEnum); - return; - } - str += 1; - } - const char* end = strchr(str, '|'); - if (end == nullptr) - end = str + strlen(str); - result->set(str, end - str); -} - -#else - -// in the release version, is allowed, and its attributes are defined, but -// are not stored and have no effect - -#if SK_USE_CONDENSED_INFO == 0 - -enum SkDump_Properties { - SK_PROPERTY(displayList), - SK_PROPERTY(eventList), - SK_PROPERTY(events), - SK_PROPERTY(groups), - SK_PROPERTY(name), - SK_PROPERTY(posts), - SK_PROPERTY(script) -}; - -const SkMemberInfo SkDump::fInfo[] = { - SK_MEMBER_PROPERTY(displayList, Boolean), - SK_MEMBER_PROPERTY(eventList, Boolean), - SK_MEMBER_PROPERTY(events, Boolean), - SK_MEMBER_PROPERTY(groups, Boolean), - SK_MEMBER_PROPERTY(name, String), - SK_MEMBER_PROPERTY(posts, Boolean), - SK_MEMBER_PROPERTY(script, String) -}; - -#endif - -DEFINE_GET_MEMBER(SkDump); - -bool SkDump::enable(SkAnimateMaker&) { - return true; -} - -bool SkDump::hasEnable() const { - return true; -} - -bool SkDump::setProperty(int index, SkScriptValue&) { - return index <= SK_PROPERTY(posts); -} - -#endif diff --git a/gfx/skia/skia/src/animator/SkDump.h b/gfx/skia/skia/src/animator/SkDump.h deleted file mode 100644 index bcf19fd9af4a..000000000000 --- a/gfx/skia/skia/src/animator/SkDump.h +++ /dev/null @@ -1,42 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkDump_DEFINED -#define SkDump_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" - -class SkAnimateMaker; -class SkString; - -class SkDump : public SkDisplayable { - DECLARE_MEMBER_INFO(Dump); -#ifdef SK_DUMP_ENABLED - SkDump(); - bool enable(SkAnimateMaker & ) override; - bool evaluate(SkAnimateMaker &); - bool hasEnable() const override; - static void GetEnumString(SkDisplayTypes , int index, SkString* result); - SkBool displayList; - SkBool eventList; - SkBool events; - SkString name; - SkBool groups; - SkBool posts; - SkString script; -#else - bool enable(SkAnimateMaker & ) override; - bool hasEnable() const override; - bool setProperty(int index, SkScriptValue& ) override; -#endif -}; - - -#endif // SkDump_DEFINED diff --git a/gfx/skia/skia/src/animator/SkExtraPathEffects.xsd b/gfx/skia/skia/src/animator/SkExtraPathEffects.xsd deleted file mode 100644 index 9592443a081a..000000000000 --- a/gfx/skia/skia/src/animator/SkExtraPathEffects.xsd +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gfx/skia/skia/src/animator/SkExtras.h b/gfx/skia/skia/src/animator/SkExtras.h deleted file mode 100644 index dcd390503458..000000000000 --- a/gfx/skia/skia/src/animator/SkExtras.h +++ /dev/null @@ -1,34 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkExtras_DEFINED -#define SkExtras_DEFINED - -#include "SkScript.h" - -class SkExtras { -public: - SkExtras(); - virtual ~SkExtras() {} - - virtual SkDisplayable* createInstance(SkDisplayTypes type) = 0; - virtual bool definesType(SkDisplayTypes type) = 0; -#if SK_USE_CONDENSED_INFO == 0 - virtual const SkMemberInfo* getMembers(SkDisplayTypes type, int* infoCountPtr) = 0; -#endif -#ifdef SK_DEBUG - virtual const char* getName(SkDisplayTypes type) = 0; -#endif - virtual SkDisplayTypes getType(const char match[], size_t len ) = 0; - - SkScriptEngine::_propertyCallBack fExtraCallBack; - void* fExtraStorage; -}; - -#endif // SkExtras_DEFINED diff --git a/gfx/skia/skia/src/animator/SkGetCondensedInfo.cpp b/gfx/skia/skia/src/animator/SkGetCondensedInfo.cpp deleted file mode 100644 index 4c6532562409..000000000000 --- a/gfx/skia/skia/src/animator/SkGetCondensedInfo.cpp +++ /dev/null @@ -1,121 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkMemberInfo.h" - -#if SK_USE_CONDENSED_INFO == 1 - -// SkCondensed.inc is auto-generated -// To generate it, execute SkDisplayType::BuildCondensedInfo() -#ifdef SK_DEBUG -#include "SkCondensedDebug.inc" -#else -#include "SkCondensedRelease.inc" -#endif - -static int _searchByName(const unsigned char* lengths, int count, const char* strings, const char target[]) { - int lo = 0; - int hi = count - 1; - while (lo < hi) { - int mid = (hi + lo) >> 1; - if (strcmp(&strings[lengths[mid << 2]], target) < 0) - lo = mid + 1; - else - hi = mid; - } - if (strcmp(&strings[lengths[hi << 2]], target) != 0) - return -1; - return hi; -} - -static int _searchByType(SkDisplayTypes type) { - unsigned char match = (unsigned char) type; - int lo = 0; - int hi = kTypeIDs - 1; - while (lo < hi) { - int mid = (hi + lo) >> 1; - if (gTypeIDs[mid] < match) - lo = mid + 1; - else - hi = mid; - } - if (gTypeIDs[hi] != type) - return -1; - return hi; -} - -const SkMemberInfo* SkDisplayType::GetMembers(SkAnimateMaker* , SkDisplayTypes type, int* infoCountPtr) { - int lookup = _searchByType(type); - if (lookup < 0) - return nullptr; - if (infoCountPtr) - *infoCountPtr = gInfoCounts[lookup]; - return gInfoTables[lookup]; -} - -// !!! replace with inline -const SkMemberInfo* SkDisplayType::GetMember(SkAnimateMaker* , SkDisplayTypes type, const char** matchPtr ) { - const SkMemberInfo* info = SkMemberInfo::Find(type, matchPtr); - SkASSERT(info); - return info; -} - -static const SkMemberInfo* _lookup(int lookup, const char** matchPtr) { - int count = gInfoCounts[lookup]; - const SkMemberInfo* info = gInfoTables[lookup]; - if (info->fType == SkType_BaseClassInfo) { - int baseTypeLookup = info->fOffset; - const SkMemberInfo* result = _lookup(baseTypeLookup, matchPtr); - if (result != nullptr) - return result; - if (--count == 0) - return nullptr; - info++; - } - SkASSERT(info->fType != SkType_BaseClassInfo); - const char* match = *matchPtr; - const char* strings = gInfoNames[lookup]; - int index = _searchByName(&info->fName, count, strings, match); - if (index < 0) - return nullptr; - return &info[index]; -} - -const SkMemberInfo* SkMemberInfo::Find(SkDisplayTypes type, int* index) { - int count = gInfoCounts[lookup]; - const SkMemberInfo* info = gInfoTables[lookup]; - if (info->fType == SkType_BaseClassInfo) { - int baseTypeLookup = info->fOffset; - const SkMemberInfo* result = Find(baseTypeLookup, index); - if (result != nullptr) - return result; - if (--count == 0) - return nullptr; - info++; - } - SkASSERT(info->fType != SkType_BaseClassInfo); - if (*index >= count) { - *index -= count; - return nullptr; - } - return &info[index]; -} - -const SkMemberInfo* SkMemberInfo::Find(SkDisplayTypes type, const char** matchPtr) { - int lookup = _searchByType(type); - SkASSERT(lookup >= 0); - return _lookup(lookup, matchPtr); -} - -const SkMemberInfo* SkMemberInfo::getInherited() const { - int baseTypeLookup = fOffset; - return gInfoTables[baseTypeLookup]; -} - -#endif diff --git a/gfx/skia/skia/src/animator/SkHitClear.cpp b/gfx/skia/skia/src/animator/SkHitClear.cpp deleted file mode 100644 index 3ac521ae64da..000000000000 --- a/gfx/skia/skia/src/animator/SkHitClear.cpp +++ /dev/null @@ -1,32 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkHitClear.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkHitClear::fInfo[] = { - SK_MEMBER_ARRAY(targets, Displayable) -}; - -#endif - -DEFINE_GET_MEMBER(SkHitClear); - -bool SkHitClear::enable(SkAnimateMaker&) { - for (int tIndex = 0; tIndex < targets.count(); tIndex++) { - SkDisplayable* target = targets[tIndex]; - target->clearBounder(); - } - return true; -} - -bool SkHitClear::hasEnable() const { - return true; -} diff --git a/gfx/skia/skia/src/animator/SkHitClear.h b/gfx/skia/skia/src/animator/SkHitClear.h deleted file mode 100644 index 042c181adc2a..000000000000 --- a/gfx/skia/skia/src/animator/SkHitClear.h +++ /dev/null @@ -1,25 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkHitClear_DEFINED -#define SkHitClear_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" -#include "SkTypedArray.h" - -class SkHitClear : public SkDisplayable { - DECLARE_MEMBER_INFO(HitClear); - bool enable(SkAnimateMaker& ) override; - bool hasEnable() const override; -private: - SkTDDisplayableArray targets; -}; - -#endif // SkHitClear_DEFINED diff --git a/gfx/skia/skia/src/animator/SkHitTest.cpp b/gfx/skia/skia/src/animator/SkHitTest.cpp deleted file mode 100644 index 79dd25bd5c0b..000000000000 --- a/gfx/skia/skia/src/animator/SkHitTest.cpp +++ /dev/null @@ -1,74 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkHitTest.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkHitTest::fInfo[] = { - SK_MEMBER_ARRAY(bullets, Displayable), - SK_MEMBER_ARRAY(hits, Int), - SK_MEMBER_ARRAY(targets, Displayable), - SK_MEMBER(value, Boolean) -}; - -#endif - -DEFINE_GET_MEMBER(SkHitTest); - -SkHitTest::SkHitTest() : value(false) { -} - -bool SkHitTest::draw(SkAnimateMaker&) { - hits.setCount(bullets.count()); - value = false; - int bulletCount = bullets.count(); - int targetCount = targets.count(); - for (int bIndex = 0; bIndex < bulletCount; bIndex++) { - SkDisplayable* bullet = bullets[bIndex]; - SkRect bBounds; - bullet->getBounds(&bBounds); - hits[bIndex] = -1; - if (bBounds.fLeft == (int16_t)0x8000U) - continue; - for (int tIndex = 0; tIndex < targetCount; tIndex++) { - SkDisplayable* target = targets[tIndex]; - SkRect tBounds; - target->getBounds(&tBounds); - if (bBounds.intersect(tBounds)) { - hits[bIndex] = tIndex; - value = true; - break; - } - } - } - return false; -} - -bool SkHitTest::enable(SkAnimateMaker&) { - for (int bIndex = 0; bIndex < bullets.count(); bIndex++) { - SkDisplayable* bullet = bullets[bIndex]; - bullet->enableBounder(); - } - for (int tIndex = 0; tIndex < targets.count(); tIndex++) { - SkDisplayable* target = targets[tIndex]; - target->enableBounder(); - } - return false; -} - -bool SkHitTest::hasEnable() const { - return true; -} - -const SkMemberInfo* SkHitTest::preferredChild(SkDisplayTypes) { - if (bullets.count() == 0) - return getMember("bullets"); - return getMember("targets"); // !!! cwap! need to refer to member through enum like kScope instead -} diff --git a/gfx/skia/skia/src/animator/SkHitTest.h b/gfx/skia/skia/src/animator/SkHitTest.h deleted file mode 100644 index bd1cbe221f5b..000000000000 --- a/gfx/skia/skia/src/animator/SkHitTest.h +++ /dev/null @@ -1,30 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkHitTest_DEFINED -#define SkHitTest_DEFINED - -#include "SkADrawable.h" -#include "SkTypedArray.h" - -class SkHitTest : public SkADrawable { - DECLARE_MEMBER_INFO(HitTest); - SkHitTest(); - bool draw(SkAnimateMaker& ) override; - bool enable(SkAnimateMaker& ) override; - bool hasEnable() const override; - const SkMemberInfo* preferredChild(SkDisplayTypes type) override; -private: - SkTDDisplayableArray bullets; - SkTDIntArray hits; - SkTDDisplayableArray targets; - SkBool value; -}; - -#endif // SkHitTest_DEFINED diff --git a/gfx/skia/skia/src/animator/SkIntArray.h b/gfx/skia/skia/src/animator/SkIntArray.h deleted file mode 100644 index ae8e36b94fb1..000000000000 --- a/gfx/skia/skia/src/animator/SkIntArray.h +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkIntArray_DEFINED -#define SkIntArray_DEFINED - -#include "SkColor.h" -#include "SkDisplayType.h" -#include "SkMath.h" -#include "SkTDArray_Experimental.h" - -class SkActive; -class SkAnimateBase; -class SkDataInput; -class SkDisplayable; -class SkDisplayEvent; -class SkADrawable; -class SkDrawColor; -class SkMatrixPart; -struct SkMemberInfo; -class SkPathPart; -class SkPaintPart; -class SkTypedArray; -class SkString; -union SkOperand; - -typedef SkIntArray(int) SkTDIntArray; -typedef SkIntArray(SkColor) SkTDColorArray; -typedef SkIntArray(SkDisplayTypes) SkTDDisplayTypesArray; -typedef SkIntArray(SkMSec) SkTDMSecArray; -typedef SkIntArray(SkScalar) SkTDScalarArray; - -typedef SkLongArray(SkActive*) SkTDActiveArray; -typedef SkLongArray(SkAnimateBase*) SkTDAnimateArray; -typedef SkLongArray(SkDataInput*) SkTDDataArray; -typedef SkLongArray(SkDisplayable*) SkTDDisplayableArray; -typedef SkLongArray(SkDisplayEvent*) SkTDDisplayEventArray; -typedef SkLongArray(SkADrawable*) SkTDDrawableArray; -typedef SkLongArray(SkDrawColor*) SkTDDrawColorArray; -typedef SkLongArray(SkMatrixPart*) SkTDMatrixPartArray; -typedef SkLongArray(const SkMemberInfo*) SkTDMemberInfoArray; -typedef SkLongArray(SkPaintPart*) SkTDPaintPartArray; -typedef SkLongArray(SkPathPart*) SkTDPathPartArray; -typedef SkLongArray(SkTypedArray*) SkTDTypedArrayArray; -typedef SkLongArray(SkString*) SkTDStringArray; -typedef SkLongArray(SkOperand) SkTDOperandArray; -typedef SkLongArray(SkOperand*) SkTDOperandPtrArray; - -#endif // SkIntArray_DEFINED diff --git a/gfx/skia/skia/src/animator/SkMatrixParts.cpp b/gfx/skia/skia/src/animator/SkMatrixParts.cpp deleted file mode 100644 index c607f2523f03..000000000000 --- a/gfx/skia/skia/src/animator/SkMatrixParts.cpp +++ /dev/null @@ -1,292 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkMatrixParts.h" -#include "SkAnimateMaker.h" -#include "SkDrawMatrix.h" -#include "SkDrawRectangle.h" -#include "SkDrawPath.h" - -SkMatrixPart::SkMatrixPart() : fMatrix(nullptr) { -} - -void SkMatrixPart::dirty() { - fMatrix->dirty(); -} - -SkDisplayable* SkMatrixPart::getParent() const { - return fMatrix; -} - -bool SkMatrixPart::setParent(SkDisplayable* parent) { - SkASSERT(parent != nullptr); - if (parent->isMatrix() == false) - return true; - fMatrix = (SkDrawMatrix*) parent; - return false; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkRotate::fInfo[] = { - SK_MEMBER(center, Point), - SK_MEMBER(degrees, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkRotate); - -SkRotate::SkRotate() : degrees(0) { - center.fX = center.fY = 0; -} - -bool SkRotate::add() { - fMatrix->rotate(degrees, center); - return false; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkScale::fInfo[] = { - SK_MEMBER(center, Point), - SK_MEMBER(x, Float), - SK_MEMBER(y, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkScale); - -SkScale::SkScale() : x(SK_Scalar1), y(SK_Scalar1) { - center.fX = center.fY = 0; -} - -bool SkScale::add() { - fMatrix->scale(x, y, center); - return false; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkSkew::fInfo[] = { - SK_MEMBER(center, Point), - SK_MEMBER(x, Float), - SK_MEMBER(y, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkSkew); - -SkSkew::SkSkew() : x(0), y(0) { - center.fX = center.fY = 0; -} - -bool SkSkew::add() { - fMatrix->skew(x, y, center); - return false; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkTranslate::fInfo[] = { - SK_MEMBER(x, Float), - SK_MEMBER(y, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkTranslate); - -SkTranslate::SkTranslate() : x(0), y(0) { -} - -bool SkTranslate::add() { - fMatrix->translate(x, y); - return false; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkFromPath::fInfo[] = { - SK_MEMBER(mode, FromPathMode), - SK_MEMBER(offset, Float), - SK_MEMBER(path, Path) -}; - -#endif - -DEFINE_GET_MEMBER(SkFromPath); - -SkFromPath::SkFromPath() : - mode(0), offset(0), path(nullptr) { -} - -SkFromPath::~SkFromPath() { -} - -bool SkFromPath::add() { - if (path == nullptr) - return true; - static const uint8_t gFlags[] = { - SkPathMeasure::kGetPosAndTan_MatrixFlag, // normal - SkPathMeasure::kGetTangent_MatrixFlag, // angle - SkPathMeasure::kGetPosition_MatrixFlag // position - }; - if ((unsigned)mode >= SK_ARRAY_COUNT(gFlags)) - return true; - SkMatrix result; - fPathMeasure.setPath(&path->getPath(), false); - if (fPathMeasure.getMatrix(offset, &result, (SkPathMeasure::MatrixFlags)gFlags[mode])) - fMatrix->set(result); - return false; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkRectToRect::fInfo[] = { - SK_MEMBER(destination, Rect), - SK_MEMBER(source, Rect) -}; - -#endif - -DEFINE_GET_MEMBER(SkRectToRect); - -SkRectToRect::SkRectToRect() : - source(nullptr), destination(nullptr) { -} - -SkRectToRect::~SkRectToRect() { -} - -bool SkRectToRect::add() { - if (source == nullptr || destination == nullptr) - return true; - SkMatrix temp; - temp.setRectToRect(source->fRect, destination->fRect, - SkMatrix::kFill_ScaleToFit); - fMatrix->set(temp); - return false; -} - -#ifdef SK_DUMP_ENABLED -void SkRectToRect::dump(SkAnimateMaker* maker) { - dumpBase(maker); - SkDebugf("/>\n"); - SkDisplayList::fIndent += 4; - if (source) { - SkDebugf("%*s\n", SkDisplayList::fIndent, ""); - SkDisplayList::fIndent += 4; - source->dump(maker); - SkDisplayList::fIndent -= 4; - SkDebugf("%*s\n", SkDisplayList::fIndent, ""); - } - if (destination) { - SkDebugf("%*s\n", SkDisplayList::fIndent, ""); - SkDisplayList::fIndent += 4; - destination->dump(maker); - SkDisplayList::fIndent -= 4; - SkDebugf("%*s\n", SkDisplayList::fIndent, ""); - } - SkDisplayList::fIndent -= 4; - dumpEnd(maker); -} -#endif - -const SkMemberInfo* SkRectToRect::preferredChild(SkDisplayTypes ) { - if (source == nullptr) - return getMember("source"); // !!! cwap! need to refer to member through enum like kScope instead - else { - SkASSERT(destination == nullptr); - return getMember("destination"); - } -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkPolyToPoly::fInfo[] = { - SK_MEMBER(destination, Polygon), - SK_MEMBER(source, Polygon) -}; - -#endif - -DEFINE_GET_MEMBER(SkPolyToPoly); - -SkPolyToPoly::SkPolyToPoly() : source(nullptr), destination(nullptr) { -} - -SkPolyToPoly::~SkPolyToPoly() { -} - -bool SkPolyToPoly::add() { - SkASSERT(source); - SkASSERT(destination); - SkPoint src[4]; - SkPoint dst[4]; - SkPath& sourcePath = source->getPath(); - int srcPts = sourcePath.getPoints(src, 4); - SkPath& destPath = destination->getPath(); - int dstPts = destPath.getPoints(dst, 4); - if (srcPts != dstPts) - return true; - SkMatrix temp; - temp.setPolyToPoly(src, dst, srcPts); - fMatrix->set(temp); - return false; -} - -#ifdef SK_DUMP_ENABLED -void SkPolyToPoly::dump(SkAnimateMaker* maker) { - dumpBase(maker); - SkDebugf("/>\n"); - SkDisplayList::fIndent += 4; - if (source) { - SkDebugf("%*s\n", SkDisplayList::fIndent, ""); - SkDisplayList::fIndent += 4; - source->dump(maker); - SkDisplayList::fIndent -= 4; - SkDebugf("%*s\n", SkDisplayList::fIndent, ""); - } - if (destination) { - SkDebugf("%*s\n", SkDisplayList::fIndent, ""); - SkDisplayList::fIndent += 4; - destination->dump(maker); - SkDisplayList::fIndent -= 4; - SkDebugf("%*s\n", SkDisplayList::fIndent, ""); - } - SkDisplayList::fIndent -= 4; - dumpEnd(maker); -} -#endif - -void SkPolyToPoly::onEndElement(SkAnimateMaker& ) { - SkASSERT(source); - SkASSERT(destination); - if (source->childHasID() || destination->childHasID()) - fMatrix->setChildHasID(); -} - -const SkMemberInfo* SkPolyToPoly::preferredChild(SkDisplayTypes ) { - if (source == nullptr) - return getMember("source"); // !!! cwap! need to refer to member through enum like kScope instead - else { - SkASSERT(destination == nullptr); - return getMember("destination"); - } -} diff --git a/gfx/skia/skia/src/animator/SkMatrixParts.h b/gfx/skia/skia/src/animator/SkMatrixParts.h deleted file mode 100644 index 3276d023d4e6..000000000000 --- a/gfx/skia/skia/src/animator/SkMatrixParts.h +++ /dev/null @@ -1,119 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkMatrixParts_DEFINED -#define SkMatrixParts_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" -#include "SkPathMeasure.h" - -class SkDrawPath; -class SkDrawRect; -class SkPolygon; - -class SkDrawMatrix; -// class SkMatrix; - -class SkMatrixPart : public SkDisplayable { -public: - SkMatrixPart(); - virtual bool add() = 0; - virtual void dirty(); - virtual SkDisplayable* getParent() const; - virtual bool setParent(SkDisplayable* parent); -#ifdef SK_DEBUG - virtual bool isMatrixPart() const { return true; } -#endif -protected: - SkDrawMatrix* fMatrix; -}; - -class SkRotate : public SkMatrixPart { - DECLARE_MEMBER_INFO(Rotate); - SkRotate(); -protected: - bool add() override; - SkScalar degrees; - SkPoint center; -}; - -class SkScale : public SkMatrixPart { - DECLARE_MEMBER_INFO(Scale); - SkScale(); -protected: - bool add() override; - SkScalar x; - SkScalar y; - SkPoint center; -}; - -class SkSkew : public SkMatrixPart { - DECLARE_MEMBER_INFO(Skew); - SkSkew(); -protected: - bool add() override; - SkScalar x; - SkScalar y; - SkPoint center; -}; - -class SkTranslate : public SkMatrixPart { - DECLARE_MEMBER_INFO(Translate); - SkTranslate(); -protected: - bool add() override; - SkScalar x; - SkScalar y; -}; - -class SkFromPath : public SkMatrixPart { - DECLARE_MEMBER_INFO(FromPath); - SkFromPath(); - virtual ~SkFromPath(); -protected: - bool add() override; - int32_t mode; - SkScalar offset; - SkDrawPath* path; - SkPathMeasure fPathMeasure; -}; - -class SkRectToRect : public SkMatrixPart { - DECLARE_MEMBER_INFO(RectToRect); - SkRectToRect(); - virtual ~SkRectToRect(); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - const SkMemberInfo* preferredChild(SkDisplayTypes type) override; -protected: - bool add() override; - SkDrawRect* source; - SkDrawRect* destination; -}; - -class SkPolyToPoly : public SkMatrixPart { - DECLARE_MEMBER_INFO(PolyToPoly); - SkPolyToPoly(); - virtual ~SkPolyToPoly(); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker* ) override; -#endif - void onEndElement(SkAnimateMaker& ) override; - const SkMemberInfo* preferredChild(SkDisplayTypes type) override; -protected: - bool add() override; - SkPolygon* source; - SkPolygon* destination; -}; - -// !!! add concat matrix ? - -#endif // SkMatrixParts_DEFINED diff --git a/gfx/skia/skia/src/animator/SkMemberInfo.cpp b/gfx/skia/skia/src/animator/SkMemberInfo.cpp deleted file mode 100644 index ea4c257b1021..000000000000 --- a/gfx/skia/skia/src/animator/SkMemberInfo.cpp +++ /dev/null @@ -1,559 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkMemberInfo.h" -#include "SkAnimateMaker.h" -#include "SkAnimatorScript.h" -#include "SkBase64.h" -#include "SkCamera.h" -#include "SkDisplayable.h" -#include "SkDisplayTypes.h" -#include "SkDraw3D.h" -#include "SkDrawColor.h" -#include "SkParse.h" -#include "SkScript.h" -#include "SkTSearch.h" -#include "SkTypedArray.h" - -size_t SkMemberInfo::GetSize(SkDisplayTypes type) { // size of simple types only - size_t byteSize; - switch (type) { - case SkType_ARGB: - byteSize = sizeof(SkColor); - break; - case SkType_AddMode: - case SkType_Align: - case SkType_ApplyMode: - case SkType_ApplyTransition: - case SkType_BitmapEncoding: - case SkType_Boolean: - case SkType_Cap: - case SkType_EventCode: - case SkType_EventKind: - case SkType_EventMode: - case SkType_FilterType: - case SkType_FontStyle: - case SkType_FromPathMode: - case SkType_Join: - case SkType_MaskFilterBlurStyle: - case SkType_PathDirection: - case SkType_Style: - case SkType_TileMode: - case SkType_Xfermode: - byteSize = sizeof(int); - break; - case SkType_Base64: // assume base64 data is always const, copied by ref - case SkType_Displayable: - case SkType_Drawable: - case SkType_Matrix: - byteSize = sizeof(void*); - break; - case SkType_MSec: - byteSize = sizeof(SkMSec); - break; - case SkType_Point: - byteSize = sizeof(SkPoint); - break; - case SkType_3D_Point: - byteSize = sizeof(Sk3D_Point); - break; - case SkType_Int: - byteSize = sizeof(int32_t); - break; - case SkType_Float: - byteSize = sizeof(SkScalar); - break; - case SkType_DynamicString: - case SkType_String: - byteSize = sizeof(SkString); // assume we'll copy by reference, not value - break; - default: -// SkASSERT(0); - byteSize = 0; - } - return byteSize; -} - -bool SkMemberInfo::getArrayValue(const SkDisplayable* displayable, int index, SkOperand* value) const { - SkASSERT(fType != SkType_String && fType != SkType_MemberProperty); - char* valuePtr = (char*) *(SkOperand**) memberData(displayable); - SkDisplayTypes type = (SkDisplayTypes) 0; - if (displayable->getType() == SkType_Array) { - SkDisplayArray* dispArray = (SkDisplayArray*) displayable; - if (dispArray->values.count() <= index) - return false; - type = dispArray->values.getType(); - } else { - SkASSERT(0); // incomplete - } - size_t byteSize = GetSize(type); - memcpy(value, valuePtr + index * byteSize, byteSize); - return true; -} - -size_t SkMemberInfo::getSize(const SkDisplayable* displayable) const { - size_t byteSize; - switch (fType) { - case SkType_MemberProperty: - byteSize = GetSize(propertyType()); - break; - case SkType_Array: { - SkDisplayTypes type; - if (displayable == nullptr) - return sizeof(int); - if (displayable->getType() == SkType_Array) { - SkDisplayArray* dispArray = (SkDisplayArray*) displayable; - type = dispArray->values.getType(); - } else - type = propertyType(); - SkTDOperandArray* array = (SkTDOperandArray*) memberData(displayable); - byteSize = GetSize(type) * array->count(); - } break; - default: - byteSize = GetSize((SkDisplayTypes) fType); - } - return byteSize; -} - -void SkMemberInfo::getString(const SkDisplayable* displayable, SkString** string) const { - if (fType == SkType_MemberProperty) { - SkScriptValue value; - displayable->getProperty(propertyIndex(), &value); - SkASSERT(value.fType == SkType_String); - *string = value.fOperand.fString; - return; - } - SkASSERT(fCount == sizeof(SkString) / sizeof(SkScalar)); - SkASSERT(fType == SkType_String || fType == SkType_DynamicString); - void* valuePtr = memberData(displayable); - *string = (SkString*) valuePtr; -} - -void SkMemberInfo::getValue(const SkDisplayable* displayable, SkOperand value[], int count) const { - SkASSERT(fType != SkType_String && fType != SkType_MemberProperty); - SkASSERT(count == fCount); - void* valuePtr = memberData(displayable); - size_t byteSize = getSize(displayable); - SkASSERT(sizeof(value[0].fScalar) == sizeof(value[0])); // no support for 64 bit pointers, yet - memcpy(value, valuePtr, byteSize); -} - -void SkMemberInfo::setString(SkDisplayable* displayable, SkString* value) const { - SkString* string = (SkString*) memberData(displayable); - string->set(*value); - displayable->dirty(); -} - -void SkMemberInfo::setValue(SkDisplayable* displayable, const SkOperand values[], - int count) const { - SkASSERT(sizeof(values[0].fScalar) == sizeof(values[0])); // no support for 64 bit pointers, yet - char* dst = (char*) memberData(displayable); - if (fType == SkType_Array) { - SkTDScalarArray* array = (SkTDScalarArray* ) dst; - array->setCount(count); - dst = (char*) array->begin(); - } - memcpy(dst, values, count * sizeof(SkOperand)); - displayable->dirty(); -} - - -static inline bool is_between(int c, int min, int max) -{ - return (unsigned)(c - min) <= (unsigned)(max - min); -} - -static inline bool is_hex(int c) -{ - if (is_between(c, '0', '9')) - return true; - c |= 0x20; // make us lower-case - if (is_between(c, 'a', 'f')) - return true; - return false; -} - - -bool SkMemberInfo::setValue(SkAnimateMaker& maker, SkTDOperandArray* arrayStorage, - int storageOffset, int maxStorage, SkDisplayable* displayable, SkDisplayTypes outType, - const char rawValue[], size_t rawValueLen) const -{ - SkString valueStr(rawValue, rawValueLen); - SkScriptValue scriptValue; - scriptValue.fType = SkType_Unknown; - scriptValue.fOperand.fS32 = 0; - SkDisplayTypes type = getType(); - SkAnimatorScript engine(maker, displayable, type); - if (arrayStorage) - displayable = nullptr; - bool success = true; - void* untypedStorage = nullptr; - if (displayable && fType != SkType_MemberProperty && fType != SkType_MemberFunction) - untypedStorage = (SkTDOperandArray*) memberData(displayable); - - if (type == SkType_ARGB) { - // for both SpiderMonkey and SkiaScript, substitute any #xyz or #xxyyzz first - // it's enough to expand the colors into 0xFFxxyyzz - const char* poundPos; - while ((poundPos = strchr(valueStr.c_str(), '#')) != nullptr) { - size_t offset = poundPos - valueStr.c_str(); - if (valueStr.size() - offset < 4) - break; - char r = poundPos[1]; - char g = poundPos[2]; - char b = poundPos[3]; - if (is_hex(r) == false || is_hex(g) == false || is_hex(b) == false) - break; - char hex = poundPos[4]; - if (is_hex(hex) == false) { - valueStr.insertUnichar(offset + 1, r); - valueStr.insertUnichar(offset + 3, g); - valueStr.insertUnichar(offset + 5, b); - } - *(char*) poundPos = '0'; // overwrite '#' - valueStr.insert(offset + 1, "xFF"); - } - } - if (SkDisplayType::IsDisplayable(&maker, type) || SkDisplayType::IsEnum(&maker, type) || type == SkType_ARGB) - goto scriptCommon; - switch (type) { - case SkType_String: -#if 0 - if (displayable && displayable->isAnimate()) { - - goto noScriptString; - } - if (strncmp(rawValue, "#string:", sizeof("#string:") - 1) == 0) { - SkASSERT(sizeof("string") == sizeof("script")); - char* stringHeader = valueStr.writable_str(); - memcpy(&stringHeader[1], "script", sizeof("script") - 1); - rawValue = valueStr.c_str(); - goto noScriptString; - } else -#endif - if (strncmp(rawValue, "#script:", sizeof("#script:") - 1) != 0) - goto noScriptString; - valueStr.remove(0, 8); - case SkType_Unknown: - case SkType_Int: - case SkType_MSec: // for the purposes of script, MSec is treated as a Scalar - case SkType_Point: - case SkType_3D_Point: - case SkType_Float: - case SkType_Array: -scriptCommon: { - const char* script = valueStr.c_str(); - success = engine.evaluateScript(&script, &scriptValue); - if (success == false) { - maker.setScriptError(engine); - return false; - } - } - SkASSERT(success); - if (scriptValue.fType == SkType_Displayable) { - if (type == SkType_String) { - const char* charPtr = nullptr; - maker.findKey(scriptValue.fOperand.fDisplayable, &charPtr); - scriptValue.fOperand.fString = new SkString(charPtr); - scriptValue.fType = SkType_String; - engine.SkScriptEngine::track(scriptValue.fOperand.fString); - break; - } - SkASSERT(SkDisplayType::IsDisplayable(&maker, type)); - if (displayable) - displayable->setReference(this, scriptValue.fOperand.fDisplayable); - else - arrayStorage->begin()[0].fDisplayable = scriptValue.fOperand.fDisplayable; - return true; - } - if (type != scriptValue.fType) { - if (scriptValue.fType == SkType_Array) { - engine.forget(scriptValue.getArray()); - goto writeStruct; // real structs have already been written by script - } - switch (type) { - case SkType_String: - success = engine.convertTo(SkType_String, &scriptValue); - break; - case SkType_MSec: - case SkType_Float: - success = engine.convertTo(SkType_Float, &scriptValue); - break; - case SkType_Int: - success = engine.convertTo(SkType_Int, &scriptValue); - break; - case SkType_Array: - success = engine.convertTo(arrayType(), &scriptValue); - // !!! incomplete; create array of appropriate type and add scriptValue to it - SkASSERT(0); - break; - case SkType_Displayable: - case SkType_Drawable: - return false; // no way to convert other types to this - default: // to avoid warnings - break; - } - if (success == false) - return false; - } - if (type == SkType_MSec) - scriptValue.fOperand.fMSec = SkScalarRoundToInt(scriptValue.fOperand.fScalar * 1000); - scriptValue.fType = type; - break; - noScriptString: - case SkType_DynamicString: - if (fType == SkType_MemberProperty && displayable) { - SkString string(rawValue, rawValueLen); - SkScriptValue scriptValue; - scriptValue.fOperand.fString = &string; - scriptValue.fType = SkType_String; - displayable->setProperty(propertyIndex(), scriptValue); - } else if (displayable) { - SkString* string = (SkString*) memberData(displayable); - string->set(rawValue, rawValueLen); - } else { - SkASSERT(arrayStorage->count() == 1); - arrayStorage->begin()->fString->set(rawValue, rawValueLen); - } - goto dirty; - case SkType_Base64: { - SkBase64 base64; - base64.decode(rawValue, rawValueLen); - *(SkBase64* ) untypedStorage = base64; - } goto dirty; - default: - SkASSERT(0); - break; - } -// if (SkDisplayType::IsStruct(type) == false) - { -writeStruct: - if (writeValue(displayable, arrayStorage, storageOffset, maxStorage, - untypedStorage, outType, scriptValue)) { - maker.setErrorCode(SkDisplayXMLParserError::kUnexpectedType); - return false; - } - } -dirty: - if (displayable) - displayable->dirty(); - return true; -} - -bool SkMemberInfo::setValue(SkAnimateMaker& maker, SkTDOperandArray* arrayStorage, - int storageOffset, int maxStorage, SkDisplayable* displayable, SkDisplayTypes outType, - SkString& raw) const { - return setValue(maker, arrayStorage, storageOffset, maxStorage, displayable, outType, raw.c_str(), - raw.size()); -} - -bool SkMemberInfo::writeValue(SkDisplayable* displayable, SkTDOperandArray* arrayStorage, - int storageOffset, int maxStorage, void* untypedStorage, SkDisplayTypes outType, - SkScriptValue& scriptValue) const -{ - SkOperand* storage = untypedStorage ? (SkOperand*) untypedStorage : arrayStorage ? - arrayStorage->begin() : nullptr; - if (storage) - storage += storageOffset; - SkDisplayTypes type = getType(); - if (fType == SkType_MemberProperty) { - if(displayable) - displayable->setProperty(propertyIndex(), scriptValue); - else { - SkASSERT(storageOffset < arrayStorage->count()); - switch (scriptValue.fType) { - case SkType_Boolean: - case SkType_Float: - case SkType_Int: - memcpy(&storage->fScalar, &scriptValue.fOperand.fScalar, sizeof(SkScalar)); - break; - case SkType_Array: - memcpy(&storage->fScalar, scriptValue.fOperand.fArray->begin(), scriptValue.fOperand.fArray->count() * sizeof(SkScalar)); - break; - case SkType_String: - storage->fString->set(*scriptValue.fOperand.fString); - break; - default: - SkASSERT(0); // type isn't handled yet - } - } - } else if (fType == SkType_MemberFunction) { - SkASSERT(scriptValue.fType == SkType_Array); - if (displayable) - displayable->executeFunction(displayable, this, scriptValue.fOperand.fArray, nullptr); - else { - int count = scriptValue.fOperand.fArray->count(); - // SkASSERT(maxStorage == 0 || count == maxStorage); - if (arrayStorage->count() == 2) - arrayStorage->setCount(2 * count); - else { - storageOffset *= count; - SkASSERT(count + storageOffset <= arrayStorage->count()); - } - memcpy(&(*arrayStorage)[storageOffset], scriptValue.fOperand.fArray->begin(), count * sizeof(SkOperand)); - } - - } else if (fType == SkType_Array) { - SkTypedArray* destArray = (SkTypedArray*) (untypedStorage ? untypedStorage : arrayStorage); - SkASSERT(destArray); - // destArray->setCount(0); - if (scriptValue.fType != SkType_Array) { - SkASSERT(type == scriptValue.fType); - // SkASSERT(storageOffset + 1 <= maxStorage); - destArray->setCount(storageOffset + 1); - (*destArray)[storageOffset] = scriptValue.fOperand; - } else { - if (type == SkType_Unknown) { - type = scriptValue.fOperand.fArray->getType(); - destArray->setType(type); - } - SkASSERT(type == scriptValue.fOperand.fArray->getType()); - int count = scriptValue.fOperand.fArray->count(); - // SkASSERT(storageOffset + count <= maxStorage); - destArray->setCount(storageOffset + count); - memcpy(destArray->begin() + storageOffset, scriptValue.fOperand.fArray->begin(), sizeof(SkOperand) * count); - } - } else if (type == SkType_String) { - SkString* string = untypedStorage ? (SkString*) untypedStorage : (*arrayStorage)[storageOffset].fString; - string->set(*scriptValue.fOperand.fString); - } else if (type == SkType_ARGB && outType == SkType_Float) { - SkTypedArray* array = scriptValue.fOperand.fArray; - SkASSERT(scriptValue.fType == SkType_Int || scriptValue.fType == SkType_ARGB || - scriptValue.fType == SkType_Array); - SkASSERT(scriptValue.fType != SkType_Array || (array != nullptr && - array->getType() == SkType_Int)); - int numberOfColors = scriptValue.fType == SkType_Array ? array->count() : 1; - int numberOfComponents = numberOfColors * 4; - // SkASSERT(maxStorage == 0 || maxStorage == numberOfComponents); - if (maxStorage == 0) - arrayStorage->setCount(numberOfComponents); - for (int index = 0; index < numberOfColors; index++) { - SkColor color = scriptValue.fType == SkType_Array ? - (SkColor) array->begin()[index].fS32 : (SkColor) scriptValue.fOperand.fS32; - storage[0].fScalar = SkIntToScalar(SkColorGetA(color)); - storage[1].fScalar = SkIntToScalar(SkColorGetR(color)); - storage[2].fScalar = SkIntToScalar(SkColorGetG(color)); - storage[3].fScalar = SkIntToScalar(SkColorGetB(color)); - storage += 4; - } - } else if (SkDisplayType::IsStruct(nullptr /* !!! maker*/, type)) { - if (scriptValue.fType != SkType_Array) - return true; // error - SkASSERT(sizeof(SkScalar) == sizeof(SkOperand)); // !!! no 64 bit pointer support yet - int count = scriptValue.fOperand.fArray->count(); - if (count > 0) { - SkASSERT(fCount == count); - memcpy(storage, scriptValue.fOperand.fArray->begin(), count * sizeof(SkOperand)); - } - } else if (scriptValue.fType == SkType_Array) { - SkASSERT(scriptValue.fOperand.fArray->getType() == type); - SkASSERT(scriptValue.fOperand.fArray->count() == getCount()); - memcpy(storage, scriptValue.fOperand.fArray->begin(), getCount() * sizeof(SkOperand)); - } else { - memcpy(storage, &scriptValue.fOperand, sizeof(SkOperand)); - } - return false; -} - - -//void SkMemberInfo::setValue(SkDisplayable* displayable, const char value[], const char name[]) const { -// void* valuePtr = (void*) ((char*) displayable + fOffset); -// switch (fType) { -// case SkType_Point3D: { -// static const char xyz[] = "x|y|z"; -// int index = find_one(xyz, name); -// SkASSERT(index >= 0); -// valuePtr = (void*) ((char*) valuePtr + index * sizeof(SkScalar)); -// } break; -// default: -// SkASSERT(0); -// } -// SkParse::FindScalar(value, (SkScalar*) valuePtr); -// displayable->dirty(); -//} - -#if SK_USE_CONDENSED_INFO == 0 - -// Find Nth memberInfo -const SkMemberInfo* SkMemberInfo::Find(const SkMemberInfo info[], int count, int* index) { - SkASSERT(*index >= 0); - if (info->fType == SkType_BaseClassInfo) { - const SkMemberInfo* inherited = (SkMemberInfo*) info->fName; - const SkMemberInfo* result = SkMemberInfo::Find(inherited, info->fCount, index); - if (result != nullptr) - return result; - if (--count == 0) - return nullptr; - info++; - } - SkASSERT(info->fName); - SkASSERT(info->fType != SkType_BaseClassInfo); - if (*index >= count) { - *index -= count; - return nullptr; - } - return &info[*index]; -} - -// Find named memberinfo -const SkMemberInfo* SkMemberInfo::Find(const SkMemberInfo info[], int count, const char** matchPtr) { - const char* match = *matchPtr; - if (info->fType == SkType_BaseClassInfo) { - const SkMemberInfo* inherited = (SkMemberInfo*) info->fName; - const SkMemberInfo* result = SkMemberInfo::Find(inherited, info->fCount, matchPtr); - if (result != nullptr) - return result; - if (--count == 0) - return nullptr; - info++; - } - SkASSERT(info->fName); - SkASSERT(info->fType != SkType_BaseClassInfo); - int index = SkStrSearch(&info->fName, count, match, sizeof(*info)); - if (index < 0 || index >= count) - return nullptr; - return &info[index]; -} - -const SkMemberInfo* SkMemberInfo::getInherited() const { - return (SkMemberInfo*) fName; -} - -#endif // SK_USE_CONDENSED_INFO == 0 - -#if 0 -bool SkMemberInfo::SetValue(void* valuePtr, const char value[], SkDisplayTypes type, - int count) { - switch (type) { - case SkType_Animate: - case SkType_BaseBitmap: - case SkType_Bitmap: - case SkType_Dash: - case SkType_Displayable: - case SkType_Drawable: - case SkType_Matrix: - case SkType_Path: - case SkType_Text: - case SkType_3D_Patch: - return false; // ref to object; caller must resolve - case SkType_MSec: { - SkParse::FindMSec(value, (SkMSec*) valuePtr); - } break; - case SkType_3D_Point: - case SkType_Point: - // case SkType_PointArray: - case SkType_ScalarArray: - SkParse::FindScalars(value, (SkScalar*) valuePtr, count); - break; - default: - SkASSERT(0); - } - return true; -} -#endif diff --git a/gfx/skia/skia/src/animator/SkMemberInfo.h b/gfx/skia/skia/src/animator/SkMemberInfo.h deleted file mode 100644 index 709d66ac84f4..000000000000 --- a/gfx/skia/skia/src/animator/SkMemberInfo.h +++ /dev/null @@ -1,276 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkMemberInfo_DEFINED -#define SkMemberInfo_DEFINED - -#if defined SK_BUILD_CONDENSED - #define SK_USE_CONDENSED_INFO 0 -#endif - -#include "SkDisplayType.h" -#include "SkScript.h" -#include "SkString.h" -#include "SkIntArray.h" -#include - -class SkAnimateMaker; -class SkDisplayable; -class SkScriptEngine; - -// temporary hacks until name change is more complete -#define SkFloat SkScalar -#define SkInt SkS32 - -struct SkMemberInfo { - //!!! alternative: - // if fCount == 0, record is member property - // then fType can be type, so caller doesn't have to check -#if SK_USE_CONDENSED_INFO == 0 - const char* fName; // may be nullptr for anonymous functions - size_t fOffset; // if negative, is index into member pointer table (for properties and functions) - SkDisplayTypes fType; - int fCount; // for properties, actual type (count is always assumed to be 1) -#else - unsigned char fName; - signed char fOffset; - unsigned char fType; - signed char fCount; -#endif - SkDisplayTypes arrayType() const { - SkASSERT(fType == SkType_Array); - return (SkDisplayTypes) fCount; // hack, but worth it? - } - int functionIndex() const { - SkASSERT(fType == SkType_MemberFunction); - return (signed) fOffset > 0 ? -1 + (int) fOffset : -1 - (int) fOffset; - } - bool getArrayValue(const SkDisplayable* displayable, int index, SkOperand* value) const; - int getCount() const { - return fType == SkType_MemberProperty || fType == SkType_Array || - fType == SkType_MemberFunction ? 1 : fCount; - } - const SkMemberInfo* getInherited() const; - size_t getSize(const SkDisplayable* ) const; - void getString(const SkDisplayable* , SkString** string) const; - SkDisplayTypes getType() const { - return fType == SkType_MemberProperty || fType == SkType_Array || - fType == SkType_MemberFunction ? (SkDisplayTypes) fCount : (SkDisplayTypes) fType; - } - void getValue(const SkDisplayable* , SkOperand values[], int count) const; - bool isEnum() const; - const char* mapEnums(const char* match, int* value) const; - void* memberData(const SkDisplayable* displayable) const { - SkASSERT(fType != SkType_MemberProperty && fType != SkType_MemberFunction); - return (void*) ((const char*) displayable + fOffset); - } - int propertyIndex() const { - SkASSERT(fType == SkType_MemberProperty); - return (signed) fOffset > 0 ? -1 + (int) fOffset : -1 - (int) fOffset; - } - SkDisplayTypes propertyType() const { - SkASSERT(fType == SkType_MemberProperty || fType == SkType_Array); - return (SkDisplayTypes) fCount; // hack, but worth it? - } - void setMemberData(SkDisplayable* displayable, const void* child, size_t size) const { - SkASSERT(fType != SkType_MemberProperty && fType != SkType_MemberFunction); - memcpy((char*) displayable + fOffset, child, size); - } - void setString(SkDisplayable* , SkString* ) const; - void setValue(SkDisplayable* , const SkOperand values[], int count) const; - bool setValue(SkAnimateMaker& , SkTDOperandArray* storage, - int storageOffset, int maxStorage, SkDisplayable* , - SkDisplayTypes outType, const char value[], size_t len) const; - bool setValue(SkAnimateMaker& , SkTDOperandArray* storage, - int storageOffset, int maxStorage, SkDisplayable* , - SkDisplayTypes outType, SkString& str) const; -// void setValue(SkDisplayable* , const char value[], const char name[]) const; - bool writeValue(SkDisplayable* displayable, SkTDOperandArray* arrayStorage, - int storageOffset, int maxStorage, void* untypedStorage, SkDisplayTypes outType, - SkScriptValue& scriptValue) const; -#if SK_USE_CONDENSED_INFO == 0 - static const SkMemberInfo* Find(const SkMemberInfo [], int count, int* index); - static const SkMemberInfo* Find(const SkMemberInfo [], int count, const char** name); -#else - static const SkMemberInfo* Find(SkDisplayTypes type, int* index); - static const SkMemberInfo* Find(SkDisplayTypes type, const char** name); -#endif - static size_t GetSize(SkDisplayTypes type); // size of simple types only -// static bool SetValue(void* value, const char* name, SkDisplayTypes , int count); -}; - -#ifndef SK_OFFSETOF - // This is offsetof for types which are not standard layout. - #define SK_OFFSETOF(type, field) (size_t)((char*)&(((type*)1024)->field) - (char*)1024) -#endif - -#define SK_MEMBER(_member, _type) \ - { #_member, SK_OFFSETOF(BASE_CLASS, _member), SkType_##_type, \ - sizeof(std::declval()._member) / sizeof(SkScalar) } - -#define SK_MEMBER_ALIAS(_member, _alias, _type) \ - { #_member, SK_OFFSETOF(BASE_CLASS, _alias), SkType_##_type, \ - sizeof(std::declval()._alias) / sizeof(SkScalar) } - -#define SK_MEMBER_ARRAY(_member, _type) \ - { #_member, SK_OFFSETOF(BASE_CLASS, _member), SkType_Array, \ - (int) SkType_##_type } - -#define SK_MEMBER_INHERITED \ - { (const char*) INHERITED::fInfo, 0, SkType_BaseClassInfo, INHERITED::fInfoCount } - -// #define SK_MEMBER_KEY_TYPE(_member, _type) -// {#_member, (size_t) -1, SkType_##_type, 0} - -#define SK_FUNCTION(_member) \ - k_##_member##Function - -#define SK_PROPERTY(_member) \ - k_##_member##Property - -#define SK_MEMBER_DYNAMIC_FUNCTION(_member, _type) \ - {#_member, (size_t) (+1 + SK_FUNCTION(_member)), SkType_MemberFunction, \ - (int) SkType_##_type } - -#define SK_MEMBER_DYNAMIC_PROPERTY(_member, _type) \ - {#_member, (size_t) (1 + SK_PROPERTY(_member)), SkType_MemberProperty, \ - (int) SkType_##_type } - -#define SK_MEMBER_FUNCTION(_member, _type) \ - {#_member, (size_t) (-1 - SK_FUNCTION(_member)), SkType_MemberFunction, \ - (int) SkType_##_type } - -#define SK_MEMBER_PROPERTY(_member, _type) \ - {#_member, (size_t) (-1 - SK_PROPERTY(_member)), SkType_MemberProperty, \ - (int) SkType_##_type } - -#if SK_USE_CONDENSED_INFO == 0 - -#define DECLARE_PRIVATE_MEMBER_INFO(_type) \ -public: \ - static const SkMemberInfo fInfo[]; \ - static const int fInfoCount; \ - const SkMemberInfo* getMember(int index) override; \ - const SkMemberInfo* getMember(const char name[]) override; \ - typedef Sk##_type BASE_CLASS - -#define DECLARE_MEMBER_INFO(_type) \ -public: \ - static const SkMemberInfo fInfo[]; \ - static const int fInfoCount; \ - const SkMemberInfo* getMember(int index) override; \ - const SkMemberInfo* getMember(const char name[]) override; \ - SkDisplayTypes getType() const override { return SkType_##_type; } \ - typedef Sk##_type BASE_CLASS - -#define DECLARE_DRAW_MEMBER_INFO(_type) \ -public: \ - static const SkMemberInfo fInfo[]; \ - static const int fInfoCount; \ - const SkMemberInfo* getMember(int index) override; \ - const SkMemberInfo* getMember(const char name[]) override; \ - SkDisplayTypes getType() const override { return SkType_##_type; } \ - typedef SkDraw##_type BASE_CLASS - -#define DECLARE_DISPLAY_MEMBER_INFO(_type) \ -public: \ - static const SkMemberInfo fInfo[]; \ - static const int fInfoCount; \ - const SkMemberInfo* getMember(int index) override; \ - const SkMemberInfo* getMember(const char name[]) override; \ - SkDisplayTypes getType() const override { return SkType_##_type; } \ - typedef SkDisplay##_type BASE_CLASS - -#define DECLARE_EMPTY_MEMBER_INFO(_type) \ -public: \ - SkDisplayTypes getType() const override { return SkType_##_type; } - -#define DECLARE_EXTRAS_MEMBER_INFO(_type) \ -public: \ - static const SkMemberInfo fInfo[]; \ - static const int fInfoCount; \ - const SkMemberInfo* getMember(int index) override; \ - const SkMemberInfo* getMember(const char name[]) override; \ - SkDisplayTypes fType; \ - SkDisplayTypes getType() const override { return fType; } \ - typedef _type BASE_CLASS - -#define DECLARE_NO_VIRTUALS_MEMBER_INFO(_type) \ -public: \ - static const SkMemberInfo fInfo[]; \ - static const int fInfoCount; \ - typedef Sk##_type BASE_CLASS - -#define DEFINE_GET_MEMBER(_class) \ - const SkMemberInfo* _class::getMember(int index) { \ - const SkMemberInfo* result = SkMemberInfo::Find(fInfo, SK_ARRAY_COUNT(fInfo), &index); \ - return result; \ - } \ - const SkMemberInfo* _class::getMember(const char name[]) { \ - const SkMemberInfo* result = SkMemberInfo::Find(fInfo, SK_ARRAY_COUNT(fInfo), &name); \ - return result; \ - } \ - const int _class::fInfoCount = SK_ARRAY_COUNT(fInfo) - -#define DEFINE_NO_VIRTUALS_GET_MEMBER(_class) \ - const int _class::fInfoCount = SK_ARRAY_COUNT(fInfo) - -#else - -#define DECLARE_PRIVATE_MEMBER_INFO(_type) \ -public: \ - typedef Sk##_type BASE_CLASS - -#define DECLARE_MEMBER_INFO(_type) \ -public: \ - virtual const SkMemberInfo* getMember(int index) { \ - return SkDisplayType::GetMember(nullptr, SkType_##_type, &index); } \ - virtual const SkMemberInfo* getMember(const char name[]) { \ - return SkDisplayType::GetMember(nullptr, SkType_##_type, &name); } \ - virtual SkDisplayTypes getType() const { return SkType_##_type; } \ - typedef Sk##_type BASE_CLASS - -#define DECLARE_DRAW_MEMBER_INFO(_type) \ -public: \ - virtual const SkMemberInfo* getMember(int index) { \ - return SkDisplayType::GetMember(nullptr, SkType_##_type, &index); } \ - virtual const SkMemberInfo* getMember(const char name[]) { \ - return SkDisplayType::GetMember(nullptr, SkType_##_type, &name); } \ - virtual SkDisplayTypes getType() const { return SkType_##_type; } \ - typedef SkDraw##_type BASE_CLASS - -#define DECLARE_DISPLAY_MEMBER_INFO(_type) \ -public: \ - virtual const SkMemberInfo* getMember(int index) { \ - return SkDisplayType::GetMember(nullptr, SkType_##_type, &index); } \ - virtual const SkMemberInfo* getMember(const char name[]) { \ - return SkDisplayType::GetMember(nullptr, SkType_##_type, &name); } \ - virtual SkDisplayTypes getType() const { return SkType_##_type; } \ - typedef SkDisplay##_type BASE_CLASS - -#define DECLARE_EXTRAS_MEMBER_INFO(_type) \ -public: \ - virtual const SkMemberInfo* getMember(int index) { \ - return SkDisplayType::GetMember(nullptr, SkType_##_type, &index); } \ - virtual const SkMemberInfo* getMember(const char name[]) { \ - return SkDisplayType::GetMember(nullptr, fType, &name); } \ - SkDisplayTypes fType; \ - virtual SkDisplayTypes getType() const { return fType; } \ - typedef _type BASE_CLASS - -#define DECLARE_NO_VIRTUALS_MEMBER_INFO(_type) \ -public: \ - typedef Sk##_type BASE_CLASS - -#define DEFINE_GET_MEMBER(_class) -#define DEFINE_NO_VIRTUALS_GET_MEMBER(_class) - -#endif - -#endif // SkMemberInfo_DEFINED diff --git a/gfx/skia/skia/src/animator/SkOpArray.cpp b/gfx/skia/skia/src/animator/SkOpArray.cpp deleted file mode 100644 index 94298cc83abe..000000000000 --- a/gfx/skia/skia/src/animator/SkOpArray.cpp +++ /dev/null @@ -1,23 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkOpArray.h" - -SkOpArray::SkOpArray() : fType(SkOperand2::kNoType) { -} - -SkOpArray::SkOpArray(SkOperand2::OpType type) : fType(type) { -} - -bool SkOpArray::getIndex(int index, SkOperand2* operand) { - if (index >= count()) { - SkASSERT(0); - return false; - } - *operand = begin()[index]; - return true; -} diff --git a/gfx/skia/skia/src/animator/SkOpArray.h b/gfx/skia/skia/src/animator/SkOpArray.h deleted file mode 100644 index 260bf78be09f..000000000000 --- a/gfx/skia/skia/src/animator/SkOpArray.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkOpArray_DEFINED -#define SkOpArray_DEFINED - -#include "SkOperand2.h" -#include "SkTDArray_Experimental.h" - -typedef SkLongArray(SkOperand2) SkTDOperand2Array; - -class SkOpArray : public SkTDOperand2Array { -public: - SkOpArray(); - SkOpArray(SkOperand2::OpType type); - bool getIndex(int index, SkOperand2* operand); - SkOperand2::OpType getType() { return fType; } - void setType(SkOperand2::OpType type) { - fType = type; - } -protected: - SkOperand2::OpType fType; -}; - -#endif // SkOpArray_DEFINED diff --git a/gfx/skia/skia/src/animator/SkOperand.h b/gfx/skia/skia/src/animator/SkOperand.h deleted file mode 100644 index 14126fccbfda..000000000000 --- a/gfx/skia/skia/src/animator/SkOperand.h +++ /dev/null @@ -1,46 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkOperand_DEFINED -#define SkOperand_DEFINED - -#include "SkDisplayType.h" - -class SkTypedArray; -class SkDisplayable; -class SkADrawable; -class SkString; - -union SkOperand { -// SkOperand() {} -// SkOperand(SkScalar scalar) : fScalar(scalar) {} - SkTypedArray* fArray; - SkDisplayable* fDisplayable; - SkADrawable* fDrawable; - void* fObject; - int32_t fS32; - SkMSec fMSec; - SkScalar fScalar; - SkString* fString; -}; - -struct SkScriptValue { - SkOperand fOperand; - SkDisplayTypes fType; - SkTypedArray* getArray() { SkASSERT(fType == SkType_Array); return fOperand.fArray; } - SkDisplayable* getDisplayable() { SkASSERT(fType == SkType_Displayable); return fOperand.fDisplayable; } - SkADrawable* getDrawable() { SkASSERT(fType == SkType_Drawable); return fOperand.fDrawable; } - int32_t getS32(SkAnimateMaker* maker) { SkASSERT(fType == SkType_Int || fType == SkType_Boolean || - SkDisplayType::IsEnum(maker, fType)); return fOperand.fS32; } - SkMSec getMSec() { SkASSERT(fType == SkType_MSec); return fOperand.fMSec; } - SkScalar getScalar() { SkASSERT(fType == SkType_Float); return fOperand.fScalar; } - SkString* getString() { SkASSERT(fType == SkType_String); return fOperand.fString; } -}; - -#endif // SkOperand_DEFINED diff --git a/gfx/skia/skia/src/animator/SkOperand2.h b/gfx/skia/skia/src/animator/SkOperand2.h deleted file mode 100644 index f844b6b4c986..000000000000 --- a/gfx/skia/skia/src/animator/SkOperand2.h +++ /dev/null @@ -1,54 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkOperand2_DEFINED -#define SkOperand2_DEFINED - -#include "SkScalar.h" - -class SkOpArray; -class SkString; - -union SkOperand2 { - enum OpType { - kNoType, - kS32 = 1, - kScalar = 2, - kString = 4, - kArray = 8, - kObject = 16 - }; - SkOpArray* fArray; - void* fObject; - size_t fReference; - int32_t fS32; - SkScalar fScalar; - SkString* fString; -}; - -struct SkScriptValue2 { - enum IsConstant { - kConstant, - kVariable - }; - enum IsWritten { - kUnwritten, - kWritten - }; - SkOperand2 fOperand; - SkOperand2::OpType fType : 8; - IsConstant fIsConstant : 8; - IsWritten fIsWritten : 8; - SkOpArray* getArray() { SkASSERT(fType == SkOperand2::kArray); return fOperand.fArray; } - void* getObject() { SkASSERT(fType == SkOperand2::kObject); return fOperand.fObject; } - int32_t getS32() { SkASSERT(fType == SkOperand2::kS32); return fOperand.fS32; } - SkScalar getScalar() { SkASSERT(fType == SkOperand2::kScalar); return fOperand.fScalar; } - SkString* getString() { SkASSERT(fType == SkOperand2::kString); return fOperand.fString; } - bool isConstant() const { return fIsConstant == kConstant; } -}; - -#endif // SkOperand2_DEFINED diff --git a/gfx/skia/skia/src/animator/SkOperandInterpolator.h b/gfx/skia/skia/src/animator/SkOperandInterpolator.h deleted file mode 100644 index adbe69f167bd..000000000000 --- a/gfx/skia/skia/src/animator/SkOperandInterpolator.h +++ /dev/null @@ -1,47 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkOperandInterpolator_DEFINED -#define SkOperandInterpolator_DEFINED - -#include "SkDisplayType.h" -#include "SkInterpolator.h" -#include "SkOperand.h" - -class SkOperandInterpolator : public SkInterpolatorBase { -public: - SkOperandInterpolator(); - SkOperandInterpolator(int elemCount, int frameCount, SkDisplayTypes type); - SkOperand* getValues() { return fValues; } - int getValuesCount() { return fFrameCount * fElemCount; } - void reset(int elemCount, int frameCount, SkDisplayTypes type); - - /** Add or replace a key frame, copying the values[] data into the interpolator. - @param index The index of this frame (frames must be ordered by time) - @param time The millisecond time for this frame - @param values The array of values [elemCount] for this frame. The data is copied - into the interpolator. - @param blend A positive scalar specifying how to blend between this and the next key frame. - [0...1) is a cubic lag/log/lag blend (slow to change at the beginning and end) - 1 is a linear blend (default) - (1...inf) is a cubic log/lag/log blend (fast to change at the beginning and end) - */ - bool setKeyFrame(int index, SkMSec time, const SkOperand values[], SkScalar blend = SK_Scalar1); - Result timeToValues(SkMSec time, SkOperand values[]) const; - SkDEBUGCODE(static void UnitTest();) -private: - SkDisplayTypes fType; - SkOperand* fValues; // pointer into fStorage -#ifdef SK_DEBUG - SkOperand(* fValuesArray)[10]; -#endif - typedef SkInterpolatorBase INHERITED; -}; - -#endif // SkOperandInterpolator_DEFINED diff --git a/gfx/skia/skia/src/animator/SkOperandIterpolator.cpp b/gfx/skia/skia/src/animator/SkOperandIterpolator.cpp deleted file mode 100644 index 89ac44dea239..000000000000 --- a/gfx/skia/skia/src/animator/SkOperandIterpolator.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkOperandInterpolator.h" -#include "SkScript.h" - -SkOperandInterpolator::SkOperandInterpolator() { - INHERITED::reset(0, 0); - fType = SkType_Unknown; -} - -SkOperandInterpolator::SkOperandInterpolator(int elemCount, int frameCount, - SkDisplayTypes type) -{ - this->reset(elemCount, frameCount, type); -} - -void SkOperandInterpolator::reset(int elemCount, int frameCount, SkDisplayTypes type) -{ -// SkASSERT(type == SkType_String || type == SkType_Float || type == SkType_Int || -// type == SkType_Displayable || type == SkType_Drawable); - INHERITED::reset(elemCount, frameCount); - fType = type; - fStorage = sk_malloc_throw((sizeof(SkOperand) * elemCount + sizeof(SkTimeCode)) * frameCount); - fTimes = (SkTimeCode*) fStorage; - fValues = (SkOperand*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount); -#ifdef SK_DEBUG - fTimesArray = (SkTimeCode(*)[10]) fTimes; - fValuesArray = (SkOperand(*)[10]) fValues; -#endif -} - -bool SkOperandInterpolator::setKeyFrame(int index, SkMSec time, const SkOperand values[], SkScalar blend) -{ - SkASSERT(values != nullptr); - blend = SkScalarPin(blend, 0, SK_Scalar1); - - bool success = ~index == SkTSearch(&fTimes->fTime, index, time, sizeof(SkTimeCode)); - SkASSERT(success); - if (success) { - SkTimeCode* timeCode = &fTimes[index]; - timeCode->fTime = time; - timeCode->fBlend[0] = SK_Scalar1 - blend; - timeCode->fBlend[1] = 0; - timeCode->fBlend[2] = 0; - timeCode->fBlend[3] = SK_Scalar1 - blend; - SkOperand* dst = &fValues[fElemCount * index]; - memcpy(dst, values, fElemCount * sizeof(SkOperand)); - } - return success; -} - -SkInterpolatorBase::Result SkOperandInterpolator::timeToValues(SkMSec time, SkOperand values[]) const -{ - SkScalar T; - int index; - bool exact; - Result result = timeToT(time, &T, &index, &exact); - if (values) - { - const SkOperand* nextSrc = &fValues[index * fElemCount]; - - if (exact) - memcpy(values, nextSrc, fElemCount * sizeof(SkScalar)); - else - { - SkASSERT(index > 0); - - const SkOperand* prevSrc = nextSrc - fElemCount; - - if (fType == SkType_Float || fType == SkType_3D_Point) { - for (int i = fElemCount - 1; i >= 0; --i) - values[i].fScalar = SkScalarInterp(prevSrc[i].fScalar, nextSrc[i].fScalar, T); - } else if (fType == SkType_Int || fType == SkType_MSec) { - for (int i = fElemCount - 1; i >= 0; --i) { - int32_t a = prevSrc[i].fS32; - int32_t b = nextSrc[i].fS32; - values[i].fS32 = a + SkScalarRoundToInt((b - a) * T); - } - } else - memcpy(values, prevSrc, sizeof(SkOperand) * fElemCount); - } - } - return result; -} - -/////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////// - -#ifdef SK_DEBUG - -#ifdef SK_SUPPORT_UNITTEST - static SkOperand* iset(SkOperand array[3], int a, int b, int c) - { - array[0].fScalar = SkIntToScalar(a); - array[1].fScalar = SkIntToScalar(b); - array[2].fScalar = SkIntToScalar(c); - return array; - } -#endif - -void SkOperandInterpolator::UnitTest() -{ -#ifdef SK_SUPPORT_UNITTEST - SkOperandInterpolator inter(3, 2, SkType_Float); - SkOperand v1[3], v2[3], v[3], vv[3]; - Result result; - - inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0); - inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330)); - - result = inter.timeToValues(0, v); - SkASSERT(result == kFreezeStart_Result); - SkASSERT(memcmp(v, v1, sizeof(v)) == 0); - - result = inter.timeToValues(99, v); - SkASSERT(result == kFreezeStart_Result); - SkASSERT(memcmp(v, v1, sizeof(v)) == 0); - - result = inter.timeToValues(100, v); - SkASSERT(result == kNormal_Result); - SkASSERT(memcmp(v, v1, sizeof(v)) == 0); - - result = inter.timeToValues(200, v); - SkASSERT(result == kNormal_Result); - SkASSERT(memcmp(v, v2, sizeof(v)) == 0); - - result = inter.timeToValues(201, v); - SkASSERT(result == kFreezeEnd_Result); - SkASSERT(memcmp(v, v2, sizeof(v)) == 0); - - result = inter.timeToValues(150, v); - SkASSERT(result == kNormal_Result); - SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0); - - result = inter.timeToValues(125, v); - SkASSERT(result == kNormal_Result); - result = inter.timeToValues(175, v); - SkASSERT(result == kNormal_Result); -#endif -} - -#endif diff --git a/gfx/skia/skia/src/animator/SkPaintPart.cpp b/gfx/skia/skia/src/animator/SkPaintPart.cpp deleted file mode 100644 index 842dbc97526b..000000000000 --- a/gfx/skia/skia/src/animator/SkPaintPart.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkPaintPart.h" -#include "SkDrawPaint.h" -#ifdef SK_DUMP_ENABLED -#include "SkDisplayList.h" -#include "SkDump.h" -#endif - -SkPaintPart::SkPaintPart() : fPaint(nullptr) { -} - -SkDisplayable* SkPaintPart::getParent() const { - return fPaint; -} - -bool SkPaintPart::setParent(SkDisplayable* parent) { - SkASSERT(parent != nullptr); - if (parent->isPaint() == false) - return true; - fPaint = (SkDrawPaint*) parent; - return false; -} - - -// SkDrawMaskFilter -bool SkDrawMaskFilter::add() { - if (fPaint->maskFilter != (SkDrawMaskFilter*) -1) - return true; - fPaint->maskFilter = this; - fPaint->fOwnsMaskFilter = true; - return false; -} - -SkMaskFilter* SkDrawMaskFilter::getMaskFilter() { - return nullptr; -} - - -// SkDrawPathEffect -bool SkDrawPathEffect::add() { - if (fPaint->isPaint()) { - if (fPaint->pathEffect != (SkDrawPathEffect*) -1) - return true; - fPaint->pathEffect = this; - fPaint->fOwnsPathEffect = true; - return false; - } - fPaint->add(nullptr, this); - return false; -} - -SkPathEffect* SkDrawPathEffect::getPathEffect() { - return nullptr; -} - - -// SkDrawShader -SkShader* SkDrawShader::getShader() { - return nullptr; -} - - -// Typeface -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDrawTypeface::fInfo[] = { - SK_MEMBER(fontName, String), - SK_MEMBER(style, FontStyle) -}; - -#endif - -DEFINE_GET_MEMBER(SkDrawTypeface); - -SkDrawTypeface::SkDrawTypeface() : style (SkTypeface::kNormal){ -} - -bool SkDrawTypeface::add() { - if (fPaint->typeface != (SkDrawTypeface*) -1) - return true; - fPaint->typeface = this; - fPaint->fOwnsTypeface = true; - return false; -} - -#ifdef SK_DUMP_ENABLED -void SkDrawTypeface::dump(SkAnimateMaker*) { - SkDebugf("%*s\n", string.c_str()); -} -#endif diff --git a/gfx/skia/skia/src/animator/SkPaintPart.h b/gfx/skia/skia/src/animator/SkPaintPart.h deleted file mode 100644 index 5d94f049e864..000000000000 --- a/gfx/skia/skia/src/animator/SkPaintPart.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkPaintPart_DEFINED -#define SkPaintPart_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" -#include "SkPaint.h" -#include "SkShader.h" -#include "SkTypeface.h" -#include "SkXfermode.h" - -class SkDrawPaint; -class SkDrawMatrix; - -class SkPaintPart : public SkDisplayable { -public: - SkPaintPart(); - virtual bool add() = 0; - virtual SkDisplayable* getParent() const; - virtual bool setParent(SkDisplayable* parent); -#ifdef SK_DEBUG - virtual bool isPaintPart() const { return true; } -#endif -protected: - SkDrawPaint* fPaint; -}; - -class SkDrawMaskFilter : public SkPaintPart { - DECLARE_EMPTY_MEMBER_INFO(MaskFilter); - virtual SkMaskFilter* getMaskFilter(); -protected: - bool add() override; -}; - -class SkDrawPathEffect : public SkPaintPart { - DECLARE_EMPTY_MEMBER_INFO(PathEffect); - virtual SkPathEffect* getPathEffect(); -protected: - bool add() override; -}; - -class SkDrawShader : public SkPaintPart { - DECLARE_DRAW_MEMBER_INFO(Shader); - SkDrawShader(); - virtual SkShader* getShader(); -protected: - bool add() override; - SkMatrix* getMatrix(); // returns nullptr if matrix is nullptr - SkDrawMatrix* matrix; - int /*SkShader::TileMode*/ tileMode; -}; - -class SkDrawTypeface : public SkPaintPart { - DECLARE_DRAW_MEMBER_INFO(Typeface); - SkDrawTypeface(); -#ifdef SK_DUMP_ENABLED - void dump(SkAnimateMaker *) override; -#endif - sk_sp getTypeface() { return SkTypeface::MakeFromName(fontName.c_str(), style); } -protected: - bool add() override; - SkString fontName; - SkTypeface::Style style; -}; - -#endif // SkPaintPart_DEFINED diff --git a/gfx/skia/skia/src/animator/SkParseSVGPath.cpp b/gfx/skia/skia/src/animator/SkParseSVGPath.cpp deleted file mode 100644 index 7050f7c1e048..000000000000 --- a/gfx/skia/skia/src/animator/SkParseSVGPath.cpp +++ /dev/null @@ -1,234 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include -#include "SkDrawPath.h" -#include "SkParse.h" -#include "SkPoint.h" -#include "SkUtils.h" -#define QUADRATIC_APPROXIMATION 1 - -#if QUADRATIC_APPROXIMATION -//////////////////////////////////////////////////////////////////////////////////// -//functions to approximate a cubic using two quadratics - -// midPt sets the first argument to be the midpoint of the other two -// it is used by quadApprox -static inline void midPt(SkPoint& dest,const SkPoint& a,const SkPoint& b) -{ - dest.set(SkScalarAve(a.fX, b.fX),SkScalarAve(a.fY, b.fY)); -} -// quadApprox - makes an approximation, which we hope is faster -static void quadApprox(SkPath &fPath, const SkPoint &p0, const SkPoint &p1, const SkPoint &p2) -{ - //divide the cubic up into two cubics, then convert them into quadratics - //define our points - SkPoint c,j,k,l,m,n,o,p,q, mid; - fPath.getLastPt(&c); - midPt(j, p0, c); - midPt(k, p0, p1); - midPt(l, p1, p2); - midPt(o, j, k); - midPt(p, k, l); - midPt(q, o, p); - //compute the first half - m.set(SkScalarHalf(3*j.fX - c.fX), SkScalarHalf(3*j.fY - c.fY)); - n.set(SkScalarHalf(3*o.fX -q.fX), SkScalarHalf(3*o.fY - q.fY)); - midPt(mid,m,n); - fPath.quadTo(mid,q); - c = q; - //compute the second half - m.set(SkScalarHalf(3*p.fX - c.fX), SkScalarHalf(3*p.fY - c.fY)); - n.set(SkScalarHalf(3*l.fX -p2.fX),SkScalarHalf(3*l.fY -p2.fY)); - midPt(mid,m,n); - fPath.quadTo(mid,p2); -} -#endif - - -static inline bool is_between(int c, int min, int max) -{ - return (unsigned)(c - min) <= (unsigned)(max - min); -} - -static inline bool is_ws(int c) -{ - return is_between(c, 1, 32); -} - -static inline bool is_digit(int c) -{ - return is_between(c, '0', '9'); -} - -static inline bool is_sep(int c) -{ - return is_ws(c) || c == ','; -} - -static const char* skip_ws(const char str[]) -{ - SkASSERT(str); - while (is_ws(*str)) - str++; - return str; -} - -static const char* skip_sep(const char str[]) -{ - SkASSERT(str); - while (is_sep(*str)) - str++; - return str; -} - -static const char* find_points(const char str[], SkPoint value[], int count, - bool isRelative, SkPoint* relative) -{ - str = SkParse::FindScalars(str, &value[0].fX, count * 2); - if (isRelative) { - for (int index = 0; index < count; index++) { - value[index].fX += relative->fX; - value[index].fY += relative->fY; - } - } - return str; -} - -static const char* find_scalar(const char str[], SkScalar* value, - bool isRelative, SkScalar relative) -{ - str = SkParse::FindScalar(str, value); - if (isRelative) - *value += relative; - return str; -} - -void SkDrawPath::parseSVG() { - fPath.reset(); - const char* data = d.c_str(); - SkPoint f = {0, 0}; - SkPoint c = {0, 0}; - SkPoint lastc = {0, 0}; - SkPoint points[3]; - char op = '\0'; - char previousOp = '\0'; - bool relative = false; - do { - data = skip_ws(data); - if (data[0] == '\0') - break; - char ch = data[0]; - if (is_digit(ch) || ch == '-' || ch == '+') { - if (op == '\0') - return; - } - else { - op = ch; - relative = false; - if (islower(op)) { - op = (char) toupper(op); - relative = true; - } - data++; - data = skip_sep(data); - } - switch (op) { - case 'M': - data = find_points(data, points, 1, relative, &c); - fPath.moveTo(points[0]); - op = 'L'; - c = points[0]; - break; - case 'L': - data = find_points(data, points, 1, relative, &c); - fPath.lineTo(points[0]); - c = points[0]; - break; - case 'H': { - SkScalar x; - data = find_scalar(data, &x, relative, c.fX); - fPath.lineTo(x, c.fY); - c.fX = x; - } - break; - case 'V': { - SkScalar y; - data = find_scalar(data, &y, relative, c.fY); - fPath.lineTo(c.fX, y); - c.fY = y; - } - break; - case 'C': - data = find_points(data, points, 3, relative, &c); - goto cubicCommon; - case 'S': - data = find_points(data, &points[1], 2, relative, &c); - points[0] = c; - if (previousOp == 'C' || previousOp == 'S') { - points[0].fX -= lastc.fX - c.fX; - points[0].fY -= lastc.fY - c.fY; - } - cubicCommon: - // if (data[0] == '\0') - // return; -#if QUADRATIC_APPROXIMATION - quadApprox(fPath, points[0], points[1], points[2]); -#else //this way just does a boring, slow old cubic - fPath.cubicTo(points[0], points[1], points[2]); -#endif - //if we are using the quadApprox, lastc is what it would have been if we had used - //cubicTo - lastc = points[1]; - c = points[2]; - break; - case 'Q': // Quadratic Bezier Curve - data = find_points(data, points, 2, relative, &c); - goto quadraticCommon; - case 'T': - data = find_points(data, &points[1], 1, relative, &c); - points[0] = points[1]; - if (previousOp == 'Q' || previousOp == 'T') { - points[0].fX = c.fX * 2 - lastc.fX; - points[0].fY = c.fY * 2 - lastc.fY; - } - quadraticCommon: - fPath.quadTo(points[0], points[1]); - lastc = points[0]; - c = points[1]; - break; - case 'Z': - fPath.close(); -#if 0 // !!! still a bug? - if (fPath.isEmpty() && (f.fX != 0 || f.fY != 0)) { - c.fX -= SkScalar.Epsilon; // !!! enough? - fPath.moveTo(c); - fPath.lineTo(f); - fPath.close(); - } -#endif - c = f; - op = '\0'; - break; - case '~': { - SkPoint args[2]; - data = find_points(data, args, 2, false, nullptr); - fPath.moveTo(args[0].fX, args[0].fY); - fPath.lineTo(args[1].fX, args[1].fY); - } - break; - default: - SkASSERT(0); - return; - } - if (previousOp == 0) - f = c; - previousOp = op; - } while (data[0] > 0); -} diff --git a/gfx/skia/skia/src/animator/SkPathParts.cpp b/gfx/skia/skia/src/animator/SkPathParts.cpp deleted file mode 100644 index b5407ceeb59d..000000000000 --- a/gfx/skia/skia/src/animator/SkPathParts.cpp +++ /dev/null @@ -1,318 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkPathParts.h" -#include "SkAnimateMaker.h" -#include "SkDrawMatrix.h" -#include "SkDrawRectangle.h" -#include "SkDrawPath.h" - -SkPathPart::SkPathPart() : fPath(nullptr) { -} - -void SkPathPart::dirty() { - fPath->dirty(); -} - -SkDisplayable* SkPathPart::getParent() const { - return fPath; -} - -bool SkPathPart::setParent(SkDisplayable* parent) { - SkASSERT(parent != nullptr); - if (parent->isPath() == false) - return true; - fPath = (SkDrawPath*) parent; - return false; -} - -// MoveTo -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkMoveTo::fInfo[] = { - SK_MEMBER(x, Float), - SK_MEMBER(y, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkMoveTo); - -SkMoveTo::SkMoveTo() : x(0), y(0) { -} - -bool SkMoveTo::add() { - fPath->fPath.moveTo(x, y); - return false; -} - - -// RMoveTo -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkRMoveTo::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkRMoveTo); - -bool SkRMoveTo::add() { - fPath->fPath.rMoveTo(x, y); - return false; -} - - -// LineTo -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkLineTo::fInfo[] = { - SK_MEMBER(x, Float), - SK_MEMBER(y, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkLineTo); - -SkLineTo::SkLineTo() : x(0), y(0) { -} - -bool SkLineTo::add() { - fPath->fPath.lineTo(x, y); - return false; -} - - -// RLineTo -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkRLineTo::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkRLineTo); - -bool SkRLineTo::add() { - fPath->fPath.rLineTo(x, y); - return false; -} - - -// QuadTo -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkQuadTo::fInfo[] = { - SK_MEMBER(x1, Float), - SK_MEMBER(x2, Float), - SK_MEMBER(y1, Float), - SK_MEMBER(y2, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkQuadTo); - -SkQuadTo::SkQuadTo() : x1(0), y1(0), x2(0), y2(0) { -} - -bool SkQuadTo::add() { - fPath->fPath.quadTo(x1, y1, x2, y2); - return false; -} - - -// RQuadTo -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkRQuadTo::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkRQuadTo); - -bool SkRQuadTo::add() { - fPath->fPath.rQuadTo(x1, y1, x2, y2); - return false; -} - - -// CubicTo -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkCubicTo::fInfo[] = { - SK_MEMBER(x1, Float), - SK_MEMBER(x2, Float), - SK_MEMBER(x3, Float), - SK_MEMBER(y1, Float), - SK_MEMBER(y2, Float), - SK_MEMBER(y3, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkCubicTo); - -SkCubicTo::SkCubicTo() : x1(0), y1(0), x2(0), y2(0), x3(0), y3(0) { -} - -bool SkCubicTo::add() { - fPath->fPath.cubicTo(x1, y1, x2, y2, x3, y3); - return false; -} - - -// RCubicTo -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkRCubicTo::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkRCubicTo); - -bool SkRCubicTo::add() { - fPath->fPath.rCubicTo(x1, y1, x2, y2, x3, y3); - return false; -} - - -// SkClose -bool SkClose::add() { - fPath->fPath.close(); - return false; -} - - -// SkAddGeom -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkAddGeom::fInfo[] = { - SK_MEMBER(direction, PathDirection) -}; - -#endif - -DEFINE_GET_MEMBER(SkAddGeom); - -SkAddGeom::SkAddGeom() : direction(SkPath::kCCW_Direction) { -} - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkAddRect::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER_ALIAS(bottom, fRect.fBottom, Float), - SK_MEMBER_ALIAS(left, fRect.fLeft, Float), - SK_MEMBER_ALIAS(right, fRect.fRight, Float), - SK_MEMBER_ALIAS(top, fRect.fTop, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkAddRect); - -SkAddRect::SkAddRect() { - fRect.setEmpty(); -} - -bool SkAddRect::add() { - fPath->fPath.addRect(fRect, (SkPath::Direction) direction); - return false; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkAddOval::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkAddOval); - -bool SkAddOval::add() { - fPath->fPath.addOval(fRect, (SkPath::Direction) direction); - return false; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkAddCircle::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER(radius, Float), - SK_MEMBER(x, Float), - SK_MEMBER(y, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkAddCircle); - -SkAddCircle::SkAddCircle() : radius(0), x(0), y(0) { -} - -bool SkAddCircle::add() { - fPath->fPath.addCircle(x, y, radius, (SkPath::Direction) direction); - return false; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkAddRoundRect::fInfo[] = { - SK_MEMBER_INHERITED, - SK_MEMBER(rx, Float), - SK_MEMBER(ry, Float) -}; - -#endif - -DEFINE_GET_MEMBER(SkAddRoundRect); - -SkAddRoundRect::SkAddRoundRect() : rx(0), ry(0) { -} - -bool SkAddRoundRect::add() { - fPath->fPath.addRoundRect(fRect, rx, ry, (SkPath::Direction) direction); - return false; -} - - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkAddPath::fInfo[] = { - SK_MEMBER(matrix, Matrix), - SK_MEMBER(path, Path) -}; - -#endif - -DEFINE_GET_MEMBER(SkAddPath); - -SkAddPath::SkAddPath() : matrix(nullptr), path(nullptr) { -} - -bool SkAddPath::add() { - SkASSERT (path != nullptr); - if (matrix) - fPath->fPath.addPath(path->fPath, matrix->getMatrix()); - else - fPath->fPath.addPath(path->fPath); - return false; -} diff --git a/gfx/skia/skia/src/animator/SkPathParts.h b/gfx/skia/skia/src/animator/SkPathParts.h deleted file mode 100644 index afa7b662d7c7..000000000000 --- a/gfx/skia/skia/src/animator/SkPathParts.h +++ /dev/null @@ -1,164 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkPathParts_DEFINED -#define SkPathParts_DEFINED - -#include "SkDisplayable.h" -#include "SkMemberInfo.h" -#include "SkPath.h" - -class SkDrawPath; -class SkDrawMatrix; - -class SkPathPart : public SkDisplayable { -public: - SkPathPart(); - virtual bool add() = 0; - virtual void dirty(); - virtual SkDisplayable* getParent() const; - virtual bool setParent(SkDisplayable* parent); -#ifdef SK_DEBUG - virtual bool isPathPart() const { return true; } -#endif -protected: - SkDrawPath* fPath; -}; - -class SkMoveTo : public SkPathPart { - DECLARE_MEMBER_INFO(MoveTo); - SkMoveTo(); - bool add() override; -protected: - SkScalar x; - SkScalar y; -}; - -class SkRMoveTo : public SkMoveTo { - DECLARE_MEMBER_INFO(RMoveTo); - bool add() override; -private: - typedef SkMoveTo INHERITED; -}; - -class SkLineTo : public SkPathPart { - DECLARE_MEMBER_INFO(LineTo); - SkLineTo(); - bool add() override; -protected: - SkScalar x; - SkScalar y; -}; - -class SkRLineTo : public SkLineTo { - DECLARE_MEMBER_INFO(RLineTo); - bool add() override; -private: - typedef SkLineTo INHERITED; -}; - -class SkQuadTo : public SkPathPart { - DECLARE_MEMBER_INFO(QuadTo); - SkQuadTo(); - bool add() override; -protected: - SkScalar x1; - SkScalar y1; - SkScalar x2; - SkScalar y2; -}; - -class SkRQuadTo : public SkQuadTo { - DECLARE_MEMBER_INFO(RQuadTo); - bool add() override; -private: - typedef SkQuadTo INHERITED; -}; - -class SkCubicTo : public SkPathPart { - DECLARE_MEMBER_INFO(CubicTo); - SkCubicTo(); - bool add() override; -protected: - SkScalar x1; - SkScalar y1; - SkScalar x2; - SkScalar y2; - SkScalar x3; - SkScalar y3; -}; - -class SkRCubicTo : public SkCubicTo { - DECLARE_MEMBER_INFO(RCubicTo); - bool add() override; -private: - typedef SkCubicTo INHERITED; -}; - -class SkClose : public SkPathPart { - DECLARE_EMPTY_MEMBER_INFO(Close); - bool add() override; -}; - -class SkAddGeom : public SkPathPart { - DECLARE_PRIVATE_MEMBER_INFO(AddGeom); - SkAddGeom(); -protected: - int /*SkPath::Direction*/ direction; -}; - -class SkAddRect : public SkAddGeom { - DECLARE_MEMBER_INFO(AddRect); - SkAddRect(); - bool add() override; -protected: - SkRect fRect; -private: - typedef SkAddGeom INHERITED; -}; - -class SkAddOval : public SkAddRect { - DECLARE_MEMBER_INFO(AddOval); - bool add() override; -private: - typedef SkAddRect INHERITED; -}; - -class SkAddCircle : public SkAddGeom { - DECLARE_MEMBER_INFO(AddCircle); - SkAddCircle(); - bool add() override; -private: - SkScalar radius; - SkScalar x; - SkScalar y; - typedef SkAddGeom INHERITED; -}; - -class SkAddRoundRect : public SkAddRect { - DECLARE_MEMBER_INFO(AddRoundRect); - SkAddRoundRect(); - bool add() override; -private: - SkScalar rx; - SkScalar ry; - typedef SkAddRect INHERITED; -}; - -class SkAddPath : public SkPathPart { - DECLARE_MEMBER_INFO(AddPath); - SkAddPath(); - bool add() override; -private: - typedef SkPathPart INHERITED; - SkDrawMatrix* matrix; - SkDrawPath* path; -}; - -#endif // SkPathParts_DEFINED diff --git a/gfx/skia/skia/src/animator/SkPostParts.cpp b/gfx/skia/skia/src/animator/SkPostParts.cpp deleted file mode 100644 index bfd5385532a5..000000000000 --- a/gfx/skia/skia/src/animator/SkPostParts.cpp +++ /dev/null @@ -1,56 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkPostParts.h" -#include "SkDisplayPost.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkDataInput::fInfo[] = { - SK_MEMBER_INHERITED -}; - -#endif - -DEFINE_GET_MEMBER(SkDataInput); - -SkDataInput::SkDataInput() : fParent(nullptr) {} - -bool SkDataInput::add() { - SkASSERT(name.size() > 0); - const char* dataName = name.c_str(); - if (fInt != (int) SK_NaN32) - fParent->fEvent.setS32(dataName, fInt); - else if (SkScalarIsNaN(fFloat) == false) - fParent->fEvent.setScalar(dataName, fFloat); - else if (string.size() > 0) - fParent->fEvent.setString(dataName, string); -// else -// SkASSERT(0); - return false; -} - -void SkDataInput::dirty() { - fParent->dirty(); -} - -SkDisplayable* SkDataInput::getParent() const { - return fParent; -} - -bool SkDataInput::setParent(SkDisplayable* displayable) { - if (displayable->isPost() == false) - return true; - fParent = (SkPost*) displayable; - return false; -} - -void SkDataInput::onEndElement(SkAnimateMaker&) { - add(); -} diff --git a/gfx/skia/skia/src/animator/SkPostParts.h b/gfx/skia/skia/src/animator/SkPostParts.h deleted file mode 100644 index fb2845be6e94..000000000000 --- a/gfx/skia/skia/src/animator/SkPostParts.h +++ /dev/null @@ -1,31 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkPostParts_DEFINED -#define SkPostParts_DEFINED - -#include "SkDisplayInput.h" - -class SkPost; - -class SkDataInput: public SkInput { - DECLARE_MEMBER_INFO(DataInput); - SkDataInput(); - bool add(); - void dirty() override; - SkDisplayable* getParent() const override; - void onEndElement(SkAnimateMaker& ) override; - bool setParent(SkDisplayable* ) override; -protected: - SkPost* fParent; - typedef SkInput INHERITED; - friend class SkPost; -}; - -#endif // SkPostParts_DEFINED diff --git a/gfx/skia/skia/src/animator/SkScript.cpp b/gfx/skia/skia/src/animator/SkScript.cpp deleted file mode 100644 index cd864146f769..000000000000 --- a/gfx/skia/skia/src/animator/SkScript.cpp +++ /dev/null @@ -1,1890 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkScript.h" -#include "SkMath.h" -#include "SkParse.h" -#include "SkString.h" -#include "SkTypedArray.h" - -/* things to do - ? re-enable support for struct literals (e.g., for initializing points or rects) - {x:1, y:2} - ? use standard XML / script notation like document.getElementById("canvas"); - finish support for typed arrays - ? allow indexing arrays by string - this could map to the 'name' attribute of a given child of an array - ? allow multiple types in the array - remove SkDisplayType.h // from SkOperand.h - merge type and operand arrays into scriptvalue array -*/ - -#ifdef SK_DEBUG -static const char* errorStrings[] = { - "array index of out bounds", // kArrayIndexOutOfBounds - "could not find reference id", // kCouldNotFindReferencedID - "dot operator expects object", // kDotOperatorExpectsObject - "error in array index", // kErrorInArrrayIndex - "error in function parameters", // kErrorInFunctionParameters - "expected array", // kExpectedArray - "expected boolean expression", // kExpectedBooleanExpression - "expected field name", // kExpectedFieldName - "expected hex", // kExpectedHex - "expected int for condition operator", // kExpectedIntForConditionOperator - "expected number", // kExpectedNumber - "expected number for array index", // kExpectedNumberForArrayIndex - "expected operator", // kExpectedOperator - "expected token", // kExpectedToken - "expected token before dot operator", // kExpectedTokenBeforeDotOperator - "expected value", // kExpectedValue - "handle member failed", // kHandleMemberFailed - "handle member function failed", // kHandleMemberFunctionFailed - "handle unbox failed", // kHandleUnboxFailed - "index out of range", // kIndexOutOfRange - "mismatched array brace", // kMismatchedArrayBrace - "mismatched brackets", // kMismatchedBrackets - "no function handler found", // kNoFunctionHandlerFound - "premature end", // kPrematureEnd - "too many parameters", // kTooManyParameters - "type conversion failed", // kTypeConversionFailed - "unterminated string" // kUnterminatedString -}; -#endif - -const SkScriptEngine::SkOperatorAttributes SkScriptEngine::gOpAttributes[] = { - { kNoType, kNoType, kNoBias }, // kUnassigned, - { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsString }, // kAdd - // kAddInt = kAdd, - { kNoType, kNoType, kNoBias }, // kAddScalar, - { kNoType, kNoType, kNoBias }, // kAddString, - { kNoType, kNoType, kNoBias }, // kArrayOp, - { kInt, kInt, kNoBias }, // kBitAnd - { kNoType, kInt, kNoBias }, // kBitNot - { kInt, kInt, kNoBias }, // kBitOr - { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kDivide - // kDivideInt = kDivide - { kNoType, kNoType, kNoBias }, // kDivideScalar - { kNoType, kNoType, kNoBias }, // kElse - { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kEqual - // kEqualInt = kEqual - { kNoType, kNoType, kNoBias }, // kEqualScalar - { kNoType, kNoType, kNoBias }, // kEqualString - { kInt, kNoType, kNoBias }, // kFlipOps - { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kGreaterEqual - // kGreaterEqualInt = kGreaterEqual - { kNoType, kNoType, kNoBias }, // kGreaterEqualScalar - { kNoType, kNoType, kNoBias }, // kGreaterEqualString - { kNoType, kNoType, kNoBias }, // kIf - { kNoType, kInt, kNoBias }, // kLogicalAnd (really, ToBool) - { kNoType, kInt, kNoBias }, // kLogicalNot - { kInt, kInt, kNoBias }, // kLogicalOr - { kNoType, SkOpType(kInt | kScalar), kNoBias }, // kMinus - // kMinusInt = kMinus - { kNoType, kNoType, kNoBias }, // kMinusScalar - { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kModulo - // kModuloInt = kModulo - { kNoType, kNoType, kNoBias }, // kModuloScalar - { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kMultiply - // kMultiplyInt = kMultiply - { kNoType, kNoType, kNoBias }, // kMultiplyScalar - { kNoType, kNoType, kNoBias }, // kParen - { kInt, kInt, kNoBias }, // kShiftLeft - { kInt, kInt, kNoBias }, // kShiftRight - { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kSubtract - // kSubtractInt = kSubtract - { kNoType, kNoType, kNoBias }, // kSubtractScalar - { kInt, kInt, kNoBias } // kXor -}; - -// Note that the real precedence for () [] is '2' -// but here, precedence means 'while an equal or smaller precedence than the current operator -// is on the stack, process it. This allows 3+5*2 to defer the add until after the multiply -// is preformed, since the add precedence is not smaller than multiply. -// But, (3*4 does not process the '(', since brackets are greater than all other precedences -#define kBracketPrecedence 16 -#define kIfElsePrecedence 15 - -const signed char SkScriptEngine::gPrecedence[] = { - -1, // kUnassigned, - 6, // kAdd, - // kAddInt = kAdd, - 6, // kAddScalar, - 6, // kAddString, // string concat - kBracketPrecedence, // kArrayOp, - 10, // kBitAnd, - 4, // kBitNot, - 12, // kBitOr, - 5, // kDivide, - // kDivideInt = kDivide, - 5, // kDivideScalar, - kIfElsePrecedence, // kElse, - 9, // kEqual, - // kEqualInt = kEqual, - 9, // kEqualScalar, - 9, // kEqualString, - -1, // kFlipOps, - 8, // kGreaterEqual, - // kGreaterEqualInt = kGreaterEqual, - 8, // kGreaterEqualScalar, - 8, // kGreaterEqualString, - kIfElsePrecedence, // kIf, - 13, // kLogicalAnd, - 4, // kLogicalNot, - 14, // kLogicalOr, - 4, // kMinus, - // kMinusInt = kMinus, - 4, // kMinusScalar, - 5, // kModulo, - // kModuloInt = kModulo, - 5, // kModuloScalar, - 5, // kMultiply, - // kMultiplyInt = kMultiply, - 5, // kMultiplyScalar, - kBracketPrecedence, // kParen, - 7, // kShiftLeft, - 7, // kShiftRight, // signed - 6, // kSubtract, - // kSubtractInt = kSubtract, - 6, // kSubtractScalar, - 11, // kXor -}; - -static inline bool is_between(int c, int min, int max) -{ - return (unsigned)(c - min) <= (unsigned)(max - min); -} - -static inline bool is_ws(int c) -{ - return is_between(c, 1, 32); -} - -static int token_length(const char* start) { - char ch = start[0]; - if (! is_between(ch, 'a' , 'z') && ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$') - return -1; - int length = 0; - do - ch = start[++length]; - while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') || - ch == '_' || ch == '$'); - return length; -} - -SkScriptEngine::SkScriptEngine(SkOpType returnType) : - fTokenLength(0), fReturnType(returnType), fError(kNoError) -{ - SkSuppress noInitialSuppress; - noInitialSuppress.fOperator = kUnassigned; - noInitialSuppress.fOpStackDepth = 0; - noInitialSuppress.fSuppress = false; - noInitialSuppress.fElse = 0; - fSuppressStack.push(noInitialSuppress); - *fOpStack.push() = kParen; - fTrackArray.appendClear(); - fTrackString.appendClear(); -} - -SkScriptEngine::~SkScriptEngine() { - for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++) - delete *stringPtr; - for (SkTypedArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++) - delete *arrayPtr; -} - -int SkScriptEngine::arithmeticOp(char ch, char nextChar, bool lastPush) { - SkOp op = kUnassigned; - bool reverseOperands = false; - bool negateResult = false; - int advance = 1; - switch (ch) { - case '+': - // !!! ignoring unary plus as implemented here has the side effect of - // suppressing errors like +"hi" - if (lastPush == false) // unary plus, don't push an operator - goto returnAdv; - op = kAdd; - break; - case '-': - op = lastPush ? kSubtract : kMinus; - break; - case '*': - op = kMultiply; - break; - case '/': - op = kDivide; - break; - case '>': - if (nextChar == '>') { - op = kShiftRight; - goto twoChar; - } - op = kGreaterEqual; - if (nextChar == '=') - goto twoChar; - reverseOperands = negateResult = true; - break; - case '<': - if (nextChar == '<') { - op = kShiftLeft; - goto twoChar; - } - op = kGreaterEqual; - reverseOperands = nextChar == '='; - negateResult = ! reverseOperands; - advance += reverseOperands; - break; - case '=': - if (nextChar == '=') { - op = kEqual; - goto twoChar; - } - break; - case '!': - if (nextChar == '=') { - op = kEqual; - negateResult = true; -twoChar: - advance++; - break; - } - op = kLogicalNot; - break; - case '?': - op = kIf; - break; - case ':': - op = kElse; - break; - case '^': - op = kXor; - break; - case '(': - *fOpStack.push() = kParen; // push even if eval is suppressed - goto returnAdv; - case '&': - SkASSERT(nextChar != '&'); - op = kBitAnd; - break; - case '|': - SkASSERT(nextChar != '|'); - op = kBitOr; - break; - case '%': - op = kModulo; - break; - case '~': - op = kBitNot; - break; - } - if (op == kUnassigned) - return 0; - if (fSuppressStack.top().fSuppress == false) { - signed char precedence = gPrecedence[op]; - do { - int idx = 0; - SkOp compare; - do { - compare = fOpStack.index(idx); - if ((compare & kArtificialOp) == 0) - break; - idx++; - } while (true); - signed char topPrecedence = gPrecedence[compare]; - SkASSERT(topPrecedence != -1); - if (topPrecedence > precedence || (topPrecedence == precedence && - gOpAttributes[op].fLeftType == kNoType)) { - break; - } - if (processOp() == false) - return 0; // error - } while (true); - if (negateResult) - *fOpStack.push() = (SkOp) (kLogicalNot | kArtificialOp); - fOpStack.push(op); - if (reverseOperands) - *fOpStack.push() = (SkOp) (kFlipOps | kArtificialOp); - } -returnAdv: - return advance; -} - -void SkScriptEngine::boxCallBack(_boxCallBack func, void* userStorage) { - UserCallBack callBack; - callBack.fBoxCallBack = func; - commonCallBack(kBox, callBack, userStorage); -} - -void SkScriptEngine::commonCallBack(CallBackType type, UserCallBack& callBack, void* userStorage) { - callBack.fCallBackType = type; - callBack.fUserStorage = userStorage; - *fUserCallBacks.prepend() = callBack; -} - -bool SkScriptEngine::convertParams(SkTDArray& params, - const SkFunctionParamType* paramTypes, int paramCount) { - if (params.count() > paramCount) { - fError = kTooManyParameters; - return false; // too many parameters passed - } - for (int index = 0; index < params.count(); index++) { - if (convertTo((SkDisplayTypes) paramTypes[index], ¶ms[index]) == false) - return false; - } - return true; -} - -bool SkScriptEngine::convertTo(SkDisplayTypes toType, SkScriptValue* value ) { - SkDisplayTypes type = value->fType; - if (type == toType) - return true; - if (ToOpType(type) == kObject) { -#if 0 // !!! I want object->string to get string from displaystringtype, not id - if (ToOpType(toType) == kString) { - bool success = handleObjectToString(value->fOperand.fObject); - if (success == false) - return false; - SkOpType type; - fTypeStack.pop(&type); - value->fType = ToDisplayType(type); - fOperandStack.pop(&value->fOperand); - return true; - } -#endif - if (handleUnbox(value) == false) { - fError = kHandleUnboxFailed; - return false; - } - return convertTo(toType, value); - } - return ConvertTo(this, toType, value); -} - -bool SkScriptEngine::evaluateDot(const char*& script, bool suppressed) { - size_t fieldLength = token_length(++script); // skip dot - if (fieldLength == 0) { - fError = kExpectedFieldName; - return false; - } - const char* field = script; - script += fieldLength; - bool success = handleProperty(suppressed); - if (success == false) { - fError = kCouldNotFindReferencedID; // note: never generated by standard animator plugins - return false; - } - return evaluateDotParam(script, suppressed, field, fieldLength); -} - -bool SkScriptEngine::evaluateDotParam(const char*& script, bool suppressed, - const char* field, size_t fieldLength) { - void* object; - if (suppressed) - object = nullptr; - else { - if (fTypeStack.top() != kObject) { - fError = kDotOperatorExpectsObject; - return false; - } - object = fOperandStack.top().fObject; - fTypeStack.pop(); - fOperandStack.pop(); - } - char ch; // see if it is a simple member or a function - while (is_ws(ch = script[0])) - script++; - bool success = true; - if (ch != '(') { - if (suppressed == false) { - if ((success = handleMember(field, fieldLength, object)) == false) - fError = kHandleMemberFailed; - } - } else { - SkTDArray params; - *fBraceStack.push() = kFunctionBrace; - success = functionParams(&script, params); - if (success && suppressed == false && - (success = handleMemberFunction(field, fieldLength, object, params)) == false) - fError = kHandleMemberFunctionFailed; - } - return success; -} - -bool SkScriptEngine::evaluateScript(const char** scriptPtr, SkScriptValue* value) { -#ifdef SK_DEBUG - const char** original = scriptPtr; -#endif - bool success; - const char* inner; - if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) { - *scriptPtr += sizeof("#script:") - 1; - if (fReturnType == kNoType || fReturnType == kString) { - success = innerScript(scriptPtr, value); - if (success == false) - goto end; - inner = value->fOperand.fString->c_str(); - scriptPtr = &inner; - } - } - { - success = innerScript(scriptPtr, value); - if (success == false) - goto end; - const char* script = *scriptPtr; - char ch; - while (is_ws(ch = script[0])) - script++; - if (ch != '\0') { - // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]" - fError = kPrematureEnd; - success = false; - } - } -end: -#ifdef SK_DEBUG - if (success == false) { - SkDebugf("script failed: %s", *original); - if (fError) - SkDebugf(" %s", errorStrings[fError - 1]); - SkDebugf("\n"); - } -#endif - return success; -} - -void SkScriptEngine::forget(SkTypedArray* array) { - if (array->getType() == SkType_String) { - for (int index = 0; index < array->count(); index++) { - SkString* string = (*array)[index].fString; - int found = fTrackString.find(string); - if (found >= 0) - fTrackString.remove(found); - } - return; - } - if (array->getType() == SkType_Array) { - for (int index = 0; index < array->count(); index++) { - SkTypedArray* child = (*array)[index].fArray; - forget(child); // forgets children of child - int found = fTrackArray.find(child); - if (found >= 0) - fTrackArray.remove(found); - } - } -} - -void SkScriptEngine::functionCallBack(_functionCallBack func, void* userStorage) { - UserCallBack callBack; - callBack.fFunctionCallBack = func; - commonCallBack(kFunction, callBack, userStorage); -} - -bool SkScriptEngine::functionParams(const char** scriptPtr, SkTDArray& params) { - (*scriptPtr)++; // skip open paren - *fOpStack.push() = kParen; - *fBraceStack.push() = kFunctionBrace; - SkBool suppressed = fSuppressStack.top().fSuppress; - do { - SkScriptValue value; - bool success = innerScript(scriptPtr, suppressed ? nullptr : &value); - if (success == false) { - fError = kErrorInFunctionParameters; - return false; - } - if (suppressed) - continue; - *params.append() = value; - } while ((*scriptPtr)[-1] == ','); - fBraceStack.pop(); - fOpStack.pop(); // pop paren - (*scriptPtr)++; // advance beyond close paren - return true; -} - -#ifdef SK_DEBUG -bool SkScriptEngine::getErrorString(SkString* str) const { - if (fError) - str->set(errorStrings[fError - 1]); - return fError != 0; -} -#endif - -bool SkScriptEngine::innerScript(const char** scriptPtr, SkScriptValue* value) { - const char* script = *scriptPtr; - char ch; - bool lastPush = false; - bool success = true; - int opBalance = fOpStack.count(); - int baseBrace = fBraceStack.count(); - int suppressBalance = fSuppressStack.count(); - while ((ch = script[0]) != '\0') { - if (is_ws(ch)) { - script++; - continue; - } - SkBool suppressed = fSuppressStack.top().fSuppress; - SkOperand operand; - const char* dotCheck; - if (fBraceStack.count() > baseBrace) { -#if 0 // disable support for struct brace - if (ch == ':') { - SkASSERT(fTokenLength > 0); - SkASSERT(fBraceStack.top() == kStructBrace); - ++script; - SkASSERT(fDisplayable); - SkString token(fToken, fTokenLength); - fTokenLength = 0; - const char* tokenName = token.c_str(); - const SkMemberInfo* tokenInfo SK_INIT_TO_AVOID_WARNING; - if (suppressed == false) { - SkDisplayTypes type = fInfo->getType(); - tokenInfo = SkDisplayType::GetMember(type, &tokenName); - SkASSERT(tokenInfo); - } - SkScriptValue tokenValue; - success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace - SkASSERT(success); - if (suppressed == false) { - if (tokenValue.fType == SkType_Displayable) { - SkASSERT(SkDisplayType::IsDisplayable(tokenInfo->getType())); - fDisplayable->setReference(tokenInfo, tokenValue.fOperand.fDisplayable); - } else { - if (tokenValue.fType != tokenInfo->getType()) { - if (convertTo(tokenInfo->getType(), &tokenValue) == false) - return false; - } - tokenInfo->writeValue(fDisplayable, nullptr, 0, 0, - (void*) ((char*) fInfo->memberData(fDisplayable) + tokenInfo->fOffset + fArrayOffset), - tokenInfo->getType(), tokenValue); - } - } - lastPush = false; - continue; - } else -#endif - if (fBraceStack.top() == kArrayBrace) { - SkScriptValue tokenValue; - success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace - if (success == false) { - fError = kErrorInArrrayIndex; - return false; - } - if (suppressed == false) { -#if 0 // no support for structures for now - if (tokenValue.fType == SkType_Structure) { - fArrayOffset += (int) fInfo->getSize(fDisplayable); - } else -#endif - { - SkDisplayTypes type = ToDisplayType(fReturnType); - if (fReturnType == kNoType) { - // !!! short sighted; in the future, allow each returned array component to carry - // its own type, and let caller do any needed conversions - if (value->fOperand.fArray->count() == 0) - value->fOperand.fArray->setType(type = tokenValue.fType); - else - type = value->fOperand.fArray->getType(); - } - if (tokenValue.fType != type) { - if (convertTo(type, &tokenValue) == false) - return false; - } - *value->fOperand.fArray->append() = tokenValue.fOperand; - } - } - lastPush = false; - continue; - } else { - if (token_length(script) == 0) { - fError = kExpectedToken; - return false; - } - } - } - if (lastPush != false && fTokenLength > 0) { - if (ch == '(') { - *fBraceStack.push() = kFunctionBrace; - if (handleFunction(&script, SkToBool(suppressed)) == false) - return false; - lastPush = true; - continue; - } else if (ch == '[') { - if (handleProperty(SkToBool(suppressed)) == false) - return false; // note: never triggered by standard animator plugins - if (handleArrayIndexer(&script, SkToBool(suppressed)) == false) - return false; - lastPush = true; - continue; - } else if (ch != '.') { - if (handleProperty(SkToBool(suppressed)) == false) - return false; // note: never triggered by standard animator plugins - lastPush = true; - continue; - } - } - if (ch == '0' && (script[1] & ~0x20) == 'X') { - if (lastPush != false) { - fError = kExpectedOperator; - return false; - } - script += 2; - script = SkParse::FindHex(script, (uint32_t*)&operand.fS32); - if (script == nullptr) { - fError = kExpectedHex; - return false; - } - goto intCommon; - } - if (lastPush == false && ch == '.') - goto scalarCommon; - if (ch >= '0' && ch <= '9') { - if (lastPush != false) { - fError = kExpectedOperator; - return false; - } - dotCheck = SkParse::FindS32(script, &operand.fS32); - if (dotCheck[0] != '.') { - script = dotCheck; -intCommon: - if (suppressed == false) - *fTypeStack.push() = kInt; - } else { -scalarCommon: - script = SkParse::FindScalar(script, &operand.fScalar); - if (suppressed == false) - *fTypeStack.push() = kScalar; - } - if (suppressed == false) - fOperandStack.push(operand); - lastPush = true; - continue; - } - int length = token_length(script); - if (length > 0) { - if (lastPush != false) { - fError = kExpectedOperator; - return false; - } - fToken = script; - fTokenLength = length; - script += length; - lastPush = true; - continue; - } - char startQuote = ch; - if (startQuote == '\'' || startQuote == '\"') { - if (lastPush != false) { - fError = kExpectedOperator; - return false; - } - operand.fString = new SkString(); - track(operand.fString); - ++script; - - // this is a lot of calls to append() one char at at time - // how hard to preflight script so we know how much to grow fString by? - do { - if (script[0] == '\\') - ++script; - operand.fString->append(script, 1); - ++script; - if (script[0] == '\0') { - fError = kUnterminatedString; - return false; - } - } while (script[0] != startQuote); - ++script; - if (suppressed == false) { - *fTypeStack.push() = kString; - fOperandStack.push(operand); - } - lastPush = true; - continue; - } - ; - if (ch == '.') { - if (fTokenLength == 0) { - SkScriptValue scriptValue; - SkDEBUGCODE(scriptValue.fOperand.fObject = nullptr); - int tokenLength = token_length(++script); - const char* token = script; - script += tokenLength; - if (suppressed == false) { - if (fTypeStack.count() == 0) { - fError = kExpectedTokenBeforeDotOperator; - return false; - } - SkOpType topType; - fTypeStack.pop(&topType); - fOperandStack.pop(&scriptValue.fOperand); - scriptValue.fType = ToDisplayType(topType); - handleBox(&scriptValue); - } - success = evaluateDotParam(script, SkToBool(suppressed), token, tokenLength); - if (success == false) - return false; - lastPush = true; - continue; - } - // get next token, and evaluate immediately - success = evaluateDot(script, SkToBool(suppressed)); - if (success == false) - return false; - lastPush = true; - continue; - } - if (ch == '[') { - if (lastPush == false) { - script++; - *fBraceStack.push() = kArrayBrace; - if (suppressed) - continue; - operand.fArray = value->fOperand.fArray = new SkTypedArray(ToDisplayType(fReturnType)); - track(value->fOperand.fArray); - *fTypeStack.push() = (SkOpType) kArray; - fOperandStack.push(operand); - continue; - } - if (handleArrayIndexer(&script, SkToBool(suppressed)) == false) - return false; - lastPush = true; - continue; - } -#if 0 // structs not supported for now - if (ch == '{') { - if (lastPush == false) { - script++; - *fBraceStack.push() = kStructBrace; - if (suppressed) - continue; - operand.fS32 = 0; - *fTypeStack.push() = (SkOpType) kStruct; - fOperandStack.push(operand); - continue; - } - SkASSERT(0); // braces in other contexts aren't supported yet - } -#endif - if (ch == ')' && fBraceStack.count() > 0) { - SkBraceStyle braceStyle = fBraceStack.top(); - if (braceStyle == kFunctionBrace) { - fBraceStack.pop(); - break; - } - } - if (ch == ',' || ch == ']') { - if (ch != ',') { - SkBraceStyle match; - fBraceStack.pop(&match); - if (match != kArrayBrace) { - fError = kMismatchedArrayBrace; - return false; - } - } - script++; - // !!! see if brace or bracket is correct closer - break; - } - char nextChar = script[1]; - int advance = logicalOp(ch, nextChar); - if (advance < 0) // error - return false; - if (advance == 0) - advance = arithmeticOp(ch, nextChar, lastPush); - if (advance == 0) // unknown token - return false; - if (advance > 0) - script += advance; - lastPush = ch == ']' || ch == ')'; - } - bool suppressed = SkToBool(fSuppressStack.top().fSuppress); - if (fTokenLength > 0) { - success = handleProperty(suppressed); - if (success == false) - return false; // note: never triggered by standard animator plugins - } - while (fOpStack.count() > opBalance) { // leave open paren - if ((fError = opError()) != kNoError) - return false; - if (processOp() == false) - return false; - } - SkOpType topType = fTypeStack.count() > 0 ? fTypeStack.top() : kNoType; - if (suppressed == false && topType != fReturnType && - topType == kString && fReturnType != kNoType) { // if result is a string, give handle property a chance to convert it to the property value - SkString* string = fOperandStack.top().fString; - fToken = string->c_str(); - fTokenLength = string->size(); - fOperandStack.pop(); - fTypeStack.pop(); - success = handleProperty(SkToBool(fSuppressStack.top().fSuppress)); - if (success == false) { // if it couldn't convert, return string (error?) - SkOperand operand; - operand.fS32 = 0; - *fTypeStack.push() = kString; - operand.fString = string; - fOperandStack.push(operand); - } - } - if (value) { - if (fOperandStack.count() == 0) - return false; - SkASSERT(fOperandStack.count() >= 1); - SkASSERT(fTypeStack.count() >= 1); - fOperandStack.pop(&value->fOperand); - SkOpType type; - fTypeStack.pop(&type); - value->fType = ToDisplayType(type); -// SkASSERT(value->fType != SkType_Unknown); - if (topType != fReturnType && topType == kObject && fReturnType != kNoType) { - if (convertTo(ToDisplayType(fReturnType), value) == false) - return false; - } - } - while (fSuppressStack.count() > suppressBalance) - fSuppressStack.pop(); - *scriptPtr = script; - return true; // no error -} - -void SkScriptEngine::memberCallBack(_memberCallBack member , void* userStorage) { - UserCallBack callBack; - callBack.fMemberCallBack = member; - commonCallBack(kMember, callBack, userStorage); -} - -void SkScriptEngine::memberFunctionCallBack(_memberFunctionCallBack func, void* userStorage) { - UserCallBack callBack; - callBack.fMemberFunctionCallBack = func; - commonCallBack(kMemberFunction, callBack, userStorage); -} - -#if 0 -void SkScriptEngine::objectToStringCallBack(_objectToStringCallBack func, void* userStorage) { - UserCallBack callBack; - callBack.fObjectToStringCallBack = func; - commonCallBack(kObjectToString, callBack, userStorage); -} -#endif - -bool SkScriptEngine::handleArrayIndexer(const char** scriptPtr, bool suppressed) { - SkScriptValue scriptValue; - (*scriptPtr)++; - *fOpStack.push() = kParen; - *fBraceStack.push() = kArrayBrace; - SkOpType saveType = fReturnType; - fReturnType = kInt; - bool success = innerScript(scriptPtr, suppressed == false ? &scriptValue : nullptr); - if (success == false) - return false; - fReturnType = saveType; - if (suppressed == false) { - if (convertTo(SkType_Int, &scriptValue) == false) - return false; - int index = scriptValue.fOperand.fS32; - SkScriptValue scriptValue; - SkOpType type; - fTypeStack.pop(&type); - fOperandStack.pop(&scriptValue.fOperand); - scriptValue.fType = ToDisplayType(type); - if (type == kObject) { - success = handleUnbox(&scriptValue); - if (success == false) - return false; - if (ToOpType(scriptValue.fType) != kArray) { - fError = kExpectedArray; - return false; - } - } - *fTypeStack.push() = scriptValue.fOperand.fArray->getOpType(); -// SkASSERT(index >= 0); - if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) { - fError = kArrayIndexOutOfBounds; - return false; - } - scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index]; - fOperandStack.push(scriptValue.fOperand); - } - fOpStack.pop(); // pop paren - return success; -} - -bool SkScriptEngine::handleBox(SkScriptValue* scriptValue) { - bool success = true; - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kBox) - continue; - success = (*callBack->fBoxCallBack)(callBack->fUserStorage, scriptValue); - if (success) { - fOperandStack.push(scriptValue->fOperand); - *fTypeStack.push() = ToOpType(scriptValue->fType); - goto done; - } - } -done: - return success; -} - -bool SkScriptEngine::handleFunction(const char** scriptPtr, bool suppressed) { - SkScriptValue callbackResult; - SkTDArray params; - SkString functionName(fToken, fTokenLength); - fTokenLength = 0; - bool success = functionParams(scriptPtr, params); - if (success == false) - goto done; - if (suppressed == true) - return true; - { - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kFunction) - continue; - success = (*callBack->fFunctionCallBack)(functionName.c_str(), functionName.size(), params, - callBack->fUserStorage, &callbackResult); - if (success) { - fOperandStack.push(callbackResult.fOperand); - *fTypeStack.push() = ToOpType(callbackResult.fType); - goto done; - } - } - } - fError = kNoFunctionHandlerFound; - return false; -done: - return success; -} - -bool SkScriptEngine::handleMember(const char* field, size_t len, void* object) { - SkScriptValue callbackResult; - bool success = true; - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kMember) - continue; - success = (*callBack->fMemberCallBack)(field, len, object, callBack->fUserStorage, &callbackResult); - if (success) { - if (callbackResult.fType == SkType_String) - track(callbackResult.fOperand.fString); - fOperandStack.push(callbackResult.fOperand); - *fTypeStack.push() = ToOpType(callbackResult.fType); - goto done; - } - } - return false; -done: - return success; -} - -bool SkScriptEngine::handleMemberFunction(const char* field, size_t len, void* object, SkTDArray& params) { - SkScriptValue callbackResult; - bool success = true; - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kMemberFunction) - continue; - success = (*callBack->fMemberFunctionCallBack)(field, len, object, params, - callBack->fUserStorage, &callbackResult); - if (success) { - if (callbackResult.fType == SkType_String) - track(callbackResult.fOperand.fString); - fOperandStack.push(callbackResult.fOperand); - *fTypeStack.push() = ToOpType(callbackResult.fType); - goto done; - } - } - return false; -done: - return success; -} - -#if 0 -bool SkScriptEngine::handleObjectToString(void* object) { - SkScriptValue callbackResult; - bool success = true; - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kObjectToString) - continue; - success = (*callBack->fObjectToStringCallBack)(object, - callBack->fUserStorage, &callbackResult); - if (success) { - if (callbackResult.fType == SkType_String) - track(callbackResult.fOperand.fString); - fOperandStack.push(callbackResult.fOperand); - *fTypeStack.push() = ToOpType(callbackResult.fType); - goto done; - } - } - return false; -done: - return success; -} -#endif - -bool SkScriptEngine::handleProperty(bool suppressed) { - SkScriptValue callbackResult; - bool success = true; - if (suppressed) - goto done; - success = false; // note that with standard animator-script plugins, callback never returns false - { - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kProperty) - continue; - success = (*callBack->fPropertyCallBack)(fToken, fTokenLength, - callBack->fUserStorage, &callbackResult); - if (success) { - if (callbackResult.fType == SkType_String && callbackResult.fOperand.fString == nullptr) { - callbackResult.fOperand.fString = new SkString(fToken, fTokenLength); - track(callbackResult.fOperand.fString); - } - fOperandStack.push(callbackResult.fOperand); - *fTypeStack.push() = ToOpType(callbackResult.fType); - goto done; - } - } - } -done: - fTokenLength = 0; - return success; -} - -bool SkScriptEngine::handleUnbox(SkScriptValue* scriptValue) { - bool success = true; - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kUnbox) - continue; - success = (*callBack->fUnboxCallBack)(callBack->fUserStorage, scriptValue); - if (success) { - if (scriptValue->fType == SkType_String) - track(scriptValue->fOperand.fString); - goto done; - } - } - return false; -done: - return success; -} - -// note that entire expression is treated as if it were enclosed in parens -// an open paren is always the first thing in the op stack - -int SkScriptEngine::logicalOp(char ch, char nextChar) { - int advance = 1; - SkOp match; - signed char precedence; - switch (ch) { - case ')': - match = kParen; - break; - case ']': - match = kArrayOp; - break; - case '?': - match = kIf; - break; - case ':': - match = kElse; - break; - case '&': - if (nextChar != '&') - goto noMatch; - match = kLogicalAnd; - advance = 2; - break; - case '|': - if (nextChar != '|') - goto noMatch; - match = kLogicalOr; - advance = 2; - break; - default: -noMatch: - return 0; - } - SkSuppress suppress; - precedence = gPrecedence[match]; - if (fSuppressStack.top().fSuppress) { - if (fSuppressStack.top().fOpStackDepth < fOpStack.count()) { - SkOp topOp = fOpStack.top(); - if (gPrecedence[topOp] <= precedence) - fOpStack.pop(); - goto goHome; - } - bool changedPrecedence = gPrecedence[fSuppressStack.top().fOperator] < precedence; - if (changedPrecedence) - fSuppressStack.pop(); - if (precedence == kIfElsePrecedence) { - if (match == kIf) { - if (changedPrecedence) - fOpStack.pop(); - else - *fOpStack.push() = kIf; - } else { - if (fSuppressStack.top().fOpStackDepth == fOpStack.count()) { - goto flipSuppress; - } - fOpStack.pop(); - } - } - if (changedPrecedence == false) - goto goHome; - } - while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence) { - if (processOp() == false) - return false; - } - if (fSuppressStack.top().fOpStackDepth > fOpStack.count()) - fSuppressStack.pop(); - switch (match) { - case kParen: - case kArrayOp: - if (fOpStack.count() <= 1 || fOpStack.top() != match) { - fError = kMismatchedBrackets; - return -1; - } - if (match == kParen) - fOpStack.pop(); - else { - SkOpType indexType; - fTypeStack.pop(&indexType); - if (indexType != kInt && indexType != kScalar) { - fError = kExpectedNumberForArrayIndex; // (although, could permit strings eventually) - return -1; - } - SkOperand indexOperand; - fOperandStack.pop(&indexOperand); - int index = indexType == kScalar ? SkScalarFloorToInt(indexOperand.fScalar) : - indexOperand.fS32; - SkOpType arrayType; - fTypeStack.pop(&arrayType); - if ((unsigned)arrayType != (unsigned)kArray) { - fError = kExpectedArray; - return -1; - } - SkOperand arrayOperand; - fOperandStack.pop(&arrayOperand); - SkTypedArray* array = arrayOperand.fArray; - SkOperand operand; - if (array->getIndex(index, &operand) == false) { - fError = kIndexOutOfRange; - return -1; - } - SkOpType resultType = array->getOpType(); - fTypeStack.push(resultType); - fOperandStack.push(operand); - } - break; - case kIf: { - SkScriptValue ifValue; - SkOpType ifType; - fTypeStack.pop(&ifType); - ifValue.fType = ToDisplayType(ifType); - fOperandStack.pop(&ifValue.fOperand); - if (convertTo(SkType_Int, &ifValue) == false) - return -1; - if (ifValue.fType != SkType_Int) { - fError = kExpectedIntForConditionOperator; - return -1; - } - suppress.fSuppress = ifValue.fOperand.fS32 == 0; - suppress.fOperator = kIf; - suppress.fOpStackDepth = fOpStack.count(); - suppress.fElse = false; - fSuppressStack.push(suppress); - // if left is true, do only up to colon - // if left is false, do only after colon - } break; - case kElse: -flipSuppress: - if (fSuppressStack.top().fElse) - fSuppressStack.pop(); - fSuppressStack.top().fElse = true; - fSuppressStack.top().fSuppress ^= true; - // flip last do / don't do consideration from last '?' - break; - case kLogicalAnd: - case kLogicalOr: { - if (fTypeStack.top() != kInt) { - fError = kExpectedBooleanExpression; - return -1; - } - int32_t topInt = fOperandStack.top().fS32; - if (fOpStack.top() != kLogicalAnd) - *fOpStack.push() = kLogicalAnd; // really means 'to bool', and is appropriate for 'or' - if (match == kLogicalOr ? topInt != 0 : topInt == 0) { - suppress.fSuppress = true; - suppress.fOperator = match; - suppress.fOpStackDepth = fOpStack.count(); - suppress.fElse = false; - fSuppressStack.push(suppress); - } else { - fTypeStack.pop(); - fOperandStack.pop(); - } - } break; - default: - SkASSERT(0); - } -goHome: - return advance; -} - -SkScriptEngine::Error SkScriptEngine::opError() { - int opCount = fOpStack.count(); - int operandCount = fOperandStack.count(); - if (opCount == 0) { - if (operandCount != 1) - return kExpectedOperator; - return kNoError; - } - SkOp op = (SkOp) (fOpStack.top() & ~kArtificialOp); - const SkOperatorAttributes* attributes = &gOpAttributes[op]; - if (attributes->fLeftType != kNoType && operandCount < 2) - return kExpectedValue; - if (attributes->fLeftType == kNoType && operandCount < 1) - return kExpectedValue; - return kNoError; -} - -bool SkScriptEngine::processOp() { - SkOp op; - fOpStack.pop(&op); - op = (SkOp) (op & ~kArtificialOp); - const SkOperatorAttributes* attributes = &gOpAttributes[op]; - SkOpType type2; - fTypeStack.pop(&type2); - SkOpType type1 = type2; - SkOperand operand2; - fOperandStack.pop(&operand2); - SkOperand operand1 = operand2; // !!! not really needed, suppresses warning - if (attributes->fLeftType != kNoType) { - fTypeStack.pop(&type1); - fOperandStack.pop(&operand1); - if (op == kFlipOps) { - SkTSwap(type1, type2); - SkTSwap(operand1, operand2); - fOpStack.pop(&op); - op = (SkOp) (op & ~kArtificialOp); - attributes = &gOpAttributes[op]; - } - if (type1 == kObject && (type1 & attributes->fLeftType) == 0) { - SkScriptValue val; - val.fType = ToDisplayType(type1); - val.fOperand = operand1; - bool success = handleUnbox(&val); - if (success == false) - return false; - type1 = ToOpType(val.fType); - operand1 = val.fOperand; - } - } - if (type2 == kObject && (type2 & attributes->fLeftType) == 0) { - SkScriptValue val; - val.fType = ToDisplayType(type2); - val.fOperand = operand2; - bool success = handleUnbox(&val); - if (success == false) - return false; - type2 = ToOpType(val.fType); - operand2 = val.fOperand; - } - if (attributes->fLeftType != kNoType) { - if (type1 != type2) { - if ((attributes->fLeftType & kString) && attributes->fBias & kTowardsString && ((type1 | type2) & kString)) { - if (type1 == kInt || type1 == kScalar) { - convertToString(operand1, type1 == kInt ? SkType_Int : SkType_Float); - type1 = kString; - } - if (type2 == kInt || type2 == kScalar) { - convertToString(operand2, type2 == kInt ? SkType_Int : SkType_Float); - type2 = kString; - } - } else if (attributes->fLeftType & kScalar && ((type1 | type2) & kScalar)) { - if (type1 == kInt) { - operand1.fScalar = IntToScalar(operand1.fS32); - type1 = kScalar; - } - if (type2 == kInt) { - operand2.fScalar = IntToScalar(operand2.fS32); - type2 = kScalar; - } - } - } - if ((type1 & attributes->fLeftType) == 0 || type1 != type2) { - if (type1 == kString) { - const char* result = SkParse::FindScalar(operand1.fString->c_str(), &operand1.fScalar); - if (result == nullptr) { - fError = kExpectedNumber; - return false; - } - type1 = kScalar; - } - if (type1 == kScalar && (attributes->fLeftType == kInt || type2 == kInt)) { - operand1.fS32 = SkScalarFloorToInt(operand1.fScalar); - type1 = kInt; - } - } - } - if ((type2 & attributes->fRightType) == 0 || type1 != type2) { - if (type2 == kString) { - const char* result = SkParse::FindScalar(operand2.fString->c_str(), &operand2.fScalar); - if (result == nullptr) { - fError = kExpectedNumber; - return false; - } - type2 = kScalar; - } - if (type2 == kScalar && (attributes->fRightType == kInt || type1 == kInt)) { - operand2.fS32 = SkScalarFloorToInt(operand2.fScalar); - type2 = kInt; - } - } - if (type2 == kScalar) - op = (SkOp) (op + 1); - else if (type2 == kString) - op = (SkOp) (op + 2); - switch(op) { - case kAddInt: - operand2.fS32 += operand1.fS32; - break; - case kAddScalar: - operand2.fScalar += operand1.fScalar; - break; - case kAddString: - if (fTrackString.find(operand1.fString) < 0) { - operand1.fString = new SkString(*operand1.fString); - track(operand1.fString); - } - operand1.fString->append(*operand2.fString); - operand2 = operand1; - break; - case kBitAnd: - operand2.fS32 &= operand1.fS32; - break; - case kBitNot: - operand2.fS32 = ~operand2.fS32; - break; - case kBitOr: - operand2.fS32 |= operand1.fS32; - break; - case kDivideInt: - if (operand2.fS32 == 0) { - operand2.fS32 = operand1.fS32 == 0 ? SK_NaN32 : operand1.fS32 > 0 ? SK_MaxS32 : -SK_MaxS32; - break; - } else { - int32_t original = operand2.fS32; - operand2.fS32 = operand1.fS32 / operand2.fS32; - if (original * operand2.fS32 == operand1.fS32) - break; // integer divide was good enough - operand2.fS32 = original; - type2 = kScalar; - } - case kDivideScalar: - if (operand2.fScalar == 0) - operand2.fScalar = operand1.fScalar == 0 ? SK_ScalarNaN : operand1.fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax; - else - operand2.fScalar = operand1.fScalar / operand2.fScalar; - break; - case kEqualInt: - operand2.fS32 = operand1.fS32 == operand2.fS32; - break; - case kEqualScalar: - operand2.fS32 = operand1.fScalar == operand2.fScalar; - type2 = kInt; - break; - case kEqualString: - operand2.fS32 = *operand1.fString == *operand2.fString; - type2 = kInt; - break; - case kGreaterEqualInt: - operand2.fS32 = operand1.fS32 >= operand2.fS32; - break; - case kGreaterEqualScalar: - operand2.fS32 = operand1.fScalar >= operand2.fScalar; - type2 = kInt; - break; - case kGreaterEqualString: - operand2.fS32 = strcmp(operand1.fString->c_str(), operand2.fString->c_str()) >= 0; - type2 = kInt; - break; - case kLogicalAnd: - operand2.fS32 = !! operand2.fS32; // really, ToBool - break; - case kLogicalNot: - operand2.fS32 = ! operand2.fS32; - break; - case kLogicalOr: - SkASSERT(0); // should have already been processed - break; - case kMinusInt: - operand2.fS32 = -operand2.fS32; - break; - case kMinusScalar: - operand2.fScalar = -operand2.fScalar; - break; - case kModuloInt: - operand2.fS32 = operand1.fS32 % operand2.fS32; - break; - case kModuloScalar: - operand2.fScalar = SkScalarMod(operand1.fScalar, operand2.fScalar); - break; - case kMultiplyInt: - operand2.fS32 *= operand1.fS32; - break; - case kMultiplyScalar: - operand2.fScalar = SkScalarMul(operand1.fScalar, operand2.fScalar); - break; - case kShiftLeft: - operand2.fS32 = operand1.fS32 << operand2.fS32; - break; - case kShiftRight: - operand2.fS32 = operand1.fS32 >> operand2.fS32; - break; - case kSubtractInt: - operand2.fS32 = operand1.fS32 - operand2.fS32; - break; - case kSubtractScalar: - operand2.fScalar = operand1.fScalar - operand2.fScalar; - break; - case kXor: - operand2.fS32 ^= operand1.fS32; - break; - default: - SkASSERT(0); - } - fTypeStack.push(type2); - fOperandStack.push(operand2); - return true; -} - -void SkScriptEngine::propertyCallBack(_propertyCallBack prop, void* userStorage) { - UserCallBack callBack; - callBack.fPropertyCallBack = prop; - commonCallBack(kProperty, callBack, userStorage); -} - -void SkScriptEngine::track(SkTypedArray* array) { - SkASSERT(fTrackArray.find(array) < 0); - *(fTrackArray.end() - 1) = array; - fTrackArray.appendClear(); -} - -void SkScriptEngine::track(SkString* string) { - SkASSERT(fTrackString.find(string) < 0); - *(fTrackString.end() - 1) = string; - fTrackString.appendClear(); -} - -void SkScriptEngine::unboxCallBack(_unboxCallBack func, void* userStorage) { - UserCallBack callBack; - callBack.fUnboxCallBack = func; - commonCallBack(kUnbox, callBack, userStorage); -} - -bool SkScriptEngine::ConvertTo(SkScriptEngine* engine, SkDisplayTypes toType, SkScriptValue* value ) { - SkASSERT(value); - if (SkDisplayType::IsEnum(nullptr /* fMaker */, toType)) - toType = SkType_Int; - if (toType == SkType_Point || toType == SkType_3D_Point) - toType = SkType_Float; - if (toType == SkType_Drawable) - toType = SkType_Displayable; - SkDisplayTypes type = value->fType; - if (type == toType) - return true; - SkOperand& operand = value->fOperand; - bool success = true; - switch (toType) { - case SkType_Int: - if (type == SkType_Boolean) - break; - if (type == SkType_Float) - operand.fS32 = SkScalarFloorToInt(operand.fScalar); - else { - if (type != SkType_String) { - success = false; - break; // error - } - success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != nullptr; - } - break; - case SkType_Float: - if (type == SkType_Int) { - if (operand.fS32 == SK_NaN32) - operand.fScalar = SK_ScalarNaN; - else if (SkAbs32(operand.fS32) == SK_MaxS32) - operand.fScalar = SkSign32(operand.fS32) * SK_ScalarMax; - else - operand.fScalar = SkIntToScalar(operand.fS32); - } else { - if (type != SkType_String) { - success = false; - break; // error - } - success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != nullptr; - } - break; - case SkType_String: { - SkString* strPtr = new SkString(); - SkASSERT(engine); - engine->track(strPtr); - if (type == SkType_Int) { - strPtr->appendS32(operand.fS32); - } else if (type == SkType_Displayable) { - SkASSERT(0); // must call through instance version instead of static version - } else { - if (type != SkType_Float) { - success = false; - break; - } - strPtr->appendScalar(operand.fScalar); - } - operand.fString = strPtr; - } break; - case SkType_Array: { - SkTypedArray* array = new SkTypedArray(type); - *array->append() = operand; - engine->track(array); - operand.fArray = array; - } break; - default: - SkASSERT(0); - } - value->fType = toType; - if (success == false) - engine->fError = kTypeConversionFailed; - return success; -} - -SkScalar SkScriptEngine::IntToScalar(int32_t s32) { - SkScalar scalar; - if (s32 == SK_NaN32) - scalar = SK_ScalarNaN; - else if (SkAbs32(s32) == SK_MaxS32) - scalar = SkSign32(s32) * SK_ScalarMax; - else - scalar = SkIntToScalar(s32); - return scalar; -} - -SkDisplayTypes SkScriptEngine::ToDisplayType(SkOpType type) { - int val = type; - switch (val) { - case kNoType: - return SkType_Unknown; - case kInt: - return SkType_Int; - case kScalar: - return SkType_Float; - case kString: - return SkType_String; - case kArray: - return SkType_Array; - case kObject: - return SkType_Displayable; -// case kStruct: -// return SkType_Structure; - default: - SkASSERT(0); - return SkType_Unknown; - } -} - -SkScriptEngine::SkOpType SkScriptEngine::ToOpType(SkDisplayTypes type) { - if (SkDisplayType::IsDisplayable(nullptr /* fMaker */, type)) - return (SkOpType) kObject; - if (SkDisplayType::IsEnum(nullptr /* fMaker */, type)) - return kInt; - switch (type) { - case SkType_ARGB: - case SkType_MSec: - case SkType_Int: - return kInt; - case SkType_Float: - case SkType_Point: - case SkType_3D_Point: - return kScalar; - case SkType_Base64: - case SkType_DynamicString: - case SkType_String: - return kString; - case SkType_Array: - return (SkOpType) kArray; - case SkType_Unknown: - return kNoType; - default: - SkASSERT(0); - return kNoType; - } -} - -bool SkScriptEngine::ValueToString(SkScriptValue value, SkString* string) { - switch (value.fType) { - case kInt: - string->reset(); - string->appendS32(value.fOperand.fS32); - break; - case kScalar: - string->reset(); - string->appendScalar(value.fOperand.fScalar); - break; - case kString: - string->set(*value.fOperand.fString); - break; - default: - SkASSERT(0); - return false; - } - return true; // no error -} - -#ifdef SK_SUPPORT_UNITTEST - -#include "SkFloatingPoint.h" - -#define DEF_SCALAR_ANSWER 0 -#define DEF_STRING_ANSWER nullptr - -#define testInt(expression) { #expression, SkType_Int, expression, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER } - #define testScalar(expression) { #expression, SkType_Float, 0, (float) expression, DEF_STRING_ANSWER } - #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkType_Float, 0, sk_float_mod(exp1, exp2), DEF_STRING_ANSWER } -#define testTrue(expression) { #expression, SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER } -#define testFalse(expression) { #expression, SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER } - -static const SkScriptNAnswer scriptTests[] = { - testInt(1>1/2), - testInt((6+7)*8), - testInt(0&&1?2:3), - testInt(3*(4+5)), - testScalar(1.0+2.0), - testScalar(1.0+5), - testScalar(3.0-1.0), - testScalar(6-1.0), - testScalar(- -5.5- -1.5), - testScalar(2.5*6.), - testScalar(0.5*4), - testScalar(4.5/.5), - testScalar(9.5/19), - testRemainder(9.5, 0.5), - testRemainder(9.,2), - testRemainder(9,2.5), - testRemainder(-9,2.5), - testTrue(-9==-9.0), - testTrue(-9.==-4.0-5), - testTrue(-9.*1==-4-5), - testFalse(-9!=-9.0), - testFalse(-9.!=-4.0-5), - testFalse(-9.*1!=-4-5), - testInt(0x123), - testInt(0XABC), - testInt(0xdeadBEEF), - { "'123'+\"456\"", SkType_String, 0, 0, "123456" }, - { "123+\"456\"", SkType_String, 0, 0, "123456" }, - { "'123'+456", SkType_String, 0, 0, "123456" }, - { "'123'|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - { "123|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - { "'123'|456", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - { "'2'<11", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - { "2<'11'", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - { "'2'<'11'", SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - testInt(123), - testInt(-345), - testInt(+678), - testInt(1+2+3), - testInt(3*4+5), - testInt(6+7*8), - testInt(-1-2-8/4), - testInt(-9%4), - testInt(9%-4), - testInt(-9%-4), - testInt(123|978), - testInt(123&978), - testInt(123^978), - testInt(2<<4), - testInt(99>>3), - testInt(~55), - testInt(~~55), - testInt(!55), - testInt(!!55), - // both int - testInt(2<2), - testInt(2<11), - testInt(20<11), - testInt(2<=2), - testInt(2<=11), - testInt(20<=11), - testInt(2>2), - testInt(2>11), - testInt(20>11), - testInt(2>=2), - testInt(2>=11), - testInt(20>=11), - testInt(2==2), - testInt(2==11), - testInt(20==11), - testInt(2!=2), - testInt(2!=11), - testInt(20!=11), - // left int, right scalar - testInt(2<2.), - testInt(2<11.), - testInt(20<11.), - testInt(2<=2.), - testInt(2<=11.), - testInt(20<=11.), - testInt(2>2.), - testInt(2>11.), - testInt(20>11.), - testInt(2>=2.), - testInt(2>=11.), - testInt(20>=11.), - testInt(2==2.), - testInt(2==11.), - testInt(20==11.), - testInt(2!=2.), - testInt(2!=11.), - testInt(20!=11.), - // left scalar, right int - testInt(2.<2), - testInt(2.<11), - testInt(20.<11), - testInt(2.<=2), - testInt(2.<=11), - testInt(20.<=11), - testInt(2.>2), - testInt(2.>11), - testInt(20.>11), - testInt(2.>=2), - testInt(2.>=11), - testInt(20.>=11), - testInt(2.==2), - testInt(2.==11), - testInt(20.==11), - testInt(2.!=2), - testInt(2.!=11), - testInt(20.!=11), - // both scalar - testInt(2.<11.), - testInt(20.<11.), - testInt(2.<=2.), - testInt(2.<=11.), - testInt(20.<=11.), - testInt(2.>2.), - testInt(2.>11.), - testInt(20.>11.), - testInt(2.>=2.), - testInt(2.>=11.), - testInt(20.>=11.), - testInt(2.==2.), - testInt(2.==11.), - testInt(20.==11.), - testInt(2.!=2.), - testInt(2.!=11.), - testInt(20.!=11.), - // int, string (string is int) - testFalse(2<'2'), - testTrue(2<'11'), - testFalse(20<'11'), - testTrue(2<='2'), - testTrue(2<='11'), - testFalse(20<='11'), - testFalse(2>'2'), - testFalse(2>'11'), - testTrue(20>'11'), - testTrue(2>='2'), - testFalse(2>='11'), - testTrue(20>='11'), - testTrue(2=='2'), - testFalse(2=='11'), - testFalse(2!='2'), - testTrue(2!='11'), - // int, string (string is scalar) - testFalse(2<'2.'), - testTrue(2<'11.'), - testFalse(20<'11.'), - testTrue(2=='2.'), - testFalse(2=='11.'), - // scalar, string - testFalse(2.<'2.'), - testTrue(2.<'11.'), - testFalse(20.<'11.'), - testTrue(2.=='2.'), - testFalse(2.=='11.'), - // string, int - testFalse('2'<2), - testTrue('2'<11), - testFalse('20'<11), - testTrue('2'==2), - testFalse('2'==11), - // string, scalar - testFalse('2'<2.), - testTrue('2'<11.), - testFalse('20'<11.), - testTrue('2'==2.), - testFalse('2'==11.), - // string, string - testFalse('2'<'2'), - testFalse('2'<'11'), - testFalse('20'<'11'), - testTrue('2'=='2'), - testFalse('2'=='11'), - // logic - testInt(1?2:3), - testInt(0?2:3), - testInt((1&&2)||3), - testInt((1&&0)||3), - testInt((1&&0)||0), - testInt(1||(0&&3)), - testInt(0||(0&&3)), - testInt(0||(1&&3)), - testInt(1?(2?3:4):5), - testInt(0?(2?3:4):5), - testInt(1?(0?3:4):5), - testInt(0?(0?3:4):5), - testInt(1?2?3:4:5), - testInt(0?2?3:4:5), - testInt(1?0?3:4:5), - testInt(0?0?3:4:5), - - testInt(1?2:(3?4:5)), - testInt(0?2:(3?4:5)), - testInt(1?0:(3?4:5)), - testInt(0?0:(3?4:5)), - testInt(1?2:3?4:5), - testInt(0?2:3?4:5), - testInt(1?0:3?4:5), - testInt(0?0:3?4:5) - , { "123.5", SkType_Float, 0, SkIntToScalar(123) + SK_Scalar1/2, DEF_STRING_ANSWER } -}; - -#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) - -void SkScriptEngine::UnitTest() { - for (unsigned index = 0; index < SkScriptNAnswer_testCount; index++) { - SkScriptEngine engine(SkScriptEngine::ToOpType(scriptTests[index].fType)); - SkScriptValue value; - const char* script = scriptTests[index].fScript; - SkASSERT(engine.evaluateScript(&script, &value) == true); - SkASSERT(value.fType == scriptTests[index].fType); - SkScalar error; - switch (value.fType) { - case SkType_Int: - SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); - break; - case SkType_Float: - error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); - SkASSERT(error < SK_Scalar1 / 10000); - break; - case SkType_String: - SkASSERT(strcmp(value.fOperand.fString->c_str(), scriptTests[index].fStringAnswer) == 0); - break; - default: - SkASSERT(0); - } - } -} -#endif diff --git a/gfx/skia/skia/src/animator/SkScript.h b/gfx/skia/skia/src/animator/SkScript.h deleted file mode 100644 index 074d10c3cc64..000000000000 --- a/gfx/skia/skia/src/animator/SkScript.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkScript_DEFINED -#define SkScript_DEFINED - -#include "SkOperand.h" -#include "SkIntArray.h" -#include "SkTDict.h" -#include "SkTDStack.h" - -class SkAnimateMaker; - -class SkScriptEngine { -public: - enum Error { - kNoError, - kArrayIndexOutOfBounds, - kCouldNotFindReferencedID, - kDotOperatorExpectsObject, - kErrorInArrrayIndex, - kErrorInFunctionParameters, - kExpectedArray, - kExpectedBooleanExpression, - kExpectedFieldName, - kExpectedHex, - kExpectedIntForConditionOperator, - kExpectedNumber, - kExpectedNumberForArrayIndex, - kExpectedOperator, - kExpectedToken, - kExpectedTokenBeforeDotOperator, - kExpectedValue, - kHandleMemberFailed, - kHandleMemberFunctionFailed, - kHandleUnboxFailed, - kIndexOutOfRange, - kMismatchedArrayBrace, - kMismatchedBrackets, - kNoFunctionHandlerFound, - kPrematureEnd, - kTooManyParameters, - kTypeConversionFailed, - kUnterminatedString - }; - - enum SkOpType { - kNoType, - kInt = 1, - kScalar = 2, - kString = 4, - kArray = 8, - kObject = 16 -// kStruct = 32 - }; - - typedef bool (*_boxCallBack)(void* userStorage, SkScriptValue* result); - typedef bool (*_functionCallBack)(const char* func, size_t len, SkTDArray& params, - void* userStorage, SkScriptValue* result); - typedef bool (*_memberCallBack)(const char* member, size_t len, void* object, - void* userStorage, SkScriptValue* result); - typedef bool (*_memberFunctionCallBack)(const char* member, size_t len, void* object, - SkTDArray& params, void* userStorage, SkScriptValue* result); -// typedef bool (*_objectToStringCallBack)(void* object, void* userStorage, SkScriptValue* result); - typedef bool (*_propertyCallBack)(const char* prop, size_t len, void* userStorage, SkScriptValue* result); - typedef bool (*_unboxCallBack)(void* userStorage, SkScriptValue* result); - SkScriptEngine(SkOpType returnType); - ~SkScriptEngine(); - void boxCallBack(_boxCallBack func, void* userStorage); - bool convertTo(SkDisplayTypes , SkScriptValue* ); - bool evaluateScript(const char** script, SkScriptValue* value); - void forget(SkTypedArray* array); - void functionCallBack(_functionCallBack func, void* userStorage); - Error getError() const { return fError; } -#ifdef SK_DEBUG - bool getErrorString(SkString* err) const; -#endif - void memberCallBack(_memberCallBack , void* userStorage); - void memberFunctionCallBack(_memberFunctionCallBack , void* userStorage); -// void objectToStringCallBack(_objectToStringCallBack , void* userStorage); - void propertyCallBack(_propertyCallBack prop, void* userStorage); - void track(SkTypedArray* array); - void track(SkString* string); - void unboxCallBack(_unboxCallBack func, void* userStorage); - static bool ConvertTo(SkScriptEngine* , SkDisplayTypes toType, SkScriptValue* value); - static SkScalar IntToScalar(int32_t ); - static SkDisplayTypes ToDisplayType(SkOpType type); - static SkOpType ToOpType(SkDisplayTypes type); - static bool ValueToString(SkScriptValue value, SkString* string); - - enum CallBackType { - kBox, - kFunction, - kMember, - kMemberFunction, - // kObjectToString, - kProperty, - kUnbox - }; - - struct UserCallBack { - CallBackType fCallBackType; - void* fUserStorage; - union { - _boxCallBack fBoxCallBack; - _functionCallBack fFunctionCallBack; - _memberCallBack fMemberCallBack; - _memberFunctionCallBack fMemberFunctionCallBack; - // _objectToStringCallBack fObjectToStringCallBack; - _propertyCallBack fPropertyCallBack; - _unboxCallBack fUnboxCallBack; - }; - }; - - enum SkOp { - kUnassigned, - kAdd, - kAddInt = kAdd, - kAddScalar, - kAddString, // string concat - kArrayOp, - kBitAnd, - kBitNot, - kBitOr, - kDivide, - kDivideInt = kDivide, - kDivideScalar, - kElse, - kEqual, - kEqualInt = kEqual, - kEqualScalar, - kEqualString, - kFlipOps, - kGreaterEqual, - kGreaterEqualInt = kGreaterEqual, - kGreaterEqualScalar, - kGreaterEqualString, - kIf, - kLogicalAnd, - kLogicalNot, - kLogicalOr, - kMinus, - kMinusInt = kMinus, - kMinusScalar, - kModulo, - kModuloInt = kModulo, - kModuloScalar, - kMultiply, - kMultiplyInt = kMultiply, - kMultiplyScalar, - kParen, - kShiftLeft, - kShiftRight, // signed - kSubtract, - kSubtractInt = kSubtract, - kSubtractScalar, - kXor, - kArtificialOp = 0x40 - }; - - enum SkOpBias { - kNoBias, - kTowardsNumber = 0, - kTowardsString - }; - -protected: - - struct SkOperatorAttributes { - unsigned int fLeftType : 3; // SkOpType, but only lower values - unsigned int fRightType : 3; // SkOpType, but only lower values - SkOpBias fBias : 1; - }; - - struct SkSuppress { // !!! could be compressed to a long - SkOp fOperator; // operand which enabled suppression - int fOpStackDepth; // depth when suppression operator was found - SkBool8 fSuppress; // set if suppression happens now, as opposed to later - SkBool8 fElse; // set on the : half of ? : - }; - - static const SkOperatorAttributes gOpAttributes[]; - static const signed char gPrecedence[]; - int arithmeticOp(char ch, char nextChar, bool lastPush); - void commonCallBack(CallBackType type, UserCallBack& callBack, void* userStorage); - bool convertParams(SkTDArray&, const SkFunctionParamType* , - int paramTypeCount); - void convertToString(SkOperand& operand, SkDisplayTypes type) { - SkScriptValue scriptValue; - scriptValue.fOperand = operand; - scriptValue.fType = type; - convertTo(SkType_String, &scriptValue); - operand = scriptValue.fOperand; - } - bool evaluateDot(const char*& script, bool suppressed); - bool evaluateDotParam(const char*& script, bool suppressed, const char* field, size_t fieldLength); - bool functionParams(const char** scriptPtr, SkTDArray& params); - bool handleArrayIndexer(const char** scriptPtr, bool suppressed); - bool handleBox(SkScriptValue* value); - bool handleFunction(const char** scriptPtr, bool suppressed); - bool handleMember(const char* field, size_t len, void* object); - bool handleMemberFunction(const char* field, size_t len, void* object, SkTDArray& params); -// bool handleObjectToString(void* object); - bool handleProperty(bool suppressed); - bool handleUnbox(SkScriptValue* scriptValue); - bool innerScript(const char** scriptPtr, SkScriptValue* value); - int logicalOp(char ch, char nextChar); - Error opError(); - bool processOp(); - void setAnimateMaker(SkAnimateMaker* maker) { fMaker = maker; } - bool setError(Error , const char* pos); - enum SkBraceStyle { - // kStructBrace, - kArrayBrace, - kFunctionBrace - }; - -#if 0 - SkIntArray(SkBraceStyle) fBraceStack; // curly, square, function paren - SkIntArray(SkOp) fOpStack; - SkIntArray(SkOpType) fTypeStack; - SkTDOperandArray fOperandStack; - SkTDArray fSuppressStack; -#else - SkTDStack fBraceStack; // curly, square, function paren - SkTDStack fOpStack; - SkTDStack fTypeStack; - SkTDStack fOperandStack; - SkTDStack fSuppressStack; -#endif - SkAnimateMaker* fMaker; - SkTDTypedArrayArray fTrackArray; - SkTDStringArray fTrackString; - const char* fToken; // one-deep stack - size_t fTokenLength; - SkTDArray fUserCallBacks; - SkOpType fReturnType; - Error fError; - int fErrorPosition; -private: - friend class SkTypedArray; -#ifdef SK_SUPPORT_UNITTEST -public: - static void UnitTest(); -#endif -}; - -#ifdef SK_SUPPORT_UNITTEST - -struct SkScriptNAnswer { - const char* fScript; - SkDisplayTypes fType; - int32_t fIntAnswer; - SkScalar fScalarAnswer; - const char* fStringAnswer; -}; - -#endif - -#endif // SkScript_DEFINED diff --git a/gfx/skia/skia/src/animator/SkScript2.h b/gfx/skia/skia/src/animator/SkScript2.h deleted file mode 100644 index f257adb45033..000000000000 --- a/gfx/skia/skia/src/animator/SkScript2.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkScript2_DEFINED -#define SkScript2_DEFINED - -#include "SkDisplayType.h" -#include "SkOperand2.h" -#include "SkStream.h" -#include "SkTDArray.h" -#include "SkTDArray_Experimental.h" -#include "SkTDict.h" -#include "SkTDStack.h" - -typedef SkLongArray(SkString*) SkTDStringArray; - -class SkAnimateMaker; -class SkScriptCallBack; - -class SkScriptEngine2 { -public: - enum Error { - kNoError, - kArrayIndexOutOfBounds, - kCouldNotFindReferencedID, - kFunctionCallFailed, - kMemberOpFailed, - kPropertyOpFailed - }; - - enum Attrs { - kConstant, - kVariable - }; - - SkScriptEngine2(SkOperand2::OpType returnType); - ~SkScriptEngine2(); - bool convertTo(SkOperand2::OpType , SkScriptValue2* ); - bool evaluateScript(const char** script, SkScriptValue2* value); - void forget(SkOpArray* array); - Error getError() { return fError; } - SkOperand2::OpType getReturnType() { return fReturnType; } - void track(SkOpArray* array) { - SkASSERT(fTrackArray.find(array) < 0); - *fTrackArray.append() = array; } - void track(SkString* string) { - SkASSERT(fTrackString.find(string) < 0); - *fTrackString.append() = string; - } - static bool ConvertTo(SkScriptEngine2* , SkOperand2::OpType toType, SkScriptValue2* value); - static SkScalar IntToScalar(int32_t ); - static bool ValueToString(const SkScriptValue2& value, SkString* string); - - enum Op { // used by tokenizer attribute table - kUnassigned, - kAdd, - kBitAnd, - kBitNot, - kBitOr, - kDivide, - kEqual, - kFlipOps, - kGreaterEqual, - kLogicalAnd, - kLogicalNot, - kLogicalOr, - kMinus, - kModulo, - kMultiply, - kShiftLeft, - kShiftRight, // signed - kSubtract, - kXor, -// following not in attribute table - kArrayOp, - kElse, - kIf, - kParen, - kLastLogicalOp, - kArtificialOp = 0x20 - }; - - enum TypeOp { // generated by tokenizer - kNop, // should never get generated - kAccumulatorPop, - kAccumulatorPush, - kAddInt, - kAddScalar, - kAddString, // string concat - kArrayIndex, - kArrayParam, - kArrayToken, - kBitAndInt, - kBitNotInt, - kBitOrInt, - kBoxToken, - kCallback, - kDivideInt, - kDivideScalar, - kDotOperator, - kElseOp, - kEnd, - kEqualInt, - kEqualScalar, - kEqualString, - kFunctionCall, - kFlipOpsOp, - kFunctionToken, - kGreaterEqualInt, - kGreaterEqualScalar, - kGreaterEqualString, - kIfOp, - kIntToScalar, - kIntToScalar2, - kIntToString, - kIntToString2, - kIntegerAccumulator, - kIntegerOperand, - kLogicalAndInt, - kLogicalNotInt, - kLogicalOrInt, - kMemberOp, - kMinusInt, - kMinusScalar, - kModuloInt, - kModuloScalar, - kMultiplyInt, - kMultiplyScalar, - kPropertyOp, - kScalarAccumulator, - kScalarOperand, - kScalarToInt, - kScalarToInt2, - kScalarToString, - kScalarToString2, - kShiftLeftInt, - kShiftRightInt, // signed - kStringAccumulator, - kStringOperand, - kStringToInt, - kStringToScalar, - kStringToScalar2, - kStringTrack, - kSubtractInt, - kSubtractScalar, - kToBool, - kUnboxToken, - kUnboxToken2, - kXorInt, - kLastTypeOp - }; - - enum OpBias { - kNoBias, - kTowardsNumber = 0, - kTowardsString - }; - -protected: - - enum BraceStyle { - // kStructBrace, - kArrayBrace, - kFunctionBrace - }; - - enum AddTokenRegister { - kAccumulator, - kOperand - }; - - enum ResultIsBoolean { - kResultIsNotBoolean, - kResultIsBoolean - }; - - struct OperatorAttributes { - unsigned int fLeftType : 3; // SkOpType union, but only lower values - unsigned int fRightType : 3; // SkOpType union, but only lower values - OpBias fBias : 1; - ResultIsBoolean fResultIsBoolean : 1; - }; - - struct Branch { - Branch() { - } - - Branch(Op op, int depth, size_t offset) - : fOffset(SkToU16(offset)), fOpStackDepth(depth), fOperator(op) - , fPrimed(kIsNotPrimed), fDone(kIsNotDone) { - } - - enum Primed { - kIsNotPrimed, - kIsPrimed - }; - - enum Done { - kIsNotDone, - kIsDone, - }; - - unsigned fOffset : 16; // offset in generated stream where branch needs to go - int fOpStackDepth : 7; // depth when operator was found - Op fOperator : 6; // operand which generated branch - mutable Primed fPrimed : 1; // mark when next instruction generates branch - Done fDone : 1; // mark when branch is complete - void prime() { fPrimed = kIsPrimed; } - void resolve(SkDynamicMemoryWStream* , size_t offset); - }; - - static const OperatorAttributes gOpAttributes[]; - static const signed char gPrecedence[]; - static const TypeOp gTokens[]; - void addToken(TypeOp ); - void addTokenConst(SkScriptValue2* , AddTokenRegister , SkOperand2::OpType , TypeOp ); - void addTokenInt(int ); - void addTokenScalar(SkScalar ); - void addTokenString(const SkString& ); - void addTokenValue(const SkScriptValue2& , AddTokenRegister ); - int arithmeticOp(char ch, char nextChar, bool lastPush); - bool convertParams(SkTDArray* , - const SkOperand2::OpType* paramTypes, int paramTypeCount); - void convertToString(SkOperand2* operand, SkOperand2::OpType type) { - SkScriptValue2 scriptValue; - scriptValue.fOperand = *operand; - scriptValue.fType = type; - convertTo(SkOperand2::kString, &scriptValue); - *operand = scriptValue.fOperand; - } - bool evaluateDot(const char*& script); - bool evaluateDotParam(const char*& script, const char* field, size_t fieldLength); - bool functionParams(const char** scriptPtr, SkTDArray* params); - size_t getTokenOffset(); - SkOperand2::OpType getUnboxType(SkOperand2 scriptValue); - bool handleArrayIndexer(const char** scriptPtr); - bool handleFunction(const char** scriptPtr); - bool handleMember(const char* field, size_t len, void* object); - bool handleMemberFunction(const char* field, size_t len, void* object, - SkTDArray* params); - bool handleProperty(); - bool handleUnbox(SkScriptValue2* scriptValue); - bool innerScript(const char** scriptPtr, SkScriptValue2* value); - int logicalOp(char ch, char nextChar); - void processLogicalOp(Op op); - bool processOp(); - void resolveBranch(Branch& ); -// void setAnimateMaker(SkAnimateMaker* maker) { fMaker = maker; } - SkDynamicMemoryWStream fStream; - SkDynamicMemoryWStream* fActiveStream; - SkTDStack fBraceStack; // curly, square, function paren - SkTDStack fBranchStack; // logical operators, slot to store forward branch - SkLongArray(SkScriptCallBack*) fCallBackArray; - SkTDStack fOpStack; - SkTDStack fValueStack; -// SkAnimateMaker* fMaker; - SkLongArray(SkOpArray*) fTrackArray; - SkTDStringArray fTrackString; - const char* fToken; // one-deep stack - size_t fTokenLength; - SkOperand2::OpType fReturnType; - Error fError; - SkOperand2::OpType fAccumulatorType; // tracking for code generation - SkBool fBranchPopAllowed; - SkBool fConstExpression; - SkBool fOperandInUse; -private: -#ifdef SK_DEBUG -public: - void decompile(const unsigned char* , size_t ); - static void UnitTest(); - static void ValidateDecompileTable(); -#endif -}; - -#ifdef SK_DEBUG - -struct SkScriptNAnswer2 { - const char* fScript; - SkOperand2::OpType fType; - int32_t fIntAnswer; - SkScalar fScalarAnswer; - const char* fStringAnswer; -}; - -#endif - - -#endif // SkScript2_DEFINED diff --git a/gfx/skia/skia/src/animator/SkScriptCallBack.h b/gfx/skia/skia/src/animator/SkScriptCallBack.h deleted file mode 100644 index fefc482f6166..000000000000 --- a/gfx/skia/skia/src/animator/SkScriptCallBack.h +++ /dev/null @@ -1,67 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkScriptCallBack_DEFINED -#define SkScriptCallBack_DEFINED - -#include "SkOperand2.h" -#include "SkTDArray_Experimental.h" - -class SkScriptCallBack { -public: - virtual ~SkScriptCallBack() { } - - enum Type { - kBox, - kFunction, - kMember, - kMemberFunction, - kProperty, - kUnbox - }; - - virtual bool getReference(const char* , size_t len, SkScriptValue2* result) { return false; } - virtual SkOperand2::OpType getReturnType(size_t ref, SkOperand2*) { - return SkOperand2::kS32; } - virtual Type getType() const = 0; -}; - -class SkScriptCallBackConvert : public SkScriptCallBack { -public: - virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) = 0; -}; - -class SkScriptCallBackFunction : public SkScriptCallBack { -public: - virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) = 0; - virtual Type getType() const { return kFunction; } - virtual bool invoke(size_t ref, SkOpArray* params, SkOperand2* value) = 0; -}; - -class SkScriptCallBackMember: public SkScriptCallBack { -public: - bool getMemberReference(const char* , size_t len, void* object, SkScriptValue2* ref); - virtual Type getType() const { return kMember; } - virtual bool invoke(size_t ref, void* object, SkOperand2* value) = 0; -}; - -class SkScriptCallBackMemberFunction : public SkScriptCallBack { -public: - bool getMemberReference(const char* , size_t len, void* object, SkScriptValue2* ref); - virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) = 0; - virtual Type getType() const { return kMemberFunction; } - virtual bool invoke(size_t ref, void* object, SkOpArray* params, SkOperand2* value) = 0; -}; - -class SkScriptCallBackProperty : public SkScriptCallBack { -public: - virtual bool getConstValue(const char* name, size_t len, SkOperand2* value) { return false; } - virtual bool getResult(size_t ref, SkOperand2* answer) { return false; } - virtual Type getType() const { return kProperty; } -}; - -#endif // SkScriptCallBack_DEFINED diff --git a/gfx/skia/skia/src/animator/SkScriptDecompile.cpp b/gfx/skia/skia/src/animator/SkScriptDecompile.cpp deleted file mode 100644 index 995da874cbf1..000000000000 --- a/gfx/skia/skia/src/animator/SkScriptDecompile.cpp +++ /dev/null @@ -1,211 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkScript2.h" - -#ifdef SK_DEBUG - -#define TypeOpName(op) {SkScriptEngine2::op, #op } - -static const struct OpName { - SkScriptEngine2::TypeOp fOp; - const char* fName; -} gOpNames[] = { - TypeOpName(kNop), // should never get generated - TypeOpName(kAccumulatorPop), - TypeOpName(kAccumulatorPush), - TypeOpName(kAddInt), - TypeOpName(kAddScalar), - TypeOpName(kAddString), // string concat - TypeOpName(kArrayIndex), - TypeOpName(kArrayParam), - TypeOpName(kArrayToken), - TypeOpName(kBitAndInt), - TypeOpName(kBitNotInt), - TypeOpName(kBitOrInt), - TypeOpName(kBoxToken), - TypeOpName(kCallback), - TypeOpName(kDivideInt), - TypeOpName(kDivideScalar), - TypeOpName(kDotOperator), - TypeOpName(kElseOp), - TypeOpName(kEnd), - TypeOpName(kEqualInt), - TypeOpName(kEqualScalar), - TypeOpName(kEqualString), - TypeOpName(kFunctionCall), - TypeOpName(kFlipOpsOp), - TypeOpName(kFunctionToken), - TypeOpName(kGreaterEqualInt), - TypeOpName(kGreaterEqualScalar), - TypeOpName(kGreaterEqualString), - TypeOpName(kIfOp), - TypeOpName(kIntToScalar), - TypeOpName(kIntToScalar2), - TypeOpName(kIntToString), - TypeOpName(kIntToString2), - TypeOpName(kIntegerAccumulator), - TypeOpName(kIntegerOperand), - TypeOpName(kLogicalAndInt), - TypeOpName(kLogicalNotInt), - TypeOpName(kLogicalOrInt), - TypeOpName(kMemberOp), - TypeOpName(kMinusInt), - TypeOpName(kMinusScalar), - TypeOpName(kModuloInt), - TypeOpName(kModuloScalar), - TypeOpName(kMultiplyInt), - TypeOpName(kMultiplyScalar), - TypeOpName(kPropertyOp), - TypeOpName(kScalarAccumulator), - TypeOpName(kScalarOperand), - TypeOpName(kScalarToInt), - TypeOpName(kScalarToInt2), - TypeOpName(kScalarToString), - TypeOpName(kScalarToString2), - TypeOpName(kShiftLeftInt), - TypeOpName(kShiftRightInt), // signed - TypeOpName(kStringAccumulator), - TypeOpName(kStringOperand), - TypeOpName(kStringToInt), - TypeOpName(kStringToScalar), - TypeOpName(kStringToScalar2), - TypeOpName(kStringTrack), - TypeOpName(kSubtractInt), - TypeOpName(kSubtractScalar), - TypeOpName(kToBool), - TypeOpName(kUnboxToken), - TypeOpName(kUnboxToken2), - TypeOpName(kXorInt) -}; - -static size_t gOpNamesSize = sizeof(gOpNames) / sizeof(gOpNames[0]); - -#define OperandName(op) {SkOperand2::op, #op } - -static const struct OperName { - SkOperand2::OpType fType; - const char* fName; -} gOperandNames[] = { - OperandName(kNoType), - OperandName(kS32), - OperandName(kScalar), - OperandName(kString), - OperandName(kArray), - OperandName(kObject) -}; - -static size_t gOperandNamesSize = sizeof(gOperandNames) / sizeof(gOperandNames[0]); - -// check to see that there are no missing or duplicate entries -void SkScriptEngine2::ValidateDecompileTable() { - SkScriptEngine2::TypeOp op = SkScriptEngine2::kNop; - size_t index; - for (index = 0; index < gOpNamesSize; index++) { - SkASSERT(gOpNames[index].fOp == op); - op = (SkScriptEngine2::TypeOp) (op + 1); - } - index = 0; - SkOperand2::OpType type = SkOperand2::kNoType; - SkASSERT(gOperandNames[index].fType == type); - for (; index < gOperandNamesSize - 1; ) { - type = (SkOperand2::OpType) (1 << index); - SkASSERT(gOperandNames[++index].fType == type); - } -} - -void SkScriptEngine2::decompile(const unsigned char* start, size_t length) { - SkASSERT(length > 0); - const unsigned char* opCode = start; - do { - SkASSERT((size_t)(opCode - start) < length); - SkScriptEngine2::TypeOp op = (SkScriptEngine2::TypeOp) *opCode++; - SkASSERT((size_t)op < gOpNamesSize); - SkDebugf("%d: %s", opCode - start - 1, gOpNames[op].fName); - switch (op) { - case SkScriptEngine2::kCallback: { - int index; - memcpy(&index, opCode, sizeof(index)); - opCode += sizeof(index); - SkDebugf(" index: %d", index); - } break; - case SkScriptEngine2::kFunctionCall: - case SkScriptEngine2::kMemberOp: - case SkScriptEngine2::kPropertyOp: { - size_t ref; - memcpy(&ref, opCode, sizeof(ref)); - opCode += sizeof(ref); - SkDebugf(" ref: %d", ref); - } break; - case SkScriptEngine2::kIntegerAccumulator: - case SkScriptEngine2::kIntegerOperand: { - int32_t integer; - memcpy(&integer, opCode, sizeof(integer)); - opCode += sizeof(int32_t); - SkDebugf(" integer: %d", integer); - } break; - case SkScriptEngine2::kScalarAccumulator: - case SkScriptEngine2::kScalarOperand: { - SkScalar scalar; - memcpy(&scalar, opCode, sizeof(scalar)); - opCode += sizeof(SkScalar); - SkDebugf(" scalar: %g", SkScalarToFloat(scalar)); - } break; - case SkScriptEngine2::kStringAccumulator: - case SkScriptEngine2::kStringOperand: { - int size; - SkString* strPtr = new SkString(); - memcpy(&size, opCode, sizeof(size)); - opCode += sizeof(size); - strPtr->set((char*) opCode, size); - opCode += size; - SkDebugf(" string: %s", strPtr->c_str()); - delete strPtr; - } break; - case SkScriptEngine2::kBoxToken: { - SkOperand2::OpType type; - memcpy(&type, opCode, sizeof(type)); - opCode += sizeof(type); - size_t index = 0; - if (type == 0) - SkDebugf(" type: %s", gOperandNames[index].fName); - else { - while (type != 0) { - SkASSERT(index + 1 < gOperandNamesSize); - if (type & (1 << index)) { - type = (SkOperand2::OpType) (type & ~(1 << index)); - SkDebugf(" type: %s", gOperandNames[index + 1].fName); - } - index++; - } - } - } break; - case SkScriptEngine2::kIfOp: - case SkScriptEngine2::kLogicalAndInt: - case SkScriptEngine2::kElseOp: - case SkScriptEngine2::kLogicalOrInt: { - int size; - memcpy(&size, opCode, sizeof(size)); - opCode += sizeof(size); - SkDebugf(" offset (address): %d (%d)", size, opCode - start + size); - } break; - case SkScriptEngine2::kEnd: - goto done; - case SkScriptEngine2::kNop: - SkASSERT(0); - default: - break; - } - SkDebugf("\n"); - } while (true); -done: - SkDebugf("\n"); -} - -#endif diff --git a/gfx/skia/skia/src/animator/SkScriptRuntime.cpp b/gfx/skia/skia/src/animator/SkScriptRuntime.cpp deleted file mode 100644 index 7cb35a69db2c..000000000000 --- a/gfx/skia/skia/src/animator/SkScriptRuntime.cpp +++ /dev/null @@ -1,351 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkScriptRuntime.h" -#include "SkScript2.h" -#include "SkMath.h" -#include "SkParse.h" -#include "SkScriptCallBack.h" -#include "SkString.h" -#include "SkOpArray.h" - -// script tokenizer - -// turn text into token string -// turn number literals into inline UTF8-style values -// process operators to turn standard notation into stack notation - -// defer processing until the tokens can all be resolved -// then, turn token strings into indices into the appropriate tables / dictionaries - -// consider: const evaluation? - -// replace script string with script tokens preceeded by special value - -// need second version of script plugins that return private index of found value? - // then would need in script index of plugin, private index - -// encode brace stack push/pop as opcodes - -// should token script enocde type where possible? - -// current flow: - // strip whitespace - // if in array brace [ recurse, continue - // if token, handle function, or array, or property (continue) - // parse number, continue - // parse token, continue - // parse string literal, continue - // if dot operator, handle dot, continue - // if [ , handle array literal or accessor, continue - // if ), pop (if function, break) - // if ], pop ; if ',' break - // handle logical ops - // or, handle arithmetic ops - // loop - -// !!! things to do - // add separate processing loop to advance while suppressed - // or, include jump offset to skip suppressed code? - -SkScriptRuntime::~SkScriptRuntime() { - for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++) - delete *stringPtr; - for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++) - delete *arrayPtr; -} - -bool SkScriptRuntime::executeTokens(unsigned char* opCode) { - SkOperand2 operand[2]; // 1=accumulator and 2=operand - SkScriptEngine2::TypeOp op; - size_t ref; - int index, size; - int registerLoad; - SkScriptCallBack* callBack SK_INIT_TO_AVOID_WARNING; - do { - switch ((op = (SkScriptEngine2::TypeOp) *opCode++)) { - case SkScriptEngine2::kArrayToken: // create an array - operand[0].fArray = new SkOpArray(SkOperand2::kNoType /*fReturnType*/); - break; - case SkScriptEngine2::kArrayIndex: // array accessor - index = operand[1].fS32; - if (index >= operand[0].fArray->count()) { - fError = kArrayIndexOutOfBounds; - return false; - } - operand[0] = operand[0].fArray->begin()[index]; - break; - case SkScriptEngine2::kArrayParam: // array initializer, or function param - *operand[0].fArray->append() = operand[1]; - break; - case SkScriptEngine2::kCallback: - memcpy(&index, opCode, sizeof(index)); - opCode += sizeof(index); - callBack = fCallBackArray[index]; - break; - case SkScriptEngine2::kFunctionCall: { - memcpy(&ref, opCode, sizeof(ref)); - opCode += sizeof(ref); - SkScriptCallBackFunction* callBackFunction = (SkScriptCallBackFunction*) callBack; - if (callBackFunction->invoke(ref, operand[0].fArray, /* params */ - &operand[0] /* result */) == false) { - fError = kFunctionCallFailed; - return false; - } - } break; - case SkScriptEngine2::kMemberOp: { - memcpy(&ref, opCode, sizeof(ref)); - opCode += sizeof(ref); - SkScriptCallBackMember* callBackMember = (SkScriptCallBackMember*) callBack; - if (callBackMember->invoke(ref, operand[0].fObject, &operand[0]) == false) { - fError = kMemberOpFailed; - return false; - } - } break; - case SkScriptEngine2::kPropertyOp: { - memcpy(&ref, opCode, sizeof(ref)); - opCode += sizeof(ref); - SkScriptCallBackProperty* callBackProperty = (SkScriptCallBackProperty*) callBack; - if (callBackProperty->getResult(ref, &operand[0])== false) { - fError = kPropertyOpFailed; - return false; - } - } break; - case SkScriptEngine2::kAccumulatorPop: - fRunStack.pop(&operand[0]); - break; - case SkScriptEngine2::kAccumulatorPush: - *fRunStack.push() = operand[0]; - break; - case SkScriptEngine2::kIntegerAccumulator: - case SkScriptEngine2::kIntegerOperand: - registerLoad = op - SkScriptEngine2::kIntegerAccumulator; - memcpy(&operand[registerLoad].fS32, opCode, sizeof(int32_t)); - opCode += sizeof(int32_t); - break; - case SkScriptEngine2::kScalarAccumulator: - case SkScriptEngine2::kScalarOperand: - registerLoad = op - SkScriptEngine2::kScalarAccumulator; - memcpy(&operand[registerLoad].fScalar, opCode, sizeof(SkScalar)); - opCode += sizeof(SkScalar); - break; - case SkScriptEngine2::kStringAccumulator: - case SkScriptEngine2::kStringOperand: { - SkString* strPtr = new SkString(); - track(strPtr); - registerLoad = op - SkScriptEngine2::kStringAccumulator; - memcpy(&size, opCode, sizeof(size)); - opCode += sizeof(size); - strPtr->set((char*) opCode, size); - opCode += size; - operand[registerLoad].fString = strPtr; - } break; - case SkScriptEngine2::kStringTrack: // call after kObjectToValue - track(operand[0].fString); - break; - case SkScriptEngine2::kBoxToken: { - SkOperand2::OpType type; - memcpy(&type, opCode, sizeof(type)); - opCode += sizeof(type); - SkScriptCallBackConvert* callBackBox = (SkScriptCallBackConvert*) callBack; - if (callBackBox->convert(type, &operand[0]) == false) - return false; - } break; - case SkScriptEngine2::kUnboxToken: - case SkScriptEngine2::kUnboxToken2: { - SkScriptCallBackConvert* callBackUnbox = (SkScriptCallBackConvert*) callBack; - if (callBackUnbox->convert(SkOperand2::kObject, &operand[0]) == false) - return false; - } break; - case SkScriptEngine2::kIfOp: - case SkScriptEngine2::kLogicalAndInt: - memcpy(&size, opCode, sizeof(size)); - opCode += sizeof(size); - if (operand[0].fS32 == 0) - opCode += size; // skip to else (or end of if predicate) - break; - case SkScriptEngine2::kElseOp: - memcpy(&size, opCode, sizeof(size)); - opCode += sizeof(size); - opCode += size; // if true: after predicate, always skip to end of else - break; - case SkScriptEngine2::kLogicalOrInt: - memcpy(&size, opCode, sizeof(size)); - opCode += sizeof(size); - if (operand[0].fS32 != 0) - opCode += size; // skip to kToBool opcode after || predicate - break; - // arithmetic conversion ops - case SkScriptEngine2::kFlipOpsOp: - SkTSwap(operand[0], operand[1]); - break; - case SkScriptEngine2::kIntToString: - case SkScriptEngine2::kIntToString2: - case SkScriptEngine2::kScalarToString: - case SkScriptEngine2::kScalarToString2:{ - SkString* strPtr = new SkString(); - track(strPtr); - if (op == SkScriptEngine2::kIntToString || op == SkScriptEngine2::kIntToString2) - strPtr->appendS32(operand[op - SkScriptEngine2::kIntToString].fS32); - else - strPtr->appendScalar(operand[op - SkScriptEngine2::kScalarToString].fScalar); - operand[0].fString = strPtr; - } break; - case SkScriptEngine2::kIntToScalar: - case SkScriptEngine2::kIntToScalar2: - operand[0].fScalar = SkScriptEngine2::IntToScalar(operand[op - SkScriptEngine2::kIntToScalar].fS32); - break; - case SkScriptEngine2::kStringToInt: - if (SkParse::FindS32(operand[0].fString->c_str(), &operand[0].fS32) == nullptr) - return false; - break; - case SkScriptEngine2::kStringToScalar: - case SkScriptEngine2::kStringToScalar2: - if (SkParse::FindScalar(operand[0].fString->c_str(), - &operand[op - SkScriptEngine2::kStringToScalar].fScalar) == nullptr) - return false; - break; - case SkScriptEngine2::kScalarToInt: - operand[0].fS32 = SkScalarFloorToInt(operand[0].fScalar); - break; - // arithmetic ops - case SkScriptEngine2::kAddInt: - operand[0].fS32 += operand[1].fS32; - break; - case SkScriptEngine2::kAddScalar: - operand[0].fScalar += operand[1].fScalar; - break; - case SkScriptEngine2::kAddString: -// if (fTrackString.find(operand[1].fString) < 0) { - // operand[1].fString = new SkString (*operand[1].fString); - // track(operand[1].fString); - // } - operand[0].fString->append(*operand[1].fString); - break; - case SkScriptEngine2::kBitAndInt: - operand[0].fS32 &= operand[1].fS32; - break; - case SkScriptEngine2::kBitNotInt: - operand[0].fS32 = ~operand[0].fS32; - break; - case SkScriptEngine2::kBitOrInt: - operand[0].fS32 |= operand[1].fS32; - break; - case SkScriptEngine2::kDivideInt: - SkASSERT(operand[1].fS32 != 0); - if (operand[1].fS32 == 0) - operand[0].fS32 = operand[0].fS32 == 0 ? SK_NaN32 : - operand[0].fS32 > 0 ? SK_MaxS32 : -SK_MaxS32; - else - if (operand[1].fS32 != 0) // throw error on divide by zero? - operand[0].fS32 /= operand[1].fS32; - break; - case SkScriptEngine2::kDivideScalar: - if (operand[1].fScalar == 0) - operand[0].fScalar = operand[0].fScalar == 0 ? SK_ScalarNaN : - operand[0].fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax; - else - operand[0].fScalar = operand[0].fScalar / operand[1].fScalar; - break; - case SkScriptEngine2::kEqualInt: - operand[0].fS32 = operand[0].fS32 == operand[1].fS32; - break; - case SkScriptEngine2::kEqualScalar: - operand[0].fS32 = operand[0].fScalar == operand[1].fScalar; - break; - case SkScriptEngine2::kEqualString: - operand[0].fS32 = *operand[0].fString == *operand[1].fString; - break; - case SkScriptEngine2::kGreaterEqualInt: - operand[0].fS32 = operand[0].fS32 >= operand[1].fS32; - break; - case SkScriptEngine2::kGreaterEqualScalar: - operand[0].fS32 = operand[0].fScalar >= operand[1].fScalar; - break; - case SkScriptEngine2::kGreaterEqualString: - operand[0].fS32 = strcmp(operand[0].fString->c_str(), operand[1].fString->c_str()) >= 0; - break; - case SkScriptEngine2::kToBool: - operand[0].fS32 = !! operand[0].fS32; - break; - case SkScriptEngine2::kLogicalNotInt: - operand[0].fS32 = ! operand[0].fS32; - break; - case SkScriptEngine2::kMinusInt: - operand[0].fS32 = -operand[0].fS32; - break; - case SkScriptEngine2::kMinusScalar: - operand[0].fScalar = -operand[0].fScalar; - break; - case SkScriptEngine2::kModuloInt: - operand[0].fS32 %= operand[1].fS32; - break; - case SkScriptEngine2::kModuloScalar: - operand[0].fScalar = SkScalarMod(operand[0].fScalar, operand[1].fScalar); - break; - case SkScriptEngine2::kMultiplyInt: - operand[0].fS32 *= operand[1].fS32; - break; - case SkScriptEngine2::kMultiplyScalar: - operand[0].fScalar = SkScalarMul(operand[0].fScalar, operand[1].fScalar); - break; - case SkScriptEngine2::kShiftLeftInt: - operand[0].fS32 <<= operand[1].fS32; - break; - case SkScriptEngine2::kShiftRightInt: - operand[0].fS32 >>= operand[1].fS32; - break; - case SkScriptEngine2::kSubtractInt: - operand[0].fS32 -= operand[1].fS32; - break; - case SkScriptEngine2::kSubtractScalar: - operand[0].fScalar -= operand[1].fScalar; - break; - case SkScriptEngine2::kXorInt: - operand[0].fS32 ^= operand[1].fS32; - break; - case SkScriptEngine2::kEnd: - goto done; - case SkScriptEngine2::kNop: - SkASSERT(0); - default: - break; - } - } while (true); -done: - fRunStack.push(operand[0]); - return true; -} - -bool SkScriptRuntime::getResult(SkOperand2* result) { - if (fRunStack.count() == 0) - return false; - fRunStack.pop(result); - return true; -} - -void SkScriptRuntime::track(SkOpArray* array) { - SkASSERT(fTrackArray.find(array) < 0); - *fTrackArray.append() = array; -} - -void SkScriptRuntime::track(SkString* string) { - SkASSERT(fTrackString.find(string) < 0); - *fTrackString.append() = string; -} - -void SkScriptRuntime::untrack(SkOpArray* array) { - int index = fTrackArray.find(array); - SkASSERT(index >= 0); - fTrackArray.begin()[index] = nullptr; -} - -void SkScriptRuntime::untrack(SkString* string) { - int index = fTrackString.find(string); - SkASSERT(index >= 0); - fTrackString.begin()[index] = nullptr; -} diff --git a/gfx/skia/skia/src/animator/SkScriptRuntime.h b/gfx/skia/skia/src/animator/SkScriptRuntime.h deleted file mode 100644 index 3e7380114894..000000000000 --- a/gfx/skia/skia/src/animator/SkScriptRuntime.h +++ /dev/null @@ -1,50 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkScriptRuntime_DEFINED -#define SkScriptRuntime_DEFINED - -#include "SkOperand2.h" -#include "SkTDArray_Experimental.h" -#include "SkTDStack.h" - -class SkScriptCallBack; - -typedef SkLongArray(SkString*) SkTDStringArray; -typedef SkLongArray(SkScriptCallBack*) SkTDScriptCallBackArray; - -class SkScriptRuntime { -public: - enum SkError { - kNoError, - kArrayIndexOutOfBounds, - kCouldNotFindReferencedID, - kFunctionCallFailed, - kMemberOpFailed, - kPropertyOpFailed - }; - - SkScriptRuntime(SkTDScriptCallBackArray& callBackArray) : fCallBackArray(callBackArray) - { } - ~SkScriptRuntime(); - bool executeTokens(unsigned char* opCode); - bool getResult(SkOperand2* result); - void untrack(SkOpArray* array); - void untrack(SkString* string); -private: - void track(SkOpArray* array); - void track(SkString* string); - SkTDScriptCallBackArray& fCallBackArray; - SkError fError; - SkTDStack fRunStack; - SkLongArray(SkOpArray*) fTrackArray; - SkTDStringArray fTrackString; - // illegal - SkScriptRuntime& operator=(const SkScriptRuntime&); -}; - -#endif // SkScriptRuntime_DEFINED diff --git a/gfx/skia/skia/src/animator/SkScriptTokenizer.cpp b/gfx/skia/skia/src/animator/SkScriptTokenizer.cpp deleted file mode 100644 index 4ab7584f7a89..000000000000 --- a/gfx/skia/skia/src/animator/SkScriptTokenizer.cpp +++ /dev/null @@ -1,1506 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkScript2.h" -#include "SkData.h" -#include "SkFloatingPoint.h" -#include "SkMath.h" -#include "SkParse.h" -#include "SkScriptCallBack.h" -#include "SkScriptRuntime.h" -#include "SkString.h" -#include "SkOpArray.h" - -const SkScriptEngine2::OperatorAttributes SkScriptEngine2::gOpAttributes[] = { -{ SkOperand2::kNoType, SkOperand2::kNoType, kNoBias, kResultIsNotBoolean }, -{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), - SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsString, kResultIsNotBoolean }, // kAdd -{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitAnd -{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitNot -{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitOr -{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), - SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kDivide -{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), - SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar |SkOperand2:: kString), kTowardsNumber, - kResultIsBoolean }, // kEqual -{ SkOperand2::kS32, SkOperand2::kNoType, kNoBias, kResultIsNotBoolean }, // kFlipOps -{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), - SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsNumber, - kResultIsBoolean }, // kGreaterEqual -{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalAnd (really, ToBool) -{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalNot -{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalOr -{ SkOperand2::kNoType, SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kMinus -{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), - SkOperand2::OpType(SkOperand2::kS32 |SkOperand2:: kScalar), kNoBias, kResultIsNotBoolean }, // kModulo -{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), - SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kMultiply -{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kShiftLeft -{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kShiftRight -{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), - SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kSubtract -{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean } // kXor -}; - -#define kBracketPrecedence 16 -#define kIfElsePrecedence 15 - -const signed char SkScriptEngine2::gPrecedence[] = { - 17, // kUnassigned, - 6, // kAdd, - 10, // kBitAnd, - 4, // kBitNot, - 12, // kBitOr, - 5, // kDivide, - 9, // kEqual, - -1, // kFlipOps, - 8, // kGreaterEqual, - 13, // kLogicalAnd, - 4, // kLogicalNot, - 14, // kLogicalOr, - 4, // kMinus, - 5, // kModulo, - 5, // kMultiply, - 7, // kShiftLeft, - 7, // kShiftRight, // signed - 6, // kSubtract, - 11, // kXor - kBracketPrecedence, // kArrayOp - kIfElsePrecedence, // kElse - kIfElsePrecedence, // kIf - kBracketPrecedence, // kParen -}; - -const SkScriptEngine2::TypeOp SkScriptEngine2::gTokens[] = { - kNop, // unassigned - kAddInt, // kAdd, - kBitAndInt, // kBitAnd, - kBitNotInt, // kBitNot, - kBitOrInt, // kBitOr, - kDivideInt, // kDivide, - kEqualInt, // kEqual, - kFlipOpsOp, // kFlipOps, - kGreaterEqualInt, // kGreaterEqual, - kLogicalAndInt, // kLogicalAnd, - kLogicalNotInt, // kLogicalNot, - kLogicalOrInt, // kLogicalOr, - kMinusInt, // kMinus, - kModuloInt, // kModulo, - kMultiplyInt, // kMultiply, - kShiftLeftInt, // kShiftLeft, - kShiftRightInt, // kShiftRight, // signed - kSubtractInt, // kSubtract, - kXorInt // kXor -}; - -static inline bool is_between(int c, int min, int max) -{ - return (unsigned)(c - min) <= (unsigned)(max - min); -} - -static inline bool is_ws(int c) -{ - return is_between(c, 1, 32); -} - -static int token_length(const char* start) { - char ch = start[0]; - if (! is_between(ch, 'a' , 'z') && ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$') - return -1; - int length = 0; - do - ch = start[++length]; - while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') || - ch == '_' || ch == '$'); - return length; -} - -SkScriptEngine2::SkScriptEngine2(SkOperand2::OpType returnType) : fActiveStream(&fStream), -fTokenLength(0), fReturnType(returnType), fError(kNoError), -fAccumulatorType(SkOperand2::kNoType), -fBranchPopAllowed(true), fConstExpression(true), fOperandInUse(false) -{ - Branch branch(kUnassigned, 0, 0); - fBranchStack.push(branch); - *fOpStack.push() = (Op) kParen; -} - -SkScriptEngine2::~SkScriptEngine2() { - for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++) - delete *stringPtr; - for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++) - delete *arrayPtr; -} - -void SkScriptEngine2::addToken(SkScriptEngine2::TypeOp op) { - int limit = fBranchStack.count() - 1; - for (int index = 0; index < limit; index++) { - Branch& branch = fBranchStack.index(index); - if (branch.fPrimed == Branch::kIsPrimed) - resolveBranch(branch); - } - if (fBranchPopAllowed) { - while (fBranchStack.top().fDone == Branch::kIsDone) - fBranchStack.pop(); - } - unsigned char charOp = (unsigned char) op; - fActiveStream->write(&charOp, sizeof(charOp)); -} - -void SkScriptEngine2::addTokenConst(SkScriptValue2* value, AddTokenRegister reg, - SkOperand2::OpType toType, SkScriptEngine2::TypeOp op) { - if (value->fIsConstant == SkScriptValue2::kConstant && convertTo(toType, value)) - return; - addTokenValue(*value, reg); - addToken(op); - value->fIsWritten = SkScriptValue2::kWritten; - value->fType = toType; -} - -void SkScriptEngine2::addTokenInt(int integer) { - fActiveStream->write(&integer, sizeof(integer)); -} - -void SkScriptEngine2::addTokenScalar(SkScalar scalar) { - fActiveStream->write(&scalar, sizeof(scalar)); -} - -void SkScriptEngine2::addTokenString(const SkString& string) { - int size = SkToInt(string.size()); - addTokenInt(size); - fActiveStream->write(string.c_str(), size); -} - -void SkScriptEngine2::addTokenValue(const SkScriptValue2& value, AddTokenRegister reg) { - if (value.isConstant() == false) { - if (reg == kAccumulator) { - if (fAccumulatorType == SkOperand2::kNoType) - addToken(kAccumulatorPop); - } else { - ; // !!! incomplete? - } - return; - } - if (reg == kAccumulator && fAccumulatorType != SkOperand2::kNoType) - addToken(kAccumulatorPush); - switch (value.fType) { - case SkOperand2::kS32: - addToken(reg == kAccumulator ? kIntegerAccumulator : kIntegerOperand); - addTokenInt(value.fOperand.fS32); - if (reg == kAccumulator) - fAccumulatorType = SkOperand2::kS32; - else - fOperandInUse = true; - break; - case SkOperand2::kScalar: - addToken(reg == kAccumulator ? kScalarAccumulator : kScalarOperand); - addTokenScalar(value.fOperand.fScalar); - if (reg == kAccumulator) - fAccumulatorType = SkOperand2::kScalar; - else - fOperandInUse = true; - break; - case SkOperand2::kString: - addToken(reg == kAccumulator ? kStringAccumulator : kStringOperand); - addTokenString(*value.fOperand.fString); - if (reg == kAccumulator) - fAccumulatorType = SkOperand2::kString; - else - fOperandInUse = true; - break; - default: - SkASSERT(0); //!!! not implemented yet - } -} - -int SkScriptEngine2::arithmeticOp(char ch, char nextChar, bool lastPush) { - Op op = kUnassigned; - bool reverseOperands = false; - bool negateResult = false; - int advance = 1; - switch (ch) { - case '+': - // !!! ignoring unary plus as implemented here has the side effect of - // suppressing errors like +"hi" - if (lastPush == false) // unary plus, don't push an operator - return advance; - op = kAdd; - break; - case '-': - op = lastPush ? kSubtract : kMinus; - break; - case '*': - op = kMultiply; - break; - case '/': - op = kDivide; - break; - case '>': - if (nextChar == '>') { - op = kShiftRight; - goto twoChar; - } - op = kGreaterEqual; - if (nextChar == '=') - goto twoChar; - reverseOperands = negateResult = true; - break; - case '<': - if (nextChar == '<') { - op = kShiftLeft; - goto twoChar; - } - op = kGreaterEqual; - reverseOperands = nextChar == '='; - negateResult = ! reverseOperands; - advance += reverseOperands; - break; - case '=': - if (nextChar == '=') { - op = kEqual; - goto twoChar; - } - break; - case '!': - if (nextChar == '=') { - op = kEqual; - negateResult = true; -twoChar: - advance++; - break; - } - op = kLogicalNot; - break; - case '?': - op =(Op) kIf; - break; - case ':': - op = (Op) kElse; - break; - case '^': - op = kXor; - break; - case '(': - *fOpStack.push() = (Op) kParen; - return advance; - case '&': - SkASSERT(nextChar != '&'); - op = kBitAnd; - break; - case '|': - SkASSERT(nextChar != '|'); - op = kBitOr; - break; - case '%': - op = kModulo; - break; - case '~': - op = kBitNot; - break; - } - if (op == kUnassigned) - return 0; - signed char precedence = gPrecedence[op]; - do { - int idx = 0; - Op compare; - do { - compare = fOpStack.index(idx); - if ((compare & kArtificialOp) == 0) - break; - idx++; - } while (true); - signed char topPrecedence = gPrecedence[compare]; - SkASSERT(topPrecedence != -1); - if (topPrecedence > precedence || (topPrecedence == precedence && - gOpAttributes[op].fLeftType == SkOperand2::kNoType)) { - break; - } - processOp(); - } while (true); - if (negateResult) - *fOpStack.push() = (Op) (kLogicalNot | kArtificialOp); - fOpStack.push(op); - if (reverseOperands) - *fOpStack.push() = (Op) (kFlipOps | kArtificialOp); - - return advance; -} - -bool SkScriptEngine2::convertParams(SkTDArray* params, - const SkOperand2::OpType* paramTypes, int paramCount) { - int count = params->count(); - if (count > paramCount) { - SkASSERT(0); - return false; // too many parameters passed - } - for (int index = 0; index < count; index++) - convertTo(paramTypes[index], &(*params)[index]); - return true; -} - -bool SkScriptEngine2::convertTo(SkOperand2::OpType toType, SkScriptValue2* value ) { - SkOperand2::OpType type = value->fType; - if (type == toType) - return true; - if (type == SkOperand2::kObject) { - if (handleUnbox(value) == false) - return false; - return convertTo(toType, value); - } - return ConvertTo(this, toType, value); -} - -bool SkScriptEngine2::evaluateDot(const char*& script) { - size_t fieldLength = token_length(++script); // skip dot - SkASSERT(fieldLength > 0); // !!! add error handling - const char* field = script; - script += fieldLength; - bool success = handleProperty(); - if (success == false) { - fError = kCouldNotFindReferencedID; - goto error; - } - return evaluateDotParam(script, field, fieldLength); -error: - return false; -} - -bool SkScriptEngine2::evaluateDotParam(const char*& script, const char* field, size_t fieldLength) { - SkScriptValue2& top = fValueStack.top(); - if (top.fType != SkOperand2::kObject) - return false; - void* object = top.fOperand.fObject; - fValueStack.pop(); - char ch; // see if it is a simple member or a function - while (is_ws(ch = script[0])) - script++; - bool success = true; - if (ch != '(') - success = handleMember(field, fieldLength, object); - else { - SkTDArray params; - *fBraceStack.push() = kFunctionBrace; - success = functionParams(&script, ¶ms); - if (success) - success = handleMemberFunction(field, fieldLength, object, ¶ms); - } - return success; -} - -bool SkScriptEngine2::evaluateScript(const char** scriptPtr, SkScriptValue2* value) { - // fArrayOffset = 0; // no support for structures for now - bool success; - const char* inner; - if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) { - *scriptPtr += sizeof("#script:") - 1; - if (fReturnType == SkOperand2::kNoType || fReturnType == SkOperand2::kString) { - success = innerScript(scriptPtr, value); - SkASSERT(success); - inner = value->fOperand.fString->c_str(); - scriptPtr = &inner; - } - } - success = innerScript(scriptPtr, value); - const char* script = *scriptPtr; - char ch; - while (is_ws(ch = script[0])) - script++; - if (ch != '\0') { - // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]" - return false; - } - return success; -} - -void SkScriptEngine2::forget(SkOpArray* array) { - if (array->getType() == SkOperand2::kString) { - for (int index = 0; index < array->count(); index++) { - SkString* string = (*array)[index].fString; - int found = fTrackString.find(string); - if (found >= 0) - fTrackString.remove(found); - } - return; - } - if (array->getType() == SkOperand2::kArray) { - for (int index = 0; index < array->count(); index++) { - SkOpArray* child = (*array)[index].fArray; - forget(child); // forgets children of child - int found = fTrackArray.find(child); - if (found >= 0) - fTrackArray.remove(found); - } - } -} - -bool SkScriptEngine2::functionParams(const char** scriptPtr, SkTDArray* params) { - (*scriptPtr)++; // skip open paren - *fOpStack.push() = (Op) kParen; - *fBraceStack.push() = kFunctionBrace; - do { - SkScriptValue2 value; - bool success = innerScript(scriptPtr, &value); - SkASSERT(success); - if (success == false) - return false; - *params->append() = value; - } while ((*scriptPtr)[-1] == ','); - fBraceStack.pop(); - fOpStack.pop(); // pop paren - (*scriptPtr)++; // advance beyond close paren - return true; -} - -size_t SkScriptEngine2::getTokenOffset() { - return fActiveStream->getOffset(); -} - -SkOperand2::OpType SkScriptEngine2::getUnboxType(SkOperand2 scriptValue) { - for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { - if ((*callBack)->getType() != SkScriptCallBack::kUnbox) - continue; - return (*callBack)->getReturnType(0, &scriptValue); - } - return SkOperand2::kObject; -} - -bool SkScriptEngine2::innerScript(const char** scriptPtr, SkScriptValue2* value) { - const char* script = *scriptPtr; - char ch; - bool lastPush = false; - bool success = true; - int opBalance = fOpStack.count(); - int baseBrace = fBraceStack.count(); - int branchBalance = fBranchStack.count(); - while ((ch = script[0]) != '\0') { - if (is_ws(ch)) { - script++; - continue; - } - SkScriptValue2 operand; - const char* dotCheck; - if (fBraceStack.count() > baseBrace) { - if (fBraceStack.top() == kArrayBrace) { - SkScriptValue2 tokenValue; - success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace - SkASSERT(success); - { - SkOperand2::OpType type = fReturnType; - if (fReturnType == SkOperand2::kNoType) { - // !!! short sighted; in the future, allow each returned array component to carry - // its own type, and let caller do any needed conversions - if (value->fOperand.fArray->count() == 0) - value->fOperand.fArray->setType(type = tokenValue.fType); - else - type = value->fOperand.fArray->getType(); - } - if (tokenValue.fType != type) - convertTo(type, &tokenValue); - *value->fOperand.fArray->append() = tokenValue.fOperand; - } - lastPush = false; - continue; - } else { - SkASSERT(token_length(script) > 0); - } - } - if (lastPush != false && fTokenLength > 0) { - if (ch == '(') { - *fBraceStack.push() = kFunctionBrace; - SkString functionName(fToken, fTokenLength); - - if (handleFunction(&script) == false) - return false; - lastPush = true; - continue; - } else if (ch == '[') { - if (handleProperty() == false) { - SkASSERT(0); - return false; - } - if (handleArrayIndexer(&script) == false) - return false; - lastPush = true; - continue; - } else if (ch != '.') { - if (handleProperty() == false) { - SkASSERT(0); - return false; - } - lastPush = true; - continue; - } - } - if (ch == '0' && (script[1] & ~0x20) == 'X') { - SkASSERT(lastPush == false); - script += 2; - script = SkParse::FindHex(script, (uint32_t*) &operand.fOperand.fS32); - SkASSERT(script); - goto intCommon; - } - if (lastPush == false && ch == '.') - goto scalarCommon; - if (ch >= '0' && ch <= '9') { - SkASSERT(lastPush == false); - dotCheck = SkParse::FindS32(script, &operand.fOperand.fS32); - if (dotCheck[0] != '.') { - script = dotCheck; -intCommon: - operand.fType = SkOperand2::kS32; - } else { -scalarCommon: - script = SkParse::FindScalar(script, &operand.fOperand.fScalar); - operand.fType = SkOperand2::kScalar; - } - operand.fIsConstant = SkScriptValue2::kConstant; - fValueStack.push(operand); - lastPush = true; - continue; - } - int length = token_length(script); - if (length > 0) { - SkASSERT(lastPush == false); - fToken = script; - fTokenLength = length; - script += length; - lastPush = true; - continue; - } - char startQuote = ch; - if (startQuote == '\'' || startQuote == '\"') { - SkASSERT(lastPush == false); - operand.fOperand.fString = new SkString(); - ++script; - const char* stringStart = script; - do { // measure string - if (script[0] == '\\') - ++script; - ++script; - SkASSERT(script[0]); // !!! throw an error - } while (script[0] != startQuote); - operand.fOperand.fString->set(stringStart, script - stringStart); - script = stringStart; - char* stringWrite = operand.fOperand.fString->writable_str(); - do { // copy string - if (script[0] == '\\') - ++script; - *stringWrite++ = script[0]; - ++script; - SkASSERT(script[0]); // !!! throw an error - } while (script[0] != startQuote); - ++script; - track(operand.fOperand.fString); - operand.fType = SkOperand2::kString; - operand.fIsConstant = SkScriptValue2::kConstant; - fValueStack.push(operand); - lastPush = true; - continue; - } - if (ch == '.') { - if (fTokenLength == 0) { - int tokenLength = token_length(++script); - const char* token = script; - script += tokenLength; - SkASSERT(fValueStack.count() > 0); // !!! add error handling - SkScriptValue2 top; - fValueStack.pop(&top); - - addTokenInt(top.fType); - addToken(kBoxToken); - top.fType = SkOperand2::kObject; - top.fIsConstant = SkScriptValue2::kVariable; - fConstExpression = false; - fValueStack.push(top); - success = evaluateDotParam(script, token, tokenLength); - SkASSERT(success); - lastPush = true; - continue; - } - // get next token, and evaluate immediately - success = evaluateDot(script); - if (success == false) { - // SkASSERT(0); - return false; - } - lastPush = true; - continue; - } - if (ch == '[') { - if (lastPush == false) { - script++; - *fBraceStack.push() = kArrayBrace; - operand.fOperand.fArray = value->fOperand.fArray = new SkOpArray(fReturnType); - track(value->fOperand.fArray); - - operand.fType = SkOperand2::kArray; - operand.fIsConstant = SkScriptValue2::kVariable; - fValueStack.push(operand); - continue; - } - if (handleArrayIndexer(&script) == false) - return false; - lastPush = true; - continue; - } -#if 0 // structs not supported for now - if (ch == '{') { - if (lastPush == false) { - script++; - *fBraceStack.push() = kStructBrace; - operand.fS32 = 0; - *fTypeStack.push() = (SkOpType) kStruct; - fOperandStack.push(operand); - continue; - } - SkASSERT(0); // braces in other contexts aren't supported yet - } -#endif - if (ch == ')' && fBraceStack.count() > 0) { - BraceStyle braceStyle = fBraceStack.top(); - if (braceStyle == kFunctionBrace) { - fBraceStack.pop(); - break; - } - } - if (ch == ',' || ch == ']') { - if (ch != ',') { - BraceStyle match; - fBraceStack.pop(&match); - SkASSERT(match == kArrayBrace); - } - script++; - // !!! see if brace or bracket is correct closer - break; - } - char nextChar = script[1]; - int advance = logicalOp(ch, nextChar); - if (advance == 0) - advance = arithmeticOp(ch, nextChar, lastPush); - if (advance == 0) // unknown token - return false; - if (advance > 0) - script += advance; - lastPush = ch == ']' || ch == ')'; - } - if (fTokenLength > 0) { - success = handleProperty(); - SkASSERT(success); - } - int branchIndex = 0; - branchBalance = fBranchStack.count() - branchBalance; - fBranchPopAllowed = false; - while (branchIndex < branchBalance) { - Branch& branch = fBranchStack.index(branchIndex++); - if (branch.fPrimed == Branch::kIsPrimed) - break; - Op branchOp = branch.fOperator; - SkOperand2::OpType lastType = fValueStack.top().fType; - addTokenValue(fValueStack.top(), kAccumulator); - fValueStack.pop(); - if (branchOp == kLogicalAnd || branchOp == kLogicalOr) { - if (branch.fOperator == kLogicalAnd) - branch.prime(); - addToken(kToBool); - } else { - resolveBranch(branch); - SkScriptValue2 operand; - operand.fType = lastType; - // !!! note that many branching expressions could be constant - // today, we always evaluate branches as returning variables - operand.fIsConstant = SkScriptValue2::kVariable; - fValueStack.push(operand); - } - if (branch.fDone == Branch::kIsNotDone) - branch.prime(); - } - fBranchPopAllowed = true; - while (fBranchStack.top().fDone == Branch::kIsDone) - fBranchStack.pop(); - while (fOpStack.count() > opBalance) { // leave open paren - if (processOp() == false) - return false; - } - SkOperand2::OpType topType = fValueStack.count() > 0 ? fValueStack.top().fType : SkOperand2::kNoType; - if (topType != fReturnType && - topType == SkOperand2::kString && fReturnType != SkOperand2::kNoType) { // if result is a string, give handle property a chance to convert it to the property value - SkString* string = fValueStack.top().fOperand.fString; - fToken = string->c_str(); - fTokenLength = string->size(); - fValueStack.pop(); - success = handleProperty(); - if (success == false) { // if it couldn't convert, return string (error?) - SkScriptValue2 operand; - operand.fType = SkOperand2::kString; - operand.fOperand.fString = string; - operand.fIsConstant = SkScriptValue2::kVariable; // !!! ? - fValueStack.push(operand); - } - } - if (fStream.getOffset() > 0) { - addToken(kEnd); - SkAutoDataUnref data(fStream.copyToData()); -#ifdef SK_DEBUG - decompile(data->bytes(), data->size()); -#endif - SkScriptRuntime runtime(fCallBackArray); - runtime.executeTokens((unsigned char*) data->bytes()); - SkScriptValue2 value1; - runtime.getResult(&value1.fOperand); - value1.fType = fReturnType; - fValueStack.push(value1); - } - if (value) { - if (fValueStack.count() == 0) - return false; - fValueStack.pop(value); - if (value->fType != fReturnType && value->fType == SkOperand2::kObject && - fReturnType != SkOperand2::kNoType) - convertTo(fReturnType, value); - } - // if (fBranchStack.top().fOpStackDepth > fOpStack.count()) - // resolveBranch(); - *scriptPtr = script; - return true; // no error -} - -bool SkScriptEngine2::handleArrayIndexer(const char** scriptPtr) { - SkScriptValue2 scriptValue; - (*scriptPtr)++; - *fOpStack.push() = (Op) kParen; - *fBraceStack.push() = kArrayBrace; - SkOperand2::OpType saveType = fReturnType; - fReturnType = SkOperand2::kS32; - bool success = innerScript(scriptPtr, &scriptValue); - fReturnType = saveType; - SkASSERT(success); - success = convertTo(SkOperand2::kS32, &scriptValue); - SkASSERT(success); - int index = scriptValue.fOperand.fS32; - fValueStack.pop(&scriptValue); - if (scriptValue.fType == SkOperand2::kObject) { - success = handleUnbox(&scriptValue); - SkASSERT(success); - SkASSERT(scriptValue.fType == SkOperand2::kArray); - } - scriptValue.fType = scriptValue.fOperand.fArray->getType(); - // SkASSERT(index >= 0); - if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) { - fError = kArrayIndexOutOfBounds; - return false; - } - scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index]; - scriptValue.fIsConstant = SkScriptValue2::kVariable; - fValueStack.push(scriptValue); - fOpStack.pop(); // pop paren - return success; -} - -bool SkScriptEngine2::handleFunction(const char** scriptPtr) { - const char* functionName = fToken; - size_t functionNameLen = fTokenLength; - fTokenLength = 0; - SkTDArray params; - bool success = functionParams(scriptPtr, ¶ms); - if (success == false) - goto done; - { - for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { - if ((*callBack)->getType() != SkScriptCallBack::kFunction) - continue; - SkScriptValue2 callbackResult; - success = (*callBack)->getReference(functionName, functionNameLen, &callbackResult); - if (success) { - callbackResult.fType = (*callBack)->getReturnType(callbackResult.fOperand.fReference, nullptr); - callbackResult.fIsConstant = SkScriptValue2::kVariable; - fValueStack.push(callbackResult); - goto done; - } - } - } - return false; -done: - fOpStack.pop(); - return success; -} - -bool SkScriptEngine2::handleMember(const char* field, size_t len, void* object) { - bool success = true; - for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { - if ((*callBack)->getType() != SkScriptCallBack::kMember) - continue; - SkScriptValue2 callbackResult; - success = (*callBack)->getReference(field, len, &callbackResult); - if (success) { - if (callbackResult.fType == SkOperand2::kString) - track(callbackResult.fOperand.fString); - callbackResult.fIsConstant = SkScriptValue2::kVariable; - fValueStack.push(callbackResult); - goto done; - } - } - return false; -done: - return success; -} - -bool SkScriptEngine2::handleMemberFunction(const char* field, size_t len, void* object, - SkTDArray* params) { - bool success = true; - for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { - if ((*callBack)->getType() != SkScriptCallBack::kMemberFunction) - continue; - SkScriptValue2 callbackResult; - success = (*callBack)->getReference(field, len, &callbackResult); - if (success) { - if (callbackResult.fType == SkOperand2::kString) - track(callbackResult.fOperand.fString); - callbackResult.fIsConstant = SkScriptValue2::kVariable; - fValueStack.push(callbackResult); - goto done; - } - } - return false; -done: - return success; -} - -bool SkScriptEngine2::handleProperty() { - bool success = true; - for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { - if ((*callBack)->getType() != SkScriptCallBack::kProperty) - continue; - SkScriptValue2 callbackResult; - success = (*callBack)->getReference(fToken, fTokenLength, &callbackResult); - if (success) { - if (callbackResult.fType == SkOperand2::kString && callbackResult.fOperand.fString == nullptr) { - callbackResult.fOperand.fString = new SkString(fToken, fTokenLength); - track(callbackResult.fOperand.fString); - } - callbackResult.fIsConstant = SkScriptValue2::kVariable; - fValueStack.push(callbackResult); - goto done; - } - } -done: - fTokenLength = 0; - return success; -} - -bool SkScriptEngine2::handleUnbox(SkScriptValue2* scriptValue) { - bool success = true; - for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { - if ((*callBack)->getType() != SkScriptCallBack::kUnbox) - continue; - SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *callBack; - success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOperand); - if (success) { - if (scriptValue->fType == SkOperand2::kString) - track(scriptValue->fOperand.fString); - goto done; - } - } - return false; -done: - return success; -} - -// note that entire expression is treated as if it were enclosed in parens -// an open paren is always the first thing in the op stack - -int SkScriptEngine2::logicalOp(char ch, char nextChar) { - int advance = 1; - Op op; - signed char precedence; - switch (ch) { - case ')': - op = (Op) kParen; - break; - case ']': - op = (Op) kArrayOp; - break; - case '?': - op = (Op) kIf; - break; - case ':': - op = (Op) kElse; - break; - case '&': - if (nextChar != '&') - goto noMatch; - op = kLogicalAnd; - advance = 2; - break; - case '|': - if (nextChar != '|') - goto noMatch; - op = kLogicalOr; - advance = 2; - break; - default: - noMatch: - return 0; - } - precedence = gPrecedence[op]; - int branchIndex = 0; - fBranchPopAllowed = false; - do { - while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence) - processOp(); - Branch& branch = fBranchStack.index(branchIndex++); - Op branchOp = branch.fOperator; - if (gPrecedence[branchOp] >= precedence) - break; - addTokenValue(fValueStack.top(), kAccumulator); - fValueStack.pop(); - if (branchOp == kLogicalAnd || branchOp == kLogicalOr) { - if (branch.fOperator == kLogicalAnd) - branch.prime(); - addToken(kToBool); - } else - resolveBranch(branch); - if (branch.fDone == Branch::kIsNotDone) - branch.prime(); - } while (true); - fBranchPopAllowed = true; - while (fBranchStack.top().fDone == Branch::kIsDone) - fBranchStack.pop(); - processLogicalOp(op); - return advance; -} - -void SkScriptEngine2::processLogicalOp(Op op) { - switch (op) { - case kParen: - case kArrayOp: - SkASSERT(fOpStack.count() > 1 && fOpStack.top() == op); // !!! add error handling - if (op == kParen) - fOpStack.pop(); - else { - SkScriptValue2 value; - fValueStack.pop(&value); - SkASSERT(value.fType == SkOperand2::kS32 || value.fType == SkOperand2::kScalar); // !!! add error handling (although, could permit strings eventually) - int index = value.fType == SkOperand2::kScalar ? SkScalarFloorToInt(value.fOperand.fScalar) : - value.fOperand.fS32; - SkScriptValue2 arrayValue; - fValueStack.pop(&arrayValue); - SkASSERT(arrayValue.fType == SkOperand2::kArray); // !!! add error handling - SkOpArray* array = arrayValue.fOperand.fArray; - SkOperand2 operand; - SkDEBUGCODE(bool success = ) array->getIndex(index, &operand); - SkASSERT(success); // !!! add error handling - SkScriptValue2 resultValue; - resultValue.fType = array->getType(); - resultValue.fOperand = operand; - resultValue.fIsConstant = SkScriptValue2::kVariable; - fValueStack.push(resultValue); - } - break; - case kIf: { - if (fAccumulatorType == SkOperand2::kNoType) { - addTokenValue(fValueStack.top(), kAccumulator); - fValueStack.pop(); - } - SkASSERT(fAccumulatorType != SkOperand2::kString); // !!! add error handling - addToken(kIfOp); - Branch branch(op, fOpStack.count(), getTokenOffset()); - *fBranchStack.push() = branch; - addTokenInt(0); // placeholder for future branch - fAccumulatorType = SkOperand2::kNoType; - } break; - case kElse: { - addTokenValue(fValueStack.top(), kAccumulator); - fValueStack.pop(); - addToken(kElseOp); - size_t newOffset = getTokenOffset(); - addTokenInt(0); // placeholder for future branch - Branch& branch = fBranchStack.top(); - resolveBranch(branch); - branch.fOperator = op; - branch.fDone = Branch::kIsNotDone; - SkASSERT(branch.fOpStackDepth == fOpStack.count()); - branch.fOffset = SkToU16(newOffset); - fAccumulatorType = SkOperand2::kNoType; - } break; - case kLogicalAnd: - case kLogicalOr: { - Branch& oldTop = fBranchStack.top(); - Branch::Primed wasPrime = oldTop.fPrimed; - Branch::Done wasDone = oldTop.fDone; - oldTop.fPrimed = Branch::kIsNotPrimed; - oldTop.fDone = Branch::kIsNotDone; - if (fAccumulatorType == SkOperand2::kNoType) { - SkASSERT(fValueStack.top().fType == SkOperand2::kS32); // !!! add error handling, and conversion to int? - addTokenValue(fValueStack.top(), kAccumulator); - fValueStack.pop(); - } else { - SkASSERT(fAccumulatorType == SkOperand2::kS32); - } - // if 'and', write beq goto opcode after end of predicate (after to bool) - // if 'or', write bne goto to bool - addToken(op == kLogicalAnd ? kLogicalAndInt : kLogicalOrInt); - Branch branch(op, fOpStack.count(), getTokenOffset()); - addTokenInt(0); // placeholder for future branch - oldTop.fPrimed = wasPrime; - oldTop.fDone = wasDone; - *fBranchStack.push() = branch; - fAccumulatorType = SkOperand2::kNoType; - } break; - default: - SkASSERT(0); - } -} - -bool SkScriptEngine2::processOp() { - Op op; - fOpStack.pop(&op); - op = (Op) (op & ~kArtificialOp); - const OperatorAttributes* attributes = &gOpAttributes[op]; - SkScriptValue2 value1; - memset(&value1, 0, sizeof(SkScriptValue2)); - SkScriptValue2 value2; - fValueStack.pop(&value2); - value2.fIsWritten = SkScriptValue2::kUnwritten; - // SkScriptEngine2::SkTypeOp convert1[3]; - // SkScriptEngine2::SkTypeOp convert2[3]; - // SkScriptEngine2::SkTypeOp* convert2Ptr = convert2; - bool constantOperands = value2.fIsConstant == SkScriptValue2::kConstant; - if (attributes->fLeftType != SkOperand2::kNoType) { - fValueStack.pop(&value1); - constantOperands &= value1.fIsConstant == SkScriptValue2::kConstant; - value1.fIsWritten = SkScriptValue2::kUnwritten; - if (op == kFlipOps) { - SkTSwap(value1, value2); - fOpStack.pop(&op); - op = (Op) (op & ~kArtificialOp); - attributes = &gOpAttributes[op]; - if (constantOperands == false) - addToken(kFlipOpsOp); - } - if (value1.fType == SkOperand2::kObject && (value1.fType & attributes->fLeftType) == 0) { - value1.fType = getUnboxType(value1.fOperand); - addToken(kUnboxToken); - } - } - if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeftType) == 0) { - value1.fType = getUnboxType(value2.fOperand); - addToken(kUnboxToken2); - } - if (attributes->fLeftType != SkOperand2::kNoType) { - if (value1.fType != value2.fType) { - if ((attributes->fLeftType & SkOperand2::kString) && attributes->fBias & kTowardsString && - ((value1.fType | value2.fType) & SkOperand2::kString)) { - if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperand2::kScalar) { - addTokenConst(&value1, kAccumulator, SkOperand2::kString, - value1.fType == SkOperand2::kS32 ? kIntToString : kScalarToString); - } - if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperand2::kScalar) { - addTokenConst(&value2, kOperand, SkOperand2::kString, - value2.fType == SkOperand2::kS32 ? kIntToString2 : kScalarToString2); - } - } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.fType | value2.fType) & - SkOperand2::kScalar)) { - if (value1.fType == SkOperand2::kS32) - addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kIntToScalar); - if (value2.fType == SkOperand2::kS32) - addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntToScalar2); - } - } - if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value2.fType) { - if (value1.fType == SkOperand2::kString) - addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStringToScalar); - if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType == SkOperand2::kS32 || - value2.fType == SkOperand2::kS32)) - addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarToInt); - } - } - AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ? - kOperand : kAccumulator; - if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.fType) { - if (value2.fType == SkOperand2::kString) - addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToScalar2); - if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == SkOperand2::kS32 || - value1.fType == SkOperand2::kS32)) - addTokenConst(&value2, rhRegister, SkOperand2::kS32, kScalarToInt2); - } - TypeOp typeOp = gTokens[op]; - if (value2.fType == SkOperand2::kScalar) - typeOp = (TypeOp) (typeOp + 1); - else if (value2.fType == SkOperand2::kString) - typeOp = (TypeOp) (typeOp + 2); - SkDynamicMemoryWStream stream; - SkOperand2::OpType saveType = SkOperand2::kNoType; - SkBool saveOperand = false; - if (constantOperands) { - fActiveStream = &stream; - saveType = fAccumulatorType; - saveOperand = fOperandInUse; - fAccumulatorType = SkOperand2::kNoType; - fOperandInUse = false; - } - if (attributes->fLeftType != SkOperand2::kNoType) { // two operands - if (value1.fIsWritten == SkScriptValue2::kUnwritten) - addTokenValue(value1, kAccumulator); - } - if (value2.fIsWritten == SkScriptValue2::kUnwritten) - addTokenValue(value2, rhRegister); - addToken(typeOp); - if (constantOperands) { - addToken(kEnd); - SkAutoDataUnref data(fStream.copyToData()); -#ifdef SK_DEBUG - decompile(data->bytes(), data->size()); -#endif - SkScriptRuntime runtime(fCallBackArray); - runtime.executeTokens((unsigned char*)data->bytes()); - runtime.getResult(&value1.fOperand); - if (attributes->fResultIsBoolean == kResultIsBoolean) - value1.fType = SkOperand2::kS32; - else if (attributes->fLeftType == SkOperand2::kNoType) // unary operand - value1.fType = value2.fType; - fValueStack.push(value1); - if (value1.fType == SkOperand2::kString) - runtime.untrack(value1.fOperand.fString); - else if (value1.fType == SkOperand2::kArray) - runtime.untrack(value1.fOperand.fArray); - fActiveStream = &fStream; - fAccumulatorType = saveType; - fOperandInUse = saveOperand; - return true; - } - value2.fIsConstant = SkScriptValue2::kVariable; - fValueStack.push(value2); - return true; -} - -void SkScriptEngine2::Branch::resolve(SkDynamicMemoryWStream* stream, size_t off) { - SkASSERT(fDone == kIsNotDone); - fPrimed = kIsNotPrimed; - fDone = kIsDone; - SkASSERT(off > fOffset + sizeof(size_t)); - size_t offset = off - fOffset - sizeof(offset); - stream->write(&offset, fOffset, sizeof(offset)); -} - -void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) { - branch.resolve(fActiveStream, getTokenOffset()); -} - -bool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toType, SkScriptValue2* value ) { - SkASSERT(value); - SkOperand2::OpType type = value->fType; - if (type == toType) - return true; - SkOperand2& operand = value->fOperand; - bool success = true; - switch (toType) { - case SkOperand2::kS32: - if (type == SkOperand2::kScalar) - operand.fS32 = SkScalarFloorToInt(operand.fScalar); - else { - SkASSERT(type == SkOperand2::kString); - success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != nullptr; - } - break; - case SkOperand2::kScalar: - if (type == SkOperand2::kS32) - operand.fScalar = IntToScalar(operand.fS32); - else { - SkASSERT(type == SkOperand2::kString); - success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != nullptr; - } - break; - case SkOperand2::kString: { - SkString* strPtr = new SkString(); - SkASSERT(engine); - engine->track(strPtr); - if (type == SkOperand2::kS32) - strPtr->appendS32(operand.fS32); - else { - SkASSERT(type == SkOperand2::kScalar); - strPtr->appendScalar(operand.fScalar); - } - operand.fString = strPtr; - } break; - case SkOperand2::kArray: { - SkOpArray* array = new SkOpArray(type); - *array->append() = operand; - engine->track(array); - operand.fArray = array; - } break; - default: - SkASSERT(0); - } - value->fType = toType; - return success; -} - -SkScalar SkScriptEngine2::IntToScalar(int32_t s32) { - SkScalar scalar; - if (s32 == (int32_t) SK_NaN32) - scalar = SK_ScalarNaN; - else if (SkAbs32(s32) == SK_MaxS32) - scalar = SkSign32(s32) * SK_ScalarMax; - else - scalar = SkIntToScalar(s32); - return scalar; -} - -bool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* string) { - switch (value.fType) { - case SkOperand2::kS32: - string->reset(); - string->appendS32(value.fOperand.fS32); - break; - case SkOperand2::kScalar: - string->reset(); - string->appendScalar(value.fOperand.fScalar); - break; - case SkOperand2::kString: - string->set(*value.fOperand.fString); - break; - default: - SkASSERT(0); - return false; - } - return true; // no error -} - -#ifdef SK_DEBUG -#if defined(SK_SUPPORT_UNITTEST) - -#define testInt(expression) { #expression, SkOperand2::kS32, expression, 0, nullptr } -#define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) (expression), nullptr } -#define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmodf((float) exp1, (float) exp2), nullptr } -#define testTrue(expression) { #expression, SkOperand2::kS32, 1, 0, nullptr } -#define testFalse(expression) { #expression, SkOperand2::kS32, 0, 0, nullptr } - -static const SkScriptNAnswer2 scriptTests[] = { - testInt(1||(0&&3)), - testScalar(- -5.5- -1.5), - testScalar(1.0+5), - testInt((6+7)*8), - testInt(3*(4+5)), - testScalar(1.0+2.0), - testScalar(3.0-1.0), - testScalar(6-1.0), - testScalar(2.5*6.), - testScalar(0.5*4), - testScalar(4.5/.5), - testScalar(9.5/19), - testRemainder(9.5, 0.5), - testRemainder(9.,2), - testRemainder(9,2.5), - testRemainder(-9,2.5), - testTrue(-9==-9.0), - testTrue(-9.==-4.0-5), - testTrue(-9.*1==-4-5), - testFalse(-9!=-9.0), - testFalse(-9.!=-4.0-5), - testFalse(-9.*1!=-4-5), - testInt(0x123), - testInt(0XABC), - testInt(0xdeadBEEF), - { "'123'+\"456\"", SkOperand2::kString, 0, 0, "123456" }, - { "123+\"456\"", SkOperand2::kString, 0, 0, "123456" }, - { "'123'+456", SkOperand2::kString, 0, 0, "123456" }, - { "'123'|\"456\"", SkOperand2::kS32, 123|456, 0, nullptr }, - { "123|\"456\"", SkOperand2::kS32, 123|456, 0, nullptr }, - { "'123'|456", SkOperand2::kS32, 123|456, 0, nullptr }, - { "'2'<11", SkOperand2::kS32, 1, 0, nullptr }, - { "2<'11'", SkOperand2::kS32, 1, 0, nullptr }, - { "'2'<'11'", SkOperand2::kS32, 0, 0, nullptr }, - testInt(123), - testInt(-345), - testInt(+678), - testInt(1+2+3), - testInt(3*4+5), - testInt(6+7*8), - testInt(-1-2-8/4), - testInt(-9%4), - testInt(9%-4), - testInt(-9%-4), - testInt(123|978), - testInt(123&978), - testInt(123^978), - testInt(2<<4), - testInt(99>>3), - testInt(~55), - testInt(~~55), - testInt(!55), - testInt(!!55), - // both int - testInt(2<2), - testInt(2<11), - testInt(20<11), - testInt(2<=2), - testInt(2<=11), - testInt(20<=11), - testInt(2>2), - testInt(2>11), - testInt(20>11), - testInt(2>=2), - testInt(2>=11), - testInt(20>=11), - testInt(2==2), - testInt(2==11), - testInt(20==11), - testInt(2!=2), - testInt(2!=11), - testInt(20!=11), - // left int, right scalar - testInt(2<2.), - testInt(2<11.), - testInt(20<11.), - testInt(2<=2.), - testInt(2<=11.), - testInt(20<=11.), - testInt(2>2.), - testInt(2>11.), - testInt(20>11.), - testInt(2>=2.), - testInt(2>=11.), - testInt(20>=11.), - testInt(2==2.), - testInt(2==11.), - testInt(20==11.), - testInt(2!=2.), - testInt(2!=11.), - testInt(20!=11.), - // left scalar, right int - testInt(2.<2), - testInt(2.<11), - testInt(20.<11), - testInt(2.<=2), - testInt(2.<=11), - testInt(20.<=11), - testInt(2.>2), - testInt(2.>11), - testInt(20.>11), - testInt(2.>=2), - testInt(2.>=11), - testInt(20.>=11), - testInt(2.==2), - testInt(2.==11), - testInt(20.==11), - testInt(2.!=2), - testInt(2.!=11), - testInt(20.!=11), - // both scalar - testInt(2.<11.), - testInt(20.<11.), - testInt(2.<=2.), - testInt(2.<=11.), - testInt(20.<=11.), - testInt(2.>2.), - testInt(2.>11.), - testInt(20.>11.), - testInt(2.>=2.), - testInt(2.>=11.), - testInt(20.>=11.), - testInt(2.==2.), - testInt(2.==11.), - testInt(20.==11.), - testInt(2.!=2.), - testInt(2.!=11.), - testInt(20.!=11.), - // int, string (string is int) - testFalse(2<'2'), - testTrue(2<'11'), - testFalse(20<'11'), - testTrue(2<='2'), - testTrue(2<='11'), - testFalse(20<='11'), - testFalse(2>'2'), - testFalse(2>'11'), - testTrue(20>'11'), - testTrue(2>='2'), - testFalse(2>='11'), - testTrue(20>='11'), - testTrue(2=='2'), - testFalse(2=='11'), - testFalse(2!='2'), - testTrue(2!='11'), - // int, string (string is scalar) - testFalse(2<'2.'), - testTrue(2<'11.'), - testFalse(20<'11.'), - testTrue(2=='2.'), - testFalse(2=='11.'), - // scalar, string - testFalse(2.<'2.'), - testTrue(2.<'11.'), - testFalse(20.<'11.'), - testTrue(2.=='2.'), - testFalse(2.=='11.'), - // string, int - testFalse('2'<2), - testTrue('2'<11), - testFalse('20'<11), - testTrue('2'==2), - testFalse('2'==11), - // string, scalar - testFalse('2'<2.), - testTrue('2'<11.), - testFalse('20'<11.), - testTrue('2'==2.), - testFalse('2'==11.), - // string, string - testFalse('2'<'2'), - testFalse('2'<'11'), - testFalse('20'<'11'), - testTrue('2'=='2'), - testFalse('2'=='11'), - // logic - testInt(1?2:3), - testInt(0?2:3), - testInt((1&&2)||3), - testInt((1&&0)||3), - testInt((1&&0)||0), - testInt(1||(0&&3)), - testInt(0||(0&&3)), - testInt(0||(1&&3)), - testInt(0&&1?2:3) - , { "123.5", SkOperand2::kScalar, 0, SkIntToScalar(123) + SK_Scalar1/2, nullptr } -}; - -#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) -#endif // SK_SUPPORT_UNITTEST - -void SkScriptEngine2::UnitTest() { -#if defined(SK_SUPPORT_UNITTEST) - ValidateDecompileTable(); - for (size_t index = 0; index < SkScriptNAnswer_testCount; index++) { - SkScriptEngine2 engine(scriptTests[index].fType); - SkScriptValue2 value; - const char* script = scriptTests[index].fScript; - const char* scriptPtr = script; - SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true); - SkASSERT(value.fType == scriptTests[index].fType); - SkScalar error; - switch (value.fType) { - case SkOperand2::kS32: - if (value.fOperand.fS32 != scriptTests[index].fIntAnswer) - SkDEBUGF(("script '%s' == value %d != expected answer %d\n", script, value.fOperand.fS32, scriptTests[index].fIntAnswer)); - SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); - break; - case SkOperand2::kScalar: - error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); - if (error >= SK_Scalar1 / 10000) - SkDEBUGF(("script '%s' == value %g != expected answer %g\n", script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScalarAnswer / (1.0f * SK_Scalar1))); - SkASSERT(error < SK_Scalar1 / 10000); - break; - case SkOperand2::kString: - SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer)); - break; - default: - SkASSERT(0); - } - } -#endif // SK_SUPPORT_UNITTEST -} -#endif // SK_DEBUG diff --git a/gfx/skia/skia/src/animator/SkSnapshot.cpp b/gfx/skia/skia/src/animator/SkSnapshot.cpp deleted file mode 100644 index 4d35432bd7e3..000000000000 --- a/gfx/skia/skia/src/animator/SkSnapshot.cpp +++ /dev/null @@ -1,67 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkTypes.h" - -#include "SkSnapshot.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkImageEncoder.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkSnapshot::fInfo[] = { - SK_MEMBER(filename, String), - SK_MEMBER(quality, Float), - SK_MEMBER(sequence, Boolean), - SK_MEMBER(type, BitmapEncoding) -}; - -#endif - -DEFINE_GET_MEMBER(SkSnapshot); - -SkSnapshot::SkSnapshot() -{ - quality = 100 * SK_Scalar1; - type = (SkImageEncoder::Type) -1; - sequence = false; - fSeqVal = 0; -} - -bool SkSnapshot::draw(SkAnimateMaker& maker) { - SkASSERT(type >= 0); - SkASSERT(filename.size() > 0); - SkImageEncoder* encoder = SkImageEncoder::Create((SkImageEncoder::Type) type); - if (!encoder) { - return false; - } - SkAutoTDelete ad(encoder); - - SkString name(filename); - if (sequence) { - char num[4] = "000"; - num[0] = (char) (num[0] + fSeqVal / 100); - num[1] = (char) (num[1] + fSeqVal / 10 % 10); - num[2] = (char) (num[2] + fSeqVal % 10); - name.append(num); - if (++fSeqVal > 999) - sequence = false; - } - if (type == SkImageEncoder::kJPEG_Type) - name.append(".jpg"); - else if (type == SkImageEncoder::kPNG_Type) - name.append(".png"); - - SkBitmap pixels; - pixels.allocPixels(maker.fCanvas->imageInfo()); - maker.fCanvas->readPixels(&pixels, 0, 0); - encoder->encodeFile(name.c_str(), pixels, SkScalarFloorToInt(quality)); - return false; -} diff --git a/gfx/skia/skia/src/animator/SkSnapshot.h b/gfx/skia/skia/src/animator/SkSnapshot.h deleted file mode 100644 index 003a9dc796e8..000000000000 --- a/gfx/skia/skia/src/animator/SkSnapshot.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkSnapShot_DEFINED -#define SkSnapShot_DEFINED - -#include "SkADrawable.h" -#include "SkMemberInfo.h" -#include "SkString.h" - -class SkSnapshot: public SkADrawable { - DECLARE_MEMBER_INFO(Snapshot); - SkSnapshot(); - bool draw(SkAnimateMaker& ) override; - private: - SkString filename; - SkScalar quality; - SkBool sequence; - int /*SkImageEncoder::Type*/ type; - int fSeqVal; -}; - -#endif // SkSnapShot_DEFINED diff --git a/gfx/skia/skia/src/animator/SkTDArray_Experimental.h b/gfx/skia/skia/src/animator/SkTDArray_Experimental.h deleted file mode 100644 index ff693ac39b5f..000000000000 --- a/gfx/skia/skia/src/animator/SkTDArray_Experimental.h +++ /dev/null @@ -1,142 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkTDArray_Experimental_DEFINED -#define SkTDArray_Experimental_DEFINED - -#include "SkTypes.h" - -#ifdef SK_BUILD_FOR_UNIX -#define SK_BUILD_FOR_ADS_12 -#endif - -#if !defined(SK_BUILD_FOR_ADS_12) && !defined(__x86_64__) -#define SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT 1 -#else -#define SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT 0 -#endif - -#if SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT == 0 -#include "SkTDArray.h" -#define SkIntArray(type) SkTDArray -#define SkLongArray(type) SkTDArray -#else - -class SkDS32Array { -protected: - SkDS32Array(); - SkDS32Array(const SkDS32Array& src); - SkDS32Array(const int32_t src[], U16CPU count); - SkDS32Array& operator=(const SkDS32Array& src); - friend int operator==(const SkDS32Array& a, const SkDS32Array& b); - int32_t* append() { return this->append(1, nullptr); } - int32_t* append(U16CPU count, const int32_t* src = nullptr); - - int32_t* appendClear() - { - int32_t* result = this->append(); - *result = 0; - return result; - } - - int find(const int32_t& elem) const; - int32_t* insert(U16CPU index, U16CPU count, const int32_t* src); - int rfind(const int32_t& elem) const; - void swap(SkDS32Array& other); -public: - bool isEmpty() const { return fCount == 0; } - int count() const { return fCount; } - - void remove(U16CPU index, U16CPU count = 1) - { - SkASSERT(index + count <= fCount); - fCount = SkToU16(fCount - count); - memmove(fArray + index, fArray + index + count, sizeof(int32_t) * (fCount - index)); - } - - void reset() - { - if (fArray) - { - sk_free(fArray); - fArray = nullptr; -#ifdef SK_DEBUG - fData = nullptr; -#endif - fReserve = fCount = 0; - } - else - { - SkASSERT(fReserve == 0 && fCount == 0); - } - } - - void setCount(U16CPU count) - { - if (count > fReserve) - this->growBy(count - fCount); - else - fCount = SkToU16(count); - } -protected: -#ifdef SK_DEBUG - enum { - kDebugArraySize = 24 - }; - int32_t(* fData)[kDebugArraySize]; -#endif - int32_t* fArray; - uint16_t fReserve, fCount; - void growBy(U16CPU extra); -}; - -#ifdef SK_DEBUG - #define SYNC() fTData = (T (*)[kDebugArraySize]) fArray -#else - #define SYNC() -#endif - -template class SkTDS32Array : public SkDS32Array { -public: - SkTDS32Array() { SkDEBUGCODE(fTData=nullptr); SkASSERT(sizeof(T) == sizeof(int32_t)); } - SkTDS32Array(const SkTDS32Array& src) : SkDS32Array(src) {} - ~SkTDS32Array() { sk_free(fArray); } - T& operator[](int index) const { SYNC(); SkASSERT((unsigned)index < fCount); return ((T*) fArray)[index]; } - SkTDS32Array& operator=(const SkTDS32Array& src) { - return (SkTDS32Array&) SkDS32Array::operator=(src); } - friend int operator==(const SkTDS32Array& a, const SkTDS32Array& b) { - return operator==((const SkDS32Array&) a, (const SkDS32Array&) b); } - T* append() { return (T*) SkDS32Array::append(); } - T* appendClear() { return (T*) SkDS32Array::appendClear(); } - T* append(U16CPU count, const T* src = nullptr) { return (T*) SkDS32Array::append(count, (const int32_t*) src); } - T* begin() const { SYNC(); return (T*) fArray; } - T* end() const { return (T*) (fArray ? fArray + fCount : nullptr); } - int find(const T& elem) const { return SkDS32Array::find((const int32_t&) elem); } - T* insert(U16CPU index) { return this->insert(index, 1, nullptr); } - T* insert(U16CPU index, U16CPU count, const T* src = nullptr) { - return (T*) SkDS32Array::insert(index, count, (const int32_t*) src); } - int rfind(const T& elem) const { return SkDS32Array::rfind((const int32_t&) elem); } - T* push() { return this->append(); } - void push(T& elem) { *this->append() = elem; } - const T& top() const { return (*this)[fCount - 1]; } - T& top() { return (*this)[fCount - 1]; } - void pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; } - void pop() { --fCount; } -private: -#ifdef SK_DEBUG - mutable T(* fTData)[kDebugArraySize]; -#endif -}; - -#define SkIntArray(type) SkTDS32Array // holds 32 bit data types -#define SkLongArray(type) SkTDS32Array - -#endif // SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT - -#endif // SkTDArray_Experimental_DEFINED diff --git a/gfx/skia/skia/src/animator/SkTDStack.h b/gfx/skia/skia/src/animator/SkTDStack.h deleted file mode 100644 index e286e4a03ac5..000000000000 --- a/gfx/skia/skia/src/animator/SkTDStack.h +++ /dev/null @@ -1,110 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkTDStack_DEFINED -#define SkTDStack_DEFINED - -#include "SkTypes.h" - -template class SkTDStack : SkNoncopyable { -public: - SkTDStack() : fCount(0), fTotalCount(0) { - fInitialRec.fNext = NULL; - fRec = &fInitialRec; - - // fCount = kSlotCount; - } - - ~SkTDStack() { - Rec* rec = fRec; - while (rec != &fInitialRec) { - Rec* next = rec->fNext; - sk_free(rec); - rec = next; - } - } - - int count() const { return fTotalCount; } - int depth() const { return fTotalCount; } - bool empty() const { return fTotalCount == 0; } - - T* push() { - SkASSERT(fCount <= kSlotCount); - if (fCount == kSlotCount) { - Rec* rec = (Rec*)sk_malloc_throw(sizeof(Rec)); - rec->fNext = fRec; - fRec = rec; - fCount = 0; - } - ++fTotalCount; - return &fRec->fSlots[fCount++]; - } - - void push(const T& elem) { *this->push() = elem; } - - const T& index(int idx) const { - SkASSERT(fRec && fCount > idx); - return fRec->fSlots[fCount - idx - 1]; - } - - T& index(int idx) { - SkASSERT(fRec && fCount > idx); - return fRec->fSlots[fCount - idx - 1]; - } - - const T& top() const { - SkASSERT(fRec && fCount > 0); - return fRec->fSlots[fCount - 1]; - } - - T& top() { - SkASSERT(fRec && fCount > 0); - return fRec->fSlots[fCount - 1]; - } - - void pop(T* elem) { - if (elem) { - *elem = fRec->fSlots[fCount - 1]; - } - this->pop(); - } - - void pop() { - SkASSERT(fCount > 0 && fRec); - --fTotalCount; - if (--fCount == 0) { - if (fRec != &fInitialRec) { - Rec* rec = fRec->fNext; - sk_free(fRec); - fCount = kSlotCount; - fRec = rec; - } else { - SkASSERT(fTotalCount == 0); - } - } - } - -private: - enum { - kSlotCount = 8 - }; - - struct Rec; - friend struct Rec; - - struct Rec { - Rec* fNext; - T fSlots[kSlotCount]; - }; - Rec fInitialRec; - Rec* fRec; - int fCount, fTotalCount; -}; - -#endif diff --git a/gfx/skia/skia/src/animator/SkTextOnPath.cpp b/gfx/skia/skia/src/animator/SkTextOnPath.cpp deleted file mode 100644 index 864741619bb5..000000000000 --- a/gfx/skia/skia/src/animator/SkTextOnPath.cpp +++ /dev/null @@ -1,39 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkTextOnPath.h" -#include "SkAnimateMaker.h" -#include "SkCanvas.h" -#include "SkDrawPath.h" -#include "SkDrawText.h" -#include "SkPaint.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkTextOnPath::fInfo[] = { - SK_MEMBER(offset, Float), - SK_MEMBER(path, Path), - SK_MEMBER(text, Text) -}; - -#endif - -DEFINE_GET_MEMBER(SkTextOnPath); - -SkTextOnPath::SkTextOnPath() : offset(0), path(nullptr), text(nullptr) { -} - -bool SkTextOnPath::draw(SkAnimateMaker& maker) { - SkASSERT(text); - SkASSERT(path); - SkBoundableAuto boundable(this, maker); - maker.fCanvas->drawTextOnPathHV(text->getText(), text->getSize(), - path->getPath(), offset, 0, *maker.fPaint); - return false; -} diff --git a/gfx/skia/skia/src/animator/SkTextOnPath.h b/gfx/skia/skia/src/animator/SkTextOnPath.h deleted file mode 100644 index 36adfd5221ac..000000000000 --- a/gfx/skia/skia/src/animator/SkTextOnPath.h +++ /dev/null @@ -1,30 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkTextOnPath_DEFINED -#define SkTextOnPath_DEFINED - -#include "SkBoundable.h" -#include "SkMemberInfo.h" - -class SkDrawPath; -class SkText; - -class SkTextOnPath : public SkBoundable { - DECLARE_MEMBER_INFO(TextOnPath); - SkTextOnPath(); - bool draw(SkAnimateMaker& ) override; -private: - SkScalar offset; - SkDrawPath* path; - SkText* text; - typedef SkBoundable INHERITED; -}; - -#endif // SkTextOnPath_DEFINED diff --git a/gfx/skia/skia/src/animator/SkTextToPath.cpp b/gfx/skia/skia/src/animator/SkTextToPath.cpp deleted file mode 100644 index d4b525b9afc8..000000000000 --- a/gfx/skia/skia/src/animator/SkTextToPath.cpp +++ /dev/null @@ -1,47 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkTextToPath.h" -#include "SkAnimateMaker.h" -#include "SkDrawPaint.h" -#include "SkDrawPath.h" -#include "SkDrawText.h" -#include "SkPaint.h" - -#if SK_USE_CONDENSED_INFO == 0 - -const SkMemberInfo SkTextToPath::fInfo[] = { - SK_MEMBER(paint, Paint), - SK_MEMBER(path, Path), - SK_MEMBER(text, Text) -}; - -#endif - -DEFINE_GET_MEMBER(SkTextToPath); - -SkTextToPath::SkTextToPath() : paint(nullptr), path(nullptr), text(nullptr) { -} - -bool SkTextToPath::draw(SkAnimateMaker& maker) { - path->draw(maker); - return false; -} - -void SkTextToPath::onEndElement(SkAnimateMaker& maker) { - if (paint == nullptr || path == nullptr || text == nullptr) { - // !!! add error message here - maker.setErrorCode(SkDisplayXMLParserError::kErrorInAttributeValue); - return; - } - SkPaint realPaint; - paint->setupPaint(&realPaint); - realPaint.getTextPath(text->getText(), text->getSize(), text->x, - text->y, &path->getPath()); -} diff --git a/gfx/skia/skia/src/animator/SkTextToPath.h b/gfx/skia/skia/src/animator/SkTextToPath.h deleted file mode 100644 index 23b6bfe8b403..000000000000 --- a/gfx/skia/skia/src/animator/SkTextToPath.h +++ /dev/null @@ -1,31 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkTextToPath_DEFINED -#define SkTextToPath_DEFINED - -#include "SkDrawPath.h" -#include "SkMemberInfo.h" - -class SkDrawPaint; -class SkDrawPath; -class SkText; - -class SkTextToPath : public SkADrawable { - DECLARE_MEMBER_INFO(TextToPath); - SkTextToPath(); - bool draw(SkAnimateMaker& ) override; - void onEndElement(SkAnimateMaker& ) override; -private: - SkDrawPaint* paint; - SkDrawPath* path; - SkText* text; -}; - -#endif // SkTextToPath_DEFINED diff --git a/gfx/skia/skia/src/animator/SkTypedArray.cpp b/gfx/skia/skia/src/animator/SkTypedArray.cpp deleted file mode 100644 index d9e2bc7f7300..000000000000 --- a/gfx/skia/skia/src/animator/SkTypedArray.cpp +++ /dev/null @@ -1,179 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkTypedArray.h" - -SkTypedArray::SkTypedArray() : fType(SkType_Unknown) { -} - -SkTypedArray::SkTypedArray(SkDisplayTypes type) : fType(type) { -} - -bool SkTypedArray::getIndex(int index, SkOperand* operand) { - if (index >= count()) { - SkASSERT(0); - return false; - } - *operand = begin()[index]; - return true; -} - - -#if SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT == 1 -SkDS32Array::SkDS32Array() -{ - fReserve = fCount = 0; - fArray = nullptr; -#ifdef SK_DEBUG - fData = nullptr; -#endif -} - -SkDS32Array::SkDS32Array(const SkDS32Array& src) -{ - fReserve = fCount = 0; - fArray = nullptr; -#ifdef SK_DEBUG - fData = nullptr; -#endif - SkDS32Array tmp(src.fArray, src.fCount); - this->swap(tmp); -} - -SkDS32Array::SkDS32Array(const int32_t src[], U16CPU count) -{ - SkASSERT(src || count == 0); - - fReserve = fCount = 0; - fArray = nullptr; -#ifdef SK_DEBUG - fData = nullptr; -#endif - if (count) - { - fArray = (int32_t*)sk_malloc_throw(count * sizeof(int32_t)); -#ifdef SK_DEBUG - fData = (int32_t (*)[kDebugArraySize]) fArray; -#endif - memcpy(fArray, src, sizeof(int32_t) * count); - fReserve = fCount = SkToU16(count); - } -} - -SkDS32Array& SkDS32Array::operator=(const SkDS32Array& src) -{ - if (this != &src) - { - if (src.fCount > fReserve) - { - SkDS32Array tmp(src.fArray, src.fCount); - this->swap(tmp); - } - else - { - memcpy(fArray, src.fArray, sizeof(int32_t) * src.fCount); - fCount = src.fCount; - } - } - return *this; -} - -int operator==(const SkDS32Array& a, const SkDS32Array& b) -{ - return a.fCount == b.fCount && - (a.fCount == 0 || !memcmp(a.fArray, b.fArray, a.fCount * sizeof(int32_t))); -} - -void SkDS32Array::swap(SkDS32Array& other) -{ - SkTSwap(fArray, other.fArray); -#ifdef SK_DEBUG - SkTSwap(fData, other.fData); -#endif - SkTSwap(fReserve, other.fReserve); - SkTSwap(fCount, other.fCount); -} - -int32_t* SkDS32Array::append(U16CPU count, const int32_t* src) -{ - unsigned oldCount = fCount; - if (count) - { - SkASSERT(src == nullptr || fArray == nullptr || - src + count <= fArray || fArray + count <= src); - - this->growBy(count); - if (src) - memcpy(fArray + oldCount, src, sizeof(int32_t) * count); - } - return fArray + oldCount; -} - -int SkDS32Array::find(const int32_t& elem) const -{ - const int32_t* iter = fArray; - const int32_t* stop = fArray + fCount; - - for (; iter < stop; iter++) - { - if (*iter == elem) - return (int) (iter - fArray); - } - return -1; -} - -void SkDS32Array::growBy(U16CPU extra) -{ - SkASSERT(extra); - SkASSERT(fCount + extra <= 0xFFFF); - - if (fCount + extra > fReserve) - { - size_t size = fCount + extra + 4; - size += size >> 2; - int32_t* array = (int32_t*)sk_malloc_throw(size * sizeof(int32_t)); - memcpy(array, fArray, fCount * sizeof(int32_t)); - - sk_free(fArray); - fArray = array; -#ifdef SK_DEBUG - fData = (int32_t (*)[kDebugArraySize]) fArray; -#endif - fReserve = SkToU16((U16CPU)size); - } - fCount = SkToU16(fCount + extra); -} - -int32_t* SkDS32Array::insert(U16CPU index, U16CPU count, const int32_t* src) -{ - SkASSERT(count); - int oldCount = fCount; - this->growBy(count); - int32_t* dst = fArray + index; - memmove(dst + count, dst, sizeof(int32_t) * (oldCount - index)); - if (src) - memcpy(dst, src, sizeof(int32_t) * count); - return dst; -} - - - int SkDS32Array::rfind(const int32_t& elem) const - { - const int32_t* iter = fArray + fCount; - const int32_t* stop = fArray; - - while (iter > stop) - { - if (*--iter == elem) - return (int) (iter - stop); - } - return -1; - } - -#endif diff --git a/gfx/skia/skia/src/animator/SkTypedArray.h b/gfx/skia/skia/src/animator/SkTypedArray.h deleted file mode 100644 index e93b106702c1..000000000000 --- a/gfx/skia/skia/src/animator/SkTypedArray.h +++ /dev/null @@ -1,31 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkTypedArray_DEFINED -#define SkTypedArray_DEFINED - -#include "SkScript.h" -#include "SkTDArray_Experimental.h" - -class SkTypedArray : public SkTDOperandArray { -public: - SkTypedArray(); - SkTypedArray(SkDisplayTypes type); - bool getIndex(int index, SkOperand* operand); - SkDisplayTypes getType() { return fType; } - SkScriptEngine::SkOpType getOpType() { return SkScriptEngine::ToOpType(fType); } - void setType(SkDisplayTypes type) { - // SkASSERT(count() == 0); - fType = type; - } -protected: - SkDisplayTypes fType; -}; - -#endif // SkTypedArray_DEFINED diff --git a/gfx/skia/skia/src/animator/SkXMLAnimatorWriter.cpp b/gfx/skia/skia/src/animator/SkXMLAnimatorWriter.cpp deleted file mode 100644 index 25b10a903d43..000000000000 --- a/gfx/skia/skia/src/animator/SkXMLAnimatorWriter.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkXMLAnimatorWriter.h" -#include "SkAnimator.h" -#include "SkAnimateMaker.h" -#include "SkDisplayXMLParser.h" - -SkXMLAnimatorWriter::SkXMLAnimatorWriter(SkAnimator* animator) : fAnimator(animator) -{ - fParser = new SkDisplayXMLParser(*fAnimator->fMaker); -} - -SkXMLAnimatorWriter::~SkXMLAnimatorWriter() { - delete fParser; -} - -void SkXMLAnimatorWriter::onAddAttributeLen(const char name[], const char value[], size_t length) -{ - fParser->onAddAttributeLen(name, value, length); -} - -void SkXMLAnimatorWriter::onAddText(const char text[], size_t length) { - SkDebugf("not implemented: SkXMLAnimatorWriter::onAddText()\n"); -} - -void SkXMLAnimatorWriter::onEndElement() -{ - Elem* elem = getEnd(); - fParser->onEndElement(elem->fName.c_str()); - doEnd(elem); -} - -void SkXMLAnimatorWriter::onStartElementLen(const char name[], size_t length) -{ - doStart(name, length); - fParser->onStartElementLen(name, length); -} - -void SkXMLAnimatorWriter::writeHeader() -{ -} - -#ifdef SK_DEBUG -#include "SkCanvas.h" -#include "SkPaint.h" - -void SkXMLAnimatorWriter::UnitTest(SkCanvas* canvas) -{ - SkAnimator s; - SkXMLAnimatorWriter w(&s); - w.startElement("screenplay"); - w.startElement("animateField"); - w.addAttribute("field", "x1"); - w.addAttribute("id", "to100"); - w.addAttribute("from", "0"); - w.addAttribute("to", "100"); - w.addAttribute("dur", "1"); - w.endElement(); - w.startElement("event"); - w.addAttribute("kind", "onLoad"); - w.startElement("line"); - w.addAttribute("id", "line"); - w.addAttribute("x1", "-1"); - w.addAttribute("y1", "20"); - w.addAttribute("x2", "150"); - w.addAttribute("y2", "40"); - w.endElement(); - w.startElement("apply"); - w.addAttribute("animator", "to100"); - w.addAttribute("scope", "line"); - w.endElement(); - w.endElement(); - w.endElement(); - SkPaint paint; - canvas->drawColor(SK_ColorWHITE); - s.draw(canvas, &paint, 0); -} - -#endif diff --git a/gfx/skia/skia/src/animator/SkXMLAnimatorWriter.h b/gfx/skia/skia/src/animator/SkXMLAnimatorWriter.h deleted file mode 100644 index 87cf21841f8b..000000000000 --- a/gfx/skia/skia/src/animator/SkXMLAnimatorWriter.h +++ /dev/null @@ -1,36 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkXMLAnimatorWriter_DEFINED -#define SkXMLAnimatorWriter_DEFINED - -#include "SkXMLWriter.h" - -class SkAnimator; -class SkDisplayXMLParser; - -class SkXMLAnimatorWriter : public SkXMLWriter { -public: - SkXMLAnimatorWriter(SkAnimator*); - virtual ~SkXMLAnimatorWriter(); - void writeHeader() override; - SkDEBUGCODE(static void UnitTest(class SkCanvas* canvas);) - -protected: - void onAddAttributeLen(const char name[], const char value[], size_t length) override; - void onEndElement() override; - void onStartElementLen(const char elem[], size_t length) override; - void onAddText(const char text[], size_t length) override; - -private: - SkAnimator* fAnimator; - SkDisplayXMLParser* fParser; -}; - -#endif // SkXMLAnimatorWriter_DEFINED diff --git a/gfx/skia/skia/src/animator/thingstodo.txt b/gfx/skia/skia/src/animator/thingstodo.txt deleted file mode 100644 index 8d0d47a02db5..000000000000 --- a/gfx/skia/skia/src/animator/thingstodo.txt +++ /dev/null @@ -1,21 +0,0 @@ -things to do: - figure out where endless or very deep recursion is possible - at these points, generate an error if actual physical stack gets too large - candidates are scripts - eval(eval(eval... user callouts - ((((( operator precedence or similar making stack deep - groups within groups - very large apply create or apply immediate steps - - write tests for math functions - looks like random takes a parameter when it should take zero parameters - - add Math, Number files to perforce for docs - alphabetize attributes in docs - - manually modified tools/screenplayDocs/xmlToJPEG.cpp - - fix docs where lines are stitched together (insert space) - - naked outside of asserts on name - handle errors for all element not contained by correct parents \ No newline at end of file diff --git a/gfx/skia/skia/src/c/sk_effects.cpp b/gfx/skia/skia/src/c/sk_effects.cpp new file mode 100644 index 000000000000..f3a31a54bb0e --- /dev/null +++ b/gfx/skia/skia/src/c/sk_effects.cpp @@ -0,0 +1,186 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "sk_types_priv.h" +#include "SkMatrix.h" + +static void from_c_matrix(const sk_matrix_t* cmatrix, SkMatrix* matrix) { + matrix->setAll(cmatrix->mat[0], cmatrix->mat[1], cmatrix->mat[2], + cmatrix->mat[3], cmatrix->mat[4], cmatrix->mat[5], + cmatrix->mat[6], cmatrix->mat[7], cmatrix->mat[8]); +} + +#include "../../include/effects/SkGradientShader.h" +#include "sk_shader.h" + +const struct { + sk_shader_tilemode_t fC; + SkShader::TileMode fSK; +} gTileModeMap[] = { + { CLAMP_SK_SHADER_TILEMODE, SkShader::kClamp_TileMode }, + { REPEAT_SK_SHADER_TILEMODE, SkShader::kRepeat_TileMode }, + { MIRROR_SK_SHADER_TILEMODE, SkShader::kMirror_TileMode }, +}; + +static bool from_c_tilemode(sk_shader_tilemode_t cMode, SkShader::TileMode* skMode) { + for (size_t i = 0; i < SK_ARRAY_COUNT(gTileModeMap); ++i) { + if (cMode == gTileModeMap[i].fC) { + if (skMode) { + *skMode = gTileModeMap[i].fSK; + } + return true; + } + } + return false; +} + +void sk_shader_ref(sk_shader_t* cshader) { + SkSafeRef(AsShader(cshader)); +} + +void sk_shader_unref(sk_shader_t* cshader) { + SkSafeUnref(AsShader(cshader)); +} + +sk_shader_t* sk_shader_new_linear_gradient(const sk_point_t pts[2], + const sk_color_t colors[], + const float colorPos[], + int colorCount, + sk_shader_tilemode_t cmode, + const sk_matrix_t* cmatrix) { + SkShader::TileMode mode; + if (!from_c_tilemode(cmode, &mode)) { + return NULL; + } + SkMatrix matrix; + if (cmatrix) { + from_c_matrix(cmatrix, &matrix); + } else { + matrix.setIdentity(); + } + return (sk_shader_t*)SkGradientShader::MakeLinear(reinterpret_cast(pts), + reinterpret_cast(colors), + colorPos, colorCount, + mode, 0, &matrix).release(); +} + +static const SkPoint& to_skpoint(const sk_point_t& p) { + return reinterpret_cast(p); +} + +sk_shader_t* sk_shader_new_radial_gradient(const sk_point_t* ccenter, + float radius, + const sk_color_t colors[], + const float colorPos[], + int colorCount, + sk_shader_tilemode_t cmode, + const sk_matrix_t* cmatrix) { + SkShader::TileMode mode; + if (!from_c_tilemode(cmode, &mode)) { + return NULL; + } + SkMatrix matrix; + if (cmatrix) { + from_c_matrix(cmatrix, &matrix); + } else { + matrix.setIdentity(); + } + SkPoint center = to_skpoint(*ccenter); + return (sk_shader_t*)SkGradientShader::MakeRadial(center, (SkScalar)radius, + reinterpret_cast(colors), + reinterpret_cast(colorPos), + colorCount, mode, 0, &matrix).release(); +} + +sk_shader_t* sk_shader_new_sweep_gradient(const sk_point_t* ccenter, + const sk_color_t colors[], + const float colorPos[], + int colorCount, + const sk_matrix_t* cmatrix) { + SkMatrix matrix; + if (cmatrix) { + from_c_matrix(cmatrix, &matrix); + } else { + matrix.setIdentity(); + } + return (sk_shader_t*)SkGradientShader::MakeSweep((SkScalar)(ccenter->x), + (SkScalar)(ccenter->y), + reinterpret_cast(colors), + reinterpret_cast(colorPos), + colorCount, 0, &matrix).release(); +} + +sk_shader_t* sk_shader_new_two_point_conical_gradient(const sk_point_t* start, + float startRadius, + const sk_point_t* end, + float endRadius, + const sk_color_t colors[], + const float colorPos[], + int colorCount, + sk_shader_tilemode_t cmode, + const sk_matrix_t* cmatrix) { + SkShader::TileMode mode; + if (!from_c_tilemode(cmode, &mode)) { + return NULL; + } + SkMatrix matrix; + if (cmatrix) { + from_c_matrix(cmatrix, &matrix); + } else { + matrix.setIdentity(); + } + SkPoint skstart = to_skpoint(*start); + SkPoint skend = to_skpoint(*end); + return (sk_shader_t*)SkGradientShader::MakeTwoPointConical(skstart, (SkScalar)startRadius, + skend, (SkScalar)endRadius, + reinterpret_cast(colors), + reinterpret_cast(colorPos), + colorCount, mode, 0, &matrix).release(); +} + +/////////////////////////////////////////////////////////////////////////////////////////// + +#include "../../include/effects/SkBlurMaskFilter.h" +#include "sk_maskfilter.h" + +const struct { + sk_blurstyle_t fC; + SkBlurStyle fSk; +} gBlurStylePairs[] = { + { NORMAL_SK_BLUR_STYLE, kNormal_SkBlurStyle }, + { SOLID_SK_BLUR_STYLE, kSolid_SkBlurStyle }, + { OUTER_SK_BLUR_STYLE, kOuter_SkBlurStyle }, + { INNER_SK_BLUR_STYLE, kInner_SkBlurStyle }, +}; + +static bool find_blurstyle(sk_blurstyle_t csrc, SkBlurStyle* dst) { + for (size_t i = 0; i < SK_ARRAY_COUNT(gBlurStylePairs); ++i) { + if (gBlurStylePairs[i].fC == csrc) { + if (dst) { + *dst = gBlurStylePairs[i].fSk; + } + return true; + } + } + return false; +} + +void sk_maskfilter_ref(sk_maskfilter_t* cfilter) { + SkSafeRef(AsMaskFilter(cfilter)); +} + +void sk_maskfilter_unref(sk_maskfilter_t* cfilter) { + SkSafeUnref(AsMaskFilter(cfilter)); +} + +sk_maskfilter_t* sk_maskfilter_new_blur(sk_blurstyle_t cstyle, float sigma) { + SkBlurStyle style; + if (!find_blurstyle(cstyle, &style)) { + return NULL; + } + return ToMaskFilter(SkBlurMaskFilter::Make(style, sigma).release()); +} diff --git a/gfx/skia/skia/src/c/sk_surface.cpp b/gfx/skia/skia/src/c/sk_surface.cpp index c9b25675a0a4..7e1fb3d3eaa5 100644 --- a/gfx/skia/skia/src/c/sk_surface.cpp +++ b/gfx/skia/skia/src/c/sk_surface.cpp @@ -503,179 +503,6 @@ sk_rect_t sk_picture_get_bounds(sk_picture_t* cpic) { /////////////////////////////////////////////////////////////////////////////////////////// -#include "../../include/effects/SkGradientShader.h" -#include "sk_shader.h" - -const struct { - sk_shader_tilemode_t fC; - SkShader::TileMode fSK; -} gTileModeMap[] = { - { CLAMP_SK_SHADER_TILEMODE, SkShader::kClamp_TileMode }, - { REPEAT_SK_SHADER_TILEMODE, SkShader::kRepeat_TileMode }, - { MIRROR_SK_SHADER_TILEMODE, SkShader::kMirror_TileMode }, -}; - -static bool from_c_tilemode(sk_shader_tilemode_t cMode, SkShader::TileMode* skMode) { - for (size_t i = 0; i < SK_ARRAY_COUNT(gTileModeMap); ++i) { - if (cMode == gTileModeMap[i].fC) { - if (skMode) { - *skMode = gTileModeMap[i].fSK; - } - return true; - } - } - return false; -} - -void sk_shader_ref(sk_shader_t* cshader) { - SkSafeRef(AsShader(cshader)); -} - -void sk_shader_unref(sk_shader_t* cshader) { - SkSafeUnref(AsShader(cshader)); -} - -sk_shader_t* sk_shader_new_linear_gradient(const sk_point_t pts[2], - const sk_color_t colors[], - const float colorPos[], - int colorCount, - sk_shader_tilemode_t cmode, - const sk_matrix_t* cmatrix) { - SkShader::TileMode mode; - if (!from_c_tilemode(cmode, &mode)) { - return NULL; - } - SkMatrix matrix; - if (cmatrix) { - from_c_matrix(cmatrix, &matrix); - } else { - matrix.setIdentity(); - } - return (sk_shader_t*)SkGradientShader::MakeLinear(reinterpret_cast(pts), - reinterpret_cast(colors), - colorPos, colorCount, - mode, 0, &matrix).release(); -} - -static const SkPoint& to_skpoint(const sk_point_t& p) { - return reinterpret_cast(p); -} - -sk_shader_t* sk_shader_new_radial_gradient(const sk_point_t* ccenter, - float radius, - const sk_color_t colors[], - const float colorPos[], - int colorCount, - sk_shader_tilemode_t cmode, - const sk_matrix_t* cmatrix) { - SkShader::TileMode mode; - if (!from_c_tilemode(cmode, &mode)) { - return NULL; - } - SkMatrix matrix; - if (cmatrix) { - from_c_matrix(cmatrix, &matrix); - } else { - matrix.setIdentity(); - } - SkPoint center = to_skpoint(*ccenter); - return (sk_shader_t*)SkGradientShader::MakeRadial(center, (SkScalar)radius, - reinterpret_cast(colors), - reinterpret_cast(colorPos), - colorCount, mode, 0, &matrix).release(); -} - -sk_shader_t* sk_shader_new_sweep_gradient(const sk_point_t* ccenter, - const sk_color_t colors[], - const float colorPos[], - int colorCount, - const sk_matrix_t* cmatrix) { - SkMatrix matrix; - if (cmatrix) { - from_c_matrix(cmatrix, &matrix); - } else { - matrix.setIdentity(); - } - return (sk_shader_t*)SkGradientShader::MakeSweep((SkScalar)(ccenter->x), - (SkScalar)(ccenter->y), - reinterpret_cast(colors), - reinterpret_cast(colorPos), - colorCount, 0, &matrix).release(); -} - -sk_shader_t* sk_shader_new_two_point_conical_gradient(const sk_point_t* start, - float startRadius, - const sk_point_t* end, - float endRadius, - const sk_color_t colors[], - const float colorPos[], - int colorCount, - sk_shader_tilemode_t cmode, - const sk_matrix_t* cmatrix) { - SkShader::TileMode mode; - if (!from_c_tilemode(cmode, &mode)) { - return NULL; - } - SkMatrix matrix; - if (cmatrix) { - from_c_matrix(cmatrix, &matrix); - } else { - matrix.setIdentity(); - } - SkPoint skstart = to_skpoint(*start); - SkPoint skend = to_skpoint(*end); - return (sk_shader_t*)SkGradientShader::MakeTwoPointConical(skstart, (SkScalar)startRadius, - skend, (SkScalar)endRadius, - reinterpret_cast(colors), - reinterpret_cast(colorPos), - colorCount, mode, 0, &matrix).release(); -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -#include "../../include/effects/SkBlurMaskFilter.h" -#include "sk_maskfilter.h" - -const struct { - sk_blurstyle_t fC; - SkBlurStyle fSk; -} gBlurStylePairs[] = { - { NORMAL_SK_BLUR_STYLE, kNormal_SkBlurStyle }, - { SOLID_SK_BLUR_STYLE, kSolid_SkBlurStyle }, - { OUTER_SK_BLUR_STYLE, kOuter_SkBlurStyle }, - { INNER_SK_BLUR_STYLE, kInner_SkBlurStyle }, -}; - -static bool find_blurstyle(sk_blurstyle_t csrc, SkBlurStyle* dst) { - for (size_t i = 0; i < SK_ARRAY_COUNT(gBlurStylePairs); ++i) { - if (gBlurStylePairs[i].fC == csrc) { - if (dst) { - *dst = gBlurStylePairs[i].fSk; - } - return true; - } - } - return false; -} - -void sk_maskfilter_ref(sk_maskfilter_t* cfilter) { - SkSafeRef(AsMaskFilter(cfilter)); -} - -void sk_maskfilter_unref(sk_maskfilter_t* cfilter) { - SkSafeUnref(AsMaskFilter(cfilter)); -} - -sk_maskfilter_t* sk_maskfilter_new_blur(sk_blurstyle_t cstyle, float sigma) { - SkBlurStyle style; - if (!find_blurstyle(cstyle, &style)) { - return NULL; - } - return ToMaskFilter(SkBlurMaskFilter::Make(style, sigma).release()); -} - -/////////////////////////////////////////////////////////////////////////////////////////// - sk_data_t* sk_data_new_with_copy(const void* src, size_t length) { return ToData(SkData::MakeWithCopy(src, length).release()); } diff --git a/gfx/skia/skia/src/codec/SkAndroidCodec.cpp b/gfx/skia/skia/src/codec/SkAndroidCodec.cpp index 23242433bfcc..b30dd52e4c67 100644 --- a/gfx/skia/skia/src/codec/SkAndroidCodec.cpp +++ b/gfx/skia/skia/src/codec/SkAndroidCodec.cpp @@ -17,37 +17,78 @@ static bool is_valid_sample_size(int sampleSize) { return sampleSize > 0; } +/** + * Loads the gamut as a set of three points (triangle). + */ +static void load_gamut(SkPoint rgb[], const SkMatrix44& xyz) { + // rx = rX / (rX + rY + rZ) + // ry = rY / (rX + rY + rZ) + // gx, gy, bx, and gy are calulcated similarly. + float rSum = xyz.get(0, 0) + xyz.get(1, 0) + xyz.get(2, 0); + float gSum = xyz.get(0, 1) + xyz.get(1, 1) + xyz.get(2, 1); + float bSum = xyz.get(0, 2) + xyz.get(1, 2) + xyz.get(2, 2); + rgb[0].fX = xyz.get(0, 0) / rSum; + rgb[0].fY = xyz.get(1, 0) / rSum; + rgb[1].fX = xyz.get(0, 1) / gSum; + rgb[1].fY = xyz.get(1, 1) / gSum; + rgb[2].fX = xyz.get(0, 2) / bSum; + rgb[2].fY = xyz.get(1, 2) / bSum; +} + +/** + * Calculates the area of the triangular gamut. + */ +static float calculate_area(SkPoint abc[]) { + SkPoint a = abc[0]; + SkPoint b = abc[1]; + SkPoint c = abc[2]; + return 0.5f * SkTAbs(a.fX*b.fY + b.fX*c.fY - a.fX*c.fY - c.fX*b.fY - b.fX*a.fY); +} + +static const float kSRGB_D50_GamutArea = 0.084f; + +static bool is_wide_gamut(const SkColorSpace* colorSpace) { + // Determine if the source image has a gamut that is wider than sRGB. If so, we + // will use P3 as the output color space to avoid clipping the gamut. + const SkMatrix44* toXYZD50 = as_CSB(colorSpace)->toXYZD50(); + if (toXYZD50) { + SkPoint rgb[3]; + load_gamut(rgb, *toXYZD50); + return calculate_area(rgb) > kSRGB_D50_GamutArea; + } + + return false; +} + SkAndroidCodec::SkAndroidCodec(SkCodec* codec) : fInfo(codec->getInfo()) , fCodec(codec) {} SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) { - SkAutoTDelete codec(SkCodec::NewFromStream(stream, chunkReader)); + std::unique_ptr codec(SkCodec::NewFromStream(stream, chunkReader)); if (nullptr == codec) { return nullptr; } - switch (codec->getEncodedFormat()) { + switch ((SkEncodedImageFormat)codec->getEncodedFormat()) { #ifdef SK_HAS_PNG_LIBRARY - case kPNG_SkEncodedFormat: - case kICO_SkEncodedFormat: + case SkEncodedImageFormat::kPNG: + case SkEncodedImageFormat::kICO: #endif #ifdef SK_HAS_JPEG_LIBRARY - case kJPEG_SkEncodedFormat: + case SkEncodedImageFormat::kJPEG: #endif -#ifdef SK_HAS_GIF_LIBRARY - case kGIF_SkEncodedFormat: -#endif - case kBMP_SkEncodedFormat: - case kWBMP_SkEncodedFormat: + case SkEncodedImageFormat::kGIF: + case SkEncodedImageFormat::kBMP: + case SkEncodedImageFormat::kWBMP: return new SkSampledCodec(codec.release()); #ifdef SK_HAS_WEBP_LIBRARY - case kWEBP_SkEncodedFormat: + case SkEncodedImageFormat::kWEBP: return new SkWebpAdapterCodec((SkWebpCodec*) codec.release()); #endif #ifdef SK_CODEC_DECODES_RAW - case kDNG_SkEncodedFormat: + case SkEncodedImageFormat::kDNG: return new SkRawAdapterCodec((SkRawCodec*)codec.release()); #endif default: @@ -65,17 +106,27 @@ SkAndroidCodec* SkAndroidCodec::NewFromData(sk_sp data, SkPngChunkReader SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorType) { // The legacy GIF and WBMP decoders always decode to kIndex_8_SkColorType. - // We will maintain this behavior. - SkEncodedFormat format = this->getEncodedFormat(); - if (kGIF_SkEncodedFormat == format || kWBMP_SkEncodedFormat == format) { - return kIndex_8_SkColorType; + // We will maintain this behavior when we can. + const SkColorType suggestedColorType = this->getInfo().colorType(); + switch ((SkEncodedImageFormat) this->getEncodedFormat()) { + case SkEncodedImageFormat::kGIF: + if (suggestedColorType == kIndex_8_SkColorType) { + return kIndex_8_SkColorType; + } + break; + case SkEncodedImageFormat::kWBMP: + return kIndex_8_SkColorType; + default: + break; } - SkColorType suggestedColorType = this->getInfo().colorType(); + bool highPrecision = fCodec->getEncodedInfo().bitsPerComponent() > 8; switch (requestedColorType) { case kARGB_4444_SkColorType: - case kN32_SkColorType: return kN32_SkColorType; + case kN32_SkColorType: + // F16 is the Android default for high precision images. + return highPrecision ? kRGBA_F16_SkColorType : kN32_SkColorType; case kIndex_8_SkColorType: if (kIndex_8_SkColorType == suggestedColorType) { return kIndex_8_SkColorType; @@ -95,6 +146,8 @@ SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorTyp return kRGB_565_SkColorType; } break; + case kRGBA_F16_SkColorType: + return kRGBA_F16_SkColorType; default: break; } @@ -105,8 +158,8 @@ SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorTyp return kN32_SkColorType; } - // This may be kN32_SkColorType or kIndex_8_SkColorType. - return suggestedColorType; + // |suggestedColorType| may be kN32_SkColorType or kIndex_8_SkColorType. + return highPrecision ? kRGBA_F16_SkColorType : suggestedColorType; } SkAlphaType SkAndroidCodec::computeOutputAlphaType(bool requestedUnpremul) { @@ -116,9 +169,47 @@ SkAlphaType SkAndroidCodec::computeOutputAlphaType(bool requestedUnpremul) { return requestedUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType; } +sk_sp SkAndroidCodec::computeOutputColorSpace(SkColorType outputColorType, + sk_sp prefColorSpace) { + switch (outputColorType) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + case kIndex_8_SkColorType: { + // If |prefColorSpace| is supported, choose it. + SkColorSpaceTransferFn fn; + if (prefColorSpace && prefColorSpace->isNumericalTransferFn(&fn)) { + return prefColorSpace; + } + + SkColorSpace* encodedSpace = fCodec->getInfo().colorSpace(); + if (encodedSpace->isNumericalTransferFn(&fn)) { + // Leave the pixels in the encoded color space. Color space conversion + // will be handled after decode time. + return sk_ref_sp(encodedSpace); + } + + if (is_wide_gamut(encodedSpace)) { + return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, + SkColorSpace::kDCIP3_D65_Gamut); + } + + return SkColorSpace::MakeSRGB(); + } + case kRGBA_F16_SkColorType: + // Note that |prefColorSpace| is ignored, F16 is always linear sRGB. + return SkColorSpace::MakeSRGBLinear(); + case kRGB_565_SkColorType: + // Note that |prefColorSpace| is ignored, 565 is always sRGB. + return SkColorSpace::MakeSRGB(); + default: + // Color correction not supported for kGray. + return nullptr; + } +} + SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const { if (!is_valid_sample_size(sampleSize)) { - return SkISize::Make(0, 0); + return {0, 0}; } // Fast path for when we are not scaling. @@ -139,7 +230,7 @@ bool SkAndroidCodec::getSupportedSubset(SkIRect* desiredSubset) const { SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const { if (!is_valid_sample_size(sampleSize)) { - return SkISize::Make(0, 0); + return {0, 0}; } // We require that the input subset is a subset that is supported by SkAndroidCodec. @@ -147,7 +238,7 @@ SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect // are made to the subset. SkIRect copySubset = subset; if (!this->getSupportedSubset(©Subset) || copySubset != subset) { - return SkISize::Make(0, 0); + return {0, 0}; } // If the subset is the entire image, for consistency, use getSampledDimensions(). @@ -157,8 +248,8 @@ SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect // This should perhaps call a virtual function, but currently both of our subclasses // want the same implementation. - return SkISize::Make(get_scaled_dimension(subset.width(), sampleSize), - get_scaled_dimension(subset.height(), sampleSize)); + return {get_scaled_dimension(subset.width(), sampleSize), + get_scaled_dimension(subset.height(), sampleSize)}; } SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels, diff --git a/gfx/skia/skia/src/codec/SkBmpCodec.cpp b/gfx/skia/skia/src/codec/SkBmpCodec.cpp index 2f796ad667fa..3d3782b4f55e 100644 --- a/gfx/skia/skia/src/codec/SkBmpCodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpCodec.cpp @@ -79,6 +79,59 @@ SkCodec* SkBmpCodec::NewFromIco(SkStream* stream) { return SkBmpCodec::NewFromStream(stream, true); } +// Header size constants +static const uint32_t kBmpHeaderBytes = 14; +static const uint32_t kBmpHeaderBytesPlusFour = kBmpHeaderBytes + 4; +static const uint32_t kBmpOS2V1Bytes = 12; +static const uint32_t kBmpOS2V2Bytes = 64; +static const uint32_t kBmpInfoBaseBytes = 16; +static const uint32_t kBmpInfoV1Bytes = 40; +static const uint32_t kBmpInfoV2Bytes = 52; +static const uint32_t kBmpInfoV3Bytes = 56; +static const uint32_t kBmpInfoV4Bytes = 108; +static const uint32_t kBmpInfoV5Bytes = 124; +static const uint32_t kBmpMaskBytes = 12; + +static BmpHeaderType get_header_type(size_t infoBytes) { + if (infoBytes >= kBmpInfoBaseBytes) { + // Check the version of the header + switch (infoBytes) { + case kBmpInfoV1Bytes: + return kInfoV1_BmpHeaderType; + case kBmpInfoV2Bytes: + return kInfoV2_BmpHeaderType; + case kBmpInfoV3Bytes: + return kInfoV3_BmpHeaderType; + case kBmpInfoV4Bytes: + return kInfoV4_BmpHeaderType; + case kBmpInfoV5Bytes: + return kInfoV5_BmpHeaderType; + case 16: + case 20: + case 24: + case 28: + case 32: + case 36: + case 42: + case 46: + case 48: + case 60: + case kBmpOS2V2Bytes: + return kOS2VX_BmpHeaderType; + default: + SkCodecPrintf("Error: unknown bmp header format.\n"); + return kUnknown_BmpHeaderType; + } + } if (infoBytes >= kBmpOS2V1Bytes) { + // The OS2V1 is treated separately because it has a unique format + return kOS2V1_BmpHeaderType; + } else { + // There are no valid bmp headers + SkCodecPrintf("Error: second bitmap header size is invalid.\n"); + return kUnknown_BmpHeaderType; + } +} + /* * Read enough of the stream to initialize the SkBmpCodec. Returns a bool * representing success or failure. If it returned true, and codecOut was @@ -86,19 +139,6 @@ SkCodec* SkBmpCodec::NewFromIco(SkStream* stream) { * Does *not* take ownership of the passed in SkStream. */ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { - // Header size constants - static const uint32_t kBmpHeaderBytes = 14; - static const uint32_t kBmpHeaderBytesPlusFour = kBmpHeaderBytes + 4; - static const uint32_t kBmpOS2V1Bytes = 12; - static const uint32_t kBmpOS2V2Bytes = 64; - static const uint32_t kBmpInfoBaseBytes = 16; - static const uint32_t kBmpInfoV1Bytes = 40; - static const uint32_t kBmpInfoV2Bytes = 52; - static const uint32_t kBmpInfoV3Bytes = 56; - static const uint32_t kBmpInfoV4Bytes = 108; - static const uint32_t kBmpInfoV5Bytes = 124; - static const uint32_t kBmpMaskBytes = 12; - // The total bytes in the bmp file // We only need to use this value for RLE decoding, so we will only // check that it is valid in the RLE case. @@ -111,7 +151,7 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { // Bmps embedded in Icos skip the first Bmp header if (!inIco) { // Read the first header and the size of the second header - SkAutoTDeleteArray hBuffer(new uint8_t[kBmpHeaderBytesPlusFour]); + std::unique_ptr hBuffer(new uint8_t[kBmpHeaderBytesPlusFour]); if (stream->read(hBuffer.get(), kBmpHeaderBytesPlusFour) != kBmpHeaderBytesPlusFour) { SkCodecPrintf("Error: unable to read first bitmap header.\n"); @@ -145,7 +185,7 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { offset = 0; // Read the size of the second header - SkAutoTDeleteArray hBuffer(new uint8_t[4]); + std::unique_ptr hBuffer(new uint8_t[4]); if (stream->read(hBuffer.get(), 4) != 4) { SkCodecPrintf("Error: unable to read size of second bitmap header.\n"); return false; @@ -157,11 +197,17 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { } } + // Determine image information depending on second header format + const BmpHeaderType headerType = get_header_type(infoBytes); + if (kUnknown_BmpHeaderType == headerType) { + return false; + } + // We already read the first four bytes of the info header to get the size const uint32_t infoBytesRemaining = infoBytes - 4; // Read the second header - SkAutoTDeleteArray iBuffer(new uint8_t[infoBytesRemaining]); + std::unique_ptr iBuffer(new uint8_t[infoBytesRemaining]); if (stream->read(iBuffer.get(), infoBytesRemaining) != infoBytesRemaining) { SkCodecPrintf("Error: unable to read second bitmap header.\n"); return false; @@ -182,80 +228,45 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { // The image width and height int width, height; - // Determine image information depending on second header format - BmpHeaderType headerType; - if (infoBytes >= kBmpInfoBaseBytes) { - // Check the version of the header - switch (infoBytes) { - case kBmpInfoV1Bytes: - headerType = kInfoV1_BmpHeaderType; - break; - case kBmpInfoV2Bytes: - headerType = kInfoV2_BmpHeaderType; - break; - case kBmpInfoV3Bytes: - headerType = kInfoV3_BmpHeaderType; - break; - case kBmpInfoV4Bytes: - headerType = kInfoV4_BmpHeaderType; - break; - case kBmpInfoV5Bytes: - headerType = kInfoV5_BmpHeaderType; - break; - case 16: - case 20: - case 24: - case 28: - case 32: - case 36: - case 42: - case 46: - case 48: - case 60: - case kBmpOS2V2Bytes: - headerType = kOS2VX_BmpHeaderType; - break; - default: - // We do not signal an error here because there is the - // possibility of new or undocumented bmp header types. Most - // of the newer versions of bmp headers are similar to and - // build off of the older versions, so we may still be able to - // decode the bmp. - SkCodecPrintf("Warning: unknown bmp header format.\n"); - headerType = kUnknown_BmpHeaderType; - break; - } - // We check the size of the header before entering the if statement. - // We should not reach this point unless the size is large enough for - // these required fields. - SkASSERT(infoBytesRemaining >= 12); - width = get_int(iBuffer.get(), 0); - height = get_int(iBuffer.get(), 4); - bitsPerPixel = get_short(iBuffer.get(), 10); + switch (headerType) { + case kInfoV1_BmpHeaderType: + case kInfoV2_BmpHeaderType: + case kInfoV3_BmpHeaderType: + case kInfoV4_BmpHeaderType: + case kInfoV5_BmpHeaderType: + case kOS2VX_BmpHeaderType: + // We check the size of the header before entering the if statement. + // We should not reach this point unless the size is large enough for + // these required fields. + SkASSERT(infoBytesRemaining >= 12); + width = get_int(iBuffer.get(), 0); + height = get_int(iBuffer.get(), 4); + bitsPerPixel = get_short(iBuffer.get(), 10); - // Some versions do not have these fields, so we check before - // overwriting the default value. - if (infoBytesRemaining >= 16) { - compression = get_int(iBuffer.get(), 12); - if (infoBytesRemaining >= 32) { - numColors = get_int(iBuffer.get(), 28); + // Some versions do not have these fields, so we check before + // overwriting the default value. + if (infoBytesRemaining >= 16) { + compression = get_int(iBuffer.get(), 12); + if (infoBytesRemaining >= 32) { + numColors = get_int(iBuffer.get(), 28); + } } - } - // All of the headers that reach this point, store color table entries - // using 4 bytes per pixel. - bytesPerColor = 4; - } else if (infoBytes >= kBmpOS2V1Bytes) { - // The OS2V1 is treated separately because it has a unique format - headerType = kOS2V1_BmpHeaderType; - width = (int) get_short(iBuffer.get(), 0); - height = (int) get_short(iBuffer.get(), 2); - bitsPerPixel = get_short(iBuffer.get(), 6); - bytesPerColor = 3; - } else { - // There are no valid bmp headers - SkCodecPrintf("Error: second bitmap header size is invalid.\n"); - return false; + // All of the headers that reach this point, store color table entries + // using 4 bytes per pixel. + bytesPerColor = 4; + break; + case kOS2V1_BmpHeaderType: + // The OS2V1 is treated separately because it has a unique format + width = (int) get_short(iBuffer.get(), 0); + height = (int) get_short(iBuffer.get(), 2); + bitsPerPixel = get_short(iBuffer.get(), 6); + bytesPerColor = 3; + break; + case kUnknown_BmpHeaderType: + // We'll exit above in this case. + SkASSERT(false); + return false; } // Check for valid dimensions from header @@ -269,9 +280,10 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { if (inIco) { height /= 2; } - if (width <= 0 || height <= 0) { - // TODO: Decide if we want to disable really large bmps as well. - // https://code.google.com/p/skia/issues/detail?id=3617 + + // Arbitrary maximum. Matches Chromium. + constexpr int kMaxDim = 1 << 16; + if (width <= 0 || height <= 0 || width >= kMaxDim || height >= kMaxDim) { SkCodecPrintf("Error: invalid bitmap dimensions.\n"); return false; } @@ -320,7 +332,7 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { switch (headerType) { case kInfoV1_BmpHeaderType: { // The V1 header stores the bit masks after the header - SkAutoTDeleteArray mBuffer(new uint8_t[kBmpMaskBytes]); + std::unique_ptr mBuffer(new uint8_t[kBmpMaskBytes]); if (stream->read(mBuffer.get(), kBmpMaskBytes) != kBmpMaskBytes) { SkCodecPrintf("Error: unable to read bit inputMasks.\n"); @@ -503,7 +515,7 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { if (codecOut) { // Check that input bit masks are valid and create the masks object - SkAutoTDelete masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel)); + std::unique_ptr masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel)); if (nullptr == masks) { SkCodecPrintf("Error: invalid input masks.\n"); return false; @@ -538,7 +550,6 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { SkCodecPrintf("Error: RLE requires valid input size.\n"); return false; } - const size_t RLEBytes = totalBytes - offset; // Bmp-in-Ico must be standard mode // When inIco is true, this line cannot be reached, since we @@ -554,7 +565,7 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { const SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kBGRA_Color, SkEncodedInfo::kBinary_Alpha, 8); *codecOut = new SkBmpRLECodec(width, height, info, stream, bitsPerPixel, numColors, - bytesPerColor, offset - bytesRead, rowOrder, RLEBytes); + bytesPerColor, offset - bytesRead, rowOrder); } return true; } @@ -569,7 +580,7 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { * Reads enough of the stream to determine the image format */ SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) { - SkAutoTDelete streamDeleter(stream); + std::unique_ptr streamDeleter(stream); SkCodec* codec = nullptr; if (ReadHeader(stream, inIco, &codec)) { // codec has taken ownership of stream, so we do not need to @@ -583,10 +594,11 @@ SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) { SkBmpCodec::SkBmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder) - : INHERITED(width, height, info, stream) + : INHERITED(width, height, info, stream, SkColorSpace::MakeSRGB()) , fBitsPerPixel(bitsPerPixel) , fRowOrder(rowOrder) , fSrcRowBytes(SkAlign4(compute_row_bytes(width, fBitsPerPixel))) + , fXformBuffer(nullptr) {} bool SkBmpCodec::onRewind() { @@ -601,13 +613,19 @@ int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const { return height - y - 1; } -SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, +SkCodec::Result SkBmpCodec::prepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { - if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { - SkCodecPrintf("Error: cannot convert input type to output type.\n"); + if (!conversion_possible(dstInfo, this->getInfo()) || + !this->initializeColorXform(dstInfo, options.fPremulBehavior)) + { return kInvalidConversion; } + return this->onPrepareToDecode(dstInfo, options, inputColorPtr, inputColorCount); +} + +SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, + const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { return prepareToDecode(dstInfo, options, inputColorPtr, inputColorCount); } @@ -627,3 +645,15 @@ bool SkBmpCodec::skipRows(int count) { bool SkBmpCodec::onSkipScanlines(int count) { return this->skipRows(count); } + +void SkBmpCodec::applyColorXform(const SkImageInfo& dstInfo, void* dst, void* src) const { + SkColorSpaceXform* xform = this->colorXform(); + if (xform) { + const SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType()); + const SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(kXformSrcColorType); + const SkAlphaType alphaType = select_xform_alpha(dstInfo.alphaType(), + this->getInfo().alphaType()); + SkAssertResult(xform->apply(dstFormat, dst, srcFormat, src, dstInfo.width(), + alphaType)); + } +} diff --git a/gfx/skia/skia/src/codec/SkBmpCodec.h b/gfx/skia/skia/src/codec/SkBmpCodec.h index 0ece7ad6ce2f..75740f76ffb2 100644 --- a/gfx/skia/skia/src/codec/SkBmpCodec.h +++ b/gfx/skia/skia/src/codec/SkBmpCodec.h @@ -41,7 +41,7 @@ protected: SkBmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder); - SkEncodedFormat onGetEncodedFormat() const override { return kBMP_SkEncodedFormat; } + SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kBMP; } /* * Read enough of the stream to initialize the SkBmpCodec. Returns a bool @@ -99,9 +99,22 @@ protected: * will be set to the number of colors in the * color table. */ - virtual SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, + virtual SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) = 0; + SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, + const SkCodec::Options& options, SkPMColor inputColorPtr[], + int* inputColorCount); + + void applyColorXform(const SkImageInfo& dstInfo, void* dst, void* src) const; + uint32_t* xformBuffer() const { return fXformBuffer.get(); } + void resetXformBuffer(int count) { fXformBuffer.reset(new uint32_t[count]); } + + /* + * BMPs are typically encoded as BGRA/BGR so this is a more efficient choice + * than RGBA. + */ + static const SkColorType kXformSrcColorType = kBGRA_8888_SkColorType; private: @@ -138,9 +151,10 @@ private: bool onSkipScanlines(int count) override; - const uint16_t fBitsPerPixel; - const SkScanlineOrder fRowOrder; - const size_t fSrcRowBytes; + const uint16_t fBitsPerPixel; + const SkScanlineOrder fRowOrder; + const size_t fSrcRowBytes; + std::unique_ptr fXformBuffer; typedef SkCodec INHERITED; }; diff --git a/gfx/skia/skia/src/codec/SkBmpMaskCodec.cpp b/gfx/skia/skia/src/codec/SkBmpMaskCodec.cpp index 5b28252f7c1d..9612a23b538f 100644 --- a/gfx/skia/skia/src/codec/SkBmpMaskCodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpMaskCodec.cpp @@ -39,11 +39,6 @@ SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo, return kInvalidScale; } - if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { - SkCodecPrintf("Error: cannot convert input type to output type.\n"); - return kInvalidConversion; - } - Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { return result; @@ -57,11 +52,23 @@ SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo, return kSuccess; } -SkCodec::Result SkBmpMaskCodec::prepareToDecode(const SkImageInfo& dstInfo, +SkCodec::Result SkBmpMaskCodec::onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { + if (this->colorXform()) { + this->resetXformBuffer(dstInfo.width()); + } + + SkImageInfo swizzlerInfo = dstInfo; + if (this->colorXform()) { + swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType); + if (kPremul_SkAlphaType == dstInfo.alphaType()) { + swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); + } + } + // Initialize the mask swizzler - fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(dstInfo, this->getInfo(), fMasks, - this->bitsPerPixel(), options)); + fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(swizzlerInfo, this->getInfo(), + fMasks.get(), this->bitsPerPixel(), options)); SkASSERT(fMaskSwizzler); return SkCodec::kSuccess; @@ -86,7 +93,14 @@ int SkBmpMaskCodec::decodeRows(const SkImageInfo& dstInfo, // Decode the row in destination format uint32_t row = this->getDstRow(y, height); void* dstRow = SkTAddOffset(dst, row * dstRowBytes); - fMaskSwizzler->swizzle(dstRow, srcRow); + + if (this->colorXform()) { + SkImageInfo xformInfo = dstInfo.makeWH(fMaskSwizzler->swizzleWidth(), dstInfo.height()); + fMaskSwizzler->swizzle(this->xformBuffer(), srcRow); + this->applyColorXform(xformInfo, dstRow, this->xformBuffer()); + } else { + fMaskSwizzler->swizzle(dstRow, srcRow); + } } // Finished decoding the entire image diff --git a/gfx/skia/skia/src/codec/SkBmpMaskCodec.h b/gfx/skia/skia/src/codec/SkBmpMaskCodec.h index cc8af856e8fd..50e285dff393 100644 --- a/gfx/skia/skia/src/codec/SkBmpMaskCodec.h +++ b/gfx/skia/skia/src/codec/SkBmpMaskCodec.h @@ -5,6 +5,9 @@ * found in the LICENSE file. */ +#ifndef SkBmpMaskCodec_DEFINED +#define SkBmpMaskCodec_DEFINED + #include "SkBmpCodec.h" #include "SkImageInfo.h" #include "SkMaskSwizzler.h" @@ -38,7 +41,7 @@ protected: size_t dstRowBytes, const Options&, SkPMColor*, int*, int*) override; - SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, + SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) override; @@ -46,15 +49,16 @@ private: SkSampler* getSampler(bool createIfNecessary) override { SkASSERT(fMaskSwizzler); - return fMaskSwizzler; + return fMaskSwizzler.get(); } int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts) override; - SkAutoTDelete fMasks; // owned - SkAutoTDelete fMaskSwizzler; - SkAutoTDeleteArray fSrcBuffer; + std::unique_ptr fMasks; + std::unique_ptr fMaskSwizzler; + std::unique_ptr fSrcBuffer; typedef SkBmpCodec INHERITED; }; +#endif // SkBmpMaskCodec_DEFINED diff --git a/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp b/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp index dc5d689235c9..1968616fa686 100644 --- a/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp @@ -17,16 +17,13 @@ SkBmpRLECodec::SkBmpRLECodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, uint32_t offset, - SkCodec::SkScanlineOrder rowOrder, - size_t RLEBytes) + SkCodec::SkScanlineOrder rowOrder) : INHERITED(width, height, info, stream, bitsPerPixel, rowOrder) , fColorTable(nullptr) , fNumColors(numColors) , fBytesPerColor(bytesPerColor) , fOffset(offset) - , fStreamBuffer(new uint8_t[RLEBytes]) - , fRLEBytes(RLEBytes) - , fOrigRLEBytes(RLEBytes) + , fBytesBuffered(0) , fCurrRLEByte(0) , fSampleX(1) {} @@ -44,10 +41,6 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, // Subsets are not supported. return kUnimplemented; } - if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { - SkCodecPrintf("Error: cannot convert input type to output type.\n"); - return kInvalidConversion; - } Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { @@ -89,7 +82,7 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, // Read the color table from the stream colorBytes = numColorsToRead * fBytesPerColor; - SkAutoTDeleteArray cBuffer(new uint8_t[colorBytes]); + std::unique_ptr cBuffer(new uint8_t[colorBytes]); if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) { SkCodecPrintf("Error: unable to read color table.\n"); return false; @@ -138,22 +131,8 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, } bool SkBmpRLECodec::initializeStreamBuffer() { - // Setup a buffer to contain the full input stream - // TODO (msarett): I'm not sure it is smart or optimal to trust fRLEBytes (read from header) - // as the size of our buffer. First of all, the decode fails if fRLEBytes is - // corrupt (negative, zero, or small) when we might be able to decode - // successfully with a fixed size buffer. Additionally, we would save memory - // using a fixed size buffer if the RLE encoding is large. On the other hand, - // we may also waste memory with a fixed size buffer. And determining a - // minimum size for our buffer would depend on the image width (so it's not - // really "fixed" size), and we may end up allocating a buffer that is - // generally larger than the average encoded size anyway. - size_t totalBytes = this->stream()->read(fStreamBuffer.get(), fRLEBytes); - if (totalBytes < fRLEBytes) { - fRLEBytes = totalBytes; - SkCodecPrintf("Warning: incomplete RLE file.\n"); - } - if (fRLEBytes == 0) { + fBytesBuffered = this->stream()->read(fStreamBuffer, kBufferSize); + if (fBytesBuffered == 0) { SkCodecPrintf("Error: could not read RLE image data.\n"); return false; } @@ -162,15 +141,12 @@ bool SkBmpRLECodec::initializeStreamBuffer() { } /* - * Before signalling kIncompleteInput, we should attempt to load the - * stream buffer with additional data. - * * @return the number of bytes remaining in the stream buffer after * attempting to read more bytes from the stream */ size_t SkBmpRLECodec::checkForMoreData() { - const size_t remainingBytes = fRLEBytes - fCurrRLEByte; - uint8_t* buffer = fStreamBuffer.get(); + const size_t remainingBytes = fBytesBuffered - fCurrRLEByte; + uint8_t* buffer = fStreamBuffer; // We will be reusing the same buffer, starting over from the beginning. // Move any remaining bytes to the start of the buffer. @@ -189,11 +165,8 @@ size_t SkBmpRLECodec::checkForMoreData() { // Update counters and return the number of bytes we currently have // available. We are at the start of the buffer again. fCurrRLEByte = 0; - // If we were unable to fill the buffer, fRLEBytes is no longer equal to - // the size of the buffer. There will be unused space at the end. This - // should be fine, given that there are no more bytes in the stream. - fRLEBytes = remainingBytes + additionalBytes; - return fRLEBytes; + fBytesBuffered = remainingBytes + additionalBytes; + return fBytesBuffered; } /* @@ -267,7 +240,7 @@ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, } } -SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo, +SkCodec::Result SkBmpRLECodec::onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { // FIXME: Support subsets for scanline decodes. if (options.fSubset) { @@ -280,18 +253,24 @@ SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo, fSampleX = 1; fLinesToSkip = 0; + SkColorType colorTableColorType = dstInfo.colorType(); + if (this->colorXform()) { + // Just set a known colorType for the colorTable. No need to actually transform + // the colors in the colorTable since we do not allow decoding RLE to kIndex8. + colorTableColorType = kBGRA_8888_SkColorType; + } + // Create the color table if necessary and prepare the stream for decode // Note that if it is non-NULL, inputColorCount will be modified - if (!this->createColorTable(dstInfo.colorType(), inputColorCount)) { + if (!this->createColorTable(colorTableColorType, inputColorCount)) { SkCodecPrintf("Error: could not create color table.\n"); return SkCodec::kInvalidInput; } // Copy the color table to the client if necessary - copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount); + copy_color_table(dstInfo, fColorTable.get(), inputColorPtr, inputColorCount); // Initialize a buffer for encoded RLE data - fRLEBytes = fOrigRLEBytes; if (!this->initializeStreamBuffer()) { SkCodecPrintf("Error: cannot initialize stream buffer.\n"); return SkCodec::kInvalidInput; @@ -306,12 +285,6 @@ SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo, */ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowBytes, const Options& opts) { - // Set RLE flags - static const uint8_t RLE_ESCAPE = 0; - static const uint8_t RLE_EOL = 0; - static const uint8_t RLE_EOF = 1; - static const uint8_t RLE_DELTA = 2; - const int width = this->getInfo().width(); int height = info.height(); @@ -320,10 +293,6 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB // Set the background as transparent. Then, if the RLE code skips pixels, // the skipped pixels will be transparent. - // Because of the need for transparent pixels, kN32 is the only color - // type that makes sense for the destination format. - SkASSERT(kRGBA_8888_SkColorType == dstInfo.colorType() || - kBGRA_8888_SkColorType == dstInfo.colorType()); if (dst) { SkSampler::Fill(dstInfo, dst, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroInitialized); } @@ -332,13 +301,58 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB // with lines that need to be skipped. if (height > fLinesToSkip) { height -= fLinesToSkip; - dst = SkTAddOffset(dst, fLinesToSkip * dstRowBytes); + if (dst) { + dst = SkTAddOffset(dst, fLinesToSkip * dstRowBytes); + } fLinesToSkip = 0; + + dstInfo = dstInfo.makeWH(dstInfo.width(), height); } else { fLinesToSkip -= height; return height; } + void* decodeDst = dst; + size_t decodeRowBytes = dstRowBytes; + SkImageInfo decodeInfo = dstInfo; + if (decodeDst) { + if (this->colorXform()) { + decodeInfo = decodeInfo.makeColorType(kXformSrcColorType); + if (kRGBA_F16_SkColorType == dstInfo.colorType()) { + int count = height * dstInfo.width(); + this->resetXformBuffer(count); + sk_bzero(this->xformBuffer(), count * sizeof(uint32_t)); + decodeDst = this->xformBuffer(); + decodeRowBytes = dstInfo.width() * sizeof(uint32_t); + } + } + } + + int decodedHeight = this->decodeRLE(decodeInfo, decodeDst, decodeRowBytes); + if (this->colorXform() && decodeDst) { + for (int y = 0; y < decodedHeight; y++) { + this->applyColorXform(dstInfo, dst, decodeDst); + decodeDst = SkTAddOffset(decodeDst, decodeRowBytes); + dst = SkTAddOffset(dst, dstRowBytes); + } + } + + return decodedHeight; +} + +int SkBmpRLECodec::decodeRLE(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes) { + // Use the original width to count the number of pixels in each row. + const int width = this->getInfo().width(); + + // This tells us the number of rows that we are meant to decode. + const int height = dstInfo.height(); + + // Set RLE flags + static const uint8_t RLE_ESCAPE = 0; + static const uint8_t RLE_EOL = 0; + static const uint8_t RLE_EOF = 1; + static const uint8_t RLE_DELTA = 2; + // Destination parameters int x = 0; int y = 0; @@ -354,8 +368,7 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB } // Every entry takes at least two bytes - if ((int) fRLEBytes - fCurrRLEByte < 2) { - SkCodecPrintf("Warning: might be incomplete RLE input.\n"); + if ((int) fBytesBuffered - fCurrRLEByte < 2) { if (this->checkForMoreData() < 2) { return y; } @@ -365,8 +378,8 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB // depending on their values. In the first interpretation, the first // byte is an escape flag and the second byte indicates what special // task to perform. - const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++]; - const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++]; + const uint8_t flag = fStreamBuffer[fCurrRLEByte++]; + const uint8_t task = fStreamBuffer[fCurrRLEByte++]; // Perform decoding if (RLE_ESCAPE == flag) { @@ -379,15 +392,14 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB return height; case RLE_DELTA: { // Two bytes are needed to specify delta - if ((int) fRLEBytes - fCurrRLEByte < 2) { - SkCodecPrintf("Warning: might be incomplete RLE input.\n"); + if ((int) fBytesBuffered - fCurrRLEByte < 2) { if (this->checkForMoreData() < 2) { return y; } } // Modify x and y - const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; - const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; + const uint8_t dx = fStreamBuffer[fCurrRLEByte++]; + const uint8_t dy = fStreamBuffer[fCurrRLEByte++]; x += dx; y += dy; if (x > width) { @@ -413,11 +425,20 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB SkCodecPrintf("Warning: invalid RLE input.\n"); return y; } + // Also abort if there are not enough bytes // remaining in the stream to set numPixels. - if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) { - SkCodecPrintf("Warning: might be incomplete RLE input.\n"); - if (this->checkForMoreData() < SkAlign2(rowBytes)) { + + // At most, alignedRowBytes can be 255 (max uint8_t) * + // 3 (max bytes per pixel) + 1 (aligned) = 766. If + // fStreamBuffer was smaller than this, + // checkForMoreData would never succeed for some bmps. + static_assert(255 * 3 + 1 < kBufferSize, + "kBufferSize needs to be larger!"); + const size_t alignedRowBytes = SkAlign2(rowBytes); + if ((int) fBytesBuffered - fCurrRLEByte < alignedRowBytes) { + SkASSERT(alignedRowBytes < kBufferSize); + if (this->checkForMoreData() < alignedRowBytes) { return y; } } @@ -425,8 +446,8 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB while (numPixels > 0) { switch(this->bitsPerPixel()) { case 4: { - SkASSERT(fCurrRLEByte < fRLEBytes); - uint8_t val = fStreamBuffer.get()[fCurrRLEByte++]; + SkASSERT(fCurrRLEByte < fBytesBuffered); + uint8_t val = fStreamBuffer[fCurrRLEByte++]; setPixel(dst, dstRowBytes, dstInfo, x++, y, val >> 4); numPixels--; @@ -438,16 +459,16 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB break; } case 8: - SkASSERT(fCurrRLEByte < fRLEBytes); + SkASSERT(fCurrRLEByte < fBytesBuffered); setPixel(dst, dstRowBytes, dstInfo, x++, - y, fStreamBuffer.get()[fCurrRLEByte++]); + y, fStreamBuffer[fCurrRLEByte++]); numPixels--; break; case 24: { - SkASSERT(fCurrRLEByte + 2 < fRLEBytes); - uint8_t blue = fStreamBuffer.get()[fCurrRLEByte++]; - uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; - uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; + SkASSERT(fCurrRLEByte + 2 < fBytesBuffered); + uint8_t blue = fStreamBuffer[fCurrRLEByte++]; + uint8_t green = fStreamBuffer[fCurrRLEByte++]; + uint8_t red = fStreamBuffer[fCurrRLEByte++]; setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, blue); numPixels--; @@ -475,8 +496,7 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB // In RLE24, the second byte read is part of the pixel color. // There are two more required bytes to finish encoding the // color. - if ((int) fRLEBytes - fCurrRLEByte < 2) { - SkCodecPrintf("Warning: might be incomplete RLE input.\n"); + if ((int) fBytesBuffered - fCurrRLEByte < 2) { if (this->checkForMoreData() < 2) { return y; } @@ -484,8 +504,8 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB // Fill the pixels up to endX with the specified color uint8_t blue = task; - uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; - uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; + uint8_t green = fStreamBuffer[fCurrRLEByte++]; + uint8_t red = fStreamBuffer[fCurrRLEByte++]; while (x < endX) { setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, blue); } @@ -548,7 +568,7 @@ SkSampler* SkBmpRLECodec::getSampler(bool /*createIfNecessary*/) { fSampler.reset(new SkBmpRLESampler(this)); } - return fSampler; + return fSampler.get(); } int SkBmpRLECodec::setSampleX(int sampleX){ diff --git a/gfx/skia/skia/src/codec/SkBmpRLECodec.h b/gfx/skia/skia/src/codec/SkBmpRLECodec.h index c5236a810073..030e82731fcb 100644 --- a/gfx/skia/skia/src/codec/SkBmpRLECodec.h +++ b/gfx/skia/skia/src/codec/SkBmpRLECodec.h @@ -4,6 +4,8 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#ifndef SkBmpRLECodec_DEFINED +#define SkBmpRLECodec_DEFINED #include "SkBmpCodec.h" #include "SkColorTable.h" @@ -32,13 +34,10 @@ public: * @param offset the offset of the image pixel data from the end of the * headers * @param rowOrder indicates whether rows are ordered top-down or bottom-up - * @param RLEBytes indicates the amount of data left in the stream - * after decoding the headers */ SkBmpRLECodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, - uint32_t offset, SkCodec::SkScanlineOrder rowOrder, - size_t RLEBytes); + uint32_t offset, SkCodec::SkScanlineOrder rowOrder); int setSampleX(int); @@ -48,7 +47,7 @@ protected: size_t dstRowBytes, const Options&, SkPMColor*, int*, int*) override; - SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, + SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) override; @@ -89,28 +88,32 @@ private: */ int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts) override; + int decodeRLE(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes); bool skipRows(int count) override; SkSampler* getSampler(bool createIfNecessary) override; - SkAutoTUnref fColorTable; // owned + sk_sp fColorTable; // fNumColors is the number specified in the header, or 0 if not present in the header. - const uint32_t fNumColors; - const uint32_t fBytesPerColor; - const uint32_t fOffset; - SkAutoTDeleteArray fStreamBuffer; - size_t fRLEBytes; - const size_t fOrigRLEBytes; - uint32_t fCurrRLEByte; - int fSampleX; - SkAutoTDelete fSampler; + const uint32_t fNumColors; + const uint32_t fBytesPerColor; + const uint32_t fOffset; + + static constexpr size_t kBufferSize = 4096; + uint8_t fStreamBuffer[kBufferSize]; + size_t fBytesBuffered; + + uint32_t fCurrRLEByte; + int fSampleX; + std::unique_ptr fSampler; // Scanline decodes allow the client to ask for a single scanline at a time. // This can be tricky when the RLE encoding instructs the decoder to jump down // multiple lines. This field keeps track of lines that need to be skipped // on subsequent calls to decodeRows(). - int fLinesToSkip; + int fLinesToSkip; typedef SkBmpCodec INHERITED; }; +#endif // SkBmpRLECodec_DEFINED diff --git a/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp b/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp index 7d67d18c8ff3..a0ad7875ebf6 100644 --- a/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp @@ -25,10 +25,11 @@ SkBmpStandardCodec::SkBmpStandardCodec(int width, int height, const SkEncodedInf , fBytesPerColor(bytesPerColor) , fOffset(offset) , fSwizzler(nullptr) - , fSrcBuffer(new uint8_t [this->srcRowBytes()]) + , fSrcBuffer(new uint8_t[this->srcRowBytes()]) , fIsOpaque(isOpaque) , fInIco(inIco) , fAndMaskRowBytes(fInIco ? SkAlign4(compute_row_bytes(this->getInfo().width(), 1)) : 0) + , fXformOnDecode(false) {} /* @@ -48,10 +49,6 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, SkCodecPrintf("Error: scaling not supported.\n"); return kInvalidScale; } - if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { - SkCodecPrintf("Error: cannot convert input type to output type.\n"); - return kInvalidConversion; - } Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { @@ -88,15 +85,22 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, // Read the color table from the stream colorBytes = numColorsToRead * fBytesPerColor; - SkAutoTDeleteArray cBuffer(new uint8_t[colorBytes]); + std::unique_ptr cBuffer(new uint8_t[colorBytes]); if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) { SkCodecPrintf("Error: unable to read color table.\n"); return false; } + SkColorType packColorType = dstColorType; + SkAlphaType packAlphaType = dstAlphaType; + if (this->colorXform()) { + packColorType = kBGRA_8888_SkColorType; + packAlphaType = kUnpremul_SkAlphaType; + } + // Choose the proper packing function - bool isPremul = (kPremul_SkAlphaType == dstAlphaType) && !fIsOpaque; - PackColorProc packARGB = choose_pack_color_proc(isPremul, dstColorType); + bool isPremul = (kPremul_SkAlphaType == packAlphaType) && !fIsOpaque; + PackColorProc packARGB = choose_pack_color_proc(isPremul, packColorType); // Fill in the color table uint32_t i = 0; @@ -120,6 +124,15 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); } + if (this->colorXform() && !fXformOnDecode) { + SkColorSpaceXform::ColorFormat dstFormat = select_xform_format_ct(dstColorType); + SkColorSpaceXform::ColorFormat srcFormat = SkColorSpaceXform::kBGRA_8888_ColorFormat; + SkAlphaType xformAlphaType = select_xform_alpha(dstAlphaType, + this->getInfo().alphaType()); + SkAssertResult(this->colorXform()->apply(dstFormat, colorTable, srcFormat, colorTable, + maxColors, xformAlphaType)); + } + // Set the color table fColorTable.reset(new SkColorTable(colorTable, maxColors)); } @@ -153,13 +166,13 @@ void SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Op // In the case of bmp-in-icos, we will report BGRA to the client, // since we may be required to apply an alpha mask after the decode. // However, the swizzler needs to know the actual format of the bmp. - SkEncodedInfo swizzlerInfo = this->getEncodedInfo(); + SkEncodedInfo encodedInfo = this->getEncodedInfo(); if (fInIco) { if (this->bitsPerPixel() <= 8) { - swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, - swizzlerInfo.alpha(), this->bitsPerPixel()); + encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, + encodedInfo.alpha(), this->bitsPerPixel()); } else if (this->bitsPerPixel() == 24) { - swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kBGR_Color, + encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kBGR_Color, SkEncodedInfo::kOpaque_Alpha, 8); } } @@ -167,13 +180,33 @@ void SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Op // Get a pointer to the color table if it exists const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); - // Create swizzler - fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, colorPtr, dstInfo, opts)); + SkImageInfo swizzlerInfo = dstInfo; + SkCodec::Options swizzlerOptions = opts; + if (this->colorXform()) { + swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType); + if (kPremul_SkAlphaType == dstInfo.alphaType()) { + swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); + } + + swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized; + } + + + fSwizzler.reset(SkSwizzler::CreateSwizzler(encodedInfo, colorPtr, swizzlerInfo, + swizzlerOptions)); SkASSERT(fSwizzler); } -SkCodec::Result SkBmpStandardCodec::prepareToDecode(const SkImageInfo& dstInfo, +SkCodec::Result SkBmpStandardCodec::onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { + fXformOnDecode = false; + if (this->colorXform()) { + fXformOnDecode = apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color()); + if (fXformOnDecode) { + this->resetXformBuffer(dstInfo.width()); + } + } + // Create the color table if necessary and prepare the stream for decode // Note that if it is non-NULL, inputColorCount will be modified if (!this->createColorTable(dstInfo.colorType(), dstInfo.alphaType(), inputColorCount)) { @@ -182,7 +215,7 @@ SkCodec::Result SkBmpStandardCodec::prepareToDecode(const SkImageInfo& dstInfo, } // Copy the color table to the client if necessary - copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount); + copy_color_table(dstInfo, fColorTable.get(), inputColorPtr, inputColorCount); // Initialize a swizzler this->initializeSwizzler(dstInfo, options); @@ -207,7 +240,15 @@ int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t uint32_t row = this->getDstRow(y, dstInfo.height()); void* dstRow = SkTAddOffset(dst, row * dstRowBytes); - fSwizzler->swizzle(dstRow, fSrcBuffer.get()); + + if (fXformOnDecode) { + SkASSERT(this->colorXform()); + SkImageInfo xformInfo = dstInfo.makeWH(fSwizzler->swizzleWidth(), dstInfo.height()); + fSwizzler->swizzle(this->xformBuffer(), fSrcBuffer.get()); + this->applyColorXform(xformInfo, dstRow, this->xformBuffer()); + } else { + fSwizzler->swizzle(dstRow, fSrcBuffer.get()); + } } if (fInIco && fIsOpaque) { @@ -266,7 +307,8 @@ void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstI // prevents us from using kIndex8. The below code depends on the output // being an SkPMColor. SkASSERT(kRGBA_8888_SkColorType == dstInfo.colorType() || - kBGRA_8888_SkColorType == dstInfo.colorType()); + kBGRA_8888_SkColorType == dstInfo.colorType() || + kRGBA_F16_SkColorType == dstInfo.colorType()); // If we are sampling, make sure that we only mask the sampled pixels. // We do not need to worry about sampling in the y-dimension because that @@ -284,10 +326,19 @@ void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstI return; } + auto applyMask = [dstInfo](void* dstRow, int x, uint64_t bit) { + if (kRGBA_F16_SkColorType == dstInfo.colorType()) { + uint64_t* dst64 = (uint64_t*) dstRow; + dst64[x] &= bit - 1; + } else { + uint32_t* dst32 = (uint32_t*) dstRow; + dst32[x] &= bit - 1; + } + }; + int row = this->getDstRow(y, dstInfo.height()); - SkPMColor* dstRow = - SkTAddOffset(dstPtr, row * dstRowBytes); + void* dstRow = SkTAddOffset(dstPtr, row * dstRowBytes); int srcX = srcStartX; for (int dstX = 0; dstX < sampledWidth; dstX++) { @@ -295,8 +346,8 @@ void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstI int modulus; SkTDivMod(srcX, 8, "ient, &modulus); uint32_t shift = 7 - modulus; - uint32_t alphaBit = (fSrcBuffer.get()[quotient] >> shift) & 0x1; - dstRow[dstX] &= alphaBit - 1; + uint64_t alphaBit = (fSrcBuffer.get()[quotient] >> shift) & 0x1; + applyMask(dstRow, dstX, alphaBit); srcX += sampleX; } } @@ -306,7 +357,7 @@ uint64_t SkBmpStandardCodec::onGetFillValue(const SkImageInfo& dstInfo) const { const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); if (colorPtr) { return get_color_table_fill_value(dstInfo.colorType(), dstInfo.alphaType(), colorPtr, 0, - nullptr); + this->colorXform(), false); } return INHERITED::onGetFillValue(dstInfo); } diff --git a/gfx/skia/skia/src/codec/SkBmpStandardCodec.h b/gfx/skia/skia/src/codec/SkBmpStandardCodec.h index 7039cf7efea5..740db8ead0b5 100644 --- a/gfx/skia/skia/src/codec/SkBmpStandardCodec.h +++ b/gfx/skia/skia/src/codec/SkBmpStandardCodec.h @@ -4,6 +4,8 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#ifndef SkBmpStandardCodec_DEFINED +#define SkBmpStandardCodec_DEFINED #include "SkBmpCodec.h" #include "SkColorTable.h" @@ -52,7 +54,7 @@ protected: return fInIco; } - SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, + SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) override; @@ -61,7 +63,7 @@ protected: SkSampler* getSampler(bool createIfNecessary) override { SkASSERT(fSwizzler); - return fSwizzler; + return fSwizzler.get(); } private: @@ -84,16 +86,18 @@ private: */ void decodeIcoMask(SkStream* stream, const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes); - SkAutoTUnref fColorTable; // owned + sk_sp fColorTable; // fNumColors is the number specified in the header, or 0 if not present in the header. - const uint32_t fNumColors; - const uint32_t fBytesPerColor; - const uint32_t fOffset; - SkAutoTDelete fSwizzler; - SkAutoTDeleteArray fSrcBuffer; - const bool fIsOpaque; - const bool fInIco; - const size_t fAndMaskRowBytes; // only used for fInIco decodes + const uint32_t fNumColors; + const uint32_t fBytesPerColor; + const uint32_t fOffset; + std::unique_ptr fSwizzler; + std::unique_ptr fSrcBuffer; + const bool fIsOpaque; + const bool fInIco; + const size_t fAndMaskRowBytes; // only used for fInIco decodes + bool fXformOnDecode; typedef SkBmpCodec INHERITED; }; +#endif // SkBmpStandardCodec_DEFINED diff --git a/gfx/skia/skia/src/codec/SkCodec.cpp b/gfx/skia/skia/src/codec/SkCodec.cpp index 84afc2bdee28..6a6fdc78c9ce 100644 --- a/gfx/skia/skia/src/codec/SkCodec.cpp +++ b/gfx/skia/skia/src/codec/SkCodec.cpp @@ -9,6 +9,7 @@ #include "SkCodec.h" #include "SkCodecPriv.h" #include "SkColorSpace.h" +#include "SkColorSpaceXform_Base.h" #include "SkData.h" #include "SkGifCodec.h" #include "SkHalf.h" @@ -34,9 +35,7 @@ static const DecoderProc gDecoderProcs[] = { #ifdef SK_HAS_WEBP_LIBRARY { SkWebpCodec::IsWebp, SkWebpCodec::NewFromStream }, #endif -#ifdef SK_HAS_GIF_LIBRARY { SkGifCodec::IsGif, SkGifCodec::NewFromStream }, -#endif #ifdef SK_HAS_PNG_LIBRARY { SkIcoCodec::IsIco, SkIcoCodec::NewFromStream }, #endif @@ -54,7 +53,7 @@ SkCodec* SkCodec::NewFromStream(SkStream* stream, return nullptr; } - SkAutoTDelete streamDeleter(stream); + std::unique_ptr streamDeleter(stream); // 14 is enough to read all of the supported types. const size_t bytesToRead = 14; @@ -142,12 +141,6 @@ SkCodec::SkCodec(const SkEncodedInfo& info, const SkImageInfo& imageInfo, SkStre SkCodec::~SkCodec() {} bool SkCodec::rewindIfNeeded() { - if (!fStream) { - // Some codecs do not have a stream. They may hold onto their own data or another codec. - // They must handle rewinding themselves. - return true; - } - // Store the value of fNeedsRewind so we can update it. Next read will // require a rewind. const bool needsRewind = fNeedsRewind; @@ -161,7 +154,9 @@ bool SkCodec::rewindIfNeeded() { // startIncrementalDecode will need to be called before incrementalDecode. fStartedIncrementalDecode = false; - if (!fStream->rewind()) { + // Some codecs do not have a stream. They may hold onto their own data or another codec. + // They must handle rewinding themselves. + if (fStream && !fStream->rewind()) { return false; } @@ -220,9 +215,7 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t } fDstInfo = info; - // FIXME: fOptions should be updated to options here, since fillIncompleteImage (called below - // in this method) accesses it. Without updating, it uses the old value. - //fOptions = *options; + fOptions = *options; // On an incomplete decode, the subclass will specify the number of scanlines that it decoded // successfully. @@ -240,6 +233,12 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t // their own. They indicate that all of the memory has been filled by // setting rowsDecoded equal to the height. if (kIncompleteInput == result && rowsDecoded != info.height()) { + // FIXME: (skbug.com/5772) fillIncompleteImage will fill using the swizzler's width, unless + // there is a subset. In that case, it will use the width of the subset. From here, the + // subset will only be non-null in the case of SkWebpCodec, but it treats the subset + // differenty from the other codecs, and it needs to use the width specified by the info. + // Set the subset to null so SkWebpCodec uses the correct width. + fOptions.fSubset = nullptr; this->fillIncompleteImage(info, pixels, rowBytes, options->fZeroInitialized, info.height(), rowsDecoded); } @@ -472,14 +471,42 @@ void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler); break; } - case kOutOfOrder_SkScanlineOrder: { - SkASSERT(1 == linesRequested || this->getInfo().height() == linesRequested); - const SkImageInfo fillInfo = info.makeWH(fillWidth, 1); - for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { - fillDst = SkTAddOffset(dst, this->outputScanline(srcY) * rowBytes); - fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler); + } +} + +bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, + SkTransferFunctionBehavior premulBehavior) { + fColorXform = nullptr; + bool needsColorCorrectPremul = needs_premul(dstInfo, fEncodedInfo) && + SkTransferFunctionBehavior::kRespect == premulBehavior; + if (needs_color_xform(dstInfo, fSrcInfo, needsColorCorrectPremul)) { + fColorXform = SkColorSpaceXform_Base::New(fSrcInfo.colorSpace(), dstInfo.colorSpace(), + premulBehavior); + if (!fColorXform) { + return false; + } + } + + return true; +} + +std::vector SkCodec::getFrameInfo() { + const size_t frameCount = this->getFrameCount(); + switch (frameCount) { + case 0: + return std::vector{}; + case 1: + if (!this->onGetFrameInfo(0, nullptr)) { + // Not animated. + return std::vector{}; } - break; + // fall through + default: { + std::vector result(frameCount); + for (size_t i = 0; i < frameCount; ++i) { + SkAssertResult(this->onGetFrameInfo(i, &result[i])); + } + return result; } } } diff --git a/gfx/skia/skia/src/codec/SkCodecAnimation.h b/gfx/skia/skia/src/codec/SkCodecAnimation.h new file mode 100644 index 000000000000..b0495b89eeae --- /dev/null +++ b/gfx/skia/skia/src/codec/SkCodecAnimation.h @@ -0,0 +1,50 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCodecAnimation_DEFINED +#define SkCodecAnimation_DEFINED + +#include "SkCodec.h" +#include "SkRect.h" + +class SkCodecAnimation { +public: + /** + * This specifies how the next frame is based on this frame. + * + * Names are based on the GIF 89a spec. + * + * The numbers correspond to values in a GIF. + */ + enum DisposalMethod { + /** + * The next frame should be drawn on top of this one. + * + * In a GIF, a value of 0 (not specified) is also treated as Keep. + */ + Keep_DisposalMethod = 1, + + /** + * Similar to Keep, except the area inside this frame's rectangle + * should be cleared to the BackGround color (transparent) before + * drawing the next frame. + */ + RestoreBGColor_DisposalMethod = 2, + + /** + * The next frame should be drawn on top of the previous frame - i.e. + * disregarding this one. + * + * In a GIF, a value of 4 is also treated as RestorePrevious. + */ + RestorePrevious_DisposalMethod = 3, + }; + +private: + SkCodecAnimation(); +}; +#endif // SkCodecAnimation_DEFINED diff --git a/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp b/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp index 8108f0de441c..6467033371fa 100644 --- a/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp +++ b/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp @@ -6,14 +6,15 @@ */ #include "SkCodecImageGenerator.h" +#include "SkMakeUnique.h" -SkImageGenerator* SkCodecImageGenerator::NewFromEncodedCodec(sk_sp data) { +std::unique_ptr SkCodecImageGenerator::MakeFromEncodedCodec(sk_sp data) { SkCodec* codec = SkCodec::NewFromData(data); if (nullptr == codec) { return nullptr; } - return new SkCodecImageGenerator(codec, data); + return std::unique_ptr(new SkCodecImageGenerator(codec, data)); } static SkImageInfo make_premul(const SkImageInfo& info) { @@ -30,20 +31,25 @@ SkCodecImageGenerator::SkCodecImageGenerator(SkCodec* codec, sk_sp data) , fData(std::move(data)) {} -SkData* SkCodecImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { +SkData* SkCodecImageGenerator::onRefEncodedData(GrContext* ctx) { return SkRef(fData.get()); } bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) { + Options opts; + opts.fColorTable = ctable; + opts.fColorTableCount = ctableCount; + opts.fBehavior = SkTransferFunctionBehavior::kRespect; + return this->onGetPixels(info, pixels, rowBytes, opts); +} - // FIXME (msarett): - // We don't give the client the chance to request an SkColorSpace. Until we improve - // the API, let's assume that they want legacy mode. - SkImageInfo decodeInfo = info.makeColorSpace(nullptr); - - SkCodec::Result result = fCodec->getPixels(decodeInfo, pixels, rowBytes, nullptr, ctable, - ctableCount); +bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + const Options& opts) { + SkCodec::Options codecOpts; + codecOpts.fPremulBehavior = opts.fBehavior; + SkCodec::Result result = fCodec->getPixels(info, pixels, rowBytes, &codecOpts, opts.fColorTable, + opts.fColorTableCount); switch (result) { case SkCodec::kSuccess: case SkCodec::kIncompleteInput: diff --git a/gfx/skia/skia/src/codec/SkCodecImageGenerator.h b/gfx/skia/skia/src/codec/SkCodecImageGenerator.h index 22a39aaaa90e..a435205fa9b9 100644 --- a/gfx/skia/skia/src/codec/SkCodecImageGenerator.h +++ b/gfx/skia/skia/src/codec/SkCodecImageGenerator.h @@ -4,8 +4,11 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#ifndef SkCodecImageGenerator_DEFINED +#define SkCodecImageGenerator_DEFINED #include "SkCodec.h" +#include "SkColorTable.h" #include "SkData.h" #include "SkImageGenerator.h" @@ -15,16 +18,15 @@ public: * If this data represents an encoded image that we know how to decode, * return an SkCodecImageGenerator. Otherwise return nullptr. */ - static SkImageGenerator* NewFromEncodedCodec(sk_sp); - static SkImageGenerator* NewFromEncodedCodec(SkData* data) { - return NewFromEncodedCodec(sk_ref_sp(data)); - } + static std::unique_ptr MakeFromEncodedCodec(sk_sp); protected: - SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) override; + SkData* onRefEncodedData(GrContext* ctx) override; bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], - int* ctableCount) override; + int* ctableCount) override; + bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options& opts) + override; bool onQueryYUV8(SkYUVSizeInfo*, SkYUVColorSpace*) const override; @@ -36,8 +38,10 @@ private: */ SkCodecImageGenerator(SkCodec* codec, sk_sp); - SkAutoTDelete fCodec; + std::unique_ptr fCodec; sk_sp fData; + sk_sp fColorTable; typedef SkImageGenerator INHERITED; }; +#endif // SkCodecImageGenerator_DEFINED diff --git a/gfx/skia/skia/src/codec/SkCodecPriv.h b/gfx/skia/skia/src/codec/SkCodecPriv.h index b93def879022..5c8dc8747aa9 100644 --- a/gfx/skia/skia/src/codec/SkCodecPriv.h +++ b/gfx/skia/skia/src/codec/SkCodecPriv.h @@ -10,7 +10,9 @@ #include "SkColorPriv.h" #include "SkColorSpaceXform.h" +#include "SkColorSpaceXformPriv.h" #include "SkColorTable.h" +#include "SkEncodedInfo.h" #include "SkImageInfo.h" #include "SkTypes.h" @@ -107,36 +109,6 @@ static inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) { return true; } -/* - * Original version of conversion_possible that does not account for color spaces. - * Used by codecs that have not been updated to support color spaces. - * - * Most of our codecs support the same conversions: - * - opaque to any alpha type - * - 565 only if opaque - * - premul to unpremul and vice versa - * - always support RGBA, BGRA - * - otherwise match the src color type - */ -static inline bool conversion_possible_ignore_color_space(const SkImageInfo& dst, - const SkImageInfo& src) { - // Ensure the alpha type is valid - if (!valid_alpha(dst.alphaType(), src.alphaType())) { - return false; - } - - // Check for supported color types - switch (dst.colorType()) { - case kRGBA_8888_SkColorType: - case kBGRA_8888_SkColorType: - return true; - case kRGB_565_SkColorType: - return kOpaque_SkAlphaType == src.alphaType(); - default: - return dst.colorType() == src.colorType(); - } -} - /* * If there is a color table, get a pointer to the colors, otherwise return nullptr */ @@ -144,25 +116,11 @@ static inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) { return nullptr != colorTable ? colorTable->readColors() : nullptr; } -static inline SkColorSpaceXform::ColorFormat select_xform_format(SkColorType colorType) { - switch (colorType) { - case kRGBA_8888_SkColorType: - return SkColorSpaceXform::kRGBA_8888_ColorFormat; - case kBGRA_8888_SkColorType: - return SkColorSpaceXform::kBGRA_8888_ColorFormat; - case kRGBA_F16_SkColorType: - return SkColorSpaceXform::kRGBA_F16_ColorFormat; - default: - SkASSERT(false); - return SkColorSpaceXform::kRGBA_8888_ColorFormat; - } -} - /* * Given that the encoded image uses a color table, return the fill value */ static inline uint64_t get_color_table_fill_value(SkColorType dstColorType, SkAlphaType alphaType, - const SkPMColor* colorPtr, uint8_t fillIndex, SkColorSpaceXform* colorXform) { + const SkPMColor* colorPtr, uint8_t fillIndex, SkColorSpaceXform* colorXform, bool isRGBA) { SkASSERT(nullptr != colorPtr); switch (dstColorType) { case kRGBA_8888_SkColorType: @@ -176,8 +134,11 @@ static inline uint64_t get_color_table_fill_value(SkColorType dstColorType, SkAl SkASSERT(colorXform); uint64_t dstColor; uint32_t srcColor = colorPtr[fillIndex]; - colorXform->apply(&dstColor, &srcColor, 1, select_xform_format(dstColorType), - SkColorSpaceXform::kRGBA_8888_ColorFormat, alphaType); + SkColorSpaceXform::ColorFormat srcFormat = + isRGBA ? SkColorSpaceXform::kRGBA_8888_ColorFormat + : SkColorSpaceXform::kBGRA_8888_ColorFormat; + SkAssertResult(colorXform->apply(select_xform_format(dstColorType), &dstColor, + srcFormat, &srcColor, 1, alphaType)); return dstColor; } default: @@ -337,14 +298,17 @@ static inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType co } } -static inline bool needs_premul(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) { +static inline bool needs_premul(const SkImageInfo& dstInfo, const SkEncodedInfo& encodedInfo) { return kPremul_SkAlphaType == dstInfo.alphaType() && - kUnpremul_SkAlphaType == srcInfo.alphaType(); + SkEncodedInfo::kUnpremul_Alpha == encodedInfo.alpha(); } -static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) { - // Color xform is necessary in order to correctly perform premultiply in linear space. - bool needsPremul = needs_premul(dstInfo, srcInfo); +static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, + bool needsColorCorrectPremul) { + // We never perform a color xform in legacy mode. + if (!dstInfo.colorSpace()) { + return false; + } // F16 is by definition a linear space, so we always must perform a color xform. bool isF16 = kRGBA_F16_SkColorType == dstInfo.colorType(); @@ -352,16 +316,18 @@ static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageIn // Need a color xform when dst space does not match the src. bool srcDstNotEqual = !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace()); - // We never perform a color xform in legacy mode. - bool isLegacy = nullptr == dstInfo.colorSpace(); - - return !isLegacy && (needsPremul || isF16 || srcDstNotEqual); + return needsColorCorrectPremul || isF16 || srcDstNotEqual; } static inline SkAlphaType select_xform_alpha(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) { return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType; } +static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) { + // We will apply the color xform when reading the color table unless F16 is requested. + return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType; +} + /* * Alpha Type Conversions * - kOpaque to kOpaque, kUnpremul, kPremul is valid @@ -390,13 +356,32 @@ static inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo case kIndex_8_SkColorType: return kIndex_8_SkColorType == src.colorType(); case kRGB_565_SkColorType: - return kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src); + return kOpaque_SkAlphaType == src.alphaType(); case kGray_8_SkColorType: return kGray_8_SkColorType == src.colorType() && - kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src); + kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src, false); default: return false; } } +static inline SkColorSpaceXform::ColorFormat select_xform_format_ct(SkColorType colorType) { + switch (colorType) { + case kRGBA_8888_SkColorType: + return SkColorSpaceXform::kRGBA_8888_ColorFormat; + case kBGRA_8888_SkColorType: + return SkColorSpaceXform::kBGRA_8888_ColorFormat; + case kRGB_565_SkColorType: + case kIndex_8_SkColorType: +#ifdef SK_PMCOLOR_IS_RGBA + return SkColorSpaceXform::kRGBA_8888_ColorFormat; +#else + return SkColorSpaceXform::kBGRA_8888_ColorFormat; +#endif + default: + SkASSERT(false); + return SkColorSpaceXform::kRGBA_8888_ColorFormat; + } +} + #endif // SkCodecPriv_DEFINED diff --git a/gfx/skia/skia/src/codec/SkGifCodec.cpp b/gfx/skia/skia/src/codec/SkGifCodec.cpp index c35cd24ae498..2e0ec3057de0 100644 --- a/gfx/skia/skia/src/codec/SkGifCodec.cpp +++ b/gfx/skia/skia/src/codec/SkGifCodec.cpp @@ -5,23 +5,51 @@ * found in the LICENSE file. */ +/* + * Copyright (C) 2006 Apple Computer, 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#include "SkCodecAnimation.h" #include "SkCodecPriv.h" #include "SkColorPriv.h" #include "SkColorTable.h" #include "SkGifCodec.h" #include "SkStream.h" #include "SkSwizzler.h" -#include "SkUtils.h" -#include "gif_lib.h" +#include + +#define GIF87_STAMP "GIF87a" +#define GIF89_STAMP "GIF89a" +#define GIF_STAMP_LEN 6 /* * Checks the start of the stream to see if the image is a gif */ bool SkGifCodec::IsGif(const void* buf, size_t bytesRead) { if (bytesRead >= GIF_STAMP_LEN) { - if (memcmp(GIF_STAMP, buf, GIF_STAMP_LEN) == 0 || - memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 || + if (memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 || memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) { return true; @@ -38,570 +66,610 @@ static SkCodec::Result gif_error(const char* msg, SkCodec::Result result = SkCod return result; } - -/* - * Read function that will be passed to gif_lib - */ -static int32_t read_bytes_callback(GifFileType* fileType, GifByteType* out, int32_t size) { - SkStream* stream = (SkStream*) fileType->UserData; - return (int32_t) stream->read(out, size); -} - -/* - * Open the gif file - */ -static GifFileType* open_gif(SkStream* stream) { -#if GIFLIB_MAJOR < 5 - return DGifOpen(stream, read_bytes_callback); -#else - return DGifOpen(stream, read_bytes_callback, nullptr); -#endif -} - -/* - * Check if a there is an index of the color table for a transparent pixel - */ -static uint32_t find_trans_index(const SavedImage& image) { - // If there is a transparent index specified, it will be contained in an - // extension block. We will loop through extension blocks in reverse order - // to check the most recent extension blocks first. - for (int32_t i = image.ExtensionBlockCount - 1; i >= 0; i--) { - // Get an extension block - const ExtensionBlock& extBlock = image.ExtensionBlocks[i]; - - // Specifically, we need to check for a graphics control extension, - // which may contain transparency information. Also, note that a valid - // graphics control extension is always four bytes. The fourth byte - // is the transparent index (if it exists), so we need at least four - // bytes. - if (GRAPHICS_EXT_FUNC_CODE == extBlock.Function && extBlock.ByteCount >= 4) { - // Check the transparent color flag which indicates whether a - // transparent index exists. It is the least significant bit of - // the first byte of the extension block. - if (1 == (extBlock.Bytes[0] & 1)) { - // Use uint32_t to prevent sign extending - return extBlock.Bytes[3]; - } - - // There should only be one graphics control extension for the image frame - break; - } - } - - // Use maximum unsigned int (surely an invalid index) to indicate that a valid - // index was not found. - return SK_MaxU32; -} - -inline uint32_t ceil_div(uint32_t a, uint32_t b) { - return (a + b - 1) / b; -} - -/* - * Gets the output row corresponding to the encoded row for interlaced gifs - */ -inline uint32_t get_output_row_interlaced(uint32_t encodedRow, uint32_t height) { - SkASSERT(encodedRow < height); - // First pass - if (encodedRow * 8 < height) { - return encodedRow * 8; - } - // Second pass - if (encodedRow * 4 < height) { - return 4 + 8 * (encodedRow - ceil_div(height, 8)); - } - // Third pass - if (encodedRow * 2 < height) { - return 2 + 4 * (encodedRow - ceil_div(height, 4)); - } - // Fourth pass - return 1 + 2 * (encodedRow - ceil_div(height, 2)); -} - -/* - * This function cleans up the gif object after the decode completes - * It is used in a SkAutoTCallIProc template - */ -void SkGifCodec::CloseGif(GifFileType* gif) { -#if GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0) - DGifCloseFile(gif); -#else - DGifCloseFile(gif, nullptr); -#endif -} - -/* - * This function free extension data that has been saved to assist the image - * decoder - */ -void SkGifCodec::FreeExtension(SavedImage* image) { - if (NULL != image->ExtensionBlocks) { -#if GIFLIB_MAJOR < 5 - FreeExtension(image); -#else - GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks); -#endif - } -} - -/* - * Read enough of the stream to initialize the SkGifCodec. - * Returns a bool representing success or failure. - * - * @param codecOut - * If it returned true, and codecOut was not nullptr, - * codecOut will be set to a new SkGifCodec. - * - * @param gifOut - * If it returned true, and codecOut was nullptr, - * gifOut must be non-nullptr and gifOut will be set to a new - * GifFileType pointer. - * - * @param stream - * Deleted on failure. - * codecOut will take ownership of it in the case where we created a codec. - * Ownership is unchanged when we returned a gifOut. - * - */ -bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** gifOut) { - SkAutoTDelete streamDeleter(stream); - - // Read gif header, logical screen descriptor, and global color table - SkAutoTCallVProc gif(open_gif(stream)); - - if (nullptr == gif) { - gif_error("DGifOpen failed.\n"); - return false; - } - - // Read through gif extensions to get to the image data. Set the - // transparent index based on the extension data. - uint32_t transIndex; - SkCodec::Result result = ReadUpToFirstImage(gif, &transIndex); - if (kSuccess != result){ - return false; - } - - // Read the image descriptor - if (GIF_ERROR == DGifGetImageDesc(gif)) { - return false; - } - // If reading the image descriptor is successful, the image count will be - // incremented. - SkASSERT(gif->ImageCount >= 1); - - if (nullptr != codecOut) { - SkISize size; - SkIRect frameRect; - if (!GetDimensions(gif, &size, &frameRect)) { - gif_error("Invalid gif size.\n"); - return false; - } - bool frameIsSubset = (size != frameRect.size()); - - // Determine the encoded alpha type. The transIndex might be valid if it less - // than 256. We are not certain that the index is valid until we process the color - // table, since some gifs have color tables with less than 256 colors. If - // there might be a valid transparent index, we must indicate that the image has - // alpha. - // In the case where we must support alpha, we indicate kBinary, since every - // pixel will either be fully opaque or fully transparent. - SkEncodedInfo::Alpha alpha = (transIndex < 256) ? SkEncodedInfo::kBinary_Alpha : - SkEncodedInfo::kOpaque_Alpha; - - // Return the codec - // Use kPalette since Gifs are encoded with a color table. - // Use 8-bits per component, since this is the output we get from giflib. - // FIXME: Gifs can actually be encoded with 4-bits per pixel. Can we support this? - SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8); - *codecOut = new SkGifCodec(size.width(), size.height(), info, streamDeleter.release(), - gif.release(), transIndex, frameRect, frameIsSubset); - } else { - SkASSERT(nullptr != gifOut); - streamDeleter.release(); - *gifOut = gif.release(); - } - return true; -} - /* * Assumes IsGif was called and returned true * Creates a gif decoder * Reads enough of the stream to determine the image format */ SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { - SkCodec* codec = nullptr; - if (ReadHeader(stream, &codec, nullptr)) { - return codec; + std::unique_ptr reader(new SkGifImageReader(stream)); + if (!reader->parse(SkGifImageReader::SkGIFSizeQuery)) { + // Fatal error occurred. + return nullptr; } - return nullptr; -} -SkGifCodec::SkGifCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, - GifFileType* gif, uint32_t transIndex, const SkIRect& frameRect, bool frameIsSubset) - : INHERITED(width, height, info, stream) - , fGif(gif) - , fSrcBuffer(new uint8_t[this->getInfo().width()]) - , fFrameRect(frameRect) - // If it is valid, fTransIndex will be used to set fFillIndex. We don't know if - // fTransIndex is valid until we process the color table, since fTransIndex may - // be greater than the size of the color table. - , fTransIndex(transIndex) - // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid, or if - // there is a valid background color. - , fFillIndex(0) - , fFrameIsSubset(frameIsSubset) - , fSwizzler(NULL) - , fColorTable(NULL) -{} + // If no images are in the data, or the first header is not yet defined, we cannot + // create a codec. In either case, the width and height are not yet known. + if (0 == reader->imagesCount() || !reader->frameContext(0)->isHeaderDefined()) { + return nullptr; + } + + // isHeaderDefined() will not return true if the screen size is empty. + SkASSERT(reader->screenHeight() > 0 && reader->screenWidth() > 0); + + const auto alpha = reader->firstFrameHasAlpha() ? SkEncodedInfo::kBinary_Alpha + : SkEncodedInfo::kOpaque_Alpha; + // Use kPalette since Gifs are encoded with a color table. + // FIXME: Gifs can actually be encoded with 4-bits per pixel. Using 8 works, but we could skip + // expanding to 8 bits and take advantage of the SkSwizzler to work from 4. + const auto encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8); + + // Although the encodedInfo is always kPalette_Color, it is possible that kIndex_8 is + // unsupported if the frame is subset and there is no transparent pixel. + const auto colorType = reader->firstFrameSupportsIndex8() ? kIndex_8_SkColorType + : kN32_SkColorType; + // The choice of unpremul versus premul is arbitrary, since all colors are either fully + // opaque or fully transparent (i.e. kBinary), but we stored the transparent colors as all + // zeroes, which is arguably premultiplied. + const auto alphaType = reader->firstFrameHasAlpha() ? kUnpremul_SkAlphaType + : kOpaque_SkAlphaType; + + const auto imageInfo = SkImageInfo::Make(reader->screenWidth(), reader->screenHeight(), + colorType, alphaType, + SkColorSpace::MakeSRGB()); + return new SkGifCodec(encodedInfo, imageInfo, reader.release()); +} bool SkGifCodec::onRewind() { - GifFileType* gifOut = nullptr; - if (!ReadHeader(this->stream(), nullptr, &gifOut)) { - return false; - } - - SkASSERT(nullptr != gifOut); - fGif.reset(gifOut); + fReader->clearDecodeState(); return true; } -SkCodec::Result SkGifCodec::ReadUpToFirstImage(GifFileType* gif, uint32_t* transIndex) { - // Use this as a container to hold information about any gif extension - // blocks. This generally stores transparency and animation instructions. - SavedImage saveExt; - SkAutoTCallVProc autoFreeExt(&saveExt); - saveExt.ExtensionBlocks = nullptr; - saveExt.ExtensionBlockCount = 0; - GifByteType* extData; - int32_t extFunction; - - // We will loop over components of gif images until we find an image. Once - // we find an image, we will decode and return it. While many gif files - // contain more than one image, we will simply decode the first image. - GifRecordType recordType; - do { - // Get the current record type - if (GIF_ERROR == DGifGetRecordType(gif, &recordType)) { - return gif_error("DGifGetRecordType failed.\n", kInvalidInput); - } - switch (recordType) { - case IMAGE_DESC_RECORD_TYPE: { - *transIndex = find_trans_index(saveExt); - - // FIXME: Gif files may have multiple images stored in a single - // file. This is most commonly used to enable - // animations. Since we are leaving animated gifs as a - // TODO, we will return kSuccess after decoding the - // first image in the file. This is the same behavior - // as SkImageDecoder_libgif. - // - // Most times this works pretty well, but sometimes it - // doesn't. For example, I have an animated test image - // where the first image in the file is 1x1, but the - // subsequent images are meaningful. This currently - // displays the 1x1 image, which is not ideal. Right - // now I am leaving this as an issue that will be - // addressed when we implement animated gifs. - // - // It is also possible (not explicitly disallowed in the - // specification) that gif files provide multiple - // images in a single file that are all meant to be - // displayed in the same frame together. I will - // currently leave this unimplemented until I find a - // test case that expects this behavior. - return kSuccess; - } - // Extensions are used to specify special properties of the image - // such as transparency or animation. - case EXTENSION_RECORD_TYPE: - // Read extension data - if (GIF_ERROR == DGifGetExtension(gif, &extFunction, &extData)) { - return gif_error("Could not get extension.\n", kIncompleteInput); - } - - // Create an extension block with our data - while (nullptr != extData) { - // Add a single block - -#if GIFLIB_MAJOR < 5 - if (AddExtensionBlock(&saveExt, extData[0], - &extData[1]) == GIF_ERROR) { -#else - if (GIF_ERROR == GifAddExtensionBlock(&saveExt.ExtensionBlockCount, - &saveExt.ExtensionBlocks, - extFunction, extData[0], &extData[1])) { -#endif - return gif_error("Could not add extension block.\n", kIncompleteInput); - } - // Move to the next block - if (GIF_ERROR == DGifGetExtensionNext(gif, &extData)) { - return gif_error("Could not get next extension.\n", kIncompleteInput); - } - } - break; - - // Signals the end of the gif file - case TERMINATE_RECORD_TYPE: - break; - - default: - // DGifGetRecordType returns an error if the record type does - // not match one of the above cases. This should not be - // reached. - SkASSERT(false); - break; - } - } while (TERMINATE_RECORD_TYPE != recordType); - - return gif_error("Could not find any images to decode in gif file.\n", kInvalidInput); +SkGifCodec::SkGifCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo, + SkGifImageReader* reader) + : INHERITED(encodedInfo, imageInfo, nullptr) + , fReader(reader) + , fTmpBuffer(nullptr) + , fSwizzler(nullptr) + , fCurrColorTable(nullptr) + , fCurrColorTableIsReal(false) + , fFilledBackground(false) + , fFirstCallToIncrementalDecode(false) + , fDst(nullptr) + , fDstRowBytes(0) + , fRowsDecoded(0) +{ + reader->setClient(this); } -bool SkGifCodec::GetDimensions(GifFileType* gif, SkISize* size, SkIRect* frameRect) { - // Get the encoded dimension values - SavedImage* image = &gif->SavedImages[gif->ImageCount - 1]; - const GifImageDesc& desc = image->ImageDesc; - int frameLeft = desc.Left; - int frameTop = desc.Top; - int frameWidth = desc.Width; - int frameHeight = desc.Height; - int width = gif->SWidth; - int height = gif->SHeight; +size_t SkGifCodec::onGetFrameCount() { + fReader->parse(SkGifImageReader::SkGIFFrameCountQuery); + return fReader->imagesCount(); +} - // Ensure that the decode dimensions are large enough to contain the frame - width = SkTMax(width, frameWidth + frameLeft); - height = SkTMax(height, frameHeight + frameTop); - - // All of these dimensions should be positive, as they are encoded as unsigned 16-bit integers. - // It is unclear why giflib casts them to ints. We will go ahead and check that they are - // in fact positive. - if (frameLeft < 0 || frameTop < 0 || frameWidth < 0 || frameHeight < 0 || width <= 0 || - height <= 0) { +bool SkGifCodec::onGetFrameInfo(size_t i, SkCodec::FrameInfo* frameInfo) const { + if (i >= fReader->imagesCount()) { return false; } - frameRect->setXYWH(frameLeft, frameTop, frameWidth, frameHeight); - size->set(width, height); + const SkGIFFrameContext* frameContext = fReader->frameContext(i); + if (!frameContext->reachedStartOfData()) { + return false; + } + + if (frameInfo) { + frameInfo->fDuration = frameContext->delayTime(); + frameInfo->fRequiredFrame = frameContext->getRequiredFrame(); + frameInfo->fFullyReceived = frameContext->isComplete(); + frameInfo->fAlphaType = frameContext->hasAlpha() ? kUnpremul_SkAlphaType + : kOpaque_SkAlphaType; + } return true; } -void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, - int* inputColorCount) { - // Set up our own color table - const uint32_t maxColors = 256; - SkPMColor colorPtr[256]; - if (NULL != inputColorCount) { - // We set the number of colors to maxColors in order to ensure - // safe memory accesses. Otherwise, an invalid pixel could - // access memory outside of our color table array. - *inputColorCount = maxColors; +int SkGifCodec::onGetRepetitionCount() { + fReader->parse(SkGifImageReader::SkGIFLoopCountQuery); + return fReader->loopCount(); +} + +static const SkColorType kXformSrcColorType = kRGBA_8888_SkColorType; + +void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, size_t frameIndex) { + SkColorType colorTableColorType = dstInfo.colorType(); + if (this->colorXform()) { + colorTableColorType = kXformSrcColorType; } - // Get local color table - ColorMapObject* colorMap = fGif->Image.ColorMap; - // If there is no local color table, use the global color table - if (NULL == colorMap) { - colorMap = fGif->SColorMap; - } - - uint32_t colorCount = 0; - if (NULL != colorMap) { - colorCount = colorMap->ColorCount; - // giflib guarantees these properties - SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); - SkASSERT(colorCount <= 256); - PackColorProc proc = choose_pack_color_proc(false, dstInfo.colorType()); - for (uint32_t i = 0; i < colorCount; i++) { - colorPtr[i] = proc(0xFF, colorMap->Colors[i].Red, - colorMap->Colors[i].Green, colorMap->Colors[i].Blue); - } - } - - // Fill in the color table for indices greater than color count. - // This allows for predictable, safe behavior. - if (colorCount > 0) { - // Gifs have the option to specify the color at a single index of the color - // table as transparent. If the transparent index is greater than the - // colorCount, we know that there is no valid transparent color in the color - // table. If there is not valid transparent index, we will try to use the - // backgroundIndex as the fill index. If the backgroundIndex is also not - // valid, we will let fFillIndex default to 0 (it is set to zero in the - // constructor). This behavior is not specified but matches - // SkImageDecoder_libgif. - uint32_t backgroundIndex = fGif->SBackGroundColor; - if (fTransIndex < colorCount) { - colorPtr[fTransIndex] = SK_ColorTRANSPARENT; - fFillIndex = fTransIndex; - } else if (backgroundIndex < colorCount) { - fFillIndex = backgroundIndex; - } - - for (uint32_t i = colorCount; i < maxColors; i++) { - colorPtr[i] = colorPtr[fFillIndex]; - } + sk_sp currColorTable = fReader->getColorTable(colorTableColorType, frameIndex); + fCurrColorTableIsReal = currColorTable; + if (!fCurrColorTableIsReal) { + // This is possible for an empty frame. Create a dummy with one value (transparent). + SkPMColor color = SK_ColorTRANSPARENT; + fCurrColorTable.reset(new SkColorTable(&color, 1)); + } else if (this->colorXform() && !fXformOnDecode) { + SkPMColor dstColors[256]; + const SkColorSpaceXform::ColorFormat dstFormat = + select_xform_format_ct(dstInfo.colorType()); + const SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(kXformSrcColorType); + const SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), + this->getInfo().alphaType()); + SkAssertResult(this->colorXform()->apply(dstFormat, dstColors, srcFormat, + currColorTable->readColors(), + currColorTable->count(), xformAlphaType)); + fCurrColorTable.reset(new SkColorTable(dstColors, currColorTable->count())); } else { - sk_memset32(colorPtr, 0xFF000000, maxColors); + fCurrColorTable = std::move(currColorTable); } - - fColorTable.reset(new SkColorTable(colorPtr, maxColors)); - copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount); } + SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, int* inputColorCount, const Options& opts) { // Check for valid input parameters - if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { + if (!conversion_possible(dstInfo, this->getInfo()) || + !this->initializeColorXform(dstInfo, opts.fPremulBehavior)) + { return gif_error("Cannot convert input type to output type.\n", kInvalidConversion); } - // Initialize color table and copy to the client if necessary - this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); + fXformOnDecode = false; + if (this->colorXform()) { + fXformOnDecode = apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color()); + if (fXformOnDecode) { + fXformBuffer.reset(new uint32_t[dstInfo.width()]); + sk_bzero(fXformBuffer.get(), dstInfo.width() * sizeof(uint32_t)); + } + } + + if (opts.fSubset) { + return gif_error("Subsets not supported.\n", kUnimplemented); + } + + const size_t frameIndex = opts.fFrameIndex; + if (frameIndex > 0) { + switch (dstInfo.colorType()) { + case kIndex_8_SkColorType: + // FIXME: It is possible that a later frame can be decoded to index8, if it does one + // of the following: + // - Covers the entire previous frame + // - Shares a color table (and transparent index) with any prior frames that are + // showing. + // We must support index8 for the first frame to be backwards compatible on Android, + // but we do not (currently) need to support later frames as index8. + return gif_error("Cannot decode multiframe gif (except frame 0) as index 8.\n", + kInvalidConversion); + case kRGB_565_SkColorType: + // FIXME: In theory, we might be able to support this, but it's not clear that it + // is necessary (Chromium does not decode to 565, and Android does not decode + // frames beyond the first). Disabling it because it is somewhat difficult: + // - If there is a transparent pixel, and this frame draws on top of another frame + // (if the frame is independent with a transparent pixel, we should not decode to + // 565 anyway, since it is not opaque), we need to skip drawing the transparent + // pixels (see writeTransparentPixels in haveDecodedRow). We currently do this by + // first swizzling into temporary memory, then copying into the destination. (We + // let the swizzler handle it first because it may need to sample.) After + // swizzling to 565, we do not know which pixels in our temporary memory + // correspond to the transparent pixel, so we do not know what to skip. We could + // special case the non-sampled case (no need to swizzle), but as this is + // currently unused we can just not support it. + return gif_error("Cannot decode multiframe gif (except frame 0) as 565.\n", + kInvalidConversion); + default: + break; + } + } + + fReader->parse((SkGifImageReader::SkGIFParseQuery) frameIndex); + + if (frameIndex >= fReader->imagesCount()) { + return gif_error("frame index out of range!\n", kIncompleteInput); + } + + if (!fReader->frameContext(frameIndex)->reachedStartOfData()) { + // We have parsed enough to know that there is a color map, but cannot + // parse the map itself yet. Exit now, so we do not build an incorrect + // table. + return gif_error("color map not available yet\n", kIncompleteInput); + } + + fTmpBuffer.reset(new uint8_t[dstInfo.minRowBytes()]); + + this->initializeColorTable(dstInfo, frameIndex); + this->initializeSwizzler(dstInfo, frameIndex); + + SkASSERT(fCurrColorTable); + if (inputColorCount) { + *inputColorCount = fCurrColorTable->count(); + } + copy_color_table(dstInfo, fCurrColorTable.get(), inputColorPtr, inputColorCount); - this->initializeSwizzler(dstInfo, opts); return kSuccess; } -void SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) { - const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); - const SkIRect* frameRect = fFrameIsSubset ? &fFrameRect : nullptr; - fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colorPtr, dstInfo, opts, - frameRect)); - SkASSERT(fSwizzler); -} +void SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, size_t frameIndex) { + const SkGIFFrameContext* frame = fReader->frameContext(frameIndex); + // This is only called by prepareToDecode, which ensures frameIndex is in range. + SkASSERT(frame); -bool SkGifCodec::readRow() { - return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); + const int xBegin = frame->xOffset(); + const int xEnd = std::min(static_cast(frame->xOffset() + frame->width()), + static_cast(fReader->screenWidth())); + + // CreateSwizzler only reads left and right of the frame. We cannot use the frame's raw + // frameRect, since it might extend beyond the edge of the frame. + SkIRect swizzleRect = SkIRect::MakeLTRB(xBegin, 0, xEnd, 0); + + SkImageInfo swizzlerInfo = dstInfo; + if (this->colorXform()) { + swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType); + if (kPremul_SkAlphaType == dstInfo.alphaType()) { + swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); + } + } + + // The default Options should be fine: + // - we'll ignore if the memory is zero initialized - unless we're the first frame, this won't + // matter anyway. + // - subsets are not supported for gif + // - the swizzler does not need to know about the frame. + // We may not be able to use the real Options anyway, since getPixels does not store it (due to + // a bug). + fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), + fCurrColorTable->readColors(), swizzlerInfo, Options(), &swizzleRect)); + SkASSERT(fSwizzler.get()); } /* * Initiates the gif decode */ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, - void* dst, size_t dstRowBytes, + void* pixels, size_t dstRowBytes, const Options& opts, SkPMColor* inputColorPtr, int* inputColorCount, int* rowsDecoded) { Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, opts); - if (kSuccess != result) { - return result; + switch (result) { + case kSuccess: + break; + case kIncompleteInput: + // onStartIncrementalDecode treats this as incomplete, since it may + // provide more data later, but in this case, no more data will be + // provided, and there is nothing to draw. We also cannot return + // kIncompleteInput, which will make SkCodec attempt to fill + // remaining rows, but that requires an SkSwizzler, which we have + // not created. + return kInvalidInput; + default: + return result; } if (dstInfo.dimensions() != this->getInfo().dimensions()) { return gif_error("Scaling not supported.\n", kInvalidScale); } - // Initialize the swizzler - if (fFrameIsSubset) { - // Fill the background - SkSampler::Fill(dstInfo, dst, dstRowBytes, this->getFillValue(dstInfo), - opts.fZeroInitialized); + fDst = pixels; + fDstRowBytes = dstRowBytes; + + return this->decodeFrame(true, opts, rowsDecoded); +} + +SkCodec::Result SkGifCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, + void* pixels, size_t dstRowBytes, + const SkCodec::Options& opts, + SkPMColor* inputColorPtr, + int* inputColorCount) { + Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, opts); + if (result != kSuccess) { + return result; } - // Iterate over rows of the input - for (int y = fFrameRect.top(); y < fFrameRect.bottom(); y++) { - if (!this->readRow()) { - *rowsDecoded = y; - return gif_error("Could not decode line.\n", kIncompleteInput); - } - void* dstRow = SkTAddOffset(dst, dstRowBytes * this->outputScanline(y)); - fSwizzler->swizzle(dstRow, fSrcBuffer.get()); - } + fDst = pixels; + fDstRowBytes = dstRowBytes; + + fFirstCallToIncrementalDecode = true; + return kSuccess; } -// FIXME: This is similar to the implementation for bmp and png. Can we share more code or -// possibly make this non-virtual? -uint64_t SkGifCodec::onGetFillValue(const SkImageInfo& dstInfo) const { - const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); - return get_color_table_fill_value(dstInfo.colorType(), dstInfo.alphaType(), colorPtr, - fFillIndex, nullptr); +SkCodec::Result SkGifCodec::onIncrementalDecode(int* rowsDecoded) { + // It is possible the client has appended more data. Parse, if needed. + const auto& options = this->options(); + const size_t frameIndex = options.fFrameIndex; + fReader->parse((SkGifImageReader::SkGIFParseQuery) frameIndex); + + const bool firstCallToIncrementalDecode = fFirstCallToIncrementalDecode; + fFirstCallToIncrementalDecode = false; + return this->decodeFrame(firstCallToIncrementalDecode, options, rowsDecoded); } -SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColorCount) { - return this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, opts); -} +SkCodec::Result SkGifCodec::decodeFrame(bool firstAttempt, const Options& opts, int* rowsDecoded) { + const SkImageInfo& dstInfo = this->dstInfo(); + const size_t frameIndex = opts.fFrameIndex; + SkASSERT(frameIndex < fReader->imagesCount()); + const SkGIFFrameContext* frameContext = fReader->frameContext(frameIndex); + if (firstAttempt) { + // rowsDecoded reports how many rows have been initialized, so a layer above + // can fill the rest. In some cases, we fill the background before decoding + // (or it is already filled for us), so we report rowsDecoded to be the full + // height. + bool filledBackground = false; + if (frameContext->getRequiredFrame() == kNone) { + // We may need to clear to transparent for one of the following reasons: + // - The frameRect does not cover the full bounds. haveDecodedRow will + // only draw inside the frameRect, so we need to clear the rest. + // - The frame is interlaced. There is no obvious way to fill + // afterwards for an incomplete image. (FIXME: Does the first pass + // cover all rows? If so, we do not have to fill here.) + // - There is no color table for this frame. In that case will not + // draw anything, so we need to fill. + if (frameContext->frameRect() != this->getInfo().bounds() + || frameContext->interlaced() || !fCurrColorTableIsReal) { + // fill ignores the width (replaces it with the actual, scaled width). + // But we need to scale in Y. + const int scaledHeight = get_scaled_dimension(dstInfo.height(), + fSwizzler->sampleY()); + auto fillInfo = dstInfo.makeWH(0, scaledHeight); + fSwizzler->fill(fillInfo, fDst, fDstRowBytes, this->getFillValue(dstInfo), + opts.fZeroInitialized); + filledBackground = true; + } + } else { + // Not independent + if (!opts.fHasPriorFrame) { + // Decode that frame into pixels. + Options prevFrameOpts(opts); + prevFrameOpts.fFrameIndex = frameContext->getRequiredFrame(); + prevFrameOpts.fHasPriorFrame = false; + // The prior frame may have a different color table, so update it and the + // swizzler. + this->initializeColorTable(dstInfo, prevFrameOpts.fFrameIndex); + this->initializeSwizzler(dstInfo, prevFrameOpts.fFrameIndex); -void SkGifCodec::handleScanlineFrame(int count, int* rowsBeforeFrame, int* rowsInFrame) { - if (fFrameIsSubset) { - const int currRow = this->currScanline(); + const Result prevResult = this->decodeFrame(true, prevFrameOpts, nullptr); + switch (prevResult) { + case kSuccess: + // Prior frame succeeded. Carry on. + break; + case kIncompleteInput: + // Prior frame was incomplete. So this frame cannot be decoded. + return kInvalidInput; + default: + return prevResult; + } - // The number of rows that remain to be skipped before reaching rows that we - // actually must decode into. - // This must be at least zero. We also make sure that it is less than or - // equal to count, since we will skip at most count rows. - *rowsBeforeFrame = SkTMin(count, SkTMax(0, fFrameRect.top() - currRow)); - - // Rows left to decode once we reach the start of the frame. - const int rowsLeft = count - *rowsBeforeFrame; - - // Count the number of that extend beyond the bottom of the frame. We do not - // need to decode into these rows. - const int rowsAfterFrame = SkTMax(0, currRow + rowsLeft - fFrameRect.bottom()); - - // Set the actual number of source rows that we need to decode. - *rowsInFrame = rowsLeft - rowsAfterFrame; - } else { - *rowsBeforeFrame = 0; - *rowsInFrame = count; - } -} - -int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { - int rowsBeforeFrame; - int rowsInFrame; - this->handleScanlineFrame(count, &rowsBeforeFrame, &rowsInFrame); - - if (fFrameIsSubset) { - // Fill the requested rows - SkImageInfo fillInfo = this->dstInfo().makeWH(this->dstInfo().width(), count); - uint64_t fillValue = this->onGetFillValue(this->dstInfo()); - fSwizzler->fill(fillInfo, dst, rowBytes, fillValue, this->options().fZeroInitialized); - - // Start to write pixels at the start of the image frame - dst = SkTAddOffset(dst, rowBytes * rowsBeforeFrame); - } - - for (int i = 0; i < rowsInFrame; i++) { - if (!this->readRow()) { - return i + rowsBeforeFrame; + // Go back to using the correct color table for this frame. + this->initializeColorTable(dstInfo, frameIndex); + this->initializeSwizzler(dstInfo, frameIndex); + } + const auto* prevFrame = fReader->frameContext(frameContext->getRequiredFrame()); + if (prevFrame->getDisposalMethod() == SkCodecAnimation::RestoreBGColor_DisposalMethod) { + SkIRect prevRect = prevFrame->frameRect(); + if (prevRect.intersect(this->getInfo().bounds())) { + // Do the divide ourselves for left and top, since we do not want + // get_scaled_dimension to upgrade 0 to 1. (This is similar to SkSampledCodec's + // sampling of the subset.) + auto left = prevRect.fLeft / fSwizzler->sampleX(); + auto top = prevRect.fTop / fSwizzler->sampleY(); + void* const eraseDst = SkTAddOffset(fDst, top * fDstRowBytes + + left * SkColorTypeBytesPerPixel(dstInfo.colorType())); + auto width = get_scaled_dimension(prevRect.width(), fSwizzler->sampleX()); + auto height = get_scaled_dimension(prevRect.height(), fSwizzler->sampleY()); + // fSwizzler->fill() would fill to the scaled width of the frame, but we want to + // fill to the scaled with of the width of the PRIOR frame, so we do all the + // scaling ourselves and call the static version. + SkSampler::Fill(dstInfo.makeWH(width, height), eraseDst, + fDstRowBytes, this->getFillValue(dstInfo), kNo_ZeroInitialized); + } + } + filledBackground = true; + } + + fFilledBackground = filledBackground; + if (filledBackground) { + // Report the full (scaled) height, since the client will never need to fill. + fRowsDecoded = get_scaled_dimension(dstInfo.height(), fSwizzler->sampleY()); + } else { + // This will be updated by haveDecodedRow. + fRowsDecoded = 0; } - fSwizzler->swizzle(dst, fSrcBuffer.get()); - dst = SkTAddOffset(dst, rowBytes); } - return count; + if (!fCurrColorTableIsReal) { + // Nothing to draw this frame. + return kSuccess; + } + + // Note: there is a difference between the following call to SkGifImageReader::decode + // returning false and leaving frameDecoded false: + // - If the method returns false, there was an error in the stream. We still treat this as + // incomplete, since we have already decoded some rows. + // - If frameDecoded is false, that just means that we do not have enough data. If more data + // is supplied, we may be able to continue decoding this frame. We also treat this as + // incomplete. + // FIXME: Ensure that we do not attempt to continue decoding if the method returns false and + // more data is supplied. + bool frameDecoded = false; + if (!fReader->decode(frameIndex, &frameDecoded) || !frameDecoded) { + if (rowsDecoded) { + *rowsDecoded = fRowsDecoded; + } + return kIncompleteInput; + } + + return kSuccess; } -bool SkGifCodec::onSkipScanlines(int count) { - int rowsBeforeFrame; - int rowsInFrame; - this->handleScanlineFrame(count, &rowsBeforeFrame, &rowsInFrame); +uint64_t SkGifCodec::onGetFillValue(const SkImageInfo& dstInfo) const { + // Note: Using fCurrColorTable relies on having called initializeColorTable already. + // This is (currently) safe because this method is only called when filling, after + // initializeColorTable has been called. + // FIXME: Is there a way to make this less fragile? + if (dstInfo.colorType() == kIndex_8_SkColorType && fCurrColorTableIsReal) { + // We only support index 8 for the first frame, for backwards + // compatibity on Android, so we are using the color table for the first frame. + SkASSERT(this->options().fFrameIndex == 0); + // Use the transparent index for the first frame. + const size_t transPixel = fReader->frameContext(0)->transparentPixel(); + if (transPixel < (size_t) fCurrColorTable->count()) { + return transPixel; + } + // Fall through to return SK_ColorTRANSPARENT (i.e. 0). This choice is arbitrary, + // but we have to pick something inside the color table, and this one is as good + // as any. + } + // Using transparent as the fill value matches the behavior in Chromium, + // which ignores the background color. + // If the colorType is kIndex_8, and there was no color table (i.e. + // fCurrColorTableIsReal is false), this value (zero) corresponds to the + // only entry in the dummy color table provided to the client. + return SK_ColorTRANSPARENT; +} - for (int i = 0; i < rowsInFrame; i++) { - if (!this->readRow()) { - return false; +void SkGifCodec::applyXformRow(const SkImageInfo& dstInfo, void* dst, const uint8_t* src) const { + if (this->colorXform() && fXformOnDecode) { + fSwizzler->swizzle(fXformBuffer.get(), src); + + const SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType()); + const SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(kXformSrcColorType); + const SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), + this->getInfo().alphaType()); + const int xformWidth = get_scaled_dimension(dstInfo.width(), fSwizzler->sampleX()); + SkAssertResult(this->colorXform()->apply(dstFormat, dst, srcFormat, fXformBuffer.get(), + xformWidth, xformAlphaType)); + } else { + fSwizzler->swizzle(dst, src); + } +} + +bool SkGifCodec::haveDecodedRow(size_t frameIndex, const unsigned char* rowBegin, + size_t rowNumber, unsigned repeatCount, bool writeTransparentPixels) +{ + const SkGIFFrameContext* frameContext = fReader->frameContext(frameIndex); + // The pixel data and coordinates supplied to us are relative to the frame's + // origin within the entire image size, i.e. + // (frameContext->xOffset, frameContext->yOffset). There is no guarantee + // that width == (size().width() - frameContext->xOffset), so + // we must ensure we don't run off the end of either the source data or the + // row's X-coordinates. + const size_t width = frameContext->width(); + const int xBegin = frameContext->xOffset(); + const int yBegin = frameContext->yOffset() + rowNumber; + const int xEnd = std::min(static_cast(frameContext->xOffset() + width), + this->getInfo().width()); + const int yEnd = std::min(static_cast(frameContext->yOffset() + rowNumber + repeatCount), + this->getInfo().height()); + // FIXME: No need to make the checks on width/xBegin/xEnd for every row. We could instead do + // this once in prepareToDecode. + if (!width || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= yBegin)) + return true; + + // yBegin is the first row in the non-sampled image. dstRow will be the row in the output, + // after potentially scaling it. + int dstRow = yBegin; + + const int sampleY = fSwizzler->sampleY(); + if (sampleY > 1) { + // Check to see whether this row or one that falls in the repeatCount is needed in the + // output. + bool foundNecessaryRow = false; + for (unsigned i = 0; i < repeatCount; i++) { + const int potentialRow = yBegin + i; + if (fSwizzler->rowNeeded(potentialRow)) { + dstRow = potentialRow / sampleY; + const int scaledHeight = get_scaled_dimension(this->dstInfo().height(), sampleY); + if (dstRow >= scaledHeight) { + return true; + } + + foundNecessaryRow = true; + repeatCount -= i; + + repeatCount = (repeatCount - 1) / sampleY + 1; + + // Make sure the repeatCount does not take us beyond the end of the dst + if (dstRow + (int) repeatCount > scaledHeight) { + repeatCount = scaledHeight - dstRow; + SkASSERT(repeatCount >= 1); + } + break; + } + } + + if (!foundNecessaryRow) { + return true; + } + } else { + // Make sure the repeatCount does not take us beyond the end of the dst + SkASSERT(this->dstInfo().height() >= yBegin); + repeatCount = SkTMin(repeatCount, (unsigned) (this->dstInfo().height() - yBegin)); + } + + if (!fFilledBackground) { + // At this point, we are definitely going to write the row, so count it towards the number + // of rows decoded. + // We do not consider the repeatCount, which only happens for interlaced, in which case we + // have already set fRowsDecoded to the proper value (reflecting that we have filled the + // background). + fRowsDecoded++; + } + + // decodeFrame will early exit if this is false, so this method will not be + // called. + SkASSERT(fCurrColorTableIsReal); + + // The swizzler takes care of offsetting into the dst width-wise. + void* dstLine = SkTAddOffset(fDst, dstRow * fDstRowBytes); + + // We may or may not need to write transparent pixels to the buffer. + // If we're compositing against a previous image, it's wrong, but if + // we're decoding an interlaced gif and displaying it "Haeberli"-style, + // we must write these for passes beyond the first, or the initial passes + // will "show through" the later ones. + const auto dstInfo = this->dstInfo(); + if (writeTransparentPixels) { + this->applyXformRow(dstInfo, dstLine, rowBegin); + } else { + sk_bzero(fTmpBuffer.get(), dstInfo.minRowBytes()); + this->applyXformRow(dstInfo, fTmpBuffer.get(), rowBegin); + + const size_t offsetBytes = fSwizzler->swizzleOffsetBytes(); + switch (dstInfo.colorType()) { + case kBGRA_8888_SkColorType: + case kRGBA_8888_SkColorType: { + uint32_t* dstPixel = SkTAddOffset(dstLine, offsetBytes); + uint32_t* srcPixel = SkTAddOffset(fTmpBuffer.get(), offsetBytes); + for (int i = 0; i < fSwizzler->swizzleWidth(); i++) { + // Technically SK_ColorTRANSPARENT is an SkPMColor, and srcPixel would have + // the opposite swizzle for the non-native swizzle, but TRANSPARENT is all + // zeroes, which is the same either way. + if (*srcPixel != SK_ColorTRANSPARENT) { + *dstPixel = *srcPixel; + } + dstPixel++; + srcPixel++; + } + break; + } + case kRGBA_F16_SkColorType: { + uint64_t* dstPixel = SkTAddOffset(dstLine, offsetBytes); + uint64_t* srcPixel = SkTAddOffset(fTmpBuffer.get(), offsetBytes); + for (int i = 0; i < fSwizzler->swizzleWidth(); i++) { + if (*srcPixel != 0) { + *dstPixel = *srcPixel; + } + dstPixel++; + srcPixel++; + } + break; + } + default: + SkASSERT(false); + break; + } + } + + // Tell the frame to copy the row data if need be. + if (repeatCount > 1) { + const size_t bytesPerPixel = SkColorTypeBytesPerPixel(this->dstInfo().colorType()); + const size_t bytesToCopy = fSwizzler->swizzleWidth() * bytesPerPixel; + void* copiedLine = SkTAddOffset(dstLine, fSwizzler->swizzleOffsetBytes()); + void* dst = copiedLine; + for (unsigned i = 1; i < repeatCount; i++) { + dst = SkTAddOffset(dst, fDstRowBytes); + memcpy(dst, copiedLine, bytesToCopy); } } return true; } - -SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { - if (fGif->Image.Interlace) { - return kOutOfOrder_SkScanlineOrder; - } - return kTopDown_SkScanlineOrder; -} - -int SkGifCodec::onOutputScanline(int inputScanline) const { - if (fGif->Image.Interlace) { - if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bottom()) { - return inputScanline; - } - return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFrameRect.height()) + - fFrameRect.top(); - } - return inputScanline; -} diff --git a/gfx/skia/skia/src/codec/SkGifCodec.h b/gfx/skia/skia/src/codec/SkGifCodec.h index c56d3719a9e0..11714eb39edc 100644 --- a/gfx/skia/skia/src/codec/SkGifCodec.h +++ b/gfx/skia/skia/src/codec/SkGifCodec.h @@ -4,15 +4,17 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#ifndef SkGifCodec_DEFINED +#define SkGifCodec_DEFINED #include "SkCodec.h" +#include "SkCodecAnimation.h" #include "SkColorSpace.h" #include "SkColorTable.h" #include "SkImageInfo.h" #include "SkSwizzler.h" -struct GifFileType; -struct SavedImage; +#include "SkGifImageReader.h" /* * @@ -30,93 +32,46 @@ public: */ static SkCodec* NewFromStream(SkStream*); + // Callback for SkGifImageReader when a row is available. + bool haveDecodedRow(size_t frameIndex, const unsigned char* rowBegin, + size_t rowNumber, unsigned repeatCount, bool writeTransparentPixels); protected: - - /* - * Read enough of the stream to initialize the SkGifCodec. - * Returns a bool representing success or failure. - * - * @param codecOut - * If it returned true, and codecOut was not nullptr, - * codecOut will be set to a new SkGifCodec. - * - * @param gifOut - * If it returned true, and codecOut was nullptr, - * gifOut must be non-nullptr and gifOut will be set to a new - * GifFileType pointer. - * - * @param stream - * Deleted on failure. - * codecOut will take ownership of it in the case where we created a codec. - * Ownership is unchanged when we returned a gifOut. - * - */ - static bool ReadHeader(SkStream* stream, SkCodec** codecOut, - GifFileType** gifOut); - /* * Performs the full gif decode */ Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor*, int*, int*) override; - SkEncodedFormat onGetEncodedFormat() const override { - return kGIF_SkEncodedFormat; + SkEncodedImageFormat onGetEncodedFormat() const override { + return SkEncodedImageFormat::kGIF; } bool onRewind() override; uint64_t onGetFillValue(const SkImageInfo&) const override; - int onOutputScanline(int inputScanline) const override; + size_t onGetFrameCount() override; + bool onGetFrameInfo(size_t, FrameInfo*) const override; + int onGetRepetitionCount() override; + + Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t, + const SkCodec::Options&, SkPMColor*, int*) override; + + Result onIncrementalDecode(int*) override; private: - /* - * A gif can contain multiple image frames. We will only decode the first - * frame. This function reads up to the first image frame, processing - * transparency and/or animation information that comes before the image - * data. - * - * @param gif Pointer to the library type that manages the gif decode - * @param transIndex This call will set the transparent index based on the - * extension data. - */ - static Result ReadUpToFirstImage(GifFileType* gif, uint32_t* transIndex); - - /* - * A gif may contain many image frames, all of different sizes. - * This function checks if the gif dimensions are valid, based on the frame - * dimensions, and corrects the gif dimensions if necessary. - * - * @param gif Pointer to the library type that manages the gif decode - * @param size Size of the image that we will decode. - * Will be set by this function if the return value is true. - * @param frameRect Contains the dimenions and offset of the first image frame. - * Will be set by this function if the return value is true. - * - * @return true on success, false otherwise - */ - static bool GetDimensions(GifFileType* gif, SkISize* size, SkIRect* frameRect); - /* * Initializes the color table that we will use for decoding. * * @param dstInfo Contains the requested dst color type. - * @param inputColorPtr Copies the encoded color table to the client's - * input color table if the client requests kIndex8. - * @param inputColorCount If the client requests kIndex8, sets - * inputColorCount to 256. Since gifs always - * contain 8-bit indices, we need a 256 entry color - * table to ensure that indexing is always in - * bounds. + * @param frameIndex Frame whose color table to use. */ - void initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* colorPtr, - int* inputColorCount); + void initializeColorTable(const SkImageInfo& dstInfo, size_t frameIndex); /* - * Checks for invalid inputs and calls setFrameDimensions(), and - * initializeColorTable() in the proper sequence. + * Does necessary setup, including setting up the color table and swizzler, + * and reports color info to the client. */ Result prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, int* inputColorCount, const Options& opts); @@ -124,82 +79,80 @@ private: /* * Initializes the swizzler. * - * @param dstInfo Output image information. Dimensions may have been - * adjusted if the image frame size does not match the size - * indicated in the header. - * @param options Informs the swizzler if destination memory is zero initialized. - * Contains subset information. + * @param dstInfo Output image information. Dimensions may have been + * adjusted if the image frame size does not match the size + * indicated in the header. + * @param frameIndex Which frame we are decoding. This determines the frameRect + * to use. */ - void initializeSwizzler(const SkImageInfo& dstInfo, - const Options& options); + void initializeSwizzler(const SkImageInfo& dstInfo, size_t frameIndex); SkSampler* getSampler(bool createIfNecessary) override { SkASSERT(fSwizzler); - return fSwizzler; + return fSwizzler.get(); } /* - * @return true if the read is successful and false if the read fails. - */ - bool readRow(); - - Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opts, - SkPMColor inputColorPtr[], int* inputColorCount) override; - - int onGetScanlines(void* dst, int count, size_t rowBytes) override; - - bool onSkipScanlines(int count) override; - - /* - * For a scanline decode of "count" lines, this function indicates how - * many of the "count" lines should be skipped until we reach the top of - * the image frame and how many of the "count" lines are actually inside - * the image frame. + * Recursive function to decode a frame. * - * @param count The number of scanlines requested. - * @param rowsBeforeFrame Output variable. The number of lines before - * we reach the top of the image frame. - * @param rowsInFrame Output variable. The number of lines to decode - * inside the image frame. + * @param firstAttempt Whether this is the first call to decodeFrame since + * starting. e.g. true in onGetPixels, and true in the + * first call to onIncrementalDecode after calling + * onStartIncrementalDecode. + * When true, this method may have to initialize the + * frame, for example by filling or decoding the prior + * frame. + * @param opts Options for decoding. May be different from + * this->options() for decoding prior frames. Specifies + * the frame to decode and whether the prior frame has + * already been decoded to fDst. If not, and the frame + * is not independent, this method will recursively + * decode the frame it depends on. + * @param rowsDecoded Out-parameter to report the total number of rows + * that have been decoded (or at least written to, if + * it had to fill), including rows decoded by prior + * calls to onIncrementalDecode. + * @return kSuccess if the frame is complete, kIncompleteInput + * otherwise. */ - void handleScanlineFrame(int count, int* rowsBeforeFrame, int* rowsInFrame); - - SkScanlineOrder onGetScanlineOrder() const override; + Result decodeFrame(bool firstAttempt, const Options& opts, int* rowsDecoded); /* - * This function cleans up the gif object after the decode completes - * It is used in a SkAutoTCallIProc template + * Swizzles and color xforms (if necessary) into dst. */ - static void CloseGif(GifFileType* gif); - - /* - * Frees any extension data used in the decode - * Used in a SkAutoTCallVProc - */ - static void FreeExtension(SavedImage* image); + void applyXformRow(const SkImageInfo& dstInfo, void* dst, const uint8_t* src) const; /* * Creates an instance of the decoder * Called only by NewFromStream - * - * @param info contains properties of the encoded data - * @param stream the stream of image data - * @param gif pointer to library type that manages gif decode - * takes ownership - * @param transIndex The transparent index. An invalid value - * indicates that there is no transparent index. + * Takes ownership of the SkGifImageReader */ - SkGifCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, - GifFileType* gif, uint32_t transIndex, const SkIRect& frameRect, bool frameIsSubset); + SkGifCodec(const SkEncodedInfo&, const SkImageInfo&, SkGifImageReader*); - SkAutoTCallVProc fGif; // owned - SkAutoTDeleteArray fSrcBuffer; - const SkIRect fFrameRect; - const uint32_t fTransIndex; - uint32_t fFillIndex; - const bool fFrameIsSubset; - SkAutoTDelete fSwizzler; - SkAutoTUnref fColorTable; + std::unique_ptr fReader; + std::unique_ptr fTmpBuffer; + std::unique_ptr fSwizzler; + sk_sp fCurrColorTable; + // We may create a dummy table if there is not a Map in the input data. In + // that case, we set this value to false, and we can skip a lot of decoding + // work (which would not be meaningful anyway). We create a "fake"/"dummy" + // one in that case, so the client and the swizzler have something to draw. + bool fCurrColorTableIsReal; + // Whether the background was filled. + bool fFilledBackground; + // True on the first call to onIncrementalDecode. This value is passed to + // decodeFrame. + bool fFirstCallToIncrementalDecode; + + void* fDst; + size_t fDstRowBytes; + + // Updated inside haveDecodedRow when rows are decoded, unless we filled + // the background, in which case it is set once and left alone. + int fRowsDecoded; + std::unique_ptr fXformBuffer; + bool fXformOnDecode; typedef SkCodec INHERITED; }; +#endif // SkGifCodec_DEFINED diff --git a/gfx/skia/skia/src/codec/SkIcoCodec.cpp b/gfx/skia/skia/src/codec/SkIcoCodec.cpp index 63b72c40391a..b5e399d87881 100644 --- a/gfx/skia/skia/src/codec/SkIcoCodec.cpp +++ b/gfx/skia/skia/src/codec/SkIcoCodec.cpp @@ -33,14 +33,14 @@ bool SkIcoCodec::IsIco(const void* buffer, size_t bytesRead) { */ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { // Ensure that we do not leak the input stream - SkAutoTDelete inputStream(stream); + std::unique_ptr inputStream(stream); // Header size constants static const uint32_t kIcoDirectoryBytes = 6; static const uint32_t kIcoDirEntryBytes = 16; // Read the directory header - SkAutoTDeleteArray dirBuffer(new uint8_t[kIcoDirectoryBytes]); + std::unique_ptr dirBuffer(new uint8_t[kIcoDirectoryBytes]); if (inputStream.get()->read(dirBuffer.get(), kIcoDirectoryBytes) != kIcoDirectoryBytes) { SkCodecPrintf("Error: unable to read ico directory header.\n"); @@ -55,7 +55,7 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { } // Ensure that we can read all of indicated directory entries - SkAutoTDeleteArray entryBuffer(new uint8_t[numImages * kIcoDirEntryBytes]); + std::unique_ptr entryBuffer(new uint8_t[numImages * kIcoDirEntryBytes]); if (inputStream.get()->read(entryBuffer.get(), numImages*kIcoDirEntryBytes) != numImages*kIcoDirEntryBytes) { SkCodecPrintf("Error: unable to read ico directory entries.\n"); @@ -69,7 +69,7 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { uint32_t offset; uint32_t size; }; - SkAutoTDeleteArray directoryEntries(new Entry[numImages]); + std::unique_ptr directoryEntries(new Entry[numImages]); // Iterate over directory entries for (uint32_t i = 0; i < numImages; i++) { @@ -107,8 +107,8 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { // Now will construct a candidate codec for each of the embedded images uint32_t bytesRead = kIcoDirectoryBytes + numImages * kIcoDirEntryBytes; - SkAutoTDelete, true>> codecs( - new (SkTArray, true>)(numImages)); + std::unique_ptr, true>> codecs( + new (SkTArray, true>)(numImages)); for (uint32_t i = 0; i < numImages; i++) { uint32_t offset = directoryEntries.get()[i].offset; uint32_t size = directoryEntries.get()[i].size; @@ -133,7 +133,7 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { SkCodecPrintf("Warning: could not create embedded stream.\n"); break; } - SkAutoTDelete embeddedStream(new SkMemoryStream(data)); + std::unique_ptr embeddedStream(new SkMemoryStream(data)); bytesRead += size; // Check if the embedded codec is bmp or png and create the codec @@ -157,11 +157,12 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { } // Use the largest codec as a "suggestion" for image info - uint32_t maxSize = 0; - uint32_t maxIndex = 0; - for (int32_t i = 0; i < codecs->count(); i++) { + size_t maxSize = 0; + int maxIndex = 0; + for (int i = 0; i < codecs->count(); i++) { SkImageInfo info = codecs->operator[](i)->getInfo(); - uint32_t size = info.width() * info.height(); + size_t size = info.getSafeSize(info.minRowBytes()); + if (size > maxSize) { maxSize = size; maxIndex = i; @@ -170,10 +171,11 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { int width = codecs->operator[](maxIndex)->getInfo().width(); int height = codecs->operator[](maxIndex)->getInfo().height(); SkEncodedInfo info = codecs->operator[](maxIndex)->getEncodedInfo(); + SkColorSpace* colorSpace = codecs->operator[](maxIndex)->getInfo().colorSpace(); // Note that stream is owned by the embedded codec, the ico does not need // direct access to the stream. - return new SkIcoCodec(width, height, info, codecs.release()); + return new SkIcoCodec(width, height, info, codecs.release(), sk_ref_sp(colorSpace)); } /* @@ -181,8 +183,9 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { * Called only by NewFromStream */ SkIcoCodec::SkIcoCodec(int width, int height, const SkEncodedInfo& info, - SkTArray, true>* codecs) - : INHERITED(width, height, info, nullptr) + SkTArray, true>* codecs, + sk_sp colorSpace) + : INHERITED(width, height, info, nullptr, std::move(colorSpace)) , fEmbeddedCodecs(codecs) , fCurrScanlineCodec(nullptr) , fCurrIncrementalCodec(nullptr) @@ -252,10 +255,8 @@ SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, break; } - SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); - result = embeddedCodec->getPixels(dstInfo, dst, dstRowBytes, &opts, colorTable, - colorCount); - + SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get(); + result = embeddedCodec->getPixels(dstInfo, dst, dstRowBytes, &opts, colorTable, colorCount); switch (result) { case kSuccess: case kIncompleteInput: @@ -285,7 +286,7 @@ SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, break; } - SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); + SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get(); result = embeddedCodec->startScanlineDecode(dstInfo, &options, colorTable, colorCount); if (kSuccess == result) { fCurrScanlineCodec = embeddedCodec; @@ -320,7 +321,7 @@ SkCodec::Result SkIcoCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, break; } - SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); + SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get(); switch (embeddedCodec->startIncrementalDecode(dstInfo, pixels, rowBytes, &options, colorTable, colorCount)) { case kSuccess: diff --git a/gfx/skia/skia/src/codec/SkIcoCodec.h b/gfx/skia/skia/src/codec/SkIcoCodec.h index a227d8c67100..2a4efb50b02d 100644 --- a/gfx/skia/skia/src/codec/SkIcoCodec.h +++ b/gfx/skia/skia/src/codec/SkIcoCodec.h @@ -4,10 +4,13 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#ifndef SkIcoCodec_DEFINED +#define SkIcoCodec_DEFINED #include "SkCodec.h" #include "SkImageInfo.h" #include "SkStream.h" +#include "SkTArray.h" #include "SkTypes.h" /* @@ -39,8 +42,8 @@ protected: Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, SkPMColor*, int*, int*) override; - SkEncodedFormat onGetEncodedFormat() const override { - return kICO_SkEncodedFormat; + SkEncodedImageFormat onGetEncodedFormat() const override { + return SkEncodedImageFormat::kICO; } SkScanlineOrder onGetScanlineOrder() const override; @@ -77,16 +80,16 @@ private: * @param embeddedCodecs codecs for the embedded images, takes ownership */ SkIcoCodec(int width, int height, const SkEncodedInfo& info, - SkTArray, true>* embeddedCodecs); + SkTArray, true>* embeddedCodecs, sk_sp colorSpace); - SkAutoTDelete, true>> fEmbeddedCodecs; // owned + std::unique_ptr, true>> fEmbeddedCodecs; // Only used by the scanline decoder. onStartScanlineDecode() will set // fCurrScanlineCodec to one of the fEmbeddedCodecs, if it can find a // codec of the appropriate size. We will use fCurrScanlineCodec for // subsequent calls to onGetScanlines() or onSkipScanlines(). // fCurrScanlineCodec is owned by this class, but should not be an - // SkAutoTDelete. It will be deleted by the destructor of fEmbeddedCodecs. + // std::unique_ptr. It will be deleted by the destructor of fEmbeddedCodecs. SkCodec* fCurrScanlineCodec; // Only used by incremental decoder. onStartIncrementalDecode() will set @@ -94,8 +97,9 @@ private: // codec of the appropriate size. We will use fCurrIncrementalCodec for // subsequent calls to incrementalDecode(). // fCurrIncrementalCodec is owned by this class, but should not be an - // SkAutoTDelete. It will be deleted by the destructor of fEmbeddedCodecs. + // std::unique_ptr. It will be deleted by the destructor of fEmbeddedCodecs. SkCodec* fCurrIncrementalCodec; typedef SkCodec INHERITED; }; +#endif // SkIcoCodec_DEFINED diff --git a/gfx/skia/skia/src/codec/SkJpegCodec.cpp b/gfx/skia/skia/src/codec/SkJpegCodec.cpp index f6c856ee1d7a..5593fc9707a4 100644 --- a/gfx/skia/skia/src/codec/SkJpegCodec.cpp +++ b/gfx/skia/skia/src/codec/SkJpegCodec.cpp @@ -6,11 +6,11 @@ */ #include "SkCodec.h" -#include "SkMSAN.h" #include "SkJpegCodec.h" #include "SkJpegDecoderMgr.h" #include "SkCodecPriv.h" #include "SkColorPriv.h" +#include "SkColorSpace_Base.h" #include "SkStream.h" #include "SkTemplates.h" #include "SkTypes.h" @@ -43,9 +43,7 @@ static uint32_t get_endian_int(const uint8_t* data, bool littleEndian) { } const uint32_t kExifHeaderSize = 14; -const uint32_t kICCHeaderSize = 14; const uint32_t kExifMarker = JPEG_APP0 + 1; -const uint32_t kICCMarker = JPEG_APP0 + 2; static bool is_orientation_marker(jpeg_marker_struct* marker, SkCodec::Origin* orientation) { if (kExifMarker != marker->marker || marker->data_length < kExifHeaderSize) { @@ -111,11 +109,10 @@ static SkCodec::Origin get_exif_orientation(jpeg_decompress_struct* dinfo) { } static bool is_icc_marker(jpeg_marker_struct* marker) { - if (kICCMarker != marker->marker || marker->data_length < kICCHeaderSize) { + if (kICCMarker != marker->marker || marker->data_length < kICCMarkerHeaderSize) { return false; } - static const uint8_t kICCSig[] { 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0' }; return !memcmp(marker->data, kICCSig, sizeof(kICCSig)); } @@ -159,8 +156,8 @@ static sk_sp get_icc_profile(jpeg_decompress_struct* dinfo) { return nullptr; } markerSequence[markerIndex] = marker; - SkASSERT(marker->data_length >= kICCHeaderSize); - totalBytes += marker->data_length - kICCHeaderSize; + SkASSERT(marker->data_length >= kICCMarkerHeaderSize); + totalBytes += marker->data_length - kICCMarkerHeaderSize; } } @@ -179,8 +176,8 @@ static sk_sp get_icc_profile(jpeg_decompress_struct* dinfo) { return nullptr; } - void* src = SkTAddOffset(marker->data, kICCHeaderSize); - size_t bytes = marker->data_length - kICCHeaderSize; + void* src = SkTAddOffset(marker->data, kICCMarkerHeaderSize); + size_t bytes = marker->data_length - kICCMarkerHeaderSize; memcpy(dst, src, bytes); dst = SkTAddOffset(dst, bytes); } @@ -188,11 +185,11 @@ static sk_sp get_icc_profile(jpeg_decompress_struct* dinfo) { return iccData; } -bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, - JpegDecoderMgr** decoderMgrOut) { +bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, JpegDecoderMgr** decoderMgrOut, + sk_sp defaultColorSpace) { // Create a JpegDecoderMgr to own all of the decompress information - SkAutoTDelete decoderMgr(new JpegDecoderMgr(stream)); + std::unique_ptr decoderMgr(new JpegDecoderMgr(stream)); // libjpeg errors will be caught and reported here if (setjmp(decoderMgr->getJmpBuf())) { @@ -228,21 +225,37 @@ bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, Origin orientation = get_exif_orientation(decoderMgr->dinfo()); sk_sp iccData = get_icc_profile(decoderMgr->dinfo()); sk_sp colorSpace = nullptr; + bool unsupportedICC = false; if (iccData) { - colorSpace = SkColorSpace::NewICC(iccData->data(), iccData->size()); + SkColorSpace_Base::ICCTypeFlag iccType = SkColorSpace_Base::kRGB_ICCTypeFlag; + switch (decoderMgr->dinfo()->jpeg_color_space) { + case JCS_CMYK: + case JCS_YCCK: + iccType = SkColorSpace_Base::kCMYK_ICCTypeFlag; + break; + case JCS_GRAYSCALE: + // Note the "or equals". We will accept gray or rgb profiles for gray images. + iccType |= SkColorSpace_Base::kGray_ICCTypeFlag; + break; + default: + break; + } + colorSpace = SkColorSpace_Base::MakeICC(iccData->data(), iccData->size(), iccType); if (!colorSpace) { SkCodecPrintf("Could not create SkColorSpace from ICC data.\n"); + unsupportedICC = true; } } if (!colorSpace) { - // Treat unmarked jpegs as sRGB. - colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); + colorSpace = defaultColorSpace; } const int width = decoderMgr->dinfo()->image_width; const int height = decoderMgr->dinfo()->image_height; - *codecOut = new SkJpegCodec(width, height, info, stream, decoderMgr.release(), - std::move(colorSpace), orientation, std::move(iccData)); + SkJpegCodec* codec = new SkJpegCodec(width, height, info, stream, decoderMgr.release(), + std::move(colorSpace), orientation); + codec->setUnsupportedICC(unsupportedICC); + *codecOut = codec; } else { SkASSERT(nullptr != decoderMgrOut); *decoderMgrOut = decoderMgr.release(); @@ -251,9 +264,13 @@ bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, } SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) { - SkAutoTDelete streamDeleter(stream); + return SkJpegCodec::NewFromStream(stream, SkColorSpace::MakeSRGB()); +} + +SkCodec* SkJpegCodec::NewFromStream(SkStream* stream, sk_sp defaultColorSpace) { + std::unique_ptr streamDeleter(stream); SkCodec* codec = nullptr; - if (ReadHeader(stream, &codec, nullptr)) { + if (ReadHeader(stream, &codec, nullptr, std::move(defaultColorSpace))) { // Codec has taken ownership of the stream, we do not need to delete it SkASSERT(codec); streamDeleter.release(); @@ -263,15 +280,13 @@ SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) { } SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, - JpegDecoderMgr* decoderMgr, sk_sp colorSpace, Origin origin, - sk_sp iccData) + JpegDecoderMgr* decoderMgr, sk_sp colorSpace, Origin origin) : INHERITED(width, height, info, stream, std::move(colorSpace), origin) , fDecoderMgr(decoderMgr) , fReadyState(decoderMgr->dinfo()->global_state) , fSwizzleSrcRow(nullptr) , fColorXformSrcRow(nullptr) , fSwizzlerSubset(SkIRect::MakeEmpty()) - , fICCData(std::move(iccData)) {} /* @@ -337,7 +352,7 @@ SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const { bool SkJpegCodec::onRewind() { JpegDecoderMgr* decoderMgr = nullptr; - if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) { + if (!ReadHeader(this->stream(), nullptr, &decoderMgr, nullptr)) { return fDecoderMgr->returnFalse("onRewind"); } SkASSERT(nullptr != decoderMgr); @@ -347,7 +362,6 @@ bool SkJpegCodec::onRewind() { fSwizzleSrcRow = nullptr; fColorXformSrcRow = nullptr; fStorage.reset(); - fColorXform.reset(nullptr); return true; } @@ -384,35 +398,34 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) { case kBGRA_8888_SkColorType: if (isCMYK) { fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; - } else if (fColorXform) { - // Our color transformation code requires RGBA order inputs, but it'll swizzle - // to BGRA for us. + } else if (this->colorXform()) { + // Always using RGBA as the input format for color xforms makes the + // implementation a little simpler. fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; } else { fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA; } return true; case kRGB_565_SkColorType: - if (fColorXform) { - return false; - } - if (isCMYK) { fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; + } else if (this->colorXform()) { + fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; } else { fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; } return true; case kGray_8_SkColorType: - if (fColorXform || JCS_GRAYSCALE != encodedColorType) { + if (this->colorXform() || JCS_GRAYSCALE != encodedColorType) { return false; } fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE; return true; case kRGBA_F16_SkColorType: - SkASSERT(fColorXform); + SkASSERT(this->colorXform()); + if (!dstInfo.colorSpace()->gammaIsLinear()) { return false; } @@ -469,7 +482,8 @@ bool SkJpegCodec::onDimensionsSupported(const SkISize& size) { return true; } -int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count) { +int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count, + const Options& opts) { // Set the jump location for libjpeg-turbo errors if (setjmp(fDecoderMgr->getJmpBuf())) { return 0; @@ -481,12 +495,12 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes // subsetting. // When fColorXformSrcRow is non-null, it means that we need to color xform and that // we cannot color xform "in place" (many times we can, but not when the dst is F16). - // In this case, we will color xform from fColorXformSrc into the dst. + // In this case, we will color xform from fColorXformSrcRow into the dst. JSAMPLE* decodeDst = (JSAMPLE*) dst; uint32_t* swizzleDst = (uint32_t*) dst; size_t decodeDstRowBytes = rowBytes; size_t swizzleDstRowBytes = rowBytes; - int dstWidth = dstInfo.width(); + int dstWidth = opts.fSubset ? opts.fSubset->width() : dstInfo.width(); if (fSwizzleSrcRow && fColorXformSrcRow) { decodeDst = (JSAMPLE*) fSwizzleSrcRow; swizzleDst = fColorXformSrcRow; @@ -506,8 +520,6 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes for (int y = 0; y < count; y++) { uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1); - size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo()); - sk_msan_mark_initialized(decodeDst, decodeDst + srcRowBytes, "skbug.com/4550"); if (0 == lines) { return y; } @@ -516,9 +528,10 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes fSwizzler->swizzle(swizzleDst, decodeDst); } - if (fColorXform) { - fColorXform->apply(dst, swizzleDst, dstWidth, select_xform_format(dstInfo.colorType()), - SkColorSpaceXform::kRGBA_8888_ColorFormat, kOpaque_SkAlphaType); + if (this->colorXform()) { + SkAssertResult(this->colorXform()->apply(select_xform_format(dstInfo.colorType()), dst, + SkColorSpaceXform::kRGBA_8888_ColorFormat, swizzleDst, dstWidth, + kOpaque_SkAlphaType)); dst = SkTAddOffset(dst, rowBytes); } @@ -529,6 +542,22 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes return count; } +/* + * This is a bit tricky. We only need the swizzler to do format conversion if the jpeg is + * encoded as CMYK. + * And even then we still may not need it. If the jpeg has a CMYK color space and a color + * xform, the color xform will handle the CMYK->RGB conversion. + */ +static inline bool needs_swizzler_to_convert_from_cmyk(J_COLOR_SPACE jpegColorType, + const SkImageInfo& srcInfo, bool hasColorSpaceXform) { + if (JCS_CMYK != jpegColorType) { + return false; + } + + bool hasCMYKColorSpace = as_CSB(srcInfo.colorSpace())->onIsCMYK(); + return !hasCMYKColorSpace || !hasColorSpaceXform; +} + /* * Performs the jpeg decode */ @@ -549,7 +578,9 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, return fDecoderMgr->returnFailure("setjmp", kInvalidInput); } - this->initializeColorXform(dstInfo); + if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) { + return kInvalidConversion; + } // Check if we can decode to the requested destination and set the output color space if (!this->setOutputColorSpace(dstInfo)) { @@ -564,14 +595,14 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, // If it's not, we want to know because it means our strategy is not optimal. SkASSERT(1 == dinfo->rec_outbuf_height); - J_COLOR_SPACE colorSpace = dinfo->out_color_space; - if (JCS_CMYK == colorSpace) { - this->initializeSwizzler(dstInfo, options); + if (needs_swizzler_to_convert_from_cmyk(dinfo->out_color_space, this->getInfo(), + this->colorXform())) { + this->initializeSwizzler(dstInfo, options, true); } this->allocateStorage(dstInfo); - int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height()); + int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height(), options); if (rows < dstInfo.height()) { *rowsDecoded = rows; return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput); @@ -587,12 +618,12 @@ void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) { if (fSwizzler) { swizzleBytes = get_row_bytes(fDecoderMgr->dinfo()); dstWidth = fSwizzler->swizzleWidth(); - SkASSERT(!fColorXform || SkIsAlign4(swizzleBytes)); + SkASSERT(!this->colorXform() || SkIsAlign4(swizzleBytes)); } size_t xformBytes = 0; - if (kRGBA_F16_SkColorType == dstInfo.colorType()) { - SkASSERT(fColorXform); + if (this->colorXform() && (kRGBA_F16_SkColorType == dstInfo.colorType() || + kRGB_565_SkColorType == dstInfo.colorType())) { xformBytes = dstWidth * sizeof(uint32_t); } @@ -605,13 +636,10 @@ void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) { } } -void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { - // libjpeg-turbo may have already performed color conversion. We must indicate the - // appropriate format to the swizzler. +void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options, + bool needsCMYKToRGB) { SkEncodedInfo swizzlerInfo = this->getEncodedInfo(); - bool preSwizzled = true; - if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { - preSwizzled = false; + if (needsCMYKToRGB) { swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color, swizzlerInfo.alpha(), swizzlerInfo.bitsPerComponent()); @@ -626,27 +654,29 @@ void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& fSwizzlerSubset.width() == options.fSubset->width()); swizzlerOptions.fSubset = &fSwizzlerSubset; } - fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, dstInfo, swizzlerOptions, - nullptr, preSwizzled)); - SkASSERT(fSwizzler); -} -void SkJpegCodec::initializeColorXform(const SkImageInfo& dstInfo) { - if (needs_color_xform(dstInfo, this->getInfo())) { - fColorXform = SkColorSpaceXform::New(this->getInfo().colorSpace(), dstInfo.colorSpace()); - SkASSERT(fColorXform); + SkImageInfo swizzlerDstInfo = dstInfo; + if (this->colorXform()) { + // The color xform will be expecting RGBA 8888 input. + swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType); } + + fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, swizzlerDstInfo, + swizzlerOptions, nullptr, !needsCMYKToRGB)); + SkASSERT(fSwizzler); } SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { if (!createIfNecessary || fSwizzler) { SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow)); - return fSwizzler; + return fSwizzler.get(); } - this->initializeSwizzler(this->dstInfo(), this->options()); + bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk( + fDecoderMgr->dinfo()->out_color_space, this->getInfo(), this->colorXform()); + this->initializeSwizzler(this->dstInfo(), this->options(), needsCMYKToRGB); this->allocateStorage(this->dstInfo()); - return fSwizzler; + return fSwizzler.get(); } SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, @@ -657,7 +687,9 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, return kInvalidInput; } - this->initializeColorXform(dstInfo); + if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) { + return kInvalidConversion; + } // Check if we can decode to the requested destination and set the output color space if (!this->setOutputColorSpace(dstInfo)) { @@ -669,6 +701,8 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, return kInvalidInput; } + bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk( + fDecoderMgr->dinfo()->out_color_space, this->getInfo(), this->colorXform()); if (options.fSubset) { uint32_t startX = options.fSubset->x(); uint32_t width = options.fSubset->width(); @@ -702,13 +736,13 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, // subset that we request. if (startX != (uint32_t) options.fSubset->x() || width != (uint32_t) options.fSubset->width()) { - this->initializeSwizzler(dstInfo, options); + this->initializeSwizzler(dstInfo, options, needsCMYKToRGB); } } // Make sure we have a swizzler if we are converting from CMYK. - if (!fSwizzler && JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { - this->initializeSwizzler(dstInfo, options); + if (!fSwizzler && needsCMYKToRGB) { + this->initializeSwizzler(dstInfo, options, true); } this->allocateStorage(dstInfo); @@ -717,7 +751,7 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, } int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { - int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count); + int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count, this->options()); if (rows < count) { // This allows us to skip calling jpeg_finish_decompress(). fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); diff --git a/gfx/skia/skia/src/codec/SkJpegCodec.h b/gfx/skia/skia/src/codec/SkJpegCodec.h index 30425eea3f80..0c2f4a1257a9 100644 --- a/gfx/skia/skia/src/codec/SkJpegCodec.h +++ b/gfx/skia/skia/src/codec/SkJpegCodec.h @@ -51,18 +51,21 @@ protected: Result onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override; - SkEncodedFormat onGetEncodedFormat() const override { - return kJPEG_SkEncodedFormat; + SkEncodedImageFormat onGetEncodedFormat() const override { + return SkEncodedImageFormat::kJPEG; } bool onRewind() override; bool onDimensionsSupported(const SkISize&) override; - sk_sp getICCData() const override { return fICCData; } - private: + /* + * Allows SkRawCodec to communicate the color space from the exif data. + */ + static SkCodec* NewFromStream(SkStream*, sk_sp defaultColorSpace); + /* * Read enough of the stream to initialize the SkJpegCodec. * Returns a bool representing success or failure. @@ -81,9 +84,12 @@ private: * codecOut will take ownership of it in the case where we created a codec. * Ownership is unchanged when we set decoderMgrOut. * + * @param defaultColorSpace + * If the jpeg does not have an embedded color space, the image data should + * be tagged with this color space. */ static bool ReadHeader(SkStream* stream, SkCodec** codecOut, - JpegDecoderMgr** decoderMgrOut); + JpegDecoderMgr** decoderMgrOut, sk_sp defaultColorSpace); /* * Creates an instance of the decoder @@ -95,8 +101,7 @@ private: * takes ownership */ SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, - JpegDecoderMgr* decoderMgr, sk_sp colorSpace, Origin origin, - sk_sp iccData); + JpegDecoderMgr* decoderMgr, sk_sp colorSpace, Origin origin); /* * Checks if the conversion between the input image and the requested output @@ -106,10 +111,10 @@ private: */ bool setOutputColorSpace(const SkImageInfo& dst); - void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options); - void initializeColorXform(const SkImageInfo& dstInfo); + void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options, + bool needsCMYKToRGB); void allocateStorage(const SkImageInfo& dstInfo); - int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count); + int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count, const Options&); /* * Scanline decoding. @@ -120,7 +125,7 @@ private: int onGetScanlines(void* dst, int count, size_t rowBytes) override; bool onSkipScanlines(int count) override; - SkAutoTDelete fDecoderMgr; + std::unique_ptr fDecoderMgr; // We will save the state of the decompress struct after reading the header. // This allows us to safely call onGetScaledDimensions() at any time. @@ -136,10 +141,9 @@ private: // to further subset the output from libjpeg-turbo. SkIRect fSwizzlerSubset; - SkAutoTDelete fSwizzler; - std::unique_ptr fColorXform; + std::unique_ptr fSwizzler; - sk_sp fICCData; + friend class SkRawCodec; typedef SkCodec INHERITED; }; diff --git a/gfx/skia/skia/src/codec/SkJpegDecoderMgr.cpp b/gfx/skia/skia/src/codec/SkJpegDecoderMgr.cpp index 70401c039117..c2837aa2b4af 100644 --- a/gfx/skia/skia/src/codec/SkJpegDecoderMgr.cpp +++ b/gfx/skia/skia/src/codec/SkJpegDecoderMgr.cpp @@ -25,6 +25,17 @@ static void output_message(j_common_ptr info) { print_message(info, "output_message"); } +static void progress_monitor(j_common_ptr info) { + int scan = ((j_decompress_ptr)info)->input_scan_number; + // Progressive images with a very large number of scans can cause the + // decoder to hang. Here we use the progress monitor to abort on + // a very large number of scans. 100 is arbitrary, but much larger + // than the number of scans we might expect in a normal image. + if (scan >= 100) { + skjpeg_err_exit(info); + } +} + bool JpegDecoderMgr::returnFalse(const char caller[]) { print_message((j_common_ptr) &fDInfo, caller); return false; @@ -71,6 +82,8 @@ void JpegDecoderMgr::init() { fInit = true; fDInfo.src = &fSrcMgr; fDInfo.err->output_message = &output_message; + fDInfo.progress = &fProgressMgr; + fProgressMgr.progress_monitor = &progress_monitor; } JpegDecoderMgr::~JpegDecoderMgr() { diff --git a/gfx/skia/skia/src/codec/SkJpegDecoderMgr.h b/gfx/skia/skia/src/codec/SkJpegDecoderMgr.h index 7bc422d4ff0b..272c5b4b1ce7 100644 --- a/gfx/skia/skia/src/codec/SkJpegDecoderMgr.h +++ b/gfx/skia/skia/src/codec/SkJpegDecoderMgr.h @@ -68,6 +68,7 @@ private: jpeg_decompress_struct fDInfo; skjpeg_source_mgr fSrcMgr; skjpeg_error_mgr fErrorMgr; + jpeg_progress_mgr fProgressMgr; bool fInit; }; diff --git a/gfx/skia/skia/src/codec/SkJpegPriv.h b/gfx/skia/skia/src/codec/SkJpegPriv.h new file mode 100644 index 000000000000..e4e5b1276397 --- /dev/null +++ b/gfx/skia/skia/src/codec/SkJpegPriv.h @@ -0,0 +1,36 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkJpegPriv_DEFINED +#define SkJpegPriv_DEFINED + +#include "SkStream.h" + +#include +// stdio is needed for jpeglib +#include + +extern "C" { + #include "jpeglib.h" + #include "jerror.h" +} + +static constexpr uint32_t kICCMarker = JPEG_APP0 + 2; +static constexpr uint32_t kICCMarkerHeaderSize = 14; +static constexpr uint8_t kICCSig[] = { + 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0', +}; + +/* + * Error handling struct + */ +struct skjpeg_error_mgr : jpeg_error_mgr { + jmp_buf fJmpBuf; +}; + +#endif diff --git a/gfx/skia/skia/src/codec/SkJpegUtility.h b/gfx/skia/skia/src/codec/SkJpegUtility.h index 43391017b53c..33f4fbda8bc6 100644 --- a/gfx/skia/skia/src/codec/SkJpegUtility.h +++ b/gfx/skia/skia/src/codec/SkJpegUtility.h @@ -9,6 +9,7 @@ #ifndef SkJpegUtility_codec_DEFINED #define SkJpegUtility_codec_DEFINED +#include "SkJpegPriv.h" #include "SkStream.h" #include @@ -20,13 +21,6 @@ extern "C" { #include "jerror.h" } -/* - * Error handling struct - */ -struct skjpeg_error_mgr : jpeg_error_mgr { - jmp_buf fJmpBuf; -}; - /* * Error handling function */ diff --git a/gfx/skia/skia/src/codec/SkMaskSwizzler.h b/gfx/skia/skia/src/codec/SkMaskSwizzler.h index 3bf8d1758f34..5d2955caabde 100644 --- a/gfx/skia/skia/src/codec/SkMaskSwizzler.h +++ b/gfx/skia/skia/src/codec/SkMaskSwizzler.h @@ -45,6 +45,13 @@ public: SkSampler::Fill(fillInfo, dst, rowBytes, colorOrIndex, zeroInit); } + /** + * Returns the byte offset at which we write to destination memory, taking + * scaling, subsetting, and partial frames into account. + * A similar function exists on SkSwizzler. + */ + int swizzleWidth() const { return fDstWidth; } + private: /* diff --git a/gfx/skia/skia/src/codec/SkPngCodec.cpp b/gfx/skia/skia/src/codec/SkPngCodec.cpp index 30fffe11636b..8bab368cdf62 100644 --- a/gfx/skia/skia/src/codec/SkPngCodec.cpp +++ b/gfx/skia/skia/src/codec/SkPngCodec.cpp @@ -8,7 +8,8 @@ #include "SkBitmap.h" #include "SkCodecPriv.h" #include "SkColorPriv.h" -#include "SkColorSpace_Base.h" +#include "SkColorSpace.h" +#include "SkColorSpacePriv.h" #include "SkColorTable.h" #include "SkMath.h" #include "SkOpts.h" @@ -212,6 +213,8 @@ void SkPngCodec::processData() { } } +static const SkColorType kXformSrcColorType = kRGBA_8888_SkColorType; + // Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here. bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) { @@ -224,14 +227,14 @@ bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) // Contents depend on tableColorType and our choice of if/when to premultiply: // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA } SkPMColor colorTable[256]; - SkColorType tableColorType = fColorXform ? kRGBA_8888_SkColorType : dstInfo.colorType(); + SkColorType tableColorType = this->colorXform() ? kXformSrcColorType : dstInfo.colorType(); png_bytep alphas; int numColorsWithAlpha = 0; if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) { // If we are performing a color xform, it will handle the premultiply. Otherwise, // we'll do it here. - bool premultiply = !fColorXform && needs_premul(dstInfo, this->getInfo()); + bool premultiply = !this->colorXform() && needs_premul(dstInfo, this->getEncodedInfo()); // Choose which function to use to create the color table. If the final destination's // colortype is unpremultiplied, the color table will store unpremultiplied colors. @@ -264,16 +267,15 @@ bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) } } - // If we are not decoding to F16, we can color xform now and store the results - // in the color table. - if (fColorXform && kRGBA_F16_SkColorType != dstInfo.colorType()) { - SkColorSpaceXform::ColorFormat xformColorFormat = is_rgba(dstInfo.colorType()) ? - SkColorSpaceXform::kRGBA_8888_ColorFormat : - SkColorSpaceXform::kBGRA_8888_ColorFormat; - SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), - this->getInfo().alphaType()); - fColorXform->apply(colorTable, colorTable, numColors, xformColorFormat, - SkColorSpaceXform::kRGBA_8888_ColorFormat, xformAlphaType); + if (this->colorXform() && + !apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color())) { + const SkColorSpaceXform::ColorFormat dstFormat = + select_xform_format_ct(dstInfo.colorType()); + const SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(kXformSrcColorType); + const SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), + this->getInfo().alphaType()); + SkAssertResult(this->colorXform()->apply(dstFormat, colorTable, srcFormat, colorTable, + numColors, xformAlphaType)); } // Pad the color table with the last color in the table (or black) in the case that @@ -316,75 +318,13 @@ static float png_inverted_fixed_point_to_float(png_fixed_point x) { return 1.0f / png_fixed_point_to_float(x); } -static constexpr float gSRGB_toXYZD50[] { - 0.4358f, 0.3853f, 0.1430f, // Rx, Gx, Bx - 0.2224f, 0.7170f, 0.0606f, // Ry, Gy, Gz - 0.0139f, 0.0971f, 0.7139f, // Rz, Gz, Bz -}; - -static bool convert_to_D50(SkMatrix44* toXYZD50, float toXYZ[9], float whitePoint[2]) { - float wX = whitePoint[0]; - float wY = whitePoint[1]; - if (wX < 0.0f || wY < 0.0f || (wX + wY > 1.0f)) { - return false; - } - - // Calculate the XYZ illuminant. Call this the src illuminant. - float wZ = 1.0f - wX - wY; - float scale = 1.0f / wY; - // TODO (msarett): - // What are common src illuminants? I'm guessing we will almost always see D65. Should - // we go ahead and save a precomputed D65->D50 Bradford matrix? Should we exit early if - // if the src illuminant is D50? - SkVector3 srcXYZ = SkVector3::Make(wX * scale, 1.0f, wZ * scale); - - // The D50 illuminant. - SkVector3 dstXYZ = SkVector3::Make(0.96422f, 1.0f, 0.82521f); - - // Calculate the chromatic adaptation matrix. We will use the Bradford method, thus - // the matrices below. The Bradford method is used by Adobe and is widely considered - // to be the best. - // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html - SkMatrix mA, mAInv; - mA.setAll(0.8951f, 0.2664f, -0.1614f, -0.7502f, 1.7135f, 0.0367f, 0.0389f, -0.0685f, 1.0296f); - mAInv.setAll(0.9869929f, -0.1470543f, 0.1599627f, 0.4323053f, 0.5183603f, 0.0492912f, - -0.0085287f, 0.0400428f, 0.9684867f); - - // Map illuminant into cone response domain. - SkVector3 srcCone; - srcCone.fX = mA[0] * srcXYZ.fX + mA[1] * srcXYZ.fY + mA[2] * srcXYZ.fZ; - srcCone.fY = mA[3] * srcXYZ.fX + mA[4] * srcXYZ.fY + mA[5] * srcXYZ.fZ; - srcCone.fZ = mA[6] * srcXYZ.fX + mA[7] * srcXYZ.fY + mA[8] * srcXYZ.fZ; - SkVector3 dstCone; - dstCone.fX = mA[0] * dstXYZ.fX + mA[1] * dstXYZ.fY + mA[2] * dstXYZ.fZ; - dstCone.fY = mA[3] * dstXYZ.fX + mA[4] * dstXYZ.fY + mA[5] * dstXYZ.fZ; - dstCone.fZ = mA[6] * dstXYZ.fX + mA[7] * dstXYZ.fY + mA[8] * dstXYZ.fZ; - - SkMatrix DXToD50; - DXToD50.setIdentity(); - DXToD50[0] = dstCone.fX / srcCone.fX; - DXToD50[4] = dstCone.fY / srcCone.fY; - DXToD50[8] = dstCone.fZ / srcCone.fZ; - DXToD50.postConcat(mAInv); - DXToD50.preConcat(mA); - - SkMatrix toXYZ3x3; - toXYZ3x3.setAll(toXYZ[0], toXYZ[3], toXYZ[6], toXYZ[1], toXYZ[4], toXYZ[7], toXYZ[2], toXYZ[5], - toXYZ[8]); - toXYZ3x3.postConcat(DXToD50); - - toXYZD50->set3x3(toXYZ3x3[0], toXYZ3x3[3], toXYZ3x3[6], - toXYZ3x3[1], toXYZ3x3[4], toXYZ3x3[7], - toXYZ3x3[2], toXYZ3x3[5], toXYZ3x3[8]); - return true; -} - #endif // LIBPNG >= 1.6 // Returns a colorSpace object that represents any color space information in -// the encoded data. If the encoded data contains no color space, this will -// return NULL. -sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr) { +// the encoded data. If the encoded data contains an invalid/unsupported color space, +// this will return NULL. If there is no color space information, it will guess sRGB +sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr, + SkColorSpace_Base::ICCTypeFlag iccType) { #if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6) @@ -401,7 +341,7 @@ sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr) { int compression; if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile, &length)) { - return SkColorSpace::NewICC(profile, length); + return SkColorSpace_Base::MakeICC(profile, length, iccType); } // Second, check for sRGB. @@ -412,68 +352,63 @@ sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr) { // FIXME (msarett): Extract this information from the sRGB chunk once // we are able to handle this information in // SkColorSpace. - return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); + return SkColorSpace::MakeSRGB(); } // Next, check for chromaticities. - png_fixed_point toXYZFixed[9]; - float toXYZ[9]; - png_fixed_point whitePointFixed[2]; - float whitePoint[2]; + png_fixed_point chrm[8]; png_fixed_point gamma; - float gammas[3]; - if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &toXYZFixed[0], &toXYZFixed[1], &toXYZFixed[2], - &toXYZFixed[3], &toXYZFixed[4], &toXYZFixed[5], &toXYZFixed[6], - &toXYZFixed[7], &toXYZFixed[8]) && - png_get_cHRM_fixed(png_ptr, info_ptr, &whitePointFixed[0], &whitePointFixed[1], nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr)) + if (png_get_cHRM_fixed(png_ptr, info_ptr, &chrm[0], &chrm[1], &chrm[2], &chrm[3], &chrm[4], + &chrm[5], &chrm[6], &chrm[7])) { - for (int i = 0; i < 9; i++) { - toXYZ[i] = png_fixed_point_to_float(toXYZFixed[i]); - } - whitePoint[0] = png_fixed_point_to_float(whitePointFixed[0]); - whitePoint[1] = png_fixed_point_to_float(whitePointFixed[1]); + SkColorSpacePrimaries primaries; + primaries.fRX = png_fixed_point_to_float(chrm[2]); + primaries.fRY = png_fixed_point_to_float(chrm[3]); + primaries.fGX = png_fixed_point_to_float(chrm[4]); + primaries.fGY = png_fixed_point_to_float(chrm[5]); + primaries.fBX = png_fixed_point_to_float(chrm[6]); + primaries.fBY = png_fixed_point_to_float(chrm[7]); + primaries.fWX = png_fixed_point_to_float(chrm[0]); + primaries.fWY = png_fixed_point_to_float(chrm[1]); SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); - if (!convert_to_D50(&toXYZD50, toXYZ, whitePoint)) { + if (!primaries.toXYZD50(&toXYZD50)) { toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50); } if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { - float value = png_inverted_fixed_point_to_float(gamma); - gammas[0] = value; - gammas[1] = value; - gammas[2] = value; + SkColorSpaceTransferFn fn; + fn.fA = 1.0f; + fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f; + fn.fG = png_inverted_fixed_point_to_float(gamma); - return SkColorSpace_Base::NewRGB(gammas, toXYZD50); + return SkColorSpace::MakeRGB(fn, toXYZD50); } // Default to sRGB gamma if the image has color space information, // but does not specify gamma. - return SkColorSpace::NewRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50); + return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50); } // Last, check for gamma. if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { - - // Set the gammas. - float value = png_inverted_fixed_point_to_float(gamma); - gammas[0] = value; - gammas[1] = value; - gammas[2] = value; + SkColorSpaceTransferFn fn; + fn.fA = 1.0f; + fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f; + fn.fG = png_inverted_fixed_point_to_float(gamma); // Since there is no cHRM, we will guess sRGB gamut. SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50); - return SkColorSpace_Base::NewRGB(gammas, toXYZD50); + return SkColorSpace::MakeRGB(fn, toXYZD50); } #endif // LIBPNG >= 1.6 - // Report that there is no color space information in the PNG. SkPngCodec is currently - // implemented to guess sRGB in this case. - return nullptr; + // Report that there is no color space information in the PNG. + // Guess sRGB in this case. + return SkColorSpace::MakeSRGB(); } void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) { @@ -485,28 +420,47 @@ void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) { // be created later if we are sampling. We'll go ahead and allocate // enough memory to swizzle if necessary. case kSwizzleColor_XformMode: { - const size_t colorXformBytes = dstInfo.width() * sizeof(uint32_t); + const int bitsPerPixel = this->getEncodedInfo().bitsPerPixel(); + + // If we have more than 8-bits (per component) of precision, we will keep that + // extra precision. Otherwise, we will swizzle to RGBA_8888 before transforming. + const size_t bytesPerPixel = (bitsPerPixel > 32) ? bitsPerPixel / 8 : 4; + const size_t colorXformBytes = dstInfo.width() * bytesPerPixel; fStorage.reset(colorXformBytes); - fColorXformSrcRow = (uint32_t*) fStorage.get(); + fColorXformSrcRow = fStorage.get(); break; } } } +static SkColorSpaceXform::ColorFormat png_select_xform_format(const SkEncodedInfo& info) { + // We use kRGB and kRGBA formats because color PNGs are always RGB or RGBA. + if (16 == info.bitsPerComponent()) { + if (SkEncodedInfo::kRGBA_Color == info.color()) { + return SkColorSpaceXform::kRGBA_U16_BE_ColorFormat; + } else if (SkEncodedInfo::kRGB_Color == info.color()) { + return SkColorSpaceXform::kRGB_U16_BE_ColorFormat; + } + } + + return SkColorSpaceXform::kRGBA_8888_ColorFormat; +} + void SkPngCodec::applyXformRow(void* dst, const void* src) { - const SkColorSpaceXform::ColorFormat srcColorFormat = SkColorSpaceXform::kRGBA_8888_ColorFormat; + const SkColorSpaceXform::ColorFormat srcColorFormat = + png_select_xform_format(this->getEncodedInfo()); switch (fXformMode) { case kSwizzleOnly_XformMode: fSwizzler->swizzle(dst, (const uint8_t*) src); break; case kColorOnly_XformMode: - fColorXform->apply(dst, (const uint32_t*) src, fXformWidth, fXformColorFormat, - srcColorFormat, fXformAlphaType); + SkAssertResult(this->colorXform()->apply(fXformColorFormat, dst, srcColorFormat, src, + fXformWidth, fXformAlphaType)); break; case kSwizzleColor_XformMode: fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src); - fColorXform->apply(dst, fColorXformSrcRow, fXformWidth, fXformColorFormat, - srcColorFormat, fXformAlphaType); + SkAssertResult(this->colorXform()->apply(fXformColorFormat, dst, srcColorFormat, + fColorXformSrcRow, fXformWidth, fXformAlphaType)); break; } } @@ -516,7 +470,7 @@ public: SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo, SkStream* stream, SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth) : INHERITED(info, imageInfo, stream, reader, png_ptr, info_ptr, bitDepth) - , fLinesDecoded(0) + , fRowsWrittenToOutput(0) , fDst(nullptr) , fRowBytes(0) , fFirstRow(0) @@ -538,13 +492,14 @@ public: #endif private: - int fLinesDecoded; // FIXME: Move to baseclass? + int fRowsWrittenToOutput; void* fDst; size_t fRowBytes; // Variables for partial decode int fFirstRow; // FIXME: Move to baseclass? int fLastRow; + int fRowsNeeded; typedef SkPngCodec INHERITED; @@ -562,24 +517,26 @@ private: fDst = dst; fRowBytes = rowBytes; - fLinesDecoded = 0; + fRowsWrittenToOutput = 0; + fFirstRow = 0; + fLastRow = height - 1; this->processData(); - if (fLinesDecoded == height) { + if (fRowsWrittenToOutput == height) { return SkCodec::kSuccess; } if (rowsDecoded) { - *rowsDecoded = fLinesDecoded; + *rowsDecoded = fRowsWrittenToOutput; } return SkCodec::kIncompleteInput; } void allRowsCallback(png_bytep row, int rowNum) { - SkASSERT(rowNum - fFirstRow == fLinesDecoded); - fLinesDecoded++; + SkASSERT(rowNum == fRowsWrittenToOutput); + fRowsWrittenToOutput++; this->applyXformRow(fDst, row); fDst = SkTAddOffset(fDst, fRowBytes); } @@ -594,18 +551,23 @@ private: fLastRow = lastRow; fDst = dst; fRowBytes = rowBytes; - fLinesDecoded = 0; + fRowsWrittenToOutput = 0; + fRowsNeeded = fLastRow - fFirstRow + 1; } SkCodec::Result decode(int* rowsDecoded) override { + if (this->swizzler()) { + const int sampleY = this->swizzler()->sampleY(); + fRowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY); + } this->processData(); - if (fLinesDecoded == fLastRow - fFirstRow + 1) { + if (fRowsWrittenToOutput == fRowsNeeded) { return SkCodec::kSuccess; } if (rowsDecoded) { - *rowsDecoded = fLinesDecoded; + *rowsDecoded = fRowsWrittenToOutput; } return SkCodec::kIncompleteInput; @@ -618,16 +580,16 @@ private: } SkASSERT(rowNum <= fLastRow); + SkASSERT(fRowsWrittenToOutput < fRowsNeeded); // If there is no swizzler, all rows are needed. - if (!this->swizzler() || this->swizzler()->rowNeeded(fLinesDecoded)) { + if (!this->swizzler() || this->swizzler()->rowNeeded(rowNum - fFirstRow)) { this->applyXformRow(fDst, row); fDst = SkTAddOffset(fDst, fRowBytes); + fRowsWrittenToOutput++; } - fLinesDecoded++; - - if (rowNum == fLastRow) { + if (fRowsWrittenToOutput == fRowsNeeded) { // Fake error to stop decoding scanlines. longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding); } @@ -764,17 +726,25 @@ private: // Now apply Xforms on all the rows that were decoded. if (!fLinesDecoded) { + if (rowsDecoded) { + *rowsDecoded = 0; + } return SkCodec::kIncompleteInput; } - const int lastRow = fLinesDecoded + fFirstRow - 1; - SkASSERT(lastRow <= fLastRow); + + const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1; + const int rowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY); + int rowsWrittenToOutput = 0; // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it // may be too tricky/expensive to handle that correctly. - png_bytep srcRow = fInterlaceBuffer.get(); - const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1; + + // Offset srcRow by get_start_coord rows. We do not need to account for fFirstRow, + // since the first row in fInterlaceBuffer corresponds to fFirstRow. + png_bytep srcRow = SkTAddOffset(fInterlaceBuffer.get(), + fPng_rowbytes * get_start_coord(sampleY)); void* dst = fDst; - for (int rowNum = fFirstRow; rowNum <= lastRow; rowNum += sampleY) { + for (; rowsWrittenToOutput < rowsNeeded; rowsWrittenToOutput++) { this->applyXformRow(dst, srcRow); dst = SkTAddOffset(dst, fRowBytes); srcRow = SkTAddOffset(srcRow, fPng_rowbytes * sampleY); @@ -785,7 +755,7 @@ private: } if (rowsDecoded) { - *rowsDecoded = fLinesDecoded; + *rowsDecoded = rowsWrittenToOutput; } return SkCodec::kIncompleteInput; } @@ -919,17 +889,17 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec // FIXME (scroggo): Once SK_GOOGLE3_PNG_HACK is no more, this method can be inline in // AutoCleanPng::infoCallback static void general_info_callback(png_structp png_ptr, png_infop info_ptr, - SkEncodedInfo::Color* outColor, SkEncodedInfo::Alpha* outAlpha) { + SkEncodedInfo::Color* outColor, SkEncodedInfo::Alpha* outAlpha, + int* outBitDepth) { png_uint_32 origWidth, origHeight; int bitDepth, encodedColorType; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, &encodedColorType, nullptr, nullptr, nullptr); - // Tell libpng to strip 16 bit/color files down to 8 bits/color. - // TODO: Should we handle this in SkSwizzler? Could this also benefit - // RAW decodes? - if (bitDepth == 16) { - SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType); + // TODO: Should we support 16-bits of precision for gray images? + if (bitDepth == 16 && (PNG_COLOR_TYPE_GRAY == encodedColorType || + PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType)) { + bitDepth = 8; png_set_strip_16(png_ptr); } @@ -944,6 +914,7 @@ static void general_info_callback(png_structp png_ptr, png_infop info_ptr, // byte into separate bytes (useful for paletted and grayscale images). if (bitDepth < 8) { // TODO: Should we use SkSwizzler here? + bitDepth = 8; png_set_packing(png_ptr); } @@ -967,6 +938,7 @@ static void general_info_callback(png_structp png_ptr, png_infop info_ptr, // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. if (bitDepth < 8) { // TODO: Should we use SkSwizzler here? + bitDepth = 8; png_set_expand_gray_1_2_4_to_8(png_ptr); } @@ -999,11 +971,14 @@ static void general_info_callback(png_structp png_ptr, png_infop info_ptr, if (outAlpha) { *outAlpha = alpha; } + if (outBitDepth) { + *outBitDepth = bitDepth; + } } #ifdef SK_GOOGLE3_PNG_HACK void SkPngCodec::rereadInfoCallback() { - general_info_callback(fPng_ptr, fInfo_ptr, nullptr, nullptr); + general_info_callback(fPng_ptr, fInfo_ptr, nullptr, nullptr, nullptr); png_set_interlace_handling(fPng_ptr); png_read_update_info(fPng_ptr, fInfo_ptr); } @@ -1012,7 +987,8 @@ void SkPngCodec::rereadInfoCallback() { void AutoCleanPng::infoCallback() { SkEncodedInfo::Color color; SkEncodedInfo::Alpha alpha; - general_info_callback(fPng_ptr, fInfo_ptr, &color, &alpha); + int bitDepth; + general_info_callback(fPng_ptr, fInfo_ptr, &color, &alpha, &bitDepth); const int numberPasses = png_set_interlace_handling(fPng_ptr); @@ -1028,13 +1004,18 @@ void AutoCleanPng::infoCallback() { #endif if (fOutCodec) { SkASSERT(nullptr == *fOutCodec); - sk_sp colorSpace = read_color_space(fPng_ptr, fInfo_ptr); + SkColorSpace_Base::ICCTypeFlag iccType = SkColorSpace_Base::kRGB_ICCTypeFlag; + if (SkEncodedInfo::kGray_Color == color || SkEncodedInfo::kGrayAlpha_Color == color) { + iccType |= SkColorSpace_Base::kGray_ICCTypeFlag; + } + sk_sp colorSpace = read_color_space(fPng_ptr, fInfo_ptr, iccType); + const bool unsupportedICC = !colorSpace; if (!colorSpace) { - // Treat unmarked pngs as sRGB. - colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); + // Treat unsupported/invalid color spaces as sRGB. + colorSpace = SkColorSpace::MakeSRGB(); } - SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, 8); + SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, bitDepth); // FIXME (scroggo): Once we get rid of SK_GOOGLE3_PNG_HACK, general_info_callback can // be inlined, so these values will already be set. png_uint_32 origWidth = png_get_image_width(fPng_ptr, fInfo_ptr); @@ -1059,6 +1040,7 @@ void AutoCleanPng::infoCallback() { *fOutCodec = new SkPngInterlacedDecoder(encodedInfo, imageInfo, fStream, fChunkReader, fPng_ptr, fInfo_ptr, bitDepth, numberPasses); } + (*fOutCodec)->setUnsupportedICC(unsupportedICC); } @@ -1107,22 +1089,31 @@ bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt } png_read_update_info(fPng_ptr, fInfo_ptr); - // Reset fSwizzler and fColorXform. We can't do this in onRewind() because the + // Reset fSwizzler and this->colorXform(). We can't do this in onRewind() because the // interlaced scanline decoder may need to rewind. fSwizzler.reset(nullptr); - fColorXform = nullptr; - if (needs_color_xform(dstInfo, this->getInfo())) { - fColorXform = SkColorSpaceXform::New(this->getInfo().colorSpace(), dstInfo.colorSpace()); - SkASSERT(fColorXform); + if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) { + return false; } - // If the image is RGBA and we have a color xform, we can skip the swizzler. - // FIXME (msarett): - // Support more input types to fColorXform (ex: RGB, Gray) and skip the swizzler more often. - if (fColorXform && SkEncodedInfo::kRGBA_Color == this->getEncodedInfo().color() && - !options.fSubset) - { + // If SkColorSpaceXform directly supports the encoded PNG format, we should skip format + // conversion in the swizzler (or skip swizzling altogether). + bool skipFormatConversion = false; + switch (this->getEncodedInfo().color()) { + case SkEncodedInfo::kRGB_Color: + if (this->getEncodedInfo().bitsPerComponent() != 16) { + break; + } + + // Fall through + case SkEncodedInfo::kRGBA_Color: + skipFormatConversion = this->colorXform(); + break; + default: + break; + } + if (skipFormatConversion && !options.fSubset) { fXformMode = kColorOnly_XformMode; return true; } @@ -1134,9 +1125,9 @@ bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt } // Copy the color table to the client if they request kIndex8 mode. - copy_color_table(dstInfo, fColorTable, ctable, ctableCount); + copy_color_table(dstInfo, fColorTable.get(), ctable, ctableCount); - this->initializeSwizzler(dstInfo, options); + this->initializeSwizzler(dstInfo, options, skipFormatConversion); return true; } @@ -1159,17 +1150,15 @@ void SkPngCodec::initializeXformParams() { } } -static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) { - // We will apply the color xform when reading the color table, unless F16 is requested. - return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType; -} - -void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { +void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options, + bool skipFormatConversion) { SkImageInfo swizzlerInfo = dstInfo; Options swizzlerOptions = options; fXformMode = kSwizzleOnly_XformMode; - if (fColorXform && apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color())) { - swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType); + if (this->colorXform() && + apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color())) + { + swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType); if (kPremul_SkAlphaType == dstInfo.alphaType()) { swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); } @@ -1184,17 +1173,17 @@ void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& o const SkPMColor* colors = get_color_ptr(fColorTable.get()); fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, swizzlerInfo, - swizzlerOptions)); + swizzlerOptions, nullptr, skipFormatConversion)); SkASSERT(fSwizzler); } SkSampler* SkPngCodec::getSampler(bool createIfNecessary) { if (fSwizzler || !createIfNecessary) { - return fSwizzler; + return fSwizzler.get(); } - this->initializeSwizzler(this->dstInfo(), this->options()); - return fSwizzler; + this->initializeSwizzler(this->dstInfo(), this->options(), true); + return fSwizzler.get(); } bool SkPngCodec::onRewind() { @@ -1289,13 +1278,13 @@ uint64_t SkPngCodec::onGetFillValue(const SkImageInfo& dstInfo) const { SkAlphaType alphaType = select_xform_alpha(dstInfo.alphaType(), this->getInfo().alphaType()); return get_color_table_fill_value(dstInfo.colorType(), alphaType, colorPtr, 0, - fColorXform.get()); + this->colorXform(), true); } return INHERITED::onGetFillValue(dstInfo); } SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) { - SkAutoTDelete streamDeleter(stream); + std::unique_ptr streamDeleter(stream); SkCodec* outCodec = nullptr; if (read_header(streamDeleter.get(), chunkReader, &outCodec, nullptr, nullptr)) { diff --git a/gfx/skia/skia/src/codec/SkPngCodec.h b/gfx/skia/skia/src/codec/SkPngCodec.h index 1fc451757eef..09231f16bd89 100644 --- a/gfx/skia/skia/src/codec/SkPngCodec.h +++ b/gfx/skia/skia/src/codec/SkPngCodec.h @@ -4,12 +4,14 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#ifndef SkPngCodec_DEFINED +#define SkPngCodec_DEFINED #include "SkCodec.h" #include "SkColorSpaceXform.h" #include "SkColorTable.h" #include "SkPngChunkReader.h" -#include "SkEncodedFormat.h" +#include "SkEncodedImageFormat.h" #include "SkImageInfo.h" #include "SkRefCnt.h" #include "SkSwizzler.h" @@ -30,7 +32,7 @@ public: // Assume IsPng was called and returned true. static SkCodec* NewFromStream(SkStream*, SkPngChunkReader* = NULL); - virtual ~SkPngCodec(); + ~SkPngCodec() override; protected: // We hold the png_ptr and info_ptr as voidp to avoid having to include png.h @@ -51,7 +53,7 @@ protected: Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor*, int*, int*) override; - SkEncodedFormat onGetEncodedFormat() const override { return kPNG_SkEncodedFormat; } + SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kPNG; } bool onRewind() override; uint64_t onGetFillValue(const SkImageInfo&) const override; @@ -61,7 +63,7 @@ protected: voidp png_ptr() { return fPng_ptr; } voidp info_ptr() { return fInfo_ptr; } - SkSwizzler* swizzler() { return fSwizzler; } + SkSwizzler* swizzler() { return fSwizzler.get(); } // Initialize variables used by applyXformRow. void initializeXformParams(); @@ -91,17 +93,16 @@ protected: SkPMColor* ctable, int* ctableCount) override; Result onIncrementalDecode(int*) override; - SkAutoTUnref fPngChunkReader; - voidp fPng_ptr; - voidp fInfo_ptr; + sk_sp fPngChunkReader; + voidp fPng_ptr; + voidp fInfo_ptr; // These are stored here so they can be used both by normal decoding and scanline decoding. - SkAutoTUnref fColorTable; // May be unpremul. - SkAutoTDelete fSwizzler; - std::unique_ptr fColorXform; - SkAutoTMalloc fStorage; - uint32_t* fColorXformSrcRow; - const int fBitDepth; + sk_sp fColorTable; // May be unpremul. + std::unique_ptr fSwizzler; + SkAutoTMalloc fStorage; + void* fColorXformSrcRow; + const int fBitDepth; private: @@ -120,7 +121,7 @@ private: // Helper to set up swizzler, color xforms, and color table. Also calls png_read_update_info. bool initializeXforms(const SkImageInfo& dstInfo, const Options&, SkPMColor* colorPtr, int* colorCount); - void initializeSwizzler(const SkImageInfo& dstInfo, const Options&); + void initializeSwizzler(const SkImageInfo& dstInfo, const Options&, bool skipFormatConversion); void allocateStorage(const SkImageInfo& dstInfo); void destroyReadStruct(); @@ -139,3 +140,4 @@ private: typedef SkCodec INHERITED; }; +#endif // SkPngCodec_DEFINED diff --git a/gfx/skia/skia/src/codec/SkRawAdapterCodec.h b/gfx/skia/skia/src/codec/SkRawAdapterCodec.h index b552f2aaeada..29e817c7d888 100644 --- a/gfx/skia/skia/src/codec/SkRawAdapterCodec.h +++ b/gfx/skia/skia/src/codec/SkRawAdapterCodec.h @@ -10,7 +10,7 @@ #include "SkAndroidCodec.h" #include "SkCodec.h" -#include "SkEncodedFormat.h" +#include "SkEncodedImageFormat.h" #include "SkRawCodec.h" #include "SkStream.h" #include "SkTypes.h" @@ -24,7 +24,7 @@ public: explicit SkRawAdapterCodec(SkRawCodec*); - virtual ~SkRawAdapterCodec() {} + ~SkRawAdapterCodec() override {} protected: diff --git a/gfx/skia/skia/src/codec/SkRawCodec.cpp b/gfx/skia/skia/src/codec/SkRawCodec.cpp index 2a6a48fdbbd9..272f737f18f2 100644 --- a/gfx/skia/skia/src/codec/SkRawCodec.cpp +++ b/gfx/skia/skia/src/codec/SkRawCodec.cpp @@ -201,7 +201,7 @@ public: class SkRawLimitedDynamicMemoryWStream : public SkDynamicMemoryWStream { public: - virtual ~SkRawLimitedDynamicMemoryWStream() {} + ~SkRawLimitedDynamicMemoryWStream() override {} bool write(const void* buffer, size_t size) override { size_t newSize; @@ -322,7 +322,7 @@ private: return fStreamBuffer.write(tempBuffer.get(), bytesRead); } - SkAutoTDelete fStream; + std::unique_ptr fStream; bool fWholeStreamRead; // Use a size-limited stream to avoid holding too huge buffer. @@ -396,7 +396,7 @@ public: } } private: - SkAutoTDelete fStream; + std::unique_ptr fStream; }; class SkPiexStream : public ::piex::StreamInterface { @@ -446,7 +446,7 @@ public: * Note: this will take the ownership of the stream. */ static SkDngImage* NewFromStream(SkRawStream* stream) { - SkAutoTDelete dngImage(new SkDngImage(stream)); + std::unique_ptr dngImage(new SkDngImage(stream)); if (!dngImage->isTiffHeaderValid()) { return nullptr; } @@ -479,10 +479,10 @@ public: const int preferredSize = SkTMax(width, height); try { // render() takes ownership of fHost, fInfo, fNegative and fDngStream when available. - SkAutoTDelete host(fHost.release()); - SkAutoTDelete info(fInfo.release()); - SkAutoTDelete negative(fNegative.release()); - SkAutoTDelete dngStream(fDngStream.release()); + std::unique_ptr host(fHost.release()); + std::unique_ptr info(fInfo.release()); + std::unique_ptr negative(fNegative.release()); + std::unique_ptr dngStream(fDngStream.release()); host->SetPreferredSize(preferredSize); host->ValidateSizes(); @@ -553,7 +553,7 @@ private: return 0x2A == get_endian_short(header + 2, littleEndian); } - void init(int width, int height, const dng_point& cfaPatternSize) { + bool init(int width, int height, const dng_point& cfaPatternSize) { fWidth = width; fHeight = height; @@ -561,6 +561,8 @@ private: // a mosaic info is available. fIsScalable = cfaPatternSize.v != 0 && cfaPatternSize.h != 0; fIsXtransImage = fIsScalable ? (cfaPatternSize.v == 6 && cfaPatternSize.h == 6) : false; + + return width > 0 && height > 0; } bool initFromPiex() { @@ -570,15 +572,9 @@ private: if (::piex::IsRaw(&piexStream) && ::piex::GetPreviewImageData(&piexStream, &imageData) == ::piex::Error::kOk) { - // Verify the size information, as it is only optional information for PIEX. - if (imageData.full_width == 0 || imageData.full_height == 0) { - return false; - } - dng_point cfaPatternSize(imageData.cfa_pattern_dim[1], imageData.cfa_pattern_dim[0]); - this->init(static_cast(imageData.full_width), - static_cast(imageData.full_height), cfaPatternSize); - return true; + return this->init(static_cast(imageData.full_width), + static_cast(imageData.full_height), cfaPatternSize); } return false; } @@ -588,7 +584,7 @@ private: // Due to the limit of DNG SDK, we need to reset host and info. fHost.reset(new SkDngHost(&fAllocator)); fInfo.reset(new dng_info); - fDngStream.reset(new SkDngStream(fStream)); + fDngStream.reset(new SkDngStream(fStream.get())); fHost->ValidateSizes(); fInfo->Parse(*fHost, *fDngStream); @@ -606,10 +602,9 @@ private: if (fNegative->GetMosaicInfo() != nullptr) { cfaPatternSize = fNegative->GetMosaicInfo()->fCFAPatternSize; } - this->init(static_cast(fNegative->DefaultCropSizeH().As_real64()), - static_cast(fNegative->DefaultCropSizeV().As_real64()), - cfaPatternSize); - return true; + return this->init(static_cast(fNegative->DefaultCropSizeH().As_real64()), + static_cast(fNegative->DefaultCropSizeV().As_real64()), + cfaPatternSize); } catch (...) { return false; } @@ -622,11 +617,11 @@ private: {} SkDngMemoryAllocator fAllocator; - SkAutoTDelete fStream; - SkAutoTDelete fHost; - SkAutoTDelete fInfo; - SkAutoTDelete fNegative; - SkAutoTDelete fDngStream; + std::unique_ptr fStream; + std::unique_ptr fHost; + std::unique_ptr fInfo; + std::unique_ptr fNegative; + std::unique_ptr fDngStream; int fWidth; int fHeight; @@ -641,7 +636,7 @@ private: * fallback to create SkRawCodec for DNG images. */ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { - SkAutoTDelete rawStream; + std::unique_ptr rawStream; if (is_asset_stream(*stream)) { rawStream.reset(new SkRawAssetStream(stream)); } else { @@ -653,6 +648,19 @@ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { ::piex::PreviewImageData imageData; if (::piex::IsRaw(&piexStream)) { ::piex::Error error = ::piex::GetPreviewImageData(&piexStream, &imageData); + if (error == ::piex::Error::kFail) { + return nullptr; + } + + sk_sp colorSpace; + switch (imageData.color_space) { + case ::piex::PreviewImageData::kSrgb: + colorSpace = SkColorSpace::MakeSRGB(); + break; + case ::piex::PreviewImageData::kAdobeRgb: + colorSpace = SkColorSpace_Base::MakeNamed(SkColorSpace_Base::kAdobeRGB_Named); + break; + } // Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only // handle the JPEG compressed preview image here. @@ -664,14 +672,13 @@ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { // FIXME: one may avoid the copy of memoryStream and use the buffered rawStream. SkMemoryStream* memoryStream = rawStream->transferBuffer(imageData.preview.offset, imageData.preview.length); - return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nullptr; - } else if (error == ::piex::Error::kFail) { - return nullptr; + return memoryStream ? SkJpegCodec::NewFromStream(memoryStream, std::move(colorSpace)) + : nullptr; } } // Takes the ownership of the rawStream. - SkAutoTDelete dngImage(SkDngImage::NewFromStream(rawStream.release())); + std::unique_ptr dngImage(SkDngImage::NewFromStream(rawStream.release())); if (!dngImage) { return nullptr; } @@ -679,22 +686,32 @@ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { return new SkRawCodec(dngImage.release()); } -SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, +SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& options, SkPMColor ctable[], int* ctableCount, int* rowsDecoded) { - if (!conversion_possible_ignore_color_space(requestedInfo, this->getInfo())) { + if (!conversion_possible(dstInfo, this->getInfo()) || + !this->initializeColorXform(dstInfo, options.fPremulBehavior)) + { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } - SkAutoTDelete swizzler(SkSwizzler::CreateSwizzler( - this->getEncodedInfo(), nullptr, requestedInfo, options)); + static const SkColorType kXformSrcColorType = kRGBA_8888_SkColorType; + SkImageInfo swizzlerInfo = dstInfo; + std::unique_ptr xformBuffer = nullptr; + if (this->colorXform()) { + swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType); + xformBuffer.reset(new uint32_t[dstInfo.width()]); + } + + std::unique_ptr swizzler(SkSwizzler::CreateSwizzler( + this->getEncodedInfo(), nullptr, swizzlerInfo, options)); SkASSERT(swizzler); - const int width = requestedInfo.width(); - const int height = requestedInfo.height(); - SkAutoTDelete image(fDngImage->render(width, height)); + const int width = dstInfo.width(); + const int height = dstInfo.height(); + std::unique_ptr image(fDngImage->render(width, height)); if (!image) { return kInvalidInput; } @@ -703,8 +720,8 @@ SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* // difference. Only the overlapping region will be converted. const float maxDiffRatio = 1.03f; const dng_point& imageSize = image->Size(); - if (imageSize.h / width > maxDiffRatio || imageSize.h < width || - imageSize.v / height > maxDiffRatio || imageSize.v < height) { + if (imageSize.h / (float) width > maxDiffRatio || imageSize.h < width || + imageSize.v / (float) height > maxDiffRatio || imageSize.v < height) { return SkCodec::kInvalidScale; } @@ -731,8 +748,20 @@ SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* return kIncompleteInput; } - swizzler->swizzle(dstRow, &srcRow[0]); - dstRow = SkTAddOffset(dstRow, dstRowBytes); + if (this->colorXform()) { + swizzler->swizzle(xformBuffer.get(), &srcRow[0]); + + const SkColorSpaceXform::ColorFormat srcFormat = + select_xform_format(kXformSrcColorType); + const SkColorSpaceXform::ColorFormat dstFormat = + select_xform_format(dstInfo.colorType()); + this->colorXform()->apply(dstFormat, dstRow, srcFormat, xformBuffer.get(), + dstInfo.width(), kOpaque_SkAlphaType); + dstRow = SkTAddOffset(dstRow, dstRowBytes); + } else { + swizzler->swizzle(dstRow, &srcRow[0]); + dstRow = SkTAddOffset(dstRow, dstRowBytes); + } } return kSuccess; } @@ -778,5 +807,6 @@ bool SkRawCodec::onDimensionsSupported(const SkISize& dim) { SkRawCodec::~SkRawCodec() {} SkRawCodec::SkRawCodec(SkDngImage* dngImage) - : INHERITED(dngImage->width(), dngImage->height(), dngImage->getEncodedInfo(), nullptr) + : INHERITED(dngImage->width(), dngImage->height(), dngImage->getEncodedInfo(), nullptr, + SkColorSpace::MakeSRGB()) , fDngImage(dngImage) {} diff --git a/gfx/skia/skia/src/codec/SkRawCodec.h b/gfx/skia/skia/src/codec/SkRawCodec.h index 3ca7b9c17ebc..51bb234b7339 100644 --- a/gfx/skia/skia/src/codec/SkRawCodec.h +++ b/gfx/skia/skia/src/codec/SkRawCodec.h @@ -37,8 +37,8 @@ protected: Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, SkPMColor*, int*, int*) override; - SkEncodedFormat onGetEncodedFormat() const override { - return kDNG_SkEncodedFormat; + SkEncodedImageFormat onGetEncodedFormat() const override { + return SkEncodedImageFormat::kDNG; } SkISize onGetScaledDimensions(float desiredScale) const override; @@ -53,7 +53,7 @@ private: */ SkRawCodec(SkDngImage* dngImage); - SkAutoTDelete fDngImage; + std::unique_ptr fDngImage; typedef SkCodec INHERITED; }; diff --git a/gfx/skia/skia/src/codec/SkSampledCodec.cpp b/gfx/skia/skia/src/codec/SkSampledCodec.cpp index cca26000d684..2b6483b05838 100644 --- a/gfx/skia/skia/src/codec/SkSampledCodec.cpp +++ b/gfx/skia/skia/src/codec/SkSampledCodec.cpp @@ -26,7 +26,7 @@ SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeS } // Only JPEG supports native downsampling. - if (this->codec()->getEncodedFormat() == kJPEG_SkEncodedFormat) { + if (this->codec()->getEncodedFormat() == SkEncodedImageFormat::kJPEG) { // See if libjpeg supports this scale directly switch (sampleSize) { case 2: @@ -75,6 +75,7 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void // Create an Options struct for the codec. SkCodec::Options codecOptions; codecOptions.fZeroInitialized = options.fZeroInitialized; + codecOptions.fPremulBehavior = SkTransferFunctionBehavior::kIgnore; SkIRect* subset = options.fSubset; if (!subset || subset->size() == this->codec()->getInfo().dimensions()) { @@ -171,6 +172,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix // Create options struct for the codec. SkCodec::Options sampledOptions; sampledOptions.fZeroInitialized = options.fZeroInitialized; + sampledOptions.fPremulBehavior = SkTransferFunctionBehavior::kIgnore; // FIXME: This was already called by onGetAndroidPixels. Can we reduce that? int sampleSize = options.fSampleSize; @@ -186,7 +188,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix // We will need to know about subsetting in the y-dimension in order to use the // scanline decoder. // Update the subset to account for scaling done by this->codec(). - SkIRect* subsetPtr = options.fSubset; + const SkIRect* subsetPtr = options.fSubset; // Do the divide ourselves, instead of calling get_scaled_dimension. If // X and Y are 0, they should remain 0, rather than being upgraded to 1 @@ -210,7 +212,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix const int samplingOffsetY = get_start_coord(sampleY); const int startY = samplingOffsetY + subsetY; - int dstHeight = info.height(); + const int dstHeight = info.height(); const SkImageInfo nativeInfo = info.makeWH(nativeSize.width(), nativeSize.height()); @@ -218,22 +220,15 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix // Although startScanlineDecode expects the bottom and top to match the // SkImageInfo, startIncrementalDecode uses them to determine which rows to // decode. - // Note: We *could* use "subsetY" and "subsetHeight" (calculated above) for - // incrementalSubset, but this code gives us a tighter bounds on the subset, - // meaning that we can start with the first row actually needed by the output, - // and stop when we've decoded the last row needed by the output. + SkCodec::Options incrementalOptions = sampledOptions; SkIRect incrementalSubset; - incrementalSubset.fTop = startY; - incrementalSubset.fBottom = startY + (dstHeight - 1) * sampleY + 1; if (sampledOptions.fSubset) { + incrementalSubset.fTop = subsetY; + incrementalSubset.fBottom = subsetY + subsetHeight; incrementalSubset.fLeft = sampledOptions.fSubset->fLeft; incrementalSubset.fRight = sampledOptions.fSubset->fRight; - } else { - incrementalSubset.fLeft = 0; - incrementalSubset.fRight = nativeSize.width(); + incrementalOptions.fSubset = &incrementalSubset; } - SkCodec::Options incrementalOptions = sampledOptions; - incrementalOptions.fSubset = &incrementalSubset; const SkCodec::Result startResult = this->codec()->startIncrementalDecode(nativeInfo, pixels, rowBytes, &incrementalOptions, options.fColorPtr, options.fColorCount); if (SkCodec::kSuccess == startResult) { @@ -258,10 +253,9 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix } SkASSERT(incResult == SkCodec::kIncompleteInput); - // Count the rows that we decoded, and also did not skip. - const int trueRowsDecoded = (rowsDecoded + sampleY - 1) / sampleY; + SkASSERT(rowsDecoded <= info.height()); this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, - info.height(), trueRowsDecoded); + info.height(), rowsDecoded); return SkCodec::kIncompleteInput; } else if (startResult != SkCodec::kUnimplemented) { return startResult; @@ -312,7 +306,6 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix } return SkCodec::kSuccess; } - case SkCodec::kOutOfOrder_SkScanlineOrder: case SkCodec::kBottomUp_SkScanlineOrder: { // Note that these modes do not support subsetting. SkASSERT(0 == subsetY && nativeSize.height() == subsetHeight); diff --git a/gfx/skia/skia/src/codec/SkSampledCodec.h b/gfx/skia/skia/src/codec/SkSampledCodec.h index 35e4f571d0d1..4bcf5bcadf7b 100644 --- a/gfx/skia/skia/src/codec/SkSampledCodec.h +++ b/gfx/skia/skia/src/codec/SkSampledCodec.h @@ -19,7 +19,7 @@ public: explicit SkSampledCodec(SkCodec*); - virtual ~SkSampledCodec() {} + ~SkSampledCodec() override {} protected: diff --git a/gfx/skia/skia/src/codec/SkSampler.h b/gfx/skia/skia/src/codec/SkSampler.h index 00015585a11d..8dce671f44db 100644 --- a/gfx/skia/skia/src/codec/SkSampler.h +++ b/gfx/skia/skia/src/codec/SkSampler.h @@ -8,6 +8,7 @@ #define SkSampler_DEFINED #include "SkCodec.h" +#include "SkCodecPriv.h" #include "SkTypes.h" class SkSampler : public SkNoncopyable { @@ -37,11 +38,10 @@ public: /** * Based on fSampleY, return whether this row belongs in the output. * - * @param row Row of the image, starting with the first row used in the - * output. + * @param row Row of the image, starting with the first row in the subset. */ bool rowNeeded(int row) const { - return row % fSampleY == 0; + return (row - get_start_coord(fSampleY)) % fSampleY == 0; } /** diff --git a/gfx/skia/skia/src/codec/SkStreamBuffer.cpp b/gfx/skia/skia/src/codec/SkStreamBuffer.cpp new file mode 100644 index 000000000000..754065d97a89 --- /dev/null +++ b/gfx/skia/skia/src/codec/SkStreamBuffer.cpp @@ -0,0 +1,87 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkStreamBuffer.h" + +SkStreamBuffer::SkStreamBuffer(SkStream* stream) + : fStream(stream) + , fPosition(0) + , fBytesBuffered(0) + , fHasLengthAndPosition(stream->hasLength() && stream->hasPosition()) + , fTrulyBuffered(0) +{} + +SkStreamBuffer::~SkStreamBuffer() { + fMarkedData.foreach([](size_t, SkData** data) { (*data)->unref(); }); +} + +const char* SkStreamBuffer::get() const { + SkASSERT(fBytesBuffered >= 1); + if (fHasLengthAndPosition && fTrulyBuffered < fBytesBuffered) { + const size_t bytesToBuffer = fBytesBuffered - fTrulyBuffered; + char* dst = SkTAddOffset(const_cast(fBuffer), fTrulyBuffered); + SkDEBUGCODE(const size_t bytesRead =) + // This stream is rewindable, so it should be safe to call the non-const + // read() + const_cast(fStream.get())->read(dst, bytesToBuffer); + SkASSERT(bytesRead == bytesToBuffer); + fTrulyBuffered = fBytesBuffered; + } + return fBuffer; +} + +bool SkStreamBuffer::buffer(size_t totalBytesToBuffer) { + // FIXME (scroggo): What should we do if the client tries to read too much? + // Should not be a problem in GIF. + SkASSERT(totalBytesToBuffer <= kMaxSize); + + if (totalBytesToBuffer <= fBytesBuffered) { + return true; + } + + if (fHasLengthAndPosition) { + const size_t remaining = fStream->getLength() - fStream->getPosition() + fTrulyBuffered; + fBytesBuffered = SkTMin(remaining, totalBytesToBuffer); + } else { + const size_t extraBytes = totalBytesToBuffer - fBytesBuffered; + const size_t bytesBuffered = fStream->read(fBuffer + fBytesBuffered, extraBytes); + fBytesBuffered += bytesBuffered; + } + return fBytesBuffered == totalBytesToBuffer; +} + +size_t SkStreamBuffer::markPosition() { + SkASSERT(fBytesBuffered >= 1); + if (!fHasLengthAndPosition) { + sk_sp data(SkData::MakeWithCopy(fBuffer, fBytesBuffered)); + SkASSERT(nullptr == fMarkedData.find(fPosition)); + fMarkedData.set(fPosition, data.release()); + } + return fPosition; +} + +sk_sp SkStreamBuffer::getDataAtPosition(size_t position, size_t length) { + if (!fHasLengthAndPosition) { + SkData** data = fMarkedData.find(position); + SkASSERT(data); + SkASSERT((*data)->size() == length); + return sk_ref_sp(*data); + } + + SkASSERT(position + length <= fStream->getLength()); + + const size_t oldPosition = fStream->getPosition(); + if (!fStream->seek(position)) { + return nullptr; + } + + sk_sp data(SkData::MakeUninitialized(length)); + void* dst = data->writable_data(); + const bool success = fStream->read(dst, length) == length; + fStream->seek(oldPosition); + return success ? data : nullptr; +} diff --git a/gfx/skia/skia/src/codec/SkStreamBuffer.h b/gfx/skia/skia/src/codec/SkStreamBuffer.h new file mode 100644 index 000000000000..2b60775dd2c5 --- /dev/null +++ b/gfx/skia/skia/src/codec/SkStreamBuffer.h @@ -0,0 +1,118 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkStreamBuffer_DEFINED +#define SkStreamBuffer_DEFINED + +#include "SkData.h" +#include "SkStream.h" +#include "SkTypes.h" +#include "../private/SkTHash.h" + +/** + * Helper class for reading from a stream that may not have all its data + * available yet. + * + * Used by GIFImageReader, and currently set up for that use case. + * + * Buffers up to 256 * 3 bytes (256 colors, with 3 bytes each) to support GIF. + * FIXME (scroggo): Make this more general purpose? + */ +class SkStreamBuffer : SkNoncopyable { +public: + // Takes ownership of the SkStream. + SkStreamBuffer(SkStream*); + + ~SkStreamBuffer(); + + /** + * Return a pointer the buffered data. + * + * The number of bytes buffered is the number passed to buffer() + * after the last call to flush(). + */ + const char* get() const; + + /** + * Buffer from the stream into our buffer. + * + * If this call returns true, get() can be used to access |bytes| bytes + * from the stream. In addition, markPosition() can be called to mark this + * position and enable calling getAtPosition() later to retrieve |bytes| + * bytes. + * + * @param bytes Total number of bytes desired. + * + * @return Whether all bytes were successfully buffered. + */ + bool buffer(size_t bytes); + + /** + * Flush the buffer. + * + * After this call, no bytes are buffered. + */ + void flush() { + if (fHasLengthAndPosition) { + if (fTrulyBuffered < fBytesBuffered) { + fStream->move(fBytesBuffered - fTrulyBuffered); + } + fTrulyBuffered = 0; + } + fPosition += fBytesBuffered; + fBytesBuffered = 0; + } + + /** + * Mark the current position in the stream to return to it later. + * + * This is the position of the start of the buffer. After this call, a + * a client can call getDataAtPosition to retrieve all the bytes currently + * buffered. + * + * @return size_t Position which can be passed to getDataAtPosition later + * to retrieve the data currently buffered. + */ + size_t markPosition(); + + /** + * Retrieve data at position, as previously marked by markPosition(). + * + * @param position Position to retrieve data, as marked by markPosition(). + * @param length Amount of data required at position. + * @return SkData The data at position. + */ + sk_sp getDataAtPosition(size_t position, size_t length); + +private: + static constexpr size_t kMaxSize = 256 * 3; + + std::unique_ptr fStream; + size_t fPosition; + char fBuffer[kMaxSize]; + size_t fBytesBuffered; + // If the stream has a length and position, we can make two optimizations: + // - We can skip buffering + // - During parsing, we can store the position and size of data that is + // needed later during decoding. + const bool fHasLengthAndPosition; + // When fHasLengthAndPosition is true, we do not need to actually buffer + // inside buffer(). We'll buffer inside get(). This keeps track of how many + // bytes we've buffered inside get(), for the (non-existent) case of: + // buffer(n) + // get() + // buffer(n + u) + // get() + // The second call to get() needs to only truly buffer the part that was + // not already buffered. + mutable size_t fTrulyBuffered; + // Only used if !fHasLengthAndPosition. In that case, markPosition will + // copy into an SkData, stored here. + SkTHashMap fMarkedData; +}; +#endif // SkStreamBuffer_DEFINED + diff --git a/gfx/skia/skia/src/codec/SkSwizzler.cpp b/gfx/skia/skia/src/codec/SkSwizzler.cpp index c9eb92305387..31fc063aec94 100644 --- a/gfx/skia/skia/src/codec/SkSwizzler.cpp +++ b/gfx/skia/skia/src/codec/SkSwizzler.cpp @@ -7,6 +7,7 @@ #include "SkCodecPriv.h" #include "SkColorPriv.h" +#include "SkHalf.h" #include "SkOpts.h" #include "SkSwizzler.h" #include "SkTemplates.h" @@ -50,6 +51,27 @@ static void sample4(void* dst, const uint8_t* src, int width, int bpp, int delta } } +static void sample6(void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + src += offset; + uint8_t* dst8 = (uint8_t*) dst; + for (int x = 0; x < width; x++) { + memcpy(dst8, src, 6); + dst8 += 6; + src += deltaSrc; + } +} + +static void sample8(void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + src += offset; + uint64_t* dst64 = (uint64_t*) dst; + for (int x = 0; x < width; x++) { + dst64[x] = *((const uint64_t*) src); + src += deltaSrc; + } +} + // kBit // These routines exclusively choose between white and black @@ -150,6 +172,35 @@ static void swizzle_bit_to_565( #undef RGB565_BLACK #undef RGB565_WHITE +static void swizzle_bit_to_f16( + void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, + int bpp, int deltaSrc, int offset, const SkPMColor* /*ctable*/) { + static const uint64_t kWhite = (((uint64_t) SK_Half1) << 0) | + (((uint64_t) SK_Half1) << 16) | + (((uint64_t) SK_Half1) << 32) | + (((uint64_t) SK_Half1) << 48); + static const uint64_t kBlack = (((uint64_t) 0) << 0) | + (((uint64_t) 0) << 16) | + (((uint64_t) 0) << 32) | + (((uint64_t) SK_Half1) << 48); + + uint64_t* SK_RESTRICT dst = (uint64_t*) dstRow; + + // increment src by byte offset and bitIndex by bit offset + src += offset / 8; + int bitIndex = offset % 8; + uint8_t currByte = *src; + + dst[0] = ((currByte >> (7 - bitIndex)) & 1) ? kWhite : kBlack; + + for (int x = 1; x < dstWidth; x++) { + int bitOffset = bitIndex + deltaSrc; + bitIndex = bitOffset % 8; + currByte = *(src += bitOffset / 8); + dst[x] = ((currByte >> (7 - bitIndex)) & 1) ? kWhite : kBlack; + } +} + // kIndex1, kIndex2, kIndex4 static void swizzle_small_index_to_index( @@ -494,6 +545,113 @@ static void fast_swizzle_rgba_to_bgra_unpremul( SkOpts::RGBA_to_BGRA((uint32_t*) dst, src + offset, width); } +// 16-bits per component kRGB and kRGBA + +static void swizzle_rgb16_to_rgba( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto strip16to8 = [](const uint8_t* ptr) { + return 0xFF000000 | (ptr[4] << 16) | (ptr[2] << 8) | ptr[0]; + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = strip16to8(src); + src += deltaSrc; + } +} + +static void swizzle_rgb16_to_bgra( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto strip16to8 = [](const uint8_t* ptr) { + return 0xFF000000 | (ptr[0] << 16) | (ptr[2] << 8) | ptr[4]; + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = strip16to8(src); + src += deltaSrc; + } +} + +static void swizzle_rgb16_to_565( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto strip16to565 = [](const uint8_t* ptr) { + return SkPack888ToRGB16(ptr[0], ptr[2], ptr[4]); + }; + + src += offset; + uint16_t* dst16 = (uint16_t*) dst; + for (int x = 0; x < width; x++) { + dst16[x] = strip16to565(src); + src += deltaSrc; + } +} + +static void swizzle_rgba16_to_rgba_unpremul( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto strip16to8 = [](const uint8_t* ptr) { + return (ptr[6] << 24) | (ptr[4] << 16) | (ptr[2] << 8) | ptr[0]; + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = strip16to8(src); + src += deltaSrc; + } +} + +static void swizzle_rgba16_to_rgba_premul( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto stripAndPremul16to8 = [](const uint8_t* ptr) { + return premultiply_argb_as_rgba(ptr[6], ptr[0], ptr[2], ptr[4]); + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = stripAndPremul16to8(src); + src += deltaSrc; + } +} + +static void swizzle_rgba16_to_bgra_unpremul( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto strip16to8 = [](const uint8_t* ptr) { + return (ptr[6] << 24) | (ptr[0] << 16) | (ptr[2] << 8) | ptr[4]; + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = strip16to8(src); + src += deltaSrc; + } +} + +static void swizzle_rgba16_to_bgra_premul( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto stripAndPremul16to8 = [](const uint8_t* ptr) { + return premultiply_argb_as_bgra(ptr[6], ptr[0], ptr[2], ptr[4]); + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = stripAndPremul16to8(src); + src += deltaSrc; + } +} + // kCMYK // // CMYK is stored as four bytes per pixel. @@ -652,28 +810,66 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo, const SkImageInfo& dstInfo, const SkCodec::Options& options, const SkIRect* frame, - bool preSwizzled) { + bool skipFormatConversion) { if (SkEncodedInfo::kPalette_Color == encodedInfo.color() && nullptr == ctable) { return nullptr; } RowProc fastProc = nullptr; RowProc proc = nullptr; - if (preSwizzled) { - switch (dstInfo.colorType()) { - case kGray_8_SkColorType: - proc = &sample1; - fastProc = © + int srcBPP; + const int dstBPP = SkColorTypeBytesPerPixel(dstInfo.colorType()); + if (skipFormatConversion) { + switch (encodedInfo.color()) { + case SkEncodedInfo::kGray_Color: + case SkEncodedInfo::kYUV_Color: + // We have a jpeg that has already been converted to the dstColorType. + srcBPP = dstBPP; + switch (dstInfo.colorType()) { + case kGray_8_SkColorType: + proc = &sample1; + fastProc = © + break; + case kRGB_565_SkColorType: + proc = &sample2; + fastProc = © + break; + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + proc = &sample4; + fastProc = © + break; + default: + return nullptr; + } break; - case kRGB_565_SkColorType: - proc = &sample2; - fastProc = © - break; - case kRGBA_8888_SkColorType: - case kBGRA_8888_SkColorType: + case SkEncodedInfo::kInvertedCMYK_Color: + case SkEncodedInfo::kYCCK_Color: + // We have a jpeg that remains in its original format. + srcBPP = 4; proc = &sample4; fastProc = © break; + case SkEncodedInfo::kRGBA_Color: + // We have a png that should remain in its original format. + SkASSERT(16 == encodedInfo.bitsPerComponent() || + 8 == encodedInfo.bitsPerComponent()); + if (8 == encodedInfo.bitsPerComponent()) { + srcBPP = 4; + proc = &sample4; + } else { + srcBPP = 8; + proc = &sample8; + } + fastProc = © + break; + case SkEncodedInfo::kRGB_Color: + // We have a png that remains in its original format. + SkASSERT(16 == encodedInfo.bitsPerComponent()); + srcBPP = 6; + proc = &sample6; + fastProc = © + break; default: return nullptr; } @@ -700,6 +896,9 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo, case kGray_8_SkColorType: proc = &swizzle_bit_to_grayscale; break; + case kRGBA_F16_SkColorType: + proc = &swizzle_bit_to_f16; + break; default: return nullptr; } @@ -806,14 +1005,31 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo, case SkEncodedInfo::kRGB_Color: switch (dstInfo.colorType()) { case kRGBA_8888_SkColorType: + if (16 == encodedInfo.bitsPerComponent()) { + proc = &swizzle_rgb16_to_rgba; + break; + } + + SkASSERT(8 == encodedInfo.bitsPerComponent()); proc = &swizzle_rgb_to_rgba; fastProc = &fast_swizzle_rgb_to_rgba; break; case kBGRA_8888_SkColorType: + if (16 == encodedInfo.bitsPerComponent()) { + proc = &swizzle_rgb16_to_bgra; + break; + } + + SkASSERT(8 == encodedInfo.bitsPerComponent()); proc = &swizzle_rgb_to_bgra; fastProc = &fast_swizzle_rgb_to_bgra; break; case kRGB_565_SkColorType: + if (16 == encodedInfo.bitsPerComponent()) { + proc = &swizzle_rgb16_to_565; + break; + } + proc = &swizzle_rgb_to_565; break; default: @@ -823,6 +1039,13 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo, case SkEncodedInfo::kRGBA_Color: switch (dstInfo.colorType()) { case kRGBA_8888_SkColorType: + if (16 == encodedInfo.bitsPerComponent()) { + proc = premultiply ? &swizzle_rgba16_to_rgba_premul : + &swizzle_rgba16_to_rgba_unpremul; + break; + } + + SkASSERT(8 == encodedInfo.bitsPerComponent()); if (premultiply) { if (SkCodec::kYes_ZeroInitialized == zeroInit) { proc = &SkipLeading8888ZerosThen; @@ -843,6 +1066,13 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo, } break; case kBGRA_8888_SkColorType: + if (16 == encodedInfo.bitsPerComponent()) { + proc = premultiply ? &swizzle_rgba16_to_bgra_premul : + &swizzle_rgba16_to_bgra_unpremul; + break; + } + + SkASSERT(8 == encodedInfo.bitsPerComponent()); if (premultiply) { if (SkCodec::kYes_ZeroInitialized == zeroInit) { proc = &SkipLeading8888ZerosThen; @@ -966,13 +1196,7 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo, default: return nullptr; } - } - int srcBPP; - const int dstBPP = SkColorTypeBytesPerPixel(dstInfo.colorType()); - if (preSwizzled) { - srcBPP = dstBPP; - } else { // Store bpp in bytes if it is an even multiple, otherwise use bits uint8_t bitsPerPixel = encodedInfo.bitsPerPixel(); srcBPP = SkIsAlign8(bitsPerPixel) ? bitsPerPixel / 8 : bitsPerPixel; diff --git a/gfx/skia/skia/src/codec/SkSwizzler.h b/gfx/skia/skia/src/codec/SkSwizzler.h index a535298a0795..ebaed7ea33fe 100644 --- a/gfx/skia/skia/src/codec/SkSwizzler.h +++ b/gfx/skia/skia/src/codec/SkSwizzler.h @@ -27,9 +27,8 @@ public: * Contains partial scanline information. * @param frame Is non-NULL if the source pixels are part of an image * frame that is a subset of the full image. - * @param preSwizzled Indicates that the codec has already swizzled to the - * destination format. The swizzler only needs to sample - * and/or subset. + * @param skipFormatConversion Indicates that we should skip format conversion. + * The swizzler only needs to sample and/or subset. * * Note that a deeper discussion of partial scanline subsets and image frame * subsets is below. Currently, we do not support both simultaneously. If @@ -39,7 +38,8 @@ public: */ static SkSwizzler* CreateSwizzler(const SkEncodedInfo& encodedInfo, const SkPMColor* ctable, const SkImageInfo& dstInfo, const SkCodec::Options&, - const SkIRect* frame = nullptr, bool preSwizzled = false); + const SkIRect* frame = nullptr, + bool skipFormatConversion = false); /** * Swizzle a line. Generally this will be called height times, once @@ -78,6 +78,12 @@ public: */ int swizzleWidth() const { return fSwizzleWidth; } + /** + * Returns the byte offset at which we write to destination memory, taking + * scaling, subsetting, and partial frames into account. + */ + size_t swizzleOffsetBytes() const { return fDstOffsetBytes; } + private: /** diff --git a/gfx/skia/skia/src/codec/SkWbmpCodec.cpp b/gfx/skia/skia/src/codec/SkWbmpCodec.cpp index 099b6e472a9e..d59789b66e16 100644 --- a/gfx/skia/skia/src/codec/SkWbmpCodec.cpp +++ b/gfx/skia/skia/src/codec/SkWbmpCodec.cpp @@ -30,14 +30,16 @@ static inline void setup_color_table(SkColorType colorType, } } -static inline bool valid_color_type(SkColorType colorType) { - switch (colorType) { +static inline bool valid_color_type(const SkImageInfo& dstInfo) { + switch (dstInfo.colorType()) { case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: case kIndex_8_SkColorType: case kGray_8_SkColorType: case kRGB_565_SkColorType: return true; + case kRGBA_F16_SkColorType: + return dstInfo.colorSpace() && dstInfo.colorSpace()->gammaIsLinear(); default: return false; } @@ -105,14 +107,14 @@ bool SkWbmpCodec::readRow(uint8_t* row) { } SkWbmpCodec::SkWbmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream) - : INHERITED(width, height, info, stream) + : INHERITED(width, height, info, stream, SkColorSpace::MakeSRGB()) , fSrcRowBytes(get_src_row_bytes(this->getInfo().width())) , fSwizzler(nullptr) , fColorTable(nullptr) {} -SkEncodedFormat SkWbmpCodec::onGetEncodedFormat() const { - return kWBMP_SkEncodedFormat; +SkEncodedImageFormat SkWbmpCodec::onGetEncodedFormat() const { + return SkEncodedImageFormat::kWBMP; } SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, @@ -127,8 +129,7 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, return kUnimplemented; } - if (!valid_color_type(info.colorType()) || - !valid_alpha(info.alphaType(), this->getInfo().alphaType())) { + if (!valid_color_type(info) || !valid_alpha(info.alphaType(), this->getInfo().alphaType())) { return kInvalidConversion; } @@ -136,7 +137,7 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, setup_color_table(info.colorType(), ctable, ctableCount); // Initialize the swizzler - SkAutoTDelete swizzler(this->initializeSwizzler(info, ctable, options)); + std::unique_ptr swizzler(this->initializeSwizzler(info, ctable, options)); SkASSERT(swizzler); // Perform the decode @@ -160,7 +161,7 @@ bool SkWbmpCodec::IsWbmp(const void* buffer, size_t bytesRead) { } SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) { - SkAutoTDelete streamDeleter(stream); + std::unique_ptr streamDeleter(stream); SkISize size; if (!read_header(stream, &size)) { return nullptr; @@ -194,8 +195,9 @@ SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, return kUnimplemented; } - if (!valid_color_type(dstInfo.colorType()) || - !valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) { + if (!valid_color_type(dstInfo) || + !valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) + { return kInvalidConversion; } diff --git a/gfx/skia/skia/src/codec/SkWbmpCodec.h b/gfx/skia/skia/src/codec/SkWbmpCodec.h index 9f29237e2394..40f507e9f34c 100644 --- a/gfx/skia/skia/src/codec/SkWbmpCodec.h +++ b/gfx/skia/skia/src/codec/SkWbmpCodec.h @@ -24,7 +24,7 @@ public: static SkCodec* NewFromStream(SkStream*); protected: - SkEncodedFormat onGetEncodedFormat() const override; + SkEncodedImageFormat onGetEncodedFormat() const override; Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor[], int*, int*) override; bool onRewind() override; @@ -36,7 +36,7 @@ private: const Options& opts); SkSampler* getSampler(bool createIfNecessary) override { SkASSERT(fSwizzler || !createIfNecessary); - return fSwizzler; + return fSwizzler.get(); } /* @@ -46,12 +46,12 @@ private: SkWbmpCodec(int width, int height, const SkEncodedInfo&, SkStream*); - const size_t fSrcRowBytes; + const size_t fSrcRowBytes; // Used for scanline decodes: - SkAutoTDelete fSwizzler; - SkAutoTUnref fColorTable; - SkAutoTMalloc fSrcBuffer; + std::unique_ptr fSwizzler; + sk_sp fColorTable; + SkAutoTMalloc fSrcBuffer; int onGetScanlines(void* dst, int count, size_t dstRowBytes) override; bool onSkipScanlines(int count) override; diff --git a/gfx/skia/skia/src/codec/SkWebpAdapterCodec.cpp b/gfx/skia/skia/src/codec/SkWebpAdapterCodec.cpp index 5aefe5d805ec..cf1f0e0e1fbb 100644 --- a/gfx/skia/skia/src/codec/SkWebpAdapterCodec.cpp +++ b/gfx/skia/skia/src/codec/SkWebpAdapterCodec.cpp @@ -40,6 +40,7 @@ SkCodec::Result SkWebpAdapterCodec::onGetAndroidPixels(const SkImageInfo& info, SkCodec::Options codecOptions; codecOptions.fZeroInitialized = options.fZeroInitialized; codecOptions.fSubset = options.fSubset; + codecOptions.fPremulBehavior = SkTransferFunctionBehavior::kIgnore; return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions, options.fColorPtr, options.fColorCount); } diff --git a/gfx/skia/skia/src/codec/SkWebpAdapterCodec.h b/gfx/skia/skia/src/codec/SkWebpAdapterCodec.h index ece46a668ad7..b2c6c7bd3bab 100644 --- a/gfx/skia/skia/src/codec/SkWebpAdapterCodec.h +++ b/gfx/skia/skia/src/codec/SkWebpAdapterCodec.h @@ -19,7 +19,7 @@ public: explicit SkWebpAdapterCodec(SkWebpCodec*); - virtual ~SkWebpAdapterCodec() {} + ~SkWebpAdapterCodec() override {} protected: diff --git a/gfx/skia/skia/src/codec/SkWebpCodec.cpp b/gfx/skia/skia/src/codec/SkWebpCodec.cpp index 3e5ef2aecf3d..ab0b91b112b6 100644 --- a/gfx/skia/skia/src/codec/SkWebpCodec.cpp +++ b/gfx/skia/skia/src/codec/SkWebpCodec.cpp @@ -7,9 +7,10 @@ #include "SkCodecPriv.h" #include "SkColorSpaceXform.h" -#include "SkWebpCodec.h" +#include "SkSampler.h" #include "SkStreamPriv.h" #include "SkTemplates.h" +#include "SkWebpCodec.h" // A WebP decoder on top of (subset of) libwebp // For more information on WebP image format, and libwebp library, see: @@ -36,7 +37,7 @@ bool SkWebpCodec::IsWebp(const void* buf, size_t bytesRead) { // bytes again. // Returns an SkWebpCodec on success; SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) { - SkAutoTDelete streamDeleter(stream); + std::unique_ptr streamDeleter(stream); // Webp demux needs a contiguous data buffer. sk_sp data = nullptr; @@ -59,34 +60,12 @@ SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) { return nullptr; } - WebPChunkIterator chunkIterator; - SkAutoTCallVProc autoCI(&chunkIterator); - sk_sp colorSpace = nullptr; - if (WebPDemuxGetChunk(demux, "ICCP", 1, &chunkIterator)) { - colorSpace = SkColorSpace::NewICC(chunkIterator.chunk.bytes, chunkIterator.chunk.size); - } - - if (!colorSpace) { - colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); - } - - // Since we do not yet support animation, we get the |width|, |height|, |color|, and |alpha| - // from the first frame. It's the only frame we will decode. - // - // TODO: - // When we support animation, we'll want to report the canvas width and canvas height instead. - // We can get these from the |demux| directly. - // What |color| and |alpha| will we want to report though? WebP allows different frames - // to be encoded in different ways, making the encoded format difficult to describe. - WebPIterator frame; - SkAutoTCallVProc autoFrame(&frame); - if (!WebPDemuxGetFrame(demux, 1, &frame)) { - return nullptr; - } + const int width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH); + const int height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT); // Sanity check for image size that's about to be decoded. { - const int64_t size = sk_64_mul(frame.width, frame.height); + const int64_t size = sk_64_mul(width, height); if (!sk_64_isS32(size)) { return nullptr; } @@ -96,10 +75,29 @@ SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) { } } - // TODO: - // The only reason we actually need to call WebPGetFeatures() is to get the |features.format|. - // This call actually re-reads the frame header. Should we suggest that libwebp expose - // the format on the |frame|? + WebPChunkIterator chunkIterator; + SkAutoTCallVProc autoCI(&chunkIterator); + sk_sp colorSpace = nullptr; + bool unsupportedICC = false; + if (WebPDemuxGetChunk(demux, "ICCP", 1, &chunkIterator)) { + colorSpace = SkColorSpace::MakeICC(chunkIterator.chunk.bytes, chunkIterator.chunk.size); + if (!colorSpace) { + unsupportedICC = true; + } + } + if (!colorSpace) { + colorSpace = SkColorSpace::MakeSRGB(); + } + + // Get the first frame and its "features" to determine the color and alpha types. + // Since we do not yet support animated webp, this is the only frame that we will + // decode. + WebPIterator frame; + SkAutoTCallVProc autoFrame(&frame); + if (!WebPDemuxGetFrame(demux, 1, &frame)) { + return nullptr; + } + WebPBitstreamFeatures features; VP8StatusCode status = WebPGetFeatures(frame.fragment.bytes, frame.fragment.size, &features); if (VP8_STATUS_OK != status) { @@ -110,8 +108,8 @@ SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) { SkEncodedInfo::Alpha alpha; switch (features.format) { case 0: - // This indicates a "mixed" format. We would see this for - // animated webps or for webps encoded in multiple fragments. + // This indicates a "mixed" format. We could see this for + // animated webps (multiple fragments). // I believe that this is a rare case. // We could also guess kYUV here, but I think it makes more // sense to guess kBGRA which is likely closer to the final @@ -122,7 +120,7 @@ SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) { break; case 1: // This is the lossy format (YUV). - if (SkToBool(features.has_alpha)) { + if (SkToBool(features.has_alpha) || frame.width != width || frame.height != height) { color = SkEncodedInfo::kYUVA_Color; alpha = SkEncodedInfo::kUnpremul_Alpha; } else { @@ -140,8 +138,11 @@ SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) { } SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8); - return new SkWebpCodec(features.width, features.height, info, std::move(colorSpace), - streamDeleter.release(), demux.release(), std::move(data)); + SkWebpCodec* codecOut = new SkWebpCodec(width, height, info, std::move(colorSpace), + streamDeleter.release(), demux.release(), + std::move(data)); + codecOut->setUnsupportedICC(unsupportedICC); + return codecOut; } SkISize SkWebpCodec::onGetScaledDimensions(float desiredScale) const { @@ -193,16 +194,12 @@ bool SkWebpCodec::onGetValidSubset(SkIRect* desiredSubset) const { SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, const Options& options, SkPMColor*, int*, int* rowsDecodedPtr) { - if (!conversion_possible(dstInfo, this->getInfo())) { + if (!conversion_possible(dstInfo, this->getInfo()) || + !this->initializeColorXform(dstInfo, options.fPremulBehavior)) + { return kInvalidConversion; } - std::unique_ptr colorXform = nullptr; - if (needs_color_xform(dstInfo, this->getInfo())) { - colorXform = SkColorSpaceXform::New(this->getInfo().colorSpace(), dstInfo.colorSpace()); - SkASSERT(colorXform); - } - WebPDecoderConfig config; if (0 == WebPInitDecoderConfig(&config)) { // ABI mismatch. @@ -213,48 +210,85 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, // Free any memory associated with the buffer. Must be called last, so we declare it first. SkAutoTCallVProc autoFree(&(config.output)); - SkIRect bounds = SkIRect::MakeSize(this->getInfo().dimensions()); - if (options.fSubset) { - // Caller is requesting a subset. - if (!bounds.contains(*options.fSubset)) { - // The subset is out of bounds. - return kInvalidParameters; - } + WebPIterator frame; + SkAutoTCallVProc autoFrame(&frame); + // If this succeeded in NewFromStream(), it should succeed again here. + SkAssertResult(WebPDemuxGetFrame(fDemux, 1, &frame)); - bounds = *options.fSubset; - - // This is tricky. libwebp snaps the top and left to even values. We could let libwebp - // do the snap, and return a subset which is a different one than requested. The problem - // with that approach is that the caller may try to stitch subsets together, and if we - // returned different subsets than requested, there would be artifacts at the boundaries. - // Instead, we report that we cannot support odd values for top and left.. - if (!SkIsAlign2(bounds.fLeft) || !SkIsAlign2(bounds.fTop)) { - return kInvalidParameters; - } - -#ifdef SK_DEBUG - { - // Make a copy, since getValidSubset can change its input. - SkIRect subset(bounds); - // That said, getValidSubset should *not* change its input, in this case; otherwise - // getValidSubset does not match the actual subsets we can do. - SkASSERT(this->getValidSubset(&subset) && subset == bounds); - } -#endif - - config.options.use_cropping = 1; - config.options.crop_left = bounds.fLeft; - config.options.crop_top = bounds.fTop; - config.options.crop_width = bounds.width(); - config.options.crop_height = bounds.height(); + // Get the frameRect. libwebp will have already signaled an error if this is not fully + // contained by the canvas. + auto frameRect = SkIRect::MakeXYWH(frame.x_offset, frame.y_offset, frame.width, frame.height); + SkASSERT(this->getInfo().bounds().contains(frameRect)); + bool frameIsSubset = frameRect.size() != this->getInfo().dimensions(); + if (frameIsSubset) { + SkSampler::Fill(dstInfo, dst, rowBytes, 0, options.fZeroInitialized); } - SkISize dstDimensions = dstInfo.dimensions(); - if (bounds.size() != dstDimensions) { - // Caller is requesting scaling. + int dstX = frameRect.x(); + int dstY = frameRect.y(); + int subsetWidth = frameRect.width(); + int subsetHeight = frameRect.height(); + if (options.fSubset) { + SkIRect subset = *options.fSubset; + SkASSERT(this->getInfo().bounds().contains(subset)); + SkASSERT(SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTop)); + SkASSERT(this->getValidSubset(&subset) && subset == *options.fSubset); + + if (!SkIRect::IntersectsNoEmptyCheck(subset, frameRect)) { + return kSuccess; + } + + int minXOffset = SkTMin(dstX, subset.x()); + int minYOffset = SkTMin(dstY, subset.y()); + dstX -= minXOffset; + dstY -= minYOffset; + frameRect.offset(-minXOffset, -minYOffset); + subset.offset(-minXOffset, -minYOffset); + + // Just like we require that the requested subset x and y offset are even, libwebp + // guarantees that the frame x and y offset are even (it's actually impossible to specify + // an odd frame offset). So we can still guarantee that the adjusted offsets are even. + SkASSERT(SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTop)); + + SkIRect intersection; + SkAssertResult(intersection.intersect(frameRect, subset)); + subsetWidth = intersection.width(); + subsetHeight = intersection.height(); + + config.options.use_cropping = 1; + config.options.crop_left = subset.x(); + config.options.crop_top = subset.y(); + config.options.crop_width = subsetWidth; + config.options.crop_height = subsetHeight; + } + + // Ignore the frame size and offset when determining if scaling is necessary. + int scaledWidth = subsetWidth; + int scaledHeight = subsetHeight; + SkISize srcSize = options.fSubset ? options.fSubset->size() : this->getInfo().dimensions(); + if (srcSize != dstInfo.dimensions()) { config.options.use_scaling = 1; - config.options.scaled_width = dstDimensions.width(); - config.options.scaled_height = dstDimensions.height(); + + if (frameIsSubset) { + float scaleX = ((float) dstInfo.width()) / srcSize.width(); + float scaleY = ((float) dstInfo.height()) / srcSize.height(); + + // We need to be conservative here and floor rather than round. + // Otherwise, we may find ourselves decoding off the end of memory. + dstX = scaleX * dstX; + scaledWidth = scaleX * scaledWidth; + dstY = scaleY * dstY; + scaledHeight = scaleY * scaledHeight; + if (0 == scaledWidth || 0 == scaledHeight) { + return kSuccess; + } + } else { + scaledWidth = dstInfo.width(); + scaledHeight = dstInfo.height(); + } + + config.options.scaled_width = scaledWidth; + config.options.scaled_height = scaledHeight; } // Swizzling between RGBA and BGRA is zero cost in a color transform. So when we have a @@ -262,29 +296,27 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, // color transform swizzle if necessary. // Lossy webp is encoded as YUV (so RGBA and BGRA are the same cost). Lossless webp is // encoded as BGRA. This means decoding to BGRA is either faster or the same cost as RGBA. - config.output.colorspace = colorXform ? MODE_BGRA : + config.output.colorspace = this->colorXform() ? MODE_BGRA : webp_decode_mode(dstInfo.colorType(), dstInfo.alphaType() == kPremul_SkAlphaType); config.output.is_external_memory = 1; // We will decode the entire image and then perform the color transform. libwebp - // does not provide a row-by-row API. This is a shame particularly in the F16 case, - // where we need to allocate an extra image-sized buffer. + // does not provide a row-by-row API. This is a shame particularly when we do not want + // 8888, since we will need to create another image sized buffer. SkAutoTMalloc pixels; - if (kRGBA_F16_SkColorType == dstInfo.colorType()) { - pixels.reset(dstDimensions.width() * dstDimensions.height()); - config.output.u.RGBA.rgba = (uint8_t*) pixels.get(); - config.output.u.RGBA.stride = (int) dstDimensions.width() * sizeof(uint32_t); - config.output.u.RGBA.size = config.output.u.RGBA.stride * dstDimensions.height(); - } else { - config.output.u.RGBA.rgba = (uint8_t*) dst; - config.output.u.RGBA.stride = (int) rowBytes; - config.output.u.RGBA.size = dstInfo.getSafeSize(rowBytes); - } + bool needsCopy = this->colorXform() && kRGBA_8888_SkColorType != dstInfo.colorType() && + kBGRA_8888_SkColorType != dstInfo.colorType(); + void* webpDst = needsCopy ? pixels.reset(dstInfo.width() * dstInfo.height()) : dst; + size_t webpRowBytes = needsCopy ? dstInfo.width() * sizeof(uint32_t) : rowBytes; + size_t totalBytes = needsCopy ? webpRowBytes * dstInfo.height() + : dstInfo.getSafeSize(webpRowBytes); + size_t dstBpp = SkColorTypeBytesPerPixel(dstInfo.colorType()); + size_t webpBpp = needsCopy ? sizeof(uint32_t) : dstBpp; - WebPIterator frame; - SkAutoTCallVProc autoFrame(&frame); - // If this succeeded in NewFromStream(), it should succeed again here. - SkAssertResult(WebPDemuxGetFrame(fDemux, 1, &frame)); + size_t offset = dstX * webpBpp + dstY * webpRowBytes; + config.output.u.RGBA.rgba = SkTAddOffset(webpDst, offset); + config.output.u.RGBA.stride = (int) webpRowBytes; + config.output.u.RGBA.size = totalBytes - offset; SkAutoTCallVProc idec(WebPIDecode(nullptr, 0, &config)); if (!idec) { @@ -295,30 +327,32 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, SkCodec::Result result; switch (WebPIUpdate(idec, frame.fragment.bytes, frame.fragment.size)) { case VP8_STATUS_OK: - rowsDecoded = dstInfo.height(); + rowsDecoded = scaledHeight; result = kSuccess; break; case VP8_STATUS_SUSPENDED: - WebPIDecGetRGB(idec, rowsDecodedPtr, nullptr, nullptr, nullptr); - rowsDecoded = *rowsDecodedPtr; + WebPIDecGetRGB(idec, &rowsDecoded, nullptr, nullptr, nullptr); + *rowsDecodedPtr = rowsDecoded + dstY; result = kIncompleteInput; break; default: return kInvalidInput; } - if (colorXform) { + if (this->colorXform()) { SkColorSpaceXform::ColorFormat dstColorFormat = select_xform_format(dstInfo.colorType()); SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), this->getInfo().alphaType()); - uint32_t* src = (uint32_t*) config.output.u.RGBA.rgba; + uint32_t* xformSrc = (uint32_t*) config.output.u.RGBA.rgba; + void* xformDst = SkTAddOffset(dst, dstBpp * dstX + rowBytes * dstY); size_t srcRowBytes = config.output.u.RGBA.stride; for (int y = 0; y < rowsDecoded; y++) { - colorXform->apply(dst, src, dstInfo.width(), dstColorFormat, - SkColorSpaceXform::kBGRA_8888_ColorFormat, xformAlphaType); - dst = SkTAddOffset(dst, rowBytes); - src = SkTAddOffset(src, srcRowBytes); + SkAssertResult(this->colorXform()->apply(dstColorFormat, xformDst, + SkColorSpaceXform::kBGRA_8888_ColorFormat, xformSrc, scaledWidth, + xformAlphaType)); + xformDst = SkTAddOffset(xformDst, rowBytes); + xformSrc = SkTAddOffset(xformSrc, srcRowBytes); } } diff --git a/gfx/skia/skia/src/codec/SkWebpCodec.h b/gfx/skia/skia/src/codec/SkWebpCodec.h index b9c493f20468..93b60f646e79 100644 --- a/gfx/skia/skia/src/codec/SkWebpCodec.h +++ b/gfx/skia/skia/src/codec/SkWebpCodec.h @@ -10,7 +10,7 @@ #include "SkCodec.h" #include "SkColorSpace.h" -#include "SkEncodedFormat.h" +#include "SkEncodedImageFormat.h" #include "SkImageInfo.h" #include "SkTypes.h" @@ -30,7 +30,7 @@ public: protected: Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor*, int*, int*) override; - SkEncodedFormat onGetEncodedFormat() const override { return kWEBP_SkEncodedFormat; } + SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kWEBP; } SkISize onGetScaledDimensions(float desiredScale) const override; diff --git a/gfx/skia/skia/src/core/Sk4x4f.h b/gfx/skia/skia/src/core/Sk4x4f.h index 9bd91973d373..0fd6b38ef715 100644 --- a/gfx/skia/skia/src/core/Sk4x4f.h +++ b/gfx/skia/skia/src/core/Sk4x4f.h @@ -10,6 +10,8 @@ #include "SkNx.h" +namespace { + struct Sk4x4f { Sk4f r,g,b,a; @@ -150,4 +152,6 @@ inline void Sk4x4f::transpose(uint8_t bs[16]) const { #endif +} // namespace + #endif//Sk4x4f_DEFINED diff --git a/gfx/skia/skia/src/core/SkAAClip.cpp b/gfx/skia/skia/src/core/SkAAClip.cpp index 088ee5584447..467939b4e733 100644 --- a/gfx/skia/skia/src/core/SkAAClip.cpp +++ b/gfx/skia/skia/src/core/SkAAClip.cpp @@ -1037,8 +1037,10 @@ public: void addAntiRectRun(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) { - SkASSERT(fBounds.contains(x + width - 1 + - (leftAlpha > 0 ? 1 : 0) + (rightAlpha > 0 ? 1 : 0), + // According to SkBlitter.cpp, no matter whether leftAlpha is 0 or positive, + // we should always consider [x, x+1] as the left-most column and [x+1, x+1+width] + // as the rect with full alpha. + SkASSERT(fBounds.contains(x + width + (rightAlpha > 0 ? 1 : 0), y + height - 1)); SkASSERT(width >= 0); @@ -1048,6 +1050,9 @@ public: width++; } else if (leftAlpha > 0) { this->addRun(x++, y, leftAlpha, 1); + } else { + // leftAlpha is 0, ignore the left column + x++; } if (rightAlpha == 0xFF) { width++; @@ -1274,9 +1279,17 @@ public: any failure cases that misses may have minor artifacts. */ void blitV(int x, int y, int height, SkAlpha alpha) override { - this->recordMinY(y); - fBuilder->addColumn(x, y, alpha, height); - fLastY = y + height - 1; + if (height == 1) { + // We're still in scan-line order if height is 1 + // This is useful for Analytic AA + const SkAlpha alphas[2] = {alpha, 0}; + const int16_t runs[2] = {1, 0}; + this->blitAntiH(x, y, alphas, runs); + } else { + this->recordMinY(y); + fBuilder->addColumn(x, y, alpha, height); + fLastY = y + height - 1; + } } void blitRect(int x, int y, int width, int height) override { @@ -1318,12 +1331,16 @@ public: } // The supersampler's buffer can be the width of the device, so - // we may have to trim the run to our bounds. If so, we assert that - // the extra spans are always alpha==0 + // we may have to trim the run to our bounds. Previously, we assert that + // the extra spans are always alpha==0. + // However, the analytic AA is too sensitive to precision errors + // so it may have extra spans with very tiny alpha because after several + // arithmatic operations, the edge may bleed the path boundary a little bit. + // Therefore, instead of always asserting alpha==0, we assert alpha < 0x10. int localX = x; int localCount = count; if (x < fLeft) { - SkASSERT(0 == *alpha); + SkASSERT(0x10 > *alpha); int gap = fLeft - x; SkASSERT(gap <= count); localX += gap; @@ -1331,7 +1348,7 @@ public: } int right = x + count; if (right > fRight) { - SkASSERT(0 == *alpha); + SkASSERT(0x10 > *alpha); localCount -= right - fRight; SkASSERT(localCount >= 0); } @@ -1386,21 +1403,31 @@ bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) { clip = &tmpClip; } + // Since we assert that the BuilderBlitter will never blit outside the intersection + // of clip and ibounds, we create this snugClip to be that intersection and send it + // to the scan-converter. + SkRegion snugClip(*clip); + if (path.isInverseFillType()) { ibounds = clip->getBounds(); } else { if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) { return this->setEmpty(); } + snugClip.op(ibounds, SkRegion::kIntersect_Op); } Builder builder(ibounds); BuilderBlitter blitter(&builder); if (doAA) { - SkScan::AntiFillPath(path, *clip, &blitter, true); + if (gSkUseAnalyticAA.load()) { + SkScan::AAAFillPath(path, snugClip, &blitter, true); + } else { + SkScan::AntiFillPath(path, snugClip, &blitter, true); + } } else { - SkScan::FillPath(path, *clip, &blitter); + SkScan::FillPath(path, snugClip, &blitter); } blitter.finish(); diff --git a/gfx/skia/skia/src/core/SkAAClip.h b/gfx/skia/skia/src/core/SkAAClip.h index 7b29ef142aa0..ff7801fbdc40 100644 --- a/gfx/skia/skia/src/core/SkAAClip.h +++ b/gfx/skia/skia/src/core/SkAAClip.h @@ -8,6 +8,7 @@ #ifndef SkAAClip_DEFINED #define SkAAClip_DEFINED +#include "SkAutoMalloc.h" #include "SkBlitter.h" #include "SkRegion.h" @@ -99,7 +100,7 @@ private: class SkAAClipBlitter : public SkBlitter { public: SkAAClipBlitter() : fScanlineScratch(nullptr) {} - virtual ~SkAAClipBlitter(); + ~SkAAClipBlitter() override; void init(SkBlitter* blitter, const SkAAClip* aaclip) { SkASSERT(aaclip && !aaclip->isEmpty()); diff --git a/gfx/skia/skia/src/core/SkATrace.cpp b/gfx/skia/skia/src/core/SkATrace.cpp new file mode 100644 index 000000000000..b40795e4da01 --- /dev/null +++ b/gfx/skia/skia/src/core/SkATrace.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkATrace.h" + +#include "SkTraceEvent.h" + +#ifdef SK_BUILD_FOR_ANDROID +#include +#endif + +SkATrace::SkATrace() : fBeginSection(nullptr), fEndSection(nullptr), fIsEnabled(nullptr) { +#ifdef SK_BUILD_FOR_ANDROID + if (void* lib = dlopen("libandroid.so", RTLD_NOW | RTLD_LOCAL)) { + fBeginSection = (decltype(fBeginSection))dlsym(lib, "ATrace_beginSection"); + fEndSection = (decltype(fEndSection))dlsym(lib, "ATrace_endSection"); + fIsEnabled = (decltype(fIsEnabled))dlsym(lib, "ATrace_isEnabled"); + } +#endif + if (!fIsEnabled) { + fIsEnabled = []{ return false; }; + } +} + +SkEventTracer::Handle SkATrace::addTraceEvent(char phase, + const uint8_t* categoryEnabledFlag, + const char* name, + uint64_t id, + int numArgs, + const char** argNames, + const uint8_t* argTypes, + const uint64_t* argValues, + uint8_t flags) { + if (fIsEnabled()) { + if (TRACE_EVENT_PHASE_COMPLETE == phase || + TRACE_EVENT_PHASE_BEGIN == phase || + TRACE_EVENT_PHASE_INSTANT == phase) { + fBeginSection(name); + } + + if (TRACE_EVENT_PHASE_END == phase || + TRACE_EVENT_PHASE_INSTANT == phase) { + fEndSection(); + } + } + return 0; +} + +void SkATrace::updateTraceEventDuration(const uint8_t* categoryEnabledFlag, + const char* name, + SkEventTracer::Handle handle) { + // This is only ever called from a scoped trace event so we will just end the ATrace section. + if (fIsEnabled()) { + fEndSection(); + } +} + +const uint8_t* SkATrace::getCategoryGroupEnabled(const char* name) { + // Chrome tracing is setup to not repeatly call this function once it has been initialized. So + // we can't use this to do a check for ATrace isEnabled(). Thus we will always return yes here + // and then check to see if ATrace is enabled when beginning and ending a section. + static uint8_t yes = SkEventTracer::kEnabledForRecording_CategoryGroupEnabledFlags; + return &yes; +} + diff --git a/gfx/skia/skia/src/core/SkATrace.h b/gfx/skia/skia/src/core/SkATrace.h new file mode 100644 index 000000000000..f2282f78c190 --- /dev/null +++ b/gfx/skia/skia/src/core/SkATrace.h @@ -0,0 +1,84 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkATrace_DEFINED +#define SkATrace_DEFINED + +#include "SkEventTracer.h" + +/** + * This class is used to support ATrace in android apps. It hooks into the SkEventTracer system. It + * currently supports the macros TRACE_EVENT*, TRACE_EVENT_INSTANT*, and TRANCE_EVENT_BEGIN/END*. + * For versions of these calls that take additoinal args and value pairs we currently just drop them + * and report only the name. Since ATrace is a simple push and pop system (all traces are fully + * nested), if using BEGIN and END you should also make sure your calls are properly nested (i.e. if + * startA is before startB, then endB is before endA). + */ +class SkATrace : public SkEventTracer { +public: + SkATrace(); + + SkEventTracer::Handle addTraceEvent(char phase, + const uint8_t* categoryEnabledFlag, + const char* name, + uint64_t id, + int numArgs, + const char** argNames, + const uint8_t* argTypes, + const uint64_t* argValues, + uint8_t flags) override; + + + void updateTraceEventDuration(const uint8_t* categoryEnabledFlag, + const char* name, + SkEventTracer::Handle handle) override; + + const uint8_t* getCategoryGroupEnabled(const char* name) override; + + const char* getCategoryGroupName(const uint8_t* categoryEnabledFlag) override { + static const char* category = "skiaATrace"; + return category; + } + +private: + void (*fBeginSection)(const char*); + void (*fEndSection)(void); + bool (*fIsEnabled)(void); +}; + + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + + #include + #define ATRACE_ANDROID_FRAMEWORK(fmt, ...) SkAndroidTraceUtil __trace = \ + (SkAndroidTraceUtil::atraceFormatBegin(fmt, ##__VA_ARGS__), SkAndroidTraceUtil()) + + class SkAndroidTraceUtil { + public: + ~SkAndroidTraceUtil() { ATRACE_END(); } + + static void atraceFormatBegin(const char* fmt, ...) { + if (CC_LIKELY(!ATRACE_ENABLED())) return; + + const int BUFFER_SIZE = 256; + va_list ap; + char buf[BUFFER_SIZE]; + + va_start(ap, fmt); + vsnprintf(buf, BUFFER_SIZE, fmt, ap); + va_end(ap); + + ATRACE_BEGIN(buf); + } + }; + +#else + #define ATRACE_ANDROID_FRAMEWORK(fmt, ...) +#endif // SK_BUILD_FOR_ANDROID_FRAMEWORK + +#endif + diff --git a/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.h b/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.h index 17255ab217ab..61f1f1e9bd59 100644 --- a/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.h +++ b/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.h @@ -26,8 +26,6 @@ public: SkAdvancedTypefaceMetrics() : fType(SkAdvancedTypefaceMetrics::kOther_Font) , fFlags((FontFlags)0) - , fLastGlyphID(0) - , fEmSize(0) , fStyle((StyleFlags)0) , fItalicAngle(0) , fAscent(0) @@ -59,9 +57,6 @@ public: }; FontFlags fFlags; // Global font flags. - uint16_t fLastGlyphID; // The last valid glyph ID in the font. - uint16_t fEmSize; // The size of the em box (defines font units). - // These enum values match the values used in the PDF file format. enum StyleFlags : uint32_t { kFixedPitch_Style = 0x00000001, diff --git a/gfx/skia/skia/src/core/SkAnalyticEdge.cpp b/gfx/skia/skia/src/core/SkAnalyticEdge.cpp new file mode 100644 index 000000000000..f6ad62f12fba --- /dev/null +++ b/gfx/skia/skia/src/core/SkAnalyticEdge.cpp @@ -0,0 +1,226 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#include "SkAnalyticEdge.h" +#include "SkFDot6.h" +#include "SkMathPriv.h" + +// This will become a bottleneck for small ovals rendering if we call SkFixedDiv twice here. +// Therefore, we'll let the outter function compute the slope once and send in the value. +// Moreover, we'll compute fDY by quickly lookup the inverse table (if possible). +bool SkAnalyticEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1, SkFixed slope) { + // Since we send in the slope, we can no longer snap y inside this function. + // If we don't send in the slope, or we do some more sophisticated snapping, this function + // could be a performance bottleneck. + SkASSERT(fWinding == 1 || fWinding == -1); + SkASSERT(fCurveCount != 0); + + SkASSERT(y0 <= y1); + + SkFDot6 dx = SkFixedToFDot6(x1 - x0); + SkFDot6 dy = SkFixedToFDot6(y1 - y0); + + // are we a zero-height line? + if (dy == 0) { + return false; + } + + SkASSERT(slope < SK_MaxS32); + + SkFDot6 absSlope = SkAbs32(SkFixedToFDot6(slope)); + fX = x0; + fDX = slope; + fUpperX = x0; + fY = y0; + fUpperY = y0; + fLowerY = y1; + fDY = (dx == 0 || slope == 0) + ? SK_MaxS32 + : absSlope < kInverseTableSize + ? QuickFDot6Inverse::Lookup(absSlope) + : SkAbs32(QuickSkFDot6Div(dy, dx)); + + return true; +} + +bool SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3]) { + fRiteE = nullptr; + + if (!fQEdge.setQuadraticWithoutUpdate(pts, kDefaultAccuracy)) { + return false; + } + fQEdge.fQx >>= kDefaultAccuracy; + fQEdge.fQy >>= kDefaultAccuracy; + fQEdge.fQDx >>= kDefaultAccuracy; + fQEdge.fQDy >>= kDefaultAccuracy; + fQEdge.fQDDx >>= kDefaultAccuracy; + fQEdge.fQDDy >>= kDefaultAccuracy; + fQEdge.fQLastX >>= kDefaultAccuracy; + fQEdge.fQLastY >>= kDefaultAccuracy; + fQEdge.fQy = SnapY(fQEdge.fQy); + fQEdge.fQLastY = SnapY(fQEdge.fQLastY); + + fWinding = fQEdge.fWinding; + fCurveCount = fQEdge.fCurveCount; + fCurveShift = fQEdge.fCurveShift; + + fSnappedX = fQEdge.fQx; + fSnappedY = fQEdge.fQy; + + return this->updateQuadratic(); +} + +bool SkAnalyticQuadraticEdge::updateQuadratic() { + int success = 0; // initialize to fail! + int count = fCurveCount; + SkFixed oldx = fQEdge.fQx; + SkFixed oldy = fQEdge.fQy; + SkFixed dx = fQEdge.fQDx; + SkFixed dy = fQEdge.fQDy; + SkFixed newx, newy, newSnappedX, newSnappedY; + int shift = fCurveShift; + + SkASSERT(count > 0); + + do { + SkFixed slope; + if (--count > 0) + { + newx = oldx + (dx >> shift); + newy = oldy + (dy >> shift); + if (SkAbs32(dy >> shift) >= SK_Fixed1 * 2) { // only snap when dy is large enough + SkFDot6 diffY = SkFixedToFDot6(newy - fSnappedY); + slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY) + : SK_MaxS32; + newSnappedY = SkTMin(fQEdge.fQLastY, SkFixedRoundToFixed(newy)); + newSnappedX = newx - SkFixedMul(slope, newy - newSnappedY); + } else { + newSnappedY = SkTMin(fQEdge.fQLastY, SnapY(newy)); + newSnappedX = newx; + SkFDot6 diffY = SkFixedToFDot6(newSnappedY - fSnappedY); + slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY) + : SK_MaxS32; + } + dx += fQEdge.fQDDx; + dy += fQEdge.fQDDy; + } + else // last segment + { + newx = fQEdge.fQLastX; + newy = fQEdge.fQLastY; + newSnappedY = newy; + newSnappedX = newx; + SkFDot6 diffY = (newy - fSnappedY) >> 10; + slope = diffY ? QuickSkFDot6Div((newx - fSnappedX) >> 10, diffY) : SK_MaxS32; + } + if (slope < SK_MaxS32) { + success = this->updateLine(fSnappedX, fSnappedY, newSnappedX, newSnappedY, slope); + } + oldx = newx; + oldy = newy; + } while (count > 0 && !success); + + SkASSERT(newSnappedY <= fQEdge.fQLastY); + + fQEdge.fQx = newx; + fQEdge.fQy = newy; + fQEdge.fQDx = dx; + fQEdge.fQDy = dy; + fSnappedX = newSnappedX; + fSnappedY = newSnappedY; + fCurveCount = SkToS8(count); + return success; +} + +bool SkAnalyticCubicEdge::setCubic(const SkPoint pts[4]) { + fRiteE = nullptr; + + if (!fCEdge.setCubicWithoutUpdate(pts, kDefaultAccuracy)) { + return false; + } + + fCEdge.fCx >>= kDefaultAccuracy; + fCEdge.fCy >>= kDefaultAccuracy; + fCEdge.fCDx >>= kDefaultAccuracy; + fCEdge.fCDy >>= kDefaultAccuracy; + fCEdge.fCDDx >>= kDefaultAccuracy; + fCEdge.fCDDy >>= kDefaultAccuracy; + fCEdge.fCDDDx >>= kDefaultAccuracy; + fCEdge.fCDDDy >>= kDefaultAccuracy; + fCEdge.fCLastX >>= kDefaultAccuracy; + fCEdge.fCLastY >>= kDefaultAccuracy; + fCEdge.fCy = SnapY(fCEdge.fCy); + fCEdge.fCLastY = SnapY(fCEdge.fCLastY); + + fWinding = fCEdge.fWinding; + fCurveCount = fCEdge.fCurveCount; + fCurveShift = fCEdge.fCurveShift; + fCubicDShift = fCEdge.fCubicDShift; + + fSnappedY = fCEdge.fCy; + + return this->updateCubic(); +} + +bool SkAnalyticCubicEdge::updateCubic() { + int success; + int count = fCurveCount; + SkFixed oldx = fCEdge.fCx; + SkFixed oldy = fCEdge.fCy; + SkFixed newx, newy; + const int ddshift = fCurveShift; + const int dshift = fCubicDShift; + + SkASSERT(count < 0); + + do { + if (++count < 0) { + newx = oldx + (fCEdge.fCDx >> dshift); + fCEdge.fCDx += fCEdge.fCDDx >> ddshift; + fCEdge.fCDDx += fCEdge.fCDDDx; + + newy = oldy + (fCEdge.fCDy >> dshift); + fCEdge.fCDy += fCEdge.fCDDy >> ddshift; + fCEdge.fCDDy += fCEdge.fCDDDy; + } + else { // last segment + newx = fCEdge.fCLastX; + newy = fCEdge.fCLastY; + } + + // we want to say SkASSERT(oldy <= newy), but our finite fixedpoint + // doesn't always achieve that, so we have to explicitly pin it here. + if (newy < oldy) { + newy = oldy; + } + + SkFixed newSnappedY = SnapY(newy); + // we want to SkASSERT(snappedNewY <= fCEdge.fCLastY), but our finite fixedpoint + // doesn't always achieve that, so we have to explicitly pin it here. + if (fCEdge.fCLastY < newSnappedY) { + newSnappedY = fCEdge.fCLastY; + count = 0; + } + + SkFixed slope = SkFixedToFDot6(newSnappedY - fSnappedY) == 0 + ? SK_MaxS32 + : SkFDot6Div(SkFixedToFDot6(newx - oldx), + SkFixedToFDot6(newSnappedY - fSnappedY)); + + success = this->updateLine(oldx, fSnappedY, newx, newSnappedY, slope); + + oldx = newx; + oldy = newy; + fSnappedY = newSnappedY; + } while (count < 0 && !success); + + fCEdge.fCx = newx; + fCEdge.fCy = newy; + fCurveCount = SkToS8(count); + return success; +} diff --git a/gfx/skia/skia/src/core/SkAnalyticEdge.h b/gfx/skia/skia/src/core/SkAnalyticEdge.h new file mode 100644 index 000000000000..6c75d157cea9 --- /dev/null +++ b/gfx/skia/skia/src/core/SkAnalyticEdge.h @@ -0,0 +1,181 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAnalyticEdge_DEFINED +#define SkAnalyticEdge_DEFINED + +#include "SkEdge.h" + +struct SkAnalyticEdge { + // Similar to SkEdge, the conic edges will be converted to quadratic edges + enum Type { + kLine_Type, + kQuad_Type, + kCubic_Type + }; + + SkAnalyticEdge* fNext; + SkAnalyticEdge* fPrev; + + // During aaa_walk_edges, if this edge is a left edge, + // then fRiteE is its corresponding right edge. Otherwise it's nullptr. + SkAnalyticEdge* fRiteE; + + SkFixed fX; + SkFixed fDX; + SkFixed fUpperX; // The x value when y = fUpperY + SkFixed fY; // The current y + SkFixed fUpperY; // The upper bound of y (our edge is from y = fUpperY to y = fLowerY) + SkFixed fLowerY; // The lower bound of y (our edge is from y = fUpperY to y = fLowerY) + SkFixed fDY; // abs(1/fDX); may be SK_MaxS32 when fDX is close to 0. + // fDY is only used for blitting trapezoids. + + SkFixed fSavedX; // For deferred blitting + SkFixed fSavedY; // For deferred blitting + SkFixed fSavedDY; // For deferred blitting + + int8_t fCurveCount; // only used by kQuad(+) and kCubic(-) + uint8_t fCurveShift; // appled to all Dx/DDx/DDDx except for fCubicDShift exception + uint8_t fCubicDShift; // applied to fCDx and fCDy only in cubic + int8_t fWinding; // 1 or -1 + + static const int kDefaultAccuracy = 2; // default accuracy for snapping + + static inline SkFixed SnapY(SkFixed y) { + const int accuracy = kDefaultAccuracy; + // This approach is safer than left shift, round, then right shift + return ((unsigned)y + (SK_Fixed1 >> (accuracy + 1))) >> (16 - accuracy) << (16 - accuracy); + } + + // Update fX, fY of this edge so fY = y + inline void goY(SkFixed y) { + if (y == fY + SK_Fixed1) { + fX = fX + fDX; + fY = y; + } else if (y != fY) { + // Drop lower digits as our alpha only has 8 bits + // (fDX and y - fUpperY may be greater than SK_Fixed1) + fX = fUpperX + SkFixedMul(fDX, y - fUpperY); + fY = y; + } + } + + inline void goY(SkFixed y, int yShift) { + SkASSERT(yShift >= 0 && yShift <= kDefaultAccuracy); + SkASSERT(fDX == 0 || y - fY == SK_Fixed1 >> yShift); + fY = y; + fX += fDX >> yShift; + } + + inline void saveXY(SkFixed x, SkFixed y, SkFixed dY) { + fSavedX = x; + fSavedY = y; + fSavedDY = dY; + } + + inline bool setLine(const SkPoint& p0, const SkPoint& p1); + inline bool updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by, SkFixed slope); + +#ifdef SK_DEBUG + void dump() const { + SkDebugf("edge: upperY:%d lowerY:%d y:%g x:%g dx:%g w:%d\n", + fUpperY, fLowerY, SkFixedToFloat(fY), SkFixedToFloat(fX), + SkFixedToFloat(fDX), fWinding); + } + + void validate() const { + SkASSERT(fPrev && fNext); + SkASSERT(fPrev->fNext == this); + SkASSERT(fNext->fPrev == this); + + SkASSERT(fUpperY < fLowerY); + SkASSERT(SkAbs32(fWinding) == 1); + } +#endif +}; + +struct SkAnalyticQuadraticEdge : public SkAnalyticEdge { + SkQuadraticEdge fQEdge; + + // snap y to integer points in the middle of the curve to accelerate AAA path filling + SkFixed fSnappedX, fSnappedY; + + bool setQuadratic(const SkPoint pts[3]); + bool updateQuadratic(); + inline void keepContinuous() { + // We use fX as the starting x to ensure the continuouty. + // Without it, we may break the sorted edge list. + SkASSERT(SkAbs32(fX - SkFixedMul(fY - fSnappedY, fDX) - fSnappedX) < SK_Fixed1); + SkASSERT(SkAbs32(fY - fSnappedY) < SK_Fixed1); // This may differ due to smooth jump + fSnappedX = fX; + fSnappedY = fY; + } +}; + +struct SkAnalyticCubicEdge : public SkAnalyticEdge { + SkCubicEdge fCEdge; + + SkFixed fSnappedY; // to make sure that y is increasing with smooth jump and snapping + + bool setCubic(const SkPoint pts[4]); + bool updateCubic(); + inline void keepContinuous() { + SkASSERT(SkAbs32(fX - SkFixedMul(fDX, fY - SnapY(fCEdge.fCy)) - fCEdge.fCx) < SK_Fixed1); + fCEdge.fCx = fX; + fSnappedY = fY; + } +}; + +bool SkAnalyticEdge::setLine(const SkPoint& p0, const SkPoint& p1) { +#if defined(__arm__) + asm volatile("dsb"); // crbug.com/710131 +#endif + fRiteE = nullptr; + + // We must set X/Y using the same way (e.g., times 4, to FDot6, then to Fixed) as Quads/Cubics. + // Otherwise the order of the edge might be wrong due to precision limit. + const int accuracy = kDefaultAccuracy; + const int multiplier = (1 << kDefaultAccuracy); + SkFixed x0 = SkFDot6ToFixed(SkScalarToFDot6(p0.fX * multiplier)) >> accuracy; + SkFixed y0 = SnapY(SkFDot6ToFixed(SkScalarToFDot6(p0.fY * multiplier)) >> accuracy); + SkFixed x1 = SkFDot6ToFixed(SkScalarToFDot6(p1.fX * multiplier)) >> accuracy; + SkFixed y1 = SnapY(SkFDot6ToFixed(SkScalarToFDot6(p1.fY * multiplier)) >> accuracy); + + int winding = 1; + + if (y0 > y1) { + SkTSwap(x0, x1); + SkTSwap(y0, y1); + winding = -1; + } + + // are we a zero-height line? + SkFDot6 dy = SkFixedToFDot6(y1 - y0); + if (dy == 0) { + return false; + } + SkFDot6 dx = SkFixedToFDot6(x1 - x0); + SkFixed slope = QuickSkFDot6Div(dx, dy); + SkFixed absSlope = SkAbs32(slope); + + fX = x0; + fDX = slope; + fUpperX = x0; + fY = y0; + fUpperY = y0; + fLowerY = y1; + fDY = dx == 0 || slope == 0 ? SK_MaxS32 : absSlope < kInverseTableSize + ? QuickFDot6Inverse::Lookup(absSlope) + : SkAbs32(QuickSkFDot6Div(dy, dx)); + fCurveCount = 0; + fWinding = SkToS8(winding); + fCurveShift = 0; + + return true; +} + +#endif diff --git a/gfx/skia/skia/src/core/SkAntiRun.h b/gfx/skia/skia/src/core/SkAntiRun.h index 8214e28d5b7e..8b19036d6c96 100644 --- a/gfx/skia/skia/src/core/SkAntiRun.h +++ b/gfx/skia/skia/src/core/SkAntiRun.h @@ -21,6 +21,12 @@ public: int16_t* fRuns; uint8_t* fAlpha; + // Return 0-255 given 0-256 + static inline SkAlpha CatchOverflow(int alpha) { + SkASSERT(alpha >= 0 && alpha <= 256); + return alpha - (alpha >> 8); + } + /// Returns true if the scanline contains only a single run, /// of alpha value 0. bool empty() const { @@ -79,7 +85,7 @@ public: runs += x; x = 0; do { - alpha[0] = SkToU8(alpha[0] + maxValue); + alpha[0] = SkToU8(CatchOverflow(alpha[0] + maxValue)); int n = runs[0]; SkASSERT(n <= middleCount); alpha += n; diff --git a/gfx/skia/skia/src/core/SkArenaAlloc.cpp b/gfx/skia/skia/src/core/SkArenaAlloc.cpp new file mode 100644 index 000000000000..eca3aa97d761 --- /dev/null +++ b/gfx/skia/skia/src/core/SkArenaAlloc.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include "SkArenaAlloc.h" + +static char* end_chain(char*) { return nullptr; } + +char* SkArenaAlloc::SkipPod(char* footerEnd) { + char* objEnd = footerEnd - (sizeof(Footer) + sizeof(int32_t)); + int32_t skip; + memmove(&skip, objEnd, sizeof(int32_t)); + return objEnd - skip; +} + +void SkArenaAlloc::RunDtorsOnBlock(char* footerEnd) { + while (footerEnd != nullptr) { + Footer footer; + memcpy(&footer, footerEnd - sizeof(Footer), sizeof(Footer)); + + FooterAction* action = (FooterAction*)(footer >> 6); + ptrdiff_t padding = footer & 63; + + footerEnd = action(footerEnd) - padding; + } +} + +char* SkArenaAlloc::NextBlock(char* footerEnd) { + char* objEnd = footerEnd - (sizeof(Footer) + sizeof(char*)); + char* next; + memmove(&next, objEnd, sizeof(char*)); + RunDtorsOnBlock(next); + delete [] objEnd; + return nullptr; +} + +SkArenaAlloc::SkArenaAlloc(char* block, size_t size, size_t extraSize) + : fDtorCursor {block} + , fCursor {block} + , fEnd {block + SkTo(size)} + , fFirstBlock {block} + , fFirstSize {SkTo(size)} + , fExtraSize {SkTo(extraSize)} +{ + if (size < sizeof(Footer)) { + fEnd = fCursor = fDtorCursor = nullptr; + } + + if (fCursor != nullptr) { + this->installFooter(end_chain, 0); + } +} + +SkArenaAlloc::~SkArenaAlloc() { + RunDtorsOnBlock(fDtorCursor); +} + +void SkArenaAlloc::reset() { + this->~SkArenaAlloc(); + new (this) SkArenaAlloc{fFirstBlock, fFirstSize, fExtraSize}; +} + +void SkArenaAlloc::installFooter(FooterAction* action, uint32_t padding) { + SkASSERT(padding < 64); + int64_t actionInt = (int64_t)(intptr_t)action; + + // The top 14 bits should be either all 0s or all 1s. Check this. + SkASSERT((actionInt << 6) >> 6 == actionInt); + Footer encodedFooter = (actionInt << 6) | padding; + memmove(fCursor, &encodedFooter, sizeof(Footer)); + fCursor += sizeof(Footer); + fDtorCursor = fCursor; +} + +void SkArenaAlloc::installPtrFooter(FooterAction* action, char* ptr, uint32_t padding) { + memmove(fCursor, &ptr, sizeof(char*)); + fCursor += sizeof(char*); + this->installFooter(action, padding); +} + +void SkArenaAlloc::installUint32Footer(FooterAction* action, uint32_t value, uint32_t padding) { + memmove(fCursor, &value, sizeof(uint32_t)); + fCursor += sizeof(uint32_t); + this->installFooter(action, padding); +} + +void SkArenaAlloc::ensureSpace(uint32_t size, uint32_t alignment) { + constexpr uint32_t headerSize = sizeof(Footer) + sizeof(ptrdiff_t); + // The chrome c++ library we use does not define std::max_align_t. + // This must be conservative to add the right amount of extra memory to handle the alignment + // padding. + constexpr uint32_t alignof_max_align_t = 8; + uint32_t objSizeAndOverhead = size + headerSize + sizeof(Footer); + if (alignment > alignof_max_align_t) { + objSizeAndOverhead += alignment - 1; + } + + uint32_t allocationSize = std::max(objSizeAndOverhead, fExtraSize * fFib0); + fFib0 += fFib1; + std::swap(fFib0, fFib1); + + // Round up to a nice size. If > 32K align to 4K boundary else up to max_align_t. The > 32K + // heuristic is from the JEMalloc behavior. + { + uint32_t mask = allocationSize > (1 << 15) ? (1 << 12) - 1 : 16 - 1; + allocationSize = (allocationSize + mask) & ~mask; + } + + char* newBlock = new char[allocationSize]; + + auto previousDtor = fDtorCursor; + fCursor = newBlock; + fDtorCursor = newBlock; + fEnd = fCursor + allocationSize; + this->installPtrFooter(NextBlock, previousDtor, 0); +} + +char* SkArenaAlloc::allocObject(uint32_t size, uint32_t alignment) { + uintptr_t mask = alignment - 1; + char* objStart = (char*)((uintptr_t)(fCursor + mask) & ~mask); + if ((ptrdiff_t)size > fEnd - objStart) { + this->ensureSpace(size, alignment); + objStart = (char*)((uintptr_t)(fCursor + mask) & ~mask); + } + return objStart; +} + +char* SkArenaAlloc::allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment) { + uintptr_t mask = alignment - 1; + +restart: + uint32_t skipOverhead = 0; + bool needsSkipFooter = fCursor != fDtorCursor; + if (needsSkipFooter) { + skipOverhead = sizeof(Footer) + sizeof(uint32_t); + } + char* objStart = (char*)((uintptr_t)(fCursor + skipOverhead + mask) & ~mask); + uint32_t totalSize = sizeIncludingFooter + skipOverhead; + + if ((ptrdiff_t)totalSize > fEnd - objStart) { + this->ensureSpace(totalSize, alignment); + goto restart; + } + + SkASSERT((ptrdiff_t)totalSize <= fEnd - objStart); + + // Install a skip footer if needed, thus terminating a run of POD data. The calling code is + // responsible for installing the footer after the object. + if (needsSkipFooter) { + this->installUint32Footer(SkipPod, SkTo(fCursor - fDtorCursor), 0); + } + + return objStart; +} + diff --git a/gfx/skia/skia/src/core/SkArenaAlloc.h b/gfx/skia/skia/src/core/SkArenaAlloc.h new file mode 100644 index 000000000000..494696ce768d --- /dev/null +++ b/gfx/skia/skia/src/core/SkArenaAlloc.h @@ -0,0 +1,205 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFixedAlloc_DEFINED +#define SkFixedAlloc_DEFINED + +#include "SkRefCnt.h" +#include "SkTFitsIn.h" +#include "SkTypes.h" +#include +#include +#include +#include +#include + +// SkArenaAlloc allocates object and destroys the allocated objects when destroyed. It's designed +// to minimize the number of underlying block allocations. SkArenaAlloc allocates first out of an +// (optional) user-provided block of memory, and when that's exhausted it allocates on the heap, +// starting with an allocation of extraSize bytes. If your data (plus a small overhead) fits in +// the user-provided block, SkArenaAlloc never uses the heap, and if it fits in extraSize bytes, +// it'll use the heap only once. If you pass extraSize = 0, it allocates blocks for each call to +// make. +// +// Examples: +// +// char block[mostCasesSize]; +// SkArenaAlloc arena(block, almostAllCasesSize); +// +// If mostCasesSize is too large for the stack, you can use the following pattern. +// +// std::unique_ptr block{new char[mostCasesSize]}; +// SkArenaAlloc arena(block.get(), mostCasesSize, almostAllCasesSize); +// +// If the program only sometimes allocates memory, use the following. +// +// SkArenaAlloc arena(nullptr, 0, almostAllCasesSize); +// +// The storage does not necessarily need to be on the stack. Embedding the storage in a class also +// works. +// +// class Foo { +// char storage[mostCasesSize]; +// SkArenaAlloc arena (storage, almostAllCasesSize); +// }; +// +// In addition, the system is optimized to handle POD data including arrays of PODs (where +// POD is really data with no destructors). For POD data it has zero overhead per item, and a +// typical block overhead of 8 bytes. For non-POD objects there is a per item overhead of 4 bytes. +// For arrays of non-POD objects there is a per array overhead of typically 8 bytes. There is an +// addition overhead when switching from POD data to non-POD data of typically 8 bytes. +// +// If additional blocks are needed they are increased exponentially. This strategy bounds the +// recursion of the RunDtorsOnBlock to be limited to O(log size-of-memory). Block size grow using +// the Fibonacci sequence which means that for 2^32 memory there are 48 allocations, and for 2^48 +// there are 71 allocations. +class SkArenaAlloc { +public: + SkArenaAlloc(char* block, size_t size, size_t extraSize = 0); + + template + SkArenaAlloc(char (&block)[kSize], size_t extraSize = kSize) + : SkArenaAlloc(block, kSize, extraSize) + {} + + SkArenaAlloc(size_t extraSize) + : SkArenaAlloc(nullptr, 0, extraSize) + {} + + ~SkArenaAlloc(); + + template + T* make(Args&&... args) { + uint32_t size = SkTo(sizeof(T)); + uint32_t alignment = SkTo(alignof(T)); + char* objStart; + if (skstd::is_trivially_destructible::value) { + objStart = this->allocObject(size, alignment); + fCursor = objStart + size; + } else { + objStart = this->allocObjectWithFooter(size + sizeof(Footer), alignment); + // Can never be UB because max value is alignof(T). + uint32_t padding = SkTo(objStart - fCursor); + + // Advance to end of object to install footer. + fCursor = objStart + size; + FooterAction* releaser = [](char* objEnd) { + char* objStart = objEnd - (sizeof(T) + sizeof(Footer)); + ((T*)objStart)->~T(); + return objStart; + }; + this->installFooter(releaser, padding); + } + + // This must be last to make objects with nested use of this allocator work. + return new(objStart) T(std::forward(args)...); + } + + template + sk_sp makeSkSp(Args&&... args) { + SkASSERT(SkTFitsIn(sizeof(T))); + + // The arena takes a ref for itself to account for the destructor. The sk_sp count can't + // become zero or the sk_sp will try to call free on the pointer. + return sk_sp(SkRef(this->make(std::forward(args)...))); + } + + template + T* makeArrayDefault(size_t count) { + uint32_t safeCount = SkTo(count); + T* array = (T*)this->commonArrayAlloc(safeCount); + + // If T is primitive then no initialization takes place. + for (size_t i = 0; i < safeCount; i++) { + new (&array[i]) T; + } + return array; + } + + template + T* makeArray(size_t count) { + uint32_t safeCount = SkTo(count); + T* array = (T*)this->commonArrayAlloc(safeCount); + + // If T is primitive then the memory is initialized. For example, an array of chars will + // be zeroed. + for (size_t i = 0; i < safeCount; i++) { + new (&array[i]) T(); + } + return array; + } + + // Destroy all allocated objects, free any heap allocations. + void reset(); + +private: + using Footer = int64_t; + using FooterAction = char* (char*); + + static char* SkipPod(char* footerEnd); + static void RunDtorsOnBlock(char* footerEnd); + static char* NextBlock(char* footerEnd); + + void installFooter(FooterAction* releaser, uint32_t padding); + void installUint32Footer(FooterAction* action, uint32_t value, uint32_t padding); + void installPtrFooter(FooterAction* action, char* ptr, uint32_t padding); + + void ensureSpace(uint32_t size, uint32_t alignment); + + char* allocObject(uint32_t size, uint32_t alignment); + + char* allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment); + + template + char* commonArrayAlloc(uint32_t count) { + char* objStart; + uint32_t arraySize = SkTo(count * sizeof(T)); + uint32_t alignment = SkTo(alignof(T)); + + if (skstd::is_trivially_destructible::value) { + objStart = this->allocObject(arraySize, alignment); + fCursor = objStart + arraySize; + } else { + uint32_t totalSize = arraySize + sizeof(Footer) + sizeof(uint32_t); + objStart = this->allocObjectWithFooter(totalSize, alignment); + + // Can never be UB because max value is alignof(T). + uint32_t padding = SkTo(objStart - fCursor); + + // Advance to end of array to install footer.? + fCursor = objStart + arraySize; + this->installUint32Footer( + [](char* footerEnd) { + char* objEnd = footerEnd - (sizeof(Footer) + sizeof(uint32_t)); + uint32_t count; + memmove(&count, objEnd, sizeof(uint32_t)); + char* objStart = objEnd - count * sizeof(T); + T* array = (T*) objStart; + for (uint32_t i = 0; i < count; i++) { + array[i].~T(); + } + return objStart; + }, + SkTo(count), + padding); + } + + return objStart; + } + + char* fDtorCursor; + char* fCursor; + char* fEnd; + char* const fFirstBlock; + const uint32_t fFirstSize; + const uint32_t fExtraSize; + // Use the Fibonacci sequence as the growth factor for block size. The size of the block + // allocated is fFib0 * fExtraSize. Using 2 ^ n * fExtraSize had too much slop for Android. + uint32_t fFib0 {1}, fFib1 {1}; +}; + +#endif//SkFixedAlloc_DEFINED diff --git a/gfx/skia/skia/src/core/SkAutoMalloc.h b/gfx/skia/skia/src/core/SkAutoMalloc.h new file mode 100644 index 000000000000..8672cd86f9cc --- /dev/null +++ b/gfx/skia/skia/src/core/SkAutoMalloc.h @@ -0,0 +1,175 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAutoMalloc_DEFINED +#define SkAutoMalloc_DEFINED + +#include "SkTypes.h" +#include "SkMalloc.h" + +#include + +/** + * Manage an allocated block of heap memory. This object is the sole manager of + * the lifetime of the block, so the caller must not call sk_free() or delete + * on the block, unless release() was called. + */ +class SkAutoMalloc : SkNoncopyable { +public: + explicit SkAutoMalloc(size_t size = 0) + : fPtr(size ? sk_malloc_throw(size) : nullptr), fSize(size) {} + + /** + * Passed to reset to specify what happens if the requested size is smaller + * than the current size (and the current block was dynamically allocated). + */ + enum OnShrink { + /** + * If the requested size is smaller than the current size, and the + * current block is dynamically allocated, free the old block and + * malloc a new block of the smaller size. + */ + kAlloc_OnShrink, + + /** + * If the requested size is smaller than the current size, and the + * current block is dynamically allocated, just return the old + * block. + */ + kReuse_OnShrink + }; + + /** + * Reallocates the block to a new size. The ptr may or may not change. + */ + void* reset(size_t size = 0, OnShrink shrink = kAlloc_OnShrink) { + if (size != fSize && (size > fSize || kReuse_OnShrink != shrink)) { + fPtr.reset(size ? sk_malloc_throw(size) : nullptr); + fSize = size; + } + return fPtr.get(); + } + + /** + * Return the allocated block. + */ + void* get() { return fPtr.get(); } + const void* get() const { return fPtr.get(); } + + /** Transfer ownership of the current ptr to the caller, setting the + internal reference to null. Note the caller is reponsible for calling + sk_free on the returned address. + */ + void* release() { + fSize = 0; + return fPtr.release(); + } + +private: + struct WrapFree { + void operator()(void* p) { sk_free(p); } + }; + std::unique_ptr fPtr; + size_t fSize; // can be larger than the requested size (see kReuse) +}; +#define SkAutoMalloc(...) SK_REQUIRE_LOCAL_VAR(SkAutoMalloc) + +/** + * Manage an allocated block of memory. If the requested size is <= kSizeRequested (or slightly + * more), then the allocation will come from the stack rather than the heap. This object is the + * sole manager of the lifetime of the block, so the caller must not call sk_free() or delete on + * the block. + */ +template class SkAutoSMalloc : SkNoncopyable { +public: + /** + * Creates initially empty storage. get() returns a ptr, but it is to a zero-byte allocation. + * Must call reset(size) to return an allocated block. + */ + SkAutoSMalloc() { + fPtr = fStorage; + fSize = kSize; + } + + /** + * Allocate a block of the specified size. If size <= kSizeRequested (or slightly more), then + * the allocation will come from the stack, otherwise it will be dynamically allocated. + */ + explicit SkAutoSMalloc(size_t size) { + fPtr = fStorage; + fSize = kSize; + this->reset(size); + } + + /** + * Free the allocated block (if any). If the block was small enough to have been allocated on + * the stack, then this does nothing. + */ + ~SkAutoSMalloc() { + if (fPtr != (void*)fStorage) { + sk_free(fPtr); + } + } + + /** + * Return the allocated block. May return non-null even if the block is of zero size. Since + * this may be on the stack or dynamically allocated, the caller must not call sk_free() on it, + * but must rely on SkAutoSMalloc to manage it. + */ + void* get() const { return fPtr; } + + /** + * Return a new block of the requested size, freeing (as necessary) any previously allocated + * block. As with the constructor, if size <= kSizeRequested (or slightly more) then the return + * block may be allocated locally, rather than from the heap. + */ + void* reset(size_t size, + SkAutoMalloc::OnShrink shrink = SkAutoMalloc::kAlloc_OnShrink, + bool* didChangeAlloc = nullptr) { + size = (size < kSize) ? kSize : size; + bool alloc = size != fSize && (SkAutoMalloc::kAlloc_OnShrink == shrink || size > fSize); + if (didChangeAlloc) { + *didChangeAlloc = alloc; + } + if (alloc) { + if (fPtr != (void*)fStorage) { + sk_free(fPtr); + } + + if (size == kSize) { + SkASSERT(fPtr != fStorage); // otherwise we lied when setting didChangeAlloc. + fPtr = fStorage; + } else { + fPtr = sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_TEMP); + } + + fSize = size; + } + SkASSERT(fSize >= size && fSize >= kSize); + SkASSERT((fPtr == fStorage) || fSize > kSize); + return fPtr; + } + +private: + // Align up to 32 bits. + static const size_t kSizeAlign4 = SkAlign4(kSizeRequested); +#if defined(GOOGLE3) + // Stack frame size is limited for GOOGLE3. 4k is less than the actual max, but some functions + // have multiple large stack allocations. + static const size_t kMaxBytes = 4 * 1024; + static const size_t kSize = kSizeRequested > kMaxBytes ? kMaxBytes : kSizeAlign4; +#else + static const size_t kSize = kSizeAlign4; +#endif + + void* fPtr; + size_t fSize; // can be larger than the requested size (see kReuse) + uint32_t fStorage[kSize >> 2]; +}; +// Can't guard the constructor because it's a template class. + +#endif diff --git a/gfx/skia/skia/src/core/SkAutoPixmapStorage.h b/gfx/skia/skia/src/core/SkAutoPixmapStorage.h index 379bf420b0ba..66c5655e5459 100644 --- a/gfx/skia/skia/src/core/SkAutoPixmapStorage.h +++ b/gfx/skia/skia/src/core/SkAutoPixmapStorage.h @@ -8,6 +8,7 @@ #ifndef SkAutoPixmapStorage_DEFINED #define SkAutoPixmapStorage_DEFINED +#include "SkMalloc.h" #include "SkPixmap.h" class SK_API SkAutoPixmapStorage : public SkPixmap { diff --git a/gfx/skia/skia/src/core/SkBigPicture.cpp b/gfx/skia/skia/src/core/SkBigPicture.cpp index 2a2e438fd6a3..1281b5bc9f07 100644 --- a/gfx/skia/skia/src/core/SkBigPicture.cpp +++ b/gfx/skia/skia/src/core/SkBigPicture.cpp @@ -28,9 +28,7 @@ void SkBigPicture::playback(SkCanvas* canvas, AbortCallback* callback) const { SkASSERT(canvas); // If the query contains the whole picture, don't bother with the BBH. - SkRect clipBounds = { 0, 0, 0, 0 }; - (void)canvas->getClipBounds(&clipBounds); - const bool useBBH = !clipBounds.contains(this->cullRect()); + const bool useBBH = !canvas->getLocalClipBounds().contains(this->cullRect()); SkRecordDraw(*fRecord, canvas, diff --git a/gfx/skia/skia/src/core/SkBigPicture.h b/gfx/skia/skia/src/core/SkBigPicture.h index c5dfda95eb56..265df397d107 100644 --- a/gfx/skia/skia/src/core/SkBigPicture.h +++ b/gfx/skia/skia/src/core/SkBigPicture.h @@ -54,8 +54,8 @@ public: int stop, const SkMatrix& initialCTM) const; // Used by GrRecordReplaceDraw - const SkBBoxHierarchy* bbh() const { return fBBH; } - const SkRecord* record() const { return fRecord; } + const SkBBoxHierarchy* bbh() const { return fBBH.get(); } + const SkRecord* record() const { return fRecord.get(); } private: struct Analysis { @@ -72,13 +72,13 @@ private: int drawableCount() const; SkPicture const* const* drawablePicts() const; - const SkRect fCullRect; - const size_t fApproxBytesUsedBySubPictures; - mutable SkOnce fAnalysisOnce; - mutable Analysis fAnalysis; - SkAutoTUnref fRecord; - SkAutoTDelete fDrawablePicts; - SkAutoTUnref fBBH; + const SkRect fCullRect; + const size_t fApproxBytesUsedBySubPictures; + mutable SkOnce fAnalysisOnce; + mutable Analysis fAnalysis; + sk_sp fRecord; + std::unique_ptr fDrawablePicts; + sk_sp fBBH; }; #endif//SkBigPicture_DEFINED diff --git a/gfx/skia/skia/src/core/SkBitmap.cpp b/gfx/skia/skia/src/core/SkBitmap.cpp index c62f5f391b47..a06d13319270 100644 --- a/gfx/skia/skia/src/core/SkBitmap.cpp +++ b/gfx/skia/skia/src/core/SkBitmap.cpp @@ -8,9 +8,11 @@ #include "SkAtomics.h" #include "SkBitmap.h" #include "SkColorPriv.h" -#include "SkConfig8888.h" +#include "SkConvertPixels.h" #include "SkData.h" #include "SkFilterQuality.h" +#include "SkHalf.h" +#include "SkImageInfoPriv.h" #include "SkMallocPixelRef.h" #include "SkMask.h" #include "SkMath.h" @@ -21,6 +23,7 @@ #include "SkTemplates.h" #include "SkUnPreMultiply.h" #include "SkWriteBuffer.h" +#include "SkWritePixelsRec.h" #include @@ -29,18 +32,48 @@ static bool reset_return_false(SkBitmap* bm) { return false; } -SkBitmap::SkBitmap() { - sk_bzero(this, sizeof(*this)); -} +SkBitmap::SkBitmap() + : fPixelLockCount(0) + , fPixels (nullptr) + , fColorTable (nullptr) + , fPixelRefOrigin{0, 0} + , fRowBytes (0) + , fFlags (0) {} -SkBitmap::SkBitmap(const SkBitmap& src) { +// copy pixelref, but don't copy lock. +SkBitmap::SkBitmap(const SkBitmap& src) + : fPixelRef (src.fPixelRef) + , fPixelLockCount(0) + , fPixels (nullptr) + , fColorTable (nullptr) + , fPixelRefOrigin(src.fPixelRefOrigin) + , fInfo (src.fInfo) + , fRowBytes (src.fRowBytes) + , fFlags (src.fFlags) +{ SkDEBUGCODE(src.validate();) - sk_bzero(this, sizeof(*this)); - *this = src; SkDEBUGCODE(this->validate();) } -SkBitmap::SkBitmap(SkBitmap&& other) : SkBitmap() { this->swap(other); } +// take lock and lockcount from other. +SkBitmap::SkBitmap(SkBitmap&& other) + : fPixelRef (std::move(other.fPixelRef)) + , fPixelLockCount (other.fPixelLockCount) + , fPixels (other.fPixels) + , fColorTable (other.fColorTable) + , fPixelRefOrigin (other.fPixelRefOrigin) + , fInfo (std::move(other.fInfo)) + , fRowBytes (other.fRowBytes) + , fFlags (other.fFlags) { + SkASSERT(!other.fPixelRef); + other.fInfo.reset(); + other.fPixelLockCount = 0; + other.fPixels = nullptr; + other.fColorTable = nullptr; + other.fPixelRefOrigin = SkIPoint{0, 0}; + other.fRowBytes = 0; + other.fFlags = 0; +} SkBitmap::~SkBitmap() { SkDEBUGCODE(this->validate();) @@ -50,46 +83,47 @@ SkBitmap::~SkBitmap() { SkBitmap& SkBitmap::operator=(const SkBitmap& src) { if (this != &src) { this->freePixels(); - this->fPixelRef = SkSafeRef(src.fPixelRef); - if (this->fPixelRef) { - // ignore the values if we have a pixelRef - this->fPixels = nullptr; - this->fColorTable = nullptr; - } else { - this->fPixels = src.fPixels; - this->fColorTable = src.fColorTable; - } - // we reset our locks if we get blown away - this->fPixelLockCount = 0; - - this->fPixelRefOrigin = src.fPixelRefOrigin; - this->fInfo = src.fInfo; - this->fRowBytes = src.fRowBytes; - this->fFlags = src.fFlags; + SkASSERT(!fPixels); + SkASSERT(!fColorTable); + SkASSERT(!fPixelLockCount); + fPixelRef = src.fPixelRef; + fPixelRefOrigin = src.fPixelRefOrigin; + fInfo = src.fInfo; + fRowBytes = src.fRowBytes; + fFlags = src.fFlags; } - SkDEBUGCODE(this->validate();) return *this; } SkBitmap& SkBitmap::operator=(SkBitmap&& other) { if (this != &other) { - this->swap(other); - other.reset(); + this->freePixels(); + SkASSERT(!fPixels); + SkASSERT(!fColorTable); + SkASSERT(!fPixelLockCount); + fPixelRef = std::move(other.fPixelRef); + fInfo = std::move(other.fInfo); + fPixelLockCount = other.fPixelLockCount; + fPixels = other.fPixels; + fColorTable = other.fColorTable; + fPixelRefOrigin = other.fPixelRefOrigin; + fRowBytes = other.fRowBytes; + fFlags = other.fFlags; + SkASSERT(!other.fPixelRef); + other.fInfo.reset(); + other.fPixelLockCount = 0; + other.fPixels = nullptr; + other.fColorTable = nullptr; + other.fPixelRefOrigin = SkIPoint{0, 0}; + other.fRowBytes = 0; + other.fFlags = 0; } return *this; } void SkBitmap::swap(SkBitmap& other) { - SkTSwap(fColorTable, other.fColorTable); - SkTSwap(fPixelRef, other.fPixelRef); - SkTSwap(fPixelRefOrigin, other.fPixelRefOrigin); - SkTSwap(fPixelLockCount, other.fPixelLockCount); - SkTSwap(fPixels, other.fPixels); - SkTSwap(fInfo, other.fInfo); - SkTSwap(fRowBytes, other.fRowBytes); - SkTSwap(fFlags, other.fFlags); - + SkTSwap(*this, other); SkDEBUGCODE(this->validate();) } @@ -181,7 +215,7 @@ void SkBitmap::updatePixelsFromRef() const { } } -SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) { +void SkBitmap::setPixelRef(sk_sp pr, int dx, int dy) { #ifdef SK_DEBUG if (pr) { if (kUnknown_SkColorType != fInfo.colorType()) { @@ -217,15 +251,13 @@ SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) { if (fPixelRef != pr) { this->freePixels(); - SkASSERT(nullptr == fPixelRef); + SkASSERT(!fPixelRef); - SkSafeRef(pr); - fPixelRef = pr; + fPixelRef = std::move(pr); this->updatePixelsFromRef(); } SkDEBUGCODE(this->validate();) - return pr; } void SkBitmap::lockPixels() const { @@ -237,7 +269,7 @@ void SkBitmap::lockPixels() const { } void SkBitmap::unlockPixels() const { - SkASSERT(nullptr == fPixelRef || fPixelLockCount > 0); + SkASSERT(!fPixelRef || fPixelLockCount > 0); if (fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) { fPixelRef->unlockPixels(); @@ -246,29 +278,21 @@ void SkBitmap::unlockPixels() const { SkDEBUGCODE(this->validate();) } -bool SkBitmap::lockPixelsAreWritable() const { - return (fPixelRef) ? fPixelRef->lockPixelsAreWritable() : false; -} - void SkBitmap::setPixels(void* p, SkColorTable* ctable) { if (nullptr == p) { - this->setPixelRef(nullptr); + this->setPixelRef(nullptr, 0, 0); return; } if (kUnknown_SkColorType == fInfo.colorType()) { - this->setPixelRef(nullptr); + this->setPixelRef(nullptr, 0, 0); return; } - SkPixelRef* pr = SkMallocPixelRef::NewDirect(fInfo, p, fRowBytes, ctable); - if (nullptr == pr) { - this->setPixelRef(nullptr); + this->setPixelRef(SkMallocPixelRef::MakeDirect(fInfo, p, fRowBytes, sk_ref_sp(ctable)), 0, 0); + if (!fPixelRef) { return; } - - this->setPixelRef(pr)->unref(); - // since we're already allocated, we lockPixels right away this->lockPixels(); SkDEBUGCODE(this->validate();) @@ -298,13 +322,11 @@ bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) // setInfo may have computed a valid rowbytes if 0 were passed in rowBytes = this->rowBytes(); - SkMallocPixelRef::PRFactory defaultFactory; - - SkPixelRef* pr = defaultFactory.create(correctedInfo, rowBytes, nullptr); - if (nullptr == pr) { + sk_sp pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes, nullptr); + if (!pr) { return reset_return_false(this); } - this->setPixelRef(pr)->unref(); + this->setPixelRef(std::move(pr), 0, 0); // TODO: lockPixels could/should return bool or void*/nullptr this->lockPixels(); @@ -314,8 +336,8 @@ bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) return true; } -bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory, - SkColorTable* ctable) { +bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, sk_sp ctable, + uint32_t allocFlags) { if (kIndex_8_SkColorType == requestedInfo.colorType() && nullptr == ctable) { return reset_return_false(this); } @@ -326,18 +348,14 @@ bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactor // setInfo may have corrected info (e.g. 565 is always opaque). const SkImageInfo& correctedInfo = this->info(); - SkMallocPixelRef::PRFactory defaultFactory; - if (nullptr == factory) { - factory = &defaultFactory; - } - - SkPixelRef* pr = factory->create(correctedInfo, correctedInfo.minRowBytes(), ctable); - if (nullptr == pr) { + sk_sp pr = (allocFlags & kZeroPixels_AllocFlag) ? + SkMallocPixelRef::MakeZeroed(correctedInfo, correctedInfo.minRowBytes(), ctable) : + SkMallocPixelRef::MakeAllocate(correctedInfo, correctedInfo.minRowBytes(), ctable); + if (!pr) { return reset_return_false(this); } - this->setPixelRef(pr)->unref(); + this->setPixelRef(std::move(pr), 0, 0); - // TODO: lockPixels could/should return bool or void*/nullptr this->lockPixels(); if (nullptr == this->getPixels()) { return reset_return_false(this); @@ -367,14 +385,14 @@ bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, siz // setInfo may have corrected info (e.g. 565 is always opaque). const SkImageInfo& correctedInfo = this->info(); - SkPixelRef* pr = SkMallocPixelRef::NewWithProc(correctedInfo, rb, ct, pixels, releaseProc, - context); + sk_sp pr = SkMallocPixelRef::MakeWithProc(correctedInfo, rb, sk_ref_sp(ct), + pixels, releaseProc, context); if (!pr) { this->reset(); return false; } - this->setPixelRef(pr)->unref(); + this->setPixelRef(std::move(pr), 0, 0); // since we're already allocated, we lockPixels right away this->lockPixels(); @@ -405,7 +423,6 @@ void SkBitmap::freePixels() { if (fPixelLockCount > 0) { fPixelRef->unlockPixels(); } - fPixelRef->unref(); fPixelRef = nullptr; fPixelRefOrigin.setZero(); } @@ -415,7 +432,7 @@ void SkBitmap::freePixels() { } uint32_t SkBitmap::getGenerationID() const { - return (fPixelRef) ? fPixelRef->getGenerationID() : 0; + return fPixelRef ? fPixelRef->getGenerationID() : 0; } void SkBitmap::notifyPixelsChanged() const { @@ -438,12 +455,12 @@ bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst, return false; } - SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), ctable); - if (nullptr == pr) { + sk_sp pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes(), sk_ref_sp(ctable)); + if (!pr) { return false; } - dst->setPixelRef(pr)->unref(); + dst->setPixelRef(std::move(pr), 0, 0); // since we're already allocated, we lockPixels right away dst->lockPixels(); return true; @@ -451,61 +468,6 @@ bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst, /////////////////////////////////////////////////////////////////////////////// -static bool copy_pixels_to(const SkPixmap& src, void* const dst, size_t dstSize, - size_t dstRowBytes, bool preserveDstPad) { - const SkImageInfo& info = src.info(); - - if (0 == dstRowBytes) { - dstRowBytes = src.rowBytes(); - } - if (dstRowBytes < info.minRowBytes()) { - return false; - } - - if (!preserveDstPad && static_cast(dstRowBytes) == src.rowBytes()) { - size_t safeSize = src.getSafeSize(); - if (safeSize > dstSize || safeSize == 0) - return false; - else { - // This implementation will write bytes beyond the end of each row, - // excluding the last row, if the bitmap's stride is greater than - // strictly required by the current config. - memcpy(dst, src.addr(), safeSize); - return true; - } - } else { - // If destination has different stride than us, then copy line by line. - if (info.getSafeSize(dstRowBytes) > dstSize) { - return false; - } else { - // Just copy what we need on each line. - size_t rowBytes = info.minRowBytes(); - const uint8_t* srcP = reinterpret_cast(src.addr()); - uint8_t* dstP = reinterpret_cast(dst); - for (int row = 0; row < info.height(); ++row) { - memcpy(dstP, srcP, rowBytes); - srcP += src.rowBytes(); - dstP += dstRowBytes; - } - - return true; - } - } -} - -bool SkBitmap::copyPixelsTo(void* dst, size_t dstSize, size_t dstRB, bool preserveDstPad) const { - if (nullptr == dst) { - return false; - } - SkAutoPixmapUnlock result; - if (!this->requestLock(&result)) { - return false; - } - return copy_pixels_to(result.pixmap(), dst, dstSize, dstRB, preserveDstPad); -} - -/////////////////////////////////////////////////////////////////////////////// - bool SkBitmap::isImmutable() const { return fPixelRef ? fPixelRef->isImmutable() : false; } @@ -561,140 +523,6 @@ void* SkBitmap::getAddr(int x, int y) const { return base; } -#include "SkHalf.h" - -SkColor SkBitmap::getColor(int x, int y) const { - SkASSERT((unsigned)x < (unsigned)this->width()); - SkASSERT((unsigned)y < (unsigned)this->height()); - - switch (this->colorType()) { - case kGray_8_SkColorType: { - uint8_t* addr = this->getAddr8(x, y); - return SkColorSetRGB(*addr, *addr, *addr); - } - case kAlpha_8_SkColorType: { - uint8_t* addr = this->getAddr8(x, y); - return SkColorSetA(0, addr[0]); - } - case kIndex_8_SkColorType: { - SkPMColor c = this->getIndex8Color(x, y); - return SkUnPreMultiply::PMColorToColor(c); - } - case kRGB_565_SkColorType: { - uint16_t* addr = this->getAddr16(x, y); - return SkPixel16ToColor(addr[0]); - } - case kARGB_4444_SkColorType: { - uint16_t* addr = this->getAddr16(x, y); - SkPMColor c = SkPixel4444ToPixel32(addr[0]); - return SkUnPreMultiply::PMColorToColor(c); - } - case kBGRA_8888_SkColorType: { - uint32_t* addr = this->getAddr32(x, y); - SkPMColor c = SkSwizzle_BGRA_to_PMColor(addr[0]); - return SkUnPreMultiply::PMColorToColor(c); - } - case kRGBA_8888_SkColorType: { - uint32_t* addr = this->getAddr32(x, y); - SkPMColor c = SkSwizzle_RGBA_to_PMColor(addr[0]); - return SkUnPreMultiply::PMColorToColor(c); - } - case kRGBA_F16_SkColorType: { - const uint64_t* addr = (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x; - Sk4f p4 = SkHalfToFloat_finite_ftz(addr[0]); - if (p4[3]) { - float inva = 1 / p4[3]; - p4 = p4 * Sk4f(inva, inva, inva, 1); - } - SkColor c; - SkNx_cast(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c); - // p4 is RGBA, but we want BGRA, so we need to swap next - return SkSwizzle_RB(c); - } - default: - SkASSERT(false); - return 0; - } - SkASSERT(false); // Not reached. - return 0; -} - -static bool compute_is_opaque(const SkPixmap& pmap) { - const int height = pmap.height(); - const int width = pmap.width(); - - switch (pmap.colorType()) { - case kAlpha_8_SkColorType: { - unsigned a = 0xFF; - for (int y = 0; y < height; ++y) { - const uint8_t* row = pmap.addr8(0, y); - for (int x = 0; x < width; ++x) { - a &= row[x]; - } - if (0xFF != a) { - return false; - } - } - return true; - } break; - case kIndex_8_SkColorType: { - const SkColorTable* ctable = pmap.ctable(); - if (nullptr == ctable) { - return false; - } - const SkPMColor* table = ctable->readColors(); - SkPMColor c = (SkPMColor)~0; - for (int i = ctable->count() - 1; i >= 0; --i) { - c &= table[i]; - } - return 0xFF == SkGetPackedA32(c); - } break; - case kRGB_565_SkColorType: - case kGray_8_SkColorType: - return true; - break; - case kARGB_4444_SkColorType: { - unsigned c = 0xFFFF; - for (int y = 0; y < height; ++y) { - const SkPMColor16* row = pmap.addr16(0, y); - for (int x = 0; x < width; ++x) { - c &= row[x]; - } - if (0xF != SkGetPackedA4444(c)) { - return false; - } - } - return true; - } break; - case kBGRA_8888_SkColorType: - case kRGBA_8888_SkColorType: { - SkPMColor c = (SkPMColor)~0; - for (int y = 0; y < height; ++y) { - const SkPMColor* row = pmap.addr32(0, y); - for (int x = 0; x < width; ++x) { - c &= row[x]; - } - if (0xFF != SkGetPackedA32(c)) { - return false; - } - } - return true; - } - default: - break; - } - return false; -} - -bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) { - SkAutoPixmapUnlock result; - if (!bm.requestLock(&result)) { - return false; - } - return compute_is_opaque(result.pixmap()); -} - - /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -730,7 +558,7 @@ void SkBitmap::eraseColor(SkColor c) const { bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { SkDEBUGCODE(this->validate();) - if (nullptr == result || nullptr == fPixelRef) { + if (nullptr == result || !fPixelRef) { return false; // no src pixels } @@ -754,7 +582,7 @@ bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { origin.fX += r.fLeft; origin.fY += r.fTop; // share the pixelref with a custom offset - dst.setPixelRef(fPixelRef, origin); + dst.setPixelRef(fPixelRef, origin.x(), origin.y()); } SkDEBUGCODE(dst.validate();) @@ -765,37 +593,31 @@ bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { /////////////////////////////////////////////////////////////////////////////// -bool SkBitmap::canCopyTo(SkColorType dstColorType) const { +bool SkBitmap::canCopyTo(SkColorType dstCT) const { const SkColorType srcCT = this->colorType(); if (srcCT == kUnknown_SkColorType) { return false; } + if (srcCT == kAlpha_8_SkColorType && dstCT != kAlpha_8_SkColorType) { + return false; // can't convert from alpha to non-alpha + } - bool sameConfigs = (srcCT == dstColorType); - switch (dstColorType) { + bool sameConfigs = (srcCT == dstCT); + switch (dstCT) { case kAlpha_8_SkColorType: case kRGB_565_SkColorType: case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: + case kRGBA_F16_SkColorType: break; - case kIndex_8_SkColorType: + case kGray_8_SkColorType: if (!sameConfigs) { return false; } break; case kARGB_4444_SkColorType: return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT; - case kGray_8_SkColorType: - switch (srcCT) { - case kGray_8_SkColorType: - case kRGBA_8888_SkColorType: - case kBGRA_8888_SkColorType: - return true; - default: - break; - } - return false; default: return false; } @@ -811,61 +633,84 @@ bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, return src.pixmap().readPixels(requestedDstInfo, dstPixels, dstRB, x, y); } -bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const { +bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const { + return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY); +} + +bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY, + SkTransferFunctionBehavior behavior) { + SkAutoPixmapUnlock dst; + if (!this->requestLock(&dst)) { + return false; + } + + if (!SkImageInfoValidConversion(fInfo, src.info())) { + return false; + } + + SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY); + if (!rec.trim(fInfo.width(), fInfo.height())) { + return false; + } + + void* dstPixels = this->getAddr(rec.fX, rec.fY); + const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height()); + SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes, + src.ctable(), behavior); + return true; +} + +bool SkBitmap::internalCopyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const { if (!this->canCopyTo(dstColorType)) { return false; } - // if we have a texture, first get those pixels - SkBitmap tmpSrc; - const SkBitmap* src = this; - - if (fPixelRef) { - SkIRect subset; - subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY, - fInfo.width(), fInfo.height()); - if (fPixelRef->readPixels(&tmpSrc, dstColorType, &subset)) { - if (fPixelRef->info().alphaType() == kUnpremul_SkAlphaType) { - // FIXME: The only meaningful implementation of readPixels - // (GrPixelRef) assumes premultiplied pixels. - return false; - } - SkASSERT(tmpSrc.width() == this->width()); - SkASSERT(tmpSrc.height() == this->height()); - - // did we get lucky and we can just return tmpSrc? - if (tmpSrc.colorType() == dstColorType && nullptr == alloc) { - dst->swap(tmpSrc); - // If the result is an exact copy, clone the gen ID. - if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) { - dst->pixelRef()->cloneGenID(*fPixelRef); - } - return true; - } - - // fall through to the raster case - src = &tmpSrc; - } - } - SkAutoPixmapUnlock srcUnlocker; - if (!src->requestLock(&srcUnlocker)) { + if (!this->requestLock(&srcUnlocker)) { return false; } - const SkPixmap& srcPM = srcUnlocker.pixmap(); + SkPixmap srcPM = srcUnlocker.pixmap(); + + // Various Android specific compatibility modes. + // TODO: + // Move the logic of this entire function into the framework, then call readPixels() directly. + SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType); + switch (dstColorType) { + case kRGB_565_SkColorType: + // copyTo() is not strict on alpha type. Here we set the src to opaque to allow + // the call to readPixels() to succeed and preserve this lenient behavior. + if (kOpaque_SkAlphaType != srcPM.alphaType()) { + srcPM = SkPixmap(srcPM.info().makeAlphaType(kOpaque_SkAlphaType), srcPM.addr(), + srcPM.rowBytes(), srcPM.ctable()); + dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType); + } + break; + case kRGBA_F16_SkColorType: + // The caller does not have an opportunity to pass a dst color space. Assume that + // they want linear sRGB. + dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear()); + + if (!srcPM.colorSpace()) { + // We can't do a sane conversion to F16 without a dst color space. Guess sRGB + // in this case. + srcPM.setColorSpace(SkColorSpace::MakeSRGB()); + } + break; + default: + break; + } - const SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType); SkBitmap tmpDst; if (!tmpDst.setInfo(dstInfo)) { return false; } // allocate colortable if srcConfig == kIndex8_Config - SkAutoTUnref ctable; + sk_sp ctable; if (dstColorType == kIndex_8_SkColorType) { ctable.reset(SkRef(srcPM.ctable())); } - if (!tmpDst.tryAllocPixels(alloc, ctable)) { + if (!tmpDst.tryAllocPixels(alloc, ctable.get())) { return false; } @@ -874,7 +719,22 @@ bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) return false; } - if (!srcPM.readPixels(dstUnlocker.pixmap())) { + SkPixmap dstPM = dstUnlocker.pixmap(); + + // We can't do a sane conversion from F16 without a src color space. Guess sRGB in this case. + if (kRGBA_F16_SkColorType == srcPM.colorType() && !dstPM.colorSpace()) { + dstPM.setColorSpace(SkColorSpace::MakeSRGB()); + } + + // readPixels does not yet support color spaces with parametric transfer functions. This + // works around that restriction when the color spaces are equal. + if (kRGBA_F16_SkColorType != dstColorType && kRGBA_F16_SkColorType != srcPM.colorType() && + dstPM.colorSpace() == srcPM.colorSpace()) { + dstPM.setColorSpace(nullptr); + srcPM.setColorSpace(nullptr); + } + + if (!srcPM.readPixels(dstPM)) { return false; } @@ -895,6 +755,16 @@ bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) return true; } +bool SkBitmap::copyTo(SkBitmap* dst, SkColorType ct) const { + return this->internalCopyTo(dst, ct, nullptr); +} + +#ifdef SK_BUILD_FOR_ANDROID +bool SkBitmap::copyTo(SkBitmap* dst, SkColorType ct, Allocator* alloc) const { + return this->internalCopyTo(dst, ct, alloc); +} +#endif + // TODO: can we merge this with copyTo? bool SkBitmap::deepCopyTo(SkBitmap* dst) const { const SkColorType dstCT = this->colorType(); @@ -902,7 +772,7 @@ bool SkBitmap::deepCopyTo(SkBitmap* dst) const { if (!this->canCopyTo(dstCT)) { return false; } - return this->copyTo(dst, dstCT, nullptr); + return this->copyTo(dst, dstCT); } /////////////////////////////////////////////////////////////////////////////// @@ -920,8 +790,9 @@ static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int return false; } const SkPixmap& pmap = apl.pixmap(); - SkPixelInfo::CopyPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes, - pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable()); + SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes, + pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable(), + SkTransferFunctionBehavior::kRespect); return true; } @@ -1025,7 +896,7 @@ static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) { void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) { const SkImageInfo info = bitmap.info(); - if (0 == info.width() || 0 == info.height() || nullptr == bitmap.pixelRef()) { + if (0 == info.width() || 0 == info.height() || bitmap.isNull()) { buffer->writeUInt(0); // instead of snugRB, signaling no pixels return; } @@ -1048,6 +919,10 @@ bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) { SkImageInfo info; info.unflatten(*buffer); + if (info.width() < 0 || info.height() < 0) { + return false; + } + // If there was an error reading "info" or if it is bogus, // don't use it to compute minRowBytes() if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(), @@ -1079,9 +954,9 @@ bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) { SkASSERT(srcRow == dstRow); // first row does not need to be moved } - SkAutoTUnref ctable; + sk_sp ctable; if (buffer->readBool()) { - ctable.reset(SkColorTable::Create(*buffer)); + ctable = SkColorTable::Create(*buffer); if (!ctable) { return false; } @@ -1105,13 +980,13 @@ bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) { } } - SkAutoTUnref pr(SkMallocPixelRef::NewWithData(info, info.minRowBytes(), - ctable.get(), data.get())); - if (!pr.get()) { + sk_sp pr = SkMallocPixelRef::MakeWithData(info, info.minRowBytes(), + std::move(ctable), std::move(data)); + if (!pr) { return false; } bitmap->setInfo(pr->info()); - bitmap->setPixelRef(pr, 0, 0); + bitmap->setPixelRef(std::move(pr), 0, 0); return true; } @@ -1122,17 +997,6 @@ enum { /////////////////////////////////////////////////////////////////////////////// -SkBitmap::RLEPixels::RLEPixels(int width, int height) { - fHeight = height; - fYPtrs = (uint8_t**)sk_calloc_throw(height * sizeof(uint8_t*)); -} - -SkBitmap::RLEPixels::~RLEPixels() { - sk_free(fYPtrs); -} - -/////////////////////////////////////////////////////////////////////////////// - #ifdef SK_DEBUG void SkBitmap::validate() const { fInfo.validate(); @@ -1191,19 +1055,7 @@ void SkBitmap::toString(SkString* str) const { } str->append(")"); - SkPixelRef* pr = this->pixelRef(); - if (nullptr == pr) { - // show null or the explicit pixel address (rare) - str->appendf(" pixels:%p", this->getPixels()); - } else { - const char* uri = pr->getURI(); - if (uri) { - str->appendf(" uri:\"%s\"", uri); - } else { - str->appendf(" pixelref:%p", pr); - } - } - + str->appendf(" pixelref:%p", this->pixelRef()); str->append(")"); } #endif @@ -1213,7 +1065,7 @@ void SkBitmap::toString(SkString* str) const { bool SkBitmap::requestLock(SkAutoPixmapUnlock* result) const { SkASSERT(result); - SkPixelRef* pr = fPixelRef; + SkPixelRef* pr = fPixelRef.get(); if (nullptr == pr) { return false; } diff --git a/gfx/skia/skia/src/core/SkBitmapCache.cpp b/gfx/skia/skia/src/core/SkBitmapCache.cpp index 153a24748b81..50553a05c2b9 100644 --- a/gfx/skia/skia/src/core/SkBitmapCache.cpp +++ b/gfx/skia/skia/src/core/SkBitmapCache.cpp @@ -26,10 +26,6 @@ void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) { /////////////////////////////////////////////////////////////////////////////////////////////////// -SkBitmap::Allocator* SkBitmapCache::GetAllocator() { - return SkResourceCache::GetAllocator(); -} - /** This function finds the bounds of the bitmap *within its pixelRef*. If the bitmap lacks a pixelRef, it will return an empty rect, since @@ -50,33 +46,45 @@ static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) { * return that subset (see get_bounds_from_bitmap). */ static SkIRect get_bounds_from_image(const SkImage* image) { + SkASSERT(image->width() > 0 && image->height() > 0); return SkIRect::MakeWH(image->width(), image->height()); } -SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm, int width, int height) { - SkBitmapCacheDesc desc; - desc.fImageID = bm.getGenerationID(); - desc.fWidth = width; - desc.fHeight = height; - desc.fBounds = get_bounds_from_bitmap(bm); - return desc; +SkBitmapCacheDesc SkBitmapCacheDesc::Make(uint32_t imageID, int origWidth, int origHeight) { + SkASSERT(imageID); + SkASSERT(origWidth > 0 && origHeight > 0); + return { imageID, 0, 0, {0, 0, origWidth, origHeight} }; +} + +SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm, int scaledWidth, int scaledHeight) { + SkASSERT(bm.width() > 0 && bm.height() > 0); + SkASSERT(scaledWidth > 0 && scaledHeight > 0); + SkASSERT(scaledWidth != bm.width() || scaledHeight != bm.height()); + + return { bm.getGenerationID(), scaledWidth, scaledHeight, get_bounds_from_bitmap(bm) }; } SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) { - return Make(bm, bm.width(), bm.height()); + SkASSERT(bm.width() > 0 && bm.height() > 0); + SkASSERT(bm.pixelRefOrigin() == SkIPoint::Make(0, 0)); + + return { bm.getGenerationID(), 0, 0, get_bounds_from_bitmap(bm) }; } -SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image, int width, int height) { - SkBitmapCacheDesc desc; - desc.fImageID = image->uniqueID(); - desc.fWidth = width; - desc.fHeight = height; - desc.fBounds = get_bounds_from_image(image); - return desc; +SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image, int scaledWidth, int scaledHeight) { + SkASSERT(image->width() > 0 && image->height() > 0); + SkASSERT(scaledWidth > 0 && scaledHeight > 0); + + // If the dimensions are the same, should we set them to 0,0? + //SkASSERT(scaledWidth != image->width() || scaledHeight != image->height()); + + return { image->uniqueID(), scaledWidth, scaledHeight, get_bounds_from_image(image) }; } SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) { - return Make(image, image->width(), image->height()); + SkASSERT(image->width() > 0 && image->height() > 0); + + return { image->uniqueID(), 0, 0, get_bounds_from_image(image) }; } namespace { @@ -84,173 +92,271 @@ static unsigned gBitmapKeyNamespaceLabel; struct BitmapKey : public SkResourceCache::Key { public: - BitmapKey(uint32_t genID, int width, int height, const SkIRect& bounds) - : fGenID(genID) - , fWidth(width) - , fHeight(height) - , fBounds(bounds) - { - this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fGenID), - sizeof(fGenID) + sizeof(fWidth) + sizeof(fHeight) + sizeof(fBounds)); - } - - BitmapKey(const SkBitmapCacheDesc& desc) - : fGenID(desc.fImageID) - , fWidth(desc.fWidth) - , fHeight(desc.fHeight) - , fBounds(desc.fBounds) - { - this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fGenID), - sizeof(fGenID) + sizeof(fWidth) + sizeof(fHeight) + sizeof(fBounds)); + BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) { + this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID), + sizeof(fDesc)); } void dump() const { - SkDebugf("-- add [%d %d] %d [%d %d %d %d]\n", fWidth, fHeight, fGenID, - fBounds.x(), fBounds.y(), fBounds.width(), fBounds.height()); + SkDebugf("-- add [%d %d] %d [%d %d %d %d]\n", + fDesc.fScaledWidth, fDesc.fScaledHeight, fDesc.fImageID, + fDesc.fSubset.x(), fDesc.fSubset.y(), fDesc.fSubset.width(), fDesc.fSubset.height()); } - const uint32_t fGenID; - const int fWidth; - const int fHeight; - const SkIRect fBounds; + const SkBitmapCacheDesc fDesc; }; +} -struct BitmapRec : public SkResourceCache::Rec { - BitmapRec(uint32_t genID, int width, int height, const SkIRect& bounds, - const SkBitmap& result) - : fKey(genID, width, height, bounds) - , fBitmap(result) +////////////////////// +#include "SkDiscardableMemory.h" +#include "SkNextID.h" + +void SkBitmapCache_setImmutableWithID(SkPixelRef* pr, uint32_t id) { + pr->setImmutableWithID(id); +} + +//#define REC_TRACE SkDebugf +static void REC_TRACE(const char format[], ...) {} + +// for diagnostics +static int32_t gRecCounter; + +class SkBitmapCache::Rec : public SkResourceCache::Rec { +public: + Rec(const SkBitmapCacheDesc& desc, const SkImageInfo& info, size_t rowBytes, + std::unique_ptr dm, void* block) + : fKey(desc) + , fDM(std::move(dm)) + , fMalloc(block) + , fInfo(info) + , fRowBytes(rowBytes) + , fExternalCounter(kBeforeFirstInstall_ExternalCounter) { -#ifdef TRACE_NEW_BITMAP_CACHE_RECS - fKey.dump(); -#endif + SkASSERT(!(fDM && fMalloc)); // can't have both + + // We need an ID to return with the bitmap/pixelref. + // If they are not scaling, we can return the same ID as the key/desc + // If they are scaling, we need a new ID + if (desc.fScaledWidth == 0 && desc.fScaledHeight == 0) { + fPrUniqueID = desc.fImageID; + } else { + fPrUniqueID = SkNextID::ImageID(); + } + REC_TRACE(" Rec(%d): [%d %d] %d\n", + sk_atomic_inc(&gRecCounter), fInfo.width(), fInfo.height(), fPrUniqueID); } - BitmapRec(const SkBitmapCacheDesc& desc, const SkBitmap& result) - : fKey(desc) - , fBitmap(result) - { -#ifdef TRACE_NEW_BITMAP_CACHE_RECS - fKey.dump(); -#endif + ~Rec() override { + SkASSERT(0 == fExternalCounter || kBeforeFirstInstall_ExternalCounter == fExternalCounter); + if (fDM && kBeforeFirstInstall_ExternalCounter == fExternalCounter) { + // we never installed, so we need to unlock before we destroy the DM + SkASSERT(fDM->data()); + fDM->unlock(); + } + REC_TRACE("~Rec(%d): [%d %d] %d\n", + sk_atomic_dec(&gRecCounter) - 1, fInfo.width(), fInfo.height(), fPrUniqueID); + sk_free(fMalloc); // may be null } const Key& getKey() const override { return fKey; } - size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); } + size_t bytesUsed() const override { + return sizeof(fKey) + fInfo.getSafeSize(fRowBytes); + } + bool canBePurged() override { + SkAutoMutexAcquire ama(fMutex); + return fExternalCounter == 0; + } + void postAddInstall(void* payload) override { + SkAssertResult(this->install(static_cast(payload))); + } const char* getCategory() const override { return "bitmap"; } SkDiscardableMemory* diagnostic_only_getDiscardable() const override { - return fBitmap.pixelRef()->diagnostic_only_getDiscardable(); + return fDM.get(); + } + + static void ReleaseProc(void* addr, void* ctx) { + Rec* rec = static_cast(ctx); + SkAutoMutexAcquire ama(rec->fMutex); + + REC_TRACE(" Rec: [%d] releaseproc\n", rec->fPrUniqueID); + + SkASSERT(rec->fExternalCounter > 0); + rec->fExternalCounter -= 1; + if (rec->fDM) { + SkASSERT(rec->fMalloc == nullptr); + if (rec->fExternalCounter == 0) { + REC_TRACE(" Rec [%d] unlock\n", rec->fPrUniqueID); + rec->fDM->unlock(); + } + } else { + SkASSERT(rec->fMalloc != nullptr); + } + } + + bool install(SkBitmap* bitmap) { + SkAutoMutexAcquire ama(fMutex); + + // are we still valid + if (!fDM && !fMalloc) { + REC_TRACE(" Rec: [%d] invalid\n", fPrUniqueID); + return false; + } + + /* + constructor fExternalCount < 0 fDM->data() + after install fExternalCount > 0 fDM->data() + after Release fExternalCount == 0 !fDM->data() + */ + if (fDM) { + if (kBeforeFirstInstall_ExternalCounter == fExternalCounter) { + SkASSERT(fDM->data()); + } else if (fExternalCounter > 0) { + SkASSERT(fDM->data()); + } else { + SkASSERT(fExternalCounter == 0); + if (!fDM->lock()) { + REC_TRACE(" Rec [%d] re-lock failed\n", fPrUniqueID); + fDM.reset(nullptr); + return false; + } + REC_TRACE(" Rec [%d] re-lock succeeded\n", fPrUniqueID); + } + SkASSERT(fDM->data()); + } + + bitmap->installPixels(fInfo, fDM ? fDM->data() : fMalloc, fRowBytes, nullptr, + ReleaseProc, this); + SkBitmapCache_setImmutableWithID(bitmap->pixelRef(), fPrUniqueID); + + REC_TRACE(" Rec: [%d] install new pr\n", fPrUniqueID); + + if (kBeforeFirstInstall_ExternalCounter == fExternalCounter) { + fExternalCounter = 1; + } else { + fExternalCounter += 1; + } + SkASSERT(fExternalCounter > 0); + return true; } static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) { - const BitmapRec& rec = static_cast(baseRec); + Rec* rec = (Rec*)&baseRec; SkBitmap* result = (SkBitmap*)contextBitmap; - - *result = rec.fBitmap; - result->lockPixels(); - return SkToBool(result->getPixels()); + REC_TRACE(" Rec: [%d] found\n", rec->fPrUniqueID); + return rec->install(result); } private: BitmapKey fKey; - SkBitmap fBitmap; + + SkMutex fMutex; + + // either fDM or fMalloc can be non-null, but not both + std::unique_ptr fDM; + void* fMalloc; + + SkImageInfo fInfo; + size_t fRowBytes; + uint32_t fPrUniqueID; + + // This field counts the number of external pixelrefs we have created. They notify us when + // they are destroyed so we can decrement this. + // + // > 0 we have outstanding pixelrefs + // == 0 we have no outstanding pixelrefs, and can be safely purged + // < 0 we have been created, but not yet "installed" the first time. + // + int fExternalCounter; + + enum { + kBeforeFirstInstall_ExternalCounter = -1 + }; }; -} // namespace + +void SkBitmapCache::PrivateDeleteRec(Rec* rec) { delete rec; } + +SkBitmapCache::RecPtr SkBitmapCache::Alloc(const SkBitmapCacheDesc& desc, const SkImageInfo& info, + SkPixmap* pmap) { + // Ensure that the caller is self-consistent: + // - if they are scaling, the info matches the scaled size + // - if they are not, the info matches the subset (i.e. the subset is the entire image) + if (desc.fScaledWidth == 0 && desc.fScaledHeight == 0) { + SkASSERT(info.width() == desc.fSubset.width()); + SkASSERT(info.height() == desc.fSubset.height()); + } else { + SkASSERT(info.width() == desc.fScaledWidth); + SkASSERT(info.height() == desc.fScaledHeight); + } + + const size_t rb = info.minRowBytes(); + size_t size = info.getSafeSize(rb); + if (0 == size) { + return nullptr; + } + + std::unique_ptr dm; + void* block = nullptr; + + auto factory = SkResourceCache::GetDiscardableFactory(); + if (factory) { + dm.reset(factory(size)); + } else { + block = sk_malloc_flags(size, 0); + } + if (!dm && !block) { + return nullptr; + } + *pmap = SkPixmap(info, dm ? dm->data() : block, rb); + return RecPtr(new Rec(desc, info, rb, std::move(dm), block)); +} + +void SkBitmapCache::Add(RecPtr rec, SkBitmap* bitmap) { + SkResourceCache::Add(rec.release(), bitmap); +} + +bool SkBitmapCache::Find(const SkBitmapCacheDesc& desc, SkBitmap* result) { + desc.validate(); + return SkResourceCache::Find(BitmapKey(desc), SkBitmapCache::Rec::Finder, result); +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// #define CHECK_LOCAL(localCache, localName, globalName, ...) \ ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__)) -bool SkBitmapCache::FindWH(const SkBitmapCacheDesc& desc, SkBitmap* result, - SkResourceCache* localCache) { - if (0 == desc.fWidth || 0 == desc.fHeight) { - // degenerate - return false; - } - return CHECK_LOCAL(localCache, find, Find, BitmapKey(desc), BitmapRec::Finder, result); -} - -bool SkBitmapCache::AddWH(const SkBitmapCacheDesc& desc, const SkBitmap& result, - SkResourceCache* localCache) { - if (0 == desc.fWidth || 0 == desc.fHeight) { - // degenerate, and the key we use for mipmaps - return false; - } - SkASSERT(result.isImmutable()); - BitmapRec* rec = new BitmapRec(desc, result); - CHECK_LOCAL(localCache, add, Add, rec); - return true; -} - -bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result, - SkResourceCache* localCache) { - BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset); - - return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result); -} - -bool SkBitmapCache::Add(SkPixelRef* pr, const SkIRect& subset, const SkBitmap& result, - SkResourceCache* localCache) { - SkASSERT(result.isImmutable()); - - if (subset.isEmpty() - || subset.top() < 0 - || subset.left() < 0 - || result.width() != subset.width() - || result.height() != subset.height()) { - return false; - } else { - BitmapRec* rec = new BitmapRec(pr->getGenerationID(), 1, 1, subset, result); - - CHECK_LOCAL(localCache, add, Add, rec); - pr->notifyAddedToCache(); - return true; - } -} - -bool SkBitmapCache::Find(uint32_t genID, SkBitmap* result, SkResourceCache* localCache) { - BitmapKey key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeEmpty()); - - return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result); -} - -void SkBitmapCache::Add(uint32_t genID, const SkBitmap& result, SkResourceCache* localCache) { - SkASSERT(result.isImmutable()); - - BitmapRec* rec = new BitmapRec(genID, 1, 1, SkIRect::MakeEmpty(), result); - - CHECK_LOCAL(localCache, add, Add, rec); -} - -////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// - namespace { static unsigned gMipMapKeyNamespaceLabel; struct MipMapKey : public SkResourceCache::Key { public: - MipMapKey(uint32_t genID, SkSourceGammaTreatment treatment, const SkIRect& bounds) - : fGenID(genID), fSrcGammaTreatment(static_cast(treatment)), fBounds(bounds) + MipMapKey(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode) + : fImageID(imageID) + , fColorMode(static_cast(colorMode)) + , fSubset(subset) { - this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID), - sizeof(fGenID) + sizeof(fSrcGammaTreatment) + sizeof(fBounds)); + SkASSERT(fImageID); + SkASSERT(!subset.isEmpty()); + this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fImageID), + sizeof(fImageID) + sizeof(fColorMode) + sizeof(fSubset)); } - uint32_t fGenID; - uint32_t fSrcGammaTreatment; - SkIRect fBounds; + uint32_t fImageID; + uint32_t fColorMode; + SkIRect fSubset; }; struct MipMapRec : public SkResourceCache::Rec { - MipMapRec(const SkBitmap& src, SkSourceGammaTreatment treatment, const SkMipMap* result) - : fKey(src.getGenerationID(), treatment, get_bounds_from_bitmap(src)) + MipMapRec(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode, + const SkMipMap* result) + : fKey(imageID, subset, colorMode) , fMipMap(result) { fMipMap->attachToCacheAndRef(); } - virtual ~MipMapRec() { + ~MipMapRec() override { fMipMap->detachFromCacheAndUnref(); } @@ -282,10 +388,11 @@ private: } const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc, - SkSourceGammaTreatment treatment, + SkDestinationSurfaceColorMode colorMode, SkResourceCache* localCache) { - // Note: we ignore width/height from desc, just need id and bounds - MipMapKey key(desc.fImageID, treatment, desc.fBounds); + SkASSERT(desc.fScaledWidth == 0); + SkASSERT(desc.fScaledHeight == 0); + MipMapKey key(desc.fImageID, desc.fSubset, colorMode); const SkMipMap* result; if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) { @@ -299,11 +406,13 @@ static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) : SkResourceCache::GetDiscardableFactory(); } -const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkSourceGammaTreatment treatment, +const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, + SkDestinationSurfaceColorMode colorMode, SkResourceCache* localCache) { - SkMipMap* mipmap = SkMipMap::Build(src, treatment, get_fact(localCache)); + SkMipMap* mipmap = SkMipMap::Build(src, colorMode, get_fact(localCache)); if (mipmap) { - MipMapRec* rec = new MipMapRec(src, treatment, mipmap); + MipMapRec* rec = new MipMapRec(src.getGenerationID(), get_bounds_from_bitmap(src), + colorMode, mipmap); CHECK_LOCAL(localCache, add, Add, rec); src.pixelRef()->notifyAddedToCache(); } diff --git a/gfx/skia/skia/src/core/SkBitmapCache.h b/gfx/skia/skia/src/core/SkBitmapCache.h index 76bcef06cf13..a59dcb5a12a8 100644 --- a/gfx/skia/skia/src/core/SkBitmapCache.h +++ b/gfx/skia/skia/src/core/SkBitmapCache.h @@ -19,62 +19,54 @@ uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID); void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID); struct SkBitmapCacheDesc { - uint32_t fImageID; - int32_t fWidth; - int32_t fHeight; - SkIRect fBounds; + uint32_t fImageID; // != 0 + int32_t fScaledWidth; // 0 for unscaled + int32_t fScaledHeight; // 0 for unscaled + SkIRect fSubset; // always set to a valid rect (entire or subset) - static SkBitmapCacheDesc Make(const SkBitmap&, int width, int height); + void validate() const { + SkASSERT(fImageID); + if (fScaledWidth || fScaledHeight) { + SkASSERT(fScaledWidth && fScaledHeight); + } + SkASSERT(fSubset.fLeft >= 0 && fSubset.fTop >= 0); + SkASSERT(fSubset.width() > 0 && fSubset.height() > 0); + } + + static SkBitmapCacheDesc Make(const SkBitmap&, int scaledWidth, int scaledHeight); static SkBitmapCacheDesc Make(const SkBitmap&); - static SkBitmapCacheDesc Make(const SkImage*, int width, int height); + static SkBitmapCacheDesc Make(const SkImage*, int scaledWidth, int scaledHeight); static SkBitmapCacheDesc Make(const SkImage*); + + // Use with care -- width/height must match the original bitmap/image + static SkBitmapCacheDesc Make(uint32_t genID, int origWidth, int origHeight); }; class SkBitmapCache { public: - /** - * Use this allocator for bitmaps, so they can use ashmem when available. - * Returns nullptr if the ResourceCache has not been initialized with a DiscardableFactory. - */ - static SkBitmap::Allocator* GetAllocator(); - /** * Search based on the desc. If found, returns true and * result will be set to the matching bitmap with its pixels already locked. */ - static bool FindWH(const SkBitmapCacheDesc&, SkBitmap* result, - SkResourceCache* localCache = nullptr); + static bool Find(const SkBitmapCacheDesc&, SkBitmap* result); - /* - * result must be marked isImmutable() - */ - static bool AddWH(const SkBitmapCacheDesc&, const SkBitmap& result, - SkResourceCache* localCache = nullptr); + class Rec; + struct RecDeleter { void operator()(Rec* r) { PrivateDeleteRec(r); } }; + typedef std::unique_ptr RecPtr; - /** - * Search based on the bitmap's genID and subset. If found, returns true and - * result will be set to the matching bitmap with its pixels already locked. - */ - static bool Find(uint32_t genID, const SkIRect& subset, SkBitmap* result, - SkResourceCache* localCache = nullptr); + static RecPtr Alloc(const SkBitmapCacheDesc&, const SkImageInfo&, SkPixmap*); + static void Add(RecPtr, SkBitmap*); - /** - * The width and the height of the provided subset must be the same as the result bitmap ones. - * result must be marked isImmutable() - */ - static bool Add(SkPixelRef*, const SkIRect& subset, const SkBitmap& result, - SkResourceCache* localCache = nullptr); - - static bool Find(uint32_t genID, SkBitmap* result, SkResourceCache* localCache = nullptr); - // todo: eliminate the need to specify ID, since it should == the bitmap's - static void Add(uint32_t genID, const SkBitmap&, SkResourceCache* localCache = nullptr); +private: + static void PrivateDeleteRec(Rec*); }; class SkMipMapCache { public: - static const SkMipMap* FindAndRef(const SkBitmapCacheDesc&, SkSourceGammaTreatment, + // Note: the scaled width/height in desc must be 0, as any other value would not make sense. + static const SkMipMap* FindAndRef(const SkBitmapCacheDesc&, SkDestinationSurfaceColorMode, SkResourceCache* localCache = nullptr); - static const SkMipMap* AddAndRef(const SkBitmap& src, SkSourceGammaTreatment, + static const SkMipMap* AddAndRef(const SkBitmap& src, SkDestinationSurfaceColorMode, SkResourceCache* localCache = nullptr); }; diff --git a/gfx/skia/skia/src/core/SkBitmapController.cpp b/gfx/skia/skia/src/core/SkBitmapController.cpp index f4ee0fb6c1b8..c72693fe8824 100644 --- a/gfx/skia/skia/src/core/SkBitmapController.cpp +++ b/gfx/skia/skia/src/core/SkBitmapController.cpp @@ -21,10 +21,6 @@ SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmapProvi const SkMatrix& inv, SkFilterQuality quality, void* storage, size_t storageSize) { - if (!provider.validForDrawing()) { - return nullptr; - } - State* state = this->onRequestBitmap(provider, inv, quality, storage, storageSize); if (state) { if (nullptr == state->fPixmap.addr()) { @@ -44,13 +40,15 @@ SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmapProvi class SkDefaultBitmapControllerState : public SkBitmapController::State { public: - SkDefaultBitmapControllerState(const SkBitmapProvider&, const SkMatrix& inv, SkFilterQuality, - SkSourceGammaTreatment); + SkDefaultBitmapControllerState(const SkBitmapProvider&, + const SkMatrix& inv, + SkFilterQuality, + bool canShadeHQ); private: - SkBitmap fResultBitmap; - SkSourceGammaTreatment fSrcGammaTreatment; - SkAutoTUnref fCurrMip; + SkBitmap fResultBitmap; + sk_sp fCurrMip; + bool fCanShadeHQ; bool processHQRequest(const SkBitmapProvider&); bool processMediumRequest(const SkBitmapProvider&); @@ -83,6 +81,9 @@ bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmapProvider& pr // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap // to a valid bitmap. If we succeed, we will set this to Low instead. fQuality = kMedium_SkFilterQuality; +#ifdef SK_USE_MIP_FOR_DOWNSCALE_HQ + return false; +#endif if (kN32_SkColorType != provider.info().colorType() || !cache_size_okay(provider, fInvMatrix) || fInvMatrix.hasPerspective()) @@ -111,11 +112,19 @@ bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmapProvider& pr return false; // only use HQ when upsampling } + // If the shader can natively handle HQ filtering, let it do it. + if (fCanShadeHQ) { + fQuality = kHigh_SkFilterQuality; + SkAssertResult(provider.asBitmap(&fResultBitmap)); + fResultBitmap.lockPixels(); + return true; + } + const int dstW = SkScalarRoundToScalar(provider.width() / invScaleX); const int dstH = SkScalarRoundToScalar(provider.height() / invScaleY); const SkBitmapCacheDesc desc = provider.makeCacheDesc(dstW, dstH); - if (!SkBitmapCache::FindWH(desc, &fResultBitmap)) { + if (!SkBitmapCache::Find(desc, &fResultBitmap)) { SkBitmap orig; if (!provider.asBitmap(&orig)) { return false; @@ -124,21 +133,36 @@ bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmapProvider& pr if (!orig.requestLock(&src)) { return false; } - if (!SkBitmapScaler::Resize(&fResultBitmap, src.pixmap(), kHQ_RESIZE_METHOD, - dstW, dstH, SkResourceCache::GetAllocator())) { + + SkPixmap dst; + SkBitmapCache::RecPtr rec; + const SkImageInfo info = SkImageInfo::MakeN32(desc.fScaledWidth, desc.fScaledHeight, + src.pixmap().alphaType()); + if (provider.isVolatile()) { + if (!fResultBitmap.tryAllocPixels(info)) { + return false; + } + SkASSERT(fResultBitmap.getPixels()); + fResultBitmap.peekPixels(&dst); + fResultBitmap.setImmutable(); // a little cheat, as we haven't resized yet, but ok + } else { + rec = SkBitmapCache::Alloc(desc, info, &dst); + if (!rec) { + return false; + } + } + if (!SkBitmapScaler::Resize(dst, src.pixmap(), kHQ_RESIZE_METHOD)) { return false; // we failed to create fScaledBitmap } - - SkASSERT(fResultBitmap.getPixels()); - fResultBitmap.setImmutable(); - if (!provider.isVolatile()) { - if (SkBitmapCache::AddWH(desc, fResultBitmap)) { - provider.notifyAddedToCache(); - } + if (rec) { + SkBitmapCache::Add(std::move(rec), &fResultBitmap); + SkASSERT(fResultBitmap.getPixels()); + provider.notifyAddedToCache(); } } SkASSERT(fResultBitmap.getPixels()); + SkASSERT(fResultBitmap.isImmutable()); fInvMatrix.postScale(SkIntToScalar(dstW) / provider.width(), SkIntToScalar(dstH) / provider.height()); @@ -165,14 +189,17 @@ bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmapProvider return false; } + SkDestinationSurfaceColorMode colorMode = provider.dstColorSpace() + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; if (invScaleSize.width() > SK_Scalar1 || invScaleSize.height() > SK_Scalar1) { - fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc(), fSrcGammaTreatment)); + fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc(), colorMode)); if (nullptr == fCurrMip.get()) { SkBitmap orig; if (!provider.asBitmap(&orig)) { return false; } - fCurrMip.reset(SkMipMapCache::AddAndRef(orig, fSrcGammaTreatment)); + fCurrMip.reset(SkMipMapCache::AddAndRef(orig, colorMode)); if (nullptr == fCurrMip.get()) { return false; } @@ -203,19 +230,21 @@ bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmapProvider SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmapProvider& provider, const SkMatrix& inv, SkFilterQuality qual, - SkSourceGammaTreatment treatment) { + bool canShadeHQ) { fInvMatrix = inv; fQuality = qual; - fSrcGammaTreatment = treatment; + fCanShadeHQ = canShadeHQ; - if (this->processHQRequest(provider) || this->processMediumRequest(provider)) { + bool processed = this->processHQRequest(provider) || this->processMediumRequest(provider); + + if (processed) { SkASSERT(fResultBitmap.getPixels()); } else { (void)provider.asBitmap(&fResultBitmap); fResultBitmap.lockPixels(); // lock may fail to give us pixels } - SkASSERT(fQuality <= kLow_SkFilterQuality); + SkASSERT(fCanShadeHQ || fQuality <= kLow_SkFilterQuality); // fResultBitmap.getPixels() may be null, but our caller knows to check fPixmap.addr() // and will destroy us if it is nullptr. @@ -227,6 +256,6 @@ SkBitmapController::State* SkDefaultBitmapController::onRequestBitmap(const SkBi const SkMatrix& inverse, SkFilterQuality quality, void* storage, size_t size) { - return SkInPlaceNewCheck(storage, size, bm, inverse, quality, - fSrcGammaTreatment); + return SkInPlaceNewCheck(storage, size, + bm, inverse, quality, fCanShadeHQ); } diff --git a/gfx/skia/skia/src/core/SkBitmapController.h b/gfx/skia/skia/src/core/SkBitmapController.h index f31c8eef5561..72fc721c537f 100644 --- a/gfx/skia/skia/src/core/SkBitmapController.h +++ b/gfx/skia/skia/src/core/SkBitmapController.h @@ -57,14 +57,14 @@ protected: class SkDefaultBitmapController : public SkBitmapController { public: - SkDefaultBitmapController(SkSourceGammaTreatment treatment) : fSrcGammaTreatment(treatment) {} + enum class CanShadeHQ { kNo, kYes }; + SkDefaultBitmapController(CanShadeHQ canShadeHQ) + : fCanShadeHQ(canShadeHQ == CanShadeHQ::kYes) {} protected: State* onRequestBitmap(const SkBitmapProvider&, const SkMatrix& inverse, SkFilterQuality, void* storage, size_t storageSize) override; - -private: - const SkSourceGammaTreatment fSrcGammaTreatment; + bool fCanShadeHQ; }; #endif diff --git a/gfx/skia/skia/src/core/SkBitmapDevice.cpp b/gfx/skia/skia/src/core/SkBitmapDevice.cpp index 26d253cf38da..fd387acb90f9 100644 --- a/gfx/skia/skia/src/core/SkBitmapDevice.cpp +++ b/gfx/skia/skia/src/core/SkBitmapDevice.cpp @@ -6,7 +6,6 @@ */ #include "SkBitmapDevice.h" -#include "SkConfig8888.h" #include "SkDraw.h" #include "SkImageFilter.h" #include "SkImageFilterCache.h" @@ -17,10 +16,11 @@ #include "SkPixelRef.h" #include "SkPixmap.h" #include "SkRasterClip.h" +#include "SkRasterHandleAllocator.h" #include "SkShader.h" #include "SkSpecialImage.h" #include "SkSurface.h" -#include "SkXfermode.h" +#include "SkVertices.h" class SkColorTable; @@ -71,6 +71,7 @@ static bool valid_for_bitmap_device(const SkImageInfo& info, SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) : INHERITED(bitmap.info(), SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)) , fBitmap(bitmap) + , fRCStack(bitmap.width(), bitmap.height()) { SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr)); fBitmap.lockPixels(); @@ -80,21 +81,26 @@ SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) { return Create(info, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)); } -SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps) +SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps, + SkRasterHandleAllocator::Handle hndl) : INHERITED(bitmap.info(), surfaceProps) , fBitmap(bitmap) + , fRasterHandle(hndl) + , fRCStack(bitmap.width(), bitmap.height()) { SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr)); fBitmap.lockPixels(); } SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, - const SkSurfaceProps& surfaceProps) { + const SkSurfaceProps& surfaceProps, + SkRasterHandleAllocator* allocator) { SkAlphaType newAT = origInfo.alphaType(); if (!valid_for_bitmap_device(origInfo, &newAT)) { return nullptr; } + SkRasterHandleAllocator::Handle hndl = nullptr; const SkImageInfo info = origInfo.makeAlphaType(newAT); SkBitmap bitmap; @@ -102,6 +108,11 @@ SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, if (!bitmap.setInfo(info)) { return nullptr; } + } else if (allocator) { + hndl = allocator->allocBitmap(info, &bitmap); + if (!hndl) { + return nullptr; + } } else if (info.isOpaque()) { // If this bitmap is opaque, we don't have any sensible default color, // so we just return uninitialized pixels. @@ -110,20 +121,13 @@ SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, } } else { // This bitmap has transparency, so we'll zero the pixels (to transparent). - // We use a ZeroedPRFactory as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT). - SkMallocPixelRef::ZeroedPRFactory factory; - if (!bitmap.tryAllocPixels(info, &factory, nullptr/*color table*/)) { + // We use the flag as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT). + if (!bitmap.tryAllocPixels(info, nullptr/*colortable*/, SkBitmap::kZeroPixels_AllocFlag)) { return nullptr; } } - return new SkBitmapDevice(bitmap, surfaceProps); -} - -void SkBitmapDevice::setNewSize(const SkISize& size) { - SkASSERT(!fBitmap.pixelRef()); - fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight)); - this->privateResize(fBitmap.info().width(), fBitmap.info().height()); + return new SkBitmapDevice(bitmap, surfaceProps, hndl); } void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { @@ -136,11 +140,7 @@ void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) { const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry); - return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps); -} - -const SkBitmap& SkBitmapDevice::onAccessBitmap() { - return fBitmap; + return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps, cinfo.fAllocator); } bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) { @@ -168,12 +168,7 @@ bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPi return false; } - const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height()); - - void* dstPixels = fBitmap.getAddr(x, y); - size_t dstRowBytes = fBitmap.rowBytes(); - - if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) { + if (fBitmap.writePixels(SkPixmap(srcInfo, srcPixels, srcRowBytes), x, y)) { fBitmap.notifyPixelsChanged(); return true; } @@ -187,50 +182,63 @@ bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, s /////////////////////////////////////////////////////////////////////////////// -void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { - draw.drawPaint(paint); +class SkBitmapDevice::BDDraw : public SkDraw { +public: + BDDraw(SkBitmapDevice* dev) { + // we need fDst to be set, and if we're actually drawing, to dirty the genID + if (!dev->accessPixels(&fDst)) { + // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels + fDst.reset(dev->imageInfo(), nullptr, 0); + } + fMatrix = &dev->ctm(); + fRC = &dev->fRCStack.rc(); + } +}; + +void SkBitmapDevice::drawPaint(const SkPaint& paint) { + BDDraw(this).drawPaint(paint); } -void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, +void SkBitmapDevice::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { - draw.drawPoints(mode, count, pts, paint); + BDDraw(this).drawPoints(mode, count, pts, paint, nullptr); } -void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { - draw.drawRect(r, paint); +void SkBitmapDevice::drawRect(const SkRect& r, const SkPaint& paint) { + BDDraw(this).drawRect(r, paint); } -void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { +void SkBitmapDevice::drawOval(const SkRect& oval, const SkPaint& paint) { SkPath path; path.addOval(oval); // call the VIRTUAL version, so any subclasses who do handle drawPath aren't // required to override drawOval. - this->drawPath(draw, path, paint, nullptr, true); + this->drawPath(path, paint, nullptr, true); } -void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) { +void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) { #ifdef SK_IGNORE_BLURRED_RRECT_OPT SkPath path; path.addRRect(rrect); // call the VIRTUAL version, so any subclasses who do handle drawPath aren't // required to override drawRRect. - this->drawPath(draw, path, paint, nullptr, true); + this->drawPath(path, paint, nullptr, true); #else - draw.drawRRect(rrect, paint); + BDDraw(this).drawRRect(rrect, paint); #endif } -void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path, +void SkBitmapDevice::drawPath(const SkPath& path, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) { - draw.drawPath(path, paint, prePathMatrix, pathIsMutable); + BDDraw(this).drawPath(path, paint, prePathMatrix, pathIsMutable); } -void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, +void SkBitmapDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint& paint) { - LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality()); - draw.drawBitmap(bitmap, matrix, nullptr, paint); + LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality()); + BDDraw(this).drawBitmap(bitmap, matrix, nullptr, paint); } static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) { @@ -242,7 +250,7 @@ static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& pain return m.getType() <= SkMatrix::kTranslate_Mask; } -void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, +void SkBitmapDevice::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { SkMatrix matrix; @@ -259,7 +267,7 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, } matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); - LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality()); + LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality()); const SkRect* dstPtr = &dst; const SkBitmap* bitmapPtr = &bitmap; @@ -307,8 +315,14 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, matrix.preTranslate(dx, dy); } +#ifdef SK_DRAWBITMAPRECT_FAST_OFFSET + SkRect extractedBitmapBounds = SkRect::MakeXYWH(dx, dy, + SkIntToScalar(bitmapPtr->width()), + SkIntToScalar(bitmapPtr->height())); +#else SkRect extractedBitmapBounds; extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); +#endif if (extractedBitmapBounds == tmpSrc) { // no fractional part in src, we can just call drawBitmap goto USE_DRAWBITMAP; @@ -319,25 +333,24 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, // matrix with the CTM, and try to call drawSprite if it can. If not, // it will make a shader and call drawRect, as we do below. if (CanApplyDstMatrixAsCTM(matrix, paint)) { - draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint); + BDDraw(this).drawBitmap(*bitmapPtr, matrix, dstPtr, paint); return; } } USE_SHADER: + // TODO(herb): Move this over to SkArenaAlloc when arena alloc has a facility to return sk_sps. // Since the shader need only live for our stack-frame, pass in a custom allocator. This // can save malloc calls, and signals to SkMakeBitmapShader to not try to copy the bitmap // if its mutable, since that precaution is not needed (give the short lifetime of the shader). - SkTBlitterAllocator allocator; + // construct a shader, so we can call drawRect with the dst auto s = SkMakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, - &matrix, kNever_SkCopyPixelsMode, &allocator); + &matrix, kNever_SkCopyPixelsMode); if (!s) { return; } - // we deliberately add a ref, since the allocator wants to be the last owner - s.get()->ref(); SkPaint paintWithShader(paint); paintWithShader.setStyle(SkPaint::kFill_Style); @@ -345,44 +358,39 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, // Call ourself, in case the subclass wanted to share this setup code // but handle the drawRect code themselves. - this->drawRect(draw, *dstPtr, paintWithShader); + this->drawRect(*dstPtr, paintWithShader); } -void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, - int x, int y, const SkPaint& paint) { - draw.drawSprite(bitmap, x, y, paint); +void SkBitmapDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) { + BDDraw(this).drawSprite(bitmap, x, y, paint); } -void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len, +void SkBitmapDevice::drawText(const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint& paint) { - draw.drawText((const char*)text, len, x, y, paint); + BDDraw(this).drawText((const char*)text, len, x, y, paint, &fSurfaceProps); } -void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, - const SkScalar xpos[], int scalarsPerPos, - const SkPoint& offset, const SkPaint& paint) { - draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint); +void SkBitmapDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[], + int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { + BDDraw(this).drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint, + &fSurfaceProps); } -void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, - int vertexCount, - const SkPoint verts[], const SkPoint textures[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, +void SkBitmapDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode, const SkPaint& paint) { - draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, - indices, indexCount, paint); + BDDraw(this).drawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), + vertices->texCoords(), vertices->colors(), bmode, + vertices->indices(), vertices->indexCount(), paint); } -void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, - int x, int y, const SkPaint& paint) { +void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) { SkASSERT(!paint.getImageFilter()); - draw.drawSprite(static_cast(device)->fBitmap, x, y, paint); + BDDraw(this).drawSprite(static_cast(device)->fBitmap, x, y, paint); } /////////////////////////////////////////////////////////////////////////////// -void SkBitmapDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, int y, +void SkBitmapDevice::drawSpecial(SkSpecialImage* srcImg, int x, int y, const SkPaint& paint) { SkASSERT(!srcImg->isTextureBacked()); @@ -391,24 +399,24 @@ void SkBitmapDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int SkImageFilter* filter = paint.getImageFilter(); if (filter) { SkIPoint offset = SkIPoint::Make(0, 0); - SkMatrix matrix = *draw.fMatrix; + SkMatrix matrix = this->ctm(); matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); - const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y); - SkAutoTUnref cache(this->getImageFilterCache()); + const SkIRect clipBounds = fRCStack.rc().getBounds().makeOffset(-x, -y); + sk_sp cache(this->getImageFilterCache()); SkImageFilter::OutputProperties outputProperties(fBitmap.colorSpace()); SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties); - + sk_sp resultImg(filter->filterImage(srcImg, ctx, &offset)); if (resultImg) { SkPaint tmpUnfiltered(paint); tmpUnfiltered.setImageFilter(nullptr); if (resultImg->getROPixels(&resultBM)) { - this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); + this->drawSprite(resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); } } } else { if (srcImg->getROPixels(&resultBM)) { - this->drawSprite(draw, resultBM, x, y, paint); + this->drawSprite(resultBM, x, y, paint); } } } @@ -419,7 +427,7 @@ sk_sp SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) { sk_sp SkBitmapDevice::makeSpecial(const SkImage* image) { return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()), - image->makeNonTextureImage()); + image->makeNonTextureImage(), fBitmap.colorSpace()); } sk_sp SkBitmapDevice::snapSpecial() { @@ -438,7 +446,7 @@ SkImageFilterCache* SkBitmapDevice::getImageFilterCache() { return cache; } -/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const { if (kN32_SkColorType != fBitmap.colorType() || @@ -452,3 +460,77 @@ bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const { } return false; } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void SkBitmapDevice::onSave() { + fRCStack.save(); +} + +void SkBitmapDevice::onRestore() { + fRCStack.restore(); +} + +void SkBitmapDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) { + fRCStack.clipRect(this->ctm(), rect, op, aa); +} + +void SkBitmapDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) { + fRCStack.clipRRect(this->ctm(), rrect, op, aa); +} + +void SkBitmapDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) { + fRCStack.clipPath(this->ctm(), path, op, aa); +} + +void SkBitmapDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) { + SkIPoint origin = this->getOrigin(); + SkRegion tmp; + const SkRegion* ptr = &rgn; + if (origin.fX | origin.fY) { + // translate from "global/canvas" coordinates to relative to this device + rgn.translate(-origin.fX, -origin.fY, &tmp); + ptr = &tmp; + } + fRCStack.clipRegion(*ptr, op); +} + +void SkBitmapDevice::onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) { + fRCStack.setDeviceClipRestriction(mutableClipRestriction); + if (!mutableClipRestriction->isEmpty()) { + SkRegion rgn(*mutableClipRestriction); + fRCStack.clipRegion(rgn, SkClipOp::kIntersect); + } +} + +bool SkBitmapDevice::onClipIsAA() const { + const SkRasterClip& rc = fRCStack.rc(); + return !rc.isEmpty() && rc.isAA(); +} + +void SkBitmapDevice::onAsRgnClip(SkRegion* rgn) const { + const SkRasterClip& rc = fRCStack.rc(); + if (rc.isAA()) { + rgn->setRect(rc.getBounds()); + } else { + *rgn = rc.bwRgn(); + } +} + +void SkBitmapDevice::validateDevBounds(const SkIRect& drawClipBounds) { +#ifdef SK_DEBUG + const SkIRect& stackBounds = fRCStack.rc().getBounds(); + SkASSERT(drawClipBounds == stackBounds); +#endif +} + +SkBaseDevice::ClipType SkBitmapDevice::onGetClipType() const { + const SkRasterClip& rc = fRCStack.rc(); + if (rc.isEmpty()) { + return kEmpty_ClipType; + } else if (rc.isRect()) { + return kRect_ClipType; + } else { + return kComplex_ClipType; + } +} diff --git a/gfx/skia/skia/include/core/SkBitmapDevice.h b/gfx/skia/skia/src/core/SkBitmapDevice.h similarity index 60% rename from gfx/skia/skia/include/core/SkBitmapDevice.h rename to gfx/skia/skia/src/core/SkBitmapDevice.h index 31c0aa3a35e5..8055b9d12df9 100644 --- a/gfx/skia/skia/include/core/SkBitmapDevice.h +++ b/gfx/skia/skia/src/core/SkBitmapDevice.h @@ -1,4 +1,3 @@ - /* * Copyright 2013 Google Inc. * @@ -14,22 +13,23 @@ #include "SkColor.h" #include "SkDevice.h" #include "SkImageInfo.h" +#include "SkPixelRef.h" +#include "SkRasterClip.h" +#include "SkRasterClipStack.h" #include "SkRect.h" #include "SkScalar.h" #include "SkSize.h" #include "SkSurfaceProps.h" -#include "SkTypes.h" -class SkDraw; class SkImageFilterCache; class SkMatrix; class SkPaint; class SkPath; class SkPixelRef; class SkPixmap; +class SkRasterHandleAllocator; class SkRRect; class SkSurface; -class SkXfermode; struct SkPoint; /////////////////////////////////////////////////////////////////////////////// @@ -54,27 +54,27 @@ public: * valid for the bitmap to have no pixels associated with it. In that case, * any drawing to this device will have no effect. */ - SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps); + SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps, + void* externalHandle = nullptr); - static SkBitmapDevice* Create(const SkImageInfo&, const SkSurfaceProps&); + static SkBitmapDevice* Create(const SkImageInfo&, const SkSurfaceProps&, + SkRasterHandleAllocator* = nullptr); protected: bool onShouldDisableLCD(const SkPaint&) const override; + void* getRasterHandle() const override { return fRasterHandle; } /** These are called inside the per-device-layer loop for each draw call. When these are called, we have already applied any saveLayer operations, and are handling any looping from the paint, and any effects from the DrawFilter. */ - void drawPaint(const SkDraw&, const SkPaint& paint) override; - virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, + void drawPaint(const SkPaint& paint) override; + void drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint[], const SkPaint& paint) override; - virtual void drawRect(const SkDraw&, const SkRect& r, - const SkPaint& paint) override; - virtual void drawOval(const SkDraw&, const SkRect& oval, - const SkPaint& paint) override; - virtual void drawRRect(const SkDraw&, const SkRRect& rr, - const SkPaint& paint) override; + void drawRect(const SkRect& r, const SkPaint& paint) override; + void drawOval(const SkRect& oval, const SkPaint& paint) override; + void drawRRect(const SkRRect& rr, const SkPaint& paint) override; /** * If pathIsMutable, then the implementation is allowed to cast path to a @@ -87,78 +87,65 @@ protected: * affect the geometry/rasterization, then the pre matrix can just be * pre-concated with the current matrix. */ - virtual void drawPath(const SkDraw&, const SkPath& path, - const SkPaint& paint, - const SkMatrix* prePathMatrix = NULL, - bool pathIsMutable = false) override; - virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, - const SkMatrix& matrix, const SkPaint& paint) override; - virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, - int x, int y, const SkPaint& paint) override; + void drawPath(const SkPath&, const SkPaint&, const SkMatrix* prePathMatrix, + bool pathIsMutable) override; + void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override; + void drawSprite(const SkBitmap&, int x, int y, const SkPaint&) override; /** * The default impl. will create a bitmap-shader from the bitmap, * and call drawRect with it. */ - void drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect*, const SkRect&, + void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&, SkCanvas::SrcRectConstraint) override; /** * Does not handle text decoration. * Decorations (underline and stike-thru) will be handled by SkCanvas. */ - virtual void drawText(const SkDraw&, const void* text, size_t len, - SkScalar x, SkScalar y, const SkPaint& paint) override; - virtual void drawPosText(const SkDraw&, const void* text, size_t len, - const SkScalar pos[], int scalarsPerPos, - const SkPoint& offset, const SkPaint& paint) override; - virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, - const SkPoint verts[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) override; - virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, const SkPaint&) override; + void drawText(const void* text, size_t len, SkScalar x, SkScalar y, + const SkPaint&) override; + void drawPosText(const void* text, size_t len, const SkScalar pos[], + int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override; + void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override; + void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; /////////////////////////////////////////////////////////////////////////// - - void drawSpecial(const SkDraw&, SkSpecialImage*, int x, int y, const SkPaint&) override; + + void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&) override; sk_sp makeSpecial(const SkBitmap&) override; sk_sp makeSpecial(const SkImage*) override; sk_sp snapSpecial() override; /////////////////////////////////////////////////////////////////////////// - /** Update as needed the pixel value in the bitmap, so that the caller can - access the pixels directly. Note: only the pixels field should be - altered. The config/width/height/rowbytes must remain unchanged. - @return the device contents as a bitmap - */ -#ifdef SK_SUPPORT_LEGACY_ACCESSBITMAP - const SkBitmap& onAccessBitmap() override; -#else - const SkBitmap& onAccessBitmap(); -#endif - - SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); } - // just for subclasses, to assign a custom pixelref - SkPixelRef* setPixelRef(SkPixelRef* pr) { - fBitmap.setPixelRef(pr); - return pr; - } - bool onReadPixels(const SkImageInfo&, void*, size_t, int x, int y) override; bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) override; bool onPeekPixels(SkPixmap*) override; bool onAccessPixels(SkPixmap*) override; + void onSave() override; + void onRestore() override; + void onClipRect(const SkRect& rect, SkClipOp, bool aa) override; + void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override; + void onClipPath(const SkPath& path, SkClipOp, bool aa) override; + void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override; + void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override; + bool onClipIsAA() const override; + void onAsRgnClip(SkRegion*) const override; + void validateDevBounds(const SkIRect& r) override; + ClipType onGetClipType() const override; + private: friend class SkCanvas; friend struct DeviceCM; //for setMatrixClip friend class SkDraw; friend class SkDrawIter; friend class SkDeviceFilteredPaint; - friend class SkSurface_Raster; + friend class SkThreadedBMPDevice; // to copy fRCStack + + class BDDraw; // used to change the backend's pixels (and possibly config/rowbytes) // but cannot change the width/height, so there should be no change to @@ -172,8 +159,8 @@ private: SkImageFilterCache* getImageFilterCache() override; SkBitmap fBitmap; - - void setNewSize(const SkISize&); // Used by SkCanvas for resetForNextPicture(). + void* fRasterHandle = nullptr; + SkRasterClipStack fRCStack; typedef SkBaseDevice INHERITED; }; diff --git a/gfx/skia/skia/src/core/SkBitmapProcShader.cpp b/gfx/skia/skia/src/core/SkBitmapProcShader.cpp index e0d281b026fa..3472bf063835 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcShader.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProcShader.cpp @@ -6,8 +6,11 @@ */ #include "SkBitmapProcShader.h" + +#include "SkArenaAlloc.h" #include "SkBitmapProcState.h" #include "SkBitmapProvider.h" +#include "SkXfermodePriv.h" static bool only_scale_and_translate(const SkMatrix& matrix) { unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; @@ -32,10 +35,6 @@ public: } } - ~BitmapProcInfoContext() override { - fInfo->~SkBitmapProcInfo(); - } - uint32_t getFlags() const override { return fFlags; } private: @@ -102,33 +101,30 @@ private: /////////////////////////////////////////////////////////////////////////////////////////////////// #include "SkLinearBitmapPipeline.h" #include "SkPM4f.h" -#include "SkXfermode.h" class LinearPipelineContext : public BitmapProcInfoContext { public: LinearPipelineContext(const SkShader& shader, const SkShader::ContextRec& rec, - SkBitmapProcInfo* info) - : INHERITED(shader, rec, info) + SkBitmapProcInfo* info, SkArenaAlloc* alloc) + : INHERITED(shader, rec, info), fAllocator{alloc} { // Save things off in case we need to build a blitter pipeline. fSrcPixmap = info->fPixmap; fAlpha = SkColorGetA(info->fPaintColor) / 255.0f; - fXMode = info->fTileModeX; - fYMode = info->fTileModeY; fFilterQuality = info->fFilterQuality; fMatrixTypeMask = info->fRealInvMatrix.getType(); - fShaderPipeline.init( + fShaderPipeline = alloc->make( info->fRealInvMatrix, info->fFilterQuality, info->fTileModeX, info->fTileModeY, info->fPaintColor, - info->fPixmap); + info->fPixmap, + fAllocator); // To implement the old shadeSpan entry-point, we need to efficiently convert our native // floats into SkPMColor. The SkXfermode::D32Procs do exactly that. // - sk_sp xfer(SkXfermode::Make(SkXfermode::kSrc_Mode)); - fXferProc = SkXfermode::GetD32Proc(xfer.get(), 0); + fSrcModeProc = SkXfermode::GetD32Proc(SkBlendMode::kSrc, 0); } void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override { @@ -142,7 +138,7 @@ public: while (count > 0) { const int n = SkTMin(count, N); fShaderPipeline->shadeSpan4f(x, y, tmp, n); - fXferProc(nullptr, dstC, tmp, n, nullptr); + fSrcModeProc(SkBlendMode::kSrc, dstC, tmp, n, nullptr); dstC += n; x += n; count -= n; @@ -150,17 +146,13 @@ public: } bool onChooseBlitProcs(const SkImageInfo& dstInfo, BlitState* state) override { - SkXfermode::Mode mode; - if (!SkXfermode::AsMode(state->fXfer, &mode)) { return false; } - - if (SkLinearBitmapPipeline::ClonePipelineForBlitting( - &fBlitterPipeline, *fShaderPipeline, + if ((fBlitterPipeline = SkLinearBitmapPipeline::ClonePipelineForBlitting( + *fShaderPipeline, fMatrixTypeMask, - fXMode, fYMode, fFilterQuality, fSrcPixmap, - fAlpha, mode, dstInfo)) + fAlpha, state->fMode, dstInfo, fAllocator))) { - state->fStorage[0] = fBlitterPipeline.get(); + state->fStorage[0] = fBlitterPipeline; state->fBlitBW = &LinearPipelineContext::ForwardToPipeline; return true; @@ -176,15 +168,15 @@ public: } private: - SkEmbeddableLinearPipeline fShaderPipeline; - SkEmbeddableLinearPipeline fBlitterPipeline; - SkXfermode::D32Proc fXferProc; - SkPixmap fSrcPixmap; - float fAlpha; - SkShader::TileMode fXMode; - SkShader::TileMode fYMode; - SkMatrix::TypeMask fMatrixTypeMask; - SkFilterQuality fFilterQuality; + // Store the allocator from the context creation incase we are asked to build a blitter. + SkArenaAlloc* fAllocator; + SkLinearBitmapPipeline* fShaderPipeline; + SkLinearBitmapPipeline* fBlitterPipeline; + SkXfermode::D32Proc fSrcModeProc; + SkPixmap fSrcPixmap; + float fAlpha; + SkMatrix::TypeMask fMatrixTypeMask; + SkFilterQuality fFilterQuality; typedef BitmapProcInfoContext INHERITED; }; @@ -205,13 +197,12 @@ size_t SkBitmapProcLegacyShader::ContextSize(const ContextRec& rec, const SkImag size_t size1 = sizeof(LinearPipelineContext) + sizeof(SkBitmapProcInfo); size_t s = SkTMax(size0, size1); return s; - return SkTMax(size0, size1); } -SkShader::Context* SkBitmapProcLegacyShader::MakeContext(const SkShader& shader, - TileMode tmx, TileMode tmy, - const SkBitmapProvider& provider, - const ContextRec& rec, void* storage) { +SkShader::Context* SkBitmapProcLegacyShader::MakeContext( + const SkShader& shader, TileMode tmx, TileMode tmy, + const SkBitmapProvider& provider, const ContextRec& rec, SkArenaAlloc* alloc) +{ SkMatrix totalInverse; // Do this first, so we know the matrix can be inverted. if (!shader.computeTotalInverse(rec, &totalInverse)) { @@ -220,25 +211,19 @@ SkShader::Context* SkBitmapProcLegacyShader::MakeContext(const SkShader& shader, // Decide if we can/want to use the new linear pipeline bool useLinearPipeline = choose_linear_pipeline(rec, provider.info()); - SkSourceGammaTreatment treatment = SkMipMap::DeduceTreatment(rec); if (useLinearPipeline) { - void* infoStorage = (char*)storage + sizeof(LinearPipelineContext); - SkBitmapProcInfo* info = new (infoStorage) SkBitmapProcInfo(provider, tmx, tmy, treatment); + SkBitmapProcInfo* info = alloc->make(provider, tmx, tmy); if (!info->init(totalInverse, *rec.fPaint)) { - info->~SkBitmapProcInfo(); return nullptr; } - return new (storage) LinearPipelineContext(shader, rec, info); + return alloc->make(shader, rec, info, alloc); } else { - void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext); - SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy, - treatment); + SkBitmapProcState* state = alloc->make(provider, tmx, tmy); if (!state->setup(totalInverse, *rec.fPaint)) { - state->~SkBitmapProcState(); return nullptr; } - return new (storage) BitmapProcShaderContext(shader, rec, state); + return alloc->make(shader, rec, state); } } diff --git a/gfx/skia/skia/src/core/SkBitmapProcShader.h b/gfx/skia/skia/src/core/SkBitmapProcShader.h index 4b7447e52e5d..204b27dd4cf7 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcShader.h +++ b/gfx/skia/skia/src/core/SkBitmapProcShader.h @@ -18,7 +18,7 @@ private: static size_t ContextSize(const ContextRec&, const SkImageInfo& srcInfo); static Context* MakeContext(const SkShader&, TileMode tmx, TileMode tmy, - const SkBitmapProvider&, const ContextRec&, void* storage); + const SkBitmapProvider&, const ContextRec&, SkArenaAlloc* alloc); typedef SkShader INHERITED; }; diff --git a/gfx/skia/skia/src/core/SkBitmapProcState.cpp b/gfx/skia/skia/src/core/SkBitmapProcState.cpp index 183016e69595..253afba41a27 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProcState.cpp @@ -19,7 +19,7 @@ #include "SkImageEncoder.h" #include "SkResourceCache.h" -#if defined(SK_ARM_HAS_NEON) || defined(SK_ARM_HAS_OPTIONAL_NEON) +#if defined(SK_ARM_HAS_NEON) // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*); @@ -37,22 +37,10 @@ extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void*, int, int, u #include "SkBitmapProcState_procs.h" SkBitmapProcInfo::SkBitmapProcInfo(const SkBitmapProvider& provider, - SkShader::TileMode tmx, SkShader::TileMode tmy, - SkSourceGammaTreatment treatment) + SkShader::TileMode tmx, SkShader::TileMode tmy) : fProvider(provider) , fTileModeX(tmx) , fTileModeY(tmy) - , fSrcGammaTreatment(treatment) - , fBMState(nullptr) -{} - -SkBitmapProcInfo::SkBitmapProcInfo(const SkBitmap& bm, - SkShader::TileMode tmx, SkShader::TileMode tmy, - SkSourceGammaTreatment treatment) - : fProvider(SkBitmapProvider(bm)) - , fTileModeX(tmx) - , fTileModeY(tmy) - , fSrcGammaTreatment(treatment) , fBMState(nullptr) {} @@ -62,9 +50,9 @@ SkBitmapProcInfo::~SkBitmapProcInfo() { /////////////////////////////////////////////////////////////////////////////// -// true iff the matrix contains, at most, scale and translate elements +// true iff the matrix has a scale and no more than an optional translate. static bool matrix_only_scale_translate(const SkMatrix& m) { - return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask); + return (m.getType() & ~SkMatrix::kTranslate_Mask) == SkMatrix::kScale_Mask; } /** @@ -74,44 +62,32 @@ static bool matrix_only_scale_translate(const SkMatrix& m) { static bool just_trans_clamp(const SkMatrix& matrix, const SkPixmap& pixmap) { SkASSERT(matrix_only_scale_translate(matrix)); - if (matrix.getType() & SkMatrix::kScale_Mask) { - SkRect dst; - SkRect src = SkRect::Make(pixmap.bounds()); + SkRect dst; + SkRect src = SkRect::Make(pixmap.bounds()); - // Can't call mapRect(), since that will fix up inverted rectangles, - // e.g. when scale is negative, and we don't want to return true for - // those. - matrix.mapPoints(SkTCast(&dst), - SkTCast(&src), - 2); + // Can't call mapRect(), since that will fix up inverted rectangles, + // e.g. when scale is negative, and we don't want to return true for + // those. + matrix.mapPoints(SkTCast(&dst), + SkTCast(&src), + 2); - // Now round all 4 edges to device space, and then compare the device - // width/height to the original. Note: we must map all 4 and subtract - // rather than map the "width" and compare, since we care about the - // phase (in pixel space) that any translate in the matrix might impart. - SkIRect idst; - dst.round(&idst); - return idst.width() == pixmap.width() && idst.height() == pixmap.height(); - } - // if we got here, we're either kTranslate_Mask or identity - return true; + // Now round all 4 edges to device space, and then compare the device + // width/height to the original. Note: we must map all 4 and subtract + // rather than map the "width" and compare, since we care about the + // phase (in pixel space) that any translate in the matrix might impart. + SkIRect idst; + dst.round(&idst); + return idst.width() == pixmap.width() && idst.height() == pixmap.height(); } static bool just_trans_general(const SkMatrix& matrix) { SkASSERT(matrix_only_scale_translate(matrix)); - if (matrix.getType() & SkMatrix::kScale_Mask) { - const SkScalar tol = SK_Scalar1 / 32768; + const SkScalar tol = SK_Scalar1 / 32768; - if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) { - return false; - } - if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) { - return false; - } - } - // if we got here, treat us as either kTranslate_Mask or identity - return true; + return SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol) + && SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol); } static bool valid_for_filtering(unsigned dimension) { @@ -133,7 +109,7 @@ bool SkBitmapProcInfo::init(const SkMatrix& inv, const SkPaint& paint) { allow_ignore_fractional_translate = false; } - SkDefaultBitmapController controller(fSrcGammaTreatment); + SkDefaultBitmapController controller(SkDefaultBitmapController::CanShadeHQ::kNo); fBMState = controller.requestBitmap(fProvider, inv, paint.getFilterQuality(), fBMStateStorage.get(), fBMStateStorage.size()); // Note : we allow the controller to return an empty (zero-dimension) result. Should we? @@ -158,7 +134,9 @@ bool SkBitmapProcInfo::init(const SkMatrix& inv, const SkPaint& paint) { // We don't do this if we're either trivial (can ignore the matrix) or clamping // in both X and Y since clamping to width,height is just as easy as to 0xFFFF. - if (!(clampClamp || trivialMatrix)) { + // Note that we cannot ignore the matrix when allow_ignore_fractional_translate is false. + + if (!(clampClamp || (trivialMatrix && allow_ignore_fractional_translate))) { fInvMatrix.postIDiv(fPixmap.width(), fPixmap.height()); } @@ -300,7 +278,7 @@ bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp) return false; } -#if !defined(SK_ARM_HAS_NEON) || defined(SK_ARM_HAS_OPTIONAL_NEON) +#if !defined(SK_ARM_HAS_NEON) static const SampleProc32 gSkBitmapProcStateSample32[] = { S32_opaque_D32_nofilter_DXDY, S32_alpha_D32_nofilter_DXDY, diff --git a/gfx/skia/skia/src/core/SkBitmapProcState.h b/gfx/skia/skia/src/core/SkBitmapProcState.h index e2e4f96951e8..73eaf4fb7c88 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState.h @@ -28,24 +28,20 @@ typedef SkFixed3232 SkFractionalInt; class SkPaint; struct SkBitmapProcInfo { - SkBitmapProcInfo(const SkBitmapProvider&, SkShader::TileMode tmx, SkShader::TileMode tmy, - SkSourceGammaTreatment); - SkBitmapProcInfo(const SkBitmap&, SkShader::TileMode tmx, SkShader::TileMode tmy, - SkSourceGammaTreatment); + SkBitmapProcInfo(const SkBitmapProvider&, SkShader::TileMode tmx, SkShader::TileMode tmy); ~SkBitmapProcInfo(); - const SkBitmapProvider fProvider; + const SkBitmapProvider fProvider; - SkPixmap fPixmap; - SkMatrix fInvMatrix; // This changes based on tile mode. + SkPixmap fPixmap; + SkMatrix fInvMatrix; // This changes based on tile mode. // TODO: combine fInvMatrix and fRealInvMatrix. - SkMatrix fRealInvMatrix; // The actual inverse matrix. - SkColor fPaintColor; - SkShader::TileMode fTileModeX; - SkShader::TileMode fTileModeY; - SkFilterQuality fFilterQuality; - SkMatrix::TypeMask fInvType; - SkSourceGammaTreatment fSrcGammaTreatment; + SkMatrix fRealInvMatrix; // The actual inverse matrix. + SkColor fPaintColor; + SkShader::TileMode fTileModeX; + SkShader::TileMode fTileModeY; + SkFilterQuality fFilterQuality; + SkMatrix::TypeMask fInvType; bool init(const SkMatrix& inverse, const SkPaint&); @@ -58,12 +54,8 @@ private: }; struct SkBitmapProcState : public SkBitmapProcInfo { - SkBitmapProcState(const SkBitmapProvider& prov, SkShader::TileMode tmx, SkShader::TileMode tmy, - SkSourceGammaTreatment treatment) - : SkBitmapProcInfo(prov, tmx, tmy, treatment) {} - SkBitmapProcState(const SkBitmap& bitmap, SkShader::TileMode tmx, SkShader::TileMode tmy, - SkSourceGammaTreatment treatment) - : SkBitmapProcInfo(bitmap, tmx, tmy, treatment) {} + SkBitmapProcState(const SkBitmapProvider& prov, SkShader::TileMode tmx, SkShader::TileMode tmy) + : SkBitmapProcInfo(prov, tmx, tmy) {} bool setup(const SkMatrix& inv, const SkPaint& paint) { return this->init(inv, paint) && this->chooseProcs(); @@ -84,7 +76,6 @@ struct SkBitmapProcState : public SkBitmapProcInfo { SkPMColor colors[]); typedef U16CPU (*FixedTileProc)(SkFixed); // returns 0..0xFFFF - typedef U16CPU (*FixedTileLowBitsProc)(SkFixed, int); // returns 0..0xF typedef U16CPU (*IntTileProc)(int value, int count); // returns 0..count-1 SkMatrix::MapXYProc fInvProc; // chooseProcs @@ -93,8 +84,6 @@ struct SkBitmapProcState : public SkBitmapProcInfo { FixedTileProc fTileProcX; // chooseProcs FixedTileProc fTileProcY; // chooseProcs - FixedTileLowBitsProc fTileLowBitsProcX; // chooseProcs - FixedTileLowBitsProc fTileLowBitsProcY; // chooseProcs IntTileProc fIntTileProcY; // chooseProcs SkFixed fFilterOneX; SkFixed fFilterOneY; @@ -244,8 +233,11 @@ public: biasY = s.fFilterOneY >> 1; } - fX = SkScalarToFractionalInt(pt.x()) - SkFixedToFractionalInt(biasX); - fY = SkScalarToFractionalInt(pt.y()) - SkFixedToFractionalInt(biasY); + // punt to unsigned for defined underflow behavior + fX = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.x()) - + (uint64_t)SkFixedToFractionalInt(biasX)); + fY = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.y()) - + (uint64_t)SkFixedToFractionalInt(biasY)); if (scalarPoint) { scalarPoint->set(pt.x() - SkFixedToScalar(biasX), diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_matrix.h b/gfx/skia/skia/src/core/SkBitmapProcState_matrix.h index 7e2e44bceea2..ea784c675c8d 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_matrix.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState_matrix.h @@ -35,14 +35,14 @@ void PERSP_FILTER_NAME(const SkBitmapProcState& s, static inline uint32_t PACK_FILTER_Y_NAME(SkFixed f, unsigned max, SkFixed one PREAMBLE_PARAM_Y) { unsigned i = TILEY_PROCF(f, max); - i = (i << 4) | TILEY_LOW_BITS(f, max); + i = (i << 4) | EXTRACT_LOW_BITS(f, max); return (i << 14) | (TILEY_PROCF((f + one), max)); } static inline uint32_t PACK_FILTER_X_NAME(SkFixed f, unsigned max, SkFixed one PREAMBLE_PARAM_X) { unsigned i = TILEX_PROCF(f, max); - i = (i << 4) | TILEX_LOW_BITS(f, max); + i = (i << 4) | EXTRACT_LOW_BITS(f, max); return (i << 14) | (TILEX_PROCF((f + one), max)); } @@ -70,9 +70,10 @@ void SCALE_FILTER_NAME(const SkBitmapProcState& s, } #ifdef CHECK_FOR_DECAL - if (can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) { - decal_filter_scale(xy, SkFractionalIntToFixed(fx), - SkFractionalIntToFixed(dx), count); + const SkFixed fixedFx = SkFractionalIntToFixed(fx); + const SkFixed fixedDx = SkFractionalIntToFixed(dx); + if (can_truncate_to_fixed_for_decal(fixedFx, fixedDx, count, maxX)) { + decal_filter_scale(xy, fixedFx, fixedDx, count); } else #endif { @@ -155,5 +156,4 @@ void PERSP_FILTER_NAME(const SkBitmapProcState& s, #undef PREAMBLE_ARG_X #undef PREAMBLE_ARG_Y -#undef TILEX_LOW_BITS -#undef TILEY_LOW_BITS +#undef EXTRACT_LOW_BITS diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp b/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp index 50b59b8bdfcd..08753bed9983 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp @@ -47,7 +47,7 @@ void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count); /////////////////////////////////////////////////////////////////////////////// // Compile neon code paths if needed -#if defined(SK_ARM_HAS_NEON) || defined(SK_ARM_HAS_OPTIONAL_NEON) +#if defined(SK_ARM_HAS_NEON) // These are defined in src/opts/SkBitmapProcState_matrixProcs_neon.cpp extern const SkBitmapProcState::MatrixProc ClampX_ClampY_Procs_neon[]; @@ -56,12 +56,11 @@ extern const SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs_neon[]; #endif // defined(SK_ARM_HAS_NEON) // Compile non-neon code path if needed -#if !defined(SK_ARM_HAS_NEON) || defined(SK_ARM_HAS_OPTIONAL_NEON) -#define MAKENAME(suffix) ClampX_ClampY ## suffix -#define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max) -#define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max) -#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF) -#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF) +#if !defined(SK_ARM_HAS_NEON) +#define MAKENAME(suffix) ClampX_ClampY ## suffix +#define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max) +#define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max) +#define EXTRACT_LOW_BITS(v, max) (((v) >> 12) & 0xF) #define CHECK_FOR_DECAL #include "SkBitmapProcState_matrix.h" @@ -94,11 +93,10 @@ static SkBitmapProcState::MatrixProc ClampX_ClampY_Procs[] = { ClampX_ClampY_filter_persp }; -#define MAKENAME(suffix) RepeatX_RepeatY ## suffix -#define TILEX_PROCF(fx, max) SK_USHIFT16((unsigned)((fx) & 0xFFFF) * ((max) + 1)) -#define TILEY_PROCF(fy, max) SK_USHIFT16((unsigned)((fy) & 0xFFFF) * ((max) + 1)) -#define TILEX_LOW_BITS(fx, max) (((unsigned)((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) -#define TILEY_LOW_BITS(fy, max) (((unsigned)((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) +#define MAKENAME(suffix) RepeatX_RepeatY ## suffix +#define TILEX_PROCF(fx, max) SK_USHIFT16((unsigned)((fx) & 0xFFFF) * ((max) + 1)) +#define TILEY_PROCF(fy, max) SK_USHIFT16((unsigned)((fy) & 0xFFFF) * ((max) + 1)) +#define EXTRACT_LOW_BITS(v, max) (((unsigned)((v) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) #include "SkBitmapProcState_matrix.h" struct RepeatTileProcs { @@ -124,17 +122,14 @@ static SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs[] = { #define MAKENAME(suffix) GeneralXY ## suffix #define PREAMBLE(state) SkBitmapProcState::FixedTileProc tileProcX = (state).fTileProcX; (void) tileProcX; \ - SkBitmapProcState::FixedTileProc tileProcY = (state).fTileProcY; (void) tileProcY; \ - SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcX = (state).fTileLowBitsProcX; (void) tileLowBitsProcX; \ - SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcY = (state).fTileLowBitsProcY; (void) tileLowBitsProcY -#define PREAMBLE_PARAM_X , SkBitmapProcState::FixedTileProc tileProcX, SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcX -#define PREAMBLE_PARAM_Y , SkBitmapProcState::FixedTileProc tileProcY, SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcY -#define PREAMBLE_ARG_X , tileProcX, tileLowBitsProcX -#define PREAMBLE_ARG_Y , tileProcY, tileLowBitsProcY + SkBitmapProcState::FixedTileProc tileProcY = (state).fTileProcY; (void) tileProcY; +#define PREAMBLE_PARAM_X , SkBitmapProcState::FixedTileProc tileProcX +#define PREAMBLE_PARAM_Y , SkBitmapProcState::FixedTileProc tileProcY +#define PREAMBLE_ARG_X , tileProcX +#define PREAMBLE_ARG_Y , tileProcY #define TILEX_PROCF(fx, max) SK_USHIFT16(tileProcX(fx) * ((max) + 1)) #define TILEY_PROCF(fy, max) SK_USHIFT16(tileProcY(fy) * ((max) + 1)) -#define TILEX_LOW_BITS(fx, max) tileLowBitsProcX(fx, (max) + 1) -#define TILEY_LOW_BITS(fy, max) tileLowBitsProcY(fy, (max) + 1) +#define EXTRACT_LOW_BITS(v, max) (((v * (max + 1)) >> 12) & 0xF) #include "SkBitmapProcState_matrix.h" struct GeneralTileProcs { @@ -188,25 +183,6 @@ static SkBitmapProcState::FixedTileProc choose_tile_proc(unsigned m) { return fixed_mirror; } -static inline U16CPU fixed_clamp_lowbits(SkFixed x, int) { - return (x >> 12) & 0xF; -} - -static inline U16CPU fixed_repeat_or_mirrow_lowbits(SkFixed x, int scale) { - return ((x * scale) >> 12) & 0xF; -} - -static SkBitmapProcState::FixedTileLowBitsProc choose_tile_lowbits_proc(unsigned m) { - if (SkShader::kClamp_TileMode == m) { - return fixed_clamp_lowbits; - } else { - SkASSERT(SkShader::kMirror_TileMode == m || - SkShader::kRepeat_TileMode == m); - // mirror and repeat have the same behavior for the low bits. - return fixed_repeat_or_mirrow_lowbits; - } -} - static inline U16CPU int_clamp(int x, int n) { if (x >= n) { x = n - 1; @@ -514,7 +490,5 @@ SkBitmapProcState::MatrixProc SkBitmapProcState::chooseMatrixProc(bool trivial_m fTileProcX = choose_tile_proc(fTileModeX); fTileProcY = choose_tile_proc(fTileModeY); - fTileLowBitsProcX = choose_tile_lowbits_proc(fTileModeX); - fTileLowBitsProcY = choose_tile_lowbits_proc(fTileModeY); return GeneralXY_Procs[index]; } diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_matrix_template.h b/gfx/skia/skia/src/core/SkBitmapProcState_matrix_template.h index 0c9371851c1f..c38610a0773b 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_matrix_template.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState_matrix_template.h @@ -36,33 +36,38 @@ void NoFilterProc_Scale(const SkBitmapProcState& s, uint32_t xy[], const SkFractionalInt dx = s.fInvSxFractionalInt; - if (tryDecal && can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) { - decal_nofilter_scale(xy, SkFractionalIntToFixed(fx), - SkFractionalIntToFixed(dx), count); - } else { - int i; - for (i = (count >> 2); i > 0; --i) { - unsigned a, b; - a = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx; - b = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx; -#ifdef SK_CPU_BENDIAN - *xy++ = (a << 16) | b; -#else - *xy++ = (b << 16) | a; -#endif - a = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx; - b = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx; -#ifdef SK_CPU_BENDIAN - *xy++ = (a << 16) | b; -#else - *xy++ = (b << 16) | a; -#endif - } - uint16_t* xx = (uint16_t*)xy; - for (i = (count & 3); i > 0; --i) { - *xx++ = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx; + if (tryDecal) { + const SkFixed fixedFx = SkFractionalIntToFixed(fx); + const SkFixed fixedDx = SkFractionalIntToFixed(dx); + + if (can_truncate_to_fixed_for_decal(fixedFx, fixedDx, count, maxX)) { + decal_nofilter_scale(xy, fixedFx, fixedDx, count); + return; } } + + int i; + for (i = (count >> 2); i > 0; --i) { + unsigned a, b; + a = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx; + b = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx; +#ifdef SK_CPU_BENDIAN + *xy++ = (a << 16) | b; +#else + *xy++ = (b << 16) | a; +#endif + a = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx; + b = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx; +#ifdef SK_CPU_BENDIAN + *xy++ = (a << 16) | b; +#else + *xy++ = (b << 16) | a; +#endif + } + uint16_t* xx = (uint16_t*)xy; + for (i = (count & 3); i > 0; --i) { + *xx++ = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx; + } } // note: we could special-case on a matrix which is skewed in X but not Y. diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_procs.h b/gfx/skia/skia/src/core/SkBitmapProcState_procs.h index cec079eae5fc..fb104ace9cb1 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_procs.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState_procs.h @@ -233,10 +233,9 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, #include "SkBitmapProcState_sample.h" -#define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max) -#define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max) -#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF) -#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF) +#define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max) +#define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max) +#define EXTRACT_LOW_BITS(v, max) (((v) >> 12) & 0xF) #undef FILTER_PROC #define FILTER_PROC(x, y, a, b, c, d, dst) NAME_WRAP(Filter_32_opaque)(x, y, a, b, c, d, dst) diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_shaderproc.h b/gfx/skia/skia/src/core/SkBitmapProcState_shaderproc.h index 523b5621e22f..1816d0464c29 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_shaderproc.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState_shaderproc.h @@ -35,7 +35,7 @@ void SCALE_FILTER_NAME(const void* sIn, int x, int y, SkPMColor* SK_RESTRICT col SkFixed fy = mapper.fixedY(); const unsigned maxY = s.fPixmap.height() - 1; // compute our two Y values up front - subY = TILEY_LOW_BITS(fy, maxY); + subY = EXTRACT_LOW_BITS(fy, maxY); int y0 = TILEY_PROCF(fy, maxY); int y1 = TILEY_PROCF((fy + s.fFilterOneY), maxY); @@ -52,7 +52,7 @@ void SCALE_FILTER_NAME(const void* sIn, int x, int y, SkPMColor* SK_RESTRICT col #endif do { - unsigned subX = TILEX_LOW_BITS(fx, maxX); + unsigned subX = EXTRACT_LOW_BITS(fx, maxX); unsigned x0 = TILEX_PROCF(fx, maxX); unsigned x1 = TILEX_PROCF((fx + oneX), maxX); @@ -76,8 +76,7 @@ void SCALE_FILTER_NAME(const void* sIn, int x, int y, SkPMColor* SK_RESTRICT col #undef TILEX_PROCF #undef TILEY_PROCF -#undef TILEX_LOW_BITS -#undef TILEY_LOW_BITS +#undef EXTRACT_LOW_BITS #undef MAKENAME #undef SRCTYPE #undef CHECKSTATE diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_utils.h b/gfx/skia/skia/src/core/SkBitmapProcState_utils.h index 3c4c1fa8c67f..4609ff34e789 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_utils.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState_utils.h @@ -1,10 +1,17 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + #ifndef SkBitmapProcState_utils_DEFINED #define SkBitmapProcState_utils_DEFINED // Helper to ensure that when we shift down, we do it w/o sign-extension // so the caller doesn't have to manually mask off the top 16 bits // -static unsigned SK_USHIFT16(unsigned x) { +static inline unsigned SK_USHIFT16(unsigned x) { return x >> 16; } @@ -18,10 +25,10 @@ static unsigned SK_USHIFT16(unsigned x) { * the decal_ function just operates on SkFixed. If that were changed, we could * skip the very_small test here. */ -static inline bool can_truncate_to_fixed_for_decal(SkFractionalInt frX, - SkFractionalInt frDx, +static inline bool can_truncate_to_fixed_for_decal(SkFixed fx, + SkFixed dx, int count, unsigned max) { - SkFixed dx = SkFractionalIntToFixed(frDx); + SkASSERT(count > 0); // if decal_ kept SkFractionalInt precision, this would just be dx <= 0 // I just made up the 1/256. Just don't want to perceive accumulated error @@ -30,11 +37,20 @@ static inline bool can_truncate_to_fixed_for_decal(SkFractionalInt frX, return false; } + // Note: it seems the test should be (fx <= max && lastFx <= max); but + // historically it's been a strict inequality check, and changing produces + // unexpected diffs. Further investigation is needed. + // We cast to unsigned so we don't have to check for negative values, which // will now appear as very large positive values, and thus fail our test! - SkFixed fx = SkFractionalIntToFixed(frX); - return (unsigned)SkFixedFloorToInt(fx) <= max && - (unsigned)SkFixedFloorToInt(fx + dx * (count - 1)) < max; + if ((unsigned)SkFixedFloorToInt(fx) >= max) { + return false; + } + + // Promote to 64bit (48.16) to avoid overflow. + const uint64_t lastFx = fx + sk_64_mul(dx, count - 1); + + return sk_64_isS32(lastFx) && (unsigned)SkFixedFloorToInt(sk_64_asS32(lastFx)) < max; } #endif /* #ifndef SkBitmapProcState_utils_DEFINED */ diff --git a/gfx/skia/skia/src/core/SkBitmapProvider.cpp b/gfx/skia/skia/src/core/SkBitmapProvider.cpp index 37f8dc9d52e9..928214c49878 100644 --- a/gfx/skia/skia/src/core/SkBitmapProvider.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProvider.cpp @@ -7,77 +7,43 @@ #include "SkBitmapProvider.h" #include "SkImage_Base.h" +#include "SkImageCacherator.h" #include "SkPixelRef.h" int SkBitmapProvider::width() const { - return fImage ? fImage->width() : fBitmap.width(); + return fImage->width(); } int SkBitmapProvider::height() const { - return fImage ? fImage->height() : fBitmap.height(); + return fImage->height(); } uint32_t SkBitmapProvider::getID() const { - return fImage ? fImage->uniqueID() : fBitmap.getGenerationID(); -} - -bool SkBitmapProvider::validForDrawing() const { - if (!fImage) { - if (0 == fBitmap.width() || 0 == fBitmap.height()) { - return false; - } - if (nullptr == fBitmap.pixelRef()) { - return false; // no pixels to read - } - if (kIndex_8_SkColorType == fBitmap.colorType()) { - SkAutoLockPixels alp(fBitmap); // but we need to call it before getColorTable() is safe. - if (!fBitmap.getColorTable()) { - return false; - } - } - } - return true; + return fImage->uniqueID(); } SkImageInfo SkBitmapProvider::info() const { - if (fImage) { - return as_IB(fImage)->onImageInfo(); - } else { - return fBitmap.info(); - } + return as_IB(fImage)->onImageInfo(); } bool SkBitmapProvider::isVolatile() const { - if (fImage) { - // add flag to images? - const SkBitmap* bm = as_IB(fImage)->onPeekBitmap(); - return bm ? bm->isVolatile() : false; - } else { - return fBitmap.isVolatile(); - } + // add flag to images? + const SkBitmap* bm = as_IB(fImage)->onPeekBitmap(); + return bm ? bm->isVolatile() : false; } SkBitmapCacheDesc SkBitmapProvider::makeCacheDesc(int w, int h) const { - return fImage ? SkBitmapCacheDesc::Make(fImage, w, h) : SkBitmapCacheDesc::Make(fBitmap, w, h); + return SkBitmapCacheDesc::Make(fImage, w, h); } SkBitmapCacheDesc SkBitmapProvider::makeCacheDesc() const { - return fImage ? SkBitmapCacheDesc::Make(fImage) : SkBitmapCacheDesc::Make(fBitmap); + return SkBitmapCacheDesc::Make(fImage); } void SkBitmapProvider::notifyAddedToCache() const { - if (fImage) { - as_IB(fImage)->notifyAddedToCache(); - } else { - fBitmap.pixelRef()->notifyAddedToCache(); - } + as_IB(fImage)->notifyAddedToCache(); } bool SkBitmapProvider::asBitmap(SkBitmap* bm) const { - if (fImage) { - return as_IB(fImage)->getROPixels(bm, SkImage::kAllow_CachingHint); - } else { - *bm = fBitmap; - return true; - } + return as_IB(fImage)->getROPixels(bm, fDstColorSpace, SkImage::kAllow_CachingHint); } diff --git a/gfx/skia/skia/src/core/SkBitmapProvider.h b/gfx/skia/skia/src/core/SkBitmapProvider.h index 9901c0fc1a05..f4904d4aa461 100644 --- a/gfx/skia/skia/src/core/SkBitmapProvider.h +++ b/gfx/skia/skia/src/core/SkBitmapProvider.h @@ -8,24 +8,26 @@ #ifndef SkBitmapProvider_DEFINED #define SkBitmapProvider_DEFINED -#include "SkBitmap.h" #include "SkImage.h" #include "SkBitmapCache.h" class SkBitmapProvider { public: - explicit SkBitmapProvider(const SkBitmap& bm) : fBitmap(bm) {} - explicit SkBitmapProvider(const SkImage* img) : fImage(SkSafeRef(img)) {} + explicit SkBitmapProvider(const SkImage* img, SkColorSpace* dstColorSpace) + : fImage(img) + , fDstColorSpace(dstColorSpace) { + SkASSERT(img); + } SkBitmapProvider(const SkBitmapProvider& other) - : fBitmap(other.fBitmap) - , fImage(SkSafeRef(other.fImage.get())) + : fImage(other.fImage) + , fDstColorSpace(other.fDstColorSpace) {} int width() const; int height() const; uint32_t getID() const; + SkColorSpace* dstColorSpace() const { return fDstColorSpace; } - bool validForDrawing() const; SkImageInfo info() const; bool isVolatile() const; @@ -38,8 +40,14 @@ public: bool asBitmap(SkBitmap*) const; private: - SkBitmap fBitmap; - SkAutoTUnref fImage; + // Stack-allocated only. + void* operator new(size_t) = delete; + void* operator new(size_t, void*) = delete; + + // SkBitmapProvider is always short-lived/stack allocated, and the source image and destination + // color space are guaranteed to outlive its scope => we can store raw ptrs to avoid ref churn. + const SkImage* fImage; + SkColorSpace* fDstColorSpace; }; #endif diff --git a/gfx/skia/skia/src/core/SkBitmapScaler.cpp b/gfx/skia/skia/src/core/SkBitmapScaler.cpp index 5edb1b23e16d..b4ade85a7536 100644 --- a/gfx/skia/skia/src/core/SkBitmapScaler.cpp +++ b/gfx/skia/skia/src/core/SkBitmapScaler.cpp @@ -22,8 +22,7 @@ public: SkResizeFilter(SkBitmapScaler::ResizeMethod method, int srcFullWidth, int srcFullHeight, float destWidth, float destHeight, - const SkRect& destSubset, - const SkConvolutionProcs& convolveProcs); + const SkRect& destSubset); ~SkResizeFilter() { delete fBitmapFilter; } // Returns the filled filter values. @@ -48,8 +47,7 @@ private: void computeFilters(int srcSize, float destSubsetLo, float destSubsetSize, float scale, - SkConvolutionFilter1D* output, - const SkConvolutionProcs& convolveProcs); + SkConvolutionFilter1D* output); SkConvolutionFilter1D fXFilter; SkConvolutionFilter1D fYFilter; @@ -58,8 +56,7 @@ private: SkResizeFilter::SkResizeFilter(SkBitmapScaler::ResizeMethod method, int srcFullWidth, int srcFullHeight, float destWidth, float destHeight, - const SkRect& destSubset, - const SkConvolutionProcs& convolveProcs) { + const SkRect& destSubset) { SkASSERT(method >= SkBitmapScaler::RESIZE_FirstMethod && method <= SkBitmapScaler::RESIZE_LastMethod); @@ -88,7 +85,7 @@ SkResizeFilter::SkResizeFilter(SkBitmapScaler::ResizeMethod method, float scaleY = destHeight / srcFullHeight; this->computeFilters(srcFullWidth, destSubset.fLeft, destSubset.width(), - scaleX, &fXFilter, convolveProcs); + scaleX, &fXFilter); if (srcFullWidth == srcFullHeight && destSubset.fLeft == destSubset.fTop && destSubset.width() == destSubset.height()&& @@ -96,7 +93,7 @@ SkResizeFilter::SkResizeFilter(SkBitmapScaler::ResizeMethod method, fYFilter = fXFilter; } else { this->computeFilters(srcFullHeight, destSubset.fTop, destSubset.height(), - scaleY, &fYFilter, convolveProcs); + scaleY, &fYFilter); } } @@ -112,98 +109,92 @@ SkResizeFilter::SkResizeFilter(SkBitmapScaler::ResizeMethod method, // the coefficients can be shared. For periods of 1 we can consider // loading the factors only once outside the borders. void SkResizeFilter::computeFilters(int srcSize, - float destSubsetLo, float destSubsetSize, - float scale, - SkConvolutionFilter1D* output, - const SkConvolutionProcs& convolveProcs) { - float destSubsetHi = destSubsetLo + destSubsetSize; // [lo, hi) + float destSubsetLo, float destSubsetSize, + float scale, + SkConvolutionFilter1D* output) { + float destSubsetHi = destSubsetLo + destSubsetSize; // [lo, hi) - // When we're doing a magnification, the scale will be larger than one. This - // means the destination pixels are much smaller than the source pixels, and - // that the range covered by the filter won't necessarily cover any source - // pixel boundaries. Therefore, we use these clamped values (max of 1) for - // some computations. - float clampedScale = SkTMin(1.0f, scale); + // When we're doing a magnification, the scale will be larger than one. This + // means the destination pixels are much smaller than the source pixels, and + // that the range covered by the filter won't necessarily cover any source + // pixel boundaries. Therefore, we use these clamped values (max of 1) for + // some computations. + float clampedScale = SkTMin(1.0f, scale); - // This is how many source pixels from the center we need to count - // to support the filtering function. - float srcSupport = fBitmapFilter->width() / clampedScale; + // This is how many source pixels from the center we need to count + // to support the filtering function. + float srcSupport = fBitmapFilter->width() / clampedScale; - float invScale = 1.0f / scale; + float invScale = 1.0f / scale; - SkSTArray<64, float, true> filterValuesArray; - SkSTArray<64, SkConvolutionFilter1D::ConvolutionFixed, true> fixedFilterValuesArray; + SkSTArray<64, float, true> filterValuesArray; + SkSTArray<64, SkConvolutionFilter1D::ConvolutionFixed, true> fixedFilterValuesArray; - // Loop over all pixels in the output range. We will generate one set of - // filter values for each one. Those values will tell us how to blend the - // source pixels to compute the destination pixel. + // Loop over all pixels in the output range. We will generate one set of + // filter values for each one. Those values will tell us how to blend the + // source pixels to compute the destination pixel. - // This is the pixel in the source directly under the pixel in the dest. - // Note that we base computations on the "center" of the pixels. To see - // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x - // downscale should "cover" the pixels around the pixel with *its center* - // at coordinates (2.5, 2.5) in the source, not those around (0, 0). - // Hence we need to scale coordinates (0.5, 0.5), not (0, 0). - destSubsetLo = SkScalarFloorToScalar(destSubsetLo); - destSubsetHi = SkScalarCeilToScalar(destSubsetHi); - float srcPixel = (destSubsetLo + 0.5f) * invScale; - int destLimit = SkScalarTruncToInt(destSubsetHi - destSubsetLo); - output->reserveAdditional(destLimit, SkScalarCeilToInt(destLimit * srcSupport * 2)); - for (int destI = 0; destI < destLimit; srcPixel += invScale, destI++) - { - // Compute the (inclusive) range of source pixels the filter covers. - float srcBegin = SkTMax(0.f, SkScalarFloorToScalar(srcPixel - srcSupport)); - float srcEnd = SkTMin(srcSize - 1.f, SkScalarCeilToScalar(srcPixel + srcSupport)); + // This is the pixel in the source directly under the pixel in the dest. + // Note that we base computations on the "center" of the pixels. To see + // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x + // downscale should "cover" the pixels around the pixel with *its center* + // at coordinates (2.5, 2.5) in the source, not those around (0, 0). + // Hence we need to scale coordinates (0.5, 0.5), not (0, 0). + destSubsetLo = SkScalarFloorToScalar(destSubsetLo); + destSubsetHi = SkScalarCeilToScalar(destSubsetHi); + float srcPixel = (destSubsetLo + 0.5f) * invScale; + int destLimit = SkScalarTruncToInt(destSubsetHi - destSubsetLo); + output->reserveAdditional(destLimit, SkScalarCeilToInt(destLimit * srcSupport * 2)); + for (int destI = 0; destI < destLimit; srcPixel += invScale, destI++) { + // Compute the (inclusive) range of source pixels the filter covers. + float srcBegin = SkTMax(0.f, SkScalarFloorToScalar(srcPixel - srcSupport)); + float srcEnd = SkTMin(srcSize - 1.f, SkScalarCeilToScalar(srcPixel + srcSupport)); - // Compute the unnormalized filter value at each location of the source - // it covers. + // Compute the unnormalized filter value at each location of the source + // it covers. - // Sum of the filter values for normalizing. - // Distance from the center of the filter, this is the filter coordinate - // in source space. We also need to consider the center of the pixel - // when comparing distance against 'srcPixel'. In the 5x downscale - // example used above the distance from the center of the filter to - // the pixel with coordinates (2, 2) should be 0, because its center - // is at (2.5, 2.5). - float destFilterDist = (srcBegin + 0.5f - srcPixel) * clampedScale; - int filterCount = SkScalarTruncToInt(srcEnd - srcBegin) + 1; - if (filterCount <= 0) { - // true when srcSize is equal to srcPixel - srcSupport; this may be a bug - return; - } - filterValuesArray.reset(filterCount); - float filterSum = fBitmapFilter->evaluate_n(destFilterDist, clampedScale, filterCount, + // Sum of the filter values for normalizing. + // Distance from the center of the filter, this is the filter coordinate + // in source space. We also need to consider the center of the pixel + // when comparing distance against 'srcPixel'. In the 5x downscale + // example used above the distance from the center of the filter to + // the pixel with coordinates (2, 2) should be 0, because its center + // is at (2.5, 2.5). + float destFilterDist = (srcBegin + 0.5f - srcPixel) * clampedScale; + int filterCount = SkScalarTruncToInt(srcEnd - srcBegin) + 1; + if (filterCount <= 0) { + // true when srcSize is equal to srcPixel - srcSupport; this may be a bug + return; + } + filterValuesArray.reset(filterCount); + float filterSum = fBitmapFilter->evaluate_n(destFilterDist, clampedScale, filterCount, filterValuesArray.begin()); - // The filter must be normalized so that we don't affect the brightness of - // the image. Convert to normalized fixed point. - int fixedSum = 0; - fixedFilterValuesArray.reset(filterCount); - const float* filterValues = filterValuesArray.begin(); - SkConvolutionFilter1D::ConvolutionFixed* fixedFilterValues = fixedFilterValuesArray.begin(); - float invFilterSum = 1 / filterSum; - for (int fixedI = 0; fixedI < filterCount; fixedI++) { - int curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] * invFilterSum); - fixedSum += curFixed; - fixedFilterValues[fixedI] = SkToS16(curFixed); + // The filter must be normalized so that we don't affect the brightness of + // the image. Convert to normalized fixed point. + int fixedSum = 0; + fixedFilterValuesArray.reset(filterCount); + const float* filterValues = filterValuesArray.begin(); + SkConvolutionFilter1D::ConvolutionFixed* fixedFilterValues = fixedFilterValuesArray.begin(); + float invFilterSum = 1 / filterSum; + for (int fixedI = 0; fixedI < filterCount; fixedI++) { + int curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] * invFilterSum); + fixedSum += curFixed; + fixedFilterValues[fixedI] = SkToS16(curFixed); + } + SkASSERT(fixedSum <= 0x7FFF); + + // The conversion to fixed point will leave some rounding errors, which + // we add back in to avoid affecting the brightness of the image. We + // arbitrarily add this to the center of the filter array (this won't always + // be the center of the filter function since it could get clipped on the + // edges, but it doesn't matter enough to worry about that case). + int leftovers = SkConvolutionFilter1D::FloatToFixed(1) - fixedSum; + fixedFilterValues[filterCount / 2] += leftovers; + + // Now it's ready to go. + output->AddFilter(SkScalarFloorToInt(srcBegin), fixedFilterValues, filterCount); } - SkASSERT(fixedSum <= 0x7FFF); - - // The conversion to fixed point will leave some rounding errors, which - // we add back in to avoid affecting the brightness of the image. We - // arbitrarily add this to the center of the filter array (this won't always - // be the center of the filter function since it could get clipped on the - // edges, but it doesn't matter enough to worry about that case). - int leftovers = SkConvolutionFilter1D::FloatToFixed(1) - fixedSum; - fixedFilterValues[filterCount / 2] += leftovers; - - // Now it's ready to go. - output->AddFilter(SkScalarFloorToInt(srcBegin), fixedFilterValues, filterCount); - } - - if (convolveProcs.fApplySIMDPadding) { - convolveProcs.fApplySIMDPadding(output); - } } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -222,13 +213,10 @@ bool SkBitmapScaler::Resize(const SkPixmap& result, const SkPixmap& source, Resi return false; } - SkConvolutionProcs convolveProcs= { 0, nullptr, nullptr, nullptr, nullptr }; - PlatformConvolutionProcs(&convolveProcs); - SkRect destSubset = SkRect::MakeIWH(result.width(), result.height()); SkResizeFilter filter(method, source.width(), source.height(), - result.width(), result.height(), destSubset, convolveProcs); + result.width(), result.height(), destSubset); // Get a subset encompassing this touched area. We construct the // offsets and row strides such that it looks like a new bitmap, while @@ -238,8 +226,7 @@ bool SkBitmapScaler::Resize(const SkPixmap& result, const SkPixmap& source, Resi return BGRAConvolve2D(sourceSubset, static_cast(source.rowBytes()), !source.isOpaque(), filter.xFilter(), filter.yFilter(), static_cast(result.rowBytes()), - static_cast(result.writable_addr()), - convolveProcs, true); + static_cast(result.writable_addr())); } bool SkBitmapScaler::Resize(SkBitmap* resultPtr, const SkPixmap& source, ResizeMethod method, diff --git a/gfx/skia/skia/src/core/SkBitmapScaler.h b/gfx/skia/skia/src/core/SkBitmapScaler.h index 3d734d6efc5a..c96be0dbf8cc 100644 --- a/gfx/skia/skia/src/core/SkBitmapScaler.h +++ b/gfx/skia/skia/src/core/SkBitmapScaler.h @@ -41,12 +41,6 @@ public: */ static bool Resize(SkBitmap* result, const SkPixmap& src, ResizeMethod method, int dest_width, int dest_height, SkBitmap::Allocator* = nullptr); - - /** Platforms can also optionally overwrite the convolution functions - if we have SIMD versions of them. - */ - - static void PlatformConvolutionProcs(SkConvolutionProcs*); }; #endif diff --git a/gfx/skia/skia/src/core/SkBlendModePriv.h b/gfx/skia/skia/src/core/SkBlendModePriv.h index b5d9e751e62d..0d0589c29ce6 100644 --- a/gfx/skia/skia/src/core/SkBlendModePriv.h +++ b/gfx/skia/skia/src/core/SkBlendModePriv.h @@ -9,11 +9,16 @@ #define SkBlendModePriv_DEFINED #include "SkBlendMode.h" +#include "SkRasterPipeline.h" bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode); +bool SkBlendMode_CanOverflow(SkBlendMode); +bool SkBlendMode_AppendStages(SkBlendMode, SkRasterPipeline* = nullptr); #if SK_SUPPORT_GPU -sk_sp SkBlendMode_AsXPFactory(SkBlendMode); +#include "GrXferProcessor.h" +const GrXPFactory* SkBlendMode_AsXPFactory(SkBlendMode); #endif + #endif diff --git a/gfx/skia/skia/include/core/SkBlitRow.h b/gfx/skia/skia/src/core/SkBlitRow.h similarity index 100% rename from gfx/skia/skia/include/core/SkBlitRow.h rename to gfx/skia/skia/src/core/SkBlitRow.h diff --git a/gfx/skia/skia/src/core/SkBlitter.cpp b/gfx/skia/skia/src/core/SkBlitter.cpp index ce689d7e8421..0e8bd2db2249 100644 --- a/gfx/skia/skia/src/core/SkBlitter.cpp +++ b/gfx/skia/skia/src/core/SkBlitter.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkBlitter.h" #include "SkAntiRun.h" #include "SkColor.h" @@ -16,7 +17,6 @@ #include "SkString.h" #include "SkTLazy.h" #include "SkUtils.h" -#include "SkXfermode.h" #include "SkXfermodeInterpretation.h" // define this for testing srgb blits @@ -26,14 +26,6 @@ SkBlitter::~SkBlitter() {} bool SkBlitter::isNullBlitter() const { return false; } -bool SkBlitter::resetShaderContext(const SkShader::ContextRec&) { - return true; -} - -SkShader::Context* SkBlitter::getShaderContext() const { - return nullptr; -} - const SkPixmap* SkBlitter::justAnOpaqueColor(uint32_t* value) { return nullptr; } @@ -71,17 +63,22 @@ void SkBlitter::blitRect(int x, int y, int width, int height) { } } -/// Default implementation doesn't check for any easy optimizations -/// such as alpha == 0 or 255; also uses blitV(), which some subclasses +/// Default implementation doesn't check for easy optimizations +/// such as alpha == 255; also uses blitV(), which some subclasses /// may not support. void SkBlitter::blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) { - this->blitV(x++, y, height, leftAlpha); + if (leftAlpha > 0) { // we may send in x = -1 with leftAlpha = 0 + this->blitV(x, y, height, leftAlpha); + } + x++; if (width > 0) { this->blitRect(x, y, width, height); x += width; } - this->blitV(x, y, height, rightAlpha); + if (rightAlpha > 0) { + this->blitV(x, y, height, rightAlpha); + } } ////////////////////////////////////////////////////////////////////////////// @@ -589,24 +586,15 @@ class Sk3DShader : public SkShader { public: Sk3DShader(sk_sp proxy) : fProxy(std::move(proxy)) {} - size_t onContextSize(const ContextRec& rec) const override { - size_t size = sizeof(Sk3DShaderContext); - if (fProxy) { - size += fProxy->contextSize(rec); - } - return size; - } - - Context* onCreateContext(const ContextRec& rec, void* storage) const override { + Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const override { SkShader::Context* proxyContext = nullptr; if (fProxy) { - char* proxyContextStorage = (char*) storage + sizeof(Sk3DShaderContext); - proxyContext = fProxy->createContext(rec, proxyContextStorage); + proxyContext = fProxy->makeContext(rec, alloc); if (!proxyContext) { return nullptr; } } - return new (storage) Sk3DShaderContext(*this, rec, proxyContext); + return alloc->make(*this, rec, proxyContext); } class Sk3DShaderContext : public SkShader::Context { @@ -623,7 +611,7 @@ public: } } - virtual ~Sk3DShaderContext() { + ~Sk3DShaderContext() override { if (fProxyContext) { fProxyContext->~Context(); } @@ -797,15 +785,15 @@ SkShader::ContextRec::DstType SkBlitter::PreferredShaderDest(const SkImageInfo& SkBlitter* SkBlitter::Choose(const SkPixmap& device, const SkMatrix& matrix, const SkPaint& origPaint, - SkTBlitterAllocator* allocator, + SkArenaAlloc* alloc, bool drawCoverage) { - SkASSERT(allocator != nullptr); + SkASSERT(alloc != nullptr); // which check, in case we're being called by a client with a dummy device // (e.g. they have a bounder that always aborts the draw) if (kUnknown_SkColorType == device.colorType() || (drawCoverage && (kAlpha_8_SkColorType != device.colorType()))) { - return allocator->createT(); + return alloc->make(); } SkShader* shader = origPaint.getShader(); @@ -831,7 +819,7 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, paint.writable()->setBlendMode(mode); break; case kSkipDrawing_SkXfermodeInterpretation:{ - return allocator->createT(); + return alloc->make(); } default: break; @@ -853,7 +841,13 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, p->setColor(0); } - if (SkBlitter* blitter = SkCreateRasterPipelineBlitter(device, *paint, allocator)) { + if (kAlpha_8_SkColorType == device.colorType() && drawCoverage) { + SkASSERT(nullptr == shader); + SkASSERT(paint->isSrcOver()); + return alloc->make(device, *paint); + } + + if (SkBlitter* blitter = SkCreateRasterPipelineBlitter(device, *paint, matrix, alloc)) { return blitter; } @@ -887,39 +881,29 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, SkShader::Context* shaderContext = nullptr; if (shader) { const SkShader::ContextRec rec(*paint, matrix, nullptr, - PreferredShaderDest(device.info())); - size_t contextSize = shader->contextSize(rec); - if (contextSize) { - // Try to create the ShaderContext - void* storage = allocator->reserveT(contextSize); - shaderContext = shader->createContext(rec, storage); - if (!shaderContext) { - allocator->freeLast(); - return allocator->createT(); - } - SkASSERT(shaderContext); - SkASSERT((void*) shaderContext == storage); - } else { - return allocator->createT(); + PreferredShaderDest(device.info()), + device.colorSpace()); + // Try to create the ShaderContext + shaderContext = shader->makeContext(rec, alloc); + if (!shaderContext) { + return alloc->make(); } + SkASSERT(shaderContext); } SkBlitter* blitter = nullptr; switch (device.colorType()) { case kAlpha_8_SkColorType: - if (drawCoverage) { - SkASSERT(nullptr == shader); - SkASSERT(paint->isSrcOver()); - blitter = allocator->createT(device, *paint); - } else if (shader) { - blitter = allocator->createT(device, *paint, shaderContext); + SkASSERT(!drawCoverage); // Handled above. + if (shader) { + blitter = alloc->make(device, *paint, shaderContext); } else { - blitter = allocator->createT(device, *paint); + blitter = alloc->make(device, *paint); } break; case kRGB_565_SkColorType: - blitter = SkBlitter_ChooseD565(device, *paint, shaderContext, allocator); + blitter = SkBlitter_ChooseD565(device, *paint, shaderContext, alloc); break; case kN32_SkColorType: @@ -929,23 +913,23 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, if (device.info().gammaCloseToSRGB()) #endif { - blitter = SkBlitter_ARGB32_Create(device, *paint, shaderContext, allocator); + blitter = SkBlitter_ARGB32_Create(device, *paint, shaderContext, alloc); } else { if (shader) { - blitter = allocator->createT( + blitter = alloc->make( device, *paint, shaderContext); } else if (paint->getColor() == SK_ColorBLACK) { - blitter = allocator->createT(device, *paint); + blitter = alloc->make(device, *paint); } else if (paint->getAlpha() == 0xFF) { - blitter = allocator->createT(device, *paint); + blitter = alloc->make(device, *paint); } else { - blitter = allocator->createT(device, *paint); + blitter = alloc->make(device, *paint); } } break; case kRGBA_F16_SkColorType: - blitter = SkBlitter_F16_Create(device, *paint, shaderContext, allocator); + blitter = SkBlitter_F16_Create(device, *paint, shaderContext, alloc); break; default: @@ -953,15 +937,16 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, } if (!blitter) { - blitter = allocator->createT(); + blitter = alloc->make(); } if (shader3D) { SkBlitter* innerBlitter = blitter; + // FIXME - comment about allocator // innerBlitter was allocated by allocator, which will delete it. // We know shaderContext or its proxies is of type Sk3DShaderContext, so we need to // wrapper the blitter to notify it when we see an emboss mask. - blitter = allocator->createT(innerBlitter, shaderContext); + blitter = alloc->make(innerBlitter, shaderContext); } return blitter; } @@ -973,7 +958,7 @@ public: SkZeroShaderContext(const SkShader& shader, const SkShader::ContextRec& rec) // Override rec with the identity matrix, so it is guaranteed to be invertible. : INHERITED(shader, SkShader::ContextRec(*rec.fPaint, SkMatrix::I(), nullptr, - rec.fPreferredDstType)) {} + rec.fPreferredDstType, rec.fDstColorSpace)) {} void shadeSpan(int x, int y, SkPMColor colors[], int count) override { sk_bzero(colors, count * sizeof(SkPMColor)); @@ -1000,19 +985,61 @@ SkShaderBlitter::~SkShaderBlitter() { fShader->unref(); } -bool SkShaderBlitter::resetShaderContext(const SkShader::ContextRec& rec) { - // Only destroy the old context if we have a new one. We need to ensure to have a - // live context in fShaderContext because the storage is owned by an SkSmallAllocator - // outside of this class. - // The new context will be of the same size as the old one because we use the same - // shader to create it. It is therefore safe to re-use the storage. - fShaderContext->~Context(); - SkShader::Context* ctx = fShader->createContext(rec, (void*)fShaderContext); - if (nullptr == ctx) { - // Need a valid context in fShaderContext's storage, so we can later (or our caller) call - // the in-place destructor. - new (fShaderContext) SkZeroShaderContext(*fShader, rec); - return false; - } - return true; +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG + +void SkRectClipCheckBlitter::blitH(int x, int y, int width) { + SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, 1))); + fBlitter->blitH(x, y, width); } + +void SkRectClipCheckBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) { + const int16_t* iter = runs; + for (; *iter; iter += *iter) + ; + int width = iter - runs; + SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, 1))); + fBlitter->blitAntiH(x, y, aa, runs); +} + +void SkRectClipCheckBlitter::blitV(int x, int y, int height, SkAlpha alpha) { + SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 1, height))); + fBlitter->blitV(x, y, height, alpha); +} + +void SkRectClipCheckBlitter::blitRect(int x, int y, int width, int height) { + SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, height))); + fBlitter->blitRect(x, y, width, height); +} + +void SkRectClipCheckBlitter::blitAntiRect(int x, int y, int width, int height, + SkAlpha leftAlpha, SkAlpha rightAlpha) { + bool skipLeft = !leftAlpha; + bool skipRight = !rightAlpha; + SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x + skipLeft, y, + width + 2 - skipRight - skipLeft, height))); + fBlitter->blitAntiRect(x, y, width, height, leftAlpha, rightAlpha); +} + +void SkRectClipCheckBlitter::blitMask(const SkMask& mask, const SkIRect& clip) { + SkASSERT(mask.fBounds.contains(clip)); + SkASSERT(fClipRect.contains(clip)); + fBlitter->blitMask(mask, clip); +} + +const SkPixmap* SkRectClipCheckBlitter::justAnOpaqueColor(uint32_t* value) { + return fBlitter->justAnOpaqueColor(value); +} + +void SkRectClipCheckBlitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) { + SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 2, 1))); + fBlitter->blitAntiH2(x, y, a0, a1); +} + +void SkRectClipCheckBlitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) { + SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 1, 2))); + fBlitter->blitAntiV2(x, y, a0, a1); +} + +#endif diff --git a/gfx/skia/skia/src/core/SkBlitter.h b/gfx/skia/skia/src/core/SkBlitter.h index 0e5fedd7ebb6..1fc49594c91e 100644 --- a/gfx/skia/skia/src/core/SkBlitter.h +++ b/gfx/skia/skia/src/core/SkBlitter.h @@ -8,13 +8,14 @@ #ifndef SkBlitter_DEFINED #define SkBlitter_DEFINED +#include "SkAutoMalloc.h" #include "SkBitmapProcShader.h" #include "SkColor.h" #include "SkRect.h" #include "SkRegion.h" #include "SkShader.h" -#include "SkTypes.h" +class SkArenaAlloc; class SkMatrix; class SkPaint; class SkPixmap; @@ -107,12 +108,6 @@ public: */ virtual bool isNullBlitter() const; - /** - * Special methods for SkShaderBlitter. On all other classes this is a no-op. - */ - virtual bool resetShaderContext(const SkShader::ContextRec&); - virtual SkShader::Context* getShaderContext() const; - /** * Special methods for blitters that can blit more than one row at a time. * This function returns the number of rows that this blitter could optimally @@ -143,14 +138,14 @@ public: static SkBlitter* Choose(const SkPixmap& dst, const SkMatrix& matrix, const SkPaint& paint, - SkTBlitterAllocator*, + SkArenaAlloc*, bool drawCoverage = false); static SkBlitter* ChooseSprite(const SkPixmap& dst, const SkPaint&, const SkPixmap& src, int left, int top, - SkTBlitterAllocator*); + SkArenaAlloc*); ///@} static SkShader::ContextRec::DstType PreferredShaderDest(const SkImageInfo&); @@ -240,6 +235,41 @@ private: const SkRegion* fRgn; }; +#ifdef SK_DEBUG +class SkRectClipCheckBlitter : public SkBlitter { +public: + void init(SkBlitter* blitter, const SkIRect& clipRect) { + SkASSERT(blitter); + SkASSERT(!clipRect.isEmpty()); + fBlitter = blitter; + fClipRect = clipRect; + } + + void blitH(int x, int y, int width) override; + void blitAntiH(int x, int y, const SkAlpha[], const int16_t runs[]) override; + void blitV(int x, int y, int height, SkAlpha alpha) override; + void blitRect(int x, int y, int width, int height) override; + void blitAntiRect(int x, int y, int width, int height, + SkAlpha leftAlpha, SkAlpha rightAlpha) override; + void blitMask(const SkMask&, const SkIRect& clip) override; + const SkPixmap* justAnOpaqueColor(uint32_t* value) override; + void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) override; + void blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) override; + + int requestRowsPreserved() const override { + return fBlitter->requestRowsPreserved(); + } + + void* allocBlitMemory(size_t sz) override { + return fBlitter->allocBlitMemory(sz); + } + +private: + SkBlitter* fBlitter; + SkIRect fClipRect; +}; +#endif + /** Factory to set up the appropriate most-efficient wrapper blitter to apply a clip. Returns a pointer to a member, so lifetime must be managed carefully. diff --git a/gfx/skia/skia/src/core/SkBlitter_A8.cpp b/gfx/skia/skia/src/core/SkBlitter_A8.cpp index cb7d718f5400..1fd4d5f0d972 100644 --- a/gfx/skia/skia/src/core/SkBlitter_A8.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_A8.cpp @@ -9,7 +9,7 @@ #include "SkCoreBlitters.h" #include "SkColorPriv.h" #include "SkShader.h" -#include "SkXfermode.h" +#include "SkXfermodePriv.h" SkA8_Blitter::SkA8_Blitter(const SkPixmap& device, const SkPaint& paint) : INHERITED(device) { fSrcA = paint.getAlpha(); diff --git a/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp b/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp index ea0554d66eaa..4478b2bd6487 100644 --- a/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp @@ -9,7 +9,7 @@ #include "SkColorPriv.h" #include "SkShader.h" #include "SkUtils.h" -#include "SkXfermode.h" +#include "SkXfermodePriv.h" #include "SkBlitMask.h" /////////////////////////////////////////////////////////////////////////////// @@ -237,11 +237,7 @@ void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { color = SkAlphaMulQ(color, SkAlpha255To256(alpha)); } -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - unsigned dst_scale = 255 - SkGetPackedA32(color); -#else unsigned dst_scale = SkAlpha255To256(255 - SkGetPackedA32(color)); -#endif size_t rowBytes = fDevice.rowBytes(); while (--height >= 0) { device[0] = color + SkAlphaMulQ(device[0], dst_scale); diff --git a/gfx/skia/skia/src/core/SkBlitter_PM4f.cpp b/gfx/skia/skia/src/core/SkBlitter_PM4f.cpp index d63e924e2c31..61105ce2dbfd 100644 --- a/gfx/skia/skia/src/core/SkBlitter_PM4f.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_PM4f.cpp @@ -6,10 +6,12 @@ */ #include "SkCoreBlitters.h" + +#include "SkArenaAlloc.h" #include "SkColorPriv.h" #include "SkShader.h" #include "SkUtils.h" -#include "SkXfermode.h" +#include "SkXfermodePriv.h" #include "SkBlitMask.h" #include "SkTemplates.h" #include "SkPM4f.h" @@ -27,7 +29,7 @@ public: void blitH(int x, int y, int width) override { SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); - fState.fProc1(fState.fXfer, State::WritableAddr(fDevice, x, y), + fState.fProc1(fState.fMode, State::WritableAddr(fDevice, x, y), &fState.fPM4f, width, nullptr); } @@ -38,7 +40,7 @@ public: size_t deviceRB = fDevice.rowBytes(); for (int i = 0; i < height; ++i) { - fState.fProc1(fState.fXfer, device, &fState.fPM4f, 1, &alpha); + fState.fProc1(fState.fMode, device, &fState.fPM4f, 1, &alpha); device = (typename State::DstType*)((char*)device + deviceRB); } } @@ -51,7 +53,7 @@ public: size_t deviceRB = fDevice.rowBytes(); do { - fState.fProc1(fState.fXfer, device, &fState.fPM4f, width, nullptr); + fState.fProc1(fState.fMode, device, &fState.fPM4f, width, nullptr); y += 1; device = (typename State::DstType*)((char*)device + deviceRB); } while (--height > 0); @@ -68,10 +70,10 @@ public: int aa = *antialias; if (aa) { if (aa == 255) { - fState.fProc1(fState.fXfer, device, &fState.fPM4f, count, nullptr); + fState.fProc1(fState.fMode, device, &fState.fPM4f, count, nullptr); } else { for (int i = 0; i < count; ++i) { - fState.fProc1(fState.fXfer, &device[i], &fState.fPM4f, 1, antialias); + fState.fProc1(fState.fMode, &device[i], &fState.fPM4f, 1, antialias); } } } @@ -125,7 +127,7 @@ public: const size_t maskRB = mask.fRowBytes; for (int i = 0; i < height; ++i) { - fState.fProc1(fState.fXfer, device, &fState.fPM4f, width, maskRow); + fState.fProc1(fState.fMode, device, &fState.fPM4f, width, maskRow); device = (typename State::DstType*)((char*)device + dstRB); maskRow += maskRB; } @@ -155,7 +157,7 @@ public: typename State::DstType* device = State::WritableAddr(fDevice, x, y); fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width); - fState.fProcN(fState.fXfer, device, fState.fBuffer, width, nullptr); + fState.fProcN(fState.fMode, device, fState.fBuffer, width, nullptr); } void blitV(int x, int y, int height, SkAlpha alpha) override { @@ -178,7 +180,7 @@ public: if (!fConstInY) { fShaderContext->shadeSpan4f(x, y, fState.fBuffer, 1); } - fState.fProcN(fState.fXfer, device, fState.fBuffer, 1, &alpha); + fState.fProcN(fState.fMode, device, fState.fBuffer, 1, &alpha); device = (typename State::DstType*)((char*)device + deviceRB); } } @@ -204,7 +206,7 @@ public: if (!fConstInY) { fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width); } - fState.fProcN(fState.fXfer, device, fState.fBuffer, width, nullptr); + fState.fProcN(fState.fMode, device, fState.fBuffer, width, nullptr); device = (typename State::DstType*)((char*)device + deviceRB); } } @@ -224,10 +226,10 @@ public: } else { fShaderContext->shadeSpan4f(x, y, fState.fBuffer, count); if (aa == 255) { - fState.fProcN(fState.fXfer, device, fState.fBuffer, count, nullptr); + fState.fProcN(fState.fMode, device, fState.fBuffer, count, nullptr); } else { for (int i = 0; i < count; ++i) { - fState.fProcN(fState.fXfer, &device[i], &fState.fBuffer[i], 1, antialias); + fState.fProcN(fState.fMode, &device[i], &fState.fBuffer[i], 1, antialias); } } } @@ -300,7 +302,7 @@ public: if (!fConstInY) { fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width); } - fState.fProcN(fState.fXfer, device, fState.fBuffer, width, maskRow); + fState.fProcN(fState.fMode, device, fState.fBuffer, width, maskRow); device = (typename State::DstType*)((char*)device + deviceRB); maskRow += maskRB; } @@ -325,7 +327,7 @@ static bool is_opaque(const SkPaint& paint, const SkShader::Context* shaderConte struct State4f { State4f(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) { - fXfer = SkXfermode::Peek(paint.getBlendMode()); + fMode = paint.getBlendMode(); if (shaderContext) { fBuffer.reset(info.width()); } else { @@ -334,10 +336,10 @@ struct State4f { fFlags = 0; } - SkXfermode* fXfer; SkPM4f fPM4f; SkAutoTMalloc fBuffer; uint32_t fFlags; + SkBlendMode fMode; SkShader::Context::BlitState fBState; }; @@ -357,8 +359,8 @@ struct State32 : State4f { if (info.gammaCloseToSRGB()) { fFlags |= SkXfermode::kDstIsSRGB_D32Flag; } - fProc1 = SkXfermode::GetD32Proc(fXfer, fFlags | SkXfermode::kSrcIsSingle_D32Flag); - fProcN = SkXfermode::GetD32Proc(fXfer, fFlags); + fProc1 = SkXfermode::GetD32Proc(fMode, fFlags | SkXfermode::kSrcIsSingle_D32Flag); + fProcN = SkXfermode::GetD32Proc(fMode, fFlags); } SkXfermode::LCD32Proc getLCDProc(uint32_t oneOrManyFlag) const { @@ -387,8 +389,8 @@ struct StateF16 : State4f { fFlags |= SkXfermode::kSrcIsOpaque_F16Flag; } SkASSERT(kRGBA_F16_SkColorType == info.colorType()); - fProc1 = SkXfermode::GetF16Proc(fXfer, fFlags | SkXfermode::kSrcIsSingle_F16Flag); - fProcN = SkXfermode::GetF16Proc(fXfer, fFlags); + fProc1 = SkXfermode::GetF16Proc(fMode, fFlags | SkXfermode::kSrcIsSingle_F16Flag); + fProcN = SkXfermode::GetF16Proc(fMode, fFlags); } SkXfermode::LCDF16Proc getLCDProc(uint32_t oneOrManyFlag) const { @@ -403,34 +405,34 @@ struct StateF16 : State4f { template SkBlitter* create(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext, - SkTBlitterAllocator* allocator) { - SkASSERT(allocator != nullptr); + SkArenaAlloc* alloc) { + SkASSERT(alloc != nullptr); if (shaderContext) { SkShader::Context::BlitState bstate; sk_bzero(&bstate, sizeof(bstate)); bstate.fCtx = shaderContext; - bstate.fXfer = SkXfermode::Peek(paint.getBlendMode()); + bstate.fMode = paint.getBlendMode(); (void)shaderContext->chooseBlitProcs(device.info(), &bstate); - return allocator->createT>(device, paint, bstate); + return alloc->make>(device, paint, bstate); } else { SkColor color = paint.getColor(); if (0 == SkColorGetA(color)) { return nullptr; } - return allocator->createT>(device, paint); + return alloc->make>(device, paint); } } SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext, - SkTBlitterAllocator* allocator) { - return create(device, paint, shaderContext, allocator); + SkArenaAlloc* alloc) { + return create(device, paint, shaderContext, alloc); } SkBlitter* SkBlitter_F16_Create(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext, - SkTBlitterAllocator* allocator) { - return create(device, paint, shaderContext, allocator); + SkArenaAlloc* alloc) { + return create(device, paint, shaderContext, alloc); } diff --git a/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp b/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp index 7860b7cb6c03..6330a39357d0 100644 --- a/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkBlitRow.h" #include "SkCoreBlitters.h" #include "SkColorPriv.h" @@ -12,13 +13,7 @@ #include "SkShader.h" #include "SkUtils.h" #include "SkUtilsArm.h" -#include "SkXfermode.h" - -#if defined(__mips_dsp) -extern void blitmask_d565_opaque_mips(int width, int height, uint16_t* device, - unsigned deviceRB, const uint8_t* alpha, - uint32_t expanded32, unsigned maskRB); -#endif +#include "SkXfermodePriv.h" #if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN) #include @@ -116,7 +111,7 @@ class SkRGB16_Shader_Blitter : public SkShaderBlitter { public: SkRGB16_Shader_Blitter(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext); - virtual ~SkRGB16_Shader_Blitter(); + ~SkRGB16_Shader_Blitter() override; void blitH(int x, int y, int width) override; virtual void blitAntiH(int x, int y, const SkAlpha* antialias, const int16_t* runs) override; @@ -138,7 +133,7 @@ class SkRGB16_Shader_Xfermode_Blitter : public SkShaderBlitter { public: SkRGB16_Shader_Xfermode_Blitter(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext); - virtual ~SkRGB16_Shader_Xfermode_Blitter(); + ~SkRGB16_Shader_Xfermode_Blitter() override; void blitH(int x, int y, int width) override; virtual void blitAntiH(int x, int y, const SkAlpha* antialias, const int16_t* runs) override; @@ -360,11 +355,9 @@ void SkRGB16_Opaque_Blitter::blitAntiH(int x, int y, #define SK_BLITBWMASK_DEVTYPE uint16_t #include "SkBlitBWMaskTemplate.h" -#if !defined(__mips_dsp) static U16CPU blend_compact(uint32_t src32, uint32_t dst32, unsigned scale5) { return SkCompact_rgb_16(dst32 + ((src32 - dst32) * scale5 >> 5)); } -#endif void SkRGB16_Opaque_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) { @@ -451,8 +444,6 @@ void SkRGB16_Opaque_Blitter::blitMask(const SkMask& mask, alpha += maskRB; } while (--height != 0); #undef UNROLL -#elif defined(__mips_dsp) - blitmask_d565_opaque_mips(width, height, device, deviceRB, alpha, expanded32, maskRB); #else // non-neon code do { int w = width; @@ -890,8 +881,8 @@ void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y, SkBlitter* SkBlitter_ChooseD565(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext, - SkTBlitterAllocator* allocator) { - SkASSERT(allocator != nullptr); + SkArenaAlloc* alloc) { + SkASSERT(alloc != nullptr); SkBlitter* blitter; SkShader* shader = paint.getShader(); @@ -903,24 +894,24 @@ SkBlitter* SkBlitter_ChooseD565(const SkPixmap& device, const SkPaint& paint, if (shader) { SkASSERT(shaderContext != nullptr); if (!is_srcover) { - blitter = allocator->createT(device, paint, + blitter = alloc->make(device, paint, shaderContext); } else { - blitter = allocator->createT(device, paint, shaderContext); + blitter = alloc->make(device, paint, shaderContext); } } else { // no shader, no xfermode, (and we always ignore colorfilter) SkColor color = paint.getColor(); if (0 == SkColorGetA(color)) { - blitter = allocator->createT(); + blitter = alloc->make(); #ifdef USE_BLACK_BLITTER } else if (SK_ColorBLACK == color) { - blitter = allocator->createT(device, paint); + blitter = alloc->make(device, paint); #endif } else if (0xFF == SkColorGetA(color)) { - blitter = allocator->createT(device, paint); + blitter = alloc->make(device, paint); } else { - blitter = allocator->createT(device, paint); + blitter = alloc->make(device, paint); } } diff --git a/gfx/skia/skia/src/core/SkBlitter_Sprite.cpp b/gfx/skia/skia/src/core/SkBlitter_Sprite.cpp index cef4cfaa2f09..4c184bdb33a0 100644 --- a/gfx/skia/skia/src/core/SkBlitter_Sprite.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_Sprite.cpp @@ -5,8 +5,8 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkOpts.h" -#include "SkSmallAllocator.h" #include "SkSpriteBlitter.h" SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source) @@ -140,7 +140,7 @@ private: // returning null means the caller will call SkBlitter::Choose() and // have wrapped the source bitmap inside a shader SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint, - const SkPixmap& source, int left, int top, SkTBlitterAllocator* allocator) { + const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) { /* We currently ignore antialiasing and filtertype, meaning we will take our special blitters regardless of these settings. Ignoring filtertype seems fine since by definition there is no scale in the matrix. Ignoring antialiasing is @@ -161,7 +161,7 @@ SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint, SkSpriteBlitter* blitter = nullptr; if (SkSpriteBlitter_Src_SrcOver::Supports(dst, source, paint)) { - blitter = allocator->createT(source); + blitter = allocator->make(source); } else { switch (dst.colorType()) { case kRGB_565_SkColorType: diff --git a/gfx/skia/skia/src/core/SkBlurImageFilter.cpp b/gfx/skia/skia/src/core/SkBlurImageFilter.cpp index 78fa071acd74..5e7f2a53ce44 100644 --- a/gfx/skia/skia/src/core/SkBlurImageFilter.cpp +++ b/gfx/skia/skia/src/core/SkBlurImageFilter.cpp @@ -15,6 +15,7 @@ #if SK_SUPPORT_GPU #include "GrContext.h" +#include "GrTextureProxy.h" #include "SkGr.h" #endif @@ -30,18 +31,11 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurImageFilterImpl) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(SkScalar sigmaX, SkScalar sigmaY, SkImageFilter* input = nullptr, - const CropRect* cropRect = nullptr) { - return SkImageFilter::MakeBlur(sigmaX, sigmaY, sk_ref_sp(input), - cropRect).release(); - } -#endif - protected: void flatten(SkWriteBuffer&) const override; sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; SkIRect onFilterNodeBounds(const SkIRect& src, const SkMatrix&, MapDirection) const override; private: @@ -81,13 +75,9 @@ static SkVector map_sigma(const SkSize& localSigma, const SkMatrix& ctm) { return sigma; } -SkBlurImageFilterImpl::SkBlurImageFilterImpl(SkScalar sigmaX, - SkScalar sigmaY, - sk_sp input, - const CropRect* cropRect) - : INHERITED(&input, 1, cropRect) - , fSigma(SkSize::Make(sigmaX, sigmaY)) { -} +SkBlurImageFilterImpl::SkBlurImageFilterImpl( + SkScalar sigmaX, SkScalar sigmaY, sk_sp input, const CropRect* cropRect) + : INHERITED(&input, 1, cropRect), fSigma{sigmaX, sigmaY} {} sk_sp SkBlurImageFilterImpl::CreateProc(SkReadBuffer& buffer) { SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); @@ -118,8 +108,8 @@ static void get_box3_params(SkScalar s, int *kernelSize, int* kernelSize3, int * } sk_sp SkBlurImageFilterImpl::onFilterImage(SkSpecialImage* source, - const Context& ctx, - SkIPoint* offset) const { + const Context& ctx, + SkIPoint* offset) const { SkIPoint inputOffset = SkIPoint::Make(0, 0); sk_sp input(this->filterInput(0, source, ctx, &inputOffset)); @@ -143,8 +133,15 @@ sk_sp SkBlurImageFilterImpl::onFilterImage(SkSpecialImage* sourc #if SK_SUPPORT_GPU if (source->isTextureBacked()) { GrContext* context = source->getContext(); - sk_sp inputTexture(input->asTextureRef(context)); - SkASSERT(inputTexture); + + // Ensure the input is in the destination's gamut. This saves us from having to do the + // xform during the filter itself. + input = ImageToColorSpace(input.get(), ctx.outputProperties()); + + sk_sp inputTexture(input->asTextureProxyRef(context)); + if (!inputTexture) { + return nullptr; + } if (0 == sigma.x() && 0 == sigma.y()) { offset->fX = inputBounds.x(); @@ -157,26 +154,29 @@ sk_sp SkBlurImageFilterImpl::onFilterImage(SkSpecialImage* sourc offset->fY = dstBounds.fTop; inputBounds.offset(-inputOffset); dstBounds.offset(-inputOffset); - // We intentionally use the source's color space, not the destination's (from ctx). We - // always blur in the source's config, so we need a compatible color space. We also want to - // avoid doing gamut conversion on every fetch of the texture. - sk_sp drawContext(SkGpuBlurUtils::GaussianBlur( + // Typically, we would create the RTC with the output's color space (from ctx), but we + // always blur in the PixelConfig of the *input*. Those might not be compatible (if they + // have different transfer functions). We've already guaranteed that those color spaces + // have the same gamut, so in this case, we do everything in the input's color space. + sk_sp renderTargetContext(SkGpuBlurUtils::GaussianBlur( context, - inputTexture.get(), - sk_ref_sp(source->getColorSpace()), + std::move(inputTexture), + sk_ref_sp(input->getColorSpace()), dstBounds, &inputBounds, sigma.x(), sigma.y())); - if (!drawContext) { + if (!renderTargetContext) { return nullptr; } - // TODO: Get the colorSpace from the drawContext (once it has one) - return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(dstBounds.width(), dstBounds.height()), - kNeedNewImageUniqueID_SpecialImage, - drawContext->asTexture(), - sk_ref_sp(input->getColorSpace()), &source->props()); + return SkSpecialImage::MakeDeferredFromGpu(context, + SkIRect::MakeWH(dstBounds.width(), + dstBounds.height()), + kNeedNewImageUniqueID_SpecialImage, + renderTargetContext->asTextureProxyRef(), + renderTargetContext->refColorSpace(), + &source->props()); } #endif @@ -270,19 +270,28 @@ sk_sp SkBlurImageFilterImpl::onFilterImage(SkSpecialImage* sourc dst, &source->props()); } +sk_sp SkBlurImageFilterImpl::onMakeColorSpace(SkColorSpaceXformer* xformer) +const { + SkASSERT(1 == this->countInputs()); + if (!this->getInput(0)) { + return sk_ref_sp(const_cast(this)); + } + + sk_sp input = this->getInput(0)->makeColorSpace(xformer); + return SkImageFilter::MakeBlur(fSigma.width(), fSigma.height(), std::move(input), + this->getCropRectIfSet()); +} SkRect SkBlurImageFilterImpl::computeFastBounds(const SkRect& src) const { SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src; - bounds.outset(SkScalarMul(fSigma.width(), SkIntToScalar(3)), - SkScalarMul(fSigma.height(), SkIntToScalar(3))); + bounds.outset(fSigma.width() * 3, fSigma.height() * 3); return bounds; } SkIRect SkBlurImageFilterImpl::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection) const { SkVector sigma = map_sigma(fSigma, ctm); - return src.makeOutset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), - SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); + return src.makeOutset(SkScalarCeilToInt(sigma.x() * 3), SkScalarCeilToInt(sigma.y() * 3)); } #ifndef SK_IGNORE_TO_STRING diff --git a/gfx/skia/skia/src/core/SkBuffer.cpp b/gfx/skia/skia/src/core/SkBuffer.cpp index df8dc6959469..7fd4170c8f2a 100644 --- a/gfx/skia/skia/src/core/SkBuffer.cpp +++ b/gfx/skia/skia/src/core/SkBuffer.cpp @@ -9,56 +9,49 @@ #include -//////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// -void SkRBuffer::readNoSizeCheck(void* buffer, size_t size) -{ - SkASSERT((fData != 0 && fStop == 0) || fPos + size <= fStop); - if (buffer) - memcpy(buffer, fPos, size); - fPos += size; -} - -const void* SkRBuffer::skip(size_t size) -{ - const void* result = fPos; - readNoSizeCheck(nullptr, size); - return result; -} - -size_t SkRBuffer::skipToAlign4() -{ - size_t pos = this->pos(); - size_t n = SkAlign4(pos) - pos; - fPos += n; - return n; -} - -bool SkRBufferWithSizeCheck::read(void* buffer, size_t size) { - fError = fError || (size > static_cast(fStop - fPos)); - if (!fError && (size > 0)) { - readNoSizeCheck(buffer, size); +bool SkRBuffer::read(void* buffer, size_t size) { + if (fValid && size <= this->available()) { + if (buffer) { + memcpy(buffer, fPos, size); + } + fPos += size; + return true; + } else { + fValid = false; + return false; } - return !fError; } -void* SkWBuffer::skip(size_t size) -{ +bool SkRBuffer::skipToAlign4() { + intptr_t pos = reinterpret_cast(fPos); + size_t n = SkAlign4(pos) - pos; + if (fValid && n <= this->available()) { + fPos += n; + return true; + } else { + fValid = false; + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void* SkWBuffer::skip(size_t size) { void* result = fPos; writeNoSizeCheck(nullptr, size); return fData == nullptr ? nullptr : result; } -void SkWBuffer::writeNoSizeCheck(const void* buffer, size_t size) -{ +void SkWBuffer::writeNoSizeCheck(const void* buffer, size_t size) { SkASSERT(fData == 0 || fStop == 0 || fPos + size <= fStop); if (fData && buffer) memcpy(fPos, buffer, size); fPos += size; } -size_t SkWBuffer::padToAlign4() -{ +size_t SkWBuffer::padToAlign4() { size_t pos = this->pos(); size_t n = SkAlign4(pos) - pos; @@ -85,53 +78,4 @@ size_t SkWBuffer::padToAlign4() #define AssertBuffer32(buffer) #endif -void* sk_buffer_write_int32(void* buffer, int32_t value) -{ - AssertBuffer32(buffer); - *(int32_t*)buffer = value; - return (char*)buffer + sizeof(int32_t); -} - -void* sk_buffer_write_int32(void* buffer, const int32_t values[], int count) -{ - AssertBuffer32(buffer); - SkASSERT(count >= 0); - - memcpy((int32_t*)buffer, values, count * sizeof(int32_t)); - return (char*)buffer + count * sizeof(int32_t); -} - -const void* sk_buffer_read_int32(const void* buffer, int32_t* value) -{ - AssertBuffer32(buffer); - if (value) - *value = *(const int32_t*)buffer; - return (const char*)buffer + sizeof(int32_t); -} - -const void* sk_buffer_read_int32(const void* buffer, int32_t values[], int count) -{ - AssertBuffer32(buffer); - SkASSERT(count >= 0); - - if (values) - memcpy(values, (const int32_t*)buffer, count * sizeof(int32_t)); - return (const char*)buffer + count * sizeof(int32_t); -} - -void* sk_buffer_write_ptr(void* buffer, void* ptr) -{ - AssertBuffer32(buffer); - *(void**)buffer = ptr; - return (char*)buffer + sizeof(void*); -} - -const void* sk_buffer_read_ptr(const void* buffer, void** ptr) -{ - AssertBuffer32(buffer); - if (ptr) - *ptr = *(void**)buffer; - return (const char*)buffer + sizeof(void*); -} - #endif diff --git a/gfx/skia/skia/src/core/SkBuffer.h b/gfx/skia/skia/src/core/SkBuffer.h index c466fb65ea9d..c9c1a8e686da 100644 --- a/gfx/skia/skia/src/core/SkBuffer.h +++ b/gfx/skia/skia/src/core/SkBuffer.h @@ -22,14 +22,7 @@ class SkRBuffer : SkNoncopyable { public: SkRBuffer() : fData(0), fPos(0), fStop(0) {} - /** Initialize RBuffer with a data pointer, but no specified length. - This signals the RBuffer to not perform range checks during reading. - */ - SkRBuffer(const void* data) { - fData = (const char*)data; - fPos = (const char*)data; - fStop = 0; // no bounds checking - } + /** Initialize RBuffer with a data point and length. */ SkRBuffer(const void* data, size_t size) { @@ -39,79 +32,39 @@ public: fStop = (const char*)data + size; } - virtual ~SkRBuffer() { } - /** Return the number of bytes that have been read from the beginning of the data pointer. */ - size_t pos() const { return fPos - fData; } + size_t pos() const { return fPos - fData; } /** Return the total size of the data pointer. Only defined if the length was specified in the constructor or in a call to reset(). */ - size_t size() const { return fStop - fData; } + size_t size() const { return fStop - fData; } /** Return true if the buffer has read to the end of the data pointer. Only defined if the length was specified in the constructor or in a call to reset(). Always returns true if the length was not specified. */ - bool eof() const { return fPos >= fStop; } + bool eof() const { return fPos >= fStop; } + + size_t available() const { return fStop - fPos; } + + bool isValid() const { return fValid; } /** Read the specified number of bytes from the data pointer. If buffer is not null, copy those bytes into buffer. */ - virtual bool read(void* buffer, size_t size) { - if (size) { - this->readNoSizeCheck(buffer, size); - } - return true; - } + bool read(void* buffer, size_t size); + bool skipToAlign4(); - const void* skip(size_t size); // return start of skipped data - size_t skipToAlign4(); - - bool readPtr(void** ptr) { return read(ptr, sizeof(void*)); } - bool readScalar(SkScalar* x) { return read(x, 4); } - bool readU32(uint32_t* x) { return read(x, 4); } - bool readS32(int32_t* x) { return read(x, 4); } - bool readU16(uint16_t* x) { return read(x, 2); } - bool readS16(int16_t* x) { return read(x, 2); } - bool readU8(uint8_t* x) { return read(x, 1); } - bool readBool(bool* x) { - uint8_t u8; - if (this->readU8(&u8)) { - *x = (u8 != 0); - return true; - } - return false; - } - -protected: - void readNoSizeCheck(void* buffer, size_t size); + bool readU8(uint8_t* x) { return this->read(x, 1); } + bool readS32(int32_t* x) { return this->read(x, 4); } + bool readU32(uint32_t* x) { return this->read(x, 4); } +private: const char* fData; const char* fPos; const char* fStop; -}; - -/** \class SkRBufferWithSizeCheck - - Same as SkRBuffer, except that a size check is performed before the read operation and an - error is set if the read operation is attempting to read past the end of the data. -*/ -class SkRBufferWithSizeCheck : public SkRBuffer { -public: - SkRBufferWithSizeCheck(const void* data, size_t size) : SkRBuffer(data, size), fError(false) {} - - /** Read the specified number of bytes from the data pointer. If buffer is not - null and the number of bytes to read does not overflow this object's data, - copy those bytes into buffer. - */ - bool read(void* buffer, size_t size) override; - - /** Returns whether or not a read operation attempted to read past the end of the data. - */ - bool isValid() const { return !fError; } -private: - bool fError; + bool fValid = true; }; /** \class SkWBuffer diff --git a/gfx/skia/skia/src/core/SkCachedData.cpp b/gfx/skia/skia/src/core/SkCachedData.cpp index 1ea232b2c563..0f3ca649aa0c 100644 --- a/gfx/skia/skia/src/core/SkCachedData.cpp +++ b/gfx/skia/skia/src/core/SkCachedData.cpp @@ -7,6 +7,7 @@ #include "SkCachedData.h" #include "SkDiscardableMemory.h" +#include "SkMalloc.h" //#define TRACK_CACHEDDATA_LIFETIME diff --git a/gfx/skia/skia/src/core/SkCanvas.cpp b/gfx/skia/skia/src/core/SkCanvas.cpp index 505592d0f294..c36744bc9bfa 100644 --- a/gfx/skia/skia/src/core/SkCanvas.cpp +++ b/gfx/skia/skia/src/core/SkCanvas.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkBitmapDevice.h" #include "SkCanvas.h" #include "SkCanvasPriv.h" @@ -14,25 +15,25 @@ #include "SkDrawable.h" #include "SkDrawFilter.h" #include "SkDrawLooper.h" -#include "SkErrorInternals.h" #include "SkImage.h" #include "SkImage_Base.h" #include "SkImageFilter.h" #include "SkImageFilterCache.h" #include "SkLatticeIter.h" +#include "SkMakeUnique.h" #include "SkMatrixUtils.h" #include "SkMetaData.h" +#include "SkNoDrawCanvas.h" #include "SkNx.h" #include "SkPaintPriv.h" #include "SkPatchUtils.h" #include "SkPicture.h" #include "SkRadialShadowMapShader.h" #include "SkRasterClip.h" -#include "SkReadPixelsRec.h" +#include "SkRasterHandleAllocator.h" #include "SkRRect.h" #include "SkShadowPaintFilterCanvas.h" #include "SkShadowShader.h" -#include "SkSmallAllocator.h" #include "SkSpecialImage.h" #include "SkSurface_Base.h" #include "SkTextBlob.h" @@ -44,12 +45,68 @@ #if SK_SUPPORT_GPU #include "GrContext.h" #include "GrRenderTarget.h" -#include "SkGrPriv.h" +#include "SkGr.h" #endif +#include "SkClipOpPriv.h" +#include "SkVertices.h" #define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0) +class SkNoPixelsDevice : public SkBaseDevice { +public: + SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props) + : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props) + { + // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage + //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0); + } + + void resetForNextPicture(const SkIRect& bounds) { + //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0); + this->privateResize(bounds.width(), bounds.height()); + } + +protected: + // We don't track the clip at all (for performance), but we have to respond to some queries. + // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse. + void onSave() override {} + void onRestore() override {} + void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {} + void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {} + void onClipPath(const SkPath& path, SkClipOp, bool aa) override {} + void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {} + void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {} + bool onClipIsAA() const override { return false; } + void onAsRgnClip(SkRegion* rgn) const override { + rgn->setRect(SkIRect::MakeWH(this->width(), this->height())); + } + ClipType onGetClipType() const override { + return kRect_ClipType; + } + + void drawPaint(const SkPaint& paint) override {} + void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {} + void drawRect(const SkRect&, const SkPaint&) override {} + void drawOval(const SkRect&, const SkPaint&) override {} + void drawRRect(const SkRRect&, const SkPaint&) override {} + void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {} + void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {} + void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {} + void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&, + SkCanvas::SrcRectConstraint) override {} + void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {} + void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&, + const SkPaint&) override {} + void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {} + void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {} + +private: + typedef SkBaseDevice INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + /* * Return true if the drawing this rect would hit every pixels in the canvas. * @@ -72,8 +129,17 @@ bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* pa const SkISize size = this->getBaseLayerSize(); const SkRect bounds = SkRect::MakeIWH(size.width(), size.height()); - if (!this->getClipStack()->quickContains(bounds)) { - return false; + + // if we're clipped at all, we can't overwrite the entire surface + { + SkBaseDevice* base = this->getDevice(); + SkBaseDevice* top = this->getTopDevice(); + if (base != top) { + return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite + } + if (!base->clipIsWideOpen()) { + return false; + } } if (rect) { @@ -189,10 +255,8 @@ struct DeviceCM { SkMatrix fMatrixStorage; SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer - DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas, - bool conservativeRasterClip, const SkMatrix& stashed) + DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas, const SkMatrix& stashed) : fNext(nullptr) - , fClip(conservativeRasterClip) , fStashedMatrix(stashed) { SkSafeRef(device); @@ -211,43 +275,6 @@ struct DeviceCM { SkASSERT(fDevice); fClip.setRect(bounds); } - - void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip, - SkRasterClip* updateClip) { - int x = fDevice->getOrigin().x(); - int y = fDevice->getOrigin().y(); - int width = fDevice->width(); - int height = fDevice->height(); - - if ((x | y) == 0) { - fMatrix = &totalMatrix; - fClip = totalClip; - } else { - fMatrixStorage = totalMatrix; - fMatrixStorage.postTranslate(SkIntToScalar(-x), - SkIntToScalar(-y)); - fMatrix = &fMatrixStorage; - - totalClip.translate(-x, -y, &fClip); - } - - fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op); - - // intersect clip, but don't translate it (yet) - - if (updateClip) { - updateClip->op(SkIRect::MakeXYWH(x, y, width, height), - SkRegion::kDifference_Op); - } - -#ifdef SK_DEBUG - if (!fClip.isEmpty()) { - SkIRect deviceR; - deviceR.set(0, 0, width, height); - SkASSERT(deviceR.contains(fClip.getBounds())); - } -#endif - } }; /* This is the record we keep for each save/restore level in the stack. @@ -267,15 +294,15 @@ public: reference counted, since the real owner is either our fLayer field, or a previous one in a lower level.) */ - DeviceCM* fTopLayer; - SkRasterClip fRasterClip; - SkMatrix fMatrix; - int fDeferredSaveCount; + DeviceCM* fTopLayer; + SkConservativeClip fRasterClip; + SkMatrix fMatrix; + int fDeferredSaveCount; // This is the current cumulative depth (aggregate of all done translateZ calls) SkScalar fCurDrawDepth; - MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) { + MCRec() { fFilter = nullptr; fLayer = nullptr; fTopLayer = nullptr; @@ -312,79 +339,47 @@ public: } }; -static SkIRect compute_device_bounds(SkBaseDevice* device) { - return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(), - device->width(), device->height()); -} - -class SkDrawIter : public SkDraw { +class SkDrawIter { public: - SkDrawIter(SkCanvas* canvas) { - canvas = canvas->canvasForDrawIter(); - canvas->updateDeviceCMCache(); - - fClipStack = canvas->fClipStack; - fCurrLayer = canvas->fMCRec->fTopLayer; - - fMultiDeviceCS = nullptr; - if (fCurrLayer->fNext) { - fMultiDeviceCS = canvas->fClipStack; - fMultiDeviceCS->save(); - } - } - - ~SkDrawIter() { - if (fMultiDeviceCS) { - fMultiDeviceCS->restore(); - } - } + SkDrawIter(SkCanvas* canvas) + : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr) + {} bool next() { - if (fMultiDeviceCS && fDevice) { - // remove the previous device's bounds - fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), SkCanvas::kDifference_Op); - } - - // skip over recs with empty clips - while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { - fCurrLayer = fCurrLayer->fNext; - } - const DeviceCM* rec = fCurrLayer; if (rec && rec->fDevice) { - - fMatrix = rec->fMatrix; - fRC = &rec->fClip; fDevice = rec->fDevice; - if (!fDevice->accessPixels(&fDst)) { - fDst.reset(fDevice->imageInfo(), nullptr, 0); - } fPaint = rec->fPaint; - SkDEBUGCODE(this->validate();) - fCurrLayer = rec->fNext; // fCurrLayer may be nullptr now - return true; } return false; } - SkBaseDevice* getDevice() const { return fDevice; } - const SkRasterClip& getClip() const { return *fRC; } int getX() const { return fDevice->getOrigin().x(); } int getY() const { return fDevice->getOrigin().y(); } - const SkMatrix& getMatrix() const { return *fMatrix; } const SkPaint* getPaint() const { return fPaint; } + SkBaseDevice* fDevice; + private: const DeviceCM* fCurrLayer; const SkPaint* fPaint; // May be null. - SkClipStack* fMultiDeviceCS; - - typedef SkDraw INHERITED; }; +#define FOR_EACH_TOP_DEVICE( code ) \ + do { \ + DeviceCM* layer = fMCRec->fTopLayer; \ + while (layer) { \ + SkBaseDevice* device = layer->fDevice; \ + if (device) { \ + code; \ + } \ + layer = layer->fNext; \ + } \ + } while (0) + ///////////////////////////////////////////////////////////////////////////// static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) { @@ -483,7 +478,7 @@ public: * draw onto the previous layer using the xfermode from the original paint. */ SkPaint tmp; - tmp.setImageFilter(fPaint->getImageFilter()); + tmp.setImageFilter(fPaint->refImageFilter()); tmp.setBlendMode(fPaint->getBlendMode()); SkRect storage; if (rawBounds) { @@ -497,9 +492,7 @@ public: } if (SkDrawLooper* looper = paint.getLooper()) { - void* buffer = fLooperContextAllocator.reserveT( - looper->contextSize()); - fLooperContext = looper->createContext(canvas, buffer); + fLooperContext = looper->makeContext(canvas, &fAlloc); fIsSimple = false; } else { fLooperContext = nullptr; @@ -532,7 +525,7 @@ public: } private: - SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it + SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it SkCanvas* fCanvas; const SkPaint& fOrigPaint; @@ -543,7 +536,8 @@ private: bool fDone; bool fIsSimple; SkDrawLooper::Context* fLooperContext; - SkSmallAllocator<1, 32> fLooperContextAllocator; + char fStorage[48]; + SkArenaAlloc fAlloc {fStorage}; bool doNext(SkDrawFilter::Type drawType); }; @@ -635,12 +629,11 @@ static inline SkRect qr_clip_bounds(const SkIRect& bounds) { void SkCanvas::resetForNextPicture(const SkIRect& bounds) { this->restoreToCount(1); - fClipStack->reset(); fMCRec->reset(bounds); // We're peering through a lot of structs here. Only at this scope do we - // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice). - static_cast(fMCRec->fLayer->fDevice)->setNewSize(bounds.size()); + // know that the device is a SkNoPixelsDevice. + static_cast(fMCRec->fLayer->fDevice)->resetForNextPicture(bounds); fDeviceClipBounds = qr_clip_bounds(bounds); fIsScaleTranslate = true; } @@ -649,28 +642,22 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { if (device && device->forceConservativeRasterClip()) { flags = InitFlags(flags | kConservativeRasterClip_InitFlag); } - // Since init() is only called once by our constructors, it is safe to perform this - // const-cast. - *const_cast(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag); fAllowSimplifyClip = false; - fDeviceCMDirty = true; fSaveCount = 1; fMetaData = nullptr; #ifdef SK_EXPERIMENTAL_SHADOWING fLights = nullptr; #endif - fClipStack.reset(new SkClipStack); - fMCRec = (MCRec*)fMCStack.push_back(); - new (fMCRec) MCRec(fConservativeRasterClip); + new (fMCRec) MCRec; + fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect); fIsScaleTranslate = true; SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage)); fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage; - new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, - fMCRec->fMatrix); + new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fMCRec->fMatrix); fMCRec->fTopLayer = fMCRec->fLayer; @@ -682,6 +669,8 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { fMCRec->fLayer->fDevice = SkRef(device); fMCRec->fRasterClip.setRect(device->getGlobalBounds()); fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds()); + + device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect); } return device; @@ -690,57 +679,35 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { SkCanvas::SkCanvas() : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) , fProps(SkSurfaceProps::kLegacyFontHost_InitType) - , fConservativeRasterClip(false) { inc_canvas(); this->init(nullptr, kDefault_InitFlags); } -static SkBitmap make_nopixels(int width, int height) { - SkBitmap bitmap; - bitmap.setInfo(SkImageInfo::MakeUnknown(width, height)); - return bitmap; -} - -class SkNoPixelsBitmapDevice : public SkBitmapDevice { -public: - SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps) - : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps) - { - this->setOrigin(bounds.x(), bounds.y()); - } - -private: - - typedef SkBitmapDevice INHERITED; -}; - SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props) : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) , fProps(SkSurfacePropsCopyOrDefault(props)) - , fConservativeRasterClip(false) { inc_canvas(); - this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps), + this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps), kDefault_InitFlags)->unref(); } SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags) : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) , fProps(SkSurfaceProps::kLegacyFontHost_InitType) - , fConservativeRasterClip(false) { inc_canvas(); - this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref(); + SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds; + this->init(new SkNoPixelsDevice(r, fProps), flags)->unref(); } SkCanvas::SkCanvas(SkBaseDevice* device) : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) , fProps(device->surfaceProps()) - , fConservativeRasterClip(false) { inc_canvas(); @@ -750,7 +717,6 @@ SkCanvas::SkCanvas(SkBaseDevice* device) SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags) : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) , fProps(device->surfaceProps()) - , fConservativeRasterClip(false) { inc_canvas(); @@ -760,25 +726,42 @@ SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags) SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props) : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) , fProps(props) - , fConservativeRasterClip(false) { inc_canvas(); - SkAutoTUnref device(new SkBitmapDevice(bitmap, fProps)); - this->init(device, kDefault_InitFlags); + sk_sp device(new SkBitmapDevice(bitmap, fProps)); + this->init(device.get(), kDefault_InitFlags); } -SkCanvas::SkCanvas(const SkBitmap& bitmap) +SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr alloc, + SkRasterHandleAllocator::Handle hndl) : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) , fProps(SkSurfaceProps::kLegacyFontHost_InitType) - , fConservativeRasterClip(false) + , fAllocator(std::move(alloc)) { inc_canvas(); - SkAutoTUnref device(new SkBitmapDevice(bitmap, fProps)); - this->init(device, kDefault_InitFlags); + sk_sp device(new SkBitmapDevice(bitmap, fProps, hndl)); + this->init(device.get(), kDefault_InitFlags); } +SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {} + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK +SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior) + : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) + , fProps(SkSurfaceProps::kLegacyFontHost_InitType) + , fAllocator(nullptr) +{ + inc_canvas(); + + SkBitmap tmp(bitmap); + *const_cast(&tmp.info()) = tmp.info().makeColorSpace(nullptr); + sk_sp device(new SkBitmapDevice(tmp, fProps, nullptr)); + this->init(device.get(), kDefault_InitFlags); +} +#endif + SkCanvas::~SkCanvas() { // free up the contents of our deque this->restoreToCount(1); // restore everything but the last @@ -844,18 +827,11 @@ SkBaseDevice* SkCanvas::getDevice() const { return rec->fLayer->fDevice; } -SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { - if (updateMatrixClip) { - const_cast(this)->updateDeviceCMCache(); - } +SkBaseDevice* SkCanvas::getTopDevice() const { return fMCRec->fTopLayer->fDevice; } bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) { - if (kUnknown_SkColorType == bitmap->colorType()) { - return false; - } - bool weAllocated = false; if (nullptr == bitmap->pixelRef()) { if (!bitmap->tryAllocPixels()) { @@ -873,7 +849,7 @@ bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) { } if (weAllocated) { - bitmap->setPixelRef(nullptr); + bitmap->setPixelRef(nullptr, 0, 0); } return false; } @@ -902,15 +878,8 @@ bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowByte if (!device) { return false; } - const SkISize size = this->getBaseLayerSize(); - SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y); - if (!rec.trim(size.width(), size.height())) { - return false; - } - - // The device can assert that the requested area is always contained in its bounds - return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY); + return device->readPixels(dstInfo, dstP, rowBytes, x, y); } bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { @@ -922,77 +891,34 @@ bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { return false; } -bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes, +bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes, int x, int y) { - switch (origInfo.colorType()) { - case kUnknown_SkColorType: - case kIndex_8_SkColorType: - return false; - default: - break; - } - if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) { - return false; - } - - const SkISize size = this->getBaseLayerSize(); - SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height()); - if (!target.intersect(0, 0, size.width(), size.height())) { - return false; - } - SkBaseDevice* device = this->getDevice(); if (!device) { return false; } - // the intersect may have shrunk info's logical size - const SkImageInfo info = origInfo.makeWH(target.width(), target.height()); - - // if x or y are negative, then we have to adjust pixels - if (x > 0) { - x = 0; + // This check gives us an early out and prevents generation ID churn on the surface. + // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec. + SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height()); + if (!srcRect.intersect(0, 0, device->width(), device->height())) { + return false; } - if (y > 0) { - y = 0; - } - // here x,y are either 0 or negative - pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel()); - // Tell our owning surface to bump its generation ID - const bool completeOverwrite = info.dimensions() == size; + // Tell our owning surface to bump its generation ID. + const bool completeOverwrite = + srcRect.size() == SkISize::Make(device->width(), device->height()); this->predrawNotify(completeOverwrite); - // The device can assert that the requested area is always contained in its bounds - return device->writePixels(info, pixels, rowBytes, target.x(), target.y()); -} - -SkCanvas* SkCanvas::canvasForDrawIter() { - return this; + // This can still fail, most notably in the case of a invalid color type or alpha type + // conversion. We could pull those checks into this function and avoid the unnecessary + // generation ID bump. But then we would be performing those checks twice, since they + // are also necessary at the bitmap/pixmap entry points. + return device->writePixels(srcInfo, pixels, rowBytes, x, y); } ////////////////////////////////////////////////////////////////////////////// -void SkCanvas::updateDeviceCMCache() { - if (fDeviceCMDirty) { - const SkMatrix& totalMatrix = this->getTotalMatrix(); - const SkRasterClip& totalClip = fMCRec->fRasterClip; - DeviceCM* layer = fMCRec->fTopLayer; - - if (nullptr == layer->fNext) { // only one layer - layer->updateMC(totalMatrix, totalClip, nullptr); - } else { - SkRasterClip clip(totalClip); - do { - layer->updateMC(totalMatrix, clip, &clip); - } while ((layer = layer->fNext) != nullptr); - } - fDeviceCMDirty = false; - } -} - -/////////////////////////////////////////////////////////////////////////////// - void SkCanvas::checkForDeferredSave() { if (fMCRec->fDeferredSaveCount > 0) { this->doSave(); @@ -1063,7 +989,7 @@ void SkCanvas::internalSave() { new (newTop) MCRec(*fMCRec); // balanced in restore() fMCRec = newTop; - fClipStack->save(); + FOR_EACH_TOP_DEVICE(device->save()); } bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) { @@ -1072,8 +998,8 @@ bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) { bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags, SkIRect* intersection, const SkImageFilter* imageFilter) { - SkIRect clipBounds; - if (!this->getClipDeviceBounds(&clipBounds)) { + SkIRect clipBounds = this->getDeviceClipBounds(); + if (clipBounds.isEmpty()) { return false; } @@ -1094,6 +1020,7 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlag // early exit if the layer's bounds are clipped out if (!ir.intersect(clipBounds)) { if (BoundsAffectsClip(saveLayerFlags)) { + fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty fMCRec->fRasterClip.setEmpty(); fDeviceClipBounds.setEmpty(); } @@ -1106,7 +1033,6 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlag if (BoundsAffectsClip(saveLayerFlags)) { // Simplify the current clips since they will be applied properly during restore() - fClipStack->clipDevRect(ir, kReplace_Op); fMCRec->fRasterClip.setRect(ir); fDeviceClipBounds = qr_clip_bounds(ir); } @@ -1138,8 +1064,8 @@ int SkCanvas::saveLayer(const SaveLayerRec& origRec) { } void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter, - SkBaseDevice* dst, const SkMatrix& ctm, - const SkClipStack* clipStack) { + SkBaseDevice* dst, const SkIPoint& dstOrigin, + const SkMatrix& ctm) { SkDraw draw; SkRasterClip rc; rc.setRect(SkIRect::MakeWH(dst->width(), dst->height())); @@ -1148,17 +1074,17 @@ void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filt } draw.fMatrix = &SkMatrix::I(); draw.fRC = &rc; - draw.fClipStack = clipStack; - draw.fDevice = dst; SkPaint p; - p.setImageFilter(filter->makeWithLocalMatrix(ctm)); + if (filter) { + p.setImageFilter(filter->makeWithLocalMatrix(ctm)); + } - int x = src->getOrigin().x() - dst->getOrigin().x(); - int y = src->getOrigin().y() - dst->getOrigin().y(); + int x = src->getOrigin().x() - dstOrigin.x(); + int y = src->getOrigin().y() - dstOrigin.y(); auto special = src->snapSpecial(); if (special) { - dst->drawSpecial(draw, special.get(), x, y, p); + dst->drawSpecial(special.get(), x, y, p); } } @@ -1175,7 +1101,7 @@ static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool i return SkImageInfo::MakeN32(w, h, alphaType); } else { // keep the same characteristics as the prev - return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace())); + return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace()); } } @@ -1222,8 +1148,6 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra // that would invoke a possibly overridden virtual this->internalSave(); - fDeviceCMDirty = true; - SkIRect ir; if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) { return; @@ -1246,7 +1170,7 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra } SkBaseDevice* priorDevice = this->getTopDevice(); - if (nullptr == priorDevice) { + if (nullptr == priorDevice) { // Do we still need this check??? SkDebugf("Unable to find device for layer."); return; } @@ -1254,31 +1178,43 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque, paint); - SkAutoTUnref newDevice; + sk_sp newDevice; { const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() || (saveLayerFlags & kPreserveLCDText_SaveLayerFlag); const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage; const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo, - preserveLCDText); + preserveLCDText, + fAllocator.get()); newDevice.reset(priorDevice->onCreateDevice(createInfo, paint)); if (!newDevice) { - SkErrorInternals::SetError(kInternalError_SkError, - "Unable to create device for layer."); return; } } - newDevice->setOrigin(ir.fLeft, ir.fTop); + DeviceCM* layer = + new DeviceCM(newDevice.get(), paint, this, stashedMatrix); - DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix); - - layer->fNext = fMCRec->fTopLayer; + // only have a "next" if this new layer doesn't affect the clip (rare) + layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer; fMCRec->fLayer = layer; fMCRec->fTopLayer = layer; // this field is NOT an owner of layer - if (rec.fBackdrop) { - DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice, - fMCRec->fMatrix, this->getClipStack()); + if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) { + DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop }, + fMCRec->fMatrix); + } + + newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop); + + newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect); + if (layer->fNext) { + // need to punch a hole in the previous device, so we don't draw there, given that + // the new top-layer will allow drawing to happen "below" it. + SkRegion hole(ir); + do { + layer = layer->fNext; + layer->fDevice->clipRegion(hole, SkClipOp::kDifference); + } while (layer->fNext); } } @@ -1295,10 +1231,6 @@ int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { void SkCanvas::internalRestore() { SkASSERT(fMCStack.count() != 0); - fDeviceCMDirty = true; - - fClipStack->restore(); - // reserve our layer (if any) DeviceCM* layer = fMCRec->fLayer; // may be null // now detach it from fMCRec so we can pop(). Gets freed after its drawn @@ -1309,18 +1241,21 @@ void SkCanvas::internalRestore() { fMCStack.pop_back(); fMCRec = (MCRec*)fMCStack.back(); + if (fMCRec) { + FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix)); + } + /* Time to draw the layer's offscreen. We can't call the public drawSprite, since if we're being recorded, we don't want to record this (the recorder will have already recorded the restore). */ if (layer) { - if (layer->fNext) { + if (fMCRec) { const SkIPoint& origin = layer->fDevice->getOrigin(); this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint); // restore what we smashed in internalSaveLayer fMCRec->fMatrix = layer->fStashedMatrix; // reset this, since internalDrawDevice will have set it to true - fDeviceCMDirty = true; delete layer; } else { // we're at the root @@ -1377,22 +1312,6 @@ bool SkCanvas::onGetProps(SkSurfaceProps* props) const { } } -#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS -const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) { - SkPixmap pmap; - if (this->peekPixels(&pmap)) { - if (info) { - *info = pmap.info(); - } - if (rowBytes) { - *rowBytes = pmap.rowBytes(); - } - return pmap.addr(); - } - return nullptr; -} -#endif - bool SkCanvas::peekPixels(SkPixmap* pmap) { return this->onPeekPixels(pmap); } @@ -1414,7 +1333,7 @@ void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoi *rowBytes = pmap.rowBytes(); } if (origin) { - *origin = this->getTopDevice(false)->getOrigin(); + *origin = this->getTopDevice()->getOrigin(); } return pmap.writable_addr(); } @@ -1440,9 +1359,12 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPa SkImageFilter* filter = paint->getImageFilter(); SkIPoint pos = { x - iter.getX(), y - iter.getY() }; if (filter) { - dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint); + sk_sp specialImage = srcDev->snapSpecial(); + if (specialImage) { + dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint); + } } else { - dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); + dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint); } } @@ -1454,12 +1376,13 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPa void SkCanvas::translate(SkScalar dx, SkScalar dy) { if (dx || dy) { this->checkForDeferredSave(); - fDeviceCMDirty = true; fMCRec->fMatrix.preTranslate(dx,dy); // Translate shouldn't affect the is-scale-translateness of the matrix. SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate()); + FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix)); + this->didTranslate(dx,dy); } } @@ -1494,16 +1417,19 @@ void SkCanvas::concat(const SkMatrix& matrix) { } this->checkForDeferredSave(); - fDeviceCMDirty = true; fMCRec->fMatrix.preConcat(matrix); fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate(); + + FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix)); + this->didConcat(matrix); } void SkCanvas::internalSetMatrix(const SkMatrix& matrix) { - fDeviceCMDirty = true; fMCRec->fMatrix = matrix; fIsScaleTranslate = matrix.isScaleTranslate(); + + FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix)); } void SkCanvas::setMatrix(const SkMatrix& matrix) { @@ -1538,23 +1464,39 @@ sk_sp SkCanvas::getLights() const { ////////////////////////////////////////////////////////////////////////////// -void SkCanvas::clipRect(const SkRect& rect, ClipOp op, bool doAA) { +void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) { this->checkForDeferredSave(); ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; this->onClipRect(rect, op, edgeStyle); } -void SkCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; + + FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA)); + AutoValidateClip avc(this); - fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA); fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op, isAA); - fDeviceCMDirty = true; fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); } -void SkCanvas::clipRRect(const SkRRect& rrect, ClipOp op, bool doAA) { +void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) { + fClipRestrictionRect = rect; + if (fClipRestrictionRect.isEmpty()) { + // we notify the device, but we *dont* resolve deferred saves (since we're just + // removing the restriction if the rect is empty. how I hate this api. + FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect)); + } else { + this->checkForDeferredSave(); + FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect)); + AutoValidateClip avc(this); + fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op); + fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); + } +} + +void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) { this->checkForDeferredSave(); ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; if (rrect.isRect()) { @@ -1564,20 +1506,19 @@ void SkCanvas::clipRRect(const SkRRect& rrect, ClipOp op, bool doAA) { } } -void SkCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { AutoValidateClip avc(this); - fDeviceCMDirty = true; - bool isAA = kSoft_ClipEdgeStyle == edgeStyle; - fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA); + + FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA)); + fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op, isAA); fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); - return; } -void SkCanvas::clipPath(const SkPath& path, ClipOp op, bool doAA) { +void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) { this->checkForDeferredSave(); ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; @@ -1602,42 +1543,30 @@ void SkCanvas::clipPath(const SkPath& path, ClipOp op, bool doAA) { this->onClipPath(path, op, edgeStyle); } -void SkCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { AutoValidateClip avc(this); - fDeviceCMDirty = true; bool isAA = kSoft_ClipEdgeStyle == edgeStyle; - - fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA); + + FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA)); const SkPath* rasterClipPath = &path; const SkMatrix* matrix = &fMCRec->fMatrix; - SkPath tempPath; - if (fAllowSimplifyClip) { - isAA = getClipStack()->asPath(&tempPath); - rasterClipPath = &tempPath; - matrix = &SkMatrix::I(); - op = kReplace_Op; - } fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op, isAA); fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); } -void SkCanvas::clipRegion(const SkRegion& rgn, ClipOp op) { +void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) { this->checkForDeferredSave(); this->onClipRegion(rgn, op); } -void SkCanvas::onClipRegion(const SkRegion& rgn, ClipOp op) { +void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) { + FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op)); + AutoValidateClip avc(this); - fDeviceCMDirty = true; - - // todo: signal fClipStack that we have a region, and therefore (I guess) - // we have to ignore it, and use the region directly? - fClipStack->clipDevRect(rgn.getBounds(), op); - fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op); fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); } @@ -1651,52 +1580,69 @@ void SkCanvas::validateClip() const { SkASSERT(this->isClipEmpty()); return; } - - SkIRect ir; - ir.set(0, 0, device->width(), device->height()); - SkRasterClip tmpClip(ir, fConservativeRasterClip); - - SkClipStack::B2TIter iter(*fClipStack); - const SkClipStack::Element* element; - while ((element = iter.next()) != nullptr) { - switch (element->getType()) { - case SkClipStack::Element::kRect_Type: - element->getRect().round(&ir); - tmpClip.op(ir, (SkRegion::Op)element->getOp()); - break; - case SkClipStack::Element::kEmpty_Type: - tmpClip.setEmpty(); - break; - default: { - SkPath path; - element->asPath(&path); - tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(), - (SkRegion::Op)element->getOp(), element->isAA()); - break; - } - } - } #endif } #endif +#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP void SkCanvas::replayClips(ClipVisitor* visitor) const { +#if 0 SkClipStack::B2TIter iter(*fClipStack); const SkClipStack::Element* element; while ((element = iter.next()) != nullptr) { element->replay(visitor); } +#endif +} +#endif + +bool SkCanvas::androidFramework_isClipAA() const { + bool containsAA = false; + + FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA()); + + return containsAA; +} + +class RgnAccumulator { + SkRegion* fRgn; +public: + RgnAccumulator(SkRegion* total) : fRgn(total) {} + void accumulate(SkBaseDevice* device, SkRegion* rgn) { + SkIPoint origin = device->getOrigin(); + if (origin.x() | origin.y()) { + rgn->translate(origin.x(), origin.y()); + } + fRgn->op(*rgn, SkRegion::kUnion_Op); + } +}; + +void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) { + RgnAccumulator accum(rgn); + SkRegion tmp; + + rgn->setEmpty(); + FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp)); } /////////////////////////////////////////////////////////////////////////////// bool SkCanvas::isClipEmpty() const { return fMCRec->fRasterClip.isEmpty(); + + // TODO: should we only use the conservative answer in a recording canvas? +#if 0 + SkBaseDevice* dev = this->getTopDevice(); + // if no device we return true + return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType; +#endif } bool SkCanvas::isClipRect() const { - return fMCRec->fRasterClip.isRect(); + SkBaseDevice* dev = this->getTopDevice(); + // if no device we return false + return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType; } static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) { @@ -1773,59 +1719,40 @@ bool SkCanvas::quickReject(const SkPath& path) const { return path.isEmpty() || this->quickReject(path.getBounds()); } -bool SkCanvas::getClipBounds(SkRect* bounds) const { - SkIRect ibounds; - if (!this->getClipDeviceBounds(&ibounds)) { - return false; +SkRect SkCanvas::onGetLocalClipBounds() const { + SkIRect ibounds = this->onGetDeviceClipBounds(); + if (ibounds.isEmpty()) { + return SkRect::MakeEmpty(); } SkMatrix inverse; // if we can't invert the CTM, we can't return local clip bounds if (!fMCRec->fMatrix.invert(&inverse)) { - if (bounds) { - bounds->setEmpty(); - } - return false; + return SkRect::MakeEmpty(); } - if (bounds) { - SkRect r; - // adjust it outwards in case we are antialiasing - const int inset = 1; + SkRect bounds; + SkRect r; + // adjust it outwards in case we are antialiasing + const int inset = 1; - r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, - ibounds.fRight + inset, ibounds.fBottom + inset); - inverse.mapRect(bounds, r); - } - return true; + r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, + ibounds.fRight + inset, ibounds.fBottom + inset); + inverse.mapRect(&bounds, r); + return bounds; } -bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { - const SkRasterClip& clip = fMCRec->fRasterClip; - if (clip.isEmpty()) { - if (bounds) { - bounds->setEmpty(); - } - return false; - } - - if (bounds) { - *bounds = clip.getBounds(); - } - return true; +SkIRect SkCanvas::onGetDeviceClipBounds() const { + return fMCRec->fRasterClip.getBounds(); } const SkMatrix& SkCanvas::getTotalMatrix() const { return fMCRec->fMatrix; } -const SkRegion& SkCanvas::internal_private_getTotalClip() const { - return fMCRec->fRasterClip.forceGetBW(); -} - -GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() { +GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() { SkBaseDevice* dev = this->getTopDevice(); - return dev ? dev->accessDrawContext() : nullptr; + return dev ? dev->accessRenderTargetContext() : nullptr; } GrContext* SkCanvas::getGrContext() { @@ -1845,11 +1772,13 @@ void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, } // We don't have this method (yet), but technically this is what we should - // be able to assert... - // SkASSERT(outer.contains(inner)); + // be able to return ... + // if (!outer.contains(inner))) { // // For now at least check for containment of bounds - SkASSERT(outer.getBounds().contains(inner.getBounds())); + if (!outer.getBounds().contains(inner.getBounds())) { + return; + } this->onDrawDRRect(outer, inner, paint); } @@ -1888,11 +1817,15 @@ void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], con this->onDrawPoints(mode, count, pts, paint); } -void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], - const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, const SkPaint& paint) { - this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode, - indices, indexCount, paint); +void SkCanvas::drawVertices(const sk_sp& vertices, SkBlendMode mode, + const SkPaint& paint) { + RETURN_ON_NULL(vertices); + this->onDrawVerticesObject(vertices.get(), mode, paint); +} + +void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) { + RETURN_ON_NULL(vertices); + this->onDrawVerticesObject(vertices, mode, paint); } void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { @@ -2019,14 +1952,13 @@ void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, } void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], - const SkColor colors[], int count, SkXfermode::Mode mode, + const SkColor colors[], int count, SkBlendMode mode, const SkRect* cull, const SkPaint* paint) { RETURN_ON_NULL(atlas); if (count <= 0) { return; } SkASSERT(atlas); - SkASSERT(xform); SkASSERT(tex); this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint); } @@ -2063,7 +1995,7 @@ void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* cl matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top()); } if (clip_bounds) { - this->getClipDeviceBounds(clip_bounds); + *clip_bounds = this->getDeviceClipBounds(); clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top()); } } @@ -2087,7 +2019,7 @@ void SkCanvas::internalDrawPaint(const SkPaint& paint) { LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false) while (iter.next()) { - iter.fDevice->drawPaint(iter, looper.paint()); + iter.fDevice->drawPaint(looper.paint()); } LOOPER_END @@ -2100,7 +2032,7 @@ void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], return; } - SkRect r, storage; + SkRect r; const SkRect* bounds = nullptr; if (paint.canComputeFastBounds()) { // special-case 2 points (common for drawing a single line) @@ -2109,6 +2041,7 @@ void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], } else { r.set(pts, SkToInt(count)); } + SkRect storage; if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) { return; } @@ -2120,7 +2053,7 @@ void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds) while (iter.next()) { - iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); + iter.fDevice->drawPoints(mode, count, pts, looper.paint()); } LOOPER_END @@ -2136,52 +2069,48 @@ static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) { void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()"); - SkRect storage; - const SkRect* bounds = nullptr; if (paint.canComputeFastBounds()) { // Skia will draw an inverted rect, because it explicitly "sorts" it downstream. // To prevent accidental rejecting at this stage, we have to sort it before we check. SkRect tmp(r); tmp.sort(); + SkRect storage; if (this->quickReject(paint.computeFastBounds(tmp, &storage))) { return; } - bounds = &r; } if (needs_autodrawlooper(this, paint)) { - LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false) + LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false) while (iter.next()) { - iter.fDevice->drawRect(iter, r, looper.paint()); + iter.fDevice->drawRect(r, looper.paint()); } LOOPER_END } else { - this->predrawNotify(bounds, &paint, false); + this->predrawNotify(&r, &paint, false); SkDrawIter iter(this); while (iter.next()) { - iter.fDevice->drawRect(iter, r, paint); + iter.fDevice->drawRect(r, paint); } } } void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { - SkRect storage; SkRect regionRect = SkRect::Make(region.getBounds()); - const SkRect* bounds = nullptr; if (paint.canComputeFastBounds()) { + SkRect storage; if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) { return; } - bounds = ®ionRect; } - LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds) + LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, ®ionRect) while (iter.next()) { - iter.fDevice->drawRegion(iter, region, looper.paint()); + iter.fDevice->drawRegion(region, looper.paint()); } LOOPER_END @@ -2189,19 +2118,17 @@ void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()"); - SkRect storage; - const SkRect* bounds = nullptr; if (paint.canComputeFastBounds()) { + SkRect storage; if (this->quickReject(paint.computeFastBounds(oval, &storage))) { return; } - bounds = &oval; } - LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) + LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval) while (iter.next()) { - iter.fDevice->drawOval(iter, oval, looper.paint()); + iter.fDevice->drawOval(oval, looper.paint()); } LOOPER_END @@ -2211,20 +2138,18 @@ void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()"); - const SkRect* bounds = nullptr; if (paint.canComputeFastBounds()) { SkRect storage; // Note we're using the entire oval as the bounds. if (this->quickReject(paint.computeFastBounds(oval, &storage))) { return; } - bounds = &oval; } - LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) + LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval) while (iter.next()) { - iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint()); + iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint()); } LOOPER_END @@ -2232,13 +2157,11 @@ void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle, void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()"); - SkRect storage; - const SkRect* bounds = nullptr; if (paint.canComputeFastBounds()) { + SkRect storage; if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) { return; } - bounds = &rrect.getBounds(); } if (rrect.isRect()) { @@ -2251,30 +2174,27 @@ void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { return; } - LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) + LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds()) while (iter.next()) { - iter.fDevice->drawRRect(iter, rrect, looper.paint()); + iter.fDevice->drawRRect(rrect, looper.paint()); } LOOPER_END } -void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, - const SkPaint& paint) { - SkRect storage; - const SkRect* bounds = nullptr; +void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { if (paint.canComputeFastBounds()) { + SkRect storage; if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) { return; } - bounds = &outer.getBounds(); } - LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) + LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds()) while (iter.next()) { - iter.fDevice->drawDRRect(iter, outer, inner, looper.paint()); + iter.fDevice->drawDRRect(outer, inner, looper.paint()); } LOOPER_END @@ -2286,28 +2206,25 @@ void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { return; } - SkRect storage; - const SkRect* bounds = nullptr; + const SkRect& pathBounds = path.getBounds(); if (!path.isInverseFillType() && paint.canComputeFastBounds()) { - const SkRect& pathBounds = path.getBounds(); + SkRect storage; if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) { return; } - bounds = &pathBounds; } - const SkRect& r = path.getBounds(); - if (r.width() <= 0 && r.height() <= 0) { + if (pathBounds.width() <= 0 && pathBounds.height() <= 0) { if (path.isInverseFillType()) { this->internalDrawPaint(paint); return; } } - LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds) + LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds) while (iter.next()) { - iter.fDevice->drawPath(iter, path, looper.paint()); + iter.fDevice->drawPath(path, looper.paint()); } LOOPER_END @@ -2369,12 +2286,12 @@ void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const S const SkPaint& pnt = looper.paint(); if (special) { SkPoint pt; - iter.fMatrix->mapXY(x, y, &pt); - iter.fDevice->drawSpecial(iter, special.get(), + iter.fDevice->ctm().mapXY(x, y, &pt); + iter.fDevice->drawSpecial(special.get(), SkScalarRoundToInt(pt.fX), SkScalarRoundToInt(pt.fY), pnt); } else { - iter.fDevice->drawImage(iter, image, x, y, pnt); + iter.fDevice->drawImage(image, x, y, pnt); } } @@ -2402,7 +2319,7 @@ void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const Sk image->isOpaque()) while (iter.next()) { - iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint); + iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint); } LOOPER_END @@ -2421,23 +2338,20 @@ void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, cons paint = lazy.init(); } - const SkMatrix matrix = SkMatrix::MakeTrans(x, y); - - SkRect storage; - const SkRect* bounds = nullptr; - if (paint->canComputeFastBounds()) { - bitmap.getBounds(&storage); - matrix.mapRect(&storage); - SkRect tmp = storage; - if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) { + SkRect bounds; + bitmap.getBounds(&bounds); + bounds.offset(x, y); + bool canFastBounds = paint->canComputeFastBounds(); + if (canFastBounds) { + SkRect storage; + if (this->quickReject(paint->computeFastBounds(bounds, &storage))) { return; } - bounds = &storage; } sk_sp special; - bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(), - *paint); + bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), + bitmap.height(), *paint); if (drawAsSprite && paint->getImageFilter()) { special = this->getDevice()->makeSpecial(bitmap); if (!special) { @@ -2445,18 +2359,20 @@ void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, cons } } - LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds) + const SkMatrix matrix = SkMatrix::MakeTrans(x, y); + + LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds) while (iter.next()) { const SkPaint& pnt = looper.paint(); if (special) { SkPoint pt; - iter.fMatrix->mapXY(x, y, &pt); - iter.fDevice->drawSpecial(iter, special.get(), + iter.fDevice->ctm().mapXY(x, y, &pt); + iter.fDevice->drawSpecial(special.get(), SkScalarRoundToInt(pt.fX), SkScalarRoundToInt(pt.fY), pnt); } else { - iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); + iter.fDevice->drawBitmap(bitmap, matrix, looper.paint()); } } @@ -2487,7 +2403,7 @@ void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, bitmap.isOpaque()) while (iter.next()) { - iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint); + iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint); } LOOPER_END @@ -2519,7 +2435,7 @@ void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, cons LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) while (iter.next()) { - iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint()); + iter.fDevice->drawImageNine(image, center, dst, looper.paint()); } LOOPER_END @@ -2545,7 +2461,7 @@ void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, c LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) while (iter.next()) { - iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint()); + iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint()); } LOOPER_END @@ -2568,7 +2484,7 @@ void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) while (iter.next()) { - iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint()); + iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint()); } LOOPER_END @@ -2591,7 +2507,7 @@ void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattic LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) while (iter.next()) { - iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint()); + iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint()); } LOOPER_END @@ -2617,87 +2533,13 @@ private: SkLazyPaint fLazy; }; -void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, - const SkRect& r, SkScalar textSize) { - if (paint.getStyle() == SkPaint::kFill_Style) { - draw.fDevice->drawRect(draw, r, paint); - } else { - SkPaint p(paint); - p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); - draw.fDevice->drawRect(draw, r, p); - } -} - -void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, - const char text[], size_t byteLength, - SkScalar x, SkScalar y) { - SkASSERT(byteLength == 0 || text != nullptr); - - // nothing to draw - if (text == nullptr || byteLength == 0 || - draw.fRC->isEmpty() || - (paint.getAlpha() == 0 && paint.isSrcOver())) { - return; - } - - SkScalar width = 0; - SkPoint start; - - start.set(0, 0); // to avoid warning - if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | - SkPaint::kStrikeThruText_Flag)) { - width = paint.measureText(text, byteLength); - - SkScalar offsetX = 0; - if (paint.getTextAlign() == SkPaint::kCenter_Align) { - offsetX = SkScalarHalf(width); - } else if (paint.getTextAlign() == SkPaint::kRight_Align) { - offsetX = width; - } - start.set(x - offsetX, y); - } - - if (0 == width) { - return; - } - - uint32_t flags = paint.getFlags(); - - if (flags & (SkPaint::kUnderlineText_Flag | - SkPaint::kStrikeThruText_Flag)) { - SkScalar textSize = paint.getTextSize(); - SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); - SkRect r; - - r.fLeft = start.fX; - r.fRight = start.fX + width; - - if (flags & SkPaint::kUnderlineText_Flag) { - SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, - start.fY); - r.fTop = offset; - r.fBottom = offset + height; - DrawRect(draw, paint, r, 1); - } - if (flags & SkPaint::kStrikeThruText_Flag) { - SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, - start.fY); - r.fTop = offset; - r.fBottom = offset + height; - DrawRect(draw, paint, r, 1); - } - } -} - void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) while (iter.next()) { SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); - iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); - DrawTextDecorations(iter, dfp.paint(), - static_cast(text), byteLength, x, y); + iter.fDevice->drawText(text, byteLength, x, y, dfp.paint()); } LOOPER_END @@ -2711,7 +2553,7 @@ void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint while (iter.next()) { SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); - iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset, + iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset, dfp.paint()); } @@ -2727,7 +2569,7 @@ void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScala while (iter.next()) { SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); - iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset, + iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset, dfp.paint()); } @@ -2739,7 +2581,7 @@ void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPat LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) while (iter.next()) { - iter.fDevice->drawTextOnPath(iter, text, byteLength, path, + iter.fDevice->drawTextOnPath(text, byteLength, path, matrix, looper.paint()); } @@ -2755,7 +2597,7 @@ void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRS LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) while (iter.next()) { - iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint()); + iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint()); } LOOPER_END @@ -2784,7 +2626,7 @@ void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, while (iter.next()) { SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); - iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter); + iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter); } LOOPER_END @@ -2835,35 +2677,33 @@ void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, this->onDrawTextBlob(blob, x, y, paint); } -void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint verts[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { +void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode, + const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()"); LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr) while (iter.next()) { - iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, - colors, xmode, indices, indexCount, - looper.paint()); + // In the common case of one iteration we could std::move vertices here. + iter.fDevice->drawVertices(vertices, bmode, looper.paint()); } LOOPER_END } void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { + const SkPoint texCoords[4], SkBlendMode bmode, + const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()"); if (nullptr == cubics) { return; } - this->onDrawPatch(cubics, colors, texCoords, xmode, paint); + this->onDrawPatch(cubics, colors, texCoords, bmode, paint); } void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { + const SkPoint texCoords[4], SkBlendMode bmode, + const SkPaint& paint) { // Since a patch is always within the convex hull of the control points, we discard it when its // bounding rectangle is completely outside the current clip. SkRect bounds; @@ -2875,7 +2715,7 @@ void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr) while (iter.next()) { - iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint); + iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint); } LOOPER_END @@ -2906,7 +2746,7 @@ void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) { } void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], - const SkColor colors[], int count, SkXfermode::Mode mode, + const SkColor colors[], int count, SkBlendMode bmode, const SkRect* cull, const SkPaint* paint) { if (cull && this->quickReject(*cull)) { return; @@ -2919,7 +2759,7 @@ void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr) while (iter.next()) { - iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt); + iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt); } LOOPER_END } @@ -2930,7 +2770,7 @@ void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* va SkPaint paint; LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr) while (iter.next()) { - iter.fDevice->drawAnnotation(iter, rect, key, value); + iter.fDevice->drawAnnotation(rect, key, value); } LOOPER_END } @@ -2940,15 +2780,6 @@ void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* va // methods, rather than actually drawing themselves. ////////////////////////////////////////////////////////////////////////////// -void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) { - TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()"); - SkPaint paint; - - paint.setARGB(a, r, g, b); - paint.setBlendMode(mode); - this->drawPaint(paint); -} - void SkCanvas::drawColor(SkColor c, SkBlendMode mode) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()"); SkPaint paint; @@ -2960,24 +2791,11 @@ void SkCanvas::drawColor(SkColor c, SkBlendMode mode) { void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)"); - SkPoint pt; - - pt.set(x, y); + const SkPoint pt = { x, y }; this->drawPoints(kPoints_PointMode, 1, &pt, paint); } -void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { - TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)"); - SkPoint pt; - SkPaint paint; - - pt.set(x, y); - paint.setColor(color); - this->drawPoints(kPoints_PointMode, 1, &pt, paint); -} - -void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, - const SkPaint& paint) { +void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()"); SkPoint pts[2]; @@ -2986,18 +2804,7 @@ void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, this->drawPoints(kLines_PointMode, 2, pts, paint); } -void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, - SkScalar right, SkScalar bottom, - const SkPaint& paint) { - TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()"); - SkRect r; - - r.set(left, top, right, bottom); - this->drawRect(r, paint); -} - -void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, - const SkPaint& paint) { +void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()"); if (radius < 0) { radius = 0; @@ -3299,11 +3106,11 @@ void SkCanvas::LayerIter::next() { } SkBaseDevice* SkCanvas::LayerIter::device() const { - return fImpl->getDevice(); + return fImpl->fDevice; } const SkMatrix& SkCanvas::LayerIter::matrix() const { - return fImpl->getMatrix(); + return fImpl->fDevice->ctm(); } const SkPaint& SkCanvas::LayerIter::paint() const { @@ -3314,13 +3121,18 @@ const SkPaint& SkCanvas::LayerIter::paint() const { return *paint; } -const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } +void SkCanvas::LayerIter::clip(SkRegion* rgn) const { + return fImpl->fDevice->onAsRgnClip(rgn); +} + int SkCanvas::LayerIter::x() const { return fImpl->getX(); } int SkCanvas::LayerIter::y() const { return fImpl->getY(); } /////////////////////////////////////////////////////////////////////////////// +#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP SkCanvasClipVisitor::~SkCanvasClipVisitor() { } +#endif /////////////////////////////////////////////////////////////////////////////// @@ -3337,6 +3149,7 @@ static bool supported_for_raster_canvas(const SkImageInfo& info) { case kAlpha_8_SkColorType: case kRGB_565_SkColorType: case kN32_SkColorType: + case kRGBA_F16_SkColorType: break; default: return false; @@ -3345,7 +3158,8 @@ static bool supported_for_raster_canvas(const SkImageInfo& info) { return true; } -SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) { +std::unique_ptr SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels, + size_t rowBytes) { if (!supported_for_raster_canvas(info)) { return nullptr; } @@ -3354,7 +3168,7 @@ SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_ if (!bitmap.installPixels(info, pixels, rowBytes)) { return nullptr; } - return new SkCanvas(bitmap); + return skstd::make_unique(bitmap); } /////////////////////////////////////////////////////////////////////////////// @@ -3383,20 +3197,20 @@ SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { fCanvas->restoreToCount(fSaveCount); } -#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API -SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) { - return this->makeSurface(info, props).release(); +/////////////////////////////////////////////////////////////////////////////// + +SkNoDrawCanvas::SkNoDrawCanvas(int width, int height) + : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {} + +SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds) + : INHERITED(bounds, kConservativeRasterClip_InitFlag) {} + +SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { + (void)this->INHERITED::getSaveLayerStrategy(rec); + return kNoLayer_SaveLayerStrategy; } -#endif -///////////////////////////////// - -const SkCanvas::ClipOp SkCanvas::kDifference_Op; -const SkCanvas::ClipOp SkCanvas::kIntersect_Op; -const SkCanvas::ClipOp SkCanvas::kUnion_Op; -const SkCanvas::ClipOp SkCanvas::kXOR_Op; -const SkCanvas::ClipOp SkCanvas::kReverseDifference_Op; -const SkCanvas::ClipOp SkCanvas::kReplace_Op; +/////////////////////////////////////////////////////////////////////////////// static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, ""); static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, ""); @@ -3404,3 +3218,58 @@ static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "") static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, ""); static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, ""); static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, ""); + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const { + if (fAllocator && fMCRec->fTopLayer->fDevice) { + const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice; + SkRasterHandleAllocator::Handle handle = dev->getRasterHandle(); + SkIPoint origin = dev->getOrigin(); + SkMatrix ctm = this->getTotalMatrix(); + ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y())); + + SkIRect clip = fMCRec->fRasterClip.getBounds(); + clip.offset(-origin.x(), -origin.y()); + if (!clip.intersect(0, 0, dev->width(), dev->height())) { + clip.setEmpty(); + } + + fAllocator->updateHandle(handle, ctm, clip); + return handle; + } + return nullptr; +} + +static bool install(SkBitmap* bm, const SkImageInfo& info, + const SkRasterHandleAllocator::Rec& rec) { + return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr, + rec.fReleaseProc, rec.fReleaseCtx); +} + +SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info, + SkBitmap* bm) { + SkRasterHandleAllocator::Rec rec; + if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) { + return nullptr; + } + return rec.fHandle; +} + +std::unique_ptr +SkRasterHandleAllocator::MakeCanvas(std::unique_ptr alloc, + const SkImageInfo& info, const Rec* rec) { + if (!alloc || !supported_for_raster_canvas(info)) { + return nullptr; + } + + SkBitmap bm; + Handle hndl; + + if (rec) { + hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr; + } else { + hndl = alloc->allocBitmap(info, &bm); + } + return hndl ? std::unique_ptr(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr; +} diff --git a/gfx/skia/skia/src/core/SkChunkAlloc.cpp b/gfx/skia/skia/src/core/SkChunkAlloc.cpp deleted file mode 100644 index 90650a7ad8f2..000000000000 --- a/gfx/skia/skia/src/core/SkChunkAlloc.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkChunkAlloc.h" - -// Don't malloc any chunks smaller than this -#define MIN_CHUNKALLOC_BLOCK_SIZE 1024 - -// Return the new min blocksize given the current value -static size_t increase_next_size(size_t size) { - return size + (size >> 1); -} - -/////////////////////////////////////////////////////////////////////////////// - -struct SkChunkAlloc::Block { - Block* fNext; - size_t fFreeSize; - char* fFreePtr; - // data[] follows - - size_t blockSize() const { - char* start = this->startOfData(); - size_t bytes = fFreePtr - start; - return fFreeSize + bytes; - } - - void reset() { - fNext = nullptr; - fFreeSize = this->blockSize(); - fFreePtr = this->startOfData(); - } - - char* startOfData() const { - return reinterpret_cast(SkAlign8(reinterpret_cast(this + 1))); - } - - static void FreeChain(Block* block) { - while (block) { - Block* next = block->fNext; - sk_free(block); - block = next; - } - } - - bool contains(const void* addr) const { - const char* ptr = reinterpret_cast(addr); - return ptr >= this->startOfData() && ptr < fFreePtr; - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -SkChunkAlloc::SkChunkAlloc(size_t minSize) { - if (minSize < MIN_CHUNKALLOC_BLOCK_SIZE) { - minSize = MIN_CHUNKALLOC_BLOCK_SIZE; - } - - fBlock = nullptr; - fMinSize = minSize; - fChunkSize = fMinSize; - fTotalCapacity = 0; - fTotalUsed = 0; - SkDEBUGCODE(fTotalLost = 0;) - SkDEBUGCODE(fBlockCount = 0;) -} - -SkChunkAlloc::~SkChunkAlloc() { - this->reset(); -} - -void SkChunkAlloc::reset() { - Block::FreeChain(fBlock); - fBlock = nullptr; - fChunkSize = fMinSize; // reset to our initial minSize - fTotalCapacity = 0; - fTotalUsed = 0; - SkDEBUGCODE(fTotalLost = 0;) - SkDEBUGCODE(fBlockCount = 0;) -} - -void SkChunkAlloc::rewind() { - SkDEBUGCODE(this->validate();) - - Block* largest = fBlock; - - if (largest) { - Block* next; - for (Block* cur = largest->fNext; cur; cur = next) { - next = cur->fNext; - if (cur->blockSize() > largest->blockSize()) { - sk_free(largest); - largest = cur; - } else { - sk_free(cur); - } - } - - largest->reset(); - fTotalCapacity = largest->blockSize(); - SkDEBUGCODE(fBlockCount = 1;) - } else { - fTotalCapacity = 0; - SkDEBUGCODE(fBlockCount = 0;) - } - - fBlock = largest; - fChunkSize = fMinSize; // reset to our initial minSize - fTotalUsed = 0; - SkDEBUGCODE(fTotalLost = 0;) - SkDEBUGCODE(this->validate();) -} - -SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) { - size_t size = bytes; - if (size < fChunkSize) { - size = fChunkSize; - } - - Block* block = (Block*)sk_malloc_flags(SkAlign8(sizeof(Block)) + size, - ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0); - - if (block) { - block->fFreeSize = size; - block->fFreePtr = block->startOfData(); - - fTotalCapacity += size; - SkDEBUGCODE(fBlockCount += 1;) - - fChunkSize = increase_next_size(fChunkSize); - } - return block; -} - -SkChunkAlloc::Block* SkChunkAlloc::addBlockIfNecessary(size_t bytes, AllocFailType ftype) { - SkASSERT(SkIsAlign8(bytes)); - - if (!fBlock || bytes > fBlock->fFreeSize) { - Block* block = this->newBlock(bytes, ftype); - if (!block) { - return nullptr; - } -#ifdef SK_DEBUG - if (fBlock) { - fTotalLost += fBlock->fFreeSize; - } -#endif - block->fNext = fBlock; - fBlock = block; - } - - SkASSERT(fBlock && bytes <= fBlock->fFreeSize); - return fBlock; -} - -void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) { - SkDEBUGCODE(this->validate();) - - bytes = SkAlign8(bytes); - - Block* block = this->addBlockIfNecessary(bytes, ftype); - if (!block) { - return nullptr; - } - - char* ptr = block->fFreePtr; - - fTotalUsed += bytes; - block->fFreeSize -= bytes; - block->fFreePtr = ptr + bytes; - SkDEBUGCODE(this->validate();) - SkASSERT(SkIsAlign8((size_t)ptr)); - return ptr; -} - -size_t SkChunkAlloc::unalloc(void* ptr) { - SkDEBUGCODE(this->validate();) - - size_t bytes = 0; - Block* block = fBlock; - if (block) { - char* cPtr = reinterpret_cast(ptr); - char* start = block->startOfData(); - if (start <= cPtr && cPtr < block->fFreePtr) { - bytes = block->fFreePtr - cPtr; - fTotalUsed -= bytes; - block->fFreeSize += bytes; - block->fFreePtr = cPtr; - } - } - SkDEBUGCODE(this->validate();) - return bytes; -} - -bool SkChunkAlloc::contains(const void* addr) const { - const Block* block = fBlock; - while (block) { - if (block->contains(addr)) { - return true; - } - block = block->fNext; - } - return false; -} - -#ifdef SK_DEBUG -void SkChunkAlloc::validate() { - int numBlocks = 0; - size_t totCapacity = 0; - size_t totUsed = 0; - size_t totLost = 0; - size_t totAvailable = 0; - - for (Block* temp = fBlock; temp; temp = temp->fNext) { - ++numBlocks; - totCapacity += temp->blockSize(); - totUsed += temp->fFreePtr - temp->startOfData(); - if (temp == fBlock) { - totAvailable += temp->fFreeSize; - } else { - totLost += temp->fFreeSize; - } - } - - SkASSERT(fBlockCount == numBlocks); - SkASSERT(fTotalCapacity == totCapacity); - SkASSERT(fTotalUsed == totUsed); - SkASSERT(fTotalLost == totLost); - SkASSERT(totCapacity == totUsed + totLost + totAvailable); -} -#endif diff --git a/gfx/skia/skia/src/core/SkClipOpPriv.h b/gfx/skia/skia/src/core/SkClipOpPriv.h new file mode 100644 index 000000000000..21695b904251 --- /dev/null +++ b/gfx/skia/skia/src/core/SkClipOpPriv.h @@ -0,0 +1,21 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkClipOpPriv_DEFINED +#define SkClipOpPriv_DEFINED + +#include "SkClipOp.h" + +const SkClipOp kDifference_SkClipOp = SkClipOp::kDifference; +const SkClipOp kIntersect_SkClipOp = SkClipOp::kIntersect; + +const SkClipOp kUnion_SkClipOp = SkClipOp::kUnion_deprecated; +const SkClipOp kXOR_SkClipOp = SkClipOp::kXOR_deprecated; +const SkClipOp kReverseDifference_SkClipOp = SkClipOp::kReverseDifference_deprecated; +const SkClipOp kReplace_SkClipOp = SkClipOp::kReplace_deprecated; + +#endif diff --git a/gfx/skia/skia/src/core/SkClipStack.cpp b/gfx/skia/skia/src/core/SkClipStack.cpp index f155b49c4f59..516cc8d1aef8 100644 --- a/gfx/skia/skia/src/core/SkClipStack.cpp +++ b/gfx/skia/skia/src/core/SkClipStack.cpp @@ -10,6 +10,7 @@ #include "SkClipStack.h" #include "SkPath.h" #include "SkPathOps.h" +#include "SkClipOpPriv.h" #include @@ -69,6 +70,7 @@ bool SkClipStack::Element::operator== (const Element& element) const { } } +#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP void SkClipStack::Element::replay(SkCanvasClipVisitor* visitor) const { static const SkRect kEmptyRect = { 0, 0, 0, 0 }; @@ -83,10 +85,11 @@ void SkClipStack::Element::replay(SkCanvasClipVisitor* visitor) const { visitor->clipRect(this->getRect(), this->getOp(), this->isAA()); break; case kEmpty_Type: - visitor->clipRect(kEmptyRect, SkCanvas::kIntersect_Op, false); + visitor->clipRect(kEmptyRect, kIntersect_SkClipOp, false); break; } } +#endif void SkClipStack::Element::invertShapeFillType() { switch (fType) { @@ -111,7 +114,7 @@ void SkClipStack::Element::invertShapeFillType() { } } -void SkClipStack::Element::initPath(int saveCount, const SkPath& path, SkCanvas::ClipOp op, +void SkClipStack::Element::initPath(int saveCount, const SkPath& path, SkClipOp op, bool doAA) { if (!path.isInverseFillType()) { SkRect r; @@ -176,16 +179,16 @@ void SkClipStack::Element::checkEmpty() const { SkASSERT(!fPath.isValid()); } -bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkCanvas::ClipOp op) const { +bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkClipOp op) const { if (kEmpty_Type == fType && - (SkCanvas::kDifference_Op == op || SkCanvas::kIntersect_Op == op)) { + (kDifference_SkClipOp == op || kIntersect_SkClipOp == op)) { return true; } // Only clips within the same save/restore frame (as captured by // the save count) can be merged return fSaveCount == saveCount && - SkCanvas::kIntersect_Op == op && - (SkCanvas::kIntersect_Op == fOp || SkCanvas::kReplace_Op == fOp); + kIntersect_SkClipOp == op && + (kIntersect_SkClipOp == fOp || kReplace_SkClipOp == fOp); } bool SkClipStack::Element::rectRectIntersectAllowed(const SkRect& newR, bool newAA) const { @@ -399,9 +402,9 @@ void SkClipStack::Element::updateBoundAndGenID(const Element* prior) { fFiniteBound = this->getRect(); fFiniteBoundType = kNormal_BoundsType; - if (SkCanvas::kReplace_Op == fOp || - (SkCanvas::kIntersect_Op == fOp && nullptr == prior) || - (SkCanvas::kIntersect_Op == fOp && prior->fIsIntersectionOfRects && + if (kReplace_SkClipOp == fOp || + (kIntersect_SkClipOp == fOp && nullptr == prior) || + (kIntersect_SkClipOp == fOp && prior->fIsIntersectionOfRects && prior->rectRectIntersectAllowed(this->getRect(), fDoAA))) { fIsIntersectionOfRects = true; } @@ -460,28 +463,28 @@ void SkClipStack::Element::updateBoundAndGenID(const Element* prior) { // Now integrate with clip with the prior clips switch (fOp) { - case SkCanvas::kDifference_Op: + case kDifference_SkClipOp: this->combineBoundsDiff(combination, prevFinite); break; - case SkCanvas::kXOR_Op: + case kXOR_SkClipOp: this->combineBoundsXOR(combination, prevFinite); break; - case SkCanvas::kUnion_Op: + case kUnion_SkClipOp: this->combineBoundsUnion(combination, prevFinite); break; - case SkCanvas::kIntersect_Op: + case kIntersect_SkClipOp: this->combineBoundsIntersection(combination, prevFinite); break; - case SkCanvas::kReverseDifference_Op: + case kReverseDifference_SkClipOp: this->combineBoundsRevDiff(combination, prevFinite); break; - case SkCanvas::kReplace_Op: + case kReplace_SkClipOp: // Replace just ignores everything prior // The current clip's bound information is already filled in // so nothing to do break; default: - SkDebugf("SkCanvas::ClipOp error\n"); + SkDebugf("SkClipOp error\n"); SkASSERT(0); break; } @@ -498,6 +501,11 @@ SkClipStack::SkClipStack() , fSaveCount(0) { } +SkClipStack::SkClipStack(void* storage, size_t size) + : fDeque(sizeof(Element), storage, size, kDefaultElementAllocCnt) + , fSaveCount(0) { +} + SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Element), kDefaultElementAllocCnt) { *this = b; @@ -579,6 +587,20 @@ void SkClipStack::restoreTo(int saveCount) { } } +SkRect SkClipStack::bounds(const SkIRect& deviceBounds) const { + // TODO: optimize this. + SkRect r; + SkClipStack::BoundsType bounds; + this->getBounds(&r, &bounds); + if (bounds == SkClipStack::kInsideOut_BoundsType) { + return SkRect::Make(deviceBounds); + } + return r.intersect(SkRect::Make(deviceBounds)) ? r : SkRect::MakeEmpty(); +} + +// TODO: optimize this. +bool SkClipStack::isEmpty(const SkIRect& r) const { return this->bounds(r).isEmpty(); } + void SkClipStack::getBounds(SkRect* canvFiniteBound, BoundsType* boundType, bool* isIntersectionOfRects) const { @@ -608,7 +630,7 @@ bool SkClipStack::internalQuickContains(const SkRect& rect) const { Iter iter(*this, Iter::kTop_IterStart); const Element* element = iter.prev(); while (element != nullptr) { - if (SkCanvas::kIntersect_Op != element->getOp() && SkCanvas::kReplace_Op != element->getOp()) + if (kIntersect_SkClipOp != element->getOp() && kReplace_SkClipOp != element->getOp()) return false; if (element->isInverseFilled()) { // Part of 'rect' could be trimmed off by the inverse-filled clip element @@ -620,7 +642,7 @@ bool SkClipStack::internalQuickContains(const SkRect& rect) const { return false; } } - if (SkCanvas::kReplace_Op == element->getOp()) { + if (kReplace_SkClipOp == element->getOp()) { break; } element = iter.prev(); @@ -633,7 +655,7 @@ bool SkClipStack::internalQuickContains(const SkRRect& rrect) const { Iter iter(*this, Iter::kTop_IterStart); const Element* element = iter.prev(); while (element != nullptr) { - if (SkCanvas::kIntersect_Op != element->getOp() && SkCanvas::kReplace_Op != element->getOp()) + if (kIntersect_SkClipOp != element->getOp() && kReplace_SkClipOp != element->getOp()) return false; if (element->isInverseFilled()) { // Part of 'rrect' could be trimmed off by the inverse-filled clip element @@ -645,7 +667,7 @@ bool SkClipStack::internalQuickContains(const SkRRect& rrect) const { return false; } } - if (SkCanvas::kReplace_Op == element->getOp()) { + if (kReplace_SkClipOp == element->getOp()) { break; } element = iter.prev(); @@ -666,8 +688,8 @@ bool SkClipStack::asPath(SkPath *path) const { element->asPath(&operand); } - SkCanvas::ClipOp elementOp = element->getOp(); - if (elementOp == SkCanvas::kReplace_Op) { + SkClipOp elementOp = element->getOp(); + if (elementOp == kReplace_SkClipOp) { *path = operand; } else { Op(*path, operand, (SkPathOp)elementOp, path); @@ -718,7 +740,7 @@ void SkClipStack::pushElement(const Element& element) { } break; } - } else if (SkCanvas::kReplace_Op == element.getOp()) { + } else if (kReplace_SkClipOp == element.getOp()) { this->restoreTo(fSaveCount - 1); prior = (Element*) fDeque.back(); } @@ -727,12 +749,16 @@ void SkClipStack::pushElement(const Element& element) { newElement->updateBoundAndGenID(prior); } -void SkClipStack::clipRRect(const SkRRect& rrect, const SkMatrix& matrix, SkCanvas::ClipOp op, +void SkClipStack::clipRRect(const SkRRect& rrect, const SkMatrix& matrix, SkClipOp op, bool doAA) { SkRRect transformedRRect; if (rrect.transform(matrix, &transformedRRect)) { Element element(fSaveCount, transformedRRect, op, doAA); this->pushElement(element); + if (this->hasClipRestriction(op)) { + Element element(fSaveCount, fClipRestrictionRect, kIntersect_SkClipOp, false); + this->pushElement(element); + } return; } SkPath path; @@ -741,11 +767,16 @@ void SkClipStack::clipRRect(const SkRRect& rrect, const SkMatrix& matrix, SkCanv this->clipPath(path, matrix, op, doAA); } -void SkClipStack::clipRect(const SkRect& rect, const SkMatrix& matrix, SkCanvas::ClipOp op, +void SkClipStack::clipRect(const SkRect& rect, const SkMatrix& matrix, SkClipOp op, bool doAA) { if (matrix.rectStaysRect()) { SkRect devRect; matrix.mapRect(&devRect, rect); + if (this->hasClipRestriction(op)) { + if (!devRect.intersect(fClipRestrictionRect)) { + devRect.setEmpty(); + } + } Element element(fSaveCount, devRect, op, doAA); this->pushElement(element); return; @@ -756,19 +787,22 @@ void SkClipStack::clipRect(const SkRect& rect, const SkMatrix& matrix, SkCanvas: this->clipPath(path, matrix, op, doAA); } -void SkClipStack::clipPath(const SkPath& path, const SkMatrix& matrix, SkCanvas::ClipOp op, +void SkClipStack::clipPath(const SkPath& path, const SkMatrix& matrix, SkClipOp op, bool doAA) { SkPath devPath; path.transform(matrix, &devPath); - Element element(fSaveCount, devPath, op, doAA); this->pushElement(element); + if (this->hasClipRestriction(op)) { + Element element(fSaveCount, fClipRestrictionRect, kIntersect_SkClipOp, false); + this->pushElement(element); + } } void SkClipStack::clipEmpty() { Element* element = (Element*) fDeque.back(); - if (element && element->canBeIntersectedInPlace(fSaveCount, SkCanvas::kIntersect_Op)) { + if (element && element->canBeIntersectedInPlace(fSaveCount, kIntersect_SkClipOp)) { element->setEmpty(); } new (fDeque.push_back()) Element(fSaveCount); @@ -794,7 +828,7 @@ const SkClipStack::Element* SkClipStack::Iter::prev() { return (const SkClipStack::Element*)fIter.prev(); } -const SkClipStack::Element* SkClipStack::Iter::skipToTopmost(SkCanvas::ClipOp op) { +const SkClipStack::Element* SkClipStack::Iter::skipToTopmost(SkClipOp op) { if (nullptr == fStack) { return nullptr; @@ -879,13 +913,13 @@ bool SkClipStack::isRRect(const SkRect& bounds, SkRRect* rrect, bool* aa) const back->getType() != SkClipStack::Element::kRRect_Type) { return false; } - if (back->getOp() == SkCanvas::kReplace_Op) { + if (back->getOp() == kReplace_SkClipOp) { *rrect = back->asRRect(); *aa = back->isAA(); return true; } - if (back->getOp() == SkCanvas::kIntersect_Op) { + if (back->getOp() == kIntersect_SkClipOp) { SkRect backBounds; if (!backBounds.intersect(bounds, back->asRRect().rect())) { return false; @@ -894,12 +928,12 @@ bool SkClipStack::isRRect(const SkRect& bounds, SkRRect* rrect, bool* aa) const SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart); SkAssertResult(static_cast(iter.prev()) == back); while (const Element* prior = (const Element*)iter.prev()) { - if ((prior->getOp() != SkCanvas::kIntersect_Op && - prior->getOp() != SkCanvas::kReplace_Op) || + if ((prior->getOp() != kIntersect_SkClipOp && + prior->getOp() != kReplace_SkClipOp) || !prior->contains(backBounds)) { return false; } - if (prior->getOp() == SkCanvas::kReplace_Op) { + if (prior->getOp() == kReplace_SkClipOp) { break; } } @@ -951,16 +985,16 @@ void SkClipStack::Element::dump() const { "reverse-difference", "replace", }; - static_assert(0 == SkCanvas::kDifference_Op, "op_str"); - static_assert(1 == SkCanvas::kIntersect_Op, "op_str"); - static_assert(2 == SkCanvas::kUnion_Op, "op_str"); - static_assert(3 == SkCanvas::kXOR_Op, "op_str"); - static_assert(4 == SkCanvas::kReverseDifference_Op, "op_str"); - static_assert(5 == SkCanvas::kReplace_Op, "op_str"); + static_assert(0 == static_cast(kDifference_SkClipOp), "op_str"); + static_assert(1 == static_cast(kIntersect_SkClipOp), "op_str"); + static_assert(2 == static_cast(kUnion_SkClipOp), "op_str"); + static_assert(3 == static_cast(kXOR_SkClipOp), "op_str"); + static_assert(4 == static_cast(kReverseDifference_SkClipOp), "op_str"); + static_assert(5 == static_cast(kReplace_SkClipOp), "op_str"); static_assert(SK_ARRAY_COUNT(kOpStrings) == SkRegion::kOpCnt, "op_str"); SkDebugf("Type: %s, Op: %s, AA: %s, Save Count: %d\n", kTypeStrings[fType], - kOpStrings[fOp], (fDoAA ? "yes" : "no"), fSaveCount); + kOpStrings[static_cast(fOp)], (fDoAA ? "yes" : "no"), fSaveCount); switch (fType) { case kEmpty_Type: SkDebugf("\n"); diff --git a/gfx/skia/skia/include/core/SkClipStack.h b/gfx/skia/skia/src/core/SkClipStack.h similarity index 83% rename from gfx/skia/skia/include/core/SkClipStack.h rename to gfx/skia/skia/src/core/SkClipStack.h index 7a8eb5ca846d..bd197e35fa5d 100644 --- a/gfx/skia/skia/include/core/SkClipStack.h +++ b/gfx/skia/skia/src/core/SkClipStack.h @@ -8,15 +8,22 @@ #ifndef SkClipStack_DEFINED #define SkClipStack_DEFINED +#include "../private/SkMessageBus.h" #include "SkCanvas.h" #include "SkDeque.h" #include "SkPath.h" -#include "SkRect.h" #include "SkRRect.h" +#include "SkRect.h" #include "SkRegion.h" #include "SkTLazy.h" +#if SK_SUPPORT_GPU +#include "GrResourceKey.h" +#endif + +#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP class SkCanvasClipVisitor; +#endif // Because a single save/restore state can have multiple clips, this class // stores the stack depth (fSaveCount) and clips (fDeque) separately. @@ -24,7 +31,7 @@ class SkCanvasClipVisitor; // (i.e., the fSaveCount in force when it was added). Restores are thus // implemented by removing clips from fDeque that have an fSaveCount larger // then the freshly decremented count. -class SK_API SkClipStack : public SkNVRefCnt { +class SkClipStack { public: enum BoundsType { // The bounding box contains all the pixels that can be written to @@ -54,24 +61,32 @@ public: static const int kTypeCnt = kLastType + 1; Element() { - this->initCommon(0, SkCanvas::kReplace_Op, false); + this->initCommon(0, SkClipOp::kReplace_deprecated, false); this->setEmpty(); } Element(const Element&); - Element(const SkRect& rect, SkCanvas::ClipOp op, bool doAA) { + Element(const SkRect& rect, SkClipOp op, bool doAA) { this->initRect(0, rect, op, doAA); } - Element(const SkRRect& rrect, SkCanvas::ClipOp op, bool doAA) { + Element(const SkRRect& rrect, SkClipOp op, bool doAA) { this->initRRect(0, rrect, op, doAA); } - Element(const SkPath& path, SkCanvas::ClipOp op, bool doAA) { + Element(const SkPath& path, SkClipOp op, bool doAA) { this->initPath(0, path, op, doAA); } + ~Element() { +#if SK_SUPPORT_GPU + for (int i = 0; i < fMessages.count(); ++i) { + SkMessageBus::Post(*fMessages[i]); + } +#endif + } + bool operator== (const Element& element) const; bool operator!= (const Element& element) const { return !(*this == element); } @@ -94,7 +109,7 @@ public: } //!< Call if getType() is not kEmpty to get the set operation used to combine this element. - SkCanvas::ClipOp getOp() const { return fOp; } + SkClipOp getOp() const { return fOp; } //!< Call to get the element as a path, regardless of its type. void asPath(SkPath* path) const; @@ -110,7 +125,7 @@ public: void invertShapeFillType(); //!< Sets the set operation represented by the element. - void setOp(SkCanvas::ClipOp op) { fOp = op; } + void setOp(SkClipOp op) { fOp = op; } /** The GenID can be used by clip stack clients to cache representations of the clip. The ID corresponds to the set of clip elements up to and including this element within the @@ -183,10 +198,12 @@ public: return kPath_Type == fType && fPath.get()->isInverseFillType(); } +#ifdef SK_SUPPORT_OBSOLETE_REPLAYCLIP /** * Replay this clip into the visitor. */ void replay(SkCanvasClipVisitor*) const; +#endif #ifdef SK_DEBUG /** @@ -196,15 +213,26 @@ public: void dump() const; #endif +#if SK_SUPPORT_GPU + /** + * This is used to purge any GPU resource cache items that become unreachable when + * the element is destroyed because their key is based on this element's gen ID. + */ + void addResourceInvalidationMessage( + std::unique_ptr msg) const { + fMessages.emplace_back(std::move(msg)); + } +#endif + private: friend class SkClipStack; SkTLazy fPath; - SkRRect fRRect; - int fSaveCount; // save count of stack when this element was added. - SkCanvas::ClipOp fOp; - Type fType; - bool fDoAA; + SkRRect fRRect; + int fSaveCount; // save count of stack when this element was added. + SkClipOp fOp; + Type fType; + bool fDoAA; /* fFiniteBoundType and fFiniteBound are used to incrementally update the clip stack's bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound represents the @@ -217,32 +245,34 @@ public: can capture the cancelling out of the extensions to infinity when two inverse filled clips are Booleaned together. */ SkClipStack::BoundsType fFiniteBoundType; - SkRect fFiniteBound; + SkRect fFiniteBound; // When element is applied to the previous elements in the stack is the result known to be // equivalent to a single rect intersection? IIOW, is the clip effectively a rectangle. - bool fIsIntersectionOfRects; - - int fGenID; + bool fIsIntersectionOfRects; + int fGenID; +#if SK_SUPPORT_GPU + mutable SkTArray> fMessages; +#endif Element(int saveCount) { - this->initCommon(saveCount, SkCanvas::kReplace_Op, false); + this->initCommon(saveCount, SkClipOp::kReplace_deprecated, false); this->setEmpty(); } - Element(int saveCount, const SkRRect& rrect, SkCanvas::ClipOp op, bool doAA) { + Element(int saveCount, const SkRRect& rrect, SkClipOp op, bool doAA) { this->initRRect(saveCount, rrect, op, doAA); } - Element(int saveCount, const SkRect& rect, SkCanvas::ClipOp op, bool doAA) { + Element(int saveCount, const SkRect& rect, SkClipOp op, bool doAA) { this->initRect(saveCount, rect, op, doAA); } - Element(int saveCount, const SkPath& path, SkCanvas::ClipOp op, bool doAA) { + Element(int saveCount, const SkPath& path, SkClipOp op, bool doAA) { this->initPath(saveCount, path, op, doAA); } - void initCommon(int saveCount, SkCanvas::ClipOp op, bool doAA) { + void initCommon(int saveCount, SkClipOp op, bool doAA) { fSaveCount = saveCount; fOp = op; fDoAA = doAA; @@ -254,13 +284,13 @@ public: fGenID = kInvalidGenID; } - void initRect(int saveCount, const SkRect& rect, SkCanvas::ClipOp op, bool doAA) { + void initRect(int saveCount, const SkRect& rect, SkClipOp op, bool doAA) { fRRect.setRect(rect); fType = kRect_Type; this->initCommon(saveCount, op, doAA); } - void initRRect(int saveCount, const SkRRect& rrect, SkCanvas::ClipOp op, bool doAA) { + void initRRect(int saveCount, const SkRRect& rrect, SkClipOp op, bool doAA) { SkRRect::Type type = rrect.getType(); fRRect = rrect; if (SkRRect::kRect_Type == type || SkRRect::kEmpty_Type == type) { @@ -271,13 +301,13 @@ public: this->initCommon(saveCount, op, doAA); } - void initPath(int saveCount, const SkPath& path, SkCanvas::ClipOp op, bool doAA); + void initPath(int saveCount, const SkPath& path, SkClipOp op, bool doAA); void setEmpty(); // All Element methods below are only used within SkClipStack.cpp inline void checkEmpty() const; - inline bool canBeIntersectedInPlace(int saveCount, SkCanvas::ClipOp op) const; + inline bool canBeIntersectedInPlace(int saveCount, SkClipOp op) const; /* This method checks to see if two rect clips can be safely merged into one. The issue here is that to be strictly correct all the edges of the resulting rect must have the same anti-aliasing. */ @@ -301,6 +331,7 @@ public: }; SkClipStack(); + SkClipStack(void* storage, size_t size); SkClipStack(const SkClipStack& b); ~SkClipStack(); @@ -314,6 +345,27 @@ public: void save(); void restore(); + class AutoRestore { + public: + AutoRestore(SkClipStack* cs, bool doSave) + : fCS(cs), fSaveCount(cs->getSaveCount()) + { + if (doSave) { + fCS->save(); + } + } + ~AutoRestore() { + SkASSERT(fCS->getSaveCount() >= fSaveCount); // no underflow + while (fCS->getSaveCount() > fSaveCount) { + fCS->restore(); + } + } + + private: + SkClipStack* fCS; + const int fSaveCount; + }; + /** * getBounds places the current finite bound in its first parameter. In its * second, it indicates which kind of bound is being returned. If @@ -327,6 +379,9 @@ public: BoundsType* boundType, bool* isIntersectionOfRects = NULL) const; + SkRect bounds(const SkIRect& deviceBounds) const; + bool isEmpty(const SkIRect& deviceBounds) const; + /** * Returns true if the input (r)rect in device space is entirely contained * by the clip. A return value of false does not guarantee that the (r)rect @@ -346,16 +401,19 @@ public: */ bool asPath(SkPath* path) const; - void clipDevRect(const SkIRect& ir, SkCanvas::ClipOp op) { + void clipDevRect(const SkIRect& ir, SkClipOp op) { SkRect r; r.set(ir); this->clipRect(r, SkMatrix::I(), op, false); } - void clipRect(const SkRect&, const SkMatrix& matrix, SkCanvas::ClipOp, bool doAA); - void clipRRect(const SkRRect&, const SkMatrix& matrix, SkCanvas::ClipOp, bool doAA); - void clipPath(const SkPath&, const SkMatrix& matrix, SkCanvas::ClipOp, bool doAA); + void clipRect(const SkRect&, const SkMatrix& matrix, SkClipOp, bool doAA); + void clipRRect(const SkRRect&, const SkMatrix& matrix, SkClipOp, bool doAA); + void clipPath(const SkPath&, const SkMatrix& matrix, SkClipOp, bool doAA); // An optimized version of clipDevRect(emptyRect, kIntersect, ...) void clipEmpty(); + void setDeviceClipRestriction(const SkIRect& rect) { + fClipRestrictionRect = SkRect::Make(rect); + } /** * isWideOpen returns true if the clip state corresponds to the infinite @@ -424,7 +482,7 @@ public: * Moves the iterator to the topmost element with the specified RegionOp and returns that * element. If no clip element with that op is found, the first element is returned. */ - const Element* skipToTopmost(SkCanvas::ClipOp op); + const Element* skipToTopmost(SkClipOp op); /** * Restarts the iterator on a clip stack. @@ -497,6 +555,7 @@ private: // clipDevRect and clipDevPath call. 0 is reserved to indicate an // invalid ID. static int32_t gGenID; + SkRect fClipRestrictionRect = SkRect::MakeEmpty(); bool internalQuickContains(const SkRect& devRect) const; bool internalQuickContains(const SkRRect& devRRect) const; @@ -511,6 +570,10 @@ private: */ void restoreTo(int saveCount); + inline bool hasClipRestriction(SkClipOp op) { + return op >= SkClipOp::kUnion_deprecated && !fClipRestrictionRect.isEmpty(); + } + /** * Return the next unique generation ID. */ diff --git a/gfx/skia/skia/src/core/SkClipStackDevice.cpp b/gfx/skia/skia/src/core/SkClipStackDevice.cpp new file mode 100644 index 000000000000..dd5118d319c0 --- /dev/null +++ b/gfx/skia/skia/src/core/SkClipStackDevice.cpp @@ -0,0 +1,108 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkClipStackDevice.h" +#include "SkDraw.h" +#include "SkRasterClip.h" + +SkIRect SkClipStackDevice::devClipBounds() const { + SkIRect r = fClipStack.bounds(this->imageInfo().bounds()).roundOut(); + if (!r.isEmpty()) { + SkASSERT(this->imageInfo().bounds().contains(r)); + } + return r; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void SkClipStackDevice::onSave() { + fClipStack.save(); +} + +void SkClipStackDevice::onRestore() { + fClipStack.restore(); +} + +void SkClipStackDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) { + fClipStack.clipRect(rect, this->ctm(), op, aa); +} + +void SkClipStackDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) { + fClipStack.clipRRect(rrect, this->ctm(), op, aa); +} + +void SkClipStackDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) { + fClipStack.clipPath(path, this->ctm(), op, aa); +} + +void SkClipStackDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) { + SkIPoint origin = this->getOrigin(); + SkRegion tmp; + const SkRegion* ptr = &rgn; + if (origin.fX | origin.fY) { + // translate from "global/canvas" coordinates to relative to this device + rgn.translate(-origin.fX, -origin.fY, &tmp); + ptr = &tmp; + } + fClipStack.clipDevRect(ptr->getBounds(), op); +} + +void SkClipStackDevice::onSetDeviceClipRestriction(SkIRect* clipRestriction) { + if (clipRestriction->isEmpty()) { + fClipStack.setDeviceClipRestriction(*clipRestriction); + } else { + SkIPoint origin = this->getOrigin(); + SkIRect rect = clipRestriction->makeOffset(-origin.x(), -origin.y()); + fClipStack.setDeviceClipRestriction(rect); + fClipStack.clipDevRect(rect, SkClipOp::kIntersect); + } +} + +bool SkClipStackDevice::onClipIsAA() const { + SkClipStack::B2TIter iter(fClipStack); + const SkClipStack::Element* element; + + while ((element = iter.next()) != nullptr) { + if (element->isAA()) { + return true; + } + } + return false; +} + +void SkClipStackDevice::onAsRgnClip(SkRegion* rgn) const { + SkClipStack::BoundsType boundType; + bool isIntersectionOfRects; + SkRect bounds; + fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects); + if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) { + rgn->setRect(bounds.round()); + } else { + SkPath path; + fClipStack.asPath(&path); + rgn->setPath(path, SkRegion(SkIRect::MakeWH(this->width(), this->height()))); + } +} + +SkBaseDevice::ClipType SkClipStackDevice::onGetClipType() const { + if (fClipStack.isWideOpen()) { + return kRect_ClipType; + } + if (fClipStack.isEmpty(SkIRect::MakeWH(this->width(), this->height()))) { + return kEmpty_ClipType; + } else { + SkClipStack::BoundsType boundType; + bool isIntersectionOfRects; + SkRect bounds; + fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects); + if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) { + return kRect_ClipType; + } else { + return kComplex_ClipType; + } + } +} diff --git a/gfx/skia/skia/src/core/SkClipStackDevice.h b/gfx/skia/skia/src/core/SkClipStackDevice.h new file mode 100644 index 000000000000..de0f6297d430 --- /dev/null +++ b/gfx/skia/skia/src/core/SkClipStackDevice.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkClipStackDevice_DEFINED +#define SkClipStackDevice_DEFINED + +#include "SkClipStack.h" +#include "SkDevice.h" + +class SK_API SkClipStackDevice : public SkBaseDevice { +public: + SkClipStackDevice(const SkImageInfo& info, const SkSurfaceProps& props) + : SkBaseDevice(info, props) + , fClipStack(fStorage, sizeof(fStorage)) + {} + + SkClipStack& cs() { return fClipStack; } + const SkClipStack& cs() const { return fClipStack; } + + SkIRect devClipBounds() const; + +protected: + void onSave() override; + void onRestore() override; + void onClipRect(const SkRect& rect, SkClipOp, bool aa) override; + void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override; + void onClipPath(const SkPath& path, SkClipOp, bool aa) override; + void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override; + void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override; + bool onClipIsAA() const override; + void onAsRgnClip(SkRegion*) const override; + ClipType onGetClipType() const override; + +private: + enum { + kPreallocCount = 16 // empirically determined, adjust as needed to reduce mallocs + }; + intptr_t fStorage[kPreallocCount * sizeof(SkClipStack::Element) / sizeof(intptr_t)]; + SkClipStack fClipStack; + + typedef SkBaseDevice INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkColor.cpp b/gfx/skia/skia/src/core/SkColor.cpp index 6dacc063e0be..bee114b1e836 100644 --- a/gfx/skia/skia/src/core/SkColor.cpp +++ b/gfx/skia/skia/src/core/SkColor.cpp @@ -73,30 +73,32 @@ void SkRGBToHSV(U8CPU r, U8CPU g, U8CPU b, SkScalar hsv[3]) { SkColor SkHSVToColor(U8CPU a, const SkScalar hsv[3]) { SkASSERT(hsv); - U8CPU s = SkUnitScalarClampToByte(hsv[1]); - U8CPU v = SkUnitScalarClampToByte(hsv[2]); + SkScalar s = SkScalarPin(hsv[1], 0, 1); + SkScalar v = SkScalarPin(hsv[2], 0, 1); - if (0 == s) { // shade of gray - return SkColorSetARGB(a, v, v, v); + U8CPU v_byte = SkScalarRoundToInt(v * 255); + + if (SkScalarNearlyZero(s)) { // shade of gray + return SkColorSetARGB(a, v_byte, v_byte, v_byte); } - SkFixed hx = (hsv[0] < 0 || hsv[0] >= SkIntToScalar(360)) ? 0 : SkScalarToFixed(hsv[0]/60); - SkFixed f = hx & 0xFFFF; + SkScalar hx = (hsv[0] < 0 || hsv[0] >= SkIntToScalar(360)) ? 0 : hsv[0]/60; + SkScalar w = SkScalarFloorToScalar(hx); + SkScalar f = hx - w; - unsigned v_scale = SkAlpha255To256(v); - unsigned p = SkAlphaMul(255 - s, v_scale); - unsigned q = SkAlphaMul(255 - (s * f >> 16), v_scale); - unsigned t = SkAlphaMul(255 - (s * (SK_Fixed1 - f) >> 16), v_scale); + unsigned p = SkScalarRoundToInt((SK_Scalar1 - s) * v * 255); + unsigned q = SkScalarRoundToInt((SK_Scalar1 - (s * f)) * v * 255); + unsigned t = SkScalarRoundToInt((SK_Scalar1 - (s * (SK_Scalar1 - f))) * v * 255); unsigned r, g, b; - SkASSERT((unsigned)(hx >> 16) < 6); - switch (hx >> 16) { - case 0: r = v; g = t; b = p; break; - case 1: r = q; g = v; b = p; break; - case 2: r = p; g = v; b = t; break; - case 3: r = p; g = q; b = v; break; - case 4: r = t; g = p; b = v; break; - default: r = v; g = p; b = q; break; + SkASSERT((unsigned)(w) < 6); + switch ((unsigned)(w)) { + case 0: r = v_byte; g = t; b = p; break; + case 1: r = q; g = v_byte; b = p; break; + case 2: r = p; g = v_byte; b = t; break; + case 3: r = p; g = q; b = v_byte; break; + case 4: r = t; g = p; b = v_byte; break; + default: r = v_byte; g = p; b = q; break; } return SkColorSetARGB(a, r, g, b); } diff --git a/gfx/skia/skia/src/core/SkColorFilter.cpp b/gfx/skia/skia/src/core/SkColorFilter.cpp index 31c0ddb06b27..8f660e99f0bd 100644 --- a/gfx/skia/skia/src/core/SkColorFilter.cpp +++ b/gfx/skia/skia/src/core/SkColorFilter.cpp @@ -6,6 +6,7 @@ */ #include "SkColorFilter.h" +#include "SkArenaAlloc.h" #include "SkReadBuffer.h" #include "SkRefCnt.h" #include "SkString.h" @@ -19,7 +20,7 @@ #include "GrFragmentProcessor.h" #endif -bool SkColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) const { +bool SkColorFilter::asColorMode(SkColor*, SkBlendMode*) const { return false; } @@ -32,16 +33,19 @@ bool SkColorFilter::asComponentTable(SkBitmap*) const { } #if SK_SUPPORT_GPU -sk_sp SkColorFilter::asFragmentProcessor(GrContext*) const { +sk_sp SkColorFilter::asFragmentProcessor(GrContext*, SkColorSpace*) const { return nullptr; } #endif -bool SkColorFilter::appendStages(SkRasterPipeline* pipeline) const { - return this->onAppendStages(pipeline); +bool SkColorFilter::appendStages(SkRasterPipeline* pipeline, + SkColorSpace* dst, + SkArenaAlloc* scratch, + bool shaderIsOpaque) const { + return this->onAppendStages(pipeline, dst, scratch, shaderIsOpaque); } -bool SkColorFilter::onAppendStages(SkRasterPipeline*) const { +bool SkColorFilter::onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, bool) const { return false; } @@ -109,14 +113,17 @@ public: SkString outerS, innerS; fOuter->toString(&outerS); fInner->toString(&innerS); - str->appendf("SkComposeColorFilter: outer(%s) inner(%s)", outerS.c_str(), innerS.c_str()); + // These strings can be long. SkString::appendf has limitations. + str->append(SkStringPrintf("SkComposeColorFilter: outer(%s) inner(%s)", outerS.c_str(), + innerS.c_str())); } #endif #if SK_SUPPORT_GPU - sk_sp asFragmentProcessor(GrContext* context) const override { - sk_sp innerFP(fInner->asFragmentProcessor(context)); - sk_sp outerFP(fOuter->asFragmentProcessor(context)); + sk_sp asFragmentProcessor(GrContext* context, + SkColorSpace* dstColorSpace) const override { + sk_sp innerFP(fInner->asFragmentProcessor(context, dstColorSpace)); + sk_sp outerFP(fOuter->asFragmentProcessor(context, dstColorSpace)); if (!innerFP || !outerFP) { return nullptr; } diff --git a/gfx/skia/skia/src/core/SkColorFilterShader.cpp b/gfx/skia/skia/src/core/SkColorFilterShader.cpp index 8bf82b8b182b..5e96b24b4115 100644 --- a/gfx/skia/skia/src/core/SkColorFilterShader.cpp +++ b/gfx/skia/skia/src/core/SkColorFilterShader.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkColorFilterShader.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" @@ -52,19 +53,15 @@ uint32_t SkColorFilterShader::FilterShaderContext::getFlags() const { return shaderF; } -SkShader::Context* SkColorFilterShader::onCreateContext(const ContextRec& rec, - void* storage) const { - char* shaderContextStorage = (char*)storage + sizeof(FilterShaderContext); - SkShader::Context* shaderContext = fShader->createContext(rec, shaderContextStorage); +SkShader::Context* SkColorFilterShader::onMakeContext(const ContextRec& rec, + SkArenaAlloc* alloc) const { + SkShader::Context* shaderContext = fShader->makeContext(rec, alloc); if (nullptr == shaderContext) { return nullptr; } - return new (storage) FilterShaderContext(*this, shaderContext, rec); + return alloc->make(*this, shaderContext, rec); } -size_t SkColorFilterShader::onContextSize(const ContextRec& rec) const { - return sizeof(FilterShaderContext) + fShader->contextSize(rec); -} SkColorFilterShader::FilterShaderContext::FilterShaderContext( const SkColorFilterShader& filterShader, @@ -74,10 +71,6 @@ SkColorFilterShader::FilterShaderContext::FilterShaderContext( , fShaderContext(shaderContext) {} -SkColorFilterShader::FilterShaderContext::~FilterShaderContext() { - fShaderContext->~Context(); -} - void SkColorFilterShader::FilterShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { const SkColorFilterShader& filterShader = static_cast(fShader); @@ -104,7 +97,8 @@ sk_sp SkColorFilterShader::asFragmentProcessor(const AsFPAr return nullptr; } - sk_sp fp2(fFilter->asFragmentProcessor(args.fContext)); + sk_sp fp2(fFilter->asFragmentProcessor(args.fContext, + args.fDstColorSpace)); if (!fp2) { return fp1; } diff --git a/gfx/skia/skia/src/core/SkColorFilterShader.h b/gfx/skia/skia/src/core/SkColorFilterShader.h index 035acd839773..e697736ae842 100644 --- a/gfx/skia/skia/src/core/SkColorFilterShader.h +++ b/gfx/skia/skia/src/core/SkColorFilterShader.h @@ -11,6 +11,8 @@ #include "SkColorFilter.h" #include "SkShader.h" +class SkArenaAlloc; + class SkColorFilterShader : public SkShader { public: SkColorFilterShader(sk_sp shader, sk_sp filter); @@ -23,7 +25,6 @@ public: public: // Takes ownership of shaderContext and calls its destructor. FilterShaderContext(const SkColorFilterShader&, SkShader::Context*, const ContextRec&); - virtual ~FilterShaderContext(); uint32_t getFlags() const override; @@ -46,8 +47,7 @@ public: protected: void flatten(SkWriteBuffer&) const override; - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec&, void* storage) const override; + Context* onMakeContext(const ContextRec&, SkArenaAlloc* alloc) const override; private: sk_sp fShader; diff --git a/gfx/skia/skia/src/core/SkColorLookUpTable.cpp b/gfx/skia/skia/src/core/SkColorLookUpTable.cpp new file mode 100644 index 000000000000..b8bb34612341 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorLookUpTable.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorLookUpTable.h" +#include "SkColorSpaceXformPriv.h" +#include "SkFloatingPoint.h" + +void SkColorLookUpTable::interp(float* dst, const float* src) const { + if (fInputChannels == 3) { + interp3D(dst, src); + } else { + SkASSERT(dst != src); + // index gets initialized as the algorithm proceeds by interpDimension. + // It's just there to store the choice of low/high so far. + int index[kMaxColorChannels]; + for (uint8_t outputDimension = 0; outputDimension < kOutputChannels; ++outputDimension) { + dst[outputDimension] = interpDimension(src, fInputChannels - 1, outputDimension, + index); + } + } +} + +void SkColorLookUpTable::interp3D(float* dst, const float* src) const { + SkASSERT(3 == kOutputChannels); + // Call the src components x, y, and z. + const uint8_t maxX = fGridPoints[0] - 1; + const uint8_t maxY = fGridPoints[1] - 1; + const uint8_t maxZ = fGridPoints[2] - 1; + + // An approximate index into each of the three dimensions of the table. + const float x = src[0] * maxX; + const float y = src[1] * maxY; + const float z = src[2] * maxZ; + + // This gives us the low index for our interpolation. + int ix = sk_float_floor2int(x); + int iy = sk_float_floor2int(y); + int iz = sk_float_floor2int(z); + + // Make sure the low index is not also the max index. + ix = (maxX == ix) ? ix - 1 : ix; + iy = (maxY == iy) ? iy - 1 : iy; + iz = (maxZ == iz) ? iz - 1 : iz; + + // Weighting factors for the interpolation. + const float diffX = x - ix; + const float diffY = y - iy; + const float diffZ = z - iz; + + // Constants to help us navigate the 3D table. + // Ex: Assume x = a, y = b, z = c. + // table[a * n001 + b * n010 + c * n100] logically equals table[a][b][c]. + const int n000 = 0; + const int n001 = 3 * fGridPoints[1] * fGridPoints[2]; + const int n010 = 3 * fGridPoints[2]; + const int n011 = n001 + n010; + const int n100 = 3; + const int n101 = n100 + n001; + const int n110 = n100 + n010; + const int n111 = n110 + n001; + + // Base ptr into the table. + const float* ptr = &(table()[ix*n001 + iy*n010 + iz*n100]); + + // The code below performs a tetrahedral interpolation for each of the three + // dst components. Once the tetrahedron containing the interpolation point is + // identified, the interpolation is a weighted sum of grid values at the + // vertices of the tetrahedron. The claim is that tetrahedral interpolation + // provides a more accurate color conversion. + // blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colorspace-conversion/ + // + // I have one test image, and visually I can't tell the difference between + // tetrahedral and trilinear interpolation. In terms of computation, the + // tetrahedral code requires more branches but less computation. The + // SampleICC library provides an option for the client to choose either + // tetrahedral or trilinear. + for (int i = 0; i < 3; i++) { + if (diffZ < diffY) { + if (diffZ > diffX) { + dst[i] = (ptr[n000] + diffZ * (ptr[n110] - ptr[n010]) + + diffY * (ptr[n010] - ptr[n000]) + + diffX * (ptr[n111] - ptr[n110])); + } else if (diffY < diffX) { + dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + + diffY * (ptr[n011] - ptr[n001]) + + diffX * (ptr[n001] - ptr[n000])); + } else { + dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + + diffY * (ptr[n010] - ptr[n000]) + + diffX * (ptr[n011] - ptr[n010])); + } + } else { + if (diffZ < diffX) { + dst[i] = (ptr[n000] + diffZ * (ptr[n101] - ptr[n001]) + + diffY * (ptr[n111] - ptr[n101]) + + diffX * (ptr[n001] - ptr[n000])); + } else if (diffY < diffX) { + dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + + diffY * (ptr[n111] - ptr[n101]) + + diffX * (ptr[n101] - ptr[n100])); + } else { + dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + + diffY * (ptr[n110] - ptr[n100]) + + diffX * (ptr[n111] - ptr[n110])); + } + } + + // |src| is guaranteed to be in the 0-1 range as are all entries + // in the table. For "increasing" tables, outputs will also be + // in the 0-1 range. While this property is logical for color + // look up tables, we don't check for it. + // And for arbitrary, non-increasing tables, it is easy to see how + // the output might not be 0-1. So we clamp here. + dst[i] = clamp_0_1(dst[i]); + + // Increment the table ptr in order to handle the next component. + // Note that this is the how table is designed: all of nXXX + // variables are multiples of 3 because there are 3 output + // components. + ptr++; + } +} + +float SkColorLookUpTable::interpDimension(const float* src, int inputDimension, + int outputDimension, + int index[kMaxColorChannels]) const { + // Base case. We've already decided whether to use the low or high point for each dimension + // which is stored inside of index[] where index[i] gives the point in the CLUT to use for + // input dimension i. + if (inputDimension < 0) { + // compute index into CLUT and look up the colour + int outputIndex = outputDimension; + int indexMultiplier = kOutputChannels; + for (int i = fInputChannels - 1; i >= 0; --i) { + outputIndex += index[i] * indexMultiplier; + indexMultiplier *= fGridPoints[i]; + } + return table()[outputIndex]; + } + // for each dimension (input channel), try both the low and high point for it + // and then do the same recursively for the later dimensions. + // Finally, we need to LERP the results. ie LERP X then LERP Y then LERP Z. + const float x = src[inputDimension] * (fGridPoints[inputDimension] - 1); + // try the low point for this dimension + index[inputDimension] = sk_float_floor2int(x); + const float diff = x - index[inputDimension]; + // and recursively LERP all sub-dimensions with the current dimension fixed to the low point + const float lo = interpDimension(src, inputDimension - 1, outputDimension, index); + // now try the high point for this dimension + index[inputDimension] = sk_float_ceil2int(x); + // and recursively LERP all sub-dimensions with the current dimension fixed to the high point + const float hi = interpDimension(src, inputDimension - 1, outputDimension, index); + // then LERP the results based on the current dimension + return clamp_0_1((1 - diff) * lo + diff * hi); +} diff --git a/gfx/skia/skia/src/core/SkColorLookUpTable.h b/gfx/skia/skia/src/core/SkColorLookUpTable.h new file mode 100644 index 000000000000..0cde767a4715 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorLookUpTable.h @@ -0,0 +1,71 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorLookUpTable_DEFINED +#define SkColorLookUpTable_DEFINED + +#include "SkRefCnt.h" +#include "SkTemplates.h" + +static constexpr uint8_t kMaxColorChannels = 4; + +class SkColorLookUpTable : public SkRefCnt { +public: + static constexpr uint8_t kOutputChannels = 3; + + SkColorLookUpTable(uint8_t inputChannels, const uint8_t gridPoints[kMaxColorChannels]) + : fInputChannels(inputChannels) { + SkASSERT(inputChannels >= 1 && inputChannels <= kMaxColorChannels); + memcpy(fGridPoints, gridPoints, fInputChannels * sizeof(uint8_t)); + } + + /** + * If fInputChannels == kOutputChannels == 3, performs tetrahedral interpolation, otherwise + * performs multilinear interpolation (ie LERP for n =1, bilinear for n=2, trilinear for n=3) + * with fInputChannels input dimensions and kOutputChannels output dimensions. + * |dst| can be |src| only when fInputChannels == kOutputChannels == 3 + * |dst| is the destination pixel, must have at least kOutputChannels elements. + * |src| is the source pixel, must have at least fInputChannels elements. + */ + void interp(float* dst, const float* src) const; + + int inputChannels() const { return fInputChannels; } + + int outputChannels() const { return kOutputChannels; } + + int gridPoints(int dimension) const { + SkASSERT(dimension >= 0 && dimension < inputChannels()); + return fGridPoints[dimension]; + } + +private: + const float* table() const { + return SkTAddOffset(this, sizeof(SkColorLookUpTable)); + } + + /** + * Performs tetrahedral interpolation with 3 input and 3 output dimensions. + * |dst| can be |src| + */ + void interp3D(float* dst, const float* src) const; + + // recursively LERPs one dimension at a time. Used by interp() for the general case + float interpDimension(const float* src, int inputDimension, int outputDimension, + int index[kMaxColorChannels]) const; + + uint8_t fInputChannels; + uint8_t fGridPoints[kMaxColorChannels]; + +public: + // Objects of this type are created in a custom fashion using sk_malloc_throw + // and therefore must be sk_freed. + void* operator new(size_t size) = delete; + void* operator new(size_t, void* p) { return p; } + void operator delete(void* p) { sk_free(p); } +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.cpp b/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.cpp index 29a3f107b8f0..f3dc41f0fe72 100644 --- a/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.cpp +++ b/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.cpp @@ -9,28 +9,34 @@ #include "SkColorPriv.h" #include "SkNx.h" #include "SkPM4fPriv.h" +#include "SkRasterPipeline.h" #include "SkReadBuffer.h" #include "SkRefCnt.h" #include "SkString.h" #include "SkUnPreMultiply.h" #include "SkWriteBuffer.h" -static void transpose(float dst[20], const float src[20]) { +static void transpose_and_scale01(float dst[20], const float src[20]) { const float* srcR = src + 0; const float* srcG = src + 5; const float* srcB = src + 10; const float* srcA = src + 15; - for (int i = 0; i < 20; i += 4) { + for (int i = 0; i < 16; i += 4) { dst[i + 0] = *srcR++; dst[i + 1] = *srcG++; dst[i + 2] = *srcB++; dst[i + 3] = *srcA++; } + // Might as well scale these translates down to [0,1] here instead of every filter call. + dst[16] = *srcR * (1/255.0f); + dst[17] = *srcG * (1/255.0f); + dst[18] = *srcB * (1/255.0f); + dst[19] = *srcA * (1/255.0f); } void SkColorMatrixFilterRowMajor255::initState() { - transpose(fTranspose, fMatrix); + transpose_and_scale01(fTranspose, fMatrix); const float* array = fMatrix; @@ -81,13 +87,11 @@ static SkPMColor round(const Sk4f& x) { template void filter_span(const float array[], const T src[], int count, T dst[]) { - // c0-c3 are already in [0,1]. const Sk4f c0 = Sk4f::Load(array + 0); const Sk4f c1 = Sk4f::Load(array + 4); const Sk4f c2 = Sk4f::Load(array + 8); const Sk4f c3 = Sk4f::Load(array + 12); - // c4 (the translate vector) is in [0, 255]. Bring it back to [0,1]. - const Sk4f c4 = Sk4f::Load(array + 16)*Sk4f(1.0f/255); + const Sk4f c4 = Sk4f::Load(array + 16); // todo: we could cache this in the constructor... T matrix_translate_pmcolor = Adaptor::From4f(premul(clamp_0_1(c4))); @@ -227,6 +231,32 @@ static void set_concat(SkScalar result[20], const SkScalar outer[20], const SkSc // End duplication ////// +bool SkColorMatrixFilterRowMajor255::onAppendStages(SkRasterPipeline* p, + SkColorSpace* dst, + SkArenaAlloc* scratch, + bool shaderIsOpaque) const { + bool willStayOpaque = shaderIsOpaque && (fFlags & kAlphaUnchanged_Flag); + bool needsClamp0 = false, + needsClamp1 = false; + for (int i = 0; i < 4; i++) { + SkScalar min = fTranspose[i+16], + max = fTranspose[i+16]; + (fTranspose[i+ 0] < 0 ? min : max) += fTranspose[i+ 0]; + (fTranspose[i+ 4] < 0 ? min : max) += fTranspose[i+ 4]; + (fTranspose[i+ 8] < 0 ? min : max) += fTranspose[i+ 8]; + (fTranspose[i+12] < 0 ? min : max) += fTranspose[i+12]; + needsClamp0 = needsClamp0 || min < 0; + needsClamp1 = needsClamp1 || max > 1; + } + + if (!shaderIsOpaque) { p->append(SkRasterPipeline::unpremul); } + if ( true) { p->append(SkRasterPipeline::matrix_4x5, fTranspose); } + if (!willStayOpaque) { p->append(SkRasterPipeline::premul); } + if ( needsClamp0) { p->append(SkRasterPipeline::clamp_0); } + if ( needsClamp1) { p->append(SkRasterPipeline::clamp_a); } + return true; +} + sk_sp SkColorMatrixFilterRowMajor255::makeComposed(sk_sp innerFilter) const { SkScalar innerMatrix[20]; @@ -240,7 +270,6 @@ SkColorMatrixFilterRowMajor255::makeComposed(sk_sp innerFilter) c #if SK_SUPPORT_GPU #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" @@ -259,7 +288,7 @@ public: class GLSLProcessor : public GrGLSLFragmentProcessor { public: // this class always generates the same code. - static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) {} + static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {} void emitCode(EmitArgs& args) override { GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; @@ -291,7 +320,7 @@ public: protected: void onSetData(const GrGLSLProgramDataManager& uniManager, - const GrProcessor& proc) override { + const GrFragmentProcessor& proc) override { const ColorMatrixEffect& cme = proc.cast(); const float* m = cme.fMatrix; // The GL matrix is transposed from SkColorMatrix. @@ -315,9 +344,10 @@ public: typedef GrGLSLFragmentProcessor INHERITED; }; - private: - ColorMatrixEffect(const SkScalar matrix[20]) { + // We could implement the constant input->constant output optimization but haven't. Other + // optimizations would be matrix-dependent. + ColorMatrixEffect(const SkScalar matrix[20]) : INHERITED(kNone_OptimizationFlags) { memcpy(fMatrix, matrix, sizeof(SkScalar) * 20); this->initClassID(); } @@ -326,7 +356,7 @@ private: return new GLSLProcessor; } - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, + virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLProcessor::GenKey(*this, caps, b); } @@ -336,51 +366,6 @@ private: return 0 == memcmp(fMatrix, cme.fMatrix, sizeof(fMatrix)); } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - // We only bother to check whether the alpha channel will be constant. If SkColorMatrix had - // type flags it might be worth checking the other components. - - // The matrix is defined such the 4th row determines the output alpha. The first four - // columns of that row multiply the input r, g, b, and a, respectively, and the last column - // is the "translation". - static const uint32_t kRGBAFlags[] = { - kR_GrColorComponentFlag, - kG_GrColorComponentFlag, - kB_GrColorComponentFlag, - kA_GrColorComponentFlag - }; - static const int kShifts[] = { - GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A, - }; - enum { - kAlphaRowStartIdx = 15, - kAlphaRowTranslateIdx = 19, - }; - - SkScalar outputA = 0; - for (int i = 0; i < 4; ++i) { - // If any relevant component of the color to be passed through the matrix is non-const - // then we can't know the final result. - if (0 != fMatrix[kAlphaRowStartIdx + i]) { - if (!(inout->validFlags() & kRGBAFlags[i])) { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); - return; - } else { - uint32_t component = (inout->color() >> kShifts[i]) & 0xFF; - outputA += fMatrix[kAlphaRowStartIdx + i] * component; - } - } - } - outputA += fMatrix[kAlphaRowTranslateIdx]; - // We pin the color to [0,1]. This would happen to the *final* color output from the frag - // shader but currently the effect does not pin its own output. So in the case of over/ - // underflow this may deviate from the actual result. Maybe the effect should pin its - // result if the matrix could over/underflow for any component? - inout->setToOther(kA_GrColorComponentFlag, - static_cast(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A, - GrInvariantOutput::kWill_ReadInput); - } - SkScalar fMatrix[20]; typedef GrFragmentProcessor INHERITED; @@ -388,6 +373,7 @@ private: GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorMatrixEffect); +#if GR_TEST_UTILS sk_sp ColorMatrixEffect::TestCreate(GrProcessorTestData* d) { SkScalar colorMatrix[20]; for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix); ++i) { @@ -395,8 +381,10 @@ sk_sp ColorMatrixEffect::TestCreate(GrProcessorTestData* d) } return ColorMatrixEffect::Make(colorMatrix); } +#endif -sk_sp SkColorMatrixFilterRowMajor255::asFragmentProcessor(GrContext*) const { +sk_sp SkColorMatrixFilterRowMajor255::asFragmentProcessor( + GrContext*, SkColorSpace*) const { return ColorMatrixEffect::Make(fMatrix); } diff --git a/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.h b/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.h index c1158859f857..5c2d616ba0bd 100644 --- a/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.h +++ b/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.h @@ -25,7 +25,7 @@ public: sk_sp makeComposed(sk_sp) const override; #if SK_SUPPORT_GPU - sk_sp asFragmentProcessor(GrContext*) const override; + sk_sp asFragmentProcessor(GrContext*, SkColorSpace*) const override; #endif SK_TO_STRING_OVERRIDE() @@ -36,6 +36,9 @@ protected: void flatten(SkWriteBuffer&) const override; private: + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + bool shaderIsOpaque) const override; + SkScalar fMatrix[20]; float fTranspose[20]; // for Sk4s uint32_t fFlags; diff --git a/gfx/skia/skia/src/core/SkColorShader.cpp b/gfx/skia/skia/src/core/SkColorShader.cpp index cfa071fed8d4..5c8bde6ee1e9 100644 --- a/gfx/skia/skia/src/core/SkColorShader.cpp +++ b/gfx/skia/skia/src/core/SkColorShader.cpp @@ -5,8 +5,11 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkColorShader.h" #include "SkColorSpace.h" +#include "SkPM4fPriv.h" +#include "SkRasterPipeline.h" #include "SkReadBuffer.h" #include "SkUtils.h" @@ -28,8 +31,8 @@ uint32_t SkColorShader::ColorShaderContext::getFlags() const { return fFlags; } -SkShader::Context* SkColorShader::onCreateContext(const ContextRec& rec, void* storage) const { - return new (storage) ColorShaderContext(*this, rec); +SkShader::Context* SkColorShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const { + return alloc->make(*this, rec); } SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader, @@ -89,8 +92,8 @@ SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const { #include "SkGr.h" #include "effects/GrConstColorProcessor.h" -sk_sp SkColorShader::asFragmentProcessor(const AsFPArgs&) const { - GrColor color = SkColorToPremulGrColor(fColor); +sk_sp SkColorShader::asFragmentProcessor(const AsFPArgs& args) const { + GrColor4f color = SkColorToPremulGrColor4f(fColor, args.fDstColorSpace); return GrConstColorProcessor::Make(color, GrConstColorProcessor::kModulateA_InputMode); } @@ -146,8 +149,8 @@ uint32_t SkColor4Shader::Color4Context::getFlags() const { return fFlags; } -SkShader::Context* SkColor4Shader::onCreateContext(const ContextRec& rec, void* storage) const { - return new (storage) Color4Context(*this, rec); +SkShader::Context* SkColor4Shader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const { + return alloc->make(*this, rec); } SkColor4Shader::Color4Context::Color4Context(const SkColor4Shader& shader, @@ -208,10 +211,15 @@ SkShader::GradientType SkColor4Shader::asAGradient(GradientInfo* info) const { #include "SkGr.h" #include "effects/GrConstColorProcessor.h" -sk_sp SkColor4Shader::asFragmentProcessor(const AsFPArgs&) const { - // TODO: how to communicate color4f to Gr - GrColor color = SkColorToPremulGrColor(fCachedByteColor); - return GrConstColorProcessor::Make(color, GrConstColorProcessor::kModulateA_InputMode); +#include "GrColorSpaceXform.h" +sk_sp SkColor4Shader::asFragmentProcessor(const AsFPArgs& args) const { + sk_sp colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(), + args.fDstColorSpace); + GrColor4f color = GrColor4f::FromSkColor4f(fColor4); + if (colorSpaceXform) { + color = colorSpaceXform->apply(color); + } + return GrConstColorProcessor::Make(color.premul(), GrConstColorProcessor::kModulateA_InputMode); } #endif @@ -242,28 +250,28 @@ static void D32_BlitBW(SkShader::Context::BlitState* state, int x, int y, const int count) { SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0]; const SkPM4f* src = (const SkPM4f*)state->fStorage[1]; - proc(state->fXfer, dst.writable_addr32(x, y), src, count, nullptr); + proc(state->fMode, dst.writable_addr32(x, y), src, count, nullptr); } static void D32_BlitAA(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst, int count, const SkAlpha aa[]) { SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0]; const SkPM4f* src = (const SkPM4f*)state->fStorage[1]; - proc(state->fXfer, dst.writable_addr32(x, y), src, count, aa); + proc(state->fMode, dst.writable_addr32(x, y), src, count, aa); } static void F16_BlitBW(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst, int count) { SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0]; const SkPM4f* src = (const SkPM4f*)state->fStorage[1]; - proc(state->fXfer, dst.writable_addr64(x, y), src, count, nullptr); + proc(state->fMode, dst.writable_addr64(x, y), src, count, nullptr); } static void F16_BlitAA(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst, int count, const SkAlpha aa[]) { SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0]; const SkPM4f* src = (const SkPM4f*)state->fStorage[1]; - proc(state->fXfer, dst.writable_addr64(x, y), src, count, aa); + proc(state->fMode, dst.writable_addr64(x, y), src, count, aa); } static bool choose_blitprocs(const SkPM4f* pm4, const SkImageInfo& info, @@ -277,13 +285,13 @@ static bool choose_blitprocs(const SkPM4f* pm4, const SkImageInfo& info, if (info.gammaCloseToSRGB()) { flags |= SkXfermode::kDstIsSRGB_D32Flag; } - state->fStorage[0] = (void*)SkXfermode::GetD32Proc(state->fXfer, flags); + state->fStorage[0] = (void*)SkXfermode::GetD32Proc(state->fMode, flags); state->fStorage[1] = (void*)pm4; state->fBlitBW = D32_BlitBW; state->fBlitAA = D32_BlitAA; return true; case kRGBA_F16_SkColorType: - state->fStorage[0] = (void*)SkXfermode::GetF16Proc(state->fXfer, flags); + state->fStorage[0] = (void*)SkXfermode::GetF16Proc(state->fMode, flags); state->fStorage[1] = (void*)pm4; state->fBlitBW = F16_BlitBW; state->fBlitAA = F16_BlitAA; @@ -301,3 +309,26 @@ bool SkColorShader::ColorShaderContext::onChooseBlitProcs(const SkImageInfo& inf bool SkColor4Shader::Color4Context::onChooseBlitProcs(const SkImageInfo& info, BlitState* state) { return choose_blitprocs(&fPM4f, info, state); } + +bool SkColorShader::onAppendStages(SkRasterPipeline* p, + SkColorSpace* dst, + SkArenaAlloc* scratch, + const SkMatrix&, + const SkPaint&, + const SkMatrix*) const { + auto color = scratch->make(SkPM4f_from_SkColor(fColor, dst)); + p->append(SkRasterPipeline::constant_color, color); + return append_gamut_transform(p, scratch, + SkColorSpace::MakeSRGB().get(), dst); +} + +bool SkColor4Shader::onAppendStages(SkRasterPipeline* p, + SkColorSpace* dst, + SkArenaAlloc* scratch, + const SkMatrix&, + const SkPaint&, + const SkMatrix*) const { + auto color = scratch->make(fColor4.premul()); + p->append(SkRasterPipeline::constant_color, color); + return append_gamut_transform(p, scratch, fColorSpace.get(), dst); +} diff --git a/gfx/skia/skia/src/core/SkColorShader.h b/gfx/skia/skia/src/core/SkColorShader.h index 0bd270222374..b9db657b2b7a 100644 --- a/gfx/skia/skia/src/core/SkColorShader.h +++ b/gfx/skia/skia/src/core/SkColorShader.h @@ -25,6 +25,7 @@ public: explicit SkColorShader(SkColor c); bool isOpaque() const override; + bool isConstant() const override { return true; } class ColorShaderContext : public SkShader::Context { public: @@ -58,13 +59,16 @@ public: protected: SkColorShader(SkReadBuffer&); void flatten(SkWriteBuffer&) const override; - Context* onCreateContext(const ContextRec&, void* storage) const override; - size_t onContextSize(const ContextRec&) const override { return sizeof(ColorShaderContext); } + Context* onMakeContext(const ContextRec&, SkArenaAlloc* storage) const override; + bool onAsLuminanceColor(SkColor* lum) const override { *lum = fColor; return true; } + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + const SkMatrix& ctm, const SkPaint&, const SkMatrix*) const override; + private: SkColor fColor; @@ -78,6 +82,7 @@ public: bool isOpaque() const override { return SkColorGetA(fCachedByteColor) == 255; } + bool isConstant() const override { return true; } class Color4Context : public SkShader::Context { public: @@ -111,18 +116,19 @@ public: protected: SkColor4Shader(SkReadBuffer&); void flatten(SkWriteBuffer&) const override; - Context* onCreateContext(const ContextRec&, void* storage) const override; - size_t onContextSize(const ContextRec&) const override { return sizeof(Color4Context); } + Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override; bool onAsLuminanceColor(SkColor* lum) const override { *lum = fCachedByteColor; return true; } + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + const SkMatrix& ctm, const SkPaint&, const SkMatrix*) const override; private: sk_sp fColorSpace; const SkColor4f fColor4; const SkColor fCachedByteColor; - + typedef SkShader INHERITED; }; diff --git a/gfx/skia/skia/src/core/SkColorSpace.cpp b/gfx/skia/skia/src/core/SkColorSpace.cpp index c6bf4b943130..9942406a0eff 100644 --- a/gfx/skia/skia/src/core/SkColorSpace.cpp +++ b/gfx/skia/skia/src/core/SkColorSpace.cpp @@ -7,40 +7,86 @@ #include "SkColorSpace.h" #include "SkColorSpace_Base.h" +#include "SkColorSpace_XYZ.h" #include "SkColorSpacePriv.h" #include "SkOnce.h" +#include "SkPoint3.h" -SkColorSpace_Base::SkColorSpace_Base(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50) - : fGammaNamed(gammaNamed) - , fGammas(nullptr) - , fProfileData(nullptr) - , fToXYZD50(toXYZD50) - , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) +bool SkColorSpacePrimaries::toXYZD50(SkMatrix44* toXYZ_D50) const { + if (!is_zero_to_one(fRX) || !is_zero_to_one(fRY) || + !is_zero_to_one(fGX) || !is_zero_to_one(fGY) || + !is_zero_to_one(fBX) || !is_zero_to_one(fBY) || + !is_zero_to_one(fWX) || !is_zero_to_one(fWY)) + { + return false; + } + + // First, we need to convert xy values (primaries) to XYZ. + SkMatrix primaries; + primaries.setAll( fRX, fGX, fBX, + fRY, fGY, fBY, + 1.0f - fRX - fRY, 1.0f - fGX - fGY, 1.0f - fBX - fBY); + SkMatrix primariesInv; + if (!primaries.invert(&primariesInv)) { + return false; + } + + // Assumes that Y is 1.0f. + SkVector3 wXYZ = SkVector3::Make(fWX / fWY, 1.0f, (1.0f - fWX - fWY) / fWY); + SkVector3 XYZ; + XYZ.fX = primariesInv[0] * wXYZ.fX + primariesInv[1] * wXYZ.fY + primariesInv[2] * wXYZ.fZ; + XYZ.fY = primariesInv[3] * wXYZ.fX + primariesInv[4] * wXYZ.fY + primariesInv[5] * wXYZ.fZ; + XYZ.fZ = primariesInv[6] * wXYZ.fX + primariesInv[7] * wXYZ.fY + primariesInv[8] * wXYZ.fZ; + SkMatrix toXYZ; + toXYZ.setAll(XYZ.fX, 0.0f, 0.0f, + 0.0f, XYZ.fY, 0.0f, + 0.0f, 0.0f, XYZ.fZ); + toXYZ.postConcat(primaries); + + // Now convert toXYZ matrix to toXYZD50. + SkVector3 wXYZD50 = SkVector3::Make(0.96422f, 1.0f, 0.82521f); + + // Calculate the chromatic adaptation matrix. We will use the Bradford method, thus + // the matrices below. The Bradford method is used by Adobe and is widely considered + // to be the best. + SkMatrix mA, mAInv; + mA.setAll(+0.8951f, +0.2664f, -0.1614f, + -0.7502f, +1.7135f, +0.0367f, + +0.0389f, -0.0685f, +1.0296f); + mAInv.setAll(+0.9869929f, -0.1470543f, +0.1599627f, + +0.4323053f, +0.5183603f, +0.0492912f, + -0.0085287f, +0.0400428f, +0.9684867f); + + SkVector3 srcCone; + srcCone.fX = mA[0] * wXYZ.fX + mA[1] * wXYZ.fY + mA[2] * wXYZ.fZ; + srcCone.fY = mA[3] * wXYZ.fX + mA[4] * wXYZ.fY + mA[5] * wXYZ.fZ; + srcCone.fZ = mA[6] * wXYZ.fX + mA[7] * wXYZ.fY + mA[8] * wXYZ.fZ; + SkVector3 dstCone; + dstCone.fX = mA[0] * wXYZD50.fX + mA[1] * wXYZD50.fY + mA[2] * wXYZD50.fZ; + dstCone.fY = mA[3] * wXYZD50.fX + mA[4] * wXYZD50.fY + mA[5] * wXYZD50.fZ; + dstCone.fZ = mA[6] * wXYZD50.fX + mA[7] * wXYZD50.fY + mA[8] * wXYZD50.fZ; + + SkMatrix DXToD50; + DXToD50.setIdentity(); + DXToD50[0] = dstCone.fX / srcCone.fX; + DXToD50[4] = dstCone.fY / srcCone.fY; + DXToD50[8] = dstCone.fZ / srcCone.fZ; + DXToD50.postConcat(mAInv); + DXToD50.preConcat(mA); + + toXYZ.postConcat(DXToD50); + toXYZ_D50->set3x3(toXYZ[0], toXYZ[3], toXYZ[6], + toXYZ[1], toXYZ[4], toXYZ[7], + toXYZ[2], toXYZ[5], toXYZ[8]); + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SkColorSpace_Base::SkColorSpace_Base(sk_sp profileData) + : fProfileData(std::move(profileData)) {} -SkColorSpace_Base::SkColorSpace_Base(sk_sp colorLUT, SkGammaNamed gammaNamed, - sk_sp gammas, const SkMatrix44& toXYZD50, - sk_sp profileData) - : fColorLUT(std::move(colorLUT)) - , fGammaNamed(gammaNamed) - , fGammas(std::move(gammas)) - , fProfileData(std::move(profileData)) - , fToXYZD50(toXYZD50) - , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) -{} - -static constexpr float gSRGB_toXYZD50[] { - 0.4358f, 0.3853f, 0.1430f, // Rx, Gx, Bx - 0.2224f, 0.7170f, 0.0606f, // Ry, Gy, Gz - 0.0139f, 0.0971f, 0.7139f, // Rz, Gz, Bz -}; - -static constexpr float gAdobeRGB_toXYZD50[] { - 0.6098f, 0.2052f, 0.1492f, // Rx, Gx, Bx - 0.3111f, 0.6257f, 0.0632f, // Ry, Gy, By - 0.0195f, 0.0609f, 0.7448f, // Rz, Gz, Bz -}; - /** * Checks if our toXYZ matrix is a close match to a known color gamut. * @@ -66,52 +112,22 @@ static bool xyz_almost_equal(const SkMatrix44& toXYZD50, const float* standard) color_space_almost_equal(toXYZD50.getFloat(3, 3), 1.0f); } -sk_sp SkColorSpace_Base::NewRGB(const float values[3], const SkMatrix44& toXYZD50) { - if (0.0f > values[0] || 0.0f > values[1] || 0.0f > values[2]) { - return nullptr; - } - - SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed; - if (color_space_almost_equal(2.2f, values[0]) && - color_space_almost_equal(2.2f, values[1]) && - color_space_almost_equal(2.2f, values[2])) { - gammaNamed = k2Dot2Curve_SkGammaNamed; - } else if (color_space_almost_equal(1.0f, values[0]) && - color_space_almost_equal(1.0f, values[1]) && - color_space_almost_equal(1.0f, values[2])) { - gammaNamed = kLinear_SkGammaNamed; - } - - if (kNonStandard_SkGammaNamed == gammaNamed) { - sk_sp gammas = sk_sp(new SkGammas()); - gammas->fRedType = SkGammas::Type::kValue_Type; - gammas->fGreenType = SkGammas::Type::kValue_Type; - gammas->fBlueType = SkGammas::Type::kValue_Type; - gammas->fRedData.fValue = values[0]; - gammas->fGreenData.fValue = values[1]; - gammas->fBlueData.fValue = values[2]; - return sk_sp(new SkColorSpace_Base(nullptr, kNonStandard_SkGammaNamed, gammas, - toXYZD50, nullptr)); - } - - return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50); -} - -sk_sp SkColorSpace_Base::NewRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50) { +sk_sp SkColorSpace_Base::MakeRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50) +{ switch (gammaNamed) { case kSRGB_SkGammaNamed: if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { - return SkColorSpace::NewNamed(kSRGB_Named); + return SkColorSpace_Base::MakeNamed(kSRGB_Named); } break; case k2Dot2Curve_SkGammaNamed: if (xyz_almost_equal(toXYZD50, gAdobeRGB_toXYZD50)) { - return SkColorSpace::NewNamed(kAdobeRGB_Named); + return SkColorSpace_Base::MakeNamed(kAdobeRGB_Named); } break; case kLinear_SkGammaNamed: if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { - return SkColorSpace::NewNamed(kSRGBLinear_Named); + return SkColorSpace_Base::MakeNamed(kSRGBLinear_Named); } break; case kNonStandard_SkGammaNamed: @@ -121,25 +137,69 @@ sk_sp SkColorSpace_Base::NewRGB(SkGammaNamed gammaNamed, const SkM break; } - return sk_sp(new SkColorSpace_Base(gammaNamed, toXYZD50)); + return sk_sp(new SkColorSpace_XYZ(gammaNamed, toXYZD50)); } -sk_sp SkColorSpace::NewRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50) { +sk_sp SkColorSpace::MakeRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50) { switch (gamma) { case kLinear_RenderTargetGamma: - return SkColorSpace_Base::NewRGB(kLinear_SkGammaNamed, toXYZD50); + return SkColorSpace_Base::MakeRGB(kLinear_SkGammaNamed, toXYZD50); case kSRGB_RenderTargetGamma: - return SkColorSpace_Base::NewRGB(kSRGB_SkGammaNamed, toXYZD50); + return SkColorSpace_Base::MakeRGB(kSRGB_SkGammaNamed, toXYZD50); default: return nullptr; } } +sk_sp SkColorSpace::MakeRGB(const SkColorSpaceTransferFn& coeffs, + const SkMatrix44& toXYZD50) { + if (!is_valid_transfer_fn(coeffs)) { + return nullptr; + } + + if (is_almost_srgb(coeffs)) { + return SkColorSpace::MakeRGB(kSRGB_RenderTargetGamma, toXYZD50); + } + + if (is_almost_2dot2(coeffs)) { + return SkColorSpace_Base::MakeRGB(k2Dot2Curve_SkGammaNamed, toXYZD50); + } + + if (is_almost_linear(coeffs)) { + return SkColorSpace_Base::MakeRGB(kLinear_SkGammaNamed, toXYZD50); + } + + void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransferFn)); + sk_sp gammas = sk_sp(new (memory) SkGammas(3)); + SkColorSpaceTransferFn* fn = SkTAddOffset(memory, sizeof(SkGammas)); + *fn = coeffs; + SkGammas::Data data; + data.fParamOffset = 0; + for (int channel = 0; channel < 3; ++channel) { + gammas->fType[channel] = SkGammas::Type::kParam_Type; + gammas->fData[channel] = data; + } + return sk_sp(new SkColorSpace_XYZ(kNonStandard_SkGammaNamed, + std::move(gammas), toXYZD50, nullptr)); +} + +sk_sp SkColorSpace::MakeRGB(RenderTargetGamma gamma, Gamut gamut) { + SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); + to_xyz_d50(&toXYZD50, gamut); + return SkColorSpace::MakeRGB(gamma, toXYZD50); +} + +sk_sp SkColorSpace::MakeRGB(const SkColorSpaceTransferFn& coeffs, Gamut gamut) { + SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); + to_xyz_d50(&toXYZD50, gamut); + return SkColorSpace::MakeRGB(coeffs, toXYZD50); +} + static SkColorSpace* gAdobeRGB; static SkColorSpace* gSRGB; static SkColorSpace* gSRGBLinear; -sk_sp SkColorSpace::NewNamed(Named named) { +sk_sp SkColorSpace_Base::MakeNamed(Named named) { static SkOnce sRGBOnce; static SkOnce adobeRGBOnce; static SkOnce sRGBLinearOnce; @@ -152,7 +212,7 @@ sk_sp SkColorSpace::NewNamed(Named named) { // Force the mutable type mask to be computed. This avoids races. (void)srgbToxyzD50.getType(); - gSRGB = new SkColorSpace_Base(kSRGB_SkGammaNamed, srgbToxyzD50); + gSRGB = new SkColorSpace_XYZ(kSRGB_SkGammaNamed, srgbToxyzD50); }); return sk_ref_sp(gSRGB); } @@ -163,7 +223,7 @@ sk_sp SkColorSpace::NewNamed(Named named) { // Force the mutable type mask to be computed. This avoids races. (void)adobergbToxyzD50.getType(); - gAdobeRGB = new SkColorSpace_Base(k2Dot2Curve_SkGammaNamed, adobergbToxyzD50); + gAdobeRGB = new SkColorSpace_XYZ(k2Dot2Curve_SkGammaNamed, adobergbToxyzD50); }); return sk_ref_sp(gAdobeRGB); } @@ -174,7 +234,7 @@ sk_sp SkColorSpace::NewNamed(Named named) { // Force the mutable type mask to be computed. This avoids races. (void)srgbToxyzD50.getType(); - gSRGBLinear = new SkColorSpace_Base(kLinear_SkGammaNamed, srgbToxyzD50); + gSRGBLinear = new SkColorSpace_XYZ(kLinear_SkGammaNamed, srgbToxyzD50); }); return sk_ref_sp(gSRGBLinear); } @@ -184,36 +244,40 @@ sk_sp SkColorSpace::NewNamed(Named named) { return nullptr; } -sk_sp SkColorSpace::makeLinearGamma() { - if (this->gammaIsLinear()) { - return sk_ref_sp(this); - } - return SkColorSpace_Base::NewRGB(kLinear_SkGammaNamed, as_CSB(this)->fToXYZD50); +sk_sp SkColorSpace::MakeSRGB() { + return SkColorSpace_Base::MakeNamed(SkColorSpace_Base::kSRGB_Named); +} + +sk_sp SkColorSpace::MakeSRGBLinear() { + return SkColorSpace_Base::MakeNamed(SkColorSpace_Base::kSRGBLinear_Named); } /////////////////////////////////////////////////////////////////////////////////////////////////// bool SkColorSpace::gammaCloseToSRGB() const { - return kSRGB_SkGammaNamed == as_CSB(this)->fGammaNamed || - k2Dot2Curve_SkGammaNamed == as_CSB(this)->fGammaNamed; + return as_CSB(this)->onGammaCloseToSRGB(); } bool SkColorSpace::gammaIsLinear() const { - return kLinear_SkGammaNamed == as_CSB(this)->fGammaNamed; + return as_CSB(this)->onGammaIsLinear(); } -const SkMatrix44& SkColorSpace_Base::fromXYZD50() const { - fFromXYZOnce([this] { - if (!fToXYZD50.invert(&fFromXYZD50)) { - // If a client gives us a dst gamut with a transform that we can't invert, we will - // simply give them back a transform to sRGB gamut. - SkDEBUGFAIL("Non-invertible XYZ matrix, defaulting to sRGB"); - SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); - srgbToxyzD50.set3x3RowMajorf(gSRGB_toXYZD50); - srgbToxyzD50.invert(&fFromXYZD50); - } - }); - return fFromXYZD50; +bool SkColorSpace::isNumericalTransferFn(SkColorSpaceTransferFn* fn) const { + return as_CSB(this)->onIsNumericalTransferFn(fn); +} + +bool SkColorSpace::toXYZD50(SkMatrix44* toXYZD50) const { + const SkMatrix44* matrix = as_CSB(this)->toXYZD50(); + if (matrix) { + *toXYZD50 = *matrix; + return true; + } + + return false; +} + +bool SkColorSpace::isSRGB() const { + return gSRGB == this; } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -223,9 +287,13 @@ enum Version { }; struct ColorSpaceHeader { + /** + * It is only valid to set zero or one flags. + * Setting multiple flags is invalid. + */ + /** * If kMatrix_Flag is set, we will write 12 floats after the header. - * Should not be set at the same time as the kICC_Flag or kFloatGamma_Flag. */ static constexpr uint8_t kMatrix_Flag = 1 << 0; @@ -233,17 +301,15 @@ struct ColorSpaceHeader { * If kICC_Flag is set, we will write an ICC profile after the header. * The ICC profile will be written as a uint32 size, followed immediately * by the data (padded to 4 bytes). - * Should not be set at the same time as the kMatrix_Flag or kFloatGamma_Flag. */ static constexpr uint8_t kICC_Flag = 1 << 1; /** - * If kFloatGamma_Flag is set, we will write 15 floats after the header. - * The first three are the gamma values, and the next twelve are the + * If kTransferFn_Flag is set, we will write 19 floats after the header. + * The first seven represent the transfer fn, and the next twelve are the * matrix. - * Should not be set at the same time as the kICC_Flag or kMatrix_Flag. */ - static constexpr uint8_t kFloatGamma_Flag = 1 << 2; + static constexpr uint8_t kTransferFn_Flag = 1 << 3; static ColorSpaceHeader Pack(Version version, uint8_t named, uint8_t gammaNamed, uint8_t flags) { @@ -252,86 +318,95 @@ struct ColorSpaceHeader { SkASSERT(k0_Version == version); header.fVersion = (uint8_t) version; - SkASSERT(named <= SkColorSpace::kSRGBLinear_Named); + SkASSERT(named <= SkColorSpace_Base::kSRGBLinear_Named); header.fNamed = (uint8_t) named; SkASSERT(gammaNamed <= kNonStandard_SkGammaNamed); header.fGammaNamed = (uint8_t) gammaNamed; - SkASSERT(flags <= kFloatGamma_Flag); + SkASSERT(flags <= kTransferFn_Flag); header.fFlags = flags; return header; } - uint8_t fVersion; // Always zero - uint8_t fNamed; // Must be a SkColorSpace::Named - uint8_t fGammaNamed; // Must be a SkGammaNamed - uint8_t fFlags; // Some combination of the flags listed above + uint8_t fVersion; // Always zero + uint8_t fNamed; // Must be a SkColorSpace::Named + uint8_t fGammaNamed; // Must be a SkGammaNamed + uint8_t fFlags; }; size_t SkColorSpace::writeToMemory(void* memory) const { // Start by trying the serialization fast path. If we haven't saved ICC profile data, // we must have a profile that we can serialize easily. if (!as_CSB(this)->fProfileData) { + // Profile data is mandatory for A2B0 color spaces. + SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(this)->type()); + const SkColorSpace_XYZ* thisXYZ = static_cast(this); // If we have a named profile, only write the enum. + const SkGammaNamed gammaNamed = thisXYZ->gammaNamed(); if (this == gSRGB) { if (memory) { - *((ColorSpaceHeader*) memory) = - ColorSpaceHeader::Pack(k0_Version, kSRGB_Named, - as_CSB(this)->fGammaNamed, 0); + *((ColorSpaceHeader*) memory) = ColorSpaceHeader::Pack( + k0_Version, SkColorSpace_Base::kSRGB_Named, gammaNamed, 0); } return sizeof(ColorSpaceHeader); } else if (this == gAdobeRGB) { if (memory) { - *((ColorSpaceHeader*) memory) = - ColorSpaceHeader::Pack(k0_Version, kAdobeRGB_Named, - as_CSB(this)->fGammaNamed, 0); + *((ColorSpaceHeader*) memory) = ColorSpaceHeader::Pack( + k0_Version, SkColorSpace_Base::kAdobeRGB_Named, gammaNamed, 0); } return sizeof(ColorSpaceHeader); } else if (this == gSRGBLinear) { if (memory) { - *((ColorSpaceHeader*)memory) = - ColorSpaceHeader::Pack(k0_Version, kSRGBLinear_Named, - as_CSB(this)->fGammaNamed, 0); + *((ColorSpaceHeader*) memory) = ColorSpaceHeader::Pack( + k0_Version, SkColorSpace_Base::kSRGBLinear_Named, gammaNamed, 0); } return sizeof(ColorSpaceHeader); } // If we have a named gamma, write the enum and the matrix. - switch (as_CSB(this)->fGammaNamed) { + switch (gammaNamed) { case kSRGB_SkGammaNamed: case k2Dot2Curve_SkGammaNamed: case kLinear_SkGammaNamed: { if (memory) { *((ColorSpaceHeader*) memory) = - ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed, + ColorSpaceHeader::Pack(k0_Version, 0, gammaNamed, ColorSpaceHeader::kMatrix_Flag); memory = SkTAddOffset(memory, sizeof(ColorSpaceHeader)); - as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); + thisXYZ->toXYZD50()->as3x4RowMajorf((float*) memory); } return sizeof(ColorSpaceHeader) + 12 * sizeof(float); } - default: - // Otherwise, write the gamma values and the matrix. + default: { + const SkGammas* gammas = thisXYZ->gammas(); + SkASSERT(gammas); + SkASSERT(gammas->isParametric(0)); + SkASSERT(gammas->isParametric(1)); + SkASSERT(gammas->isParametric(2)); + SkASSERT(gammas->data(0) == gammas->data(1)); + SkASSERT(gammas->data(0) == gammas->data(2)); + if (memory) { *((ColorSpaceHeader*) memory) = - ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed, - ColorSpaceHeader::kFloatGamma_Flag); + ColorSpaceHeader::Pack(k0_Version, 0, thisXYZ->fGammaNamed, + ColorSpaceHeader::kTransferFn_Flag); memory = SkTAddOffset(memory, sizeof(ColorSpaceHeader)); - const SkGammas* gammas = as_CSB(this)->gammas(); - SkASSERT(gammas); - SkASSERT(SkGammas::Type::kValue_Type == gammas->fRedType && - SkGammas::Type::kValue_Type == gammas->fGreenType && - SkGammas::Type::kValue_Type == gammas->fBlueType); - *(((float*) memory) + 0) = gammas->fRedData.fValue; - *(((float*) memory) + 1) = gammas->fGreenData.fValue; - *(((float*) memory) + 2) = gammas->fBlueData.fValue; - memory = SkTAddOffset(memory, 3 * sizeof(float)); + *(((float*) memory) + 0) = gammas->params(0).fA; + *(((float*) memory) + 1) = gammas->params(0).fB; + *(((float*) memory) + 2) = gammas->params(0).fC; + *(((float*) memory) + 3) = gammas->params(0).fD; + *(((float*) memory) + 4) = gammas->params(0).fE; + *(((float*) memory) + 5) = gammas->params(0).fF; + *(((float*) memory) + 6) = gammas->params(0).fG; + memory = SkTAddOffset(memory, 7 * sizeof(float)); - as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); + thisXYZ->fToXYZD50.as3x4RowMajorf((float*) memory); } - return sizeof(ColorSpaceHeader) + 15 * sizeof(float); + + return sizeof(ColorSpaceHeader) + 19 * sizeof(float); + } } } @@ -376,7 +451,7 @@ sk_sp SkColorSpace::Deserialize(const void* data, size_t length) { data = SkTAddOffset(data, sizeof(ColorSpaceHeader)); length -= sizeof(ColorSpaceHeader); if (0 == header.fFlags) { - return NewNamed((Named) header.fNamed); + return SkColorSpace_Base::MakeNamed((SkColorSpace_Base::Named) header.fNamed); } switch ((SkGammaNamed) header.fGammaNamed) { @@ -389,7 +464,7 @@ sk_sp SkColorSpace::Deserialize(const void* data, size_t length) { SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); toXYZ.set3x4RowMajorf((const float*) data); - return SkColorSpace_Base::NewRGB((SkGammaNamed) header.fGammaNamed, toXYZ); + return SkColorSpace_Base::MakeRGB((SkGammaNamed) header.fGammaNamed, toXYZ); } default: break; @@ -408,22 +483,26 @@ sk_sp SkColorSpace::Deserialize(const void* data, size_t length) { return nullptr; } - return NewICC(data, profileSize); + return MakeICC(data, profileSize); } - case ColorSpaceHeader::kFloatGamma_Flag: { - if (length < 15 * sizeof(float)) { + case ColorSpaceHeader::kTransferFn_Flag: { + if (length < 19 * sizeof(float)) { return nullptr; } - float gammas[3]; - gammas[0] = *(((const float*) data) + 0); - gammas[1] = *(((const float*) data) + 1); - gammas[2] = *(((const float*) data) + 2); - data = SkTAddOffset(data, 3 * sizeof(float)); + SkColorSpaceTransferFn transferFn; + transferFn.fA = *(((const float*) data) + 0); + transferFn.fB = *(((const float*) data) + 1); + transferFn.fC = *(((const float*) data) + 2); + transferFn.fD = *(((const float*) data) + 3); + transferFn.fE = *(((const float*) data) + 4); + transferFn.fF = *(((const float*) data) + 5); + transferFn.fG = *(((const float*) data) + 6); + data = SkTAddOffset(data, 7 * sizeof(float)); SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); toXYZ.set3x4RowMajorf((const float*) data); - return SkColorSpace_Base::NewRGB(gammas, toXYZ); + return SkColorSpace::MakeRGB(transferFn, toXYZ); } default: return nullptr; @@ -450,23 +529,74 @@ bool SkColorSpace::Equals(const SkColorSpace* src, const SkColorSpace* dst) { return false; } - // It's important to check fProfileData before named gammas. Some profiles may have named - // gammas, but also include other wacky features that cause us to save the data. - switch (as_CSB(src)->fGammaNamed) { + // profiles are mandatory for A2B0 color spaces + SkASSERT(as_CSB(src)->type() == SkColorSpace_Base::Type::kXYZ); + const SkColorSpace_XYZ* srcXYZ = static_cast(src); + const SkColorSpace_XYZ* dstXYZ = static_cast(dst); + + if (srcXYZ->gammaNamed() != dstXYZ->gammaNamed()) { + return false; + } + + switch (srcXYZ->gammaNamed()) { case kSRGB_SkGammaNamed: case k2Dot2Curve_SkGammaNamed: case kLinear_SkGammaNamed: - return (as_CSB(src)->fGammaNamed == as_CSB(dst)->fGammaNamed) && - (as_CSB(src)->fToXYZD50 == as_CSB(dst)->fToXYZD50); - default: - if (as_CSB(src)->fGammaNamed != as_CSB(dst)->fGammaNamed) { - return false; + if (srcXYZ->toXYZD50Hash() == dstXYZ->toXYZD50Hash()) { + SkASSERT(*srcXYZ->toXYZD50() == *dstXYZ->toXYZD50() && "Hash collision"); + return true; } - + return false; + default: // It is unlikely that we will reach this case. - sk_sp srcData = src->serialize(); - sk_sp dstData = dst->serialize(); - return srcData->size() == dstData->size() && - 0 == memcmp(srcData->data(), dstData->data(), srcData->size()); + sk_sp serializedSrcData = src->serialize(); + sk_sp serializedDstData = dst->serialize(); + return serializedSrcData->size() == serializedDstData->size() && + 0 == memcmp(serializedSrcData->data(), serializedDstData->data(), + serializedSrcData->size()); } } + +SkColorSpaceTransferFn SkColorSpaceTransferFn::invert() const { + // Original equation is: y = (ax + b)^g + e for x >= d + // y = cx + f otherwise + // + // so 1st inverse is: (y - e)^(1/g) = ax + b + // x = ((y - e)^(1/g) - b) / a + // + // which can be re-written as: x = (1/a)(y - e)^(1/g) - b/a + // x = ((1/a)^g)^(1/g) * (y - e)^(1/g) - b/a + // x = ([(1/a)^g]y + [-((1/a)^g)e]) ^ [1/g] + [-b/a] + // + // and 2nd inverse is: x = (y - f) / c + // which can be re-written as: x = [1/c]y + [-f/c] + // + // and now both can be expressed in terms of the same parametric form as the + // original - parameters are enclosed in square brackets. + SkColorSpaceTransferFn inv = { 0, 0, 0, 0, 0, 0, 0 }; + + // find inverse for linear segment (if possible) + if (!transfer_fn_almost_equal(0.f, fC)) { + inv.fC = 1.f / fC; + inv.fF = -fF / fC; + } else { + // otherwise assume it should be 0 as it is the lower segment + // as y = f is a constant function + } + + // find inverse for the other segment (if possible) + if (transfer_fn_almost_equal(0.f, fA) || transfer_fn_almost_equal(0.f, fG)) { + // otherwise assume it should be 1 as it is the top segment + // as you can't invert the constant functions y = b^g + c, or y = 1 + c + inv.fG = 1.f; + inv.fE = 1.f; + } else { + inv.fG = 1.f / fG; + inv.fA = powf(1.f / fA, fG); + inv.fB = -inv.fA * fE; + inv.fE = -fB / fA; + } + inv.fD = fC * fD + fF; + + return inv; +} diff --git a/gfx/skia/skia/src/core/SkColorSpacePriv.h b/gfx/skia/skia/src/core/SkColorSpacePriv.h index e7c8aaa10382..4a63ddfa141a 100644 --- a/gfx/skia/skia/src/core/SkColorSpacePriv.h +++ b/gfx/skia/skia/src/core/SkColorSpacePriv.h @@ -4,9 +4,196 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#ifndef SkColorSpacePriv_DEFINED +#define SkColorSpacePriv_DEFINED + +#include + +#include "SkColorSpace_Base.h" #define SkColorSpacePrintf(...) -inline bool color_space_almost_equal(float a, float b) { +static constexpr float gSRGB_toXYZD50[] { + 0.4360747f, 0.3850649f, 0.1430804f, // Rx, Gx, Bx + 0.2225045f, 0.7168786f, 0.0606169f, // Ry, Gy, Gz + 0.0139322f, 0.0971045f, 0.7141733f, // Rz, Gz, Bz +}; + +static constexpr float gAdobeRGB_toXYZD50[] { + 0.6097559f, 0.2052401f, 0.1492240f, // Rx, Gx, Bx + 0.3111242f, 0.6256560f, 0.0632197f, // Ry, Gy, Gz + 0.0194811f, 0.0608902f, 0.7448387f, // Rz, Gz, Bz +}; + +static constexpr float gDCIP3_toXYZD50[] { + 0.515102f, 0.291965f, 0.157153f, // Rx, Gx, Bx + 0.241182f, 0.692236f, 0.0665819f, // Ry, Gy, Gz + -0.00104941f, 0.0418818f, 0.784378f, // Rz, Gz, Bz +}; + +static constexpr float gRec2020_toXYZD50[] { + 0.673459f, 0.165661f, 0.125100f, // Rx, Gx, Bx + 0.279033f, 0.675338f, 0.0456288f, // Ry, Gy, Gz + -0.00193139f, 0.0299794f, 0.797162f, // Rz, Gz, Bz +}; + +static inline void to_xyz_d50(SkMatrix44* toXYZD50, SkColorSpace::Gamut gamut) { + switch (gamut) { + case SkColorSpace::kSRGB_Gamut: + toXYZD50->set3x3RowMajorf(gSRGB_toXYZD50); + break; + case SkColorSpace::kAdobeRGB_Gamut: + toXYZD50->set3x3RowMajorf(gAdobeRGB_toXYZD50); + break; + case SkColorSpace::kDCIP3_D65_Gamut: + toXYZD50->set3x3RowMajorf(gDCIP3_toXYZD50); + break; + case SkColorSpace::kRec2020_Gamut: + toXYZD50->set3x3RowMajorf(gRec2020_toXYZD50); + break; + } +} + +static inline bool color_space_almost_equal(float a, float b) { return SkTAbs(a - b) < 0.01f; } + +// Let's use a stricter version for transfer functions. Worst case, these are encoded +// in ICC format, which offers 16-bits of fractional precision. +static inline bool transfer_fn_almost_equal(float a, float b) { + return SkTAbs(a - b) < 0.001f; +} + +static inline bool is_zero_to_one(float v) { + // Because we allow a value just barely larger than 1, the client can use an + // entirely linear transfer function. + return (0.0f <= v) && (v <= nextafterf(1.0f, 2.0f)); +} + +static inline bool is_valid_transfer_fn(const SkColorSpaceTransferFn& coeffs) { + if (SkScalarIsNaN(coeffs.fA) || SkScalarIsNaN(coeffs.fB) || + SkScalarIsNaN(coeffs.fC) || SkScalarIsNaN(coeffs.fD) || + SkScalarIsNaN(coeffs.fE) || SkScalarIsNaN(coeffs.fF) || + SkScalarIsNaN(coeffs.fG)) + { + return false; + } + + if (!is_zero_to_one(coeffs.fD)) { + return false; + } + + if (coeffs.fD == 0.0f) { + // Y = (aX + b)^g + e for always + if (0.0f == coeffs.fA || 0.0f == coeffs.fG) { + SkColorSpacePrintf("A or G is zero, constant transfer function " + "is nonsense"); + return false; + } + } + + if (coeffs.fD >= 1.0f) { + // Y = cX + f for always + if (0.0f == coeffs.fC) { + SkColorSpacePrintf("C is zero, constant transfer function is " + "nonsense"); + return false; + } + } + + if ((0.0f == coeffs.fA || 0.0f == coeffs.fG) && 0.0f == coeffs.fC) { + SkColorSpacePrintf("A or G, and C are zero, constant transfer function " + "is nonsense"); + return false; + } + + if (coeffs.fC < 0.0f) { + SkColorSpacePrintf("Transfer function must be increasing"); + return false; + } + + if (coeffs.fA < 0.0f || coeffs.fG < 0.0f) { + SkColorSpacePrintf("Transfer function must be positive or increasing"); + return false; + } + + return true; +} + +static inline bool is_almost_srgb(const SkColorSpaceTransferFn& coeffs) { + return transfer_fn_almost_equal(1.0f / 1.055f, coeffs.fA) && + transfer_fn_almost_equal(0.055f / 1.055f, coeffs.fB) && + transfer_fn_almost_equal(1.0f / 12.92f, coeffs.fC) && + transfer_fn_almost_equal(0.04045f, coeffs.fD) && + transfer_fn_almost_equal(0.00000f, coeffs.fE) && + transfer_fn_almost_equal(0.00000f, coeffs.fF) && + transfer_fn_almost_equal(2.40000f, coeffs.fG); +} + +static inline bool is_almost_2dot2(const SkColorSpaceTransferFn& coeffs) { + return transfer_fn_almost_equal(1.0f, coeffs.fA) && + transfer_fn_almost_equal(0.0f, coeffs.fB) && + transfer_fn_almost_equal(0.0f, coeffs.fE) && + transfer_fn_almost_equal(2.2f, coeffs.fG) && + coeffs.fD <= 0.0f; +} + +static inline bool is_almost_linear(const SkColorSpaceTransferFn& coeffs) { + // OutputVal = InputVal ^ 1.0f + const bool linearExp = + transfer_fn_almost_equal(1.0f, coeffs.fA) && + transfer_fn_almost_equal(0.0f, coeffs.fB) && + transfer_fn_almost_equal(0.0f, coeffs.fE) && + transfer_fn_almost_equal(1.0f, coeffs.fG) && + coeffs.fD <= 0.0f; + + // OutputVal = 1.0f * InputVal + const bool linearFn = + transfer_fn_almost_equal(1.0f, coeffs.fC) && + transfer_fn_almost_equal(0.0f, coeffs.fF) && + coeffs.fD >= 1.0f; + + return linearExp || linearFn; +} + +static inline void value_to_parametric(SkColorSpaceTransferFn* coeffs, float exponent) { + coeffs->fA = 1.0f; + coeffs->fB = 0.0f; + coeffs->fC = 0.0f; + coeffs->fD = 0.0f; + coeffs->fE = 0.0f; + coeffs->fF = 0.0f; + coeffs->fG = exponent; +} + +static inline bool named_to_parametric(SkColorSpaceTransferFn* coeffs, + SkGammaNamed gammaNamed) { + switch (gammaNamed) { + case kSRGB_SkGammaNamed: + coeffs->fA = 1.0f / 1.055f; + coeffs->fB = 0.055f / 1.055f; + coeffs->fC = 1.0f / 12.92f; + coeffs->fD = 0.04045f; + coeffs->fE = 0.0f; + coeffs->fF = 0.0f; + coeffs->fG = 2.4f; + return true; + case k2Dot2Curve_SkGammaNamed: + value_to_parametric(coeffs, 2.2f); + return true; + case kLinear_SkGammaNamed: + coeffs->fA = 0.0f; + coeffs->fB = 0.0f; + coeffs->fC = 1.0f; + // Make sure that we use the linear segment of the transfer function even + // when the x-value is 1.0f. + coeffs->fD = nextafterf(1.0f, 2.0f); + coeffs->fE = 0.0f; + coeffs->fF = 0.0f; + coeffs->fG = 0.0f; + return true; + default: + return false; + } +} +#endif // SkColorSpacePriv_DEFINED diff --git a/gfx/skia/skia/src/core/SkColorSpaceXform.cpp b/gfx/skia/skia/src/core/SkColorSpaceXform.cpp index f7a0239d272a..52a685194cf5 100644 --- a/gfx/skia/skia/src/core/SkColorSpaceXform.cpp +++ b/gfx/skia/skia/src/core/SkColorSpaceXform.cpp @@ -6,11 +6,17 @@ */ #include "SkColorPriv.h" +#include "SkColorSpace_A2B.h" #include "SkColorSpace_Base.h" +#include "SkColorSpace_XYZ.h" #include "SkColorSpacePriv.h" -#include "SkColorSpaceXform.h" +#include "SkColorSpaceXform_A2B.h" +#include "SkColorSpaceXform_Base.h" +#include "SkColorSpaceXformPriv.h" #include "SkHalf.h" #include "SkOpts.h" +#include "SkPM4fPriv.h" +#include "SkRasterPipeline.h" #include "SkSRGB.h" static constexpr float sk_linear_from_2dot2[256] = { @@ -88,14 +94,6 @@ static void build_table_linear_from_gamma(float* outTable, float exponent) { } } -// Interpolating lookup in a variably sized table. -static float interp_lut(float input, const float* table, int tableSize) { - float index = input * (tableSize - 1); - float diff = index - sk_float_floor2int(index); - return table[(int) sk_float_floor2int(index)] * (1.0f - diff) + - table[(int) sk_float_ceil2int(index)] * diff; -} - // outTable is always 256 entries, inTable may be larger or smaller. static void build_table_linear_from_gamma(float* outTable, const float* inTable, int inTableSize) { @@ -109,38 +107,23 @@ static void build_table_linear_from_gamma(float* outTable, const float* inTable, } } + static void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c, float d, float e, float f) { - // Y = (aX + b)^g + c for X >= d - // Y = eX + f otherwise + // Y = (aX + b)^g + e for X >= d + // Y = cX + f otherwise for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) { if (x >= d) { - *outTable++ = powf(a * x + b, g) + c; + *outTable++ = clamp_0_1(powf(a * x + b, g) + e); } else { - *outTable++ = e * x + f; + *outTable++ = clamp_0_1(c * x + f); } } } /////////////////////////////////////////////////////////////////////////////////////////////////// -// Expand range from 0-1 to 0-255, then convert. -static uint8_t clamp_normalized_float_to_byte(float v) { - // The ordering of the logic is a little strange here in order - // to make sure we convert NaNs to 0. - v = v * 255.0f; - if (v >= 254.5f) { - return 255; - } else if (v >= 0.5f) { - return (uint8_t) (v + 0.5f); - } else { - return 0; - } -} - -static const int kDstGammaTableSize = - SkColorSpaceXform_Base - ::kDstGammaTableSize; +static const int kDstGammaTableSize = SkColorSpaceXform_Base::kDstGammaTableSize; static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) { float toGammaExp = 1.0f / exponent; @@ -151,39 +134,9 @@ static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) { } } -// Inverse table lookup. Ex: what index corresponds to the input value? This will -// have strange results when the table is non-increasing. But any sane gamma -// function will be increasing. -static float inverse_interp_lut(float input, const float* table, int tableSize) { - if (input <= table[0]) { - return table[0]; - } else if (input >= table[tableSize - 1]) { - return 1.0f; - } - - for (int i = 1; i < tableSize; i++) { - if (table[i] >= input) { - // We are guaranteed that input is greater than table[i - 1]. - float diff = input - table[i - 1]; - float distance = table[i] - table[i - 1]; - float index = (i - 1) + diff / distance; - return index / (tableSize - 1); - } - } - - // Should be unreachable, since we'll return before the loop if input is - // larger than the last entry. - SkASSERT(false); - return 0.0f; -} - static void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable, int inTableSize) { - for (int i = 0; i < kDstGammaTableSize; i++) { - float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1))); - float y = inverse_interp_lut(x, inTable, inTableSize); - outTable[i] = clamp_normalized_float_to_byte(y); - } + invert_table_gamma(nullptr, outTable, kDstGammaTableSize, inTable, inTableSize); } static float inverse_parametric(float x, float g, float a, float b, float c, float d, float e, @@ -195,26 +148,26 @@ static float inverse_parametric(float x, float g, float a, float b, float c, flo // Assume that the gamma function is continuous, or this won't make much sense anyway. // Plug in |d| to the first equation to calculate the new piecewise interval. // Then simply use the inverse of the original functions. - float interval = e * d + f; + float interval = c * d + f; if (x < interval) { - // X = (Y - F) / E - if (0.0f == e) { + // X = (Y - F) / C + if (0.0f == c) { // The gamma curve for this segment is constant, so the inverse is undefined. // Since this is the lower segment, guess zero. return 0.0f; } - return (x - f) / e; + return (x - f) / c; } - // X = ((Y - C)^(1 / G) - B) / A + // X = ((Y - E)^(1 / G) - B) / A if (0.0f == a || 0.0f == g) { // The gamma curve for this segment is constant, so the inverse is undefined. // Since this is the upper segment, guess one. return 1.0f; } - return (powf(x - c, 1.0f / g) - b) / a; + return (powf(x - e, 1.0f / g) - b) / a; } static void build_table_linear_to_gamma(uint8_t* outTable, float g, float a, @@ -256,9 +209,10 @@ static const GammaFns kFromLinear { // Build tables to transform src gamma to linear. template static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize, - SkColorSpace* space, const GammaFns& fns, bool gammasAreMatching) + const SkColorSpace_XYZ* space, const GammaFns& fns, + bool gammasAreMatching) { - switch (as_CSB(space)->gammaNamed()) { + switch (space->gammaNamed()) { case kSRGB_SkGammaNamed: outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable; break; @@ -269,7 +223,7 @@ static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr; break; default: { - const SkGammas* gammas = as_CSB(space)->gammas(); + const SkGammas* gammas = space->gammas(); SkASSERT(gammas); auto build_table = [=](int i) { @@ -277,8 +231,8 @@ static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, switch (gammas->data(i).fNamed) { case kSRGB_SkGammaNamed: (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], 2.4f, - (1.0f / 1.055f), (0.055f / 1.055f), 0.0f, - 0.04045f, (1.0f / 12.92f), 0.0f); + (1.0f / 1.055f), (0.055f / 1.055f), + (1.0f / 12.92f), 0.04045f, 0.0f, 0.0f); outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; break; case k2Dot2Curve_SkGammaNamed: @@ -303,7 +257,7 @@ static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; } else { SkASSERT(gammas->isParametric(i)); - const SkGammas::Params& params = gammas->params(i); + const SkColorSpaceTransferFn& params = gammas->params(i); (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG, params.fA, params.fB, params.fC, params.fD, params.fE, params.fF); @@ -326,149 +280,67 @@ static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, } } -/////////////////////////////////////////////////////////////////////////////////////////////////// - -static inline bool is_almost_identity(const SkMatrix44& srcToDst) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - float expected = (i == j) ? 1.0f : 0.0f; - if (!color_space_almost_equal(srcToDst.getFloat(i,j), expected)) { - return false; - } - } - } - return true; +void SkColorSpaceXform_Base::BuildDstGammaTables(const uint8_t* dstGammaTables[3], + uint8_t* dstStorage, + const SkColorSpace_XYZ* space, + bool gammasAreMatching) { + build_gamma_tables(dstGammaTables, dstStorage, kDstGammaTableSize, space, kFromLinear, + gammasAreMatching); } /////////////////////////////////////////////////////////////////////////////////////////////////// std::unique_ptr SkColorSpaceXform::New(SkColorSpace* srcSpace, SkColorSpace* dstSpace) { + return SkColorSpaceXform_Base::New(srcSpace, dstSpace, SkTransferFunctionBehavior::kRespect); +} + +std::unique_ptr SkColorSpaceXform_Base::New(SkColorSpace* srcSpace, + SkColorSpace* dstSpace, SkTransferFunctionBehavior premulBehavior) { + if (!srcSpace || !dstSpace) { // Invalid input return nullptr; } + if (SkColorSpace_Base::Type::kA2B == as_CSB(dstSpace)->type()) { + SkCSXformPrintf("A2B destinations not supported\n"); + return nullptr; + } + + if (SkColorSpace_Base::Type::kA2B == as_CSB(srcSpace)->type()) { + SkColorSpace_A2B* src = static_cast(srcSpace); + SkColorSpace_XYZ* dst = static_cast(dstSpace); + return std::unique_ptr(new SkColorSpaceXform_A2B(src, dst)); + } + SkColorSpace_XYZ* srcSpaceXYZ = static_cast(srcSpace); + SkColorSpace_XYZ* dstSpaceXYZ = static_cast(dstSpace); + ColorSpaceMatch csm = kNone_ColorSpaceMatch; SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); if (SkColorSpace::Equals(srcSpace, dstSpace)) { srcToDst.setIdentity(); csm = kFull_ColorSpaceMatch; } else { - srcToDst.setConcat(as_CSB(dstSpace)->fromXYZD50(), as_CSB(srcSpace)->toXYZD50()); - - if (is_almost_identity(srcToDst)) { + if (srcSpaceXYZ->toXYZD50Hash() == dstSpaceXYZ->toXYZD50Hash()) { + SkASSERT(*srcSpaceXYZ->toXYZD50() == *dstSpaceXYZ->toXYZD50() && "Hash collision"); srcToDst.setIdentity(); csm = kGamut_ColorSpaceMatch; + } else { + srcToDst.setConcat(*dstSpaceXYZ->fromXYZD50(), *srcSpaceXYZ->toXYZD50()); } } switch (csm) { case kNone_ColorSpaceMatch: - switch (as_CSB(dstSpace)->gammaNamed()) { - case kSRGB_SkGammaNamed: - if (srcSpace->gammaIsLinear()) { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } else { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } - case k2Dot2Curve_SkGammaNamed: - if (srcSpace->gammaIsLinear()) { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } else { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } - case kLinear_SkGammaNamed: - if (srcSpace->gammaIsLinear()) { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } else { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } - default: - if (srcSpace->gammaIsLinear()) { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } else { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } - } + return std::unique_ptr(new SkColorSpaceXform_XYZ + (srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior)); case kGamut_ColorSpaceMatch: - switch (as_CSB(dstSpace)->gammaNamed()) { - case kSRGB_SkGammaNamed: - if (srcSpace->gammaIsLinear()) { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } else { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } - case k2Dot2Curve_SkGammaNamed: - if (srcSpace->gammaIsLinear()) { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } else { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } - case kLinear_SkGammaNamed: - if (srcSpace->gammaIsLinear()) { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } else { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } - default: - if (srcSpace->gammaIsLinear()) { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } else { - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } - } + return std::unique_ptr(new SkColorSpaceXform_XYZ + (srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior)); case kFull_ColorSpaceMatch: - switch (as_CSB(dstSpace)->gammaNamed()) { - case kSRGB_SkGammaNamed: - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - case k2Dot2Curve_SkGammaNamed: - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - case kLinear_SkGammaNamed: - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - default: - return std::unique_ptr(new SkColorSpaceXform_Base - - (srcSpace, srcToDst, dstSpace)); - } + return std::unique_ptr(new SkColorSpaceXform_XYZ + (srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior)); default: SkASSERT(false); return nullptr; @@ -477,143 +349,14 @@ std::unique_ptr SkColorSpaceXform::New(SkColorSpace* srcSpace /////////////////////////////////////////////////////////////////////////////////////////////////// -static float byte_to_float(uint8_t byte) { - return ((float) byte) * (1.0f / 255.0f); -} +#define AI SK_ALWAYS_INLINE -// Clamp to the 0-1 range. -static float clamp_normalized_float(float v) { - if (v > 1.0f) { - return 1.0f; - } else if ((v < 0.0f) || sk_float_isnan(v)) { - return 0.0f; - } else { - return v; - } -} - -static void interp_3d_clut(float dst[3], float src[3], const SkColorLookUpTable* colorLUT) { - // Call the src components x, y, and z. - uint8_t maxX = colorLUT->fGridPoints[0] - 1; - uint8_t maxY = colorLUT->fGridPoints[1] - 1; - uint8_t maxZ = colorLUT->fGridPoints[2] - 1; - - // An approximate index into each of the three dimensions of the table. - float x = src[0] * maxX; - float y = src[1] * maxY; - float z = src[2] * maxZ; - - // This gives us the low index for our interpolation. - int ix = sk_float_floor2int(x); - int iy = sk_float_floor2int(y); - int iz = sk_float_floor2int(z); - - // Make sure the low index is not also the max index. - ix = (maxX == ix) ? ix - 1 : ix; - iy = (maxY == iy) ? iy - 1 : iy; - iz = (maxZ == iz) ? iz - 1 : iz; - - // Weighting factors for the interpolation. - float diffX = x - ix; - float diffY = y - iy; - float diffZ = z - iz; - - // Constants to help us navigate the 3D table. - // Ex: Assume x = a, y = b, z = c. - // table[a * n001 + b * n010 + c * n100] logically equals table[a][b][c]. - const int n000 = 0; - const int n001 = 3 * colorLUT->fGridPoints[1] * colorLUT->fGridPoints[2]; - const int n010 = 3 * colorLUT->fGridPoints[2]; - const int n011 = n001 + n010; - const int n100 = 3; - const int n101 = n100 + n001; - const int n110 = n100 + n010; - const int n111 = n110 + n001; - - // Base ptr into the table. - const float* ptr = &(colorLUT->table()[ix*n001 + iy*n010 + iz*n100]); - - // The code below performs a tetrahedral interpolation for each of the three - // dst components. Once the tetrahedron containing the interpolation point is - // identified, the interpolation is a weighted sum of grid values at the - // vertices of the tetrahedron. The claim is that tetrahedral interpolation - // provides a more accurate color conversion. - // blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colorspace-conversion/ - // - // I have one test image, and visually I can't tell the difference between - // tetrahedral and trilinear interpolation. In terms of computation, the - // tetrahedral code requires more branches but less computation. The - // SampleICC library provides an option for the client to choose either - // tetrahedral or trilinear. - for (int i = 0; i < 3; i++) { - if (diffZ < diffY) { - if (diffZ < diffX) { - dst[i] = (ptr[n000] + diffZ * (ptr[n110] - ptr[n010]) + - diffY * (ptr[n010] - ptr[n000]) + - diffX * (ptr[n111] - ptr[n110])); - } else if (diffY < diffX) { - dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + - diffY * (ptr[n011] - ptr[n001]) + - diffX * (ptr[n001] - ptr[n000])); - } else { - dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + - diffY * (ptr[n010] - ptr[n000]) + - diffX * (ptr[n011] - ptr[n010])); - } - } else { - if (diffZ < diffX) { - dst[i] = (ptr[n000] + diffZ * (ptr[n101] - ptr[n001]) + - diffY * (ptr[n111] - ptr[n101]) + - diffX * (ptr[n001] - ptr[n000])); - } else if (diffY < diffX) { - dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + - diffY * (ptr[n111] - ptr[n101]) + - diffX * (ptr[n101] - ptr[n100])); - } else { - dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + - diffY * (ptr[n110] - ptr[n100]) + - diffX * (ptr[n111] - ptr[n110])); - } - } - - // Increment the table ptr in order to handle the next component. - // Note that this is the how table is designed: all of nXXX - // variables are multiples of 3 because there are 3 output - // components. - ptr++; - } -} - -static void handle_color_lut(uint32_t* dst, const uint32_t* src, int len, - SkColorLookUpTable* colorLUT) { - while (len-- > 0) { - uint8_t r = (*src >> 0) & 0xFF, - g = (*src >> 8) & 0xFF, - b = (*src >> 16) & 0xFF; - - float in[3]; - float out[3]; - in[0] = byte_to_float(r); - in[1] = byte_to_float(g); - in[2] = byte_to_float(b); - interp_3d_clut(out, in, colorLUT); - - r = sk_float_round2int(255.0f * clamp_normalized_float(out[0])); - g = sk_float_round2int(255.0f * clamp_normalized_float(out[1])); - b = sk_float_round2int(255.0f * clamp_normalized_float(out[2])); - *dst = SkPackARGB_as_RGBA(0xFF, r, g, b); - - src++; - dst++; - } -} - -static inline void load_matrix(const float matrix[16], - Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) { - rXgXbX = Sk4f::Load(matrix + 0); - rYgYbY = Sk4f::Load(matrix + 4); - rZgZbZ = Sk4f::Load(matrix + 8); - rTgTbT = Sk4f::Load(matrix + 12); +static AI void load_matrix(const float matrix[13], + Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) { + rXgXbX = Sk4f::Load(matrix + 0); + rYgYbY = Sk4f::Load(matrix + 3); + rZgZbZ = Sk4f::Load(matrix + 6); + rTgTbT = Sk4f::Load(matrix + 9); } enum Order { @@ -621,7 +364,7 @@ enum Order { kBGRA_Order, }; -static inline void set_rb_shifts(Order kOrder, int* kRShift, int* kBShift) { +static AI void set_rb_shifts(Order kOrder, int* kRShift, int* kBShift) { if (kRGBA_Order == kOrder) { *kRShift = 0; *kBShift = 16; @@ -632,9 +375,9 @@ static inline void set_rb_shifts(Order kOrder, int* kRShift, int* kBShift) { } template -static inline void load_rgb_from_tables(const uint32_t* src, - Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, - const float* const srcTables[3]) { +static AI void load_rgb_from_tables(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const srcTables[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); r = { srcTables[0][(src[0] >> kRShift) & 0xFF], @@ -653,9 +396,9 @@ static inline void load_rgb_from_tables(const uint32_t* src, } template -static inline void load_rgba_from_tables(const uint32_t* src, - Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, - const float* const srcTables[3]) { +static AI void load_rgba_from_tables(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const srcTables[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); r = { srcTables[0][(src[0] >> kRShift) & 0xFF], @@ -674,9 +417,8 @@ static inline void load_rgba_from_tables(const uint32_t* src, } template -static inline void load_rgb_linear(const uint32_t* src, - Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, - const float* const[3]) { +static AI void load_rgb_linear(const uint32_t* src, Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); r = (1.0f / 255.0f) * SkNx_cast((Sk4u::Load(src) >> kRShift) & 0xFF); @@ -686,9 +428,8 @@ static inline void load_rgb_linear(const uint32_t* src, } template -static inline void load_rgba_linear(const uint32_t* src, - Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, - const float* const[3]) { +static AI void load_rgba_linear(const uint32_t* src, Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); r = (1.0f / 255.0f) * SkNx_cast((Sk4u::Load(src) >> kRShift) & 0xFF); @@ -698,20 +439,21 @@ static inline void load_rgba_linear(const uint32_t* src, } template -static inline void load_rgb_from_tables_1(const uint32_t* src, - Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&, - const float* const srcTables[3]) { +static AI void load_rgb_from_tables_1(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const srcTables[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]); g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]); b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]); + a = 0.0f; // Don't let MSAN complain that |a| is uninitialized. } template -static inline void load_rgba_from_tables_1(const uint32_t* src, - Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, - const float* const srcTables[3]) { +static AI void load_rgba_from_tables_1(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const srcTables[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]); @@ -721,20 +463,21 @@ static inline void load_rgba_from_tables_1(const uint32_t* src, } template -static inline void load_rgb_linear_1(const uint32_t* src, - Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&, - const float* const srcTables[3]) { +static AI void load_rgb_linear_1(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const srcTables[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF)); g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF)); b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF)); + a = 0.0f; // Don't let MSAN complain that |a| is uninitialized. } template -static inline void load_rgba_linear_1(const uint32_t* src, - Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, - const float* const srcTables[3]) { +static AI void load_rgba_linear_1(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const srcTables[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF)); @@ -743,45 +486,34 @@ static inline void load_rgba_linear_1(const uint32_t* src, a = Sk4f((1.0f / 255.0f) * ((*src >> 24))); } -static inline void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a, - const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ, - Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) { +static AI void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a, + const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) { dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b; dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b; db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b; da = a; } -static inline void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b, - const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ, - Sk4f& rgba) { +static AI void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b, + const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ, + Sk4f& rgba) { rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b; } -static inline void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) { +static AI void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) { dr = dr + rTgTbT[0]; dg = dg + rTgTbT[1]; db = db + rTgTbT[2]; } -static inline void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) { +static AI void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) { rgba = rgba + rTgTbT; } -static inline void premultiply(Sk4f& dr, Sk4f& dg, Sk4f& db, const Sk4f& da) { - dr = da * dr; - dg = da * dg; - db = da * db; -} - -static inline void premultiply_1(const Sk4f& a, Sk4f& rgba) { - rgba = a * rgba; -} - template -static inline void store_srgb(void* dst, const uint32_t* src, - Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, - const uint8_t* const[3]) { +static AI void store_srgb(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, + const uint8_t* const[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); dr = sk_linear_to_srgb_needs_trunc(dr); @@ -802,9 +534,9 @@ static inline void store_srgb(void* dst, const uint32_t* src, } template -static inline void store_srgb_1(void* dst, const uint32_t* src, - Sk4f& rgba, const Sk4f&, - const uint8_t* const[3]) { +static AI void store_srgb_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f&, + const uint8_t* const[3]) { rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba)); uint32_t tmp; @@ -817,7 +549,7 @@ static inline void store_srgb_1(void* dst, const uint32_t* src, *(uint32_t*)dst = tmp; } -static inline Sk4f linear_to_2dot2(const Sk4f& x) { +static AI Sk4f linear_to_2dot2(const Sk4f& x) { // x^(29/64) is a very good approximation of the true value, x^(1/2.2). auto x2 = x.rsqrt(), // x^(-1/2) x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(), // x^(-1/32) @@ -828,9 +560,8 @@ static inline Sk4f linear_to_2dot2(const Sk4f& x) { } template -static inline void store_2dot2(void* dst, const uint32_t* src, - Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, - const uint8_t* const[3]) { +static AI void store_2dot2(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, + const uint8_t* const[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); dr = linear_to_2dot2(dr); @@ -851,9 +582,9 @@ static inline void store_2dot2(void* dst, const uint32_t* src, } template -static inline void store_2dot2_1(void* dst, const uint32_t* src, - Sk4f& rgba, const Sk4f&, - const uint8_t* const[3]) { +static AI void store_2dot2_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f&, + const uint8_t* const[3]) { rgba = sk_clamp_0_255(linear_to_2dot2(rgba)); uint32_t tmp; @@ -867,9 +598,8 @@ static inline void store_2dot2_1(void* dst, const uint32_t* src, } template -static inline void store_linear(void* dst, const uint32_t* src, - Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, - const uint8_t* const[3]) { +static AI void store_linear(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, + const uint8_t* const[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); dr = sk_clamp_0_255(255.0f * dr); @@ -886,9 +616,9 @@ static inline void store_linear(void* dst, const uint32_t* src, } template -static inline void store_linear_1(void* dst, const uint32_t* src, - Sk4f& rgba, const Sk4f&, - const uint8_t* const[3]) { +static AI void store_linear_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f&, + const uint8_t* const[3]) { rgba = sk_clamp_0_255(255.0f * rgba); uint32_t tmp; @@ -902,62 +632,45 @@ static inline void store_linear_1(void* dst, const uint32_t* src, } template -static inline void store_f16(void* dst, const uint32_t* src, - Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da, - const uint8_t* const[3]) { - Sk4h_store4(dst, SkFloatToHalf_finite_ftz(dr), - SkFloatToHalf_finite_ftz(dg), - SkFloatToHalf_finite_ftz(db), - SkFloatToHalf_finite_ftz(da)); +static AI void store_f16(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da, + const uint8_t* const[3]) { + Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr), + SkFloatToHalf_finite_ftz(dg), + SkFloatToHalf_finite_ftz(db), + SkFloatToHalf_finite_ftz(da)); } template -static inline void store_f16_1(void* dst, const uint32_t* src, - Sk4f& rgba, const Sk4f& a, - const uint8_t* const[3]) { +static AI void store_f16_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f& a, + const uint8_t* const[3]) { rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]); SkFloatToHalf_finite_ftz(rgba).store((uint64_t*) dst); } template -static inline void store_f32(void* dst, const uint32_t* src, - Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da, - const uint8_t* const[3]) { - Sk4f_store4(dst, dr, dg, db, da); +static AI void store_f16_opaque(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, + Sk4f&, const uint8_t* const[3]) { + Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr), + SkFloatToHalf_finite_ftz(dg), + SkFloatToHalf_finite_ftz(db), + SK_Half1); } template -static inline void store_f32_1(void* dst, const uint32_t* src, - Sk4f& rgba, const Sk4f& a, - const uint8_t* const[3]) { - rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]); - rgba.store((float*) dst); -} - -template -static inline void store_f16_opaque(void* dst, const uint32_t* src, - Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, - const uint8_t* const[3]) { - Sk4h_store4(dst, SkFloatToHalf_finite_ftz(dr), - SkFloatToHalf_finite_ftz(dg), - SkFloatToHalf_finite_ftz(db), - SK_Half1); -} - -template -static inline void store_f16_1_opaque(void* dst, const uint32_t* src, - Sk4f& rgba, const Sk4f&, - const uint8_t* const[3]) { +static AI void store_f16_1_opaque(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f&, + const uint8_t* const[3]) { uint64_t tmp; SkFloatToHalf_finite_ftz(rgba).store(&tmp); + tmp &= 0x0000FFFFFFFFFFFF; tmp |= static_cast(SK_Half1) << 48; *((uint64_t*) dst) = tmp; } template -static inline void store_generic(void* dst, const uint32_t* src, - Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, - const uint8_t* const dstTables[3]) { +static AI void store_generic(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, + const uint8_t* const dstTables[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f); @@ -990,9 +703,9 @@ static inline void store_generic(void* dst, const uint32_t* src, } template -static inline void store_generic_1(void* dst, const uint32_t* src, - Sk4f& rgba, const Sk4f&, - const uint8_t* const dstTables[3]) { +static AI void store_generic_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f&, + const uint8_t* const dstTables[3]) { int kRShift, kGShift = 8, kBShift; set_rb_shifts(kOrder, &kRShift, &kBShift); rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f); @@ -1010,89 +723,6 @@ typedef decltype(load_rgb_from_tables_1)* Load1Fn; typedef decltype(store_generic )* StoreFn; typedef decltype(store_generic_1 )* Store1Fn; -template -static inline void do_color_xform(void* dst, const uint32_t* src, int len, - const float* const srcTables[3], const float matrix[16], - const uint8_t* const dstTables[3], LoadFn load, Load1Fn load_1, - StoreFn store, Store1Fn store_1, size_t sizeOfDstPixel) { - Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT; - load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT); - - if (len >= 4) { - // Naively this would be a loop of load-transform-store, but we found it faster to - // move the N+1th load ahead of the Nth store. We don't bother doing this for N<4. - Sk4f r, g, b, a; - load(src, r, g, b, a, srcTables); - src += 4; - len -= 4; - - Sk4f dr, dg, db, da; - while (len >= 4) { - if (kNone_ColorSpaceMatch == kCSM) { - transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da); - translate_gamut(rTgTbT, dr, dg, db); - } else { - dr = r; - dg = g; - db = b; - da = a; - } - - if (kPremul_SkAlphaType == kAlphaType) { - premultiply(dr, dg, db, da); - } - - load(src, r, g, b, a, srcTables); - - store(dst, src - 4, dr, dg, db, da, dstTables); - dst = SkTAddOffset(dst, 4 * sizeOfDstPixel); - src += 4; - len -= 4; - } - - if (kNone_ColorSpaceMatch == kCSM) { - transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da); - translate_gamut(rTgTbT, dr, dg, db); - } else { - dr = r; - dg = g; - db = b; - da = a; - } - - if (kPremul_SkAlphaType == kAlphaType) { - premultiply(dr, dg, db, da); - } - - store(dst, src - 4, dr, dg, db, da, dstTables); - dst = SkTAddOffset(dst, 4 * sizeOfDstPixel); - } - - while (len > 0) { - Sk4f r, g, b, a; - load_1(src, r, g, b, a, srcTables); - - Sk4f rgba; - if (kNone_ColorSpaceMatch == kCSM) { - transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba); - translate_gamut_1(rTgTbT, rgba); - } else { - rgba = Sk4f(r[0], g[0], b[0], a[0]); - } - - if (kPremul_SkAlphaType == kAlphaType) { - premultiply_1(a, rgba); - } - - store_1(dst, src, rgba, a, dstTables); - - src += 1; - len -= 1; - dst = SkTAddOffset(dst, sizeOfDstPixel); - } -} - enum SrcFormat { kRGBA_8888_Linear_SrcFormat, kRGBA_8888_Table_SrcFormat, @@ -1110,24 +740,21 @@ enum DstFormat { kBGRA_8888_2Dot2_DstFormat, kBGRA_8888_Table_DstFormat, kF16_Linear_DstFormat, - kF32_Linear_DstFormat, }; template -static void color_xform_RGBA(void* dst, const uint32_t* src, int len, - const float* const srcTables[3], const float matrix[16], +static void color_xform_RGBA(void* dst, const void* vsrc, int len, + const float* const srcTables[3], const float matrix[13], const uint8_t* const dstTables[3]) { LoadFn load; Load1Fn load_1; - static constexpr bool loadAlpha = (kPremul_SkAlphaType == kAlphaType) || - (kF16_Linear_DstFormat == kDst) || - (kF32_Linear_DstFormat == kDst); + const bool kLoadAlpha = kF16_Linear_DstFormat == kDst && kOpaque_SkAlphaType != kAlphaType; switch (kSrc) { case kRGBA_8888_Linear_SrcFormat: - if (loadAlpha) { + if (kLoadAlpha) { load = load_rgba_linear; load_1 = load_rgba_linear_1; } else { @@ -1136,7 +763,7 @@ static void color_xform_RGBA(void* dst, const uint32_t* src, int len, } break; case kRGBA_8888_Table_SrcFormat: - if (loadAlpha) { + if (kLoadAlpha) { load = load_rgba_from_tables; load_1 = load_rgba_from_tables_1; } else { @@ -1145,7 +772,7 @@ static void color_xform_RGBA(void* dst, const uint32_t* src, int len, } break; case kBGRA_8888_Linear_SrcFormat: - if (loadAlpha) { + if (kLoadAlpha) { load = load_rgba_linear; load_1 = load_rgba_linear_1; } else { @@ -1154,7 +781,7 @@ static void color_xform_RGBA(void* dst, const uint32_t* src, int len, } break; case kBGRA_8888_Table_SrcFormat: - if (loadAlpha) { + if (kLoadAlpha) { load = load_rgba_from_tables; load_1 = load_rgba_from_tables_1; } else { @@ -1215,28 +842,84 @@ static void color_xform_RGBA(void* dst, const uint32_t* src, int len, store_f16_1; sizeOfDstPixel = 8; break; - case kF32_Linear_DstFormat: - store = store_f32; - store_1 = store_f32_1; - sizeOfDstPixel = 16; - break; } - do_color_xform - (dst, src, len, srcTables, matrix, dstTables, load, load_1, store, store_1, - sizeOfDstPixel); + const uint32_t* src = (const uint32_t*) vsrc; + Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT; + load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT); + + if (len >= 4) { + // Naively this would be a loop of load-transform-store, but we found it faster to + // move the N+1th load ahead of the Nth store. We don't bother doing this for N<4. + Sk4f r, g, b, a; + load(src, r, g, b, a, srcTables); + src += 4; + len -= 4; + + Sk4f dr, dg, db, da; + while (len >= 4) { + if (kNone_ColorSpaceMatch == kCSM) { + transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da); + translate_gamut(rTgTbT, dr, dg, db); + } else { + dr = r; + dg = g; + db = b; + da = a; + } + + load(src, r, g, b, a, srcTables); + + store(dst, src - 4, dr, dg, db, da, dstTables); + dst = SkTAddOffset(dst, 4 * sizeOfDstPixel); + src += 4; + len -= 4; + } + + if (kNone_ColorSpaceMatch == kCSM) { + transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da); + translate_gamut(rTgTbT, dr, dg, db); + } else { + dr = r; + dg = g; + db = b; + da = a; + } + + store(dst, src - 4, dr, dg, db, da, dstTables); + dst = SkTAddOffset(dst, 4 * sizeOfDstPixel); + } + + while (len > 0) { + Sk4f r, g, b, a; + load_1(src, r, g, b, a, srcTables); + + Sk4f rgba; + if (kNone_ColorSpaceMatch == kCSM) { + transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba); + translate_gamut_1(rTgTbT, rgba); + } else { + rgba = Sk4f(r[0], g[0], b[0], a[0]); + } + + store_1(dst, src, rgba, a, dstTables); + + src += 1; + len -= 1; + dst = SkTAddOffset(dst, sizeOfDstPixel); + } } /////////////////////////////////////////////////////////////////////////////////////////////////// -static inline int num_tables(SkColorSpace* space) { - switch (as_CSB(space)->gammaNamed()) { +static AI int num_tables(SkColorSpace_XYZ* space) { + switch (space->gammaNamed()) { case kSRGB_SkGammaNamed: case k2Dot2Curve_SkGammaNamed: case kLinear_SkGammaNamed: return 0; default: { - const SkGammas* gammas = as_CSB(space)->gammas(); + const SkGammas* gammas = space->gammas(); SkASSERT(gammas); bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) && @@ -1251,190 +934,375 @@ static inline int num_tables(SkColorSpace* space) { } } -template -SkColorSpaceXform_Base -::SkColorSpaceXform_Base(SkColorSpace* srcSpace, const SkMatrix44& srcToDst, SkColorSpace* dstSpace) - : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) +template +SkColorSpaceXform_XYZ +::SkColorSpaceXform_XYZ(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst, + SkColorSpace_XYZ* dstSpace, SkTransferFunctionBehavior premulBehavior) + : fPremulBehavior(premulBehavior) { - srcToDst.asColMajorf(fSrcToDst); + fSrcToDst[ 0] = srcToDst.get(0, 0); + fSrcToDst[ 1] = srcToDst.get(1, 0); + fSrcToDst[ 2] = srcToDst.get(2, 0); + fSrcToDst[ 3] = srcToDst.get(0, 1); + fSrcToDst[ 4] = srcToDst.get(1, 1); + fSrcToDst[ 5] = srcToDst.get(2, 1); + fSrcToDst[ 6] = srcToDst.get(0, 2); + fSrcToDst[ 7] = srcToDst.get(1, 2); + fSrcToDst[ 8] = srcToDst.get(2, 2); + fSrcToDst[ 9] = srcToDst.get(0, 3); + fSrcToDst[10] = srcToDst.get(1, 3); + fSrcToDst[11] = srcToDst.get(2, 3); + fSrcToDst[12] = 0.0f; const int numSrcTables = num_tables(srcSpace); - const int numDstTables = num_tables(dstSpace); - const size_t srcTableBytes = numSrcTables * 256 * sizeof(float); - const size_t dstTableBytes = numDstTables * kDstGammaTableSize * sizeof(uint8_t); - fStorage.reset(srcTableBytes + dstTableBytes); - float* srcStorage = (float*) fStorage.get(); - uint8_t* dstStorage = SkTAddOffset(fStorage.get(), srcTableBytes); - + const size_t srcEntries = numSrcTables * 256; const bool srcGammasAreMatching = (1 >= numSrcTables); - const bool dstGammasAreMatching = (1 >= numDstTables); - build_gamma_tables(fSrcGammaTables, srcStorage, 256, srcSpace, kToLinear, srcGammasAreMatching); - build_gamma_tables(fDstGammaTables, dstStorage, kDstGammaTableSize, dstSpace, kFromLinear, - dstGammasAreMatching); + fSrcStorage.reset(srcEntries); + build_gamma_tables(fSrcGammaTables, fSrcStorage.get(), 256, srcSpace, kToLinear, + srcGammasAreMatching); + + const int numDstTables = num_tables(dstSpace); + dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables); + + if (srcSpace->gammaIsLinear()) { + fSrcGamma = kLinear_SrcGamma; + } else if (kSRGB_SkGammaNamed == srcSpace->gammaNamed()) { + fSrcGamma = kSRGB_SrcGamma; + } else { + fSrcGamma = kTable_SrcGamma; + } + + switch (dstSpace->gammaNamed()) { + case kSRGB_SkGammaNamed: + fDstGamma = kSRGB_DstGamma; + break; + case k2Dot2Curve_SkGammaNamed: + fDstGamma = k2Dot2_DstGamma; + break; + case kLinear_SkGammaNamed: + fDstGamma = kLinear_DstGamma; + break; + default: + fDstGamma = kTable_DstGamma; + break; + } } /////////////////////////////////////////////////////////////////////////////////////////////////// template -static inline void apply_set_alpha(void* dst, const uint32_t* src, int len, SkAlphaType alphaType, - const float* const srcTables[3], const float matrix[16], - const uint8_t* const dstTables[3]) { +static AI bool apply_set_alpha(void* dst, const void* src, int len, SkAlphaType alphaType, + const float* const srcTables[3], const float matrix[13], + const uint8_t* const dstTables[3]) { switch (alphaType) { case kOpaque_SkAlphaType: - return color_xform_RGBA - (dst, src, len, srcTables, matrix, dstTables); - case kPremul_SkAlphaType: - return color_xform_RGBA + color_xform_RGBA (dst, src, len, srcTables, matrix, dstTables); + return true; case kUnpremul_SkAlphaType: - return color_xform_RGBA + color_xform_RGBA (dst, src, len, srcTables, matrix, dstTables); + return true; default: - SkASSERT(false); - return; + return false; } } -template -static inline void apply_set_src(void* dst, const uint32_t* src, int len, SkAlphaType alphaType, - const float* const srcTables[3], const float matrix[16], - const uint8_t* const dstTables[3], - SkColorSpaceXform::ColorFormat srcColorFormat) { +template +static AI bool apply_set_src(void* dst, const void* src, int len, SkAlphaType alphaType, + const float* const srcTables[3], const float matrix[13], + const uint8_t* const dstTables[3], + SkColorSpaceXform::ColorFormat srcColorFormat, + SrcGamma srcGamma) { switch (srcColorFormat) { case SkColorSpaceXform::kRGBA_8888_ColorFormat: - switch (kSrc) { + switch (srcGamma) { case kLinear_SrcGamma: return apply_set_alpha (dst, src, len, alphaType, nullptr, matrix, dstTables); - case kTable_SrcGamma: + default: return apply_set_alpha (dst, src, len, alphaType, srcTables, matrix, dstTables); } case SkColorSpaceXform::kBGRA_8888_ColorFormat: - switch (kSrc) { + switch (srcGamma) { case kLinear_SrcGamma: return apply_set_alpha (dst, src, len, alphaType, nullptr, matrix, dstTables); - case kTable_SrcGamma: + default: return apply_set_alpha (dst, src, len, alphaType, srcTables, matrix, dstTables); } default: - SkASSERT(false); + return false; } } -template -void SkColorSpaceXform_Base -::apply(void* dst, const uint32_t* src, int len, ColorFormat dstColorFormat, - ColorFormat srcColorFormat, SkAlphaType alphaType) -const +#undef AI + +template +bool SkColorSpaceXform_XYZ +::onApply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat, const void* src, + int len, SkAlphaType alphaType) const { if (kFull_ColorSpaceMatch == kCSM) { - switch (alphaType) { - case kPremul_SkAlphaType: - // We can't skip the xform since we need to perform a premultiply in the - // linear space. - break; - default: - switch (dstColorFormat) { - case kRGBA_8888_ColorFormat: - return (void) memcpy(dst, src, len * sizeof(uint32_t)); - case kBGRA_8888_ColorFormat: - return SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len); - case kRGBA_F16_ColorFormat: - case kRGBA_F32_ColorFormat: - // There's still work to do to xform to linear floats. - break; - default: - SkASSERT(false); - return; - } + if (kPremul_SkAlphaType != alphaType) { + if ((kRGBA_8888_ColorFormat == dstColorFormat && + kRGBA_8888_ColorFormat == srcColorFormat) || + (kBGRA_8888_ColorFormat == dstColorFormat && + kBGRA_8888_ColorFormat == srcColorFormat)) + { + memcpy(dst, src, len * sizeof(uint32_t)); + return true; + } + if ((kRGBA_8888_ColorFormat == dstColorFormat && + kBGRA_8888_ColorFormat == srcColorFormat) || + (kBGRA_8888_ColorFormat == dstColorFormat && + kRGBA_8888_ColorFormat == srcColorFormat)) + { + SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len); + return true; + } } } -#if defined(GOOGLE3) - // Stack frame size is limited in GOOGLE3. - SkAutoSMalloc<256 * sizeof(uint32_t)> storage; -#else - SkAutoSMalloc<1024 * sizeof(uint32_t)> storage; -#endif - if (fColorLUT) { - size_t storageBytes = len * sizeof(uint32_t); - storage.reset(storageBytes); - handle_color_lut((uint32_t*) storage.get(), src, len, fColorLUT.get()); - src = (const uint32_t*) storage.get(); + if (kRGBA_F32_ColorFormat == dstColorFormat || + kBGR_565_ColorFormat == dstColorFormat || + kRGBA_F32_ColorFormat == srcColorFormat || + kRGBA_F16_ColorFormat == srcColorFormat || + kRGBA_U16_BE_ColorFormat == srcColorFormat || + kRGB_U16_BE_ColorFormat == srcColorFormat || + kPremul_SkAlphaType == alphaType) + { + return this->applyPipeline(dstColorFormat, dst, srcColorFormat, src, len, alphaType); } switch (dstColorFormat) { case kRGBA_8888_ColorFormat: - switch (kDst) { + switch (fDstGamma) { case kLinear_DstGamma: - return apply_set_src + return apply_set_src (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, - srcColorFormat); + srcColorFormat, fSrcGamma); case kSRGB_DstGamma: - return apply_set_src + return apply_set_src (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, - srcColorFormat); + srcColorFormat, fSrcGamma); case k2Dot2_DstGamma: - return apply_set_src + return apply_set_src (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, - srcColorFormat); + srcColorFormat, fSrcGamma); case kTable_DstGamma: - return apply_set_src + return apply_set_src (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables, - srcColorFormat); + srcColorFormat, fSrcGamma); } case kBGRA_8888_ColorFormat: - switch (kDst) { + switch (fDstGamma) { case kLinear_DstGamma: - return apply_set_src + return apply_set_src (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, - srcColorFormat); + srcColorFormat, fSrcGamma); case kSRGB_DstGamma: - return apply_set_src + return apply_set_src (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, - srcColorFormat); + srcColorFormat, fSrcGamma); case k2Dot2_DstGamma: - return apply_set_src + return apply_set_src (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, - srcColorFormat); + srcColorFormat, fSrcGamma); case kTable_DstGamma: - return apply_set_src + return apply_set_src (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables, - srcColorFormat); + srcColorFormat, fSrcGamma); } case kRGBA_F16_ColorFormat: - switch (kDst) { + switch (fDstGamma) { case kLinear_DstGamma: - return apply_set_src + return apply_set_src (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, - srcColorFormat); + srcColorFormat, fSrcGamma); default: - SkASSERT(false); - return; - } - case kRGBA_F32_ColorFormat: - switch (kDst) { - case kLinear_DstGamma: - return apply_set_src - (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, - srcColorFormat); - default: - SkASSERT(false); - return; + return false; } default: SkASSERT(false); - return; + return false; } } +bool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat, + const void* src, int len, SkAlphaType alphaType) const { + return ((SkColorSpaceXform_Base*) this)->onApply(dstColorFormat, dst, srcColorFormat, src, len, + alphaType); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// -std::unique_ptr SlowIdentityXform(SkColorSpace* space) { - return std::unique_ptr(new SkColorSpaceXform_Base - - (space, SkMatrix::I(), space)); +template +bool SkColorSpaceXform_XYZ +::applyPipeline(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat, + const void* src, int len, SkAlphaType alphaType) const { + SkRasterPipeline pipeline; + + LoadTablesContext loadTables; + switch (srcColorFormat) { + case kRGBA_8888_ColorFormat: + if (kLinear_SrcGamma == fSrcGamma) { + pipeline.append(SkRasterPipeline::load_8888, &src); + } else { + loadTables.fSrc = src; + loadTables.fR = fSrcGammaTables[0]; + loadTables.fG = fSrcGammaTables[1]; + loadTables.fB = fSrcGammaTables[2]; + pipeline.append(SkRasterPipeline::load_tables, &loadTables); + } + + break; + case kBGRA_8888_ColorFormat: + if (kLinear_SrcGamma == fSrcGamma) { + pipeline.append(SkRasterPipeline::load_8888, &src); + } else { + loadTables.fSrc = src; + loadTables.fR = fSrcGammaTables[2]; + loadTables.fG = fSrcGammaTables[1]; + loadTables.fB = fSrcGammaTables[0]; + pipeline.append(SkRasterPipeline::load_tables, &loadTables); + } + + pipeline.append(SkRasterPipeline::swap_rb); + break; + case kRGBA_F16_ColorFormat: + if (kLinear_SrcGamma != fSrcGamma) { + return false; + } + pipeline.append(SkRasterPipeline::load_f16, &src); + break; + case kRGBA_F32_ColorFormat: + if (kLinear_SrcGamma != fSrcGamma) { + return false; + } + pipeline.append(SkRasterPipeline::load_f32, &src); + break; + case kRGBA_U16_BE_ColorFormat: + switch (fSrcGamma) { + case kLinear_SrcGamma: + pipeline.append(SkRasterPipeline::load_u16_be, &src); + break; + case kSRGB_SrcGamma: + pipeline.append(SkRasterPipeline::load_u16_be, &src); + pipeline.append_from_srgb(kUnpremul_SkAlphaType); + break; + case kTable_SrcGamma: + loadTables.fSrc = src; + loadTables.fR = fSrcGammaTables[0]; + loadTables.fG = fSrcGammaTables[1]; + loadTables.fB = fSrcGammaTables[2]; + pipeline.append(SkRasterPipeline::load_tables_u16_be, &loadTables); + break; + } + break; + case kRGB_U16_BE_ColorFormat: + switch (fSrcGamma) { + case kLinear_SrcGamma: + pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src); + break; + case kSRGB_SrcGamma: + pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src); + pipeline.append_from_srgb(kUnpremul_SkAlphaType); + break; + case kTable_SrcGamma: + loadTables.fSrc = src; + loadTables.fR = fSrcGammaTables[0]; + loadTables.fG = fSrcGammaTables[1]; + loadTables.fB = fSrcGammaTables[2]; + pipeline.append(SkRasterPipeline::load_tables_rgb_u16_be, &loadTables); + break; + } + break; + default: + return false; + } + + if (kNone_ColorSpaceMatch == kCSM) { + pipeline.append(SkRasterPipeline::matrix_3x4, fSrcToDst); + + if (kRGBA_F16_ColorFormat != dstColorFormat && + kRGBA_F32_ColorFormat != dstColorFormat) + { + bool need_clamp_0, need_clamp_1; + analyze_3x4_matrix(fSrcToDst, &need_clamp_0, &need_clamp_1); + + if (need_clamp_0) { pipeline.append(SkRasterPipeline::clamp_0); } + if (need_clamp_1) { pipeline.append(SkRasterPipeline::clamp_1); } + } + } + + if (kPremul_SkAlphaType == alphaType && SkTransferFunctionBehavior::kRespect == fPremulBehavior) + { + pipeline.append(SkRasterPipeline::premul); + } + + TablesContext tables; + switch (fDstGamma) { + case kSRGB_DstGamma: + pipeline.append(SkRasterPipeline::to_srgb); + break; + case k2Dot2_DstGamma: + pipeline.append(SkRasterPipeline::to_2dot2); + break; + case kTable_DstGamma: + tables.fR = fDstGammaTables[0]; + tables.fG = fDstGammaTables[1]; + tables.fB = fDstGammaTables[2]; + tables.fCount = SkColorSpaceXform_Base::kDstGammaTableSize; + pipeline.append(SkRasterPipeline::byte_tables_rgb, &tables); + default: + break; + } + + if (kPremul_SkAlphaType == alphaType && SkTransferFunctionBehavior::kIgnore == fPremulBehavior) + { + pipeline.append(SkRasterPipeline::premul); + } + + switch (dstColorFormat) { + case kRGBA_8888_ColorFormat: + pipeline.append(SkRasterPipeline::store_8888, &dst); + break; + case kBGRA_8888_ColorFormat: + pipeline.append(SkRasterPipeline::swap_rb); + pipeline.append(SkRasterPipeline::store_8888, &dst); + break; + case kRGBA_F16_ColorFormat: + if (kLinear_DstGamma != fDstGamma) { + return false; + } + pipeline.append(SkRasterPipeline::store_f16, &dst); + break; + case kRGBA_F32_ColorFormat: + if (kLinear_DstGamma != fDstGamma) { + return false; + } + pipeline.append(SkRasterPipeline::store_f32, &dst); + break; + case kBGR_565_ColorFormat: + if (kOpaque_SkAlphaType != alphaType) { + return false; + } + pipeline.append(SkRasterPipeline::store_565, &dst); + break; + default: + return false; + } + + pipeline.run(0, len); + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +std::unique_ptr SlowIdentityXform(SkColorSpace_XYZ* space) { + return std::unique_ptr(new SkColorSpaceXform_XYZ + (space, SkMatrix::I(), space, SkTransferFunctionBehavior::kRespect)); } diff --git a/gfx/skia/skia/src/core/SkColorSpaceXform.h b/gfx/skia/skia/src/core/SkColorSpaceXform.h deleted file mode 100644 index bb99071fe033..000000000000 --- a/gfx/skia/skia/src/core/SkColorSpaceXform.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkColorSpaceXform_DEFINED -#define SkColorSpaceXform_DEFINED - -#include "SkColorSpace.h" -#include "SkColorSpace_Base.h" -#include "SkImageInfo.h" - -class SkColorSpaceXform : SkNoncopyable { -public: - - /** - * Create an object to handle color space conversions. - * - * @param srcSpace The encoded color space. - * @param dstSpace The destination color space. - * - */ - static std::unique_ptr New(SkColorSpace* srcSpace, SkColorSpace* dstSpace); - - enum ColorFormat : uint8_t { - kRGBA_8888_ColorFormat, - kBGRA_8888_ColorFormat, - kRGBA_F16_ColorFormat, - kRGBA_F32_ColorFormat, - }; - - /** - * Apply the color conversion to a |src| buffer, storing the output in the |dst| buffer. - * - * @param dst Stored in the format described by |dstColorFormat| - * @param src Stored in the format described by |srcColorFormat| - * @param len Number of pixels in the buffers - * @param dstColorFormat Describes color format of |dst| - * @param srcColorFormat Describes color format of |src| - * Must be kRGBA_8888 or kBGRA_8888 - * @param alphaType Describes alpha properties of the |dst| (and |src|) - * kUnpremul preserves input alpha values - * kPremul performs a premultiplication and also preserves alpha values - * kOpaque optimization hint, |dst| alphas set to 1 - * - */ - virtual void apply(void* dst, const uint32_t* src, int len, ColorFormat dstColorFormat, - ColorFormat srcColorFormat, SkAlphaType alphaType) const = 0; - - virtual ~SkColorSpaceXform() {} -}; - -enum SrcGamma { - kLinear_SrcGamma, - kTable_SrcGamma, -}; - -enum DstGamma { - kLinear_DstGamma, - kSRGB_DstGamma, - k2Dot2_DstGamma, - kTable_DstGamma, -}; - -enum ColorSpaceMatch { - kNone_ColorSpaceMatch, - kGamut_ColorSpaceMatch, - kFull_ColorSpaceMatch, -}; - -template -class SkColorSpaceXform_Base : public SkColorSpaceXform { -public: - - void apply(void* dst, const uint32_t* src, int len, ColorFormat dstColorFormat, - ColorFormat srcColorFormat, SkAlphaType alphaType) const override; - - static constexpr int kDstGammaTableSize = 1024; - -private: - SkColorSpaceXform_Base(SkColorSpace* srcSpace, const SkMatrix44& srcToDst, - SkColorSpace* dstSpace); - - sk_sp fColorLUT; - - // Contain pointers into storage or pointers into precomputed tables. - const float* fSrcGammaTables[3]; - const uint8_t* fDstGammaTables[3]; - SkAutoMalloc fStorage; - - float fSrcToDst[16]; - - friend class SkColorSpaceXform; - friend std::unique_ptr SlowIdentityXform(SkColorSpace* space); -}; - -// For testing. Bypasses opts for when src and dst color spaces are equal. -std::unique_ptr SlowIdentityXform(SkColorSpace* space); - -#endif diff --git a/gfx/skia/skia/src/core/SkColorSpaceXformCanvas.cpp b/gfx/skia/skia/src/core/SkColorSpaceXformCanvas.cpp new file mode 100644 index 000000000000..e85d4d02df38 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpaceXformCanvas.cpp @@ -0,0 +1,312 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorFilter.h" +#include "SkColorSpaceXformCanvas.h" +#include "SkColorSpaceXformer.h" +#include "SkGradientShader.h" +#include "SkImage_Base.h" +#include "SkImagePriv.h" +#include "SkMakeUnique.h" +#include "SkNoDrawCanvas.h" +#include "SkSurface.h" + +class SkColorSpaceXformCanvas : public SkNoDrawCanvas { +public: + SkColorSpaceXformCanvas(SkCanvas* target, sk_sp targetCS, + std::unique_ptr xformer) + : SkNoDrawCanvas(SkIRect::MakeSize(target->getBaseLayerSize())) + , fTarget(target) + , fTargetCS(targetCS) + , fXformer(std::move(xformer)) + { + // Set the matrix and clip to match |fTarget|. Otherwise, we'll answer queries for + // bounds/matrix differently than |fTarget| would. + SkCanvas::onClipRect(SkRect::Make(fTarget->getDeviceClipBounds()), + SkClipOp::kIntersect, kHard_ClipEdgeStyle); + SkCanvas::setMatrix(fTarget->getTotalMatrix()); + } + + SkImageInfo onImageInfo() const override { + return fTarget->imageInfo(); + } + + void onDrawPaint(const SkPaint& paint) override { + fTarget->drawPaint(fXformer->apply(paint)); + } + + void onDrawRect(const SkRect& rect, const SkPaint& paint) override { + fTarget->drawRect(rect, fXformer->apply(paint)); + } + void onDrawOval(const SkRect& oval, const SkPaint& paint) override { + fTarget->drawOval(oval, fXformer->apply(paint)); + } + void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override { + fTarget->drawRRect(rrect, fXformer->apply(paint)); + } + void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override { + fTarget->drawDRRect(outer, inner, fXformer->apply(paint)); + } + void onDrawPath(const SkPath& path, const SkPaint& paint) override { + fTarget->drawPath(path, fXformer->apply(paint)); + } + void onDrawArc(const SkRect& oval, SkScalar start, SkScalar sweep, bool useCenter, + const SkPaint& paint) override { + fTarget->drawArc(oval, start, sweep, useCenter, fXformer->apply(paint)); + } + void onDrawRegion(const SkRegion& region, const SkPaint& paint) override { + fTarget->drawRegion(region, fXformer->apply(paint)); + } + void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texs[4], + SkBlendMode mode, const SkPaint& paint) override { + SkColor xformed[4]; + if (colors) { + fXformer->apply(xformed, colors, 4); + colors = xformed; + } + + fTarget->drawPatch(cubics, colors, texs, mode, fXformer->apply(paint)); + } + void onDrawPoints(PointMode mode, size_t count, const SkPoint* pts, + const SkPaint& paint) override { + fTarget->drawPoints(mode, count, pts, fXformer->apply(paint)); + } + void onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode, + const SkPaint& paint) override { + sk_sp copy; + if (vertices->hasColors()) { + int count = vertices->vertexCount(); + SkSTArray<8, SkColor> xformed(count); + fXformer->apply(xformed.begin(), vertices->colors(), count); + copy = SkVertices::MakeCopy(vertices->mode(), count, vertices->positions(), + vertices->texCoords(), xformed.begin(), + vertices->indexCount(), vertices->indices()); + vertices = copy.get(); + } + + fTarget->drawVertices(vertices, mode, fXformer->apply(paint)); + } + + void onDrawText(const void* ptr, size_t len, + SkScalar x, SkScalar y, + const SkPaint& paint) override { + fTarget->drawText(ptr, len, x, y, fXformer->apply(paint)); + } + void onDrawPosText(const void* ptr, size_t len, + const SkPoint* xys, + const SkPaint& paint) override { + fTarget->drawPosText(ptr, len, xys, fXformer->apply(paint)); + } + void onDrawPosTextH(const void* ptr, size_t len, + const SkScalar* xs, SkScalar y, + const SkPaint& paint) override { + fTarget->drawPosTextH(ptr, len, xs, y, fXformer->apply(paint)); + } + void onDrawTextOnPath(const void* ptr, size_t len, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) override { + fTarget->drawTextOnPath(ptr, len, path, matrix, fXformer->apply(paint)); + } + void onDrawTextRSXform(const void* ptr, size_t len, + const SkRSXform* xforms, const SkRect* cull, + const SkPaint& paint) override { + fTarget->drawTextRSXform(ptr, len, xforms, cull, fXformer->apply(paint)); + } + void onDrawTextBlob(const SkTextBlob* blob, + SkScalar x, SkScalar y, + const SkPaint& paint) override { + fTarget->drawTextBlob(blob, x, y, fXformer->apply(paint)); + } + + void onDrawImage(const SkImage* img, + SkScalar l, SkScalar t, + const SkPaint* paint) override { + fTarget->drawImage(fXformer->apply(img).get(), + l, t, + fXformer->apply(paint)); + } + void onDrawImageRect(const SkImage* img, + const SkRect* src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint) override { + fTarget->drawImageRect(fXformer->apply(img).get(), + src ? *src : SkRect::MakeIWH(img->width(), img->height()), dst, + fXformer->apply(paint), constraint); + } + void onDrawImageNine(const SkImage* img, + const SkIRect& center, const SkRect& dst, + const SkPaint* paint) override { + fTarget->drawImageNine(fXformer->apply(img).get(), + center, dst, + fXformer->apply(paint)); + } + void onDrawImageLattice(const SkImage* img, + const Lattice& lattice, const SkRect& dst, + const SkPaint* paint) override { + fTarget->drawImageLattice(fXformer->apply(img).get(), + lattice, dst, + fXformer->apply(paint)); + } + void onDrawAtlas(const SkImage* atlas, const SkRSXform* xforms, const SkRect* tex, + const SkColor* colors, int count, SkBlendMode mode, + const SkRect* cull, const SkPaint* paint) override { + SkSTArray<8, SkColor> xformed; + if (colors) { + xformed.reset(count); + fXformer->apply(xformed.begin(), colors, count); + colors = xformed.begin(); + } + + fTarget->drawAtlas(fXformer->apply(atlas).get(), xforms, tex, colors, count, mode, cull, + fXformer->apply(paint)); + } + + void onDrawBitmap(const SkBitmap& bitmap, + SkScalar l, SkScalar t, + const SkPaint* paint) override { + if (this->skipXform(bitmap)) { + return fTarget->drawBitmap(bitmap, l, t, fXformer->apply(paint)); + } + + fTarget->drawImage(fXformer->apply(bitmap).get(), l, t, fXformer->apply(paint)); + } + void onDrawBitmapRect(const SkBitmap& bitmap, + const SkRect* src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint) override { + if (this->skipXform(bitmap)) { + return fTarget->drawBitmapRect(bitmap, + src ? *src : SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, + fXformer->apply(paint), constraint); + } + + fTarget->drawImageRect(fXformer->apply(bitmap).get(), + src ? *src : SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, + fXformer->apply(paint), constraint); + } + void onDrawBitmapNine(const SkBitmap& bitmap, + const SkIRect& center, const SkRect& dst, + const SkPaint* paint) override { + if (this->skipXform(bitmap)) { + return fTarget->drawBitmapNine(bitmap, center, dst, fXformer->apply(paint)); + } + + fTarget->drawImageNine(fXformer->apply(bitmap).get(), center, dst, fXformer->apply(paint)); + + } + void onDrawBitmapLattice(const SkBitmap& bitmap, + const Lattice& lattice, const SkRect& dst, + const SkPaint* paint) override { + if (this->skipXform(bitmap)) { + return fTarget->drawBitmapLattice(bitmap, lattice, dst, fXformer->apply(paint)); + } + + + fTarget->drawImageLattice(fXformer->apply(bitmap).get(), lattice, dst, + fXformer->apply(paint)); + } + + // TODO: May not be ideal to unfurl pictures. + void onDrawPicture(const SkPicture* pic, + const SkMatrix* matrix, + const SkPaint* paint) override { + SkCanvas::onDrawPicture(pic, matrix, fXformer->apply(paint)); + } + void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override { + SkCanvas::onDrawDrawable(drawable, matrix); + } + + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override { + fTarget->saveLayer({ + rec.fBounds, + fXformer->apply(rec.fPaint), + rec.fBackdrop, // TODO: this is an image filter + rec.fSaveLayerFlags, + }); + return kNoLayer_SaveLayerStrategy; + } + +#ifdef SK_SUPPORT_LEGACY_DRAWFILTER + SkDrawFilter* setDrawFilter(SkDrawFilter* filter) override { + SkCanvas::setDrawFilter(filter); + return fTarget->setDrawFilter(filter); + } +#endif + + // Everything from here on should be uninteresting strictly proxied state-change calls. + void willSave() override { fTarget->save(); } + void willRestore() override { fTarget->restore(); } + + void didConcat (const SkMatrix& m) override { fTarget->concat (m); } + void didSetMatrix(const SkMatrix& m) override { fTarget->setMatrix(m); } + + void onClipRect(const SkRect& clip, SkClipOp op, ClipEdgeStyle style) override { + SkCanvas::onClipRect(clip, op, style); + fTarget->clipRect(clip, op, style); + } + void onClipRRect(const SkRRect& clip, SkClipOp op, ClipEdgeStyle style) override { + SkCanvas::onClipRRect(clip, op, style); + fTarget->clipRRect(clip, op, style); + } + void onClipPath(const SkPath& clip, SkClipOp op, ClipEdgeStyle style) override { + SkCanvas::onClipPath(clip, op, style); + fTarget->clipPath(clip, op, style); + } + void onClipRegion(const SkRegion& clip, SkClipOp op) override { + SkCanvas::onClipRegion(clip, op); + fTarget->clipRegion(clip, op); + } + + void onDrawAnnotation(const SkRect& rect, const char* key, SkData* val) override { + fTarget->drawAnnotation(rect, key, val); + } + + sk_sp onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) override { + return fTarget->makeSurface(info, &props); + } + + SkISize getBaseLayerSize() const override { return fTarget->getBaseLayerSize(); } + SkRect onGetLocalClipBounds() const override { return fTarget->getLocalClipBounds(); } + SkIRect onGetDeviceClipBounds() const override { return fTarget->getDeviceClipBounds(); } + bool isClipEmpty() const override { return fTarget->isClipEmpty(); } + bool isClipRect() const override { return fTarget->isClipRect(); } + bool onPeekPixels(SkPixmap* pixmap) override { return fTarget->peekPixels(pixmap); } + bool onAccessTopLayerPixels(SkPixmap* pixmap) override { + SkImageInfo info; + size_t rowBytes; + SkIPoint* origin = nullptr; + void* addr = fTarget->accessTopLayerPixels(&info, &rowBytes, origin); + if (addr) { + *pixmap = SkPixmap(info, addr, rowBytes); + return true; + } + return false; + } + + bool onGetProps(SkSurfaceProps* props) const override { return fTarget->getProps(props); } + void onFlush() override { return fTarget->flush(); } + +private: + bool skipXform(const SkBitmap& bitmap) { + return (!bitmap.colorSpace() && fTargetCS->isSRGB()) || + (SkColorSpace::Equals(bitmap.colorSpace(), fTargetCS.get())) || + (kAlpha_8_SkColorType == bitmap.colorType()); + } + + SkCanvas* fTarget; + sk_sp fTargetCS; + std::unique_ptr fXformer; +}; + +std::unique_ptr SkCreateColorSpaceXformCanvas(SkCanvas* target, + sk_sp targetCS) { + std::unique_ptr xformer = SkColorSpaceXformer::Make(targetCS); + if (!xformer) { + return nullptr; + } + + return skstd::make_unique(target, std::move(targetCS), + std::move(xformer)); +} diff --git a/gfx/skia/skia/src/core/SkColorSpaceXformPriv.h b/gfx/skia/skia/src/core/SkColorSpaceXformPriv.h new file mode 100644 index 000000000000..405b1da018c1 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpaceXformPriv.h @@ -0,0 +1,103 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpaceXformPriv_DEFINED +#define SkColorSpaceXformPriv_DEFINED + +#include "SkColorSpace_Base.h" +#include "SkColorSpaceXform.h" +#include "SkHalf.h" +#include "SkSRGB.h" + +#define SkCSXformPrintfDefined 0 +#define SkCSXformPrintf(...) + +// Interpolating lookup in a variably sized table. +static inline float interp_lut(float input, const float* table, int tableSize) { + float index = input * (tableSize - 1); + float diff = index - sk_float_floor2int(index); + return table[(int) sk_float_floor2int(index)] * (1.0f - diff) + + table[(int) sk_float_ceil2int(index)] * diff; +} + +// Expand range from 0-1 to 0-255, then convert. +static inline uint8_t clamp_normalized_float_to_byte(float v) { + // The ordering of the logic is a little strange here in order + // to make sure we convert NaNs to 0. + v = v * 255.0f; + if (v >= 254.5f) { + return 255; + } else if (v >= 0.5f) { + return (uint8_t) (v + 0.5f); + } else { + return 0; + } +} + +static inline float clamp_0_1(float v) { + // The ordering of the logic is a little strange here in order + // to make sure we convert NaNs to 0. + if (v >= 1.0f) { + return 1.0f; + } else if (v >= 0.0f) { + return v; + } else { + return 0.0f; + } +} + +/** + * Invert table lookup. Ex: what indices corresponds to the input values? + * This will have strange results when the table is not increasing. + * But any sane gamma function will be increasing. + * @param outTableFloat Destination table for float (0-1) results. Can be nullptr if not wanted. + * @param outTableByte Destination table for byte (0-255) results. Can be nullptr if not wanted. + * @param outTableSize Number of elements in |outTableFloat| or |outTableBytes| + * @param inTable The source table to invert + * @param inTableSize The number of elements in |inTable| + */ +static inline void invert_table_gamma(float* outTableFloat, uint8_t* outTableByte, + int outTableSize, const float* inTable, int inTableSize) { + // should never have a gamma table this small anyway, 0/1 are either not allowed + // or imply a non-table gamma such as linear/exponential + SkASSERT(inTableSize >= 2); + int inIndex = 1; + for (int outIndex = 0; outIndex < outTableSize; ++outIndex) { + const float input = outIndex / (outTableSize - 1.0f); + while (inIndex < inTableSize - 1 && inTable[inIndex] < input) { + ++inIndex; + } + const float diff = input - inTable[inIndex - 1]; + const float distance = inTable[inIndex] - inTable[inIndex - 1]; + const float normalizedIndex = (inIndex - 1) + diff / distance; + const float index = normalizedIndex / (inTableSize - 1); + if (outTableByte) { + outTableByte[outIndex] = clamp_normalized_float_to_byte(index); + } + if (outTableFloat) { + outTableFloat[outIndex] = clamp_0_1(index); + } + } +} + +static inline SkColorSpaceXform::ColorFormat select_xform_format(SkColorType colorType) { + switch (colorType) { + case kRGBA_8888_SkColorType: + return SkColorSpaceXform::kRGBA_8888_ColorFormat; + case kBGRA_8888_SkColorType: + return SkColorSpaceXform::kBGRA_8888_ColorFormat; + case kRGBA_F16_SkColorType: + return SkColorSpaceXform::kRGBA_F16_ColorFormat; + case kRGB_565_SkColorType: + return SkColorSpaceXform::kBGR_565_ColorFormat; + default: + SkASSERT(false); + return SkColorSpaceXform::kRGBA_8888_ColorFormat; + } +} + +#endif diff --git a/gfx/skia/skia/src/core/SkColorSpaceXform_A2B.cpp b/gfx/skia/skia/src/core/SkColorSpaceXform_A2B.cpp new file mode 100644 index 000000000000..85fd42c1d457 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpaceXform_A2B.cpp @@ -0,0 +1,318 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorSpaceXform_A2B.h" + +#include "SkColorPriv.h" +#include "SkColorSpace_A2B.h" +#include "SkColorSpace_XYZ.h" +#include "SkColorSpacePriv.h" +#include "SkColorSpaceXformPriv.h" +#include "SkMakeUnique.h" +#include "SkNx.h" +#include "SkSRGB.h" +#include "SkTypes.h" + +bool SkColorSpaceXform_A2B::onApply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat, + const void* src, int count, SkAlphaType alphaType) const { + SkRasterPipeline pipeline; + switch (srcFormat) { + case kBGRA_8888_ColorFormat: + pipeline.append(SkRasterPipeline::load_8888, &src); + pipeline.append(SkRasterPipeline::swap_rb); + break; + case kRGBA_8888_ColorFormat: + pipeline.append(SkRasterPipeline::load_8888, &src); + break; + case kRGBA_U16_BE_ColorFormat: + pipeline.append(SkRasterPipeline::load_u16_be, &src); + break; + case kRGB_U16_BE_ColorFormat: + pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src); + break; + default: + SkCSXformPrintf("F16/F32 sources must be linear.\n"); + return false; + } + + pipeline.extend(fElementsPipeline); + + if (kPremul_SkAlphaType == alphaType) { + pipeline.append(SkRasterPipeline::premul); + } + + switch (dstFormat) { + case kBGRA_8888_ColorFormat: + pipeline.append(SkRasterPipeline::swap_rb); + pipeline.append(SkRasterPipeline::store_8888, &dst); + break; + case kRGBA_8888_ColorFormat: + pipeline.append(SkRasterPipeline::store_8888, &dst); + break; + case kRGBA_F16_ColorFormat: + if (!fLinearDstGamma) { + return false; + } + pipeline.append(SkRasterPipeline::store_f16, &dst); + break; + case kRGBA_F32_ColorFormat: + if (!fLinearDstGamma) { + return false; + } + pipeline.append(SkRasterPipeline::store_f32, &dst); + break; + case kBGR_565_ColorFormat: + if (kOpaque_SkAlphaType != alphaType) { + return false; + } + pipeline.append(SkRasterPipeline::store_565, &dst); + break; + default: + return false; + } + pipeline.run(0,count); + + return true; +} + +static inline bool gamma_to_parametric(SkColorSpaceTransferFn* coeffs, const SkGammas& gammas, + int channel) { + switch (gammas.type(channel)) { + case SkGammas::Type::kNamed_Type: + return named_to_parametric(coeffs, gammas.data(channel).fNamed); + case SkGammas::Type::kValue_Type: + value_to_parametric(coeffs, gammas.data(channel).fValue); + return true; + case SkGammas::Type::kParam_Type: + *coeffs = gammas.params(channel); + return true; + default: + return false; + } +} + +SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, + SkColorSpace_XYZ* dstSpace) + : fLinearDstGamma(kLinear_SkGammaNamed == dstSpace->gammaNamed()) { +#if (SkCSXformPrintfDefined) + static const char* debugGammaNamed[4] = { + "Linear", "SRGB", "2.2", "NonStandard" + }; + static const char* debugGammas[5] = { + "None", "Named", "Value", "Table", "Param" + }; +#endif + int currentChannels; + switch (srcSpace->iccType()) { + case SkColorSpace_Base::kRGB_ICCTypeFlag: + currentChannels = 3; + break; + case SkColorSpace_Base::kCMYK_ICCTypeFlag: + currentChannels = 4; + // CMYK images from JPEGs (the only format that supports it) are actually + // inverted CMYK, so we need to invert every channel. + // TransferFn is y = -x + 1 for x < 1.f, otherwise 0x + 0, ie y = 1 - x for x in [0,1] + this->addTransferFns({1.f, 0.f, 0.f, -1.f, 1.f, 0.f, 1.f}, 4); + break; + default: + currentChannels = 0; + SkASSERT(false); + } + // add in all input color space -> PCS xforms + for (int i = 0; i < srcSpace->count(); ++i) { + const SkColorSpace_A2B::Element& e = srcSpace->element(i); + SkASSERT(e.inputChannels() == currentChannels); + currentChannels = e.outputChannels(); + switch (e.type()) { + case SkColorSpace_A2B::Element::Type::kGammaNamed: + if (kLinear_SkGammaNamed == e.gammaNamed()) { + break; + } + + // take the fast path for 3-channel named gammas + if (3 == currentChannels) { + if (k2Dot2Curve_SkGammaNamed == e.gammaNamed()) { + SkCSXformPrintf("fast path from 2.2\n"); + fElementsPipeline.append(SkRasterPipeline::from_2dot2); + break; + } else if (kSRGB_SkGammaNamed == e.gammaNamed()) { + SkCSXformPrintf("fast path from sRGB\n"); + // Images should always start the pipeline as unpremul + fElementsPipeline.append_from_srgb(kUnpremul_SkAlphaType); + break; + } + } + + SkCSXformPrintf("Gamma stage added: %s\n", debugGammaNamed[(int)e.gammaNamed()]); + SkColorSpaceTransferFn fn; + SkAssertResult(named_to_parametric(&fn, e.gammaNamed())); + this->addTransferFns(fn, currentChannels); + break; + case SkColorSpace_A2B::Element::Type::kGammas: { + const SkGammas& gammas = e.gammas(); + SkCSXformPrintf("Gamma stage added:"); + for (int channel = 0; channel < gammas.channels(); ++channel) { + SkCSXformPrintf(" %s", debugGammas[(int)gammas.type(channel)]); + } + SkCSXformPrintf("\n"); + bool gammaNeedsRef = false; + for (int channel = 0; channel < gammas.channels(); ++channel) { + if (SkGammas::Type::kTable_Type == gammas.type(channel)) { + SkTableTransferFn table = { + gammas.table(channel), + gammas.data(channel).fTable.fSize, + }; + + this->addTableFn(table, channel); + gammaNeedsRef = true; + } else { + SkColorSpaceTransferFn fn; + SkAssertResult(gamma_to_parametric(&fn, gammas, channel)); + this->addTransferFn(fn, channel); + } + } + if (gammaNeedsRef) { + fGammaRefs.push_back(sk_ref_sp(&gammas)); + } + break; + } + case SkColorSpace_A2B::Element::Type::kCLUT: + SkCSXformPrintf("CLUT (%d -> %d) stage added\n", e.colorLUT().inputChannels(), + e.colorLUT().outputChannels()); + fCLUTs.push_back(sk_ref_sp(&e.colorLUT())); + fElementsPipeline.append(SkRasterPipeline::color_lookup_table, + fCLUTs.back().get()); + break; + case SkColorSpace_A2B::Element::Type::kMatrix: + if (!e.matrix().isIdentity()) { + SkCSXformPrintf("Matrix stage added\n"); + addMatrix(e.matrix()); + } + break; + } + } + + // Lab PCS -> XYZ PCS + if (SkColorSpace_A2B::PCS::kLAB == srcSpace->pcs()) { + SkCSXformPrintf("Lab -> XYZ element added\n"); + fElementsPipeline.append(SkRasterPipeline::lab_to_xyz); + } + + // we should now be in XYZ PCS + SkASSERT(3 == currentChannels); + + // and XYZ PCS -> output color space xforms + if (!dstSpace->fromXYZD50()->isIdentity()) { + addMatrix(*dstSpace->fromXYZD50()); + } + + switch (dstSpace->gammaNamed()) { + case kLinear_SkGammaNamed: + // do nothing + break; + case k2Dot2Curve_SkGammaNamed: + fElementsPipeline.append(SkRasterPipeline::to_2dot2); + break; + case kSRGB_SkGammaNamed: + fElementsPipeline.append(SkRasterPipeline::to_srgb); + break; + case kNonStandard_SkGammaNamed: { + for (int channel = 0; channel < 3; ++channel) { + const SkGammas& gammas = *dstSpace->gammas(); + if (SkGammas::Type::kTable_Type == gammas.type(channel)) { + static constexpr int kInvTableSize = 256; + std::vector storage(kInvTableSize); + invert_table_gamma(storage.data(), nullptr, storage.size(), + gammas.table(channel), + gammas.data(channel).fTable.fSize); + SkTableTransferFn table = { + storage.data(), + (int) storage.size(), + }; + fTableStorage.push_front(std::move(storage)); + + this->addTableFn(table, channel); + } else { + SkColorSpaceTransferFn fn; + SkAssertResult(gamma_to_parametric(&fn, gammas, channel)); + this->addTransferFn(fn.invert(), channel); + } + } + } + break; + } +} + +void SkColorSpaceXform_A2B::addTransferFns(const SkColorSpaceTransferFn& fn, int channelCount) { + for (int i = 0; i < channelCount; ++i) { + this->addTransferFn(fn, i); + } +} + +void SkColorSpaceXform_A2B::addTransferFn(const SkColorSpaceTransferFn& fn, int channelIndex) { + fTransferFns.push_front(fn); + switch (channelIndex) { + case 0: + fElementsPipeline.append(SkRasterPipeline::parametric_r, &fTransferFns.front()); + break; + case 1: + fElementsPipeline.append(SkRasterPipeline::parametric_g, &fTransferFns.front()); + break; + case 2: + fElementsPipeline.append(SkRasterPipeline::parametric_b, &fTransferFns.front()); + break; + case 3: + fElementsPipeline.append(SkRasterPipeline::parametric_a, &fTransferFns.front()); + break; + default: + SkASSERT(false); + } +} + +void SkColorSpaceXform_A2B::addTableFn(const SkTableTransferFn& fn, int channelIndex) { + fTableTransferFns.push_front(fn); + switch (channelIndex) { + case 0: + fElementsPipeline.append(SkRasterPipeline::table_r, &fTableTransferFns.front()); + break; + case 1: + fElementsPipeline.append(SkRasterPipeline::table_g, &fTableTransferFns.front()); + break; + case 2: + fElementsPipeline.append(SkRasterPipeline::table_b, &fTableTransferFns.front()); + break; + case 3: + fElementsPipeline.append(SkRasterPipeline::table_a, &fTableTransferFns.front()); + break; + default: + SkASSERT(false); + } +} + +void SkColorSpaceXform_A2B::addMatrix(const SkMatrix44& matrix) { + fMatrices.push_front(std::vector(12)); + auto& m = fMatrices.front(); + m[ 0] = matrix.get(0, 0); + m[ 1] = matrix.get(1, 0); + m[ 2] = matrix.get(2, 0); + m[ 3] = matrix.get(0, 1); + m[ 4] = matrix.get(1, 1); + m[ 5] = matrix.get(2, 1); + m[ 6] = matrix.get(0, 2); + m[ 7] = matrix.get(1, 2); + m[ 8] = matrix.get(2, 2); + m[ 9] = matrix.get(0, 3); + m[10] = matrix.get(1, 3); + m[11] = matrix.get(2, 3); + SkASSERT(matrix.get(3, 0) == 0.f); + SkASSERT(matrix.get(3, 1) == 0.f); + SkASSERT(matrix.get(3, 2) == 0.f); + SkASSERT(matrix.get(3, 3) == 1.f); + fElementsPipeline.append(SkRasterPipeline::matrix_3x4, m.data()); + fElementsPipeline.append(SkRasterPipeline::clamp_0); + fElementsPipeline.append(SkRasterPipeline::clamp_1); +} diff --git a/gfx/skia/skia/src/core/SkColorSpaceXform_A2B.h b/gfx/skia/skia/src/core/SkColorSpaceXform_A2B.h new file mode 100644 index 000000000000..937402026dc9 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpaceXform_A2B.h @@ -0,0 +1,59 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpaceXform_A2B_DEFINED +#define SkColorSpaceXform_A2B_DEFINED + +#include "SkColorSpace_Base.h" +#include "SkColorSpaceXform_Base.h" +#include "SkRasterPipeline.h" + +#include +#include +#include + +class SkColorSpace_A2B; +class SkColorSpace_XYZ; + +struct SkTableTransferFn { + const float* fData; + int fSize; +}; + +class SkColorSpaceXform_A2B : public SkColorSpaceXform_Base { +public: + bool onApply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat, const void* src, + int count, SkAlphaType alphaType) const override; + +private: + SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, SkColorSpace_XYZ* dstSpace); + + void addTransferFns(const SkColorSpaceTransferFn& fn, int channelCount); + + void addTransferFn(const SkColorSpaceTransferFn& fn, int channelIndex); + + void addTableFn(const SkTableTransferFn& table, int channelIndex); + + void addMatrix(const SkMatrix44& matrix); + + SkRasterPipeline fElementsPipeline; + bool fLinearDstGamma; + + // storage used by the pipeline + std::forward_list fTransferFns; + std::forward_list fTableTransferFns; + std::forward_list> fMatrices; + std::vector> fCLUTs; + + // these are here to maintain ownership of tables used in the pipeline + std::forward_list> fTableStorage; + std::vector> fGammaRefs; + + friend class SkColorSpaceXform_Base; +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkColorSpaceXform_Base.h b/gfx/skia/skia/src/core/SkColorSpaceXform_Base.h new file mode 100644 index 000000000000..f72ace0fb5cb --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpaceXform_Base.h @@ -0,0 +1,104 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpaceXform_Base_DEFINED +#define SkColorSpaceXform_Base_DEFINED + +#include "SkColorSpace.h" +#include "SkColorSpace_Base.h" +#include "SkColorSpaceXform.h" +#include "SkResourceCache.h" + +class SkColorSpace_XYZ; + +class SkColorSpaceXform_Base : public SkColorSpaceXform { +public: + static constexpr int kDstGammaTableSize = 1024; + + static std::unique_ptr New(SkColorSpace* srcSpace, SkColorSpace* dstSpace, + SkTransferFunctionBehavior premulBehavior); + +protected: + virtual bool onApply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat, const void* src, + int count, SkAlphaType alphaType) const = 0; + +private: + static void BuildDstGammaTables(const uint8_t* outGammaTables[3], uint8_t* gammaTableStorage, + const SkColorSpace_XYZ* space, bool gammasAreMatching); + + friend class SkColorSpaceXform; + friend class SkColorSpace_XYZ; +}; + +enum SrcGamma { + kLinear_SrcGamma, + kTable_SrcGamma, + kSRGB_SrcGamma, +}; + +enum DstGamma { + kLinear_DstGamma, + kSRGB_DstGamma, + k2Dot2_DstGamma, + kTable_DstGamma, +}; + +enum ColorSpaceMatch { + kNone_ColorSpaceMatch, + kGamut_ColorSpaceMatch, + kFull_ColorSpaceMatch, +}; + +template +class SkColorSpaceXform_XYZ : public SkColorSpaceXform_Base { +protected: + bool onApply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat, const void* src, + int count, SkAlphaType alphaType) const override; + +private: + bool applyPipeline(ColorFormat dstFormat, void* dst, ColorFormat srcFormat, const void* src, + int count, SkAlphaType alphaType) const; + + SkColorSpaceXform_XYZ(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst, + SkColorSpace_XYZ* dstSpace, SkTransferFunctionBehavior premulBehavior); + + // Contain pointers into storage or pointers into precomputed tables. + const float* fSrcGammaTables[3]; + SkAutoTMalloc fSrcStorage; + const uint8_t* fDstGammaTables[3]; + sk_sp fDstStorage; + + // Holds a 3x4 matrix. Padding is useful for vector loading. + float fSrcToDst[13]; + + SrcGamma fSrcGamma; + DstGamma fDstGamma; + SkTransferFunctionBehavior fPremulBehavior; + + friend class SkColorSpaceXform_Base; + friend std::unique_ptr SlowIdentityXform(SkColorSpace_XYZ* space); +}; + +struct LoadTablesContext { + const void* fSrc; + const float* fR; + const float* fG; + const float* fB; +}; + +// Must be kept in sync with "Tables" struct in RasterPipeline_opts byte_tables_rgb. +struct TablesContext { + const uint8_t* fR; + const uint8_t* fG; + const uint8_t* fB; + int fCount; +}; + +// For testing. Bypasses opts for when src and dst color spaces are equal. +std::unique_ptr SlowIdentityXform(SkColorSpace_XYZ* space); + +#endif diff --git a/gfx/skia/skia/src/core/SkColorSpaceXformer.cpp b/gfx/skia/skia/src/core/SkColorSpaceXformer.cpp new file mode 100644 index 000000000000..fe66e74c7986 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpaceXformer.cpp @@ -0,0 +1,196 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorFilter.h" +#include "SkColorSpaceXformer.h" +#include "SkColorSpaceXform_Base.h" +#include "SkDrawLooper.h" +#include "SkGradientShader.h" +#include "SkImage_Base.h" +#include "SkImageFilter.h" +#include "SkImagePriv.h" +#include "SkMakeUnique.h" + +std::unique_ptr SkColorSpaceXformer::Make(sk_sp dst) { + std::unique_ptr fromSRGB = SkColorSpaceXform_Base::New( + SkColorSpace::MakeSRGB().get(), dst.get(), SkTransferFunctionBehavior::kIgnore); + if (!fromSRGB) { + return nullptr; + } + + auto xformer = std::unique_ptr(new SkColorSpaceXformer()); + xformer->fDst = std::move(dst); + xformer->fFromSRGB = std::move(fromSRGB); + return xformer; +} + +sk_sp SkColorSpaceXformer::apply(const SkImage* src) { + return src->makeColorSpace(fDst, SkTransferFunctionBehavior::kIgnore); +} + +sk_sp SkColorSpaceXformer::apply(const SkBitmap& src) { + sk_sp image = SkMakeImageFromRasterBitmap(src, kNever_SkCopyPixelsMode); + if (!image) { + return nullptr; + } + + sk_sp xformed = image->makeColorSpace(fDst, SkTransferFunctionBehavior::kIgnore); + // We want to be sure we don't let the kNever_SkCopyPixelsMode image escape this stack frame. + SkASSERT(xformed != image); + return xformed; +} + +// As far as I know, SkModeColorFilter is the only color filter that holds a color. +sk_sp SkColorSpaceXformer::apply(const SkColorFilter* colorFilter) { + SkColor color; + SkBlendMode mode; + if (colorFilter->asColorMode(&color, &mode)) { + return SkColorFilter::MakeModeFilter(this->apply(color), mode); + } + + return sk_ref_sp(const_cast(colorFilter)); +} + +void SkColorSpaceXformer::apply(SkColor* xformed, const SkColor* srgb, int n) { + SkAssertResult(fFromSRGB->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, xformed, + SkColorSpaceXform::kBGRA_8888_ColorFormat, srgb, + n, kUnpremul_SkAlphaType)); +} + +SkColor SkColorSpaceXformer::apply(SkColor srgb) { + SkColor xformed; + this->apply(&xformed, &srgb, 1); + return xformed; +} + +// TODO: Is this introspection going to be enough, or do we need a new SkShader method? +sk_sp SkColorSpaceXformer::apply(const SkShader* shader) { + SkColor color; + if (shader->isConstant() && shader->asLuminanceColor(&color)) { + return SkShader::MakeColorShader(this->apply(color)) + ->makeWithLocalMatrix(shader->getLocalMatrix()); + } + + SkShader::TileMode xy[2]; + SkMatrix local; + if (auto img = shader->isAImage(&local, xy)) { + return this->apply(img)->makeShader(xy[0], xy[1], &local); + } + + SkShader::ComposeRec compose; + if (shader->asACompose(&compose)) { + auto A = this->apply(compose.fShaderA), + B = this->apply(compose.fShaderB); + if (A && B) { + return SkShader::MakeComposeShader(std::move(A), std::move(B), compose.fBlendMode) + ->makeWithLocalMatrix(shader->getLocalMatrix()); + } + } + + SkShader::GradientInfo gradient; + sk_bzero(&gradient, sizeof(gradient)); + if (auto type = shader->asAGradient(&gradient)) { + SkSTArray<8, SkColor> colors(gradient.fColorCount); + SkSTArray<8, SkScalar> pos(gradient.fColorCount); + + gradient.fColors = colors.begin(); + gradient.fColorOffsets = pos.begin(); + shader->asAGradient(&gradient); + + SkSTArray<8, SkColor> xformed(gradient.fColorCount); + this->apply(xformed.begin(), gradient.fColors, gradient.fColorCount); + + switch (type) { + case SkShader::kNone_GradientType: + case SkShader::kColor_GradientType: + SkASSERT(false); // Should be unreachable. + break; + + case SkShader::kLinear_GradientType: + return SkGradientShader::MakeLinear(gradient.fPoint, + xformed.begin(), + gradient.fColorOffsets, + gradient.fColorCount, + gradient.fTileMode, + gradient.fGradientFlags, + &shader->getLocalMatrix()); + case SkShader::kRadial_GradientType: + return SkGradientShader::MakeRadial(gradient.fPoint[0], + gradient.fRadius[0], + xformed.begin(), + gradient.fColorOffsets, + gradient.fColorCount, + gradient.fTileMode, + gradient.fGradientFlags, + &shader->getLocalMatrix()); + case SkShader::kSweep_GradientType: + return SkGradientShader::MakeSweep(gradient.fPoint[0].fX, + gradient.fPoint[0].fY, + xformed.begin(), + gradient.fColorOffsets, + gradient.fColorCount, + gradient.fGradientFlags, + &shader->getLocalMatrix()); + case SkShader::kConical_GradientType: + return SkGradientShader::MakeTwoPointConical(gradient.fPoint[0], + gradient.fRadius[0], + gradient.fPoint[1], + gradient.fRadius[1], + xformed.begin(), + gradient.fColorOffsets, + gradient.fColorCount, + gradient.fTileMode, + gradient.fGradientFlags, + &shader->getLocalMatrix()); + } + } + + return sk_ref_sp(const_cast(shader)); +} + +const SkPaint& SkColorSpaceXformer::apply(const SkPaint& src) { + const SkPaint* result = &src; + auto get_dst = [&] { + if (result == &src) { + fDstPaint = src; + result = &fDstPaint; + } + return &fDstPaint; + }; + + // All SkColorSpaces have the same black point. + if (src.getColor() & 0xffffff) { + get_dst()->setColor(this->apply(src.getColor())); + } + + if (auto shader = src.getShader()) { + if (auto replacement = this->apply(shader)) { + get_dst()->setShader(std::move(replacement)); + } + } + + if (auto cf = src.getColorFilter()) { + auto replacement = this->apply(cf); + if (replacement.get() != cf) { + get_dst()->setColorFilter(std::move(replacement)); + } + } + + if (auto looper = src.getDrawLooper()) { + get_dst()->setDrawLooper(looper->makeColorSpace(this)); + } + + if (auto imageFilter = src.getImageFilter()) { + get_dst()->setImageFilter(imageFilter->makeColorSpace(this)); + } + + return *result; +} + +const SkPaint* SkColorSpaceXformer::apply(const SkPaint* src) { + return src ? &this->apply(*src) : nullptr; +} diff --git a/gfx/skia/skia/src/core/SkColorSpaceXformer.h b/gfx/skia/skia/src/core/SkColorSpaceXformer.h new file mode 100644 index 000000000000..6d5aaacd6115 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpaceXformer.h @@ -0,0 +1,37 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpaceXformer_DEFINED +#define SkColorSpaceXformer_DEFINED + +#include "SkColorSpaceXform.h" +#include "SkImage.h" +#include "SkShader.h" + +class SkColorSpaceXformer : public SkNoncopyable { +public: + static std::unique_ptr Make(sk_sp dst); + + sk_sp apply(const SkImage* src); + sk_sp apply(const SkBitmap& bitmap); + sk_sp apply(const SkColorFilter* shader); + const SkPaint* apply(const SkPaint* src); + const SkPaint& apply(const SkPaint& src); + void apply(SkColor dst[], const SkColor src[], int n); + SkColor apply(SkColor srgb); + +private: + sk_sp apply(const SkShader* shader); + + SkColorSpaceXformer() {} + + sk_sp fDst; + std::unique_ptr fFromSRGB; + SkPaint fDstPaint; +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkColorSpace_A2B.cpp b/gfx/skia/skia/src/core/SkColorSpace_A2B.cpp new file mode 100644 index 000000000000..7e097ffa8032 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpace_A2B.cpp @@ -0,0 +1,18 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorSpace_A2B.h" + +SkColorSpace_A2B::SkColorSpace_A2B(ICCTypeFlag iccType, std::vector elements, + PCS pcs, sk_sp profileData) + : INHERITED(std::move(profileData)) + , fICCType(iccType) + , fElements(std::move(elements)) + , fPCS(pcs) +{ + SkASSERT(kRGB_ICCTypeFlag == iccType || kCMYK_ICCTypeFlag == iccType); +} diff --git a/gfx/skia/skia/src/core/SkColorSpace_A2B.h b/gfx/skia/skia/src/core/SkColorSpace_A2B.h new file mode 100644 index 000000000000..610f07e9d0cb --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpace_A2B.h @@ -0,0 +1,179 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpace_A2B_DEFINED +#define SkColorSpace_A2B_DEFINED + +#include "SkColorSpace_Base.h" + +#include + +// An alternative SkColorSpace that represents all the color space data that +// is stored in an A2B0 ICC tag. This allows us to use alternative profile +// connection spaces (CIELAB instead of just CIEXYZ), use color-lookup-tables +// to do color space transformations not representable as TRC functions or +// matrix operations, as well as have multiple TRC functions. The CLUT also +// allows conversion between non-3-channel input color spaces ie CMYK(4) to +// a workable PCS (ie XYZ). +// +// AtoBType, lut8Type and lut16Type A2B0 tag types are supported. There are +// also MPET (multi-processing-elements) A2B0 tags in the standard which allow +// you to combine these 3 primitives (TRC, CLUT, matrix) in any order/quantity. +// MPET tags are currently unsupported by the MakeICC parser, could be supported +// here by the nature of the design. +class SkColorSpace_A2B : public SkColorSpace_Base { +public: + const SkMatrix44* toXYZD50() const override { + // the matrix specified in A2B0 profiles is not necessarily + // a to-XYZ matrix, as to-Lab is supported as well so returning + // that could be misleading. Additionally, B-curves are applied + // after the matrix is, but a toXYZD50 matrix is the last thing + // applied in order to get into the (XYZ) profile connection space. + return nullptr; + } + + uint32_t toXYZD50Hash() const override { + // See toXYZD50()'s comment. + return 0; + } + + const SkMatrix44* fromXYZD50() const override { + // See toXYZD50()'s comment. Also, A2B0 profiles are not supported + // as destination color spaces, so an inverse matrix is never wanted. + return nullptr; + } + + // There is no single gamma curve in an A2B0 profile + bool onGammaCloseToSRGB() const override { return false; } + bool onGammaIsLinear() const override { return false; } + bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const override { return false; } + + bool onIsCMYK() const override { return kCMYK_ICCTypeFlag == fICCType; } + + sk_sp makeLinearGamma() override { + // TODO: Analyze the extrema of our projection into XYZ and use suitable primaries? + // For now, just fall back to a default, because we don't have a good answer. + return SkColorSpace::MakeSRGBLinear(); + } + + sk_sp makeSRGBGamma() override { + // See comment in makeLinearGamma + return SkColorSpace::MakeSRGB(); + } + + Type type() const override { return Type::kA2B; } + + class Element { + public: + Element(SkGammaNamed gammaNamed, int channelCount) + : fType(Type::kGammaNamed) + , fGammaNamed(gammaNamed) + , fMatrix(SkMatrix44::kUninitialized_Constructor) + , fInputChannels(channelCount) + , fOutputChannels(channelCount) { + SkASSERT(gammaNamed != kNonStandard_SkGammaNamed); + } + + explicit Element(sk_sp gammas) + : fType(Type::kGammas) + , fGammas(std::move(gammas)) + , fMatrix(SkMatrix44::kUninitialized_Constructor) + , fInputChannels(fGammas->channels()) + , fOutputChannels(fGammas->channels()) { + for (int i = 0; i < fGammas->channels(); ++i) { + if (SkGammas::Type::kTable_Type == fGammas->type(i)) { + SkASSERT(fGammas->data(i).fTable.fSize >= 2); + } + } + } + + explicit Element(sk_sp colorLUT) + : fType(Type::kCLUT) + , fCLUT(std::move(colorLUT)) + , fMatrix(SkMatrix44::kUninitialized_Constructor) + , fInputChannels(fCLUT->inputChannels()) + , fOutputChannels(fCLUT->outputChannels()) + {} + + explicit Element(const SkMatrix44& matrix) + : fType(Type::kMatrix) + , fMatrix(matrix) + , fInputChannels(3) + , fOutputChannels(3) + {} + + enum class Type { + kGammaNamed, + kGammas, + kCLUT, + kMatrix + }; + + Type type() const { return fType; } + + SkGammaNamed gammaNamed() const { + SkASSERT(Type::kGammaNamed == fType); + return fGammaNamed; + } + + const SkGammas& gammas() const { + SkASSERT(Type::kGammas == fType); + return *fGammas; + } + + const SkColorLookUpTable& colorLUT() const { + SkASSERT(Type::kCLUT == fType); + return *fCLUT; + } + + const SkMatrix44& matrix() const { + SkASSERT(Type::kMatrix == fType); + return fMatrix; + } + + int inputChannels() const { return fInputChannels; } + + int outputChannels() const { return fOutputChannels; } + + private: + Type fType; + SkGammaNamed fGammaNamed; + sk_sp fGammas; + sk_sp fCLUT; + SkMatrix44 fMatrix; + int fInputChannels; + int fOutputChannels; + }; + const Element& element(int i) const { return fElements[i]; } + + int count() const { return (int)fElements.size(); } + + // the intermediate profile connection space that this color space + // represents the transformation to + enum class PCS : uint8_t { + kLAB, // CIELAB + kXYZ // CIEXYZ + }; + + PCS pcs() const { return fPCS; } + + ICCTypeFlag iccType() const { return fICCType; } + + SkColorSpace_A2B(ICCTypeFlag iccType, std::vector elements, PCS pcs, + sk_sp profileData); + +private: + ICCTypeFlag fICCType; + std::vector fElements; + PCS fPCS; + + friend class SkColorSpace_Base; + friend class ColorSpaceXformTest; + typedef SkColorSpace_Base INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkColorSpace_Base.h b/gfx/skia/skia/src/core/SkColorSpace_Base.h index 07fa3832530d..61f65a59835a 100644 --- a/gfx/skia/skia/src/core/SkColorSpace_Base.h +++ b/gfx/skia/skia/src/core/SkColorSpace_Base.h @@ -8,6 +8,7 @@ #ifndef SkColorSpace_Base_DEFINED #define SkColorSpace_Base_DEFINED +#include "SkColorLookUpTable.h" #include "SkColorSpace.h" #include "SkData.h" #include "SkOnce.h" @@ -42,19 +43,6 @@ struct SkGammas : SkRefCnt { } }; - // Contains the parameters for a parametric curve. - struct Params { - // Y = (aX + b)^g + c for X >= d - // Y = eX + f otherwise - float fG; - float fA; - float fB; - float fC; - float fD; - float fE; - float fF; - }; - // Contains the actual gamma curve information. Should be interpreted // based on the type of the gamma curve. union Data { @@ -67,13 +55,18 @@ struct SkGammas : SkRefCnt { this->fTable.fSize == that.fTable.fSize; } + inline bool operator!=(const Data& that) const { + return !(*this == that); + } + SkGammaNamed fNamed; float fValue; Table fTable; size_t fParamOffset; - const Params& params(const SkGammas* base) const { - return *SkTAddOffset(base, sizeof(SkGammas) + fParamOffset); + const SkColorSpaceTransferFn& params(const SkGammas* base) const { + return *SkTAddOffset( + base, sizeof(SkGammas) + fParamOffset); } }; @@ -94,17 +87,8 @@ struct SkGammas : SkRefCnt { } const Data& data(int i) const { - switch (i) { - case 0: - return fRedData; - case 1: - return fGreenData; - case 2: - return fBlueData; - default: - SkASSERT(false); - return fRedData; - } + SkASSERT(i >= 0 && i < fChannels); + return fData[i]; } const float* table(int i) const { @@ -112,38 +96,35 @@ struct SkGammas : SkRefCnt { return this->data(i).fTable.table(this); } - const Params& params(int i) const { + int tableSize(int i) const { + SkASSERT(isTable(i)); + return this->data(i).fTable.fSize; + } + + const SkColorSpaceTransferFn& params(int i) const { SkASSERT(isParametric(i)); return this->data(i).params(this); } Type type(int i) const { - switch (i) { - case 0: - return fRedType; - case 1: - return fGreenType; - case 2: - return fBlueType; - default: - SkASSERT(false); - return fRedType; + SkASSERT(i >= 0 && i < fChannels); + return fType[i]; + } + + uint8_t channels() const { return fChannels; } + + SkGammas(uint8_t channels) + : fChannels(channels) { + SkASSERT(channels <= kMaxColorChannels); + for (uint8_t i = 0; i < kMaxColorChannels; ++i) { + fType[i] = Type::kNone_Type; } } - SkGammas() - : fRedType(Type::kNone_Type) - , fGreenType(Type::kNone_Type) - , fBlueType(Type::kNone_Type) - {} - // These fields should only be modified when initializing the struct. - Data fRedData; - Data fGreenData; - Data fBlueData; - Type fRedType; - Type fGreenType; - Type fBlueType; + uint8_t fChannels; + Data fData[kMaxColorChannels]; + Type fType[kMaxColorChannels]; // Objects of this type are sometimes created in a custom fashion using // sk_malloc_throw and therefore must be sk_freed. We overload new to @@ -155,71 +136,83 @@ struct SkGammas : SkRefCnt { void operator delete(void* p) { sk_free(p); } }; -struct SkColorLookUpTable : public SkRefCnt { - static constexpr uint8_t kOutputChannels = 3; - - uint8_t fInputChannels; - uint8_t fGridPoints[3]; - - const float* table() const { - return SkTAddOffset(this, sizeof(SkColorLookUpTable)); - } - - SkColorLookUpTable(uint8_t inputChannels, uint8_t gridPoints[3]) - : fInputChannels(inputChannels) - { - SkASSERT(3 == inputChannels); - memcpy(fGridPoints, gridPoints, 3 * sizeof(uint8_t)); - } - - // Objects of this type are created in a custom fashion using sk_malloc_throw - // and therefore must be sk_freed. - void* operator new(size_t size) = delete; - void* operator new(size_t, void* p) { return p; } - void operator delete(void* p) { sk_free(p); } -}; - class SkColorSpace_Base : public SkColorSpace { public: - static sk_sp NewRGB(const float gammas[3], const SkMatrix44& toXYZD50); - - SkGammaNamed gammaNamed() const { return fGammaNamed; } - const SkGammas* gammas() const { return fGammas.get(); } - - const SkColorLookUpTable* colorLUT() const { return fColorLUT.get(); } - - const SkMatrix44& toXYZD50() const { return fToXYZD50; } - const SkMatrix44& fromXYZD50() const; - -private: + /** + * Describes color space gamut as a transformation to XYZ D50. + * Returns nullptr if color gamut cannot be described in terms of XYZ D50. + */ + virtual const SkMatrix44* toXYZD50() const = 0; /** - * FIXME (msarett): - * Hiding this function until we can determine if we need it. Known issues include: - * Only writes 3x3 matrices - * Only writes float gammas - * Rejected by some parsers because the "profile description" is empty + * Returns a hash of the gamut transofmration to XYZ D50. Allows for fast equality checking + * of gamuts, at the (very small) risk of collision. + * Returns 0 if color gamut cannot be described in terms of XYZ D50. */ - sk_sp writeToICC() const; + virtual uint32_t toXYZD50Hash() const = 0; - static sk_sp NewRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50); + /** + * Describes color space gamut as a transformation from XYZ D50 + * Returns nullptr if color gamut cannot be described in terms of XYZ D50. + */ + virtual const SkMatrix44* fromXYZD50() const = 0; - SkColorSpace_Base(SkGammaNamed gammaNamed, const SkMatrix44& toXYZ); + virtual bool onGammaCloseToSRGB() const = 0; - SkColorSpace_Base(sk_sp colorLUT, SkGammaNamed gammaNamed, - sk_sp gammas, const SkMatrix44& toXYZ, sk_sp profileData); + virtual bool onGammaIsLinear() const = 0; - sk_sp fColorLUT; - const SkGammaNamed fGammaNamed; - sk_sp fGammas; - sk_sp fProfileData; + virtual bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const = 0; - const SkMatrix44 fToXYZD50; - mutable SkMatrix44 fFromXYZD50; - mutable SkOnce fFromXYZOnce; + virtual bool onIsCMYK() const { return false; } + + /** + * Returns a color space with the same gamut as this one, but with a linear gamma. + * For color spaces whose gamut can not be described in terms of XYZ D50, returns + * linear sRGB. + */ + virtual sk_sp makeLinearGamma() = 0; + + /** + * Returns a color space with the same gamut as this one, with with the sRGB transfer + * function. For color spaces whose gamut can not be described in terms of XYZ D50, returns + * sRGB. + */ + virtual sk_sp makeSRGBGamma() = 0; + + enum class Type : uint8_t { + kXYZ, + kA2B + }; + + virtual Type type() const = 0; + + typedef uint8_t ICCTypeFlag; + static constexpr ICCTypeFlag kRGB_ICCTypeFlag = 1 << 0; + static constexpr ICCTypeFlag kCMYK_ICCTypeFlag = 1 << 1; + static constexpr ICCTypeFlag kGray_ICCTypeFlag = 1 << 2; + + static sk_sp MakeICC(const void* input, size_t len, ICCTypeFlag type); + + static sk_sp MakeRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50); + + enum Named : uint8_t { + kSRGB_Named, + kAdobeRGB_Named, + kSRGBLinear_Named, + kSRGB_NonLinearBlending_Named, + }; + + static sk_sp MakeNamed(Named); + +protected: + SkColorSpace_Base(sk_sp profileData); + +private: + sk_sp fProfileData; friend class SkColorSpace; + friend class SkColorSpace_XYZ; friend class ColorSpaceXformTest; friend class ColorSpaceTest; typedef SkColorSpace INHERITED; diff --git a/gfx/skia/skia/src/core/SkColorSpace_ICC.cpp b/gfx/skia/skia/src/core/SkColorSpace_ICC.cpp index 4ef9f2b0a831..6d4bba26bd2f 100644 --- a/gfx/skia/skia/src/core/SkColorSpace_ICC.cpp +++ b/gfx/skia/skia/src/core/SkColorSpace_ICC.cpp @@ -5,11 +5,15 @@ * found in the LICENSE file. */ +#include "SkAutoMalloc.h" #include "SkColorSpace.h" -#include "SkColorSpace_Base.h" #include "SkColorSpacePriv.h" +#include "SkColorSpace_A2B.h" +#include "SkColorSpace_Base.h" +#include "SkColorSpace_XYZ.h" #include "SkEndian.h" #include "SkFixed.h" +#include "SkICCPriv.h" #include "SkTemplates.h" #define return_if_false(pred, msg) \ @@ -38,21 +42,7 @@ static int32_t read_big_endian_i32(const uint8_t* ptr) { return (int32_t) read_big_endian_u32(ptr); } -// This is equal to the header size according to the ICC specification (128) -// plus the size of the tag count (4). We include the tag count since we -// always require it to be present anyway. -static constexpr size_t kICCHeaderSize = 132; - -// Contains a signature (4), offset (4), and size (4). -static constexpr size_t kICCTagTableEntrySize = 12; - -static constexpr uint32_t kRGB_ColorSpace = SkSetFourByteTag('R', 'G', 'B', ' '); -static constexpr uint32_t kDisplay_Profile = SkSetFourByteTag('m', 'n', 't', 'r'); -static constexpr uint32_t kInput_Profile = SkSetFourByteTag('s', 'c', 'n', 'r'); -static constexpr uint32_t kOutput_Profile = SkSetFourByteTag('p', 'r', 't', 'r'); -static constexpr uint32_t kColorSpace_Profile = SkSetFourByteTag('s', 'p', 'a', 'c'); -static constexpr uint32_t kXYZ_PCSSpace = SkSetFourByteTag('X', 'Y', 'Z', ' '); -static constexpr uint32_t kACSP_Signature = SkSetFourByteTag('a', 'c', 's', 'p'); +static constexpr float kWhitePointD50[] = { 0.96420f, 1.00000f, 0.82491f, }; struct ICCProfileHeader { uint32_t fSize; @@ -124,13 +114,37 @@ struct ICCProfileHeader { fProfileClass == kColorSpace_Profile, "Unsupported profile"); - // TODO (msarett): - // All the profiles we've tested so far use RGB as the input color space. - return_if_false(fInputColorSpace == kRGB_ColorSpace, "Unsupported color space"); + switch (fInputColorSpace) { + case kRGB_ColorSpace: + SkColorSpacePrintf("RGB Input Color Space"); + break; + case kCMYK_ColorSpace: + SkColorSpacePrintf("CMYK Input Color Space\n"); + break; + case kGray_ColorSpace: + SkColorSpacePrintf("Gray Input Color Space\n"); + break; + default: + SkColorSpacePrintf("Unsupported Input Color Space: %c%c%c%c\n", + (fInputColorSpace>>24)&0xFF, (fInputColorSpace>>16)&0xFF, + (fInputColorSpace>> 8)&0xFF, (fInputColorSpace>> 0)&0xFF); + return false; + } - // TODO (msarett): - // All the profiles we've tested so far use XYZ as the profile connection space. - return_if_false(fPCS == kXYZ_PCSSpace, "Unsupported PCS space"); + switch (fPCS) { + case kXYZ_PCSSpace: + SkColorSpacePrintf("XYZ PCS\n"); + break; + case kLAB_PCSSpace: + SkColorSpacePrintf("Lab PCS\n"); + break; + default: + // ICC currently (V4.3) only specifices XYZ and Lab PCS spaces + SkColorSpacePrintf("Unsupported PCS space: %c%c%c%c\n", + (fPCS>>24)&0xFF, (fPCS>>16)&0xFF, + (fPCS>> 8)&0xFF, (fPCS>> 0)&0xFF); + return false; + } return_if_false(fSignature == kACSP_Signature, "Bad signature"); @@ -144,10 +158,11 @@ struct ICCProfileHeader { SkColorSpacePrintf("Warning, bad rendering intent.\n"); } - return_if_false(color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[0]), 0.96420f) && - color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[1]), 1.00000f) && - color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[2]), 0.82491f), - "Illuminant must be D50"); + return_if_false( + color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[0]), kWhitePointD50[0]) && + color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[1]), kWhitePointD50[1]) && + color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[2]), kWhitePointD50[2]), + "Illuminant must be D50"); return_if_false(fTagCount <= 100, "Too many tags"); @@ -214,14 +229,6 @@ struct ICCTag { } }; -static constexpr uint32_t kTAG_rXYZ = SkSetFourByteTag('r', 'X', 'Y', 'Z'); -static constexpr uint32_t kTAG_gXYZ = SkSetFourByteTag('g', 'X', 'Y', 'Z'); -static constexpr uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z'); -static constexpr uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C'); -static constexpr uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); -static constexpr uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); -static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0'); - static bool load_xyz(float dst[3], const uint8_t* src, size_t len) { if (len < 20) { SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len); @@ -235,9 +242,6 @@ static bool load_xyz(float dst[3], const uint8_t* src, size_t len) { return true; } -static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); -static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); - static SkGammas::Type set_gamma_value(SkGammas::Data* data, float value) { if (color_space_almost_equal(2.2f, value)) { data->fNamed = k2Dot2Curve_SkGammaNamed; @@ -274,8 +278,8 @@ static float read_big_endian_16_dot_16(const uint8_t buf[4]) { * * @return kNone_Type on failure, otherwise the type of the gamma tag. */ -static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* outParams, - size_t* outTagBytes, const uint8_t* src, size_t len) { +static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkColorSpaceTransferFn* outParams, + size_t* outTagBytes, const uint8_t* src, size_t len) { if (len < 12) { SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); return SkGammas::Type::kNone_Type; @@ -345,8 +349,8 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out } if (26 == count) { - // The magic values were chosen because they match a very common LCMS sRGB - // gamma table. + // The magic values match a clever "minimum size" approach to representing sRGB. + // code.facebook.com/posts/411525055626587/under-the-hood-improving-facebook-photos if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && 3062 == read_big_endian_u16((const uint8_t*) &table[6]) && 12824 == read_big_endian_u16((const uint8_t*) &table[12]) && @@ -359,7 +363,7 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out if (4096 == count) { // The magic values were chosen because they match Nikon, Epson, and - // LCMS sRGB gamma tables (all of which use different rounding rules). + // lcms2 sRGB gamma tables (all of which use different rounding rules). if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && 950 == read_big_endian_u16((const uint8_t*) &table[515]) && 3342 == read_big_endian_u16((const uint8_t*) &table[1025]) && @@ -375,14 +379,6 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out return SkGammas::Type::kTable_Type; } case kTAG_ParaCurveType: { - enum ParaCurveType { - kExponential_ParaCurveType = 0, - kGAB_ParaCurveType = 1, - kGABC_ParaCurveType = 2, - kGABDE_ParaCurveType = 3, - kGABCDEF_ParaCurveType = 4, - }; - // Determine the format of the parametric curve tag. uint16_t format = read_big_endian_u16(src + 8); if (format > kGABCDEF_ParaCurveType) { @@ -407,8 +403,8 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out // Here's where the real parametric gammas start. There are many // permutations of the same equations. // - // Y = (aX + b)^g + c for X >= d - // Y = eX + f otherwise + // Y = (aX + b)^g + e for X >= d + // Y = cX + f otherwise // // We will fill in with zeros as necessary to always match the above form. if (len < 24) { @@ -434,11 +430,11 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out return SkGammas::Type::kNone_Type; } - // Y = (aX + b)^g + c for X >= -b/a - // Y = c otherwise - c = read_big_endian_16_dot_16(src + 24); + // Y = (aX + b)^g + e for X >= -b/a + // Y = e otherwise + e = read_big_endian_16_dot_16(src + 24); d = -b / a; - f = c; + f = e; break; case kGABDE_ParaCurveType: tagBytes = 12 + 20; @@ -448,14 +444,9 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out } // Y = (aX + b)^g for X >= d - // Y = eX otherwise + // Y = cX otherwise + c = read_big_endian_16_dot_16(src + 24); d = read_big_endian_16_dot_16(src + 28); - - // Not a bug! We define |e| to always be the coefficient on X in the - // second equation. The spec calls this |c| in this particular equation. - // We don't follow their convention because then |c| would have a - // different meaning in each of our cases. - e = read_big_endian_16_dot_16(src + 24); break; case kGABCDEF_ParaCurveType: tagBytes = 12 + 28; @@ -464,10 +455,8 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out return SkGammas::Type::kNone_Type; } - // Y = (aX + b)^g + c for X >= d - // Y = eX + f otherwise - // NOTE: The ICC spec writes "cX" in place of "eX" but I think - // it's a typo. + // Y = (aX + b)^g + e for X >= d + // Y = cX + f otherwise c = read_big_endian_16_dot_16(src + 24); d = read_big_endian_16_dot_16(src + 28); e = read_big_endian_16_dot_16(src + 32); @@ -478,49 +467,6 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out return SkGammas::Type::kNone_Type; } - // Recognize and simplify a very common parametric representation of sRGB gamma. - if (color_space_almost_equal(0.9479f, a) && - color_space_almost_equal(0.0521f, b) && - color_space_almost_equal(0.0000f, c) && - color_space_almost_equal(0.0405f, d) && - color_space_almost_equal(0.0774f, e) && - color_space_almost_equal(0.0000f, f) && - color_space_almost_equal(2.4000f, g)) { - outData->fNamed = kSRGB_SkGammaNamed; - return SkGammas::Type::kNamed_Type; - } - - // Fail on invalid gammas. - if (SkScalarIsNaN(d)) { - return SkGammas::Type::kNone_Type; - } - - if (d <= 0.0f) { - // Y = (aX + b)^g + c for always - if (0.0f == a || 0.0f == g) { - SkColorSpacePrintf("A or G is zero, constant gamma function " - "is nonsense"); - return SkGammas::Type::kNone_Type; - } - } - - if (d >= 1.0f) { - // Y = eX + f for always - if (0.0f == e) { - SkColorSpacePrintf("E is zero, constant gamma function is " - "nonsense"); - return SkGammas::Type::kNone_Type; - } - } - - if ((0.0f == a || 0.0f == g) && 0.0f == e) { - SkColorSpacePrintf("A or G, and E are zero, constant gamma function " - "is nonsense"); - return SkGammas::Type::kNone_Type; - } - - *outTagBytes = tagBytes; - outParams->fG = g; outParams->fA = a; outParams->fB = b; @@ -528,6 +474,22 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out outParams->fD = d; outParams->fE = e; outParams->fF = f; + + if (!is_valid_transfer_fn(*outParams)) { + return SkGammas::Type::kNone_Type; + } + + if (is_almost_srgb(*outParams)) { + outData->fNamed = kSRGB_SkGammaNamed; + return SkGammas::Type::kNamed_Type; + } + + if (is_almost_2dot2(*outParams)) { + outData->fNamed = k2Dot2Curve_SkGammaNamed; + return SkGammas::Type::kNamed_Type; + } + + *outTagBytes = tagBytes; return SkGammas::Type::kParam_Type; } default: @@ -547,7 +509,7 @@ static size_t gamma_alloc_size(SkGammas::Type type, const SkGammas::Data& data) case SkGammas::Type::kTable_Type: return sizeof(float) * data.fTable.fSize; case SkGammas::Type::kParam_Type: - return sizeof(SkGammas::Params); + return sizeof(SkColorSpaceTransferFn); default: SkASSERT(false); return 0; @@ -584,7 +546,7 @@ static void handle_invalid_gamma(SkGammas::Type* type, SkGammas::Data* data) { * @return Additional bytes of memory that are being used by this gamma curve. */ static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type, - SkGammas::Data* data, const SkGammas::Params& params, + SkGammas::Data* data, const SkColorSpaceTransferFn& params, const uint8_t* src) { void* storage = SkTAddOffset(memory, offset + sizeof(SkGammas)); @@ -606,68 +568,52 @@ static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type, } case SkGammas::Type::kParam_Type: data->fTable.fOffset = offset; - memcpy(storage, ¶ms, sizeof(SkGammas::Params)); - return sizeof(SkGammas::Params); + memcpy(storage, ¶ms, sizeof(SkColorSpaceTransferFn)); + return sizeof(SkColorSpaceTransferFn); default: SkASSERT(false); return 0; } } -static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); +static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); +static constexpr uint32_t kTAG_lut8Type = SkSetFourByteTag('m', 'f', 't', '1'); +static constexpr uint32_t kTAG_lut16Type = SkSetFourByteTag('m', 'f', 't', '2'); static bool load_color_lut(sk_sp* colorLUT, uint32_t inputChannels, - const uint8_t* src, size_t len) { - // 16 bytes reserved for grid points, 2 for precision, 2 for padding. - // The color LUT data follows after this header. - static constexpr uint32_t kColorLUTHeaderSize = 20; - if (len < kColorLUTHeaderSize) { - SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len); - return false; + size_t precision, const uint8_t gridPoints[3], const uint8_t* src, + size_t len) { + switch (precision) { + case 1: // 8-bit data + case 2: // 16-bit data + break; + default: + SkColorSpacePrintf("Color LUT precision must be 8-bit or 16-bit. Found: %d-bit\n", + 8*precision); + return false; } - size_t dataLen = len - kColorLUTHeaderSize; - SkASSERT(3 == inputChannels); - uint8_t gridPoints[3]; - uint32_t numEntries = 1; + uint32_t numEntries = SkColorLookUpTable::kOutputChannels; for (uint32_t i = 0; i < inputChannels; i++) { - gridPoints[i] = src[i]; - if (0 == src[i]) { + if (0 == gridPoints[i]) { SkColorSpacePrintf("Each input channel must have at least one grid point."); return false; } - if (!safe_mul(numEntries, src[i], &numEntries)) { + if (!safe_mul(numEntries, gridPoints[i], &numEntries)) { SkColorSpacePrintf("Too many entries in Color LUT."); return false; } } - if (!safe_mul(numEntries, SkColorLookUpTable::kOutputChannels, &numEntries)) { - SkColorSpacePrintf("Too many entries in Color LUT."); - return false; - } - - // Space is provided for a maximum of the 16 input channels. Now we determine the precision - // of the table values. - uint8_t precision = src[16]; - switch (precision) { - case 1: // 8-bit data - case 2: // 16-bit data - break; - default: - SkColorSpacePrintf("Color LUT precision must be 8-bit or 16-bit.\n"); - return false; - } - uint32_t clutBytes; if (!safe_mul(numEntries, precision, &clutBytes)) { - SkColorSpacePrintf("Too many entries in Color LUT."); + SkColorSpacePrintf("Too many entries in Color LUT.\n"); return false; } - if (dataLen < clutBytes) { - SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len); + if (len < clutBytes) { + SkColorSpacePrintf("Color LUT tag is too small (%d / %d bytes).\n", len, clutBytes); return false; } @@ -677,10 +623,10 @@ static bool load_color_lut(sk_sp* colorLUT, uint32_t inputCh gridPoints)); float* table = SkTAddOffset(memory, sizeof(SkColorLookUpTable)); - const uint8_t* ptr = src + kColorLUTHeaderSize; + const uint8_t* ptr = src; for (uint32_t i = 0; i < numEntries; i++, ptr += precision) { if (1 == precision) { - table[i] = ((float) ptr[i]) / 255.0f; + table[i] = ((float) *ptr) / 255.0f; } else { table[i] = ((float) read_big_endian_u16(ptr)) / 65535.0f; } @@ -689,179 +635,178 @@ static bool load_color_lut(sk_sp* colorLUT, uint32_t inputCh return true; } -static bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { - if (len < 48) { +/** + * Reads a matrix out of an A2B tag of an ICC profile. + * If |translate| is true, it will load a 3x4 matrix out that corresponds to a XYZ + * transform as well as a translation, and if |translate| is false it only loads a + * 3x3 matrix with no translation + * + * @param matrix The matrix to store the result in + * @param src Data to load the matrix out of. + * @param len The length of |src|. + * Must have 48 bytes if |translate| is set and 36 bytes otherwise. + * @param translate Whether to read the translation column or not + * @param pcs The profile connection space of the profile this matrix is for + * + * @return false on failure, true on success + */ +static bool load_matrix(SkMatrix44* matrix, const uint8_t* src, size_t len, bool translate, + SkColorSpace_A2B::PCS pcs) { + const size_t minLen = translate ? 48 : 36; + if (len < minLen) { SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len); return false; } - // For this matrix to behave like our "to XYZ D50" matrices, it needs to be scaled. - constexpr float scale = 65535.0 / 32768.0; + float encodingFactor; + switch (pcs) { + case SkColorSpace_A2B::PCS::kLAB: + encodingFactor = 1.f; + break; + case SkColorSpace_A2B::PCS::kXYZ: + encodingFactor = 65535 / 32768.f; + break; + default: + encodingFactor = 1.f; + SkASSERT(false); + break; + } float array[16]; - array[ 0] = scale * SkFixedToFloat(read_big_endian_i32(src)); - array[ 1] = scale * SkFixedToFloat(read_big_endian_i32(src + 4)); - array[ 2] = scale * SkFixedToFloat(read_big_endian_i32(src + 8)); - array[ 3] = scale * SkFixedToFloat(read_big_endian_i32(src + 36)); // translate R - array[ 4] = scale * SkFixedToFloat(read_big_endian_i32(src + 12)); - array[ 5] = scale * SkFixedToFloat(read_big_endian_i32(src + 16)); - array[ 6] = scale * SkFixedToFloat(read_big_endian_i32(src + 20)); - array[ 7] = scale * SkFixedToFloat(read_big_endian_i32(src + 40)); // translate G - array[ 8] = scale * SkFixedToFloat(read_big_endian_i32(src + 24)); - array[ 9] = scale * SkFixedToFloat(read_big_endian_i32(src + 28)); - array[10] = scale * SkFixedToFloat(read_big_endian_i32(src + 32)); - array[11] = scale * SkFixedToFloat(read_big_endian_i32(src + 44)); // translate B + array[ 0] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src)); + array[ 1] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 4)); + array[ 2] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 8)); + + array[ 4] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 12)); + array[ 5] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 16)); + array[ 6] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 20)); + + array[ 8] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 24)); + array[ 9] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 28)); + array[10] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 32)); + + if (translate) { + array[ 3] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 36)); // translate R + array[ 7] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 40)); // translate G + array[11] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 44)); // translate B + } else { + array[ 3] = 0.0f; + array[ 7] = 0.0f; + array[11] = 0.0f; + } + array[12] = 0.0f; array[13] = 0.0f; array[14] = 0.0f; array[15] = 1.0f; - toXYZ->setRowMajorf(array); + matrix->setRowMajorf(array); + SkColorSpacePrintf("A2B0 matrix loaded:\n"); + for (int r = 0; r < 4; ++r) { + SkColorSpacePrintf("|"); + for (int c = 0; c < 4; ++c) { + SkColorSpacePrintf(" %f ", matrix->get(r, c)); + } + SkColorSpacePrintf("|\n"); + } return true; } static inline SkGammaNamed is_named(const sk_sp& gammas) { - if (gammas->isNamed(0) && gammas->isNamed(1) && gammas->isNamed(2) && - gammas->fRedData.fNamed == gammas->fGreenData.fNamed && - gammas->fRedData.fNamed == gammas->fBlueData.fNamed) - { - return gammas->fRedData.fNamed; + for (uint8_t i = 0; i < gammas->channels(); ++i) { + if (!gammas->isNamed(i) || gammas->data(i).fNamed != gammas->data(0).fNamed) { + return kNonStandard_SkGammaNamed; + } } - - return kNonStandard_SkGammaNamed; + return gammas->data(0).fNamed; } +/** + * Parse and load an entire stored curve. Handles invalid gammas as well. + * + * There's nothing to do for the simple cases, but for table gammas we need to actually + * read the table into heap memory. And for parametric gammas, we need to copy over the + * parameter values. + * + * @param gammaNamed Out-variable. The named gamma curve. + * @param gammas Out-variable. The stored gamma curve information. Can be null if + * gammaNamed is a named curve + * @param inputChannels The number of gamma input channels + * @param rTagPtr Pointer to start of the gamma tag. + * @param taglen The size in bytes of the tag + * + * @return false on failure, true on success + */ +static bool parse_and_load_gamma(SkGammaNamed* gammaNamed, sk_sp* gammas, + uint8_t inputChannels, const uint8_t* tagSrc, size_t tagLen) { + SkGammas::Data data[kMaxColorChannels]; + SkColorSpaceTransferFn params[kMaxColorChannels]; + SkGammas::Type type[kMaxColorChannels]; + const uint8_t* tagPtr[kMaxColorChannels]; -static bool load_a2b0(sk_sp* colorLUT, SkGammaNamed* gammaNamed, - sk_sp* gammas, SkMatrix44* toXYZ, const uint8_t* src, size_t len) { - if (len < 32) { - SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); - return false; - } + tagPtr[0] = tagSrc; - uint32_t type = read_big_endian_u32(src); - if (kTAG_AtoBType != type) { - // FIXME (msarett): Need to support lut8Type and lut16Type. - SkColorSpacePrintf("Unsupported A to B tag type.\n"); - return false; - } + *gammaNamed = kNonStandard_SkGammaNamed; - // Read the number of channels. The four bytes that we skipped are reserved and - // must be zero. - uint8_t inputChannels = src[8]; - uint8_t outputChannels = src[9]; - if (3 != inputChannels || SkColorLookUpTable::kOutputChannels != outputChannels) { - // We only handle (supposedly) RGB inputs and RGB outputs. The numbers of input - // channels and output channels both must be 3. - // TODO (msarett): - // Support different numbers of input channels. Ex: CMYK (4). - SkColorSpacePrintf("Input and output channels must equal 3 in A to B tag.\n"); - return false; - } + // On an invalid first gamma, tagBytes remains set as zero. This causes the two + // subsequent to be treated as identical (which is what we want). + size_t tagBytes = 0; + type[0] = parse_gamma(&data[0], ¶ms[0], &tagBytes, tagPtr[0], tagLen); + handle_invalid_gamma(&type[0], &data[0]); + size_t alignedTagBytes = SkAlign4(tagBytes); - // Read the offsets of each element in the A to B tag. With the exception of A curves and - // B curves (which we do not yet support), we will handle these elements in the order in - // which they should be applied (rather than the order in which they occur in the tag). - // If the offset is non-zero it indicates that the element is present. - uint32_t offsetToACurves = read_big_endian_i32(src + 28); - uint32_t offsetToBCurves = read_big_endian_i32(src + 12); - if ((0 != offsetToACurves) || (0 != offsetToBCurves)) { - // FIXME (msarett): Handle A and B curves. - // Note that the A curve is technically required in order to have a color LUT. - // However, all the A curves I have seen so far have are just placeholders that - // don't actually transform the data. - SkColorSpacePrintf("Ignoring A and/or B curve. Output may be wrong.\n"); - } - - uint32_t offsetToColorLUT = read_big_endian_i32(src + 24); - if (0 != offsetToColorLUT && offsetToColorLUT < len) { - if (!load_color_lut(colorLUT, inputChannels, src + offsetToColorLUT, - len - offsetToColorLUT)) { - SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); + bool allChannelsSame = false; + if (inputChannels * alignedTagBytes <= tagLen) { + allChannelsSame = true; + for (uint8_t i = 1; i < inputChannels; ++i) { + if (0 != memcmp(tagSrc, tagSrc + i * alignedTagBytes, tagBytes)) { + allChannelsSame = false; + break; + } } } - - uint32_t offsetToMCurves = read_big_endian_i32(src + 20); - if (0 != offsetToMCurves && offsetToMCurves < len) { - const uint8_t* rTagPtr = src + offsetToMCurves; - size_t tagLen = len - offsetToMCurves; - - SkGammas::Data rData; - SkGammas::Params rParams; - - // On an invalid first gamma, tagBytes remains set as zero. This causes the two - // subsequent to be treated as identical (which is what we want). - size_t tagBytes = 0; - SkGammas::Type rType = parse_gamma(&rData, &rParams, &tagBytes, rTagPtr, tagLen); - handle_invalid_gamma(&rType, &rData); - size_t alignedTagBytes = SkAlign4(tagBytes); - - if ((3 * alignedTagBytes <= tagLen) && - !memcmp(rTagPtr, rTagPtr + 1 * alignedTagBytes, tagBytes) && - !memcmp(rTagPtr, rTagPtr + 2 * alignedTagBytes, tagBytes)) - { - if (SkGammas::Type::kNamed_Type == rType) { - *gammaNamed = rData.fNamed; - } else { - size_t allocSize = sizeof(SkGammas); - return_if_false(safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize), - "SkGammas struct is too large to allocate"); - void* memory = sk_malloc_throw(allocSize); - *gammas = sk_sp(new (memory) SkGammas()); - load_gammas(memory, 0, rType, &rData, rParams, rTagPtr); - - (*gammas)->fRedType = rType; - (*gammas)->fGreenType = rType; - (*gammas)->fBlueType = rType; - - (*gammas)->fRedData = rData; - (*gammas)->fGreenData = rData; - (*gammas)->fBlueData = rData; - } + if (allChannelsSame) { + if (SkGammas::Type::kNamed_Type == type[0]) { + *gammaNamed = data[0].fNamed; } else { - const uint8_t* gTagPtr = rTagPtr + alignedTagBytes; - tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0; - SkGammas::Data gData; - SkGammas::Params gParams; - tagBytes = 0; - SkGammas::Type gType = parse_gamma(&gData, &gParams, &tagBytes, gTagPtr, - tagLen); - handle_invalid_gamma(&gType, &gData); - - alignedTagBytes = SkAlign4(tagBytes); - const uint8_t* bTagPtr = gTagPtr + alignedTagBytes; - tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0; - SkGammas::Data bData; - SkGammas::Params bParams; - SkGammas::Type bType = parse_gamma(&bData, &bParams, &tagBytes, bTagPtr, - tagLen); - handle_invalid_gamma(&bType, &bData); - size_t allocSize = sizeof(SkGammas); - return_if_false(safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize), - "SkGammas struct is too large to allocate"); - return_if_false(safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize), - "SkGammas struct is too large to allocate"); - return_if_false(safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize), + return_if_false(safe_add(allocSize, gamma_alloc_size(type[0], data[0]), &allocSize), "SkGammas struct is too large to allocate"); void* memory = sk_malloc_throw(allocSize); - *gammas = sk_sp(new (memory) SkGammas()); + *gammas = sk_sp(new (memory) SkGammas(inputChannels)); + load_gammas(memory, 0, type[0], &data[0], params[0], tagPtr[0]); - uint32_t offset = 0; - (*gammas)->fRedType = rType; - offset += load_gammas(memory, offset, rType, &rData, rParams, rTagPtr); - - (*gammas)->fGreenType = gType; - offset += load_gammas(memory, offset, gType, &gData, gParams, gTagPtr); - - (*gammas)->fBlueType = bType; - load_gammas(memory, offset, bType, &bData, bParams, bTagPtr); - - (*gammas)->fRedData = rData; - (*gammas)->fGreenData = gData; - (*gammas)->fBlueData = bData; + for (uint8_t channel = 0; channel < inputChannels; ++channel) { + (*gammas)->fType[channel] = type[0]; + (*gammas)->fData[channel] = data[0]; + } } } else { - // Guess sRGB if the chunk is missing a transfer function. - *gammaNamed = kSRGB_SkGammaNamed; + for (uint8_t channel = 1; channel < inputChannels; ++channel) { + tagPtr[channel] = tagPtr[channel - 1] + alignedTagBytes; + tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0; + tagBytes = 0; + type[channel] = parse_gamma(&data[channel], ¶ms[channel], &tagBytes, + tagPtr[channel], tagLen); + handle_invalid_gamma(&type[channel], &data[channel]); + alignedTagBytes = SkAlign4(tagBytes); + } + + size_t allocSize = sizeof(SkGammas); + for (uint8_t channel = 0; channel < inputChannels; ++channel) { + return_if_false(safe_add(allocSize, gamma_alloc_size(type[channel], data[channel]), + &allocSize), + "SkGammas struct is too large to allocate"); + } + void* memory = sk_malloc_throw(allocSize); + *gammas = sk_sp(new (memory) SkGammas(inputChannels)); + + uint32_t offset = 0; + for (uint8_t channel = 0; channel < inputChannels; ++channel) { + (*gammas)->fType[channel] = type[channel]; + offset += load_gammas(memory,offset, type[channel], &data[channel], params[channel], + tagPtr[channel]); + (*gammas)->fData[channel] = data[channel]; + + } } if (kNonStandard_SkGammaNamed == *gammaNamed) { @@ -871,15 +816,436 @@ static bool load_a2b0(sk_sp* colorLUT, SkGammaNamed* gammaNa *gammas = nullptr; } } + return true; +} - uint32_t offsetToMatrix = read_big_endian_i32(src + 16); - if (0 != offsetToMatrix && offsetToMatrix < len) { - if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { - SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); - toXYZ->setIdentity(); +static bool is_lut_gamma_linear(const uint8_t* src, size_t count, size_t precision) { + // check for linear gamma (this is very common in lut gammas, as they aren't optional) + const float normalizeX = 1.f / (count - 1); + for (uint32_t x = 0; x < count; ++x) { + const float y = precision == 1 ? (src[x] / 255.f) + : (read_big_endian_u16(src + 2*x) / 65535.f); + if (!color_space_almost_equal(x * normalizeX, y)) { + return false; + } + } + return true; +} + +static bool load_lut_gammas(sk_sp* gammas, SkGammaNamed* gammaNamed, size_t numTables, + size_t entriesPerTable, size_t precision, const uint8_t* src, + size_t len) { + if (precision != 1 && precision != 2) { + SkColorSpacePrintf("Invalid gamma table precision %d\n", precision); + return false; + } + uint32_t totalEntries; + return_if_false(safe_mul(entriesPerTable, numTables, &totalEntries), + "Too many entries in gamma table."); + uint32_t readBytes; + return_if_false(safe_mul(precision, totalEntries, &readBytes), + "SkGammas struct is too large to read"); + if (len < readBytes) { + SkColorSpacePrintf("Gamma table is too small. Provided: %d. Required: %d\n", + len, readBytes); + return false; + } + + uint32_t writeBytesPerChannel; + return_if_false(safe_mul(sizeof(float), entriesPerTable, &writeBytesPerChannel), + "SkGammas struct is too large to allocate"); + const size_t readBytesPerChannel = precision * entriesPerTable; + size_t numTablesToUse = 1; + for (size_t tableIndex = 1; tableIndex < numTables; ++tableIndex) { + if (0 != memcmp(src, src + readBytesPerChannel * tableIndex, readBytesPerChannel)) { + numTablesToUse = numTables; + break; } } + if (1 == numTablesToUse) { + if (is_lut_gamma_linear(src, entriesPerTable, precision)) { + *gammaNamed = kLinear_SkGammaNamed; + return true; + } + } + *gammaNamed = kNonStandard_SkGammaNamed; + + uint32_t writetableBytes; + return_if_false(safe_mul(numTablesToUse, writeBytesPerChannel, &writetableBytes), + "SkGammas struct is too large to allocate"); + size_t allocSize = sizeof(SkGammas); + return_if_false(safe_add(allocSize, (size_t)writetableBytes, &allocSize), + "SkGammas struct is too large to allocate"); + + void* memory = sk_malloc_throw(allocSize); + *gammas = sk_sp(new (memory) SkGammas(numTables)); + + for (size_t tableIndex = 0; tableIndex < numTablesToUse; ++tableIndex) { + const uint8_t* ptr = src + readBytesPerChannel * tableIndex; + const size_t offset = sizeof(SkGammas) + tableIndex * writeBytesPerChannel; + float* table = SkTAddOffset(memory, offset); + if (1 == precision) { + for (uint32_t i = 0; i < entriesPerTable; ++i, ptr += 1) { + table[i] = ((float) *ptr) / 255.0f; + } + } else if (2 == precision) { + for (uint32_t i = 0; i < entriesPerTable; ++i, ptr += 2) { + table[i] = ((float) read_big_endian_u16(ptr)) / 65535.0f; + } + } + } + + SkASSERT(1 == numTablesToUse|| numTables == numTablesToUse); + + size_t tableOffset = 0; + for (size_t tableIndex = 0; tableIndex < numTables; ++tableIndex) { + (*gammas)->fType[tableIndex] = SkGammas::Type::kTable_Type; + (*gammas)->fData[tableIndex].fTable.fOffset = tableOffset; + (*gammas)->fData[tableIndex].fTable.fSize = entriesPerTable; + if (numTablesToUse > 1) { + tableOffset += writeBytesPerChannel; + } + } + + return true; +} + +bool load_a2b0_a_to_b_type(std::vector* elements, const uint8_t* src, + size_t len, SkColorSpace_A2B::PCS pcs) { + SkASSERT(len >= 32); + // Read the number of channels. The four bytes (4-7) that we skipped are reserved and + // must be zero. + const uint8_t inputChannels = src[8]; + const uint8_t outputChannels = src[9]; + if (SkColorLookUpTable::kOutputChannels != outputChannels) { + // We only handle RGB outputs. The number of output channels must be 3. + SkColorSpacePrintf("Output channels (%d) must equal 3 in A to B tag.\n", outputChannels); + return false; + } + if (inputChannels == 0 || inputChannels > 4) { + // And we only support 4 input channels. + // ICC says up to 16 but our decode can only handle 4. + // It could easily be extended to support up to 8, but we only allow CMYK/RGB + // input color spaces which are 3 and 4 so let's restrict it to 4 instead of 8. + // We can always change this check when we support bigger input spaces. + SkColorSpacePrintf("Input channels (%d) must be between 1 and 4 in A to B tag.\n", + inputChannels); + return false; + } + + + // It is important that these are loaded in the order of application, as the + // order you construct an A2B color space's elements is the order it is applied + + // If the offset is non-zero it indicates that the element is present. + const uint32_t offsetToACurves = read_big_endian_i32(src + 28); + if (0 != offsetToACurves && offsetToACurves < len) { + const size_t tagLen = len - offsetToACurves; + SkGammaNamed gammaNamed; + sk_sp gammas; + if (!parse_and_load_gamma(&gammaNamed, &gammas, inputChannels, src + offsetToACurves, + tagLen)) { + return false; + } + if (gammas) { + elements->push_back(SkColorSpace_A2B::Element(std::move(gammas))); + } else if (kLinear_SkGammaNamed != gammaNamed) { + elements->push_back(SkColorSpace_A2B::Element(gammaNamed, inputChannels)); + } + } + + const uint32_t offsetToColorLUT = read_big_endian_i32(src + 24); + if (0 != offsetToColorLUT && offsetToColorLUT < len) { + sk_sp colorLUT; + const uint8_t* clutSrc = src + offsetToColorLUT; + const size_t clutLen = len - offsetToColorLUT; + // 16 bytes reserved for grid points, 1 for precision, 3 for padding. + // The color LUT data follows after this header. + static constexpr uint32_t kColorLUTHeaderSize = 20; + if (clutLen < kColorLUTHeaderSize) { + SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", clutLen); + return false; + } + + SkASSERT(inputChannels <= kMaxColorChannels); + uint8_t gridPoints[kMaxColorChannels]; + for (uint32_t i = 0; i < inputChannels; ++i) { + gridPoints[i] = clutSrc[i]; + } + // Space is provided for a maximum of 16 input channels. + // Now we determine the precision of the table values. + const uint8_t precision = clutSrc[16]; + if (!load_color_lut(&colorLUT, inputChannels, precision, gridPoints, + clutSrc + kColorLUTHeaderSize, clutLen - kColorLUTHeaderSize)) { + SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); + return false; + } + elements->push_back(SkColorSpace_A2B::Element(std::move(colorLUT))); + } + + const uint32_t offsetToMCurves = read_big_endian_i32(src + 20); + if (0 != offsetToMCurves && offsetToMCurves < len) { + const size_t tagLen = len - offsetToMCurves; + SkGammaNamed gammaNamed; + sk_sp gammas; + if (!parse_and_load_gamma(&gammaNamed, &gammas, outputChannels, src + offsetToMCurves, + tagLen)) { + return false; + } + if (gammas) { + elements->push_back(SkColorSpace_A2B::Element(std::move(gammas))); + } else if (kLinear_SkGammaNamed != gammaNamed) { + elements->push_back(SkColorSpace_A2B::Element(gammaNamed, outputChannels)); + } + } + + const uint32_t offsetToMatrix = read_big_endian_i32(src + 16); + if (0 != offsetToMatrix && offsetToMatrix < len) { + SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor); + if (!load_matrix(&matrix, src + offsetToMatrix, len - offsetToMatrix, true, pcs)) { + SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); + } else if (!matrix.isIdentity()) { + elements->push_back(SkColorSpace_A2B::Element(matrix)); + } + } + + const uint32_t offsetToBCurves = read_big_endian_i32(src + 12); + if (0 != offsetToBCurves && offsetToBCurves < len) { + const size_t tagLen = len - offsetToBCurves; + SkGammaNamed gammaNamed; + sk_sp gammas; + if (!parse_and_load_gamma(&gammaNamed, &gammas, outputChannels, src + offsetToBCurves, + tagLen)) { + return false; + } + if (gammas) { + elements->push_back(SkColorSpace_A2B::Element(std::move(gammas))); + } else if (kLinear_SkGammaNamed != gammaNamed) { + elements->push_back(SkColorSpace_A2B::Element(gammaNamed, outputChannels)); + } + } + + return true; +} + +bool load_a2b0_lutn_type(std::vector* elements, const uint8_t* src, + size_t len, SkColorSpace_A2B::PCS pcs) { + const uint32_t type = read_big_endian_u32(src); + switch (type) { + case kTAG_lut8Type: + SkASSERT(len >= 48); + break; + case kTAG_lut16Type: + SkASSERT(len >= 52); + break; + default: + SkASSERT(false); + return false; + } + // Read the number of channels. + // The four bytes (4-7) that we skipped are reserved and must be zero. + const uint8_t inputChannels = src[8]; + const uint8_t outputChannels = src[9]; + if (SkColorLookUpTable::kOutputChannels != outputChannels) { + // We only handle RGB outputs. The number of output channels must be 3. + SkColorSpacePrintf("Output channels (%d) must equal 3 in A to B tag.\n", outputChannels); + return false; + } + if (inputChannels == 0 || inputChannels > 4) { + // And we only support 4 input channels. + // ICC says up to 16 but our decode can only handle 4. + // It could easily be extended to support up to 8, but we only allow CMYK/RGB + // input color spaces which are 3 and 4 so let's restrict it to 4 instead of 8. + // We can always change this check when we support bigger input spaces. + SkColorSpacePrintf("Input channels (%d) must be between 1 and 4 in A to B tag.\n", + inputChannels); + return false; + } + + const uint8_t clutGridPoints = src[10]; + // 11th byte reserved for padding (required to be zero) + + SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor); + load_matrix(&matrix, &src[12], len - 12, false, pcs); + if (!matrix.isIdentity()) { + // ICC specs (10.8/10.9) say lut8/16Type profiles must have identity matrices + // if the input color space is not PCSXYZ, and we do not support PCSXYZ input color spaces + // so we should never encounter a non-identity matrix here. + // However, 2 test images from the ICC website have RGB input spaces and non-identity + // matrices so we're not going to fail here, despite being against the spec. + SkColorSpacePrintf("Warning: non-Identity matrix found in non-XYZ input color space" + "lut profile"); + elements->push_back(SkColorSpace_A2B::Element(matrix)); + } + + size_t dataOffset = 48; + // # of input table entries + size_t inTableEntries = 256; + // # of output table entries + size_t outTableEntries = 256; + size_t precision = 1; + if (kTAG_lut16Type == type) { + dataOffset = 52; + inTableEntries = read_big_endian_u16(src + 48); + outTableEntries = read_big_endian_u16(src + 50); + precision = 2; + + constexpr size_t kMaxLut16GammaEntries = 4096; + if (inTableEntries < 2) { + SkColorSpacePrintf("Too few (%d) input gamma table entries. Must have at least 2.\n", + inTableEntries); + return false; + } else if (inTableEntries > kMaxLut16GammaEntries) { + SkColorSpacePrintf("Too many (%d) input gamma table entries. Must have at most %d.\n", + inTableEntries, kMaxLut16GammaEntries); + return false; + } + + if (outTableEntries < 2) { + SkColorSpacePrintf("Too few (%d) output gamma table entries. Must have at least 2.\n", + outTableEntries); + return false; + } else if (outTableEntries > kMaxLut16GammaEntries) { + SkColorSpacePrintf("Too many (%d) output gamma table entries. Must have at most %d.\n", + outTableEntries, kMaxLut16GammaEntries); + return false; + } + } + + const size_t inputOffset = dataOffset; + return_if_false(len >= inputOffset, "A2B0 lutnType tag too small for input gamma table"); + sk_sp inputGammas; + SkGammaNamed inputGammaNamed; + if (!load_lut_gammas(&inputGammas, &inputGammaNamed, inputChannels, inTableEntries, precision, + src + inputOffset, len - inputOffset)) { + SkColorSpacePrintf("Failed to read input gammas from lutnType tag.\n"); + return false; + } + SkASSERT(inputGammas || inputGammaNamed != kNonStandard_SkGammaNamed); + if (kLinear_SkGammaNamed != inputGammaNamed) { + if (kNonStandard_SkGammaNamed != inputGammaNamed) { + elements->push_back(SkColorSpace_A2B::Element(inputGammaNamed, inputChannels)); + } else { + elements->push_back(SkColorSpace_A2B::Element(std::move(inputGammas))); + } + } + + const size_t clutOffset = inputOffset + precision*inTableEntries*inputChannels; + return_if_false(len >= clutOffset, "A2B0 lutnType tag too small for CLUT"); + sk_sp colorLUT; + const uint8_t gridPoints[kMaxColorChannels] = { + clutGridPoints, clutGridPoints, clutGridPoints, clutGridPoints + }; + if (!load_color_lut(&colorLUT, inputChannels, precision, gridPoints, src + clutOffset, + len - clutOffset)) { + SkColorSpacePrintf("Failed to read color LUT from lutnType tag.\n"); + return false; + } + SkASSERT(colorLUT); + elements->push_back(SkColorSpace_A2B::Element(std::move(colorLUT))); + + size_t clutSize = precision * outputChannels; + for (int i = 0; i < inputChannels; ++i) { + clutSize *= clutGridPoints; + } + const size_t outputOffset = clutOffset + clutSize; + return_if_false(len >= outputOffset, "A2B0 lutnType tag too small for output gamma table"); + sk_sp outputGammas; + SkGammaNamed outputGammaNamed; + if (!load_lut_gammas(&outputGammas, &outputGammaNamed, outputChannels, outTableEntries, + precision, src + outputOffset, len - outputOffset)) { + SkColorSpacePrintf("Failed to read output gammas from lutnType tag.\n"); + return false; + } + SkASSERT(outputGammas || outputGammaNamed != kNonStandard_SkGammaNamed); + if (kLinear_SkGammaNamed != outputGammaNamed) { + if (kNonStandard_SkGammaNamed != outputGammaNamed) { + elements->push_back(SkColorSpace_A2B::Element(outputGammaNamed, outputChannels)); + } else { + elements->push_back(SkColorSpace_A2B::Element(std::move(outputGammas))); + } + } + + return true; +} + +static inline int icf_channels(SkColorSpace_Base::ICCTypeFlag iccType) { + switch (iccType) { + case SkColorSpace_Base::kRGB_ICCTypeFlag: + return 3; + case SkColorSpace_Base::kCMYK_ICCTypeFlag: + return 4; + default: + SkASSERT(false); + return 0; + } +} + +static bool load_a2b0(std::vector* elements, const uint8_t* src, + size_t len, SkColorSpace_A2B::PCS pcs, + SkColorSpace_Base::ICCTypeFlag iccType) { + if (len < 4) { + return false; + } + const uint32_t type = read_big_endian_u32(src); + + switch (type) { + case kTAG_AtoBType: + if (len < 32) { + SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); + return false; + } + SkColorSpacePrintf("A2B0 tag is of type lutAtoBType\n"); + if (!load_a2b0_a_to_b_type(elements, src, len, pcs)) { + return false; + } + break; + case kTAG_lut8Type: + if (len < 48) { + SkColorSpacePrintf("lut8 tag is too small (%d bytes).", len); + return false; + } + SkColorSpacePrintf("A2B0 tag of type lut8Type\n"); + if (!load_a2b0_lutn_type(elements, src, len, pcs)) { + return false; + } + break; + case kTAG_lut16Type: + if (len < 52) { + SkColorSpacePrintf("lut16 tag is too small (%d bytes).", len); + return false; + } + SkColorSpacePrintf("A2B0 tag of type lut16Type\n"); + if (!load_a2b0_lutn_type(elements, src, len, pcs)) { + return false; + } + break; + default: + SkColorSpacePrintf("Unsupported A to B tag type: %c%c%c%c\n", (type>>24)&0xFF, + (type>>16)&0xFF, (type>>8)&0xFF, type&0xFF); + return false; + } + SkASSERT(SkColorSpace_A2B::PCS::kLAB == pcs || SkColorSpace_A2B::PCS::kXYZ == pcs); + static constexpr int kPCSChannels = 3; // must be PCSLAB or PCSXYZ + if (elements->empty()) { + return kPCSChannels == icf_channels(iccType); + } + // now let's verify that the input/output channels of each A2B element actually match up + if (icf_channels(iccType) != elements->front().inputChannels()) { + SkColorSpacePrintf("Input channel count does not match first A2B element's input count"); + return false; + } + for (size_t i = 1; i < elements->size(); ++i) { + if ((*elements)[i - 1].outputChannels() != (*elements)[i].inputChannels()) { + SkColorSpacePrintf("A2B elements don't agree in input/output channel counts"); + return false; + } + } + if (kPCSChannels != elements->back().outputChannels()) { + SkColorSpacePrintf("PCS channel count doesn't match last A2B element's output count"); + return false; + } return true; } @@ -899,7 +1265,227 @@ static bool tag_equals(const ICCTag* a, const ICCTag* b, const uint8_t* base) { return !memcmp(a->addr(base), b->addr(base), a->fLength); } -sk_sp SkColorSpace::NewICC(const void* input, size_t len) { +static inline bool is_close_to_d50(const SkMatrix44& matrix) { + // rX + gX + bX + float X = matrix.getFloat(0, 0) + matrix.getFloat(0, 1) + matrix.getFloat(0, 2); + + // rY + gY + bY + float Y = matrix.getFloat(1, 0) + matrix.getFloat(1, 1) + matrix.getFloat(1, 2); + + // rZ + gZ + bZ + float Z = matrix.getFloat(2, 0) + matrix.getFloat(2, 1) + matrix.getFloat(2, 2); + + static const float kD50_WhitePoint[3] = { 0.96420f, 1.00000f, 0.82491f }; + + // This is a bit more lenient than QCMS and Adobe. Is there a reason to be stricter here? + return (SkTAbs(X - kD50_WhitePoint[0]) <= 0.04f) && + (SkTAbs(Y - kD50_WhitePoint[1]) <= 0.04f) && + (SkTAbs(Z - kD50_WhitePoint[2]) <= 0.04f); +} + +static sk_sp make_xyz(const ICCProfileHeader& header, ICCTag* tags, int tagCount, + const uint8_t* base, sk_sp profileData) { + if (kLAB_PCSSpace == header.fPCS) { + return nullptr; + } + + // Recognize the rXYZ, gXYZ, and bXYZ tags. + const ICCTag* r = ICCTag::Find(tags, tagCount, kTAG_rXYZ); + const ICCTag* g = ICCTag::Find(tags, tagCount, kTAG_gXYZ); + const ICCTag* b = ICCTag::Find(tags, tagCount, kTAG_bXYZ); + if (!r || !g || !b) { + return nullptr; + } + + float toXYZ[9]; + if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) || + !load_xyz(&toXYZ[3], g->addr(base), g->fLength) || + !load_xyz(&toXYZ[6], b->addr(base), b->fLength)) + { + return_null("Need valid rgb tags for XYZ space"); + } + SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); + mat.set3x3(toXYZ[0], toXYZ[1], toXYZ[2], + toXYZ[3], toXYZ[4], toXYZ[5], + toXYZ[6], toXYZ[7], toXYZ[8]); + if (!is_close_to_d50(mat)) { + return_null("XYZ matrix is not D50"); + } + + // If some, but not all, of the gamma tags are missing, assume that all + // gammas are meant to be the same. + r = ICCTag::Find(tags, tagCount, kTAG_rTRC); + g = ICCTag::Find(tags, tagCount, kTAG_gTRC); + b = ICCTag::Find(tags, tagCount, kTAG_bTRC); + if ((!r || !g || !b)) { + if (!r) { + r = g ? g : b; + } + if (!g) { + g = r ? r : b; + } + if (!b) { + b = r ? r : g; + } + } + + SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed; + sk_sp gammas = nullptr; + size_t tagBytes; + if (r && g && b) { + if (tag_equals(r, g, base) && tag_equals(g, b, base)) { + SkGammas::Data data; + SkColorSpaceTransferFn params; + SkGammas::Type type = + parse_gamma(&data, ¶ms, &tagBytes, r->addr(base), r->fLength); + handle_invalid_gamma(&type, &data); + + if (SkGammas::Type::kNamed_Type == type) { + gammaNamed = data.fNamed; + } else { + size_t allocSize = sizeof(SkGammas); + if (!safe_add(allocSize, gamma_alloc_size(type, data), &allocSize)) { + return_null("SkGammas struct is too large to allocate"); + } + void* memory = sk_malloc_throw(allocSize); + gammas = sk_sp(new (memory) SkGammas(3)); + load_gammas(memory, 0, type, &data, params, r->addr(base)); + + for (int i = 0; i < 3; ++i) { + gammas->fType[i] = type; + gammas->fData[i] = data; + } + } + } else { + SkGammas::Data rData; + SkColorSpaceTransferFn rParams; + SkGammas::Type rType = + parse_gamma(&rData, &rParams, &tagBytes, r->addr(base), r->fLength); + handle_invalid_gamma(&rType, &rData); + + SkGammas::Data gData; + SkColorSpaceTransferFn gParams; + SkGammas::Type gType = + parse_gamma(&gData, &gParams, &tagBytes, g->addr(base), g->fLength); + handle_invalid_gamma(&gType, &gData); + + SkGammas::Data bData; + SkColorSpaceTransferFn bParams; + SkGammas::Type bType = + parse_gamma(&bData, &bParams, &tagBytes, b->addr(base), b->fLength); + handle_invalid_gamma(&bType, &bData); + + size_t allocSize = sizeof(SkGammas); + if (!safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize) || + !safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize) || + !safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize)) { + return_null("SkGammas struct is too large to allocate"); + } + void* memory = sk_malloc_throw(allocSize); + gammas = sk_sp(new (memory) SkGammas(3)); + + uint32_t offset = 0; + gammas->fType[0] = rType; + offset += load_gammas(memory, offset, rType, &rData, rParams, + r->addr(base)); + + gammas->fType[1] = gType; + offset += load_gammas(memory, offset, gType, &gData, gParams, + g->addr(base)); + + gammas->fType[2] = bType; + load_gammas(memory, offset, bType, &bData, bParams, b->addr(base)); + + gammas->fData[0] = rData; + gammas->fData[1] = gData; + gammas->fData[2] = bData; + } + } else { + // Guess sRGB if the profile is missing transfer functions. + gammaNamed = kSRGB_SkGammaNamed; + } + + if (kNonStandard_SkGammaNamed == gammaNamed) { + // It's possible that we'll initially detect non-matching gammas, only for + // them to evaluate to the same named gamma curve. + gammaNamed = is_named(gammas); + } + + if (kNonStandard_SkGammaNamed == gammaNamed) { + return sk_sp(new SkColorSpace_XYZ(gammaNamed, + std::move(gammas), + mat, std::move(profileData))); + } + + return SkColorSpace_Base::MakeRGB(gammaNamed, mat); +} + +static sk_sp make_gray(const ICCProfileHeader& header, ICCTag* tags, int tagCount, + const uint8_t* base, sk_sp profileData) { + if (kLAB_PCSSpace == header.fPCS) { + return nullptr; + } + + const ICCTag* grayTRC = ICCTag::Find(tags, tagCount, kTAG_kTRC); + if (!grayTRC) { + return_null("grayTRC tag required for monochrome profiles."); + } + SkGammas::Data data; + SkColorSpaceTransferFn params; + size_t tagBytes; + SkGammas::Type type = + parse_gamma(&data, ¶ms, &tagBytes, grayTRC->addr(base), grayTRC->fLength); + handle_invalid_gamma(&type, &data); + + SkMatrix44 toXYZD50(SkMatrix44::kIdentity_Constructor); + toXYZD50.setFloat(0, 0, kWhitePointD50[0]); + toXYZD50.setFloat(1, 1, kWhitePointD50[1]); + toXYZD50.setFloat(2, 2, kWhitePointD50[2]); + if (SkGammas::Type::kNamed_Type == type) { + return SkColorSpace_Base::MakeRGB(data.fNamed, toXYZD50); + } + + size_t allocSize = sizeof(SkGammas); + if (!safe_add(allocSize, gamma_alloc_size(type, data), &allocSize)) { + return_null("SkGammas struct is too large to allocate"); + } + void* memory = sk_malloc_throw(allocSize); + sk_sp gammas = sk_sp(new (memory) SkGammas(3)); + load_gammas(memory, 0, type, &data, params, grayTRC->addr(base)); + for (int i = 0; i < 3; ++i) { + gammas->fType[i] = type; + gammas->fData[i] = data; + } + + return sk_sp(new SkColorSpace_XYZ(kNonStandard_SkGammaNamed, + std::move(gammas), + toXYZD50, std::move(profileData))); +} + +static sk_sp make_a2b(SkColorSpace_Base::ICCTypeFlag iccType, + const ICCProfileHeader& header, ICCTag* tags, int tagCount, + const uint8_t* base, sk_sp profileData) { + const ICCTag* a2b0 = ICCTag::Find(tags, tagCount, kTAG_A2B0); + if (a2b0) { + const SkColorSpace_A2B::PCS pcs = kXYZ_PCSSpace == header.fPCS + ? SkColorSpace_A2B::PCS::kXYZ + : SkColorSpace_A2B::PCS::kLAB; + std::vector elements; + if (load_a2b0(&elements, a2b0->addr(base), a2b0->fLength, pcs, iccType)) { + return sk_sp(new SkColorSpace_A2B(iccType, std::move(elements), + pcs, std::move(profileData))); + } + } + + return nullptr; +} + +sk_sp SkColorSpace::MakeICC(const void* input, size_t len) { + return SkColorSpace_Base::MakeICC(input, len, SkColorSpace_Base::kRGB_ICCTypeFlag); +} + +sk_sp SkColorSpace_Base::MakeICC(const void* input, size_t len, + ICCTypeFlag desiredType) { if (!input || len < kICCHeaderSize) { return_null("Data is null or not large enough to contain an ICC profile"); } @@ -907,8 +1493,8 @@ sk_sp SkColorSpace::NewICC(const void* input, size_t len) { // Create our own copy of the input. void* memory = sk_malloc_throw(len); memcpy(memory, input, len); - sk_sp data = SkData::MakeFromMalloc(memory, len); - const uint8_t* base = data->bytes(); + sk_sp profileData = SkData::MakeFromMalloc(memory, len); + const uint8_t* base = profileData->bytes(); const uint8_t* ptr = base; // Read the ICC profile header and check to make sure that it is valid. @@ -949,390 +1535,36 @@ sk_sp SkColorSpace::NewICC(const void* input, size_t len) { switch (header.fInputColorSpace) { case kRGB_ColorSpace: { - // Recognize the rXYZ, gXYZ, and bXYZ tags. - const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ); - const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); - const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); - if (r && g && b) { - float toXYZ[9]; - if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) || - !load_xyz(&toXYZ[3], g->addr(base), g->fLength) || - !load_xyz(&toXYZ[6], b->addr(base), b->fLength)) - { - return_null("Need valid rgb tags for XYZ space"); - } - SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); - mat.set3x3(toXYZ[0], toXYZ[1], toXYZ[2], - toXYZ[3], toXYZ[4], toXYZ[5], - toXYZ[6], toXYZ[7], toXYZ[8]); - - r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); - g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); - b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); - - // If some, but not all, of the gamma tags are missing, assume that all - // gammas are meant to be the same. This behavior is an arbitrary guess, - // but it simplifies the code below. - if ((!r || !g || !b) && (r || g || b)) { - if (!r) { - r = g ? g : b; - } - - if (!g) { - g = r ? r : b; - } - - if (!b) { - b = r ? r : g; - } - } - - SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed; - sk_sp gammas = nullptr; - size_t tagBytes; - if (r && g && b) { - if (tag_equals(r, g, base) && tag_equals(g, b, base)) { - SkGammas::Data data; - SkGammas::Params params; - SkGammas::Type type = - parse_gamma(&data, ¶ms, &tagBytes, r->addr(base), r->fLength); - handle_invalid_gamma(&type, &data); - - if (SkGammas::Type::kNamed_Type == type) { - gammaNamed = data.fNamed; - } else { - size_t allocSize = sizeof(SkGammas); - if (!safe_add(allocSize, gamma_alloc_size(type, data), &allocSize)) { - return_null("SkGammas struct is too large to allocate"); - } - void* memory = sk_malloc_throw(allocSize); - gammas = sk_sp(new (memory) SkGammas()); - load_gammas(memory, 0, type, &data, params, r->addr(base)); - - gammas->fRedType = type; - gammas->fGreenType = type; - gammas->fBlueType = type; - - gammas->fRedData = data; - gammas->fGreenData = data; - gammas->fBlueData = data; - } - } else { - SkGammas::Data rData; - SkGammas::Params rParams; - SkGammas::Type rType = - parse_gamma(&rData, &rParams, &tagBytes, r->addr(base), r->fLength); - handle_invalid_gamma(&rType, &rData); - - SkGammas::Data gData; - SkGammas::Params gParams; - SkGammas::Type gType = - parse_gamma(&gData, &gParams, &tagBytes, g->addr(base), g->fLength); - handle_invalid_gamma(&gType, &gData); - - SkGammas::Data bData; - SkGammas::Params bParams; - SkGammas::Type bType = - parse_gamma(&bData, &bParams, &tagBytes, b->addr(base), b->fLength); - handle_invalid_gamma(&bType, &bData); - - size_t allocSize = sizeof(SkGammas); - if (!safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize) || - !safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize) || - !safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize)) - { - return_null("SkGammas struct is too large to allocate"); - } - void* memory = sk_malloc_throw(allocSize); - gammas = sk_sp(new (memory) SkGammas()); - - uint32_t offset = 0; - gammas->fRedType = rType; - offset += load_gammas(memory, offset, rType, &rData, rParams, - r->addr(base)); - - gammas->fGreenType = gType; - offset += load_gammas(memory, offset, gType, &gData, gParams, - g->addr(base)); - - gammas->fBlueType = bType; - load_gammas(memory, offset, bType, &bData, bParams, b->addr(base)); - - gammas->fRedData = rData; - gammas->fGreenData = gData; - gammas->fBlueData = bData; - } - } else { - // Guess sRGB if the profile is missing transfer functions. - gammaNamed = kSRGB_SkGammaNamed; - } - - if (kNonStandard_SkGammaNamed == gammaNamed) { - // It's possible that we'll initially detect non-matching gammas, only for - // them to evaluate to the same named gamma curve. - gammaNamed = is_named(gammas); - if (kNonStandard_SkGammaNamed == gammaNamed) { - return sk_sp(new SkColorSpace_Base(nullptr, gammaNamed, - std::move(gammas), mat, - std::move(data))); - } - } - - return SkColorSpace_Base::NewRGB(gammaNamed, mat); + if (!(kRGB_ICCTypeFlag & desiredType)) { + return_null("Provided input color format (RGB) does not match profile."); } - // Recognize color profile specified by A2B0 tag. - const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); - if (a2b0) { - SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed; - sk_sp gammas = nullptr; - sk_sp colorLUT = nullptr; - SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); - if (!load_a2b0(&colorLUT, &gammaNamed, &gammas, &toXYZ, a2b0->addr(base), - a2b0->fLength)) { - return_null("Failed to parse A2B0 tag"); - } - - if (colorLUT || kNonStandard_SkGammaNamed == gammaNamed) { - return sk_sp(new SkColorSpace_Base(std::move(colorLUT), - gammaNamed, std::move(gammas), - toXYZ, std::move(data))); - } - - return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ); + sk_sp colorSpace = + make_xyz(header, tags.get(), tagCount, base, profileData); + if (colorSpace) { + return colorSpace; } - } - default: + + desiredType = kRGB_ICCTypeFlag; break; - } - - return_null("ICC profile contains unsupported colorspace"); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// We will write a profile with the minimum nine required tags. -static constexpr uint32_t kICCNumEntries = 9; - -static constexpr uint32_t kTAG_desc = SkSetFourByteTag('d', 'e', 's', 'c'); -static constexpr uint32_t kTAG_desc_Bytes = 12; -static constexpr uint32_t kTAG_desc_Offset = kICCHeaderSize + kICCNumEntries*kICCTagTableEntrySize; - -static constexpr uint32_t kTAG_XYZ_Bytes = 20; -static constexpr uint32_t kTAG_rXYZ_Offset = kTAG_desc_Offset + kTAG_desc_Bytes; -static constexpr uint32_t kTAG_gXYZ_Offset = kTAG_rXYZ_Offset + kTAG_XYZ_Bytes; -static constexpr uint32_t kTAG_bXYZ_Offset = kTAG_gXYZ_Offset + kTAG_XYZ_Bytes; - -static constexpr uint32_t kTAG_TRC_Bytes = 14; -static constexpr uint32_t kTAG_rTRC_Offset = kTAG_bXYZ_Offset + kTAG_XYZ_Bytes; -static constexpr uint32_t kTAG_gTRC_Offset = kTAG_rTRC_Offset + SkAlign4(kTAG_TRC_Bytes); -static constexpr uint32_t kTAG_bTRC_Offset = kTAG_gTRC_Offset + SkAlign4(kTAG_TRC_Bytes); - -static constexpr uint32_t kTAG_wtpt = SkSetFourByteTag('w', 't', 'p', 't'); -static constexpr uint32_t kTAG_wtpt_Offset = kTAG_bTRC_Offset + SkAlign4(kTAG_TRC_Bytes); - -static constexpr uint32_t kTAG_cprt = SkSetFourByteTag('c', 'p', 'r', 't'); -static constexpr uint32_t kTAG_cprt_Bytes = 12; -static constexpr uint32_t kTAG_cprt_Offset = kTAG_wtpt_Offset + kTAG_XYZ_Bytes; - -static constexpr uint32_t kICCProfileSize = kTAG_cprt_Offset + kTAG_cprt_Bytes; - -static constexpr uint32_t gICCHeader[kICCHeaderSize / 4] { - SkEndian_SwapBE32(kICCProfileSize), // Size of the profile - 0, // Preferred CMM type (ignored) - SkEndian_SwapBE32(0x02100000), // Version 2.1 - SkEndian_SwapBE32(kDisplay_Profile), // Display device profile - SkEndian_SwapBE32(kRGB_ColorSpace), // RGB input color space - SkEndian_SwapBE32(kXYZ_PCSSpace), // XYZ profile connection space - 0, 0, 0, // Date and time (ignored) - SkEndian_SwapBE32(kACSP_Signature), // Profile signature - 0, // Platform target (ignored) - 0x00000000, // Flags: not embedded, can be used independently - 0, // Device manufacturer (ignored) - 0, // Device model (ignored) - 0, 0, // Device attributes (ignored) - SkEndian_SwapBE32(1), // Relative colorimetric rendering intent - SkEndian_SwapBE32(0x0000f6d6), // D50 standard illuminant (X) - SkEndian_SwapBE32(0x00010000), // D50 standard illuminant (Y) - SkEndian_SwapBE32(0x0000d32d), // D50 standard illuminant (Z) - 0, // Profile creator (ignored) - 0, 0, 0, 0, // Profile id checksum (ignored) - 0, 0, 0, 0, 0, 0, 0, // Reserved (ignored) - SkEndian_SwapBE32(kICCNumEntries), // Number of tags -}; - -static constexpr uint32_t gICCTagTable[3 * kICCNumEntries] { - // Profile description - SkEndian_SwapBE32(kTAG_desc), - SkEndian_SwapBE32(kTAG_desc_Offset), - SkEndian_SwapBE32(kTAG_desc_Bytes), - - // rXYZ - SkEndian_SwapBE32(kTAG_rXYZ), - SkEndian_SwapBE32(kTAG_rXYZ_Offset), - SkEndian_SwapBE32(kTAG_XYZ_Bytes), - - // gXYZ - SkEndian_SwapBE32(kTAG_gXYZ), - SkEndian_SwapBE32(kTAG_gXYZ_Offset), - SkEndian_SwapBE32(kTAG_XYZ_Bytes), - - // bXYZ - SkEndian_SwapBE32(kTAG_bXYZ), - SkEndian_SwapBE32(kTAG_bXYZ_Offset), - SkEndian_SwapBE32(kTAG_XYZ_Bytes), - - // rTRC - SkEndian_SwapBE32(kTAG_rTRC), - SkEndian_SwapBE32(kTAG_rTRC_Offset), - SkEndian_SwapBE32(kTAG_TRC_Bytes), - - // gTRC - SkEndian_SwapBE32(kTAG_gTRC), - SkEndian_SwapBE32(kTAG_gTRC_Offset), - SkEndian_SwapBE32(kTAG_TRC_Bytes), - - // bTRC - SkEndian_SwapBE32(kTAG_bTRC), - SkEndian_SwapBE32(kTAG_bTRC_Offset), - SkEndian_SwapBE32(kTAG_TRC_Bytes), - - // White point - SkEndian_SwapBE32(kTAG_wtpt), - SkEndian_SwapBE32(kTAG_wtpt_Offset), - SkEndian_SwapBE32(kTAG_XYZ_Bytes), - - // Copyright - SkEndian_SwapBE32(kTAG_cprt), - SkEndian_SwapBE32(kTAG_cprt_Offset), - SkEndian_SwapBE32(kTAG_cprt_Bytes), -}; - -static constexpr uint32_t kTAG_TextType = SkSetFourByteTag('m', 'l', 'u', 'c'); -static constexpr uint32_t gEmptyTextTag[3] { - SkEndian_SwapBE32(kTAG_TextType), // Type signature - 0, // Reserved - 0, // Zero records -}; - -static void write_xyz_tag(uint32_t* ptr, const SkMatrix44& toXYZ, int col) { - ptr[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); - ptr[1] = 0; - ptr[2] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(0, col))); - ptr[3] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(1, col))); - ptr[4] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(2, col))); -} - -static void write_trc_tag(uint32_t* ptr, float value) { - ptr[0] = SkEndian_SwapBE32(kTAG_CurveType); - ptr[1] = 0; - - // Gamma will be specified with a single value. - ptr[2] = SkEndian_SwapBE32(1); - - // Convert gamma to 16-bit fixed point. - uint16_t* ptr16 = (uint16_t*) (ptr + 3); - ptr16[0] = SkEndian_SwapBE16((uint16_t) (value * 256.0f)); - - // Pad tag with zero. - ptr16[1] = 0; -} - -sk_sp SkColorSpace_Base::writeToICC() const { - // Return if this object was created from a profile, or if we have already serialized - // the profile. - if (fProfileData) { - return fProfileData; - } - - // The client may create an SkColorSpace using an SkMatrix44, but currently we only - // support writing profiles with 3x3 matrices. - // TODO (msarett): Fix this! - if (0.0f != fToXYZD50.getFloat(3, 0) || 0.0f != fToXYZD50.getFloat(3, 1) || - 0.0f != fToXYZD50.getFloat(3, 2) || 0.0f != fToXYZD50.getFloat(0, 3) || - 0.0f != fToXYZD50.getFloat(1, 3) || 0.0f != fToXYZD50.getFloat(2, 3)) - { - return nullptr; - } - - SkAutoMalloc profile(kICCProfileSize); - uint8_t* ptr = (uint8_t*) profile.get(); - - // Write profile header - memcpy(ptr, gICCHeader, sizeof(gICCHeader)); - ptr += sizeof(gICCHeader); - - // Write tag table - memcpy(ptr, gICCTagTable, sizeof(gICCTagTable)); - ptr += sizeof(gICCTagTable); - - // Write profile description tag - memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); - ptr += sizeof(gEmptyTextTag); - - // Write XYZ tags - write_xyz_tag((uint32_t*) ptr, fToXYZD50, 0); - ptr += kTAG_XYZ_Bytes; - write_xyz_tag((uint32_t*) ptr, fToXYZD50, 1); - ptr += kTAG_XYZ_Bytes; - write_xyz_tag((uint32_t*) ptr, fToXYZD50, 2); - ptr += kTAG_XYZ_Bytes; - - // Write TRC tags - SkGammaNamed gammaNamed = this->gammaNamed(); - if (kNonStandard_SkGammaNamed == gammaNamed) { - // FIXME (msarett): - // Write the correct gamma representation rather than 2.2f. - write_trc_tag((uint32_t*) ptr, 2.2f); - ptr += SkAlign4(kTAG_TRC_Bytes); - write_trc_tag((uint32_t*) ptr, 2.2f); - ptr += SkAlign4(kTAG_TRC_Bytes); - write_trc_tag((uint32_t*) ptr, 2.2f); - ptr += SkAlign4(kTAG_TRC_Bytes); - } else { - switch (gammaNamed) { - case kSRGB_SkGammaNamed: - // FIXME (msarett): - // kSRGB cannot be represented by a value. Here we fall through to 2.2f, - // which is a close guess. To be more accurate, we need to represent sRGB - // gamma with a parametric curve. - case k2Dot2Curve_SkGammaNamed: - write_trc_tag((uint32_t*) ptr, 2.2f); - ptr += SkAlign4(kTAG_TRC_Bytes); - write_trc_tag((uint32_t*) ptr, 2.2f); - ptr += SkAlign4(kTAG_TRC_Bytes); - write_trc_tag((uint32_t*) ptr, 2.2f); - ptr += SkAlign4(kTAG_TRC_Bytes); - break; - case kLinear_SkGammaNamed: - write_trc_tag((uint32_t*) ptr, 1.0f); - ptr += SkAlign4(kTAG_TRC_Bytes); - write_trc_tag((uint32_t*) ptr, 1.0f); - ptr += SkAlign4(kTAG_TRC_Bytes); - write_trc_tag((uint32_t*) ptr, 1.0f); - ptr += SkAlign4(kTAG_TRC_Bytes); - break; - default: - SkASSERT(false); - break; } + case kGray_ColorSpace: { + if (!(kGray_ICCTypeFlag & desiredType)) { + return_null("Provided input color format (Gray) does not match profile."); + } + + return make_gray(header, tags.get(), tagCount, base, profileData); + } + case kCMYK_ColorSpace: + if (!(kCMYK_ICCTypeFlag & desiredType)) { + return_null("Provided input color format (CMYK) does not match profile."); + } + + desiredType = kCMYK_ICCTypeFlag; + break; + default: + return_null("ICC profile contains unsupported colorspace"); } - // Write white point tag - uint32_t* ptr32 = (uint32_t*) ptr; - ptr32[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); - ptr32[1] = 0; - // TODO (msarett): These values correspond to the D65 white point. This may not always be - // correct. - ptr32[2] = SkEndian_SwapBE32(0x0000f351); - ptr32[3] = SkEndian_SwapBE32(0x00010000); - ptr32[4] = SkEndian_SwapBE32(0x000116cc); - ptr += kTAG_XYZ_Bytes; - - // Write copyright tag - memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); - - // TODO (msarett): Should we try to hold onto the data so we can return immediately if - // the client calls again? - return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); + return make_a2b(desiredType, header, tags.get(), tagCount, base, profileData); } diff --git a/gfx/skia/skia/src/core/SkColorSpace_XYZ.cpp b/gfx/skia/skia/src/core/SkColorSpace_XYZ.cpp new file mode 100644 index 000000000000..baf99694b336 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpace_XYZ.cpp @@ -0,0 +1,114 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorSpace_XYZ.h" +#include "SkColorSpacePriv.h" +#include "SkColorSpaceXform_Base.h" +#include "SkOpts.h" + +SkColorSpace_XYZ::SkColorSpace_XYZ(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50) + : INHERITED(nullptr) + , fGammaNamed(gammaNamed) + , fGammas(nullptr) + , fToXYZD50(toXYZD50) + , fToXYZD50Hash(SkOpts::hash_fn(toXYZD50.values(), 16 * sizeof(SkMScalar), 0)) + , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) +{} + +SkColorSpace_XYZ::SkColorSpace_XYZ(SkGammaNamed gammaNamed, sk_sp gammas, + const SkMatrix44& toXYZD50, sk_sp profileData) + : INHERITED(std::move(profileData)) + , fGammaNamed(gammaNamed) + , fGammas(std::move(gammas)) + , fToXYZD50(toXYZD50) + , fToXYZD50Hash(SkOpts::hash_fn(toXYZD50.values(), 16 * sizeof(SkMScalar), 0)) + , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) { + SkASSERT(!fGammas || 3 == fGammas->channels()); + if (fGammas) { + for (int i = 0; i < fGammas->channels(); ++i) { + if (SkGammas::Type::kTable_Type == fGammas->type(i)) { + SkASSERT(fGammas->data(i).fTable.fSize >= 2); + } + } + } +} + +const SkMatrix44* SkColorSpace_XYZ::fromXYZD50() const { + fFromXYZOnce([this] { + if (!fToXYZD50.invert(&fFromXYZD50)) { + // If a client gives us a dst gamut with a transform that we can't invert, we will + // simply give them back a transform to sRGB gamut. + SkDEBUGFAIL("Non-invertible XYZ matrix, defaulting to sRGB"); + SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); + srgbToxyzD50.set3x3RowMajorf(gSRGB_toXYZD50); + srgbToxyzD50.invert(&fFromXYZD50); + } + }); + return &fFromXYZD50; +} + +bool SkColorSpace_XYZ::onGammaCloseToSRGB() const { + return kSRGB_SkGammaNamed == fGammaNamed || k2Dot2Curve_SkGammaNamed == fGammaNamed; +} + +bool SkColorSpace_XYZ::onGammaIsLinear() const { + return kLinear_SkGammaNamed == fGammaNamed; +} + +bool SkColorSpace_XYZ::onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const { + if (named_to_parametric(coeffs, fGammaNamed)) { + return true; + } + + SkASSERT(fGammas); + if (fGammas->data(0) != fGammas->data(1) || fGammas->data(0) != fGammas->data(2)) { + return false; + } + + if (fGammas->isValue(0)) { + value_to_parametric(coeffs, fGammas->data(0).fValue); + return true; + } + + if (fGammas->isParametric(0)) { + *coeffs = fGammas->params(0); + return true; + } + + return false; +} + +sk_sp SkColorSpace_XYZ::makeLinearGamma() { + if (this->gammaIsLinear()) { + return sk_ref_sp(this); + } + return SkColorSpace_Base::MakeRGB(kLinear_SkGammaNamed, fToXYZD50); +} + +sk_sp SkColorSpace_XYZ::makeSRGBGamma() { + if (this->gammaCloseToSRGB()) { + return sk_ref_sp(this); + } + return SkColorSpace_Base::MakeRGB(kSRGB_SkGammaNamed, fToXYZD50); +} + +void SkColorSpace_XYZ::toDstGammaTables(const uint8_t* tables[3], sk_sp* storage, + int numTables) const { + fToDstGammaOnce([this, numTables] { + const bool gammasAreMatching = numTables <= 1; + fDstStorage = + SkData::MakeUninitialized(numTables * SkColorSpaceXform_Base::kDstGammaTableSize); + SkColorSpaceXform_Base::BuildDstGammaTables(fToDstGammaTables, + (uint8_t*) fDstStorage->writable_data(), this, + gammasAreMatching); + }); + + *storage = fDstStorage; + tables[0] = fToDstGammaTables[0]; + tables[1] = fToDstGammaTables[1]; + tables[2] = fToDstGammaTables[2]; +} diff --git a/gfx/skia/skia/src/core/SkColorSpace_XYZ.h b/gfx/skia/skia/src/core/SkColorSpace_XYZ.h new file mode 100644 index 000000000000..d0ce0f813e37 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpace_XYZ.h @@ -0,0 +1,63 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpace_XYZ_DEFINED +#define SkColorSpace_XYZ_DEFINED + +#include "SkColorSpace_Base.h" +#include "SkData.h" +#include "SkOnce.h" + +class SkColorSpace_XYZ : public SkColorSpace_Base { +public: + const SkMatrix44* toXYZD50() const override { return &fToXYZD50; } + uint32_t toXYZD50Hash() const override { return fToXYZD50Hash; } + + const SkMatrix44* fromXYZD50() const override; + + bool onGammaCloseToSRGB() const override; + + bool onGammaIsLinear() const override; + + bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const override; + + Type type() const override { return Type::kXYZ; } + + sk_sp makeLinearGamma() override; + sk_sp makeSRGBGamma() override; + + SkGammaNamed gammaNamed() const { return fGammaNamed; } + + const SkGammas* gammas() const { return fGammas.get(); } + + void toDstGammaTables(const uint8_t* tables[3], sk_sp* storage, int numTables) const; + + SkColorSpace_XYZ(SkGammaNamed gammaNamed, const SkMatrix44& toXYZ); + + SkColorSpace_XYZ(SkGammaNamed gammaNamed, sk_sp gammas, + const SkMatrix44& toXYZ, sk_sp profileData); + +private: + const SkGammaNamed fGammaNamed; + sk_sp fGammas; + const SkMatrix44 fToXYZD50; + uint32_t fToXYZD50Hash; + + mutable SkMatrix44 fFromXYZD50; + mutable SkOnce fFromXYZOnce; + + mutable sk_sp fDstStorage; + mutable const uint8_t* fToDstGammaTables[3]; + mutable SkOnce fToDstGammaOnce; + + friend class SkColorSpace; + friend class SkColorSpace_Base; + friend class ColorSpaceXformTest; + typedef SkColorSpace_Base INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkColorTable.cpp b/gfx/skia/skia/src/core/SkColorTable.cpp index 296b31c369e4..928f5158d428 100644 --- a/gfx/skia/skia/src/core/SkColorTable.cpp +++ b/gfx/skia/skia/src/core/SkColorTable.cpp @@ -23,11 +23,7 @@ void SkColorTable::init(const SkPMColor colors[], int count) { SkColorTable::SkColorTable(const SkPMColor colors[], int count) { SkASSERT(0 == count || colors); - if (count < 0) { - count = 0; - } else if (count > 256) { - count = 256; - } + SkASSERT(count >= 0 && count <= 256); this->init(colors, count); } @@ -56,6 +52,16 @@ const uint16_t* SkColorTable::read16BitCache() const { return f16BitCache; } +sk_sp SkColorTable::Make(const SkPMColor colors[], int count) { + if (count < 0 || count > 256) { + return nullptr; + } + if (count && !colors) { + return nullptr; + } + return sk_make_sp(colors, count); +} + /////////////////////////////////////////////////////////////////////////////// #if 0 @@ -85,14 +91,14 @@ void SkColorTable::writeToBuffer(SkWriteBuffer& buffer) const { buffer.writeColorArray(fColors, fCount); } -SkColorTable* SkColorTable::Create(SkReadBuffer& buffer) { +sk_sp SkColorTable::Create(SkReadBuffer& buffer) { if (buffer.isVersionLT(SkReadBuffer::kRemoveColorTableAlpha_Version)) { /*fAlphaType = */buffer.readUInt(); } const int count = buffer.getArrayCount(); if (0 == count) { - return new SkColorTable(nullptr, 0); + return sk_sp(new SkColorTable(nullptr, 0)); } if (count < 0 || count > 256) { @@ -101,10 +107,10 @@ SkColorTable* SkColorTable::Create(SkReadBuffer& buffer) { } const size_t allocSize = count * sizeof(SkPMColor); - SkAutoTDelete colors((SkPMColor*)sk_malloc_throw(allocSize)); - if (!buffer.readColorArray(colors, count)) { + std::unique_ptr colors((SkPMColor*)sk_malloc_throw(allocSize)); + if (!buffer.readColorArray(colors.get(), count)) { return nullptr; } - return new SkColorTable(colors.release(), count, kAllocatedWithMalloc); + return sk_sp(new SkColorTable(colors.release(), count, kAllocatedWithMalloc)); } diff --git a/gfx/skia/skia/src/core/SkComposeShader.cpp b/gfx/skia/skia/src/core/SkComposeShader.cpp index 7696e1632e73..dd95c3edb3c4 100644 --- a/gfx/skia/skia/src/core/SkComposeShader.cpp +++ b/gfx/skia/skia/src/core/SkComposeShader.cpp @@ -5,23 +5,31 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkComposeShader.h" #include "SkColorFilter.h" #include "SkColorPriv.h" #include "SkColorShader.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" -#include "SkXfermode.h" #include "SkString.h" -/////////////////////////////////////////////////////////////////////////////// - -size_t SkComposeShader::onContextSize(const ContextRec& rec) const { - return sizeof(ComposeShaderContext) - + fShaderA->contextSize(rec) - + fShaderB->contextSize(rec); +sk_sp SkShader::MakeComposeShader(sk_sp dst, sk_sp src, + SkBlendMode mode) { + if (!src || !dst) { + return nullptr; + } + if (SkBlendMode::kSrc == mode) { + return src; + } + if (SkBlendMode::kDst == mode) { + return dst; + } + return sk_sp(new SkComposeShader(std::move(dst), std::move(src), mode)); } +/////////////////////////////////////////////////////////////////////////////// + class SkAutoAlphaRestore { public: SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { @@ -42,29 +50,28 @@ private: sk_sp SkComposeShader::CreateProc(SkReadBuffer& buffer) { sk_sp shaderA(buffer.readShader()); sk_sp shaderB(buffer.readShader()); - sk_sp mode(buffer.readXfermode()); + SkBlendMode mode; + if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode2_Version)) { + sk_sp xfer = buffer.readXfermode(); + mode = xfer ? xfer->blend() : SkBlendMode::kSrcOver; + } else { + mode = (SkBlendMode)buffer.read32(); + } if (!shaderA || !shaderB) { return nullptr; } - return sk_make_sp(std::move(shaderA), std::move(shaderB), std::move(mode)); + return sk_make_sp(std::move(shaderA), std::move(shaderB), mode); } void SkComposeShader::flatten(SkWriteBuffer& buffer) const { buffer.writeFlattenable(fShaderA.get()); buffer.writeFlattenable(fShaderB.get()); - buffer.writeFlattenable(fMode.get()); + buffer.write32((int)fMode); } -template void safe_call_destructor(T* obj) { - if (obj) { - obj->~T(); - } -} - -SkShader::Context* SkComposeShader::onCreateContext(const ContextRec& rec, void* storage) const { - char* aStorage = (char*) storage + sizeof(ComposeShaderContext); - char* bStorage = aStorage + fShaderA->contextSize(rec); - +SkShader::Context* SkComposeShader::onMakeContext( + const ContextRec& rec, SkArenaAlloc* alloc) const +{ // we preconcat our localMatrix (if any) with the device matrix // before calling our sub-shaders SkMatrix tmpM; @@ -80,15 +87,13 @@ SkShader::Context* SkComposeShader::onCreateContext(const ContextRec& rec, void* newRec.fMatrix = &tmpM; newRec.fPaint = &opaquePaint; - SkShader::Context* contextA = fShaderA->createContext(newRec, aStorage); - SkShader::Context* contextB = fShaderB->createContext(newRec, bStorage); + SkShader::Context* contextA = fShaderA->makeContext(newRec, alloc); + SkShader::Context* contextB = fShaderB->makeContext(newRec, alloc); if (!contextA || !contextB) { - safe_call_destructor(contextA); - safe_call_destructor(contextB); return nullptr; } - return new (storage) ComposeShaderContext(*this, rec, contextA, contextB); + return alloc->make(*this, rec, contextA, contextB); } SkComposeShader::ComposeShaderContext::ComposeShaderContext( @@ -98,16 +103,11 @@ SkComposeShader::ComposeShaderContext::ComposeShaderContext( , fShaderContextA(contextA) , fShaderContextB(contextB) {} -SkComposeShader::ComposeShaderContext::~ComposeShaderContext() { - fShaderContextA->~Context(); - fShaderContextB->~Context(); -} - bool SkComposeShader::asACompose(ComposeRec* rec) const { if (rec) { - rec->fShaderA = fShaderA.get(); - rec->fShaderB = fShaderB.get(); - rec->fMode = fMode.get(); + rec->fShaderA = fShaderA.get(); + rec->fShaderB = fShaderB.get(); + rec->fBlendMode = fMode; } return true; } @@ -120,12 +120,13 @@ bool SkComposeShader::asACompose(ComposeRec* rec) const { void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { SkShader::Context* shaderContextA = fShaderContextA; SkShader::Context* shaderContextB = fShaderContextB; - SkXfermode* mode = static_cast(fShader).fMode.get(); + SkBlendMode mode = static_cast(fShader).fMode; unsigned scale = SkAlpha255To256(this->getPaintAlpha()); SkPMColor tmp[TMP_COLOR_COUNT]; - if (nullptr == mode) { // implied SRC_OVER + SkXfermode* xfer = SkXfermode::Peek(mode); + if (nullptr == xfer) { // implied SRC_OVER // TODO: when we have a good test-case, should use SkBlitRow::Proc32 // for these loops do { @@ -161,7 +162,7 @@ void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor re shaderContextA->shadeSpan(x, y, result, n); shaderContextB->shadeSpan(x, y, tmp, n); - mode->xfer32(result, tmp, n, nullptr); + xfer->xfer32(result, tmp, n, nullptr); if (256 != scale) { for (int i = 0; i < n; i++) { @@ -184,21 +185,15 @@ void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor re ///////////////////////////////////////////////////////////////////// sk_sp SkComposeShader::asFragmentProcessor(const AsFPArgs& args) const { - // Fragment processor will only support SkXfermode::Mode modes currently. - SkXfermode::Mode mode; - if (!(SkXfermode::AsMode(fMode, &mode))) { - return nullptr; - } - - switch (mode) { - case SkXfermode::kClear_Mode: - return GrConstColorProcessor::Make(GrColor_TRANSPARENT_BLACK, + switch (fMode) { + case SkBlendMode::kClear: + return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), GrConstColorProcessor::kIgnore_InputMode); break; - case SkXfermode::kSrc_Mode: + case SkBlendMode::kSrc: return fShaderB->asFragmentProcessor(args); break; - case SkXfermode::kDst_Mode: + case SkBlendMode::kDst: return fShaderA->asFragmentProcessor(args); break; default: @@ -211,7 +206,7 @@ sk_sp SkComposeShader::asFragmentProcessor(const AsFPArgs& return nullptr; } return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), - std::move(fpA), mode); + std::move(fpA), fMode); } } #endif @@ -224,9 +219,8 @@ void SkComposeShader::toString(SkString* str) const { fShaderA->toString(str); str->append(" ShaderB: "); fShaderB->toString(str); - if (fMode) { - str->append(" Xfermode: "); - fMode->toString(str); + if (SkBlendMode::kSrcOver != fMode) { + str->appendf(" Xfermode: %s", SkXfermode::ModeName(fMode)); } this->INHERITED::toString(str); @@ -234,18 +228,3 @@ void SkComposeShader::toString(SkString* str) const { str->append(")"); } #endif - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -sk_sp SkShader::MakeComposeShader(sk_sp dst, sk_sp src, - sk_sp xfer) { - if (!dst || !src) { - return nullptr; - } - return sk_make_sp(std::move(dst), std::move(src), std::move(xfer)); -} - -sk_sp SkShader::MakeComposeShader(sk_sp dst, sk_sp src, - SkXfermode::Mode mode) { - return MakeComposeShader(std::move(dst), std::move(src), SkXfermode::Make(mode)); -} diff --git a/gfx/skia/skia/src/core/SkComposeShader.h b/gfx/skia/skia/src/core/SkComposeShader.h index d1b095ec3fd0..be788af2af5a 100644 --- a/gfx/skia/skia/src/core/SkComposeShader.h +++ b/gfx/skia/skia/src/core/SkComposeShader.h @@ -9,7 +9,7 @@ #define SkComposeShader_DEFINED #include "SkShader.h" -#include "SkXfermode.h" +#include "SkBlendMode.h" /////////////////////////////////////////////////////////////////////////////////////////// @@ -28,10 +28,10 @@ public: @param mode The xfermode that combines the colors from the two shaders. If mode is null, then SRC_OVER is assumed. */ - SkComposeShader(sk_sp sA, sk_sp sB, sk_sp mode) + SkComposeShader(sk_sp sA, sk_sp sB, SkBlendMode mode) : fShaderA(std::move(sA)) , fShaderB(std::move(sB)) - , fMode(std::move(mode)) + , fMode(mode) {} #if SK_SUPPORT_GPU @@ -45,11 +45,6 @@ public: ComposeShaderContext(const SkComposeShader&, const ContextRec&, SkShader::Context* contextA, SkShader::Context* contextB); - SkShader::Context* getShaderContextA() const { return fShaderContextA; } - SkShader::Context* getShaderContextB() const { return fShaderContextB; } - - virtual ~ComposeShaderContext(); - void shadeSpan(int x, int y, SkPMColor[], int count) override; private: @@ -72,13 +67,12 @@ public: protected: SkComposeShader(SkReadBuffer&); void flatten(SkWriteBuffer&) const override; - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec&, void*) const override; + Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override; private: sk_sp fShaderA; sk_sp fShaderB; - sk_sp fMode; + SkBlendMode fMode; typedef SkShader INHERITED; }; diff --git a/gfx/skia/skia/src/core/SkConfig8888.cpp b/gfx/skia/skia/src/core/SkConfig8888.cpp deleted file mode 100644 index 7c3f0214e34a..000000000000 --- a/gfx/skia/skia/src/core/SkConfig8888.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBitmap.h" -#include "SkCanvas.h" -#include "SkConfig8888.h" -#include "SkColorPriv.h" -#include "SkDither.h" -#include "SkMathPriv.h" -#include "SkUnPreMultiply.h" - -enum AlphaVerb { - kNothing_AlphaVerb, - kPremul_AlphaVerb, - kUnpremul_AlphaVerb, -}; - -template uint32_t convert32(uint32_t c) { - if (doSwapRB) { - c = SkSwizzle_RB(c); - } - - // Lucky for us, in both RGBA and BGRA, the alpha component is always in the same place, so - // we can perform premul or unpremul the same way without knowing the swizzles for RGB. - switch (doAlpha) { - case kNothing_AlphaVerb: - // no change - break; - case kPremul_AlphaVerb: - c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c), - SkGetPackedG32(c), SkGetPackedB32(c)); - break; - case kUnpremul_AlphaVerb: - c = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(c); - break; - } - return c; -} - -template -void convert32_row(uint32_t* dst, const uint32_t* src, int count) { - // This has to be correct if src == dst (but not partial overlap) - for (int i = 0; i < count; ++i) { - dst[i] = convert32(src[i]); - } -} - -static bool is_32bit_colortype(SkColorType ct) { - return kRGBA_8888_SkColorType == ct || kBGRA_8888_SkColorType == ct; -} - -static AlphaVerb compute_AlphaVerb(SkAlphaType src, SkAlphaType dst) { - SkASSERT(kUnknown_SkAlphaType != src); - SkASSERT(kUnknown_SkAlphaType != dst); - - if (kOpaque_SkAlphaType == src || kOpaque_SkAlphaType == dst || src == dst) { - return kNothing_AlphaVerb; - } - if (kPremul_SkAlphaType == dst) { - SkASSERT(kUnpremul_SkAlphaType == src); - return kPremul_AlphaVerb; - } else { - SkASSERT(kPremul_SkAlphaType == src); - SkASSERT(kUnpremul_SkAlphaType == dst); - return kUnpremul_AlphaVerb; - } -} - -static void memcpy32_row(uint32_t* dst, const uint32_t* src, int count) { - memcpy(dst, src, count * 4); -} - -bool SkSrcPixelInfo::convertPixelsTo(SkDstPixelInfo* dst, int width, int height) const { - if (width <= 0 || height <= 0) { - return false; - } - - if (!is_32bit_colortype(fColorType) || !is_32bit_colortype(dst->fColorType)) { - return false; - } - - void (*proc)(uint32_t* dst, const uint32_t* src, int count); - AlphaVerb doAlpha = compute_AlphaVerb(fAlphaType, dst->fAlphaType); - bool doSwapRB = fColorType != dst->fColorType; - - switch (doAlpha) { - case kNothing_AlphaVerb: - if (doSwapRB) { - proc = convert32_row; - } else { - if (fPixels == dst->fPixels) { - return true; - } - proc = memcpy32_row; - } - break; - case kPremul_AlphaVerb: - if (doSwapRB) { - proc = convert32_row; - } else { - proc = convert32_row; - } - break; - case kUnpremul_AlphaVerb: - if (doSwapRB) { - proc = convert32_row; - } else { - proc = convert32_row; - } - break; - } - - uint32_t* dstP = static_cast(dst->fPixels); - const uint32_t* srcP = static_cast(fPixels); - size_t srcInc = fRowBytes >> 2; - size_t dstInc = dst->fRowBytes >> 2; - for (int y = 0; y < height; ++y) { - proc(dstP, srcP, width); - dstP += dstInc; - srcP += srcInc; - } - return true; -} - -static void copy_g8_to_32(void* dst, size_t dstRB, const void* src, size_t srcRB, int w, int h) { - uint32_t* dst32 = (uint32_t*)dst; - const uint8_t* src8 = (const uint8_t*)src; - - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - dst32[x] = SkPackARGB32(0xFF, src8[x], src8[x], src8[x]); - } - dst32 = (uint32_t*)((char*)dst32 + dstRB); - src8 += srcRB; - } -} - -static void copy_32_to_g8(void* dst, size_t dstRB, const void* src, size_t srcRB, - const SkImageInfo& srcInfo) { - uint8_t* dst8 = (uint8_t*)dst; - const uint32_t* src32 = (const uint32_t*)src; - - const int w = srcInfo.width(); - const int h = srcInfo.height(); - const bool isBGRA = (kBGRA_8888_SkColorType == srcInfo.colorType()); - - for (int y = 0; y < h; ++y) { - if (isBGRA) { - // BGRA - for (int x = 0; x < w; ++x) { - uint32_t s = src32[x]; - dst8[x] = SkComputeLuminance((s >> 16) & 0xFF, (s >> 8) & 0xFF, s & 0xFF); - } - } else { - // RGBA - for (int x = 0; x < w; ++x) { - uint32_t s = src32[x]; - dst8[x] = SkComputeLuminance(s & 0xFF, (s >> 8) & 0xFF, (s >> 16) & 0xFF); - } - } - src32 = (const uint32_t*)((const char*)src32 + srcRB); - dst8 += dstRB; - } -} - -static bool extract_alpha(void* dst, size_t dstRB, const void* src, size_t srcRB, - const SkImageInfo& srcInfo, SkColorTable* ctable) { - uint8_t* SK_RESTRICT dst8 = (uint8_t*)dst; - - const int w = srcInfo.width(); - const int h = srcInfo.height(); - if (srcInfo.isOpaque()) { - // src is opaque, so just fill alpha with 0xFF - for (int y = 0; y < h; ++y) { - memset(dst8, 0xFF, w); - dst8 += dstRB; - } - return true; - } - switch (srcInfo.colorType()) { - case kN32_SkColorType: { - const SkPMColor* SK_RESTRICT src32 = (const SkPMColor*)src; - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - dst8[x] = SkGetPackedA32(src32[x]); - } - dst8 += dstRB; - src32 = (const SkPMColor*)((const char*)src32 + srcRB); - } - break; - } - case kARGB_4444_SkColorType: { - const SkPMColor16* SK_RESTRICT src16 = (const SkPMColor16*)src; - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - dst8[x] = SkPacked4444ToA32(src16[x]); - } - dst8 += dstRB; - src16 = (const SkPMColor16*)((const char*)src16 + srcRB); - } - break; - } - case kIndex_8_SkColorType: { - if (nullptr == ctable) { - return false; - } - const SkPMColor* SK_RESTRICT table = ctable->readColors(); - const uint8_t* SK_RESTRICT src8 = (const uint8_t*)src; - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - dst8[x] = SkGetPackedA32(table[src8[x]]); - } - dst8 += dstRB; - src8 += srcRB; - } - break; - } - default: - return false; - } - return true; -} - -bool SkPixelInfo::CopyPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, - const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB, - SkColorTable* ctable) { - if (srcInfo.dimensions() != dstInfo.dimensions()) { - return false; - } - - const int width = srcInfo.width(); - const int height = srcInfo.height(); - - // Do the easiest one first : both configs are equal - if ((srcInfo == dstInfo) && !ctable) { - size_t bytes = width * srcInfo.bytesPerPixel(); - for (int y = 0; y < height; ++y) { - memcpy(dstPixels, srcPixels, bytes); - srcPixels = (const char*)srcPixels + srcRB; - dstPixels = (char*)dstPixels + dstRB; - } - return true; - } - - // Handle fancy alpha swizzling if both are ARGB32 - if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel()) { - SkDstPixelInfo dstPI; - dstPI.fColorType = dstInfo.colorType(); - dstPI.fAlphaType = dstInfo.alphaType(); - dstPI.fPixels = dstPixels; - dstPI.fRowBytes = dstRB; - - SkSrcPixelInfo srcPI; - srcPI.fColorType = srcInfo.colorType(); - srcPI.fAlphaType = srcInfo.alphaType(); - srcPI.fPixels = srcPixels; - srcPI.fRowBytes = srcRB; - - return srcPI.convertPixelsTo(&dstPI, width, height); - } - - // If they agree on colorType and the alphaTypes are compatible, then we just memcpy. - // Note: we've already taken care of 32bit colortypes above. - if (srcInfo.colorType() == dstInfo.colorType()) { - switch (srcInfo.colorType()) { - case kRGB_565_SkColorType: - case kAlpha_8_SkColorType: - case kGray_8_SkColorType: - break; - case kIndex_8_SkColorType: - case kARGB_4444_SkColorType: - case kRGBA_F16_SkColorType: - if (srcInfo.alphaType() != dstInfo.alphaType()) { - return false; - } - break; - default: - return false; - } - SkRectMemcpy(dstPixels, dstRB, srcPixels, srcRB, width * srcInfo.bytesPerPixel(), height); - return true; - } - - /* - * Begin section where we try to change colorTypes along the way. Not all combinations - * are supported. - */ - - if (kGray_8_SkColorType == srcInfo.colorType() && 4 == dstInfo.bytesPerPixel()) { - copy_g8_to_32(dstPixels, dstRB, srcPixels, srcRB, width, height); - return true; - } - if (kGray_8_SkColorType == dstInfo.colorType() && 4 == srcInfo.bytesPerPixel()) { - copy_32_to_g8(dstPixels, dstRB, srcPixels, srcRB, srcInfo); - return true; - } - - if (kAlpha_8_SkColorType == dstInfo.colorType() && - extract_alpha(dstPixels, dstRB, srcPixels, srcRB, srcInfo, ctable)) { - return true; - } - - // Can no longer draw directly into 4444, but we can manually whack it for a few combinations - if (kARGB_4444_SkColorType == dstInfo.colorType() && - (kN32_SkColorType == srcInfo.colorType() || kIndex_8_SkColorType == srcInfo.colorType())) { - if (srcInfo.alphaType() == kUnpremul_SkAlphaType) { - // Our method for converting to 4444 assumes premultiplied. - return false; - } - - const SkPMColor* table = nullptr; - if (kIndex_8_SkColorType == srcInfo.colorType()) { - if (nullptr == ctable) { - return false; - } - table = ctable->readColors(); - } - - for (int y = 0; y < height; ++y) { - DITHER_4444_SCAN(y); - SkPMColor16* SK_RESTRICT dstRow = (SkPMColor16*)dstPixels; - if (table) { - const uint8_t* SK_RESTRICT srcRow = (const uint8_t*)srcPixels; - for (int x = 0; x < width; ++x) { - dstRow[x] = SkDitherARGB32To4444(table[srcRow[x]], DITHER_VALUE(x)); - } - } else { - const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)srcPixels; - for (int x = 0; x < width; ++x) { - dstRow[x] = SkDitherARGB32To4444(srcRow[x], DITHER_VALUE(x)); - } - } - dstPixels = (char*)dstPixels + dstRB; - srcPixels = (const char*)srcPixels + srcRB; - } - return true; - } - - if (dstInfo.alphaType() == kUnpremul_SkAlphaType) { - // We do not support drawing to unpremultiplied bitmaps. - return false; - } - - // Final fall-back, draw with a canvas - // - // Always clear the dest in case one of the blitters accesses it - // TODO: switch the allocation of tmpDst to call sk_calloc_throw - { - SkBitmap bm; - if (!bm.installPixels(srcInfo, const_cast(srcPixels), srcRB, ctable, nullptr, nullptr)) { - return false; - } - SkAutoTUnref canvas(SkCanvas::NewRasterDirect(dstInfo, dstPixels, dstRB)); - if (nullptr == canvas.get()) { - return false; - } - - SkPaint paint; - paint.setDither(true); - - canvas->clear(0); - canvas->drawBitmap(bm, 0, 0, &paint); - return true; - } -} diff --git a/gfx/skia/skia/src/core/SkConfig8888.h b/gfx/skia/skia/src/core/SkConfig8888.h deleted file mode 100644 index ff287267aa47..000000000000 --- a/gfx/skia/skia/src/core/SkConfig8888.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkPixelInfo_DEFINED -#define SkPixelInfo_DEFINED - -#include "SkImageInfo.h" - -class SkColorTable; - -struct SkPixelInfo { - SkColorType fColorType; - SkAlphaType fAlphaType; - size_t fRowBytes; - - static bool CopyPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, - const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes, - SkColorTable* srcCTable = nullptr); -}; - -struct SkDstPixelInfo : SkPixelInfo { - void* fPixels; -}; - -struct SkSrcPixelInfo : SkPixelInfo { - const void* fPixels; - - // Guaranteed to work even if src.fPixels and dst.fPixels are the same - // (but not if they overlap partially) - bool convertPixelsTo(SkDstPixelInfo* dst, int width, int height) const; -}; - -static inline void SkRectMemcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, - size_t bytesPerRow, int rowCount) { - SkASSERT(bytesPerRow <= srcRB); - SkASSERT(bytesPerRow <= dstRB); - for (int i = 0; i < rowCount; ++i) { - memcpy(dst, src, bytesPerRow); - dst = (char*)dst + dstRB; - src = (const char*)src + srcRB; - } -} - -#endif diff --git a/gfx/skia/skia/src/core/SkConvertPixels.cpp b/gfx/skia/skia/src/core/SkConvertPixels.cpp new file mode 100644 index 000000000000..b919f5dbe821 --- /dev/null +++ b/gfx/skia/skia/src/core/SkConvertPixels.cpp @@ -0,0 +1,422 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorSpaceXform_Base.h" +#include "SkColorSpaceXformPriv.h" +#include "SkColorTable.h" +#include "SkConvertPixels.h" +#include "SkHalf.h" +#include "SkImageInfoPriv.h" +#include "SkOpts.h" +#include "SkPM4fPriv.h" +#include "SkRasterPipeline.h" +#include "SkUnPreMultiply.h" +#include "SkUnPreMultiplyPriv.h" + +// Fast Path 1: The memcpy() case. +static inline bool can_memcpy(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) { + if (dstInfo.colorType() != srcInfo.colorType()) { + return false; + } + + if (kAlpha_8_SkColorType == dstInfo.colorType()) { + return true; + } + + if (dstInfo.alphaType() != srcInfo.alphaType() && + kOpaque_SkAlphaType != dstInfo.alphaType() && + kOpaque_SkAlphaType != srcInfo.alphaType()) + { + // We need to premultiply or unpremultiply. + return false; + } + + return !dstInfo.colorSpace() || + SkColorSpace::Equals(dstInfo.colorSpace(), srcInfo.colorSpace()); +} + +// Fast Path 2: Simple swizzles and premuls. +enum AlphaVerb { + kNothing_AlphaVerb, + kPremul_AlphaVerb, + kUnpremul_AlphaVerb, +}; + +template +static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) { + SkUnpremultiplyRow(dst, (const uint32_t*) src, count); +} + +void swizzle_and_multiply(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, + const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) { + void (*proc)(uint32_t* dst, const void* src, int count); + const bool swapRB = dstInfo.colorType() != srcInfo.colorType(); + AlphaVerb alphaVerb = kNothing_AlphaVerb; + if (kPremul_SkAlphaType == dstInfo.alphaType() && + kUnpremul_SkAlphaType == srcInfo.alphaType()) + { + alphaVerb = kPremul_AlphaVerb; + } else if (kUnpremul_SkAlphaType == dstInfo.alphaType() && + kPremul_SkAlphaType == srcInfo.alphaType()) { + alphaVerb = kUnpremul_AlphaVerb; + } + + switch (alphaVerb) { + case kNothing_AlphaVerb: + // If we do not need to swap or multiply, we should hit the memcpy case. + SkASSERT(swapRB); + proc = SkOpts::RGBA_to_BGRA; + break; + case kPremul_AlphaVerb: + proc = swapRB ? SkOpts::RGBA_to_bgrA : SkOpts::RGBA_to_rgbA; + break; + case kUnpremul_AlphaVerb: + proc = swapRB ? wrap_unpremultiply : wrap_unpremultiply; + break; + } + + for (int y = 0; y < dstInfo.height(); y++) { + proc((uint32_t*) dstPixels, srcPixels, dstInfo.width()); + dstPixels = SkTAddOffset(dstPixels, dstRB); + srcPixels = SkTAddOffset(srcPixels, srcRB); + } +} + +// Fast Path 3: Color space xform. +static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, + SkTransferFunctionBehavior behavior) { + // Unpremultiplication is unsupported by SkColorSpaceXform. Note that if |src| is non-linearly + // premultiplied, we're always going to have to unpremultiply before doing anything. + if (kPremul_SkAlphaType == srcInfo.alphaType() && + (kUnpremul_SkAlphaType == dstInfo.alphaType() || + SkTransferFunctionBehavior::kIgnore == behavior)) { + return false; + } + + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + case kRGBA_F16_SkColorType: + break; + default: + return false; + } + + switch (srcInfo.colorType()) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + break; + default: + return false; + } + + return true; +} + +static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, + const SkImageInfo& srcInfo, const void* srcPixels, + size_t srcRB, SkTransferFunctionBehavior behavior) { + SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType()); + SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(srcInfo.colorType()); + SkAlphaType xformAlpha; + switch (srcInfo.alphaType()) { + case kOpaque_SkAlphaType: + xformAlpha = kOpaque_SkAlphaType; + break; + case kPremul_SkAlphaType: + SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType()); + + // This signal means: copy the src alpha to the dst, do not premultiply (in this + // case because the pixels are already premultiplied). + xformAlpha = kUnpremul_SkAlphaType; + break; + case kUnpremul_SkAlphaType: + SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType() || + kUnpremul_SkAlphaType == dstInfo.alphaType()); + + xformAlpha = dstInfo.alphaType(); + break; + default: + SkASSERT(false); + xformAlpha = kUnpremul_SkAlphaType; + break; + } + + std::unique_ptr xform = + SkColorSpaceXform_Base::New(srcInfo.colorSpace(), dstInfo.colorSpace(), behavior); + SkASSERT(xform); + + for (int y = 0; y < dstInfo.height(); y++) { + SkAssertResult(xform->apply(dstFormat, dstPixels, srcFormat, srcPixels, dstInfo.width(), + xformAlpha)); + dstPixels = SkTAddOffset(dstPixels, dstRB); + srcPixels = SkTAddOffset(srcPixels, srcRB); + } +} + +// Fast Path 4: Index 8 sources. +template +void do_index8(const SkImageInfo& dstInfo, T* dstPixels, size_t dstRB, + const SkImageInfo& srcInfo, const uint8_t* srcPixels, size_t srcRB, + SkColorTable* ctable, SkTransferFunctionBehavior behavior) { + T dstCTable[256]; + int count = ctable->count(); + SkImageInfo srcInfo8888 = srcInfo.makeColorType(kN32_SkColorType).makeWH(count, 1); + SkImageInfo dstInfoCT = dstInfo.makeWH(count, 1); + size_t rowBytes = count * sizeof(T); + SkConvertPixels(dstInfoCT, dstCTable, rowBytes, srcInfo8888, ctable->readColors(), rowBytes, + nullptr, behavior); + + for (int y = 0; y < dstInfo.height(); y++) { + for (int x = 0; x < dstInfo.width(); x++) { + dstPixels[x] = dstCTable[srcPixels[x]]; + } + dstPixels = SkTAddOffset(dstPixels, dstRB); + srcPixels = SkTAddOffset(srcPixels, srcRB); + } +} + +void convert_from_index8(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, + const SkImageInfo& srcInfo, const uint8_t* srcPixels, size_t srcRB, + SkColorTable* ctable, SkTransferFunctionBehavior behavior) { + switch (dstInfo.colorType()) { + case kAlpha_8_SkColorType: + do_index8(dstInfo, (uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, + behavior); + break; + case kRGB_565_SkColorType: + case kARGB_4444_SkColorType: + do_index8(dstInfo, (uint16_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, + behavior); + break; + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + do_index8(dstInfo, (uint32_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, + behavior); + break; + case kRGBA_F16_SkColorType: + do_index8(dstInfo, (uint64_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, + behavior); + break; + default: + SkASSERT(false); + } +} + +// Fast Path 5: Alpha 8 dsts. +static void convert_to_alpha8(uint8_t* dst, size_t dstRB, const SkImageInfo& srcInfo, + const void* src, size_t srcRB, SkColorTable* ctable) { + if (srcInfo.isOpaque()) { + for (int y = 0; y < srcInfo.height(); ++y) { + memset(dst, 0xFF, srcInfo.width()); + dst = SkTAddOffset(dst, dstRB); + } + return; + } + + switch (srcInfo.colorType()) { + case kBGRA_8888_SkColorType: + case kRGBA_8888_SkColorType: { + auto src32 = (const uint32_t*) src; + for (int y = 0; y < srcInfo.height(); y++) { + for (int x = 0; x < srcInfo.width(); x++) { + dst[x] = src32[x] >> 24; + } + dst = SkTAddOffset(dst, dstRB); + src32 = SkTAddOffset(src32, srcRB); + } + break; + } + case kARGB_4444_SkColorType: { + auto src16 = (const uint16_t*) src; + for (int y = 0; y < srcInfo.height(); y++) { + for (int x = 0; x < srcInfo.width(); x++) { + dst[x] = SkPacked4444ToA32(src16[x]); + } + dst = SkTAddOffset(dst, dstRB); + src16 = SkTAddOffset(src16, srcRB); + } + break; + } + case kIndex_8_SkColorType: { + SkASSERT(ctable); + const uint32_t* table = ctable->readColors(); + auto src8 = (const uint8_t*)src; + for (int y = 0; y < srcInfo.height(); y++) { + for (int x = 0; x < srcInfo.width(); x++) { + dst[x] = table[src8[x]] >> 24; + } + dst = SkTAddOffset(dst, dstRB); + src8 = SkTAddOffset(src8, srcRB); + } + break; + } + case kRGBA_F16_SkColorType: { + auto src64 = (const uint64_t*) src; + for (int y = 0; y < srcInfo.height(); y++) { + for (int x = 0; x < srcInfo.width(); x++) { + dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48)); + } + dst = SkTAddOffset(dst, dstRB); + src64 = SkTAddOffset(src64, srcRB); + } + break; + } + default: + SkASSERT(false); + break; + } +} + +// Default: Use the pipeline. +static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB, + const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB, + bool isColorAware, SkTransferFunctionBehavior behavior) { + SkRasterPipeline pipeline; + switch (srcInfo.colorType()) { + case kRGBA_8888_SkColorType: + pipeline.append(SkRasterPipeline::load_8888, &srcRow); + break; + case kBGRA_8888_SkColorType: + pipeline.append(SkRasterPipeline::load_8888, &srcRow); + pipeline.append(SkRasterPipeline::swap_rb); + break; + case kRGB_565_SkColorType: + pipeline.append(SkRasterPipeline::load_565, &srcRow); + break; + case kRGBA_F16_SkColorType: + pipeline.append(SkRasterPipeline::load_f16, &srcRow); + break; + case kGray_8_SkColorType: + pipeline.append(SkRasterPipeline::load_g8, &srcRow); + break; + case kARGB_4444_SkColorType: + pipeline.append(SkRasterPipeline::load_4444, &srcRow); + break; + default: + SkASSERT(false); + break; + } + + SkAlphaType premulState = srcInfo.alphaType(); + if (kPremul_SkAlphaType == premulState && SkTransferFunctionBehavior::kIgnore == behavior) { + pipeline.append(SkRasterPipeline::unpremul); + premulState = kUnpremul_SkAlphaType; + } + + if (isColorAware && srcInfo.gammaCloseToSRGB()) { + pipeline.append_from_srgb(srcInfo.alphaType()); + } + + float matrix[12]; + if (isColorAware) { + SkAssertResult(append_gamut_transform(&pipeline, matrix, srcInfo.colorSpace(), + dstInfo.colorSpace())); + } + + SkAlphaType dat = dstInfo.alphaType(); + if (SkTransferFunctionBehavior::kRespect == behavior) { + if (kPremul_SkAlphaType == premulState && kUnpremul_SkAlphaType == dat) { + pipeline.append(SkRasterPipeline::unpremul); + premulState = kUnpremul_SkAlphaType; + } else if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat) { + pipeline.append(SkRasterPipeline::premul); + premulState = kPremul_SkAlphaType; + } + } + + if (isColorAware && dstInfo.gammaCloseToSRGB()) { + pipeline.append(SkRasterPipeline::to_srgb); + } + + if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat && + SkTransferFunctionBehavior::kIgnore == behavior) + { + pipeline.append(SkRasterPipeline::premul); + premulState = kPremul_SkAlphaType; + } + + // The final premul state must equal the dst alpha type. Note that if we are "converting" + // opaque to another alpha type, there's no need to worry about multiplication. + SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType()); + + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: + pipeline.append(SkRasterPipeline::store_8888, &dstRow); + break; + case kBGRA_8888_SkColorType: + pipeline.append(SkRasterPipeline::swap_rb); + pipeline.append(SkRasterPipeline::store_8888, &dstRow); + break; + case kRGB_565_SkColorType: + pipeline.append(SkRasterPipeline::store_565, &dstRow); + break; + case kRGBA_F16_SkColorType: + pipeline.append(SkRasterPipeline::store_f16, &dstRow); + break; + case kARGB_4444_SkColorType: + pipeline.append(SkRasterPipeline::store_4444, &dstRow); + break; + default: + SkASSERT(false); + break; + } + + for (int y = 0; y < srcInfo.height(); ++y) { + pipeline.run(0,srcInfo.width()); + // The pipeline has pointers to srcRow and dstRow, so we just need to update them in the + // loop to move between rows of src/dst. + dstRow = SkTAddOffset(dstRow, dstRB); + srcRow = SkTAddOffset(srcRow, srcRB); + } +} + +void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, + const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB, + SkColorTable* ctable, SkTransferFunctionBehavior behavior) { + SkASSERT(dstInfo.dimensions() == srcInfo.dimensions()); + SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo)); + + // Fast Path 1: The memcpy() case. + if (can_memcpy(dstInfo, srcInfo)) { + SkRectMemcpy(dstPixels, dstRB, srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height()); + return; + } + + const bool isColorAware = dstInfo.colorSpace(); + SkASSERT(srcInfo.colorSpace() || !isColorAware); + + // Fast Path 2: Simple swizzles and premuls. + if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel() && !isColorAware) { + swizzle_and_multiply(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB); + return; + } + + // Fast Path 3: Color space xform. + if (isColorAware && optimized_color_xform(dstInfo, srcInfo, behavior)) { + apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, behavior); + return; + } + + // Fast Path 4: Index 8 sources. + if (kIndex_8_SkColorType == srcInfo.colorType()) { + SkASSERT(ctable); + convert_from_index8(dstInfo, dstPixels, dstRB, srcInfo, (const uint8_t*) srcPixels, srcRB, + ctable, behavior); + return; + } + + // Fast Path 5: Alpha 8 dsts. + if (kAlpha_8_SkColorType == dstInfo.colorType()) { + convert_to_alpha8((uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable); + return; + } + + // Default: Use the pipeline. + convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware, + behavior); +} diff --git a/gfx/skia/skia/src/core/SkConvertPixels.h b/gfx/skia/skia/src/core/SkConvertPixels.h new file mode 100644 index 000000000000..c825d84aa196 --- /dev/null +++ b/gfx/skia/skia/src/core/SkConvertPixels.h @@ -0,0 +1,36 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkConvertPixels_DEFINED +#define SkConvertPixels_DEFINED + +#include "SkImageInfo.h" +#include "SkTemplates.h" + +class SkColorTable; + +void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, + const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes, + SkColorTable* srcCTable, SkTransferFunctionBehavior behavior); + +static inline void SkRectMemcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, + size_t bytesPerRow, int rowCount) { + SkASSERT(bytesPerRow <= dstRB); + SkASSERT(bytesPerRow <= srcRB); + if (bytesPerRow == dstRB && bytesPerRow == srcRB) { + memcpy(dst, src, bytesPerRow * rowCount); + return; + } + + for (int i = 0; i < rowCount; ++i) { + memcpy(dst, src, bytesPerRow); + dst = SkTAddOffset(dst, dstRB); + src = SkTAddOffset(src, srcRB); + } +} + +#endif diff --git a/gfx/skia/skia/src/core/SkConvolver.cpp b/gfx/skia/skia/src/core/SkConvolver.cpp index c662e2ddaf0d..9f0cfea821fa 100644 --- a/gfx/skia/skia/src/core/SkConvolver.cpp +++ b/gfx/skia/skia/src/core/SkConvolver.cpp @@ -3,22 +3,10 @@ // found in the LICENSE file. #include "SkConvolver.h" +#include "SkOpts.h" #include "SkTArray.h" namespace { - - // Converts the argument to an 8-bit unsigned value by clamping to the range - // 0-255. - inline unsigned char ClampTo8(int a) { - if (static_cast(a) < 256) { - return a; // Avoid the extra check in the common case. - } - if (a < 0) { - return 0; - } - return 255; - } - // Stores a list of rows in a circular buffer. The usage is you write into it // by calling AdvanceRow. It will keep track of which row in the buffer it // should use next, and the total number of rows added. @@ -108,169 +96,6 @@ namespace { SkTArray fRowAddresses; }; -// Convolves horizontally along a single row. The row data is given in -// |srcData| and continues for the numValues() of the filter. -template - void ConvolveHorizontally(const unsigned char* srcData, - const SkConvolutionFilter1D& filter, - unsigned char* outRow) { - // Loop over each pixel on this row in the output image. - int numValues = filter.numValues(); - for (int outX = 0; outX < numValues; outX++) { - // Get the filter that determines the current output pixel. - int filterOffset, filterLength; - const SkConvolutionFilter1D::ConvolutionFixed* filterValues = - filter.FilterForValue(outX, &filterOffset, &filterLength); - - // Compute the first pixel in this row that the filter affects. It will - // touch |filterLength| pixels (4 bytes each) after this. - const unsigned char* rowToFilter = &srcData[filterOffset * 4]; - - // Apply the filter to the row to get the destination pixel in |accum|. - int accum[4] = {0}; - for (int filterX = 0; filterX < filterLength; filterX++) { - SkConvolutionFilter1D::ConvolutionFixed curFilter = filterValues[filterX]; - accum[0] += curFilter * rowToFilter[filterX * 4 + 0]; - accum[1] += curFilter * rowToFilter[filterX * 4 + 1]; - accum[2] += curFilter * rowToFilter[filterX * 4 + 2]; - if (hasAlpha) { - accum[3] += curFilter * rowToFilter[filterX * 4 + 3]; - } - } - - // Bring this value back in range. All of the filter scaling factors - // are in fixed point with kShiftBits bits of fractional part. - accum[0] >>= SkConvolutionFilter1D::kShiftBits; - accum[1] >>= SkConvolutionFilter1D::kShiftBits; - accum[2] >>= SkConvolutionFilter1D::kShiftBits; - if (hasAlpha) { - accum[3] >>= SkConvolutionFilter1D::kShiftBits; - } - - // Store the new pixel. - outRow[outX * 4 + 0] = ClampTo8(accum[0]); - outRow[outX * 4 + 1] = ClampTo8(accum[1]); - outRow[outX * 4 + 2] = ClampTo8(accum[2]); - if (hasAlpha) { - outRow[outX * 4 + 3] = ClampTo8(accum[3]); - } - } - } - - // There's a bug somewhere here with GCC autovectorization (-ftree-vectorize). We originally - // thought this was 32 bit only, but subsequent tests show that some 64 bit gcc compiles - // suffer here too. - // - // Dropping to -O2 disables -ftree-vectorize. GCC 4.6 needs noinline. https://bug.skia.org/2575 - #if SK_HAS_ATTRIBUTE(optimize) && defined(SK_RELEASE) - #define SK_MAYBE_DISABLE_VECTORIZATION __attribute__((optimize("O2"), noinline)) - #else - #define SK_MAYBE_DISABLE_VECTORIZATION - #endif - - SK_MAYBE_DISABLE_VECTORIZATION - static void ConvolveHorizontallyAlpha(const unsigned char* srcData, - const SkConvolutionFilter1D& filter, - unsigned char* outRow) { - return ConvolveHorizontally(srcData, filter, outRow); - } - - SK_MAYBE_DISABLE_VECTORIZATION - static void ConvolveHorizontallyNoAlpha(const unsigned char* srcData, - const SkConvolutionFilter1D& filter, - unsigned char* outRow) { - return ConvolveHorizontally(srcData, filter, outRow); - } - - #undef SK_MAYBE_DISABLE_VECTORIZATION - - -// Does vertical convolution to produce one output row. The filter values and -// length are given in the first two parameters. These are applied to each -// of the rows pointed to in the |sourceDataRows| array, with each row -// being |pixelWidth| wide. -// -// The output must have room for |pixelWidth * 4| bytes. -template - void ConvolveVertically(const SkConvolutionFilter1D::ConvolutionFixed* filterValues, - int filterLength, - unsigned char* const* sourceDataRows, - int pixelWidth, - unsigned char* outRow) { - // We go through each column in the output and do a vertical convolution, - // generating one output pixel each time. - for (int outX = 0; outX < pixelWidth; outX++) { - // Compute the number of bytes over in each row that the current column - // we're convolving starts at. The pixel will cover the next 4 bytes. - int byteOffset = outX * 4; - - // Apply the filter to one column of pixels. - int accum[4] = {0}; - for (int filterY = 0; filterY < filterLength; filterY++) { - SkConvolutionFilter1D::ConvolutionFixed curFilter = filterValues[filterY]; - accum[0] += curFilter * sourceDataRows[filterY][byteOffset + 0]; - accum[1] += curFilter * sourceDataRows[filterY][byteOffset + 1]; - accum[2] += curFilter * sourceDataRows[filterY][byteOffset + 2]; - if (hasAlpha) { - accum[3] += curFilter * sourceDataRows[filterY][byteOffset + 3]; - } - } - - // Bring this value back in range. All of the filter scaling factors - // are in fixed point with kShiftBits bits of precision. - accum[0] >>= SkConvolutionFilter1D::kShiftBits; - accum[1] >>= SkConvolutionFilter1D::kShiftBits; - accum[2] >>= SkConvolutionFilter1D::kShiftBits; - if (hasAlpha) { - accum[3] >>= SkConvolutionFilter1D::kShiftBits; - } - - // Store the new pixel. - outRow[byteOffset + 0] = ClampTo8(accum[0]); - outRow[byteOffset + 1] = ClampTo8(accum[1]); - outRow[byteOffset + 2] = ClampTo8(accum[2]); - if (hasAlpha) { - unsigned char alpha = ClampTo8(accum[3]); - - // Make sure the alpha channel doesn't come out smaller than any of the - // color channels. We use premultipled alpha channels, so this should - // never happen, but rounding errors will cause this from time to time. - // These "impossible" colors will cause overflows (and hence random pixel - // values) when the resulting bitmap is drawn to the screen. - // - // We only need to do this when generating the final output row (here). - int maxColorChannel = SkTMax(outRow[byteOffset + 0], - SkTMax(outRow[byteOffset + 1], - outRow[byteOffset + 2])); - if (alpha < maxColorChannel) { - outRow[byteOffset + 3] = maxColorChannel; - } else { - outRow[byteOffset + 3] = alpha; - } - } else { - // No alpha channel, the image is opaque. - outRow[byteOffset + 3] = 0xff; - } - } - } - - void ConvolveVertically(const SkConvolutionFilter1D::ConvolutionFixed* filterValues, - int filterLength, - unsigned char* const* sourceDataRows, - int pixelWidth, - unsigned char* outRow, - bool sourceHasAlpha) { - if (sourceHasAlpha) { - ConvolveVertically(filterValues, filterLength, - sourceDataRows, pixelWidth, - outRow); - } else { - ConvolveVertically(filterValues, filterLength, - sourceDataRows, pixelWidth, - outRow); - } - } - } // namespace // SkConvolutionFilter1D --------------------------------------------------------- @@ -346,9 +171,7 @@ bool BGRAConvolve2D(const unsigned char* sourceData, const SkConvolutionFilter1D& filterX, const SkConvolutionFilter1D& filterY, int outputByteRowStride, - unsigned char* output, - const SkConvolutionProcs& convolveProcs, - bool useSimdIfPossible) { + unsigned char* output) { int maxYFilterSize = filterY.maxFilter(); @@ -369,12 +192,12 @@ bool BGRAConvolve2D(const unsigned char* sourceData, // intermediate image and helps cache coherency. // We will need four extra rows to allow horizontal convolution could be done // simultaneously. We also pad each row in row buffer to be aligned-up to - // 16 bytes. + // 32 bytes. // TODO(jiesun): We do not use aligned load from row buffer in vertical // convolution pass yet. Somehow Windows does not like it. - int rowBufferWidth = (filterX.numValues() + 15) & ~0xF; + int rowBufferWidth = (filterX.numValues() + 31) & ~0x1F; int rowBufferHeight = maxYFilterSize + - (convolveProcs.fConvolve4RowsHorizontally ? 4 : 0); + (SkOpts::convolve_4_rows_horizontally != nullptr ? 4 : 0); // check for too-big allocation requests : crbug.com/528628 { @@ -401,19 +224,6 @@ bool BGRAConvolve2D(const unsigned char* sourceData, // We need to check which is the last line to convolve before we advance 4 // lines in one iteration. int lastFilterOffset, lastFilterLength; - - // SSE2 can access up to 3 extra pixels past the end of the - // buffer. At the bottom of the image, we have to be careful - // not to access data past the end of the buffer. Normally - // we fall back to the C++ implementation for the last row. - // If the last row is less than 3 pixels wide, we may have to fall - // back to the C++ version for more rows. Compute how many - // rows we need to avoid the SSE implementation for here. - filterX.FilterForValue(filterX.numValues() - 1, &lastFilterOffset, - &lastFilterLength); - int avoidSimdRows = 1 + convolveProcs.fExtraHorizontalReads / - (lastFilterOffset + lastFilterLength); - filterY.FilterForValue(numOutputRows - 1, &lastFilterOffset, &lastFilterLength); @@ -423,36 +233,20 @@ bool BGRAConvolve2D(const unsigned char* sourceData, // Generate output rows until we have enough to run the current filter. while (nextXRow < filterOffset + filterLength) { - if (convolveProcs.fConvolve4RowsHorizontally && - nextXRow + 3 < lastFilterOffset + lastFilterLength - - avoidSimdRows) { + if (SkOpts::convolve_4_rows_horizontally != nullptr && + nextXRow + 3 < lastFilterOffset + lastFilterLength) { const unsigned char* src[4]; unsigned char* outRow[4]; for (int i = 0; i < 4; ++i) { src[i] = &sourceData[(uint64_t)(nextXRow + i) * sourceByteRowStride]; outRow[i] = rowBuffer.advanceRow(); } - convolveProcs.fConvolve4RowsHorizontally(src, filterX, outRow, 4*rowBufferWidth); + SkOpts::convolve_4_rows_horizontally(src, filterX, outRow, 4*rowBufferWidth); nextXRow += 4; } else { - // Check if we need to avoid SSE2 for this row. - if (convolveProcs.fConvolveHorizontally && - nextXRow < lastFilterOffset + lastFilterLength - - avoidSimdRows) { - convolveProcs.fConvolveHorizontally( + SkOpts::convolve_horizontally( &sourceData[(uint64_t)nextXRow * sourceByteRowStride], filterX, rowBuffer.advanceRow(), sourceHasAlpha); - } else { - if (sourceHasAlpha) { - ConvolveHorizontallyAlpha( - &sourceData[(uint64_t)nextXRow * sourceByteRowStride], - filterX, rowBuffer.advanceRow()); - } else { - ConvolveHorizontallyNoAlpha( - &sourceData[(uint64_t)nextXRow * sourceByteRowStride], - filterX, rowBuffer.advanceRow()); - } - } nextXRow++; } } @@ -465,22 +259,14 @@ bool BGRAConvolve2D(const unsigned char* sourceData, unsigned char* const* rowsToConvolve = rowBuffer.GetRowAddresses(&firstRowInCircularBuffer); - // Now compute the start of the subset of those rows that the filter - // needs. + // Now compute the start of the subset of those rows that the filter needs. unsigned char* const* firstRowForFilter = &rowsToConvolve[filterOffset - firstRowInCircularBuffer]; - if (convolveProcs.fConvolveVertically) { - convolveProcs.fConvolveVertically(filterValues, filterLength, - firstRowForFilter, - filterX.numValues(), curOutputRow, - sourceHasAlpha); - } else { - ConvolveVertically(filterValues, filterLength, - firstRowForFilter, - filterX.numValues(), curOutputRow, - sourceHasAlpha); - } + SkOpts::convolve_vertically(filterValues, filterLength, + firstRowForFilter, + filterX.numValues(), curOutputRow, + sourceHasAlpha); } return true; } diff --git a/gfx/skia/skia/src/core/SkConvolver.h b/gfx/skia/skia/src/core/SkConvolver.h index 4e23f6cc17a3..4c4b1fd71100 100644 --- a/gfx/skia/skia/src/core/SkConvolver.h +++ b/gfx/skia/skia/src/core/SkConvolver.h @@ -140,38 +140,6 @@ private: int fMaxFilter; }; -typedef void (*SkConvolveVertically_pointer)( - const SkConvolutionFilter1D::ConvolutionFixed* filterValues, - int filterLength, - unsigned char* const* sourceDataRows, - int pixelWidth, - unsigned char* outRow, - bool hasAlpha); -typedef void (*SkConvolve4RowsHorizontally_pointer)( - const unsigned char* srcData[4], - const SkConvolutionFilter1D& filter, - unsigned char* outRow[4], - size_t outRowBytes); -typedef void (*SkConvolveHorizontally_pointer)( - const unsigned char* srcData, - const SkConvolutionFilter1D& filter, - unsigned char* outRow, - bool hasAlpha); -typedef void (*SkConvolveFilterPadding_pointer)( - SkConvolutionFilter1D* filter); - -struct SkConvolutionProcs { - // This is how many extra pixels may be read by the - // conolve*horizontally functions. - int fExtraHorizontalReads; - SkConvolveVertically_pointer fConvolveVertically; - SkConvolve4RowsHorizontally_pointer fConvolve4RowsHorizontally; - SkConvolveHorizontally_pointer fConvolveHorizontally; - SkConvolveFilterPadding_pointer fApplySIMDPadding; -}; - - - // Does a two-dimensional convolution on the given source image. // // It is assumed the source pixel offsets referenced in the input filters @@ -200,8 +168,6 @@ SK_API bool BGRAConvolve2D(const unsigned char* sourceData, const SkConvolutionFilter1D& xfilter, const SkConvolutionFilter1D& yfilter, int outputByteRowStride, - unsigned char* output, - const SkConvolutionProcs&, - bool useSimdIfPossible); + unsigned char* output); #endif // SK_CONVOLVER_H diff --git a/gfx/skia/skia/src/core/SkCoreBlitters.h b/gfx/skia/skia/src/core/SkCoreBlitters.h index 46b2b7ee943a..0e8b819c672a 100644 --- a/gfx/skia/skia/src/core/SkCoreBlitters.h +++ b/gfx/skia/skia/src/core/SkCoreBlitters.h @@ -12,7 +12,7 @@ #include "SkBlitter.h" #include "SkBlitRow.h" #include "SkShader.h" -#include "SkSmallAllocator.h" +#include "SkXfermodePriv.h" class SkRasterBlitter : public SkBlitter { public: @@ -36,15 +36,6 @@ public: SkShader::Context* shaderContext); virtual ~SkShaderBlitter(); - /** - * Create a new shader context and uses it instead of the old one if successful. - * Will create the context at the same location as the old one (this is safe - * because the shader itself is unchanged). - */ - bool resetShaderContext(const SkShader::ContextRec&) override; - - SkShader::Context* getShaderContext() const override { return fShaderContext; } - protected: uint32_t fShaderFlags; const SkShader* fShader; @@ -94,7 +85,7 @@ class SkA8_Shader_Blitter : public SkShaderBlitter { public: SkA8_Shader_Blitter(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext); - virtual ~SkA8_Shader_Blitter(); + ~SkA8_Shader_Blitter() override; void blitH(int x, int y, int width) override; void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override; void blitMask(const SkMask&, const SkIRect&) override; @@ -165,7 +156,7 @@ class SkARGB32_Shader_Blitter : public SkShaderBlitter { public: SkARGB32_Shader_Blitter(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext); - virtual ~SkARGB32_Shader_Blitter(); + ~SkARGB32_Shader_Blitter() override; void blitH(int x, int y, int width) override; void blitV(int x, int y, int height, SkAlpha alpha) override; void blitRect(int x, int y, int width, int height) override; @@ -186,10 +177,10 @@ private: }; SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint&, SkShader::Context*, - SkTBlitterAllocator*); + SkArenaAlloc*); SkBlitter* SkBlitter_F16_Create(const SkPixmap& device, const SkPaint&, SkShader::Context*, - SkTBlitterAllocator*); + SkArenaAlloc*); /////////////////////////////////////////////////////////////////////////////// @@ -208,10 +199,11 @@ SkBlitter* SkBlitter_F16_Create(const SkPixmap& device, const SkPaint&, SkShader SkBlitter* SkBlitter_ChooseD565(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext, - SkTBlitterAllocator* allocator); + SkArenaAlloc* allocator); // Returns nullptr if no SkRasterPipeline blitter can be constructed for this paint. -SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap&, const SkPaint&, SkTBlitterAllocator*); +SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap&, const SkPaint&, const SkMatrix& ctm, + SkArenaAlloc*); #endif diff --git a/gfx/skia/skia/src/core/SkCpu.cpp b/gfx/skia/skia/src/core/SkCpu.cpp index 9c827f3ef94a..d90e482c70c4 100644 --- a/gfx/skia/skia/src/core/SkCpu.cpp +++ b/gfx/skia/skia/src/core/SkCpu.cpp @@ -8,6 +8,10 @@ #include "SkCpu.h" #include "SkOnce.h" +#if !defined(__has_include) + #define __has_include(x) 0 +#endif + #if defined(SK_CPU_X86) #if defined(SK_BUILD_FOR_WIN32) #include @@ -45,7 +49,8 @@ if (abcd[2] & (1<<19)) { features |= SkCpu::SSE41; } if (abcd[2] & (1<<20)) { features |= SkCpu::SSE42; } - if ((abcd[2] & (3<<26)) == (3<<26) && (xgetbv(0) & 6) == 6) { // XSAVE + OSXSAVE + if ((abcd[2] & (3<<26)) == (3<<26) // XSAVE + OSXSAVE + && (xgetbv(0) & (3<<1)) == (3<<1)) { // XMM and YMM state enabled. if (abcd[2] & (1<<28)) { features |= SkCpu:: AVX; } if (abcd[2] & (1<<29)) { features |= SkCpu::F16C; } if (abcd[2] & (1<<12)) { features |= SkCpu:: FMA; } @@ -54,51 +59,56 @@ if (abcd[1] & (1<<5)) { features |= SkCpu::AVX2; } if (abcd[1] & (1<<3)) { features |= SkCpu::BMI1; } if (abcd[1] & (1<<8)) { features |= SkCpu::BMI2; } + + if ((xgetbv(0) & (7<<5)) == (7<<5)) { // All ZMM state bits enabled too. + if (abcd[1] & (1<<16)) { features |= SkCpu::AVX512F; } + if (abcd[1] & (1<<17)) { features |= SkCpu::AVX512DQ; } + if (abcd[1] & (1<<21)) { features |= SkCpu::AVX512IFMA; } + if (abcd[1] & (1<<26)) { features |= SkCpu::AVX512PF; } + if (abcd[1] & (1<<27)) { features |= SkCpu::AVX512ER; } + if (abcd[1] & (1<<28)) { features |= SkCpu::AVX512CD; } + if (abcd[1] & (1<<30)) { features |= SkCpu::AVX512BW; } + if (abcd[1] & (1<<31)) { features |= SkCpu::AVX512VL; } + } } return features; } -#elif defined(SK_CPU_ARM32) && \ - defined(SK_BUILD_FOR_ANDROID) && \ - !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) - #ifdef MOZ_SKIA - #include "mozilla/arm.h" - static uint32_t read_cpu_features() { - uint32_t features = 0; - if (mozilla::supports_neon()) { features |= SkCpu::NEON; } - return features; - } - #else - #include "cpu-features.h" +#elif defined(SK_CPU_ARM64) && __has_include() && __has_include() + #include + #include static uint32_t read_cpu_features() { uint32_t features = 0; - - uint64_t android_features = android_getCpuFeatures(); - if (android_features & ANDROID_CPU_ARM_FEATURE_NEON ) { features |= SkCpu::NEON ; } - if (android_features & ANDROID_CPU_ARM_FEATURE_NEON_FMA) { features |= SkCpu::NEON_FMA; } - if (android_features & ANDROID_CPU_ARM_FEATURE_VFP_FP16) { features |= SkCpu::VFP_FP16; } + uint32_t hwcaps = getauxval(AT_HWCAP); + if (hwcaps & HWCAP_CRC32) { features |= SkCpu::CRC32; } return features; } - #endif -#elif defined(SK_CPU_ARM64) && \ - defined(SK_BUILD_FOR_ANDROID) && \ - !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) - #ifdef MOZ_SKIA - static uint32_t read_cpu_features() { - return 0; - } - #else - #include "cpu-features.h" + +#elif defined(SK_CPU_ARM32) && __has_include() && __has_include() + // asm/hwcap.h and sys/auxv.h won't be present on NDK builds before API v21. + #include + #include static uint32_t read_cpu_features() { uint32_t features = 0; - - uint64_t android_features = android_getCpuFeatures(); - if (android_features & ANDROID_CPU_ARM64_FEATURE_CRC32) { features |= SkCpu::CRC32; } + uint32_t hwcaps = getauxval(AT_HWCAP); + if (hwcaps & HWCAP_VFPv4) { features |= SkCpu::NEON|SkCpu::NEON_FMA|SkCpu::VFP_FP16; } return features; } - #endif + +#elif defined(SK_CPU_ARM32) && __has_include() + #include + + static uint32_t read_cpu_features() { + uint32_t features = 0; + uint64_t cpu_features = android_getCpuFeatures(); + if (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) { features |= SkCpu::NEON; } + if (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON_FMA) { features |= SkCpu::NEON_FMA; } + if (cpu_features & ANDROID_CPU_ARM_FEATURE_VFP_FP16) { features |= SkCpu::VFP_FP16; } + return features; + } + #else static uint32_t read_cpu_features() { return 0; diff --git a/gfx/skia/skia/src/core/SkCpu.h b/gfx/skia/skia/src/core/SkCpu.h index 34c19d25401a..24428d97818c 100644 --- a/gfx/skia/skia/src/core/SkCpu.h +++ b/gfx/skia/skia/src/core/SkCpu.h @@ -12,21 +12,32 @@ struct SkCpu { enum { - SSE1 = 1 << 0, - SSE2 = 1 << 1, - SSE3 = 1 << 2, - SSSE3 = 1 << 3, - SSE41 = 1 << 4, - SSE42 = 1 << 5, - AVX = 1 << 6, - F16C = 1 << 7, - FMA = 1 << 8, - AVX2 = 1 << 9, - BMI1 = 1 << 10, - BMI2 = 1 << 11, - + SSE1 = 1 << 0, + SSE2 = 1 << 1, + SSE3 = 1 << 2, + SSSE3 = 1 << 3, + SSE41 = 1 << 4, + SSE42 = 1 << 5, + AVX = 1 << 6, + F16C = 1 << 7, + FMA = 1 << 8, + AVX2 = 1 << 9, + BMI1 = 1 << 10, + BMI2 = 1 << 11, // Handy alias for all the cool Haswell+ instructions. HSW = AVX2 | BMI1 | BMI2 | F16C | FMA, + + AVX512F = 1 << 12, + AVX512DQ = 1 << 13, + AVX512IFMA = 1 << 14, + AVX512PF = 1 << 15, + AVX512ER = 1 << 16, + AVX512CD = 1 << 17, + AVX512BW = 1 << 18, + AVX512VL = 1 << 19, + + // Handy alias for all the cool Skylake Xeon+ instructions. + SKY = AVX512F | AVX512DQ | AVX512CD | AVX512BW | AVX512VL, }; enum { NEON = 1 << 0, diff --git a/gfx/skia/skia/src/core/SkData.cpp b/gfx/skia/skia/src/core/SkData.cpp index ec619d99e5a1..84b60be53b3d 100644 --- a/gfx/skia/skia/src/core/SkData.cpp +++ b/gfx/skia/skia/src/core/SkData.cpp @@ -19,10 +19,9 @@ SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) { fReleaseProcContext = context; } -// This constructor means we are inline with our fPtr's contents. Thus we set fPtr -// to point right after this. We also set our releaseproc to sk_inplace_sentinel_releaseproc, -// since we need to handle "delete" ourselves. See internal_displose(). -// +/** This constructor means we are inline with our fPtr's contents. + * Thus we set fPtr to point right after this. + */ SkData::SkData(size_t size) { fPtr = (char*)(this + 1); // contents are immediately after this fSize = size; @@ -70,12 +69,12 @@ sk_sp SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) { sk_throw(); } - char* storage = (char*)sk_malloc_throw(actualLength); - SkData* data = new (storage) SkData(length); + void* storage = ::operator new (actualLength); + sk_sp data(new (storage) SkData(length)); if (srcOrNull) { memcpy(data->writable_data(), srcOrNull, length); } - return sk_sp(data); + return data; } void SkData::DummyReleaseProc(const void*, void*) {} @@ -144,8 +143,7 @@ sk_sp SkData::MakeFromFD(int fd) { if (nullptr == addr) { return nullptr; } - - return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, nullptr); + return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast(size)); } // assumes context is a SkData diff --git a/gfx/skia/skia/src/core/SkDataTable.cpp b/gfx/skia/skia/src/core/SkDataTable.cpp index ea2b91b90323..e80ba8f2b572 100644 --- a/gfx/skia/skia/src/core/SkDataTable.cpp +++ b/gfx/skia/skia/src/core/SkDataTable.cpp @@ -129,53 +129,3 @@ sk_sp SkDataTable::MakeArrayProc(const void* array, size_t elemSize } return sk_sp(new SkDataTable(array, elemSize, count, proc, ctx)); } - -/////////////////////////////////////////////////////////////////////////////// - -static void chunkalloc_freeproc(void* context) { delete (SkChunkAlloc*)context; } - -SkDataTableBuilder::SkDataTableBuilder(size_t minChunkSize) - : fHeap(nullptr) - , fMinChunkSize(minChunkSize) {} - -SkDataTableBuilder::~SkDataTableBuilder() { this->reset(); } - -void SkDataTableBuilder::reset(size_t minChunkSize) { - fMinChunkSize = minChunkSize; - fDir.reset(); - if (fHeap) { - delete fHeap; - fHeap = nullptr; - } -} - -void SkDataTableBuilder::append(const void* src, size_t size) { - if (nullptr == fHeap) { - fHeap = new SkChunkAlloc(fMinChunkSize); - } - - void* dst = fHeap->alloc(size, SkChunkAlloc::kThrow_AllocFailType); - memcpy(dst, src, size); - - SkDataTable::Dir* dir = fDir.append(); - dir->fPtr = dst; - dir->fSize = size; -} - -sk_sp SkDataTableBuilder::detachDataTable() { - const int count = fDir.count(); - if (0 == count) { - return SkDataTable::MakeEmpty(); - } - - // Copy the dir into the heap; - void* dir = fHeap->alloc(count * sizeof(SkDataTable::Dir), SkChunkAlloc::kThrow_AllocFailType); - memcpy(dir, fDir.begin(), count * sizeof(SkDataTable::Dir)); - - sk_sp table( - new SkDataTable((SkDataTable::Dir*)dir, count, chunkalloc_freeproc, fHeap)); - // we have to detach our fHeap, since we are giving that to the table - fHeap = nullptr; - fDir.reset(); - return table; -} diff --git a/gfx/skia/skia/src/core/SkDeduper.h b/gfx/skia/skia/src/core/SkDeduper.h index f82f4fd8c268..4ba685f10d62 100644 --- a/gfx/skia/skia/src/core/SkDeduper.h +++ b/gfx/skia/skia/src/core/SkDeduper.h @@ -8,7 +8,7 @@ #ifndef SkDeduper_DEFINED #define SkDeduper_DEFINED -#include "SkTypes.h" +#include "SkFlattenable.h" class SkImage; class SkPicture; diff --git a/gfx/skia/skia/src/core/SkDeque.cpp b/gfx/skia/skia/src/core/SkDeque.cpp index f9ab4af531a7..167ce46ccc4b 100644 --- a/gfx/skia/skia/src/core/SkDeque.cpp +++ b/gfx/skia/skia/src/core/SkDeque.cpp @@ -5,8 +5,8 @@ * found in the LICENSE file. */ - #include "SkDeque.h" +#include "SkMalloc.h" struct SkDeque::Block { Block* fNext; diff --git a/gfx/skia/skia/src/core/SkDescriptor.h b/gfx/skia/skia/src/core/SkDescriptor.h index efa02783be50..0e91c3c2cf98 100644 --- a/gfx/skia/skia/src/core/SkDescriptor.h +++ b/gfx/skia/skia/src/core/SkDescriptor.h @@ -11,6 +11,7 @@ #include "SkOpts.h" #include "SkTypes.h" +#include class SkDescriptor : SkNoncopyable { public: @@ -19,15 +20,13 @@ public: return sizeof(SkDescriptor) + entryCount * sizeof(Entry); } - static SkDescriptor* Alloc(size_t length) { + static std::unique_ptr Alloc(size_t length) { SkASSERT(SkAlign4(length) == length); - SkDescriptor* desc = (SkDescriptor*)sk_malloc_throw(length); - return desc; + return std::unique_ptr(static_cast(::operator new (length))); } - static void Free(SkDescriptor* desc) { - sk_free(desc); - } + // Ensure the unsized delete is called. + void operator delete(void* p) { ::operator delete(p); } void init() { fLength = sizeof(SkDescriptor); @@ -79,9 +78,9 @@ public: return nullptr; } - SkDescriptor* copy() const { - SkDescriptor* desc = SkDescriptor::Alloc(fLength); - memcpy(desc, this, fLength); + std::unique_ptr copy() const { + std::unique_ptr desc = SkDescriptor::Alloc(fLength); + memcpy(desc.get(), this, fLength); return desc; } @@ -149,7 +148,7 @@ public: if (size <= sizeof(fStorage)) { fDesc = (SkDescriptor*)(void*)fStorage; } else { - fDesc = SkDescriptor::Alloc(size); + fDesc = SkDescriptor::Alloc(size).release(); } } @@ -157,7 +156,7 @@ public: private: void free() { if (fDesc != (SkDescriptor*)(void*)fStorage) { - SkDescriptor::Free(fDesc); + delete fDesc; } } diff --git a/gfx/skia/skia/src/core/SkDevice.cpp b/gfx/skia/skia/src/core/SkDevice.cpp index 70eabab7367e..f2732e256909 100644 --- a/gfx/skia/skia/src/core/SkDevice.cpp +++ b/gfx/skia/skia/src/core/SkDevice.cpp @@ -5,54 +5,59 @@ * found in the LICENSE file. */ -#include "SkColorFilter.h" #include "SkDevice.h" +#include "SkColorFilter.h" #include "SkDraw.h" #include "SkDrawFilter.h" -#include "SkImage_Base.h" +#include "SkImageCacherator.h" #include "SkImageFilter.h" #include "SkImageFilterCache.h" #include "SkImagePriv.h" +#include "SkImage_Base.h" #include "SkLatticeIter.h" -#include "SkMetaData.h" #include "SkPatchUtils.h" -#include "SkPathPriv.h" #include "SkPathMeasure.h" -#include "SkRasterClip.h" +#include "SkPathPriv.h" #include "SkRSXform.h" +#include "SkRasterClip.h" #include "SkShader.h" #include "SkSpecialImage.h" +#include "SkTLazy.h" #include "SkTextBlobRunIterator.h" #include "SkTextToPathIter.h" +#include "SkVertices.h" SkBaseDevice::SkBaseDevice(const SkImageInfo& info, const SkSurfaceProps& surfaceProps) : fInfo(info) , fSurfaceProps(surfaceProps) { fOrigin.setZero(); - fMetaData = nullptr; + fCTM.reset(); } -SkBaseDevice::~SkBaseDevice() { delete fMetaData; } +void SkBaseDevice::setOrigin(const SkMatrix& globalCTM, int x, int y) { + fOrigin.set(x, y); + fCTM = globalCTM; + fCTM.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); +} -SkMetaData& SkBaseDevice::getMetaData() { - // metadata users are rare, so we lazily allocate it. If that changes we - // can decide to just make it a field in the device (rather than a ptr) - if (nullptr == fMetaData) { - fMetaData = new SkMetaData; +void SkBaseDevice::setGlobalCTM(const SkMatrix& ctm) { + fCTM = ctm; + if (fOrigin.fX | fOrigin.fY) { + fCTM.postTranslate(-SkIntToScalar(fOrigin.fX), -SkIntToScalar(fOrigin.fY)); } - return *fMetaData; } -#ifdef SK_SUPPORT_LEGACY_ACCESSBITMAP -const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) { - const SkBitmap& bitmap = this->onAccessBitmap(); - if (changePixels) { - bitmap.notifyPixelsChanged(); +bool SkBaseDevice::clipIsWideOpen() const { + if (kRect_ClipType == this->onGetClipType()) { + SkRegion rgn; + this->onAsRgnClip(&rgn); + SkASSERT(rgn.isRect()); + return rgn.getBounds() == SkIRect::MakeWH(this->width(), this->height()); + } else { + return false; } - return bitmap; } -#endif SkPixelGeometry SkBaseDevice::CreateInfo::AdjustGeometry(const SkImageInfo& info, TileUsage tileUsage, @@ -77,35 +82,36 @@ static inline bool is_int(float x) { return x == (float) sk_float_round2int(x); } -void SkBaseDevice::drawRegion(const SkDraw& draw, const SkRegion& region, const SkPaint& paint) { - bool isNonTranslate = draw.fMatrix->getType() & ~(SkMatrix::kTranslate_Mask); +void SkBaseDevice::drawRegion(const SkRegion& region, const SkPaint& paint) { + const SkMatrix& ctm = this->ctm(); + bool isNonTranslate = ctm.getType() & ~(SkMatrix::kTranslate_Mask); bool complexPaint = paint.getStyle() != SkPaint::kFill_Style || paint.getMaskFilter() || paint.getPathEffect(); - bool antiAlias = paint.isAntiAlias() && (!is_int(draw.fMatrix->getTranslateX()) || - !is_int(draw.fMatrix->getTranslateY())); + bool antiAlias = paint.isAntiAlias() && (!is_int(ctm.getTranslateX()) || + !is_int(ctm.getTranslateY())); if (isNonTranslate || complexPaint || antiAlias) { SkPath path; region.getBoundaryPath(&path); - return this->drawPath(draw, path, paint, nullptr, false); + return this->drawPath(path, paint, nullptr, false); } SkRegion::Iterator it(region); while (!it.done()) { - this->drawRect(draw, SkRect::Make(it.rect()), paint); + this->drawRect(SkRect::Make(it.rect()), paint); it.next(); } } -void SkBaseDevice::drawArc(const SkDraw& draw, const SkRect& oval, SkScalar startAngle, +void SkBaseDevice::drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint& paint) { SkPath path; bool isFillNoPathEffect = SkPaint::kFill_Style == paint.getStyle() && !paint.getPathEffect(); SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter, isFillNoPathEffect); - this->drawPath(draw, path, paint); + this->drawPath(path, paint); } -void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, +void SkBaseDevice::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { SkPath path; path.addRRect(outer); @@ -115,25 +121,19 @@ void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, const SkMatrix* preMatrix = nullptr; const bool pathIsMutable = true; - this->drawPath(draw, path, paint, preMatrix, pathIsMutable); + this->drawPath(path, paint, preMatrix, pathIsMutable); } -void SkBaseDevice::drawPatch(const SkDraw& draw, const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { - SkPatchUtils::VertexData data; - - SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, draw.fMatrix); - - // It automatically adjusts lodX and lodY in case it exceeds the number of indices. - // If it fails to generate the vertices, then we do not draw. - if (SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height())) { - this->drawVertices(draw, SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints, - data.fTexCoords, data.fColors, xmode, data.fIndices, data.fIndexCount, - paint); +void SkBaseDevice::drawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode bmode, const SkPaint& paint) { + SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &this->ctm()); + auto vertices = SkPatchUtils::MakeVertices(cubics, colors, texCoords, lod.width(), lod.height()); + if (vertices) { + this->drawVertices(vertices.get(), bmode, paint); } } -void SkBaseDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y, +void SkBaseDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint &paint, SkDrawFilter* drawFilter) { SkPaint runPaint = paint; @@ -156,14 +156,14 @@ void SkBaseDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkSc switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: - this->drawText(draw, it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint); + this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint); break; case SkTextBlob::kHorizontal_Positioning: - this->drawPosText(draw, it.glyphs(), textLen, it.pos(), 1, + this->drawPosText(it.glyphs(), textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), runPaint); break; case SkTextBlob::kFull_Positioning: - this->drawPosText(draw, it.glyphs(), textLen, it.pos(), 2, + this->drawPosText(it.glyphs(), textLen, it.pos(), 2, SkPoint::Make(x, y), runPaint); break; default: @@ -177,70 +177,68 @@ void SkBaseDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkSc } } -void SkBaseDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y, +void SkBaseDevice::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint& paint) { - // Default impl : turns everything into raster bitmap SkBitmap bm; - if (as_IB(image)->getROPixels(&bm)) { - this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); + if (as_IB(image)->getROPixels(&bm, this->imageInfo().colorSpace())) { + this->drawBitmap(bm, SkMatrix::MakeTrans(x, y), paint); } } -void SkBaseDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src, +void SkBaseDevice::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { - // Default impl : turns everything into raster bitmap SkBitmap bm; - if (as_IB(image)->getROPixels(&bm)) { - this->drawBitmapRect(draw, bm, src, dst, paint, constraint); + if (as_IB(image)->getROPixels(&bm, this->imageInfo().colorSpace())) { + this->drawBitmapRect(bm, src, dst, paint, constraint); } } -void SkBaseDevice::drawImageNine(const SkDraw& draw, const SkImage* image, const SkIRect& center, +void SkBaseDevice::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, const SkPaint& paint) { SkLatticeIter iter(image->width(), image->height(), center, dst); SkRect srcR, dstR; while (iter.next(&srcR, &dstR)) { - this->drawImageRect(draw, image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); + this->drawImageRect(image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); } } -void SkBaseDevice::drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, const SkIRect& center, +void SkBaseDevice::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint& paint) { SkLatticeIter iter(bitmap.width(), bitmap.height(), center, dst); SkRect srcR, dstR; while (iter.next(&srcR, &dstR)) { - this->drawBitmapRect(draw, bitmap, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); + this->drawBitmapRect(bitmap, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); } } -void SkBaseDevice::drawImageLattice(const SkDraw& draw, const SkImage* image, +void SkBaseDevice::drawImageLattice(const SkImage* image, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint& paint) { SkLatticeIter iter(lattice, dst); SkRect srcR, dstR; while (iter.next(&srcR, &dstR)) { - this->drawImageRect(draw, image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); + this->drawImageRect(image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); } } -void SkBaseDevice::drawBitmapLattice(const SkDraw& draw, const SkBitmap& bitmap, +void SkBaseDevice::drawBitmapLattice(const SkBitmap& bitmap, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint& paint) { SkLatticeIter iter(lattice, dst); SkRect srcR, dstR; while (iter.next(&srcR, &dstR)) { - this->drawBitmapRect(draw, bitmap, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); + this->drawBitmapRect(bitmap, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); } } -void SkBaseDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRSXform xform[], +void SkBaseDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], const SkColor colors[], int count, - SkXfermode::Mode mode, const SkPaint& paint) { + SkBlendMode mode, const SkPaint& paint) { SkPath path; path.setIsVolatile(true); @@ -262,19 +260,19 @@ void SkBaseDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkR pnt.setShader(std::move(shader)); if (colors) { - pnt.setColorFilter(SkColorFilter::MakeModeFilter(colors[i], mode)); + pnt.setColorFilter(SkColorFilter::MakeModeFilter(colors[i], (SkBlendMode)mode)); } path.rewind(); path.addPoly(quad, 4, true); path.setConvexity(SkPath::kConvex_Convexity); - this->drawPath(draw, path, pnt, nullptr, true); + this->drawPath(path, pnt, nullptr, true); } } /////////////////////////////////////////////////////////////////////////////////////////////////// -void SkBaseDevice::drawSpecial(const SkDraw&, SkSpecialImage*, int x, int y, const SkPaint&) {} +void SkBaseDevice::drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&) {} sk_sp SkBaseDevice::makeSpecial(const SkBitmap&) { return nullptr; } sk_sp SkBaseDevice::makeSpecial(const SkImage*) { return nullptr; } sk_sp SkBaseDevice::snapSpecial() { return nullptr; } @@ -282,31 +280,11 @@ sk_sp SkBaseDevice::snapSpecial() { return nullptr; } /////////////////////////////////////////////////////////////////////////////////////////////////// bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) { -#ifdef SK_DEBUG - SkASSERT(info.width() > 0 && info.height() > 0); - SkASSERT(dstP); - SkASSERT(rowBytes >= info.minRowBytes()); - SkASSERT(x >= 0 && y >= 0); - - const SkImageInfo& srcInfo = this->imageInfo(); - SkASSERT(x + info.width() <= srcInfo.width()); - SkASSERT(y + info.height() <= srcInfo.height()); -#endif return this->onReadPixels(info, dstP, rowBytes, x, y); } bool SkBaseDevice::writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y) { -#ifdef SK_DEBUG - SkASSERT(info.width() > 0 && info.height() > 0); - SkASSERT(pixels); - SkASSERT(rowBytes >= info.minRowBytes()); - SkASSERT(x >= 0 && y >= 0); - - const SkImageInfo& dstInfo = this->imageInfo(); - SkASSERT(x + info.width() <= dstInfo.width()); - SkASSERT(y + info.height() <= dstInfo.height()); -#endif return this->onWritePixels(info, pixels, rowBytes, x, y); } @@ -363,8 +341,7 @@ static void morphpoints(SkPoint dst[], const SkPoint src[], int count, matrix.postTranslate(pos.fX, pos.fY); matrix.mapPoints(&dst[i], &pt, 1); */ - dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy), - pos.fY + SkScalarMul(tangent.fX, sy)); + dst[i].set(pos.fX - tangent.fY * sy, pos.fY + tangent.fX * sy); } } @@ -411,13 +388,13 @@ static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, } } -void SkBaseDevice::drawTextOnPath(const SkDraw& draw, const void* text, size_t byteLength, +void SkBaseDevice::drawTextOnPath(const void* text, size_t byteLength, const SkPath& follow, const SkMatrix* matrix, const SkPaint& paint) { SkASSERT(byteLength == 0 || text != nullptr); // nothing to draw - if (text == nullptr || byteLength == 0 || draw.fRC->isEmpty()) { + if (text == nullptr || byteLength == 0) { return; } @@ -452,7 +429,7 @@ void SkBaseDevice::drawTextOnPath(const SkDraw& draw, const void* text, size_t b m.postConcat(*matrix); } morphpath(&tmp, *iterPath, meas, m); - this->drawPath(draw, tmp, iter.getPaint(), nullptr, true); + this->drawPath(tmp, iter.getPaint(), nullptr, true); } } } @@ -467,7 +444,7 @@ static int count_utf16(const char* text) { static int return_4(const char* text) { return 4; } static int return_2(const char* text) { return 2; } -void SkBaseDevice::drawTextRSXform(const SkDraw& draw, const void* text, size_t len, +void SkBaseDevice::drawTextRSXform(const void* text, size_t len, const SkRSXform xform[], const SkPaint& paint) { CountTextProc proc = nullptr; switch (paint.getTextEncoding()) { @@ -485,15 +462,15 @@ void SkBaseDevice::drawTextRSXform(const SkDraw& draw, const void* text, size_t break; } - SkDraw localD(draw); SkMatrix localM, currM; const void* stopText = (const char*)text + len; while ((const char*)text < (const char*)stopText) { localM.setRSXform(*xform++); - currM.setConcat(*draw.fMatrix, localM); - localD.fMatrix = &currM; + currM.setConcat(this->ctm(), localM); + SkAutoDeviceCTMRestore adc(this, currM); + int subLen = proc((const char*)text); - this->drawText(localD, text, subLen, 0, 0, paint); + this->drawText(text, subLen, 0, 0, paint); text = (const char*)text + subLen; } } diff --git a/gfx/skia/skia/include/core/SkDevice.h b/gfx/skia/skia/src/core/SkDevice.h similarity index 70% rename from gfx/skia/skia/include/core/SkDevice.h rename to gfx/skia/skia/src/core/SkDevice.h index c29a65d7761a..f1f548811192 100644 --- a/gfx/skia/skia/include/core/SkDevice.h +++ b/gfx/skia/skia/src/core/SkDevice.h @@ -14,26 +14,18 @@ #include "SkSurfaceProps.h" class SkBitmap; -class SkClipStack; -class SkDraw; class SkDrawFilter; class SkImageFilterCache; struct SkIRect; class SkMatrix; -class SkMetaData; +class SkRasterHandleAllocator; class SkRegion; class SkSpecialImage; class GrRenderTarget; class SK_API SkBaseDevice : public SkRefCnt { public: - /** - * Construct a new device. - */ - explicit SkBaseDevice(const SkImageInfo&, const SkSurfaceProps&); - virtual ~SkBaseDevice(); - - SkMetaData& getMetaData(); + SkBaseDevice(const SkImageInfo&, const SkSurfaceProps&); /** * Return ImageInfo for this device. If the canvas is not backed by pixels @@ -77,16 +69,6 @@ public: return this->imageInfo().isOpaque(); } -#ifdef SK_SUPPORT_LEGACY_ACCESSBITMAP - /** Return the bitmap associated with this device. Call this each time you need - to access the bitmap, as it notifies the subclass to perform any flushing - etc. before you examine the pixels. - @param changePixels set to true if the caller plans to change the pixels - @return the device's bitmap - */ - const SkBitmap& accessBitmap(bool changePixels); -#endif - bool writePixels(const SkImageInfo&, const void*, size_t rowBytes, int x, int y); /** @@ -112,6 +94,37 @@ public: */ const SkIPoint& getOrigin() const { return fOrigin; } + virtual void* getRasterHandle() const { return nullptr; } + + void save() { this->onSave(); } + void restore(const SkMatrix& ctm) { + this->onRestore(); + this->setGlobalCTM(ctm); + } + void clipRect(const SkRect& rect, SkClipOp op, bool aa) { + this->onClipRect(rect, op, aa); + } + void clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) { + this->onClipRRect(rrect, op, aa); + } + void clipPath(const SkPath& path, SkClipOp op, bool aa) { + this->onClipPath(path, op, aa); + } + void clipRegion(const SkRegion& region, SkClipOp op) { + this->onClipRegion(region, op); + } + void androidFramework_setDeviceClipRestriction(SkIRect* mutableClipRestriction) { + this->onSetDeviceClipRestriction(mutableClipRestriction); + } + bool clipIsWideOpen() const; + + const SkMatrix& ctm() const { return fCTM; } + void setCTM(const SkMatrix& ctm) { + fCTM = ctm; + } + void setGlobalCTM(const SkMatrix& ctm); + virtual void validateDevBounds(const SkIRect&) {} + protected: enum TileUsage { kPossible_TileUsage, //!< the created device may be drawn tiled @@ -130,28 +143,44 @@ protected: virtual bool onShouldDisableLCD(const SkPaint&) const { return false; } + virtual void onSave() {} + virtual void onRestore() {} + virtual void onClipRect(const SkRect& rect, SkClipOp, bool aa) {} + virtual void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) {} + virtual void onClipPath(const SkPath& path, SkClipOp, bool aa) {} + virtual void onClipRegion(const SkRegion& deviceRgn, SkClipOp) {} + virtual void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) {} + virtual bool onClipIsAA() const = 0; + virtual void onAsRgnClip(SkRegion*) const = 0; + enum ClipType { + kEmpty_ClipType, + kRect_ClipType, + kComplex_ClipType + }; + virtual ClipType onGetClipType() const = 0; + /** These are called inside the per-device-layer loop for each draw call. When these are called, we have already applied any saveLayer operations, and are handling any looping from the paint, and any effects from the DrawFilter. */ - virtual void drawPaint(const SkDraw&, const SkPaint& paint) = 0; - virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, + virtual void drawPaint(const SkPaint& paint) = 0; + virtual void drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint[], const SkPaint& paint) = 0; - virtual void drawRect(const SkDraw&, const SkRect& r, + virtual void drawRect(const SkRect& r, const SkPaint& paint) = 0; - virtual void drawRegion(const SkDraw&, const SkRegion& r, + virtual void drawRegion(const SkRegion& r, const SkPaint& paint); - virtual void drawOval(const SkDraw&, const SkRect& oval, + virtual void drawOval(const SkRect& oval, const SkPaint& paint) = 0; /** By the time this is called we know that abs(sweepAngle) is in the range [0, 360). */ - virtual void drawArc(const SkDraw&, const SkRect& oval, SkScalar startAngle, + virtual void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint& paint); - virtual void drawRRect(const SkDraw&, const SkRRect& rr, + virtual void drawRRect(const SkRRect& rr, const SkPaint& paint) = 0; // Default impl calls drawPath() - virtual void drawDRRect(const SkDraw&, const SkRRect& outer, + virtual void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint&); /** @@ -165,75 +194,71 @@ protected: * affect the geometry/rasterization, then the pre matrix can just be * pre-concated with the current matrix. */ - virtual void drawPath(const SkDraw&, const SkPath& path, + virtual void drawPath(const SkPath& path, const SkPaint& paint, const SkMatrix* prePathMatrix = NULL, bool pathIsMutable = false) = 0; - virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, + virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint& paint) = 0; - virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, + virtual void drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) = 0; /** * The default impl. will create a bitmap-shader from the bitmap, * and call drawRect with it. */ - virtual void drawBitmapRect(const SkDraw&, const SkBitmap&, + virtual void drawBitmapRect(const SkBitmap&, const SkRect* srcOrNull, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint) = 0; - virtual void drawBitmapNine(const SkDraw&, const SkBitmap&, const SkIRect& center, + virtual void drawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint&); - virtual void drawBitmapLattice(const SkDraw&, const SkBitmap&, const SkCanvas::Lattice&, + virtual void drawBitmapLattice(const SkBitmap&, const SkCanvas::Lattice&, const SkRect& dst, const SkPaint&); - virtual void drawImage(const SkDraw&, const SkImage*, SkScalar x, SkScalar y, const SkPaint&); - virtual void drawImageRect(const SkDraw&, const SkImage*, const SkRect* src, const SkRect& dst, + virtual void drawImage(const SkImage*, SkScalar x, SkScalar y, const SkPaint&); + virtual void drawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint); - virtual void drawImageNine(const SkDraw&, const SkImage*, const SkIRect& center, + virtual void drawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, const SkPaint&); - virtual void drawImageLattice(const SkDraw&, const SkImage*, const SkCanvas::Lattice&, + virtual void drawImageLattice(const SkImage*, const SkCanvas::Lattice&, const SkRect& dst, const SkPaint&); /** * Does not handle text decoration. * Decorations (underline and stike-thru) will be handled by SkCanvas. */ - virtual void drawText(const SkDraw&, const void* text, size_t len, + virtual void drawText(const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint& paint) = 0; - virtual void drawPosText(const SkDraw&, const void* text, size_t len, + virtual void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) = 0; - virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, - const SkPoint verts[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) = 0; + virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0; // default implementation unrolls the blob runs. - virtual void drawTextBlob(const SkDraw&, const SkTextBlob*, SkScalar x, SkScalar y, + virtual void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y, const SkPaint& paint, SkDrawFilter* drawFilter); // default implementation calls drawVertices - virtual void drawPatch(const SkDraw&, const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint); + virtual void drawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint); // default implementation calls drawPath - virtual void drawAtlas(const SkDraw&, const SkImage* atlas, const SkRSXform[], const SkRect[], - const SkColor[], int count, SkXfermode::Mode, const SkPaint&); + virtual void drawAtlas(const SkImage* atlas, const SkRSXform[], const SkRect[], + const SkColor[], int count, SkBlendMode, const SkPaint&); - virtual void drawAnnotation(const SkDraw&, const SkRect&, const char[], SkData*) {} + virtual void drawAnnotation(const SkRect&, const char[], SkData*) {} /** The SkDevice passed will be an SkDevice which was returned by a call to onCreateDevice on this device with kNeverTile_TileExpectation. */ - virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, + virtual void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) = 0; - virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, const SkPath&, + virtual void drawTextOnPath(const void* text, size_t len, const SkPath&, const SkMatrix*, const SkPaint&); - virtual void drawTextRSXform(const SkDraw&, const void* text, size_t len, const SkRSXform[], + virtual void drawTextRSXform(const void* text, size_t len, const SkRSXform[], const SkPaint&); - virtual void drawSpecial(const SkDraw&, SkSpecialImage*, int x, int y, const SkPaint&); + virtual void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&); virtual sk_sp makeSpecial(const SkBitmap&); virtual sk_sp makeSpecial(const SkImage*); virtual sk_sp snapSpecial(); @@ -242,20 +267,8 @@ protected: /////////////////////////////////////////////////////////////////////////// -#ifdef SK_SUPPORT_LEGACY_ACCESSBITMAP - /** Update as needed the pixel value in the bitmap, so that the caller can - access the pixels directly. - @return The device contents as a bitmap - */ - virtual const SkBitmap& onAccessBitmap() { - SkASSERT(0); - return fLegacyBitmap; - } -#endif - virtual GrContext* context() const { return nullptr; } -protected: virtual sk_sp makeSurface(const SkImageInfo&, const SkSurfaceProps&); virtual bool onPeekPixels(SkPixmap*) { return false; } @@ -293,15 +306,18 @@ protected: CreateInfo(const SkImageInfo& info, TileUsage tileUsage, SkPixelGeometry geo, - bool preserveLCDText) + bool preserveLCDText, + SkRasterHandleAllocator* allocator) : fInfo(info) , fTileUsage(tileUsage) , fPixelGeometry(AdjustGeometry(info, tileUsage, geo, preserveLCDText)) + , fAllocator(allocator) {} const SkImageInfo fInfo; const TileUsage fTileUsage; const SkPixelGeometry fPixelGeometry; + SkRasterHandleAllocator* fAllocator = nullptr; }; /** @@ -343,10 +359,10 @@ private: /** * Don't call this! */ - virtual GrDrawContext* accessDrawContext() { return nullptr; } + virtual GrRenderTargetContext* accessRenderTargetContext() { return nullptr; } // just called by SkCanvas when built as a layer - void setOrigin(int x, int y) { fOrigin.set(x, y); } + void setOrigin(const SkMatrix& ctm, int x, int y); /** Causes any deferred drawing to the device to be completed. */ @@ -354,21 +370,35 @@ private: virtual SkImageFilterCache* getImageFilterCache() { return NULL; } + friend class SkNoPixelsDevice; friend class SkBitmapDevice; void privateResize(int w, int h) { *const_cast(&fInfo) = fInfo.makeWH(w, h); } - SkIPoint fOrigin; - SkMetaData* fMetaData; + SkIPoint fOrigin; const SkImageInfo fInfo; const SkSurfaceProps fSurfaceProps; - -#ifdef SK_SUPPORT_LEGACY_ACCESSBITMAP - SkBitmap fLegacyBitmap; -#endif + SkMatrix fCTM; typedef SkRefCnt INHERITED; }; +class SkAutoDeviceCTMRestore : SkNoncopyable { +public: + SkAutoDeviceCTMRestore(SkBaseDevice* device, const SkMatrix& ctm) + : fDevice(device) + , fPrevCTM(device->ctm()) + { + fDevice->setCTM(ctm); + } + ~SkAutoDeviceCTMRestore() { + fDevice->setCTM(fPrevCTM); + } + +private: + SkBaseDevice* fDevice; + const SkMatrix fPrevCTM; +}; + #endif diff --git a/gfx/skia/skia/src/core/SkDeviceLooper.cpp b/gfx/skia/skia/src/core/SkDeviceLooper.cpp index c4e401361c17..cea92704ef03 100644 --- a/gfx/skia/skia/src/core/SkDeviceLooper.cpp +++ b/gfx/skia/skia/src/core/SkDeviceLooper.cpp @@ -11,7 +11,6 @@ SkDeviceLooper::SkDeviceLooper(const SkPixmap& base, const SkRasterClip& rc, con bool aa) : fBaseDst(base) , fBaseRC(rc) - , fSubsetRC(rc.isForceConservativeRects()) , fDelta(aa ? kAA_Delta : kBW_Delta) { // sentinels that next() has not yet been called, and so our mapper functions diff --git a/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp b/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp index 7e4675bbc1d0..f227d6a30d4e 100644 --- a/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp +++ b/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp @@ -5,8 +5,10 @@ * found in the LICENSE file. */ +#include "SkAutoMalloc.h" #include "SkDistanceFieldGen.h" #include "SkPoint.h" +#include "SkTemplates.h" struct DFData { float fAlpha; // alpha value of source texel diff --git a/gfx/skia/skia/src/core/SkDraw.cpp b/gfx/skia/skia/src/core/SkDraw.cpp index 72b292d308b2..1941e589d960 100644 --- a/gfx/skia/skia/src/core/SkDraw.cpp +++ b/gfx/skia/skia/src/core/SkDraw.cpp @@ -7,14 +7,18 @@ #define __STDC_LIMIT_MACROS #include "SkDraw.h" + +#include "SkArenaAlloc.h" #include "SkBlendModePriv.h" #include "SkBlitter.h" #include "SkCanvas.h" #include "SkColorPriv.h" +#include "SkColorShader.h" #include "SkDevice.h" #include "SkDeviceLooper.h" #include "SkFindAndPlaceGlyph.h" #include "SkFixed.h" +#include "SkLocalMatrixShader.h" #include "SkMaskFilter.h" #include "SkMatrix.h" #include "SkPaint.h" @@ -24,16 +28,15 @@ #include "SkRRect.h" #include "SkScan.h" #include "SkShader.h" -#include "SkSmallAllocator.h" #include "SkString.h" #include "SkStroke.h" #include "SkStrokeRec.h" #include "SkTemplates.h" #include "SkTextMapStateProc.h" #include "SkTLazy.h" +#include "SkUnPreMultiply.h" #include "SkUtils.h" #include "SkVertState.h" -#include "SkXfermode.h" #include "SkBitmapProcShader.h" #include "SkDrawProcs.h" @@ -54,7 +57,7 @@ public: } SkAutoBlitterChoose(const SkPixmap& dst, const SkMatrix& matrix, const SkPaint& paint, bool drawCoverage = false) { - fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage); + fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAlloc, drawCoverage); } SkBlitter* operator->() { return fBlitter; } @@ -63,53 +66,26 @@ public: void choose(const SkPixmap& dst, const SkMatrix& matrix, const SkPaint& paint, bool drawCoverage = false) { SkASSERT(!fBlitter); - fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage); + fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAlloc, drawCoverage); } private: - // Owned by fAllocator, which will handle the delete. + // Owned by fAlloc, which will handle the delete. SkBlitter* fBlitter; - SkTBlitterAllocator fAllocator; + + char fStorage[kSkBlitterContextSize]; + SkArenaAlloc fAlloc{fStorage}; }; #define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose) -/** - * Since we are providing the storage for the shader (to avoid the perf cost - * of calling new) we insist that in our destructor we can account for all - * owners of the shader. - */ -class SkAutoBitmapShaderInstall : SkNoncopyable { -public: - SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint, - const SkMatrix* localMatrix = nullptr) - : fPaint(paint) /* makes a copy of the paint */ { - fPaint.setShader(SkMakeBitmapShader(src, SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode, localMatrix, - kNever_SkCopyPixelsMode, - &fAllocator)); - // we deliberately left the shader with an owner-count of 2 - fPaint.getShader()->ref(); - SkASSERT(2 == fPaint.getShader()->getRefCnt()); - } - - ~SkAutoBitmapShaderInstall() { - // since fAllocator will destroy shader, we insist that owners == 2 - SkASSERT(2 == fPaint.getShader()->getRefCnt()); - - fPaint.setShader(nullptr); // unref the shader by 1 - - } - - // return the new paint that has the shader applied - const SkPaint& paintWithShader() const { return fPaint; } - -private: - // copy of caller's paint (which we then modify) - SkPaint fPaint; - // Stores the shader. - SkTBlitterAllocator fAllocator; -}; -#define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall) +static SkPaint make_paint_with_image( + const SkPaint& origPaint, const SkBitmap& bitmap, SkMatrix* matrix = nullptr) { + SkPaint paint(origPaint); + paint.setShader(SkMakeBitmapShader(bitmap, SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode, matrix, + kNever_SkCopyPixelsMode)); + return paint; +} /////////////////////////////////////////////////////////////////////////////// @@ -471,7 +447,7 @@ bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint, fPaint = &paint; fClip = nullptr; fRC = rc; - fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1; + fRadius = SkScalarToFixed(width * sx) >> 1; return true; } } @@ -538,7 +514,7 @@ PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) { void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint, - bool forceUseDevice) const { + SkBaseDevice* device) const { // if we're in lines mode, force count to be even if (SkCanvas::kLines_PointMode == mode) { count &= ~(size_t)1; @@ -557,7 +533,7 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, } PtProcRec rec; - if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) { + if (!device && rec.init(mode, paint, fMatrix, fRC)) { SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); SkPoint devPts[MAX_DEV_PTS]; @@ -601,12 +577,10 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, // pass true for the last point, since we can modify // then path then path.setIsVolatile((count-1) == i); - if (fDevice) { - fDevice->drawPath(*this, path, newPaint, &preMatrix, - (count-1) == i); + if (device) { + device->drawPath(path, newPaint, &preMatrix, (count-1) == i); } else { - this->drawPath(path, newPaint, &preMatrix, - (count-1) == i); + this->drawPath(path, newPaint, &preMatrix, (count-1) == i); } } } else { @@ -617,8 +591,8 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, r.fTop = pts[i].fY - radius; r.fRight = r.fLeft + width; r.fBottom = r.fTop + width; - if (fDevice) { - fDevice->drawRect(*this, r, newPaint); + if (device) { + device->drawRect(r, newPaint); } else { this->drawRect(r, newPaint); } @@ -648,16 +622,16 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, newP.setStyle(SkPaint::kFill_Style); if (!pointData.fFirst.isEmpty()) { - if (fDevice) { - fDevice->drawPath(*this, pointData.fFirst, newP); + if (device) { + device->drawPath(pointData.fFirst, newP); } else { this->drawPath(pointData.fFirst, newP); } } if (!pointData.fLast.isEmpty()) { - if (fDevice) { - fDevice->drawPath(*this, pointData.fLast, newP); + if (device) { + device->drawPath(pointData.fLast, newP); } else { this->drawPath(pointData.fLast, newP); } @@ -673,18 +647,17 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, newP.setStrokeCap(SkPaint::kButt_Cap); } - if (fDevice) { - fDevice->drawPoints(*this, - SkCanvas::kPoints_PointMode, - pointData.fNumPoints, - pointData.fPoints, - newP); + if (device) { + device->drawPoints(SkCanvas::kPoints_PointMode, + pointData.fNumPoints, + pointData.fPoints, + newP); } else { this->drawPoints(SkCanvas::kPoints_PointMode, pointData.fNumPoints, pointData.fPoints, newP, - forceUseDevice); + device); } break; } else { @@ -699,8 +672,8 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, pointData.fPoints[i].fY - pointData.fSize.fY, pointData.fPoints[i].fX + pointData.fSize.fX, pointData.fPoints[i].fY + pointData.fSize.fY); - if (fDevice) { - fDevice->drawRect(*this, r, newP); + if (device) { + device->drawRect(r, newP); } else { this->drawRect(r, newP); } @@ -721,8 +694,8 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, for (size_t i = 0; i < count; i += inc) { path.moveTo(pts[i]); path.lineTo(pts[i+1]); - if (fDevice) { - fDevice->drawPath(*this, path, p, nullptr, true); + if (device) { + device->drawPath(path, p, nullptr, true); } else { this->drawPath(path, p, nullptr, true); } @@ -1149,7 +1122,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, // this is the old technique, which we preserve for now so // we don't change previous results (testing) // the new way seems fine, its just (a tiny bit) different - int scale = (int)SkScalarMul(coverage, 256); + int scale = (int)(coverage * 256); newAlpha = origPaint.getAlpha() * scale >> 8; #endif SkPaint* writablePaint = paint.writable(); @@ -1260,11 +1233,11 @@ void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) cons SkPaint tmpPaint; tmpPaint.setFlags(paint.getFlags()); tmpPaint.setFilterQuality(paint.getFilterQuality()); - SkAutoBitmapShaderInstall install(bitmap, tmpPaint); + SkPaint paintWithShader = make_paint_with_image(tmpPaint, bitmap); SkRect rr; rr.set(0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); - c.drawRect(rr, install.paintWithShader()); + c.drawRect(rr, paintWithShader); } this->drawDevMask(mask, paint); } @@ -1325,7 +1298,8 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, int ix = SkScalarRoundToInt(matrix.getTranslateX()); int iy = SkScalarRoundToInt(matrix.getTranslateY()); if (clipHandlesSprite(*fRC, ix, iy, pmap)) { - SkTBlitterAllocator allocator; + char storage[kSkBlitterContextSize]; + SkArenaAlloc allocator{storage}; // blitter will be owned by the allocator. SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator); if (blitter) { @@ -1342,11 +1316,10 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, SkDraw draw(*this); draw.fMatrix = &matrix; - if (bitmap.colorType() == kAlpha_8_SkColorType) { + if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) { draw.drawBitmapAsMask(bitmap, *paint); } else { - SkAutoBitmapShaderInstall install(bitmap, *paint); - const SkPaint& paintWithShader = install.paintWithShader(); + SkPaint paintWithShader = make_paint_with_image(*paint, bitmap); const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height()); if (dstBounds) { this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds); @@ -1382,8 +1355,9 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& ori const SkPixmap& pmap = unlocker.pixmap(); if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) { - SkTBlitterAllocator allocator; // blitter will be owned by the allocator. + char storage[kSkBlitterContextSize]; + SkArenaAlloc allocator{storage}; SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator); if (blitter) { SkScan::FillIRect(bounds, *fRC, blitter); @@ -1399,15 +1373,13 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& ori // create shader with offset matrix.setTranslate(r.fLeft, r.fTop); - SkAutoBitmapShaderInstall install(bitmap, paint, &matrix); - const SkPaint& shaderPaint = install.paintWithShader(); - + SkPaint paintWithShader = make_paint_with_image(paint, bitmap, &matrix); SkDraw draw(*this); matrix.reset(); draw.fMatrix = &matrix; // call ourself with a rect // is this OK if paint has a rasterizer? - draw.drawRect(r, shaderPaint); + draw.drawRect(r, paintWithShader); } /////////////////////////////////////////////////////////////////////////////// @@ -1437,8 +1409,7 @@ bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM)); } -void SkDraw::drawText_asPaths(const char text[], size_t byteLength, - SkScalar x, SkScalar y, +void SkDraw::drawText_asPaths(const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) const { SkDEBUGCODE(this->validate();) @@ -1454,12 +1425,7 @@ void SkDraw::drawText_asPaths(const char text[], size_t byteLength, while (iter.next(&iterPath, &xpos)) { matrix.postTranslate(xpos - prevXPos, 0); if (iterPath) { - const SkPaint& pnt = iter.getPaint(); - if (fDevice) { - fDevice->drawPath(*this, *iterPath, pnt, &matrix, false); - } else { - this->drawPath(*iterPath, pnt, &matrix, false); - } + this->drawPath(*iterPath, iter.getPaint(), &matrix, false); } prevXPos = xpos; } @@ -1591,14 +1557,14 @@ private: uint32_t SkDraw::scalerContextFlags() const { uint32_t flags = SkPaint::kBoostContrast_ScalerContextFlag; - if (!SkImageInfoIsGammaCorrect(fDevice->imageInfo())) { + if (!fDst.colorSpace()) { flags |= SkPaint::kFakeGamma_ScalerContextFlag; } return flags; } -void SkDraw::drawText(const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkPaint& paint) const { +void SkDraw::drawText(const char text[], size_t byteLength, SkScalar x, SkScalar y, + const SkPaint& paint, const SkSurfaceProps* props) const { SkASSERT(byteLength == 0 || text != nullptr); SkDEBUGCODE(this->validate();) @@ -1615,7 +1581,7 @@ void SkDraw::drawText(const char text[], size_t byteLength, return; } - SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), fMatrix); + SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), fMatrix); // The Blitter Choose needs to be live while using the blitter below. SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); @@ -1629,9 +1595,9 @@ void SkDraw::drawText(const char text[], size_t byteLength, ////////////////////////////////////////////////////////////////////////////// -void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkPaint& origPaint) const { +void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset, + const SkPaint& origPaint, const SkSurfaceProps* props) const { // setup our std paint, in hopes of getting hits in the cache SkPaint paint(origPaint); SkScalar matrixScale = paint.setupForAsPaths(); @@ -1646,7 +1612,7 @@ void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), paint.isDevKernText(), true); - SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), nullptr); + SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), nullptr); const char* stop = text + byteLength; SkTextAlignProc alignProc(paint.getTextAlign()); @@ -1654,7 +1620,7 @@ void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, // Now restore the original settings, so we "draw" with whatever style/stroking. paint.setStyle(origPaint.getStyle()); - paint.setPathEffect(sk_ref_sp(origPaint.getPathEffect())); + paint.setPathEffect(origPaint.refPathEffect()); while (text < stop) { const SkGlyph& glyph = glyphCacheProc(cache.get(), &text); @@ -1668,20 +1634,16 @@ void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, matrix[SkMatrix::kMTransX] = loc.fX; matrix[SkMatrix::kMTransY] = loc.fY; - if (fDevice) { - fDevice->drawPath(*this, *path, paint, &matrix, false); - } else { - this->drawPath(*path, paint, &matrix, false); - } + this->drawPath(*path, paint, &matrix, false); } } pos += scalarsPerPosition; } } -void SkDraw::drawPosText(const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkPaint& paint) const { +void SkDraw::drawPosText(const char text[], size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset, const SkPaint& paint, + const SkSurfaceProps* props) const { SkASSERT(byteLength == 0 || text != nullptr); SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); @@ -1693,11 +1655,11 @@ void SkDraw::drawPosText(const char text[], size_t byteLength, } if (ShouldDrawTextAsPaths(paint, *fMatrix)) { - this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint); + this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint, props); return; } - SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), fMatrix); + SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), fMatrix); // The Blitter Choose needs to be live while using the blitter below. SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); @@ -1740,7 +1702,7 @@ public: class TriColorShaderContext : public SkShader::Context { public: TriColorShaderContext(const SkTriColorShader& shader, const ContextRec&); - virtual ~TriColorShaderContext(); + ~TriColorShaderContext() override; void shadeSpan(int x, int y, SkPMColor dstC[], int count) override; private: @@ -1775,9 +1737,8 @@ public: } protected: - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec& rec, void* storage) const override { - return new (storage) TriColorShaderContext(*this, rec); + Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const override { + return alloc->make(*this, rec); } private: @@ -1833,10 +1794,6 @@ SkTriColorShader::TriColorShaderContext::TriColorShaderContext(const SkTriColorS SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {} -size_t SkTriColorShader::onContextSize(const ContextRec&) const { - return sizeof(TriColorShaderContext); -} - void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) { SkTriColorShader* parent = static_cast(const_cast(&fShader)); TriColorShaderData* set = parent->takeSetupData(); @@ -1891,9 +1848,109 @@ void SkTriColorShader::toString(SkString* str) const { } #endif -void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, +namespace { + +// Similar to SkLocalMatrixShader, but composes the local matrix with the CTM (instead +// of composing with the inherited local matrix): +// +// rec' = {rec.ctm x localMatrix, rec.localMatrix} +// +// (as opposed to rec' = {rec.ctm, rec.localMatrix x localMatrix}) +// +class SkLocalInnerMatrixShader final : public SkShader { +public: + SkLocalInnerMatrixShader(sk_sp proxy, const SkMatrix& localMatrix) + : INHERITED(&localMatrix) + , fProxyShader(std::move(proxy)) {} + + Factory getFactory() const override { + SkASSERT(false); + return nullptr; + } + +protected: + void flatten(SkWriteBuffer&) const override { + SkASSERT(false); + } + + Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const override { + SkMatrix adjustedCTM = SkMatrix::Concat(*rec.fMatrix, this->getLocalMatrix()); + ContextRec newRec(rec); + newRec.fMatrix = &adjustedCTM; + return fProxyShader->makeContext(newRec, alloc); + } + + bool onAppendStages(SkRasterPipeline* p, SkColorSpace* cs, SkArenaAlloc* alloc, + const SkMatrix& ctm, const SkPaint& paint, + const SkMatrix* localM) const override { + // We control the shader graph ancestors, so we know there's no local matrix being + // injected before this. + SkASSERT(!localM); + + SkMatrix adjustedCTM = SkMatrix::Concat(ctm, this->getLocalMatrix()); + return fProxyShader->appendStages(p, cs, alloc, adjustedCTM, paint); + } + +private: + sk_sp fProxyShader; + + typedef SkShader INHERITED; +}; + +sk_sp MakeTextureShader(const VertState& state, const SkPoint verts[], + const SkPoint texs[], const SkPaint& paint, + SkColorSpace* dstColorSpace, + SkArenaAlloc* alloc) { + SkASSERT(paint.getShader()); + + const auto& p0 = texs[state.f0], + p1 = texs[state.f1], + p2 = texs[state.f2]; + + if (p0 != p1 || p0 != p2) { + // Common case (non-collapsed texture coordinates). + // Map the texture to vertices using a local transform. + + // We cannot use a plain SkLocalMatrix shader, because we need the texture matrix + // to compose next to the CTM. + SkMatrix localMatrix; + return texture_to_matrix(state, verts, texs, &localMatrix) + ? alloc->makeSkSp(paint.refShader(), localMatrix) + : nullptr; + } + + // Collapsed texture coordinates special case. + // The texture is a solid color, sampled at the given point. + SkMatrix shaderInvLocalMatrix; + SkAssertResult(paint.getShader()->getLocalMatrix().invert(&shaderInvLocalMatrix)); + + const auto sample = SkPoint::Make(0.5f, 0.5f); + const auto mappedSample = shaderInvLocalMatrix.mapXY(sample.x(), sample.y()), + mappedPoint = shaderInvLocalMatrix.mapXY(p0.x(), p0.y()); + const auto localMatrix = SkMatrix::MakeTrans(mappedSample.x() - mappedPoint.x(), + mappedSample.y() - mappedPoint.y()); + + SkShader::ContextRec rec(paint, SkMatrix::I(), &localMatrix, + SkShader::ContextRec::kPMColor_DstType, dstColorSpace); + auto* ctx = paint.getShader()->makeContext(rec, alloc); + if (!ctx) { + return nullptr; + } + + SkPMColor pmColor; + ctx->shadeSpan(SkScalarFloorToInt(sample.x()), SkScalarFloorToInt(sample.y()), &pmColor, 1); + + // no need to keep this temp context around. + alloc->reset(); + + return alloc->makeSkSp(SkUnPreMultiply::PMColorToColor(pmColor)); +} + +} // anonymous ns + +void SkDraw::drawVertices(SkVertices::VertexMode vmode, int count, const SkPoint vertices[], const SkPoint textures[], - const SkColor colors[], SkXfermode* xmode, + const SkColor colors[], SkBlendMode bmode, const uint16_t indices[], int indexCount, const SkPaint& paint) const { SkASSERT(0 == count || vertices); @@ -1940,9 +1997,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, } else { // colors * texture SkASSERT(shader); - sk_sp xfer = xmode ? sk_ref_sp(xmode) - : SkXfermode::Make(SkXfermode::kModulate_Mode); - p.setShader(SkShader::MakeComposeShader(triShader, sk_ref_sp(shader), std::move(xfer))); + p.setShader(SkShader::MakeComposeShader(triShader, sk_ref_sp(shader), bmode)); } } @@ -1960,12 +2015,31 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, SkTriColorShader::TriColorShaderData verticesSetup = { vertices, colors, &state }; while (vertProc(&state)) { + auto* blitterPtr = blitter.get(); + + // We're going to allocate at most + // + // * one SkLocalMatrixShader OR one SkColorShader + // * one SkComposeShader + // * one SkAutoBlitterChoose + // + static constexpr size_t kAllocSize = + sizeof(SkAutoBlitterChoose) + sizeof(SkComposeShader) + + SkTMax(sizeof(SkLocalInnerMatrixShader), sizeof(SkColorShader)); + char allocBuffer[kAllocSize]; + SkArenaAlloc alloc(allocBuffer); + if (textures) { - SkMatrix tempM; - if (texture_to_matrix(state, vertices, textures, &tempM)) { - SkShader::ContextRec rec(p, *fMatrix, &tempM, - SkBlitter::PreferredShaderDest(fDst.info())); - if (!blitter->resetShaderContext(rec)) { + sk_sp texShader = MakeTextureShader(state, vertices, textures, paint, + fDst.colorSpace(), &alloc); + if (texShader) { + SkPaint localPaint(p); + localPaint.setShader(colors + ? alloc.makeSkSp(triShader, std::move(texShader), bmode) + : std::move(texShader)); + + blitterPtr = alloc.make(fDst, *fMatrix, localPaint)->get(); + if (blitterPtr->isNullBlitter()) { continue; } } @@ -1977,8 +2051,8 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, SkPoint tmp[] = { devVerts[state.f0], devVerts[state.f1], devVerts[state.f2] }; - SkScan::FillTriangle(tmp, *fRC, blitter.get()); - triShader->bindSetupData(NULL); + SkScan::FillTriangle(tmp, *fRC, blitterPtr); + triShader->bindSetupData(nullptr); } } else { // no colors[] and no texture, stroke hairlines with paint's color. diff --git a/gfx/skia/skia/include/core/SkDraw.h b/gfx/skia/skia/src/core/SkDraw.h similarity index 88% rename from gfx/skia/skia/include/core/SkDraw.h rename to gfx/skia/skia/src/core/SkDraw.h index d7068fd3fcb3..316873579990 100644 --- a/gfx/skia/skia/include/core/SkDraw.h +++ b/gfx/skia/skia/src/core/SkDraw.h @@ -14,6 +14,7 @@ #include "SkMask.h" #include "SkPaint.h" #include "SkStrokeRec.h" +#include "SkVertices.h" class SkBitmap; class SkClipStack; @@ -33,7 +34,7 @@ public: void drawPaint(const SkPaint&) const; void drawPoints(SkCanvas::PointMode, size_t count, const SkPoint[], - const SkPaint&, bool forceUseDevice = false) const; + const SkPaint&, SkBaseDevice*) const; void drawRect(const SkRect& prePaintRect, const SkPaint&, const SkMatrix* paintMatrix, const SkRect* postPaintRect) const; void drawRect(const SkRect& rect, const SkPaint& paint) const { @@ -64,13 +65,13 @@ public: const SkPaint&) const; void drawSprite(const SkBitmap&, int x, int y, const SkPaint&) const; void drawText(const char text[], size_t byteLength, SkScalar x, - SkScalar y, const SkPaint& paint) const; + SkScalar y, const SkPaint& paint, const SkSurfaceProps*) const; void drawPosText(const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkPaint& paint) const; - void drawVertices(SkCanvas::VertexMode mode, int count, + const SkPoint& offset, const SkPaint&, const SkSurfaceProps*) const; + void drawVertices(SkVertices::VertexMode mode, int count, const SkPoint vertices[], const SkPoint textures[], - const SkColor colors[], SkXfermode* xmode, + const SkColor colors[], SkBlendMode bmode, const uint16_t indices[], int ptCount, const SkPaint& paint) const; @@ -114,11 +115,11 @@ public: SkPoint* strokeSize); static bool ShouldDrawTextAsPaths(const SkPaint&, const SkMatrix&); - void drawText_asPaths(const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkPaint&) const; - void drawPosText_asPaths(const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkPaint&) const; + void drawText_asPaths(const char text[], size_t byteLength, SkScalar x, SkScalar y, + const SkPaint&) const; + void drawPosText_asPaths(const char text[], size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset, + const SkPaint&, const SkSurfaceProps*) const; static SkScalar ComputeResScaleForStroking(const SkMatrix& ); private: void drawDevMask(const SkMask& mask, const SkPaint&) const; @@ -150,9 +151,6 @@ public: const SkMatrix* fMatrix; // required const SkRasterClip* fRC; // required - const SkClipStack* fClipStack; // optional, may be null - SkBaseDevice* fDevice; // optional, may be null - #ifdef SK_DEBUG void validate() const; #else diff --git a/gfx/skia/skia/src/core/SkDrawLooper.cpp b/gfx/skia/skia/src/core/SkDrawLooper.cpp index aa53f2e3a131..54c9af19fac2 100644 --- a/gfx/skia/skia/src/core/SkDrawLooper.cpp +++ b/gfx/skia/skia/src/core/SkDrawLooper.cpp @@ -5,19 +5,19 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkDrawLooper.h" #include "SkCanvas.h" #include "SkMatrix.h" #include "SkPaint.h" #include "SkRect.h" -#include "SkSmallAllocator.h" bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) const { SkCanvas canvas; - SkSmallAllocator<1, 32> allocator; - void* buffer = allocator.reserveT(this->contextSize()); + char storage[48]; + SkArenaAlloc alloc {storage}; - SkDrawLooper::Context* context = this->createContext(&canvas, buffer); + SkDrawLooper::Context* context = this->makeContext(&canvas, &alloc); for (;;) { SkPaint p(paint); if (context->next(&canvas, &p)) { @@ -38,11 +38,12 @@ void SkDrawLooper::computeFastBounds(const SkPaint& paint, const SkRect& s, const SkRect src = s; SkCanvas canvas; - SkSmallAllocator<1, 32> allocator; - void* buffer = allocator.reserveT(this->contextSize()); + char storage[48]; + SkArenaAlloc alloc {storage}; *dst = src; // catch case where there are no loops - SkDrawLooper::Context* context = this->createContext(&canvas, buffer); + SkDrawLooper::Context* context = this->makeContext(&canvas, &alloc); + for (bool firstTime = true;; firstTime = false) { SkPaint p(paint); if (context->next(&canvas, &p)) { diff --git a/gfx/skia/skia/src/core/SkEdge.cpp b/gfx/skia/skia/src/core/SkEdge.cpp index d91c3e6bce8f..f8e8d98b5d96 100644 --- a/gfx/skia/skia/src/core/SkEdge.cpp +++ b/gfx/skia/skia/src/core/SkEdge.cpp @@ -157,23 +157,28 @@ static inline SkFDot6 cheap_distance(SkFDot6 dx, SkFDot6 dy) return dx; } -static inline int diff_to_shift(SkFDot6 dx, SkFDot6 dy) +static inline int diff_to_shift(SkFDot6 dx, SkFDot6 dy, int shiftAA = 2) { // cheap calc of distance from center of p0-p2 to the center of the curve SkFDot6 dist = cheap_distance(dx, dy); // shift down dist (it is currently in dot6) - // down by 5 should give us 1/2 pixel accuracy (assuming our dist is accurate...) + // down by 3 should give us 1/8 pixel accuracy (assuming our dist is accurate...) // this is chosen by heuristic: make it as big as possible (to minimize segments) // ... but small enough so that our curves still look smooth + // When shift > 0, we're using AA and everything is scaled up so we can + // lower the accuracy. +#ifdef SK_SUPPORT_LEGACY_QUAD_SHIFT dist = (dist + (1 << 4)) >> 5; +#else + dist = (dist + (1 << 4)) >> (3 + shiftAA); +#endif // each subdivision (shift value) cuts this dist (error) by 1/4 return (32 - SkCLZ(dist)) >> 1; } -int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift) -{ +bool SkQuadraticEdge::setQuadraticWithoutUpdate(const SkPoint pts[3], int shift) { SkFDot6 x0, y0, x1, y1, x2, y2; { @@ -215,7 +220,10 @@ int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift) { SkFDot6 dx = (SkLeftShift(x1, 1) - x0 - x2) >> 2; SkFDot6 dy = (SkLeftShift(y1, 1) - y0 - y2) >> 2; - shift = diff_to_shift(dx, dy); + // This is a little confusing: + // before this line, shift is the scale up factor for AA; + // after this line, shift is the fCurveShift. + shift = diff_to_shift(dx, dy, shift); SkASSERT(shift >= 0); } // need at least 1 subdivision for our bias trick @@ -266,6 +274,13 @@ int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift) fQLastX = SkFDot6ToFixed(x2); fQLastY = SkFDot6ToFixed(y2); + return true; +} + +int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift) { + if (!setQuadraticWithoutUpdate(pts, shift)) { + return 0; + } return this->updateQuadratic(); } @@ -332,7 +347,7 @@ static SkFDot6 cubic_delta_from_line(SkFDot6 a, SkFDot6 b, SkFDot6 c, SkFDot6 d) return SkMax32(SkAbs32(oneThird), SkAbs32(twoThird)); } -int SkCubicEdge::setCubic(const SkPoint pts[4], int shift) { +bool SkCubicEdge::setCubicWithoutUpdate(const SkPoint pts[4], int shift) { SkFDot6 x0, y0, x1, y1, x2, y2, x3, y3; { @@ -428,6 +443,13 @@ int SkCubicEdge::setCubic(const SkPoint pts[4], int shift) { fCLastX = SkFDot6ToFixed(x3); fCLastY = SkFDot6ToFixed(y3); + return true; +} + +int SkCubicEdge::setCubic(const SkPoint pts[4], int shift) { + if (!this->setCubicWithoutUpdate(pts, shift)) { + return 0; + } return this->updateCubic(); } diff --git a/gfx/skia/skia/src/core/SkEdge.h b/gfx/skia/skia/src/core/SkEdge.h index 11669b4f7fb4..9be932552187 100644 --- a/gfx/skia/skia/src/core/SkEdge.h +++ b/gfx/skia/skia/src/core/SkEdge.h @@ -68,6 +68,7 @@ struct SkQuadraticEdge : public SkEdge { SkFixed fQDDx, fQDDy; SkFixed fQLastX, fQLastY; + bool setQuadraticWithoutUpdate(const SkPoint pts[3], int shiftUp); int setQuadratic(const SkPoint pts[3], int shiftUp); int updateQuadratic(); }; @@ -79,6 +80,7 @@ struct SkCubicEdge : public SkEdge { SkFixed fCDDDx, fCDDDy; SkFixed fCLastX, fCLastY; + bool setCubicWithoutUpdate(const SkPoint pts[4], int shiftUp); int setCubic(const SkPoint pts[4], int shiftUp); int updateCubic(); }; @@ -130,5 +132,4 @@ int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, int shift) { return 1; } - #endif diff --git a/gfx/skia/skia/src/core/SkEdgeBuilder.cpp b/gfx/skia/skia/src/core/SkEdgeBuilder.cpp index af68e0ff656e..ceb8f1ad3105 100644 --- a/gfx/skia/skia/src/core/SkEdgeBuilder.cpp +++ b/gfx/skia/skia/src/core/SkEdgeBuilder.cpp @@ -7,14 +7,11 @@ #include "SkEdgeBuilder.h" #include "SkPath.h" #include "SkEdge.h" +#include "SkAnalyticEdge.h" #include "SkEdgeClipper.h" #include "SkLineClipper.h" #include "SkGeometry.h" -template static T* typedAllocThrow(SkChunkAlloc& alloc) { - return static_cast(alloc.allocThrow(sizeof(T))); -} - /////////////////////////////////////////////////////////////////////////////// SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) { @@ -62,45 +59,139 @@ SkEdgeBuilder::Combine SkEdgeBuilder::CombineVertical(const SkEdge* edge, SkEdge return kNo_Combine; } -static bool vertical_line(const SkEdge* edge) { +static inline bool approximatelyEqual(SkFixed a, SkFixed b) { + return SkAbs32(a - b) < 0x100; +} + +SkEdgeBuilder::Combine SkEdgeBuilder::CombineVertical( + const SkAnalyticEdge* edge, SkAnalyticEdge* last) { + SkASSERT(fAnalyticAA); + if (last->fCurveCount || last->fDX || edge->fX != last->fX) { + return kNo_Combine; + } + if (edge->fWinding == last->fWinding) { + if (edge->fLowerY == last->fUpperY) { + last->fUpperY = edge->fUpperY; + last->fY = last->fUpperY; + return kPartial_Combine; + } + if (approximatelyEqual(edge->fUpperY, last->fLowerY)) { + last->fLowerY = edge->fLowerY; + return kPartial_Combine; + } + return kNo_Combine; + } + if (approximatelyEqual(edge->fUpperY, last->fUpperY)) { + if (approximatelyEqual(edge->fLowerY, last->fLowerY)) { + return kTotal_Combine; + } + if (edge->fLowerY < last->fLowerY) { + last->fUpperY = edge->fLowerY; + last->fY = last->fUpperY; + return kPartial_Combine; + } + last->fUpperY = last->fLowerY; + last->fY = last->fUpperY; + last->fLowerY = edge->fLowerY; + last->fWinding = edge->fWinding; + return kPartial_Combine; + } + if (approximatelyEqual(edge->fLowerY, last->fLowerY)) { + if (edge->fUpperY > last->fUpperY) { + last->fLowerY = edge->fUpperY; + return kPartial_Combine; + } + last->fLowerY = last->fUpperY; + last->fUpperY = edge->fUpperY; + last->fY = last->fUpperY; + last->fWinding = edge->fWinding; + return kPartial_Combine; + } + return kNo_Combine; +} + +bool SkEdgeBuilder::vertical_line(const SkEdge* edge) { + return !edge->fDX && !edge->fCurveCount; +} + +bool SkEdgeBuilder::vertical_line(const SkAnalyticEdge* edge) { + SkASSERT(fAnalyticAA); return !edge->fDX && !edge->fCurveCount; } void SkEdgeBuilder::addLine(const SkPoint pts[]) { - SkEdge* edge = typedAllocThrow(fAlloc); - if (edge->setLine(pts[0], pts[1], fShiftUp)) { - if (vertical_line(edge) && fList.count()) { - Combine combine = CombineVertical(edge, *(fList.end() - 1)); - if (kNo_Combine != combine) { - if (kTotal_Combine == combine) { - fList.pop(); + if (fAnalyticAA) { + SkAnalyticEdge* edge = fAlloc.make(); + if (edge->setLine(pts[0], pts[1])) { + if (vertical_line(edge) && fList.count()) { + Combine combine = CombineVertical(edge, (SkAnalyticEdge*)*(fList.end() - 1)); + if (kNo_Combine != combine) { + if (kTotal_Combine == combine) { + fList.pop(); + } + goto unallocate_analytic_edge; } - goto unallocate_edge; } + fList.push(edge); + } else { +unallocate_analytic_edge: + ; + // TODO: unallocate edge from storage... } - fList.push(edge); } else { + SkEdge* edge = fAlloc.make(); + if (edge->setLine(pts[0], pts[1], fShiftUp)) { + if (vertical_line(edge) && fList.count()) { + Combine combine = CombineVertical(edge, (SkEdge*)*(fList.end() - 1)); + if (kNo_Combine != combine) { + if (kTotal_Combine == combine) { + fList.pop(); + } + goto unallocate_edge; + } + } + fList.push(edge); + } else { unallocate_edge: - ; - // TODO: unallocate edge from storage... + ; + // TODO: unallocate edge from storage... + } } } void SkEdgeBuilder::addQuad(const SkPoint pts[]) { - SkQuadraticEdge* edge = typedAllocThrow(fAlloc); - if (edge->setQuadratic(pts, fShiftUp)) { - fList.push(edge); + if (fAnalyticAA) { + SkAnalyticQuadraticEdge* edge = fAlloc.make(); + if (edge->setQuadratic(pts)) { + fList.push(edge); + } else { + // TODO: unallocate edge from storage... + } } else { - // TODO: unallocate edge from storage... + SkQuadraticEdge* edge = fAlloc.make(); + if (edge->setQuadratic(pts, fShiftUp)) { + fList.push(edge); + } else { + // TODO: unallocate edge from storage... + } } } void SkEdgeBuilder::addCubic(const SkPoint pts[]) { - SkCubicEdge* edge = typedAllocThrow(fAlloc); - if (edge->setCubic(pts, fShiftUp)) { - fList.push(edge); + if (fAnalyticAA) { + SkAnalyticCubicEdge* edge = fAlloc.make(); + if (edge->setCubic(pts)) { + fList.push(edge); + } else { + // TODO: unallocate edge from storage... + } } else { - // TODO: unallocate edge from storage... + SkCubicEdge* edge = fAlloc.make(); + if (edge->setCubic(pts, fShiftUp)) { + fList.push(edge); + } else { + // TODO: unallocate edge from storage... + } } } @@ -135,7 +226,14 @@ static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) { } SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkEdge* edge, SkEdge** edgePtr) { - return !vertical_line(edge) || edgePtr <= fEdgeList ? kNo_Combine : + return !vertical_line(edge) || edgePtr <= (SkEdge**)fEdgeList ? kNo_Combine : + CombineVertical(edge, edgePtr[-1]); +} + +SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkAnalyticEdge* edge, + SkAnalyticEdge** edgePtr) { + SkASSERT(fAnalyticAA); + return !vertical_line(edge) || edgePtr <= (SkAnalyticEdge**)fEdgeList ? kNo_Combine : CombineVertical(edge, edgePtr[-1]); } @@ -152,15 +250,14 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift // segments. maxEdgeCount *= SkLineClipper::kMaxClippedLineSegments; } - size_t maxEdgeSize = maxEdgeCount * sizeof(SkEdge); - size_t maxEdgePtrSize = maxEdgeCount * sizeof(SkEdge*); - // lets store the edges and their pointers in the same block - char* storage = (char*)fAlloc.allocThrow(maxEdgeSize + maxEdgePtrSize); - SkEdge* edge = reinterpret_cast(storage); - SkEdge** edgePtr = reinterpret_cast(storage + maxEdgeSize); - // Record the beginning of our pointers, so we can return them to the caller - fEdgeList = edgePtr; + size_t edgeSize = fAnalyticAA ? sizeof(SkAnalyticEdge) : sizeof(SkEdge); + char* edge = fAnalyticAA ? (char*)fAlloc.makeArrayDefault(maxEdgeCount) + : (char*)fAlloc.makeArrayDefault(maxEdgeCount); + + SkDEBUGCODE(char* edgeStart = edge); + char** edgePtr = fAlloc.makeArrayDefault(maxEdgeCount); + fEdgeList = (void**)edgePtr; if (iclip) { SkRect clip; @@ -178,10 +275,16 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift int lineCount = SkLineClipper::ClipLine(pts, clip, lines, canCullToTheRight); SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments); for (int i = 0; i < lineCount; i++) { - if (edge->setLine(lines[i], lines[i + 1], shiftUp)) { - Combine combine = checkVertical(edge, edgePtr); + bool setLineResult = fAnalyticAA ? + ((SkAnalyticEdge*)edge)->setLine(lines[i], lines[i + 1]) : + ((SkEdge*)edge)->setLine(lines[i], lines[i + 1], shiftUp); + if (setLineResult) { + Combine combine = fAnalyticAA ? + checkVertical((SkAnalyticEdge*)edge, (SkAnalyticEdge**)edgePtr) : + checkVertical((SkEdge*)edge, (SkEdge**)edgePtr); if (kNo_Combine == combine) { - *edgePtr++ = edge++; + *edgePtr++ = edge; + edge += edgeSize; } else if (kTotal_Combine == combine) { --edgePtr; } @@ -202,25 +305,32 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift // we ignore these, and just get the whole segment from // the corresponding line/quad/cubic verbs break; - case SkPath::kLine_Verb: - if (edge->setLine(pts[0], pts[1], shiftUp)) { - Combine combine = checkVertical(edge, edgePtr); + case SkPath::kLine_Verb: { + bool setLineResult = fAnalyticAA ? + ((SkAnalyticEdge*)edge)->setLine(pts[0], pts[1]) : + ((SkEdge*)edge)->setLine(pts[0], pts[1], shiftUp); + if (setLineResult) { + Combine combine = fAnalyticAA ? + checkVertical((SkAnalyticEdge*)edge, (SkAnalyticEdge**)edgePtr) : + checkVertical((SkEdge*)edge, (SkEdge**)edgePtr); if (kNo_Combine == combine) { - *edgePtr++ = edge++; + *edgePtr++ = edge; + edge += edgeSize; } else if (kTotal_Combine == combine) { --edgePtr; } } break; + } default: SkDEBUGFAIL("unexpected verb"); break; } } } - SkASSERT((char*)edge <= (char*)fEdgeList); - SkASSERT(edgePtr - fEdgeList <= maxEdgeCount); - return SkToInt(edgePtr - fEdgeList); + SkASSERT((size_t)(edge - edgeStart) <= maxEdgeCount * edgeSize); + SkASSERT(edgePtr - (char**)fEdgeList <= maxEdgeCount); + return SkToInt(edgePtr - (char**)fEdgeList); } static void handle_quad(SkEdgeBuilder* builder, const SkPoint pts[3]) { @@ -232,10 +342,11 @@ static void handle_quad(SkEdgeBuilder* builder, const SkPoint pts[3]) { } int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, int shiftUp, - bool canCullToTheRight) { + bool canCullToTheRight, bool analyticAA) { fAlloc.reset(); fList.reset(); fShiftUp = shiftUp; + fAnalyticAA = analyticAA; if (SkPath::kLine_SegmentMask == path.getSegmentMasks()) { return this->buildPoly(path, iclip, shiftUp, canCullToTheRight); @@ -260,14 +371,11 @@ int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, int shiftUp, // we ignore these, and just get the whole segment from // the corresponding line/quad/cubic verbs break; - case SkPath::kLine_Verb: { - SkPoint lines[SkLineClipper::kMaxPoints]; - int lineCount = SkLineClipper::ClipLine(pts, clip, lines, canCullToTheRight); - for (int i = 0; i < lineCount; i++) { - this->addLine(&lines[i]); + case SkPath::kLine_Verb: + if (clipper.clipLine(pts[0], pts[1], clip)) { + this->addClipper(&clipper); } break; - } case SkPath::kQuad_Verb: if (clipper.clipQuad(pts, clip)) { this->addClipper(&clipper); diff --git a/gfx/skia/skia/src/core/SkEdgeBuilder.h b/gfx/skia/skia/src/core/SkEdgeBuilder.h index 59f62870e747..413d87342390 100644 --- a/gfx/skia/skia/src/core/SkEdgeBuilder.h +++ b/gfx/skia/skia/src/core/SkEdgeBuilder.h @@ -7,11 +7,12 @@ #ifndef SkEdgeBuilder_DEFINED #define SkEdgeBuilder_DEFINED -#include "SkChunkAlloc.h" +#include "SkArenaAlloc.h" #include "SkRect.h" #include "SkTDArray.h" struct SkEdge; +struct SkAnalyticEdge; class SkEdgeClipper; class SkPath; @@ -21,9 +22,11 @@ public: // returns the number of built edges. The array of those edge pointers // is returned from edgeList(). - int build(const SkPath& path, const SkIRect* clip, int shiftUp, bool clipToTheRight); + int build(const SkPath& path, const SkIRect* clip, int shiftUp, bool clipToTheRight, + bool analyticAA = false); - SkEdge** edgeList() { return fEdgeList; } + SkEdge** edgeList() { return (SkEdge**)fEdgeList; } + SkAnalyticEdge** analyticEdgeList() { return (SkAnalyticEdge**)fEdgeList; } private: enum Combine { @@ -32,11 +35,15 @@ private: kTotal_Combine }; - static Combine CombineVertical(const SkEdge* edge, SkEdge* last); + Combine CombineVertical(const SkEdge* edge, SkEdge* last); + Combine CombineVertical(const SkAnalyticEdge* edge, SkAnalyticEdge* last); Combine checkVertical(const SkEdge* edge, SkEdge** edgePtr); + Combine checkVertical(const SkAnalyticEdge* edge, SkAnalyticEdge** edgePtr); + bool vertical_line(const SkEdge* edge); + bool vertical_line(const SkAnalyticEdge* edge); - SkChunkAlloc fAlloc; - SkTDArray fList; + SkArenaAlloc fAlloc; + SkTDArray fList; /* * If we're in general mode, we allcoate the pointers in fList, and this @@ -44,9 +51,10 @@ private: * empty, as we will have preallocated room for the pointers in fAlloc's * block, and fEdgeList will point into that. */ - SkEdge** fEdgeList; + void** fEdgeList; int fShiftUp; + bool fAnalyticAA; public: void addLine(const SkPoint pts[]); diff --git a/gfx/skia/skia/src/core/SkEdgeClipper.cpp b/gfx/skia/skia/src/core/SkEdgeClipper.cpp index b5ac27ae5908..2abbd1b1d430 100644 --- a/gfx/skia/skia/src/core/SkEdgeClipper.cpp +++ b/gfx/skia/skia/src/core/SkEdgeClipper.cpp @@ -8,6 +8,7 @@ #include "SkEdgeClipper.h" #include "SkGeometry.h" +#include "SkLineClipper.h" static bool quick_reject(const SkRect& bounds, const SkRect& clip) { return bounds.fTop >= clip.fBottom || bounds.fBottom <= clip.fTop; @@ -42,6 +43,23 @@ static bool sort_increasing_Y(SkPoint dst[], const SkPoint src[], int count) { } } +bool SkEdgeClipper::clipLine(SkPoint p0, SkPoint p1, const SkRect& clip) { + fCurrPoint = fPoints; + fCurrVerb = fVerbs; + + SkPoint lines[SkLineClipper::kMaxPoints]; + const SkPoint pts[] = { p0, p1 }; + int lineCount = SkLineClipper::ClipLine(pts, clip, lines, fCanCullToTheRight); + for (int i = 0; i < lineCount; i++) { + this->appendLine(lines[i], lines[i + 1]); + } + + *fCurrVerb = SkPath::kDone_Verb; + fCurrPoint = fPoints; + fCurrVerb = fVerbs; + return SkPath::kDone_Verb != fVerbs[0]; +} + /////////////////////////////////////////////////////////////////////////////// static bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2, @@ -373,28 +391,49 @@ void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) { } } -static bool quick_reject_in_y(const SkPoint pts[4], const SkRect& clip) { - Sk4s ys(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY); - Sk4s t(clip.top()); - Sk4s b(clip.bottom()); +static SkRect compute_cubic_bounds(const SkPoint pts[4]) { + SkRect r; + r.set(pts, 4); + return r; +} - return (ys < t).allTrue() || (ys > b).allTrue(); +static bool too_big_for_reliable_float_math(const SkRect& r) { + // limit set as the largest float value for which we can still reliably compute things like + // - chopping at XY extrema + // - chopping at Y or X values for clipping + // + // Current value chosen just by experiment. Larger (and still succeeds) is always better. + // + const SkScalar limit = 1 << 22; + return r.fLeft < -limit || r.fTop < -limit || r.fRight > limit || r.fBottom > limit; } bool SkEdgeClipper::clipCubic(const SkPoint srcPts[4], const SkRect& clip) { fCurrPoint = fPoints; fCurrVerb = fVerbs; - if (!quick_reject_in_y(srcPts, clip)) { - SkPoint monoY[10]; - int countY = SkChopCubicAtYExtrema(srcPts, monoY); - for (int y = 0; y <= countY; y++) { - SkPoint monoX[10]; - int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX); - for (int x = 0; x <= countX; x++) { - this->clipMonoCubic(&monoX[x * 3], clip); - SkASSERT(fCurrVerb - fVerbs < kMaxVerbs); - SkASSERT(fCurrPoint - fPoints <= kMaxPoints); + const SkRect bounds = compute_cubic_bounds(srcPts); + // check if we're clipped out vertically + if (bounds.fBottom > clip.fTop && bounds.fTop < clip.fBottom) { + if (too_big_for_reliable_float_math(bounds)) { + // can't safely clip the cubic, so we give up and draw a line (which we can safely clip) + // + // If we rewrote chopcubicat*extrema and chopmonocubic using doubles, we could very + // likely always handle the cubic safely, but (it seems) at a big loss in speed, so + // we'd only want to take that alternate impl if needed. Perhaps a TODO to try it. + // + return this->clipLine(srcPts[0], srcPts[3], clip); + } else { + SkPoint monoY[10]; + int countY = SkChopCubicAtYExtrema(srcPts, monoY); + for (int y = 0; y <= countY; y++) { + SkPoint monoX[10]; + int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX); + for (int x = 0; x <= countX; x++) { + this->clipMonoCubic(&monoX[x * 3], clip); + SkASSERT(fCurrVerb - fVerbs < kMaxVerbs); + SkASSERT(fCurrPoint - fPoints <= kMaxPoints); + } } } } @@ -407,6 +446,13 @@ bool SkEdgeClipper::clipCubic(const SkPoint srcPts[4], const SkRect& clip) { /////////////////////////////////////////////////////////////////////////////// +void SkEdgeClipper::appendLine(SkPoint p0, SkPoint p1) { + *fCurrVerb++ = SkPath::kLine_Verb; + fCurrPoint[0] = p0; + fCurrPoint[1] = p1; + fCurrPoint += 2; +} + void SkEdgeClipper::appendVLine(SkScalar x, SkScalar y0, SkScalar y1, bool reverse) { *fCurrVerb++ = SkPath::kLine_Verb; diff --git a/gfx/skia/skia/src/core/SkEdgeClipper.h b/gfx/skia/skia/src/core/SkEdgeClipper.h index e460c1cd879a..1a12c1e81a7b 100644 --- a/gfx/skia/skia/src/core/SkEdgeClipper.h +++ b/gfx/skia/skia/src/core/SkEdgeClipper.h @@ -18,6 +18,7 @@ class SkEdgeClipper { public: SkEdgeClipper(bool canCullToTheRight) : fCanCullToTheRight(canCullToTheRight) {} + bool clipLine(SkPoint p0, SkPoint p1, const SkRect& clip); bool clipQuad(const SkPoint pts[3], const SkRect& clip); bool clipCubic(const SkPoint pts[4], const SkRect& clip); @@ -31,14 +32,15 @@ private: const bool fCanCullToTheRight; enum { - kMaxVerbs = 13, - kMaxPoints = 32 + kMaxVerbs = 18, // max curvature in X and Y split cubic into 9 pieces, * (line + cubic) + kMaxPoints = 54 // 2 lines + 1 cubic require 6 points; times 9 pieces }; SkPoint fPoints[kMaxPoints]; SkPath::Verb fVerbs[kMaxVerbs]; void clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip); void clipMonoCubic(const SkPoint srcPts[4], const SkRect& clip); + void appendLine(SkPoint p0, SkPoint p1); void appendVLine(SkScalar x, SkScalar y0, SkScalar y1, bool reverse); void appendQuad(const SkPoint pts[3], bool reverse); void appendCubic(const SkPoint pts[4], bool reverse); diff --git a/gfx/skia/skia/src/core/SkEmptyShader.h b/gfx/skia/skia/src/core/SkEmptyShader.h index 528ceeabeea3..b2c9b76792da 100644 --- a/gfx/skia/skia/src/core/SkEmptyShader.h +++ b/gfx/skia/skia/src/core/SkEmptyShader.h @@ -24,13 +24,7 @@ public: SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkEmptyShader) protected: - size_t onContextSize(const ContextRec&) const override { - // Even though createContext returns nullptr we have to return a value of at least - // sizeof(SkShader::Context) to satisfy SkSmallAllocator. - return sizeof(SkShader::Context); - } - - SkShader::Context* onCreateContext(const ContextRec&, void*) const override { + SkShader::Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override { return nullptr; } diff --git a/gfx/skia/skia/src/core/SkError.cpp b/gfx/skia/skia/src/core/SkError.cpp deleted file mode 100644 index d85b5ff0cc08..000000000000 --- a/gfx/skia/skia/src/core/SkError.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTLS.h" -#include "SkTypes.h" -#include "SkError.h" -#include "SkErrorInternals.h" - -#include -#include - -namespace { -void *CreateThreadError() { return new SkError(kNoError_SkError); } -void DeleteThreadError(void *v) { delete reinterpret_cast(v); } - #define THREAD_ERROR \ - (*reinterpret_cast(SkTLS::Get(CreateThreadError, DeleteThreadError))) - - void *CreateThreadErrorCallback() { - return new SkErrorCallbackFunction(SkErrorInternals::DefaultErrorCallback); - } - void DeleteThreadErrorCallback(void* v) { - delete reinterpret_cast(v); - } - - #define THREAD_ERROR_CALLBACK \ - *(reinterpret_cast(SkTLS::Get(CreateThreadErrorCallback, \ - DeleteThreadErrorCallback))) - - void *CreateThreadErrorContext() { return new void **(nullptr); } - void DeleteThreadErrorContext(void *v) { delete reinterpret_cast(v); } - #define THREAD_ERROR_CONTEXT \ - (*reinterpret_cast(SkTLS::Get(CreateThreadErrorContext, DeleteThreadErrorContext))) - - #define ERROR_STRING_LENGTH 2048 - - void *CreateThreadErrorString() { return new char[(ERROR_STRING_LENGTH)]; } - void DeleteThreadErrorString(void *v) { delete[] reinterpret_cast(v); } - #define THREAD_ERROR_STRING \ - (reinterpret_cast(SkTLS::Get(CreateThreadErrorString, DeleteThreadErrorString))) -} - -SkError SkGetLastError() { - return SkErrorInternals::GetLastError(); -} -void SkClearLastError() { - SkErrorInternals::ClearError(); -} -void SkSetErrorCallback(SkErrorCallbackFunction cb, void *context) { - SkErrorInternals::SetErrorCallback(cb, context); -} -const char *SkGetLastErrorString() { - return SkErrorInternals::GetLastErrorString(); -} - -// ------------ Private Error functions --------- - -void SkErrorInternals::SetErrorCallback(SkErrorCallbackFunction cb, void *context) { - if (cb == nullptr) { - THREAD_ERROR_CALLBACK = SkErrorInternals::DefaultErrorCallback; - } else { - THREAD_ERROR_CALLBACK = cb; - } - THREAD_ERROR_CONTEXT = context; -} - -void SkErrorInternals::DefaultErrorCallback(SkError code, void *context) { - SkDebugf("Skia Error: %s\n", SkGetLastErrorString()); -} - -void SkErrorInternals::ClearError() { - SkErrorInternals::SetError( kNoError_SkError, "All is well" ); -} - -SkError SkErrorInternals::GetLastError() { - return THREAD_ERROR; -} - -const char *SkErrorInternals::GetLastErrorString() { - return THREAD_ERROR_STRING; -} - -void SkErrorInternals::SetError(SkError code, const char *fmt, ...) { - THREAD_ERROR = code; - va_list args; - - char *str = THREAD_ERROR_STRING; - const char *error_name = nullptr; - switch( code ) { - case kNoError_SkError: - error_name = "No Error"; - break; - case kInvalidArgument_SkError: - error_name = "Invalid Argument"; - break; - case kInvalidOperation_SkError: - error_name = "Invalid Operation"; - break; - case kInvalidHandle_SkError: - error_name = "Invalid Handle"; - break; - case kInvalidPaint_SkError: - error_name = "Invalid Paint"; - break; - case kOutOfMemory_SkError: - error_name = "Out Of Memory"; - break; - case kParseError_SkError: - error_name = "Parse Error"; - break; - default: - error_name = "Unknown error"; - break; - } - - sprintf( str, "%s: ", error_name ); - int string_left = SkToInt(ERROR_STRING_LENGTH - strlen(str)); - str += strlen(str); - - va_start( args, fmt ); - vsnprintf( str, string_left, fmt, args ); - va_end( args ); - SkErrorCallbackFunction fn = THREAD_ERROR_CALLBACK; - if (fn && code != kNoError_SkError) { - fn(code, THREAD_ERROR_CONTEXT); - } -} diff --git a/gfx/skia/skia/src/core/SkErrorInternals.h b/gfx/skia/skia/src/core/SkErrorInternals.h deleted file mode 100644 index d57357609945..000000000000 --- a/gfx/skia/skia/src/core/SkErrorInternals.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkErrorInternals_DEFINED -#define SkErrorInternals_DEFINED - -#include "SkError.h" - -class SkErrorInternals { - -public: - static void ClearError(); - static void SetError(SkError code, const char *fmt, ...); - static SkError GetLastError(); - static const char *GetLastErrorString(); - static void SetErrorCallback(SkErrorCallbackFunction cb, void *context); - static void DefaultErrorCallback(SkError code, void *context); -}; - - - -#endif /* SkErrorInternals_DEFINED */ diff --git a/gfx/skia/skia/src/core/SkExecutor.cpp b/gfx/skia/skia/src/core/SkExecutor.cpp new file mode 100644 index 000000000000..6144dfddac51 --- /dev/null +++ b/gfx/skia/skia/src/core/SkExecutor.cpp @@ -0,0 +1,124 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkExecutor.h" +#include "SkMakeUnique.h" +#include "SkMutex.h" +#include "SkSemaphore.h" +#include "SkSpinlock.h" +#include "SkTArray.h" +#include "SkThreadUtils.h" + +#if defined(_MSC_VER) + #include + static int num_cores() { + SYSTEM_INFO sysinfo; + GetNativeSystemInfo(&sysinfo); + return (int)sysinfo.dwNumberOfProcessors; + } +#else + #include + static int num_cores() { + return (int)sysconf(_SC_NPROCESSORS_ONLN); + } +#endif + +SkExecutor::~SkExecutor() {} + +// The default default SkExecutor is an SkTrivialExecutor, which just runs the work right away. +class SkTrivialExecutor final : public SkExecutor { + void add(std::function work) override { + work(); + } +}; + +static SkTrivialExecutor gTrivial; +static SkExecutor* gDefaultExecutor = &gTrivial; + +SkExecutor& SkExecutor::GetDefault() { + return *gDefaultExecutor; +} +void SkExecutor::SetDefault(SkExecutor* executor) { + gDefaultExecutor = executor ? executor : &gTrivial; +} + +// An SkThreadPool is an executor that runs work on a fixed pool of OS threads. +class SkThreadPool final : public SkExecutor { +public: + explicit SkThreadPool(int threads) { + for (int i = 0; i < threads; i++) { + fThreads.emplace_back(new SkThread(&Loop, this)); + fThreads.back()->start(); + } + } + + ~SkThreadPool() override { + // Signal each thread that it's time to shut down. + for (int i = 0; i < fThreads.count(); i++) { + this->add(nullptr); + } + // Wait for each thread to shut down. + for (int i = 0; i < fThreads.count(); i++) { + fThreads[i]->join(); + } + } + + virtual void add(std::function work) override { + // Add some work to our pile of work to do. + { + SkAutoExclusive lock(fWorkLock); + fWork.emplace_back(std::move(work)); + } + // Tell the Loop() threads to pick it up. + fWorkAvailable.signal(1); + } + + virtual void borrow() override { + // If there is work waiting, do it. + if (fWorkAvailable.try_wait()) { + SkAssertResult(this->do_work()); + } + } + +private: + // This method should be called only when fWorkAvailable indicates there's work to do. + bool do_work() { + std::function work; + { + SkAutoExclusive lock(fWorkLock); + SkASSERT(!fWork.empty()); // TODO: if (fWork.empty()) { return true; } ? + work = std::move(fWork.back()); + fWork.pop_back(); + } + + if (!work) { + return false; // This is Loop()'s signal to shut down. + } + + work(); + return true; + } + + static void Loop(void* ctx) { + auto pool = (SkThreadPool*)ctx; + do { + pool->fWorkAvailable.wait(); + } while (pool->do_work()); + } + + // Both SkMutex and SkSpinlock can work here. + using Lock = SkMutex; + + SkTArray> fThreads; + SkTArray> fWork; + Lock fWorkLock; + SkSemaphore fWorkAvailable; +}; + +std::unique_ptr SkExecutor::MakeThreadPool(int threads) { + return skstd::make_unique(threads > 0 ? threads : num_cores()); +} diff --git a/gfx/skia/skia/src/core/SkFDot6.h b/gfx/skia/skia/src/core/SkFDot6.h index 726aa2e46de6..004666115ea9 100644 --- a/gfx/skia/skia/src/core/SkFDot6.h +++ b/gfx/skia/skia/src/core/SkFDot6.h @@ -75,4 +75,39 @@ inline SkFixed SkFDot6Div(SkFDot6 a, SkFDot6 b) { } } +#include "SkFDot6Constants.h" + +class QuickFDot6Inverse { +public: + inline static SkFixed Lookup(SkFDot6 x) { + SkASSERT(SkAbs32(x) < kInverseTableSize); + return gFDot6INVERSE[kInverseTableSize + x]; + } +}; + +static inline SkFixed QuickSkFDot6Div(SkFDot6 a, SkFDot6 b) { + const int kMinBits = 3; // abs(b) should be at least (1 << kMinBits) for quick division + const int kMaxBits = 31; // Number of bits available in signed int + // Given abs(b) <= (1 << kMinBits), the inverse of abs(b) is at most 1 << (22 - kMinBits) in + // SkFixed format. Hence abs(a) should be less than kMaxAbsA + const int kMaxAbsA = 1 << (kMaxBits - (22 - kMinBits)); + SkFDot6 abs_a = SkAbs32(a); + SkFDot6 abs_b = SkAbs32(b); + if (abs_b >= (1 << kMinBits) && abs_b < kInverseTableSize && abs_a < kMaxAbsA) { + SkASSERT((int64_t)a * QuickFDot6Inverse::Lookup(b) <= SK_MaxS32 + && (int64_t)a * QuickFDot6Inverse::Lookup(b) >= SK_MinS32); + SkFixed ourAnswer = (a * QuickFDot6Inverse::Lookup(b)) >> 6; + #ifdef SK_DEBUG + SkFixed directAnswer = SkFDot6Div(a, b); + SkASSERT( + (directAnswer == 0 && ourAnswer == 0) || + SkFixedDiv(SkAbs32(directAnswer - ourAnswer), SkAbs32(directAnswer)) <= 1 << 10 + ); + #endif + return ourAnswer; + } else { + return SkFDot6Div(a, b); + } +} + #endif diff --git a/gfx/skia/skia/src/core/SkFDot6Constants.h b/gfx/skia/skia/src/core/SkFDot6Constants.h new file mode 100644 index 000000000000..945bee522dd4 --- /dev/null +++ b/gfx/skia/skia/src/core/SkFDot6Constants.h @@ -0,0 +1,199 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAAAConstants_DEFINED +#define SkAAAConstants_DEFINED + +static const int kInverseTableSize = 1024; // SK_FDot6One * 16 + +static constexpr const SkFDot6 gFDot6INVERSE[kInverseTableSize * 2] = { + -4096, -4100, -4104, -4108, -4112, -4116, -4120, -4124, -4128, -4132, -4136, + -4140, -4144, -4148, -4152, -4156, -4161, -4165, -4169, -4173, -4177, -4181, + -4185, -4190, -4194, -4198, -4202, -4206, -4211, -4215, -4219, -4223, -4228, + -4232, -4236, -4240, -4245, -4249, -4253, -4258, -4262, -4266, -4271, -4275, + -4279, -4284, -4288, -4293, -4297, -4301, -4306, -4310, -4315, -4319, -4324, + -4328, -4332, -4337, -4341, -4346, -4350, -4355, -4359, -4364, -4369, -4373, + -4378, -4382, -4387, -4391, -4396, -4401, -4405, -4410, -4415, -4419, -4424, + -4429, -4433, -4438, -4443, -4447, -4452, -4457, -4462, -4466, -4471, -4476, + -4481, -4485, -4490, -4495, -4500, -4505, -4510, -4514, -4519, -4524, -4529, + -4534, -4539, -4544, -4549, -4554, -4559, -4563, -4568, -4573, -4578, -4583, + -4588, -4593, -4599, -4604, -4609, -4614, -4619, -4624, -4629, -4634, -4639, + -4644, -4650, -4655, -4660, -4665, -4670, -4675, -4681, -4686, -4691, -4696, + -4702, -4707, -4712, -4718, -4723, -4728, -4733, -4739, -4744, -4750, -4755, + -4760, -4766, -4771, -4777, -4782, -4788, -4793, -4798, -4804, -4809, -4815, + -4821, -4826, -4832, -4837, -4843, -4848, -4854, -4860, -4865, -4871, -4877, + -4882, -4888, -4894, -4899, -4905, -4911, -4917, -4922, -4928, -4934, -4940, + -4946, -4951, -4957, -4963, -4969, -4975, -4981, -4987, -4993, -4999, -5005, + -5011, -5017, -5023, -5029, -5035, -5041, -5047, -5053, -5059, -5065, -5071, + -5077, -5084, -5090, -5096, -5102, -5108, -5115, -5121, -5127, -5133, -5140, + -5146, -5152, -5159, -5165, -5171, -5178, -5184, -5190, -5197, -5203, -5210, + -5216, -5223, -5229, -5236, -5242, -5249, -5256, -5262, -5269, -5275, -5282, + -5289, -5295, -5302, -5309, -5315, -5322, -5329, -5336, -5343, -5349, -5356, + -5363, -5370, -5377, -5384, -5391, -5398, -5405, -5412, -5418, -5426, -5433, + -5440, -5447, -5454, -5461, -5468, -5475, -5482, -5489, -5497, -5504, -5511, + -5518, -5526, -5533, -5540, -5548, -5555, -5562, -5570, -5577, -5584, -5592, + -5599, -5607, -5614, -5622, -5629, -5637, -5645, -5652, -5660, -5667, -5675, + -5683, -5691, -5698, -5706, -5714, -5722, -5729, -5737, -5745, -5753, -5761, + -5769, -5777, -5785, -5793, -5801, -5809, -5817, -5825, -5833, -5841, -5849, + -5857, -5866, -5874, -5882, -5890, -5899, -5907, -5915, -5924, -5932, -5940, + -5949, -5957, -5966, -5974, -5983, -5991, -6000, -6009, -6017, -6026, -6034, + -6043, -6052, -6061, -6069, -6078, -6087, -6096, -6105, -6114, -6123, -6132, + -6141, -6150, -6159, -6168, -6177, -6186, -6195, -6204, -6213, -6223, -6232, + -6241, -6250, -6260, -6269, -6278, -6288, -6297, -6307, -6316, -6326, -6335, + -6345, -6355, -6364, -6374, -6384, -6393, -6403, -6413, -6423, -6432, -6442, + -6452, -6462, -6472, -6482, -6492, -6502, -6512, -6523, -6533, -6543, -6553, + -6563, -6574, -6584, -6594, -6605, -6615, -6626, -6636, -6647, -6657, -6668, + -6678, -6689, -6700, -6710, -6721, -6732, -6743, -6754, -6765, -6775, -6786, + -6797, -6808, -6820, -6831, -6842, -6853, -6864, -6875, -6887, -6898, -6909, + -6921, -6932, -6944, -6955, -6967, -6978, -6990, -7002, -7013, -7025, -7037, + -7049, -7061, -7073, -7084, -7096, -7108, -7121, -7133, -7145, -7157, -7169, + -7182, -7194, -7206, -7219, -7231, -7244, -7256, -7269, -7281, -7294, -7307, + -7319, -7332, -7345, -7358, -7371, -7384, -7397, -7410, -7423, -7436, -7449, + -7463, -7476, -7489, -7503, -7516, -7530, -7543, -7557, -7570, -7584, -7598, + -7612, -7626, -7639, -7653, -7667, -7681, -7695, -7710, -7724, -7738, -7752, + -7767, -7781, -7796, -7810, -7825, -7839, -7854, -7869, -7884, -7898, -7913, + -7928, -7943, -7958, -7973, -7989, -8004, -8019, -8035, -8050, -8065, -8081, + -8097, -8112, -8128, -8144, -8160, -8176, -8192, -8208, -8224, -8240, -8256, + -8272, -8289, -8305, -8322, -8338, -8355, -8371, -8388, -8405, -8422, -8439, + -8456, -8473, -8490, -8507, -8525, -8542, -8559, -8577, -8594, -8612, -8630, + -8648, -8665, -8683, -8701, -8719, -8738, -8756, -8774, -8793, -8811, -8830, + -8848, -8867, -8886, -8905, -8924, -8943, -8962, -8981, -9000, -9020, -9039, + -9058, -9078, -9098, -9118, -9137, -9157, -9177, -9198, -9218, -9238, -9258, + -9279, -9300, -9320, -9341, -9362, -9383, -9404, -9425, -9446, -9467, -9489, + -9510, -9532, -9554, -9576, -9597, -9619, -9642, -9664, -9686, -9709, -9731, + -9754, -9776, -9799, -9822, -9845, -9868, -9892, -9915, -9939, -9962, -9986, + -10010, -10034, -10058, -10082, -10106, -10131, -10155, -10180, -10205, -10230, + -10255, -10280, -10305, -10330, -10356, -10381, -10407, -10433, -10459, -10485, + -10512, -10538, -10564, -10591, -10618, -10645, -10672, -10699, -10727, -10754, + -10782, -10810, -10837, -10866, -10894, -10922, -10951, -10979, -11008, -11037, + -11066, -11096, -11125, -11155, -11184, -11214, -11244, -11275, -11305, -11335, + -11366, -11397, -11428, -11459, -11491, -11522, -11554, -11586, -11618, -11650, + -11683, -11715, -11748, -11781, -11814, -11848, -11881, -11915, -11949, -11983, + -12018, -12052, -12087, -12122, -12157, -12192, -12228, -12264, -12300, -12336, + -12372, -12409, -12446, -12483, -12520, -12557, -12595, -12633, -12671, -12710, + -12748, -12787, -12826, -12865, -12905, -12945, -12985, -13025, -13066, -13107, + -13148, -13189, -13231, -13273, -13315, -13357, -13400, -13443, -13486, -13530, + -13573, -13617, -13662, -13706, -13751, -13797, -13842, -13888, -13934, -13981, + -14027, -14074, -14122, -14169, -14217, -14266, -14315, -14364, -14413, -14463, + -14513, -14563, -14614, -14665, -14716, -14768, -14820, -14873, -14926, -14979, + -15033, -15087, -15141, -15196, -15252, -15307, -15363, -15420, -15477, -15534, + -15592, -15650, -15709, -15768, -15827, -15887, -15947, -16008, -16070, -16131, + -16194, -16256, -16320, -16384, -16448, -16513, -16578, -16644, -16710, -16777, + -16844, -16912, -16980, -17050, -17119, -17189, -17260, -17331, -17403, -17476, + -17549, -17623, -17697, -17772, -17848, -17924, -18001, -18078, -18157, -18236, + -18315, -18396, -18477, -18558, -18641, -18724, -18808, -18893, -18978, -19065, + -19152, -19239, -19328, -19418, -19508, -19599, -19691, -19784, -19878, -19972, + -20068, -20164, -20262, -20360, -20460, -20560, -20661, -20763, -20867, -20971, + -21076, -21183, -21290, -21399, -21509, -21620, -21732, -21845, -21959, -22075, + -22192, -22310, -22429, -22550, -22671, -22795, -22919, -23045, -23172, -23301, + -23431, -23563, -23696, -23831, -23967, -24105, -24244, -24385, -24528, -24672, + -24818, -24966, -25115, -25266, -25420, -25575, -25731, -25890, -26051, -26214, + -26379, -26546, -26715, -26886, -27060, -27235, -27413, -27594, -27776, -27962, + -28149, -28339, -28532, -28728, -28926, -29127, -29330, -29537, -29746, -29959, + -30174, -30393, -30615, -30840, -31068, -31300, -31536, -31775, -32017, -32263, + -32513, -32768, -33026, -33288, -33554, -33825, -34100, -34379, -34663, -34952, + -35246, -35544, -35848, -36157, -36472, -36792, -37117, -37449, -37786, -38130, + -38479, -38836, -39199, -39568, -39945, -40329, -40721, -41120, -41527, -41943, + -42366, -42799, -43240, -43690, -44150, -44620, -45100, -45590, -46091, -46603, + -47127, -47662, -48210, -48770, -49344, -49932, -50533, -51150, -51781, -52428, + -53092, -53773, -54471, -55188, -55924, -56679, -57456, -58254, -59074, -59918, + -60787, -61680, -62601, -63550, -64527, -65536, -66576, -67650, -68759, -69905, + -71089, -72315, -73584, -74898, -76260, -77672, -79137, -80659, -82241, -83886, + -85598, -87381, -89240, -91180, -93206, -95325, -97541, -99864, -102300, + -104857, -107546, -110376, -113359, -116508, -119837, -123361, -127100, -131072, + -135300, -139810, -144631, -149796, -155344, -161319, -167772, -174762, -182361, + -190650, -199728, -209715, -220752, -233016, -246723, -262144, -279620, -299593, + -322638, -349525, -381300, -419430, -466033, -524288, -599186, -699050, -838860, + -1048576, -1398101, -2097152, -4194304, 0, 4194304, 2097152, 1398101, 1048576, + 838860, 699050, 599186, 524288, 466033, 419430, 381300, 349525, 322638, 299593, + 279620, 262144, 246723, 233016, 220752, 209715, 199728, 190650, 182361, 174762, + 167772, 161319, 155344, 149796, 144631, 139810, 135300, 131072, 127100, 123361, + 119837, 116508, 113359, 110376, 107546, 104857, 102300, 99864, 97541, 95325, + 93206, 91180, 89240, 87381, 85598, 83886, 82241, 80659, 79137, 77672, 76260, + 74898, 73584, 72315, 71089, 69905, 68759, 67650, 66576, 65536, 64527, 63550, + 62601, 61680, 60787, 59918, 59074, 58254, 57456, 56679, 55924, 55188, 54471, + 53773, 53092, 52428, 51781, 51150, 50533, 49932, 49344, 48770, 48210, 47662, + 47127, 46603, 46091, 45590, 45100, 44620, 44150, 43690, 43240, 42799, 42366, + 41943, 41527, 41120, 40721, 40329, 39945, 39568, 39199, 38836, 38479, 38130, + 37786, 37449, 37117, 36792, 36472, 36157, 35848, 35544, 35246, 34952, 34663, + 34379, 34100, 33825, 33554, 33288, 33026, 32768, 32513, 32263, 32017, 31775, + 31536, 31300, 31068, 30840, 30615, 30393, 30174, 29959, 29746, 29537, 29330, + 29127, 28926, 28728, 28532, 28339, 28149, 27962, 27776, 27594, 27413, 27235, + 27060, 26886, 26715, 26546, 26379, 26214, 26051, 25890, 25731, 25575, 25420, + 25266, 25115, 24966, 24818, 24672, 24528, 24385, 24244, 24105, 23967, 23831, + 23696, 23563, 23431, 23301, 23172, 23045, 22919, 22795, 22671, 22550, 22429, + 22310, 22192, 22075, 21959, 21845, 21732, 21620, 21509, 21399, 21290, 21183, + 21076, 20971, 20867, 20763, 20661, 20560, 20460, 20360, 20262, 20164, 20068, + 19972, 19878, 19784, 19691, 19599, 19508, 19418, 19328, 19239, 19152, 19065, + 18978, 18893, 18808, 18724, 18641, 18558, 18477, 18396, 18315, 18236, 18157, + 18078, 18001, 17924, 17848, 17772, 17697, 17623, 17549, 17476, 17403, 17331, + 17260, 17189, 17119, 17050, 16980, 16912, 16844, 16777, 16710, 16644, 16578, + 16513, 16448, 16384, 16320, 16256, 16194, 16131, 16070, 16008, 15947, 15887, + 15827, 15768, 15709, 15650, 15592, 15534, 15477, 15420, 15363, 15307, 15252, + 15196, 15141, 15087, 15033, 14979, 14926, 14873, 14820, 14768, 14716, 14665, + 14614, 14563, 14513, 14463, 14413, 14364, 14315, 14266, 14217, 14169, 14122, + 14074, 14027, 13981, 13934, 13888, 13842, 13797, 13751, 13706, 13662, 13617, + 13573, 13530, 13486, 13443, 13400, 13357, 13315, 13273, 13231, 13189, 13148, + 13107, 13066, 13025, 12985, 12945, 12905, 12865, 12826, 12787, 12748, 12710, + 12671, 12633, 12595, 12557, 12520, 12483, 12446, 12409, 12372, 12336, 12300, + 12264, 12228, 12192, 12157, 12122, 12087, 12052, 12018, 11983, 11949, 11915, + 11881, 11848, 11814, 11781, 11748, 11715, 11683, 11650, 11618, 11586, 11554, + 11522, 11491, 11459, 11428, 11397, 11366, 11335, 11305, 11275, 11244, 11214, + 11184, 11155, 11125, 11096, 11066, 11037, 11008, 10979, 10951, 10922, 10894, + 10866, 10837, 10810, 10782, 10754, 10727, 10699, 10672, 10645, 10618, 10591, + 10564, 10538, 10512, 10485, 10459, 10433, 10407, 10381, 10356, 10330, 10305, + 10280, 10255, 10230, 10205, 10180, 10155, 10131, 10106, 10082, 10058, 10034, + 10010, 9986, 9962, 9939, 9915, 9892, 9868, 9845, 9822, 9799, 9776, 9754, 9731, + 9709, 9686, 9664, 9642, 9619, 9597, 9576, 9554, 9532, 9510, 9489, 9467, 9446, + 9425, 9404, 9383, 9362, 9341, 9320, 9300, 9279, 9258, 9238, 9218, 9198, 9177, + 9157, 9137, 9118, 9098, 9078, 9058, 9039, 9020, 9000, 8981, 8962, 8943, 8924, + 8905, 8886, 8867, 8848, 8830, 8811, 8793, 8774, 8756, 8738, 8719, 8701, 8683, + 8665, 8648, 8630, 8612, 8594, 8577, 8559, 8542, 8525, 8507, 8490, 8473, 8456, + 8439, 8422, 8405, 8388, 8371, 8355, 8338, 8322, 8305, 8289, 8272, 8256, 8240, + 8224, 8208, 8192, 8176, 8160, 8144, 8128, 8112, 8097, 8081, 8065, 8050, 8035, + 8019, 8004, 7989, 7973, 7958, 7943, 7928, 7913, 7898, 7884, 7869, 7854, 7839, + 7825, 7810, 7796, 7781, 7767, 7752, 7738, 7724, 7710, 7695, 7681, 7667, 7653, + 7639, 7626, 7612, 7598, 7584, 7570, 7557, 7543, 7530, 7516, 7503, 7489, 7476, + 7463, 7449, 7436, 7423, 7410, 7397, 7384, 7371, 7358, 7345, 7332, 7319, 7307, + 7294, 7281, 7269, 7256, 7244, 7231, 7219, 7206, 7194, 7182, 7169, 7157, 7145, + 7133, 7121, 7108, 7096, 7084, 7073, 7061, 7049, 7037, 7025, 7013, 7002, 6990, + 6978, 6967, 6955, 6944, 6932, 6921, 6909, 6898, 6887, 6875, 6864, 6853, 6842, + 6831, 6820, 6808, 6797, 6786, 6775, 6765, 6754, 6743, 6732, 6721, 6710, 6700, + 6689, 6678, 6668, 6657, 6647, 6636, 6626, 6615, 6605, 6594, 6584, 6574, 6563, + 6553, 6543, 6533, 6523, 6512, 6502, 6492, 6482, 6472, 6462, 6452, 6442, 6432, + 6423, 6413, 6403, 6393, 6384, 6374, 6364, 6355, 6345, 6335, 6326, 6316, 6307, + 6297, 6288, 6278, 6269, 6260, 6250, 6241, 6232, 6223, 6213, 6204, 6195, 6186, + 6177, 6168, 6159, 6150, 6141, 6132, 6123, 6114, 6105, 6096, 6087, 6078, 6069, + 6061, 6052, 6043, 6034, 6026, 6017, 6009, 6000, 5991, 5983, 5974, 5966, 5957, + 5949, 5940, 5932, 5924, 5915, 5907, 5899, 5890, 5882, 5874, 5866, 5857, 5849, + 5841, 5833, 5825, 5817, 5809, 5801, 5793, 5785, 5777, 5769, 5761, 5753, 5745, + 5737, 5729, 5722, 5714, 5706, 5698, 5691, 5683, 5675, 5667, 5660, 5652, 5645, + 5637, 5629, 5622, 5614, 5607, 5599, 5592, 5584, 5577, 5570, 5562, 5555, 5548, + 5540, 5533, 5526, 5518, 5511, 5504, 5497, 5489, 5482, 5475, 5468, 5461, 5454, + 5447, 5440, 5433, 5426, 5418, 5412, 5405, 5398, 5391, 5384, 5377, 5370, 5363, + 5356, 5349, 5343, 5336, 5329, 5322, 5315, 5309, 5302, 5295, 5289, 5282, 5275, + 5269, 5262, 5256, 5249, 5242, 5236, 5229, 5223, 5216, 5210, 5203, 5197, 5190, + 5184, 5178, 5171, 5165, 5159, 5152, 5146, 5140, 5133, 5127, 5121, 5115, 5108, + 5102, 5096, 5090, 5084, 5077, 5071, 5065, 5059, 5053, 5047, 5041, 5035, 5029, + 5023, 5017, 5011, 5005, 4999, 4993, 4987, 4981, 4975, 4969, 4963, 4957, 4951, + 4946, 4940, 4934, 4928, 4922, 4917, 4911, 4905, 4899, 4894, 4888, 4882, 4877, + 4871, 4865, 4860, 4854, 4848, 4843, 4837, 4832, 4826, 4821, 4815, 4809, 4804, + 4798, 4793, 4788, 4782, 4777, 4771, 4766, 4760, 4755, 4750, 4744, 4739, 4733, + 4728, 4723, 4718, 4712, 4707, 4702, 4696, 4691, 4686, 4681, 4675, 4670, 4665, + 4660, 4655, 4650, 4644, 4639, 4634, 4629, 4624, 4619, 4614, 4609, 4604, 4599, + 4593, 4588, 4583, 4578, 4573, 4568, 4563, 4559, 4554, 4549, 4544, 4539, 4534, + 4529, 4524, 4519, 4514, 4510, 4505, 4500, 4495, 4490, 4485, 4481, 4476, 4471, + 4466, 4462, 4457, 4452, 4447, 4443, 4438, 4433, 4429, 4424, 4419, 4415, 4410, + 4405, 4401, 4396, 4391, 4387, 4382, 4378, 4373, 4369, 4364, 4359, 4355, 4350, + 4346, 4341, 4337, 4332, 4328, 4324, 4319, 4315, 4310, 4306, 4301, 4297, 4293, + 4288, 4284, 4279, 4275, 4271, 4266, 4262, 4258, 4253, 4249, 4245, 4240, 4236, + 4232, 4228, 4223, 4219, 4215, 4211, 4206, 4202, 4198, 4194, 4190, 4185, 4181, + 4177, 4173, 4169, 4165, 4161, 4156, 4152, 4148, 4144, 4140, 4136, 4132, 4128, + 4124, 4120, 4116, 4112, 4108, 4104, 4100 +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h b/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h index 257528cd0386..c17dccbe3e0d 100644 --- a/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h +++ b/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h @@ -436,7 +436,7 @@ private: SkPoint findAndPositionGlyph( const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) override { - SkPoint finalPosition = position; + if (kTextAlignment != SkPaint::kLeft_Align) { // Get the width of an un-sub-pixel positioned glyph for calculating the // alignment. This is not needed for kLeftAlign because its adjustment is @@ -447,26 +447,28 @@ private: if (metricGlyph.fWidth <= 0) { // Exiting early, be sure to update text pointer. *text = tempText; - return finalPosition + SkPoint{SkFloatToScalar(metricGlyph.fAdvanceX), - SkFloatToScalar(metricGlyph.fAdvanceY)}; + return position + SkPoint{SkFloatToScalar(metricGlyph.fAdvanceX), + SkFloatToScalar(metricGlyph.fAdvanceY)}; } // Adjust the final position by the alignment adjustment. - finalPosition -= TextAlignmentAdjustment(kTextAlignment, metricGlyph); + position -= TextAlignmentAdjustment(kTextAlignment, metricGlyph); } // Find the glyph. - SkIPoint lookupPosition = SubpixelAlignment(kAxisAlignment, finalPosition); + SkIPoint lookupPosition = SkScalarsAreFinite(position.fX, position.fY) + ? SubpixelAlignment(kAxisAlignment, position) + : SkIPoint{0, 0}; const SkGlyph& renderGlyph = fGlyphFinder->lookupGlyphXY(text, lookupPosition.fX, lookupPosition.fY); // If the glyph has no width (no pixels) then don't bother processing it. if (renderGlyph.fWidth > 0) { - processOneGlyph(renderGlyph, finalPosition, + processOneGlyph(renderGlyph, position, SubpixelPositionRounding(kAxisAlignment)); } - return finalPosition + SkPoint{SkFloatToScalar(renderGlyph.fAdvanceX), - SkFloatToScalar(renderGlyph.fAdvanceY)}; + return position + SkPoint{SkFloatToScalar(renderGlyph.fAdvanceX), + SkFloatToScalar(renderGlyph.fAdvanceY)}; } private: diff --git a/gfx/skia/skia/src/core/SkFixed15.h b/gfx/skia/skia/src/core/SkFixed15.h new file mode 100644 index 000000000000..509febc7c116 --- /dev/null +++ b/gfx/skia/skia/src/core/SkFixed15.h @@ -0,0 +1,77 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFixed15_DEFINED +#define SkFixed15_DEFINED + +#include "SkTypes.h" + +// SkFixed15 is a fixed point value that represents values in [0,1] as [0x0000, 0x8000]. +// This mapping allows us to implement most operations in tightly packed 16-bit SIMD, +// most notably multiplying using Q15 multiplication instructions (and a little fixup). + +class SkFixed15 { +public: + SkFixed15() = default; + + SkFixed15(float val) : fVal(val * 32768) { SkASSERT(0.0f <= val && val <= 1.0f); } + explicit operator float() const { return fVal * (1/32768.0f); } + + static SkFixed15 Load(uint16_t val) { + SkASSERT(val <= 32768); + return val; + } + uint16_t store() const { return fVal; } + + static SkFixed15 FromU8(uint8_t val) { + return val*128 + (val>>1) // 32768/255 == 128.50196..., which is very close to 128 + 0.5. + + ((val+1)>>8); // All val but 255 are correct. +1 if val == 255 to get 32768. + } + + uint8_t to_u8() const { + // FromU8() and to_u8() roundtrip all bytes. + // There is still much room to tweak this towards the ideal, a rounding scale by 255/32768. + return (fVal - (fVal>>8))>>7; + } + + SkFixed15 operator +(SkFixed15 o) const { return fVal + o.fVal; } + SkFixed15 operator -(SkFixed15 o) const { return fVal - o.fVal; } + SkFixed15 operator *(SkFixed15 o) const { return (fVal * o.fVal + (1<<14)) >> 15; } + SkFixed15 operator<<(int bits) const { return fVal << bits; } + SkFixed15 operator>>(int bits) const { return fVal >> bits; } + + SkFixed15& operator +=(SkFixed15 o) { return (*this = *this + o); } + SkFixed15& operator -=(SkFixed15 o) { return (*this = *this - o); } + SkFixed15& operator *=(SkFixed15 o) { return (*this = *this * o); } + SkFixed15& operator<<=(int bits) { return (*this = *this << bits); } + SkFixed15& operator>>=(int bits) { return (*this = *this >> bits); } + + bool operator==(SkFixed15 o) const { return fVal == o.fVal; } + bool operator!=(SkFixed15 o) const { return fVal != o.fVal; } + bool operator<=(SkFixed15 o) const { return fVal <= o.fVal; } + bool operator>=(SkFixed15 o) const { return fVal >= o.fVal; } + bool operator< (SkFixed15 o) const { return fVal < o.fVal; } + bool operator> (SkFixed15 o) const { return fVal > o.fVal; } + +private: + SkFixed15(int val) : fVal(val) {} + + uint16_t fVal; +}; + +// Notes +// - SSSE3+ multiply is _mm_abs_epi16(_mm_mulhrs_epi16(x, y)); +// - NEON multipy is vsraq_n_u16(vabsq_s16(vqrdmulhq_s16(x,y)), +// vandq_s16(x,y), 15); +// - Conversion to and from float can be done manually with bit masks and float add/subtract, +// rather than the naive version here involving int<->float conversion and float multiply. +// - On x86, conversion to float is _mm_sub_ps(_mm_unpacklo_epi16(x, _mm_set1_epi16(0x4380)), +// _mm_set1_ps(256.0f)). // 0x43800000 +// - On ARM, we can use the vcvtq_n_f32_u32(vmovl_u16(x), 15) to convert to float, +// and vcvtq_n_u32_f32(..., 15) for the other way around. + +#endif//SkFixed15_DEFINED diff --git a/gfx/skia/skia/src/core/SkFlattenableSerialization.cpp b/gfx/skia/skia/src/core/SkFlattenableSerialization.cpp index 704526673da9..e72b4c534892 100644 --- a/gfx/skia/skia/src/core/SkFlattenableSerialization.cpp +++ b/gfx/skia/skia/src/core/SkFlattenableSerialization.cpp @@ -25,3 +25,8 @@ SkFlattenable* SkValidatingDeserializeFlattenable(const void* data, size_t size, SkValidatingReadBuffer buffer(data, size); return buffer.readFlattenable(type); } + +sk_sp SkValidatingDeserializeImageFilter(const void* data, size_t size) { + return sk_sp((SkImageFilter*)SkValidatingDeserializeFlattenable( + data, size, SkImageFilter::GetFlattenableType())); +} diff --git a/gfx/skia/skia/src/core/SkFontMgr.cpp b/gfx/skia/skia/src/core/SkFontMgr.cpp index 57f82b03ba28..8ce0b39682f2 100644 --- a/gfx/skia/skia/src/core/SkFontMgr.cpp +++ b/gfx/skia/skia/src/core/SkFontMgr.cpp @@ -132,11 +132,11 @@ SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, int ttcIndex) con return this->onCreateFromStream(stream, ttcIndex); } -SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, const FontParameters& params) const { +SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, const SkFontArguments& args) const { if (nullptr == stream) { return nullptr; } - return this->onCreateFromStream(stream, params); + return this->onCreateFromStream(stream, args); } SkTypeface* SkFontMgr::createFromFontData(std::unique_ptr data) const { @@ -147,8 +147,8 @@ SkTypeface* SkFontMgr::createFromFontData(std::unique_ptr data) cons } // This implementation is temporary until it can be made pure virtual. -SkTypeface* SkFontMgr::onCreateFromStream(SkStreamAsset* stream, const FontParameters& p) const { - return this->createFromStream(stream, p.getCollectionIndex()); +SkTypeface* SkFontMgr::onCreateFromStream(SkStreamAsset* stream, const SkFontArguments& args) const{ + return this->createFromStream(stream, args.getCollectionIndex()); } // This implementation is temporary until it can be made pure virtual. @@ -167,15 +167,15 @@ SkTypeface* SkFontMgr::legacyCreateTypeface(const char familyName[], SkFontStyle return this->onLegacyCreateTypeface(familyName, style); } -SkFontMgr* SkFontMgr::RefDefault() { +sk_sp SkFontMgr::RefDefault() { static SkOnce once; - static SkFontMgr* singleton; + static sk_sp singleton; once([]{ - SkFontMgr* fm = SkFontMgr::Factory(); - singleton = fm ? fm : new SkEmptyFontMgr; + sk_sp fm = SkFontMgr::Factory(); + singleton = fm ? std::move(fm) : sk_make_sp(); }); - return SkRef(singleton); + return singleton; } /** diff --git a/gfx/skia/skia/src/core/SkFontStream.cpp b/gfx/skia/skia/src/core/SkFontStream.cpp index b2ffe8deba4a..e9f23f9f247e 100644 --- a/gfx/skia/skia/src/core/SkFontStream.cpp +++ b/gfx/skia/skia/src/core/SkFontStream.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkAutoMalloc.h" #include "SkEndian.h" #include "SkFontStream.h" #include "SkStream.h" diff --git a/gfx/skia/skia/src/core/SkGeometry.cpp b/gfx/skia/skia/src/core/SkGeometry.cpp index 58b45140e226..2817f2a61c73 100644 --- a/gfx/skia/skia/src/core/SkGeometry.cpp +++ b/gfx/skia/skia/src/core/SkGeometry.cpp @@ -15,12 +15,6 @@ static SkVector to_vector(const Sk2s& x) { return vector; } -/** If defined, this makes eval_quad and eval_cubic do more setup (sometimes - involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul. - May also introduce overflow of fixed when we compute our setup. -*/ -// #define DIRECT_EVAL_OF_POLYNOMIALS - //////////////////////////////////////////////////////////////////////// static int is_not_monotonic(SkScalar a, SkScalar b, SkScalar c) { @@ -289,33 +283,6 @@ void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4]) { ///// CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS ///// ////////////////////////////////////////////////////////////////////////////// -#ifdef SK_SUPPORT_LEGACY_EVAL_CUBIC -static SkScalar eval_cubic(const SkScalar src[], SkScalar t) { - SkASSERT(src); - SkASSERT(t >= 0 && t <= SK_Scalar1); - - if (t == 0) { - return src[0]; - } - -#ifdef DIRECT_EVAL_OF_POLYNOMIALS - SkScalar D = src[0]; - SkScalar A = src[6] + 3*(src[2] - src[4]) - D; - SkScalar B = 3*(src[4] - src[2] - src[2] + D); - SkScalar C = 3*(src[2] - D); - - return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); -#else - SkScalar ab = SkScalarInterp(src[0], src[2], t); - SkScalar bc = SkScalarInterp(src[2], src[4], t); - SkScalar cd = SkScalarInterp(src[4], src[6], t); - SkScalar abc = SkScalarInterp(ab, bc, t); - SkScalar bcd = SkScalarInterp(bc, cd, t); - return SkScalarInterp(abc, bcd, t); -#endif -} -#endif - static SkVector eval_cubic_derivative(const SkPoint src[4], SkScalar t) { SkQuadCoeff coeff; Sk2s P0 = from_point(src[0]); @@ -346,11 +313,7 @@ void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc, SkASSERT(t >= 0 && t <= SK_Scalar1); if (loc) { -#ifdef SK_SUPPORT_LEGACY_EVAL_CUBIC - loc->set(eval_cubic(&src[0].fX, t), eval_cubic(&src[0].fY, t)); -#else *loc = to_point(SkCubicCoeff(src).eval(t)); -#endif } if (tangent) { // The derivative equation returns a zero tangent vector when t is 0 or 1, and the @@ -587,8 +550,9 @@ static SkCubicType classify_cubic(const SkPoint p[4], const SkScalar d[3]) { } else if (discr < -SK_ScalarNearlyZero) { return kLoop_SkCubicType; } else { - if (0.f == d[0] && 0.f == d[1]) { - return (0.f == d[2] ? kLine_SkCubicType : kQuadratic_SkCubicType); + if (SkScalarAbs(d[0]) < SK_ScalarNearlyZero && SkScalarAbs(d[1]) < SK_ScalarNearlyZero) { + return ((SkScalarAbs(d[2]) < SK_ScalarNearlyZero) ? kLine_SkCubicType + : kQuadratic_SkCubicType); } else { return kCusp_SkCubicType; } diff --git a/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp b/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp index 21c4d16c4af7..298357eb78c7 100644 --- a/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp +++ b/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp @@ -19,7 +19,6 @@ #include "SkPathEffect.h" #include "SkPictureShader.h" #include "SkRecordedDrawable.h" -#include "SkXfermode.h" /* * Registers all of the required effects subclasses for picture deserialization. @@ -37,18 +36,13 @@ void SkFlattenable::PrivateInitializer::InitCore() { SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLocalMatrixShader) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPictureShader) - // PathEffect - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposePathEffect) // ImageFilter SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMatrixImageFilter) - // ColorFilter SkColorFilter::InitializeFlattenables(); - + SkPathEffect::InitializeFlattenables(); SkShader::InitializeFlattenables(); - - // Xfermode SkXfermode::InitializeFlattenables(); // Drawable diff --git a/gfx/skia/skia/src/core/SkGlyph.h b/gfx/skia/skia/src/core/SkGlyph.h index 04f9296b556a..06c1d76fb3e3 100644 --- a/gfx/skia/skia/src/core/SkGlyph.h +++ b/gfx/skia/skia/src/core/SkGlyph.h @@ -8,10 +8,12 @@ #ifndef SkGlyph_DEFINED #define SkGlyph_DEFINED +#include "SkArenaAlloc.h" #include "SkChecksum.h" -#include "SkTypes.h" #include "SkFixed.h" #include "SkMask.h" +#include "SkTypes.h" + class SkPath; class SkGlyphCache; @@ -22,8 +24,9 @@ class SkGlyphCache; #define kMaxGlyphWidth (1<<13) -SK_BEGIN_REQUIRE_DENSE -class SkGlyph { +/** (glyph-index or unicode-point) + subpixel-pos */ +struct SkPackedID { + static constexpr uint32_t kImpossibleID = ~0; enum { kSubBits = 2, kSubMask = ((1 << kSubBits) - 1), @@ -34,84 +37,34 @@ class SkGlyph { kSubShiftY = 0 }; - // Support horizontal and vertical skipping strike-through / underlines. - // The caller walks the linked list looking for a match. For a horizontal underline, - // the fBounds contains the top and bottom of the underline. The fInterval pair contains the - // beginning and end of of the intersection of the bounds and the glyph's path. - // If interval[0] >= interval[1], no intesection was found. - struct Intercept { - Intercept* fNext; - SkScalar fBounds[2]; // for horz underlines, the boundaries in Y - SkScalar fInterval[2]; // the outside intersections of the axis and the glyph - }; - - struct PathData { - Intercept* fIntercept; - SkPath* fPath; - }; - -public: - static const SkFixed kSubpixelRound = SK_FixedHalf >> SkGlyph::kSubBits; - // A value that can never be generated by MakeID. - static const uint32_t kImpossibleID = ~0; - void* fImage; - PathData* fPathData; - float fAdvanceX, fAdvanceY; - - uint16_t fWidth, fHeight; - int16_t fTop, fLeft; - - uint8_t fMaskFormat; - int8_t fRsbDelta, fLsbDelta; // used by auto-kerning - int8_t fForceBW; - - void initWithGlyphID(uint32_t glyph_id) { - this->initCommon(MakeID(glyph_id)); + SkPackedID(uint32_t code) { + SkASSERT(code <= kCodeMask); + SkASSERT(code != kImpossibleID); + fID = code; } - void initGlyphIdFrom(const SkGlyph& glyph) { - this->initCommon(glyph.fID); + SkPackedID(uint32_t code, SkFixed x, SkFixed y) { + SkASSERT(code <= kCodeMask); + x = FixedToSub(x); + y = FixedToSub(y); + uint32_t ID = (x << (kSubShift + kSubShiftX)) | + (y << (kSubShift + kSubShiftY)) | + code; + SkASSERT(ID != kImpossibleID); + fID = ID; } - void initGlyphFromCombinedID(uint32_t combined_id) { - this->initCommon(combined_id); + constexpr SkPackedID() : fID(kImpossibleID) {} + + bool operator==(const SkPackedID& that) const { + return fID == that.fID; + } + bool operator!=(const SkPackedID& that) const { + return !(*this == that); } - /** - * Compute the rowbytes for the specified width and mask-format. - */ - static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) { - unsigned rb = width; - if (SkMask::kBW_Format == format) { - rb = (rb + 7) >> 3; - } else if (SkMask::kARGB32_Format == format) { - rb <<= 2; - } else if (SkMask::kLCD16_Format == format) { - rb = SkAlign4(rb << 1); - } else { - rb = SkAlign4(rb); - } - return rb; - } - - unsigned rowBytes() const { - return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat); - } - - bool isJustAdvance() const { - return MASK_FORMAT_JUST_ADVANCE == fMaskFormat; - } - - bool isFullMetrics() const { - return MASK_FORMAT_JUST_ADVANCE != fMaskFormat; - } - - uint16_t getGlyphID() const { - return ID2Code(fID); - } - - unsigned getSubX() const { - return ID2SubX(fID); + uint32_t code() const { + return fID & kCodeMask; } SkFixed getSubXFixed() const { @@ -122,42 +75,17 @@ public: return SubToFixed(ID2SubY(fID)); } - size_t computeImageSize() const; - - /** Call this to set all of the metrics fields to 0 (e.g. if the scaler - encounters an error measuring a glyph). Note: this does not alter the - fImage, fPath, fID, fMaskFormat fields. - */ - void zeroMetrics(); - - void toMask(SkMask* mask) const; - - class HashTraits { - public: - static uint32_t GetKey(const SkGlyph& glyph) { - return glyph.fID; - } - static uint32_t Hash(uint32_t glyphId) { - return SkChecksum::CheapMix(glyphId); - } - }; - - private: - // TODO(herb) remove friend statement after SkGlyphCache cleanup. - friend class SkGlyphCache; - - void initCommon(uint32_t id) { - fID = id; - fImage = nullptr; - fPathData = nullptr; - fMaskFormat = MASK_FORMAT_UNKNOWN; - fForceBW = 0; + uint32_t hash() const { + return SkChecksum::CheapMix(fID); } - static unsigned ID2Code(uint32_t id) { - return id & kCodeMask; - } +// FIXME - This is needed because the Android framework directly accesses fID. +// Remove when fID accesses are cleaned up. +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + operator uint32_t() const { return fID; } +#endif +private: static unsigned ID2SubX(uint32_t id) { return id >> (kSubShift + kSubShiftX); } @@ -175,29 +103,165 @@ public: return sub << (16 - kSubBits); } - static uint32_t MakeID(unsigned code) { - SkASSERT(code <= kCodeMask); - SkASSERT(code != kImpossibleID); - return code; + uint32_t fID; +}; + +struct SkPackedGlyphID : public SkPackedID { + SkPackedGlyphID(SkGlyphID code) : SkPackedID(code) { } + SkPackedGlyphID(SkGlyphID code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { } + SkPackedGlyphID() : SkPackedID() { } + SkGlyphID code() const { + return SkTo(SkPackedID::code()); + } +}; + +struct SkPackedUnicharID : public SkPackedID { + SkPackedUnicharID(SkUnichar code) : SkPackedID(code) { } + SkPackedUnicharID(SkUnichar code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { } + SkPackedUnicharID() : SkPackedID() { } + SkUnichar code() const { + return SkTo(SkPackedID::code()); + } +}; + +SK_BEGIN_REQUIRE_DENSE +class SkGlyph { + // Support horizontal and vertical skipping strike-through / underlines. + // The caller walks the linked list looking for a match. For a horizontal underline, + // the fBounds contains the top and bottom of the underline. The fInterval pair contains the + // beginning and end of of the intersection of the bounds and the glyph's path. + // If interval[0] >= interval[1], no intesection was found. + struct Intercept { + Intercept* fNext; + SkScalar fBounds[2]; // for horz underlines, the boundaries in Y + SkScalar fInterval[2]; // the outside intersections of the axis and the glyph + }; + + struct PathData { + Intercept* fIntercept; + SkPath* fPath; + }; + +public: + static const SkFixed kSubpixelRound = SK_FixedHalf >> SkPackedID::kSubBits; + void* fImage; + PathData* fPathData; + float fAdvanceX, fAdvanceY; + + uint16_t fWidth, fHeight; + int16_t fTop, fLeft; + + uint8_t fMaskFormat; + int8_t fRsbDelta, fLsbDelta; // used by auto-kerning + int8_t fForceBW; + + void initWithGlyphID(SkPackedGlyphID glyph_id) { + fID = glyph_id; + fImage = nullptr; + fPathData = nullptr; + fMaskFormat = MASK_FORMAT_UNKNOWN; + fForceBW = 0; } - static uint32_t MakeID(unsigned code, SkFixed x, SkFixed y) { - SkASSERT(code <= kCodeMask); - x = FixedToSub(x); - y = FixedToSub(y); - uint32_t ID = (x << (kSubShift + kSubShiftX)) | - (y << (kSubShift + kSubShiftY)) | - code; - SkASSERT(ID != kImpossibleID); - return ID; + static size_t BitsToBytes(size_t bits) { + return (bits + 7) >> 3; } - // FIXME - This is needed because the Android frame work directly - // accesses fID. Remove when fID accesses are cleaned up. + /** + * Compute the rowbytes for the specified width and mask-format. + */ + static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) { + unsigned rb = width; + if (SkMask::kBW_Format == format) { + rb = BitsToBytes(rb); + } else if (SkMask::kARGB32_Format == format) { + rb <<= 2; + } else if (SkMask::kLCD16_Format == format) { + rb = SkAlign4(rb << 1); + } else { + rb = SkAlign4(rb); + } + return rb; + } + + size_t allocImage(SkArenaAlloc* alloc) { + size_t allocSize; + if (SkMask::kBW_Format == fMaskFormat) { + allocSize = BitsToBytes(fWidth) * fHeight; + fImage = alloc->makeArrayDefault(allocSize); + } else if (SkMask::kARGB32_Format == fMaskFormat) { + allocSize = fWidth * fHeight; + fImage = alloc->makeArrayDefault(fWidth * fHeight); + allocSize *= sizeof(uint32_t); + } else if (SkMask::kLCD16_Format == fMaskFormat) { + allocSize = SkAlign2(fWidth) * fHeight; + fImage = alloc->makeArrayDefault(allocSize); + allocSize *= sizeof(uint16_t); + } else { + allocSize = SkAlign4(fWidth) * fHeight; + fImage = alloc->makeArrayDefault(allocSize); + } + return allocSize; + } + + unsigned rowBytes() const { + return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat); + } + + bool isJustAdvance() const { + return MASK_FORMAT_JUST_ADVANCE == fMaskFormat; + } + + bool isFullMetrics() const { + return MASK_FORMAT_JUST_ADVANCE != fMaskFormat; + } + + SkGlyphID getGlyphID() const { + return fID.code(); + } + + SkPackedGlyphID getPackedID() const { + return fID; + } + + SkFixed getSubXFixed() const { + return fID.getSubXFixed(); + } + + SkFixed getSubYFixed() const { + return fID.getSubYFixed(); + } + + size_t computeImageSize() const; + + /** Call this to set all of the metrics fields to 0 (e.g. if the scaler + encounters an error measuring a glyph). Note: this does not alter the + fImage, fPath, fID, fMaskFormat fields. + */ + void zeroMetrics(); + + void toMask(SkMask* mask) const; + + class HashTraits { + public: + static SkPackedGlyphID GetKey(const SkGlyph& glyph) { + return glyph.fID; + } + static uint32_t Hash(SkPackedGlyphID glyphId) { + return glyphId.hash(); + } + }; + + private: + // TODO(herb) remove friend statement after SkGlyphCache cleanup. + friend class SkGlyphCache; + +// FIXME - This is needed because the Android frame work directly accesses fID. +// Remove when fID accesses are cleaned up. #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK public: #endif - uint32_t fID; + SkPackedGlyphID fID; }; SK_END_REQUIRE_DENSE diff --git a/gfx/skia/skia/src/core/SkGlyphCache.cpp b/gfx/skia/skia/src/core/SkGlyphCache.cpp index a8eaa667a58a..d5efc0e67244 100644 --- a/gfx/skia/skia/src/core/SkGlyphCache.cpp +++ b/gfx/skia/skia/src/core/SkGlyphCache.cpp @@ -33,51 +33,33 @@ static SkGlyphCache_Globals& get_globals() { /////////////////////////////////////////////////////////////////////////////// -// so we don't grow our arrays a lot -#define kMinGlyphCount 16 -#define kMinGlyphImageSize (16*2) -#define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphCount) - -SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkScalerContext* ctx) +SkGlyphCache::SkGlyphCache(const SkDescriptor* desc, std::unique_ptr ctx) : fDesc(desc->copy()) - , fScalerContext(ctx) - , fGlyphAlloc(kMinAllocAmount) { - SkASSERT(typeface); + , fScalerContext(std::move(ctx)) { SkASSERT(desc); - SkASSERT(ctx); + SkASSERT(fScalerContext); fPrev = fNext = nullptr; fScalerContext->getFontMetrics(&fFontMetrics); fMemoryUsed = sizeof(*this); - - fAuxProcList = nullptr; } SkGlyphCache::~SkGlyphCache() { - fGlyphMap.foreach ([](SkGlyph* g) { + fGlyphMap.foreach([](SkGlyph* g) { if (g->fPathData) { delete g->fPathData->fPath; - } } ); - SkDescriptor::Free(fDesc); - delete fScalerContext; - this->invokeAndRemoveAuxProcs(); + } + }); } -SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(PackedUnicharID packedUnicharID) { - if (nullptr == fPackedUnicharIDToPackedGlyphID.get()) { - // Allocate the array. - fPackedUnicharIDToPackedGlyphID.reset(kHashCount); - // Initialize array to map character and position with the impossible glyph ID. This - // represents no mapping. - for (int i = 0; i getCharGlyphRec(packedUnicharID); if (rec->fPackedUnicharID == packedUnicharID) { // The glyph exists in the unichar to glyph mapping cache. Return it. - return SkGlyph::ID2Code(rec->fPackedGlyphID); + return rec->fPackedGlyphID.code(); } else { // The glyph is not in the unichar to glyph mapping cache. Insert it. rec->fPackedUnicharID = packedUnicharID; - uint16_t glyphID = fScalerContext->charToGlyphID(charCode); - rec->fPackedGlyphID = SkGlyph::MakeID(glyphID); + SkGlyphID glyphID = fScalerContext->charToGlyphID(charCode); + rec->fPackedGlyphID = SkPackedGlyphID(glyphID); return glyphID; } } -SkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) { +SkUnichar SkGlyphCache::glyphToUnichar(SkGlyphID glyphID) { return fScalerContext->glyphIDToChar(glyphID); } @@ -126,7 +108,7 @@ const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) { const SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) { VALIDATE(); - PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID); + SkPackedGlyphID packedGlyphID(glyphID); return *this->lookupByPackedGlyphID(packedGlyphID, kJustAdvance_MetricsType); } @@ -144,32 +126,27 @@ const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode, SkFixed x, Sk const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) { VALIDATE(); - PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID); + SkPackedGlyphID packedGlyphID(glyphID); return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType); } const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFixed y) { VALIDATE(); - PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID, x, y); + SkPackedGlyphID packedGlyphID(glyphID, x, y); return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType); } SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, MetricsType type, SkFixed x, SkFixed y) { - PackedUnicharID id = SkGlyph::MakeID(charCode, x, y); + SkPackedUnicharID id(charCode, x, y); CharGlyphRec* rec = this->getCharGlyphRec(id); if (rec->fPackedUnicharID != id) { - // this ID is based on the UniChar rec->fPackedUnicharID = id; - // this ID is based on the glyph index - PackedGlyphID combinedID = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode), x, y); - rec->fPackedGlyphID = combinedID; - return this->lookupByPackedGlyphID(combinedID, type); - } else { - return this->lookupByPackedGlyphID(rec->fPackedGlyphID, type); + rec->fPackedGlyphID = SkPackedGlyphID(fScalerContext->charToGlyphID(charCode), x, y); } + return this->lookupByPackedGlyphID(rec->fPackedGlyphID, type); } -SkGlyph* SkGlyphCache::lookupByPackedGlyphID(PackedGlyphID packedGlyphID, MetricsType type) { +SkGlyph* SkGlyphCache::lookupByPackedGlyphID(SkPackedGlyphID packedGlyphID, MetricsType type) { SkGlyph* glyph = fGlyphMap.find(packedGlyphID); if (nullptr == glyph) { @@ -182,13 +159,13 @@ SkGlyph* SkGlyphCache::lookupByPackedGlyphID(PackedGlyphID packedGlyphID, Metric return glyph; } -SkGlyph* SkGlyphCache::allocateNewGlyph(PackedGlyphID packedGlyphID, MetricsType mtype) { +SkGlyph* SkGlyphCache::allocateNewGlyph(SkPackedGlyphID packedGlyphID, MetricsType mtype) { fMemoryUsed += sizeof(SkGlyph); SkGlyph* glyphPtr; { SkGlyph glyph; - glyph.initGlyphFromCombinedID(packedGlyphID); + glyph.initWithGlyphID(packedGlyphID); glyphPtr = fGlyphMap.set(glyph); } @@ -199,16 +176,14 @@ SkGlyph* SkGlyphCache::allocateNewGlyph(PackedGlyphID packedGlyphID, MetricsType fScalerContext->getMetrics(glyphPtr); } - SkASSERT(glyphPtr->fID != SkGlyph::kImpossibleID); + SkASSERT(glyphPtr->fID != SkPackedGlyphID()); return glyphPtr; } const void* SkGlyphCache::findImage(const SkGlyph& glyph) { if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) { if (nullptr == glyph.fImage) { - size_t size = glyph.computeImageSize(); - const_cast(glyph).fImage = fGlyphAlloc.alloc(size, - SkChunkAlloc::kReturnNil_AllocFailType); + size_t size = const_cast(glyph).allocImage(&fAlloc); // check that alloc() actually succeeded if (glyph.fImage) { fScalerContext->getImage(glyph); @@ -226,12 +201,11 @@ const void* SkGlyphCache::findImage(const SkGlyph& glyph) { const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) { if (glyph.fWidth) { if (glyph.fPathData == nullptr) { - SkGlyph::PathData* pathData = - (SkGlyph::PathData* ) fGlyphAlloc.allocThrow(sizeof(SkGlyph::PathData)); + SkGlyph::PathData* pathData = fAlloc.make(); const_cast(glyph).fPathData = pathData; pathData->fIntercept = nullptr; SkPath* path = pathData->fPath = new SkPath; - fScalerContext->getPath(glyph, path); + fScalerContext->getPath(glyph.getPackedID(), path); fMemoryUsed += sizeof(SkPath) + path->countPoints() * sizeof(SkPoint); } } @@ -295,7 +269,7 @@ void SkGlyphCache::AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis, } } -void SkGlyphCache::AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis, +void SkGlyphCache::AddQuad(const SkPoint pts[3], SkScalar axis, bool yAxis, SkGlyph::Intercept* intercept) { SkDQuad quad; quad.set(pts); @@ -308,7 +282,7 @@ void SkGlyphCache::AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis, } } -void SkGlyphCache::AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis, +void SkGlyphCache::AddCubic(const SkPoint pts[4], SkScalar axis, bool yAxis, SkGlyph::Intercept* intercept) { SkDCubic cubic; cubic.set(pts); @@ -347,8 +321,7 @@ void SkGlyphCache::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkSc return; } - SkGlyph::Intercept* intercept = - (SkGlyph::Intercept* ) fGlyphAlloc.allocThrow(sizeof(SkGlyph::Intercept)); + SkGlyph::Intercept* intercept = fAlloc.make(); intercept->fNext = glyph->fPathData->fIntercept; intercept->fBounds[0] = bounds[0]; intercept->fBounds[1] = bounds[1]; @@ -425,53 +398,6 @@ void SkGlyphCache::dump() const { SkDebugf("%s\n", msg.c_str()); } -/////////////////////////////////////////////////////////////////////////////// - -bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const { - const AuxProcRec* rec = fAuxProcList; - while (rec) { - if (rec->fProc == proc) { - if (dataPtr) { - *dataPtr = rec->fData; - } - return true; - } - rec = rec->fNext; - } - return false; -} - -void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) { - if (proc == nullptr) { - return; - } - - AuxProcRec* rec = fAuxProcList; - while (rec) { - if (rec->fProc == proc) { - rec->fData = data; - return; - } - rec = rec->fNext; - } - // not found, create a new rec - rec = new AuxProcRec; - rec->fProc = proc; - rec->fData = data; - rec->fNext = fAuxProcList; - fAuxProcList = rec; -} - -void SkGlyphCache::invokeAndRemoveAuxProcs() { - AuxProcRec* rec = fAuxProcList; - while (rec) { - rec->fProc(rec->fData); - AuxProcRec* next = rec->fNext; - delete rec; - rec = next; - } -} - /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -579,13 +505,13 @@ SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, { // pass true the first time, to notice if the scalercontext failed, // so we can try the purge. - SkScalerContext* ctx = typeface->createScalerContext(effects, desc, true); + std::unique_ptr ctx = typeface->createScalerContext(effects, desc, true); if (!ctx) { get_globals().purgeAll(); ctx = typeface->createScalerContext(effects, desc, false); SkASSERT(ctx); } - cache = new SkGlyphCache(typeface, desc, ctx); + cache = new SkGlyphCache(desc, std::move(ctx)); } AutoValidate av(cache); diff --git a/gfx/skia/skia/src/core/SkGlyphCache.h b/gfx/skia/skia/src/core/SkGlyphCache.h index 84a32eb3ef0b..8908949cef45 100644 --- a/gfx/skia/skia/src/core/SkGlyphCache.h +++ b/gfx/skia/skia/src/core/SkGlyphCache.h @@ -7,8 +7,8 @@ #ifndef SkGlyphCache_DEFINED #define SkGlyphCache_DEFINED +#include "SkArenaAlloc.h" #include "SkBitmap.h" -#include "SkChunkAlloc.h" #include "SkDescriptor.h" #include "SkGlyph.h" #include "SkPaint.h" @@ -16,6 +16,7 @@ #include "SkScalerContext.h" #include "SkTemplates.h" #include "SkTDArray.h" +#include class SkTraceMemoryDump; @@ -38,7 +39,7 @@ public: getGlyphIDMetrics instead. */ const SkGlyph& getUnicharAdvance(SkUnichar); - const SkGlyph& getGlyphIDAdvance(uint16_t); + const SkGlyph& getGlyphIDAdvance(SkGlyphID); /** Returns a glyph with all fields valid except fImage and fPath, which may be null. If they are null, call findImage or findPath for those. If they are not null, then they are valid. @@ -47,7 +48,7 @@ public: fAdvance/fDevKern fields, call those instead. */ const SkGlyph& getUnicharMetrics(SkUnichar); - const SkGlyph& getGlyphIDMetrics(uint16_t); + const SkGlyph& getGlyphIDMetrics(SkGlyphID); /** These are variants that take the device position of the glyph. Call these only if you are drawing in subpixel mode. Passing 0, 0 is effectively the same as calling the variants @@ -59,11 +60,11 @@ public: /** Return the glyphID for the specified Unichar. If the char has already been seen, use the existing cache entry. If not, ask the scalercontext to compute it for us. */ - uint16_t unicharToGlyph(SkUnichar); + SkGlyphID unicharToGlyph(SkUnichar); /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to a character code of zero. */ - SkUnichar glyphToUnichar(uint16_t); + SkUnichar glyphToUnichar(SkGlyphID); /** Returns the number of glyphs for this strike. */ @@ -109,21 +110,7 @@ public: void dump() const; - /** AuxProc/Data allow a client to associate data with this cache entry. Multiple clients can - use this, as their data is keyed with a function pointer. In addition to serving as a - key, the function pointer is called with the data when the glyphcache object is deleted, - so the client can cleanup their data as well. - NOTE: the auxProc must not try to access this glyphcache in any way, since it may be in - the process of being deleted. - */ - - //! If the proc is found, return true and set *dataPtr to its data - bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const; - - //! Add a proc/data pair to the glyphcache. proc should be non-null - void setAuxProc(void (*auxProc)(void*), void* auxData); - - SkScalerContext* getScalerContext() const { return fScalerContext; } + SkScalerContext* getScalerContext() const { return fScalerContext.get(); } /** Find a matching cache entry, and call proc() with it. If none is found create a new one. If the proc() returns true, detach the cache and return it, otherwise leave it and return @@ -200,42 +187,30 @@ private: kHashMask = kHashCount - 1 }; - typedef uint32_t PackedGlyphID; // glyph-index + subpixel-pos - typedef uint32_t PackedUnicharID; // unichar + subpixel-pos - struct CharGlyphRec { - PackedUnicharID fPackedUnicharID; - PackedGlyphID fPackedGlyphID; + SkPackedUnicharID fPackedUnicharID; + SkPackedGlyphID fPackedGlyphID; }; - struct AuxProcRec { - AuxProcRec* fNext; - void (*fProc)(void*); - void* fData; - }; - - // SkGlyphCache takes ownership of the scalercontext. - SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); + SkGlyphCache(const SkDescriptor*, std::unique_ptr); ~SkGlyphCache(); // Return the SkGlyph* associated with MakeID. The id parameter is the // combined glyph/x/y id generated by MakeID. If it is just a glyph id // then x and y are assumed to be zero. - SkGlyph* lookupByPackedGlyphID(PackedGlyphID packedGlyphID, MetricsType type); + SkGlyph* lookupByPackedGlyphID(SkPackedGlyphID packedGlyphID, MetricsType type); // Return a SkGlyph* associated with unicode id and position x and y. SkGlyph* lookupByChar(SkUnichar id, MetricsType type, SkFixed x = 0, SkFixed y = 0); // Return a new SkGlyph for the glyph ID and subpixel position id. Limit the amount // of work using type. - SkGlyph* allocateNewGlyph(PackedGlyphID packedGlyphID, MetricsType type); + SkGlyph* allocateNewGlyph(SkPackedGlyphID packedGlyphID, MetricsType type); static bool DetachProc(const SkGlyphCache*, void*) { return true; } // The id arg is a combined id generated by MakeID. - CharGlyphRec* getCharGlyphRec(PackedUnicharID id); - - void invokeAndRemoveAuxProcs(); + CharGlyphRec* getCharGlyphRec(SkPackedUnicharID id); static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale, SkScalar xPos, SkScalar* array, int* count); @@ -253,21 +228,24 @@ private: SkGlyphCache* fNext; SkGlyphCache* fPrev; - SkDescriptor* const fDesc; - SkScalerContext* const fScalerContext; + const std::unique_ptr fDesc; + const std::unique_ptr fScalerContext; SkPaint::FontMetrics fFontMetrics; // Map from a combined GlyphID and sub-pixel position to a SkGlyph. - SkTHashTable fGlyphMap; + SkTHashTable fGlyphMap; - SkChunkAlloc fGlyphAlloc; + // so we don't grow our arrays a lot + static constexpr size_t kMinGlyphCount = 8; + static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */; + static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount; - SkAutoTArray fPackedUnicharIDToPackedGlyphID; + SkArenaAlloc fAlloc {kMinAllocAmount}; + + std::unique_ptr fPackedUnicharIDToPackedGlyphID; // used to track (approx) how much ram is tied-up in this cache - size_t fMemoryUsed; - - AuxProcRec* fAuxProcList; + size_t fMemoryUsed; }; class SkAutoGlyphCache : public std::unique_ptr { diff --git a/gfx/skia/skia/src/core/SkGpuBlurUtils.cpp b/gfx/skia/skia/src/core/SkGpuBlurUtils.cpp index ec3b0a99091a..e832c879a12b 100644 --- a/gfx/skia/skia/src/core/SkGpuBlurUtils.cpp +++ b/gfx/skia/skia/src/core/SkGpuBlurUtils.cpp @@ -10,20 +10,21 @@ #include "SkRect.h" #if SK_SUPPORT_GPU -#include "effects/GrConvolutionEffect.h" -#include "effects/GrMatrixConvolutionEffect.h" -#include "GrContext.h" #include "GrCaps.h" -#include "GrDrawContext.h" +#include "GrContext.h" #include "GrFixedClip.h" +#include "GrRenderTargetContext.h" +#include "GrRenderTargetContextPriv.h" +#include "effects/GrGaussianConvolutionFragmentProcessor.h" +#include "effects/GrMatrixConvolutionEffect.h" #define MAX_BLUR_SIGMA 4.0f static void scale_irect_roundout(SkIRect* rect, float xScale, float yScale) { - rect->fLeft = SkScalarFloorToInt(SkScalarMul(rect->fLeft, xScale)); - rect->fTop = SkScalarFloorToInt(SkScalarMul(rect->fTop, yScale)); - rect->fRight = SkScalarCeilToInt(SkScalarMul(rect->fRight, xScale)); - rect->fBottom = SkScalarCeilToInt(SkScalarMul(rect->fBottom, yScale)); + rect->fLeft = SkScalarFloorToInt(rect->fLeft * xScale); + rect->fTop = SkScalarFloorToInt(rect->fTop * yScale); + rect->fRight = SkScalarCeilToInt(rect->fRight * xScale); + rect->fBottom = SkScalarCeilToInt(rect->fBottom * yScale); } static void scale_irect(SkIRect* rect, int xScale, int yScale) { @@ -61,37 +62,40 @@ static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int } } *radius = static_cast(ceilf(sigma * 3.0f)); - SkASSERT(*radius <= GrConvolutionEffect::kMaxKernelRadius); + SkASSERT(*radius <= GrGaussianConvolutionFragmentProcessor::kMaxKernelRadius); return sigma; } -static void convolve_gaussian_1d(GrDrawContext* drawContext, +static void convolve_gaussian_1d(GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkIRect& dstRect, const SkIPoint& srcOffset, - GrTexture* texture, + sk_sp proxy, Gr1DKernelEffect::Direction direction, int radius, float sigma, bool useBounds, - float bounds[2]) { + int bounds[2]) { GrPaint paint; - paint.setGammaCorrect(drawContext->isGammaCorrect()); - sk_sp conv(GrConvolutionEffect::MakeGaussian( - texture, direction, radius, sigma, useBounds, bounds)); + paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); + + GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider(); + + sk_sp conv(GrGaussianConvolutionFragmentProcessor::Make( + resourceProvider, std::move(proxy), direction, radius, sigma, useBounds, bounds)); paint.addColorFragmentProcessor(std::move(conv)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()), -SkIntToScalar(srcOffset.y())); - drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), - SkRect::Make(dstRect), localMatrix); + renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstRect), localMatrix); } -static void convolve_gaussian_2d(GrDrawContext* drawContext, +static void convolve_gaussian_2d(GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkIRect& dstRect, const SkIPoint& srcOffset, - GrTexture* texture, + sk_sp proxy, int radiusX, int radiusY, SkScalar sigmaX, @@ -102,41 +106,43 @@ static void convolve_gaussian_2d(GrDrawContext* drawContext, SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); GrPaint paint; - paint.setGammaCorrect(drawContext->isGammaCorrect()); + paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); SkIRect bounds = srcBounds ? *srcBounds : SkIRect::EmptyIRect(); + GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider(); + sk_sp conv(GrMatrixConvolutionEffect::MakeGaussian( - texture, bounds, size, 1.0, 0.0, kernelOffset, + resourceProvider, std::move(proxy), bounds, size, 1.0, 0.0, kernelOffset, srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode, true, sigmaX, sigmaY)); paint.addColorFragmentProcessor(std::move(conv)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), - SkRect::Make(dstRect), localMatrix); + renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstRect), localMatrix); } -static void convolve_gaussian(GrDrawContext* drawContext, +static void convolve_gaussian(GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkIRect& srcRect, - GrTexture* texture, + sk_sp proxy, Gr1DKernelEffect::Direction direction, int radius, float sigma, const SkIRect* srcBounds, const SkIPoint& srcOffset) { - float bounds[2] = { 0.0f, 1.0f }; + int bounds[2] = { 0, 0 }; SkIRect dstRect = SkIRect::MakeWH(srcRect.width(), srcRect.height()); if (!srcBounds) { - convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, - direction, radius, sigma, false, bounds); + convolve_gaussian_1d(renderTargetContext, clip, dstRect, srcOffset, + std::move(proxy), direction, radius, sigma, false, bounds); return; } SkIRect midRect = *srcBounds, leftRect, rightRect; midRect.offset(srcOffset); SkIRect topRect, bottomRect; if (direction == Gr1DKernelEffect::kX_Direction) { - bounds[0] = SkIntToFloat(srcBounds->left()) / texture->width(); - bounds[1] = SkIntToFloat(srcBounds->right()) / texture->width(); + bounds[0] = srcBounds->left(); + bounds[1] = srcBounds->right(); topRect = SkIRect::MakeLTRB(0, 0, dstRect.right(), midRect.top()); bottomRect = SkIRect::MakeLTRB(0, midRect.bottom(), dstRect.right(), dstRect.bottom()); midRect.inset(radius, 0); @@ -146,8 +152,8 @@ static void convolve_gaussian(GrDrawContext* drawContext, dstRect.fTop = midRect.top(); dstRect.fBottom = midRect.bottom(); } else { - bounds[0] = SkIntToFloat(srcBounds->top()) / texture->height(); - bounds[1] = SkIntToFloat(srcBounds->bottom()) / texture->height(); + bounds[0] = srcBounds->top(); + bounds[1] = srcBounds->bottom(); topRect = SkIRect::MakeLTRB(0, 0, midRect.left(), dstRect.bottom()); bottomRect = SkIRect::MakeLTRB(midRect.right(), 0, dstRect.right(), dstRect.bottom()); midRect.inset(0, radius); @@ -158,38 +164,49 @@ static void convolve_gaussian(GrDrawContext* drawContext, dstRect.fRight = midRect.right(); } if (!topRect.isEmpty()) { - drawContext->clear(&topRect, 0, false); + renderTargetContext->clear(&topRect, 0, false); } if (!bottomRect.isEmpty()) { - drawContext->clear(&bottomRect, 0, false); + renderTargetContext->clear(&bottomRect, 0, false); } if (midRect.isEmpty()) { // Blur radius covers srcBounds; use bounds over entire draw - convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, - direction, radius, sigma, true, bounds); + convolve_gaussian_1d(renderTargetContext, clip, dstRect, srcOffset, + std::move(proxy), direction, radius, sigma, true, bounds); } else { // Draw right and left margins with bounds; middle without. - convolve_gaussian_1d(drawContext, clip, leftRect, srcOffset, texture, - direction, radius, sigma, true, bounds); - convolve_gaussian_1d(drawContext, clip, rightRect, srcOffset, texture, - direction, radius, sigma, true, bounds); - convolve_gaussian_1d(drawContext, clip, midRect, srcOffset, texture, - direction, radius, sigma, false, bounds); + convolve_gaussian_1d(renderTargetContext, clip, leftRect, srcOffset, + proxy, direction, radius, sigma, true, bounds); + convolve_gaussian_1d(renderTargetContext, clip, rightRect, srcOffset, + proxy, direction, radius, sigma, true, bounds); + convolve_gaussian_1d(renderTargetContext, clip, midRect, srcOffset, + std::move(proxy), direction, radius, sigma, false, bounds); } } namespace SkGpuBlurUtils { -sk_sp GaussianBlur(GrContext* context, - GrTexture* origSrc, - sk_sp colorSpace, - const SkIRect& dstBounds, - const SkIRect* srcBounds, - float sigmaX, - float sigmaY, - SkBackingFit fit) { +sk_sp GaussianBlur(GrContext* context, + sk_sp srcProxy, + sk_sp colorSpace, + const SkIRect& dstBounds, + const SkIRect* srcBounds, + float sigmaX, + float sigmaY, + SkBackingFit fit) { SkASSERT(context); + + { + // Chrome is crashing with proxies when they need to be instantiated. + // Force an instantiation here (where, in olden days, we used to require a GrTexture) + // to see if the input is already un-instantiable. + GrTexture* temp = srcProxy->instantiate(context->resourceProvider()); + if (!temp) { + return nullptr; + } + } + SkIRect clearRect; int scaleFactorX, radiusX; int scaleFactorY, radiusY; @@ -216,23 +233,18 @@ sk_sp GaussianBlur(GrContext* context, // setup new clip GrFixedClip clip(localDstBounds); - sk_sp srcTexture(sk_ref_sp(origSrc)); + const GrPixelConfig config = srcProxy->config(); - SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() || - kRGBA_8888_GrPixelConfig == srcTexture->config() || - kSRGBA_8888_GrPixelConfig == srcTexture->config() || - kSBGRA_8888_GrPixelConfig == srcTexture->config() || - kRGBA_half_GrPixelConfig == srcTexture->config() || - kAlpha_8_GrPixelConfig == srcTexture->config()); + SkASSERT(kBGRA_8888_GrPixelConfig == config || kRGBA_8888_GrPixelConfig == config || + kSRGBA_8888_GrPixelConfig == config || kSBGRA_8888_GrPixelConfig == config || + kRGBA_half_GrPixelConfig == config || kAlpha_8_GrPixelConfig == config); const int width = dstBounds.width(); const int height = dstBounds.height(); - const GrPixelConfig config = srcTexture->config(); - sk_sp dstDrawContext(context->makeDrawContext(fit, - width, height, config, colorSpace, - 0, kDefault_GrSurfaceOrigin)); - if (!dstDrawContext) { + sk_sp dstRenderTargetContext(context->makeDeferredRenderTargetContext( + fit, width, height, config, colorSpace, 0, kBottomLeft_GrSurfaceOrigin)); + if (!dstRenderTargetContext) { return nullptr; } @@ -243,58 +255,59 @@ sk_sp GaussianBlur(GrContext* context, // We shouldn't be scaling because this is a small size blur SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY)); - convolve_gaussian_2d(dstDrawContext.get(), clip, localDstBounds, srcOffset, - srcTexture.get(), radiusX, radiusY, sigmaX, sigmaY, srcBounds); + convolve_gaussian_2d(dstRenderTargetContext.get(), clip, localDstBounds, srcOffset, + std::move(srcProxy), radiusX, radiusY, sigmaX, sigmaY, srcBounds); - return dstDrawContext; + return dstRenderTargetContext; } - sk_sp tmpDrawContext(context->makeDrawContext(fit, - width, height, config, colorSpace, - 0, kDefault_GrSurfaceOrigin)); - if (!tmpDrawContext) { + sk_sp tmpRenderTargetContext(context->makeDeferredRenderTargetContext( + fit, width, height, config, colorSpace, 0, kBottomLeft_GrSurfaceOrigin)); + if (!tmpRenderTargetContext) { return nullptr; } - sk_sp srcDrawContext; + sk_sp srcRenderTargetContext; SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY)); for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { GrPaint paint; - paint.setGammaCorrect(dstDrawContext->isGammaCorrect()); - SkMatrix matrix; - matrix.setIDiv(srcTexture->width(), srcTexture->height()); + paint.setGammaCorrect(dstRenderTargetContext->isGammaCorrect()); SkIRect dstRect(srcRect); if (srcBounds && i == 1) { - SkRect domain; - matrix.mapRect(&domain, SkRect::Make(*srcBounds)); - domain.inset((i < scaleFactorX) ? SK_ScalarHalf / srcTexture->width() : 0.0f, - (i < scaleFactorY) ? SK_ScalarHalf / srcTexture->height() : 0.0f); + SkRect domain = SkRect::Make(*srcBounds); + domain.inset((i < scaleFactorX) ? SK_ScalarHalf : 0.0f, + (i < scaleFactorY) ? SK_ScalarHalf : 0.0f); sk_sp fp(GrTextureDomainEffect::Make( - srcTexture.get(), + context->resourceProvider(), + std::move(srcProxy), nullptr, - matrix, + SkMatrix::I(), domain, GrTextureDomain::kDecal_Mode, - GrTextureParams::kBilerp_FilterMode)); + GrSamplerParams::kBilerp_FilterMode)); paint.addColorFragmentProcessor(std::move(fp)); srcRect.offset(-srcOffset); srcOffset.set(0, 0); } else { - GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); - paint.addColorTextureProcessor(srcTexture.get(), nullptr, matrix, params); + GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode); + paint.addColorTextureProcessor(context->resourceProvider(), std::move(srcProxy), + nullptr, SkMatrix::I(), params); } paint.setPorterDuffXPFactory(SkBlendMode::kSrc); shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY); - dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), - SkRect::Make(dstRect), SkRect::Make(srcRect)); + dstRenderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstRect), SkRect::Make(srcRect)); - srcDrawContext = dstDrawContext; + srcRenderTargetContext = dstRenderTargetContext; srcRect = dstRect; - srcTexture = srcDrawContext->asTexture(); - dstDrawContext.swap(tmpDrawContext); + srcProxy = srcRenderTargetContext->asTextureProxyRef(); + if (!srcProxy) { + return nullptr; + } + dstRenderTargetContext.swap(tmpRenderTargetContext); localSrcBounds = srcRect; } @@ -302,79 +315,86 @@ sk_sp GaussianBlur(GrContext* context, scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); if (sigmaX > 0.0f) { if (scaleFactorX > 1) { - SkASSERT(srcDrawContext); + SkASSERT(srcRenderTargetContext); // Clear out a radius to the right of the srcRect to prevent the // X convolution from reading garbage. clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, radiusX, srcRect.height()); - srcDrawContext->clear(&clearRect, 0x0, false); + srcRenderTargetContext->priv().absClear(&clearRect, 0x0); } - convolve_gaussian(dstDrawContext.get(), clip, srcRect, - srcTexture.get(), Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, + convolve_gaussian(dstRenderTargetContext.get(), clip, srcRect, + std::move(srcProxy), Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, srcBounds, srcOffset); - srcDrawContext = dstDrawContext; - srcTexture = srcDrawContext->asTexture(); + srcRenderTargetContext = dstRenderTargetContext; + srcProxy = srcRenderTargetContext->asTextureProxyRef(); + if (!srcProxy) { + return nullptr; + } srcRect.offsetTo(0, 0); - dstDrawContext.swap(tmpDrawContext); + dstRenderTargetContext.swap(tmpRenderTargetContext); localSrcBounds = srcRect; srcOffset.set(0, 0); } if (sigmaY > 0.0f) { if (scaleFactorY > 1 || sigmaX > 0.0f) { - SkASSERT(srcDrawContext); + SkASSERT(srcRenderTargetContext); // Clear out a radius below the srcRect to prevent the Y // convolution from reading garbage. clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, srcRect.width(), radiusY); - srcDrawContext->clear(&clearRect, 0x0, false); + srcRenderTargetContext->priv().absClear(&clearRect, 0x0); } - convolve_gaussian(dstDrawContext.get(), clip, srcRect, - srcTexture.get(), Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, + convolve_gaussian(dstRenderTargetContext.get(), clip, srcRect, + std::move(srcProxy), Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, srcBounds, srcOffset); - srcDrawContext = dstDrawContext; + srcRenderTargetContext = dstRenderTargetContext; srcRect.offsetTo(0, 0); - dstDrawContext.swap(tmpDrawContext); + dstRenderTargetContext.swap(tmpRenderTargetContext); } - SkASSERT(srcDrawContext); - srcTexture = nullptr; // we don't use this from here on out + SkASSERT(srcRenderTargetContext); + srcProxy.reset(nullptr); // we don't use this from here on out if (scaleFactorX > 1 || scaleFactorY > 1) { // Clear one pixel to the right and below, to accommodate bilinear upsampling. + // TODO: it seems like we should actually be clamping here rather than darkening + // the bottom right edges. clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1); - srcDrawContext->clear(&clearRect, 0x0, false); + srcRenderTargetContext->priv().absClear(&clearRect, 0x0); clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, 1, srcRect.height()); - srcDrawContext->clear(&clearRect, 0x0, false); - - SkMatrix matrix; - matrix.setIDiv(srcDrawContext->width(), srcDrawContext->height()); + srcRenderTargetContext->priv().absClear(&clearRect, 0x0); GrPaint paint; - paint.setGammaCorrect(dstDrawContext->isGammaCorrect()); + paint.setGammaCorrect(dstRenderTargetContext->isGammaCorrect()); // FIXME: this should be mitchell, not bilinear. - GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); - sk_sp tex(srcDrawContext->asTexture()); - paint.addColorTextureProcessor(tex.get(), nullptr, matrix, params); + GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode); + sk_sp proxy(srcRenderTargetContext->asTextureProxyRef()); + if (!proxy) { + return nullptr; + } + + paint.addColorTextureProcessor(context->resourceProvider(), std::move(proxy), + nullptr, SkMatrix::I(), params); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); SkIRect dstRect(srcRect); scale_irect(&dstRect, scaleFactorX, scaleFactorY); - dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), - SkRect::Make(dstRect), SkRect::Make(srcRect)); + dstRenderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstRect), SkRect::Make(srcRect)); - srcDrawContext = dstDrawContext; + srcRenderTargetContext = dstRenderTargetContext; srcRect = dstRect; - dstDrawContext.swap(tmpDrawContext); + dstRenderTargetContext.swap(tmpRenderTargetContext); } - return srcDrawContext; + return srcRenderTargetContext; } } diff --git a/gfx/skia/skia/src/core/SkGpuBlurUtils.h b/gfx/skia/skia/src/core/SkGpuBlurUtils.h index a12a08873c3a..c6c56b61f7a5 100644 --- a/gfx/skia/skia/src/core/SkGpuBlurUtils.h +++ b/gfx/skia/skia/src/core/SkGpuBlurUtils.h @@ -9,7 +9,7 @@ #define SkGpuBlurUtils_DEFINED #if SK_SUPPORT_GPU -#include "GrDrawContext.h" +#include "GrRenderTargetContext.h" class GrContext; class GrTexture; @@ -19,27 +19,28 @@ struct SkRect; namespace SkGpuBlurUtils { /** * Applies a 2D Gaussian blur to a given texture. The blurred result is returned - * as a drawContext in case the caller wishes to future draw into the result. + * as a renderTargetContext in case the caller wishes to future draw into the result. * Note: one of sigmaX and sigmaY should be non-zero! * @param context The GPU context - * @param srcTexture The source texture to be blurred. - * @param colorSpace Color space of the source (used for the drawContext result, too). + * @param src The source to be blurred. + * @param colorSpace Color space of the source (used for the renderTargetContext result, + * too). * @param dstBounds The destination bounds, relative to the source texture. * @param srcBounds The source bounds, relative to the source texture. If non-null, * no pixels will be sampled outside of this rectangle. * @param sigmaX The blur's standard deviation in X. * @param sigmaY The blur's standard deviation in Y. - * @param fit backing fit for the returned draw context - * @return The drawContext containing the blurred result. + * @param fit backing fit for the returned render target context + * @return The renderTargetContext containing the blurred result. */ - sk_sp GaussianBlur(GrContext* context, - GrTexture* srcTexture, - sk_sp colorSpace, - const SkIRect& dstBounds, - const SkIRect* srcBounds, - float sigmaX, - float sigmaY, - SkBackingFit fit = SkBackingFit::kApprox); + sk_sp GaussianBlur(GrContext* context, + sk_sp src, + sk_sp colorSpace, + const SkIRect& dstBounds, + const SkIRect* srcBounds, + float sigmaX, + float sigmaY, + SkBackingFit fit = SkBackingFit::kApprox); }; #endif diff --git a/gfx/skia/skia/src/core/SkGraphics.cpp b/gfx/skia/skia/src/core/SkGraphics.cpp index 01b1432ef034..803b7435bb6b 100644 --- a/gfx/skia/skia/src/core/SkGraphics.cpp +++ b/gfx/skia/skia/src/core/SkGraphics.cpp @@ -28,7 +28,6 @@ #include "SkTSearch.h" #include "SkTime.h" #include "SkUtils.h" -#include "SkXfermode.h" #include diff --git a/gfx/skia/skia/src/core/SkICC.cpp b/gfx/skia/skia/src/core/SkICC.cpp new file mode 100644 index 000000000000..40a733f87238 --- /dev/null +++ b/gfx/skia/skia/src/core/SkICC.cpp @@ -0,0 +1,356 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkAutoMalloc.h" +#include "SkColorSpace_Base.h" +#include "SkColorSpace_XYZ.h" +#include "SkColorSpacePriv.h" +#include "SkColorSpaceXformPriv.h" +#include "SkEndian.h" +#include "SkFixed.h" +#include "SkICC.h" +#include "SkICCPriv.h" + +SkICC::SkICC(sk_sp colorSpace) + : fColorSpace(std::move(colorSpace)) +{} + +sk_sp SkICC::Make(const void* ptr, size_t len) { + sk_sp colorSpace = SkColorSpace::MakeICC(ptr, len); + if (!colorSpace) { + return nullptr; + } + + return sk_sp(new SkICC(std::move(colorSpace))); +} + +bool SkICC::toXYZD50(SkMatrix44* toXYZD50) const { + const SkMatrix44* m = as_CSB(fColorSpace)->toXYZD50(); + if (!m) { + return false; + } + + *toXYZD50 = *m; + return true; +} + +bool SkICC::isNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const { + return as_CSB(fColorSpace)->onIsNumericalTransferFn(coeffs); +} + +static const int kDefaultTableSize = 512; // Arbitrary + +void fn_to_table(float* tablePtr, const SkColorSpaceTransferFn& fn) { + // Y = (aX + b)^g + e for X >= d + // Y = cX + f otherwise + for (int i = 0; i < kDefaultTableSize; i++) { + float x = ((float) i) / ((float) (kDefaultTableSize - 1)); + if (x >= fn.fD) { + tablePtr[i] = clamp_0_1(powf(fn.fA * x + fn.fB, fn.fG) + fn.fE); + } else { + tablePtr[i] = clamp_0_1(fn.fC * x + fn.fF); + } + } +} + +void copy_to_table(float* tablePtr, const SkGammas* gammas, int index) { + SkASSERT(gammas->isTable(index)); + const float* ptr = gammas->table(index); + const size_t bytes = gammas->tableSize(index) * sizeof(float); + memcpy(tablePtr, ptr, bytes); +} + +bool SkICC::rawTransferFnData(Tables* tables) const { + if (SkColorSpace_Base::Type::kA2B == as_CSB(fColorSpace)->type()) { + return false; + } + SkColorSpace_XYZ* colorSpace = (SkColorSpace_XYZ*) fColorSpace.get(); + + SkColorSpaceTransferFn fn; + if (this->isNumericalTransferFn(&fn)) { + tables->fStorage = SkData::MakeUninitialized(kDefaultTableSize * sizeof(float)); + fn_to_table((float*) tables->fStorage->writable_data(), fn); + tables->fRed.fOffset = tables->fGreen.fOffset = tables->fBlue.fOffset = 0; + tables->fRed.fCount = tables->fGreen.fCount = tables->fBlue.fCount = kDefaultTableSize; + return true; + } + + const SkGammas* gammas = colorSpace->gammas(); + SkASSERT(gammas); + if (gammas->data(0) == gammas->data(1) && gammas->data(0) == gammas->data(2)) { + SkASSERT(gammas->isTable(0)); + tables->fStorage = SkData::MakeUninitialized(gammas->tableSize(0) * sizeof(float)); + copy_to_table((float*) tables->fStorage->writable_data(), gammas, 0); + tables->fRed.fOffset = tables->fGreen.fOffset = tables->fBlue.fOffset = 0; + tables->fRed.fCount = tables->fGreen.fCount = tables->fBlue.fCount = gammas->tableSize(0); + return true; + } + + // Determine the storage size. + size_t storageSize = 0; + for (int i = 0; i < 3; i++) { + if (gammas->isTable(i)) { + storageSize += gammas->tableSize(i) * sizeof(float); + } else { + storageSize += kDefaultTableSize * sizeof(float); + } + } + + // Fill in the tables. + tables->fStorage = SkData::MakeUninitialized(storageSize); + float* ptr = (float*) tables->fStorage->writable_data(); + size_t offset = 0; + Channel rgb[3]; + for (int i = 0; i < 3; i++) { + if (gammas->isTable(i)) { + copy_to_table(ptr, gammas, i); + rgb[i].fOffset = offset; + rgb[i].fCount = gammas->tableSize(i); + offset += rgb[i].fCount * sizeof(float); + ptr += rgb[i].fCount; + continue; + } + + if (gammas->isNamed(i)) { + SkAssertResult(named_to_parametric(&fn, gammas->data(i).fNamed)); + } else if (gammas->isValue(i)) { + value_to_parametric(&fn, gammas->data(i).fValue); + } else { + SkASSERT(gammas->isParametric(i)); + fn = gammas->params(i); + } + + fn_to_table(ptr, fn); + rgb[i].fOffset = offset; + rgb[i].fCount = kDefaultTableSize; + offset += kDefaultTableSize * sizeof(float); + ptr += kDefaultTableSize; + } + + tables->fRed = rgb[0]; + tables->fGreen = rgb[1]; + tables->fBlue = rgb[2]; + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// Google Skia (UTF-16) +static constexpr uint8_t kDescriptionTagBody[] = { + 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, + 0x53, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x61, 0x00, 0x20, + }; +static_assert(SkIsAlign4(sizeof(kDescriptionTagBody)), "Description must be aligned to 4-bytes."); +static constexpr uint32_t kDescriptionTagHeader[7] { + SkEndian_SwapBE32(kTAG_TextType), // Type signature + 0, // Reserved + SkEndian_SwapBE32(1), // Number of records + SkEndian_SwapBE32(12), // Record size (must be 12) + SkEndian_SwapBE32(SkSetFourByteTag('e', 'n', 'U', 'S')), // English USA + SkEndian_SwapBE32(sizeof(kDescriptionTagBody)), // Length of string + SkEndian_SwapBE32(28), // Offset of string +}; + +static constexpr uint32_t kWhitePointTag[5] { + SkEndian_SwapBE32(kXYZ_PCSSpace), + 0, + SkEndian_SwapBE32(0x0000f6d6), // X = 0.96420 (D50) + SkEndian_SwapBE32(0x00010000), // Y = 1.00000 (D50) + SkEndian_SwapBE32(0x0000d32d), // Z = 0.82491 (D50) +}; + +// Google Inc. 2016 (UTF-16) +static constexpr uint8_t kCopyrightTagBody[] = { + 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, + 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, + 0x00, 0x36, +}; +static_assert(SkIsAlign4(sizeof(kCopyrightTagBody)), "Copyright must be aligned to 4-bytes."); +static constexpr uint32_t kCopyrightTagHeader[7] { + SkEndian_SwapBE32(kTAG_TextType), // Type signature + 0, // Reserved + SkEndian_SwapBE32(1), // Number of records + SkEndian_SwapBE32(12), // Record size (must be 12) + SkEndian_SwapBE32(SkSetFourByteTag('e', 'n', 'U', 'S')), // English USA + SkEndian_SwapBE32(sizeof(kCopyrightTagBody)), // Length of string + SkEndian_SwapBE32(28), // Offset of string +}; + +// We will write a profile with the minimum nine required tags. +static constexpr uint32_t kICCNumEntries = 9; + +static constexpr uint32_t kTAG_desc = SkSetFourByteTag('d', 'e', 's', 'c'); +static constexpr uint32_t kTAG_desc_Bytes = sizeof(kDescriptionTagHeader) + + sizeof(kDescriptionTagBody); +static constexpr uint32_t kTAG_desc_Offset = kICCHeaderSize + + kICCNumEntries * kICCTagTableEntrySize; + +static constexpr uint32_t kTAG_XYZ_Bytes = 20; +static constexpr uint32_t kTAG_rXYZ_Offset = kTAG_desc_Offset + kTAG_desc_Bytes; +static constexpr uint32_t kTAG_gXYZ_Offset = kTAG_rXYZ_Offset + kTAG_XYZ_Bytes; +static constexpr uint32_t kTAG_bXYZ_Offset = kTAG_gXYZ_Offset + kTAG_XYZ_Bytes; + +static constexpr uint32_t kTAG_TRC_Bytes = 40; +static constexpr uint32_t kTAG_rTRC_Offset = kTAG_bXYZ_Offset + kTAG_XYZ_Bytes; +static constexpr uint32_t kTAG_gTRC_Offset = kTAG_rTRC_Offset; +static constexpr uint32_t kTAG_bTRC_Offset = kTAG_rTRC_Offset; + +static constexpr uint32_t kTAG_wtpt = SkSetFourByteTag('w', 't', 'p', 't'); +static constexpr uint32_t kTAG_wtpt_Offset = kTAG_bTRC_Offset + kTAG_TRC_Bytes; + +static constexpr uint32_t kTAG_cprt = SkSetFourByteTag('c', 'p', 'r', 't'); +static constexpr uint32_t kTAG_cprt_Bytes = sizeof(kCopyrightTagHeader) + + sizeof(kCopyrightTagBody); +static constexpr uint32_t kTAG_cprt_Offset = kTAG_wtpt_Offset + kTAG_XYZ_Bytes; + +static constexpr uint32_t kICCProfileSize = kTAG_cprt_Offset + kTAG_cprt_Bytes; + +static constexpr uint32_t kICCHeader[kICCHeaderSize / 4] { + SkEndian_SwapBE32(kICCProfileSize), // Size of the profile + 0, // Preferred CMM type (ignored) + SkEndian_SwapBE32(0x02100000), // Version 2.1 + SkEndian_SwapBE32(kDisplay_Profile), // Display device profile + SkEndian_SwapBE32(kRGB_ColorSpace), // RGB input color space + SkEndian_SwapBE32(kXYZ_PCSSpace), // XYZ profile connection space + 0, 0, 0, // Date and time (ignored) + SkEndian_SwapBE32(kACSP_Signature), // Profile signature + 0, // Platform target (ignored) + 0x00000000, // Flags: not embedded, can be used independently + 0, // Device manufacturer (ignored) + 0, // Device model (ignored) + 0, 0, // Device attributes (ignored) + SkEndian_SwapBE32(1), // Relative colorimetric rendering intent + SkEndian_SwapBE32(0x0000f6d6), // D50 standard illuminant (X) + SkEndian_SwapBE32(0x00010000), // D50 standard illuminant (Y) + SkEndian_SwapBE32(0x0000d32d), // D50 standard illuminant (Z) + 0, // Profile creator (ignored) + 0, 0, 0, 0, // Profile id checksum (ignored) + 0, 0, 0, 0, 0, 0, 0, // Reserved (ignored) + SkEndian_SwapBE32(kICCNumEntries), // Number of tags +}; + +static constexpr uint32_t kICCTagTable[3 * kICCNumEntries] { + // Profile description + SkEndian_SwapBE32(kTAG_desc), + SkEndian_SwapBE32(kTAG_desc_Offset), + SkEndian_SwapBE32(kTAG_desc_Bytes), + + // rXYZ + SkEndian_SwapBE32(kTAG_rXYZ), + SkEndian_SwapBE32(kTAG_rXYZ_Offset), + SkEndian_SwapBE32(kTAG_XYZ_Bytes), + + // gXYZ + SkEndian_SwapBE32(kTAG_gXYZ), + SkEndian_SwapBE32(kTAG_gXYZ_Offset), + SkEndian_SwapBE32(kTAG_XYZ_Bytes), + + // bXYZ + SkEndian_SwapBE32(kTAG_bXYZ), + SkEndian_SwapBE32(kTAG_bXYZ_Offset), + SkEndian_SwapBE32(kTAG_XYZ_Bytes), + + // rTRC + SkEndian_SwapBE32(kTAG_rTRC), + SkEndian_SwapBE32(kTAG_rTRC_Offset), + SkEndian_SwapBE32(kTAG_TRC_Bytes), + + // gTRC + SkEndian_SwapBE32(kTAG_gTRC), + SkEndian_SwapBE32(kTAG_gTRC_Offset), + SkEndian_SwapBE32(kTAG_TRC_Bytes), + + // bTRC + SkEndian_SwapBE32(kTAG_bTRC), + SkEndian_SwapBE32(kTAG_bTRC_Offset), + SkEndian_SwapBE32(kTAG_TRC_Bytes), + + // White point + SkEndian_SwapBE32(kTAG_wtpt), + SkEndian_SwapBE32(kTAG_wtpt_Offset), + SkEndian_SwapBE32(kTAG_XYZ_Bytes), + + // Copyright + SkEndian_SwapBE32(kTAG_cprt), + SkEndian_SwapBE32(kTAG_cprt_Offset), + SkEndian_SwapBE32(kTAG_cprt_Bytes), +}; + +static void write_xyz_tag(uint32_t* ptr, const SkMatrix44& toXYZ, int col) { + ptr[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); + ptr[1] = 0; + ptr[2] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(0, col))); + ptr[3] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(1, col))); + ptr[4] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(2, col))); +} + +static void write_trc_tag(uint32_t* ptr, const SkColorSpaceTransferFn& fn) { + ptr[0] = SkEndian_SwapBE32(kTAG_ParaCurveType); + ptr[1] = 0; + ptr[2] = (uint32_t) (SkEndian_SwapBE16(kGABCDEF_ParaCurveType)); + ptr[3] = SkEndian_SwapBE32(SkFloatToFixed(fn.fG)); + ptr[4] = SkEndian_SwapBE32(SkFloatToFixed(fn.fA)); + ptr[5] = SkEndian_SwapBE32(SkFloatToFixed(fn.fB)); + ptr[6] = SkEndian_SwapBE32(SkFloatToFixed(fn.fC)); + ptr[7] = SkEndian_SwapBE32(SkFloatToFixed(fn.fD)); + ptr[8] = SkEndian_SwapBE32(SkFloatToFixed(fn.fE)); + ptr[9] = SkEndian_SwapBE32(SkFloatToFixed(fn.fF)); +} + +static bool is_3x3(const SkMatrix44& toXYZD50) { + return 0.0f == toXYZD50.get(3, 0) && 0.0f == toXYZD50.get(3, 1) && 0.0f == toXYZD50.get(3, 2) && + 0.0f == toXYZD50.get(0, 3) && 0.0f == toXYZD50.get(1, 3) && 0.0f == toXYZD50.get(2, 3) && + 1.0f == toXYZD50.get(3, 3); +} + +sk_sp SkICC::WriteToICC(const SkColorSpaceTransferFn& fn, const SkMatrix44& toXYZD50) { + if (!is_3x3(toXYZD50) || !is_valid_transfer_fn(fn)) { + return nullptr; + } + + SkAutoMalloc profile(kICCProfileSize); + uint8_t* ptr = (uint8_t*) profile.get(); + + // Write profile header + memcpy(ptr, kICCHeader, sizeof(kICCHeader)); + ptr += sizeof(kICCHeader); + + // Write tag table + memcpy(ptr, kICCTagTable, sizeof(kICCTagTable)); + ptr += sizeof(kICCTagTable); + + // Write profile description tag + memcpy(ptr, kDescriptionTagHeader, sizeof(kDescriptionTagHeader)); + ptr += sizeof(kDescriptionTagHeader); + memcpy(ptr, kDescriptionTagBody, sizeof(kDescriptionTagBody)); + ptr += sizeof(kDescriptionTagBody); + + // Write XYZ tags + write_xyz_tag((uint32_t*) ptr, toXYZD50, 0); + ptr += kTAG_XYZ_Bytes; + write_xyz_tag((uint32_t*) ptr, toXYZD50, 1); + ptr += kTAG_XYZ_Bytes; + write_xyz_tag((uint32_t*) ptr, toXYZD50, 2); + ptr += kTAG_XYZ_Bytes; + + // Write TRC tag + write_trc_tag((uint32_t*) ptr, fn); + ptr += kTAG_TRC_Bytes; + + // Write white point tag (must be D50) + memcpy(ptr, kWhitePointTag, sizeof(kWhitePointTag)); + ptr += sizeof(kWhitePointTag); + + // Write copyright tag + memcpy(ptr, kCopyrightTagHeader, sizeof(kCopyrightTagHeader)); + ptr += sizeof(kCopyrightTagHeader); + memcpy(ptr, kCopyrightTagBody, sizeof(kCopyrightTagBody)); + ptr += sizeof(kCopyrightTagBody); + + SkASSERT(kICCProfileSize == ptr - (uint8_t*) profile.get()); + return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); +} diff --git a/gfx/skia/skia/src/core/SkICCPriv.h b/gfx/skia/skia/src/core/SkICCPriv.h new file mode 100644 index 000000000000..4c656f17d8ec --- /dev/null +++ b/gfx/skia/skia/src/core/SkICCPriv.h @@ -0,0 +1,52 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkICCPriv_DEFINED +#define SkICCPriv_DEFINED + +#include "SkTypes.h" + +// This is equal to the header size according to the ICC specification (128) +// plus the size of the tag count (4). We include the tag count since we +// always require it to be present anyway. +static constexpr size_t kICCHeaderSize = 132; + +// Contains a signature (4), offset (4), and size (4). +static constexpr size_t kICCTagTableEntrySize = 12; + +static constexpr uint32_t kRGB_ColorSpace = SkSetFourByteTag('R', 'G', 'B', ' '); +static constexpr uint32_t kCMYK_ColorSpace = SkSetFourByteTag('C', 'M', 'Y', 'K'); +static constexpr uint32_t kGray_ColorSpace = SkSetFourByteTag('G', 'R', 'A', 'Y'); +static constexpr uint32_t kDisplay_Profile = SkSetFourByteTag('m', 'n', 't', 'r'); +static constexpr uint32_t kInput_Profile = SkSetFourByteTag('s', 'c', 'n', 'r'); +static constexpr uint32_t kOutput_Profile = SkSetFourByteTag('p', 'r', 't', 'r'); +static constexpr uint32_t kColorSpace_Profile = SkSetFourByteTag('s', 'p', 'a', 'c'); +static constexpr uint32_t kXYZ_PCSSpace = SkSetFourByteTag('X', 'Y', 'Z', ' '); +static constexpr uint32_t kLAB_PCSSpace = SkSetFourByteTag('L', 'a', 'b', ' '); +static constexpr uint32_t kACSP_Signature = SkSetFourByteTag('a', 'c', 's', 'p'); + +static constexpr uint32_t kTAG_rXYZ = SkSetFourByteTag('r', 'X', 'Y', 'Z'); +static constexpr uint32_t kTAG_gXYZ = SkSetFourByteTag('g', 'X', 'Y', 'Z'); +static constexpr uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z'); +static constexpr uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C'); +static constexpr uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); +static constexpr uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); +static constexpr uint32_t kTAG_kTRC = SkSetFourByteTag('k', 'T', 'R', 'C'); +static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0'); + +static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); +static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); +static constexpr uint32_t kTAG_TextType = SkSetFourByteTag('m', 'l', 'u', 'c'); + +enum ParaCurveType { + kExponential_ParaCurveType = 0, + kGAB_ParaCurveType = 1, + kGABC_ParaCurveType = 2, + kGABDE_ParaCurveType = 3, + kGABCDEF_ParaCurveType = 4, +}; +#endif // SkICCPriv_DEFINED diff --git a/gfx/skia/skia/src/core/SkImageCacherator.cpp b/gfx/skia/skia/src/core/SkImageCacherator.cpp index 496ca74d9a18..a31d31ff968d 100644 --- a/gfx/skia/skia/src/core/SkImageCacherator.cpp +++ b/gfx/skia/skia/src/core/SkImageCacherator.cpp @@ -7,6 +7,7 @@ #include "SkBitmap.h" #include "SkBitmapCache.h" +#include "SkColorSpace_Base.h" #include "SkImage_Base.h" #include "SkImageCacherator.h" #include "SkMallocPixelRef.h" @@ -16,13 +17,14 @@ #if SK_SUPPORT_GPU #include "GrContext.h" +#include "GrContextPriv.h" #include "GrGpuResourcePriv.h" -#include "GrImageIDTextureAdjuster.h" +#include "GrImageTextureMaker.h" #include "GrResourceKey.h" -#include "GrTextureParams.h" +#include "GrResourceProvider.h" +#include "GrSamplerParams.h" #include "GrYUVProvider.h" #include "SkGr.h" -#include "SkGrPriv.h" #endif // Until we actually have codecs/etc. that can contain/support a GPU texture format @@ -32,52 +34,101 @@ // see skbug.com/ 4971, 5128, ... //#define SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR -SkImageCacherator* SkImageCacherator::NewFromGenerator(SkImageGenerator* gen, - const SkIRect* subset) { - if (!gen) { - return nullptr; +// Helper for exclusive access to a shared generator. +class SkImageCacherator::ScopedGenerator { +public: + ScopedGenerator(const sk_sp& gen) + : fSharedGenerator(gen) + , fAutoAquire(gen->fMutex) {} + + SkImageGenerator* operator->() const { + fSharedGenerator->fMutex.assertHeld(); + return fSharedGenerator->fGenerator.get(); } - // We are required to take ownership of gen, regardless of if we return a cacherator or not - SkAutoTDelete genHolder(gen); + operator SkImageGenerator*() const { + fSharedGenerator->fMutex.assertHeld(); + return fSharedGenerator->fGenerator.get(); + } - const SkImageInfo& info = gen->getInfo(); +private: + const sk_sp& fSharedGenerator; + SkAutoExclusive fAutoAquire; +}; + +SkImageCacherator::Validator::Validator(sk_sp gen, const SkIRect* subset) + : fSharedGenerator(std::move(gen)) { + + if (!fSharedGenerator) { + return; + } + + // The following generator accessors are safe without acquiring the mutex (const getters). + // TODO: refactor to use a ScopedGenerator instead, for clarity. + const SkImageInfo& info = fSharedGenerator->fGenerator->getInfo(); if (info.isEmpty()) { - return nullptr; + fSharedGenerator.reset(); + return; } - uint32_t uniqueID = gen->uniqueID(); + fUniqueID = fSharedGenerator->fGenerator->uniqueID(); const SkIRect bounds = SkIRect::MakeWH(info.width(), info.height()); if (subset) { if (!bounds.contains(*subset)) { - return nullptr; + fSharedGenerator.reset(); + return; } if (*subset != bounds) { // we need a different uniqueID since we really are a subset of the raw generator - uniqueID = SkNextID::ImageID(); + fUniqueID = SkNextID::ImageID(); } } else { subset = &bounds; } - // Now that we know we can hand-off the generator (to be owned by the cacherator) we can - // release our holder. (we DONT want to delete it here anymore) - genHolder.release(); + fInfo = info.makeWH(subset->width(), subset->height()); + fOrigin = SkIPoint::Make(subset->x(), subset->y()); - return new SkImageCacherator(gen, gen->getInfo().makeWH(subset->width(), subset->height()), - SkIPoint::Make(subset->x(), subset->y()), uniqueID); + // colortables are poorly to not-at-all supported in our resourcecache, so we + // bully them into N32 (the generator will perform the up-sample) + if (fInfo.colorType() == kIndex_8_SkColorType) { + fInfo = fInfo.makeColorType(kN32_SkColorType); + } } -SkImageCacherator::SkImageCacherator(SkImageGenerator* gen, const SkImageInfo& info, - const SkIPoint& origin, uint32_t uniqueID) - : fNotThreadSafeGenerator(gen) - , fInfo(info) - , fOrigin(origin) - , fUniqueID(uniqueID) -{} +SkImageCacherator* SkImageCacherator::NewFromGenerator(std::unique_ptr gen, + const SkIRect* subset) { + Validator validator(SharedGenerator::Make(std::move(gen)), subset); + + return validator ? new SkImageCacherator(&validator) : nullptr; +} + +SkImageCacherator::SkImageCacherator(Validator* validator) + : fSharedGenerator(std::move(validator->fSharedGenerator)) // we take ownership + , fInfo(validator->fInfo) + , fOrigin(validator->fOrigin) +{ + SkASSERT(fSharedGenerator); + SkASSERT(fInfo.colorType() != kIndex_8_SkColorType); + // We explicit set the legacy format slot, but leave the others uninitialized (via SkOnce) + // and only resolove them to IDs as needed (by calling getUniqueID()). + fIDRecs[kLegacy_CachedFormat].fOnce([this, validator] { + fIDRecs[kLegacy_CachedFormat].fUniqueID = validator->fUniqueID; + }); +} + +SkImageCacherator::~SkImageCacherator() {} + +uint32_t SkImageCacherator::getUniqueID(CachedFormat format) const { + IDRec* rec = &fIDRecs[format]; + rec->fOnce([rec] { + rec->fUniqueID = SkNextID::ImageID(); + }); + return rec->fUniqueID; +} SkData* SkImageCacherator::refEncoded(GrContext* ctx) { - ScopedGenerator generator(this); + ScopedGenerator generator(fSharedGenerator); return generator->refEncodedData(ctx); } @@ -88,111 +139,179 @@ static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) { return true; } -// Note, this returns a new, mutable, bitmap, with a new genID. -// If you want the immutable bitmap with the same ID as our cacherator, call tryLockAsBitmap() -// -bool SkImageCacherator::generateBitmap(SkBitmap* bitmap) { - SkBitmap::Allocator* allocator = SkResourceCache::GetAllocator(); - - ScopedGenerator generator(this); - const SkImageInfo& genInfo = generator->getInfo(); - if (fInfo.dimensions() == genInfo.dimensions()) { - SkASSERT(fOrigin.x() == 0 && fOrigin.y() == 0); - // fast-case, no copy needed - return generator->tryGenerateBitmap(bitmap, fInfo, allocator); - } else { - // need to handle subsetting, so we first generate the full size version, and then - // "read" from it to get our subset. See https://bug.skia.org/4213 - - SkBitmap full; - if (!generator->tryGenerateBitmap(&full, genInfo, allocator)) { - return false; - } - if (!bitmap->tryAllocPixels(fInfo, nullptr, full.getColorTable())) { - return false; - } - return full.readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), - fOrigin.x(), fOrigin.y()); - } -} - bool SkImageCacherator::directGeneratePixels(const SkImageInfo& info, void* pixels, size_t rb, - int srcX, int srcY) { - ScopedGenerator generator(this); + int srcX, int srcY, + SkTransferFunctionBehavior behavior) { + ScopedGenerator generator(fSharedGenerator); const SkImageInfo& genInfo = generator->getInfo(); // Currently generators do not natively handle subsets, so check that first. if (srcX || srcY || genInfo.width() != info.width() || genInfo.height() != info.height()) { return false; } - return generator->getPixels(info, pixels, rb); + + SkImageGenerator::Options opts; + opts.fBehavior = behavior; + return generator->getPixels(info, pixels, rb, &opts); } ////////////////////////////////////////////////////////////////////////////////////////////////// -bool SkImageCacherator::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap) { - return SkBitmapCache::Find(fUniqueID, bitmap) && check_output_bitmap(*bitmap, fUniqueID); +bool SkImageCacherator::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap, CachedFormat format) { + uint32_t uniqueID = this->getUniqueID(format); + return SkBitmapCache::Find(SkBitmapCacheDesc::Make(uniqueID, + fInfo.width(), fInfo.height()), bitmap) && + check_output_bitmap(*bitmap, uniqueID); } -bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap, const SkImage* client, - SkImage::CachingHint chint) { - if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap)) { - return true; - } - if (!this->generateBitmap(bitmap)) { +static bool generate_pixels(SkImageGenerator* gen, const SkPixmap& pmap, int originX, int originY) { + const int genW = gen->getInfo().width(); + const int genH = gen->getInfo().height(); + const SkIRect srcR = SkIRect::MakeWH(genW, genH); + const SkIRect dstR = SkIRect::MakeXYWH(originX, originY, pmap.width(), pmap.height()); + if (!srcR.contains(dstR)) { return false; } - bitmap->pixelRef()->setImmutableWithID(fUniqueID); - if (SkImage::kAllow_CachingHint == chint) { - SkBitmapCache::Add(fUniqueID, *bitmap); - if (client) { - as_IB(client)->notifyAddedToCache(); + // If they are requesting a subset, we have to have a temp allocation for full image, and + // then copy the subset into their allocation + SkBitmap full; + SkPixmap fullPM; + const SkPixmap* dstPM = &pmap; + if (srcR != dstR) { + if (!full.tryAllocPixels(pmap.info().makeWH(genW, genH))) { + return false; + } + if (!full.peekPixels(&fullPM)) { + return false; + } + dstPM = &fullPM; + } + + if (!gen->getPixels(dstPM->info(), dstPM->writable_addr(), dstPM->rowBytes())) { + return false; + } + + if (srcR != dstR) { + if (!full.readPixels(pmap, originX, originY)) { + return false; } } return true; } -bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap, const SkImage* client, +bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap, const SkImage* client, + SkImage::CachingHint chint, CachedFormat format, + const SkImageInfo& info) { + if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap, format)) { + return true; + } + + uint32_t uniqueID = this->getUniqueID(format); + + SkBitmap tmpBitmap; + SkBitmapCache::RecPtr cacheRec; + SkPixmap pmap; + if (SkImage::kAllow_CachingHint == chint) { + auto desc = SkBitmapCacheDesc::Make(uniqueID, info.width(), info.height()); + cacheRec = SkBitmapCache::Alloc(desc, info, &pmap); + if (!cacheRec) { + return false; + } + } else { + if (!tmpBitmap.tryAllocPixels(info)) { + return false; + } + if (!tmpBitmap.peekPixels(&pmap)) { + return false; + } + } + + ScopedGenerator generator(fSharedGenerator); + if (!generate_pixels(generator, pmap, fOrigin.x(), fOrigin.y())) { + return false; + } + + if (cacheRec) { + SkBitmapCache::Add(std::move(cacheRec), bitmap); + SkASSERT(bitmap->getPixels()); // we're locked + SkASSERT(bitmap->isImmutable()); + SkASSERT(bitmap->getGenerationID() == uniqueID); + if (client) { + as_IB(client)->notifyAddedToCache(); + } + } else { + *bitmap = tmpBitmap; + bitmap->lockPixels(); + bitmap->pixelRef()->setImmutableWithID(uniqueID); + } + return true; +} + +bool SkImageCacherator::lockAsBitmap(GrContext* context, SkBitmap* bitmap, const SkImage* client, + SkColorSpace* dstColorSpace, SkImage::CachingHint chint) { - if (this->tryLockAsBitmap(bitmap, client, chint)) { - return check_output_bitmap(*bitmap, fUniqueID); + CachedFormat format = this->chooseCacheFormat(dstColorSpace); + SkImageInfo cacheInfo = this->buildCacheInfo(format); + const uint32_t uniqueID = this->getUniqueID(format); + + if (this->tryLockAsBitmap(bitmap, client, chint, format, cacheInfo)) { + return check_output_bitmap(*bitmap, uniqueID); } #if SK_SUPPORT_GPU + if (!context) { + bitmap->reset(); + return false; + } + // Try to get a texture and read it back to raster (and then cache that with our ID) - SkAutoTUnref tex; + sk_sp proxy; { - ScopedGenerator generator(this); - SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height()); - tex.reset(generator->generateTexture(nullptr, &subset)); + ScopedGenerator generator(fSharedGenerator); + proxy = generator->generateTexture(context, cacheInfo, fOrigin); } - if (!tex) { + if (!proxy) { bitmap->reset(); return false; } - if (!bitmap->tryAllocPixels(fInfo)) { - bitmap->reset(); - return false; - } - - const uint32_t pixelOpsFlags = 0; - if (!tex->readPixels(0, 0, bitmap->width(), bitmap->height(), - SkImageInfo2GrPixelConfig(fInfo, *tex->getContext()->caps()), - bitmap->getPixels(), bitmap->rowBytes(), pixelOpsFlags)) { - bitmap->reset(); - return false; - } - - bitmap->pixelRef()->setImmutableWithID(fUniqueID); + const auto desc = SkBitmapCacheDesc::Make(uniqueID, fInfo.width(), fInfo.height()); + SkBitmapCache::RecPtr rec; + SkPixmap pmap; if (SkImage::kAllow_CachingHint == chint) { - SkBitmapCache::Add(fUniqueID, *bitmap); + rec = SkBitmapCache::Alloc(desc, cacheInfo, &pmap); + if (!rec) { + bitmap->reset(); + return false; + } + } else { + if (!bitmap->tryAllocPixels(cacheInfo)) { + bitmap->reset(); + return false; + } + } + + sk_sp sContext(context->contextPriv().makeWrappedSurfaceContext( + proxy, + fInfo.refColorSpace())); // src colorSpace + if (!sContext) { + bitmap->reset(); + return false; + } + + if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) { + bitmap->reset(); + return false; + } + + if (rec) { + SkBitmapCache::Add(std::move(rec), bitmap); if (client) { as_IB(client)->notifyAddedToCache(); } } - return check_output_bitmap(*bitmap, fUniqueID); + return check_output_bitmap(*bitmap, uniqueID); #else return false; #endif @@ -200,7 +319,180 @@ bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap, const SkImage* client, ////////////////////////////////////////////////////////////////////////////////////////////////// +// Abstraction of GrCaps that handles the cases where we don't have a caps pointer (because +// we're in raster mode), or where GPU support is entirely missing. In theory, we only need the +// chosen format to be texturable, but that lets us choose F16 on GLES implemenations where we +// won't be able to read the texture back. We'd like to ensure that SkImake::makeNonTextureImage +// works, so we require that the formats we choose are renderable (as a proxy for being readable). +struct CacheCaps { + CacheCaps(const GrCaps* caps) : fCaps(caps) {} + #if SK_SUPPORT_GPU + bool supportsHalfFloat() const { + return !fCaps || + (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) && + fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false)); + } + + bool supportsSRGB() const { + return !fCaps || + (fCaps->srgbSupport() && fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig)); + } + + bool supportsSBGR() const { + return !fCaps || fCaps->srgbSupport(); + } +#else + bool supportsHalfFloat() const { return true; } + bool supportsSRGB() const { return true; } + bool supportsSBGR() const { return true; } +#endif + + const GrCaps* fCaps; +}; + +SkImageCacherator::CachedFormat SkImageCacherator::chooseCacheFormat(SkColorSpace* dstColorSpace, + const GrCaps* grCaps) { + SkColorSpace* cs = fInfo.colorSpace(); + if (!cs || !dstColorSpace) { + return kLegacy_CachedFormat; + } + + CacheCaps caps(grCaps); + switch (fInfo.colorType()) { + case kUnknown_SkColorType: + case kAlpha_8_SkColorType: + case kRGB_565_SkColorType: + case kARGB_4444_SkColorType: + // We don't support color space on these formats, so always decode in legacy mode: + // TODO: Ask the codec to decode these to something else (at least sRGB 8888)? + return kLegacy_CachedFormat; + + case kIndex_8_SkColorType: + SkDEBUGFAIL("Index_8 should have been remapped at construction time."); + return kLegacy_CachedFormat; + + case kGray_8_SkColorType: + // TODO: What do we do with grayscale sources that have strange color spaces attached? + // The codecs and color space xform don't handle this correctly (yet), so drop it on + // the floor. (Also, inflating by a factor of 8 is going to be unfortunate). + // As it is, we don't directly support sRGB grayscale, so ask the codec to convert + // it for us. This bypasses some really sketchy code GrUploadPixmapToTexture. + if (cs->gammaCloseToSRGB() && caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + + case kRGBA_8888_SkColorType: + if (cs->gammaCloseToSRGB()) { + if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } else { + if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } + + case kBGRA_8888_SkColorType: + // Odd case. sBGRA isn't a real thing, so we may not have this texturable. + if (caps.supportsSBGR()) { + if (cs->gammaCloseToSRGB()) { + return kSBGR8888_CachedFormat; + } else if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + // sBGRA support without sRGBA is highly unlikely (impossible?) Nevertheless. + return kLegacy_CachedFormat; + } + } else { + if (cs->gammaCloseToSRGB()) { + if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } else { + if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } + } + + case kRGBA_F16_SkColorType: + if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } + SkDEBUGFAIL("Unreachable"); + return kLegacy_CachedFormat; +} + +SkImageInfo SkImageCacherator::buildCacheInfo(CachedFormat format) { + switch (format) { + case kLegacy_CachedFormat: + return fInfo.makeColorSpace(nullptr); + case kLinearF16_CachedFormat: + return fInfo.makeColorType(kRGBA_F16_SkColorType) + .makeColorSpace(as_CSB(fInfo.colorSpace())->makeLinearGamma()); + case kSRGB8888_CachedFormat: + // If the transfer function is nearly (but not exactly) sRGB, we don't want the codec + // to bother trans-coding. It would be slow, and do more harm than good visually, + // so we make sure to leave the colorspace as-is. + if (fInfo.colorSpace()->gammaCloseToSRGB()) { + return fInfo.makeColorType(kRGBA_8888_SkColorType); + } else { + return fInfo.makeColorType(kRGBA_8888_SkColorType) + .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma()); + } + case kSBGR8888_CachedFormat: + // See note above about not-quite-sRGB transfer functions. + if (fInfo.colorSpace()->gammaCloseToSRGB()) { + return fInfo.makeColorType(kBGRA_8888_SkColorType); + } else { + return fInfo.makeColorType(kBGRA_8888_SkColorType) + .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma()); + } + default: + SkDEBUGFAIL("Invalid cached format"); + return fInfo; + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + +#if SK_SUPPORT_GPU + +void SkImageCacherator::makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat format, + GrUniqueKey* cacheKey) { + SkASSERT(!cacheKey->isValid()); + if (origKey.isValid()) { + static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); + GrUniqueKey::Builder builder(cacheKey, origKey, kDomain, 1); + builder[0] = format; + } +} #ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrSurfaceDesc desc) { @@ -212,7 +504,7 @@ static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrS } desc.fConfig = config; - return ctx->textureProvider()->createTexture(desc, SkBudgeted::kYes, rawStart, 0); + return ctx->resourceProvider()->createTexture(desc, SkBudgeted::kYes, rawStart, 0); } #endif @@ -231,11 +523,20 @@ public: } }; -static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) { +static void set_key_on_proxy(GrResourceProvider* resourceProvider, + GrTextureProxy* proxy, const GrUniqueKey& key) { if (key.isValid()) { - tex->resourcePriv().setUniqueKey(key); + resourceProvider->assignUniqueKeyToProxy(key, proxy); } - return tex; +} + +sk_sp SkImageCacherator::getColorSpace(GrContext* ctx, SkColorSpace* dstColorSpace) { + // TODO: This isn't always correct. Picture generator currently produces textures in N32, + // and will (soon) emit them in an arbitrary (destination) space. We will need to stash that + // information in/on the key so we can return the correct space in case #1 of lockTexture. + CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps()); + SkImageInfo cacheInfo = this->buildCacheInfo(format); + return sk_ref_sp(cacheInfo.colorSpace()); } /* @@ -247,10 +548,12 @@ static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) { * 4. Ask the generator to return YUV planes, which the GPU can convert * 5. Ask the generator to return RGB(A) data, which the GPU can convert */ -GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key, - const SkImage* client, SkImage::CachingHint chint, - bool willBeMipped, - SkSourceGammaTreatment gammaTreatment) { +sk_sp SkImageCacherator::lockTextureProxy(GrContext* ctx, + const GrUniqueKey& origKey, + const SkImage* client, + SkImage::CachingHint chint, + bool willBeMipped, + SkColorSpace* dstColorSpace) { // Values representing the various texture lock paths we can take. Used for logging the path // taken to a histogram. enum LockTexturePath { @@ -264,27 +567,40 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key enum { kLockTexturePathCount = kRGBA_LockTexturePath + 1 }; + // Determine which cached format we're going to use (which may involve decoding to a different + // info than the generator provides). + CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps()); + + // Fold the cache format into our texture key + GrUniqueKey key; + this->makeCacheKeyFromOrigKey(origKey, format, &key); + // 1. Check the cache for a pre-existing one if (key.isValid()) { - if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) { + if (sk_sp proxy = ctx->resourceProvider()->findProxyByUniqueKey(key)) { SK_HISTOGRAM_ENUMERATION("LockTexturePath", kPreExisting_LockTexturePath, kLockTexturePathCount); - return tex; + return proxy; } } + // The CachedFormat is both an index for which cache "slot" we'll use to store this particular + // decoded variant of the encoded data, and also a recipe for how to transform the original + // info to get the one that we're going to decode to. + SkImageInfo cacheInfo = this->buildCacheInfo(format); + // 2. Ask the generator to natively create one { - ScopedGenerator generator(this); - SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height()); - if (GrTexture* tex = generator->generateTexture(ctx, &subset)) { + ScopedGenerator generator(fSharedGenerator); + if (sk_sp proxy = generator->generateTexture(ctx, cacheInfo, fOrigin)) { SK_HISTOGRAM_ENUMERATION("LockTexturePath", kNative_LockTexturePath, kLockTexturePathCount); - return set_key_and_return(tex, key); + set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key); + return proxy; } } - const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(fInfo, *ctx->caps()); + const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(cacheInfo, *ctx->caps()); #ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR // 3. Ask the generator to return a compressed form that the GPU might support @@ -300,31 +616,32 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key #endif // 4. Ask the generator to return YUV planes, which the GPU can convert - { - ScopedGenerator generator(this); + if (!ctx->contextPriv().disableGpuYUVConversion()) { + ScopedGenerator generator(fSharedGenerator); Generator_GrYUVProvider provider(generator); - sk_sp tex = provider.refAsTexture(ctx, desc, true); - if (tex) { + if (sk_sp proxy = provider.refAsTextureProxy(ctx, desc, true)) { SK_HISTOGRAM_ENUMERATION("LockTexturePath", kYUV_LockTexturePath, kLockTexturePathCount); - return set_key_and_return(tex.release(), key); + set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key); + return proxy; } } // 5. Ask the generator to return RGB(A) data, which the GPU can convert SkBitmap bitmap; - if (this->tryLockAsBitmap(&bitmap, client, chint)) { - GrTexture* tex = nullptr; + if (this->tryLockAsBitmap(&bitmap, client, chint, format, cacheInfo)) { + sk_sp proxy; if (willBeMipped) { - tex = GrGenerateMipMapsAndUploadToTexture(ctx, bitmap, gammaTreatment); + proxy = GrGenerateMipMapsAndUploadToTextureProxy(ctx, bitmap, dstColorSpace); } - if (!tex) { - tex = GrUploadBitmapToTexture(ctx, bitmap); + if (!proxy) { + proxy = GrUploadBitmapToTextureProxy(ctx->resourceProvider(), bitmap); } - if (tex) { + if (proxy) { SK_HISTOGRAM_ENUMERATION("LockTexturePath", kRGBA_LockTexturePath, kLockTexturePathCount); - return set_key_and_return(tex, key); + set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key); + return proxy; } } SK_HISTOGRAM_ENUMERATION("LockTexturePath", kFailure_LockTexturePath, @@ -334,23 +651,21 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key /////////////////////////////////////////////////////////////////////////////////////////////////// -GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParams& params, - SkSourceGammaTreatment gammaTreatment, - const SkImage* client, SkImage::CachingHint chint) { +sk_sp SkImageCacherator::lockAsTextureProxy(GrContext* ctx, + const GrSamplerParams& params, + SkColorSpace* dstColorSpace, + sk_sp* texColorSpace, + const SkImage* client, + SkScalar scaleAdjust[2], + SkImage::CachingHint chint) { if (!ctx) { return nullptr; } - return GrImageTextureMaker(ctx, this, client, chint).refTextureForParams(params, - gammaTreatment); -} - -#else - -GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParams&, - SkSourceGammaTreatment gammaTreatment, - const SkImage* client, SkImage::CachingHint) { - return nullptr; + return GrImageTextureMaker(ctx, this, client, chint).refTextureProxyForParams(params, + dstColorSpace, + texColorSpace, + scaleAdjust); } #endif diff --git a/gfx/skia/skia/src/core/SkImageCacherator.h b/gfx/skia/skia/src/core/SkImageCacherator.h index 3be69a578568..0f0135201089 100644 --- a/gfx/skia/skia/src/core/SkImageCacherator.h +++ b/gfx/skia/skia/src/core/SkImageCacherator.h @@ -12,8 +12,10 @@ #include "SkMutex.h" #include "SkTemplates.h" +class GrCaps; class GrContext; -class GrTextureParams; +class GrSamplerParams; +class GrTextureProxy; class GrUniqueKey; class SkBitmap; class SkImage; @@ -23,11 +25,22 @@ class SkImage; */ class SkImageCacherator { public: - // Takes ownership of the generator - static SkImageCacherator* NewFromGenerator(SkImageGenerator*, const SkIRect* subset = nullptr); + static SkImageCacherator* NewFromGenerator(std::unique_ptr, + const SkIRect* subset = nullptr); + + ~SkImageCacherator(); const SkImageInfo& info() const { return fInfo; } - uint32_t uniqueID() const { return fUniqueID; } + uint32_t uniqueID() const { return this->getUniqueID(kLegacy_CachedFormat); } + + enum CachedFormat { + kLegacy_CachedFormat, // The format from the generator, with any color space stripped out + kLinearF16_CachedFormat, // Half float RGBA with linear gamma + kSRGB8888_CachedFormat, // sRGB bytes + kSBGR8888_CachedFormat, // sRGB bytes, in BGR order + + kNumCachedFormats, + }; /** * On success (true), bitmap will point to the pixels for this generator. If this returns @@ -36,9 +49,10 @@ public: * If not NULL, the client will be notified (->notifyAddedToCache()) when resources are * added to the cache on its behalf. */ - bool lockAsBitmap(SkBitmap*, const SkImage* client, + bool lockAsBitmap(GrContext*, SkBitmap*, const SkImage* client, SkColorSpace* dstColorSpace, SkImage::CachingHint = SkImage::kAllow_CachingHint); +#if SK_SUPPORT_GPU /** * Returns a ref() on the texture produced by this generator. The caller must call unref() * when it is done. Will return nullptr on failure. @@ -46,11 +60,20 @@ public: * If not NULL, the client will be notified (->notifyAddedToCache()) when resources are * added to the cache on its behalf. * - * The caller is responsible for calling texture->unref() when they are done. + * The caller is responsible for calling proxy->unref() when they are done. + * + * The scaleAdjust in/out parameter will return any scale adjustment that needs + * to be applied to the absolute texture coordinates in the case where the image + * was resized to meet the sampling requirements (e.g., resized out to the next power of 2). + * It can be null if the caller knows resizing will not be required. */ - GrTexture* lockAsTexture(GrContext*, const GrTextureParams&, - SkSourceGammaTreatment gammaTreatment, const SkImage* client, - SkImage::CachingHint = SkImage::kAllow_CachingHint); + sk_sp lockAsTextureProxy(GrContext*, const GrSamplerParams&, + SkColorSpace* dstColorSpace, + sk_sp* texColorSpace, + const SkImage* client, + SkScalar scaleAdjust[2], + SkImage::CachingHint = SkImage::kAllow_CachingHint); +#endif /** * If the underlying src naturally is represented by an encoded blob (in SkData), this returns @@ -62,44 +85,84 @@ public: SkData* refEncoded(GrContext*); // Only return true if the generate has already been cached. - bool lockAsBitmapOnlyIfAlreadyCached(SkBitmap*); + bool lockAsBitmapOnlyIfAlreadyCached(SkBitmap*, CachedFormat); // Call the underlying generator directly bool directGeneratePixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, - int srcX, int srcY); + int srcX, int srcY, SkTransferFunctionBehavior behavior); private: - SkImageCacherator(SkImageGenerator*, const SkImageInfo&, const SkIPoint&, uint32_t uniqueID); - - bool generateBitmap(SkBitmap*); - bool tryLockAsBitmap(SkBitmap*, const SkImage*, SkImage::CachingHint); -#if SK_SUPPORT_GPU - // Returns the texture. If the cacherator is generating the texture and wants to cache it, - // it should use the passed in key (if the key is valid). - GrTexture* lockTexture(GrContext*, const GrUniqueKey& key, const SkImage* client, - SkImage::CachingHint, bool willBeMipped, SkSourceGammaTreatment); -#endif - - class ScopedGenerator { - SkImageCacherator* fCacher; + // Ref-counted tuple(SkImageGenerator, SkMutex) which allows sharing of one generator + // among several cacherators. + class SharedGenerator final : public SkNVRefCnt { public: - ScopedGenerator(SkImageCacherator* cacher) : fCacher(cacher) { - fCacher->fMutexForGenerator.acquire(); + static sk_sp Make(std::unique_ptr gen) { + return gen ? sk_sp(new SharedGenerator(std::move(gen))) : nullptr; } - ~ScopedGenerator() { - fCacher->fMutexForGenerator.release(); + + private: + explicit SharedGenerator(std::unique_ptr gen) + : fGenerator(std::move(gen)) + { + SkASSERT(fGenerator); } - SkImageGenerator* operator->() const { return fCacher->fNotThreadSafeGenerator; } - operator SkImageGenerator*() const { return fCacher->fNotThreadSafeGenerator; } + + friend class ScopedGenerator; + friend class SkImageCacherator; + + std::unique_ptr fGenerator; + SkMutex fMutex; + }; + class ScopedGenerator; + + struct Validator { + Validator(sk_sp, const SkIRect* subset); + + MOZ_IMPLICIT operator bool() const { return fSharedGenerator.get(); } + + sk_sp fSharedGenerator; + SkImageInfo fInfo; + SkIPoint fOrigin; + uint32_t fUniqueID; }; - SkMutex fMutexForGenerator; - SkAutoTDelete fNotThreadSafeGenerator; + SkImageCacherator(Validator*); - const SkImageInfo fInfo; - const SkIPoint fOrigin; - const uint32_t fUniqueID; + CachedFormat chooseCacheFormat(SkColorSpace* dstColorSpace, const GrCaps* = nullptr); + SkImageInfo buildCacheInfo(CachedFormat); + + bool tryLockAsBitmap(SkBitmap*, const SkImage*, SkImage::CachingHint, CachedFormat, + const SkImageInfo&); +#if SK_SUPPORT_GPU + // Returns the texture proxy. If the cacherator is generating the texture and wants to cache it, + // it should use the passed in key (if the key is valid). + sk_sp lockTextureProxy(GrContext*, + const GrUniqueKey& key, + const SkImage* client, + SkImage::CachingHint, + bool willBeMipped, + SkColorSpace* dstColorSpace); + // Returns the color space of the texture that would be returned if you called lockTexture. + // Separate code path to allow querying of the color space for textures that cached (even + // externally). + sk_sp getColorSpace(GrContext*, SkColorSpace* dstColorSpace); + void makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat, GrUniqueKey* cacheKey); +#endif + + sk_sp fSharedGenerator; + const SkImageInfo fInfo; + const SkIPoint fOrigin; + + struct IDRec { + SkOnce fOnce; + uint32_t fUniqueID; + }; + mutable IDRec fIDRecs[kNumCachedFormats]; + + uint32_t getUniqueID(CachedFormat) const; friend class GrImageTextureMaker; + friend class SkImage; + friend class SkImage_Generator; }; #endif diff --git a/gfx/skia/skia/src/core/SkImageFilter.cpp b/gfx/skia/skia/src/core/SkImageFilter.cpp index 68183cc444b3..a0d3df750076 100644 --- a/gfx/skia/skia/src/core/SkImageFilter.cpp +++ b/gfx/skia/skia/src/core/SkImageFilter.cpp @@ -8,6 +8,7 @@ #include "SkImageFilter.h" #include "SkCanvas.h" +#include "SkColorSpace_Base.h" #include "SkFuzzLogging.h" #include "SkImageFilterCache.h" #include "SkLocalMatrixImageFilter.h" @@ -20,9 +21,10 @@ #include "SkWriteBuffer.h" #if SK_SUPPORT_GPU #include "GrContext.h" -#include "GrDrawContext.h" #include "GrFixedClip.h" -#include "SkGrPriv.h" +#include "GrRenderTargetContext.h" +#include "GrTextureProxy.h" +#include "SkGr.h" #endif #ifndef SK_IGNORE_TO_STRING @@ -205,9 +207,9 @@ sk_sp SkImageFilter::filterImage(SkSpecialImage* src, const Cont const SkIRect srcSubset = fUsesSrcInput ? src->subset() : SkIRect::MakeWH(0, 0); SkImageFilterCacheKey key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID, srcSubset); if (context.cache()) { - SkSpecialImage* result = context.cache()->get(key, offset); + sk_sp result = context.cache()->get(key, offset); if (result) { - return sk_sp(SkRef(result)); + return result; } } @@ -285,24 +287,24 @@ sk_sp SkImageFilter::DrawWithFP(GrContext* context, sk_sp colorSpace = sk_ref_sp(outputProperties.colorSpace()); GrPixelConfig config = GrRenderableConfigForColorSpace(colorSpace.get()); - sk_sp drawContext(context->makeDrawContext(SkBackingFit::kApprox, - bounds.width(), bounds.height(), - config, - std::move(colorSpace))); - if (!drawContext) { + sk_sp renderTargetContext(context->makeDeferredRenderTargetContext( + SkBackingFit::kApprox, bounds.width(), bounds.height(), config, std::move(colorSpace))); + if (!renderTargetContext) { return nullptr; } - paint.setGammaCorrect(drawContext->isGammaCorrect()); + paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); SkIRect dstIRect = SkIRect::MakeWH(bounds.width(), bounds.height()); SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrFixedClip clip(dstIRect); - drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); + renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect, + srcRect); - return SkSpecialImage::MakeFromGpu(dstIRect, kNeedNewImageUniqueID_SpecialImage, - drawContext->asTexture(), - sk_ref_sp(drawContext->getColorSpace())); + return SkSpecialImage::MakeDeferredFromGpu(context, dstIRect, + kNeedNewImageUniqueID_SpecialImage, + renderTargetContext->asTextureProxyRef(), + renderTargetContext->refColorSpace()); } #endif @@ -344,6 +346,37 @@ bool SkImageFilter::applyCropRect(const Context& ctx, const SkIRect& srcBounds, return dstBounds->intersect(ctx.clipBounds()); } +#if SK_SUPPORT_GPU +sk_sp SkImageFilter::ImageToColorSpace(SkSpecialImage* src, + const OutputProperties& outProps) { + // There are several conditions that determine if we actually need to convert the source to the + // destination's color space. Rather than duplicate that logic here, just try to make an xform + // object. If that produces something, then both are tagged, and the source is in a different + // gamut than the dest. There is some overhead to making the xform, but those are cached, and + // if we get one back, that means we're about to use it during the conversion anyway. + sk_sp colorSpaceXform = GrColorSpaceXform::Make(src->getColorSpace(), + outProps.colorSpace()); + + if (!colorSpaceXform) { + // No xform needed, just return the original image + return sk_ref_sp(src); + } + + sk_sp surf(src->makeSurface(outProps, + SkISize::Make(src->width(), src->height()))); + if (!surf) { + return sk_ref_sp(src); + } + + SkCanvas* canvas = surf->getCanvas(); + SkASSERT(canvas); + SkPaint p; + p.setBlendMode(SkBlendMode::kSrc); + src->draw(canvas, 0, 0, &p); + return surf->makeImageSnapshot(); +} +#endif + // Return a larger (newWidth x newHeight) copy of 'src' with black padding // around it. static sk_sp pad_image(SkSpecialImage* src, diff --git a/gfx/skia/skia/src/core/SkImageFilterCache.cpp b/gfx/skia/skia/src/core/SkImageFilterCache.cpp index c7104def3728..0d9e3677908f 100644 --- a/gfx/skia/skia/src/core/SkImageFilterCache.cpp +++ b/gfx/skia/skia/src/core/SkImageFilterCache.cpp @@ -41,7 +41,7 @@ public: : fKey(key), fImage(SkRef(image)), fOffset(offset) {} Key fKey; - SkAutoTUnref fImage; + sk_sp fImage; SkIPoint fOffset; static const Key& GetKey(const Value& v) { return v.fKey; @@ -52,7 +52,7 @@ public: SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value); }; - SkSpecialImage* get(const Key& key, SkIPoint* offset) const override { + sk_sp get(const Key& key, SkIPoint* offset) const override { SkAutoMutexAcquire mutex(fMutex); if (Value* v = fLookup.find(key)) { *offset = v->fOffset; diff --git a/gfx/skia/skia/src/core/SkImageFilterCache.h b/gfx/skia/skia/src/core/SkImageFilterCache.h index a65357f69cb0..8f0d9f10fc5d 100644 --- a/gfx/skia/skia/src/core/SkImageFilterCache.h +++ b/gfx/skia/skia/src/core/SkImageFilterCache.h @@ -53,7 +53,7 @@ public: virtual ~SkImageFilterCache() {} static SkImageFilterCache* Create(size_t maxBytes); static SkImageFilterCache* Get(); - virtual SkSpecialImage* get(const SkImageFilterCacheKey& key, SkIPoint* offset) const = 0; + virtual sk_sp get(const SkImageFilterCacheKey& key, SkIPoint* offset) const = 0; virtual void set(const SkImageFilterCacheKey& key, SkSpecialImage* image, const SkIPoint& offset) = 0; virtual void purge() = 0; diff --git a/gfx/skia/skia/src/core/SkImageGenerator.cpp b/gfx/skia/skia/src/core/SkImageGenerator.cpp index 84d9c743eb4d..f47bb1d1608b 100644 --- a/gfx/skia/skia/src/core/SkImageGenerator.cpp +++ b/gfx/skia/skia/src/core/SkImageGenerator.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkImage.h" #include "SkImageGenerator.h" #include "SkNextID.h" @@ -44,6 +45,15 @@ bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t r return success; } +bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + const Options* opts) { + Options defaultOpts; + if (!opts) { + opts = &defaultOpts; + } + return this->onGetPixels(info, pixels, rowBytes, *opts); +} + bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { SkASSERT(kIndex_8_SkColorType != info.colorType()); if (kIndex_8_SkColorType == info.colorType()) { @@ -76,40 +86,27 @@ bool SkImageGenerator::getYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes return this->onGetYUV8Planes(sizeInfo, planes); } -GrTexture* SkImageGenerator::generateTexture(GrContext* ctx, const SkIRect* subset) { - if (subset && !SkIRect::MakeWH(fInfo.width(), fInfo.height()).contains(*subset)) { +#if SK_SUPPORT_GPU +#include "GrTextureProxy.h" + +sk_sp SkImageGenerator::generateTexture(GrContext* ctx, const SkImageInfo& info, + const SkIPoint& origin) { + SkIRect srcRect = SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()); + if (!SkIRect::MakeWH(fInfo.width(), fInfo.height()).contains(srcRect)) { return nullptr; } - return this->onGenerateTexture(ctx, subset); + return this->onGenerateTexture(ctx, info, origin); } -bool SkImageGenerator::computeScaledDimensions(SkScalar scale, SupportedSizes* sizes) { - if (scale > 0 && scale <= 1) { - return this->onComputeScaledDimensions(scale, sizes); - } - return false; -} - -bool SkImageGenerator::generateScaledPixels(const SkISize& scaledSize, - const SkIPoint& subsetOrigin, - const SkPixmap& subsetPixels) { - if (scaledSize.width() <= 0 || scaledSize.height() <= 0) { - return false; - } - if (subsetPixels.width() <= 0 || subsetPixels.height() <= 0) { - return false; - } - const SkIRect subset = SkIRect::MakeXYWH(subsetOrigin.x(), subsetOrigin.y(), - subsetPixels.width(), subsetPixels.height()); - if (!SkIRect::MakeWH(scaledSize.width(), scaledSize.height()).contains(subset)) { - return false; - } - return this->onGenerateScaledPixels(scaledSize, subsetOrigin, subsetPixels); +sk_sp SkImageGenerator::onGenerateTexture(GrContext*, const SkImageInfo&, + const SkIPoint&) { + return nullptr; } +#endif ///////////////////////////////////////////////////////////////////////////////////////////// -SkData* SkImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { +SkData* SkImageGenerator::onRefEncodedData(GrContext* ctx) { return nullptr; } @@ -123,97 +120,26 @@ bool SkImageGenerator::onGetPixels(const SkImageInfo& info, void* dst, size_t rb #include "SkBitmap.h" #include "SkColorTable.h" -static bool reset_and_return_false(SkBitmap* bitmap) { - bitmap->reset(); - return false; -} - -bool SkImageGenerator::tryGenerateBitmap(SkBitmap* bitmap, const SkImageInfo* infoPtr, - SkBitmap::Allocator* allocator) { - SkImageInfo info = infoPtr ? *infoPtr : this->getInfo(); - if (0 == info.getSafeSize(info.minRowBytes())) { - return false; - } - if (!bitmap->setInfo(info)) { - return reset_and_return_false(bitmap); - } - - SkPMColor ctStorage[256]; - memset(ctStorage, 0xFF, sizeof(ctStorage)); // init with opaque-white for the moment - SkAutoTUnref ctable(new SkColorTable(ctStorage, 256)); - if (!bitmap->tryAllocPixels(allocator, ctable)) { - // SkResourceCache's custom allcator can'thandle ctables, so it may fail on - // kIndex_8_SkColorTable. - // https://bug.skia.org/4355 -#if 1 - // ignroe the allocator, and see if we can succeed without it - if (!bitmap->tryAllocPixels(nullptr, ctable)) { - return reset_and_return_false(bitmap); - } -#else - // this is the up-scale technique, not fully debugged, but we keep it here at the moment - // to remind ourselves that this might be better than ignoring the allocator. - - info = SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType()); - if (!bitmap->setInfo(info)) { - return reset_and_return_false(bitmap); - } - // we pass nullptr for the ctable arg, since we are now explicitly N32 - if (!bitmap->tryAllocPixels(allocator, nullptr)) { - return reset_and_return_false(bitmap); - } -#endif - } - - bitmap->lockPixels(); - if (!bitmap->getPixels()) { - return reset_and_return_false(bitmap); - } - - int ctCount = 0; - if (!this->getPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), - ctStorage, &ctCount)) { - return reset_and_return_false(bitmap); - } - - if (ctCount > 0) { - SkASSERT(kIndex_8_SkColorType == bitmap->colorType()); - // we and bitmap should be owners - SkASSERT(!ctable->unique()); - - // Now we need to overwrite the ctable we built earlier, with the correct colors. - // This does mean that we may have made the table too big, but that cannot be avoided - // until we can change SkImageGenerator's API to return us the ctable *before* we have to - // allocate space for all the pixels. - ctable->dangerous_overwriteColors(ctStorage, ctCount); - } else { - SkASSERT(kIndex_8_SkColorType != bitmap->colorType()); - // we should be the only owner - SkASSERT(ctable->unique()); - } - return true; -} - #include "SkGraphics.h" -static SkGraphics::ImageGeneratorFromEncodedFactory gFactory; +static SkGraphics::ImageGeneratorFromEncodedDataFactory gFactory; -SkGraphics::ImageGeneratorFromEncodedFactory -SkGraphics::SetImageGeneratorFromEncodedFactory(ImageGeneratorFromEncodedFactory factory) +SkGraphics::ImageGeneratorFromEncodedDataFactory +SkGraphics::SetImageGeneratorFromEncodedDataFactory(ImageGeneratorFromEncodedDataFactory factory) { - ImageGeneratorFromEncodedFactory prev = gFactory; + ImageGeneratorFromEncodedDataFactory prev = gFactory; gFactory = factory; return prev; } -SkImageGenerator* SkImageGenerator::NewFromEncoded(SkData* data) { - if (nullptr == data) { +std::unique_ptr SkImageGenerator::MakeFromEncoded(sk_sp data) { + if (!data) { return nullptr; } if (gFactory) { - if (SkImageGenerator* generator = gFactory(data)) { + if (std::unique_ptr generator = gFactory(data)) { return generator; } } - return SkImageGenerator::NewFromEncodedImpl(data); + return SkImageGenerator::MakeFromEncodedImpl(std::move(data)); } diff --git a/gfx/skia/skia/src/core/SkImageGeneratorPriv.h b/gfx/skia/skia/src/core/SkImageGeneratorPriv.h deleted file mode 100644 index 93114e328fb5..000000000000 --- a/gfx/skia/skia/src/core/SkImageGeneratorPriv.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkImageGeneratorPriv_DEFINED -#define SkImageGeneratorPriv_DEFINED - -#include "SkImageGenerator.h" -#include "SkDiscardableMemory.h" - -/** - * Takes ownership of SkImageGenerator. If this method fails for - * whatever reason, it will return false and immediatetely delete - * the generator. If it succeeds, it will modify destination - * bitmap. - * - * If generator is nullptr, will safely return false. - * - * If this fails or when the SkDiscardablePixelRef that is - * installed into destination is destroyed, it will call - * `delete` on the generator. Therefore, generator should be - * allocated with `new`. - * - * @param destination Upon success, this bitmap will be - * configured and have a pixelref installed. - * - * @param factory If not nullptr, this object will be used as a - * source of discardable memory when decoding. If nullptr, then - * SkDiscardableMemory::Create() will be called. - * - * @return true iff successful. - */ -bool SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator*, const SkIRect* subset, - SkBitmap* destination, - SkDiscardableMemory::Factory* factory); - -#endif diff --git a/gfx/skia/skia/src/core/SkImageInfo.cpp b/gfx/skia/skia/src/core/SkImageInfo.cpp index 75c6807d17fc..5d0710dc1f88 100644 --- a/gfx/skia/skia/src/core/SkImageInfo.cpp +++ b/gfx/skia/skia/src/core/SkImageInfo.cpp @@ -19,7 +19,7 @@ static bool color_type_is_valid(SkColorType colorType) { SkImageInfo SkImageInfo::MakeS32(int width, int height, SkAlphaType at) { return SkImageInfo(width, height, kN32_SkColorType, at, - SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)); + SkColorSpace::MakeSRGB()); } static const int kColorTypeMask = 0x0F; @@ -98,17 +98,10 @@ bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType, #include "SkReadPixelsRec.h" bool SkReadPixelsRec::trim(int srcWidth, int srcHeight) { - switch (fInfo.colorType()) { - case kUnknown_SkColorType: - case kIndex_8_SkColorType: - return false; - default: - break; - } if (nullptr == fPixels || fRowBytes < fInfo.minRowBytes()) { return false; } - if (0 == fInfo.width() || 0 == fInfo.height()) { + if (0 >= fInfo.width() || 0 >= fInfo.height()) { return false; } @@ -135,3 +128,39 @@ bool SkReadPixelsRec::trim(int srcWidth, int srcHeight) { return true; } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "SkWritePixelsRec.h" + +bool SkWritePixelsRec::trim(int dstWidth, int dstHeight) { + if (nullptr == fPixels || fRowBytes < fInfo.minRowBytes()) { + return false; + } + if (0 >= fInfo.width() || 0 >= fInfo.height()) { + return false; + } + + int x = fX; + int y = fY; + SkIRect dstR = SkIRect::MakeXYWH(x, y, fInfo.width(), fInfo.height()); + if (!dstR.intersect(0, 0, dstWidth, dstHeight)) { + return false; + } + + // if x or y are negative, then we have to adjust pixels + if (x > 0) { + x = 0; + } + if (y > 0) { + y = 0; + } + // here x,y are either 0 or negative + fPixels = ((const char*)fPixels - y * fRowBytes - x * fInfo.bytesPerPixel()); + // the intersect may have shrunk info's logical size + fInfo = fInfo.makeWH(dstR.width(), dstR.height()); + fX = dstR.x(); + fY = dstR.y(); + + return true; +} diff --git a/gfx/skia/skia/src/core/SkImageInfoPriv.h b/gfx/skia/skia/src/core/SkImageInfoPriv.h new file mode 100644 index 000000000000..855e506bb2c0 --- /dev/null +++ b/gfx/skia/skia/src/core/SkImageInfoPriv.h @@ -0,0 +1,112 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageInfoPriv_DEFINED +#define SkImageInfoPriv_DEFINED + +#include "SkImageInfo.h" + +/** + * Returns true if |info| contains a valid combination of width, height, colorType, alphaType, + * colorSpace. Returns false otherwise. + */ +static inline bool SkImageInfoIsValid(const SkImageInfo& info) { + if (info.width() <= 0 || info.height() <= 0) { + return false; + } + + const int kMaxDimension = SK_MaxS32 >> 2; + if (info.width() > kMaxDimension || info.height() > kMaxDimension) { + return false; + } + + if (kUnknown_SkColorType == info.colorType() || kUnknown_SkAlphaType == info.alphaType()) { + return false; + } + + if (kOpaque_SkAlphaType != info.alphaType() && + (kRGB_565_SkColorType == info.colorType() || kGray_8_SkColorType == info.colorType())) { + return false; + } + + if (kRGBA_F16_SkColorType == info.colorType() && + (!info.colorSpace() || !info.colorSpace()->gammaIsLinear())) { + return false; + } + + if (info.colorSpace() && + (!info.colorSpace()->gammaCloseToSRGB() && !info.colorSpace()->gammaIsLinear())) { + return false; + } + + return true; +} + +/** + * Returns true if Skia has defined a pixel conversion from the |src| to the |dst|. + * Returns false otherwise. Some discussion of false cases: + * We will not convert to kIndex8 unless it exactly matches the src, since color tables + * are immutable. + * We do not convert to kGray8 when the |src| is not kGray8 in the same color space. + * We may add this feature - it just requires some work to convert to luminance while + * handling color spaces correctly. Currently no one is asking for this. + * We will not convert from kAlpha8 when the |dst| is not kAlpha8. This would require + * inventing color information. + * We will not convert to kOpaque when the |src| is not kOpaque. This could be + * implemented to set all the alpha values to 1, but there is still some ambiguity - + * should we use kPremul or kUnpremul color values with the opaque alphas? Or should + * we just use whatever the |src| alpha is? In the future, we could choose to clearly + * define this, but currently no one is asking for this feature. + * We will not convert to a particular color space if |src| is nullptr. The color space + * conversion is not well-defined. + */ +static inline bool SkImageInfoValidConversion(const SkImageInfo& dst, const SkImageInfo& src) { + if (!SkImageInfoIsValid(dst) || !SkImageInfoIsValid(src)) { + return false; + } + + if (kIndex_8_SkColorType == dst.colorType()) { + if (kIndex_8_SkColorType != src.colorType()) { + return false; + } + + if ((kPremul_SkAlphaType == dst.alphaType() && kUnpremul_SkAlphaType == src.alphaType()) || + (kUnpremul_SkAlphaType == dst.alphaType() && kPremul_SkAlphaType == src.alphaType())) + { + return false; + } + + if (dst.colorSpace() && !SkColorSpace::Equals(dst.colorSpace(), src.colorSpace())) { + return false; + } + } + + if (kGray_8_SkColorType == dst.colorType()) { + if (kGray_8_SkColorType != src.colorType()) { + return false; + } + + if (dst.colorSpace() && !SkColorSpace::Equals(dst.colorSpace(), src.colorSpace())) { + return false; + } + } + + if (kAlpha_8_SkColorType != dst.colorType() && kAlpha_8_SkColorType == src.colorType()) { + return false; + } + + if (kOpaque_SkAlphaType == dst.alphaType() && kOpaque_SkAlphaType != src.alphaType()) { + return false; + } + + if (dst.colorSpace() && !src.colorSpace()) { + return false; + } + + return true; +} +#endif // SkImageInfoPriv_DEFINED diff --git a/gfx/skia/skia/src/core/SkImagePriv.h b/gfx/skia/skia/src/core/SkImagePriv.h index 8e2f5cecde21..921fdc85c8cf 100644 --- a/gfx/skia/skia/src/core/SkImagePriv.h +++ b/gfx/skia/skia/src/core/SkImagePriv.h @@ -9,7 +9,6 @@ #define SkImagePriv_DEFINED #include "SkImage.h" -#include "SkSmallAllocator.h" #include "SkSurface.h" enum SkCopyPixelsMode { @@ -18,25 +17,13 @@ enum SkCopyPixelsMode { kNever_SkCopyPixelsMode, //!< never copy src pixels (even if they are marked mutable) }; +// A good size for creating shader contexts on the stack. enum {kSkBlitterContextSize = 3332}; -// Commonly used allocator. It currently is only used to allocate up to 3 objects. The total -// bytes requested is calculated using one of our large shaders, its context size plus the size of -// an Sk3DBlitter in SkDraw.cpp -// Note that some contexts may contain other contexts (e.g. for compose shaders), but we've not -// yet found a situation where the size below isn't big enough. -typedef SkSmallAllocator<3, kSkBlitterContextSize> SkTBlitterAllocator; - // If alloc is non-nullptr, it will be used to allocate the returned SkShader, and MUST outlive // the SkShader. sk_sp SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode, SkShader::TileMode, - const SkMatrix* localMatrix, SkCopyPixelsMode, - SkTBlitterAllocator* alloc); - -// Call this if you explicitly want to use/share this pixelRef in the image -extern sk_sp SkMakeImageFromPixelRef(const SkImageInfo&, SkPixelRef*, - const SkIPoint& pixelRefOrigin, - size_t rowBytes); + const SkMatrix* localMatrix, SkCopyPixelsMode); /** * Examines the bitmap to decide if it can share the existing pixelRef, or @@ -56,20 +43,13 @@ extern sk_sp SkMakeImageFromPixelRef(const SkImageInfo&, SkPixelRef*, * SkImageInfo, or the bitmap's pixels cannot be accessed, this will return * nullptr. */ -extern sk_sp SkMakeImageFromRasterBitmap(const SkBitmap&, SkCopyPixelsMode, - SkTBlitterAllocator* = nullptr); +extern sk_sp SkMakeImageFromRasterBitmap(const SkBitmap&, SkCopyPixelsMode); // Given an image created from SkNewImageFromBitmap, return its pixelref. This // may be called to see if the surface and the image share the same pixelref, // in which case the surface may need to perform a copy-on-write. extern const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* rasterImage); -// When a texture is shared by a surface and an image its budgeted status is that of the -// surface. This function is used when the surface makes a new texture for itself in order -// for the orphaned image to determine whether the original texture counts against the -// budget or not. -extern void SkTextureImageApplyBudgetedDecision(SkImage* textureImage); - // Update the texture wrapped by an image created with NewTexture. This // is called when a surface and image share the same GrTexture and the // surface needs to perform a copy-on-write @@ -81,23 +61,31 @@ extern void SkTextureImageSetTexture(SkImage* image, GrTexture* texture); * src). In particular this is intended to use the texture even if the image's original content * changes subsequent to this call (i.e. the src is mutable!). * - * This must be balanced by an equal number of calls to SkImage_unpinAsTexture() -- calls can be - * nested. + * All successful calls must be balanced by an equal number of calls to SkImage_unpinAsTexture(). * * Once in this "pinned" state, the image has all of the same thread restrictions that exist * for a natively created gpu image (e.g. SkImage::MakeFromTexture) * - all drawing, pinning, unpinning must happen in the same thread as the GrContext. + * + * @return true if the image was successfully uploaded and locked into a texture */ -void SkImage_pinAsTexture(const SkImage*, GrContext*); +bool SkImage_pinAsTexture(const SkImage*, GrContext*); /** - * The balancing call to SkImage_pinAsTexture. When a balanced number of calls have been made, then - * the "pinned" texture is free to be purged, etc. This also means that a subsequent "pin" call - * will look at the original content again, and if its uniqueID/generationID has changed, then - * a newer texture will be uploaded/pinned. + * The balancing call to a successful invokation of SkImage_pinAsTexture. When a balanced number of + * calls have been made, then the "pinned" texture is free to be purged, etc. This also means that a + * subsequent "pin" call will look at the original content again, and if its uniqueID/generationID + * has changed, then a newer texture will be uploaded/pinned. * * The context passed to unpin must match the one passed to pin. */ void SkImage_unpinAsTexture(const SkImage*, GrContext*); +/** + * Returns a new image containing the same pixel values as the source, but with a different color + * space assigned. This performs no color space conversion. Primarily used in tests, to visualize + * the results of rendering in wide or narrow gamuts. + */ +sk_sp SkImageMakeRasterCopyAndAssignColorSpace(const SkImage*, SkColorSpace*); + #endif diff --git a/gfx/skia/skia/src/core/SkLRUCache.h b/gfx/skia/skia/src/core/SkLRUCache.h new file mode 100644 index 000000000000..7f3805cf2873 --- /dev/null +++ b/gfx/skia/skia/src/core/SkLRUCache.h @@ -0,0 +1,115 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkLRUCache_DEFINED +#define SkLRUCache_DEFINED + +#include "SkChecksum.h" +#include "SkTHash.h" +#include "SkTInternalLList.h" + +/** + * A generic LRU cache. + */ +template +class SkLRUCache : public SkNoncopyable { +private: + struct Entry { + Entry(const K& key, V&& value) + : fKey(key) + , fValue(std::move(value)) {} + + K fKey; + V fValue; + + SK_DECLARE_INTERNAL_LLIST_INTERFACE(Entry); + }; + +public: + explicit SkLRUCache(int maxCount) + : fMaxCount(maxCount) {} + + ~SkLRUCache() { + Entry* node = fLRU.head(); + while (node) { + fLRU.remove(node); + delete node; + node = fLRU.head(); + } + } + + V* find(const K& key) { + Entry** value = fMap.find(key); + if (!value) { + return nullptr; + } + Entry* entry = *value; + if (entry != fLRU.head()) { + fLRU.remove(entry); + fLRU.addToHead(entry); + } // else it's already at head position, don't need to do anything + return &entry->fValue; + } + + V* insert(const K& key, V value) { + Entry* entry = new Entry(key, std::move(value)); + fMap.set(entry); + fLRU.addToHead(entry); + while (fMap.count() > fMaxCount) { + this->remove(fLRU.tail()->fKey); + } + return &entry->fValue; + } + + int count() { + return fMap.count(); + } + + template // f(V*) + void foreach(Fn&& fn) { + typename SkTInternalLList::Iter iter; + for (Entry* e = iter.init(fLRU, SkTInternalLList::Iter::kHead_IterStart); e; + e = iter.next()) { + fn(&e->fValue); + } + } + + void reset() { + fMap.reset(); + for (Entry* e = fLRU.head(); e; e = fLRU.head()) { + fLRU.remove(e); + delete e; + } + } + +private: + struct Traits { + static const K& GetKey(Entry* e) { + return e->fKey; + } + + static uint32_t Hash(const K& k) { + return HashK()(k); + } + }; + + void remove(const K& key) { + Entry** value = fMap.find(key); + SkASSERT(value); + Entry* entry = *value; + SkASSERT(key == entry->fKey); + fMap.remove(key); + fLRU.remove(entry); + delete entry; + } + + int fMaxCount; + SkTHashTable fMap; + SkTInternalLList fLRU; +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkLightingShader.cpp b/gfx/skia/skia/src/core/SkLightingShader.cpp index 9030a192b477..1c8b1b4f58fe 100644 --- a/gfx/skia/skia/src/core/SkLightingShader.cpp +++ b/gfx/skia/skia/src/core/SkLightingShader.cpp @@ -5,11 +5,11 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkBitmapProcShader.h" #include "SkBitmapProcState.h" #include "SkColor.h" #include "SkEmptyShader.h" -#include "SkErrorInternals.h" #include "SkLightingShader.h" #include "SkMathPriv.h" #include "SkNormalSource.h" @@ -64,8 +64,6 @@ public: SkShader::Context* diffuseContext, SkNormalSource::Provider*, void* heapAllocated); - ~LightingShaderContext() override; - void shadeSpan(int x, int y, SkPMColor[], int count) override; uint32_t getFlags() const override { return fFlags; } @@ -76,8 +74,6 @@ public: SkColor fPaintColor; uint32_t fFlags; - void* fHeapAllocated; - typedef SkShader::Context INHERITED; }; @@ -86,8 +82,7 @@ public: protected: void flatten(SkWriteBuffer&) const override; - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec&, void*) const override; + Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override; private: sk_sp fDiffuseShader; @@ -105,22 +100,19 @@ private: #include "GrCoordTransform.h" #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" -#include "GrTextureAccess.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" #include "SkGr.h" -#include "SkGrPriv.h" // This FP expects a premul'd color input for its diffuse color. Premul'ing of the paint's color is // handled by the asFragmentProcessor() factory, but shaders providing diffuse color must output it // premul'd. class LightingFP : public GrFragmentProcessor { public: - LightingFP(sk_sp normalFP, sk_sp lights) { - + LightingFP(sk_sp normalFP, sk_sp lights) + : INHERITED(kPreservesOpaqueInput_OptimizationFlag) { // fuse all ambient lights into a single one fAmbientColor = lights->ambientLightColor(); for (int i = 0; i < lights->numLights(); ++i) { @@ -201,14 +193,14 @@ public: "diffuseColor.a);", args.fOutputColor); } - static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { + static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const LightingFP& lightingFP = proc.cast(); b->add32(lightingFP.fDirectionalLights.count()); } protected: - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) override { const LightingFP& lightingFP = proc.cast(); const SkTArray& directionalLights = lightingFP.directionalLights(); @@ -242,16 +234,12 @@ public: GrGLSLProgramDataManager::UniformHandle fAmbientColorUni; }; - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLLightingFP::GenKey(*this, caps, b); } const char* name() const override { return "LightingFP"; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->mulByUnknownFourComponents(); - } - const SkTArray& directionalLights() const { return fDirectionalLights; } const SkColor3f& ambientColor() const { return fAmbientColor; } @@ -266,6 +254,8 @@ private: SkTArray fDirectionalLights; SkColor3f fAmbientColor; + + typedef GrFragmentProcessor INHERITED; }; //////////////////////////////////////////////////////////////////////////// @@ -310,8 +300,7 @@ SkLightingShaderImpl::LightingShaderContext::LightingShaderContext( void* heapAllocated) : INHERITED(shader, rec) , fDiffuseContext(diffuseContext) - , fNormalProvider(normalProvider) - , fHeapAllocated(heapAllocated) { + , fNormalProvider(normalProvider) { bool isOpaque = shader.isOpaque(); // update fFlags @@ -324,17 +313,6 @@ SkLightingShaderImpl::LightingShaderContext::LightingShaderContext( fFlags = flags; } -SkLightingShaderImpl::LightingShaderContext::~LightingShaderContext() { - // The dependencies have been created outside of the context on memory that was allocated by - // the onCreateContext() method. Call the destructors and free the memory. - if (fDiffuseContext) { - fDiffuseContext->~Context(); - } - fNormalProvider->~Provider(); - - sk_free(fHeapAllocated); -} - static inline SkPMColor convert(SkColor3f color, U8CPU a) { if (color.fX <= 0.0f) { color.fX = 0.0f; @@ -458,39 +436,23 @@ void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const { } } -size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const { - return sizeof(LightingShaderContext); -} - -SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, - void* storage) const { - size_t heapRequired = (fDiffuseShader ? fDiffuseShader->contextSize(rec) : 0) + - fNormalSource->providerSize(rec); - void* heapAllocated = sk_malloc_throw(heapRequired); - - void* diffuseContextStorage = heapAllocated; - void* normalProviderStorage = (char*) diffuseContextStorage + - (fDiffuseShader ? fDiffuseShader->contextSize(rec) : 0); - +SkShader::Context* SkLightingShaderImpl::onMakeContext( + const ContextRec& rec, SkArenaAlloc* alloc) const +{ SkShader::Context *diffuseContext = nullptr; if (fDiffuseShader) { - diffuseContext = fDiffuseShader->createContext(rec, diffuseContextStorage); + diffuseContext = fDiffuseShader->makeContext(rec, alloc); if (!diffuseContext) { - sk_free(heapAllocated); return nullptr; } } - SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, - normalProviderStorage); + SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, alloc); if (!normalProvider) { - diffuseContext->~Context(); - sk_free(heapAllocated); return nullptr; } - return new (storage) LightingShaderContext(*this, rec, diffuseContext, normalProvider, - heapAllocated); + return alloc->make(*this, rec, diffuseContext, normalProvider, nullptr); } /////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/core/SkLinearBitmapPipeline.cpp b/gfx/skia/skia/src/core/SkLinearBitmapPipeline.cpp index 401eb41b79dd..2878f19a9fb5 100644 --- a/gfx/skia/skia/src/core/SkLinearBitmapPipeline.cpp +++ b/gfx/skia/skia/src/core/SkLinearBitmapPipeline.cpp @@ -12,6 +12,7 @@ #include #include +#include "SkArenaAlloc.h" #include "SkLinearBitmapPipeline_core.h" #include "SkLinearBitmapPipeline_matrix.h" #include "SkLinearBitmapPipeline_tile.h" @@ -20,53 +21,6 @@ #include "SkOpts.h" #include "SkPM4f.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// SkLinearBitmapPipeline::Stage -template -SkLinearBitmapPipeline::Stage::~Stage() { - if (fIsInitialized) { - this->get()->~Base(); - } -} - -template -template -void SkLinearBitmapPipeline::Stage::initStage(Next* next, Args&& ... args) { - SkASSERTF(sizeof(Variant) <= sizeof(fSpace), - "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace)); - - new (&fSpace) Variant(next, std::forward(args)...); - fStageCloner = [this](Next* nextClone, void* addr) { - new (addr) Variant(nextClone, (const Variant&)*this->get()); - }; - fIsInitialized = true; -}; - -template -template -void SkLinearBitmapPipeline::Stage::initSink(Args&& ... args) { - SkASSERTF(sizeof(Variant) <= sizeof(fSpace), - "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace)); - new (&fSpace) Variant(std::forward(args)...); - fIsInitialized = true; -}; - -template -template -To* SkLinearBitmapPipeline::Stage::getInterface() { - From* down = static_cast(this->get()); - return static_cast(down); -} - -template -Base* SkLinearBitmapPipeline::Stage::cloneStageTo( - Next* next, Stage* cloneToStage) const -{ - if (!fIsInitialized) return nullptr; - fStageCloner(next, &cloneToStage->fSpace); - return cloneToStage->get(); -} - namespace { //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -88,9 +42,9 @@ public: : fNext{next} , fStrategy{std::forward(args)...}{ } - MatrixStage(Next* next, const MatrixStage& stage) + MatrixStage(Next* next, MatrixStage* stage) : fNext{next} - , fStrategy{stage.fStrategy} { } + , fStrategy{stage->fStrategy} { } void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { fStrategy.processPoints(&xs, &ys); @@ -128,39 +82,6 @@ template using PerspectiveMatrix = MatrixStage; -static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( - SkLinearBitmapPipeline::PointProcessorInterface* next, - const SkMatrix& inverse, - SkLinearBitmapPipeline::MatrixStage* matrixProc) { - if (inverse.hasPerspective()) { - matrixProc->initStage>( - next, - SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, - SkVector{inverse.getScaleX(), inverse.getScaleY()}, - SkVector{inverse.getSkewX(), inverse.getSkewY()}, - SkVector{inverse.getPerspX(), inverse.getPerspY()}, - inverse.get(SkMatrix::kMPersp2)); - } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { - matrixProc->initStage>( - next, - SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, - SkVector{inverse.getScaleX(), inverse.getScaleY()}, - SkVector{inverse.getSkewX(), inverse.getSkewY()}); - } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) { - matrixProc->initStage>( - next, - SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, - SkVector{inverse.getScaleX(), inverse.getScaleY()}); - } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) { - matrixProc->initStage>( - next, - SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); - } else { - return next; - } - return matrixProc->get(); -} - //////////////////////////////////////////////////////////////////////////////////////////////////// // Tile Stage @@ -172,10 +93,10 @@ public: , fXStrategy{dimensions.width()} , fYStrategy{dimensions.height()}{ } - CombinedTileStage(Next* next, const CombinedTileStage& stage) + CombinedTileStage(Next* next, CombinedTileStage* stage) : fNext{next} - , fXStrategy{stage.fXStrategy} - , fYStrategy{stage.fYStrategy} { } + , fXStrategy{stage->fXStrategy} + , fYStrategy{stage->fYStrategy} { } void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { fXStrategy.tileXPoints(&xs); @@ -219,60 +140,6 @@ private: YStrategy fYStrategy; }; -template -void choose_tiler_ymode( - SkShader::TileMode yMode, SkFilterQuality filterQuality, SkISize dimensions, - Next* next, - SkLinearBitmapPipeline::TileStage* tileStage) { - switch (yMode) { - case SkShader::kClamp_TileMode: { - using Tiler = CombinedTileStage; - tileStage->initStage(next, dimensions); - break; - } - case SkShader::kRepeat_TileMode: { - using Tiler = CombinedTileStage; - tileStage->initStage(next, dimensions); - break; - } - case SkShader::kMirror_TileMode: { - using Tiler = CombinedTileStage; - tileStage->initStage(next, dimensions); - break; - } - } -}; - -static SkLinearBitmapPipeline::PointProcessorInterface* choose_tiler( - SkLinearBitmapPipeline::SampleProcessorInterface* next, - SkISize dimensions, - SkShader::TileMode xMode, - SkShader::TileMode yMode, - SkFilterQuality filterQuality, - SkScalar dx, - SkLinearBitmapPipeline::TileStage* tileStage) -{ - switch (xMode) { - case SkShader::kClamp_TileMode: - choose_tiler_ymode(yMode, filterQuality, dimensions, next, tileStage); - break; - case SkShader::kRepeat_TileMode: - if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) { - choose_tiler_ymode( - yMode, kNone_SkFilterQuality, dimensions, next, tileStage); - } else { - choose_tiler_ymode( - yMode, filterQuality, dimensions, next, tileStage); - } - break; - case SkShader::kMirror_TileMode: - choose_tiler_ymode(yMode, filterQuality, dimensions, next, tileStage); - break; - } - - return tileStage->get(); -} - //////////////////////////////////////////////////////////////////////////////////////////////////// // Specialized Samplers @@ -423,138 +290,10 @@ private: using Blender = SkLinearBitmapPipeline::BlendProcessorInterface; -template -static SkLinearBitmapPipeline::PixelAccessorInterface* choose_specific_accessor( - const SkPixmap& srcPixmap, SkLinearBitmapPipeline::Accessor* accessor) -{ - if (srcPixmap.info().gammaCloseToSRGB()) { - using PA = PixelAccessor; - accessor->init(srcPixmap); - return accessor->get(); - } else { - using PA = PixelAccessor; - accessor->init(srcPixmap); - return accessor->get(); - } -} - -static SkLinearBitmapPipeline::PixelAccessorInterface* choose_pixel_accessor( - const SkPixmap& srcPixmap, - const SkColor A8TintColor, - SkLinearBitmapPipeline::Accessor* accessor) -{ - const SkImageInfo& imageInfo = srcPixmap.info(); - - SkLinearBitmapPipeline::PixelAccessorInterface* pixelAccessor = nullptr; - switch (imageInfo.colorType()) { - case kAlpha_8_SkColorType: { - using PA = PixelAccessor; - accessor->init(srcPixmap, A8TintColor); - pixelAccessor = accessor->get(); - } - break; - case kARGB_4444_SkColorType: - pixelAccessor = choose_specific_accessor(srcPixmap, accessor); - break; - case kRGB_565_SkColorType: - pixelAccessor = choose_specific_accessor(srcPixmap, accessor); - break; - case kRGBA_8888_SkColorType: - pixelAccessor = choose_specific_accessor(srcPixmap, accessor); - break; - case kBGRA_8888_SkColorType: - pixelAccessor = choose_specific_accessor(srcPixmap, accessor); - break; - case kIndex_8_SkColorType: - pixelAccessor = choose_specific_accessor(srcPixmap, accessor); - break; - case kGray_8_SkColorType: - pixelAccessor = choose_specific_accessor(srcPixmap, accessor); - break; - case kRGBA_F16_SkColorType: { - using PA = PixelAccessor; - accessor->init(srcPixmap); - pixelAccessor = accessor->get(); - } - break; - default: - SkFAIL("Not implemented. Unsupported src"); - break; - } - - return pixelAccessor; -} - -SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler( - Blender* next, - SkFilterQuality filterQuality, - SkShader::TileMode xTile, SkShader::TileMode yTile, - const SkPixmap& srcPixmap, - const SkColor A8TintColor, - SkLinearBitmapPipeline::SampleStage* sampleStage, - SkLinearBitmapPipeline::Accessor* accessor) { - const SkImageInfo& imageInfo = srcPixmap.info(); - SkISize dimensions = imageInfo.dimensions(); - - // Special case samplers with fully expanded templates - if (imageInfo.gammaCloseToSRGB()) { - if (filterQuality == kNone_SkFilterQuality) { - switch (imageInfo.colorType()) { - case kN32_SkColorType: { - using S = - NearestNeighborSampler< - PixelAccessor, Blender>; - sampleStage->initStage(next, srcPixmap); - return sampleStage->get(); - } - case kIndex_8_SkColorType: { - using S = - NearestNeighborSampler< - PixelAccessor, Blender>; - sampleStage->initStage(next, srcPixmap); - return sampleStage->get(); - } - default: - break; - } - } else { - switch (imageInfo.colorType()) { - case kN32_SkColorType: { - using S = - BilerpSampler< - PixelAccessor, Blender>; - sampleStage->initStage(next, dimensions, xTile, yTile, srcPixmap); - return sampleStage->get(); - } - case kIndex_8_SkColorType: { - using S = - BilerpSampler< - PixelAccessor, Blender>; - sampleStage->initStage(next, dimensions, xTile, yTile, srcPixmap); - return sampleStage->get(); - } - default: - break; - } - } - } - - auto pixelAccessor = choose_pixel_accessor(srcPixmap, A8TintColor, accessor); - // General cases. - if (filterQuality == kNone_SkFilterQuality) { - using S = NearestNeighborSampler; - sampleStage->initStage(next, pixelAccessor); - } else { - using S = BilerpSampler; - sampleStage->initStage(next, dimensions, xTile, yTile, pixelAccessor); - } - return sampleStage->get(); -} - //////////////////////////////////////////////////////////////////////////////////////////////////// // Pixel Blender Stage template -class SrcFPPixel final : public SkLinearBitmapPipeline::BlendProcessorInterface { +class SrcFPPixel final : public Blender { public: SrcFPPixel(float postAlpha) : fPostAlpha{postAlpha} { } SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {} @@ -597,22 +336,9 @@ private: SkPM4f* fDst; SkPM4f* fEnd; - Sk4f fPostAlpha; + float fPostAlpha; }; -static SkLinearBitmapPipeline::BlendProcessorInterface* choose_blender_for_shading( - SkAlphaType alphaType, - float postAlpha, - SkLinearBitmapPipeline::BlenderStage* blenderStage) { - if (alphaType == kUnpremul_SkAlphaType) { - blenderStage->initSink>(postAlpha); - } else { - // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType - blenderStage->initSink>(postAlpha); - } - return blenderStage->get(); -} - } // namespace //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -624,7 +350,8 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline( SkFilterQuality filterQuality, SkShader::TileMode xTile, SkShader::TileMode yTile, SkColor paintColor, - const SkPixmap& srcPixmap) + const SkPixmap& srcPixmap, + SkArenaAlloc* allocator) { SkISize dimensions = srcPixmap.info().dimensions(); const SkImageInfo& srcImageInfo = srcPixmap.info(); @@ -652,80 +379,76 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline( float postAlpha = SkColorGetA(paintColor) * (1.0f / 255.0f); // As the stages are built, the chooser function may skip a stage. For example, with the // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage. - auto blenderStage = choose_blender_for_shading(alphaType, postAlpha, &fBlenderStage); - auto samplerStage = choose_pixel_sampler( - blenderStage, filterQuality, xTile, yTile, - srcPixmap, paintColor, &fSampleStage, &fAccessor); - auto tilerStage = choose_tiler(samplerStage, dimensions, xTile, yTile, - filterQuality, dx, &fTileStage); - fFirstStage = choose_matrix(tilerStage, adjustedInverse, &fMatrixStage); + auto blenderStage = this->chooseBlenderForShading(alphaType, postAlpha, allocator); + auto samplerStage = this->chooseSampler( + blenderStage, filterQuality, xTile, yTile, srcPixmap, paintColor, allocator); + auto tilerStage = this->chooseTiler( + samplerStage, dimensions, xTile, yTile, filterQuality, dx, allocator); + fFirstStage = this->chooseMatrix(tilerStage, adjustedInverse, allocator); fLastStage = blenderStage; } -bool SkLinearBitmapPipeline::ClonePipelineForBlitting( - SkEmbeddableLinearPipeline* pipelineStorage, - const SkLinearBitmapPipeline& pipeline, - SkMatrix::TypeMask matrixMask, - SkShader::TileMode xTileMode, - SkShader::TileMode yTileMode, - SkFilterQuality filterQuality, - const SkPixmap& srcPixmap, - float finalAlpha, - SkXfermode::Mode xferMode, - const SkImageInfo& dstInfo) -{ - if (xferMode == SkXfermode::kSrcOver_Mode - && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) { - xferMode = SkXfermode::kSrc_Mode; - } - - if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return false; } - if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return false; } - if (finalAlpha != 1.0f) { return false; } - if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType - || dstInfo.colorType() != kRGBA_8888_SkColorType) { return false; } - - if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) { - return false; - } - - if (xferMode != SkXfermode::kSrc_Mode && xferMode != SkXfermode::kSrcOver_Mode) { - return false; - } - - pipelineStorage->init(pipeline, srcPixmap, xferMode, dstInfo); - - return true; -} - SkLinearBitmapPipeline::SkLinearBitmapPipeline( const SkLinearBitmapPipeline& pipeline, const SkPixmap& srcPixmap, - SkXfermode::Mode mode, - const SkImageInfo& dstInfo) + SkBlendMode mode, + const SkImageInfo& dstInfo, + SkArenaAlloc* allocator) { - SkASSERT(mode == SkXfermode::kSrc_Mode || mode == SkXfermode::kSrcOver_Mode); + SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver); SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType() && srcPixmap.info().colorType() == kRGBA_8888_SkColorType); - if (mode == SkXfermode::kSrc_Mode) { - fSampleStage.initSink( + SampleProcessorInterface* sampleStage; + if (mode == SkBlendMode::kSrc) { + auto sampler = allocator->make( srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4); - fLastStage = fSampleStage.getInterface(); + sampleStage = sampler; + fLastStage = sampler; } else { - fSampleStage.initSink( + auto sampler = allocator->make( srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4); - fLastStage = fSampleStage.getInterface(); + sampleStage = sampler; + fLastStage = sampler; } - auto sampleStage = fSampleStage.get(); - auto tilerStage = pipeline.fTileStage.cloneStageTo(sampleStage, &fTileStage); - tilerStage = (tilerStage != nullptr) ? tilerStage : sampleStage; - auto matrixStage = pipeline.fMatrixStage.cloneStageTo(tilerStage, &fMatrixStage); - matrixStage = (matrixStage != nullptr) ? matrixStage : tilerStage; + auto tilerStage = pipeline.fTileStageCloner(sampleStage, allocator); + auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, allocator); fFirstStage = matrixStage; } +SkLinearBitmapPipeline* SkLinearBitmapPipeline::ClonePipelineForBlitting( + const SkLinearBitmapPipeline& pipeline, + SkMatrix::TypeMask matrixMask, + SkFilterQuality filterQuality, + const SkPixmap& srcPixmap, + float finalAlpha, + SkBlendMode blendMode, + const SkImageInfo& dstInfo, + SkArenaAlloc* allocator) +{ + if (blendMode == SkBlendMode::kSrcOver && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) { + blendMode = SkBlendMode::kSrc; + } + + if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return nullptr; } + if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return nullptr; } + if (finalAlpha != 1.0f) { return nullptr; } + if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType + || dstInfo.colorType() != kRGBA_8888_SkColorType) { return nullptr; } + + if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) { + return nullptr; + } + + if (blendMode != SkBlendMode::kSrc && blendMode != SkBlendMode::kSrcOver) { + return nullptr; + } + + return allocator->make( + pipeline, srcPixmap, blendMode, dstInfo, allocator); +} + void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { SkASSERT(count > 0); this->blitSpan(x, y, dst, count); @@ -741,3 +464,255 @@ void SkLinearBitmapPipeline::blitSpan(int x, int y, void* dst, int count) { // first pixel to the center of the last pixel. This implies that length is count-1. fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count}); } + +SkLinearBitmapPipeline::PointProcessorInterface* +SkLinearBitmapPipeline::chooseMatrix( + PointProcessorInterface* next, + const SkMatrix& inverse, + SkArenaAlloc* allocator) +{ + if (inverse.hasPerspective()) { + auto matrixStage = allocator->make>( + next, + SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, + SkVector{inverse.getScaleX(), inverse.getScaleY()}, + SkVector{inverse.getSkewX(), inverse.getSkewY()}, + SkVector{inverse.getPerspX(), inverse.getPerspY()}, + inverse.get(SkMatrix::kMPersp2)); + fMatrixStageCloner = + [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) { + return memory->make>(cloneNext, matrixStage); + }; + return matrixStage; + } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { + auto matrixStage = allocator->make>( + next, + SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, + SkVector{inverse.getScaleX(), inverse.getScaleY()}, + SkVector{inverse.getSkewX(), inverse.getSkewY()}); + fMatrixStageCloner = + [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) { + return memory->make>(cloneNext, matrixStage); + }; + return matrixStage; + } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) { + auto matrixStage = allocator->make>( + next, + SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, + SkVector{inverse.getScaleX(), inverse.getScaleY()}); + fMatrixStageCloner = + [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) { + return memory->make>(cloneNext, matrixStage); + }; + return matrixStage; + } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) { + auto matrixStage = allocator->make>( + next, + SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); + fMatrixStageCloner = + [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) { + return memory->make>(cloneNext, matrixStage); + }; + return matrixStage; + } else { + fMatrixStageCloner = [](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) { + return cloneNext; + }; + return next; + } +} + +template +SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::createTiler( + SampleProcessorInterface* next, + SkISize dimensions, + SkArenaAlloc* allocator) +{ + auto tilerStage = allocator->make(next, dimensions); + fTileStageCloner = + [tilerStage](SampleProcessorInterface* cloneNext, + SkArenaAlloc* memory) -> PointProcessorInterface* { + return memory->make(cloneNext, tilerStage); + }; + return tilerStage; +} + +template +SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTilerYMode( + SampleProcessorInterface* next, + SkShader::TileMode yMode, + SkISize dimensions, + SkArenaAlloc* allocator) +{ + switch (yMode) { + case SkShader::kClamp_TileMode: { + using Tiler = CombinedTileStage; + return this->createTiler(next, dimensions, allocator); + } + case SkShader::kRepeat_TileMode: { + using Tiler = CombinedTileStage; + return this->createTiler(next, dimensions, allocator); + } + case SkShader::kMirror_TileMode: { + using Tiler = CombinedTileStage; + return this->createTiler(next, dimensions, allocator); + } + } + + // Should never get here. + SkFAIL("Not all Y tile cases covered."); + return nullptr; +} + +SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTiler( + SampleProcessorInterface* next, + SkISize dimensions, + SkShader::TileMode xMode, + SkShader::TileMode yMode, + SkFilterQuality filterQuality, + SkScalar dx, + SkArenaAlloc* allocator) +{ + switch (xMode) { + case SkShader::kClamp_TileMode: + return this->chooseTilerYMode(next, yMode, dimensions, allocator); + case SkShader::kRepeat_TileMode: + if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) { + return this->chooseTilerYMode( + next, yMode, dimensions, allocator); + } else { + return this->chooseTilerYMode( + next, yMode, dimensions, allocator); + } + case SkShader::kMirror_TileMode: + return this->chooseTilerYMode(next, yMode, dimensions, allocator); + } + + // Should never get here. + SkFAIL("Not all X tile cases covered."); + return nullptr; +} + +template +SkLinearBitmapPipeline::PixelAccessorInterface* + SkLinearBitmapPipeline::chooseSpecificAccessor( + const SkPixmap& srcPixmap, + SkArenaAlloc* allocator) +{ + if (srcPixmap.info().gammaCloseToSRGB()) { + using Accessor = PixelAccessor; + return allocator->make(srcPixmap); + } else { + using Accessor = PixelAccessor; + return allocator->make(srcPixmap); + } +} + +SkLinearBitmapPipeline::PixelAccessorInterface* SkLinearBitmapPipeline::choosePixelAccessor( + const SkPixmap& srcPixmap, + const SkColor A8TintColor, + SkArenaAlloc* allocator) +{ + const SkImageInfo& imageInfo = srcPixmap.info(); + + switch (imageInfo.colorType()) { + case kAlpha_8_SkColorType: { + using Accessor = PixelAccessor; + return allocator->make(srcPixmap, A8TintColor); + } + case kARGB_4444_SkColorType: + return this->chooseSpecificAccessor(srcPixmap, allocator); + case kRGB_565_SkColorType: + return this->chooseSpecificAccessor(srcPixmap, allocator); + case kRGBA_8888_SkColorType: + return this->chooseSpecificAccessor(srcPixmap, allocator); + case kBGRA_8888_SkColorType: + return this->chooseSpecificAccessor(srcPixmap, allocator); + case kIndex_8_SkColorType: + return this->chooseSpecificAccessor(srcPixmap, allocator); + case kGray_8_SkColorType: + return this->chooseSpecificAccessor(srcPixmap, allocator); + case kRGBA_F16_SkColorType: { + using Accessor = PixelAccessor; + return allocator->make(srcPixmap); + } + default: + // Should never get here. + SkFAIL("Pixel source not supported."); + return nullptr; + } +} + +SkLinearBitmapPipeline::SampleProcessorInterface* SkLinearBitmapPipeline::chooseSampler( + Blender* next, + SkFilterQuality filterQuality, + SkShader::TileMode xTile, SkShader::TileMode yTile, + const SkPixmap& srcPixmap, + const SkColor A8TintColor, + SkArenaAlloc* allocator) +{ + const SkImageInfo& imageInfo = srcPixmap.info(); + SkISize dimensions = imageInfo.dimensions(); + + // Special case samplers with fully expanded templates + if (imageInfo.gammaCloseToSRGB()) { + if (filterQuality == kNone_SkFilterQuality) { + switch (imageInfo.colorType()) { + case kN32_SkColorType: { + using Sampler = + NearestNeighborSampler< + PixelAccessor, Blender>; + return allocator->make(next, srcPixmap); + } + case kIndex_8_SkColorType: { + using Sampler = + NearestNeighborSampler< + PixelAccessor, Blender>; + return allocator->make(next, srcPixmap); + } + default: + break; + } + } else { + switch (imageInfo.colorType()) { + case kN32_SkColorType: { + using Sampler = + BilerpSampler< + PixelAccessor, Blender>; + return allocator->make(next, dimensions, xTile, yTile, srcPixmap); + } + case kIndex_8_SkColorType: { + using Sampler = + BilerpSampler< + PixelAccessor, Blender>; + return allocator->make(next, dimensions, xTile, yTile, srcPixmap); + } + default: + break; + } + } + } + + auto pixelAccessor = this->choosePixelAccessor(srcPixmap, A8TintColor, allocator); + // General cases. + if (filterQuality == kNone_SkFilterQuality) { + using Sampler = NearestNeighborSampler; + return allocator->make(next, pixelAccessor); + } else { + using Sampler = BilerpSampler; + return allocator->make(next, dimensions, xTile, yTile, pixelAccessor); + } +} + +Blender* SkLinearBitmapPipeline::chooseBlenderForShading( + SkAlphaType alphaType, + float postAlpha, + SkArenaAlloc* allocator) +{ + if (alphaType == kUnpremul_SkAlphaType) { + return allocator->make>(postAlpha); + } else { + // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType + return allocator->make>(postAlpha); + } +} diff --git a/gfx/skia/skia/src/core/SkLinearBitmapPipeline.h b/gfx/skia/skia/src/core/SkLinearBitmapPipeline.h index 91b573df5d8c..8ce02009b296 100644 --- a/gfx/skia/skia/src/core/SkLinearBitmapPipeline.h +++ b/gfx/skia/skia/src/core/SkLinearBitmapPipeline.h @@ -8,6 +8,7 @@ #ifndef SkLinearBitmapPipeline_DEFINED #define SkLinearBitmapPipeline_DEFINED +#include "SkArenaAlloc.h" #include "SkColor.h" #include "SkImageInfo.h" #include "SkMatrix.h" @@ -32,150 +33,90 @@ public: SkFilterQuality filterQuality, SkShader::TileMode xTile, SkShader::TileMode yTile, SkColor paintColor, - const SkPixmap& srcPixmap); + const SkPixmap& srcPixmap, + SkArenaAlloc* allocator); SkLinearBitmapPipeline( const SkLinearBitmapPipeline& pipeline, const SkPixmap& srcPixmap, - SkXfermode::Mode xferMode, - const SkImageInfo& dstInfo); + SkBlendMode, + const SkImageInfo& dstInfo, + SkArenaAlloc* allocator); - static bool ClonePipelineForBlitting( - SkEmbeddableLinearPipeline* pipelineStorage, + static SkLinearBitmapPipeline* ClonePipelineForBlitting( const SkLinearBitmapPipeline& pipeline, SkMatrix::TypeMask matrixMask, - SkShader::TileMode xTileMode, - SkShader::TileMode yTileMode, SkFilterQuality filterQuality, const SkPixmap& srcPixmap, float finalAlpha, - SkXfermode::Mode xferMode, - const SkImageInfo& dstInfo); + SkBlendMode, + const SkImageInfo& dstInfo, + SkArenaAlloc* allocator); ~SkLinearBitmapPipeline(); void shadeSpan4f(int x, int y, SkPM4f* dst, int count); void blitSpan(int32_t x, int32_t y, void* dst, int count); - template - class Stage { - public: - Stage() : fIsInitialized{false} {} - ~Stage(); - - template - void initStage(Next* next, Args&& ... args); - - template - void initSink(Args&& ... args); - - template - To* getInterface(); - - // Copy this stage to `cloneToStage` with `next` as its next stage - // (not necessarily the same as our next, you see), returning `cloneToStage`. - // Note: There is no cloneSinkTo method because the code usually places the top part of - // the pipeline on a new sampler. - Base* cloneStageTo(Next* next, Stage* cloneToStage) const; - - Base* get() const { return reinterpret_cast(&fSpace); } - Base* operator->() const { return this->get(); } - Base& operator*() const { return *(this->get()); } - - private: - std::function fStageCloner; - struct SK_STRUCT_ALIGN(16) Space { - char space[kSize]; - }; - bool fIsInitialized; - mutable Space fSpace; - }; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// PolyMemory - template - class PolyMemory { - public: - PolyMemory() : fIsInitialized{false} { } - ~PolyMemory() { - if (fIsInitialized) { - this->get()->~Base(); - } - } - template - void init(Args&& ... args) { - SkASSERTF(sizeof(Variant) <= sizeof(fSpace), - "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace)); - - new (&fSpace) Variant(std::forward(args)...); - fIsInitialized = true; - } - - Base* get() const { return reinterpret_cast(&fSpace); } - Base* operator->() const { return this->get(); } - Base& operator*() const { return *(this->get()); } - - private: - struct SK_STRUCT_ALIGN(16) Space { - char space[kSize]; - }; - mutable Space fSpace; - bool fIsInitialized; - - }; - class PointProcessorInterface; class SampleProcessorInterface; class BlendProcessorInterface; class DestinationInterface; class PixelAccessorInterface; - // These values were generated by the assert above in Stage::init{Sink|Stage}. - using MatrixStage = Stage; - using TileStage = Stage; - using SampleStage = Stage; - using BlenderStage = Stage; - using Accessor = PolyMemory; + using MatrixCloner = + std::function; + using TilerCloner = + std::function; + + PointProcessorInterface* chooseMatrix( + PointProcessorInterface* next, + const SkMatrix& inverse, + SkArenaAlloc* allocator); + + template + PointProcessorInterface* createTiler(SampleProcessorInterface* next, SkISize dimensions, + SkArenaAlloc* allocator); + + template + PointProcessorInterface* chooseTilerYMode( + SampleProcessorInterface* next, SkShader::TileMode yMode, SkISize dimensions, + SkArenaAlloc* allocator); + + PointProcessorInterface* chooseTiler( + SampleProcessorInterface* next, + SkISize dimensions, + SkShader::TileMode xMode, SkShader::TileMode yMode, + SkFilterQuality filterQuality, + SkScalar dx, + SkArenaAlloc* allocator); + + template + PixelAccessorInterface* chooseSpecificAccessor(const SkPixmap& srcPixmap, + SkArenaAlloc* allocator); + + PixelAccessorInterface* choosePixelAccessor( + const SkPixmap& srcPixmap, + const SkColor A8TintColor, + SkArenaAlloc* allocator); + + SampleProcessorInterface* chooseSampler( + BlendProcessorInterface* next, + SkFilterQuality filterQuality, + SkShader::TileMode xTile, SkShader::TileMode yTile, + const SkPixmap& srcPixmap, + const SkColor A8TintColor, + SkArenaAlloc* allocator); + + BlendProcessorInterface* chooseBlenderForShading( + SkAlphaType alphaType, + float postAlpha, + SkArenaAlloc* allocator); -private: PointProcessorInterface* fFirstStage; - MatrixStage fMatrixStage; - TileStage fTileStage; - SampleStage fSampleStage; - BlenderStage fBlenderStage; + MatrixCloner fMatrixStageCloner; + TilerCloner fTileStageCloner; DestinationInterface* fLastStage; - Accessor fAccessor; -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// SkEmbeddableLinearPipeline - manage stricter alignment needs for SkLinearBitmapPipeline. -class SkEmbeddableLinearPipeline { -public: - SkEmbeddableLinearPipeline() { } - ~SkEmbeddableLinearPipeline() { - if (get() != nullptr) { - get()->~SkLinearBitmapPipeline(); - } - } - - template - void init(Args&&... args) { - // Ensure that our pipeline is created at a 16 byte aligned address. - fPipeline = (SkLinearBitmapPipeline*)SkAlign16((intptr_t)fPipelineStorage); - new (fPipeline) SkLinearBitmapPipeline{std::forward(args)...}; - } - - SkLinearBitmapPipeline* get() const { return fPipeline; } - SkLinearBitmapPipeline& operator*() const { return *this->get(); } - SkLinearBitmapPipeline* operator->() const { return this->get(); } - -private: - enum { - kActualSize = sizeof(SkLinearBitmapPipeline), - kPaddedSize = SkAlignPtr(kActualSize + 12), - }; - void* fPipelineStorage[kPaddedSize / sizeof(void*)]; - SkLinearBitmapPipeline* fPipeline{nullptr}; }; #endif // SkLinearBitmapPipeline_DEFINED diff --git a/gfx/skia/skia/src/core/SkLinearBitmapPipeline_core.h b/gfx/skia/skia/src/core/SkLinearBitmapPipeline_core.h index 5ef6fcab5b7a..ce6c05b75260 100644 --- a/gfx/skia/skia/src/core/SkLinearBitmapPipeline_core.h +++ b/gfx/skia/skia/src/core/SkLinearBitmapPipeline_core.h @@ -157,23 +157,28 @@ void span_fallback(Span span, Stage* stage) { SkScalar length; int count; std::tie(start, length, count) = span; - Sk4f xs{X(start)}; + Sk4f startXs{X(start)}; Sk4f ys{Y(start)}; + Sk4f mults = {0.0f, 1.0f, 2.0f, 3.0f}; // Initializing this is not needed, but some compilers can't figure this out. - Sk4s fourDx{0.0f}; + Sk4s dXs{0.0f}; if (count > 1) { SkScalar dx = length / (count - 1); - xs = xs + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * dx; - // Only used if count is >= 4. - fourDx = Sk4f{4.0f * dx}; + dXs = Sk4f{dx}; } + // Instead of using xs = xs + dx every round, this uses xs = i * dx + X(start). This + // eliminates the rounding error for the sum. + Sk4f xs = startXs + mults * dXs; while (count >= 4) { stage->pointList4(xs, ys); - xs = xs + fourDx; + + mults += Sk4f{4.0f}; + xs = mults * dXs + startXs; count -= 4; } + if (count > 0) { stage->pointListFew(count, xs, ys); } diff --git a/gfx/skia/skia/src/core/SkLinearBitmapPipeline_matrix.h b/gfx/skia/skia/src/core/SkLinearBitmapPipeline_matrix.h index d194d0729a7f..78f723148ebe 100644 --- a/gfx/skia/skia/src/core/SkLinearBitmapPipeline_matrix.h +++ b/gfx/skia/skia/src/core/SkLinearBitmapPipeline_matrix.h @@ -17,21 +17,21 @@ public: : fXOffset{X(offset)} , fYOffset{Y(offset)} { } - void processPoints(Sk4s* xs, Sk4s* ys) { + void processPoints(Sk4s* xs, Sk4s* ys) const { *xs = *xs + fXOffset; *ys = *ys + fYOffset; } template - bool maybeProcessSpan(Span span, Next* next) { + bool maybeProcessSpan(Span span, Next* next) const { SkPoint start; SkScalar length; int count; std::tie(start, length, count) = span; - next->pointSpan(Span{start + SkPoint{fXOffset[0], fYOffset[0]}, length, count}); + next->pointSpan(Span{start + SkPoint{fXOffset, fYOffset}, length, count}); return true; } private: - const Sk4s fXOffset, fYOffset; + const SkScalar fXOffset, fYOffset; }; class ScaleMatrixStrategy { @@ -39,25 +39,25 @@ public: ScaleMatrixStrategy(SkVector offset, SkVector scale) : fXOffset{X(offset)}, fYOffset{Y(offset)} , fXScale{X(scale)}, fYScale{Y(scale)} { } - void processPoints(Sk4s* xs, Sk4s* ys) { + void processPoints(Sk4s* xs, Sk4s* ys) const { *xs = *xs * fXScale + fXOffset; *ys = *ys * fYScale + fYOffset; } template - bool maybeProcessSpan(Span span, Next* next) { + bool maybeProcessSpan(Span span, Next* next) const { SkPoint start; SkScalar length; int count; std::tie(start, length, count) = span; SkPoint newStart = - SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] + fYOffset[0]}; - SkScalar newLength = length * fXScale[0]; + SkPoint{X(start) * fXScale + fXOffset, Y(start) * fYScale + fYOffset}; + SkScalar newLength = length * fXScale; next->pointSpan(Span{newStart, newLength, count}); return true; } private: - const Sk4s fXOffset, fYOffset; - const Sk4s fXScale, fYScale; + const SkScalar fXOffset, fYOffset; + const SkScalar fXScale, fYScale; }; class AffineMatrixStrategy { @@ -66,7 +66,7 @@ public: : fXOffset{X(offset)}, fYOffset{Y(offset)} , fXScale{X(scale)}, fYScale{Y(scale)} , fXSkew{X(skew)}, fYSkew{Y(skew)} { } - void processPoints(Sk4s* xs, Sk4s* ys) { + void processPoints(Sk4s* xs, Sk4s* ys) const { Sk4s newXs = fXScale * *xs + fXSkew * *ys + fXOffset; Sk4s newYs = fYSkew * *xs + fYScale * *ys + fYOffset; @@ -75,14 +75,14 @@ public: } template - bool maybeProcessSpan(Span span, Next* next) { + bool maybeProcessSpan(Span span, Next* next) const { return false; } private: - const Sk4s fXOffset, fYOffset; - const Sk4s fXScale, fYScale; - const Sk4s fXSkew, fYSkew; + const SkScalar fXOffset, fYOffset; + const SkScalar fXScale, fYScale; + const SkScalar fXSkew, fYSkew; }; class PerspectiveMatrixStrategy { @@ -92,7 +92,7 @@ public: : fXOffset{X(offset)}, fYOffset{Y(offset)}, fZOffset{zOffset} , fXScale{X(scale)}, fYScale{Y(scale)} , fXSkew{X(skew)}, fYSkew{Y(skew)}, fZXSkew{X(zSkew)}, fZYSkew{Y(zSkew)} { } - void processPoints(Sk4s* xs, Sk4s* ys) { + void processPoints(Sk4s* xs, Sk4s* ys) const { Sk4s newXs = fXScale * *xs + fXSkew * *ys + fXOffset; Sk4s newYs = fYSkew * *xs + fYScale * *ys + fYOffset; Sk4s newZs = fZXSkew * *xs + fZYSkew * *ys + fZOffset; @@ -102,14 +102,14 @@ public: } template - bool maybeProcessSpan(Span span, Next* next) { + bool maybeProcessSpan(Span span, Next* next) const { return false; } private: - const Sk4s fXOffset, fYOffset, fZOffset; - const Sk4s fXScale, fYScale; - const Sk4s fXSkew, fYSkew, fZXSkew, fZYSkew; + const SkScalar fXOffset, fYOffset, fZOffset; + const SkScalar fXScale, fYScale; + const SkScalar fXSkew, fYSkew, fZXSkew, fZYSkew; }; diff --git a/gfx/skia/skia/src/core/SkLinearBitmapPipeline_sample.h b/gfx/skia/skia/src/core/SkLinearBitmapPipeline_sample.h index 5f9948c644c7..a7f5d7383eaf 100644 --- a/gfx/skia/skia/src/core/SkLinearBitmapPipeline_sample.h +++ b/gfx/skia/skia/src/core/SkLinearBitmapPipeline_sample.h @@ -10,9 +10,10 @@ #include +#include "SkAutoMalloc.h" #include "SkColor.h" #include "SkColorPriv.h" -#include "SkFixed.h" +#include "SkFixed.h" // for SkFixed1 only. Don't use SkFixed in this file. #include "SkHalf.h" #include "SkLinearBitmapPipeline_core.h" #include "SkNx.h" @@ -65,15 +66,17 @@ template <> class PixelConverter { public: using Element = uint8_t; - PixelConverter(const SkPixmap& srcPixmap, SkColor tintColor) - : fTintColor{set_alpha(Sk4f_from_SkColor(tintColor), 1.0f)} { } + PixelConverter(const SkPixmap& srcPixmap, SkColor tintColor) { + fTintColor = SkColor4f::FromColor(tintColor); + fTintColor.fA = 1.0f; + } Sk4f toSk4f(const Element pixel) const { - return fTintColor * (pixel * (1.0f/255.0f)); + return Sk4f::Load(&fTintColor) * (pixel * (1.0f/255.0f)); } private: - const Sk4f fTintColor; + SkColor4f fTintColor; }; template @@ -385,15 +388,17 @@ private: SkPoint start; SkScalar length; int count; std::tie(start, length, count) = span; SkScalar x = X(start); - SkFixed fx = SkScalarToFixed(x); + // fx is a fixed 48.16 number. + int64_t fx = static_cast(x * SK_Fixed1); SkScalar dx = length / (count - 1); - SkFixed fdx = SkScalarToFixed(dx); + // fdx is a fixed 48.16 number. + int64_t fdx = static_cast(dx * SK_Fixed1); const void* row = fAccessor.row((int)std::floor(Y(start))); Next* next = fNext; - int ix = SkFixedFloorToInt(fx); - int prevIX = ix; + int64_t ix = fx >> 16; + int64_t prevIX = ix; Sk4f fpixel = fAccessor.getPixelFromRow(row, ix); // When dx is less than one, each pixel is used more than once. Using the fixed point fx @@ -405,7 +410,7 @@ private: prevIX = ix; } fx += fdx; - ix = SkFixedFloorToInt(fx); + ix = fx >> 16; return fpixel; }; diff --git a/gfx/skia/skia/src/core/SkLinearBitmapPipeline_tile.h b/gfx/skia/skia/src/core/SkLinearBitmapPipeline_tile.h index 1e07c22cf54f..e18f7a1a5d35 100644 --- a/gfx/skia/skia/src/core/SkLinearBitmapPipeline_tile.h +++ b/gfx/skia/skia/src/core/SkLinearBitmapPipeline_tile.h @@ -15,18 +15,29 @@ #include namespace { + +void assertTiled(const Sk4s& vs, SkScalar vMax) { + SkASSERT(0 <= vs[0] && vs[0] < vMax); + SkASSERT(0 <= vs[1] && vs[1] < vMax); + SkASSERT(0 <= vs[2] && vs[2] < vMax); + SkASSERT(0 <= vs[3] && vs[3] < vMax); +} + +/* + * Clamp in the X direction. + * Observations: + * * sample pointer border - if the sample point is <= 0.5 or >= Max - 0.5 then the pixel + * value should be a border color. For this case, create the span using clampToSinglePixel. + */ class XClampStrategy { public: XClampStrategy(int32_t max) - : fXsMax{SkScalar(max - 0.5f)} + : fXMaxPixel{SkScalar(max - SK_ScalarHalf)} , fXMax{SkScalar(max)} { } void tileXPoints(Sk4s* xs) { - *xs = Sk4s::Min(Sk4s::Max(*xs, 0.0f), fXsMax); - SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); - SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); - SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); - SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); + *xs = Sk4s::Min(Sk4s::Max(*xs, SK_ScalarHalf), fXMaxPixel); + assertTiled(*xs, fXMax); } template @@ -76,9 +87,9 @@ public: // * Over - for the portion of the span > xMax, take the color at pixel {xMax-1, y} and // use it to fill in the rest of the destination pixels. if (dx >= 0) { - Span leftClamped = span.breakAt(0.0f, dx); + Span leftClamped = span.breakAt(SK_ScalarHalf, dx); if (!leftClamped.isEmpty()) { - leftClamped.clampToSinglePixel({0.0f, y}); + leftClamped.clampToSinglePixel({SK_ScalarHalf, y}); next->pointSpan(leftClamped); } Span center = span.breakAt(fXMax, dx); @@ -86,21 +97,21 @@ public: next->pointSpan(center); } if (!span.isEmpty()) { - span.clampToSinglePixel({fXMax - 1, y}); + span.clampToSinglePixel({fXMaxPixel, y}); next->pointSpan(span); } } else { Span rightClamped = span.breakAt(fXMax, dx); if (!rightClamped.isEmpty()) { - rightClamped.clampToSinglePixel({fXMax - 1, y}); + rightClamped.clampToSinglePixel({fXMaxPixel, y}); next->pointSpan(rightClamped); } - Span center = span.breakAt(0.0f, dx); + Span center = span.breakAt(SK_ScalarHalf, dx); if (!center.isEmpty()) { next->pointSpan(center); } if (!span.isEmpty()) { - span.clampToSinglePixel({0.0f, y}); + span.clampToSinglePixel({SK_ScalarHalf, y}); next->pointSpan(span); } } @@ -108,53 +119,48 @@ public: } private: - const Sk4s fXsMax; + const SkScalar fXMaxPixel; const SkScalar fXMax; }; class YClampStrategy { public: YClampStrategy(int32_t max) - : fYMax{SkScalar(max) - 0.5f} - , fYsMax{SkScalar(max) - 0.5f} { } + : fYMaxPixel{SkScalar(max) - SK_ScalarHalf} { } void tileYPoints(Sk4s* ys) { - *ys = Sk4s::Min(Sk4s::Max(*ys, 0.0f), fYsMax); - SkASSERT(0 <= (*ys)[0] && (*ys)[0] <= fYMax); - SkASSERT(0 <= (*ys)[1] && (*ys)[1] <= fYMax); - SkASSERT(0 <= (*ys)[2] && (*ys)[2] <= fYMax); - SkASSERT(0 <= (*ys)[3] && (*ys)[3] <= fYMax); + *ys = Sk4s::Min(Sk4s::Max(*ys, SK_ScalarHalf), fYMaxPixel); + assertTiled(*ys, fYMaxPixel + SK_ScalarHalf); } SkScalar tileY(SkScalar y) { - return std::min(std::max(0.0f, y), fYMax); + Sk4f ys{y}; + tileYPoints(&ys); + return ys[0]; } private: - const SkScalar fYMax; - const Sk4s fYsMax; + const SkScalar fYMaxPixel; }; -SkScalar tile_mod(SkScalar x, SkScalar base) { - return x - SkScalarFloorToScalar(x / base) * base; +SkScalar tile_mod(SkScalar x, SkScalar base, SkScalar cap) { + // When x is a negative number *very* close to zero, the difference becomes 0 - (-base) = base + // which is an out of bound value. The min() corrects these problematic values. + return std::min(x - SkScalarFloorToScalar(x / base) * base, cap); } class XRepeatStrategy { public: XRepeatStrategy(int32_t max) : fXMax{SkScalar(max)} - , fXsMax{SkScalar(max)} - , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} - , fXsInvMax{1.0f / SkScalar(max)} { } + , fXCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} + , fXInvMax{1.0f / SkScalar(max)} { } void tileXPoints(Sk4s* xs) { - Sk4s divX = *xs * fXsInvMax; - Sk4s modX = *xs - divX.floor() * fXsMax; - *xs = Sk4s::Min(fXsCap, modX); - SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); - SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); - SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); - SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); + Sk4s divX = *xs * fXInvMax; + Sk4s modX = *xs - divX.floor() * fXMax; + *xs = Sk4s::Min(fXCap, modX); + assertTiled(*xs, fXMax); } template @@ -163,7 +169,7 @@ public: SkPoint start; SkScalar length; int count; std::tie(start, length, count) = originalSpan; // Make x and y in range on the tile. - SkScalar x = tile_mod(X(start), fXMax); + SkScalar x = tile_mod(X(start), fXMax, fXCap); SkScalar y = Y(start); SkScalar dx = length / (count - 1); @@ -228,9 +234,8 @@ public: private: const SkScalar fXMax; - const Sk4s fXsMax; - const Sk4s fXsCap; - const Sk4s fXsInvMax; + const SkScalar fXCap; + const SkScalar fXInvMax; }; // The XRepeatUnitScaleStrategy exploits the situation where dx = 1.0. The main advantage is that @@ -242,18 +247,14 @@ class XRepeatUnitScaleStrategy { public: XRepeatUnitScaleStrategy(int32_t max) : fXMax{SkScalar(max)} - , fXsMax{SkScalar(max)} - , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} - , fXsInvMax{1.0f / SkScalar(max)} { } + , fXCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} + , fXInvMax{1.0f / SkScalar(max)} { } void tileXPoints(Sk4s* xs) { - Sk4s divX = *xs * fXsInvMax; - Sk4s modX = *xs - divX.floor() * fXsMax; - *xs = Sk4s::Min(fXsCap, modX); - SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); - SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); - SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); - SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); + Sk4s divX = *xs * fXInvMax; + Sk4s modX = *xs - divX.floor() * fXMax; + *xs = Sk4s::Min(fXCap, modX); + assertTiled(*xs, fXMax); } template @@ -262,7 +263,7 @@ public: SkPoint start; SkScalar length; int count; std::tie(start, length, count) = originalSpan; // Make x and y in range on the tile. - SkScalar x = tile_mod(X(start), fXMax); + SkScalar x = tile_mod(X(start), fXMax, fXCap); SkScalar y = Y(start); // No need trying to go fast because the steps are larger than a tile or there is one point. @@ -319,104 +320,92 @@ public: private: const SkScalar fXMax; - const Sk4s fXsMax; - const Sk4s fXsCap; - const Sk4s fXsInvMax; + const SkScalar fXCap; + const SkScalar fXInvMax; }; class YRepeatStrategy { public: YRepeatStrategy(int32_t max) : fYMax{SkScalar(max)} - , fYsMax{SkScalar(max)} + , fYCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} , fYsInvMax{1.0f / SkScalar(max)} { } void tileYPoints(Sk4s* ys) { Sk4s divY = *ys * fYsInvMax; - Sk4s modY = *ys - divY.floor() * fYsMax; - *ys = modY; - SkASSERT(0 <= (*ys)[0] && (*ys)[0] < fYMax); - SkASSERT(0 <= (*ys)[1] && (*ys)[1] < fYMax); - SkASSERT(0 <= (*ys)[2] && (*ys)[2] < fYMax); - SkASSERT(0 <= (*ys)[3] && (*ys)[3] < fYMax); + Sk4s modY = *ys - divY.floor() * fYMax; + *ys = Sk4s::Min(fYCap, modY); + assertTiled(*ys, fYMax); } SkScalar tileY(SkScalar y) { - SkScalar answer = tile_mod(y, fYMax); + SkScalar answer = tile_mod(y, fYMax, fYCap); SkASSERT(0 <= answer && answer < fYMax); return answer; } private: const SkScalar fYMax; - const Sk4s fYsMax; - const Sk4s fYsInvMax; + const SkScalar fYCap; + const SkScalar fYsInvMax; }; // max = 40 // mq2[x_] := Abs[(x - 40) - Floor[(x - 40)/80] * 80 - 40] class XMirrorStrategy { public: XMirrorStrategy(int32_t max) - : fXsMax{SkScalar(max)} - , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} - , fXsDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { } + : fXMax{SkScalar(max)} + , fXCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} + , fXDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { } void tileXPoints(Sk4s* xs) { - Sk4f bias = *xs - fXsMax; - Sk4f div = bias * fXsDoubleInvMax; - Sk4f mod = bias - div.floor() * 2.0f * fXsMax; - Sk4f unbias = mod - fXsMax; - *xs = Sk4f::Min(unbias.abs(), fXsCap); - SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXsMax[0]); - SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXsMax[0]); - SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXsMax[0]); - SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXsMax[0]); + Sk4f bias = *xs - fXMax; + Sk4f div = bias * fXDoubleInvMax; + Sk4f mod = bias - div.floor() * 2.0f * fXMax; + Sk4f unbias = mod - fXMax; + *xs = Sk4f::Min(unbias.abs(), fXCap); + assertTiled(*xs, fXMax); } template bool maybeProcessSpan(Span originalSpan, Next* next) { return false; } private: - Sk4f fXsMax; - Sk4f fXsCap; - Sk4f fXsDoubleInvMax; + SkScalar fXMax; + SkScalar fXCap; + SkScalar fXDoubleInvMax; }; class YMirrorStrategy { public: YMirrorStrategy(int32_t max) : fYMax{SkScalar(max)} - , fYsMax{SkScalar(max)} - , fYsCap{nextafterf(SkScalar(max), 0.0f)} - , fYsDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { } + , fYCap{nextafterf(SkScalar(max), 0.0f)} + , fYDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { } void tileYPoints(Sk4s* ys) { - Sk4f bias = *ys - fYsMax; - Sk4f div = bias * fYsDoubleInvMax; - Sk4f mod = bias - div.floor() * 2.0f * fYsMax; - Sk4f unbias = mod - fYsMax; - *ys = Sk4f::Min(unbias.abs(), fYsCap); - SkASSERT(0 <= (*ys)[0] && (*ys)[0] < fYMax); - SkASSERT(0 <= (*ys)[1] && (*ys)[1] < fYMax); - SkASSERT(0 <= (*ys)[2] && (*ys)[2] < fYMax); - SkASSERT(0 <= (*ys)[3] && (*ys)[3] < fYMax); + Sk4f bias = *ys - fYMax; + Sk4f div = bias * fYDoubleInvMax; + Sk4f mod = bias - div.floor() * 2.0f * fYMax; + Sk4f unbias = mod - fYMax; + *ys = Sk4f::Min(unbias.abs(), fYCap); + assertTiled(*ys, fYMax); } SkScalar tileY(SkScalar y) { SkScalar bias = y - fYMax; - SkScalar div = bias * fYsDoubleInvMax[0]; + SkScalar div = bias * fYDoubleInvMax; SkScalar mod = bias - SkScalarFloorToScalar(div) * 2.0f * fYMax; SkScalar unbias = mod - fYMax; - SkScalar answer = SkMinScalar(SkScalarAbs(unbias), fYsCap[0]); + SkScalar answer = SkMinScalar(SkScalarAbs(unbias), fYCap); SkASSERT(0 <= answer && answer < fYMax); return answer; } private: SkScalar fYMax; - Sk4f fYsMax; - Sk4f fYsCap; - Sk4f fYsDoubleInvMax; + SkScalar fYCap; + SkScalar fYDoubleInvMax; }; } // namespace diff --git a/gfx/skia/skia/src/core/SkLiteDL.cpp b/gfx/skia/skia/src/core/SkLiteDL.cpp index ea9180bb826d..4a8280d5f5d1 100644 --- a/gfx/skia/skia/src/core/SkLiteDL.cpp +++ b/gfx/skia/skia/src/core/SkLiteDL.cpp @@ -12,8 +12,10 @@ #include "SkLiteDL.h" #include "SkMath.h" #include "SkPicture.h" +#include "SkRegion.h" #include "SkRSXform.h" #include "SkTextBlob.h" +#include "SkVertices.h" #ifndef SKLITEDL_PAGE #define SKLITEDL_PAGE 4096 @@ -38,14 +40,8 @@ static void copy_v(void* dst, const S* src, int n, Rest&&... rest) { // Helper for getting back at arrays which have been copy_v'd together after an Op. template -static D* pod(T* op, size_t offset = 0) { - return SkTAddOffset(op+1, offset); -} - -// Pre-cache lazy non-threadsafe fields on SkPath and/or SkMatrix. -static void make_threadsafe(SkPath* path, SkMatrix* matrix) { - if (path) { path->updateBoundsCache(); } - if (matrix) { (void)matrix->getType(); } +static const D* pod(const T* op, size_t offset = 0) { + return SkTAddOffset(op+1, offset); } namespace { @@ -66,8 +62,6 @@ namespace { #undef M struct Op { - void makeThreadsafe() {} - uint32_t type : 8; uint32_t skip : 24; }; @@ -79,7 +73,7 @@ namespace { SetDrawFilter(SkDrawFilter* df) : drawFilter(sk_ref_sp(df)) {} sk_sp drawFilter; #endif - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { #ifdef SK_SUPPORT_LEGACY_DRAWFILTER c->setDrawFilter(drawFilter.get()); #endif @@ -88,11 +82,11 @@ namespace { struct Save final : Op { static const auto kType = Type::Save; - void draw(SkCanvas* c, const SkMatrix&) { c->save(); } + void draw(SkCanvas* c, const SkMatrix&) const { c->save(); } }; struct Restore final : Op { static const auto kType = Type::Restore; - void draw(SkCanvas* c, const SkMatrix&) { c->restore(); } + void draw(SkCanvas* c, const SkMatrix&) const { c->restore(); } }; struct SaveLayer final : Op { static const auto kType = Type::SaveLayer; @@ -107,7 +101,7 @@ namespace { SkPaint paint; sk_sp backdrop; SkCanvas::SaveLayerFlags flags; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->saveLayer({ maybe_unset(bounds), &paint, backdrop.get(), flags }); } }; @@ -116,23 +110,21 @@ namespace { static const auto kType = Type::Concat; Concat(const SkMatrix& matrix) : matrix(matrix) {} SkMatrix matrix; - void draw(SkCanvas* c, const SkMatrix&) { c->concat(matrix); } - void makeThreadsafe() { make_threadsafe(nullptr, &matrix); } + void draw(SkCanvas* c, const SkMatrix&) const { c->concat(matrix); } }; struct SetMatrix final : Op { static const auto kType = Type::SetMatrix; SetMatrix(const SkMatrix& matrix) : matrix(matrix) {} SkMatrix matrix; - void draw(SkCanvas* c, const SkMatrix& original) { + void draw(SkCanvas* c, const SkMatrix& original) const { c->setMatrix(SkMatrix::Concat(original, matrix)); } - void makeThreadsafe() { make_threadsafe(nullptr, &matrix); } }; struct Translate final : Op { static const auto kType = Type::Translate; Translate(SkScalar dx, SkScalar dy) : dx(dx), dy(dy) {} SkScalar dx,dy; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->translate(dx, dy); } }; @@ -140,7 +132,7 @@ namespace { static const auto kType = Type::TranslateZ; TranslateZ(SkScalar dz) : dz(dz) {} SkScalar dz; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { #ifdef SK_EXPERIMENTAL_SHADOWING c->translateZ(dz); #endif @@ -149,71 +141,69 @@ namespace { struct ClipPath final : Op { static const auto kType = Type::ClipPath; - ClipPath(const SkPath& path, SkCanvas::ClipOp op, bool aa) : path(path), op(op), aa(aa) {} - SkPath path; - SkCanvas::ClipOp op; - bool aa; - void draw(SkCanvas* c, const SkMatrix&) { c->clipPath(path, op, aa); } - void makeThreadsafe() { make_threadsafe(&path, nullptr); } + ClipPath(const SkPath& path, SkClipOp op, bool aa) : path(path), op(op), aa(aa) {} + SkPath path; + SkClipOp op; + bool aa; + void draw(SkCanvas* c, const SkMatrix&) const { c->clipPath(path, op, aa); } }; struct ClipRect final : Op { static const auto kType = Type::ClipRect; - ClipRect(const SkRect& rect, SkCanvas::ClipOp op, bool aa) : rect(rect), op(op), aa(aa) {} - SkRect rect; - SkCanvas::ClipOp op; - bool aa; - void draw(SkCanvas* c, const SkMatrix&) { c->clipRect(rect, op, aa); } + ClipRect(const SkRect& rect, SkClipOp op, bool aa) : rect(rect), op(op), aa(aa) {} + SkRect rect; + SkClipOp op; + bool aa; + void draw(SkCanvas* c, const SkMatrix&) const { c->clipRect(rect, op, aa); } }; struct ClipRRect final : Op { static const auto kType = Type::ClipRRect; - ClipRRect(const SkRRect& rrect, SkCanvas::ClipOp op, bool aa) : rrect(rrect), op(op), aa(aa) {} - SkRRect rrect; - SkCanvas::ClipOp op; - bool aa; - void draw(SkCanvas* c, const SkMatrix&) { c->clipRRect(rrect, op, aa); } + ClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) : rrect(rrect), op(op), aa(aa) {} + SkRRect rrect; + SkClipOp op; + bool aa; + void draw(SkCanvas* c, const SkMatrix&) const { c->clipRRect(rrect, op, aa); } }; struct ClipRegion final : Op { static const auto kType = Type::ClipRegion; - ClipRegion(const SkRegion& region, SkCanvas::ClipOp op) : region(region), op(op) {} - SkRegion region; - SkCanvas::ClipOp op; - void draw(SkCanvas* c, const SkMatrix&) { c->clipRegion(region, op); } + ClipRegion(const SkRegion& region, SkClipOp op) : region(region), op(op) {} + SkRegion region; + SkClipOp op; + void draw(SkCanvas* c, const SkMatrix&) const { c->clipRegion(region, op); } }; struct DrawPaint final : Op { static const auto kType = Type::DrawPaint; DrawPaint(const SkPaint& paint) : paint(paint) {} SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { c->drawPaint(paint); } + void draw(SkCanvas* c, const SkMatrix&) const { c->drawPaint(paint); } }; struct DrawPath final : Op { static const auto kType = Type::DrawPath; DrawPath(const SkPath& path, const SkPaint& paint) : path(path), paint(paint) {} SkPath path; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { c->drawPath(path, paint); } - void makeThreadsafe() { make_threadsafe(&path, nullptr); } + void draw(SkCanvas* c, const SkMatrix&) const { c->drawPath(path, paint); } }; struct DrawRect final : Op { static const auto kType = Type::DrawRect; DrawRect(const SkRect& rect, const SkPaint& paint) : rect(rect), paint(paint) {} SkRect rect; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { c->drawRect(rect, paint); } + void draw(SkCanvas* c, const SkMatrix&) const { c->drawRect(rect, paint); } }; struct DrawRegion final : Op { static const auto kType = Type::DrawRegion; DrawRegion(const SkRegion& region, const SkPaint& paint) : region(region), paint(paint) {} SkRegion region; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { c->drawRegion(region, paint); } + void draw(SkCanvas* c, const SkMatrix&) const { c->drawRegion(region, paint); } }; struct DrawOval final : Op { static const auto kType = Type::DrawOval; DrawOval(const SkRect& oval, const SkPaint& paint) : oval(oval), paint(paint) {} SkRect oval; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { c->drawOval(oval, paint); } + void draw(SkCanvas* c, const SkMatrix&) const { c->drawOval(oval, paint); } }; struct DrawArc final : Op { static const auto kType = Type::DrawArc; @@ -226,15 +216,15 @@ namespace { SkScalar sweepAngle; bool useCenter; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { c->drawArc(oval, startAngle, sweepAngle, - useCenter, paint); } + void draw(SkCanvas* c, const SkMatrix&) const { c->drawArc(oval, startAngle, sweepAngle, + useCenter, paint); } }; struct DrawRRect final : Op { static const auto kType = Type::DrawRRect; DrawRRect(const SkRRect& rrect, const SkPaint& paint) : rrect(rrect), paint(paint) {} SkRRect rrect; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { c->drawRRect(rrect, paint); } + void draw(SkCanvas* c, const SkMatrix&) const { c->drawRRect(rrect, paint); } }; struct DrawDRRect final : Op { static const auto kType = Type::DrawDRRect; @@ -242,7 +232,7 @@ namespace { : outer(outer), inner(inner), paint(paint) {} SkRRect outer, inner; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { c->drawDRRect(outer, inner, paint); } + void draw(SkCanvas* c, const SkMatrix&) const { c->drawDRRect(outer, inner, paint); } }; struct DrawAnnotation final : Op { @@ -250,7 +240,7 @@ namespace { DrawAnnotation(const SkRect& rect, SkData* value) : rect(rect), value(sk_ref_sp(value)) {} SkRect rect; sk_sp value; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->drawAnnotation(rect, pod(this), value.get()); } }; @@ -259,16 +249,10 @@ namespace { DrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) : drawable(sk_ref_sp(drawable)) { if (matrix) { this->matrix = *matrix; } } - sk_sp drawable; - sk_sp snapped; - SkMatrix matrix = SkMatrix::I(); - void draw(SkCanvas* c, const SkMatrix&) { - snapped ? c->drawPicture(snapped.get(), &matrix, nullptr) - : c->drawDrawable(drawable.get(), &matrix); - } - void makeThreadsafe() { - snapped.reset(drawable->newPictureSnapshot()); - make_threadsafe(nullptr, &matrix); + sk_sp drawable; + SkMatrix matrix = SkMatrix::I(); + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawDrawable(drawable.get(), &matrix); } }; struct DrawPicture final : Op { @@ -282,10 +266,9 @@ namespace { SkMatrix matrix = SkMatrix::I(); SkPaint paint; bool has_paint = false; // TODO: why is a default paint not the same? - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->drawPicture(picture.get(), &matrix, has_paint ? &paint : nullptr); } - void makeThreadsafe() { make_threadsafe(nullptr, &matrix); } }; struct DrawShadowedPicture final : Op { static const auto kType = Type::DrawShadowedPicture; @@ -300,12 +283,11 @@ namespace { SkMatrix matrix = SkMatrix::I(); SkPaint paint; SkShadowParams params; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { #ifdef SK_EXPERIMENTAL_SHADOWING c->drawShadowedPicture(picture.get(), &matrix, &paint, params); #endif } - void makeThreadsafe() { make_threadsafe(nullptr, &matrix); } }; struct DrawImage final : Op { @@ -317,7 +299,7 @@ namespace { sk_sp image; SkScalar x,y; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { c->drawImage(image.get(), x,y, &paint); } + void draw(SkCanvas* c, const SkMatrix&) const { c->drawImage(image.get(), x,y, &paint); } }; struct DrawImageNine final : Op { static const auto kType = Type::DrawImageNine; @@ -330,7 +312,7 @@ namespace { SkIRect center; SkRect dst; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->drawImageNine(image.get(), center, dst, &paint); } }; @@ -346,7 +328,7 @@ namespace { SkRect src, dst; SkPaint paint; SkCanvas::SrcRectConstraint constraint; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->drawImageRect(image.get(), src, dst, &paint, constraint); } }; @@ -362,7 +344,7 @@ namespace { SkIRect src; SkRect dst; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { auto xdivs = pod(this, 0), ydivs = pod(this, xs*sizeof(int)); auto flags = (0 == fs) ? nullptr : @@ -378,7 +360,7 @@ namespace { size_t bytes; SkScalar x,y; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->drawText(pod(this), bytes, x,y, paint); } }; @@ -389,7 +371,7 @@ namespace { size_t bytes; SkPaint paint; int n; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { auto points = pod(this); auto text = pod(this, n*sizeof(SkPoint)); c->drawPosText(text, bytes, points, paint); @@ -403,7 +385,7 @@ namespace { SkScalar y; SkPaint paint; int n; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { auto xs = pod(this); auto text = pod(this, n*sizeof(SkScalar)); c->drawPosTextH(text, bytes, xs, y, paint); @@ -420,10 +402,9 @@ namespace { SkPath path; SkMatrix matrix = SkMatrix::I(); SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->drawTextOnPath(pod(this), bytes, path, &matrix, paint); } - void makeThreadsafe() { make_threadsafe(&path, &matrix); } }; struct DrawTextRSXform final : Op { static const auto kType = Type::DrawTextRSXform; @@ -434,7 +415,7 @@ namespace { size_t bytes; SkRect cull = kUnset; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->drawTextRSXform(pod(this), bytes, pod(this, bytes), maybe_unset(cull), paint); } @@ -446,7 +427,7 @@ namespace { sk_sp blob; SkScalar x,y; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->drawTextBlob(blob.get(), x,y, paint); } }; @@ -454,8 +435,9 @@ namespace { struct DrawPatch final : Op { static const auto kType = Type::DrawPatch; DrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texs[4], - SkXfermode* xfermode, const SkPaint& paint) - : xfermode(sk_ref_sp(xfermode)), paint(paint) { + SkBlendMode bmode, const SkPaint& paint) + : xfermode(bmode), paint(paint) + { copy_v(this->cubics, cubics, 12); if (colors) { copy_v(this->colors, colors, 4); has_colors = true; } if (texs ) { copy_v(this->texs , texs , 4); has_texs = true; } @@ -463,13 +445,13 @@ namespace { SkPoint cubics[12]; SkColor colors[4]; SkPoint texs[4]; - sk_sp xfermode; + SkBlendMode xfermode; SkPaint paint; bool has_colors = false; bool has_texs = false; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->drawPatch(cubics, has_colors ? colors : nullptr, has_texs ? texs : nullptr, - xfermode.get(), paint); + xfermode, paint); } }; struct DrawPoints final : Op { @@ -479,51 +461,24 @@ namespace { SkCanvas::PointMode mode; size_t count; SkPaint paint; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { c->drawPoints(mode, count, pod(this), paint); } }; struct DrawVertices final : Op { static const auto kType = Type::DrawVertices; - DrawVertices(SkCanvas::VertexMode mode, int count, SkXfermode* xfermode, int nindices, - const SkPaint& paint, bool has_texs, bool has_colors, bool has_indices) - : mode(mode), count(count), xfermode(sk_ref_sp(xfermode)), nindices(nindices) - , paint(paint), has_texs(has_texs), has_colors(has_colors), has_indices(has_indices) {} - SkCanvas::VertexMode mode; - int count; - sk_sp xfermode; - int nindices; - SkPaint paint; - bool has_texs; - bool has_colors; - bool has_indices; - void draw(SkCanvas* c, const SkMatrix&) { - SkPoint* vertices = pod(this, 0); - size_t offset = count*sizeof(SkPoint); - - SkPoint* texs = nullptr; - if (has_texs) { - texs = pod(this, offset); - offset += count*sizeof(SkPoint); - } - - SkColor* colors = nullptr; - if (has_colors) { - colors = pod(this, offset); - offset += count*sizeof(SkColor); - } - - uint16_t* indices = nullptr; - if (has_indices) { - indices = pod(this, offset); - } - c->drawVertices(mode, count, vertices, texs, colors, xfermode.get(), - indices, nindices, paint); + DrawVertices(const SkVertices* v, SkBlendMode m, const SkPaint& p) + : vertices(sk_ref_sp(const_cast(v))), mode(m), paint(p) {} + sk_sp vertices; + SkBlendMode mode; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawVertices(vertices, mode, paint); } }; struct DrawAtlas final : Op { static const auto kType = Type::DrawAtlas; - DrawAtlas(const SkImage* atlas, int count, SkXfermode::Mode xfermode, + DrawAtlas(const SkImage* atlas, int count, SkBlendMode xfermode, const SkRect* cull, const SkPaint* paint, bool has_colors) : atlas(sk_ref_sp(atlas)), count(count), xfermode(xfermode), has_colors(has_colors) { if (cull) { this->cull = *cull; } @@ -531,11 +486,11 @@ namespace { } sk_sp atlas; int count; - SkXfermode::Mode xfermode; + SkBlendMode xfermode; SkRect cull = kUnset; SkPaint paint; bool has_colors; - void draw(SkCanvas* c, const SkMatrix&) { + void draw(SkCanvas* c, const SkMatrix&) const { auto xforms = pod(this, 0); auto texs = pod(this, count*sizeof(SkRSXform)); auto colors = has_colors @@ -567,10 +522,10 @@ void* SkLiteDL::push(size_t pod, Args&&... args) { } template -inline void SkLiteDL::map(const Fn fns[], Args... args) { +inline void SkLiteDL::map(const Fn fns[], Args... args) const { auto end = fBytes.get() + fUsed; - for (uint8_t* ptr = fBytes.get(); ptr < end; ) { - auto op = (Op*)ptr; + for (const uint8_t* ptr = fBytes.get(); ptr < end; ) { + auto op = (const Op*)ptr; auto type = op->type; auto skip = op->skip; if (auto fn = fns[type]) { // We replace no-op functions with nullptrs @@ -598,16 +553,16 @@ void SkLiteDL::setMatrix(const SkMatrix& matrix) { this->push(0, ma void SkLiteDL::translate(SkScalar dx, SkScalar dy) { this->push(0, dx, dy); } void SkLiteDL::translateZ(SkScalar dz) { this->push(0, dz); } -void SkLiteDL::clipPath(const SkPath& path, SkCanvas::ClipOp op, bool aa) { +void SkLiteDL::clipPath(const SkPath& path, SkClipOp op, bool aa) { this->push(0, path, op, aa); } -void SkLiteDL::clipRect(const SkRect& rect, SkCanvas::ClipOp op, bool aa) { +void SkLiteDL::clipRect(const SkRect& rect, SkClipOp op, bool aa) { this->push(0, rect, op, aa); } -void SkLiteDL::clipRRect(const SkRRect& rrect, SkCanvas::ClipOp op, bool aa) { +void SkLiteDL::clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) { this->push(0, rrect, op, aa); } -void SkLiteDL::clipRegion(const SkRegion& region, SkCanvas::ClipOp op) { +void SkLiteDL::clipRegion(const SkRegion& region, SkClipOp op) { this->push(0, region, op); } @@ -711,30 +666,19 @@ void SkLiteDL::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, cons } void SkLiteDL::drawPatch(const SkPoint points[12], const SkColor colors[4], const SkPoint texs[4], - SkXfermode* xfermode, const SkPaint& paint) { - this->push(0, points, colors, texs, xfermode, paint); + SkBlendMode bmode, const SkPaint& paint) { + this->push(0, points, colors, texs, bmode, paint); } void SkLiteDL::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint points[], const SkPaint& paint) { void* pod = this->push(count*sizeof(SkPoint), mode, count, paint); copy_v(pod, points,count); } -void SkLiteDL::drawVertices(SkCanvas::VertexMode mode, int count, const SkPoint vertices[], - const SkPoint texs[], const SkColor colors[], SkXfermode* xfermode, - const uint16_t indices[], int nindices, const SkPaint& paint) { - size_t bytes = count * sizeof(SkPoint); - if (texs ) { bytes += count * sizeof(SkPoint); } - if (colors) { bytes += count * sizeof(SkColor); } - if (indices) { bytes += nindices * sizeof(uint16_t); } - void* pod = this->push(bytes, mode, count, xfermode, nindices, paint, - texs != nullptr, colors != nullptr, indices != nullptr); - copy_v(pod, vertices, count, - texs, texs ? count : 0, - colors, colors ? count : 0, - indices, indices ? nindices : 0); +void SkLiteDL::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) { + this->push(0, vertices, mode, paint); } void SkLiteDL::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[], - const SkColor colors[], int count, SkXfermode::Mode xfermode, + const SkColor colors[], int count, SkBlendMode xfermode, const SkRect* cull, const SkPaint* paint) { size_t bytes = count*(sizeof(SkRSXform) + sizeof(SkRect)); if (colors) { @@ -747,18 +691,16 @@ void SkLiteDL::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const S colors, colors ? count : 0); } -typedef void(*draw_fn)(void*, SkCanvas*, const SkMatrix&); -typedef void(*void_fn)(void*); +typedef void(*draw_fn)(const void*, SkCanvas*, const SkMatrix&); +typedef void(*void_fn)(const void*); // All ops implement draw(). -#define M(T) [](void* op, SkCanvas* c, const SkMatrix& original) { ((T*)op)->draw(c, original); }, +#define M(T) [](const void* op, SkCanvas* c, const SkMatrix& original) { \ + ((const T*)op)->draw(c, original); \ +}, static const draw_fn draw_fns[] = { TYPES(M) }; #undef M -#define M(T) [](void* op) { ((T*)op)->makeThreadsafe(); }, -static const void_fn make_threadsafe_fns[] = { TYPES(M) }; -#undef M - // Older libstdc++ has pre-standard std::has_trivial_destructor. #if defined(__GLIBCXX__) && (__GLIBCXX__ < 20130000) template using can_skip_destructor = std::has_trivial_destructor; @@ -767,49 +709,23 @@ static const void_fn make_threadsafe_fns[] = { TYPES(M) }; #endif // Most state ops (matrix, clip, save, restore) have a trivial destructor. -#define M(T) !can_skip_destructor::value ? [](void* op) { ((T*)op)->~T(); } : (void_fn)nullptr, +#define M(T) !can_skip_destructor::value ? [](const void* op) { ((const T*)op)->~T(); } \ + : (void_fn)nullptr, static const void_fn dtor_fns[] = { TYPES(M) }; #undef M -void SkLiteDL::onDraw(SkCanvas* canvas) { this->map(draw_fns, canvas, canvas->getTotalMatrix()); } -void SkLiteDL::makeThreadsafe() { this->map(make_threadsafe_fns); } - -SkRect SkLiteDL::onGetBounds() { - return fBounds; +void SkLiteDL::draw(SkCanvas* canvas) const { + SkAutoCanvasRestore acr(canvas, false); + this->map(draw_fns, canvas, canvas->getTotalMatrix()); } -SkLiteDL:: SkLiteDL(SkRect bounds) : fUsed(0), fReserved(0), fBounds(bounds) {} - SkLiteDL::~SkLiteDL() { - this->reset(SkRect::MakeEmpty()); + this->reset(); } -sk_sp SkLiteDL::New(SkRect bounds) { - return sk_sp(new SkLiteDL(bounds)); -} - -void SkLiteDL::reset(SkRect bounds) { - SkASSERT(this->unique()); +void SkLiteDL::reset() { this->map(dtor_fns); // Leave fBytes and fReserved alone. fUsed = 0; - fBounds = bounds; -} - -void SkLiteDL::drawAsLayer(SkCanvas* canvas, const SkMatrix* matrix, const SkPaint* paint) { - auto fallback_plan = [&] { - SkRect bounds = this->getBounds(); - canvas->saveLayer(&bounds, paint); - this->draw(canvas, matrix); - canvas->restore(); - }; - - // TODO: single-draw specializations - - return fallback_plan(); -} - -void SkLiteDL::setBounds(const SkRect& bounds) { - fBounds = bounds; } diff --git a/gfx/skia/skia/src/core/SkLiteDL.h b/gfx/skia/skia/src/core/SkLiteDL.h index 3e9eb5e294e1..1f344cd9e759 100644 --- a/gfx/skia/skia/src/core/SkLiteDL.h +++ b/gfx/skia/skia/src/core/SkLiteDL.h @@ -15,25 +15,19 @@ #include "SkRect.h" #include "SkTDArray.h" -class SkLiteDL final : public SkDrawable { +class SkLiteDL final { public: - static sk_sp New(SkRect); - void reset(SkRect); + ~SkLiteDL(); - void makeThreadsafe(); + void draw(SkCanvas* canvas) const; + + void reset(); bool empty() const { return fUsed == 0; } #ifdef SK_SUPPORT_LEGACY_DRAWFILTER void setDrawFilter(SkDrawFilter*); #endif - // Draws as if... - // SkRect bounds = this->getBounds(); - // canvas->saveLayer(&bounds, paint); - // this->draw(canvas, matrix); - // canvas->restore(); - void drawAsLayer(SkCanvas*, const SkMatrix*, const SkPaint*); - void save(); void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, SkCanvas::SaveLayerFlags); void restore(); @@ -43,10 +37,10 @@ public: void translate(SkScalar, SkScalar); void translateZ(SkScalar); - void clipPath (const SkPath&, SkCanvas::ClipOp, bool aa); - void clipRect (const SkRect&, SkCanvas::ClipOp, bool aa); - void clipRRect (const SkRRect&, SkCanvas::ClipOp, bool aa); - void clipRegion(const SkRegion&, SkCanvas::ClipOp); + void clipPath (const SkPath&, SkClipOp, bool aa); + void clipRect (const SkRect&, SkClipOp, bool aa); + void clipRRect (const SkRRect&, SkClipOp, bool aa); + void clipRegion(const SkRegion&, SkClipOp); void drawPaint (const SkPaint&); void drawPath (const SkPath&, const SkPaint&); @@ -78,32 +72,22 @@ public: const SkRect&, const SkPaint*); void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], - SkXfermode*, const SkPaint&); + SkBlendMode, const SkPaint&); void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&); - void drawVertices(SkCanvas::VertexMode, int, const SkPoint[], const SkPoint[], const SkColor[], - SkXfermode*, const uint16_t[], int, const SkPaint&); + void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&); void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, - SkXfermode::Mode, const SkRect*, const SkPaint*); - - void setBounds(const SkRect& bounds); + SkBlendMode, const SkRect*, const SkPaint*); private: - SkLiteDL(SkRect); - ~SkLiteDL(); - - SkRect onGetBounds() override; - void onDraw(SkCanvas*) override; - template void* push(size_t, Args&&...); template - void map(const Fn[], Args...); + void map(const Fn[], Args...) const; SkAutoTMalloc fBytes; - size_t fUsed; - size_t fReserved; - SkRect fBounds; + size_t fUsed = 0; + size_t fReserved = 0; }; #endif//SkLiteDL_DEFINED diff --git a/gfx/skia/skia/src/core/SkLiteRecorder.cpp b/gfx/skia/skia/src/core/SkLiteRecorder.cpp index 49b1984c44a9..f899f8822fcf 100644 --- a/gfx/skia/skia/src/core/SkLiteRecorder.cpp +++ b/gfx/skia/skia/src/core/SkLiteRecorder.cpp @@ -10,11 +10,11 @@ #include "SkSurface.h" SkLiteRecorder::SkLiteRecorder() - : SkCanvas({0,0,1,1}, SkCanvas::kConservativeRasterClip_InitFlag) + : INHERITED(1, 1) , fDL(nullptr) {} -void SkLiteRecorder::reset(SkLiteDL* dl) { - this->resetForNextPicture(dl->getBounds().roundOut()); +void SkLiteRecorder::reset(SkLiteDL* dl, const SkIRect& bounds) { + this->resetForNextPicture(bounds); fDL = dl; } @@ -25,7 +25,7 @@ sk_sp SkLiteRecorder::onNewSurface(const SkImageInfo&, const SkSurfac #ifdef SK_SUPPORT_LEGACY_DRAWFILTER SkDrawFilter* SkLiteRecorder::setDrawFilter(SkDrawFilter* df) { fDL->setDrawFilter(df); - return SkCanvas::setDrawFilter(df); + return this->INHERITED::setDrawFilter(df); } #endif @@ -40,21 +40,21 @@ void SkLiteRecorder::didConcat (const SkMatrix& matrix) { fDL-> concat(mat void SkLiteRecorder::didSetMatrix(const SkMatrix& matrix) { fDL->setMatrix(matrix); } void SkLiteRecorder::didTranslate(SkScalar dx, SkScalar dy) { fDL->translate(dx, dy); } -void SkLiteRecorder::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle style) { +void SkLiteRecorder::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle style) { fDL->clipRect(rect, op, style==kSoft_ClipEdgeStyle); - SkCanvas::onClipRect(rect, op, style); + this->INHERITED::onClipRect(rect, op, style); } -void SkLiteRecorder::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle style) { +void SkLiteRecorder::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle style) { fDL->clipRRect(rrect, op, style==kSoft_ClipEdgeStyle); - SkCanvas::onClipRRect(rrect, op, style); + this->INHERITED::onClipRRect(rrect, op, style); } -void SkLiteRecorder::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle style) { +void SkLiteRecorder::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle style) { fDL->clipPath(path, op, style==kSoft_ClipEdgeStyle); - SkCanvas::onClipPath(path, op, style); + this->INHERITED::onClipPath(path, op, style); } -void SkLiteRecorder::onClipRegion(const SkRegion& region, ClipOp op) { +void SkLiteRecorder::onClipRegion(const SkRegion& region, SkClipOp op) { fDL->clipRegion(region, op); - SkCanvas::onClipRegion(region, op); + this->INHERITED::onClipRegion(region, op); } void SkLiteRecorder::onDrawPaint(const SkPaint& paint) { @@ -171,31 +171,27 @@ void SkLiteRecorder::onDrawImageLattice(const SkImage* img, void SkLiteRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], - SkXfermode* xfermode, const SkPaint& paint) { - fDL->drawPatch(cubics, colors, texCoords, xfermode, paint); + SkBlendMode bmode, const SkPaint& paint) { + fDL->drawPatch(cubics, colors, texCoords, bmode, paint); } void SkLiteRecorder::onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { fDL->drawPoints(mode, count, pts, paint); } -void SkLiteRecorder::onDrawVertices(SkCanvas::VertexMode mode, - int count, const SkPoint vertices[], - const SkPoint texs[], const SkColor colors[], - SkXfermode* xfermode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { - fDL->drawVertices(mode, count, vertices, texs, colors, xfermode, indices, indexCount, paint); +void SkLiteRecorder::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode, + const SkPaint& paint) { + fDL->drawVertices(vertices, mode, paint); } void SkLiteRecorder::onDrawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[], const SkColor colors[], int count, - SkXfermode::Mode xfermode, + SkBlendMode bmode, const SkRect* cull, const SkPaint* paint) { - fDL->drawAtlas(atlas, xforms, texs, colors, count, xfermode, cull, paint); + fDL->drawAtlas(atlas, xforms, texs, colors, count, bmode, cull, paint); } void SkLiteRecorder::didTranslateZ(SkScalar dz) { diff --git a/gfx/skia/skia/src/core/SkLiteRecorder.h b/gfx/skia/skia/src/core/SkLiteRecorder.h index be278549a670..ea7cc78b2df1 100644 --- a/gfx/skia/skia/src/core/SkLiteRecorder.h +++ b/gfx/skia/skia/src/core/SkLiteRecorder.h @@ -8,14 +8,14 @@ #ifndef SkLiteRecorder_DEFINED #define SkLiteRecorder_DEFINED -#include "SkCanvas.h" +#include "SkNoDrawCanvas.h" class SkLiteDL; -class SkLiteRecorder final : public SkCanvas { +class SkLiteRecorder final : public SkNoDrawCanvas { public: SkLiteRecorder(); - void reset(SkLiteDL*); + void reset(SkLiteDL*, const SkIRect& bounds); sk_sp onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; @@ -31,10 +31,10 @@ public: void didSetMatrix(const SkMatrix&) override; void didTranslate(SkScalar, SkScalar) override; - void onClipRect (const SkRect&, ClipOp, ClipEdgeStyle) override; - void onClipRRect (const SkRRect&, ClipOp, ClipEdgeStyle) override; - void onClipPath (const SkPath&, ClipOp, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, ClipOp) override; + void onClipRect (const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect (const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath (const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; void onDrawPaint (const SkPaint&) override; void onDrawPath (const SkPath&, const SkPaint&) override; @@ -72,12 +72,11 @@ public: SrcRectConstraint) override; void onDrawPatch(const SkPoint[12], const SkColor[4], - const SkPoint[4], SkXfermode*, const SkPaint&) override; + const SkPoint[4], SkBlendMode, const SkPaint&) override; void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; - void onDrawVertices(VertexMode, int, const SkPoint[], const SkPoint[], const SkColor[], - SkXfermode*, const uint16_t[], int, const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], - int, SkXfermode::Mode, const SkRect*, const SkPaint*) override; + int, SkBlendMode, const SkRect*, const SkPaint*) override; #ifdef SK_EXPERIMENTAL_SHADOWING void didTranslateZ(SkScalar) override; @@ -90,6 +89,8 @@ public: #endif private: + typedef SkNoDrawCanvas INHERITED; + SkLiteDL* fDL; }; diff --git a/gfx/skia/skia/src/core/SkLocalMatrixImageFilter.h b/gfx/skia/skia/src/core/SkLocalMatrixImageFilter.h index 3ec50384b9cc..5d69a20f3f19 100644 --- a/gfx/skia/skia/src/core/SkLocalMatrixImageFilter.h +++ b/gfx/skia/skia/src/core/SkLocalMatrixImageFilter.h @@ -21,12 +21,6 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLocalMatrixImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(const SkMatrix& localM, SkImageFilter* input) { - return Make(localM, sk_sp(SkSafeRef(input))).release(); - } -#endif - protected: void flatten(SkWriteBuffer&) const override; sk_sp onFilterImage(SkSpecialImage* source, const Context&, diff --git a/gfx/skia/skia/src/core/SkLocalMatrixShader.cpp b/gfx/skia/skia/src/core/SkLocalMatrixShader.cpp index cdd7533273c4..33472f1f59b0 100644 --- a/gfx/skia/skia/src/core/SkLocalMatrixShader.cpp +++ b/gfx/skia/skia/src/core/SkLocalMatrixShader.cpp @@ -18,8 +18,7 @@ sk_sp SkLocalMatrixShader::asFragmentProcessor(const AsFPAr tmp.preConcat(*args.fLocalMatrix); } return fProxyShader->asFragmentProcessor(AsFPArgs( - args.fContext, args.fViewMatrix, &tmp, args.fFilterQuality, args.fDstColorSpace, - args.fGammaTreatment)); + args.fContext, args.fViewMatrix, &tmp, args.fFilterQuality, args.fDstColorSpace)); } #endif @@ -38,8 +37,9 @@ void SkLocalMatrixShader::flatten(SkWriteBuffer& buffer) const { buffer.writeFlattenable(fProxyShader.get()); } -SkShader::Context* SkLocalMatrixShader::onCreateContext(const ContextRec& rec, - void* storage) const { +SkShader::Context* SkLocalMatrixShader::onMakeContext( + const ContextRec& rec, SkArenaAlloc* alloc) const +{ ContextRec newRec(rec); SkMatrix tmp; if (rec.fLocalMatrix) { @@ -48,7 +48,33 @@ SkShader::Context* SkLocalMatrixShader::onCreateContext(const ContextRec& rec, } else { newRec.fLocalMatrix = &this->getLocalMatrix(); } - return fProxyShader->createContext(newRec, storage); + return fProxyShader->makeContext(newRec, alloc); +} + +SkImage* SkLocalMatrixShader::onIsAImage(SkMatrix* outMatrix, enum TileMode* mode) const { + SkMatrix imageMatrix; + SkImage* image = fProxyShader->isAImage(&imageMatrix, mode); + if (image && outMatrix) { + // Local matrix must be applied first so it is on the right side of the concat. + *outMatrix = SkMatrix::Concat(imageMatrix, this->getLocalMatrix()); + } + + return image; +} + +bool SkLocalMatrixShader::onAppendStages(SkRasterPipeline* p, + SkColorSpace* dst, + SkArenaAlloc* scratch, + const SkMatrix& ctm, + const SkPaint& paint, + const SkMatrix* localM) const { + SkMatrix tmp; + if (localM) { + tmp.setConcat(*localM, this->getLocalMatrix()); + } + + return fProxyShader->onAppendStages(p, dst, scratch, ctm, paint, + localM ? &tmp : &this->getLocalMatrix()); } #ifndef SK_IGNORE_TO_STRING @@ -70,14 +96,16 @@ sk_sp SkShader::makeWithLocalMatrix(const SkMatrix& localMatrix) const const SkMatrix* lm = &localMatrix; - SkShader* baseShader = const_cast(this); + sk_sp baseShader; SkMatrix otherLocalMatrix; - SkAutoTUnref proxy(this->refAsALocalMatrixShader(&otherLocalMatrix)); + sk_sp proxy(this->makeAsALocalMatrixShader(&otherLocalMatrix)); if (proxy) { otherLocalMatrix.preConcat(localMatrix); lm = &otherLocalMatrix; - baseShader = proxy.get(); + baseShader = proxy; + } else { + baseShader = sk_ref_sp(const_cast(this)); } - return sk_make_sp(baseShader, *lm); + return sk_make_sp(std::move(baseShader), *lm); } diff --git a/gfx/skia/skia/src/core/SkLocalMatrixShader.h b/gfx/skia/skia/src/core/SkLocalMatrixShader.h index 849d9af91dac..cba140906b45 100644 --- a/gfx/skia/skia/src/core/SkLocalMatrixShader.h +++ b/gfx/skia/skia/src/core/SkLocalMatrixShader.h @@ -13,12 +13,13 @@ #include "SkWriteBuffer.h" class GrFragmentProcessor; +class SkArenaAlloc; class SkLocalMatrixShader : public SkShader { public: - SkLocalMatrixShader(SkShader* proxy, const SkMatrix& localMatrix) + SkLocalMatrixShader(sk_sp proxy, const SkMatrix& localMatrix) : INHERITED(&localMatrix) - , fProxyShader(SkRef(proxy)) + , fProxyShader(std::move(proxy)) {} GradientType asAGradient(GradientInfo* info) const override { @@ -29,11 +30,11 @@ public: sk_sp asFragmentProcessor(const AsFPArgs&) const override; #endif - SkShader* refAsALocalMatrixShader(SkMatrix* localMatrix) const override { + sk_sp makeAsALocalMatrixShader(SkMatrix* localMatrix) const override { if (localMatrix) { *localMatrix = this->getLocalMatrix(); } - return SkRef(fProxyShader.get()); + return fProxyShader; } SK_TO_STRING_OVERRIDE() @@ -41,15 +42,13 @@ public: protected: void flatten(SkWriteBuffer&) const override; - Context* onCreateContext(const ContextRec&, void*) const override; - size_t onContextSize(const ContextRec& rec) const override { - return fProxyShader->contextSize(rec); - } + Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override; - SkImage* onIsAImage(SkMatrix* matrix, TileMode* mode) const override { - return fProxyShader->isAImage(matrix, mode); - } + SkImage* onIsAImage(SkMatrix* matrix, TileMode* mode) const override; + + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + const SkMatrix&, const SkPaint&, const SkMatrix*) const override; #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP bool onIsABitmap(SkBitmap* bitmap, SkMatrix* matrix, TileMode* mode) const override { @@ -58,7 +57,7 @@ protected: #endif private: - SkAutoTUnref fProxyShader; + sk_sp fProxyShader; typedef SkShader INHERITED; }; diff --git a/gfx/skia/skia/src/core/SkMallocPixelRef.cpp b/gfx/skia/skia/src/core/SkMallocPixelRef.cpp index fffc0448486c..ed3a97b7e0f5 100644 --- a/gfx/skia/skia/src/core/SkMallocPixelRef.cpp +++ b/gfx/skia/skia/src/core/SkMallocPixelRef.cpp @@ -37,22 +37,23 @@ static bool is_valid(const SkImageInfo& info, SkColorTable* ctable) { return true; } -SkMallocPixelRef* SkMallocPixelRef::NewDirect(const SkImageInfo& info, - void* addr, - size_t rowBytes, - SkColorTable* ctable) { - if (!is_valid(info, ctable)) { +sk_sp SkMallocPixelRef::MakeDirect(const SkImageInfo& info, + void* addr, + size_t rowBytes, + sk_sp ctable) { + if (!is_valid(info, ctable.get())) { return nullptr; } - return new SkMallocPixelRef(info, addr, rowBytes, ctable, nullptr, nullptr); + return sk_sp(new SkMallocPixelRef(info, addr, rowBytes, std::move(ctable), + nullptr, nullptr)); } - SkMallocPixelRef* SkMallocPixelRef::NewUsing(void*(*alloc)(size_t), - const SkImageInfo& info, - size_t requestedRowBytes, - SkColorTable* ctable) { - if (!is_valid(info, ctable)) { + sk_sp SkMallocPixelRef::MakeUsing(void*(*alloc)(size_t), + const SkImageInfo& info, + size_t requestedRowBytes, + sk_sp ctable) { + if (!is_valid(info, ctable.get())) { return nullptr; } @@ -84,139 +85,109 @@ SkMallocPixelRef* SkMallocPixelRef::NewDirect(const SkImageInfo& info, return nullptr; } - return new SkMallocPixelRef(info, addr, rowBytes, ctable, sk_free_releaseproc, nullptr); + return sk_sp(new SkMallocPixelRef(info, addr, rowBytes, std::move(ctable), + sk_free_releaseproc, nullptr)); } -SkMallocPixelRef* SkMallocPixelRef::NewAllocate(const SkImageInfo& info, +sk_sp SkMallocPixelRef::MakeAllocate(const SkImageInfo& info, size_t rowBytes, - SkColorTable* ctable) { + sk_sp ctable) { auto sk_malloc_nothrow = [](size_t size) { return sk_malloc_flags(size, 0); }; - return NewUsing(sk_malloc_nothrow, info, rowBytes, ctable); + return MakeUsing(sk_malloc_nothrow, info, rowBytes, std::move(ctable)); } -SkMallocPixelRef* SkMallocPixelRef::NewZeroed(const SkImageInfo& info, - size_t rowBytes, - SkColorTable* ctable) { - return NewUsing(sk_calloc, info, rowBytes, ctable); -} - -SkMallocPixelRef* SkMallocPixelRef::NewWithProc(const SkImageInfo& info, - size_t rowBytes, - SkColorTable* ctable, - void* addr, - SkMallocPixelRef::ReleaseProc proc, - void* context) { - if (!is_valid(info, ctable)) { - return nullptr; - } - return new SkMallocPixelRef(info, addr, rowBytes, ctable, proc, context); +sk_sp SkMallocPixelRef::MakeZeroed(const SkImageInfo& info, + size_t rowBytes, + sk_sp ctable) { + return MakeUsing(sk_calloc, info, rowBytes, std::move(ctable)); } static void sk_data_releaseproc(void*, void* dataPtr) { (static_cast(dataPtr))->unref(); } -SkMallocPixelRef* SkMallocPixelRef::NewWithData(const SkImageInfo& info, +sk_sp SkMallocPixelRef::MakeWithProc(const SkImageInfo& info, + size_t rowBytes, + sk_sp ctable, + void* addr, + SkMallocPixelRef::ReleaseProc proc, + void* context) { + if (!is_valid(info, ctable.get())) { + if (proc) { + proc(addr, context); + } + return nullptr; + } + return sk_sp(new SkMallocPixelRef(info, addr, rowBytes, std::move(ctable), + proc, context)); +} + +sk_sp SkMallocPixelRef::MakeWithData(const SkImageInfo& info, size_t rowBytes, - SkColorTable* ctable, - SkData* data) { + sk_sp ctable, + sk_sp data) { SkASSERT(data != nullptr); - if (!is_valid(info, ctable)) { + if (!is_valid(info, ctable.get())) { return nullptr; } - if ((rowBytes < info.minRowBytes()) - || (data->size() < info.getSafeSize(rowBytes))) { + if ((rowBytes < info.minRowBytes()) || (data->size() < info.getSafeSize(rowBytes))) { return nullptr; } - data->ref(); - SkMallocPixelRef* pr = - new SkMallocPixelRef(info, const_cast(data->data()), rowBytes, ctable, - sk_data_releaseproc, static_cast(data)); - SkASSERT(pr != nullptr); - // We rely on the immutability of the pixels to make the - // const_cast okay. - pr->setImmutable(); - return pr; + // must get this address before we call release + void* pixels = const_cast(data->data()); + SkPixelRef* pr = new SkMallocPixelRef(info, pixels, rowBytes, std::move(ctable), + sk_data_releaseproc, data.release()); + pr->setImmutable(); // since we were created with (immutable) data + return sk_sp(pr); } /////////////////////////////////////////////////////////////////////////////// -SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage, - size_t rowBytes, SkColorTable* ctable, - bool ownsPixels) - : INHERITED(info) - , fReleaseProc(ownsPixels ? sk_free_releaseproc : nullptr) - , fReleaseProcContext(nullptr) { - // This constructor is now DEPRICATED. - SkASSERT(is_valid(info, ctable)); - SkASSERT(rowBytes >= info.minRowBytes()); - - if (kIndex_8_SkColorType != info.colorType()) { - ctable = nullptr; +static sk_sp sanitize(const SkImageInfo& info, sk_sp ctable) { + if (kIndex_8_SkColorType == info.colorType()) { + SkASSERT(ctable); + } else { + ctable.reset(nullptr); } - - fStorage = storage; - fCTable = ctable; - fRB = rowBytes; - SkSafeRef(ctable); - - this->setPreLocked(fStorage, rowBytes, fCTable); + return ctable; } SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage, - size_t rowBytes, SkColorTable* ctable, + size_t rowBytes, sk_sp ctable, SkMallocPixelRef::ReleaseProc proc, void* context) - : INHERITED(info) + : INHERITED(info, storage, rowBytes, sanitize(info, std::move(ctable))) , fReleaseProc(proc) , fReleaseProcContext(context) -{ - SkASSERT(is_valid(info, ctable)); - SkASSERT(rowBytes >= info.minRowBytes()); - - if (kIndex_8_SkColorType != info.colorType()) { - ctable = nullptr; - } - - fStorage = storage; - fCTable = ctable; - fRB = rowBytes; - SkSafeRef(ctable); - - this->setPreLocked(fStorage, rowBytes, fCTable); -} +{} SkMallocPixelRef::~SkMallocPixelRef() { - SkSafeUnref(fCTable); if (fReleaseProc != nullptr) { - fReleaseProc(fStorage, fReleaseProcContext); + fReleaseProc(this->pixels(), fReleaseProcContext); } } +#ifdef SK_SUPPORT_LEGACY_NO_ADDR_PIXELREF bool SkMallocPixelRef::onNewLockPixels(LockRec* rec) { - rec->fPixels = fStorage; - rec->fRowBytes = fRB; - rec->fColorTable = fCTable; + sk_throw(); // should never get here return true; } void SkMallocPixelRef::onUnlockPixels() { // nothing to do } +#endif size_t SkMallocPixelRef::getAllocatedSizeInBytes() const { - return this->info().getSafeSize(fRB); + return this->info().getSafeSize(this->rowBytes()); } -/////////////////////////////////////////////////////////////////////////////// - -SkPixelRef* SkMallocPixelRef::PRFactory::create(const SkImageInfo& info, size_t rowBytes, - SkColorTable* ctable) { - return SkMallocPixelRef::NewAllocate(info, rowBytes, ctable); -} - -SkPixelRef* SkMallocPixelRef::ZeroedPRFactory::create(const SkImageInfo& info, size_t rowBytes, - SkColorTable* ctable) { - return SkMallocPixelRef::NewZeroed(info, rowBytes, ctable); +#ifdef SK_SUPPORT_LEGACY_PIXELREFFACTORY +SkMallocPixelRef* SkMallocPixelRef::NewWithData(const SkImageInfo& info, + size_t rowBytes, + SkColorTable* ctable, + SkData* data) { + return (SkMallocPixelRef*)MakeWithData(info, rowBytes, sk_ref_sp(ctable), sk_ref_sp(data)).release(); } +#endif diff --git a/gfx/skia/skia/src/core/SkMask.cpp b/gfx/skia/skia/src/core/SkMask.cpp index 111508074a3e..167d30d166b1 100644 --- a/gfx/skia/skia/src/core/SkMask.cpp +++ b/gfx/skia/skia/src/core/SkMask.cpp @@ -7,6 +7,8 @@ #include "SkMask.h" +#include "SkMalloc.h" + //#define TRACK_SKMASK_LIFETIME /** returns the product if it is positive and fits in 31 bits. Otherwise this diff --git a/gfx/skia/skia/src/core/SkMaskCache.cpp b/gfx/skia/skia/src/core/SkMaskCache.cpp index eb7c8f0941f3..f998a928ccfb 100644 --- a/gfx/skia/skia/src/core/SkMaskCache.cpp +++ b/gfx/skia/skia/src/core/SkMaskCache.cpp @@ -44,7 +44,7 @@ struct RRectBlurRec : public SkResourceCache::Rec { fValue.fData = data; fValue.fData->attachToCacheAndRef(); } - ~RRectBlurRec() { + ~RRectBlurRec() override { fValue.fData->detachFromCacheAndUnref(); } @@ -110,15 +110,15 @@ public: SkASSERT(1 == count || 2 == count); SkIRect ir; rects[0].roundOut(&ir); - fSizes[0] = SkSize::Make(rects[0].width(), rects[0].height()); + fSizes[0] = SkSize{rects[0].width(), rects[0].height()}; if (2 == count) { - fSizes[1] = SkSize::Make(rects[1].width(), rects[1].height()); - fSizes[2] = SkSize::Make(rects[0].x() - rects[1].x(), rects[0].y() - rects[1].y()); + fSizes[1] = SkSize{rects[1].width(), rects[1].height()}; + fSizes[2] = SkSize{rects[0].x() - rects[1].x(), rects[0].y() - rects[1].y()}; } else { - fSizes[1] = SkSize::Make(0, 0); - fSizes[2] = SkSize::Make(0, 0); + fSizes[1] = SkSize{0, 0}; + fSizes[2] = SkSize{0, 0}; } - fSizes[3] = SkSize::Make(rects[0].x() - ir.x(), rects[0].y() - ir.y()); + fSizes[3] = SkSize{rects[0].x() - ir.x(), rects[0].y() - ir.y()}; this->init(&gRectsBlurKeyNamespaceLabel, 0, sizeof(fSigma) + sizeof(fStyle) + sizeof(fQuality) + sizeof(fSizes)); @@ -138,7 +138,7 @@ struct RectsBlurRec : public SkResourceCache::Rec { fValue.fData = data; fValue.fData->attachToCacheAndRef(); } - ~RectsBlurRec() { + ~RectsBlurRec() override { fValue.fData->detachFromCacheAndUnref(); } diff --git a/gfx/skia/skia/src/core/SkMaskFilter.cpp b/gfx/skia/skia/src/core/SkMaskFilter.cpp index 62cfcf964643..e8577488fc1d 100644 --- a/gfx/skia/skia/src/core/SkMaskFilter.cpp +++ b/gfx/skia/skia/src/core/SkMaskFilter.cpp @@ -5,18 +5,19 @@ * found in the LICENSE file. */ - #include "SkMaskFilter.h" + +#include "SkAutoMalloc.h" #include "SkBlitter.h" -#include "SkDraw.h" #include "SkCachedData.h" +#include "SkDraw.h" #include "SkPath.h" -#include "SkRasterClip.h" #include "SkRRect.h" -#include "SkTypes.h" +#include "SkRasterClip.h" #if SK_SUPPORT_GPU #include "GrTexture.h" +#include "GrTextureProxy.h" #include "SkGr.h" #endif @@ -313,20 +314,19 @@ bool SkMaskFilter::canFilterMaskGPU(const SkRRect& devRRect, return false; } - bool SkMaskFilter::directFilterMaskGPU(GrTextureProvider* texProvider, - GrDrawContext* drawContext, - GrPaint* grp, - const GrClip&, - const SkMatrix& viewMatrix, - const SkStrokeRec& strokeRec, - const SkPath& path) const { +bool SkMaskFilter::directFilterMaskGPU(GrContext*, + GrRenderTargetContext* renderTargetContext, + GrPaint&&, + const GrClip&, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkPath& path) const { return false; } - bool SkMaskFilter::directFilterRRectMaskGPU(GrContext*, - GrDrawContext* drawContext, - GrPaint* grp, + GrRenderTargetContext* renderTargetContext, + GrPaint&&, const GrClip&, const SkMatrix& viewMatrix, const SkStrokeRec& strokeRec, @@ -335,11 +335,11 @@ bool SkMaskFilter::directFilterRRectMaskGPU(GrContext*, return false; } -bool SkMaskFilter::filterMaskGPU(GrTexture* src, - const SkMatrix& ctm, - const SkIRect& maskRect, - GrTexture** result) const { - return false; +sk_sp SkMaskFilter::filterMaskGPU(GrContext*, + sk_sp srcProxy, + const SkMatrix& ctm, + const SkIRect& maskRect) const { + return nullptr; } #endif diff --git a/gfx/skia/skia/src/core/SkMaskGamma.h b/gfx/skia/skia/src/core/SkMaskGamma.h index 94219d42ac3a..f90f75a878ed 100644 --- a/gfx/skia/skia/src/core/SkMaskGamma.h +++ b/gfx/skia/skia/src/core/SkMaskGamma.h @@ -174,11 +174,11 @@ private: */ template class SkTMaskPreBlend { private: - SkTMaskPreBlend(const SkTMaskGamma* parent, + SkTMaskPreBlend(sk_sp> parent, const uint8_t* r, const uint8_t* g, const uint8_t* b) - : fParent(SkSafeRef(parent)), fR(r), fG(g), fB(b) { } + : fParent(std::move(parent)), fR(r), fG(g), fB(b) { } - SkAutoTUnref > fParent; + sk_sp> fParent; friend class SkTMaskGamma; public: /** Creates a non applicable SkTMaskPreBlend. */ @@ -189,7 +189,7 @@ public: * when return value optimization is enabled. */ SkTMaskPreBlend(const SkTMaskPreBlend& that) - : fParent(SkSafeRef(that.fParent.get())), fR(that.fR), fG(that.fG), fB(that.fB) { } + : fParent(that.fParent), fR(that.fR), fG(that.fG), fB(that.fB) { } ~SkTMaskPreBlend() { } @@ -205,7 +205,7 @@ template SkTMaskPreBlend SkTMaskGamma::preBlend(SkColor color) const { return fIsLinear ? SkTMaskPreBlend() - : SkTMaskPreBlend(this, + : SkTMaskPreBlend(sk_ref_sp(this), fGammaTables[SkColorGetR(color) >> (8 - MAX_LUM_BITS)], fGammaTables[SkColorGetG(color) >> (8 - MAX_LUM_BITS)], fGammaTables[SkColorGetB(color) >> (8 - MAX_LUM_BITS)]); diff --git a/gfx/skia/skia/src/core/SkMathPriv.h b/gfx/skia/skia/src/core/SkMathPriv.h index fca09f3ffc30..5ef0cb25e445 100644 --- a/gfx/skia/skia/src/core/SkMathPriv.h +++ b/gfx/skia/skia/src/core/SkMathPriv.h @@ -131,6 +131,16 @@ static inline int SkNextPow2(int value) { return 1 << (32 - SkCLZ(value - 1)); } +/** +* Returns the largest power-of-2 that is <= the specified value. If value +* is already a power of 2, then it is returned unchanged. It is undefined +* if value is <= 0. +*/ +static inline int SkPrevPow2(int value) { + SkASSERT(value > 0); + return 1 << (32 - SkCLZ(value >> 1)); +} + /** * Returns the log2 of the specified value, were that value to be rounded up * to the next power of 2. It is undefined to pass 0. Examples: @@ -145,6 +155,20 @@ static inline int SkNextLog2(uint32_t value) { return 32 - SkCLZ(value - 1); } +/** +* Returns the log2 of the specified value, were that value to be rounded down +* to the previous power of 2. It is undefined to pass 0. Examples: +* SkPrevLog2(1) -> 0 +* SkPrevLog2(2) -> 1 +* SkPrevLog2(3) -> 1 +* SkPrevLog2(4) -> 2 +* SkPrevLog2(5) -> 2 +*/ +static inline int SkPrevLog2(uint32_t value) { + SkASSERT(value != 0); + return 32 - SkCLZ(value >> 1); +} + /////////////////////////////////////////////////////////////////////////////// /** @@ -154,6 +178,28 @@ static inline uint32_t GrNextPow2(uint32_t n) { return n ? (1 << (32 - SkCLZ(n - 1))) : 1; } +/** + * Returns the next power of 2 >= n or n if the next power of 2 can't be represented by size_t. + */ +static inline size_t GrNextSizePow2(size_t n) { + constexpr int kNumSizeTBits = 8 * sizeof(size_t); + constexpr size_t kHighBitSet = size_t(1) << (kNumSizeTBits - 1); + + if (!n) { + return 1; + } else if (n >= kHighBitSet) { + return n; + } + + n--; + uint32_t shift = 1; + while (shift < kNumSizeTBits) { + n |= n >> shift; + shift <<= 1; + } + return n + 1; +} + static inline int GrNextPow2(int n) { SkASSERT(n >= 0); // this impl only works for non-neg. return n ? (1 << (32 - SkCLZ(n - 1))) : 1; diff --git a/gfx/skia/skia/src/core/SkMatrix.cpp b/gfx/skia/skia/src/core/SkMatrix.cpp index a05ae0a17767..8517d875557f 100644 --- a/gfx/skia/skia/src/core/SkMatrix.cpp +++ b/gfx/skia/skia/src/core/SkMatrix.cpp @@ -271,7 +271,7 @@ static inline SkScalar scross(SkScalar a, SkScalar b, SkScalar c, SkScalar d) { } void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) { - if (dx || dy) { + if ((dx != 0) | (dy != 0)) { fMat[kMTransX] = dx; fMat[kMTransY] = dy; @@ -286,31 +286,24 @@ void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) { } void SkMatrix::preTranslate(SkScalar dx, SkScalar dy) { - if (!dx && !dy) { - return; - } + const unsigned mask = this->getType(); - if (fTypeMask <= kTranslate_Mask) { + if (mask <= kTranslate_Mask) { fMat[kMTransX] += dx; fMat[kMTransY] += dy; - this->setTypeMask((fMat[kMTransX] != 0 || fMat[kMTransY] != 0) ? kTranslate_Mask - : kIdentity_Mask); - } else if (this->hasPerspective()) { + } else if (mask & kPerspective_Mask) { SkMatrix m; m.setTranslate(dx, dy); this->preConcat(m); + return; } else { fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy); fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy); - this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); } + this->updateTranslateMask(); } void SkMatrix::postTranslate(SkScalar dx, SkScalar dy) { - if (!dx && !dy) { - return; - } - if (this->hasPerspective()) { SkMatrix m; m.setTranslate(dx, dy); @@ -318,7 +311,7 @@ void SkMatrix::postTranslate(SkScalar dx, SkScalar dy) { } else { fMat[kMTransX] += dx; fMat[kMTransY] += dy; - this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); + this->updateTranslateMask(); } } @@ -1038,7 +1031,7 @@ void SkMatrix::Affine_vpts(const SkMatrix& m, SkPoint dst[], const SkPoint src[] const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = { SkMatrix::Identity_pts, SkMatrix::Trans_pts, - SkMatrix::Scale_pts, SkMatrix::Scale_pts, + SkMatrix::Scale_pts, SkMatrix::Scale_pts, SkMatrix::Affine_vpts, SkMatrix::Affine_vpts, SkMatrix::Affine_vpts, SkMatrix::Affine_vpts, // repeat the persp proc 8 times @@ -1410,32 +1403,32 @@ bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst, /* check if abs(x2) > abs(y2) */ if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) { - float denom = SkScalarMulDiv(x1, y2, x2) - y1; + float denom = (x1 * y2 / x2) - y1; if (checkForZero(denom)) { return false; } - a1 = (SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1) / denom; + a1 = (((x0 - x1) * y2 / x2) - y0 + y1) / denom; } else { - float denom = x1 - SkScalarMulDiv(y1, x2, y2); + float denom = x1 - (y1 * x2 / y2); if (checkForZero(denom)) { return false; } - a1 = (x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2)) / denom; + a1 = (x0 - x1 - ((y0 - y1) * x2 / y2)) / denom; } /* check if abs(x1) > abs(y1) */ if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) { - float denom = y2 - SkScalarMulDiv(x2, y1, x1); + float denom = y2 - (x2 * y1 / x1); if (checkForZero(denom)) { return false; } - a2 = (y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1)) / denom; + a2 = (y0 - y2 - ((x0 - x2) * y1 / x1)) / denom; } else { - float denom = SkScalarMulDiv(y2, x1, y1) - x2; + float denom = (y2 * x1 / y1) - x2; if (checkForZero(denom)) { return false; } - a2 = (SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2) / denom; + a2 = (((y0 - y2) * x1 / y1) - x0 + x2) / denom; } float invScale = SkScalarInvert(scale.fX); diff --git a/gfx/skia/skia/src/core/SkMatrix44.cpp b/gfx/skia/skia/src/core/SkMatrix44.cpp index 818f23af5a4f..f5cdc2344adf 100644 --- a/gfx/skia/skia/src/core/SkMatrix44.cpp +++ b/gfx/skia/skia/src/core/SkMatrix44.cpp @@ -946,21 +946,15 @@ bool SkMatrix44::preserves2dAxisAlignment (SkMScalar epsilon) const { /////////////////////////////////////////////////////////////////////////////// void SkMatrix44::dump() const { - static const char* format = - "[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]\n"; -#if 0 + static const char* format = "|%g %g %g %g|\n" + "|%g %g %g %g|\n" + "|%g %g %g %g|\n" + "|%g %g %g %g|\n"; SkDebugf(format, fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0], fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1], fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2], fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]); -#else - SkDebugf(format, - fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3], - fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3], - fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3], - fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]); -#endif } /////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/core/SkMatrixImageFilter.h b/gfx/skia/skia/src/core/SkMatrixImageFilter.h index e02541c12ece..f6880877c015 100644 --- a/gfx/skia/skia/src/core/SkMatrixImageFilter.h +++ b/gfx/skia/skia/src/core/SkMatrixImageFilter.h @@ -34,14 +34,6 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMatrixImageFilter) -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(const SkMatrix& transform, - SkFilterQuality filterQuality, - SkImageFilter* input = nullptr) { - return Make(transform, filterQuality, sk_ref_sp(input)).release(); - } -#endif - protected: SkMatrixImageFilter(const SkMatrix& transform, SkFilterQuality, diff --git a/gfx/skia/skia/src/core/SkMatrixUtils.h b/gfx/skia/skia/src/core/SkMatrixUtils.h index 0e01fbe95399..c311a6cfd2b8 100644 --- a/gfx/skia/skia/src/core/SkMatrixUtils.h +++ b/gfx/skia/skia/src/core/SkMatrixUtils.h @@ -8,6 +8,7 @@ #ifndef SkMatrixUtils_DEFINED #define SkMatrixUtils_DEFINED +#include "SkPoint.h" #include "SkSize.h" class SkMatrix; diff --git a/gfx/skia/skia/src/core/SkMetaData.cpp b/gfx/skia/skia/src/core/SkMetaData.cpp index 6e1f5e2a3d0e..d1564e9fecce 100644 --- a/gfx/skia/skia/src/core/SkMetaData.cpp +++ b/gfx/skia/skia/src/core/SkMetaData.cpp @@ -7,6 +7,8 @@ #include "SkMetaData.h" + +#include "SkMalloc.h" #include "SkRefCnt.h" struct PtrPair { diff --git a/gfx/skia/skia/src/core/SkMipMap.cpp b/gfx/skia/skia/src/core/SkMipMap.cpp index c5bd3ac3b754..d15d2c96dd37 100644 --- a/gfx/skia/skia/src/core/SkMipMap.cpp +++ b/gfx/skia/skia/src/core/SkMipMap.cpp @@ -12,6 +12,7 @@ #include "SkMathPriv.h" #include "SkNx.h" #include "SkPM4fPriv.h" +#include "SkSRGB.h" #include "SkTypes.h" // @@ -23,7 +24,6 @@ struct ColorTypeFilter_8888 { typedef uint32_t Type; -#if defined(SKNX_IS_FAST) static Sk4h Expand(uint32_t x) { return SkNx_cast(Sk4b::Load(&x)); } @@ -32,23 +32,21 @@ struct ColorTypeFilter_8888 { SkNx_cast(x).store(&r); return r; } -#else - static uint64_t Expand(uint32_t x) { - return (x & 0xFF00FF) | ((uint64_t)(x & 0xFF00FF00) << 24); - } - static uint32_t Compact(uint64_t x) { - return (uint32_t)((x & 0xFF00FF) | ((x >> 24) & 0xFF00FF00)); - } -#endif }; struct ColorTypeFilter_S32 { typedef uint32_t Type; - static Sk4f Expand(uint32_t x) { - return Sk4f_fromS32(x); + static Sk4h Expand(uint32_t x) { + return Sk4h(sk_linear12_from_srgb[(x ) & 0xFF], + sk_linear12_from_srgb[(x >> 8) & 0xFF], + sk_linear12_from_srgb[(x >> 16) & 0xFF], + (x >> 24) << 4); } - static uint32_t Compact(const Sk4f& x) { - return Sk4f_toS32(x); + static uint32_t Compact(const Sk4h& x) { + return sk_linear12_to_srgb[x[0]] | + sk_linear12_to_srgb[x[1]] << 8 | + sk_linear12_to_srgb[x[2]] << 16 | + (x[3] >> 4) << 24; } }; @@ -244,18 +242,30 @@ template void downsample_3_2(void* dst, const void* src, size_t src auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); auto d = static_cast(dst); - auto c02 = F::Expand(p0[0]); - auto c12 = F::Expand(p1[0]); - for (int i = 0; i < count; ++i) { - auto c00 = c02; - auto c01 = F::Expand(p0[1]); - c02 = F::Expand(p0[2]); - auto c10 = c12; - auto c11 = F::Expand(p1[1]); - c12 = F::Expand(p1[2]); + // Given pixels: + // a0 b0 c0 d0 e0 ... + // a1 b1 c1 d1 e1 ... + // We want: + // (a0 + 2*b0 + c0 + a1 + 2*b1 + c1) / 8 + // (c0 + 2*d0 + e0 + c1 + 2*d1 + e1) / 8 + // ... - auto c = add_121(c00, c01, c02) + add_121(c10, c11, c12); - d[i] = F::Compact(shift_right(c, 3)); + auto c0 = F::Expand(p0[0]); + auto c1 = F::Expand(p1[0]); + auto c = c0 + c1; + for (int i = 0; i < count; ++i) { + auto a = c; + + auto b0 = F::Expand(p0[1]); + auto b1 = F::Expand(p1[1]); + auto b = b0 + b0 + b1 + b1; + + c0 = F::Expand(p0[2]); + c1 = F::Expand(p1[2]); + c = c0 + c1; + + auto sum = a + b + c; + d[i] = F::Compact(shift_right(sum, 3)); p0 += 2; p1 += 2; } @@ -268,25 +278,34 @@ template void downsample_3_3(void* dst, const void* src, size_t src auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); auto d = static_cast(dst); - auto c02 = F::Expand(p0[0]); - auto c12 = F::Expand(p1[0]); - auto c22 = F::Expand(p2[0]); - for (int i = 0; i < count; ++i) { - auto c00 = c02; - auto c01 = F::Expand(p0[1]); - c02 = F::Expand(p0[2]); - auto c10 = c12; - auto c11 = F::Expand(p1[1]); - c12 = F::Expand(p1[2]); - auto c20 = c22; - auto c21 = F::Expand(p2[1]); - c22 = F::Expand(p2[2]); + // Given pixels: + // a0 b0 c0 d0 e0 ... + // a1 b1 c1 d1 e1 ... + // a2 b2 c2 d2 e2 ... + // We want: + // (a0 + 2*b0 + c0 + 2*a1 + 4*b1 + 2*c1 + a2 + 2*b2 + c2) / 16 + // (c0 + 2*d0 + e0 + 2*c1 + 4*d1 + 2*e1 + c2 + 2*d2 + e2) / 16 + // ... - auto c = - add_121(c00, c01, c02) + - shift_left(add_121(c10, c11, c12), 1) + - add_121(c20, c21, c22); - d[i] = F::Compact(shift_right(c, 4)); + auto c0 = F::Expand(p0[0]); + auto c1 = F::Expand(p1[0]); + auto c2 = F::Expand(p2[0]); + auto c = add_121(c0, c1, c2); + for (int i = 0; i < count; ++i) { + auto a = c; + + auto b0 = F::Expand(p0[1]); + auto b1 = F::Expand(p1[1]); + auto b2 = F::Expand(p2[1]); + auto b = shift_left(add_121(b0, b1, b2), 1); + + c0 = F::Expand(p0[2]); + c1 = F::Expand(p1[2]); + c2 = F::Expand(p2[2]); + c = add_121(c0, c1, c2); + + auto sum = a + b + c; + d[i] = F::Compact(shift_right(sum, 4)); p0 += 2; p1 += 2; p2 += 2; @@ -295,6 +314,163 @@ template void downsample_3_3(void* dst, const void* src, size_t src /////////////////////////////////////////////////////////////////////////////////////////////////// +// Some sRGB specific performance optimizations. + +void downsample_2_2_srgb(void* dst, const void* src, size_t srcRB, int count) { + const uint8_t* p0 = ((const uint8_t*) src); + const uint8_t* p1 = ((const uint8_t*) src) + srcRB; + uint8_t* d = (uint8_t*) dst; + + // Given pixels: + // a0 b0 c0 d0 ... + // a1 b1 c1 d1 ... + // We want: + // (a0 + b0 + a1 + b1) / 4 + // (c0 + d0 + c1 + d1) / 4 + // ... + while (count >= 2) { + Sk8h a0c0 = Sk8h(sk_linear12_from_srgb[p0[ 0]], + sk_linear12_from_srgb[p0[ 1]], + sk_linear12_from_srgb[p0[ 2]], + p0[ 3] << 4 , + sk_linear12_from_srgb[p0[ 8]], + sk_linear12_from_srgb[p0[ 9]], + sk_linear12_from_srgb[p0[10]], + p0[11] << 4 ); + Sk8h b0d0 = Sk8h(sk_linear12_from_srgb[p0[ 4]], + sk_linear12_from_srgb[p0[ 5]], + sk_linear12_from_srgb[p0[ 6]], + p0[ 7] << 4 , + sk_linear12_from_srgb[p0[12]], + sk_linear12_from_srgb[p0[13]], + sk_linear12_from_srgb[p0[14]], + p0[15] << 4 ); + Sk8h a1c1 = Sk8h(sk_linear12_from_srgb[p1[ 0]], + sk_linear12_from_srgb[p1[ 1]], + sk_linear12_from_srgb[p1[ 2]], + p1[ 3] << 4 , + sk_linear12_from_srgb[p1[ 8]], + sk_linear12_from_srgb[p1[ 9]], + sk_linear12_from_srgb[p1[10]], + p1[11] << 4 ); + Sk8h b1d1 = Sk8h(sk_linear12_from_srgb[p1[ 4]], + sk_linear12_from_srgb[p1[ 5]], + sk_linear12_from_srgb[p1[ 6]], + p1[ 7] << 4 , + sk_linear12_from_srgb[p1[12]], + sk_linear12_from_srgb[p1[13]], + sk_linear12_from_srgb[p1[14]], + p1[15] << 4 ); + + Sk8h avg = (a0c0 + b0d0 + a1c1 + b1d1) >> 2; + d[0] = sk_linear12_to_srgb[avg[0]]; + d[1] = sk_linear12_to_srgb[avg[1]]; + d[2] = sk_linear12_to_srgb[avg[2]]; + d[3] = avg[3] >> 4; + d[4] = sk_linear12_to_srgb[avg[4]]; + d[5] = sk_linear12_to_srgb[avg[5]]; + d[6] = sk_linear12_to_srgb[avg[6]]; + d[7] = avg[7] >> 4; + + p0 += 16; + p1 += 16; + d += 8; + count -= 2; + } + + if (count) { + downsample_2_2(d, p0, srcRB, count); + } +} + +void downsample_2_3_srgb(void* dst, const void* src, size_t srcRB, int count) { + const uint8_t* p0 = ((const uint8_t*) src); + const uint8_t* p1 = p0 + srcRB; + const uint8_t* p2 = p1 + srcRB; + uint8_t* d = (uint8_t*) dst; + + // Given pixels: + // a0 b0 c0 d0 ... + // a1 b1 c1 d1 ... + // a2 b2 c2 d2 ... + // We want: + // (a0 + b0 + 2*a1 + 2*b1 + a2 + b2) / 8 + // (c0 + d0 + 2*c1 + 2*d1 + c2 + d2) / 8 + // ... + while (count >= 2) { + Sk8h a0c0 = Sk8h(sk_linear12_from_srgb[p0[ 0]], + sk_linear12_from_srgb[p0[ 1]], + sk_linear12_from_srgb[p0[ 2]], + p0[ 3] << 4 , + sk_linear12_from_srgb[p0[ 8]], + sk_linear12_from_srgb[p0[ 9]], + sk_linear12_from_srgb[p0[10]], + p0[11] << 4 ); + Sk8h b0d0 = Sk8h(sk_linear12_from_srgb[p0[ 4]], + sk_linear12_from_srgb[p0[ 5]], + sk_linear12_from_srgb[p0[ 6]], + p0[ 7] << 4 , + sk_linear12_from_srgb[p0[12]], + sk_linear12_from_srgb[p0[13]], + sk_linear12_from_srgb[p0[14]], + p0[15] << 4 ); + Sk8h a1c1 = Sk8h(sk_linear12_from_srgb[p1[ 0]], + sk_linear12_from_srgb[p1[ 1]], + sk_linear12_from_srgb[p1[ 2]], + p1[ 3] << 4 , + sk_linear12_from_srgb[p1[ 8]], + sk_linear12_from_srgb[p1[ 9]], + sk_linear12_from_srgb[p1[10]], + p1[11] << 4 ); + Sk8h b1d1 = Sk8h(sk_linear12_from_srgb[p1[ 4]], + sk_linear12_from_srgb[p1[ 5]], + sk_linear12_from_srgb[p1[ 6]], + p1[ 7] << 4 , + sk_linear12_from_srgb[p1[12]], + sk_linear12_from_srgb[p1[13]], + sk_linear12_from_srgb[p1[14]], + p1[15] << 4 ); + Sk8h a2c2 = Sk8h(sk_linear12_from_srgb[p2[ 0]], + sk_linear12_from_srgb[p2[ 1]], + sk_linear12_from_srgb[p2[ 2]], + p2[ 3] << 4 , + sk_linear12_from_srgb[p2[ 8]], + sk_linear12_from_srgb[p2[ 9]], + sk_linear12_from_srgb[p2[10]], + p2[11] << 4 ); + Sk8h b2d2 = Sk8h(sk_linear12_from_srgb[p2[ 4]], + sk_linear12_from_srgb[p2[ 5]], + sk_linear12_from_srgb[p2[ 6]], + p2[ 7] << 4 , + sk_linear12_from_srgb[p2[12]], + sk_linear12_from_srgb[p2[13]], + sk_linear12_from_srgb[p2[14]], + p2[15] << 4 ); + + Sk8h avg = (a0c0 + b0d0 + a1c1 + a1c1 + b1d1 + b1d1 + a2c2 + b2d2) >> 3; + d[0] = sk_linear12_to_srgb[avg[0]]; + d[1] = sk_linear12_to_srgb[avg[1]]; + d[2] = sk_linear12_to_srgb[avg[2]]; + d[3] = avg[3] >> 4; + d[4] = sk_linear12_to_srgb[avg[4]]; + d[5] = sk_linear12_to_srgb[avg[5]]; + d[6] = sk_linear12_to_srgb[avg[6]]; + d[7] = avg[7] >> 4; + + p0 += 16; + p1 += 16; + p2 += 16; + d += 8; + count -= 2; + } + + if (count) { + downsample_2_3(d, p0, srcRB, count); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { if (levelCount < 0) { return 0; @@ -306,7 +482,7 @@ size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { return sk_64_asS32(size); } -SkMipMap* SkMipMap::Build(const SkPixmap& src, SkSourceGammaTreatment treatment, +SkMipMap* SkMipMap::Build(const SkPixmap& src, SkDestinationSurfaceColorMode colorMode, SkDiscardableFactoryProc fact) { typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count); @@ -321,7 +497,7 @@ SkMipMap* SkMipMap::Build(const SkPixmap& src, SkSourceGammaTreatment treatment, const SkColorType ct = src.colorType(); const SkAlphaType at = src.alphaType(); - const bool srgbGamma = (SkSourceGammaTreatment::kRespect == treatment) + const bool srgbGamma = (SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware == colorMode) && src.info().gammaCloseToSRGB(); switch (ct) { @@ -331,8 +507,8 @@ SkMipMap* SkMipMap::Build(const SkPixmap& src, SkSourceGammaTreatment treatment, proc_1_2 = downsample_1_2; proc_1_3 = downsample_1_3; proc_2_1 = downsample_2_1; - proc_2_2 = downsample_2_2; - proc_2_3 = downsample_2_3; + proc_2_2 = downsample_2_2_srgb; + proc_2_3 = downsample_2_3_srgb; proc_3_1 = downsample_3_1; proc_3_2 = downsample_3_2; proc_3_3 = downsample_3_3; @@ -601,7 +777,7 @@ bool SkMipMap::extractLevel(const SkSize& scaleSize, Level* levelPtr) const { // Helper which extracts a pixmap from the src bitmap // -SkMipMap* SkMipMap::Build(const SkBitmap& src, SkSourceGammaTreatment treatment, +SkMipMap* SkMipMap::Build(const SkBitmap& src, SkDestinationSurfaceColorMode colorMode, SkDiscardableFactoryProc fact) { SkAutoPixmapUnlock srcUnlocker; if (!src.requestLock(&srcUnlocker)) { @@ -612,7 +788,7 @@ SkMipMap* SkMipMap::Build(const SkBitmap& src, SkSourceGammaTreatment treatment, if (nullptr == srcPixmap.addr()) { sk_throw(); } - return Build(srcPixmap, treatment, fact); + return Build(srcPixmap, colorMode, fact); } int SkMipMap::countLevels() const { diff --git a/gfx/skia/skia/src/core/SkMipMap.h b/gfx/skia/skia/src/core/SkMipMap.h index 0f31a9f703d4..f3425cbeaa56 100644 --- a/gfx/skia/skia/src/core/SkMipMap.h +++ b/gfx/skia/skia/src/core/SkMipMap.h @@ -28,12 +28,15 @@ typedef SkDiscardableMemory* (*SkDiscardableFactoryProc)(size_t bytes); */ class SkMipMap : public SkCachedData { public: - static SkMipMap* Build(const SkPixmap& src, SkSourceGammaTreatment, SkDiscardableFactoryProc); - static SkMipMap* Build(const SkBitmap& src, SkSourceGammaTreatment, SkDiscardableFactoryProc); + static SkMipMap* Build(const SkPixmap& src, SkDestinationSurfaceColorMode, + SkDiscardableFactoryProc); + static SkMipMap* Build(const SkBitmap& src, SkDestinationSurfaceColorMode, + SkDiscardableFactoryProc); - static SkSourceGammaTreatment DeduceTreatment(const SkShader::ContextRec& rec) { - return (SkShader::ContextRec::kPMColor_DstType == rec.fPreferredDstType) ? - SkSourceGammaTreatment::kIgnore : SkSourceGammaTreatment::kRespect; + static SkDestinationSurfaceColorMode DeduceColorMode(const SkShader::ContextRec& rec) { + return (SkShader::ContextRec::kPMColor_DstType == rec.fPreferredDstType) + ? SkDestinationSurfaceColorMode::kLegacy + : SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware; } // Determines how many levels a SkMipMap will have without creating that mipmap. diff --git a/gfx/skia/skia/src/core/SkModeColorFilter.cpp b/gfx/skia/skia/src/core/SkModeColorFilter.cpp index ba3b50d763b1..d074482a6fe9 100644 --- a/gfx/skia/skia/src/core/SkModeColorFilter.cpp +++ b/gfx/skia/skia/src/core/SkModeColorFilter.cpp @@ -6,12 +6,17 @@ */ #include "SkBlitRow.h" +#include "SkBlendModePriv.h" #include "SkColorFilter.h" #include "SkColorPriv.h" +#include "SkArenaAlloc.h" #include "SkModeColorFilter.h" +#include "SkPM4fPriv.h" +#include "SkRasterPipeline.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkUtils.h" +#include "SkRandom.h" #include "SkString.h" #include "SkValidationUtils.h" #include "SkPM4f.h" @@ -27,7 +32,7 @@ void SkModeColorFilter::toString(SkString* str) const { } #endif -bool SkModeColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) const { +bool SkModeColorFilter::asColorMode(SkColor* color, SkBlendMode* mode) const { if (color) { *color = fColor; } @@ -40,8 +45,8 @@ bool SkModeColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) cons uint32_t SkModeColorFilter::getFlags() const { uint32_t flags = 0; switch (fMode) { - case SkXfermode::kDst_Mode: //!< [Da, Dc] - case SkXfermode::kSrcATop_Mode: //!< [Da, Sc * Da + (1 - Sa) * Dc] + case SkBlendMode::kDst: //!< [Da, Dc] + case SkBlendMode::kSrcATop: //!< [Da, Sc * Da + (1 - Sa) * Dc] flags |= kAlphaUnchanged_Flag; default: break; @@ -59,17 +64,16 @@ void SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColo } void SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const { - SkPM4f color = SkPM4f::FromPMColor(fPMColor); SkXfermodeProc4f proc = SkXfermode::GetProc4f(fMode); - + auto pm4f = SkColor4f::FromColor(fColor).premul(); for (int i = 0; i < count; i++) { - result[i] = proc(color, shader[i]); + result[i] = proc(pm4f, shader[i]); } } void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const { buffer.writeColor(fColor); - buffer.writeUInt(fMode); + buffer.writeUInt((int)fMode); } void SkModeColorFilter::updateCache() { @@ -79,25 +83,41 @@ void SkModeColorFilter::updateCache() { sk_sp SkModeColorFilter::CreateProc(SkReadBuffer& buffer) { SkColor color = buffer.readColor(); - SkXfermode::Mode mode = (SkXfermode::Mode)buffer.readUInt(); + SkBlendMode mode = (SkBlendMode)buffer.readUInt(); return SkColorFilter::MakeModeFilter(color, mode); } +bool SkModeColorFilter::onAppendStages(SkRasterPipeline* p, + SkColorSpace* dst, + SkArenaAlloc* scratch, + bool shaderIsOpaque) const { + auto color = scratch->make(SkPM4f_from_SkColor(fColor, dst)); + + p->append(SkRasterPipeline::move_src_dst); + p->append(SkRasterPipeline::constant_color, color); + auto mode = (SkBlendMode)fMode; + if (!SkBlendMode_AppendStages(mode, p)) { + return false; + } + if (SkBlendMode_CanOverflow(mode)) { p->append(SkRasterPipeline::clamp_a); } + return true; +} + /////////////////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU #include "GrBlend.h" -#include "GrInvariantOutput.h" #include "effects/GrXfermodeFragmentProcessor.h" #include "effects/GrConstColorProcessor.h" #include "SkGr.h" -sk_sp SkModeColorFilter::asFragmentProcessor(GrContext*) const { - if (SkXfermode::kDst_Mode == fMode) { +sk_sp SkModeColorFilter::asFragmentProcessor( + GrContext*, SkColorSpace* dstColorSpace) const { + if (SkBlendMode::kDst == fMode) { return nullptr; } sk_sp constFP( - GrConstColorProcessor::Make(SkColorToPremulGrColor(fColor), + GrConstColorProcessor::Make(SkColorToPremulGrColor4f(fColor, dstColorSpace), GrConstColorProcessor::kIgnore_InputMode)); sk_sp fp( GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(constFP), fMode)); @@ -107,12 +127,8 @@ sk_sp SkModeColorFilter::asFragmentProcessor(GrContext*) co #ifdef SK_DEBUG // With a solid color input this should always be able to compute the blended color // (at least for coeff modes) - if (fMode <= SkXfermode::kLastCoeffMode) { - static SkRandom gRand; - GrInvariantOutput io(GrPremulColor(gRand.nextU()), kRGBA_GrColorComponentFlags, - false); - fp->computeInvariantOutput(&io); - SkASSERT(io.validFlags() == kRGBA_GrColorComponentFlags); + if ((unsigned)fMode <= (unsigned)SkBlendMode::kLastCoeffMode) { + SkASSERT(fp->hasConstantOutputForConstantInput()); } #endif return fp; @@ -124,7 +140,7 @@ sk_sp SkModeColorFilter::asFragmentProcessor(GrContext*) co class Src_SkModeColorFilter final : public SkModeColorFilter { public: - Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrc_Mode) {} + Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkBlendMode::kSrc) {} void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override { sk_memset32(result, this->getPMColor(), count); @@ -136,7 +152,7 @@ private: class SrcOver_SkModeColorFilter final : public SkModeColorFilter { public: - SrcOver_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrcOver_Mode) { } + SrcOver_SkModeColorFilter(SkColor color) : INHERITED(color, SkBlendMode::kSrcOver) { } void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override { SkBlitRow::Color32(result, shader, count, this->getPMColor()); @@ -148,7 +164,7 @@ private: /////////////////////////////////////////////////////////////////////////////// -sk_sp SkColorFilter::MakeModeFilter(SkColor color, SkXfermode::Mode mode) { +sk_sp SkColorFilter::MakeModeFilter(SkColor color, SkBlendMode mode) { if (!SkIsValidMode(mode)) { return nullptr; } @@ -157,34 +173,34 @@ sk_sp SkColorFilter::MakeModeFilter(SkColor color, SkXfermode::Mo // first collaps some modes if possible - if (SkXfermode::kClear_Mode == mode) { + if (SkBlendMode::kClear == mode) { color = 0; - mode = SkXfermode::kSrc_Mode; - } else if (SkXfermode::kSrcOver_Mode == mode) { + mode = SkBlendMode::kSrc; + } else if (SkBlendMode::kSrcOver == mode) { if (0 == alpha) { - mode = SkXfermode::kDst_Mode; + mode = SkBlendMode::kDst; } else if (255 == alpha) { - mode = SkXfermode::kSrc_Mode; + mode = SkBlendMode::kSrc; } // else just stay srcover } // weed out combinations that are noops, and just return null - if (SkXfermode::kDst_Mode == mode || - (0 == alpha && (SkXfermode::kSrcOver_Mode == mode || - SkXfermode::kDstOver_Mode == mode || - SkXfermode::kDstOut_Mode == mode || - SkXfermode::kSrcATop_Mode == mode || - SkXfermode::kXor_Mode == mode || - SkXfermode::kDarken_Mode == mode)) || - (0xFF == alpha && SkXfermode::kDstIn_Mode == mode)) { + if (SkBlendMode::kDst == mode || + (0 == alpha && (SkBlendMode::kSrcOver == mode || + SkBlendMode::kDstOver == mode || + SkBlendMode::kDstOut == mode || + SkBlendMode::kSrcATop == mode || + SkBlendMode::kXor == mode || + SkBlendMode::kDarken == mode)) || + (0xFF == alpha && SkBlendMode::kDstIn == mode)) { return nullptr; } switch (mode) { - case SkXfermode::kSrc_Mode: + case SkBlendMode::kSrc: return sk_make_sp(color); - case SkXfermode::kSrcOver_Mode: + case SkBlendMode::kSrcOver: return sk_make_sp(color); default: return SkModeColorFilter::Make(color, mode); diff --git a/gfx/skia/skia/src/core/SkModeColorFilter.h b/gfx/skia/skia/src/core/SkModeColorFilter.h index 7d4d4cc3ef8d..4d0b17293095 100644 --- a/gfx/skia/skia/src/core/SkModeColorFilter.h +++ b/gfx/skia/skia/src/core/SkModeColorFilter.h @@ -6,27 +6,22 @@ */ #include "SkColorFilter.h" -#include "SkXfermode.h" +#include "SkPM4f.h" #ifndef SkModeColorFilter_DEFINED #define SkModeColorFilter_DEFINED class SkModeColorFilter : public SkColorFilter { public: - static sk_sp Make(SkColor color, SkXfermode::Mode mode) { + static sk_sp Make(SkColor color, SkBlendMode mode) { return sk_sp(new SkModeColorFilter(color, mode)); } -#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR - static SkColorFilter* Create(SkColor color, SkXfermode::Mode mode) { - return Make(color, mode).release(); - } -#endif SkColor getColor() const { return fColor; } - SkXfermode::Mode getMode() const { return fMode; } + SkBlendMode getMode() const { return fMode; } SkPMColor getPMColor() const { return fPMColor; } - bool asColorMode(SkColor*, SkXfermode::Mode*) const override; + bool asColorMode(SkColor*, SkBlendMode*) const override; uint32_t getFlags() const override; void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override; void filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const override; @@ -36,12 +31,12 @@ public: #endif #if SK_SUPPORT_GPU - sk_sp asFragmentProcessor(GrContext*) const override; + sk_sp asFragmentProcessor(GrContext*, SkColorSpace*) const override; #endif SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkModeColorFilter) protected: - SkModeColorFilter(SkColor color, SkXfermode::Mode mode) { + SkModeColorFilter(SkColor color, SkBlendMode mode) { fColor = color; fMode = mode; this->updateCache(); @@ -49,9 +44,12 @@ protected: void flatten(SkWriteBuffer&) const override; + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + bool shaderIsOpaque) const override; + private: SkColor fColor; - SkXfermode::Mode fMode; + SkBlendMode fMode; // cache SkPMColor fPMColor; SkXfermodeProc fProc; diff --git a/gfx/skia/skia/src/core/SkMultiPictureDraw.cpp b/gfx/skia/skia/src/core/SkMultiPictureDraw.cpp index b3c6368767cd..1df27ff4cca7 100644 --- a/gfx/skia/skia/src/core/SkMultiPictureDraw.cpp +++ b/gfx/skia/skia/src/core/SkMultiPictureDraw.cpp @@ -18,7 +18,7 @@ void SkMultiPictureDraw::DrawData::draw() { void SkMultiPictureDraw::DrawData::init(SkCanvas* canvas, const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { fPicture = SkRef(picture); - fCanvas = SkRef(canvas); + fCanvas = canvas; if (matrix) { fMatrix = *matrix; } else { @@ -34,7 +34,6 @@ void SkMultiPictureDraw::DrawData::init(SkCanvas* canvas, const SkPicture* pictu void SkMultiPictureDraw::DrawData::Reset(SkTDArray& data) { for (int i = 0; i < data.count(); ++i) { data[i].fPicture->unref(); - data[i].fCanvas->unref(); delete data[i].fPaint; } data.rewind(); diff --git a/gfx/skia/skia/src/core/SkNormalBevelSource.cpp b/gfx/skia/skia/src/core/SkNormalBevelSource.cpp index 4a08728a9819..05bb5f61634e 100644 --- a/gfx/skia/skia/src/core/SkNormalBevelSource.cpp +++ b/gfx/skia/skia/src/core/SkNormalBevelSource.cpp @@ -7,6 +7,7 @@ #include "SkNormalBevelSource.h" +#include "SkArenaAlloc.h" #include "SkNormalSource.h" #include "SkNormalSourcePriv.h" #include "SkPoint3.h" @@ -14,7 +15,6 @@ #include "SkWriteBuffer.h" #if SK_SUPPORT_GPU -#include "GrInvariantOutput.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "SkGr.h" @@ -30,12 +30,13 @@ class NormalBevelFP : public GrFragmentProcessor { public: NormalBevelFP(SkNormalSource::BevelType bevelType, SkScalar bevelWidth, SkScalar bevelHeight) - : fBevelType(bevelType) - , fBevelWidth(bevelWidth) - , fBevelHeight(bevelHeight) { + : INHERITED(kNone_OptimizationFlags) + , fBevelType(bevelType) + , fBevelWidth(bevelWidth) + , fBevelHeight(bevelHeight) { this->initClassID(); - fUsesDistanceVectorField = true; + this->setWillUseDistanceVectorField(); } class GLSLNormalBevelFP : public GLSLNormalFP { @@ -104,15 +105,14 @@ public: fragBuilder->codeAppendf("%s = vec4(normal, 0.0);", args.fOutputColor); } - static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { + static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const NormalBevelFP& fp = proc.cast(); b->add32(static_cast(fp.fBevelType)); } protected: void setNormalData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) override { + const GrFragmentProcessor& proc) override { const NormalBevelFP& normalBevelFP = proc.cast(); // Updating uniform if bevel type requires it and data has changed @@ -217,16 +217,12 @@ public: GrGLSLProgramDataManager::UniformHandle fNormalizedHeightUni; }; - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLNormalBevelFP::GenKey(*this, caps, b); } const char* name() const override { return "NormalBevelFP"; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput); - } - private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalBevelFP; } @@ -240,6 +236,8 @@ private: SkNormalSource::BevelType fBevelType; SkScalar fBevelWidth; SkScalar fBevelHeight; + + typedef GrFragmentProcessor INHERITED; }; sk_sp SkNormalBevelSourceImpl::asFragmentProcessor( @@ -261,12 +259,8 @@ SkNormalBevelSourceImpl::Provider::Provider() {} SkNormalBevelSourceImpl::Provider::~Provider() {} SkNormalSource::Provider* SkNormalBevelSourceImpl::asProvider(const SkShader::ContextRec &rec, - void *storage) const { - return new (storage) Provider(); -} - -size_t SkNormalBevelSourceImpl::providerSize(const SkShader::ContextRec&) const { - return sizeof(Provider); + SkArenaAlloc* alloc) const { + return alloc->make(); } // TODO Implement feature for the CPU pipeline diff --git a/gfx/skia/skia/src/core/SkNormalBevelSource.h b/gfx/skia/skia/src/core/SkNormalBevelSource.h index d133738bcee2..2fefacda8eb3 100644 --- a/gfx/skia/skia/src/core/SkNormalBevelSource.h +++ b/gfx/skia/skia/src/core/SkNormalBevelSource.h @@ -22,8 +22,7 @@ public: #endif SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec, - void* storage) const override; - size_t providerSize(const SkShader::ContextRec& rec) const override; + SkArenaAlloc*) const override; SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkNormalBevelSourceImpl) @@ -35,7 +34,7 @@ private: public: Provider(); - virtual ~Provider(); + ~Provider() override; void fillScanLine(int x, int y, SkPoint3 output[], int count) const override; diff --git a/gfx/skia/skia/src/core/SkNormalFlatSource.cpp b/gfx/skia/skia/src/core/SkNormalFlatSource.cpp index c30cca14d10e..2547f4bda4df 100644 --- a/gfx/skia/skia/src/core/SkNormalFlatSource.cpp +++ b/gfx/skia/skia/src/core/SkNormalFlatSource.cpp @@ -7,6 +7,7 @@ #include "SkNormalFlatSource.h" +#include "SkArenaAlloc.h" #include "SkNormalSource.h" #include "SkNormalSourcePriv.h" #include "SkPoint3.h" @@ -14,13 +15,12 @@ #include "SkWriteBuffer.h" #if SK_SUPPORT_GPU -#include "GrInvariantOutput.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" class NormalFlatFP : public GrFragmentProcessor { public: - NormalFlatFP() { + NormalFlatFP() : INHERITED(kConstantOutputForConstantInput_OptimizationFlag) { this->initClassID(); } @@ -34,30 +34,29 @@ public: fragBuilder->codeAppendf("%s = vec4(0, 0, 1, 0);", args.fOutputColor); } - static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { + static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) { b->add32(0x0); } protected: - void setNormalData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) override {} + void setNormalData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override {} }; - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { - GLSLNormalFlatFP::GenKey(*this, caps, b); - } - const char* name() const override { return "NormalFlatFP"; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput); +private: + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { + GLSLNormalFlatFP::GenKey(*this, caps, b); } -private: + GrColor4f constantOutputForConstantInput(GrColor4f) const override { + return GrColor4f(0, 0, 1, 0); + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalFlatFP; } bool onIsEqual(const GrFragmentProcessor&) const override { return true; } + + typedef GrFragmentProcessor INHERITED; }; sk_sp SkNormalFlatSourceImpl::asFragmentProcessor( @@ -75,12 +74,8 @@ SkNormalFlatSourceImpl::Provider::Provider() {} SkNormalFlatSourceImpl::Provider::~Provider() {} SkNormalSource::Provider* SkNormalFlatSourceImpl::asProvider(const SkShader::ContextRec &rec, - void *storage) const { - return new (storage) Provider(); -} - -size_t SkNormalFlatSourceImpl::providerSize(const SkShader::ContextRec&) const { - return sizeof(Provider); + SkArenaAlloc *alloc) const { + return alloc->make(); } void SkNormalFlatSourceImpl::Provider::fillScanLine(int x, int y, SkPoint3 output[], diff --git a/gfx/skia/skia/src/core/SkNormalFlatSource.h b/gfx/skia/skia/src/core/SkNormalFlatSource.h index e1295596b93d..82b56f1a8ba0 100644 --- a/gfx/skia/skia/src/core/SkNormalFlatSource.h +++ b/gfx/skia/skia/src/core/SkNormalFlatSource.h @@ -19,8 +19,7 @@ public: #endif SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec, - void* storage) const override; - size_t providerSize(const SkShader::ContextRec& rec) const override; + SkArenaAlloc* alloc) const override; SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkNormalFlatSourceImpl) @@ -32,7 +31,7 @@ private: public: Provider(); - virtual ~Provider(); + ~Provider() override; void fillScanLine(int x, int y, SkPoint3 output[], int count) const override; diff --git a/gfx/skia/skia/src/core/SkNormalMapSource.cpp b/gfx/skia/skia/src/core/SkNormalMapSource.cpp index 25c533cdbfa5..65c5c892686c 100644 --- a/gfx/skia/skia/src/core/SkNormalMapSource.cpp +++ b/gfx/skia/skia/src/core/SkNormalMapSource.cpp @@ -7,6 +7,7 @@ #include "SkNormalMapSource.h" +#include "SkArenaAlloc.h" #include "SkLightingShader.h" #include "SkMatrix.h" #include "SkNormalSource.h" @@ -17,8 +18,7 @@ #if SK_SUPPORT_GPU #include "GrCoordTransform.h" -#include "GrInvariantOutput.h" -#include "GrTextureParams.h" +#include "GrSamplerParams.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "SkGr.h" @@ -26,7 +26,7 @@ class NormalMapFP : public GrFragmentProcessor { public: NormalMapFP(sk_sp mapFP, const SkMatrix& invCTM) - : fInvCTM(invCTM) { + : INHERITED(kNone_OptimizationFlags), fInvCTM(invCTM) { this->registerChildProcessor(mapFP); this->initClassID(); @@ -73,13 +73,13 @@ public: fragBuilder->codeAppend( "}"); } - static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b) { b->add32(0x0); } protected: void setNormalData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) override { + const GrFragmentProcessor& proc) override { const NormalMapFP& normalMapFP = proc.cast(); const SkMatrix& invCTM = normalMapFP.invCTM(); @@ -96,16 +96,12 @@ public: GrGLSLProgramDataManager::UniformHandle fXformUni; }; - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLNormalMapFP::GenKey(*this, caps, b); } const char* name() const override { return "NormalMapFP"; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput); - } - const SkMatrix& invCTM() const { return fInvCTM; } private: @@ -117,6 +113,8 @@ private: } SkMatrix fInvCTM; + + typedef GrFragmentProcessor INHERITED; }; sk_sp SkNormalMapSourceImpl::asFragmentProcessor( @@ -134,55 +132,39 @@ sk_sp SkNormalMapSourceImpl::asFragmentProcessor( //////////////////////////////////////////////////////////////////////////// SkNormalMapSourceImpl::Provider::Provider(const SkNormalMapSourceImpl& source, - SkShader::Context* mapContext, - SkPaint* overridePaint) + SkShader::Context* mapContext) : fSource(source) - , fMapContext(mapContext) - , fOverridePaint(overridePaint) {} - -SkNormalMapSourceImpl::Provider::~Provider() { - fMapContext->~Context(); - fOverridePaint->~SkPaint(); -} + , fMapContext(mapContext) {} SkNormalSource::Provider* SkNormalMapSourceImpl::asProvider(const SkShader::ContextRec &rec, - void *storage) const { + SkArenaAlloc* alloc) const { SkMatrix normTotalInv; if (!this->computeNormTotalInverse(rec, &normTotalInv)) { return nullptr; } // Overriding paint's alpha because we need the normal map's RGB channels to be unpremul'd - void* paintStorage = (char*)storage + sizeof(Provider); - SkPaint* overridePaint = new (paintStorage) SkPaint(*(rec.fPaint)); - overridePaint->setAlpha(0xFF); - SkShader::ContextRec overrideRec(*overridePaint, *(rec.fMatrix), rec.fLocalMatrix, - rec.fPreferredDstType); + SkPaint overridePaint {*(rec.fPaint)}; + overridePaint.setAlpha(0xFF); + SkShader::ContextRec overrideRec(overridePaint, *(rec.fMatrix), rec.fLocalMatrix, + rec.fPreferredDstType, rec.fDstColorSpace); - void* mapContextStorage = (char*) paintStorage + sizeof(SkPaint); - SkShader::Context* context = fMapShader->createContext(overrideRec, mapContextStorage); + SkShader::Context* context = fMapShader->makeContext(overrideRec, alloc); if (!context) { return nullptr; } - return new (storage) Provider(*this, context, overridePaint); -} - -size_t SkNormalMapSourceImpl::providerSize(const SkShader::ContextRec& rec) const { - return sizeof(Provider) + sizeof(SkPaint) + fMapShader->contextSize(rec); + return alloc->make(*this, context); } bool SkNormalMapSourceImpl::computeNormTotalInverse(const SkShader::ContextRec& rec, SkMatrix* normTotalInverse) const { - SkMatrix total; - total.setConcat(*rec.fMatrix, fMapShader->getLocalMatrix()); - - const SkMatrix* m = &total; + SkMatrix total = SkMatrix::Concat(*rec.fMatrix, fMapShader->getLocalMatrix()); if (rec.fLocalMatrix) { - total.setConcat(*m, *rec.fLocalMatrix); - m = &total; + total.preConcat(*rec.fLocalMatrix); } - return m->invert(normTotalInverse); + + return total.invert(normTotalInverse); } #define BUFFER_MAX 16 diff --git a/gfx/skia/skia/src/core/SkNormalMapSource.h b/gfx/skia/skia/src/core/SkNormalMapSource.h index 5908369fc7d8..f2b07f21e9e6 100644 --- a/gfx/skia/skia/src/core/SkNormalMapSource.h +++ b/gfx/skia/skia/src/core/SkNormalMapSource.h @@ -21,8 +21,7 @@ public: #endif SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec, - void* storage) const override; - size_t providerSize(const SkShader::ContextRec& rec) const override; + SkArenaAlloc* alloc) const override; SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkNormalMapSourceImpl) @@ -34,10 +33,7 @@ protected: private: class Provider : public SkNormalSource::Provider { public: - Provider(const SkNormalMapSourceImpl& source, SkShader::Context* mapContext, - SkPaint* overridePaint); - - virtual ~Provider() override; + Provider(const SkNormalMapSourceImpl& source, SkShader::Context* mapContext); void fillScanLine(int x, int y, SkPoint3 output[], int count) const override; @@ -45,8 +41,6 @@ private: const SkNormalMapSourceImpl& fSource; SkShader::Context* fMapContext; - SkPaint* fOverridePaint; - typedef SkNormalSource::Provider INHERITED; }; diff --git a/gfx/skia/skia/src/core/SkNormalSource.h b/gfx/skia/skia/src/core/SkNormalSource.h index 32ef08ce5230..221c09db9996 100644 --- a/gfx/skia/skia/src/core/SkNormalSource.h +++ b/gfx/skia/skia/src/core/SkNormalSource.h @@ -44,11 +44,7 @@ public: /** Returns an instance of 'Provider' that provides normals for the CPU pipeline. The necessary data will be initialized in place at 'storage'. */ - virtual Provider* asProvider(const SkShader::ContextRec&, void* storage) const = 0; - - /** Amount of memory needed to store a provider object and its dependencies. - */ - virtual size_t providerSize(const SkShader::ContextRec&) const = 0; + virtual Provider* asProvider(const SkShader::ContextRec&, SkArenaAlloc*) const = 0; /** Returns a normal source that provides normals sourced from the the normal map argument. diff --git a/gfx/skia/skia/src/core/SkNormalSourcePriv.h b/gfx/skia/skia/src/core/SkNormalSourcePriv.h index ce8baf61e4de..d508bed84137 100644 --- a/gfx/skia/skia/src/core/SkNormalSourcePriv.h +++ b/gfx/skia/skia/src/core/SkNormalSourcePriv.h @@ -39,7 +39,8 @@ public: } } - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) final override { + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) final override { if (!fDidIntercept) { this->setNormalData(pdman, proc); } @@ -47,7 +48,7 @@ public: protected: virtual void onEmitCode(EmitArgs& args) = 0; - virtual void setNormalData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) = 0; + virtual void setNormalData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) = 0; private: bool fDidIntercept; diff --git a/gfx/skia/skia/src/core/SkNx.h b/gfx/skia/skia/src/core/SkNx.h index 6bca856d8b11..5df575342c9d 100644 --- a/gfx/skia/skia/src/core/SkNx.h +++ b/gfx/skia/skia/src/core/SkNx.h @@ -8,15 +8,16 @@ #ifndef SkNx_DEFINED #define SkNx_DEFINED -//#define SKNX_NO_SIMD - +#include "SkSafe_math.h" #include "SkScalar.h" #include "SkTypes.h" #include -#include #include -#define SI static inline +// Every single SkNx method wants to be fully inlined. (We know better than MSVC). +#define AI SK_ALWAYS_INLINE + +namespace { // The default SkNx just proxies down to a pair of SkNx. template @@ -25,79 +26,107 @@ struct SkNx { Half fLo, fHi; - SkNx() = default; - SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {} + AI SkNx() = default; + AI SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {} - SkNx(T v) : fLo(v), fHi(v) {} + AI SkNx(T v) : fLo(v), fHi(v) {} - SkNx(T a, T b) : fLo(a) , fHi(b) { static_assert(N==2, ""); } - SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) { static_assert(N==4, ""); } - SkNx(T a, T b, T c, T d, T e, T f, T g, T h) : fLo(a,b,c,d), fHi(e,f,g,h) { + AI SkNx(T a, T b) : fLo(a) , fHi(b) { static_assert(N==2, ""); } + AI SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) { static_assert(N==4, ""); } + AI SkNx(T a, T b, T c, T d, T e, T f, T g, T h) : fLo(a,b,c,d), fHi(e,f,g,h) { static_assert(N==8, ""); } - SkNx(T a, T b, T c, T d, T e, T f, T g, T h, - T i, T j, T k, T l, T m, T n, T o, T p) : fLo(a,b,c,d, e,f,g,h), fHi(i,j,k,l, m,n,o,p) { + AI SkNx(T a, T b, T c, T d, T e, T f, T g, T h, + T i, T j, T k, T l, T m, T n, T o, T p) + : fLo(a,b,c,d, e,f,g,h), fHi(i,j,k,l, m,n,o,p) { static_assert(N==16, ""); } - T operator[](int k) const { + AI T operator[](int k) const { SkASSERT(0 <= k && k < N); return k < N/2 ? fLo[k] : fHi[k-N/2]; } - static SkNx Load(const void* vptr) { + AI static SkNx Load(const void* vptr) { auto ptr = (const char*)vptr; return { Half::Load(ptr), Half::Load(ptr + N/2*sizeof(T)) }; } - void store(void* vptr) const { + AI void store(void* vptr) const { auto ptr = (char*)vptr; fLo.store(ptr); fHi.store(ptr + N/2*sizeof(T)); } - bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } - bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } + AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) { + auto ptr = (const char*)vptr; + Half al, bl, cl, dl, + ah, bh, ch, dh; + Half::Load4(ptr , &al, &bl, &cl, &dl); + Half::Load4(ptr + 4*N/2*sizeof(T), &ah, &bh, &ch, &dh); + *a = SkNx{al, ah}; + *b = SkNx{bl, bh}; + *c = SkNx{cl, ch}; + *d = SkNx{dl, dh}; + } + AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) { + auto ptr = (const char*)vptr; + Half al, bl, cl, + ah, bh, ch; + Half::Load3(ptr , &al, &bl, &cl); + Half::Load3(ptr + 3*N/2*sizeof(T), &ah, &bh, &ch); + *a = SkNx{al, ah}; + *b = SkNx{bl, bh}; + *c = SkNx{cl, ch}; + } + AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { + auto ptr = (char*)vptr; + Half::Store4(ptr, a.fLo, b.fLo, c.fLo, d.fLo); + Half::Store4(ptr + 4*N/2*sizeof(T), a.fHi, b.fHi, c.fHi, d.fHi); + } - SkNx abs() const { return { fLo. abs(), fHi. abs() }; } - SkNx sqrt() const { return { fLo. sqrt(), fHi. sqrt() }; } - SkNx rsqrt() const { return { fLo. rsqrt(), fHi. rsqrt() }; } - SkNx floor() const { return { fLo. floor(), fHi. floor() }; } - SkNx invert() const { return { fLo.invert(), fHi.invert() }; } + AI bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } + AI bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } - SkNx operator!() const { return { !fLo, !fHi }; } - SkNx operator-() const { return { -fLo, -fHi }; } - SkNx operator~() const { return { ~fLo, ~fHi }; } + AI SkNx abs() const { return { fLo. abs(), fHi. abs() }; } + AI SkNx sqrt() const { return { fLo. sqrt(), fHi. sqrt() }; } + AI SkNx rsqrt() const { return { fLo. rsqrt(), fHi. rsqrt() }; } + AI SkNx floor() const { return { fLo. floor(), fHi. floor() }; } + AI SkNx invert() const { return { fLo.invert(), fHi.invert() }; } - SkNx operator<<(int bits) const { return { fLo << bits, fHi << bits }; } - SkNx operator>>(int bits) const { return { fLo >> bits, fHi >> bits }; } + AI SkNx operator!() const { return { !fLo, !fHi }; } + AI SkNx operator-() const { return { -fLo, -fHi }; } + AI SkNx operator~() const { return { ~fLo, ~fHi }; } - SkNx operator+(const SkNx& y) const { return { fLo + y.fLo, fHi + y.fHi }; } - SkNx operator-(const SkNx& y) const { return { fLo - y.fLo, fHi - y.fHi }; } - SkNx operator*(const SkNx& y) const { return { fLo * y.fLo, fHi * y.fHi }; } - SkNx operator/(const SkNx& y) const { return { fLo / y.fLo, fHi / y.fHi }; } + AI SkNx operator<<(int bits) const { return { fLo << bits, fHi << bits }; } + AI SkNx operator>>(int bits) const { return { fLo >> bits, fHi >> bits }; } - SkNx operator&(const SkNx& y) const { return { fLo & y.fLo, fHi & y.fHi }; } - SkNx operator|(const SkNx& y) const { return { fLo | y.fLo, fHi | y.fHi }; } - SkNx operator^(const SkNx& y) const { return { fLo ^ y.fLo, fHi ^ y.fHi }; } + AI SkNx operator+(const SkNx& y) const { return { fLo + y.fLo, fHi + y.fHi }; } + AI SkNx operator-(const SkNx& y) const { return { fLo - y.fLo, fHi - y.fHi }; } + AI SkNx operator*(const SkNx& y) const { return { fLo * y.fLo, fHi * y.fHi }; } + AI SkNx operator/(const SkNx& y) const { return { fLo / y.fLo, fHi / y.fHi }; } - SkNx operator==(const SkNx& y) const { return { fLo == y.fLo, fHi == y.fHi }; } - SkNx operator!=(const SkNx& y) const { return { fLo != y.fLo, fHi != y.fHi }; } - SkNx operator<=(const SkNx& y) const { return { fLo <= y.fLo, fHi <= y.fHi }; } - SkNx operator>=(const SkNx& y) const { return { fLo >= y.fLo, fHi >= y.fHi }; } - SkNx operator< (const SkNx& y) const { return { fLo < y.fLo, fHi < y.fHi }; } - SkNx operator> (const SkNx& y) const { return { fLo > y.fLo, fHi > y.fHi }; } + AI SkNx operator&(const SkNx& y) const { return { fLo & y.fLo, fHi & y.fHi }; } + AI SkNx operator|(const SkNx& y) const { return { fLo | y.fLo, fHi | y.fHi }; } + AI SkNx operator^(const SkNx& y) const { return { fLo ^ y.fLo, fHi ^ y.fHi }; } - SkNx saturatedAdd(const SkNx& y) const { + AI SkNx operator==(const SkNx& y) const { return { fLo == y.fLo, fHi == y.fHi }; } + AI SkNx operator!=(const SkNx& y) const { return { fLo != y.fLo, fHi != y.fHi }; } + AI SkNx operator<=(const SkNx& y) const { return { fLo <= y.fLo, fHi <= y.fHi }; } + AI SkNx operator>=(const SkNx& y) const { return { fLo >= y.fLo, fHi >= y.fHi }; } + AI SkNx operator< (const SkNx& y) const { return { fLo < y.fLo, fHi < y.fHi }; } + AI SkNx operator> (const SkNx& y) const { return { fLo > y.fLo, fHi > y.fHi }; } + + AI SkNx saturatedAdd(const SkNx& y) const { return { fLo.saturatedAdd(y.fLo), fHi.saturatedAdd(y.fHi) }; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return { fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi) }; } - static SkNx Min(const SkNx& x, const SkNx& y) { + AI static SkNx Min(const SkNx& x, const SkNx& y) { return { Half::Min(x.fLo, y.fLo), Half::Min(x.fHi, y.fHi) }; } - static SkNx Max(const SkNx& x, const SkNx& y) { + AI static SkNx Max(const SkNx& x, const SkNx& y) { return { Half::Max(x.fLo, y.fLo), Half::Max(x.fHi, y.fHi) }; } }; @@ -107,81 +136,104 @@ template struct SkNx<1,T> { T fVal; - SkNx() = default; - SkNx(T v) : fVal(v) {} + AI SkNx() = default; + AI SkNx(T v) : fVal(v) {} // Android complains against unused parameters, so we guard it - T operator[](int SkDEBUGCODE(k)) const { + AI T operator[](int SkDEBUGCODE(k)) const { SkASSERT(k == 0); return fVal; } - static SkNx Load(const void* ptr) { + AI static SkNx Load(const void* ptr) { SkNx v; memcpy(&v, ptr, sizeof(T)); return v; } - void store(void* ptr) const { memcpy(ptr, &fVal, sizeof(T)); } + AI void store(void* ptr) const { memcpy(ptr, &fVal, sizeof(T)); } - bool anyTrue() const { return fVal != 0; } - bool allTrue() const { return fVal != 0; } + AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) { + auto ptr = (const char*)vptr; + *a = Load(ptr + 0*sizeof(T)); + *b = Load(ptr + 1*sizeof(T)); + *c = Load(ptr + 2*sizeof(T)); + *d = Load(ptr + 3*sizeof(T)); + } + AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) { + auto ptr = (const char*)vptr; + *a = Load(ptr + 0*sizeof(T)); + *b = Load(ptr + 1*sizeof(T)); + *c = Load(ptr + 2*sizeof(T)); + } + AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { + auto ptr = (char*)vptr; + a.store(ptr + 0*sizeof(T)); + b.store(ptr + 1*sizeof(T)); + c.store(ptr + 2*sizeof(T)); + d.store(ptr + 3*sizeof(T)); + } - SkNx abs() const { return Abs(fVal); } - SkNx sqrt() const { return Sqrt(fVal); } - SkNx rsqrt() const { return T(1) / this->sqrt(); } - SkNx floor() const { return Floor(fVal); } - SkNx invert() const { return T(1) / *this; } + AI bool anyTrue() const { return fVal != 0; } + AI bool allTrue() const { return fVal != 0; } - SkNx operator!() const { return !fVal; } - SkNx operator-() const { return -fVal; } - SkNx operator~() const { return FromBits(~ToBits(fVal)); } + AI SkNx abs() const { return Abs(fVal); } + AI SkNx sqrt() const { return Sqrt(fVal); } + AI SkNx rsqrt() const { return T(1) / this->sqrt(); } + AI SkNx floor() const { return Floor(fVal); } + AI SkNx invert() const { return T(1) / *this; } - SkNx operator<<(int bits) const { return fVal << bits; } - SkNx operator>>(int bits) const { return fVal >> bits; } + AI SkNx operator!() const { return !fVal; } + AI SkNx operator-() const { return -fVal; } + AI SkNx operator~() const { return FromBits(~ToBits(fVal)); } - SkNx operator+(const SkNx& y) const { return fVal + y.fVal; } - SkNx operator-(const SkNx& y) const { return fVal - y.fVal; } - SkNx operator*(const SkNx& y) const { return fVal * y.fVal; } - SkNx operator/(const SkNx& y) const { return fVal / y.fVal; } + AI SkNx operator<<(int bits) const { return fVal << bits; } + AI SkNx operator>>(int bits) const { return fVal >> bits; } - SkNx operator&(const SkNx& y) const { return FromBits(ToBits(fVal) & ToBits(y.fVal)); } - SkNx operator|(const SkNx& y) const { return FromBits(ToBits(fVal) | ToBits(y.fVal)); } - SkNx operator^(const SkNx& y) const { return FromBits(ToBits(fVal) ^ ToBits(y.fVal)); } + AI SkNx operator+(const SkNx& y) const { return fVal + y.fVal; } + AI SkNx operator-(const SkNx& y) const { return fVal - y.fVal; } + AI SkNx operator*(const SkNx& y) const { return fVal * y.fVal; } + AI SkNx operator/(const SkNx& y) const { return fVal / y.fVal; } - SkNx operator==(const SkNx& y) const { return FromBits(fVal == y.fVal ? ~0 : 0); } - SkNx operator!=(const SkNx& y) const { return FromBits(fVal != y.fVal ? ~0 : 0); } - SkNx operator<=(const SkNx& y) const { return FromBits(fVal <= y.fVal ? ~0 : 0); } - SkNx operator>=(const SkNx& y) const { return FromBits(fVal >= y.fVal ? ~0 : 0); } - SkNx operator< (const SkNx& y) const { return FromBits(fVal < y.fVal ? ~0 : 0); } - SkNx operator> (const SkNx& y) const { return FromBits(fVal > y.fVal ? ~0 : 0); } + AI SkNx operator&(const SkNx& y) const { return FromBits(ToBits(fVal) & ToBits(y.fVal)); } + AI SkNx operator|(const SkNx& y) const { return FromBits(ToBits(fVal) | ToBits(y.fVal)); } + AI SkNx operator^(const SkNx& y) const { return FromBits(ToBits(fVal) ^ ToBits(y.fVal)); } - static SkNx Min(const SkNx& x, const SkNx& y) { return x.fVal < y.fVal ? x : y; } - static SkNx Max(const SkNx& x, const SkNx& y) { return x.fVal > y.fVal ? x : y; } + AI SkNx operator==(const SkNx& y) const { return FromBits(fVal == y.fVal ? ~0 : 0); } + AI SkNx operator!=(const SkNx& y) const { return FromBits(fVal != y.fVal ? ~0 : 0); } + AI SkNx operator<=(const SkNx& y) const { return FromBits(fVal <= y.fVal ? ~0 : 0); } + AI SkNx operator>=(const SkNx& y) const { return FromBits(fVal >= y.fVal ? ~0 : 0); } + AI SkNx operator< (const SkNx& y) const { return FromBits(fVal < y.fVal ? ~0 : 0); } + AI SkNx operator> (const SkNx& y) const { return FromBits(fVal > y.fVal ? ~0 : 0); } - SkNx saturatedAdd(const SkNx& y) const { + AI static SkNx Min(const SkNx& x, const SkNx& y) { return x.fVal < y.fVal ? x : y; } + AI static SkNx Max(const SkNx& x, const SkNx& y) { return x.fVal > y.fVal ? x : y; } + + AI SkNx saturatedAdd(const SkNx& y) const { static_assert(std::is_unsigned::value, ""); T sum = fVal + y.fVal; return sum < fVal ? std::numeric_limits::max() : sum; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e; } + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e; } private: // Helper functions to choose the right float/double methods. (In madness lies...) - static float Abs(float val) { return ::fabsf(val); } - static float Sqrt(float val) { return ::sqrtf(val); } - static float Floor(float val) { return ::floorf(val); } + AI static float Abs(float val) { return ::fabsf(val); } + AI static float Sqrt(float val) { return ::sqrtf(val); } + AI static float Floor(float val) { return ::floorf(val); } - static double Abs(double val) { return ::fabs(val); } - static double Sqrt(double val) { return ::sqrt(val); } - static double Floor(double val) { return ::floor(val); } + AI static double Abs(double val) { return ::fabs(val); } + AI static double Sqrt(double val) { return ::sqrt(val); } + AI static double Floor(double val) { return ::floor(val); } // Helper functions for working with floats/doubles as bit patterns. - template static U ToBits(U v) { return v; } - static int32_t ToBits(float v) { int32_t bits; memcpy(&bits, &v, sizeof(v)); return bits; } - static int64_t ToBits(double v) { int64_t bits; memcpy(&bits, &v, sizeof(v)); return bits; } + template + AI static U ToBits(U v) { return v; } + AI static int32_t ToBits(float v) { int32_t bits; memcpy(&bits, &v, sizeof(v)); return bits; } + AI static int64_t ToBits(double v) { int64_t bits; memcpy(&bits, &v, sizeof(v)); return bits; } - template static T FromBits(Bits bits) { + template + AI static T FromBits(Bits bits) { static_assert(std::is_pod::value && std::is_pod::value && sizeof(T) <= sizeof(Bits), ""); @@ -192,7 +244,7 @@ private: }; // Allow scalars on the left or right of binary operators, and things like +=, &=, etc. -#define V template SI SkNx +#define V template AI static SkNx V operator+ (T x, const SkNx& y) { return SkNx(x) + y; } V operator- (T x, const SkNx& y) { return SkNx(x) - y; } V operator* (T x, const SkNx& y) { return SkNx(x) * y; } @@ -243,14 +295,14 @@ private: // SkNx ~~> SkNx + SkNx template -SI void SkNx_split(const SkNx& v, SkNx* lo, SkNx* hi) { +AI static void SkNx_split(const SkNx& v, SkNx* lo, SkNx* hi) { *lo = v.fLo; *hi = v.fHi; } // SkNx + SkNx ~~> SkNx template -SI SkNx SkNx_join(const SkNx& lo, const SkNx& hi) { +AI static SkNx SkNx_join(const SkNx& lo, const SkNx& hi) { return { lo, hi }; } @@ -261,20 +313,27 @@ SI SkNx SkNx_join(const SkNx& lo, const SkNx& hi) { // SkNx_shuffle<2,1,2,1,2,1,2,1>(v) ~~> {B,G,B,G,B,G,B,G} // SkNx_shuffle<3,3,3,3>(v) ~~> {A,A,A,A} template -SI SkNx SkNx_shuffle(const SkNx& v) { +AI static SkNx SkNx_shuffle(const SkNx& v) { return { v[Ix]... }; } // Cast from SkNx to SkNx, as if you called static_cast(Src). template -SI SkNx SkNx_cast(const SkNx& v) { +AI static SkNx SkNx_cast(const SkNx& v) { return { SkNx_cast(v.fLo), SkNx_cast(v.fHi) }; } template -SI SkNx<1,Dst> SkNx_cast(const SkNx<1,Src>& v) { +AI static SkNx<1,Dst> SkNx_cast(const SkNx<1,Src>& v) { return static_cast(v.fVal); } +template +AI static SkNx SkNx_fma(const SkNx& f, const SkNx& m, const SkNx& a) { + return f*m+a; +} + +} // namespace + typedef SkNx<2, float> Sk2f; typedef SkNx<4, float> Sk4f; typedef SkNx<8, float> Sk8f; @@ -294,6 +353,7 @@ typedef SkNx<8, uint16_t> Sk8h; typedef SkNx<16, uint16_t> Sk16h; typedef SkNx<4, int32_t> Sk4i; +typedef SkNx<8, int32_t> Sk8i; typedef SkNx<4, uint32_t> Sk4u; // Include platform specific specializations if available. @@ -303,63 +363,20 @@ typedef SkNx<4, uint32_t> Sk4u; #include "../opts/SkNx_neon.h" #else -SI Sk4i Sk4f_round(const Sk4f& x) { +AI static Sk4i Sk4f_round(const Sk4f& x) { return { (int) lrintf (x[0]), (int) lrintf (x[1]), (int) lrintf (x[2]), (int) lrintf (x[3]), }; } -// Load 4 Sk4h and transpose them (256 bits total). -SI void Sk4h_load4(const void* vptr, Sk4h* r, Sk4h* g, Sk4h* b, Sk4h* a) { - const uint64_t* ptr = (const uint64_t*)vptr; - auto p0 = Sk4h::Load(ptr+0), - p1 = Sk4h::Load(ptr+1), - p2 = Sk4h::Load(ptr+2), - p3 = Sk4h::Load(ptr+3); - *r = { p0[0], p1[0], p2[0], p3[0] }; - *g = { p0[1], p1[1], p2[1], p3[1] }; - *b = { p0[2], p1[2], p2[2], p3[2] }; - *a = { p0[3], p1[3], p2[3], p3[3] }; -} - -// Transpose 4 Sk4h and store (256 bits total). -SI void Sk4h_store4(void* dst, const Sk4h& r, const Sk4h& g, const Sk4h& b, const Sk4h& a) { - uint64_t* dst64 = (uint64_t*) dst; - Sk4h(r[0], g[0], b[0], a[0]).store(dst64 + 0); - Sk4h(r[1], g[1], b[1], a[1]).store(dst64 + 1); - Sk4h(r[2], g[2], b[2], a[2]).store(dst64 + 2); - Sk4h(r[3], g[3], b[3], a[3]).store(dst64 + 3); -} - -// Load 4 Sk4f and transpose them (512 bits total). -SI void Sk4f_load4(const void* vptr, Sk4f* r, Sk4f* g, Sk4f* b, Sk4f* a) { - const float* ptr = (const float*) vptr; - auto p0 = Sk4f::Load(ptr + 0), - p1 = Sk4f::Load(ptr + 4), - p2 = Sk4f::Load(ptr + 8), - p3 = Sk4f::Load(ptr + 12); - *r = { p0[0], p1[0], p2[0], p3[0] }; - *g = { p0[1], p1[1], p2[1], p3[1] }; - *b = { p0[2], p1[2], p2[2], p3[2] }; - *a = { p0[3], p1[3], p2[3], p3[3] }; -} - -// Transpose 4 Sk4f and store (512 bits total). -SI void Sk4f_store4(void* vdst, const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a) { - float* dst = (float*) vdst; - Sk4f(r[0], g[0], b[0], a[0]).store(dst + 0); - Sk4f(r[1], g[1], b[1], a[1]).store(dst + 4); - Sk4f(r[2], g[2], b[2], a[2]).store(dst + 8); - Sk4f(r[3], g[3], b[3], a[3]).store(dst + 12); -} - #endif -SI void Sk4f_ToBytes(uint8_t p[16], const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) { +AI static void Sk4f_ToBytes(uint8_t p[16], + const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) { SkNx_cast(SkNx_join(SkNx_join(a,b), SkNx_join(c,d))).store(p); } -#undef SI +#undef AI #endif//SkNx_DEFINED diff --git a/gfx/skia/skia/include/core/SkOSFile.h b/gfx/skia/skia/src/core/SkOSFile.h similarity index 59% rename from gfx/skia/skia/include/core/SkOSFile.h rename to gfx/skia/skia/src/core/SkOSFile.h index f977327e2552..88ad958b1c90 100644 --- a/gfx/skia/skia/include/core/SkOSFile.h +++ b/gfx/skia/skia/src/core/SkOSFile.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -21,30 +20,16 @@ enum SkFILE_Flags { kWrite_SkFILE_Flag = 0x02 }; -#ifdef _WIN32 -const static char SkPATH_SEPARATOR = '\\'; -#else -const static char SkPATH_SEPARATOR = '/'; -#endif - FILE* sk_fopen(const char path[], SkFILE_Flags); void sk_fclose(FILE*); size_t sk_fgetsize(FILE*); -/** Return true if the file could seek back to the beginning -*/ -bool sk_frewind(FILE*); -size_t sk_fread(void* buffer, size_t byteCount, FILE*); size_t sk_fwrite(const void* buffer, size_t byteCount, FILE*); -char* sk_fgets(char* str, int size, FILE* f); - void sk_fflush(FILE*); void sk_fsync(FILE*); -bool sk_fseek(FILE*, size_t); -bool sk_fmove(FILE*, long); size_t sk_ftell(FILE*); /** Maps a file into memory. Returns the address and length on success, NULL otherwise. @@ -80,8 +65,9 @@ bool sk_exists(const char *path, SkFILE_Flags = (SkFILE_Flags)0); // Returns true if a directory exists at this path. bool sk_isdir(const char *path); -// Have we reached the end of the file? -int sk_feof(FILE *); +// Like pread, but may affect the file position marker. +// Returns the number of bytes read or SIZE_MAX if failed. +size_t sk_qread(FILE*, void* buffer, size_t count, size_t offset); // Create a new directory at this path; returns true if successful. @@ -110,40 +96,4 @@ public: }; }; -/** - * Functions for modifying SkStrings which represent paths on the filesystem. - */ -class SkOSPath { -public: - /** - * Assembles rootPath and relativePath into a single path, like this: - * rootPath/relativePath. - * It is okay to call with a NULL rootPath and/or relativePath. A path - * separator will still be inserted. - * - * Uses SkPATH_SEPARATOR, to work on all platforms. - */ - static SkString Join(const char* rootPath, const char* relativePath); - - /** - * Return the name of the file, ignoring the directory structure. - * Behaves like python's os.path.basename. If the fullPath is - * /dir/subdir/, an empty string is returned. - * @param fullPath Full path to the file. - * @return SkString The basename of the file - anything beyond the - * final slash, or the full name if there is no slash. - */ - static SkString Basename(const char* fullPath); - - /** - * Given a qualified file name returns the directory. - * Behaves like python's os.path.dirname. If the fullPath is - * /dir/subdir/ the return will be /dir/subdir/ - * @param fullPath Full path to the file. - * @return SkString The dir containing the file - anything preceding the - * final slash, or the full name if ending in a slash. - */ - static SkString Dirname(const char* fullPath); -}; - #endif diff --git a/gfx/skia/skia/src/core/SkOpts.cpp b/gfx/skia/skia/src/core/SkOpts.cpp index c9bb48b55739..273c6547549d 100644 --- a/gfx/skia/skia/src/core/SkOpts.cpp +++ b/gfx/skia/skia/src/core/SkOpts.cpp @@ -36,16 +36,15 @@ #define SK_OPTS_NS portable #endif +#include "SkBitmapFilter_opts.h" #include "SkBlend_opts.h" #include "SkBlitMask_opts.h" #include "SkBlitRow_opts.h" #include "SkBlurImageFilter_opts.h" #include "SkChecksum_opts.h" -#include "SkColorCubeFilter_opts.h" #include "SkMorphologyImageFilter_opts.h" #include "SkRasterPipeline_opts.h" #include "SkSwizzler_opts.h" -#include "SkTextureCompressor_opts.h" #include "SkXfermode_opts.h" namespace SkOpts { @@ -55,7 +54,6 @@ namespace SkOpts { // They'll still get a chance to be replaced with even better ones, e.g. using SSE4.1. #define DEFINE_DEFAULT(name) decltype(name) name = SK_OPTS_NS::name DEFINE_DEFAULT(create_xfermode); - DEFINE_DEFAULT(color_cube_filter_span); DEFINE_DEFAULT(box_blur_xx); DEFINE_DEFAULT(box_blur_xy); @@ -66,9 +64,6 @@ namespace SkOpts { DEFINE_DEFAULT( erode_x); DEFINE_DEFAULT( erode_y); - DEFINE_DEFAULT(texture_compressor); - DEFINE_DEFAULT(fill_block_dimensions); - DEFINE_DEFAULT(blit_mask_d32_a8); DEFINE_DEFAULT(blit_row_color32); @@ -88,114 +83,22 @@ namespace SkOpts { DEFINE_DEFAULT(srcover_srgb_srgb); DEFINE_DEFAULT(hash_fn); + + DEFINE_DEFAULT(run_pipeline); + + DEFINE_DEFAULT(convolve_vertically); + DEFINE_DEFAULT(convolve_horizontally); + DEFINE_DEFAULT(convolve_4_rows_horizontally); + #undef DEFINE_DEFAULT - // TODO: might be nice to only create one instance of tail-insensitive stages. - - SkRasterPipeline::Fn stages_4[] = { - stage_4, - stage_4, - stage_4, - - stage_4, - stage_4, - stage_4, - - stage_4, - stage_4, - stage_4, - - stage_4, - - stage_4, - stage_4, - stage_4, - - stage_4, - - SK_OPTS_NS::dst, - SK_OPTS_NS::dstatop, - SK_OPTS_NS::dstin, - SK_OPTS_NS::dstout, - SK_OPTS_NS::dstover, - SK_OPTS_NS::srcatop, - SK_OPTS_NS::srcin, - SK_OPTS_NS::srcout, - SK_OPTS_NS::srcover, - SK_OPTS_NS::clear, - SK_OPTS_NS::modulate, - SK_OPTS_NS::multiply, - SK_OPTS_NS::plus_, - SK_OPTS_NS::screen, - SK_OPTS_NS::xor_, - SK_OPTS_NS::colorburn, - SK_OPTS_NS::colordodge, - SK_OPTS_NS::darken, - SK_OPTS_NS::difference, - SK_OPTS_NS::exclusion, - SK_OPTS_NS::hardlight, - SK_OPTS_NS::lighten, - SK_OPTS_NS::overlay, - SK_OPTS_NS::softlight, - }; - static_assert(SK_ARRAY_COUNT(stages_4) == SkRasterPipeline::kNumStockStages, ""); - - SkRasterPipeline::Fn stages_1_3[] = { - stage_1_3, - stage_1_3, - stage_1_3, - - stage_1_3, - stage_1_3, - stage_1_3, - - stage_1_3, - stage_1_3, - stage_1_3, - - stage_1_3, - - stage_1_3, - stage_1_3, - stage_1_3, - - stage_1_3, - - SK_OPTS_NS::dst, - SK_OPTS_NS::dstatop, - SK_OPTS_NS::dstin, - SK_OPTS_NS::dstout, - SK_OPTS_NS::dstover, - SK_OPTS_NS::srcatop, - SK_OPTS_NS::srcin, - SK_OPTS_NS::srcout, - SK_OPTS_NS::srcover, - SK_OPTS_NS::clear, - SK_OPTS_NS::modulate, - SK_OPTS_NS::multiply, - SK_OPTS_NS::plus_, - SK_OPTS_NS::screen, - SK_OPTS_NS::xor_, - SK_OPTS_NS::colorburn, - SK_OPTS_NS::colordodge, - SK_OPTS_NS::darken, - SK_OPTS_NS::difference, - SK_OPTS_NS::exclusion, - SK_OPTS_NS::hardlight, - SK_OPTS_NS::lighten, - SK_OPTS_NS::overlay, - SK_OPTS_NS::softlight, - }; - static_assert(SK_ARRAY_COUNT(stages_1_3) == SkRasterPipeline::kNumStockStages, ""); - // Each Init_foo() is defined in src/opts/SkOpts_foo.cpp. void Init_ssse3(); void Init_sse41(); void Init_sse42(); void Init_avx(); void Init_hsw(); - void Init_crc32() {} - void Init_neon(); + void Init_crc32(); static void init() { #if !defined(SK_BUILD_NO_OPTS) @@ -209,9 +112,6 @@ namespace SkOpts { #elif defined(SK_CPU_ARM64) if (SkCpu::Supports(SkCpu::CRC32)) { Init_crc32(); } - #elif defined(SK_CPU_ARM32) && !defined(SK_ARM_HAS_NEON) && defined(SK_ARM_HAS_OPTIONAL_NEON) - if (SkCpu::Supports(SkCpu::NEON)) { Init_neon(); } - #endif #endif } diff --git a/gfx/skia/skia/src/core/SkOpts.h b/gfx/skia/skia/src/core/SkOpts.h index 50de9c45e2b0..801b96da3a7d 100644 --- a/gfx/skia/skia/src/core/SkOpts.h +++ b/gfx/skia/skia/src/core/SkOpts.h @@ -8,10 +8,10 @@ #ifndef SkOpts_DEFINED #define SkOpts_DEFINED +#include "SkConvolver.h" #include "SkRasterPipeline.h" -#include "SkTextureCompressor.h" #include "SkTypes.h" -#include "SkXfermode.h" +#include "SkXfermodePriv.h" struct ProcCoeff; @@ -24,7 +24,7 @@ namespace SkOpts { // Declare function pointers here... // May return nullptr if we haven't specialized the given Mode. - extern SkXfermode* (*create_xfermode)(const ProcCoeff&, SkXfermode::Mode); + extern SkXfermode* (*create_xfermode)(const ProcCoeff&, SkBlendMode); typedef void (*BoxBlur)(const SkPMColor*, int, const SkIRect& srcBounds, SkPMColor*, int, int, int, int, int); extern BoxBlur box_blur_xx, box_blur_xy, box_blur_yx; @@ -32,24 +32,10 @@ namespace SkOpts { typedef void (*Morph)(const SkPMColor*, SkPMColor*, int, int, int, int, int); extern Morph dilate_x, dilate_y, erode_x, erode_y; - typedef bool (*TextureCompressor)(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes); - extern TextureCompressor (*texture_compressor)(SkColorType, SkTextureCompressor::Format); - extern bool (*fill_block_dimensions)(SkTextureCompressor::Format, int* x, int* y); - extern void (*blit_mask_d32_a8)(SkPMColor*, size_t, const SkAlpha*, size_t, SkColor, int, int); extern void (*blit_row_color32)(SkPMColor*, const SkPMColor*, int, SkPMColor); extern void (*blit_row_s32a_opaque)(SkPMColor*, const SkPMColor*, int, U8CPU); - // This function is an optimized version of SkColorCubeFilter::filterSpan - extern void (*color_cube_filter_span)(const SkPMColor[], - int, - SkPMColor[], - const int * [2], - const SkScalar * [2], - int, - const SkColor*); - // Swizzle input into some sort of 8888 pixel, {premul,unpremul} x {rgba,bgra}. typedef void (*Swizzle_8888)(uint32_t*, const void*, int); extern Swizzle_8888 RGBA_to_BGRA, // i.e. just swap RB @@ -73,8 +59,16 @@ namespace SkOpts { return hash_fn(data, bytes, seed); } - extern SkRasterPipeline::Fn stages_4 [SkRasterPipeline::kNumStockStages], - stages_1_3[SkRasterPipeline::kNumStockStages]; + extern void (*run_pipeline)(size_t, size_t, const SkRasterPipeline::Stage*, int); + + extern void (*convolve_vertically)(const SkConvolutionFilter1D::ConvolutionFixed* filter_values, + int filter_length, unsigned char* const* source_data_rows, + int pixel_width, unsigned char* out_row, bool has_alpha); + extern void (*convolve_4_rows_horizontally)(const unsigned char* src_data[4], + const SkConvolutionFilter1D& filter, + unsigned char* out_row[4], size_t out_row_bytes); + extern void (*convolve_horizontally)(const unsigned char* src_data, const SkConvolutionFilter1D& filter, + unsigned char* out_row, bool has_alpha); } #endif//SkOpts_DEFINED diff --git a/gfx/skia/skia/src/core/SkOverdrawCanvas.cpp b/gfx/skia/skia/src/core/SkOverdrawCanvas.cpp new file mode 100644 index 000000000000..ad37b9a98ffe --- /dev/null +++ b/gfx/skia/skia/src/core/SkOverdrawCanvas.cpp @@ -0,0 +1,308 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorFilter.h" +#include "SkDrawable.h" +#include "SkFindAndPlaceGlyph.h" +#include "SkImagePriv.h" +#include "SkLatticeIter.h" +#include "SkOverdrawCanvas.h" +#include "SkPatchUtils.h" +#include "SkPath.h" +#include "SkRRect.h" +#include "SkRSXform.h" +#include "SkTextBlob.h" +#include "SkTextBlobRunIterator.h" + +namespace { +class ProcessOneGlyphBounds { +public: + ProcessOneGlyphBounds(SkOverdrawCanvas* canvas) + : fCanvas(canvas) + {} + + void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) { + int left = SkScalarFloorToInt(position.fX) + glyph.fLeft; + int top = SkScalarFloorToInt(position.fY) + glyph.fTop; + int right = left + glyph.fWidth; + int bottom = top + glyph.fHeight; + fCanvas->onDrawRect(SkRect::MakeLTRB(left, top, right, bottom), SkPaint()); + } + +private: + SkOverdrawCanvas* fCanvas; +}; +}; + +SkOverdrawCanvas::SkOverdrawCanvas(SkCanvas* canvas) + : INHERITED(canvas->onImageInfo().width(), canvas->onImageInfo().height()) +{ + // Non-drawing calls that SkOverdrawCanvas does not override (translate, save, etc.) + // will pass through to the input canvas. + this->addCanvas(canvas); + + static constexpr float kIncrementAlpha[] = { + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + }; + + fPaint.setAntiAlias(false); + fPaint.setBlendMode(SkBlendMode::kPlus); + fPaint.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(kIncrementAlpha)); +} + +void SkOverdrawCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint& paint) { + ProcessOneGlyphBounds processBounds(this); + SkSurfaceProps props(0, kUnknown_SkPixelGeometry); + this->getProps(&props); + SkAutoGlyphCache cache(paint, &props, 0, &this->getTotalMatrix()); + SkFindAndPlaceGlyph::ProcessText(paint.getTextEncoding(), (const char*) text, byteLength, + SkPoint::Make(x, y), SkMatrix(), paint.getTextAlign(), + cache.get(), processBounds); +} + +void SkOverdrawCanvas::drawPosTextCommon(const void* text, size_t byteLength, const SkScalar pos[], + int scalarsPerPos, const SkPoint& offset, + const SkPaint& paint) { + ProcessOneGlyphBounds processBounds(this); + SkSurfaceProps props(0, kUnknown_SkPixelGeometry); + this->getProps(&props); + SkAutoGlyphCache cache(paint, &props, 0, &this->getTotalMatrix()); + SkFindAndPlaceGlyph::ProcessPosText(paint.getTextEncoding(), (const char*) text, byteLength, + SkPoint::Make(0, 0), SkMatrix(), (const SkScalar*) pos, 2, + paint.getTextAlign(), cache.get(), processBounds); +} + +void SkOverdrawCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint& paint) { + this->drawPosTextCommon(text, byteLength, (SkScalar*) pos, 2, SkPoint::Make(0, 0), paint); +} + +void SkOverdrawCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xs[], + SkScalar y, const SkPaint& paint) { + this->drawPosTextCommon(text, byteLength, (SkScalar*) xs, 1, SkPoint::Make(0, y), paint); +} + +void SkOverdrawCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, + const SkMatrix* matrix, const SkPaint& paint) { + SkASSERT(false); + return; +} + +typedef int (*CountTextProc)(const char* text); +static int count_utf16(const char* text) { + const uint16_t* prev = (uint16_t*)text; + (void)SkUTF16_NextUnichar(&prev); + return SkToInt((const char*)prev - text); +} +static int return_4(const char* text) { return 4; } +static int return_2(const char* text) { return 2; } + +void SkOverdrawCanvas::onDrawTextRSXform(const void* text, size_t byteLength, + const SkRSXform xform[], const SkRect*, + const SkPaint& paint) { + CountTextProc proc = nullptr; + switch (paint.getTextEncoding()) { + case SkPaint::kUTF8_TextEncoding: + proc = SkUTF8_CountUTF8Bytes; + break; + case SkPaint::kUTF16_TextEncoding: + proc = count_utf16; + break; + case SkPaint::kUTF32_TextEncoding: + proc = return_4; + break; + case SkPaint::kGlyphID_TextEncoding: + proc = return_2; + break; + } + SkASSERT(proc); + + SkMatrix matrix; + const void* stopText = (const char*)text + byteLength; + while ((const char*)text < (const char*)stopText) { + matrix.setRSXform(*xform++); + matrix.setConcat(this->getTotalMatrix(), matrix); + int subLen = proc((const char*)text); + + this->save(); + this->concat(matrix); + this->drawText(text, subLen, 0, 0, paint); + this->restore(); + + text = (const char*)text + subLen; + } +} + +void SkOverdrawCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) { + SkPaint runPaint = paint; + SkTextBlobRunIterator it(blob); + for (;!it.done(); it.next()) { + size_t textLen = it.glyphCount() * sizeof(uint16_t); + const SkPoint& offset = it.offset(); + it.applyFontToPaint(&runPaint); + switch (it.positioning()) { + case SkTextBlob::kDefault_Positioning: + this->onDrawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint); + break; + case SkTextBlob::kHorizontal_Positioning: + this->drawPosTextCommon(it.glyphs(), textLen, it.pos(), 1, + SkPoint::Make(x, y + offset.y()), runPaint); + break; + case SkTextBlob::kFull_Positioning: + this->drawPosTextCommon(it.glyphs(), textLen, it.pos(), 2, SkPoint::Make(x, y), + runPaint); + break; + default: + SkASSERT(false); + break; + } + } +} + +void SkOverdrawCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode blendMode, + const SkPaint&) { + fList[0]->onDrawPatch(cubics, colors, texCoords, blendMode, fPaint); +} + +void SkOverdrawCanvas::onDrawPaint(const SkPaint& paint) { + if (0 == paint.getColor() && !paint.getColorFilter() && !paint.getShader()) { + // This is a clear, ignore it. + } else { + fList[0]->onDrawPaint(this->overdrawPaint(paint)); + } +} + +void SkOverdrawCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { + fList[0]->onDrawRect(rect, this->overdrawPaint(paint)); +} + +void SkOverdrawCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { + fList[0]->onDrawRegion(region, this->overdrawPaint(paint)); +} + +void SkOverdrawCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { + fList[0]->onDrawOval(oval, this->overdrawPaint(paint)); +} + +void SkOverdrawCanvas::onDrawArc(const SkRect& arc, SkScalar startAngle, SkScalar sweepAngle, + bool useCenter, const SkPaint& paint) { + fList[0]->onDrawArc(arc, startAngle, sweepAngle, useCenter, this->overdrawPaint(paint)); +} + +void SkOverdrawCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, + const SkPaint& paint) { + fList[0]->onDrawDRRect(outer, inner, this->overdrawPaint(paint)); +} + +void SkOverdrawCanvas::onDrawRRect(const SkRRect& rect, const SkPaint& paint) { + fList[0]->onDrawRRect(rect, this->overdrawPaint(paint)); +} + +void SkOverdrawCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint points[], + const SkPaint& paint) { + fList[0]->onDrawPoints(mode, count, points, this->overdrawPaint(paint)); +} + +void SkOverdrawCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode blendMode, + const SkPaint& paint) { + fList[0]->onDrawVerticesObject(vertices, blendMode, this->overdrawPaint(paint)); +} + +void SkOverdrawCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[], + const SkRect texs[], const SkColor colors[], int count, + SkBlendMode mode, const SkRect* cull, const SkPaint* paint) { + SkPaint* paintPtr = &fPaint; + SkPaint storage; + if (paint) { + storage = this->overdrawPaint(*paint); + paintPtr = &storage; + } + + fList[0]->onDrawAtlas(image, xform, texs, colors, count, mode, cull, paintPtr); +} + +void SkOverdrawCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { + fList[0]->onDrawPath(path, fPaint); +} + +void SkOverdrawCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint*) { + fList[0]->onDrawRect(SkRect::MakeXYWH(x, y, image->width(), image->height()), fPaint); +} + +void SkOverdrawCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, + const SkPaint*, SrcRectConstraint) { + fList[0]->onDrawRect(dst, fPaint); +} + +void SkOverdrawCanvas::onDrawImageNine(const SkImage*, const SkIRect&, const SkRect& dst, + const SkPaint*) { + fList[0]->onDrawRect(dst, fPaint); +} + +void SkOverdrawCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, + const SkRect& dst, const SkPaint*) { + SkIRect bounds; + Lattice latticePlusBounds = lattice; + if (!latticePlusBounds.fBounds) { + bounds = SkIRect::MakeWH(image->width(), image->height()); + latticePlusBounds.fBounds = &bounds; + } + + if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) { + SkLatticeIter iter(latticePlusBounds, dst); + + SkRect dummy, iterDst; + while (iter.next(&dummy, &iterDst)) { + fList[0]->onDrawRect(iterDst, fPaint); + } + } else { + fList[0]->onDrawRect(dst, fPaint); + } +} + +void SkOverdrawCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, + const SkPaint*) { + fList[0]->onDrawRect(SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()), fPaint); +} + +void SkOverdrawCanvas::onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect& dst, + const SkPaint*, SrcRectConstraint) { + fList[0]->onDrawRect(dst, fPaint); +} + +void SkOverdrawCanvas::onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect& dst, + const SkPaint*) { + fList[0]->onDrawRect(dst, fPaint); +} + +void SkOverdrawCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, + const SkRect& dst, const SkPaint* paint) { + sk_sp image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); + this->onDrawImageLattice(image.get(), lattice, dst, paint); +} + +void SkOverdrawCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { + drawable->draw(this, matrix); +} + +void SkOverdrawCanvas::onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) { + SkASSERT(false); + return; +} + +inline SkPaint SkOverdrawCanvas::overdrawPaint(const SkPaint& paint) { + SkPaint newPaint = fPaint; + newPaint.setStyle(paint.getStyle()); + newPaint.setStrokeWidth(paint.getStrokeWidth()); + return newPaint; +} diff --git a/gfx/skia/skia/src/core/SkOverdrawCanvas.h b/gfx/skia/skia/src/core/SkOverdrawCanvas.h new file mode 100644 index 000000000000..5c247b1630e9 --- /dev/null +++ b/gfx/skia/skia/src/core/SkOverdrawCanvas.h @@ -0,0 +1,70 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOverdrawCanvas_DEFINED +#define SkOverdrawCanvas_DEFINED + +#include "SkNWayCanvas.h" + +/** + * Captures all drawing commands. Rather than draw the actual content, this device + * increments the alpha channel of each pixel every time it would have been touched + * by a draw call. This is useful for detecting overdraw. + */ +class SkOverdrawCanvas : public SkNWayCanvas { +public: + /* Does not take ownership of canvas */ + SkOverdrawCanvas(SkCanvas*); + + void onDrawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override; + void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint&) override; + void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override; + void onDrawTextOnPath(const void*, size_t, const SkPath&, const SkMatrix*, + const SkPaint&) override; + void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, + const SkPaint&) override; + void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override; + void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, + const SkPaint&) override; + void onDrawPaint(const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawRegion(const SkRegion&, const SkPaint&) override; + void onDrawOval(const SkRect&, const SkPaint&) override; + void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override; + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawPoints(PointMode, size_t, const SkPoint[], const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; + void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], + int, SkBlendMode, const SkRect*, const SkPaint*) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override; + void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*, + SrcRectConstraint) override; + void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override; + void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override; + void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override; + void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, + SrcRectConstraint) override; + void onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect&, const SkPaint*) override; + void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, + const SkPaint*) override; + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + +private: + void drawPosTextCommon(const void*, size_t, const SkScalar[], int, const SkPoint&, + const SkPaint&); + + inline SkPaint overdrawPaint(const SkPaint& paint); + + SkPaint fPaint; + + typedef SkNWayCanvas INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkPM4fPriv.h b/gfx/skia/skia/src/core/SkPM4fPriv.h index 89a0caeb70ce..821c8822cb87 100644 --- a/gfx/skia/skia/src/core/SkPM4fPriv.h +++ b/gfx/skia/skia/src/core/SkPM4fPriv.h @@ -9,7 +9,11 @@ #define SkPM4fPriv_DEFINED #include "SkColorPriv.h" +#include "SkColorSpace.h" +#include "SkColorSpace_Base.h" +#include "SkArenaAlloc.h" #include "SkPM4f.h" +#include "SkRasterPipeline.h" #include "SkSRGB.h" static inline Sk4f set_alpha(const Sk4f& px, float alpha) { @@ -71,4 +75,98 @@ static inline float exact_srgb_to_linear(float srgb) { return linear; } +static inline void analyze_3x4_matrix(const float matrix[12], + bool* can_underflow, bool* can_overflow) { + // | 0 3 6 9 | |r| |x| + // | 1 4 7 10 | x |g| = |y| + // | 2 5 8 11 | |b| |z| + // |1| + // We'll find min/max bounds on each of x,y,z assuming r,g,b are all in [0,1]. + // If any can be <0, we'll set can_underflow; if any can be >1, can_overflow. + bool underflow = false, + overflow = false; + for (int i = 0; i < 3; i++) { + SkScalar min = matrix[i+9], + max = matrix[i+9]; + (matrix[i+0] < 0 ? min : max) += matrix[i+0]; + (matrix[i+3] < 0 ? min : max) += matrix[i+3]; + (matrix[i+6] < 0 ? min : max) += matrix[i+6]; + underflow = underflow || min < 0; + overflow = overflow || max > 1; + } + *can_underflow = underflow; + *can_overflow = overflow; +} + + +// N.B. scratch_matrix_3x4 must live at least as long as p. +static inline bool append_gamut_transform(SkRasterPipeline* p, float scratch_matrix_3x4[12], + SkColorSpace* src, SkColorSpace* dst) { + if (src == dst) { return true; } + if (!dst) { return true; } // Legacy modes intentionally ignore color gamut. + if (!src) { return true; } // A null src color space means linear gamma, dst gamut. + + auto toXYZ = as_CSB(src)-> toXYZD50(), + fromXYZ = as_CSB(dst)->fromXYZD50(); + if (!toXYZ || !fromXYZ) { return false; } // Unsupported color space type. + + if (as_CSB(src)->toXYZD50Hash() == as_CSB(dst)->toXYZD50Hash()) { return true; } + + SkMatrix44 m44(*fromXYZ, *toXYZ); + + // Convert from 4x4 to (column-major) 3x4. + auto ptr = scratch_matrix_3x4; + *ptr++ = m44.get(0,0); *ptr++ = m44.get(1,0); *ptr++ = m44.get(2,0); + *ptr++ = m44.get(0,1); *ptr++ = m44.get(1,1); *ptr++ = m44.get(2,1); + *ptr++ = m44.get(0,2); *ptr++ = m44.get(1,2); *ptr++ = m44.get(2,2); + *ptr++ = m44.get(0,3); *ptr++ = m44.get(1,3); *ptr++ = m44.get(2,3); + + bool needs_clamp_0, needs_clamp_a; + analyze_3x4_matrix(scratch_matrix_3x4, &needs_clamp_0, &needs_clamp_a); + + p->append(SkRasterPipeline::matrix_3x4, scratch_matrix_3x4); + if (needs_clamp_0) { p->append(SkRasterPipeline::clamp_0); } + if (needs_clamp_a) { p->append(SkRasterPipeline::clamp_a); } + return true; +} + +static inline bool append_gamut_transform(SkRasterPipeline* p, SkArenaAlloc* scratch, + SkColorSpace* src, SkColorSpace* dst) { + return append_gamut_transform(p, scratch->makeArrayDefault(12), src, dst); +} + +static inline SkColor4f to_colorspace(const SkColor4f& c, SkColorSpace* src, SkColorSpace* dst) { + SkColor4f color4f = c; + if (src && dst) { + void* color4f_ptr = &color4f; + + float scratch_matrix_3x4[12]; + + SkRasterPipeline p; + p.append(SkRasterPipeline::constant_color, color4f_ptr); + append_gamut_transform(&p, scratch_matrix_3x4, src, dst); + p.append(SkRasterPipeline::store_f32, &color4f_ptr); + + p.run(0,1); + } + return color4f; +} + +static inline SkColor4f SkColor4f_from_SkColor(SkColor color, SkColorSpace* dst) { + SkColor4f color4f; + if (dst) { + // sRGB gamma, sRGB gamut. + color4f = to_colorspace(SkColor4f::FromColor(color), + SkColorSpace::MakeSRGB().get(), dst); + } else { + // Linear gamma, dst gamut. + swizzle_rb(SkNx_cast(Sk4b::Load(&color)) * (1/255.0f)).store(&color4f); + } + return color4f; +} + +static inline SkPM4f SkPM4f_from_SkColor(SkColor color, SkColorSpace* dst) { + return SkColor4f_from_SkColor(color, dst).premul(); +} + #endif diff --git a/gfx/skia/skia/src/core/SkPaint.cpp b/gfx/skia/skia/src/core/SkPaint.cpp index 17843496bbfe..568ba6a0216d 100644 --- a/gfx/skia/skia/src/core/SkPaint.cpp +++ b/gfx/skia/skia/src/core/SkPaint.cpp @@ -6,6 +6,7 @@ */ #include "SkPaint.h" +#include "SkPaintPriv.h" #include "SkAutoKern.h" #include "SkColorFilter.h" #include "SkData.h" @@ -35,7 +36,6 @@ #include "SkTextToPathIter.h" #include "SkTLazy.h" #include "SkTypeface.h" -#include "SkXfermode.h" static inline uint32_t set_clear_mask(uint32_t bits, bool cond, uint32_t mask) { return cond ? bits | mask : bits & ~mask; @@ -185,6 +185,17 @@ bool operator==(const SkPaint& a, const SkPaint& b) { #undef EQUAL } +#define DEFINE_REF_FOO(type) sk_sp SkPaint::ref##type() const { return f##type; } +DEFINE_REF_FOO(ColorFilter) +DEFINE_REF_FOO(DrawLooper) +DEFINE_REF_FOO(ImageFilter) +DEFINE_REF_FOO(MaskFilter) +DEFINE_REF_FOO(PathEffect) +DEFINE_REF_FOO(Rasterizer) +DEFINE_REF_FOO(Shader) +DEFINE_REF_FOO(Typeface) +#undef DEFINE_REF_FOO + void SkPaint::reset() { SkPaint init; *this = init; @@ -234,14 +245,6 @@ void SkPaint::setVerticalText(bool doVertical) { this->setFlags(set_clear_mask(fBitfields.fFlags, doVertical, kVerticalText_Flag)); } -void SkPaint::setUnderlineText(bool doUnderline) { - this->setFlags(set_clear_mask(fBitfields.fFlags, doUnderline, kUnderlineText_Flag)); -} - -void SkPaint::setStrikeThruText(bool doStrikeThru) { - this->setFlags(set_clear_mask(fBitfields.fFlags, doStrikeThru, kStrikeThruText_Flag)); -} - void SkPaint::setFakeBoldText(bool doFakeBold) { this->setFlags(set_clear_mask(fBitfields.fFlags, doFakeBold, kFakeBoldText_Flag)); } @@ -367,58 +370,6 @@ MOVE_FIELD(DrawLooper) #undef MOVE_FIELD void SkPaint::setLooper(sk_sp looper) { fDrawLooper = std::move(looper); } -#define SET_PTR(Field) \ - Sk##Field* SkPaint::set##Field(Sk##Field* f) { \ - this->f##Field.reset(SkSafeRef(f)); \ - return f; \ - } -#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR -SET_PTR(Typeface) -#endif -#ifdef SK_SUPPORT_LEGACY_MINOR_EFFECT_PTR -SET_PTR(Rasterizer) -#endif -SET_PTR(ImageFilter) -#ifdef SK_SUPPORT_LEGACY_CREATESHADER_PTR -SET_PTR(Shader) -#endif -#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR -SET_PTR(ColorFilter) -#endif -#ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR -SkXfermode* SkPaint::setXfermode(SkXfermode* xfer) { - this->setBlendMode(xfer ? xfer->blend() : SkBlendMode::kSrcOver); - return this->getXfermode(); -} -#endif -#ifdef SK_SUPPORT_LEGACY_PATHEFFECT_PTR -SET_PTR(PathEffect) -#endif -#ifdef SK_SUPPORT_LEGACY_MASKFILTER_PTR -SET_PTR(MaskFilter) -#endif -#undef SET_PTR - -#ifdef SK_SUPPORT_LEGACY_MINOR_EFFECT_PTR -SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) { - fDrawLooper.reset(SkSafeRef(looper)); - return looper; -} -#endif - -#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT -void SkPaint::setXfermode(sk_sp mode) { - this->setBlendMode(mode ? mode->blend() : SkBlendMode::kSrcOver); -} -SkXfermode* SkPaint::getXfermode() const { - return SkXfermode::Peek((SkBlendMode)fBlendMode); -} -SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) { - this->setBlendMode((SkBlendMode)mode); - return SkXfermode::Peek((SkBlendMode)mode); -} -#endif - /////////////////////////////////////////////////////////////////////////////// static SkScalar mag2(SkScalar x, SkScalar y) { @@ -493,7 +444,11 @@ int SkPaint::textToGlyphs(const void* textData, size_t byteLength, uint16_t glyp switch (this->getTextEncoding()) { case SkPaint::kUTF8_TextEncoding: while (text < stop) { - *gptr++ = cache->unicharToGlyph(SkUTF8_NextUnichar(&text)); + SkUnichar u = SkUTF8_NextUnicharWithError(&text, stop); + if (u < 0) { + return 0; // bad UTF-8 sequence + } + *gptr++ = cache->unicharToGlyph(u); } break; case SkPaint::kUTF16_TextEncoding: { @@ -863,12 +818,12 @@ SkScalar SkPaint::measureText(const void* textData, size_t length, SkRect* bound width = paint.measure_text(cache, text, length, &tempCount, bounds); if (scale) { - width = SkScalarMul(width, scale); + width *= scale; if (bounds) { - bounds->fLeft = SkScalarMul(bounds->fLeft, scale); - bounds->fTop = SkScalarMul(bounds->fTop, scale); - bounds->fRight = SkScalarMul(bounds->fRight, scale); - bounds->fBottom = SkScalarMul(bounds->fBottom, scale); + bounds->fLeft *= scale; + bounds->fTop *= scale; + bounds->fRight *= scale; + bounds->fBottom *= scale; } } } else if (bounds) { @@ -983,17 +938,7 @@ SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const { paint.descriptorProc(nullptr, kNone_ScalerContextFlags, zoomPtr, FontMetricsDescProc, metrics); if (scale) { - metrics->fTop = SkScalarMul(metrics->fTop, scale); - metrics->fAscent = SkScalarMul(metrics->fAscent, scale); - metrics->fDescent = SkScalarMul(metrics->fDescent, scale); - metrics->fBottom = SkScalarMul(metrics->fBottom, scale); - metrics->fLeading = SkScalarMul(metrics->fLeading, scale); - metrics->fAvgCharWidth = SkScalarMul(metrics->fAvgCharWidth, scale); - metrics->fXMin = SkScalarMul(metrics->fXMin, scale); - metrics->fXMax = SkScalarMul(metrics->fXMax, scale); - metrics->fXHeight = SkScalarMul(metrics->fXHeight, scale); - metrics->fUnderlineThickness = SkScalarMul(metrics->fUnderlineThickness, scale); - metrics->fUnderlinePosition = SkScalarMul(metrics->fUnderlinePosition, scale); + SkPaintPriv::ScaleFontMetrics(metrics, scale); } return metrics->fDescent - metrics->fAscent + metrics->fLeading; } @@ -1046,7 +991,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, SkScalar adjust = autokern.adjust(g); if (count > 0) { - *widths++ = SkScalarMul(prevWidth + adjust, scale); + *widths++ = (prevWidth + adjust) * scale; } prevWidth = advance(g, xyIndex); } @@ -1056,7 +1001,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, ++count; } if (count > 0 && widths) { - *widths = SkScalarMul(prevWidth, scale); + *widths = prevWidth * scale; } } else { while (text < stop) { @@ -1083,8 +1028,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, while (text < stop) { const SkGlyph& g = glyphCacheProc(cache, &text); if (widths) { - *widths++ = SkScalarMul(advance(g, xyIndex), - scale); + *widths++ = advance(g, xyIndex) * scale; } if (bounds) { set_bounds(g, bounds++, scale); @@ -1409,7 +1353,7 @@ void SkScalerContext::MakeRec(const SkPaint& paint, kStdFakeBoldInterpKeys, kStdFakeBoldInterpValues, kStdFakeBoldInterpLength); - SkScalar extra = SkScalarMul(paint.getTextSize(), fakeBoldScale); + SkScalar extra = paint.getTextSize() * fakeBoldScale; if (style == SkPaint::kFill_Style) { style = SkPaint::kStrokeAndFill_Style; @@ -2092,10 +2036,10 @@ void SkPaint::toString(SkString* str) const { if (typeface) { SkDynamicMemoryWStream ostream; typeface->serialize(&ostream); - SkAutoTDelete istream(ostream.detachAsStream()); + std::unique_ptr istream(ostream.detachAsStream()); SkFontDescriptor descriptor; - if (!SkFontDescriptor::Deserialize(istream, &descriptor)) { + if (!SkFontDescriptor::Deserialize(istream.get(), &descriptor)) { str->append("

FontDescriptor deserialization failed
"); } else { str->append("
Font Family Name:
"); @@ -2190,8 +2134,6 @@ void SkPaint::toString(SkString* str) const { bool needSeparator = false; SkAddFlagToString(str, this->isAntiAlias(), "AntiAlias", &needSeparator); SkAddFlagToString(str, this->isDither(), "Dither", &needSeparator); - SkAddFlagToString(str, this->isUnderlineText(), "UnderlineText", &needSeparator); - SkAddFlagToString(str, this->isStrikeThruText(), "StrikeThruText", &needSeparator); SkAddFlagToString(str, this->isFakeBoldText(), "FakeBoldText", &needSeparator); SkAddFlagToString(str, this->isLinearText(), "LinearText", &needSeparator); SkAddFlagToString(str, this->isSubpixelText(), "SubpixelText", &needSeparator); @@ -2293,20 +2235,19 @@ SkTextBaseIter::SkTextBaseIter(const char text[], size_t length, sk_sp pe; if (!applyStrokeAndPathEffects) { - style = paint.getStyle(); // restore - pe = sk_ref_sp(paint.getPathEffect()); // restore + style = paint.getStyle(); // restore + pe = paint.refPathEffect(); // restore } fPaint.setStyle(style); fPaint.setPathEffect(pe); - fPaint.setMaskFilter(sk_ref_sp(paint.getMaskFilter())); // restore + fPaint.setMaskFilter(paint.refMaskFilter()); // restore // now compute fXOffset if needed SkScalar xOffset = 0; if (paint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first int count; - SkScalar width = SkScalarMul(fPaint.measure_text(fCache, text, length, - &count, nullptr), fScale); + SkScalar width = fPaint.measure_text(fCache, text, length, &count, nullptr) * fScale; if (paint.getTextAlign() == SkPaint::kCenter_Align) { width = SkScalarHalf(width); } @@ -2329,7 +2270,7 @@ bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) { if (fText < fStop) { const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText); - fXPos += SkScalarMul(fPrevAdvance + fAutoKern.adjust(glyph), fScale); + fXPos += (fPrevAdvance + fAutoKern.adjust(glyph)) * fScale; fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking(); if (glyph.fWidth) { @@ -2351,7 +2292,7 @@ bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) { bool SkTextInterceptsIter::next(SkScalar* array, int* count) { const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText); - fXPos += SkScalarMul(fPrevAdvance + fAutoKern.adjust(glyph), fScale); + fXPos += (fPrevAdvance + fAutoKern.adjust(glyph)) * fScale; fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking(); if (fCache->findPath(glyph)) { fCache->findIntercepts(fBounds, fScale, fXPos, SkToBool(fXYIndex), diff --git a/gfx/skia/skia/src/core/SkPaintPriv.cpp b/gfx/skia/skia/src/core/SkPaintPriv.cpp index cbe2558c2a82..7dfb2e30ff0d 100644 --- a/gfx/skia/skia/src/core/SkPaintPriv.cpp +++ b/gfx/skia/skia/src/core/SkPaintPriv.cpp @@ -11,6 +11,7 @@ #include "SkImage.h" #include "SkPaint.h" #include "SkShader.h" +#include "SkXfermodePriv.h" static bool changes_alpha(const SkPaint& paint) { SkColorFilter* cf = paint.getColorFilter(); @@ -53,3 +54,18 @@ bool SkPaintPriv::Overwrites(const SkImage* image, const SkPaint* paint) { return Overwrites(paint, image->isOpaque() ? kOpaque_ShaderOverrideOpacity : kNotOpaque_ShaderOverrideOpacity); } + +void SkPaintPriv::ScaleFontMetrics(SkPaint::FontMetrics* metrics, SkScalar scale) { + metrics->fTop *= scale; + metrics->fAscent *= scale; + metrics->fDescent *= scale; + metrics->fBottom *= scale; + metrics->fLeading *= scale; + metrics->fAvgCharWidth *= scale; + metrics->fXMin *= scale; + metrics->fXMax *= scale; + metrics->fXHeight *= scale; + metrics->fUnderlineThickness *= scale; + metrics->fUnderlinePosition *= scale; +} + diff --git a/gfx/skia/skia/src/core/SkPaintPriv.h b/gfx/skia/skia/src/core/SkPaintPriv.h index 1cf404075b0c..de8e6c73faf4 100644 --- a/gfx/skia/skia/src/core/SkPaintPriv.h +++ b/gfx/skia/skia/src/core/SkPaintPriv.h @@ -8,11 +8,10 @@ #ifndef SkPaintPriv_DEFINED #define SkPaintPriv_DEFINED -#include "SkTypes.h" +#include "SkPaint.h" class SkBitmap; class SkImage; -class SkPaint; class SkPaintPriv { public: @@ -45,6 +44,8 @@ public: * pixels. */ static bool Overwrites(const SkImage*, const SkPaint* paint); + + static void ScaleFontMetrics(SkPaint::FontMetrics*, SkScalar); }; #endif diff --git a/gfx/skia/skia/src/core/SkPath.cpp b/gfx/skia/skia/src/core/SkPath.cpp index a2ef546209ad..a7f515a2a882 100644 --- a/gfx/skia/skia/src/core/SkPath.cpp +++ b/gfx/skia/skia/src/core/SkPath.cpp @@ -8,13 +8,20 @@ #include #include "SkBuffer.h" #include "SkCubicClipper.h" -#include "SkErrorInternals.h" #include "SkGeometry.h" #include "SkMath.h" #include "SkPathPriv.h" #include "SkPathRef.h" #include "SkRRect.h" +static float poly_eval(float A, float B, float C, float t) { + return (A * t + B) * t + C; +} + +static float poly_eval(float A, float B, float C, float D, float t) { + return ((A * t + B) * t + C) * t + D; +} + //////////////////////////////////////////////////////////////////////////// /** @@ -221,7 +228,7 @@ bool SkPath::interpolate(const SkPath& ending, SkScalar weight, SkPath* out) con } out->reset(); out->addPath(*this); - fPathRef->interpolate(*ending.fPathRef, weight, out->fPathRef); + fPathRef->interpolate(*ending.fPathRef, weight, out->fPathRef.get()); return true; } @@ -240,10 +247,10 @@ static inline bool check_edge_against_rect(const SkPoint& p0, } if (v.fX || v.fY) { // check the cross product of v with the vec from edgeBegin to each rect corner - SkScalar yL = SkScalarMul(v.fY, rect.fLeft - edgeBegin->fX); - SkScalar xT = SkScalarMul(v.fX, rect.fTop - edgeBegin->fY); - SkScalar yR = SkScalarMul(v.fY, rect.fRight - edgeBegin->fX); - SkScalar xB = SkScalarMul(v.fX, rect.fBottom - edgeBegin->fY); + SkScalar yL = v.fY * (rect.fLeft - edgeBegin->fX); + SkScalar xT = v.fX * (rect.fTop - edgeBegin->fY); + SkScalar yR = v.fY * (rect.fRight - edgeBegin->fX); + SkScalar xB = v.fX * (rect.fBottom - edgeBegin->fY); if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) { return false; } @@ -1092,7 +1099,7 @@ static int build_arc_conics(const SkRect& oval, const SkVector& start, const SkV int count = SkConic::BuildUnitArc(start, stop, dir, &matrix, conics); if (0 == count) { - matrix.mapXY(start.x(), start.y(), singlePt); + matrix.mapXY(stop.x(), stop.y(), singlePt); } return count; } @@ -1208,10 +1215,6 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, assert_known_direction(dir); if (rx < 0 || ry < 0) { - SkErrorInternals::SetError( kInvalidArgument_SkError, - "I got %f and %f as radii to SkPath::AddRoundRect, " - "but negative radii are not allowed.", - SkScalarToDouble(rx), SkScalarToDouble(ry) ); return; } @@ -1293,6 +1296,25 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, angles_to_unit_vectors(startAngle, sweepAngle, &startV, &stopV, &dir); SkPoint singlePt; + + // At this point, we know that the arc is not a lone point, but startV == stopV + // indicates that the sweepAngle is too small such that angles_to_unit_vectors + // cannot handle it. + if (startV == stopV) { + SkScalar endAngle = SkDegreesToRadians(startAngle + sweepAngle); + SkScalar radiusX = oval.width() / 2; + SkScalar radiusY = oval.height() / 2; + // We cannot use SkScalarSinCos function in the next line because + // SkScalarSinCos has a threshold *SkScalarNearlyZero*. When sin(startAngle) + // is 0 and sweepAngle is very small and radius is huge, the expected + // behavior here is to draw a line. But calling SkScalarSinCos will + // make sin(endAngle) to be 0 which will then draw a dot. + singlePt.set(oval.centerX() + radiusX * sk_float_cos(endAngle), + oval.centerY() + radiusY * sk_float_sin(endAngle)); + forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt); + return; + } + SkConic conics[SkConic::kMaxConicsForArc]; int count = build_arc_conics(oval, startV, stopV, dir, conics, &singlePt); if (count) { @@ -1472,10 +1494,10 @@ void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar return; } - SkScalar dist = SkScalarAbs(SkScalarMulDiv(radius, SK_Scalar1 - cosh, sinh)); + SkScalar dist = SkScalarAbs(radius * (1 - cosh) / sinh); - SkScalar xx = x1 - SkScalarMul(dist, before.fX); - SkScalar yy = y1 - SkScalarMul(dist, before.fY); + SkScalar xx = x1 - dist * before.fX; + SkScalar yy = y1 - dist * before.fY; after.setLength(dist); this->lineTo(xx, yy); SkScalar weight = SkScalarSqrt(SK_ScalarHalf + cosh * SK_ScalarHalf); @@ -1556,49 +1578,41 @@ static int pts_in_verb(unsigned verb) { // ignore the last point of the 1st contour void SkPath::reversePathTo(const SkPath& path) { - int i, vcount = path.fPathRef->countVerbs(); - // exit early if the path is empty, or just has a moveTo. - if (vcount < 2) { + const uint8_t* verbs = path.fPathRef->verbsMemBegin(); // points at the last verb + if (!verbs) { // empty path returns nullptr return; } + const uint8_t* verbsEnd = path.fPathRef->verbs() - 1; // points just past the first verb + SkASSERT(verbsEnd[0] == kMove_Verb); + const SkPoint* pts = path.fPathRef->pointsEnd() - 1; + const SkScalar* conicWeights = path.fPathRef->conicWeightsEnd(); - SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); - - const uint8_t* verbs = path.fPathRef->verbs(); - const SkPoint* pts = path.fPathRef->points(); - const SkScalar* conicWeights = path.fPathRef->conicWeights(); - - SkASSERT(verbs[~0] == kMove_Verb); - for (i = 1; i < vcount; ++i) { - unsigned v = verbs[~i]; - int n = pts_in_verb(v); - if (n == 0) { - break; - } - pts += n; - conicWeights += (SkPath::kConic_Verb == v); - } - - while (--i > 0) { - switch (verbs[~i]) { + while (verbs < verbsEnd) { + uint8_t v = *verbs++; + pts -= pts_in_verb(v); + switch (v) { + case kMove_Verb: + // if the path has multiple contours, stop after reversing the last + return; case kLine_Verb: - this->lineTo(pts[-1].fX, pts[-1].fY); + this->lineTo(pts[0]); break; case kQuad_Verb: - this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY); + this->quadTo(pts[1], pts[0]); break; case kConic_Verb: - this->conicTo(pts[-1], pts[-2], *--conicWeights); + this->conicTo(pts[1], pts[0], *--conicWeights); break; case kCubic_Verb: - this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY, - pts[-3].fX, pts[-3].fY); + this->cubicTo(pts[2], pts[1], pts[0]); + break; + case kClose_Verb: + SkASSERT(verbs - path.fPathRef->verbsMemBegin() == 1); break; default: SkDEBUGFAIL("bad verb"); break; } - pts -= pts_in_verb(verbs[~i]); } } @@ -1735,8 +1749,8 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const { dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection; } else { SkScalar det2x2 = - SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix::kMScaleY)) - - SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix::kMSkewY)); + matrix.get(SkMatrix::kMScaleX) * matrix.get(SkMatrix::kMScaleY) - + matrix.get(SkMatrix::kMSkewX) * matrix.get(SkMatrix::kMSkewY); if (det2x2 < 0) { dst->fFirstDirection = SkPathPriv::OppositeFirstDirection( (SkPathPriv::FirstDirection)fFirstDirection.load()); @@ -2051,7 +2065,7 @@ size_t SkPath::writeToMemory(void* storage) const { } size_t SkPath::readFromMemory(const void* storage, size_t length) { - SkRBufferWithSizeCheck buffer(storage, length); + SkRBuffer buffer(storage, length); int32_t packed; if (!buffer.readS32(&packed)) { @@ -2100,6 +2114,7 @@ size_t SkPath::readFromMemory(const void* storage, size_t length) { /////////////////////////////////////////////////////////////////////////////// +#include "SkString.h" #include "SkStringUtils.h" #include "SkStream.h" @@ -2144,11 +2159,15 @@ void SkPath::dump(SkWStream* wStream, bool forceClose, bool dumpAsHex) const { SkPoint pts[4]; Verb verb; - if (!wStream) { - SkDebugf("path: forceClose=%s\n", forceClose ? "true" : "false"); - } SkString builder; - + char const * const gFillTypeStrs[] = { + "Winding", + "EvenOdd", + "InverseWinding", + "InverseEvenOdd", + }; + builder.printf("path.setFillType(SkPath::k%s_FillType);\n", + gFillTypeStrs[(int) this->getFillType()]); while ((verb = iter.next(pts, false)) != kDone_Verb) { switch (verb) { case kMove_Verb: @@ -2394,8 +2413,9 @@ private: break; case kBackwards_DirChange: if (fIsCurve) { - fConvexity = SkPath::kConcave_Convexity; - fFirstDirection = SkPathPriv::kUnknown_FirstDirection; + // If any of the subsequent dir is non-backward, it'll be concave. + // Otherwise, it's still convex. + fExpectedDir = dir; } fLastVec = vec; break; @@ -2752,18 +2772,13 @@ static bool between(SkScalar a, SkScalar b, SkScalar c) { return (a - b) * (c - b) <= 0; } -static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, - SkScalar D, SkScalar t) { - return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); -} - static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3, SkScalar t) { SkScalar A = c3 + 3*(c1 - c2) - c0; SkScalar B = 3*(c2 - c1 - c1 + c0); SkScalar C = 3*(c1 - c0); SkScalar D = c0; - return eval_cubic_coeff(A, B, C, D, t); + return poly_eval(A, B, C, D, t); } template static void find_minmax(const SkPoint pts[], @@ -2848,7 +2863,7 @@ static double conic_eval_numerator(const SkScalar src[], SkScalar w, SkScalar t) SkScalar C = src[0]; SkScalar A = src[4] - 2 * src2w + C; SkScalar B = 2 * (src2w - C); - return (A * t + B) * t + C; + return poly_eval(A, B, C, t); } @@ -2856,7 +2871,7 @@ static double conic_eval_denominator(SkScalar w, SkScalar t) { SkScalar B = 2 * (w - 1); SkScalar C = 1; SkScalar A = -B; - return (A * t + B) * t + C; + return poly_eval(A, B, C, t); } static int winding_mono_conic(const SkConic& conic, SkScalar x, SkScalar y, int* onCurveCount) { @@ -2977,7 +2992,7 @@ static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* o SkScalar C = pts[0].fX; SkScalar A = pts[2].fX - 2 * pts[1].fX + C; SkScalar B = 2 * (pts[1].fX - C); - xt = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); + xt = poly_eval(A, B, C, t); } if (SkScalarNearlyEqual(xt, x)) { if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they're start points @@ -3026,7 +3041,7 @@ static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurv if (y == y1) { return 0; } - SkScalar cross = SkScalarMul(x1 - x0, y - pts[0].fY) - SkScalarMul(dy, x - x0); + SkScalar cross = (x1 - x0) * (y - pts[0].fY) - dy * (x - x0); if (!cross) { // zero cross means the point is on the line, and since the case where @@ -3115,7 +3130,7 @@ static void tangent_quad(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar C = pts[0].fX; SkScalar A = pts[2].fX - 2 * pts[1].fX + C; SkScalar B = 2 * (pts[1].fX - C); - SkScalar xt = (A * t + B) * t + C; + SkScalar xt = poly_eval(A, B, C, t); if (!SkScalarNearlyEqual(x, xt)) { continue; } @@ -3386,3 +3401,97 @@ void SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar st path->close(); } } + +/////////////////////////////////////////////////////////////////////////////////////////////////// +#include "SkNx.h" + +static int compute_quad_extremas(const SkPoint src[3], SkPoint extremas[3]) { + SkScalar ts[2]; + int n = SkFindQuadExtrema(src[0].fX, src[1].fX, src[2].fX, ts); + n += SkFindQuadExtrema(src[0].fY, src[1].fY, src[2].fY, &ts[n]); + SkASSERT(n >= 0 && n <= 2); + for (int i = 0; i < n; ++i) { + extremas[i] = SkEvalQuadAt(src, ts[i]); + } + extremas[n] = src[2]; + return n + 1; +} + +static int compute_conic_extremas(const SkPoint src[3], SkScalar w, SkPoint extremas[3]) { + SkConic conic(src[0], src[1], src[2], w); + SkScalar ts[2]; + int n = conic.findXExtrema(ts); + n += conic.findYExtrema(&ts[n]); + SkASSERT(n >= 0 && n <= 2); + for (int i = 0; i < n; ++i) { + extremas[i] = conic.evalAt(ts[i]); + } + extremas[n] = src[2]; + return n + 1; +} + +static int compute_cubic_extremas(const SkPoint src[3], SkPoint extremas[5]) { + SkScalar ts[4]; + int n = SkFindCubicExtrema(src[0].fX, src[1].fX, src[2].fX, src[3].fX, ts); + n += SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY, src[3].fY, &ts[n]); + SkASSERT(n >= 0 && n <= 4); + for (int i = 0; i < n; ++i) { + SkEvalCubicAt(src, ts[i], &extremas[i], nullptr, nullptr); + } + extremas[n] = src[3]; + return n + 1; +} + +SkRect SkPath::computeTightBounds() const { + if (0 == this->countVerbs()) { + return SkRect::MakeEmpty(); + } + + if (this->getSegmentMasks() == SkPath::kLine_SegmentMask) { + return this->getBounds(); + } + + SkPoint extremas[5]; // big enough to hold worst-case curve type (cubic) extremas + 1 + SkPoint pts[4]; + SkPath::RawIter iter(*this); + + // initial with the first MoveTo, so we don't have to check inside the switch + Sk2s min, max; + min = max = from_point(this->getPoint(0)); + for (;;) { + int count = 0; + switch (iter.next(pts)) { + case SkPath::kMove_Verb: + extremas[0] = pts[0]; + count = 1; + break; + case SkPath::kLine_Verb: + extremas[0] = pts[1]; + count = 1; + break; + case SkPath::kQuad_Verb: + count = compute_quad_extremas(pts, extremas); + break; + case SkPath::kConic_Verb: + count = compute_conic_extremas(pts, iter.conicWeight(), extremas); + break; + case SkPath::kCubic_Verb: + count = compute_cubic_extremas(pts, extremas); + break; + case SkPath::kClose_Verb: + break; + case SkPath::kDone_Verb: + goto DONE; + } + for (int i = 0; i < count; ++i) { + Sk2s tmp = from_point(extremas[i]); + min = Sk2s::Min(min, tmp); + max = Sk2s::Max(max, tmp); + } + } +DONE: + SkRect bounds; + min.store((SkPoint*)&bounds.fLeft); + max.store((SkPoint*)&bounds.fRight); + return bounds; +} diff --git a/gfx/skia/skia/src/core/SkPathEffect.cpp b/gfx/skia/skia/src/core/SkPathEffect.cpp index 1178348af530..ec5ac3b94517 100644 --- a/gfx/skia/skia/src/core/SkPathEffect.cpp +++ b/gfx/skia/skia/src/core/SkPathEffect.cpp @@ -27,20 +27,35 @@ SkPathEffect::DashType SkPathEffect::asADash(DashInfo* info) const { /////////////////////////////////////////////////////////////////////////////// -SkPairPathEffect::SkPairPathEffect(sk_sp pe0, sk_sp pe1) - : fPE0(std::move(pe0)), fPE1(std::move(pe1)) -{ - SkASSERT(fPE0.get()); - SkASSERT(fPE1.get()); -} +/** \class SkPairPathEffect -/* - Format: [oe0-factory][pe1-factory][pe0-size][pe0-data][pe1-data] -*/ -void SkPairPathEffect::flatten(SkWriteBuffer& buffer) const { - buffer.writeFlattenable(fPE0.get()); - buffer.writeFlattenable(fPE1.get()); -} + Common baseclass for Compose and Sum. This subclass manages two pathEffects, + including flattening them. It does nothing in filterPath, and is only useful + for managing the lifetimes of its two arguments. + */ +class SK_API SkPairPathEffect : public SkPathEffect { +protected: + SkPairPathEffect(sk_sp pe0, sk_sp pe1) + : fPE0(std::move(pe0)), fPE1(std::move(pe1)) + { + SkASSERT(fPE0.get()); + SkASSERT(fPE1.get()); + } + + void flatten(SkWriteBuffer& buffer) const override { + buffer.writeFlattenable(fPE0.get()); + buffer.writeFlattenable(fPE1.get()); + } + + // these are visible to our subclasses + sk_sp fPE0; + sk_sp fPE1; + + SK_TO_STRING_OVERRIDE() + +private: + typedef SkPathEffect INHERITED; +}; #ifndef SK_IGNORE_TO_STRING void SkPairPathEffect::toString(SkString* str) const { @@ -55,7 +70,61 @@ void SkPairPathEffect::toString(SkString* str) const { } #endif -/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +/** \class SkComposePathEffect + + This subclass of SkPathEffect composes its two arguments, to create + a compound pathEffect. + */ +class SK_API SkComposePathEffect : public SkPairPathEffect { +public: + /** Construct a pathEffect whose effect is to apply first the inner pathEffect + and the the outer pathEffect (e.g. outer(inner(path))) + The reference counts for outer and inner are both incremented in the constructor, + and decremented in the destructor. + */ + static sk_sp Make(sk_sp outer, sk_sp inner) { + if (!outer) { + return inner; + } + if (!inner) { + return outer; + } + return sk_sp(new SkComposePathEffect(outer, inner)); + } + + bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec, + const SkRect* cullRect) const override { + SkPath tmp; + const SkPath* ptr = &src; + + if (fPE1->filterPath(&tmp, src, rec, cullRect)) { + ptr = &tmp; + } + return fPE0->filterPath(dst, *ptr, rec, cullRect); + } + + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposePathEffect) + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + bool exposedInAndroidJavaAPI() const override { return true; } +#endif + +protected: + SkComposePathEffect(sk_sp outer, sk_sp inner) + : INHERITED(outer, inner) {} + +private: + // illegal + SkComposePathEffect(const SkComposePathEffect&); + SkComposePathEffect& operator=(const SkComposePathEffect&); + friend class SkPathEffect; + + typedef SkPairPathEffect INHERITED; +}; sk_sp SkComposePathEffect::CreateProc(SkReadBuffer& buffer) { sk_sp pe0(buffer.readPathEffect()); @@ -63,18 +132,6 @@ sk_sp SkComposePathEffect::CreateProc(SkReadBuffer& buffer) { return SkComposePathEffect::Make(std::move(pe0), std::move(pe1)); } -bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src, - SkStrokeRec* rec, const SkRect* cullRect) const { - SkPath tmp; - const SkPath* ptr = &src; - - if (fPE1->filterPath(&tmp, src, rec, cullRect)) { - ptr = &tmp; - } - return fPE0->filterPath(dst, *ptr, rec, cullRect); -} - - #ifndef SK_IGNORE_TO_STRING void SkComposePathEffect::toString(SkString* str) const { str->appendf("SkComposePathEffect: ("); @@ -85,20 +142,62 @@ void SkComposePathEffect::toString(SkString* str) const { /////////////////////////////////////////////////////////////////////////////// +/** \class SkSumPathEffect + + This subclass of SkPathEffect applies two pathEffects, one after the other. + Its filterPath() returns true if either of the effects succeeded. + */ +class SK_API SkSumPathEffect : public SkPairPathEffect { +public: + /** Construct a pathEffect whose effect is to apply two effects, in sequence. + (e.g. first(path) + second(path)) + The reference counts for first and second are both incremented in the constructor, + and decremented in the destructor. + */ + static sk_sp Make(sk_sp first, sk_sp second) { + if (!first) { + return second; + } + if (!second) { + return first; + } + return sk_sp(new SkSumPathEffect(first, second)); + } + + bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec, + const SkRect* cullRect) const override { + // use bit-or so that we always call both, even if the first one succeeds + return fPE0->filterPath(dst, src, rec, cullRect) | + fPE1->filterPath(dst, src, rec, cullRect); + } + + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSumPathEffect) + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + bool exposedInAndroidJavaAPI() const override { return true; } +#endif + +protected: + SkSumPathEffect(sk_sp first, sk_sp second) + : INHERITED(first, second) {} + +private: + // illegal + SkSumPathEffect(const SkSumPathEffect&); + SkSumPathEffect& operator=(const SkSumPathEffect&); + friend class SkPathEffect; + + typedef SkPairPathEffect INHERITED; +}; + sk_sp SkSumPathEffect::CreateProc(SkReadBuffer& buffer) { sk_sp pe0(buffer.readPathEffect()); sk_sp pe1(buffer.readPathEffect()); return SkSumPathEffect::Make(pe0, pe1); } -bool SkSumPathEffect::filterPath(SkPath* dst, const SkPath& src, - SkStrokeRec* rec, const SkRect* cullRect) const { - // use bit-or so that we always call both, even if the first one succeeds - return fPE0->filterPath(dst, src, rec, cullRect) | - fPE1->filterPath(dst, src, rec, cullRect); -} - - #ifndef SK_IGNORE_TO_STRING void SkSumPathEffect::toString(SkString* str) const { str->appendf("SkSumPathEffect: ("); @@ -106,3 +205,19 @@ void SkSumPathEffect::toString(SkString* str) const { str->appendf(")"); } #endif + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +sk_sp SkPathEffect::MakeSum(sk_sp first, sk_sp second) { + return SkSumPathEffect::Make(std::move(first), std::move(second)); +} + +sk_sp SkPathEffect::MakeCompose(sk_sp outer, + sk_sp inner) { + return SkComposePathEffect::Make(std::move(outer), std::move(inner)); +} + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkPathEffect) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposePathEffect) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSumPathEffect) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END diff --git a/gfx/skia/skia/src/core/SkPathMeasure.cpp b/gfx/skia/skia/src/core/SkPathMeasure.cpp index 643ffe356857..1660714f516f 100644 --- a/gfx/skia/skia/src/core/SkPathMeasure.cpp +++ b/gfx/skia/skia/src/core/SkPathMeasure.cpp @@ -577,14 +577,11 @@ const SkPathMeasure::Segment* SkPathMeasure::distanceToSegment( SkASSERT(distance >= startD); SkASSERT(seg->fDistance > startD); - *t = startT + SkScalarMulDiv(seg->getScalarT() - startT, - distance - startD, - seg->fDistance - startD); + *t = startT + (seg->getScalarT() - startT) * (distance - startD) / (seg->fDistance - startD); return seg; } -bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos, - SkVector* tangent) { +bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos, SkVector* tangent) { if (nullptr == fPath) { return false; } diff --git a/gfx/skia/skia/src/core/SkPathRef.cpp b/gfx/skia/skia/src/core/SkPathRef.cpp index 2f212cde164a..56e8b9f68365 100644 --- a/gfx/skia/skia/src/core/SkPathRef.cpp +++ b/gfx/skia/skia/src/core/SkPathRef.cpp @@ -12,7 +12,7 @@ #include ////////////////////////////////////////////////////////////////////////////// -SkPathRef::Editor::Editor(SkAutoTUnref* pathRef, +SkPathRef::Editor::Editor(sk_sp* pathRef, int incReserveVerbs, int incReservePoints) { @@ -23,7 +23,7 @@ SkPathRef::Editor::Editor(SkAutoTUnref* pathRef, copy->copy(**pathRef, incReserveVerbs, incReservePoints); pathRef->reset(copy); } - fPathRef = *pathRef; + fPathRef = pathRef->get(); fPathRef->callGenIDChangeListeners(); fPathRef->fGenerationID = 0; SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);) @@ -111,12 +111,12 @@ static void transform_dir_and_start(const SkMatrix& matrix, bool isRRect, bool* } } -void SkPathRef::CreateTransformedCopy(SkAutoTUnref* dst, +void SkPathRef::CreateTransformedCopy(sk_sp* dst, const SkPathRef& src, const SkMatrix& matrix) { SkDEBUGCODE(src.validate();) if (matrix.isIdentity()) { - if (*dst != &src) { + if (dst->get() != &src) { src.ref(); dst->reset(const_cast(&src)); SkDEBUGCODE((*dst)->validate();) @@ -128,7 +128,7 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref* dst, dst->reset(new SkPathRef); } - if (*dst != &src) { + if (dst->get() != &src) { (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count()); sk_careful_memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * sizeof(uint8_t)); @@ -192,12 +192,43 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref* dst, SkDEBUGCODE((*dst)->validate();) } +// Given the verb array, deduce the required number of pts and conics, +// or if an invalid verb is encountered, return false. +static bool deduce_pts_conics(const uint8_t verbs[], int vCount, int* ptCountPtr, + int* conicCountPtr) { + int ptCount = 0; + int conicCount = 0; + for (int i = 0; i < vCount; ++i) { + switch (verbs[i]) { + case SkPath::kMove_Verb: + case SkPath::kLine_Verb: + ptCount += 1; + break; + case SkPath::kConic_Verb: + conicCount += 1; + // fall-through + case SkPath::kQuad_Verb: + ptCount += 2; + break; + case SkPath::kCubic_Verb: + ptCount += 3; + break; + case SkPath::kClose_Verb: + break; + default: + return false; + } + } + *ptCountPtr = ptCount; + *conicCountPtr = conicCount; + return true; +} + SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) { - SkPathRef* ref = new SkPathRef; + std::unique_ptr ref(new SkPathRef); int32_t packed; if (!buffer->readS32(&packed)) { - delete ref; return nullptr; } @@ -205,6 +236,10 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) { uint8_t segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; bool isOval = (packed >> kIsOval_SerializationShift) & 1; bool isRRect = (packed >> kIsRRect_SerializationShift) & 1; + if (isOval && isRRect) { + // Fuzzing generates data with both oval and rrect flags set; abort early in this case/ + return nullptr; + } bool rrectOrOvalIsCCW = (packed >> kRRectOrOvalIsCCW_SerializationShift) & 1; unsigned rrectOrOvalStartIdx = (packed >> kRRectOrOvalStartIdx_SerializationShift) & 0x7; @@ -221,7 +256,6 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) { static_cast(maxPtrDiff) || !buffer->readS32(&conicCount) || conicCount < 0) { - delete ref; return nullptr; } @@ -234,9 +268,23 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) { !buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)) || !buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)) || !buffer->read(&ref->fBounds, sizeof(SkRect))) { - delete ref; return nullptr; } + + // Check that the verbs are valid, and imply the correct number of pts and conics + { + int pCount, cCount; + if (!deduce_pts_conics(ref->verbsMemBegin(), ref->countVerbs(), &pCount, &cCount) || + pCount != ref->countPoints() || cCount != ref->fConicWeights.count()) { + return nullptr; + } + // Check that the bounds match the serialized bounds. + SkRect bounds; + if (ComputePtBounds(&bounds, *ref) != SkToBool(ref->fIsFinite) || bounds != ref->fBounds) { + return nullptr; + } + } + ref->fBoundsIsDirty = false; // resetToSize clears fSegmentMask and fIsOval @@ -245,10 +293,10 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) { ref->fIsRRect = isRRect; ref->fRRectOrOvalIsCCW = rrectOrOvalIsCCW; ref->fRRectOrOvalStartIdx = rrectOrOvalStartIdx; - return ref; + return ref.release(); } -void SkPathRef::Rewind(SkAutoTUnref* pathRef) { +void SkPathRef::Rewind(sk_sp* pathRef) { if ((*pathRef)->unique()) { SkDEBUGCODE((*pathRef)->validate();) (*pathRef)->callGenIDChangeListeners(); diff --git a/gfx/skia/skia/src/core/SkPicture.cpp b/gfx/skia/skia/src/core/SkPicture.cpp index 88da70aacf3b..039efc85c7a1 100644 --- a/gfx/skia/skia/src/core/SkPicture.cpp +++ b/gfx/skia/skia/src/core/SkPicture.cpp @@ -24,31 +24,6 @@ static bool g_AllPictureIOSecurityPrecautionsEnabled = false; DECLARE_SKMESSAGEBUS_MESSAGE(SkPicture::DeletionMessage); -#ifdef SK_SUPPORT_LEGACY_PICTUREINSTALLPIXELREF -class InstallProcImageDeserializer : public SkImageDeserializer { - SkPicture::InstallPixelRefProc fProc; -public: - InstallProcImageDeserializer(SkPicture::InstallPixelRefProc proc) : fProc(proc) {} - - sk_sp makeFromMemory(const void* data, size_t length, const SkIRect* subset) override { - SkBitmap bitmap; - if (fProc(data, length, &bitmap)) { - bitmap.setImmutable(); - return SkImage::MakeFromBitmap(bitmap); - } - return nullptr; - } - sk_sp makeFromData(SkData* data, const SkIRect* subset) override { - return this->makeFromMemory(data->data(), data->size(), subset); - } -}; - -sk_sp SkPicture::MakeFromStream(SkStream* stream, InstallPixelRefProc proc) { - InstallProcImageDeserializer deserializer(proc); - return MakeFromStream(stream, &deserializer); -} -#endif - /* SkPicture impl. This handles generic responsibilities like unique IDs and serialization. */ SkPicture::SkPicture() : fUniqueID(0) {} @@ -196,9 +171,9 @@ sk_sp SkPicture::MakeFromStream(SkStream* stream, SkImageDeserializer if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) { return nullptr; } - SkAutoTDelete data( + std::unique_ptr data( SkPictureData::CreateFromStream(stream, info, factory, typefaces)); - return Forwardport(info, data, nullptr); + return Forwardport(info, data.get(), nullptr); } sk_sp SkPicture::MakeFromBuffer(SkReadBuffer& buffer) { @@ -206,8 +181,8 @@ sk_sp SkPicture::MakeFromBuffer(SkReadBuffer& buffer) { if (!InternalOnly_BufferIsSKP(&buffer, &info) || !buffer.readBool()) { return nullptr; } - SkAutoTDelete data(SkPictureData::CreateFromBuffer(buffer, info)); - return Forwardport(info, data, &buffer); + std::unique_ptr data(SkPictureData::CreateFromBuffer(buffer, info)); + return Forwardport(info, data.get(), &buffer); } SkPictureData* SkPicture::backport() const { @@ -233,7 +208,7 @@ void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer, SkRefCntSet* typefaceSet) const { SkPictInfo info = this->createHeader(); - SkAutoTDelete data(this->backport()); + std::unique_ptr data(this->backport()); stream->write(&info, sizeof(info)); if (data) { @@ -246,7 +221,7 @@ void SkPicture::serialize(SkWStream* stream, void SkPicture::flatten(SkWriteBuffer& buffer) const { SkPictInfo info = this->createHeader(); - SkAutoTDelete data(this->backport()); + std::unique_ptr data(this->backport()); buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic)); buffer.writeUInt(info.getVersion()); diff --git a/gfx/skia/skia/src/core/SkPictureAnalyzer.cpp b/gfx/skia/skia/src/core/SkPictureAnalyzer.cpp index a7a4d94496fa..62c27e15a1a2 100644 --- a/gfx/skia/skia/src/core/SkPictureAnalyzer.cpp +++ b/gfx/skia/skia/src/core/SkPictureAnalyzer.cpp @@ -38,7 +38,7 @@ void SkPictureGpuAnalyzer::analyzePicture(const SkPicture* picture) { fNumSlowPaths += picture->numSlowPaths(); } -void SkPictureGpuAnalyzer::analyzeClipPath(const SkPath& path, SkCanvas::ClipOp op, bool doAntiAlias) { +void SkPictureGpuAnalyzer::analyzeClipPath(const SkPath& path, SkClipOp op, bool doAntiAlias) { const SkRecords::ClipPath clipOp = { SkIRect::MakeEmpty(), // Willie don't care. path, diff --git a/gfx/skia/skia/src/core/SkPictureCommon.h b/gfx/skia/skia/src/core/SkPictureCommon.h index 9b0a2f7c04f1..6f6a9f1fcf81 100644 --- a/gfx/skia/skia/src/core/SkPictureCommon.h +++ b/gfx/skia/skia/src/core/SkPictureCommon.h @@ -4,6 +4,8 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#ifndef SkPictureCommon_DEFINED +#define SkPictureCommon_DEFINED // Some shared code used by both SkBigPicture and SkMiniPicture. // SkTextHunter -- SkRecord visitor that returns true when the op draws text. @@ -119,7 +121,7 @@ struct SkPathCounter { void operator()(const SkRecords::ClipPath& op) { // TODO: does the SkRegion op matter? - if (op.opAA.aa && !op.path.isConvex()) { + if (op.opAA.aa() && !op.path.isConvex()) { fNumSlowPathsAndDashEffects++; } } @@ -138,3 +140,4 @@ struct SkPathCounter { int fNumSlowPathsAndDashEffects; }; +#endif // SkPictureCommon_DEFINED diff --git a/gfx/skia/skia/src/core/SkPictureContentInfo.h b/gfx/skia/skia/src/core/SkPictureContentInfo.h index 81c8a274e33b..36cfa7784f01 100644 --- a/gfx/skia/skia/src/core/SkPictureContentInfo.h +++ b/gfx/skia/skia/src/core/SkPictureContentInfo.h @@ -8,6 +8,7 @@ #ifndef SkPictureContentInfo_DEFINED #define SkPictureContentInfo_DEFINED +#include "SkPaint.h" #include "SkTDArray.h" class GrContext; diff --git a/gfx/skia/skia/src/core/SkPictureData.cpp b/gfx/skia/skia/src/core/SkPictureData.cpp index 68789acddf0f..69ff736fcf86 100644 --- a/gfx/skia/skia/src/core/SkPictureData.cpp +++ b/gfx/skia/skia/src/core/SkPictureData.cpp @@ -4,7 +4,10 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ + #include + +#include "SkAutoMalloc.h" #include "SkImageGenerator.h" #include "SkPictureData.h" #include "SkPictureRecord.h" @@ -84,6 +87,15 @@ SkPictureData::SkPictureData(const SkPictureRecord& record, } } + const SkTDArray& verts = record.getVerticesRefs(); + fVerticesCount = verts.count(); + if (fVerticesCount > 0) { + fVerticesRefs = new const SkVertices* [fVerticesCount]; + for (int i = 0; i < fVerticesCount; ++i) { + fVerticesRefs[i] = SkRef(verts[i]); + } + } + const SkTDArray& imgs = record.getImageRefs(); fImageCount = imgs.count(); if (fImageCount > 0) { @@ -101,6 +113,8 @@ void SkPictureData::init() { fDrawableCount = 0; fTextBlobRefs = nullptr; fTextBlobCount = 0; + fVerticesRefs = nullptr; + fVerticesCount = 0; fImageRefs = nullptr; fImageCount = 0; fFactoryPlayback = nullptr; @@ -125,6 +139,11 @@ SkPictureData::~SkPictureData() { } delete[] fTextBlobRefs; + for (int i = 0; i < fVerticesCount; i++) { + fVerticesRefs[i]->unref(); + } + delete[] fVerticesRefs; + for (int i = 0; i < fImageCount; i++) { fImageRefs[i]->unref(); } @@ -244,6 +263,13 @@ void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const { } } + if (fVerticesCount > 0) { + write_tag_size(buffer, SK_PICT_VERTICES_BUFFER_TAG, fVerticesCount); + for (i = 0; i < fVerticesCount; ++i) { + buffer.writeDataAsByteArray(fVerticesRefs[i]->encode().get()); + } + } + if (fImageCount > 0) { write_tag_size(buffer, SK_PICT_IMAGE_BUFFER_TAG, fImageCount); for (i = 0; i < fImageCount; ++i) { @@ -268,7 +294,7 @@ void SkPictureData::serialize(SkWStream* stream, SkFactorySet factSet; // buffer refs factSet, so factSet must come first. SkBinaryWriteBuffer buffer(SkBinaryWriteBuffer::kCrossProcess_Flag); buffer.setFactoryRecorder(&factSet); - buffer.setPixelSerializer(pixelSerializer); + buffer.setPixelSerializer(sk_ref_sp(pixelSerializer)); buffer.setTypefaceRecorder(typefaceSet); this->flattenToBuffer(buffer); @@ -461,6 +487,10 @@ bool SkPictureData::parseStreamTag(SkStream* stream, static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) { return buffer.readImage().release(); } +static const SkVertices* create_vertices_from_buffer(SkReadBuffer& buffer) { + auto data = buffer.readByteArrayAsData(); + return data ? SkVertices::Decode(data->data(), data->size()).release() : nullptr; +} static const SkImage* create_bitmap_image_from_buffer(SkReadBuffer& buffer) { return buffer.readBitmapAsImage().release(); @@ -485,6 +515,10 @@ bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount, if (0 == inCount) { return true; } + if (!buffer.validate(SkTFitsIn(inCount))) { + return false; + } + *outCount = inCount; *array = new const T* [*outCount]; bool success = true; @@ -519,6 +553,9 @@ bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t } break; case SK_PICT_PAINT_BUFFER_TAG: { + if (!buffer.validate(SkTFitsIn(size))) { + return false; + } const int count = SkToInt(size); fPaints.reset(count); for (int i = 0; i < count; ++i) { @@ -539,6 +576,12 @@ bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t return false; } break; + case SK_PICT_VERTICES_BUFFER_TAG: + if (!new_array_from_buffer(buffer, size, &fVerticesRefs, &fVerticesCount, + create_vertices_from_buffer)) { + return false; + } + break; case SK_PICT_IMAGE_BUFFER_TAG: if (!new_array_from_buffer(buffer, size, &fImageRefs, &fImageCount, create_image_from_buffer)) { @@ -577,7 +620,7 @@ SkPictureData* SkPictureData::CreateFromStream(SkStream* stream, const SkPictInfo& info, SkImageDeserializer* factory, SkTypefacePlayback* topLevelTFPlayback) { - SkAutoTDelete data(new SkPictureData(info)); + std::unique_ptr data(new SkPictureData(info)); if (!topLevelTFPlayback) { topLevelTFPlayback = &data->fTFPlayback; } @@ -590,7 +633,7 @@ SkPictureData* SkPictureData::CreateFromStream(SkStream* stream, SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer, const SkPictInfo& info) { - SkAutoTDelete data(new SkPictureData(info)); + std::unique_ptr data(new SkPictureData(info)); buffer.setVersion(info.getVersion()); if (!data->parseBuffer(buffer)) { diff --git a/gfx/skia/skia/src/core/SkPictureData.h b/gfx/skia/skia/src/core/SkPictureData.h index 332b79963832..37a02373befb 100644 --- a/gfx/skia/skia/src/core/SkPictureData.h +++ b/gfx/skia/skia/src/core/SkPictureData.h @@ -68,6 +68,7 @@ public: #define SK_PICT_PAINT_BUFFER_TAG SkSetFourByteTag('p', 'n', 't', ' ') #define SK_PICT_PATH_BUFFER_TAG SkSetFourByteTag('p', 't', 'h', ' ') #define SK_PICT_TEXTBLOB_BUFFER_TAG SkSetFourByteTag('b', 'l', 'o', 'b') +#define SK_PICT_VERTICES_BUFFER_TAG SkSetFourByteTag('v', 'e', 'r', 't') #define SK_PICT_IMAGE_BUFFER_TAG SkSetFourByteTag('i', 'm', 'a', 'g') // Always write this guy last (with no length field afterwards) @@ -143,6 +144,11 @@ public: return reader->validateIndex(index, fTextBlobCount) ? fTextBlobRefs[index] : nullptr; } + const SkVertices* getVertices(SkReadBuffer* reader) const { + const int index = reader->readInt() - 1; + return reader->validateIndex(index, fVerticesCount) ? fVerticesRefs[index] : nullptr; + } + #if SK_SUPPORT_GPU /** * sampleCount is the number of samples-per-pixel or zero if non-MSAA. @@ -185,6 +191,8 @@ private: int fDrawableCount; const SkTextBlob** fTextBlobRefs; int fTextBlobCount; + const SkVertices** fVerticesRefs; + int fVerticesCount; const SkImage** fImageRefs; int fImageCount; const SkImage** fBitmapImageRefs; diff --git a/gfx/skia/skia/src/core/SkPictureFlat.cpp b/gfx/skia/skia/src/core/SkPictureFlat.cpp index 013bc7f98ea4..6078cb629327 100644 --- a/gfx/skia/skia/src/core/SkPictureFlat.cpp +++ b/gfx/skia/skia/src/core/SkPictureFlat.cpp @@ -13,7 +13,6 @@ #include "SkRasterizer.h" #include "SkShader.h" #include "SkTypeface.h" -#include "SkXfermode.h" /////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/core/SkPictureFlat.h b/gfx/skia/skia/src/core/SkPictureFlat.h index beb2dd8338a8..a1647468f507 100644 --- a/gfx/skia/skia/src/core/SkPictureFlat.h +++ b/gfx/skia/skia/src/core/SkPictureFlat.h @@ -9,7 +9,6 @@ #include "SkCanvas.h" #include "SkChecksum.h" -#include "SkChunkAlloc.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkPaint.h" @@ -52,7 +51,7 @@ enum DrawType { DRAW_TEXT, DRAW_TEXT_ON_PATH, DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT - DRAW_VERTICES, + DRAW_VERTICES_RETIRED_03_2017, RESTORE, ROTATE, SAVE, @@ -94,8 +93,9 @@ enum DrawType { DRAW_IMAGE_LATTICE, DRAW_ARC, DRAW_REGION, + DRAW_VERTICES_OBJECT, - LAST_DRAWTYPE_ENUM = DRAW_REGION + LAST_DRAWTYPE_ENUM = DRAW_VERTICES_OBJECT }; // In the 'match' method, this constant will match any flavor of DRAW_BITMAP* @@ -128,13 +128,22 @@ enum SaveLayerRecFlatFlags { // clipparams are packed in 5 bits // doAA:1 | clipOp:4 -static inline uint32_t ClipParams_pack(SkCanvas::ClipOp op, bool doAA) { +static inline uint32_t ClipParams_pack(SkClipOp op, bool doAA) { unsigned doAABit = doAA ? 1 : 0; - return (doAABit << 4) | op; + return (doAABit << 4) | static_cast(op); } -static inline SkCanvas::ClipOp ClipParams_unpackRegionOp(uint32_t packed) { - return (SkCanvas::ClipOp)(packed & 0xF); +template T asValidEnum(SkReadBuffer* buffer, uint32_t candidate) { + + if (buffer->validate(candidate <= static_cast(T::kMax_EnumValue))) { + return static_cast(candidate); + } + + return T::kMax_EnumValue; +} + +static inline SkClipOp ClipParams_unpackRegionOp(SkReadBuffer* buffer, uint32_t packed) { + return asValidEnum(buffer, packed & 0xF); } static inline bool ClipParams_unpackDoAA(uint32_t packed) { diff --git a/gfx/skia/skia/src/core/SkPictureImageGenerator.cpp b/gfx/skia/skia/src/core/SkPictureImageGenerator.cpp index 6f4ffa1f5bb9..a1d919af3454 100644 --- a/gfx/skia/skia/src/core/SkPictureImageGenerator.cpp +++ b/gfx/skia/skia/src/core/SkPictureImageGenerator.cpp @@ -6,52 +6,45 @@ */ #include "SkImage_Base.h" -#include "SkImageGenerator.h" #include "SkCanvas.h" +#include "SkMakeUnique.h" #include "SkMatrix.h" #include "SkPaint.h" #include "SkPicture.h" +#include "SkPictureImageGenerator.h" #include "SkSurface.h" -#include "SkTLazy.h" -class SkPictureImageGenerator : SkImageGenerator { -public: - static SkImageGenerator* Create(const SkISize&, const SkPicture*, const SkMatrix*, - const SkPaint*); - -protected: - bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], - int* ctableCount) override; - bool onComputeScaledDimensions(SkScalar scale, SupportedSizes*) override; - bool onGenerateScaledPixels(const SkISize&, const SkIPoint&, const SkPixmap&) override; - -#if SK_SUPPORT_GPU - GrTexture* onGenerateTexture(GrContext*, const SkIRect*) override; -#endif - -private: - SkPictureImageGenerator(const SkISize&, const SkPicture*, const SkMatrix*, const SkPaint*); - - SkAutoTUnref fPicture; - SkMatrix fMatrix; - SkTLazy fPaint; - - typedef SkImageGenerator INHERITED; -}; - -SkImageGenerator* SkPictureImageGenerator::Create(const SkISize& size, const SkPicture* picture, - const SkMatrix* matrix, const SkPaint* paint) { +std::unique_ptr +SkPictureImageGenerator::Make(const SkISize& size, sk_sp picture, const SkMatrix* matrix, + const SkPaint* paint, SkImage::BitDepth bitDepth, + sk_sp colorSpace) { if (!picture || size.isEmpty()) { return nullptr; } - return new SkPictureImageGenerator(size, picture, matrix, paint); + if (SkImage::BitDepth::kF16 == bitDepth && (!colorSpace || !colorSpace->gammaIsLinear())) { + return nullptr; + } + + if (colorSpace && (!colorSpace->gammaCloseToSRGB() && !colorSpace->gammaIsLinear())) { + return nullptr; + } + + SkColorType colorType = kN32_SkColorType; + if (SkImage::BitDepth::kF16 == bitDepth) { + colorType = kRGBA_F16_SkColorType; + } + + SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, + kPremul_SkAlphaType, std::move(colorSpace)); + return std::unique_ptr( + new SkPictureImageGenerator(info, std::move(picture), matrix, paint)); } -SkPictureImageGenerator::SkPictureImageGenerator(const SkISize& size, const SkPicture* picture, +SkPictureImageGenerator::SkPictureImageGenerator(const SkImageInfo& info, sk_sp picture, const SkMatrix* matrix, const SkPaint* paint) - : INHERITED(SkImageInfo::MakeN32Premul(size)) - , fPicture(SkRef(picture)) { + : INHERITED(info) + , fPicture(std::move(picture)) { if (matrix) { fMatrix = *matrix; @@ -66,7 +59,7 @@ SkPictureImageGenerator::SkPictureImageGenerator(const SkISize& size, const SkPi bool SkPictureImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) { - if (info != getInfo() || ctable || ctableCount) { + if (ctable || ctableCount) { return false; } @@ -77,83 +70,51 @@ bool SkPictureImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, bitmap.eraseColor(SK_ColorTRANSPARENT); SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); - canvas.drawPicture(fPicture, &fMatrix, fPaint.getMaybeNull()); + canvas.drawPicture(fPicture.get(), &fMatrix, fPaint.getMaybeNull()); return true; } -bool SkPictureImageGenerator::onComputeScaledDimensions(SkScalar scale, - SupportedSizes* sizes) { - SkASSERT(scale > 0 && scale <= 1); - const int w = this->getInfo().width(); - const int h = this->getInfo().height(); - const int sw = SkScalarRoundToInt(scale * w); - const int sh = SkScalarRoundToInt(scale * h); - if (sw > 0 && sh > 0) { - sizes->fSizes[0].set(sw, sh); - sizes->fSizes[1].set(sw, sh); - return true; - } - return false; -} - -bool SkPictureImageGenerator::onGenerateScaledPixels(const SkISize& scaledSize, - const SkIPoint& scaledOrigin, - const SkPixmap& scaledPixels) { - int w = scaledSize.width(); - int h = scaledSize.height(); - - const SkScalar scaleX = SkIntToScalar(w) / this->getInfo().width(); - const SkScalar scaleY = SkIntToScalar(h) / this->getInfo().height(); - SkMatrix matrix = SkMatrix::MakeScale(scaleX, scaleY); - matrix.postTranslate(-SkIntToScalar(scaledOrigin.x()), -SkIntToScalar(scaledOrigin.y())); - - SkBitmap bitmap; - if (!bitmap.installPixels(scaledPixels)) { - return false; - } - - bitmap.eraseColor(SK_ColorTRANSPARENT); - SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); - matrix.preConcat(fMatrix); - canvas.drawPicture(fPicture, &matrix, fPaint.getMaybeNull()); - return true; -} - /////////////////////////////////////////////////////////////////////////////////////////////////// -SkImageGenerator* SkImageGenerator::NewFromPicture(const SkISize& size, const SkPicture* picture, - const SkMatrix* matrix, const SkPaint* paint) { - return SkPictureImageGenerator::Create(size, picture, matrix, paint); +std::unique_ptr +SkImageGenerator::MakeFromPicture(const SkISize& size, sk_sp picture, + const SkMatrix* matrix, const SkPaint* paint, + SkImage::BitDepth bitDepth, sk_sp colorSpace) { + // Check this here (rather than in SkPictureImageGenerator::Create) so SkPictureShader + // has a private entry point to create legacy picture backed images. + if (!colorSpace) { + return nullptr; + } + + return SkPictureImageGenerator::Make(size, std::move(picture), matrix, paint, bitDepth, + std::move(colorSpace)); } /////////////////////////////////////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU -#include "GrTexture.h" - -GrTexture* SkPictureImageGenerator::onGenerateTexture(GrContext* ctx, const SkIRect* subset) { - const SkImageInfo& info = this->getInfo(); - SkImageInfo surfaceInfo = subset ? info.makeWH(subset->width(), subset->height()) : info; +sk_sp SkPictureImageGenerator::onGenerateTexture(GrContext* ctx, + const SkImageInfo& info, + const SkIPoint& origin) { + SkASSERT(ctx); // // TODO: respect the usage, by possibly creating a different (pow2) surface // - sk_sp surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, surfaceInfo)); + sk_sp surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, info)); if (!surface) { return nullptr; } SkMatrix matrix = fMatrix; - if (subset) { - matrix.postTranslate(-subset->x(), -subset->y()); - } + matrix.postTranslate(-origin.x(), -origin.y()); surface->getCanvas()->clear(0); // does NewRenderTarget promise to do this for us? - surface->getCanvas()->drawPicture(fPicture, &matrix, fPaint.getMaybeNull()); + surface->getCanvas()->drawPicture(fPicture.get(), &matrix, fPaint.getMaybeNull()); sk_sp image(surface->makeImageSnapshot()); if (!image) { return nullptr; } - return SkSafeRef(as_IB(image)->peekTexture()); + return as_IB(image)->asTextureProxyRef(); } #endif diff --git a/gfx/skia/skia/src/core/SkPictureImageGenerator.h b/gfx/skia/skia/src/core/SkPictureImageGenerator.h new file mode 100644 index 000000000000..83872608a56b --- /dev/null +++ b/gfx/skia/skia/src/core/SkPictureImageGenerator.h @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkPictureImageGenerator_DEFINED +#define SkPictureImageGenerator_DEFINED + +#include "SkImageGenerator.h" +#include "SkTLazy.h" + +class SkPictureImageGenerator : public SkImageGenerator { +public: + static std::unique_ptr Make(const SkISize&, sk_sp, const SkMatrix*, + const SkPaint*, SkImage::BitDepth, + sk_sp); + +protected: + bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], + int* ctableCount) override; + +#if SK_SUPPORT_GPU + sk_sp onGenerateTexture(GrContext*, const SkImageInfo&, + const SkIPoint&) override; +#endif + +private: + SkPictureImageGenerator(const SkImageInfo& info, sk_sp, const SkMatrix*, + const SkPaint*); + + sk_sp fPicture; + SkMatrix fMatrix; + SkTLazy fPaint; + + typedef SkImageGenerator INHERITED; +}; +#endif // SkPictureImageGenerator_DEFINED diff --git a/gfx/skia/skia/src/core/SkPicturePlayback.cpp b/gfx/skia/skia/src/core/SkPicturePlayback.cpp index a246a306e6b1..51a3da9b0d84 100644 --- a/gfx/skia/skia/src/core/SkPicturePlayback.cpp +++ b/gfx/skia/skia/src/core/SkPicturePlayback.cpp @@ -86,7 +86,7 @@ void SkPicturePlayback::draw(SkCanvas* canvas, AutoResetOpID aroi(this); SkASSERT(0 == fCurOffset); - SkAutoTDelete reader; + std::unique_ptr reader; if (buffer) { reader.reset(buffer->clone(fPictureData->opData()->bytes(), fPictureData->opData()->size())); @@ -107,12 +107,12 @@ void SkPicturePlayback::draw(SkCanvas* canvas, fCurOffset = reader->offset(); uint32_t size; - DrawType op = ReadOpAndSize(reader, &size); + DrawType op = ReadOpAndSize(reader.get(), &size); if (!reader->validate(op > UNUSED && op <= LAST_DRAWTYPE_ENUM)) { return; } - this->handleOp(reader, op, size, canvas, initialMatrix); + this->handleOp(reader.get(), op, size, canvas, initialMatrix); } // need to propagate invalid state to the parent reader @@ -126,6 +126,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, uint32_t size, SkCanvas* canvas, const SkMatrix& initialMatrix) { +#define BREAK_ON_READ_ERROR(r) if (!r->isValid()) { break; } + switch (op) { case NOOP: { SkASSERT(size >= 4); @@ -134,9 +136,11 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, case CLIP_PATH: { const SkPath& path = fPictureData->getPath(reader); uint32_t packed = reader->readInt(); - SkCanvas::ClipOp clipOp = ClipParams_unpackRegionOp(packed); + SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed); bool doAA = ClipParams_unpackDoAA(packed); size_t offsetToRestore = reader->readInt(); + BREAK_ON_READ_ERROR(reader); + SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset()); canvas->clipPath(path, clipOp, doAA); if (canvas->isClipEmpty() && offsetToRestore) { @@ -147,8 +151,10 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, SkRegion region; reader->readRegion(®ion); uint32_t packed = reader->readInt(); - SkCanvas::ClipOp clipOp = ClipParams_unpackRegionOp(packed); + SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed); size_t offsetToRestore = reader->readInt(); + BREAK_ON_READ_ERROR(reader); + SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset()); canvas->clipRegion(region, clipOp); if (canvas->isClipEmpty() && offsetToRestore) { @@ -159,9 +165,11 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, SkRect rect; reader->readRect(&rect); uint32_t packed = reader->readInt(); - SkCanvas::ClipOp clipOp = ClipParams_unpackRegionOp(packed); + SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed); bool doAA = ClipParams_unpackDoAA(packed); size_t offsetToRestore = reader->readInt(); + BREAK_ON_READ_ERROR(reader); + SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset()); canvas->clipRect(rect, clipOp, doAA); if (canvas->isClipEmpty() && offsetToRestore) { @@ -172,9 +180,11 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, SkRRect rrect; reader->readRRect(&rrect); uint32_t packed = reader->readInt(); - SkCanvas::ClipOp clipOp = ClipParams_unpackRegionOp(packed); + SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed); bool doAA = ClipParams_unpackDoAA(packed); size_t offsetToRestore = reader->readInt(); + BREAK_ON_READ_ERROR(reader); + SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset()); canvas->clipRRect(rrect, clipOp, doAA); if (canvas->isClipEmpty() && offsetToRestore) { @@ -186,6 +196,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, case CONCAT: { SkMatrix matrix; reader->readMatrix(&matrix); + BREAK_ON_READ_ERROR(reader); + canvas->concat(matrix); break; } @@ -194,7 +206,10 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, reader->readRect(&rect); SkString key; reader->readString(&key); - canvas->drawAnnotation(rect, key.c_str(), reader->readByteArrayAsData().get()); + sk_sp data = reader->readByteArrayAsData(); + BREAK_ON_READ_ERROR(reader); + + canvas->drawAnnotation(rect, key.c_str(), data.get()); } break; case DRAW_ARC: { const SkPaint* paint = fPictureData->getPaint(reader); @@ -203,6 +218,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, SkScalar startAngle = reader->readScalar(); SkScalar sweepAngle = reader->readScalar(); int useCenter = reader->readInt(); + BREAK_ON_READ_ERROR(reader); + if (paint) { canvas->drawArc(rect, startAngle, sweepAngle, SkToBool(useCenter), *paint); } @@ -215,15 +232,17 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkRSXform* xform = (const SkRSXform*)reader->skip(count * sizeof(SkRSXform)); const SkRect* tex = (const SkRect*)reader->skip(count * sizeof(SkRect)); const SkColor* colors = nullptr; - SkXfermode::Mode mode = SkXfermode::kDst_Mode; + SkBlendMode mode = SkBlendMode::kDst; if (flags & DRAW_ATLAS_HAS_COLORS) { colors = (const SkColor*)reader->skip(count * sizeof(SkColor)); - mode = (SkXfermode::Mode)reader->readUInt(); + mode = (SkBlendMode)reader->readUInt(); } const SkRect* cull = nullptr; if (flags & DRAW_ATLAS_HAS_CULL) { cull = (const SkRect*)reader->skip(sizeof(SkRect)); } + BREAK_ON_READ_ERROR(reader); + canvas->drawAtlas(atlas, xform, tex, colors, count, mode, cull, paint); } break; case DRAW_BITMAP: { @@ -231,6 +250,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkImage* image = fPictureData->getBitmapAsImage(reader); SkPoint loc; reader->readPoint(&loc); + BREAK_ON_READ_ERROR(reader); + canvas->drawImage(image, loc.fX, loc.fY, paint); } break; case DRAW_BITMAP_RECT: { @@ -241,6 +262,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, SkRect dst; reader->readRect(&dst); // required SkCanvas::SrcRectConstraint constraint = (SkCanvas::SrcRectConstraint)reader->readInt(); + BREAK_ON_READ_ERROR(reader); + if (src) { canvas->drawImageRect(image, *src, dst, paint, constraint); } else { @@ -252,6 +275,7 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkImage* image = fPictureData->getBitmapAsImage(reader); SkMatrix matrix; reader->readMatrix(&matrix); + BREAK_ON_READ_ERROR(reader); SkAutoCanvasRestore acr(canvas, true); canvas->concat(matrix); @@ -264,24 +288,34 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, reader->readIRect(&src); SkRect dst; reader->readRect(&dst); + BREAK_ON_READ_ERROR(reader); + canvas->drawImageNine(image, src, dst, paint); } break; - case DRAW_CLEAR: - canvas->clear(reader->readInt()); - break; + case DRAW_CLEAR: { + auto c = reader->readInt(); + BREAK_ON_READ_ERROR(reader); + + canvas->clear(c); + } break; case DRAW_DATA: { // This opcode is now dead, just need to skip it for backwards compatibility size_t length = reader->readInt(); (void)reader->skip(length); // skip handles padding the read out to a multiple of 4 } break; - case DRAW_DRAWABLE: - canvas->drawDrawable(fPictureData->getDrawable(reader)); - break; + case DRAW_DRAWABLE: { + auto* d = fPictureData->getDrawable(reader); + BREAK_ON_READ_ERROR(reader); + + canvas->drawDrawable(d); + } break; case DRAW_DRAWABLE_MATRIX: { SkMatrix matrix; reader->readMatrix(&matrix); SkDrawable* drawable = fPictureData->getDrawable(reader); + BREAK_ON_READ_ERROR(reader); + canvas->drawDrawable(drawable, &matrix); } break; case DRAW_DRRECT: { @@ -289,6 +323,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, SkRRect outer, inner; reader->readRRect(&outer); reader->readRRect(&inner); + BREAK_ON_READ_ERROR(reader); + if (paint) { canvas->drawDRRect(outer, inner, *paint); } @@ -314,6 +350,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkImage* image = fPictureData->getImage(reader); SkPoint loc; reader->readPoint(&loc); + BREAK_ON_READ_ERROR(reader); + canvas->drawImage(image, loc.fX, loc.fY, paint); } break; case DRAW_IMAGE_LATTICE: { @@ -332,6 +370,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, lattice.fBounds = &src; SkRect dst; reader->readRect(&dst); + BREAK_ON_READ_ERROR(reader); + canvas->drawImageLattice(image, lattice, dst, paint); } break; case DRAW_IMAGE_NINE: { @@ -341,6 +381,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, reader->readIRect(¢er); SkRect dst; reader->readRect(&dst); + BREAK_ON_READ_ERROR(reader); + canvas->drawImageNine(image, center, dst, paint); } break; case DRAW_IMAGE_RECT_STRICT: @@ -357,18 +399,24 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, // newer op-code stores the constraint explicitly constraint = (SkCanvas::SrcRectConstraint)reader->readInt(); } + BREAK_ON_READ_ERROR(reader); + canvas->legacy_drawImageRect(image, src, dst, paint, constraint); } break; case DRAW_OVAL: { const SkPaint* paint = fPictureData->getPaint(reader); SkRect rect; reader->readRect(&rect); + BREAK_ON_READ_ERROR(reader); + if (paint) { canvas->drawOval(rect, *paint); } } break; case DRAW_PAINT: { const SkPaint* paint = fPictureData->getPaint(reader); + BREAK_ON_READ_ERROR(reader); + if (paint) { canvas->drawPaint(*paint); } @@ -388,32 +436,41 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, texCoords = (const SkPoint*)reader->skip(SkPatchUtils::kNumCorners * sizeof(SkPoint)); } - sk_sp xfer; + SkBlendMode bmode = SkBlendMode::kModulate; if (flag & DRAW_VERTICES_HAS_XFER) { - int mode = reader->readInt(); - if (mode < 0 || mode > SkXfermode::kLastMode) { - mode = SkXfermode::kModulate_Mode; + unsigned mode = reader->readInt(); + if (mode <= (unsigned)SkBlendMode::kLastMode) { + bmode = (SkBlendMode)mode; } - xfer = SkXfermode::Make((SkXfermode::Mode)mode); } + BREAK_ON_READ_ERROR(reader); + if (paint) { - canvas->drawPatch(cubics, colors, texCoords, std::move(xfer), *paint); + canvas->drawPatch(cubics, colors, texCoords, bmode, *paint); } } break; case DRAW_PATH: { const SkPaint* paint = fPictureData->getPaint(reader); + const auto& path = fPictureData->getPath(reader); + BREAK_ON_READ_ERROR(reader); + if (paint) { - canvas->drawPath(fPictureData->getPath(reader), *paint); + canvas->drawPath(path, *paint); } } break; - case DRAW_PICTURE: - canvas->drawPicture(fPictureData->getPicture(reader)); - break; + case DRAW_PICTURE: { + const auto* pic = fPictureData->getPicture(reader); + BREAK_ON_READ_ERROR(reader); + + canvas->drawPicture(pic); + } break; case DRAW_PICTURE_MATRIX_PAINT: { const SkPaint* paint = fPictureData->getPaint(reader); SkMatrix matrix; reader->readMatrix(&matrix); const SkPicture* pic = fPictureData->getPicture(reader); + BREAK_ON_READ_ERROR(reader); + canvas->drawPicture(pic, &matrix, paint); } break; case DRAW_POINTS: { @@ -421,6 +478,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, SkCanvas::PointMode mode = (SkCanvas::PointMode)reader->readInt(); size_t count = reader->readInt(); const SkPoint* pts = (const SkPoint*)reader->skip(sizeof(SkPoint)* count); + BREAK_ON_READ_ERROR(reader); + if (paint) { canvas->drawPoints(mode, count, pts, *paint); } @@ -431,6 +490,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, get_text(reader, &text); size_t points = reader->readInt(); const SkPoint* pos = (const SkPoint*)reader->skip(points * sizeof(SkPoint)); + BREAK_ON_READ_ERROR(reader); + if (paint && text.text()) { canvas->drawPosText(text.text(), text.length(), pos, *paint); } @@ -443,8 +504,9 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkPoint* pos = (const SkPoint*)reader->skip(points * sizeof(SkPoint)); const SkScalar top = reader->readScalar(); const SkScalar bottom = reader->readScalar(); - SkRect clip; - canvas->getClipBounds(&clip); + BREAK_ON_READ_ERROR(reader); + + SkRect clip = canvas->getLocalClipBounds(); if (top < clip.fBottom && bottom > clip.fTop && paint && text.text()) { canvas->drawPosText(text.text(), text.length(), pos, *paint); } @@ -456,6 +518,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, size_t xCount = reader->readInt(); const SkScalar constY = reader->readScalar(); const SkScalar* xpos = (const SkScalar*)reader->skip(xCount * sizeof(SkScalar)); + BREAK_ON_READ_ERROR(reader); + if (paint && text.text()) { canvas->drawPosTextH(text.text(), text.length(), xpos, constY, *paint); } @@ -466,11 +530,12 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, get_text(reader, &text); size_t xCount = reader->readInt(); const SkScalar* xpos = (const SkScalar*)reader->skip((3 + xCount) * sizeof(SkScalar)); + BREAK_ON_READ_ERROR(reader); + const SkScalar top = *xpos++; const SkScalar bottom = *xpos++; const SkScalar constY = *xpos++; - SkRect clip; - canvas->getClipBounds(&clip); + SkRect clip = canvas->getLocalClipBounds(); if (top < clip.fBottom && bottom > clip.fTop && paint && text.text()) { canvas->drawPosTextH(text.text(), text.length(), xpos, constY, *paint); } @@ -479,6 +544,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkPaint* paint = fPictureData->getPaint(reader); SkRect rect; reader->readRect(&rect); + BREAK_ON_READ_ERROR(reader); + if (paint) { canvas->drawRect(rect, *paint); } @@ -487,6 +554,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkPaint* paint = fPictureData->getPaint(reader); SkRegion region; reader->readRegion(®ion); + BREAK_ON_READ_ERROR(reader); + if (paint) { canvas->drawRegion(region, *paint); } @@ -495,6 +564,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkPaint* paint = fPictureData->getPaint(reader); SkRRect rrect; reader->readRRect(&rrect); + BREAK_ON_READ_ERROR(reader); + if (paint) { canvas->drawRRect(rrect, *paint); } @@ -512,6 +583,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, get_text(reader, &text); SkScalar x = reader->readScalar(); SkScalar y = reader->readScalar(); + BREAK_ON_READ_ERROR(reader); + if (paint && text.text()) { canvas->drawText(text.text(), text.length(), x, y, *paint); } @@ -521,6 +594,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkTextBlob* blob = fPictureData->getTextBlob(reader); SkScalar x = reader->readScalar(); SkScalar y = reader->readScalar(); + BREAK_ON_READ_ERROR(reader); + if (paint) { canvas->drawTextBlob(blob, x, y, *paint); } @@ -530,12 +605,13 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, TextContainer text; get_text(reader, &text); const SkScalar* ptr = (const SkScalar*)reader->skip(4 * sizeof(SkScalar)); + BREAK_ON_READ_ERROR(reader); + // ptr[0] == x // ptr[1] == y // ptr[2] == top // ptr[3] == bottom - SkRect clip; - canvas->getClipBounds(&clip); + SkRect clip = canvas->getLocalClipBounds(); float top = ptr[2]; float bottom = ptr[3]; if (top < clip.fBottom && bottom > clip.fTop && paint && text.text()) { @@ -549,6 +625,8 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkPath& path = fPictureData->getPath(reader); SkMatrix matrix; reader->readMatrix(&matrix); + BREAK_ON_READ_ERROR(reader); + if (paint && text.text()) { canvas->drawTextOnPath(text.text(), text.length(), path, &matrix, *paint); } @@ -564,15 +642,16 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, if (flags & DRAW_TEXT_RSXFORM_HAS_CULL) { cull = (const SkRect*)reader->skip(sizeof(SkRect)); } + BREAK_ON_READ_ERROR(reader); + if (text.text()) { canvas->drawTextRSXform(text.text(), text.length(), xform, cull, *paint); } } break; - case DRAW_VERTICES: { - sk_sp xfer; + case DRAW_VERTICES_RETIRED_03_2017: { const SkPaint* paint = fPictureData->getPaint(reader); DrawVertexFlags flags = (DrawVertexFlags)reader->readInt(); - SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader->readInt(); + SkVertices::VertexMode vmode = (SkVertices::VertexMode)reader->readInt(); int vCount = reader->readInt(); const SkPoint* verts = (const SkPoint*)reader->skip(vCount * sizeof(SkPoint)); const SkPoint* texs = nullptr; @@ -589,31 +668,41 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, iCount = reader->readInt(); indices = (const uint16_t*)reader->skip(iCount * sizeof(uint16_t)); } + SkBlendMode bmode = SkBlendMode::kModulate; if (flags & DRAW_VERTICES_HAS_XFER) { - int mode = reader->readInt(); - if (mode < 0 || mode > SkXfermode::kLastMode) { - mode = SkXfermode::kModulate_Mode; + unsigned mode = reader->readInt(); + if (mode <= (unsigned)SkBlendMode::kLastMode) { + bmode = (SkBlendMode)mode; } - xfer = SkXfermode::Make((SkXfermode::Mode)mode); } + BREAK_ON_READ_ERROR(reader); + if (paint) { - canvas->drawVertices(vmode, vCount, verts, texs, colors, - xfer, indices, iCount, *paint); + canvas->drawVertices(SkVertices::MakeCopy(vmode, vCount, verts, texs, colors, + iCount, indices), bmode, *paint); + } + } break; + case DRAW_VERTICES_OBJECT: { + const SkPaint* paint = fPictureData->getPaint(reader); + const SkVertices* vertices = fPictureData->getVertices(reader); + SkBlendMode bmode = static_cast(reader->readInt()); + + BREAK_ON_READ_ERROR(reader); + + if (paint && vertices) { + canvas->drawVertices(vertices, bmode, *paint); } } break; case RESTORE: canvas->restore(); break; - case ROTATE: - canvas->rotate(reader->readScalar()); - break; + case ROTATE: { + auto deg = reader->readScalar(); + BREAK_ON_READ_ERROR(reader); + + canvas->rotate(deg); + } break; case SAVE: - // SKPs with version < 29 also store a SaveFlags param. - if (size > 4) { - if (reader->validate(8 == size)) { - reader->readInt(); - } - } canvas->save(); break; case SAVE_LAYER_SAVEFLAGS_DEPRECATED: { @@ -621,13 +710,18 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, const SkRect* boundsPtr = get_rect_ptr(reader, &storage); const SkPaint* paint = fPictureData->getPaint(reader); auto flags = SkCanvas::LegacySaveFlagsToSaveLayerFlags(reader->readInt()); + BREAK_ON_READ_ERROR(reader); + canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, flags)); } break; case SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016: { SkRect storage; const SkRect* boundsPtr = get_rect_ptr(reader, &storage); const SkPaint* paint = fPictureData->getPaint(reader); - canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, reader->readInt())); + auto flags = reader->readInt(); + BREAK_ON_READ_ERROR(reader); + + canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, flags)); } break; case SAVE_LAYER_SAVELAYERREC: { SkCanvas::SaveLayerRec rec(nullptr, nullptr, nullptr, 0); @@ -641,42 +735,57 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, rec.fPaint = fPictureData->getPaint(reader); } if (flatFlags & SAVELAYERREC_HAS_BACKDROP) { - const SkPaint* paint = fPictureData->getPaint(reader); - rec.fBackdrop = paint->getImageFilter(); + if (const auto* paint = fPictureData->getPaint(reader)) { + rec.fBackdrop = paint->getImageFilter(); + } } if (flatFlags & SAVELAYERREC_HAS_FLAGS) { rec.fSaveLayerFlags = reader->readInt(); } + BREAK_ON_READ_ERROR(reader); + canvas->saveLayer(rec); } break; case SCALE: { SkScalar sx = reader->readScalar(); SkScalar sy = reader->readScalar(); + BREAK_ON_READ_ERROR(reader); + canvas->scale(sx, sy); } break; case SET_MATRIX: { SkMatrix matrix; reader->readMatrix(&matrix); + BREAK_ON_READ_ERROR(reader); + matrix.postConcat(initialMatrix); canvas->setMatrix(matrix); } break; case SKEW: { SkScalar sx = reader->readScalar(); SkScalar sy = reader->readScalar(); + BREAK_ON_READ_ERROR(reader); + canvas->skew(sx, sy); } break; case TRANSLATE: { SkScalar dx = reader->readScalar(); SkScalar dy = reader->readScalar(); + BREAK_ON_READ_ERROR(reader); + canvas->translate(dx, dy); } break; case TRANSLATE_Z: { #ifdef SK_EXPERIMENTAL_SHADOWING SkScalar dz = reader->readScalar(); + BREAK_ON_READ_ERROR(reader); + canvas->translateZ(dz); #endif } break; default: SkASSERTF(false, "Unknown draw type: %d", op); } + +#undef BREAK_ON_READ_ERROR } diff --git a/gfx/skia/skia/src/core/SkPictureRecord.cpp b/gfx/skia/skia/src/core/SkPictureRecord.cpp index 6325edae00e7..9bdb6c5cc49e 100644 --- a/gfx/skia/skia/src/core/SkPictureRecord.cpp +++ b/gfx/skia/skia/src/core/SkPictureRecord.cpp @@ -13,6 +13,7 @@ #include "SkRSXform.h" #include "SkTextBlob.h" #include "SkTSearch.h" +#include "SkClipOpPriv.h" #define HEAP_BLOCK_SIZE 4096 @@ -35,6 +36,7 @@ SkPictureRecord::~SkPictureRecord() { fPictureRefs.unrefAll(); fDrawableRefs.unrefAll(); fTextBlobRefs.unrefAll(); + fVerticesRefs.unrefAll(); } /////////////////////////////////////////////////////////////////////////////// @@ -108,7 +110,7 @@ void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) { if (flatFlags & SAVELAYERREC_HAS_BACKDROP) { // overkill, but we didn't already track single flattenables, so using a paint for that SkPaint paint; - paint.setImageFilter(const_cast(rec.fBackdrop)); + paint.setImageFilter(sk_ref_sp(const_cast(rec.fBackdrop))); this->addPaint(paint); } if (flatFlags & SAVELAYERREC_HAS_FLAGS) { @@ -230,18 +232,18 @@ void SkPictureRecord::didTranslateZ(SkScalar z) { #endif } -static bool clipOpExpands(SkCanvas::ClipOp op) { +static bool clipOpExpands(SkClipOp op) { switch (op) { - case SkCanvas::kUnion_Op: - case SkCanvas::kXOR_Op: - case SkCanvas::kReverseDifference_Op: - case SkCanvas::kReplace_Op: + case kUnion_SkClipOp: + case kXOR_SkClipOp: + case kReverseDifference_SkClipOp: + case kReplace_SkClipOp: return true; - case SkCanvas::kIntersect_Op: - case SkCanvas::kDifference_Op: + case kIntersect_SkClipOp: + case kDifference_SkClipOp: return false; default: - SkDEBUGFAIL("unknown region op"); + SkDEBUGFAIL("unknown clipop"); return false; } } @@ -279,7 +281,7 @@ void SkPictureRecord::endRecording() { this->restoreToCount(fInitialSaveCount); } -size_t SkPictureRecord::recordRestoreOffsetPlaceholder(ClipOp op) { +size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkClipOp op) { if (fRestoreOffsetStack.isEmpty()) { return -1; } @@ -309,12 +311,12 @@ size_t SkPictureRecord::recordRestoreOffsetPlaceholder(ClipOp op) { return offset; } -void SkPictureRecord::onClipRect(const SkRect& rect, SkCanvas::ClipOp op, ClipEdgeStyle edgeStyle) { +void SkPictureRecord::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle); this->INHERITED::onClipRect(rect, op, edgeStyle); } -size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkCanvas::ClipOp op, bool doAA) { +size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkClipOp op, bool doAA) { // id + rect + clip params size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size; // recordRestoreOffsetPlaceholder doesn't always write an offset @@ -331,12 +333,12 @@ size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkCanvas::ClipOp op, return offset; } -void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkCanvas::ClipOp op, ClipEdgeStyle edgeStyle) { +void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle); this->INHERITED::onClipRRect(rrect, op, edgeStyle); } -size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkCanvas::ClipOp op, bool doAA) { +size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) { // op + rrect + clip params size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size; // recordRestoreOffsetPlaceholder doesn't always write an offset @@ -352,13 +354,13 @@ size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkCanvas::ClipOp o return offset; } -void SkPictureRecord::onClipPath(const SkPath& path, SkCanvas::ClipOp op, ClipEdgeStyle edgeStyle) { +void SkPictureRecord::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { int pathID = this->addPathToHeap(path); this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle); this->INHERITED::onClipPath(path, op, edgeStyle); } -size_t SkPictureRecord::recordClipPath(int pathID, SkCanvas::ClipOp op, bool doAA) { +size_t SkPictureRecord::recordClipPath(int pathID, SkClipOp op, bool doAA) { // op + path index + clip params size_t size = 3 * kUInt32Size; // recordRestoreOffsetPlaceholder doesn't always write an offset @@ -374,12 +376,12 @@ size_t SkPictureRecord::recordClipPath(int pathID, SkCanvas::ClipOp op, bool doA return offset; } -void SkPictureRecord::onClipRegion(const SkRegion& region, ClipOp op) { +void SkPictureRecord::onClipRegion(const SkRegion& region, SkClipOp op) { this->recordClipRegion(region, op); this->INHERITED::onClipRegion(region, op); } -size_t SkPictureRecord::recordClipRegion(const SkRegion& region, ClipOp op) { +size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkClipOp op) { // op + clip params + region size_t size = 2 * kUInt32Size + region.writeToMemory(nullptr); // recordRestoreOffsetPlaceholder doesn't always write an offset @@ -720,70 +722,21 @@ void SkPictureRecord::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matri this->validate(initialOffset, size); } -void SkPictureRecord::onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xfer, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { - uint32_t flags = 0; - if (texs) { - flags |= DRAW_VERTICES_HAS_TEXS; - } - if (colors) { - flags |= DRAW_VERTICES_HAS_COLORS; - } - if (indexCount > 0) { - flags |= DRAW_VERTICES_HAS_INDICES; - } - if (xfer) { - SkXfermode::Mode mode; - if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) { - flags |= DRAW_VERTICES_HAS_XFER; - } - } +void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode, + const SkPaint& paint) { + // op + paint index + vertices index + mode + size_t size = 4 * kUInt32Size; + size_t initialOffset = this->addDraw(DRAW_VERTICES_OBJECT, &size); - // op + paint index + flags + vmode + vCount + vertices - size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint); - if (flags & DRAW_VERTICES_HAS_TEXS) { - size += vertexCount * sizeof(SkPoint); // + uvs - } - if (flags & DRAW_VERTICES_HAS_COLORS) { - size += vertexCount * sizeof(SkColor); // + vert colors - } - if (flags & DRAW_VERTICES_HAS_INDICES) { - // + num indices + indices - size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t)); - } - if (flags & DRAW_VERTICES_HAS_XFER) { - size += kUInt32Size; // mode enum - } - - size_t initialOffset = this->addDraw(DRAW_VERTICES, &size); this->addPaint(paint); - this->addInt(flags); - this->addInt(vmode); - this->addInt(vertexCount); - this->addPoints(vertices, vertexCount); - if (flags & DRAW_VERTICES_HAS_TEXS) { - this->addPoints(texs, vertexCount); - } - if (flags & DRAW_VERTICES_HAS_COLORS) { - fWriter.writeMul4(colors, vertexCount * sizeof(SkColor)); - } - if (flags & DRAW_VERTICES_HAS_INDICES) { - this->addInt(indexCount); - fWriter.writePad(indices, indexCount * sizeof(uint16_t)); - } - if (flags & DRAW_VERTICES_HAS_XFER) { - SkXfermode::Mode mode = SkXfermode::kModulate_Mode; - (void)xfer->asMode(&mode); - this->addInt(mode); - } + this->addVertices(vertices); + this->addInt(static_cast(mode)); + this->validate(initialOffset, size); } void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, + const SkPoint texCoords[4], SkBlendMode bmode, const SkPaint& paint) { // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size; @@ -796,12 +749,9 @@ void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors flag |= DRAW_VERTICES_HAS_TEXS; size += SkPatchUtils::kNumCorners * sizeof(SkPoint); } - if (xmode) { - SkXfermode::Mode mode; - if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) { - flag |= DRAW_VERTICES_HAS_XFER; - size += kUInt32Size; - } + if (SkBlendMode::kModulate != bmode) { + flag |= DRAW_VERTICES_HAS_XFER; + size += kUInt32Size; } size_t initialOffset = this->addDraw(DRAW_PATCH, &size); @@ -817,15 +767,13 @@ void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint)); } if (flag & DRAW_VERTICES_HAS_XFER) { - SkXfermode::Mode mode = SkXfermode::kModulate_Mode; - xmode->asMode(&mode); - this->addInt(mode); + this->addInt((int)bmode); } this->validate(initialOffset, size); } void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], - const SkColor colors[], int count, SkXfermode::Mode mode, + const SkColor colors[], int count, SkBlendMode mode, const SkRect* cull, const SkPaint* paint) { // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect); @@ -851,7 +799,7 @@ void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], // write optional parameters if (colors) { fWriter.write(colors, count * sizeof(SkColor)); - this->addInt(mode); + this->addInt((int)mode); } if (cull) { fWriter.write(cull, sizeof(SkRect)); @@ -993,4 +941,9 @@ void SkPictureRecord::addTextBlob(const SkTextBlob* blob) { this->addInt(find_or_append_uniqueID(fTextBlobRefs, blob) + 1); } +void SkPictureRecord::addVertices(const SkVertices* vertices) { + // follow the convention of recording a 1-based index + this->addInt(find_or_append_uniqueID(fVerticesRefs, vertices) + 1); +} + /////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/core/SkPictureRecord.h b/gfx/skia/skia/src/core/SkPictureRecord.h index 6d75609db9e5..dc9a002ac98d 100644 --- a/gfx/skia/skia/src/core/SkPictureRecord.h +++ b/gfx/skia/skia/src/core/SkPictureRecord.h @@ -15,6 +15,7 @@ #include "SkTArray.h" #include "SkTDArray.h" #include "SkTHash.h" +#include "SkVertices.h" #include "SkWriter32.h" // These macros help with packing and unpacking a single byte value and @@ -29,7 +30,7 @@ class SkPictureRecord : public SkCanvas { public: SkPictureRecord(const SkISize& dimensions, uint32_t recordFlags); - virtual ~SkPictureRecord(); + ~SkPictureRecord() override; const SkTDArray& getPictureRefs() const { return fPictureRefs; @@ -43,7 +44,11 @@ public: return fTextBlobRefs; } - const SkTDArray& getImageRefs() const { + const SkTDArray& getVerticesRefs() const { + return fVerticesRefs; + } + + const SkTDArray& getImageRefs() const { return fImageRefs; } @@ -76,7 +81,7 @@ protected: private: void handleOptimization(int opt); - size_t recordRestoreOffsetPlaceholder(SkCanvas::ClipOp); + size_t recordRestoreOffsetPlaceholder(SkClipOp); void fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset); SkTDArray fRestoreOffsetStack; @@ -140,6 +145,7 @@ private: void addRegion(const SkRegion& region); void addText(const void* text, size_t byteLength); void addTextBlob(const SkTextBlob* blob); + void addVertices(const SkVertices*); int find(const SkBitmap& bitmap); @@ -178,10 +184,9 @@ protected: const SkPaint& paint) override; void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, - const SkPaint& paint) override; + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) override; void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, - SkXfermode::Mode, const SkRect*, const SkPaint*) override; + SkBlendMode, const SkRect*, const SkPaint*) override; void onDrawPaint(const SkPaint&) override; void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; @@ -198,17 +203,12 @@ protected: const SkPaint*) override; void onDrawImageLattice(const SkImage*, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint*) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; - void onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint&) override; - - void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; - void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, ClipOp) override; + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; @@ -231,10 +231,10 @@ protected: void recordConcat(const SkMatrix& matrix); void recordTranslate(const SkMatrix& matrix); void recordScale(const SkMatrix& matrix); - size_t recordClipRect(const SkRect& rect, SkCanvas::ClipOp op, bool doAA); - size_t recordClipRRect(const SkRRect& rrect, SkCanvas::ClipOp op, bool doAA); - size_t recordClipPath(int pathID, SkCanvas::ClipOp op, bool doAA); - size_t recordClipRegion(const SkRegion& region, SkCanvas::ClipOp op); + size_t recordClipRect(const SkRect& rect, SkClipOp op, bool doAA); + size_t recordClipRRect(const SkRRect& rrect, SkClipOp op, bool doAA); + size_t recordClipPath(int pathID, SkClipOp op, bool doAA); + size_t recordClipRegion(const SkRegion& region, SkClipOp op); void recordSave(); void recordSaveLayer(const SaveLayerRec&); void recordRestore(bool fillInSkips = true); @@ -273,6 +273,7 @@ private: SkTDArray fPictureRefs; SkTDArray fDrawableRefs; SkTDArray fTextBlobRefs; + SkTDArray fVerticesRefs; uint32_t fRecordFlags; int fInitialSaveCount; diff --git a/gfx/skia/skia/src/core/SkPictureRecorder.cpp b/gfx/skia/skia/src/core/SkPictureRecorder.cpp index 5631a081d4a0..701df7d44fc3 100644 --- a/gfx/skia/skia/src/core/SkPictureRecorder.cpp +++ b/gfx/skia/skia/src/core/SkPictureRecorder.cpp @@ -9,7 +9,6 @@ #include "SkData.h" #include "SkDrawable.h" #include "SkPictureRecorder.h" -#include "SkPictureUtils.h" #include "SkRecord.h" #include "SkRecordDraw.h" #include "SkRecordOpts.h" @@ -19,14 +18,16 @@ SkPictureRecorder::SkPictureRecorder() { fActivelyRecording = false; - fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeWH(0, 0), &fMiniRecorder)); + fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeEmpty(), &fMiniRecorder)); } SkPictureRecorder::~SkPictureRecorder() {} -SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect, +SkCanvas* SkPictureRecorder::beginRecording(const SkRect& userCullRect, SkBBHFactory* bbhFactory /* = nullptr */, uint32_t recordFlags /* = 0 */) { + const SkRect cullRect = userCullRect.isEmpty() ? SkRect::MakeEmpty() : userCullRect; + fCullRect = cullRect; fFlags = recordFlags; @@ -55,20 +56,11 @@ sk_sp SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlag fRecorder->restoreToCount(1); // If we were missing any restores, add them now. if (fRecord->count() == 0) { - if (finishFlags & kReturnNullForEmpty_FinishFlag) { - return nullptr; - } return fMiniRecorder.detachAsPicture(fCullRect); } // TODO: delay as much of this work until just before first playback? - SkRecordOptimize(fRecord); - - if (fRecord->count() == 0) { - if (finishFlags & kReturnNullForEmpty_FinishFlag) { - return nullptr; - } - } + SkRecordOptimize(fRecord.get()); SkDrawableList* drawableList = fRecorder->getDrawableList(); SkBigPicture::SnapshotArray* pictList = @@ -89,7 +81,7 @@ sk_sp SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlag size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures(); for (int i = 0; pictList && i < pictList->count(); i++) { - subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]); + subPictureBytes += pictList->begin()[i]->approximateBytesUsed(); } return sk_make_sp(fCullRect, fRecord.release(), pictList, fBBH.release(), subPictureBytes); @@ -122,13 +114,7 @@ sk_sp SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFl fRecorder->flushMiniRecorder(); fRecorder->restoreToCount(1); // If we were missing any restores, add them now. - SkRecordOptimize(fRecord); - - if (fRecord->count() == 0) { - if (finishFlags & kReturnNullForEmpty_FinishFlag) { - return nullptr; - } - } + SkRecordOptimize(fRecord.get()); if (fBBH.get()) { SkAutoTMalloc bounds(fRecord->count()); @@ -137,11 +123,8 @@ sk_sp SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFl } sk_sp drawable = - sk_make_sp(fRecord, fBBH, fRecorder->detachDrawableList(), fCullRect); - - // release our refs now, so only the drawable will be the owner. - fRecord.reset(nullptr); - fBBH.reset(nullptr); + sk_make_sp(std::move(fRecord), std::move(fBBH), + fRecorder->detachDrawableList(), fCullRect); return drawable; } diff --git a/gfx/skia/skia/src/core/SkPictureShader.cpp b/gfx/skia/skia/src/core/SkPictureShader.cpp index 3349558b7fac..50c33a82a079 100644 --- a/gfx/skia/skia/src/core/SkPictureShader.cpp +++ b/gfx/skia/skia/src/core/SkPictureShader.cpp @@ -7,18 +7,22 @@ #include "SkPictureShader.h" +#include "SkArenaAlloc.h" #include "SkBitmap.h" #include "SkBitmapProcShader.h" #include "SkCanvas.h" #include "SkImage.h" +#include "SkImageShader.h" #include "SkMatrixUtils.h" #include "SkPicture.h" +#include "SkPictureImageGenerator.h" #include "SkReadBuffer.h" #include "SkResourceCache.h" #if SK_SUPPORT_GPU #include "GrContext.h" #include "GrCaps.h" +#include "GrFragmentProcessor.h" #endif namespace { @@ -63,27 +67,27 @@ private: }; struct BitmapShaderRec : public SkResourceCache::Rec { - BitmapShaderRec(const BitmapShaderKey& key, SkShader* tileShader, size_t bitmapBytes) + BitmapShaderRec(const BitmapShaderKey& key, SkShader* tileShader) : fKey(key) - , fShader(SkRef(tileShader)) - , fBitmapBytes(bitmapBytes) {} + , fShader(SkRef(tileShader)) {} - BitmapShaderKey fKey; - SkAutoTUnref fShader; - size_t fBitmapBytes; + BitmapShaderKey fKey; + sk_sp fShader; + size_t fBitmapBytes; const Key& getKey() const override { return fKey; } size_t bytesUsed() const override { - return sizeof(fKey) + sizeof(SkShader) + fBitmapBytes; + // Just the record overhead -- the actual pixels are accounted by SkImageCacherator. + return sizeof(fKey) + sizeof(SkImageShader); } const char* getCategory() const override { return "bitmap-shader"; } SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; } static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) { const BitmapShaderRec& rec = static_cast(baseRec); - SkAutoTUnref* result = reinterpret_cast*>(contextShader); + sk_sp* result = reinterpret_cast*>(contextShader); - result->reset(SkRef(rec.fShader.get())); + *result = rec.fShader; // The bitmap shader is backed by an image generator, thus it can always re-generate its // pixels if discarded. @@ -156,6 +160,7 @@ void SkPictureShader::flatten(SkWriteBuffer& buffer) const { } sk_sp SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix, const SkMatrix* localM, + SkColorSpace* dstColorSpace, const int maxTextureSize) const { SkASSERT(fPicture && !fPicture->cullRect().isEmpty()); @@ -180,19 +185,19 @@ sk_sp SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix, con // Clamp the tile size to about 4M pixels static const SkScalar kMaxTileArea = 2048 * 2048; - SkScalar tileArea = SkScalarMul(scaledSize.width(), scaledSize.height()); + SkScalar tileArea = scaledSize.width() * scaledSize.height(); if (tileArea > kMaxTileArea) { SkScalar clampScale = SkScalarSqrt(kMaxTileArea / tileArea); - scaledSize.set(SkScalarMul(scaledSize.width(), clampScale), - SkScalarMul(scaledSize.height(), clampScale)); + scaledSize.set(scaledSize.width() * clampScale, + scaledSize.height() * clampScale); } #if SK_SUPPORT_GPU // Scale down the tile size if larger than maxTextureSize for GPU Path or it should fail on create texture if (maxTextureSize) { if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) { SkScalar downScale = maxTextureSize / SkMaxScalar(scaledSize.width(), scaledSize.height()); - scaledSize.set(SkScalarFloorToScalar(SkScalarMul(scaledSize.width(), downScale)), - SkScalarFloorToScalar(SkScalarMul(scaledSize.height(), downScale))); + scaledSize.set(SkScalarFloorToScalar(scaledSize.width() * downScale), + SkScalarFloorToScalar(scaledSize.height() * downScale)); } } #endif @@ -223,8 +228,9 @@ sk_sp SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix, con tileMatrix.setRectToRect(fTile, SkRect::MakeIWH(tileSize.width(), tileSize.height()), SkMatrix::kFill_ScaleToFit); - sk_sp tileImage( - SkImage::MakeFromPicture(fPicture, tileSize, &tileMatrix, nullptr)); + sk_sp tileImage = SkImage::MakeFromGenerator( + SkPictureImageGenerator::Make(tileSize, fPicture, &tileMatrix, nullptr, + SkImage::BitDepth::kU8, sk_ref_sp(dstColorSpace))); if (!tileImage) { return nullptr; } @@ -233,57 +239,50 @@ sk_sp SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix, con shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); tileShader = tileImage->makeShader(fTmx, fTmy, &shaderMatrix); - const SkImageInfo tileInfo = SkImageInfo::MakeN32Premul(tileSize); - SkResourceCache::Add(new BitmapShaderRec(key, tileShader.get(), - tileInfo.getSafeSize(tileInfo.minRowBytes()))); + SkResourceCache::Add(new BitmapShaderRec(key, tileShader.get())); } return tileShader; } -size_t SkPictureShader::onContextSize(const ContextRec&) const { - return sizeof(PictureShaderContext); -} - -SkShader::Context* SkPictureShader::onCreateContext(const ContextRec& rec, void* storage) const { - sk_sp bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.fLocalMatrix)); - if (!bitmapShader) { - return nullptr; - } - return PictureShaderContext::Create(storage, *this, rec, bitmapShader); +bool SkPictureShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* cs, SkArenaAlloc* alloc, + const SkMatrix& ctm, const SkPaint& paint, + const SkMatrix* localMatrix) const { + // Keep bitmapShader alive by using alloc instead of stack memory + auto& bitmapShader = *alloc->make>(); + bitmapShader = this->refBitmapShader(ctm, localMatrix, cs); + return bitmapShader && bitmapShader->appendStages(p, cs, alloc, ctm, paint); } ///////////////////////////////////////////////////////////////////////////////////////// +SkShader::Context* SkPictureShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) +const { + sk_sp bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.fLocalMatrix, + rec.fDstColorSpace)); + if (!bitmapShader) { + return nullptr; + } -SkShader::Context* SkPictureShader::PictureShaderContext::Create(void* storage, - const SkPictureShader& shader, const ContextRec& rec, - sk_sp bitmapShader) { - PictureShaderContext* ctx = new (storage) PictureShaderContext(shader, rec, - std::move(bitmapShader)); + PictureShaderContext* ctx = + alloc->make(*this, rec, std::move(bitmapShader), alloc); if (nullptr == ctx->fBitmapShaderContext) { - ctx->~PictureShaderContext(); ctx = nullptr; } return ctx; } +///////////////////////////////////////////////////////////////////////////////////////// + SkPictureShader::PictureShaderContext::PictureShaderContext( - const SkPictureShader& shader, const ContextRec& rec, sk_sp bitmapShader) + const SkPictureShader& shader, const ContextRec& rec, sk_sp bitmapShader, + SkArenaAlloc* alloc) : INHERITED(shader, rec) , fBitmapShader(std::move(bitmapShader)) { - fBitmapShaderContextStorage = sk_malloc_throw(fBitmapShader->contextSize(rec)); - fBitmapShaderContext = fBitmapShader->createContext(rec, fBitmapShaderContextStorage); + fBitmapShaderContext = fBitmapShader->makeContext(rec, alloc); //if fBitmapShaderContext is null, we are invalid } -SkPictureShader::PictureShaderContext::~PictureShaderContext() { - if (fBitmapShaderContext) { - fBitmapShaderContext->~Context(); - } - sk_free(fBitmapShaderContextStorage); -} - uint32_t SkPictureShader::PictureShaderContext::getFlags() const { SkASSERT(fBitmapShaderContext); return fBitmapShaderContext->getFlags(); @@ -324,12 +323,11 @@ sk_sp SkPictureShader::asFragmentProcessor(const AsFPArgs& maxTextureSize = args.fContext->caps()->maxTextureSize(); } sk_sp bitmapShader(this->refBitmapShader(*args.fViewMatrix, args.fLocalMatrix, - maxTextureSize)); + args.fDstColorSpace, maxTextureSize)); if (!bitmapShader) { return nullptr; } return bitmapShader->asFragmentProcessor(SkShader::AsFPArgs( - args.fContext, args.fViewMatrix, nullptr, args.fFilterQuality, args.fDstColorSpace, - args.fGammaTreatment)); + args.fContext, args.fViewMatrix, nullptr, args.fFilterQuality, args.fDstColorSpace)); } #endif diff --git a/gfx/skia/skia/src/core/SkPictureShader.h b/gfx/skia/skia/src/core/SkPictureShader.h index f2927a032150..9807cd948200 100644 --- a/gfx/skia/skia/src/core/SkPictureShader.h +++ b/gfx/skia/skia/src/core/SkPictureShader.h @@ -10,6 +10,7 @@ #include "SkShader.h" +class SkArenaAlloc; class SkBitmap; class SkPicture; @@ -34,13 +35,15 @@ public: protected: SkPictureShader(SkReadBuffer&); void flatten(SkWriteBuffer&) const override; - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec&, void* storage) const override; + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + const SkMatrix&, const SkPaint&, const SkMatrix*) const override; + Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override; private: SkPictureShader(sk_sp, TileMode, TileMode, const SkMatrix*, const SkRect*); sk_sp refBitmapShader(const SkMatrix&, const SkMatrix* localMatrix, + SkColorSpace* dstColorSpace, const int maxTextureSize = 0) const; sk_sp fPicture; @@ -49,20 +52,14 @@ private: class PictureShaderContext : public SkShader::Context { public: - static Context* Create(void* storage, const SkPictureShader&, const ContextRec&, - sk_sp bitmapShader); - - virtual ~PictureShaderContext(); + PictureShaderContext( + const SkPictureShader&, const ContextRec&, sk_sp bitmapShader, SkArenaAlloc*); uint32_t getFlags() const override; ShadeProc asAShadeProc(void** ctx) override; void shadeSpan(int x, int y, SkPMColor dstC[], int count) override; - private: - PictureShaderContext(const SkPictureShader&, const ContextRec&, - sk_sp bitmapShader); - sk_sp fBitmapShader; SkShader::Context* fBitmapShaderContext; void* fBitmapShaderContextStorage; diff --git a/gfx/skia/skia/src/core/SkPipe.h b/gfx/skia/skia/src/core/SkPipe.h index 04c3ae2dcae3..027edfba7ab0 100644 --- a/gfx/skia/skia/src/core/SkPipe.h +++ b/gfx/skia/skia/src/core/SkPipe.h @@ -9,14 +9,19 @@ #define SkPipe_DEFINED #include "SkData.h" +#include "SkImage.h" +#include "SkPicture.h" class SkCanvas; -class SkImage; -class SkPicture; -class SkTypefaceSerializer; +class SkImageDeserializer; +class SkImageSerializer; +class SkTypeface; class SkTypefaceDeserializer; +class SkTypefaceSerializer; class SkWStream; +struct SkRect; + class SkPipeSerializer { public: SkPipeSerializer(); @@ -24,6 +29,7 @@ public: // Ownership is not transferred, so caller must ceep the serializer alive void setTypefaceSerializer(SkTypefaceSerializer*); + void setImageSerializer(SkImageSerializer*); void resetCache(); @@ -48,6 +54,7 @@ public: // Ownership is not transferred, so caller must ceep the deserializer alive void setTypefaceDeserializer(SkTypefaceDeserializer*); + void setImageDeserializer(SkImageDeserializer*); sk_sp readImage(const SkData* data) { if (!data) { @@ -82,6 +89,14 @@ public: virtual sk_sp serialize(SkTypeface*) = 0; }; +class SkImageSerializer { +public: + virtual ~SkImageSerializer() {} + + virtual sk_sp serialize(SkImage*) = 0; +}; + + class SkTypefaceDeserializer { public: virtual ~SkTypefaceDeserializer() {} diff --git a/gfx/skia/skia/src/core/SkPixelRef.cpp b/gfx/skia/skia/src/core/SkPixelRef.cpp index cdc318b2a812..1b14e260b559 100644 --- a/gfx/skia/skia/src/core/SkPixelRef.cpp +++ b/gfx/skia/skia/src/core/SkPixelRef.cpp @@ -36,10 +36,22 @@ static SkImageInfo validate_info(const SkImageInfo& info) { return info.makeAlphaType(newAlphaType); } +static void validate_pixels_ctable(const SkImageInfo& info, const SkColorTable* ctable) { + if (info.isEmpty()) { + return; // can't require ctable if the dimensions are empty + } + if (kIndex_8_SkColorType == info.colorType()) { + SkASSERT(ctable); + } else { + SkASSERT(nullptr == ctable); + } +} + #ifdef SK_TRACE_PIXELREF_LIFETIME static int32_t gInstCounter; #endif +#ifdef SK_SUPPORT_LEGACY_NO_ADDR_PIXELREF SkPixelRef::SkPixelRef(const SkImageInfo& info) : fInfo(validate_info(info)) #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK @@ -57,6 +69,31 @@ SkPixelRef::SkPixelRef(const SkImageInfo& info) fPreLocked = false; fAddedToCache.store(false); } +#endif + +SkPixelRef::SkPixelRef(const SkImageInfo& info, void* pixels, size_t rowBytes, + sk_sp ctable) + : fInfo(validate_info(info)) + , fCTable(std::move(ctable)) +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + , fStableID(SkNextID::ImageID()) +#endif +{ + validate_pixels_ctable(fInfo, fCTable.get()); + SkASSERT(rowBytes >= info.minRowBytes()); +#ifdef SK_TRACE_PIXELREF_LIFETIME + SkDebugf(" pixelref %d\n", sk_atomic_inc(&gInstCounter)); +#endif + fRec.fPixels = pixels; + fRec.fRowBytes = rowBytes; + fRec.fColorTable = fCTable.get(); + + fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT; + this->needsNewGenID(); + fMutability = kMutable; + fPreLocked = true; + fAddedToCache.store(false); +} SkPixelRef::~SkPixelRef() { #ifndef SK_SUPPORT_LEGACY_UNBALANCED_PIXELREF_LOCKCOUNT @@ -69,6 +106,23 @@ SkPixelRef::~SkPixelRef() { this->callGenIDChangeListeners(); } +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK +// This is undefined if there are clients in-flight trying to use us +void SkPixelRef::android_only_reset(const SkImageInfo& info, size_t rowBytes, + sk_sp ctable) { + validate_pixels_ctable(info, ctable.get()); + + *const_cast(&fInfo) = info; + fCTable = std::move(ctable); + // note: we do not change fRec.fPixels + fRec.fRowBytes = rowBytes; + fRec.fColorTable = fCTable.get(); + + // conservative, since its possible the "new" settings are the same as the old. + this->notifyPixelsChanged(); +} +#endif + void SkPixelRef::needsNewGenID() { fTaggedGenID.store(0); SkASSERT(!this->genIDIsUnique()); // This method isn't threadsafe, so the assert should be fine. @@ -88,17 +142,7 @@ void SkPixelRef::cloneGenID(const SkPixelRef& that) { SkASSERT(!that. genIDIsUnique()); } -static void validate_pixels_ctable(const SkImageInfo& info, const SkColorTable* ctable) { - if (info.isEmpty()) { - return; // can't require ctable if the dimensions are empty - } - if (kIndex_8_SkColorType == info.colorType()) { - SkASSERT(ctable); - } else { - SkASSERT(nullptr == ctable); - } -} - +#ifdef SK_SUPPORT_LEGACY_NO_ADDR_PIXELREF void SkPixelRef::setPreLocked(void* pixels, size_t rowBytes, SkColorTable* ctable) { SkASSERT(pixels); validate_pixels_ctable(fInfo, ctable); @@ -110,6 +154,7 @@ void SkPixelRef::setPreLocked(void* pixels, size_t rowBytes, SkColorTable* ctabl fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT; fPreLocked = true; } +#endif // Increments fLockCount only on success bool SkPixelRef::lockPixelsInsideMutex() { @@ -206,7 +251,7 @@ bool SkPixelRef::requestLock(const LockRequest& request, LockResult* result) { result->fSize.set(fInfo.width(), fInfo.height()); } else { SkAutoMutexAcquire ac(fMutex); - if (!this->onRequestLock(request, result)) { + if (!this->internalRequestLock(request, result)) { return false; } } @@ -217,14 +262,6 @@ bool SkPixelRef::requestLock(const LockRequest& request, LockResult* result) { return false; } -bool SkPixelRef::lockPixelsAreWritable() const { - return this->onLockPixelsAreWritable(); -} - -bool SkPixelRef::onLockPixelsAreWritable() const { - return true; -} - uint32_t SkPixelRef::getGenerationID() const { uint32_t id = fTaggedGenID.load(); if (0 == id) { @@ -307,22 +344,11 @@ void SkPixelRef::restoreMutability() { fMutability = kMutable; } -bool SkPixelRef::readPixels(SkBitmap* dst, SkColorType ct, const SkIRect* subset) { - return this->onReadPixels(dst, ct, subset); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// -bool SkPixelRef::onReadPixels(SkBitmap* dst, SkColorType, const SkIRect* subset) { - return false; -} void SkPixelRef::onNotifyPixelsChanged() { } -SkData* SkPixelRef::onRefEncodedData() { - return nullptr; -} - size_t SkPixelRef::getAllocatedSizeInBytes() const { return 0; } @@ -333,7 +359,7 @@ static void unlock_legacy_result(void* ctx) { pr->unref(); // balancing the Ref in onRequestLoc } -bool SkPixelRef::onRequestLock(const LockRequest& request, LockResult* result) { +bool SkPixelRef::internalRequestLock(const LockRequest& request, LockResult* result) { if (!this->lockPixelsInsideMutex()) { return false; } diff --git a/gfx/skia/skia/src/core/SkPixmap.cpp b/gfx/skia/skia/src/core/SkPixmap.cpp index 108c87757b78..7eac6c4ed57b 100644 --- a/gfx/skia/skia/src/core/SkPixmap.cpp +++ b/gfx/skia/skia/src/core/SkPixmap.cpp @@ -5,13 +5,20 @@ * found in the LICENSE file. */ +#include "SkBitmap.h" +#include "SkCanvas.h" #include "SkColorPriv.h" -#include "SkConfig8888.h" +#include "SkConvertPixels.h" #include "SkData.h" +#include "SkImageInfoPriv.h" +#include "SkHalf.h" #include "SkMask.h" -#include "SkPixmap.h" -#include "SkUtils.h" +#include "SkNx.h" #include "SkPM4f.h" +#include "SkPixmap.h" +#include "SkReadPixelsRec.h" +#include "SkSurface.h" +#include "SkUtils.h" void SkAutoPixmapUnlock::reset(const SkPixmap& pm, void (*unlock)(void*), void* ctx) { SkASSERT(pm.addr() != nullptr); @@ -77,40 +84,22 @@ bool SkPixmap::extractSubset(SkPixmap* result, const SkIRect& subset) const { return true; } -bool SkPixmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB, - int x, int y) const { - if (kUnknown_SkColorType == requestedDstInfo.colorType()) { - return false; - } - if (nullptr == dstPixels || dstRB < requestedDstInfo.minRowBytes()) { - return false; - } - if (0 == requestedDstInfo.width() || 0 == requestedDstInfo.height()) { +bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int x, int y) +const { + if (!SkImageInfoValidConversion(dstInfo, fInfo)) { return false; } - SkIRect srcR = SkIRect::MakeXYWH(x, y, requestedDstInfo.width(), requestedDstInfo.height()); - if (!srcR.intersect(0, 0, this->width(), this->height())) { + SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, x, y); + if (!rec.trim(fInfo.width(), fInfo.height())) { return false; } - // the intersect may have shrunk info's logical size - const SkImageInfo dstInfo = requestedDstInfo.makeWH(srcR.width(), srcR.height()); - - // if x or y are negative, then we have to adjust pixels - if (x > 0) { - x = 0; - } - if (y > 0) { - y = 0; - } - // here x,y are either 0 or negative - dstPixels = ((char*)dstPixels - y * dstRB - x * dstInfo.bytesPerPixel()); - - const SkImageInfo srcInfo = this->info().makeWH(dstInfo.width(), dstInfo.height()); - const void* srcPixels = this->addr(srcR.x(), srcR.y()); - return SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRB, - srcInfo, srcPixels, this->rowBytes(), this->ctable()); + const void* srcPixels = this->addr(rec.fX, rec.fY); + const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height()); + SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(), + this->ctable(), SkTransferFunctionBehavior::kRespect); + return true; } static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) { @@ -206,15 +195,19 @@ bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const { } break; } + case kRGBA_F16_SkColorType: + // The colorspace is unspecified, so assume linear just like getColor(). + this->erase(SkColor4f{(1 / 255.0f) * r, + (1 / 255.0f) * g, + (1 / 255.0f) * b, + (1 / 255.0f) * a}, &area); + break; default: return false; // no change, so don't call notifyPixelsChanged() } return true; } -#include "SkNx.h" -#include "SkHalf.h" - bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const { SkPixmap pm; if (subset) { @@ -238,11 +231,6 @@ bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const { return true; } -#include "SkBitmap.h" -#include "SkCanvas.h" -#include "SkSurface.h" -#include "SkXfermode.h" - bool SkPixmap::scalePixels(const SkPixmap& dst, SkFilterQuality quality) const { // Can't do anthing with empty src or dst if (this->width() <= 0 || this->height() <= 0 || dst.width() <= 0 || dst.height() <= 0) { @@ -274,3 +262,136 @@ bool SkPixmap::scalePixels(const SkPixmap& dst, SkFilterQuality quality) const { } ////////////////////////////////////////////////////////////////////////////////////////////////// + +SkColor SkPixmap::getColor(int x, int y) const { + SkASSERT(this->addr()); + SkASSERT((unsigned)x < (unsigned)this->width()); + SkASSERT((unsigned)y < (unsigned)this->height()); + switch (this->colorType()) { + case kGray_8_SkColorType: { + uint8_t value = *this->addr8(x, y); + return SkColorSetRGB(value, value, value); + } + case kAlpha_8_SkColorType: { + return SkColorSetA(0, *this->addr8(x, y)); + } + case kIndex_8_SkColorType: { + SkASSERT(this->ctable()); + SkPMColor pmColor = (*this->ctable())[*this->addr8(x, y)]; + return SkUnPreMultiply::PMColorToColor(pmColor); + } + case kRGB_565_SkColorType: { + return SkPixel16ToColor(*this->addr16(x, y)); + } + case kARGB_4444_SkColorType: { + uint16_t value = *this->addr16(x, y); + SkPMColor c = SkPixel4444ToPixel32(value); + return SkUnPreMultiply::PMColorToColor(c); + } + case kBGRA_8888_SkColorType: { + uint32_t value = *this->addr32(x, y); + SkPMColor c = SkSwizzle_BGRA_to_PMColor(value); + return SkUnPreMultiply::PMColorToColor(c); + } + case kRGBA_8888_SkColorType: { + uint32_t value = *this->addr32(x, y); + SkPMColor c = SkSwizzle_RGBA_to_PMColor(value); + return SkUnPreMultiply::PMColorToColor(c); + } + case kRGBA_F16_SkColorType: { + const uint64_t* addr = + (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x; + Sk4f p4 = SkHalfToFloat_finite_ftz(*addr); + if (p4[3]) { + float inva = 1 / p4[3]; + p4 = p4 * Sk4f(inva, inva, inva, 1); + } + SkColor c; + SkNx_cast(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c); + // p4 is RGBA, but we want BGRA, so we need to swap next + return SkSwizzle_RB(c); + } + default: + SkDEBUGFAIL(""); + return SkColorSetARGB(0, 0, 0, 0); + } +} + +bool SkPixmap::computeIsOpaque() const { + const int height = this->height(); + const int width = this->width(); + + switch (this->colorType()) { + case kAlpha_8_SkColorType: { + unsigned a = 0xFF; + for (int y = 0; y < height; ++y) { + const uint8_t* row = this->addr8(0, y); + for (int x = 0; x < width; ++x) { + a &= row[x]; + } + if (0xFF != a) { + return false; + } + } + return true; + } break; + case kIndex_8_SkColorType: { + const SkColorTable* ctable = this->ctable(); + if (nullptr == ctable) { + return false; + } + const SkPMColor* table = ctable->readColors(); + SkPMColor c = (SkPMColor)~0; + for (int i = ctable->count() - 1; i >= 0; --i) { + c &= table[i]; + } + return 0xFF == SkGetPackedA32(c); + } break; + case kRGB_565_SkColorType: + case kGray_8_SkColorType: + return true; + break; + case kARGB_4444_SkColorType: { + unsigned c = 0xFFFF; + for (int y = 0; y < height; ++y) { + const SkPMColor16* row = this->addr16(0, y); + for (int x = 0; x < width; ++x) { + c &= row[x]; + } + if (0xF != SkGetPackedA4444(c)) { + return false; + } + } + return true; + } break; + case kBGRA_8888_SkColorType: + case kRGBA_8888_SkColorType: { + SkPMColor c = (SkPMColor)~0; + for (int y = 0; y < height; ++y) { + const SkPMColor* row = this->addr32(0, y); + for (int x = 0; x < width; ++x) { + c &= row[x]; + } + if (0xFF != SkGetPackedA32(c)) { + return false; + } + } + return true; + } + case kRGBA_F16_SkColorType: { + const SkHalf* row = (const SkHalf*)this->addr(); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + if (row[4 * x + 3] < SK_Half1) { + return false; + } + } + row += this->rowBytes() >> 1; + } + return true; + } + default: + break; + } + return false; +} diff --git a/gfx/skia/skia/src/core/SkPoint.cpp b/gfx/skia/skia/src/core/SkPoint.cpp index 162c62acad70..dfa484bb4c69 100644 --- a/gfx/skia/skia/src/core/SkPoint.cpp +++ b/gfx/skia/skia/src/core/SkPoint.cpp @@ -62,7 +62,7 @@ void SkPoint::rotateCCW(SkPoint* dst) const { void SkPoint::scale(SkScalar scale, SkPoint* dst) const { SkASSERT(dst); - dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale)); + dst->set(fX * scale, fY * scale); } bool SkPoint::normalize() { diff --git a/gfx/skia/skia/src/core/SkRRect.cpp b/gfx/skia/skia/src/core/SkRRect.cpp index 1188989cdb8f..824ee62e6040 100644 --- a/gfx/skia/skia/src/core/SkRRect.cpp +++ b/gfx/skia/skia/src/core/SkRRect.cpp @@ -33,8 +33,8 @@ void SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { if (fRect.width() < xRad+xRad || fRect.height() < yRad+yRad) { SkScalar scale = SkMinScalar(fRect.width() / (xRad + xRad), fRect.height() / (yRad + yRad)); SkASSERT(scale < SK_Scalar1); - xRad = SkScalarMul(xRad, scale); - yRad = SkScalarMul(yRad, scale); + xRad *= scale; + yRad *= scale; } for (int i = 0; i < 4; ++i) { @@ -79,10 +79,10 @@ void SkRRect::setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad } if (scale < SK_Scalar1) { - leftRad = SkScalarMul(leftRad, scale); - topRad = SkScalarMul(topRad, scale); - rightRad = SkScalarMul(rightRad, scale); - bottomRad = SkScalarMul(bottomRad, scale); + leftRad *= scale; + topRad *= scale; + rightRad *= scale; + bottomRad *= scale; } if (leftRad == rightRad && topRad == bottomRad) { @@ -246,9 +246,9 @@ bool SkRRect::checkCornerContainment(SkScalar x, SkScalar y) const { // a^2 b^2 // or : // b^2*x^2 + a^2*y^2 <= (ab)^2 - SkScalar dist = SkScalarMul(SkScalarSquare(canonicalPt.fX), SkScalarSquare(fRadii[index].fY)) + - SkScalarMul(SkScalarSquare(canonicalPt.fY), SkScalarSquare(fRadii[index].fX)); - return dist <= SkScalarSquare(SkScalarMul(fRadii[index].fX, fRadii[index].fY)); + SkScalar dist = SkScalarSquare(canonicalPt.fX) * SkScalarSquare(fRadii[index].fY) + + SkScalarSquare(canonicalPt.fY) * SkScalarSquare(fRadii[index].fX); + return dist <= SkScalarSquare(fRadii[index].fX * fRadii[index].fY); } bool SkRRect::allCornersCircular() const { @@ -404,8 +404,8 @@ bool SkRRect::transform(const SkMatrix& matrix, SkRRect* dst) const { // Scale the radii without respecting the flip. for (int i = 0; i < 4; ++i) { - dst->fRadii[i].fX = SkScalarMul(fRadii[i].fX, xScale); - dst->fRadii[i].fY = SkScalarMul(fRadii[i].fY, yScale); + dst->fRadii[i].fX = fRadii[i].fX * xScale; + dst->fRadii[i].fY = fRadii[i].fY * yScale; } // Now swap as necessary. @@ -456,10 +456,8 @@ void SkRRect::inset(SkScalar dx, SkScalar dy, SkRRect* dst) const { /////////////////////////////////////////////////////////////////////////////// size_t SkRRect::writeToMemory(void* buffer) const { - SkASSERT(kSizeInMemory == sizeof(SkRect) + sizeof(fRadii)); - - memcpy(buffer, &fRect, sizeof(SkRect)); - memcpy((char*)buffer + sizeof(SkRect), fRadii, sizeof(fRadii)); + // Serialize only the rect and corners, but not the derived type tag. + memcpy(buffer, this, kSizeInMemory); return kSizeInMemory; } @@ -468,14 +466,10 @@ size_t SkRRect::readFromMemory(const void* buffer, size_t length) { return 0; } - SkScalar storage[12]; - SkASSERT(sizeof(storage) == kSizeInMemory); + // Deserialize rect and corners, then rederive the type tag. + memcpy(this, buffer, kSizeInMemory); + this->computeType(); - // we make a local copy, to ensure alignment before we cast - memcpy(storage, buffer, kSizeInMemory); - - this->setRectRadii(*(const SkRect*)&storage[0], - (const SkVector*)&storage[4]); return kSizeInMemory; } diff --git a/gfx/skia/skia/src/core/SkRTree.cpp b/gfx/skia/skia/src/core/SkRTree.cpp index bae2fdce3f86..4d1787e70d99 100644 --- a/gfx/skia/skia/src/core/SkRTree.cpp +++ b/gfx/skia/skia/src/core/SkRTree.cpp @@ -7,7 +7,8 @@ #include "SkRTree.h" -SkRTree::SkRTree(SkScalar aspectRatio) : fCount(0), fAspectRatio(aspectRatio) {} +SkRTree::SkRTree(SkScalar aspectRatio) + : fCount(0), fAspectRatio(isfinite(aspectRatio) ? aspectRatio : 1) {} SkRect SkRTree::getRootBound() const { if (fCount) { diff --git a/gfx/skia/skia/src/core/SkRTree.h b/gfx/skia/skia/src/core/SkRTree.h index 499f7a5d7dcb..0fb491e22f59 100644 --- a/gfx/skia/skia/src/core/SkRTree.h +++ b/gfx/skia/skia/src/core/SkRTree.h @@ -38,7 +38,7 @@ public: * create better proportioned tiles of rectangles. */ explicit SkRTree(SkScalar aspectRatio = 1); - virtual ~SkRTree() {} + ~SkRTree() override {} void insert(const SkRect[], int N) override; void search(const SkRect& query, SkTDArray* results) const override; diff --git a/gfx/skia/skia/src/core/SkRWBuffer.cpp b/gfx/skia/skia/src/core/SkRWBuffer.cpp index e69070b5f908..7770b20769e0 100644 --- a/gfx/skia/skia/src/core/SkRWBuffer.cpp +++ b/gfx/skia/skia/src/core/SkRWBuffer.cpp @@ -5,8 +5,10 @@ * found in the LICENSE file. */ -#include "SkAtomics.h" #include "SkRWBuffer.h" + +#include "SkAtomics.h" +#include "SkMalloc.h" #include "SkStream.h" // Force small chunks to be a page's worth @@ -270,7 +272,7 @@ public: fGlobalOffset = fLocalOffset = 0; } - virtual ~SkROBufferStreamAsset() { fBuffer->unref(); } + ~SkROBufferStreamAsset() override { fBuffer->unref(); } size_t getLength() const override { return fBuffer->size(); } @@ -355,6 +357,6 @@ private: }; SkStreamAsset* SkRWBuffer::newStreamSnapshot() const { - SkAutoTUnref buffer(this->newRBufferSnapshot()); - return new SkROBufferStreamAsset(buffer); + sk_sp buffer(this->newRBufferSnapshot()); + return new SkROBufferStreamAsset(buffer.get()); } diff --git a/gfx/skia/skia/src/core/SkRadialShadowMapShader.cpp b/gfx/skia/skia/src/core/SkRadialShadowMapShader.cpp index 29773a63b513..afbb3c79d2e5 100644 --- a/gfx/skia/skia/src/core/SkRadialShadowMapShader.cpp +++ b/gfx/skia/skia/src/core/SkRadialShadowMapShader.cpp @@ -87,7 +87,6 @@ private: #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "SkGr.h" -#include "SkGrPriv.h" #include "SkImage_Base.h" #include "GrInvariantOutput.h" #include "SkSpecialImage.h" @@ -176,13 +175,14 @@ public: fragBuilder->codeAppendf("%s = vec4(vec3(closestDistHere / 2.0),1);", args.fOutputColor); } - static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, + static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) { b->add32(0); // nothing to add here } protected: - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) override { const RadialShadowMapFP &radialShadowMapFP = proc.cast(); const SkVector3& lightPos = radialShadowMapFP.lightPos(); @@ -213,15 +213,12 @@ public: GrGLSLProgramDataManager::UniformHandle fHeightUni; }; - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLRadialShadowMapFP::GenKey(*this, caps, b); } const char* name() const override { return "RadialShadowMapFP"; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->mulByUnknownFourComponents(); - } const SkVector3& lightPos() const { return fLightPos; } diff --git a/gfx/skia/skia/src/core/SkRasterClip.cpp b/gfx/skia/skia/src/core/SkRasterClip.cpp index 1090c66f34ba..a08119a34df1 100644 --- a/gfx/skia/skia/src/core/SkRasterClip.cpp +++ b/gfx/skia/skia/src/core/SkRasterClip.cpp @@ -8,10 +8,125 @@ #include "SkRasterClip.h" #include "SkPath.h" +enum MutateResult { + kDoNothing_MutateResult, + kReplaceClippedAgainstGlobalBounds_MutateResult, + kContinue_MutateResult, +}; + +static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) { + if (inverseFilled) { + switch (*op) { + case SkRegion::kIntersect_Op: + case SkRegion::kDifference_Op: + // These ops can only shrink the current clip. So leaving + // the clip unchanged conservatively respects the contract. + return kDoNothing_MutateResult; + case SkRegion::kUnion_Op: + case SkRegion::kReplace_Op: + case SkRegion::kReverseDifference_Op: + case SkRegion::kXOR_Op: { + // These ops can grow the current clip up to the extents of + // the input clip, which is inverse filled, so we just set + // the current clip to the device bounds. + *op = SkRegion::kReplace_Op; + return kReplaceClippedAgainstGlobalBounds_MutateResult; + } + } + } else { + // Not inverse filled + switch (*op) { + case SkRegion::kIntersect_Op: + case SkRegion::kUnion_Op: + case SkRegion::kReplace_Op: + return kContinue_MutateResult; + case SkRegion::kDifference_Op: + // Difference can only shrink the current clip. + // Leaving clip unchanged conservatively fullfills the contract. + return kDoNothing_MutateResult; + case SkRegion::kReverseDifference_Op: + // To reverse, we swap in the bounds with a replace op. + // As with difference, leave it unchanged. + *op = SkRegion::kReplace_Op; + return kContinue_MutateResult; + case SkRegion::kXOR_Op: + // Be conservative, based on (A XOR B) always included in (A union B), + // which is always included in (bounds(A) union bounds(B)) + *op = SkRegion::kUnion_Op; + return kContinue_MutateResult; + } + } + SkFAIL("should not get here"); + return kDoNothing_MutateResult; +} + +void SkConservativeClip::op(const SkRect& localRect, const SkMatrix& ctm, const SkIRect& devBounds, + SkRegion::Op op, bool doAA) { + SkIRect ir; + switch (mutate_conservative_op(&op, false)) { + case kDoNothing_MutateResult: + return; + case kReplaceClippedAgainstGlobalBounds_MutateResult: + ir = devBounds; + break; + case kContinue_MutateResult: { + SkRect devRect; + ctm.mapRect(&devRect, localRect); + ir = doAA ? devRect.roundOut() : devRect.round(); + } break; + } + this->op(ir, op); +} + +void SkConservativeClip::op(const SkRRect& rrect, const SkMatrix& ctm, const SkIRect& devBounds, + SkRegion::Op op, bool doAA) { + this->op(rrect.getBounds(), ctm, devBounds, op, doAA); +} + +void SkConservativeClip::op(const SkPath& path, const SkMatrix& ctm, const SkIRect& devBounds, + SkRegion::Op op, bool doAA) { + SkIRect ir; + switch (mutate_conservative_op(&op, path.isInverseFillType())) { + case kDoNothing_MutateResult: + return; + case kReplaceClippedAgainstGlobalBounds_MutateResult: + ir = devBounds; + break; + case kContinue_MutateResult: { + SkRect bounds = path.getBounds(); + ctm.mapRect(&bounds); + ir = bounds.roundOut(); + break; + } + } + return this->op(ir, op); +} + +void SkConservativeClip::op(const SkRegion& rgn, SkRegion::Op op) { + this->op(rgn.getBounds(), op); +} + +void SkConservativeClip::op(const SkIRect& devRect, SkRegion::Op op) { + if (SkRegion::kIntersect_Op == op) { + if (!fBounds.intersect(devRect)) { + fBounds.setEmpty(); + } + return; + } + + // This may still create a complex region (which we would then take the bounds + // Perhaps we should inline the op-logic directly to never create the rgn... + SkRegion result; + result.op(SkRegion(fBounds), SkRegion(devRect), op); + fBounds = result.getBounds(); + this->applyClipRestriction(op, &fBounds); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + SkRasterClip::SkRasterClip(const SkRasterClip& src) { AUTO_RASTERCLIP_VALIDATE(src); - fForceConservativeRects = src.fForceConservativeRects; fIsBW = src.fIsBW; if (fIsBW) { fBW = src.fBW; @@ -21,27 +136,25 @@ SkRasterClip::SkRasterClip(const SkRasterClip& src) { fIsEmpty = src.isEmpty(); fIsRect = src.isRect(); + fClipRestrictionRect = src.fClipRestrictionRect; SkDEBUGCODE(this->validate();) } SkRasterClip::SkRasterClip(const SkRegion& rgn) : fBW(rgn) { - fForceConservativeRects = false; fIsBW = true; fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute fIsRect = !fIsEmpty; SkDEBUGCODE(this->validate();) } -SkRasterClip::SkRasterClip(const SkIRect& bounds, bool forceConservativeRects) : fBW(bounds) { - fForceConservativeRects = forceConservativeRects; +SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) { fIsBW = true; fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute fIsRect = !fIsEmpty; SkDEBUGCODE(this->validate();) } -SkRasterClip::SkRasterClip(bool forceConservativeRects) { - fForceConservativeRects = forceConservativeRects; +SkRasterClip::SkRasterClip() { fIsBW = true; fIsEmpty = true; fIsRect = false; @@ -53,8 +166,6 @@ SkRasterClip::~SkRasterClip() { } bool SkRasterClip::operator==(const SkRasterClip& other) const { - // This impl doesn't care if fForceConservativeRects is the same in both, only the current state - if (fIsBW != other.fIsBW) { return false; } @@ -113,65 +224,9 @@ bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bo ///////////////////////////////////////////////////////////////////////////////////// -enum MutateResult { - kDoNothing_MutateResult, - kReplaceClippedAgainstGlobalBounds_MutateResult, - kContinue_MutateResult, -}; - -static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) { - if (inverseFilled) { - switch (*op) { - case SkRegion::kIntersect_Op: - case SkRegion::kDifference_Op: - // These ops can only shrink the current clip. So leaving - // the clip unchanged conservatively respects the contract. - return kDoNothing_MutateResult; - case SkRegion::kUnion_Op: - case SkRegion::kReplace_Op: - case SkRegion::kReverseDifference_Op: - case SkRegion::kXOR_Op: { - // These ops can grow the current clip up to the extents of - // the input clip, which is inverse filled, so we just set - // the current clip to the device bounds. - *op = SkRegion::kReplace_Op; - return kReplaceClippedAgainstGlobalBounds_MutateResult; - } - } - } else { - // Not inverse filled - switch (*op) { - case SkRegion::kIntersect_Op: - case SkRegion::kUnion_Op: - case SkRegion::kReplace_Op: - return kContinue_MutateResult; - case SkRegion::kDifference_Op: - // Difference can only shrink the current clip. - // Leaving clip unchanged conservatively fullfills the contract. - return kDoNothing_MutateResult; - case SkRegion::kReverseDifference_Op: - // To reverse, we swap in the bounds with a replace op. - // As with difference, leave it unchanged. - *op = SkRegion::kReplace_Op; - return kContinue_MutateResult; - case SkRegion::kXOR_Op: - // Be conservative, based on (A XOR B) always included in (A union B), - // which is always included in (bounds(A) union bounds(B)) - *op = SkRegion::kUnion_Op; - return kContinue_MutateResult; - } - } - SkFAIL("should not get here"); - return kDoNothing_MutateResult; -} - bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) { AUTO_RASTERCLIP_VALIDATE(*this); - if (fForceConservativeRects) { - return this->setConservativeRect(path.getBounds(), clip.getBounds(), path.isInverseFillType()); - } - if (this->isBW() && !doAA) { (void)fBW.setPath(path, clip); } else { @@ -185,11 +240,10 @@ bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) return this->updateCacheAndReturnNonEmpty(); } -bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, const SkIRect& bounds, +bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, const SkIRect& devBounds, SkRegion::Op op, bool doAA) { - if (fForceConservativeRects) { - return this->op(rrect.getBounds(), matrix, bounds, op, doAA); - } + SkIRect bounds(devBounds); + this->applyClipRestriction(op, &bounds); SkPath path; path.addRRect(rrect); @@ -197,27 +251,11 @@ bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, const SkIRec return this->op(path, matrix, bounds, op, doAA); } -bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& bounds, +bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& devBounds, SkRegion::Op op, bool doAA) { AUTO_RASTERCLIP_VALIDATE(*this); - - if (fForceConservativeRects) { - SkIRect ir; - switch (mutate_conservative_op(&op, path.isInverseFillType())) { - case kDoNothing_MutateResult: - return !this->isEmpty(); - case kReplaceClippedAgainstGlobalBounds_MutateResult: - ir = bounds; - break; - case kContinue_MutateResult: { - SkRect bounds = path.getBounds(); - matrix.mapRect(&bounds); - ir = bounds.roundOut(); - break; - } - } - return this->op(ir, op); - } + SkIRect bounds(devBounds); + this->applyClipRestriction(op, &bounds); // base is used to limit the size (and therefore memory allocation) of the // region that results from scan converting devPath. @@ -241,7 +279,7 @@ bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& return this->setPath(devPath, this->bwRgn(), doAA); } else { base.setRect(this->getBounds()); - SkRasterClip clip(fForceConservativeRects); + SkRasterClip clip; clip.setPath(devPath, base, doAA); return this->op(clip, op); } @@ -251,7 +289,7 @@ bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& if (SkRegion::kReplace_Op == op) { return this->setPath(devPath, base, doAA); } else { - SkRasterClip clip(fForceConservativeRects); + SkRasterClip clip; clip.setPath(devPath, base, doAA); return this->op(clip, op); } @@ -321,32 +359,17 @@ static bool nearly_integral(SkScalar x) { return x - SkScalarFloorToScalar(x) < domain; } -bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& bounds, +bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& devBounds, SkRegion::Op op, bool doAA) { AUTO_RASTERCLIP_VALIDATE(*this); SkRect devRect; - if (fForceConservativeRects) { - SkIRect ir; - switch (mutate_conservative_op(&op, false)) { - case kDoNothing_MutateResult: - return !this->isEmpty(); - case kReplaceClippedAgainstGlobalBounds_MutateResult: - ir = bounds; - break; - case kContinue_MutateResult: - matrix.mapRect(&devRect, localRect); - ir = devRect.roundOut(); - break; - } - return this->op(ir, op); - } const bool isScaleTrans = matrix.isScaleTranslate(); if (!isScaleTrans) { SkPath path; path.addRect(localRect); path.setIsVolatile(true); - return this->op(path, matrix, bounds, op, doAA); + return this->op(path, matrix, devBounds, op, doAA); } matrix.mapRect(&devRect, localRect); @@ -363,11 +386,13 @@ bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkI if (fIsBW && !doAA) { SkIRect ir; devRect.round(&ir); + this->applyClipRestriction(op, &ir); (void)fBW.op(ir, op); } else { if (fIsBW) { this->convertToAA(); } + this->applyClipRestriction(op, &devRect); (void)fAA.op(devRect, op, doAA); } return this->updateCacheAndReturnNonEmpty(); @@ -418,8 +443,6 @@ const SkRegion& SkRasterClip::forceGetBW() { void SkRasterClip::convertToAA() { AUTO_RASTERCLIP_VALIDATE(*this); - SkASSERT(!fForceConservativeRects); - SkASSERT(fIsBW); fAA.setRegion(fBW); fIsBW = false; diff --git a/gfx/skia/skia/src/core/SkRasterClip.h b/gfx/skia/skia/src/core/SkRasterClip.h index 4b462479c34c..1e50e0453928 100644 --- a/gfx/skia/skia/src/core/SkRasterClip.h +++ b/gfx/skia/skia/src/core/SkRasterClip.h @@ -13,6 +13,39 @@ class SkRRect; +class SkConservativeClip { + SkIRect fBounds; + const SkIRect* fClipRestrictionRect; + + inline void applyClipRestriction(SkRegion::Op op, SkIRect* bounds) { + if (op >= SkRegion::kUnion_Op && fClipRestrictionRect + && !fClipRestrictionRect->isEmpty()) { + if (!bounds->intersect(*fClipRestrictionRect)) { + bounds->setEmpty(); + } + } + } + +public: + SkConservativeClip() : fBounds(SkIRect::MakeEmpty()), fClipRestrictionRect(nullptr) {} + + bool isEmpty() const { return fBounds.isEmpty(); } + bool isRect() const { return true; } + const SkIRect& getBounds() const { return fBounds; } + + void setEmpty() { fBounds.setEmpty(); } + void setRect(const SkIRect& r) { fBounds = r; } + void setDeviceClipRestriction(const SkIRect* rect) { + fClipRestrictionRect = rect; + } + + void op(const SkRect&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA); + void op(const SkRRect&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA); + void op(const SkPath&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA); + void op(const SkRegion&, SkRegion::Op); + void op(const SkIRect&, SkRegion::Op); +}; + /** * Wraps a SkRegion and SkAAClip, so we have a single object that can represent either our * BW or antialiased clips. @@ -24,8 +57,8 @@ class SkRRect; */ class SkRasterClip { public: - SkRasterClip(bool forceConservativeRects = false); - SkRasterClip(const SkIRect&, bool forceConservativeRects = false); + SkRasterClip(); + SkRasterClip(const SkIRect&); SkRasterClip(const SkRegion&); SkRasterClip(const SkRasterClip&); ~SkRasterClip(); @@ -37,8 +70,6 @@ public: return !(*this == other); } - bool isForceConservativeRects() const { return fForceConservativeRects; } - bool isBW() const { return fIsBW; } bool isAA() const { return !fIsBW; } const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; } @@ -94,14 +125,18 @@ public: void validate() const {} #endif + void setDeviceClipRestriction(const SkIRect* rect) { + fClipRestrictionRect = rect; + } + private: SkRegion fBW; SkAAClip fAA; - bool fForceConservativeRects; bool fIsBW; // these 2 are caches based on querying the right obj based on fIsBW bool fIsEmpty; bool fIsRect; + const SkIRect* fClipRestrictionRect = nullptr; bool computeIsEmpty() const { return fIsBW ? fBW.isEmpty() : fAA.isEmpty(); @@ -131,6 +166,24 @@ private: bool setPath(const SkPath& path, const SkIRect& clip, bool doAA); bool op(const SkRasterClip&, SkRegion::Op); bool setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse); + + inline void applyClipRestriction(SkRegion::Op op, SkIRect* bounds) { + if (op >= SkRegion::kUnion_Op && fClipRestrictionRect + && !fClipRestrictionRect->isEmpty()) { + if (!bounds->intersect(*fClipRestrictionRect)) { + bounds->setEmpty(); + } + } + } + + inline void applyClipRestriction(SkRegion::Op op, SkRect* bounds) { + if (op >= SkRegion::kUnion_Op && fClipRestrictionRect + && !fClipRestrictionRect->isEmpty()) { + if (!bounds->intersect(SkRect::Make(*fClipRestrictionRect))) { + bounds->setEmpty(); + } + } + } }; class SkAutoRasterClipValidate : SkNoncopyable { diff --git a/gfx/skia/skia/src/core/SkRasterClipStack.h b/gfx/skia/skia/src/core/SkRasterClipStack.h new file mode 100644 index 000000000000..f3e3b17df78c --- /dev/null +++ b/gfx/skia/skia/src/core/SkRasterClipStack.h @@ -0,0 +1,173 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRasterClipStack_DEFINED +#define SkRasterClipStack_DEFINED + +#include "SkClipOp.h" +#include "SkDeque.h" +#include "SkRasterClip.h" + +template class SkTStack { +public: + SkTStack(void* storage, size_t size) : fDeque(sizeof(T), storage, size), fTop(nullptr) {} + ~SkTStack() { + while (!fDeque.empty()) { + ((T*)fDeque.back())->~T(); + fDeque.pop_back(); + } + } + + bool empty() const { return fDeque.empty(); } + + int count() const { return fDeque.count(); } + + const T& top() const { + SkASSERT(fTop); + return *fTop; + } + + T& top() { + SkASSERT(fTop); + return *fTop; + } + + T* push_raw() { return (T*)fDeque.push_back(); } + T& push() { + fTop = this->push_raw(); + new (fTop) T(); + return *fTop; + } + T& push(const T& src) { + fTop = this->push_raw(); + new (fTop) T(src); + return *fTop; + } + + void pop() { + fTop->~T(); + fDeque.pop_back(); + fTop = fDeque.empty() ? nullptr : (T*)fDeque.back(); + } + +private: + SkDeque fDeque; + T* fTop; +}; + +class SkRasterClipStack : SkNoncopyable { + int fCounter = 0; +public: + SkRasterClipStack(int width, int height) + : fStack(fStorage, sizeof(fStorage)) + , fRootBounds(SkIRect::MakeWH(width, height)) + { + Rec& rec = fStack.push(); + rec.fRC.setRect(fRootBounds); + rec.fDeferredCount = 0; + SkASSERT(fStack.count() == 1); + } + + void setNewSize(int w, int h) { + fRootBounds.setXYWH(0, 0, w, h); + + SkASSERT(fStack.count() == 1); + Rec& rec = fStack.top(); + SkASSERT(rec.fDeferredCount == 0); + rec.fRC.setRect(fRootBounds); + } + + const SkRasterClip& rc() const { return fStack.top().fRC; } + + void save() { + fCounter += 1; + SkASSERT(fStack.top().fDeferredCount >= 0); + fStack.top().fDeferredCount += 1; + } + + void restore() { + fCounter -= 1; SkASSERT(fCounter >= 0); + if (--fStack.top().fDeferredCount < 0) { + SkASSERT(fStack.top().fDeferredCount == -1); + SkASSERT(fStack.count() > 1); + fStack.pop(); + } + } + + void clipRect(const SkMatrix& ctm, const SkRect& rect, SkClipOp op, bool aa) { + this->writable_rc().op(rect, ctm, fRootBounds, (SkRegion::Op)op, aa); + this->trimIfExpanding(op); + this->validate(); + } + + void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, SkClipOp op, bool aa) { + this->writable_rc().op(rrect, ctm, fRootBounds, (SkRegion::Op)op, aa); + this->trimIfExpanding(op); + this->validate(); + } + + void clipPath(const SkMatrix& ctm, const SkPath& path, SkClipOp op, bool aa) { + this->writable_rc().op(path, ctm, fRootBounds, (SkRegion::Op)op, aa); + this->trimIfExpanding(op); + this->validate(); + } + + void clipRegion(const SkRegion& rgn, SkClipOp op) { + this->writable_rc().op(rgn, (SkRegion::Op)op); + this->trimIfExpanding(op); + this->validate(); + } + + void setDeviceClipRestriction(SkIRect* mutableClipRestriction) { + this->writable_rc().setDeviceClipRestriction(mutableClipRestriction); + } + + void validate() const { +#ifdef SK_DEBUG + const SkRasterClip& clip = this->rc(); + if (fRootBounds.isEmpty()) { + SkASSERT(clip.isEmpty()); + } else if (!clip.isEmpty()) { + SkASSERT(fRootBounds.contains(clip.getBounds())); + } +#endif + } + +private: + struct Rec { + SkRasterClip fRC; + int fDeferredCount; // 0 for a "normal" entry + }; + + enum { + ELEM_COUNT = 16, + PTR_COUNT = ELEM_COUNT * sizeof(Rec) / sizeof(void*) + }; + void* fStorage[PTR_COUNT]; + SkTStack fStack; + SkIRect fRootBounds; + + SkRasterClip& writable_rc() { + SkASSERT(fStack.top().fDeferredCount >= 0); + if (fStack.top().fDeferredCount > 0) { + fStack.top().fDeferredCount -= 1; + fStack.push(fStack.top()); + fStack.top().fDeferredCount = 0; + } + return fStack.top().fRC; + } + + void trimIfExpanding(SkClipOp op) { + if ((int)op > (int)SkClipOp::kIntersect) { + Rec& rec = fStack.top(); + SkASSERT(rec.fDeferredCount == 0); + rec.fRC.op(fRootBounds, SkRegion::kIntersect_Op); + } + } +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkRasterPipeline.cpp b/gfx/skia/skia/src/core/SkRasterPipeline.cpp index 72d5b7b96393..3e3fe3bd859e 100644 --- a/gfx/skia/skia/src/core/SkRasterPipeline.cpp +++ b/gfx/skia/skia/src/core/SkRasterPipeline.cpp @@ -10,50 +10,52 @@ SkRasterPipeline::SkRasterPipeline() {} -void SkRasterPipeline::append(SkRasterPipeline::Fn body, - SkRasterPipeline::Fn tail, - void* ctx) { - // Each stage holds its own context and the next function to call. - // So the pipeline itself has to hold onto the first function that starts the pipeline. - (fBody.empty() ? fBodyStart : fBody.back().fNext) = body; - (fTail.empty() ? fTailStart : fTail.back().fNext) = tail; - - // Each last stage starts with its next function set to JustReturn as a safety net. - // It'll be overwritten by the next call to append(). - fBody.push_back({ &JustReturn, ctx }); - fTail.push_back({ &JustReturn, ctx }); -} - void SkRasterPipeline::append(StockStage stage, void* ctx) { - this->append(SkOpts::stages_4[stage], SkOpts::stages_1_3[stage], ctx); + SkASSERT(stage != from_srgb); + fStages.push_back({stage, ctx}); } void SkRasterPipeline::extend(const SkRasterPipeline& src) { - SkASSERT(src.fBody.count() == src.fTail.count()); + fStages.insert(fStages.end(), + src.fStages.begin(), src.fStages.end()); +} - Fn body = src.fBodyStart, - tail = src.fTailStart; - for (int i = 0; i < src.fBody.count(); i++) { - SkASSERT(src.fBody[i].fCtx == src.fTail[i].fCtx); - this->append(body, tail, src.fBody[i].fCtx); - body = src.fBody[i].fNext; - tail = src.fTail[i].fNext; +void SkRasterPipeline::run(size_t x, size_t n) const { + if (!fStages.empty()) { + if (this->run_with_jumper(x, n)) { + return; + } + SkOpts::run_pipeline(x,n, fStages.data(), SkToInt(fStages.size())); } } -void SkRasterPipeline::run(size_t x, size_t n) { - // It's fastest to start uninitialized if the compilers all let us. If not, next fastest is 0. - Sk4f v; - - while (n >= 4) { - fBodyStart(fBody.begin(), x,0, v,v,v,v, v,v,v,v); - x += 4; - n -= 4; - } - if (n > 0) { - fTailStart(fTail.begin(), x,n, v,v,v,v, v,v,v,v); +void SkRasterPipeline::dump() const { + SkDebugf("SkRasterPipeline, %d stages\n", SkToInt(fStages.size())); + for (auto&& st : fStages) { + const char* name = ""; + switch (st.stage) { + #define M(x) case x: name = #x; break; + SK_RASTER_PIPELINE_STAGES(M) + #undef M + } + SkDebugf("\t%s\n", name); } + SkDebugf("\n"); } -void SK_VECTORCALL SkRasterPipeline::JustReturn(Stage*, size_t, size_t, Sk4f,Sk4f,Sk4f,Sk4f, - Sk4f,Sk4f,Sk4f,Sk4f) {} +// It's pretty easy to start with sound premultiplied linear floats, pack those +// to sRGB encoded bytes, then read them back to linear floats and find them not +// quite premultiplied, with a color channel just a smidge greater than the alpha +// channel. This can happen basically any time we have different transfer +// functions for alpha and colors... sRGB being the only one we draw into. + +// This is an annoying problem with no known good solution. So apply the clamp hammer. + +void SkRasterPipeline::append_from_srgb(SkAlphaType at) { + //this->append(from_srgb); + fStages.push_back({from_srgb, nullptr}); + + if (at == kPremul_SkAlphaType) { + this->append(SkRasterPipeline::clamp_a); + } +} diff --git a/gfx/skia/skia/src/core/SkRasterPipeline.h b/gfx/skia/skia/src/core/SkRasterPipeline.h index 996c7838e37d..ee4479de06d8 100644 --- a/gfx/skia/skia/src/core/SkRasterPipeline.h +++ b/gfx/skia/skia/src/core/SkRasterPipeline.h @@ -8,9 +8,11 @@ #ifndef SkRasterPipeline_DEFINED #define SkRasterPipeline_DEFINED +#include "SkImageInfo.h" #include "SkNx.h" #include "SkTArray.h" #include "SkTypes.h" +#include /** * SkRasterPipeline provides a cheap way to chain together a pixel processing pipeline. @@ -53,105 +55,88 @@ // TODO: There may be a better place to stuff tail, e.g. in the bottom alignment bits of // the Stage*. This mostly matters on 64-bit Windows where every register is precious. +#define SK_RASTER_PIPELINE_STAGES(M) \ + M(move_src_dst) M(move_dst_src) M(swap) \ + M(clamp_0) M(clamp_1) M(clamp_a) \ + M(unpremul) M(premul) \ + M(set_rgb) M(swap_rb) \ + M(from_srgb) M(to_srgb) \ + M(from_2dot2) M(to_2dot2) \ + M(constant_color) M(seed_shader) \ + M(load_a8) M(store_a8) \ + M(load_g8) \ + M(load_565) M(store_565) \ + M(load_4444) M(store_4444) \ + M(load_f16) M(store_f16) \ + M(load_f32) M(store_f32) \ + M(load_8888) M(store_8888) \ + M(load_u16_be) M(load_rgb_u16_be) M(store_u16_be) \ + M(load_tables_u16_be) M(load_tables_rgb_u16_be) \ + M(load_tables) \ + M(scale_u8) M(scale_1_float) \ + M(lerp_u8) M(lerp_565) M(lerp_1_float) \ + M(dstatop) M(dstin) M(dstout) M(dstover) \ + M(srcatop) M(srcin) M(srcout) M(srcover) \ + M(clear) M(modulate) M(multiply) M(plus_) M(screen) M(xor_) \ + M(colorburn) M(colordodge) M(darken) M(difference) \ + M(exclusion) M(hardlight) M(lighten) M(overlay) M(softlight) \ + M(luminance_to_alpha) \ + M(matrix_2x3) M(matrix_3x4) M(matrix_4x5) \ + M(matrix_perspective) \ + M(parametric_r) M(parametric_g) M(parametric_b) \ + M(parametric_a) \ + M(table_r) M(table_g) M(table_b) M(table_a) \ + M(color_lookup_table) M(lab_to_xyz) \ + M(clamp_x) M(mirror_x) M(repeat_x) \ + M(clamp_y) M(mirror_y) M(repeat_y) \ + M(gather_a8) M(gather_g8) M(gather_i8) \ + M(gather_565) M(gather_4444) M(gather_8888) M(gather_f16) \ + M(bilinear_nx) M(bilinear_px) M(bilinear_ny) M(bilinear_py) \ + M(bicubic_n3x) M(bicubic_n1x) M(bicubic_p1x) M(bicubic_p3x) \ + M(bicubic_n3y) M(bicubic_n1y) M(bicubic_p1y) M(bicubic_p3y) \ + M(save_xy) M(accumulate) \ + M(linear_gradient) \ + M(linear_gradient_2stops) \ + M(byte_tables) M(byte_tables_rgb) \ + M(shader_adapter) \ + M(rgb_to_hsl) \ + M(hsl_to_rgb) + class SkRasterPipeline { public: - struct Stage; - using Fn = void(SK_VECTORCALL *)(Stage*, size_t, size_t, Sk4f,Sk4f,Sk4f,Sk4f, - Sk4f,Sk4f,Sk4f,Sk4f); - struct Stage { - template - T ctx() { return static_cast(fCtx); } - - void SK_VECTORCALL next(size_t x, size_t tail, Sk4f v0, Sk4f v1, Sk4f v2, Sk4f v3, - Sk4f v4, Sk4f v5, Sk4f v6, Sk4f v7) { - // Stages are logically a pipeline, and physically are contiguous in an array. - // To get to the next stage, we just increment our pointer to the next array element. - fNext(this+1, x,tail, v0,v1,v2,v3, v4,v5,v6,v7); - } - - // It makes next() a good bit cheaper if we hold the next function to call here, - // rather than logically simpler choice of the function implementing this stage. - Fn fNext; - void* fCtx; - }; - - SkRasterPipeline(); - // Run the pipeline constructed with append(), walking x through [x,x+n), - // generally in 4-pixel steps, with perhaps one jagged tail step. - void run(size_t x, size_t n); - void run(size_t n) { this->run(0, n); } - enum StockStage { - store_565, - store_srgb, - store_f16, - - load_s_565, - load_s_srgb, - load_s_f16, - - load_d_565, - load_d_srgb, - load_d_f16, - - scale_u8, - - lerp_u8, - lerp_565, - lerp_constant_float, - - constant_color, - - dst, - dstatop, - dstin, - dstout, - dstover, - srcatop, - srcin, - srcout, - srcover, - clear, - modulate, - multiply, - plus_, - screen, - xor_, - colorburn, - colordodge, - darken, - difference, - exclusion, - hardlight, - lighten, - overlay, - softlight, - - kNumStockStages, + #define M(stage) stage, + SK_RASTER_PIPELINE_STAGES(M) + #undef M }; void append(StockStage, void* = nullptr); void append(StockStage stage, const void* ctx) { this->append(stage, const_cast(ctx)); } - // Append all stages to this pipeline. void extend(const SkRasterPipeline&); + // Runs the pipeline walking x through [x,x+n). + void run(size_t x, size_t n) const; + + void dump() const; + + struct Stage { + StockStage stage; + void* ctx; + }; + + // Conversion from sRGB can be subtly tricky when premultiplication is involved. + // Use these helpers to keep things sane. + void append_from_srgb(SkAlphaType); + + bool empty() const { return fStages.empty(); } + private: - using Stages = SkSTArray<10, Stage, /*MEM_COPY=*/true>; + bool run_with_jumper(size_t x, size_t n) const; - void append(Fn body, Fn tail, void*); - - // This no-op default makes fBodyStart and fTailStart unconditionally safe to call, - // and is always the last stage's fNext as a sort of safety net to make sure even a - // buggy pipeline can't walk off its own end. - static void SK_VECTORCALL JustReturn(Stage*, size_t, size_t, Sk4f,Sk4f,Sk4f,Sk4f, - Sk4f,Sk4f,Sk4f,Sk4f); - Stages fBody, - fTail; - Fn fBodyStart = &JustReturn, - fTailStart = &JustReturn; + std::vector fStages; }; #endif//SkRasterPipeline_DEFINED diff --git a/gfx/skia/skia/src/core/SkRasterPipelineBlitter.cpp b/gfx/skia/skia/src/core/SkRasterPipelineBlitter.cpp index 91d60bee3aac..a926b43efa0e 100644 --- a/gfx/skia/skia/src/core/SkRasterPipelineBlitter.cpp +++ b/gfx/skia/skia/src/core/SkRasterPipelineBlitter.cpp @@ -5,29 +5,27 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkBlitter.h" +#include "SkBlendModePriv.h" #include "SkColor.h" #include "SkColorFilter.h" #include "SkOpts.h" #include "SkPM4f.h" +#include "SkPM4fPriv.h" #include "SkRasterPipeline.h" #include "SkShader.h" -#include "SkXfermode.h" +#include "SkUtils.h" class SkRasterPipelineBlitter : public SkBlitter { public: - static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkTBlitterAllocator*); + static SkBlitter* Create(const SkPixmap&, const SkPaint&, const SkMatrix& ctm, + SkArenaAlloc*); - SkRasterPipelineBlitter(SkPixmap dst, - SkRasterPipeline shader, - SkRasterPipeline colorFilter, - SkRasterPipeline xfermode, - SkPM4f paintColor) + SkRasterPipelineBlitter(SkPixmap dst, SkBlendMode blend, SkPM4f paintColor) : fDst(dst) - , fShader(shader) - , fColorFilter(colorFilter) - , fXfermode(xfermode) + , fBlend(blend) , fPaintColor(paintColor) {} @@ -40,144 +38,231 @@ public: // blits using something like a SkRasterPipeline::runFew() method. private: - void append_load_d(SkRasterPipeline*, const void*) const; - void append_store (SkRasterPipeline*, void*) const; + void append_load_d(SkRasterPipeline*) const; + void append_blend (SkRasterPipeline*) const; + void maybe_clamp (SkRasterPipeline*) const; + void append_store (SkRasterPipeline*) const; SkPixmap fDst; - SkRasterPipeline fShader, fColorFilter, fXfermode; + SkBlendMode fBlend; SkPM4f fPaintColor; + SkRasterPipeline fShader; + + // We may be able to specialize blitH() into a memset. + bool fCanMemsetInBlitH = false; + uint64_t fMemsetColor = 0; // Big enough for largest dst format, F16. + + // Built lazily on first use. + SkRasterPipeline fBlitH, + fBlitAntiH, + fBlitMaskA8, + fBlitMaskLCD16; + + // These values are pointed to by the blit pipelines above, + // which allows us to adjust them from call to call. + void* fDstPtr = nullptr; + const void* fMaskPtr = nullptr; + float fCurrentCoverage = 0.0f; + int fCurrentY = 0; typedef SkBlitter INHERITED; }; SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst, const SkPaint& paint, - SkTBlitterAllocator* alloc) { - return SkRasterPipelineBlitter::Create(dst, paint, alloc); + const SkMatrix& ctm, + SkArenaAlloc* alloc) { + return SkRasterPipelineBlitter::Create(dst, paint, ctm, alloc); } static bool supported(const SkImageInfo& info) { switch (info.colorType()) { + case kAlpha_8_SkColorType: return true; + case kRGB_565_SkColorType: return true; case kN32_SkColorType: return info.gammaCloseToSRGB(); case kRGBA_F16_SkColorType: return true; - case kRGB_565_SkColorType: return true; default: return false; } } -template -static bool append_effect_stages(const Effect* effect, SkRasterPipeline* pipeline) { - return !effect || effect->appendStages(pipeline); -} - - SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, const SkPaint& paint, - SkTBlitterAllocator* alloc) { - if (!supported(dst.info())) { - return nullptr; - } - if (paint.getShader()) { - return nullptr; // TODO: need to work out how shaders and their contexts work - } - - SkRasterPipeline shader, colorFilter, xfermode; - if (!append_effect_stages(paint.getColorFilter(), &colorFilter) || - !append_effect_stages(SkXfermode::Peek(paint.getBlendMode()), &xfermode )) { - return nullptr; - } - - uint32_t paintColor = paint.getColor(); - - SkColor4f color; - if (SkImageInfoIsGammaCorrect(dst.info())) { - color = SkColor4f::FromColor(paintColor); - } else { - swizzle_rb(SkNx_cast(Sk4b::Load(&paintColor)) * (1/255.0f)).store(&color); - } - - auto blitter = alloc->createT( + const SkMatrix& ctm, + SkArenaAlloc* alloc) { + auto blitter = alloc->make( dst, - shader, colorFilter, xfermode, - color.premul()); + paint.getBlendMode(), + SkPM4f_from_SkColor(paint.getColor(), dst.colorSpace())); - if (!paint.getShader()) { - blitter->fShader.append(SkRasterPipeline::constant_color, &blitter->fPaintColor); + + SkBlendMode* blend = &blitter->fBlend; + SkPM4f* paintColor = &blitter->fPaintColor; + SkRasterPipeline* pipeline = &blitter->fShader; + + SkShader* shader = paint.getShader(); + SkColorFilter* colorFilter = paint.getColorFilter(); + + // TODO: all temporary + if (!supported(dst.info()) || !SkBlendMode_AppendStages(*blend)) { + return nullptr; } - if (paint.isSrcOver()) { - blitter->fXfermode.append(SkRasterPipeline::srcover); + + bool is_opaque = paintColor->a() == 1.0f, + is_constant = true; + if (shader) { + pipeline->append(SkRasterPipeline::seed_shader, &blitter->fCurrentY); + if (!shader->appendStages(pipeline, dst.colorSpace(), alloc, ctm, paint)) { + return nullptr; + } + if (!is_opaque) { + pipeline->append(SkRasterPipeline::scale_1_float, + &paintColor->fVec[SkPM4f::A]); + } + + is_opaque = is_opaque && shader->isOpaque(); + is_constant = shader->isConstant(); + } else { + pipeline->append(SkRasterPipeline::constant_color, paintColor); + } + + if (colorFilter) { + if (!colorFilter->appendStages(pipeline, dst.colorSpace(), alloc, is_opaque)) { + return nullptr; + } + is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); + } + + if (is_constant) { + pipeline->append(SkRasterPipeline::store_f32, &paintColor); + pipeline->run(0,1); + + *pipeline = SkRasterPipeline(); + pipeline->append(SkRasterPipeline::constant_color, paintColor); + + is_opaque = paintColor->a() == 1.0f; + } + + if (is_opaque && *blend == SkBlendMode::kSrcOver) { + *blend = SkBlendMode::kSrc; + } + + if (is_constant && *blend == SkBlendMode::kSrc) { + SkRasterPipeline p; + p.extend(*pipeline); + blitter->fDstPtr = &blitter->fMemsetColor; + blitter->append_store(&p); + p.run(0,1); + + blitter->fCanMemsetInBlitH = true; } return blitter; } -void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p, const void* dst) const { +void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p) const { SkASSERT(supported(fDst.info())); + p->append(SkRasterPipeline::move_src_dst); switch (fDst.info().colorType()) { - case kN32_SkColorType: - if (fDst.info().gammaCloseToSRGB()) { - p->append(SkRasterPipeline::load_d_srgb, dst); - } - break; - case kRGBA_F16_SkColorType: - p->append(SkRasterPipeline::load_d_f16, dst); - break; - case kRGB_565_SkColorType: - p->append(SkRasterPipeline::load_d_565, dst); - break; + case kAlpha_8_SkColorType: p->append(SkRasterPipeline::load_a8, &fDstPtr); break; + case kRGB_565_SkColorType: p->append(SkRasterPipeline::load_565, &fDstPtr); break; + case kBGRA_8888_SkColorType: + case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::load_8888, &fDstPtr); break; + case kRGBA_F16_SkColorType: p->append(SkRasterPipeline::load_f16, &fDstPtr); break; + default: break; + } + if (fDst.info().colorType() == kBGRA_8888_SkColorType) { + p->append(SkRasterPipeline::swap_rb); + } + if (fDst.info().gammaCloseToSRGB()) { + p->append_from_srgb(fDst.info().alphaType()); + } + p->append(SkRasterPipeline::swap); +} + +void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p) const { + if (fDst.info().gammaCloseToSRGB()) { + p->append(SkRasterPipeline::to_srgb); + } + if (fDst.info().colorType() == kBGRA_8888_SkColorType) { + p->append(SkRasterPipeline::swap_rb); + } + + SkASSERT(supported(fDst.info())); + switch (fDst.info().colorType()) { + case kAlpha_8_SkColorType: p->append(SkRasterPipeline::store_a8, &fDstPtr); break; + case kRGB_565_SkColorType: p->append(SkRasterPipeline::store_565, &fDstPtr); break; + case kBGRA_8888_SkColorType: + case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::store_8888, &fDstPtr); break; + case kRGBA_F16_SkColorType: p->append(SkRasterPipeline::store_f16, &fDstPtr); break; default: break; } } -void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p, void* dst) const { - SkASSERT(supported(fDst.info())); +void SkRasterPipelineBlitter::append_blend(SkRasterPipeline* p) const { + SkAssertResult(SkBlendMode_AppendStages(fBlend, p)); +} - switch (fDst.info().colorType()) { - case kN32_SkColorType: - if (fDst.info().gammaCloseToSRGB()) { - p->append(SkRasterPipeline::store_srgb, dst); - } - break; - case kRGBA_F16_SkColorType: - p->append(SkRasterPipeline::store_f16, dst); - break; - case kRGB_565_SkColorType: - p->append(SkRasterPipeline::store_565, dst); - break; - default: break; +void SkRasterPipelineBlitter::maybe_clamp(SkRasterPipeline* p) const { + if (SkBlendMode_CanOverflow(fBlend)) { + p->append(SkRasterPipeline::clamp_a); } } void SkRasterPipelineBlitter::blitH(int x, int y, int w) { - auto dst = fDst.writable_addr(0,y); + fDstPtr = fDst.writable_addr(0,y); + fCurrentY = y; - SkRasterPipeline p; - p.extend(fShader); - p.extend(fColorFilter); - this->append_load_d(&p, dst); - p.extend(fXfermode); - this->append_store(&p, dst); + if (fCanMemsetInBlitH) { + switch (fDst.shiftPerPixel()) { + case 0: memset ((uint8_t *)fDstPtr + x, fMemsetColor, w); return; + case 1: sk_memset16((uint16_t*)fDstPtr + x, fMemsetColor, w); return; + case 2: sk_memset32((uint32_t*)fDstPtr + x, fMemsetColor, w); return; + case 3: sk_memset64((uint64_t*)fDstPtr + x, fMemsetColor, w); return; + default: break; + } + } - p.run(x, w); + auto& p = fBlitH; + if (p.empty()) { + p.extend(fShader); + if (fBlend != SkBlendMode::kSrc) { + this->append_load_d(&p); + this->append_blend(&p); + this->maybe_clamp(&p); + } + this->append_store(&p); + } + p.run(x,w); } void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) { - auto dst = fDst.writable_addr(0,y); - float coverage; - - SkRasterPipeline p; - p.extend(fShader); - p.extend(fColorFilter); - this->append_load_d(&p, dst); - p.extend(fXfermode); - p.append(SkRasterPipeline::lerp_constant_float, &coverage); - this->append_store(&p, dst); + auto& p = fBlitAntiH; + if (p.empty()) { + p.extend(fShader); + if (fBlend == SkBlendMode::kSrcOver) { + p.append(SkRasterPipeline::scale_1_float, &fCurrentCoverage); + this->append_load_d(&p); + this->append_blend(&p); + } else { + this->append_load_d(&p); + this->append_blend(&p); + p.append(SkRasterPipeline::lerp_1_float, &fCurrentCoverage); + } + this->maybe_clamp(&p); + this->append_store(&p); + } + fDstPtr = fDst.writable_addr(0,y); + fCurrentY = y; for (int16_t run = *runs; run > 0; run = *runs) { - coverage = *aa * (1/255.0f); - p.run(x, run); - + switch (*aa) { + case 0x00: break; + case 0xff: this->blitH(x,y,run); break; + default: + fCurrentCoverage = *aa * (1/255.0f); + p.run(x,run); + } x += run; runs += run; aa += run; @@ -190,26 +275,49 @@ void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) return INHERITED::blitMask(mask, clip); } + if (mask.fFormat == SkMask::kA8_Format && fBlitMaskA8.empty()) { + auto& p = fBlitMaskA8; + p.extend(fShader); + if (fBlend == SkBlendMode::kSrcOver) { + p.append(SkRasterPipeline::scale_u8, &fMaskPtr); + this->append_load_d(&p); + this->append_blend(&p); + } else { + this->append_load_d(&p); + this->append_blend(&p); + p.append(SkRasterPipeline::lerp_u8, &fMaskPtr); + } + this->maybe_clamp(&p); + this->append_store(&p); + } + + if (mask.fFormat == SkMask::kLCD16_Format && fBlitMaskLCD16.empty()) { + auto& p = fBlitMaskLCD16; + p.extend(fShader); + this->append_load_d(&p); + this->append_blend(&p); + p.append(SkRasterPipeline::lerp_565, &fMaskPtr); + this->maybe_clamp(&p); + this->append_store(&p); + } + int x = clip.left(); for (int y = clip.top(); y < clip.bottom(); y++) { - auto dst = fDst.writable_addr(0,y); + fDstPtr = fDst.writable_addr(0,y); + fCurrentY = y; - SkRasterPipeline p; - p.extend(fShader); - p.extend(fColorFilter); - this->append_load_d(&p, dst); - p.extend(fXfermode); switch (mask.fFormat) { case SkMask::kA8_Format: - p.append(SkRasterPipeline::lerp_u8, mask.getAddr8(x,y)-x); + fMaskPtr = mask.getAddr8(x,y)-x; + fBlitMaskA8.run(x,clip.width()); break; case SkMask::kLCD16_Format: - p.append(SkRasterPipeline::lerp_565, mask.getAddrLCD16(x,y)-x); + fMaskPtr = mask.getAddrLCD16(x,y)-x; + fBlitMaskLCD16.run(x,clip.width()); + break; + default: + // TODO break; - default: break; } - this->append_store(&p, dst); - - p.run(x, clip.width()); } } diff --git a/gfx/skia/skia/src/core/SkReadBuffer.cpp b/gfx/skia/skia/src/core/SkReadBuffer.cpp index 7679622c5839..33e1d025ddcc 100644 --- a/gfx/skia/skia/src/core/SkReadBuffer.cpp +++ b/gfx/skia/skia/src/core/SkReadBuffer.cpp @@ -7,10 +7,10 @@ #include "SkBitmap.h" #include "SkDeduper.h" -#include "SkErrorInternals.h" #include "SkImage.h" #include "SkImageDeserializer.h" #include "SkImageGenerator.h" +#include "SkMakeUnique.h" #include "SkReadBuffer.h" #include "SkStream.h" #include "SkTypeface.h" @@ -29,9 +29,9 @@ namespace { static sk_sp MakeEmptyImage(int width, int height) { return SkImage::MakeFromGenerator( - new EmptyImageGenerator(SkImageInfo::MakeN32Premul(width, height))); + skstd::make_unique(SkImageInfo::MakeN32Premul(width, height))); } - + } // anonymous namespace @@ -225,9 +225,7 @@ sk_sp SkReadBuffer::readBitmapAsImage() { if (this->readBool()) { this->readUInt(); // Bitmap index this->readUInt(); // Bitmap generation ID - SkErrorInternals::SetError(kParseError_SkError, "SkWriteBuffer::writeBitmap " - "stored the SkBitmap in an SkBitmapHeap, but " - "that feature is no longer supported."); + // Old unsupported SkBitmapHeap format. No longer supported. } else { // The writer stored false, meaning the SkBitmap was not stored in an SkBitmapHeap. const size_t length = this->readUInt(); @@ -246,13 +244,11 @@ sk_sp SkReadBuffer::readBitmapAsImage() { return image; } - // This bitmap was encoded when written, but we are unable to decode, possibly due to - // not having a decoder. - SkErrorInternals::SetError(kParseError_SkError, - "Could not decode bitmap. Resulting bitmap will be empty."); - // Even though we weren't able to decode the pixels, the readbuffer should still be - // intact, so we return true with an empty bitmap, so we don't force an abort of the - // larger deserialize. + // This bitmap was encoded when written, but we are unable to + // decode, possibly due to not having a decoder. Even though we + // weren't able to decode the pixels, the readbuffer should still + // be intact, so we return true with an empty bitmap, so we don't + // force an abort of the larger deserialize. return MakeEmptyImage(width, height); } else { SkBitmap bitmap; @@ -315,8 +311,8 @@ sk_sp SkReadBuffer::readTypeface() { if (fInflator) { return sk_ref_sp(fInflator->getTypeface(this->read32())); } - - uint32_t index = fReader.readU32(); + + uint32_t index = this->readUInt(); if (0 == index || index > (unsigned)fTFCount) { return nullptr; } else { diff --git a/gfx/skia/skia/src/core/SkReadBuffer.h b/gfx/skia/skia/src/core/SkReadBuffer.h index 6b0d332e0f43..014e034020be 100644 --- a/gfx/skia/skia/src/core/SkReadBuffer.h +++ b/gfx/skia/skia/src/core/SkReadBuffer.h @@ -23,7 +23,7 @@ #include "SkShader.h" #include "SkTHash.h" #include "SkWriteBuffer.h" -#include "SkXfermode.h" +#include "SkXfermodePriv.h" class SkBitmap; class SkImage; @@ -70,6 +70,8 @@ public: kBlurMaskFilterWritesOccluder = 47, kGradientShaderFloatColor_Version = 49, kXfermodeToBlendMode_Version = 50, + kXfermodeToBlendMode2_Version = 51, + kTextBlobImplicitRunCount_Version = 52, }; /** @@ -105,8 +107,6 @@ public: bool isPtr64Bit() const { return SkToBool(fFlags & kPtrIs64Bit_Flag); } bool isValidating() const { return SkToBool(fFlags & kValidation_Flag); } - SkReader32* getReader32() { return &fReader; } - size_t size() { return fReader.size(); } size_t offset() { return fReader.offset(); } bool eof() { return fReader.eof(); } diff --git a/gfx/skia/skia/src/core/SkReader32.h b/gfx/skia/skia/src/core/SkReader32.h index 7e31fb9e2387..1f027f71bbc4 100644 --- a/gfx/skia/skia/src/core/SkReader32.h +++ b/gfx/skia/skia/src/core/SkReader32.h @@ -96,7 +96,7 @@ public: void read(void* dst, size_t size) { SkASSERT(0 == size || dst != nullptr); SkASSERT(ptr_align_4(fCurr)); - memcpy(dst, fCurr, size); + sk_careful_memcpy(dst, fCurr, size); fCurr += SkAlign4(size); SkASSERT(fCurr <= fStop); } diff --git a/gfx/skia/skia/src/core/SkRecord.cpp b/gfx/skia/skia/src/core/SkRecord.cpp index 3685b2d16d8b..3d098c6c8974 100644 --- a/gfx/skia/skia/src/core/SkRecord.cpp +++ b/gfx/skia/skia/src/core/SkRecord.cpp @@ -8,6 +8,9 @@ #include "SkRecord.h" #include +SkRecord::SkRecord() + : fCount(0), fReserved(0), fAlloc(8/*first malloc at 256 bytes*/) {} + SkRecord::~SkRecord() { Destroyer destroyer; for (int i = 0; i < this->count(); i++) { @@ -17,19 +20,14 @@ SkRecord::~SkRecord() { void SkRecord::grow() { SkASSERT(fCount == fReserved); - SkASSERT(fReserved > 0); - fReserved *= 2; + fReserved = fReserved ? fReserved * 2 : 4; fRecords.realloc(fReserved); } size_t SkRecord::bytesUsed() const { - size_t bytes = fAlloc.approxBytesAllocated() + sizeof(SkRecord); - // If fReserved <= kInlineRecords, we've already accounted for fRecords with sizeof(SkRecord). - // When we go over that limit, they're allocated on the heap (and the inline space is wasted). - if (fReserved > kInlineRecords) { - bytes += fReserved * sizeof(Record); - } - return bytes; + return sizeof(SkRecord) + + fReserved * sizeof(Record) + + fAlloc.approxBytesAllocated(); } void SkRecord::defrag() { diff --git a/gfx/skia/skia/src/core/SkRecord.h b/gfx/skia/skia/src/core/SkRecord.h index 79fe5232fb38..3766e3447e82 100644 --- a/gfx/skia/skia/src/core/SkRecord.h +++ b/gfx/skia/skia/src/core/SkRecord.h @@ -25,18 +25,9 @@ // only with SkRecords::* structs defined in SkRecords.h. Your compiler will helpfully yell if you // get this wrong. -class SkRecord : public SkNVRefCnt { - enum { - // TODO: tune these two constants. - kInlineRecords = 4, // Ideally our lower limit on recorded ops per picture. - kInlineAllocLgBytes = 8, // 1<<8 == 256 bytes inline, then SkVarAlloc starting at 512 bytes. - }; +class SkRecord : public SkRefCnt { public: - SkRecord() - : fCount(0) - , fReserved(kInlineRecords) - , fAlloc(kInlineAllocLgBytes+1, // First malloc'd block is 2x as large as fInlineAlloc. - fInlineAlloc, sizeof(fInlineAlloc)) {} + SkRecord(); ~SkRecord(); // Returns the number of canvas commands in this SkRecord. @@ -187,12 +178,11 @@ private: // fRecords needs to be a data structure that can append fixed length data, and need to // support efficient random access and forward iteration. (It doesn't need to be contiguous.) int fCount, fReserved; - SkAutoSTMalloc fRecords; + SkAutoTMalloc fRecords; // fAlloc needs to be a data structure which can append variable length data in contiguous // chunks, returning a stable handle to that data for later retrieval. SkVarAlloc fAlloc; - char fInlineAlloc[1 << kInlineAllocLgBytes]; }; #endif//SkRecord_DEFINED diff --git a/gfx/skia/skia/src/core/SkRecordDraw.cpp b/gfx/skia/skia/src/core/SkRecordDraw.cpp index dca19df1005c..21f9de956bfc 100644 --- a/gfx/skia/skia/src/core/SkRecordDraw.cpp +++ b/gfx/skia/skia/src/core/SkRecordDraw.cpp @@ -20,13 +20,10 @@ void SkRecordDraw(const SkRecord& record, if (bbh) { // Draw only ops that affect pixels in the canvas's current clip. // The SkRecord and BBH were recorded in identity space. This canvas - // is not necessarily in that same space. getClipBounds() returns us + // is not necessarily in that same space. getLocalClipBounds() returns us // this canvas' clip bounds transformed back into identity space, which // lets us query the BBH. - SkRect query; - if (!canvas->getClipBounds(&query)) { - query.setEmpty(); - } + SkRect query = canvas->getLocalClipBounds(); SkTDArray ops; bbh->search(query, &ops); @@ -85,9 +82,9 @@ DRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix))); DRAW(Concat, concat(r.matrix)); DRAW(Translate, translate(r.dx, r.dy)); -DRAW(ClipPath, clipPath(r.path, r.opAA.op, r.opAA.aa)); -DRAW(ClipRRect, clipRRect(r.rrect, r.opAA.op, r.opAA.aa)); -DRAW(ClipRect, clipRect(r.rect, r.opAA.op, r.opAA.aa)); +DRAW(ClipPath, clipPath(r.path, r.opAA.op(), r.opAA.aa())); +DRAW(ClipRRect, clipRRect(r.rrect, r.opAA.op(), r.opAA.aa())); +DRAW(ClipRect, clipRect(r.rect, r.opAA.op(), r.opAA.aa())); DRAW(ClipRegion, clipRegion(r.region, r.op)); #ifdef SK_EXPERIMENTAL_SHADOWING @@ -116,7 +113,7 @@ DRAW(DrawImageNine, drawImageNine(r.image.get(), r.center, r.dst, r.paint)); DRAW(DrawOval, drawOval(r.oval, r.paint)); DRAW(DrawPaint, drawPaint(r.paint)); DRAW(DrawPath, drawPath(r.path, r.paint)); -DRAW(DrawPatch, drawPatch(r.cubics, r.colors, r.texCoords, r.xmode, r.paint)); +DRAW(DrawPatch, drawPatch(r.cubics, r.colors, r.texCoords, r.bmode, r.paint)); DRAW(DrawPicture, drawPicture(r.picture.get(), &r.matrix, r.paint)); #ifdef SK_EXPERIMENTAL_SHADOWING @@ -137,8 +134,7 @@ DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.p DRAW(DrawTextRSXform, drawTextRSXform(r.text, r.byteLength, r.xforms, r.cull, r.paint)); DRAW(DrawAtlas, drawAtlas(r.atlas.get(), r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint)); -DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors, - r.xmode, r.indices, r.indexCount, r.paint)); +DRAW(DrawVertices, drawVertices(r.vertices, r.bmode, r.paint)); DRAW(DrawAnnotation, drawAnnotation(r.rect, r.key.c_str(), r.value.get())); #undef DRAW @@ -457,9 +453,7 @@ private: return this->adjustAndMap(dst, &op.paint); } Bounds bounds(const DrawVertices& op) const { - SkRect dst; - dst.set(op.vertices, op.vertexCount); - return this->adjustAndMap(dst, &op.paint); + return this->adjustAndMap(op.vertices->bounds(), &op.paint); } Bounds bounds(const DrawAtlas& op) const { diff --git a/gfx/skia/skia/src/core/SkRecordOpts.cpp b/gfx/skia/skia/src/core/SkRecordOpts.cpp index a7feec1fb368..07ef19d5a519 100644 --- a/gfx/skia/skia/src/core/SkRecordOpts.cpp +++ b/gfx/skia/skia/src/core/SkRecordOpts.cpp @@ -10,7 +10,6 @@ #include "SkRecordPattern.h" #include "SkRecords.h" #include "SkTDArray.h" -#include "SkXfermode.h" using namespace SkRecords; @@ -173,6 +172,7 @@ void SkRecordNoopSaveRestores(SkRecord* record) { while (apply(&onlyDraws, record) || apply(&noDraws, record)); } +#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK static bool effectively_srcover(const SkPaint* paint) { if (!paint || paint->isSrcOver()) { return true; @@ -193,6 +193,11 @@ struct SaveLayerDrawRestoreNooper { return false; } + if (match->first()->saveLayerFlags & (1U << 31)) { + // can't throw away the layer if the kDontClipToLayer_PrivateSaveLayerFlag is set + return false; + } + // A SaveLayer's bounds field is just a hint, so we should be free to ignore it. SkPaint* layerPaint = match->first()->paint; SkPaint* drawPaint = match->second(); @@ -225,7 +230,7 @@ void SkRecordNoopSaveLayerDrawRestores(SkRecord* record) { SaveLayerDrawRestoreNooper pass; apply(&pass, record); } - +#endif /* For SVG generated: SaveLayer (non-opaque, typically for CSS opacity) @@ -293,7 +298,12 @@ void SkRecordOptimize(SkRecord* record) { // https://bugs.chromium.org/p/skia/issues/detail?id=5548 // SkRecordNoopSaveRestores(record); + // Turn off this optimization completely for Android framework + // because it makes the following Android CTS test fail: + // android.uirendering.cts.testclasses.LayerTests#testSaveLayerClippedWithAlpha +#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK SkRecordNoopSaveLayerDrawRestores(record); +#endif SkRecordMergeSvgOpacityAndFilterLayers(record); record->defrag(); @@ -302,7 +312,10 @@ void SkRecordOptimize(SkRecord* record) { void SkRecordOptimize2(SkRecord* record) { multiple_set_matrices(record); SkRecordNoopSaveRestores(record); + // See why we turn this off in SkRecordOptimize above. +#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK SkRecordNoopSaveLayerDrawRestores(record); +#endif SkRecordMergeSvgOpacityAndFilterLayers(record); record->defrag(); diff --git a/gfx/skia/skia/src/core/SkRecordOpts.h b/gfx/skia/skia/src/core/SkRecordOpts.h index d6531b522686..f9db0698cfcf 100644 --- a/gfx/skia/skia/src/core/SkRecordOpts.h +++ b/gfx/skia/skia/src/core/SkRecordOpts.h @@ -16,9 +16,11 @@ void SkRecordOptimize(SkRecord*); // Turns logical no-op Save-[non-drawing command]*-Restore patterns into actual no-ops. void SkRecordNoopSaveRestores(SkRecord*); +#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK // For some SaveLayer-[drawing command]-Restore patterns, merge the SaveLayer's alpha into the // draw, and no-op the SaveLayer and Restore. void SkRecordNoopSaveLayerDrawRestores(SkRecord*); +#endif // For SVG generated SaveLayer-Save-ClipRect-SaveLayer-3xRestore patterns, merge // the alpha of the first SaveLayer to the second SaveLayer. diff --git a/gfx/skia/skia/src/core/SkRecordPattern.h b/gfx/skia/skia/src/core/SkRecordPattern.h index 45f45724c199..73fe7630c438 100644 --- a/gfx/skia/skia/src/core/SkRecordPattern.h +++ b/gfx/skia/skia/src/core/SkRecordPattern.h @@ -8,6 +8,7 @@ #ifndef SkRecordPattern_DEFINED #define SkRecordPattern_DEFINED +#include "SkRecord.h" #include "SkTLogic.h" namespace SkRecords { diff --git a/gfx/skia/skia/src/core/SkRecordedDrawable.cpp b/gfx/skia/skia/src/core/SkRecordedDrawable.cpp index 9e68be1d25ac..342701a3655e 100644 --- a/gfx/skia/skia/src/core/SkRecordedDrawable.cpp +++ b/gfx/skia/skia/src/core/SkRecordedDrawable.cpp @@ -10,7 +10,6 @@ #include "SkPicturePlayback.h" #include "SkPictureRecord.h" #include "SkPictureRecorder.h" -#include "SkPictureUtils.h" #include "SkRecordedDrawable.h" #include "SkRecordDraw.h" @@ -21,7 +20,7 @@ void SkRecordedDrawable::onDraw(SkCanvas* canvas) { drawables = fDrawableList->begin(); drawableCount = fDrawableList->count(); } - SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, fBBH, nullptr/*callback*/); + SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, fBBH.get(), nullptr); } SkPicture* SkRecordedDrawable::onNewPictureSnapshot() { @@ -34,7 +33,7 @@ SkPicture* SkRecordedDrawable::onNewPictureSnapshot() { size_t subPictureBytes = 0; for (int i = 0; pictList && i < pictList->count(); i++) { - subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]); + subPictureBytes += pictList->begin()[i]->approximateBytesUsed(); } // SkBigPicture will take ownership of a ref on both fRecord and fBBH. // We're not willing to give up our ownership, so we must ref them for SkPicture. @@ -51,10 +50,8 @@ void SkRecordedDrawable::flatten(SkWriteBuffer& buffer) const { SkPictureRecord pictureRecord(SkISize::Make(fBounds.width(), fBounds.height()), 0); // If the query contains the whole picture, don't bother with the bounding box hierarchy. - SkRect clipBounds; - pictureRecord.getClipBounds(&clipBounds); SkBBoxHierarchy* bbh; - if (clipBounds.contains(fBounds)) { + if (pictureRecord.getLocalClipBounds().contains(fBounds)) { bbh = nullptr; } else { bbh = fBBH.get(); @@ -81,13 +78,13 @@ sk_sp SkRecordedDrawable::CreateProc(SkReadBuffer& buffer) { info.setVersion(buffer.getVersion()); info.fCullRect = bounds; info.fFlags = 0; // ??? - SkAutoTDelete pictureData(SkPictureData::CreateFromBuffer(buffer, info)); + std::unique_ptr pictureData(SkPictureData::CreateFromBuffer(buffer, info)); if (!pictureData) { return nullptr; } // Create a drawable. - SkPicturePlayback playback(pictureData); + SkPicturePlayback playback(pictureData.get()); SkPictureRecorder recorder; playback.draw(recorder.beginRecording(bounds), nullptr, &buffer); return recorder.finishRecordingAsDrawable(); diff --git a/gfx/skia/skia/src/core/SkRecordedDrawable.h b/gfx/skia/skia/src/core/SkRecordedDrawable.h index 7e2d9bc599ee..c7ba74143e6a 100644 --- a/gfx/skia/skia/src/core/SkRecordedDrawable.h +++ b/gfx/skia/skia/src/core/SkRecordedDrawable.h @@ -4,6 +4,8 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#ifndef SkRecordedDrawable_DEFINED +#define SkRecordedDrawable_DEFINED #include "SkBBoxHierarchy.h" #include "SkDrawable.h" @@ -12,11 +14,11 @@ class SkRecordedDrawable : public SkDrawable { public: - SkRecordedDrawable(SkRecord* record, SkBBoxHierarchy* bbh, SkDrawableList* drawableList, - const SkRect& bounds) - : fRecord(SkRef(record)) - , fBBH(SkSafeRef(bbh)) - , fDrawableList(drawableList) // we take ownership + SkRecordedDrawable(sk_sp record, sk_sp bbh, + std::unique_ptr drawableList, const SkRect& bounds) + : fRecord(std::move(record)) + , fBBH(std::move(bbh)) + , fDrawableList(std::move(drawableList)) , fBounds(bounds) {} @@ -34,8 +36,9 @@ protected: SkPicture* onNewPictureSnapshot() override; private: - SkAutoTUnref fRecord; - SkAutoTUnref fBBH; - SkAutoTDelete fDrawableList; + sk_sp fRecord; + sk_sp fBBH; + std::unique_ptr fDrawableList; const SkRect fBounds; }; +#endif // SkRecordedDrawable_DEFINED diff --git a/gfx/skia/skia/src/core/SkRecorder.cpp b/gfx/skia/skia/src/core/SkRecorder.cpp index 08c73700d857..0f2891a825af 100644 --- a/gfx/skia/skia/src/core/SkRecorder.cpp +++ b/gfx/skia/skia/src/core/SkRecorder.cpp @@ -10,7 +10,6 @@ #include "SkImage.h" #include "SkPatchUtils.h" #include "SkPicture.h" -#include "SkPictureUtils.h" #include "SkRecorder.h" #include "SkSurface.h" @@ -37,14 +36,14 @@ void SkDrawableList::append(SkDrawable* drawable) { /////////////////////////////////////////////////////////////////////////////////////////////// SkRecorder::SkRecorder(SkRecord* record, int width, int height, SkMiniRecorder* mr) - : SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag) + : SkNoDrawCanvas(width, height) , fDrawPictureMode(Record_DrawPictureMode) , fApproxBytesUsedBySubPictures(0) , fRecord(record) , fMiniRecorder(mr) {} SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds, SkMiniRecorder* mr) - : SkCanvas(bounds.roundOut(), SkCanvas::kConservativeRasterClip_InitFlag) + : SkNoDrawCanvas(bounds.roundOut()) , fDrawPictureMode(Record_DrawPictureMode) , fApproxBytesUsedBySubPictures(0) , fRecord(record) @@ -75,8 +74,8 @@ void SkRecorder::forgetRecord() { #define TRY_MINIRECORDER(method, ...) \ if (fMiniRecorder && fMiniRecorder->method(__VA_ARGS__)) { return; } -// For methods which must call back into SkCanvas. -#define INHERITED(method, ...) this->SkCanvas::method(__VA_ARGS__) +// For methods which must call back into SkNoDrawCanvas. +#define INHERITED(method, ...) this->SkNoDrawCanvas::method(__VA_ARGS__) // Use copy() only for optional arguments, to be copied if present or skipped if not. // (For most types we just pass by value and let copy constructors do their thing.) @@ -301,7 +300,7 @@ void SkRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, const SkPaint* paint) { if (fDrawPictureMode == Record_DrawPictureMode) { - fApproxBytesUsedBySubPictures += SkPictureUtils::ApproximateBytesUsed(pic); + fApproxBytesUsedBySubPictures += pic->approximateBytesUsed(); APPEND(DrawPicture, this->copy(paint), sk_ref_sp(pic), matrix ? *matrix : SkMatrix::I()); } else { SkASSERT(fDrawPictureMode == Playback_DrawPictureMode); @@ -313,7 +312,7 @@ void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, con void SkRecorder::onDrawShadowedPicture(const SkPicture* pic, const SkMatrix* matrix, const SkPaint* paint, const SkShadowParams& params) { if (fDrawPictureMode == Record_DrawPictureMode) { - fApproxBytesUsedBySubPictures += SkPictureUtils::ApproximateBytesUsed(pic); + fApproxBytesUsedBySubPictures += pic->approximateBytesUsed(); APPEND(DrawShadowedPicture, this->copy(paint), sk_ref_sp(pic), matrix ? *matrix : SkMatrix::I(), @@ -327,33 +326,23 @@ void SkRecorder::onDrawShadowedPicture(const SkPicture* pic, const SkMatrix* mat } -void SkRecorder::onDrawVertices(VertexMode vmode, - int vertexCount, const SkPoint vertices[], - const SkPoint texs[], const SkColor colors[], - SkXfermode* xmode, - const uint16_t indices[], int indexCount, const SkPaint& paint) { - APPEND(DrawVertices, paint, - vmode, - vertexCount, - this->copy(vertices, vertexCount), - texs ? this->copy(texs, vertexCount) : nullptr, - colors ? this->copy(colors, vertexCount) : nullptr, - sk_ref_sp(xmode), - this->copy(indices, indexCount), - indexCount); +void SkRecorder::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode, + const SkPaint& paint) { + APPEND(DrawVertices, paint, sk_ref_sp(const_cast(vertices)), bmode); } void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { + const SkPoint texCoords[4], SkBlendMode bmode, + const SkPaint& paint) { APPEND(DrawPatch, paint, cubics ? this->copy(cubics, SkPatchUtils::kNumCtrlPts) : nullptr, colors ? this->copy(colors, SkPatchUtils::kNumCorners) : nullptr, texCoords ? this->copy(texCoords, SkPatchUtils::kNumCorners) : nullptr, - sk_ref_sp(xmode)); + bmode); } void SkRecorder::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], - const SkColor colors[], int count, SkXfermode::Mode mode, + const SkColor colors[], int count, SkBlendMode mode, const SkRect* cull, const SkPaint* paint) { APPEND(DrawAtlas, this->copy(paint), sk_ref_sp(atlas), @@ -382,7 +371,7 @@ SkCanvas::SaveLayerStrategy SkRecorder::getSaveLayerStrategy(const SaveLayerRec& } void SkRecorder::didRestore() { - APPEND(Restore, this->devBounds(), this->getTotalMatrix()); + APPEND(Restore, this->getDeviceClipBounds(), this->getTotalMatrix()); } void SkRecorder::didConcat(const SkMatrix& matrix) { @@ -403,27 +392,27 @@ void SkRecorder::didTranslateZ(SkScalar z) { #endif } -void SkRecorder::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkRecorder::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { INHERITED(onClipRect, rect, op, edgeStyle); SkRecords::ClipOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle); - APPEND(ClipRect, this->devBounds(), rect, opAA); + APPEND(ClipRect, this->getDeviceClipBounds(), rect, opAA); } -void SkRecorder::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkRecorder::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { INHERITED(onClipRRect, rrect, op, edgeStyle); SkRecords::ClipOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle); - APPEND(ClipRRect, this->devBounds(), rrect, opAA); + APPEND(ClipRRect, this->getDeviceClipBounds(), rrect, opAA); } -void SkRecorder::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkRecorder::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { INHERITED(onClipPath, path, op, edgeStyle); SkRecords::ClipOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle); - APPEND(ClipPath, this->devBounds(), path, opAA); + APPEND(ClipPath, this->getDeviceClipBounds(), path, opAA); } -void SkRecorder::onClipRegion(const SkRegion& deviceRgn, ClipOp op) { +void SkRecorder::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { INHERITED(onClipRegion, deviceRgn, op); - APPEND(ClipRegion, this->devBounds(), deviceRgn, op); + APPEND(ClipRegion, this->getDeviceClipBounds(), deviceRgn, op); } sk_sp SkRecorder::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) { diff --git a/gfx/skia/skia/src/core/SkRecorder.h b/gfx/skia/skia/src/core/SkRecorder.h index 8efae17c6e3f..3407fc703246 100644 --- a/gfx/skia/skia/src/core/SkRecorder.h +++ b/gfx/skia/skia/src/core/SkRecorder.h @@ -9,8 +9,8 @@ #define SkRecorder_DEFINED #include "SkBigPicture.h" -#include "SkCanvas.h" #include "SkMiniRecorder.h" +#include "SkNoDrawCanvas.h" #include "SkRecord.h" #include "SkRecords.h" #include "SkTDArray.h" @@ -36,7 +36,7 @@ private: // SkRecorder provides an SkCanvas interface for recording into an SkRecord. -class SkRecorder : public SkCanvas { +class SkRecorder final : public SkNoDrawCanvas { public: // Does not take ownership of the SkRecord. SkRecorder(SkRecord*, int width, int height, SkMiniRecorder* = nullptr); // legacy version @@ -48,7 +48,7 @@ public: size_t approxBytesUsedBySubPictures() const { return fApproxBytesUsedBySubPictures; } SkDrawableList* getDrawableList() const { return fDrawableList.get(); } - SkDrawableList* detachDrawableList() { return fDrawableList.release(); } + std::unique_ptr detachDrawableList() { return std::move(fDrawableList); } // Make SkRecorder forget entirely about its SkRecord*; all calls to SkRecorder will fail. void forgetRecord(); @@ -99,7 +99,7 @@ public: SkScalar y, const SkPaint& paint) override; void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) override; void onDrawPaint(const SkPaint&) override; @@ -124,18 +124,14 @@ public: const SkPaint*) override; void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst, const SkPaint*) override; - void onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], - int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) override; + int count, SkBlendMode, const SkRect* cull, const SkPaint*) override; - void onClipRect(const SkRect& rect, ClipOp, ClipEdgeStyle) override; - void onClipRRect(const SkRRect& rrect, ClipOp, ClipEdgeStyle) override; - void onClipPath(const SkPath& path, ClipOp, ClipEdgeStyle) override; - void onClipRegion(const SkRegion& deviceRgn, ClipOp) override; + void onClipRect(const SkRect& rect, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect& rrect, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath& path, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; @@ -164,16 +160,10 @@ private: template T* copy(const T[], size_t count); - SkIRect devBounds() const { - SkIRect devBounds; - this->getClipDeviceBounds(&devBounds); - return devBounds; - } - DrawPictureMode fDrawPictureMode; size_t fApproxBytesUsedBySubPictures; SkRecord* fRecord; - SkAutoTDelete fDrawableList; + std::unique_ptr fDrawableList; SkMiniRecorder* fMiniRecorder; }; diff --git a/gfx/skia/skia/src/core/SkRect.cpp b/gfx/skia/skia/src/core/SkRect.cpp index 0b2723ab0a55..d868bbb85900 100644 --- a/gfx/skia/skia/src/core/SkRect.cpp +++ b/gfx/skia/skia/src/core/SkRect.cpp @@ -7,6 +7,8 @@ #include "SkRect.h" +#include "SkMalloc.h" + void SkIRect::join(int32_t left, int32_t top, int32_t right, int32_t bottom) { // do nothing if the params are empty if (left >= right || top >= bottom) { diff --git a/gfx/skia/skia/src/core/SkRegion.cpp b/gfx/skia/skia/src/core/SkRegion.cpp index a50425afd8e9..e873ebb4534c 100644 --- a/gfx/skia/skia/src/core/SkRegion.cpp +++ b/gfx/skia/skia/src/core/SkRegion.cpp @@ -196,14 +196,15 @@ char* SkRegion::toString() { if (result == nullptr) { return nullptr; } - count = sprintf(result, "SkRegion("); + count = snprintf(result, max, "SkRegion("); iter.reset(*this); while (!iter.done()) { const SkIRect& r = iter.rect(); - count += sprintf(result+count, "(%d,%d,%d,%d)", r.fLeft, r.fTop, r.fRight, r.fBottom); + count += snprintf(result+count, max - count, + "(%d,%d,%d,%d)", r.fLeft, r.fTop, r.fRight, r.fBottom); iter.next(); } - count += sprintf(result+count, ")"); + count += snprintf(result+count, max - count, ")"); return result; } #endif @@ -283,6 +284,7 @@ bool SkRegion::setRuns(RunType runs[], int count) { if (!this->isComplex() || fRunHead->fRunCount != count) { this->freeRuns(); this->allocateRuns(count); + SkASSERT(this->isComplex()); } // must call this before we can write directly into runs() @@ -546,6 +548,7 @@ void SkRegion::translate(int dx, int dy, SkRegion* dst) const { } else { SkRegion tmp; tmp.allocateRuns(*fRunHead); + SkASSERT(tmp.isComplex()); tmp.fBounds = fBounds; dst->swap(tmp); } @@ -1126,29 +1129,113 @@ size_t SkRegion::writeToMemory(void* storage) const { return buffer.pos(); } +// Validate that a memory sequence is a valid region. +// Try to check all possible errors. +// never read beyond &runs[runCount-1]. +static bool validate_run(const int32_t* runs, + int runCount, + const SkIRect& givenBounds, + int32_t ySpanCount, + int32_t intervalCount) { + // Region Layout: + // Top ( Bottom Span_Interval_Count ( Left Right )* Sentinel )+ Sentinel + if (ySpanCount < 1 || intervalCount < 2 || runCount != 2 + 3 * ySpanCount + 2 * intervalCount) { + return false; + } + SkASSERT(runCount >= 7); // 7==SkRegion::kRectRegionRuns + // quick sanity check: + if (runs[runCount - 1] != SkRegion::kRunTypeSentinel || + runs[runCount - 2] != SkRegion::kRunTypeSentinel) { + return false; + } + const int32_t* const end = runs + runCount; + SkIRect bounds = {0, 0, 0 ,0}; // calulated bounds + SkIRect rect = {0, 0, 0, 0}; // current rect + rect.fTop = *runs++; + if (rect.fTop == SkRegion::kRunTypeSentinel) { + return false; // no rect can contain SkRegion::kRunTypeSentinel + } + do { + --ySpanCount; + if (ySpanCount < 0) { + return false; // too many yspans + } + rect.fBottom = *runs++; + if (rect.fBottom == SkRegion::kRunTypeSentinel) { + return false; + } + int32_t xIntervals = *runs++; + SkASSERT(runs < end); + if (xIntervals < 0 || runs + 1 + 2 * xIntervals > end) { + return false; + } + intervalCount -= xIntervals; + if (intervalCount < 0) { + return false; // too many intervals + } + while (xIntervals-- > 0) { + rect.fLeft = *runs++; + rect.fRight = *runs++; + if (rect.fLeft == SkRegion::kRunTypeSentinel || + rect.fRight == SkRegion::kRunTypeSentinel || rect.isEmpty()) { + return false; + } + bounds.join(rect); + } + if (*runs++ != SkRegion::kRunTypeSentinel) { + return false; // required check sentinal. + } + rect.fTop = rect.fBottom; + SkASSERT(runs < end); + } while (*runs != SkRegion::kRunTypeSentinel); + ++runs; + if (ySpanCount != 0 || intervalCount != 0 || givenBounds != bounds) { + return false; + } + SkASSERT(runs == end); // if ySpanCount && intervalCount are right, must be correct length. + return true; +} size_t SkRegion::readFromMemory(const void* storage, size_t length) { - SkRBufferWithSizeCheck buffer(storage, length); - SkRegion tmp; - int32_t count; + SkRBuffer buffer(storage, length); + SkRegion tmp; + int32_t count; - if (buffer.readS32(&count) && (count >= 0) && buffer.read(&tmp.fBounds, sizeof(tmp.fBounds))) { + // Serialized Region Format: + // Empty: + // -1 + // Simple Rect: + // 0 LEFT TOP RIGHT BOTTOM + // Complex Region: + // COUNT LEFT TOP RIGHT BOTTOM Y_SPAN_COUNT TOTAL_INTERVAL_COUNT [RUNS....] + if (!buffer.readS32(&count) || count < -1) { + return 0; + } + if (count >= 0) { + if (!buffer.read(&tmp.fBounds, sizeof(tmp.fBounds)) || tmp.fBounds.isEmpty()) { + return 0; // Short buffer or bad bounds for non-empty region; report failure. + } if (count == 0) { tmp.fRunHead = SkRegion_gRectRunHeadPtr; } else { int32_t ySpanCount, intervalCount; - if (buffer.readS32(&ySpanCount) && buffer.readS32(&intervalCount) && - intervalCount > 1) { - tmp.allocateRuns(count, ySpanCount, intervalCount); - buffer.read(tmp.fRunHead->writable_runs(), count * sizeof(RunType)); + if (!buffer.readS32(&ySpanCount) || + !buffer.readS32(&intervalCount) || + buffer.available() < count * sizeof(int32_t)) { + return 0; } + if (!validate_run((const int32_t*)((const char*)storage + buffer.pos()), count, + tmp.fBounds, ySpanCount, intervalCount)) { + return 0; // invalid runs, don't even allocate + } + tmp.allocateRuns(count, ySpanCount, intervalCount); + SkASSERT(tmp.isComplex()); + SkAssertResult(buffer.read(tmp.fRunHead->writable_runs(), count * sizeof(int32_t))); } } - size_t sizeRead = 0; - if (buffer.isValid()) { - this->swap(tmp); - sizeRead = buffer.pos(); - } - return sizeRead; + SkASSERT(tmp.isValid()); + SkASSERT(buffer.isValid()); + this->swap(tmp); + return buffer.pos(); } /////////////////////////////////////////////////////////////////////////////// @@ -1160,103 +1247,24 @@ const SkRegion& SkRegion::GetEmptyRegion() { /////////////////////////////////////////////////////////////////////////////// -#ifdef SK_DEBUG - -// Starts with first X-interval, and returns a ptr to the X-sentinel -static const SkRegion::RunType* skip_intervals_slow(const SkRegion::RunType runs[]) { - // want to track that our intevals are all disjoint, such that - // prev-right < next-left. We rely on this optimization in places such as - // contains(). - // - SkRegion::RunType prevR = -SkRegion::kRunTypeSentinel; - - while (runs[0] < SkRegion::kRunTypeSentinel) { - SkASSERT(prevR < runs[0]); - SkASSERT(runs[0] < runs[1]); - SkASSERT(runs[1] < SkRegion::kRunTypeSentinel); - prevR = runs[1]; - runs += 2; - } - return runs; -} - -static void compute_bounds(const SkRegion::RunType runs[], - SkIRect* bounds, int* ySpanCountPtr, - int* intervalCountPtr) { - assert_sentinel(runs[0], false); // top - - int left = SK_MaxS32; - int rite = SK_MinS32; - int bot; - int ySpanCount = 0; - int intervalCount = 0; - - bounds->fTop = *runs++; - do { - bot = *runs++; - SkASSERT(SkRegion::kRunTypeSentinel > bot); - - ySpanCount += 1; - - runs += 1; // skip intervalCount for now - if (*runs < SkRegion::kRunTypeSentinel) { - if (left > *runs) { - left = *runs; - } - - const SkRegion::RunType* prev = runs; - runs = skip_intervals_slow(runs); - int intervals = SkToInt((runs - prev) >> 1); - SkASSERT(prev[-1] == intervals); - intervalCount += intervals; - - if (rite < runs[-1]) { - rite = runs[-1]; - } - } else { - SkASSERT(0 == runs[-1]); // no intervals - } - SkASSERT(SkRegion::kRunTypeSentinel == *runs); - runs += 1; - } while (SkRegion::kRunTypeSentinel != *runs); - - bounds->fLeft = left; - bounds->fRight = rite; - bounds->fBottom = bot; - *ySpanCountPtr = ySpanCount; - *intervalCountPtr = intervalCount; -} - -void SkRegion::validate() const { +bool SkRegion::isValid() const { if (this->isEmpty()) { - // check for explicit empty (the zero rect), so we can compare rects to know when - // two regions are equal (i.e. emptyRectA == emptyRectB) - // this is stricter than just asserting fBounds.isEmpty() - SkASSERT(fBounds.fLeft == 0 && fBounds.fTop == 0 && fBounds.fRight == 0 && fBounds.fBottom == 0); - } else { - SkASSERT(!fBounds.isEmpty()); - if (!this->isRect()) { - SkASSERT(fRunHead->fRefCnt >= 1); - SkASSERT(fRunHead->fRunCount > kRectRegionRuns); - - const RunType* run = fRunHead->readonly_runs(); - - // check that our bounds match our runs - { - SkIRect bounds; - int ySpanCount, intervalCount; - compute_bounds(run, &bounds, &ySpanCount, &intervalCount); - - SkASSERT(bounds == fBounds); - SkASSERT(ySpanCount > 0); - SkASSERT(fRunHead->getYSpanCount() == ySpanCount); - // SkASSERT(intervalCount > 1); - SkASSERT(fRunHead->getIntervalCount() == intervalCount); - } - } + return fBounds == SkIRect{0, 0, 0, 0}; } + if (fBounds.isEmpty()) { + return false; + } + if (this->isRect()) { + return true; + } + return fRunHead && fRunHead->fRefCnt > 0 && + validate_run(fRunHead->readonly_runs(), fRunHead->fRunCount, fBounds, + fRunHead->getYSpanCount(), fRunHead->getIntervalCount()); } +#ifdef SK_DEBUG +void SkRegion::validate() const { SkASSERT(this->isValid()); } + void SkRegion::dump() const { if (this->isEmpty()) { SkDebugf(" rgn: empty\n"); diff --git a/gfx/skia/skia/src/core/SkRegionPriv.h b/gfx/skia/skia/src/core/SkRegionPriv.h index a4cf77b7f517..4ccb68a392db 100644 --- a/gfx/skia/skia/src/core/SkRegionPriv.h +++ b/gfx/skia/skia/src/core/SkRegionPriv.h @@ -10,10 +10,16 @@ #define SkRegionPriv_DEFINED #include "SkRegion.h" + #include "SkAtomics.h" +#include "SkMalloc.h" + +inline bool SkRegionValueIsSentinel(int32_t value) { + return value == (int32_t)SkRegion::kRunTypeSentinel; +} #define assert_sentinel(value, isSentinel) \ - SkASSERT(((value) == SkRegion::kRunTypeSentinel) == isSentinel) + SkASSERT(SkRegionValueIsSentinel(value) == isSentinel) //SkDEBUGCODE(extern int32_t gRgnAllocCounter;) @@ -62,7 +68,9 @@ public: //SkDEBUGCODE(sk_atomic_inc(&gRgnAllocCounter);) //SkDEBUGF(("************** gRgnAllocCounter::alloc %d\n", gRgnAllocCounter)); - SkASSERT(count >= SkRegion::kRectRegionRuns); + if (count < SkRegion::kRectRegionRuns) { + return nullptr; + } const int64_t size = sk_64_mul(count, sizeof(RunType)) + sizeof(RunHead); if (count < 0 || !sk_64_isS32(size)) { SK_ABORT("Invalid Size"); } @@ -77,10 +85,14 @@ public: } static RunHead* Alloc(int count, int yspancount, int intervalCount) { - SkASSERT(yspancount > 0); - SkASSERT(intervalCount > 1); + if (yspancount <= 0 || intervalCount <= 1) { + return nullptr; + } RunHead* head = Alloc(count); + if (!head) { + return nullptr; + } head->fYSpanCount = yspancount; head->fIntervalCount = intervalCount; return head; diff --git a/gfx/skia/skia/src/core/SkRegion_path.cpp b/gfx/skia/skia/src/core/SkRegion_path.cpp index 47df8f6d71fb..fec78256b3cd 100644 --- a/gfx/skia/skia/src/core/SkRegion_path.cpp +++ b/gfx/skia/skia/src/core/SkRegion_path.cpp @@ -26,7 +26,7 @@ static bool sk_memeq32(const int32_t* SK_RESTRICT a, const int32_t* SK_RESTRICT class SkRgnBuilder : public SkBlitter { public: SkRgnBuilder(); - virtual ~SkRgnBuilder(); + ~SkRgnBuilder() override; // returns true if it could allocate the working storage needed bool init(int maxHeight, int maxTransitions, bool pathIsInverse); diff --git a/gfx/skia/skia/src/core/SkResourceCache.cpp b/gfx/skia/skia/src/core/SkResourceCache.cpp index 4bdc8dd9e037..5928b48b075b 100644 --- a/gfx/skia/skia/src/core/SkResourceCache.cpp +++ b/gfx/skia/skia/src/core/SkResourceCache.cpp @@ -5,11 +5,11 @@ * found in the LICENSE file. */ +#include "SkDiscardableMemory.h" #include "SkMessageBus.h" #include "SkMipMap.h" #include "SkMutex.h" #include "SkOpts.h" -#include "SkPixelRef.h" #include "SkResourceCache.h" #include "SkTraceMemoryDump.h" @@ -51,10 +51,19 @@ void SkResourceCache::Key::init(void* nameSpace, uint64_t sharedID, size_t dataS (fCount32 - kUnhashedLocal32s) << 2); } -#include "SkTDynamicHash.h" +#include "SkTHash.h" + +namespace { + struct HashTraits { + static uint32_t Hash(const SkResourceCache::Key& key) { return key.hash(); } + static const SkResourceCache::Key& GetKey(const SkResourceCache::Rec* rec) { + return rec->getKey(); + } + }; +} class SkResourceCache::Hash : - public SkTDynamicHash {}; + public SkTHashTable {}; /////////////////////////////////////////////////////////////////////////////// @@ -66,140 +75,15 @@ void SkResourceCache::init() { fTotalBytesUsed = 0; fCount = 0; fSingleAllocationByteLimit = 0; - fAllocator = nullptr; // One of these should be explicit set by the caller after we return. fTotalByteLimit = 0; fDiscardableFactory = nullptr; } -#include "SkDiscardableMemory.h" - -class SkOneShotDiscardablePixelRef : public SkPixelRef { -public: - - // Ownership of the discardablememory is transfered to the pixelref - // The pixelref will ref() the colortable (if not NULL), and unref() in destructor - SkOneShotDiscardablePixelRef(const SkImageInfo&, SkDiscardableMemory*, size_t rowBytes, - SkColorTable*); - ~SkOneShotDiscardablePixelRef(); - -protected: - bool onNewLockPixels(LockRec*) override; - void onUnlockPixels() override; - size_t getAllocatedSizeInBytes() const override; - - SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return fDM; } - -private: - SkDiscardableMemory* fDM; - size_t fRB; - bool fFirstTime; - SkColorTable* fCTable; - - typedef SkPixelRef INHERITED; -}; - -SkOneShotDiscardablePixelRef::SkOneShotDiscardablePixelRef(const SkImageInfo& info, - SkDiscardableMemory* dm, - size_t rowBytes, - SkColorTable* ctable) - : INHERITED(info) - , fDM(dm) - , fRB(rowBytes) - , fCTable(ctable) -{ - SkASSERT(dm->data()); - fFirstTime = true; - SkSafeRef(ctable); -} - -SkOneShotDiscardablePixelRef::~SkOneShotDiscardablePixelRef() { - delete fDM; - SkSafeUnref(fCTable); -} - -bool SkOneShotDiscardablePixelRef::onNewLockPixels(LockRec* rec) { - if (fFirstTime) { - // we're already locked - SkASSERT(fDM->data()); - fFirstTime = false; - goto SUCCESS; - } - - // A previous call to onUnlock may have deleted our DM, so check for that - if (nullptr == fDM) { - return false; - } - - if (!fDM->lock()) { - // since it failed, we delete it now, to free-up the resource - delete fDM; - fDM = nullptr; - return false; - } - -SUCCESS: - rec->fPixels = fDM->data(); - rec->fColorTable = fCTable; - rec->fRowBytes = fRB; - return true; -} - -void SkOneShotDiscardablePixelRef::onUnlockPixels() { - SkASSERT(!fFirstTime); - fDM->unlock(); -} - -size_t SkOneShotDiscardablePixelRef::getAllocatedSizeInBytes() const { - return this->info().getSafeSize(fRB); -} - -class SkResourceCacheDiscardableAllocator : public SkBitmap::Allocator { -public: - SkResourceCacheDiscardableAllocator(SkResourceCache::DiscardableFactory factory) { - SkASSERT(factory); - fFactory = factory; - } - - bool allocPixelRef(SkBitmap*, SkColorTable*) override; - -private: - SkResourceCache::DiscardableFactory fFactory; -}; - -bool SkResourceCacheDiscardableAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { - size_t size = bitmap->getSize(); - uint64_t size64 = bitmap->computeSize64(); - if (0 == size || size64 > (uint64_t)size) { - return false; - } - - if (kIndex_8_SkColorType == bitmap->colorType()) { - if (!ctable) { - return false; - } - } else { - ctable = nullptr; - } - - SkDiscardableMemory* dm = fFactory(size); - if (nullptr == dm) { - return false; - } - - SkImageInfo info = bitmap->info(); - bitmap->setPixelRef(new SkOneShotDiscardablePixelRef(info, dm, bitmap->rowBytes(), - ctable))->unref(); - bitmap->lockPixels(); - return bitmap->readyToDraw(); -} - SkResourceCache::SkResourceCache(DiscardableFactory factory) { this->init(); fDiscardableFactory = factory; - - fAllocator = new SkResourceCacheDiscardableAllocator(factory); } SkResourceCache::SkResourceCache(size_t byteLimit) { @@ -208,8 +92,6 @@ SkResourceCache::SkResourceCache(size_t byteLimit) { } SkResourceCache::~SkResourceCache() { - SkSafeUnref(fAllocator); - Rec* rec = fHead; while (rec) { Rec* next = rec->fNext; @@ -224,8 +106,8 @@ SkResourceCache::~SkResourceCache() { bool SkResourceCache::find(const Key& key, FindVisitor visitor, void* context) { this->checkMessages(); - Rec* rec = fHash->find(key); - if (rec) { + if (auto found = fHash->find(key)) { + Rec* rec = *found; if (visitor(*rec, context)) { this->moveToHead(rec); // for our LRU return true; @@ -249,19 +131,27 @@ static void make_size_str(size_t size, SkString* str) { static bool gDumpCacheTransactions; -void SkResourceCache::add(Rec* rec) { +void SkResourceCache::add(Rec* rec, void* payload) { this->checkMessages(); SkASSERT(rec); // See if we already have this key (racy inserts, etc.) - Rec* existing = fHash->find(rec->getKey()); - if (existing) { - delete rec; - return; + if (Rec** preexisting = fHash->find(rec->getKey())) { + Rec* prev = *preexisting; + if (prev->canBePurged()) { + // if it can be purged, the install may fail, so we have to remove it + this->remove(prev); + } else { + // if it cannot be purged, we reuse it and delete the new one + prev->postAddInstall(payload); + delete rec; + return; + } } this->addToHead(rec); - fHash->add(rec); + fHash->set(rec); + rec->postAddInstall(payload); if (gDumpCacheTransactions) { SkString bytesStr, totalStr; @@ -276,6 +166,7 @@ void SkResourceCache::add(Rec* rec) { } void SkResourceCache::remove(Rec* rec) { + SkASSERT(rec->canBePurged()); size_t used = rec->bytesUsed(); SkASSERT(used <= fTotalBytesUsed); @@ -285,6 +176,8 @@ void SkResourceCache::remove(Rec* rec) { fTotalBytesUsed -= used; fCount -= 1; + //SkDebugf("-RC count [%3d] bytes %d\n", fCount, fTotalBytesUsed); + if (gDumpCacheTransactions) { SkString bytesStr, totalStr; make_size_str(used, &bytesStr); @@ -315,7 +208,9 @@ void SkResourceCache::purgeAsNeeded(bool forcePurge) { } Rec* prev = rec->fPrev; - this->remove(rec); + if (rec->canBePurged()) { + this->remove(rec); + } rec = prev; } } @@ -342,8 +237,11 @@ void SkResourceCache::purgeSharedID(uint64_t sharedID) { while (rec) { Rec* prev = rec->fPrev; if (rec->getKey().getSharedID() == sharedID) { -// SkDebugf("purgeSharedID id=%llx rec=%p\n", sharedID, rec); - this->remove(rec); + // even though the "src" is now dead, caches could still be in-flight, so + // we have to check if it can be removed. + if (rec->canBePurged()) { + this->remove(rec); + } #ifdef SK_TRACK_PURGE_SHAREDID_HITRATE found = true; #endif @@ -579,11 +477,6 @@ SkResourceCache::DiscardableFactory SkResourceCache::GetDiscardableFactory() { return get_cache()->discardableFactory(); } -SkBitmap::Allocator* SkResourceCache::GetAllocator() { - SkAutoMutexAcquire am(gMutex); - return get_cache()->allocator(); -} - SkCachedData* SkResourceCache::NewCachedData(size_t bytes) { SkAutoMutexAcquire am(gMutex); return get_cache()->newCachedData(bytes); @@ -619,9 +512,9 @@ bool SkResourceCache::Find(const Key& key, FindVisitor visitor, void* context) { return get_cache()->find(key, visitor, context); } -void SkResourceCache::Add(Rec* rec) { +void SkResourceCache::Add(Rec* rec, void* payload) { SkAutoMutexAcquire am(gMutex); - get_cache()->add(rec); + get_cache()->add(rec, payload); } void SkResourceCache::VisitAll(Visitor visitor, void* context) { diff --git a/gfx/skia/skia/src/core/SkResourceCache.h b/gfx/skia/skia/src/core/SkResourceCache.h index 5919336312fe..6087be782465 100644 --- a/gfx/skia/skia/src/core/SkResourceCache.h +++ b/gfx/skia/skia/src/core/SkResourceCache.h @@ -82,14 +82,26 @@ public: virtual const Key& getKey() const = 0; virtual size_t bytesUsed() const = 0; + // Called if the cache needs to purge/remove/delete the Rec. Default returns true. + // Subclass may return false if there are outstanding references to it (e.g. bitmaps). + // Will only be deleted/removed-from-the-cache when this returns true. + virtual bool canBePurged() { return true; } + + // A rec is first created/initialized, and then added to the cache. As part of the add(), + // the cache will callback into the rec with postAddInstall, passing in whatever payload + // was passed to add/Add. + // + // This late-install callback exists because the process of add-ing might end up deleting + // the new rec (if an existing rec in the cache has the same key and cannot be purged). + // If the new rec will be deleted during add, the pre-existing one (with the same key) + // will have postAddInstall() called on it instead, so that either way an "install" will + // happen during the add. + virtual void postAddInstall(void*) {} + // for memory usage diagnostics virtual const char* getCategory() const = 0; virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return nullptr; } - // for SkTDynamicHash::Traits - static uint32_t Hash(const Key& key) { return key.hash(); } - static const Key& GetKey(const Rec& rec) { return rec.getKey(); } - private: Rec* fNext; Rec* fPrev; @@ -139,7 +151,7 @@ public: * false : Rec is "stale" -- the cache will purge it. */ static bool Find(const Key& key, FindVisitor, void* context); - static void Add(Rec*); + static void Add(Rec*, void* payload = nullptr); typedef void (*Visitor)(const Rec&, void* context); // Call the visitor for every Rec in the cache. @@ -167,12 +179,6 @@ public: */ static DiscardableFactory GetDiscardableFactory(); - /** - * Use this allocator for bitmaps, so they can use ashmem when available. - * Returns nullptr if the ResourceCache has not been initialized with a DiscardableFactory. - */ - static SkBitmap::Allocator* GetAllocator(); - static SkCachedData* NewCachedData(size_t bytes); static void PostPurgeSharedID(uint64_t sharedID); @@ -212,7 +218,7 @@ public: * false : Rec is "stale" -- the cache will purge it. */ bool find(const Key&, FindVisitor, void* context); - void add(Rec*); + void add(Rec*, void* payload = nullptr); void visitAll(Visitor, void* context); size_t getTotalBytesUsed() const { return fTotalBytesUsed; } @@ -243,7 +249,6 @@ public: } DiscardableFactory discardableFactory() const { return fDiscardableFactory; } - SkBitmap::Allocator* allocator() const { return fAllocator; } SkCachedData* newCachedData(size_t bytes); @@ -260,8 +265,6 @@ private: Hash* fHash; DiscardableFactory fDiscardableFactory; - // the allocator is nullptr or one that matches discardables - SkBitmap::Allocator* fAllocator; size_t fTotalBytesUsed; size_t fTotalByteLimit; diff --git a/gfx/skia/skia/src/core/SkSRGB.cpp b/gfx/skia/skia/src/core/SkSRGB.cpp index 57d2ae037361..327c7d809d21 100644 --- a/gfx/skia/skia/src/core/SkSRGB.cpp +++ b/gfx/skia/skia/src/core/SkSRGB.cpp @@ -73,3 +73,252 @@ const float sk_linear_from_srgb[256] = { 0.938685728457888000f, 0.947306536733200000f, 0.955973353249286000f, 0.964686247894465000f, 0.973445290398413000f, 0.982250550333117000f, 0.991102097113830000f, 1.000000000000000000f, }; + +/* + * Converts sRGB encoded bytes to a 12-bit linear representation. + */ +const uint16_t sk_linear12_from_srgb[256] = { + 0, 1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15, 16, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, 37, + 40, 42, 45, 48, 50, 53, 56, 59, 62, 66, 69, 72, 76, 79, 83, 87, 91, 95, 99, 103, 107, 112, + 116, 121, 126, 131, 136, 141, 146, 151, 156, 162, 168, 173, 179, 185, 191, 197, 204, 210, + 216, 223, 230, 237, 244, 251, 258, 265, 273, 280, 288, 296, 304, 312, 320, 329, 337, 346, + 354, 363, 372, 381, 390, 400, 409, 419, 428, 438, 448, 458, 469, 479, 490, 500, 511, 522, + 533, 544, 555, 567, 578, 590, 602, 614, 626, 639, 651, 664, 676, 689, 702, 715, 728, 742, + 755, 769, 783, 797, 811, 825, 840, 854, 869, 884, 899, 914, 929, 945, 960, 976, 992, 1008, + 1024, 1041, 1057, 1074, 1091, 1108, 1125, 1142, 1159, 1177, 1195, 1213, 1231, 1249, 1267, + 1286, 1304, 1323, 1342, 1361, 1381, 1400, 1420, 1440, 1459, 1480, 1500, 1520, 1541, 1562, + 1582, 1603, 1625, 1646, 1668, 1689, 1711, 1733, 1755, 1778, 1800, 1823, 1846, 1869, 1892, + 1916, 1939, 1963, 1987, 2011, 2035, 2059, 2084, 2109, 2133, 2159, 2184, 2209, 2235, 2260, + 2286, 2312, 2339, 2365, 2392, 2419, 2446, 2473, 2500, 2527, 2555, 2583, 2611, 2639, 2668, + 2696, 2725, 2754, 2783, 2812, 2841, 2871, 2901, 2931, 2961, 2991, 3022, 3052, 3083, 3114, + 3146, 3177, 3209, 3240, 3272, 3304, 3337, 3369, 3402, 3435, 3468, 3501, 3535, 3568, 3602, + 3636, 3670, 3705, 3739, 3774, 3809, 3844, 3879, 3915, 3950, 3986, 4022, 4059, 4095, +}; + +/* + * Converts 12-bit linear to sRGB encoded bytes. + */ +const uint8_t sk_linear12_to_srgb[4096] = { + 0, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 10, 11, 12, 13, 13, 14, 15, 15, 16, 16, 17, 18, 18, + 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 23, 24, 24, 25, 25, 25, 26, 26, 27, 27, 27, 28, 28, + 29, 29, 29, 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 36, + 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, + 42, 42, 43, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 47, 47, 47, + 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 52, 52, + 52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, + 56, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, + 60, 60, 61, 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 64, 64, 64, + 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, + 67, 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 70, 70, 70, 70, 70, 70, 70, 71, + 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 74, 74, + 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, 77, 77, + 77, 77, 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, + 80, 80, 80, 80, 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, 81, 81, 82, 82, 82, 82, 82, 82, + 82, 82, 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, 84, 84, 84, 84, 84, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 86, 86, 86, 86, 86, 86, 86, 86, 86, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 89, 89, 89, 89, 89, 89, 89, 89, 89, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 104, 104, 104, + 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, + 111, 111, 111, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 117, 117, 117, 117, 117, + 117, 117, 117, 117, 117, 117, 117, 117, 117, 118, 118, 118, 118, 118, 118, 118, 118, 118, + 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 132, 132, 132, 132, 132, + 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 141, 141, 141, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 144, 144, 144, 144, 144, 144, 144, + 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 148, 148, 148, 148, 148, 148, 148, 148, 148, + 148, 148, 148, 148, 148, 148, 148, 148, 148, 149, 149, 149, 149, 149, 149, 149, 149, 149, + 149, 149, 149, 149, 149, 149, 149, 149, 149, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 152, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 153, 153, 153, 153, 153, 153, 153, + 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 154, 154, 154, 154, 154, 154, 154, + 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 157, 157, 157, + 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, 158, + 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, + 163, 163, 163, 163, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 164, 164, 164, 164, + 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 166, 166, 166, + 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, + 168, 168, 168, 168, 168, 168, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 171, 171, 171, 171, 171, 171, + 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, + 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, + 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 179, 179, 179, 179, 179, + 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, + 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 183, 183, 183, 183, 183, + 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, + 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + 187, 187, 187, 187, 187, 187, 187, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, + 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190, 190, 190, 190, 190, 190, 190, 190, 191, 191, 191, 191, 191, 191, 191, 191, 191, + 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, + 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, + 194, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 195, 196, 196, 196, 196, 196, 196, 196, 196, 196, + 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 197, + 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, + 197, 197, 197, 197, 197, 197, 197, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, + 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, + 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 201, 201, 201, 201, + 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 201, 201, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, + 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 205, 205, 205, 205, + 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, + 205, 205, 205, 205, 205, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 207, 207, 207, + 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, + 207, 207, 207, 207, 207, 207, 207, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, + 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, + 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, + 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, + 217, 217, 217, 217, 217, 217, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 219, + 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, + 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 220, 220, 220, + 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, + 220, 220, 220, 220, 220, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 223, 223, 223, 223, 223, 223, + 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, + 223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 226, 226, 226, + 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, + 226, 226, 226, 226, 226, 226, 226, 226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 227, + 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, + 227, 227, 227, 227, 227, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, + 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, + 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, + 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 231, 231, 231, 231, 231, 231, 231, 231, + 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, + 231, 231, 231, 231, 231, 231, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, + 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, + 232, 232, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 234, + 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, + 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 235, 235, 235, 235, 235, + 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, + 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 241, 241, 241, + 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, + 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 242, 242, 242, 242, 242, + 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, + 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, + 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, + 250, 250, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, + 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, + 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, +}; diff --git a/gfx/skia/skia/src/core/SkSRGB.h b/gfx/skia/skia/src/core/SkSRGB.h index e60e288861f0..83ae5a4b2725 100644 --- a/gfx/skia/skia/src/core/SkSRGB.h +++ b/gfx/skia/skia/src/core/SkSRGB.h @@ -20,17 +20,20 @@ * sk_linear_to_srgb() will run a little faster than usual when compiled with SSE4.1+. */ -extern const float sk_linear_from_srgb[256]; +extern const float sk_linear_from_srgb[256]; +extern const uint16_t sk_linear12_from_srgb[256]; +extern const uint8_t sk_linear12_to_srgb[4096]; -static inline Sk4f sk_clamp_0_255(const Sk4f& x) { +template +static inline V sk_clamp_0_255(const V& x) { // The order of the arguments is important here. We want to make sure that NaN // clamps to zero. Note that max(NaN, 0) = 0, while max(0, NaN) = NaN. - return Sk4f::Min(Sk4f::Max(x, 0.0f), 255.0f); + return V::Min(V::Max(x, 0.0f), 255.0f); } -// This should probably only be called from sk_linear_to_srgb() or sk_linear_to_srgb_noclamp(). -// It generally doesn't make sense to work with sRGB floats. -static inline Sk4f sk_linear_to_srgb_needs_trunc(const Sk4f& x) { +// [0.0f, 1.0f] -> [0.0f, 255.xf], for small x. Correct after truncation. +template +static inline V sk_linear_to_srgb_needs_trunc(const V& x) { // Approximation of the sRGB gamma curve (within 1 when scaled to 8-bit pixels). // // Constants tuned by brute force to minimize (in order of importance) after truncation: @@ -43,42 +46,65 @@ static inline Sk4f sk_linear_to_srgb_needs_trunc(const Sk4f& x) { auto lo = (13.0471f * 255.0f) * x; - auto hi = (-0.0974983f * 255.0f) - + (+0.687999f * 255.0f) * sqrt - + (+0.412999f * 255.0f) * ftrt; + auto hi = SkNx_fma(V{+0.412999f * 255.0f}, ftrt, + SkNx_fma(V{+0.687999f * 255.0f}, sqrt, + V{-0.0974983f * 255.0f})); return (x < 0.0048f).thenElse(lo, hi); } -static inline Sk4i sk_linear_to_srgb(const Sk4f& x) { - Sk4f f = sk_linear_to_srgb_needs_trunc(x); +// [0.0f, 1.0f] -> [0.0f, 1.0f]. Correct after rounding. +template +static inline V sk_linear_to_srgb_needs_round(const V& x) { + // Tuned to round trip each sRGB byte after rounding. + auto rsqrt = x.rsqrt(), + sqrt = rsqrt.invert(), + ftrt = rsqrt.rsqrt(); + + auto lo = 12.46f * x; + + auto hi = V::Min(1.0f, SkNx_fma(V{+0.411192f}, ftrt, + SkNx_fma(V{+0.689206f}, sqrt, + V{-0.0988f}))); + return (x < 0.0043f).thenElse(lo, hi); +} + +template +static inline SkNx sk_linear_to_srgb(const SkNx& x) { + auto f = sk_linear_to_srgb_needs_trunc(x); return SkNx_cast(sk_clamp_0_255(f)); } -static inline Sk4i sk_linear_to_srgb_noclamp(const Sk4f& x) { - Sk4f f = sk_linear_to_srgb_needs_trunc(x); - for (int i = 0; i < 4; i++) { - SkASSERTF(0.0f <= f[i] && f[i] < 256.0f, "f[%d] was %g, outside [0,256)\n", i, f[i]); - } - return SkNx_cast(f); -} - -// sRGB -> linear, using math instead of table lookups, scaling better to larger SIMD vectors. -static inline Sk4f sk_linear_from_srgb_math(const Sk4i& s) { - auto x = SkNx_cast(s); - - const float u = 1/255.0f; // x is [0,255], so x^n needs scaling by u^n. +// sRGB -> linear, using math instead of table lookups. +template +static inline V sk_linear_from_srgb_math(const V& x) { // Non-linear segment of sRGB curve approximated by // l = 0.0025 + 0.6975x^2 + 0.3x^3 - const float k0 = 0.0025f, - k2 = 0.6975f * u*u, - k3 = 0.3000f * u*u*u; - auto hi = k0 + (k2 + k3*x) * (x*x); + const V k0 = 0.0025f, + k2 = 0.6975f, + k3 = 0.3000f; + auto hi = SkNx_fma(x*x, SkNx_fma(x, k3, k2), k0); // Linear segment of sRGB curve: the normal slope, extended a little further than normal. - auto lo = x * (u/12.92f); + auto lo = x * (1/12.92f); - return (x < 14.025f).thenElse(lo, hi); + return (x < 0.055f).thenElse(lo, hi); +} + +// Same as above, starting from ints. +template +static inline SkNx sk_linear_from_srgb_math(const SkNx& s) { + auto x = SkNx_cast(s); + + // Same math as above, but working with x in [0,255], so x^n needs scaling by u^n. + const float u = 1/255.0f; + + const SkNx k0 = 0.0025f, + k2 = 0.6975f * u*u, + k3 = 0.3000f * u*u*u; + auto hi = SkNx_fma(x*x, SkNx_fma(x, k3, k2), k0); + auto lo = x * (u/12.92f); + return (x < (0.055f/u)).thenElse(lo, hi); } #endif//SkSRGB_DEFINED diff --git a/gfx/skia/skia/src/core/SkScalerContext.cpp b/gfx/skia/skia/src/core/SkScalerContext.cpp index ecac82a34c8a..a5a47e4d99b6 100644 --- a/gfx/skia/skia/src/core/SkScalerContext.cpp +++ b/gfx/skia/skia/src/core/SkScalerContext.cpp @@ -5,23 +5,25 @@ * found in the LICENSE file. */ - #include "SkScalerContext.h" + +#include "SkAutoMalloc.h" #include "SkAutoPixmapStorage.h" #include "SkColorPriv.h" #include "SkDescriptor.h" #include "SkDraw.h" #include "SkGlyph.h" +#include "SkMakeUnique.h" #include "SkMaskFilter.h" #include "SkMaskGamma.h" #include "SkMatrix22.h" -#include "SkReadBuffer.h" -#include "SkWriteBuffer.h" #include "SkPathEffect.h" -#include "SkRasterizer.h" #include "SkRasterClip.h" +#include "SkRasterizer.h" +#include "SkReadBuffer.h" #include "SkStroke.h" #include "SkStrokeRec.h" +#include "SkWriteBuffer.h" #define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3) @@ -62,11 +64,11 @@ void SkGlyph::zeroMetrics() { #define DUMP_RECx #endif -SkScalerContext::SkScalerContext(SkTypeface* typeface, const SkScalerContextEffects& effects, +SkScalerContext::SkScalerContext(sk_sp typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc) : fRec(*static_cast(desc->findEntry(kRec_SkDescriptorTag, nullptr))) - , fTypeface(sk_ref_sp(typeface)) + , fTypeface(std::move(typeface)) , fPathEffect(sk_ref_sp(effects.fPathEffect)) , fMaskFilter(sk_ref_sp(effects.fMaskFilter)) , fRasterizer(sk_ref_sp(effects.fRasterizer)) @@ -130,7 +132,7 @@ void SkScalerContext::getMetrics(SkGlyph* glyph) { SkPath devPath, fillPath; SkMatrix fillToDevMatrix; - this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); + this->internalGetPath(glyph->getPackedID(), &fillPath, &devPath, &fillToDevMatrix); if (fRasterizer) { SkMask mask; @@ -461,7 +463,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) { SkMask::kARGB32_Format != origGlyph.fMaskFormat); if (fMaskFilter) { // restore the prefilter bounds - tmpGlyph.initGlyphIdFrom(origGlyph); + tmpGlyph.initWithGlyphID(origGlyph.getPackedID()); // need the original bounds, sans our maskfilter SkMaskFilter* mf = fMaskFilter.release(); // temp disable @@ -486,7 +488,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) { SkMatrix fillToDevMatrix; SkMask mask; - this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); + this->internalGetPath(glyph->getPackedID(), &fillPath, &devPath, &fillToDevMatrix); glyph->toMask(&mask); if (fRasterizer) { @@ -563,11 +565,12 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) { } } -void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) { - this->internalGetPath(glyph, nullptr, path, nullptr); +void SkScalerContext::getPath(SkPackedGlyphID glyphID, SkPath* path) { + this->internalGetPath(glyphID, nullptr, path, nullptr); } void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) { + SkASSERT(fm); this->generateFontMetrics(fm); } @@ -577,14 +580,14 @@ SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) { /////////////////////////////////////////////////////////////////////////////// -void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, - SkPath* devPath, SkMatrix* fillToDevMatrix) { +void SkScalerContext::internalGetPath(SkPackedGlyphID glyphID, SkPath* fillPath, + SkPath* devPath, SkMatrix* fillToDevMatrix) { SkPath path; - generatePath(glyph, &path); + generatePath(glyphID.code(), &path); if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { - SkFixed dx = glyph.getSubXFixed(); - SkFixed dy = glyph.getSubYFixed(); + SkFixed dx = glyphID.getSubXFixed(); + SkFixed dy = glyphID.getSubYFixed(); if (dx | dy) { path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy)); } @@ -831,9 +834,9 @@ SkAxisAlignment SkScalerContext::computeAxisAlignmentForHText() { class SkScalerContext_Empty : public SkScalerContext { public: - SkScalerContext_Empty(SkTypeface* typeface, const SkScalerContextEffects& effects, + SkScalerContext_Empty(sk_sp typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc) - : SkScalerContext(typeface, effects, desc) {} + : SkScalerContext(std::move(typeface), effects, desc) {} protected: unsigned generateGlyphCount() override { @@ -849,7 +852,7 @@ protected: glyph->zeroMetrics(); } void generateImage(const SkGlyph& glyph) override {} - void generatePath(const SkGlyph& glyph, SkPath* path) override {} + void generatePath(SkGlyphID glyph, SkPath* path) override {} void generateFontMetrics(SkPaint::FontMetrics* metrics) override { if (metrics) { sk_bzero(metrics, sizeof(*metrics)); @@ -859,13 +862,13 @@ protected: extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc); -SkScalerContext* SkTypeface::createScalerContext(const SkScalerContextEffects& effects, - const SkDescriptor* desc, - bool allowFailure) const { - SkScalerContext* c = this->onCreateScalerContext(effects, desc); - +std::unique_ptr SkTypeface::createScalerContext( + const SkScalerContextEffects& effects, const SkDescriptor* desc, bool allowFailure) const +{ + std::unique_ptr c(this->onCreateScalerContext(effects, desc)); if (!c && !allowFailure) { - c = new SkScalerContext_Empty(const_cast(this), effects, desc); + c = skstd::make_unique(sk_ref_sp(const_cast(this)), + effects, desc); } return c; } diff --git a/gfx/skia/skia/src/core/SkScalerContext.h b/gfx/skia/skia/src/core/SkScalerContext.h index 48ec0624cf64..7bfdb92a52c9 100644 --- a/gfx/skia/skia/src/core/SkScalerContext.h +++ b/gfx/skia/skia/src/core/SkScalerContext.h @@ -8,13 +8,13 @@ #ifndef SkScalerContext_DEFINED #define SkScalerContext_DEFINED +#include "SkGlyph.h" #include "SkMask.h" #include "SkMaskGamma.h" #include "SkMatrix.h" #include "SkPaint.h" #include "SkTypeface.h" -class SkGlyph; class SkDescriptor; class SkMaskFilter; class SkPathEffect; @@ -211,7 +211,7 @@ public: kHinting_Mask = kHintingBit1_Flag | kHintingBit2_Flag, }; - SkScalerContext(SkTypeface*, const SkScalerContextEffects&, const SkDescriptor*); + SkScalerContext(sk_sp, const SkScalerContextEffects&, const SkDescriptor*); virtual ~SkScalerContext(); SkTypeface* getTypeface() const { return fTypeface.get(); } @@ -248,7 +248,7 @@ public: void getAdvance(SkGlyph*); void getMetrics(SkGlyph*); void getImage(const SkGlyph&); - void getPath(const SkGlyph&, SkPath*); + void getPath(SkPackedGlyphID, SkPath*); void getFontMetrics(SkPaint::FontMetrics*); /** Return the size in bytes of the associated gamma lookup table @@ -309,11 +309,8 @@ protected: /** Sets the passed path to the glyph outline. * If this cannot be done the path is set to empty; * this is indistinguishable from a glyph with an empty path. - * This does not set glyph.fPath. - * - * TODO: path is always glyph.fPath, no reason to pass separately. */ - virtual void generatePath(const SkGlyph& glyph, SkPath* path) = 0; + virtual void generatePath(SkGlyphID glyphId, SkPath* path) = 0; /** Retrieves font metrics. */ virtual void generateFontMetrics(SkPaint::FontMetrics*) = 0; @@ -350,14 +347,9 @@ private: // calling generateImage. bool fGenerateImageFromPath; - void internalGetPath(const SkGlyph& glyph, SkPath* fillPath, + void internalGetPath(SkPackedGlyphID id, SkPath* fillPath, SkPath* devPath, SkMatrix* fillToDevMatrix); - // returns the right context from our link-list for this char. If no match - // is found it returns nullptr. If a match is found then the glyphID param is - // set to the glyphID that maps to the provided char. - SkScalerContext* getContextFromChar(SkUnichar uni, uint16_t* glyphID); - // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks. protected: // Visible to subclasses so that generateImage can apply the pre-blend directly. diff --git a/gfx/skia/skia/src/core/SkScan.cpp b/gfx/skia/skia/src/core/SkScan.cpp index 7fce3f172658..c2f00f3a8494 100644 --- a/gfx/skia/skia/src/core/SkScan.cpp +++ b/gfx/skia/skia/src/core/SkScan.cpp @@ -10,6 +10,14 @@ #include "SkBlitter.h" #include "SkRasterClip.h" +#ifdef SK_NO_ANALYTIC_AA + std::atomic gSkUseAnalyticAA{false}; +#else + std::atomic gSkUseAnalyticAA{true}; +#endif + +std::atomic gSkForceAnalyticAA{false}; + static inline void blitrect(SkBlitter* blitter, const SkIRect& r) { blitter->blitRect(r.fLeft, r.fTop, r.width(), r.height()); } diff --git a/gfx/skia/skia/src/core/SkScan.h b/gfx/skia/skia/src/core/SkScan.h index 4aa8e443990e..c99554218b74 100644 --- a/gfx/skia/skia/src/core/SkScan.h +++ b/gfx/skia/skia/src/core/SkScan.h @@ -11,6 +11,7 @@ #include "SkFixed.h" #include "SkRect.h" +#include class SkRasterClip; class SkRegion; @@ -22,6 +23,11 @@ class SkPath; */ typedef SkIRect SkXRect; +extern std::atomic gSkUseAnalyticAA; +extern std::atomic gSkForceAnalyticAA; + +class AdditiveBlitter; + class SkScan { public: /* @@ -45,6 +51,7 @@ public: static void AntiFillXRect(const SkXRect&, const SkRasterClip&, SkBlitter*); static void FillPath(const SkPath&, const SkRasterClip&, SkBlitter*); static void AntiFillPath(const SkPath&, const SkRasterClip&, SkBlitter*); + static void AAAFillPath(const SkPath&, const SkRasterClip&, SkBlitter*); static void FrameRect(const SkRect&, const SkPoint& strokeSize, const SkRasterClip&, SkBlitter*); static void AntiFrameRect(const SkRect&, const SkPoint& strokeSize, @@ -79,6 +86,8 @@ private: const SkRegion*, SkBlitter*); static void HairLineRgn(const SkPoint[], int count, const SkRegion*, SkBlitter*); static void AntiHairLineRgn(const SkPoint[], int count, const SkRegion*, SkBlitter*); + static void AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter, + bool forceRLE = false); // SkAAClip uses forceRLE }; /** Assign an SkXRect from a SkIRect, by promoting the src rect's coordinates diff --git a/gfx/skia/skia/src/core/SkScanPriv.h b/gfx/skia/skia/src/core/SkScanPriv.h index 798cae6d0fc3..eca3c9c67e2d 100644 --- a/gfx/skia/skia/src/core/SkScanPriv.h +++ b/gfx/skia/skia/src/core/SkScanPriv.h @@ -23,17 +23,58 @@ public: private: SkRectClipBlitter fRectBlitter; SkRgnClipBlitter fRgnBlitter; +#ifdef SK_DEBUG + SkRectClipCheckBlitter fRectClipCheckBlitter; +#endif SkBlitter* fBlitter; const SkIRect* fClipRect; }; -// clipRect == null means path is entirely inside the clip -void sk_fill_path(const SkPath& path, const SkIRect* clipRect, +void sk_fill_path(const SkPath& path, const SkIRect& clipRect, SkBlitter* blitter, int start_y, int stop_y, int shiftEdgesUp, - const SkRegion& clipRgn); + bool pathContainedInClip); // blit the rects above and below avoid, clipped to clip void sk_blit_above(SkBlitter*, const SkIRect& avoid, const SkRegion& clip); void sk_blit_below(SkBlitter*, const SkIRect& avoid, const SkRegion& clip); +template +static inline void remove_edge(EdgeType* edge) { + edge->fPrev->fNext = edge->fNext; + edge->fNext->fPrev = edge->fPrev; +} + +template +static inline void insert_edge_after(EdgeType* edge, EdgeType* afterMe) { + edge->fPrev = afterMe; + edge->fNext = afterMe->fNext; + afterMe->fNext->fPrev = edge; + afterMe->fNext = edge; +} + +template +static void backward_insert_edge_based_on_x(EdgeType* edge) { + SkFixed x = edge->fX; + EdgeType* prev = edge->fPrev; + while (prev->fPrev && prev->fX > x) { + prev = prev->fPrev; + } + if (prev->fNext != edge) { + remove_edge(edge); + insert_edge_after(edge, prev); + } +} + +// Start from the right side, searching backwards for the point to begin the new edge list +// insertion, marching forwards from here. The implementation could have started from the left +// of the prior insertion, and search to the right, or with some additional caching, binary +// search the starting point. More work could be done to determine optimal new edge insertion. +template +static EdgeType* backward_insert_start(EdgeType* prev, SkFixed x) { + while (prev->fPrev && prev->fX > x) { + prev = prev->fPrev; + } + return prev; +} + #endif diff --git a/gfx/skia/skia/src/core/SkScan_AAAPath.cpp b/gfx/skia/skia/src/core/SkScan_AAAPath.cpp new file mode 100644 index 000000000000..3eca13764274 --- /dev/null +++ b/gfx/skia/skia/src/core/SkScan_AAAPath.cpp @@ -0,0 +1,1842 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkAnalyticEdge.h" +#include "SkAntiRun.h" +#include "SkAutoMalloc.h" +#include "SkBlitter.h" +#include "SkEdge.h" +#include "SkEdgeBuilder.h" +#include "SkGeometry.h" +#include "SkPath.h" +#include "SkQuadClipper.h" +#include "SkRasterClip.h" +#include "SkRegion.h" +#include "SkScan.h" +#include "SkScanPriv.h" +#include "SkTSort.h" +#include "SkTemplates.h" +#include "SkUtils.h" + +/////////////////////////////////////////////////////////////////////////////// + +/* + +The following is a high-level overview of our analytic anti-aliasing +algorithm. We consider a path as a collection of line segments, as +quadratic/cubic curves are converted to small line segments. Without loss of +generality, let's assume that the draw region is [0, W] x [0, H]. + +Our algorithm is based on horizontal scan lines (y = c_i) as the previous +sampling-based algorithm did. However, our algorithm uses non-equal-spaced +scan lines, while the previous method always uses equal-spaced scan lines, +such as (y = 1/2 + 0, 1/2 + 1, 1/2 + 2, ...) in the previous non-AA algorithm, +and (y = 1/8 + 1/4, 1/8 + 2/4, 1/8 + 3/4, ...) in the previous +16-supersampling AA algorithm. + +Our algorithm contains scan lines y = c_i for c_i that is either: + +1. an integer between [0, H] + +2. the y value of a line segment endpoint + +3. the y value of an intersection of two line segments + +For two consecutive scan lines y = c_i, y = c_{i+1}, we analytically computes +the coverage of this horizontal strip of our path on each pixel. This can be +done very efficiently because the strip of our path now only consists of +trapezoids whose top and bottom edges are y = c_i, y = c_{i+1} (this includes +rectangles and triangles as special cases). + +We now describe how the coverage of single pixel is computed against such a +trapezoid. That coverage is essentially the intersection area of a rectangle +(e.g., [0, 1] x [c_i, c_{i+1}]) and our trapezoid. However, that intersection +could be complicated, as shown in the example region A below: + ++-----------\----+ +| \ C| +| \ | +\ \ | +|\ A \| +| \ \ +| \ | +| B \ | ++----\-----------+ + +However, we don't have to compute the area of A directly. Instead, we can +compute the excluded area, which are B and C, quite easily, because they're +just triangles. In fact, we can prove that an excluded region (take B as an +example) is either itself a simple trapezoid (including rectangles, triangles, +and empty regions), or its opposite (the opposite of B is A + C) is a simple +trapezoid. In any case, we can compute its area efficiently. + +In summary, our algorithm has a higher quality because it generates ground- +truth coverages analytically. It is also faster because it has much fewer +unnessasary horizontal scan lines. For example, given a triangle path, the +number of scan lines in our algorithm is only about 3 + H while the +16-supersampling algorithm has about 4H scan lines. + +*/ + +/////////////////////////////////////////////////////////////////////////////// + +static inline void addAlpha(SkAlpha* alpha, SkAlpha delta) { + SkASSERT(*alpha + (int)delta <= 256); + *alpha = SkAlphaRuns::CatchOverflow(*alpha + (int)delta); +} + +static inline void safelyAddAlpha(SkAlpha* alpha, SkAlpha delta) { + *alpha = SkTMin(0xFF, *alpha + (int)delta); +} + +class AdditiveBlitter : public SkBlitter { +public: + ~AdditiveBlitter() override {} + + virtual SkBlitter* getRealBlitter(bool forceRealBlitter = false) = 0; + + virtual void blitAntiH(int x, int y, const SkAlpha antialias[], int len) = 0; + virtual void blitAntiH(int x, int y, const SkAlpha alpha) = 0; + virtual void blitAntiH(int x, int y, int width, const SkAlpha alpha) = 0; + + void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override { + SkDEBUGFAIL("Please call real blitter's blitAntiH instead."); + } + + void blitV(int x, int y, int height, SkAlpha alpha) override { + SkDEBUGFAIL("Please call real blitter's blitV instead."); + } + + void blitH(int x, int y, int width) override { + SkDEBUGFAIL("Please call real blitter's blitH instead."); + } + + void blitRect(int x, int y, int width, int height) override { + SkDEBUGFAIL("Please call real blitter's blitRect instead."); + } + + void blitAntiRect(int x, int y, int width, int height, + SkAlpha leftAlpha, SkAlpha rightAlpha) override { + SkDEBUGFAIL("Please call real blitter's blitAntiRect instead."); + } + + virtual int getWidth() = 0; + + // Flush the additive alpha cache if floor(y) and floor(nextY) is different + // (i.e., we'll start working on a new pixel row). + virtual void flush_if_y_changed(SkFixed y, SkFixed nextY) = 0; +}; + +// We need this mask blitter because it significantly accelerates small path filling. +class MaskAdditiveBlitter : public AdditiveBlitter { +public: + MaskAdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, + bool isInverse); + ~MaskAdditiveBlitter() override { + fRealBlitter->blitMask(fMask, fClipRect); + } + + // Most of the time, we still consider this mask blitter as the real blitter + // so we can accelerate blitRect and others. But sometimes we want to return + // the absolute real blitter (e.g., when we fall back to the old code path). + SkBlitter* getRealBlitter(bool forceRealBlitter) override { + return forceRealBlitter ? fRealBlitter : this; + } + + // Virtual function is slow. So don't use this. Directly add alpha to the mask instead. + void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override; + + // Allowing following methods are used to blit rectangles during aaa_walk_convex_edges + // Since there aren't many rectangles, we can still bear the slow speed of virtual functions. + void blitAntiH(int x, int y, const SkAlpha alpha) override; + void blitAntiH(int x, int y, int width, const SkAlpha alpha) override; + void blitV(int x, int y, int height, SkAlpha alpha) override; + void blitRect(int x, int y, int width, int height) override; + void blitAntiRect(int x, int y, int width, int height, + SkAlpha leftAlpha, SkAlpha rightAlpha) override; + + // The flush is only needed for RLE (RunBasedAdditiveBlitter) + void flush_if_y_changed(SkFixed y, SkFixed nextY) override {} + + int getWidth() override { return fClipRect.width(); } + + static bool canHandleRect(const SkIRect& bounds) { + int width = bounds.width(); + if (width > MaskAdditiveBlitter::kMAX_WIDTH) { + return false; + } + int64_t rb = SkAlign4(width); + // use 64bits to detect overflow + int64_t storage = rb * bounds.height(); + + return (width <= MaskAdditiveBlitter::kMAX_WIDTH) && + (storage <= MaskAdditiveBlitter::kMAX_STORAGE); + } + + // Return a pointer where pointer[x] corresonds to the alpha of (x, y) + inline uint8_t* getRow(int y) { + if (y != fY) { + fY = y; + fRow = fMask.fImage + (y - fMask.fBounds.fTop) * fMask.fRowBytes - fMask.fBounds.fLeft; + } + return fRow; + } + +private: + // so we don't try to do very wide things, where the RLE blitter would be faster + static const int kMAX_WIDTH = 32; + static const int kMAX_STORAGE = 1024; + + SkBlitter* fRealBlitter; + SkMask fMask; + SkIRect fClipRect; + // we add 2 because we can write 1 extra byte at either end due to precision error + uint32_t fStorage[(kMAX_STORAGE >> 2) + 2]; + + uint8_t* fRow; + int fY; +}; + +MaskAdditiveBlitter::MaskAdditiveBlitter( + SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, bool isInverse) { + SkASSERT(canHandleRect(ir)); + SkASSERT(!isInverse); + + fRealBlitter = realBlitter; + + fMask.fImage = (uint8_t*)fStorage + 1; // There's 1 extra byte at either end of fStorage + fMask.fBounds = ir; + fMask.fRowBytes = ir.width(); + fMask.fFormat = SkMask::kA8_Format; + + fY = ir.fTop - 1; + fRow = nullptr; + + fClipRect = ir; + if (!fClipRect.intersect(clip.getBounds())) { + SkASSERT(0); + fClipRect.setEmpty(); + } + + memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 2); +} + +void MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) { + SkFAIL("Don't use this; directly add alphas to the mask."); +} + +void MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { + SkASSERT(x >= fMask.fBounds.fLeft -1); + addAlpha(&this->getRow(y)[x], alpha); +} + +void MaskAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { + SkASSERT(x >= fMask.fBounds.fLeft -1); + uint8_t* row = this->getRow(y); + for (int i = 0; i < width; ++i) { + addAlpha(&row[x + i], alpha); + } +} + +void MaskAdditiveBlitter::blitV(int x, int y, int height, SkAlpha alpha) { + if (alpha == 0) { + return; + } + SkASSERT(x >= fMask.fBounds.fLeft -1); + // This must be called as if this is a real blitter. + // So we directly set alpha rather than adding it. + uint8_t* row = this->getRow(y); + for (int i = 0; i < height; ++i) { + row[x] = alpha; + row += fMask.fRowBytes; + } +} + +void MaskAdditiveBlitter::blitRect(int x, int y, int width, int height) { + SkASSERT(x >= fMask.fBounds.fLeft -1); + // This must be called as if this is a real blitter. + // So we directly set alpha rather than adding it. + uint8_t* row = this->getRow(y); + for (int i = 0; i < height; ++i) { + memset(row + x, 0xFF, width); + row += fMask.fRowBytes; + } +} + +void MaskAdditiveBlitter::blitAntiRect(int x, int y, int width, int height, + SkAlpha leftAlpha, SkAlpha rightAlpha) { + blitV(x, y, height, leftAlpha); + blitV(x + 1 + width, y, height, rightAlpha); + blitRect(x + 1, y, width, height); +} + +class RunBasedAdditiveBlitter : public AdditiveBlitter { +public: + RunBasedAdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, + bool isInverse); + ~RunBasedAdditiveBlitter() override; + + SkBlitter* getRealBlitter(bool forceRealBlitter) override; + + void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override; + void blitAntiH(int x, int y, const SkAlpha alpha) override; + void blitAntiH(int x, int y, int width, const SkAlpha alpha) override; + + int getWidth() override; + + void flush_if_y_changed(SkFixed y, SkFixed nextY) override { + if (SkFixedFloorToInt(y) != SkFixedFloorToInt(nextY)) { + this->flush(); + } + } + +protected: + SkBlitter* fRealBlitter; + + /// Current y coordinate + int fCurrY; + /// Widest row of region to be blitted + int fWidth; + /// Leftmost x coordinate in any row + int fLeft; + /// Initial y coordinate (top of bounds). + int fTop; + + // The next three variables are used to track a circular buffer that + // contains the values used in SkAlphaRuns. These variables should only + // ever be updated in advanceRuns(), and fRuns should always point to + // a valid SkAlphaRuns... + int fRunsToBuffer; + void* fRunsBuffer; + int fCurrentRun; + SkAlphaRuns fRuns; + + int fOffsetX; + + inline bool check(int x, int width) const { + #ifdef SK_DEBUG + if (x < 0 || x + width > fWidth) { + // SkDebugf("Ignore x = %d, width = %d\n", x, width); + } + #endif + return (x >= 0 && x + width <= fWidth); + } + + // extra one to store the zero at the end + inline int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof(int16_t); } + + // This function updates the fRuns variable to point to the next buffer space + // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun + // and resets fRuns to point to an empty scanline. + inline void advanceRuns() { + const size_t kRunsSz = this->getRunsSz(); + fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer; + fRuns.fRuns = reinterpret_cast( + reinterpret_cast(fRunsBuffer) + fCurrentRun * kRunsSz); + fRuns.fAlpha = reinterpret_cast(fRuns.fRuns + fWidth + 1); + fRuns.reset(fWidth); + } + + // Blitting 0xFF and 0 is much faster so we snap alphas close to them + inline SkAlpha snapAlpha(SkAlpha alpha) { + return alpha > 247 ? 0xFF : alpha < 8 ? 0 : alpha; + } + + inline void flush() { + if (fCurrY >= fTop) { + SkASSERT(fCurrentRun < fRunsToBuffer); + for (int x = 0; fRuns.fRuns[x]; x += fRuns.fRuns[x]) { + // It seems that blitting 255 or 0 is much faster than blitting 254 or 1 + fRuns.fAlpha[x] = snapAlpha(fRuns.fAlpha[x]); + } + if (!fRuns.empty()) { + // SkDEBUGCODE(fRuns.dump();) + fRealBlitter->blitAntiH(fLeft, fCurrY, fRuns.fAlpha, fRuns.fRuns); + this->advanceRuns(); + fOffsetX = 0; + } + fCurrY = fTop - 1; + } + } + + inline void checkY(int y) { + if (y != fCurrY) { + this->flush(); + fCurrY = y; + } + } +}; + +RunBasedAdditiveBlitter::RunBasedAdditiveBlitter( + SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, bool isInverse) { + fRealBlitter = realBlitter; + + SkIRect sectBounds; + if (isInverse) { + // We use the clip bounds instead of the ir, since we may be asked to + //draw outside of the rect when we're a inverse filltype + sectBounds = clip.getBounds(); + } else { + if (!sectBounds.intersect(ir, clip.getBounds())) { + sectBounds.setEmpty(); + } + } + + const int left = sectBounds.left(); + const int right = sectBounds.right(); + + fLeft = left; + fWidth = right - left; + fTop = sectBounds.top(); + fCurrY = fTop - 1; + + fRunsToBuffer = realBlitter->requestRowsPreserved(); + fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz()); + fCurrentRun = -1; + + this->advanceRuns(); + + fOffsetX = 0; +} + +RunBasedAdditiveBlitter::~RunBasedAdditiveBlitter() { + this->flush(); +} + +SkBlitter* RunBasedAdditiveBlitter::getRealBlitter(bool forceRealBlitter) { + return fRealBlitter; +} + +void RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) { + checkY(y); + x -= fLeft; + + if (x < 0) { + len += x; + antialias -= x; + x = 0; + } + len = SkTMin(len, fWidth - x); + SkASSERT(check(x, len)); + + if (x < fOffsetX) { + fOffsetX = 0; + } + + fOffsetX = fRuns.add(x, 0, len, 0, 0, fOffsetX); // Break the run + for (int i = 0; i < len; i += fRuns.fRuns[x + i]) { + for (int j = 1; j < fRuns.fRuns[x + i]; j++) { + fRuns.fRuns[x + i + j] = 1; + fRuns.fAlpha[x + i + j] = fRuns.fAlpha[x + i]; + } + fRuns.fRuns[x + i] = 1; + } + for (int i = 0; i < len; ++i) { + addAlpha(&fRuns.fAlpha[x + i], antialias[i]); + } +} +void RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { + checkY(y); + x -= fLeft; + + if (x < fOffsetX) { + fOffsetX = 0; + } + + if (this->check(x, 1)) { + fOffsetX = fRuns.add(x, 0, 1, 0, alpha, fOffsetX); + } +} + +void RunBasedAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { + checkY(y); + x -= fLeft; + + if (x < fOffsetX) { + fOffsetX = 0; + } + + if (this->check(x, width)) { + fOffsetX = fRuns.add(x, 0, width, 0, alpha, fOffsetX); + } +} + +int RunBasedAdditiveBlitter::getWidth() { return fWidth; } + +// This exists specifically for concave path filling. +// In those cases, we can easily accumulate alpha greater than 0xFF. +class SafeRLEAdditiveBlitter : public RunBasedAdditiveBlitter { +public: + SafeRLEAdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, + bool isInverse) : RunBasedAdditiveBlitter(realBlitter, ir, clip, isInverse) {} + + void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override; + void blitAntiH(int x, int y, const SkAlpha alpha) override; + void blitAntiH(int x, int y, int width, const SkAlpha alpha) override; +}; + +void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) { + checkY(y); + x -= fLeft; + + if (x < 0) { + len += x; + antialias -= x; + x = 0; + } + len = SkTMin(len, fWidth - x); + SkASSERT(check(x, len)); + + if (x < fOffsetX) { + fOffsetX = 0; + } + + fOffsetX = fRuns.add(x, 0, len, 0, 0, fOffsetX); // Break the run + for (int i = 0; i < len; i += fRuns.fRuns[x + i]) { + for (int j = 1; j < fRuns.fRuns[x + i]; j++) { + fRuns.fRuns[x + i + j] = 1; + fRuns.fAlpha[x + i + j] = fRuns.fAlpha[x + i]; + } + fRuns.fRuns[x + i] = 1; + } + for (int i = 0; i < len; ++i) { + safelyAddAlpha(&fRuns.fAlpha[x + i], antialias[i]); + } +} + +void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { + checkY(y); + x -= fLeft; + + if (x < fOffsetX) { + fOffsetX = 0; + } + + if (check(x, 1)) { + // Break the run + fOffsetX = fRuns.add(x, 0, 1, 0, 0, fOffsetX); + safelyAddAlpha(&fRuns.fAlpha[x], alpha); + } +} + +void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { + checkY(y); + x -= fLeft; + + if (x < fOffsetX) { + fOffsetX = 0; + } + + if (check(x, width)) { + // Break the run + fOffsetX = fRuns.add(x, 0, width, 0, 0, fOffsetX); + for(int i = x; i < x + width; i += fRuns.fRuns[i]) { + safelyAddAlpha(&fRuns.fAlpha[i], alpha); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +// Return the alpha of a trapezoid whose height is 1 +static inline SkAlpha trapezoidToAlpha(SkFixed l1, SkFixed l2) { + SkASSERT(l1 >= 0 && l2 >= 0); + return (l1 + l2) >> 9; +} + +// The alpha of right-triangle (a, a*b), in 16 bits +static inline SkFixed partialTriangleToAlpha16(SkFixed a, SkFixed b) { + SkASSERT(a <= SK_Fixed1); + // SkFixedMul(SkFixedMul(a, a), b) >> 1 + // return ((((a >> 8) * (a >> 8)) >> 8) * (b >> 8)) >> 1; + return (a >> 11) * (a >> 11) * (b >> 11); +} + +// The alpha of right-triangle (a, a*b) +static inline SkAlpha partialTriangleToAlpha(SkFixed a, SkFixed b) { + return partialTriangleToAlpha16(a, b) >> 8; +} + +static inline SkAlpha getPartialAlpha(SkAlpha alpha, SkFixed partialHeight) { + return SkToU8(SkFixedRoundToInt(alpha * partialHeight)); +} + +static inline SkAlpha getPartialAlpha(SkAlpha alpha, SkAlpha fullAlpha) { + return ((uint16_t)alpha * fullAlpha) >> 8; +} + +// For SkFixed that's close to SK_Fixed1, we can't convert it to alpha by just shifting right. +// For example, when f = SK_Fixed1, right shifting 8 will get 256, but we need 255. +// This is rarely the problem so we'll only use this for blitting rectangles. +static inline SkAlpha f2a(SkFixed f) { + SkASSERT(f <= SK_Fixed1); + return getPartialAlpha(0xFF, f); +} + +// Suppose that line (l1, y)-(r1, y+1) intersects with (l2, y)-(r2, y+1), +// approximate (very coarsely) the x coordinate of the intersection. +static inline SkFixed approximateIntersection(SkFixed l1, SkFixed r1, SkFixed l2, SkFixed r2) { + if (l1 > r1) { SkTSwap(l1, r1); } + if (l2 > r2) { SkTSwap(l2, r2); } + return (SkTMax(l1, l2) + SkTMin(r1, r2)) >> 1; +} + +// Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0] +static inline void computeAlphaAboveLine(SkAlpha* alphas, SkFixed l, SkFixed r, + SkFixed dY, SkAlpha fullAlpha) { + SkASSERT(l <= r); + SkASSERT(l >> 16 == 0); + int R = SkFixedCeilToInt(r); + if (R == 0) { + return; + } else if (R == 1) { + alphas[0] = getPartialAlpha(((R << 17) - l - r) >> 9, fullAlpha); + } else { + SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle + SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle + SkFixed firstH = SkFixedMul(first, dY); // vertical edge of the left-most triangle + alphas[0] = SkFixedMul(first, firstH) >> 9; // triangle alpha + SkFixed alpha16 = firstH + (dY >> 1); // rectangle plus triangle + for (int i = 1; i < R - 1; ++i) { + alphas[i] = alpha16 >> 8; + alpha16 += dY; + } + alphas[R - 1] = fullAlpha - partialTriangleToAlpha(last, dY); + } +} + +// Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0] +static inline void computeAlphaBelowLine( + SkAlpha* alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha) { + SkASSERT(l <= r); + SkASSERT(l >> 16 == 0); + int R = SkFixedCeilToInt(r); + if (R == 0) { + return; + } else if (R == 1) { + alphas[0] = getPartialAlpha(trapezoidToAlpha(l, r), fullAlpha); + } else { + SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle + SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle + SkFixed lastH = SkFixedMul(last, dY); // vertical edge of the right-most triangle + alphas[R-1] = SkFixedMul(last, lastH) >> 9; // triangle alpha + SkFixed alpha16 = lastH + (dY >> 1); // rectangle plus triangle + for (int i = R - 2; i > 0; i--) { + alphas[i] = alpha16 >> 8; + alpha16 += dY; + } + alphas[0] = fullAlpha - partialTriangleToAlpha(first, dY); + } +} + +// Note that if fullAlpha != 0xFF, we'll multiply alpha by fullAlpha +static SK_ALWAYS_INLINE void blit_single_alpha(AdditiveBlitter* blitter, int y, int x, + SkAlpha alpha, SkAlpha fullAlpha, SkAlpha* maskRow, + bool isUsingMask, bool noRealBlitter, bool needSafeCheck) { + if (isUsingMask) { + if (fullAlpha == 0xFF && !noRealBlitter) { // noRealBlitter is needed for concave paths + maskRow[x] = alpha; + } else if (needSafeCheck) { + safelyAddAlpha(&maskRow[x], getPartialAlpha(alpha, fullAlpha)); + } else { + addAlpha(&maskRow[x], getPartialAlpha(alpha, fullAlpha)); + } + } else { + if (fullAlpha == 0xFF && !noRealBlitter) { + blitter->getRealBlitter()->blitV(x, y, 1, alpha); + } else { + blitter->blitAntiH(x, y, getPartialAlpha(alpha, fullAlpha)); + } + } +} + +static SK_ALWAYS_INLINE void blit_two_alphas(AdditiveBlitter* blitter, int y, int x, + SkAlpha a1, SkAlpha a2, SkAlpha fullAlpha, SkAlpha* maskRow, + bool isUsingMask, bool noRealBlitter, bool needSafeCheck) { + if (isUsingMask) { + if (needSafeCheck) { + safelyAddAlpha(&maskRow[x], a1); + safelyAddAlpha(&maskRow[x + 1], a2); + } else { + addAlpha(&maskRow[x], a1); + addAlpha(&maskRow[x + 1], a2); + } + } else { + if (fullAlpha == 0xFF && !noRealBlitter) { + blitter->getRealBlitter()->blitAntiH2(x, y, a1, a2); + } else { + blitter->blitAntiH(x, y, a1); + blitter->blitAntiH(x + 1, y, a2); + } + } +} + +// It's important that this is inline. Otherwise it'll be much slower. +static SK_ALWAYS_INLINE void blit_full_alpha(AdditiveBlitter* blitter, int y, int x, int len, + SkAlpha fullAlpha, SkAlpha* maskRow, bool isUsingMask, + bool noRealBlitter, bool needSafeCheck) { + if (isUsingMask) { + for (int i = 0; i < len; ++i) { + if (needSafeCheck) { + safelyAddAlpha(&maskRow[x + i], fullAlpha); + } else { + addAlpha(&maskRow[x + i], fullAlpha); + } + } + } else { + if (fullAlpha == 0xFF && !noRealBlitter) { + blitter->getRealBlitter()->blitH(x, y, len); + } else { + blitter->blitAntiH(x, y, len, fullAlpha); + } + } +} + +static void blit_aaa_trapezoid_row(AdditiveBlitter* blitter, int y, + SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, + SkFixed lDY, SkFixed rDY, SkAlpha fullAlpha, SkAlpha* maskRow, + bool isUsingMask, bool noRealBlitter, bool needSafeCheck) { + int L = SkFixedFloorToInt(ul), R = SkFixedCeilToInt(lr); + int len = R - L; + + if (len == 1) { + SkAlpha alpha = trapezoidToAlpha(ur - ul, lr - ll); + blit_single_alpha(blitter, y, L, alpha, fullAlpha, maskRow, isUsingMask, noRealBlitter, + needSafeCheck); + return; + } + + // SkDebugf("y = %d, len = %d, ul = %f, ur = %f, ll = %f, lr = %f\n", y, len, + // SkFixedToFloat(ul), SkFixedToFloat(ur), SkFixedToFloat(ll), SkFixedToFloat(lr)); + + const int kQuickLen = 31; + // This is faster than SkAutoSMalloc<1024> + char quickMemory[(sizeof(SkAlpha) * 2 + sizeof(int16_t)) * (kQuickLen + 1)]; + SkAlpha* alphas; + + if (len <= kQuickLen) { + alphas = (SkAlpha*)quickMemory; + } else { + alphas = new SkAlpha[(len + 1) * (sizeof(SkAlpha) * 2 + sizeof(int16_t))]; + } + + SkAlpha* tempAlphas = alphas + len + 1; + int16_t* runs = (int16_t*)(alphas + (len + 1) * 2); + + for (int i = 0; i < len; ++i) { + runs[i] = 1; + alphas[i] = fullAlpha; + } + runs[len] = 0; + + int uL = SkFixedFloorToInt(ul); + int lL = SkFixedCeilToInt(ll); + if (uL + 2 == lL) { // We only need to compute two triangles, accelerate this special case + SkFixed first = SkIntToFixed(uL) + SK_Fixed1 - ul; + SkFixed second = ll - ul - first; + SkAlpha a1 = fullAlpha - partialTriangleToAlpha(first, lDY); + SkAlpha a2 = partialTriangleToAlpha(second, lDY); + alphas[0] = alphas[0] > a1 ? alphas[0] - a1 : 0; + alphas[1] = alphas[1] > a2 ? alphas[1] - a2 : 0; + } else { + computeAlphaBelowLine(tempAlphas + uL - L, ul - SkIntToFixed(uL), ll - SkIntToFixed(uL), + lDY, fullAlpha); + for (int i = uL; i < lL; ++i) { + if (alphas[i - L] > tempAlphas[i - L]) { + alphas[i - L] -= tempAlphas[i - L]; + } else { + alphas[i - L] = 0; + } + } + } + + int uR = SkFixedFloorToInt(ur); + int lR = SkFixedCeilToInt(lr); + if (uR + 2 == lR) { // We only need to compute two triangles, accelerate this special case + SkFixed first = SkIntToFixed(uR) + SK_Fixed1 - ur; + SkFixed second = lr - ur - first; + SkAlpha a1 = partialTriangleToAlpha(first, rDY); + SkAlpha a2 = fullAlpha - partialTriangleToAlpha(second, rDY); + alphas[len-2] = alphas[len-2] > a1 ? alphas[len-2] - a1 : 0; + alphas[len-1] = alphas[len-1] > a2 ? alphas[len-1] - a2 : 0; + } else { + computeAlphaAboveLine(tempAlphas + uR - L, ur - SkIntToFixed(uR), lr - SkIntToFixed(uR), + rDY, fullAlpha); + for (int i = uR; i < lR; ++i) { + if (alphas[i - L] > tempAlphas[i - L]) { + alphas[i - L] -= tempAlphas[i - L]; + } else { + alphas[i - L] = 0; + } + } + } + + if (isUsingMask) { + for (int i = 0; i < len; ++i) { + if (needSafeCheck) { + safelyAddAlpha(&maskRow[L + i], alphas[i]); + } else { + addAlpha(&maskRow[L + i], alphas[i]); + } + } + } else { + if (fullAlpha == 0xFF && !noRealBlitter) { + // Real blitter is faster than RunBasedAdditiveBlitter + blitter->getRealBlitter()->blitAntiH(L, y, alphas, runs); + } else { + blitter->blitAntiH(L, y, alphas, len); + } + } + + if (len > kQuickLen) { + delete [] alphas; + } +} + +static SK_ALWAYS_INLINE void blit_trapezoid_row(AdditiveBlitter* blitter, int y, + SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, + SkFixed lDY, SkFixed rDY, SkAlpha fullAlpha, + SkAlpha* maskRow, bool isUsingMask, bool noRealBlitter = false, + bool needSafeCheck = false) { + SkASSERT(lDY >= 0 && rDY >= 0); // We should only send in the absolte value + + if (ul > ur) { +#ifdef SK_DEBUG + // SkDebugf("ul = %f > ur = %f!\n", SkFixedToFloat(ul), SkFixedToFloat(ur)); +#endif + return; + } + + // Edge crosses. Approximate it. This should only happend due to precision limit, + // so the approximation could be very coarse. + if (ll > lr) { +#ifdef SK_DEBUG + // SkDebugf("approximate intersection: %d %f %f\n", y, + // SkFixedToFloat(ll), SkFixedToFloat(lr)); +#endif + ll = lr = approximateIntersection(ul, ll, ur, lr); + } + + if (ul == ur && ll == lr) { + return; // empty trapzoid + } + + // We're going to use the left line ul-ll and the rite line ur-lr + // to exclude the area that's not covered by the path. + // Swapping (ul, ll) or (ur, lr) won't affect that exclusion + // so we'll do that for simplicity. + if (ul > ll) { SkTSwap(ul, ll); } + if (ur > lr) { SkTSwap(ur, lr); } + + SkFixed joinLeft = SkFixedCeilToFixed(ll); + SkFixed joinRite = SkFixedFloorToFixed(ur); + if (joinLeft <= joinRite) { // There's a rect from joinLeft to joinRite that we can blit + if (ul < joinLeft) { + int len = SkFixedCeilToInt(joinLeft - ul); + if (len == 1) { + SkAlpha alpha = trapezoidToAlpha(joinLeft - ul, joinLeft - ll); + blit_single_alpha(blitter, y, ul >> 16, alpha, fullAlpha, maskRow, isUsingMask, + noRealBlitter, needSafeCheck); + } else if (len == 2) { + SkFixed first = joinLeft - SK_Fixed1 - ul; + SkFixed second = ll - ul - first; + SkAlpha a1 = partialTriangleToAlpha(first, lDY); + SkAlpha a2 = fullAlpha - partialTriangleToAlpha(second, lDY); + blit_two_alphas(blitter, y, ul >> 16, a1, a2, fullAlpha, maskRow, isUsingMask, + noRealBlitter, needSafeCheck); + } else { + blit_aaa_trapezoid_row(blitter, y, ul, joinLeft, ll, joinLeft, lDY, SK_MaxS32, + fullAlpha, maskRow, isUsingMask, noRealBlitter, + needSafeCheck); + } + } + // SkAAClip requires that we blit from left to right. + // Hence we must blit [ul, joinLeft] before blitting [joinLeft, joinRite] + if (joinLeft < joinRite) { + blit_full_alpha(blitter, y, SkFixedFloorToInt(joinLeft), + SkFixedFloorToInt(joinRite - joinLeft), + fullAlpha, maskRow, isUsingMask, noRealBlitter, needSafeCheck); + } + if (lr > joinRite) { + int len = SkFixedCeilToInt(lr - joinRite); + if (len == 1) { + SkAlpha alpha = trapezoidToAlpha(ur - joinRite, lr - joinRite); + blit_single_alpha(blitter, y, joinRite >> 16, alpha, fullAlpha, maskRow, + isUsingMask, noRealBlitter, needSafeCheck); + } else if (len == 2) { + SkFixed first = joinRite + SK_Fixed1 - ur; + SkFixed second = lr - ur - first; + SkAlpha a1 = fullAlpha - partialTriangleToAlpha(first, rDY); + SkAlpha a2 = partialTriangleToAlpha(second, rDY); + blit_two_alphas(blitter, y, joinRite >> 16, a1, a2, fullAlpha, maskRow, + isUsingMask, noRealBlitter, needSafeCheck); + } else { + blit_aaa_trapezoid_row(blitter, y, joinRite, ur, joinRite, lr, SK_MaxS32, rDY, + fullAlpha, maskRow, isUsingMask, noRealBlitter, + needSafeCheck); + } + } + } else { + blit_aaa_trapezoid_row(blitter, y, ul, ur, ll, lr, lDY, rDY, fullAlpha, maskRow, + isUsingMask, noRealBlitter, needSafeCheck); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static bool operator<(const SkAnalyticEdge& a, const SkAnalyticEdge& b) { + int valuea = a.fUpperY; + int valueb = b.fUpperY; + + if (valuea == valueb) { + valuea = a.fX; + valueb = b.fX; + } + + if (valuea == valueb) { + valuea = a.fDX; + valueb = b.fDX; + } + + return valuea < valueb; +} + +static SkAnalyticEdge* sort_edges(SkAnalyticEdge* list[], int count, SkAnalyticEdge** last) { + SkTQSort(list, list + count - 1); + + // now make the edges linked in sorted order + for (int i = 1; i < count; ++i) { + list[i - 1]->fNext = list[i]; + list[i]->fPrev = list[i - 1]; + } + + *last = list[count - 1]; + return list[0]; +} + +#ifdef SK_DEBUG + static void validate_sort(const SkAnalyticEdge* edge) { + SkFixed y = SkIntToFixed(-32768); + + while (edge->fUpperY != SK_MaxS32) { + edge->validate(); + SkASSERT(y <= edge->fUpperY); + + y = edge->fUpperY; + edge = (SkAnalyticEdge*)edge->fNext; + } + } +#else + #define validate_sort(edge) +#endif + +// return true if we're done with this edge +static bool update_edge(SkAnalyticEdge* edge, SkFixed last_y) { + if (last_y >= edge->fLowerY) { + if (edge->fCurveCount < 0) { + if (static_cast(edge)->updateCubic()) { + return false; + } + } else if (edge->fCurveCount > 0) { + if (static_cast(edge)->updateQuadratic()) { + return false; + } + } + return true; + } + SkASSERT(false); + return false; +} + +// For an edge, we consider it smooth if the Dx doesn't change much, and Dy is large enough +// For curves that are updating, the Dx is not changing much if fQDx/fCDx and fQDy/fCDy are +// relatively large compared to fQDDx/QCDDx and fQDDy/fCDDy +static inline bool isSmoothEnough(SkAnalyticEdge* thisEdge, SkAnalyticEdge* nextEdge, int stop_y) { + if (thisEdge->fCurveCount < 0) { + const SkCubicEdge& cEdge = static_cast(thisEdge)->fCEdge; + int ddshift = cEdge.fCurveShift; + return SkAbs32(cEdge.fCDx) >> 1 >= SkAbs32(cEdge.fCDDx) >> ddshift && + SkAbs32(cEdge.fCDy) >> 1 >= SkAbs32(cEdge.fCDDy) >> ddshift && + // current Dy is (fCDy - (fCDDy >> ddshift)) >> dshift + (cEdge.fCDy - (cEdge.fCDDy >> ddshift)) >> cEdge.fCubicDShift >= SK_Fixed1; + } else if (thisEdge->fCurveCount > 0) { + const SkQuadraticEdge& qEdge = static_cast(thisEdge)->fQEdge; + return SkAbs32(qEdge.fQDx) >> 1 >= SkAbs32(qEdge.fQDDx) && + SkAbs32(qEdge.fQDy) >> 1 >= SkAbs32(qEdge.fQDDy) && + // current Dy is (fQDy - fQDDy) >> shift + (qEdge.fQDy - qEdge.fQDDy) >> qEdge.fCurveShift + >= SK_Fixed1; + } + return SkAbs32(nextEdge->fDX - thisEdge->fDX) <= SK_Fixed1 && // DDx should be small + nextEdge->fLowerY - nextEdge->fUpperY >= SK_Fixed1; // Dy should be large +} + +// Check if the leftE and riteE are changing smoothly in terms of fDX. +// If yes, we can later skip the fractional y and directly jump to integer y. +static inline bool isSmoothEnough(SkAnalyticEdge* leftE, SkAnalyticEdge* riteE, + SkAnalyticEdge* currE, int stop_y) { + if (currE->fUpperY >= stop_y << 16) { + return false; // We're at the end so we won't skip anything + } + if (leftE->fLowerY + SK_Fixed1 < riteE->fLowerY) { + return isSmoothEnough(leftE, currE, stop_y); // Only leftE is changing + } else if (leftE->fLowerY > riteE->fLowerY + SK_Fixed1) { + return isSmoothEnough(riteE, currE, stop_y); // Only riteE is changing + } + + // Now both edges are changing, find the second next edge + SkAnalyticEdge* nextCurrE = currE->fNext; + if (nextCurrE->fUpperY >= stop_y << 16) { // Check if we're at the end + return false; + } + if (*nextCurrE < *currE) { + SkTSwap(currE, nextCurrE); + } + return isSmoothEnough(leftE, currE, stop_y) && isSmoothEnough(riteE, nextCurrE, stop_y); +} + +static inline void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, + AdditiveBlitter* blitter, int start_y, int stop_y, SkFixed leftBound, SkFixed riteBound, + bool isUsingMask) { + validate_sort((SkAnalyticEdge*)prevHead->fNext); + + SkAnalyticEdge* leftE = (SkAnalyticEdge*) prevHead->fNext; + SkAnalyticEdge* riteE = (SkAnalyticEdge*) leftE->fNext; + SkAnalyticEdge* currE = (SkAnalyticEdge*) riteE->fNext; + + SkFixed y = SkTMax(leftE->fUpperY, riteE->fUpperY); + + #ifdef SK_DEBUG + int frac_y_cnt = 0; + int total_y_cnt = 0; + #endif + + for (;;) { + // We have to check fLowerY first because some edges might be alone (e.g., there's only + // a left edge but no right edge in a given y scan line) due to precision limit. + while (leftE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges + if (update_edge(leftE, y)) { + if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) { + goto END_WALK; + } + leftE = currE; + currE = (SkAnalyticEdge*)currE->fNext; + } + } + while (riteE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges + if (update_edge(riteE, y)) { + if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) { + goto END_WALK; + } + riteE = currE; + currE = (SkAnalyticEdge*)currE->fNext; + } + } + + SkASSERT(leftE); + SkASSERT(riteE); + + // check our bottom clip + if (SkFixedFloorToInt(y) >= stop_y) { + break; + } + + SkASSERT(SkFixedFloorToInt(leftE->fUpperY) <= stop_y); + SkASSERT(SkFixedFloorToInt(riteE->fUpperY) <= stop_y); + + leftE->goY(y); + riteE->goY(y); + + if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX && + leftE->fDX > riteE->fDX)) { + SkTSwap(leftE, riteE); + } + + SkFixed local_bot_fixed = SkMin32(leftE->fLowerY, riteE->fLowerY); + if (isSmoothEnough(leftE, riteE, currE, stop_y)) { + local_bot_fixed = SkFixedCeilToFixed(local_bot_fixed); + } + local_bot_fixed = SkMin32(local_bot_fixed, SkIntToFixed(stop_y)); + + SkFixed left = SkTMax(leftBound, leftE->fX); + SkFixed dLeft = leftE->fDX; + SkFixed rite = SkTMin(riteBound, riteE->fX); + SkFixed dRite = riteE->fDX; + if (0 == (dLeft | dRite)) { + int fullLeft = SkFixedCeilToInt(left); + int fullRite = SkFixedFloorToInt(rite); + SkFixed partialLeft = SkIntToFixed(fullLeft) - left; + SkFixed partialRite = rite - SkIntToFixed(fullRite); + int fullTop = SkFixedCeilToInt(y); + int fullBot = SkFixedFloorToInt(local_bot_fixed); + SkFixed partialTop = SkIntToFixed(fullTop) - y; + SkFixed partialBot = local_bot_fixed - SkIntToFixed(fullBot); + if (fullTop > fullBot) { // The rectangle is within one pixel height... + partialTop -= (SK_Fixed1 - partialBot); + partialBot = 0; + } + + if (fullRite >= fullLeft) { + if (partialTop > 0) { // blit first partial row + if (partialLeft > 0) { + blitter->blitAntiH(fullLeft - 1, fullTop - 1, + f2a(SkFixedMul(partialTop, partialLeft))); + } + blitter->blitAntiH(fullLeft, fullTop - 1, fullRite - fullLeft, + f2a(partialTop)); + if (partialRite > 0) { + blitter->blitAntiH(fullRite, fullTop - 1, + f2a(SkFixedMul(partialTop, partialRite))); + } + blitter->flush_if_y_changed(y, y + partialTop); + } + + // Blit all full-height rows from fullTop to fullBot + if (fullBot > fullTop && + // SkAAClip cannot handle the empty rect so check the non-emptiness here + // (bug chromium:662800) + (fullRite > fullLeft || f2a(partialLeft) > 0 || f2a(partialRite) > 0)) { + blitter->getRealBlitter()->blitAntiRect(fullLeft - 1, fullTop, + fullRite - fullLeft, fullBot - fullTop, + f2a(partialLeft), f2a(partialRite)); + } + + if (partialBot > 0) { // blit last partial row + if (partialLeft > 0) { + blitter->blitAntiH(fullLeft - 1, fullBot, + f2a(SkFixedMul(partialBot, partialLeft))); + } + blitter->blitAntiH(fullLeft, fullBot, fullRite - fullLeft, f2a(partialBot)); + if (partialRite > 0) { + blitter->blitAntiH(fullRite, fullBot, + f2a(SkFixedMul(partialBot, partialRite))); + } + } + } else { // left and rite are within the same pixel + if (partialTop > 0) { + blitter->blitAntiH(fullLeft - 1, fullTop - 1, 1, + f2a(SkFixedMul(partialTop, rite - left))); + blitter->flush_if_y_changed(y, y + partialTop); + } + if (fullBot > fullTop) { + blitter->getRealBlitter()->blitV(fullLeft - 1, fullTop, fullBot - fullTop, + f2a(rite - left)); + } + if (partialBot > 0) { + blitter->blitAntiH(fullLeft - 1, fullBot, 1, + f2a(SkFixedMul(partialBot, rite - left))); + } + } + + y = local_bot_fixed; + } else { + // The following constant are used to snap X + // We snap X mainly for speedup (no tiny triangle) and + // avoiding edge cases caused by precision errors + const SkFixed kSnapDigit = SK_Fixed1 >> 4; + const SkFixed kSnapHalf = kSnapDigit >> 1; + const SkFixed kSnapMask = (-1 ^ (kSnapDigit - 1)); + left += kSnapHalf; rite += kSnapHalf; // For fast rounding + + // Number of blit_trapezoid_row calls we'll have + int count = SkFixedCeilToInt(local_bot_fixed) - SkFixedFloorToInt(y); + #ifdef SK_DEBUG + total_y_cnt += count; + frac_y_cnt += ((int)(y & 0xFFFF0000) != y); + if ((int)(y & 0xFFFF0000) != y) { + // SkDebugf("frac_y = %f\n", SkFixedToFloat(y)); + } + #endif + + // If we're using mask blitter, we advance the mask row in this function + // to save some "if" condition checks. + SkAlpha* maskRow = nullptr; + if (isUsingMask) { + maskRow = static_cast(blitter)->getRow(y >> 16); + } + + // Instead of writing one loop that handles both partial-row blit_trapezoid_row + // and full-row trapezoid_row together, we use the following 3-stage flow to + // handle partial-row blit and full-row blit separately. It will save us much time + // on changing y, left, and rite. + if (count > 1) { + if ((int)(y & 0xFFFF0000) != y) { // There's a partial-row on the top + count--; + SkFixed nextY = SkFixedCeilToFixed(y + 1); + SkFixed dY = nextY - y; + SkFixed nextLeft = left + SkFixedMul(dLeft, dY); + SkFixed nextRite = rite + SkFixedMul(dRite, dY); + SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound && + (nextLeft & kSnapMask) >= leftBound && + (nextRite & kSnapMask) <= riteBound); + blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask, + nextLeft & kSnapMask, nextRite & kSnapMask, leftE->fDY, riteE->fDY, + getPartialAlpha(0xFF, dY), maskRow, isUsingMask); + blitter->flush_if_y_changed(y, nextY); + left = nextLeft; rite = nextRite; y = nextY; + } + + while (count > 1) { // Full rows in the middle + count--; + if (isUsingMask) { + maskRow = static_cast(blitter)->getRow(y >> 16); + } + SkFixed nextY = y + SK_Fixed1, nextLeft = left + dLeft, nextRite = rite + dRite; + SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound && + (nextLeft & kSnapMask) >= leftBound && + (nextRite & kSnapMask) <= riteBound); + blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask, + nextLeft & kSnapMask, nextRite & kSnapMask, + leftE->fDY, riteE->fDY, 0xFF, maskRow, isUsingMask); + blitter->flush_if_y_changed(y, nextY); + left = nextLeft; rite = nextRite; y = nextY; + } + } + + if (isUsingMask) { + maskRow = static_cast(blitter)->getRow(y >> 16); + } + + SkFixed dY = local_bot_fixed - y; // partial-row on the bottom + SkASSERT(dY <= SK_Fixed1); + // Smooth jumping to integer y may make the last nextLeft/nextRite out of bound. + // Take them back into the bound here. + // Note that we substract kSnapHalf later so we have to add them to leftBound/riteBound + SkFixed nextLeft = SkTMax(left + SkFixedMul(dLeft, dY), leftBound + kSnapHalf); + SkFixed nextRite = SkTMin(rite + SkFixedMul(dRite, dY), riteBound + kSnapHalf); + SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound && + (nextLeft & kSnapMask) >= leftBound && (nextRite & kSnapMask) <= riteBound); + blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask, + nextLeft & kSnapMask, nextRite & kSnapMask, leftE->fDY, riteE->fDY, + getPartialAlpha(0xFF, dY), maskRow, isUsingMask); + blitter->flush_if_y_changed(y, local_bot_fixed); + left = nextLeft; rite = nextRite; y = local_bot_fixed; + left -= kSnapHalf; rite -= kSnapHalf; + } + + leftE->fX = left; + riteE->fX = rite; + leftE->fY = riteE->fY = y; + } + +END_WALK: + ; + #ifdef SK_DEBUG + // SkDebugf("frac_y_cnt = %d, total_y_cnt = %d\n", frac_y_cnt, total_y_cnt); + #endif +} + +/////////////////////////////////////////////////////////////////////////////// + +static inline void updateNextNextY(SkFixed y, SkFixed nextY, SkFixed* nextNextY) { + *nextNextY = y > nextY && y < *nextNextY ? y : *nextNextY; +} + +static inline void checkIntersection(const SkAnalyticEdge* edge, SkFixed nextY, SkFixed* nextNextY) +{ + if (edge->fPrev->fPrev && edge->fPrev->fX + edge->fPrev->fDX > edge->fX + edge->fDX) { + *nextNextY = nextY + (SK_Fixed1 >> SkAnalyticEdge::kDefaultAccuracy); + } +} + +static void insert_new_edges(SkAnalyticEdge* newEdge, SkFixed y, SkFixed* nextNextY) { + if (newEdge->fUpperY > y) { + updateNextNextY(newEdge->fUpperY, y, nextNextY); + return; + } + SkAnalyticEdge* prev = newEdge->fPrev; + if (prev->fX <= newEdge->fX) { + while (newEdge->fUpperY <= y) { + checkIntersection(newEdge, y, nextNextY); + updateNextNextY(newEdge->fLowerY, y, nextNextY); + newEdge = newEdge->fNext; + } + updateNextNextY(newEdge->fUpperY, y, nextNextY); + return; + } + // find first x pos to insert + SkAnalyticEdge* start = backward_insert_start(prev, newEdge->fX); + //insert the lot, fixing up the links as we go + do { + SkAnalyticEdge* next = newEdge->fNext; + do { + if (start->fNext == newEdge) { + goto nextEdge; + } + SkAnalyticEdge* after = start->fNext; + if (after->fX >= newEdge->fX) { + break; + } + SkASSERT(start != after); + start = after; + } while (true); + remove_edge(newEdge); + insert_edge_after(newEdge, start); +nextEdge: + checkIntersection(newEdge, y, nextNextY); + updateNextNextY(newEdge->fLowerY, y, nextNextY); + start = newEdge; + newEdge = next; + } while (newEdge->fUpperY <= y); + updateNextNextY(newEdge->fUpperY, y, nextNextY); +} + +static void validate_edges_for_y(const SkAnalyticEdge* edge, SkFixed y) { +#ifdef SK_DEBUG + while (edge->fUpperY <= y) { + SkASSERT(edge->fPrev && edge->fNext); + SkASSERT(edge->fPrev->fNext == edge); + SkASSERT(edge->fNext->fPrev == edge); + SkASSERT(edge->fUpperY <= edge->fLowerY); + SkASSERT(edge->fPrev->fPrev == nullptr || edge->fPrev->fX <= edge->fX); + edge = edge->fNext; + } +#endif +} + +// Return true if prev->fX, next->fX are too close in the current pixel row. +static inline bool edges_too_close(SkAnalyticEdge* prev, SkAnalyticEdge* next, SkFixed lowerY) { + // Note that even if the following test failed, the edges might still be very close to each + // other at some point within the current pixel row because of prev->fDX and next->fDX. + // However, to handle that case, we have to sacrafice more performance. + // I think the current quality is good enough (mainly by looking at Nebraska-StateSeal.svg) + // so I'll ignore fDX for performance tradeoff. + return next && prev && next->fUpperY < lowerY && prev->fX >= next->fX - SkAbs32(next->fDX); + // The following is more accurate but also slower. + // return (prev && prev->fPrev && next && next->fNext != nullptr && next->fUpperY < lowerY && + // prev->fX + SkAbs32(prev->fDX) >= next->fX - SkAbs32(next->fDX)); +} + +// This function exists for the case where the previous rite edge is removed because +// its fLowerY <= nextY +static inline bool edges_too_close(int prevRite, SkFixed ul, SkFixed ll) { + return prevRite > SkFixedFloorToInt(ul) || prevRite > SkFixedFloorToInt(ll); +} + +static inline void blit_saved_trapezoid(SkAnalyticEdge* leftE, SkFixed lowerY, + SkFixed lowerLeft, SkFixed lowerRite, + AdditiveBlitter* blitter, SkAlpha* maskRow, bool isUsingMask, bool noRealBlitter, + SkFixed leftClip, SkFixed rightClip) { + SkAnalyticEdge* riteE = leftE->fRiteE; + SkASSERT(riteE); + SkASSERT(riteE->fNext == nullptr || leftE->fSavedY == riteE->fSavedY); + SkASSERT(SkFixedFloorToInt(lowerY - 1) == SkFixedFloorToInt(leftE->fSavedY)); + int y = SkFixedFloorToInt(leftE->fSavedY); + // Instead of using f2a(lowerY - leftE->fSavedY), we use the following fullAlpha + // to elimiate cumulative error: if there are many fractional y scan lines within the + // same row, the former may accumulate the rounding error while the later won't. + SkAlpha fullAlpha = f2a(lowerY - SkIntToFixed(y)) - f2a(leftE->fSavedY - SkIntToFixed(y)); + // We need fSavedDY because the (quad or cubic) edge might be updated + blit_trapezoid_row(blitter, y, + SkTMax(leftE->fSavedX, leftClip), SkTMin(riteE->fSavedX, rightClip), + SkTMax(lowerLeft, leftClip), SkTMin(lowerRite, rightClip), + leftE->fSavedDY, riteE->fSavedDY, fullAlpha, maskRow, isUsingMask, + noRealBlitter || + (fullAlpha == 0xFF && (edges_too_close(leftE->fPrev, leftE, lowerY) + || edges_too_close(riteE, riteE->fNext, lowerY))), + true); + leftE->fRiteE = nullptr; +} + +static inline void deferred_blit(SkAnalyticEdge* leftE, SkAnalyticEdge* riteE, + SkFixed left, SkFixed leftDY, // don't save leftE->fX/fDY as they may have been updated + SkFixed y, SkFixed nextY, bool isIntegralNextY, bool leftEnds, bool riteEnds, + AdditiveBlitter* blitter, SkAlpha* maskRow, bool isUsingMask, bool noRealBlitter, + SkFixed leftClip, SkFixed rightClip, int yShift) { + if (leftE->fRiteE && leftE->fRiteE != riteE) { + // leftE's right edge changed. Blit the saved trapezoid. + SkASSERT(leftE->fRiteE->fNext == nullptr || leftE->fRiteE->fY == y); + blit_saved_trapezoid(leftE, y, left, leftE->fRiteE->fX, + blitter, maskRow, isUsingMask, noRealBlitter, leftClip, rightClip); + } + if (!leftE->fRiteE) { + // Save and defer blitting the trapezoid + SkASSERT(riteE->fRiteE == nullptr); + SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY); + SkASSERT(riteE->fNext == nullptr || riteE->fY == y); + leftE->saveXY(left, y, leftDY); + riteE->saveXY(riteE->fX, y, riteE->fDY); + leftE->fRiteE = riteE; + } + SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY); + riteE->goY(nextY, yShift); + // Always blit when edges end or nextY is integral + if (isIntegralNextY || leftEnds || riteEnds) { + blit_saved_trapezoid(leftE, nextY, leftE->fX, riteE->fX, + blitter, maskRow, isUsingMask, noRealBlitter, leftClip, rightClip); + } +} + +static void aaa_walk_edges(SkAnalyticEdge* prevHead, SkAnalyticEdge* nextTail, + SkPath::FillType fillType, AdditiveBlitter* blitter, int start_y, int stop_y, + SkFixed leftClip, SkFixed rightClip, bool isUsingMask, bool forceRLE, bool useDeferred, + bool skipIntersect) { + prevHead->fX = prevHead->fUpperX = leftClip; + nextTail->fX = nextTail->fUpperX = rightClip; + SkFixed y = SkTMax(prevHead->fNext->fUpperY, SkIntToFixed(start_y)); + SkFixed nextNextY = SK_MaxS32; + + { + SkAnalyticEdge* edge; + for(edge = prevHead->fNext; edge->fUpperY <= y; edge = edge->fNext) { + edge->goY(y); + updateNextNextY(edge->fLowerY, y, &nextNextY); + } + updateNextNextY(edge->fUpperY, y, &nextNextY); + } + + // returns 1 for evenodd, -1 for winding, regardless of inverse-ness + int windingMask = (fillType & 1) ? 1 : -1; + + bool isInverse = SkPath::IsInverseFillType(fillType); + + if (isInverse && SkIntToFixed(start_y) != y) { + int width = SkFixedFloorToInt(rightClip - leftClip); + if (SkFixedFloorToInt(y) != start_y) { + blitter->getRealBlitter()->blitRect(SkFixedFloorToInt(leftClip), start_y, + width, SkFixedFloorToInt(y) - start_y); + start_y = SkFixedFloorToInt(y); + } + SkAlpha* maskRow = isUsingMask ? static_cast(blitter)->getRow(start_y) + : nullptr; + blit_full_alpha(blitter, start_y, SkFixedFloorToInt(leftClip), width, + f2a(y - SkIntToFixed(start_y)), maskRow, isUsingMask, false, false); + } + + while (true) { + int w = 0; + bool in_interval = isInverse; + SkFixed prevX = prevHead->fX; + SkFixed nextY = SkTMin(nextNextY, SkFixedCeilToFixed(y + 1)); + bool isIntegralNextY = (nextY & (SK_Fixed1 - 1)) == 0; + SkAnalyticEdge* currE = prevHead->fNext; + SkAnalyticEdge* leftE = prevHead; + SkFixed left = leftClip; + SkFixed leftDY = 0; + bool leftEnds = false; + int prevRite = SkFixedFloorToInt(leftClip); + + nextNextY = SK_MaxS32; + + SkASSERT((nextY & ((SK_Fixed1 >> 2) - 1)) == 0); + int yShift = 0; + if ((nextY - y) & (SK_Fixed1 >> 2)) { + yShift = 2; + nextY = y + (SK_Fixed1 >> 2); + } else if ((nextY - y) & (SK_Fixed1 >> 1)) { + yShift = 1; + SkASSERT(nextY == y + (SK_Fixed1 >> 1)); + } + + SkAlpha fullAlpha = f2a(nextY - y); + + // If we're using mask blitter, we advance the mask row in this function + // to save some "if" condition checks. + SkAlpha* maskRow = nullptr; + if (isUsingMask) { + maskRow = static_cast(blitter)->getRow(SkFixedFloorToInt(y)); + } + + SkASSERT(currE->fPrev == prevHead); + validate_edges_for_y(currE, y); + + // Even if next - y == SK_Fixed1, we can still break the left-to-right order requirement + // of the SKAAClip: |\| (two trapezoids with overlapping middle wedges) + bool noRealBlitter = forceRLE; // forceRLE && (nextY - y != SK_Fixed1); + + while (currE->fUpperY <= y) { + SkASSERT(currE->fLowerY >= nextY); + SkASSERT(currE->fY == y); + + w += currE->fWinding; + bool prev_in_interval = in_interval; + in_interval = !(w & windingMask) == isInverse; + + bool isLeft = in_interval && !prev_in_interval; + bool isRite = !in_interval && prev_in_interval; + bool currEnds = currE->fLowerY == nextY; + + if (useDeferred) { + if (currE->fRiteE && !isLeft) { + // currE is a left edge previously, but now it's not. + // Blit the trapezoid between fSavedY and y. + SkASSERT(currE->fRiteE->fY == y); + blit_saved_trapezoid(currE, y, currE->fX, currE->fRiteE->fX, + blitter, maskRow, isUsingMask, noRealBlitter, leftClip, rightClip); + } + if (leftE->fRiteE == currE && !isRite) { + // currE is a right edge previously, but now it's not. + // Moreover, its corresponding leftE doesn't change (otherwise we'll handle it + // in the previous if clause). Hence we blit the trapezoid. + blit_saved_trapezoid(leftE, y, left, currE->fX, + blitter, maskRow, isUsingMask, noRealBlitter, leftClip, rightClip); + } + } + + if (isRite) { + if (useDeferred) { + deferred_blit(leftE, currE, left, leftDY, y, nextY, isIntegralNextY, + leftEnds, currEnds, blitter, maskRow, isUsingMask, noRealBlitter, + leftClip, rightClip, yShift); + } else { + SkFixed rite = currE->fX; + currE->goY(nextY, yShift); + leftE->fX = SkTMax(leftClip, leftE->fX); + rite = SkTMin(rightClip, rite); + currE->fX = SkTMin(rightClip, currE->fX); + blit_trapezoid_row(blitter, y >> 16, left, rite, leftE->fX, currE->fX, + leftDY, currE->fDY, fullAlpha, maskRow, isUsingMask, + noRealBlitter || (fullAlpha == 0xFF && ( + edges_too_close(prevRite, left, leftE->fX) || + edges_too_close(currE, currE->fNext, nextY) + )), + true); + prevRite = SkFixedCeilToInt(SkTMax(rite, currE->fX)); + } + } else { + if (isLeft) { + left = SkTMax(currE->fX, leftClip); + leftDY = currE->fDY; + leftE = currE; + leftEnds = leftE->fLowerY == nextY; + } + currE->goY(nextY, yShift); + } + + + SkAnalyticEdge* next = currE->fNext; + SkFixed newX; + + while (currE->fLowerY <= nextY) { + if (currE->fCurveCount < 0) { + SkAnalyticCubicEdge* cubicEdge = (SkAnalyticCubicEdge*)currE; + cubicEdge->keepContinuous(); + if (!cubicEdge->updateCubic()) { + break; + } + } else if (currE->fCurveCount > 0) { + SkAnalyticQuadraticEdge* quadEdge = (SkAnalyticQuadraticEdge*)currE; + quadEdge->keepContinuous(); + if (!quadEdge->updateQuadratic()) { + break; + } + } else { + break; + } + } + SkASSERT(currE->fY == nextY); + + if (currE->fLowerY <= nextY) { + remove_edge(currE); + } else { + updateNextNextY(currE->fLowerY, nextY, &nextNextY); + newX = currE->fX; + SkASSERT(currE->fLowerY > nextY); + if (newX < prevX) { // ripple currE backwards until it is x-sorted + // If the crossing edge is a right edge, blit the saved trapezoid. + if (leftE->fRiteE == currE && useDeferred) { + SkASSERT(leftE->fY == nextY && currE->fY == nextY); + blit_saved_trapezoid(leftE, nextY, leftE->fX, currE->fX, + blitter, maskRow, isUsingMask, noRealBlitter, leftClip, rightClip); + } + backward_insert_edge_based_on_x(currE); + } else { + prevX = newX; + } + if (!skipIntersect) { + checkIntersection(currE, nextY, &nextNextY); + } + } + + currE = next; + SkASSERT(currE); + } + + // was our right-edge culled away? + if (in_interval) { + if (useDeferred) { + deferred_blit(leftE, nextTail, left, leftDY, y, nextY, isIntegralNextY, + leftEnds, false, blitter, maskRow, isUsingMask, noRealBlitter, + leftClip, rightClip, yShift); + } else { + blit_trapezoid_row(blitter, y >> 16, + left, rightClip, + SkTMax(leftClip, leftE->fX), rightClip, + leftDY, 0, fullAlpha, maskRow, isUsingMask, + noRealBlitter || + (fullAlpha == 0xFF && edges_too_close(leftE->fPrev, leftE, nextY)), + true); + } + } + + if (forceRLE) { + ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, nextY); + } + + y = nextY; + if (y >= SkIntToFixed(stop_y)) { + break; + } + + // now currE points to the first edge with a fUpperY larger than the previous y + insert_new_edges(currE, y, &nextNextY); + } +} + +static SK_ALWAYS_INLINE void aaa_fill_path(const SkPath& path, const SkIRect& clipRect, + AdditiveBlitter* blitter, int start_y, int stop_y, bool pathContainedInClip, + bool isUsingMask, bool forceRLE) { // forceRLE implies that SkAAClip is calling us + SkASSERT(blitter); + + SkEdgeBuilder builder; + + // If we're convex, then we need both edges, even the right edge is past the clip + const bool canCullToTheRight = !path.isConvex(); + + SkASSERT(gSkUseAnalyticAA.load()); + const SkIRect* builderClip = pathContainedInClip ? nullptr : &clipRect; + int count = builder.build(path, builderClip, 0, canCullToTheRight, true); + SkASSERT(count >= 0); + + SkAnalyticEdge** list = (SkAnalyticEdge**)builder.analyticEdgeList(); + + SkIRect rect = clipRect; + if (0 == count) { + if (path.isInverseFillType()) { + /* + * Since we are in inverse-fill, our caller has already drawn above + * our top (start_y) and will draw below our bottom (stop_y). Thus + * we need to restrict our drawing to the intersection of the clip + * and those two limits. + */ + if (rect.fTop < start_y) { + rect.fTop = start_y; + } + if (rect.fBottom > stop_y) { + rect.fBottom = stop_y; + } + if (!rect.isEmpty()) { + blitter->getRealBlitter()->blitRect(rect.fLeft, rect.fTop, + rect.width(), rect.height()); + } + } + return; + } + + SkAnalyticEdge headEdge, tailEdge, *last; + // this returns the first and last edge after they're sorted into a dlink list + SkAnalyticEdge* edge = sort_edges(list, count, &last); + + headEdge.fRiteE = nullptr; + headEdge.fPrev = nullptr; + headEdge.fNext = edge; + headEdge.fUpperY = headEdge.fLowerY = SK_MinS32; + headEdge.fX = SK_MinS32; + headEdge.fDX = 0; + headEdge.fDY = SK_MaxS32; + headEdge.fUpperX = SK_MinS32; + edge->fPrev = &headEdge; + + tailEdge.fRiteE = nullptr; + tailEdge.fPrev = last; + tailEdge.fNext = nullptr; + tailEdge.fUpperY = tailEdge.fLowerY = SK_MaxS32; + tailEdge.fX = SK_MaxS32; + tailEdge.fDX = 0; + tailEdge.fDY = SK_MaxS32; + tailEdge.fUpperX = SK_MaxS32; + last->fNext = &tailEdge; + + // now edge is the head of the sorted linklist + + if (!pathContainedInClip && start_y < clipRect.fTop) { + start_y = clipRect.fTop; + } + if (!pathContainedInClip && stop_y > clipRect.fBottom) { + stop_y = clipRect.fBottom; + } + + SkFixed leftBound = SkIntToFixed(rect.fLeft); + SkFixed rightBound = SkIntToFixed(rect.fRight); + if (isUsingMask) { + // If we're using mask, then we have to limit the bound within the path bounds. + // Otherwise, the edge drift may access an invalid address inside the mask. + SkIRect ir; + path.getBounds().roundOut(&ir); + leftBound = SkTMax(leftBound, SkIntToFixed(ir.fLeft)); + rightBound = SkTMin(rightBound, SkIntToFixed(ir.fRight)); + } + + if (!path.isInverseFillType() && path.isConvex()) { + SkASSERT(count >= 2); // convex walker does not handle missing right edges + aaa_walk_convex_edges(&headEdge, blitter, start_y, stop_y, + leftBound, rightBound, isUsingMask); + } else { + // Only use deferred blitting if there are many edges. + bool useDeferred = count > + (SkFixedFloorToInt(tailEdge.fPrev->fLowerY - headEdge.fNext->fUpperY) + 1) * 4; + + // We skip intersection computation if there are many points which probably already + // give us enough fractional scan lines. + bool skipIntersect = path.countPoints() > (stop_y - start_y) * 2; + + aaa_walk_edges(&headEdge, &tailEdge, path.getFillType(), blitter, start_y, stop_y, + leftBound, rightBound, isUsingMask, forceRLE, useDeferred, skipIntersect); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static int overflows_short_shift(int value, int shift) { + const int s = 16 + shift; + return (SkLeftShift(value, s) >> s) - value; +} + +/** + Would any of the coordinates of this rectangle not fit in a short, + when left-shifted by shift? +*/ +static int rect_overflows_short_shift(SkIRect rect, int shift) { + SkASSERT(!overflows_short_shift(8191, 2)); + SkASSERT(overflows_short_shift(8192, 2)); + SkASSERT(!overflows_short_shift(32767, 0)); + SkASSERT(overflows_short_shift(32768, 0)); + + // Since we expect these to succeed, we bit-or together + // for a tiny extra bit of speed. + return overflows_short_shift(rect.fLeft, 2) | + overflows_short_shift(rect.fRight, 2) | + overflows_short_shift(rect.fTop, 2) | + overflows_short_shift(rect.fBottom, 2); +} + +static bool fitsInsideLimit(const SkRect& r, SkScalar max) { + const SkScalar min = -max; + return r.fLeft > min && r.fTop > min && + r.fRight < max && r.fBottom < max; +} + +static bool safeRoundOut(const SkRect& src, SkIRect* dst, int32_t maxInt) { + const SkScalar maxScalar = SkIntToScalar(maxInt); + + if (fitsInsideLimit(src, maxScalar)) { + src.roundOut(dst); + return true; + } + return false; +} + +void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter, + bool forceRLE) { + if (origClip.isEmpty()) { + return; + } + + const bool isInverse = path.isInverseFillType(); + SkIRect ir; + if (!safeRoundOut(path.getBounds(), &ir, SK_MaxS32 >> 2)) { + return; + } + if (ir.isEmpty()) { + if (isInverse) { + blitter->blitRegion(origClip); + } + return; + } + + SkIRect clippedIR; + if (isInverse) { + // If the path is an inverse fill, it's going to fill the entire + // clip, and we care whether the entire clip exceeds our limits. + clippedIR = origClip.getBounds(); + } else { + if (!clippedIR.intersect(ir, origClip.getBounds())) { + return; + } + } + // If the intersection of the path bounds and the clip bounds + // will overflow 32767 when << by 2, our SkFixed will overflow, + // so draw without antialiasing. + if (rect_overflows_short_shift(clippedIR, 2)) { + SkScan::FillPath(path, origClip, blitter); + return; + } + + // Our antialiasing can't handle a clip larger than 32767, so we restrict + // the clip to that limit here. (the runs[] uses int16_t for its index). + // + // A more general solution (one that could also eliminate the need to + // disable aa based on ir bounds (see overflows_short_shift) would be + // to tile the clip/target... + SkRegion tmpClipStorage; + const SkRegion* clipRgn = &origClip; + { + static const int32_t kMaxClipCoord = 32767; + const SkIRect& bounds = origClip.getBounds(); + if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) { + SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord }; + tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op); + clipRgn = &tmpClipStorage; + } + } + // for here down, use clipRgn, not origClip + + SkScanClipper clipper(blitter, clipRgn, ir); + const SkIRect* clipRect = clipper.getClipRect(); + + if (clipper.getBlitter() == nullptr) { // clipped out + if (isInverse) { + blitter->blitRegion(*clipRgn); + } + return; + } + + // now use the (possibly wrapped) blitter + blitter = clipper.getBlitter(); + + if (isInverse) { + sk_blit_above(blitter, ir, *clipRgn); + } + + SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop); + + if (MaskAdditiveBlitter::canHandleRect(ir) && !isInverse && !forceRLE) { + MaskAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); + aaa_fill_path(path, clipRgn->getBounds(), &additiveBlitter, ir.fTop, ir.fBottom, + clipRect == nullptr, true, forceRLE); + } else if (!isInverse && path.isConvex()) { + RunBasedAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); + aaa_fill_path(path, clipRgn->getBounds(), &additiveBlitter, ir.fTop, ir.fBottom, + clipRect == nullptr, false, forceRLE); + } else { + SafeRLEAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); + aaa_fill_path(path, clipRgn->getBounds(), &additiveBlitter, ir.fTop, ir.fBottom, + clipRect == nullptr, false, forceRLE); + } + + if (isInverse) { + sk_blit_below(blitter, ir, *clipRgn); + } +} + +// This almost copies SkScan::AntiFillPath +void SkScan::AAAFillPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { + if (clip.isEmpty()) { + return; + } + + if (clip.isBW()) { + AAAFillPath(path, clip.bwRgn(), blitter); + } else { + SkRegion tmp; + SkAAClipBlitter aaBlitter; + + tmp.setRect(clip.getBounds()); + aaBlitter.init(blitter, &clip.aaRgn()); + AAAFillPath(path, tmp, &aaBlitter, true); + } +} diff --git a/gfx/skia/skia/src/core/SkScan_AntiPath.cpp b/gfx/skia/skia/src/core/SkScan_AntiPath.cpp index b41a99c8981f..ac4c8c39f498 100644 --- a/gfx/skia/skia/src/core/SkScan_AntiPath.cpp +++ b/gfx/skia/skia/src/core/SkScan_AntiPath.cpp @@ -104,7 +104,7 @@ class SuperBlitter : public BaseSuperBlitter { public: SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, bool isInverse); - virtual ~SuperBlitter() { + ~SuperBlitter() override { this->flush(); } @@ -394,7 +394,7 @@ void SuperBlitter::blitRect(int x, int y, int width, int height) { class MaskSuperBlitter : public BaseSuperBlitter { public: MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion&, bool isInverse); - virtual ~MaskSuperBlitter() { + ~MaskSuperBlitter() override { fRealBlitter->blitMask(fMask, fClipRect); } @@ -691,6 +691,9 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip, return; } + SkASSERT(clipper.getClipRect() == nullptr || + *clipper.getClipRect() == clipRgn->getBounds()); + // now use the (possibly wrapped) blitter blitter = clipper.getBlitter(); @@ -715,10 +718,12 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip, if (!isInverse && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) { MaskSuperBlitter superBlit(blitter, ir, *clipRgn, isInverse); SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop); - sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn); + sk_fill_path(path, clipRgn->getBounds(), &superBlit, ir.fTop, ir.fBottom, SHIFT, + superClipRect == nullptr); } else { SuperBlitter superBlit(blitter, ir, *clipRgn, isInverse); - sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn); + sk_fill_path(path, clipRgn->getBounds(), &superBlit, ir.fTop, ir.fBottom, SHIFT, + superClipRect == nullptr); } if (isInverse) { @@ -748,8 +753,28 @@ void SkScan::FillPath(const SkPath& path, const SkRasterClip& clip, } } +static bool suitableForAAA(const SkPath& path) { + if (gSkForceAnalyticAA.load()) { + return true; + } + const SkRect& bounds = path.getBounds(); + // When the path have so many points compared to the size of its bounds/resolution, + // it indicates that the path is not quite smooth in the current resolution: + // the expected number of turning points in every pixel row/column is significantly greater than + // zero. Hence Aanlytic AA is not likely to produce visible quality improvements, and Analytic + // AA might be slower than supersampling. + return path.countPoints() < SkTMax(bounds.width(), bounds.height()) / 2 - 10; +} + void SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { + // Do not use AAA if path is too complicated: + // there won't be any speedup or significant visual improvement. + if (gSkUseAnalyticAA.load() && suitableForAAA(path)) { + SkScan::AAAFillPath(path, clip, blitter); + return; + } + if (clip.isEmpty()) { return; } diff --git a/gfx/skia/skia/src/core/SkScan_Antihair.cpp b/gfx/skia/skia/src/core/SkScan_Antihair.cpp index b3770eb64681..474255bd8dd2 100644 --- a/gfx/skia/skia/src/core/SkScan_Antihair.cpp +++ b/gfx/skia/skia/src/core/SkScan_Antihair.cpp @@ -747,8 +747,6 @@ void SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip, AntiFillXRect(xr, nullptr, blitter); } else { SkAAClipBlitterWrapper wrapper(clip, blitter); - blitter = wrapper.getBlitter(); - AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter()); } } diff --git a/gfx/skia/skia/src/core/SkScan_Path.cpp b/gfx/skia/skia/src/core/SkScan_Path.cpp index 5b80492cfa28..0415b2f99a82 100644 --- a/gfx/skia/skia/src/core/SkScan_Path.cpp +++ b/gfx/skia/skia/src/core/SkScan_Path.cpp @@ -36,42 +36,6 @@ #define validate_sort(edge) #endif -static inline void remove_edge(SkEdge* edge) { - edge->fPrev->fNext = edge->fNext; - edge->fNext->fPrev = edge->fPrev; -} - -static inline void insert_edge_after(SkEdge* edge, SkEdge* afterMe) { - edge->fPrev = afterMe; - edge->fNext = afterMe->fNext; - afterMe->fNext->fPrev = edge; - afterMe->fNext = edge; -} - -static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, curr_y)) { - SkFixed x = edge->fX; - - SkEdge* prev = edge->fPrev; - while (prev->fX > x) { - prev = prev->fPrev; - } - if (prev->fNext != edge) { - remove_edge(edge); - insert_edge_after(edge, prev); - } -} - -// Start from the right side, searching backwards for the point to begin the new edge list -// insertion, marching forwards from here. The implementation could have started from the left -// of the prior insertion, and search to the right, or with some additional caching, binary -// search the starting point. More work could be done to determine optimal new edge insertion. -static SkEdge* backward_insert_start(SkEdge* prev, SkFixed x) { - while (prev->fX > x) { - prev = prev->fPrev; - } - return prev; -} - static void insert_new_edges(SkEdge* newEdge, int curr_y) { if (newEdge->fFirstY != curr_y) { return; @@ -191,7 +155,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType, currE->fX = newX; NEXT_X: if (newX < prevX) { // ripple currE backwards until it is x-sorted - backward_insert_edge_based_on_x(currE SkPARAM(curr_y)); + backward_insert_edge_based_on_x(currE); } else { prevX = newX; } @@ -421,21 +385,24 @@ static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) { return list[0]; } -// clipRect may be null, even though we always have a clip. This indicates that -// the path is contained in the clip, and so we can ignore it during the blit -// -// clipRect (if no null) has already been shifted up -// -void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter, - int start_y, int stop_y, int shiftEdgesUp, const SkRegion& clipRgn) { +// clipRect has not been shifted up +void sk_fill_path(const SkPath& path, const SkIRect& clipRect, SkBlitter* blitter, + int start_y, int stop_y, int shiftEdgesUp, bool pathContainedInClip) { SkASSERT(blitter); + SkIRect shiftedClip = clipRect; + shiftedClip.fLeft <<= shiftEdgesUp; + shiftedClip.fRight <<= shiftEdgesUp; + shiftedClip.fTop <<= shiftEdgesUp; + shiftedClip.fBottom <<= shiftEdgesUp; + SkEdgeBuilder builder; // If we're convex, then we need both edges, even the right edge is past the clip const bool canCullToTheRight = !path.isConvex(); - int count = builder.build(path, clipRect, shiftEdgesUp, canCullToTheRight); + SkIRect* builderClip = pathContainedInClip ? nullptr : &shiftedClip; + int count = builder.build(path, builderClip, shiftEdgesUp, canCullToTheRight); SkASSERT(count >= 0); SkEdge** list = builder.edgeList(); @@ -448,7 +415,7 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte * we need to restrict our drawing to the intersection of the clip * and those two limits. */ - SkIRect rect = clipRgn.getBounds(); + SkIRect rect = clipRect; if (rect.fTop < start_y) { rect.fTop = start_y; } @@ -484,18 +451,18 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte start_y = SkLeftShift(start_y, shiftEdgesUp); stop_y = SkLeftShift(stop_y, shiftEdgesUp); - if (clipRect && start_y < clipRect->fTop) { - start_y = clipRect->fTop; + if (!pathContainedInClip && start_y < shiftedClip.fTop) { + start_y = shiftedClip.fTop; } - if (clipRect && stop_y > clipRect->fBottom) { - stop_y = clipRect->fBottom; + if (!pathContainedInClip && stop_y > shiftedClip.fBottom) { + stop_y = shiftedClip.fBottom; } InverseBlitter ib; PrePostProc proc = nullptr; if (path.isInverseFillType()) { - ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp); + ib.setBlitter(blitter, clipRect, shiftEdgesUp); blitter = &ib; proc = PrePostInverseBlitterProc; } @@ -504,14 +471,8 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte SkASSERT(count >= 2); // convex walker does not handle missing right edges walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, nullptr); } else { - int rightEdge; - if (clipRect) { - rightEdge = clipRect->right(); - } else { - rightEdge = SkScalarRoundToInt(path.getBounds().right()) << shiftEdgesUp; - } - - walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc, rightEdge); + walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc, + shiftedClip.right()); } } @@ -561,12 +522,21 @@ SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip, if (clip->isRect()) { if (fClipRect->contains(ir)) { +#ifdef SK_DEBUG + fRectClipCheckBlitter.init(blitter, *fClipRect); + blitter = &fRectClipCheckBlitter; +#endif fClipRect = nullptr; } else { // only need a wrapper blitter if we're horizontally clipped if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) { fRectBlitter.init(blitter, *fClipRect); blitter = &fRectBlitter; + } else { +#ifdef SK_DEBUG + fRectClipCheckBlitter.init(blitter, *fClipRect); + blitter = &fRectClipCheckBlitter; +#endif } } } else { @@ -698,8 +668,10 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, if (path.isInverseFillType()) { sk_blit_above(blitter, ir, *clipPtr); } - sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom, - 0, *clipPtr); + SkASSERT(clipper.getClipRect() == nullptr || + *clipper.getClipRect() == clipPtr->getBounds()); + sk_fill_path(path, clipPtr->getBounds(), blitter, ir.fTop, ir.fBottom, + 0, clipper.getClipRect() == nullptr); if (path.isInverseFillType()) { sk_blit_below(blitter, ir, *clipPtr); } diff --git a/gfx/skia/skia/src/core/SkSemaphore.cpp b/gfx/skia/skia/src/core/SkSemaphore.cpp index 1ebe51b15c1b..f8f6e165ad06 100644 --- a/gfx/skia/skia/src/core/SkSemaphore.cpp +++ b/gfx/skia/skia/src/core/SkSemaphore.cpp @@ -71,3 +71,11 @@ void SkBaseSemaphore::osWait() { void SkBaseSemaphore::cleanup() { delete fOSSemaphore; } + +bool SkBaseSemaphore::try_wait() { + int count = fCount.load(std::memory_order_relaxed); + if (count > 0) { + return fCount.compare_exchange_weak(count, count-1, std::memory_order_acquire); + } + return false; +} diff --git a/gfx/skia/skia/src/core/SkShader.cpp b/gfx/skia/skia/src/core/SkShader.cpp index 56011c57847c..cfdd8b946e6f 100644 --- a/gfx/skia/skia/src/core/SkShader.cpp +++ b/gfx/skia/skia/src/core/SkShader.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkAtomics.h" #include "SkBitmapProcShader.h" #include "SkColorShader.h" @@ -13,9 +14,12 @@ #include "SkPaint.h" #include "SkPicture.h" #include "SkPictureShader.h" +#include "SkPM4fPriv.h" +#include "SkRasterPipeline.h" #include "SkReadBuffer.h" #include "SkScalar.h" #include "SkShader.h" +#include "SkTLazy.h" #include "SkWriteBuffer.h" #if SK_SUPPORT_GPU @@ -66,15 +70,12 @@ void SkShader::flatten(SkWriteBuffer& buffer) const { } bool SkShader::computeTotalInverse(const ContextRec& rec, SkMatrix* totalInverse) const { - SkMatrix total; - total.setConcat(*rec.fMatrix, fLocalMatrix); - - const SkMatrix* m = &total; + SkMatrix total = SkMatrix::Concat(*rec.fMatrix, fLocalMatrix); if (rec.fLocalMatrix) { - total.setConcat(*m, *rec.fLocalMatrix); - m = &total; + total.preConcat(*rec.fLocalMatrix); } - return m->invert(totalInverse); + + return total.invert(totalInverse); } bool SkShader::asLuminanceColor(SkColor* colorPtr) const { @@ -89,23 +90,11 @@ bool SkShader::asLuminanceColor(SkColor* colorPtr) const { return false; } -SkShader::Context* SkShader::createContext(const ContextRec& rec, void* storage) const { +SkShader::Context* SkShader::makeContext(const ContextRec& rec, SkArenaAlloc* alloc) const { if (!this->computeTotalInverse(rec, nullptr)) { return nullptr; } - return this->onCreateContext(rec, storage); -} - -SkShader::Context* SkShader::onCreateContext(const ContextRec& rec, void*) const { - return nullptr; -} - -size_t SkShader::contextSize(const ContextRec& rec) const { - return this->onContextSize(rec); -} - -size_t SkShader::onContextSize(const ContextRec&) const { - return 0; + return this->onMakeContext(rec, alloc); } SkShader::Context::Context(const SkShader& shader, const ContextRec& rec) @@ -230,7 +219,7 @@ sk_sp SkShader::asFragmentProcessor(const AsFPArgs&) const } #endif -SkShader* SkShader::refAsALocalMatrixShader(SkMatrix*) const { +sk_sp SkShader::makeAsALocalMatrixShader(SkMatrix*) const { return nullptr; } @@ -240,11 +229,17 @@ sk_sp SkShader::MakeColorShader(SkColor color) { return sk_make_sp SkShader::MakeBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, const SkMatrix* localMatrix) { - return SkMakeBitmapShader(src, tmx, tmy, localMatrix, kIfMutable_SkCopyPixelsMode, nullptr); + if (localMatrix && !localMatrix->invert(nullptr)) { + return nullptr; + } + return SkMakeBitmapShader(src, tmx, tmy, localMatrix, kIfMutable_SkCopyPixelsMode); } sk_sp SkShader::MakePictureShader(sk_sp src, TileMode tmx, TileMode tmy, const SkMatrix* localMatrix, const SkRect* tile) { + if (localMatrix && !localMatrix->invert(nullptr)) { + return nullptr; + } return SkPictureShader::Make(std::move(src), tmx, tmy, localMatrix, tile); } @@ -257,6 +252,39 @@ void SkShader::toString(SkString* str) const { } #endif +bool SkShader::appendStages(SkRasterPipeline* pipeline, + SkColorSpace* dst, + SkArenaAlloc* scratch, + const SkMatrix& ctm, + const SkPaint& paint) const { + return this->onAppendStages(pipeline, dst, scratch, ctm, paint, nullptr); +} + +bool SkShader::onAppendStages(SkRasterPipeline* p, + SkColorSpace* cs, + SkArenaAlloc* alloc, + const SkMatrix& ctm, + const SkPaint& paint, + const SkMatrix* localM) const { + // Legacy shaders handle the paint opacity internally, + // but RP applies it as a separate stage. + SkTCopyOnFirstWrite opaquePaint(paint); + if (paint.getAlpha() != SK_AlphaOPAQUE) { + opaquePaint.writable()->setAlpha(SK_AlphaOPAQUE); + } + + ContextRec rec(*opaquePaint, ctm, localM, ContextRec::kPM4f_DstType, cs); + if (auto* ctx = this->makeContext(rec, alloc)) { + p->append(SkRasterPipeline::shader_adapter, ctx); + + // Legacy shaders aren't aware of color spaces. We can pretty + // safely assume they're in sRGB gamut. + return append_gamut_transform(p, alloc, + SkColorSpace::MakeSRGB().get(), cs); + } + return false; +} + /////////////////////////////////////////////////////////////////////////////////////////////////// sk_sp SkEmptyShader::CreateProc(SkReadBuffer&) { @@ -274,30 +302,3 @@ void SkEmptyShader::toString(SkString* str) const { str->append(")"); } #endif - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef SK_SUPPORT_LEGACY_CREATESHADER_PTR -SkShader* SkShader::CreateComposeShader(SkShader* dst, SkShader* src, SkXfermode::Mode mode) { - return MakeComposeShader(sk_ref_sp(dst), sk_ref_sp(src), mode).release(); -} -SkShader* SkShader::CreateComposeShader(SkShader* dst, SkShader* src, SkXfermode* xfer) { - return MakeComposeShader(sk_ref_sp(dst), sk_ref_sp(src), xfer).release(); -} -SkShader* SkShader::CreatePictureShader(const SkPicture* src, TileMode tmx, TileMode tmy, - const SkMatrix* localMatrix, const SkRect* tile) { - return MakePictureShader(sk_ref_sp(const_cast(src)), tmx, tmy, - localMatrix, tile).release(); -} -SkShader* SkShader::newWithColorFilter(SkColorFilter* filter) const { - return this->makeWithColorFilter(sk_ref_sp(filter)).release(); -} -#endif - -#ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR -#include "SkXfermode.h" -sk_sp SkShader::MakeComposeShader(sk_sp dst, sk_sp src, - SkXfermode* xfer) { - return MakeComposeShader(std::move(dst), std::move(src), sk_ref_sp(xfer)); -} -#endif diff --git a/gfx/skia/skia/src/core/SkShadowShader.cpp b/gfx/skia/skia/src/core/SkShadowShader.cpp index c3ede8081ed3..9353ca60cf7e 100644 --- a/gfx/skia/skia/src/core/SkShadowShader.cpp +++ b/gfx/skia/skia/src/core/SkShadowShader.cpp @@ -101,7 +101,6 @@ private: #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "SkGr.h" -#include "SkGrPriv.h" #include "SkSpecialImage.h" #include "SkImage_Base.h" #include "GrContext.h" @@ -138,10 +137,11 @@ public: // gets deleted when the ShadowFP is destroyed, and frees the GrTexture* fTexture[fNumNonAmbLights] = sk_sp(shadowMap->asTextureRef(context, - GrTextureParams::ClampNoFilter(), - SkSourceGammaTreatment::kIgnore)); - fDepthMapAccess[fNumNonAmbLights].reset(fTexture[fNumNonAmbLights].get()); - this->addTextureAccess(&fDepthMapAccess[fNumNonAmbLights]); + GrSamplerParams::ClampNoFilter(), + SkDestinationSurfaceColorMode::kLegacy, + nullptr)); + fDepthMapSampler[fNumNonAmbLights].reset(fTexture[fNumNonAmbLights].get()); + this->addTextureSampler(&fDepthMapSampler[fNumNonAmbLights]); fDepthMapHeight[fNumNonAmbLights] = shadowMap->height(); fDepthMapWidth[fNumNonAmbLights] = shadowMap->width(); @@ -447,7 +447,7 @@ public: } - static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, + static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const ShadowFP& shadowFP = proc.cast(); b->add32(shadowFP.fNumNonAmbLights); @@ -461,7 +461,8 @@ public: } protected: - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) override { const ShadowFP &shadowFP = proc.cast(); for (int i = 0; i < shadowFP.numLights(); i++) { @@ -551,15 +552,12 @@ public: GrGLSLProgramDataManager::UniformHandle fAmbientColorUni; }; - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLShadowFP::GenKey(*this, caps, b); } const char* name() const override { return "shadowFP"; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->mulByUnknownFourComponents(); - } int32_t numLights() const { return fNumNonAmbLights; } const SkColor3f& ambientColor() const { return fAmbientColor; } bool isPointLight(int i) const { @@ -628,7 +626,7 @@ private: bool fIsRadialLight[SkShadowShader::kMaxNonAmbientLights]; SkVector3 fLightDirOrPos[SkShadowShader::kMaxNonAmbientLights]; SkColor3f fLightColor[SkShadowShader::kMaxNonAmbientLights]; - GrTextureAccess fDepthMapAccess[SkShadowShader::kMaxNonAmbientLights]; + TextureSampler fDepthMapSampler[SkShadowShader::kMaxNonAmbientLights]; sk_sp fTexture[SkShadowShader::kMaxNonAmbientLights]; int fDepthMapWidth[SkShadowShader::kMaxNonAmbientLights]; diff --git a/gfx/skia/skia/src/core/SkSmallAllocator.h b/gfx/skia/skia/src/core/SkSmallAllocator.h deleted file mode 100644 index 9095fa57fc11..000000000000 --- a/gfx/skia/skia/src/core/SkSmallAllocator.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2014 Google, Inc - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSmallAllocator_DEFINED -#define SkSmallAllocator_DEFINED - -#include "SkTDArray.h" -#include "SkTypes.h" - -#include - -/* - * Template class for allocating small objects without additional heap memory - * allocations. kMaxObjects is a hard limit on the number of objects that can - * be allocated using this class. After that, attempts to create more objects - * with this class will assert and return nullptr. - * - * kTotalBytes is the total number of bytes provided for storage for all - * objects created by this allocator. If an object to be created is larger - * than the storage (minus storage already used), it will be allocated on the - * heap. This class's destructor will handle calling the destructor for each - * object it allocated and freeing its memory. - * - * Current the class always aligns each allocation to 16-bytes to be safe, but future - * may reduce this to only the alignment that is required per alloc. - */ -template -class SkSmallAllocator : SkNoncopyable { -public: - SkSmallAllocator() - : fStorageUsed(0) - , fNumObjects(0) - {} - - ~SkSmallAllocator() { - // Destruct in reverse order, in case an earlier object points to a - // later object. - while (fNumObjects > 0) { - fNumObjects--; - Rec* rec = &fRecs[fNumObjects]; - rec->fKillProc(rec->fObj); - // Safe to do if fObj is in fStorage, since fHeapStorage will - // point to nullptr. - sk_free(rec->fHeapStorage); - } - } - - /* - * Create a new object of type T. Its lifetime will be handled by this - * SkSmallAllocator. - * Note: If kMaxObjects have been created by this SkSmallAllocator, nullptr - * will be returned. - */ - template - T* createT(const Args&... args) { - void* buf = this->reserveT(); - if (nullptr == buf) { - return nullptr; - } - return new (buf) T(args...); - } - - /* - * Reserve a specified amount of space (must be enough space for one T). - * The space will be in fStorage if there is room, or on the heap otherwise. - * Either way, this class will call ~T() in its destructor and free the heap - * allocation if necessary. - * Unlike createT(), this method will not call the constructor of T. - */ - template void* reserveT(size_t storageRequired = sizeof(T)) { - SkASSERT(fNumObjects < kMaxObjects); - SkASSERT(storageRequired >= sizeof(T)); - if (kMaxObjects == fNumObjects) { - return nullptr; - } - const size_t storageRemaining = sizeof(fStorage) - fStorageUsed; - Rec* rec = &fRecs[fNumObjects]; - if (storageRequired > storageRemaining) { - // Allocate on the heap. Ideally we want to avoid this situation. - - // With the gm composeshader_bitmap2, storage required is 4476 - // and storage remaining is 3392. Increasing the base storage - // causes google 3 tests to fail. - - rec->fStorageSize = 0; - rec->fHeapStorage = sk_malloc_throw(storageRequired); - rec->fObj = static_cast(rec->fHeapStorage); - } else { - // There is space in fStorage. - rec->fStorageSize = storageRequired; - rec->fHeapStorage = nullptr; - rec->fObj = static_cast(fStorage.fBytes + fStorageUsed); - fStorageUsed += storageRequired; - } - rec->fKillProc = DestroyT; - fNumObjects++; - return rec->fObj; - } - - /* - * Free the memory reserved last without calling the destructor. - * Can be used in a nested way, i.e. after reserving A and B, calling - * freeLast once will free B and calling it again will free A. - */ - void freeLast() { - SkASSERT(fNumObjects > 0); - Rec* rec = &fRecs[fNumObjects - 1]; - sk_free(rec->fHeapStorage); - fStorageUsed -= rec->fStorageSize; - - fNumObjects--; - } - -private: - struct Rec { - size_t fStorageSize; // 0 if allocated on heap - void* fObj; - void* fHeapStorage; - void (*fKillProc)(void*); - }; - - // Used to call the destructor for allocated objects. - template - static void DestroyT(void* ptr) { - static_cast(ptr)->~T(); - } - - struct SK_STRUCT_ALIGN(16) Storage { - // we add kMaxObjects * 15 to account for the worst-case slop, where each allocation wasted - // 15 bytes (due to forcing each to be 16-byte aligned) - char fBytes[kTotalBytes + kMaxObjects * 15]; - }; - - Storage fStorage; - // Number of bytes used so far. - size_t fStorageUsed; - uint32_t fNumObjects; - Rec fRecs[kMaxObjects]; -}; - -#endif // SkSmallAllocator_DEFINED diff --git a/gfx/skia/skia/src/core/SkSpecialImage.cpp b/gfx/skia/skia/src/core/SkSpecialImage.cpp index 5d62c6bc6232..0853432d79d4 100644 --- a/gfx/skia/skia/src/core/SkSpecialImage.cpp +++ b/gfx/skia/skia/src/core/SkSpecialImage.cpp @@ -17,10 +17,15 @@ #if SK_SUPPORT_GPU #include "GrContext.h" +#include "GrContextPriv.h" +#include "GrResourceProvider.h" +#include "GrSurfaceContext.h" +#include "GrSurfaceProxyPriv.h" #include "GrTexture.h" -#include "GrTextureParams.h" +#include "GrSamplerParams.h" +#include "GrTextureProxy.h" #include "SkGr.h" -#include "SkGrPriv.h" +#include "SkImage_Gpu.h" #endif // Currently the raster imagefilters can only handle certain imageinfos. Call this to know if @@ -42,12 +47,12 @@ public: virtual bool onGetROPixels(SkBitmap*) const = 0; - virtual GrTexture* onPeekTexture() const { return nullptr; } + virtual GrContext* onGetContext() const { return nullptr; } virtual SkColorSpace* onGetColorSpace() const = 0; #if SK_SUPPORT_GPU - virtual sk_sp onAsTextureRef(GrContext* context) const = 0; + virtual sk_sp onAsTextureProxyRef(GrContext* context) const = 0; #endif virtual sk_sp onMakeSubset(const SkIRect& subset) const = 0; @@ -55,7 +60,7 @@ public: virtual sk_sp onMakeSurface(const SkImageFilter::OutputProperties& outProps, const SkISize& size, SkAlphaType at) const = 0; - virtual sk_sp onMakeTightSubset(const SkIRect& subset) const = 0; + virtual sk_sp onAsImage(const SkIRect* subset) const = 0; virtual sk_sp onMakeTightSurface(const SkImageFilter::OutputProperties& outProps, const SkISize& size, SkAlphaType at) const = 0; @@ -82,8 +87,8 @@ sk_sp SkSpecialImage::makeTextureImage(GrContext* context) { if (!context) { return nullptr; } - if (GrTexture* peek = as_SIB(this)->onPeekTexture()) { - return peek->getContext() == context ? sk_sp(SkRef(this)) : nullptr; + if (GrContext* curContext = as_SIB(this)->onGetContext()) { + return curContext == context ? sk_sp(SkRef(this)) : nullptr; } SkBitmap bmp; @@ -99,18 +104,24 @@ sk_sp SkSpecialImage::makeTextureImage(GrContext* context) { return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props()); } - sk_sp resultTex(GrRefCachedBitmapTexture(context, - bmp, - GrTextureParams::ClampNoFilter(), - SkSourceGammaTreatment::kRespect)); - if (!resultTex) { + // TODO: this is a tight copy of 'bmp' but it doesn't have to be (given SkSpecialImage's + // semantics). Since this is cached though we would have to bake the fit into the cache key. + sk_sp proxy = GrMakeCachedBitmapProxy(context->resourceProvider(), bmp); + if (!proxy) { return nullptr; } - return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(resultTex->width(), resultTex->height()), - this->uniqueID(), - resultTex, sk_ref_sp(this->getColorSpace()), &this->props(), - this->alphaType()); + const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height()); + + // GrMakeCachedBitmapProxy has uploaded only the specified subset of 'bmp' so we need not + // bother with SkBitmap::getSubset + return SkSpecialImage::MakeDeferredFromGpu(context, + rect, + this->uniqueID(), + std::move(proxy), + sk_ref_sp(this->getColorSpace()), + &this->props(), + this->alphaType()); #else return nullptr; #endif @@ -125,22 +136,11 @@ bool SkSpecialImage::getROPixels(SkBitmap* bm) const { } bool SkSpecialImage::isTextureBacked() const { -#if SK_SUPPORT_GPU - return as_SIB(this)->onPeekTexture() && as_SIB(this)->onPeekTexture()->getContext(); -#else - return false; -#endif + return SkToBool(as_SIB(this)->onGetContext()); } GrContext* SkSpecialImage::getContext() const { -#if SK_SUPPORT_GPU - GrTexture* texture = as_SIB(this)->onPeekTexture(); - - if (texture) { - return texture->getContext(); - } -#endif - return nullptr; + return as_SIB(this)->onGetContext(); } SkColorSpace* SkSpecialImage::getColorSpace() const { @@ -148,8 +148,8 @@ SkColorSpace* SkSpecialImage::getColorSpace() const { } #if SK_SUPPORT_GPU -sk_sp SkSpecialImage::asTextureRef(GrContext* context) const { - return as_SIB(this)->onAsTextureRef(context); +sk_sp SkSpecialImage::asTextureProxyRef(GrContext* context) const { + return as_SIB(this)->onAsTextureProxyRef(context); } #endif @@ -167,10 +167,11 @@ sk_sp SkSpecialImage::makeSubset(const SkIRect& subset) const { return as_SIB(this)->onMakeSubset(subset); } -sk_sp SkSpecialImage::makeTightSubset(const SkIRect& subset) const { - return as_SIB(this)->onMakeTightSubset(subset); +sk_sp SkSpecialImage::asImage(const SkIRect* subset) const { + return as_SIB(this)->onAsImage(subset); } + #ifdef SK_DEBUG static bool rect_fits(const SkIRect& rect, int width, int height) { if (0 == width && 0 == height) { @@ -187,18 +188,21 @@ static bool rect_fits(const SkIRect& rect, int width, int height) { sk_sp SkSpecialImage::MakeFromImage(const SkIRect& subset, sk_sp image, + SkColorSpace* dstColorSpace, const SkSurfaceProps* props) { SkASSERT(rect_fits(subset, image->width(), image->height())); #if SK_SUPPORT_GPU - if (GrTexture* texture = as_IB(image)->peekTexture()) { - return MakeFromGpu(subset, image->uniqueID(), sk_ref_sp(texture), - sk_ref_sp(as_IB(image)->onImageInfo().colorSpace()), props); + if (sk_sp proxy = as_IB(image)->asTextureProxyRef()) { + GrContext* context = ((SkImage_Gpu*) as_IB(image))->context(); + + return MakeDeferredFromGpu(context, subset, image->uniqueID(), std::move(proxy), + as_IB(image)->onImageInfo().refColorSpace(), props); } else #endif { SkBitmap bm; - if (as_IB(image)->getROPixels(&bm)) { + if (as_IB(image)->getROPixels(&bm, dstColorSpace)) { return MakeFromRaster(subset, bm, props); } } @@ -244,12 +248,9 @@ public: } #if SK_SUPPORT_GPU - sk_sp onAsTextureRef(GrContext* context) const override { + sk_sp onAsTextureProxyRef(GrContext* context) const override { if (context) { - return sk_ref_sp(GrRefCachedBitmapTexture(context, - fBitmap, - GrTextureParams::ClampNoFilter(), - SkSourceGammaTreatment::kRespect)); + return GrMakeCachedBitmapProxy(context->resourceProvider(), fBitmap); } return nullptr; @@ -287,14 +288,18 @@ public: &this->props()); } - sk_sp onMakeTightSubset(const SkIRect& subset) const override { - SkBitmap subsetBM; + sk_sp onAsImage(const SkIRect* subset) const override { + if (subset) { + SkBitmap subsetBM; - if (!fBitmap.extractSubset(&subsetBM, subset)) { - return nullptr; + if (!fBitmap.extractSubset(&subsetBM, *subset)) { + return nullptr; + } + + return SkImage::MakeFromBitmap(subsetBM); } - return SkImage::MakeFromBitmap(subsetBM); + return SkImage::MakeFromBitmap(fBitmap); } sk_sp onMakeTightSurface(const SkImageFilter::OutputProperties& outProps, @@ -341,15 +346,21 @@ sk_sp SkSpecialImage::MakeFromRaster(const SkIRect& subset, #if SK_SUPPORT_GPU /////////////////////////////////////////////////////////////////////////////// #include "GrTexture.h" -#include "SkImage_Gpu.h" + +static sk_sp wrap_proxy_in_image(GrContext* context, sk_sp proxy, + SkAlphaType alphaType, sk_sp colorSpace) { + return sk_make_sp(context, kNeedNewImageUniqueID, alphaType, + std::move(proxy), std::move(colorSpace), SkBudgeted::kYes); +} class SkSpecialImage_Gpu : public SkSpecialImage_Base { public: - SkSpecialImage_Gpu(const SkIRect& subset, - uint32_t uniqueID, sk_sp tex, SkAlphaType at, + SkSpecialImage_Gpu(GrContext* context, const SkIRect& subset, + uint32_t uniqueID, sk_sp proxy, SkAlphaType at, sk_sp colorSpace, const SkSurfaceProps* props) : INHERITED(subset, uniqueID, props) - , fTexture(std::move(tex)) + , fContext(context) + , fTextureProxy(std::move(proxy)) , fAlphaType(at) , fColorSpace(std::move(colorSpace)) , fAddedRasterVersionToCache(false) { @@ -363,46 +374,61 @@ public: SkAlphaType alphaType() const override { return fAlphaType; } - size_t getSize() const override { return fTexture->gpuMemorySize(); } + size_t getSize() const override { return fTextureProxy->gpuMemorySize(); } void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override { SkRect dst = SkRect::MakeXYWH(x, y, this->subset().width(), this->subset().height()); - auto img = sk_sp(new SkImage_Gpu(fTexture->width(), fTexture->height(), - this->uniqueID(), fAlphaType, fTexture.get(), - fColorSpace, SkBudgeted::kNo)); + // TODO: In this instance we know we're going to draw a sub-portion of the backing + // texture into the canvas so it is okay to wrap it in an SkImage. This poses + // some problems for full deferral however in that when the deferred SkImage_Gpu + // instantiates itself it is going to have to either be okay with having a larger + // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs + // to be tightened (if it is deferred). + sk_sp img = sk_sp(new SkImage_Gpu(canvas->getGrContext(), + this->uniqueID(), fAlphaType, + fTextureProxy, + fColorSpace, SkBudgeted::kNo)); canvas->drawImageRect(img, this->subset(), - dst, paint, SkCanvas::kStrict_SrcRectConstraint); + dst, paint, SkCanvas::kStrict_SrcRectConstraint); } - GrTexture* onPeekTexture() const override { return fTexture.get(); } + GrContext* onGetContext() const override { return fContext; } - sk_sp onAsTextureRef(GrContext*) const override { return fTexture; } + sk_sp onAsTextureProxyRef(GrContext*) const override { + return fTextureProxy; + } bool onGetROPixels(SkBitmap* dst) const override { - if (SkBitmapCache::Find(this->uniqueID(), dst)) { + const auto desc = SkBitmapCacheDesc::Make(this->uniqueID(), this->width(), this->height()); + if (SkBitmapCache::Find(desc, dst)) { SkASSERT(dst->getGenerationID() == this->uniqueID()); SkASSERT(dst->isImmutable()); SkASSERT(dst->getPixels()); return true; } + SkPixmap pmap; SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(), this->alphaType(), fColorSpace); - - if (!dst->tryAllocPixels(info)) { + auto rec = SkBitmapCache::Alloc(desc, info, &pmap); + if (!rec) { return false; } - if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig, - dst->getPixels(), dst->rowBytes())) { + sk_sp sContext = fContext->contextPriv().makeWrappedSurfaceContext( + fTextureProxy, nullptr); + if (!sContext) { return false; } - dst->pixelRef()->setImmutableWithID(this->uniqueID()); - SkBitmapCache::Add(this->uniqueID(), *dst); + if (!sContext->readPixels(info, pmap.writable_addr(), pmap.rowBytes(), 0, 0)) { + return false; + } + + SkBitmapCache::Add(std::move(rec), dst); fAddedRasterVersionToCache.store(true); return true; } @@ -413,48 +439,54 @@ public: sk_sp onMakeSurface(const SkImageFilter::OutputProperties& outProps, const SkISize& size, SkAlphaType at) const override { - if (!fTexture->getContext()) { + if (!fContext) { return nullptr; } SkColorSpace* colorSpace = outProps.colorSpace(); return SkSpecialSurface::MakeRenderTarget( - fTexture->getContext(), size.width(), size.height(), + fContext, size.width(), size.height(), GrRenderableConfigForColorSpace(colorSpace), sk_ref_sp(colorSpace)); } sk_sp onMakeSubset(const SkIRect& subset) const override { - return SkSpecialImage::MakeFromGpu(subset, - this->uniqueID(), - fTexture, - fColorSpace, - &this->props(), - fAlphaType); + return SkSpecialImage::MakeDeferredFromGpu(fContext, + subset, + this->uniqueID(), + fTextureProxy, + fColorSpace, + &this->props(), + fAlphaType); } - sk_sp onMakeTightSubset(const SkIRect& subset) const override { - if (0 == subset.fLeft && 0 == subset.fTop && - fTexture->width() == subset.width() && - fTexture->height() == subset.height()) { - // The existing GrTexture is already tight so reuse it in the SkImage - return sk_make_sp(fTexture->width(), fTexture->height(), - kNeedNewImageUniqueID, - fAlphaType, fTexture.get(), fColorSpace, - SkBudgeted::kYes); + // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy? + sk_sp onAsImage(const SkIRect* subset) const override { + if (subset) { + // TODO: if this becomes a bottle neck we could base this logic on what the size + // will be when it is finally instantiated - but that is more fraught. + if (GrResourceProvider::IsFunctionallyExact(fTextureProxy.get()) && + 0 == subset->fLeft && 0 == subset->fTop && + fTextureProxy->width() == subset->width() && + fTextureProxy->height() == subset->height()) { + // The existing GrTexture is already tight so reuse it in the SkImage + return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace); + } + + sk_sp subsetProxy(GrSurfaceProxy::Copy(fContext, fTextureProxy.get(), + *subset, SkBudgeted::kYes)); + if (!subsetProxy) { + return nullptr; + } + + SkASSERT(subsetProxy->priv().isExact()); + // MDB: this is acceptable (wrapping subsetProxy in an SkImage) bc Copy will + // return a kExact-backed proxy + return wrap_proxy_in_image(fContext, std::move(subsetProxy), fAlphaType, fColorSpace); } - GrContext* ctx = fTexture->getContext(); - GrSurfaceDesc desc = fTexture->desc(); - desc.fWidth = subset.width(); - desc.fHeight = subset.height(); + fTextureProxy->priv().exactify(); - sk_sp subTx(ctx->textureProvider()->createTexture(desc, SkBudgeted::kYes)); - if (!subTx) { - return nullptr; - } - ctx->copySurface(subTx.get(), fTexture.get(), subset, SkIPoint::Make(0, 0)); - return sk_make_sp(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID, - fAlphaType, subTx.get(), fColorSpace, SkBudgeted::kYes); + return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace); } sk_sp onMakeTightSurface(const SkImageFilter::OutputProperties& outProps, @@ -464,11 +496,12 @@ public: ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType; SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at, sk_ref_sp(colorSpace)); - return SkSurface::MakeRenderTarget(fTexture->getContext(), SkBudgeted::kYes, info); + return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info); } private: - sk_sp fTexture; + GrContext* fContext; + sk_sp fTextureProxy; const SkAlphaType fAlphaType; sk_sp fColorSpace; mutable SkAtomic fAddedRasterVersionToCache; @@ -476,15 +509,15 @@ private: typedef SkSpecialImage_Base INHERITED; }; -sk_sp SkSpecialImage::MakeFromGpu(const SkIRect& subset, - uint32_t uniqueID, - sk_sp tex, - sk_sp colorSpace, - const SkSurfaceProps* props, - SkAlphaType at) { - SkASSERT(rect_fits(subset, tex->width(), tex->height())); - return sk_make_sp(subset, uniqueID, std::move(tex), at, +sk_sp SkSpecialImage::MakeDeferredFromGpu(GrContext* context, + const SkIRect& subset, + uint32_t uniqueID, + sk_sp proxy, + sk_sp colorSpace, + const SkSurfaceProps* props, + SkAlphaType at) { + SkASSERT(rect_fits(subset, proxy->width(), proxy->height())); + return sk_make_sp(context, subset, uniqueID, std::move(proxy), at, std::move(colorSpace), props); } - #endif diff --git a/gfx/skia/skia/src/core/SkSpecialImage.h b/gfx/skia/skia/src/core/SkSpecialImage.h index c1f3791edf37..33de36ca2349 100644 --- a/gfx/skia/skia/src/core/SkSpecialImage.h +++ b/gfx/skia/skia/src/core/SkSpecialImage.h @@ -16,7 +16,9 @@ #include "SkImageInfo.h" // for SkAlphaType class GrContext; +class GrSurfaceProxy; class GrTexture; +class GrTextureProxy; class SkBitmap; class SkCanvas; class SkImage; @@ -34,7 +36,7 @@ enum { * This is a restricted form of SkImage solely intended for internal use. It * differs from SkImage in that: * - it can only be backed by raster or gpu (no generators) - * - it can be backed by a GrTexture larger than its nominal bounds + * - it can be backed by a GrTextureProxy larger than its nominal bounds * - it can't be drawn tiled * - it can't be drawn with MIPMAPs * It is similar to SkImage in that it abstracts how the pixels are stored/represented. @@ -71,17 +73,19 @@ public: static sk_sp MakeFromImage(const SkIRect& subset, sk_sp, + SkColorSpace* dstColorSpace, const SkSurfaceProps* = nullptr); static sk_sp MakeFromRaster(const SkIRect& subset, const SkBitmap&, const SkSurfaceProps* = nullptr); #if SK_SUPPORT_GPU - static sk_sp MakeFromGpu(const SkIRect& subset, - uint32_t uniqueID, - sk_sp, - sk_sp, - const SkSurfaceProps* = nullptr, - SkAlphaType at = kPremul_SkAlphaType); + static sk_sp MakeDeferredFromGpu(GrContext*, + const SkIRect& subset, + uint32_t uniqueID, + sk_sp, + sk_sp, + const SkSurfaceProps* = nullptr, + SkAlphaType at = kPremul_SkAlphaType); #endif /** @@ -106,11 +110,14 @@ public: sk_sp makeSubset(const SkIRect& subset) const; /** - * Extract a subset of this special image and return it as an SkImage. + * Create an SkImage from the contents of this special image optionally extracting a subset. * It may or may not point to the same backing memory. - * TODO: switch this to makeSurface once we resolved the naming issue + * Note: when no 'subset' parameter is specified the the entire SkSpecialImage will be + * returned - including whatever extra padding may have resulted from a loose fit! + * When the 'subset' parameter is specified the returned image will be tight even if that + * entails a copy! */ - sk_sp makeTightSubset(const SkIRect& subset) const; + sk_sp asImage(const SkIRect* subset = nullptr) const; // TODO: hide this when GrLayerHoister uses SkSpecialImages more fully (see skbug.com/5063) /** @@ -125,10 +132,10 @@ public: #if SK_SUPPORT_GPU /** - * Regardless of the underlying backing store, return the contents as a GrTexture. + * Regardless of the underlying backing store, return the contents as a GrTextureProxy. * The active portion of the texture can be retrieved via 'subset'. */ - sk_sp asTextureRef(GrContext*) const; + sk_sp asTextureProxyRef(GrContext*) const; #endif // TODO: hide this whe the imagefilter all have a consistent draw path (see skbug.com/5063) diff --git a/gfx/skia/skia/src/core/SkSpecialSurface.cpp b/gfx/skia/skia/src/core/SkSpecialSurface.cpp index 85bb61a3e3fe..40afb57cec64 100644 --- a/gfx/skia/skia/src/core/SkSpecialSurface.cpp +++ b/gfx/skia/skia/src/core/SkSpecialSurface.cpp @@ -24,12 +24,12 @@ public: void reset() { fCanvas.reset(); } // This can return nullptr if reset has already been called or something when wrong in the ctor - SkCanvas* onGetCanvas() { return fCanvas; } + SkCanvas* onGetCanvas() { return fCanvas.get(); } virtual sk_sp onMakeImageSnapshot() = 0; protected: - SkAutoTUnref fCanvas; // initialized by derived classes in ctors + std::unique_ptr fCanvas; // initialized by derived classes in ctors private: typedef SkSpecialSurface INHERITED; @@ -63,14 +63,14 @@ sk_sp SkSpecialSurface::makeImageSnapshot() { class SkSpecialSurface_Raster : public SkSpecialSurface_Base { public: - SkSpecialSurface_Raster(SkPixelRef* pr, + SkSpecialSurface_Raster(sk_sp pr, const SkIRect& subset, const SkSurfaceProps* props) : INHERITED(subset, props) { const SkImageInfo& info = pr->info(); fBitmap.setInfo(info, info.minRowBytes()); - fBitmap.setPixelRef(pr); + fBitmap.setPixelRef(std::move(pr), 0, 0); fCanvas.reset(new SkCanvas(fBitmap, this->props())); fCanvas->clipRect(SkRect::Make(subset)); @@ -93,19 +93,19 @@ private: sk_sp SkSpecialSurface::MakeFromBitmap(const SkIRect& subset, SkBitmap& bm, const SkSurfaceProps* props) { - return sk_make_sp(bm.pixelRef(), subset, props); + return sk_make_sp(sk_ref_sp(bm.pixelRef()), subset, props); } sk_sp SkSpecialSurface::MakeRaster(const SkImageInfo& info, const SkSurfaceProps* props) { - SkAutoTUnref pr(SkMallocPixelRef::NewZeroed(info, 0, nullptr)); - if (nullptr == pr.get()) { + sk_sp pr = SkMallocPixelRef::MakeZeroed(info, 0, nullptr); + if (!pr) { return nullptr; } const SkIRect subset = SkIRect::MakeWH(pr->info().width(), pr->info().height()); - return sk_make_sp(pr, subset, props); + return sk_make_sp(std::move(pr), subset, props); } #if SK_SUPPORT_GPU @@ -115,13 +115,12 @@ sk_sp SkSpecialSurface::MakeRaster(const SkImageInfo& info, class SkSpecialSurface_Gpu : public SkSpecialSurface_Base { public: - SkSpecialSurface_Gpu(sk_sp drawContext, - int width, int height, - const SkIRect& subset) - : INHERITED(subset, &drawContext->surfaceProps()) - , fDrawContext(std::move(drawContext)) { + SkSpecialSurface_Gpu(GrContext* context, sk_sp renderTargetContext, + int width, int height, const SkIRect& subset) + : INHERITED(subset, &renderTargetContext->surfaceProps()) + , fRenderTargetContext(std::move(renderTargetContext)) { - sk_sp device(SkGpuDevice::Make(fDrawContext, width, height, + sk_sp device(SkGpuDevice::Make(context, fRenderTargetContext, width, height, SkGpuDevice::kUninit_InitContents)); if (!device) { return; @@ -137,18 +136,22 @@ public: ~SkSpecialSurface_Gpu() override { } sk_sp onMakeImageSnapshot() override { - sk_sp tmp(SkSpecialImage::MakeFromGpu( - this->subset(), - kNeedNewImageUniqueID_SpecialImage, - fDrawContext->asTexture(), - sk_ref_sp(fDrawContext->getColorSpace()), - &this->props())); - fDrawContext = nullptr; + if (!fRenderTargetContext->asTextureProxy()) { + return nullptr; + } + sk_sp tmp(SkSpecialImage::MakeDeferredFromGpu( + fCanvas->getGrContext(), + this->subset(), + kNeedNewImageUniqueID_SpecialImage, + fRenderTargetContext->asTextureProxyRef(), + fRenderTargetContext->refColorSpace(), + &this->props())); + fRenderTargetContext = nullptr; return tmp; } private: - sk_sp fDrawContext; + sk_sp fRenderTargetContext; typedef SkSpecialSurface_Base INHERITED; }; @@ -161,16 +164,16 @@ sk_sp SkSpecialSurface::MakeRenderTarget(GrContext* context, return nullptr; } - sk_sp drawContext(context->makeDrawContext(SkBackingFit::kApprox, - width, height, config, - std::move(colorSpace))); - if (!drawContext) { + sk_sp renderTargetContext(context->makeRenderTargetContext( + SkBackingFit::kApprox, width, height, config, std::move(colorSpace))); + if (!renderTargetContext) { return nullptr; } const SkIRect subset = SkIRect::MakeWH(width, height); - return sk_make_sp(std::move(drawContext), width, height, subset); + return sk_make_sp(context, std::move(renderTargetContext), + width, height, subset); } #endif diff --git a/gfx/skia/skia/src/core/SkSpecialSurface.h b/gfx/skia/skia/src/core/SkSpecialSurface.h index 2aa03dd4deff..96b74a4dacc4 100644 --- a/gfx/skia/skia/src/core/SkSpecialSurface.h +++ b/gfx/skia/skia/src/core/SkSpecialSurface.h @@ -8,13 +8,17 @@ #ifndef SkSpecialSurface_DEFINED #define SkSpecialSurface_DEFINED +#include "SkImageInfo.h" #include "SkRefCnt.h" #include "SkSurfaceProps.h" +#if SK_SUPPORT_GPU +#include "GrTypes.h" +#endif + class GrContext; -struct GrSurfaceDesc; +class SkBitmap; class SkCanvas; -struct SkImageInfo; class SkSpecialImage; /** diff --git a/gfx/skia/skia/src/core/SkSpriteBlitter.h b/gfx/skia/skia/src/core/SkSpriteBlitter.h index 3a6286086790..3cec67424094 100644 --- a/gfx/skia/skia/src/core/SkSpriteBlitter.h +++ b/gfx/skia/skia/src/core/SkSpriteBlitter.h @@ -11,7 +11,6 @@ #include "SkBlitter.h" #include "SkPixmap.h" #include "SkShader.h" -#include "SkSmallAllocator.h" class SkPaint; @@ -33,10 +32,10 @@ public: // A SkSpriteBlitter must implement blitRect. void blitRect(int x, int y, int width, int height) override = 0; - static SkSpriteBlitter* ChooseD16(const SkPixmap& source, const SkPaint&, SkTBlitterAllocator*); - static SkSpriteBlitter* ChooseL32(const SkPixmap& source, const SkPaint&, SkTBlitterAllocator*); - static SkSpriteBlitter* ChooseS32(const SkPixmap& source, const SkPaint&, SkTBlitterAllocator*); - static SkSpriteBlitter* ChooseF16(const SkPixmap& source, const SkPaint&, SkTBlitterAllocator*); + static SkSpriteBlitter* ChooseD16(const SkPixmap& source, const SkPaint&, SkArenaAlloc*); + static SkSpriteBlitter* ChooseL32(const SkPixmap& source, const SkPaint&, SkArenaAlloc*); + static SkSpriteBlitter* ChooseS32(const SkPixmap& source, const SkPaint&, SkArenaAlloc*); + static SkSpriteBlitter* ChooseF16(const SkPixmap& source, const SkPaint&, SkArenaAlloc*); protected: SkPixmap fDst; diff --git a/gfx/skia/skia/src/core/SkSpriteBlitter4f.cpp b/gfx/skia/skia/src/core/SkSpriteBlitter4f.cpp index 38ec7394d74f..f893478c0863 100644 --- a/gfx/skia/skia/src/core/SkSpriteBlitter4f.cpp +++ b/gfx/skia/skia/src/core/SkSpriteBlitter4f.cpp @@ -6,21 +6,22 @@ */ #include "SkSpriteBlitter.h" +#include "SkArenaAlloc.h" #include "SkSpanProcs.h" #include "SkTemplates.h" -#include "SkXfermode.h" +#include "SkXfermodePriv.h" class Sprite_4f : public SkSpriteBlitter { public: Sprite_4f(const SkPixmap& src, const SkPaint& paint) : INHERITED(src) { - fXfer = SkXfermode::Peek(paint.getBlendMode()); + fMode = paint.getBlendMode(); fLoader = SkLoadSpanProc_Choose(src.info()); fFilter = SkFilterSpanProc_Choose(paint); fBuffer.reset(src.width()); } protected: - SkXfermode* fXfer; + SkBlendMode fMode; SkLoadSpanProc fLoader; SkFilterSpanProc fFilter; SkAutoTMalloc fBuffer; @@ -38,7 +39,7 @@ public: if (src.isOpaque()) { flags |= SkXfermode::kSrcIsOpaque_F16Flag; } - fWriter = SkXfermode::GetF16Proc(fXfer, flags); + fWriter = SkXfermode::GetF16Proc(fMode, flags); } void blitRect(int x, int y, int width, int height) override { @@ -49,7 +50,7 @@ public: for (int bottom = y + height; y < bottom; ++y) { fLoader(fSource, x - fLeft, y - fTop, fBuffer, width); fFilter(*fPaint, fBuffer, width); - fWriter(fXfer, dst, fBuffer, width, nullptr); + fWriter(fMode, dst, fBuffer, width, nullptr); dst = (uint64_t* SK_RESTRICT)((char*)dst + dstRB); } } @@ -62,7 +63,7 @@ private: SkSpriteBlitter* SkSpriteBlitter::ChooseF16(const SkPixmap& source, const SkPaint& paint, - SkTBlitterAllocator* allocator) { + SkArenaAlloc* allocator) { SkASSERT(allocator != nullptr); if (paint.getMaskFilter() != nullptr) { @@ -72,7 +73,7 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseF16(const SkPixmap& source, const SkPain switch (source.colorType()) { case kN32_SkColorType: case kRGBA_F16_SkColorType: - return allocator->createT(source, paint); + return allocator->make(source, paint); default: return nullptr; } @@ -87,7 +88,7 @@ public: if (src.isOpaque()) { flags |= SkXfermode::kSrcIsOpaque_D32Flag; } - fWriter = SkXfermode::GetD32Proc(fXfer, flags); + fWriter = SkXfermode::GetD32Proc(fMode, flags); } void blitRect(int x, int y, int width, int height) override { @@ -98,7 +99,7 @@ public: for (int bottom = y + height; y < bottom; ++y) { fLoader(fSource, x - fLeft, y - fTop, fBuffer, width); fFilter(*fPaint, fBuffer, width); - fWriter(fXfer, dst, fBuffer, width, nullptr); + fWriter(fMode, dst, fBuffer, width, nullptr); dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB); } } @@ -112,7 +113,7 @@ private: SkSpriteBlitter* SkSpriteBlitter::ChooseS32(const SkPixmap& source, const SkPaint& paint, - SkTBlitterAllocator* allocator) { + SkArenaAlloc* allocator) { SkASSERT(allocator != nullptr); if (paint.getMaskFilter() != nullptr) { @@ -122,7 +123,7 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseS32(const SkPixmap& source, const SkPain switch (source.colorType()) { case kN32_SkColorType: case kRGBA_F16_SkColorType: - return allocator->createT(source, paint); + return allocator->make(source, paint); default: return nullptr; } diff --git a/gfx/skia/skia/src/core/SkSpriteBlitter_ARGB32.cpp b/gfx/skia/skia/src/core/SkSpriteBlitter_ARGB32.cpp index 1a76b1b2fe15..3ecfcf472b30 100644 --- a/gfx/skia/skia/src/core/SkSpriteBlitter_ARGB32.cpp +++ b/gfx/skia/skia/src/core/SkSpriteBlitter_ARGB32.cpp @@ -6,12 +6,13 @@ */ #include "SkSpriteBlitter.h" +#include "SkArenaAlloc.h" #include "SkBlitRow.h" #include "SkColorFilter.h" #include "SkColorPriv.h" #include "SkTemplates.h" #include "SkUtils.h" -#include "SkXfermode.h" +#include "SkXfermodePriv.h" /////////////////////////////////////////////////////////////////////////////// @@ -80,7 +81,7 @@ public: fAlpha = paint.getAlpha(); } - virtual ~Sprite_D32_XferFilter() { + ~Sprite_D32_XferFilter() override { delete[] fBuffer; SkSafeUnref(fColorFilter); } @@ -253,7 +254,7 @@ public: /////////////////////////////////////////////////////////////////////////////// SkSpriteBlitter* SkSpriteBlitter::ChooseL32(const SkPixmap& source, const SkPaint& paint, - SkTBlitterAllocator* allocator) { + SkArenaAlloc* allocator) { SkASSERT(allocator != nullptr); if (paint.getMaskFilter() != nullptr) { @@ -271,22 +272,22 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseL32(const SkPixmap& source, const SkPain return nullptr; // we only have opaque sprites } if (!isSrcOver || filter) { - blitter = allocator->createT(source, paint); + blitter = allocator->make(source, paint); } else if (source.isOpaque()) { - blitter = allocator->createT(source); + blitter = allocator->make(source); } else { - blitter = allocator->createT(source); + blitter = allocator->make(source); } break; case kN32_SkColorType: if (!isSrcOver || filter) { if (255 == alpha) { // this can handle xfermode or filter, but not alpha - blitter = allocator->createT(source, paint); + blitter = allocator->make(source, paint); } } else { // this can handle alpha, but not xfermode or filter - blitter = allocator->createT(source, alpha); + blitter = allocator->make(source, alpha); } break; default: diff --git a/gfx/skia/skia/src/core/SkSpriteBlitter_RGB16.cpp b/gfx/skia/skia/src/core/SkSpriteBlitter_RGB16.cpp index 9df7dab48c4f..c616e2224e53 100644 --- a/gfx/skia/skia/src/core/SkSpriteBlitter_RGB16.cpp +++ b/gfx/skia/skia/src/core/SkSpriteBlitter_RGB16.cpp @@ -7,6 +7,7 @@ #include "SkSpriteBlitter.h" +#include "SkArenaAlloc.h" #include "SkBlitRow.h" #include "SkTemplates.h" #include "SkUtils.h" @@ -30,11 +31,7 @@ static inline void D16_S32A_Blend_Pixel_helper(uint16_t* dst, SkPMColor sc, dg = SkAlphaBlend(SkPacked32ToG16(sc), SkGetPackedG16(dc), src_scale); db = SkAlphaBlend(SkPacked32ToB16(sc), SkGetPackedB16(dc), src_scale); } else { -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - unsigned dst_scale = 255 - SkAlphaMul(sa, src_scale); -#else unsigned dst_scale = SkAlphaMulInv256(sa, src_scale); -#endif dr = (SkPacked32ToR16(sc) * src_scale + SkGetPackedR16(dc) * dst_scale) >> 8; dg = (SkPacked32ToG16(sc) * src_scale + SkGetPackedG16(dc) * dst_scale) >> 8; db = (SkPacked32ToB16(sc) * src_scale + SkGetPackedB16(dc) * dst_scale) >> 8; @@ -300,7 +297,7 @@ private: /////////////////////////////////////////////////////////////////////////////// SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkPixmap& source, const SkPaint& paint, - SkTBlitterAllocator* allocator) { + SkArenaAlloc* allocator) { SkASSERT(allocator != nullptr); @@ -324,7 +321,7 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkPixmap& source, const SkPain if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) { break; } - blitter = allocator->createT(source); + blitter = allocator->make(source); break; } case kARGB_4444_SkColorType: @@ -332,16 +329,16 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkPixmap& source, const SkPain break; } if (255 == alpha) { - blitter = allocator->createT(source); + blitter = allocator->make(source); } else { - blitter = allocator->createT(source, alpha >> 4); + blitter = allocator->make(source, alpha >> 4); } break; case kRGB_565_SkColorType: if (255 == alpha) { - blitter = allocator->createT(source); + blitter = allocator->make(source); } else { - blitter = allocator->createT(source, alpha); + blitter = allocator->make(source, alpha); } break; case kIndex_8_SkColorType: @@ -354,15 +351,15 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkPixmap& source, const SkPain } if (source.isOpaque()) { if (255 == alpha) { - blitter = allocator->createT(source); + blitter = allocator->make(source); } else { - blitter = allocator->createT(source, alpha); + blitter = allocator->make(source, alpha); } } else { if (255 == alpha) { - blitter = allocator->createT(source); + blitter = allocator->make(source); } else { - blitter = allocator->createT(source, alpha); + blitter = allocator->make(source, alpha); } } break; diff --git a/gfx/skia/skia/src/core/SkStream.cpp b/gfx/skia/skia/src/core/SkStream.cpp index e7b3a7a7e577..f0e16a6ff6a9 100644 --- a/gfx/skia/skia/src/core/SkStream.cpp +++ b/gfx/skia/skia/src/core/SkStream.cpp @@ -70,11 +70,6 @@ SkWStream::~SkWStream() { } -void SkWStream::newline() -{ - this->write("\n", 1); -} - void SkWStream::flush() { } @@ -107,20 +102,6 @@ bool SkWStream::writeScalarAsText(SkScalar value) return this->write(buffer, stop - buffer); } -bool SkWStream::write8(U8CPU value) { - uint8_t v = SkToU8(value); - return this->write(&v, 1); -} - -bool SkWStream::write16(U16CPU value) { - uint16_t v = SkToU16(value); - return this->write(&v, 2); -} - -bool SkWStream::write32(uint32_t value) { - return this->write(&value, 4); -} - bool SkWStream::writeScalar(SkScalar value) { return this->write(&value, sizeof(value)); } @@ -174,105 +155,95 @@ bool SkWStream::writeStream(SkStream* stream, size_t length) { /////////////////////////////////////////////////////////////////////////////// -SkFILEStream::SkFILEStream(const char file[]) : fName(file), fOwnership(kCallerPasses_Ownership) { - fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : nullptr; -} +SkFILEStream::SkFILEStream(std::shared_ptr file, size_t size, + size_t offset, size_t originalOffset) + : fFILE(std::move(file)) + , fSize(size) + , fOffset(SkTMin(offset, fSize)) + , fOriginalOffset(SkTMin(originalOffset, fSize)) +{ } -SkFILEStream::SkFILEStream(FILE* file, Ownership ownership) - : fFILE(file) - , fOwnership(ownership) { -} +SkFILEStream::SkFILEStream(std::shared_ptr file, size_t size, size_t offset) + : SkFILEStream(std::move(file), size, offset, offset) +{ } + +SkFILEStream::SkFILEStream(FILE* file) + : SkFILEStream(std::shared_ptr(file, sk_fclose), + file ? sk_fgetsize(file) : 0, + file ? sk_ftell(file) : 0) +{ } + + +SkFILEStream::SkFILEStream(const char path[]) + : SkFILEStream(path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr) +{ } SkFILEStream::~SkFILEStream() { - if (fFILE && fOwnership != kCallerRetains_Ownership) { - sk_fclose(fFILE); - } + this->close(); } -void SkFILEStream::setPath(const char path[]) { - fName.set(path); - if (fFILE) { - sk_fclose(fFILE); - fFILE = nullptr; - } - if (path) { - fFILE = sk_fopen(fName.c_str(), kRead_SkFILE_Flag); - } +void SkFILEStream::close() { + fFILE.reset(); + fSize = 0; + fOffset = 0; } size_t SkFILEStream::read(void* buffer, size_t size) { - if (fFILE) { - return sk_fread(buffer, size, fFILE); + if (size > fSize - fOffset) { + size = fSize - fOffset; } - return 0; + size_t bytesRead = size; + if (buffer) { + bytesRead = sk_qread(fFILE.get(), buffer, size, fOffset); + } + if (bytesRead == SIZE_MAX) { + return 0; + } + fOffset += bytesRead; + return bytesRead; } bool SkFILEStream::isAtEnd() const { - return sk_feof(fFILE); + if (fOffset == fSize) { + return true; + } + return fOffset >= sk_fgetsize(fFILE.get()); } bool SkFILEStream::rewind() { - if (fFILE) { - if (sk_frewind(fFILE)) { - return true; - } - // we hit an error - sk_fclose(fFILE); - fFILE = nullptr; - } - return false; + // TODO: fOriginalOffset instead of 0. + fOffset = 0; + return true; } SkStreamAsset* SkFILEStream::duplicate() const { - if (nullptr == fFILE) { - return new SkMemoryStream(); - } - - if (fData.get()) { - return new SkMemoryStream(fData); - } - - if (!fName.isEmpty()) { - SkAutoTDelete that(new SkFILEStream(fName.c_str())); - if (sk_fidentical(that->fFILE, this->fFILE)) { - return that.release(); - } - } - - fData = SkData::MakeFromFILE(fFILE); - if (nullptr == fData) { - return nullptr; - } - return new SkMemoryStream(fData); + // TODO: fOriginalOffset instead of 0. + return new SkFILEStream(fFILE, fSize, 0, fOriginalOffset); } size_t SkFILEStream::getPosition() const { - return sk_ftell(fFILE); + return fOffset; } bool SkFILEStream::seek(size_t position) { - return sk_fseek(fFILE, position); + fOffset = position > fSize ? fSize : position; + return true; } bool SkFILEStream::move(long offset) { - return sk_fmove(fFILE, offset); + return this->seek(fOffset + offset); } SkStreamAsset* SkFILEStream::fork() const { - SkAutoTDelete that(this->duplicate()); - that->seek(this->getPosition()); - return that.release(); + return new SkFILEStream(fFILE, fSize, fOffset, fOriginalOffset); } size_t SkFILEStream::getLength() const { - return sk_fgetsize(fFILE); + return fSize; } const void* SkFILEStream::getMemoryBase() { - if (nullptr == fData.get()) { - return nullptr; - } - return fData->data(); + return nullptr; } /////////////////////////////////////////////////////////////////////////////// @@ -307,17 +278,6 @@ SkMemoryStream::SkMemoryStream(sk_sp data) : fData(std::move(data)) { fOffset = 0; } -#ifdef SK_SUPPORT_LEGACY_STREAM_DATA -SkMemoryStream::SkMemoryStream(SkData* data) { - if (nullptr == data) { - fData = SkData::MakeEmpty(); - } else { - fData = sk_ref_sp(data); - } - fOffset = 0; -} -#endif - void SkMemoryStream::setMemoryOwned(const void* src, size_t size) { fData = SkData::MakeFromMalloc(src, size); fOffset = 0; @@ -392,7 +352,7 @@ bool SkMemoryStream::move(long offset) { } SkMemoryStream* SkMemoryStream::fork() const { - SkAutoTDelete that(this->duplicate()); + std::unique_ptr that(this->duplicate()); that->seek(fOffset); return that.release(); } @@ -461,24 +421,15 @@ void SkFILEWStream::fsync() //////////////////////////////////////////////////////////////////////// -SkMemoryWStream::SkMemoryWStream(void* buffer, size_t size) - : fBuffer((char*)buffer), fMaxLength(size), fBytesWritten(0) -{ -} - -bool SkMemoryWStream::write(const void* buffer, size_t size) { - size = SkTMin(size, fMaxLength - fBytesWritten); - if (size > 0) { - memcpy(fBuffer + fBytesWritten, buffer, size); - fBytesWritten += size; - return true; +static inline void sk_memcpy_4bytes(void* dst, const void* src, size_t size) { + if (size == 4) { + memcpy(dst, src, 4); + } else { + memcpy(dst, src, size); } - return false; } -//////////////////////////////////////////////////////////////////////// - -#define SkDynamicMemoryWStream_MinBlockSize 256 +#define SkDynamicMemoryWStream_MinBlockSize 4096 struct SkDynamicMemoryWStream::Block { Block* fNext; @@ -490,65 +441,69 @@ struct SkDynamicMemoryWStream::Block { size_t avail() const { return fStop - fCurr; } size_t written() const { return fCurr - this->start(); } - void init(size_t size) - { + void init(size_t size) { fNext = nullptr; fCurr = this->start(); fStop = this->start() + size; } - const void* append(const void* data, size_t size) - { + const void* append(const void* data, size_t size) { SkASSERT((size_t)(fStop - fCurr) >= size); - memcpy(fCurr, data, size); + sk_memcpy_4bytes(fCurr, data, size); fCurr += size; return (const void*)((const char*)data + size); } }; SkDynamicMemoryWStream::SkDynamicMemoryWStream() - : fHead(nullptr), fTail(nullptr), fBytesWritten(0) + : fHead(nullptr), fTail(nullptr), fBytesWrittenBeforeTail(0) {} -SkDynamicMemoryWStream::~SkDynamicMemoryWStream() -{ - reset(); +SkDynamicMemoryWStream::~SkDynamicMemoryWStream() { + this->reset(); } -void SkDynamicMemoryWStream::reset() -{ - this->invalidateCopy(); - +void SkDynamicMemoryWStream::reset() { Block* block = fHead; - while (block != nullptr) { Block* next = block->fNext; sk_free(block); block = next; } fHead = fTail = nullptr; - fBytesWritten = 0; + fBytesWrittenBeforeTail = 0; } -bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) -{ +size_t SkDynamicMemoryWStream::bytesWritten() const { + this->validate(); + + if (fTail) { + return fBytesWrittenBeforeTail + fTail->written(); + } + return 0; +} + +bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) { if (count > 0) { - this->invalidateCopy(); - - fBytesWritten += count; - size_t size; - if (fTail != nullptr && fTail->avail() > 0) { - size = SkTMin(fTail->avail(), count); - buffer = fTail->append(buffer, size); - SkASSERT(count >= size); - count -= size; - if (count == 0) - return true; + if (fTail) { + if (fTail->avail() > 0) { + size = SkTMin(fTail->avail(), count); + buffer = fTail->append(buffer, size); + SkASSERT(count >= size); + count -= size; + if (count == 0) { + return true; + } + } + // If we get here, we've just exhausted fTail, so update our tracker + fBytesWrittenBeforeTail += fTail->written(); } - size = SkTMax(count, SkDynamicMemoryWStream_MinBlockSize); + size = SkTMax(count, SkDynamicMemoryWStream_MinBlockSize - sizeof(Block)); + size = SkAlign4(size); // ensure we're always a multiple of 4 (see padToAlign4()) + Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); block->init(size); block->append(buffer, count); @@ -558,39 +513,15 @@ bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) else fHead = fTail = block; fTail = block; + this->validate(); } return true; } -bool SkDynamicMemoryWStream::write(const void* buffer, size_t offset, size_t count) -{ - if (offset + count > fBytesWritten) { +bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count) { + if (offset + count > this->bytesWritten()) { return false; // test does not partially modify } - - this->invalidateCopy(); - - Block* block = fHead; - while (block != nullptr) { - size_t size = block->written(); - if (offset < size) { - size_t part = offset + count > size ? size - offset : count; - memcpy(block->start() + offset, buffer, part); - if (count <= part) - return true; - count -= part; - buffer = (const void*) ((char* ) buffer + part); - } - offset = offset > size ? offset - size : 0; - block = block->fNext; - } - return false; -} - -bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count) -{ - if (offset + count > fBytesWritten) - return false; // test does not partially modify Block* block = fHead; while (block != nullptr) { size_t size = block->written(); @@ -608,19 +539,13 @@ bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count) return false; } -void SkDynamicMemoryWStream::copyTo(void* dst) const -{ - if (fCopy) { - memcpy(dst, fCopy->data(), fBytesWritten); - } else { - Block* block = fHead; - - while (block != nullptr) { - size_t size = block->written(); - memcpy(dst, block->start(), size); - dst = (void*)((char*)dst + size); - block = block->fNext; - } +void SkDynamicMemoryWStream::copyTo(void* dst) const { + Block* block = fHead; + while (block != nullptr) { + size_t size = block->written(); + memcpy(dst, block->start(), size); + dst = (void*)((char*)dst + size); + block = block->fNext; } } @@ -630,35 +555,73 @@ void SkDynamicMemoryWStream::writeToStream(SkWStream* dst) const { } } -void SkDynamicMemoryWStream::padToAlign4() -{ - // cast to remove unary-minus warning - int padBytes = -(int)fBytesWritten & 0x03; - if (padBytes == 0) - return; - int zero = 0; - write(&zero, padBytes); +void SkDynamicMemoryWStream::padToAlign4() { + // The contract is to write zeros until the entire stream has written a multiple of 4 bytes. + // Our Blocks are guaranteed always be (a) full (except the tail) and (b) a multiple of 4 + // so it is sufficient to just examine the tail (if present). + + if (fTail) { + // cast to remove unary-minus warning + int padBytes = -(int)fTail->written() & 0x03; + if (padBytes) { + int zero = 0; + fTail->append(&zero, padBytes); + } + } } -sk_sp SkDynamicMemoryWStream::snapshotAsData() const { - if (nullptr == fCopy) { - auto data = SkData::MakeUninitialized(fBytesWritten); - // be sure to call copyTo() before we assign to fCopy - this->copyTo(data->writable_data()); - fCopy = std::move(data); + +void SkDynamicMemoryWStream::copyToAndReset(void* ptr) { + // By looping through the source and freeing as we copy, we + // can reduce real memory use with large streams. + char* dst = reinterpret_cast(ptr); + Block* block = fHead; + while (block != nullptr) { + size_t len = block->written(); + memcpy(dst, block->start(), len); + dst += len; + Block* next = block->fNext; + sk_free(block); + block = next; } - return fCopy; + fHead = fTail = nullptr; + fBytesWrittenBeforeTail = 0; } sk_sp SkDynamicMemoryWStream::detachAsData() { - sk_sp data = this->snapshotAsData(); - this->reset(); + const size_t size = this->bytesWritten(); + if (0 == size) { + return SkData::MakeEmpty(); + } + sk_sp data = SkData::MakeUninitialized(size); + this->copyToAndReset(data->writable_data()); return data; } -void SkDynamicMemoryWStream::invalidateCopy() { - fCopy = nullptr; +#ifdef SK_DEBUG +void SkDynamicMemoryWStream::validate() const { + if (!fHead) { + SkASSERT(!fTail); + SkASSERT(fBytesWrittenBeforeTail == 0); + return; + } + SkASSERT(fTail); + + size_t bytes = 0; + const Block* block = fHead; + while (block) { + if (block->fNext) { + SkASSERT(block->avail() == 0); + bytes += block->written(); + SkASSERT(bytes == SkAlign4(bytes)); // see padToAlign4() + } + block = block->fNext; + } + SkASSERT(bytes == fBytesWrittenBeforeTail); } +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////// class SkBlockMemoryRefCnt : public SkRefCnt { public: @@ -678,15 +641,8 @@ public: class SkBlockMemoryStream : public SkStreamAsset { public: - SkBlockMemoryStream(SkDynamicMemoryWStream::Block* head, size_t size) - : fBlockMemory(new SkBlockMemoryRefCnt(head)) - , fCurrent(head) - , fSize(size) - , fOffset(0) - , fCurrentOffset(0) {} - - SkBlockMemoryStream(SkBlockMemoryRefCnt* headRef, size_t size) - : fBlockMemory(SkRef(headRef)), fCurrent(fBlockMemory->fHead) + SkBlockMemoryStream(sk_sp headRef, size_t size) + : fBlockMemory(std::move(headRef)), fCurrent(fBlockMemory->fHead) , fSize(size) , fOffset(0), fCurrentOffset(0) { } size_t read(void* buffer, size_t rawCount) override { @@ -730,8 +686,7 @@ public: size_t currentOffset = fCurrentOffset; while (bytesLeftToPeek) { SkASSERT(current); - size_t bytesFromCurrent = - SkTMin(current->written() - currentOffset, bytesLeftToPeek); + size_t bytesFromCurrent = SkTMin(current->written() - currentOffset, bytesLeftToPeek); memcpy(buffer, current->start() + currentOffset, bytesFromCurrent); bytesLeftToPeek -= bytesFromCurrent; buffer += bytesFromCurrent; @@ -749,7 +704,7 @@ public: } SkBlockMemoryStream* duplicate() const override { - return new SkBlockMemoryStream(fBlockMemory.get(), fSize); + return new SkBlockMemoryStream(fBlockMemory, fSize); } size_t getPosition() const override { @@ -778,7 +733,7 @@ public: } SkBlockMemoryStream* fork() const override { - SkAutoTDelete that(this->duplicate()); + std::unique_ptr that(this->duplicate()); that->fCurrent = this->fCurrent; that->fOffset = this->fOffset; that->fCurrentOffset = this->fCurrentOffset; @@ -790,59 +745,31 @@ public: } const void* getMemoryBase() override { - if (nullptr != fBlockMemory->fHead && - nullptr == fBlockMemory->fHead->fNext) { + if (fBlockMemory->fHead && !fBlockMemory->fHead->fNext) { return fBlockMemory->fHead->start(); } return nullptr; } private: - SkAutoTUnref const fBlockMemory; + sk_sp const fBlockMemory; SkDynamicMemoryWStream::Block const * fCurrent; size_t const fSize; size_t fOffset; size_t fCurrentOffset; }; -SkStreamAsset* SkDynamicMemoryWStream::detachAsStream() { - if (fCopy) { - SkMemoryStream* stream = new SkMemoryStream(fCopy); - this->reset(); - return stream; - } - SkBlockMemoryStream* stream = new SkBlockMemoryStream(fHead, fBytesWritten); - fHead = 0; +std::unique_ptr SkDynamicMemoryWStream::detachAsStream() { + std::unique_ptr stream + = skstd::make_unique(sk_make_sp(fHead), + this->bytesWritten()); + fHead = nullptr; // signal reset() to not free anything this->reset(); return stream; } /////////////////////////////////////////////////////////////////////////////// - -void SkDebugWStream::newline() -{ -#if defined(SK_DEBUG) - SkDebugf("\n"); - fBytesWritten++; -#endif -} - -bool SkDebugWStream::write(const void* buffer, size_t size) -{ -#if defined(SK_DEBUG) - char* s = new char[size+1]; - memcpy(s, buffer, size); - s[size] = 0; - SkDebugf("%s", s); - delete[] s; - fBytesWritten += size; -#endif - return true; -} - /////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - static sk_sp mmap_filename(const char path[]) { FILE* file = sk_fopen(path, kRead_SkFILE_Flag); diff --git a/gfx/skia/skia/src/core/SkStringUtils.h b/gfx/skia/skia/src/core/SkStringUtils.h index fd158c30bd51..fecf833d73ae 100644 --- a/gfx/skia/skia/src/core/SkStringUtils.h +++ b/gfx/skia/skia/src/core/SkStringUtils.h @@ -8,6 +8,8 @@ #ifndef SkStringUtils_DEFINED #define SkStringUtils_DEFINED +#include "SkScalar.h" + class SkString; /** diff --git a/gfx/skia/skia/src/core/SkStroke.cpp b/gfx/skia/skia/src/core/SkStroke.cpp index 8ff7910bdc18..e384df1ef74c 100644 --- a/gfx/skia/skia/src/core/SkStroke.cpp +++ b/gfx/skia/skia/src/core/SkStroke.cpp @@ -606,15 +606,23 @@ SkPathStroker::ReductionType SkPathStroker::CheckCubicLinear(const SkPoint cubic if (count == 0) { return kLine_ReductionType; } + int rCount = 0; + // Now loop over the t-values, and reject any that evaluate to either end-point for (int index = 0; index < count; ++index) { SkScalar t = tValues[index]; - SkEvalCubicAt(cubic, t, &reduction[index], nullptr, nullptr); + SkEvalCubicAt(cubic, t, &reduction[rCount], nullptr, nullptr); + if (reduction[rCount] != cubic[0] && reduction[rCount] != cubic[3]) { + ++rCount; + } + } + if (rCount == 0) { + return kLine_ReductionType; } static_assert(kQuad_ReductionType + 1 == kDegenerate_ReductionType, "enum_out_of_whack"); static_assert(kQuad_ReductionType + 2 == kDegenerate2_ReductionType, "enum_out_of_whack"); static_assert(kQuad_ReductionType + 3 == kDegenerate3_ReductionType, "enum_out_of_whack"); - return (ReductionType) (kQuad_ReductionType + count); + return (ReductionType) (kQuad_ReductionType + rCount); } SkPathStroker::ReductionType SkPathStroker::CheckConicLinear(const SkConic& conic, diff --git a/gfx/skia/skia/src/core/SkStrokeRec.cpp b/gfx/skia/skia/src/core/SkStrokeRec.cpp index f3cca1653f04..7e667bc66851 100644 --- a/gfx/skia/skia/src/core/SkStrokeRec.cpp +++ b/gfx/skia/skia/src/core/SkStrokeRec.cpp @@ -147,7 +147,7 @@ static inline SkScalar get_inflation_bounds(SkPaint::Join join, SkScalar radius = SkScalarHalf(strokeWidth); if (SkPaint::kMiter_Join == join) { if (miterLimit > SK_Scalar1) { - radius = SkScalarMul(miterLimit, radius); + radius *= miterLimit; } } return radius; diff --git a/gfx/skia/skia/src/core/SkStrokerPriv.cpp b/gfx/skia/skia/src/core/SkStrokerPriv.cpp index 840f961982c5..52144cdc5fc1 100644 --- a/gfx/skia/skia/src/core/SkStrokerPriv.cpp +++ b/gfx/skia/skia/src/core/SkStrokerPriv.cpp @@ -5,22 +5,17 @@ * found in the LICENSE file. */ - #include "SkStrokerPriv.h" #include "SkGeometry.h" #include "SkPath.h" -static void ButtCapper(SkPath* path, const SkPoint& pivot, - const SkVector& normal, const SkPoint& stop, - SkPath*) -{ +static void ButtCapper(SkPath* path, const SkPoint& pivot, const SkVector& normal, + const SkPoint& stop, SkPath*) { path->lineTo(stop.fX, stop.fY); } -static void RoundCapper(SkPath* path, const SkPoint& pivot, - const SkVector& normal, const SkPoint& stop, - SkPath*) -{ +static void RoundCapper(SkPath* path, const SkPoint& pivot, const SkVector& normal, + const SkPoint& stop, SkPath*) { SkVector parallel; normal.rotateCW(¶llel); @@ -30,20 +25,15 @@ static void RoundCapper(SkPath* path, const SkPoint& pivot, path->conicTo(projectedCenter - normal, stop, SK_ScalarRoot2Over2); } -static void SquareCapper(SkPath* path, const SkPoint& pivot, - const SkVector& normal, const SkPoint& stop, - SkPath* otherPath) -{ +static void SquareCapper(SkPath* path, const SkPoint& pivot, const SkVector& normal, + const SkPoint& stop, SkPath* otherPath) { SkVector parallel; normal.rotateCW(¶llel); - if (otherPath) - { + if (otherPath) { path->setLastPt(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY); path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY); - } - else - { + } else { path->lineTo(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY); path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY); path->lineTo(stop.fX, stop.fY); @@ -52,9 +42,8 @@ static void SquareCapper(SkPath* path, const SkPoint& pivot, ///////////////////////////////////////////////////////////////////////////// -static bool is_clockwise(const SkVector& before, const SkVector& after) -{ - return SkScalarMul(before.fX, after.fY) - SkScalarMul(before.fY, after.fX) > 0; +static bool is_clockwise(const SkVector& before, const SkVector& after) { + return before.fX * after.fY > before.fY * after.fX; } enum AngleType { @@ -64,19 +53,18 @@ enum AngleType { kNearlyLine_AngleType }; -static AngleType Dot2AngleType(SkScalar dot) -{ +static AngleType Dot2AngleType(SkScalar dot) { // need more precise fixed normalization // SkASSERT(SkScalarAbs(dot) <= SK_Scalar1 + SK_ScalarNearlyZero); - if (dot >= 0) // shallow or line + if (dot >= 0) { // shallow or line return SkScalarNearlyZero(SK_Scalar1 - dot) ? kNearlyLine_AngleType : kShallow_AngleType; - else // sharp or 180 + } else { // sharp or 180 return SkScalarNearlyZero(SK_Scalar1 + dot) ? kNearly180_AngleType : kSharp_AngleType; + } } -static void HandleInnerJoin(SkPath* inner, const SkPoint& pivot, const SkVector& after) -{ +static void HandleInnerJoin(SkPath* inner, const SkPoint& pivot, const SkVector& after) { #if 1 /* In the degenerate case that the stroke radius is larger than our segments just connecting the two inner segments may "show through" as a funny @@ -92,13 +80,11 @@ static void HandleInnerJoin(SkPath* inner, const SkPoint& pivot, const SkVector& static void BluntJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal, const SkPoint& pivot, const SkVector& afterUnitNormal, - SkScalar radius, SkScalar invMiterLimit, bool, bool) -{ + SkScalar radius, SkScalar invMiterLimit, bool, bool) { SkVector after; afterUnitNormal.scale(radius, &after); - if (!is_clockwise(beforeUnitNormal, afterUnitNormal)) - { + if (!is_clockwise(beforeUnitNormal, afterUnitNormal)) { SkTSwap(outer, inner); after.negate(); } @@ -109,8 +95,7 @@ static void BluntJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnit static void RoundJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal, const SkPoint& pivot, const SkVector& afterUnitNormal, - SkScalar radius, SkScalar invMiterLimit, bool, bool) -{ + SkScalar radius, SkScalar invMiterLimit, bool, bool) { SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal); AngleType angleType = Dot2AngleType(dotProd); @@ -121,8 +106,7 @@ static void RoundJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnit SkVector after = afterUnitNormal; SkRotationDirection dir = kCW_SkRotationDirection; - if (!is_clockwise(before, after)) - { + if (!is_clockwise(before, after)) { SkTSwap(outer, inner); before.negate(); after.negate(); @@ -148,8 +132,7 @@ static void RoundJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnit static void MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal, const SkPoint& pivot, const SkVector& afterUnitNormal, SkScalar radius, SkScalar invMiterLimit, - bool prevIsLine, bool currIsLine) -{ + bool prevIsLine, bool currIsLine) { // negate the dot since we're using normals instead of tangents SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal); AngleType angleType = Dot2AngleType(dotProd); @@ -159,17 +142,16 @@ static void MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnit SkScalar sinHalfAngle; bool ccw; - if (angleType == kNearlyLine_AngleType) + if (angleType == kNearlyLine_AngleType) { return; - if (angleType == kNearly180_AngleType) - { + } + if (angleType == kNearly180_AngleType) { currIsLine = false; goto DO_BLUNT; } ccw = !is_clockwise(before, after); - if (ccw) - { + if (ccw) { SkTSwap(outer, inner); before.negate(); after.negate(); @@ -181,10 +163,8 @@ static void MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnit that (for speed an accuracy). Note: we only need to check one normal if dot==0 */ - if (0 == dotProd && invMiterLimit <= kOneOverSqrt2) - { - mid.set(SkScalarMul(before.fX + after.fX, radius), - SkScalarMul(before.fY + after.fY, radius)); + if (0 == dotProd && invMiterLimit <= kOneOverSqrt2) { + mid = (before + after) * radius; goto DO_MITER; } @@ -197,41 +177,41 @@ static void MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnit hence 1 + dot instead of 1 - dot in the formula */ sinHalfAngle = SkScalarSqrt(SkScalarHalf(SK_Scalar1 + dotProd)); - if (sinHalfAngle < invMiterLimit) - { + if (sinHalfAngle < invMiterLimit) { currIsLine = false; goto DO_BLUNT; } // choose the most accurate way to form the initial mid-vector - if (angleType == kSharp_AngleType) - { + if (angleType == kSharp_AngleType) { mid.set(after.fY - before.fY, before.fX - after.fX); - if (ccw) + if (ccw) { mid.negate(); - } - else + } + } else { mid.set(before.fX + after.fX, before.fY + after.fY); + } mid.setLength(radius / sinHalfAngle); DO_MITER: - if (prevIsLine) + if (prevIsLine) { outer->setLastPt(pivot.fX + mid.fX, pivot.fY + mid.fY); - else + } else { outer->lineTo(pivot.fX + mid.fX, pivot.fY + mid.fY); + } DO_BLUNT: after.scale(radius); - if (!currIsLine) + if (!currIsLine) { outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY); + } HandleInnerJoin(inner, pivot, after); } ///////////////////////////////////////////////////////////////////////////// -SkStrokerPriv::CapProc SkStrokerPriv::CapFactory(SkPaint::Cap cap) -{ - static const SkStrokerPriv::CapProc gCappers[] = { +SkStrokerPriv::CapProc SkStrokerPriv::CapFactory(SkPaint::Cap cap) { + const SkStrokerPriv::CapProc gCappers[] = { ButtCapper, RoundCapper, SquareCapper }; @@ -239,9 +219,8 @@ SkStrokerPriv::CapProc SkStrokerPriv::CapFactory(SkPaint::Cap cap) return gCappers[cap]; } -SkStrokerPriv::JoinProc SkStrokerPriv::JoinFactory(SkPaint::Join join) -{ - static const SkStrokerPriv::JoinProc gJoiners[] = { +SkStrokerPriv::JoinProc SkStrokerPriv::JoinFactory(SkPaint::Join join) { + const SkStrokerPriv::JoinProc gJoiners[] = { MiterJoiner, RoundJoiner, BluntJoiner }; diff --git a/gfx/skia/skia/src/core/SkTLList.h b/gfx/skia/skia/src/core/SkTLList.h index 58fa3f4aac8d..194879d6d161 100644 --- a/gfx/skia/skia/src/core/SkTLList.h +++ b/gfx/skia/skia/src/core/SkTLList.h @@ -9,6 +9,8 @@ #define SkTLList_DEFINED #include "SkTInternalLList.h" + +#include "SkMalloc.h" #include "SkTypes.h" #include diff --git a/gfx/skia/skia/src/core/SkTSearch.cpp b/gfx/skia/skia/src/core/SkTSearch.cpp index 9ff977763827..7081f672cf5a 100644 --- a/gfx/skia/skia/src/core/SkTSearch.cpp +++ b/gfx/skia/skia/src/core/SkTSearch.cpp @@ -7,6 +7,9 @@ #include "SkTSearch.h" + +#include "SkMalloc.h" + #include static inline const char* index_into_base(const char*const* base, int index, diff --git a/gfx/skia/skia/src/core/SkTSort.h b/gfx/skia/skia/src/core/SkTSort.h index 7101bab9bab5..e76f5c93f7b6 100644 --- a/gfx/skia/skia/src/core/SkTSort.h +++ b/gfx/skia/skia/src/core/SkTSort.h @@ -119,13 +119,16 @@ template void SkTHeapSort(T array[], size_t count) { /** Sorts the array of size count using comparator lessThan using an Insertion Sort algorithm. */ template static void SkTInsertionSort(T* left, T* right, C lessThan) { for (T* next = left + 1; next <= right; ++next) { - T insert = *next; - T* hole = next; - while (left < hole && lessThan(insert, *(hole - 1))) { - *hole = *(hole - 1); - --hole; + if (!lessThan(*next, *(next - 1))) { + continue; } - *hole = insert; + T insert = std::move(*next); + T* hole = next; + do { + *hole = std::move(*(hole - 1)); + --hole; + } while (left < hole && lessThan(insert, *(hole - 1))); + *hole = std::move(insert); } } diff --git a/gfx/skia/skia/src/core/SkTTopoSort.h b/gfx/skia/skia/src/core/SkTTopoSort.h index 35b85eeb8147..21c80696e778 100644 --- a/gfx/skia/skia/src/core/SkTTopoSort.h +++ b/gfx/skia/skia/src/core/SkTTopoSort.h @@ -76,7 +76,7 @@ bool SkTTopoSort_Visit(T* node, SkTDArray* result) { // // TODO: potentially add a version that takes a seed node and just outputs that // node and all the nodes on which it depends. This could be used to partially -// flush a drawTarget DAG. +// flush a GrOpList DAG. template bool SkTTopoSort(SkTDArray* graph) { SkTDArray result; diff --git a/gfx/skia/skia/src/core/SkTaskGroup.cpp b/gfx/skia/skia/src/core/SkTaskGroup.cpp index d151510cfa10..9469b8c1ce18 100644 --- a/gfx/skia/skia/src/core/SkTaskGroup.cpp +++ b/gfx/skia/skia/src/core/SkTaskGroup.cpp @@ -5,206 +5,43 @@ * found in the LICENSE file. */ -#include "SkLeanWindows.h" -#include "SkOnce.h" -#include "SkSemaphore.h" -#include "SkSpinlock.h" -#include "SkTArray.h" -#include "SkTDArray.h" +#include "SkExecutor.h" #include "SkTaskGroup.h" -#include "SkThreadUtils.h" -#if defined(SK_BUILD_FOR_WIN32) - static void query_num_cores(int* cores) { - SYSTEM_INFO sysinfo; - GetNativeSystemInfo(&sysinfo); - *cores = sysinfo.dwNumberOfProcessors; - } -#else - #include - static void query_num_cores(int* cores) { - *cores = (int)sysconf(_SC_NPROCESSORS_ONLN); - } -#endif +SkTaskGroup::SkTaskGroup(SkExecutor& executor) : fPending(0), fExecutor(executor) {} -static int num_cores() { - // We cache num_cores() so we only query the OS once. - static int cores = 0; - static SkOnce once; - once(query_num_cores, &cores); - SkASSERT(cores > 0); - return cores; +void SkTaskGroup::add(std::function fn) { + fPending.fetch_add(+1, std::memory_order_relaxed); + fExecutor.add([=] { + fn(); + fPending.fetch_add(-1, std::memory_order_release); + }); } -namespace { - -class ThreadPool : SkNoncopyable { -public: - static void Add(std::function fn, SkAtomic* pending) { - if (!gGlobal) { - return fn(); - } - gGlobal->add(fn, pending); +void SkTaskGroup::batch(int N, std::function fn) { + // TODO: I really thought we had some sort of more clever chunking logic. + fPending.fetch_add(+N, std::memory_order_relaxed); + for (int i = 0; i < N; i++) { + fExecutor.add([=] { + fn(i); + fPending.fetch_add(-1, std::memory_order_release); + }); } +} - static void Batch(int N, std::function fn, SkAtomic* pending) { - if (!gGlobal) { - for (int i = 0; i < N; i++) { fn(i); } - return; - } - gGlobal->batch(N, fn, pending); +void SkTaskGroup::wait() { + // Actively help the executor do work until our task group is done. + // This lets SkTaskGroups nest arbitrarily deep on a single SkExecutor: + // no thread ever blocks waiting for others to do its work. + // (We may end up doing work that's not part of our task group. That's fine.) + while (fPending.load(std::memory_order_acquire) > 0) { + fExecutor.borrow(); } - - static void Wait(SkAtomic* pending) { - if (!gGlobal) { // If we have no threads, the work must already be done. - SkASSERT(pending->load(sk_memory_order_relaxed) == 0); - return; - } - // Acquire pairs with decrement release here or in Loop. - while (pending->load(sk_memory_order_acquire) > 0) { - // Lend a hand until our SkTaskGroup of interest is done. - Work work; - { - // We're stealing work opportunistically, - // so we never call fWorkAvailable.wait(), which could sleep us if there's no work. - // This means fWorkAvailable is only an upper bound on fWork.count(). - AutoLock lock(&gGlobal->fWorkLock); - if (gGlobal->fWork.empty()) { - // Someone has picked up all the work (including ours). How nice of them! - // (They may still be working on it, so we can't assert *pending == 0 here.) - continue; - } - work = gGlobal->fWork.back(); - gGlobal->fWork.pop_back(); - } - // This Work isn't necessarily part of our SkTaskGroup of interest, but that's fine. - // We threads gotta stick together. We're always making forward progress. - work.fn(); - work.pending->fetch_add(-1, sk_memory_order_release); // Pairs with load above. - } - } - -private: - struct AutoLock { - AutoLock(SkSpinlock* lock) : fLock(lock) { fLock->acquire(); } - ~AutoLock() { fLock->release(); } - private: - SkSpinlock* fLock; - }; - - struct Work { - std::function fn; // A function to call - SkAtomic* pending; // then decrement pending afterwards. - }; - - explicit ThreadPool(int threads) { - if (threads == -1) { - threads = num_cores(); - } - for (int i = 0; i < threads; i++) { - fThreads.push(new SkThread(&ThreadPool::Loop, this)); - fThreads.top()->start(); - } - } - - ~ThreadPool() { - SkASSERT(fWork.empty()); // All SkTaskGroups should be destroyed by now. - - // Send a poison pill to each thread. - SkAtomic dummy(0); - for (int i = 0; i < fThreads.count(); i++) { - this->add(nullptr, &dummy); - } - // Wait for them all to swallow the pill and die. - for (int i = 0; i < fThreads.count(); i++) { - fThreads[i]->join(); - } - SkASSERT(fWork.empty()); // Can't hurt to double check. - fThreads.deleteAll(); - } - - void add(std::function fn, SkAtomic* pending) { - Work work = { fn, pending }; - pending->fetch_add(+1, sk_memory_order_relaxed); // No barrier needed. - { - AutoLock lock(&fWorkLock); - fWork.push_back(work); - } - fWorkAvailable.signal(1); - } - - void batch(int N, std::function fn, SkAtomic* pending) { - pending->fetch_add(+N, sk_memory_order_relaxed); // No barrier needed. - { - AutoLock lock(&fWorkLock); - for (int i = 0; i < N; i++) { - Work work = { [i, fn]() { fn(i); }, pending }; - fWork.push_back(work); - } - } - fWorkAvailable.signal(N); - } - - static void Loop(void* arg) { - ThreadPool* pool = (ThreadPool*)arg; - Work work; - while (true) { - // Sleep until there's work available, and claim one unit of Work as we wake. - pool->fWorkAvailable.wait(); - { - AutoLock lock(&pool->fWorkLock); - if (pool->fWork.empty()) { - // Someone in Wait() stole our work (fWorkAvailable is an upper bound). - // Well, that's fine, back to sleep for us. - continue; - } - work = pool->fWork.back(); - pool->fWork.pop_back(); - } - if (!work.fn) { - return; // Poison pill. Time... to die. - } - work.fn(); - work.pending->fetch_add(-1, sk_memory_order_release); // Pairs with load in Wait(). - } - } - - // fWorkLock must be held when reading or modifying fWork. - SkSpinlock fWorkLock; - SkTArray fWork; - - // A thread-safe upper bound for fWork.count(). - // - // We'd have it be an exact count but for the loop in Wait(): - // we never want that to block, so it can't call fWorkAvailable.wait(), - // and that's the only way to decrement fWorkAvailable. - // So fWorkAvailable may overcount actual the work available. - // We make do, but this means some worker threads may wake spuriously. - SkSemaphore fWorkAvailable; - - // These are only changed in a single-threaded context. - SkTDArray fThreads; - static ThreadPool* gGlobal; - - friend struct SkTaskGroup::Enabler; -}; -ThreadPool* ThreadPool::gGlobal = nullptr; - -} // namespace +} SkTaskGroup::Enabler::Enabler(int threads) { - SkASSERT(ThreadPool::gGlobal == nullptr); - if (threads != 0) { - ThreadPool::gGlobal = new ThreadPool(threads); + if (threads) { + fThreadPool = SkExecutor::MakeThreadPool(threads); + SkExecutor::SetDefault(fThreadPool.get()); } } - -SkTaskGroup::Enabler::~Enabler() { delete ThreadPool::gGlobal; } - -SkTaskGroup::SkTaskGroup() : fPending(0) {} - -void SkTaskGroup::wait() { ThreadPool::Wait(&fPending); } -void SkTaskGroup::add(std::function fn) { ThreadPool::Add(fn, &fPending); } -void SkTaskGroup::batch(int N, std::function fn) { - ThreadPool::Batch(N, fn, &fPending); -} diff --git a/gfx/skia/skia/src/core/SkTaskGroup.h b/gfx/skia/skia/src/core/SkTaskGroup.h index 0f793f31e255..ff291ea29e5b 100644 --- a/gfx/skia/skia/src/core/SkTaskGroup.h +++ b/gfx/skia/skia/src/core/SkTaskGroup.h @@ -8,24 +8,18 @@ #ifndef SkTaskGroup_DEFINED #define SkTaskGroup_DEFINED -#include - +#include "SkExecutor.h" #include "SkTypes.h" -#include "SkAtomics.h" -#include "SkTemplates.h" +#include +#include class SkTaskGroup : SkNoncopyable { public: - // Create one of these in main() to enable SkTaskGroups globally. - struct Enabler : SkNoncopyable { - explicit Enabler(int threads = -1); // Default is system-reported core count. - ~Enabler(); - }; - - SkTaskGroup(); + // Tasks added to this SkTaskGroup will run on its executor. + explicit SkTaskGroup(SkExecutor& executor = SkExecutor::GetDefault()); ~SkTaskGroup() { this->wait(); } - // Add a task to this SkTaskGroup. It will likely run on another thread. + // Add a task to this SkTaskGroup. void add(std::function fn); // Add a batch of N tasks, all calling fn with different arguments. @@ -35,8 +29,16 @@ public: // You may safely reuse this SkTaskGroup after wait() returns. void wait(); + // A convenience for testing tools. + // Creates and owns a thread pool, and passes it to SkExecutor::SetDefault(). + struct Enabler { + explicit Enabler(int threads = -1); // -1 -> num_cores, 0 -> noop + std::unique_ptr fThreadPool; + }; + private: - SkAtomic fPending; + std::atomic fPending; + SkExecutor& fExecutor; }; #endif//SkTaskGroup_DEFINED diff --git a/gfx/skia/skia/src/core/SkTextBlob.cpp b/gfx/skia/skia/src/core/SkTextBlob.cpp index ca75a2e0381d..6fc4bea2fb0f 100644 --- a/gfx/skia/skia/src/core/SkTextBlob.cpp +++ b/gfx/skia/skia/src/core/SkTextBlob.cpp @@ -11,6 +11,10 @@ #include "SkTypeface.h" #include "SkWriteBuffer.h" +#if SK_SUPPORT_GPU +#include "text/GrTextBlobCache.h" +#endif + namespace { // TODO(fmalita): replace with SkFont. @@ -56,8 +60,6 @@ public: private: const static uint32_t kFlagsMask = SkPaint::kAntiAlias_Flag | - SkPaint::kUnderlineText_Flag | - SkPaint::kStrikeThruText_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag | SkPaint::kSubpixelText_Flag | @@ -71,7 +73,7 @@ private: SkScalar fSize; SkScalar fScaleX; - // Keep this SkAutoTUnref off the first position, to avoid interfering with SkNoncopyable + // Keep this sk_sp off the first position, to avoid interfering with SkNoncopyable // empty baseclass optimization (http://code.google.com/p/skia/issues/detail?id=3694). sk_sp fTypeface; SkScalar fSkewX; @@ -134,10 +136,12 @@ public: : fFont(font) , fCount(count) , fOffset(offset) - , fPositioning(pos) - , fExtended(textSize > 0) { + , fFlags(pos) { + SkASSERT(static_cast(pos) <= Flags::kPositioning_Mask); + SkDEBUGCODE(fMagic = kRunRecordMagic); if (textSize > 0) { + fFlags |= kExtended_Flag; *this->textSizePtr() = textSize; } } @@ -155,7 +159,7 @@ public: } GlyphPositioning positioning() const { - return fPositioning; + return static_cast(fFlags & kPositioning_Mask); } uint16_t* glyphBuffer() const { @@ -170,16 +174,17 @@ public: SkAlign4(fCount * sizeof(uint16_t))); } - uint32_t textSize() const { return fExtended ? *this->textSizePtr() : 0; } + uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; } uint32_t* clusterBuffer() const { // clusters follow the textSize. - return fExtended ? 1 + this->textSizePtr() : nullptr; + return isExtended() ? 1 + this->textSizePtr() : nullptr; } char* textBuffer() const { - if (!fExtended) { return nullptr; } - return reinterpret_cast(this->clusterBuffer() + fCount); + return isExtended() + ? reinterpret_cast(this->clusterBuffer() + fCount) + : nullptr; } static size_t StorageSize(int glyphCount, int textSize, @@ -203,22 +208,21 @@ public: } static const RunRecord* Next(const RunRecord* run) { - return reinterpret_cast( - reinterpret_cast(run) - + StorageSize(run->glyphCount(), run->textSize(), run->positioning())); + return SkToBool(run->fFlags & kLast_Flag) ? nullptr : NextUnchecked(run); } void validate(const uint8_t* storageTop) const { SkASSERT(kRunRecordMagic == fMagic); - SkASSERT((uint8_t*)Next(this) <= storageTop); + SkASSERT((uint8_t*)NextUnchecked(this) <= storageTop); SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer()); - SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(fPositioning) <= (SkScalar*)Next(this)); - if (fExtended) { + SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(positioning()) + <= (SkScalar*)NextUnchecked(this)); + if (isExtended()) { SkASSERT(textSize() > 0); - SkASSERT(textSizePtr() < (uint32_t*)Next(this)); - SkASSERT(clusterBuffer() < (uint32_t*)Next(this)); - SkASSERT(textBuffer() + textSize() <= (char*)Next(this)); + SkASSERT(textSizePtr() < (uint32_t*)NextUnchecked(this)); + SkASSERT(clusterBuffer() < (uint32_t*)NextUnchecked(this)); + SkASSERT(textBuffer() + textSize() <= (char*)NextUnchecked(this)); } static_assert(sizeof(SkTextBlob::RunRecord) == sizeof(RunRecordStorageEquivalent), "runrecord_should_stay_packed"); @@ -227,6 +231,18 @@ public: private: friend class SkTextBlobBuilder; + enum Flags { + kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning + kLast_Flag = 0x04, // set for the last blob run + kExtended_Flag = 0x08, // set for runs with text/cluster info + }; + + static const RunRecord* NextUnchecked(const RunRecord* run) { + return reinterpret_cast( + reinterpret_cast(run) + + StorageSize(run->glyphCount(), run->textSize(), run->positioning())); + } + static size_t PosCount(int glyphCount, SkTextBlob::GlyphPositioning positioning) { return glyphCount * ScalarsPerGlyph(positioning); @@ -234,8 +250,8 @@ private: uint32_t* textSizePtr() const { // textSize follows the position buffer. - SkASSERT(fExtended); - return (uint32_t*)(&this->posBuffer()[PosCount(fCount, fPositioning)]); + SkASSERT(isExtended()); + return (uint32_t*)(&this->posBuffer()[PosCount(fCount, positioning())]); } void grow(uint32_t count) { @@ -244,18 +260,21 @@ private: fCount += count; // Move the initial pos scalars to their new location. - size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPositioning); - SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this)); + size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning()); + SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)NextUnchecked(this)); // memmove, as the buffers may overlap memmove(posBuffer(), initialPosBuffer, copySize); } + bool isExtended() const { + return fFlags & kExtended_Flag; + } + RunFont fFont; uint32_t fCount; SkPoint fOffset; - GlyphPositioning fPositioning; - bool fExtended; + uint32_t fFlags; SkDEBUGCODE(unsigned fMagic;) }; @@ -269,20 +288,25 @@ static int32_t next_id() { return id; } -SkTextBlob::SkTextBlob(int runCount, const SkRect& bounds) - : fRunCount(runCount) - , fBounds(bounds) - , fUniqueID(next_id()) { -} +SkTextBlob::SkTextBlob(const SkRect& bounds) + : fBounds(bounds) + , fUniqueID(next_id()) + , fAddedToCache(false) {} SkTextBlob::~SkTextBlob() { - const RunRecord* run = RunRecord::First(this); - for (int i = 0; i < fRunCount; ++i) { - const RunRecord* nextRun = RunRecord::Next(run); +#if SK_SUPPORT_GPU + if (fAddedToCache.load()) { + GrTextBlobCache::PostPurgeBlobMessage(fUniqueID); + } +#endif + + const auto* run = RunRecord::First(this); + do { + const auto* nextRun = RunRecord::Next(run); SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);) run->~RunRecord(); run = nextRun; - } + } while (run); } namespace { @@ -297,9 +321,6 @@ union PositioningAndExtended { } // namespace void SkTextBlob::flatten(SkWriteBuffer& buffer) const { - int runCount = fRunCount; - - buffer.write32(runCount); buffer.writeRect(fBounds); SkPaint runPaint; @@ -333,13 +354,15 @@ void SkTextBlob::flatten(SkWriteBuffer& buffer) const { } it.next(); - SkDEBUGCODE(runCount--); } - SkASSERT(0 == runCount); + + // Marker for the last run (0 is not a valid glyph count). + buffer.write32(0); } sk_sp SkTextBlob::MakeFromBuffer(SkReadBuffer& reader) { - int runCount = reader.read32(); + const int runCount = reader.isVersionLT(SkReadBuffer::kTextBlobImplicitRunCount_Version) + ? reader.read32() : std::numeric_limits::max(); if (runCount < 0) { return nullptr; } @@ -350,6 +373,11 @@ sk_sp SkTextBlob::MakeFromBuffer(SkReadBuffer& reader) { SkTextBlobBuilder blobBuilder; for (int i = 0; i < runCount; ++i) { int glyphCount = reader.read32(); + if (glyphCount == 0 && + !reader.isVersionLT(SkReadBuffer::kTextBlobImplicitRunCount_Version)) { + // End-of-runs marker. + break; + } PositioningAndExtended pe; pe.intValue = reader.read32(); @@ -405,13 +433,12 @@ unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) { } SkTextBlobRunIterator::SkTextBlobRunIterator(const SkTextBlob* blob) - : fCurrentRun(SkTextBlob::RunRecord::First(blob)) - , fRemainingRuns(blob->fRunCount) { + : fCurrentRun(SkTextBlob::RunRecord::First(blob)) { SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;) } bool SkTextBlobRunIterator::done() const { - return fRemainingRuns <= 0; + return !fCurrentRun; } void SkTextBlobRunIterator::next() { @@ -420,7 +447,6 @@ void SkTextBlobRunIterator::next() { if (!this->done()) { SkDEBUGCODE(fCurrentRun->validate(fStorageTop);) fCurrentRun = SkTextBlob::RunRecord::Next(fCurrentRun); - fRemainingRuns--; } } @@ -744,29 +770,36 @@ const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPos(const SkP } sk_sp SkTextBlobBuilder::make() { - SkASSERT((fRunCount > 0) == (nullptr != fStorage.get())); + if (!fRunCount) { + // We don't instantiate empty blobs. + SkASSERT(!fStorage.get()); + SkASSERT(fStorageUsed == 0); + SkASSERT(fStorageSize == 0); + SkASSERT(fLastRun == 0); + SkASSERT(fBounds.isEmpty()); + return nullptr; + } this->updateDeferredBounds(); - if (0 == fRunCount) { - SkASSERT(nullptr == fStorage.get()); - fStorageUsed = sizeof(SkTextBlob); - fStorage.realloc(fStorageUsed); - } + // Tag the last run as such. + auto* lastRun = reinterpret_cast(fStorage.get() + fLastRun); + lastRun->fFlags |= SkTextBlob::RunRecord::kLast_Flag; - SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fRunCount, fBounds); + SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fBounds); SkDEBUGCODE(const_cast(blob)->fStorageSize = fStorageSize;) SkDEBUGCODE( size_t validateSize = sizeof(SkTextBlob); - const SkTextBlob::RunRecord* run = SkTextBlob::RunRecord::First(blob); - for (int i = 0; i < fRunCount; ++i) { + for (const auto* run = SkTextBlob::RunRecord::First(blob); run; + run = SkTextBlob::RunRecord::Next(run)) { validateSize += SkTextBlob::RunRecord::StorageSize( - run->fCount, run->textSize(), run->fPositioning); + run->fCount, run->textSize(), run->positioning()); run->validate(reinterpret_cast(blob) + fStorageUsed); - run = SkTextBlob::RunRecord::Next(run); + fRunCount--; } SkASSERT(validateSize == fStorageUsed); + SkASSERT(fRunCount == 0); ) fStorageUsed = 0; diff --git a/gfx/skia/skia/src/core/SkTextBlobRunIterator.h b/gfx/skia/skia/src/core/SkTextBlobRunIterator.h index 2f1477bf06f7..18f41d7dcb6b 100644 --- a/gfx/skia/skia/src/core/SkTextBlobRunIterator.h +++ b/gfx/skia/skia/src/core/SkTextBlobRunIterator.h @@ -36,7 +36,6 @@ public: private: const SkTextBlob::RunRecord* fCurrentRun; - int fRemainingRuns; SkDEBUGCODE(uint8_t* fStorageTop;) }; diff --git a/gfx/skia/skia/src/core/SkTextMapStateProc.h b/gfx/skia/skia/src/core/SkTextMapStateProc.h index 944050917cfa..81ef5dee5026 100644 --- a/gfx/skia/skia/src/core/SkTextMapStateProc.h +++ b/gfx/skia/skia/src/core/SkTextMapStateProc.h @@ -26,8 +26,8 @@ public: } else { // Bake the matrix scale/translation components into fOffset, // to expedite proc computations. - fOffset.set(SkScalarMul(offset.x(), fMatrix.getScaleX()) + fMatrix.getTranslateX(), - SkScalarMul(offset.y(), fMatrix.getScaleY()) + fMatrix.getTranslateY()); + fOffset.set(offset.x() * fMatrix.getScaleX() + fMatrix.getTranslateX(), + offset.y() * fMatrix.getScaleY() + fMatrix.getTranslateY()); if (mtype & SkMatrix::kScale_Mask) { fMapCase = kOnlyScaleX; @@ -61,7 +61,7 @@ inline void SkTextMapStateProc::operator()(const SkScalar pos[], SkPoint* loc) c fProc(fMatrix, pos[0] + fOffset.x(), pos[1] + fOffset.y(), loc); break; case kOnlyScaleX: - loc->set(SkScalarMul(fScaleX, *pos) + fOffset.x(), fOffset.y()); + loc->set(fScaleX * *pos + fOffset.x(), fOffset.y()); break; case kOnlyTransX: loc->set(*pos + fOffset.x(), fOffset.y()); diff --git a/gfx/skia/skia/src/core/SkTextToPathIter.h b/gfx/skia/skia/src/core/SkTextToPathIter.h index dcd5a01cd3ca..6de12a84cefa 100644 --- a/gfx/skia/skia/src/core/SkTextToPathIter.h +++ b/gfx/skia/skia/src/core/SkTextToPathIter.h @@ -75,7 +75,7 @@ public: && fPaint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first const char* text = fText; const SkGlyph& glyph = fGlyphCacheProc(fCache, &text); - SkScalar width = SkScalarMul(SkFloatToScalar((&glyph.fAdvanceX)[0]), fScale); + SkScalar width = (&glyph.fAdvanceX)[0] * fScale; if (fPaint.getTextAlign() == SkPaint::kCenter_Align) { width = SkScalarHalf(width); } diff --git a/gfx/skia/skia/src/core/SkThreadedBMPDevice.cpp b/gfx/skia/skia/src/core/SkThreadedBMPDevice.cpp new file mode 100644 index 000000000000..1cf7fe449a46 --- /dev/null +++ b/gfx/skia/skia/src/core/SkThreadedBMPDevice.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkThreadedBMPDevice.h" + +#include "SkPath.h" +#include "SkTaskGroup.h" +#include "SkVertices.h" + +SkThreadedBMPDevice::SkThreadedBMPDevice(const SkBitmap& bitmap, int threads) + : INHERITED(bitmap) + , fThreadCnt(threads) +{ + // Tiling using stripes for now; we'll explore better tiling in the future. + int h = (bitmap.height() + fThreadCnt - 1) / SkTMax(fThreadCnt, 1); + int w = bitmap.width(); + int top = 0; + for(int tid = 0; tid < fThreadCnt; ++tid, top += h) { + fThreadBounds.push_back(SkIRect::MakeLTRB(0, top, w, top + h)); + } +} + +void SkThreadedBMPDevice::flush() { + SkTaskGroup().batch(fThreadCnt, [this](int i) { + for(auto& element : fQueue) { + if (SkIRect::Intersects(fThreadBounds[i], element.fDrawBounds)) { + element.fDrawFn(fThreadBounds[i]); + } + } + }); + fQueue.reset(); +} + +// Having this captured in lambda seems to be faster than saving this in DrawElement +struct SkThreadedBMPDevice::DrawState { + SkPixmap fDst; + SkMatrix fMatrix; + SkRasterClip fRC; + + explicit DrawState(SkThreadedBMPDevice* dev) { + // we need fDst to be set, and if we're actually drawing, to dirty the genID + if (!dev->accessPixels(&fDst)) { + // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels + fDst.reset(dev->imageInfo(), nullptr, 0); + } + fMatrix = dev->ctm(); + fRC = dev->fRCStack.rc(); + } + + SkDraw getThreadDraw(SkRasterClip& threadRC, const SkIRect& threadBounds) const { + SkDraw draw; + draw.fDst = fDst; + draw.fMatrix = &fMatrix; + threadRC = fRC; + threadRC.op(threadBounds, SkRegion::kIntersect_Op); + draw.fRC = &threadRC; + return draw; + } +}; + +SkIRect SkThreadedBMPDevice::transformDrawBounds(const SkRect& drawBounds) const { + if (drawBounds.isLargest()) { + return SkIRect::MakeLargest(); + } + SkRect transformedBounds; + this->ctm().mapRect(&transformedBounds, drawBounds); + return transformedBounds.roundOut(); +} + +// The do {...} while (false) is to enforce trailing semicolon as suggested by mtklein@ +#define THREADED_DRAW(drawBounds, actualDrawCall) \ + do { \ + DrawState ds(this); \ + fQueue.push_back({ \ + this->transformDrawBounds(drawBounds), \ + [=](const SkIRect& threadBounds) { \ + SkRasterClip threadRC; \ + SkDraw draw = ds.getThreadDraw(threadRC, threadBounds); \ + draw.actualDrawCall; \ + }, \ + }); \ + } while (false) + +static inline SkRect get_fast_bounds(const SkRect& r, const SkPaint& p) { + SkRect result; + if (p.canComputeFastBounds()) { + result = p.computeFastBounds(r, &result); + } else { + result = SkRect::MakeLargest(); + } + return result; +} + +void SkThreadedBMPDevice::drawPaint(const SkPaint& paint) { + THREADED_DRAW(SkRect::MakeLargest(), drawPaint(paint)); +} + +void SkThreadedBMPDevice::drawPoints(SkCanvas::PointMode mode, size_t count, + const SkPoint pts[], const SkPaint& paint) { + // TODO tighter drawBounds + SkRect drawBounds = SkRect::MakeLargest(); + THREADED_DRAW(drawBounds, drawPoints(mode, count, pts, paint, nullptr)); +} + +void SkThreadedBMPDevice::drawRect(const SkRect& r, const SkPaint& paint) { + SkRect drawBounds = get_fast_bounds(r, paint); + THREADED_DRAW(drawBounds, drawRect(r, paint)); +} + +void SkThreadedBMPDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) { +#ifdef SK_IGNORE_BLURRED_RRECT_OPT + SkPath path; + + path.addRRect(rrect); + // call the VIRTUAL version, so any subclasses who do handle drawPath aren't + // required to override drawRRect. + this->drawPath(path, paint, nullptr, false); +#else + SkRect drawBounds = get_fast_bounds(rrect.getBounds(), paint); + THREADED_DRAW(drawBounds, drawRRect(rrect, paint)); +#endif +} + +void SkThreadedBMPDevice::drawPath(const SkPath& path, const SkPaint& paint, + const SkMatrix* prePathMatrix, bool pathIsMutable) { + SkRect drawBounds = path.isInverseFillType() ? SkRect::MakeLargest() + : get_fast_bounds(path.getBounds(), paint); + // For thread safety, make path imutable + THREADED_DRAW(drawBounds, drawPath(path, paint, prePathMatrix, false)); +} + +void SkThreadedBMPDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, + const SkPaint& paint) { + LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality()); + SkRect drawBounds = SkRect::MakeWH(bitmap.width(), bitmap.height()); + matrix.mapRect(&drawBounds); + THREADED_DRAW(drawBounds, drawBitmap(bitmap, matrix, nullptr, paint)); +} + +void SkThreadedBMPDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) { + SkRect drawBounds = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); + THREADED_DRAW(drawBounds, drawSprite(bitmap, x, y, paint)); +} + +void SkThreadedBMPDevice::drawText(const void* text, size_t len, SkScalar x, SkScalar y, + const SkPaint& paint) { + SkRect drawBounds = SkRect::MakeLargest(); // TODO tighter drawBounds + THREADED_DRAW(drawBounds, drawText((const char*)text, len, x, y, paint, &this->surfaceProps())); +} + +void SkThreadedBMPDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[], + int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { + SkRect drawBounds = SkRect::MakeLargest(); // TODO tighter drawBounds + THREADED_DRAW(drawBounds, drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, + paint, &surfaceProps())); +} + +void SkThreadedBMPDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode, + const SkPaint& paint) { + SkRect drawBounds = SkRect::MakeLargest(); // TODO tighter drawBounds + THREADED_DRAW(drawBounds, drawVertices(vertices->mode(), vertices->vertexCount(), + vertices->positions(), vertices->texCoords(), + vertices->colors(), bmode, vertices->indices(), + vertices->indexCount(), paint)); +} + +void SkThreadedBMPDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) { + SkASSERT(!paint.getImageFilter()); + SkRect drawBounds = SkRect::MakeXYWH(x, y, device->width(), device->height()); + THREADED_DRAW(drawBounds, + drawSprite(static_cast(device)->fBitmap, x, y, paint)); +} diff --git a/gfx/skia/skia/src/core/SkThreadedBMPDevice.h b/gfx/skia/skia/src/core/SkThreadedBMPDevice.h new file mode 100644 index 000000000000..ea69f7a8588d --- /dev/null +++ b/gfx/skia/skia/src/core/SkThreadedBMPDevice.h @@ -0,0 +1,57 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkThreadedBMPDevice_DEFINED +#define SkThreadedBMPDevice_DEFINED + +#include "SkDraw.h" +#include "SkBitmapDevice.h" + +/////////////////////////////////////////////////////////////////////////////// +class SkThreadedBMPDevice : public SkBitmapDevice { +public: + SkThreadedBMPDevice(const SkBitmap& bitmap, int threads); + +protected: + void drawPaint(const SkPaint& paint) override; + void drawPoints(SkCanvas::PointMode mode, size_t count, + const SkPoint[], const SkPaint& paint) override; + void drawRect(const SkRect& r, const SkPaint& paint) override; + void drawRRect(const SkRRect& rr, const SkPaint& paint) override; + + void drawPath(const SkPath&, const SkPaint&, const SkMatrix* prePathMatrix, + bool pathIsMutable) override; + void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override; + void drawSprite(const SkBitmap&, int x, int y, const SkPaint&) override; + + void drawText(const void* text, size_t len, SkScalar x, SkScalar y, + const SkPaint&) override; + void drawPosText(const void* text, size_t len, const SkScalar pos[], + int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override; + void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override; + void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; + + void flush() override; + +private: + struct DrawElement { + SkIRect fDrawBounds; + std::function fDrawFn; + }; + + struct DrawState; + + SkIRect transformDrawBounds(const SkRect& drawBounds) const; + + const int fThreadCnt; + SkTArray fThreadBounds; + SkTArray fQueue; + + typedef SkBitmapDevice INHERITED; +}; + +#endif // SkThreadedBMPDevice_DEFINED diff --git a/gfx/skia/skia/src/core/SkTime.cpp b/gfx/skia/skia/src/core/SkTime.cpp index a496a22b5420..ae88178cb720 100644 --- a/gfx/skia/skia/src/core/SkTime.cpp +++ b/gfx/skia/skia/src/core/SkTime.cpp @@ -49,16 +49,16 @@ void SkTime::GetDateTime(DateTime* dt) { if (dt) { time_t m_time; time(&m_time); - struct tm* tstruct; - tstruct = gmtime(&m_time); + struct tm tstruct; + gmtime_r(&m_time, &tstruct); dt->fTimeZoneMinutes = 0; - dt->fYear = tstruct->tm_year + 1900; - dt->fMonth = SkToU8(tstruct->tm_mon + 1); - dt->fDayOfWeek = SkToU8(tstruct->tm_wday); - dt->fDay = SkToU8(tstruct->tm_mday); - dt->fHour = SkToU8(tstruct->tm_hour); - dt->fMinute = SkToU8(tstruct->tm_min); - dt->fSecond = SkToU8(tstruct->tm_sec); + dt->fYear = tstruct.tm_year + 1900; + dt->fMonth = SkToU8(tstruct.tm_mon + 1); + dt->fDayOfWeek = SkToU8(tstruct.tm_wday); + dt->fDay = SkToU8(tstruct.tm_mday); + dt->fHour = SkToU8(tstruct.tm_hour); + dt->fMinute = SkToU8(tstruct.tm_min); + dt->fSecond = SkToU8(tstruct.tm_sec); } } #endif // SK_BUILD_FOR_WIN32 diff --git a/gfx/skia/skia/src/core/SkTraceEventCommon.h b/gfx/skia/skia/src/core/SkTraceEventCommon.h index 57f67775e805..d066d903c2c2 100644 --- a/gfx/skia/skia/src/core/SkTraceEventCommon.h +++ b/gfx/skia/skia/src/core/SkTraceEventCommon.h @@ -1,6 +1,8 @@ // Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef SkTraceEventCommon_DEFINED +#define SkTraceEventCommon_DEFINED // This header file defines the set of trace_event macros without specifying // how the events actually get collected and stored. If you need to expose trace @@ -1037,3 +1039,4 @@ #define TRACE_EVENT_SCOPE_NAME_GLOBAL ('g') #define TRACE_EVENT_SCOPE_NAME_PROCESS ('p') #define TRACE_EVENT_SCOPE_NAME_THREAD ('t') +#endif // SkTraceEventCommon_DEFINED diff --git a/gfx/skia/skia/src/core/SkTypeface.cpp b/gfx/skia/skia/src/core/SkTypeface.cpp index 8747c6e54aff..2d8f920ba988 100644 --- a/gfx/skia/skia/src/core/SkTypeface.cpp +++ b/gfx/skia/skia/src/core/SkTypeface.cpp @@ -73,6 +73,11 @@ protected: SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override { return new EmptyLocalizedStrings; } + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override + { + return 0; + } int onGetTableTags(SkFontTableTag tags[]) const override { return 0; } size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; @@ -87,7 +92,7 @@ SkTypeface* SkTypeface::GetDefaultTypeface(Style style) { SkASSERT((int)style < 4); once[style]([style] { - SkAutoTUnref fm(SkFontMgr::RefDefault()); + sk_sp fm(SkFontMgr::RefDefault()); SkTypeface* t = fm->legacyCreateTypeface(nullptr, SkFontStyle::FromOldStyle(style)); defaults[style] = t ? t : SkEmptyTypeface::Create(); }); @@ -129,7 +134,7 @@ sk_sp SkTypeface::MakeFromName(const char name[], (fontStyle.weight() == SkFontStyle::kBold_Weight ? SkTypeface::kBold : SkTypeface::kNormal))); } - SkAutoTUnref fm(SkFontMgr::RefDefault()); + sk_sp fm(SkFontMgr::RefDefault()); return sk_sp(fm->legacyCreateTypeface(name, fontStyle)); } @@ -142,22 +147,22 @@ sk_sp SkTypeface::MakeFromTypeface(SkTypeface* family, Style s) { return sk_ref_sp(family); } - SkAutoTUnref fm(SkFontMgr::RefDefault()); + sk_sp fm(SkFontMgr::RefDefault()); return sk_sp(fm->matchFaceStyle(family, SkFontStyle::FromOldStyle(s))); } sk_sp SkTypeface::MakeFromStream(SkStreamAsset* stream, int index) { - SkAutoTUnref fm(SkFontMgr::RefDefault()); + sk_sp fm(SkFontMgr::RefDefault()); return sk_sp(fm->createFromStream(stream, index)); } sk_sp SkTypeface::MakeFromFontData(std::unique_ptr data) { - SkAutoTUnref fm(SkFontMgr::RefDefault()); + sk_sp fm(SkFontMgr::RefDefault()); return sk_sp(fm->createFromFontData(std::move(data))); } sk_sp SkTypeface::MakeFromFile(const char path[], int index) { - SkAutoTUnref fm(SkFontMgr::RefDefault()); + sk_sp fm(SkFontMgr::RefDefault()); return sk_sp(fm->createFromFile(path, index)); } @@ -202,6 +207,12 @@ sk_sp SkTypeface::MakeDeserialize(SkStream* stream) { /////////////////////////////////////////////////////////////////////////////// +int SkTypeface::getVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const +{ + return this->onGetVariationDesignPosition(coordinates, coordinateCount); +} + int SkTypeface::countTables() const { return this->onGetTableTags(nullptr); } @@ -346,13 +357,14 @@ bool SkTypeface::onComputeBounds(SkRect* bounds) const { desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); SkScalerContextEffects noeffects; - SkAutoTDelete ctx(this->createScalerContext(noeffects, desc, true)); - if (ctx.get()) { - SkPaint::FontMetrics fm; - ctx->getFontMetrics(&fm); - bounds->set(fm.fXMin * invTextSize, fm.fTop * invTextSize, - fm.fXMax * invTextSize, fm.fBottom * invTextSize); - return true; + std::unique_ptr ctx = this->createScalerContext(noeffects, desc, true); + if (!ctx) { + return false; } - return false; + + SkPaint::FontMetrics fm; + ctx->getFontMetrics(&fm); + bounds->set(fm.fXMin * invTextSize, fm.fTop * invTextSize, + fm.fXMax * invTextSize, fm.fBottom * invTextSize); + return true; } diff --git a/gfx/skia/skia/src/core/SkUnPreMultiplyPriv.h b/gfx/skia/skia/src/core/SkUnPreMultiplyPriv.h new file mode 100644 index 000000000000..073e239ed7d5 --- /dev/null +++ b/gfx/skia/skia/src/core/SkUnPreMultiplyPriv.h @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkUnPreMultiplyPriv_DEFINED +#define SkUnPreMultiplyPriv_DEFINED + +#include "SkColor.h" + +template +void SkUnpremultiplyRow(uint32_t* dst, const uint32_t* src, int count) { + const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); + + for (int i = 0; i < count; i++) { + uint32_t c = *src++; + uint8_t r, g, b, a; + if (kSwapRB) { + r = (c >> 16) & 0xFF; + g = (c >> 8) & 0xFF; + b = (c >> 0) & 0xFF; + a = (c >> 24) & 0xFF; + } else { + r = (c >> 0) & 0xFF; + g = (c >> 8) & 0xFF; + b = (c >> 16) & 0xFF; + a = (c >> 24) & 0xFF; + } + + if (0 != a && 255 != a) { + SkUnPreMultiply::Scale scale = table[a]; + r = SkUnPreMultiply::ApplyScale(scale, r); + g = SkUnPreMultiply::ApplyScale(scale, g); + b = SkUnPreMultiply::ApplyScale(scale, b); + } + + *dst++ = (r << 0) | (g << 8) | (b << 16) | (a << 24); + } +} + +#endif diff --git a/gfx/skia/skia/src/core/SkUtils.cpp b/gfx/skia/skia/src/core/SkUtils.cpp index 635d1b173647..311394d70c44 100644 --- a/gfx/skia/skia/src/core/SkUtils.cpp +++ b/gfx/skia/skia/src/core/SkUtils.cpp @@ -8,6 +8,22 @@ #include "SkUtils.h" +void sk_memset16(uint16_t buffer[], uint16_t value, int count) { + for (int i = 0; i < count; i++) { + buffer[i] = value; + } +} +void sk_memset32(uint32_t buffer[], uint32_t value, int count) { + for (int i = 0; i < count; i++) { + buffer[i] = value; + } +} +void sk_memset64(uint64_t buffer[], uint64_t value, int count) { + for (int i = 0; i < count; i++) { + buffer[i] = value; + } +} + /* 0xxxxxxx 1 total 10xxxxxx // never a leading byte 110xxxxx 2 total @@ -19,10 +35,19 @@ 0xE5 << 24 */ +static bool utf8_byte_is_valid(uint8_t c) { + return c < 0xF5 && (c & 0xFE) != 0xC0; +} +static bool utf8_byte_is_continuation(uint8_t c) { + return (c & 0xC0) == 0x80; +} +static bool utf8_byte_is_leading_byte(uint8_t c) { + return utf8_byte_is_valid(c) && !utf8_byte_is_continuation(c); +} + #ifdef SK_DEBUG static void assert_utf8_leadingbyte(unsigned c) { - SkASSERT(c <= 0xF7); // otherwise leading byte is too big (more than 4 bytes) - SkASSERT((c & 0xC0) != 0x80); // can't begin with a middle char + SkASSERT(utf8_byte_is_leading_byte(SkToU8(c))); } int SkUTF8_LeadByteToCount(unsigned c) { @@ -33,6 +58,29 @@ #define assert_utf8_leadingbyte(c) #endif +/** + * @returns -1 iff invalid UTF8 byte, + * 0 iff UTF8 continuation byte, + * 1 iff ASCII byte, + * 2 iff leading byte of 2-byte sequence, + * 3 iff leading byte of 3-byte sequence, and + * 4 iff leading byte of 4-byte sequence. + * + * I.e.: if return value > 0, then gives length of sequence. +*/ +static int utf8_byte_type(uint8_t c) { + if (c < 0x80) { + return 1; + } else if (c < 0xC0) { + return 0; + } else if (c < 0xF5 && (c & 0xFE) != 0xC0) { // "octet values C0, C1, F5 to FF never appear" + return (((0xE5 << 24) >> ((unsigned)c >> 4 << 1)) & 3) + 1; + } else { + return -1; + } +} +static bool utf8_type_is_valid_leading_byte(int type) { return type > 0; } + int SkUTF8_CountUnichars(const char utf8[]) { SkASSERT(utf8); @@ -49,15 +97,28 @@ int SkUTF8_CountUnichars(const char utf8[]) { return count; } -int SkUTF8_CountUnichars(const char utf8[], size_t byteLength) { +// SAFE: returns -1 if invalid UTF-8 +int SkUTF8_CountUnicharsWithError(const char utf8[], size_t byteLength) { SkASSERT(utf8 || 0 == byteLength); int count = 0; const char* stop = utf8 + byteLength; while (utf8 < stop) { - utf8 += SkUTF8_LeadByteToCount(*(const uint8_t*)utf8); - count += 1; + int type = utf8_byte_type(*(const uint8_t*)utf8); + SkASSERT(type >= -1 && type <= 4); + if (!utf8_type_is_valid_leading_byte(type) || + utf8 + type > stop) { // Sequence extends beyond end. + return -1; + } + while(type-- > 1) { + ++utf8; + if (!utf8_byte_is_continuation(*(const uint8_t*)utf8)) { + return -1; + } + } + ++utf8; + ++count; } return count; } @@ -83,6 +144,39 @@ SkUnichar SkUTF8_ToUnichar(const char utf8[]) { return c; } +// SAFE: returns -1 on invalid UTF-8 sequence. +SkUnichar SkUTF8_NextUnicharWithError(const char** ptr, const char* end) { + SkASSERT(ptr && *ptr); + SkASSERT(*ptr < end); + const uint8_t* p = (const uint8_t*)*ptr; + int c = *p; + int hic = c << 24; + + if (!utf8_byte_is_leading_byte(c)) { + return -1; + } + if (hic < 0) { + uint32_t mask = (uint32_t)~0x3F; + hic = SkLeftShift(hic, 1); + do { + ++p; + if (p >= (const uint8_t*)end) { + return -1; + } + // check before reading off end of array. + uint8_t nextByte = *p; + if (!utf8_byte_is_continuation(nextByte)) { + return -1; + } + c = (c << 6) | (nextByte & 0x3F); + mask <<= 5; + } while ((hic = SkLeftShift(hic, 1)) < 0); + c &= ~mask; + } + *ptr = (char*)p + 1; + return c; +} + SkUnichar SkUTF8_NextUnichar(const char** ptr) { SkASSERT(ptr && *ptr); diff --git a/gfx/skia/skia/src/core/SkUtils.h b/gfx/skia/skia/src/core/SkUtils.h index 26f19e690631..241a61ad2fd2 100644 --- a/gfx/skia/skia/src/core/SkUtils.h +++ b/gfx/skia/skia/src/core/SkUtils.h @@ -9,39 +9,16 @@ #define SkUtils_DEFINED #include "SkTypes.h" +#include "SkMath.h" -/** Similar to memset(), but it assigns a 16bit value into the buffer. +/** Similar to memset(), but it assigns a 16, 32, or 64-bit value into the buffer. @param buffer The memory to have value copied into it - @param value The 16bit value to be copied into buffer + @param value The value to be copied into buffer @param count The number of times value should be copied into the buffer. */ -static inline void sk_memset16(uint16_t buffer[], uint16_t value, int count) { - for (int i = 0; i < count; i++) { - buffer[i] = value; - } -} - -/** Similar to memset(), but it assigns a 32bit value into the buffer. - @param buffer The memory to have value copied into it - @param value The 32bit value to be copied into buffer - @param count The number of times value should be copied into the buffer. -*/ -static inline void sk_memset32(uint32_t buffer[], uint32_t value, int count) { - for (int i = 0; i < count; i++) { - buffer[i] = value; - } -} - -/** Similar to memset(), but it assigns a 64bit value into the buffer. - @param buffer The memory to have value copied into it - @param value The 64bit value to be copied into buffer - @param count The number of times value should be copied into the buffer. -*/ -static inline void sk_memset64(uint64_t buffer[], uint64_t value, int count) { - for (int i = 0; i < count; i++) { - buffer[i] = value; - } -} +void sk_memset16(uint16_t buffer[], uint16_t value, int count); +void sk_memset32(uint32_t buffer[], uint32_t value, int count); +void sk_memset64(uint64_t buffer[], uint64_t value, int count); /////////////////////////////////////////////////////////////////////////////// #define kMaxBytesInUTF8Sequence 4 @@ -58,7 +35,31 @@ inline int SkUTF8_CountUTF8Bytes(const char utf8[]) { } int SkUTF8_CountUnichars(const char utf8[]); -int SkUTF8_CountUnichars(const char utf8[], size_t byteLength); + +/** This function is safe: invalid UTF8 sequences will return -1; */ +int SkUTF8_CountUnicharsWithError(const char utf8[], size_t byteLength); + +/** This function is safe: invalid UTF8 sequences will return 0; */ +inline int SkUTF8_CountUnichars(const char utf8[], size_t byteLength) { + return SkClampPos(SkUTF8_CountUnicharsWithError(utf8, byteLength)); +} + +/** This function is safe: invalid UTF8 sequences will return -1 + * When -1 is returned, ptr is unchanged. + * Precondition: *ptr < end; + */ +SkUnichar SkUTF8_NextUnicharWithError(const char** ptr, const char* end); + +/** this version replaces invalid utf-8 sequences with code point U+FFFD. */ +inline SkUnichar SkUTF8_NextUnichar(const char** ptr, const char* end) { + SkUnichar val = SkUTF8_NextUnicharWithError(ptr, end); + if (val < 0) { + *ptr = end; + return 0xFFFD; // REPLACEMENT CHARACTER + } + return val; +} + SkUnichar SkUTF8_ToUnichar(const char utf8[]); SkUnichar SkUTF8_NextUnichar(const char**); SkUnichar SkUTF8_PrevUnichar(const char**); @@ -99,5 +100,4 @@ inline bool SkUnichar_IsVariationSelector(SkUnichar uni) { } return true; } - #endif diff --git a/gfx/skia/skia/src/core/SkUtilsArm.h b/gfx/skia/skia/src/core/SkUtilsArm.h index 7cb34e2ee91d..0d35193e0407 100644 --- a/gfx/skia/skia/src/core/SkUtilsArm.h +++ b/gfx/skia/skia/src/core/SkUtilsArm.h @@ -8,11 +8,9 @@ #ifndef SkUtilsArm_DEFINED #define SkUtilsArm_DEFINED -#include "SkCpu.h" +#include "SkTypes.h" -#if defined(SK_ARM_HAS_OPTIONAL_NEON) - #define SK_ARM_NEON_WRAP(x) (SkCpu::Supports(SkCpu::NEON) ? x ## _neon : x) -#elif defined(SK_ARM_HAS_NEON) +#if defined(SK_ARM_HAS_NEON) #define SK_ARM_NEON_WRAP(x) (x ## _neon) #else #define SK_ARM_NEON_WRAP(x) (x) diff --git a/gfx/skia/skia/src/core/SkValidatingReadBuffer.cpp b/gfx/skia/skia/src/core/SkValidatingReadBuffer.cpp index e1b84d597fa7..71dbc459ff54 100644 --- a/gfx/skia/skia/src/core/SkValidatingReadBuffer.cpp +++ b/gfx/skia/skia/src/core/SkValidatingReadBuffer.cpp @@ -6,7 +6,6 @@ */ #include "SkBitmap.h" -#include "SkErrorInternals.h" #include "SkValidatingReadBuffer.h" #include "SkStream.h" #include "SkTypeface.h" @@ -42,6 +41,7 @@ void SkValidatingReadBuffer::setMemory(const void* data, size_t size) { const void* SkValidatingReadBuffer::skip(size_t size) { size_t inc = SkAlign4(size); + this->validate(inc >= size); const void* addr = fReader.peek(); this->validate(IsPtrAlign4(addr) && fReader.isAvailable(inc)); if (fError) { @@ -199,27 +199,27 @@ bool SkValidatingReadBuffer::readArray(void* value, size_t size, size_t elementS } bool SkValidatingReadBuffer::readByteArray(void* value, size_t size) { - return readArray(static_cast(value), size, sizeof(unsigned char)); + return this->readArray(static_cast(value), size, sizeof(unsigned char)); } bool SkValidatingReadBuffer::readColorArray(SkColor* colors, size_t size) { - return readArray(colors, size, sizeof(SkColor)); + return this->readArray(colors, size, sizeof(SkColor)); } bool SkValidatingReadBuffer::readColor4fArray(SkColor4f* colors, size_t size) { - return readArray(colors, size, sizeof(SkColor4f)); + return this->readArray(colors, size, sizeof(SkColor4f)); } bool SkValidatingReadBuffer::readIntArray(int32_t* values, size_t size) { - return readArray(values, size, sizeof(int32_t)); + return this->readArray(values, size, sizeof(int32_t)); } bool SkValidatingReadBuffer::readPointArray(SkPoint* points, size_t size) { - return readArray(points, size, sizeof(SkPoint)); + return this->readArray(points, size, sizeof(SkPoint)); } bool SkValidatingReadBuffer::readScalarArray(SkScalar* values, size_t size) { - return readArray(values, size, sizeof(SkScalar)); + return this->readArray(values, size, sizeof(SkScalar)); } uint32_t SkValidatingReadBuffer::getArrayCount() { @@ -254,7 +254,7 @@ SkFlattenable* SkValidatingReadBuffer::readFlattenable(SkFlattenable::Type type) } else { // Read the index. We are guaranteed that the first byte // is zeroed, so we must shift down a byte. - uint32_t index = fReader.readU32() >> 8; + uint32_t index = this->readUInt() >> 8; if (0 == index) { return nullptr; // writer failed to give us the flattenable } diff --git a/gfx/skia/skia/src/core/SkValidationUtils.h b/gfx/skia/skia/src/core/SkValidationUtils.h index e9e59866ca99..5e2b91d4d344 100644 --- a/gfx/skia/skia/src/core/SkValidationUtils.h +++ b/gfx/skia/skia/src/core/SkValidationUtils.h @@ -9,7 +9,8 @@ #define SkValidationUtils_DEFINED #include "SkBitmap.h" -#include "SkXfermode.h" +#include "SkBlendMode.h" +#include "SkXfermodePriv.h" /** Returns true if coeff's value is in the SkXfermode::Coeff enum. */ @@ -17,10 +18,10 @@ static inline bool SkIsValidCoeff(SkXfermode::Coeff coeff) { return coeff >= 0 && coeff < SkXfermode::kCoeffCount; } -/** Returns true if mode's value is in the SkXfermode::Mode enum. +/** Returns true if mode's value is in the SkBlendMode enum. */ -static inline bool SkIsValidMode(SkXfermode::Mode mode) { - return (mode >= 0) && (mode <= SkXfermode::kLastMode); +static inline bool SkIsValidMode(SkBlendMode mode) { + return (unsigned)mode <= (unsigned)SkBlendMode::kLastMode; } /** Returns true if the rect's dimensions are between 0 and SK_MaxS32 diff --git a/gfx/skia/skia/src/core/SkVarAlloc.cpp b/gfx/skia/skia/src/core/SkVarAlloc.cpp index ea0524b67f24..cfa1188c6271 100644 --- a/gfx/skia/skia/src/core/SkVarAlloc.cpp +++ b/gfx/skia/skia/src/core/SkVarAlloc.cpp @@ -7,6 +7,8 @@ #include "SkVarAlloc.h" +#include "SkMalloc.h" + struct SkVarAlloc::Block { Block* prev; char* data() { return (char*)(this + 1); } diff --git a/gfx/skia/skia/src/core/SkVertState.cpp b/gfx/skia/skia/src/core/SkVertState.cpp index 7c3047ec407d..ef3604d7367e 100644 --- a/gfx/skia/skia/src/core/SkVertState.cpp +++ b/gfx/skia/skia/src/core/SkVertState.cpp @@ -92,13 +92,13 @@ bool VertState::TriangleFanX(VertState* state) { return true; } -VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) { +VertState::Proc VertState::chooseProc(SkVertices::VertexMode mode) { switch (mode) { - case SkCanvas::kTriangles_VertexMode: + case SkVertices::kTriangles_VertexMode: return fIndices ? TrianglesX : Triangles; - case SkCanvas::kTriangleStrip_VertexMode: + case SkVertices::kTriangleStrip_VertexMode: return fIndices ? TriangleStripX : TriangleStrip; - case SkCanvas::kTriangleFan_VertexMode: + case SkVertices::kTriangleFan_VertexMode: return fIndices ? TriangleFanX : TriangleFan; default: return nullptr; diff --git a/gfx/skia/skia/src/core/SkVertState.h b/gfx/skia/skia/src/core/SkVertState.h index ab794521b08d..89d224ee6e7a 100644 --- a/gfx/skia/skia/src/core/SkVertState.h +++ b/gfx/skia/skia/src/core/SkVertState.h @@ -8,7 +8,7 @@ #ifndef SkVertState_DEFINED #define SkVertState_DEFINED -#include "SkCanvas.h" +#include "SkVertices.h" /** \struct VertState This is a helper for drawVertices(). It is used to iterate over the triangles @@ -40,7 +40,7 @@ struct VertState { * Choose an appropriate function to traverse the vertices. * @param mode Specifies the SkCanvas::VertexMode. */ - Proc chooseProc(SkCanvas::VertexMode mode); + Proc chooseProc(SkVertices::VertexMode mode); private: int fCount; diff --git a/gfx/skia/skia/src/core/SkVertices.cpp b/gfx/skia/skia/src/core/SkVertices.cpp new file mode 100644 index 000000000000..8dadad056bd2 --- /dev/null +++ b/gfx/skia/skia/src/core/SkVertices.cpp @@ -0,0 +1,221 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkAtomics.h" +#include "SkVertices.h" +#include "SkData.h" +#include "SkReader32.h" +#include "SkWriter32.h" + +static int32_t gNextID = 1; +static int32_t next_id() { + int32_t id; + do { + id = sk_atomic_inc(&gNextID); + } while (id == SK_InvalidGenID); + return id; +} + +struct SkVertices::Sizes { + Sizes(int vertexCount, int indexCount, bool hasTexs, bool hasColors) { + int64_t vSize = (int64_t)vertexCount * sizeof(SkPoint); + int64_t tSize = hasTexs ? (int64_t)vertexCount * sizeof(SkPoint) : 0; + int64_t cSize = hasColors ? (int64_t)vertexCount * sizeof(SkColor) : 0; + int64_t iSize = (int64_t)indexCount * sizeof(uint16_t); + + int64_t total = sizeof(SkVertices) + vSize + tSize + cSize + iSize; + if (!sk_64_isS32(total)) { + sk_bzero(this, sizeof(*this)); + } else { + fTotal = SkToSizeT(total); + fVSize = SkToSizeT(vSize); + fTSize = SkToSizeT(tSize); + fCSize = SkToSizeT(cSize); + fISize = SkToSizeT(iSize); + fArrays = fTotal - sizeof(SkVertices); // just the sum of the arrays + } + } + + bool isValid() const { return fTotal != 0; } + + size_t fTotal; // size of entire SkVertices allocation (obj + arrays) + size_t fArrays; // size of all the arrays (V + T + C + I) + size_t fVSize; + size_t fTSize; + size_t fCSize; + size_t fISize; +}; + +SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount, + uint32_t builderFlags) { + bool hasTexs = SkToBool(builderFlags & SkVertices::kHasTexCoords_BuilderFlag); + bool hasColors = SkToBool(builderFlags & SkVertices::kHasColors_BuilderFlag); + this->init(mode, vertexCount, indexCount, + SkVertices::Sizes(vertexCount, indexCount, hasTexs, hasColors)); +} + +SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount, + const SkVertices::Sizes& sizes) { + this->init(mode, vertexCount, indexCount, sizes); +} + +void SkVertices::Builder::init(VertexMode mode, int vertexCount, int indexCount, + const SkVertices::Sizes& sizes) { + if (!sizes.isValid()) { + return; // fVertices will already be null + } + + void* storage = ::operator new (sizes.fTotal); + fVertices.reset(new (storage) SkVertices); + + // need to point past the object to store the arrays + char* ptr = (char*)storage + sizeof(SkVertices); + + fVertices->fPositions = (SkPoint*)ptr; ptr += sizes.fVSize; + fVertices->fTexs = sizes.fTSize ? (SkPoint*)ptr : nullptr; ptr += sizes.fTSize; + fVertices->fColors = sizes.fCSize ? (SkColor*)ptr : nullptr; ptr += sizes.fCSize; + fVertices->fIndices = sizes.fISize ? (uint16_t*)ptr : nullptr; + fVertices->fVertexCnt = vertexCount; + fVertices->fIndexCnt = indexCount; + fVertices->fMode = mode; + // We defer assigning fBounds and fUniqueID until detach() is called +} + +sk_sp SkVertices::Builder::detach() { + if (fVertices) { + fVertices->fBounds.set(fVertices->fPositions, fVertices->fVertexCnt); + fVertices->fUniqueID = next_id(); + return std::move(fVertices); // this will null fVertices after the return + } + return nullptr; +} + +int SkVertices::Builder::vertexCount() const { + return fVertices ? fVertices->vertexCount() : 0; +} + +int SkVertices::Builder::indexCount() const { + return fVertices ? fVertices->indexCount() : 0; +} + +SkPoint* SkVertices::Builder::positions() { + return fVertices ? const_cast(fVertices->positions()) : nullptr; +} + +SkPoint* SkVertices::Builder::texCoords() { + return fVertices ? const_cast(fVertices->texCoords()) : nullptr; +} + +SkColor* SkVertices::Builder::colors() { + return fVertices ? const_cast(fVertices->colors()) : nullptr; +} + +uint16_t* SkVertices::Builder::indices() { + return fVertices ? const_cast(fVertices->indices()) : nullptr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +sk_sp SkVertices::MakeCopy(VertexMode mode, int vertexCount, + const SkPoint pos[], const SkPoint texs[], + const SkColor colors[], int indexCount, + const uint16_t indices[]) { + Sizes sizes(vertexCount, indexCount, texs != nullptr, colors != nullptr); + if (!sizes.isValid()) { + return nullptr; + } + + Builder builder(mode, vertexCount, indexCount, sizes); + SkASSERT(builder.isValid()); + + sk_careful_memcpy(builder.positions(), pos, sizes.fVSize); + sk_careful_memcpy(builder.texCoords(), texs, sizes.fTSize); + sk_careful_memcpy(builder.colors(), colors, sizes.fCSize); + sk_careful_memcpy(builder.indices(), indices, sizes.fISize); + + return builder.detach(); +} + +size_t SkVertices::approximateSize() const { + Sizes sizes(fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors()); + SkASSERT(sizes.isValid()); + return sizeof(SkVertices) + sizes.fArrays; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | indices[] +// = header + arrays + +#define kMode_Mask 0x0FF +#define kHasTexs_Mask 0x100 +#define kHasColors_Mask 0x200 +#define kHeaderSize (3 * sizeof(uint32_t)) + +sk_sp SkVertices::encode() const { + // packed has room for addtional flags in the future (e.g. versioning) + uint32_t packed = static_cast(fMode); + SkASSERT((packed & ~kMode_Mask) == 0); // our mode fits in the mask bits + if (this->hasTexCoords()) { + packed |= kHasTexs_Mask; + } + if (this->hasColors()) { + packed |= kHasColors_Mask; + } + + Sizes sizes(fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors()); + SkASSERT(sizes.isValid()); + // need to force alignment to 4 for SkWriter32 -- will pad w/ 0s as needed + const size_t size = SkAlign4(kHeaderSize + sizes.fArrays); + + sk_sp data = SkData::MakeUninitialized(size); + SkWriter32 writer(data->writable_data(), data->size()); + + writer.write32(packed); + writer.write32(fVertexCnt); + writer.write32(fIndexCnt); + writer.write(fPositions, sizes.fVSize); + writer.write(fTexs, sizes.fTSize); + writer.write(fColors, sizes.fCSize); + // if index-count is odd, we won't be 4-bytes aligned, so we call the pad version + writer.writePad(fIndices, sizes.fISize); + + return data; +} + +sk_sp SkVertices::Decode(const void* data, size_t length) { + if (length < kHeaderSize) { + return nullptr; + } + + SkReader32 reader(data, length); + + const uint32_t packed = reader.readInt(); + const int vertexCount = reader.readInt(); + const int indexCount = reader.readInt(); + + const VertexMode mode = static_cast(packed & kMode_Mask); + const bool hasTexs = SkToBool(packed & kHasTexs_Mask); + const bool hasColors = SkToBool(packed & kHasColors_Mask); + Sizes sizes(vertexCount, indexCount, hasTexs, hasColors); + if (!sizes.isValid()) { + return nullptr; + } + // logically we can be only 2-byte aligned, but our buffer is always 4-byte aligned + if (SkAlign4(kHeaderSize + sizes.fArrays) != length) { + return nullptr; + } + + Builder builder(mode, vertexCount, indexCount, sizes); + + reader.read(builder.positions(), sizes.fVSize); + reader.read(builder.texCoords(), sizes.fTSize); + reader.read(builder.colors(), sizes.fCSize); + reader.read(builder.indices(), sizes.fISize); + + return builder.detach(); +} diff --git a/gfx/skia/skia/src/core/SkWriteBuffer.cpp b/gfx/skia/skia/src/core/SkWriteBuffer.cpp index 019bc247b598..79422abceaa7 100644 --- a/gfx/skia/skia/src/core/SkWriteBuffer.cpp +++ b/gfx/skia/skia/src/core/SkWriteBuffer.cpp @@ -153,30 +153,15 @@ void SkBinaryWriteBuffer::writeBitmap(const SkBitmap& bitmap) { // Write a bool to indicate that we did not use an SkBitmapHeap. That feature is deprecated. this->writeBool(false); - SkPixelRef* pixelRef = bitmap.pixelRef(); - if (pixelRef) { - // see if the pixelref already has an encoded version - sk_sp existingData(pixelRef->refEncodedData()); - if (existingData) { - // Assumes that if the client did not set a serializer, they are - // happy to get the encoded data. - if (!fPixelSerializer || fPixelSerializer->useEncodedData(existingData->data(), - existingData->size())) { - write_encoded_bitmap(this, existingData.get(), bitmap.pixelRefOrigin()); - return; - } - } - - // see if the caller wants to manually encode - SkAutoPixmapUnlock result; - if (fPixelSerializer && bitmap.requestLock(&result)) { - sk_sp data(fPixelSerializer->encode(result.pixmap())); - if (data) { - // if we have to "encode" the bitmap, then we assume there is no - // offset to share, since we are effectively creating a new pixelref - write_encoded_bitmap(this, data.get(), SkIPoint::Make(0, 0)); - return; - } + // see if the caller wants to manually encode + SkAutoPixmapUnlock result; + if (fPixelSerializer && bitmap.requestLock(&result)) { + sk_sp data(fPixelSerializer->encode(result.pixmap())); + if (data) { + // if we have to "encode" the bitmap, then we assume there is no + // offset to share, since we are effectively creating a new pixelref + write_encoded_bitmap(this, data.get(), SkIPoint::Make(0, 0)); + return; } } @@ -236,11 +221,8 @@ SkRefCntSet* SkBinaryWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) { return rec; } -void SkBinaryWriteBuffer::setPixelSerializer(SkPixelSerializer* serializer) { - fPixelSerializer.reset(serializer); - if (serializer) { - serializer->ref(); - } +void SkBinaryWriteBuffer::setPixelSerializer(sk_sp serializer) { + fPixelSerializer = std::move(serializer); } void SkBinaryWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) { diff --git a/gfx/skia/skia/src/core/SkWritePixelsRec.h b/gfx/skia/skia/src/core/SkWritePixelsRec.h new file mode 100644 index 000000000000..652a13a82230 --- /dev/null +++ b/gfx/skia/skia/src/core/SkWritePixelsRec.h @@ -0,0 +1,41 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkWritePixelsRec_DEFINED +#define SkWritePixelsRec_DEFINED + +#include "SkImageInfo.h" + +/** + * Helper class to package and trim the parameters passed to writePixels() + */ +struct SkWritePixelsRec { + SkWritePixelsRec(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y) + : fPixels(pixels) + , fRowBytes(rowBytes) + , fInfo(info) + , fX(x) + , fY(y) + {} + + const void* fPixels; + size_t fRowBytes; + SkImageInfo fInfo; + int fX; + int fY; + + /* + * On true, may have modified its fields (except fRowBytes) to make it a legal subset + * of the specified dst width/height. + * + * On false, leaves self unchanged, but indicates that it does not overlap dst, or + * is not valid (e.g. bad fInfo) for writePixels(). + */ + bool trim(int dstWidth, int dstHeight); +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkXfermode.cpp b/gfx/skia/skia/src/core/SkXfermode.cpp index 38a160870ef4..6f470f6dbe71 100644 --- a/gfx/skia/skia/src/core/SkXfermode.cpp +++ b/gfx/skia/skia/src/core/SkXfermode.cpp @@ -5,7 +5,6 @@ * found in the LICENSE file. */ -#include "SkXfermode.h" #include "SkXfermode_proccoeff.h" #include "SkColorPriv.h" #include "SkMathPriv.h" @@ -949,7 +948,8 @@ template SkPM4f proc_4f(const SkPM4f& s assert_unit(s); assert_unit(d); SkPM4f r = as_pm4f(blend(as_4f(s), as_4f(d))); - assert_unit(r); + // Turn this assert off for now because srgb conversions may end up in rgb > a + // assert_unit(r); return r; } @@ -1001,7 +1001,7 @@ sk_sp SkXfermode::makeFragmentProcessorForImageFilter( return nullptr; } -sk_sp SkXfermode::asXPFactory() const { +const GrXPFactory* SkXfermode::asXPFactory() const { // This should never be called. // TODO: make pure virtual in SkXfermode once Android update lands SkASSERT(0); @@ -1109,12 +1109,12 @@ sk_sp SkProcCoeffXfermode::CreateProc(SkReadBuffer& buffer) { } void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const { - buffer.write32(fMode); + buffer.write32((int)fMode); } bool SkProcCoeffXfermode::asMode(Mode* mode) const { if (mode) { - *mode = fMode; + *mode = (Mode)fMode; } return true; } @@ -1254,15 +1254,15 @@ sk_sp SkProcCoeffXfermode::makeFragmentProcessorForImageFil return GrXfermodeFragmentProcessor::MakeFromDstProcessor(std::move(dst), fMode); } -sk_sp SkProcCoeffXfermode::asXPFactory() const { +const GrXPFactory* SkProcCoeffXfermode::asXPFactory() const { if (CANNOT_USE_COEFF != fSrcCoeff) { - sk_sp result(GrPorterDuffXPFactory::Make(fMode)); + const GrXPFactory* result(GrPorterDuffXPFactory::Get(fMode)); SkASSERT(result); return result; } SkASSERT(GrCustomXfermode::IsSupportedMode(fMode)); - return GrCustomXfermode::MakeXPFactory(fMode); + return GrCustomXfermode::Get(fMode); } #endif @@ -1279,6 +1279,10 @@ const char* SkXfermode::ModeName(Mode mode) { static_assert(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, "mode_count"); } +const char* SkBlendMode_Name(SkBlendMode mode) { + return SkXfermode::ModeName((SkXfermode::Mode)mode); +} + #ifndef SK_IGNORE_TO_STRING void SkProcCoeffXfermode::toString(SkString* str) const { str->append("SkProcCoeffXfermode: "); @@ -1307,59 +1311,51 @@ void SkProcCoeffXfermode::toString(SkString* str) const { #endif -sk_sp SkXfermode::Make(Mode mode) { - if ((unsigned)mode >= kModeCount) { +sk_sp SkXfermode::Make(SkBlendMode mode) { + if ((unsigned)mode > (unsigned)SkBlendMode::kLastMode) { // report error return nullptr; } // Skia's "default" mode is srcover. nullptr in SkPaint is interpreted as srcover // so we can just return nullptr from the factory. - if (kSrcOver_Mode == mode) { + if (SkBlendMode::kSrcOver == mode) { return nullptr; } - SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); + const int COUNT_BLENDMODES = (int)SkBlendMode::kLastMode + 1; + SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == COUNT_BLENDMODES); - static SkOnce once[SkXfermode::kLastMode+1]; - static SkXfermode* cached[SkXfermode::kLastMode+1]; + static SkOnce once[COUNT_BLENDMODES]; + static SkXfermode* cached[COUNT_BLENDMODES]; - once[mode]([mode] { - ProcCoeff rec = gProcCoeffs[mode]; + once[(int)mode]([mode] { + ProcCoeff rec = gProcCoeffs[(int)mode]; if (auto xfermode = SkOpts::create_xfermode(rec, mode)) { - cached[mode] = xfermode; + cached[(int)mode] = xfermode; } else { - cached[mode] = new SkProcCoeffXfermode(rec, mode); + cached[(int)mode] = new SkProcCoeffXfermode(rec, mode); } }); - return sk_ref_sp(cached[mode]); + return sk_ref_sp(cached[(int)mode]); } -SkXfermodeProc SkXfermode::GetProc(Mode mode) { +SkXfermodeProc SkXfermode::GetProc(SkBlendMode mode) { SkXfermodeProc proc = nullptr; if ((unsigned)mode < kModeCount) { - proc = gProcCoeffs[mode].fProc; + proc = gProcCoeffs[(unsigned)mode].fProc; } return proc; } -SkXfermodeProc4f SkXfermode::GetProc4f(Mode mode) { +SkXfermodeProc4f SkXfermode::GetProc4f(SkBlendMode mode) { SkXfermodeProc4f proc = nullptr; if ((unsigned)mode < kModeCount) { - proc = gProcCoeffs[mode].fProc4f; + proc = gProcCoeffs[(unsigned)mode].fProc4f; } return proc; } -static SkPM4f missing_proc4f(const SkPM4f& src, const SkPM4f& dst) { - return src; -} - -SkXfermodeProc4f SkXfermode::getProc4f() const { - Mode mode; - return this->asMode(&mode) ? GetProc4f(mode) : missing_proc4f; -} - bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) { SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); @@ -1421,58 +1417,10 @@ bool SkXfermode::IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType) { return xfer->isOpaque(opacityType); } -bool SkXfermode::appendStages(SkRasterPipeline* pipeline) const { - return this->onAppendStages(pipeline); -} - -bool SkXfermode::onAppendStages(SkRasterPipeline*) const { - return false; -} - SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode) SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END - -bool SkProcCoeffXfermode::onAppendStages(SkRasterPipeline* p) const { - switch (fMode) { - case kSrc_Mode: /*This stage is a no-op.*/ return true; - case kDst_Mode: p->append(SkRasterPipeline::dst); return true; - case kSrcATop_Mode: p->append(SkRasterPipeline::srcatop); return true; - case kDstATop_Mode: p->append(SkRasterPipeline::dstatop); return true; - case kSrcIn_Mode: p->append(SkRasterPipeline::srcin); return true; - case kDstIn_Mode: p->append(SkRasterPipeline::dstin); return true; - case kSrcOut_Mode: p->append(SkRasterPipeline::srcout); return true; - case kDstOut_Mode: p->append(SkRasterPipeline::dstout); return true; - case kSrcOver_Mode: p->append(SkRasterPipeline::srcover); return true; - case kDstOver_Mode: p->append(SkRasterPipeline::dstover); return true; - - case kClear_Mode: p->append(SkRasterPipeline::clear); return true; - case kModulate_Mode: p->append(SkRasterPipeline::modulate); return true; - case kMultiply_Mode: p->append(SkRasterPipeline::multiply); return true; - case kPlus_Mode: p->append(SkRasterPipeline::plus_); return true; - case kScreen_Mode: p->append(SkRasterPipeline::screen); return true; - case kXor_Mode: p->append(SkRasterPipeline::xor_); return true; - - case kColorBurn_Mode: p->append(SkRasterPipeline::colorburn); return true; - case kColorDodge_Mode: p->append(SkRasterPipeline::colordodge); return true; - case kDarken_Mode: p->append(SkRasterPipeline::darken); return true; - case kDifference_Mode: p->append(SkRasterPipeline::difference); return true; - case kExclusion_Mode: p->append(SkRasterPipeline::exclusion); return true; - case kHardLight_Mode: p->append(SkRasterPipeline::hardlight); return true; - case kLighten_Mode: p->append(SkRasterPipeline::lighten); return true; - case kOverlay_Mode: p->append(SkRasterPipeline::overlay); return true; - case kSoftLight_Mode: p->append(SkRasterPipeline::softlight); return true; - - // TODO - case kColor_Mode: return false; - case kHue_Mode: return false; - case kLuminosity_Mode: return false; - case kSaturation_Mode: return false; - } - return false; -} - /////////////////////////////////////////////////////////////////////////////////////////////////// bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode) { @@ -1521,15 +1469,58 @@ bool SkXfermode::IsOpaque(SkBlendMode mode, SrcColorOpacity opacityType) { } #if SK_SUPPORT_GPU -sk_sp SkBlendMode_AsXPFactory(SkBlendMode mode) { +const GrXPFactory* SkBlendMode_AsXPFactory(SkBlendMode mode) { const ProcCoeff rec = gProcCoeffs[(int)mode]; if (CANNOT_USE_COEFF != rec.fSC) { - sk_sp result(GrPorterDuffXPFactory::Make(mode)); + const GrXPFactory* result = GrPorterDuffXPFactory::Get(mode); SkASSERT(result); return result; } - SkASSERT(GrCustomXfermode::IsSupportedMode((SkXfermode::Mode)mode)); - return GrCustomXfermode::MakeXPFactory((SkXfermode::Mode)mode); + SkASSERT(GrCustomXfermode::IsSupportedMode(mode)); + return GrCustomXfermode::Get(mode); } #endif + +bool SkBlendMode_CanOverflow(SkBlendMode mode) { return mode == SkBlendMode::kPlus; } + +bool SkBlendMode_AppendStages(SkBlendMode mode, SkRasterPipeline* p) { + auto stage = SkRasterPipeline::srcover; + switch (mode) { + case SkBlendMode::kClear: stage = SkRasterPipeline::clear; break; + case SkBlendMode::kSrc: return true; // This stage is a no-op. + case SkBlendMode::kDst: stage = SkRasterPipeline::move_dst_src; break; + case SkBlendMode::kSrcOver: stage = SkRasterPipeline::srcover; break; + case SkBlendMode::kDstOver: stage = SkRasterPipeline::dstover; break; + case SkBlendMode::kSrcIn: stage = SkRasterPipeline::srcin; break; + case SkBlendMode::kDstIn: stage = SkRasterPipeline::dstin; break; + case SkBlendMode::kSrcOut: stage = SkRasterPipeline::srcout; break; + case SkBlendMode::kDstOut: stage = SkRasterPipeline::dstout; break; + case SkBlendMode::kSrcATop: stage = SkRasterPipeline::srcatop; break; + case SkBlendMode::kDstATop: stage = SkRasterPipeline::dstatop; break; + case SkBlendMode::kXor: stage = SkRasterPipeline::xor_; break; + case SkBlendMode::kPlus: stage = SkRasterPipeline::plus_; break; + case SkBlendMode::kModulate: stage = SkRasterPipeline::modulate; break; + + case SkBlendMode::kScreen: stage = SkRasterPipeline::screen; break; + case SkBlendMode::kOverlay: stage = SkRasterPipeline::overlay; break; + case SkBlendMode::kDarken: stage = SkRasterPipeline::darken; break; + case SkBlendMode::kLighten: stage = SkRasterPipeline::lighten; break; + case SkBlendMode::kColorDodge: stage = SkRasterPipeline::colordodge; break; + case SkBlendMode::kColorBurn: stage = SkRasterPipeline::colorburn; break; + case SkBlendMode::kHardLight: stage = SkRasterPipeline::hardlight; break; + case SkBlendMode::kSoftLight: stage = SkRasterPipeline::softlight; break; + case SkBlendMode::kDifference: stage = SkRasterPipeline::difference; break; + case SkBlendMode::kExclusion: stage = SkRasterPipeline::exclusion; break; + case SkBlendMode::kMultiply: stage = SkRasterPipeline::multiply; break; + + case SkBlendMode::kHue: + case SkBlendMode::kSaturation: + case SkBlendMode::kColor: + case SkBlendMode::kLuminosity: return false; // TODO + } + if (p) { + p->append(stage); + } + return true; +} diff --git a/gfx/skia/skia/src/core/SkXfermode4f.cpp b/gfx/skia/skia/src/core/SkXfermode4f.cpp index 1a9b58e2177c..e9d55905a715 100644 --- a/gfx/skia/skia/src/core/SkXfermode4f.cpp +++ b/gfx/skia/skia/src/core/SkXfermode4f.cpp @@ -7,7 +7,7 @@ #include "SkPM4fPriv.h" #include "SkUtils.h" -#include "SkXfermode.h" +#include "SkXfermodePriv.h" #include "Sk4x4f.h" static SkPM4f rgba_to_pmcolor_order(const SkPM4f& x) { @@ -73,10 +73,10 @@ static void store_4_srgb(void* ptr, const Sk4x4f& p) { /////////////////////////////////////////////////////////////////////////////////////////////////// -template void general_1(const SkXfermode* xfer, uint32_t dst[], +template void general_1(SkBlendMode mode, uint32_t dst[], const SkPM4f* src, int count, const SkAlpha aa[]) { const SkPM4f s = rgba_to_pmcolor_order(*src); - SkXfermodeProc4f proc = xfer->getProc4f(); + SkXfermodeProc4f proc = SkXfermode::GetProc4f(mode); SkPM4f d; if (aa) { for (int i = 0; i < count; ++i) { @@ -94,9 +94,9 @@ template void general_1(const SkXfermode* xfer, uint32_t dst[], } } -template void general_n(const SkXfermode* xfer, uint32_t dst[], +template void general_n(SkBlendMode mode, uint32_t dst[], const SkPM4f src[], int count, const SkAlpha aa[]) { - SkXfermodeProc4f proc = xfer->getProc4f(); + SkXfermodeProc4f proc = SkXfermode::GetProc4f(mode); SkPM4f d; if (aa) { for (int i = 0; i < count; ++i) { @@ -123,8 +123,8 @@ const SkXfermode::D32Proc gProcs_General[] = { /////////////////////////////////////////////////////////////////////////////////////////////////// -static void clear_linear(const SkXfermode*, uint32_t dst[], const SkPM4f[], - int count, const SkAlpha aa[]) { +static void clear_linear(SkBlendMode, uint32_t dst[], const SkPM4f[], int count, + const SkAlpha aa[]) { if (aa) { for (int i = 0; i < count; ++i) { unsigned a = aa[i]; @@ -142,8 +142,7 @@ static void clear_linear(const SkXfermode*, uint32_t dst[], const SkPM4f[], } } -static void clear_srgb(const SkXfermode*, uint32_t dst[], const SkPM4f[], - int count, const SkAlpha aa[]) { +static void clear_srgb(SkBlendMode, uint32_t dst[], const SkPM4f[], int count, const SkAlpha aa[]) { if (aa) { for (int i = 0; i < count; ++i) { if (aa[i]) { @@ -165,8 +164,8 @@ const SkXfermode::D32Proc gProcs_Clear[] = { /////////////////////////////////////////////////////////////////////////////////////////////////// -template void src_n(const SkXfermode*, uint32_t dst[], - const SkPM4f src[], int count, const SkAlpha aa[]) { +template void src_n(SkBlendMode, uint32_t dst[], const SkPM4f src[], int count, + const SkAlpha aa[]) { for (int i = 0; i < count; ++i) { unsigned a = 0xFF; if (aa) { @@ -188,8 +187,8 @@ static Sk4f lerp(const Sk4f& src, const Sk4f& dst, const Sk4f& src_scale) { return dst + (src - dst) * src_scale; } -template void src_1(const SkXfermode*, uint32_t dst[], - const SkPM4f* src, int count, const SkAlpha aa[]) { +template void src_1(SkBlendMode, uint32_t dst[], const SkPM4f* src, int count, + const SkAlpha aa[]) { const Sk4f s4 = src->to4f_pmorder(); if (aa) { @@ -225,7 +224,7 @@ const SkXfermode::D32Proc gProcs_Src[] = { /////////////////////////////////////////////////////////////////////////////////////////////////// -static void dst(const SkXfermode*, uint32_t dst[], const SkPM4f[], int count, const SkAlpha aa[]) {} +static void dst(SkBlendMode, uint32_t dst[], const SkPM4f[], int count, const SkAlpha aa[]) {} const SkXfermode::D32Proc gProcs_Dst[] = { dst, dst, dst, dst, dst, dst, dst, dst, @@ -234,8 +233,8 @@ const SkXfermode::D32Proc gProcs_Dst[] = { /////////////////////////////////////////////////////////////////////////////////////////////////// -template void srcover_n(const SkXfermode*, uint32_t dst[], - const SkPM4f src[], int count, const SkAlpha aa[]) { +template void srcover_n(SkBlendMode, uint32_t dst[], const SkPM4f src[], int count, + const SkAlpha aa[]) { if (aa) { for (int i = 0; i < count; ++i) { unsigned a = aa[i]; @@ -276,8 +275,8 @@ template void srcover_n(const SkXfermode*, uint32_t dst[], } } -static void srcover_linear_dst_1(const SkXfermode*, uint32_t dst[], - const SkPM4f* src, int count, const SkAlpha aa[]) { +static void srcover_linear_dst_1(SkBlendMode, uint32_t dst[], const SkPM4f* src, int count, + const SkAlpha aa[]) { const Sk4f s4 = src->to4f_pmorder(); const Sk4f dst_scale = Sk4f(1 - get_alpha(s4)); @@ -305,8 +304,8 @@ static void srcover_linear_dst_1(const SkXfermode*, uint32_t dst[], } } -static void srcover_srgb_dst_1(const SkXfermode*, uint32_t dst[], - const SkPM4f* src, int count, const SkAlpha aa[]) { +static void srcover_srgb_dst_1(SkBlendMode, uint32_t dst[], const SkPM4f* src, int count, + const SkAlpha aa[]) { Sk4f s4 = src->to4f_pmorder(); Sk4f dst_scale = Sk4f(1 - get_alpha(s4)); @@ -360,33 +359,21 @@ const SkXfermode::D32Proc gProcs_SrcOver[] = { /////////////////////////////////////////////////////////////////////////////////////////////////// -static SkXfermode::D32Proc find_proc(SkXfermode::Mode mode, uint32_t flags) { +SkXfermode::D32Proc SkXfermode::GetD32Proc(SkBlendMode mode, uint32_t flags) { SkASSERT(0 == (flags & ~7)); flags &= 7; switch (mode) { - case SkXfermode::kClear_Mode: return gProcs_Clear[flags]; - case SkXfermode::kSrc_Mode: return gProcs_Src[flags]; - case SkXfermode::kDst_Mode: return gProcs_Dst[flags]; - case SkXfermode::kSrcOver_Mode: return gProcs_SrcOver[flags]; + case SkBlendMode::kClear: return gProcs_Clear[flags]; + case SkBlendMode::kSrc: return gProcs_Src[flags]; + case SkBlendMode::kDst: return gProcs_Dst[flags]; + case SkBlendMode::kSrcOver: return gProcs_SrcOver[flags]; default: break; } return gProcs_General[flags]; } -SkXfermode::D32Proc SkXfermode::onGetD32Proc(uint32_t flags) const { - SkASSERT(0 == (flags & ~7)); - flags &= 7; - - Mode mode; - return this->asMode(&mode) ? find_proc(mode, flags) : gProcs_General[flags]; -} - -SkXfermode::D32Proc SkXfermode::GetD32Proc(SkXfermode* xfer, uint32_t flags) { - return xfer ? xfer->onGetD32Proc(flags) : find_proc(SkXfermode::kSrcOver_Mode, flags); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// #include "SkColorPriv.h" diff --git a/gfx/skia/skia/src/core/SkXfermodeF16.cpp b/gfx/skia/skia/src/core/SkXfermodeF16.cpp index 9cf7254d1fb1..ece4a097c37f 100644 --- a/gfx/skia/skia/src/core/SkXfermodeF16.cpp +++ b/gfx/skia/skia/src/core/SkXfermodeF16.cpp @@ -8,7 +8,7 @@ #include "SkHalf.h" #include "SkPM4fPriv.h" #include "SkUtils.h" -#include "SkXfermode.h" +#include "SkXfermodePriv.h" static Sk4f lerp_by_coverage(const Sk4f& src, const Sk4f& dst, uint8_t srcCoverage) { return dst + (src - dst) * Sk4f(srcCoverage * (1/255.0f)); @@ -16,9 +16,9 @@ static Sk4f lerp_by_coverage(const Sk4f& src, const Sk4f& dst, uint8_t srcCovera /////////////////////////////////////////////////////////////////////////////////////////////////// -static void xfer_1(const SkXfermode* xfer, uint64_t dst[], const SkPM4f* src, int count, +static void xfer_1(SkBlendMode mode, uint64_t dst[], const SkPM4f* src, int count, const SkAlpha aa[]) { - SkXfermodeProc4f proc = xfer->getProc4f(); + SkXfermodeProc4f proc = SkXfermode::GetProc4f(mode); SkPM4f d; if (aa) { for (int i = 0; i < count; ++i) { @@ -36,9 +36,9 @@ static void xfer_1(const SkXfermode* xfer, uint64_t dst[], const SkPM4f* src, in } } -static void xfer_n(const SkXfermode* xfer, uint64_t dst[], const SkPM4f src[], int count, +static void xfer_n(SkBlendMode mode, uint64_t dst[], const SkPM4f src[], int count, const SkAlpha aa[]) { - SkXfermodeProc4f proc = xfer->getProc4f(); + SkXfermodeProc4f proc = SkXfermode::GetProc4f(mode); SkPM4f d; if (aa) { for (int i = 0; i < count; ++i) { @@ -60,7 +60,7 @@ const SkXfermode::F16Proc gProcs_General[] = { xfer_n, xfer_n, xfer_1, xfer_1 }; /////////////////////////////////////////////////////////////////////////////////////////////////// -static void clear(const SkXfermode*, uint64_t dst[], const SkPM4f*, int count, const SkAlpha aa[]) { +static void clear(SkBlendMode, uint64_t dst[], const SkPM4f*, int count, const SkAlpha aa[]) { if (aa) { for (int i = 0; i < count; ++i) { if (aa[i]) { @@ -77,8 +77,7 @@ const SkXfermode::F16Proc gProcs_Clear[] = { clear, clear, clear, clear }; /////////////////////////////////////////////////////////////////////////////////////////////////// -static void src_1(const SkXfermode*, uint64_t dst[], const SkPM4f* src, int count, - const SkAlpha aa[]) { +static void src_1(SkBlendMode, uint64_t dst[], const SkPM4f* src, int count, const SkAlpha aa[]) { const Sk4f s4 = Sk4f::Load(src->fVec); if (aa) { for (int i = 0; i < count; ++i) { @@ -92,8 +91,7 @@ static void src_1(const SkXfermode*, uint64_t dst[], const SkPM4f* src, int coun } } -static void src_n(const SkXfermode*, uint64_t dst[], const SkPM4f src[], int count, - const SkAlpha aa[]) { +static void src_n(SkBlendMode, uint64_t dst[], const SkPM4f src[], int count, const SkAlpha aa[]) { if (aa) { for (int i = 0; i < count; ++i) { const Sk4f s4 = Sk4f::Load(src[i].fVec); @@ -112,13 +110,13 @@ const SkXfermode::F16Proc gProcs_Src[] = { src_n, src_n, src_1, src_1 }; /////////////////////////////////////////////////////////////////////////////////////////////////// -static void dst(const SkXfermode*, uint64_t*, const SkPM4f*, int count, const SkAlpha[]) {} +static void dst(SkBlendMode, uint64_t*, const SkPM4f*, int count, const SkAlpha[]) {} const SkXfermode::F16Proc gProcs_Dst[] = { dst, dst, dst, dst }; /////////////////////////////////////////////////////////////////////////////////////////////////// -static void srcover_1(const SkXfermode*, uint64_t dst[], const SkPM4f* src, int count, +static void srcover_1(SkBlendMode, uint64_t dst[], const SkPM4f* src, int count, const SkAlpha aa[]) { const Sk4f s4 = Sk4f::Load(src->fVec); const Sk4f dst_scale = Sk4f(1 - get_alpha(s4)); @@ -133,7 +131,7 @@ static void srcover_1(const SkXfermode*, uint64_t dst[], const SkPM4f* src, int } } -static void srcover_n(const SkXfermode*, uint64_t dst[], const SkPM4f src[], int count, +static void srcover_n(SkBlendMode, uint64_t dst[], const SkPM4f src[], int count, const SkAlpha aa[]) { for (int i = 0; i < count; ++i) { Sk4f s = Sk4f::Load(src+i), @@ -150,29 +148,17 @@ const SkXfermode::F16Proc gProcs_SrcOver[] = { srcover_n, src_n, srcover_1, src_ /////////////////////////////////////////////////////////////////////////////////////////////////// -static SkXfermode::F16Proc find_proc(SkXfermode::Mode mode, uint32_t flags) { +SkXfermode::F16Proc SkXfermode::GetF16Proc(SkBlendMode mode, uint32_t flags) { SkASSERT(0 == (flags & ~3)); flags &= 3; switch (mode) { - case SkXfermode::kClear_Mode: return gProcs_Clear[flags]; - case SkXfermode::kSrc_Mode: return gProcs_Src[flags]; - case SkXfermode::kDst_Mode: return gProcs_Dst[flags]; - case SkXfermode::kSrcOver_Mode: return gProcs_SrcOver[flags]; + case SkBlendMode::kClear: return gProcs_Clear[flags]; + case SkBlendMode::kSrc: return gProcs_Src[flags]; + case SkBlendMode::kDst: return gProcs_Dst[flags]; + case SkBlendMode::kSrcOver: return gProcs_SrcOver[flags]; default: break; } return gProcs_General[flags]; } - -SkXfermode::F16Proc SkXfermode::onGetF16Proc(uint32_t flags) const { - SkASSERT(0 == (flags & ~3)); - flags &= 3; - - Mode mode; - return this->asMode(&mode) ? find_proc(mode, flags) : gProcs_General[flags]; -} - -SkXfermode::F16Proc SkXfermode::GetF16Proc(SkXfermode* xfer, uint32_t flags) { - return xfer ? xfer->onGetF16Proc(flags) : find_proc(SkXfermode::kSrcOver_Mode, flags); -} diff --git a/gfx/skia/skia/include/core/SkXfermode.h b/gfx/skia/skia/src/core/SkXfermodePriv.h similarity index 87% rename from gfx/skia/skia/include/core/SkXfermode.h rename to gfx/skia/skia/src/core/SkXfermodePriv.h index 253ee1b4089a..2fae2c0ed04a 100644 --- a/gfx/skia/skia/include/core/SkXfermode.h +++ b/gfx/skia/skia/src/core/SkXfermodePriv.h @@ -5,8 +5,8 @@ * found in the LICENSE file. */ -#ifndef SkXfermode_DEFINED -#define SkXfermode_DEFINED +#ifndef SkXfermodePriv_DEFINED +#define SkXfermodePriv_DEFINED #include "SkBlendMode.h" #include "SkColor.h" @@ -152,16 +152,8 @@ public: /** Return an SkXfermode object for the specified mode. */ - static sk_sp Make(Mode); -#ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR - static SkXfermode* Create(Mode mode) { - return Make(mode).release(); - } - SK_ATTR_DEPRECATED("use AsMode(...)") - static bool IsMode(const SkXfermode* xfer, Mode* mode) { - return AsMode(xfer, mode); - } -#endif + static sk_sp Make(SkBlendMode); + static sk_sp Make(Mode m) { return Make((SkBlendMode)m); } /** * Skia maintains global xfermode objects corresponding to each BlendMode. This returns a @@ -178,25 +170,14 @@ public: return xfer.get(); } - static sk_sp Make(SkBlendMode bm) { - return Make((Mode)bm); - } - SkBlendMode blend() const { Mode mode; SkAssertResult(this->asMode(&mode)); return (SkBlendMode)mode; } - /** Return a function pointer to a routine that applies the specified - porter-duff transfer mode. - */ - static SkXfermodeProc GetProc(Mode mode); - static SkXfermodeProc4f GetProc4f(Mode); - - virtual SkXfermodeProc4f getProc4f() const; - - bool appendStages(SkRasterPipeline*) const; + static SkXfermodeProc GetProc(SkBlendMode); + static SkXfermodeProc4f GetProc4f(SkBlendMode); /** * If the specified mode can be represented by a pair of Coeff, then return @@ -205,6 +186,9 @@ public: * src and dst parameters. */ static bool ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst); + static bool ModeAsCoeff(SkBlendMode mode, Coeff* src, Coeff* dst) { + return ModeAsCoeff((Mode)mode, src, dst); + } /** * Returns whether or not the xfer mode can support treating coverage as alpha @@ -262,7 +246,7 @@ public: The xfermode will return a factory for which the caller will get a ref. It is up to the caller to install it. XferProcessors cannot use a background texture. */ - virtual sk_sp asXPFactory() const; + virtual const GrXPFactory* asXPFactory() const; #endif SK_TO_STRING_PUREVIRT() @@ -274,23 +258,17 @@ public: kSrcIsSingle_D32Flag = 1 << 1, kDstIsSRGB_D32Flag = 1 << 2, }; - typedef void (*D32Proc)(const SkXfermode*, uint32_t dst[], const SkPM4f src[], + typedef void (*D32Proc)(SkBlendMode, uint32_t dst[], const SkPM4f src[], int count, const SkAlpha coverage[]); - static D32Proc GetD32Proc(SkXfermode*, uint32_t flags); - static D32Proc GetD32Proc(const sk_sp& xfer, uint32_t flags) { - return GetD32Proc(xfer.get(), flags); - } + static D32Proc GetD32Proc(SkBlendMode, uint32_t flags); enum F16Flags { kSrcIsOpaque_F16Flag = 1 << 0, kSrcIsSingle_F16Flag = 1 << 1, }; - typedef void (*F16Proc)(const SkXfermode*, uint64_t dst[], const SkPM4f src[], int count, + typedef void (*F16Proc)(SkBlendMode, uint64_t dst[], const SkPM4f src[], int count, const SkAlpha coverage[]); - static F16Proc GetF16Proc(SkXfermode*, uint32_t flags); - static F16Proc GetF16Proc(const sk_sp& xfer, uint32_t flags) { - return GetF16Proc(xfer.get(), flags); - } + static F16Proc GetF16Proc(SkBlendMode, uint32_t flags); enum LCDFlags { kSrcIsOpaque_LCDFlag = 1 << 0, // else src(s) may have alpha < 1 @@ -316,10 +294,6 @@ protected: */ virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst) const; - virtual D32Proc onGetD32Proc(uint32_t flags) const; - virtual F16Proc onGetF16Proc(uint32_t flags) const; - virtual bool onAppendStages(SkRasterPipeline*) const; - private: enum { kModeCount = kLastMode + 1 diff --git a/gfx/skia/skia/src/core/SkXfermode_proccoeff.h b/gfx/skia/skia/src/core/SkXfermode_proccoeff.h index 1e6cc482a6be..372453218a27 100644 --- a/gfx/skia/skia/src/core/SkXfermode_proccoeff.h +++ b/gfx/skia/skia/src/core/SkXfermode_proccoeff.h @@ -8,7 +8,6 @@ #ifndef SkXfermode_proccoeff_DEFINED #define SkXfermode_proccoeff_DEFINED -#include "SkXfermode.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" @@ -23,7 +22,7 @@ struct ProcCoeff { class SK_API SkProcCoeffXfermode : public SkXfermode { public: - SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode) { + SkProcCoeffXfermode(const ProcCoeff& rec, SkBlendMode mode) { fMode = mode; fProc = rec.fProc; // these may be valid, or may be CANNOT_USE_COEFF @@ -47,24 +46,22 @@ public: #if SK_SUPPORT_GPU sk_sp makeFragmentProcessorForImageFilter( sk_sp) const override; - sk_sp asXPFactory() const override; + const GrXPFactory* asXPFactory() const override; #endif SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcCoeffXfermode) - bool onAppendStages(SkRasterPipeline*) const override; - protected: void flatten(SkWriteBuffer& buffer) const override; - Mode getMode() const { return fMode; } + SkBlendMode getMode() const { return fMode; } SkXfermodeProc getProc() const { return fProc; } private: SkXfermodeProc fProc; - Mode fMode; + SkBlendMode fMode; Coeff fSrcCoeff, fDstCoeff; friend class SkXfermode; diff --git a/gfx/skia/skia/src/core/SkYUVPlanesCache.cpp b/gfx/skia/skia/src/core/SkYUVPlanesCache.cpp index 07a07c698b6e..a962d5a4b70d 100644 --- a/gfx/skia/skia/src/core/SkYUVPlanesCache.cpp +++ b/gfx/skia/skia/src/core/SkYUVPlanesCache.cpp @@ -39,7 +39,7 @@ struct YUVPlanesRec : public SkResourceCache::Rec { fValue.fInfo = *info; fValue.fData->attachToCacheAndRef(); } - ~YUVPlanesRec() { + ~YUVPlanesRec() override { fValue.fData->detachFromCacheAndUnref(); } diff --git a/gfx/skia/skia/src/effects/GrAlphaThresholdFragmentProcessor.cpp b/gfx/skia/skia/src/effects/GrAlphaThresholdFragmentProcessor.cpp index 442acd012995..6c355c1fee90 100644 --- a/gfx/skia/skia/src/effects/GrAlphaThresholdFragmentProcessor.cpp +++ b/gfx/skia/skia/src/effects/GrAlphaThresholdFragmentProcessor.cpp @@ -9,57 +9,47 @@ #if SK_SUPPORT_GPU -#include "GrInvariantOutput.h" -#include "GrTextureAccess.h" +#include "GrContext.h" #include "SkRefCnt.h" - #include "glsl/GrGLSLColorSpaceXformHelper.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLUniformHandler.h" +#include "../private/GrGLSL.h" -sk_sp GrAlphaThresholdFragmentProcessor::Make( - GrTexture* texture, - sk_sp colorSpaceXform, - GrTexture* maskTexture, - float innerThreshold, - float outerThreshold, - const SkIRect& bounds) { - return sk_sp(new GrAlphaThresholdFragmentProcessor( - texture, std::move(colorSpaceXform), - maskTexture, - innerThreshold, outerThreshold, - bounds)); -} - -static SkMatrix make_div_and_translate_matrix(GrTexture* texture, int x, int y) { - SkMatrix matrix = GrCoordTransform::MakeDivByTextureWHMatrix(texture); - matrix.preTranslate(SkIntToScalar(x), SkIntToScalar(y)); - return matrix; +inline GrFragmentProcessor::OptimizationFlags GrAlphaThresholdFragmentProcessor::OptFlags(float outerThreshold) { + if (outerThreshold >= 1.f) { + return kPreservesOpaqueInput_OptimizationFlag | + kCompatibleWithCoverageAsAlpha_OptimizationFlag; + } else { + return kCompatibleWithCoverageAsAlpha_OptimizationFlag; + } } GrAlphaThresholdFragmentProcessor::GrAlphaThresholdFragmentProcessor( - GrTexture* texture, + GrResourceProvider* resourceProvider, + sk_sp proxy, sk_sp colorSpaceXform, - GrTexture* maskTexture, + sk_sp maskProxy, float innerThreshold, float outerThreshold, const SkIRect& bounds) - : fInnerThreshold(innerThreshold) - , fOuterThreshold(outerThreshold) - , fImageCoordTransform(GrCoordTransform::MakeDivByTextureWHMatrix(texture), texture, - GrTextureParams::kNone_FilterMode) - , fImageTextureAccess(texture) - , fColorSpaceXform(std::move(colorSpaceXform)) - , fMaskCoordTransform(make_div_and_translate_matrix(maskTexture, -bounds.x(), -bounds.y()), - maskTexture, - GrTextureParams::kNone_FilterMode) - , fMaskTextureAccess(maskTexture) { + : INHERITED(OptFlags(outerThreshold)) + , fInnerThreshold(innerThreshold) + , fOuterThreshold(outerThreshold) + , fImageCoordTransform(resourceProvider, SkMatrix::I(), proxy.get()) + , fImageTextureSampler(resourceProvider, std::move(proxy)) + , fColorSpaceXform(std::move(colorSpaceXform)) + , fMaskCoordTransform( + resourceProvider, + SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())), + maskProxy.get()) + , fMaskTextureSampler(resourceProvider, maskProxy) { this->initClassID(); this->addCoordTransform(&fImageCoordTransform); - this->addTextureAccess(&fImageTextureAccess); + this->addTextureSampler(&fImageTextureSampler); this->addCoordTransform(&fMaskCoordTransform); - this->addTextureAccess(&fMaskTextureAccess); + this->addTextureSampler(&fMaskTextureSampler); } bool GrAlphaThresholdFragmentProcessor::onIsEqual(const GrFragmentProcessor& sBase) const { @@ -68,23 +58,13 @@ bool GrAlphaThresholdFragmentProcessor::onIsEqual(const GrFragmentProcessor& sBa this->fOuterThreshold == s.fOuterThreshold); } -void GrAlphaThresholdFragmentProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const { - if (GrPixelConfigIsAlphaOnly(this->texture(0)->config())) { - inout->mulByUnknownSingleComponent(); - } else if (GrPixelConfigIsOpaque(this->texture(0)->config()) && fOuterThreshold >= 1.f) { - inout->mulByUnknownOpaqueFourComponents(); - } else { - inout->mulByUnknownFourComponents(); - } -} - /////////////////////////////////////////////////////////////////////////////// class GrGLAlphaThresholdFragmentProcessor : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor& effect, const GrGLSLCaps&, + static inline void GenKey(const GrProcessor& effect, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrAlphaThresholdFragmentProcessor& atfp = effect.cast(); @@ -92,12 +72,12 @@ public: } protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fInnerThresholdVar; GrGLSLProgramDataManager::UniformHandle fOuterThresholdVar; - GrGLSLProgramDataManager::UniformHandle fColorSpaceXformVar; + GrGLSLColorSpaceXformHelper fColorSpaceHelper; typedef GrGLSLFragmentProcessor INHERITED; }; @@ -112,8 +92,7 @@ void GrGLAlphaThresholdFragmentProcessor::emitCode(EmitArgs& args) { const GrAlphaThresholdFragmentProcessor& atfp = args.fFp.cast(); - GrGLSLColorSpaceXformHelper colorSpaceHelper(uniformHandler, atfp.colorSpaceXform(), - &fColorSpaceXformVar); + fColorSpaceHelper.emitCode(uniformHandler, atfp.colorSpaceXform()); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); @@ -123,7 +102,7 @@ void GrGLAlphaThresholdFragmentProcessor::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("vec2 mask_coord = %s;", maskCoords2D.c_str()); fragBuilder->codeAppend("vec4 input_color = "); fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord", kVec2f_GrSLType, - &colorSpaceHelper); + &fColorSpaceHelper); fragBuilder->codeAppend(";"); fragBuilder->codeAppend("vec4 mask_color = "); fragBuilder->appendTextureLookup(args.fTexSamplers[1], "mask_coord"); @@ -153,12 +132,12 @@ void GrGLAlphaThresholdFragmentProcessor::emitCode(EmitArgs& args) { } void GrGLAlphaThresholdFragmentProcessor::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) { + const GrFragmentProcessor& proc) { const GrAlphaThresholdFragmentProcessor& atfp = proc.cast(); pdman.set1f(fInnerThresholdVar, atfp.innerThreshold()); pdman.set1f(fOuterThresholdVar, atfp.outerThreshold()); if (SkToBool(atfp.colorSpaceXform())) { - pdman.setSkMatrix44(fColorSpaceXformVar, atfp.colorSpaceXform()->srcToDst()); + fColorSpaceHelper.setData(pdman, atfp.colorSpaceXform()); } } @@ -166,11 +145,13 @@ void GrGLAlphaThresholdFragmentProcessor::onSetData(const GrGLSLProgramDataManag GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrAlphaThresholdFragmentProcessor); +#if GR_TEST_UTILS sk_sp GrAlphaThresholdFragmentProcessor::TestCreate(GrProcessorTestData* d) { - GrTexture* bmpTex = d->fTextures[GrProcessorUnitTest::kSkiaPMTextureIdx]; - GrTexture* maskTex = d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx]; - float innerThresh = d->fRandom->nextUScalar1(); - float outerThresh = d->fRandom->nextUScalar1(); + sk_sp bmpProxy = d->textureProxy(GrProcessorUnitTest::kSkiaPMTextureIdx); + sk_sp maskProxy = d->textureProxy(GrProcessorUnitTest::kAlphaTextureIdx); + // Make the inner and outer thresholds be in (0, 1) exclusive and be sorted correctly. + float innerThresh = d->fRandom->nextUScalar1() * .99f + 0.005f; + float outerThresh = d->fRandom->nextUScalar1() * .99f + 0.005f; const int kMaxWidth = 1000; const int kMaxHeight = 1000; uint32_t width = d->fRandom->nextULessThan(kMaxWidth); @@ -178,15 +159,19 @@ sk_sp GrAlphaThresholdFragmentProcessor::TestCreate(GrProce uint32_t x = d->fRandom->nextULessThan(kMaxWidth - width); uint32_t y = d->fRandom->nextULessThan(kMaxHeight - height); SkIRect bounds = SkIRect::MakeXYWH(x, y, width, height); - auto colorSpaceXform = GrTest::TestColorXform(d->fRandom); - return GrAlphaThresholdFragmentProcessor::Make(bmpTex, colorSpaceXform, maskTex, + sk_sp colorSpaceXform = GrTest::TestColorXform(d->fRandom); + return GrAlphaThresholdFragmentProcessor::Make(d->resourceProvider(), + std::move(bmpProxy), + std::move(colorSpaceXform), + std::move(maskProxy), innerThresh, outerThresh, bounds); } +#endif /////////////////////////////////////////////////////////////////////////////// -void GrAlphaThresholdFragmentProcessor::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrAlphaThresholdFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLAlphaThresholdFragmentProcessor::GenKey(*this, caps, b); } diff --git a/gfx/skia/skia/src/effects/GrAlphaThresholdFragmentProcessor.h b/gfx/skia/skia/src/effects/GrAlphaThresholdFragmentProcessor.h index c5b8d4ede29a..f7690d3b9791 100644 --- a/gfx/skia/skia/src/effects/GrAlphaThresholdFragmentProcessor.h +++ b/gfx/skia/skia/src/effects/GrAlphaThresholdFragmentProcessor.h @@ -20,12 +20,21 @@ class GrAlphaThresholdFragmentProcessor : public GrFragmentProcessor { public: - static sk_sp Make(GrTexture* texture, + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, sk_sp colorSpaceXform, - GrTexture* maskTexture, + sk_sp maskProxy, float innerThreshold, float outerThreshold, - const SkIRect& bounds); + const SkIRect& bounds) { + return sk_sp(new GrAlphaThresholdFragmentProcessor( + resourceProvider, + std::move(proxy), + std::move(colorSpaceXform), + std::move(maskProxy), + innerThreshold, outerThreshold, + bounds)); + } const char* name() const override { return "Alpha Threshold"; } @@ -35,31 +44,32 @@ public: GrColorSpaceXform* colorSpaceXform() const { return fColorSpaceXform.get(); } private: - GrAlphaThresholdFragmentProcessor(GrTexture* texture, + static OptimizationFlags OptFlags(float outerThreshold); + + GrAlphaThresholdFragmentProcessor(GrResourceProvider*, + sk_sp proxy, sk_sp colorSpaceXform, - GrTexture* maskTexture, + sk_sp maskProxy, float innerThreshold, float outerThreshold, const SkIRect& bounds); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; float fInnerThreshold; float fOuterThreshold; GrCoordTransform fImageCoordTransform; - GrTextureAccess fImageTextureAccess; + TextureSampler fImageTextureSampler; // Color space transform is for the image (not the mask) sk_sp fColorSpaceXform; GrCoordTransform fMaskCoordTransform; - GrTextureAccess fMaskTextureAccess; + TextureSampler fMaskTextureSampler; typedef GrFragmentProcessor INHERITED; }; diff --git a/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.cpp b/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.cpp index 3e80ef517c86..56dd45625354 100644 --- a/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.cpp +++ b/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.cpp @@ -10,9 +10,7 @@ #if SK_SUPPORT_GPU #include "GrContext.h" -#include "GrInvariantOutput.h" -#include "GrTextureProvider.h" - +#include "GrResourceProvider.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" @@ -25,7 +23,7 @@ public: void emitCode(EmitArgs&) override; protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fDataUniform; @@ -47,7 +45,6 @@ void GrCircleBlurFragmentProcessor::GLSLProcessor::emitCode(EmitArgs& args) { &dataName); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const char *fragmentPos = fragBuilder->fragmentPosition(); if (args.fInputColor) { fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor); @@ -57,9 +54,9 @@ void GrCircleBlurFragmentProcessor::GLSLProcessor::emitCode(EmitArgs& args) { // We just want to compute "(length(vec) - %s.z + 0.5) * %s.w" but need to rearrange // for precision. - fragBuilder->codeAppendf("vec2 vec = vec2( (%s.x - %s.x) * %s.w , (%s.y - %s.y) * %s.w );", - fragmentPos, dataName, dataName, - fragmentPos, dataName, dataName); + fragBuilder->codeAppendf("vec2 vec = vec2( (sk_FragCoord.x - %s.x) * %s.w, " + "(sk_FragCoord.y - %s.y) * %s.w );", + dataName, dataName, dataName, dataName); fragBuilder->codeAppendf("float dist = length(vec) + (0.5 - %s.z) * %s.w;", dataName, dataName); @@ -71,7 +68,7 @@ void GrCircleBlurFragmentProcessor::GLSLProcessor::emitCode(EmitArgs& args) { } void GrCircleBlurFragmentProcessor::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) { + const GrFragmentProcessor& proc) { const GrCircleBlurFragmentProcessor& cbfp = proc.cast(); const SkRect& circle = cbfp.fCircle; @@ -85,33 +82,31 @@ void GrCircleBlurFragmentProcessor::GLSLProcessor::onSetData(const GrGLSLProgram /////////////////////////////////////////////////////////////////////////////// -GrCircleBlurFragmentProcessor::GrCircleBlurFragmentProcessor(const SkRect& circle, +GrCircleBlurFragmentProcessor::GrCircleBlurFragmentProcessor(GrResourceProvider* resourceProvider, + const SkRect& circle, float textureRadius, float solidRadius, - GrTexture* blurProfile) - : fCircle(circle) - , fSolidRadius(solidRadius) - , fTextureRadius(textureRadius) - , fBlurProfileAccess(blurProfile, GrTextureParams::kBilerp_FilterMode) { + sk_sp blurProfile) + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fCircle(circle) + , fSolidRadius(solidRadius) + , fTextureRadius(textureRadius) + , fBlurProfileSampler(resourceProvider, std::move(blurProfile), + GrSamplerParams::kBilerp_FilterMode) { this->initClassID(); - this->addTextureAccess(&fBlurProfileAccess); - this->setWillReadFragmentPosition(); + this->addTextureSampler(&fBlurProfileSampler); } GrGLSLFragmentProcessor* GrCircleBlurFragmentProcessor::onCreateGLSLInstance() const { return new GLSLProcessor; } -void GrCircleBlurFragmentProcessor::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrCircleBlurFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { // The code for this processor is always the same so there is nothing to add to the key. return; } -void GrCircleBlurFragmentProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->mulByUnknownSingleComponent(); -} - // Computes an unnormalized half kernel (right side). Returns the summation of all the half kernel // values. static float make_unnormalized_half_kernel(float* halfKernel, int halfKernelSize, float sigma) { @@ -265,8 +260,10 @@ static uint8_t* create_half_plane_profile(int profileWidth) { return profile; } -static GrTexture* create_profile_texture(GrTextureProvider* textureProvider, const SkRect& circle, - float sigma, float* solidRadius, float* textureRadius) { +static sk_sp create_profile_texture(GrResourceProvider* resourceProvider, + const SkRect& circle, + float sigma, + float* solidRadius, float* textureRadius) { float circleR = circle.width() / 2.0f; // Profile textures are cached by the ratio of sigma to circle radius and by the size of the // profile texture (binned by powers of 2). @@ -302,7 +299,7 @@ static GrTexture* create_profile_texture(GrTextureProvider* textureProvider, con builder[0] = sigmaToCircleRRatioFixed; builder.finish(); - GrTexture *blurProfile = textureProvider->findAndRefTextureByUniqueKey(key); + sk_sp blurProfile = resourceProvider->findProxyByUniqueKey(key); if (!blurProfile) { static constexpr int kProfileTextureWidth = 512; GrSurfaceDesc texDesc; @@ -310,7 +307,7 @@ static GrTexture* create_profile_texture(GrTextureProvider* textureProvider, con texDesc.fHeight = 1; texDesc.fConfig = kAlpha_8_GrPixelConfig; - SkAutoTDeleteArray profile(nullptr); + std::unique_ptr profile(nullptr); if (useHalfPlaneApprox) { profile.reset(create_half_plane_profile(kProfileTextureWidth)); } else { @@ -320,10 +317,13 @@ static GrTexture* create_profile_texture(GrTextureProvider* textureProvider, con kProfileTextureWidth)); } - blurProfile = textureProvider->createTexture(texDesc, SkBudgeted::kYes, profile.get(), 0); - if (blurProfile) { - textureProvider->assignUniqueKeyToTexture(key, blurProfile); + blurProfile = GrSurfaceProxy::MakeDeferred(resourceProvider, + texDesc, SkBudgeted::kYes, profile.get(), 0); + if (!blurProfile) { + return nullptr; } + + resourceProvider->assignUniqueKeyToProxy(key, blurProfile.get()); } return blurProfile; @@ -331,28 +331,32 @@ static GrTexture* create_profile_texture(GrTextureProvider* textureProvider, con ////////////////////////////////////////////////////////////////////////////// -sk_sp GrCircleBlurFragmentProcessor::Make(GrTextureProvider*textureProvider, +sk_sp GrCircleBlurFragmentProcessor::Make(GrResourceProvider* resourceProvider, const SkRect& circle, float sigma) { float solidRadius; float textureRadius; - SkAutoTUnref profile(create_profile_texture(textureProvider, circle, sigma, - &solidRadius, &textureRadius)); + sk_sp profile(create_profile_texture(resourceProvider, circle, sigma, + &solidRadius, &textureRadius)); if (!profile) { return nullptr; } - return sk_sp(new GrCircleBlurFragmentProcessor(circle, textureRadius, - solidRadius, profile)); + return sk_sp(new GrCircleBlurFragmentProcessor(resourceProvider, + circle, + textureRadius, solidRadius, + std::move(profile))); } ////////////////////////////////////////////////////////////////////////////// GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleBlurFragmentProcessor); +#if GR_TEST_UTILS sk_sp GrCircleBlurFragmentProcessor::TestCreate(GrProcessorTestData* d) { SkScalar wh = d->fRandom->nextRangeScalar(100.f, 1000.f); SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f); SkRect circle = SkRect::MakeWH(wh, wh); - return GrCircleBlurFragmentProcessor::Make(d->fContext->textureProvider(), circle, sigma); + return GrCircleBlurFragmentProcessor::Make(d->resourceProvider(), circle, sigma); } +#endif #endif diff --git a/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.h b/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.h index 66072887da2e..c6cf3ba92315 100644 --- a/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.h +++ b/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.h @@ -16,7 +16,7 @@ #include "GrFragmentProcessor.h" #include "GrProcessorUnitTest.h" -class GrTextureProvider; +class GrResourceProvider; // This FP handles the special case of a blurred circle. It uses a 1D // profile that is just rotated about the origin of the circle. @@ -34,8 +34,7 @@ public: return str; } - static sk_sp Make(GrTextureProvider*textureProvider, - const SkRect& circle, float sigma); + static sk_sp Make(GrResourceProvider*, const SkRect& circle, float sigma); private: // This nested GLSL processor implementation is defined in the cpp file. @@ -46,12 +45,13 @@ private: * The x texture coord should map from 0 to 1 across the radius range of solidRadius to * solidRadius + textureRadius. */ - GrCircleBlurFragmentProcessor(const SkRect& circle, float textureRadius, float innerRadius, - GrTexture* blurProfile); + GrCircleBlurFragmentProcessor(GrResourceProvider*, const SkRect& circle, + float textureRadius, float innerRadius, + sk_sp blurProfile); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; bool onIsEqual(const GrFragmentProcessor& other) const override { const GrCircleBlurFragmentProcessor& cbfp = other.cast(); @@ -59,12 +59,10 @@ private: fTextureRadius == cbfp.fTextureRadius; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - SkRect fCircle; SkScalar fSolidRadius; float fTextureRadius; - GrTextureAccess fBlurProfileAccess; + TextureSampler fBlurProfileSampler; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; diff --git a/gfx/skia/skia/src/effects/Sk1DPathEffect.cpp b/gfx/skia/skia/src/effects/Sk1DPathEffect.cpp index 26cd046aa8ad..37cd13052e47 100644 --- a/gfx/skia/skia/src/effects/Sk1DPathEffect.cpp +++ b/gfx/skia/skia/src/effects/Sk1DPathEffect.cpp @@ -205,7 +205,8 @@ void SkPath1DPathEffect::toString(SkString* str) const { sk_sp SkPath1DPathEffect::Make(const SkPath& path, SkScalar advance, SkScalar phase, Style style) { - if (advance <= 0 || path.isEmpty()) { + if (advance <= 0 || !SkScalarIsFinite(advance) || + !SkScalarIsFinite(phase) || path.isEmpty()) { return nullptr; } return sk_sp(new SkPath1DPathEffect(path, advance, phase, style)); diff --git a/gfx/skia/skia/src/effects/SkAlphaThresholdFilter.cpp b/gfx/skia/skia/src/effects/SkAlphaThresholdFilter.cpp index bbae2e1552ef..35328d522754 100644 --- a/gfx/skia/skia/src/effects/SkAlphaThresholdFilter.cpp +++ b/gfx/skia/skia/src/effects/SkAlphaThresholdFilter.cpp @@ -16,8 +16,9 @@ #if SK_SUPPORT_GPU #include "GrAlphaThresholdFragmentProcessor.h" #include "GrContext.h" -#include "GrDrawContext.h" #include "GrFixedClip.h" +#include "GrRenderTargetContext.h" +#include "GrTextureProxy.h" #endif class SK_API SkAlphaThresholdFilterImpl : public SkImageFilter { @@ -36,8 +37,12 @@ protected: sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + #if SK_SUPPORT_GPU - sk_sp createMaskTexture(GrContext*, const SkMatrix&, const SkIRect& bounds) const; + sk_sp createMaskTexture(GrContext*, + const SkMatrix&, + const SkIRect& bounds) const; #endif private: @@ -93,32 +98,29 @@ SkAlphaThresholdFilterImpl::SkAlphaThresholdFilterImpl(const SkRegion& region, } #if SK_SUPPORT_GPU -sk_sp SkAlphaThresholdFilterImpl::createMaskTexture(GrContext* context, - const SkMatrix& inMatrix, - const SkIRect& bounds) const { +sk_sp SkAlphaThresholdFilterImpl::createMaskTexture(GrContext* context, + const SkMatrix& inMatrix, + const SkIRect& bounds) const { - sk_sp drawContext(context->makeDrawContextWithFallback(SkBackingFit::kApprox, - bounds.width(), - bounds.height(), - kAlpha_8_GrPixelConfig, - nullptr)); - if (!drawContext) { + sk_sp rtContext(context->makeDeferredRenderTargetContextWithFallback( + SkBackingFit::kApprox, bounds.width(), bounds.height(), kAlpha_8_GrPixelConfig, nullptr)); + if (!rtContext) { return nullptr; } - GrPaint grPaint; - grPaint.setPorterDuffXPFactory(SkBlendMode::kSrc); + GrPaint paint; + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); SkRegion::Iterator iter(fRegion); - drawContext->clear(nullptr, 0x0, true); + rtContext->clear(nullptr, 0x0, true); GrFixedClip clip(SkIRect::MakeWH(bounds.width(), bounds.height())); while (!iter.done()) { SkRect rect = SkRect::Make(iter.rect()); - drawContext->drawRect(clip, grPaint, inMatrix, rect); + rtContext->drawRect(clip, std::move(paint), GrAA::kNo, inMatrix, rect); iter.next(); } - return drawContext->asTexture(); + return rtContext->asTextureProxyRef(); } #endif @@ -150,8 +152,8 @@ sk_sp SkAlphaThresholdFilterImpl::onFilterImage(SkSpecialImage* if (source->isTextureBacked()) { GrContext* context = source->getContext(); - sk_sp inputTexture(input->asTextureRef(context)); - SkASSERT(inputTexture); + sk_sp inputProxy(input->asTextureProxyRef(context)); + SkASSERT(inputProxy); offset->fX = bounds.left(); offset->fY = bounds.top(); @@ -161,21 +163,23 @@ sk_sp SkAlphaThresholdFilterImpl::onFilterImage(SkSpecialImage* SkMatrix matrix(ctx.ctm()); matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); - sk_sp maskTexture(this->createMaskTexture(context, matrix, bounds)); - if (!maskTexture) { + sk_sp maskProxy(this->createMaskTexture(context, matrix, bounds)); + if (!maskProxy) { return nullptr; } const OutputProperties& outProps = ctx.outputProperties(); sk_sp colorSpaceXform = GrColorSpaceXform::Make(input->getColorSpace(), outProps.colorSpace()); + sk_sp fp(GrAlphaThresholdFragmentProcessor::Make( - inputTexture.get(), - std::move(colorSpaceXform), - maskTexture.get(), - fInnerThreshold, - fOuterThreshold, - bounds)); + context->resourceProvider(), + std::move(inputProxy), + std::move(colorSpaceXform), + std::move(maskProxy), + fInnerThreshold, + fOuterThreshold, + bounds)); if (!fp) { return nullptr; } @@ -220,8 +224,9 @@ sk_sp SkAlphaThresholdFilterImpl::onFilterImage(SkSpecialImage* U8CPU outerThreshold = (U8CPU)(fOuterThreshold * 0xFF); SkColor* dptr = dst.getAddr32(0, 0); int dstWidth = dst.width(), dstHeight = dst.height(); + SkIPoint srcOffset = { bounds.fLeft - inputOffset.fX, bounds.fTop - inputOffset.fY }; for (int y = 0; y < dstHeight; ++y) { - const SkColor* sptr = inputBM.getAddr32(bounds.fLeft, bounds.fTop+y); + const SkColor* sptr = inputBM.getAddr32(srcOffset.fX, srcOffset.fY+y); for (int x = 0; x < dstWidth; ++x) { const SkColor& source = sptr[x]; @@ -259,6 +264,18 @@ sk_sp SkAlphaThresholdFilterImpl::onFilterImage(SkSpecialImage* dst); } +sk_sp SkAlphaThresholdFilterImpl::onMakeColorSpace(SkColorSpaceXformer* xformer) +const { + SkASSERT(1 == this->countInputs()); + if (!this->getInput(0)) { + return sk_ref_sp(const_cast(this)); + } + + sk_sp input = this->getInput(0)->makeColorSpace(xformer); + return SkAlphaThresholdFilter::Make(fRegion, fInnerThreshold, fOuterThreshold, + std::move(input), this->getCropRectIfSet()); +} + #ifndef SK_IGNORE_TO_STRING void SkAlphaThresholdFilterImpl::toString(SkString* str) const { str->appendf("SkAlphaThresholdImageFilter: ("); diff --git a/gfx/skia/skia/src/effects/SkArithmeticImageFilter.cpp b/gfx/skia/skia/src/effects/SkArithmeticImageFilter.cpp new file mode 100644 index 000000000000..cf85cfafecb5 --- /dev/null +++ b/gfx/skia/skia/src/effects/SkArithmeticImageFilter.cpp @@ -0,0 +1,530 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkArithmeticImageFilter.h" +#include "SkArithmeticModePriv.h" +#include "SkCanvas.h" +#include "SkNx.h" +#include "SkReadBuffer.h" +#include "SkSpecialImage.h" +#include "SkSpecialSurface.h" +#include "SkWriteBuffer.h" +#include "SkXfermodeImageFilter.h" +#if SK_SUPPORT_GPU +#include "GrClip.h" +#include "GrContext.h" +#include "GrRenderTargetContext.h" +#include "GrTextureProxy.h" +#include "SkGr.h" +#include "effects/GrConstColorProcessor.h" +#include "effects/GrTextureDomain.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" +#endif + +class ArithmeticImageFilterImpl : public SkImageFilter { +public: + ArithmeticImageFilterImpl(float k1, float k2, float k3, float k4, bool enforcePMColor, + sk_sp inputs[2], const CropRect* cropRect) + : INHERITED(inputs, 2, cropRect), fK{k1, k2, k3, k4}, fEnforcePMColor(enforcePMColor) {} + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(ArithmeticImageFilterImpl) + +protected: + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + +#if SK_SUPPORT_GPU + sk_sp filterImageGPU(SkSpecialImage* source, + sk_sp background, + const SkIPoint& backgroundOffset, + sk_sp foreground, + const SkIPoint& foregroundOffset, + const SkIRect& bounds, + const OutputProperties& outputProperties) const; +#endif + + void flatten(SkWriteBuffer& buffer) const override { + this->INHERITED::flatten(buffer); + for (int i = 0; i < 4; ++i) { + buffer.writeScalar(fK[i]); + } + buffer.writeBool(fEnforcePMColor); + } + + void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const; + + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + +private: + const float fK[4]; + const bool fEnforcePMColor; + + friend class ::SkArithmeticImageFilter; + + typedef SkImageFilter INHERITED; +}; + +sk_sp ArithmeticImageFilterImpl::CreateProc(SkReadBuffer& buffer) { + SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2); + float k[4]; + for (int i = 0; i < 4; ++i) { + k[i] = buffer.readScalar(); + } + const bool enforcePMColor = buffer.readBool(); + return SkArithmeticImageFilter::Make(k[0], k[1], k[2], k[3], enforcePMColor, common.getInput(0), + common.getInput(1), &common.cropRect()); +} + +static Sk4f pin(float min, const Sk4f& val, float max) { + return Sk4f::Max(min, Sk4f::Min(val, max)); +} + +template +void arith_span(const float k[], SkPMColor dst[], const SkPMColor src[], int count) { + const Sk4f k1 = k[0] * (1/255.0f), + k2 = k[1], + k3 = k[2], + k4 = k[3] * 255.0f + 0.5f; + + for (int i = 0; i < count; i++) { + Sk4f s = SkNx_cast(Sk4b::Load(src+i)), + d = SkNx_cast(Sk4b::Load(dst+i)), + r = pin(0, k1*s*d + k2*s + k3*d + k4, 255); + if (EnforcePMColor) { + Sk4f a = SkNx_shuffle<3,3,3,3>(r); + r = Sk4f::Min(a, r); + } + SkNx_cast(r).store(dst+i); + } +} + +// apply mode to src==transparent (0) +template void arith_transparent(const float k[], SkPMColor dst[], int count) { + const Sk4f k3 = k[2], + k4 = k[3] * 255.0f + 0.5f; + + for (int i = 0; i < count; i++) { + Sk4f d = SkNx_cast(Sk4b::Load(dst+i)), + r = pin(0, k3*d + k4, 255); + if (EnforcePMColor) { + Sk4f a = SkNx_shuffle<3,3,3,3>(r); + r = Sk4f::Min(a, r); + } + SkNx_cast(r).store(dst+i); + } +} + +static bool intersect(SkPixmap* dst, SkPixmap* src, int srcDx, int srcDy) { + SkIRect dstR = SkIRect::MakeWH(dst->width(), dst->height()); + SkIRect srcR = SkIRect::MakeXYWH(srcDx, srcDy, src->width(), src->height()); + SkIRect sect; + if (!sect.intersect(dstR, srcR)) { + return false; + } + *dst = SkPixmap(dst->info().makeWH(sect.width(), sect.height()), + dst->addr(sect.fLeft, sect.fTop), + dst->rowBytes()); + *src = SkPixmap(src->info().makeWH(sect.width(), sect.height()), + src->addr(SkTMax(0, -srcDx), SkTMax(0, -srcDy)), + src->rowBytes()); + return true; +} + +sk_sp ArithmeticImageFilterImpl::onFilterImage(SkSpecialImage* source, + const Context& ctx, + SkIPoint* offset) const { + SkIPoint backgroundOffset = SkIPoint::Make(0, 0); + sk_sp background(this->filterInput(0, source, ctx, &backgroundOffset)); + + SkIPoint foregroundOffset = SkIPoint::Make(0, 0); + sk_sp foreground(this->filterInput(1, source, ctx, &foregroundOffset)); + + SkIRect foregroundBounds = SkIRect::EmptyIRect(); + if (foreground) { + foregroundBounds = SkIRect::MakeXYWH(foregroundOffset.x(), foregroundOffset.y(), + foreground->width(), foreground->height()); + } + + SkIRect srcBounds = SkIRect::EmptyIRect(); + if (background) { + srcBounds = SkIRect::MakeXYWH(backgroundOffset.x(), backgroundOffset.y(), + background->width(), background->height()); + } + + srcBounds.join(foregroundBounds); + if (srcBounds.isEmpty()) { + return nullptr; + } + + SkIRect bounds; + if (!this->applyCropRect(ctx, srcBounds, &bounds)) { + return nullptr; + } + + offset->fX = bounds.left(); + offset->fY = bounds.top(); + +#if SK_SUPPORT_GPU + if (source->isTextureBacked()) { + return this->filterImageGPU(source, background, backgroundOffset, foreground, + foregroundOffset, bounds, ctx.outputProperties()); + } +#endif + + sk_sp surf(source->makeSurface(ctx.outputProperties(), bounds.size())); + if (!surf) { + return nullptr; + } + + SkCanvas* canvas = surf->getCanvas(); + SkASSERT(canvas); + + canvas->clear(0x0); // can't count on background to fully clear the background + canvas->translate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); + + if (background) { + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); + background->draw(canvas, SkIntToScalar(backgroundOffset.fX), + SkIntToScalar(backgroundOffset.fY), &paint); + } + + this->drawForeground(canvas, foreground.get(), foregroundBounds); + + return surf->makeImageSnapshot(); +} + +#if SK_SUPPORT_GPU + +namespace { +class ArithmeticFP : public GrFragmentProcessor { +public: + static sk_sp Make(float k1, float k2, float k3, float k4, + bool enforcePMColor, sk_sp dst) { + return sk_sp( + new ArithmeticFP(k1, k2, k3, k4, enforcePMColor, std::move(dst))); + } + + ~ArithmeticFP() override {} + + const char* name() const override { return "Arithmetic"; } + + SkString dumpInfo() const override { + SkString str; + str.appendf("K1: %.2f K2: %.2f K3: %.2f K4: %.2f", fK1, fK2, fK3, fK4); + return str; + } + + float k1() const { return fK1; } + float k2() const { return fK2; } + float k3() const { return fK3; } + float k4() const { return fK4; } + bool enforcePMColor() const { return fEnforcePMColor; } + +private: + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { + class GLSLFP : public GrGLSLFragmentProcessor { + public: + void emitCode(EmitArgs& args) override { + const ArithmeticFP& arith = args.fFp.cast(); + + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + SkString dstColor("dstColor"); + this->emitChild(0, nullptr, &dstColor, args); + + fKUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType, + kDefault_GrSLPrecision, "k"); + const char* kUni = args.fUniformHandler->getUniformCStr(fKUni); + + // We don't try to optimize for this case at all + if (!args.fInputColor) { + fragBuilder->codeAppend("const vec4 src = vec4(1);"); + } else { + fragBuilder->codeAppendf("vec4 src = %s;", args.fInputColor); + } + + fragBuilder->codeAppendf("vec4 dst = %s;", dstColor.c_str()); + fragBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;", + args.fOutputColor, kUni, kUni, kUni, kUni); + fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", args.fOutputColor, + args.fOutputColor); + if (arith.fEnforcePMColor) { + fragBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);", args.fOutputColor, + args.fOutputColor, args.fOutputColor); + } + } + + protected: + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) override { + const ArithmeticFP& arith = proc.cast(); + pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); + } + + private: + GrGLSLProgramDataManager::UniformHandle fKUni; + }; + return new GLSLFP; + } + + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { + b->add32(fEnforcePMColor ? 1 : 0); + } + + bool onIsEqual(const GrFragmentProcessor& fpBase) const override { + const ArithmeticFP& fp = fpBase.cast(); + return fK1 == fp.fK1 && fK2 == fp.fK2 && fK3 == fp.fK3 && fK4 == fp.fK4 && + fEnforcePMColor == fp.fEnforcePMColor; + } + + // This could implement the const input -> const output optimization but it's unlikely to help. + ArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor, + sk_sp dst) + : INHERITED(kNone_OptimizationFlags) + , fK1(k1) + , fK2(k2) + , fK3(k3) + , fK4(k4) + , fEnforcePMColor(enforcePMColor) { + this->initClassID(); + SkASSERT(dst); + SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(dst)); + SkASSERT(0 == dstIndex); + } + + float fK1, fK2, fK3, fK4; + bool fEnforcePMColor; + + GR_DECLARE_FRAGMENT_PROCESSOR_TEST; + typedef GrFragmentProcessor INHERITED; +}; +} + +#if GR_TEST_UTILS +sk_sp ArithmeticFP::TestCreate(GrProcessorTestData* d) { + float k1 = d->fRandom->nextF(); + float k2 = d->fRandom->nextF(); + float k3 = d->fRandom->nextF(); + float k4 = d->fRandom->nextF(); + bool enforcePMColor = d->fRandom->nextBool(); + + sk_sp dst(GrProcessorUnitTest::MakeChildFP(d)); + return ArithmeticFP::Make(k1, k2, k3, k4, enforcePMColor, std::move(dst)); +} +#endif + +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ArithmeticFP); + +sk_sp ArithmeticImageFilterImpl::filterImageGPU( + SkSpecialImage* source, + sk_sp + background, + const SkIPoint& backgroundOffset, + sk_sp + foreground, + const SkIPoint& foregroundOffset, + const SkIRect& bounds, + const OutputProperties& outputProperties) const { + SkASSERT(source->isTextureBacked()); + + GrContext* context = source->getContext(); + + sk_sp backgroundProxy, foregroundProxy; + + if (background) { + backgroundProxy = background->asTextureProxyRef(context); + } + + if (foreground) { + foregroundProxy = foreground->asTextureProxyRef(context); + } + + GrPaint paint; + sk_sp bgFP; + + if (backgroundProxy) { + SkMatrix backgroundMatrix = SkMatrix::MakeTrans(-SkIntToScalar(backgroundOffset.fX), + -SkIntToScalar(backgroundOffset.fY)); + sk_sp bgXform = + GrColorSpaceXform::Make(background->getColorSpace(), outputProperties.colorSpace()); + bgFP = GrTextureDomainEffect::Make( + context->resourceProvider(), std::move(backgroundProxy), std::move(bgXform), + backgroundMatrix, GrTextureDomain::MakeTexelDomain(background->subset()), + GrTextureDomain::kDecal_Mode, GrSamplerParams::kNone_FilterMode); + } else { + bgFP = GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), + GrConstColorProcessor::kIgnore_InputMode); + } + + if (foregroundProxy) { + SkMatrix foregroundMatrix = SkMatrix::MakeTrans(-SkIntToScalar(foregroundOffset.fX), + -SkIntToScalar(foregroundOffset.fY)); + sk_sp fgXform = + GrColorSpaceXform::Make(foreground->getColorSpace(), outputProperties.colorSpace()); + sk_sp foregroundFP; + + foregroundFP = GrTextureDomainEffect::Make( + context->resourceProvider(), std::move(foregroundProxy), std::move(fgXform), + foregroundMatrix, GrTextureDomain::MakeTexelDomain(foreground->subset()), + GrTextureDomain::kDecal_Mode, GrSamplerParams::kNone_FilterMode); + + paint.addColorFragmentProcessor(std::move(foregroundFP)); + + sk_sp xferFP = + ArithmeticFP::Make(fK[0], fK[1], fK[2], fK[3], fEnforcePMColor, std::move(bgFP)); + + // A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed + if (xferFP) { + paint.addColorFragmentProcessor(std::move(xferFP)); + } + } else { + paint.addColorFragmentProcessor(std::move(bgFP)); + } + + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + + sk_sp renderTargetContext(context->makeDeferredRenderTargetContext( + SkBackingFit::kApprox, bounds.width(), bounds.height(), + GrRenderableConfigForColorSpace(outputProperties.colorSpace()), + sk_ref_sp(outputProperties.colorSpace()))); + if (!renderTargetContext) { + return nullptr; + } + paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); + + SkMatrix matrix; + matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); + renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, + SkRect::Make(bounds)); + + return SkSpecialImage::MakeDeferredFromGpu(context, + SkIRect::MakeWH(bounds.width(), bounds.height()), + kNeedNewImageUniqueID_SpecialImage, + renderTargetContext->asTextureProxyRef(), + renderTargetContext->refColorSpace()); +} +#endif + +void ArithmeticImageFilterImpl::drawForeground(SkCanvas* canvas, SkSpecialImage* img, + const SkIRect& fgBounds) const { + SkPixmap dst; + if (!canvas->peekPixels(&dst)) { + return; + } + + const SkMatrix& ctm = canvas->getTotalMatrix(); + SkASSERT(ctm.getType() <= SkMatrix::kTranslate_Mask); + const int dx = SkScalarRoundToInt(ctm.getTranslateX()); + const int dy = SkScalarRoundToInt(ctm.getTranslateY()); + + if (img) { + SkBitmap srcBM; + SkPixmap src; + if (!img->getROPixels(&srcBM)) { + return; + } + srcBM.lockPixels(); + if (!srcBM.peekPixels(&src)) { + return; + } + + auto proc = fEnforcePMColor ? arith_span : arith_span; + SkPixmap tmpDst = dst; + if (intersect(&tmpDst, &src, fgBounds.fLeft + dx, fgBounds.fTop + dy)) { + for (int y = 0; y < tmpDst.height(); ++y) { + proc(fK, tmpDst.writable_addr32(0, y), src.addr32(0, y), tmpDst.width()); + } + } + } + + // Now apply the mode with transparent-color to the outside of the fg image + SkRegion outside(SkIRect::MakeWH(dst.width(), dst.height())); + outside.op(fgBounds.makeOffset(dx, dy), SkRegion::kDifference_Op); + auto proc = fEnforcePMColor ? arith_transparent : arith_transparent; + for (SkRegion::Iterator iter(outside); !iter.done(); iter.next()) { + const SkIRect r = iter.rect(); + for (int y = r.fTop; y < r.fBottom; ++y) { + proc(fK, dst.writable_addr32(r.fLeft, y), r.width()); + } + } +} + +sk_sp ArithmeticImageFilterImpl::onMakeColorSpace(SkColorSpaceXformer* xformer) +const { + SkASSERT(2 == this->countInputs()); + if (!this->getInput(0) && !this->getInput(1)) { + return sk_ref_sp(const_cast(this)); + } + + sk_sp background = + this->getInput(0) ? this->getInput(0)->makeColorSpace(xformer) : nullptr; + sk_sp foreground = + this->getInput(1) ? this->getInput(1)->makeColorSpace(xformer) : nullptr; + return SkArithmeticImageFilter::Make(fK[0], fK[1], fK[2], fK[3], fEnforcePMColor, + std::move(background), std::move(foreground), + getCropRectIfSet()); +} + +#ifndef SK_IGNORE_TO_STRING +void ArithmeticImageFilterImpl::toString(SkString* str) const { + str->appendf("SkArithmeticImageFilter: ("); + str->appendf("K[]: (%f %f %f %f)", fK[0], fK[1], fK[2], fK[3]); + if (this->getInput(0)) { + str->appendf("foreground: ("); + this->getInput(0)->toString(str); + str->appendf(")"); + } + if (this->getInput(1)) { + str->appendf("background: ("); + this->getInput(1)->toString(str); + str->appendf(")"); + } + str->append(")"); +} +#endif + +sk_sp SkArithmeticImageFilter::Make(float k1, float k2, float k3, float k4, + bool enforcePMColor, + sk_sp background, + sk_sp foreground, + const SkImageFilter::CropRect* crop) { + if (!SkScalarIsFinite(k1) || !SkScalarIsFinite(k2) || !SkScalarIsFinite(k3) || + !SkScalarIsFinite(k4)) { + return nullptr; + } + + // are we nearly some other "std" mode? + int mode = -1; // illegal mode + if (SkScalarNearlyZero(k1) && SkScalarNearlyEqual(k2, SK_Scalar1) && SkScalarNearlyZero(k3) && + SkScalarNearlyZero(k4)) { + mode = (int)SkBlendMode::kSrc; + } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) && + SkScalarNearlyEqual(k3, SK_Scalar1) && SkScalarNearlyZero(k4)) { + mode = (int)SkBlendMode::kDst; + } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) && SkScalarNearlyZero(k3) && + SkScalarNearlyZero(k4)) { + mode = (int)SkBlendMode::kClear; + } + if (mode >= 0) { + return SkXfermodeImageFilter::Make((SkBlendMode)mode, std::move(background), + std::move(foreground), crop); + } + + sk_sp inputs[2] = {std::move(background), std::move(foreground)}; + return sk_sp( + new ArithmeticImageFilterImpl(k1, k2, k3, k4, enforcePMColor, inputs, crop)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(ArithmeticImageFilterImpl) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END diff --git a/gfx/skia/skia/src/effects/SkArithmeticMode.cpp b/gfx/skia/skia/src/effects/SkArithmeticMode.cpp index 62595cf1eef3..d604a12fbbda 100644 --- a/gfx/skia/skia/src/effects/SkArithmeticMode.cpp +++ b/gfx/skia/skia/src/effects/SkArithmeticMode.cpp @@ -6,17 +6,11 @@ */ #include "SkArithmeticModePriv.h" -#include "SkColorPriv.h" -#include "SkNx.h" -#include "SkRasterPipeline.h" #include "SkReadBuffer.h" -#include "SkString.h" -#include "SkUnPreMultiply.h" -#include "SkWriteBuffer.h" -#if SK_SUPPORT_GPU -#include "SkArithmeticMode_gpu.h" -#endif +// This class only exists to unflatten instances that were serialized into old pictures as part of +// SkXfermodeImageFilter before the advent of SkBlendMode. Those image filters will now be +// transformed to SkArithmeticImageFilter which does not use this class in its implementation. class SkArithmeticMode_scalar : public SkXfermode { public: SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, @@ -28,17 +22,15 @@ public: fEnforcePMColor = enforcePMColor; } - void xfer32(SkPMColor[], const SkPMColor[], int count, const SkAlpha[]) const override; + void xfer32(SkPMColor[], const SkPMColor[], int count, const SkAlpha[]) const override { + SkFAIL("This should never be called."); + } SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar) -#if SK_SUPPORT_GPU - sk_sp makeFragmentProcessorForImageFilter( - sk_sp dst) const override; - sk_sp asXPFactory() const override; -#endif - + // This is used to extract the arithmetic params into an SkArithmeticImageFilter. Afterwards, + // this object is destroyed and arithemtic blending is implemented directly in the image filter. bool isArithmetic(SkArithmeticParams* params) const override { if (params) { memcpy(params->fK, fK, 4 * sizeof(float)); @@ -48,13 +40,7 @@ public: } private: - void flatten(SkWriteBuffer& buffer) const override { - buffer.writeScalar(fK[0]); - buffer.writeScalar(fK[1]); - buffer.writeScalar(fK[2]); - buffer.writeScalar(fK[3]); - buffer.writeBool(fEnforcePMColor); - } + void flatten(SkWriteBuffer& buffer) const override { SkFAIL("This shouild never be called."); } SkScalar fK[4]; bool fEnforcePMColor; @@ -73,48 +59,9 @@ sk_sp SkArithmeticMode_scalar::CreateProc(SkReadBuffer& buffer) { return SkArithmeticMode::Make(k1, k2, k3, k4, enforcePMColor); } -void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[], - int count, const SkAlpha aaCoverage[]) const { - const Sk4f k1 = fK[0] * (1/255.0f), - k2 = fK[1], - k3 = fK[2], - k4 = fK[3] * 255.0f + 0.5f; - - auto pin = [](float min, const Sk4f& val, float max) { - return Sk4f::Max(min, Sk4f::Min(val, max)); - }; - - for (int i = 0; i < count; i++) { - if (aaCoverage && aaCoverage[i] == 0) { - continue; - } - - Sk4f s = SkNx_cast(Sk4b::Load(src+i)), - d = SkNx_cast(Sk4b::Load(dst+i)), - r = pin(0, k1*s*d + k2*s + k3*d + k4, 255); - - if (fEnforcePMColor) { - Sk4f a = SkNx_shuffle<3,3,3,3>(r); - r = Sk4f::Min(a, r); - } - - if (aaCoverage && aaCoverage[i] != 255) { - Sk4f c = aaCoverage[i] * (1/255.0f); - r = d + (r-d)*c; - } - - SkNx_cast(r).store(dst+i); - } -} - #ifndef SK_IGNORE_TO_STRING void SkArithmeticMode_scalar::toString(SkString* str) const { - str->append("SkArithmeticMode_scalar: "); - for (int i = 0; i < 4; ++i) { - str->appendScalar(fK[i]); - str->append(" "); - } - str->appendS32(fEnforcePMColor ? 1 : 0); + SkFAIL("This should never be called."); } #endif @@ -132,30 +79,6 @@ sk_sp SkArithmeticMode::Make(SkScalar k1, SkScalar k2, SkScalar k3, return sk_make_sp(k1, k2, k3, k4, enforcePMColor); } - -////////////////////////////////////////////////////////////////////////////// - -#if SK_SUPPORT_GPU -sk_sp SkArithmeticMode_scalar::makeFragmentProcessorForImageFilter( - sk_sp dst) const { - return GrArithmeticFP::Make(SkScalarToFloat(fK[0]), - SkScalarToFloat(fK[1]), - SkScalarToFloat(fK[2]), - SkScalarToFloat(fK[3]), - fEnforcePMColor, - std::move(dst)); -} - -sk_sp SkArithmeticMode_scalar::asXPFactory() const { - return GrArithmeticXPFactory::Make(SkScalarToFloat(fK[0]), - SkScalarToFloat(fK[1]), - SkScalarToFloat(fK[2]), - SkScalarToFloat(fK[3]), - fEnforcePMColor); -} - -#endif - SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticMode) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticMode_scalar) SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END diff --git a/gfx/skia/skia/src/effects/SkArithmeticModePriv.h b/gfx/skia/skia/src/effects/SkArithmeticModePriv.h index e619274d25dc..4c13a8163ed7 100644 --- a/gfx/skia/skia/src/effects/SkArithmeticModePriv.h +++ b/gfx/skia/skia/src/effects/SkArithmeticModePriv.h @@ -8,15 +8,18 @@ #ifndef SkArithmeticModePriv_DEFINED #define SkArithmeticModePriv_DEFINED -#include "SkArithmeticMode.h" +#include "SkScalar.h" +#include "SkXfermodePriv.h" + +class SkXfermode; struct SkArithmeticParams { float fK[4]; bool fEnforcePMColor; }; -#ifndef SK_SUPPORT_LEGACY_ARITHMETICMODE - +// This only exists to unflatten instances that were serialized into old pictures as part of +// SkXfermodeImageFilter before the advent of SkBlendMode. class SK_API SkArithmeticMode { public: /** @@ -28,14 +31,6 @@ public: */ static sk_sp Make(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, bool enforcePMColor = true); -#ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR - static SkXfermode* Create(SkScalar k1, SkScalar k2, - SkScalar k3, SkScalar k4, - bool enforcePMColor = true) { - return Make(k1, k2, k3, k4, enforcePMColor).release(); - } -#endif - SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP(); private: @@ -43,5 +38,3 @@ private: }; #endif - -#endif diff --git a/gfx/skia/skia/src/effects/SkArithmeticMode_gpu.cpp b/gfx/skia/skia/src/effects/SkArithmeticMode_gpu.cpp deleted file mode 100644 index d20ebbe42b1e..000000000000 --- a/gfx/skia/skia/src/effects/SkArithmeticMode_gpu.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkArithmeticMode_gpu.h" - -#if SK_SUPPORT_GPU -#include "GrContext.h" -#include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" -#include "GrProcessor.h" -#include "GrTexture.h" -#include "glsl/GrGLSLFragmentProcessor.h" -#include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLUniformHandler.h" -#include "glsl/GrGLSLXferProcessor.h" - -static void add_arithmetic_code(GrGLSLFragmentBuilder* fragBuilder, - const char* srcColor, - const char* dstColor, - const char* outputColor, - const char* kUni, - bool enforcePMColor) { - // We don't try to optimize for this case at all - if (nullptr == srcColor) { - fragBuilder->codeAppend("const vec4 src = vec4(1);"); - } else { - fragBuilder->codeAppendf("vec4 src = %s;", srcColor); - } - - fragBuilder->codeAppendf("vec4 dst = %s;", dstColor); - fragBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;", - outputColor, kUni, kUni, kUni, kUni); - fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor); - if (enforcePMColor) { - fragBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);", - outputColor, outputColor, outputColor); - } -} - -class GLArithmeticFP : public GrGLSLFragmentProcessor { -public: - void emitCode(EmitArgs& args) override { - const GrArithmeticFP& arith = args.fFp.cast(); - - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - SkString dstColor("dstColor"); - this->emitChild(0, nullptr, &dstColor, args); - - fKUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "k"); - const char* kUni = args.fUniformHandler->getUniformCStr(fKUni); - - add_arithmetic_code(fragBuilder, - args.fInputColor, - dstColor.c_str(), - args.fOutputColor, - kUni, - arith.enforcePMColor()); - } - - static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { - const GrArithmeticFP& arith = proc.cast(); - uint32_t key = arith.enforcePMColor() ? 1 : 0; - b->add32(key); - } - -protected: - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { - const GrArithmeticFP& arith = proc.cast(); - pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); - } - -private: - GrGLSLProgramDataManager::UniformHandle fKUni; - - typedef GrGLSLFragmentProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -GrArithmeticFP::GrArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor, - sk_sp dst) - : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) { - this->initClassID(); - - SkASSERT(dst); - SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(std::move(dst)); - SkASSERT(0 == dstIndex); -} - -void GrArithmeticFP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { - GLArithmeticFP::GenKey(*this, caps, b); -} - -GrGLSLFragmentProcessor* GrArithmeticFP::onCreateGLSLInstance() const { - return new GLArithmeticFP; -} - -bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& fpBase) const { - const GrArithmeticFP& fp = fpBase.cast(); - return fK1 == fp.fK1 && - fK2 == fp.fK2 && - fK3 == fp.fK3 && - fK4 == fp.fK4 && - fEnforcePMColor == fp.fEnforcePMColor; -} - -void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const { - // TODO: optimize this - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); -} - -/////////////////////////////////////////////////////////////////////////////// - -sk_sp GrArithmeticFP::TestCreate(GrProcessorTestData* d) { - float k1 = d->fRandom->nextF(); - float k2 = d->fRandom->nextF(); - float k3 = d->fRandom->nextF(); - float k4 = d->fRandom->nextF(); - bool enforcePMColor = d->fRandom->nextBool(); - - sk_sp dst(GrProcessorUnitTest::MakeChildFP(d)); - return GrArithmeticFP::Make(k1, k2, k3, k4, enforcePMColor, std::move(dst)); -} - -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP); - -/////////////////////////////////////////////////////////////////////////////// -// Xfer Processor -/////////////////////////////////////////////////////////////////////////////// - -class ArithmeticXP : public GrXferProcessor { -public: - ArithmeticXP(const DstTexture*, bool hasMixedSamples, - float k1, float k2, float k3, float k4, bool enforcePMColor); - - const char* name() const override { return "Arithmetic"; } - - GrGLSLXferProcessor* createGLSLInstance() const override; - - float k1() const { return fK1; } - float k2() const { return fK2; } - float k3() const { return fK3; } - float k4() const { return fK4; } - bool enforcePMColor() const { return fEnforcePMColor; } - -private: - GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const override; - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; - - bool onIsEqual(const GrXferProcessor& xpBase) const override { - const ArithmeticXP& xp = xpBase.cast(); - if (fK1 != xp.fK1 || - fK2 != xp.fK2 || - fK3 != xp.fK3 || - fK4 != xp.fK4 || - fEnforcePMColor != xp.fEnforcePMColor) { - return false; - } - return true; - } - - float fK1, fK2, fK3, fK4; - bool fEnforcePMColor; - - typedef GrXferProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -class GLArithmeticXP : public GrGLSLXferProcessor { -public: - GLArithmeticXP(const ArithmeticXP& arithmeticXP) - : fEnforcePMColor(arithmeticXP.enforcePMColor()) { - } - - ~GLArithmeticXP() override {} - - static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) { - const ArithmeticXP& arith = processor.cast(); - uint32_t key = arith.enforcePMColor() ? 1 : 0; - b->add32(key); - } - -private: - void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, - GrGLSLUniformHandler* uniformHandler, - const char* srcColor, - const char* srcCoverage, - const char* dstColor, - const char* outColor, - const char* outColorSecondary, - const GrXferProcessor& proc) override { - fKUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "k"); - const char* kUni = uniformHandler->getUniformCStr(fKUni); - - add_arithmetic_code(fragBuilder, srcColor, dstColor, outColor, kUni, fEnforcePMColor); - - // Apply coverage. - INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor, - outColorSecondary, proc); - } - - void onSetData(const GrGLSLProgramDataManager& pdman, - const GrXferProcessor& processor) override { - const ArithmeticXP& arith = processor.cast(); - pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); - fEnforcePMColor = arith.enforcePMColor(); - } - - GrGLSLProgramDataManager::UniformHandle fKUni; - bool fEnforcePMColor; - - typedef GrGLSLXferProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -ArithmeticXP::ArithmeticXP(const DstTexture* dstTexture, bool hasMixedSamples, - float k1, float k2, float k3, float k4, bool enforcePMColor) - : INHERITED(dstTexture, true, hasMixedSamples) - , fK1(k1) - , fK2(k2) - , fK3(k3) - , fK4(k4) - , fEnforcePMColor(enforcePMColor) { - this->initClassID(); -} - -void ArithmeticXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { - GLArithmeticXP::GenKey(*this, caps, b); -} - -GrGLSLXferProcessor* ArithmeticXP::createGLSLInstance() const { return new GLArithmeticXP(*this); } - -GrXferProcessor::OptFlags ArithmeticXP::onGetOptimizations( - const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const { - return GrXferProcessor::kNone_OptFlags; -} - -/////////////////////////////////////////////////////////////////////////////// - -GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float k4, - bool enforcePMColor) - : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) { - this->initClassID(); -} - -GrXferProcessor* -GrArithmeticXPFactory::onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture* dstTexture) const { - return new ArithmeticXP(dstTexture, hasMixedSamples, fK1, fK2, fK3, fK4, fEnforcePMColor); -} - - -void GrArithmeticXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - InvariantBlendedColor* blendedColor) const { - blendedColor->fWillBlendWithDst = true; - - // TODO: We could try to optimize this more. For example if fK1 and fK3 are zero, then we won't - // be blending the color with dst at all so we can know what the output color is (up to the - // valid color components passed in). - blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; -} - -GR_DEFINE_XP_FACTORY_TEST(GrArithmeticXPFactory); - -sk_sp GrArithmeticXPFactory::TestCreate(GrProcessorTestData* d) { - float k1 = d->fRandom->nextF(); - float k2 = d->fRandom->nextF(); - float k3 = d->fRandom->nextF(); - float k4 = d->fRandom->nextF(); - bool enforcePMColor = d->fRandom->nextBool(); - - return GrArithmeticXPFactory::Make(k1, k2, k3, k4, enforcePMColor); -} - -#endif diff --git a/gfx/skia/skia/src/effects/SkArithmeticMode_gpu.h b/gfx/skia/skia/src/effects/SkArithmeticMode_gpu.h deleted file mode 100644 index 4704399d24c4..000000000000 --- a/gfx/skia/skia/src/effects/SkArithmeticMode_gpu.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkArithmeticMode_gpu_DEFINED -#define SkArithmeticMode_gpu_DEFINED - -#include "SkTypes.h" - -#if SK_SUPPORT_GPU - -#include "GrCaps.h" -#include "GrCoordTransform.h" -#include "GrFragmentProcessor.h" -#include "GrTextureAccess.h" -#include "GrTypes.h" -#include "GrXferProcessor.h" - -class GrInvariantOutput; -class GrProcOptInfo; -class GrTexture; - -/////////////////////////////////////////////////////////////////////////////// -// Fragment Processor -/////////////////////////////////////////////////////////////////////////////// - -class GrGLArtithmeticFP; - -class GrArithmeticFP : public GrFragmentProcessor { -public: - static sk_sp Make(float k1, float k2, float k3, float k4, - bool enforcePMColor, sk_sp dst) { - return sk_sp(new GrArithmeticFP(k1, k2, k3, k4, enforcePMColor, - std::move(dst))); - } - - ~GrArithmeticFP() override {} - - const char* name() const override { return "Arithmetic"; } - - SkString dumpInfo() const override { - SkString str; - str.appendf("K1: %.2f K2: %.2f K3: %.2f K4: %.2f", fK1, fK2, fK3, fK4); - return str; - } - - float k1() const { return fK1; } - float k2() const { return fK2; } - float k3() const { return fK3; } - float k4() const { return fK4; } - bool enforcePMColor() const { return fEnforcePMColor; } - -private: - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; - - bool onIsEqual(const GrFragmentProcessor&) const override; - - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - GrArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor, - sk_sp dst); - - float fK1, fK2, fK3, fK4; - bool fEnforcePMColor; - - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - typedef GrFragmentProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Xfer Processor -/////////////////////////////////////////////////////////////////////////////// - -class GrArithmeticXPFactory : public GrXPFactory { -public: - static sk_sp Make(float k1, float k2, float k3, float k4, bool enforcePMColor) { - return sk_sp(new GrArithmeticXPFactory(k1, k2, k3, k4, enforcePMColor)); - } - - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - GrXPFactory::InvariantBlendedColor*) const override; - -private: - GrArithmeticXPFactory(float k1, float k2, float k3, float k4, bool enforcePMColor); - - GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture*) const override; - - bool onWillReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const override { - return true; - } - - bool onIsEqual(const GrXPFactory& xpfBase) const override { - const GrArithmeticXPFactory& xpf = xpfBase.cast(); - if (fK1 != xpf.fK1 || - fK2 != xpf.fK2 || - fK3 != xpf.fK3 || - fK4 != xpf.fK4 || - fEnforcePMColor != xpf.fEnforcePMColor) { - return false; - } - return true; - } - - GR_DECLARE_XP_FACTORY_TEST; - - float fK1, fK2, fK3, fK4; - bool fEnforcePMColor; - - typedef GrXPFactory INHERITED; -}; - -#endif -#endif diff --git a/gfx/skia/skia/src/effects/SkBlurDrawLooper.cpp b/gfx/skia/skia/src/effects/SkBlurDrawLooper.cpp deleted file mode 100644 index 30583747c9c1..000000000000 --- a/gfx/skia/skia/src/effects/SkBlurDrawLooper.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBlurDrawLooper.h" -#include "SkBlurMask.h" // just for SkBlurMask::ConvertRadiusToSigma -#include "SkBlurMaskFilter.h" -#include "SkCanvas.h" -#include "SkColorFilter.h" -#include "SkReadBuffer.h" -#include "SkWriteBuffer.h" -#include "SkMaskFilter.h" -#include "SkPaint.h" -#include "SkString.h" -#include "SkStringUtils.h" - -SkBlurDrawLooper::SkBlurDrawLooper(SkColor color, SkScalar sigma, - SkScalar dx, SkScalar dy, uint32_t flags) { - this->init(sigma, dx, dy, color, flags); -} - -// only call from constructor -void SkBlurDrawLooper::initEffects() { - SkASSERT(fBlurFlags <= kAll_BlurFlag); - if (fSigma > 0) { - uint32_t flags = fBlurFlags & kIgnoreTransform_BlurFlag ? - SkBlurMaskFilter::kIgnoreTransform_BlurFlag : - SkBlurMaskFilter::kNone_BlurFlag; - - flags |= fBlurFlags & kHighQuality_BlurFlag ? - SkBlurMaskFilter::kHighQuality_BlurFlag : - SkBlurMaskFilter::kNone_BlurFlag; - - fBlur = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, fSigma, flags); - } else { - fBlur = nullptr; - } - - if (fBlurFlags & kOverrideColor_BlurFlag) { - // Set alpha to 1 for the override since transparency will already - // be baked into the blurred mask. - SkColor opaqueColor = SkColorSetA(fBlurColor, 255); - //The SrcIn xfer mode will multiply 'color' by the incoming alpha - fColorFilter = SkColorFilter::MakeModeFilter(opaqueColor, SkXfermode::kSrcIn_Mode); - } else { - fColorFilter = nullptr; - } -} - -void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy, - SkColor color, uint32_t flags) { - fSigma = sigma; - fDx = dx; - fDy = dy; - fBlurColor = color; - fBlurFlags = flags; - - this->initEffects(); -} - -sk_sp SkBlurDrawLooper::CreateProc(SkReadBuffer& buffer) { - const SkColor color = buffer.readColor(); - const SkScalar sigma = buffer.readScalar(); - const SkScalar dx = buffer.readScalar(); - const SkScalar dy = buffer.readScalar(); - const uint32_t flags = buffer.read32(); - return Make(color, sigma, dx, dy, flags); -} - -void SkBlurDrawLooper::flatten(SkWriteBuffer& buffer) const { - buffer.writeColor(fBlurColor); - buffer.writeScalar(fSigma); - buffer.writeScalar(fDx); - buffer.writeScalar(fDy); - buffer.write32(fBlurFlags); -} - -bool SkBlurDrawLooper::asABlurShadow(BlurShadowRec* rec) const { - if (fSigma <= 0 || (fBlurFlags & fBlurFlags & kIgnoreTransform_BlurFlag)) { - return false; - } - - if (rec) { - rec->fSigma = fSigma; - rec->fColor = fBlurColor; - rec->fOffset.set(fDx, fDy); - rec->fStyle = kNormal_SkBlurStyle; - rec->fQuality = (fBlurFlags & kHighQuality_BlurFlag) ? - kHigh_SkBlurQuality : kLow_SkBlurQuality; - } - return true; -} - -//////////////////////////////////////////////////////////////////////////////////////// - -SkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const { - return new (storage) BlurDrawLooperContext(this); -} - -SkBlurDrawLooper::BlurDrawLooperContext::BlurDrawLooperContext( - const SkBlurDrawLooper* looper) - : fLooper(looper), fState(SkBlurDrawLooper::kBeforeEdge) {} - -bool SkBlurDrawLooper::BlurDrawLooperContext::next(SkCanvas* canvas, - SkPaint* paint) { - switch (fState) { - case kBeforeEdge: - // we do nothing if a maskfilter is already installed - if (paint->getMaskFilter()) { - fState = kDone; - return false; - } -#ifdef SK_BUILD_FOR_ANDROID - SkColor blurColor; - blurColor = fLooper->fBlurColor; - if (SkColorGetA(blurColor) == 255) { - blurColor = SkColorSetA(blurColor, paint->getAlpha()); - } - paint->setColor(blurColor); -#else - paint->setColor(fLooper->fBlurColor); -#endif - paint->setMaskFilter(fLooper->fBlur); - paint->setColorFilter(fLooper->fColorFilter); - canvas->save(); - if (fLooper->fBlurFlags & kIgnoreTransform_BlurFlag) { - SkMatrix transform(canvas->getTotalMatrix()); - transform.postTranslate(fLooper->fDx, fLooper->fDy); - canvas->setMatrix(transform); - } else { - canvas->translate(fLooper->fDx, fLooper->fDy); - } - fState = kAfterEdge; - return true; - case kAfterEdge: - canvas->restore(); - fState = kDone; - return true; - default: - SkASSERT(kDone == fState); - return false; - } -} - -#ifndef SK_IGNORE_TO_STRING -void SkBlurDrawLooper::toString(SkString* str) const { - str->append("SkBlurDrawLooper: "); - - str->append("dx: "); - str->appendScalar(fDx); - - str->append(" dy: "); - str->appendScalar(fDy); - - str->append(" color: "); - str->appendHex(fBlurColor); - - str->append(" flags: ("); - if (kNone_BlurFlag == fBlurFlags) { - str->append("None"); - } else { - bool needsSeparator = false; - SkAddFlagToString(str, SkToBool(kIgnoreTransform_BlurFlag & fBlurFlags), "IgnoreTransform", - &needsSeparator); - SkAddFlagToString(str, SkToBool(kOverrideColor_BlurFlag & fBlurFlags), "OverrideColor", - &needsSeparator); - SkAddFlagToString(str, SkToBool(kHighQuality_BlurFlag & fBlurFlags), "HighQuality", - &needsSeparator); - } - str->append(")"); - - // TODO: add optional "fBlurFilter->toString(str);" when SkMaskFilter::toString is added - // alternatively we could cache the radius in SkBlurDrawLooper and just add it here -} -#endif diff --git a/gfx/skia/skia/src/effects/SkBlurMask.cpp b/gfx/skia/skia/src/effects/SkBlurMask.cpp index d22881aa9e12..eee16313f60c 100644 --- a/gfx/skia/skia/src/effects/SkBlurMask.cpp +++ b/gfx/skia/skia/src/effects/SkBlurMask.cpp @@ -75,17 +75,17 @@ SkScalar SkBlurMask::ConvertSigmaToRadius(SkScalar sigma) { * } * } */ +template static int boxBlur(const uint8_t* src, int src_y_stride, uint8_t* dst, - int leftRadius, int rightRadius, int width, int height, - bool transpose) + int leftRadius, int rightRadius, int width, int height) { int diameter = leftRadius + rightRadius; int kernelSize = diameter + 1; int border = SkMin32(width, diameter); uint32_t scale = (1 << 24) / kernelSize; int new_width = width + SkMax32(leftRadius, rightRadius) * 2; - int dst_x_stride = transpose ? height : 1; - int dst_y_stride = transpose ? 1 : new_width; + int dst_x_stride = Transpose ? height : 1; + int dst_y_stride = Transpose ? 1 : new_width; uint32_t half = 1 << 23; for (int y = 0; y < height; ++y) { uint32_t sum = 0; @@ -277,9 +277,10 @@ static int boxBlur(const uint8_t* src, int src_y_stride, uint8_t* dst, * return new_width; */ +template static int boxBlurInterp(const uint8_t* src, int src_y_stride, uint8_t* dst, int radius, int width, int height, - bool transpose, uint8_t outer_weight) + uint8_t outer_weight) { int diameter = radius * 2; int kernelSize = diameter + 1; @@ -291,8 +292,8 @@ static int boxBlurInterp(const uint8_t* src, int src_y_stride, uint8_t* dst, uint32_t inner_scale = (inner_weight << 16) / (kernelSize - 2); uint32_t half = 1 << 23; int new_width = width + diameter; - int dst_x_stride = transpose ? height : 1; - int dst_y_stride = transpose ? 1 : new_width; + int dst_x_stride = Transpose ? height : 1; + int dst_y_stride = Transpose ? 1 : new_width; for (int y = 0; y < height; ++y) { uint32_t outer_sum = 0, inner_sum = 0; uint8_t* dptr = dst + y * dst_y_stride; @@ -553,30 +554,30 @@ bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, get_adjusted_radii(passRadius, &loRadius, &hiRadius); if (kHigh_SkBlurQuality == quality) { // Do three X blurs, with a transpose on the final one. - w = boxBlur(sp, src.fRowBytes, tp, loRadius, hiRadius, w, h, false); - w = boxBlur(tp, w, dp, hiRadius, loRadius, w, h, false); - w = boxBlur(dp, w, tp, hiRadius, hiRadius, w, h, true); + w = boxBlur(sp, src.fRowBytes, tp, loRadius, hiRadius, w, h); + w = boxBlur(tp, w, dp, hiRadius, loRadius, w, h); + w = boxBlur(dp, w, tp, hiRadius, hiRadius, w, h); // Do three Y blurs, with a transpose on the final one. - h = boxBlur(tp, h, dp, loRadius, hiRadius, h, w, false); - h = boxBlur(dp, h, tp, hiRadius, loRadius, h, w, false); - h = boxBlur(tp, h, dp, hiRadius, hiRadius, h, w, true); + h = boxBlur(tp, h, dp, loRadius, hiRadius, h, w); + h = boxBlur(dp, h, tp, hiRadius, loRadius, h, w); + h = boxBlur(tp, h, dp, hiRadius, hiRadius, h, w); } else { - w = boxBlur(sp, src.fRowBytes, tp, rx, rx, w, h, true); - h = boxBlur(tp, h, dp, ry, ry, h, w, true); + w = boxBlur(sp, src.fRowBytes, tp, rx, rx, w, h); + h = boxBlur(tp, h, dp, ry, ry, h, w); } } else { if (kHigh_SkBlurQuality == quality) { // Do three X blurs, with a transpose on the final one. - w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, false, outerWeight); - w = boxBlurInterp(tp, w, dp, rx, w, h, false, outerWeight); - w = boxBlurInterp(dp, w, tp, rx, w, h, true, outerWeight); + w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, outerWeight); + w = boxBlurInterp(tp, w, dp, rx, w, h, outerWeight); + w = boxBlurInterp(dp, w, tp, rx, w, h, outerWeight); // Do three Y blurs, with a transpose on the final one. - h = boxBlurInterp(tp, h, dp, ry, h, w, false, outerWeight); - h = boxBlurInterp(dp, h, tp, ry, h, w, false, outerWeight); - h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWeight); + h = boxBlurInterp(tp, h, dp, ry, h, w, outerWeight); + h = boxBlurInterp(dp, h, tp, ry, h, w, outerWeight); + h = boxBlurInterp(tp, h, dp, ry, h, w, outerWeight); } else { - w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWeight); - h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWeight); + w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, outerWeight); + h = boxBlurInterp(tp, h, dp, ry, h, w, outerWeight); } } @@ -769,7 +770,7 @@ bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, return true; } - SkAutoTDeleteArray profile(ComputeBlurProfile(sigma)); + std::unique_ptr profile(ComputeBlurProfile(sigma)); size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { diff --git a/gfx/skia/skia/src/effects/SkBlurMaskFilter.cpp b/gfx/skia/skia/src/effects/SkBlurMaskFilter.cpp index c32e111f294f..8b216bc4b863 100644 --- a/gfx/skia/skia/src/effects/SkBlurMaskFilter.cpp +++ b/gfx/skia/skia/src/effects/SkBlurMaskFilter.cpp @@ -17,17 +17,19 @@ #if SK_SUPPORT_GPU #include "GrCircleBlurFragmentProcessor.h" +#include "GrClip.h" #include "GrContext.h" -#include "GrDrawContext.h" -#include "GrTexture.h" #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" +#include "GrRenderTargetContext.h" +#include "GrResourceProvider.h" +#include "GrShaderCaps.h" #include "GrStyle.h" +#include "GrTexture.h" +#include "GrTextureProxy.h" #include "effects/GrSimpleTextureEffect.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLSampler.h" #include "glsl/GrGLSLUniformHandler.h" #endif @@ -49,25 +51,25 @@ public: const SkIRect& clipBounds, const SkMatrix& ctm, SkRect* maskRect) const override; - bool directFilterMaskGPU(GrTextureProvider* texProvider, - GrDrawContext* drawContext, - GrPaint* grp, + bool directFilterMaskGPU(GrContext*, + GrRenderTargetContext* renderTargetContext, + GrPaint&&, const GrClip&, const SkMatrix& viewMatrix, const SkStrokeRec& strokeRec, const SkPath& path) const override; bool directFilterRRectMaskGPU(GrContext*, - GrDrawContext* drawContext, - GrPaint* grp, + GrRenderTargetContext* renderTargetContext, + GrPaint&&, const GrClip&, const SkMatrix& viewMatrix, const SkStrokeRec& strokeRec, const SkRRect& rrect, const SkRRect& devRRect) const override; - bool filterMaskGPU(GrTexture* src, - const SkMatrix& ctm, - const SkIRect& maskRect, - GrTexture** result) const override; + sk_sp filterMaskGPU(GrContext*, + sk_sp srcProxy, + const SkMatrix& ctm, + const SkIRect& maskRect) const override; #endif void computeFastBounds(const SkRect&, SkRect*) const override; @@ -127,14 +129,12 @@ const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128); sk_sp SkBlurMaskFilter::Make(SkBlurStyle style, SkScalar sigma, const SkRect& occluder, uint32_t flags) { + SkASSERT(!(flags & ~SkBlurMaskFilter::kAll_BlurFlag)); + SkASSERT(style <= kLastEnum_SkBlurStyle); + if (!SkScalarIsFinite(sigma) || sigma <= 0) { return nullptr; } - if ((unsigned)style > (unsigned)kLastEnum_SkBlurStyle) { - return nullptr; - } - SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag); - flags &= SkBlurMaskFilter::kAll_BlurFlag; return sk_sp(new SkBlurMaskFilterImpl(sigma, style, occluder, flags)); } @@ -734,7 +734,12 @@ void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src, sk_sp SkBlurMaskFilterImpl::CreateProc(SkReadBuffer& buffer) { const SkScalar sigma = buffer.readScalar(); const unsigned style = buffer.readUInt(); - const unsigned flags = buffer.readUInt(); + unsigned flags = buffer.readUInt(); + + buffer.validate(style <= kLastEnum_SkBlurStyle); + buffer.validate(!(flags & ~SkBlurMaskFilter::kAll_BlurFlag)); + + flags &= SkBlurMaskFilter::kAll_BlurFlag; SkRect occluder; if (buffer.isVersionLT(SkReadBuffer::kBlurMaskFilterWritesOccluder)) { @@ -767,7 +772,7 @@ public: const char* name() const override { return "RectBlur"; } - static sk_sp Make(GrTextureProvider *textureProvider, + static sk_sp Make(GrResourceProvider* resourceProvider, const SkRect& rect, float sigma) { int doubleProfileSize = SkScalarCeilToInt(12*sigma); @@ -777,7 +782,7 @@ public: return nullptr; } - SkAutoTUnref blurProfile(CreateBlurProfileTexture(textureProvider, sigma)); + sk_sp blurProfile(CreateBlurProfileTexture(resourceProvider, sigma)); if (!blurProfile) { return nullptr; } @@ -800,8 +805,10 @@ public: } else { precision = kDefault_GrSLPrecision; } - return sk_sp( - new GrRectBlurEffect(rect, sigma, blurProfile, precision)); + + return sk_sp(new GrRectBlurEffect(resourceProvider, + rect, sigma, + std::move(blurProfile), precision)); } const SkRect& getRect() const { return fRect; } @@ -809,22 +816,20 @@ public: GrSLPrecision precision() const { return fPrecision; } private: - GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile, - GrSLPrecision fPrecision); + GrRectBlurEffect(GrResourceProvider*, const SkRect& rect, float sigma, + sk_sp blurProfile, GrSLPrecision fPrecision); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - static GrTexture* CreateBlurProfileTexture(GrTextureProvider*, float sigma); + static sk_sp CreateBlurProfileTexture(GrResourceProvider*, float sigma); SkRect fRect; float fSigma; - GrTextureAccess fBlurProfileAccess; + TextureSampler fBlurProfileSampler; GrSLPrecision fPrecision; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; @@ -836,10 +841,10 @@ class GrGLRectBlurEffect : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs&) override; - static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b); + static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; @@ -867,7 +872,7 @@ void OutputRectBlurProfileLookup(GrGLSLFPFragmentBuilder* fragBuilder, } -void GrGLRectBlurEffect::GenKey(const GrProcessor& proc, const GrGLSLCaps&, +void GrGLRectBlurEffect::GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrRectBlurEffect& rbe = proc.cast(); @@ -884,7 +889,7 @@ void GrGLRectBlurEffect::emitCode(EmitArgs& args) { const char *profileSizeName; SkString precisionString; - if (args.fGLSLCaps->usesPrecisionModifiers()) { + if (args.fShaderCaps->usesPrecisionModifiers()) { precisionString.printf("%s ", GrGLSLPrecisionString(rbe.precision())); } fProxyRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, @@ -899,7 +904,6 @@ void GrGLRectBlurEffect::emitCode(EmitArgs& args) { &profileSizeName); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const char *fragmentPos = fragBuilder->fragmentPosition(); if (args.fInputColor) { fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor); @@ -907,8 +911,8 @@ void GrGLRectBlurEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("vec4 src=vec4(1);"); } - fragBuilder->codeAppendf("%s vec2 translatedPos = %s.xy - %s.xy;", precisionString.c_str(), - fragmentPos, rectName); + fragBuilder->codeAppendf("%s vec2 translatedPos = sk_FragCoord.xy - %s.xy;", + precisionString.c_str(), rectName); fragBuilder->codeAppendf("%s float width = %s.z - %s.x;", precisionString.c_str(), rectName, rectName); fragBuilder->codeAppendf("%s float height = %s.w - %s.y;", precisionString.c_str(), rectName, @@ -931,7 +935,7 @@ void GrGLRectBlurEffect::emitCode(EmitArgs& args) { } void GrGLRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) { + const GrFragmentProcessor& proc) { const GrRectBlurEffect& rbe = proc.cast(); SkRect rect = rbe.getRect(); @@ -939,8 +943,9 @@ void GrGLRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman, pdman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma())); } -GrTexture* GrRectBlurEffect::CreateBlurProfileTexture(GrTextureProvider* textureProvider, - float sigma) { +sk_sp GrRectBlurEffect::CreateBlurProfileTexture( + GrResourceProvider* resourceProvider, + float sigma) { GrSurfaceDesc texDesc; unsigned int profileSize = SkScalarCeilToInt(6*sigma); @@ -956,32 +961,36 @@ GrTexture* GrRectBlurEffect::CreateBlurProfileTexture(GrTextureProvider* texture builder[0] = profileSize; builder.finish(); - GrTexture *blurProfile = textureProvider->findAndRefTextureByUniqueKey(key); - + sk_sp blurProfile(resourceProvider->findProxyByUniqueKey(key)); if (!blurProfile) { - SkAutoTDeleteArray profile(SkBlurMask::ComputeBlurProfile(sigma)); + std::unique_ptr profile(SkBlurMask::ComputeBlurProfile(sigma)); - blurProfile = textureProvider->createTexture(texDesc, SkBudgeted::kYes, profile.get(), 0); - if (blurProfile) { - textureProvider->assignUniqueKeyToTexture(key, blurProfile); + blurProfile = GrSurfaceProxy::MakeDeferred(resourceProvider, + texDesc, SkBudgeted::kYes, profile.get(), 0); + if (!blurProfile) { + return nullptr; } + + resourceProvider->assignUniqueKeyToProxy(key, blurProfile.get()); } return blurProfile; } -GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile, +GrRectBlurEffect::GrRectBlurEffect(GrResourceProvider* resourceProvider, + const SkRect& rect, float sigma, + sk_sp blurProfile, GrSLPrecision precision) - : fRect(rect) - , fSigma(sigma) - , fBlurProfileAccess(blurProfile) - , fPrecision(precision) { + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fRect(rect) + , fSigma(sigma) + , fBlurProfileSampler(resourceProvider, std::move(blurProfile)) + , fPrecision(precision) { this->initClassID(); - this->addTextureAccess(&fBlurProfileAccess); - this->setWillReadFragmentPosition(); + this->addTextureSampler(&fBlurProfileSampler); } -void GrRectBlurEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLRectBlurEffect::GenKey(*this, caps, b); } @@ -995,29 +1004,26 @@ bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& sBase) const { return this->getSigma() == s.getSigma() && this->getRect() == s.getRect(); } -void GrRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->mulByUnknownSingleComponent(); -} - GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect); +#if GR_TEST_UTILS sk_sp GrRectBlurEffect::TestCreate(GrProcessorTestData* d) { float sigma = d->fRandom->nextRangeF(3,8); float width = d->fRandom->nextRangeF(200,300); float height = d->fRandom->nextRangeF(200,300); - return GrRectBlurEffect::Make(d->fContext->textureProvider(), SkRect::MakeWH(width, height), - sigma); + return GrRectBlurEffect::Make(d->resourceProvider(), + SkRect::MakeWH(width, height), sigma); } +#endif - -bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider, - GrDrawContext* drawContext, - GrPaint* grp, +bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context, + GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, const GrClip& clip, const SkMatrix& viewMatrix, const SkStrokeRec& strokeRec, const SkPath& path) const { - SkASSERT(drawContext); + SkASSERT(renderTargetContext); if (fBlurStyle != kNormal_SkBlurStyle) { return false; @@ -1030,6 +1036,7 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider, SkScalar xformedSigma = this->computeXformedSigma(viewMatrix); + GrResourceProvider* resourceProvider = context->resourceProvider(); sk_sp fp; SkRect rect; @@ -1037,9 +1044,9 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider, SkScalar pad = 3.0f * xformedSigma; rect.outset(pad, pad); - fp = GrRectBlurEffect::Make(texProvider, rect, xformedSigma); + fp = GrRectBlurEffect::Make(resourceProvider, rect, xformedSigma); } else if (path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height())) { - fp = GrCircleBlurFragmentProcessor::Make(texProvider, rect, xformedSigma); + fp = GrCircleBlurFragmentProcessor::Make(resourceProvider, rect, xformedSigma); // expand the rect for the coverage geometry int pad = SkScalarCeilToInt(6*xformedSigma)/2; @@ -1052,14 +1059,14 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider, return false; } - grp->addCoverageFragmentProcessor(std::move(fp)); - SkMatrix inverse; if (!viewMatrix.invert(&inverse)) { return false; } - drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), rect, inverse); + paint.addCoverageFragmentProcessor(std::move(fp)); + renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + rect, inverse); return true; } @@ -1072,7 +1079,7 @@ public: float sigma, float xformedSigma, const SkRRect& srcRRect, const SkRRect& devRRect); - virtual ~GrRRectBlurEffect() {} + ~GrRRectBlurEffect() override {} const char* name() const override { return "GrRRectBlur"; } const SkRRect& getRRect() const { return fRRect; } @@ -1081,29 +1088,27 @@ public: private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - GrRRectBlurEffect(float sigma, const SkRRect&, GrTexture* profileTexture); + GrRRectBlurEffect(GrResourceProvider*, float sigma, const SkRRect&, + sk_sp profileProxy); - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, + virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; bool onIsEqual(const GrFragmentProcessor& other) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - SkRRect fRRect; float fSigma; - GrTextureAccess fNinePatchAccess; + TextureSampler fNinePatchSampler; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; typedef GrFragmentProcessor INHERITED; }; -static sk_sp find_or_create_rrect_blur_mask(GrContext* context, - const SkRRect& rrectToDraw, - const SkISize& size, - float xformedSigma, - bool doAA) { +static sk_sp find_or_create_rrect_blur_mask(GrContext* context, + const SkRRect& rrectToDraw, + const SkISize& size, + float xformedSigma) { static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey key; GrUniqueKey::Builder builder(&key, kDomain, 9); @@ -1118,39 +1123,43 @@ static sk_sp find_or_create_rrect_blur_mask(GrContext* context, } builder.finish(); - sk_sp mask(context->textureProvider()->findAndRefTextureByUniqueKey(key)); + sk_sp mask(context->resourceProvider()->findProxyByUniqueKey(key)); if (!mask) { // TODO: this could be approx but the texture coords will need to be updated - sk_sp dc(context->makeDrawContextWithFallback(SkBackingFit::kExact, - size.fWidth, size.fHeight, - kAlpha_8_GrPixelConfig, - nullptr)); - if (!dc) { + sk_sp rtc(context->makeDeferredRenderTargetContextWithFallback( + SkBackingFit::kExact, size.fWidth, size.fHeight, kAlpha_8_GrPixelConfig, nullptr)); + if (!rtc) { return nullptr; } - GrPaint grPaint; - grPaint.setAntiAlias(doAA); + GrPaint paint; - dc->clear(nullptr, 0x0, true); - dc->drawRRect(GrNoClip(), grPaint, SkMatrix::I(), rrectToDraw, GrStyle::SimpleFill()); + rtc->clear(nullptr, 0x0, true); + rtc->drawRRect(GrNoClip(), std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw, + GrStyle::SimpleFill()); - sk_sp srcTexture(dc->asTexture()); - sk_sp dc2(SkGpuBlurUtils::GaussianBlur(context, - srcTexture.get(), - nullptr, - SkIRect::MakeWH(size.fWidth, - size.fHeight), - nullptr, - xformedSigma, xformedSigma, - SkBackingFit::kExact)); - if (!dc2) { + sk_sp srcProxy(rtc->asTextureProxyRef()); + if (!srcProxy) { + return nullptr; + } + sk_sp rtc2(SkGpuBlurUtils::GaussianBlur(context, + std::move(srcProxy), + nullptr, + SkIRect::MakeWH( + size.fWidth, + size.fHeight), + nullptr, + xformedSigma, xformedSigma, + SkBackingFit::kExact)); + if (!rtc2) { return nullptr; } - mask = dc2->asTexture(); - SkASSERT(mask); - context->textureProvider()->assignUniqueKeyToTexture(key, mask.get()); + mask = rtc2->asTextureProxyRef(); + if (!mask) { + return nullptr; + } + context->resourceProvider()->assignUniqueKeyToProxy(key, mask.get()); } return mask; @@ -1187,28 +1196,27 @@ sk_sp GrRRectBlurEffect::Make(GrContext* context, return nullptr; } - sk_sp mask(find_or_create_rrect_blur_mask(context, rrectToDraw, size, - xformedSigma, true)); + sk_sp mask(find_or_create_rrect_blur_mask(context, rrectToDraw, + size, xformedSigma)); if (!mask) { return nullptr; } - return sk_sp(new GrRRectBlurEffect(xformedSigma, + return sk_sp(new GrRRectBlurEffect(context->resourceProvider(), + xformedSigma, devRRect, - mask.get())); + std::move(mask))); } -void GrRRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->mulByUnknownSingleComponent(); -} - -GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTexture *ninePatchTexture) - : fRRect(rrect), - fSigma(sigma), - fNinePatchAccess(ninePatchTexture) { +GrRRectBlurEffect::GrRRectBlurEffect(GrResourceProvider* resourceProvider, + float sigma, const SkRRect& rrect, + sk_sp ninePatchProxy) + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fRRect(rrect) + , fSigma(sigma) + , fNinePatchSampler(resourceProvider, std::move(ninePatchProxy)) { this->initClassID(); - this->addTextureAccess(&fNinePatchAccess); - this->setWillReadFragmentPosition(); + this->addTextureSampler(&fNinePatchSampler); } bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const { @@ -1222,6 +1230,7 @@ bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const { GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect); +#if GR_TEST_UTILS sk_sp GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) { SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f); SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f); @@ -1229,8 +1238,9 @@ sk_sp GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f); SkRRect rrect; rrect.setRectXY(SkRect::MakeWH(w, h), r, r); - return GrRRectBlurEffect::Make(d->fContext, sigma, sigma, rrect, rrect); + return GrRRectBlurEffect::Make(d->context(), sigma, sigma, rrect, rrect); } +#endif ////////////////////////////////////////////////////////////////////////////// @@ -1239,7 +1249,7 @@ public: void emitCode(EmitArgs&) override; protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fProxyRectUniform; @@ -1274,12 +1284,11 @@ void GrGLRRectBlurEffect::emitCode(EmitArgs& args) { &blurRadiusName); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const char* fragmentPos = fragBuilder->fragmentPosition(); // warp the fragment position to the appropriate part of the 9patch blur texture fragBuilder->codeAppendf("vec2 rectCenter = (%s.xy + %s.zw)/2.0;", rectName, rectName); - fragBuilder->codeAppendf("vec2 translatedFragPos = %s.xy - %s.xy;", fragmentPos, rectName); + fragBuilder->codeAppendf("vec2 translatedFragPos = sk_FragCoord.xy - %s.xy;", rectName); fragBuilder->codeAppendf("float threshold = %s + 2.0*%s;", cornerRadiusName, blurRadiusName); fragBuilder->codeAppendf("vec2 middle = %s.zw - %s.xy - 2.0*threshold;", rectName, rectName); @@ -1306,7 +1315,7 @@ void GrGLRRectBlurEffect::emitCode(EmitArgs& args) { } void GrGLRRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) { + const GrFragmentProcessor& proc) { const GrRRectBlurEffect& brre = proc.cast(); const SkRRect& rrect = brre.getRRect(); @@ -1323,7 +1332,7 @@ void GrGLRRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman, pdman.set1f(fCornerRadiusUniform, radius); } -void GrRRectBlurEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrRRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLRRectBlurEffect::GenKey(*this, caps, b); } @@ -1333,14 +1342,14 @@ GrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const { } bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, - GrDrawContext* drawContext, - GrPaint* grp, + GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, const GrClip& clip, const SkMatrix& viewMatrix, const SkStrokeRec& strokeRec, const SkRRect& srcRRect, const SkRRect& devRRect) const { - SkASSERT(drawContext); + SkASSERT(renderTargetContext); if (fBlurStyle != kNormal_SkBlurStyle) { return false; @@ -1350,6 +1359,7 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, return false; } + GrResourceProvider* resourceProvider = context->resourceProvider(); SkScalar xformedSigma = this->computeXformedSigma(viewMatrix); if (devRRect.isRect() || devRRect.isCircle()) { @@ -1362,25 +1372,22 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, SkScalar pad = 3.0f * xformedSigma; const SkRect dstCoverageRect = devRRect.rect().makeOutset(pad, pad); - fp = GrRectBlurEffect::Make(context->textureProvider(), dstCoverageRect, xformedSigma); + fp = GrRectBlurEffect::Make(resourceProvider, dstCoverageRect, xformedSigma); } else { - fp = GrCircleBlurFragmentProcessor::Make(context->textureProvider(), - devRRect.rect(), - xformedSigma); + fp = GrCircleBlurFragmentProcessor::Make(resourceProvider, + devRRect.rect(), xformedSigma); } if (!fp) { return false; } - GrPaint newPaint(*grp); - newPaint.addCoverageFragmentProcessor(std::move(fp)); - newPaint.setAntiAlias(false); + paint.addCoverageFragmentProcessor(std::move(fp)); SkRect srcProxyRect = srcRRect.rect(); srcProxyRect.outset(3.0f*fSigma, 3.0f*fSigma); - drawContext->drawRect(clip, newPaint, viewMatrix, srcProxyRect); + renderTargetContext->drawRect(clip, std::move(paint), GrAA::kNo, viewMatrix, srcProxyRect); return true; } @@ -1390,10 +1397,6 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, return false; } - GrPaint newPaint(*grp); - newPaint.addCoverageFragmentProcessor(std::move(fp)); - newPaint.setAntiAlias(false); - if (!this->ignoreXform()) { SkRect srcProxyRect = srcRRect.rect(); srcProxyRect.outset(3.0f*fSigma, 3.0f*fSigma); @@ -1425,8 +1428,10 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, numIndices = 6; } - drawContext->drawVertices(clip, newPaint, viewMatrix, kTriangles_GrPrimitiveType, - numPoints, points, nullptr, nullptr, indices, numIndices); + paint.addCoverageFragmentProcessor(std::move(fp)); + renderTargetContext->drawVertices(clip, std::move(paint), viewMatrix, + kTriangles_GrPrimitiveType, numPoints, points, nullptr, + nullptr, indices, numIndices); } else { SkMatrix inverse; @@ -1438,8 +1443,9 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, SkRect proxyRect = devRRect.rect(); proxyRect.outset(extra, extra); - - drawContext->fillRectWithLocalMatrix(clip, newPaint, SkMatrix::I(), proxyRect, inverse); + paint.addCoverageFragmentProcessor(std::move(fp)); + renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, + SkMatrix::I(), proxyRect, inverse); } return true; @@ -1487,34 +1493,35 @@ bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect, return true; } -bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src, - const SkMatrix& ctm, - const SkIRect& maskRect, - GrTexture** result) const { +sk_sp SkBlurMaskFilterImpl::filterMaskGPU(GrContext* context, + sk_sp srcProxy, + const SkMatrix& ctm, + const SkIRect& maskRect) const { // 'maskRect' isn't snapped to the UL corner but the mask in 'src' is. const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height()); - GrContext* context = src->getContext(); - SkScalar xformedSigma = this->computeXformedSigma(ctm); SkASSERT(xformedSigma > 0); // If we're doing a normal blur, we can clobber the pathTexture in the // gaussianBlur. Otherwise, we need to save it for later compositing. bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle); - sk_sp drawContext(SkGpuBlurUtils::GaussianBlur(context, src, nullptr, - clipRect, nullptr, - xformedSigma, xformedSigma)); - if (!drawContext) { - return false; + sk_sp renderTargetContext(SkGpuBlurUtils::GaussianBlur(context, + srcProxy, + nullptr, clipRect, + nullptr, + xformedSigma, + xformedSigma)); + if (!renderTargetContext) { + return nullptr; } if (!isNormalBlur) { GrPaint paint; - SkMatrix matrix; - matrix.setIDiv(src->width(), src->height()); // Blend pathTexture over blurTexture. - paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(src, nullptr, matrix)); + paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(context->resourceProvider(), + std::move(srcProxy), + nullptr, SkMatrix::I())); if (kInner_SkBlurStyle == fBlurStyle) { // inner: dst = dst * src paint.setCoverageSetOpXPFactory(SkRegion::kIntersect_Op); @@ -1530,11 +1537,11 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src, paint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); } - drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), SkRect::Make(clipRect)); + renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(clipRect)); } - *result = drawContext->asTexture().release(); - return true; + return renderTargetContext->asTextureProxyRef(); } #endif // SK_SUPPORT_GPU diff --git a/gfx/skia/skia/src/effects/SkColorCubeFilter.cpp b/gfx/skia/skia/src/effects/SkColorCubeFilter.cpp deleted file mode 100644 index 3eb70d32d0b1..000000000000 --- a/gfx/skia/skia/src/effects/SkColorCubeFilter.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkColorCubeFilter.h" -#include "SkColorPriv.h" -#include "SkOnce.h" -#include "SkOpts.h" -#include "SkReadBuffer.h" -#include "SkUnPreMultiply.h" -#include "SkWriteBuffer.h" -#if SK_SUPPORT_GPU -#include "GrContext.h" -#include "GrCoordTransform.h" -#include "GrInvariantOutput.h" -#include "GrTexturePriv.h" -#include "SkGr.h" -#include "glsl/GrGLSLFragmentProcessor.h" -#include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLUniformHandler.h" -#endif - -/////////////////////////////////////////////////////////////////////////////// -namespace { - -int32_t SkNextColorCubeUniqueID() { - static int32_t gColorCubeUniqueID; - // do a loop in case our global wraps around, as we never want to return a 0 - int32_t genID; - do { - genID = sk_atomic_inc(&gColorCubeUniqueID) + 1; - } while (0 == genID); - return genID; -} - -} // end namespace - -static const int MIN_CUBE_SIZE = 4; -static const int MAX_CUBE_SIZE = 64; - -static bool is_valid_3D_lut(SkData* cubeData, int cubeDimension) { - size_t minMemorySize = sizeof(uint8_t) * 4 * cubeDimension * cubeDimension * cubeDimension; - return (cubeDimension >= MIN_CUBE_SIZE) && (cubeDimension <= MAX_CUBE_SIZE) && - (nullptr != cubeData) && (cubeData->size() >= minMemorySize); -} - -sk_sp SkColorCubeFilter::Make(sk_sp cubeData, int cubeDimension) { - if (!is_valid_3D_lut(cubeData.get(), cubeDimension)) { - return nullptr; - } - - return sk_sp(new SkColorCubeFilter(std::move(cubeData), cubeDimension)); -} - -SkColorCubeFilter::SkColorCubeFilter(sk_sp cubeData, int cubeDimension) - : fCubeData(std::move(cubeData)) - , fUniqueID(SkNextColorCubeUniqueID()) - , fCache(cubeDimension) -{} - -uint32_t SkColorCubeFilter::getFlags() const { - return this->INHERITED::getFlags() | kAlphaUnchanged_Flag; -} - -SkColorCubeFilter::ColorCubeProcesingCache::ColorCubeProcesingCache(int cubeDimension) - : fCubeDimension(cubeDimension) { - fColorToIndex[0] = fColorToIndex[1] = nullptr; - fColorToFactors[0] = fColorToFactors[1] = nullptr; - fColorToScalar = nullptr; -} - -void SkColorCubeFilter::ColorCubeProcesingCache::getProcessingLuts( - const int* (*colorToIndex)[2], const SkScalar* (*colorToFactors)[2], - const SkScalar** colorToScalar) { - fLutsInitOnce(SkColorCubeFilter::ColorCubeProcesingCache::initProcessingLuts, this); - - SkASSERT((fColorToIndex[0] != nullptr) && - (fColorToIndex[1] != nullptr) && - (fColorToFactors[0] != nullptr) && - (fColorToFactors[1] != nullptr) && - (fColorToScalar != nullptr)); - (*colorToIndex)[0] = fColorToIndex[0]; - (*colorToIndex)[1] = fColorToIndex[1]; - (*colorToFactors)[0] = fColorToFactors[0]; - (*colorToFactors)[1] = fColorToFactors[1]; - (*colorToScalar) = fColorToScalar; -} - -void SkColorCubeFilter::ColorCubeProcesingCache::initProcessingLuts( - SkColorCubeFilter::ColorCubeProcesingCache* cache) { - static const SkScalar inv8bit = SkScalarInvert(SkIntToScalar(255)); - - // We need 256 int * 2 for fColorToIndex, so a total of 512 int. - // We need 256 SkScalar * 2 for fColorToFactors and 256 SkScalar - // for fColorToScalar, so a total of 768 SkScalar. - cache->fLutStorage.reset(512 * sizeof(int) + 768 * sizeof(SkScalar)); - uint8_t* storage = cache->fLutStorage.get(); - cache->fColorToIndex[0] = (int*)storage; - cache->fColorToIndex[1] = cache->fColorToIndex[0] + 256; - cache->fColorToFactors[0] = (SkScalar*)(storage + (512 * sizeof(int))); - cache->fColorToFactors[1] = cache->fColorToFactors[0] + 256; - cache->fColorToScalar = cache->fColorToFactors[1] + 256; - - SkScalar size = SkIntToScalar(cache->fCubeDimension); - SkScalar scale = (size - SK_Scalar1) * inv8bit; - - for (int i = 0; i < 256; ++i) { - SkScalar index = scale * i; - cache->fColorToIndex[0][i] = SkScalarFloorToInt(index); - cache->fColorToIndex[1][i] = cache->fColorToIndex[0][i] + 1; - cache->fColorToScalar[i] = inv8bit * i; - if (cache->fColorToIndex[1][i] < cache->fCubeDimension) { - cache->fColorToFactors[1][i] = index - SkIntToScalar(cache->fColorToIndex[0][i]); - cache->fColorToFactors[0][i] = SK_Scalar1 - cache->fColorToFactors[1][i]; - } else { - cache->fColorToIndex[1][i] = cache->fColorToIndex[0][i]; - cache->fColorToFactors[0][i] = SK_Scalar1; - cache->fColorToFactors[1][i] = 0; - } - } -} - -void SkColorCubeFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const { - const int* colorToIndex[2]; - const SkScalar* colorToFactors[2]; - const SkScalar* colorToScalar; - fCache.getProcessingLuts(&colorToIndex, &colorToFactors, &colorToScalar); - - SkOpts::color_cube_filter_span(src, count, dst, colorToIndex, - colorToFactors, fCache.cubeDimension(), - (const SkColor*)fCubeData->data()); -} - -sk_sp SkColorCubeFilter::CreateProc(SkReadBuffer& buffer) { - int cubeDimension = buffer.readInt(); - auto cubeData(buffer.readByteArrayAsData()); - if (!buffer.validate(is_valid_3D_lut(cubeData.get(), cubeDimension))) { - return nullptr; - } - return Make(std::move(cubeData), cubeDimension); -} - -void SkColorCubeFilter::flatten(SkWriteBuffer& buffer) const { - this->INHERITED::flatten(buffer); - buffer.writeInt(fCache.cubeDimension()); - buffer.writeDataAsByteArray(fCubeData.get()); -} - -#ifndef SK_IGNORE_TO_STRING -void SkColorCubeFilter::toString(SkString* str) const { - str->append("SkColorCubeFilter "); -} -#endif - -/////////////////////////////////////////////////////////////////////////////// -#if SK_SUPPORT_GPU - -class GrColorCubeEffect : public GrFragmentProcessor { -public: - static sk_sp Make(GrTexture* colorCube) { - return (nullptr != colorCube) ? sk_sp(new GrColorCubeEffect(colorCube)) - : nullptr; - } - - virtual ~GrColorCubeEffect(); - - const char* name() const override { return "ColorCube"; } - - int colorCubeSize() const { return fColorCubeAccess.getTexture()->width(); } - - - void onComputeInvariantOutput(GrInvariantOutput*) const override; - - class GLSLProcessor : public GrGLSLFragmentProcessor { - public: - void emitCode(EmitArgs&) override; - - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); - - protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; - - private: - GrGLSLProgramDataManager::UniformHandle fColorCubeSizeUni; - GrGLSLProgramDataManager::UniformHandle fColorCubeInvSizeUni; - - typedef GrGLSLFragmentProcessor INHERITED; - }; - -private: - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const override; - - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - - bool onIsEqual(const GrFragmentProcessor&) const override { return true; } - - GrColorCubeEffect(GrTexture* colorCube); - - GrTextureAccess fColorCubeAccess; - - typedef GrFragmentProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -GrColorCubeEffect::GrColorCubeEffect(GrTexture* colorCube) - : fColorCubeAccess(colorCube, GrTextureParams::kBilerp_FilterMode) { - this->initClassID(); - this->addTextureAccess(&fColorCubeAccess); -} - -GrColorCubeEffect::~GrColorCubeEffect() { -} - -void GrColorCubeEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const { - GLSLProcessor::GenKey(*this, caps, b); -} - -GrGLSLFragmentProcessor* GrColorCubeEffect::onCreateGLSLInstance() const { - return new GLSLProcessor; -} - -void GrColorCubeEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); -} - -/////////////////////////////////////////////////////////////////////////////// - -void GrColorCubeEffect::GLSLProcessor::emitCode(EmitArgs& args) { - if (nullptr == args.fInputColor) { - args.fInputColor = "vec4(1)"; - } - - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - fColorCubeSizeUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kFloat_GrSLType, kDefault_GrSLPrecision, - "Size"); - const char* colorCubeSizeUni = uniformHandler->getUniformCStr(fColorCubeSizeUni); - fColorCubeInvSizeUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kFloat_GrSLType, kDefault_GrSLPrecision, - "InvSize"); - const char* colorCubeInvSizeUni = uniformHandler->getUniformCStr(fColorCubeInvSizeUni); - - const char* nonZeroAlpha = "nonZeroAlpha"; - const char* unPMColor = "unPMColor"; - const char* cubeIdx = "cubeIdx"; - const char* cCoords1 = "cCoords1"; - const char* cCoords2 = "cCoords2"; - - // Note: if implemented using texture3D in OpenGL ES older than OpenGL ES 3.0, - // the shader might need "#extension GL_OES_texture_3D : enable". - - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - - // Unpremultiply color - fragBuilder->codeAppendf("\tfloat %s = max(%s.a, 0.00001);\n", nonZeroAlpha, args.fInputColor); - fragBuilder->codeAppendf("\tvec4 %s = vec4(%s.rgb / %s, %s);\n", - unPMColor, args.fInputColor, nonZeroAlpha, nonZeroAlpha); - - // Fit input color into the cube. - fragBuilder->codeAppendf( - "vec3 %s = vec3(%s.rg * vec2((%s - 1.0) * %s) + vec2(0.5 * %s), %s.b * (%s - 1.0));\n", - cubeIdx, unPMColor, colorCubeSizeUni, colorCubeInvSizeUni, colorCubeInvSizeUni, - unPMColor, colorCubeSizeUni); - - // Compute y coord for for texture fetches. - fragBuilder->codeAppendf("vec2 %s = vec2(%s.r, (floor(%s.b) + %s.g) * %s);\n", - cCoords1, cubeIdx, cubeIdx, cubeIdx, colorCubeInvSizeUni); - fragBuilder->codeAppendf("vec2 %s = vec2(%s.r, (ceil(%s.b) + %s.g) * %s);\n", - cCoords2, cubeIdx, cubeIdx, cubeIdx, colorCubeInvSizeUni); - - // Apply the cube. - fragBuilder->codeAppendf("%s = vec4(mix(", args.fOutputColor); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], cCoords1); - fragBuilder->codeAppend(".bgr, "); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], cCoords2); - - // Premultiply color by alpha. Note that the input alpha is not modified by this shader. - fragBuilder->codeAppendf(".bgr, fract(%s.b)) * vec3(%s), %s.a);\n", - cubeIdx, nonZeroAlpha, args.fInputColor); -} - -void GrColorCubeEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) { - const GrColorCubeEffect& colorCube = proc.cast(); - SkScalar size = SkIntToScalar(colorCube.colorCubeSize()); - pdman.set1f(fColorCubeSizeUni, SkScalarToFloat(size)); - pdman.set1f(fColorCubeInvSizeUni, SkScalarToFloat(SkScalarInvert(size))); -} - -void GrColorCubeEffect::GLSLProcessor::GenKey(const GrProcessor& proc, - const GrGLSLCaps&, GrProcessorKeyBuilder* b) { -} - -sk_sp SkColorCubeFilter::asFragmentProcessor(GrContext* context) const { - static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey key; - GrUniqueKey::Builder builder(&key, kDomain, 2); - builder[0] = fUniqueID; - builder[1] = fCache.cubeDimension(); - builder.finish(); - - GrSurfaceDesc desc; - desc.fWidth = fCache.cubeDimension(); - desc.fHeight = fCache.cubeDimension() * fCache.cubeDimension(); - desc.fConfig = kRGBA_8888_GrPixelConfig; - desc.fIsMipMapped = false; - - SkAutoTUnref textureCube( - context->textureProvider()->findAndRefTextureByUniqueKey(key)); - if (!textureCube) { - textureCube.reset(context->textureProvider()->createTexture( - desc, SkBudgeted::kYes, fCubeData->data(), 0)); - if (textureCube) { - context->textureProvider()->assignUniqueKeyToTexture(key, textureCube); - } else { - return nullptr; - } - } - - return sk_sp(GrColorCubeEffect::Make(textureCube)); -} -#endif diff --git a/gfx/skia/skia/src/effects/SkColorFilterImageFilter.cpp b/gfx/skia/skia/src/effects/SkColorFilterImageFilter.cpp index 507a80580fde..75dccfecef62 100644 --- a/gfx/skia/skia/src/effects/SkColorFilterImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkColorFilterImageFilter.cpp @@ -9,6 +9,7 @@ #include "SkCanvas.h" #include "SkColorFilter.h" +#include "SkColorSpaceXformer.h" #include "SkReadBuffer.h" #include "SkSpecialImage.h" #include "SkSpecialSurface.h" @@ -116,6 +117,18 @@ sk_sp SkColorFilterImageFilter::onFilterImage(SkSpecialImage* so return surf->makeImageSnapshot(); } +sk_sp SkColorFilterImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) +const { + SkASSERT(1 == this->countInputs()); + + sk_sp input = + this->getInput(0) ? this->getInput(0)->makeColorSpace(xformer) : nullptr; + sk_sp colorFilter = xformer->apply(fColorFilter.get()); + + return SkColorFilterImageFilter::Make(std::move(colorFilter), std::move(input), + this->getCropRectIfSet()); +} + bool SkColorFilterImageFilter::onIsColorFilterNode(SkColorFilter** filter) const { SkASSERT(1 == this->countInputs()); if (!this->cropRectIsSet()) { diff --git a/gfx/skia/skia/src/effects/SkColorMatrixFilter.cpp b/gfx/skia/skia/src/effects/SkColorMatrixFilter.cpp index 32cb3d91616b..0a2f08fb17d9 100644 --- a/gfx/skia/skia/src/effects/SkColorMatrixFilter.cpp +++ b/gfx/skia/skia/src/effects/SkColorMatrixFilter.cpp @@ -20,8 +20,7 @@ sk_sp SkColorMatrixFilter::MakeLightingFilter(SkColor mul, SkColo const SkColor opaqueAlphaMask = SK_ColorBLACK; // omit the alpha and compare only the RGB values if (0 == (add & ~opaqueAlphaMask)) { - return SkColorFilter::MakeModeFilter(mul | opaqueAlphaMask, - SkXfermode::Mode::kModulate_Mode); + return SkColorFilter::MakeModeFilter(mul | opaqueAlphaMask, SkBlendMode::kModulate); } SkColorMatrix matrix; diff --git a/gfx/skia/skia/src/effects/SkComposeImageFilter.cpp b/gfx/skia/skia/src/effects/SkComposeImageFilter.cpp index a5b9190a4cb9..9397c83d691e 100644 --- a/gfx/skia/skia/src/effects/SkComposeImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkComposeImageFilter.cpp @@ -61,6 +61,13 @@ sk_sp SkComposeImageFilter::onFilterImage(SkSpecialImage* source return outer; } +sk_sp SkComposeImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + SkASSERT(2 == this->countInputs() && this->getInput(0) && this->getInput(1)); + + return SkComposeImageFilter::Make(this->getInput(0)->makeColorSpace(xformer), + this->getInput(1)->makeColorSpace(xformer)); +} + SkIRect SkComposeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection direction) const { SkImageFilter* outer = this->getInput(0); diff --git a/gfx/skia/skia/src/effects/SkDashPathEffect.cpp b/gfx/skia/skia/src/effects/SkDashPathEffect.cpp index 1dbf29336175..b1029e1eefdb 100644 --- a/gfx/skia/skia/src/effects/SkDashPathEffect.cpp +++ b/gfx/skia/skia/src/effects/SkDashPathEffect.cpp @@ -47,7 +47,7 @@ static void outset_for_stroke(SkRect* rect, const SkStrokeRec& rec) { radius = SK_Scalar1; // hairlines } if (SkPaint::kMiter_Join == rec.getJoin()) { - radius = SkScalarMul(radius, rec.getMiter()); + radius *= rec.getMiter(); } rect->outset(radius, radius); } @@ -280,8 +280,8 @@ bool SkDashPathEffect::asPoints(PointData* results, if (clampedInitialDashLength > 0) { // partial first block SkASSERT(SkPaint::kRound_Cap != rec.getCap()); // can't handle partial circles - SkScalar x = pts[0].fX + SkScalarMul(tangent.fX, SkScalarHalf(clampedInitialDashLength)); - SkScalar y = pts[0].fY + SkScalarMul(tangent.fY, SkScalarHalf(clampedInitialDashLength)); + SkScalar x = pts[0].fX + tangent.fX * SkScalarHalf(clampedInitialDashLength); + SkScalar y = pts[0].fY + tangent.fY * SkScalarHalf(clampedInitialDashLength); SkScalar halfWidth, halfHeight; if (isXAxis) { halfWidth = SkScalarHalf(clampedInitialDashLength); @@ -313,8 +313,8 @@ bool SkDashPathEffect::asPoints(PointData* results, distance += SkScalarHalf(fIntervals[0]); for (int i = 0; i < numMidPoints; ++i) { - SkScalar x = pts[0].fX + SkScalarMul(tangent.fX, distance); - SkScalar y = pts[0].fY + SkScalarMul(tangent.fY, distance); + SkScalar x = pts[0].fX + tangent.fX * distance; + SkScalar y = pts[0].fY + tangent.fY * distance; SkASSERT(curPt < results->fNumPoints); results->fPoints[curPt].set(x, y); @@ -331,8 +331,8 @@ bool SkDashPathEffect::asPoints(PointData* results, SkASSERT(SkPaint::kRound_Cap != rec.getCap()); // can't handle partial circles SkScalar temp = length - distance; SkASSERT(temp < fIntervals[0]); - SkScalar x = pts[0].fX + SkScalarMul(tangent.fX, distance + SkScalarHalf(temp)); - SkScalar y = pts[0].fY + SkScalarMul(tangent.fY, distance + SkScalarHalf(temp)); + SkScalar x = pts[0].fX + tangent.fX * (distance + SkScalarHalf(temp)); + SkScalar y = pts[0].fY + tangent.fY * (distance + SkScalarHalf(temp)); SkScalar halfWidth, halfHeight; if (isXAxis) { halfWidth = SkScalarHalf(temp); diff --git a/gfx/skia/skia/src/effects/SkDiscretePathEffect.cpp b/gfx/skia/skia/src/effects/SkDiscretePathEffect.cpp index 4525c1e32ab0..b9d76f5b138e 100644 --- a/gfx/skia/skia/src/effects/SkDiscretePathEffect.cpp +++ b/gfx/skia/skia/src/effects/SkDiscretePathEffect.cpp @@ -110,13 +110,13 @@ bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src, } if (meas.getPosTan(distance, &p, &v)) { - Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale)); + Perterb(&p, v, rand.nextSScalar1() * scale); dst->moveTo(p); } while (--n >= 0) { distance += delta; if (meas.getPosTan(distance, &p, &v)) { - Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale)); + Perterb(&p, v, rand.nextSScalar1() * scale); dst->lineTo(p); } } diff --git a/gfx/skia/skia/src/effects/SkDisplacementMapEffect.cpp b/gfx/skia/skia/src/effects/SkDisplacementMapEffect.cpp index 88f5026663e9..06f16f01955a 100644 --- a/gfx/skia/skia/src/effects/SkDisplacementMapEffect.cpp +++ b/gfx/skia/skia/src/effects/SkDisplacementMapEffect.cpp @@ -14,13 +14,14 @@ #include "SkUnPreMultiply.h" #include "SkColorPriv.h" #if SK_SUPPORT_GPU +#include "GrClip.h" #include "GrContext.h" -#include "GrDrawContext.h" #include "GrCoordTransform.h" -#include "GrInvariantOutput.h" +#include "GrRenderTargetContext.h" +#include "GrTextureProxy.h" #include "SkGr.h" -#include "SkGrPriv.h" #include "effects/GrTextureDomain.h" +#include "glsl/GrGLSLColorSpaceXformHelper.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" @@ -66,19 +67,16 @@ void computeDisplacement(const SkVector& scale, SkBitmap* dst, static const SkScalar Inv8bit = SkScalarInvert(255); const int srcW = src.width(); const int srcH = src.height(); - const SkVector scaleForColor = SkVector::Make(SkScalarMul(scale.fX, Inv8bit), - SkScalarMul(scale.fY, Inv8bit)); - const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - SkScalarMul(scale.fX, SK_ScalarHalf), - SK_ScalarHalf - SkScalarMul(scale.fY, SK_ScalarHalf)); + const SkVector scaleForColor = SkVector::Make(scale.fX * Inv8bit, scale.fY * Inv8bit); + const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - scale.fX * SK_ScalarHalf, + SK_ScalarHalf - scale.fY * SK_ScalarHalf); const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); SkPMColor* dstPtr = dst->getAddr32(0, 0); for (int y = bounds.top(); y < bounds.bottom(); ++y) { const SkPMColor* displPtr = displ.getAddr32(bounds.left() + offset.fX, y + offset.fY); for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) { - const SkScalar displX = SkScalarMul(scaleForColor.fX, - SkIntToScalar(getValue(*displPtr, table))) + scaleAdj.fX; - const SkScalar displY = SkScalarMul(scaleForColor.fY, - SkIntToScalar(getValue(*displPtr, table))) + scaleAdj.fY; + SkScalar displX = scaleForColor.fX * getValue(*displPtr, table) + scaleAdj.fX; + SkScalar displY = scaleForColor.fY * getValue(*displPtr, table) + scaleAdj.fY; // Truncate the displacement values const int srcX = x + SkScalarTruncToInt(displX); const int srcY = y + SkScalarTruncToInt(displY); @@ -216,16 +214,20 @@ void SkDisplacementMapEffect::flatten(SkWriteBuffer& buffer) const { class GrDisplacementMapEffect : public GrFragmentProcessor { public: static sk_sp Make( + GrResourceProvider* resourceProvider, SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, SkVector scale, - GrTexture* displacement, const SkMatrix& offsetMatrix, GrTexture* color, - const SkISize& colorDimensions) { + sk_sp displacement, const SkMatrix& offsetMatrix, + sk_sp color, + sk_sp colorSpaceXform, const SkISize& colorDimensions) { return sk_sp( - new GrDisplacementMapEffect(xChannelSelector, yChannelSelector, scale, displacement, - offsetMatrix, color, colorDimensions)); + new GrDisplacementMapEffect(resourceProvider, xChannelSelector, yChannelSelector, scale, + std::move(displacement), + offsetMatrix, std::move(color), std::move(colorSpaceXform), + colorDimensions)); } - virtual ~GrDisplacementMapEffect(); + ~GrDisplacementMapEffect() override; SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const { return fXChannelSelector; @@ -237,30 +239,31 @@ public: const char* name() const override { return "DisplacementMap"; } const GrTextureDomain& domain() const { return fDomain; } + GrColorSpaceXform* colorSpaceXform() const { return fColorSpaceXform.get(); } private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, + GrDisplacementMapEffect(GrResourceProvider*, + SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, const SkVector& scale, - GrTexture* displacement, const SkMatrix& offsetMatrix, - GrTexture* color, + sk_sp displacement, const SkMatrix& offsetMatrix, + sk_sp color, sk_sp colorSpaceXform, const SkISize& colorDimensions); GR_DECLARE_FRAGMENT_PROCESSOR_TEST; GrCoordTransform fDisplacementTransform; - GrTextureAccess fDisplacementAccess; + TextureSampler fDisplacementSampler; GrCoordTransform fColorTransform; GrTextureDomain fDomain; - GrTextureAccess fColorAccess; + TextureSampler fColorSampler; + sk_sp fColorSpaceXform; SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector; SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector; SkVector fScale; @@ -324,47 +327,53 @@ sk_sp SkDisplacementMapEffect::onFilterImage(SkSpecialImage* sou if (source->isTextureBacked()) { GrContext* context = source->getContext(); - sk_sp colorTexture(color->asTextureRef(context)); - sk_sp displTexture(displ->asTextureRef(context)); - if (!colorTexture || !displTexture) { + sk_sp colorProxy(color->asTextureProxyRef(context)); + sk_sp displProxy(displ->asTextureProxyRef(context)); + if (!colorProxy || !displProxy) { return nullptr; } + SkMatrix offsetMatrix = SkMatrix::MakeTrans(SkIntToScalar(colorOffset.fX - displOffset.fX), + SkIntToScalar(colorOffset.fY - displOffset.fY)); + SkColorSpace* colorSpace = ctx.outputProperties().colorSpace(); + sk_sp colorSpaceXform = GrColorSpaceXform::Make(color->getColorSpace(), + colorSpace); GrPaint paint; - SkMatrix offsetMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(displTexture.get()); - offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displOffset.fX), - SkIntToScalar(colorOffset.fY - displOffset.fY)); - paint.addColorFragmentProcessor( - GrDisplacementMapEffect::Make(fXChannelSelector, + GrDisplacementMapEffect::Make(context->resourceProvider(), + fXChannelSelector, fYChannelSelector, scale, - displTexture.get(), + std::move(displProxy), offsetMatrix, - colorTexture.get(), + std::move(colorProxy), + std::move(colorSpaceXform), SkISize::Make(color->width(), color->height()))); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); SkMatrix matrix; matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y())); - SkColorSpace* colorSpace = ctx.outputProperties().colorSpace(); - sk_sp drawContext( - context->makeDrawContext(SkBackingFit::kApprox, bounds.width(), bounds.height(), - GrRenderableConfigForColorSpace(colorSpace), - sk_ref_sp(colorSpace))); - if (!drawContext) { + sk_sp renderTargetContext( + context->makeDeferredRenderTargetContext(SkBackingFit::kApprox, + bounds.width(), bounds.height(), + GrRenderableConfigForColorSpace(colorSpace), + sk_ref_sp(colorSpace))); + if (!renderTargetContext) { return nullptr; } - paint.setGammaCorrect(drawContext->isGammaCorrect()); + paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); - drawContext->drawRect(GrNoClip(), paint, matrix, SkRect::Make(colorBounds)); + renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, + SkRect::Make(colorBounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); - return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(bounds.width(), bounds.height()), - kNeedNewImageUniqueID_SpecialImage, - drawContext->asTexture(), - sk_ref_sp(drawContext->getColorSpace())); + return SkSpecialImage::MakeDeferredFromGpu( + context, + SkIRect::MakeWH(bounds.width(), bounds.height()), + kNeedNewImageUniqueID_SpecialImage, + renderTargetContext->asTextureProxyRef(), + renderTargetContext->refColorSpace()); } #endif @@ -403,6 +412,23 @@ sk_sp SkDisplacementMapEffect::onFilterImage(SkSpecialImage* sou dst); } +sk_sp SkDisplacementMapEffect::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + SkASSERT(2 == this->countInputs()); + if (!this->getInput(1)) { + return sk_ref_sp(const_cast(this)); + } + + // Intentionally avoid xforming the displacement filter. The values will be used as + // offsets, not as colors. + sk_sp displacement = sk_ref_sp(const_cast(this->getInput(0))); + sk_sp color = + this->getInput(1) ? this->getInput(1)->makeColorSpace(xformer) : nullptr; + + return SkDisplacementMapEffect::Make(fXChannelSelector, fYChannelSelector, fScale, + std::move(displacement), std::move(color), + this->getCropRectIfSet()); +} + SkRect SkDisplacementMapEffect::computeFastBounds(const SkRect& src) const { SkRect bounds = this->getColorInput() ? this->getColorInput()->computeFastBounds(src) : src; bounds.outset(SkScalarAbs(fScale) * SK_ScalarHalf, SkScalarAbs(fScale) * SK_ScalarHalf); @@ -449,13 +475,16 @@ class GrGLDisplacementMapEffect : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: - GrGLSLProgramDataManager::UniformHandle fScaleUni; + typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; + + UniformHandle fScaleUni; + GrGLSLColorSpaceXformHelper fColorSpaceHelper; GrTextureDomain::GLDomain fGLDomain; typedef GrGLSLFragmentProcessor INHERITED; @@ -467,33 +496,38 @@ GrGLSLFragmentProcessor* GrDisplacementMapEffect::onCreateGLSLInstance() const { return new GrGLDisplacementMapEffect; } -void GrDisplacementMapEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrDisplacementMapEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLDisplacementMapEffect::GenKey(*this, caps, b); } GrDisplacementMapEffect::GrDisplacementMapEffect( - SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, - SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, - const SkVector& scale, - GrTexture* displacement, - const SkMatrix& offsetMatrix, - GrTexture* color, - const SkISize& colorDimensions) - : fDisplacementTransform(offsetMatrix, displacement, GrTextureParams::kNone_FilterMode) - , fDisplacementAccess(displacement) - , fColorTransform(color, GrTextureParams::kNone_FilterMode) - , fDomain(GrTextureDomain::MakeTexelDomain(color, SkIRect::MakeSize(colorDimensions)), - GrTextureDomain::kDecal_Mode) - , fColorAccess(color) - , fXChannelSelector(xChannelSelector) - , fYChannelSelector(yChannelSelector) - , fScale(scale) { + GrResourceProvider* resourceProvider, + SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, + SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, + const SkVector& scale, + sk_sp displacement, + const SkMatrix& offsetMatrix, + sk_sp color, + sk_sp colorSpaceXform, + const SkISize& colorDimensions) + : INHERITED(GrPixelConfigIsOpaque(color->config()) ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags) + , fDisplacementTransform(resourceProvider, offsetMatrix, displacement.get()) + , fDisplacementSampler(resourceProvider, displacement) + , fColorTransform(resourceProvider, color.get()) + , fDomain(color.get(), GrTextureDomain::MakeTexelDomain(SkIRect::MakeSize(colorDimensions)), + GrTextureDomain::kDecal_Mode) + , fColorSampler(resourceProvider, color) + , fColorSpaceXform(std::move(colorSpaceXform)) + , fXChannelSelector(xChannelSelector) + , fYChannelSelector(yChannelSelector) + , fScale(scale) { this->initClassID(); this->addCoordTransform(&fDisplacementTransform); - this->addTextureAccess(&fDisplacementAccess); + this->addTextureSampler(&fDisplacementSampler); this->addCoordTransform(&fColorTransform); - this->addTextureAccess(&fColorAccess); + this->addTextureSampler(&fColorSampler); } GrDisplacementMapEffect::~GrDisplacementMapEffect() { @@ -506,24 +540,18 @@ bool GrDisplacementMapEffect::onIsEqual(const GrFragmentProcessor& sBase) const fScale == s.fScale; } -void GrDisplacementMapEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - // Any displacement offset bringing a pixel out of bounds will output a color of (0,0,0,0), - // so the only way we'd get a constant alpha is if the input color image has a constant alpha - // and no displacement offset push any texture coordinates out of bounds OR if the constant - // alpha is 0. Since this isn't trivial to compute at this point, let's assume the output is - // not of constant color when a displacement effect is applied. - inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput); -} - /////////////////////////////////////////////////////////////////////////////// GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDisplacementMapEffect); +#if GR_TEST_UTILS sk_sp GrDisplacementMapEffect::TestCreate(GrProcessorTestData* d) { int texIdxDispl = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : GrProcessorUnitTest::kAlphaTextureIdx; int texIdxColor = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp dispProxy = d->textureProxy(texIdxDispl); + sk_sp colorProxy = d->textureProxy(texIdxColor); static const int kMaxComponent = 4; SkDisplacementMapEffect::ChannelSelectorType xChannelSelector = static_cast( @@ -534,12 +562,16 @@ sk_sp GrDisplacementMapEffect::TestCreate(GrProcessorTestDa SkVector scale = SkVector::Make(d->fRandom->nextRangeScalar(0, 100.0f), d->fRandom->nextRangeScalar(0, 100.0f)); SkISize colorDimensions; - colorDimensions.fWidth = d->fRandom->nextRangeU(0, d->fTextures[texIdxColor]->width()); - colorDimensions.fHeight = d->fRandom->nextRangeU(0, d->fTextures[texIdxColor]->height()); - return GrDisplacementMapEffect::Make(xChannelSelector, yChannelSelector, scale, - d->fTextures[texIdxDispl], SkMatrix::I(), - d->fTextures[texIdxColor], colorDimensions); + colorDimensions.fWidth = d->fRandom->nextRangeU(0, colorProxy->width()); + colorDimensions.fHeight = d->fRandom->nextRangeU(0, colorProxy->height()); + auto colorSpaceXform = GrTest::TestColorXform(d->fRandom); + return GrDisplacementMapEffect::Make(d->resourceProvider(), + xChannelSelector, yChannelSelector, scale, + std::move(dispProxy), SkMatrix::I(), + std::move(colorProxy), colorSpaceXform, + colorDimensions); } +#endif /////////////////////////////////////////////////////////////////////////////// @@ -552,10 +584,12 @@ void GrGLDisplacementMapEffect::emitCode(EmitArgs& args) { const char* scaleUni = args.fUniformHandler->getUniformCStr(fScaleUni); const char* dColor = "dColor"; const char* cCoords = "cCoords"; - const char* nearZero = "1e-6"; // Since 6.10352e−5 is the smallest half float, use + const char* nearZero = "1e-6"; // Since 6.10352e-5 is the smallest half float, use // a number smaller than that to approximate 0, but // leave room for 32-bit float GPU rounding errors. + fColorSpaceHelper.emitCode(args.fUniformHandler, displacementMap.colorSpaceXform()); + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("\t\tvec4 %s = ", dColor); fragBuilder->appendTextureLookup(args.fTexSamplers[0], args.fTransformedCoords[0].c_str(), @@ -609,33 +643,39 @@ void GrGLDisplacementMapEffect::emitCode(EmitArgs& args) { fGLDomain.sampleTexture(fragBuilder, args.fUniformHandler, - args.fGLSLCaps, + args.fShaderCaps, domain, args.fOutputColor, SkString(cCoords), - args.fTexSamplers[1]); + args.fTexSamplers[1], + nullptr, + &fColorSpaceHelper); fragBuilder->codeAppend(";\n"); } void GrGLDisplacementMapEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) { + const GrFragmentProcessor& proc) { const GrDisplacementMapEffect& displacementMap = proc.cast(); - GrTexture* colorTex = displacementMap.texture(1); + GrTexture* colorTex = displacementMap.textureSampler(1).texture(); SkScalar scaleX = displacementMap.scale().fX / colorTex->width(); SkScalar scaleY = displacementMap.scale().fY / colorTex->height(); pdman.set2f(fScaleUni, SkScalarToFloat(scaleX), colorTex->origin() == kTopLeft_GrSurfaceOrigin ? SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY)); - fGLDomain.setData(pdman, displacementMap.domain(), colorTex->origin()); + fGLDomain.setData(pdman, displacementMap.domain(), colorTex); + if (SkToBool(displacementMap.colorSpaceXform())) { + fColorSpaceHelper.setData(pdman, displacementMap.colorSpaceXform()); + } } void GrGLDisplacementMapEffect::GenKey(const GrProcessor& proc, - const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrDisplacementMapEffect& displacementMap = proc.cast(); uint32_t xKey = displacementMap.xChannelSelector(); uint32_t yKey = displacementMap.yChannelSelector() << kChannelSelectorKeyBits; b->add32(xKey | yKey); + b->add32(GrColorSpaceXform::XformKey(displacementMap.colorSpaceXform())); } #endif diff --git a/gfx/skia/skia/src/effects/SkDropShadowImageFilter.cpp b/gfx/skia/skia/src/effects/SkDropShadowImageFilter.cpp index cc43db7f08b2..af1480916bc1 100644 --- a/gfx/skia/skia/src/effects/SkDropShadowImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkDropShadowImageFilter.cpp @@ -9,6 +9,7 @@ #include "SkBlurImageFilter.h" #include "SkCanvas.h" +#include "SkColorSpaceXformer.h" #include "SkReadBuffer.h" #include "SkSpecialImage.h" #include "SkSpecialSurface.h" @@ -93,8 +94,9 @@ sk_sp SkDropShadowImageFilter::onFilterImage(SkSpecialImage* sou sigma.fY = SkMaxScalar(0, sigma.fY); SkPaint paint; + paint.setAntiAlias(true); paint.setImageFilter(SkBlurImageFilter::Make(sigma.fX, sigma.fY, nullptr)); - paint.setColorFilter(SkColorFilter::MakeModeFilter(fColor, SkXfermode::kSrcIn_Mode)); + paint.setColorFilter(SkColorFilter::MakeModeFilter(fColor, SkBlendMode::kSrcIn)); SkVector offsetVec = SkVector::Make(fDx, fDy); ctx.ctm().mapVectors(&offsetVec, 1); @@ -111,12 +113,21 @@ sk_sp SkDropShadowImageFilter::onFilterImage(SkSpecialImage* sou return surf->makeImageSnapshot(); } +sk_sp SkDropShadowImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + SkASSERT(1 == this->countInputs()); + + sk_sp input = + this->getInput(0) ? this->getInput(0)->makeColorSpace(xformer) : nullptr; + + return SkDropShadowImageFilter::Make(fDx, fDy, fSigmaX, fSigmaY, xformer->apply(fColor), + fShadowMode, std::move(input)); +} + SkRect SkDropShadowImageFilter::computeFastBounds(const SkRect& src) const { SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src; SkRect shadowBounds = bounds; shadowBounds.offset(fDx, fDy); - shadowBounds.outset(SkScalarMul(fSigmaX, SkIntToScalar(3)), - SkScalarMul(fSigmaY, SkIntToScalar(3))); + shadowBounds.outset(fSigmaX * 3, fSigmaY * 3); if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { bounds.join(shadowBounds); } else { @@ -137,8 +148,8 @@ SkIRect SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const Sk SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); ctm.mapVectors(&sigma, 1); dst.outset( - SkScalarCeilToInt(SkScalarAbs(SkScalarMul(sigma.x(), SkIntToScalar(3)))), - SkScalarCeilToInt(SkScalarAbs(SkScalarMul(sigma.y(), SkIntToScalar(3))))); + SkScalarCeilToInt(SkScalarAbs(sigma.x() * 3)), + SkScalarCeilToInt(SkScalarAbs(sigma.y() * 3))); if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { dst.join(src); } diff --git a/gfx/skia/skia/src/effects/SkEmbossMaskFilter.cpp b/gfx/skia/skia/src/effects/SkEmbossMaskFilter.cpp index 5f3952d1ad84..4caef9ef0ba8 100644 --- a/gfx/skia/skia/src/effects/SkEmbossMaskFilter.cpp +++ b/gfx/skia/skia/src/effects/SkEmbossMaskFilter.cpp @@ -17,15 +17,7 @@ sk_sp SkEmbossMaskFilter::Make(SkScalar blurSigma, const Light& li return sk_sp(new SkEmbossMaskFilter(blurSigma, light)); } -#ifdef SK_SUPPORT_LEGACY_MASKFILTER_PTR -SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3], - SkScalar ambient, SkScalar specular, - SkScalar blurRadius) { - return SkBlurMaskFilter::CreateEmboss(SkBlurMask::ConvertRadiusToSigma(blurRadius), - direction, ambient, specular); -} -#endif - +#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER sk_sp SkBlurMaskFilter::MakeEmboss(SkScalar blurSigma, const SkScalar direction[3], SkScalar ambient, SkScalar specular) { if (direction == nullptr) { @@ -43,6 +35,7 @@ sk_sp SkBlurMaskFilter::MakeEmboss(SkScalar blurSigma, const SkSca return SkEmbossMaskFilter::Make(blurSigma, light); } +#endif /////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/include/effects/SkEmbossMaskFilter.h b/gfx/skia/skia/src/effects/SkEmbossMaskFilter.h similarity index 88% rename from gfx/skia/skia/include/effects/SkEmbossMaskFilter.h rename to gfx/skia/skia/src/effects/SkEmbossMaskFilter.h index 8a3428245185..395657224c92 100644 --- a/gfx/skia/skia/include/effects/SkEmbossMaskFilter.h +++ b/gfx/skia/skia/src/effects/SkEmbossMaskFilter.h @@ -25,12 +25,6 @@ public: static sk_sp Make(SkScalar blurSigma, const Light& light); -#ifdef SK_SUPPORT_LEGACY_MASKFILTER_PTR - static SkMaskFilter* Create(SkScalar blurSigma, const Light& light) { - return Make(blurSigma, light).release(); - } -#endif - // overrides from SkMaskFilter // This method is not exported to java. SkMask::Format getFormat() const override; diff --git a/gfx/skia/skia/src/effects/SkEmbossMask_Table.h b/gfx/skia/skia/src/effects/SkEmbossMask_Table.h index b7073f302b71..09fc348b38b2 100644 --- a/gfx/skia/skia/src/effects/SkEmbossMask_Table.h +++ b/gfx/skia/skia/src/effects/SkEmbossMask_Table.h @@ -4,7 +4,8 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - +#ifndef SkEmbossMask_Table_DEFINED +#define SkEmbossMask_Table_DEFINED #include "SkTypes.h" @@ -1035,3 +1036,4 @@ static const uint16_t gInvSqrtTable[128 * 128] = { 0x00C0, 0x00C0, 0x00BF, 0x00BE, 0x00BE, 0x00BD, 0x00BC, 0x00BC, 0x00BB, 0x00BA, 0x00BA, 0x00B9, 0x00B8, 0x00B8, 0x00B7, 0x00B6 }; #define kDeltaUsedToBuildTable 32 +#endif // SkEmbossMask_Table_DEFINED diff --git a/gfx/skia/skia/src/effects/SkGammaColorFilter.cpp b/gfx/skia/skia/src/effects/SkGammaColorFilter.cpp deleted file mode 100644 index eba8e320d8fa..000000000000 --- a/gfx/skia/skia/src/effects/SkGammaColorFilter.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkGammaColorFilter.h" - -#include "SkReadBuffer.h" -#include "SkString.h" - -#if SK_SUPPORT_GPU -#include "effects/GrGammaEffect.h" -#endif - -void SkGammaColorFilter::filterSpan(const SkPMColor src[], int count, - SkPMColor dst[]) const { - // Gamma-correcting bytes to bytes is pretty questionable. - SkASSERT(0); - for (int i = 0; i < count; ++i) { - SkPMColor c = src[i]; - - // TODO: implement cpu gamma correction? - dst[i] = c; - } -} - -sk_sp SkGammaColorFilter::Make(SkScalar gamma) { - return sk_sp(new SkGammaColorFilter(gamma)); -} - -SkGammaColorFilter::SkGammaColorFilter(SkScalar gamma) : fGamma(gamma) {} - -sk_sp SkGammaColorFilter::CreateProc(SkReadBuffer& buffer) { - SkScalar gamma = buffer.readScalar(); - - return Make(gamma); -} - -void SkGammaColorFilter::flatten(SkWriteBuffer& buffer) const { - this->INHERITED::flatten(buffer); - buffer.writeScalar(fGamma); -} - -#ifndef SK_IGNORE_TO_STRING -void SkGammaColorFilter::toString(SkString* str) const { - str->appendf("SkGammaColorFilter (%.2f)", fGamma); -} -#endif - -#if SK_SUPPORT_GPU -sk_sp SkGammaColorFilter::asFragmentProcessor(GrContext*) const { - return GrGammaEffect::Make(fGamma); -} -#endif diff --git a/gfx/skia/skia/src/effects/SkGaussianEdgeShader.cpp b/gfx/skia/skia/src/effects/SkGaussianEdgeShader.cpp index ddc5d96fc8b4..7bbbb79117c3 100644 --- a/gfx/skia/skia/src/effects/SkGaussianEdgeShader.cpp +++ b/gfx/skia/skia/src/effects/SkGaussianEdgeShader.cpp @@ -9,21 +9,17 @@ #include "SkReadBuffer.h" #include "SkWriteBuffer.h" +class SkArenaAlloc; + /** \class SkGaussianEdgeShaderImpl This subclass of shader applies a Gaussian to shadow edge - If largerBlur is false: - The radius of the Gaussian blur is specified by the g value of the color, in 6.2 fixed point. - For spot shadows, we increase the stroke width to set the shadow against the shape. This pad - is specified by b, also in 6.2 fixed point. The r value represents the max final alpha. - The incoming alpha should be 1. + If the primitive supports an implicit distance to the edge, the radius of the blur is specified + by r & g values of the color in 14.2 fixed point. For spot shadows, we increase the stroke width + to set the shadow against the shape. This pad is specified by b, also in 6.2 fixed point. - If largerBlur is true: - The radius of the Gaussian blur is specified by the r & g values of the color in 14.2 fixed point. - For spot shadows, we increase the stroke width to set the shadow against the shape. This pad - is specified by b, also in 6.2 fixed point. The a value represents the max final alpha. - - LargerBlur will be removed once Android is migrated to the updated shader. + When not using implicit distance, then b in the input color represents the input to the + blur function. */ class SkGaussianEdgeShaderImpl : public SkShader { public: @@ -40,7 +36,9 @@ public: protected: void flatten(SkWriteBuffer&) const override; - + Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* storage) const override { + return nullptr; + } private: friend class SkGaussianEdgeShader; @@ -51,84 +49,12 @@ private: #if SK_SUPPORT_GPU -#include "GrCoordTransform.h" -#include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" -#include "glsl/GrGLSLFragmentProcessor.h" -#include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLUniformHandler.h" -#include "SkGr.h" -#include "SkGrPriv.h" - -class GaussianEdgeFP : public GrFragmentProcessor { -public: - GaussianEdgeFP() { - this->initClassID(); - - // enable output of distance information for shape - fUsesDistanceVectorField = true; - } - - class GLSLGaussianEdgeFP : public GrGLSLFragmentProcessor { - public: - GLSLGaussianEdgeFP() {} - - void emitCode(EmitArgs& args) override { - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - - if (!args.fGpImplementsDistanceVector) { - fragBuilder->codeAppendf("// GP does not implement fsDistanceVector - " - " returning grey in GLSLGaussianEdgeFP\n"); - fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor); - fragBuilder->codeAppendf("%s = vec4(0.0, 0.0, 0.0, color.r);", args.fOutputColor); - } else { - fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor); - fragBuilder->codeAppend("float radius = color.r*256.0*64.0 + color.g*64.0;"); - fragBuilder->codeAppend("float pad = color.b*64.0;"); - - fragBuilder->codeAppendf("float factor = 1.0 - clamp((%s.z - pad)/radius, 0.0, 1.0);", - fragBuilder->distanceVectorName()); - fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;"); - fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.a);", - args.fOutputColor); - } - } - - static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { - // only one shader generated currently - b->add32(0x0); - } - - protected: - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {} - - bool fLargerBlur; - }; - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { - GLSLGaussianEdgeFP::GenKey(*this, caps, b); - } - - const char* name() const override { return "GaussianEdgeFP"; } - - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->mulByUnknownFourComponents(); - } - -private: - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { - return new GLSLGaussianEdgeFP(); - } - - bool onIsEqual(const GrFragmentProcessor& proc) const override { return true; } -}; +#include "effects/GrBlurredEdgeFragmentProcessor.h" //////////////////////////////////////////////////////////////////////////// sk_sp SkGaussianEdgeShaderImpl::asFragmentProcessor(const AsFPArgs&) const { - return sk_make_sp(); + return GrBlurredEdgeFP::Make(GrBlurredEdgeFP::kGaussian_Mode); } #endif diff --git a/gfx/skia/skia/include/effects/SkGaussianEdgeShader.h b/gfx/skia/skia/src/effects/SkGaussianEdgeShader.h similarity index 100% rename from gfx/skia/skia/include/effects/SkGaussianEdgeShader.h rename to gfx/skia/skia/src/effects/SkGaussianEdgeShader.h diff --git a/gfx/skia/skia/src/effects/SkHighContrastFilter.cpp b/gfx/skia/skia/src/effects/SkHighContrastFilter.cpp new file mode 100644 index 000000000000..5d92cdf0d023 --- /dev/null +++ b/gfx/skia/skia/src/effects/SkHighContrastFilter.cpp @@ -0,0 +1,470 @@ +/* +* Copyright 2017 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#include "SkHighContrastFilter.h" + +#include "SkArenaAlloc.h" +#include "SkRasterPipeline.h" +#include "SkReadBuffer.h" +#include "SkString.h" +#include "SkWriteBuffer.h" + +#if SK_SUPPORT_GPU +#include "GrContext.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#endif + +using InvertStyle = SkHighContrastConfig::InvertStyle; + +namespace { + +SkScalar Hue2RGB(SkScalar p, SkScalar q, SkScalar t) { + if (t < 0) { + t += 1; + } else if (t > 1) { + t -= 1; + } + + if (t < 1/6.f) { + return p + (q - p) * 6 * t; + } + + if (t < 1/2.f) { + return q; + } + + if (t < 2/3.f) { + return p + (q - p) * (2/3.f - t) * 6; + } + + return p; +} + +uint8_t SkScalarToUint8Clamp(SkScalar f) { + if (f <= 0) { + return 0; + } else if (f >= 1) { + return 255; + } + return static_cast(255 * f); +} + +SkScalar IncreaseContrast(SkScalar f, SkScalar contrast) { + SkScalar m = (1 + contrast) / (1 - contrast); + SkScalar b = (-0.5f * m + 0.5f); + return m * f + b; +} + +static SkPMColor ApplyHighContrastFilter(const SkHighContrastConfig& config, + SkPMColor pmColor) { + SkColor color = SkUnPreMultiply::PMColorToColor(pmColor); + SkScalar rf = SkColorGetR(color) / 255.f; + SkScalar gf = SkColorGetG(color) / 255.f; + SkScalar bf = SkColorGetB(color) / 255.f; + + // Apply a gamma of 2.0 so that the rest of the calculations + // happen roughly in linear space. + rf *= rf; + gf *= gf; + bf *= bf; + + // Convert to grayscale using luminance coefficients. + if (config.fGrayscale) { + SkScalar lum = + rf * SK_LUM_COEFF_R + gf * SK_LUM_COEFF_G + bf * SK_LUM_COEFF_B; + rf = lum; + gf = lum; + bf = lum; + } + + // Now invert. + if (config.fInvertStyle == InvertStyle::kInvertBrightness) { + rf = 1 - rf; + gf = 1 - gf; + bf = 1 - bf; + } else if (config.fInvertStyle == InvertStyle::kInvertLightness) { + // Convert to HSL + SkScalar max = SkTMax(SkTMax(rf, gf), bf); + SkScalar min = SkTMin(SkTMin(rf, gf), bf); + SkScalar l = (max + min) / 2; + SkScalar h, s; + + if (max == min) { + h = 0; + s = 0; + } else { + SkScalar d = max - min; + s = l > 0.5f ? d / (2 - max - min) : d / (max + min); + if (max == rf) { + h = (gf - bf) / d + (gf < bf ? 6 : 0); + } else if (max == gf) { + h = (bf - rf) / d + 2; + } else { + h = (rf - gf) / d + 4; + } + h /= 6; + } + + // Invert lightness. + l = 1 - l; + + // Now convert back to RGB. + if (s == 0) { + // Grayscale + rf = l; + gf = l; + bf = l; + } else { + SkScalar q = l < 0.5f ? l * (1 + s) : l + s - l * s; + SkScalar p = 2 * l - q; + rf = Hue2RGB(p, q, h + 1/3.f); + gf = Hue2RGB(p, q, h); + bf = Hue2RGB(p, q, h - 1/3.f); + } + } + + // Increase contrast. + if (config.fContrast != 0.0f) { + rf = IncreaseContrast(rf, config.fContrast); + gf = IncreaseContrast(gf, config.fContrast); + bf = IncreaseContrast(bf, config.fContrast); + } + + // Convert back from linear to a color space with a gamma of ~2.0. + rf = SkScalarSqrt(rf); + gf = SkScalarSqrt(gf); + bf = SkScalarSqrt(bf); + + return SkPremultiplyARGBInline(SkColorGetA(color), + SkScalarToUint8Clamp(rf), + SkScalarToUint8Clamp(gf), + SkScalarToUint8Clamp(bf)); +} + +} // namespace + +class SkHighContrast_Filter : public SkColorFilter { +public: + SkHighContrast_Filter(const SkHighContrastConfig& config) { + fConfig = config; + // Clamp contrast to just inside -1 to 1 to avoid division by zero. + fConfig.fContrast = SkScalarPin(fConfig.fContrast, + -1.0f + FLT_EPSILON, + 1.0f - FLT_EPSILON); + } + + ~SkHighContrast_Filter() override {} + +#if SK_SUPPORT_GPU + sk_sp asFragmentProcessor(GrContext*, SkColorSpace*) const override; + #endif + + void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const + override; + bool onAppendStages(SkRasterPipeline* p, + SkColorSpace* dst, + SkArenaAlloc* scratch, + bool shaderIsOpaque) const override; + + SK_TO_STRING_OVERRIDE() + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkHighContrast_Filter) + +protected: + void flatten(SkWriteBuffer&) const override; + +private: + SkHighContrastConfig fConfig; + + friend class SkHighContrastFilter; + + typedef SkColorFilter INHERITED; +}; + +void SkHighContrast_Filter::filterSpan(const SkPMColor src[], int count, + SkPMColor dst[]) const { + for (int i = 0; i < count; ++i) + dst[i] = ApplyHighContrastFilter(fConfig, src[i]); +} + +bool SkHighContrast_Filter::onAppendStages(SkRasterPipeline* p, + SkColorSpace* dst, + SkArenaAlloc* scratch, + bool shaderIsOpaque) const { + if (!shaderIsOpaque) { + p->append(SkRasterPipeline::unpremul); + } + + if (fConfig.fGrayscale) { + float r = SK_LUM_COEFF_R; + float g = SK_LUM_COEFF_G; + float b = SK_LUM_COEFF_B; + float* matrix = scratch->makeArray(12); + matrix[0] = matrix[1] = matrix[2] = r; + matrix[3] = matrix[4] = matrix[5] = g; + matrix[6] = matrix[7] = matrix[8] = b; + p->append(SkRasterPipeline::matrix_3x4, matrix); + } + + if (fConfig.fInvertStyle == InvertStyle::kInvertBrightness) { + float* matrix = scratch->makeArray(12); + matrix[0] = matrix[4] = matrix[8] = -1; + matrix[9] = matrix[10] = matrix[11] = 1; + p->append(SkRasterPipeline::matrix_3x4, matrix); + } else if (fConfig.fInvertStyle == InvertStyle::kInvertLightness) { + p->append(SkRasterPipeline::rgb_to_hsl); + float* matrix = scratch->makeArray(12); + matrix[0] = matrix[4] = matrix[11] = 1; + matrix[8] = -1; + p->append(SkRasterPipeline::matrix_3x4, matrix); + p->append(SkRasterPipeline::hsl_to_rgb); + } + + if (fConfig.fContrast != 0.0) { + float* matrix = scratch->makeArray(12); + float c = fConfig.fContrast; + float m = (1 + c) / (1 - c); + float b = (-0.5f * m + 0.5f); + matrix[0] = matrix[4] = matrix[8] = m; + matrix[9] = matrix[10] = matrix[11] = b; + p->append(SkRasterPipeline::matrix_3x4, matrix); + } + + p->append(SkRasterPipeline::clamp_0); + p->append(SkRasterPipeline::clamp_1); + + if (!shaderIsOpaque) { + p->append(SkRasterPipeline::premul); + } + + return true; +} + +void SkHighContrast_Filter::flatten(SkWriteBuffer& buffer) const { + buffer.writeBool(fConfig.fGrayscale); + buffer.writeInt(static_cast(fConfig.fInvertStyle)); + buffer.writeScalar(fConfig.fContrast); +} + +sk_sp SkHighContrast_Filter::CreateProc(SkReadBuffer& buffer) { + SkHighContrastConfig config; + config.fGrayscale = buffer.readBool(); + config.fInvertStyle = static_cast(buffer.readInt()); + config.fContrast = buffer.readScalar(); + return SkHighContrastFilter::Make(config); +} + +sk_sp SkHighContrastFilter::Make( + const SkHighContrastConfig& config) { + if (!config.isValid()) + return nullptr; + return sk_make_sp(config); +} + +#ifndef SK_IGNORE_TO_STRING +void SkHighContrast_Filter::toString(SkString* str) const { + str->append("SkHighContrastColorFilter "); +} +#endif + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkHighContrastFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkHighContrast_Filter) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END + +#if SK_SUPPORT_GPU +class HighContrastFilterEffect : public GrFragmentProcessor { +public: + static sk_sp Make(const SkHighContrastConfig& config) { + return sk_sp(new HighContrastFilterEffect(config)); + } + + const char* name() const override { return "HighContrastFilter"; } + + const SkHighContrastConfig& config() const { return fConfig; } + +private: + HighContrastFilterEffect(const SkHighContrastConfig& config) + : INHERITED(kNone_OptimizationFlags) + , fConfig(config) { + this->initClassID(); + } + + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + + virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const override; + + bool onIsEqual(const GrFragmentProcessor& other) const override { + const HighContrastFilterEffect& that = other.cast(); + return fConfig.fGrayscale == that.fConfig.fGrayscale && + fConfig.fInvertStyle == that.fConfig.fInvertStyle && + fConfig.fContrast == that.fConfig.fContrast; + } + + SkHighContrastConfig fConfig; + + typedef GrFragmentProcessor INHERITED; +}; + +class GLHighContrastFilterEffect : public GrGLSLFragmentProcessor { +public: + static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); + + GLHighContrastFilterEffect(const SkHighContrastConfig& config); + +protected: + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; + void emitCode(EmitArgs& args) override; + +private: + UniformHandle fContrastUni; + SkHighContrastConfig fConfig; + + typedef GrGLSLFragmentProcessor INHERITED; +}; + +GrGLSLFragmentProcessor* HighContrastFilterEffect::onCreateGLSLInstance() const { + return new GLHighContrastFilterEffect(fConfig); +} + +void HighContrastFilterEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const { + GLHighContrastFilterEffect::GenKey(*this, caps, b); +} + +void GLHighContrastFilterEffect::onSetData(const GrGLSLProgramDataManager& pdm, + const GrFragmentProcessor& proc) { + const HighContrastFilterEffect& hcfe = proc.cast(); + pdm.set1f(fContrastUni, hcfe.config().fContrast); +} + +GLHighContrastFilterEffect::GLHighContrastFilterEffect(const SkHighContrastConfig& config) + : INHERITED() + , fConfig(config) { +} + +void GLHighContrastFilterEffect::GenKey( + const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) { + const HighContrastFilterEffect& hcfe = proc.cast(); + b->add32(static_cast(hcfe.config().fGrayscale)); + b->add32(static_cast(hcfe.config().fInvertStyle)); +} + +void GLHighContrastFilterEffect::emitCode(EmitArgs& args) { + const char* contrast; + fContrastUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, + kFloat_GrSLType, kDefault_GrSLPrecision, + "contrast", &contrast); + + if (nullptr == args.fInputColor) { + args.fInputColor = "vec4(1)"; + } + + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + + fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor); + + // Unpremultiply. The max() is to guard against 0 / 0. + fragBuilder->codeAppendf("float nonZeroAlpha = max(color.a, 0.00001);"); + fragBuilder->codeAppendf("color = vec4(color.rgb / nonZeroAlpha, nonZeroAlpha);"); + + // Grayscale. + if (fConfig.fGrayscale) { + fragBuilder->codeAppendf("float luma = dot(color, vec4(%f, %f, %f, 0));", + SK_LUM_COEFF_R, SK_LUM_COEFF_G, SK_LUM_COEFF_B); + fragBuilder->codeAppendf("color = vec4(luma, luma, luma, 0);"); + } + + if (fConfig.fInvertStyle == InvertStyle::kInvertBrightness) { + fragBuilder->codeAppendf("color = vec4(1, 1, 1, 1) - color;"); + } + + if (fConfig.fInvertStyle == InvertStyle::kInvertLightness) { + // Convert from RGB to HSL. + fragBuilder->codeAppendf("float fmax = max(color.r, max(color.g, color.b));"); + fragBuilder->codeAppendf("float fmin = min(color.r, min(color.g, color.b));"); + fragBuilder->codeAppendf("float l = (fmax + fmin) / 2;"); + + fragBuilder->codeAppendf("float h;"); + fragBuilder->codeAppendf("float s;"); + + fragBuilder->codeAppendf("if (fmax == fmin) {"); + fragBuilder->codeAppendf(" h = 0;"); + fragBuilder->codeAppendf(" s = 0;"); + fragBuilder->codeAppendf("} else {"); + fragBuilder->codeAppendf(" float d = fmax - fmin;"); + fragBuilder->codeAppendf(" s = l > 0.5 ?"); + fragBuilder->codeAppendf(" d / (2 - fmax - fmin) :"); + fragBuilder->codeAppendf(" d / (fmax + fmin);"); + fragBuilder->codeAppendf(" if (fmax == color.r) {"); + fragBuilder->codeAppendf(" h = (color.g - color.b) / d + "); + fragBuilder->codeAppendf(" (color.g < color.b ? 6 : 0);"); + fragBuilder->codeAppendf(" } else if (fmax == color.g) {"); + fragBuilder->codeAppendf(" h = (color.b - color.r) / d + 2;"); + fragBuilder->codeAppendf(" } else {"); + fragBuilder->codeAppendf(" h = (color.r - color.g) / d + 4;"); + fragBuilder->codeAppendf(" }"); + fragBuilder->codeAppendf("}"); + fragBuilder->codeAppendf("h /= 6;"); + fragBuilder->codeAppendf("l = 1.0 - l;"); + // Convert back from HSL to RGB. + SkString hue2rgbFuncName; + static const GrShaderVar gHue2rgbArgs[] = { + GrShaderVar("p", kFloat_GrSLType), + GrShaderVar("q", kFloat_GrSLType), + GrShaderVar("t", kFloat_GrSLType), + }; + fragBuilder->emitFunction(kFloat_GrSLType, + "hue2rgb", + SK_ARRAY_COUNT(gHue2rgbArgs), + gHue2rgbArgs, + "if (t < 0)" + " t += 1;" + "if (t > 1)" + " t -= 1;" + "if (t < 1/6.)" + " return p + (q - p) * 6 * t;" + "if (t < 1/2.)" + " return q;" + "if (t < 2/3.)" + " return p + (q - p) * (2/3. - t) * 6;" + "return p;", + &hue2rgbFuncName); + fragBuilder->codeAppendf("if (s == 0) {"); + fragBuilder->codeAppendf(" color = vec4(l, l, l, 0);"); + fragBuilder->codeAppendf("} else {"); + fragBuilder->codeAppendf(" float q = l < 0.5 ? l * (1 + s) : l + s - l * s;"); + fragBuilder->codeAppendf(" float p = 2 * l - q;"); + fragBuilder->codeAppendf(" color.r = %s(p, q, h + 1/3.);", hue2rgbFuncName.c_str()); + fragBuilder->codeAppendf(" color.g = %s(p, q, h);", hue2rgbFuncName.c_str()); + fragBuilder->codeAppendf(" color.b = %s(p, q, h - 1/3.);", hue2rgbFuncName.c_str()); + fragBuilder->codeAppendf("}"); + } + + // Contrast. + fragBuilder->codeAppendf("if (%s != 0) {", contrast); + fragBuilder->codeAppendf(" float m = (1 + %s) / (1 - %s);", contrast, contrast); + fragBuilder->codeAppendf(" float off = (-0.5 * m + 0.5);"); + fragBuilder->codeAppendf(" color = m * color + off;"); + fragBuilder->codeAppendf("}"); + + // Clamp. + fragBuilder->codeAppendf("color = clamp(color, 0, 1);"); + + // Restore the original alpha and premultiply. + fragBuilder->codeAppendf("color.a = %s.a;", args.fInputColor); + fragBuilder->codeAppendf("color.rgb *= color.a;"); + + // Copy to the output color. + fragBuilder->codeAppendf("%s = color;", args.fOutputColor); +} + +sk_sp SkHighContrast_Filter::asFragmentProcessor(GrContext*, SkColorSpace*) const { + return HighContrastFilterEffect::Make(fConfig); +} +#endif diff --git a/gfx/skia/skia/src/effects/SkImageSource.cpp b/gfx/skia/skia/src/effects/SkImageSource.cpp index f96a4a16769b..e051160403d4 100644 --- a/gfx/skia/skia/src/effects/SkImageSource.cpp +++ b/gfx/skia/skia/src/effects/SkImageSource.cpp @@ -8,6 +8,7 @@ #include "SkImageSource.h" #include "SkCanvas.h" +#include "SkColorSpaceXformer.h" #include "SkImage.h" #include "SkReadBuffer.h" #include "SkSpecialImage.h" @@ -27,7 +28,7 @@ sk_sp SkImageSource::Make(sk_sp image, const SkRect& srcRect, const SkRect& dstRect, SkFilterQuality filterQuality) { - if (!image) { + if (!image || srcRect.width() <= 0.0f || srcRect.height() <= 0.0f) { return nullptr; } @@ -83,12 +84,21 @@ sk_sp SkImageSource::onFilterImage(SkSpecialImage* source, const ctx.ctm().mapRect(&dstRect, fDstRect); SkRect bounds = SkRect::MakeIWH(fImage->width(), fImage->height()); - if (fSrcRect == bounds && dstRect == bounds) { - // No regions cropped out or resized; return entire image. - offset->fX = offset->fY = 0; - return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(fImage->width(), fImage->height()), - fImage, - &source->props()); + if (fSrcRect == bounds) { + int iLeft = dstRect.fLeft; + int iTop = dstRect.fTop; + // TODO: this seems to be a very noise-prone way to determine this (esp. the floating-point + // widths & heights). + if (dstRect.width() == bounds.width() && dstRect.height() == bounds.height() && + iLeft == dstRect.fLeft && iTop == dstRect.fTop) { + // The dest is just an un-scaled integer translation of the entire image; return it + offset->fX = iLeft; + offset->fY = iTop; + + return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(fImage->width(), fImage->height()), + fImage, ctx.outputProperties().colorSpace(), + &source->props()); + } } const SkIRect dstIRect = dstRect.roundOut(); @@ -122,6 +132,12 @@ sk_sp SkImageSource::onFilterImage(SkSpecialImage* source, const return surf->makeImageSnapshot(); } +sk_sp SkImageSource::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + SkASSERT(0 == this->countInputs()); + + return SkImageSource::Make(xformer->apply(fImage.get()), fSrcRect, fDstRect, fFilterQuality); +} + SkRect SkImageSource::computeFastBounds(const SkRect& src) const { return fDstRect; } diff --git a/gfx/skia/skia/src/effects/SkLayerDrawLooper.cpp b/gfx/skia/skia/src/effects/SkLayerDrawLooper.cpp index 784228fa8b2c..feeea66a3589 100644 --- a/gfx/skia/skia/src/effects/SkLayerDrawLooper.cpp +++ b/gfx/skia/skia/src/effects/SkLayerDrawLooper.cpp @@ -4,7 +4,11 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#include "SkArenaAlloc.h" +#include "SkBlurDrawLooper.h" +#include "SkBlurMaskFilter.h" #include "SkCanvas.h" +#include "SkColorSpaceXformer.h" #include "SkColor.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" @@ -15,7 +19,7 @@ SkLayerDrawLooper::LayerInfo::LayerInfo() { fPaintBits = 0; // ignore our paint fields - fColorMode = SkXfermode::kDst_Mode; // ignore our color + fColorMode = SkBlendMode::kDst; // ignore our color fOffset.set(0, 0); fPostTranslate = false; } @@ -34,16 +38,17 @@ SkLayerDrawLooper::~SkLayerDrawLooper() { } } -SkLayerDrawLooper::Context* SkLayerDrawLooper::createContext(SkCanvas* canvas, void* storage) const { +SkLayerDrawLooper::Context* +SkLayerDrawLooper::makeContext(SkCanvas* canvas, SkArenaAlloc* alloc) const { canvas->save(); - return new (storage) LayerDrawLooperContext(this); + return alloc->make(this); } -static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) { +static SkColor xferColor(SkColor src, SkColor dst, SkBlendMode mode) { switch (mode) { - case SkXfermode::kSrc_Mode: + case SkBlendMode::kSrc: return src; - case SkXfermode::kDst_Mode: + case SkBlendMode::kDst: return dst; default: { SkPMColor pmS = SkPreMultiplyColor(src); @@ -59,8 +64,15 @@ static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) { // text/length parameters of a draw[Pos]Text call. void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo( SkPaint* dst, const SkPaint& src, const LayerInfo& info) { - - dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode)); + SkColor srcColor = src.getColor(); +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + // The framework may respect the alpha value on the original paint. + // Match this legacy behavior. + if (SkColorGetA(srcColor) == 255) { + srcColor = SkColorSetA(srcColor, dst->getAlpha()); + } +#endif + dst->setColor(xferColor(srcColor, dst->getColor(), (SkBlendMode)info.fColorMode)); BitFlags bits = info.fPaintBits; SkPaint::TextEncoding encoding = dst->getTextEncoding(); @@ -92,16 +104,16 @@ void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo( } if (bits & kPathEffect_Bit) { - dst->setPathEffect(sk_ref_sp(src.getPathEffect())); + dst->setPathEffect(src.refPathEffect()); } if (bits & kMaskFilter_Bit) { - dst->setMaskFilter(sk_ref_sp(src.getMaskFilter())); + dst->setMaskFilter(src.refMaskFilter()); } if (bits & kShader_Bit) { - dst->setShader(sk_ref_sp(src.getShader())); + dst->setShader(src.refShader()); } if (bits & kColorFilter_Bit) { - dst->setColorFilter(sk_ref_sp(src.getColorFilter())); + dst->setColorFilter(src.refColorFilter()); } if (bits & kXfermode_Bit) { dst->setBlendMode(src.getBlendMode()); @@ -161,7 +173,7 @@ bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const { if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) { return false; } - if (SkXfermode::kSrc_Mode != rec->fInfo.fColorMode) { + if (SkBlendMode::kSrc != (SkBlendMode)rec->fInfo.fColorMode) { return false; } const SkMaskFilter* mf = rec->fPaint.getMaskFilter(); @@ -178,7 +190,7 @@ bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const { if (rec->fInfo.fPaintBits) { return false; } - if (SkXfermode::kDst_Mode != rec->fInfo.fColorMode) { + if (SkBlendMode::kDst != (SkBlendMode)rec->fInfo.fColorMode) { return false; } if (!rec->fInfo.fOffset.equals(0, 0)) { @@ -195,6 +207,37 @@ bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const { return true; } +sk_sp SkLayerDrawLooper::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + if (!fCount) { + return sk_ref_sp(const_cast(this)); + } + + auto looper = sk_sp(new SkLayerDrawLooper()); + looper->fCount = fCount; + + Rec* oldRec = fRecs; + Rec* newTopRec = new Rec(); + newTopRec->fInfo = oldRec->fInfo; + newTopRec->fPaint = xformer->apply(oldRec->fPaint); + newTopRec->fNext = nullptr; + + Rec* prevNewRec = newTopRec; + oldRec = oldRec->fNext; + while (oldRec) { + Rec* newRec = new Rec(); + newRec->fInfo = oldRec->fInfo; + newRec->fPaint = xformer->apply(oldRec->fPaint); + newRec->fNext = nullptr; + prevNewRec->fNext = newRec; + + prevNewRec = newRec; + oldRec = oldRec->fNext; + } + + looper->fRecs = newTopRec; + return std::move(looper); +} + /////////////////////////////////////////////////////////////////////////////// void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const { @@ -206,7 +249,7 @@ void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const { buffer.writeInt(0); buffer.writeInt(rec->fInfo.fPaintBits); - buffer.writeInt(rec->fInfo.fColorMode); + buffer.writeInt((int)rec->fInfo.fColorMode); buffer.writePoint(rec->fInfo.fOffset); buffer.writeBool(rec->fInfo.fPostTranslate); buffer.writePaint(rec->fPaint); @@ -224,7 +267,7 @@ sk_sp SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) { (void)buffer.readInt(); info.fPaintBits = buffer.readInt(); - info.fColorMode = (SkXfermode::Mode)buffer.readInt(); + info.fColorMode = (SkBlendMode)buffer.readInt(); buffer.readPoint(&info.fOffset); info.fPostTranslate = buffer.readBool(); buffer.readPaint(builder.addLayerOnTop(info)); @@ -262,14 +305,14 @@ void SkLayerDrawLooper::toString(SkString* str) const { } str->append(") "); - static const char* gModeStrings[SkXfermode::kLastMode+1] = { + static const char* gModeStrings[(int)SkBlendMode::kLastMode+1] = { "kClear", "kSrc", "kDst", "kSrcOver", "kDstOver", "kSrcIn", "kDstIn", "kSrcOut", "kDstOut", "kSrcATop", "kDstATop", "kXor", "kPlus", "kMultiply", "kScreen", "kOverlay", "kDarken", "kLighten", "kColorDodge", "kColorBurn", "kHardLight", "kSoftLight", "kDifference", "kExclusion" }; - str->appendf("mode: %s ", gModeStrings[rec->fInfo.fColorMode]); + str->appendf("mode: %s ", gModeStrings[(int)rec->fInfo.fColorMode]); str->append("offset: ("); str->appendScalar(rec->fInfo.fOffset.fX); @@ -354,3 +397,28 @@ sk_sp SkLayerDrawLooper::Builder::detach() { return sk_sp(looper); } + +sk_sp SkBlurDrawLooper::Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy) +{ + sk_sp blur = nullptr; + if (sigma > 0.0f) { + blur = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, sigma, SkBlurMaskFilter::kNone_BlurFlag); + } + + SkLayerDrawLooper::Builder builder; + + // First layer + SkLayerDrawLooper::LayerInfo defaultLayer; + builder.addLayer(defaultLayer); + + // Blur layer + SkLayerDrawLooper::LayerInfo blurInfo; + blurInfo.fColorMode = SkBlendMode::kSrc; + blurInfo.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit; + blurInfo.fOffset = SkVector::Make(dx, dy); + SkPaint* paint = builder.addLayer(blurInfo); + paint->setMaskFilter(std::move(blur)); + paint->setColor(color); + + return builder.detach(); +} diff --git a/gfx/skia/skia/src/effects/SkLayerRasterizer.cpp b/gfx/skia/skia/src/effects/SkLayerRasterizer.cpp index 71d7fb63c5c5..b3e84593bd6e 100644 --- a/gfx/skia/skia/src/effects/SkLayerRasterizer.cpp +++ b/gfx/skia/skia/src/effects/SkLayerRasterizer.cpp @@ -17,7 +17,6 @@ #include "SkPathEffect.h" #include "../core/SkRasterClip.h" #include "../core/SkStrokeRec.h" -#include "SkXfermode.h" #include struct SkLayerRasterizer_Rec { diff --git a/gfx/skia/skia/src/effects/SkLightingImageFilter.cpp b/gfx/skia/skia/src/effects/SkLightingImageFilter.cpp index 057ef24e95d8..58c45ff0aef3 100644 --- a/gfx/skia/skia/src/effects/SkLightingImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkLightingImageFilter.cpp @@ -16,19 +16,20 @@ #if SK_SUPPORT_GPU #include "GrContext.h" -#include "GrDrawContext.h" #include "GrFixedClip.h" #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" #include "GrPaint.h" +#include "GrRenderTargetContext.h" +#include "GrTextureProxy.h" + #include "SkGr.h" -#include "SkGrPriv.h" #include "effects/GrSingleTextureEffect.h" #include "effects/GrTextureDomain.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" +#include "../private/GrGLSL.h" class GrGLDiffuseLightingEffect; class GrGLSpecularLightingEffect; @@ -82,7 +83,7 @@ public: : fKD(kd) {} SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const { - SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight)); + SkScalar colorScale = fKD * normal.dot(surfaceTolight); colorScale = SkScalarClampMax(colorScale, SK_Scalar1); SkPoint3 color = lightColor.makeScale(colorScale); return SkPackARGB32(255, @@ -107,8 +108,7 @@ public: SkPoint3 halfDir(surfaceTolight); halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1) fast_normalize(&halfDir); - SkScalar colorScale = SkScalarMul(fKS, - SkScalarPow(normal.dot(halfDir), fShininess)); + SkScalar colorScale = fKS * SkScalarPow(normal.dot(halfDir), fShininess); colorScale = SkScalarClampMax(colorScale, SK_Scalar1); SkPoint3 color = lightColor.makeScale(colorScale); return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255), @@ -122,13 +122,11 @@ private: }; inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) { - return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale); + return (-a + b - 2 * c + 2 * d -e + f) * scale; } inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) { - SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale), - SkScalarMul(-y, surfaceScale), - SK_Scalar1); + SkPoint3 vector = SkPoint3::Make(-x * surfaceScale, -y * surfaceScale, 1); fast_normalize(&vector); return vector; } @@ -362,15 +360,16 @@ protected: const SkIRect& bounds, const SkMatrix& matrix, const OutputProperties& outputProperties) const; - virtual sk_sp makeFragmentProcessor(GrTexture*, + virtual sk_sp makeFragmentProcessor(GrResourceProvider*, + sk_sp, const SkMatrix&, const SkIRect* srcBounds, BoundaryMode boundaryMode) const = 0; #endif private: #if SK_SUPPORT_GPU - void drawRect(GrDrawContext* drawContext, - GrTexture* src, + void drawRect(GrRenderTargetContext*, + sk_sp srcProxy, const SkMatrix& matrix, const GrClip& clip, const SkRect& dstRect, @@ -382,22 +381,26 @@ private: }; #if SK_SUPPORT_GPU -void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext, - GrTexture* src, +void SkLightingImageFilterInternal::drawRect(GrRenderTargetContext* renderTargetContext, + sk_sp srcProxy, const SkMatrix& matrix, const GrClip& clip, const SkRect& dstRect, BoundaryMode boundaryMode, const SkIRect* srcBounds, const SkIRect& bounds) const { + GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider(); + SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y())); GrPaint paint; - paint.setGammaCorrect(drawContext->isGammaCorrect()); - sk_sp fp(this->makeFragmentProcessor(src, matrix, srcBounds, + paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); + sk_sp fp(this->makeFragmentProcessor(resourceProvider, std::move(srcProxy), + matrix, srcBounds, boundaryMode)); paint.addColorFragmentProcessor(std::move(fp)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); + renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect, + srcRect); } sk_sp SkLightingImageFilterInternal::filterImageGPU( @@ -410,14 +413,14 @@ sk_sp SkLightingImageFilterInternal::filterImageGPU( GrContext* context = source->getContext(); - sk_sp inputTexture(input->asTextureRef(context)); - SkASSERT(inputTexture); + sk_sp inputProxy(input->asTextureProxyRef(context)); + SkASSERT(inputProxy); - sk_sp drawContext( - context->makeDrawContext(SkBackingFit::kApprox,offsetBounds.width(), offsetBounds.height(), - GrRenderableConfigForColorSpace(outputProperties.colorSpace()), - sk_ref_sp(outputProperties.colorSpace()))); - if (!drawContext) { + sk_sp renderTargetContext(context->makeDeferredRenderTargetContext( + SkBackingFit::kApprox, offsetBounds.width(), offsetBounds.height(), + GrRenderableConfigForColorSpace(outputProperties.colorSpace()), + sk_ref_sp(outputProperties.colorSpace()))); + if (!renderTargetContext) { return nullptr; } @@ -439,29 +442,31 @@ sk_sp SkLightingImageFilterInternal::filterImageGPU( SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1); const SkIRect* pSrcBounds = inputBounds.contains(offsetBounds) ? nullptr : &inputBounds; - this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, topLeft, + this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, topLeft, kTopLeft_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, top, kTop_BoundaryMode, - pSrcBounds, offsetBounds); - this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, topRight, + this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, top, + kTop_BoundaryMode, pSrcBounds, offsetBounds); + this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, topRight, kTopRight_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, left, kLeft_BoundaryMode, - pSrcBounds, offsetBounds); - this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, interior, + this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, left, + kLeft_BoundaryMode, pSrcBounds, offsetBounds); + this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, interior, kInterior_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, right, kRight_BoundaryMode, - pSrcBounds, offsetBounds); - this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, bottomLeft, + this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, right, + kRight_BoundaryMode, pSrcBounds, offsetBounds); + this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, bottom, + this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, bottom, kBottom_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, bottomRight, + this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, bottomRight, kBottomRight_BoundaryMode, pSrcBounds, offsetBounds); - return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()), + return SkSpecialImage::MakeDeferredFromGpu( + context, + SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()), kNeedNewImageUniqueID_SpecialImage, - drawContext->asTexture(), - sk_ref_sp(drawContext->getColorSpace())); + renderTargetContext->asTextureProxyRef(), + renderTargetContext->refColorSpace()); } #endif @@ -487,8 +492,8 @@ protected: SkIPoint* offset) const override; #if SK_SUPPORT_GPU - sk_sp makeFragmentProcessor(GrTexture*, const SkMatrix&, - const SkIRect* bounds, + sk_sp makeFragmentProcessor(GrResourceProvider*, sk_sp, + const SkMatrix&, const SkIRect* bounds, BoundaryMode) const override; #endif @@ -523,8 +528,8 @@ protected: SkIPoint* offset) const override; #if SK_SUPPORT_GPU - sk_sp makeFragmentProcessor(GrTexture*, const SkMatrix&, - const SkIRect* bounds, + sk_sp makeFragmentProcessor(GrResourceProvider*, sk_sp, + const SkMatrix&, const SkIRect* bounds, BoundaryMode) const override; #endif @@ -539,7 +544,8 @@ private: class GrLightingEffect : public GrSingleTextureEffect { public: - GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale, + GrLightingEffect(GrResourceProvider*, sk_sp, + const SkImageFilterLight* light, SkScalar surfaceScale, const SkMatrix& matrix, BoundaryMode boundaryMode, const SkIRect* srcBounds); ~GrLightingEffect() override; @@ -552,10 +558,6 @@ public: protected: bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - // lighting shaders are complicated. We just throw up our hands. - inout->mulByUnknownFourComponents(); - } private: const SkImageFilterLight* fLight; @@ -569,7 +571,8 @@ private: class GrDiffuseLightingEffect : public GrLightingEffect { public: - static sk_sp Make(GrTexture* texture, + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, const SkImageFilterLight* light, SkScalar surfaceScale, const SkMatrix& matrix, @@ -577,8 +580,8 @@ public: BoundaryMode boundaryMode, const SkIRect* srcBounds) { return sk_sp( - new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode, - srcBounds)); + new GrDiffuseLightingEffect(resourceProvider, std::move(proxy), light, + surfaceScale, matrix, kd, boundaryMode, srcBounds)); } const char* name() const override { return "DiffuseLighting"; } @@ -588,11 +591,11 @@ public: private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - GrDiffuseLightingEffect(GrTexture* texture, + GrDiffuseLightingEffect(GrResourceProvider*, sk_sp, const SkImageFilterLight* light, SkScalar surfaceScale, const SkMatrix& matrix, @@ -601,13 +604,15 @@ private: const SkIRect* srcBounds); GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - typedef GrLightingEffect INHERITED; SkScalar fKD; + + typedef GrLightingEffect INHERITED; }; class GrSpecularLightingEffect : public GrLightingEffect { public: - static sk_sp Make(GrTexture* texture, + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, const SkImageFilterLight* light, SkScalar surfaceScale, const SkMatrix& matrix, @@ -616,7 +621,8 @@ public: BoundaryMode boundaryMode, const SkIRect* srcBounds) { return sk_sp( - new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess, + new GrSpecularLightingEffect(resourceProvider, std::move(proxy), + light, surfaceScale, matrix, ks, shininess, boundaryMode, srcBounds)); } @@ -628,11 +634,11 @@ public: SkScalar shininess() const { return fShininess; } private: - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - GrSpecularLightingEffect(GrTexture* texture, + GrSpecularLightingEffect(GrResourceProvider*, sk_sp, const SkImageFilterLight* light, SkScalar surfaceScale, const SkMatrix& matrix, @@ -642,9 +648,10 @@ private: const SkIRect* srcBounds); GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - typedef GrLightingEffect INHERITED; SkScalar fKS; SkScalar fShininess; + + typedef GrLightingEffect INHERITED; }; /////////////////////////////////////////////////////////////////////////////// @@ -695,7 +702,7 @@ private: class GrGLDistantLight : public GrGLLight { public: - virtual ~GrGLDistantLight() {} + ~GrGLDistantLight() override {} void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override; void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override; @@ -708,7 +715,7 @@ private: class GrGLPointLight : public GrGLLight { public: - virtual ~GrGLPointLight() {} + ~GrGLPointLight() override {} void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override; void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override; @@ -721,7 +728,7 @@ private: class GrGLSpotLight : public GrGLLight { public: - virtual ~GrGLSpotLight() {} + ~GrGLSpotLight() override {} void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override; void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override; void emitLightColor(GrGLSLUniformHandler*, @@ -751,8 +758,6 @@ class GrGLLight; class SkImageFilterLight : public SkRefCnt { public: - - enum LightType { kDistant_LightType, kPoint_LightType, @@ -764,8 +769,6 @@ public: virtual bool isEqual(const SkImageFilterLight& other) const { return fColor == other.fColor; } - // Called to know whether the generated GrGLLight will require access to the fragment position. - virtual bool requiresFragmentPosition() const = 0; virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0; // Defined below SkLight's subclasses. @@ -814,7 +817,6 @@ public: return nullptr; #endif } - bool requiresFragmentPosition() const override { return false; } bool isEqual(const SkImageFilterLight& other) const override { if (other.type() != kDistant_LightType) { @@ -857,8 +859,7 @@ public: SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const { SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x), fLocation.fY - SkIntToScalar(y), - fLocation.fZ - SkScalarMul(SkIntToScalar(z), - surfaceScale)); + fLocation.fZ - SkIntToScalar(z) * surfaceScale); fast_normalize(&direction); return direction; } @@ -873,7 +874,6 @@ public: return nullptr; #endif } - bool requiresFragmentPosition() const override { return true; } bool isEqual(const SkImageFilterLight& other) const override { if (other.type() != kPoint_LightType) { return false; @@ -962,8 +962,7 @@ public: SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const { SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x), fLocation.fY - SkIntToScalar(y), - fLocation.fZ - SkScalarMul(SkIntToScalar(z), - surfaceScale)); + fLocation.fZ - SkIntToScalar(z) * surfaceScale); fast_normalize(&direction); return direction; } @@ -973,8 +972,7 @@ public: if (cosAngle >= fCosOuterConeAngle) { scale = SkScalarPow(cosAngle, fSpecularExponent); if (cosAngle < fCosInnerConeAngle) { - scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle); - scale *= fConeScale; + scale *= (cosAngle - fCosOuterConeAngle) * fConeScale; } } return this->color().makeScale(scale); @@ -987,7 +985,6 @@ public: return nullptr; #endif } - bool requiresFragmentPosition() const override { return true; } LightType type() const override { return kSpot_LightType; } const SkPoint3& location() const { return fLocation; } const SkPoint3& target() const { return fTarget; } @@ -1342,12 +1339,14 @@ void SkDiffuseLightingImageFilter::toString(SkString* str) const { #if SK_SUPPORT_GPU sk_sp SkDiffuseLightingImageFilter::makeFragmentProcessor( - GrTexture* texture, + GrResourceProvider* resourceProvider, + sk_sp proxy, const SkMatrix& matrix, const SkIRect* srcBounds, BoundaryMode boundaryMode) const { - SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255)); - return GrDiffuseLightingEffect::Make(texture, this->light(), scale, matrix, this->kd(), + SkScalar scale = this->surfaceScale() * 255; + return GrDiffuseLightingEffect::Make(resourceProvider, std::move(proxy), + this->light(), scale, matrix, this->kd(), boundaryMode, srcBounds); } #endif @@ -1507,12 +1506,14 @@ void SkSpecularLightingImageFilter::toString(SkString* str) const { #if SK_SUPPORT_GPU sk_sp SkSpecularLightingImageFilter::makeFragmentProcessor( - GrTexture* texture, + GrResourceProvider* resourceProvider, + sk_sp proxy, const SkMatrix& matrix, const SkIRect* srcBounds, BoundaryMode boundaryMode) const { - SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255)); - return GrSpecularLightingEffect::Make(texture, this->light(), scale, matrix, this->ks(), + SkScalar scale = this->surfaceScale() * 255; + return GrSpecularLightingEffect::Make(resourceProvider, std::move(proxy), this->light(), + scale, matrix, this->ks(), this->shininess(), boundaryMode, srcBounds); } #endif @@ -1624,20 +1625,20 @@ SkString emitNormalFunc(BoundaryMode mode, } -class GrGLLightingEffect : public GrGLSLFragmentProcessor { +class GrGLLightingEffect : public GrGLSLFragmentProcessor { public: GrGLLightingEffect() : fLight(nullptr) { } - virtual ~GrGLLightingEffect() { delete fLight; } + ~GrGLLightingEffect() override { delete fLight; } void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b); protected: /** * Subclasses of GrGLLightingEffect must call INHERITED::onSetData(); */ - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; virtual void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, @@ -1659,7 +1660,7 @@ public: void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override; protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: typedef GrGLLightingEffect INHERITED; @@ -1674,7 +1675,7 @@ public: void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override; protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: typedef GrGLLightingEffect INHERITED; @@ -1685,36 +1686,31 @@ private: /////////////////////////////////////////////////////////////////////////////// -namespace { - -GrTextureDomain create_domain(GrTexture* texture, const SkIRect* srcBounds, - GrTextureDomain::Mode mode) { +static GrTextureDomain create_domain(GrTextureProxy* proxy, const SkIRect* srcBounds, + GrTextureDomain::Mode mode) { if (srcBounds) { - SkRect texelDomain = GrTextureDomain::MakeTexelDomainForMode(texture, *srcBounds, mode); - return GrTextureDomain(texelDomain, mode); + SkRect texelDomain = GrTextureDomain::MakeTexelDomainForMode(*srcBounds, mode); + return GrTextureDomain(proxy, texelDomain, mode); } else { - return GrTextureDomain(SkRect::MakeEmpty(), GrTextureDomain::kIgnore_Mode); + return GrTextureDomain::IgnoredDomain(); } } -}; - -GrLightingEffect::GrLightingEffect(GrTexture* texture, +GrLightingEffect::GrLightingEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, const SkImageFilterLight* light, SkScalar surfaceScale, const SkMatrix& matrix, BoundaryMode boundaryMode, const SkIRect* srcBounds) - : INHERITED(texture, nullptr, GrCoordTransform::MakeDivByTextureWHMatrix(texture)) - , fLight(light) - , fSurfaceScale(surfaceScale) - , fFilterMatrix(matrix) - , fBoundaryMode(boundaryMode) - , fDomain(create_domain(texture, srcBounds, GrTextureDomain::kDecal_Mode)) { + // Perhaps this could advertise the opaque or coverage-as-alpha optimizations? + : INHERITED(resourceProvider, kNone_OptimizationFlags, proxy, nullptr, SkMatrix::I()) + , fLight(light) + , fSurfaceScale(surfaceScale) + , fFilterMatrix(matrix) + , fBoundaryMode(boundaryMode) + , fDomain(create_domain(proxy.get(), srcBounds, GrTextureDomain::kDecal_Mode)) { fLight->ref(); - if (light->requiresFragmentPosition()) { - this->setWillReadFragmentPosition(); - } } GrLightingEffect::~GrLightingEffect() { @@ -1730,14 +1726,16 @@ bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const { /////////////////////////////////////////////////////////////////////////////// -GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, +GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, const SkImageFilterLight* light, SkScalar surfaceScale, const SkMatrix& matrix, SkScalar kd, BoundaryMode boundaryMode, const SkIRect* srcBounds) - : INHERITED(texture, light, surfaceScale, matrix, boundaryMode, srcBounds), fKD(kd) { + : INHERITED(resourceProvider, std::move(proxy), light, surfaceScale, matrix, + boundaryMode, srcBounds), fKD(kd) { this->initClassID(); } @@ -1746,7 +1744,7 @@ bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const return INHERITED::onIsEqual(sBase) && this->kd() == s.kd(); } -void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLDiffuseLightingEffect::GenKey(*this, caps, b); } @@ -1757,24 +1755,28 @@ GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const { GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect); +#if GR_TEST_UTILS sk_sp GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; - GrTexture* tex = d->fTextures[texIdx]; + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); SkScalar surfaceScale = d->fRandom->nextSScalar1(); SkScalar kd = d->fRandom->nextUScalar1(); - SkAutoTUnref light(create_random_light(d->fRandom)); + sk_sp light(create_random_light(d->fRandom)); SkMatrix matrix; for (int i = 0; i < 9; i++) { matrix[i] = d->fRandom->nextUScalar1(); } - SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, tex->width()), - d->fRandom->nextRangeU(0, tex->height()), - d->fRandom->nextRangeU(0, tex->width()), - d->fRandom->nextRangeU(0, tex->height())); + SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, proxy->width()), + d->fRandom->nextRangeU(0, proxy->height()), + d->fRandom->nextRangeU(0, proxy->width()), + d->fRandom->nextRangeU(0, proxy->height())); BoundaryMode mode = static_cast(d->fRandom->nextU() % kBoundaryModeCount); - return GrDiffuseLightingEffect::Make(tex, light, surfaceScale, matrix, kd, mode, &srcBounds); + return GrDiffuseLightingEffect::Make(d->resourceProvider(), + std::move(proxy), light.get(), surfaceScale, + matrix, kd, mode, &srcBounds); } +#endif /////////////////////////////////////////////////////////////////////////////// @@ -1796,14 +1798,14 @@ void GrGLLightingEffect::emitCode(EmitArgs& args) { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString lightFunc; this->emitLightFunc(uniformHandler, fragBuilder, &lightFunc); - static const GrGLSLShaderVar gSobelArgs[] = { - GrGLSLShaderVar("a", kFloat_GrSLType), - GrGLSLShaderVar("b", kFloat_GrSLType), - GrGLSLShaderVar("c", kFloat_GrSLType), - GrGLSLShaderVar("d", kFloat_GrSLType), - GrGLSLShaderVar("e", kFloat_GrSLType), - GrGLSLShaderVar("f", kFloat_GrSLType), - GrGLSLShaderVar("scale", kFloat_GrSLType), + static const GrShaderVar gSobelArgs[] = { + GrShaderVar("a", kFloat_GrSLType), + GrShaderVar("b", kFloat_GrSLType), + GrShaderVar("c", kFloat_GrSLType), + GrShaderVar("d", kFloat_GrSLType), + GrShaderVar("e", kFloat_GrSLType), + GrShaderVar("f", kFloat_GrSLType), + GrShaderVar("scale", kFloat_GrSLType), }; SkString sobelFuncName; SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); @@ -1814,10 +1816,10 @@ void GrGLLightingEffect::emitCode(EmitArgs& args) { gSobelArgs, "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n", &sobelFuncName); - static const GrGLSLShaderVar gPointToNormalArgs[] = { - GrGLSLShaderVar("x", kFloat_GrSLType), - GrGLSLShaderVar("y", kFloat_GrSLType), - GrGLSLShaderVar("scale", kFloat_GrSLType), + static const GrShaderVar gPointToNormalArgs[] = { + GrShaderVar("x", kFloat_GrSLType), + GrShaderVar("y", kFloat_GrSLType), + GrShaderVar("scale", kFloat_GrSLType), }; SkString pointToNormalName; fragBuilder->emitFunction(kVec3f_GrSLType, @@ -1827,9 +1829,9 @@ void GrGLLightingEffect::emitCode(EmitArgs& args) { "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n", &pointToNormalName); - static const GrGLSLShaderVar gInteriorNormalArgs[] = { - GrGLSLShaderVar("m", kFloat_GrSLType, 9), - GrGLSLShaderVar("surfaceScale", kFloat_GrSLType), + static const GrShaderVar gInteriorNormalArgs[] = { + GrShaderVar("m", kFloat_GrSLType, 9), + GrShaderVar("surfaceScale", kFloat_GrSLType), }; SkString normalBody = emitNormalFunc(le.boundaryMode(), pointToNormalName.c_str(), @@ -1858,7 +1860,7 @@ void GrGLLightingEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("vec4 %s;", temp.c_str()); fDomain.sampleTexture(fragBuilder, args.fUniformHandler, - args.fGLSLCaps, + args.fShaderCaps, le.domain(), temp.c_str(), texCoords, @@ -1882,27 +1884,27 @@ void GrGLLightingEffect::emitCode(EmitArgs& args) { } void GrGLLightingEffect::GenKey(const GrProcessor& proc, - const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) { + const GrShaderCaps& caps, GrProcessorKeyBuilder* b) { const GrLightingEffect& lighting = proc.cast(); b->add32(lighting.boundaryMode() << 2 | lighting.light()->type()); b->add32(GrTextureDomain::GLDomain::DomainKey(lighting.domain())); } void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) { + const GrFragmentProcessor& proc) { const GrLightingEffect& lighting = proc.cast(); if (!fLight) { fLight = lighting.light()->createGLLight(); } - GrTexture* texture = lighting.texture(0); + GrTexture* texture = lighting.textureSampler(0).texture(); float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f; pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height()); pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale()); - SkAutoTUnref transformedLight( - lighting.light()->transform(lighting.filterMatrix())); - fDomain.setData(pdman, lighting.domain(), texture->origin()); - fLight->setData(pdman, transformedLight); + sk_sp transformedLight( + lighting.light()->transform(lighting.filterMatrix())); + fDomain.setData(pdman, lighting.domain(), texture); + fLight->setData(pdman, transformedLight.get()); } /////////////////////////////////////////////////////////////////////////////// @@ -1917,10 +1919,10 @@ void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandl kFloat_GrSLType, kDefault_GrSLPrecision, "KD", &kd); - static const GrGLSLShaderVar gLightArgs[] = { - GrGLSLShaderVar("normal", kVec3f_GrSLType), - GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType), - GrGLSLShaderVar("lightColor", kVec3f_GrSLType) + static const GrShaderVar gLightArgs[] = { + GrShaderVar("normal", kVec3f_GrSLType), + GrShaderVar("surfaceToLight", kVec3f_GrSLType), + GrShaderVar("lightColor", kVec3f_GrSLType) }; SkString lightBody; lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd); @@ -1934,7 +1936,7 @@ void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandl } void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) { + const GrFragmentProcessor& proc) { INHERITED::onSetData(pdman, proc); const GrDiffuseLightingEffect& diffuse = proc.cast(); pdman.set1f(fKDUni, diffuse.kd()); @@ -1942,7 +1944,8 @@ void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman, /////////////////////////////////////////////////////////////////////////////// -GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, +GrSpecularLightingEffect::GrSpecularLightingEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, const SkImageFilterLight* light, SkScalar surfaceScale, const SkMatrix& matrix, @@ -1950,7 +1953,8 @@ GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, SkScalar shininess, BoundaryMode boundaryMode, const SkIRect* srcBounds) - : INHERITED(texture, light, surfaceScale, matrix, boundaryMode, srcBounds) + : INHERITED(resourceProvider, std::move(proxy), light, surfaceScale, + matrix, boundaryMode, srcBounds) , fKS(ks) , fShininess(shininess) { this->initClassID(); @@ -1963,7 +1967,7 @@ bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const this->shininess() == s.shininess(); } -void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLSpecularLightingEffect::GenKey(*this, caps, b); } @@ -1974,27 +1978,29 @@ GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect); +#if GR_TEST_UTILS sk_sp GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; - GrTexture* tex = d->fTextures[texIdx]; + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); SkScalar surfaceScale = d->fRandom->nextSScalar1(); SkScalar ks = d->fRandom->nextUScalar1(); SkScalar shininess = d->fRandom->nextUScalar1(); - SkAutoTUnref light(create_random_light(d->fRandom)); + sk_sp light(create_random_light(d->fRandom)); SkMatrix matrix; for (int i = 0; i < 9; i++) { matrix[i] = d->fRandom->nextUScalar1(); } BoundaryMode mode = static_cast(d->fRandom->nextU() % kBoundaryModeCount); - SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, tex->width()), - d->fRandom->nextRangeU(0, tex->height()), - d->fRandom->nextRangeU(0, tex->width()), - d->fRandom->nextRangeU(0, tex->height())); - return GrSpecularLightingEffect::Make(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx], - light, surfaceScale, matrix, ks, shininess, mode, + SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, proxy->width()), + d->fRandom->nextRangeU(0, proxy->height()), + d->fRandom->nextRangeU(0, proxy->width()), + d->fRandom->nextRangeU(0, proxy->height())); + return GrSpecularLightingEffect::Make(d->resourceProvider(), std::move(proxy), + light.get(), surfaceScale, matrix, ks, shininess, mode, &srcBounds); } +#endif /////////////////////////////////////////////////////////////////////////////// @@ -2012,14 +2018,15 @@ void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHand "Shininess", &shininess); - static const GrGLSLShaderVar gLightArgs[] = { - GrGLSLShaderVar("normal", kVec3f_GrSLType), - GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType), - GrGLSLShaderVar("lightColor", kVec3f_GrSLType) + static const GrShaderVar gLightArgs[] = { + GrShaderVar("normal", kVec3f_GrSLType), + GrShaderVar("surfaceToLight", kVec3f_GrSLType), + GrShaderVar("lightColor", kVec3f_GrSLType) }; SkString lightBody; lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n"); - lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess); + lightBody.appendf("\thighp float colorScale = %s * pow(dot(normal, halfDir), %s);\n", + ks, shininess); lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n"); lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n"); fragBuilder->emitFunction(kVec4f_GrSLType, @@ -2031,7 +2038,7 @@ void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHand } void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& effect) { + const GrFragmentProcessor& effect) { INHERITED::onSetData(pdman, effect); const GrSpecularLightingEffect& spec = effect.cast(); pdman.set1f(fKSUni, spec.ks()); @@ -2094,8 +2101,8 @@ void GrGLPointLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler, fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec3f_GrSLType, kDefault_GrSLPrecision, "LightLocation", &loc); - fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))", - loc, fragBuilder->fragmentPosition(), z); + fragBuilder->codeAppendf("normalize(%s - vec3(sk_FragCoord.xy, %s))", + loc, z); } /////////////////////////////////////////////////////////////////////////////// @@ -2121,8 +2128,8 @@ void GrGLSpotLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler, kVec3f_GrSLType, kDefault_GrSLPrecision, "LightLocation", &location); - fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))", - location, fragBuilder->fragmentPosition(), z); + fragBuilder->codeAppendf("normalize(%s - vec3(sk_FragCoord.xy, %s))", + location, z); } void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler, @@ -2151,8 +2158,8 @@ void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler, fSUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s); - static const GrGLSLShaderVar gLightColorArgs[] = { - GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType) + static const GrShaderVar gLightColorArgs[] = { + GrShaderVar("surfaceToLight", kVec3f_GrSLType) }; SkString lightColorBody; lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s); diff --git a/gfx/skia/skia/src/effects/SkLumaColorFilter.cpp b/gfx/skia/skia/src/effects/SkLumaColorFilter.cpp index ec94eca76d42..2809c8b4922e 100644 --- a/gfx/skia/skia/src/effects/SkLumaColorFilter.cpp +++ b/gfx/skia/skia/src/effects/SkLumaColorFilter.cpp @@ -8,11 +8,11 @@ #include "SkLumaColorFilter.h" #include "SkColorPriv.h" +#include "SkRasterPipeline.h" #include "SkString.h" #if SK_SUPPORT_GPU #include "GrContext.h" -#include "GrInvariantOutput.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #endif @@ -37,6 +37,14 @@ void SkLumaColorFilter::filterSpan(const SkPMColor src[], int count, } } +bool SkLumaColorFilter::onAppendStages(SkRasterPipeline* p, + SkColorSpace* dst, + SkArenaAlloc* scratch, + bool shaderIsOpaque) const { + p->append(SkRasterPipeline::luminance_to_alpha); + return true; +} + sk_sp SkLumaColorFilter::Make() { return sk_sp(new SkLumaColorFilter); } @@ -66,7 +74,7 @@ public: class GLSLProcessor : public GrGLSLFragmentProcessor { public: - static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) {} + static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {} void emitCode(EmitArgs& args) override { if (nullptr == args.fInputColor) { @@ -89,7 +97,7 @@ public: }; private: - LumaColorFilterEffect() { + LumaColorFilterEffect() : INHERITED(kConstantOutputForConstantInput_OptimizationFlag) { this->initClassID(); } @@ -97,21 +105,24 @@ private: return new GLSLProcessor; } - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, + virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLProcessor::GenKey(*this, caps, b); } bool onIsEqual(const GrFragmentProcessor&) const override { return true; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - // The output is always black. The alpha value for the color passed in is arbitrary. - inout->setToOther(kRGB_GrColorComponentFlags, GrColorPackRGBA(0, 0, 0, 0), - GrInvariantOutput::kWill_ReadInput); + GrColor4f constantOutputForConstantInput(GrColor4f input) const override { + float luma = SK_ITU_BT709_LUM_COEFF_R * input.fRGBA[0] + + SK_ITU_BT709_LUM_COEFF_G * input.fRGBA[1] + + SK_ITU_BT709_LUM_COEFF_B * input.fRGBA[2]; + return GrColor4f(0, 0, 0, luma); } + + typedef GrFragmentProcessor INHERITED; }; -sk_sp SkLumaColorFilter::asFragmentProcessor(GrContext*) const { +sk_sp SkLumaColorFilter::asFragmentProcessor(GrContext*, SkColorSpace*) const { return LumaColorFilterEffect::Make(); } #endif diff --git a/gfx/skia/skia/src/effects/SkMagnifierImageFilter.cpp b/gfx/skia/skia/src/effects/SkMagnifierImageFilter.cpp index c546730e8020..9be3438502a9 100644 --- a/gfx/skia/skia/src/effects/SkMagnifierImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkMagnifierImageFilter.cpp @@ -17,27 +17,50 @@ //////////////////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU #include "GrContext.h" -#include "GrDrawContext.h" -#include "GrInvariantOutput.h" +#include "effects/GrProxyMove.h" #include "effects/GrSingleTextureEffect.h" +#include "glsl/GrGLSLColorSpaceXformHelper.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" +#include "../private/GrGLSL.h" +#endif +sk_sp SkMagnifierImageFilter::Make(const SkRect& srcRect, SkScalar inset, + sk_sp input, + const CropRect* cropRect) { + if (!SkScalarIsFinite(inset) || !SkIsValidRect(srcRect)) { + return nullptr; + } + if (inset < 0) { + return nullptr; + } + // Negative numbers in src rect are not supported + if (srcRect.fLeft < 0 || srcRect.fTop < 0) { + return nullptr; + } + return sk_sp(new SkMagnifierImageFilter(srcRect, inset, + std::move(input), + cropRect)); +} + +#if SK_SUPPORT_GPU class GrMagnifierEffect : public GrSingleTextureEffect { - public: - static sk_sp Make(GrTexture* texture, - const SkRect& bounds, - float xOffset, - float yOffset, + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, + sk_sp colorSpaceXform, + const SkIRect& bounds, + const SkRect& srcRect, float xInvZoom, float yInvZoom, float xInvInset, float yInvInset) { - return sk_sp(new GrMagnifierEffect(texture, bounds, - xOffset, yOffset, + return sk_sp(new GrMagnifierEffect(resourceProvider, + std::move(proxy), + std::move(colorSpaceXform), + bounds, srcRect, xInvZoom, yInvZoom, xInvInset, yInvInset)); } @@ -46,10 +69,8 @@ public: const char* name() const override { return "Magnifier"; } - const SkRect& bounds() const { return fBounds; } // Bounds of source image. - // Offset to apply to zoomed pixels, (srcRect position / texture size). - float xOffset() const { return fXOffset; } - float yOffset() const { return fYOffset; } + const SkIRect& bounds() const { return fBounds; } // Bounds of source image. + const SkRect& srcRect() const { return fSrcRect; } // Scale to apply to zoomed pixels (srcRect size / bounds size). float xInvZoom() const { return fXInvZoom; } @@ -60,38 +81,39 @@ public: float yInvInset() const { return fYInvInset; } private: - GrMagnifierEffect(GrTexture* texture, - const SkRect& bounds, - float xOffset, - float yOffset, + GrMagnifierEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, + sk_sp colorSpaceXform, + const SkIRect& bounds, + const SkRect& srcRect, float xInvZoom, float yInvZoom, float xInvInset, float yInvInset) - : INHERITED(texture, nullptr, GrCoordTransform::MakeDivByTextureWHMatrix(texture)) - , fBounds(bounds) - , fXOffset(xOffset) - , fYOffset(yOffset) - , fXInvZoom(xInvZoom) - , fYInvZoom(yInvZoom) - , fXInvInset(xInvInset) - , fYInvInset(yInvInset) { + : INHERITED{resourceProvider, + ModulationFlags(proxy->config()), + GR_PROXY_MOVE(proxy), + std::move(colorSpaceXform), + SkMatrix::I()} // TODO: no GrSamplerParams::kBilerp_FilterMode? + , fBounds(bounds) + , fSrcRect(srcRect) + , fXInvZoom(xInvZoom) + , fYInvZoom(yInvZoom) + , fXInvInset(xInvInset) + , fYInvInset(yInvInset) { this->initClassID(); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - SkRect fBounds; - float fXOffset; - float fYOffset; + SkIRect fBounds; + SkRect fSrcRect; float fXInvZoom; float fYInvZoom; float fXInvInset; @@ -107,14 +129,21 @@ class GrGLMagnifierEffect : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs&) override; + static inline void GenKey(const GrProcessor& effect, const GrShaderCaps&, + GrProcessorKeyBuilder* b) { + const GrMagnifierEffect& zoom = effect.cast(); + b->add32(GrColorSpaceXform::XformKey(zoom.colorSpaceXform())); + } + protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: UniformHandle fOffsetVar; UniformHandle fInvZoomVar; UniformHandle fInvInsetVar; UniformHandle fBoundsVar; + GrGLSLColorSpaceXformHelper fColorSpaceHelper; typedef GrGLSLFragmentProcessor INHERITED; }; @@ -134,6 +163,9 @@ void GrGLMagnifierEffect::emitCode(EmitArgs& args) { kVec4f_GrSLType, kDefault_GrSLPrecision, "Bounds"); + const GrMagnifierEffect& zoom = args.fFp.cast(); + fColorSpaceHelper.emitCode(uniformHandler, zoom.colorSpaceXform()); + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str()); @@ -160,7 +192,8 @@ void GrGLMagnifierEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppend("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n"); fragBuilder->codeAppend("\t\tvec4 output_color = "); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], "mix_coord"); + fragBuilder->appendTextureLookup(args.fTexSamplers[0], "mix_coord", kVec2f_GrSLType, + &fColorSpaceHelper); fragBuilder->codeAppend(";\n"); fragBuilder->codeAppendf("\t\t%s = output_color;", args.fOutputColor); @@ -170,18 +203,48 @@ void GrGLMagnifierEffect::emitCode(EmitArgs& args) { } void GrGLMagnifierEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& effect) { + const GrFragmentProcessor& effect) { const GrMagnifierEffect& zoom = effect.cast(); - pdman.set2f(fOffsetVar, zoom.xOffset(), zoom.yOffset()); + + GrTexture* tex = zoom.textureSampler(0).texture(); + SkASSERT(tex); + + SkScalar invW = 1.0f / tex->width(); + SkScalar invH = 1.0f / tex->height(); + + { + SkScalar y = zoom.srcRect().y() * invH; + if (tex->origin() != kTopLeft_GrSurfaceOrigin) { + y = 1.0f - (zoom.srcRect().height() / zoom.bounds().height()) - y; + } + + pdman.set2f(fOffsetVar, zoom.srcRect().x() * invW, y); + } + pdman.set2f(fInvZoomVar, zoom.xInvZoom(), zoom.yInvZoom()); pdman.set2f(fInvInsetVar, zoom.xInvInset(), zoom.yInvInset()); - pdman.set4f(fBoundsVar, zoom.bounds().x(), zoom.bounds().y(), - zoom.bounds().width(), zoom.bounds().height()); + + { + SkScalar y = zoom.bounds().y() * invH; + if (tex->origin() != kTopLeft_GrSurfaceOrigin) { + y = 1.0f - zoom.bounds().height() * invH; + } + + pdman.set4f(fBoundsVar, + zoom.bounds().x() * invW, + y, + SkIntToScalar(tex->width()) / zoom.bounds().width(), + SkIntToScalar(tex->height()) / zoom.bounds().height()); + } + + if (SkToBool(zoom.colorSpaceXform())) { + fColorSpaceHelper.setData(pdman, zoom.colorSpaceXform()); + } } ///////////////////////////////////////////////////////////////////// -void GrMagnifierEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrMagnifierEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLMagnifierEffect::GenKey(*this, caps, b); } @@ -192,68 +255,51 @@ GrGLSLFragmentProcessor* GrMagnifierEffect::onCreateGLSLInstance() const { GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMagnifierEffect); +#if GR_TEST_UTILS sk_sp GrMagnifierEffect::TestCreate(GrProcessorTestData* d) { - GrTexture* texture = d->fTextures[0]; + sk_sp proxy = d->textureProxy(0); const int kMaxWidth = 200; const int kMaxHeight = 200; - const int kMaxInset = 20; + const SkScalar kMaxInset = 20.0f; uint32_t width = d->fRandom->nextULessThan(kMaxWidth); uint32_t height = d->fRandom->nextULessThan(kMaxHeight); - uint32_t x = d->fRandom->nextULessThan(kMaxWidth - width); - uint32_t y = d->fRandom->nextULessThan(kMaxHeight - height); - uint32_t inset = d->fRandom->nextULessThan(kMaxInset); + SkScalar inset = d->fRandom->nextRangeScalar(1.0f, kMaxInset); + sk_sp colorSpaceXform = GrTest::TestColorXform(d->fRandom); + + SkIRect bounds = SkIRect::MakeWH(SkIntToScalar(kMaxWidth), SkIntToScalar(kMaxHeight)); + SkRect srcRect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); sk_sp effect(GrMagnifierEffect::Make( - texture, - SkRect::MakeWH(SkIntToScalar(kMaxWidth), SkIntToScalar(kMaxHeight)), - (float) width / texture->width(), - (float) height / texture->height(), - texture->width() / (float) x, - texture->height() / (float) y, - (float) inset / texture->width(), - (float) inset / texture->height())); + d->resourceProvider(), + std::move(proxy), + std::move(colorSpaceXform), + bounds, + srcRect, + srcRect.width() / bounds.width(), + srcRect.height() / bounds.height(), + bounds.width() / inset, + bounds.height() / inset)); SkASSERT(effect); return effect; } +#endif /////////////////////////////////////////////////////////////////////////////// bool GrMagnifierEffect::onIsEqual(const GrFragmentProcessor& sBase) const { const GrMagnifierEffect& s = sBase.cast(); return (this->fBounds == s.fBounds && - this->fXOffset == s.fXOffset && - this->fYOffset == s.fYOffset && + this->fSrcRect == s.fSrcRect && this->fXInvZoom == s.fXInvZoom && this->fYInvZoom == s.fYInvZoom && this->fXInvInset == s.fXInvInset && this->fYInvInset == s.fYInvInset); } -void GrMagnifierEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - this->updateInvariantOutputForModulation(inout); -} - #endif //////////////////////////////////////////////////////////////////////////////// -sk_sp SkMagnifierImageFilter::Make(const SkRect& srcRect, SkScalar inset, - sk_sp input, - const CropRect* cropRect) { - - if (!SkScalarIsFinite(inset) || !SkIsValidRect(srcRect)) { - return nullptr; - } - // Negative numbers in src rect are not supported - if (srcRect.fLeft < 0 || srcRect.fTop < 0) { - return nullptr; - } - return sk_sp(new SkMagnifierImageFilter(srcRect, inset, - std::move(input), - cropRect)); -} - - SkMagnifierImageFilter::SkMagnifierImageFilter(const SkRect& srcRect, SkScalar inset, sk_sp input, @@ -261,7 +307,7 @@ SkMagnifierImageFilter::SkMagnifierImageFilter(const SkRect& srcRect, : INHERITED(&input, 1, cropRect) , fSrcRect(srcRect) , fInset(inset) { - SkASSERT(srcRect.x() >= 0 && srcRect.y() >= 0 && inset >= 0); + SkASSERT(srcRect.left() >= 0 && srcRect.top() >= 0 && inset >= 0); } sk_sp SkMagnifierImageFilter::CreateProc(SkReadBuffer& buffer) { @@ -304,31 +350,22 @@ sk_sp SkMagnifierImageFilter::onFilterImage(SkSpecialImage* sour if (source->isTextureBacked()) { GrContext* context = source->getContext(); - sk_sp inputTexture(input->asTextureRef(context)); - SkASSERT(inputTexture); + sk_sp inputProxy(input->asTextureProxyRef(context)); + SkASSERT(inputProxy); offset->fX = bounds.left(); offset->fY = bounds.top(); bounds.offset(-inputOffset); - SkScalar yOffset = inputTexture->origin() == kTopLeft_GrSurfaceOrigin - ? fSrcRect.y() - : inputTexture->height() - - fSrcRect.height() * inputTexture->height() / bounds.height() - fSrcRect.y(); - int boundsY = inputTexture->origin() == kTopLeft_GrSurfaceOrigin - ? bounds.y() - : inputTexture->height() - bounds.height(); - SkRect effectBounds = SkRect::MakeXYWH( - SkIntToScalar(bounds.x()) / inputTexture->width(), - SkIntToScalar(boundsY) / inputTexture->height(), - SkIntToScalar(inputTexture->width()) / bounds.width(), - SkIntToScalar(inputTexture->height()) / bounds.height()); - // SRGBTODO: Handle sRGB here + SkColorSpace* dstColorSpace = ctx.outputProperties().colorSpace(); + sk_sp colorSpaceXform = GrColorSpaceXform::Make(input->getColorSpace(), + dstColorSpace); sk_sp fp(GrMagnifierEffect::Make( - inputTexture.get(), - effectBounds, - fSrcRect.x() / inputTexture->width(), - yOffset / inputTexture->height(), + context->resourceProvider(), + std::move(inputProxy), + std::move(colorSpaceXform), + bounds, + fSrcRect, invXZoom, invYZoom, bounds.width() * invInset, @@ -393,10 +430,8 @@ sk_sp SkMagnifierImageFilter::onFilterImage(SkSpecialImage* sour weight = SkMinScalar(sqDist, SK_Scalar1); } - SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * invXZoom)) + - (SK_Scalar1 - weight) * x; - SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * invYZoom)) + - (SK_Scalar1 - weight) * y; + SkScalar x_interp = weight * (fSrcRect.x() + x * invXZoom) + (1 - weight) * x; + SkScalar y_interp = weight * (fSrcRect.y() + y * invYZoom) + (1 - weight) * y; int x_val = SkTPin(bounds.x() + SkScalarFloorToInt(x_interp), 0, inputBM.width() - 1); int y_val = SkTPin(bounds.y() + SkScalarFloorToInt(y_interp), 0, inputBM.height() - 1); @@ -412,6 +447,17 @@ sk_sp SkMagnifierImageFilter::onFilterImage(SkSpecialImage* sour dst); } +sk_sp SkMagnifierImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + SkASSERT(1 == this->countInputs()); + if (!this->getInput(0)) { + return sk_ref_sp(const_cast(this)); + } + + sk_sp input = this->getInput(0)->makeColorSpace(xformer); + return SkMagnifierImageFilter::Make(fSrcRect, fInset, std::move(input), + this->getCropRectIfSet()); +} + #ifndef SK_IGNORE_TO_STRING void SkMagnifierImageFilter::toString(SkString* str) const { str->appendf("SkMagnifierImageFilter: ("); diff --git a/gfx/skia/skia/src/effects/SkMatrixConvolutionImageFilter.cpp b/gfx/skia/skia/src/effects/SkMatrixConvolutionImageFilter.cpp index 5477d7ab7e4c..092cb661bd36 100644 --- a/gfx/skia/skia/src/effects/SkMatrixConvolutionImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkMatrixConvolutionImageFilter.cpp @@ -10,14 +10,13 @@ #include "SkColorPriv.h" #include "SkReadBuffer.h" #include "SkSpecialImage.h" -#include "SkSpecialSurface.h" #include "SkWriteBuffer.h" #include "SkRect.h" #include "SkUnPreMultiply.h" #if SK_SUPPORT_GPU #include "GrContext.h" -#include "GrDrawContext.h" +#include "GrTextureProxy.h" #include "effects/GrMatrixConvolutionEffect.h" #endif @@ -183,19 +182,19 @@ void SkMatrixConvolutionImageFilter::filterPixels(const SkBitmap& src, bounds); SkScalar k = fKernel[cy * fKernelSize.fWidth + cx]; if (convolveAlpha) { - sumA += SkScalarMul(SkIntToScalar(SkGetPackedA32(s)), k); + sumA += SkGetPackedA32(s) * k; } - sumR += SkScalarMul(SkIntToScalar(SkGetPackedR32(s)), k); - sumG += SkScalarMul(SkIntToScalar(SkGetPackedG32(s)), k); - sumB += SkScalarMul(SkIntToScalar(SkGetPackedB32(s)), k); + sumR += SkGetPackedR32(s) * k; + sumG += SkGetPackedG32(s) * k; + sumB += SkGetPackedB32(s) * k; } } int a = convolveAlpha - ? SkClampMax(SkScalarFloorToInt(SkScalarMul(sumA, fGain) + fBias), 255) + ? SkClampMax(SkScalarFloorToInt(sumA * fGain + fBias), 255) : 255; - int r = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumR, fGain) + fBias), a); - int g = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumG, fGain) + fBias), a); - int b = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumB, fGain) + fBias), a); + int r = SkClampMax(SkScalarFloorToInt(sumR * fGain + fBias), a); + int g = SkClampMax(SkScalarFloorToInt(sumG * fGain + fBias), a); + int b = SkClampMax(SkScalarFloorToInt(sumB * fGain + fBias), a); if (!convolveAlpha) { a = SkGetPackedA32(PixelFetcher::fetch(src, x, y, bounds)); *dptr++ = SkPreMultiplyARGB(a, r, g, b); @@ -283,7 +282,6 @@ static GrTextureDomain::Mode convert_tilemodes(SkMatrixConvolutionImageFilter::T } return GrTextureDomain::kIgnore_Mode; } - #endif sk_sp SkMatrixConvolutionImageFilter::onFilterImage(SkSpecialImage* source, @@ -307,15 +305,21 @@ sk_sp SkMatrixConvolutionImageFilter::onFilterImage(SkSpecialIma fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE) { GrContext* context = source->getContext(); - sk_sp inputTexture(input->asTextureRef(context)); - SkASSERT(inputTexture); + // Ensure the input is in the destination color space. Typically applyCropRect will have + // called pad_image to account for our dilation of bounds, so the result will already be + // moved to the destination color space. If a filter DAG avoids that, then we use this + // fall-back, which saves us from having to do the xform during the filter itself. + input = ImageToColorSpace(input.get(), ctx.outputProperties()); + + sk_sp inputProxy(input->asTextureProxyRef(context)); + SkASSERT(inputProxy); offset->fX = bounds.left(); offset->fY = bounds.top(); bounds.offset(-inputOffset); - // SRGBTODO: handle sRGB here - sk_sp fp(GrMatrixConvolutionEffect::Make(inputTexture.get(), + sk_sp fp(GrMatrixConvolutionEffect::Make(context->resourceProvider(), + std::move(inputProxy), bounds, fKernelSize, fKernel, @@ -384,6 +388,19 @@ sk_sp SkMatrixConvolutionImageFilter::onFilterImage(SkSpecialIma dst); } +sk_sp SkMatrixConvolutionImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) +const { + SkASSERT(1 == this->countInputs()); + if (!this->getInput(0)) { + return sk_ref_sp(const_cast(this)); + } + + sk_sp input = this->getInput(0)->makeColorSpace(xformer); + return SkMatrixConvolutionImageFilter::Make(fKernelSize, fKernel, fGain, fBias, fKernelOffset, + fTileMode, fConvolveAlpha, std::move(input), + this->getCropRectIfSet()); +} + SkIRect SkMatrixConvolutionImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection direction) const { SkIRect dst = src; diff --git a/gfx/skia/skia/src/effects/SkMergeImageFilter.cpp b/gfx/skia/skia/src/effects/SkMergeImageFilter.cpp index 9830669f049b..546d66a79710 100644 --- a/gfx/skia/skia/src/effects/SkMergeImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkMergeImageFilter.cpp @@ -16,17 +16,16 @@ sk_sp SkMergeImageFilter::Make(sk_sp first, sk_sp second, - SkXfermode::Mode mode, + SkBlendMode mode, const CropRect* cropRect) { sk_sp inputs[2] = { first, second }; - SkXfermode::Mode modes[2] = { mode, mode }; + SkBlendMode modes[2] = { mode, mode }; return sk_sp(new SkMergeImageFilter(inputs, 2, modes, cropRect)); } -sk_sp SkMergeImageFilter::Make(sk_sp filters[], - int count, - const SkXfermode::Mode modes[], - const CropRect* cropRect) { +sk_sp SkMergeImageFilter::MakeN(sk_sp filters[], int count, + const SkBlendMode modes[], + const CropRect* cropRect) { return sk_sp(new SkMergeImageFilter(filters, count, modes, cropRect)); } @@ -46,12 +45,12 @@ void SkMergeImageFilter::initAllocModes() { } } -void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) { +void SkMergeImageFilter::initModes(const SkBlendMode modes[]) { if (modes) { this->initAllocModes(); int inputCount = this->countInputs(); for (int i = 0; i < inputCount; ++i) { - fModes[i] = SkToU8(modes[i]); + fModes[i] = SkToU8((unsigned)modes[i]); } } else { fModes = nullptr; @@ -59,7 +58,7 @@ void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) { } SkMergeImageFilter::SkMergeImageFilter(sk_sp filters[], int count, - const SkXfermode::Mode modes[], + const SkBlendMode modes[], const CropRect* cropRect) : INHERITED(filters, count, cropRect) { SkASSERT(count >= 0); @@ -83,8 +82,8 @@ sk_sp SkMergeImageFilter::onFilterImage(SkSpecialImage* source, SkIRect bounds; bounds.setEmpty(); - SkAutoTDeleteArray> inputs(new sk_sp[inputCount]); - SkAutoTDeleteArray offsets(new SkIPoint[inputCount]); + std::unique_ptr[]> inputs(new sk_sp[inputCount]); + std::unique_ptr offsets(new SkIPoint[inputCount]); // Filter all of the inputs. for (int i = 0; i < inputCount; ++i) { @@ -144,6 +143,18 @@ sk_sp SkMergeImageFilter::onFilterImage(SkSpecialImage* source, return surf->makeImageSnapshot(); } +sk_sp SkMergeImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + SkSTArray<5, sk_sp> inputs(this->countInputs()); + SkSTArray<5, SkBlendMode> modes(this->countInputs()); + for (int i = 0; i < this->countInputs(); i++) { + inputs.push_back(this->getInput(i) ? this->getInput(i)->makeColorSpace(xformer) : nullptr); + modes.push_back((SkBlendMode) fModes[i]); + } + + return SkMergeImageFilter::MakeN(inputs.begin(), this->countInputs(), modes.begin(), + this->getCropRectIfSet()); +} + sk_sp SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) { Common common; if (!common.unflatten(buffer, -1)) { @@ -153,21 +164,21 @@ sk_sp SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) { const int count = common.inputCount(); bool hasModes = buffer.readBool(); if (hasModes) { - SkAutoSTArray<4, SkXfermode::Mode> modes(count); + SkAutoSTArray<4, SkBlendMode> modes(count); SkAutoSTArray<4, uint8_t> modes8(count); if (!buffer.readByteArray(modes8.get(), count)) { return nullptr; } for (int i = 0; i < count; ++i) { - modes[i] = (SkXfermode::Mode)modes8[i]; + modes[i] = (SkBlendMode)modes8[i]; buffer.validate(SkIsValidMode(modes[i])); } if (!buffer.isValid()) { return nullptr; } - return Make(common.inputs(), count, modes.get(), &common.cropRect()); + return MakeN(common.inputs(), count, modes.get(), &common.cropRect()); } - return Make(common.inputs(), count, nullptr, &common.cropRect()); + return MakeN(common.inputs(), count, nullptr, &common.cropRect()); } void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const { diff --git a/gfx/skia/skia/src/effects/SkMorphologyImageFilter.cpp b/gfx/skia/skia/src/effects/SkMorphologyImageFilter.cpp index 2bd792860b2a..d7454a46884a 100644 --- a/gfx/skia/skia/src/effects/SkMorphologyImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkMorphologyImageFilter.cpp @@ -17,17 +17,19 @@ #if SK_SUPPORT_GPU #include "GrContext.h" -#include "GrDrawContext.h" #include "GrFixedClip.h" -#include "GrInvariantOutput.h" +#include "GrRenderTargetContext.h" #include "GrTexture.h" +#include "GrTextureProxy.h" + #include "SkGr.h" -#include "SkGrPriv.h" #include "effects/Gr1DKernelEffect.h" +#include "effects/GrProxyMove.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" +#include "../private/GrGLSL.h" #endif sk_sp SkDilateImageFilter::Make(int radiusX, int radiusY, @@ -137,25 +139,27 @@ void SkDilateImageFilter::toString(SkString* str) const { * color. */ class GrMorphologyEffect : public Gr1DKernelEffect { - public: - enum MorphologyType { kErode_MorphologyType, kDilate_MorphologyType, }; - static sk_sp Make(GrTexture* tex, Direction dir, int radius, - MorphologyType type) { - return sk_sp(new GrMorphologyEffect(tex, dir, radius, type)); + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, + Direction dir, int radius, MorphologyType type) { + return sk_sp(new GrMorphologyEffect(resourceProvider, std::move(proxy), + dir, radius, type)); } - static sk_sp Make(GrTexture* tex, Direction dir, int radius, - MorphologyType type, float bounds[2]) { - return sk_sp(new GrMorphologyEffect(tex, dir, radius, type, bounds)); + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, Direction dir, int radius, + MorphologyType type, const float bounds[2]) { + return sk_sp(new GrMorphologyEffect(resourceProvider, std::move(proxy), + dir, radius, type, bounds)); } - virtual ~GrMorphologyEffect(); + ~GrMorphologyEffect() override; MorphologyType type() const { return fType; } bool useRange() const { return fUseRange; } @@ -172,15 +176,14 @@ protected: private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType); - GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType, - float bounds[2]); + GrMorphologyEffect(GrResourceProvider*, sk_sp, + Direction, int radius, MorphologyType); + GrMorphologyEffect(GrResourceProvider*, sk_sp, + Direction, int radius, MorphologyType, const float bounds[2]); GR_DECLARE_FRAGMENT_PROCESSOR_TEST; @@ -193,10 +196,10 @@ class GrGLMorphologyEffect : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fPixelSizeUni; @@ -279,7 +282,7 @@ void GrGLMorphologyEffect::emitCode(EmitArgs& args) { } void GrGLMorphologyEffect::GenKey(const GrProcessor& proc, - const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrMorphologyEffect& m = proc.cast(); uint32_t key = static_cast(m.radius()); key |= (m.type() << 8); @@ -291,9 +294,9 @@ void GrGLMorphologyEffect::GenKey(const GrProcessor& proc, } void GrGLMorphologyEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& proc) { + const GrFragmentProcessor& proc) { const GrMorphologyEffect& m = proc.cast(); - GrTexture& texture = *m.texture(0); + GrTexture& texture = *m.textureSampler(0).texture(); float pixelSize = 0.0f; switch (m.direction()) { @@ -310,34 +313,43 @@ void GrGLMorphologyEffect::onSetData(const GrGLSLProgramDataManager& pdman, if (m.useRange()) { const float* range = m.range(); - if (m.direction() && texture.origin() == kBottomLeft_GrSurfaceOrigin) { - pdman.set2f(fRangeUni, 1.0f - range[1], 1.0f - range[0]); + if (Gr1DKernelEffect::kY_Direction == m.direction() && + texture.origin() == kBottomLeft_GrSurfaceOrigin) { + pdman.set2f(fRangeUni, 1.0f - (range[1]*pixelSize), 1.0f - (range[0]*pixelSize)); } else { - pdman.set2f(fRangeUni, range[0], range[1]); + pdman.set2f(fRangeUni, range[0] * pixelSize, range[1] * pixelSize); } } } /////////////////////////////////////////////////////////////////////////////// -GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture, +GrMorphologyEffect::GrMorphologyEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, Direction direction, int radius, MorphologyType type) - : INHERITED(texture, direction, radius) - , fType(type) - , fUseRange(false) { + : INHERITED{resourceProvider, + ModulationFlags(proxy->config()), + GR_PROXY_MOVE(proxy), + direction, radius} + , fType(type) + , fUseRange(false) { this->initClassID(); } -GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture, +GrMorphologyEffect::GrMorphologyEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, Direction direction, int radius, MorphologyType type, - float range[2]) - : INHERITED(texture, direction, radius) - , fType(type) - , fUseRange(true) { + const float range[2]) + : INHERITED{resourceProvider, + ModulationFlags(proxy->config()), + GR_PROXY_MOVE(proxy), + direction, radius} + , fType(type) + , fUseRange(true) { this->initClassID(); fRange[0] = range[0]; fRange[1] = range[1]; @@ -346,7 +358,7 @@ GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture, GrMorphologyEffect::~GrMorphologyEffect() { } -void GrMorphologyEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrMorphologyEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLMorphologyEffect::GenKey(*this, caps, b); } @@ -362,70 +374,73 @@ bool GrMorphologyEffect::onIsEqual(const GrFragmentProcessor& sBase) const { this->type() == s.type()); } -void GrMorphologyEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - // This is valid because the color components of the result of the kernel all come - // exactly from existing values in the source texture. - this->updateInvariantOutputForModulation(inout); -} - /////////////////////////////////////////////////////////////////////////////// GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMorphologyEffect); +#if GR_TEST_UTILS sk_sp GrMorphologyEffect::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); + Direction dir = d->fRandom->nextBool() ? kX_Direction : kY_Direction; static const int kMaxRadius = 10; int radius = d->fRandom->nextRangeU(1, kMaxRadius); - MorphologyType type = d->fRandom->nextBool() ? GrMorphologyEffect::kErode_MorphologyType : - GrMorphologyEffect::kDilate_MorphologyType; + MorphologyType type = d->fRandom->nextBool() ? GrMorphologyEffect::kErode_MorphologyType + : GrMorphologyEffect::kDilate_MorphologyType; - return GrMorphologyEffect::Make(d->fTextures[texIdx], dir, radius, type); + return GrMorphologyEffect::Make(d->resourceProvider(), + std::move(proxy), dir, radius, type); } +#endif -static void apply_morphology_rect(GrDrawContext* drawContext, +static void apply_morphology_rect(GrRenderTargetContext* renderTargetContext, const GrClip& clip, - GrTexture* texture, + sk_sp proxy, const SkIRect& srcRect, const SkIRect& dstRect, int radius, GrMorphologyEffect::MorphologyType morphType, - float bounds[2], + const float bounds[2], Gr1DKernelEffect::Direction direction) { GrPaint paint; - paint.setGammaCorrect(drawContext->isGammaCorrect()); - paint.addColorFragmentProcessor(GrMorphologyEffect::Make(texture, - direction, - radius, - morphType, + paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); + + GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider(); + + paint.addColorFragmentProcessor(GrMorphologyEffect::Make(resourceProvider, std::move(proxy), + direction, radius, morphType, bounds)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - drawContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect), - SkRect::Make(srcRect)); + renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstRect), SkRect::Make(srcRect)); } -static void apply_morphology_rect_no_bounds(GrDrawContext* drawContext, +static void apply_morphology_rect_no_bounds(GrRenderTargetContext* renderTargetContext, const GrClip& clip, - GrTexture* texture, + sk_sp proxy, const SkIRect& srcRect, const SkIRect& dstRect, int radius, GrMorphologyEffect::MorphologyType morphType, Gr1DKernelEffect::Direction direction) { GrPaint paint; - paint.setGammaCorrect(drawContext->isGammaCorrect()); - paint.addColorFragmentProcessor(GrMorphologyEffect::Make(texture, direction, radius, - morphType)); + paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); + + GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider(); + + paint.addColorFragmentProcessor(GrMorphologyEffect::Make(resourceProvider, std::move(proxy), + direction, radius, morphType)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - drawContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect), - SkRect::Make(srcRect)); + renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstRect), SkRect::Make(srcRect)); } -static void apply_morphology_pass(GrDrawContext* drawContext, +static void apply_morphology_pass(GrRenderTargetContext* renderTargetContext, const GrClip& clip, - GrTexture* texture, + sk_sp textureProxy, const SkIRect& srcRect, const SkIRect& dstRect, int radius, @@ -436,8 +451,8 @@ static void apply_morphology_pass(GrDrawContext* drawContext, SkIRect middleSrcRect = srcRect, middleDstRect = dstRect; SkIRect upperSrcRect = srcRect, upperDstRect = dstRect; if (direction == Gr1DKernelEffect::kX_Direction) { - bounds[0] = (SkIntToScalar(srcRect.left()) + 0.5f) / texture->width(); - bounds[1] = (SkIntToScalar(srcRect.right()) - 0.5f) / texture->width(); + bounds[0] = SkIntToScalar(srcRect.left()) + 0.5f; + bounds[1] = SkIntToScalar(srcRect.right()) - 0.5f; lowerSrcRect.fRight = srcRect.left() + radius; lowerDstRect.fRight = dstRect.left() + radius; upperSrcRect.fLeft = srcRect.right() - radius; @@ -445,8 +460,8 @@ static void apply_morphology_pass(GrDrawContext* drawContext, middleSrcRect.inset(radius, 0); middleDstRect.inset(radius, 0); } else { - bounds[0] = (SkIntToScalar(srcRect.top()) + 0.5f) / texture->height(); - bounds[1] = (SkIntToScalar(srcRect.bottom()) - 0.5f) / texture->height(); + bounds[0] = SkIntToScalar(srcRect.top()) + 0.5f; + bounds[1] = SkIntToScalar(srcRect.bottom()) - 0.5f; lowerSrcRect.fBottom = srcRect.top() + radius; lowerDstRect.fBottom = dstRect.top() + radius; upperSrcRect.fTop = srcRect.bottom() - radius; @@ -456,16 +471,16 @@ static void apply_morphology_pass(GrDrawContext* drawContext, } if (middleSrcRect.fLeft - middleSrcRect.fRight >= 0) { // radius covers srcRect; use bounds over entire draw - apply_morphology_rect(drawContext, clip, texture, srcRect, dstRect, radius, - morphType, bounds, direction); + apply_morphology_rect(renderTargetContext, clip, std::move(textureProxy), + srcRect, dstRect, radius, morphType, bounds, direction); } else { // Draw upper and lower margins with bounds; middle without. - apply_morphology_rect(drawContext, clip, texture, lowerSrcRect, lowerDstRect, radius, - morphType, bounds, direction); - apply_morphology_rect(drawContext, clip, texture, upperSrcRect, upperDstRect, radius, - morphType, bounds, direction); - apply_morphology_rect_no_bounds(drawContext, clip, texture, middleSrcRect, middleDstRect, - radius, morphType, direction); + apply_morphology_rect(renderTargetContext, clip, textureProxy, + lowerSrcRect, lowerDstRect, radius, morphType, bounds, direction); + apply_morphology_rect(renderTargetContext, clip, textureProxy, + upperSrcRect, upperDstRect, radius, morphType, bounds, direction); + apply_morphology_rect_no_bounds(renderTargetContext, clip, std::move(textureProxy), + middleSrcRect, middleDstRect, radius, morphType, direction); } } @@ -476,7 +491,7 @@ static sk_sp apply_morphology( GrMorphologyEffect::MorphologyType morphType, SkISize radius, const SkImageFilter::OutputProperties& outputProperties) { - sk_sp srcTexture(input->asTextureRef(context)); + sk_sp srcTexture(input->asTextureProxyRef(context)); SkASSERT(srcTexture); sk_sp colorSpace = sk_ref_sp(outputProperties.colorSpace()); GrPixelConfig config = GrRenderableConfigForColorSpace(colorSpace.get()); @@ -490,14 +505,13 @@ static sk_sp apply_morphology( SkASSERT(radius.width() > 0 || radius.height() > 0); if (radius.fWidth > 0) { - sk_sp dstDrawContext(context->makeDrawContext(SkBackingFit::kApprox, - rect.width(), rect.height(), - config, colorSpace)); - if (!dstDrawContext) { + sk_sp dstRTContext(context->makeDeferredRenderTargetContext( + SkBackingFit::kApprox, rect.width(), rect.height(), config, colorSpace)); + if (!dstRTContext) { return nullptr; } - apply_morphology_pass(dstDrawContext.get(), clip, srcTexture.get(), + apply_morphology_pass(dstRTContext.get(), clip, std::move(srcTexture), srcRect, dstRect, radius.fWidth, morphType, Gr1DKernelEffect::kX_Direction); SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom, @@ -505,30 +519,30 @@ static sk_sp apply_morphology( GrColor clearColor = GrMorphologyEffect::kErode_MorphologyType == morphType ? SK_ColorWHITE : SK_ColorTRANSPARENT; - dstDrawContext->clear(&clearRect, clearColor, false); + dstRTContext->clear(&clearRect, clearColor, false); - srcTexture = dstDrawContext->asTexture(); + srcTexture = dstRTContext->asTextureProxyRef(); srcRect = dstRect; } if (radius.fHeight > 0) { - sk_sp dstDrawContext(context->makeDrawContext(SkBackingFit::kApprox, - rect.width(), rect.height(), - config, colorSpace)); - if (!dstDrawContext) { + sk_sp dstRTContext(context->makeDeferredRenderTargetContext( + SkBackingFit::kApprox, rect.width(), rect.height(), config, colorSpace)); + if (!dstRTContext) { return nullptr; } - apply_morphology_pass(dstDrawContext.get(), clip, srcTexture.get(), + apply_morphology_pass(dstRTContext.get(), clip, std::move(srcTexture), srcRect, dstRect, radius.fHeight, morphType, Gr1DKernelEffect::kY_Direction); - srcTexture = dstDrawContext->asTexture(); + srcTexture = dstRTContext->asTextureProxyRef(); } - return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(rect.width(), rect.height()), - kNeedNewImageUniqueID_SpecialImage, - std::move(srcTexture), std::move(colorSpace), - &input->props()); + return SkSpecialImage::MakeDeferredFromGpu(context, + SkIRect::MakeWH(rect.width(), rect.height()), + kNeedNewImageUniqueID_SpecialImage, + std::move(srcTexture), std::move(colorSpace), + &input->props()); } #endif @@ -570,6 +584,12 @@ sk_sp SkMorphologyImageFilter::onFilterImage(SkSpecialImage* sou if (source->isTextureBacked()) { GrContext* context = source->getContext(); + // Ensure the input is in the destination color space. Typically applyCropRect will have + // called pad_image to account for our dilation of bounds, so the result will already be + // moved to the destination color space. If a filter DAG avoids that, then we use this + // fall-back, which saves us from having to do the xform during the filter itself. + input = ImageToColorSpace(input.get(), ctx.outputProperties()); + auto type = (kDilate_Op == this->op()) ? GrMorphologyEffect::kDilate_MorphologyType : GrMorphologyEffect::kErode_MorphologyType; sk_sp result(apply_morphology(context, input.get(), srcBounds, type, @@ -640,3 +660,17 @@ sk_sp SkMorphologyImageFilter::onFilterImage(SkSpecialImage* sou return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), dst, &source->props()); } + +sk_sp SkMorphologyImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + SkASSERT(1 == this->countInputs()); + if (!this->getInput(0)) { + return sk_ref_sp(const_cast(this)); + } + + sk_sp input = this->getInput(0)->makeColorSpace(xformer); + return (SkMorphologyImageFilter::kDilate_Op == this->op()) + ? SkDilateImageFilter::Make(fRadius.width(), fRadius.height(), std::move(input), + this->getCropRectIfSet()) + : SkErodeImageFilter::Make(fRadius.width(), fRadius.height(), std::move(input), + this->getCropRectIfSet()); +} diff --git a/gfx/skia/skia/src/effects/SkOffsetImageFilter.cpp b/gfx/skia/skia/src/effects/SkOffsetImageFilter.cpp index 2e8b0d916d65..973b2a69d555 100644 --- a/gfx/skia/skia/src/effects/SkOffsetImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkOffsetImageFilter.cpp @@ -73,6 +73,17 @@ sk_sp SkOffsetImageFilter::onFilterImage(SkSpecialImage* source, } } +sk_sp SkOffsetImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + SkASSERT(1 == this->countInputs()); + if (!this->getInput(0)) { + return sk_ref_sp(const_cast(this)); + } + + sk_sp input = this->getInput(0)->makeColorSpace(xformer); + return SkOffsetImageFilter::Make(fOffset.fX, fOffset.fY, std::move(input), + this->getCropRectIfSet()); +} + SkRect SkOffsetImageFilter::computeFastBounds(const SkRect& src) const { SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src; bounds.offset(fOffset.fX, fOffset.fY); diff --git a/gfx/skia/skia/src/effects/SkOverdrawColorFilter.cpp b/gfx/skia/skia/src/effects/SkOverdrawColorFilter.cpp new file mode 100644 index 000000000000..87bbc1069e47 --- /dev/null +++ b/gfx/skia/skia/src/effects/SkOverdrawColorFilter.cpp @@ -0,0 +1,177 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkOverdrawColorFilter.h" + +void SkOverdrawColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const { + for (int x = 0; x < count; x++) { + uint8_t alpha = SkGetPackedA32(src[x]); + if (alpha >= kNumColors) { + alpha = kNumColors - 1; + } + + dst[x] = fColors[alpha]; + } +} + +void SkOverdrawColorFilter::toString(SkString* str) const { + str->append("SkOverdrawColorFilter ("); + for (int i = 0; i < kNumColors; i++) { + str->appendf("%d: %x\n", i, fColors[i]); + } + str->append(")"); +} + +void SkOverdrawColorFilter::flatten(SkWriteBuffer& buffer) const { + buffer.writeByteArray(fColors, kNumColors * sizeof(SkPMColor)); +} + +sk_sp SkOverdrawColorFilter::CreateProc(SkReadBuffer& buffer) { + SkPMColor colors[kNumColors]; + size_t size = buffer.getArrayCount(); + if (!buffer.validate(size == sizeof(colors))) { + return nullptr; + } + if (!buffer.readByteArray(colors, sizeof(colors))) { + return nullptr; + } + + return SkOverdrawColorFilter::Make(colors); +} + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkOverdrawColorFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkOverdrawColorFilter) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END + +#if SK_SUPPORT_GPU + +#include "GrFragmentProcessor.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" + +class OverdrawFragmentProcessor : public GrFragmentProcessor { +public: + static sk_sp Make(const SkPMColor* colors); + + const char* name() const override { return "Overdraw"; } +private: + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} + bool onIsEqual(const GrFragmentProcessor&) const override; + + OverdrawFragmentProcessor(const GrColor4f* colors); + + GrColor4f fColors[SkOverdrawColorFilter::kNumColors]; + + typedef GrFragmentProcessor INHERITED; +}; + +class GLOverdrawFragmentProcessor : public GrGLSLFragmentProcessor { +public: + GLOverdrawFragmentProcessor(const GrColor4f* colors); + + void emitCode(EmitArgs&) override; + +protected: + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override {} + +private: + GrColor4f fColors[SkOverdrawColorFilter::kNumColors]; + + typedef GrGLSLFragmentProcessor INHERITED; +}; + +sk_sp SkOverdrawColorFilter::asFragmentProcessor(GrContext*, + SkColorSpace*) const { + return OverdrawFragmentProcessor::Make(fColors); +} + +sk_sp OverdrawFragmentProcessor::Make(const SkPMColor* colors) { + GrColor4f grColors[SkOverdrawColorFilter::kNumColors]; + for (int i = 0; i < SkOverdrawColorFilter::kNumColors; i++) { + grColors[i] = GrColor4f::FromGrColor(GrColorPackRGBA(SkGetPackedR32(colors[i]), + SkGetPackedG32(colors[i]), + SkGetPackedB32(colors[i]), + SkGetPackedA32(colors[i]))); + } + + return sk_sp(new OverdrawFragmentProcessor(grColors)); +} + +// This could implement the constant input -> constant output optimization, but we don't really +// care given how this is used. +OverdrawFragmentProcessor::OverdrawFragmentProcessor(const GrColor4f* colors) + : INHERITED(kNone_OptimizationFlags) { + this->initClassID(); + memcpy(fColors, colors, SkOverdrawColorFilter::kNumColors * sizeof(GrColor4f)); +} + +GrGLSLFragmentProcessor* OverdrawFragmentProcessor::onCreateGLSLInstance() const { + return new GLOverdrawFragmentProcessor(fColors); +} + +bool OverdrawFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const { + const OverdrawFragmentProcessor& that = other.cast(); + return 0 == memcmp(fColors, that.fColors, + sizeof(GrColor4f) * SkOverdrawColorFilter::kNumColors); +} + +GLOverdrawFragmentProcessor::GLOverdrawFragmentProcessor(const GrColor4f* colors) { + memcpy(fColors, colors, SkOverdrawColorFilter::kNumColors * sizeof(GrColor4f)); +} + +void GLOverdrawFragmentProcessor::emitCode(EmitArgs& args) { + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + if (nullptr == args.fInputColor) { + fragBuilder->codeAppendf("%s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, + fColors[5].fRGBA[0], + fColors[5].fRGBA[1], + fColors[5].fRGBA[2], + fColors[5].fRGBA[3]); + } else { + fragBuilder->codeAppendf("float alpha = 255.0 * %s.a;", args.fInputColor); + fragBuilder->codeAppendf("if (alpha < 0.5) {"); + fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, + fColors[0].fRGBA[0], + fColors[0].fRGBA[1], + fColors[0].fRGBA[2], + fColors[0].fRGBA[3]); + fragBuilder->codeAppendf("} else if (alpha < 1.5) {"); + fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, + fColors[1].fRGBA[0], + fColors[1].fRGBA[1], + fColors[1].fRGBA[2], + fColors[1].fRGBA[3]); + fragBuilder->codeAppendf("} else if (alpha < 2.5) {"); + fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, + fColors[2].fRGBA[0], + fColors[2].fRGBA[1], + fColors[2].fRGBA[2], + fColors[2].fRGBA[3]); + fragBuilder->codeAppendf("} else if (alpha < 3.5) {"); + fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, + fColors[3].fRGBA[0], + fColors[3].fRGBA[1], + fColors[3].fRGBA[2], + fColors[3].fRGBA[3]); + fragBuilder->codeAppendf("} else if (alpha < 4.5) {"); + fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, + fColors[4].fRGBA[0], + fColors[4].fRGBA[1], + fColors[4].fRGBA[2], + fColors[4].fRGBA[3]); + fragBuilder->codeAppendf("} else {"); + fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, + fColors[5].fRGBA[0], + fColors[5].fRGBA[1], + fColors[5].fRGBA[2], + fColors[5].fRGBA[3]); + fragBuilder->codeAppendf("}"); + } +} + +#endif diff --git a/gfx/skia/skia/src/effects/SkOverdrawColorFilter.h b/gfx/skia/skia/src/effects/SkOverdrawColorFilter.h new file mode 100644 index 000000000000..6c5ce592f3f2 --- /dev/null +++ b/gfx/skia/skia/src/effects/SkOverdrawColorFilter.h @@ -0,0 +1,54 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorFilter.h" +#include "../../src/core/SkReadBuffer.h" + +#ifndef SkOverdrawColorFilter_DEFINED +#define SkOverdrawColorFilter_DEFINED + +/** + * Uses the value in the src alpha channel to set the dst pixel. + * 0 -> fColors[0] + * 1 -> fColors[1] + * ... + * 5 (or larger) -> fColors[5] + * + */ +class SkOverdrawColorFilter : public SkColorFilter { +public: + static constexpr int kNumColors = 6; + + static sk_sp Make(const SkPMColor colors[kNumColors]) { + return sk_sp(new SkOverdrawColorFilter(colors)); + } + +#if SK_SUPPORT_GPU + sk_sp asFragmentProcessor(GrContext*, SkColorSpace*) const override; +#endif + + void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override; + void toString(SkString* str) const override; + + static sk_sp CreateProc(SkReadBuffer& buffer); + Factory getFactory() const override { return CreateProc; } + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() + +protected: + void flatten(SkWriteBuffer& buffer) const override; + +private: + SkOverdrawColorFilter(const SkPMColor colors[kNumColors]) { + memcpy(fColors, colors, kNumColors * sizeof(SkPMColor)); + } + + SkPMColor fColors[kNumColors]; + + typedef SkColorFilter INHERITED; +}; + +#endif // SkOverdrawColorFilter_DEFINED diff --git a/gfx/skia/skia/src/effects/SkPaintImageFilter.cpp b/gfx/skia/skia/src/effects/SkPaintImageFilter.cpp index 0a0e4e92edf9..c79385855f99 100644 --- a/gfx/skia/skia/src/effects/SkPaintImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkPaintImageFilter.cpp @@ -7,6 +7,7 @@ #include "SkPaintImageFilter.h" #include "SkCanvas.h" +#include "SkColorSpaceXformer.h" #include "SkReadBuffer.h" #include "SkSpecialImage.h" #include "SkSpecialSurface.h" @@ -68,6 +69,10 @@ sk_sp SkPaintImageFilter::onFilterImage(SkSpecialImage* source, return surf->makeImageSnapshot(); } +sk_sp SkPaintImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + return SkPaintImageFilter::Make(xformer->apply(fPaint), this->getCropRectIfSet()); +} + bool SkPaintImageFilter::affectsTransparentBlack() const { return true; } diff --git a/gfx/skia/skia/src/effects/SkPerlinNoiseShader.cpp b/gfx/skia/skia/src/effects/SkPerlinNoiseShader.cpp index caff4958af9f..72a26d5f6b35 100644 --- a/gfx/skia/skia/src/effects/SkPerlinNoiseShader.cpp +++ b/gfx/skia/skia/src/effects/SkPerlinNoiseShader.cpp @@ -6,6 +6,8 @@ */ #include "SkPerlinNoiseShader.h" + +#include "SkArenaAlloc.h" #include "SkColorFilter.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" @@ -16,7 +18,6 @@ #if SK_SUPPORT_GPU #include "GrContext.h" #include "GrCoordTransform.h" -#include "GrInvariantOutput.h" #include "SkGr.h" #include "effects/GrConstColorProcessor.h" #include "glsl/GrGLSLFragmentProcessor.h" @@ -46,10 +47,7 @@ inline int checkNoise(int noiseValue, int limitValue, int newValue) { } inline SkScalar smoothCurve(SkScalar t) { - static const SkScalar SK_Scalar3 = 3.0f; - - // returns t * t * (3 - 2 * t) - return SkScalarMul(SkScalarSquare(t), SK_Scalar3 - 2 * t); + return t * t * (3 - 2 * t); } } // end namespace @@ -187,16 +185,14 @@ private: for (int channel = 0; channel < 4; ++channel) { for (int i = 0; i < kBlockSize; ++i) { fGradient[channel][i] = SkPoint::Make( - SkScalarMul(SkIntToScalar(fNoise[channel][i][0] - kBlockSize), - gInvBlockSizef), - SkScalarMul(SkIntToScalar(fNoise[channel][i][1] - kBlockSize), - gInvBlockSizef)); + (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef, + (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef); fGradient[channel][i].normalize(); // Put the normalized gradient back into the noise data - fNoise[channel][i][0] = SkScalarRoundToInt(SkScalarMul( - fGradient[channel][i].fX + SK_Scalar1, gHalfMax16bits)); - fNoise[channel][i][1] = SkScalarRoundToInt(SkScalarMul( - fGradient[channel][i].fY + SK_Scalar1, gHalfMax16bits)); + fNoise[channel][i][0] = SkScalarRoundToInt( + (fGradient[channel][i].fX + 1) * gHalfMax16bits); + fNoise[channel][i][1] = SkScalarRoundToInt( + (fGradient[channel][i].fY + 1) * gHalfMax16bits); } } } @@ -384,8 +380,8 @@ SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::calculateTurbulenceValue stitchData = fPaintingData->fStitchDataInit; } SkScalar turbulenceFunctionResult = 0; - SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), fPaintingData->fBaseFrequency.fX), - SkScalarMul(point.y(), fPaintingData->fBaseFrequency.fY))); + SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData->fBaseFrequency.fX, + point.y() * fPaintingData->fBaseFrequency.fY)); SkScalar ratio = SK_Scalar1; for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) { SkScalar noise = noise2D(channel, stitchData, noiseVector); @@ -407,8 +403,7 @@ SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::calculateTurbulenceValue // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 // by fractalNoise and (turbulenceFunctionResult) by turbulence. if (perlinNoiseShader.fType == kFractalNoise_Type) { - turbulenceFunctionResult = - SkScalarMul(turbulenceFunctionResult, SK_ScalarHalf) + SK_ScalarHalf; + turbulenceFunctionResult = turbulenceFunctionResult * SK_ScalarHalf + SK_ScalarHalf; } if (channel == 3) { // Scale alpha by paint value @@ -434,21 +429,16 @@ SkPMColor SkPerlinNoiseShader::PerlinNoiseShaderContext::shade( return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]); } -SkShader::Context* SkPerlinNoiseShader::onCreateContext(const ContextRec& rec, - void* storage) const { - return new (storage) PerlinNoiseShaderContext(*this, rec); -} - -size_t SkPerlinNoiseShader::onContextSize(const ContextRec&) const { - return sizeof(PerlinNoiseShaderContext); +SkShader::Context* SkPerlinNoiseShader::onMakeContext( + const ContextRec& rec, SkArenaAlloc* alloc) const { + return alloc->make(*this, rec); } SkPerlinNoiseShader::PerlinNoiseShaderContext::PerlinNoiseShaderContext( const SkPerlinNoiseShader& shader, const ContextRec& rec) : INHERITED(shader, rec) { - SkMatrix newMatrix = *rec.fMatrix; - newMatrix.preConcat(shader.getLocalMatrix()); + SkMatrix newMatrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix()); if (rec.fLocalMatrix) { newMatrix.preConcat(*rec.fLocalMatrix); } @@ -479,10 +469,10 @@ class GrGLPerlinNoise : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fStitchDataUni; @@ -495,17 +485,19 @@ private: class GrPerlinNoiseEffect : public GrFragmentProcessor { public: - static sk_sp Make(SkPerlinNoiseShader::Type type, + static sk_sp Make(GrResourceProvider* resourceProvider, + SkPerlinNoiseShader::Type type, int numOctaves, bool stitchTiles, SkPerlinNoiseShader::PaintingData* paintingData, - GrTexture* permutationsTexture, GrTexture* noiseTexture, + sk_sp permutationsProxy, + sk_sp noiseProxy, const SkMatrix& matrix) { return sk_sp( - new GrPerlinNoiseEffect(type, numOctaves, stitchTiles, paintingData, - permutationsTexture, noiseTexture, matrix)); + new GrPerlinNoiseEffect(resourceProvider, type, numOctaves, stitchTiles, paintingData, + std::move(permutationsProxy), std::move(noiseProxy), matrix)); } - virtual ~GrPerlinNoiseEffect() { delete fPaintingData; } + ~GrPerlinNoiseEffect() override { delete fPaintingData; } const char* name() const override { return "PerlinNoise"; } @@ -515,14 +507,13 @@ public: bool stitchTiles() const { return fStitchTiles; } const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; } int numOctaves() const { return fNumOctaves; } - const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); } private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GrGLPerlinNoise; } - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, + virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GrGLPerlinNoise::GenKey(*this, caps, b); } @@ -536,25 +527,22 @@ private: fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput); - } - - GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type, - int numOctaves, bool stitchTiles, + GrPerlinNoiseEffect(GrResourceProvider* resourceProvider, + SkPerlinNoiseShader::Type type, int numOctaves, bool stitchTiles, SkPerlinNoiseShader::PaintingData* paintingData, - GrTexture* permutationsTexture, GrTexture* noiseTexture, + sk_sp permutationsProxy, sk_sp noiseProxy, const SkMatrix& matrix) - : fType(type) - , fNumOctaves(numOctaves) - , fStitchTiles(stitchTiles) - , fPermutationsAccess(permutationsTexture) - , fNoiseAccess(noiseTexture) - , fPaintingData(paintingData) { + : INHERITED(kNone_OptimizationFlags) + , fType(type) + , fCoordTransform(matrix) + , fNumOctaves(numOctaves) + , fStitchTiles(stitchTiles) + , fPermutationsSampler(resourceProvider, std::move(permutationsProxy)) + , fNoiseSampler(resourceProvider, std::move(noiseProxy)) + , fPaintingData(paintingData) { this->initClassID(); - this->addTextureAccess(&fPermutationsAccess); - this->addTextureAccess(&fNoiseAccess); - fCoordTransform.reset(matrix); + this->addTextureSampler(&fPermutationsSampler); + this->addTextureSampler(&fNoiseSampler); this->addCoordTransform(&fCoordTransform); } @@ -564,8 +552,8 @@ private: GrCoordTransform fCoordTransform; int fNumOctaves; bool fStitchTiles; - GrTextureAccess fPermutationsAccess; - GrTextureAccess fNoiseAccess; + TextureSampler fPermutationsSampler; + TextureSampler fNoiseSampler; SkPerlinNoiseShader::PaintingData *fPaintingData; private: @@ -575,6 +563,7 @@ private: ///////////////////////////////////////////////////////////////////// GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoiseEffect); +#if GR_TEST_UTILS sk_sp GrPerlinNoiseEffect::TestCreate(GrProcessorTestData* d) { int numOctaves = d->fRandom->nextRangeU(2, 10); bool stitchTiles = d->fRandom->nextBool(); @@ -592,12 +581,10 @@ sk_sp GrPerlinNoiseEffect::TestCreate(GrProcessorTestData* SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed, stitchTiles ? &tileSize : nullptr)); - SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom); - auto colorSpace = GrTest::TestColorSpace(d->fRandom); - return shader->asFragmentProcessor(SkShader::AsFPArgs(d->fContext, &viewMatrix, nullptr, - kNone_SkFilterQuality, colorSpace.get(), - SkSourceGammaTreatment::kRespect)); + GrTest::TestAsFPArgs asFPArgs(d); + return shader->asFragmentProcessor(asFPArgs.args()); } +#endif void GrGLPerlinNoise::emitCode(EmitArgs& args) { const GrPerlinNoiseEffect& pne = args.fFp.cast(); @@ -642,15 +629,15 @@ void GrGLPerlinNoise::emitCode(EmitArgs& args) { const char* dotLattice = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);"; // Add noise function - static const GrGLSLShaderVar gPerlinNoiseArgs[] = { - GrGLSLShaderVar(chanCoord, kFloat_GrSLType), - GrGLSLShaderVar(noiseVec, kVec2f_GrSLType) + static const GrShaderVar gPerlinNoiseArgs[] = { + GrShaderVar(chanCoord, kFloat_GrSLType), + GrShaderVar(noiseVec, kVec2f_GrSLType) }; - static const GrGLSLShaderVar gPerlinNoiseStitchArgs[] = { - GrGLSLShaderVar(chanCoord, kFloat_GrSLType), - GrGLSLShaderVar(noiseVec, kVec2f_GrSLType), - GrGLSLShaderVar(stitchData, kVec2f_GrSLType) + static const GrShaderVar gPerlinNoiseStitchArgs[] = { + GrShaderVar(chanCoord, kFloat_GrSLType), + GrShaderVar(noiseVec, kVec2f_GrSLType), + GrShaderVar(stitchData, kVec2f_GrSLType) }; SkString noiseCode; @@ -851,7 +838,7 @@ void GrGLPerlinNoise::emitCode(EmitArgs& args) { args.fOutputColor, args.fOutputColor); } -void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrGLSLCaps&, +void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrPerlinNoiseEffect& turbulence = processor.cast(); @@ -879,7 +866,7 @@ void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrGLSLCaps&, } void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrFragmentProcessor& processor) { INHERITED::onSetData(pdman, processor); const GrPerlinNoiseEffect& turbulence = processor.cast(); @@ -909,13 +896,17 @@ sk_sp SkPerlinNoiseShader::asFragmentProcessor(const AsFPAr if (0 == fNumOctaves) { if (kFractalNoise_Type == fType) { // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2) + // TODO: Either treat the output of this shader as sRGB or allow client to specify a + // color space of the noise. Either way, this case (and the GLSL) need to convert to + // the destination. sk_sp inner( - GrConstColorProcessor::Make(0x80404040, + GrConstColorProcessor::Make(GrColor4f::FromGrColor(0x80404040), GrConstColorProcessor::kModulateRGBA_InputMode)); return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)); } // Emit zero. - return GrConstColorProcessor::Make(0x0, GrConstColorProcessor::kIgnore_InputMode); + return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), + GrConstColorProcessor::kIgnore_InputMode); } // Either we don't stitch tiles, either we have a valid tile size @@ -923,23 +914,24 @@ sk_sp SkPerlinNoiseShader::asFragmentProcessor(const AsFPAr SkPerlinNoiseShader::PaintingData* paintingData = new PaintingData(fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY, matrix); - SkAutoTUnref permutationsTexture( - GrRefCachedBitmapTexture(args.fContext, paintingData->getPermutationsBitmap(), - GrTextureParams::ClampNoFilter(), args.fGammaTreatment)); - SkAutoTUnref noiseTexture( - GrRefCachedBitmapTexture(args.fContext, paintingData->getNoiseBitmap(), - GrTextureParams::ClampNoFilter(), args.fGammaTreatment)); + sk_sp permutationsProxy(GrMakeCachedBitmapProxy( + args.fContext->resourceProvider(), + paintingData->getPermutationsBitmap())); + sk_sp noiseProxy(GrMakeCachedBitmapProxy(args.fContext->resourceProvider(), + paintingData->getNoiseBitmap())); SkMatrix m = *args.fViewMatrix; m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1); m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1); - if ((permutationsTexture) && (noiseTexture)) { + if (permutationsProxy && noiseProxy) { sk_sp inner( - GrPerlinNoiseEffect::Make(fType, + GrPerlinNoiseEffect::Make(args.fContext->resourceProvider(), + fType, fNumOctaves, fStitchTiles, paintingData, - permutationsTexture, noiseTexture, + std::move(permutationsProxy), + std::move(noiseProxy), m)); return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)); } diff --git a/gfx/skia/skia/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp b/gfx/skia/skia/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp new file mode 100644 index 000000000000..1c7134ee9404 --- /dev/null +++ b/gfx/skia/skia/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp @@ -0,0 +1,574 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkRRectsGaussianEdgeMaskFilter.h" +#include "SkReadBuffer.h" +#include "SkRRect.h" +#include "SkWriteBuffer.h" + +#if SK_SUPPORT_GPU +#include "GrFragmentProcessor.h" +#endif + + /** \class SkRRectsGaussianEdgeMaskFilterImpl + * This mask filter applies a gaussian edge to the intersection of two round rects. + * The round rects must have the same radii at each corner and the x&y radii + * must also be equal. + */ +class SkRRectsGaussianEdgeMaskFilterImpl : public SkMaskFilter { +public: + SkRRectsGaussianEdgeMaskFilterImpl(const SkRRect& first, const SkRRect& second, + SkScalar radius) + : fFirst(first) + , fSecond(second) + , fRadius(radius) { + } + + SkMask::Format getFormat() const override { return SkMask::kA8_Format; } + bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, + SkIPoint* margin) const override; + +#if SK_SUPPORT_GPU + bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix& ctm) const override; +#endif + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkRRectsGaussianEdgeMaskFilterImpl) + +protected: + void flatten(SkWriteBuffer&) const override; + +private: + SkRRect fFirst; + SkRRect fSecond; + SkScalar fRadius; + + friend class SkRRectsGaussianEdgeMaskFilter; // for serialization registration system + + typedef SkMaskFilter INHERITED; +}; + +// x & y are in device space +static SkScalar compute_rrect_normalized_dist(const SkRRect& rr, const SkPoint& p, SkScalar rad) { + SkASSERT(rr.getType() == SkRRect::kOval_Type || rr.getType() == SkRRect::kRect_Type || + rr.getType() == SkRRect::kSimple_Type); + SkASSERT(rad > 0.0f); + + SkVector delta = { SkTAbs(p.fX - rr.rect().centerX()), SkTAbs(p.fY - rr.rect().centerY()) }; + + SkScalar halfW = 0.5f * rr.rect().width(); + SkScalar halfH = 0.5f * rr.rect().height(); + SkScalar invRad = 1.0f/rad; + + const SkVector& radii = rr.getSimpleRadii(); + SkASSERT(SkScalarNearlyEqual(radii.fX, radii.fY)); + + switch (rr.getType()) { + case SkRRect::kOval_Type: { + float scaledDist = delta.length() * invRad; + return SkTPin(halfW * invRad - scaledDist, 0.0f, 1.0f); + } + case SkRRect::kRect_Type: { + SkScalar xDist = (halfW - delta.fX) * invRad; + SkScalar yDist = (halfH - delta.fY) * invRad; + + SkVector v = { 1.0f - SkTPin(xDist, 0.0f, 1.0f), 1.0f - SkTPin(yDist, 0.0f, 1.0f) }; + return SkTPin(1.0f - v.length(), 0.0f, 1.0f); + } + case SkRRect::kSimple_Type: { + + //---------------- + // ice-cream-cone fractional distance computation + + // When the blurRadius is larger than the corner radius we want to use it to + // compute the pointy end of the ice cream cone. If it smaller we just want to use + // the center of the corner's circle. When using the blurRadius the inset amount + // can't exceed the halfwidths of the RRect. + SkScalar insetDist = SkTMin(SkTMax(rad, radii.fX), SkTMin(halfW, halfH)); + + // "maxValue" is a correction term for if the blurRadius is larger than the + // size of the RRect. In that case we don't want to go all the way to black. + SkScalar maxValue = insetDist * invRad; + + SkVector coneBottom = { halfW - insetDist, halfH - insetDist }; + SkVector ptInConeSpace = delta - coneBottom; + + SkVector cornerTop = { halfW - radii.fX - coneBottom.fX, halfH - coneBottom.fY }; + SkVector cornerRight = { halfW - coneBottom.fX, halfH - radii.fY - coneBottom.fY }; + + SkScalar cross1 = ptInConeSpace.cross(cornerTop); + SkScalar cross2 = cornerRight.cross(ptInConeSpace); + bool inCone = cross1 > 0.0f && cross2 > 0.0f; + + if (!inCone) { + SkScalar xDist = (halfW - delta.fX) * invRad; + SkScalar yDist = (halfH - delta.fY) * invRad; + + return SkTPin(SkTMin(xDist, yDist), 0.0f, 1.0f); // perpendicular distance + } + + SkVector cornerCenterInConeSpace = { insetDist - radii.fX, insetDist - radii.fY }; + + SkVector connectingVec = ptInConeSpace - cornerCenterInConeSpace; + float distToPtInConeSpace = SkPoint::Normalize(&ptInConeSpace); + + // "a" (i.e., dot(ptInConeSpace, ptInConeSpace) should always be 1.0f since + // ptInConeSpace is now normalized + SkScalar b = 2.0f * ptInConeSpace.dot(connectingVec); + SkScalar c = connectingVec.dot(connectingVec) - radii.fX * radii.fY; + + // lop off negative values that are outside the cone + SkScalar coneDist = SkTMax(0.0f, 0.5f * (-b + SkScalarSqrt(b*b - 4*c))); + + // make the coneDist a fraction of how far it is from the edge to the cone's base + coneDist = (maxValue*coneDist) / (coneDist+distToPtInConeSpace); + return SkTPin(coneDist, 0.0f, 1.0f); + } + default: + return 0.0f; + } +} + +bool SkRRectsGaussianEdgeMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, + const SkMatrix& matrix, + SkIPoint* margin) const { + + if (src.fFormat != SkMask::kA8_Format) { + return false; + } + + if (margin) { + margin->set(0, 0); + } + + dst->fBounds = src.fBounds; + dst->fRowBytes = dst->fBounds.width(); + dst->fFormat = SkMask::kA8_Format; + dst->fImage = nullptr; + + if (src.fImage) { + size_t dstSize = dst->computeImageSize(); + if (0 == dstSize) { + return false; // too big to allocate, abort + } + + const uint8_t* srcPixels = src.fImage; + uint8_t* dstPixels = dst->fImage = SkMask::AllocImage(dstSize); + + SkPoint basePt = { SkIntToScalar(src.fBounds.fLeft), SkIntToScalar(src.fBounds.fTop) }; + + for (int y = 0; y < dst->fBounds.height(); ++y) { + const uint8_t* srcRow = srcPixels + y * dst->fRowBytes; + uint8_t* dstRow = dstPixels + y*dst->fRowBytes; + + for (int x = 0; x < dst->fBounds.width(); ++x) { + SkPoint curPt = { basePt.fX + x, basePt.fY + y }; + + SkVector vec; + vec.fX = 1.0f - compute_rrect_normalized_dist(fFirst, curPt, fRadius); + vec.fY = 1.0f - compute_rrect_normalized_dist(fSecond, curPt, fRadius); + + SkScalar factor = SkTPin(vec.length(), 0.0f, 1.0f); + factor = exp(-factor * factor * 4.0f) - 0.018f; + SkASSERT(factor >= 0.0f && factor <= 1.0f); + + dstRow[x] = (uint8_t) (factor * srcRow[x]); + } + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////// + +#if SK_SUPPORT_GPU + +#include "GrCoordTransform.h" +#include "GrFragmentProcessor.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" +#include "SkGr.h" + +class RRectsGaussianEdgeFP : public GrFragmentProcessor { +public: + enum Mode { + kCircle_Mode, + kRect_Mode, + kSimpleCircular_Mode, + }; + + RRectsGaussianEdgeFP(const SkRRect& first, const SkRRect& second, SkScalar radius) + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fFirst(first) + , fSecond(second) + , fRadius(radius) { + this->initClassID(); + + fFirstMode = ComputeMode(fFirst); + fSecondMode = ComputeMode(fSecond); + } + + class GLSLRRectsGaussianEdgeFP : public GrGLSLFragmentProcessor { + public: + GLSLRRectsGaussianEdgeFP() { } + + // This method emits code so that, for each shape, the distance from the edge is returned + // in 'outputName' clamped to 0..1 with positive distance being towards the center of the + // shape. The distance will have been normalized by the radius. + void emitModeCode(Mode mode, + GrGLSLFPFragmentBuilder* fragBuilder, + const char* posName, + const char* sizesName, + const char* radiiName, + const char* radName, + const char* outputName, + const char indices[2]) { // how to access the params for the 2 rrects + + // Positive distance is towards the center of the circle. + // Map all the cases to the lower right quadrant. + fragBuilder->codeAppendf("vec2 delta = abs(sk_FragCoord.xy - %s.%s);", + posName, indices); + + switch (mode) { + case kCircle_Mode: + // When a shadow circle gets large we can have some precision issues if + // we do "length(delta)/radius". The scaleDist temporary cuts the + // delta vector down a bit before invoking length. + fragBuilder->codeAppendf("float scaledDist = length(delta/%s);", radName); + fragBuilder->codeAppendf("%s = clamp((%s.%c/%s - scaledDist), 0.0, 1.0);", + outputName, sizesName, indices[0], radName); + break; + case kRect_Mode: + fragBuilder->codeAppendf( + "vec2 rectDist = vec2(1.0 - clamp((%s.%c - delta.x)/%s, 0.0, 1.0)," + "1.0 - clamp((%s.%c - delta.y)/%s, 0.0, 1.0));", + sizesName, indices[0], radName, + sizesName, indices[1], radName); + fragBuilder->codeAppendf("%s = clamp(1.0 - length(rectDist), 0.0, 1.0);", + outputName); + break; + case kSimpleCircular_Mode: + // For the circular round rect we combine 2 distances: + // the fractional position from the corner inset point to the corner's circle + // the minimum perpendicular distance to the bounding rectangle + // The first distance is used when the pixel is inside the ice-cream-cone-shaped + // portion of a corner. The second is used everywhere else. + // This is intended to approximate the interpolation pattern if we had + // tessellated this geometry into a RRect outside and a rect inside. + + //---------------- + // rect distance computation + fragBuilder->codeAppendf("float xDist = (%s.%c - delta.x) / %s;", + sizesName, indices[0], radName); + fragBuilder->codeAppendf("float yDist = (%s.%c - delta.y) / %s;", + sizesName, indices[1], radName); + fragBuilder->codeAppend("float rectDist = clamp(min(xDist, yDist), 0.0, 1.0);"); + + //---------------- + // ice-cream-cone fractional distance computation + + // When the blurRadius is larger than the corner radius we want to use it to + // compute the pointy end of the ice cream cone. If it smaller we just want to + // use the center of the corner's circle. When using the blurRadius the inset + // amount can't exceed the halfwidths of the RRect. + fragBuilder->codeAppendf("float insetDist = min(max(%s, %s.%c)," + "min(%s.%c, %s.%c));", + radName, radiiName, indices[0], + sizesName, indices[0], sizesName, indices[1]); + // "maxValue" is a correction term for if the blurRadius is larger than the + // size of the RRect. In that case we don't want to go all the way to black. + fragBuilder->codeAppendf("float maxValue = insetDist/%s;", radName); + + fragBuilder->codeAppendf("vec2 coneBottom = vec2(%s.%c - insetDist," + "%s.%c - insetDist);", + sizesName, indices[0], sizesName, indices[1]); + + fragBuilder->codeAppendf("vec2 cornerTop = vec2(%s.%c - %s.%c, %s.%c) -" + "coneBottom;", + sizesName, indices[0], radiiName, indices[0], + sizesName, indices[1]); + fragBuilder->codeAppendf("vec2 cornerRight = vec2(%s.%c, %s.%c - %s.%c) -" + "coneBottom;", + sizesName, indices[0], + sizesName, indices[1], radiiName, indices[1]); + + fragBuilder->codeAppend("vec2 ptInConeSpace = delta - coneBottom;"); + fragBuilder->codeAppend("float distToPtInConeSpace = length(ptInConeSpace);"); + + fragBuilder->codeAppend("float cross1 = ptInConeSpace.x * cornerTop.y -" + "ptInConeSpace.y * cornerTop.x;"); + fragBuilder->codeAppend("float cross2 = -ptInConeSpace.x * cornerRight.y + " + "ptInConeSpace.y * cornerRight.x;"); + + fragBuilder->codeAppend("float inCone = step(0.0, cross1) *" + "step(0.0, cross2);"); + + fragBuilder->codeAppendf("vec2 cornerCenterInConeSpace = vec2(insetDist -" + "%s.%c);", + radiiName, indices[0]); + + fragBuilder->codeAppend("vec2 connectingVec = ptInConeSpace -" + "cornerCenterInConeSpace;"); + fragBuilder->codeAppend("ptInConeSpace = normalize(ptInConeSpace);"); + + // "a" (i.e., dot(ptInConeSpace, ptInConeSpace) should always be 1.0f since + // ptInConeSpace is now normalized + fragBuilder->codeAppend("float b = 2.0 * dot(ptInConeSpace, connectingVec);"); + fragBuilder->codeAppendf("float c = dot(connectingVec, connectingVec) - " + "%s.%c * %s.%c;", + radiiName, indices[0], radiiName, indices[0]); + + fragBuilder->codeAppend("float fourAC = 4*c;"); + // This max prevents sqrt(-1) when outside the cone + fragBuilder->codeAppend("float bSq = max(b*b, fourAC);"); + + // lop off negative values that are outside the cone + fragBuilder->codeAppend("float coneDist = " + "max(0.0, 0.5 * (-b + sqrt(bSq - fourAC)));"); + // make the coneDist a fraction of how far it is from the edge to the + // cone's base + fragBuilder->codeAppend("coneDist = (maxValue*coneDist) /" + "(coneDist+distToPtInConeSpace);"); + fragBuilder->codeAppend("coneDist = clamp(coneDist, 0.0, 1.0);"); + + //---------------- + fragBuilder->codeAppendf("%s = mix(rectDist, coneDist, inCone);", outputName); + break; + } + } + + void emitCode(EmitArgs& args) override { + const RRectsGaussianEdgeFP& fp = args.fFp.cast(); + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + + const char* positionsUniName = nullptr; + fPositionsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "Positions", &positionsUniName); + const char* sizesUniName = nullptr; + fSizesUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "Sizes", &sizesUniName); + const char* radiiUniName = nullptr; + if (fp.fFirstMode == kSimpleCircular_Mode || fp.fSecondMode == kSimpleCircular_Mode) { + fRadiiUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "Radii", &radiiUniName); + } + const char* radUniName = nullptr; + fRadiusUni = uniformHandler->addUniform(kFragment_GrShaderFlag, + kFloat_GrSLType, kDefault_GrSLPrecision, + "Radius", &radUniName); + + fragBuilder->codeAppend("float firstDist;"); + fragBuilder->codeAppend("{"); + this->emitModeCode(fp.firstMode(), fragBuilder, + positionsUniName, sizesUniName, radiiUniName, + radUniName, "firstDist", "xy"); + fragBuilder->codeAppend("}"); + + fragBuilder->codeAppend("float secondDist;"); + fragBuilder->codeAppend("{"); + this->emitModeCode(fp.secondMode(), fragBuilder, + positionsUniName, sizesUniName, radiiUniName, + radUniName, "secondDist", "zw"); + fragBuilder->codeAppend("}"); + + fragBuilder->codeAppend("vec2 distVec = vec2(1.0 - firstDist, 1.0 - secondDist);"); + + // Finally use the distance to apply the Gaussian edge + fragBuilder->codeAppend("float factor = clamp(length(distVec), 0.0, 1.0);"); + fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;"); + fragBuilder->codeAppendf("%s = factor*%s;", + args.fOutputColor, args.fInputColor); + } + + static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) { + const RRectsGaussianEdgeFP& fp = proc.cast(); + + b->add32(fp.firstMode() | (fp.secondMode() << 4)); + } + + protected: + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) override { + const RRectsGaussianEdgeFP& edgeFP = proc.cast(); + + const SkRRect& first = edgeFP.first(); + const SkRRect& second = edgeFP.second(); + + pdman.set4f(fPositionsUni, + first.getBounds().centerX(), + first.getBounds().centerY(), + second.getBounds().centerX(), + second.getBounds().centerY()); + + pdman.set4f(fSizesUni, + 0.5f * first.rect().width(), + 0.5f * first.rect().height(), + 0.5f * second.rect().width(), + 0.5f * second.rect().height()); + + if (edgeFP.firstMode() == kSimpleCircular_Mode || + edgeFP.secondMode() == kSimpleCircular_Mode) { + // This is a bit of overkill since fX should equal fY for both round rects but it + // makes the shader code simpler. + pdman.set4f(fRadiiUni, + first.getSimpleRadii().fX, first.getSimpleRadii().fY, + second.getSimpleRadii().fX, second.getSimpleRadii().fY); + } + + pdman.set1f(fRadiusUni, edgeFP.radius()); + } + + private: + // The centers of the two round rects (x1, y1, x2, y2) + GrGLSLProgramDataManager::UniformHandle fPositionsUni; + + // The half widths and half heights of the two round rects (w1/2, h1/2, w2/2, h2/2) + // For circles we still upload both width & height to simplify things + GrGLSLProgramDataManager::UniformHandle fSizesUni; + + // The corner radii of the two round rects (rx1, ry1, rx2, ry2) + // We upload both the x&y radii (although they are currently always the same) to make + // the indexing in the shader code simpler. In some future world we could also support + // non-circular corner round rects & ellipses. + GrGLSLProgramDataManager::UniformHandle fRadiiUni; + + // The radius parameters (radius) + GrGLSLProgramDataManager::UniformHandle fRadiusUni; + + typedef GrGLSLFragmentProcessor INHERITED; + }; + + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { + GLSLRRectsGaussianEdgeFP::GenKey(*this, caps, b); + } + + const char* name() const override { return "RRectsGaussianEdgeFP"; } + + const SkRRect& first() const { return fFirst; } + Mode firstMode() const { return fFirstMode; } + const SkRRect& second() const { return fSecond; } + Mode secondMode() const { return fSecondMode; } + SkScalar radius() const { return fRadius; } + +private: + static Mode ComputeMode(const SkRRect& rr) { + if (rr.isCircle()) { + return kCircle_Mode; + } else if (rr.isRect()) { + return kRect_Mode; + } else { + SkASSERT(rr.isSimpleCircular()); + return kSimpleCircular_Mode; + } + } + + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { + return new GLSLRRectsGaussianEdgeFP; + } + + bool onIsEqual(const GrFragmentProcessor& proc) const override { + const RRectsGaussianEdgeFP& edgeFP = proc.cast(); + return fFirst == edgeFP.fFirst && + fSecond == edgeFP.fSecond && + fRadius == edgeFP.fRadius; + } + + SkRRect fFirst; + Mode fFirstMode; + SkRRect fSecond; + Mode fSecondMode; + SkScalar fRadius; + + typedef GrFragmentProcessor INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////// +bool SkRRectsGaussianEdgeMaskFilterImpl::asFragmentProcessor(GrFragmentProcessor** fp, + GrTexture*, const + SkMatrix& ctm) const { + if (fp) { + *fp = new RRectsGaussianEdgeFP(fFirst, fSecond, fRadius); + } + + return true; +} + +#endif + +//////////////////////////////////////////////////////////////////////////// + +#ifndef SK_IGNORE_TO_STRING +void SkRRectsGaussianEdgeMaskFilterImpl::toString(SkString* str) const { + str->appendf("RRectsGaussianEdgeMaskFilter: ()"); +} +#endif + +sk_sp SkRRectsGaussianEdgeMaskFilterImpl::CreateProc(SkReadBuffer& buf) { + SkRect rect1, rect2; + + buf.readRect(&rect1); + SkScalar xRad1 = buf.readScalar(); + SkScalar yRad1 = buf.readScalar(); + + buf.readRect(&rect2); + SkScalar xRad2 = buf.readScalar(); + SkScalar yRad2 = buf.readScalar(); + + SkScalar radius = buf.readScalar(); + + return sk_make_sp(SkRRect::MakeRectXY(rect1, xRad1, yRad1), + SkRRect::MakeRectXY(rect2, xRad2, yRad2), + radius); +} + +void SkRRectsGaussianEdgeMaskFilterImpl::flatten(SkWriteBuffer& buf) const { + INHERITED::flatten(buf); + + SkASSERT(fFirst.isRect() || fFirst.isCircle() || fFirst.isSimpleCircular()); + buf.writeRect(fFirst.rect()); + const SkVector& radii1 = fFirst.getSimpleRadii(); + buf.writeScalar(radii1.fX); + buf.writeScalar(radii1.fY); + + SkASSERT(fSecond.isRect() || fSecond.isCircle() || fSecond.isSimpleCircular()); + buf.writeRect(fSecond.rect()); + const SkVector& radii2 = fSecond.getSimpleRadii(); + buf.writeScalar(radii2.fX); + buf.writeScalar(radii2.fY); + + buf.writeScalar(fRadius); +} + +/////////////////////////////////////////////////////////////////////////////// + +sk_sp SkRRectsGaussianEdgeMaskFilter::Make(const SkRRect& first, + const SkRRect& second, + SkScalar radius) { + if ((!first.isRect() && !first.isCircle() && !first.isSimpleCircular()) || + (!second.isRect() && !second.isCircle() && !second.isSimpleCircular())) { + // we only deal with the shapes where the x & y radii are equal + // and the same for all four corners + return nullptr; + } + + return sk_make_sp(first, second, radius); +} + +/////////////////////////////////////////////////////////////////////////////// + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkRRectsGaussianEdgeMaskFilter) +SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRRectsGaussianEdgeMaskFilterImpl) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END + +/////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/effects/SkRRectsGaussianEdgeShader.cpp b/gfx/skia/skia/src/effects/SkRRectsGaussianEdgeShader.cpp deleted file mode 100644 index e7703f964aae..000000000000 --- a/gfx/skia/skia/src/effects/SkRRectsGaussianEdgeShader.cpp +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkRRectsGaussianEdgeShader.h" -#include "SkReadBuffer.h" -#include "SkWriteBuffer.h" - - /** \class SkRRectsGaussianEdgeShaderImpl - * This shader applies a gaussian edge to the intersection of two round rects. - * The round rects must have the same radii at each corner and the x&y radii - * must also be equal. - */ -class SkRRectsGaussianEdgeShaderImpl : public SkShader { -public: - SkRRectsGaussianEdgeShaderImpl(const SkRRect& first, const SkRRect& second, SkScalar radius) - : fFirst(first) - , fSecond(second) - , fRadius(radius) { - } - - bool isOpaque() const override { return false; } - -#if SK_SUPPORT_GPU - sk_sp asFragmentProcessor(const AsFPArgs&) const override; -#endif - - class GaussianEdgeShaderContext : public SkShader::Context { - public: - GaussianEdgeShaderContext(const SkRRectsGaussianEdgeShaderImpl&, const ContextRec&); - - ~GaussianEdgeShaderContext() override { } - - void shadeSpan(int x, int y, SkPMColor[], int count) override; - - uint32_t getFlags() const override { return 0; } - - private: - SkColor fPaintColor; - - typedef SkShader::Context INHERITED; - }; - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkRRectsGaussianEdgeShaderImpl) - -protected: - void flatten(SkWriteBuffer&) const override; - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec&, void*) const override; - -private: - SkRRect fFirst; - SkRRect fSecond; - SkScalar fRadius; - - friend class SkRRectsGaussianEdgeShader; // for serialization registration system - - typedef SkShader INHERITED; -}; - -//////////////////////////////////////////////////////////////////////////// - -#if SK_SUPPORT_GPU - -#include "GrCoordTransform.h" -#include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" -#include "glsl/GrGLSLFragmentProcessor.h" -#include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLUniformHandler.h" -#include "SkGr.h" -#include "SkGrPriv.h" - -class RRectsGaussianEdgeFP : public GrFragmentProcessor { -public: - enum Mode { - kCircle_Mode, - kRect_Mode, - kSimpleCircular_Mode, - }; - - RRectsGaussianEdgeFP(const SkRRect& first, const SkRRect& second, SkScalar radius) - : fFirst(first) - , fSecond(second) - , fRadius(radius) { - this->initClassID(); - this->setWillReadFragmentPosition(); - - fFirstMode = ComputeMode(fFirst); - fSecondMode = ComputeMode(fSecond); - } - - class GLSLRRectsGaussianEdgeFP : public GrGLSLFragmentProcessor { - public: - GLSLRRectsGaussianEdgeFP() { } - - // This method emits code so that, for each shape, the distance from the edge is returned - // in 'outputName' clamped to 0..1 with positive distance being towards the center of the - // shape. The distance will have been normalized by the radius. - void emitModeCode(Mode mode, - GrGLSLFPFragmentBuilder* fragBuilder, - const char* posName, - const char* sizesName, - const char* radiiName, - const char* radName, - const char* outputName, - const char indices[2]) { // how to access the params for the 2 rrects - - // positive distance is towards the center of the circle - fragBuilder->codeAppendf("vec2 delta = %s.xy - %s.%s;", - fragBuilder->fragmentPosition(), posName, indices); - - switch (mode) { - case kCircle_Mode: - // When a shadow circle gets large we can have some precision issues if - // we do "length(delta)/radius". The scaleDist temporary cuts the - // delta vector down a bit before invoking length. - fragBuilder->codeAppendf("float scaledDist = length(delta/%s);", radName); - fragBuilder->codeAppendf("%s = clamp((%s.%c/%s - scaledDist), 0.0, 1.0);", - outputName, sizesName, indices[0], radName); - break; - case kRect_Mode: - fragBuilder->codeAppendf( - "vec2 rectDist = vec2(1.0 - clamp((%s.%c - abs(delta.x))/%s, 0.0, 1.0)," - "1.0 - clamp((%s.%c - abs(delta.y))/%s, 0.0, 1.0));", - sizesName, indices[0], radName, - sizesName, indices[1], radName); - fragBuilder->codeAppendf("%s = clamp(1.0 - length(rectDist), 0.0, 1.0);", - outputName); - break; - case kSimpleCircular_Mode: - // For the circular round rect we first compute the distance - // to the rect. Then we compute a multiplier that is 1 if the - // point is in one of the circular corners. We then compute the - // distance from the corner and then use the multiplier to mask - // between the two distances. - fragBuilder->codeAppendf("float xDist = clamp((%s.%c - abs(delta.x))/%s," - "0.0, 1.0);", - sizesName, indices[0], radName); - fragBuilder->codeAppendf("float yDist = clamp((%s.%c - abs(delta.y))/%s," - "0.0, 1.0);", - sizesName, indices[1], radName); - fragBuilder->codeAppend("float rectDist = min(xDist, yDist);"); - - fragBuilder->codeAppendf("vec2 cornerCenter = %s.%s - %s.%s;", - sizesName, indices, radiiName, indices); - fragBuilder->codeAppend("delta = vec2(abs(delta.x) - cornerCenter.x," - "abs(delta.y) - cornerCenter.y);"); - fragBuilder->codeAppendf("xDist = %s.%c - abs(delta.x);", radiiName, indices[0]); - fragBuilder->codeAppendf("yDist = %s.%c - abs(delta.y);", radiiName, indices[1]); - fragBuilder->codeAppend("float cornerDist = min(xDist, yDist);"); - fragBuilder->codeAppend("float multiplier = step(0.0, cornerDist);"); - - fragBuilder->codeAppendf("delta += %s.%s;", radiiName, indices); - - fragBuilder->codeAppendf("cornerDist = clamp((2.0 * %s.%c - length(delta))/%s," - "0.0, 1.0);", - radiiName, indices[0], radName); - - fragBuilder->codeAppendf("%s = (multiplier * cornerDist) +" - "((1.0-multiplier) * rectDist);", - outputName); - break; - } - } - - void emitCode(EmitArgs& args) override { - const RRectsGaussianEdgeFP& fp = args.fFp.cast(); - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - - const char* positionsUniName = nullptr; - fPositionsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "Positions", &positionsUniName); - const char* sizesUniName = nullptr; - fSizesUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "Sizes", &sizesUniName); - const char* radiiUniName = nullptr; - if (fp.fFirstMode == kSimpleCircular_Mode || fp.fSecondMode == kSimpleCircular_Mode) { - fRadiiUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "Radii", &radiiUniName); - } - const char* radUniName = nullptr; - fRadiusUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kFloat_GrSLType, kDefault_GrSLPrecision, - "Radius", &radUniName); - - fragBuilder->codeAppend("float firstDist;"); - fragBuilder->codeAppend("{"); - this->emitModeCode(fp.firstMode(), fragBuilder, - positionsUniName, sizesUniName, radiiUniName, - radUniName, "firstDist", "xy"); - fragBuilder->codeAppend("}"); - - fragBuilder->codeAppend("float secondDist;"); - fragBuilder->codeAppend("{"); - this->emitModeCode(fp.secondMode(), fragBuilder, - positionsUniName, sizesUniName, radiiUniName, - radUniName, "secondDist", "zw"); - fragBuilder->codeAppend("}"); - - fragBuilder->codeAppend("vec2 distVec = vec2(1.0 - firstDist, 1.0 - secondDist);"); - - // Finally use the distance to apply the Gaussian edge - fragBuilder->codeAppend("float factor = clamp(length(distVec), 0.0, 1.0);"); - fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;"); - fragBuilder->codeAppendf("%s = factor*%s;", - args.fOutputColor, args.fInputColor); - } - - static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { - const RRectsGaussianEdgeFP& fp = proc.cast(); - - b->add32(fp.firstMode() | (fp.secondMode() << 4)); - } - - protected: - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { - const RRectsGaussianEdgeFP& edgeFP = proc.cast(); - - const SkRRect& first = edgeFP.first(); - const SkRRect& second = edgeFP.second(); - - pdman.set4f(fPositionsUni, - first.getBounds().centerX(), - first.getBounds().centerY(), - second.getBounds().centerX(), - second.getBounds().centerY()); - - pdman.set4f(fSizesUni, - 0.5f * first.rect().width(), - 0.5f * first.rect().height(), - 0.5f * second.rect().width(), - 0.5f * second.rect().height()); - - if (edgeFP.firstMode() == kSimpleCircular_Mode || - edgeFP.secondMode() == kSimpleCircular_Mode) { - // This is a bit of overkill since fX should equal fY for both round rects but it - // makes the shader code simpler. - pdman.set4f(fRadiiUni, - 0.5f * first.getSimpleRadii().fX, - 0.5f * first.getSimpleRadii().fY, - 0.5f * second.getSimpleRadii().fX, - 0.5f * second.getSimpleRadii().fY); - } - - pdman.set1f(fRadiusUni, edgeFP.radius()); - } - - private: - // The centers of the two round rects (x1, y1, x2, y2) - GrGLSLProgramDataManager::UniformHandle fPositionsUni; - - // The half widths and half heights of the two round rects (w1/2, h1/2, w2/2, h2/2) - // For circles we still upload both width & height to simplify things - GrGLSLProgramDataManager::UniformHandle fSizesUni; - - // The half corner radii of the two round rects (rx1/2, ry1/2, rx2/2, ry2/2) - // We upload both the x&y radii (although they are currently always the same) to make - // the indexing in the shader code simpler. In some future world we could also support - // non-circular corner round rects & ellipses. - GrGLSLProgramDataManager::UniformHandle fRadiiUni; - - // The radius parameters (radius) - GrGLSLProgramDataManager::UniformHandle fRadiusUni; - - typedef GrGLSLFragmentProcessor INHERITED; - }; - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { - GLSLRRectsGaussianEdgeFP::GenKey(*this, caps, b); - } - - const char* name() const override { return "RRectsGaussianEdgeFP"; } - - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); - } - - const SkRRect& first() const { return fFirst; } - Mode firstMode() const { return fFirstMode; } - const SkRRect& second() const { return fSecond; } - Mode secondMode() const { return fSecondMode; } - SkScalar radius() const { return fRadius; } - -private: - static Mode ComputeMode(const SkRRect& rr) { - if (rr.isCircle()) { - return kCircle_Mode; - } else if (rr.isRect()) { - return kRect_Mode; - } else { - SkASSERT(rr.isSimpleCircular()); - return kSimpleCircular_Mode; - } - } - - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { - return new GLSLRRectsGaussianEdgeFP; - } - - bool onIsEqual(const GrFragmentProcessor& proc) const override { - const RRectsGaussianEdgeFP& edgeFP = proc.cast(); - return fFirst == edgeFP.fFirst && - fSecond == edgeFP.fSecond && - fRadius == edgeFP.fRadius; - } - - SkRRect fFirst; - Mode fFirstMode; - SkRRect fSecond; - Mode fSecondMode; - SkScalar fRadius; - - typedef GrFragmentProcessor INHERITED; -}; - -//////////////////////////////////////////////////////////////////////////// - -sk_sp SkRRectsGaussianEdgeShaderImpl::asFragmentProcessor( - const AsFPArgs& args) const { - return sk_make_sp(fFirst, fSecond, fRadius); -} - -#endif - -//////////////////////////////////////////////////////////////////////////// - -SkRRectsGaussianEdgeShaderImpl::GaussianEdgeShaderContext::GaussianEdgeShaderContext( - const SkRRectsGaussianEdgeShaderImpl& shader, - const ContextRec& rec) - : INHERITED(shader, rec) { - - fPaintColor = rec.fPaint->getColor(); -} - -void SkRRectsGaussianEdgeShaderImpl::GaussianEdgeShaderContext::shadeSpan(int x, int y, - SkPMColor result[], - int count) { - // TODO: implement - for (int i = 0; i < count; ++i) { - result[i] = fPaintColor; - } -} - -//////////////////////////////////////////////////////////////////////////// - -#ifndef SK_IGNORE_TO_STRING -void SkRRectsGaussianEdgeShaderImpl::toString(SkString* str) const { - str->appendf("RRectsGaussianEdgeShader: ()"); -} -#endif - -sk_sp SkRRectsGaussianEdgeShaderImpl::CreateProc(SkReadBuffer& buf) { - // Discarding SkShader flattenable params - bool hasLocalMatrix = buf.readBool(); - SkAssertResult(!hasLocalMatrix); - - SkRect rect1, rect2; - - buf.readRect(&rect1); - SkScalar xRad1 = buf.readScalar(); - SkScalar yRad1 = buf.readScalar(); - - buf.readRect(&rect2); - SkScalar xRad2 = buf.readScalar(); - SkScalar yRad2 = buf.readScalar(); - - SkScalar radius = buf.readScalar(); - - return sk_make_sp(SkRRect::MakeRectXY(rect1, xRad1, yRad1), - SkRRect::MakeRectXY(rect2, xRad2, yRad2), - radius); -} - -void SkRRectsGaussianEdgeShaderImpl::flatten(SkWriteBuffer& buf) const { - INHERITED::flatten(buf); - - SkASSERT(fFirst.isRect() || fFirst.isCircle() || fFirst.isSimpleCircular()); - buf.writeRect(fFirst.rect()); - const SkVector& radii1 = fFirst.getSimpleRadii(); - buf.writeScalar(radii1.fX); - buf.writeScalar(radii1.fY); - - SkASSERT(fSecond.isRect() || fSecond.isCircle() || fSecond.isSimpleCircular()); - buf.writeRect(fSecond.rect()); - const SkVector& radii2 = fSecond.getSimpleRadii(); - buf.writeScalar(radii2.fX); - buf.writeScalar(radii2.fY); - - buf.writeScalar(fRadius); -} - -size_t SkRRectsGaussianEdgeShaderImpl::onContextSize(const ContextRec& rec) const { - return sizeof(GaussianEdgeShaderContext); -} - -SkShader::Context* SkRRectsGaussianEdgeShaderImpl::onCreateContext(const ContextRec& rec, - void* storage) const { - return new (storage) GaussianEdgeShaderContext(*this, rec); -} - -/////////////////////////////////////////////////////////////////////////////// - -sk_sp SkRRectsGaussianEdgeShader::Make(const SkRRect& first, - const SkRRect& second, - SkScalar radius, SkScalar unused) { - if ((!first.isRect() && !first.isCircle() && !first.isSimpleCircular()) || - (!second.isRect() && !second.isCircle() && !second.isSimpleCircular())) { - // we only deal with the shapes where the x & y radii are equal - // and the same for all four corners - return nullptr; - } - - return sk_make_sp(first, second, radius); -} - -/////////////////////////////////////////////////////////////////////////////// - -SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkRRectsGaussianEdgeShader) -SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRRectsGaussianEdgeShaderImpl) -SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END - -/////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/effects/SkTableColorFilter.cpp b/gfx/skia/skia/src/effects/SkTableColorFilter.cpp index ebf646b99968..0667f51b751e 100644 --- a/gfx/skia/skia/src/effects/SkTableColorFilter.cpp +++ b/gfx/skia/skia/src/effects/SkTableColorFilter.cpp @@ -7,78 +7,15 @@ #include "SkTableColorFilter.h" +#include "SkArenaAlloc.h" #include "SkBitmap.h" #include "SkColorPriv.h" +#include "SkRasterPipeline.h" #include "SkReadBuffer.h" #include "SkString.h" #include "SkUnPreMultiply.h" #include "SkWriteBuffer.h" -class SkTable_ColorFilter : public SkColorFilter { -public: - SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[], - const uint8_t tableG[], const uint8_t tableB[]) { - fBitmap = nullptr; - fFlags = 0; - - uint8_t* dst = fStorage; - if (tableA) { - memcpy(dst, tableA, 256); - dst += 256; - fFlags |= kA_Flag; - } - if (tableR) { - memcpy(dst, tableR, 256); - dst += 256; - fFlags |= kR_Flag; - } - if (tableG) { - memcpy(dst, tableG, 256); - dst += 256; - fFlags |= kG_Flag; - } - if (tableB) { - memcpy(dst, tableB, 256); - fFlags |= kB_Flag; - } - } - - virtual ~SkTable_ColorFilter() { delete fBitmap; } - - bool asComponentTable(SkBitmap* table) const override; - sk_sp makeComposed(sk_sp inner) const override; - -#if SK_SUPPORT_GPU - sk_sp asFragmentProcessor(GrContext*) const override; -#endif - - void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override; - - SK_TO_STRING_OVERRIDE() - - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter) - - enum { - kA_Flag = 1 << 0, - kR_Flag = 1 << 1, - kG_Flag = 1 << 2, - kB_Flag = 1 << 3, - }; - -protected: - void flatten(SkWriteBuffer&) const override; - -private: - mutable const SkBitmap* fBitmap; // lazily allocated - - uint8_t fStorage[256 * 4]; - unsigned fFlags; - - friend class SkTableColorFilter; - - typedef SkColorFilter INHERITED; -}; - static const uint8_t gIdentityTable[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, @@ -114,6 +51,97 @@ static const uint8_t gIdentityTable[] = { 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; +class SkTable_ColorFilter : public SkColorFilter { +public: + SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[], + const uint8_t tableG[], const uint8_t tableB[]) { + fBitmap = nullptr; + fFlags = 0; + + uint8_t* dst = fStorage; + if (tableA) { + memcpy(dst, tableA, 256); + dst += 256; + fFlags |= kA_Flag; + } + if (tableR) { + memcpy(dst, tableR, 256); + dst += 256; + fFlags |= kR_Flag; + } + if (tableG) { + memcpy(dst, tableG, 256); + dst += 256; + fFlags |= kG_Flag; + } + if (tableB) { + memcpy(dst, tableB, 256); + fFlags |= kB_Flag; + } + } + + ~SkTable_ColorFilter() override { delete fBitmap; } + + bool asComponentTable(SkBitmap* table) const override; + sk_sp makeComposed(sk_sp inner) const override; + +#if SK_SUPPORT_GPU + sk_sp asFragmentProcessor(GrContext*, SkColorSpace*) const override; +#endif + + void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override; + + SK_TO_STRING_OVERRIDE() + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter) + + enum { + kA_Flag = 1 << 0, + kR_Flag = 1 << 1, + kG_Flag = 1 << 2, + kB_Flag = 1 << 3, + }; + + bool onAppendStages(SkRasterPipeline* p, SkColorSpace*, SkArenaAlloc* alloc, + bool shaderIsOpaque) const override { + const uint8_t *r = gIdentityTable, + *g = gIdentityTable, + *b = gIdentityTable, + *a = gIdentityTable; + const uint8_t* ptr = fStorage; + if (fFlags & kA_Flag) { a = ptr; ptr += 256; } + if (fFlags & kR_Flag) { r = ptr; ptr += 256; } + if (fFlags & kG_Flag) { g = ptr; ptr += 256; } + if (fFlags & kB_Flag) { b = ptr; } + + if (!shaderIsOpaque) { + p->append(SkRasterPipeline::unpremul); + } + + struct Tables { const uint8_t *r, *g, *b, *a; }; + p->append(SkRasterPipeline::byte_tables, alloc->make(Tables{r,g,b,a})); + + bool definitelyOpaque = shaderIsOpaque && a[0xff] == 0xff; + if (!definitelyOpaque) { + p->append(SkRasterPipeline::premul); + } + return true; + } + +protected: + void flatten(SkWriteBuffer&) const override; + +private: + mutable const SkBitmap* fBitmap; // lazily allocated + + uint8_t fStorage[256 * 4]; + unsigned fFlags; + + friend class SkTableColorFilter; + + typedef SkColorFilter INHERITED; +}; + void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const { const uint8_t* table = fStorage; const uint8_t* tableA = gIdentityTable; @@ -333,7 +361,6 @@ sk_sp SkTable_ColorFilter::makeComposed(sk_sp inne #include "GrContext.h" #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" #include "GrTextureStripAtlas.h" #include "SkGr.h" #include "glsl/GrGLSLFragmentProcessor.h" @@ -343,9 +370,11 @@ sk_sp SkTable_ColorFilter::makeComposed(sk_sp inne class ColorTableEffect : public GrFragmentProcessor { public: - static sk_sp Make(GrContext* context, SkBitmap bitmap, unsigned flags); + static sk_sp Make(GrContext* context, + const SkBitmap& bitmap, + unsigned flags); - virtual ~ColorTableEffect(); + ~ColorTableEffect() override; const char* name() const override { return "ColorTable"; } @@ -355,23 +384,18 @@ public: private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags); + ColorTableEffect(GrResourceProvider* , sk_sp proxy, + GrTextureStripAtlas* atlas, int row, unsigned flags); GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - GrTextureAccess fTextureAccess; - - // currently not used in shader code, just to assist onComputeInvariantOutput(). - unsigned fFlags; - - GrTextureStripAtlas* fAtlas; - int fRow; + TextureSampler fTextureSampler; + GrTextureStripAtlas* fAtlas; + int fRow; typedef GrFragmentProcessor INHERITED; }; @@ -380,17 +404,18 @@ class GLColorTableEffect : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs&) override; - static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) {} + static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {} protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: UniformHandle fRGBAYValuesUni; typedef GrGLSLFragmentProcessor INHERITED; }; -void GLColorTableEffect::onSetData(const GrGLSLProgramDataManager& pdm, const GrProcessor& proc) { +void GLColorTableEffect::onSetData(const GrGLSLProgramDataManager& pdm, + const GrFragmentProcessor& proc) { // The textures are organized in a strip where the rows are ordered a, r, g, b. float rgbaYValues[4]; const ColorTableEffect& cte = proc.cast(); @@ -459,37 +484,46 @@ void GLColorTableEffect::emitCode(EmitArgs& args) { } /////////////////////////////////////////////////////////////////////////////// -sk_sp ColorTableEffect::Make(GrContext* context, SkBitmap bitmap, +sk_sp ColorTableEffect::Make(GrContext* context, const SkBitmap& bitmap, unsigned flags) { GrTextureStripAtlas::Desc desc; desc.fWidth = bitmap.width(); desc.fHeight = 128; desc.fRowHeight = bitmap.height(); + + // TODO: this seems a bit heavy handed (passing a GrContext as part of the desc) desc.fContext = context; desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *context->caps()); GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc); int row = atlas->lockRow(bitmap); - SkAutoTUnref texture; + sk_sp proxy; if (-1 == row) { atlas = nullptr; - texture.reset(GrRefCachedBitmapTexture(context, bitmap, GrTextureParams::ClampNoFilter(), - SkSourceGammaTreatment::kRespect)); + + proxy = GrMakeCachedBitmapProxy(context->resourceProvider(), bitmap); } else { - texture.reset(SkRef(atlas->getTexture())); + proxy = atlas->asTextureProxyRef(); } - return sk_sp(new ColorTableEffect(texture, atlas, row, flags)); + if (!proxy) { + return nullptr; + } + + return sk_sp(new ColorTableEffect(context->resourceProvider(), + std::move(proxy), + atlas, row, flags)); } -ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, - unsigned flags) - : fTextureAccess(texture) - , fFlags(flags) - , fAtlas(atlas) - , fRow(row) { +ColorTableEffect::ColorTableEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, + GrTextureStripAtlas* atlas, int row, unsigned flags) + : INHERITED(kNone_OptimizationFlags) // Not bothering with table-specific optimizations. + , fTextureSampler(resourceProvider, std::move(proxy)) + , fAtlas(atlas) + , fRow(row) { this->initClassID(); - this->addTextureAccess(&fTextureAccess); + this->addTextureSampler(&fTextureSampler); } ColorTableEffect::~ColorTableEffect() { @@ -498,7 +532,7 @@ ColorTableEffect::~ColorTableEffect() { } } -void ColorTableEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void ColorTableEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLColorTableEffect::GenKey(*this, caps, b); } @@ -517,29 +551,11 @@ bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const { return fRow == that.fRow; } -void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - // If we kept the table in the effect then we could actually run known inputs through the - // table. - GrColorComponentFlags invalidateFlags = kNone_GrColorComponentFlags; - if (fFlags & SkTable_ColorFilter::kR_Flag) { - invalidateFlags |= kR_GrColorComponentFlag; - } - if (fFlags & SkTable_ColorFilter::kG_Flag) { - invalidateFlags |= kG_GrColorComponentFlag; - } - if (fFlags & SkTable_ColorFilter::kB_Flag) { - invalidateFlags |= kB_GrColorComponentFlag; - } - if (fFlags & SkTable_ColorFilter::kA_Flag) { - invalidateFlags |= kA_GrColorComponentFlag; - } - inout->invalidateComponents(invalidateFlags, GrInvariantOutput::kWill_ReadInput); -} - /////////////////////////////////////////////////////////////////////////////// GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect); +#if GR_TEST_UTILS sk_sp ColorTableEffect::TestCreate(GrProcessorTestData* d) { int flags = 0; uint8_t luts[256][4]; @@ -561,13 +577,15 @@ sk_sp ColorTableEffect::TestCreate(GrProcessorTestData* d) (flags & (1 << 2)) ? luts[2] : nullptr, (flags & (1 << 3)) ? luts[3] : nullptr )); - - sk_sp fp = filter->asFragmentProcessor(d->fContext); + sk_sp colorSpace = GrTest::TestColorSpace(d->fRandom); + sk_sp fp = filter->asFragmentProcessor(d->context(), colorSpace.get()); SkASSERT(fp); return fp; } +#endif -sk_sp SkTable_ColorFilter::asFragmentProcessor(GrContext* context) const { +sk_sp SkTable_ColorFilter::asFragmentProcessor(GrContext* context, + SkColorSpace*) const { SkBitmap bitmap; this->asComponentTable(&bitmap); diff --git a/gfx/skia/skia/src/effects/SkTileImageFilter.cpp b/gfx/skia/skia/src/effects/SkTileImageFilter.cpp index a140db216b74..262ad6567222 100644 --- a/gfx/skia/skia/src/effects/SkTileImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkTileImageFilter.cpp @@ -73,7 +73,7 @@ sk_sp SkTileImageFilter::onFilterImage(SkSpecialImage* source, // We create an SkImage here b.c. it needs to be a tight fit for the tiling sk_sp subset; if (inputBounds.contains(srcIRect)) { - subset = input->makeTightSubset(srcIRect); + subset = input->asImage(&srcIRect); if (!subset) { return nullptr; } @@ -116,6 +116,16 @@ sk_sp SkTileImageFilter::onFilterImage(SkSpecialImage* source, return surf->makeImageSnapshot(); } +sk_sp SkTileImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { + SkASSERT(1 == this->countInputs()); + if (!this->getInput(0)) { + return sk_ref_sp(const_cast(this)); + } + + sk_sp input = this->getInput(0)->makeColorSpace(xformer); + return SkTileImageFilter::Make(fSrcRect, fDstRect, std::move(input)); +} + SkIRect SkTileImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection direction) const { SkRect rect = kReverse_MapDirection == direction ? fSrcRect : fDstRect; diff --git a/gfx/skia/skia/src/effects/SkXfermodeImageFilter.cpp b/gfx/skia/skia/src/effects/SkXfermodeImageFilter.cpp index b0735168b51a..14cf0c3a422c 100644 --- a/gfx/skia/skia/src/effects/SkXfermodeImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkXfermodeImageFilter.cpp @@ -6,25 +6,26 @@ */ #include "SkXfermodeImageFilter.h" +#include "SkArithmeticImageFilter.h" #include "SkArithmeticModePriv.h" - #include "SkCanvas.h" #include "SkColorPriv.h" #include "SkReadBuffer.h" #include "SkSpecialImage.h" #include "SkSpecialSurface.h" #include "SkWriteBuffer.h" -#include "SkXfermode.h" #if SK_SUPPORT_GPU +#include "GrClip.h" #include "GrContext.h" -#include "GrDrawContext.h" +#include "GrRenderTargetContext.h" +#include "GrTextureProxy.h" + #include "effects/GrConstColorProcessor.h" #include "effects/GrTextureDomain.h" #include "effects/GrSimpleTextureEffect.h" -#include "SkArithmeticMode_gpu.h" #include "SkGr.h" -#include "SkGrPriv.h" #endif +#include "SkClipOpPriv.h" class SkXfermodeImageFilter_Base : public SkImageFilter { public: @@ -37,6 +38,7 @@ public: protected: sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; #if SK_SUPPORT_GPU sk_sp filterImageGPU(SkSpecialImage* source, @@ -50,12 +52,14 @@ protected: void flatten(SkWriteBuffer&) const override; - virtual void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const; + void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const; #if SK_SUPPORT_GPU - virtual sk_sp makeFGFrag(sk_sp bgFP) const; + sk_sp makeFGFrag(sk_sp bgFP) const; #endif private: + static sk_sp LegacyArithmeticCreateProc(SkReadBuffer& buffer); + SkBlendMode fMode; friend class SkXfermodeImageFilter; @@ -73,16 +77,6 @@ sk_sp SkXfermodeImageFilter::Make(SkBlendMode mode, return sk_sp(new SkXfermodeImageFilter_Base(mode, inputs, cropRect)); } -#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT -sk_sp SkXfermodeImageFilter::Make(sk_sp mode, - sk_sp background, - sk_sp foreground, - const SkImageFilter::CropRect* cropRect) { - return Make(mode ? mode->blend() : SkBlendMode::kSrcOver, - std::move(background), std::move(foreground), cropRect); -} -#endif - SkXfermodeImageFilter_Base::SkXfermodeImageFilter_Base(SkBlendMode mode, sk_sp inputs[2], const CropRect* cropRect) @@ -116,10 +110,9 @@ sk_sp SkXfermodeImageFilter_Base::CreateProc(SkReadBuffer& buffer return SkXfermodeImageFilter::Make((SkBlendMode)mode, common.getInput(0), common.getInput(1), &common.cropRect()); } else { - return SkXfermodeImageFilter::MakeArithmetic(arith.fK[0], arith.fK[1], arith.fK[2], - arith.fK[3], arith.fEnforcePMColor, - common.getInput(0), - common.getInput(1), &common.cropRect()); + return SkArithmeticImageFilter::Make(arith.fK[0], arith.fK[1], arith.fK[2], arith.fK[3], + arith.fEnforcePMColor, common.getInput(0), + common.getInput(1), &common.cropRect()); } } @@ -195,6 +188,22 @@ sk_sp SkXfermodeImageFilter_Base::onFilterImage(SkSpecialImage* return surf->makeImageSnapshot(); } +sk_sp SkXfermodeImageFilter_Base::onMakeColorSpace(SkColorSpaceXformer* xformer) +const { + SkASSERT(2 == this->countInputs()); + if (!this->getInput(0) && !this->getInput(1)) { + return sk_ref_sp(const_cast(this)); + } + + sk_sp background = + this->getInput(0) ? this->getInput(0)->makeColorSpace(xformer) : nullptr; + sk_sp foreground = + this->getInput(1) ? this->getInput(1)->makeColorSpace(xformer) : nullptr; + + return SkXfermodeImageFilter::Make(fMode, std::move(background), std::move(foreground), + this->getCropRectIfSet()); +} + void SkXfermodeImageFilter_Base::drawForeground(SkCanvas* canvas, SkSpecialImage* img, const SkIRect& fgBounds) const { SkPaint paint; @@ -204,7 +213,7 @@ void SkXfermodeImageFilter_Base::drawForeground(SkCanvas* canvas, SkSpecialImage } SkAutoCanvasRestore acr(canvas, true); - canvas->clipRect(SkRect::Make(fgBounds), SkCanvas::kDifference_Op); + canvas->clipRect(SkRect::Make(fgBounds), kDifference_SkClipOp); paint.setColor(0); canvas->drawPaint(paint); } @@ -243,49 +252,48 @@ sk_sp SkXfermodeImageFilter_Base::filterImageGPU( GrContext* context = source->getContext(); - sk_sp backgroundTex, foregroundTex; - + sk_sp backgroundProxy, foregroundProxy; + if (background) { - backgroundTex = background->asTextureRef(context); + backgroundProxy = background->asTextureProxyRef(context); } if (foreground) { - foregroundTex = foreground->asTextureRef(context); + foregroundProxy = foreground->asTextureProxyRef(context); } GrPaint paint; sk_sp bgFP; - if (backgroundTex) { - SkMatrix backgroundMatrix; - backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); - backgroundMatrix.preTranslate(-SkIntToScalar(backgroundOffset.fX), - -SkIntToScalar(backgroundOffset.fY)); + if (backgroundProxy) { + SkMatrix bgMatrix = SkMatrix::MakeTrans(-SkIntToScalar(backgroundOffset.fX), + -SkIntToScalar(backgroundOffset.fY)); + sk_sp bgXform = GrColorSpaceXform::Make(background->getColorSpace(), + outputProperties.colorSpace()); bgFP = GrTextureDomainEffect::Make( - backgroundTex.get(), nullptr, backgroundMatrix, - GrTextureDomain::MakeTexelDomain(backgroundTex.get(), - background->subset()), + context->resourceProvider(), std::move(backgroundProxy), + std::move(bgXform), bgMatrix, + GrTextureDomain::MakeTexelDomain(background->subset()), GrTextureDomain::kDecal_Mode, - GrTextureParams::kNone_FilterMode); + GrSamplerParams::kNone_FilterMode); } else { - bgFP = GrConstColorProcessor::Make(GrColor_TRANSPARENT_BLACK, - GrConstColorProcessor::kIgnore_InputMode); + bgFP = GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), + GrConstColorProcessor::kIgnore_InputMode); } - if (foregroundTex) { - SkMatrix foregroundMatrix; - foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); - foregroundMatrix.preTranslate(-SkIntToScalar(foregroundOffset.fX), - -SkIntToScalar(foregroundOffset.fY)); - + if (foregroundProxy) { + SkMatrix fgMatrix = SkMatrix::MakeTrans(-SkIntToScalar(foregroundOffset.fX), + -SkIntToScalar(foregroundOffset.fY)); + sk_sp fgXform = GrColorSpaceXform::Make(foreground->getColorSpace(), + outputProperties.colorSpace()); sk_sp foregroundFP; foregroundFP = GrTextureDomainEffect::Make( - foregroundTex.get(), nullptr, foregroundMatrix, - GrTextureDomain::MakeTexelDomain(foregroundTex.get(), - foreground->subset()), + context->resourceProvider(), std::move(foregroundProxy), + std::move(fgXform), fgMatrix, + GrTextureDomain::MakeTexelDomain(foreground->subset()), GrTextureDomain::kDecal_Mode, - GrTextureParams::kNone_FilterMode); + GrSamplerParams::kNone_FilterMode); paint.addColorFragmentProcessor(std::move(foregroundFP)); @@ -301,23 +309,25 @@ sk_sp SkXfermodeImageFilter_Base::filterImageGPU( paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - sk_sp drawContext( - context->makeDrawContext(SkBackingFit::kApprox, bounds.width(), bounds.height(), - GrRenderableConfigForColorSpace(outputProperties.colorSpace()), - sk_ref_sp(outputProperties.colorSpace()))); - if (!drawContext) { + sk_sp renderTargetContext(context->makeDeferredRenderTargetContext( + SkBackingFit::kApprox, bounds.width(), bounds.height(), + GrRenderableConfigForColorSpace(outputProperties.colorSpace()), + sk_ref_sp(outputProperties.colorSpace()))); + if (!renderTargetContext) { return nullptr; } - paint.setGammaCorrect(drawContext->isGammaCorrect()); + paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); - drawContext->drawRect(GrNoClip(), paint, matrix, SkRect::Make(bounds)); + renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, + SkRect::Make(bounds)); - return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(bounds.width(), bounds.height()), - kNeedNewImageUniqueID_SpecialImage, - drawContext->asTexture(), - sk_ref_sp(drawContext->getColorSpace())); + return SkSpecialImage::MakeDeferredFromGpu(context, + SkIRect::MakeWH(bounds.width(), bounds.height()), + kNeedNewImageUniqueID_SpecialImage, + renderTargetContext->asTextureProxyRef(), + renderTargetContext->refColorSpace()); } sk_sp @@ -330,10 +340,10 @@ SkXfermodeImageFilter_Base::makeFGFrag(sk_sp bgFP) const { // than us and won't return a kSrcOver_Mode SkXfermode. That means we // have to get one the hard way. struct ProcCoeff rec; - rec.fProc = SkXfermode::GetProc(SkXfermode::kSrcOver_Mode); - SkXfermode::ModeAsCoeff(SkXfermode::kSrcOver_Mode, &rec.fSC, &rec.fDC); + rec.fProc = SkXfermode::GetProc(SkBlendMode::kSrcOver); + SkXfermode::ModeAsCoeff(SkBlendMode::kSrcOver, &rec.fSC, &rec.fDC); - srcover.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode)); + srcover.reset(new SkProcCoeffXfermode(rec, SkBlendMode::kSrcOver)); xfer = srcover.get(); } @@ -341,196 +351,23 @@ SkXfermodeImageFilter_Base::makeFGFrag(sk_sp bgFP) const { } #endif - /////////////////////////////////////////////////////////////////////////////////////////////////// -class SkArithmeticImageFilter : public SkXfermodeImageFilter_Base { -public: - SkArithmeticImageFilter(float k1, float k2, float k3, float k4, bool enforcePMColor, - sk_sp inputs[2], const CropRect* cropRect) - // need to pass a blendmode to our inherited constructor, but we ignore it - : SkXfermodeImageFilter_Base(SkBlendMode::kSrcOver, inputs, cropRect) - , fK{ k1, k2, k3, k4 } - , fEnforcePMColor(enforcePMColor) - {} - - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticImageFilter) - -protected: - void flatten(SkWriteBuffer& buffer) const override { - this->INHERITED::flatten(buffer); - for (int i = 0; i < 4; ++i) { - buffer.writeScalar(fK[i]); - } - buffer.writeBool(fEnforcePMColor); - } - void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const override; -#if SK_SUPPORT_GPU - sk_sp makeFGFrag(sk_sp bgFP) const override { - return GrArithmeticFP::Make(fK[0], fK[1], fK[2], fK[3], fEnforcePMColor, std::move(bgFP)); - } -#endif - -private: - const float fK[4]; - const bool fEnforcePMColor; - - friend class SkXfermodeImageFilter; - - typedef SkXfermodeImageFilter_Base INHERITED; -}; - -sk_sp SkArithmeticImageFilter::CreateProc(SkReadBuffer& buffer) { +sk_sp SkXfermodeImageFilter_Base::LegacyArithmeticCreateProc(SkReadBuffer& buffer) { SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2); - - // skip the mode (srcover) our parent-class wrote + // skip the unused mode (srcover) field SkDEBUGCODE(int mode =) unflatten_blendmode(buffer, nullptr); if (!buffer.isValid()) { return nullptr; } SkASSERT(SkBlendMode::kSrcOver == (SkBlendMode)mode); - float k[4]; for (int i = 0; i < 4; ++i) { k[i] = buffer.readScalar(); } const bool enforcePMColor = buffer.readBool(); - return SkXfermodeImageFilter::MakeArithmetic(k[0], k[1], k[2], k[3], enforcePMColor, - common.getInput(0), common.getInput(1), - &common.cropRect()); -} - -#include "SkNx.h" - -static Sk4f pin(float min, const Sk4f& val, float max) { - return Sk4f::Max(min, Sk4f::Min(val, max)); -} - -template void arith_span(const float k[], SkPMColor dst[], - const SkPMColor src[], int count) { - const Sk4f k1 = k[0] * (1/255.0f), - k2 = k[1], - k3 = k[2], - k4 = k[3] * 255.0f + 0.5f; - - for (int i = 0; i < count; i++) { - Sk4f s = SkNx_cast(Sk4b::Load(src+i)), - d = SkNx_cast(Sk4b::Load(dst+i)), - r = pin(0, k1*s*d + k2*s + k3*d + k4, 255); - if (EnforcePMColor) { - Sk4f a = SkNx_shuffle<3,3,3,3>(r); - r = Sk4f::Min(a, r); - } - SkNx_cast(r).store(dst+i); - } -} - -// apply mode to src==transparent (0) -template void arith_transparent(const float k[], SkPMColor dst[], int count) { - const Sk4f k3 = k[2], - k4 = k[3] * 255.0f + 0.5f; - - for (int i = 0; i < count; i++) { - Sk4f d = SkNx_cast(Sk4b::Load(dst+i)), - r = pin(0, k3*d + k4, 255); - if (EnforcePMColor) { - Sk4f a = SkNx_shuffle<3,3,3,3>(r); - r = Sk4f::Min(a, r); - } - SkNx_cast(r).store(dst+i); - } -} - -static bool intersect(SkPixmap* dst, SkPixmap* src, int srcDx, int srcDy) { - SkIRect dstR = SkIRect::MakeWH(dst->width(), dst->height()); - SkIRect srcR = SkIRect::MakeXYWH(srcDx, srcDy, src->width(), src->height()); - SkIRect sect; - if (!sect.intersect(dstR, srcR)) { - return false; - } - *dst = SkPixmap(dst->info().makeWH(sect.width(), sect.height()), - dst->addr(sect.fLeft, sect.fTop), - dst->rowBytes()); - *src = SkPixmap(src->info().makeWH(sect.width(), sect.height()), - src->addr(SkTMax(0, -srcDx), SkTMax(0, -srcDy)), - src->rowBytes()); - return true; -} - -void SkArithmeticImageFilter::drawForeground(SkCanvas* canvas, SkSpecialImage* img, - const SkIRect& fgBounds) const { - SkPixmap dst; - if (!canvas->peekPixels(&dst)) { - return; - } - - const SkMatrix& ctm = canvas->getTotalMatrix(); - SkASSERT(ctm.getType() <= SkMatrix::kTranslate_Mask); - const int dx = SkScalarRoundToInt(ctm.getTranslateX()); - const int dy = SkScalarRoundToInt(ctm.getTranslateY()); - - if (img) { - SkBitmap srcBM; - SkPixmap src; - if (!img->getROPixels(&srcBM)) { - return; - } - srcBM.lockPixels(); - if (!srcBM.peekPixels(&src)) { - return; - } - - auto proc = fEnforcePMColor ? arith_span : arith_span; - SkPixmap tmpDst = dst; - if (intersect(&tmpDst, &src, fgBounds.fLeft + dx, fgBounds.fTop + dy)) { - for (int y = 0; y < tmpDst.height(); ++y) { - proc(fK, tmpDst.writable_addr32(0, y), src.addr32(0, y), tmpDst.width()); - } - } - } - - // Now apply the mode with transparent-color to the outside of the fg image - SkRegion outside(SkIRect::MakeWH(dst.width(), dst.height())); - outside.op(fgBounds.makeOffset(dx, dy), SkRegion::kDifference_Op); - auto proc = fEnforcePMColor ? arith_transparent : arith_transparent; - for (SkRegion::Iterator iter(outside); !iter.done(); iter.next()) { - const SkIRect r = iter.rect(); - for (int y = r.fTop; y < r.fBottom; ++y) { - proc(fK, dst.writable_addr32(r.fLeft, y), r.width()); - } - } -} - -sk_sp SkXfermodeImageFilter::MakeArithmetic(float k1, float k2, float k3, float k4, - bool enforcePMColor, - sk_sp background, - sk_sp foreground, - const SkImageFilter::CropRect* crop) { - if (!SkScalarIsFinite(k1) || !SkScalarIsFinite(k2) || - !SkScalarIsFinite(k3) || !SkScalarIsFinite(k4)) { - return nullptr; - } - - // are we nearly some other "std" mode? - int mode = -1; // illegal mode - if (SkScalarNearlyZero(k1) && SkScalarNearlyEqual(k2, SK_Scalar1) && - SkScalarNearlyZero(k3) && SkScalarNearlyZero(k4)) { - mode = (int)SkBlendMode::kSrc; - } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) && - SkScalarNearlyEqual(k3, SK_Scalar1) && SkScalarNearlyZero(k4)) { - mode = (int)SkBlendMode::kDst; - } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) && - SkScalarNearlyZero(k3) && SkScalarNearlyZero(k4)) { - mode = (int)SkBlendMode::kClear; - } - if (mode >= 0) { - return SkXfermodeImageFilter::Make((SkBlendMode)mode, - std::move(background), std::move(foreground), crop); - } - - sk_sp inputs[2] = { std::move(background), std::move(foreground) }; - return sk_sp(new SkArithmeticImageFilter(k1, k2, k3, k4, enforcePMColor, - inputs, crop)); + return SkArithmeticImageFilter::Make(k[0], k[1], k[2], k[3], enforcePMColor, common.getInput(0), + common.getInput(1), &common.cropRect()); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -540,5 +377,9 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermodeImageFilter) // manually register the legacy serialized name "SkXfermodeImageFilter" SkFlattenable::Register("SkXfermodeImageFilter", SkXfermodeImageFilter_Base::CreateProc, SkFlattenable::kSkImageFilter_Type); - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticImageFilter) + // manually register the legacy serialized name "SkArithmeticImageFilter" from when that filter + // was implemented as a xfermode image filter. + SkFlattenable::Register("SkArithmeticImageFilter", + SkXfermodeImageFilter_Base::LegacyArithmeticCreateProc, + SkFlattenable::kSkImageFilter_Type); SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END diff --git a/gfx/skia/skia/src/effects/gradients/Sk4fGradientBase.cpp b/gfx/skia/skia/src/effects/gradients/Sk4fGradientBase.cpp index fa9364a606da..81442df0489d 100644 --- a/gfx/skia/skia/src/effects/gradients/Sk4fGradientBase.cpp +++ b/gfx/skia/skia/src/effects/gradients/Sk4fGradientBase.cpp @@ -20,28 +20,6 @@ Sk4f pack_color(SkColor c, bool premul, const Sk4f& component_scale) { return pm4f * component_scale; } -template -SkScalar tileProc(SkScalar t); - -template<> -SkScalar tileProc(SkScalar t) { - // synthetic clamp-mode edge intervals allow for a free-floating t: - // [-inf..0)[0..1)[1..+inf) - return t; -} - -template<> -SkScalar tileProc(SkScalar t) { - // t % 1 (intervals range: [0..1)) - return t - SkScalarFloorToScalar(t); -} - -template<> -SkScalar tileProc(SkScalar t) { - // t % 2 (synthetic mirror intervals expand the range to [0..2) - return t - SkScalarFloorToScalar(t / 2) * 2; -} - class IntervalIterator { public: IntervalIterator(const SkColor* colors, const SkScalar* pos, int count, bool reverse) @@ -117,62 +95,52 @@ private: const int fAdvance; }; +void addMirrorIntervals(const SkColor colors[], + const SkScalar pos[], int count, + const Sk4f& componentScale, + bool premulColors, bool reverse, + Sk4fGradientIntervalBuffer::BufferType* buffer) { + const IntervalIterator iter(colors, pos, count, reverse); + iter.iterate([&] (SkColor c0, SkColor c1, SkScalar t0, SkScalar t1) { + SkASSERT(buffer->empty() || buffer->back().fT1 == 2 - t0); + + const auto mirror_t0 = 2 - t0; + const auto mirror_t1 = 2 - t1; + // mirror_p1 & mirror_p1 may collapse for very small values - recheck to avoid + // triggering Interval asserts. + if (mirror_t0 != mirror_t1) { + buffer->emplace_back(pack_color(c0, premulColors, componentScale), mirror_t0, + pack_color(c1, premulColors, componentScale), mirror_t1); + } + }); +} + } // anonymous namespace -SkGradientShaderBase::GradientShaderBase4fContext:: -Interval::Interval(const Sk4f& c0, SkScalar p0, - const Sk4f& c1, SkScalar p1) - : fP0(p0) - , fP1(p1) +Sk4fGradientInterval::Sk4fGradientInterval(const Sk4f& c0, SkScalar t0, + const Sk4f& c1, SkScalar t1) + : fT0(t0) + , fT1(t1) , fZeroRamp((c0 == c1).allTrue()) { - - SkASSERT(p0 != p1); + SkASSERT(t0 != t1); // Either p0 or p1 can be (-)inf for synthetic clamp edge intervals. - SkASSERT(SkScalarIsFinite(p0) || SkScalarIsFinite(p1)); + SkASSERT(SkScalarIsFinite(t0) || SkScalarIsFinite(t1)); - const auto dp = p1 - p0; + const auto dt = t1 - t0; // Clamp edge intervals are always zero-ramp. - SkASSERT(SkScalarIsFinite(dp) || fZeroRamp); - const Sk4f dc = SkScalarIsFinite(dp) ? (c1 - c0) / dp : 0; + SkASSERT(SkScalarIsFinite(dt) || fZeroRamp); + SkASSERT(SkScalarIsFinite(t0) || fZeroRamp); + const Sk4f dc = SkScalarIsFinite(dt) ? (c1 - c0) / dt : 0; + const Sk4f bias = c0 - (SkScalarIsFinite(t0) ? t0 * dc : 0); - c0.store(&fC0.fVec); - dc.store(&fDc.fVec); + bias.store(&fCb.fVec); + dc.store(&fCg.fVec); } -SkGradientShaderBase:: -GradientShaderBase4fContext::GradientShaderBase4fContext(const SkGradientShaderBase& shader, - const ContextRec& rec) - : INHERITED(shader, rec) - , fFlags(this->INHERITED::getFlags()) -#ifdef SK_SUPPORT_LEGACY_GRADIENT_DITHERING - , fDither(true) -#else - , fDither(rec.fPaint->isDither()) -#endif -{ - const SkMatrix& inverse = this->getTotalInverse(); - fDstToPos.setConcat(shader.fPtsToUnit, inverse); - fDstToPosProc = fDstToPos.getMapXYProc(); - fDstToPosClass = static_cast(INHERITED::ComputeMatrixClass(fDstToPos)); - - if (shader.fColorsAreOpaque && this->getPaintAlpha() == SK_AlphaOPAQUE) { - fFlags |= kOpaqueAlpha_Flag; - } - - fColorsArePremul = - (shader.fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag) - || shader.fColorsAreOpaque; -} - -bool SkGradientShaderBase:: -GradientShaderBase4fContext::isValid() const { - return fDstToPos.isFinite(); -} - -void SkGradientShaderBase:: -GradientShaderBase4fContext::buildIntervals(const SkGradientShaderBase& shader, - const ContextRec& rec, bool reverse) { +void Sk4fGradientIntervalBuffer::init(const SkColor colors[], const SkScalar pos[], int count, + SkShader::TileMode tileMode, bool premulColors, + SkScalar alpha, bool reverse) { // The main job here is to build a specialized interval list: a different // representation of the color stops data, optimized for efficient scan line // access during shading. @@ -214,71 +182,131 @@ GradientShaderBase4fContext::buildIntervals(const SkGradientShaderBase& shader, // // TODO: investigate collapsing intervals << 1px. - SkASSERT(shader.fColorCount > 0); - SkASSERT(shader.fOrigColors); + SkASSERT(count > 0); + SkASSERT(colors); - const float paintAlpha = rec.fPaint->getAlpha() * (1.0f / 255); - const Sk4f componentScale = fColorsArePremul - ? Sk4f(paintAlpha) - : Sk4f(1.0f, 1.0f, 1.0f, paintAlpha); - const int first_index = reverse ? shader.fColorCount - 1 : 0; - const int last_index = shader.fColorCount - 1 - first_index; + fIntervals.reset(); + + const Sk4f componentScale = premulColors + ? Sk4f(alpha) + : Sk4f(1.0f, 1.0f, 1.0f, alpha); + const int first_index = reverse ? count - 1 : 0; + const int last_index = count - 1 - first_index; const SkScalar first_pos = reverse ? SK_Scalar1 : 0; const SkScalar last_pos = SK_Scalar1 - first_pos; - if (shader.fTileMode == SkShader::kClamp_TileMode) { + if (tileMode == SkShader::kClamp_TileMode) { // synthetic edge interval: -/+inf .. P0 - const Sk4f clamp_color = pack_color(shader.fOrigColors[first_index], - fColorsArePremul, componentScale); + const Sk4f clamp_color = pack_color(colors[first_index], + premulColors, componentScale); const SkScalar clamp_pos = reverse ? SK_ScalarInfinity : SK_ScalarNegativeInfinity; fIntervals.emplace_back(clamp_color, clamp_pos, clamp_color, first_pos); - } else if (shader.fTileMode == SkShader::kMirror_TileMode && reverse) { + } else if (tileMode == SkShader::kMirror_TileMode && reverse) { // synthetic mirror intervals injected before main intervals: (2 .. 1] - addMirrorIntervals(shader, componentScale, false); + addMirrorIntervals(colors, pos, count, componentScale, premulColors, false, &fIntervals); } - const IntervalIterator iter(shader.fOrigColors, - shader.fOrigPos, - shader.fColorCount, - reverse); - iter.iterate([this, &componentScale] (SkColor c0, SkColor c1, SkScalar p0, SkScalar p1) { - SkASSERT(fIntervals.empty() || fIntervals.back().fP1 == p0); + const IntervalIterator iter(colors, pos, count, reverse); + iter.iterate([&] (SkColor c0, SkColor c1, SkScalar t0, SkScalar t1) { + SkASSERT(fIntervals.empty() || fIntervals.back().fT1 == t0); - fIntervals.emplace_back(pack_color(c0, fColorsArePremul, componentScale), - p0, - pack_color(c1, fColorsArePremul, componentScale), - p1); + fIntervals.emplace_back(pack_color(c0, premulColors, componentScale), t0, + pack_color(c1, premulColors, componentScale), t1); }); - if (shader.fTileMode == SkShader::kClamp_TileMode) { + if (tileMode == SkShader::kClamp_TileMode) { // synthetic edge interval: Pn .. +/-inf - const Sk4f clamp_color = pack_color(shader.fOrigColors[last_index], - fColorsArePremul, componentScale); + const Sk4f clamp_color = pack_color(colors[last_index], premulColors, componentScale); const SkScalar clamp_pos = reverse ? SK_ScalarNegativeInfinity : SK_ScalarInfinity; fIntervals.emplace_back(clamp_color, last_pos, clamp_color, clamp_pos); - } else if (shader.fTileMode == SkShader::kMirror_TileMode && !reverse) { + } else if (tileMode == SkShader::kMirror_TileMode && !reverse) { // synthetic mirror intervals injected after main intervals: [1 .. 2) - addMirrorIntervals(shader, componentScale, true); + addMirrorIntervals(colors, pos, count, componentScale, premulColors, true, &fIntervals); } } -void SkGradientShaderBase:: -GradientShaderBase4fContext::addMirrorIntervals(const SkGradientShaderBase& shader, - const Sk4f& componentScale, bool reverse) { - const IntervalIterator iter(shader.fOrigColors, - shader.fOrigPos, - shader.fColorCount, - reverse); - iter.iterate([this, &componentScale] (SkColor c0, SkColor c1, SkScalar p0, SkScalar p1) { - SkASSERT(fIntervals.empty() || fIntervals.back().fP1 == 2 - p0); +const Sk4fGradientInterval* Sk4fGradientIntervalBuffer::find(SkScalar t) const { + // Binary search. + const auto* i0 = fIntervals.begin(); + const auto* i1 = fIntervals.end() - 1; - fIntervals.emplace_back(pack_color(c0, fColorsArePremul, componentScale), - 2 - p0, - pack_color(c1, fColorsArePremul, componentScale), - 2 - p1); - }); + while (i0 != i1) { + SkASSERT(i0 < i1); + SkASSERT(t >= i0->fT0 && t <= i1->fT1); + + const auto* i = i0 + ((i1 - i0) >> 1); + + if (t > i->fT1) { + i0 = i + 1; + } else { + i1 = i; + } + } + + SkASSERT(i0->contains(t)); + return i0; +} + +const Sk4fGradientInterval* Sk4fGradientIntervalBuffer::findNext( + SkScalar t, const Sk4fGradientInterval* prev, bool increasing) const { + + SkASSERT(!prev->contains(t)); + SkASSERT(prev >= fIntervals.begin() && prev < fIntervals.end()); + SkASSERT(t >= fIntervals.front().fT0 && t <= fIntervals.back().fT1); + + const auto* i = prev; + + // Use the |increasing| signal to figure which direction we should search for + // the next interval, then perform a linear search. + if (increasing) { + do { + i += 1; + if (i >= fIntervals.end()) { + i = fIntervals.begin(); + } + } while (!i->contains(t)); + } else { + do { + i -= 1; + if (i < fIntervals.begin()) { + i = fIntervals.end() - 1; + } + } while (!i->contains(t)); + } + + return i; +} + +SkGradientShaderBase:: +GradientShaderBase4fContext::GradientShaderBase4fContext(const SkGradientShaderBase& shader, + const ContextRec& rec) + : INHERITED(shader, rec) + , fFlags(this->INHERITED::getFlags()) +#ifdef SK_SUPPORT_LEGACY_GRADIENT_DITHERING + , fDither(true) +#else + , fDither(rec.fPaint->isDither()) +#endif +{ + const SkMatrix& inverse = this->getTotalInverse(); + fDstToPos.setConcat(shader.fPtsToUnit, inverse); + fDstToPosProc = fDstToPos.getMapXYProc(); + fDstToPosClass = static_cast(INHERITED::ComputeMatrixClass(fDstToPos)); + + if (shader.fColorsAreOpaque && this->getPaintAlpha() == SK_AlphaOPAQUE) { + fFlags |= kOpaqueAlpha_Flag; + } + + fColorsArePremul = + (shader.fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag) + || shader.fColorsAreOpaque; +} + +bool SkGradientShaderBase:: +GradientShaderBase4fContext::isValid() const { + return fDstToPos.isFinite(); } void SkGradientShaderBase:: @@ -333,7 +361,7 @@ GradientShaderBase4fContext::shadeSpanInternal(int x, int y, int count) const { static const int kBufSize = 128; SkScalar ts[kBufSize]; - TSampler sampler(*this); + TSampler sampler(*this); SkASSERT(count > 0); do { @@ -348,26 +376,35 @@ GradientShaderBase4fContext::shadeSpanInternal(int x, int y, } while (count > 0); } -template +template class SkGradientShaderBase::GradientShaderBase4fContext::TSampler { public: TSampler(const GradientShaderBase4fContext& ctx) - : fFirstInterval(ctx.fIntervals.begin()) - , fLastInterval(ctx.fIntervals.end() - 1) + : fCtx(ctx) , fInterval(nullptr) { - SkASSERT(fLastInterval >= fFirstInterval); + switch (tileMode) { + case kClamp_TileMode: + fLargestIntervalValue = SK_ScalarInfinity; + break; + case kRepeat_TileMode: + fLargestIntervalValue = nextafterf(1, 0); + break; + case kMirror_TileMode: + fLargestIntervalValue = nextafterf(2.0f, 0); + break; + } } Sk4f sample(SkScalar t) { - const SkScalar tiled_t = tileProc(t); + const auto tiled_t = tileProc(t); if (!fInterval) { // Very first sample => locate the initial interval. // TODO: maybe do this in ctor to remove a branch? - fInterval = this->findFirstInterval(tiled_t); + fInterval = fCtx.fIntervals.find(tiled_t); this->loadIntervalData(fInterval); - } else if (tiled_t < fInterval->fP0 || tiled_t >= fInterval->fP1) { - fInterval = this->findNextInterval(t, tiled_t); + } else if (!fInterval->contains(tiled_t)) { + fInterval = fCtx.fIntervals.findNext(tiled_t, fInterval, t >= fPrevT); this->loadIntervalData(fInterval); } @@ -376,69 +413,40 @@ public: } private: + SkScalar tileProc(SkScalar t) const { + switch (tileMode) { + case kClamp_TileMode: + // synthetic clamp-mode edge intervals allow for a free-floating t: + // [-inf..0)[0..1)[1..+inf) + return t; + case kRepeat_TileMode: + // t % 1 (intervals range: [0..1)) + // Due to the extra arithmetic, we must clamp to ensure the value remains less than 1. + return SkTMin(t - SkScalarFloorToScalar(t), fLargestIntervalValue); + case kMirror_TileMode: + // t % 2 (synthetic mirror intervals expand the range to [0..2) + // Due to the extra arithmetic, we must clamp to ensure the value remains less than 2. + return SkTMin(t - SkScalarFloorToScalar(t / 2) * 2, fLargestIntervalValue); + } + + SK_ABORT("Unhandled tile mode."); + return 0; + } + Sk4f lerp(SkScalar t) { - SkASSERT(t >= fInterval->fP0 && t < fInterval->fP1); - return fCc + fDc * (t - fInterval->fP0); + SkASSERT(fInterval->contains(t)); + return fCb + fCg * t; } - const Interval* findFirstInterval(SkScalar t) const { - // Binary search. - const Interval* i0 = fFirstInterval; - const Interval* i1 = fLastInterval; - - while (i0 != i1) { - SkASSERT(i0 < i1); - SkASSERT(t >= i0->fP0 && t < i1->fP1); - - const Interval* i = i0 + ((i1 - i0) >> 1); - - if (t >= i->fP1) { - i0 = i + 1; - } else { - i1 = i; - } - } - - SkASSERT(t >= i0->fP0 && t <= i0->fP1); - return i0; + void loadIntervalData(const Sk4fGradientInterval* i) { + fCb = DstTraits::load(i->fCb); + fCg = DstTraits::load(i->fCg); } - const Interval* findNextInterval(SkScalar t, SkScalar tiled_t) const { - SkASSERT(tiled_t < fInterval->fP0 || tiled_t >= fInterval->fP1); - SkASSERT(tiled_t >= fFirstInterval->fP0 && tiled_t < fLastInterval->fP1); - - const Interval* i = fInterval; - - // Use the t vs. prev_t signal to figure which direction we should search for - // the next interval, then perform a linear search. - if (t >= fPrevT) { - do { - i += 1; - if (i > fLastInterval) { - i = fFirstInterval; - } - } while (tiled_t < i->fP0 || tiled_t >= i->fP1); - } else { - do { - i -= 1; - if (i < fFirstInterval) { - i = fLastInterval; - } - } while (tiled_t < i->fP0 || tiled_t >= i->fP1); - } - - return i; - } - - void loadIntervalData(const Interval* i) { - fCc = DstTraits::load(i->fC0); - fDc = DstTraits::load(i->fDc); - } - - const Interval* fFirstInterval; - const Interval* fLastInterval; - const Interval* fInterval; - SkScalar fPrevT; - Sk4f fCc; - Sk4f fDc; + const GradientShaderBase4fContext& fCtx; + const Sk4fGradientInterval* fInterval; + SkScalar fPrevT; + SkScalar fLargestIntervalValue; + Sk4f fCb; + Sk4f fCg; }; diff --git a/gfx/skia/skia/src/effects/gradients/Sk4fGradientBase.h b/gfx/skia/skia/src/effects/gradients/Sk4fGradientBase.h index fd6d6563a724..fcdcd9e8c771 100644 --- a/gfx/skia/skia/src/effects/gradients/Sk4fGradientBase.h +++ b/gfx/skia/skia/src/effects/gradients/Sk4fGradientBase.h @@ -17,6 +17,42 @@ #include "SkShader.h" #include "SkTArray.h" +struct Sk4fGradientInterval { + Sk4fGradientInterval(const Sk4f& c0, SkScalar t0, + const Sk4f& c1, SkScalar t1); + + bool contains(SkScalar t) const { + // True if t is in [p0,p1]. Note: this helper assumes a + // natural/increasing interval - so it's not usable in Sk4fLinearGradient. + SkASSERT(fT0 < fT1); + return t >= fT0 && t <= fT1; + } + + // Color bias and color gradient, such that for a t in this interval + // + // C = fCb + t * fCg; + SkPM4f fCb, fCg; + SkScalar fT0, fT1; + bool fZeroRamp; +}; + +class Sk4fGradientIntervalBuffer { +public: + void init(const SkColor colors[], const SkScalar pos[], int count, + SkShader::TileMode tileMode, bool premulColors, SkScalar alpha, bool reverse); + + const Sk4fGradientInterval* find(SkScalar t) const; + const Sk4fGradientInterval* findNext(SkScalar t, const Sk4fGradientInterval* prev, + bool increasing) const; + + using BufferType = SkSTArray<8, Sk4fGradientInterval, true>; + + const BufferType* operator->() const { return &fIntervals; } + +private: + BufferType fIntervals; +}; + class SkGradientShaderBase:: GradientShaderBase4fContext : public SkShader::Context { public: @@ -31,28 +67,15 @@ public: bool isValid() const; protected: - struct Interval { - Interval(const Sk4f& c0, SkScalar p0, - const Sk4f& c1, SkScalar p1); - - bool isZeroRamp() const { return fZeroRamp; } - - SkPM4f fC0, fDc; - SkScalar fP0, fP1; - bool fZeroRamp; - }; - virtual void mapTs(int x, int y, SkScalar ts[], int count) const = 0; - void buildIntervals(const SkGradientShaderBase&, const ContextRec&, bool reverse); - - SkSTArray<8, Interval, true> fIntervals; - SkMatrix fDstToPos; - SkMatrix::MapXYProc fDstToPosProc; - uint8_t fDstToPosClass; - uint8_t fFlags; - bool fDither; - bool fColorsArePremul; + Sk4fGradientIntervalBuffer fIntervals; + SkMatrix fDstToPos; + SkMatrix::MapXYProc fDstToPosProc; + uint8_t fDstToPosClass; + uint8_t fFlags; + bool fDither; + bool fColorsArePremul; private: using INHERITED = SkShader::Context; @@ -60,7 +83,7 @@ private: void addMirrorIntervals(const SkGradientShaderBase&, const Sk4f& componentScale, bool reverse); - template + template class TSampler; template diff --git a/gfx/skia/skia/src/effects/gradients/Sk4fGradientPriv.h b/gfx/skia/skia/src/effects/gradients/Sk4fGradientPriv.h index 65fa821e85c8..b8f4bcaee169 100644 --- a/gfx/skia/skia/src/effects/gradients/Sk4fGradientPriv.h +++ b/gfx/skia/skia/src/effects/gradients/Sk4fGradientPriv.h @@ -29,17 +29,6 @@ enum class DstType { F32, // Linear float. Used for shaders only. }; -template -inline SkPMColor trunc_from_4f_255(const Sk4f& c) { - SkPMColor pmc; - SkNx_cast(c).store(&pmc); - if (premul == ApplyPremul::True) { - pmc = SkPreMultiplyARGB(SkGetPackedA32(pmc), SkGetPackedR32(pmc), - SkGetPackedG32(pmc), SkGetPackedB32(pmc)); - } - return pmc; -} - template struct PremulTraits; @@ -69,24 +58,34 @@ struct PremulTraits { // // - store4x() Store 4 Sk4f values to dest (opportunistic optimization). // -template +template struct DstTraits; template struct DstTraits { + using PM = PremulTraits; using Type = SkPMColor; - // For L32, we prescale the values by 255 to save a per-pixel multiplication. + // For L32, prescaling by 255 saves a per-pixel multiplication when premul is not needed. static Sk4f load(const SkPM4f& c) { - return c.to4f_pmorder() * Sk4f(255); + return premul == ApplyPremul::False + ? c.to4f_pmorder() * Sk4f(255) + : c.to4f_pmorder(); } static void store(const Sk4f& c, Type* dst) { - *dst = trunc_from_4f_255(c); + if (premul == ApplyPremul::False) { + // c is prescaled by 255, just store. + SkNx_cast(c).store(dst); + } else { + *dst = Sk4f_toL32(PM::apply(c)); + } } static void store(const Sk4f& c, Type* dst, int n) { - sk_memset32(dst, trunc_from_4f_255(c), n); + Type pmc; + store(c, &pmc); + sk_memset32(dst, pmc, n); } static void store4x(const Sk4f& c0, const Sk4f& c1, diff --git a/gfx/skia/skia/src/effects/gradients/Sk4fLinearGradient.cpp b/gfx/skia/skia/src/effects/gradients/Sk4fLinearGradient.cpp index f9618dd1b5ec..fe900e8d03e9 100644 --- a/gfx/skia/skia/src/effects/gradients/Sk4fLinearGradient.cpp +++ b/gfx/skia/skia/src/effects/gradients/Sk4fLinearGradient.cpp @@ -7,7 +7,8 @@ #include "Sk4fLinearGradient.h" #include "Sk4x4f.h" -#include "SkXfermode.h" + +#include namespace { @@ -90,23 +91,33 @@ SkScalar pinFx(SkScalar fx) { template<> SkScalar pinFx(SkScalar fx) { - const SkScalar f = SkScalarFraction(fx); - return f < 0 ? f + 1 : f; + SkScalar f = SkScalarFraction(fx); + if (f < 0) { + f = SkTMin(f + 1, nextafterf(1, 0)); + } + SkASSERT(f >= 0); + SkASSERT(f < 1.0f); + return f; } template<> SkScalar pinFx(SkScalar fx) { - const SkScalar f = SkScalarMod(fx, 2.0f); - return f < 0 ? f + 2 : f; + SkScalar f = SkScalarMod(fx, 2.0f); + if (f < 0) { + f = SkTMin(f + 2, nextafterf(2, 0)); + } + SkASSERT(f >= 0); + SkASSERT(f < 2.0f); + return f; } -// true when x is in [k1,k2), or [k2, k1) when the interval is reversed. +// true when x is in [k1,k2], or [k2, k1] when the interval is reversed. // TODO(fmalita): hoist the reversed interval check out of this helper. bool in_range(SkScalar x, SkScalar k1, SkScalar k2) { SkASSERT(k1 != k2); return (k1 < k2) - ? (x >= k1 && x < k2) - : (x > k2 && x <= k1); + ? (x >= k1 && x <= k2) + : (x >= k2 && x <= k1); } } // anonymous namespace @@ -117,51 +128,52 @@ LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader, : INHERITED(shader, rec) { // Our fast path expects interval points to be monotonically increasing in x. - const bool reverseIntervals = this->isFast() && signbit(fDstToPos.getScaleX()); - this->buildIntervals(shader, rec, reverseIntervals); + const bool reverseIntervals = this->isFast() && std::signbit(fDstToPos.getScaleX()); + fIntervals.init(shader.fOrigColors, shader.fOrigPos, shader.fColorCount, shader.fTileMode, + fColorsArePremul, rec.fPaint->getAlpha() * (1.0f / 255), reverseIntervals); - SkASSERT(fIntervals.count() > 0); - fCachedInterval = fIntervals.begin(); + SkASSERT(fIntervals->count() > 0); + fCachedInterval = fIntervals->begin(); } -const SkGradientShaderBase::GradientShaderBase4fContext::Interval* +const Sk4fGradientInterval* SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const { - SkASSERT(in_range(fx, fIntervals.front().fP0, fIntervals.back().fP1)); + SkASSERT(in_range(fx, fIntervals->front().fT0, fIntervals->back().fT1)); if (1) { // Linear search, using the last scanline interval as a starting point. - SkASSERT(fCachedInterval >= fIntervals.begin()); - SkASSERT(fCachedInterval < fIntervals.end()); + SkASSERT(fCachedInterval >= fIntervals->begin()); + SkASSERT(fCachedInterval < fIntervals->end()); const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1; - while (!in_range(fx, fCachedInterval->fP0, fCachedInterval->fP1)) { + while (!in_range(fx, fCachedInterval->fT0, fCachedInterval->fT1)) { fCachedInterval += search_dir; - if (fCachedInterval >= fIntervals.end()) { - fCachedInterval = fIntervals.begin(); - } else if (fCachedInterval < fIntervals.begin()) { - fCachedInterval = fIntervals.end() - 1; + if (fCachedInterval >= fIntervals->end()) { + fCachedInterval = fIntervals->begin(); + } else if (fCachedInterval < fIntervals->begin()) { + fCachedInterval = fIntervals->end() - 1; } } return fCachedInterval; } else { // Binary search. Seems less effective than linear + caching. - const Interval* i0 = fIntervals.begin(); - const Interval* i1 = fIntervals.end() - 1; + const auto* i0 = fIntervals->begin(); + const auto* i1 = fIntervals->end() - 1; while (i0 != i1) { SkASSERT(i0 < i1); - SkASSERT(in_range(fx, i0->fP0, i1->fP1)); + SkASSERT(in_range(fx, i0->fT0, i1->fT1)); - const Interval* i = i0 + ((i1 - i0) >> 1); + const auto* i = i0 + ((i1 - i0) >> 1); - if (in_range(fx, i0->fP0, i->fP1)) { + if (in_range(fx, i0->fT0, i->fT1)) { i1 = i; } else { - SkASSERT(in_range(fx, i->fP1, i1->fP1)); + SkASSERT(in_range(fx, i->fT1, i1->fT1)); i0 = i + 1; } } - SkASSERT(in_range(fx, i0->fP0, i0->fP1)); + SkASSERT(in_range(fx, i0->fT0, i0->fT1)); return i0; } } @@ -240,12 +252,12 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, &pt); const SkScalar fx = pinFx(pt.x()); const SkScalar dx = fDstToPos.getScaleX(); - LinearIntervalProcessor proc(fIntervals.begin(), - fIntervals.end() - 1, - this->findInterval(fx), - fx, - dx, - SkScalarNearlyZero(dx * count)); + LinearIntervalProcessor proc(fIntervals->begin(), + fIntervals->end() - 1, + this->findInterval(fx), + fx, + dx, + SkScalarNearlyZero(dx * count)); while (count > 0) { // What we really want here is SkTPin(advance, 1, count) // but that's a significant perf hit for >> stops; investigate. @@ -274,17 +286,17 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, } } -template +template class SkLinearGradient:: LinearGradient4fContext::LinearIntervalProcessor { public: - LinearIntervalProcessor(const Interval* firstInterval, - const Interval* lastInterval, - const Interval* i, + LinearIntervalProcessor(const Sk4fGradientInterval* firstInterval, + const Sk4fGradientInterval* lastInterval, + const Sk4fGradientInterval* i, SkScalar fx, SkScalar dx, bool is_vertical) - : fAdvX((i->fP1 - fx) / dx) + : fAdvX(is_vertical ? SK_ScalarInfinity : (i->fT1 - fx) / dx) , fFirstInterval(firstInterval) , fLastInterval(lastInterval) , fInterval(i) @@ -293,13 +305,28 @@ public: { SkASSERT(fAdvX >= 0); SkASSERT(firstInterval <= lastInterval); - SkASSERT(in_range(fx, i->fP0, i->fP1)); - this->compute_interval_props(fx - i->fP0); + + if (tileMode != kClamp_TileMode && !is_vertical) { + const auto spanX = (lastInterval->fT1 - firstInterval->fT0) / dx; + SkASSERT(spanX >= 0); + + // If we're in a repeating tile mode and the whole gradient is compressed into a + // fraction of a pixel, we just use the average color in zero-ramp mode. + // This also avoids cases where we make no progress due to interval advances being + // close to zero. + static constexpr SkScalar kMinSpanX = .25f; + if (spanX < kMinSpanX) { + this->init_average_props(); + return; + } + } + + this->compute_interval_props(fx); } SkScalar currentAdvance() const { SkASSERT(fAdvX >= 0); - SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx); + SkASSERT(fAdvX <= (fInterval->fT1 - fInterval->fT0) / fDx || !std::isfinite(fAdvX)); return fAdvX; } @@ -322,19 +349,43 @@ public: private: void compute_interval_props(SkScalar t) { - fZeroRamp = fIsVertical || fInterval->isZeroRamp(); - fCc = DstTraits::load(fInterval->fC0); + SkASSERT(in_range(t, fInterval->fT0, fInterval->fT1)); - if (fInterval->isZeroRamp()) { + fZeroRamp = fIsVertical || fInterval->fZeroRamp; + fCc = DstTraits::load(fInterval->fCb); + + if (fInterval->fZeroRamp) { fDcDx = 0; } else { - const Sk4f dC = DstTraits::load(fInterval->fDc); + const Sk4f dC = DstTraits::load(fInterval->fCg); fCc = fCc + dC * Sk4f(t); fDcDx = dC * fDx; } } - const Interval* next_interval(const Interval* i) const { + void init_average_props() { + fAdvX = SK_ScalarInfinity; + fZeroRamp = true; + fDcDx = 0; + fCc = Sk4f(0); + + // TODO: precompute the average at interval setup time? + for (const auto* i = fFirstInterval; i <= fLastInterval; ++i) { + // Each interval contributes its average color to the total/weighted average: + // + // C = (c0 + c1) / 2 = (Cb + Cg * t0 + Cb + Cg * t1) / 2 = Cb + Cg *(t0 + t1) / 2 + // + // Avg += C * (t1 - t0) + // + auto c = DstTraits::load(i->fCb); + if (!i->fZeroRamp) { + c = c + DstTraits::load(i->fCg) * (i->fT0 + i->fT1) * 0.5f; + } + fCc = fCc + c * (i->fT1 - i->fT0); + } + } + + const Sk4fGradientInterval* next_interval(const Sk4fGradientInterval* i) const { SkASSERT(i >= fFirstInterval); SkASSERT(i <= fLastInterval); i++; @@ -353,11 +404,11 @@ private: do { advX -= fAdvX; fInterval = this->next_interval(fInterval); - fAdvX = (fInterval->fP1 - fInterval->fP0) / fDx; + fAdvX = (fInterval->fT1 - fInterval->fT0) / fDx; SkASSERT(fAdvX > 0); } while (advX >= fAdvX); - compute_interval_props(0); + compute_interval_props(fInterval->fT0); SkASSERT(advX >= 0); return advX; @@ -369,11 +420,11 @@ private: SkScalar fAdvX; // remaining interval advance in dst bool fZeroRamp; // current interval color grad is 0 - const Interval* fFirstInterval; - const Interval* fLastInterval; - const Interval* fInterval; // current interval - const SkScalar fDx; // 'dx' for consistency with other impls; actually dt/dx - const bool fIsVertical; + const Sk4fGradientInterval* fFirstInterval; + const Sk4fGradientInterval* fLastInterval; + const Sk4fGradientInterval* fInterval; // current interval + const SkScalar fDx; // 'dx' for consistency with other impls; actually dt/dx + const bool fIsVertical; }; void SkLinearGradient:: @@ -415,7 +466,9 @@ LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const { } else { for (int i = 0; i < count; ++i) { fDstToPosProc(fDstToPos, sx, sy, &pt); - ts[i] = pt.x(); + // Perspective may yield NaN values. + // Short of a better idea, drop to 0. + ts[i] = SkScalarIsNaN(pt.x()) ? 0 : pt.x(); sx += SK_Scalar1; } } @@ -423,13 +476,8 @@ LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const { bool SkLinearGradient::LinearGradient4fContext::onChooseBlitProcs(const SkImageInfo& info, BlitState* state) { - SkXfermode::Mode mode; - if (!SkXfermode::AsMode(state->fXfer, &mode)) { - return false; - } - - if (mode != SkXfermode::kSrc_Mode && - !(mode == SkXfermode::kSrcOver_Mode && (fFlags & kOpaqueAlpha_Flag))) { + if (state->fMode != SkBlendMode::kSrc && + !(state->fMode == SkBlendMode::kSrcOver && (fFlags & kOpaqueAlpha_Flag))) { return false; } diff --git a/gfx/skia/skia/src/effects/gradients/Sk4fLinearGradient.h b/gfx/skia/skia/src/effects/gradients/Sk4fLinearGradient.h index dc7a1795834e..eebd30fbf5d9 100644 --- a/gfx/skia/skia/src/effects/gradients/Sk4fLinearGradient.h +++ b/gfx/skia/skia/src/effects/gradients/Sk4fLinearGradient.h @@ -27,7 +27,7 @@ protected: private: using INHERITED = GradientShaderBase4fContext; - template + template class LinearIntervalProcessor; template @@ -38,14 +38,14 @@ private: void shadeSpanInternal(int x, int y, typename DstTraits::Type[], int count) const; - const Interval* findInterval(SkScalar fx) const; + const Sk4fGradientInterval* findInterval(SkScalar fx) const; bool isFast() const { return fDstToPosClass == kLinear_MatrixClass; } static void D32_BlitBW(BlitState*, int x, int y, const SkPixmap& dst, int count); static void D64_BlitBW(BlitState*, int x, int y, const SkPixmap& dst, int count); - mutable const Interval* fCachedInterval; + mutable const Sk4fGradientInterval* fCachedInterval; }; #endif // Sk4fLinearGradient_DEFINED diff --git a/gfx/skia/skia/src/effects/gradients/SkClampRange.cpp b/gfx/skia/skia/src/effects/gradients/SkClampRange.cpp index 2056e5001c1c..efc93959d11b 100644 --- a/gfx/skia/skia/src/effects/gradients/SkClampRange.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkClampRange.cpp @@ -18,18 +18,23 @@ static int SkCLZ64(uint64_t value) { return count + SkCLZ(SkToU32(value)); } -static bool sk_64_smul_check(int64_t a, int64_t b, int64_t* result) { +static bool sk_64_smul_check(int64_t count, int64_t dx, int64_t* result) { // Do it the slow way until we have some assembly. - int64_t ua = SkTAbs(a); - int64_t ub = SkTAbs(b); - int zeros = SkCLZ64(ua) + SkCLZ64(ub); + if (dx == std::numeric_limits::min()) { + return false; // SkTAbs overflow + } + + SkASSERT(count >= 0); + uint64_t ucount = static_cast(count); + uint64_t udx = static_cast(SkTAbs(dx)); + int zeros = SkCLZ64(ucount) + SkCLZ64(udx); // this is a conservative check: it may return false when in fact it would not have overflowed. // Hackers Delight uses 34 as its convervative check, but that is for 32x32 multiplies. // Since we are looking at 64x64 muls, we add 32 to the check. if (zeros < (32 + 34)) { return false; } - *result = a * b; + *result = count * dx; return true; } @@ -48,6 +53,7 @@ static bool sk_64_sadd_check(int64_t a, int64_t b, int64_t* result) { return true; } + /* * returns [0..count] for the number of steps (<= count) for which x0 <= edge * given each step is followed by x0 += dx diff --git a/gfx/skia/skia/src/effects/gradients/SkClampRange.h b/gfx/skia/skia/src/effects/gradients/SkClampRange.h index d3d2d08c86d8..8a22e72d3817 100644 --- a/gfx/skia/skia/src/effects/gradients/SkClampRange.h +++ b/gfx/skia/skia/src/effects/gradients/SkClampRange.h @@ -11,11 +11,22 @@ #include "SkFixed.h" #include "SkScalar.h" -#define SkGradFixed SkFixed3232 -#define SkScalarToGradFixed(x) SkScalarToFixed3232(x) -#define SkFixedToGradFixed(x) SkFixedToFixed3232(x) -#define SkGradFixedToFixed(x) (SkFixed)((x) >> 16) -#define kFracMax_SkGradFixed 0xFFFFFFFFLL +#define SkGradFixed SkFixed3232 + +// We want the largest 32.32 value representable as a float. (float)0x7FFFFFFF +// becomes too big, due to limited mantissa on the float and its rounding rules, so +// we have to manually compute the next smaller value (aka nextafter). + +// #define SkGradFixedMaxScalar nextafterf(SkFixed3232ToFloat(SkFixed3232Max), 0) +// #define SkGradFixedMinScalar nextafterf(SkFixed3232ToFloat(SkFixed3232Min), 0) +#define SkGradFixedMaxScalar ( 2147483520.0f) +#define SkGradFixedMinScalar (-2147483520.0f) +#define SkScalarPinToGradFixed(x) SkScalarToFixed3232(SkTPin(x, \ + SkGradFixedMinScalar,\ + SkGradFixedMaxScalar)) +#define SkFixedToGradFixed(x) SkFixedToFixed3232(x) +#define SkGradFixedToFixed(x) (SkFixed)((x) >> 16) +#define kFracMax_SkGradFixed 0xFFFFFFFFLL /** * Iteration fixed fx by dx, clamping as you go to [0..kFracMax_SkGradFixed], this class diff --git a/gfx/skia/skia/src/effects/gradients/SkGradientBitmapCache.cpp b/gfx/skia/skia/src/effects/gradients/SkGradientBitmapCache.cpp index 20b87e02cad8..06b2d8c3fe0a 100644 --- a/gfx/skia/skia/src/effects/gradients/SkGradientBitmapCache.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkGradientBitmapCache.cpp @@ -8,6 +8,8 @@ #include "SkGradientBitmapCache.h" +#include "SkMalloc.h" + struct SkGradientBitmapCache::Entry { Entry* fPrev; Entry* fNext; diff --git a/gfx/skia/skia/src/effects/gradients/SkGradientShader.cpp b/gfx/skia/skia/src/effects/gradients/SkGradientShader.cpp index 17302d9d4f36..730cfbfa4f3a 100644 --- a/gfx/skia/skia/src/effects/gradients/SkGradientShader.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkGradientShader.cpp @@ -6,9 +6,11 @@ */ #include "Sk4fLinearGradient.h" +#include "SkColorSpace_XYZ.h" #include "SkGradientShaderPriv.h" #include "SkHalf.h" #include "SkLinearGradient.h" +#include "SkMallocPixelRef.h" #include "SkRadialGradient.h" #include "SkTwoPointConicalGradient.h" #include "SkSweepGradient.h" @@ -216,7 +218,7 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatri if (!desc.fColorSpace) { // This happens if we were constructed from SkColors, so our colors are really sRGB - fColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named); + fColorSpace = SkColorSpace::MakeSRGBLinear(); } else { // The color space refers to the float colors, so it must be linear gamma SkASSERT(desc.fColorSpace->gammaIsLinear()); @@ -409,12 +411,9 @@ SkGradientShaderBase::GradientShaderCache::GradientShaderCache( { // Only initialize the cache in getCache32. fCache32 = nullptr; - fCache32PixelRef = nullptr; } -SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() { - SkSafeUnref(fCache32PixelRef); -} +SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() {} /* * r,g,b used to be SkFixed, but on gcc (4.2.1 mac and 4.6.3 goobuntu) in @@ -583,8 +582,8 @@ void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache* const SkImageInfo info = SkImageInfo::MakeN32Premul(kCache32Count, kNumberOfDitherRows); SkASSERT(nullptr == cache->fCache32PixelRef); - cache->fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, nullptr); - cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->getAddr(); + cache->fCache32PixelRef = SkMallocPixelRef::MakeAllocate(info, 0, nullptr); + cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->pixels(); if (cache->fShader.fColorCount == 2) { Build32bitCache(cache->fCache32, cache->fShader.fOrigColors[0], cache->fShader.fOrigColors[1], kCache32Count, cache->fCacheAlpha, @@ -665,7 +664,7 @@ void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap) const { * The gradient holds a cache for the most recent value of alpha. Successive * callers with the same alpha value will share the same cache. */ -SkGradientShaderBase::GradientShaderCache* SkGradientShaderBase::refCache(U8CPU alpha, +sk_sp SkGradientShaderBase::refCache(U8CPU alpha, bool dither) const { SkAutoMutexAcquire ama(fCacheMutex); if (!fCache || fCache->getAlpha() != alpha || fCache->getDither() != dither) { @@ -674,7 +673,6 @@ SkGradientShaderBase::GradientShaderCache* SkGradientShaderBase::refCache(U8CPU // Increment the ref counter inside the mutex to ensure the returned pointer is still valid. // Otherwise, the pointer may have been overwritten on a different thread before the object's // ref count was incremented. - fCache.get()->ref(); return fCache; } @@ -690,7 +688,7 @@ SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex); void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap, GradientBitmapType bitmapType) const { // our caller assumes no external alpha, so we ensure that our cache is built with 0xFF - SkAutoTUnref cache(this->refCache(0xFF, true)); + sk_sp cache(this->refCache(0xFF, true)); // build our key: [numColors + colors[] + {positions[]} + flags + colorType ] int count = 1 + fColorCount + 1 + 1; @@ -730,7 +728,7 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap, // force our cache32pixelref to be built (void)cache->getCache32(); bitmap->setInfo(SkImageInfo::MakeN32Premul(kCache32Count, 1)); - bitmap->setPixelRef(cache->getCache32PixelRef()); + bitmap->setPixelRef(sk_ref_sp(cache->getCache32PixelRef()), 0, 0); } else { // For these cases we use the bitmap cache, but not the GradientShaderCache. So just // allocate and populate the bitmap's data directly. @@ -740,12 +738,12 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap, case GradientBitmapType::kSRGB: info = SkImageInfo::Make(kCache32Count, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType, - SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)); + SkColorSpace::MakeSRGB()); break; case GradientBitmapType::kHalfFloat: info = SkImageInfo::Make( kCache32Count, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType, - SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named)); + SkColorSpace::MakeSRGBLinear()); break; default: SkFAIL("Unexpected bitmap type"); @@ -763,9 +761,11 @@ void SkGradientShaderBase::commonAsAGradient(GradientInfo* info, bool flipGrad) if (info->fColorCount >= fColorCount) { SkColor* colorLoc; Rec* recLoc; + SkAutoSTArray<8, SkColor> colorStorage; + SkAutoSTArray<8, Rec> recStorage; if (flipGrad && (info->fColors || info->fColorOffsets)) { - SkAutoSTArray<8, SkColor> colorStorage(fColorCount); - SkAutoSTArray<8, Rec> recStorage(fColorCount); + colorStorage.reset(fColorCount); + recStorage.reset(fColorCount); colorLoc = colorStorage.get(); recLoc = recStorage.get(); FlipGradientColors(colorLoc, recLoc, fOrigColors, fRecs, fColorCount); @@ -944,6 +944,9 @@ sk_sp SkGradientShader::MakeLinear(const SkPoint pts[2], if (1 == colorCount) { return SkShader::MakeColorShader(colors[0], std::move(colorSpace)); } + if (localMatrix && !localMatrix->invert(nullptr)) { + return nullptr; + } ColorStopOptimizer opt(colors, pos, colorCount, mode); @@ -980,6 +983,9 @@ sk_sp SkGradientShader::MakeRadial(const SkPoint& center, SkScalar rad if (1 == colorCount) { return SkShader::MakeColorShader(colors[0], std::move(colorSpace)); } + if (localMatrix && !localMatrix->invert(nullptr)) { + return nullptr; + } ColorStopOptimizer opt(colors, pos, colorCount, mode); @@ -1026,6 +1032,9 @@ sk_sp SkGradientShader::MakeTwoPointConical(const SkPoint& start, return SkShader::MakeEmptyShader(); } } + if (localMatrix && !localMatrix->invert(nullptr)) { + return nullptr; + } EXPAND_1_COLOR(colorCount); ColorStopOptimizer opt(colors, pos, colorCount, mode); @@ -1086,6 +1095,9 @@ sk_sp SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy, if (1 == colorCount) { return SkShader::MakeColorShader(colors[0], std::move(colorSpace)); } + if (localMatrix && !localMatrix->invert(nullptr)) { + return nullptr; + } auto mode = SkShader::kClamp_TileMode; @@ -1109,7 +1121,7 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END #if SK_SUPPORT_GPU #include "GrContext.h" -#include "GrInvariantOutput.h" +#include "GrShaderCaps.h" #include "GrTextureStripAtlas.h" #include "gl/GrGLContext.h" #include "glsl/GrGLSLColorSpaceXformHelper.h" @@ -1125,7 +1137,7 @@ static inline bool close_to_one_half(const SkFixed& val) { static inline int color_type_to_color_count(GrGradientEffect::ColorType colorType) { switch (colorType) { #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS - case GrGradientEffect::kHardStopCentered_ColorType: + case GrGradientEffect::kSingleHardStop_ColorType: return 4; case GrGradientEffect::kHardStopLeftEdged_ColorType: case GrGradientEffect::kHardStopRightEdged_ColorType: @@ -1149,11 +1161,10 @@ GrGradientEffect::ColorType GrGradientEffect::determineColorType( if (shader.fOrigPos) { if (4 == shader.fColorCount) { if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) && - SkScalarNearlyEqual(shader.fOrigPos[1], 0.5f) && - SkScalarNearlyEqual(shader.fOrigPos[2], 0.5f) && + SkScalarNearlyEqual(shader.fOrigPos[1], shader.fOrigPos[2]) && SkScalarNearlyEqual(shader.fOrigPos[3], 1.0f)) { - return kHardStopCentered_ColorType; + return kSingleHardStop_ColorType; } } else if (3 == shader.fColorCount) { if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) && @@ -1191,6 +1202,10 @@ void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniform kDefault_GrSLPrecision, "Colors", colorCount); + if (ge.fColorType == kSingleHardStop_ColorType) { + fHardStopT = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, + kDefault_GrSLPrecision, "HardStopT"); + } } else { fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, @@ -1286,12 +1301,14 @@ static inline void set_before_interp_color_uni_array(const GrGLSLProgramDataMana } void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrFragmentProcessor& processor) { const GrGradientEffect& e = processor.cast(); switch (e.getColorType()) { #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS - case GrGradientEffect::kHardStopCentered_ColorType: + case GrGradientEffect::kSingleHardStop_ColorType: + pdman.set1f(fHardStopT, e.fPositions[1]); + // fall through case GrGradientEffect::kHardStopLeftEdged_ColorType: case GrGradientEffect::kHardStopRightEdged_ColorType: #endif @@ -1325,7 +1342,7 @@ void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& fCachedYCoord = yCoord; } if (SkToBool(e.fColorSpaceXform)) { - pdman.setSkMatrix44(fColorSpaceXformUni, e.fColorSpaceXform->srcToDst()); + fColorSpaceHelper.setData(pdman, e.fColorSpaceXform.get()); } break; } @@ -1347,7 +1364,7 @@ uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor& key |= kThreeColorKey; } #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS - else if (GrGradientEffect::kHardStopCentered_ColorType == e.getColorType()) { + else if (GrGradientEffect::kSingleHardStop_ColorType == e.getColorType()) { key |= kHardStopCenteredKey; } else if (GrGradientEffect::kHardStopLeftEdged_ColorType == e.getColorType()) { key |= kHardStopZeroZeroOneKey; @@ -1371,7 +1388,7 @@ uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor& void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBuilder, GrGLSLUniformHandler* uniformHandler, - const GrGLSLCaps* glslCaps, + const GrShaderCaps* shaderCaps, const GrGradientEffect& ge, const char* gradientTValue, const char* outputColor, @@ -1379,9 +1396,10 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui const TextureSamplers& texSamplers) { switch (ge.getColorType()) { #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS - case kHardStopCentered_ColorType: { + case kSingleHardStop_ColorType: { const char* t = gradientTValue; const char* colors = uniformHandler->getUniformCStr(fColorsUni); + const char* stopT = uniformHandler->getUniformCStr(fHardStopT); fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t); @@ -1399,22 +1417,25 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui } // Calculate color - fragBuilder->codeAppendf("float relative_t = fract(2.0 * clamp_t);"); - if (SkShader::kClamp_TileMode == ge.fTileMode) { - fragBuilder->codeAppendf("relative_t += step(1.0, %s);", t); - } - - fragBuilder->codeAppendf("vec4 start = %s[0];", colors); - fragBuilder->codeAppendf("vec4 end = %s[1];", colors); - fragBuilder->codeAppendf("if (clamp_t >= 0.5) {"); + fragBuilder->codeAppend ("vec4 start, end;"); + fragBuilder->codeAppend ("float relative_t;"); + fragBuilder->codeAppendf("if (clamp_t < %s) {", stopT); + fragBuilder->codeAppendf(" start = %s[0];", colors); + fragBuilder->codeAppendf(" end = %s[1];", colors); + fragBuilder->codeAppendf(" relative_t = clamp_t / %s;", stopT); + fragBuilder->codeAppend ("} else {"); fragBuilder->codeAppendf(" start = %s[2];", colors); fragBuilder->codeAppendf(" end = %s[3];", colors); - fragBuilder->codeAppendf("}"); - fragBuilder->codeAppendf("vec4 colorTemp = mix(start, end, relative_t);"); + fragBuilder->codeAppendf(" relative_t = (clamp_t - %s) / (1 - %s);", stopT, stopT); + fragBuilder->codeAppend ("}"); + fragBuilder->codeAppend ("vec4 colorTemp = mix(start, end, relative_t);"); if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); } + if (ge.fColorSpaceXform) { + fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); + } fragBuilder->codeAppendf("%s = %s;", outputColor, (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); @@ -1451,6 +1472,9 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); } + if (ge.fColorSpaceXform) { + fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); + } fragBuilder->codeAppendf("%s = %s;", outputColor, (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); @@ -1487,6 +1511,9 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); } + if (ge.fColorSpaceXform) { + fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); + } fragBuilder->codeAppendf("%s = %s;", outputColor, (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); @@ -1510,6 +1537,9 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); } + if (ge.fColorSpaceXform) { + fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); + } fragBuilder->codeAppendf("%s = %s;", outputColor, (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); @@ -1524,7 +1554,7 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui fragBuilder->codeAppendf("float oneMinus2t = 1.0 - (2.0 * %s);", t); fragBuilder->codeAppendf("vec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s[0];", colors); - if (!glslCaps->canUseMinAndAbsTogether()) { + if (!shaderCaps->canUseMinAndAbsTogether()) { // The Tegra3 compiler will sometimes never return if we have // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression. fragBuilder->codeAppendf("float minAbs = abs(oneMinus2t);"); @@ -1539,6 +1569,9 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); } + if (ge.fColorSpaceXform) { + fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); + } fragBuilder->codeAppendf("%s = %s;", outputColor, (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); @@ -1547,15 +1580,14 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui } case kTexture_ColorType: { - GrGLSLColorSpaceXformHelper colorSpaceHelper(uniformHandler, ge.fColorSpaceXform.get(), - &fColorSpaceXformUni); + fColorSpaceHelper.emitCode(uniformHandler, ge.fColorSpaceXform.get()); const char* fsyuni = uniformHandler->getUniformCStr(fFSYUni); fragBuilder->codeAppendf("vec2 coord = vec2(%s, %s);", gradientTValue, fsyuni); fragBuilder->codeAppendf("%s = ", outputColor); fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord", - kVec2f_GrSLType, &colorSpaceHelper); + kVec2f_GrSLType, &fColorSpaceHelper); fragBuilder->codeAppend(";"); break; @@ -1565,7 +1597,15 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui ///////////////////////////////////////////////////////////////////// -GrGradientEffect::GrGradientEffect(const CreateArgs& args) { +inline GrFragmentProcessor::OptimizationFlags GrGradientEffect::OptFlags(bool isOpaque) { + return isOpaque + ? kPreservesOpaqueInput_OptimizationFlag | + kCompatibleWithCoverageAsAlpha_OptimizationFlag + : kCompatibleWithCoverageAsAlpha_OptimizationFlag; +} + +GrGradientEffect::GrGradientEffect(const CreateArgs& args, bool isOpaque) + : INHERITED(OptFlags(isOpaque)) { const SkGradientShaderBase& shader(*args.fShader); fIsOpaque = shader.isOpaque(); @@ -1599,7 +1639,7 @@ GrGradientEffect::GrGradientEffect(const CreateArgs& args) { #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS case kHardStopLeftEdged_ColorType: case kHardStopRightEdged_ColorType: - case kHardStopCentered_ColorType: + case kSingleHardStop_ColorType: #endif fRow = -1; @@ -1633,6 +1673,8 @@ GrGradientEffect::GrGradientEffect(const CreateArgs& args) { SkBitmap bitmap; shader.getGradientTableBitmap(&bitmap, bitmapType); + SkASSERT(1 == bitmap.height() && SkIsPow2(bitmap.width())); + GrTextureStripAtlas::Desc desc; desc.fWidth = bitmap.width(); @@ -1645,28 +1687,41 @@ GrGradientEffect::GrGradientEffect(const CreateArgs& args) { // We always filter the gradient table. Each table is one row of a texture, always // y-clamp. - GrTextureParams params; - params.setFilterMode(GrTextureParams::kBilerp_FilterMode); + GrSamplerParams params; + params.setFilterMode(GrSamplerParams::kBilerp_FilterMode); params.setTileModeX(args.fTileMode); fRow = fAtlas->lockRow(bitmap); if (-1 != fRow) { fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight(); - fCoordTransform.reset(*args.fMatrix, fAtlas->getTexture(), params.filterMode()); - fTextureAccess.reset(fAtlas->getTexture(), params); + // This is 1/2 places where auto-normalization is disabled + fCoordTransform.reset(args.fContext->resourceProvider(), *args.fMatrix, + fAtlas->asTextureProxyRef().get(), false); + fTextureSampler.reset(args.fContext->resourceProvider(), + fAtlas->asTextureProxyRef(), params); } else { - SkAutoTUnref texture( - GrRefCachedBitmapTexture(args.fContext, bitmap, params, - SkSourceGammaTreatment::kRespect)); - if (!texture) { + // In this instance we know the params are: + // clampY, bilerp + // and the proxy is: + // exact fit, power of two in both dimensions + // Only the x-tileMode is unknown. However, given all the other knowns we know + // that GrMakeCachedBitmapProxy is sufficient (i.e., it won't need to be + // extracted to a subset or mipmapped). + sk_sp proxy = GrMakeCachedBitmapProxy( + args.fContext->resourceProvider(), + bitmap); + if (!proxy) { return; } - fCoordTransform.reset(*args.fMatrix, texture, params.filterMode()); - fTextureAccess.reset(texture, params); + // This is 2/2 places where auto-normalization is disabled + fCoordTransform.reset(args.fContext->resourceProvider(), *args.fMatrix, + proxy.get(), false); + fTextureSampler.reset(args.fContext->resourceProvider(), + std::move(proxy), params); fYCoord = SK_ScalarHalf; } - this->addTextureAccess(&fTextureAccess); + this->addTextureSampler(&fTextureSampler); break; } @@ -1683,68 +1738,80 @@ GrGradientEffect::~GrGradientEffect() { bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const { const GrGradientEffect& ge = processor.cast(); - if (this->fColorType == ge.getColorType()) { - if (kTexture_ColorType == fColorType) { - if (fYCoord != ge.getYCoord()) { + if (this->fColorType != ge.getColorType()) { + return false; + } + SkASSERT(this->useAtlas() == ge.useAtlas()); + if (kTexture_ColorType == fColorType) { + if (fYCoord != ge.getYCoord()) { + return false; + } + } else { + if (kSingleHardStop_ColorType == fColorType) { + if (!SkScalarNearlyEqual(ge.fPositions[1], fPositions[1])) { return false; } - } else { - if (this->getPremulType() != ge.getPremulType() || - this->fColors.count() != ge.fColors.count() || - this->fColors4f.count() != ge.fColors4f.count()) { - return false; - } - - for (int i = 0; i < this->fColors.count(); i++) { - if (*this->getColors(i) != *ge.getColors(i)) { - return false; - } - } - for (int i = 0; i < this->fColors4f.count(); i++) { - if (*this->getColors4f(i) != *ge.getColors4f(i)) { - return false; - } - } + } + if (this->getPremulType() != ge.getPremulType() || + this->fColors.count() != ge.fColors.count() || + this->fColors4f.count() != ge.fColors4f.count()) { + return false; } - - SkASSERT(this->useAtlas() == ge.useAtlas()); - return GrColorSpaceXform::Equals(this->fColorSpaceXform.get(), ge.fColorSpaceXform.get()); + for (int i = 0; i < this->fColors.count(); i++) { + if (*this->getColors(i) != *ge.getColors(i)) { + return false; + } + } + for (int i = 0; i < this->fColors4f.count(); i++) { + if (*this->getColors4f(i) != *ge.getColors4f(i)) { + return false; + } + } } - - return false; + return GrColorSpaceXform::Equals(this->fColorSpaceXform.get(), ge.fColorSpaceXform.get()); } -void GrGradientEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - if (fIsOpaque) { - inout->mulByUnknownOpaqueFourComponents(); - } else { - inout->mulByUnknownFourComponents(); - } -} - -int GrGradientEffect::RandomGradientParams(SkRandom* random, - SkColor colors[], - SkScalar** stops, - SkShader::TileMode* tm) { - int outColors = random->nextRangeU(1, kMaxRandomGradientColors); +#if GR_TEST_UTILS +GrGradientEffect::RandomGradientParams::RandomGradientParams(SkRandom* random) { + // Set color count to min of 2 so that we don't trigger the const color optimization and make + // a non-gradient processor. + fColorCount = random->nextRangeU(2, kMaxRandomGradientColors); + fUseColors4f = random->nextBool(); // if one color, omit stops, otherwise randomly decide whether or not to - if (outColors == 1 || (outColors >= 2 && random->nextBool())) { - *stops = nullptr; + if (fColorCount == 1 || (fColorCount >= 2 && random->nextBool())) { + fStops = nullptr; + } else { + fStops = fStopStorage; + } + + // if using SkColor4f, attach a random (possibly null) color space (with linear gamma) + if (fUseColors4f) { + fColorSpace = GrTest::TestColorSpace(random); + if (fColorSpace) { + SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(fColorSpace)->type()); + fColorSpace = static_cast(fColorSpace.get())->makeLinearGamma(); + } } SkScalar stop = 0.f; - for (int i = 0; i < outColors; ++i) { - colors[i] = random->nextU(); - if (*stops) { - (*stops)[i] = stop; - stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f; + for (int i = 0; i < fColorCount; ++i) { + if (fUseColors4f) { + fColors4f[i].fR = random->nextUScalar1(); + fColors4f[i].fG = random->nextUScalar1(); + fColors4f[i].fB = random->nextUScalar1(); + fColors4f[i].fA = random->nextUScalar1(); + } else { + fColors[i] = random->nextU(); + } + if (fStops) { + fStops[i] = stop; + stop = i < fColorCount - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f; } } - *tm = static_cast(random->nextULessThan(SkShader::kTileModeCount)); - - return outColors; + fTileMode = static_cast(random->nextULessThan(SkShader::kTileModeCount)); } +#endif #endif diff --git a/gfx/skia/skia/src/effects/gradients/SkGradientShaderPriv.h b/gfx/skia/skia/src/effects/gradients/SkGradientShaderPriv.h index 61a44184ff27..0feb44bfc878 100644 --- a/gfx/skia/skia/src/effects/gradients/SkGradientShaderPriv.h +++ b/gfx/skia/skia/src/effects/gradients/SkGradientShaderPriv.h @@ -10,15 +10,17 @@ #include "SkGradientBitmapCache.h" #include "SkGradientShader.h" + +#include "SkArenaAlloc.h" +#include "SkAutoMalloc.h" #include "SkClampRange.h" #include "SkColorPriv.h" #include "SkColorSpace.h" -#include "SkReadBuffer.h" -#include "SkWriteBuffer.h" -#include "SkMallocPixelRef.h" -#include "SkUtils.h" -#include "SkShader.h" #include "SkOnce.h" +#include "SkReadBuffer.h" +#include "SkShader.h" +#include "SkUtils.h" +#include "SkWriteBuffer.h" #if SK_SUPPORT_GPU #define GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1 @@ -116,7 +118,7 @@ public: }; SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit); - virtual ~SkGradientShaderBase(); + ~SkGradientShaderBase() override; // The cache is initialized on-demand when getCache32 is called. class GradientShaderCache : public SkRefCnt { @@ -126,7 +128,7 @@ public: const SkPMColor* getCache32(); - SkMallocPixelRef* getCache32PixelRef() const { return fCache32PixelRef; } + SkPixelRef* getCache32PixelRef() const { return fCache32PixelRef.get(); } unsigned getAlpha() const { return fCacheAlpha; } bool getDither() const { return fCacheDither; } @@ -135,7 +137,7 @@ public: // Working pointer. If it's nullptr, we need to recompute the cache values. SkPMColor* fCache32; - SkMallocPixelRef* fCache32PixelRef; + sk_sp fCache32PixelRef; const unsigned fCacheAlpha; // The alpha value we used when we computed the cache. // Larger than 8bits so we can store uninitialized // value. @@ -167,7 +169,7 @@ public: uint8_t fFlags; bool fDither; - SkAutoTUnref fCache; + sk_sp fCache; private: typedef SkShader::Context INHERITED; @@ -235,10 +237,9 @@ protected: int count); template - static Context* CheckedCreateContext(void* storage, Args&&... args) { - auto* ctx = new (storage) T(std::forward(args)...); + static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) { + auto* ctx = alloc->make(std::forward(args)...); if (!ctx->isValid()) { - ctx->~T(); return nullptr; } return ctx; @@ -267,9 +268,9 @@ public: private: bool fColorsAreOpaque; - GradientShaderCache* refCache(U8CPU alpha, bool dither) const; - mutable SkMutex fCacheMutex; - mutable SkAutoTUnref fCache; + sk_sp refCache(U8CPU alpha, bool dither) const; + mutable SkMutex fCacheMutex; + mutable sk_sp fCache; void initCommon(); @@ -293,6 +294,7 @@ static inline int next_dither_toggle(int toggle) { #include "GrColorSpaceXform.h" #include "GrCoordTransform.h" #include "GrFragmentProcessor.h" +#include "glsl/GrGLSLColorSpaceXformHelper.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" @@ -350,9 +352,7 @@ public: class GLSLProcessor; - GrGradientEffect(const CreateArgs&); - - virtual ~GrGradientEffect(); + ~GrGradientEffect() override; bool useAtlas() const { return SkToBool(-1 != fRow); } SkScalar getYCoord() const { return fYCoord; } @@ -363,7 +363,7 @@ public: kTexture_ColorType, #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS - kHardStopCentered_ColorType, // 0, 0.5, 0.5, 1 + kSingleHardStop_ColorType, // 0, t, t, 1 kHardStopLeftEdged_ColorType, // 0, 0, 1 kHardStopRightEdged_ColorType, // 0, 1, 1 #endif @@ -400,26 +400,38 @@ public: } protected: - /** Populates a pair of arrays with colors and stop info to construct a random gradient. - The function decides whether stop values should be used or not. The return value indicates - the number of colors, which will be capped by kMaxRandomGradientColors. colors should be - sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least - size kMaxRandomGradientColors. It may be updated to nullptr, indicating that nullptr should - be passed to the gradient factory rather than the array. - */ - static const int kMaxRandomGradientColors = 4; - static int RandomGradientParams(SkRandom* r, - SkColor colors[kMaxRandomGradientColors], - SkScalar** stops, - SkShader::TileMode* tm); + GrGradientEffect(const CreateArgs&, bool isOpaque); + + #if GR_TEST_UTILS + /** Helper struct that stores (and populates) parameters to construct a random gradient. + If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and + fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount + will be the number of color stops in either case, and fColors and fStops can be passed to + the gradient factory. (The constructor may decide not to use stops, in which case fStops + will be nullptr). */ + struct RandomGradientParams { + static const int kMaxRandomGradientColors = 5; + + RandomGradientParams(SkRandom* r); + + bool fUseColors4f; + SkColor fColors[kMaxRandomGradientColors]; + SkColor4f fColors4f[kMaxRandomGradientColors]; + sk_sp fColorSpace; + SkScalar fStopStorage[kMaxRandomGradientColors]; + SkShader::TileMode fTileMode; + int fColorCount; + SkScalar* fStops; + }; + #endif bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - const GrCoordTransform& getCoordTransform() const { return fCoordTransform; } private: + static OptimizationFlags OptFlags(bool isOpaque); + // If we're in legacy mode, then fColors will be populated. If we're gamma-correct, then // fColors4f and fColorSpaceXform will be populated. SkTDArray fColors; @@ -431,7 +443,7 @@ private: SkShader::TileMode fTileMode; GrCoordTransform fCoordTransform; - GrTextureAccess fTextureAccess; + TextureSampler fTextureSampler; SkScalar fYCoord; GrTextureStripAtlas* fAtlas; int fRow; @@ -453,7 +465,7 @@ public: } protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; protected: /** @@ -473,7 +485,7 @@ protected: // of hard stop gradients void emitColor(GrGLSLFPFragmentBuilder* fragBuilder, GrGLSLUniformHandler* uniformHandler, - const GrGLSLCaps* caps, + const GrShaderCaps* shaderCaps, const GrGradientEffect&, const char* gradientTValue, const char* outputColor, @@ -506,8 +518,9 @@ private: SkScalar fCachedYCoord; GrGLSLProgramDataManager::UniformHandle fColorsUni; + GrGLSLProgramDataManager::UniformHandle fHardStopT; GrGLSLProgramDataManager::UniformHandle fFSYUni; - GrGLSLProgramDataManager::UniformHandle fColorSpaceXformUni; + GrGLSLColorSpaceXformHelper fColorSpaceHelper; typedef GrGLSLFragmentProcessor INHERITED; }; diff --git a/gfx/skia/skia/src/effects/gradients/SkLinearGradient.cpp b/gfx/skia/skia/src/effects/gradients/SkLinearGradient.cpp index df2765b466b0..221ae4f5461f 100644 --- a/gfx/skia/skia/src/effects/gradients/SkLinearGradient.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkLinearGradient.cpp @@ -74,16 +74,187 @@ void SkLinearGradient::flatten(SkWriteBuffer& buffer) const { buffer.writePoint(fEnd); } -size_t SkLinearGradient::onContextSize(const ContextRec& rec) const { +SkShader::Context* SkLinearGradient::onMakeContext( + const ContextRec& rec, SkArenaAlloc* alloc) const +{ return use_4f_context(rec, fGradFlags) - ? sizeof(LinearGradient4fContext) - : sizeof(LinearGradientContext); + ? CheckedMakeContext(alloc, *this, rec) + : CheckedMakeContext< LinearGradientContext>(alloc, *this, rec); } -SkShader::Context* SkLinearGradient::onCreateContext(const ContextRec& rec, void* storage) const { - return use_4f_context(rec, fGradFlags) - ? CheckedCreateContext(storage, *this, rec) - : CheckedCreateContext< LinearGradientContext>(storage, *this, rec); +// +// Stages: +// +// * matrix (map dst -> grad space) +// * clamp/repeat/mirror (tiling) +// * linear_gradient_2stops (lerp c0/c1) +// * optional premul +// +bool SkLinearGradient::onAppendStages(SkRasterPipeline* p, + SkColorSpace* dstCS, + SkArenaAlloc* alloc, + const SkMatrix& ctm, + const SkPaint& paint, + const SkMatrix* localM) const { + // Local matrix not supported currently. Remove once we have a generic RP wrapper. + if (localM || !getLocalMatrix().isIdentity()) { + return false; + } + + SkMatrix dstToPts; + if (!ctm.invert(&dstToPts)) { + return false; + } + + const auto dstToUnit = SkMatrix::Concat(fPtsToUnit, dstToPts); + + // If the gradient is less than a quarter of a pixel, this falls into the subpixel gradient code + // handled on a different path. + SkVector dx = dstToUnit.mapVector(1, 0); + if (dx.fX >= 4) { + return false; + } + + auto* m = alloc->makeArrayDefault(9); + if (dstToUnit.asAffine(m)) { + // TODO: mapping y is not needed; split the matrix stages to save some math? + p->append(SkRasterPipeline::matrix_2x3, m); + } else { + dstToUnit.get9(m); + p->append(SkRasterPipeline::matrix_perspective, m); + } + + // TODO: clamp/repeat/mirror const 1f stages? + auto* limit = alloc->make(1.0f); + + const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag; + auto prepareColor = [premulGrad, dstCS, this](int i) { + SkColor4f c = dstCS ? to_colorspace(fOrigColors4f[i], fColorSpace.get(), dstCS) + : SkColor4f_from_SkColor(fOrigColors[i], nullptr); + return premulGrad ? c.premul() + : SkPM4f::From4f(Sk4f::Load(&c)); + }; + + // The two-stop case with stops at 0 and 1. + if (fColorCount == 2 && fOrigPos == nullptr) { + switch (fTileMode) { + case kClamp_TileMode: p->append(SkRasterPipeline:: clamp_x, limit); break; + case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, limit); break; + case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, limit); break; + } + + const SkPM4f c_l = prepareColor(0), + c_r = prepareColor(1); + + // See F and B below. + auto* f_and_b = alloc->makeArrayDefault(2); + f_and_b[0] = SkPM4f::From4f(c_r.to4f() - c_l.to4f()); + f_and_b[1] = c_l; + + p->append(SkRasterPipeline::linear_gradient_2stops, f_and_b); + } else { + switch (fTileMode) { + // The search strategy does not need clamping. It has implicit hard stops at the + // first and last stop. + case kClamp_TileMode: break; + case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, limit); break; + case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, limit); break; + } + + struct Stop { float t; SkPM4f f, b; }; + struct Ctx { size_t n; Stop* stops; SkPM4f start; }; + + auto* ctx = alloc->make(); + ctx->start = prepareColor(0); + + // For each stop we calculate a bias B and a scale factor F, such that + // for any t between stops n and n+1, the color we want is B[n] + F[n]*t. + auto init_stop = [](float t_l, float t_r, SkPM4f c_l, SkPM4f c_r, Stop *stop) { + auto F = SkPM4f::From4f((c_r.to4f() - c_l.to4f()) / (t_r - t_l)); + auto B = SkPM4f::From4f(c_l.to4f() - (F.to4f() * t_l)); + *stop = {t_l, F, B}; + }; + + if (fOrigPos == nullptr) { + // Handle evenly distributed stops. + + float dt = 1.0f / (fColorCount - 1); + // In the evenly distributed case, fColorCount is the number of stops. There are no + // dummy entries. + auto* stopsArray = alloc->makeArrayDefault(fColorCount); + + float t_l = 0; + SkPM4f c_l = ctx->start; + for (int i = 0; i < fColorCount - 1; i++) { + // Use multiply instead of accumulating error using repeated addition. + float t_r = (i + 1) * dt; + SkPM4f c_r = prepareColor(i + 1); + init_stop(t_l, t_r, c_l, c_r, &stopsArray[i]); + + t_l = t_r; + c_l = c_r; + } + + // Force the last stop. + stopsArray[fColorCount - 1].t = 1; + stopsArray[fColorCount - 1].f = SkPM4f::From4f(Sk4f{0}); + stopsArray[fColorCount - 1].b = prepareColor(fColorCount - 1); + + ctx->n = fColorCount; + ctx->stops = stopsArray; + } else { + // Handle arbitrary stops. + + // Remove the dummy stops inserted by SkGradientShaderBase::SkGradientShaderBase + // because they are naturally handled by the search method. + int firstStop; + int lastStop; + if (fColorCount > 2) { + firstStop = fOrigColors4f[0] != fOrigColors4f[1] ? 0 : 1; + lastStop = fOrigColors4f[fColorCount - 2] != fOrigColors4f[fColorCount - 1] + ? fColorCount - 1 : fColorCount - 2; + } else { + firstStop = 0; + lastStop = 1; + } + int realCount = lastStop - firstStop + 1; + + // This is the maximum number of stops. There may be fewer stops because the duplicate + // points of hard stops are removed. + auto* stopsArray = alloc->makeArrayDefault(realCount); + + size_t stopCount = 0; + float t_l = fOrigPos[firstStop]; + SkPM4f c_l = prepareColor(firstStop); + // N.B. lastStop is the index of the last stop, not one after. + for (int i = firstStop; i < lastStop; i++) { + float t_r = fOrigPos[i + 1]; + SkPM4f c_r = prepareColor(i + 1); + if (t_l < t_r) { + init_stop(t_l, t_r, c_l, c_r, &stopsArray[stopCount]); + stopCount += 1; + } + t_l = t_r; + c_l = c_r; + } + + stopsArray[stopCount].t = fOrigPos[lastStop]; + stopsArray[stopCount].f = SkPM4f::From4f(Sk4f{0}); + stopsArray[stopCount].b = prepareColor(lastStop); + stopCount += 1; + + ctx->n = stopCount; + ctx->stops = stopsArray; + } + + p->append(SkRasterPipeline::linear_gradient, ctx); + } + + if (!premulGrad && !this->colorsAreOpaque()) { + p->append(SkRasterPipeline::premul); + } + + return true; } // This swizzles SkColor into the same component order as SkPMColor, but does not actually @@ -189,7 +360,12 @@ void shadeSpan_linear_vertical_lerp(TileProc proc, SkGradFixed dx, SkGradFixed f // We're a vertical gradient, so no change in a span. // If colors change sharply across the gradient, dithering is // insufficient (it subsamples the color space) and we need to lerp. - unsigned fullIndex = proc(SkGradFixedToFixed(fx) - (SK_FixedHalf >> SkGradientShaderBase::kCache32Bits)); + unsigned fullIndex = proc(SkGradFixedToFixed(fx)); + if (fullIndex >= (SK_FixedHalf >> SkGradientShaderBase::kCache32Bits)) { + fullIndex -= SK_FixedHalf >> SkGradientShaderBase::kCache32Bits; + } else { + fullIndex = 0; + } unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift; unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1); @@ -276,15 +452,12 @@ void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SkASSERT(count > 0); const SkLinearGradient& linearGradient = static_cast(fShader); -// Only use the Sk4f impl when known to be fast. -#if defined(SKNX_IS_FAST) if (SkShader::kClamp_TileMode == linearGradient.fTileMode && kLinear_MatrixClass == fDstToIndexClass) { this->shade4_clamp(x, y, dstC, count); return; } -#endif SkPoint srcPt; SkMatrix::MapXYProc dstProc = fDstToIndexProc; @@ -295,15 +468,15 @@ void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* if (fDstToIndexClass != kPerspective_MatrixClass) { dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf, &srcPt); - SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX); + SkGradFixed dx, fx = SkScalarPinToGradFixed(srcPt.fX); if (fDstToIndexClass == kFixedStepInX_MatrixClass) { const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y)); // todo: do we need a real/high-precision value for dx here? - dx = SkScalarToGradFixed(step.fX); + dx = SkScalarPinToGradFixed(step.fX); } else { SkASSERT(fDstToIndexClass == kLinear_MatrixClass); - dx = SkScalarToGradFixed(fDstToIndex.getScaleX()); + dx = SkScalarPinToGradFixed(fDstToIndex.getScaleX()); } LinearShadeProc shadeProc = shadeSpan_linear_repeat; @@ -343,7 +516,7 @@ SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { #if SK_SUPPORT_GPU #include "GrColorSpaceXform.h" -#include "glsl/GrGLSLCaps.h" +#include "GrShaderCaps.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "SkGr.h" @@ -357,19 +530,18 @@ public: return sk_sp(new GrLinearGradient(args)); } - virtual ~GrLinearGradient() { } + ~GrLinearGradient() override {} const char* name() const override { return "Linear Gradient"; } private: - GrLinearGradient(const CreateArgs& args) - : INHERITED(args) { + GrLinearGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) { this->initClassID(); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, + virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; @@ -383,11 +555,11 @@ class GrLinearGradient::GLSLLinearProcessor : public GrGradientEffect::GLSLProce public: GLSLLinearProcessor(const GrProcessor&) {} - virtual ~GLSLLinearProcessor() { } + ~GLSLLinearProcessor() override {} virtual void emitCode(EmitArgs&) override; - static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + static void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { b->add32(GenBaseGradientKey(processor)); } @@ -401,7 +573,7 @@ GrGLSLFragmentProcessor* GrLinearGradient::onCreateGLSLInstance() const { return new GrLinearGradient::GLSLLinearProcessor(*this); } -void GrLinearGradient::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrLinearGradient::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrLinearGradient::GLSLLinearProcessor::GenKey(*this, caps, b); } @@ -410,24 +582,23 @@ void GrLinearGradient::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrLinearGradient); +#if GR_TEST_UTILS sk_sp GrLinearGradient::TestCreate(GrProcessorTestData* d) { SkPoint points[] = {{d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}, {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}}; - SkColor colors[kMaxRandomGradientColors]; - SkScalar stopsArray[kMaxRandomGradientColors]; - SkScalar* stops = stopsArray; - SkShader::TileMode tm; - int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm); - auto shader = SkGradientShader::MakeLinear(points, colors, stops, colorCount, tm); - SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom); - auto dstColorSpace = GrTest::TestColorSpace(d->fRandom); - sk_sp fp = shader->asFragmentProcessor(SkShader::AsFPArgs( - d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(), - SkSourceGammaTreatment::kRespect)); + RandomGradientParams params(d->fRandom); + auto shader = params.fUseColors4f ? + SkGradientShader::MakeLinear(points, params.fColors4f, params.fColorSpace, params.fStops, + params.fColorCount, params.fTileMode) : + SkGradientShader::MakeLinear(points, params.fColors, params.fStops, + params.fColorCount, params.fTileMode); + GrTest::TestAsFPArgs asFPArgs(d); + sk_sp fp = shader->asFragmentProcessor(asFPArgs.args()); GrAlwaysAssert(fp); return fp; } +#endif ///////////////////////////////////////////////////////////////////// @@ -438,7 +609,7 @@ void GrLinearGradient::GLSLLinearProcessor::emitCode(EmitArgs& args) { t.append(".x"); this->emitColor(args.fFragBuilder, args.fUniformHandler, - args.fGLSLCaps, + args.fShaderCaps, ge, t.c_str(), args.fOutputColor, @@ -525,25 +696,46 @@ find_backward(const SkLinearGradient::LinearGradientContext::Rec rec[], float ti return rec; } -template SkPMColor trunc_from_255(const Sk4f& x) { +// As an optimization, we can apply the dither bias before interpolation -- but only when +// operating in premul space (apply_alpha == false). When apply_alpha == true, we must +// defer the bias application until after premul. +// +// The following two helpers encapsulate this logic: pre_bias is called before interpolation, +// and effects the bias when apply_alpha == false, while post_bias is called after premul and +// effects the bias for the apply_alpha == true case. + +template +Sk4f pre_bias(const Sk4f& x, const Sk4f& bias) { + return apply_alpha ? x : x + bias; +} + +template +Sk4f post_bias(const Sk4f& x, const Sk4f& bias) { + return apply_alpha ? x + bias : x; +} + +template SkPMColor trunc_from_255(const Sk4f& x, const Sk4f& bias) { SkPMColor c; - SkNx_cast(x).store(&c); + Sk4f c4f255 = x; if (apply_alpha) { - c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c), - SkGetPackedG32(c), SkGetPackedB32(c)); + const float scale = x[SkPM4f::A] * (1 / 255.f); + c4f255 *= Sk4f(scale, scale, scale, 1); } + SkNx_cast(post_bias(c4f255, bias)).store(&c); + return c; } template void fill(SkPMColor dst[], int count, - const Sk4f& c4, const Sk4f& c4other) { - sk_memset32_dither(dst, trunc_from_255(c4), - trunc_from_255(c4other), count); + const Sk4f& c4, const Sk4f& bias0, const Sk4f& bias1) { + const SkPMColor c0 = trunc_from_255(pre_bias(c4, bias0), bias0); + const SkPMColor c1 = trunc_from_255(pre_bias(c4, bias1), bias1); + sk_memset32_dither(dst, c0, c1, count); } template void fill(SkPMColor dst[], int count, const Sk4f& c4) { // Assumes that c4 does not need to be dithered. - sk_memset32(dst, trunc_from_255(c4), count); + sk_memset32(dst, trunc_from_255(c4, 0), count); } /* @@ -573,8 +765,8 @@ template void ramp(SkPMColor dstC[], int n, const Sk4f& c, co const Sk4f& dither0, const Sk4f& dither1) { Sk4f dc2 = dc + dc; Sk4f dc4 = dc2 + dc2; - Sk4f cd0 = c + dither0; - Sk4f cd1 = c + dc + dither1; + Sk4f cd0 = pre_bias(c , dither0); + Sk4f cd1 = pre_bias(c + dc, dither1); Sk4f cd2 = cd0 + dc2; Sk4f cd3 = cd1 + dc2; while (n >= 4) { @@ -582,10 +774,10 @@ template void ramp(SkPMColor dstC[], int n, const Sk4f& c, co Sk4f_ToBytes((uint8_t*)dstC, cd0, cd1, cd2, cd3); dstC += 4; } else { - *dstC++ = trunc_from_255(cd0); - *dstC++ = trunc_from_255(cd1); - *dstC++ = trunc_from_255(cd2); - *dstC++ = trunc_from_255(cd3); + *dstC++ = trunc_from_255(cd0, dither0); + *dstC++ = trunc_from_255(cd1, dither1); + *dstC++ = trunc_from_255(cd2, dither0); + *dstC++ = trunc_from_255(cd3, dither1); } cd0 = cd0 + dc4; cd1 = cd1 + dc4; @@ -594,12 +786,12 @@ template void ramp(SkPMColor dstC[], int n, const Sk4f& c, co n -= 4; } if (n & 2) { - *dstC++ = trunc_from_255(cd0); - *dstC++ = trunc_from_255(cd1); + *dstC++ = trunc_from_255(cd0, dither0); + *dstC++ = trunc_from_255(cd1, dither1); cd0 = cd0 + dc2; } if (n & 1) { - *dstC++ = trunc_from_255(cd0); + *dstC++ = trunc_from_255(cd0, dither0); } } @@ -740,19 +932,20 @@ void SkLinearGradient::LinearGradientContext::shade4_clamp(int x, int y, SkPMCol } } const float dither[2] = { dither0, dither1 }; - const float invDx = 1 / dx; if (SkScalarNearlyZero(dx * count)) { // gradient is vertical const float pinFx = SkTPin(fx, 0.0f, 1.0f); Sk4f c = lerp_color(pinFx, find_forward(fRecs.begin(), pinFx)); if (fApplyAlphaAfterInterp) { - fill(dstC, count, c + dither0, c + dither1); + fill(dstC, count, c, dither0, dither1); } else { - fill(dstC, count, c + dither0, c + dither1); + fill(dstC, count, c, dither0, dither1); } return; } + SkASSERT(0.f != dx); + const float invDx = 1 / dx; if (dx > 0) { if (fApplyAlphaAfterInterp) { this->shade4_dx_clamp(dstC, count, fx, dx, invDx, dither); diff --git a/gfx/skia/skia/src/effects/gradients/SkLinearGradient.h b/gfx/skia/skia/src/effects/gradients/SkLinearGradient.h index 7a85b88cb79d..4118deeae5dd 100644 --- a/gfx/skia/skia/src/effects/gradients/SkLinearGradient.h +++ b/gfx/skia/skia/src/effects/gradients/SkLinearGradient.h @@ -66,8 +66,10 @@ public: protected: SkLinearGradient(SkReadBuffer& buffer); void flatten(SkWriteBuffer& buffer) const override; - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec&, void* storage) const override; + Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override; + + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + const SkMatrix&, const SkPaint&, const SkMatrix*) const override; private: class LinearGradient4fContext; diff --git a/gfx/skia/skia/src/effects/gradients/SkRadialGradient.cpp b/gfx/skia/skia/src/effects/gradients/SkRadialGradient.cpp index 18ef3768620f..2caf905a51b0 100644 --- a/gfx/skia/skia/src/effects/gradients/SkRadialGradient.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkRadialGradient.cpp @@ -39,12 +39,10 @@ SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, const , fRadius(radius) { } -size_t SkRadialGradient::onContextSize(const ContextRec&) const { - return sizeof(RadialGradientContext); -} - -SkShader::Context* SkRadialGradient::onCreateContext(const ContextRec& rec, void* storage) const { - return CheckedCreateContext(storage, *this, rec); +SkShader::Context* SkRadialGradient::onMakeContext( + const ContextRec& rec, SkArenaAlloc* alloc) const +{ + return CheckedMakeContext(alloc, *this, rec); } SkRadialGradient::RadialGradientContext::RadialGradientContext( @@ -240,7 +238,7 @@ void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y, #if SK_SUPPORT_GPU #include "SkGr.h" -#include "glsl/GrGLSLCaps.h" +#include "GrShaderCaps.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" class GrRadialGradient : public GrGradientEffect { @@ -251,19 +249,18 @@ public: return sk_sp(new GrRadialGradient(args)); } - virtual ~GrRadialGradient() { } + ~GrRadialGradient() override {} const char* name() const override { return "Radial Gradient"; } private: - GrRadialGradient(const CreateArgs& args) - : INHERITED(args) { + GrRadialGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) { this->initClassID(); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, + virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; @@ -276,11 +273,11 @@ private: class GrRadialGradient::GLSLRadialProcessor : public GrGradientEffect::GLSLProcessor { public: GLSLRadialProcessor(const GrProcessor&) {} - virtual ~GLSLRadialProcessor() { } + ~GLSLRadialProcessor() override {} virtual void emitCode(EmitArgs&) override; - static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + static void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { b->add32(GenBaseGradientKey(processor)); } @@ -295,7 +292,7 @@ GrGLSLFragmentProcessor* GrRadialGradient::onCreateGLSLInstance() const { return new GrRadialGradient::GLSLRadialProcessor(*this); } -void GrRadialGradient::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrRadialGradient::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrRadialGradient::GLSLRadialProcessor::GenKey(*this, caps, b); } @@ -304,24 +301,27 @@ void GrRadialGradient::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRadialGradient); +#if GR_TEST_UTILS sk_sp GrRadialGradient::TestCreate(GrProcessorTestData* d) { - SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}; - SkScalar radius = d->fRandom->nextUScalar1(); - - SkColor colors[kMaxRandomGradientColors]; - SkScalar stopsArray[kMaxRandomGradientColors]; - SkScalar* stops = stopsArray; - SkShader::TileMode tm; - int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm); - auto shader = SkGradientShader::MakeRadial(center, radius, colors, stops, colorCount, tm); - SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom); - auto dstColorSpace = GrTest::TestColorSpace(d->fRandom); - sk_sp fp = shader->asFragmentProcessor(SkShader::AsFPArgs( - d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(), - SkSourceGammaTreatment::kRespect)); + sk_sp shader; + do { + RandomGradientParams params(d->fRandom); + SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}; + SkScalar radius = d->fRandom->nextUScalar1(); + shader = params.fUseColors4f + ? SkGradientShader::MakeRadial(center, radius, params.fColors4f, + params.fColorSpace, params.fStops, + params.fColorCount, params.fTileMode) + : SkGradientShader::MakeRadial(center, radius, params.fColors, + params.fStops, params.fColorCount, + params.fTileMode); + } while (!shader); + GrTest::TestAsFPArgs asFPArgs(d); + sk_sp fp = shader->asFragmentProcessor(asFPArgs.args()); GrAlwaysAssert(fp); return fp; } +#endif ///////////////////////////////////////////////////////////////////// @@ -333,7 +333,7 @@ void GrRadialGradient::GLSLRadialProcessor::emitCode(EmitArgs& args) { t.append(")"); this->emitColor(args.fFragBuilder, args.fUniformHandler, - args.fGLSLCaps, + args.fShaderCaps, ge, t.c_str(), args.fOutputColor, args.fInputColor, diff --git a/gfx/skia/skia/src/effects/gradients/SkRadialGradient.h b/gfx/skia/skia/src/effects/gradients/SkRadialGradient.h index 0b239039eeca..f92fbb3b72d7 100644 --- a/gfx/skia/skia/src/effects/gradients/SkRadialGradient.h +++ b/gfx/skia/skia/src/effects/gradients/SkRadialGradient.h @@ -35,8 +35,7 @@ public: protected: SkRadialGradient(SkReadBuffer& buffer); void flatten(SkWriteBuffer& buffer) const override; - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec&, void* storage) const override; + Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override; private: const SkPoint fCenter; diff --git a/gfx/skia/skia/src/effects/gradients/SkSweepGradient.cpp b/gfx/skia/skia/src/effects/gradients/SkSweepGradient.cpp index d1fe269b9cb2..79013b3322ae 100644 --- a/gfx/skia/skia/src/effects/gradients/SkSweepGradient.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkSweepGradient.cpp @@ -45,12 +45,10 @@ void SkSweepGradient::flatten(SkWriteBuffer& buffer) const { buffer.writePoint(fCenter); } -size_t SkSweepGradient::onContextSize(const ContextRec&) const { - return sizeof(SweepGradientContext); -} - -SkShader::Context* SkSweepGradient::onCreateContext(const ContextRec& rec, void* storage) const { - return CheckedCreateContext(storage, *this, rec); +SkShader::Context* SkSweepGradient::onMakeContext( + const ContextRec& rec, SkArenaAlloc* alloc) const +{ + return CheckedMakeContext(alloc, *this, rec); } SkSweepGradient::SweepGradientContext::SweepGradientContext( @@ -122,8 +120,8 @@ void SkSweepGradient::SweepGradientContext::shadeSpan(int x, int y, SkPMColor* S #if SK_SUPPORT_GPU #include "SkGr.h" +#include "GrShaderCaps.h" #include "gl/GrGLContext.h" -#include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" class GrSweepGradient : public GrGradientEffect { @@ -133,19 +131,18 @@ public: static sk_sp Make(const CreateArgs& args) { return sk_sp(new GrSweepGradient(args)); } - virtual ~GrSweepGradient() { } + ~GrSweepGradient() override {} const char* name() const override { return "Sweep Gradient"; } private: - GrSweepGradient(const CreateArgs& args) - : INHERITED(args) { + GrSweepGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) { this->initClassID(); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, + virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; @@ -158,11 +155,11 @@ private: class GrSweepGradient::GLSLSweepProcessor : public GrGradientEffect::GLSLProcessor { public: GLSLSweepProcessor(const GrProcessor&) {} - virtual ~GLSLSweepProcessor() { } + ~GLSLSweepProcessor() override {} virtual void emitCode(EmitArgs&) override; - static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + static void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { b->add32(GenBaseGradientKey(processor)); } @@ -177,7 +174,7 @@ GrGLSLFragmentProcessor* GrSweepGradient::onCreateGLSLInstance() const { return new GrSweepGradient::GLSLSweepProcessor(*this); } -void GrSweepGradient::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrSweepGradient::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrSweepGradient::GLSLSweepProcessor::GenKey(*this, caps, b); } @@ -187,24 +184,22 @@ void GrSweepGradient::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSweepGradient); +#if GR_TEST_UTILS sk_sp GrSweepGradient::TestCreate(GrProcessorTestData* d) { SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}; - SkColor colors[kMaxRandomGradientColors]; - SkScalar stopsArray[kMaxRandomGradientColors]; - SkScalar* stops = stopsArray; - SkShader::TileMode tmIgnored; - int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tmIgnored); - sk_sp shader(SkGradientShader::MakeSweep(center.fX, center.fY, colors, stops, - colorCount)); - SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom); - auto dstColorSpace = GrTest::TestColorSpace(d->fRandom); - sk_sp fp = shader->asFragmentProcessor(SkShader::AsFPArgs( - d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(), - SkSourceGammaTreatment::kRespect)); + RandomGradientParams params(d->fRandom); + auto shader = params.fUseColors4f ? + SkGradientShader::MakeSweep(center.fX, center.fY, params.fColors4f, params.fColorSpace, + params.fStops, params.fColorCount) : + SkGradientShader::MakeSweep(center.fX, center.fY, params.fColors, + params.fStops, params.fColorCount); + GrTest::TestAsFPArgs asFPArgs(d); + sk_sp fp = shader->asFragmentProcessor(asFPArgs.args()); GrAlwaysAssert(fp); return fp; } +#endif ///////////////////////////////////////////////////////////////////// @@ -214,18 +209,21 @@ void GrSweepGradient::GLSLSweepProcessor::emitCode(EmitArgs& args) { SkString coords2D = args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]); SkString t; // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi] - // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int - // thus must us -1.0 * %s.x to work correctly - if (args.fGLSLCaps->mustForceNegatedAtanParamToFloat()){ - t.printf("(atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5)", - coords2D.c_str(), coords2D.c_str()); + if (args.fShaderCaps->atan2ImplementedAsAtanYOverX()) { + // On some devices they incorrectly implement atan2(y,x) as atan(y/x). In actuality it is + // atan2(y,x) = 2 * atan(y / (sqrt(x^2 + y^2) + x)). So to work around this we pass in + // (sqrt(x^2 + y^2) + x) as the second parameter to atan2 in these cases. We let the device + // handle the undefined behavior of the second paramenter being 0 instead of doing the + // divide ourselves and using atan instead. + t.printf("(2.0 * atan(- %s.y, length(%s) - %s.x) * 0.1591549430918 + 0.5)", + coords2D.c_str(), coords2D.c_str(), coords2D.c_str()); } else { t.printf("(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5)", coords2D.c_str(), coords2D.c_str()); } this->emitColor(args.fFragBuilder, args.fUniformHandler, - args.fGLSLCaps, + args.fShaderCaps, ge, t.c_str(), args.fOutputColor, args.fInputColor, diff --git a/gfx/skia/skia/src/effects/gradients/SkSweepGradient.h b/gfx/skia/skia/src/effects/gradients/SkSweepGradient.h index f132118b391a..30ebb1ad4e4a 100644 --- a/gfx/skia/skia/src/effects/gradients/SkSweepGradient.h +++ b/gfx/skia/skia/src/effects/gradients/SkSweepGradient.h @@ -35,8 +35,7 @@ public: protected: void flatten(SkWriteBuffer& buffer) const override; - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec&, void* storage) const override; + Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override; private: const SkPoint fCenter; diff --git a/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp b/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp index 599fd4c9fdca..a9740aa45540 100644 --- a/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp @@ -210,13 +210,9 @@ bool SkTwoPointConicalGradient::isOpaque() const { return false; } -size_t SkTwoPointConicalGradient::onContextSize(const ContextRec&) const { - return sizeof(TwoPointConicalGradientContext); -} - -SkShader::Context* SkTwoPointConicalGradient::onCreateContext(const ContextRec& rec, - void* storage) const { - return CheckedCreateContext(storage, *this, rec); +SkShader::Context* SkTwoPointConicalGradient::onMakeContext( + const ContextRec& rec, SkArenaAlloc* alloc) const { + return CheckedMakeContext(alloc, *this, rec); } SkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradientContext( diff --git a/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.h b/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.h index d16e4bc3c5db..d73ba11512bf 100644 --- a/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.h +++ b/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.h @@ -47,7 +47,7 @@ public: class TwoPointConicalGradientContext : public SkGradientShaderBase::GradientShaderBaseContext { public: TwoPointConicalGradientContext(const SkTwoPointConicalGradient&, const ContextRec&); - ~TwoPointConicalGradientContext() {} + ~TwoPointConicalGradientContext() override {} void shadeSpan(int x, int y, SkPMColor dstC[], int count) override; @@ -75,8 +75,7 @@ public: protected: SkTwoPointConicalGradient(SkReadBuffer& buffer); void flatten(SkWriteBuffer& buffer) const override; - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec&, void* storage) const override; + Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override; private: SkPoint fCenter1; diff --git a/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp b/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp index a8df3b50c331..fedb4459043e 100644 --- a/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp @@ -10,7 +10,6 @@ #if SK_SUPPORT_GPU #include "GrCoordTransform.h" -#include "GrInvariantOutput.h" #include "GrPaint.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" @@ -53,8 +52,7 @@ static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader, if (0 != diffLen) { SkScalar invDiffLen = SkScalarInvert(diffLen); SkMatrix rot; - rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY), - SkScalarMul(invDiffLen, diff.fX)); + rot.setSinCos(-invDiffLen * diff.fY, invDiffLen * diff.fX); invLMatrix->postConcat(rot); } } @@ -67,7 +65,7 @@ public: return sk_sp(new Edge2PtConicalEffect(args)); } - virtual ~Edge2PtConicalEffect() {} + ~Edge2PtConicalEffect() override {} const char* name() const override { return "Two-Point Conical Gradient Edge Touching"; @@ -81,7 +79,7 @@ public: private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor& sBase) const override { const Edge2PtConicalEffect& s = sBase.cast(); @@ -92,7 +90,7 @@ private: } Edge2PtConicalEffect(const CreateArgs& args) - : INHERITED(args) { + : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */) { const SkTwoPointConicalGradient& shader = *static_cast(args.fShader); fCenterX1 = shader.getCenterX1(); @@ -112,13 +110,13 @@ private: // float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z) fBTransform = this->getCoordTransform(); SkMatrix& bMatrix = *fBTransform.accessMatrix(); - SkScalar r0dr = SkScalarMul(fRadius0, fDiffRadius); - bMatrix[SkMatrix::kMScaleX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMScaleX]) + - SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp0])); - bMatrix[SkMatrix::kMSkewX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMSkewX]) + - SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp1])); - bMatrix[SkMatrix::kMTransX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMTransX]) + - SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp2])); + SkScalar r0dr = fRadius0 * fDiffRadius; + bMatrix[SkMatrix::kMScaleX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMScaleX] + + r0dr * bMatrix[SkMatrix::kMPersp0]); + bMatrix[SkMatrix::kMSkewX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMSkewX] + + r0dr * bMatrix[SkMatrix::kMPersp1]); + bMatrix[SkMatrix::kMTransX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMTransX] + + r0dr * bMatrix[SkMatrix::kMPersp2]); this->addCoordTransform(&fBTransform); } @@ -141,14 +139,14 @@ private: class Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor : public GrGradientEffect::GLSLProcessor { public: GLSLEdge2PtConicalProcessor(const GrProcessor&); - virtual ~GLSLEdge2PtConicalProcessor() { } + ~GLSLEdge2PtConicalProcessor() override {} virtual void emitCode(EmitArgs&) override; - static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b); + static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; UniformHandle fParamUni; @@ -168,7 +166,7 @@ private: }; -void Edge2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void Edge2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(*this, caps, b); } @@ -182,6 +180,7 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Edge2PtConicalEffect); /* * All Two point conical gradient test create functions may occasionally create edge case shaders */ +#if GR_TEST_UTILS sk_sp Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) { SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}; SkScalar radius1 = d->fRandom->nextUScalar1(); @@ -199,21 +198,20 @@ sk_sp Edge2PtConicalEffect::TestCreate(GrProcessorTestData* SkScalar diffLen = diff.length(); radius2 = radius1 + diffLen; - SkColor colors[kMaxRandomGradientColors]; - SkScalar stopsArray[kMaxRandomGradientColors]; - SkScalar* stops = stopsArray; - SkShader::TileMode tm; - int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm); - auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, - colors, stops, colorCount, tm); - SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom); - auto dstColorSpace = GrTest::TestColorSpace(d->fRandom); - sk_sp fp = shader->asFragmentProcessor(SkShader::AsFPArgs( - d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(), - SkSourceGammaTreatment::kRespect)); + RandomGradientParams params(d->fRandom); + auto shader = params.fUseColors4f ? + SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, + params.fColors4f, params.fColorSpace, params.fStops, + params.fColorCount, params.fTileMode) : + SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, + params.fColors, params.fStops, + params.fColorCount, params.fTileMode); + GrTest::TestAsFPArgs asFPArgs(d); + sk_sp fp = shader->asFragmentProcessor(asFPArgs.args()); GrAlwaysAssert(fp); return fp; } +#endif Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GLSLEdge2PtConicalProcessor(const GrProcessor&) : fVSVaryingName(nullptr) @@ -276,7 +274,7 @@ void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::emitCode(EmitArgs& args) fragBuilder->codeAppend("\t"); this->emitColor(fragBuilder, uniformHandler, - args.fGLSLCaps, + args.fShaderCaps, ge, tName.c_str(), args.fOutputColor, @@ -286,8 +284,7 @@ void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::emitCode(EmitArgs& args) } void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::onSetData( - const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { INHERITED::onSetData(pdman, processor); const Edge2PtConicalEffect& data = processor.cast(); SkScalar radius0 = data.radius(); @@ -296,15 +293,14 @@ void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::onSetData( if (fCachedRadius != radius0 || fCachedDiffRadius != diffRadius) { - pdman.set3f(fParamUni, SkScalarToFloat(radius0), - SkScalarToFloat(SkScalarMul(radius0, radius0)), SkScalarToFloat(diffRadius)); + pdman.set3f(fParamUni, radius0, radius0 * radius0, diffRadius); fCachedRadius = radius0; fCachedDiffRadius = diffRadius; } } void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(const GrProcessor& processor, - const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + const GrShaderCaps&, GrProcessorKeyBuilder* b) { b->add32(GenBaseGradientKey(processor)); } @@ -335,8 +331,7 @@ static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& sha if (0.f != *focalX) { SkScalar invFocalX = SkScalarInvert(*focalX); SkMatrix rot; - rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY), - SkScalarMul(invFocalX, focalTrans.fX)); + rot.setSinCos(-invFocalX * focalTrans.fY, invFocalX * focalTrans.fX); matrix.postConcat(rot); } @@ -351,7 +346,7 @@ static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& sha } // Scale factor 1 / (1 - focalX * focalX) - SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX); + SkScalar oneMinusF2 = 1.f - *focalX * *focalX; SkScalar s = SkScalarInvert(oneMinusF2); @@ -379,7 +374,7 @@ public: new FocalOutside2PtConicalEffect(args, focalX)); } - virtual ~FocalOutside2PtConicalEffect() { } + ~FocalOutside2PtConicalEffect() override {} const char* name() const override { return "Two-Point Conical Gradient Focal Outside"; @@ -391,7 +386,7 @@ public: private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor& sBase) const override { const FocalOutside2PtConicalEffect& s = sBase.cast(); @@ -400,10 +395,15 @@ private: this->fIsFlipped == s.fIsFlipped); } + static bool IsFlipped(const CreateArgs& args) { + // eww. + return static_cast(args.fShader)->isFlippedGrad(); + } + FocalOutside2PtConicalEffect(const CreateArgs& args, SkScalar focalX) - : INHERITED(args) - , fFocalX(focalX) - , fIsFlipped(static_cast(args.fShader)->isFlippedGrad()) { + : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */) + , fFocalX(focalX) + , fIsFlipped(IsFlipped(args)) { this->initClassID(); } @@ -415,18 +415,18 @@ private: typedef GrGradientEffect INHERITED; }; -class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor +class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor : public GrGradientEffect::GLSLProcessor { public: GLSLFocalOutside2PtConicalProcessor(const GrProcessor&); - virtual ~GLSLFocalOutside2PtConicalProcessor() { } + ~GLSLFocalOutside2PtConicalProcessor() override {} virtual void emitCode(EmitArgs&) override; - static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b); + static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; UniformHandle fParamUni; @@ -447,7 +447,7 @@ private: }; -void FocalOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void FocalOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(*this, caps, b); } @@ -461,6 +461,7 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect); /* * All Two point conical gradient test create functions may occasionally create edge case shaders */ +#if GR_TEST_UTILS sk_sp FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) { SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}; SkScalar radius1 = 0.f; @@ -470,26 +471,26 @@ sk_sp FocalOutside2PtConicalEffect::TestCreate(GrProcessorT center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()); // Need to make sure the centers are not the same or else focal point will be inside } while (center1 == center2); - SkPoint diff = center2 - center1; - SkScalar diffLen = diff.length(); - // Below makes sure that the focal point is not contained within circle two - radius2 = d->fRandom->nextRangeF(0.f, diffLen); - SkColor colors[kMaxRandomGradientColors]; - SkScalar stopsArray[kMaxRandomGradientColors]; - SkScalar* stops = stopsArray; - SkShader::TileMode tm; - int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm); - auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, - colors, stops, colorCount, tm); - SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom); - auto dstColorSpace = GrTest::TestColorSpace(d->fRandom); - sk_sp fp = shader->asFragmentProcessor(SkShader::AsFPArgs( - d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(), - SkSourceGammaTreatment::kRespect)); + SkPoint diff = center2 - center1; + SkScalar diffLen = diff.length(); + // Below makes sure that the focal point is not contained within circle two + radius2 = d->fRandom->nextRangeF(0.f, diffLen); + + RandomGradientParams params(d->fRandom); + auto shader = params.fUseColors4f ? + SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, + params.fColors4f, params.fColorSpace, params.fStops, + params.fColorCount, params.fTileMode) : + SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, + params.fColors, params.fStops, + params.fColorCount, params.fTileMode); + GrTest::TestAsFPArgs asFPArgs(d); + sk_sp fp = shader->asFragmentProcessor(asFPArgs.args()); GrAlwaysAssert(fp); return fp; } +#endif FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor ::GLSLFocalOutside2PtConicalProcessor(const GrProcessor& processor) @@ -543,7 +544,7 @@ void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::emitCode fragBuilder->codeAppend("\t\t"); this->emitColor(fragBuilder, uniformHandler, - args.fGLSLCaps, + args.fShaderCaps, ge, tName.c_str(), args.fOutputColor, @@ -553,15 +554,14 @@ void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::emitCode } void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::onSetData( - const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { INHERITED::onSetData(pdman, processor); const FocalOutside2PtConicalEffect& data = processor.cast(); SkASSERT(data.isFlipped() == fIsFlipped); SkScalar focal = data.focal(); if (fCachedFocal != focal) { - SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal); + SkScalar oneMinus2F = 1.f - focal * focal; pdman.set2f(fParamUni, SkScalarToFloat(focal), SkScalarToFloat(oneMinus2F)); fCachedFocal = focal; @@ -570,7 +570,7 @@ void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::onSetDat void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey( const GrProcessor& processor, - const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + const GrShaderCaps&, GrProcessorKeyBuilder* b) { uint32_t* key = b->add32n(2); key[0] = GenBaseGradientKey(processor); key[1] = processor.cast().isFlipped(); @@ -587,7 +587,7 @@ public: new FocalInside2PtConicalEffect(args, focalX)); } - virtual ~FocalInside2PtConicalEffect() {} + ~FocalInside2PtConicalEffect() override {} const char* name() const override { return "Two-Point Conical Gradient Focal Inside"; @@ -600,7 +600,7 @@ public: private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor& sBase) const override { const FocalInside2PtConicalEffect& s = sBase.cast(); @@ -609,7 +609,7 @@ private: } FocalInside2PtConicalEffect(const CreateArgs& args, SkScalar focalX) - : INHERITED(args), fFocalX(focalX) { + : INHERITED(args, args.fShader->colorsAreOpaque()), fFocalX(focalX) { this->initClassID(); } @@ -624,14 +624,14 @@ class FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor : public GrGradientEffect::GLSLProcessor { public: GLSLFocalInside2PtConicalProcessor(const GrProcessor&); - virtual ~GLSLFocalInside2PtConicalProcessor() {} + ~GLSLFocalInside2PtConicalProcessor() override {} virtual void emitCode(EmitArgs&) override; - static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b); + static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; UniformHandle fFocalUni; @@ -650,7 +650,7 @@ private: }; -void FocalInside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void FocalInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(*this, caps, b); } @@ -664,6 +664,7 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect); /* * All Two point conical gradient test create functions may occasionally create edge case shaders */ +#if GR_TEST_UTILS sk_sp FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) { SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}; SkScalar radius1 = 0.f; @@ -680,21 +681,20 @@ sk_sp FocalInside2PtConicalEffect::TestCreate(GrProcessorTe // If the circles are identical the factory will give us an empty shader. } while (radius1 == radius2 && center1 == center2); - SkColor colors[kMaxRandomGradientColors]; - SkScalar stopsArray[kMaxRandomGradientColors]; - SkScalar* stops = stopsArray; - SkShader::TileMode tm; - int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm); - auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, - colors, stops, colorCount, tm); - SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom); - auto dstColorSpace = GrTest::TestColorSpace(d->fRandom); - sk_sp fp = shader->asFragmentProcessor(SkShader::AsFPArgs( - d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(), - SkSourceGammaTreatment::kRespect)); + RandomGradientParams params(d->fRandom); + auto shader = params.fUseColors4f ? + SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, + params.fColors4f, params.fColorSpace, params.fStops, + params.fColorCount, params.fTileMode) : + SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, + params.fColors, params.fStops, + params.fColorCount, params.fTileMode); + GrTest::TestAsFPArgs asFPArgs(d); + sk_sp fp = shader->asFragmentProcessor(asFPArgs.args()); GrAlwaysAssert(fp); return fp; } +#endif FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor ::GLSLFocalInside2PtConicalProcessor(const GrProcessor&) @@ -713,7 +713,7 @@ void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::emitCode(E // this is the distance along x-axis from the end center to focal point in // transformed coordinates - GrGLSLShaderVar focal = uniformHandler->getUniformVariable(fFocalUni); + GrShaderVar focal = uniformHandler->getUniformVariable(fFocalUni); // if we have a vec3 from being in perspective, convert it to a vec2 first GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -726,7 +726,7 @@ void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::emitCode(E this->emitColor(fragBuilder, uniformHandler, - args.fGLSLCaps, + args.fShaderCaps, ge, tName.c_str(), args.fOutputColor, @@ -735,8 +735,7 @@ void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::emitCode(E } void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::onSetData( - const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { INHERITED::onSetData(pdman, processor); const FocalInside2PtConicalEffect& data = processor.cast(); SkScalar focal = data.focal(); @@ -749,7 +748,7 @@ void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::onSetData( void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey( const GrProcessor& processor, - const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + const GrShaderCaps&, GrProcessorKeyBuilder* b) { b->add32(GenBaseGradientKey(processor)); } @@ -826,7 +825,7 @@ public: new CircleInside2PtConicalEffect(args, info)); } - virtual ~CircleInside2PtConicalEffect() {} + ~CircleInside2PtConicalEffect() override {} const char* name() const override { return "Two-Point Conical Gradient Inside"; } @@ -839,7 +838,7 @@ public: private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, + virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; bool onIsEqual(const GrFragmentProcessor& sBase) const override { @@ -852,7 +851,7 @@ private: } CircleInside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info) - : INHERITED(args), fInfo(info) { + : INHERITED(args, args.fShader->colorsAreOpaque()), fInfo(info) { this->initClassID(); } @@ -867,14 +866,14 @@ class CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor : public GrGradientEffect::GLSLProcessor { public: GLSLCircleInside2PtConicalProcessor(const GrProcessor&); - virtual ~GLSLCircleInside2PtConicalProcessor() {} + ~GLSLCircleInside2PtConicalProcessor() override {} virtual void emitCode(EmitArgs&) override; - static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b); + static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; UniformHandle fCenterUni; UniformHandle fParamUni; @@ -898,7 +897,7 @@ private: }; -void CircleInside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void CircleInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(*this, caps, b); } @@ -912,6 +911,7 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect); /* * All Two point conical gradient test create functions may occasionally create edge case shaders */ +#if GR_TEST_UTILS sk_sp CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) { SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}; SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0 @@ -927,21 +927,20 @@ sk_sp CircleInside2PtConicalEffect::TestCreate(GrProcessorT // If the circles are identical the factory will give us an empty shader. } while (radius1 == radius2 && center1 == center2); - SkColor colors[kMaxRandomGradientColors]; - SkScalar stopsArray[kMaxRandomGradientColors]; - SkScalar* stops = stopsArray; - SkShader::TileMode tm; - int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm); - auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, - colors, stops, colorCount, tm); - SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom); - auto dstColorSpace = GrTest::TestColorSpace(d->fRandom); - sk_sp fp = shader->asFragmentProcessor(SkShader::AsFPArgs( - d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(), - SkSourceGammaTreatment::kRespect)); + RandomGradientParams params(d->fRandom); + auto shader = params.fUseColors4f ? + SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, + params.fColors4f, params.fColorSpace, params.fStops, + params.fColorCount, params.fTileMode) : + SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, + params.fColors, params.fStops, + params.fColorCount, params.fTileMode); + GrTest::TestAsFPArgs asFPArgs(d); + sk_sp fp = shader->asFragmentProcessor(asFPArgs.args()); GrAlwaysAssert(fp); return fp; } +#endif CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor ::GLSLCircleInside2PtConicalProcessor(const GrProcessor& processor) @@ -965,11 +964,11 @@ void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::emitCode "Conical2FSParams"); SkString tName("t"); - GrGLSLShaderVar center = uniformHandler->getUniformVariable(fCenterUni); + GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni); // params.x = A // params.y = B // params.z = C - GrGLSLShaderVar params = uniformHandler->getUniformVariable(fParamUni); + GrShaderVar params = uniformHandler->getUniformVariable(fParamUni); // if we have a vec3 from being in perspective, convert it to a vec2 first GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -992,7 +991,7 @@ void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::emitCode this->emitColor(fragBuilder, uniformHandler, - args.fGLSLCaps, + args.fShaderCaps, ge, tName.c_str(), args.fOutputColor, @@ -1001,8 +1000,7 @@ void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::emitCode } void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::onSetData( - const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { INHERITED::onSetData(pdman, processor); const CircleInside2PtConicalEffect& data = processor.cast(); SkScalar centerX = data.centerX(); @@ -1027,7 +1025,7 @@ void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::onSetDat void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey( const GrProcessor& processor, - const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + const GrShaderCaps&, GrProcessorKeyBuilder* b) { b->add32(GenBaseGradientKey(processor)); } @@ -1042,7 +1040,7 @@ public: new CircleOutside2PtConicalEffect(args, info)); } - virtual ~CircleOutside2PtConicalEffect() {} + ~CircleOutside2PtConicalEffect() override {} const char* name() const override { return "Two-Point Conical Gradient Outside"; } @@ -1057,7 +1055,7 @@ public: private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor& sBase) const override { const CircleOutside2PtConicalEffect& s = sBase.cast(); @@ -1071,7 +1069,8 @@ private: } CircleOutside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info) - : INHERITED(args), fInfo(info) { + : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */) + , fInfo(info) { this->initClassID(); const SkTwoPointConicalGradient& shader = *static_cast(args.fShader); @@ -1097,14 +1096,14 @@ class CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor : public GrGradientEffect::GLSLProcessor { public: GLSLCircleOutside2PtConicalProcessor(const GrProcessor&); - virtual ~GLSLCircleOutside2PtConicalProcessor() {} + ~GLSLCircleOutside2PtConicalProcessor() override {} virtual void emitCode(EmitArgs&) override; - static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b); + static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; UniformHandle fCenterUni; UniformHandle fParamUni; @@ -1131,7 +1130,7 @@ private: }; -void CircleOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void CircleOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(*this, caps, b); } @@ -1145,6 +1144,7 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect); /* * All Two point conical gradient test create functions may occasionally create edge case shaders */ +#if GR_TEST_UTILS sk_sp CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) { SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}; SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0 @@ -1161,21 +1161,20 @@ sk_sp CircleOutside2PtConicalEffect::TestCreate(GrProcessor // and have radius2 >= radius to match sorting on cpu side radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen); - SkColor colors[kMaxRandomGradientColors]; - SkScalar stopsArray[kMaxRandomGradientColors]; - SkScalar* stops = stopsArray; - SkShader::TileMode tm; - int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm); - auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, - colors, stops, colorCount, tm); - SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom); - auto dstColorSpace = GrTest::TestColorSpace(d->fRandom); - sk_sp fp = shader->asFragmentProcessor(SkShader::AsFPArgs( - d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(), - SkSourceGammaTreatment::kRespect)); + RandomGradientParams params(d->fRandom); + auto shader = params.fUseColors4f ? + SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, + params.fColors4f, params.fColorSpace, params.fStops, + params.fColorCount, params.fTileMode) : + SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, + params.fColors, params.fStops, + params.fColorCount, params.fTileMode); + GrTest::TestAsFPArgs asFPArgs(d); + sk_sp fp = shader->asFragmentProcessor(asFPArgs.args()); GrAlwaysAssert(fp); return fp; } +#endif CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor ::GLSLCircleOutside2PtConicalProcessor(const GrProcessor& processor) @@ -1203,11 +1202,11 @@ void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::emitCo "Conical2FSParams"); SkString tName("t"); - GrGLSLShaderVar center = uniformHandler->getUniformVariable(fCenterUni); + GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni); // params.x = A // params.y = B // params.z = C - GrGLSLShaderVar params = uniformHandler->getUniformVariable(fParamUni); + GrShaderVar params = uniformHandler->getUniformVariable(fParamUni); // if we have a vec3 from being in perspective, convert it to a vec2 first GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -1246,7 +1245,7 @@ void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::emitCo fragBuilder->codeAppend("\t\t"); this->emitColor(fragBuilder, uniformHandler, - args.fGLSLCaps, + args.fShaderCaps, ge, tName.c_str(), args.fOutputColor, @@ -1256,8 +1255,7 @@ void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::emitCo } void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::onSetData( - const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { INHERITED::onSetData(pdman, processor); const CircleOutside2PtConicalEffect& data = processor.cast(); SkASSERT(data.isFlipped() == fIsFlipped); @@ -1286,7 +1284,7 @@ void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::onSetD void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey( const GrProcessor& processor, - const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + const GrShaderCaps&, GrProcessorKeyBuilder* b) { uint32_t* key = b->add32n(2); key[0] = GenBaseGradientKey(processor); key[1] = processor.cast().isFlipped(); diff --git a/gfx/skia/skia/src/effects/shadows/SkAmbientShadowMaskFilter.cpp b/gfx/skia/skia/src/effects/shadows/SkAmbientShadowMaskFilter.cpp new file mode 100644 index 000000000000..e6a8de4141e4 --- /dev/null +++ b/gfx/skia/skia/src/effects/shadows/SkAmbientShadowMaskFilter.cpp @@ -0,0 +1,298 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkAmbientShadowMaskFilter.h" +#include "SkReadBuffer.h" +#include "SkStringUtils.h" +#include "SkWriteBuffer.h" + +#if SK_SUPPORT_GPU +#include "GrContext.h" +#include "GrRenderTargetContext.h" +#include "GrFragmentProcessor.h" +#include "GrStyle.h" +#include "GrTexture.h" +#include "GrTextureProxy.h" +#include "SkStrokeRec.h" +#endif + +class SkAmbientShadowMaskFilterImpl : public SkMaskFilter { +public: + SkAmbientShadowMaskFilterImpl(SkScalar occluderHeight, SkScalar ambientAlpha, uint32_t flags); + + // overrides from SkMaskFilter + SkMask::Format getFormat() const override; + bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, + SkIPoint* margin) const override; + +#if SK_SUPPORT_GPU + bool canFilterMaskGPU(const SkRRect& devRRect, + const SkIRect& clipBounds, + const SkMatrix& ctm, + SkRect* maskRect) const override; + bool directFilterMaskGPU(GrContext*, + GrRenderTargetContext* drawContext, + GrPaint&&, + const GrClip&, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkPath& path) const override; + bool directFilterRRectMaskGPU(GrContext*, + GrRenderTargetContext* drawContext, + GrPaint&&, + const GrClip&, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkRRect& rrect, + const SkRRect& devRRect) const override; + sk_sp filterMaskGPU(GrContext*, + sk_sp srcProxy, + const SkMatrix& ctm, + const SkIRect& maskRect) const override; +#endif + + void computeFastBounds(const SkRect&, SkRect*) const override; + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkAmbientShadowMaskFilterImpl) + +private: + SkScalar fOccluderHeight; + SkScalar fAmbientAlpha; + uint32_t fFlags; + + SkAmbientShadowMaskFilterImpl(SkReadBuffer&); + void flatten(SkWriteBuffer&) const override; + + friend class SkAmbientShadowMaskFilter; + + typedef SkMaskFilter INHERITED; +}; + +sk_sp SkAmbientShadowMaskFilter::Make(SkScalar occluderHeight, SkScalar ambientAlpha, + uint32_t flags) { + // add some param checks here for early exit + + return sk_sp(new SkAmbientShadowMaskFilterImpl(occluderHeight, ambientAlpha, + flags)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SkAmbientShadowMaskFilterImpl::SkAmbientShadowMaskFilterImpl(SkScalar occluderHeight, + SkScalar ambientAlpha, + uint32_t flags) + : fOccluderHeight(occluderHeight) + , fAmbientAlpha(ambientAlpha) + , fFlags(flags) { + SkASSERT(fOccluderHeight > 0); + SkASSERT(fAmbientAlpha >= 0); +} + +SkMask::Format SkAmbientShadowMaskFilterImpl::getFormat() const { + return SkMask::kA8_Format; +} + +bool SkAmbientShadowMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, + const SkMatrix& matrix, + SkIPoint* margin) const { + // TODO something + return false; +} + +void SkAmbientShadowMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) const { + // TODO compute based on ambient data + dst->set(src.fLeft, src.fTop, src.fRight, src.fBottom); +} + +sk_sp SkAmbientShadowMaskFilterImpl::CreateProc(SkReadBuffer& buffer) { + const SkScalar occluderHeight = buffer.readScalar(); + const SkScalar ambientAlpha = buffer.readScalar(); + const uint32_t flags = buffer.readUInt(); + + return SkAmbientShadowMaskFilter::Make(occluderHeight, ambientAlpha, flags); +} + +void SkAmbientShadowMaskFilterImpl::flatten(SkWriteBuffer& buffer) const { + buffer.writeScalar(fOccluderHeight); + buffer.writeScalar(fAmbientAlpha); + buffer.writeUInt(fFlags); +} + +#if SK_SUPPORT_GPU + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +bool SkAmbientShadowMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect, + const SkIRect& clipBounds, + const SkMatrix& ctm, + SkRect* maskRect) const { + // TODO + *maskRect = devRRect.rect(); + return true; +} + +static const float kHeightFactor = 1.0f / 128.0f; +static const float kGeomFactor = 64.0f; + +bool SkAmbientShadowMaskFilterImpl::directFilterMaskGPU(GrContext* context, + GrRenderTargetContext* rtContext, + GrPaint&& paint, + const GrClip& clip, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkPath& path) const { + SkASSERT(rtContext); + // TODO: this will not handle local coordinates properly + + if (fAmbientAlpha <= 0.0f) { + return true; + } + + // only convex paths for now + if (!path.isConvex()) { + return false; + } + + if (strokeRec.getStyle() != SkStrokeRec::kFill_Style) { + return false; + } + + // if circle + // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we + // have our own GeometryProc. + if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) { + SkRRect rrect = SkRRect::MakeOval(path.getBounds()); + return this->directFilterRRectMaskGPU(context, rtContext, std::move(paint), clip, + SkMatrix::I(), strokeRec, rrect, rrect); + } else if (path.isRect(nullptr)) { + SkRRect rrect = SkRRect::MakeRect(path.getBounds()); + return this->directFilterRRectMaskGPU(context, rtContext, std::move(paint), clip, + SkMatrix::I(), strokeRec, rrect, rrect); + } + + // TODO + return false; +} + +bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*, + GrRenderTargetContext* rtContext, + GrPaint&& paint, + const GrClip& clip, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkRRect& rrect, + const SkRRect& devRRect) const { + // It's likely the caller has already done these checks, but we have to be sure. + // TODO: support analytic blurring of general rrect + + // Fast path only supports filled rrects for now. + // TODO: fill and stroke as well. + if (SkStrokeRec::kFill_Style != strokeRec.getStyle()) { + return false; + } + // Fast path only supports simple rrects with circular corners. + SkASSERT(devRRect.allCornersCircular()); + if (!rrect.isRect() && !rrect.isOval() && !rrect.isSimple()) { + return false; + } + // Fast path only supports uniform scale. + SkScalar scaleFactors[2]; + if (!viewMatrix.getMinMaxScales(scaleFactors)) { + // matrix is degenerate + return false; + } + if (scaleFactors[0] != scaleFactors[1]) { + return false; + } + SkScalar scaleFactor = scaleFactors[0]; + + // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space + const SkScalar minRadius = 0.5f / scaleFactor; + bool isRect = rrect.getSimpleRadii().fX <= minRadius; + + // TODO: take flags into account when generating shadow data + + if (fAmbientAlpha > 0.0f) { + SkScalar srcSpaceAmbientRadius = fOccluderHeight * kHeightFactor * kGeomFactor; + const float umbraAlpha = (1.0f + SkTMax(fOccluderHeight * kHeightFactor, 0.0f)); + const SkScalar strokeWidth = srcSpaceAmbientRadius * umbraAlpha; + + // For the ambient rrect, we outset the offset rect by srcSpaceAmbientRadius + // minus half the strokeWidth to get our stroke shape. + SkScalar ambientPathOutset = SkTMax(srcSpaceAmbientRadius - strokeWidth * 0.5f, + minRadius); + + SkRRect ambientRRect; + if (isRect) { + const SkRect temp = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset); + ambientRRect = SkRRect::MakeRectXY(temp, ambientPathOutset, ambientPathOutset); + } else { + rrect.outset(ambientPathOutset, ambientPathOutset, &ambientRRect); + } + + const SkScalar devSpaceAmbientRadius = strokeWidth * scaleFactor; + + GrPaint newPaint(paint); + GrColor4f color = newPaint.getColor4f(); + color.fRGBA[3] *= fAmbientAlpha; + newPaint.setColor4f(color); + SkStrokeRec ambientStrokeRec(SkStrokeRec::kHairline_InitStyle); + ambientStrokeRec.setStrokeStyle(strokeWidth, false); + + rtContext->drawShadowRRect(clip, std::move(newPaint), viewMatrix, ambientRRect, + devSpaceAmbientRadius, + GrStyle(ambientStrokeRec, nullptr)); + } + + return true; +} + +sk_sp SkAmbientShadowMaskFilterImpl::filterMaskGPU(GrContext*, + sk_sp srcProxy, + const SkMatrix& ctm, + const SkIRect& maskRect) const { + // This filter is generative and doesn't operate on pre-existing masks + return nullptr; +} + +#endif // SK_SUPPORT_GPU + +#ifndef SK_IGNORE_TO_STRING +void SkAmbientShadowMaskFilterImpl::toString(SkString* str) const { + str->append("SkAmbientShadowMaskFilterImpl: ("); + + str->append("occluderHeight: "); + str->appendScalar(fOccluderHeight); + str->append(" "); + + str->append("ambientAlpha: "); + str->appendScalar(fAmbientAlpha); + str->append(" "); + + str->append("flags: ("); + if (fFlags) { + bool needSeparator = false; + SkAddFlagToString(str, + SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag), + "TransparentOccluder", &needSeparator); + SkAddFlagToString(str, + SkToBool(fFlags & SkShadowFlags::kGaussianEdge_ShadowFlag), + "GaussianEdge", &needSeparator); + SkAddFlagToString(str, + SkToBool(fFlags & SkShadowFlags::kLargerUmbra_ShadowFlag), + "LargerUmbra", &needSeparator); + } else { + str->append("None"); + } + str->append("))"); +} +#endif + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkAmbientShadowMaskFilter) +SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkAmbientShadowMaskFilterImpl) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END diff --git a/gfx/skia/skia/src/effects/shadows/SkAmbientShadowMaskFilter.h b/gfx/skia/skia/src/effects/shadows/SkAmbientShadowMaskFilter.h new file mode 100644 index 000000000000..cd77b106a45a --- /dev/null +++ b/gfx/skia/skia/src/effects/shadows/SkAmbientShadowMaskFilter.h @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAmbientShadowMaskFilter_DEFINED +#define SkAmbientShadowMaskFilter_DEFINED + +#include "SkMaskFilter.h" +#include "SkShadowFlags.h" + +/* + * This filter implements a shadow representing ambient occlusion for an occluding object. + */ +class SK_API SkAmbientShadowMaskFilter { +public: + /** Create a shadow maskfilter. + * @param occluderHeight Height of occluding object off of ground plane. + * @param ambientAlpha Base opacity of the ambient occlusion shadow. + * @param flags Flags to use - defaults to none + * @return The new shadow maskfilter + */ + static sk_sp Make(SkScalar occluderHeight, SkScalar ambientAlpha, + uint32_t flags = SkShadowFlags::kNone_ShadowFlag); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() + +private: + SkAmbientShadowMaskFilter(); // can't be instantiated +}; +#endif diff --git a/gfx/skia/skia/src/effects/shadows/SkSpotShadowMaskFilter.cpp b/gfx/skia/skia/src/effects/shadows/SkSpotShadowMaskFilter.cpp new file mode 100644 index 000000000000..ee82342eccf6 --- /dev/null +++ b/gfx/skia/skia/src/effects/shadows/SkSpotShadowMaskFilter.cpp @@ -0,0 +1,370 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSpotShadowMaskFilter.h" +#include "SkReadBuffer.h" +#include "SkStringUtils.h" +#include "SkWriteBuffer.h" + +#if SK_SUPPORT_GPU +#include "GrContext.h" +#include "GrRenderTargetContext.h" +#include "GrFragmentProcessor.h" +#include "GrStyle.h" +#include "GrTexture.h" +#include "GrTextureProxy.h" +#include "SkStrokeRec.h" +#endif + +class SkSpotShadowMaskFilterImpl : public SkMaskFilter { +public: + SkSpotShadowMaskFilterImpl(SkScalar occluderHeight, const SkPoint3& lightPos, + SkScalar lightRadius, SkScalar spotAlpha, uint32_t flags); + + // overrides from SkMaskFilter + SkMask::Format getFormat() const override; + bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, + SkIPoint* margin) const override; + +#if SK_SUPPORT_GPU + bool canFilterMaskGPU(const SkRRect& devRRect, + const SkIRect& clipBounds, + const SkMatrix& ctm, + SkRect* maskRect) const override; + bool directFilterMaskGPU(GrContext*, + GrRenderTargetContext* drawContext, + GrPaint&&, + const GrClip&, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkPath& path) const override; + bool directFilterRRectMaskGPU(GrContext*, + GrRenderTargetContext* drawContext, + GrPaint&&, + const GrClip&, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkRRect& rrect, + const SkRRect& devRRect) const override; + sk_sp filterMaskGPU(GrContext*, + sk_sp srcProxy, + const SkMatrix& ctm, + const SkIRect& maskRect) const override; +#endif + + void computeFastBounds(const SkRect&, SkRect*) const override; + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotShadowMaskFilterImpl) + +private: + SkScalar fOccluderHeight; + SkPoint3 fLightPos; + SkScalar fLightRadius; + SkScalar fSpotAlpha; + uint32_t fFlags; + + SkSpotShadowMaskFilterImpl(SkReadBuffer&); + void flatten(SkWriteBuffer&) const override; + + friend class SkSpotShadowMaskFilter; + + typedef SkMaskFilter INHERITED; +}; + +sk_sp SkSpotShadowMaskFilter::Make(SkScalar occluderHeight, const SkPoint3& lightPos, + SkScalar lightRadius, SkScalar spotAlpha, + uint32_t flags) { + // add some param checks here for early exit + + return sk_sp(new SkSpotShadowMaskFilterImpl(occluderHeight, lightPos, + lightRadius, spotAlpha, flags)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SkSpotShadowMaskFilterImpl::SkSpotShadowMaskFilterImpl(SkScalar occluderHeight, + const SkPoint3& lightPos, + SkScalar lightRadius, + SkScalar spotAlpha, + uint32_t flags) + : fOccluderHeight(occluderHeight) + , fLightPos(lightPos) + , fLightRadius(lightRadius) + , fSpotAlpha(spotAlpha) + , fFlags(flags) { + SkASSERT(fOccluderHeight > 0); + SkASSERT(fLightPos.z() > 0 && fLightPos.z() > fOccluderHeight); + SkASSERT(fLightRadius > 0); + SkASSERT(fSpotAlpha >= 0); +} + +SkMask::Format SkSpotShadowMaskFilterImpl::getFormat() const { + return SkMask::kA8_Format; +} + +bool SkSpotShadowMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, + const SkMatrix& matrix, + SkIPoint* margin) const { + // TODO something + return false; +} + +void SkSpotShadowMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) const { + // TODO compute based on ambient + spot data + dst->set(src.fLeft, src.fTop, src.fRight, src.fBottom); +} + +sk_sp SkSpotShadowMaskFilterImpl::CreateProc(SkReadBuffer& buffer) { + const SkScalar occluderHeight = buffer.readScalar(); + const SkScalar lightX = buffer.readScalar(); + const SkScalar lightY = buffer.readScalar(); + const SkScalar lightZ = buffer.readScalar(); + const SkPoint3 lightPos = SkPoint3::Make(lightX, lightY, lightZ); + const SkScalar lightRadius = buffer.readScalar(); + const SkScalar spotAlpha = buffer.readScalar(); + const uint32_t flags = buffer.readUInt(); + + return SkSpotShadowMaskFilter::Make(occluderHeight, lightPos, lightRadius, + spotAlpha, flags); +} + +void SkSpotShadowMaskFilterImpl::flatten(SkWriteBuffer& buffer) const { + buffer.writeScalar(fOccluderHeight); + buffer.writeScalar(fLightPos.fX); + buffer.writeScalar(fLightPos.fY); + buffer.writeScalar(fLightPos.fZ); + buffer.writeScalar(fLightRadius); + buffer.writeScalar(fSpotAlpha); + buffer.writeUInt(fFlags); +} + +#if SK_SUPPORT_GPU + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +bool SkSpotShadowMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect, + const SkIRect& clipBounds, + const SkMatrix& ctm, + SkRect* maskRect) const { + // TODO + *maskRect = devRRect.rect(); + return true; +} + +bool SkSpotShadowMaskFilterImpl::directFilterMaskGPU(GrContext* context, + GrRenderTargetContext* rtContext, + GrPaint&& paint, + const GrClip& clip, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkPath& path) const { + SkASSERT(rtContext); + // TODO: this will not handle local coordinates properly + + if (fSpotAlpha <= 0.0f) { + return true; + } + + // only convex paths for now + if (!path.isConvex()) { + return false; + } + + if (strokeRec.getStyle() != SkStrokeRec::kFill_Style) { + return false; + } + + // if circle + // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we + // have our own GeometryProc. + if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) { + SkRRect rrect = SkRRect::MakeOval(path.getBounds()); + return this->directFilterRRectMaskGPU(context, rtContext, std::move(paint), clip, + SkMatrix::I(), strokeRec, rrect, rrect); + } else if (path.isRect(nullptr)) { + SkRRect rrect = SkRRect::MakeRect(path.getBounds()); + return this->directFilterRRectMaskGPU(context, rtContext, std::move(paint), clip, + SkMatrix::I(), strokeRec, rrect, rrect); + } + + return false; +} + +bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*, + GrRenderTargetContext* rtContext, + GrPaint&& paint, + const GrClip& clip, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkRRect& rrect, + const SkRRect& devRRect) const { + // It's likely the caller has already done these checks, but we have to be sure. + // TODO: support analytic blurring of general rrect + + // Fast path only supports filled rrects for now. + // TODO: fill and stroke as well. + if (SkStrokeRec::kFill_Style != strokeRec.getStyle()) { + return false; + } + // Fast path only supports simple rrects with circular corners. + SkASSERT(devRRect.allCornersCircular()); + if (!rrect.isRect() && !rrect.isOval() && !rrect.isSimple()) { + return false; + } + // Fast path only supports uniform scale. + SkScalar scaleFactors[2]; + if (!viewMatrix.getMinMaxScales(scaleFactors)) { + // matrix is degenerate + return false; + } + if (scaleFactors[0] != scaleFactors[1]) { + return false; + } + SkScalar scaleFactor = scaleFactors[0]; + + // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space + const SkScalar minRadius = 0.5f / scaleFactor; + bool isRect = rrect.getSimpleRadii().fX <= minRadius; + + // TODO: take flags into account when generating shadow data + + if (fSpotAlpha > 0.0f) { + float zRatio = SkTPin(fOccluderHeight / (fLightPos.fZ - fOccluderHeight), 0.0f, 0.95f); + + SkScalar srcSpaceSpotRadius = 2.0f * fLightRadius * zRatio; + + SkRRect spotRRect; + if (isRect) { + spotRRect = SkRRect::MakeRectXY(rrect.rect(), minRadius, minRadius); + } else { + spotRRect = rrect; + } + + SkRRect spotShadowRRect; + // Compute the scale and translation for the spot shadow. + const SkScalar scale = fLightPos.fZ / (fLightPos.fZ - fOccluderHeight); + spotRRect.transform(SkMatrix::MakeScale(scale, scale), &spotShadowRRect); + + SkPoint center = SkPoint::Make(spotShadowRRect.rect().centerX(), + spotShadowRRect.rect().centerY()); + SkMatrix ctmInverse; + if (!viewMatrix.invert(&ctmInverse)) { + SkDebugf("Matrix is degenerate. Will not render spot shadow!\n"); + //**** TODO: this is not good + return true; + } + SkPoint lightPos2D = SkPoint::Make(fLightPos.fX, fLightPos.fY); + ctmInverse.mapPoints(&lightPos2D, 1); + const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX), + zRatio*(center.fY - lightPos2D.fY)); + + // We want to extend the stroked area in so that it meets up with the caster + // geometry. The stroked geometry will, by definition already be inset half the + // stroke width but we also have to account for the scaling. + SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(rrect.rect().fLeft), + SkTAbs(rrect.rect().fRight)), + SkTMax(SkTAbs(rrect.rect().fTop), + SkTAbs(rrect.rect().fBottom))); + SkScalar insetAmount = spotOffset.length() - (0.5f * srcSpaceSpotRadius) + scaleOffset; + + // Compute area + SkScalar strokeWidth = srcSpaceSpotRadius + insetAmount; + SkScalar strokedArea = 2.0f*strokeWidth * + (spotShadowRRect.width() + spotShadowRRect.height()); + SkScalar filledArea = (spotShadowRRect.height() + srcSpaceSpotRadius) * + (spotShadowRRect.width() + srcSpaceSpotRadius); + + GrColor4f color = paint.getColor4f(); + color.fRGBA[3] *= fSpotAlpha; + paint.setColor4f(color); + + SkStrokeRec spotStrokeRec(SkStrokeRec::kFill_InitStyle); + // If the area of the stroked geometry is larger than the fill geometry, + // or if the caster is transparent, just fill it. + if (strokedArea > filledArea || + fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag) { + spotStrokeRec.setStrokeStyle(srcSpaceSpotRadius, true); + } else { + // Since we can't have unequal strokes, inset the shadow rect so the inner + // and outer edges of the stroke will land where we want. + SkRect insetRect = spotShadowRRect.rect().makeInset(insetAmount / 2.0f, + insetAmount / 2.0f); + SkScalar insetRad = SkTMax(spotShadowRRect.getSimpleRadii().fX - insetAmount / 2.0f, + minRadius); + spotShadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad); + spotStrokeRec.setStrokeStyle(strokeWidth, false); + } + + // handle scale of radius and pad due to CTM + const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor; + + spotShadowRRect.offset(spotOffset.fX, spotOffset.fY); + + rtContext->drawShadowRRect(clip, std::move(paint), viewMatrix, spotShadowRRect, + devSpaceSpotRadius, GrStyle(spotStrokeRec, nullptr)); + } + + return true; +} + +sk_sp SkSpotShadowMaskFilterImpl::filterMaskGPU(GrContext*, + sk_sp srcProxy, + const SkMatrix& ctm, + const SkIRect& maskRect) const { + // This filter is generative and doesn't operate on pre-existing masks + return nullptr; +} + +#endif + +#ifndef SK_IGNORE_TO_STRING +void SkSpotShadowMaskFilterImpl::toString(SkString* str) const { + str->append("SkSpotShadowMaskFilterImpl: ("); + + str->append("occluderHeight: "); + str->appendScalar(fOccluderHeight); + str->append(" "); + + str->append("lightPos: ("); + str->appendScalar(fLightPos.fX); + str->append(", "); + str->appendScalar(fLightPos.fY); + str->append(", "); + str->appendScalar(fLightPos.fZ); + str->append(") "); + + str->append("lightRadius: "); + str->appendScalar(fLightRadius); + str->append(" "); + + str->append("spotAlpha: "); + str->appendScalar(fSpotAlpha); + str->append(" "); + + str->append("flags: ("); + if (fFlags) { + bool needSeparator = false; + SkAddFlagToString(str, + SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag), + "TransparentOccluder", &needSeparator); + SkAddFlagToString(str, + SkToBool(fFlags & SkShadowFlags::kGaussianEdge_ShadowFlag), + "GaussianEdge", &needSeparator); + SkAddFlagToString(str, + SkToBool(fFlags & SkShadowFlags::kLargerUmbra_ShadowFlag), + "LargerUmbra", &needSeparator); + } else { + str->append("None"); + } + str->append("))"); +} +#endif + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkSpotShadowMaskFilter) +SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotShadowMaskFilterImpl) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END diff --git a/gfx/skia/skia/src/effects/shadows/SkSpotShadowMaskFilter.h b/gfx/skia/skia/src/effects/shadows/SkSpotShadowMaskFilter.h new file mode 100644 index 000000000000..5e1a4a9ec902 --- /dev/null +++ b/gfx/skia/skia/src/effects/shadows/SkSpotShadowMaskFilter.h @@ -0,0 +1,37 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSpotShadowMaskFilter_DEFINED +#define SkSpotShadowMaskFilter_DEFINED + +#include "SkMaskFilter.h" +#include "SkShadowFlags.h" + +/* + * This filter implements a shadow for an occluding object + * representing a displaced shadow from a point light. + */ +class SK_API SkSpotShadowMaskFilter { +public: + /** Create a shadow maskfilter. + * @param occluderHeight Height of occluding object off of ground plane. + * @param lightPos Position of the light applied to this object. + * @param lightRadius Radius of the light (light is assumed to be spherical). + * @param spotAlpha Base opacity of the displaced spot shadow. + * @param flags Flags to use - defaults to none + * @return The new shadow maskfilter + */ + static sk_sp Make(SkScalar occluderHeight, const SkPoint3& lightPos, + SkScalar lightRadius, SkScalar spotAlpha, + uint32_t flags = SkShadowFlags::kNone_ShadowFlag); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() + +private: + SkSpotShadowMaskFilter(); // can't be instantiated +}; +#endif diff --git a/gfx/skia/skia/src/fonts/SkFontMgr_indirect.cpp b/gfx/skia/skia/src/fonts/SkFontMgr_indirect.cpp index 070c0aa40287..f3ba9d1c25f6 100644 --- a/gfx/skia/skia/src/fonts/SkFontMgr_indirect.cpp +++ b/gfx/skia/skia/src/fonts/SkFontMgr_indirect.cpp @@ -5,7 +5,6 @@ * found in the LICENSE file. */ -#include "SkDataTable.h" #include "SkFontMgr.h" #include "SkFontMgr_indirect.h" #include "SkFontStyle.h" @@ -55,35 +54,22 @@ public: return this->matchStyleCSS3(pattern); } private: - SkAutoTUnref fOwner; + sk_sp fOwner; int fFamilyIndex; - SkAutoTUnref fData; + sk_sp fData; }; -void SkFontMgr_Indirect::set_up_family_names(const SkFontMgr_Indirect* self) { - self->fFamilyNames = self->fProxy->getFamilyNames(); -} - int SkFontMgr_Indirect::onCountFamilies() const { - fFamilyNamesInitOnce(SkFontMgr_Indirect::set_up_family_names, this); - return fFamilyNames->count(); + return 0; } void SkFontMgr_Indirect::onGetFamilyName(int index, SkString* familyName) const { - fFamilyNamesInitOnce(SkFontMgr_Indirect::set_up_family_names, this); - if (index >= fFamilyNames->count()) { - familyName->reset(); - return; - } - familyName->set(fFamilyNames->atStr(index)); + SkFAIL("Not implemented"); } SkFontStyleSet* SkFontMgr_Indirect::onCreateStyleSet(int index) const { - SkRemotableFontIdentitySet* set = fProxy->getIndex(index); - if (nullptr == set) { - return nullptr; - } - return new SkStyleSet_Indirect(this, index, set); + SkFAIL("Not implemented"); + return nullptr; } SkFontStyleSet* SkFontMgr_Indirect::onMatchFamily(const char familyName[]) const { @@ -97,7 +83,7 @@ SkTypeface* SkFontMgr_Indirect::createTypefaceFromFontId(const SkFontIdentity& i SkAutoMutexAcquire ama(fDataCacheMutex); - SkAutoTUnref dataTypeface; + sk_sp dataTypeface; int dataTypefaceIndex = 0; for (int i = 0; i < fDataCache.count(); ++i) { const DataEntry& entry = fDataCache[i]; @@ -123,19 +109,19 @@ SkTypeface* SkFontMgr_Indirect::createTypefaceFromFontId(const SkFontIdentity& i // No exact match, but did find a data match. if (dataTypeface.get() != nullptr) { - SkAutoTDelete stream(dataTypeface->openStream(nullptr)); + std::unique_ptr stream(dataTypeface->openStream(nullptr)); if (stream.get() != nullptr) { return fImpl->createFromStream(stream.release(), dataTypefaceIndex); } } // No data match, request data and add entry. - SkAutoTDelete stream(fProxy->getData(id.fDataId)); + std::unique_ptr stream(fProxy->getData(id.fDataId)); if (stream.get() == nullptr) { return nullptr; } - SkAutoTUnref typeface(fImpl->createFromStream(stream.release(), id.fTtcIndex)); + sk_sp typeface(fImpl->createFromStream(stream.release(), id.fTtcIndex)); if (typeface.get() == nullptr) { return nullptr; } @@ -186,7 +172,7 @@ SkTypeface* SkFontMgr_Indirect::onCreateFromData(SkData* data, int ttcIndex) con SkTypeface* SkFontMgr_Indirect::onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const { - SkAutoTUnref face(this->matchFamilyStyle(familyName, style)); + sk_sp face(this->matchFamilyStyle(familyName, style)); if (nullptr == face.get()) { face.reset(this->matchFamilyStyle(nullptr, style)); diff --git a/gfx/skia/skia/src/fonts/SkGScalerContext.cpp b/gfx/skia/skia/src/fonts/SkGScalerContext.cpp index 5a439b7eb558..3b9c6606365b 100644 --- a/gfx/skia/skia/src/fonts/SkGScalerContext.cpp +++ b/gfx/skia/skia/src/fonts/SkGScalerContext.cpp @@ -5,26 +5,27 @@ * found in the LICENSE file. */ +#include "SkCanvas.h" #include "SkDescriptor.h" #include "SkGScalerContext.h" #include "SkGlyph.h" +#include "SkPaintPriv.h" #include "SkPath.h" -#include "SkCanvas.h" +#include "SkMakeUnique.h" #define STD_SIZE 1 class SkGScalerContext : public SkScalerContext { public: - SkGScalerContext(SkGTypeface* face, const SkScalerContextEffects& effects, + SkGScalerContext(sk_sp face, const SkScalerContextEffects& effects, const SkDescriptor* desc) - : SkScalerContext(face, effects, desc) - , fFace(face) + : SkScalerContext(std::move(face), effects, desc) { - + size_t descSize = SkDescriptor::ComputeOverhead(1) + sizeof(SkScalerContext::Rec); SkAutoDescriptor ad(descSize); SkDescriptor* newDesc = ad.getDesc(); - + newDesc->init(); void* entry = newDesc->addEntry(kRec_SkDescriptorTag, sizeof(SkScalerContext::Rec), &fRec); @@ -38,26 +39,26 @@ public: } SkASSERT(descSize == newDesc->getLength()); newDesc->computeChecksum(); - - fProxy = face->proxy()->createScalerContext(effects, newDesc); - + + fProxy = this->getGTypeface()->proxy()->createScalerContext(effects, newDesc); + fRec.getSingleMatrix(&fMatrix); fMatrix.preScale(SK_Scalar1 / STD_SIZE, SK_Scalar1 / STD_SIZE); } - virtual ~SkGScalerContext() { delete fProxy; } protected: + SkGTypeface* getGTypeface() { return static_cast(this->getTypeface()); } + unsigned generateGlyphCount() override; uint16_t generateCharToGlyph(SkUnichar) override; void generateAdvance(SkGlyph*) override; void generateMetrics(SkGlyph*) override; void generateImage(const SkGlyph&) override; - void generatePath(const SkGlyph&, SkPath*) override; + void generatePath(SkGlyphID, SkPath*) override; void generateFontMetrics(SkPaint::FontMetrics*) override; private: - SkGTypeface* fFace; - SkScalerContext* fProxy; + std::unique_ptr fProxy; SkMatrix fMatrix; }; @@ -89,11 +90,11 @@ void SkGScalerContext::generateMetrics(SkGlyph* glyph) { glyph->fAdvanceY = SkScalarToFloat(advance.fY); SkPath path; - fProxy->getPath(*glyph, &path); + fProxy->getPath(glyph->getPackedID(), &path); path.transform(fMatrix); SkRect storage; - const SkPaint& paint = fFace->paint(); + const SkPaint& paint = this->getGTypeface()->paint(); const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(), &storage, SkPaint::kFill_Style); @@ -109,7 +110,7 @@ void SkGScalerContext::generateMetrics(SkGlyph* glyph) { void SkGScalerContext::generateImage(const SkGlyph& glyph) { if (SkMask::kARGB32_Format == glyph.fMaskFormat) { SkPath path; - fProxy->getPath(glyph, &path); + fProxy->getPath(glyph.getPackedID(), &path); SkBitmap bm; bm.installPixels(SkImageInfo::MakeN32Premul(glyph.fWidth, glyph.fHeight), @@ -120,31 +121,20 @@ void SkGScalerContext::generateImage(const SkGlyph& glyph) { canvas.translate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop)); canvas.concat(fMatrix); - canvas.drawPath(path, fFace->paint()); + canvas.drawPath(path, this->getGTypeface()->paint()); } else { fProxy->getImage(glyph); } } -void SkGScalerContext::generatePath(const SkGlyph& glyph, SkPath* path) { - fProxy->getPath(glyph, path); +void SkGScalerContext::generatePath(SkGlyphID glyph, SkPath* path) { + fProxy->getPath(SkPackedGlyphID(glyph), path); path->transform(fMatrix); } void SkGScalerContext::generateFontMetrics(SkPaint::FontMetrics* metrics) { fProxy->getFontMetrics(metrics); - if (metrics) { - SkScalar scale = fMatrix.getScaleY(); - metrics->fTop = SkScalarMul(metrics->fTop, scale); - metrics->fAscent = SkScalarMul(metrics->fAscent, scale); - metrics->fDescent = SkScalarMul(metrics->fDescent, scale); - metrics->fBottom = SkScalarMul(metrics->fBottom, scale); - metrics->fLeading = SkScalarMul(metrics->fLeading, scale); - metrics->fAvgCharWidth = SkScalarMul(metrics->fAvgCharWidth, scale); - metrics->fXMin = SkScalarMul(metrics->fXMin, scale); - metrics->fXMax = SkScalarMul(metrics->fXMax, scale); - metrics->fXHeight = SkScalarMul(metrics->fXHeight, scale); - } + SkPaintPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY()); } /////////////////////////////////////////////////////////////////////////////// @@ -159,7 +149,7 @@ SkGTypeface::SkGTypeface(sk_sp proxy, const SkPaint& paint) SkScalerContext* SkGTypeface::onCreateScalerContext(const SkScalerContextEffects& effects, const SkDescriptor* desc) const { - return new SkGScalerContext(const_cast(this), effects, desc); + return new SkGScalerContext(sk_ref_sp(const_cast(this)), effects, desc); } void SkGTypeface::onFilterRec(SkScalerContextRec* rec) const { @@ -205,6 +195,12 @@ SkTypeface::LocalizedStrings* SkGTypeface::onCreateFamilyNameIterator() const { return fProxy->createFamilyNameIterator(); } +int SkGTypeface::onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const +{ + return fProxy->onGetVariationDesignPosition(coordinates, coordinateCount); +} + int SkGTypeface::onGetTableTags(SkFontTableTag tags[]) const { return fProxy->getTableTags(tags); } diff --git a/gfx/skia/skia/src/fonts/SkGScalerContext.h b/gfx/skia/skia/src/fonts/SkGScalerContext.h index 3eb25a81da1c..562513c7bc7c 100644 --- a/gfx/skia/skia/src/fonts/SkGScalerContext.h +++ b/gfx/skia/skia/src/fonts/SkGScalerContext.h @@ -37,6 +37,8 @@ protected: void onGetFamilyName(SkString* familyName) const override; SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override; int onGetTableTags(SkFontTableTag tags[]) const override; size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override; diff --git a/gfx/skia/skia/src/fonts/SkRandomScalerContext.cpp b/gfx/skia/skia/src/fonts/SkRandomScalerContext.cpp index c9cb87c03ccf..3a292dcd79fa 100644 --- a/gfx/skia/skia/src/fonts/SkRandomScalerContext.cpp +++ b/gfx/skia/skia/src/fonts/SkRandomScalerContext.cpp @@ -5,17 +5,19 @@ * found in the LICENSE file. */ -#include "SkRandomScalerContext.h" -#include "SkGlyph.h" -#include "SkPath.h" #include "SkCanvas.h" +#include "SkGlyph.h" +#include "SkMakeUnique.h" +#include "SkPath.h" +#include "SkRandomScalerContext.h" #include "SkRasterizer.h" +class SkDescriptor; + class SkRandomScalerContext : public SkScalerContext { public: - SkRandomScalerContext(SkRandomTypeface*, const SkScalerContextEffects&, + SkRandomScalerContext(sk_sp, const SkScalerContextEffects&, const SkDescriptor*, bool fFakeIt); - virtual ~SkRandomScalerContext(); protected: unsigned generateGlyphCount() override; @@ -23,31 +25,26 @@ protected: void generateAdvance(SkGlyph*) override; void generateMetrics(SkGlyph*) override; void generateImage(const SkGlyph&) override; - void generatePath(const SkGlyph&, SkPath*) override; + void generatePath(SkGlyphID, SkPath*) override; void generateFontMetrics(SkPaint::FontMetrics*) override; private: - SkRandomTypeface* fFace; - SkScalerContext* fProxy; + SkRandomTypeface* getRandomTypeface() const { + return static_cast(this->getTypeface()); + } + std::unique_ptr fProxy; bool fFakeIt; }; -#define STD_SIZE 1 - -#include "SkDescriptor.h" - -SkRandomScalerContext::SkRandomScalerContext(SkRandomTypeface* face, +SkRandomScalerContext::SkRandomScalerContext(sk_sp face, const SkScalerContextEffects& effects, const SkDescriptor* desc, bool fakeIt) - : SkScalerContext(face, effects, desc) - , fFace(face) + : SkScalerContext(std::move(face), effects, desc) , fFakeIt(fakeIt) { - fProxy = face->proxy()->createScalerContext(effects, desc); + fProxy = this->getRandomTypeface()->proxy()->createScalerContext(effects, desc); } -SkRandomScalerContext::~SkRandomScalerContext() { delete fProxy; } - unsigned SkRandomScalerContext::generateGlyphCount() { return fProxy->getGlyphCount(); } @@ -87,10 +84,10 @@ void SkRandomScalerContext::generateMetrics(SkGlyph* glyph) { } if (SkMask::kARGB32_Format == format) { SkPath path; - fProxy->getPath(*glyph, &path); + fProxy->getPath(glyph->getPackedID(), &path); SkRect storage; - const SkPaint& paint = fFace->paint(); + const SkPaint& paint = this->getRandomTypeface()->paint(); const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(), &storage, SkPaint::kFill_Style); @@ -104,7 +101,7 @@ void SkRandomScalerContext::generateMetrics(SkGlyph* glyph) { SkPath devPath, fillPath; SkMatrix fillToDevMatrix; - this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); + this->internalGetPath(glyph->getPackedID(), &fillPath, &devPath, &fillToDevMatrix); // just use devPath const SkIRect ir = devPath.getBounds().roundOut(); @@ -157,7 +154,7 @@ void SkRandomScalerContext::generateImage(const SkGlyph& glyph) { if (!fFakeIt) { if (SkMask::kARGB32_Format == glyph.fMaskFormat) { SkPath path; - fProxy->getPath(glyph, &path); + fProxy->getPath(glyph.getPackedID(), &path); SkBitmap bm; bm.installPixels(SkImageInfo::MakeN32Premul(glyph.fWidth, glyph.fHeight), @@ -167,7 +164,7 @@ void SkRandomScalerContext::generateImage(const SkGlyph& glyph) { SkCanvas canvas(bm); canvas.translate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop)); - canvas.drawPath(path, fFace->paint()); + canvas.drawPath(path, this->getRandomTypeface()->paint()); } else { fProxy->forceGenerateImageFromPath(); fProxy->getImage(glyph); @@ -178,8 +175,8 @@ void SkRandomScalerContext::generateImage(const SkGlyph& glyph) { } } -void SkRandomScalerContext::generatePath(const SkGlyph& glyph, SkPath* path) { - fProxy->getPath(glyph, path); +void SkRandomScalerContext::generatePath(SkGlyphID glyph, SkPath* path) { + fProxy->generatePath(glyph, path); } void SkRandomScalerContext::generateFontMetrics(SkPaint::FontMetrics* metrics) { @@ -198,7 +195,8 @@ SkRandomTypeface::SkRandomTypeface(sk_sp proxy, const SkPaint& paint SkScalerContext* SkRandomTypeface::onCreateScalerContext(const SkScalerContextEffects& effects, const SkDescriptor* desc) const { - return new SkRandomScalerContext(const_cast(this), effects, desc, fFakeIt); + return new SkRandomScalerContext(sk_ref_sp(const_cast(this)), + effects, desc, fFakeIt); } void SkRandomTypeface::onFilterRec(SkScalerContextRec* rec) const { @@ -244,6 +242,12 @@ SkTypeface::LocalizedStrings* SkRandomTypeface::onCreateFamilyNameIterator() con return fProxy->createFamilyNameIterator(); } +int SkRandomTypeface::onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const +{ + return fProxy->onGetVariationDesignPosition(coordinates, coordinateCount); +} + int SkRandomTypeface::onGetTableTags(SkFontTableTag tags[]) const { return fProxy->getTableTags(tags); } diff --git a/gfx/skia/skia/src/fonts/SkRandomScalerContext.h b/gfx/skia/skia/src/fonts/SkRandomScalerContext.h index 076689d93a42..c84b76470e24 100644 --- a/gfx/skia/skia/src/fonts/SkRandomScalerContext.h +++ b/gfx/skia/skia/src/fonts/SkRandomScalerContext.h @@ -42,6 +42,8 @@ protected: void onGetFamilyName(SkString* familyName) const override; SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override; int onGetTableTags(SkFontTableTag tags[]) const override; size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override; diff --git a/gfx/skia/skia/src/fonts/SkTestScalerContext.cpp b/gfx/skia/skia/src/fonts/SkTestScalerContext.cpp index f7678a2ca4e3..db726376f133 100644 --- a/gfx/skia/skia/src/fonts/SkTestScalerContext.cpp +++ b/gfx/skia/skia/src/fonts/SkTestScalerContext.cpp @@ -11,8 +11,9 @@ #include "SkDescriptor.h" #include "SkFontDescriptor.h" #include "SkGlyph.h" +#include "SkMakeUnique.h" #include "SkMask.h" -// #include "SkOTUtils.h" +#include "SkPaintPriv.h" #include "SkScalerContext.h" #include "SkTestScalerContext.h" #include "SkTypefaceCache.h" @@ -116,9 +117,9 @@ void SkTestFont::init(const SkScalar* pts, const unsigned char* verbs) { } } -SkTestTypeface::SkTestTypeface(SkTestFont* testFont, const SkFontStyle& style) +SkTestTypeface::SkTestTypeface(sk_sp testFont, const SkFontStyle& style) : SkTypeface(style, false) - , fTestFont(testFont) { + , fTestFont(std::move(testFont)) { } void SkTestTypeface::getAdvance(SkGlyph* glyph) { @@ -137,8 +138,8 @@ void SkTestTypeface::getMetrics(SkGlyph* glyph) { glyph->fAdvanceY = 0; } -void SkTestTypeface::getPath(const SkGlyph& glyph, SkPath* path) { - *path = *fTestFont->fPaths[glyph.getGlyphID()]; +void SkTestTypeface::getPath(SkGlyphID glyph, SkPath* path) { + *path = *fTestFont->fPaths[glyph]; } void SkTestTypeface::onFilterRec(SkScalerContextRec* rec) const { @@ -153,7 +154,6 @@ SkAdvancedTypefaceMetrics* SkTestTypeface::onGetAdvancedTypefaceMetrics( SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics; info->fFontName.set(fTestFont->fName); int glyphCount = this->onCountGlyphs(); - info->fLastGlyphID = SkToU16(glyphCount - 1); SkTDArray& toUnicode = info->fGlyphToUnicode; toUnicode.setCount(glyphCount); @@ -171,8 +171,8 @@ void SkTestTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) } int SkTestTypeface::onCharsToGlyphs(const void* chars, Encoding encoding, - uint16_t glyphs[], int glyphCount) const { - SkASSERT(encoding == kUTF16_Encoding); + uint16_t glyphs[], int glyphCount) const { + SkASSERT(encoding == kUTF32_Encoding); for (int index = 0; index < glyphCount; ++index) { SkUnichar ch = ((SkUnichar*) chars)[index]; glyphs[index] = fTestFont->codeToIndex(ch); @@ -187,38 +187,39 @@ void SkTestTypeface::onGetFamilyName(SkString* familyName) const { SkTypeface::LocalizedStrings* SkTestTypeface::onCreateFamilyNameIterator() const { SkString familyName(fTestFont->fName); SkString language("und"); //undetermined -SkASSERT(0); // incomplete +//SkASSERT(0); // incomplete return nullptr; // return new SkOTUtils::LocalizedStrings_SingleName(familyName, language); } class SkTestScalerContext : public SkScalerContext { public: - SkTestScalerContext(SkTestTypeface* face, const SkScalerContextEffects& effects, + SkTestScalerContext(sk_sp face, const SkScalerContextEffects& effects, const SkDescriptor* desc) - : SkScalerContext(face, effects, desc) - , fFace(face) + : SkScalerContext(std::move(face), effects, desc) { fRec.getSingleMatrix(&fMatrix); this->forceGenerateImageFromPath(); } - virtual ~SkTestScalerContext() { +protected: + SkTestTypeface* getTestTypeface() const { + return static_cast(this->getTypeface()); } -protected: unsigned generateGlyphCount() override { - return fFace->onCountGlyphs(); + return this->getTestTypeface()->onCountGlyphs(); } uint16_t generateCharToGlyph(SkUnichar uni) override { uint16_t glyph; - (void) fFace->onCharsToGlyphs((const void *) &uni, SkTypeface::kUTF16_Encoding, &glyph, 1); + (void) this->getTestTypeface()->onCharsToGlyphs((const void *) &uni, + SkTypeface::kUTF32_Encoding, &glyph, 1); return glyph; } void generateAdvance(SkGlyph* glyph) override { - fFace->getAdvance(glyph); + this->getTestTypeface()->getAdvance(glyph); const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), SkFloatToScalar(glyph->fAdvanceY)); @@ -227,7 +228,7 @@ protected: } void generateMetrics(SkGlyph* glyph) override { - fFace->getMetrics(glyph); + this->getTestTypeface()->getMetrics(glyph); const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), SkFloatToScalar(glyph->fAdvanceY)); @@ -235,7 +236,7 @@ protected: glyph->fAdvanceY = SkScalarToFloat(advance.fY); SkPath path; - fFace->getPath(*glyph, &path); + this->getTestTypeface()->getPath(glyph->getGlyphID(), &path); path.transform(fMatrix); SkRect storage; @@ -253,7 +254,7 @@ protected: void generateImage(const SkGlyph& glyph) override { SkPath path; - fFace->getPath(glyph, &path); + this->getTestTypeface()->getPath(glyph.getGlyphID(), &path); SkBitmap bm; bm.installPixels(SkImageInfo::MakeN32Premul(glyph.fWidth, glyph.fHeight), @@ -269,33 +270,22 @@ protected: canvas.drawPath(path, paint); } - void generatePath(const SkGlyph& glyph, SkPath* path) override { - fFace->getPath(glyph, path); + void generatePath(SkGlyphID glyph, SkPath* path) override { + this->getTestTypeface()->getPath(glyph, path); path->transform(fMatrix); } void generateFontMetrics(SkPaint::FontMetrics* metrics) override { - fFace->getFontMetrics(metrics); - if (metrics) { - SkScalar scale = fMatrix.getScaleY(); - metrics->fTop = SkScalarMul(metrics->fTop, scale); - metrics->fAscent = SkScalarMul(metrics->fAscent, scale); - metrics->fDescent = SkScalarMul(metrics->fDescent, scale); - metrics->fBottom = SkScalarMul(metrics->fBottom, scale); - metrics->fLeading = SkScalarMul(metrics->fLeading, scale); - metrics->fAvgCharWidth = SkScalarMul(metrics->fAvgCharWidth, scale); - metrics->fXMin = SkScalarMul(metrics->fXMin, scale); - metrics->fXMax = SkScalarMul(metrics->fXMax, scale); - metrics->fXHeight = SkScalarMul(metrics->fXHeight, scale); - } + this->getTestTypeface()->getFontMetrics(metrics); + SkPaintPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY()); } private: - SkTestTypeface* fFace; SkMatrix fMatrix; }; -SkScalerContext* SkTestTypeface::onCreateScalerContext(const SkScalerContextEffects& effects, - const SkDescriptor* desc) const { - return new SkTestScalerContext(const_cast(this), effects, desc); +SkScalerContext* SkTestTypeface::onCreateScalerContext( + const SkScalerContextEffects& effects, const SkDescriptor* desc) const +{ + return new SkTestScalerContext(sk_ref_sp(const_cast(this)), effects, desc); } diff --git a/gfx/skia/skia/src/fonts/SkTestScalerContext.h b/gfx/skia/skia/src/fonts/SkTestScalerContext.h index a5fa1de90d2c..5b2ec4f5a2b4 100644 --- a/gfx/skia/skia/src/fonts/SkTestScalerContext.h +++ b/gfx/skia/skia/src/fonts/SkTestScalerContext.h @@ -26,13 +26,11 @@ struct SkTestFontData { const SkPaint::FontMetrics& fMetrics; const char* fName; SkTypeface::Style fStyle; - SkTestFont* fFontCache; + sk_sp fCachedFont; }; class SkTestFont : public SkRefCnt { public: - - SkTestFont(const SkTestFontData& ); virtual ~SkTestFont(); int codeToIndex(SkUnichar charCode) const; @@ -58,14 +56,11 @@ private: class SkTestTypeface : public SkTypeface { public: - SkTestTypeface(SkTestFont*, const SkFontStyle& style); - virtual ~SkTestTypeface() { - SkSafeUnref(fTestFont); - } + SkTestTypeface(sk_sp, const SkFontStyle& style); void getAdvance(SkGlyph* glyph); void getFontMetrics(SkPaint::FontMetrics* metrics); void getMetrics(SkGlyph* glyph); - void getPath(const SkGlyph& glyph, SkPath* path); + void getPath(SkGlyphID glyph, SkPath* path); protected: SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, const SkDescriptor* desc) const override; @@ -89,13 +84,18 @@ protected: } int onGetUPEM() const override { - SkASSERT(0); // don't expect to get here - return 1; + return 2048; } void onGetFamilyName(SkString* familyName) const override; SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override + { + return 0; + } + int onGetTableTags(SkFontTableTag tags[]) const override { return 0; } @@ -105,7 +105,7 @@ protected: return 0; } private: - SkTestFont* fTestFont; + sk_sp fTestFont; friend class SkTestScalerContext; }; diff --git a/gfx/skia/skia/src/gpu/GrAllocator.h b/gfx/skia/skia/src/gpu/GrAllocator.h index 5b9bd5bab97b..e5d2f4ea6109 100644 --- a/gfx/skia/skia/src/gpu/GrAllocator.h +++ b/gfx/skia/skia/src/gpu/GrAllocator.h @@ -258,6 +258,13 @@ public: return *(T*)item; } + template T& emplace_back(Args&&... args) { + void* item = fAllocator.push_back(); + SkASSERT(item); + new (item) T(std::forward(args)...); + return *(T*)item; + } + /** * Remove the last item, only call if count() != 0 */ diff --git a/gfx/skia/skia/src/gpu/GrAppliedClip.h b/gfx/skia/skia/src/gpu/GrAppliedClip.h index 3e98c6cb0569..8488dc4d5d65 100644 --- a/gfx/skia/skia/src/gpu/GrAppliedClip.h +++ b/gfx/skia/skia/src/gpu/GrAppliedClip.h @@ -8,21 +8,19 @@ #ifndef GrAppliedClip_DEFINED #define GrAppliedClip_DEFINED +#include "GrFragmentProcessor.h" #include "GrScissorState.h" #include "GrWindowRectsState.h" -class GrFragmentProcessor; - /** * Produced by GrClip. It provides a set of modifications to the drawing state that are used to - * create the final GrPipeline for a GrBatch. + * create the final GrPipeline for a GrOp. */ -class GrAppliedClip : public SkNoncopyable { +class GrAppliedClip { public: - GrAppliedClip(const SkRect& drawBounds) - : fHasStencilClip(false) - , fClippedDrawBounds(drawBounds) { - } + GrAppliedClip() = default; + GrAppliedClip(GrAppliedClip&& that) = default; + GrAppliedClip(const GrAppliedClip&) = delete; const GrScissorState& scissorState() const { return fScissorState; } const GrWindowRectsState& windowRectsState() const { return fWindowRectsState; } @@ -31,9 +29,11 @@ public: /** * Intersects the applied clip with the provided rect. Returns false if the draw became empty. + * 'clippedDrawBounds' will be intersected with 'irect'. This returns false if the clip becomes + * empty or the draw no longer intersects the clip. In either case the draw can be skipped. */ - bool addScissor(const SkIRect& irect) { - return fScissorState.intersect(irect) && fClippedDrawBounds.intersect(SkRect::Make(irect)); + bool addScissor(const SkIRect& irect, SkRect* clippedDrawBounds) { + return fScissorState.intersect(irect) && clippedDrawBounds->intersect(SkRect::Make(irect)); } void addWindowRectangles(const GrWindowRectsState& windowState) { @@ -41,10 +41,9 @@ public: fWindowRectsState = windowState; } - void addWindowRectangles(const GrWindowRectangles& windows, const SkIPoint& origin, - GrWindowRectsState::Mode mode) { + void addWindowRectangles(const GrWindowRectangles& windows, GrWindowRectsState::Mode mode) { SkASSERT(!fWindowRectsState.enabled()); - fWindowRectsState.set(windows, origin, mode); + fWindowRectsState.set(windows, mode); } void addCoverageFP(sk_sp fp) { @@ -57,19 +56,32 @@ public: fHasStencilClip = true; } - /** - * Returns the device bounds of the draw after clip has been applied. TODO: Ideally this would - * consider the combined effect of all clipping techniques in play (scissor, stencil, fp, etc.). - */ - const SkRect& clippedDrawBounds() const { return fClippedDrawBounds; } + bool doesClip() const { + return fScissorState.enabled() || fClipCoverageFP || fHasStencilClip || + fWindowRectsState.enabled(); + } + + bool operator==(const GrAppliedClip& that) const { + if (fScissorState != that.fScissorState || fHasStencilClip != that.fHasStencilClip) { + return false; + } + if (SkToBool(fClipCoverageFP)) { + if (!SkToBool(that.fClipCoverageFP) || + !that.fClipCoverageFP->isEqual(*fClipCoverageFP)) { + return false; + } + } else if (SkToBool(that.fClipCoverageFP)) { + return false; + } + return fWindowRectsState == that.fWindowRectsState; + } + bool operator!=(const GrAppliedClip& that) const { return !(*this == that); } private: GrScissorState fScissorState; GrWindowRectsState fWindowRectsState; sk_sp fClipCoverageFP; - bool fHasStencilClip; - SkRect fClippedDrawBounds; - typedef SkNoncopyable INHERITED; + bool fHasStencilClip = false; }; #endif diff --git a/gfx/skia/skia/src/gpu/GrAuditTrail.cpp b/gfx/skia/skia/src/gpu/GrAuditTrail.cpp index 82dc7f713fc2..e6b5c3adb2bd 100644 --- a/gfx/skia/skia/src/gpu/GrAuditTrail.cpp +++ b/gfx/skia/skia/src/gpu/GrAuditTrail.cpp @@ -6,137 +6,136 @@ */ #include "GrAuditTrail.h" -#include "batches/GrBatch.h" +#include "ops/GrOp.h" const int GrAuditTrail::kGrAuditTrailInvalidID = -1; -void GrAuditTrail::addBatch(const GrBatch* batch) { +void GrAuditTrail::addOp(const GrOp* op, + GrGpuResource::UniqueID resourceID, + GrRenderTargetProxy::UniqueID proxyID) { SkASSERT(fEnabled); - Batch* auditBatch = new Batch; - fBatchPool.emplace_back(auditBatch); - auditBatch->fName = batch->name(); - auditBatch->fBounds = batch->bounds(); - auditBatch->fClientID = kGrAuditTrailInvalidID; - auditBatch->fBatchListID = kGrAuditTrailInvalidID; - auditBatch->fChildID = kGrAuditTrailInvalidID; + Op* auditOp = new Op; + fOpPool.emplace_back(auditOp); + auditOp->fName = op->name(); + auditOp->fBounds = op->bounds(); + auditOp->fClientID = kGrAuditTrailInvalidID; + auditOp->fOpListID = kGrAuditTrailInvalidID; + auditOp->fChildID = kGrAuditTrailInvalidID; // consume the current stack trace if any - auditBatch->fStackTrace = fCurrentStackTrace; + auditOp->fStackTrace = fCurrentStackTrace; fCurrentStackTrace.reset(); if (fClientID != kGrAuditTrailInvalidID) { - auditBatch->fClientID = fClientID; - Batches** batchesLookup = fClientIDLookup.find(fClientID); - Batches* batches = nullptr; - if (!batchesLookup) { - batches = new Batches; - fClientIDLookup.set(fClientID, batches); + auditOp->fClientID = fClientID; + Ops** opsLookup = fClientIDLookup.find(fClientID); + Ops* ops = nullptr; + if (!opsLookup) { + ops = new Ops; + fClientIDLookup.set(fClientID, ops); } else { - batches = *batchesLookup; + ops = *opsLookup; } - batches->push_back(auditBatch); + ops->push_back(auditOp); } - // Our algorithm doesn't bother to reorder inside of a BatchNode - // so the ChildID will start at 0 - auditBatch->fBatchListID = fBatchList.count(); - auditBatch->fChildID = 0; + // Our algorithm doesn't bother to reorder inside of an OpNode so the ChildID will start at 0 + auditOp->fOpListID = fOpList.count(); + auditOp->fChildID = 0; - // We use the batch pointer as a key to find the batchnode we are 'glomming' batches onto - fIDLookup.set(batch->uniqueID(), auditBatch->fBatchListID); - BatchNode* batchNode = new BatchNode; - batchNode->fBounds = batch->bounds(); - batchNode->fRenderTargetUniqueID = batch->renderTargetUniqueID(); - batchNode->fChildren.push_back(auditBatch); - fBatchList.emplace_back(batchNode); + // We use the op pointer as a key to find the OpNode we are 'glomming' ops onto + fIDLookup.set(op->uniqueID(), auditOp->fOpListID); + OpNode* opNode = new OpNode(resourceID, proxyID); + opNode->fBounds = op->bounds(); + opNode->fChildren.push_back(auditOp); + fOpList.emplace_back(opNode); } -void GrAuditTrail::batchingResultCombined(const GrBatch* consumer, const GrBatch* consumed) { - // Look up the batch we are going to glom onto +void GrAuditTrail::opsCombined(const GrOp* consumer, const GrOp* consumed) { + // Look up the op we are going to glom onto int* indexPtr = fIDLookup.find(consumer->uniqueID()); SkASSERT(indexPtr); int index = *indexPtr; - SkASSERT(index < fBatchList.count() && fBatchList[index]); - BatchNode& consumerBatch = *fBatchList[index]; + SkASSERT(index < fOpList.count() && fOpList[index]); + OpNode& consumerOp = *fOpList[index]; - // Look up the batch which will be glommed + // Look up the op which will be glommed int* consumedPtr = fIDLookup.find(consumed->uniqueID()); SkASSERT(consumedPtr); int consumedIndex = *consumedPtr; - SkASSERT(consumedIndex < fBatchList.count() && fBatchList[consumedIndex]); - BatchNode& consumedBatch = *fBatchList[consumedIndex]; + SkASSERT(consumedIndex < fOpList.count() && fOpList[consumedIndex]); + OpNode& consumedOp = *fOpList[consumedIndex]; - // steal all of consumed's batches - for (int i = 0; i < consumedBatch.fChildren.count(); i++) { - Batch* childBatch = consumedBatch.fChildren[i]; + // steal all of consumed's ops + for (int i = 0; i < consumedOp.fChildren.count(); i++) { + Op* childOp = consumedOp.fChildren[i]; - // set the ids for the child batch - childBatch->fBatchListID = index; - childBatch->fChildID = consumerBatch.fChildren.count(); - consumerBatch.fChildren.push_back(childBatch); + // set the ids for the child op + childOp->fOpListID = index; + childOp->fChildID = consumerOp.fChildren.count(); + consumerOp.fChildren.push_back(childOp); } // Update the bounds for the combineWith node - consumerBatch.fBounds = consumer->bounds(); + consumerOp.fBounds = consumer->bounds(); - // remove the old node from our batchlist and clear the combinee's lookup - // NOTE: because we can't change the shape of the batchlist, we use a sentinel - fBatchList[consumedIndex].reset(nullptr); + // remove the old node from our opList and clear the combinee's lookup + // NOTE: because we can't change the shape of the oplist, we use a sentinel + fOpList[consumedIndex].reset(nullptr); fIDLookup.remove(consumed->uniqueID()); } -void GrAuditTrail::copyOutFromBatchList(BatchInfo* outBatchInfo, int batchListID) { - SkASSERT(batchListID < fBatchList.count()); - const BatchNode* bn = fBatchList[batchListID]; +void GrAuditTrail::copyOutFromOpList(OpInfo* outOpInfo, int opListID) { + SkASSERT(opListID < fOpList.count()); + const OpNode* bn = fOpList[opListID].get(); SkASSERT(bn); - outBatchInfo->fBounds = bn->fBounds; - outBatchInfo->fRenderTargetUniqueID = bn->fRenderTargetUniqueID; + outOpInfo->fBounds = bn->fBounds; + outOpInfo->fResourceUniqueID = bn->fResourceUniqueID; + outOpInfo->fProxyUniqueID = bn->fProxyUniqueID; for (int j = 0; j < bn->fChildren.count(); j++) { - BatchInfo::Batch& outBatch = outBatchInfo->fBatches.push_back(); - const Batch* currentBatch = bn->fChildren[j]; - outBatch.fBounds = currentBatch->fBounds; - outBatch.fClientID = currentBatch->fClientID; + OpInfo::Op& outOp = outOpInfo->fOps.push_back(); + const Op* currentOp = bn->fChildren[j]; + outOp.fBounds = currentOp->fBounds; + outOp.fClientID = currentOp->fClientID; } } -void GrAuditTrail::getBoundsByClientID(SkTArray* outInfo, int clientID) { - Batches** batchesLookup = fClientIDLookup.find(clientID); - if (batchesLookup) { - // We track which batchlistID we're currently looking at. If it changes, then we - // need to push back a new batch info struct. We happen to know that batches are - // in sequential order in the batchlist, otherwise we'd have to do more bookkeeping - int currentBatchListID = kGrAuditTrailInvalidID; - for (int i = 0; i < (*batchesLookup)->count(); i++) { - const Batch* batch = (**batchesLookup)[i]; +void GrAuditTrail::getBoundsByClientID(SkTArray* outInfo, int clientID) { + Ops** opsLookup = fClientIDLookup.find(clientID); + if (opsLookup) { + // We track which oplistID we're currently looking at. If it changes, then we need to push + // back a new op info struct. We happen to know that ops are in sequential order in the + // oplist, otherwise we'd have to do more bookkeeping + int currentOpListID = kGrAuditTrailInvalidID; + for (int i = 0; i < (*opsLookup)->count(); i++) { + const Op* op = (**opsLookup)[i]; - // Because we will copy out all of the batches associated with a given - // batch list id everytime the id changes, we only have to update our struct - // when the id changes. - if (kGrAuditTrailInvalidID == currentBatchListID || - batch->fBatchListID != currentBatchListID) { - BatchInfo& outBatchInfo = outInfo->push_back(); + // Because we will copy out all of the ops associated with a given op list id everytime + // the id changes, we only have to update our struct when the id changes. + if (kGrAuditTrailInvalidID == currentOpListID || op->fOpListID != currentOpListID) { + OpInfo& outOpInfo = outInfo->push_back(); - // copy out all of the batches so the client can display them even if - // they have a different clientID - this->copyOutFromBatchList(&outBatchInfo, batch->fBatchListID); + // copy out all of the ops so the client can display them even if they have a + // different clientID + this->copyOutFromOpList(&outOpInfo, op->fOpListID); } } } } -void GrAuditTrail::getBoundsByBatchListID(BatchInfo* outInfo, int batchListID) { - this->copyOutFromBatchList(outInfo, batchListID); +void GrAuditTrail::getBoundsByOpListID(OpInfo* outInfo, int opListID) { + this->copyOutFromOpList(outInfo, opListID); } void GrAuditTrail::fullReset() { SkASSERT(fEnabled); - fBatchList.reset(); + fOpList.reset(); fIDLookup.reset(); - // free all client batches - fClientIDLookup.foreach([](const int&, Batches** batches) { delete *batches; }); + // free all client ops + fClientIDLookup.foreach ([](const int&, Ops** ops) { delete *ops; }); fClientIDLookup.reset(); - fBatchPool.reset(); // must be last, frees all of the memory + fOpPool.reset(); // must be last, frees all of the memory } template @@ -230,7 +229,7 @@ static SkString pretty_print_json(SkString json) { SkString GrAuditTrail::toJson(bool prettyPrint) const { SkString json; json.append("{"); - JsonifyTArray(&json, "Batches", fBatchList, false); + JsonifyTArray(&json, "Ops", fOpList, false); json.append("}"); if (prettyPrint) { @@ -243,9 +242,9 @@ SkString GrAuditTrail::toJson(bool prettyPrint) const { SkString GrAuditTrail::toJson(int clientID, bool prettyPrint) const { SkString json; json.append("{"); - Batches** batches = fClientIDLookup.find(clientID); - if (batches) { - JsonifyTArray(&json, "Batches", **batches, false); + Ops** ops = fClientIDLookup.find(clientID); + if (ops) { + JsonifyTArray(&json, "Ops", **ops, false); } json.appendf("}"); @@ -265,12 +264,12 @@ static void skrect_to_json(SkString* json, const char* name, const SkRect& rect) json->append("}"); } -SkString GrAuditTrail::Batch::toJson() const { +SkString GrAuditTrail::Op::toJson() const { SkString json; json.append("{"); json.appendf("\"Name\": \"%s\",", fName.c_str()); json.appendf("\"ClientID\": \"%d\",", fClientID); - json.appendf("\"BatchListID\": \"%d\",", fBatchListID); + json.appendf("\"OpListID\": \"%d\",", fOpListID); json.appendf("\"ChildID\": \"%d\",", fChildID); skrect_to_json(&json, "Bounds", fBounds); if (fStackTrace.count()) { @@ -287,12 +286,13 @@ SkString GrAuditTrail::Batch::toJson() const { return json; } -SkString GrAuditTrail::BatchNode::toJson() const { +SkString GrAuditTrail::OpNode::toJson() const { SkString json; json.append("{"); - json.appendf("\"RenderTarget\": \"%u\",", fRenderTargetUniqueID); + json.appendf("\"ResourceID\": \"%u\",", fResourceUniqueID.asUInt()); + json.appendf("\"ProxyID\": \"%u\",", fProxyUniqueID.asUInt()); skrect_to_json(&json, "Bounds", fBounds); - JsonifyTArray(&json, "Batches", fChildren, true); + JsonifyTArray(&json, "Ops", fChildren, true); json.append("}"); return json; } diff --git a/gfx/skia/skia/src/gpu/GrAutoLocaleSetter.h b/gfx/skia/skia/src/gpu/GrAutoLocaleSetter.h index 564abd917f1b..cec041e086ab 100644 --- a/gfx/skia/skia/src/gpu/GrAutoLocaleSetter.h +++ b/gfx/skia/skia/src/gpu/GrAutoLocaleSetter.h @@ -20,6 +20,9 @@ #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) #include +#define HAVE_XLOCALE 1 +#else +#define HAVE_XLOCALE 0 #endif #if defined(SK_BUILD_FOR_ANDROID) || defined(__UCLIBC__) || defined(_NEWLIB_VERSION) @@ -45,6 +48,12 @@ public: fShouldRestoreLocale = false; } #elif HAVE_LOCALE_T +#if HAVE_XLOCALE + // In xlocale nullptr means the C locale. + if (0 == strcmp(name, "C")) { + name = nullptr; + } +#endif fLocale = newlocale(LC_ALL, name, 0); if (fLocale) { fOldLocale = uselocale(fLocale); @@ -82,5 +91,6 @@ private: }; #undef HAVE_LOCALE_T +#undef HAVE_XLOCALE #endif diff --git a/gfx/skia/skia/src/gpu/GrBatchAtlas.cpp b/gfx/skia/skia/src/gpu/GrBatchAtlas.cpp deleted file mode 100644 index e0828a4e6a1c..000000000000 --- a/gfx/skia/skia/src/gpu/GrBatchAtlas.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrBatchAtlas.h" -#include "GrBatchFlushState.h" -#include "GrRectanizer.h" -#include "GrTracing.h" - -//////////////////////////////////////////////////////////////////////////////// - -GrBatchAtlas::BatchPlot::BatchPlot(int index, uint64_t genID, int offX, int offY, int width, - int height, GrPixelConfig config) - : fLastUpload(GrBatchDrawToken::AlreadyFlushedToken()) - , fLastUse(GrBatchDrawToken::AlreadyFlushedToken()) - , fIndex(index) - , fGenID(genID) - , fID(CreateId(fIndex, fGenID)) - , fData(nullptr) - , fWidth(width) - , fHeight(height) - , fX(offX) - , fY(offY) - , fRects(nullptr) - , fOffset(SkIPoint16::Make(fX * fWidth, fY * fHeight)) - , fConfig(config) - , fBytesPerPixel(GrBytesPerPixel(config)) -#ifdef SK_DEBUG - , fDirty(false) -#endif -{ - fDirtyRect.setEmpty(); -} - -GrBatchAtlas::BatchPlot::~BatchPlot() { - sk_free(fData); - delete fRects; -} - -bool GrBatchAtlas::BatchPlot::addSubImage(int width, int height, const void* image, - SkIPoint16* loc) { - SkASSERT(width <= fWidth && height <= fHeight); - - if (!fRects) { - fRects = GrRectanizer::Factory(fWidth, fHeight); - } - - if (!fRects->addRect(width, height, loc)) { - return false; - } - - if (!fData) { - fData = reinterpret_cast(sk_calloc_throw(fBytesPerPixel * fWidth * - fHeight)); - } - size_t rowBytes = width * fBytesPerPixel; - const unsigned char* imagePtr = (const unsigned char*)image; - // point ourselves at the right starting spot - unsigned char* dataPtr = fData; - dataPtr += fBytesPerPixel * fWidth * loc->fY; - dataPtr += fBytesPerPixel * loc->fX; - // copy into the data buffer - for (int i = 0; i < height; ++i) { - memcpy(dataPtr, imagePtr, rowBytes); - dataPtr += fBytesPerPixel * fWidth; - imagePtr += rowBytes; - } - - fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height); - - loc->fX += fOffset.fX; - loc->fY += fOffset.fY; - SkDEBUGCODE(fDirty = true;) - - return true; -} - -void GrBatchAtlas::BatchPlot::uploadToTexture(GrDrawBatch::WritePixelsFn& writePixels, - GrTexture* texture) { - // We should only be issuing uploads if we are in fact dirty - SkASSERT(fDirty && fData && texture); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "GrBatchPlot::uploadToTexture"); - size_t rowBytes = fBytesPerPixel * fWidth; - const unsigned char* dataPtr = fData; - dataPtr += rowBytes * fDirtyRect.fTop; - dataPtr += fBytesPerPixel * fDirtyRect.fLeft; - writePixels(texture, fOffset.fX + fDirtyRect.fLeft, fOffset.fY + fDirtyRect.fTop, - fDirtyRect.width(), fDirtyRect.height(), fConfig, dataPtr, rowBytes); - fDirtyRect.setEmpty(); - SkDEBUGCODE(fDirty = false;) -} - -void GrBatchAtlas::BatchPlot::resetRects() { - if (fRects) { - fRects->reset(); - } - - fGenID++; - fID = CreateId(fIndex, fGenID); - - // zero out the plot - if (fData) { - sk_bzero(fData, fBytesPerPixel * fWidth * fHeight); - } - - fDirtyRect.setEmpty(); - SkDEBUGCODE(fDirty = false;) -} - -/////////////////////////////////////////////////////////////////////////////// - -GrBatchAtlas::GrBatchAtlas(GrTexture* texture, int numPlotsX, int numPlotsY) - : fTexture(texture) - , fAtlasGeneration(kInvalidAtlasGeneration + 1) { - - fPlotWidth = texture->width() / numPlotsX; - fPlotHeight = texture->height() / numPlotsY; - SkASSERT(numPlotsX * numPlotsY <= BulkUseTokenUpdater::kMaxPlots); - SkASSERT(fPlotWidth * numPlotsX == texture->width()); - SkASSERT(fPlotHeight * numPlotsY == texture->height()); - - SkDEBUGCODE(fNumPlots = numPlotsX * numPlotsY;) - - // We currently do not support compressed atlases... - SkASSERT(!GrPixelConfigIsCompressed(texture->desc().fConfig)); - - // set up allocated plots - fPlotArray = new SkAutoTUnref[numPlotsX * numPlotsY]; - - SkAutoTUnref* currPlot = fPlotArray; - for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) { - for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) { - uint32_t index = r * numPlotsX + c; - currPlot->reset(new BatchPlot(index, 1, x, y, fPlotWidth, fPlotHeight, - texture->desc().fConfig)); - - // build LRU list - fPlotList.addToHead(currPlot->get()); - ++currPlot; - } - } -} - -GrBatchAtlas::~GrBatchAtlas() { - SkSafeUnref(fTexture); - delete[] fPlotArray; -} - -void GrBatchAtlas::processEviction(AtlasID id) { - for (int i = 0; i < fEvictionCallbacks.count(); i++) { - (*fEvictionCallbacks[i].fFunc)(id, fEvictionCallbacks[i].fData); - } -} - -inline void GrBatchAtlas::updatePlot(GrDrawBatch::Target* target, AtlasID* id, BatchPlot* plot) { - this->makeMRU(plot); - - // If our most recent upload has already occurred then we have to insert a new - // upload. Otherwise, we already have a scheduled upload that hasn't yet ocurred. - // This new update will piggy back on that previously scheduled update. - if (target->hasDrawBeenFlushed(plot->lastUploadToken())) { - // With c+14 we could move sk_sp into lamba to only ref once. - sk_sp plotsp(SkRef(plot)); - GrTexture* texture = fTexture; - GrBatchDrawToken lastUploadToken = target->addAsapUpload( - [plotsp, texture] (GrDrawBatch::WritePixelsFn& writePixels) { - plotsp->uploadToTexture(writePixels, texture); - } - ); - plot->setLastUploadToken(lastUploadToken); - } - *id = plot->id(); -} - -bool GrBatchAtlas::addToAtlas(AtlasID* id, GrDrawBatch::Target* target, - int width, int height, const void* image, SkIPoint16* loc) { - // We should already have a texture, TODO clean this up - SkASSERT(fTexture); - if (width > fPlotWidth || height > fPlotHeight) { - return false; - } - - // now look through all allocated plots for one we can share, in Most Recently Refed order - GrBatchPlotList::Iter plotIter; - plotIter.init(fPlotList, GrBatchPlotList::Iter::kHead_IterStart); - BatchPlot* plot; - while ((plot = plotIter.get())) { - SkASSERT(GrBytesPerPixel(fTexture->desc().fConfig) == plot->bpp()); - if (plot->addSubImage(width, height, image, loc)) { - this->updatePlot(target, id, plot); - return true; - } - plotIter.next(); - } - - // If the above fails, then see if the least recently refed plot has already been flushed to the - // gpu - plot = fPlotList.tail(); - SkASSERT(plot); - if (target->hasDrawBeenFlushed(plot->lastUseToken())) { - this->processEviction(plot->id()); - plot->resetRects(); - SkASSERT(GrBytesPerPixel(fTexture->desc().fConfig) == plot->bpp()); - SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc); - SkASSERT(verify); - this->updatePlot(target, id, plot); - fAtlasGeneration++; - return true; - } - - // If this plot has been used in a draw that is currently being prepared by a batch, then we - // have to fail. This gives the batch a chance to enqueue the draw, and call back into this - // function. When that draw is enqueued, the draw token advances, and the subsequent call will - // continue past this branch and prepare an inline upload that will occur after the enqueued - // draw which references the plot's pre-upload content. - if (plot->lastUseToken() == target->nextDrawToken()) { - return false; - } - - this->processEviction(plot->id()); - fPlotList.remove(plot); - SkAutoTUnref& newPlot = fPlotArray[plot->index()]; - newPlot.reset(plot->clone()); - - fPlotList.addToHead(newPlot.get()); - SkASSERT(GrBytesPerPixel(fTexture->desc().fConfig) == newPlot->bpp()); - SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc); - SkASSERT(verify); - - // Note that this plot will be uploaded inline with the draws whereas the - // one it displaced most likely was uploaded asap. - // With c+14 we could move sk_sp into lamba to only ref once. - sk_sp plotsp(SkRef(newPlot.get())); - GrTexture* texture = fTexture; - GrBatchDrawToken lastUploadToken = target->addInlineUpload( - [plotsp, texture] (GrDrawBatch::WritePixelsFn& writePixels) { - plotsp->uploadToTexture(writePixels, texture); - } - ); - newPlot->setLastUploadToken(lastUploadToken); - - *id = newPlot->id(); - - fAtlasGeneration++; - return true; -} diff --git a/gfx/skia/skia/src/gpu/GrBatchAtlas.h b/gfx/skia/skia/src/gpu/GrBatchAtlas.h deleted file mode 100644 index 827106fdf9ca..000000000000 --- a/gfx/skia/skia/src/gpu/GrBatchAtlas.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrBatchAtlas_DEFINED -#define GrBatchAtlas_DEFINED - -#include "GrTexture.h" -#include "SkPoint.h" -#include "SkTDArray.h" -#include "SkTInternalLList.h" - -#include "batches/GrDrawBatch.h" - -class GrRectanizer; - -struct GrBatchAtlasConfig { - int numPlotsX() const { return fWidth / fPlotWidth; } - int numPlotsY() const { return fHeight / fPlotWidth; } - int fWidth; - int fHeight; - int fLog2Width; - int fLog2Height; - int fPlotWidth; - int fPlotHeight; -}; - -class GrBatchAtlas { -public: - // An AtlasID is an opaque handle which callers can use to determine if the atlas contains - // a specific piece of data - typedef uint64_t AtlasID; - static const uint32_t kInvalidAtlasID = 0; - static const uint64_t kInvalidAtlasGeneration = 0; - - // A function pointer for use as a callback during eviction. Whenever GrBatchAtlas evicts a - // specific AtlasID, it will call all of the registered listeners so they can optionally process - // the eviction - typedef void (*EvictionFunc)(GrBatchAtlas::AtlasID, void*); - - GrBatchAtlas(GrTexture*, int numPlotsX, int numPlotsY); - ~GrBatchAtlas(); - - // Adds a width x height subimage to the atlas. Upon success it returns - // the containing GrPlot and absolute location in the backing texture. - // nullptr is returned if the subimage cannot fit in the atlas. - // If provided, the image data will be written to the CPU-side backing bitmap. - // NOTE: If the client intends to refer to the atlas, they should immediately call 'setUseToken' - // with the currentToken from the batch target, otherwise the next call to addToAtlas might - // cause an eviction - bool addToAtlas(AtlasID*, GrDrawBatch::Target*, int width, int height, const void* image, - SkIPoint16* loc); - - GrTexture* getTexture() const { return fTexture; } - - uint64_t atlasGeneration() const { return fAtlasGeneration; } - - inline bool hasID(AtlasID id) { - uint32_t index = GetIndexFromID(id); - SkASSERT(index < fNumPlots); - return fPlotArray[index]->genID() == GetGenerationFromID(id); - } - - // To ensure the atlas does not evict a given entry, the client must set the last use token - inline void setLastUseToken(AtlasID id, GrBatchDrawToken batchToken) { - SkASSERT(this->hasID(id)); - uint32_t index = GetIndexFromID(id); - SkASSERT(index < fNumPlots); - this->makeMRU(fPlotArray[index]); - fPlotArray[index]->setLastUseToken(batchToken); - } - - inline void registerEvictionCallback(EvictionFunc func, void* userData) { - EvictionData* data = fEvictionCallbacks.append(); - data->fFunc = func; - data->fData = userData; - } - - /* - * A class which can be handed back to GrBatchAtlas for updating in bulk last use tokens. The - * current max number of plots the GrBatchAtlas can handle is 32, if in the future this is - * insufficient then we can move to a 64 bit int - */ - class BulkUseTokenUpdater { - public: - BulkUseTokenUpdater() : fPlotAlreadyUpdated(0) {} - BulkUseTokenUpdater(const BulkUseTokenUpdater& that) - : fPlotsToUpdate(that.fPlotsToUpdate) - , fPlotAlreadyUpdated(that.fPlotAlreadyUpdated) { - } - - void add(AtlasID id) { - int index = GrBatchAtlas::GetIndexFromID(id); - if (!this->find(index)) { - this->set(index); - } - } - - void reset() { - fPlotsToUpdate.reset(); - fPlotAlreadyUpdated = 0; - } - - private: - bool find(int index) const { - SkASSERT(index < kMaxPlots); - return (fPlotAlreadyUpdated >> index) & 1; - } - - void set(int index) { - SkASSERT(!this->find(index)); - fPlotAlreadyUpdated = fPlotAlreadyUpdated | (1 << index); - fPlotsToUpdate.push_back(index); - } - - static const int kMinItems = 4; - static const int kMaxPlots = 32; - SkSTArray fPlotsToUpdate; - uint32_t fPlotAlreadyUpdated; - - friend class GrBatchAtlas; - }; - - void setLastUseTokenBulk(const BulkUseTokenUpdater& updater, GrBatchDrawToken batchToken) { - int count = updater.fPlotsToUpdate.count(); - for (int i = 0; i < count; i++) { - BatchPlot* plot = fPlotArray[updater.fPlotsToUpdate[i]]; - this->makeMRU(plot); - plot->setLastUseToken(batchToken); - } - } - - static const int kGlyphMaxDim = 256; - static bool GlyphTooLargeForAtlas(int width, int height) { - return width > kGlyphMaxDim || height > kGlyphMaxDim; - } - -private: - // The backing GrTexture for a GrBatchAtlas is broken into a spatial grid of BatchPlots. - // The BatchPlots keep track of subimage placement via their GrRectanizer. A BatchPlot - // manages the lifetime of its data using two tokens, a last use token and a last upload token. - // Once a BatchPlot is "full" (i.e. there is no room for the new subimage according to the - // GrRectanizer), it can no longer be used unless the last use of the GrPlot has already been - // flushed through to the gpu. - class BatchPlot : public SkRefCnt { - SK_DECLARE_INTERNAL_LLIST_INTERFACE(BatchPlot); - - public: - // index() is a unique id for the plot relative to the owning GrAtlas. genID() is a - // monotonically incremented number which is bumped every time this plot is - // evicted from the cache (i.e., there is continuity in genID() across atlas spills). - uint32_t index() const { return fIndex; } - uint64_t genID() const { return fGenID; } - GrBatchAtlas::AtlasID id() const { - SkASSERT(GrBatchAtlas::kInvalidAtlasID != fID); - return fID; - } - SkDEBUGCODE(size_t bpp() const { return fBytesPerPixel; }) - - bool addSubImage(int width, int height, const void* image, SkIPoint16* loc); - - // To manage the lifetime of a plot, we use two tokens. We use the last upload token to - // know when we can 'piggy back' uploads, ie if the last upload hasn't been flushed to gpu, - // we don't need to issue a new upload even if we update the cpu backing store. We use - // lastUse to determine when we can evict a plot from the cache, ie if the last use has - // already flushed through the gpu then we can reuse the plot. - GrBatchDrawToken lastUploadToken() const { return fLastUpload; } - GrBatchDrawToken lastUseToken() const { return fLastUse; } - void setLastUploadToken(GrBatchDrawToken batchToken) { fLastUpload = batchToken; } - void setLastUseToken(GrBatchDrawToken batchToken) { fLastUse = batchToken; } - - void uploadToTexture(GrDrawBatch::WritePixelsFn&, GrTexture* texture); - void resetRects(); - - private: - BatchPlot(int index, uint64_t genID, int offX, int offY, int width, int height, - GrPixelConfig config); - - ~BatchPlot() override; - - // Create a clone of this plot. The cloned plot will take the place of the - // current plot in the atlas. - BatchPlot* clone() const { - return new BatchPlot(fIndex, fGenID+1, fX, fY, fWidth, fHeight, fConfig); - } - - static GrBatchAtlas::AtlasID CreateId(uint32_t index, uint64_t generation) { - SkASSERT(index < (1 << 16)); - SkASSERT(generation < ((uint64_t)1 << 48)); - return generation << 16 | index; - } - - GrBatchDrawToken fLastUpload; - GrBatchDrawToken fLastUse; - - const uint32_t fIndex; - uint64_t fGenID; - GrBatchAtlas::AtlasID fID; - unsigned char* fData; - const int fWidth; - const int fHeight; - const int fX; - const int fY; - GrRectanizer* fRects; - const SkIPoint16 fOffset; // the offset of the plot in the backing texture - const GrPixelConfig fConfig; - const size_t fBytesPerPixel; - SkIRect fDirtyRect; - SkDEBUGCODE(bool fDirty;) - - friend class GrBatchAtlas; - - typedef SkRefCnt INHERITED; - }; - - typedef SkTInternalLList GrBatchPlotList; - - static uint32_t GetIndexFromID(AtlasID id) { - return id & 0xffff; - } - - // top 48 bits are reserved for the generation ID - static uint64_t GetGenerationFromID(AtlasID id) { - return (id >> 16) & 0xffffffffffff; - } - - inline void updatePlot(GrDrawBatch::Target*, AtlasID*, BatchPlot*); - - inline void makeMRU(BatchPlot* plot) { - if (fPlotList.head() == plot) { - return; - } - - fPlotList.remove(plot); - fPlotList.addToHead(plot); - } - - inline void processEviction(AtlasID); - - GrTexture* fTexture; - int fPlotWidth; - int fPlotHeight; - SkDEBUGCODE(uint32_t fNumPlots;) - - uint64_t fAtlasGeneration; - - struct EvictionData { - EvictionFunc fFunc; - void* fData; - }; - - SkTDArray fEvictionCallbacks; - // allocated array of GrBatchPlots - SkAutoTUnref* fPlotArray; - // LRU list of GrPlots (MRU at head - LRU at tail) - GrBatchPlotList fPlotList; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/GrBatchFlushState.cpp b/gfx/skia/skia/src/gpu/GrBatchFlushState.cpp deleted file mode 100644 index 4e51ae4ddd02..000000000000 --- a/gfx/skia/skia/src/gpu/GrBatchFlushState.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrBatchFlushState.h" - -#include "GrBatchAtlas.h" -#include "GrPipeline.h" - -GrBatchFlushState::GrBatchFlushState(GrGpu* gpu, GrResourceProvider* resourceProvider) - : fGpu(gpu) - , fResourceProvider(resourceProvider) - , fCommandBuffer(nullptr) - , fVertexPool(gpu) - , fIndexPool(gpu) - , fLastIssuedToken(GrBatchDrawToken::AlreadyFlushedToken()) - , fLastFlushedToken(0) {} - -void* GrBatchFlushState::makeVertexSpace(size_t vertexSize, int vertexCount, - const GrBuffer** buffer, int* startVertex) { - return fVertexPool.makeSpace(vertexSize, vertexCount, buffer, startVertex); -} - -uint16_t* GrBatchFlushState::makeIndexSpace(int indexCount, - const GrBuffer** buffer, int* startIndex) { - return reinterpret_cast(fIndexPool.makeSpace(indexCount, buffer, startIndex)); -} diff --git a/gfx/skia/skia/src/gpu/GrBatchTest.cpp b/gfx/skia/skia/src/gpu/GrBatchTest.cpp deleted file mode 100644 index fe320a268ab6..000000000000 --- a/gfx/skia/skia/src/gpu/GrBatchTest.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrBatchTest.h" -#include "SkRandom.h" -#include "SkTypes.h" - -#ifdef GR_TEST_UTILS - -DRAW_BATCH_TEST_EXTERN(AAConvexPathBatch); -DRAW_BATCH_TEST_EXTERN(AADistanceFieldPathBatch); -DRAW_BATCH_TEST_EXTERN(AAFillRectBatch); -DRAW_BATCH_TEST_EXTERN(AAFillRectBatchLocalMatrix); -DRAW_BATCH_TEST_EXTERN(AAHairlineBatch); -DRAW_BATCH_TEST_EXTERN(AAStrokeRectBatch); -DRAW_BATCH_TEST_EXTERN(AnalyticRectBatch); -DRAW_BATCH_TEST_EXTERN(DashBatch); -DRAW_BATCH_TEST_EXTERN(DefaultPathBatch); -DRAW_BATCH_TEST_EXTERN(CircleBatch); -DRAW_BATCH_TEST_EXTERN(DIEllipseBatch); -DRAW_BATCH_TEST_EXTERN(EllipseBatch); -DRAW_BATCH_TEST_EXTERN(GrDrawAtlasBatch); -DRAW_BATCH_TEST_EXTERN(NonAAStrokeRectBatch); -DRAW_BATCH_TEST_EXTERN(RRectBatch); -DRAW_BATCH_TEST_EXTERN(TesselatingPathBatch); -DRAW_BATCH_TEST_EXTERN(TextBlobBatch); -DRAW_BATCH_TEST_EXTERN(VerticesBatch); - -static BatchTestFunc gTestBatches[] = { - DRAW_BATCH_TEST_ENTRY(AAConvexPathBatch), - DRAW_BATCH_TEST_ENTRY(AADistanceFieldPathBatch), - DRAW_BATCH_TEST_ENTRY(AAFillRectBatch), - DRAW_BATCH_TEST_ENTRY(AAFillRectBatchLocalMatrix), - DRAW_BATCH_TEST_ENTRY(AAHairlineBatch), - DRAW_BATCH_TEST_ENTRY(AAStrokeRectBatch), - DRAW_BATCH_TEST_ENTRY(AnalyticRectBatch), - DRAW_BATCH_TEST_ENTRY(DashBatch), - DRAW_BATCH_TEST_ENTRY(DefaultPathBatch), - DRAW_BATCH_TEST_ENTRY(CircleBatch), - DRAW_BATCH_TEST_ENTRY(DIEllipseBatch), - DRAW_BATCH_TEST_ENTRY(EllipseBatch), - DRAW_BATCH_TEST_ENTRY(GrDrawAtlasBatch), - DRAW_BATCH_TEST_ENTRY(NonAAStrokeRectBatch), - DRAW_BATCH_TEST_ENTRY(RRectBatch), - DRAW_BATCH_TEST_ENTRY(TesselatingPathBatch), - DRAW_BATCH_TEST_ENTRY(TextBlobBatch), - DRAW_BATCH_TEST_ENTRY(VerticesBatch) -}; - -GrDrawBatch* GrRandomDrawBatch(SkRandom* random, GrContext* context) { - uint32_t index = random->nextULessThan(static_cast(SK_ARRAY_COUNT(gTestBatches))); - BatchTestFunc func = gTestBatches[index]; - return (*func)(random, context); -} -#endif diff --git a/gfx/skia/skia/src/gpu/GrBatchTest.h b/gfx/skia/skia/src/gpu/GrBatchTest.h deleted file mode 100644 index 32e8e28930e6..000000000000 --- a/gfx/skia/skia/src/gpu/GrBatchTest.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrBatchTest_DEFINED -#define GrBatchTest_DEFINED - -#include "GrTestUtils.h" - -#ifdef GR_TEST_UTILS - -class GrDrawBatch; -class GrContext; -class SkRandom; - -/* - * This file defines some macros for testing batches, and also declares functions / objects which - * are generally useful for GrBatch testing - */ - -// Batches should define test functions using DRAW_BATCH_TEST_DEFINE. The other macros defined -// below are used exclusively by the test harness. -typedef GrDrawBatch* (*BatchTestFunc)(SkRandom* random, GrContext* context); -#define DRAW_BATCH_TEST_DEFINE(Batch) \ - GrDrawBatch* Batch##__Test(SkRandom* random, GrContext* context) -#define DRAW_BATCH_TEST_EXTERN(Batch) \ - extern GrDrawBatch* Batch##__Test(SkRandom*, GrContext* context); -#define DRAW_BATCH_TEST_ENTRY(Batch) \ - Batch##__Test -#define DRAW_BATCH_TEST_FRIEND(Batch) \ - friend GrDrawBatch* Batch##__Test(SkRandom* random, GrContext* context); - -GrDrawBatch* GrRandomDrawBatch(SkRandom*, GrContext*); - -#endif -#endif diff --git a/gfx/skia/skia/src/gpu/GrBitmapTextureMaker.cpp b/gfx/skia/skia/src/gpu/GrBitmapTextureMaker.cpp new file mode 100644 index 000000000000..6c771675eea7 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrBitmapTextureMaker.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrBitmapTextureMaker.h" + +#include "GrContext.h" +#include "GrGpuResourcePriv.h" +#include "GrResourceProvider.h" +#include "SkBitmap.h" +#include "SkGr.h" +#include "SkPixelRef.h" + +static bool bmp_is_alpha_only(const SkBitmap& bm) { return kAlpha_8_SkColorType == bm.colorType(); } + +GrBitmapTextureMaker::GrBitmapTextureMaker(GrContext* context, const SkBitmap& bitmap) + : INHERITED(context, bitmap.width(), bitmap.height(), bmp_is_alpha_only(bitmap)) + , fBitmap(bitmap) { + if (!bitmap.isVolatile()) { + SkIPoint origin = bitmap.pixelRefOrigin(); + SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bitmap.width(), + bitmap.height()); + GrMakeKeyFromImageID(&fOriginalKey, bitmap.pixelRef()->getGenerationID(), subset); + } +} + +sk_sp GrBitmapTextureMaker::refOriginalTextureProxy(bool willBeMipped, + SkColorSpace* dstColorSpace) { + sk_sp proxy; + + if (fOriginalKey.isValid()) { + proxy = this->context()->resourceProvider()->findProxyByUniqueKey(fOriginalKey); + if (proxy) { + return proxy; + } + } + if (willBeMipped) { + proxy = GrGenerateMipMapsAndUploadToTextureProxy(this->context(), fBitmap, dstColorSpace); + } + if (!proxy) { + proxy = GrUploadBitmapToTextureProxy(this->context()->resourceProvider(), fBitmap); + } + if (proxy && fOriginalKey.isValid()) { + this->context()->resourceProvider()->assignUniqueKeyToProxy(fOriginalKey, proxy.get()); + // MDB TODO (caching): this has to play nice with the GrSurfaceProxy's caching + GrInstallBitmapUniqueKeyInvalidator(fOriginalKey, fBitmap.pixelRef()); + } + return proxy; +} + +void GrBitmapTextureMaker::makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey, + SkColorSpace* dstColorSpace) { + // Destination color space is irrelevant - we always upload the bitmap's contents as-is + if (fOriginalKey.isValid()) { + MakeCopyKeyFromOrigKey(fOriginalKey, copyParams, copyKey); + } +} + +void GrBitmapTextureMaker::didCacheCopy(const GrUniqueKey& copyKey) { + GrInstallBitmapUniqueKeyInvalidator(copyKey, fBitmap.pixelRef()); +} + +SkAlphaType GrBitmapTextureMaker::alphaType() const { + return fBitmap.alphaType(); +} + +sk_sp GrBitmapTextureMaker::getColorSpace(SkColorSpace* dstColorSpace) { + // Color space doesn't depend on destination color space - it's just whatever is in the bitmap + return fBitmap.refColorSpace(); +} diff --git a/gfx/skia/skia/src/gpu/GrBitmapTextureMaker.h b/gfx/skia/skia/src/gpu/GrBitmapTextureMaker.h new file mode 100644 index 000000000000..c706962cdf36 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrBitmapTextureMaker.h @@ -0,0 +1,39 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrBitmapTextureMaker_DEFINED +#define GrBitmapTextureMaker_DEFINED + +#include "GrTextureMaker.h" + +/** This class manages the conversion of SW-backed bitmaps to GrTextures. If the input bitmap is + non-volatile the texture is cached using a key created from the pixels' image id and the + subset of the pixelref specified by the bitmap. */ +class GrBitmapTextureMaker : public GrTextureMaker { +public: + GrBitmapTextureMaker(GrContext* context, const SkBitmap& bitmap); + +protected: + sk_sp refOriginalTextureProxy(bool willBeMipped, + SkColorSpace* dstColorSpace) override; + + void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey, + SkColorSpace* dstColorSpace) override; + + void didCacheCopy(const GrUniqueKey& copyKey) override; + + SkAlphaType alphaType() const override; + sk_sp getColorSpace(SkColorSpace* dstColorSpace) override; + +private: + const SkBitmap fBitmap; + GrUniqueKey fOriginalKey; + + typedef GrTextureMaker INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrBlurUtils.cpp b/gfx/skia/skia/src/gpu/GrBlurUtils.cpp index 5f575e3c8471..9d28b54f542f 100644 --- a/gfx/skia/skia/src/gpu/GrBlurUtils.cpp +++ b/gfx/skia/skia/src/gpu/GrBlurUtils.cpp @@ -6,16 +6,19 @@ */ #include "GrBlurUtils.h" -#include "GrDrawContext.h" +#include "GrRenderTargetContext.h" #include "GrCaps.h" #include "GrContext.h" +#include "GrContextPriv.h" #include "GrFixedClip.h" +#include "GrRenderTargetContextPriv.h" +#include "GrResourceProvider.h" #include "effects/GrSimpleTextureEffect.h" #include "GrStyle.h" #include "GrTexture.h" -#include "GrTextureProvider.h" +#include "GrTextureProxy.h" #include "SkDraw.h" -#include "SkGrPriv.h" +#include "SkGr.h" #include "SkMaskFilter.h" #include "SkPaint.h" #include "SkTLazy.h" @@ -27,35 +30,39 @@ static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& r // Draw a mask using the supplied paint. Since the coverage/geometry // is already burnt into the mask this boils down to a rect draw. // Return true if the mask was successfully drawn. -static bool draw_mask(GrDrawContext* drawContext, +static bool draw_mask(GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkMatrix& viewMatrix, const SkIRect& maskRect, - GrPaint* grp, - GrTexture* mask) { - SkMatrix matrix; - matrix.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); - matrix.postIDiv(mask->width(), mask->height()); - matrix.preConcat(viewMatrix); - grp->addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(mask, nullptr, matrix)); - + GrPaint&& paint, + sk_sp mask) { SkMatrix inverse; if (!viewMatrix.invert(&inverse)) { return false; } - drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), SkRect::Make(maskRect), - inverse); + + GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider(); + + SkMatrix matrix = SkMatrix::MakeTrans(-SkIntToScalar(maskRect.fLeft), + -SkIntToScalar(maskRect.fTop)); + matrix.preConcat(viewMatrix); + paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(resourceProvider, + std::move(mask), + nullptr, matrix)); + + renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(maskRect), inverse); return true; } -static bool sw_draw_with_mask_filter(GrDrawContext* drawContext, - GrTextureProvider* textureProvider, +static bool sw_draw_with_mask_filter(GrContext* context, + GrRenderTargetContext* renderTargetContext, const GrClip& clipData, const SkMatrix& viewMatrix, const SkPath& devPath, const SkMaskFilter* filter, const SkIRect& clipBounds, - GrPaint* grp, + GrPaint&& paint, SkStrokeRec::InitStyle fillOrHairline) { SkMask srcM, dstM; if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM, @@ -77,64 +84,70 @@ static bool sw_draw_with_mask_filter(GrDrawContext* drawContext, // we now have a device-aligned 8bit mask in dstM, ready to be drawn using // the current clip (and identity matrix) and GrPaint settings GrSurfaceDesc desc; + desc.fOrigin = kTopLeft_GrSurfaceOrigin; desc.fWidth = dstM.fBounds.width(); desc.fHeight = dstM.fBounds.height(); desc.fConfig = kAlpha_8_GrPixelConfig; - SkAutoTUnref texture(textureProvider->createApproxTexture(desc)); - if (!texture) { + sk_sp sContext = context->contextPriv().makeDeferredSurfaceContext( + desc, + SkBackingFit::kApprox, + SkBudgeted::kYes); + if (!sContext) { return false; } - texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, - dstM.fImage, dstM.fRowBytes); - return draw_mask(drawContext, clipData, viewMatrix, dstM.fBounds, grp, texture); + SkImageInfo ii = SkImageInfo::MakeA8(desc.fWidth, desc.fHeight); + if (!sContext->writePixels(ii, dstM.fImage, dstM.fRowBytes, 0, 0)) { + return false; + } + + return draw_mask(renderTargetContext, clipData, viewMatrix, + dstM.fBounds, std::move(paint), sContext->asTextureProxyRef()); } // Create a mask of 'devPath' and place the result in 'mask'. -static sk_sp create_mask_GPU(GrContext* context, - const SkIRect& maskRect, - const SkPath& devPath, - SkStrokeRec::InitStyle fillOrHairline, - bool doAA, - int sampleCnt) { - if (!doAA) { +static sk_sp create_mask_GPU(GrContext* context, + const SkIRect& maskRect, + const SkPath& devPath, + SkStrokeRec::InitStyle fillOrHairline, + GrAA aa, + int sampleCnt) { + if (GrAA::kNo == aa) { // Don't need MSAA if mask isn't AA sampleCnt = 0; } - sk_sp drawContext(context->makeDrawContextWithFallback(SkBackingFit::kApprox, - maskRect.width(), - maskRect.height(), - kAlpha_8_GrPixelConfig, - nullptr, - sampleCnt)); - if (!drawContext) { + sk_sp rtContext(context->makeDeferredRenderTargetContextWithFallback( + SkBackingFit::kApprox, maskRect.width(), maskRect.height(), kAlpha_8_GrPixelConfig, nullptr, + sampleCnt)); + if (!rtContext) { return nullptr; } - drawContext->clear(nullptr, 0x0, true); + rtContext->priv().absClear(nullptr, 0x0); - GrPaint tempPaint; - tempPaint.setAntiAlias(doAA); - tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); + GrPaint maskPaint; + maskPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height()); GrFixedClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at - // the origin using tempPaint. + // the origin using maskPaint. SkMatrix translate; translate.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); - drawContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHairline)); - return drawContext->asTexture();; + rtContext->drawPath(clip, std::move(maskPaint), aa, translate, devPath, + GrStyle(fillOrHairline)); + return rtContext->asTextureProxyRef(); } static void draw_path_with_mask_filter(GrContext* context, - GrDrawContext* drawContext, + GrRenderTargetContext* renderTargetContext, const GrClip& clip, - GrPaint* paint, + GrPaint&& paint, + GrAA aa, const SkMatrix& viewMatrix, const SkMaskFilter* maskFilter, const GrStyle& style, @@ -143,7 +156,9 @@ static void draw_path_with_mask_filter(GrContext* context, SkASSERT(maskFilter); SkIRect clipBounds; - clip.getConservativeBounds(drawContext->width(), drawContext->height(), &clipBounds); + clip.getConservativeBounds(renderTargetContext->width(), + renderTargetContext->height(), + &clipBounds); SkTLazy tmpPath; SkStrokeRec::InitStyle fillOrHairline; @@ -194,9 +209,9 @@ static void draw_path_with_mask_filter(GrContext* context, return; } - if (maskFilter->directFilterMaskGPU(context->textureProvider(), - drawContext, - paint, + if (maskFilter->directFilterMaskGPU(context, + renderTargetContext, + std::move(paint), clip, viewMatrix, SkStrokeRec(fillOrHairline), @@ -206,19 +221,20 @@ static void draw_path_with_mask_filter(GrContext* context, return; } - sk_sp mask(create_mask_GPU(context, - finalIRect, - *path, - fillOrHairline, - paint->isAntiAlias(), - drawContext->numColorSamples())); - if (mask) { - GrTexture* filtered; - - if (maskFilter->filterMaskGPU(mask.get(), viewMatrix, finalIRect, &filtered)) { - // filterMaskGPU gives us ownership of a ref to the result - SkAutoTUnref atu(filtered); - if (draw_mask(drawContext, clip, viewMatrix, finalIRect, paint, filtered)) { + sk_sp maskProxy(create_mask_GPU(context, + finalIRect, + *path, + fillOrHairline, + aa, + renderTargetContext->numColorSamples())); + if (maskProxy) { + sk_sp filtered = maskFilter->filterMaskGPU(context, + std::move(maskProxy), + viewMatrix, + finalIRect); + if (filtered) { + if (draw_mask(renderTargetContext, clip, viewMatrix, + finalIRect, std::move(paint), std::move(filtered))) { // This path is completely drawn return; } @@ -226,26 +242,26 @@ static void draw_path_with_mask_filter(GrContext* context, } } - sw_draw_with_mask_filter(drawContext, context->textureProvider(), - clip, viewMatrix, *path, - maskFilter, clipBounds, paint, fillOrHairline); + sw_draw_with_mask_filter(context, renderTargetContext, clip, viewMatrix, *path, maskFilter, + clipBounds, std::move(paint), fillOrHairline); } void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, - GrDrawContext* drawContext, + GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkPath& path, - GrPaint* paint, + GrPaint&& paint, + GrAA aa, const SkMatrix& viewMatrix, const SkMaskFilter* mf, const GrStyle& style, bool pathIsMutable) { - draw_path_with_mask_filter(context, drawContext, clip, paint, viewMatrix, mf, - style, &path, pathIsMutable); + draw_path_with_mask_filter(context, renderTargetContext, clip, std::move(paint), aa, viewMatrix, + mf, style, &path, pathIsMutable); } void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, - GrDrawContext* drawContext, + GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkPath& origPath, const SkPaint& paint, @@ -281,15 +297,16 @@ void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) GrPaint grPaint; - if (!SkPaintToGrPaint(context, drawContext, paint, viewMatrix, &grPaint)) { + if (!SkPaintToGrPaint(context, renderTargetContext, paint, viewMatrix, &grPaint)) { return; } - - if (paint.getMaskFilter()) { - draw_path_with_mask_filter(context, drawContext, clip, &grPaint, viewMatrix, - paint.getMaskFilter(), style, - path, pathIsMutable); + GrAA aa = GrBoolToAA(paint.isAntiAlias()); + SkMaskFilter* mf = paint.getMaskFilter(); + if (mf && !mf->asFragmentProcessor(nullptr, nullptr, viewMatrix)) { + // The MaskFilter wasn't already handled in SkPaintToGrPaint + draw_path_with_mask_filter(context, renderTargetContext, clip, std::move(grPaint), aa, + viewMatrix, mf, style, path, pathIsMutable); } else { - drawContext->drawPath(clip, grPaint, viewMatrix, *path, style); + renderTargetContext->drawPath(clip, std::move(grPaint), aa, viewMatrix, *path, style); } } diff --git a/gfx/skia/skia/src/gpu/GrBlurUtils.h b/gfx/skia/skia/src/gpu/GrBlurUtils.h index aef1bdba05df..bf6d63874861 100644 --- a/gfx/skia/skia/src/gpu/GrBlurUtils.h +++ b/gfx/skia/skia/src/gpu/GrBlurUtils.h @@ -8,11 +8,13 @@ #ifndef GrBlurUtils_DEFINED #define GrBlurUtils_DEFINED +#include "GrTypes.h" + class GrClip; class GrContext; -class GrDrawContext; class GrPaint; class GrRenderTarget; +class GrRenderTargetContext; class GrStyle; struct SkIRect; class SkMaskFilter; @@ -30,7 +32,7 @@ namespace GrBlurUtils { * Draw a path handling the mask filter if present. */ void drawPathWithMaskFilter(GrContext* context, - GrDrawContext* drawContext, + GrRenderTargetContext* renderTargetContext, const GrClip& clip, const SkPath& origSrcPath, const SkPaint& paint, @@ -44,15 +46,15 @@ namespace GrBlurUtils { * optional. The GrPaint will be modified after return. */ void drawPathWithMaskFilter(GrContext*, - GrDrawContext*, + GrRenderTargetContext*, const GrClip&, const SkPath& path, - GrPaint*, + GrPaint&&, + GrAA, const SkMatrix& viewMatrix, const SkMaskFilter*, const GrStyle&, bool pathIsMutable); - }; #endif diff --git a/gfx/skia/skia/src/gpu/GrBufferAllocPool.cpp b/gfx/skia/skia/src/gpu/GrBufferAllocPool.cpp index e3f30b0c1c57..38bde0dc9a38 100644 --- a/gfx/skia/skia/src/gpu/GrBufferAllocPool.cpp +++ b/gfx/skia/skia/src/gpu/GrBufferAllocPool.cpp @@ -334,7 +334,7 @@ void* GrVertexBufferAllocPool::makeSpace(size_t vertexSize, SkASSERT(buffer); SkASSERT(startVertex); - size_t offset = 0; // assign to suppress warning + size_t offset SK_INIT_TO_AVOID_WARNING; void* ptr = INHERITED::makeSpace(vertexSize * vertexCount, vertexSize, buffer, @@ -359,7 +359,7 @@ void* GrIndexBufferAllocPool::makeSpace(int indexCount, SkASSERT(buffer); SkASSERT(startIndex); - size_t offset = 0; // assign to suppress warning + size_t offset SK_INIT_TO_AVOID_WARNING; void* ptr = INHERITED::makeSpace(indexCount * sizeof(uint16_t), sizeof(uint16_t), buffer, diff --git a/gfx/skia/skia/src/gpu/GrCaps.cpp b/gfx/skia/skia/src/gpu/GrCaps.cpp index 0f77b5a47774..ade64d6588c1 100644 --- a/gfx/skia/skia/src/gpu/GrCaps.cpp +++ b/gfx/skia/skia/src/gpu/GrCaps.cpp @@ -9,79 +9,28 @@ #include "GrContextOptions.h" #include "GrWindowRectangles.h" -GrShaderCaps::GrShaderCaps() { - fShaderDerivativeSupport = false; - fGeometryShaderSupport = false; - fPathRenderingSupport = false; - fDstReadInShaderSupport = false; - fDualSourceBlendingSupport = false; - fIntegerSupport = false; - fTexelBufferSupport = false; - fShaderPrecisionVaries = false; -} - -static const char* shader_type_to_string(GrShaderType type) { - switch (type) { - case kVertex_GrShaderType: - return "vertex"; - case kGeometry_GrShaderType: - return "geometry"; - case kFragment_GrShaderType: - return "fragment"; +static const char* pixel_config_name(GrPixelConfig config) { + switch (config) { + case kUnknown_GrPixelConfig: return "Unknown"; + case kAlpha_8_GrPixelConfig: return "Alpha8"; + case kGray_8_GrPixelConfig: return "Gray8"; + case kRGB_565_GrPixelConfig: return "RGB565"; + case kRGBA_4444_GrPixelConfig: return "RGBA444"; + case kRGBA_8888_GrPixelConfig: return "RGBA8888"; + case kBGRA_8888_GrPixelConfig: return "BGRA8888"; + case kSRGBA_8888_GrPixelConfig: return "SRGBA8888"; + case kSBGRA_8888_GrPixelConfig: return "SBGRA8888"; + case kRGBA_8888_sint_GrPixelConfig: return "RGBA8888_sint"; + case kETC1_GrPixelConfig: return "ETC1"; + case kRGBA_float_GrPixelConfig: return "RGBAFloat"; + case kRG_float_GrPixelConfig: return "RGFloat"; + case kAlpha_half_GrPixelConfig: return "AlphaHalf"; + case kRGBA_half_GrPixelConfig: return "RGBAHalf"; } - return ""; + SkFAIL("Invalid pixel config"); + return ""; } -static const char* precision_to_string(GrSLPrecision p) { - switch (p) { - case kLow_GrSLPrecision: - return "low"; - case kMedium_GrSLPrecision: - return "medium"; - case kHigh_GrSLPrecision: - return "high"; - } - return ""; -} - -SkString GrShaderCaps::dump() const { - SkString r; - static const char* gNY[] = { "NO", "YES" }; - r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]); - r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]); - r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]); - r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]); - r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]); - r.appendf("Integer Support : %s\n", gNY[fIntegerSupport]); - r.appendf("Texel Buffer Support : %s\n", gNY[fTexelBufferSupport]); - - r.appendf("Shader Float Precisions (varies: %s):\n", gNY[fShaderPrecisionVaries]); - - for (int s = 0; s < kGrShaderTypeCount; ++s) { - GrShaderType shaderType = static_cast(s); - r.appendf("\t%s:\n", shader_type_to_string(shaderType)); - for (int p = 0; p < kGrSLPrecisionCount; ++p) { - if (fFloatPrecisions[s][p].supported()) { - GrSLPrecision precision = static_cast(p); - r.appendf("\t\t%s: log_low: %d log_high: %d bits: %d\n", - precision_to_string(precision), - fFloatPrecisions[s][p].fLogRangeLow, - fFloatPrecisions[s][p].fLogRangeHigh, - fFloatPrecisions[s][p].fBits); - } - } - } - - return r; -} - -void GrShaderCaps::applyOptionsOverrides(const GrContextOptions& options) { - fDualSourceBlendingSupport = fDualSourceBlendingSupport && !options.fSuppressDualSourceBlending; - this->onApplyOptionsOverrides(options); -} - -/////////////////////////////////////////////////////////////////////////////// - GrCaps::GrCaps(const GrContextOptions& options) { fMipMapSupport = false; fNPOTTextureTileSupport = false; @@ -104,6 +53,7 @@ GrCaps::GrCaps(const GrContextOptions& options) { fMustClearUploadedBufferData = false; fSampleShadingSupport = false; fFenceSyncSupport = false; + fCrossContextTextureSupport = false; fUseDrawInsteadOfClear = false; @@ -192,6 +142,7 @@ SkString GrCaps::dump() const { r.appendf("Must clear buffer memory : %s\n", gNY[fMustClearUploadedBufferData]); r.appendf("Sample shading support : %s\n", gNY[fSampleShadingSupport]); r.appendf("Fence sync support : %s\n", gNY[fFenceSyncSupport]); + r.appendf("Cross context texture support : %s\n", gNY[fCrossContextTextureSupport]); r.appendf("Draw Instead of Clear [workaround] : %s\n", gNY[fUseDrawInsteadOfClear]); r.appendf("Draw Instead of TexSubImage [workaround] : %s\n", @@ -240,59 +191,23 @@ SkString GrCaps::dump() const { r.appendf("Map Buffer Support : %s\n", map_flags_to_string(fMapBufferFlags).c_str()); - static const char* kConfigNames[] = { - "Unknown", // kUnknown_GrPixelConfig - "Alpha8", // kAlpha_8_GrPixelConfig, - "Index8", // kIndex_8_GrPixelConfig, - "RGB565", // kRGB_565_GrPixelConfig, - "RGBA444", // kRGBA_4444_GrPixelConfig, - "RGBA8888", // kRGBA_8888_GrPixelConfig, - "BGRA8888", // kBGRA_8888_GrPixelConfig, - "SRGBA8888",// kSRGBA_8888_GrPixelConfig, - "SBGRA8888",// kSBGRA_8888_GrPixelConfig, - "ETC1", // kETC1_GrPixelConfig, - "LATC", // kLATC_GrPixelConfig, - "R11EAC", // kR11_EAC_GrPixelConfig, - "ASTC12x12",// kASTC_12x12_GrPixelConfig, - "RGBAFloat",// kRGBA_float_GrPixelConfig - "AlphaHalf",// kAlpha_half_GrPixelConfig - "RGBAHalf", // kRGBA_half_GrPixelConfig - }; - GR_STATIC_ASSERT(0 == kUnknown_GrPixelConfig); - GR_STATIC_ASSERT(1 == kAlpha_8_GrPixelConfig); - GR_STATIC_ASSERT(2 == kIndex_8_GrPixelConfig); - GR_STATIC_ASSERT(3 == kRGB_565_GrPixelConfig); - GR_STATIC_ASSERT(4 == kRGBA_4444_GrPixelConfig); - GR_STATIC_ASSERT(5 == kRGBA_8888_GrPixelConfig); - GR_STATIC_ASSERT(6 == kBGRA_8888_GrPixelConfig); - GR_STATIC_ASSERT(7 == kSRGBA_8888_GrPixelConfig); - GR_STATIC_ASSERT(8 == kSBGRA_8888_GrPixelConfig); - GR_STATIC_ASSERT(9 == kETC1_GrPixelConfig); - GR_STATIC_ASSERT(10 == kLATC_GrPixelConfig); - GR_STATIC_ASSERT(11 == kR11_EAC_GrPixelConfig); - GR_STATIC_ASSERT(12 == kASTC_12x12_GrPixelConfig); - GR_STATIC_ASSERT(13 == kRGBA_float_GrPixelConfig); - GR_STATIC_ASSERT(14 == kAlpha_half_GrPixelConfig); - GR_STATIC_ASSERT(15 == kRGBA_half_GrPixelConfig); - GR_STATIC_ASSERT(SK_ARRAY_COUNT(kConfigNames) == kGrPixelConfigCnt); - SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig, false)); SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig, true)); - for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { + for (size_t i = 1; i < kGrPixelConfigCnt; ++i) { GrPixelConfig config = static_cast(i); r.appendf("%s is renderable: %s, with MSAA: %s\n", - kConfigNames[i], + pixel_config_name(config), gNY[this->isConfigRenderable(config, false)], gNY[this->isConfigRenderable(config, true)]); } SkASSERT(!this->isConfigTexturable(kUnknown_GrPixelConfig)); - for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { + for (size_t i = 1; i < kGrPixelConfigCnt; ++i) { GrPixelConfig config = static_cast(i); r.appendf("%s is uploadable to a texture: %s\n", - kConfigNames[i], + pixel_config_name(config), gNY[this->isConfigTexturable(config)]); } diff --git a/gfx/skia/skia/include/gpu/GrClip.h b/gfx/skia/skia/src/gpu/GrClip.h similarity index 80% rename from gfx/skia/skia/include/gpu/GrClip.h rename to gfx/skia/skia/src/gpu/GrClip.h index 96c6291ef751..c44653baadd6 100644 --- a/gfx/skia/skia/include/gpu/GrClip.h +++ b/gfx/skia/skia/src/gpu/GrClip.h @@ -8,12 +8,13 @@ #ifndef GrClip_DEFINED #define GrClip_DEFINED -#include "SkRect.h" +#include "GrTypes.h" #include "SkRRect.h" +#include "SkRect.h" class GrAppliedClip; class GrContext; -class GrDrawContext; +class GrRenderTargetContext; /** * GrClip is an abstract base class for applying a clip. It constructs a clip mask if necessary, and @@ -27,8 +28,17 @@ public: } virtual void getConservativeBounds(int width, int height, SkIRect* devResult, bool* isIntersectionOfRects = nullptr) const = 0; - virtual bool apply(GrContext*, GrDrawContext*, bool useHWAA, bool hasUserStencilSettings, - GrAppliedClip* out) const = 0; + /** + * This computes a GrAppliedClip from the clip which in turn can be used to build a GrPipeline. + * To determine the appropriate clipping implementation the GrClip subclass must know whether + * the draw will enable HW AA or uses the stencil buffer. On input 'bounds' is a conservative + * bounds of the draw that is to be clipped. After return 'bounds' has been intersected with a + * conservative bounds of the clip. A return value of false indicates that the draw can be + * skipped as it is fully clipped out. + */ + virtual bool apply(GrContext*, GrRenderTargetContext*, bool useHWAA, + bool hasUserStencilSettings, GrAppliedClip* result, + SkRect* bounds) const = 0; virtual ~GrClip() {} @@ -45,7 +55,7 @@ public: * @return true if the clip is equivalent to a single rrect, false otherwise. * */ - virtual bool isRRect(const SkRect& rtBounds, SkRRect* rrect, bool* aa) const = 0; + virtual bool isRRect(const SkRect& rtBounds, SkRRect* rrect, GrAA* aa) const = 0; /** * This is the maximum distance that a draw may extend beyond a clip's boundary and still count @@ -62,8 +72,8 @@ public: * @param innerClipBounds device-space rect contained by the clip (SkRect or SkIRect). * @param queryBounds device-space bounds of the query region. */ - template constexpr static bool IsInsideClip(const TRect& innerClipBounds, - const SkRect& queryBounds) { + template + constexpr static bool IsInsideClip(const TRect& innerClipBounds, const SkRect& queryBounds) { return innerClipBounds.fRight - innerClipBounds.fLeft > kBoundsTolerance && innerClipBounds.fBottom - innerClipBounds.fTop > kBoundsTolerance && innerClipBounds.fLeft < queryBounds.fLeft + kBoundsTolerance && @@ -78,8 +88,8 @@ public: * @param outerClipBounds device-space rect that contains the clip (SkRect or SkIRect). * @param queryBounds device-space bounds of the query region. */ - template constexpr static bool IsOutsideClip(const TRect& outerClipBounds, - const SkRect& queryBounds) { + template + constexpr static bool IsOutsideClip(const TRect& outerClipBounds, const SkRect& queryBounds) { return outerClipBounds.fRight - outerClipBounds.fLeft <= kBoundsTolerance || outerClipBounds.fBottom - outerClipBounds.fTop <= kBoundsTolerance || outerClipBounds.fLeft >= queryBounds.fRight - kBoundsTolerance || @@ -124,12 +134,8 @@ public: */ class GrNoClip final : public GrClip { private: - bool quickContains(const SkRect&) const final { - return true; - } - bool quickContains(const SkRRect&) const final { - return true; - } + bool quickContains(const SkRect&) const final { return true; } + bool quickContains(const SkRRect&) const final { return true; } void getConservativeBounds(int width, int height, SkIRect* devResult, bool* isIntersectionOfRects) const final { devResult->setXYWH(0, 0, width, height); @@ -137,10 +143,11 @@ private: *isIntersectionOfRects = true; } } - bool apply(GrContext*, GrDrawContext*, bool, bool, GrAppliedClip*) const final { + bool apply(GrContext*, GrRenderTargetContext*, bool, bool, GrAppliedClip*, + SkRect*) const final { return true; } - bool isRRect(const SkRect&, SkRRect*, bool*) const override { return false; } + bool isRRect(const SkRect&, SkRRect*, GrAA*) const override { return false; } }; #endif diff --git a/gfx/skia/skia/src/gpu/GrClipStackClip.cpp b/gfx/skia/skia/src/gpu/GrClipStackClip.cpp index b25bcf29dc40..b0109819d770 100644 --- a/gfx/skia/skia/src/gpu/GrClipStackClip.cpp +++ b/gfx/skia/skia/src/gpu/GrClipStackClip.cpp @@ -10,54 +10,47 @@ #include "GrAppliedClip.h" #include "GrContextPriv.h" #include "GrDrawingManager.h" -#include "GrDrawContextPriv.h" +#include "GrRenderTargetContextPriv.h" #include "GrFixedClip.h" #include "GrGpuResourcePriv.h" #include "GrRenderTargetPriv.h" #include "GrStencilAttachment.h" #include "GrSWMaskHelper.h" +#include "GrTextureProxy.h" #include "effects/GrConvexPolyEffect.h" #include "effects/GrRRectEffect.h" #include "effects/GrTextureDomain.h" +#include "SkClipOpPriv.h" typedef SkClipStack::Element Element; typedef GrReducedClip::InitialState InitialState; typedef GrReducedClip::ElementList ElementList; static const int kMaxAnalyticElements = 4; +const char GrClipStackClip::kMaskTestTag[] = "clip_mask"; bool GrClipStackClip::quickContains(const SkRect& rect) const { if (!fStack || fStack->isWideOpen()) { return true; } - return fStack->quickContains(rect.makeOffset(SkIntToScalar(fOrigin.x()), - SkIntToScalar(fOrigin.y()))); + return fStack->quickContains(rect); } bool GrClipStackClip::quickContains(const SkRRect& rrect) const { if (!fStack || fStack->isWideOpen()) { return true; } - return fStack->quickContains(rrect.makeOffset(SkIntToScalar(fOrigin.fX), - SkIntToScalar(fOrigin.fY))); + return fStack->quickContains(rrect); } -bool GrClipStackClip::isRRect(const SkRect& origRTBounds, SkRRect* rr, bool* aa) const { +bool GrClipStackClip::isRRect(const SkRect& origRTBounds, SkRRect* rr, GrAA* aa) const { if (!fStack) { return false; } const SkRect* rtBounds = &origRTBounds; - SkRect tempRTBounds; - bool origin = fOrigin.fX || fOrigin.fY; - if (origin) { - tempRTBounds = origRTBounds; - tempRTBounds.offset(SkIntToScalar(fOrigin.fX), SkIntToScalar(fOrigin.fY)); - rtBounds = &tempRTBounds; - } - if (fStack->isRRect(*rtBounds, rr, aa)) { - if (origin) { - rr->offset(-SkIntToScalar(fOrigin.fX), -SkIntToScalar(fOrigin.fY)); - } + bool isAA; + if (fStack->isRRect(*rtBounds, rr, &isAA)) { + *aa = GrBoolToAA(isAA); return true; } return false; @@ -73,17 +66,18 @@ void GrClipStackClip::getConservativeBounds(int width, int height, SkIRect* devR return; } SkRect devBounds; - fStack->getConservativeBounds(-fOrigin.x(), -fOrigin.y(), width, height, &devBounds, - isIntersectionOfRects); + fStack->getConservativeBounds(0, 0, width, height, &devBounds, isIntersectionOfRects); devBounds.roundOut(devResult); } //////////////////////////////////////////////////////////////////////////////// // set up the draw state to enable the aa clipping mask. -static sk_sp create_fp_for_mask(GrTexture* result, +static sk_sp create_fp_for_mask(GrResourceProvider* resourceProvider, + sk_sp mask, const SkIRect &devBound) { SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); - return GrDeviceSpaceTextureDecalFragmentProcessor::Make(result, domainTexels, + return GrDeviceSpaceTextureDecalFragmentProcessor::Make(resourceProvider, + std::move(mask), domainTexels, {devBound.fLeft, devBound.fTop}); } @@ -92,7 +86,7 @@ static sk_sp create_fp_for_mask(GrTexture* result, // 'prOut' to the non-SW path renderer that will do the job). bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, bool hasUserStencilSettings, - const GrDrawContext* drawContext, + const GrRenderTargetContext* renderTargetContext, const SkMatrix& viewMatrix, const Element* element, GrPathRenderer** prOut, @@ -115,26 +109,25 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, path.toggleInverseFillType(); } - GrPathRendererChain::DrawType type; - - if (needsStencil) { - type = element->isAA() - ? GrPathRendererChain::kStencilAndColorAntiAlias_DrawType - : GrPathRendererChain::kStencilAndColor_DrawType; - } else { - type = element->isAA() - ? GrPathRendererChain::kColorAntiAlias_DrawType - : GrPathRendererChain::kColor_DrawType; - } + GrPathRendererChain::DrawType type = + needsStencil ? GrPathRendererChain::DrawType::kStencilAndColor + : GrPathRendererChain::DrawType::kColor; GrShape shape(path, GrStyle::SimpleFill()); GrPathRenderer::CanDrawPathArgs canDrawArgs; canDrawArgs.fShaderCaps = context->caps()->shaderCaps(); canDrawArgs.fViewMatrix = &viewMatrix; canDrawArgs.fShape = &shape; - canDrawArgs.fAntiAlias = element->isAA(); + if (!element->isAA()) { + canDrawArgs.fAAType = GrAAType::kNone; + } else if (renderTargetContext->isUnifiedMultisampled()) { + canDrawArgs.fAAType = GrAAType::kMSAA; + } else if (renderTargetContext->isStencilBufferMultisampled()){ + canDrawArgs.fAAType = GrAAType::kMixedSamples; + } else { + canDrawArgs.fAAType = GrAAType::kCoverage; + } canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings; - canDrawArgs.fIsStencilBufferMSAA = drawContext->isStencilBufferMultisampled(); // the 'false' parameter disallows use of the SW path renderer GrPathRenderer* pr = @@ -153,7 +146,7 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, */ bool GrClipStackClip::UseSWOnlyPath(GrContext* context, bool hasUserStencilSettings, - const GrDrawContext* drawContext, + const GrRenderTargetContext* renderTargetContext, const GrReducedClip& reducedClip) { // TODO: generalize this function so that when // a clip gets complex enough it can just be done in SW regardless @@ -167,13 +160,13 @@ bool GrClipStackClip::UseSWOnlyPath(GrContext* context, for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) { const Element* element = iter.get(); - SkCanvas::ClipOp op = element->getOp(); + SkClipOp op = element->getOp(); bool invert = element->isInverseFilled(); bool needsStencil = invert || - SkCanvas::kIntersect_Op == op || SkCanvas::kReverseDifference_Op == op; + kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op; if (PathNeedsSWRenderer(context, hasUserStencilSettings, - drawContext, translate, element, nullptr, needsStencil)) { + renderTargetContext, translate, element, nullptr, needsStencil)) { return true; } } @@ -182,29 +175,26 @@ bool GrClipStackClip::UseSWOnlyPath(GrContext* context, static bool get_analytic_clip_processor(const ElementList& elements, bool abortIfAA, - const SkVector& clipToRTOffset, - const SkRect& drawBounds, + const SkRect& drawDevBounds, sk_sp* resultFP) { - SkRect boundsInClipSpace; - boundsInClipSpace = drawBounds.makeOffset(-clipToRTOffset.fX, -clipToRTOffset.fY); SkASSERT(elements.count() <= kMaxAnalyticElements); SkSTArray> fps; ElementList::Iter iter(elements); while (iter.get()) { - SkCanvas::ClipOp op = iter.get()->getOp(); + SkClipOp op = iter.get()->getOp(); bool invert; bool skip = false; switch (op) { - case SkRegion::kReplace_Op: + case kReplace_SkClipOp: SkASSERT(iter.get() == elements.head()); // Fallthrough, handled same as intersect. - case SkRegion::kIntersect_Op: + case kIntersect_SkClipOp: invert = false; - if (iter.get()->contains(boundsInClipSpace)) { + if (iter.get()->contains(drawDevBounds)) { skip = true; } break; - case SkRegion::kDifference_Op: + case kDifference_SkClipOp: invert = true; // We don't currently have a cheap test for whether a rect is fully outside an // element's primitive, so don't attempt to set skip. @@ -227,19 +217,14 @@ static bool get_analytic_clip_processor(const ElementList& elements, switch (iter.get()->getType()) { case SkClipStack::Element::kPath_Type: - fps.emplace_back(GrConvexPolyEffect::Make(edgeType, iter.get()->getPath(), - &clipToRTOffset)); + fps.emplace_back(GrConvexPolyEffect::Make(edgeType, iter.get()->getPath())); break; case SkClipStack::Element::kRRect_Type: { - SkRRect rrect = iter.get()->getRRect(); - rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); - fps.emplace_back(GrRRectEffect::Make(edgeType, rrect)); + fps.emplace_back(GrRRectEffect::Make(edgeType, iter.get()->getRRect())); break; } case SkClipStack::Element::kRect_Type: { - SkRect rect = iter.get()->getRect(); - rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); - fps.emplace_back(GrConvexPolyEffect::Make(edgeType, rect)); + fps.emplace_back(GrConvexPolyEffect::Make(edgeType, iter.get()->getRect())); break; } default: @@ -262,36 +247,27 @@ static bool get_analytic_clip_processor(const ElementList& elements, //////////////////////////////////////////////////////////////////////////////// // sort out what kind of clip mask needs to be created: alpha, stencil, // scissor, or entirely software -bool GrClipStackClip::apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA, - bool hasUserStencilSettings, GrAppliedClip* out) const { +bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTargetContext, + bool useHWAA, bool hasUserStencilSettings, GrAppliedClip* out, + SkRect* bounds) const { + SkRect devBounds = SkRect::MakeIWH(renderTargetContext->width(), renderTargetContext->height()); + if (!devBounds.intersect(*bounds)) { + return false; + } + if (!fStack || fStack->isWideOpen()) { return true; } - SkRect devBounds = SkRect::MakeIWH(drawContext->width(), drawContext->height()); - if (!devBounds.intersect(out->clippedDrawBounds()) || - GrClip::GetPixelIBounds(devBounds).isEmpty()) { - return false; - } + const GrReducedClip reducedClip(*fStack, devBounds, + renderTargetContext->priv().maxWindowRectangles()); - GrRenderTarget* rt = drawContext->accessRenderTarget(); - - const SkScalar clipX = SkIntToScalar(fOrigin.x()), - clipY = SkIntToScalar(fOrigin.y()); - - SkRect clipSpaceDevBounds = devBounds.makeOffset(clipX, clipY); - const GrReducedClip reducedClip(*fStack, clipSpaceDevBounds, - rt->renderTargetPriv().maxWindowRectangles()); - - if (reducedClip.hasIBounds() && - !GrClip::IsInsideClip(reducedClip.ibounds(), clipSpaceDevBounds)) { - SkIRect scissorSpaceIBounds(reducedClip.ibounds()); - scissorSpaceIBounds.offset(-fOrigin); - out->addScissor(scissorSpaceIBounds); + if (reducedClip.hasIBounds() && !GrClip::IsInsideClip(reducedClip.ibounds(), devBounds)) { + out->addScissor(reducedClip.ibounds(), bounds); } if (!reducedClip.windowRectangles().empty()) { - out->addWindowRectangles(reducedClip.windowRectangles(), fOrigin, + out->addWindowRectangles(reducedClip.windowRectangles(), GrWindowRectsState::Mode::kExclusive); } @@ -299,7 +275,13 @@ bool GrClipStackClip::apply(GrContext* context, GrDrawContext* drawContext, bool return InitialState::kAllIn == reducedClip.initialState(); } +#ifdef SK_DEBUG SkASSERT(reducedClip.hasIBounds()); + SkIRect rtIBounds = SkIRect::MakeWH(renderTargetContext->width(), + renderTargetContext->height()); + const SkIRect& clipIBounds = reducedClip.ibounds(); + SkASSERT(rtIBounds.contains(clipIBounds)); // Mask shouldn't be larger than the RT. +#endif // An element count of 4 was chosen because of the common pattern in Blink of: // isect RR @@ -312,8 +294,8 @@ bool GrClipStackClip::apply(GrContext* context, GrDrawContext* drawContext, bool if (reducedClip.elements().count() <= kMaxAnalyticElements) { // When there are multiple samples we want to do per-sample clipping, not compute a // fractional pixel coverage. - bool disallowAnalyticAA = drawContext->isStencilBufferMultisampled(); - if (disallowAnalyticAA && !drawContext->numColorSamples()) { + bool disallowAnalyticAA = renderTargetContext->isStencilBufferMultisampled(); + if (disallowAnalyticAA && !renderTargetContext->numColorSamples()) { // With a single color sample, any coverage info is lost from color once it hits the // color buffer anyway, so we may as well use coverage AA if nothing else in the pipe // is multisampled. @@ -321,42 +303,41 @@ bool GrClipStackClip::apply(GrContext* context, GrDrawContext* drawContext, bool } sk_sp clipFP; if (reducedClip.requiresAA() && - get_analytic_clip_processor(reducedClip.elements(), disallowAnalyticAA, - {-clipX, -clipY}, devBounds, &clipFP)) { + get_analytic_clip_processor(reducedClip.elements(), disallowAnalyticAA, devBounds, + &clipFP)) { out->addCoverageFP(std::move(clipFP)); return true; } } // If the stencil buffer is multisampled we can use it to do everything. - if (!drawContext->isStencilBufferMultisampled() && reducedClip.requiresAA()) { - sk_sp result; - if (UseSWOnlyPath(context, hasUserStencilSettings, drawContext, reducedClip)) { + if (!renderTargetContext->isStencilBufferMultisampled() && reducedClip.requiresAA()) { + sk_sp result; + if (UseSWOnlyPath(context, hasUserStencilSettings, renderTargetContext, reducedClip)) { // The clip geometry is complex enough that it will be more efficient to create it // entirely in software - result = CreateSoftwareClipMask(context->textureProvider(), reducedClip); + result = this->createSoftwareClipMask(context, reducedClip); } else { - result = CreateAlphaClipMask(context, reducedClip); - // If createAlphaClipMask fails it means UseSWOnlyPath has a bug - SkASSERT(result); + result = this->createAlphaClipMask(context, reducedClip); } if (result) { // The mask's top left coord should be pinned to the rounded-out top left corner of - // clipSpace bounds. We determine the mask's position WRT to the render target here. - SkIRect rtSpaceMaskBounds = reducedClip.ibounds(); - rtSpaceMaskBounds.offset(-fOrigin); - out->addCoverageFP(create_fp_for_mask(result.get(), rtSpaceMaskBounds)); + // the clip's device space bounds. + out->addCoverageFP(create_fp_for_mask(context->resourceProvider(), std::move(result), + reducedClip.ibounds())); return true; } // if alpha clip mask creation fails fall through to the non-AA code paths } + GrRenderTarget* rt = renderTargetContext->accessRenderTarget(); + if (!rt) { + return true; + } + // use the stencil clip if we can't represent the clip as a rectangle. - // TODO: these need to be swapped over to using a StencilAttachmentProxy - GrStencilAttachment* stencilAttachment = - context->resourceProvider()->attachStencilAttachment(rt); - if (nullptr == stencilAttachment) { + if (!context->resourceProvider()->attachStencilAttachment(rt)) { SkDebugf("WARNING: failed to attach stencil buffer for clip mask. Clip will be ignored.\n"); return true; } @@ -364,11 +345,10 @@ bool GrClipStackClip::apply(GrContext* context, GrDrawContext* drawContext, bool // This relies on the property that a reduced sub-rect of the last clip will contain all the // relevant window rectangles that were in the last clip. This subtle requirement will go away // after clipping is overhauled. - if (stencilAttachment->mustRenderClip(reducedClip.elementsGenID(), reducedClip.ibounds(), - fOrigin)) { - reducedClip.drawStencilClipMask(context, drawContext, fOrigin); - stencilAttachment->setLastClip(reducedClip.elementsGenID(), reducedClip.ibounds(), - fOrigin); + if (renderTargetContext->priv().mustRenderClip(reducedClip.elementsGenID(), + reducedClip.ibounds())) { + reducedClip.drawStencilClipMask(context, renderTargetContext); + renderTargetContext->priv().setLastClip(reducedClip.elementsGenID(), reducedClip.ibounds()); } out->addStencilClip(); return true; @@ -377,111 +357,133 @@ bool GrClipStackClip::apply(GrContext* context, GrDrawContext* drawContext, bool //////////////////////////////////////////////////////////////////////////////// // Create a 8-bit clip mask in alpha -static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey* key) { +static void create_clip_mask_key(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey* key) { static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey::Builder builder(key, kDomain, 3); + GrUniqueKey::Builder builder(key, kDomain, 3, GrClipStackClip::kMaskTestTag); builder[0] = clipGenID; - builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); - builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); + // SkToS16 because image filters outset layers to a size indicated by the filter, which can + // sometimes result in negative coordinates from device space. + builder[1] = SkToS16(bounds.fLeft) | (SkToS16(bounds.fRight) << 16); + builder[2] = SkToS16(bounds.fTop) | (SkToS16(bounds.fBottom) << 16); } -sk_sp GrClipStackClip::CreateAlphaClipMask(GrContext* context, - const GrReducedClip& reducedClip) { +static void add_invalidate_on_pop_message(const SkClipStack& stack, int32_t clipGenID, + const GrUniqueKey& clipMaskKey) { + SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); + while (const Element* element = iter.prev()) { + if (element->getGenID() == clipGenID) { + std::unique_ptr msg( + new GrUniqueKeyInvalidatedMessage(clipMaskKey)); + element->addResourceInvalidationMessage(std::move(msg)); + return; + } + } + SkDEBUGFAIL("Gen ID was not found in stack."); +} + +sk_sp GrClipStackClip::createAlphaClipMask(GrContext* context, + const GrReducedClip& reducedClip) const { GrResourceProvider* resourceProvider = context->resourceProvider(); GrUniqueKey key; - GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key); - if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) { - return sk_sp(texture); + create_clip_mask_key(reducedClip.elementsGenID(), reducedClip.ibounds(), &key); + + sk_sp proxy(resourceProvider->findProxyByUniqueKey(key)); + if (proxy) { + return proxy; } - sk_sp dc(context->makeDrawContextWithFallback(SkBackingFit::kApprox, - reducedClip.width(), - reducedClip.height(), - kAlpha_8_GrPixelConfig, - nullptr)); - if (!dc) { + sk_sp rtc(context->makeRenderTargetContextWithFallback( + SkBackingFit::kApprox, + reducedClip.width(), + reducedClip.height(), + kAlpha_8_GrPixelConfig, + nullptr)); + if (!rtc) { return nullptr; } - if (!reducedClip.drawAlphaClipMask(dc.get())) { + if (!reducedClip.drawAlphaClipMask(rtc.get())) { return nullptr; } - sk_sp texture(dc->asTexture()); - SkASSERT(texture); - texture->resourcePriv().setUniqueKey(key); - return texture; + sk_sp result(rtc->asTextureProxyRef()); + if (!result) { + return nullptr; + } + + resourceProvider->assignUniqueKeyToProxy(key, result.get()); + // MDB TODO (caching): this has to play nice with the GrSurfaceProxy's caching + add_invalidate_on_pop_message(*fStack, reducedClip.elementsGenID(), key); + + return result; } -sk_sp GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texProvider, - const GrReducedClip& reducedClip) { +sk_sp GrClipStackClip::createSoftwareClipMask( + GrContext* context, + const GrReducedClip& reducedClip) const { GrUniqueKey key; - GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key); - if (GrTexture* texture = texProvider->findAndRefTextureByUniqueKey(key)) { - return sk_sp(texture); + create_clip_mask_key(reducedClip.elementsGenID(), reducedClip.ibounds(), &key); + + sk_sp proxy(context->resourceProvider()->findProxyByUniqueKey(key)); + if (proxy) { + return proxy; } - // The mask texture may be larger than necessary. We round out the clip space bounds and pin - // the top left corner of the resulting rect to the top left of the texture. + // The mask texture may be larger than necessary. We round out the clip bounds and pin the top + // left corner of the resulting rect to the top left of the texture. SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.height()); - GrSWMaskHelper helper(texProvider); + GrSWMaskHelper helper; // Set the matrix so that rendered clip elements are transformed to mask space from clip // space. SkMatrix translate; translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-reducedClip.top())); - helper.init(maskSpaceIBounds, &translate); + if (!helper.init(maskSpaceIBounds, &translate)) { + return nullptr; + } helper.clear(InitialState::kAllIn == reducedClip.initialState() ? 0xFF : 0x00); for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) { const Element* element = iter.get(); - SkCanvas::ClipOp op = element->getOp(); + SkClipOp op = element->getOp(); + GrAA aa = GrBoolToAA(element->isAA()); - if (SkCanvas::kIntersect_Op == op || SkCanvas::kReverseDifference_Op == op) { + if (kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op) { // Intersect and reverse difference require modifying pixels outside of the geometry // that is being "drawn". In both cases we erase all the pixels outside of the geometry // but leave the pixels inside the geometry alone. For reverse difference we invert all // the pixels before clearing the ones outside the geometry. - if (SkCanvas::kReverseDifference_Op == op) { + if (kReverseDifference_SkClipOp == op) { SkRect temp = SkRect::Make(reducedClip.ibounds()); // invert the entire scene - helper.drawRect(temp, SkRegion::kXOR_Op, false, 0xFF); + helper.drawRect(temp, SkRegion::kXOR_Op, GrAA::kNo, 0xFF); } SkPath clipPath; element->asPath(&clipPath); clipPath.toggleInverseFillType(); GrShape shape(clipPath, GrStyle::SimpleFill()); - helper.drawShape(shape, SkRegion::kReplace_Op, element->isAA(), 0x00); + helper.drawShape(shape, SkRegion::kReplace_Op, aa, 0x00); continue; } // The other ops (union, xor, diff) only affect pixels inside // the geometry so they can just be drawn normally if (Element::kRect_Type == element->getType()) { - helper.drawRect(element->getRect(), (SkRegion::Op)op, element->isAA(), 0xFF); + helper.drawRect(element->getRect(), (SkRegion::Op)op, aa, 0xFF); } else { SkPath path; element->asPath(&path); GrShape shape(path, GrStyle::SimpleFill()); - helper.drawShape(shape, (SkRegion::Op)op, element->isAA(), 0xFF); + helper.drawShape(shape, (SkRegion::Op)op, aa, 0xFF); } } - // Allocate clip mask texture - GrSurfaceDesc desc; - desc.fWidth = reducedClip.width(); - desc.fHeight = reducedClip.height(); - desc.fConfig = kAlpha_8_GrPixelConfig; - - sk_sp result(texProvider->createApproxTexture(desc)); - if (!result) { - return nullptr; - } - result->resourcePriv().setUniqueKey(key); - - helper.toTexture(result.get()); + sk_sp result(helper.toTextureProxy(context, SkBackingFit::kApprox)); + context->resourceProvider()->assignUniqueKeyToProxy(key, result.get()); + // MDB TODO (caching): this has to play nice with the GrSurfaceProxy's caching + add_invalidate_on_pop_message(*fStack, reducedClip.elementsGenID(), key); return result; } diff --git a/gfx/skia/skia/src/gpu/GrClipStackClip.h b/gfx/skia/skia/src/gpu/GrClipStackClip.h index 075d1d857d9d..8058c3b8a490 100644 --- a/gfx/skia/skia/src/gpu/GrClipStackClip.h +++ b/gfx/skia/skia/src/gpu/GrClipStackClip.h @@ -12,9 +12,7 @@ #include "SkClipStack.h" class GrPathRenderer; -class GrTexture; -class GrTextureProvider; -class GrUniqueKey; +class GrTextureProxy; /** * GrClipStackClip can apply a generic SkClipStack to the draw state. It may need to generate an @@ -22,28 +20,26 @@ class GrUniqueKey; */ class GrClipStackClip final : public GrClip { public: - GrClipStackClip(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) { - this->reset(stack, origin); - } + GrClipStackClip(const SkClipStack* stack = nullptr) { this->reset(stack); } - void reset(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) { - fOrigin = origin ? *origin : SkIPoint::Make(0, 0); - fStack.reset(SkSafeRef(stack)); - } + void reset(const SkClipStack* stack) { fStack = stack; } bool quickContains(const SkRect&) const final; bool quickContains(const SkRRect&) const final; void getConservativeBounds(int width, int height, SkIRect* devResult, bool* isIntersectionOfRects) const final; - bool apply(GrContext*, GrDrawContext*, bool useHWAA, bool hasUserStencilSettings, - GrAppliedClip* out) const final; + bool apply(GrContext*, GrRenderTargetContext*, bool useHWAA, bool hasUserStencilSettings, + GrAppliedClip* out, SkRect* bounds) const final; - bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const override; + bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA* aa) const override; + + sk_sp testingOnly_createClipMask(GrContext*) const; + static const char kMaskTestTag[]; private: static bool PathNeedsSWRenderer(GrContext* context, bool hasUserStencilSettings, - const GrDrawContext*, + const GrRenderTargetContext*, const SkMatrix& viewMatrix, const SkClipStack::Element* element, GrPathRenderer** prOut, @@ -51,21 +47,17 @@ private: // Creates an alpha mask of the clip. The mask is a rasterization of elements through the // rect specified by clipSpaceIBounds. - static sk_sp CreateAlphaClipMask(GrContext*, const GrReducedClip&); + sk_sp createAlphaClipMask(GrContext*, const GrReducedClip&) const; // Similar to createAlphaClipMask but it rasterizes in SW and uploads to the result texture. - static sk_sp CreateSoftwareClipMask(GrTextureProvider*, const GrReducedClip&); + sk_sp createSoftwareClipMask(GrContext*, const GrReducedClip&) const; - static bool UseSWOnlyPath(GrContext*, - bool hasUserStencilSettings, - const GrDrawContext*, - const GrReducedClip&); + static bool UseSWOnlyPath(GrContext*, + bool hasUserStencilSettings, + const GrRenderTargetContext*, + const GrReducedClip&); - static GrTexture* CreateCachedMask(int width, int height, const GrUniqueKey& key, - bool renderTarget); - - SkIPoint fOrigin; - SkAutoTUnref fStack; + const SkClipStack* fStack; }; #endif // GrClipStackClip_DEFINED diff --git a/gfx/skia/skia/src/gpu/GrColorSpaceXform.cpp b/gfx/skia/skia/src/gpu/GrColorSpaceXform.cpp index d2270fafdd4a..58f160cd18b8 100644 --- a/gfx/skia/skia/src/gpu/GrColorSpaceXform.cpp +++ b/gfx/skia/skia/src/gpu/GrColorSpaceXform.cpp @@ -9,36 +9,56 @@ #include "SkColorSpace.h" #include "SkColorSpace_Base.h" #include "SkMatrix44.h" +#include "SkSpinlock.h" -static inline bool sk_float_almost_equals(float x, float y, float tol) { - return sk_float_abs(x - y) <= tol; -} +class GrColorSpaceXformCache { +public: + using NewValueFn = std::function(void)>; -static inline bool matrix_is_almost_identity(const SkMatrix44& m, - SkMScalar tol = SK_MScalar1 / (1 << 12)) { - return - sk_float_almost_equals(m.getFloat(0, 0), 1.0f, tol) && - sk_float_almost_equals(m.getFloat(0, 1), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(0, 2), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(0, 3), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(1, 0), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(1, 1), 1.0f, tol) && - sk_float_almost_equals(m.getFloat(1, 2), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(1, 3), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(2, 0), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(2, 1), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(2, 2), 1.0f, tol) && - sk_float_almost_equals(m.getFloat(2, 3), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(3, 0), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(3, 1), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(3, 2), 0.0f, tol) && - sk_float_almost_equals(m.getFloat(3, 3), 1.0f, tol); -} + GrColorSpaceXformCache() : fSequence(0) {} -GrColorSpaceXform::GrColorSpaceXform(const SkMatrix44& srcToDst) + sk_sp findOrAdd(uint64_t key, NewValueFn newValue) { + int oldest = 0; + for (int i = 0; i < kEntryCount; ++i) { + if (fEntries[i].fKey == key) { + fEntries[i].fLastUse = fSequence++; + return fEntries[i].fXform; + } + if (fEntries[i].fLastUse < fEntries[oldest].fLastUse) { + oldest = i; + } + } + fEntries[oldest].fKey = key; + fEntries[oldest].fXform = newValue(); + fEntries[oldest].fLastUse = fSequence++; + return fEntries[oldest].fXform; + } + +private: + enum { kEntryCount = 32 }; + + struct Entry { + // The default Entry is "valid". Any 64-bit key that is the same 32-bit value repeated + // implies no xform is necessary, so nullptr should be returned. This particular case should + // never happen, but by initializing all entries with this data, we can avoid special cases + // for the array not yet being full. + Entry() : fKey(0), fXform(nullptr), fLastUse(0) {} + + uint64_t fKey; + sk_sp fXform; + uint64_t fLastUse; + }; + + Entry fEntries[kEntryCount]; + uint64_t fSequence; +}; + +GrColorSpaceXform::GrColorSpaceXform(const SkMatrix44& srcToDst) : fSrcToDst(srcToDst) {} -sk_sp GrColorSpaceXform::Make(SkColorSpace* src, SkColorSpace* dst) { +static SkSpinlock gColorSpaceXformCacheSpinlock; + +sk_sp GrColorSpaceXform::Make(const SkColorSpace* src, const SkColorSpace* dst) { if (!src || !dst) { // Invalid return nullptr; @@ -49,14 +69,41 @@ sk_sp GrColorSpaceXform::Make(SkColorSpace* src, SkColorSpace return nullptr; } - SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); - srcToDst.setConcat(as_CSB(dst)->fromXYZD50(), as_CSB(src)->toXYZD50()); - - if (matrix_is_almost_identity(srcToDst)) { + const SkMatrix44* toXYZD50 = as_CSB(src)->toXYZD50(); + const SkMatrix44* fromXYZD50 = as_CSB(dst)->fromXYZD50(); + if (!toXYZD50 || !fromXYZD50) { + // unsupported colour spaces -- cannot specify gamut as a matrix return nullptr; } - return sk_make_sp(srcToDst); + uint32_t srcHash = as_CSB(src)->toXYZD50Hash(); + uint32_t dstHash = as_CSB(dst)->toXYZD50Hash(); + if (srcHash == dstHash) { + // Identical gamut - no conversion needed in this case + SkASSERT(*toXYZD50 == *as_CSB(dst)->toXYZD50() && "Hash collision"); + return nullptr; + } + + auto deferredResult = [fromXYZD50, toXYZD50]() { + SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); + srcToDst.setConcat(*fromXYZD50, *toXYZD50); + return sk_make_sp(srcToDst); + }; + + if (gColorSpaceXformCacheSpinlock.tryAcquire()) { + static GrColorSpaceXformCache* gCache; + if (nullptr == gCache) { + gCache = new GrColorSpaceXformCache(); + } + + uint64_t key = static_cast(srcHash) << 32 | static_cast(dstHash); + sk_sp xform = gCache->findOrAdd(key, deferredResult); + gColorSpaceXformCacheSpinlock.release(); + return xform; + } else { + // Rather than wait for the spin lock, just bypass the cache + return deferredResult(); + } } bool GrColorSpaceXform::Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b) { @@ -74,5 +121,9 @@ bool GrColorSpaceXform::Equals(const GrColorSpaceXform* a, const GrColorSpaceXfo GrColor4f GrColorSpaceXform::apply(const GrColor4f& srcColor) { GrColor4f result; fSrcToDst.mapScalars(srcColor.fRGBA, result.fRGBA); + // We always operate on unpremul colors, so clamp to [0,1]. + for (int i = 0; i < 4; ++i) { + result.fRGBA[i] = SkTPin(result.fRGBA[i], 0.0f, 1.0f); + } return result; } diff --git a/gfx/skia/skia/src/gpu/GrContext.cpp b/gfx/skia/skia/src/gpu/GrContext.cpp index 176d5da59b57..31f1787d5623 100644 --- a/gfx/skia/skia/src/gpu/GrContext.cpp +++ b/gfx/skia/skia/src/gpu/GrContext.cpp @@ -6,30 +6,40 @@ */ #include "GrContext.h" -#include "GrContextPriv.h" +#include "GrClip.h" #include "GrContextOptions.h" +#include "GrContextPriv.h" #include "GrDrawingManager.h" -#include "GrDrawContext.h" +#include "GrRenderTargetContext.h" +#include "GrRenderTargetProxy.h" #include "GrResourceCache.h" #include "GrResourceProvider.h" +#include "GrSemaphore.h" #include "GrSoftwarePathRenderer.h" +#include "GrSurfaceContext.h" #include "GrSurfacePriv.h" - -#include "SkConfig8888.h" -#include "SkGrPriv.h" - -#include "batches/GrCopySurfaceBatch.h" +#include "GrSurfaceProxyPriv.h" +#include "GrTextureContext.h" +#include "SkConvertPixels.h" +#include "SkGr.h" +#include "SkUnPreMultiplyPriv.h" #include "effects/GrConfigConversionEffect.h" -#include "effects/GrGammaEffect.h" #include "text/GrTextBlobCache.h" +#define ASSERT_OWNED_PROXY(P) \ +SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this) +#define ASSERT_OWNED_PROXY_PRIV(P) \ +SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == fContext) + #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) #define ASSERT_SINGLE_OWNER \ SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);) #define ASSERT_SINGLE_OWNER_PRIV \ SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);) #define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; } +#define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; } #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; } +#define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; } #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; } //////////////////////////////////////////////////////////////////////////////// @@ -65,7 +75,7 @@ GrContext::GrContext() : fUniqueID(next_id()) { fCaps = nullptr; fResourceCache = nullptr; fResourceProvider = nullptr; - fBatchFontCache = nullptr; + fAtlasGlyphCache = nullptr; } bool GrContext::init(GrBackend backend, GrBackendContext backendContext, @@ -88,22 +98,19 @@ void GrContext::initCommon(const GrContextOptions& options) { fResourceCache = new GrResourceCache(fCaps); fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner); + fDisableGpuYUVConversion = options.fDisableGpuYUVConversion; fDidTestPMConversions = false; - GrDrawTarget::Options dtOptions; - dtOptions.fClipBatchToBounds = options.fClipBatchToBounds; - dtOptions.fDrawBatchBounds = options.fDrawBatchBounds; - dtOptions.fMaxBatchLookback = options.fMaxBatchLookback; - dtOptions.fMaxBatchLookahead = options.fMaxBatchLookahead; + GrRenderTargetOpList::Options rtOpListOptions; + rtOpListOptions.fMaxOpCombineLookback = options.fMaxOpCombineLookback; + rtOpListOptions.fMaxOpCombineLookahead = options.fMaxOpCombineLookahead; GrPathRendererChain::Options prcOptions; - prcOptions.fDisableDistanceFieldRenderer = options.fDisableDistanceFieldPaths; prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching; - prcOptions.fDisableAllPathRenderers = options.fForceSWPathMasks; - fDrawingManager.reset(new GrDrawingManager(this, dtOptions, prcOptions, options.fImmediateMode, - &fSingleOwner)); + prcOptions.fGpuPathRenderers = options.fGpuPathRenderers; + fDrawingManager.reset(new GrDrawingManager(this, rtOpListOptions, prcOptions, + options.fImmediateMode, &fSingleOwner)); - // GrBatchFontCache will eventually replace GrFontCache - fBatchFontCache = new GrBatchFontCache(this); + fAtlasGlyphCache = new GrAtlasGlyphCache(this); fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this)); } @@ -126,17 +133,17 @@ GrContext::~GrContext() { delete fResourceProvider; delete fResourceCache; - delete fBatchFontCache; + delete fAtlasGlyphCache; fGpu->unref(); fCaps->unref(); } -GrContextThreadSafeProxy* GrContext::threadSafeProxy() { +sk_sp GrContext::threadSafeProxy() { if (!fThreadSafeProxy) { - fThreadSafeProxy.reset(new GrContextThreadSafeProxy(fCaps, this->uniqueID())); + fThreadSafeProxy.reset(new GrContextThreadSafeProxy(sk_ref_sp(fCaps), this->uniqueID())); } - return SkRef(fThreadSafeProxy.get()); + return fThreadSafeProxy; } void GrContext::abandonContext() { @@ -154,7 +161,7 @@ void GrContext::abandonContext() { fGpu->disconnect(GrGpu::DisconnectType::kAbandon); - fBatchFontCache->freeAll(); + fAtlasGlyphCache->freeAll(); fTextBlobCache->freeAll(); } @@ -172,7 +179,7 @@ void GrContext::releaseResourcesAndAbandonContext() { fGpu->disconnect(GrGpu::DisconnectType::kCleanup); - fBatchFontCache->freeAll(); + fAtlasGlyphCache->freeAll(); fTextBlobCache->freeAll(); } @@ -186,13 +193,18 @@ void GrContext::freeGpuResources() { this->flush(); - fBatchFontCache->freeAll(); + fAtlasGlyphCache->freeAll(); fDrawingManager->freeGpuResources(); fResourceCache->purgeAllUnlocked(); } +void GrContext::purgeResourcesNotUsedInMs(std::chrono::milliseconds ms) { + ASSERT_SINGLE_OWNER + fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - ms); +} + void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const { ASSERT_SINGLE_OWNER @@ -208,9 +220,10 @@ void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) void GrContext::TextBlobCacheOverBudgetCB(void* data) { SkASSERT(data); - // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on GrDrawContext - // to perform a necessary flush. The solution is to move drawText calls to below the GrContext - // level, but this is not trivial because they call drawPath on SkGpuDevice. + // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on + // GrRenderTargetContext to perform a necessary flush. The solution is to move drawText calls + // to below the GrContext level, but this is not trivial because they call drawPath on + // SkGpuDevice. GrContext* context = reinterpret_cast(data); context->flush(); } @@ -220,39 +233,59 @@ void GrContext::TextBlobCacheOverBudgetCB(void* data) { void GrContext::flush() { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED - fDrawingManager->flush(); + + fDrawingManager->flush(nullptr); +} + +void GrContextPriv::flush(GrSurfaceProxy* proxy) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_IF_ABANDONED_PRIV + ASSERT_OWNED_PROXY_PRIV(proxy); + + fContext->fDrawingManager->flush(proxy); } bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes, const void* inPixels, size_t outRowBytes, void* outPixels) { - SkSrcPixelInfo srcPI; - if (!GrPixelConfigToColorType(srcConfig, &srcPI.fColorType)) { + SkColorType colorType; + if (!GrPixelConfigToColorType(srcConfig, &colorType) || + 4 != SkColorTypeBytesPerPixel(colorType)) + { return false; } - srcPI.fAlphaType = kUnpremul_SkAlphaType; - srcPI.fPixels = inPixels; - srcPI.fRowBytes = inRowBytes; - SkDstPixelInfo dstPI; - dstPI.fColorType = srcPI.fColorType; - dstPI.fAlphaType = kPremul_SkAlphaType; - dstPI.fPixels = outPixels; - dstPI.fRowBytes = outRowBytes; + for (int y = 0; y < height; y++) { + SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width); + outPixels = SkTAddOffset(outPixels, outRowBytes); + inPixels = SkTAddOffset(inPixels, inRowBytes); + } - return srcPI.convertPixelsTo(&dstPI, width, height); + return true; } -bool GrContext::writeSurfacePixels(GrSurface* surface, - int left, int top, int width, int height, - GrPixelConfig srcConfig, const void* buffer, size_t rowBytes, - uint32_t pixelOpsFlags) { - ASSERT_SINGLE_OWNER - RETURN_FALSE_IF_ABANDONED - ASSERT_OWNED_RESOURCE(surface); - SkASSERT(surface); - GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::writeSurfacePixels"); +static bool valid_unpremul_config(GrPixelConfig config) { + return GrPixelConfigIs8888Unorm(config) || kRGBA_half_GrPixelConfig == config; +} - this->testPMConversionsIfNecessary(pixelOpsFlags); +bool GrContextPriv::writeSurfacePixels(GrSurfaceProxy* dstProxy, SkColorSpace* dstColorSpace, + int left, int top, int width, int height, + GrPixelConfig srcConfig, SkColorSpace* srcColorSpace, + const void* buffer, size_t rowBytes, + uint32_t pixelOpsFlags) { + // TODO: Color space conversion + + ASSERT_SINGLE_OWNER_PRIV + RETURN_FALSE_IF_ABANDONED_PRIV + ASSERT_OWNED_PROXY_PRIV(dstProxy); + SkASSERT(dstProxy); + GR_AUDIT_TRAIL_AUTO_FRAME(&fContext->fAuditTrail, "GrContextPriv::writeSurfacePixels"); + + GrSurface* surface = dstProxy->instantiate(fContext->resourceProvider()); + if (!surface) { + return false; + } + + fContext->testPMConversionsIfNecessary(pixelOpsFlags); // Trim the params here so that if we wind up making a temporary surface it can be as small as // necessary and because GrGpu::getWritePixelsInfo requires it. @@ -262,70 +295,72 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, return false; } - bool applyPremulToSrc = false; - if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { - if (!GrPixelConfigIs8888(srcConfig)) { - return false; - } - applyPremulToSrc = true; + bool applyPremulToSrc = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags); + if (applyPremulToSrc && !valid_unpremul_config(srcConfig)) { + return false; + } + // We don't allow conversion between integer configs and float/fixed configs. + if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(srcConfig)) { + return false; } GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference; // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when // we've already determined that there isn't a roundtrip preserving conversion processor pair. - if (applyPremulToSrc && !this->didFailPMUPMConversionTest()) { + if (applyPremulToSrc && fContext->validPMUPMConversionExists(srcConfig)) { drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference; } GrGpu::WritePixelTempDrawInfo tempDrawInfo; - if (!fGpu->getWritePixelsInfo(surface, width, height, srcConfig, &drawPreference, - &tempDrawInfo)) { + if (!fContext->fGpu->getWritePixelsInfo(surface, width, height, srcConfig, + &drawPreference, &tempDrawInfo)) { return false; } if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && surface->surfacePriv().hasPendingIO()) { - this->flush(); + this->flush(nullptr); // MDB TODO: tighten this } - SkAutoTUnref tempTexture; + sk_sp tempProxy; if (GrGpu::kNoDraw_DrawPreference != drawPreference) { - tempTexture.reset( - this->textureProvider()->createApproxTexture(tempDrawInfo.fTempSurfaceDesc)); - if (!tempTexture && GrGpu::kRequireDraw_DrawPreference == drawPreference) { + tempProxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(), + tempDrawInfo.fTempSurfaceDesc, + SkBackingFit::kApprox, + SkBudgeted::kYes); + if (!tempProxy && GrGpu::kRequireDraw_DrawPreference == drawPreference) { return false; } } // temp buffer for doing sw premul conversion, if needed. SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); - if (tempTexture) { + if (tempProxy) { + sk_sp texFP = GrSimpleTextureEffect::Make( + fContext->resourceProvider(), tempProxy, nullptr, SkMatrix::I()); sk_sp fp; - SkMatrix textureMatrix; - textureMatrix.setIDiv(tempTexture->width(), tempTexture->height()); if (applyPremulToSrc) { - fp = this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwizzle, textureMatrix); - // If premultiplying was the only reason for the draw, fall back to a straight write. - if (!fp) { - if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) { - tempTexture.reset(nullptr); - } - } else { + fp = fContext->createUPMToPMEffect(texFP, tempProxy->config()); + if (fp) { + // We no longer need to do this on CPU before the upload. applyPremulToSrc = false; + } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) { + // We only wanted to do the draw to perform the premul so don't bother. + tempProxy.reset(nullptr); } } - if (tempTexture) { + if (tempProxy) { if (!fp) { - fp = GrConfigConversionEffect::Make(tempTexture, tempDrawInfo.fSwizzle, - GrConfigConversionEffect::kNone_PMConversion, - textureMatrix); - if (!fp) { - return false; - } + fp = std::move(texFP); } - GrRenderTarget* renderTarget = surface->asRenderTarget(); - SkASSERT(renderTarget); - if (tempTexture->surfacePriv().hasPendingIO()) { - this->flush(); + fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle); + SkASSERT(fp); + + if (tempProxy->priv().hasPendingIO()) { + this->flush(tempProxy.get()); + } + GrTexture* texture = tempProxy->instantiate(fContext->resourceProvider()); + if (!texture) { + return false; } if (applyPremulToSrc) { size_t tmpRowBytes = 4 * width; @@ -338,9 +373,9 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, buffer = tmpPixels.get(); applyPremulToSrc = false; } - if (!fGpu->writePixels(tempTexture, 0, 0, width, height, - tempDrawInfo.fWriteConfig, buffer, - rowBytes)) { + if (!fContext->fGpu->writePixels(texture, 0, 0, width, height, + tempDrawInfo.fWriteConfig, buffer, + rowBytes)) { return false; } SkMatrix matrix; @@ -348,10 +383,11 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, // TODO: Need to decide the semantics of this function for color spaces. Do we support // conversion from a passed-in color space? For now, specifying nullptr means that this // path will do no conversion, so it will match the behavior of the non-draw path. - sk_sp drawContext(this->contextPriv().makeWrappedDrawContext( - sk_ref_sp(renderTarget), - nullptr)); - if (!drawContext) { + GrRenderTarget* renderTarget = surface->asRenderTarget(); + SkASSERT(renderTarget); + sk_sp renderTargetContext( + this->makeWrappedRenderTargetContext(sk_ref_sp(renderTarget), nullptr)); + if (!renderTargetContext) { return false; } GrPaint paint; @@ -359,14 +395,15 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, paint.setPorterDuffXPFactory(SkBlendMode::kSrc); paint.setAllowSRGBInputs(true); SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); - drawContext->drawRect(GrNoClip(), paint, matrix, rect, nullptr); + renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect, + nullptr); if (kFlushWrites_PixelOp & pixelOpsFlags) { - this->flushSurfaceWrites(surface); + this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy()); } } } - if (!tempTexture) { + if (!tempProxy) { if (applyPremulToSrc) { size_t tmpRowBytes = 4 * width; tmpPixels.reset(width * height); @@ -378,23 +415,31 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, buffer = tmpPixels.get(); applyPremulToSrc = false; } - return fGpu->writePixels(surface, left, top, width, height, srcConfig, buffer, rowBytes); + return fContext->fGpu->writePixels(surface, left, top, width, height, srcConfig, + buffer, rowBytes); } return true; } -bool GrContext::readSurfacePixels(GrSurface* src, - int left, int top, int width, int height, - GrPixelConfig dstConfig, void* buffer, size_t rowBytes, - uint32_t flags) { - ASSERT_SINGLE_OWNER - RETURN_FALSE_IF_ABANDONED - ASSERT_OWNED_RESOURCE(src); - SkASSERT(src); - GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::readSurfacePixels"); +bool GrContextPriv::readSurfacePixels(GrSurfaceProxy* srcProxy, SkColorSpace* srcColorSpace, + int left, int top, int width, int height, + GrPixelConfig dstConfig, SkColorSpace* dstColorSpace, + void* buffer, size_t rowBytes, uint32_t flags) { + // TODO: Color space conversion - this->testPMConversionsIfNecessary(flags); - SkAutoMutexAcquire ama(fReadPixelsMutex); + ASSERT_SINGLE_OWNER_PRIV + RETURN_FALSE_IF_ABANDONED_PRIV + ASSERT_OWNED_PROXY_PRIV(srcProxy); + SkASSERT(srcProxy); + GR_AUDIT_TRAIL_AUTO_FRAME(&fContext->fAuditTrail, "GrContextPriv::readSurfacePixels"); + + // MDB TODO: delay this instantiation until later in the method + GrSurface* src = srcProxy->instantiate(fContext->resourceProvider()); + if (!src) { + return false; + } + + fContext->testPMConversionsIfNecessary(flags); // Adjust the params so that if we wind up using an intermediate surface we've already done // all the trimming and the temporary can be the min size required. @@ -405,29 +450,33 @@ bool GrContext::readSurfacePixels(GrSurface* src, } if (!(kDontFlush_PixelOpsFlag & flags) && src->surfacePriv().hasPendingWrite()) { - this->flush(); + this->flush(nullptr); // MDB TODO: tighten this } bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags); - if (unpremul && !GrPixelConfigIs8888(dstConfig)) { - // The unpremul flag is only allowed for 8888 configs. + if (unpremul && !valid_unpremul_config(dstConfig)) { + // The unpremul flag is only allowed for 8888 and F16 configs. + return false; + } + // We don't allow conversion between integer configs and float/fixed configs. + if (GrPixelConfigIsSint(src->config()) != GrPixelConfigIsSint(dstConfig)) { return false; } GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference; // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when // we've already determined that there isn't a roundtrip preserving conversion processor pair. - if (unpremul && !this->didFailPMUPMConversionTest()) { + if (unpremul && fContext->validPMUPMConversionExists(src->config())) { drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference; } GrGpu::ReadPixelTempDrawInfo tempDrawInfo; - if (!fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig, &drawPreference, - &tempDrawInfo)) { + if (!fContext->fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig, + &drawPreference, &tempDrawInfo)) { return false; } - SkAutoTUnref surfaceToRead(SkRef(src)); + sk_sp proxyToRead = sk_ref_sp(srcProxy); bool didTempDraw = false; if (GrGpu::kNoDraw_DrawPreference != drawPreference) { if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) { @@ -440,42 +489,45 @@ bool GrContext::readSurfacePixels(GrSurface* src, // TODO: Need to decide the semantics of this function for color spaces. Do we support // conversion to a passed-in color space? For now, specifying nullptr means that this // path will do no conversion, so it will match the behavior of the non-draw path. - sk_sp tempDC = this->makeDrawContext(tempDrawInfo.fTempSurfaceFit, + sk_sp tempRTC = fContext->makeRenderTargetContext( + tempDrawInfo.fTempSurfaceFit, tempDrawInfo.fTempSurfaceDesc.fWidth, tempDrawInfo.fTempSurfaceDesc.fHeight, tempDrawInfo.fTempSurfaceDesc.fConfig, nullptr, tempDrawInfo.fTempSurfaceDesc.fSampleCnt, tempDrawInfo.fTempSurfaceDesc.fOrigin); - if (tempDC) { - SkMatrix textureMatrix; - textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); - textureMatrix.postIDiv(src->width(), src->height()); + if (tempRTC) { + SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top)); + sk_sp proxy = sk_ref_sp(srcProxy->asTextureProxy()); + sk_sp texFP = GrSimpleTextureEffect::Make( + fContext->resourceProvider(), proxy, nullptr, textureMatrix); sk_sp fp; if (unpremul) { - fp = this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwizzle, - textureMatrix); + fp = fContext->createPMToUPMEffect(texFP, proxy->config()); if (fp) { - unpremul = false; // we no longer need to do this on CPU after the read back. + // We no longer need to do this on CPU after the read back. + unpremul = false; } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) { - // We only wanted to do the draw in order to perform the unpremul so don't - // bother. - tempDC.reset(nullptr); + // We only wanted to do the draw to perform the unpremul so don't bother. + tempRTC.reset(nullptr); } } - if (!fp && tempDC) { - fp = GrConfigConversionEffect::Make(src->asTexture(), tempDrawInfo.fSwizzle, - GrConfigConversionEffect::kNone_PMConversion, - textureMatrix); - } - if (fp) { + if (tempRTC) { + if (!fp) { + fp = std::move(texFP); + } + fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle); + SkASSERT(fp); + GrPaint paint; paint.addColorFragmentProcessor(std::move(fp)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); paint.setAllowSRGBInputs(true); SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); - tempDC->drawRect(GrNoClip(), paint, SkMatrix::I(), rect, nullptr); - surfaceToRead.reset(tempDC->asTexture().release()); + tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect, + nullptr); + proxyToRead = tempRTC->asTextureProxyRef(); left = 0; top = 0; didTempDraw = true; @@ -483,101 +535,70 @@ bool GrContext::readSurfacePixels(GrSurface* src, } } + if (!proxyToRead) { + return false; + } + + GrSurface* surfaceToRead = proxyToRead->instantiate(fContext->resourceProvider()); + if (!surfaceToRead) { + return false; + } + if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) { return false; } GrPixelConfig configToRead = dstConfig; if (didTempDraw) { - this->flushSurfaceWrites(surfaceToRead); + this->flushSurfaceWrites(proxyToRead.get()); configToRead = tempDrawInfo.fReadConfig; } - if (!fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead, buffer, - rowBytes)) { + if (!fContext->fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead, + buffer, rowBytes)) { return false; } // Perform umpremul conversion if we weren't able to perform it as a draw. if (unpremul) { - SkDstPixelInfo dstPI; - if (!GrPixelConfigToColorType(dstConfig, &dstPI.fColorType)) { + SkColorType colorType; + if (!GrPixelConfigToColorType(dstConfig, &colorType) || + 4 != SkColorTypeBytesPerPixel(colorType)) + { return false; } - dstPI.fAlphaType = kUnpremul_SkAlphaType; - dstPI.fPixels = buffer; - dstPI.fRowBytes = rowBytes; - SkSrcPixelInfo srcPI; - srcPI.fColorType = dstPI.fColorType; - srcPI.fAlphaType = kPremul_SkAlphaType; - srcPI.fPixels = buffer; - srcPI.fRowBytes = rowBytes; - - return srcPI.convertPixelsTo(&dstPI, width, height); + for (int y = 0; y < height; y++) { + SkUnpremultiplyRow((uint32_t*) buffer, (const uint32_t*) buffer, width); + buffer = SkTAddOffset(buffer, rowBytes); + } } return true; } -void GrContext::prepareSurfaceForExternalIO(GrSurface* surface) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkASSERT(surface); - ASSERT_OWNED_RESOURCE(surface); - fDrawingManager->prepareSurfaceForExternalIO(surface); +void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_IF_ABANDONED_PRIV + SkASSERT(proxy); + ASSERT_OWNED_PROXY_PRIV(proxy); + fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy); } -bool GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, - const SkIPoint& dstPoint) { - ASSERT_SINGLE_OWNER - RETURN_FALSE_IF_ABANDONED - GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::copySurface"); - - if (!src || !dst) { - return false; - } - ASSERT_OWNED_RESOURCE(src); - ASSERT_OWNED_RESOURCE(dst); - - if (!dst->asRenderTarget()) { - SkIRect clippedSrcRect; - SkIPoint clippedDstPoint; - if (!GrCopySurfaceBatch::ClipSrcRectAndDstPoint(dst, src, srcRect, dstPoint, - &clippedSrcRect, &clippedDstPoint)) { - return false; - } - // If we don't have an RT for the dst then we won't have a GrDrawContext to insert the - // the copy surface into. In the future we plan to have a more limited Context type - // (GrCopyContext?) that has the subset of GrDrawContext operations that should be - // allowed on textures that aren't render targets. - // For now we just flush any writes to the src and issue an immediate copy to the dst. - src->flushWrites(); - return fGpu->copySurface(dst, src, clippedSrcRect, clippedDstPoint); - } - sk_sp drawContext(this->contextPriv().makeWrappedDrawContext( - sk_ref_sp(dst->asRenderTarget()), - nullptr)); - if (!drawContext) { - return false; - } - - if (!drawContext->copySurface(src, srcRect, dstPoint)) { - return false; - } - return true; -} - -void GrContext::flushSurfaceWrites(GrSurface* surface) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - if (surface->surfacePriv().hasPendingWrite()) { - this->flush(); +void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_IF_ABANDONED_PRIV + SkASSERT(proxy); + ASSERT_OWNED_PROXY_PRIV(proxy); + if (proxy->priv().hasPendingWrite()) { + this->flush(proxy); } } -void GrContext::flushSurfaceIO(GrSurface* surface) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - if (surface->surfacePriv().hasPendingIO()) { - this->flush(); +void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_IF_ABANDONED_PRIV + SkASSERT(proxy); + ASSERT_OWNED_PROXY_PRIV(proxy); + if (proxy->priv().hasPendingIO()) { + this->flush(proxy); } } @@ -600,48 +621,119 @@ int GrContext::getRecommendedSampleCount(GrPixelConfig config, return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? chosenSampleCount : 0; } -sk_sp GrContextPriv::makeWrappedDrawContext(sk_sp rt, - sk_sp colorSpace, - const SkSurfaceProps* surfaceProps) { +sk_sp GrContextPriv::makeWrappedRenderTargetContext( + sk_sp rt, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps) { ASSERT_SINGLE_OWNER_PRIV - return this->drawingManager()->makeDrawContext(std::move(rt), - std::move(colorSpace), - surfaceProps); + + sk_sp proxy(GrSurfaceProxy::MakeWrapped(std::move(rt))); + if (!proxy) { + return nullptr; + } + + return this->drawingManager()->makeRenderTargetContext(std::move(proxy), + std::move(colorSpace), + surfaceProps); } -sk_sp GrContextPriv::makeBackendTextureDrawContext(const GrBackendTextureDesc& desc, - sk_sp colorSpace, - const SkSurfaceProps* props, - GrWrapOwnership ownership) { +sk_sp GrContextPriv::makeWrappedSurfaceContext(sk_sp proxy, + sk_sp colorSpace) { ASSERT_SINGLE_OWNER_PRIV - SkASSERT(desc.fFlags & kRenderTarget_GrBackendTextureFlag); - sk_sp surface(fContext->textureProvider()->wrapBackendTexture(desc, ownership)); + if (proxy->asRenderTargetProxy()) { + return this->drawingManager()->makeRenderTargetContext(std::move(proxy), + std::move(colorSpace), nullptr); + } else { + SkASSERT(proxy->asTextureProxy()); + return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace)); + } +} + +sk_sp GrContextPriv::makeWrappedSurfaceContext(sk_sp surface) { + ASSERT_SINGLE_OWNER_PRIV + + sk_sp proxy(GrSurfaceProxy::MakeWrapped(std::move(surface))); + if (!proxy) { + return nullptr; + } + + return this->makeWrappedSurfaceContext(std::move(proxy), nullptr); +} + +sk_sp GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc, + SkBackingFit fit, + SkBudgeted isDstBudgeted) { + + sk_sp proxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(), + dstDesc, fit, isDstBudgeted); + if (!proxy) { + return nullptr; + } + + return this->makeWrappedSurfaceContext(std::move(proxy), nullptr); +} + +sk_sp GrContextPriv::makeBackendSurfaceContext(const GrBackendTextureDesc& desc, + sk_sp colorSpace) { + ASSERT_SINGLE_OWNER_PRIV + + sk_sp surface(fContext->resourceProvider()->wrapBackendTexture(desc)); if (!surface) { return nullptr; } - return this->drawingManager()->makeDrawContext(sk_ref_sp(surface->asRenderTarget()), - std::move(colorSpace), props); + sk_sp proxy(GrSurfaceProxy::MakeWrapped(std::move(surface))); + if (!proxy) { + return nullptr; + } + + return this->makeWrappedSurfaceContext(std::move(proxy), std::move(colorSpace)); } -sk_sp GrContextPriv::makeBackendRenderTargetDrawContext( +sk_sp GrContextPriv::makeBackendTextureRenderTargetContext( + const GrBackendTextureDesc& desc, + sk_sp colorSpace, + const SkSurfaceProps* props) { + ASSERT_SINGLE_OWNER_PRIV + SkASSERT(desc.fFlags & kRenderTarget_GrBackendTextureFlag); + + sk_sp surface(fContext->resourceProvider()->wrapBackendTexture(desc)); + if (!surface) { + return nullptr; + } + + sk_sp proxy(GrSurfaceProxy::MakeWrapped(std::move(surface))); + if (!proxy) { + return nullptr; + } + + return this->drawingManager()->makeRenderTargetContext(std::move(proxy), + std::move(colorSpace), props); +} + +sk_sp GrContextPriv::makeBackendRenderTargetRenderTargetContext( const GrBackendRenderTargetDesc& desc, sk_sp colorSpace, const SkSurfaceProps* surfaceProps) { ASSERT_SINGLE_OWNER_PRIV - sk_sp rt(fContext->textureProvider()->wrapBackendRenderTarget(desc)); + sk_sp rt(fContext->resourceProvider()->wrapBackendRenderTarget(desc)); if (!rt) { return nullptr; } - return this->drawingManager()->makeDrawContext(std::move(rt), - std::move(colorSpace), - surfaceProps); + sk_sp proxy(GrSurfaceProxy::MakeWrapped(std::move(rt))); + if (!proxy) { + return nullptr; + } + + return this->drawingManager()->makeRenderTargetContext(std::move(proxy), + std::move(colorSpace), + surfaceProps); } -sk_sp GrContextPriv::makeBackendTextureAsRenderTargetDrawContext( +sk_sp GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext( const GrBackendTextureDesc& desc, sk_sp colorSpace, const SkSurfaceProps* surfaceProps) { @@ -653,75 +745,79 @@ sk_sp GrContextPriv::makeBackendTextureAsRenderTargetDrawContext( return nullptr; } - return this->drawingManager()->makeDrawContext(sk_ref_sp(surface->asRenderTarget()), - std::move(colorSpace), - surfaceProps); + sk_sp proxy(GrSurfaceProxy::MakeWrapped(std::move(surface))); + if (!proxy) { + return nullptr; + } + + return this->drawingManager()->makeRenderTargetContext(std::move(proxy), + std::move(colorSpace), + surfaceProps); } +void GrContextPriv::addPreFlushCallbackObject(sk_sp preFlushCBObject) { + fContext->fDrawingManager->addPreFlushCallbackObject(std::move(preFlushCBObject)); +} + + static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) { - static const GrPixelConfig kFallback[] = { - kUnknown_GrPixelConfig, // kUnknown_GrPixelConfig - kRGBA_8888_GrPixelConfig, // kAlpha_8_GrPixelConfig - kUnknown_GrPixelConfig, // kIndex_8_GrPixelConfig - kRGBA_8888_GrPixelConfig, // kRGB_565_GrPixelConfig - kRGBA_8888_GrPixelConfig, // kRGBA_4444_GrPixelConfig - kUnknown_GrPixelConfig, // kRGBA_8888_GrPixelConfig - kRGBA_8888_GrPixelConfig, // kBGRA_8888_GrPixelConfig - kUnknown_GrPixelConfig, // kSRGBA_8888_GrPixelConfig - kSRGBA_8888_GrPixelConfig, // kSBGRA_8888_GrPixelConfig - kUnknown_GrPixelConfig, // kETC1_GrPixelConfig - kUnknown_GrPixelConfig, // kLATC_GrPixelConfig - kUnknown_GrPixelConfig, // kR11_EAC_GrPixelConfig - kUnknown_GrPixelConfig, // kASTC_12x12_GrPixelConfig - kUnknown_GrPixelConfig, // kRGBA_float_GrPixelConfig - kRGBA_half_GrPixelConfig, // kAlpha_half_GrPixelConfig - kUnknown_GrPixelConfig, // kRGBA_half_GrPixelConfig - }; - return kFallback[config]; - - GR_STATIC_ASSERT(0 == kUnknown_GrPixelConfig); - GR_STATIC_ASSERT(1 == kAlpha_8_GrPixelConfig); - GR_STATIC_ASSERT(2 == kIndex_8_GrPixelConfig); - GR_STATIC_ASSERT(3 == kRGB_565_GrPixelConfig); - GR_STATIC_ASSERT(4 == kRGBA_4444_GrPixelConfig); - GR_STATIC_ASSERT(5 == kRGBA_8888_GrPixelConfig); - GR_STATIC_ASSERT(6 == kBGRA_8888_GrPixelConfig); - GR_STATIC_ASSERT(7 == kSRGBA_8888_GrPixelConfig); - GR_STATIC_ASSERT(8 == kSBGRA_8888_GrPixelConfig); - GR_STATIC_ASSERT(9 == kETC1_GrPixelConfig); - GR_STATIC_ASSERT(10 == kLATC_GrPixelConfig); - GR_STATIC_ASSERT(11 == kR11_EAC_GrPixelConfig); - GR_STATIC_ASSERT(12 == kASTC_12x12_GrPixelConfig); - GR_STATIC_ASSERT(13 == kRGBA_float_GrPixelConfig); - GR_STATIC_ASSERT(14 == kAlpha_half_GrPixelConfig); - GR_STATIC_ASSERT(15 == kRGBA_half_GrPixelConfig); - GR_STATIC_ASSERT(SK_ARRAY_COUNT(kFallback) == kGrPixelConfigCnt); + switch (config) { + case kAlpha_8_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + return kRGBA_8888_GrPixelConfig; + case kSBGRA_8888_GrPixelConfig: + return kSRGBA_8888_GrPixelConfig; + case kAlpha_half_GrPixelConfig: + return kRGBA_half_GrPixelConfig; + default: + return kUnknown_GrPixelConfig; + } } -sk_sp GrContext::makeDrawContextWithFallback(SkBackingFit fit, - int width, int height, - GrPixelConfig config, - sk_sp colorSpace, - int sampleCnt, - GrSurfaceOrigin origin, - const SkSurfaceProps* surfaceProps, - SkBudgeted budgeted) { +sk_sp GrContext::makeRenderTargetContextWithFallback( + SkBackingFit fit, + int width, int height, + GrPixelConfig config, + sk_sp colorSpace, + int sampleCnt, + GrSurfaceOrigin origin, + const SkSurfaceProps* surfaceProps, + SkBudgeted budgeted) { if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) { config = GrPixelConfigFallback(config); } - return this->makeDrawContext(fit, width, height, config, std::move(colorSpace), - sampleCnt, origin, surfaceProps, budgeted); + return this->makeRenderTargetContext(fit, width, height, config, std::move(colorSpace), + sampleCnt, origin, surfaceProps, budgeted); } -sk_sp GrContext::makeDrawContext(SkBackingFit fit, - int width, int height, - GrPixelConfig config, - sk_sp colorSpace, - int sampleCnt, - GrSurfaceOrigin origin, - const SkSurfaceProps* surfaceProps, - SkBudgeted budgeted) { +sk_sp GrContext::makeDeferredRenderTargetContextWithFallback( + SkBackingFit fit, + int width, int height, + GrPixelConfig config, + sk_sp colorSpace, + int sampleCnt, + GrSurfaceOrigin origin, + const SkSurfaceProps* surfaceProps, + SkBudgeted budgeted) { + if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) { + config = GrPixelConfigFallback(config); + } + + return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace), + sampleCnt, origin, surfaceProps, budgeted); +} + +sk_sp GrContext::makeRenderTargetContext(SkBackingFit fit, + int width, int height, + GrPixelConfig config, + sk_sp colorSpace, + int sampleCnt, + GrSurfaceOrigin origin, + const SkSurfaceProps* surfaceProps, + SkBudgeted budgeted) { if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) { return nullptr; } @@ -736,22 +832,61 @@ sk_sp GrContext::makeDrawContext(SkBackingFit fit, sk_sp tex; if (SkBackingFit::kExact == fit) { - tex.reset(this->textureProvider()->createTexture(desc, budgeted)); + tex = this->resourceProvider()->createTexture(desc, budgeted); } else { - tex.reset(this->textureProvider()->createApproxTexture(desc)); + tex.reset(this->resourceProvider()->createApproxTexture(desc, 0)); } if (!tex) { return nullptr; } - sk_sp drawContext(this->contextPriv().makeWrappedDrawContext( - sk_ref_sp(tex->asRenderTarget()), + sk_sp renderTargetContext( + this->contextPriv().makeWrappedRenderTargetContext(sk_ref_sp(tex->asRenderTarget()), std::move(colorSpace), surfaceProps)); - if (!drawContext) { + if (!renderTargetContext) { return nullptr; } - return drawContext; + renderTargetContext->discard(); + + return renderTargetContext; +} + +sk_sp GrContext::makeDeferredRenderTargetContext( + SkBackingFit fit, + int width, int height, + GrPixelConfig config, + sk_sp colorSpace, + int sampleCnt, + GrSurfaceOrigin origin, + const SkSurfaceProps* surfaceProps, + SkBudgeted budgeted) { + GrSurfaceDesc desc; + desc.fFlags = kRenderTarget_GrSurfaceFlag; + desc.fOrigin = origin; + desc.fWidth = width; + desc.fHeight = height; + desc.fConfig = config; + desc.fSampleCnt = sampleCnt; + + sk_sp rtp = GrSurfaceProxy::MakeDeferred(this->resourceProvider(), + desc, fit, budgeted); + if (!rtp) { + return nullptr; + } + + sk_sp renderTargetContext( + fDrawingManager->makeRenderTargetContext(std::move(rtp), + std::move(colorSpace), + surfaceProps)); + + if (!renderTargetContext) { + return nullptr; + } + + renderTargetContext->discard(); + + return renderTargetContext; } bool GrContext::abandoned() const { @@ -771,8 +906,7 @@ void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { void GrContext::testPMConversionsIfNecessary(uint32_t flags) { ASSERT_SINGLE_OWNER - if (SkToBool(kUnpremul_PixelOpsFlag & flags)) { - SkAutoMutexAcquire ama(fTestPMConversionsMutex); + if (SkToBool(GrContextPriv::kUnpremul_PixelOpsFlag & flags)) { if (!fDidTestPMConversions) { test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion); fDidTestPMConversions = true; @@ -780,42 +914,48 @@ void GrContext::testPMConversionsIfNecessary(uint32_t flags) { } } -sk_sp GrContext::createPMToUPMEffect(GrTexture* texture, - const GrSwizzle& swizzle, - const SkMatrix& matrix) const { +sk_sp GrContext::createPMToUPMEffect(sk_sp fp, + GrPixelConfig config) { ASSERT_SINGLE_OWNER // We should have already called this->testPMConversionsIfNecessary(). SkASSERT(fDidTestPMConversions); - GrConfigConversionEffect::PMConversion pmToUPM = - static_cast(fPMToUPMConversion); - if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) { - return GrConfigConversionEffect::Make(texture, swizzle, pmToUPM, matrix); - } else { - return nullptr; + if (kRGBA_half_GrPixelConfig == config) { + return GrFragmentProcessor::UnpremulOutput(std::move(fp)); + } else if (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config) { + GrConfigConversionEffect::PMConversion pmToUPM = + static_cast(fPMToUPMConversion); + if (GrConfigConversionEffect::kPMConversionCnt != pmToUPM) { + return GrConfigConversionEffect::Make(std::move(fp), pmToUPM); + } } + return nullptr; } -sk_sp GrContext::createUPMToPMEffect(GrTexture* texture, - const GrSwizzle& swizzle, - const SkMatrix& matrix) const { +sk_sp GrContext::createUPMToPMEffect(sk_sp fp, + GrPixelConfig config) { ASSERT_SINGLE_OWNER // We should have already called this->testPMConversionsIfNecessary(). SkASSERT(fDidTestPMConversions); - GrConfigConversionEffect::PMConversion upmToPM = - static_cast(fUPMToPMConversion); - if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) { - return GrConfigConversionEffect::Make(texture, swizzle, upmToPM, matrix); - } else { - return nullptr; + if (kRGBA_half_GrPixelConfig == config) { + return GrFragmentProcessor::PremulOutput(std::move(fp)); + } else if (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config) { + GrConfigConversionEffect::PMConversion upmToPM = + static_cast(fUPMToPMConversion); + if (GrConfigConversionEffect::kPMConversionCnt != upmToPM) { + return GrConfigConversionEffect::Make(std::move(fp), upmToPM); + } } + return nullptr; } -bool GrContext::didFailPMUPMConversionTest() const { +bool GrContext::validPMUPMConversionExists(GrPixelConfig config) const { ASSERT_SINGLE_OWNER // We should have already called this->testPMConversionsIfNecessary(). SkASSERT(fDidTestPMConversions); // The PM<->UPM tests fail or succeed together so we only need to check one. - return GrConfigConversionEffect::kNone_PMConversion == fPMToUPMConversion; + // For F16, we always allow PM/UPM conversion on the GPU, even if it doesn't round-trip. + return GrConfigConversionEffect::kPMConversionCnt != fPMToUPMConversion || + kRGBA_half_GrPixelConfig == config; } ////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/gpu/GrContextPriv.h b/gfx/skia/skia/src/gpu/GrContextPriv.h index 29eb151b6cc9..95df8eacc96a 100644 --- a/gfx/skia/skia/src/gpu/GrContextPriv.h +++ b/gfx/skia/skia/src/gpu/GrContextPriv.h @@ -9,36 +9,157 @@ #define GrContextPriv_DEFINED #include "GrContext.h" +#include "GrSurfaceContext.h" + +class GrSemaphore; +class GrSurfaceProxy; +class GrPreFlushCallbackObject; /** Class that adds methods to GrContext that are only intended for use internal to Skia. This class is purely a privileged window into GrContext. It should never have additional data members or virtual methods. */ class GrContextPriv { public: - GrDrawingManager* drawingManager() { return fContext->fDrawingManager; } + GrDrawingManager* drawingManager() { return fContext->fDrawingManager.get(); } - // Create a drawContext that wraps an existing renderTarget - sk_sp makeWrappedDrawContext(sk_sp rt, - sk_sp colorSpace, - const SkSurfaceProps* = nullptr); + // Create a renderTargetContext that wraps an existing renderTarget + sk_sp makeWrappedRenderTargetContext(sk_sp, + sk_sp, + const SkSurfaceProps* = nullptr); - sk_sp makeBackendTextureDrawContext(const GrBackendTextureDesc& desc, - sk_sp colorSpace, - const SkSurfaceProps* = nullptr, - GrWrapOwnership = kBorrow_GrWrapOwnership); + // Create a surfaceContext that wraps an existing texture or renderTarget + sk_sp makeWrappedSurfaceContext(sk_sp); - sk_sp makeBackendRenderTargetDrawContext(const GrBackendRenderTargetDesc& desc, - sk_sp colorSpace, - const SkSurfaceProps* = nullptr); + sk_sp makeWrappedSurfaceContext(sk_sp, sk_sp); - sk_sp makeBackendTextureAsRenderTargetDrawContext( + sk_sp makeDeferredSurfaceContext(const GrSurfaceDesc&, + SkBackingFit, + SkBudgeted); + + // TODO: Maybe add a 'surfaceProps' param (that is ignored for non-RTs) and remove + // makeBackendTextureRenderTargetContext & makeBackendTextureAsRenderTargetRenderTargetContext + sk_sp makeBackendSurfaceContext(const GrBackendTextureDesc& desc, + sk_sp colorSpace); + + sk_sp makeBackendTextureRenderTargetContext( + const GrBackendTextureDesc& desc, + sk_sp colorSpace, + const SkSurfaceProps* = nullptr); + + sk_sp makeBackendRenderTargetRenderTargetContext( + const GrBackendRenderTargetDesc& desc, + sk_sp colorSpace, + const SkSurfaceProps* = nullptr); + + sk_sp makeBackendTextureAsRenderTargetRenderTargetContext( const GrBackendTextureDesc& desc, sk_sp colorSpace, const SkSurfaceProps* = nullptr); + bool disableGpuYUVConversion() const { return fContext->fDisableGpuYUVConversion; } + + /** + * Call to ensure all drawing to the context has been issued to the + * underlying 3D API. + * The 'proxy' parameter is a hint. If it is supplied the context will guarantee that + * the draws required for that proxy are flushed but it could do more. If no 'proxy' is + * provided then all current work will be flushed. + */ + void flush(GrSurfaceProxy*); + + /* + * A ref will be taken on the preFlushCallbackObject which will be removed when the + * context is destroyed. + */ + void addPreFlushCallbackObject(sk_sp); + + /** + * After this returns any pending writes to the surface will have been issued to the + * backend 3D API. + */ + void flushSurfaceWrites(GrSurfaceProxy*); + + /** + * After this returns any pending reads or writes to the surface will have been issued to the + * backend 3D API. + */ + void flushSurfaceIO(GrSurfaceProxy*); + + /** + * Finalizes all pending reads and writes to the surface and also performs an MSAA resolve + * if necessary. + * + * It is not necessary to call this before reading the render target via Skia/GrContext. + * GrContext will detect when it must perform a resolve before reading pixels back from the + * surface or using it as a texture. + */ + void prepareSurfaceForExternalIO(GrSurfaceProxy*); + + /** + * These flags can be used with the read/write pixels functions below. + */ + enum PixelOpsFlags { + /** The GrContext will not be flushed before the surface read or write. This means that + the read or write may occur before previous draws have executed. */ + kDontFlush_PixelOpsFlag = 0x1, + /** Any surface writes should be flushed to the backend 3D API after the surface operation + is complete */ + kFlushWrites_PixelOp = 0x2, + /** The src for write or dst read is unpremultiplied. This is only respected if both the + config src and dst configs are an RGBA/BGRA 8888 format. */ + kUnpremul_PixelOpsFlag = 0x4, + }; + + /** + * Reads a rectangle of pixels from a surface. + * @param surface the surface to read from. + * @param srcColorSpace color space of the surface + * @param left left edge of the rectangle to read (inclusive) + * @param top top edge of the rectangle to read (inclusive) + * @param width width of rectangle to read in pixels. + * @param height height of rectangle to read in pixels. + * @param config the pixel config of the destination buffer + * @param dstColorSpace color space of the destination buffer + * @param buffer memory to read the rectangle into. + * @param rowBytes number of bytes bewtween consecutive rows. Zero means rows are tightly + * packed. + * @param pixelOpsFlags see PixelOpsFlags enum above. + * + * @return true if the read succeeded, false if not. The read can fail because of an unsupported + * pixel configs + */ + bool readSurfacePixels(GrSurfaceProxy* src, SkColorSpace* srcColorSpace, + int left, int top, int width, int height, + GrPixelConfig config, SkColorSpace* dstColorSpace, void* buffer, + size_t rowBytes = 0, + uint32_t pixelOpsFlags = 0); + + /** + * Writes a rectangle of pixels to a surface. + * @param dst the surface to write to. + * @param dstColorSpace color space of the surface + * @param left left edge of the rectangle to write (inclusive) + * @param top top edge of the rectangle to write (inclusive) + * @param width width of rectangle to write in pixels. + * @param height height of rectangle to write in pixels. + * @param config the pixel config of the source buffer + * @param srcColorSpace color space of the source buffer + * @param buffer memory to read pixels from + * @param rowBytes number of bytes between consecutive rows. Zero + * means rows are tightly packed. + * @param pixelOpsFlags see PixelOpsFlags enum above. + * @return true if the write succeeded, false if not. The write can fail because of an + * unsupported combination of surface and src configs. + */ + bool writeSurfacePixels(GrSurfaceProxy* dst, SkColorSpace* dstColorSpace, + int left, int top, int width, int height, + GrPixelConfig config, SkColorSpace* srcColorSpace, const void* buffer, + size_t rowBytes, + uint32_t pixelOpsFlags = 0); + private: explicit GrContextPriv(GrContext* context) : fContext(context) {} - GrContextPriv(const GrContextPriv&) {} // unimpl + GrContextPriv(const GrContextPriv&); // unimpl GrContextPriv& operator=(const GrContextPriv&); // unimpl // No taking addresses of this type. diff --git a/gfx/skia/skia/src/gpu/GrCoordTransform.cpp b/gfx/skia/skia/src/gpu/GrCoordTransform.cpp index 2da49c43fbbc..79d9e98b7677 100644 --- a/gfx/skia/skia/src/gpu/GrCoordTransform.cpp +++ b/gfx/skia/skia/src/gpu/GrCoordTransform.cpp @@ -6,55 +6,19 @@ */ #include "GrCoordTransform.h" -#include "GrCaps.h" -#include "GrContext.h" -#include "GrGpu.h" +#include "GrResourceProvider.h" +#include "GrTextureProxy.h" -void GrCoordTransform::reset(const SkMatrix& m, const GrTexture* texture, - GrTextureParams::FilterMode filter) { - SkASSERT(texture); +void GrCoordTransform::reset(GrResourceProvider* resourceProvider, const SkMatrix& m, + GrTextureProxy* proxy, bool normalize) { + SkASSERT(proxy); SkASSERT(!fInProcessor); fMatrix = m; - fReverseY = kBottomLeft_GrSurfaceOrigin == texture->origin(); - - // Always start at kDefault. Then if precisions differ we see if the precision needs to be - // increased. Our rule is that we want at least 4 subpixel values in the representation for - // coords between 0 to 1 when bi- or tri-lerping and 1 value when nearest filtering. Note that - // this still might not be enough when drawing with repeat or mirror-repeat modes but that case - // can be arbitrarily bad. - int subPixelThresh = filter > GrTextureParams::kNone_FilterMode ? 4 : 1; - fPrecision = kDefault_GrSLPrecision; - if (texture->getContext()) { - const GrShaderCaps* caps = texture->getContext()->caps()->shaderCaps(); - if (caps->floatPrecisionVaries()) { - int maxD = SkTMax(texture->width(), texture->height()); - const GrShaderCaps::PrecisionInfo* info; - info = &caps->getFloatShaderPrecisionInfo(kFragment_GrShaderType, fPrecision); - do { - SkASSERT(info->supported()); - // Make sure there is at least 2 bits of subpixel precision in the range of - // texture coords from 0.5 to 1.0. - if ((2 << info->fBits) / maxD > subPixelThresh) { - break; - } - if (kHigh_GrSLPrecision == fPrecision) { - break; - } - GrSLPrecision nextP = static_cast(fPrecision + 1); - info = &caps->getFloatShaderPrecisionInfo(kFragment_GrShaderType, nextP); - if (!info->supported()) { - break; - } - fPrecision = nextP; - } while (true); - } - } -} - -void GrCoordTransform::reset(const SkMatrix& m, GrSLPrecision precision) { - SkASSERT(!fInProcessor); - fMatrix = m; - fReverseY = false; - fPrecision = precision; + // MDB TODO: just GrCaps is needed for this method + // MDB TODO: once all the coord transforms take a proxy just store it here and + // instantiate later + fTexture = proxy->instantiate(resourceProvider); + fNormalize = normalize; + fReverseY = kBottomLeft_GrSurfaceOrigin == proxy->origin(); } diff --git a/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.cpp b/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.cpp index 7d89f2727b85..90d32394e72a 100644 --- a/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.cpp +++ b/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.cpp @@ -7,7 +7,6 @@ #include "GrDefaultGeoProcFactory.h" -#include "GrInvariantOutput.h" #include "SkRefCnt.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" @@ -23,23 +22,22 @@ */ enum GPFlag { - kColor_GPFlag = 0x1, - kLocalCoord_GPFlag = 0x2, - kCoverage_GPFlag= 0x4, + kColorAttribute_GPFlag = 0x1, + kColorAttributeIsSkColor_GPFlag = 0x2, + kLocalCoordAttribute_GPFlag = 0x4, + kCoverageAttribute_GPFlag = 0x8, }; class DefaultGeoProc : public GrGeometryProcessor { public: static sk_sp Make(uint32_t gpTypeFlags, - GrColor color, - const SkMatrix& viewMatrix, - const SkMatrix& localMatrix, - bool localCoordsWillBeRead, - bool coverageWillBeIgnored, - uint8_t coverage) { + GrColor color, + const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, + bool localCoordsWillBeRead, + uint8_t coverage) { return sk_sp(new DefaultGeoProc( - gpTypeFlags, color, viewMatrix, localMatrix, coverage, - localCoordsWillBeRead, coverageWillBeIgnored)); + gpTypeFlags, color, viewMatrix, localMatrix, coverage, localCoordsWillBeRead)); } const char* name() const override { return "DefaultGeometryProcessor"; } @@ -49,13 +47,11 @@ public: const Attribute* inLocalCoords() const { return fInLocalCoords; } const Attribute* inCoverage() const { return fInCoverage; } GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } bool hasVertexColor() const { return SkToBool(fInColor); } const SkMatrix& viewMatrix() const { return fViewMatrix; } const SkMatrix& localMatrix() const { return fLocalMatrix; } bool localCoordsWillBeRead() const { return fLocalCoordsWillBeRead; } uint8_t coverage() const { return fCoverage; } - bool coverageWillBeIgnored() const { return fCoverageWillBeIgnored; } bool hasVertexCoverage() const { return SkToBool(fInCoverage); } class GLSLProcessor : public GrGLSLGeometryProcessor { @@ -74,13 +70,21 @@ public: varyingHandler->emitAttributes(gp); // Setup pass through color - if (!gp.colorIgnored()) { - if (gp.hasVertexColor()) { - varyingHandler->addPassThroughAttribute(gp.inColor(), args.fOutputColor); + if (gp.hasVertexColor()) { + GrGLSLVertToFrag varying(kVec4f_GrSLType); + varyingHandler->addVarying("color", &varying); + if (gp.fFlags & kColorAttributeIsSkColor_GPFlag) { + // Do a red/blue swap and premul the color. + vertBuilder->codeAppendf("%s = vec4(%s.a*%s.bgr, %s.a);", varying.vsOut(), + gp.inColor()->fName, gp.inColor()->fName, + gp.inColor()->fName); } else { - this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, - &fColorUniform); + vertBuilder->codeAppendf("%s = %s;\n", varying.vsOut(), gp.inColor()->fName); } + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn()); + } else { + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, + &fColorUniform); } // Setup position @@ -112,38 +116,31 @@ public: } // Setup coverage as pass through - if (!gp.coverageWillBeIgnored()) { - if (gp.hasVertexCoverage()) { - fragBuilder->codeAppendf("float alpha = 1.0;"); - varyingHandler->addPassThroughAttribute(gp.inCoverage(), "alpha"); - fragBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage); - } else if (gp.coverage() == 0xff) { - fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage); - } else { - const char* fragCoverage; - fCoverageUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, - kFloat_GrSLType, - kDefault_GrSLPrecision, - "Coverage", - &fragCoverage); - fragBuilder->codeAppendf("%s = vec4(%s);", args.fOutputCoverage, fragCoverage); - } + if (gp.hasVertexCoverage()) { + fragBuilder->codeAppendf("float alpha = 1.0;"); + varyingHandler->addPassThroughAttribute(gp.inCoverage(), "alpha"); + fragBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage); + } else if (gp.coverage() == 0xff) { + fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage); + } else { + const char* fragCoverage; + fCoverageUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, + kFloat_GrSLType, + kDefault_GrSLPrecision, + "Coverage", + &fragCoverage); + fragBuilder->codeAppendf("%s = vec4(%s);", args.fOutputCoverage, fragCoverage); } } static inline void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const DefaultGeoProc& def = gp.cast(); uint32_t key = def.fFlags; - key |= def.colorIgnored() << 8; - key |= def.coverageWillBeIgnored() << 9; - key |= def.hasVertexColor() << 10; - key |= def.hasVertexCoverage() << 11; - key |= def.coverage() == 0xff ? 0x1 << 12 : 0; - key |= def.localCoordsWillBeRead() && def.localMatrix().hasPerspective() ? 0x1 << 24 : - 0x0; - key |= ComputePosKey(def.viewMatrix()) << 25; + key |= (def.coverage() == 0xff) ? 0x10 : 0; + key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x20 : 0x0; + key |= ComputePosKey(def.viewMatrix()) << 20; b->add32(key); } @@ -166,8 +163,7 @@ public: fColor = dgp.color(); } - if (!dgp.coverageWillBeIgnored() && - dgp.coverage() != fCoverage && !dgp.hasVertexCoverage()) { + if (dgp.coverage() != fCoverage && !dgp.hasVertexCoverage()) { pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.coverage())); fCoverage = dgp.coverage(); } @@ -185,11 +181,11 @@ public: typedef GrGLSLGeometryProcessor INHERITED; }; - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLProcessor::GenKey(*this, caps, b); } - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { return new GLSLProcessor(); } @@ -199,49 +195,39 @@ private: const SkMatrix& viewMatrix, const SkMatrix& localMatrix, uint8_t coverage, - bool localCoordsWillBeRead, - bool coverageWillBeIgnored) - : fInPosition(nullptr) - , fInColor(nullptr) - , fInLocalCoords(nullptr) - , fInCoverage(nullptr) - , fColor(color) - , fViewMatrix(viewMatrix) - , fLocalMatrix(localMatrix) - , fCoverage(coverage) - , fFlags(gpTypeFlags) - , fLocalCoordsWillBeRead(localCoordsWillBeRead) - , fCoverageWillBeIgnored(coverageWillBeIgnored) { + bool localCoordsWillBeRead) + : fColor(color) + , fViewMatrix(viewMatrix) + , fLocalMatrix(localMatrix) + , fCoverage(coverage) + , fFlags(gpTypeFlags) + , fLocalCoordsWillBeRead(localCoordsWillBeRead) { this->initClassID(); - bool hasColor = SkToBool(gpTypeFlags & kColor_GPFlag); - bool hasExplicitLocalCoords = SkToBool(gpTypeFlags & kLocalCoord_GPFlag); - bool hasCoverage = SkToBool(gpTypeFlags & kCoverage_GPFlag); fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision); - if (hasColor) { + if (fFlags & kColorAttribute_GPFlag) { fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); } - if (hasExplicitLocalCoords) { + if (fFlags & kLocalCoordAttribute_GPFlag) { fInLocalCoords = &this->addVertexAttrib("inLocalCoord", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision); this->setHasExplicitLocalCoords(); } - if (hasCoverage) { + if (fFlags & kCoverageAttribute_GPFlag) { fInCoverage = &this->addVertexAttrib("inCoverage", kFloat_GrVertexAttribType); } } - const Attribute* fInPosition; - const Attribute* fInColor; - const Attribute* fInLocalCoords; - const Attribute* fInCoverage; + const Attribute* fInPosition = nullptr; + const Attribute* fInColor = nullptr; + const Attribute* fInLocalCoords = nullptr; + const Attribute* fInCoverage = nullptr; GrColor fColor; SkMatrix fViewMatrix; SkMatrix fLocalMatrix; uint8_t fCoverage; uint32_t fFlags; bool fLocalCoordsWillBeRead; - bool fCoverageWillBeIgnored; GR_DECLARE_GEOMETRY_PROCESSOR_TEST; @@ -250,38 +236,46 @@ private: GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc); +#if GR_TEST_UTILS sk_sp DefaultGeoProc::TestCreate(GrProcessorTestData* d) { uint32_t flags = 0; if (d->fRandom->nextBool()) { - flags |= kColor_GPFlag; + flags |= kColorAttribute_GPFlag; } if (d->fRandom->nextBool()) { - flags |= kCoverage_GPFlag; + flags |= kColorAttributeIsSkColor_GPFlag; } if (d->fRandom->nextBool()) { - flags |= kLocalCoord_GPFlag; + flags |= kCoverageAttribute_GPFlag; + } + if (d->fRandom->nextBool()) { + flags |= kLocalCoordAttribute_GPFlag; } return DefaultGeoProc::Make(flags, GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom), GrTest::TestMatrix(d->fRandom), - d->fRandom->nextBool(), + d->fRandom->nextBool(), GrRandomCoverage(d->fRandom)); } +#endif sk_sp GrDefaultGeoProcFactory::Make(const Color& color, const Coverage& coverage, const LocalCoords& localCoords, const SkMatrix& viewMatrix) { uint32_t flags = 0; - flags |= color.fType == Color::kAttribute_Type ? kColor_GPFlag : 0; - flags |= coverage.fType == Coverage::kAttribute_Type ? kCoverage_GPFlag : 0; - flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoord_GPFlag : 0; + if (Color::kPremulGrColorAttribute_Type == color.fType) { + flags |= kColorAttribute_GPFlag; + } else if (Color::kUnpremulSkColorAttribute_Type == color.fType) { + flags |= kColorAttribute_GPFlag | kColorAttributeIsSkColor_GPFlag; + } + flags |= coverage.fType == Coverage::kAttribute_Type ? kCoverageAttribute_GPFlag : 0; + flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0; uint8_t inCoverage = coverage.fCoverage; - bool coverageWillBeIgnored = coverage.fType == Coverage::kNone_Type; bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type; GrColor inColor = color.fColor; @@ -290,7 +284,6 @@ sk_sp GrDefaultGeoProcFactory::Make(const Color& color, viewMatrix, localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(), localCoordsWillBeRead, - coverageWillBeIgnored, inCoverage); } diff --git a/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.h b/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.h index 022930b65991..00ee90d9400b 100644 --- a/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.h +++ b/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.h @@ -12,9 +12,7 @@ /* * A factory for creating default Geometry Processors which simply multiply position by the uniform - * view matrix and wire through color, coverage, UV coords if requested. Right now this is only - * used in the creation of optimized draw states because adding default GPs to the drawstate can - * interfere with batching due to updating the drawstate. + * view matrix and wire through color, coverage, UV coords if requested. */ namespace GrDefaultGeoProcFactory { // Structs for adding vertex attributes @@ -64,18 +62,13 @@ namespace GrDefaultGeoProcFactory { struct Color { enum Type { - kNone_Type, - kUniform_Type, - kAttribute_Type, + kPremulGrColorUniform_Type, + kPremulGrColorAttribute_Type, + kUnpremulSkColorAttribute_Type, }; - Color(GrColor color) : fType(kUniform_Type), fColor(color) {} + explicit Color(GrColor color) : fType(kPremulGrColorUniform_Type), fColor(color) {} Color(Type type) : fType(type), fColor(GrColor_ILLEGAL) { - SkASSERT(type != kUniform_Type); - - // TODO This is temporary - if (kAttribute_Type == type) { - fColor = GrColor_WHITE; - } + SkASSERT(type != kPremulGrColorUniform_Type); } Type fType; @@ -84,12 +77,11 @@ namespace GrDefaultGeoProcFactory { struct Coverage { enum Type { - kNone_Type, kSolid_Type, kUniform_Type, kAttribute_Type, }; - Coverage(uint8_t coverage) : fType(kUniform_Type), fCoverage(coverage) {} + explicit Coverage(uint8_t coverage) : fType(kUniform_Type), fCoverage(coverage) {} Coverage(Type type) : fType(type), fCoverage(0xff) { SkASSERT(type != kUniform_Type); } @@ -129,8 +121,6 @@ namespace GrDefaultGeoProcFactory { const Coverage&, const LocalCoords&, const SkMatrix& viewMatrix); - - inline size_t DefaultVertexStride() { return sizeof(PositionAttr); } }; #endif diff --git a/gfx/skia/skia/src/gpu/GrDistanceFieldGenFromVector.cpp b/gfx/skia/skia/src/gpu/GrDistanceFieldGenFromVector.cpp new file mode 100644 index 000000000000..8867ab1ab63e --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrDistanceFieldGenFromVector.cpp @@ -0,0 +1,875 @@ +/* + * Copyright 2017 ARM Ltd. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkDistanceFieldGen.h" +#include "GrDistanceFieldGenFromVector.h" + +#include "GrConfig.h" +#include "GrPathUtils.h" +#include "SkAutoMalloc.h" +#include "SkGeometry.h" +#include "SkMatrix.h" +#include "SkPathOps.h" +#include "SkPoint.h" + +/** + * If a scanline (a row of texel) cross from the kRight_SegSide + * of a segment to the kLeft_SegSide, the winding score should + * add 1. + * And winding score should subtract 1 if the scanline cross + * from kLeft_SegSide to kRight_SegSide. + * Always return kNA_SegSide if the scanline does not cross over + * the segment. Winding score should be zero in this case. + * You can get the winding number for each texel of the scanline + * by adding the winding score from left to right. + * Assuming we always start from outside, so the winding number + * should always start from zero. + * ________ ________ + * | | | | + * ...R|L......L|R.....L|R......R|L..... <= Scanline & side of segment + * |+1 |-1 |-1 |+1 <= Winding score + * 0 | 1 ^ 0 ^ -1 |0 <= Winding number + * |________| |________| + * + * .......NA................NA.......... + * 0 0 + */ +enum SegSide { + kLeft_SegSide = -1, + kOn_SegSide = 0, + kRight_SegSide = 1, + kNA_SegSide = 2, +}; + +struct DFData { + float fDistSq; // distance squared to nearest (so far) edge + int fDeltaWindingScore; // +1 or -1 whenever a scanline cross over a segment +}; + +/////////////////////////////////////////////////////////////////////////////// + +/* + * Type definition for double precision DPoint and DAffineMatrix + */ + +// Point with double precision +struct DPoint { + double fX, fY; + + static DPoint Make(double x, double y) { + DPoint pt; + pt.set(x, y); + return pt; + } + + double x() const { return fX; } + double y() const { return fY; } + + void set(double x, double y) { fX = x; fY = y; } + + /** Returns the euclidian distance from (0,0) to (x,y) + */ + static double Length(double x, double y) { + return sqrt(x * x + y * y); + } + + /** Returns the euclidian distance between a and b + */ + static double Distance(const DPoint& a, const DPoint& b) { + return Length(a.fX - b.fX, a.fY - b.fY); + } + + double distanceToSqd(const DPoint& pt) const { + double dx = fX - pt.fX; + double dy = fY - pt.fY; + return dx * dx + dy * dy; + } +}; + +// Matrix with double precision for affine transformation. +// We don't store row 3 because its always (0, 0, 1). +class DAffineMatrix { +public: + double operator[](int index) const { + SkASSERT((unsigned)index < 6); + return fMat[index]; + } + + double& operator[](int index) { + SkASSERT((unsigned)index < 6); + return fMat[index]; + } + + void setAffine(double m11, double m12, double m13, + double m21, double m22, double m23) { + fMat[0] = m11; + fMat[1] = m12; + fMat[2] = m13; + fMat[3] = m21; + fMat[4] = m22; + fMat[5] = m23; + } + + /** Set the matrix to identity + */ + void reset() { + fMat[0] = fMat[4] = 1.0; + fMat[1] = fMat[3] = + fMat[2] = fMat[5] = 0.0; + } + + // alias for reset() + void setIdentity() { this->reset(); } + + DPoint mapPoint(const SkPoint& src) const { + DPoint pt = DPoint::Make(src.x(), src.y()); + return this->mapPoint(pt); + } + + DPoint mapPoint(const DPoint& src) const { + return DPoint::Make(fMat[0] * src.x() + fMat[1] * src.y() + fMat[2], + fMat[3] * src.x() + fMat[4] * src.y() + fMat[5]); + } +private: + double fMat[6]; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static const double kClose = (SK_Scalar1 / 16.0); +static const double kCloseSqd = kClose * kClose; +static const double kNearlyZero = (SK_Scalar1 / (1 << 18)); +static const double kTangentTolerance = (SK_Scalar1 / (1 << 11)); +static const float kConicTolerance = 0.25f; + +static inline bool between_closed_open(double a, double b, double c, + double tolerance = 0.0, + bool xformToleranceToX = false) { + SkASSERT(tolerance >= 0.0); + double tolB = tolerance; + double tolC = tolerance; + + if (xformToleranceToX) { + // Canonical space is y = x^2 and the derivative of x^2 is 2x. + // So the slope of the tangent line at point (x, x^2) is 2x. + // + // /| + // sqrt(2x * 2x + 1 * 1) / | 2x + // /__| + // 1 + tolB = tolerance / sqrt(4.0 * b * b + 1.0); + tolC = tolerance / sqrt(4.0 * c * c + 1.0); + } + return b < c ? (a >= b - tolB && a < c - tolC) : + (a >= c - tolC && a < b - tolB); +} + +static inline bool between_closed(double a, double b, double c, + double tolerance = 0.0, + bool xformToleranceToX = false) { + SkASSERT(tolerance >= 0.0); + double tolB = tolerance; + double tolC = tolerance; + + if (xformToleranceToX) { + tolB = tolerance / sqrt(4.0 * b * b + 1.0); + tolC = tolerance / sqrt(4.0 * c * c + 1.0); + } + return b < c ? (a >= b - tolB && a <= c + tolC) : + (a >= c - tolC && a <= b + tolB); +} + +static inline bool nearly_zero(double x, double tolerance = kNearlyZero) { + SkASSERT(tolerance >= 0.0); + return fabs(x) <= tolerance; +} + +static inline bool nearly_equal(double x, double y, + double tolerance = kNearlyZero, + bool xformToleranceToX = false) { + SkASSERT(tolerance >= 0.0); + if (xformToleranceToX) { + tolerance = tolerance / sqrt(4.0 * y * y + 1.0); + } + return fabs(x - y) <= tolerance; +} + +static inline double sign_of(const double &val) { + return (val < 0.0) ? -1.0 : 1.0; +} + +static bool is_colinear(const SkPoint pts[3]) { + return nearly_zero((pts[1].y() - pts[0].y()) * (pts[1].x() - pts[2].x()) - + (pts[1].y() - pts[2].y()) * (pts[1].x() - pts[0].x()), kCloseSqd); +} + +class PathSegment { +public: + enum { + // These enum values are assumed in member functions below. + kLine = 0, + kQuad = 1, + } fType; + + // line uses 2 pts, quad uses 3 pts + SkPoint fPts[3]; + + DPoint fP0T, fP2T; + DAffineMatrix fXformMatrix; + double fScalingFactor; + double fScalingFactorSqd; + double fNearlyZeroScaled; + double fTangentTolScaledSqd; + SkRect fBoundingBox; + + void init(); + + int countPoints() { + GR_STATIC_ASSERT(0 == kLine && 1 == kQuad); + return fType + 2; + } + + const SkPoint& endPt() const { + GR_STATIC_ASSERT(0 == kLine && 1 == kQuad); + return fPts[fType + 1]; + } +}; + +typedef SkTArray PathSegmentArray; + +void PathSegment::init() { + const DPoint p0 = DPoint::Make(fPts[0].x(), fPts[0].y()); + const DPoint p2 = DPoint::Make(this->endPt().x(), this->endPt().y()); + const double p0x = p0.x(); + const double p0y = p0.y(); + const double p2x = p2.x(); + const double p2y = p2.y(); + + fBoundingBox.set(fPts[0], this->endPt()); + + if (fType == PathSegment::kLine) { + fScalingFactorSqd = fScalingFactor = 1.0; + double hypotenuse = DPoint::Distance(p0, p2); + + const double cosTheta = (p2x - p0x) / hypotenuse; + const double sinTheta = (p2y - p0y) / hypotenuse; + + fXformMatrix.setAffine( + cosTheta, sinTheta, -(cosTheta * p0x) - (sinTheta * p0y), + -sinTheta, cosTheta, (sinTheta * p0x) - (cosTheta * p0y) + ); + } else { + SkASSERT(fType == PathSegment::kQuad); + + // Calculate bounding box + const SkPoint _P1mP0 = fPts[1] - fPts[0]; + SkPoint t = _P1mP0 - fPts[2] + fPts[1]; + t.fX = _P1mP0.x() / t.x(); + t.fY = _P1mP0.y() / t.y(); + t.fX = SkScalarClampMax(t.x(), 1.0); + t.fY = SkScalarClampMax(t.y(), 1.0); + t.fX = _P1mP0.x() * t.x(); + t.fY = _P1mP0.y() * t.y(); + const SkPoint m = fPts[0] + t; + fBoundingBox.growToInclude(&m, 1); + + const double p1x = fPts[1].x(); + const double p1y = fPts[1].y(); + + const double p0xSqd = p0x * p0x; + const double p0ySqd = p0y * p0y; + const double p2xSqd = p2x * p2x; + const double p2ySqd = p2y * p2y; + const double p1xSqd = p1x * p1x; + const double p1ySqd = p1y * p1y; + + const double p01xProd = p0x * p1x; + const double p02xProd = p0x * p2x; + const double b12xProd = p1x * p2x; + const double p01yProd = p0y * p1y; + const double p02yProd = p0y * p2y; + const double b12yProd = p1y * p2y; + + const double sqrtA = p0y - (2.0 * p1y) + p2y; + const double a = sqrtA * sqrtA; + const double h = -1.0 * (p0y - (2.0 * p1y) + p2y) * (p0x - (2.0 * p1x) + p2x); + const double sqrtB = p0x - (2.0 * p1x) + p2x; + const double b = sqrtB * sqrtB; + const double c = (p0xSqd * p2ySqd) - (4.0 * p01xProd * b12yProd) + - (2.0 * p02xProd * p02yProd) + (4.0 * p02xProd * p1ySqd) + + (4.0 * p1xSqd * p02yProd) - (4.0 * b12xProd * p01yProd) + + (p2xSqd * p0ySqd); + const double g = (p0x * p02yProd) - (2.0 * p0x * p1ySqd) + + (2.0 * p0x * b12yProd) - (p0x * p2ySqd) + + (2.0 * p1x * p01yProd) - (4.0 * p1x * p02yProd) + + (2.0 * p1x * b12yProd) - (p2x * p0ySqd) + + (2.0 * p2x * p01yProd) + (p2x * p02yProd) + - (2.0 * p2x * p1ySqd); + const double f = -((p0xSqd * p2y) - (2.0 * p01xProd * p1y) + - (2.0 * p01xProd * p2y) - (p02xProd * p0y) + + (4.0 * p02xProd * p1y) - (p02xProd * p2y) + + (2.0 * p1xSqd * p0y) + (2.0 * p1xSqd * p2y) + - (2.0 * b12xProd * p0y) - (2.0 * b12xProd * p1y) + + (p2xSqd * p0y)); + + const double cosTheta = sqrt(a / (a + b)); + const double sinTheta = -1.0 * sign_of((a + b) * h) * sqrt(b / (a + b)); + + const double gDef = cosTheta * g - sinTheta * f; + const double fDef = sinTheta * g + cosTheta * f; + + + const double x0 = gDef / (a + b); + const double y0 = (1.0 / (2.0 * fDef)) * (c - (gDef * gDef / (a + b))); + + + const double lambda = -1.0 * ((a + b) / (2.0 * fDef)); + fScalingFactor = fabs(1.0 / lambda); + fScalingFactorSqd = fScalingFactor * fScalingFactor; + + const double lambda_cosTheta = lambda * cosTheta; + const double lambda_sinTheta = lambda * sinTheta; + + fXformMatrix.setAffine( + lambda_cosTheta, -lambda_sinTheta, lambda * x0, + lambda_sinTheta, lambda_cosTheta, lambda * y0 + ); + } + + fNearlyZeroScaled = kNearlyZero / fScalingFactor; + fTangentTolScaledSqd = kTangentTolerance * kTangentTolerance / fScalingFactorSqd; + + fP0T = fXformMatrix.mapPoint(p0); + fP2T = fXformMatrix.mapPoint(p2); +} + +static void init_distances(DFData* data, int size) { + DFData* currData = data; + + for (int i = 0; i < size; ++i) { + // init distance to "far away" + currData->fDistSq = SK_DistanceFieldMagnitude * SK_DistanceFieldMagnitude; + currData->fDeltaWindingScore = 0; + ++currData; + } +} + +static inline void add_line_to_segment(const SkPoint pts[2], + PathSegmentArray* segments) { + segments->push_back(); + segments->back().fType = PathSegment::kLine; + segments->back().fPts[0] = pts[0]; + segments->back().fPts[1] = pts[1]; + + segments->back().init(); +} + +static inline void add_quad_segment(const SkPoint pts[3], + PathSegmentArray* segments) { + if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || + pts[1].distanceToSqd(pts[2]) < kCloseSqd || + is_colinear(pts)) { + if (pts[0] != pts[2]) { + SkPoint line_pts[2]; + line_pts[0] = pts[0]; + line_pts[1] = pts[2]; + add_line_to_segment(line_pts, segments); + } + } else { + segments->push_back(); + segments->back().fType = PathSegment::kQuad; + segments->back().fPts[0] = pts[0]; + segments->back().fPts[1] = pts[1]; + segments->back().fPts[2] = pts[2]; + + segments->back().init(); + } +} + +static inline void add_cubic_segments(const SkPoint pts[4], + PathSegmentArray* segments) { + SkSTArray<15, SkPoint, true> quads; + GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, &quads); + int count = quads.count(); + for (int q = 0; q < count; q += 3) { + add_quad_segment(&quads[q], segments); + } +} + +static float calculate_nearest_point_for_quad( + const PathSegment& segment, + const DPoint &xFormPt) { + static const float kThird = 0.33333333333f; + static const float kTwentySeventh = 0.037037037f; + + const float a = 0.5f - (float)xFormPt.y(); + const float b = -0.5f * (float)xFormPt.x(); + + const float a3 = a * a * a; + const float b2 = b * b; + + const float c = (b2 * 0.25f) + (a3 * kTwentySeventh); + + if (c >= 0.f) { + const float sqrtC = sqrt(c); + const float result = (float)cbrt((-b * 0.5f) + sqrtC) + (float)cbrt((-b * 0.5f) - sqrtC); + return result; + } else { + const float cosPhi = (float)sqrt((b2 * 0.25f) * (-27.f / a3)) * ((b > 0) ? -1.f : 1.f); + const float phi = (float)acos(cosPhi); + float result; + if (xFormPt.x() > 0.f) { + result = 2.f * (float)sqrt(-a * kThird) * (float)cos(phi * kThird); + if (!between_closed(result, segment.fP0T.x(), segment.fP2T.x())) { + result = 2.f * (float)sqrt(-a * kThird) * (float)cos((phi * kThird) + (SK_ScalarPI * 2.f * kThird)); + } + } else { + result = 2.f * (float)sqrt(-a * kThird) * (float)cos((phi * kThird) + (SK_ScalarPI * 2.f * kThird)); + if (!between_closed(result, segment.fP0T.x(), segment.fP2T.x())) { + result = 2.f * (float)sqrt(-a * kThird) * (float)cos(phi * kThird); + } + } + return result; + } +} + +// This structure contains some intermediate values shared by the same row. +// It is used to calculate segment side of a quadratic bezier. +struct RowData { + // The intersection type of a scanline and y = x * x parabola in canonical space. + enum IntersectionType { + kNoIntersection, + kVerticalLine, + kTangentLine, + kTwoPointsIntersect + } fIntersectionType; + + // The direction of the quadratic segment/scanline in the canonical space. + // 1: The quadratic segment/scanline going from negative x-axis to positive x-axis. + // 0: The scanline is a vertical line in the canonical space. + // -1: The quadratic segment/scanline going from positive x-axis to negative x-axis. + int fQuadXDirection; + int fScanlineXDirection; + + // The y-value(equal to x*x) of intersection point for the kVerticalLine intersection type. + double fYAtIntersection; + + // The x-value for two intersection points. + double fXAtIntersection1; + double fXAtIntersection2; +}; + +void precomputation_for_row( + RowData *rowData, + const PathSegment& segment, + const SkPoint& pointLeft, + const SkPoint& pointRight + ) { + if (segment.fType != PathSegment::kQuad) { + return; + } + + const DPoint& xFormPtLeft = segment.fXformMatrix.mapPoint(pointLeft); + const DPoint& xFormPtRight = segment.fXformMatrix.mapPoint(pointRight);; + + rowData->fQuadXDirection = (int)sign_of(segment.fP2T.x() - segment.fP0T.x()); + rowData->fScanlineXDirection = (int)sign_of(xFormPtRight.x() - xFormPtLeft.x()); + + const double x1 = xFormPtLeft.x(); + const double y1 = xFormPtLeft.y(); + const double x2 = xFormPtRight.x(); + const double y2 = xFormPtRight.y(); + + if (nearly_equal(x1, x2, segment.fNearlyZeroScaled, true)) { + rowData->fIntersectionType = RowData::kVerticalLine; + rowData->fYAtIntersection = x1 * x1; + rowData->fScanlineXDirection = 0; + return; + } + + // Line y = mx + b + const double m = (y2 - y1) / (x2 - x1); + const double b = -m * x1 + y1; + + const double m2 = m * m; + const double c = m2 + 4.0 * b; + + const double tol = 4.0 * segment.fTangentTolScaledSqd / (m2 + 1.0); + + // Check if the scanline is the tangent line of the curve, + // and the curve start or end at the same y-coordinate of the scanline + if ((rowData->fScanlineXDirection == 1 && + (segment.fPts[0].y() == pointLeft.y() || + segment.fPts[2].y() == pointLeft.y())) && + nearly_zero(c, tol)) { + rowData->fIntersectionType = RowData::kTangentLine; + rowData->fXAtIntersection1 = m / 2.0; + rowData->fXAtIntersection2 = m / 2.0; + } else if (c <= 0.0) { + rowData->fIntersectionType = RowData::kNoIntersection; + return; + } else { + rowData->fIntersectionType = RowData::kTwoPointsIntersect; + const double d = sqrt(c); + rowData->fXAtIntersection1 = (m + d) / 2.0; + rowData->fXAtIntersection2 = (m - d) / 2.0; + } +} + +SegSide calculate_side_of_quad( + const PathSegment& segment, + const SkPoint& point, + const DPoint& xFormPt, + const RowData& rowData) { + SegSide side = kNA_SegSide; + + if (RowData::kVerticalLine == rowData.fIntersectionType) { + side = (SegSide)(int)(sign_of(xFormPt.y() - rowData.fYAtIntersection) * rowData.fQuadXDirection); + } + else if (RowData::kTwoPointsIntersect == rowData.fIntersectionType) { + const double p1 = rowData.fXAtIntersection1; + const double p2 = rowData.fXAtIntersection2; + + int signP1 = (int)sign_of(p1 - xFormPt.x()); + bool includeP1 = true; + bool includeP2 = true; + + if (rowData.fScanlineXDirection == 1) { + if ((rowData.fQuadXDirection == -1 && segment.fPts[0].y() <= point.y() && + nearly_equal(segment.fP0T.x(), p1, segment.fNearlyZeroScaled, true)) || + (rowData.fQuadXDirection == 1 && segment.fPts[2].y() <= point.y() && + nearly_equal(segment.fP2T.x(), p1, segment.fNearlyZeroScaled, true))) { + includeP1 = false; + } + if ((rowData.fQuadXDirection == -1 && segment.fPts[2].y() <= point.y() && + nearly_equal(segment.fP2T.x(), p2, segment.fNearlyZeroScaled, true)) || + (rowData.fQuadXDirection == 1 && segment.fPts[0].y() <= point.y() && + nearly_equal(segment.fP0T.x(), p2, segment.fNearlyZeroScaled, true))) { + includeP2 = false; + } + } + + if (includeP1 && between_closed(p1, segment.fP0T.x(), segment.fP2T.x(), + segment.fNearlyZeroScaled, true)) { + side = (SegSide)(signP1 * rowData.fQuadXDirection); + } + if (includeP2 && between_closed(p2, segment.fP0T.x(), segment.fP2T.x(), + segment.fNearlyZeroScaled, true)) { + int signP2 = (int)sign_of(p2 - xFormPt.x()); + if (side == kNA_SegSide || signP2 == 1) { + side = (SegSide)(-signP2 * rowData.fQuadXDirection); + } + } + } else if (RowData::kTangentLine == rowData.fIntersectionType) { + // The scanline is the tangent line of current quadratic segment. + + const double p = rowData.fXAtIntersection1; + int signP = (int)sign_of(p - xFormPt.x()); + if (rowData.fScanlineXDirection == 1) { + // The path start or end at the tangent point. + if (segment.fPts[0].y() == point.y()) { + side = (SegSide)(signP); + } else if (segment.fPts[2].y() == point.y()) { + side = (SegSide)(-signP); + } + } + } + + return side; +} + +static float distance_to_segment(const SkPoint& point, + const PathSegment& segment, + const RowData& rowData, + SegSide* side) { + SkASSERT(side); + + const DPoint xformPt = segment.fXformMatrix.mapPoint(point); + + if (segment.fType == PathSegment::kLine) { + float result = SK_DistanceFieldPad * SK_DistanceFieldPad; + + if (between_closed(xformPt.x(), segment.fP0T.x(), segment.fP2T.x())) { + result = (float)(xformPt.y() * xformPt.y()); + } else if (xformPt.x() < segment.fP0T.x()) { + result = (float)(xformPt.x() * xformPt.x() + xformPt.y() * xformPt.y()); + } else { + result = (float)((xformPt.x() - segment.fP2T.x()) * (xformPt.x() - segment.fP2T.x()) + + xformPt.y() * xformPt.y()); + } + + if (between_closed_open(point.y(), segment.fBoundingBox.top(), + segment.fBoundingBox.bottom())) { + *side = (SegSide)(int)sign_of(xformPt.y()); + } else { + *side = kNA_SegSide; + } + return result; + } else { + SkASSERT(segment.fType == PathSegment::kQuad); + + const float nearestPoint = calculate_nearest_point_for_quad(segment, xformPt); + + float dist; + + if (between_closed(nearestPoint, segment.fP0T.x(), segment.fP2T.x())) { + DPoint x = DPoint::Make(nearestPoint, nearestPoint * nearestPoint); + dist = (float)xformPt.distanceToSqd(x); + } else { + const float distToB0T = (float)xformPt.distanceToSqd(segment.fP0T); + const float distToB2T = (float)xformPt.distanceToSqd(segment.fP2T); + + if (distToB0T < distToB2T) { + dist = distToB0T; + } else { + dist = distToB2T; + } + } + + if (between_closed_open(point.y(), segment.fBoundingBox.top(), + segment.fBoundingBox.bottom())) { + *side = calculate_side_of_quad(segment, point, xformPt, rowData); + } else { + *side = kNA_SegSide; + } + + return (float)(dist * segment.fScalingFactorSqd); + } +} + +static void calculate_distance_field_data(PathSegmentArray* segments, + DFData* dataPtr, + int width, int height) { + int count = segments->count(); + for (int a = 0; a < count; ++a) { + PathSegment& segment = (*segments)[a]; + const SkRect& segBB = segment.fBoundingBox.makeOutset( + SK_DistanceFieldPad, SK_DistanceFieldPad); + int startColumn = (int)segBB.left(); + int endColumn = SkScalarCeilToInt(segBB.right()); + + int startRow = (int)segBB.top(); + int endRow = SkScalarCeilToInt(segBB.bottom()); + + SkASSERT((startColumn >= 0) && "StartColumn < 0!"); + SkASSERT((endColumn <= width) && "endColumn > width!"); + SkASSERT((startRow >= 0) && "StartRow < 0!"); + SkASSERT((endRow <= height) && "EndRow > height!"); + + // Clip inside the distance field to avoid overflow + startColumn = SkTMax(startColumn, 0); + endColumn = SkTMin(endColumn, width); + startRow = SkTMax(startRow, 0); + endRow = SkTMin(endRow, height); + + for (int row = startRow; row < endRow; ++row) { + SegSide prevSide = kNA_SegSide; + const float pY = row + 0.5f; + RowData rowData; + + const SkPoint pointLeft = SkPoint::Make((SkScalar)startColumn, pY); + const SkPoint pointRight = SkPoint::Make((SkScalar)endColumn, pY); + + if (between_closed_open(pY, segment.fBoundingBox.top(), + segment.fBoundingBox.bottom())) { + precomputation_for_row(&rowData, segment, pointLeft, pointRight); + } + + for (int col = startColumn; col < endColumn; ++col) { + int idx = (row * width) + col; + + const float pX = col + 0.5f; + const SkPoint point = SkPoint::Make(pX, pY); + + const float distSq = dataPtr[idx].fDistSq; + int dilation = distSq < 1.5 * 1.5 ? 1 : + distSq < 2.5 * 2.5 ? 2 : + distSq < 3.5 * 3.5 ? 3 : SK_DistanceFieldPad; + if (dilation > SK_DistanceFieldPad) { + dilation = SK_DistanceFieldPad; + } + + // Optimisation for not calculating some points. + if (dilation != SK_DistanceFieldPad && !segment.fBoundingBox.roundOut() + .makeOutset(dilation, dilation).contains(col, row)) { + continue; + } + + SegSide side = kNA_SegSide; + int deltaWindingScore = 0; + float currDistSq = distance_to_segment(point, segment, rowData, &side); + if (prevSide == kLeft_SegSide && side == kRight_SegSide) { + deltaWindingScore = -1; + } else if (prevSide == kRight_SegSide && side == kLeft_SegSide) { + deltaWindingScore = 1; + } + + prevSide = side; + + if (currDistSq < distSq) { + dataPtr[idx].fDistSq = currDistSq; + } + + dataPtr[idx].fDeltaWindingScore += deltaWindingScore; + } + } + } +} + +template +static unsigned char pack_distance_field_val(float dist) { + // The distance field is constructed as unsigned char values, so that the zero value is at 128, + // Beside 128, we have 128 values in range [0, 128), but only 127 values in range (128, 255]. + // So we multiply distanceMagnitude by 127/128 at the latter range to avoid overflow. + dist = SkScalarPin(-dist, -distanceMagnitude, distanceMagnitude * 127.0f / 128.0f); + + // Scale into the positive range for unsigned distance. + dist += distanceMagnitude; + + // Scale into unsigned char range. + // Round to place negative and positive values as equally as possible around 128 + // (which represents zero). + return (unsigned char)SkScalarRoundToInt(dist / (2 * distanceMagnitude) * 256.0f); +} + +bool GrGenerateDistanceFieldFromPath(unsigned char* distanceField, + const SkPath& path, const SkMatrix& drawMatrix, + int width, int height, size_t rowBytes) { + SkASSERT(distanceField); + + SkDEBUGCODE(SkPath xformPath;); + SkDEBUGCODE(path.transform(drawMatrix, &xformPath)); + SkDEBUGCODE(SkIRect pathBounds = xformPath.getBounds().roundOut()); + SkDEBUGCODE(SkIRect expectPathBounds = SkIRect::MakeWH(width - 2 * SK_DistanceFieldPad, + height - 2 * SK_DistanceFieldPad)); + SkASSERT(expectPathBounds.isEmpty() || + expectPathBounds.contains(pathBounds.x(), pathBounds.y())); + SkASSERT(expectPathBounds.isEmpty() || pathBounds.isEmpty() || + expectPathBounds.contains(pathBounds)); + + SkPath simplifiedPath; + SkPath workingPath; + if (Simplify(path, &simplifiedPath)) { + workingPath = simplifiedPath; + } else { + workingPath = path; + } + + if (!IsDistanceFieldSupportedFillType(workingPath.getFillType())) { + return false; + } + + workingPath.transform(drawMatrix); + + SkDEBUGCODE(pathBounds = workingPath.getBounds().roundOut()); + SkASSERT(expectPathBounds.isEmpty() || + expectPathBounds.contains(pathBounds.x(), pathBounds.y())); + SkASSERT(expectPathBounds.isEmpty() || pathBounds.isEmpty() || + expectPathBounds.contains(pathBounds)); + + // translate path to offset (SK_DistanceFieldPad, SK_DistanceFieldPad) + SkMatrix dfMatrix; + dfMatrix.setTranslate(SK_DistanceFieldPad, SK_DistanceFieldPad); + workingPath.transform(dfMatrix); + + // create temp data + size_t dataSize = width * height * sizeof(DFData); + SkAutoSMalloc<1024> dfStorage(dataSize); + DFData* dataPtr = (DFData*) dfStorage.get(); + + // create initial distance data + init_distances(dataPtr, width * height); + + SkPath::Iter iter(workingPath, true); + SkSTArray<15, PathSegment, true> segments; + + for (;;) { + SkPoint pts[4]; + SkPath::Verb verb = iter.next(pts); + switch (verb) { + case SkPath::kMove_Verb: + break; + case SkPath::kLine_Verb: { + add_line_to_segment(pts, &segments); + break; + } + case SkPath::kQuad_Verb: + add_quad_segment(pts, &segments); + break; + case SkPath::kConic_Verb: { + SkScalar weight = iter.conicWeight(); + SkAutoConicToQuads converter; + const SkPoint* quadPts = converter.computeQuads(pts, weight, kConicTolerance); + for (int i = 0; i < converter.countQuads(); ++i) { + add_quad_segment(quadPts + 2*i, &segments); + } + break; + } + case SkPath::kCubic_Verb: { + add_cubic_segments(pts, &segments); + break; + }; + default: + break; + } + if (verb == SkPath::kDone_Verb) { + break; + } + } + + calculate_distance_field_data(&segments, dataPtr, width, height); + + for (int row = 0; row < height; ++row) { + int windingNumber = 0; // Winding number start from zero for each scanline + for (int col = 0; col < width; ++col) { + int idx = (row * width) + col; + windingNumber += dataPtr[idx].fDeltaWindingScore; + + enum DFSign { + kInside = -1, + kOutside = 1 + } dfSign; + + if (workingPath.getFillType() == SkPath::kWinding_FillType) { + dfSign = windingNumber ? kInside : kOutside; + } else if (workingPath.getFillType() == SkPath::kInverseWinding_FillType) { + dfSign = windingNumber ? kOutside : kInside; + } else if (workingPath.getFillType() == SkPath::kEvenOdd_FillType) { + dfSign = (windingNumber % 2) ? kInside : kOutside; + } else { + SkASSERT(workingPath.getFillType() == SkPath::kInverseEvenOdd_FillType); + dfSign = (windingNumber % 2) ? kOutside : kInside; + } + + // The winding number at the end of a scanline should be zero. + SkASSERT(((col != width - 1) || (windingNumber == 0)) && + "Winding number should be zero at the end of a scan line."); + // Fallback to use SkPath::contains to determine the sign of pixel in release build. + if (col == width - 1 && windingNumber != 0) { + for (int col = 0; col < width; ++col) { + int idx = (row * width) + col; + dfSign = workingPath.contains(col + 0.5, row + 0.5) ? kInside : kOutside; + const float miniDist = sqrt(dataPtr[idx].fDistSq); + const float dist = dfSign * miniDist; + + unsigned char pixelVal = pack_distance_field_val(dist); + + distanceField[(row * rowBytes) + col] = pixelVal; + } + continue; + } + + const float miniDist = sqrt(dataPtr[idx].fDistSq); + const float dist = dfSign * miniDist; + + unsigned char pixelVal = pack_distance_field_val(dist); + + distanceField[(row * rowBytes) + col] = pixelVal; + } + } + return true; +} diff --git a/gfx/skia/skia/src/gpu/GrDistanceFieldGenFromVector.h b/gfx/skia/skia/src/gpu/GrDistanceFieldGenFromVector.h new file mode 100644 index 000000000000..48a0784229c1 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrDistanceFieldGenFromVector.h @@ -0,0 +1,39 @@ +/* + * Copyright 2017 ARM Ltd. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDistanceFieldGenFromVector_DEFINED +#define GrDistanceFieldGenFromVector_DEFINED + +#include "SkPath.h" + +class SkMatrix; + +#ifndef SK_USE_LEGACY_DISTANCE_FIELDS + #define SK_USE_LEGACY_DISTANCE_FIELDS +#endif + +/** Given a vector path, generate the associated distance field. + + * @param distanceField The distance field to be generated. Should already be allocated + * by the client with the padding defined in "SkDistanceFieldGen.h". + * @param path The path we're using to generate the distance field. + * @param matrix Transformation matrix for path. + * @param width Width of the distance field. + * @param height Height of the distance field. + * @param rowBytes Size of each row in the distance field, in bytes. + */ +bool GrGenerateDistanceFieldFromPath(unsigned char* distanceField, + const SkPath& path, const SkMatrix& viewMatrix, + int width, int height, size_t rowBytes); + +inline bool IsDistanceFieldSupportedFillType(SkPath::FillType fFillType) +{ + return (SkPath::kEvenOdd_FillType == fFillType || + SkPath::kInverseEvenOdd_FillType == fFillType); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/GrDrawContext.cpp b/gfx/skia/skia/src/gpu/GrDrawContext.cpp deleted file mode 100644 index 42d6795903d1..000000000000 --- a/gfx/skia/skia/src/gpu/GrDrawContext.cpp +++ /dev/null @@ -1,1435 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrBatchTest.h" -#include "GrColor.h" -#include "GrDrawContext.h" -#include "GrDrawContextPriv.h" -#include "GrDrawingManager.h" -#include "GrFixedClip.h" -#include "GrGpuResourcePriv.h" -#include "GrOvalRenderer.h" -#include "GrPathRenderer.h" -#include "GrPipelineBuilder.h" -#include "GrRenderTarget.h" -#include "GrRenderTargetPriv.h" -#include "GrResourceProvider.h" -#include "SkSurfacePriv.h" - -#include "batches/GrBatch.h" -#include "batches/GrClearBatch.h" -#include "batches/GrDrawAtlasBatch.h" -#include "batches/GrDrawVerticesBatch.h" -#include "batches/GrRectBatchFactory.h" -#include "batches/GrNinePatch.h" // TODO Factory -#include "batches/GrRegionBatch.h" - -#include "effects/GrRRectEffect.h" - -#include "instanced/InstancedRendering.h" - -#include "text/GrAtlasTextContext.h" -#include "text/GrStencilAndCoverTextContext.h" - -#include "../private/GrAuditTrail.h" - -#include "SkGr.h" -#include "SkLatticeIter.h" -#include "SkMatrixPriv.h" - -#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fDrawingManager->getContext()) -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) -#define ASSERT_SINGLE_OWNER_PRIV \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fDrawContext->fSingleOwner);) -#define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; } -#define RETURN_IF_ABANDONED_PRIV if (fDrawContext->fDrawingManager->wasAbandoned()) { return; } -#define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; } -#define RETURN_FALSE_IF_ABANDONED_PRIV if (fDrawContext->fDrawingManager->wasAbandoned()) { return false; } -#define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; } - -using gr_instanced::InstancedRendering; - -class AutoCheckFlush { -public: - AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) { - SkASSERT(fDrawingManager); - } - ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); } - -private: - GrDrawingManager* fDrawingManager; -}; - -bool GrDrawContext::wasAbandoned() const { - return fDrawingManager->wasAbandoned(); -} - -// In MDB mode the reffing of the 'getLastDrawTarget' call's result allows in-progress -// drawTargets to be picked up and added to by drawContexts lower in the call -// stack. When this occurs with a closed drawTarget, a new one will be allocated -// when the drawContext attempts to use it (via getDrawTarget). -GrDrawContext::GrDrawContext(GrContext* context, - GrDrawingManager* drawingMgr, - sk_sp rt, - sk_sp colorSpace, - const SkSurfaceProps* surfaceProps, - GrAuditTrail* auditTrail, - GrSingleOwner* singleOwner) - : fDrawingManager(drawingMgr) - , fRenderTarget(std::move(rt)) - , fDrawTarget(SkSafeRef(fRenderTarget->getLastDrawTarget())) - , fContext(context) - , fInstancedPipelineInfo(fRenderTarget.get()) - , fColorSpace(std::move(colorSpace)) - , fColorXformFromSRGB(nullptr) - , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) - , fAuditTrail(auditTrail) -#ifdef SK_DEBUG - , fSingleOwner(singleOwner) -#endif -{ - if (fColorSpace) { - // sRGB sources are very common (SkColor, etc...), so we cache that gamut transformation - auto srgbColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); - fColorXformFromSRGB = GrColorSpaceXform::Make(srgbColorSpace.get(), fColorSpace.get()); - } - SkDEBUGCODE(this->validate();) -} - -#ifdef SK_DEBUG -void GrDrawContext::validate() const { - SkASSERT(fRenderTarget); - ASSERT_OWNED_RESOURCE(fRenderTarget); - - if (fDrawTarget && !fDrawTarget->isClosed()) { - SkASSERT(fRenderTarget->getLastDrawTarget() == fDrawTarget); - } -} -#endif - -GrDrawContext::~GrDrawContext() { - ASSERT_SINGLE_OWNER - SkSafeUnref(fDrawTarget); -} - -GrDrawTarget* GrDrawContext::getDrawTarget() { - ASSERT_SINGLE_OWNER - SkDEBUGCODE(this->validate();) - - if (!fDrawTarget || fDrawTarget->isClosed()) { - fDrawTarget = fDrawingManager->newDrawTarget(fRenderTarget.get()); - } - - return fDrawTarget; -} - -bool GrDrawContext::copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { - ASSERT_SINGLE_OWNER - RETURN_FALSE_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::copySurface"); - - return this->getDrawTarget()->copySurface(fRenderTarget.get(), src, srcRect, dstPoint); -} - -void GrDrawContext::drawText(const GrClip& clip, const GrPaint& grPaint, - const SkPaint& skPaint, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkIRect& clipBounds) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawText"); - - GrAtlasTextContext* atlasTextContext = fDrawingManager->getAtlasTextContext(); - atlasTextContext->drawText(fContext, this, clip, grPaint, skPaint, viewMatrix, fSurfaceProps, - text, byteLength, x, y, clipBounds); -} - -void GrDrawContext::drawPosText(const GrClip& clip, const GrPaint& grPaint, - const SkPaint& skPaint, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkIRect& clipBounds) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPosText"); - - GrAtlasTextContext* atlasTextContext = fDrawingManager->getAtlasTextContext(); - atlasTextContext->drawPosText(fContext, this, clip, grPaint, skPaint, viewMatrix, - fSurfaceProps, text, byteLength, pos, scalarsPerPosition, - offset, clipBounds); - -} - -void GrDrawContext::drawTextBlob(const GrClip& clip, const SkPaint& skPaint, - const SkMatrix& viewMatrix, const SkTextBlob* blob, - SkScalar x, SkScalar y, - SkDrawFilter* filter, const SkIRect& clipBounds) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawTextBlob"); - - GrAtlasTextContext* atlasTextContext = fDrawingManager->getAtlasTextContext(); - atlasTextContext->drawTextBlob(fContext, this, clip, skPaint, viewMatrix, fSurfaceProps, blob, - x, y, filter, clipBounds); -} - -void GrDrawContext::discard() { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::discard"); - - AutoCheckFlush acf(fDrawingManager); - this->getDrawTarget()->discard(fRenderTarget.get()); -} - -void GrDrawContext::clear(const SkIRect* rect, - const GrColor color, - bool canIgnoreRect) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::clear"); - - AutoCheckFlush acf(fDrawingManager); - this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color, canIgnoreRect); -} - -void GrDrawContextPriv::clear(const GrFixedClip& clip, - const GrColor color, - bool canIgnoreClip) { - ASSERT_SINGLE_OWNER_PRIV - RETURN_IF_ABANDONED_PRIV - SkDEBUGCODE(fDrawContext->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContextPriv::clear"); - - AutoCheckFlush acf(fDrawContext->fDrawingManager); - fDrawContext->internalClear(clip, color, canIgnoreClip); -} - -void GrDrawContext::internalClear(const GrFixedClip& clip, - const GrColor color, - bool canIgnoreClip) { - bool isFull = false; - if (!clip.hasWindowRectangles()) { - isFull = !clip.scissorEnabled() || - (canIgnoreClip && fContext->caps()->fullClearIsFree()) || - clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height())); - } - - if (fContext->caps()->useDrawInsteadOfClear()) { - // This works around a driver bug with clear by drawing a rect instead. - // The driver will ignore a clear if it is the only thing rendered to a - // target before the target is read. - SkRect clearRect = SkRect::MakeIWH(this->width(), this->height()); - if (isFull) { - this->discard(); - } else if (!clearRect.intersect(SkRect::Make(clip.scissorRect()))) { - return; - } - - GrPaint paint; - paint.setColor4f(GrColor4f::FromGrColor(color)); - paint.setXPFactory(GrPorterDuffXPFactory::Make(SkXfermode::Mode::kSrc_Mode)); - - this->drawRect(clip, paint, SkMatrix::I(), clearRect); - } else if (isFull) { - this->getDrawTarget()->fullClear(this->accessRenderTarget(), color); - } else { - sk_sp batch(GrClearBatch::Make(clip, color, this->accessRenderTarget())); - if (!batch) { - return; - } - this->getDrawTarget()->addBatch(std::move(batch)); - } -} - -void GrDrawContext::drawPaint(const GrClip& clip, - const GrPaint& origPaint, - const SkMatrix& viewMatrix) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPaint"); - - // set rect to be big enough to fill the space, but not super-huge, so we - // don't overflow fixed-point implementations - - SkRect r = fRenderTarget->getBoundsRect(); - SkTCopyOnFirstWrite paint(origPaint); - - SkRRect rrect; - bool aaRRect; - // Check if we can replace a clipRRect()/drawPaint() with a drawRRect(). We only do the - // transformation for non-rect rrects. Rects caused a performance regression on an Android - // test that needs investigation. We also skip cases where there are fragment processors - // because they may depend on having correct local coords and this path draws in device space - // without a local matrix. - if (!paint->numTotalFragmentProcessors() && - clip.isRRect(r, &rrect, &aaRRect) && !rrect.isRect()) { - paint.writable()->setAntiAlias(aaRRect); - this->drawRRect(GrNoClip(), *paint, SkMatrix::I(), rrect, GrStyle::SimpleFill()); - return; - } - - // by definition this fills the entire clip, no need for AA - if (paint->isAntiAlias()) { - paint.writable()->setAntiAlias(false); - } - - bool isPerspective = viewMatrix.hasPerspective(); - - // We attempt to map r by the inverse matrix and draw that. mapRect will - // map the four corners and bound them with a new rect. This will not - // produce a correct result for some perspective matrices. - if (!isPerspective) { - if (!SkMatrixPriv::InverseMapRect(viewMatrix, &r, r)) { - SkDebugf("Could not invert matrix\n"); - return; - } - this->drawRect(clip, *paint, viewMatrix, r); - } else { - SkMatrix localMatrix; - if (!viewMatrix.invert(&localMatrix)) { - SkDebugf("Could not invert matrix\n"); - return; - } - - AutoCheckFlush acf(fDrawingManager); - - this->drawNonAAFilledRect(clip, *paint, SkMatrix::I(), r, nullptr, &localMatrix, nullptr, - false /* useHWAA */); - } -} - -static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) { - return point.fX >= rect.fLeft && point.fX <= rect.fRight && - point.fY >= rect.fTop && point.fY <= rect.fBottom; -} - -static bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) { - return viewMatrix.preservesRightAngles(); -} - -static bool should_apply_coverage_aa(const GrPaint& paint, GrRenderTarget* rt, - bool* useHWAA = nullptr) { - if (!paint.isAntiAlias()) { - if (useHWAA) { - *useHWAA = false; - } - return false; - } else { - if (useHWAA) { - *useHWAA = rt->isUnifiedMultisampled(); - } - return !rt->isUnifiedMultisampled(); - } -} - -// Attempts to crop a rect and optional local rect to the clip boundaries. -// Returns false if the draw can be skipped entirely. -static bool crop_filled_rect(int width, int height, const GrClip& clip, - const SkMatrix& viewMatrix, SkRect* rect, - SkRect* localRect = nullptr) { - if (!viewMatrix.rectStaysRect()) { - return true; - } - - SkIRect clipDevBounds; - SkRect clipBounds; - - clip.getConservativeBounds(width, height, &clipDevBounds); - if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) { - return false; - } - - if (localRect) { - if (!rect->intersects(clipBounds)) { - return false; - } - const SkScalar dx = localRect->width() / rect->width(); - const SkScalar dy = localRect->height() / rect->height(); - if (clipBounds.fLeft > rect->fLeft) { - localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx; - rect->fLeft = clipBounds.fLeft; - } - if (clipBounds.fTop > rect->fTop) { - localRect->fTop += (clipBounds.fTop - rect->fTop) * dy; - rect->fTop = clipBounds.fTop; - } - if (clipBounds.fRight < rect->fRight) { - localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx; - rect->fRight = clipBounds.fRight; - } - if (clipBounds.fBottom < rect->fBottom) { - localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy; - rect->fBottom = clipBounds.fBottom; - } - return true; - } - - return rect->intersect(clipBounds); -} - -bool GrDrawContext::drawFilledRect(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& rect, - const GrUserStencilSettings* ss) { - SkRect croppedRect = rect; - if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) { - return true; - } - - SkAutoTUnref batch; - bool useHWAA; - - if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) { - InstancedRendering* ir = this->getDrawTarget()->instancedRendering(); - batch.reset(ir->recordRect(croppedRect, viewMatrix, paint.getColor(), - paint.isAntiAlias(), fInstancedPipelineInfo, - &useHWAA)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - if (ss) { - pipelineBuilder.setUserStencil(ss); - } - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return true; - } - } - - if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) { - // The fill path can handle rotation but not skew. - if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) { - SkRect devBoundRect; - viewMatrix.mapRect(&devBoundRect, croppedRect); - - batch.reset(GrRectBatchFactory::CreateAAFill(paint, viewMatrix, rect, croppedRect, - devBoundRect)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - if (ss) { - pipelineBuilder.setUserStencil(ss); - } - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return true; - } - } - } else { - this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, nullptr, nullptr, ss, - useHWAA); - return true; - } - - return false; -} - -void GrDrawContext::drawRect(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& rect, - const GrStyle* style) { - if (!style) { - style = &GrStyle::SimpleFill(); - } - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRect"); - - // Path effects should've been devolved to a path in SkGpuDevice - SkASSERT(!style->pathEffect()); - - AutoCheckFlush acf(fDrawingManager); - - const SkStrokeRec& stroke = style->strokeRec(); - if (stroke.getStyle() == SkStrokeRec::kFill_Style) { - - if (!fContext->caps()->useDrawInsteadOfClear()) { - // Check if this is a full RT draw and can be replaced with a clear. We don't bother - // checking cases where the RT is fully inside a stroke. - SkRect rtRect = fRenderTarget->getBoundsRect(); - // Does the clip contain the entire RT? - if (clip.quickContains(rtRect)) { - SkMatrix invM; - if (!viewMatrix.invert(&invM)) { - return; - } - // Does the rect bound the RT? - SkPoint srcSpaceRTQuad[4]; - invM.mapRectToQuad(srcSpaceRTQuad, rtRect); - if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) && - rect_contains_inclusive(rect, srcSpaceRTQuad[1]) && - rect_contains_inclusive(rect, srcSpaceRTQuad[2]) && - rect_contains_inclusive(rect, srcSpaceRTQuad[3])) { - // Will it blend? - GrColor clearColor; - if (paint.isConstantBlendedColor(&clearColor)) { - this->clear(nullptr, clearColor, true); - return; - } - } - } - } - - if (this->drawFilledRect(clip, paint, viewMatrix, rect, nullptr)) { - return; - } - } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style || - stroke.getStyle() == SkStrokeRec::kHairline_Style) { - if ((!rect.width() || !rect.height()) && - SkStrokeRec::kHairline_Style != stroke.getStyle()) { - SkScalar r = stroke.getWidth() / 2; - // TODO: Move these stroke->fill fallbacks to GrShape? - switch (stroke.getJoin()) { - case SkPaint::kMiter_Join: - this->drawRect(clip, paint, viewMatrix, - {rect.fLeft - r, rect.fTop - r, - rect.fRight + r, rect.fBottom + r}, - &GrStyle::SimpleFill()); - return; - case SkPaint::kRound_Join: - // Raster draws nothing when both dimensions are empty. - if (rect.width() || rect.height()){ - SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r); - this->drawRRect(clip, paint, viewMatrix, rrect, GrStyle::SimpleFill()); - return; - } - case SkPaint::kBevel_Join: - if (!rect.width()) { - this->drawRect(clip, paint, viewMatrix, - {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom}, - &GrStyle::SimpleFill()); - } else { - this->drawRect(clip, paint, viewMatrix, - {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r}, - &GrStyle::SimpleFill()); - } - return; - } - } - - bool useHWAA; - bool snapToPixelCenters = false; - SkAutoTUnref batch; - - GrColor color = paint.getColor(); - if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) { - // The stroke path needs the rect to remain axis aligned (no rotation or skew). - if (viewMatrix.rectStaysRect()) { - batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, stroke)); - } - } else { - // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of - // hairline rects. We jam all the vertices to pixel centers to avoid this, but not - // when MSAA is enabled because it can cause ugly artifacts. - snapToPixelCenters = stroke.getStyle() == SkStrokeRec::kHairline_Style && - !fRenderTarget->isUnifiedMultisampled(); - batch.reset(GrRectBatchFactory::CreateNonAAStroke(color, viewMatrix, rect, - stroke, snapToPixelCenters)); - } - - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - - if (snapToPixelCenters) { - pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag, - snapToPixelCenters); - } - - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return; - } - } - - SkPath path; - path.setIsVolatile(true); - path.addRect(rect); - this->internalDrawPath(clip, paint, viewMatrix, path, *style); -} - -void GrDrawContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) { - ASSERT_SINGLE_OWNER_PRIV - RETURN_IF_ABANDONED_PRIV - SkDEBUGCODE(fDrawContext->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContextPriv::clearStencilClip"); - - AutoCheckFlush acf(fDrawContext->fDrawingManager); - fDrawContext->getDrawTarget()->clearStencilClip(clip, insideStencilMask, - fDrawContext->accessRenderTarget()); -} - -void GrDrawContextPriv::stencilPath(const GrClip& clip, - bool useHWAA, - const SkMatrix& viewMatrix, - const GrPath* path) { - fDrawContext->getDrawTarget()->stencilPath(fDrawContext, clip, useHWAA, viewMatrix, path); -} - -void GrDrawContextPriv::stencilRect(const GrClip& clip, - const GrUserStencilSettings* ss, - bool useHWAA, - const SkMatrix& viewMatrix, - const SkRect& rect) { - ASSERT_SINGLE_OWNER_PRIV - RETURN_IF_ABANDONED_PRIV - SkDEBUGCODE(fDrawContext->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContext::stencilRect"); - - AutoCheckFlush acf(fDrawContext->fDrawingManager); - - GrPaint paint; - paint.setAntiAlias(useHWAA); - paint.setXPFactory(GrDisableColorXPFactory::Make()); - - fDrawContext->drawNonAAFilledRect(clip, paint, viewMatrix, rect, nullptr, nullptr, ss, useHWAA); -} - -bool GrDrawContextPriv::drawAndStencilRect(const GrClip& clip, - const GrUserStencilSettings* ss, - SkRegion::Op op, - bool invert, - bool doAA, - const SkMatrix& viewMatrix, - const SkRect& rect) { - ASSERT_SINGLE_OWNER_PRIV - RETURN_FALSE_IF_ABANDONED_PRIV - SkDEBUGCODE(fDrawContext->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContext::drawAndStencilRect"); - - AutoCheckFlush acf(fDrawContext->fDrawingManager); - - GrPaint paint; - paint.setAntiAlias(doAA); - paint.setCoverageSetOpXPFactory(op, invert); - - if (fDrawContext->drawFilledRect(clip, paint, viewMatrix, rect, ss)) { - return true; - } - - SkPath path; - path.setIsVolatile(true); - path.addRect(rect); - return this->drawAndStencilPath(clip, ss, op, invert, doAA, viewMatrix, path); -} - -void GrDrawContext::fillRectToRect(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& rectToDraw, - const SkRect& localRect) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectToRect"); - - SkRect croppedRect = rectToDraw; - SkRect croppedLocalRect = localRect; - if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, - &croppedRect, &croppedLocalRect)) { - return; - } - - AutoCheckFlush acf(fDrawingManager); - bool useHWAA; - - if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) { - InstancedRendering* ir = this->getDrawTarget()->instancedRendering(); - SkAutoTUnref batch(ir->recordRect(croppedRect, viewMatrix, paint.getColor(), - croppedLocalRect, paint.isAntiAlias(), - fInstancedPipelineInfo, &useHWAA)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return; - } - } - - if (!should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) { - this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, &croppedLocalRect, - nullptr, nullptr, useHWAA); - return; - } - - if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) { - SkAutoTUnref batch(GrAAFillRectBatch::CreateWithLocalRect(paint.getColor(), - viewMatrix, - croppedRect, - croppedLocalRect)); - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->drawBatch(pipelineBuilder, clip, batch); - return; - } - - SkMatrix viewAndUnLocalMatrix; - if (!viewAndUnLocalMatrix.setRectToRect(localRect, rectToDraw, SkMatrix::kFill_ScaleToFit)) { - SkDebugf("fillRectToRect called with empty local matrix.\n"); - return; - } - viewAndUnLocalMatrix.postConcat(viewMatrix); - - SkPath path; - path.setIsVolatile(true); - path.addRect(localRect); - this->internalDrawPath(clip, paint, viewAndUnLocalMatrix, path, GrStyle()); -} - -void GrDrawContext::fillRectWithLocalMatrix(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& rectToDraw, - const SkMatrix& localMatrix) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectWithLocalMatrix"); - - SkRect croppedRect = rectToDraw; - if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) { - return; - } - - AutoCheckFlush acf(fDrawingManager); - bool useHWAA; - - if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) { - InstancedRendering* ir = this->getDrawTarget()->instancedRendering(); - SkAutoTUnref batch(ir->recordRect(croppedRect, viewMatrix, paint.getColor(), - localMatrix, paint.isAntiAlias(), - fInstancedPipelineInfo, &useHWAA)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return; - } - } - - if (!should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) { - this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, nullptr, - &localMatrix, nullptr, useHWAA); - return; - } - - if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) { - SkAutoTUnref batch(GrAAFillRectBatch::Create(paint.getColor(), viewMatrix, - localMatrix, croppedRect)); - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return; - } - - SkMatrix viewAndUnLocalMatrix; - if (!localMatrix.invert(&viewAndUnLocalMatrix)) { - SkDebugf("fillRectWithLocalMatrix called with degenerate local matrix.\n"); - return; - } - viewAndUnLocalMatrix.postConcat(viewMatrix); - - SkPath path; - path.setIsVolatile(true); - path.addRect(rectToDraw); - path.transform(localMatrix); - this->internalDrawPath(clip, paint, viewAndUnLocalMatrix, path, GrStyle()); -} - -void GrDrawContext::drawVertices(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - GrPrimitiveType primitiveType, - int vertexCount, - const SkPoint positions[], - const SkPoint texCoords[], - const GrColor colors[], - const uint16_t indices[], - int indexCount) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawVertices"); - - AutoCheckFlush acf(fDrawingManager); - - // TODO clients should give us bounds - SkRect bounds; - if (!bounds.setBoundsCheck(positions, vertexCount)) { - SkDebugf("drawVertices call empty bounds\n"); - return; - } - - viewMatrix.mapRect(&bounds); - - SkAutoTUnref batch(new GrDrawVerticesBatch(paint.getColor(), - primitiveType, viewMatrix, positions, - vertexCount, indices, indexCount, - colors, texCoords, bounds)); - - GrPipelineBuilder pipelineBuilder(paint, this->mustUseHWAA(paint)); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); -} - -/////////////////////////////////////////////////////////////////////////////// - -void GrDrawContext::drawAtlas(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - int spriteCount, - const SkRSXform xform[], - const SkRect texRect[], - const SkColor colors[]) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawAtlas"); - - AutoCheckFlush acf(fDrawingManager); - - SkAutoTUnref batch(new GrDrawAtlasBatch(paint.getColor(), viewMatrix, spriteCount, - xform, texRect, colors)); - - GrPipelineBuilder pipelineBuilder(paint, this->mustUseHWAA(paint)); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); -} - -/////////////////////////////////////////////////////////////////////////////// - -void GrDrawContext::drawRRect(const GrClip& origClip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRRect& rrect, - const GrStyle& style) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRRect"); - if (rrect.isEmpty()) { - return; - } - - GrNoClip noclip; - const GrClip* clip = &origClip; -#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK - // The Android framework frequently clips rrects to themselves where the clip is non-aa and the - // draw is aa. Since our lower level clip code works from batch bounds, which are SkRects, it - // doesn't detect that the clip can be ignored (modulo antialiasing). The following test - // attempts to mitigate the stencil clip cost but will only help when the entire clip stack - // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. - SkRRect devRRect; - if (rrect.transform(viewMatrix, &devRRect) && clip->quickContains(devRRect)) { - clip = &noclip; - } -#endif - SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice - - AutoCheckFlush acf(fDrawingManager); - const SkStrokeRec stroke = style.strokeRec(); - bool useHWAA; - - if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() && - stroke.isFillStyle()) { - InstancedRendering* ir = this->getDrawTarget()->instancedRendering(); - SkAutoTUnref batch(ir->recordRRect(rrect, viewMatrix, paint.getColor(), - paint.isAntiAlias(), fInstancedPipelineInfo, - &useHWAA)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, *clip, batch); - return; - } - } - - if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) { - GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); - SkAutoTUnref batch(GrOvalRenderer::CreateRRectBatch(paint.getColor(), - viewMatrix, - rrect, - stroke, - shaderCaps)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, *clip, batch); - return; - } - } - - SkPath path; - path.setIsVolatile(true); - path.addRRect(rrect); - this->internalDrawPath(*clip, paint, viewMatrix, path, style); -} - -bool GrDrawContext::drawFilledDRRect(const GrClip& clip, - const GrPaint& paintIn, - const SkMatrix& viewMatrix, - const SkRRect& origOuter, - const SkRRect& origInner) { - SkASSERT(!origInner.isEmpty()); - SkASSERT(!origOuter.isEmpty()); - - if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) { - bool useHWAA; - InstancedRendering* ir = this->getDrawTarget()->instancedRendering(); - SkAutoTUnref batch(ir->recordDRRect(origOuter, origInner, viewMatrix, - paintIn.getColor(), paintIn.isAntiAlias(), - fInstancedPipelineInfo, &useHWAA)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paintIn, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return true; - } - } - - bool applyAA = paintIn.isAntiAlias() && !fRenderTarget->isUnifiedMultisampled(); - - GrPrimitiveEdgeType innerEdgeType = applyAA ? kInverseFillAA_GrProcessorEdgeType : - kInverseFillBW_GrProcessorEdgeType; - GrPrimitiveEdgeType outerEdgeType = applyAA ? kFillAA_GrProcessorEdgeType : - kFillBW_GrProcessorEdgeType; - - SkTCopyOnFirstWrite inner(origInner), outer(origOuter); - SkMatrix inverseVM; - if (!viewMatrix.isIdentity()) { - if (!origInner.transform(viewMatrix, inner.writable())) { - return false; - } - if (!origOuter.transform(viewMatrix, outer.writable())) { - return false; - } - if (!viewMatrix.invert(&inverseVM)) { - return false; - } - } else { - inverseVM.reset(); - } - - GrPaint grPaint(paintIn); - grPaint.setAntiAlias(false); - - // TODO these need to be a geometry processors - sk_sp innerEffect(GrRRectEffect::Make(innerEdgeType, *inner)); - if (!innerEffect) { - return false; - } - - sk_sp outerEffect(GrRRectEffect::Make(outerEdgeType, *outer)); - if (!outerEffect) { - return false; - } - - grPaint.addCoverageFragmentProcessor(std::move(innerEffect)); - grPaint.addCoverageFragmentProcessor(std::move(outerEffect)); - - SkRect bounds = outer->getBounds(); - if (applyAA) { - bounds.outset(SK_ScalarHalf, SK_ScalarHalf); - } - - this->fillRectWithLocalMatrix(clip, grPaint, SkMatrix::I(), bounds, inverseVM); - return true; -} - -void GrDrawContext::drawDRRect(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRRect& outer, - const SkRRect& inner) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawDRRect"); - - SkASSERT(!outer.isEmpty()); - SkASSERT(!inner.isEmpty()); - - AutoCheckFlush acf(fDrawingManager); - - if (this->drawFilledDRRect(clip, paint, viewMatrix, outer, inner)) { - return; - } - - SkPath path; - path.setIsVolatile(true); - path.addRRect(inner); - path.addRRect(outer); - path.setFillType(SkPath::kEvenOdd_FillType); - - this->internalDrawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill()); -} - -/////////////////////////////////////////////////////////////////////////////// - -static inline bool is_int(float x) { - return x == (float) sk_float_round2int(x); -} - -void GrDrawContext::drawRegion(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRegion& region, - const GrStyle& style) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRegion"); - - bool isNonTranslate = SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)); - bool complexStyle = !style.isSimpleFill(); - bool antiAlias = paint.isAntiAlias() && (!is_int(viewMatrix.getTranslateX()) || - !is_int(viewMatrix.getTranslateY())); - if (isNonTranslate || complexStyle || antiAlias) { - SkPath path; - region.getBoundaryPath(&path); - return this->drawPath(clip, paint, viewMatrix, path, style); - } - - SkAutoTUnref batch(GrRegionBatch::Create(paint.getColor(), viewMatrix, region)); - GrPipelineBuilder pipelineBuilder(paint, false); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); -} - -void GrDrawContext::drawOval(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& oval, - const GrStyle& style) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawOval"); - - if (oval.isEmpty()) { - return; - } - - SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice - - AutoCheckFlush acf(fDrawingManager); - const SkStrokeRec& stroke = style.strokeRec(); - bool useHWAA; - - if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() && - stroke.isFillStyle()) { - InstancedRendering* ir = this->getDrawTarget()->instancedRendering(); - SkAutoTUnref batch(ir->recordOval(oval, viewMatrix, paint.getColor(), - paint.isAntiAlias(), fInstancedPipelineInfo, - &useHWAA)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return; - } - } - - if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) { - GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); - SkAutoTUnref batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(), - viewMatrix, - oval, - stroke, - shaderCaps)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return; - } - } - - SkPath path; - path.setIsVolatile(true); - path.addOval(oval); - this->internalDrawPath(clip, paint, viewMatrix, path, style); -} - -void GrDrawContext::drawArc(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& oval, - SkScalar startAngle, - SkScalar sweepAngle, - bool useCenter, - const GrStyle& style) { - bool useHWAA; - if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) { - GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); - SkAutoTUnref batch(GrOvalRenderer::CreateArcBatch(paint.getColor(), - viewMatrix, - oval, - startAngle, - sweepAngle, - useCenter, - style, - shaderCaps)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return; - } - } - SkPath path; - SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter, - style.isSimpleFill()); - this->internalDrawPath(clip, paint, viewMatrix, path, style); - return; -} - -void GrDrawContext::drawImageLattice(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - int imageWidth, - int imageHeight, - std::unique_ptr iter, - const SkRect& dst) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawImageLattice"); - - AutoCheckFlush acf(fDrawingManager); - - SkAutoTUnref batch(GrNinePatch::CreateNonAA(paint.getColor(), viewMatrix, - imageWidth, imageHeight, - std::move(iter), dst)); - - GrPipelineBuilder pipelineBuilder(paint, this->mustUseHWAA(paint)); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); -} - -void GrDrawContext::prepareForExternalIO() { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::prepareForExternalIO"); - - ASSERT_OWNED_RESOURCE(fRenderTarget); - - fDrawingManager->prepareSurfaceForExternalIO(fRenderTarget.get()); -} - -void GrDrawContext::drawNonAAFilledRect(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect* localRect, - const SkMatrix* localMatrix, - const GrUserStencilSettings* ss, - bool useHWAA) { - SkASSERT(!useHWAA || this->isStencilBufferMultisampled()); - SkAutoTUnref batch( - GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rect, localRect, - localMatrix)); - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - if (ss) { - pipelineBuilder.setUserStencil(ss); - } - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); -} - -bool GrDrawContext::readPixels(const SkImageInfo& dstInfo, void* dstBuffer, size_t dstRowBytes, - int x, int y) { - // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels - GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo, *fContext->caps()); - if (kUnknown_GrPixelConfig == config) { - return false; - } - - uint32_t flags = 0; - if (kUnpremul_SkAlphaType == dstInfo.alphaType()) { - flags = GrContext::kUnpremul_PixelOpsFlag; - } - - return fRenderTarget->readPixels(x, y, dstInfo.width(), dstInfo.height(), - config, dstBuffer, dstRowBytes, flags); -} - -bool GrDrawContext::writePixels(const SkImageInfo& srcInfo, const void* srcBuffer, - size_t srcRowBytes, int x, int y) { - // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels - GrPixelConfig config = SkImageInfo2GrPixelConfig(srcInfo, *fContext->caps()); - if (kUnknown_GrPixelConfig == config) { - return false; - } - uint32_t flags = 0; - if (kUnpremul_SkAlphaType == srcInfo.alphaType()) { - flags = GrContext::kUnpremul_PixelOpsFlag; - } - - return fRenderTarget->writePixels(x, y, srcInfo.width(), srcInfo.height(), - config, srcBuffer, srcRowBytes, flags); -} - -// Can 'path' be drawn as a pair of filled nested rectangles? -static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) { - - if (path.isInverseFillType()) { - return false; - } - - // TODO: this restriction could be lifted if we were willing to apply - // the matrix to all the points individually rather than just to the rect - if (!viewMatrix.rectStaysRect()) { - return false; - } - - SkPath::Direction dirs[2]; - if (!path.isNestedFillRects(rects, dirs)) { - return false; - } - - if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) { - // The two rects need to be wound opposite to each other - return false; - } - - // Right now, nested rects where the margin is not the same width - // all around do not render correctly - const SkScalar* outer = rects[0].asScalars(); - const SkScalar* inner = rects[1].asScalars(); - - bool allEq = true; - - SkScalar margin = SkScalarAbs(outer[0] - inner[0]); - bool allGoE1 = margin >= SK_Scalar1; - - for (int i = 1; i < 4; ++i) { - SkScalar temp = SkScalarAbs(outer[i] - inner[i]); - if (temp < SK_Scalar1) { - allGoE1 = false; - } - if (!SkScalarNearlyEqual(margin, temp)) { - allEq = false; - } - } - - return allEq || allGoE1; -} - -void GrDrawContext::drawPath(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkPath& path, - const GrStyle& style) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPath"); - - if (path.isEmpty()) { - if (path.isInverseFillType()) { - this->drawPaint(clip, paint, viewMatrix); - } - return; - } - - AutoCheckFlush acf(fDrawingManager); - - bool useHWAA; - if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA) && !style.pathEffect()) { - if (style.isSimpleFill() && !path.isConvex()) { - // Concave AA paths are expensive - try to avoid them for special cases - SkRect rects[2]; - - if (fills_as_nested_rects(viewMatrix, path, rects)) { - SkAutoTUnref batch(GrRectBatchFactory::CreateAAFillNestedRects( - paint.getColor(), viewMatrix, rects)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - } - return; - } - } - SkRect ovalRect; - bool isOval = path.isOval(&ovalRect); - - if (isOval && !path.isInverseFillType()) { - GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); - SkAutoTUnref batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(), - viewMatrix, - ovalRect, - style.strokeRec(), - shaderCaps)); - if (batch) { - GrPipelineBuilder pipelineBuilder(paint, useHWAA); - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); - return; - } - } - } - - // Note that internalDrawPath may sw-rasterize the path into a scratch texture. - // Scratch textures can be recycled after they are returned to the texture - // cache. This presents a potential hazard for buffered drawing. However, - // the writePixels that uploads to the scratch will perform a flush so we're - // OK. - this->internalDrawPath(clip, paint, viewMatrix, path, style); -} - -bool GrDrawContextPriv::drawAndStencilPath(const GrClip& clip, - const GrUserStencilSettings* ss, - SkRegion::Op op, - bool invert, - bool doAA, - const SkMatrix& viewMatrix, - const SkPath& path) { - ASSERT_SINGLE_OWNER_PRIV - RETURN_FALSE_IF_ABANDONED_PRIV - SkDEBUGCODE(fDrawContext->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContext::drawPath"); - - if (path.isEmpty() && path.isInverseFillType()) { - this->drawAndStencilRect(clip, ss, op, invert, false, SkMatrix::I(), - SkRect::MakeIWH(fDrawContext->width(), - fDrawContext->height())); - return true; - } - - AutoCheckFlush acf(fDrawContext->fDrawingManager); - - // An Assumption here is that path renderer would use some form of tweaking - // the src color (either the input alpha or in the frag shader) to implement - // aa. If we have some future driver-mojo path AA that can do the right - // thing WRT to the blend then we'll need some query on the PR. - bool useCoverageAA = doAA && !fDrawContext->isUnifiedMultisampled(); - bool hasUserStencilSettings = !ss->isUnused(); - bool isStencilBufferMSAA = fDrawContext->isStencilBufferMultisampled(); - - const GrPathRendererChain::DrawType type = - useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType - : GrPathRendererChain::kColor_DrawType; - - GrShape shape(path, GrStyle::SimpleFill()); - GrPathRenderer::CanDrawPathArgs canDrawArgs; - canDrawArgs.fShaderCaps = fDrawContext->fDrawingManager->getContext()->caps()->shaderCaps(); - canDrawArgs.fViewMatrix = &viewMatrix; - canDrawArgs.fShape = &shape; - canDrawArgs.fAntiAlias = useCoverageAA; - canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings; - canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA; - - // Don't allow the SW renderer - GrPathRenderer* pr = fDrawContext->fDrawingManager->getPathRenderer(canDrawArgs, false, type); - if (!pr) { - return false; - } - - GrPaint paint; - paint.setCoverageSetOpXPFactory(op, invert); - - GrPathRenderer::DrawPathArgs args; - args.fResourceProvider = fDrawContext->fDrawingManager->getContext()->resourceProvider(); - args.fPaint = &paint; - args.fUserStencilSettings = ss; - args.fDrawContext = fDrawContext; - args.fClip = &clip; - args.fViewMatrix = &viewMatrix; - args.fShape = &shape; - args.fAntiAlias = useCoverageAA; - args.fGammaCorrect = fDrawContext->isGammaCorrect(); - pr->drawPath(args); - return true; -} - -SkBudgeted GrDrawContextPriv::isBudgeted() const { - ASSERT_SINGLE_OWNER_PRIV - - if (fDrawContext->wasAbandoned()) { - return SkBudgeted::kNo; - } - - SkDEBUGCODE(fDrawContext->validate();) - - return fDrawContext->fRenderTarget->resourcePriv().isBudgeted(); -} - -void GrDrawContext::internalDrawPath(const GrClip& clip, - const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkPath& path, - const GrStyle& style) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkASSERT(!path.isEmpty()); - - bool useCoverageAA = should_apply_coverage_aa(paint, fRenderTarget.get()); - constexpr bool kHasUserStencilSettings = false; - bool isStencilBufferMSAA = this->isStencilBufferMultisampled(); - - const GrPathRendererChain::DrawType type = - useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType - : GrPathRendererChain::kColor_DrawType; - - GrShape shape(path, style); - if (shape.isEmpty()) { - return; - } - GrPathRenderer::CanDrawPathArgs canDrawArgs; - canDrawArgs.fShaderCaps = fDrawingManager->getContext()->caps()->shaderCaps(); - canDrawArgs.fViewMatrix = &viewMatrix; - canDrawArgs.fShape = &shape; - canDrawArgs.fAntiAlias = useCoverageAA; - canDrawArgs.fHasUserStencilSettings = kHasUserStencilSettings; - canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA; - - // Try a 1st time without applying any of the style to the geometry (and barring sw) - GrPathRenderer* pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type); - SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix); - - if (!pr && shape.style().pathEffect()) { - // It didn't work above, so try again with the path effect applied. - shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale); - if (shape.isEmpty()) { - return; - } - pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type); - } - if (!pr) { - if (shape.style().applies()) { - shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale); - if (shape.isEmpty()) { - return; - } - } - // This time, allow SW renderer - pr = fDrawingManager->getPathRenderer(canDrawArgs, true, type); - } - - if (!pr) { -#ifdef SK_DEBUG - SkDebugf("Unable to find path renderer compatible with path.\n"); -#endif - return; - } - - GrPathRenderer::DrawPathArgs args; - args.fResourceProvider = fDrawingManager->getContext()->resourceProvider(); - args.fPaint = &paint; - args.fUserStencilSettings = &GrUserStencilSettings::kUnused; - args.fDrawContext = this; - args.fClip = &clip; - args.fViewMatrix = &viewMatrix; - args.fShape = canDrawArgs.fShape; - args.fAntiAlias = useCoverageAA; - args.fGammaCorrect = this->isGammaCorrect(); - pr->drawPath(args); -} - -void GrDrawContext::drawBatch(const GrPipelineBuilder& pipelineBuilder, const GrClip& clip, - GrDrawBatch* batch) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawBatch"); - - this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); -} diff --git a/gfx/skia/skia/src/gpu/GrDrawContextPriv.h b/gfx/skia/skia/src/gpu/GrDrawContextPriv.h deleted file mode 100644 index 63eae12a0614..000000000000 --- a/gfx/skia/skia/src/gpu/GrDrawContextPriv.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrDrawContextPriv_DEFINED -#define GrDrawContextPriv_DEFINED - -#include "GrDrawContext.h" -#include "GrDrawTarget.h" -#include "GrPathRendering.h" - -class GrFixedClip; -class GrPath; -struct GrUserStencilSettings; - -/** Class that adds methods to GrDrawContext that are only intended for use internal to Skia. - This class is purely a privileged window into GrDrawContext. It should never have additional - data members or virtual methods. */ -class GrDrawContextPriv { -public: - gr_instanced::InstancedRendering* accessInstancedRendering() const { - return fDrawContext->getDrawTarget()->instancedRendering(); - } - - void clear(const GrFixedClip&, const GrColor, bool canIgnoreClip); - - void clearStencilClip(const GrFixedClip&, bool insideStencilMask); - - void stencilRect(const GrClip& clip, - const GrUserStencilSettings* ss, - bool useHWAA, - const SkMatrix& viewMatrix, - const SkRect& rect); - - void stencilPath(const GrClip&, - bool useHWAA, - const SkMatrix& viewMatrix, - const GrPath*); - - bool drawAndStencilRect(const GrClip&, - const GrUserStencilSettings*, - SkRegion::Op op, - bool invert, - bool doAA, - const SkMatrix& viewMatrix, - const SkRect&); - - bool drawAndStencilPath(const GrClip&, - const GrUserStencilSettings*, - SkRegion::Op op, - bool invert, - bool doAA, - const SkMatrix& viewMatrix, - const SkPath&); - - SkBudgeted isBudgeted() const; - - void testingOnly_drawBatch(const GrPaint&, - GrDrawBatch* batch, - const GrUserStencilSettings* = nullptr, - bool snapToCenters = false); - -private: - explicit GrDrawContextPriv(GrDrawContext* drawContext) : fDrawContext(drawContext) {} - GrDrawContextPriv(const GrRenderTargetPriv&) {} // unimpl - GrDrawContextPriv& operator=(const GrRenderTargetPriv&); // unimpl - - // No taking addresses of this type. - const GrDrawContextPriv* operator&() const; - GrDrawContextPriv* operator&(); - - GrDrawContext* fDrawContext; - - friend class GrDrawContext; // to construct/copy this type. -}; - -inline GrDrawContextPriv GrDrawContext::drawContextPriv() { return GrDrawContextPriv(this); } - -inline const GrDrawContextPriv GrDrawContext::drawContextPriv () const { - return GrDrawContextPriv(const_cast(this)); -} - -#endif diff --git a/gfx/skia/skia/src/gpu/GrDrawOpAtlas.cpp b/gfx/skia/skia/src/gpu/GrDrawOpAtlas.cpp new file mode 100644 index 000000000000..143bdd81fb90 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrDrawOpAtlas.cpp @@ -0,0 +1,308 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrDrawOpAtlas.h" + +#include "GrContext.h" +#include "GrOpFlushState.h" +#include "GrRectanizer.h" +#include "GrResourceProvider.h" +#include "GrTracing.h" + +std::unique_ptr GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig config, + int width, int height, + int numPlotsX, int numPlotsY, + GrDrawOpAtlas::EvictionFunc func, + void* data) { + GrSurfaceDesc desc; + desc.fFlags = kNone_GrSurfaceFlags; + desc.fWidth = width; + desc.fHeight = height; + desc.fConfig = config; + + // We don't want to flush the context so we claim we're in the middle of flushing so as to + // guarantee we do not recieve a texture with pending IO + // TODO: Determine how to avoid having to do this. (https://bug.skia.org/4156) + static const uint32_t kFlags = GrResourceProvider::kNoPendingIO_Flag; + sk_sp texture(ctx->resourceProvider()->createApproxTexture(desc, kFlags)); + if (!texture) { + return nullptr; + } + + // MDB TODO: for now, wrap an instantiated texture. Having the deferred instantiation + // possess the correct properties (e.g., no pendingIO) should fall out of the system but + // should receive special attention. + // Note: When switching over to the deferred proxy, use the kExact flag to create + // the atlas and assert that the width & height are powers of 2. + sk_sp proxy = GrSurfaceProxy::MakeWrapped(std::move(texture)); + if (!proxy) { + return nullptr; + } + + std::unique_ptr atlas( + new GrDrawOpAtlas(ctx, std::move(proxy), numPlotsX, numPlotsY)); + atlas->registerEvictionCallback(func, data); + return atlas; +} + + +//////////////////////////////////////////////////////////////////////////////// + +GrDrawOpAtlas::Plot::Plot(int index, uint64_t genID, int offX, int offY, int width, int height, + GrPixelConfig config) + : fLastUpload(GrDrawOpUploadToken::AlreadyFlushedToken()) + , fLastUse(GrDrawOpUploadToken::AlreadyFlushedToken()) + , fIndex(index) + , fGenID(genID) + , fID(CreateId(fIndex, fGenID)) + , fData(nullptr) + , fWidth(width) + , fHeight(height) + , fX(offX) + , fY(offY) + , fRects(nullptr) + , fOffset(SkIPoint16::Make(fX * fWidth, fY * fHeight)) + , fConfig(config) + , fBytesPerPixel(GrBytesPerPixel(config)) +#ifdef SK_DEBUG + , fDirty(false) +#endif +{ + fDirtyRect.setEmpty(); +} + +GrDrawOpAtlas::Plot::~Plot() { + sk_free(fData); + delete fRects; +} + +bool GrDrawOpAtlas::Plot::addSubImage(int width, int height, const void* image, SkIPoint16* loc) { + SkASSERT(width <= fWidth && height <= fHeight); + + if (!fRects) { + fRects = GrRectanizer::Factory(fWidth, fHeight); + } + + if (!fRects->addRect(width, height, loc)) { + return false; + } + + if (!fData) { + fData = reinterpret_cast(sk_calloc_throw(fBytesPerPixel * fWidth * + fHeight)); + } + size_t rowBytes = width * fBytesPerPixel; + const unsigned char* imagePtr = (const unsigned char*)image; + // point ourselves at the right starting spot + unsigned char* dataPtr = fData; + dataPtr += fBytesPerPixel * fWidth * loc->fY; + dataPtr += fBytesPerPixel * loc->fX; + // copy into the data buffer, swizzling as we go if this is ARGB data + if (4 == fBytesPerPixel && kSkia8888_GrPixelConfig == kBGRA_8888_GrPixelConfig) { + for (int i = 0; i < height; ++i) { + SkOpts::RGBA_to_BGRA(reinterpret_cast(dataPtr), imagePtr, width); + dataPtr += fBytesPerPixel * fWidth; + imagePtr += rowBytes; + } + } else { + for (int i = 0; i < height; ++i) { + memcpy(dataPtr, imagePtr, rowBytes); + dataPtr += fBytesPerPixel * fWidth; + imagePtr += rowBytes; + } + } + + fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height); + + loc->fX += fOffset.fX; + loc->fY += fOffset.fY; + SkDEBUGCODE(fDirty = true;) + + return true; +} + +void GrDrawOpAtlas::Plot::uploadToTexture(GrDrawOp::WritePixelsFn& writePixels, + GrTexture* texture) { + // We should only be issuing uploads if we are in fact dirty + SkASSERT(fDirty && fData && texture); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "GrDrawOpAtlas::Plot::uploadToTexture"); + size_t rowBytes = fBytesPerPixel * fWidth; + const unsigned char* dataPtr = fData; + dataPtr += rowBytes * fDirtyRect.fTop; + dataPtr += fBytesPerPixel * fDirtyRect.fLeft; + writePixels(texture, fOffset.fX + fDirtyRect.fLeft, fOffset.fY + fDirtyRect.fTop, + fDirtyRect.width(), fDirtyRect.height(), fConfig, dataPtr, rowBytes); + fDirtyRect.setEmpty(); + SkDEBUGCODE(fDirty = false;) +} + +void GrDrawOpAtlas::Plot::resetRects() { + if (fRects) { + fRects->reset(); + } + + fGenID++; + fID = CreateId(fIndex, fGenID); + + // zero out the plot + if (fData) { + sk_bzero(fData, fBytesPerPixel * fWidth * fHeight); + } + + fDirtyRect.setEmpty(); + SkDEBUGCODE(fDirty = false;) +} + +/////////////////////////////////////////////////////////////////////////////// + +GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, sk_sp proxy, + int numPlotsX, int numPlotsY) + : fContext(context) + , fProxy(std::move(proxy)) + , fAtlasGeneration(kInvalidAtlasGeneration + 1) { + fPlotWidth = fProxy->width() / numPlotsX; + fPlotHeight = fProxy->height() / numPlotsY; + SkASSERT(numPlotsX * numPlotsY <= BulkUseTokenUpdater::kMaxPlots); + SkASSERT(fPlotWidth * numPlotsX == fProxy->width()); + SkASSERT(fPlotHeight * numPlotsY == fProxy->height()); + + SkDEBUGCODE(fNumPlots = numPlotsX * numPlotsY;) + + // We currently do not support compressed atlases... + SkASSERT(!GrPixelConfigIsCompressed(fProxy->desc().fConfig)); + + // set up allocated plots + fPlotArray.reset(new sk_sp[ numPlotsX * numPlotsY ]); + + sk_sp* currPlot = fPlotArray.get(); + for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) { + for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) { + uint32_t index = r * numPlotsX + c; + currPlot->reset( + new Plot(index, 1, x, y, fPlotWidth, fPlotHeight, fProxy->desc().fConfig)); + + // build LRU list + fPlotList.addToHead(currPlot->get()); + ++currPlot; + } + } +} + +void GrDrawOpAtlas::processEviction(AtlasID id) { + for (int i = 0; i < fEvictionCallbacks.count(); i++) { + (*fEvictionCallbacks[i].fFunc)(id, fEvictionCallbacks[i].fData); + } +} + +inline bool GrDrawOpAtlas::updatePlot(GrDrawOp::Target* target, AtlasID* id, Plot* plot) { + this->makeMRU(plot); + + // If our most recent upload has already occurred then we have to insert a new + // upload. Otherwise, we already have a scheduled upload that hasn't yet ocurred. + // This new update will piggy back on that previously scheduled update. + if (target->hasDrawBeenFlushed(plot->lastUploadToken())) { + // With c+14 we could move sk_sp into lamba to only ref once. + sk_sp plotsp(SkRef(plot)); + + // MDB TODO: this is currently fine since the atlas' proxy is always pre-instantiated. + // Once it is deferred more care must be taken upon instantiation failure. + GrTexture* texture = fProxy->instantiate(fContext->resourceProvider()); + if (!texture) { + return false; + } + + GrDrawOpUploadToken lastUploadToken = target->addAsapUpload( + [plotsp, texture] (GrDrawOp::WritePixelsFn& writePixels) { + plotsp->uploadToTexture(writePixels, texture); + } + ); + plot->setLastUploadToken(lastUploadToken); + } + *id = plot->id(); + return true; +} + +bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width, int height, + const void* image, SkIPoint16* loc) { + // We should already have a texture, TODO clean this up + SkASSERT(fProxy); + if (width > fPlotWidth || height > fPlotHeight) { + return false; + } + + // now look through all allocated plots for one we can share, in Most Recently Refed order + PlotList::Iter plotIter; + plotIter.init(fPlotList, PlotList::Iter::kHead_IterStart); + Plot* plot; + while ((plot = plotIter.get())) { + SkASSERT(GrBytesPerPixel(fProxy->desc().fConfig) == plot->bpp()); + if (plot->addSubImage(width, height, image, loc)) { + return this->updatePlot(target, id, plot); + } + plotIter.next(); + } + + // If the above fails, then see if the least recently refed plot has already been flushed to the + // gpu + plot = fPlotList.tail(); + SkASSERT(plot); + if (target->hasDrawBeenFlushed(plot->lastUseToken())) { + this->processEviction(plot->id()); + plot->resetRects(); + SkASSERT(GrBytesPerPixel(fProxy->desc().fConfig) == plot->bpp()); + SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc); + SkASSERT(verify); + if (!this->updatePlot(target, id, plot)) { + return false; + } + + fAtlasGeneration++; + return true; + } + + // If this plot has been used in a draw that is currently being prepared by an op, then we have + // to fail. This gives the op a chance to enqueue the draw, and call back into this function. + // When that draw is enqueued, the draw token advances, and the subsequent call will continue + // past this branch and prepare an inline upload that will occur after the enqueued draw which + // references the plot's pre-upload content. + if (plot->lastUseToken() == target->nextDrawToken()) { + return false; + } + + this->processEviction(plot->id()); + fPlotList.remove(plot); + sk_sp& newPlot = fPlotArray[plot->index()]; + newPlot.reset(plot->clone()); + + fPlotList.addToHead(newPlot.get()); + SkASSERT(GrBytesPerPixel(fProxy->desc().fConfig) == newPlot->bpp()); + SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc); + SkASSERT(verify); + + // Note that this plot will be uploaded inline with the draws whereas the + // one it displaced most likely was uploaded asap. + // With c+14 we could move sk_sp into lambda to only ref once. + sk_sp plotsp(SkRef(newPlot.get())); + // MDB TODO: this is currently fine since the atlas' proxy is always pre-instantiated. + // Once it is deferred more care must be taken upon instantiation failure. + GrTexture* texture = fProxy->instantiate(fContext->resourceProvider()); + if (!texture) { + return false; + } + + GrDrawOpUploadToken lastUploadToken = target->addInlineUpload( + [plotsp, texture] (GrDrawOp::WritePixelsFn& writePixels) { + plotsp->uploadToTexture(writePixels, texture); + } + ); + newPlot->setLastUploadToken(lastUploadToken); + + *id = newPlot->id(); + + fAtlasGeneration++; + return true; +} diff --git a/gfx/skia/skia/src/gpu/GrDrawOpAtlas.h b/gfx/skia/skia/src/gpu/GrDrawOpAtlas.h new file mode 100644 index 000000000000..1119e3de18cf --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrDrawOpAtlas.h @@ -0,0 +1,309 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDrawOpAtlas_DEFINED +#define GrDrawOpAtlas_DEFINED + +#include "SkPoint.h" +#include "SkTDArray.h" +#include "SkTInternalLList.h" + +#include "ops/GrDrawOp.h" + +class GrRectanizer; + +struct GrDrawOpAtlasConfig { + int numPlotsX() const { return fWidth / fPlotWidth; } + int numPlotsY() const { return fHeight / fPlotWidth; } + int fWidth; + int fHeight; + int fLog2Width; + int fLog2Height; + int fPlotWidth; + int fPlotHeight; +}; + +/** + * This class manages an atlas texture on behalf of GrDrawOps. The draw ops that use the atlas + * perform texture uploads when preparing their draws during flush. The class provides facilities + * for using GrDrawOpUploadToken to detect data hazards. Op's uploads are performed in "asap" mode + * until it is impossible to add data without overwriting texels read by draws that have not yet + * executed on the gpu. At that point the uploads are performed "inline" between draws. If a single + * draw would use enough subimage space to overflow the atlas texture then the atlas will fail to + * add a subimage. This gives the op the chance to end the draw and begin a new one. Additional + * uploads will then succeed in inline mode. + */ +class GrDrawOpAtlas { +public: + /** + * An AtlasID is an opaque handle which callers can use to determine if the atlas contains + * a specific piece of data. + */ + typedef uint64_t AtlasID; + static const uint32_t kInvalidAtlasID = 0; + static const uint64_t kInvalidAtlasGeneration = 0; + + /** + * A function pointer for use as a callback during eviction. Whenever GrDrawOpAtlas evicts a + * specific AtlasID, it will call all of the registered listeners so they can process the + * eviction. + */ + typedef void (*EvictionFunc)(GrDrawOpAtlas::AtlasID, void*); + + /** + * Returns a GrDrawOpAtlas. This function can be called anywhere, but the returned atlas + * should only be used inside of GrMeshDrawOp::onPrepareDraws. + * @param GrPixelConfig The pixel config which this atlas will store + * @param width width in pixels of the atlas + * @param height height in pixels of the atlas + * @param numPlotsX The number of plots the atlas should be broken up into in the X + * direction + * @param numPlotsY The number of plots the atlas should be broken up into in the Y + * direction + * @param func An eviction function which will be called whenever the atlas has to + * evict data + * @param data User supplied data which will be passed into func whenver an + * eviction occurs + * @return An initialized GrDrawOpAtlas, or nullptr if creation fails + */ + static std::unique_ptr Make(GrContext*, GrPixelConfig, + int width, int height, + int numPlotsX, int numPlotsY, + GrDrawOpAtlas::EvictionFunc func, void* data); + + /** + * Adds a width x height subimage to the atlas. Upon success it returns an ID and the subimage's + * coordinates in the backing texture. False is returned if the subimage cannot fit in the + * atlas without overwriting texels that will be read in the current draw. This indicates that + * the op should end its current draw and begin another before adding more data. Upon success, + * an upload of the provided image data will have been added to the GrDrawOp::Target, in "asap" + * mode if possible, otherwise in "inline" mode. Successive uploads in either mode may be + * consolidated. + * NOTE: When the GrDrawOp prepares a draw that reads from the atlas, it must immediately call + * 'setUseToken' with the currentToken from the GrDrawOp::Target, otherwise the next call to + * addToAtlas might cause the previous data to be overwritten before it has been read. + */ + bool addToAtlas(AtlasID*, GrDrawOp::Target*, int width, int height, const void* image, + SkIPoint16* loc); + + GrContext* context() const { return fContext; } + sk_sp getProxy() const { return fProxy; } + + uint64_t atlasGeneration() const { return fAtlasGeneration; } + + inline bool hasID(AtlasID id) { + uint32_t index = GetIndexFromID(id); + SkASSERT(index < fNumPlots); + return fPlotArray[index]->genID() == GetGenerationFromID(id); + } + + /** To ensure the atlas does not evict a given entry, the client must set the last use token. */ + inline void setLastUseToken(AtlasID id, GrDrawOpUploadToken token) { + SkASSERT(this->hasID(id)); + uint32_t index = GetIndexFromID(id); + SkASSERT(index < fNumPlots); + this->makeMRU(fPlotArray[index].get()); + fPlotArray[index]->setLastUseToken(token); + } + + inline void registerEvictionCallback(EvictionFunc func, void* userData) { + EvictionData* data = fEvictionCallbacks.append(); + data->fFunc = func; + data->fData = userData; + } + + /** + * A class which can be handed back to GrDrawOpAtlas for updating last use tokens in bulk. The + * current max number of plots the GrDrawOpAtlas can handle is 32. If in the future this is + * insufficient then we can move to a 64 bit int. + */ + class BulkUseTokenUpdater { + public: + BulkUseTokenUpdater() : fPlotAlreadyUpdated(0) {} + BulkUseTokenUpdater(const BulkUseTokenUpdater& that) + : fPlotsToUpdate(that.fPlotsToUpdate) + , fPlotAlreadyUpdated(that.fPlotAlreadyUpdated) { + } + + void add(AtlasID id) { + int index = GrDrawOpAtlas::GetIndexFromID(id); + if (!this->find(index)) { + this->set(index); + } + } + + void reset() { + fPlotsToUpdate.reset(); + fPlotAlreadyUpdated = 0; + } + + private: + bool find(int index) const { + SkASSERT(index < kMaxPlots); + return (fPlotAlreadyUpdated >> index) & 1; + } + + void set(int index) { + SkASSERT(!this->find(index)); + fPlotAlreadyUpdated = fPlotAlreadyUpdated | (1 << index); + fPlotsToUpdate.push_back(index); + } + + static const int kMinItems = 4; + static const int kMaxPlots = 32; + SkSTArray fPlotsToUpdate; + uint32_t fPlotAlreadyUpdated; + + friend class GrDrawOpAtlas; + }; + + void setLastUseTokenBulk(const BulkUseTokenUpdater& updater, GrDrawOpUploadToken token) { + int count = updater.fPlotsToUpdate.count(); + for (int i = 0; i < count; i++) { + Plot* plot = fPlotArray[updater.fPlotsToUpdate[i]].get(); + this->makeMRU(plot); + plot->setLastUseToken(token); + } + } + + static const int kGlyphMaxDim = 256; + static bool GlyphTooLargeForAtlas(int width, int height) { + return width > kGlyphMaxDim || height > kGlyphMaxDim; + } + +private: + GrDrawOpAtlas(GrContext*, sk_sp, int numPlotsX, int numPlotsY); + + /** + * The backing GrTexture for a GrDrawOpAtlas is broken into a spatial grid of Plots. The Plots + * keep track of subimage placement via their GrRectanizer. A Plot manages the lifetime of its + * data using two tokens, a last use token and a last upload token. Once a Plot is "full" (i.e. + * there is no room for the new subimage according to the GrRectanizer), it can no longer be + * used unless the last use of the Plot has already been flushed through to the gpu. + */ + class Plot : public SkRefCnt { + SK_DECLARE_INTERNAL_LLIST_INTERFACE(Plot); + + public: + /** index() is a unique id for the plot relative to the owning GrAtlas. */ + uint32_t index() const { return fIndex; } + /** + * genID() is incremented when the plot is evicted due to a atlas spill. It is used to know + * if a particular subimage is still present in the atlas. + */ + uint64_t genID() const { return fGenID; } + GrDrawOpAtlas::AtlasID id() const { + SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != fID); + return fID; + } + SkDEBUGCODE(size_t bpp() const { return fBytesPerPixel; }) + + bool addSubImage(int width, int height, const void* image, SkIPoint16* loc); + + /** + * To manage the lifetime of a plot, we use two tokens. We use the last upload token to + * know when we can 'piggy back' uploads, i.e. if the last upload hasn't been flushed to + * the gpu, we don't need to issue a new upload even if we update the cpu backing store. We + * use lastUse to determine when we can evict a plot from the cache, i.e. if the last use + * has already flushed through the gpu then we can reuse the plot. + */ + GrDrawOpUploadToken lastUploadToken() const { return fLastUpload; } + GrDrawOpUploadToken lastUseToken() const { return fLastUse; } + void setLastUploadToken(GrDrawOpUploadToken token) { fLastUpload = token; } + void setLastUseToken(GrDrawOpUploadToken token) { fLastUse = token; } + + void uploadToTexture(GrDrawOp::WritePixelsFn&, GrTexture* texture); + void resetRects(); + + private: + Plot(int index, uint64_t genID, int offX, int offY, int width, int height, + GrPixelConfig config); + + ~Plot() override; + + /** + * Create a clone of this plot. The cloned plot will take the place of the current plot in + * the atlas + */ + Plot* clone() const { + return new Plot(fIndex, fGenID + 1, fX, fY, fWidth, fHeight, fConfig); + } + + static GrDrawOpAtlas::AtlasID CreateId(uint32_t index, uint64_t generation) { + SkASSERT(index < (1 << 16)); + SkASSERT(generation < ((uint64_t)1 << 48)); + return generation << 16 | index; + } + + GrDrawOpUploadToken fLastUpload; + GrDrawOpUploadToken fLastUse; + + const uint32_t fIndex; + uint64_t fGenID; + GrDrawOpAtlas::AtlasID fID; + unsigned char* fData; + const int fWidth; + const int fHeight; + const int fX; + const int fY; + GrRectanizer* fRects; + const SkIPoint16 fOffset; // the offset of the plot in the backing texture + const GrPixelConfig fConfig; + const size_t fBytesPerPixel; + SkIRect fDirtyRect; + SkDEBUGCODE(bool fDirty); + + friend class GrDrawOpAtlas; + + typedef SkRefCnt INHERITED; + }; + + typedef SkTInternalLList PlotList; + + static uint32_t GetIndexFromID(AtlasID id) { + return id & 0xffff; + } + + // top 48 bits are reserved for the generation ID + static uint64_t GetGenerationFromID(AtlasID id) { + return (id >> 16) & 0xffffffffffff; + } + + inline bool updatePlot(GrDrawOp::Target*, AtlasID*, Plot*); + + inline void makeMRU(Plot* plot) { + if (fPlotList.head() == plot) { + return; + } + + fPlotList.remove(plot); + fPlotList.addToHead(plot); + } + + inline void processEviction(AtlasID); + + GrContext* fContext; + sk_sp fProxy; + int fPlotWidth; + int fPlotHeight; + SkDEBUGCODE(uint32_t fNumPlots;) + + uint64_t fAtlasGeneration; + + struct EvictionData { + EvictionFunc fFunc; + void* fData; + }; + + SkTDArray fEvictionCallbacks; + // allocated array of Plots + std::unique_ptr[]> fPlotArray; + // LRU list of Plots (MRU at head - LRU at tail) + PlotList fPlotList; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrDrawOpTest.cpp b/gfx/skia/skia/src/gpu/GrDrawOpTest.cpp new file mode 100644 index 000000000000..1e88c219f5c4 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrDrawOpTest.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrDrawOpTest.h" +#include "SkRandom.h" +#include "SkTypes.h" +#include "ops/GrMeshDrawOp.h" + +#if GR_TEST_UTILS + +#define DRAW_OP_TEST_EXTERN(Op) \ + extern std::unique_ptr Op##__Test(SkRandom*, GrContext* context); + +#define DRAW_OP_TEST_ENTRY(Op) Op##__Test + +DRAW_OP_TEST_EXTERN(AAConvexPathOp); +DRAW_OP_TEST_EXTERN(AAFillRectOp); +DRAW_OP_TEST_EXTERN(AAFillRectOpLocalMatrix); +DRAW_OP_TEST_EXTERN(AAFlatteningConvexPathOp) +DRAW_OP_TEST_EXTERN(AAHairlineOp); +DRAW_OP_TEST_EXTERN(AAStrokeRectOp); +DRAW_OP_TEST_EXTERN(AnalyticRectOp); +DRAW_OP_TEST_EXTERN(DashOp); +DRAW_OP_TEST_EXTERN(DefaultPathOp); +DRAW_OP_TEST_EXTERN(CircleOp); +DRAW_OP_TEST_EXTERN(DIEllipseOp); +DRAW_OP_TEST_EXTERN(EllipseOp); +DRAW_OP_TEST_EXTERN(GrDrawAtlasOp); +DRAW_OP_TEST_EXTERN(NonAAStrokeRectOp); +DRAW_OP_TEST_EXTERN(RRectOp); +DRAW_OP_TEST_EXTERN(SmallPathOp); +DRAW_OP_TEST_EXTERN(TesselatingPathOp); +DRAW_OP_TEST_EXTERN(TextBlobOp); +DRAW_OP_TEST_EXTERN(VerticesOp); + +std::unique_ptr GrRandomDrawOp(SkRandom* random, GrContext* context) { + using MakeTestDrawOpFn = + std::unique_ptr(SkRandom * random, GrContext * context); + static constexpr MakeTestDrawOpFn* gFactories[] = { + DRAW_OP_TEST_ENTRY(AAConvexPathOp), + DRAW_OP_TEST_ENTRY(AAFillRectOp), + DRAW_OP_TEST_ENTRY(AAFillRectOpLocalMatrix), + DRAW_OP_TEST_ENTRY(AAFlatteningConvexPathOp), + DRAW_OP_TEST_ENTRY(AAHairlineOp), + DRAW_OP_TEST_ENTRY(AAStrokeRectOp), + DRAW_OP_TEST_ENTRY(AnalyticRectOp), + DRAW_OP_TEST_ENTRY(DashOp), + DRAW_OP_TEST_ENTRY(DefaultPathOp), + DRAW_OP_TEST_ENTRY(CircleOp), + DRAW_OP_TEST_ENTRY(DIEllipseOp), + DRAW_OP_TEST_ENTRY(EllipseOp), + DRAW_OP_TEST_ENTRY(GrDrawAtlasOp), + DRAW_OP_TEST_ENTRY(NonAAStrokeRectOp), + DRAW_OP_TEST_ENTRY(RRectOp), + DRAW_OP_TEST_ENTRY(SmallPathOp), + DRAW_OP_TEST_ENTRY(TesselatingPathOp), + DRAW_OP_TEST_ENTRY(TextBlobOp), + DRAW_OP_TEST_ENTRY(VerticesOp) + }; + + uint32_t index = random->nextULessThan(static_cast(SK_ARRAY_COUNT(gFactories))); + return gFactories[index](random, context); +} +#endif diff --git a/gfx/skia/skia/src/gpu/GrDrawOpTest.h b/gfx/skia/skia/src/gpu/GrDrawOpTest.h new file mode 100644 index 000000000000..376022999b98 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrDrawOpTest.h @@ -0,0 +1,32 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDrawOpTest_DEFINED +#define GrDrawOpTest_DEFINED + +#include "GrTestUtils.h" +#include "SkRefCnt.h" + +#if GR_TEST_UTILS + +class GrContext; +class GrLegacyMeshDrawOp; +class SkRandom; + +/** This function returns a randomly configured GrDrawOp for testing purposes. */ +std::unique_ptr GrRandomDrawOp(SkRandom*, GrContext*); + +/** GrDrawOp subclasses should define test factory functions using this macro. */ +#define DRAW_OP_TEST_DEFINE(Op) \ + std::unique_ptr Op##__Test(SkRandom* random, GrContext* context) + +/** This macro may be used if the test factory function must be made a friend of a class. */ +#define DRAW_OP_TEST_FRIEND(Op) \ + friend std::unique_ptr Op##__Test(SkRandom* random, GrContext* context); + +#endif +#endif diff --git a/gfx/skia/skia/src/gpu/GrDrawTarget.cpp b/gfx/skia/skia/src/gpu/GrDrawTarget.cpp deleted file mode 100644 index 0117d0e1a15a..000000000000 --- a/gfx/skia/skia/src/gpu/GrDrawTarget.cpp +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrDrawTarget.h" - -#include "GrAppliedClip.h" -#include "GrAuditTrail.h" -#include "GrCaps.h" -#include "GrDrawContext.h" -#include "GrGpu.h" -#include "GrGpuCommandBuffer.h" -#include "GrPath.h" -#include "GrPipeline.h" -#include "GrMemoryPool.h" -#include "GrPipelineBuilder.h" -#include "GrRenderTarget.h" -#include "GrResourceProvider.h" -#include "GrRenderTargetPriv.h" -#include "GrStencilAttachment.h" -#include "GrSurfacePriv.h" -#include "GrTexture.h" -#include "gl/GrGLRenderTarget.h" - -#include "SkStrokeRec.h" - -#include "batches/GrClearBatch.h" -#include "batches/GrClearStencilClipBatch.h" -#include "batches/GrCopySurfaceBatch.h" -#include "batches/GrDiscardBatch.h" -#include "batches/GrDrawBatch.h" -#include "batches/GrDrawPathBatch.h" -#include "batches/GrRectBatchFactory.h" -#include "batches/GrStencilPathBatch.h" - -#include "instanced/InstancedRendering.h" - -//////////////////////////////////////////////////////////////////////////////// - -// Experimentally we have found that most batching occurs within the first 10 comparisons. -static const int kDefaultMaxBatchLookback = 10; -static const int kDefaultMaxBatchLookahead = 10; - -GrDrawTarget::GrDrawTarget(GrRenderTarget* rt, GrGpu* gpu, GrResourceProvider* resourceProvider, - GrAuditTrail* auditTrail, const Options& options) - : fLastFullClearBatch(nullptr) - , fGpu(SkRef(gpu)) - , fResourceProvider(resourceProvider) - , fAuditTrail(auditTrail) - , fFlags(0) - , fRenderTarget(rt) { - // TODO: Stop extracting the context (currently needed by GrClip) - fContext = fGpu->getContext(); - - fClipBatchToBounds = options.fClipBatchToBounds; - fDrawBatchBounds = options.fDrawBatchBounds; - fMaxBatchLookback = (options.fMaxBatchLookback < 0) ? kDefaultMaxBatchLookback : - options.fMaxBatchLookback; - fMaxBatchLookahead = (options.fMaxBatchLookahead < 0) ? kDefaultMaxBatchLookahead : - options.fMaxBatchLookahead; - - if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) { - fInstancedRendering.reset(fGpu->createInstancedRendering()); - } - - rt->setLastDrawTarget(this); - -#ifdef SK_DEBUG - static int debugID = 0; - fDebugID = debugID++; -#endif -} - -GrDrawTarget::~GrDrawTarget() { - if (fRenderTarget && this == fRenderTarget->getLastDrawTarget()) { - fRenderTarget->setLastDrawTarget(nullptr); - } - - fGpu->unref(); -} - -//////////////////////////////////////////////////////////////////////////////// - -// Add a GrDrawTarget-based dependency -void GrDrawTarget::addDependency(GrDrawTarget* dependedOn) { - SkASSERT(!dependedOn->dependsOn(this)); // loops are bad - - if (this->dependsOn(dependedOn)) { - return; // don't add duplicate dependencies - } - - *fDependencies.push() = dependedOn; -} - -// Convert from a GrSurface-based dependency to a GrDrawTarget one -void GrDrawTarget::addDependency(GrSurface* dependedOn) { - if (dependedOn->asRenderTarget() && dependedOn->asRenderTarget()->getLastDrawTarget()) { - // If it is still receiving dependencies, this DT shouldn't be closed - SkASSERT(!this->isClosed()); - - GrDrawTarget* dt = dependedOn->asRenderTarget()->getLastDrawTarget(); - if (dt == this) { - // self-read - presumably for dst reads - } else { - this->addDependency(dt); - - // Can't make it closed in the self-read case - dt->makeClosed(); - } - } -} - -#ifdef SK_DEBUG -void GrDrawTarget::dump() const { - SkDebugf("--------------------------------------------------------------\n"); - SkDebugf("node: %d -> RT: %d\n", fDebugID, fRenderTarget ? fRenderTarget->uniqueID() : -1); - SkDebugf("relies On (%d): ", fDependencies.count()); - for (int i = 0; i < fDependencies.count(); ++i) { - SkDebugf("%d, ", fDependencies[i]->fDebugID); - } - SkDebugf("\n"); - SkDebugf("batches (%d):\n", fRecordedBatches.count()); - for (int i = 0; i < fRecordedBatches.count(); ++i) { - SkDebugf("*******************************\n"); - if (!fRecordedBatches[i].fBatch) { - SkDebugf("%d: \n", i); - } else { - SkDebugf("%d: %s\n", i, fRecordedBatches[i].fBatch->name()); - SkString str = fRecordedBatches[i].fBatch->dumpInfo(); - SkDebugf("%s\n", str.c_str()); - const SkRect& clippedBounds = fRecordedBatches[i].fClippedBounds; - SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", - clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight, - clippedBounds.fBottom); - } - } -} -#endif - -bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder, - GrRenderTarget* rt, - const GrClip& clip, - const GrPipelineOptimizations& optimizations, - GrXferProcessor::DstTexture* dstTexture, - const SkRect& batchBounds) { - SkRect bounds = batchBounds; - bounds.outset(0.5f, 0.5f); - - if (!pipelineBuilder.willXPNeedDstTexture(*this->caps(), optimizations)) { - return true; - } - - if (this->caps()->textureBarrierSupport()) { - if (GrTexture* rtTex = rt->asTexture()) { - // The render target is a texture, so we can read from it directly in the shader. The XP - // will be responsible to detect this situation and request a texture barrier. - dstTexture->setTexture(rtTex); - dstTexture->setOffset(0, 0); - return true; - } - } - - SkIRect copyRect; - clip.getConservativeBounds(rt->width(), rt->height(), ©Rect); - - SkIRect drawIBounds; - bounds.roundOut(&drawIBounds); - if (!copyRect.intersect(drawIBounds)) { -#ifdef SK_DEBUG - GrCapsDebugf(this->caps(), "Missed an early reject. " - "Bailing on draw from setupDstReadIfNecessary.\n"); -#endif - return false; - } - - // MSAA consideration: When there is support for reading MSAA samples in the shader we could - // have per-sample dst values by making the copy multisampled. - GrSurfaceDesc desc; - if (!fGpu->initDescForDstCopy(rt, &desc)) { - desc.fOrigin = kDefault_GrSurfaceOrigin; - desc.fFlags = kRenderTarget_GrSurfaceFlag; - desc.fConfig = rt->config(); - } - - desc.fWidth = copyRect.width(); - desc.fHeight = copyRect.height(); - - static const uint32_t kFlags = 0; - SkAutoTUnref copy(fResourceProvider->createApproxTexture(desc, kFlags)); - - if (!copy) { - SkDebugf("Failed to create temporary copy of destination texture.\n"); - return false; - } - SkIPoint dstPoint = {0, 0}; - this->copySurface(copy, rt, copyRect, dstPoint); - dstTexture->setTexture(copy); - dstTexture->setOffset(copyRect.fLeft, copyRect.fTop); - return true; -} - -void GrDrawTarget::prepareBatches(GrBatchFlushState* flushState) { - // Semi-usually the drawTargets are already closed at this point, but sometimes Ganesh - // needs to flush mid-draw. In that case, the SkGpuDevice's drawTargets won't be closed - // but need to be flushed anyway. Closing such drawTargets here will mean new - // drawTargets will be created to replace them if the SkGpuDevice(s) write to them again. - this->makeClosed(); - - // Loop over the batches that haven't yet generated their geometry - for (int i = 0; i < fRecordedBatches.count(); ++i) { - if (fRecordedBatches[i].fBatch) { - fRecordedBatches[i].fBatch->prepare(flushState); - } - } - - if (fInstancedRendering) { - fInstancedRendering->beginFlush(flushState->resourceProvider()); - } -} - -bool GrDrawTarget::drawBatches(GrBatchFlushState* flushState) { - if (0 == fRecordedBatches.count()) { - return false; - } - // Draw all the generated geometry. - SkRandom random; - GrRenderTarget* currentRT = nullptr; - SkAutoTDelete commandBuffer; - SkRect bounds = SkRect::MakeEmpty(); - for (int i = 0; i < fRecordedBatches.count(); ++i) { - if (!fRecordedBatches[i].fBatch) { - continue; - } - if (fRecordedBatches[i].fBatch->renderTarget() != currentRT) { - if (commandBuffer) { - commandBuffer->end(); - if (bounds.intersect(0, 0, - SkIntToScalar(currentRT->width()), - SkIntToScalar(currentRT->height()))) { - SkIRect iBounds; - bounds.roundOut(&iBounds); - commandBuffer->submit(iBounds); - } - commandBuffer.reset(); - } - bounds.setEmpty(); - currentRT = fRecordedBatches[i].fBatch->renderTarget(); - if (currentRT) { - static const GrGpuCommandBuffer::LoadAndStoreInfo kBasicLoadStoreInfo - { GrGpuCommandBuffer::LoadOp::kLoad,GrGpuCommandBuffer::StoreOp::kStore, - GrColor_ILLEGAL }; - commandBuffer.reset(fGpu->createCommandBuffer(currentRT, - kBasicLoadStoreInfo, // Color - kBasicLoadStoreInfo)); // Stencil - } - flushState->setCommandBuffer(commandBuffer); - } - if (commandBuffer) { - bounds.join(fRecordedBatches[i].fClippedBounds); - } - if (fDrawBatchBounds) { - const SkRect& bounds = fRecordedBatches[i].fClippedBounds; - SkIRect ibounds; - bounds.roundOut(&ibounds); - // In multi-draw buffer all the batches use the same render target and we won't need to - // get the batchs bounds. - if (GrRenderTarget* rt = fRecordedBatches[i].fBatch->renderTarget()) { - fGpu->drawDebugWireRect(rt, ibounds, 0xFF000000 | random.nextU()); - } - } - fRecordedBatches[i].fBatch->draw(flushState); - } - if (commandBuffer) { - commandBuffer->end(); - if (bounds.intersect(0, 0, - SkIntToScalar(currentRT->width()), - SkIntToScalar(currentRT->height()))) { - SkIRect iBounds; - bounds.roundOut(&iBounds); - commandBuffer->submit(iBounds); - } - flushState->setCommandBuffer(nullptr); - } - - fGpu->finishDrawTarget(); - return true; -} - -void GrDrawTarget::reset() { - fLastFullClearBatch = nullptr; - fRecordedBatches.reset(); - if (fInstancedRendering) { - fInstancedRendering->endFlush(); - } -} - -static void batch_bounds(SkRect* bounds, const GrBatch* batch) { - *bounds = batch->bounds(); - if (batch->hasZeroArea()) { - if (batch->hasAABloat()) { - bounds->outset(0.5f, 0.5f); - } else { - // We don't know which way the particular GPU will snap lines or points at integer - // coords. So we ensure that the bounds is large enough for either snap. - SkRect before = *bounds; - bounds->roundOut(bounds); - if (bounds->fLeft == before.fLeft) { - bounds->fLeft -= 1; - } - if (bounds->fTop == before.fTop) { - bounds->fTop -= 1; - } - if (bounds->fRight == before.fRight) { - bounds->fRight += 1; - } - if (bounds->fBottom == before.fBottom) { - bounds->fBottom += 1; - } - } - } -} - -void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder, - GrDrawContext* drawContext, - const GrClip& clip, - GrDrawBatch* batch) { - // Setup clip - SkRect bounds; - batch_bounds(&bounds, batch); - GrAppliedClip appliedClip(bounds); - if (!clip.apply(fContext, drawContext, pipelineBuilder.isHWAntialias(), - pipelineBuilder.hasUserStencilSettings(), &appliedClip)) { - return; - } - - // TODO: this is the only remaining usage of the AutoRestoreFragmentProcessorState - remove it - GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps; - if (appliedClip.clipCoverageFragmentProcessor()) { - arfps.set(&pipelineBuilder); - arfps.addCoverageFragmentProcessor(sk_ref_sp(appliedClip.clipCoverageFragmentProcessor())); - } - - if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) { - if (!fResourceProvider->attachStencilAttachment(drawContext->accessRenderTarget())) { - SkDebugf("ERROR creating stencil attachment. Draw skipped.\n"); - return; - } - } - - GrPipeline::CreateArgs args; - args.fPipelineBuilder = &pipelineBuilder; - args.fDrawContext = drawContext; - args.fCaps = this->caps(); - batch->getPipelineOptimizations(&args.fOpts); - if (args.fOpts.fOverrides.fUsePLSDstRead || fClipBatchToBounds) { - GrGLIRect viewport; - viewport.fLeft = 0; - viewport.fBottom = 0; - viewport.fWidth = drawContext->width(); - viewport.fHeight = drawContext->height(); - SkIRect ibounds; - ibounds.fLeft = SkTPin(SkScalarFloorToInt(batch->bounds().fLeft), viewport.fLeft, - viewport.fWidth); - ibounds.fTop = SkTPin(SkScalarFloorToInt(batch->bounds().fTop), viewport.fBottom, - viewport.fHeight); - ibounds.fRight = SkTPin(SkScalarCeilToInt(batch->bounds().fRight), viewport.fLeft, - viewport.fWidth); - ibounds.fBottom = SkTPin(SkScalarCeilToInt(batch->bounds().fBottom), viewport.fBottom, - viewport.fHeight); - if (!appliedClip.addScissor(ibounds)) { - return; - } - } - args.fOpts.fColorPOI.completeCalculations( - sk_sp_address_as_pointer_address(pipelineBuilder.fColorFragmentProcessors.begin()), - pipelineBuilder.numColorFragmentProcessors()); - args.fOpts.fCoveragePOI.completeCalculations( - sk_sp_address_as_pointer_address(pipelineBuilder.fCoverageFragmentProcessors.begin()), - pipelineBuilder.numCoverageFragmentProcessors()); - args.fScissor = &appliedClip.scissorState(); - args.fWindowRectsState = &appliedClip.windowRectsState(); - args.fHasStencilClip = appliedClip.hasStencilClip(); - if (!this->setupDstReadIfNecessary(pipelineBuilder, drawContext->accessRenderTarget(), - clip, args.fOpts, - &args.fDstTexture, batch->bounds())) { - return; - } - - if (!batch->installPipeline(args)) { - return; - } - -#ifdef ENABLE_MDB - SkASSERT(fRenderTarget); - batch->pipeline()->addDependenciesTo(fRenderTarget); -#endif - this->recordBatch(batch, appliedClip.clippedDrawBounds()); -} - -void GrDrawTarget::stencilPath(GrDrawContext* drawContext, - const GrClip& clip, - bool useHWAA, - const SkMatrix& viewMatrix, - const GrPath* path) { - // TODO: extract portions of checkDraw that are relevant to path stenciling. - SkASSERT(path); - SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); - - // FIXME: Use path bounds instead of this WAR once - // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved. - SkRect bounds = SkRect::MakeIWH(drawContext->width(), drawContext->height()); - - // Setup clip - GrAppliedClip appliedClip(bounds); - if (!clip.apply(fContext, drawContext, useHWAA, true, &appliedClip)) { - return; - } - // TODO: respect fClipBatchToBounds if we ever start computing bounds here. - - // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never - // attempt this in a situation that would require coverage AA. - SkASSERT(!appliedClip.clipCoverageFragmentProcessor()); - - GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment( - drawContext->accessRenderTarget()); - if (!stencilAttachment) { - SkDebugf("ERROR creating stencil attachment. Draw skipped.\n"); - return; - } - - GrBatch* batch = GrStencilPathBatch::Create(viewMatrix, - useHWAA, - path->getFillType(), - appliedClip.hasStencilClip(), - stencilAttachment->bits(), - appliedClip.scissorState(), - drawContext->accessRenderTarget(), - path); - this->recordBatch(batch, appliedClip.clippedDrawBounds()); - batch->unref(); -} - -void GrDrawTarget::addBatch(sk_sp batch) { - this->recordBatch(batch.get(), batch->bounds()); -} - -void GrDrawTarget::fullClear(GrRenderTarget* renderTarget, GrColor color) { - // Currently this just inserts or updates the last clear batch. However, once in MDB this can - // remove all the previously recorded batches and change the load op to clear with supplied - // color. - if (fLastFullClearBatch && - fLastFullClearBatch->renderTargetUniqueID() == renderTarget->uniqueID()) { - // As currently implemented, fLastFullClearBatch should be the last batch because we would - // have cleared it when another batch was recorded. - SkASSERT(fRecordedBatches.back().fBatch.get() == fLastFullClearBatch); - fLastFullClearBatch->setColor(color); - return; - } - sk_sp batch(GrClearBatch::Make(GrFixedClip::Disabled(), color, renderTarget)); - if (batch.get() == this->recordBatch(batch.get(), batch->bounds())) { - fLastFullClearBatch = batch.get(); - } -} - -void GrDrawTarget::discard(GrRenderTarget* renderTarget) { - // Currently this just inserts a discard batch. However, once in MDB this can remove all the - // previously recorded batches and change the load op to discard. - if (this->caps()->discardRenderTargetSupport()) { - GrBatch* batch = new GrDiscardBatch(renderTarget); - this->recordBatch(batch, batch->bounds()); - batch->unref(); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -bool GrDrawTarget::copySurface(GrSurface* dst, - GrSurface* src, - const SkIRect& srcRect, - const SkIPoint& dstPoint) { - GrBatch* batch = GrCopySurfaceBatch::Create(dst, src, srcRect, dstPoint); - if (!batch) { - return false; - } -#ifdef ENABLE_MDB - this->addDependency(src); -#endif - - this->recordBatch(batch, batch->bounds()); - batch->unref(); - return true; -} - -static inline bool can_reorder(const SkRect& a, const SkRect& b) { - return a.fRight <= b.fLeft || a.fBottom <= b.fTop || - b.fRight <= a.fLeft || b.fBottom <= a.fTop; -} - -static void join(SkRect* out, const SkRect& a, const SkRect& b) { - SkASSERT(a.fLeft <= a.fRight && a.fTop <= a.fBottom); - SkASSERT(b.fLeft <= b.fRight && b.fTop <= b.fBottom); - out->fLeft = SkTMin(a.fLeft, b.fLeft); - out->fTop = SkTMin(a.fTop, b.fTop); - out->fRight = SkTMax(a.fRight, b.fRight); - out->fBottom = SkTMax(a.fBottom, b.fBottom); -} - -GrBatch* GrDrawTarget::recordBatch(GrBatch* batch, const SkRect& clippedBounds) { - // A closed drawTarget should never receive new/more batches - SkASSERT(!this->isClosed()); - - // Check if there is a Batch Draw we can batch with by linearly searching back until we either - // 1) check every draw - // 2) intersect with something - // 3) find a 'blocker' - GR_AUDIT_TRAIL_ADDBATCH(fAuditTrail, batch); - GrBATCH_INFO("Re-Recording (%s, B%u)\n" - "\tBounds LRTB (%f, %f, %f, %f)\n", - batch->name(), - batch->uniqueID(), - batch->bounds().fLeft, batch->bounds().fRight, - batch->bounds().fTop, batch->bounds().fBottom); - GrBATCH_INFO(SkTabString(batch->dumpInfo(), 1).c_str()); - GrBATCH_INFO("\tClipped Bounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", - clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight, - clippedBounds.fBottom); - GrBATCH_INFO("\tOutcome:\n"); - int maxCandidates = SkTMin(fMaxBatchLookback, fRecordedBatches.count()); - if (maxCandidates) { - int i = 0; - while (true) { - GrBatch* candidate = fRecordedBatches.fromBack(i).fBatch.get(); - // We cannot continue to search backwards if the render target changes - if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) { - GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", - candidate->name(), candidate->uniqueID()); - break; - } - if (candidate->combineIfPossible(batch, *this->caps())) { - GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(), - candidate->uniqueID()); - GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, candidate, batch); - join(&fRecordedBatches.fromBack(i).fClippedBounds, - fRecordedBatches.fromBack(i).fClippedBounds, clippedBounds); - return candidate; - } - // Stop going backwards if we would cause a painter's order violation. - const SkRect& candidateBounds = fRecordedBatches.fromBack(i).fClippedBounds; - if (!can_reorder(candidateBounds, clippedBounds)) { - GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(), - candidate->uniqueID()); - break; - } - ++i; - if (i == maxCandidates) { - GrBATCH_INFO("\t\tReached max lookback or beginning of batch array %d\n", i); - break; - } - } - } else { - GrBATCH_INFO("\t\tFirstBatch\n"); - } - GR_AUDIT_TRAIL_BATCHING_RESULT_NEW(fAuditTrail, batch); - fRecordedBatches.emplace_back(RecordedBatch{sk_ref_sp(batch), clippedBounds}); - fLastFullClearBatch = nullptr; - return batch; -} - -void GrDrawTarget::forwardCombine() { - if (fMaxBatchLookahead <= 0) { - return; - } - for (int i = 0; i < fRecordedBatches.count() - 2; ++i) { - GrBatch* batch = fRecordedBatches[i].fBatch.get(); - const SkRect& batchBounds = fRecordedBatches[i].fClippedBounds; - int maxCandidateIdx = SkTMin(i + fMaxBatchLookahead, fRecordedBatches.count() - 1); - int j = i + 1; - while (true) { - GrBatch* candidate = fRecordedBatches[j].fBatch.get(); - // We cannot continue to search if the render target changes - if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) { - GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", - candidate->name(), candidate->uniqueID()); - break; - } - if (j == i +1) { - // We assume batch would have combined with candidate when the candidate was added - // via backwards combining in recordBatch. - SkASSERT(!batch->combineIfPossible(candidate, *this->caps())); - } else if (batch->combineIfPossible(candidate, *this->caps())) { - GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(), - candidate->uniqueID()); - GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, batch, candidate); - fRecordedBatches[j].fBatch = std::move(fRecordedBatches[i].fBatch); - join(&fRecordedBatches[j].fClippedBounds, fRecordedBatches[j].fClippedBounds, - batchBounds); - break; - } - // Stop going traversing if we would cause a painter's order violation. - const SkRect& candidateBounds = fRecordedBatches[j].fClippedBounds; - if (!can_reorder(candidateBounds, batchBounds)) { - GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(), - candidate->uniqueID()); - break; - } - ++j; - if (j > maxCandidateIdx) { - GrBATCH_INFO("\t\tReached max lookahead or end of batch array %d\n", i); - break; - } - } - } -} - -/////////////////////////////////////////////////////////////////////////////// - -void GrDrawTarget::clearStencilClip(const GrFixedClip& clip, - bool insideStencilMask, - GrRenderTarget* rt) { - GrBatch* batch = new GrClearStencilClipBatch(clip, insideStencilMask, rt); - this->recordBatch(batch, batch->bounds()); - batch->unref(); -} diff --git a/gfx/skia/skia/src/gpu/GrDrawTarget.h b/gfx/skia/skia/src/gpu/GrDrawTarget.h deleted file mode 100644 index 35de23915020..000000000000 --- a/gfx/skia/skia/src/gpu/GrDrawTarget.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrDrawTarget_DEFINED -#define GrDrawTarget_DEFINED - -#include "GrClip.h" -#include "GrContext.h" -#include "GrPathProcessor.h" -#include "GrPrimitiveProcessor.h" -#include "GrPathRendering.h" -#include "GrXferProcessor.h" - -#include "batches/GrDrawBatch.h" - -#include "SkClipStack.h" -#include "SkMatrix.h" -#include "SkPath.h" -#include "SkStringUtils.h" -#include "SkStrokeRec.h" -#include "SkTArray.h" -#include "SkTLazy.h" -#include "SkTypes.h" -#include "SkXfermode.h" - -//#define ENABLE_MDB 1 - -class GrAuditTrail; -class GrBatch; -class GrClearBatch; -class GrClip; -class GrCaps; -class GrPath; -class GrDrawPathBatchBase; -class GrPipelineBuilder; - -class GrDrawTarget final : public SkRefCnt { -public: - /** Options for GrDrawTarget behavior. */ - struct Options { - Options () - : fClipBatchToBounds(false) - , fDrawBatchBounds(false) - , fMaxBatchLookback(-1) - , fMaxBatchLookahead(-1) {} - bool fClipBatchToBounds; - bool fDrawBatchBounds; - int fMaxBatchLookback; - int fMaxBatchLookahead; - }; - - GrDrawTarget(GrRenderTarget*, GrGpu*, GrResourceProvider*, GrAuditTrail*, const Options&); - - ~GrDrawTarget() override; - - void makeClosed() { - fLastFullClearBatch = nullptr; - // We only close drawTargets When MDB is enabled. When MDB is disabled there is only - // ever one drawTarget and all calls will be funnelled into it. -#ifdef ENABLE_MDB - this->setFlag(kClosed_Flag); -#endif - this->forwardCombine(); - } - - bool isClosed() const { return this->isSetFlag(kClosed_Flag); } - - // TODO: this entry point is only needed in the non-MDB world. Remove when - // we make the switch to MDB - void clearRT() { fRenderTarget = nullptr; } - - /* - * Notify this drawTarget that it relies on the contents of 'dependedOn' - */ - void addDependency(GrSurface* dependedOn); - - /* - * Does this drawTarget depend on 'dependedOn'? - */ - bool dependsOn(GrDrawTarget* dependedOn) const { - return fDependencies.find(dependedOn) >= 0; - } - - /* - * Dump out the drawTarget dependency DAG - */ - SkDEBUGCODE(void dump() const;) - - /** - * Empties the draw buffer of any queued up draws. - */ - void reset(); - - /** - * Together these two functions flush all queued up draws to GrCommandBuffer. The return value - * of drawBatches() indicates whether any commands were actually issued to the GPU. - */ - void prepareBatches(GrBatchFlushState* flushState); - bool drawBatches(GrBatchFlushState* flushState); - - /** - * Gets the capabilities of the draw target. - */ - const GrCaps* caps() const { return fGpu->caps(); } - - void drawBatch(const GrPipelineBuilder&, GrDrawContext*, const GrClip&, GrDrawBatch*); - - void addBatch(sk_sp); - - /** - * Draws the path into user stencil bits. Upon return, all user stencil values - * inside the path will be nonzero. The path's fill must be either even/odd or - * winding (notnverse or hairline).It will respect the HW antialias boolean (if - * possible in the 3D API). Note, we will never have an inverse fill with - * stencil path. - */ - void stencilPath(GrDrawContext*, - const GrClip&, - bool useHWAA, - const SkMatrix& viewMatrix, - const GrPath*); - - /** Clears the entire render target */ - void fullClear(GrRenderTarget*, GrColor color); - - /** Discards the contents render target. */ - void discard(GrRenderTarget*); - - /** - * Copies a pixel rectangle from one surface to another. This call may finalize - * reserved vertex/index data (as though a draw call was made). The src pixels - * copied are specified by srcRect. They are copied to a rect of the same - * size in dst with top left at dstPoint. If the src rect is clipped by the - * src bounds then pixel values in the dst rect corresponding to area clipped - * by the src rect are not overwritten. This method is not guaranteed to succeed - * depending on the type of surface, configs, etc, and the backend-specific - * limitations. - */ - bool copySurface(GrSurface* dst, - GrSurface* src, - const SkIRect& srcRect, - const SkIPoint& dstPoint); - - gr_instanced::InstancedRendering* instancedRendering() const { - SkASSERT(fInstancedRendering); - return fInstancedRendering; - } - -private: - friend class GrDrawingManager; // for resetFlag & TopoSortTraits - friend class GrDrawContextPriv; // for clearStencilClip - - enum Flags { - kClosed_Flag = 0x01, //!< This drawTarget can't accept any more batches - - kWasOutput_Flag = 0x02, //!< Flag for topological sorting - kTempMark_Flag = 0x04, //!< Flag for topological sorting - }; - - void setFlag(uint32_t flag) { - fFlags |= flag; - } - - void resetFlag(uint32_t flag) { - fFlags &= ~flag; - } - - bool isSetFlag(uint32_t flag) const { - return SkToBool(fFlags & flag); - } - - struct TopoSortTraits { - static void Output(GrDrawTarget* dt, int /* index */) { - dt->setFlag(GrDrawTarget::kWasOutput_Flag); - } - static bool WasOutput(const GrDrawTarget* dt) { - return dt->isSetFlag(GrDrawTarget::kWasOutput_Flag); - } - static void SetTempMark(GrDrawTarget* dt) { - dt->setFlag(GrDrawTarget::kTempMark_Flag); - } - static void ResetTempMark(GrDrawTarget* dt) { - dt->resetFlag(GrDrawTarget::kTempMark_Flag); - } - static bool IsTempMarked(const GrDrawTarget* dt) { - return dt->isSetFlag(GrDrawTarget::kTempMark_Flag); - } - static int NumDependencies(const GrDrawTarget* dt) { - return dt->fDependencies.count(); - } - static GrDrawTarget* Dependency(GrDrawTarget* dt, int index) { - return dt->fDependencies[index]; - } - }; - - // Returns the batch that the input batch was combined with or the input batch if it wasn't - // combined. - GrBatch* recordBatch(GrBatch*, const SkRect& clippedBounds); - void forwardCombine(); - - // Makes a copy of the dst if it is necessary for the draw. Returns false if a copy is required - // but couldn't be made. Otherwise, returns true. This method needs to be protected because it - // needs to be accessed by GLPrograms to setup a correct drawstate - bool setupDstReadIfNecessary(const GrPipelineBuilder&, - GrRenderTarget*, - const GrClip&, - const GrPipelineOptimizations& optimizations, - GrXferProcessor::DstTexture*, - const SkRect& batchBounds); - - void addDependency(GrDrawTarget* dependedOn); - - // Used only by drawContextPriv. - void clearStencilClip(const GrFixedClip&, bool insideStencilMask, GrRenderTarget*); - - struct RecordedBatch { - sk_sp fBatch; - SkRect fClippedBounds; - }; - SkSTArray<256, RecordedBatch, true> fRecordedBatches; - GrClearBatch* fLastFullClearBatch; - // The context is only in service of the GrClip, remove once it doesn't need this. - GrContext* fContext; - GrGpu* fGpu; - GrResourceProvider* fResourceProvider; - GrAuditTrail* fAuditTrail; - - SkDEBUGCODE(int fDebugID;) - uint32_t fFlags; - - // 'this' drawTarget relies on the output of the drawTargets in 'fDependencies' - SkTDArray fDependencies; - GrRenderTarget* fRenderTarget; - - bool fClipBatchToBounds; - bool fDrawBatchBounds; - int fMaxBatchLookback; - int fMaxBatchLookahead; - - SkAutoTDelete fInstancedRendering; - - typedef SkRefCnt INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/GrDrawingManager.cpp b/gfx/skia/skia/src/gpu/GrDrawingManager.cpp index 5e9b68d88f3b..b64b9ee23aa7 100644 --- a/gfx/skia/skia/src/gpu/GrDrawingManager.cpp +++ b/gfx/skia/skia/src/gpu/GrDrawingManager.cpp @@ -8,34 +8,33 @@ #include "GrDrawingManager.h" #include "GrContext.h" -#include "GrDrawContext.h" -#include "GrDrawTarget.h" -#include "GrPathRenderingDrawContext.h" +#include "GrRenderTargetContext.h" +#include "GrPathRenderingRenderTargetContext.h" +#include "GrRenderTargetProxy.h" #include "GrResourceProvider.h" #include "GrSoftwarePathRenderer.h" #include "GrSurfacePriv.h" +#include "GrSurfaceProxyPriv.h" +#include "GrTextureContext.h" +#include "GrTextureOpList.h" #include "SkSurface_Gpu.h" #include "SkTTopoSort.h" -#include "instanced/InstancedRendering.h" - #include "text/GrAtlasTextContext.h" #include "text/GrStencilAndCoverTextContext.h" -using gr_instanced::InstancedRendering; - void GrDrawingManager::cleanup() { - for (int i = 0; i < fDrawTargets.count(); ++i) { - fDrawTargets[i]->makeClosed(); // no drawTarget should receive a new command after this - fDrawTargets[i]->clearRT(); + for (int i = 0; i < fOpLists.count(); ++i) { + fOpLists[i]->makeClosed(); // no opList should receive a new command after this + fOpLists[i]->clearTarget(); - // We shouldn't need to do this, but it turns out some clients still hold onto drawtargets + // We shouldn't need to do this, but it turns out some clients still hold onto opLists // after a cleanup - fDrawTargets[i]->reset(); - fDrawTargets[i]->unref(); + fOpLists[i]->reset(); + fOpLists[i]->unref(); } - fDrawTargets.reset(); + fOpLists.reset(); delete fPathRendererChain; fPathRendererChain = nullptr; @@ -48,11 +47,8 @@ GrDrawingManager::~GrDrawingManager() { void GrDrawingManager::abandon() { fAbandoned = true; - for (int i = 0; i < fDrawTargets.count(); ++i) { - if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) { - InstancedRendering* ir = fDrawTargets[i]->instancedRendering(); - ir->resetGpuResources(InstancedRendering::ResetType::kAbandon); - } + for (int i = 0; i < fOpLists.count(); ++i) { + fOpLists[i]->abandonGpuResources(); } this->cleanup(); } @@ -62,70 +58,111 @@ void GrDrawingManager::freeGpuResources() { delete fPathRendererChain; fPathRendererChain = nullptr; SkSafeSetNull(fSoftwarePathRenderer); - for (int i = 0; i < fDrawTargets.count(); ++i) { - if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) { - InstancedRendering* ir = fDrawTargets[i]->instancedRendering(); - ir->resetGpuResources(InstancedRendering::ResetType::kDestroy); - } + for (int i = 0; i < fOpLists.count(); ++i) { + fOpLists[i]->freeGpuResources(); } } void GrDrawingManager::reset() { - for (int i = 0; i < fDrawTargets.count(); ++i) { - fDrawTargets[i]->reset(); + for (int i = 0; i < fOpLists.count(); ++i) { + fOpLists[i]->reset(); } fFlushState.reset(); } -void GrDrawingManager::internalFlush(GrResourceCache::FlushType type) { +// MDB TODO: make use of the 'proxy' parameter. +void GrDrawingManager::internalFlush(GrSurfaceProxy*, GrResourceCache::FlushType type) { if (fFlushing || this->wasAbandoned()) { return; } fFlushing = true; bool flushed = false; - SkDEBUGCODE(bool result =) - SkTTopoSort(&fDrawTargets); - SkASSERT(result); - for (int i = 0; i < fDrawTargets.count(); ++i) { - fDrawTargets[i]->prepareBatches(&fFlushState); + for (int i = 0; i < fOpLists.count(); ++i) { + // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh + // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed + // but need to be flushed anyway. Closing such GrOpLists here will mean new + // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again. + fOpLists[i]->makeClosed(); + } + + SkDEBUGCODE(bool result =) + SkTTopoSort(&fOpLists); + SkASSERT(result); + + GrPreFlushResourceProvider preFlushProvider(this); + + if (fPreFlushCBObjects.count()) { + // MDB TODO: pre-MDB '1' is the correct pre-allocated size. Post-MDB it will need + // to be larger. + SkAutoSTArray<1, uint32_t> opListIds(fOpLists.count()); + for (int i = 0; i < fOpLists.count(); ++i) { + opListIds[i] = fOpLists[i]->uniqueID(); + } + + SkSTArray<1, sk_sp> renderTargetContexts; + for (int i = 0; i < fPreFlushCBObjects.count(); ++i) { + fPreFlushCBObjects[i]->preFlush(&preFlushProvider, + opListIds.get(), opListIds.count(), + &renderTargetContexts); + if (!renderTargetContexts.count()) { + continue; // This is fine. No atlases of this type are required for this flush + } + + for (int j = 0; j < renderTargetContexts.count(); ++j) { + GrRenderTargetOpList* opList = renderTargetContexts[j]->getOpList(); + if (!opList) { + continue; // Odd - but not a big deal + } + SkDEBUGCODE(opList->validateTargetsSingleRenderTarget()); + opList->prepareOps(&fFlushState); + if (!opList->executeOps(&fFlushState)) { + continue; // This is bad + } + } + renderTargetContexts.reset(); + } + } + + for (int i = 0; i < fOpLists.count(); ++i) { + fOpLists[i]->prepareOps(&fFlushState); } - // Enable this to print out verbose batching information #if 0 - for (int i = 0; i < fDrawTargets.count(); ++i) { - SkDEBUGCODE(fDrawTargets[i]->dump();) + // Enable this to print out verbose GrOp information + for (int i = 0; i < fOpLists.count(); ++i) { + SkDEBUGCODE(fOpLists[i]->dump();) } #endif // Upload all data to the GPU fFlushState.preIssueDraws(); - for (int i = 0; i < fDrawTargets.count(); ++i) { - if (fDrawTargets[i]->drawBatches(&fFlushState)) { + for (int i = 0; i < fOpLists.count(); ++i) { + if (fOpLists[i]->executeOps(&fFlushState)) { flushed = true; } } SkASSERT(fFlushState.nextDrawToken() == fFlushState.nextTokenToFlush()); - for (int i = 0; i < fDrawTargets.count(); ++i) { - fDrawTargets[i]->reset(); + for (int i = 0; i < fOpLists.count(); ++i) { + fOpLists[i]->reset(); #ifdef ENABLE_MDB - fDrawTargets[i]->unref(); + fOpLists[i]->unref(); #endif } #ifndef ENABLE_MDB - // When MDB is disabled we keep reusing the same drawTarget - if (fDrawTargets.count()) { - SkASSERT(fDrawTargets.count() == 1); + // When MDB is disabled we keep reusing the same GrOpList + if (fOpLists.count()) { + SkASSERT(fOpLists.count() == 1); // Clear out this flag so the topological sort's SkTTopoSort_CheckAllUnmarked check // won't bark - fDrawTargets[0]->resetFlag(GrDrawTarget::kWasOutput_Flag); + fOpLists[0]->resetFlag(GrOpList::kWasOutput_Flag); } #else - fDrawTargets.reset(); + fOpLists.reset(); #endif fFlushState.reset(); @@ -136,45 +173,75 @@ void GrDrawingManager::internalFlush(GrResourceCache::FlushType type) { fFlushing = false; } -void GrDrawingManager::prepareSurfaceForExternalIO(GrSurface* surface) { +void GrDrawingManager::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) { if (this->wasAbandoned()) { return; } - SkASSERT(surface); - SkASSERT(surface->getContext() == fContext); + SkASSERT(proxy); - if (surface->surfacePriv().hasPendingIO()) { - this->flush(); + if (proxy->priv().hasPendingIO()) { + this->flush(proxy); } - GrRenderTarget* rt = surface->asRenderTarget(); - if (fContext->getGpu() && rt) { - fContext->getGpu()->resolveRenderTarget(rt); + GrSurface* surface = proxy->instantiate(fContext->resourceProvider()); + if (!surface) { + return; + } + + if (fContext->getGpu() && surface->asRenderTarget()) { + fContext->getGpu()->resolveRenderTarget(surface->asRenderTarget()); } } -GrDrawTarget* GrDrawingManager::newDrawTarget(GrRenderTarget* rt) { +void GrDrawingManager::addPreFlushCallbackObject(sk_sp preFlushCBObject) { + fPreFlushCBObjects.push_back(preFlushCBObject); +} + +GrRenderTargetOpList* GrDrawingManager::newOpList(GrRenderTargetProxy* rtp) { SkASSERT(fContext); #ifndef ENABLE_MDB - // When MDB is disabled we always just return the single drawTarget - if (fDrawTargets.count()) { - SkASSERT(fDrawTargets.count() == 1); - // In the non-MDB-world the same drawTarget gets reused for multiple render targets. + // When MDB is disabled we always just return the single GrOpList + if (fOpLists.count()) { + SkASSERT(fOpLists.count() == 1); + // In the non-MDB-world the same GrOpList gets reused for multiple render targets. // Update this pointer so all the asserts are happy - rt->setLastDrawTarget(fDrawTargets[0]); + rtp->setLastOpList(fOpLists[0]); // DrawingManager gets the creation ref - this ref is for the caller - return SkRef(fDrawTargets[0]); + + // TODO: although this is true right now it isn't cool + return SkRef((GrRenderTargetOpList*) fOpLists[0]); } #endif - GrDrawTarget* dt = new GrDrawTarget(rt, fContext->getGpu(), fContext->resourceProvider(), - fContext->getAuditTrail(), fOptionsForDrawTargets); + GrRenderTargetOpList* opList = new GrRenderTargetOpList(rtp, + fContext->getGpu(), + fContext->resourceProvider(), + fContext->getAuditTrail(), + fOptionsForOpLists); - *fDrawTargets.append() = dt; + *fOpLists.append() = opList; // DrawingManager gets the creation ref - this ref is for the caller - return SkRef(dt); + return SkRef(opList); +} + +GrTextureOpList* GrDrawingManager::newOpList(GrTextureProxy* textureProxy) { + SkASSERT(fContext); + + GrTextureOpList* opList = new GrTextureOpList(textureProxy, fContext->getGpu(), + fContext->getAuditTrail()); + +#ifndef ENABLE_MDB + // When MDB is disabled we still create a new GrOpList, but don't store or ref it - we rely + // on the caller to immediately execute and free it. + return opList; +#else + *fOpLists.append() = opList; + + // Drawing manager gets the creation ref - this ref is for the caller + return SkRef(opList); +#endif } GrAtlasTextContext* GrDrawingManager::getAtlasTextContext() { @@ -204,48 +271,84 @@ GrPathRenderer* GrDrawingManager::getPathRenderer(const GrPathRenderer::CanDrawP if (!pr && allowSW) { if (!fSoftwarePathRenderer) { fSoftwarePathRenderer = - new GrSoftwarePathRenderer(fContext->textureProvider(), + new GrSoftwarePathRenderer(fContext->resourceProvider(), fOptionsForPathRendererChain.fAllowPathMaskCaching); } - pr = fSoftwarePathRenderer; + if (fSoftwarePathRenderer->canDrawPath(args)) { + pr = fSoftwarePathRenderer; + } } return pr; } -sk_sp GrDrawingManager::makeDrawContext(sk_sp rt, - sk_sp colorSpace, - const SkSurfaceProps* surfaceProps) { - if (this->wasAbandoned()) { +sk_sp GrDrawingManager::makeRenderTargetContext( + sk_sp sProxy, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps) { + if (this->wasAbandoned() || !sProxy->asRenderTargetProxy()) { return nullptr; } // SkSurface catches bad color space usage at creation. This check handles anything that slips // by, including internal usage. We allow a null color space here, for read/write pixels and // other special code paths. If a color space is provided, though, enforce all other rules. - if (colorSpace && !SkSurface_Gpu::Valid(fContext, rt->config(), colorSpace.get())) { + if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) { SkDEBUGFAIL("Invalid config and colorspace combination"); return nullptr; } + sk_sp rtp(sk_ref_sp(sProxy->asRenderTargetProxy())); + bool useDIF = false; if (surfaceProps) { useDIF = surfaceProps->isUseDeviceIndependentFonts(); } if (useDIF && fContext->caps()->shaderCaps()->pathRenderingSupport() && - rt->isStencilBufferMultisampled()) { + rtp->isStencilBufferMultisampled()) { + // TODO: defer stencil buffer attachment for PathRenderingDrawContext + sk_sp rt(sk_ref_sp(rtp->instantiate(fContext->resourceProvider()))); + if (!rt) { + return nullptr; + } GrStencilAttachment* sb = fContext->resourceProvider()->attachStencilAttachment(rt.get()); if (sb) { - return sk_sp(new GrPathRenderingDrawContext( - fContext, this, std::move(rt), + return sk_sp(new GrPathRenderingRenderTargetContext( + fContext, this, std::move(rtp), std::move(colorSpace), surfaceProps, fContext->getAuditTrail(), fSingleOwner)); } } - return sk_sp(new GrDrawContext(fContext, this, std::move(rt), - std::move(colorSpace), surfaceProps, - fContext->getAuditTrail(), - fSingleOwner)); + return sk_sp(new GrRenderTargetContext(fContext, this, std::move(rtp), + std::move(colorSpace), + surfaceProps, + fContext->getAuditTrail(), + fSingleOwner)); +} + +sk_sp GrDrawingManager::makeTextureContext(sk_sp sProxy, + sk_sp colorSpace) { + if (this->wasAbandoned() || !sProxy->asTextureProxy()) { + return nullptr; + } + + // SkSurface catches bad color space usage at creation. This check handles anything that slips + // by, including internal usage. We allow a null color space here, for read/write pixels and + // other special code paths. If a color space is provided, though, enforce all other rules. + if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) { + SkDEBUGFAIL("Invalid config and colorspace combination"); + return nullptr; + } + + // GrTextureRenderTargets should always be using GrRenderTargetContext + SkASSERT(!sProxy->asRenderTargetProxy()); + + sk_sp textureProxy(sk_ref_sp(sProxy->asTextureProxy())); + + return sk_sp(new GrTextureContext(fContext, this, std::move(textureProxy), + std::move(colorSpace), + fContext->getAuditTrail(), + fSingleOwner)); } diff --git a/gfx/skia/skia/src/gpu/GrDrawingManager.h b/gfx/skia/skia/src/gpu/GrDrawingManager.h index 9fced38163cc..f30273f7f1a3 100644 --- a/gfx/skia/skia/src/gpu/GrDrawingManager.h +++ b/gfx/skia/skia/src/gpu/GrDrawingManager.h @@ -8,24 +8,28 @@ #ifndef GrDrawingManager_DEFINED #define GrDrawingManager_DEFINED -#include "text/GrAtlasTextContext.h" -#include "GrDrawTarget.h" -#include "GrBatchFlushState.h" -#include "GrPathRendererChain.h" +#include "GrOpFlushState.h" #include "GrPathRenderer.h" +#include "GrPathRendererChain.h" +#include "GrPreFlushResourceProvider.h" +#include "GrRenderTargetOpList.h" #include "GrResourceCache.h" -#include "SkTDArray.h" +#include "SkTArray.h" +#include "text/GrAtlasTextContext.h" class GrContext; -class GrDrawContext; +class GrRenderTargetContext; +class GrRenderTargetProxy; class GrSingleOWner; class GrSoftwarePathRenderer; +class GrTextureContext; +class GrTextureOpList; -// The GrDrawingManager allocates a new GrDrawContext for each GrRenderTarget -// but all of them still land in the same GrDrawTarget! +// The GrDrawingManager allocates a new GrRenderTargetContext for each GrRenderTarget +// but all of them still land in the same GrOpList! // -// In the future this class will allocate a new GrDrawContext for -// each GrRenderTarget/GrDrawTarget and manage the DAG. +// In the future this class will allocate a new GrRenderTargetContext for +// each GrRenderTarget/GrOpList and manage the DAG. class GrDrawingManager { public: ~GrDrawingManager(); @@ -33,13 +37,15 @@ public: bool wasAbandoned() const { return fAbandoned; } void freeGpuResources(); - sk_sp makeDrawContext(sk_sp rt, - sk_sp, - const SkSurfaceProps*); + sk_sp makeRenderTargetContext(sk_sp, + sk_sp, + const SkSurfaceProps*); + sk_sp makeTextureContext(sk_sp, sk_sp); - // The caller automatically gets a ref on the returned drawTarget. It must + // The caller automatically gets a ref on the returned opList. It must // be balanced by an unref call. - GrDrawTarget* newDrawTarget(GrRenderTarget* rt); + GrRenderTargetOpList* newOpList(GrRenderTargetProxy* rtp); + GrTextureOpList* newOpList(GrTextureProxy* textureProxy); GrContext* getContext() { return fContext; } @@ -52,22 +58,25 @@ public: void flushIfNecessary() { if (fContext->getResourceCache()->requestsFlush()) { - this->internalFlush(GrResourceCache::kCacheRequested); + this->internalFlush(nullptr, GrResourceCache::kCacheRequested); } else if (fIsImmediateMode) { - this->internalFlush(GrResourceCache::kImmediateMode); + this->internalFlush(nullptr, GrResourceCache::kImmediateMode); } } static bool ProgramUnitTest(GrContext* context, int maxStages); - void prepareSurfaceForExternalIO(GrSurface*); + void prepareSurfaceForExternalIO(GrSurfaceProxy*); + + void addPreFlushCallbackObject(sk_sp preFlushCBObject); private: - GrDrawingManager(GrContext* context, const GrDrawTarget::Options& optionsForDrawTargets, + GrDrawingManager(GrContext* context, + const GrRenderTargetOpList::Options& optionsForOpLists, const GrPathRendererChain::Options& optionsForPathRendererChain, bool isImmediateMode, GrSingleOwner* singleOwner) : fContext(context) - , fOptionsForDrawTargets(optionsForDrawTargets) + , fOptionsForOpLists(optionsForOpLists) , fOptionsForPathRendererChain(optionsForPathRendererChain) , fSingleOwner(singleOwner) , fAbandoned(false) @@ -82,33 +91,39 @@ private: void abandon(); void cleanup(); void reset(); - void flush() { this->internalFlush(GrResourceCache::FlushType::kExternal); } - void internalFlush(GrResourceCache::FlushType); + void flush(GrSurfaceProxy* proxy) { + this->internalFlush(proxy, GrResourceCache::FlushType::kExternal); + } + void internalFlush(GrSurfaceProxy*, GrResourceCache::FlushType); friend class GrContext; // for access to: ctor, abandon, reset & flush + friend class GrContextPriv; // access to: flush + friend class GrPreFlushResourceProvider; // this is just a shallow wrapper around this class static const int kNumPixelGeometries = 5; // The different pixel geometries static const int kNumDFTOptions = 2; // DFT or no DFT GrContext* fContext; - GrDrawTarget::Options fOptionsForDrawTargets; + GrRenderTargetOpList::Options fOptionsForOpLists; GrPathRendererChain::Options fOptionsForPathRendererChain; // In debug builds we guard against improper thread handling GrSingleOwner* fSingleOwner; bool fAbandoned; - SkTDArray fDrawTargets; + SkTDArray fOpLists; - SkAutoTDelete fAtlasTextContext; + std::unique_ptr fAtlasTextContext; GrPathRendererChain* fPathRendererChain; GrSoftwarePathRenderer* fSoftwarePathRenderer; - GrBatchFlushState fFlushState; + GrOpFlushState fFlushState; bool fFlushing; bool fIsImmediateMode; + + SkTArray> fPreFlushCBObjects; }; #endif diff --git a/gfx/skia/skia/src/gpu/GrFixedClip.cpp b/gfx/skia/skia/src/gpu/GrFixedClip.cpp index 7385028bafb0..e551f9b966ba 100644 --- a/gfx/skia/skia/src/gpu/GrFixedClip.cpp +++ b/gfx/skia/skia/src/gpu/GrFixedClip.cpp @@ -8,7 +8,7 @@ #include "GrFixedClip.h" #include "GrAppliedClip.h" -#include "GrDrawContext.h" +#include "GrRenderTargetContext.h" bool GrFixedClip::quickContains(const SkRect& rect) const { if (fWindowRectsState.enabled()) { @@ -29,7 +29,7 @@ void GrFixedClip::getConservativeBounds(int w, int h, SkIRect* devResult, bool* } } -bool GrFixedClip::isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const { +bool GrFixedClip::isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA* aa) const { if (fWindowRectsState.enabled()) { return false; } @@ -39,23 +39,24 @@ bool GrFixedClip::isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const { return false; } rr->setRect(rect); - *aa = false; + *aa = GrAA::kNo; return true; } return false; }; -bool GrFixedClip::apply(GrContext*, GrDrawContext* dc, bool, bool, GrAppliedClip* out) const { +bool GrFixedClip::apply(GrContext*, GrRenderTargetContext* rtc, bool, bool, GrAppliedClip* out, + SkRect* bounds) const { if (fScissorState.enabled()) { - SkIRect tightScissor = SkIRect::MakeWH(dc->width(), dc->height()); + SkIRect tightScissor = SkIRect::MakeWH(rtc->width(), rtc->height()); if (!tightScissor.intersect(fScissorState.rect())) { return false; } - if (IsOutsideClip(tightScissor, out->clippedDrawBounds())) { + if (IsOutsideClip(tightScissor, *bounds)) { return false; } - if (!IsInsideClip(fScissorState.rect(), out->clippedDrawBounds())) { - out->addScissor(tightScissor); + if (!IsInsideClip(fScissorState.rect(), *bounds)) { + out->addScissor(tightScissor, bounds); } } diff --git a/gfx/skia/skia/src/gpu/GrFixedClip.h b/gfx/skia/skia/src/gpu/GrFixedClip.h index 6fb7d23ed1a3..744bb27a81ac 100644 --- a/gfx/skia/skia/src/gpu/GrFixedClip.h +++ b/gfx/skia/skia/src/gpu/GrFixedClip.h @@ -35,15 +35,15 @@ public: void disableWindowRectangles() { fWindowRectsState.setDisabled(); } - void setWindowRectangles(const GrWindowRectangles& windows, const SkIPoint& origin, - GrWindowRectsState::Mode mode) { - fWindowRectsState.set(windows, origin, mode); + void setWindowRectangles(const GrWindowRectangles& windows, GrWindowRectsState::Mode mode) { + fWindowRectsState.set(windows, mode); } bool quickContains(const SkRect&) const override; void getConservativeBounds(int w, int h, SkIRect* devResult, bool* iior) const override; - bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const override; - bool apply(GrContext*, GrDrawContext*, bool, bool, GrAppliedClip* out) const override; + bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const override; + bool apply(GrContext*, GrRenderTargetContext*, bool, bool, GrAppliedClip*, + SkRect*) const override; static const GrFixedClip& Disabled(); diff --git a/gfx/skia/skia/src/gpu/GrFragmentProcessor.cpp b/gfx/skia/skia/src/gpu/GrFragmentProcessor.cpp index 123792d2514a..352946731b2d 100644 --- a/gfx/skia/skia/src/gpu/GrFragmentProcessor.cpp +++ b/gfx/skia/skia/src/gpu/GrFragmentProcessor.cpp @@ -7,15 +7,14 @@ #include "GrFragmentProcessor.h" #include "GrCoordTransform.h" -#include "GrInvariantOutput.h" #include "GrPipeline.h" -#include "GrProcOptInfo.h" +#include "GrProcessorAnalysis.h" +#include "effects/GrConstColorProcessor.h" +#include "effects/GrXfermodeFragmentProcessor.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" -#include "effects/GrConstColorProcessor.h" -#include "effects/GrXfermodeFragmentProcessor.h" GrFragmentProcessor::~GrFragmentProcessor() { // If we got here then our ref count must have reached zero, so we will have converted refs @@ -27,7 +26,7 @@ GrFragmentProcessor::~GrFragmentProcessor() { bool GrFragmentProcessor::isEqual(const GrFragmentProcessor& that) const { if (this->classID() != that.classID() || - !this->hasSameSamplers(that)) { + !this->hasSameSamplersAndAccesses(that)) { return false; } if (!this->hasSameTransforms(that)) { @@ -56,17 +55,9 @@ GrGLSLFragmentProcessor* GrFragmentProcessor::createGLSLInstance() const { return glFragProc; } -void GrFragmentProcessor::addTextureAccess(const GrTextureAccess* textureAccess) { - INHERITED::addTextureAccess(textureAccess); -} - -void GrFragmentProcessor::addBufferAccess(const GrBufferAccess* bufferAccess) { - INHERITED::addBufferAccess(bufferAccess); -} - void GrFragmentProcessor::addCoordTransform(const GrCoordTransform* transform) { fCoordTransforms.push_back(transform); - fUsesLocalCoords = true; + fFlags |= kUsesLocalCoords_Flag; SkDEBUGCODE(transform->setInProcessor();) } @@ -74,10 +65,10 @@ int GrFragmentProcessor::registerChildProcessor(sk_sp child this->combineRequiredFeatures(*child); if (child->usesLocalCoords()) { - fUsesLocalCoords = true; + fFlags |= kUsesLocalCoords_Flag; } if (child->usesDistanceVectorField()) { - fUsesDistanceVectorField = true; + fFlags |= kUsesDistanceVectorField_Flag; } int index = fChildProcessors.count(); @@ -100,7 +91,7 @@ bool GrFragmentProcessor::hasSameTransforms(const GrFragmentProcessor& that) con } int count = this->numCoordTransforms(); for (int i = 0; i < count; ++i) { - if (this->coordTransform(i) != that.coordTransform(i)) { + if (!this->coordTransform(i).hasSameEffectAs(that.coordTransform(i))) { return false; } } @@ -112,43 +103,87 @@ sk_sp GrFragmentProcessor::MulOutputByInputAlpha( if (!fp) { return nullptr; } - return GrXfermodeFragmentProcessor::MakeFromDstProcessor(std::move(fp), - SkXfermode::kDstIn_Mode); + return GrXfermodeFragmentProcessor::MakeFromDstProcessor(std::move(fp), SkBlendMode::kDstIn); +} + +namespace { + +class PremulInputFragmentProcessor : public GrFragmentProcessor { +public: + PremulInputFragmentProcessor() + : INHERITED(kPreservesOpaqueInput_OptimizationFlag | + kConstantOutputForConstantInput_OptimizationFlag) { + this->initClassID(); + } + + const char* name() const override { return "PremultiplyInput"; } + +private: + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { + class GLFP : public GrGLSLFragmentProcessor { + public: + void emitCode(EmitArgs& args) override { + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, args.fInputColor); + fragBuilder->codeAppendf("%s.rgb *= %s.a;", + args.fOutputColor, args.fInputColor); + } + }; + return new GLFP; + } + + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} + + bool onIsEqual(const GrFragmentProcessor&) const override { return true; } + + GrColor4f constantOutputForConstantInput(GrColor4f input) const override { + return input.premul(); + } + + typedef GrFragmentProcessor INHERITED; +}; + +class UnpremulInputFragmentProcessor : public GrFragmentProcessor { +public: + UnpremulInputFragmentProcessor() + : INHERITED(kPreservesOpaqueInput_OptimizationFlag | + kConstantOutputForConstantInput_OptimizationFlag) { + this->initClassID(); + } + + const char* name() const override { return "UnpremultiplyInput"; } + +private: + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { + class GLFP : public GrGLSLFragmentProcessor { + public: + void emitCode(EmitArgs& args) override { + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, args.fInputColor); + fragBuilder->codeAppendf("float invAlpha = %s.a <= 0.0 ? 0.0 : 1.0 / %s.a;", + args.fInputColor, args.fInputColor); + fragBuilder->codeAppendf("%s.rgb *= invAlpha;", args.fOutputColor); + } + }; + return new GLFP; + } + + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} + + bool onIsEqual(const GrFragmentProcessor&) const override { return true; } + + GrColor4f constantOutputForConstantInput(GrColor4f input) const override { + return input.unpremul(); + } + + typedef GrFragmentProcessor INHERITED; +}; + } sk_sp GrFragmentProcessor::PremulInput(sk_sp fp) { - - class PremulInputFragmentProcessor : public GrFragmentProcessor { - public: - PremulInputFragmentProcessor() { - this->initClassID(); - } - - const char* name() const override { return "PremultiplyInput"; } - - private: - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { - class GLFP : public GrGLSLFragmentProcessor { - public: - void emitCode(EmitArgs& args) override { - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - - fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, args.fInputColor); - fragBuilder->codeAppendf("%s.rgb *= %s.a;", - args.fOutputColor, args.fInputColor); - } - }; - return new GLFP; - } - - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override {} - - bool onIsEqual(const GrFragmentProcessor&) const override { return true; } - - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->premulFourChannelColor(); - } - }; if (!fp) { return nullptr; } @@ -156,12 +191,86 @@ sk_sp GrFragmentProcessor::PremulInput(sk_sp GrFragmentProcessor::MulOutputByInputUnpremulColor( - sk_sp fp) { +sk_sp GrFragmentProcessor::PremulOutput(sk_sp fp) { + if (!fp) { + return nullptr; + } + sk_sp fpPipeline[] = { fp, sk_make_sp() }; + return GrFragmentProcessor::RunInSeries(fpPipeline, 2); +} + +sk_sp GrFragmentProcessor::UnpremulOutput(sk_sp fp) { + if (!fp) { + return nullptr; + } + sk_sp fpPipeline[] = { fp, sk_make_sp() }; + return GrFragmentProcessor::RunInSeries(fpPipeline, 2); +} + +sk_sp GrFragmentProcessor::SwizzleOutput(sk_sp fp, + const GrSwizzle& swizzle) { + class SwizzleFragmentProcessor : public GrFragmentProcessor { + public: + SwizzleFragmentProcessor(const GrSwizzle& swizzle) + : INHERITED(kAll_OptimizationFlags) + , fSwizzle(swizzle) { + this->initClassID(); + } + + const char* name() const override { return "Swizzle"; } + const GrSwizzle& swizzle() const { return fSwizzle; } + + private: + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { + class GLFP : public GrGLSLFragmentProcessor { + public: + void emitCode(EmitArgs& args) override { + const SwizzleFragmentProcessor& sfp = args.fFp.cast(); + const GrSwizzle& swizzle = sfp.swizzle(); + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + + fragBuilder->codeAppendf("%s = %s.%s;", + args.fOutputColor, args.fInputColor, swizzle.c_str()); + } + }; + return new GLFP; + } + + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { + b->add32(fSwizzle.asKey()); + } + + bool onIsEqual(const GrFragmentProcessor& other) const override { + const SwizzleFragmentProcessor& sfp = other.cast(); + return fSwizzle == sfp.fSwizzle; + } + + GrColor4f constantOutputForConstantInput(GrColor4f input) const override { + return fSwizzle.applyTo(input); + } + + GrSwizzle fSwizzle; + + typedef GrFragmentProcessor INHERITED; + }; + + if (!fp) { + return nullptr; + } + if (GrSwizzle::RGBA() == swizzle) { + return fp; + } + sk_sp fpPipeline[] = { fp, sk_make_sp(swizzle) }; + return GrFragmentProcessor::RunInSeries(fpPipeline, 2); +} + +sk_sp GrFragmentProcessor::MakeInputPremulAndMulByOutput( + sk_sp fp) { class PremulFragmentProcessor : public GrFragmentProcessor { public: - PremulFragmentProcessor(sk_sp processor) { + PremulFragmentProcessor(sk_sp processor) + : INHERITED(OptFlags(processor.get())) { this->initClassID(); this->registerChildProcessor(processor); } @@ -183,42 +292,31 @@ sk_sp GrFragmentProcessor::MulOutputByInputUnpremulColor( return new GLFP; } - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override {} + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} bool onIsEqual(const GrFragmentProcessor&) const override { return true; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - // TODO: Add a helper to GrInvariantOutput that handles multiplying by color with flags? - if (!(inout->validFlags() & kA_GrColorComponentFlag)) { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); - return; + static OptimizationFlags OptFlags(const GrFragmentProcessor* inner) { + OptimizationFlags flags = kNone_OptimizationFlags; + if (inner->preservesOpaqueInput()) { + flags |= kPreservesOpaqueInput_OptimizationFlag; } - - GrInvariantOutput childOutput(GrColor_WHITE, kRGBA_GrColorComponentFlags, false); - this->childProcessor(0).computeInvariantOutput(&childOutput); - - if (0 == GrColorUnpackA(inout->color()) || 0 == GrColorUnpackA(childOutput.color())) { - inout->mulByKnownFourComponents(0x0); - return; + if (inner->hasConstantOutputForConstantInput()) { + flags |= kConstantOutputForConstantInput_OptimizationFlag; } - GrColorComponentFlags commonFlags = childOutput.validFlags() & inout->validFlags(); - GrColor c0 = GrPremulColor(inout->color()); - GrColor c1 = childOutput.color(); - GrColor color = 0x0; - if (commonFlags & kR_GrColorComponentFlag) { - color |= SkMulDiv255Round(GrColorUnpackR(c0), GrColorUnpackR(c1)) << - GrColor_SHIFT_R; - } - if (commonFlags & kG_GrColorComponentFlag) { - color |= SkMulDiv255Round(GrColorUnpackG(c0), GrColorUnpackG(c1)) << - GrColor_SHIFT_G; - } - if (commonFlags & kB_GrColorComponentFlag) { - color |= SkMulDiv255Round(GrColorUnpackB(c0), GrColorUnpackB(c1)) << - GrColor_SHIFT_B; - } - inout->setToOther(commonFlags, color, GrInvariantOutput::kWill_ReadInput); + return flags; } + + GrColor4f constantOutputForConstantInput(GrColor4f input) const override { + GrColor4f childColor = ConstantOutputForConstantInput(this->childProcessor(0), + GrColor4f::OpaqueWhite()); + return GrColor4f(input.fRGBA[3] * input.fRGBA[0] * childColor.fRGBA[0], + input.fRGBA[3] * input.fRGBA[1] * childColor.fRGBA[1], + input.fRGBA[3] * input.fRGBA[2] * childColor.fRGBA[2], + input.fRGBA[3] * childColor.fRGBA[3]); + } + + typedef GrFragmentProcessor INHERITED; }; if (!fp) { return nullptr; @@ -233,7 +331,7 @@ sk_sp GrFragmentProcessor::OverrideInput(sk_sp child, GrColor4f color) - : fColor(color) { + : INHERITED(OptFlags(child.get(), color)), fColor(color) { this->initClassID(); this->registerChildProcessor(std::move(child)); } @@ -255,7 +353,7 @@ sk_sp GrFragmentProcessor::OverrideInput(sk_sp().fColor; if (!fHaveSetColor || color != fPreviousColor) { pdman.set4fv(fColorUni, 1, color.fRGBA); @@ -273,36 +371,43 @@ sk_sp GrFragmentProcessor::OverrideInput(sk_spoptimizationFlags(); + OptimizationFlags flags = kNone_OptimizationFlags; + if (childFlags & kConstantOutputForConstantInput_OptimizationFlag) { + flags |= kConstantOutputForConstantInput_OptimizationFlag; + } + if ((childFlags & kPreservesOpaqueInput_OptimizationFlag) && color.isOpaque()) { + flags |= kPreservesOpaqueInput_OptimizationFlag; + } + return flags; + } + + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {} bool onIsEqual(const GrFragmentProcessor& that) const override { return fColor == that.cast().fColor; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->setToOther(kRGBA_GrColorComponentFlags, fColor.toGrColor(), - GrInvariantOutput::kWillNot_ReadInput); - this->childProcessor(0).computeInvariantOutput(inout); + GrColor4f constantOutputForConstantInput(GrColor4f) const override { + return ConstantOutputForConstantInput(this->childProcessor(0), fColor); } GrColor4f fColor; + + typedef GrFragmentProcessor INHERITED; }; - GrInvariantOutput childOut(0x0, kNone_GrColorComponentFlags, false); - fp->computeInvariantOutput(&childOut); - if (childOut.willUseInputColor()) { - return sk_sp(new ReplaceInputFragmentProcessor(std::move(fp), color)); - } else { - return fp; - } + return sk_sp(new ReplaceInputFragmentProcessor(std::move(fp), color)); } sk_sp GrFragmentProcessor::RunInSeries(sk_sp* series, int cnt) { class SeriesFragmentProcessor : public GrFragmentProcessor { public: - SeriesFragmentProcessor(sk_sp* children, int cnt){ + SeriesFragmentProcessor(sk_sp* children, int cnt) + : INHERITED(OptFlags(children, cnt)) { SkASSERT(cnt > 1); this->initClassID(); for (int i = 0; i < cnt; ++i) { @@ -331,55 +436,54 @@ sk_sp GrFragmentProcessor::RunInSeries(sk_sp* children, int cnt) { + OptimizationFlags flags = kAll_OptimizationFlags; + for (int i = 0; i < cnt && flags != kNone_OptimizationFlags; ++i) { + flags &= children[i]->optimizationFlags(); + } + return flags; + } + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} bool onIsEqual(const GrFragmentProcessor&) const override { return true; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - GrProcOptInfo info; - info.calcWithInitialValues(fChildProcessors.begin(), fChildProcessors.count(), - inout->color(), inout->validFlags(), false, false); - for (int i = 0; i < this->numChildProcessors(); ++i) { - this->childProcessor(i).computeInvariantOutput(inout); + GrColor4f constantOutputForConstantInput(GrColor4f color) const override { + int childCnt = this->numChildProcessors(); + for (int i = 0; i < childCnt; ++i) { + color = ConstantOutputForConstantInput(this->childProcessor(i), color); } + return color; } + + typedef GrFragmentProcessor INHERITED; }; if (!cnt) { return nullptr; } - - // Run the through the series, do the invariant output processing, and look for eliminations. - GrProcOptInfo info; - info.calcWithInitialValues(sk_sp_address_as_pointer_address(series), cnt, - 0x0, kNone_GrColorComponentFlags, false, false); - if (kRGBA_GrColorComponentFlags == info.validFlags()) { - return GrConstColorProcessor::Make(info.color(), GrConstColorProcessor::kIgnore_InputMode); + if (1 == cnt) { + return series[0]; } - + // Run the through the series, do the invariant output processing, and look for eliminations. + GrColorFragmentProcessorAnalysis info; + info.analyzeProcessors(sk_sp_address_as_pointer_address(series), cnt); SkTArray> replacementSeries; - - int firstIdx = info.firstEffectiveProcessorIndex(); - cnt -= firstIdx; - if (firstIdx > 0 && info.inputColorIsUsed()) { - sk_sp colorFP(GrConstColorProcessor::Make( - info.inputColorToFirstEffectiveProccesor(), GrConstColorProcessor::kIgnore_InputMode)); - cnt += 1; + GrColor4f knownColor; + int leadingFPsToEliminate = info.initialProcessorsToEliminate(&knownColor); + if (leadingFPsToEliminate) { + sk_sp colorFP( + GrConstColorProcessor::Make(knownColor, GrConstColorProcessor::kIgnore_InputMode)); + if (leadingFPsToEliminate == cnt) { + return colorFP; + } + cnt = cnt - leadingFPsToEliminate + 1; replacementSeries.reserve(cnt); replacementSeries.emplace_back(std::move(colorFP)); for (int i = 0; i < cnt - 1; ++i) { - replacementSeries.emplace_back(std::move(series[firstIdx + i])); + replacementSeries.emplace_back(std::move(series[leadingFPsToEliminate + i])); } series = replacementSeries.begin(); - } else { - series += firstIdx; - cnt -= firstIdx; - } - - if (1 == cnt) { - return series[0]; } return sk_sp(new SeriesFragmentProcessor(series, cnt)); } diff --git a/gfx/skia/skia/src/gpu/GrGeometryProcessor.h b/gfx/skia/skia/src/gpu/GrGeometryProcessor.h index bc6f6ebbe412..e5222bf80a41 100644 --- a/gfx/skia/skia/src/gpu/GrGeometryProcessor.h +++ b/gfx/skia/skia/src/gpu/GrGeometryProcessor.h @@ -51,6 +51,7 @@ protected: */ const Attribute& addVertexAttrib(const char* name, GrVertexAttribType type, GrSLPrecision precision = kDefault_GrSLPrecision) { + precision = (kDefault_GrSLPrecision == precision) ? kMedium_GrSLPrecision : precision; fAttribs.emplace_back(name, type, precision); fVertexStride += fAttribs.back().fOffset; return fAttribs.back(); @@ -64,7 +65,6 @@ protected: * 1) LocalCoordTransform * Position - in Shader * 2) LocalCoordTransform * ExplicitLocalCoords- in Shader * 3) A transformation on the CPU uploaded via vertex attribute - * TODO make this GrBatches responsibility */ enum LocalCoordsType { kUnused_LocalCoordsType, diff --git a/gfx/skia/skia/src/gpu/GrGlyph.h b/gfx/skia/skia/src/gpu/GrGlyph.h index 5e611ce16838..5005b74543ac 100644 --- a/gfx/skia/skia/src/gpu/GrGlyph.h +++ b/gfx/skia/skia/src/gpu/GrGlyph.h @@ -8,7 +8,7 @@ #ifndef GrGlyph_DEFINED #define GrGlyph_DEFINED -#include "GrBatchAtlas.h" +#include "GrDrawOpAtlas.h" #include "GrRect.h" #include "GrTypes.h" @@ -32,7 +32,7 @@ struct GrGlyph { typedef uint32_t PackedID; - GrBatchAtlas::AtlasID fID; + GrDrawOpAtlas::AtlasID fID; SkPath* fPath; PackedID fPackedID; GrMaskFormat fMaskFormat; @@ -41,13 +41,13 @@ struct GrGlyph { bool fTooLargeForAtlas; void init(GrGlyph::PackedID packed, const SkIRect& bounds, GrMaskFormat format) { - fID = GrBatchAtlas::kInvalidAtlasID; + fID = GrDrawOpAtlas::kInvalidAtlasID; fPath = nullptr; fPackedID = packed; fBounds.set(bounds); fMaskFormat = format; fAtlasLocation.set(0, 0); - fTooLargeForAtlas = GrBatchAtlas::GlyphTooLargeForAtlas(bounds.width(), bounds.height()); + fTooLargeForAtlas = GrDrawOpAtlas::GlyphTooLargeForAtlas(bounds.width(), bounds.height()); } void reset() { diff --git a/gfx/skia/skia/src/gpu/GrGpu.cpp b/gfx/skia/skia/src/gpu/GrGpu.cpp index 0de9fedb8c6d..b1560f9a2d5a 100644 --- a/gfx/skia/skia/src/gpu/GrGpu.cpp +++ b/gfx/skia/skia/src/gpu/GrGpu.cpp @@ -19,6 +19,7 @@ #include "GrResourceProvider.h" #include "GrRenderTargetPriv.h" #include "GrStencilAttachment.h" +#include "GrStencilSettings.h" #include "GrSurfacePriv.h" #include "GrTexturePriv.h" #include "SkMathPriv.h" @@ -56,21 +57,26 @@ void GrGpu::disconnect(DisconnectType) {} //////////////////////////////////////////////////////////////////////////////// -bool GrGpu::makeCopyForTextureParams(int width, int height, const GrTextureParams& textureParams, - GrTextureProducer::CopyParams* copyParams) const { +bool GrGpu::isACopyNeededForTextureParams(int width, int height, + const GrSamplerParams& textureParams, + GrTextureProducer::CopyParams* copyParams, + SkScalar scaleAdjust[2]) const { const GrCaps& caps = *this->caps(); if (textureParams.isTiled() && !caps.npotTextureTileSupport() && (!SkIsPow2(width) || !SkIsPow2(height))) { + SkASSERT(scaleAdjust); copyParams->fWidth = GrNextPow2(width); copyParams->fHeight = GrNextPow2(height); + scaleAdjust[0] = ((SkScalar) copyParams->fWidth) / width; + scaleAdjust[1] = ((SkScalar) copyParams->fHeight) / height; switch (textureParams.filterMode()) { - case GrTextureParams::kNone_FilterMode: - copyParams->fFilter = GrTextureParams::kNone_FilterMode; + case GrSamplerParams::kNone_FilterMode: + copyParams->fFilter = GrSamplerParams::kNone_FilterMode; break; - case GrTextureParams::kBilerp_FilterMode: - case GrTextureParams::kMipMap_FilterMode: + case GrSamplerParams::kBilerp_FilterMode: + case GrSamplerParams::kMipMap_FilterMode: // We are only ever scaling up so no reason to ever indicate kMipMap. - copyParams->fFilter = GrTextureParams::kBilerp_FilterMode; + copyParams->fFilter = GrSamplerParams::kBilerp_FilterMode; break; } return true; @@ -103,6 +109,10 @@ static bool check_texture_creation_params(const GrCaps& caps, const GrSurfaceDes return false; } + if (GrPixelConfigIsSint(desc.fConfig) && texels.count() > 1) { + return false; + } + *isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); if (*isRT && !caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { return false; @@ -178,19 +188,12 @@ GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budget fStats.incTextureUploads(); } } - // This is a current work around to get discards into newly created textures. Once we are in - // MDB world, we should remove this code a rely on the draw target having specified load - // operations. - if (isRT && texels.empty()) { - GrRenderTarget* rt = tex->asRenderTarget(); - SkASSERT(rt); - rt->discard(); - } } return tex; } -GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc, GrWrapOwnership ownership) { +sk_sp GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc, + GrWrapOwnership ownership) { this->handleDirtyContext(); if (!this->caps()->isConfigTexturable(desc.fConfig)) { return nullptr; @@ -203,30 +206,27 @@ GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc, GrWrapOwn if (desc.fWidth > maxSize || desc.fHeight > maxSize) { return nullptr; } - GrTexture* tex = this->onWrapBackendTexture(desc, ownership); - if (nullptr == tex) { + sk_sp tex = this->onWrapBackendTexture(desc, ownership); + if (!tex) { return nullptr; } // TODO: defer this and attach dynamically GrRenderTarget* tgt = tex->asRenderTarget(); if (tgt && !fContext->resourceProvider()->attachStencilAttachment(tgt)) { - tex->unref(); return nullptr; - } else { - return tex; } + return tex; } -GrRenderTarget* GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc, - GrWrapOwnership ownership) { +sk_sp GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) { if (!this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { return nullptr; } this->handleDirtyContext(); - return this->onWrapBackendRenderTarget(desc, ownership); + return this->onWrapBackendRenderTarget(desc); } -GrRenderTarget* GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc& desc) { +sk_sp GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc& desc) { this->handleDirtyContext(); if (!(desc.fFlags & kRenderTarget_GrBackendTextureFlag)) { return nullptr; @@ -262,6 +262,13 @@ bool GrGpu::copySurface(GrSurface* dst, const SkIPoint& dstPoint) { SkASSERT(dst && src); this->handleDirtyContext(); + // We don't allow conversion between integer configs and float/fixed configs. + if (GrPixelConfigIsSint(dst->config()) != GrPixelConfigIsSint(src->config())) { + return false; + } + if (GrPixelConfigIsCompressed(dst->config())) { + return false; + } return this->onCopySurface(dst, src, srcRect, dstPoint); } @@ -270,8 +277,14 @@ bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, int width, int height, size ReadPixelTempDrawInfo* tempDrawInfo) { SkASSERT(drawPreference); SkASSERT(tempDrawInfo); + SkASSERT(srcSurface); SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference); + // We don't allow conversion between integer configs and float/fixed configs. + if (GrPixelConfigIsSint(srcSurface->config()) != GrPixelConfigIsSint(readConfig)) { + return false; + } + // We currently do not support reading into a compressed buffer if (GrPixelConfigIsCompressed(readConfig)) { return false; @@ -305,6 +318,7 @@ bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, int width, int height, WritePixelTempDrawInfo* tempDrawInfo) { SkASSERT(drawPreference); SkASSERT(tempDrawInfo); + SkASSERT(dstSurface); SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference); if (GrPixelConfigIsCompressed(dstSurface->desc().fConfig) && @@ -312,6 +326,11 @@ bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, int width, int height, return false; } + // We don't allow conversion between integer configs and float/fixed configs. + if (GrPixelConfigIsSint(dstSurface->config()) != GrPixelConfigIsSint(srcConfig)) { + return false; + } + if (SkToBool(dstSurface->asRenderTarget())) { if (this->caps()->useDrawInsteadOfAllRenderTargetWrites()) { ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); @@ -343,7 +362,12 @@ bool GrGpu::readPixels(GrSurface* surface, int left, int top, int width, int height, GrPixelConfig config, void* buffer, size_t rowBytes) { - this->handleDirtyContext(); + SkASSERT(surface); + + // We don't allow conversion between integer configs and float/fixed configs. + if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) { + return false; + } // We cannot read pixels into a compressed buffer if (GrPixelConfigIsCompressed(config)) { @@ -358,6 +382,8 @@ bool GrGpu::readPixels(GrSurface* surface, return false; } + this->handleDirtyContext(); + return this->onReadPixels(surface, left, top, width, height, config, buffer, @@ -367,15 +393,18 @@ bool GrGpu::readPixels(GrSurface* surface, bool GrGpu::writePixels(GrSurface* surface, int left, int top, int width, int height, GrPixelConfig config, const SkTArray& texels) { - if (!surface) { - return false; - } + SkASSERT(surface); for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { if (!texels[currentMipLevel].fPixels ) { return false; } } + // We don't allow conversion between integer configs and float/fixed configs. + if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) { + return false; + } + this->handleDirtyContext(); if (this->onWritePixels(surface, left, top, width, height, config, texels)) { SkIRect rect = SkIRect::MakeXYWH(left, top, width, height); @@ -406,6 +435,11 @@ bool GrGpu::transferPixels(GrSurface* surface, SkASSERT(transferBuffer); SkASSERT(fence); + // We don't allow conversion between integer configs and float/fixed configs. + if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) { + return false; + } + this->handleDirtyContext(); if (this->onTransferPixels(surface, left, top, width, height, config, transferBuffer, offset, rowBytes)) { @@ -443,21 +477,21 @@ void GrGpu::didWriteToSurface(GrSurface* surface, const SkIRect* bounds, uint32_ } } -const GrGpu::MultisampleSpecs& GrGpu::getMultisampleSpecs(GrRenderTarget* rt, - const GrStencilSettings& stencil) { +const GrGpu::MultisampleSpecs& GrGpu::queryMultisampleSpecs(const GrPipeline& pipeline) { + GrRenderTarget* rt = pipeline.getRenderTarget(); SkASSERT(rt->desc().fSampleCnt > 1); -#ifndef SK_DEBUG - // In debug mode we query the multisample info every time to verify the caching is correct. - if (uint8_t id = rt->renderTargetPriv().accessMultisampleSpecsID()) { - SkASSERT(id > 0 && id < fMultisampleSpecs.count()); - return fMultisampleSpecs[id]; + GrStencilSettings stencil; + if (pipeline.isStencilEnabled()) { + // TODO: attach stencil and create settings during render target flush. + SkASSERT(rt->renderTargetPriv().getStencilAttachment()); + stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(), + rt->renderTargetPriv().numStencilBits()); } -#endif int effectiveSampleCnt; SkSTArray<16, SkPoint, true> pattern; - this->onGetMultisampleSpecs(rt, stencil, &effectiveSampleCnt, &pattern); + this->onQueryMultisampleSpecs(rt, stencil, &effectiveSampleCnt, &pattern); SkASSERT(effectiveSampleCnt >= rt->desc().fSampleCnt); uint8_t id; @@ -480,10 +514,7 @@ const GrGpu::MultisampleSpecs& GrGpu::getMultisampleSpecs(GrRenderTarget* rt, } } SkASSERT(id > 0); - SkASSERT(!rt->renderTargetPriv().accessMultisampleSpecsID() || - rt->renderTargetPriv().accessMultisampleSpecsID() == id); - rt->renderTargetPriv().accessMultisampleSpecsID() = id; return fMultisampleSpecs[id]; } diff --git a/gfx/skia/skia/src/gpu/GrGpu.h b/gfx/skia/skia/src/gpu/GrGpu.h index b8703dc68e36..df8cb080a451 100644 --- a/gfx/skia/skia/src/gpu/GrGpu.h +++ b/gfx/skia/skia/src/gpu/GrGpu.h @@ -12,14 +12,13 @@ #include "GrProgramDesc.h" #include "GrSwizzle.h" #include "GrAllocator.h" -#include "GrTextureParamsAdjuster.h" +#include "GrTextureProducer.h" #include "GrTypes.h" #include "GrXferProcessor.h" #include "SkPath.h" #include "SkTArray.h" #include -class GrBatchTracker; class GrBuffer; class GrContext; struct GrContextOptions; @@ -34,6 +33,7 @@ class GrPathRendering; class GrPipeline; class GrPrimitiveProcessor; class GrRenderTarget; +class GrSemaphore; class GrStencilAttachment; class GrStencilSettings; class GrSurface; @@ -122,19 +122,19 @@ public: } /** - * Implements GrTextureProvider::wrapBackendTexture + * Implements GrResourceProvider::wrapBackendTexture */ - GrTexture* wrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership); + sk_sp wrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership); /** - * Implements GrTextureProvider::wrapBackendRenderTarget + * Implements GrResourceProvider::wrapBackendRenderTarget */ - GrRenderTarget* wrapBackendRenderTarget(const GrBackendRenderTargetDesc&, GrWrapOwnership); + sk_sp wrapBackendRenderTarget(const GrBackendRenderTargetDesc&); /** - * Implements GrTextureProvider::wrapBackendTextureAsRenderTarget + * Implements GrResourceProvider::wrapBackendTextureAsRenderTarget */ - GrRenderTarget* wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&); + sk_sp wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&); /** * Creates a buffer in GPU memory. For a client-side buffer use GrBuffer::CreateCPUBacked. @@ -307,14 +307,6 @@ public: GrPixelConfig config, GrBuffer* transferBuffer, size_t offset, size_t rowBytes, GrFence* fence); - /** - * This is can be called before allocating a texture to be a dst for copySurface. This is only - * used for doing dst copies needed in blends, thus the src is always a GrRenderTarget. It will - * populate the origin, config, and flags fields of the desc such that copySurface can - * efficiently succeed. - */ - virtual bool initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const = 0; - // After the client interacts directly with the 3D context state the GrGpu // must resync its internal state and assumptions about 3D context state. // Each time this occurs the GrGpu bumps a timestamp. @@ -331,7 +323,7 @@ public: ResetTimestamp getResetTimestamp() const { return fResetTimestamp; } // Called to perform a surface to surface copy. Fallbacks to issuing a draw from the src to dst - // take place at the GrDrawTarget level and this function implement faster copy paths. The rect + // take place at the GrOpList level and this function implement faster copy paths. The rect // and point are pre-clipped. The src rect and implied dst rect are guaranteed to be within the // src/dst bounds and non-empty. bool copySurface(GrSurface* dst, @@ -355,26 +347,42 @@ public: const SkPoint* fSampleLocations; }; - // Finds a render target's multisample specs. The stencil settings are only needed to flush the - // draw state prior to querying multisample information; they should not have any effect on the - // multisample information itself. - const MultisampleSpecs& getMultisampleSpecs(GrRenderTarget*, const GrStencilSettings&); + // Finds a render target's multisample specs. The pipeline is only needed in case we need to + // flush the draw state prior to querying multisample info. The pipeline is not expected to + // affect the multisample information itself. + const MultisampleSpecs& queryMultisampleSpecs(const GrPipeline&); - // Creates a GrGpuCommandBuffer in which the GrDrawTarget can send draw commands to instead of - // directly to the Gpu object. + // Finds the multisample specs with a given unique id. + const MultisampleSpecs& getMultisampleSpecs(uint8_t uniqueID) { + SkASSERT(uniqueID > 0 && uniqueID < fMultisampleSpecs.count()); + return fMultisampleSpecs[uniqueID]; + } + + // Creates a GrGpuCommandBuffer in which the GrOpList can send draw commands to instead of + // directly to the Gpu object. This currently does not take a GrRenderTarget. The command buffer + // is expected to infer the render target from the first draw, clear, or discard. This is an + // awkward workaround that goes away after MDB is complete and the render target is known from + // the GrRenderTargetOpList. virtual GrGpuCommandBuffer* createCommandBuffer( - GrRenderTarget* target, const GrGpuCommandBuffer::LoadAndStoreInfo& colorInfo, const GrGpuCommandBuffer::LoadAndStoreInfo& stencilInfo) = 0; - // Called by drawtarget when flushing. - // Provides a hook for post-flush actions (e.g. PLS reset and Vulkan command buffer submits). - virtual void finishDrawTarget() {} + // Called by GrOpList when flushing. + // Provides a hook for post-flush actions (e.g. Vulkan command buffer submits). + virtual void finishOpList() {} - virtual GrFence SK_WARN_UNUSED_RESULT insertFence() const = 0; - virtual bool waitFence(GrFence, uint64_t timeout = 1000) const = 0; + virtual GrFence SK_WARN_UNUSED_RESULT insertFence() = 0; + virtual bool waitFence(GrFence, uint64_t timeout = 1000) = 0; virtual void deleteFence(GrFence) const = 0; + virtual sk_sp SK_WARN_UNUSED_RESULT makeSemaphore() = 0; + virtual void insertSemaphore(sk_sp semaphore) = 0; + virtual void waitSemaphore(sk_sp semaphore) = 0; + + // Ensures that all queued up driver-level commands have been sent to the GPU. For example, on + // OpenGL, this calls glFlush. + virtual void flush() = 0; + /////////////////////////////////////////////////////////////////////////// // Debugging and Stats @@ -463,22 +471,24 @@ public: virtual void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) = 0; // Determines whether a texture will need to be rescaled in order to be used with the - // GrTextureParams. This variation is called when the caller will create a new texture using the - // texture provider from a non-texture src (cpu-backed image, ...). - bool makeCopyForTextureParams(int width, int height, const GrTextureParams&, - GrTextureProducer::CopyParams*) const; + // GrSamplerParams. This variation is called when the caller will create a new texture using the + // resource provider from a non-texture src (cpu-backed image, ...). + bool isACopyNeededForTextureParams(int width, int height, const GrSamplerParams&, + GrTextureProducer::CopyParams*, + SkScalar scaleAdjust[2]) const; // Like the above but this variation should be called when the caller is not creating the // original texture but rather was handed the original texture. It adds additional checks // relevant to original textures that were created external to Skia via - // GrTextureProvider::wrap methods. - bool makeCopyForTextureParams(GrTexture* texture, const GrTextureParams& params, - GrTextureProducer::CopyParams* copyParams) const { - if (this->makeCopyForTextureParams(texture->width(), texture->height(), params, - copyParams)) { + // GrResourceProvider::wrap methods. + bool isACopyNeededForTextureParams(GrTextureProxy* proxy, const GrSamplerParams& params, + GrTextureProducer::CopyParams* copyParams, + SkScalar scaleAdjust[2]) const { + if (this->isACopyNeededForTextureParams(proxy->width(), proxy->height(), params, + copyParams, scaleAdjust)) { return true; } - return this->onMakeCopyForTextureParams(texture, params, copyParams); + return this->onIsACopyNeededForTextureParams(proxy, params, copyParams, scaleAdjust); } // This is only to be used in GL-specific tests. @@ -507,10 +517,10 @@ protected: // Handles cases where a surface will be updated without a call to flushRenderTarget void didWriteToSurface(GrSurface* surface, const SkIRect* bounds, uint32_t mipLevels = 1) const; - Stats fStats; - SkAutoTDelete fPathRendering; + Stats fStats; + std::unique_ptr fPathRendering; // Subclass must initialize this in its constructor. - SkAutoTUnref fCaps; + sk_sp fCaps; typedef SkTArray SamplePattern; @@ -532,17 +542,19 @@ private: SkBudgeted budgeted, const SkTArray& texels) = 0; - virtual GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) = 0; - virtual GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&, - GrWrapOwnership) = 0; - virtual GrRenderTarget* onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&) = 0; + virtual sk_sp onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) = 0; + virtual sk_sp onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) = 0; + virtual sk_sp onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&)=0; virtual GrBuffer* onCreateBuffer(size_t size, GrBufferType intendedType, GrAccessPattern, const void* data) = 0; virtual gr_instanced::InstancedRendering* onCreateInstancedRendering() = 0; - virtual bool onMakeCopyForTextureParams(GrTexture* texture, const GrTextureParams&, - GrTextureProducer::CopyParams*) const { return false; } + virtual bool onIsACopyNeededForTextureParams(GrTextureProxy* proxy, const GrSamplerParams&, + GrTextureProducer::CopyParams*, + SkScalar scaleAdjust[2]) const { + return false; + } virtual bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes, GrPixelConfig readConfig, DrawPreference*, @@ -581,8 +593,8 @@ private: const SkIPoint& dstPoint) = 0; // overridden by backend specific derived class to perform the multisample queries - virtual void onGetMultisampleSpecs(GrRenderTarget*, const GrStencilSettings&, - int* effectiveSampleCnt, SamplePattern*) = 0; + virtual void onQueryMultisampleSpecs(GrRenderTarget*, const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) = 0; void resetContext() { this->onResetContext(fResetBits); diff --git a/gfx/skia/skia/src/gpu/GrGpuCommandBuffer.cpp b/gfx/skia/skia/src/gpu/GrGpuCommandBuffer.cpp index 022c16696fd2..4eb98433efb5 100644 --- a/gfx/skia/skia/src/gpu/GrGpuCommandBuffer.cpp +++ b/gfx/skia/skia/src/gpu/GrGpuCommandBuffer.cpp @@ -14,36 +14,37 @@ #include "GrRenderTarget.h" #include "SkRect.h" -void GrGpuCommandBuffer::submit(const SkIRect& bounds) { +void GrGpuCommandBuffer::submit() { this->gpu()->handleDirtyContext(); - this->onSubmit(bounds); + this->onSubmit(); } -void GrGpuCommandBuffer::clear(const GrFixedClip& clip, GrColor color, GrRenderTarget* rt) { +void GrGpuCommandBuffer::clear(GrRenderTarget* rt, const GrFixedClip& clip, GrColor color) { +#ifdef SK_DEBUG SkASSERT(rt); SkASSERT(!clip.scissorEnabled() || (SkIRect::MakeWH(rt->width(), rt->height()).contains(clip.scissorRect()) && SkIRect::MakeWH(rt->width(), rt->height()) != clip.scissorRect())); +#endif this->onClear(rt, clip, color); } -void GrGpuCommandBuffer::clearStencilClip(const GrFixedClip& clip, - bool insideStencilMask, - GrRenderTarget* rt) { - SkASSERT(rt); +void GrGpuCommandBuffer::clearStencilClip(GrRenderTarget* rt, const GrFixedClip& clip, + bool insideStencilMask) { this->onClearStencilClip(rt, clip, insideStencilMask); } - bool GrGpuCommandBuffer::draw(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, const GrMesh* mesh, - int meshCount) { + int meshCount, + const SkRect& bounds) { + SkASSERT(pipeline.isInitialized()); if (primProc.numAttribs() > this->gpu()->caps()->maxVertexAttributes()) { this->gpu()->stats()->incNumFailedDraws(); return false; } - this->onDraw(pipeline, primProc, mesh, meshCount); + this->onDraw(pipeline, primProc, mesh, meshCount, bounds); return true; } diff --git a/gfx/skia/skia/src/gpu/GrGpuCommandBuffer.h b/gfx/skia/skia/src/gpu/GrGpuCommandBuffer.h index 2336dc5aaf86..23a300c2f47c 100644 --- a/gfx/skia/skia/src/gpu/GrGpuCommandBuffer.h +++ b/gfx/skia/skia/src/gpu/GrGpuCommandBuffer.h @@ -9,7 +9,9 @@ #define GrGpuCommandBuffer_DEFINED #include "GrColor.h" +#include "ops/GrDrawOp.h" +class GrOpFlushState; class GrFixedClip; class GrGpu; class GrMesh; @@ -17,12 +19,19 @@ class GrPipeline; class GrPrimitiveProcessor; class GrRenderTarget; struct SkIRect; +struct SkRect; /** * The GrGpuCommandBuffer is a series of commands (draws, clears, and discards), which all target * the same render target. It is possible that these commands execute immediately (GL), or get - * buffered up for later execution (Vulkan). GrBatches will execute their draw commands into a + * buffered up for later execution (Vulkan). GrOps will execute their draw commands into a * GrGpuCommandBuffer. + * + * Ideally we'd know the GrRenderTarget, or at least its properties when the GrGpuCommandBuffer, is + * created. We also then wouldn't include it in the GrPipeline or as a parameter to the clear and + * discard methods. The logical place for that will be in GrRenderTargetOpList post-MDB. For now + * the render target is redundantly passed to each operation, though it will always be the same + * render target for a given command buffer even pre-MDB. */ class GrGpuCommandBuffer { public: @@ -51,8 +60,7 @@ public: // Sends the command buffer off to the GPU object to execute the commands built up in the // buffer. The gpu object is allowed to defer execution of the commands until it is flushed. - // The bounds should represent the bounds of all the draws put into the command buffer. - void submit(const SkIRect& bounds); + void submit(); // We pass in an array of meshCount GrMesh to the draw. The backend should loop over each // GrMesh object and emit a draw for it. Each draw will use the same GrPipeline and @@ -61,36 +69,44 @@ public: bool draw(const GrPipeline&, const GrPrimitiveProcessor&, const GrMesh*, - int meshCount); + int meshCount, + const SkRect& bounds); + + // Performs an upload of vertex data in the middle of a set of a set of draws + virtual void inlineUpload(GrOpFlushState* state, GrDrawOp::DeferredUploadFn& upload, + GrRenderTarget* rt) = 0; /** - * Clear the passed in render target. Ignores the draw state and clip. - */ - void clear(const GrFixedClip&, GrColor, GrRenderTarget*); + * Clear the passed in render target. Ignores the draw state and clip. + */ + void clear(GrRenderTarget*, const GrFixedClip&, GrColor); + + void clearStencilClip(GrRenderTarget*, const GrFixedClip&, bool insideStencilMask); - void clearStencilClip(const GrFixedClip&, bool insideStencilMask, GrRenderTarget*); /** - * Discards the contents render target. nullptr indicates that the current render target should - * be discarded. - **/ + * Discards the contents render target. nullptr indicates that the current render target should + * be discarded. + */ // TODO: This should be removed in the future to favor using the load and store ops for discard - virtual void discard(GrRenderTarget* = nullptr) = 0; + virtual void discard(GrRenderTarget*) = 0; private: virtual GrGpu* gpu() = 0; - virtual void onSubmit(const SkIRect& bounds) = 0; + virtual GrRenderTarget* renderTarget() = 0; + + virtual void onSubmit() = 0; // overridden by backend-specific derived class to perform the draw call. virtual void onDraw(const GrPipeline&, const GrPrimitiveProcessor&, const GrMesh*, - int meshCount) = 0; + int meshCount, + const SkRect& bounds) = 0; // overridden by backend-specific derived class to perform the clear. virtual void onClear(GrRenderTarget*, const GrFixedClip&, GrColor) = 0; - virtual void onClearStencilClip(GrRenderTarget*, - const GrFixedClip&, + virtual void onClearStencilClip(GrRenderTarget*, const GrFixedClip&, bool insideStencilMask) = 0; }; diff --git a/gfx/skia/skia/src/gpu/GrGpuResource.cpp b/gfx/skia/skia/src/gpu/GrGpuResource.cpp index c1578b50ab59..dcc4e62282e6 100644 --- a/gfx/skia/skia/src/gpu/GrGpuResource.cpp +++ b/gfx/skia/skia/src/gpu/GrGpuResource.cpp @@ -43,6 +43,17 @@ void GrGpuResource::registerWithCacheWrapped() { get_resource_cache(fGpu)->resourceAccess().insertResource(this); } +void GrGpuResource::detachFromCache() { + if (this->wasDestroyed()) { + return; + } + if (fUniqueKey.isValid()) { + this->removeUniqueKey(); + } + this->removeScratchKey(); + this->makeUnbudgeted(); +} + GrGpuResource::~GrGpuResource() { // The cache should have released or destroyed this resource. SkASSERT(this->wasDestroyed()); @@ -70,7 +81,7 @@ void GrGpuResource::abandon() { void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { // Dump resource as "skia/gpu_resources/resource_#". SkString dumpName("skia/gpu_resources/resource_"); - dumpName.appendS32(this->uniqueID()); + dumpName.appendU32(this->uniqueID().asUInt()); traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", this->gpuMemorySize()); diff --git a/gfx/skia/skia/src/gpu/GrGpuResourceCacheAccess.h b/gfx/skia/skia/src/gpu/GrGpuResourceCacheAccess.h index e91f899cf2b8..cfc18e75ea96 100644 --- a/gfx/skia/skia/src/gpu/GrGpuResourceCacheAccess.h +++ b/gfx/skia/skia/src/gpu/GrGpuResourceCacheAccess.h @@ -63,6 +63,10 @@ private: SkASSERT(fResource->isPurgeable()); fResource->fExternalFlushCntWhenBecamePurgeable = cnt; } + void setTimeWhenResourceBecomePurgeable() { + SkASSERT(fResource->isPurgeable()); + fResource->fTimeWhenBecamePurgeable = GrStdSteadyClock::now(); + } /** * Called by the cache to determine whether this resource has been puregable for more than * a threshold number of external flushes. @@ -71,6 +75,14 @@ private: SkASSERT(fResource->isPurgeable()); return fResource->fExternalFlushCntWhenBecamePurgeable; } + /** + * Called by the cache to determine whether this resource should be purged based on the length + * of time it has been available for purging. + */ + GrStdSteadyClock::time_point timeWhenResourceBecamePurgeable() { + SkASSERT(fResource->isPurgeable()); + return fResource->fTimeWhenBecamePurgeable; + } int* accessCacheIndex() const { return &fResource->fCacheArrayIndex; } diff --git a/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.cpp b/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.cpp deleted file mode 100644 index 5a96b6d3e603..000000000000 --- a/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrImageIDTextureAdjuster.h" - -#include "GrContext.h" -#include "GrGpuResourcePriv.h" -#include "SkBitmap.h" -#include "SkGrPriv.h" -#include "SkImage_Base.h" -#include "SkImageCacherator.h" -#include "SkPixelRef.h" - -static bool bmp_is_alpha_only(const SkBitmap& bm) { return kAlpha_8_SkColorType == bm.colorType(); } - -GrBitmapTextureMaker::GrBitmapTextureMaker(GrContext* context, const SkBitmap& bitmap) - : INHERITED(context, bitmap.width(), bitmap.height(), bmp_is_alpha_only(bitmap)) - , fBitmap(bitmap) -{ - if (!bitmap.isVolatile()) { - SkIPoint origin = bitmap.pixelRefOrigin(); - SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bitmap.width(), - bitmap.height()); - GrMakeKeyFromImageID(&fOriginalKey, bitmap.pixelRef()->getGenerationID(), subset); - } -} - -GrTexture* GrBitmapTextureMaker::refOriginalTexture(bool willBeMipped, - SkSourceGammaTreatment gammaTreatment) { - GrTexture* tex = nullptr; - - if (fOriginalKey.isValid()) { - tex = this->context()->textureProvider()->findAndRefTextureByUniqueKey(fOriginalKey); - if (tex) { - return tex; - } - } - if (willBeMipped) { - tex = GrGenerateMipMapsAndUploadToTexture(this->context(), fBitmap, gammaTreatment); - } - if (!tex) { - tex = GrUploadBitmapToTexture(this->context(), fBitmap); - } - if (tex && fOriginalKey.isValid()) { - tex->resourcePriv().setUniqueKey(fOriginalKey); - GrInstallBitmapUniqueKeyInvalidator(fOriginalKey, fBitmap.pixelRef()); - } - return tex; -} - -void GrBitmapTextureMaker::makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) { - if (fOriginalKey.isValid()) { - MakeCopyKeyFromOrigKey(fOriginalKey, copyParams, copyKey); - } -} - -void GrBitmapTextureMaker::didCacheCopy(const GrUniqueKey& copyKey) { - GrInstallBitmapUniqueKeyInvalidator(copyKey, fBitmap.pixelRef()); -} - -SkAlphaType GrBitmapTextureMaker::alphaType() const { - return fBitmap.alphaType(); -} - -SkColorSpace* GrBitmapTextureMaker::getColorSpace() { - return fBitmap.colorSpace(); -} - -////////////////////////////////////////////////////////////////////////////// -static bool cacher_is_alpha_only(const SkImageCacherator& cacher) { - return kAlpha_8_SkColorType == cacher.info().colorType(); -} -GrImageTextureMaker::GrImageTextureMaker(GrContext* context, SkImageCacherator* cacher, - const SkImage* client, SkImage::CachingHint chint) - : INHERITED(context, cacher->info().width(), cacher->info().height(), - cacher_is_alpha_only(*cacher)) - , fCacher(cacher) - , fClient(client) - , fCachingHint(chint) { - if (client) { - GrMakeKeyFromImageID(&fOriginalKey, client->uniqueID(), - SkIRect::MakeWH(this->width(), this->height())); - } -} - -GrTexture* GrImageTextureMaker::refOriginalTexture(bool willBeMipped, - SkSourceGammaTreatment gammaTreatment) { - return fCacher->lockTexture(this->context(), fOriginalKey, fClient, fCachingHint, willBeMipped, - gammaTreatment); -} - -void GrImageTextureMaker::makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey) { - if (fOriginalKey.isValid() && SkImage::kAllow_CachingHint == fCachingHint) { - MakeCopyKeyFromOrigKey(fOriginalKey, stretch, paramsCopyKey); - } -} - -void GrImageTextureMaker::didCacheCopy(const GrUniqueKey& copyKey) { - if (fClient) { - as_IB(fClient)->notifyAddedToCache(); - } -} - -SkAlphaType GrImageTextureMaker::alphaType() const { - return fCacher->info().alphaType(); -} - -SkColorSpace* GrImageTextureMaker::getColorSpace() { - return fCacher->info().colorSpace(); -} diff --git a/gfx/skia/skia/src/gpu/GrImageTextureMaker.cpp b/gfx/skia/skia/src/gpu/GrImageTextureMaker.cpp new file mode 100644 index 000000000000..a1a6053a0308 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrImageTextureMaker.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrImageTextureMaker.h" + +#include "GrContext.h" +#include "GrGpuResourcePriv.h" +#include "SkGr.h" +#include "SkImage_Base.h" +#include "SkImageCacherator.h" +#include "SkPixelRef.h" + +static bool cacher_is_alpha_only(const SkImageCacherator& cacher) { + return kAlpha_8_SkColorType == cacher.info().colorType(); +} + +GrImageTextureMaker::GrImageTextureMaker(GrContext* context, SkImageCacherator* cacher, + const SkImage* client, SkImage::CachingHint chint) + : INHERITED(context, cacher->info().width(), cacher->info().height(), + cacher_is_alpha_only(*cacher)) + , fCacher(cacher) + , fClient(client) + , fCachingHint(chint) { + if (client) { + GrMakeKeyFromImageID(&fOriginalKey, client->uniqueID(), + SkIRect::MakeWH(this->width(), this->height())); + } +} + +sk_sp GrImageTextureMaker::refOriginalTextureProxy(bool willBeMipped, + SkColorSpace* dstColorSpace) { + return fCacher->lockTextureProxy(this->context(), fOriginalKey, fClient, fCachingHint, + willBeMipped, dstColorSpace); +} + +void GrImageTextureMaker::makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey, + SkColorSpace* dstColorSpace) { + if (fOriginalKey.isValid() && SkImage::kAllow_CachingHint == fCachingHint) { + SkImageCacherator::CachedFormat cacheFormat = + fCacher->chooseCacheFormat(dstColorSpace, this->context()->caps()); + GrUniqueKey cacheKey; + fCacher->makeCacheKeyFromOrigKey(fOriginalKey, cacheFormat, &cacheKey); + MakeCopyKeyFromOrigKey(cacheKey, stretch, paramsCopyKey); + } +} + +void GrImageTextureMaker::didCacheCopy(const GrUniqueKey& copyKey) { + if (fClient) { + as_IB(fClient)->notifyAddedToCache(); + } +} + +SkAlphaType GrImageTextureMaker::alphaType() const { + return fCacher->info().alphaType(); +} +sk_sp GrImageTextureMaker::getColorSpace(SkColorSpace* dstColorSpace) { + return fCacher->getColorSpace(this->context(), dstColorSpace); +} diff --git a/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.h b/gfx/skia/skia/src/gpu/GrImageTextureMaker.h similarity index 50% rename from gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.h rename to gfx/skia/skia/src/gpu/GrImageTextureMaker.h index 36ac0ad3e14e..514590377552 100644 --- a/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.h +++ b/gfx/skia/skia/src/gpu/GrImageTextureMaker.h @@ -1,44 +1,18 @@ /* - * Copyright 2015 Google Inc. + * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#ifndef GrImageIDTextureAdjuster_DEFINED -#define GrImageIDTextureAdjuster_DEFINED +#ifndef GrImageTextureMaker_DEFINED +#define GrImageTextureMaker_DEFINED -#include "GrTextureParamsAdjuster.h" +#include "GrTextureMaker.h" #include "SkImage.h" -class SkBitmap; -class SkImage_Base; class SkImageCacherator; -/** This class manages the conversion of SW-backed bitmaps to GrTextures. If the input bitmap is - non-volatile the texture is cached using a key created from the pixels' image id and the - subset of the pixelref specified by the bitmap. */ -class GrBitmapTextureMaker : public GrTextureMaker { -public: - GrBitmapTextureMaker(GrContext* context, const SkBitmap& bitmap); - -protected: - GrTexture* refOriginalTexture(bool willBeMipped, SkSourceGammaTreatment) override; - - void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override; - - void didCacheCopy(const GrUniqueKey& copyKey) override; - - SkAlphaType alphaType() const override; - SkColorSpace* getColorSpace() override; - -private: - const SkBitmap fBitmap; - GrUniqueKey fOriginalKey; - - typedef GrTextureMaker INHERITED; -}; - /** This class manages the conversion of generator-backed images to GrTextures. If the caching hint is kAllow the image's ID is used for the cache key. */ class GrImageTextureMaker : public GrTextureMaker { @@ -50,13 +24,15 @@ protected: // TODO: consider overriding this, for the case where the underlying generator might be // able to efficiently produce a "stretched" texture natively (e.g. picture-backed) // GrTexture* generateTextureForParams(const CopyParams&) override; + sk_sp refOriginalTextureProxy(bool willBeMipped, + SkColorSpace* dstColorSpace) override; - GrTexture* refOriginalTexture(bool willBeMipped, SkSourceGammaTreatment) override; - void makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey) override; + void makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey, + SkColorSpace* dstColorSpace) override; void didCacheCopy(const GrUniqueKey& copyKey) override; SkAlphaType alphaType() const override; - SkColorSpace* getColorSpace() override; + sk_sp getColorSpace(SkColorSpace* dstColorSpace) override; private: SkImageCacherator* fCacher; diff --git a/gfx/skia/skia/src/gpu/GrInvariantOutput.cpp b/gfx/skia/skia/src/gpu/GrInvariantOutput.cpp deleted file mode 100644 index ee64d333abd5..000000000000 --- a/gfx/skia/skia/src/gpu/GrInvariantOutput.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrInvariantOutput.h" - -#ifdef SK_DEBUG - -void GrInvariantOutput::validate() const { - if (fIsSingleComponent) { - SkASSERT(0 == fValidFlags || kRGBA_GrColorComponentFlags == fValidFlags); - if (kRGBA_GrColorComponentFlags == fValidFlags) { - SkASSERT(this->colorComponentsAllEqual()); - } - } - - // If we claim that we are not using the input color we must not be modulating the input. - SkASSERT(fNonMulStageFound || fWillUseInputColor); -} - -bool GrInvariantOutput::colorComponentsAllEqual() const { - unsigned colorA = GrColorUnpackA(fColor); - return(GrColorUnpackR(fColor) == colorA && - GrColorUnpackG(fColor) == colorA && - GrColorUnpackB(fColor) == colorA); -} - -#endif // end DEBUG diff --git a/gfx/skia/skia/src/gpu/GrMemoryPool.cpp b/gfx/skia/skia/src/gpu/GrMemoryPool.cpp index 6bc0f54602f6..32a361297223 100644 --- a/gfx/skia/skia/src/gpu/GrMemoryPool.cpp +++ b/gfx/skia/skia/src/gpu/GrMemoryPool.cpp @@ -6,6 +6,10 @@ */ #include "GrMemoryPool.h" +#include "SkMalloc.h" +#ifdef SK_DEBUG +#include "SkAtomics.h" +#endif #ifdef SK_DEBUG #define VALIDATE this->validate() @@ -13,17 +17,19 @@ #define VALIDATE #endif +constexpr size_t GrMemoryPool::kSmallestMinAllocSize; + GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize) { SkDEBUGCODE(fAllocationCnt = 0); SkDEBUGCODE(fAllocBlockCnt = 0); - minAllocSize = SkTMax(minAllocSize, 1 << 10); - fMinAllocSize = GrSizeAlignUp(minAllocSize + kPerAllocPad, kAlignment); - fPreallocSize = GrSizeAlignUp(preallocSize + kPerAllocPad, kAlignment); - fPreallocSize = SkTMax(fPreallocSize, fMinAllocSize); + minAllocSize = SkTMax(GrSizeAlignUp(minAllocSize, kAlignment), kSmallestMinAllocSize); + preallocSize = SkTMax(GrSizeAlignUp(preallocSize, kAlignment), minAllocSize); + + fMinAllocSize = minAllocSize; fSize = 0; - fHead = CreateBlock(fPreallocSize); + fHead = CreateBlock(preallocSize); fTail = fHead; fHead->fNext = nullptr; fHead->fPrev = nullptr; @@ -32,6 +38,19 @@ GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize) { GrMemoryPool::~GrMemoryPool() { VALIDATE; +#ifdef SK_DEBUG + int i = 0; + int n = fAllocatedIDs.count(); + fAllocatedIDs.foreach([&i, n] (int32_t id) { + if (++i == 1) { + SkDebugf("Leaked IDs (in no particular order): %d", id); + } else if (i < 11) { + SkDebugf(", %d%s", id, (n == i ? "\n" : "")); + } else if (i == 11) { + SkDebugf(", ...\n"); + } + }); +#endif SkASSERT(0 == fAllocationCnt); SkASSERT(fHead == fTail); SkASSERT(0 == fHead->fLiveCount); @@ -43,7 +62,7 @@ void* GrMemoryPool::allocate(size_t size) { size += kPerAllocPad; size = GrSizeAlignUp(size, kAlignment); if (fTail->fFreeSize < size) { - size_t blockSize = size; + size_t blockSize = size + kHeaderSize; blockSize = SkTMax(blockSize, fMinAllocSize); BlockHeader* block = CreateBlock(blockSize); @@ -62,13 +81,15 @@ void* GrMemoryPool::allocate(size_t size) { // so that we can decrement the live count on delete in constant time. AllocHeader* allocData = reinterpret_cast(ptr); SkDEBUGCODE(allocData->fSentinal = kAssignedMarker); + SkDEBUGCODE(allocData->fID = []{static int32_t gID; return sk_atomic_inc(&gID) + 1;}()); + // You can set a breakpoint here when a leaked ID is allocated to see the stack frame. + SkDEBUGCODE(fAllocatedIDs.add(allocData->fID)); allocData->fHeader = fTail; ptr += kPerAllocPad; fTail->fPrevPtr = fTail->fCurrPtr; fTail->fCurrPtr += size; fTail->fFreeSize -= size; fTail->fLiveCount += 1; - SkDEBUGCODE(++fAllocationCnt); VALIDATE; return reinterpret_cast(ptr); @@ -80,6 +101,7 @@ void GrMemoryPool::release(void* p) { AllocHeader* allocData = reinterpret_cast(ptr); SkASSERT(kAssignedMarker == allocData->fSentinal); SkDEBUGCODE(allocData->fSentinal = kFreedMarker); + SkDEBUGCODE(fAllocatedIDs.remove(allocData->fID)); BlockHeader* block = allocData->fHeader; SkASSERT(kAssignedMarker == block->fBlockSentinal); if (1 == block->fLiveCount) { @@ -87,7 +109,7 @@ void GrMemoryPool::release(void* p) { if (fHead == block) { fHead->fCurrPtr = reinterpret_cast(fHead) + kHeaderSize; fHead->fLiveCount = 0; - fHead->fFreeSize = fPreallocSize; + fHead->fFreeSize = fHead->fSize - kHeaderSize; } else { BlockHeader* prev = block->fPrev; BlockHeader* next = block->fNext; @@ -115,18 +137,18 @@ void GrMemoryPool::release(void* p) { VALIDATE; } -GrMemoryPool::BlockHeader* GrMemoryPool::CreateBlock(size_t size) { - size_t paddedSize = size + kHeaderSize; +GrMemoryPool::BlockHeader* GrMemoryPool::CreateBlock(size_t blockSize) { + blockSize = SkTMax(blockSize, kHeaderSize); BlockHeader* block = - reinterpret_cast(sk_malloc_throw(paddedSize)); + reinterpret_cast(sk_malloc_throw(blockSize)); // we assume malloc gives us aligned memory SkASSERT(!(reinterpret_cast(block) % kAlignment)); SkDEBUGCODE(block->fBlockSentinal = kAssignedMarker); block->fLiveCount = 0; - block->fFreeSize = size; + block->fFreeSize = blockSize - kHeaderSize; block->fCurrPtr = reinterpret_cast(block) + kHeaderSize; block->fPrevPtr = 0; // gcc warns on assigning nullptr to an intptr_t. - block->fSize = paddedSize; + block->fSize = blockSize; return block; } @@ -153,18 +175,16 @@ void GrMemoryPool::validate() { intptr_t b = reinterpret_cast(block); size_t ptrOffset = block->fCurrPtr - b; size_t totalSize = ptrOffset + block->fFreeSize; - size_t userSize = totalSize - kHeaderSize; intptr_t userStart = b + kHeaderSize; SkASSERT(!(b % kAlignment)); SkASSERT(!(totalSize % kAlignment)); - SkASSERT(!(userSize % kAlignment)); SkASSERT(!(block->fCurrPtr % kAlignment)); if (fHead != block) { SkASSERT(block->fLiveCount); - SkASSERT(userSize >= fMinAllocSize); + SkASSERT(totalSize >= fMinAllocSize); } else { - SkASSERT(userSize == fPreallocSize); + SkASSERT(totalSize == block->fSize); } if (!block->fLiveCount) { SkASSERT(ptrOffset == kHeaderSize); @@ -179,6 +199,7 @@ void GrMemoryPool::validate() { prev = block; } while ((block = block->fNext)); SkASSERT(allocCount == fAllocationCnt); + SkASSERT(fAllocationCnt == fAllocatedIDs.count()); SkASSERT(prev == fTail); SkASSERT(fAllocBlockCnt != 0 || fSize == 0); #endif diff --git a/gfx/skia/skia/src/gpu/GrMemoryPool.h b/gfx/skia/skia/src/gpu/GrMemoryPool.h index 43826d354a13..26a763430ff0 100644 --- a/gfx/skia/skia/src/gpu/GrMemoryPool.h +++ b/gfx/skia/skia/src/gpu/GrMemoryPool.h @@ -9,20 +9,30 @@ #define GrMemoryPool_DEFINED #include "GrTypes.h" +#ifdef SK_DEBUG +#include "SkTHash.h" +#endif /** * Allocates memory in blocks and parcels out space in the blocks for allocation * requests. It is optimized for allocate / release speed over memory - * effeciency. The interface is designed to be used to implement operator new + * efficiency. The interface is designed to be used to implement operator new * and delete overrides. All allocations are expected to be released before the * pool's destructor is called. Allocations will be 8-byte aligned. */ class GrMemoryPool { public: /** - * Prealloc size is the amount of space to make available at pool creation - * time and keep around until pool destruction. The min alloc size is the - * smallest allowed size of additional allocations. + * Prealloc size is the amount of space to allocate at pool creation + * time and keep around until pool destruction. The min alloc size is + * the smallest allowed size of additional allocations. Both sizes are + * adjusted to ensure that: + * 1. they are are 8-byte aligned + * 2. minAllocSize >= kSmallestMinAllocSize + * 3. preallocSize >= minAllocSize + * + * Both sizes is what the pool will end up allocating from the system, and + * portions of the allocated memory is used for internal bookkeeping. */ GrMemoryPool(size_t preallocSize, size_t minAllocSize); @@ -48,6 +58,16 @@ public: */ size_t size() const { return fSize; } + /** + * Returns the preallocated size of the GrMemoryPool + */ + size_t preallocSize() const { return fHead->fSize; } + + /** + * Minimum value of minAllocSize constructor argument. + */ + constexpr static size_t kSmallestMinAllocSize = 1 << 10; + private: struct BlockHeader; @@ -77,25 +97,93 @@ private: struct AllocHeader { #ifdef SK_DEBUG uint32_t fSentinal; ///< known value to check for memory stomping (e.g., (CD)*) + int32_t fID; ///< ID that can be used to track down leaks by clients. #endif BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides }; - enum { - // We assume this alignment is good enough for everybody. - kAlignment = 8, - kHeaderSize = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment), - kPerAllocPad = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment), - }; size_t fSize; - size_t fPreallocSize; size_t fMinAllocSize; BlockHeader* fHead; BlockHeader* fTail; #ifdef SK_DEBUG int fAllocationCnt; int fAllocBlockCnt; + SkTHashSet fAllocatedIDs; #endif + +protected: + enum { + // We assume this alignment is good enough for everybody. + kAlignment = 8, + kHeaderSize = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment), + kPerAllocPad = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment), + }; }; +/** + * Variant of GrMemoryPool that can only allocate objects of a single type. It is + * not as flexible as GrMemoryPool, but it has more convenient allocate() method, + * and more importantly, it guarantees number of objects that are preallocated at + * construction or when adding a new memory block. I.e. + * + * GrMemoryPool pool(3 * sizeof(T), 1000 * sizeof(T)); + * pool.allocate(sizeof(T)); + * pool.allocate(sizeof(T)); + * pool.allocate(sizeof(T)); + * + * will preallocate 3 * sizeof(T) bytes and use some of those bytes for internal + * structures. Because of that, last allocate() call will end up allocating a new + * block of 1000 * sizeof(T) bytes. In contrast, + * + * GrObjectMemoryPool pool(3, 1000); + * pool.allocate(); + * pool.allocate(); + * pool.allocate(); + * + * guarantees to preallocate enough memory for 3 objects of sizeof(T), so last + * allocate() will use preallocated memory and won't cause allocation of a new block. + * + * Same thing is true for the second (minAlloc) ctor argument: this class guarantees + * that a newly added block will have enough space for 1000 objects of sizeof(T), while + * GrMemoryPool does not. + */ +template +class GrObjectMemoryPool: public GrMemoryPool { +public: + /** + * Preallocates memory for preallocCount objects, and sets new block size to be + * enough to hold minAllocCount objects. + */ + GrObjectMemoryPool(size_t preallocCount, size_t minAllocCount) + : GrMemoryPool(CountToSize(preallocCount), + CountToSize(SkTMax(minAllocCount, kSmallestMinAllocCount))) { + } + + /** + * Allocates memory for an object, but doesn't construct or otherwise initialize it. + * The memory must be freed with release(). + */ + T* allocate() { return static_cast(GrMemoryPool::allocate(sizeof(T))); } + +private: + constexpr static size_t kTotalObjectSize = + kPerAllocPad + GR_CT_ALIGN_UP(sizeof(T), kAlignment); + + constexpr static size_t CountToSize(size_t count) { + return kHeaderSize + count * kTotalObjectSize; + } + +public: + /** + * Minimum value of minAllocCount constructor argument. + */ + constexpr static size_t kSmallestMinAllocCount = + (GrMemoryPool::kSmallestMinAllocSize - kHeaderSize + kTotalObjectSize - 1) / + kTotalObjectSize; +}; + +template +constexpr size_t GrObjectMemoryPool::kSmallestMinAllocCount; + #endif diff --git a/gfx/skia/skia/src/gpu/GrMesh.h b/gfx/skia/skia/src/gpu/GrMesh.h index 964e0b4a8e16..5d1ce6f3e4f5 100644 --- a/gfx/skia/skia/src/gpu/GrMesh.h +++ b/gfx/skia/skia/src/gpu/GrMesh.h @@ -35,7 +35,7 @@ protected: }; /** - * Used to communicate index and vertex buffers, counts, and offsets for a draw from GrBatch to + * Used to communicate index and vertex buffers, counts, and offsets for a draw from GrOp to * GrGpu. It also holds the primitive type for the draw. TODO: Consider moving ownership of this * and draw-issuing responsibility to GrPrimitiveProcessor. The rest of the vertex info lives there * already (stride, attribute mappings). diff --git a/gfx/skia/skia/src/gpu/GrOpFlushState.cpp b/gfx/skia/skia/src/gpu/GrOpFlushState.cpp new file mode 100644 index 000000000000..c6f5d383832e --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrOpFlushState.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrOpFlushState.h" + +#include "GrDrawOpAtlas.h" +#include "GrPipeline.h" + +GrOpFlushState::GrOpFlushState(GrGpu* gpu, GrResourceProvider* resourceProvider) + : fGpu(gpu) + , fResourceProvider(resourceProvider) + , fCommandBuffer(nullptr) + , fVertexPool(gpu) + , fIndexPool(gpu) + , fLastIssuedToken(GrDrawOpUploadToken::AlreadyFlushedToken()) + , fLastFlushedToken(0) + , fOpArgs(nullptr) {} + +void* GrOpFlushState::makeVertexSpace(size_t vertexSize, int vertexCount, + const GrBuffer** buffer, int* startVertex) { + return fVertexPool.makeSpace(vertexSize, vertexCount, buffer, startVertex); +} + +uint16_t* GrOpFlushState::makeIndexSpace(int indexCount, + const GrBuffer** buffer, int* startIndex) { + return reinterpret_cast(fIndexPool.makeSpace(indexCount, buffer, startIndex)); +} diff --git a/gfx/skia/skia/src/gpu/GrBatchFlushState.h b/gfx/skia/skia/src/gpu/GrOpFlushState.h similarity index 51% rename from gfx/skia/skia/src/gpu/GrBatchFlushState.h rename to gfx/skia/skia/src/gpu/GrOpFlushState.h index d2d9a4b48890..4ba87feebfb7 100644 --- a/gfx/skia/skia/src/gpu/GrBatchFlushState.h +++ b/gfx/skia/skia/src/gpu/GrOpFlushState.h @@ -5,25 +5,26 @@ * found in the LICENSE file. */ -#ifndef GrBatchBuffer_DEFINED -#define GrBatchBuffer_DEFINED +#ifndef GrOpFlushState_DEFINED +#define GrOpFlushState_DEFINED #include "GrBufferAllocPool.h" -#include "batches/GrVertexBatch.h" +#include "GrGpu.h" +#include "ops/GrMeshDrawOp.h" class GrGpuCommandBuffer; class GrResourceProvider; -/** Tracks the state across all the GrBatches in a GrDrawTarget flush. */ -class GrBatchFlushState { +/** Tracks the state across all the GrOps (really just the GrDrawOps) in a GrOpList flush. */ +class GrOpFlushState { public: - GrBatchFlushState(GrGpu*, GrResourceProvider*); + GrOpFlushState(GrGpu*, GrResourceProvider*); - ~GrBatchFlushState() { this->reset(); } + ~GrOpFlushState() { this->reset(); } - /** Inserts an upload to be executed after all batches in the flush prepared their draws - but before the draws are executed to the backend 3D API. */ - void addASAPUpload(GrDrawBatch::DeferredUploadFn&& upload) { + /** Inserts an upload to be executed after all ops in the flush prepared their draws but before + the draws are executed to the backend 3D API. */ + void addASAPUpload(GrDrawOp::DeferredUploadFn&& upload) { fAsapUploads.emplace_back(std::move(upload)); } @@ -31,34 +32,34 @@ public: GrResourceProvider* resourceProvider() const { return fResourceProvider; } /** Has the token been flushed to the backend 3D API. */ - bool hasDrawBeenFlushed(GrBatchDrawToken token) const { + bool hasDrawBeenFlushed(GrDrawOpUploadToken token) const { return token.fSequenceNumber <= fLastFlushedToken.fSequenceNumber; } /** Issue a token to an operation that is being enqueued. */ - GrBatchDrawToken issueDrawToken() { - return GrBatchDrawToken(++fLastIssuedToken.fSequenceNumber); + GrDrawOpUploadToken issueDrawToken() { + return GrDrawOpUploadToken(++fLastIssuedToken.fSequenceNumber); } /** Call every time a draw that was issued a token is flushed */ void flushToken() { ++fLastFlushedToken.fSequenceNumber; } /** Gets the next draw token that will be issued. */ - GrBatchDrawToken nextDrawToken() const { - return GrBatchDrawToken(fLastIssuedToken.fSequenceNumber + 1); + GrDrawOpUploadToken nextDrawToken() const { + return GrDrawOpUploadToken(fLastIssuedToken.fSequenceNumber + 1); } /** The last token flushed to all the way to the backend API. */ - GrBatchDrawToken nextTokenToFlush() const { - return GrBatchDrawToken(fLastFlushedToken.fSequenceNumber + 1); + GrDrawOpUploadToken nextTokenToFlush() const { + return GrDrawOpUploadToken(fLastFlushedToken.fSequenceNumber + 1); } void* makeVertexSpace(size_t vertexSize, int vertexCount, const GrBuffer** buffer, int* startVertex); uint16_t* makeIndexSpace(int indexCount, const GrBuffer** buffer, int* startIndex); - /** This is called after each batch has a chance to prepare its draws and before the draws - are issued. */ + /** This is called after each op has a chance to prepare its draws and before the draws are + issued. */ void preIssueDraws() { fVertexPool.unmap(); fIndexPool.unmap(); @@ -70,8 +71,8 @@ public: fAsapUploads.reset(); } - void doUpload(GrDrawBatch::DeferredUploadFn& upload) { - GrDrawBatch::WritePixelsFn wp = [this] (GrSurface* surface, + void doUpload(GrDrawOp::DeferredUploadFn& upload) { + GrDrawOp::WritePixelsFn wp = [this] (GrSurface* surface, int left, int top, int width, int height, GrPixelConfig config, const void* buffer, size_t rowBytes) -> bool { @@ -95,97 +96,105 @@ public: fIndexPool.reset(); } + /** Additional data required on a per-op basis when executing GrDrawOps. */ + struct DrawOpArgs { + GrRenderTarget* fRenderTarget; + const GrAppliedClip* fAppliedClip; + GrXferProcessor::DstTexture fDstTexture; + }; + + void setDrawOpArgs(DrawOpArgs* opArgs) { fOpArgs = opArgs; } + + const DrawOpArgs& drawOpArgs() const { + SkASSERT(fOpArgs); + return *fOpArgs; + } + private: - - GrGpu* fGpu; - - GrResourceProvider* fResourceProvider; - - GrGpuCommandBuffer* fCommandBuffer; - - GrVertexBufferAllocPool fVertexPool; - GrIndexBufferAllocPool fIndexPool; - - SkSTArray<4, GrDrawBatch::DeferredUploadFn> fAsapUploads; - - GrBatchDrawToken fLastIssuedToken; - - GrBatchDrawToken fLastFlushedToken; + GrGpu* fGpu; + GrResourceProvider* fResourceProvider; + GrGpuCommandBuffer* fCommandBuffer; + GrVertexBufferAllocPool fVertexPool; + GrIndexBufferAllocPool fIndexPool; + SkSTArray<4, GrDrawOp::DeferredUploadFn> fAsapUploads; + GrDrawOpUploadToken fLastIssuedToken; + GrDrawOpUploadToken fLastFlushedToken; + DrawOpArgs* fOpArgs; }; /** - * A word about uploads and tokens: Batches should usually schedule their uploads to occur at the + * A word about uploads and tokens: Ops should usually schedule their uploads to occur at the * begining of a frame whenever possible. These are called ASAP uploads. Of course, this requires * that there are no draws that have yet to be flushed that rely on the old texture contents. In * that case the ASAP upload would happen prior to the previous draw causing the draw to read the * new (wrong) texture data. In that case they should schedule an inline upload. * - * Batches, in conjunction with helpers such as GrBatchAtlas, can use the token system to know + * Ops, in conjunction with helpers such as GrDrawOpAtlas, can use the token system to know * what the most recent draw was that referenced a resource (or portion of a resource). Each draw * is assigned a token. A resource (or portion) can be tagged with the most recent draw's * token. The target provides a facility for testing whether the draw corresponding to the token - * has been flushed. If it has not been flushed then the batch must perform an inline upload - * instead. When scheduling an inline upload the batch provides the token of the draw that the - * upload must occur before. The upload will then occur between the draw that requires the new - * data but after the token that requires the old data. + * has been flushed. If it has not been flushed then the op must perform an inline upload instead. + * When scheduling an inline upload the op provides the token of the draw that the upload must occur + * before. The upload will then occur between the draw that requires the new data but after the + * token that requires the old data. * - * TODO: Currently the token/upload interface is spread over GrDrawBatch, GrVertexBatch, - * GrDrawBatch::Target, and GrVertexBatch::Target. However, the interface at the GrDrawBatch - * level is not complete and isn't useful. We should push it down to GrVertexBatch until it - * is required at the GrDrawBatch level. + * TODO: Currently the token/upload interface is spread over GrDrawOp, GrMeshDrawOp, + * GrDrawOp::Target, and GrMeshDrawOp::Target. However, the interface at the GrDrawOp level is not + * complete and isn't useful. We should push it down to GrMeshDrawOp until it is required at the + * GrDrawOp level. */ - + /** - * GrDrawBatch instances use this object to allocate space for their geometry and to issue the draws - * that render their batch. + * GrDrawOp instances use this object to allocate space for their geometry and to issue the draws + * that render their op. */ -class GrDrawBatch::Target { +class GrDrawOp::Target { public: - Target(GrBatchFlushState* state, GrDrawBatch* batch) : fState(state), fBatch(batch) {} + Target(GrOpFlushState* state, GrDrawOp* op) : fState(state), fOp(op) {} /** Returns the token of the draw that this upload will occur before. */ - GrBatchDrawToken addInlineUpload(DeferredUploadFn&& upload) { - fBatch->fInlineUploads.emplace_back(std::move(upload), fState->nextDrawToken()); - return fBatch->fInlineUploads.back().fUploadBeforeToken; + GrDrawOpUploadToken addInlineUpload(DeferredUploadFn&& upload) { + fOp->fInlineUploads.emplace_back(std::move(upload), fState->nextDrawToken()); + return fOp->fInlineUploads.back().fUploadBeforeToken; } /** Returns the token of the draw that this upload will occur before. Since ASAP uploads are done first during a flush, this will be the first token since the most recent flush. */ - GrBatchDrawToken addAsapUpload(DeferredUploadFn&& upload) { + GrDrawOpUploadToken addAsapUpload(DeferredUploadFn&& upload) { fState->addASAPUpload(std::move(upload)); return fState->nextTokenToFlush(); } - bool hasDrawBeenFlushed(GrBatchDrawToken token) const { + bool hasDrawBeenFlushed(GrDrawOpUploadToken token) const { return fState->hasDrawBeenFlushed(token); } - /** Gets the next draw token that will be issued by this target. This can be used by a batch + /** Gets the next draw token that will be issued by this target. This can be used by an op to record that the next draw it issues will use a resource (e.g. texture) while preparing that draw. */ - GrBatchDrawToken nextDrawToken() const { return fState->nextDrawToken(); } + GrDrawOpUploadToken nextDrawToken() const { return fState->nextDrawToken(); } const GrCaps& caps() const { return fState->caps(); } GrResourceProvider* resourceProvider() const { return fState->resourceProvider(); } protected: - GrDrawBatch* batch() { return fBatch; } - GrBatchFlushState* state() { return fState; } + GrDrawOp* op() { return fOp; } + GrOpFlushState* state() { return fState; } private: - GrBatchFlushState* fState; - GrDrawBatch* fBatch; + GrOpFlushState* fState; + GrDrawOp* fOp; }; -/** Extension of GrDrawBatch::Target for use by GrVertexBatch. Adds the ability to create vertex +/** Extension of GrDrawOp::Target for use by GrMeshDrawOp. Adds the ability to create vertex draws. */ -class GrVertexBatch::Target : public GrDrawBatch::Target { +class GrMeshDrawOp::Target : public GrDrawOp::Target { public: - Target(GrBatchFlushState* state, GrVertexBatch* batch) : INHERITED(state, batch) {} + Target(GrOpFlushState* state, GrMeshDrawOp* op) : INHERITED(state, op) {} - void draw(const GrGeometryProcessor* gp, const GrMesh& mesh); + void draw(const GrGeometryProcessor* gp, const GrPipeline* pipeline, const GrMesh& mesh); void* makeVertexSpace(size_t vertexSize, int vertexCount, const GrBuffer** buffer, int* startVertex) { @@ -196,15 +205,15 @@ public: return this->state()->makeIndexSpace(indexCount, buffer, startIndex); } - /** Helpers for batches which over-allocate and then return data to the pool. */ + /** Helpers for ops which over-allocate and then return data to the pool. */ void putBackIndices(int indices) { this->state()->putBackIndices(indices); } void putBackVertices(int vertices, size_t vertexStride) { this->state()->putBackVertexSpace(vertices * vertexStride); } private: - GrVertexBatch* vertexBatch() { return static_cast(this->batch()); } - typedef GrDrawBatch::Target INHERITED; + GrMeshDrawOp* meshDrawOp() { return static_cast(this->op()); } + typedef GrDrawOp::Target INHERITED; }; #endif diff --git a/gfx/skia/skia/src/gpu/GrOpList.cpp b/gfx/skia/skia/src/gpu/GrOpList.cpp new file mode 100644 index 000000000000..1f90f431a5e1 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrOpList.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrOpList.h" + +#include "GrRenderTargetOpList.h" +#include "GrSurface.h" +#include "GrSurfaceProxy.h" + +uint32_t GrOpList::CreateUniqueID() { + static int32_t gUniqueID = SK_InvalidUniqueID; + uint32_t id; + // Loop in case our global wraps around, as we never want to return a 0. + do { + id = static_cast(sk_atomic_inc(&gUniqueID) + 1); + } while (id == SK_InvalidUniqueID); + return id; +} + +GrOpList::GrOpList(GrSurfaceProxy* surfaceProxy, GrAuditTrail* auditTrail) + : fUniqueID(CreateUniqueID()) + , fFlags(0) + , fTarget(surfaceProxy) + , fAuditTrail(auditTrail) { + + surfaceProxy->setLastOpList(this); +} + +GrOpList::~GrOpList() { + if (fTarget && this == fTarget->getLastOpList()) { + fTarget->setLastOpList(nullptr); + } +} + +// Add a GrOpList-based dependency +void GrOpList::addDependency(GrOpList* dependedOn) { + SkASSERT(!dependedOn->dependsOn(this)); // loops are bad + + if (this->dependsOn(dependedOn)) { + return; // don't add duplicate dependencies + } + + *fDependencies.push() = dependedOn; +} + +// Convert from a GrSurface-based dependency to a GrOpList one +void GrOpList::addDependency(GrSurface* dependedOn) { + if (dependedOn->getLastOpList()) { + // If it is still receiving dependencies, this GrOpList shouldn't be closed + SkASSERT(!this->isClosed()); + + GrOpList* opList = dependedOn->getLastOpList(); + if (opList == this) { + // self-read - presumably for dst reads + } else { + this->addDependency(opList); + + // Can't make it closed in the self-read case + opList->makeClosed(); + } + } +} + +#ifdef SK_DEBUG +void GrOpList::dump() const { + SkDebugf("--------------------------------------------------------------\n"); + SkDebugf("node: %d -> RT: %d\n", fUniqueID, fTarget ? fTarget->uniqueID().asUInt() : -1); + SkDebugf("relies On (%d): ", fDependencies.count()); + for (int i = 0; i < fDependencies.count(); ++i) { + SkDebugf("%d, ", fDependencies[i]->fUniqueID); + } + SkDebugf("\n"); +} +#endif diff --git a/gfx/skia/skia/src/gpu/GrOpList.h b/gfx/skia/skia/src/gpu/GrOpList.h new file mode 100644 index 000000000000..557126681a3c --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrOpList.h @@ -0,0 +1,146 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrOpList_DEFINED +#define GrOpList_DEFINED + +#include "SkRefCnt.h" +#include "SkTDArray.h" + +//#define ENABLE_MDB 1 + +class GrAuditTrail; +class GrOpFlushState; +class GrRenderTargetOpList; +class GrSurface; +class GrSurfaceProxy; +class GrTextureOpList; + +class GrOpList : public SkRefCnt { +public: + GrOpList(GrSurfaceProxy* surfaceProxy, GrAuditTrail* auditTrail); + ~GrOpList() override; + + // These two methods are invoked as flush time + virtual void prepareOps(GrOpFlushState* flushState) = 0; + virtual bool executeOps(GrOpFlushState* flushState) = 0; + + virtual void makeClosed() { + // We only close GrOpLists when MDB is enabled. When MDB is disabled there is only + // ever one GrOpLists and all calls will be funnelled into it. +#ifdef ENABLE_MDB + this->setFlag(kClosed_Flag); +#endif + } + + // TODO: it seems a bit odd that GrOpList has nothing to clear on reset + virtual void reset() = 0; + + // TODO: in an MDB world, where the OpLists don't allocate GPU resources, it seems like + // these could go away + virtual void abandonGpuResources() = 0; + virtual void freeGpuResources() = 0; + + // TODO: this entry point is only needed in the non-MDB world. Remove when + // we make the switch to MDB + void clearTarget() { fTarget = nullptr; } + + bool isClosed() const { return this->isSetFlag(kClosed_Flag); } + + /* + * Notify this GrOpList that it relies on the contents of 'dependedOn' + */ + void addDependency(GrSurface* dependedOn); + + /* + * Does this opList depend on 'dependedOn'? + */ + bool dependsOn(GrOpList* dependedOn) const { + return fDependencies.find(dependedOn) >= 0; + } + + /* + * Safely cast this GrOpList to a GrTextureOpList (if possible). + */ + virtual GrTextureOpList* asTextureOpList() { return nullptr; } + + /* + * Safely case this GrOpList to a GrRenderTargetOpList (if possible). + */ + virtual GrRenderTargetOpList* asRenderTargetOpList() { return nullptr; } + + int32_t uniqueID() const { return fUniqueID; } + + /* + * Dump out the GrOpList dependency DAG + */ + SkDEBUGCODE(virtual void dump() const;) + +private: + friend class GrDrawingManager; // for resetFlag & TopoSortTraits + + static uint32_t CreateUniqueID(); + + enum Flags { + kClosed_Flag = 0x01, //!< This GrOpList can't accept any more ops + + kWasOutput_Flag = 0x02, //!< Flag for topological sorting + kTempMark_Flag = 0x04, //!< Flag for topological sorting + }; + + void setFlag(uint32_t flag) { + fFlags |= flag; + } + + void resetFlag(uint32_t flag) { + fFlags &= ~flag; + } + + bool isSetFlag(uint32_t flag) const { + return SkToBool(fFlags & flag); + } + + struct TopoSortTraits { + static void Output(GrOpList* dt, int /* index */) { + dt->setFlag(GrOpList::kWasOutput_Flag); + } + static bool WasOutput(const GrOpList* dt) { + return dt->isSetFlag(GrOpList::kWasOutput_Flag); + } + static void SetTempMark(GrOpList* dt) { + dt->setFlag(GrOpList::kTempMark_Flag); + } + static void ResetTempMark(GrOpList* dt) { + dt->resetFlag(GrOpList::kTempMark_Flag); + } + static bool IsTempMarked(const GrOpList* dt) { + return dt->isSetFlag(GrOpList::kTempMark_Flag); + } + static int NumDependencies(const GrOpList* dt) { + return dt->fDependencies.count(); + } + static GrOpList* Dependency(GrOpList* dt, int index) { + return dt->fDependencies[index]; + } + }; + + void addDependency(GrOpList* dependedOn); + + uint32_t fUniqueID; + uint32_t fFlags; + GrSurfaceProxy* fTarget; + + // 'this' GrOpList relies on the output of the GrOpLists in 'fDependencies' + SkTDArray fDependencies; + +protected: + GrAuditTrail* fAuditTrail; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrOvalRenderer.h b/gfx/skia/skia/src/gpu/GrOvalRenderer.h deleted file mode 100644 index c4ea4968d781..000000000000 --- a/gfx/skia/skia/src/gpu/GrOvalRenderer.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrOvalRenderer_DEFINED -#define GrOvalRenderer_DEFINED - -#include "GrColor.h" - -class GrDrawBatch; -class GrShaderCaps; -class GrStyle; -class SkMatrix; -struct SkRect; -class SkRRect; -class SkStrokeRec; - -/* - * This class wraps helper functions that draw ovals and roundrects (filled & stroked) - */ -class GrOvalRenderer { -public: - static GrDrawBatch* CreateOvalBatch(GrColor, - const SkMatrix& viewMatrix, - const SkRect& oval, - const SkStrokeRec& stroke, - const GrShaderCaps* shaderCaps); - static GrDrawBatch* CreateRRectBatch(GrColor, - const SkMatrix& viewMatrix, - const SkRRect& rrect, - const SkStrokeRec& stroke, - const GrShaderCaps* shaderCaps); - - static GrDrawBatch* CreateArcBatch(GrColor, - const SkMatrix& viewMatrix, - const SkRect& oval, - SkScalar startAngle, - SkScalar sweepAngle, - bool useCenter, - const GrStyle&, - const GrShaderCaps* shaderCaps); -}; - -#endif // GrOvalRenderer_DEFINED diff --git a/gfx/skia/skia/src/gpu/GrPLSGeometryProcessor.h b/gfx/skia/skia/src/gpu/GrPLSGeometryProcessor.h deleted file mode 100644 index 0640af63f073..000000000000 --- a/gfx/skia/skia/src/gpu/GrPLSGeometryProcessor.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrPLSGeometryProcessor_DEFINED -#define GrPLSGeometryProcessor_DEFINED - -#include "GrGeometryProcessor.h" - -/** - * A minor extension to GrGeometryProcessor that adds bounds tracking for pixel local storage - * purposes. - */ -class GrPLSGeometryProcessor : public GrGeometryProcessor { -public: - GrPixelLocalStorageState getPixelLocalStorageState() const override { - return GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState; - } - - const SkRect& getBounds() const { - return fBounds; - } - - void setBounds(SkRect& bounds) { - fBounds = bounds; - } - -private: - SkRect fBounds; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/GrPaint.cpp b/gfx/skia/skia/src/gpu/GrPaint.cpp index d33881c09d8a..6c5a041c9417 100644 --- a/gfx/skia/skia/src/gpu/GrPaint.cpp +++ b/gfx/skia/skia/src/gpu/GrPaint.cpp @@ -6,69 +6,70 @@ */ #include "GrPaint.h" - -#include "GrProcOptInfo.h" +#include "GrXferProcessor.h" #include "effects/GrCoverageSetOpXP.h" #include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrSimpleTextureEffect.h" -GrPaint::GrPaint() - : fAntiAlias(false) - , fDisableOutputConversionToSRGB(false) - , fAllowSRGBInputs(false) - , fUsesDistanceVectorField(false) - , fColor(GrColor4f::FromGrColor(GrColor_WHITE)) {} - -void GrPaint::setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) { - fXPFactory = GrCoverageSetOpXPFactory::Make(regionOp, invertCoverage); +void GrPaint::setPorterDuffXPFactory(SkBlendMode mode) { + fXPFactory = GrPorterDuffXPFactory::Get(mode); } -void GrPaint::addColorTextureProcessor(GrTexture* texture, +void GrPaint::setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) { + fXPFactory = GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage); +} + +void GrPaint::addColorTextureProcessor(GrResourceProvider* resourceProvider, + sk_sp proxy, sk_sp colorSpaceXform, const SkMatrix& matrix) { - this->addColorFragmentProcessor(GrSimpleTextureEffect::Make(texture, + this->addColorFragmentProcessor(GrSimpleTextureEffect::Make(resourceProvider, std::move(proxy), std::move(colorSpaceXform), matrix)); } -void GrPaint::addCoverageTextureProcessor(GrTexture* texture, const SkMatrix& matrix) { - this->addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(texture, nullptr, matrix)); -} - -void GrPaint::addColorTextureProcessor(GrTexture* texture, +void GrPaint::addColorTextureProcessor(GrResourceProvider* resourceProvider, + sk_sp proxy, sk_sp colorSpaceXform, const SkMatrix& matrix, - const GrTextureParams& params) { - this->addColorFragmentProcessor(GrSimpleTextureEffect::Make(texture, + const GrSamplerParams& params) { + this->addColorFragmentProcessor(GrSimpleTextureEffect::Make(resourceProvider, + std::move(proxy), std::move(colorSpaceXform), matrix, params)); } -void GrPaint::addCoverageTextureProcessor(GrTexture* texture, - const SkMatrix& matrix, - const GrTextureParams& params) { - this->addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(texture, nullptr, matrix, - params)); +void GrPaint::addCoverageTextureProcessor(GrResourceProvider* resourceProvider, + sk_sp proxy, + const SkMatrix& matrix) { + this->addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(resourceProvider, + std::move(proxy), + nullptr, matrix)); } -bool GrPaint::internalIsConstantBlendedColor(GrColor paintColor, GrColor* color) const { - GrProcOptInfo colorProcInfo; - colorProcInfo.calcWithInitialValues( - sk_sp_address_as_pointer_address(fColorFragmentProcessors.begin()), - this->numColorFragmentProcessors(), paintColor, kRGBA_GrColorComponentFlags, false); +void GrPaint::addCoverageTextureProcessor(GrResourceProvider* resourceProvider, + sk_sp proxy, + const SkMatrix& matrix, + const GrSamplerParams& params) { + this->addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(resourceProvider, + std::move(proxy), + nullptr, matrix, params)); +} - GrXPFactory::InvariantBlendedColor blendedColor; - if (fXPFactory) { - fXPFactory->getInvariantBlendedColor(colorProcInfo, &blendedColor); - } else { - GrPorterDuffXPFactory::SrcOverInvariantBlendedColor(colorProcInfo.color(), - colorProcInfo.validFlags(), - colorProcInfo.isOpaque(), - &blendedColor); +bool GrPaint::isConstantBlendedColor(GrColor* constantColor) const { + // This used to do a more sophisticated analysis but now it just explicitly looks for common + // cases. + static const GrXPFactory* kSrc = GrPorterDuffXPFactory::Get(SkBlendMode::kSrc); + static const GrXPFactory* kClear = GrPorterDuffXPFactory::Get(SkBlendMode::kClear); + if (kClear == fXPFactory) { + *constantColor = GrColor_TRANSPARENT_BLACK; + return true; } - - if (kRGBA_GrColorComponentFlags == blendedColor.fKnownColorFlags) { - *color = blendedColor.fKnownColor; + if (this->numColorFragmentProcessors()) { + return false; + } + if (kSrc == fXPFactory || (!fXPFactory && fColor.isOpaque())) { + *constantColor = fColor.toGrColor(); return true; } return false; diff --git a/gfx/skia/skia/include/gpu/GrPaint.h b/gfx/skia/skia/src/gpu/GrPaint.h similarity index 61% rename from gfx/skia/skia/include/gpu/GrPaint.h rename to gfx/skia/skia/src/gpu/GrPaint.h index a8af3c2f172d..bcf6858df8b0 100644 --- a/gfx/skia/skia/include/gpu/GrPaint.h +++ b/gfx/skia/skia/src/gpu/GrPaint.h @@ -12,13 +12,14 @@ #include "GrColor.h" #include "GrColorSpaceXform.h" -#include "GrXferProcessor.h" -#include "effects/GrPorterDuffXferProcessor.h" #include "GrFragmentProcessor.h" - #include "SkBlendMode.h" #include "SkRefCnt.h" #include "SkRegion.h" +#include "SkTLazy.h" + +class GrTextureProxy; +class GrXPFactory; /** * The paint describes how color and coverage are computed at each pixel by GrContext draw @@ -30,21 +31,18 @@ * The primitive color computation starts with the color specified by setColor(). This color is the * input to the first color stage. Each color stage feeds its output to the next color stage. * - * Fractional pixel coverage follows a similar flow. The coverage is initially the value specified - * by setCoverage(). This is input to the first coverage stage. Coverage stages are chained - * together in the same manner as color stages. The output of the last stage is modulated by any - * fractional coverage produced by anti-aliasing. This last step produces the final coverage, C. + * Fractional pixel coverage follows a similar flow. The GrGeometryProcessor (specified elsewhere) + * provides the initial coverage which is passed to the first coverage fragment processor, which + * feeds its output to next coverage fragment processor. * * setXPFactory is used to control blending between the output color and dest. It also implements * the application of fractional coverage from the coverage pipeline. */ class GrPaint { public: - GrPaint(); - - GrPaint(const GrPaint& paint) { *this = paint; } - - ~GrPaint() { } + GrPaint() = default; + explicit GrPaint(const GrPaint&) = default; + ~GrPaint() = default; /** * The initial color of the drawn primitive. Defaults to solid white. @@ -57,12 +55,6 @@ public: */ GrColor getColor() const { return fColor.toGrColor(); } - /** - * Should primitives be anti-aliased or not. Defaults to false. - */ - void setAntiAlias(bool aa) { fAntiAlias = aa; } - bool isAntiAlias() const { return fAntiAlias; } - /** * Should shader output conversion from linear to sRGB be disabled. * Only relevant if the destination is sRGB. Defaults to false. @@ -91,17 +83,9 @@ public: setAllowSRGBInputs(gammaCorrect); } - void setXPFactory(sk_sp xpFactory) { - fXPFactory = std::move(xpFactory); - } + void setXPFactory(const GrXPFactory* xpFactory) { fXPFactory = xpFactory; } - void setPorterDuffXPFactory(SkBlendMode mode) { - fXPFactory = GrPorterDuffXPFactory::Make((SkXfermode::Mode)mode); - } - - void setPorterDuffXPFactory(SkXfermode::Mode mode) { - fXPFactory = GrPorterDuffXPFactory::Make(mode); - } + void setPorterDuffXPFactory(SkBlendMode mode); void setCoverageSetOpXPFactory(SkRegion::Op, bool invertCoverage = false); @@ -127,20 +111,22 @@ public: * Helpers for adding color or coverage effects that sample a texture. The matrix is applied * to the src space position to compute texture coordinates. */ - void addColorTextureProcessor(GrTexture*, sk_sp, const SkMatrix&); - void addCoverageTextureProcessor(GrTexture*, const SkMatrix&); - void addColorTextureProcessor(GrTexture*, sk_sp, const SkMatrix&, - const GrTextureParams&); - void addCoverageTextureProcessor(GrTexture*, const SkMatrix&, const GrTextureParams&); + void addColorTextureProcessor(GrResourceProvider*, sk_sp, + sk_sp, const SkMatrix&); + void addColorTextureProcessor(GrResourceProvider*, sk_sp, + sk_sp, const SkMatrix&, + const GrSamplerParams&); + + void addCoverageTextureProcessor(GrResourceProvider*, sk_sp, const SkMatrix&); + void addCoverageTextureProcessor(GrResourceProvider*, sk_sp, + const SkMatrix&, const GrSamplerParams&); int numColorFragmentProcessors() const { return fColorFragmentProcessors.count(); } int numCoverageFragmentProcessors() const { return fCoverageFragmentProcessors.count(); } int numTotalFragmentProcessors() const { return this->numColorFragmentProcessors() + this->numCoverageFragmentProcessors(); } - GrXPFactory* getXPFactory() const { - return fXPFactory.get(); - } + const GrXPFactory* getXPFactory() const { return fXPFactory; } GrFragmentProcessor* getColorFragmentProcessor(int i) const { return fColorFragmentProcessors[i].get(); @@ -149,52 +135,69 @@ public: return fCoverageFragmentProcessors[i].get(); } - GrPaint& operator=(const GrPaint& paint) { - fAntiAlias = paint.fAntiAlias; - fDisableOutputConversionToSRGB = paint.fDisableOutputConversionToSRGB; - fAllowSRGBInputs = paint.fAllowSRGBInputs; - fUsesDistanceVectorField = paint.fUsesDistanceVectorField; - - fColor = paint.fColor; - fColorFragmentProcessors = paint.fColorFragmentProcessors; - fCoverageFragmentProcessors = paint.fCoverageFragmentProcessors; - - fXPFactory = paint.fXPFactory; - - return *this; - } - /** * Returns true if the paint's output color will be constant after blending. If the result is * true, constantColor will be updated to contain the constant color. Note that we can conflate * coverage and color, so the actual values written to pixels with partial coverage may still * not seem constant, even if this function returns true. */ - bool isConstantBlendedColor(GrColor* constantColor) const { - GrColor paintColor = this->getColor(); - if (!fXPFactory && fColorFragmentProcessors.empty()) { - if (!GrColorIsOpaque(paintColor)) { - return false; - } - *constantColor = paintColor; - return true; - } - return this->internalIsConstantBlendedColor(paintColor, constantColor); - } + bool isConstantBlendedColor(GrColor* constantColor) const; private: - bool internalIsConstantBlendedColor(GrColor paintColor, GrColor* constantColor) const; + template class MoveOrImpl; - mutable sk_sp fXPFactory; +public: + /** + * A temporary instance of this class can be used to select between moving an existing paint or + * a temporary copy of an existing paint into a call site. MoveOrClone(paint, false) is a rvalue + * reference to paint while MoveOrClone(paint, true) is a rvalue reference to a copy of paint. + */ + using MoveOrClone = MoveOrImpl; + + /** + * A temporary instance of this class can be used to select between moving an existing or a + * newly default constructed paint into a call site. MoveOrNew(paint, false) is a rvalue + * reference to paint while MoveOrNew(paint, true) is a rvalue reference to a default paint. + */ + using MoveOrNew = MoveOrImpl; + +private: + GrPaint& operator=(const GrPaint&) = delete; + + friend class GrProcessorSet; + + const GrXPFactory* fXPFactory = nullptr; SkSTArray<4, sk_sp> fColorFragmentProcessors; SkSTArray<2, sk_sp> fCoverageFragmentProcessors; + bool fDisableOutputConversionToSRGB = false; + bool fAllowSRGBInputs = false; + bool fUsesDistanceVectorField = false; + GrColor4f fColor = GrColor4f::OpaqueWhite(); +}; - bool fAntiAlias; - bool fDisableOutputConversionToSRGB; - bool fAllowSRGBInputs; - bool fUsesDistanceVectorField; +/** This is the implementation of MoveOrCopy and MoveOrNew. */ +template +class GrPaint::MoveOrImpl { +public: + MoveOrImpl(GrPaint& paint, bool newPaint) { + if (newPaint) { + if (COPY_IF_NEW) { + fStorage.init(paint); + } else { + fStorage.init(); + }; + fPaint = fStorage.get(); + } else { + fPaint = &paint; + } + } - GrColor4f fColor; + operator GrPaint&&() && { return std::move(*fPaint); } + GrPaint& paint() { return *fPaint; } + +private: + SkTLazy fStorage; + GrPaint* fPaint; }; #endif diff --git a/gfx/skia/skia/src/gpu/GrPathProcessor.cpp b/gfx/skia/skia/src/gpu/GrPathProcessor.cpp index c90481b8da8c..39d418ba6b6b 100644 --- a/gfx/skia/skia/src/gpu/GrPathProcessor.cpp +++ b/gfx/skia/skia/src/gpu/GrPathProcessor.cpp @@ -7,8 +7,8 @@ #include "GrPathProcessor.h" +#include "GrShaderCaps.h" #include "gl/GrGLGpu.h" -#include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" @@ -18,11 +18,9 @@ public: GrGLPathProcessor() : fColor(GrColor_ILLEGAL) {} static void GenKey(const GrPathProcessor& pathProc, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { - b->add32(SkToInt(pathProc.overrides().readsColor()) | - (SkToInt(pathProc.overrides().readsCoverage()) << 1) | - (SkToInt(pathProc.viewMatrix().hasPerspective()) << 2)); + b->add32(SkToInt(pathProc.viewMatrix().hasPerspective())); } void emitCode(EmitArgs& args) override { @@ -37,20 +35,16 @@ public: this->emitTransforms(args.fVaryingHandler, args.fFPCoordTransformHandler); // Setup uniform color - if (pathProc.overrides().readsColor()) { - const char* stagedLocalVarName; - fColorUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, - kVec4f_GrSLType, - kDefault_GrSLPrecision, - "Color", - &stagedLocalVarName); - fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, stagedLocalVarName); - } + const char* stagedLocalVarName; + fColorUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, + kVec4f_GrSLType, + kDefault_GrSLPrecision, + "Color", + &stagedLocalVarName); + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, stagedLocalVarName); // setup constant solid coverage - if (pathProc.overrides().readsCoverage()) { - fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage); - } + fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage); } void emitTransforms(GrGLSLVaryingHandler* varyingHandler, @@ -79,7 +73,7 @@ public: const GrPrimitiveProcessor& primProc, FPCoordTransformIter&& transformIter) override { const GrPathProcessor& pathProc = primProc.cast(); - if (pathProc.overrides().readsColor() && pathProc.color() != fColor) { + if (pathProc.color() != fColor) { float c[4]; GrColorToRGBAFloat(pathProc.color(), c); pd.set4fv(fColorUniform, 1, c); @@ -120,22 +114,20 @@ private: }; GrPathProcessor::GrPathProcessor(GrColor color, - const GrXPOverridesForBatch& overrides, const SkMatrix& viewMatrix, const SkMatrix& localMatrix) - : fColor(color) - , fViewMatrix(viewMatrix) - , fLocalMatrix(localMatrix) - , fOverrides(overrides) { + : fColor(color) + , fViewMatrix(viewMatrix) + , fLocalMatrix(localMatrix) { this->initClassID(); } -void GrPathProcessor::getGLSLProcessorKey(const GrGLSLCaps& caps, +void GrPathProcessor::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLPathProcessor::GenKey(*this, caps, b); } -GrGLSLPrimitiveProcessor* GrPathProcessor::createGLSLInstance(const GrGLSLCaps& caps) const { +GrGLSLPrimitiveProcessor* GrPathProcessor::createGLSLInstance(const GrShaderCaps& caps) const { SkASSERT(caps.pathRenderingSupport()); return new GrGLPathProcessor(); } diff --git a/gfx/skia/skia/src/gpu/GrPathProcessor.h b/gfx/skia/skia/src/gpu/GrPathProcessor.h index 8c9e0d6be2b5..581bd5052f6e 100644 --- a/gfx/skia/skia/src/gpu/GrPathProcessor.h +++ b/gfx/skia/skia/src/gpu/GrPathProcessor.h @@ -17,10 +17,9 @@ class GrPathProcessor : public GrPrimitiveProcessor { public: static GrPathProcessor* Create(GrColor color, - const GrXPOverridesForBatch& overrides, const SkMatrix& viewMatrix = SkMatrix::I(), const SkMatrix& localMatrix = SkMatrix::I()) { - return new GrPathProcessor(color, overrides, viewMatrix, localMatrix); + return new GrPathProcessor(color, viewMatrix, localMatrix); } const char* name() const override { return "PathProcessor"; } @@ -31,25 +30,21 @@ public: bool willUseGeoShader() const override { return false; } - virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, + virtual void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps& caps) const override; - - const GrXPOverridesForBatch& overrides() const { return fOverrides; } + virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override; virtual bool isPathRendering() const override { return true; } private: - GrPathProcessor(GrColor color, const GrXPOverridesForBatch& overrides, - const SkMatrix& viewMatrix, const SkMatrix& localMatrix); + GrPathProcessor(GrColor, const SkMatrix& viewMatrix, const SkMatrix& localMatrix); bool hasExplicitLocalCoords() const override { return false; } GrColor fColor; const SkMatrix fViewMatrix; const SkMatrix fLocalMatrix; - GrXPOverridesForBatch fOverrides; typedef GrPrimitiveProcessor INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/GrPathRange.h b/gfx/skia/skia/src/gpu/GrPathRange.h index 7bca17f26057..39779a700835 100644 --- a/gfx/skia/skia/src/gpu/GrPathRange.h +++ b/gfx/skia/skia/src/gpu/GrPathRange.h @@ -143,7 +143,7 @@ private: kPathsPerGroup = 16 // Paths get tracked in groups of 16 for lazy loading. }; - mutable SkAutoTUnref fPathGenerator; + mutable sk_sp fPathGenerator; mutable SkTArray fGeneratedPaths; const int fNumPaths; diff --git a/gfx/skia/skia/src/gpu/GrPathRenderer.h b/gfx/skia/skia/src/gpu/GrPathRenderer.h index 37cc3f986307..05673d5f8642 100644 --- a/gfx/skia/skia/src/gpu/GrPathRenderer.h +++ b/gfx/skia/skia/src/gpu/GrPathRenderer.h @@ -9,7 +9,7 @@ #define GrPathRenderer_DEFINED #include "GrCaps.h" -#include "GrDrawContext.h" +#include "GrRenderTargetContext.h" #include "GrPaint.h" #include "GrResourceProvider.h" #include "GrShape.h" @@ -22,7 +22,7 @@ class GrFixedClip; struct GrPoint; /** - * Base class for drawing paths into a GrDrawTarget. + * Base class for drawing paths into a GrOpList. * * Derived classes can use stages GrPaint::kTotalStages through GrPipelineBuilder::kNumStages-1. * The stages before GrPaint::kTotalStages are reserved for setting up the draw (i.e., textures and @@ -40,10 +40,10 @@ public: * rendered into the stencil. * * A GrPathRenderer can provide three levels of support for stenciling paths: - * 1) kNoRestriction: This is the most general. The caller sets up the GrPipelineBuilder on the target - * and calls drawPath(). The path is rendered exactly as the draw state - * indicates including support for simultaneous color and stenciling with - * arbitrary stenciling rules. Pixels partially covered by AA paths are + * 1) kNoRestriction: This is the most general. The caller sets up the GrPipelineBuilder on the + * target and calls drawPath(). The path is rendered exactly as the draw + * state indicates including support for simultaneous color and stenciling + * with arbitrary stenciling rules. Pixels partially covered by AA paths are * affected by the stencil settings. * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil * simultaneously. The path renderer does support the stencilPath() function @@ -78,17 +78,16 @@ public: * fPipelineBuilder The pipelineBuilder * fViewMatrix The viewMatrix * fShape The shape to draw - * fAntiAlias True if anti-aliasing is required. + * fAntiAlias The type of anti aliasing required. */ struct CanDrawPathArgs { const GrShaderCaps* fShaderCaps; const SkMatrix* fViewMatrix; const GrShape* fShape; - bool fAntiAlias; + GrAAType fAAType; // These next two are only used by GrStencilAndCoverPathRenderer bool fHasUserStencilSettings; - bool fIsStencilBufferMSAA; #ifdef SK_DEBUG void validate() const { @@ -121,26 +120,24 @@ public: * fColor Color to render with * fViewMatrix The viewMatrix * fShape The shape to draw - * fAntiAlias true if anti-aliasing is required. + * fAAtype true if anti-aliasing is required. * fGammaCorrect true if gamma-correct rendering is to be used. */ struct DrawPathArgs { - GrResourceProvider* fResourceProvider; - const GrPaint* fPaint; - const GrUserStencilSettings*fUserStencilSettings; - - GrDrawContext* fDrawContext; - const GrClip* fClip; - const SkMatrix* fViewMatrix; - const GrShape* fShape; - bool fAntiAlias; - bool fGammaCorrect; + GrContext* fContext; + GrPaint&& fPaint; + const GrUserStencilSettings* fUserStencilSettings; + GrRenderTargetContext* fRenderTargetContext; + const GrClip* fClip; + const SkMatrix* fViewMatrix; + const GrShape* fShape; + GrAAType fAAType; + bool fGammaCorrect; #ifdef SK_DEBUG void validate() const { - SkASSERT(fResourceProvider); - SkASSERT(fPaint); + SkASSERT(fContext); SkASSERT(fUserStencilSettings); - SkASSERT(fDrawContext); + SkASSERT(fRenderTargetContext); SkASSERT(fClip); SkASSERT(fViewMatrix); SkASSERT(fShape); @@ -156,13 +153,16 @@ public: SkDEBUGCODE(args.validate();) #ifdef SK_DEBUG CanDrawPathArgs canArgs; - canArgs.fShaderCaps = args.fResourceProvider->caps()->shaderCaps(); + canArgs.fShaderCaps = args.fContext->caps()->shaderCaps(); canArgs.fViewMatrix = args.fViewMatrix; canArgs.fShape = args.fShape; - canArgs.fAntiAlias = args.fAntiAlias; + canArgs.fAAType = args.fAAType; canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused(); - canArgs.fIsStencilBufferMSAA = args.fDrawContext->isStencilBufferMultisampled(); + SkASSERT(!(canArgs.fAAType == GrAAType::kMSAA && + !args.fRenderTargetContext->isUnifiedMultisampled())); + SkASSERT(!(canArgs.fAAType == GrAAType::kMixedSamples && + !args.fRenderTargetContext->isStencilBufferMultisampled())); SkASSERT(this->canDrawPath(canArgs)); if (!args.fUserStencilSettings->isUnused()) { SkPath path; @@ -177,26 +177,27 @@ public: /* Args to stencilPath(). * * fResourceProvider The resource provider for creating gpu resources to render the path - * fDrawContext The target of the draws + * fRenderTargetContext The target of the draws * fViewMatrix Matrix applied to the path. * fPath The path to draw. - * fIsAA Is the path to be drawn AA (only set when MSAA is available) + * fAAType The type of AA, cannot be kCoverage. */ struct StencilPathArgs { - GrResourceProvider* fResourceProvider; - GrDrawContext* fDrawContext; - const GrClip* fClip; - const SkMatrix* fViewMatrix; - bool fIsAA; - const GrShape* fShape; + GrContext* fContext; + GrRenderTargetContext* fRenderTargetContext; + const GrClip* fClip; + const SkMatrix* fViewMatrix; + GrAAType fAAType; + const GrShape* fShape; #ifdef SK_DEBUG void validate() const { - SkASSERT(fResourceProvider); - SkASSERT(fDrawContext); + SkASSERT(fContext); + SkASSERT(fRenderTargetContext); SkASSERT(fViewMatrix); SkASSERT(fShape); SkASSERT(fShape->style().isSimpleFill()); + SkASSERT(GrAAType::kCoverage != fAAType); SkPath path; fShape->asPath(&path); SkASSERT(!path.isInverseFillType()); @@ -276,15 +277,15 @@ private: GrPaint paint; - DrawPathArgs drawArgs; - drawArgs.fResourceProvider = args.fResourceProvider; - drawArgs.fPaint = &paint; - drawArgs.fUserStencilSettings = &kIncrementStencil; - drawArgs.fDrawContext = args.fDrawContext; - drawArgs.fViewMatrix = args.fViewMatrix; - drawArgs.fShape = args.fShape; - drawArgs.fAntiAlias = false; // In this case the MSAA handles the AA so we want to draw BW - drawArgs.fGammaCorrect = false; + DrawPathArgs drawArgs{args.fContext, + std::move(paint), + &kIncrementStencil, + args.fRenderTargetContext, + nullptr, // clip + args.fViewMatrix, + args.fShape, + args.fAAType, + false}; this->drawPath(drawArgs); } diff --git a/gfx/skia/skia/src/gpu/GrPathRendererChain.cpp b/gfx/skia/skia/src/gpu/GrPathRendererChain.cpp index 95105ba079bf..55c4a305dc4d 100644 --- a/gfx/skia/skia/src/gpu/GrPathRendererChain.cpp +++ b/gfx/skia/skia/src/gpu/GrPathRendererChain.cpp @@ -9,61 +9,60 @@ #include "GrPathRendererChain.h" #include "GrCaps.h" +#include "GrShaderCaps.h" #include "gl/GrGLCaps.h" -#include "glsl/GrGLSLCaps.h" #include "GrContext.h" #include "GrGpu.h" -#include "batches/GrAAConvexPathRenderer.h" -#include "batches/GrAADistanceFieldPathRenderer.h" -#include "batches/GrAAHairLinePathRenderer.h" -#include "batches/GrAALinearizingConvexPathRenderer.h" -#include "batches/GrDashLinePathRenderer.h" -#include "batches/GrDefaultPathRenderer.h" -#include "batches/GrMSAAPathRenderer.h" -#include "batches/GrPLSPathRenderer.h" -#include "batches/GrStencilAndCoverPathRenderer.h" -#include "batches/GrTessellatingPathRenderer.h" +#include "ops/GrAAConvexPathRenderer.h" +#include "ops/GrAAHairLinePathRenderer.h" +#include "ops/GrAALinearizingConvexPathRenderer.h" +#include "ops/GrSmallPathRenderer.h" +#include "ops/GrDashLinePathRenderer.h" +#include "ops/GrDefaultPathRenderer.h" +#include "ops/GrMSAAPathRenderer.h" +#include "ops/GrStencilAndCoverPathRenderer.h" +#include "ops/GrTessellatingPathRenderer.h" GrPathRendererChain::GrPathRendererChain(GrContext* context, const Options& options) { - if (!options.fDisableAllPathRenderers) { - const GrCaps& caps = *context->caps(); - this->addPathRenderer(new GrDashLinePathRenderer)->unref(); - - if (GrPathRenderer* pr = GrStencilAndCoverPathRenderer::Create(context->resourceProvider(), - caps)) { - this->addPathRenderer(pr)->unref(); + using GpuPathRenderers = GrContextOptions::GpuPathRenderers; + const GrCaps& caps = *context->caps(); + if (options.fGpuPathRenderers & GpuPathRenderers::kDashLine) { + fChain.push_back(sk_make_sp()); + } + if (options.fGpuPathRenderers & GpuPathRenderers::kStencilAndCover) { + sk_sp pr( + GrStencilAndCoverPathRenderer::Create(context->resourceProvider(), caps)); + if (pr) { + fChain.push_back(std::move(pr)); } - #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK + } +#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK + if (options.fGpuPathRenderers & GpuPathRenderers::kMSAA) { if (caps.sampleShadingSupport()) { - this->addPathRenderer(new GrMSAAPathRenderer)->unref(); + fChain.push_back(sk_make_sp()); } - #endif - this->addPathRenderer(new GrAAHairLinePathRenderer)->unref(); - this->addPathRenderer(new GrAAConvexPathRenderer)->unref(); - this->addPathRenderer(new GrAALinearizingConvexPathRenderer)->unref(); - if (caps.shaderCaps()->plsPathRenderingSupport()) { - this->addPathRenderer(new GrPLSPathRenderer)->unref(); - } - if (!options.fDisableDistanceFieldRenderer) { - this->addPathRenderer(new GrAADistanceFieldPathRenderer)->unref(); - } - this->addPathRenderer(new GrTessellatingPathRenderer)->unref(); - this->addPathRenderer(new GrDefaultPathRenderer(caps.twoSidedStencilSupport(), - caps.stencilWrapOpsSupport()))->unref(); } -} - -GrPathRendererChain::~GrPathRendererChain() { - for (int i = 0; i < fChain.count(); ++i) { - fChain[i]->unref(); +#endif + if (options.fGpuPathRenderers & GpuPathRenderers::kAAHairline) { + fChain.push_back(sk_make_sp()); + } + if (options.fGpuPathRenderers & GpuPathRenderers::kAAConvex) { + fChain.push_back(sk_make_sp()); + } + if (options.fGpuPathRenderers & GpuPathRenderers::kAALinearizing) { + fChain.push_back(sk_make_sp()); + } + if (options.fGpuPathRenderers & GpuPathRenderers::kSmall) { + fChain.push_back(sk_make_sp()); + } + if (options.fGpuPathRenderers & GpuPathRenderers::kTessellating) { + fChain.push_back(sk_make_sp()); + } + if (options.fGpuPathRenderers & GpuPathRenderers::kDefault) { + fChain.push_back(sk_make_sp(caps.twoSidedStencilSupport(), + caps.stencilWrapOpsSupport())); } -} - -GrPathRenderer* GrPathRendererChain::addPathRenderer(GrPathRenderer* pr) { - fChain.push_back() = pr; - pr->ref(); - return pr; } GrPathRenderer* GrPathRendererChain::getPathRenderer( @@ -75,10 +74,9 @@ GrPathRenderer* GrPathRendererChain::getPathRenderer( GR_STATIC_ASSERT(GrPathRenderer::kStencilOnly_StencilSupport < GrPathRenderer::kNoRestriction_StencilSupport); GrPathRenderer::StencilSupport minStencilSupport; - if (kStencilOnly_DrawType == drawType) { + if (DrawType::kStencil == drawType) { minStencilSupport = GrPathRenderer::kStencilOnly_StencilSupport; - } else if (kStencilAndColor_DrawType == drawType || - kStencilAndColorAntiAlias_DrawType == drawType) { + } else if (DrawType::kStencilAndColor == drawType) { minStencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; } else { minStencilSupport = GrPathRenderer::kNoSupport_StencilSupport; @@ -100,7 +98,7 @@ GrPathRenderer* GrPathRendererChain::getPathRenderer( *stencilSupport = support; } } - return fChain[i]; + return fChain[i].get(); } } return nullptr; diff --git a/gfx/skia/skia/src/gpu/GrPathRendererChain.h b/gfx/skia/skia/src/gpu/GrPathRendererChain.h index 8788374d71d4..c0a0ee39f568 100644 --- a/gfx/skia/skia/src/gpu/GrPathRendererChain.h +++ b/gfx/skia/skia/src/gpu/GrPathRendererChain.h @@ -10,6 +10,7 @@ #include "GrPathRenderer.h" +#include "GrContextOptions.h" #include "SkTypes.h" #include "SkTArray.h" @@ -24,23 +25,18 @@ class GrContext; class GrPathRendererChain : public SkNoncopyable { public: struct Options { - bool fDisableDistanceFieldRenderer = false; + using GpuPathRenderers = GrContextOptions::GpuPathRenderers; bool fAllowPathMaskCaching = false; - bool fDisableAllPathRenderers = false; + GpuPathRenderers fGpuPathRenderers = GpuPathRenderers::kAll; }; GrPathRendererChain(GrContext* context, const Options&); - ~GrPathRendererChain(); - /** Documents how the caller plans to use a GrPathRenderer to draw a path. It affects the PR returned by getPathRenderer */ - enum DrawType { - kColor_DrawType, // draw to the color buffer, no AA - kColorAntiAlias_DrawType, // draw to color buffer, with partial coverage AA - kStencilOnly_DrawType, // draw just to the stencil buffer - kStencilAndColor_DrawType, // draw the stencil and color buffer, no AA - kStencilAndColorAntiAlias_DrawType // draw the stencil and color buffer, with partial - // coverage AA. + enum class DrawType { + kColor, // draw to the color buffer, no AA + kStencil, // draw just to the stencil buffer + kStencilAndColor, // draw the stencil and color buffer, no AA }; /** Returns a GrPathRenderer compatible with the request if one is available. If the caller @@ -52,13 +48,10 @@ public: GrPathRenderer::StencilSupport* stencilSupport); private: - // takes a ref and unrefs in destructor - GrPathRenderer* addPathRenderer(GrPathRenderer* pr); - enum { kPreAllocCount = 8, }; - SkSTArray fChain; + SkSTArray> fChain; }; #endif diff --git a/gfx/skia/skia/src/gpu/GrPathRendering.cpp b/gfx/skia/skia/src/gpu/GrPathRendering.cpp index fe912e23a2ec..18d000a17793 100644 --- a/gfx/skia/skia/src/gpu/GrPathRendering.cpp +++ b/gfx/skia/skia/src/gpu/GrPathRendering.cpp @@ -53,30 +53,20 @@ public: #endif {} - virtual ~GlyphGenerator() { -#ifdef SK_DEBUG - SkDescriptor::Free(fDesc); -#endif - } - int getNumPaths() override { return fScalerContext->getGlyphCount(); } void generatePath(int glyphID, SkPath* out) override { - SkGlyph skGlyph; - skGlyph.initWithGlyphID(glyphID); - fScalerContext->getMetrics(&skGlyph); - - fScalerContext->getPath(skGlyph, out); + fScalerContext->getPath(glyphID, out); } #ifdef SK_DEBUG bool isEqualTo(const SkDescriptor& desc) const override { return *fDesc == desc; } #endif private: - const SkAutoTDelete fScalerContext; + const std::unique_ptr fScalerContext; #ifdef SK_DEBUG - SkDescriptor* const fDesc; + const std::unique_ptr fDesc; #endif }; @@ -90,8 +80,8 @@ GrPathRange* GrPathRendering::createGlyphs(const SkTypeface* typeface, } if (desc) { - SkAutoTUnref generator(new GlyphGenerator(*typeface, effects, *desc)); - return this->createPathRange(generator, style); + sk_sp generator(new GlyphGenerator(*typeface, effects, *desc)); + return this->createPathRange(generator.get(), style); } SkScalerContextRec rec; @@ -111,6 +101,6 @@ GrPathRange* GrPathRendering::createGlyphs(const SkTypeface* typeface, // No effects, so we make a dummy struct SkScalerContextEffects noEffects; - SkAutoTUnref generator(new GlyphGenerator(*typeface, noEffects, *genericDesc)); - return this->createPathRange(generator, style); + sk_sp generator(new GlyphGenerator(*typeface, noEffects, *genericDesc)); + return this->createPathRange(generator.get(), style); } diff --git a/gfx/skia/skia/src/gpu/GrPathRenderingDrawContext.cpp b/gfx/skia/skia/src/gpu/GrPathRenderingDrawContext.cpp deleted file mode 100644 index 1380f7dc78a5..000000000000 --- a/gfx/skia/skia/src/gpu/GrPathRenderingDrawContext.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrPathRenderingDrawContext.h" - -#include "GrDrawingManager.h" - -#include "text/GrStencilAndCoverTextContext.h" - -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());) -#define RETURN_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return; } - -void GrPathRenderingDrawContext::drawText(const GrClip& clip, const GrPaint& grPaint, - const SkPaint& skPaint, - const SkMatrix& viewMatrix, const char text[], - size_t byteLength, SkScalar x, SkScalar y, - const SkIRect& clipBounds) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrPathRenderingDrawContext::drawText"); - - if (!fStencilAndCoverTextContext) { - GrAtlasTextContext* fallbackContext = this->drawingManager()->getAtlasTextContext(); - fStencilAndCoverTextContext.reset(GrStencilAndCoverTextContext::Create(fallbackContext)); - } - - fStencilAndCoverTextContext->drawText(this->drawingManager()->getContext(), this, clip, grPaint, - skPaint, viewMatrix, this->surfaceProps(), - text, byteLength, x, y, clipBounds); -} - -void GrPathRenderingDrawContext::drawPosText(const GrClip& clip, const GrPaint& grPaint, - const SkPaint& skPaint, - const SkMatrix& viewMatrix, const char text[], - size_t byteLength, const SkScalar pos[], - int scalarsPerPosition, const SkPoint& offset, - const SkIRect& clipBounds) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrPathRenderingDrawContext::drawPosText"); - - if (!fStencilAndCoverTextContext) { - GrAtlasTextContext* fallbackContext = this->drawingManager()->getAtlasTextContext(); - fStencilAndCoverTextContext.reset(GrStencilAndCoverTextContext::Create(fallbackContext)); - } - - fStencilAndCoverTextContext->drawPosText(this->drawingManager()->getContext(), this, clip, - grPaint, skPaint, viewMatrix, this->surfaceProps(), - text, byteLength, pos, scalarsPerPosition, offset, - clipBounds); -} - -void GrPathRenderingDrawContext::drawTextBlob(const GrClip& clip, const SkPaint& skPaint, - const SkMatrix& viewMatrix, const SkTextBlob* blob, - SkScalar x, SkScalar y, - SkDrawFilter* filter, const SkIRect& clipBounds) { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrPathRenderingDrawContext::drawTextBlob"); - - if (!fStencilAndCoverTextContext) { - GrAtlasTextContext* fallbackContext = this->drawingManager()->getAtlasTextContext(); - fStencilAndCoverTextContext.reset(GrStencilAndCoverTextContext::Create(fallbackContext)); - } - - fStencilAndCoverTextContext->drawTextBlob(this->drawingManager()->getContext(), this, clip, - skPaint, viewMatrix, this->surfaceProps(), blob, x, - y, filter, clipBounds); -} diff --git a/gfx/skia/skia/src/gpu/GrPathRenderingDrawContext.h b/gfx/skia/skia/src/gpu/GrPathRenderingDrawContext.h deleted file mode 100644 index 5c1a968b1772..000000000000 --- a/gfx/skia/skia/src/gpu/GrPathRenderingDrawContext.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrPathRenderingDrawContext_DEFINED -#define GrPathRenderingDrawContext_DEFINED - -#include "GrDrawContext.h" - -class GrStencilAndCoverTextContext; - -class GrPathRenderingDrawContext : public GrDrawContext { -public: - void drawText(const GrClip&, const GrPaint&, const SkPaint&, - const SkMatrix& viewMatrix, const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkIRect& clipBounds) override; - void drawPosText(const GrClip&, const GrPaint&, const SkPaint&, - const SkMatrix& viewMatrix, const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkIRect& clipBounds) override; - void drawTextBlob(const GrClip&, const SkPaint&, - const SkMatrix& viewMatrix, const SkTextBlob*, - SkScalar x, SkScalar y, - SkDrawFilter*, const SkIRect& clipBounds) override; -protected: - GrPathRenderingDrawContext(GrContext* ctx, GrDrawingManager* mgr, sk_sp rt, - sk_sp colorSpace, const SkSurfaceProps* surfaceProps, - GrAuditTrail* at, GrSingleOwner* so) - : INHERITED(ctx, mgr, std::move(rt), std::move(colorSpace), surfaceProps, at, so) {} - -private: - SkAutoTDelete fStencilAndCoverTextContext; - - friend class GrDrawingManager; // for ctor - - typedef GrDrawContext INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/GrPathRenderingRenderTargetContext.cpp b/gfx/skia/skia/src/gpu/GrPathRenderingRenderTargetContext.cpp new file mode 100644 index 000000000000..90966a8e84f2 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrPathRenderingRenderTargetContext.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrPathRenderingRenderTargetContext.h" + +#include "GrDrawingManager.h" + +#include "text/GrStencilAndCoverTextContext.h" + +#define ASSERT_SINGLE_OWNER \ + SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());) +#define RETURN_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return; } + +void GrPathRenderingRenderTargetContext::drawText(const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, const char text[], + size_t byteLength, SkScalar x, SkScalar y, + const SkIRect& clipBounds) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrPathRenderingRenderTargetContext::drawText"); + + if (!fStencilAndCoverTextContext) { + GrAtlasTextContext* fallbackContext = this->drawingManager()->getAtlasTextContext(); + fStencilAndCoverTextContext.reset(GrStencilAndCoverTextContext::Create(fallbackContext)); + } + + fStencilAndCoverTextContext->drawText(this->drawingManager()->getContext(), this, clip, skPaint, + viewMatrix, this->surfaceProps(), text, byteLength, x, y, + clipBounds); +} + +void GrPathRenderingRenderTargetContext::drawPosText(const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, const char text[], + size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset, + const SkIRect& clipBounds) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), + "GrPathRenderingRenderTargetContext::drawPosText"); + + if (!fStencilAndCoverTextContext) { + GrAtlasTextContext* fallbackContext = this->drawingManager()->getAtlasTextContext(); + fStencilAndCoverTextContext.reset(GrStencilAndCoverTextContext::Create(fallbackContext)); + } + + fStencilAndCoverTextContext->drawPosText( + this->drawingManager()->getContext(), this, clip, skPaint, viewMatrix, + this->surfaceProps(), text, byteLength, pos, scalarsPerPosition, offset, clipBounds); +} + +void GrPathRenderingRenderTargetContext::drawTextBlob(const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, + const SkTextBlob* blob, + SkScalar x, SkScalar y, + SkDrawFilter* filter, + const SkIRect& clipBounds) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), + "GrPathRenderingRenderTargetContext::drawTextBlob"); + + if (!fStencilAndCoverTextContext) { + GrAtlasTextContext* fallbackContext = this->drawingManager()->getAtlasTextContext(); + fStencilAndCoverTextContext.reset(GrStencilAndCoverTextContext::Create(fallbackContext)); + } + + fStencilAndCoverTextContext->drawTextBlob(this->drawingManager()->getContext(), this, clip, + skPaint, viewMatrix, this->surfaceProps(), blob, x, + y, filter, clipBounds); +} diff --git a/gfx/skia/skia/src/gpu/GrPathRenderingRenderTargetContext.h b/gfx/skia/skia/src/gpu/GrPathRenderingRenderTargetContext.h new file mode 100644 index 000000000000..420bbe83b3aa --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrPathRenderingRenderTargetContext.h @@ -0,0 +1,40 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrPathRenderingRenderTargetContext_DEFINED +#define GrPathRenderingRenderTargetContext_DEFINED + +#include "text/GrStencilAndCoverTextContext.h" + +class GrPathRenderingRenderTargetContext : public GrRenderTargetContext { +public: + void drawText(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], + size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds) override; + void drawPosText(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], + size_t byteLength, const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset, const SkIRect& clipBounds) override; + void drawTextBlob(const GrClip&, const SkPaint&, + const SkMatrix& viewMatrix, const SkTextBlob*, + SkScalar x, SkScalar y, + SkDrawFilter*, const SkIRect& clipBounds) override; +protected: + GrPathRenderingRenderTargetContext(GrContext* ctx, GrDrawingManager* mgr, + sk_sp rtp, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps, GrAuditTrail* at, + GrSingleOwner* so) + : INHERITED(ctx, mgr, std::move(rtp), std::move(colorSpace), surfaceProps, at, so) {} + +private: + std::unique_ptr fStencilAndCoverTextContext; + + friend class GrDrawingManager; // for ctor + + typedef GrRenderTargetContext INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrPathUtils.cpp b/gfx/skia/skia/src/gpu/GrPathUtils.cpp index bff9490113a7..5ee434aa92a3 100644 --- a/gfx/skia/skia/src/gpu/GrPathUtils.cpp +++ b/gfx/skia/skia/src/gpu/GrPathUtils.cpp @@ -36,8 +36,7 @@ SkScalar GrPathUtils::scaleToleranceToSrc(SkScalar devTol, static const int MAX_POINTS_PER_CURVE = 1 << 10; static const SkScalar gMinCurveTol = 0.0001f; -uint32_t GrPathUtils::quadraticPointCount(const SkPoint points[], - SkScalar tol) { +uint32_t GrPathUtils::quadraticPointCount(const SkPoint points[], SkScalar tol) { if (tol < gMinCurveTol) { tol = gMinCurveTol; } @@ -158,8 +157,7 @@ uint32_t GrPathUtils::generateCubicPoints(const SkPoint& p0, return a + b; } -int GrPathUtils::worstCasePointCount(const SkPath& path, int* subpaths, - SkScalar tol) { +int GrPathUtils::worstCasePointCount(const SkPath& path, int* subpaths, SkScalar tol) { if (tol < gMinCurveTol) { tol = gMinCurveTol; } @@ -183,7 +181,7 @@ int GrPathUtils::worstCasePointCount(const SkPath& path, int* subpaths, case SkPath::kConic_Verb: { SkScalar weight = iter.conicWeight(); SkAutoConicToQuads converter; - const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f); + const SkPoint* quadPts = converter.computeQuads(pts, weight, tol); for (int i = 0; i < converter.countQuads(); ++i) { pointCount += quadraticPointCount(quadPts + 2*i, tol); } @@ -320,14 +318,15 @@ void GrPathUtils::QuadUVMatrix::set(const SkPoint qPts[3]) { //////////////////////////////////////////////////////////////////////////////// -// k = (y2 - y0, x0 - x2, (x2 - x0)*y0 - (y2 - y0)*x0 ) -// l = (2*w * (y1 - y0), 2*w * (x0 - x1), 2*w * (x1*y0 - x0*y1)) -// m = (2*w * (y2 - y1), 2*w * (x1 - x2), 2*w * (x2*y1 - x1*y2)) -void GrPathUtils::getConicKLM(const SkPoint p[3], const SkScalar weight, SkScalar klm[9]) { +// k = (y2 - y0, x0 - x2, x2*y0 - x0*y2) +// l = (y1 - y0, x0 - x1, x1*y0 - x0*y1) * 2*w +// m = (y2 - y1, x1 - x2, x2*y1 - x1*y2) * 2*w +void GrPathUtils::getConicKLM(const SkPoint p[3], const SkScalar weight, SkMatrix* out) { + SkMatrix& klm = *out; const SkScalar w2 = 2.f * weight; klm[0] = p[2].fY - p[0].fY; klm[1] = p[0].fX - p[2].fX; - klm[2] = (p[2].fX - p[0].fX) * p[0].fY - (p[2].fY - p[0].fY) * p[0].fX; + klm[2] = p[2].fX * p[0].fY - p[0].fX * p[2].fY; klm[3] = w2 * (p[1].fY - p[0].fY); klm[4] = w2 * (p[0].fX - p[1].fX); @@ -441,8 +440,9 @@ void convert_noninflect_cubic_to_quads(const SkPoint p[4], detABSqd = SkScalarSquare(detABSqd); SkScalar detDCSqd = dc.cross(da); detDCSqd = SkScalarSquare(detDCSqd); - if (SkScalarMul(detABSqd, invDALengthSqd) < toleranceSqd && - SkScalarMul(detDCSqd, invDALengthSqd) < toleranceSqd) { + if (detABSqd * invDALengthSqd < toleranceSqd && + detDCSqd * invDALengthSqd < toleranceSqd) + { doQuads = true; } } @@ -499,9 +499,9 @@ void convert_noninflect_cubic_to_quads(const SkPoint p[4], SkScalar z0 = -ab.dot(p[0]); dc.setOrthog(dc); SkScalar z1 = -dc.dot(p[3]); - cAvg.fX = SkScalarMul(ab.fY, z1) - SkScalarMul(z0, dc.fY); - cAvg.fY = SkScalarMul(z0, dc.fX) - SkScalarMul(ab.fX, z1); - SkScalar z = SkScalarMul(ab.fX, dc.fY) - SkScalarMul(ab.fY, dc.fX); + cAvg.fX = ab.fY * z1 - z0 * dc.fY; + cAvg.fY = z0 * dc.fX - ab.fX * z1; + SkScalar z = ab.fX * dc.fY - ab.fY * dc.fX; z = SkScalarInvert(z); cAvg.fX *= z; cAvg.fY *= z; @@ -512,7 +512,7 @@ void convert_noninflect_cubic_to_quads(const SkPoint p[4], // the distances and tolerance can't be negative. // (d0 + d1)^2 > toleranceSqd // d0Sqd + 2*d0*d1 + d1Sqd > toleranceSqd - SkScalar d0d1 = SkScalarSqrt(SkScalarMul(d0Sqd, d1Sqd)); + SkScalar d0d1 = SkScalarSqrt(d0Sqd * d1Sqd); subdivide = 2 * d0d1 + d0Sqd + d1Sqd > toleranceSqd; } } @@ -574,155 +574,273 @@ void GrPathUtils::convertCubicToQuadsConstrainToTangents(const SkPoint p[4], //////////////////////////////////////////////////////////////////////////////// -// Solves linear system to extract klm -// P.K = k (similarly for l, m) -// Where P is matrix of control points -// K is coefficients for the line K -// k is vector of values of K evaluated at the control points -// Solving for K, thus K = P^(-1) . k -static void calc_cubic_klm(const SkPoint p[4], const SkScalar controlK[4], - const SkScalar controlL[4], const SkScalar controlM[4], - SkScalar k[3], SkScalar l[3], SkScalar m[3]) { - SkMatrix matrix; - matrix.setAll(p[0].fX, p[0].fY, 1.f, - p[1].fX, p[1].fY, 1.f, - p[2].fX, p[2].fY, 1.f); - SkMatrix inverse; - if (matrix.invert(&inverse)) { - inverse.mapHomogeneousPoints(k, controlK, 1); - inverse.mapHomogeneousPoints(l, controlL, 1); - inverse.mapHomogeneousPoints(m, controlM, 1); +/** + * Computes an SkMatrix that can find the cubic KLM functionals as follows: + * + * | ..K.. | | ..kcoeffs.. | + * | ..L.. | = | ..lcoeffs.. | * inverse_transpose_power_basis_matrix + * | ..M.. | | ..mcoeffs.. | + * + * 'kcoeffs' are the power basis coefficients to a scalar valued cubic function that returns the + * signed distance to line K from a given point on the curve: + * + * k(t,s) = C(t,s) * K [C(t,s) is defined in the following comment] + * + * The same applies for lcoeffs and mcoeffs. These are found separately, depending on the type of + * curve. There are 4 coefficients but 3 rows in the matrix, so in order to do this calculation the + * caller must first remove a specific column of coefficients. + * + * @return which column of klm coefficients to exclude from the calculation. + */ +static int calc_inverse_transpose_power_basis_matrix(const SkPoint pts[4], SkMatrix* out) { + using SkScalar4 = SkNx<4, SkScalar>; + + // First we convert the bezier coordinates 'pts' to power basis coefficients X,Y,W=[0 0 0 1]. + // M3 is the matrix that does this conversion. The homogeneous equation for the cubic becomes: + // + // | X Y 0 | + // C(t,s) = [t^3 t^2*s t*s^2 s^3] * | . . 0 | + // | . . 0 | + // | . . 1 | + // + const SkScalar4 M3[3] = {SkScalar4(-1, 3, -3, 1), + SkScalar4(3, -6, 3, 0), + SkScalar4(-3, 3, 0, 0)}; + // 4th column of M3 = SkScalar4(1, 0, 0, 0)}; + SkScalar4 X(pts[3].x(), 0, 0, 0); + SkScalar4 Y(pts[3].y(), 0, 0, 0); + for (int i = 2; i >= 0; --i) { + X += M3[i] * pts[i].x(); + Y += M3[i] * pts[i].y(); } + // The matrix is 3x4. In order to invert it, we first need to make it square by throwing out one + // of the top three rows. We toss the row that leaves us with the largest absolute determinant. + // Since the right column will be [0 0 1], the determinant reduces to x0*y1 - y0*x1. + SkScalar absDet[4]; + const SkScalar4 DETX1 = SkNx_shuffle<1,0,0,3>(X), DETY1 = SkNx_shuffle<1,0,0,3>(Y); + const SkScalar4 DETX2 = SkNx_shuffle<2,2,1,3>(X), DETY2 = SkNx_shuffle<2,2,1,3>(Y); + const SkScalar4 DET = DETX1 * DETY2 - DETY1 * DETX2; + DET.abs().store(absDet); + const int skipRow = absDet[0] > absDet[2] ? (absDet[0] > absDet[1] ? 0 : 1) + : (absDet[1] > absDet[2] ? 1 : 2); + const SkScalar rdet = 1 / DET[skipRow]; + const int row0 = (0 != skipRow) ? 0 : 1; + const int row1 = (2 == skipRow) ? 1 : 2; + + // Compute the inverse-transpose of the power basis matrix with the 'skipRow'th row removed. + // Since W=[0 0 0 1], it follows that our corresponding solution will be equal to: + // + // | y1 -x1 x1*y2 - y1*x2 | + // 1/det * | -y0 x0 -x0*y2 + y0*x2 | + // | 0 0 det | + // + const SkScalar4 R(rdet, rdet, rdet, 1); + X *= R; + Y *= R; + + SkScalar x[4], y[4], z[4]; + X.store(x); + Y.store(y); + (X * SkNx_shuffle<3,3,3,3>(Y) - Y * SkNx_shuffle<3,3,3,3>(X)).store(z); + + out->setAll( y[row1], -x[row1], z[row1], + -y[row0], x[row0], -z[row0], + 0, 0, 1); + + return skipRow; } -static void set_serp_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) { - SkScalar tempSqrt = SkScalarSqrt(9.f * d[1] * d[1] - 12.f * d[0] * d[2]); - SkScalar ls = 3.f * d[1] - tempSqrt; - SkScalar lt = 6.f * d[0]; - SkScalar ms = 3.f * d[1] + tempSqrt; - SkScalar mt = 6.f * d[0]; +static void negate_kl(SkMatrix* klm) { + // We could use klm->postScale(-1, -1), but it ends up doing a full matrix multiply. + for (int i = 0; i < 6; ++i) { + (*klm)[i] = -(*klm)[i]; + } +} - k[0] = ls * ms; - k[1] = (3.f * ls * ms - ls * mt - lt * ms) / 3.f; - k[2] = (lt * (mt - 2.f * ms) + ls * (3.f * ms - 2.f * mt)) / 3.f; - k[3] = (lt - ls) * (mt - ms); +static void calc_serp_klm(const SkPoint pts[4], const SkScalar d[3], SkMatrix* klm) { + SkMatrix CIT; + int skipCol = calc_inverse_transpose_power_basis_matrix(pts, &CIT); - l[0] = ls * ls * ls; - const SkScalar lt_ls = lt - ls; - l[1] = ls * ls * lt_ls * -1.f; - l[2] = lt_ls * lt_ls * ls; - l[3] = -1.f * lt_ls * lt_ls * lt_ls; + const SkScalar root = SkScalarSqrt(9 * d[1] * d[1] - 12 * d[0] * d[2]); - m[0] = ms * ms * ms; - const SkScalar mt_ms = mt - ms; - m[1] = ms * ms * mt_ms * -1.f; - m[2] = mt_ms * mt_ms * ms; - m[3] = -1.f * mt_ms * mt_ms * mt_ms; + const SkScalar tl = 3 * d[1] + root; + const SkScalar sl = 6 * d[0]; + const SkScalar tm = 3 * d[1] - root; + const SkScalar sm = 6 * d[0]; - // If d0 < 0 we need to flip the orientation of our curve + SkMatrix klmCoeffs; + int col = 0; + if (0 != skipCol) { + klmCoeffs[0] = 0; + klmCoeffs[3] = -sl * sl * sl; + klmCoeffs[6] = -sm * sm * sm; + ++col; + } + if (1 != skipCol) { + klmCoeffs[col + 0] = sl * sm; + klmCoeffs[col + 3] = 3 * sl * sl * tl; + klmCoeffs[col + 6] = 3 * sm * sm * tm; + ++col; + } + if (2 != skipCol) { + klmCoeffs[col + 0] = -tl * sm - tm * sl; + klmCoeffs[col + 3] = -3 * sl * tl * tl; + klmCoeffs[col + 6] = -3 * sm * tm * tm; + ++col; + } + + SkASSERT(2 == col); + klmCoeffs[2] = tl * tm; + klmCoeffs[5] = tl * tl * tl; + klmCoeffs[8] = tm * tm * tm; + + klm->setConcat(klmCoeffs, CIT); + + // If d0 > 0 we need to flip the orientation of our curve // This is done by negating the k and l values // We want negative distance values to be on the inside - if ( d[0] > 0) { - for (int i = 0; i < 4; ++i) { - k[i] = -k[i]; - l[i] = -l[i]; - } + if (d[0] > 0) { + negate_kl(klm); } } -static void set_loop_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) { - SkScalar tempSqrt = SkScalarSqrt(4.f * d[0] * d[2] - 3.f * d[1] * d[1]); - SkScalar ls = d[1] - tempSqrt; - SkScalar lt = 2.f * d[0]; - SkScalar ms = d[1] + tempSqrt; - SkScalar mt = 2.f * d[0]; +static void calc_loop_klm(const SkPoint pts[4], SkScalar d1, SkScalar td, SkScalar sd, + SkScalar te, SkScalar se, SkMatrix* klm) { + SkMatrix CIT; + int skipCol = calc_inverse_transpose_power_basis_matrix(pts, &CIT); - k[0] = ls * ms; - k[1] = (3.f * ls*ms - ls * mt - lt * ms) / 3.f; - k[2] = (lt * (mt - 2.f * ms) + ls * (3.f * ms - 2.f * mt)) / 3.f; - k[3] = (lt - ls) * (mt - ms); + const SkScalar tesd = te * sd; + const SkScalar tdse = td * se; - l[0] = ls * ls * ms; - l[1] = (ls * (ls * (mt - 3.f * ms) + 2.f * lt * ms))/-3.f; - l[2] = ((lt - ls) * (ls * (2.f * mt - 3.f * ms) + lt * ms))/3.f; - l[3] = -1.f * (lt - ls) * (lt - ls) * (mt - ms); + SkMatrix klmCoeffs; + int col = 0; + if (0 != skipCol) { + klmCoeffs[0] = 0; + klmCoeffs[3] = -sd * sd * se; + klmCoeffs[6] = -se * se * sd; + ++col; + } + if (1 != skipCol) { + klmCoeffs[col + 0] = sd * se; + klmCoeffs[col + 3] = sd * (2 * tdse + tesd); + klmCoeffs[col + 6] = se * (2 * tesd + tdse); + ++col; + } + if (2 != skipCol) { + klmCoeffs[col + 0] = -tdse - tesd; + klmCoeffs[col + 3] = -td * (tdse + 2 * tesd); + klmCoeffs[col + 6] = -te * (tesd + 2 * tdse); + ++col; + } - m[0] = ls * ms * ms; - m[1] = (ms * (ls * (2.f * mt - 3.f * ms) + lt * ms))/-3.f; - m[2] = ((mt - ms) * (ls * (mt - 3.f * ms) + 2.f * lt * ms))/3.f; - m[3] = -1.f * (lt - ls) * (mt - ms) * (mt - ms); + SkASSERT(2 == col); + klmCoeffs[2] = td * te; + klmCoeffs[5] = td * td * te; + klmCoeffs[8] = te * te * td; + klm->setConcat(klmCoeffs, CIT); - // If (d0 < 0 && sign(k1) > 0) || (d0 > 0 && sign(k1) < 0), - // we need to flip the orientation of our curve. + // For the general loop curve, we flip the orientation in the same pattern as the serp case + // above. Thus we only check d1. Technically we should check the value of the hessian as well + // cause we care about the sign of d1*Hessian. However, the Hessian is always negative outside + // the loop section and positive inside. We take care of the flipping for the loop sections + // later on. + if (d1 > 0) { + negate_kl(klm); + } +} + +// For the case when we have a cusp at a parameter value of infinity (discr == 0, d1 == 0). +static void calc_inf_cusp_klm(const SkPoint pts[4], SkScalar d2, SkScalar d3, SkMatrix* klm) { + SkMatrix CIT; + int skipCol = calc_inverse_transpose_power_basis_matrix(pts, &CIT); + + const SkScalar tn = d3; + const SkScalar sn = 3 * d2; + + SkMatrix klmCoeffs; + int col = 0; + if (0 != skipCol) { + klmCoeffs[0] = 0; + klmCoeffs[3] = -sn * sn * sn; + ++col; + } + if (1 != skipCol) { + klmCoeffs[col + 0] = 0; + klmCoeffs[col + 3] = 3 * sn * sn * tn; + ++col; + } + if (2 != skipCol) { + klmCoeffs[col + 0] = -sn; + klmCoeffs[col + 3] = -3 * sn * tn * tn; + ++col; + } + + SkASSERT(2 == col); + klmCoeffs[2] = tn; + klmCoeffs[5] = tn * tn * tn; + + klmCoeffs[6] = 0; + klmCoeffs[7] = 0; + klmCoeffs[8] = 1; + + klm->setConcat(klmCoeffs, CIT); +} + +// For the case when a cubic bezier is actually a quadratic. We duplicate k in l so that the +// implicit becomes: +// +// k^3 - l*m == k^3 - l*k == k * (k^2 - l) +// +// In the quadratic case we can simply assign fixed values at each control point: +// +// | ..K.. | | pts[0] pts[1] pts[2] pts[3] | | 0 1/3 2/3 1 | +// | ..L.. | * | . . . . | == | 0 0 1/3 1 | +// | ..K.. | | 1 1 1 1 | | 0 1/3 2/3 1 | +// +static void calc_quadratic_klm(const SkPoint pts[4], SkScalar d3, SkMatrix* klm) { + SkMatrix klmAtPts; + klmAtPts.setAll(0, 1.f/3, 1, + 0, 0, 1, + 0, 1.f/3, 1); + + SkMatrix inversePts; + inversePts.setAll(pts[0].x(), pts[1].x(), pts[3].x(), + pts[0].y(), pts[1].y(), pts[3].y(), + 1, 1, 1); + SkAssertResult(inversePts.invert(&inversePts)); + + klm->setConcat(klmAtPts, inversePts); + + // If d3 > 0 we need to flip the orientation of our curve // This is done by negating the k and l values - if ( (d[0] < 0 && k[1] > 0) || (d[0] > 0 && k[1] < 0)) { - for (int i = 0; i < 4; ++i) { - k[i] = -k[i]; - l[i] = -l[i]; - } + if (d3 > 0) { + negate_kl(klm); } } -static void set_cusp_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) { - const SkScalar ls = d[2]; - const SkScalar lt = 3.f * d[1]; - - k[0] = ls; - k[1] = ls - lt / 3.f; - k[2] = ls - 2.f * lt / 3.f; - k[3] = ls - lt; - - l[0] = ls * ls * ls; - const SkScalar ls_lt = ls - lt; - l[1] = ls * ls * ls_lt; - l[2] = ls_lt * ls_lt * ls; - l[3] = ls_lt * ls_lt * ls_lt; - - m[0] = 1.f; - m[1] = 1.f; - m[2] = 1.f; - m[3] = 1.f; +// For the case when a cubic bezier is actually a line. We set K=0, L=1, M=-line, which results in +// the following implicit: +// +// k^3 - l*m == 0^3 - 1*(-line) == -(-line) == line +// +static void calc_line_klm(const SkPoint pts[4], SkMatrix* klm) { + SkScalar ny = pts[0].x() - pts[3].x(); + SkScalar nx = pts[3].y() - pts[0].y(); + SkScalar k = nx * pts[0].x() + ny * pts[0].y(); + klm->setAll( 0, 0, 0, + 0, 0, 1, + -nx, -ny, k); } -// For the case when a cubic is actually a quadratic -// M = -// 0 0 0 -// 1/3 0 1/3 -// 2/3 1/3 2/3 -// 1 1 1 -static void set_quadratic_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) { - k[0] = 0.f; - k[1] = 1.f/3.f; - k[2] = 2.f/3.f; - k[3] = 1.f; +int GrPathUtils::chopCubicAtLoopIntersection(const SkPoint src[4], SkPoint dst[10], SkMatrix* klm, + int* loopIndex) { + // Variables to store the two parametric values at the loop double point. + SkScalar t1 = 0, t2 = 0; - l[0] = 0.f; - l[1] = 0.f; - l[2] = 1.f/3.f; - l[3] = 1.f; - - m[0] = 0.f; - m[1] = 1.f/3.f; - m[2] = 2.f/3.f; - m[3] = 1.f; - - // If d2 < 0 we need to flip the orientation of our curve - // This is done by negating the k and l values - if ( d[2] > 0) { - for (int i = 0; i < 4; ++i) { - k[i] = -k[i]; - l[i] = -l[i]; - } - } -} - -int GrPathUtils::chopCubicAtLoopIntersection(const SkPoint src[4], SkPoint dst[10], SkScalar klm[9], - SkScalar klm_rev[3]) { - // Variable to store the two parametric values at the loop double point - SkScalar smallS = 0.f; - SkScalar largeS = 0.f; + // Homogeneous parametric values at the loop double point. + SkScalar td, sd, te, se; SkScalar d[3]; SkCubicType cType = SkClassifyCubic(src, d); @@ -730,27 +848,24 @@ int GrPathUtils::chopCubicAtLoopIntersection(const SkPoint src[4], SkPoint dst[1 int chop_count = 0; if (kLoop_SkCubicType == cType) { SkScalar tempSqrt = SkScalarSqrt(4.f * d[0] * d[2] - 3.f * d[1] * d[1]); - SkScalar ls = d[1] - tempSqrt; - SkScalar lt = 2.f * d[0]; - SkScalar ms = d[1] + tempSqrt; - SkScalar mt = 2.f * d[0]; - ls = ls / lt; - ms = ms / mt; + td = d[1] + tempSqrt; + sd = 2.f * d[0]; + te = d[1] - tempSqrt; + se = 2.f * d[0]; + + t1 = td / sd; + t2 = te / se; // need to have t values sorted since this is what is expected by SkChopCubicAt - if (ls <= ms) { - smallS = ls; - largeS = ms; - } else { - smallS = ms; - largeS = ls; + if (t1 > t2) { + SkTSwap(t1, t2); } SkScalar chop_ts[2]; - if (smallS > 0.f && smallS < 1.f) { - chop_ts[chop_count++] = smallS; + if (t1 > 0.f && t1 < 1.f) { + chop_ts[chop_count++] = t1; } - if (largeS > 0.f && largeS < 1.f) { - chop_ts[chop_count++] = largeS; + if (t2 > 0.f && t2 < 1.f) { + chop_ts[chop_count++] = t2; } if(dst) { SkChopCubicAt(src, dst, chop_ts, chop_count); @@ -761,66 +876,49 @@ int GrPathUtils::chopCubicAtLoopIntersection(const SkPoint src[4], SkPoint dst[1 } } - if (klm && klm_rev) { - // Set klm_rev to to match the sub_section of cubic that needs to have its orientation - // flipped. This will always be the section that is the "loop" + if (loopIndex) { if (2 == chop_count) { - klm_rev[0] = 1.f; - klm_rev[1] = -1.f; - klm_rev[2] = 1.f; + *loopIndex = 1; } else if (1 == chop_count) { - if (smallS < 0.f) { - klm_rev[0] = -1.f; - klm_rev[1] = 1.f; + if (t1 < 0.f) { + *loopIndex = 0; } else { - klm_rev[0] = 1.f; - klm_rev[1] = -1.f; + *loopIndex = 1; } } else { - if (smallS < 0.f && largeS > 1.f) { - klm_rev[0] = -1.f; + if (t1 < 0.f && t2 > 1.f) { + *loopIndex = 0; } else { - klm_rev[0] = 1.f; + *loopIndex = -1; } } - SkScalar controlK[4]; - SkScalar controlL[4]; - SkScalar controlM[4]; + } - if (kSerpentine_SkCubicType == cType || (kCusp_SkCubicType == cType && 0.f != d[0])) { - set_serp_klm(d, controlK, controlL, controlM); - } else if (kLoop_SkCubicType == cType) { - set_loop_klm(d, controlK, controlL, controlM); - } else if (kCusp_SkCubicType == cType) { - SkASSERT(0.f == d[0]); - set_cusp_klm(d, controlK, controlL, controlM); - } else if (kQuadratic_SkCubicType == cType) { - set_quadratic_klm(d, controlK, controlL, controlM); - } - - calc_cubic_klm(src, controlK, controlL, controlM, klm, &klm[3], &klm[6]); + if (klm) { + switch (cType) { + case kSerpentine_SkCubicType: + calc_serp_klm(src, d, klm); + break; + case kLoop_SkCubicType: + calc_loop_klm(src, d[0], td, sd, te, se, klm); + break; + case kCusp_SkCubicType: + if (0 != d[0]) { + // FIXME: SkClassifyCubic has a tolerance, but we need an exact classification + // here to be sure we won't get a negative in the square root. + calc_serp_klm(src, d, klm); + } else { + calc_inf_cusp_klm(src, d[1], d[2], klm); + } + break; + case kQuadratic_SkCubicType: + calc_quadratic_klm(src, d[2], klm); + break; + case kLine_SkCubicType: + case kPoint_SkCubicType: + calc_line_klm(src, klm); + break; + }; } return chop_count + 1; } - -void GrPathUtils::getCubicKLM(const SkPoint p[4], SkScalar klm[9]) { - SkScalar d[3]; - SkCubicType cType = SkClassifyCubic(p, d); - - SkScalar controlK[4]; - SkScalar controlL[4]; - SkScalar controlM[4]; - - if (kSerpentine_SkCubicType == cType || (kCusp_SkCubicType == cType && 0.f != d[0])) { - set_serp_klm(d, controlK, controlL, controlM); - } else if (kLoop_SkCubicType == cType) { - set_loop_klm(d, controlK, controlL, controlM); - } else if (kCusp_SkCubicType == cType) { - SkASSERT(0.f == d[0]); - set_cusp_klm(d, controlK, controlL, controlM); - } else if (kQuadratic_SkCubicType == cType) { - set_quadratic_klm(d, controlK, controlL, controlM); - } - - calc_cubic_klm(p, controlK, controlL, controlM, klm, &klm[3], &klm[6]); -} diff --git a/gfx/skia/skia/src/gpu/GrPathUtils.h b/gfx/skia/skia/src/gpu/GrPathUtils.h index fcc32c89c4d1..7dea3a1353d1 100644 --- a/gfx/skia/skia/src/gpu/GrPathUtils.h +++ b/gfx/skia/skia/src/gpu/GrPathUtils.h @@ -98,13 +98,15 @@ namespace GrPathUtils { // Input is 3 control points and a weight for a bezier conic. Calculates the // three linear functionals (K,L,M) that represent the implicit equation of the - // conic, K^2 - LM. + // conic, k^2 - lm. // - // Output: - // K = (klm[0], klm[1], klm[2]) - // L = (klm[3], klm[4], klm[5]) - // M = (klm[6], klm[7], klm[8]) - void getConicKLM(const SkPoint p[3], const SkScalar weight, SkScalar klm[9]); + // Output: klm holds the linear functionals K,L,M as row vectors: + // + // | ..K.. | | x | | k | + // | ..L.. | * | y | == | l | + // | ..M.. | | 1 | | m | + // + void getConicKLM(const SkPoint p[3], const SkScalar weight, SkMatrix* klm); // Converts a cubic into a sequence of quads. If working in device space // use tolScale = 1, otherwise set based on stretchiness of the matrix. The @@ -127,48 +129,39 @@ namespace GrPathUtils { // Chops the cubic bezier passed in by src, at the double point (intersection point) // if the curve is a cubic loop. If it is a loop, there will be two parametric values for - // the double point: ls and ms. We chop the cubic at these values if they are between 0 and 1. + // the double point: t1 and t2. We chop the cubic at these values if they are between 0 and 1. // Return value: - // Value of 3: ls and ms are both between (0,1), and dst will contain the three cubics, + // Value of 3: t1 and t2 are both between (0,1), and dst will contain the three cubics, // dst[0..3], dst[3..6], and dst[6..9] if dst is not nullptr - // Value of 2: Only one of ls and ms are between (0,1), and dst will contain the two cubics, + // Value of 2: Only one of t1 and t2 are between (0,1), and dst will contain the two cubics, // dst[0..3] and dst[3..6] if dst is not nullptr - // Value of 1: Neither ls or ms are between (0,1), and dst will contain the one original cubic, + // Value of 1: Neither t1 nor t2 are between (0,1), and dst will contain the one original cubic, // dst[0..3] if dst is not nullptr // // Optional KLM Calculation: - // The function can also return the KLM linear functionals for the chopped cubic implicit form - // of K^3 - LM. - // It will calculate a single set of KLM values that can be shared by all sub cubics, except - // for the subsection that is "the loop" the K and L values need to be negated. - // Output: - // klm: Holds the values for the linear functionals as: - // K = (klm[0], klm[1], klm[2]) - // L = (klm[3], klm[4], klm[5]) - // M = (klm[6], klm[7], klm[8]) - // klm_rev: These values are flags for the corresponding sub cubic saying whether or not - // the K and L values need to be flipped. A value of -1.f means flip K and L and - // a value of 1.f means do nothing. - // *****DO NOT FLIP M, JUST K AND L***** + // The function can also return the KLM linear functionals for the cubic implicit form of + // k^3 - lm. This can be shared by all chopped cubics. // - // Notice that the klm lines are calculated in the same space as the input control points. + // Output: + // + // klm: Holds the linear functionals K,L,M as row vectors: + // + // | ..K.. | | x | | k | + // | ..L.. | * | y | == | l | + // | ..M.. | | 1 | | m | + // + // loopIndex: This value will tell the caller which of the chopped sections (if any) are the + // actual loop. A value of -1 means there is no loop section. The caller can then use + // this value to decide how/if they want to flip the orientation of this section. + // The flip should be done by negating the k and l values as follows: + // + // KLM.postScale(-1, -1) + // + // Notice that the KLM lines are calculated in the same space as the input control points. // If you transform the points the lines will also need to be transformed. This can be done // by mapping the lines with the inverse-transpose of the matrix used to map the points. int chopCubicAtLoopIntersection(const SkPoint src[4], SkPoint dst[10] = nullptr, - SkScalar klm[9] = nullptr, SkScalar klm_rev[3] = nullptr); - - // Input is p which holds the 4 control points of a non-rational cubic Bezier curve. - // Output is the coefficients of the three linear functionals K, L, & M which - // represent the implicit form of the cubic as f(x,y,w) = K^3 - LM. The w term - // will always be 1. The output is stored in the array klm, where the values are: - // K = (klm[0], klm[1], klm[2]) - // L = (klm[3], klm[4], klm[5]) - // M = (klm[6], klm[7], klm[8]) - // - // Notice that the klm lines are calculated in the same space as the input control points. - // If you transform the points the lines will also need to be transformed. This can be done - // by mapping the lines with the inverse-transpose of the matrix used to map the points. - void getCubicKLM(const SkPoint p[4], SkScalar klm[9]); + SkMatrix* klm = nullptr, int* loopIndex = nullptr); // When tessellating curved paths into linear segments, this defines the maximum distance // in screen space which a segment may deviate from the mathmatically correct value. diff --git a/gfx/skia/skia/src/gpu/GrPipeline.cpp b/gfx/skia/skia/src/gpu/GrPipeline.cpp index d9ebcf85f924..193c32020ff9 100644 --- a/gfx/skia/skia/src/gpu/GrPipeline.cpp +++ b/gfx/skia/skia/src/gpu/GrPipeline.cpp @@ -7,179 +7,87 @@ #include "GrPipeline.h" +#include "GrAppliedClip.h" #include "GrCaps.h" -#include "GrDrawContext.h" -#include "GrDrawTarget.h" #include "GrGpu.h" #include "GrPipelineBuilder.h" -#include "GrProcOptInfo.h" +#include "GrRenderTargetContext.h" +#include "GrRenderTargetOpList.h" #include "GrRenderTargetPriv.h" #include "GrXferProcessor.h" -#include "batches/GrBatch.h" +#include "ops/GrOp.h" -GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args, - GrXPOverridesForBatch* overrides) { - const GrPipelineBuilder& builder = *args.fPipelineBuilder; +void GrPipeline::init(const InitArgs& args) { + SkASSERT(args.fRenderTarget); + SkASSERT(args.fProcessors); + SkASSERT(args.fProcessors->isFinalized()); - GrPipeline* pipeline = new (memory) GrPipeline; - GrRenderTarget* rt = args.fDrawContext->accessRenderTarget(); - pipeline->fRenderTarget.reset(rt); - SkASSERT(pipeline->fRenderTarget); - pipeline->fScissorState = *args.fScissor; - pipeline->fWindowRectsState = *args.fWindowRectsState; - if (builder.hasUserStencilSettings() || args.fHasStencilClip) { - const GrRenderTargetPriv& rtPriv = rt->renderTargetPriv(); - pipeline->fStencilSettings.reset(*builder.getUserStencil(), args.fHasStencilClip, - rtPriv.numStencilBits()); - SkASSERT(!pipeline->fStencilSettings.usesWrapOp() || args.fCaps->stencilWrapOpsSupport()); - } - pipeline->fDrawFace = builder.getDrawFace(); + fRenderTarget.reset(args.fRenderTarget); - pipeline->fFlags = 0; - if (builder.isHWAntialias()) { - pipeline->fFlags |= kHWAA_Flag; - } - if (builder.snapVerticesToPixelCenters()) { - pipeline->fFlags |= kSnapVertices_Flag; - } - if (builder.getDisableOutputConversionToSRGB()) { - pipeline->fFlags |= kDisableOutputConversionToSRGB_Flag; - } - if (builder.getAllowSRGBInputs()) { - pipeline->fFlags |= kAllowSRGBInputs_Flag; - } - if (builder.getUsesDistanceVectorField()) { - pipeline->fFlags |= kUsesDistanceVectorField_Flag; - } - if (args.fHasStencilClip) { - pipeline->fFlags |= kHasStencilClip_Flag; - } - - // Create XferProcessor from DS's XPFactory - bool hasMixedSamples = args.fDrawContext->hasMixedSamples() && - (builder.isHWAntialias() || !pipeline->fStencilSettings.isDisabled()); - const GrXPFactory* xpFactory = builder.getXPFactory(); - SkAutoTUnref xferProcessor; - if (xpFactory) { - xferProcessor.reset(xpFactory->createXferProcessor(args.fOpts, - hasMixedSamples, - &args.fDstTexture, - *args.fCaps)); - if (!xferProcessor) { - pipeline->~GrPipeline(); - return nullptr; + fFlags = args.fFlags; + if (args.fAppliedClip) { + fScissorState = args.fAppliedClip->scissorState(); + if (args.fAppliedClip->hasStencilClip()) { + fFlags |= kHasStencilClip_Flag; } - } else { - // This may return nullptr in the common case of src-over implemented using hw blending. - xferProcessor.reset(GrPorterDuffXPFactory::CreateSrcOverXferProcessor( - *args.fCaps, - args.fOpts, - hasMixedSamples, - &args.fDstTexture)); + fWindowRectsState = args.fAppliedClip->windowRectsState(); } - GrColor overrideColor = GrColor_ILLEGAL; - if (args.fOpts.fColorPOI.firstEffectiveProcessorIndex() != 0) { - overrideColor = args.fOpts.fColorPOI.inputColorToFirstEffectiveProccesor(); + if (args.fProcessors->usesDistanceVectorField()) { + fFlags |= kUsesDistanceVectorField_Flag; + } + if (args.fProcessors->disableOutputConversionToSRGB()) { + fFlags |= kDisableOutputConversionToSRGB_Flag; + } + if (args.fProcessors->allowSRGBInputs()) { + fFlags |= kAllowSRGBInputs_Flag; + } + if (!args.fUserStencil->isDisabled(fFlags & kHasStencilClip_Flag)) { + fFlags |= kStencilEnabled_Flag; } - GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags; + fUserStencilSettings = args.fUserStencil; - const GrXferProcessor* xpForOpts = xferProcessor ? xferProcessor.get() : - &GrPorterDuffXPFactory::SimpleSrcOverXP(); - optFlags = xpForOpts->getOptimizations(args.fOpts, - pipeline->fStencilSettings.doesWrite(), - &overrideColor, - *args.fCaps); + fDrawFace = static_cast(args.fDrawFace); - // When path rendering the stencil settings are not always set on the GrPipelineBuilder - // so we must check the draw type. In cases where we will skip drawing we simply return a - // null GrPipeline. - if (GrXferProcessor::kSkipDraw_OptFlag & optFlags) { - pipeline->~GrPipeline(); - return nullptr; + fXferProcessor = args.fProcessors->refXferProcessor(); + + if (args.fDstTexture.texture()) { + fDstTexture.reset(args.fDstTexture.texture()); + fDstTextureOffset = args.fDstTexture.offset(); } - // No need to have an override color if it isn't even going to be used. - if (SkToBool(GrXferProcessor::kIgnoreColor_OptFlag & optFlags)) { - overrideColor = GrColor_ILLEGAL; + // Copy GrFragmentProcessors from GrPipelineBuilder to Pipeline, possibly removing some of the + // color fragment processors. + fNumColorProcessors = args.fProcessors->numColorFragmentProcessors(); + int numTotalProcessors = + fNumColorProcessors + args.fProcessors->numCoverageFragmentProcessors(); + if (args.fAppliedClip && args.fAppliedClip->clipCoverageFragmentProcessor()) { + ++numTotalProcessors; } - - pipeline->fXferProcessor.reset(xferProcessor); - - int firstColorProcessorIdx = args.fOpts.fColorPOI.firstEffectiveProcessorIndex(); - - // TODO: Once we can handle single or four channel input into coverage GrFragmentProcessors - // then we can use GrPipelineBuilder's coverageProcInfo (like color above) to set this initial - // information. - int firstCoverageProcessorIdx = 0; - - pipeline->adjustProgramFromOptimizations(builder, optFlags, args.fOpts.fColorPOI, - args.fOpts.fCoveragePOI, &firstColorProcessorIdx, - &firstCoverageProcessorIdx); - - bool usesLocalCoords = false; - - // Copy GrFragmentProcessors from GrPipelineBuilder to Pipeline - pipeline->fNumColorProcessors = builder.numColorFragmentProcessors() - firstColorProcessorIdx; - int numTotalProcessors = pipeline->fNumColorProcessors + - builder.numCoverageFragmentProcessors() - firstCoverageProcessorIdx; - pipeline->fFragmentProcessors.reset(numTotalProcessors); + fFragmentProcessors.reset(numTotalProcessors); int currFPIdx = 0; - for (int i = firstColorProcessorIdx; i < builder.numColorFragmentProcessors(); - ++i, ++currFPIdx) { - const GrFragmentProcessor* fp = builder.getColorFragmentProcessor(i); - pipeline->fFragmentProcessors[currFPIdx].reset(fp); - usesLocalCoords = usesLocalCoords || fp->usesLocalCoords(); + for (int i = 0; i < args.fProcessors->numColorFragmentProcessors(); ++i, ++currFPIdx) { + const GrFragmentProcessor* fp = args.fProcessors->colorFragmentProcessor(i); + fFragmentProcessors[currFPIdx].reset(fp); } - for (int i = firstCoverageProcessorIdx; i < builder.numCoverageFragmentProcessors(); - ++i, ++currFPIdx) { - const GrFragmentProcessor* fp = builder.getCoverageFragmentProcessor(i); - pipeline->fFragmentProcessors[currFPIdx].reset(fp); - usesLocalCoords = usesLocalCoords || fp->usesLocalCoords(); + for (int i = 0; i < args.fProcessors->numCoverageFragmentProcessors(); ++i, ++currFPIdx) { + const GrFragmentProcessor* fp = args.fProcessors->coverageFragmentProcessor(i); + fFragmentProcessors[currFPIdx].reset(fp); } - - // Setup info we need to pass to GrPrimitiveProcessors that are used with this GrPipeline. - overrides->fFlags = 0; - if (!SkToBool(optFlags & GrXferProcessor::kIgnoreColor_OptFlag)) { - overrides->fFlags |= GrXPOverridesForBatch::kReadsColor_Flag; + if (args.fAppliedClip) { + if (const GrFragmentProcessor* fp = args.fAppliedClip->clipCoverageFragmentProcessor()) { + fFragmentProcessors[currFPIdx].reset(fp); + } } - if (GrColor_ILLEGAL != overrideColor) { - overrides->fFlags |= GrXPOverridesForBatch::kUseOverrideColor_Flag; - overrides->fOverrideColor = overrideColor; - } - if (!SkToBool(optFlags & GrXferProcessor::kIgnoreCoverage_OptFlag)) { - overrides->fFlags |= GrXPOverridesForBatch::kReadsCoverage_Flag; - } - if (usesLocalCoords) { - overrides->fFlags |= GrXPOverridesForBatch::kReadsLocalCoords_Flag; - } - if (SkToBool(optFlags & GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag)) { - overrides->fFlags |= GrXPOverridesForBatch::kCanTweakAlphaForCoverage_Flag; - } - - GrXPFactory::InvariantBlendedColor blendedColor; - if (xpFactory) { - xpFactory->getInvariantBlendedColor(args.fOpts.fColorPOI, &blendedColor); - } else { - GrPorterDuffXPFactory::SrcOverInvariantBlendedColor(args.fOpts.fColorPOI.color(), - args.fOpts.fColorPOI.validFlags(), - args.fOpts.fColorPOI.isOpaque(), - &blendedColor); - } - if (blendedColor.fWillBlendWithDst) { - overrides->fFlags |= GrXPOverridesForBatch::kWillColorBlendWithDst_Flag; - } - - return pipeline; } static void add_dependencies_for_processor(const GrFragmentProcessor* proc, GrRenderTarget* rt) { GrFragmentProcessor::TextureAccessIter iter(proc); - while (const GrTextureAccess* access = iter.next()) { - SkASSERT(rt->getLastDrawTarget()); - rt->getLastDrawTarget()->addDependency(access->getTexture()); + while (const GrResourceIOProcessor::TextureSampler* sampler = iter.next()) { + SkASSERT(rt->getLastOpList()); + rt->getLastOpList()->addDependency(sampler->texture()); } } @@ -188,32 +96,22 @@ void GrPipeline::addDependenciesTo(GrRenderTarget* rt) const { add_dependencies_for_processor(fFragmentProcessors[i].get(), rt); } - const GrXferProcessor& xfer = this->getXferProcessor(); - - for (int i = 0; i < xfer.numTextures(); ++i) { - GrTexture* texture = xfer.textureAccess(i).getTexture(); - SkASSERT(rt->getLastDrawTarget()); - rt->getLastDrawTarget()->addDependency(texture); + if (fDstTexture) { + SkASSERT(rt->getLastOpList()); + rt->getLastOpList()->addDependency(fDstTexture.get()); } } -void GrPipeline::adjustProgramFromOptimizations(const GrPipelineBuilder& pipelineBuilder, - GrXferProcessor::OptFlags flags, - const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - int* firstColorProcessorIdx, - int* firstCoverageProcessorIdx) { - fIgnoresCoverage = SkToBool(flags & GrXferProcessor::kIgnoreCoverage_OptFlag); - - if ((flags & GrXferProcessor::kIgnoreColor_OptFlag) || - (flags & GrXferProcessor::kOverrideColor_OptFlag)) { - *firstColorProcessorIdx = pipelineBuilder.numColorFragmentProcessors(); - } - - if (flags & GrXferProcessor::kIgnoreCoverage_OptFlag) { - *firstCoverageProcessorIdx = pipelineBuilder.numCoverageFragmentProcessors(); - } -} +GrPipeline::GrPipeline(GrRenderTarget* rt, SkBlendMode blendmode) + : fRenderTarget(rt) + , fScissorState() + , fWindowRectsState() + , fUserStencilSettings(&GrUserStencilSettings::kUnused) + , fDrawFace(static_cast(GrDrawFace::kBoth)) + , fFlags() + , fXferProcessor(GrPorterDuffXPFactory::MakeNoCoverageXP(blendmode)) + , fFragmentProcessors() + , fNumColorProcessors(0) {} //////////////////////////////////////////////////////////////////////////////// @@ -224,11 +122,10 @@ bool GrPipeline::AreEqual(const GrPipeline& a, const GrPipeline& b) { a.fFragmentProcessors.count() != b.fFragmentProcessors.count() || a.fNumColorProcessors != b.fNumColorProcessors || a.fScissorState != b.fScissorState || - !a.fWindowRectsState.cheapEqualTo(b.fWindowRectsState) || + a.fWindowRectsState != b.fWindowRectsState || a.fFlags != b.fFlags || - a.fStencilSettings != b.fStencilSettings || - a.fDrawFace != b.fDrawFace || - a.fIgnoresCoverage != b.fIgnoresCoverage) { + a.fUserStencilSettings != b.fUserStencilSettings || + a.fDrawFace != b.fDrawFace) { return false; } diff --git a/gfx/skia/skia/src/gpu/GrPipeline.h b/gfx/skia/skia/src/gpu/GrPipeline.h index 6366e8050f86..b08b4baa1f5f 100644 --- a/gfx/skia/skia/src/gpu/GrPipeline.h +++ b/gfx/skia/skia/src/gpu/GrPipeline.h @@ -10,40 +10,25 @@ #include "GrColor.h" #include "GrFragmentProcessor.h" -#include "GrGpu.h" #include "GrNonAtomicRef.h" #include "GrPendingProgramElement.h" -#include "GrPrimitiveProcessor.h" -#include "GrProcOptInfo.h" +#include "GrProcessorSet.h" #include "GrProgramDesc.h" #include "GrScissorState.h" -#include "GrStencilSettings.h" +#include "GrUserStencilSettings.h" #include "GrWindowRectsState.h" #include "SkMatrix.h" #include "SkRefCnt.h" - #include "effects/GrCoverageSetOpXP.h" #include "effects/GrDisableColorXP.h" #include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrSimpleTextureEffect.h" -class GrBatch; -class GrDrawContext; +class GrAppliedClip; class GrDeviceCoordTexture; +class GrOp; class GrPipelineBuilder; - -struct GrBatchToXPOverrides { - GrBatchToXPOverrides() - : fUsePLSDstRead(false) {} - - bool fUsePLSDstRead; -}; - -struct GrPipelineOptimizations { - GrProcOptInfo fColorPOI; - GrProcOptInfo fCoveragePOI; - GrBatchToXPOverrides fOverrides; -}; +class GrRenderTargetContext; /** * Class that holds an optimized version of a GrPipelineBuilder. It is meant to be an immutable @@ -54,19 +39,48 @@ public: /////////////////////////////////////////////////////////////////////////// /// @name Creation - struct CreateArgs { - const GrPipelineBuilder* fPipelineBuilder; - GrDrawContext* fDrawContext; - const GrCaps* fCaps; - GrPipelineOptimizations fOpts; - const GrScissorState* fScissor; - const GrWindowRectsState* fWindowRectsState; - bool fHasStencilClip; + enum Flags { + /** + * Perform HW anti-aliasing. This means either HW FSAA, if supported by the render target, + * or smooth-line rendering if a line primitive is drawn and line smoothing is supported by + * the 3D API. + */ + kHWAntialias_Flag = 0x1, + + /** + * Modifies the vertex shader so that vertices will be positioned at pixel centers. + */ + kSnapVerticesToPixelCenters_Flag = 0x2, + }; + + struct InitArgs { + uint32_t fFlags = 0; + GrDrawFace fDrawFace = GrDrawFace::kBoth; + const GrProcessorSet* fProcessors = nullptr; // Must be finalized + const GrUserStencilSettings* fUserStencil = &GrUserStencilSettings::kUnused; + const GrAppliedClip* fAppliedClip = nullptr; + GrRenderTarget* fRenderTarget = nullptr; + const GrCaps* fCaps = nullptr; GrXferProcessor::DstTexture fDstTexture; }; - /** Creates a pipeline into a pre-allocated buffer */ - static GrPipeline* CreateAt(void* memory, const CreateArgs&, GrXPOverridesForBatch*); + /** + * A Default constructed pipeline is unusable until init() is called. + **/ + GrPipeline() = default; + + /** + * Creates a simple pipeline with default settings and no processors. The provided blend mode + * must be "Porter Duff" (<= kLastCoeffMode). This pipeline is initialized without requiring + * a call to init(). + **/ + GrPipeline(GrRenderTarget*, SkBlendMode); + + /** (Re)initializes a pipeline. After initialization the pipeline can be used. */ + void init(const InitArgs&); + + /** True if the pipeline has been initialized. */ + bool isInitialized() const { return SkToBool(fRenderTarget.get()); } /// @} @@ -82,9 +96,9 @@ public: static bool AreEqual(const GrPipeline& a, const GrPipeline& b); /** - * Allows a GrBatch subclass to determine whether two GrBatches can combine. This is a stricter - * test than isEqual because it also considers blend barriers when the two batches' bounds - * overlap + * Allows a GrOp subclass to determine whether two GrOp instances can combine. This is a + * stricter test than isEqual because it also considers blend barriers when the two ops' + * bounds overlap */ static bool CanCombine(const GrPipeline& a, const SkRect& aBounds, const GrPipeline& b, const SkRect& bBounds, @@ -106,8 +120,8 @@ public: /////////////////////////////////////////////////////////////////////////// /// @name GrFragmentProcessors - // Make the renderTarget's drawTarget (if it exists) be dependent on any - // drawTargets in this pipeline + // Make the renderTarget's GrOpList (if it exists) be dependent on any + // GrOpLists in this pipeline void addDependenciesTo(GrRenderTarget* rt) const; int numColorFragmentProcessors() const { return fNumColorProcessors; } @@ -117,7 +131,7 @@ public: int numFragmentProcessors() const { return fFragmentProcessors.count(); } const GrXferProcessor& getXferProcessor() const { - if (fXferProcessor.get()) { + if (fXferProcessor) { return *fXferProcessor.get(); } else { // A null xp member means the common src-over case. GrXferProcessor's ref'ing @@ -126,6 +140,17 @@ public: } } + /** + * If the GrXferProcessor uses a texture to access the dst color, then this returns that + * texture and the offset to the dst contents within that texture. + */ + GrTexture* dstTexture(SkIPoint* offset = nullptr) const { + if (offset) { + *offset = fDstTextureOffset; + } + return fDstTexture.get(); + } + const GrFragmentProcessor& getColorFragmentProcessor(int idx) const { SkASSERT(idx < this->numColorFragmentProcessors()); return *fFragmentProcessors[idx].get(); @@ -149,14 +174,16 @@ public: */ GrRenderTarget* getRenderTarget() const { return fRenderTarget.get(); } - const GrStencilSettings& getStencil() const { return fStencilSettings; } + const GrUserStencilSettings* getUserStencil() const { return fUserStencilSettings; } const GrScissorState& getScissorState() const { return fScissorState; } const GrWindowRectsState& getWindowRectsState() const { return fWindowRectsState; } - bool isHWAntialiasState() const { return SkToBool(fFlags & kHWAA_Flag); } - bool snapVerticesToPixelCenters() const { return SkToBool(fFlags & kSnapVertices_Flag); } + bool isHWAntialiasState() const { return SkToBool(fFlags & kHWAntialias_Flag); } + bool snapVerticesToPixelCenters() const { + return SkToBool(fFlags & kSnapVerticesToPixelCenters_Flag); + } bool getDisableOutputConversionToSRGB() const { return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag); } @@ -169,9 +196,15 @@ public: bool hasStencilClip() const { return SkToBool(fFlags & kHasStencilClip_Flag); } + bool isStencilEnabled() const { + return SkToBool(fFlags & kStencilEnabled_Flag); + } GrXferBarrierType xferBarrierType(const GrCaps& caps) const { - return this->getXferProcessor().xferBarrierType(fRenderTarget.get(), caps); + if (fDstTexture.get() && fDstTexture.get() == fRenderTarget.get()->asTexture()) { + return kTexture_GrXferBarrierType; + } + return this->getXferProcessor().xferBarrierType(caps); } /** @@ -179,59 +212,36 @@ public: * or both faces. * @return the current draw face(s). */ - GrDrawFace getDrawFace() const { return fDrawFace; } - - - /////////////////////////////////////////////////////////////////////////// - - bool ignoresCoverage() const { return fIgnoresCoverage; } + GrDrawFace getDrawFace() const { return static_cast(fDrawFace); } private: - GrPipeline() { /** Initialized in factory function*/ } - - /** - * Alter the program desc and inputs (attribs and processors) based on the blend optimization. - */ - void adjustProgramFromOptimizations(const GrPipelineBuilder& ds, - GrXferProcessor::OptFlags, - const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - int* firstColorProcessorIdx, - int* firstCoverageProcessorIdx); - - /** - * Calculates the primary and secondary output types of the shader. For certain output types - * the function may adjust the blend coefficients. After this function is called the src and dst - * blend coeffs will represent those used by backend API. - */ - void setOutputStateInfo(const GrPipelineBuilder& ds, GrXferProcessor::OptFlags, - const GrCaps&); - - enum Flags { - kHWAA_Flag = 0x1, - kSnapVertices_Flag = 0x2, + /** This is a continuation of the public "Flags" enum. */ + enum PrivateFlags { kDisableOutputConversionToSRGB_Flag = 0x4, - kAllowSRGBInputs_Flag = 0x8, - kUsesDistanceVectorField_Flag = 0x10, - kHasStencilClip_Flag = 0x20, + kAllowSRGBInputs_Flag = 0x8, + kUsesDistanceVectorField_Flag = 0x10, + kHasStencilClip_Flag = 0x20, + kStencilEnabled_Flag = 0x40, }; - typedef GrPendingIOResource RenderTarget; - typedef GrPendingProgramElement PendingFragmentProcessor; - typedef SkAutoSTArray<8, PendingFragmentProcessor> FragmentProcessorArray; - typedef GrPendingProgramElement ProgramXferProcessor; - RenderTarget fRenderTarget; - GrScissorState fScissorState; - GrWindowRectsState fWindowRectsState; - GrStencilSettings fStencilSettings; - GrDrawFace fDrawFace; - uint32_t fFlags; - ProgramXferProcessor fXferProcessor; - FragmentProcessorArray fFragmentProcessors; - bool fIgnoresCoverage; + using RenderTarget = GrPendingIOResource; + using DstTexture = GrPendingIOResource; + using PendingFragmentProcessor = GrPendingProgramElement; + using FragmentProcessorArray = SkAutoSTArray<8, PendingFragmentProcessor>; + + DstTexture fDstTexture; + SkIPoint fDstTextureOffset; + RenderTarget fRenderTarget; + GrScissorState fScissorState; + GrWindowRectsState fWindowRectsState; + const GrUserStencilSettings* fUserStencilSettings; + uint16_t fDrawFace; + uint16_t fFlags; + sk_sp fXferProcessor; + FragmentProcessorArray fFragmentProcessors; // This value is also the index in fFragmentProcessors where coverage processors begin. - int fNumColorProcessors; + int fNumColorProcessors; typedef SkRefCnt INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/GrPipelineBuilder.cpp b/gfx/skia/skia/src/gpu/GrPipelineBuilder.cpp deleted file mode 100644 index 864d6f1bc613..000000000000 --- a/gfx/skia/skia/src/gpu/GrPipelineBuilder.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrPipelineBuilder.h" - -#include "GrBlend.h" -#include "GrPaint.h" -#include "GrPipeline.h" -#include "GrProcOptInfo.h" -#include "GrXferProcessor.h" -#include "batches/GrBatch.h" -#include "effects/GrPorterDuffXferProcessor.h" - -GrPipelineBuilder::GrPipelineBuilder() - : fFlags(0x0) - , fUserStencilSettings(&GrUserStencilSettings::kUnused) - , fDrawFace(GrDrawFace::kBoth) { - SkDEBUGCODE(fBlockEffectRemovalCnt = 0;) -} - -GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, bool useHWAA) - : GrPipelineBuilder() { - SkDEBUGCODE(fBlockEffectRemovalCnt = 0;) - - for (int i = 0; i < paint.numColorFragmentProcessors(); ++i) { - fColorFragmentProcessors.emplace_back(SkRef(paint.getColorFragmentProcessor(i))); - } - - for (int i = 0; i < paint.numCoverageFragmentProcessors(); ++i) { - fCoverageFragmentProcessors.emplace_back(SkRef(paint.getCoverageFragmentProcessor(i))); - } - - fXPFactory.reset(SkSafeRef(paint.getXPFactory())); - - this->setState(GrPipelineBuilder::kHWAntialias_Flag, useHWAA); - this->setState(GrPipelineBuilder::kDisableOutputConversionToSRGB_Flag, - paint.getDisableOutputConversionToSRGB()); - this->setState(GrPipelineBuilder::kAllowSRGBInputs_Flag, - paint.getAllowSRGBInputs()); - this->setState(GrPipelineBuilder::kUsesDistanceVectorField_Flag, - paint.usesDistanceVectorField()); -} - -//////////////////////////////////////////////////////////////////////////////s - -bool GrPipelineBuilder::willXPNeedDstTexture(const GrCaps& caps, - const GrPipelineOptimizations& optimizations) const { - if (this->getXPFactory()) { - return this->getXPFactory()->willNeedDstTexture(caps, optimizations); - } - return GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(caps, optimizations); -} - -void GrPipelineBuilder::AutoRestoreFragmentProcessorState::set( - const GrPipelineBuilder* pipelineBuilder) { - if (fPipelineBuilder) { - int m = fPipelineBuilder->numColorFragmentProcessors() - fColorEffectCnt; - SkASSERT(m >= 0); - fPipelineBuilder->fColorFragmentProcessors.pop_back_n(m); - - int n = fPipelineBuilder->numCoverageFragmentProcessors() - fCoverageEffectCnt; - SkASSERT(n >= 0); - fPipelineBuilder->fCoverageFragmentProcessors.pop_back_n(n); - - SkDEBUGCODE(--fPipelineBuilder->fBlockEffectRemovalCnt;) - } - fPipelineBuilder = const_cast(pipelineBuilder); - if (nullptr != pipelineBuilder) { - fColorEffectCnt = pipelineBuilder->numColorFragmentProcessors(); - fCoverageEffectCnt = pipelineBuilder->numCoverageFragmentProcessors(); - SkDEBUGCODE(++pipelineBuilder->fBlockEffectRemovalCnt;) - } -} - -//////////////////////////////////////////////////////////////////////////////// - -GrPipelineBuilder::~GrPipelineBuilder() { - SkASSERT(0 == fBlockEffectRemovalCnt); -} diff --git a/gfx/skia/skia/src/gpu/GrPipelineBuilder.h b/gfx/skia/skia/src/gpu/GrPipelineBuilder.h index 0c33eb344f8c..78aead0f896f 100644 --- a/gfx/skia/skia/src/gpu/GrPipelineBuilder.h +++ b/gfx/skia/skia/src/gpu/GrPipelineBuilder.h @@ -8,38 +8,35 @@ #ifndef GrPipelineBuilder_DEFINED #define GrPipelineBuilder_DEFINED -#include "GrBlend.h" -#include "GrCaps.h" #include "GrGpuResourceRef.h" -#include "GrProcOptInfo.h" +#include "GrPipeline.h" +#include "GrProcessorSet.h" #include "GrRenderTarget.h" #include "GrUserStencilSettings.h" #include "GrXferProcessor.h" -#include "SkMatrix.h" -#include "SkRefCnt.h" -#include "effects/GrCoverageSetOpXP.h" -#include "effects/GrDisableColorXP.h" -#include "effects/GrPorterDuffXferProcessor.h" -#include "effects/GrSimpleTextureEffect.h" -class GrDrawBatch; class GrCaps; +class GrDrawOp; class GrPaint; class GrTexture; -class GrPipelineBuilder : public SkNoncopyable { +class GrPipelineBuilder : private SkNoncopyable { public: - GrPipelineBuilder(); - /** * Initializes the GrPipelineBuilder based on a GrPaint and MSAA availability. Note * that GrPipelineBuilder encompasses more than GrPaint. Aspects of GrPipelineBuilder that have * no GrPaint equivalents are set to default values with the exception of vertex attribute state * which is unmodified by this function and clipping which will be enabled. */ - GrPipelineBuilder(const GrPaint&, bool useHWAA = false); - - virtual ~GrPipelineBuilder(); + GrPipelineBuilder(GrPaint&& paint, GrAAType aaType) + : fFlags(0x0) + , fDrawFace(GrDrawFace::kBoth) + , fUserStencilSettings(&GrUserStencilSettings::kUnused) + , fProcessors(std::move(paint)) { + if (GrAATypeIsHW(aaType)) { + fFlags |= GrPipeline::kHWAntialias_Flag; + } + } /////////////////////////////////////////////////////////////////////////// /// @name Fragment Processors @@ -51,123 +48,29 @@ public: /// feed their output to the GrXferProcessor which controls blending. //// - int numColorFragmentProcessors() const { return fColorFragmentProcessors.count(); } - int numCoverageFragmentProcessors() const { return fCoverageFragmentProcessors.count(); } - int numFragmentProcessors() const { return this->numColorFragmentProcessors() + - this->numCoverageFragmentProcessors(); } + int numColorFragmentProcessors() const { return fProcessors.numColorFragmentProcessors(); } + int numCoverageFragmentProcessors() const { + return fProcessors.numCoverageFragmentProcessors(); + } + int numFragmentProcessors() const { return fProcessors.numFragmentProcessors(); } const GrFragmentProcessor* getColorFragmentProcessor(int idx) const { - return fColorFragmentProcessors[idx].get(); + return fProcessors.colorFragmentProcessor(idx); } const GrFragmentProcessor* getCoverageFragmentProcessor(int idx) const { - return fCoverageFragmentProcessors[idx].get(); + return fProcessors.coverageFragmentProcessor(idx); } - void addColorFragmentProcessor(sk_sp processor) { - SkASSERT(processor); - fColorFragmentProcessors.push_back(std::move(processor)); + const GrProcessorSet& processors() const { return fProcessors; } + + GrProcessorSet::Analysis finalizeProcessors(const GrProcessorAnalysisColor& colorInput, + const GrProcessorAnalysisCoverage coverageInput, + const GrAppliedClip* clip, bool isMixedSamples, + const GrCaps& caps, GrColor* overrideColor) { + return fProcessors.finalize(colorInput, coverageInput, clip, isMixedSamples, caps, + overrideColor); } - void addCoverageFragmentProcessor(sk_sp processor) { - SkASSERT(processor); - fCoverageFragmentProcessors.push_back(std::move(processor)); - } - - /** - * Creates a GrSimpleTextureEffect that uses local coords as texture coordinates. - */ - void addColorTextureProcessor(GrTexture* texture, const SkMatrix& matrix) { - this->addColorFragmentProcessor(GrSimpleTextureEffect::Make(texture, nullptr, matrix)); - } - - void addCoverageTextureProcessor(GrTexture* texture, const SkMatrix& matrix) { - this->addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(texture, nullptr, matrix)); - } - - void addColorTextureProcessor(GrTexture* texture, - const SkMatrix& matrix, - const GrTextureParams& params) { - this->addColorFragmentProcessor(GrSimpleTextureEffect::Make(texture, nullptr, matrix, - params)); - } - - void addCoverageTextureProcessor(GrTexture* texture, - const SkMatrix& matrix, - const GrTextureParams& params) { - this->addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(texture, nullptr, matrix, - params)); - } - - /** - * When this object is destroyed it will remove any color/coverage FPs from the pipeline builder - * that were added after its constructor. - * This class can transiently modify its "const" GrPipelineBuilder object but will restore it - * when done - so it is notionally "const" correct. - */ - class AutoRestoreFragmentProcessorState : public ::SkNoncopyable { - public: - AutoRestoreFragmentProcessorState() - : fPipelineBuilder(nullptr) - , fColorEffectCnt(0) - , fCoverageEffectCnt(0) {} - - AutoRestoreFragmentProcessorState(const GrPipelineBuilder& ds) - : fPipelineBuilder(nullptr) - , fColorEffectCnt(0) - , fCoverageEffectCnt(0) { - this->set(&ds); - } - - ~AutoRestoreFragmentProcessorState() { this->set(nullptr); } - - void set(const GrPipelineBuilder* ds); - - bool isSet() const { return SkToBool(fPipelineBuilder); } - - void addCoverageFragmentProcessor(sk_sp processor) { - SkASSERT(this->isSet()); - return fPipelineBuilder->addCoverageFragmentProcessor(std::move(processor)); - } - - private: - // notionally const (as marginalia) - GrPipelineBuilder* fPipelineBuilder; - int fColorEffectCnt; - int fCoverageEffectCnt; - }; - - /// @} - - /////////////////////////////////////////////////////////////////////////// - /// @name Blending - //// - - /** - * Installs a GrXPFactory. This object controls how src color, fractional pixel coverage, - * and the dst color are blended. - */ - void setXPFactory(sk_sp xpFactory) { - fXPFactory = std::move(xpFactory); - } - - /** - * Sets a GrXPFactory that disables color writes to the destination. This is useful when - * rendering to the stencil buffer. - */ - void setDisableColorXPFactory() { - fXPFactory = GrDisableColorXPFactory::Make(); - } - - const GrXPFactory* getXPFactory() const { - return fXPFactory.get(); - } - - /** - * Checks whether the xp will need destination in a texture to correctly blend. - */ - bool willXPNeedDstTexture(const GrCaps& caps, - const GrPipelineOptimizations& optimizations) const; - /// @} @@ -176,7 +79,6 @@ public: //// bool hasUserStencilSettings() const { return !fUserStencilSettings->isUnused(); } - const GrUserStencilSettings* getUserStencil() const { return fUserStencilSettings; } /** * Sets the user stencil settings for the next draw. @@ -186,7 +88,6 @@ public: * @param settings the stencil settings to use. */ void setUserStencil(const GrUserStencilSettings* settings) { fUserStencilSettings = settings; } - void disableUserStencil() { fUserStencilSettings = &GrUserStencilSettings::kUnused; } /// @} @@ -194,77 +95,13 @@ public: /// @name State Flags //// - /** - * Flags that affect rendering. Controlled using enable/disableState(). All - * default to disabled. - */ - enum Flags { - /** - * Perform HW anti-aliasing. This means either HW FSAA, if supported by the render target, - * or smooth-line rendering if a line primitive is drawn and line smoothing is supported by - * the 3D API. - */ - kHWAntialias_Flag = 0x01, + bool isHWAntialias() const { return SkToBool(fFlags & GrPipeline::kHWAntialias_Flag); } - /** - * Modifies the vertex shader so that vertices will be positioned at pixel centers. - */ - kSnapVerticesToPixelCenters_Flag = 0x02, - - /** - * Suppress linear -> sRGB conversion when rendering to sRGB render targets. - */ - kDisableOutputConversionToSRGB_Flag = 0x04, - - /** - * Allow sRGB -> linear conversion when reading from sRGB inputs. - */ - kAllowSRGBInputs_Flag = 0x08, - - /** - * Signals that one or more FPs need access to the distance vector field to the nearest - * edge - */ - kUsesDistanceVectorField_Flag = 0x10, - - kLast_Flag = kUsesDistanceVectorField_Flag, - }; - - bool isHWAntialias() const { return SkToBool(fFlags & kHWAntialias_Flag); } - bool snapVerticesToPixelCenters() const { - return SkToBool(fFlags & kSnapVerticesToPixelCenters_Flag); } - bool getDisableOutputConversionToSRGB() const { - return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag); } - bool getAllowSRGBInputs() const { - return SkToBool(fFlags & kAllowSRGBInputs_Flag); } - bool getUsesDistanceVectorField() const { - return SkToBool(fFlags & kUsesDistanceVectorField_Flag); } - - /** - * Enable render state settings. - * - * @param flags bitfield of Flags specifying the states to enable - */ - void enableState(uint32_t flags) { fFlags |= flags; } - - /** - * Disable render state settings. - * - * @param flags bitfield of Flags specifying the states to disable - */ - void disableState(uint32_t flags) { fFlags &= ~(flags); } - - /** - * Enable or disable flags based on a boolean. - * - * @param flags bitfield of Flags to enable or disable - * @param enable if true enable stateBits, otherwise disable - */ - void setState(uint32_t flags, bool enable) { + void setSnapVerticesToPixelCenters(bool enable) { if (enable) { - this->enableState(flags); + fFlags |= GrPipeline::kSnapVerticesToPixelCenters_Flag; } else { - this->disableState(flags); + fFlags &= ~GrPipeline::kSnapVerticesToPixelCenters_Flag; } } @@ -274,13 +111,6 @@ public: /// @name Face Culling //// - /** - * Gets whether the target is drawing clockwise, counterclockwise, - * or both faces. - * @return the current draw face(s). - */ - GrDrawFace getDrawFace() const { return fDrawFace; } - /** * Controls whether clockwise, counterclockwise, or both faces are drawn. * @param face the face(s) to draw. @@ -292,26 +122,18 @@ public: /// @} - /////////////////////////////////////////////////////////////////////////// - - bool usePLSDstRead(const GrDrawBatch* batch) const; + void getPipelineInitArgs(GrPipeline::InitArgs* args) const { + args->fFlags = fFlags; + args->fUserStencil = fUserStencilSettings; + args->fDrawFace = fDrawFace; + args->fProcessors = &fProcessors; + } private: - // Some of the auto restore objects assume that no effects are removed during their lifetime. - // This is used to assert that this condition holds. - SkDEBUGCODE(mutable int fBlockEffectRemovalCnt;) - - typedef SkSTArray<4, sk_sp> FragmentProcessorArray; - - uint32_t fFlags; - const GrUserStencilSettings* fUserStencilSettings; - GrDrawFace fDrawFace; - mutable sk_sp fXPFactory; - FragmentProcessorArray fColorFragmentProcessors; - FragmentProcessorArray fCoverageFragmentProcessors; - - friend class GrPipeline; - friend class GrDrawTarget; + uint32_t fFlags; + GrDrawFace fDrawFace; + const GrUserStencilSettings* fUserStencilSettings; + GrProcessorSet fProcessors; }; #endif diff --git a/gfx/skia/skia/src/gpu/GrPreFlushResourceProvider.cpp b/gfx/skia/skia/src/gpu/GrPreFlushResourceProvider.cpp new file mode 100644 index 000000000000..7a105604e0bb --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrPreFlushResourceProvider.cpp @@ -0,0 +1,83 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrPreFlushResourceProvider.h" + +#include "GrDrawingManager.h" +#include "GrSurfaceProxy.h" + +sk_sp GrPreFlushResourceProvider::makeRenderTargetContext( + const GrSurfaceDesc& desc, + sk_sp colorSpace, + const SkSurfaceProps* props) { + GrSurfaceDesc tmpDesc = desc; + tmpDesc.fFlags |= kRenderTarget_GrSurfaceFlag; + + // Because this is being allocated at the start of a flush we must ensure the proxy + // will, when instantiated, have no pending IO. + // TODO: fold the kNoPendingIO_Flag into GrSurfaceFlags? + sk_sp proxy = GrSurfaceProxy::MakeDeferred( + fDrawingMgr->getContext()->resourceProvider(), + tmpDesc, + SkBackingFit::kExact, + SkBudgeted::kYes, + GrResourceProvider::kNoPendingIO_Flag); + if (!proxy->asRenderTargetProxy()) { + return nullptr; + } + + sk_sp opList(new GrRenderTargetOpList( + proxy->asRenderTargetProxy(), + fDrawingMgr->fContext->getGpu(), + fDrawingMgr->fContext->resourceProvider(), + fDrawingMgr->fContext->getAuditTrail(), + fDrawingMgr->fOptionsForOpLists)); + proxy->setLastOpList(opList.get()); + + sk_sp renderTargetContext( + fDrawingMgr->makeRenderTargetContext(std::move(proxy), + std::move(colorSpace), + props)); + + if (!renderTargetContext) { + return nullptr; + } + + renderTargetContext->discard(); + + return renderTargetContext; +} + +// TODO: we only need this entry point as long as we have to pre-allocate the atlas. +// Remove it ASAP. +sk_sp GrPreFlushResourceProvider::makeRenderTargetContext( + sk_sp proxy, + sk_sp colorSpace, + const SkSurfaceProps* props) { + + sk_sp opList(new GrRenderTargetOpList( + proxy->asRenderTargetProxy(), + fDrawingMgr->fContext->getGpu(), + fDrawingMgr->fContext->resourceProvider(), + fDrawingMgr->fContext->getAuditTrail(), + fDrawingMgr->fOptionsForOpLists)); + proxy->setLastOpList(opList.get()); + + sk_sp renderTargetContext( + fDrawingMgr->makeRenderTargetContext(std::move(proxy), + std::move(colorSpace), + props)); + + if (!renderTargetContext) { + return nullptr; + } + + renderTargetContext->discard(); + + return renderTargetContext; +} + diff --git a/gfx/skia/skia/src/gpu/GrPreFlushResourceProvider.h b/gfx/skia/skia/src/gpu/GrPreFlushResourceProvider.h new file mode 100644 index 000000000000..86a299a42299 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrPreFlushResourceProvider.h @@ -0,0 +1,77 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrPreFlushResourceProvider_DEFINED +#define GrPreFlushResourceProvider_DEFINED + +#include "GrTypes.h" +#include "GrNonAtomicRef.h" + +// These two are just for GrPreFlushCallbackObject +#include "SkRefCnt.h" +#include "SkTDArray.h" + +class GrDrawingManager; +class GrOpList; +class GrPreFlushResourceProvider; +class GrRenderTargetOpList; +class GrRenderTargetContext; +class GrSurfaceProxy; + +class SkColorSpace; +class SkSurfaceProps; + +/* + * This is the base class from which all per-flush callback objects must be derived. It + * provides the "preFlush" interface. + */ +class GrPreFlushCallbackObject : public GrNonAtomicRef { +public: + virtual ~GrPreFlushCallbackObject() { } + + /* + * The preFlush callback allows subsystems (e.g., text, path renderers) to create atlases + * for a specific flush. All the GrOpList IDs required for the flush are passed into the + * callback. The callback should return the render target contexts used to render the atlases + * in 'results'. + */ + virtual void preFlush(GrPreFlushResourceProvider*, + const uint32_t* opListIDs, int numOpListIDs, + SkTArray>* results) = 0; + +private: + typedef SkRefCnt INHERITED; +}; + +/* + * This class is a shallow wrapper around the drawing manager. It is passed into the + * preFlush callbacks and is intended to limit the functionality available to them. + * It should never have additional data members or virtual methods. + */ +class GrPreFlushResourceProvider { +public: + sk_sp makeRenderTargetContext(const GrSurfaceDesc& desc, + sk_sp colorSpace, + const SkSurfaceProps* props); + + // TODO: we only need this entry point as long as we have to pre-allocate the atlas. + // Remove it ASAP. + sk_sp makeRenderTargetContext(sk_sp proxy, + sk_sp colorSpace, + const SkSurfaceProps* props); + +private: + explicit GrPreFlushResourceProvider(GrDrawingManager* drawingMgr) : fDrawingMgr(drawingMgr) {} + GrPreFlushResourceProvider(const GrPreFlushResourceProvider&); // unimpl + GrPreFlushResourceProvider& operator=(const GrPreFlushResourceProvider&); // unimpl + + GrDrawingManager* fDrawingMgr; + + friend class GrDrawingManager; // to construct this type. +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrPrimitiveProcessor.cpp b/gfx/skia/skia/src/gpu/GrPrimitiveProcessor.cpp index 2aaaa0474fe3..b981977af374 100644 --- a/gfx/skia/skia/src/gpu/GrPrimitiveProcessor.cpp +++ b/gfx/skia/skia/src/gpu/GrPrimitiveProcessor.cpp @@ -10,23 +10,15 @@ #include "GrCoordTransform.h" /** - * The key for an individual coord transform is made up of a matrix type, a precision, and a bit - * that indicates the source of the input coords. + * The key for an individual coord transform is made up of a matrix type, and a bit that indicates + * the source of the input coords. */ enum { kMatrixTypeKeyBits = 1, - kMatrixTypeKeyMask = (1 << kMatrixTypeKeyBits) - 1, - - kPrecisionBits = 2, - kPrecisionShift = kMatrixTypeKeyBits, - - kPositionCoords_Flag = (1 << (kPrecisionShift + kPrecisionBits)), - - kTransformKeyBits = kMatrixTypeKeyBits + kPrecisionBits + 2, + kPositionCoords_Flag = 1 << kMatrixTypeKeyBits, + kTransformKeyBits = kMatrixTypeKeyBits + 1, }; -GR_STATIC_ASSERT(kHigh_GrSLPrecision < (1 << kPrecisionBits)); - /** * We specialize the vertex code for each of these matrix types. */ @@ -52,9 +44,6 @@ GrPrimitiveProcessor::getTransformKey(const SkTArrayprecision() << kPrecisionShift); - key <<= kTransformKeyBits * t; SkASSERT(0 == (totalKey & key)); // keys for each transform ought not to overlap diff --git a/gfx/skia/skia/src/gpu/GrPrimitiveProcessor.h b/gfx/skia/skia/src/gpu/GrPrimitiveProcessor.h index 00b4df01ed96..d078ac507213 100644 --- a/gfx/skia/skia/src/gpu/GrPrimitiveProcessor.h +++ b/gfx/skia/skia/src/gpu/GrPrimitiveProcessor.h @@ -18,134 +18,27 @@ * responsible for providing a color and coverage input into the Ganesh rendering pipeline. Through * optimization, Ganesh may decide a different color, no color, and / or no coverage are required * from the GrPrimitiveProcessor, so the GrPrimitiveProcessor must be able to support this - * functionality. We also use the GrPrimitiveProcessor to make batching decisions. + * functionality. * * There are two feedback loops between the GrFragmentProcessors, the GrXferProcessor, and the - * GrPrimitiveProcessor. These loops run on the CPU and compute any invariant components which - * might be useful for correctness / optimization decisions. The GrPrimitiveProcessor seeds these - * loops, one with initial color and one with initial coverage, in its - * onComputeInvariantColor / Coverage calls. These seed values are processed by the subsequent - * stages of the rendering pipeline and the output is then fed back into the GrPrimitiveProcessor in - * the initBatchTracker call, where the GrPrimitiveProcessor can then initialize the GrBatchTracker - * struct with the appropriate values. - * - * We are evolving this system to move towards generating geometric meshes and their associated - * vertex data after we have batched and reordered draws. This system, known as 'deferred geometry' - * will allow the GrPrimitiveProcessor much greater control over how data is transmitted to shaders. - * - * In a deferred geometry world, the GrPrimitiveProcessor can always 'batch' To do this, each - * primitive type is associated with one GrPrimitiveProcessor, who has complete control of how - * it draws. Each primitive draw will bundle all required data to perform the draw, and these - * bundles of data will be owned by an instance of the associated GrPrimitiveProcessor. Bundles - * can be updated alongside the GrBatchTracker struct itself, ultimately allowing the - * GrPrimitiveProcessor complete control of how it gets data into the fragment shader as long as - * it emits the appropriate color, or none at all, as directed. + * GrPrimitiveProcessor. These loops run on the CPU and to determine known properties of the final + * color and coverage inputs to the GrXferProcessor in order to perform optimizations that preserve + * correctness. The GrDrawOp seeds these loops with initial color and coverage, in its + * getProcessorAnalysisInputs implementation. These seed values are processed by the + * subsequent + * stages of the rendering pipeline and the output is then fed back into the GrDrawOp in + * the applyPipelineOptimizations call, where the op can use the information to inform decisions + * about GrPrimitiveProcessor creation. */ -class GrGLSLCaps; class GrGLSLPrimitiveProcessor; -struct GrInitInvariantOutput; - -// Describes the state of pixel local storage with respect to the current draw. -enum GrPixelLocalStorageState { - // The draw is actively updating PLS. - kDraw_GrPixelLocalStorageState, - // The draw is a "finish" operation which is reading from PLS and writing color. - kFinish_GrPixelLocalStorageState, - // The draw does not use PLS. - kDisabled_GrPixelLocalStorageState -}; - -/* - * This class allows the GrPipeline to communicate information about the pipeline to a - * GrBatch which should be forwarded to the GrPrimitiveProcessor(s) created by the batch. - * These are not properly part of the pipeline because they assume the specific inputs - * that the batch provided when it created the pipeline. Identical pipelines may be - * created by different batches with different input assumptions and therefore different - * computed optimizations. It is the batch-specific optimizations that allow the pipelines - * to be equal. - */ -class GrXPOverridesForBatch { -public: - /** Does the pipeline require the GrPrimitiveProcessor's color? */ - bool readsColor() const { return SkToBool(kReadsColor_Flag & fFlags); } - - /** Does the pipeline require the GrPrimitiveProcessor's coverage? */ - bool readsCoverage() const { return - SkToBool(kReadsCoverage_Flag & fFlags); } - - /** Does the pipeline require access to (implicit or explicit) local coordinates? */ - bool readsLocalCoords() const { - return SkToBool(kReadsLocalCoords_Flag & fFlags); - } - - /** Does the pipeline allow the GrPrimitiveProcessor to combine color and coverage into one - color output ? */ - bool canTweakAlphaForCoverage() const { - return SkToBool(kCanTweakAlphaForCoverage_Flag & fFlags); - } - - /** Does the pipeline require the GrPrimitiveProcessor to specify a specific color (and if - so get the color)? */ - bool getOverrideColorIfSet(GrColor* overrideColor) const { - if (SkToBool(kUseOverrideColor_Flag & fFlags)) { - SkASSERT(SkToBool(kReadsColor_Flag & fFlags)); - if (overrideColor) { - *overrideColor = fOverrideColor; - } - return true; - } - return false; - } - - /** - * Returns true if the pipeline's color output will be affected by the existing render target - * destination pixel values (meaning we need to be careful with overlapping draws). Note that we - * can conflate coverage and color, so the destination color may still bleed into pixels that - * have partial coverage, even if this function returns false. - * - * The above comment seems incorrect for the use case. This funciton is used to turn two - * overlapping draws into a single draw (really to stencil multiple paths and do a single - * cover). It seems that what really matters is whether the dst is read for color OR for - * coverage. - */ - bool willColorBlendWithDst() const { return SkToBool(kWillColorBlendWithDst_Flag & fFlags); } - -private: - enum { - // If this is not set the primitive processor need not produce a color output - kReadsColor_Flag = 0x1, - - // If this is not set the primitive processor need not produce a coverage output - kReadsCoverage_Flag = 0x2, - - // If this is not set the primitive processor need not produce local coordinates - kReadsLocalCoords_Flag = 0x4, - - // If this flag is set then the primitive processor may produce color*coverage as - // its color output (and not output a separate coverage). - kCanTweakAlphaForCoverage_Flag = 0x8, - - // If this flag is set the GrPrimitiveProcessor must produce fOverrideColor as its - // output color. If not set fOverrideColor is to be ignored. - kUseOverrideColor_Flag = 0x10, - - kWillColorBlendWithDst_Flag = 0x20, - }; - - uint32_t fFlags; - GrColor fOverrideColor; - - friend class GrPipeline; // To initialize this -}; - /* * GrPrimitiveProcessor defines an interface which all subclasses must implement. All * GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage * pipelines, and they must provide some notion of equality */ -class GrPrimitiveProcessor : public GrProcessor { +class GrPrimitiveProcessor : public GrResourceIOProcessor, public GrProgramElement { public: // Only the GrGeometryProcessor subclass actually has a geo shader or vertex attributes, but // we put these calls on the base class to prevent having to cast @@ -171,7 +64,7 @@ public: const Attribute& getAttrib(int index) const { return fAttribs[index]; } // Returns the vertex stride of the GP. A common use case is to request geometry from a - // drawtarget based off of the stride, and to populate this memory using an implicit array of + // GrOpList based off of the stride, and to populate this memory using an implicit array of // structs. In this case, it is best to assert the vertexstride == sizeof(VertexStruct). size_t getVertexStride() const { return fVertexStride; } @@ -190,21 +83,16 @@ public: * * TODO: A better name for this function would be "compute" instead of "get". */ - virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const = 0; + virtual void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0; /** Returns a new instance of the appropriate *GL* implementation class for the given GrProcessor; caller is responsible for deleting the object. */ - virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps& caps) const = 0; + virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const = 0; virtual bool isPathRendering() const { return false; } - virtual GrPixelLocalStorageState getPixelLocalStorageState() const { - return kDisabled_GrPixelLocalStorageState; - } - /** * If non-null, overrides the dest color returned by GrGLSLFragmentShaderBuilder::dstColor(). */ @@ -226,6 +114,9 @@ protected: size_t fVertexStride; private: + void addPendingIOs() const override { GrResourceIOProcessor::addPendingIOs(); } + void removeRefs() const override { GrResourceIOProcessor::removeRefs(); } + void pendingIOComplete() const override { GrResourceIOProcessor::pendingIOComplete(); } void notifyRefCntIsZero() const final {} virtual bool hasExplicitLocalCoords() const = 0; diff --git a/gfx/skia/skia/src/gpu/GrProcOptInfo.cpp b/gfx/skia/skia/src/gpu/GrProcOptInfo.cpp deleted file mode 100644 index 183a42fb33e1..000000000000 --- a/gfx/skia/skia/src/gpu/GrProcOptInfo.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrProcOptInfo.h" - -#include "GrGeometryProcessor.h" - -#include "batches/GrDrawBatch.h" - -void GrProcOptInfo::calcWithInitialValues(const GrFragmentProcessor * const processors[], - int cnt, - GrColor startColor, - GrColorComponentFlags flags, - bool areCoverageStages, - bool isLCD) { - GrInitInvariantOutput out; - out.fIsSingleComponent = areCoverageStages; - out.fColor = startColor; - out.fValidFlags = flags; - out.fIsLCDCoverage = isLCD; - fInOut.reset(out); - this->internalCalc(processors, cnt); -} - -void GrProcOptInfo::initUsingInvariantOutput(GrInitInvariantOutput invOutput) { - fInOut.reset(invOutput); -} - -void GrProcOptInfo::completeCalculations(const GrFragmentProcessor * const processors[], int cnt) { - this->internalCalc(processors, cnt); -} - -void GrProcOptInfo::internalCalc(const GrFragmentProcessor* const processors[], int cnt) { - fFirstEffectiveProcessorIndex = 0; - fInputColorIsUsed = true; - fInputColor = fInOut.color(); - - for (int i = 0; i < cnt; ++i) { - const GrFragmentProcessor* processor = processors[i]; - fInOut.resetWillUseInputColor(); - processor->computeInvariantOutput(&fInOut); - SkDEBUGCODE(fInOut.validate()); - if (!fInOut.willUseInputColor()) { - fFirstEffectiveProcessorIndex = i; - fInputColorIsUsed = false; - } - if (kRGBA_GrColorComponentFlags == fInOut.validFlags()) { - fFirstEffectiveProcessorIndex = i + 1; - fInputColor = fInOut.color(); - fInputColorIsUsed = true; - // Since we are clearing all previous color stages we are in a state where we have found - // zero stages that don't multiply the inputColor. - fInOut.resetNonMulStageFound(); - } - } -} diff --git a/gfx/skia/skia/src/gpu/GrProcOptInfo.h b/gfx/skia/skia/src/gpu/GrProcOptInfo.h deleted file mode 100644 index 87e7cd9c6977..000000000000 --- a/gfx/skia/skia/src/gpu/GrProcOptInfo.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrProcOptInfo_DEFINED -#define GrProcOptInfo_DEFINED - -#include "GrColor.h" -#include "GrInvariantOutput.h" - -class GrDrawBatch; -class GrFragmentProcessor; -class GrPrimitiveProcessor; - -/** - * GrProcOptInfo gathers invariant data from a set of processor stages.It is used to recognize - * optimizations related to eliminating stages and vertex attributes that aren't necessary for a - * draw. - */ -class GrProcOptInfo { -public: - GrProcOptInfo() - : fInOut(0, static_cast(0), false) - , fFirstEffectiveProcessorIndex(0) - , fInputColorIsUsed(true) - , fInputColor(0) {} - - void calcWithInitialValues(const GrFragmentProcessor* const *, int cnt, GrColor startColor, - GrColorComponentFlags, bool areCoverageStages, bool isLCD = false); - void initUsingInvariantOutput(GrInitInvariantOutput invOutput); - void completeCalculations(const GrFragmentProcessor * const processors[], int cnt); - - bool isSolidWhite() const { return fInOut.isSolidWhite(); } - bool isOpaque() const { return fInOut.isOpaque(); } - bool isSingleComponent() const { return fInOut.isSingleComponent(); } - bool allStagesMultiplyInput() const { return fInOut.allStagesMulInput(); } - - // TODO: Once texture pixel configs quaries are updated, we no longer need this function. - // For now this function will correctly tell us if we are using LCD text or not and should only - // be called when looking at the coverage output. - bool isFourChannelOutput() const { return !fInOut.isSingleComponent() && - fInOut.isLCDCoverage(); } - - GrColor color() const { return fInOut.color(); } - - GrColorComponentFlags validFlags() const { - return fInOut.validFlags(); - } - - /** - * Returns the index of the first effective color processor. If an intermediate processor - * doesn't read its input or has a known output, then we can ignore all earlier processors - * since they will not affect the final output. Thus the first effective processors index is - * the index to the first processor that will have an effect on the final output. - * - * If processors before the firstEffectiveProcessorIndex() are removed, corresponding values - * from inputColorIsUsed(), inputColorToEffectiveProcessor(), removeVertexAttribs(), and - * readsDst() must be used when setting up the draw to ensure correct drawing. - */ - int firstEffectiveProcessorIndex() const { return fFirstEffectiveProcessorIndex; } - - /** - * True if the first effective processor reads its input, false otherwise. - */ - bool inputColorIsUsed() const { return fInputColorIsUsed; } - - /** - * If input color is used and per-vertex colors are not used, this is the input color to the - * first effective processor. - */ - GrColor inputColorToFirstEffectiveProccesor() const { return fInputColor; } - -private: - void internalCalc(const GrFragmentProcessor* const[], int cnt); - - GrInvariantOutput fInOut; - int fFirstEffectiveProcessorIndex; - bool fInputColorIsUsed; - GrColor fInputColor; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/GrProcessor.cpp b/gfx/skia/skia/src/gpu/GrProcessor.cpp index 5ca993596920..7c1052886d8b 100644 --- a/gfx/skia/skia/src/gpu/GrProcessor.cpp +++ b/gfx/skia/skia/src/gpu/GrProcessor.cpp @@ -8,13 +8,24 @@ #include "GrProcessor.h" #include "GrContext.h" #include "GrGeometryProcessor.h" -#include "GrInvariantOutput.h" #include "GrMemoryPool.h" +#include "GrSamplerParams.h" +#include "GrTexturePriv.h" +#include "GrTextureProxy.h" #include "GrXferProcessor.h" #include "SkSpinlock.h" -#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS +#if GR_TEST_UTILS +GrResourceProvider* GrProcessorTestData::resourceProvider() { + return fContext->resourceProvider(); +} + +const GrCaps* GrProcessorTestData::caps() { + return fContext->caps(); +} + +#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS class GrFragmentProcessor; class GrGeometryProcessor; @@ -29,13 +40,6 @@ GrProcessorTestFactory::GetFactories() { return &gFactories; } -template<> -SkTArray*, true>* -GrProcessorTestFactory::GetFactories() { - static SkTArray*, true> gFactories; - return &gFactories; -} - template<> SkTArray*, true>* GrProcessorTestFactory::GetFactories() { @@ -43,6 +47,11 @@ GrProcessorTestFactory::GetFactories() { return &gFactories; } +SkTArray* GrXPFactoryTestFactory::GetFactories() { + static SkTArray gFactories; + return &gFactories; +} + /* * To ensure we always have successful static initialization, before creating from the factories * we verify the count is as expected. If a new factory is added, then these numbers must be @@ -50,11 +59,13 @@ GrProcessorTestFactory::GetFactories() { */ static const int kFPFactoryCount = 41; static const int kGPFactoryCount = 14; -static const int kXPFactoryCount = 6; +static const int kXPFactoryCount = 4; template<> void GrProcessorTestFactory::VerifyFactoryCount() { if (kFPFactoryCount != GetFactories()->count()) { + SkDebugf("\nExpected %d fragment processor factories, found %d.\n", + kFPFactoryCount, GetFactories()->count()); SkFAIL("Wrong number of fragment processor factories!"); } } @@ -62,18 +73,22 @@ void GrProcessorTestFactory::VerifyFactoryCount() { template<> void GrProcessorTestFactory::VerifyFactoryCount() { if (kGPFactoryCount != GetFactories()->count()) { + SkDebugf("\nExpected %d geometry processor factories, found %d.\n", + kGPFactoryCount, GetFactories()->count()); SkFAIL("Wrong number of geometry processor factories!"); } } -template<> -void GrProcessorTestFactory::VerifyFactoryCount() { +void GrXPFactoryTestFactory::VerifyFactoryCount() { if (kXPFactoryCount != GetFactories()->count()) { + SkDebugf("\nExpected %d xp factory factories, found %d.\n", + kXPFactoryCount, GetFactories()->count()); SkFAIL("Wrong number of xp factory factories!"); } } #endif +#endif // We use a global pool protected by a mutex(spinlock). Chrome may use the same GrContext on @@ -105,32 +120,70 @@ int32_t GrProcessor::gCurrProcessorClassID = GrProcessor::kIllegalProcessorClass /////////////////////////////////////////////////////////////////////////////// -GrProcessor::~GrProcessor() {} - -void GrProcessor::addTextureAccess(const GrTextureAccess* access) { - fTextureAccesses.push_back(access); - this->addGpuResource(access->getProgramTexture()); -} - -void GrProcessor::addBufferAccess(const GrBufferAccess* access) { - fBufferAccesses.push_back(access); - this->addGpuResource(access->getProgramBuffer()); -} - -void* GrProcessor::operator new(size_t size) { - return MemoryPoolAccessor().pool()->allocate(size); -} +void* GrProcessor::operator new(size_t size) { return MemoryPoolAccessor().pool()->allocate(size); } void GrProcessor::operator delete(void* target) { return MemoryPoolAccessor().pool()->release(target); } -bool GrProcessor::hasSameSamplers(const GrProcessor& that) const { - if (this->numTextures() != that.numTextures() || this->numBuffers() != that.numBuffers()) { +/////////////////////////////////////////////////////////////////////////////// + +void GrResourceIOProcessor::addTextureSampler(const TextureSampler* access) { + fTextureSamplers.push_back(access); +} + +void GrResourceIOProcessor::addBufferAccess(const BufferAccess* access) { + fBufferAccesses.push_back(access); +} + +void GrResourceIOProcessor::addImageStorageAccess(const ImageStorageAccess* access) { + fImageStorageAccesses.push_back(access); +} + +void GrResourceIOProcessor::addPendingIOs() const { + for (const auto& sampler : fTextureSamplers) { + sampler->programTexture()->markPendingIO(); + } + for (const auto& buffer : fBufferAccesses) { + buffer->programBuffer()->markPendingIO(); + } + for (const auto& imageStorage : fImageStorageAccesses) { + imageStorage->programTexture()->markPendingIO(); + } +} + +void GrResourceIOProcessor::removeRefs() const { + for (const auto& sampler : fTextureSamplers) { + sampler->programTexture()->removeRef(); + } + for (const auto& buffer : fBufferAccesses) { + buffer->programBuffer()->removeRef(); + } + for (const auto& imageStorage : fImageStorageAccesses) { + imageStorage->programTexture()->removeRef(); + } +} + +void GrResourceIOProcessor::pendingIOComplete() const { + for (const auto& sampler : fTextureSamplers) { + sampler->programTexture()->pendingIOComplete(); + } + for (const auto& buffer : fBufferAccesses) { + buffer->programBuffer()->pendingIOComplete(); + } + for (const auto& imageStorage : fImageStorageAccesses) { + imageStorage->programTexture()->pendingIOComplete(); + } +} + +bool GrResourceIOProcessor::hasSameSamplersAndAccesses(const GrResourceIOProcessor& that) const { + if (this->numTextureSamplers() != that.numTextureSamplers() || + this->numBuffers() != that.numBuffers() || + this->numImageStorages() != that.numImageStorages()) { return false; } - for (int i = 0; i < this->numTextures(); ++i) { - if (this->textureAccess(i) != that.textureAccess(i)) { + for (int i = 0; i < this->numTextureSamplers(); ++i) { + if (this->textureSampler(i) != that.textureSampler(i)) { return false; } } @@ -139,11 +192,123 @@ bool GrProcessor::hasSameSamplers(const GrProcessor& that) const { return false; } } + for (int i = 0; i < this->numImageStorages(); ++i) { + if (this->imageStorageAccess(i) != that.imageStorageAccess(i)) { + return false; + } + } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////// -// Initial static variable from GrXPFactory -int32_t GrXPFactory::gCurrXPFClassID = - GrXPFactory::kIllegalXPFClassID; +GrResourceIOProcessor::TextureSampler::TextureSampler() {} + +GrResourceIOProcessor::TextureSampler::TextureSampler(GrTexture* texture, + const GrSamplerParams& params) { + this->reset(texture, params); +} + +GrResourceIOProcessor::TextureSampler::TextureSampler(GrTexture* texture, + GrSamplerParams::FilterMode filterMode, + SkShader::TileMode tileXAndY, + GrShaderFlags visibility) { + this->reset(texture, filterMode, tileXAndY, visibility); +} + +GrResourceIOProcessor::TextureSampler::TextureSampler(GrResourceProvider* resourceProvider, + sk_sp proxy, + const GrSamplerParams& params) { + this->reset(resourceProvider, std::move(proxy), params); +} + +GrResourceIOProcessor::TextureSampler::TextureSampler(GrResourceProvider* resourceProvider, + sk_sp proxy, + GrSamplerParams::FilterMode filterMode, + SkShader::TileMode tileXAndY, + GrShaderFlags visibility) { + this->reset(resourceProvider, std::move(proxy), filterMode, tileXAndY, visibility); +} + +void GrResourceIOProcessor::TextureSampler::reset(GrTexture* texture, + const GrSamplerParams& params, + GrShaderFlags visibility) { + SkASSERT(texture); + fTexture.set(SkRef(texture), kRead_GrIOType); + fParams = params; + fParams.setFilterMode(SkTMin(params.filterMode(), texture->texturePriv().highestFilterMode())); + fVisibility = visibility; +} + +void GrResourceIOProcessor::TextureSampler::reset(GrTexture* texture, + GrSamplerParams::FilterMode filterMode, + SkShader::TileMode tileXAndY, + GrShaderFlags visibility) { + SkASSERT(texture); + fTexture.set(SkRef(texture), kRead_GrIOType); + filterMode = SkTMin(filterMode, texture->texturePriv().highestFilterMode()); + fParams.reset(tileXAndY, filterMode); + fVisibility = visibility; +} + +void GrResourceIOProcessor::TextureSampler::reset(GrResourceProvider* resourceProvider, + sk_sp proxy, + const GrSamplerParams& params, + GrShaderFlags visibility) { + // For now, end the deferral at this time. Once all the TextureSamplers are swapped over + // to taking a GrSurfaceProxy just use the IORefs on the proxy + GrTexture* texture = proxy->instantiate(resourceProvider); + SkASSERT(texture); + fTexture.set(SkRef(texture), kRead_GrIOType); + fParams = params; + fParams.setFilterMode(SkTMin(params.filterMode(), texture->texturePriv().highestFilterMode())); + fVisibility = visibility; +} + +void GrResourceIOProcessor::TextureSampler::reset(GrResourceProvider* resourceProvider, + sk_sp proxy, + GrSamplerParams::FilterMode filterMode, + SkShader::TileMode tileXAndY, + GrShaderFlags visibility) { + // For now, end the deferral at this time. Once all the TextureSamplers are swapped over + // to taking a GrSurfaceProxy just use the IORefs on the proxy + GrTexture* texture = proxy->instantiate(resourceProvider); + SkASSERT(texture); + fTexture.set(SkRef(texture), kRead_GrIOType); + filterMode = SkTMin(filterMode, texture->texturePriv().highestFilterMode()); + fParams.reset(tileXAndY, filterMode); + fVisibility = visibility; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +GrResourceIOProcessor::ImageStorageAccess::ImageStorageAccess(sk_sp texture, + GrIOType ioType, + GrSLMemoryModel memoryModel, + GrSLRestrict restrict, + GrShaderFlags visibility) { + SkASSERT(texture); + fTexture.set(texture.release(), ioType); + fMemoryModel = memoryModel; + fRestrict = restrict; + fVisibility = visibility; + // We currently infer this from the config. However, we could allow the client to specify + // a format that is different but compatible with the config. + switch (fTexture.get()->config()) { + case kRGBA_8888_GrPixelConfig: + fFormat = GrImageStorageFormat::kRGBA8; + break; + case kRGBA_8888_sint_GrPixelConfig: + fFormat = GrImageStorageFormat::kRGBA8i; + break; + case kRGBA_half_GrPixelConfig: + fFormat = GrImageStorageFormat::kRGBA16f; + break; + case kRGBA_float_GrPixelConfig: + fFormat = GrImageStorageFormat::kRGBA32f; + break; + default: + SkFAIL("Config is not (yet) supported as image storage."); + break; + } +} diff --git a/gfx/skia/skia/src/gpu/GrProcessorAnalysis.cpp b/gfx/skia/skia/src/gpu/GrProcessorAnalysis.cpp new file mode 100644 index 000000000000..317246d24764 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrProcessorAnalysis.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrProcessorAnalysis.h" +#include "GrGeometryProcessor.h" +#include "ops/GrDrawOp.h" + +void GrColorFragmentProcessorAnalysis::analyzeProcessors( + const GrFragmentProcessor* const* processors, int cnt) { + for (int i = 0; i < cnt; ++i) { + bool knowCurrentOutput = fProcessorsVisitedWithKnownOutput == fTotalProcessorsVisited; + if (fUsesLocalCoords && !knowCurrentOutput && + !fAllProcessorsCompatibleWithCoverageAsAlpha && !fIsOpaque) { + fTotalProcessorsVisited += cnt - i; + return; + } + const GrFragmentProcessor* fp = processors[i]; + if (knowCurrentOutput && + fp->hasConstantOutputForConstantInput(fLastKnownOutputColor, &fLastKnownOutputColor)) { + ++fProcessorsVisitedWithKnownOutput; + fIsOpaque = fLastKnownOutputColor.isOpaque(); + // We reset these since the caller is expected to not use the earlier fragment + // processors. + fAllProcessorsCompatibleWithCoverageAsAlpha = true; + fUsesLocalCoords = false; + } else if (fIsOpaque && !fp->preservesOpaqueInput()) { + fIsOpaque = false; + } + if (fAllProcessorsCompatibleWithCoverageAsAlpha && !fp->compatibleWithCoverageAsAlpha()) { + fAllProcessorsCompatibleWithCoverageAsAlpha = false; + } + if (fp->usesLocalCoords()) { + fUsesLocalCoords = true; + } + ++fTotalProcessorsVisited; + } +} diff --git a/gfx/skia/skia/src/gpu/GrProcessorAnalysis.h b/gfx/skia/skia/src/gpu/GrProcessorAnalysis.h new file mode 100644 index 000000000000..ad56ab4e2d99 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrProcessorAnalysis.h @@ -0,0 +1,172 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrProcessorAnalysis_DEFINED +#define GrProcessorAnalysis_DEFINED + +#include "GrColor.h" + +class GrDrawOp; +class GrFragmentProcessor; +class GrPrimitiveProcessor; + +class GrProcessorAnalysisColor { +public: + enum class Opaque { + kNo, + kYes, + }; + + GrProcessorAnalysisColor(Opaque opaque = Opaque::kNo) + : fFlags(opaque == Opaque::kYes ? kIsOpaque_Flag : 0) {} + + GrProcessorAnalysisColor(GrColor color) { this->setToConstant(color); } + + void setToConstant(GrColor color) { + fColor = color; + if (GrColorIsOpaque(color)) { + fFlags = kColorIsKnown_Flag | kIsOpaque_Flag; + } else { + fFlags = kColorIsKnown_Flag; + } + } + + void setToUnknown() { fFlags = 0; } + + void setToUnknownOpaque() { fFlags = kIsOpaque_Flag; } + + bool isOpaque() const { return SkToBool(kIsOpaque_Flag & fFlags); } + + bool isConstant(GrColor* color = nullptr) const { + if (kColorIsKnown_Flag & fFlags) { + if (color) { + *color = fColor; + } + return true; + } + return false; + } + + bool operator==(const GrProcessorAnalysisColor& that) const { + if (fFlags != that.fFlags) { + return false; + } + return (kColorIsKnown_Flag & fFlags) ? fColor == that.fColor : true; + } + + /** The returned value reflects the common properties of the two inputs. */ + static GrProcessorAnalysisColor Combine(const GrProcessorAnalysisColor& a, + const GrProcessorAnalysisColor& b) { + GrProcessorAnalysisColor result; + uint32_t commonFlags = a.fFlags & b.fFlags; + if ((kColorIsKnown_Flag & commonFlags) && a.fColor == b.fColor) { + result.fColor = a.fColor; + result.fFlags = a.fFlags; + } else if (kIsOpaque_Flag & commonFlags) { + result.fFlags = kIsOpaque_Flag; + } + return result; + } + +private: + enum Flags { + kColorIsKnown_Flag = 0x1, + kIsOpaque_Flag = 0x2, + }; + uint32_t fFlags; + GrColor fColor; +}; + +enum class GrProcessorAnalysisCoverage { kNone, kSingleChannel, kLCD }; + +/** + * GrColorFragmentProcessorAnalysis gathers invariant data from a set of color fragment processor. + * It is used to recognize optimizations that can simplify the generated shader or make blending + * more effecient. + */ +class GrColorFragmentProcessorAnalysis { +public: + GrColorFragmentProcessorAnalysis() = default; + + GrColorFragmentProcessorAnalysis(const GrProcessorAnalysisColor& input) + : GrColorFragmentProcessorAnalysis() { + fAllProcessorsCompatibleWithCoverageAsAlpha = true; + fIsOpaque = input.isOpaque(); + GrColor color; + if (input.isConstant(&color)) { + fLastKnownOutputColor = GrColor4f::FromGrColor(color); + fProcessorsVisitedWithKnownOutput = 0; + } + } + + void reset(const GrProcessorAnalysisColor& input) { + *this = GrColorFragmentProcessorAnalysis(input); + } + + /** + * Runs through a series of processors and updates calculated values. This can be called + * repeatedly for cases when the sequence of processors is not in a contiguous array. + */ + void analyzeProcessors(const GrFragmentProcessor* const* processors, int cnt); + + bool isOpaque() const { return fIsOpaque; } + + /** + * Are all the fragment processors compatible with conflating coverage with color prior to the + * the first fragment processor. This result does not consider processors that should be + * eliminated as indicated by initialProcessorsToEliminate(). + */ + bool allProcessorsCompatibleWithCoverageAsAlpha() const { + return fAllProcessorsCompatibleWithCoverageAsAlpha; + } + + /** + * Do any of the fragment processors require local coords. This result does not consider + * processors that should be eliminated as indicated by initialProcessorsToEliminate(). + */ + bool usesLocalCoords() const { return fUsesLocalCoords; } + + /** + * If we detected that the result after the first N processors is a known color then we + * eliminate those N processors and replace the GrDrawOp's color input to the GrPipeline with + * the known output of the Nth processor, so that the Nth+1 fragment processor (or the XP if + * there are only N processors) sees its expected input. If this returns 0 then there are no + * processors to eliminate. + */ + int initialProcessorsToEliminate(GrColor* newPipelineInputColor) const { + if (fProcessorsVisitedWithKnownOutput > 0) { + *newPipelineInputColor = fLastKnownOutputColor.toGrColor(); + } + return SkTMax(0, fProcessorsVisitedWithKnownOutput); + } + + int initialProcessorsToEliminate(GrColor4f* newPipelineInputColor) const { + if (fProcessorsVisitedWithKnownOutput > 0) { + *newPipelineInputColor = fLastKnownOutputColor; + } + return SkTMax(0, fProcessorsVisitedWithKnownOutput); + } + + GrProcessorAnalysisColor outputColor() const { + if (fProcessorsVisitedWithKnownOutput != fTotalProcessorsVisited) { + return GrProcessorAnalysisColor(fIsOpaque ? GrProcessorAnalysisColor::Opaque::kYes + : GrProcessorAnalysisColor::Opaque::kNo); + } + return GrProcessorAnalysisColor(fLastKnownOutputColor.toGrColor()); + } + +private: + int fTotalProcessorsVisited = 0; + // negative one means even the color is unknown before adding the first processor. + int fProcessorsVisitedWithKnownOutput = -1; + bool fIsOpaque = false; + bool fAllProcessorsCompatibleWithCoverageAsAlpha = true; + bool fUsesLocalCoords = false; + GrColor4f fLastKnownOutputColor; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrProcessorSet.cpp b/gfx/skia/skia/src/gpu/GrProcessorSet.cpp new file mode 100644 index 000000000000..a76a10b8f9f3 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrProcessorSet.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrProcessorSet.h" +#include "GrAppliedClip.h" +#include "GrCaps.h" +#include "GrXferProcessor.h" +#include "effects/GrPorterDuffXferProcessor.h" + +GrProcessorSet::GrProcessorSet(GrPaint&& paint) : fXP(paint.getXPFactory()) { + fFlags = 0; + if (paint.numColorFragmentProcessors() <= kMaxColorProcessors) { + fColorFragmentProcessorCnt = paint.numColorFragmentProcessors(); + fFragmentProcessors.reset(paint.numTotalFragmentProcessors()); + int i = 0; + for (auto& fp : paint.fColorFragmentProcessors) { + fFragmentProcessors[i++] = fp.release(); + } + for (auto& fp : paint.fCoverageFragmentProcessors) { + fFragmentProcessors[i++] = fp.release(); + } + if (paint.usesDistanceVectorField()) { + fFlags |= kUseDistanceVectorField_Flag; + } + } else { + SkDebugf("Insane number of color fragment processors in paint. Dropping all processors."); + fColorFragmentProcessorCnt = 0; + } + if (paint.getDisableOutputConversionToSRGB()) { + fFlags |= kDisableOutputConversionToSRGB_Flag; + } + if (paint.getAllowSRGBInputs()) { + fFlags |= kAllowSRGBInputs_Flag; + } +} + +GrProcessorSet::~GrProcessorSet() { + for (int i = fFragmentProcessorOffset; i < fFragmentProcessors.count(); ++i) { + if (this->isFinalized()) { + fFragmentProcessors[i]->completedExecution(); + } else { + fFragmentProcessors[i]->unref(); + } + } + if (this->isFinalized() && this->xferProcessor()) { + this->xferProcessor()->unref(); + } +} + +bool GrProcessorSet::operator==(const GrProcessorSet& that) const { + SkASSERT(this->isFinalized()); + SkASSERT(that.isFinalized()); + int fpCount = this->numFragmentProcessors(); + if (((fFlags ^ that.fFlags) & ~kFinalized_Flag) || fpCount != that.numFragmentProcessors() || + fColorFragmentProcessorCnt != that.fColorFragmentProcessorCnt) { + return false; + } + + for (int i = 0; i < fpCount; ++i) { + int a = i + fFragmentProcessorOffset; + int b = i + that.fFragmentProcessorOffset; + if (!fFragmentProcessors[a]->isEqual(*that.fFragmentProcessors[b])) { + return false; + } + } + // Most of the time both of these are null + if (!this->xferProcessor() && !that.xferProcessor()) { + return true; + } + const GrXferProcessor& thisXP = this->xferProcessor() + ? *this->xferProcessor() + : GrPorterDuffXPFactory::SimpleSrcOverXP(); + const GrXferProcessor& thatXP = that.xferProcessor() + ? *that.xferProcessor() + : GrPorterDuffXPFactory::SimpleSrcOverXP(); + return thisXP.isEqual(thatXP); +} + +GrProcessorSet::Analysis GrProcessorSet::finalize(const GrProcessorAnalysisColor& colorInput, + const GrProcessorAnalysisCoverage coverageInput, + const GrAppliedClip* clip, bool isMixedSamples, + const GrCaps& caps, GrColor* overrideInputColor) { + SkASSERT(!this->isFinalized()); + SkASSERT(!fFragmentProcessorOffset); + + GrProcessorSet::Analysis analysis; + + const GrFragmentProcessor* clipFP = clip ? clip->clipCoverageFragmentProcessor() : nullptr; + GrColorFragmentProcessorAnalysis colorAnalysis(colorInput); + analysis.fCompatibleWithCoverageAsAlpha = GrProcessorAnalysisCoverage::kLCD != coverageInput; + + const GrFragmentProcessor* const* fps = fFragmentProcessors.get() + fFragmentProcessorOffset; + colorAnalysis.analyzeProcessors(fps, fColorFragmentProcessorCnt); + analysis.fCompatibleWithCoverageAsAlpha &= + colorAnalysis.allProcessorsCompatibleWithCoverageAsAlpha(); + fps += fColorFragmentProcessorCnt; + int n = this->numCoverageFragmentProcessors(); + bool hasCoverageFP = n > 0; + bool coverageUsesLocalCoords = false; + for (int i = 0; i < n; ++i) { + if (!fps[i]->compatibleWithCoverageAsAlpha()) { + analysis.fCompatibleWithCoverageAsAlpha = false; + // Other than tests that exercise atypical behavior we expect all coverage FPs to be + // compatible with the coverage-as-alpha optimization. + GrCapsDebugf(&caps, "Coverage FP is not compatible with coverage as alpha.\n"); + } + coverageUsesLocalCoords |= fps[i]->usesLocalCoords(); + } + + if (clipFP) { + analysis.fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha(); + coverageUsesLocalCoords |= clipFP->usesLocalCoords(); + hasCoverageFP = true; + } + int colorFPsToEliminate = colorAnalysis.initialProcessorsToEliminate(overrideInputColor); + analysis.fInputColorType = static_cast( + colorFPsToEliminate ? Analysis::kOverridden_InputColorType + : Analysis::kOriginal_InputColorType); + + GrProcessorAnalysisCoverage outputCoverage; + if (GrProcessorAnalysisCoverage::kLCD == coverageInput) { + outputCoverage = GrProcessorAnalysisCoverage::kLCD; + } else if (hasCoverageFP || GrProcessorAnalysisCoverage::kSingleChannel == coverageInput) { + outputCoverage = GrProcessorAnalysisCoverage::kSingleChannel; + } else { + outputCoverage = GrProcessorAnalysisCoverage::kNone; + } + + GrXPFactory::AnalysisProperties props = GrXPFactory::GetAnalysisProperties( + this->xpFactory(), colorAnalysis.outputColor(), outputCoverage, caps); + if (!this->numCoverageFragmentProcessors() && + GrProcessorAnalysisCoverage::kNone == coverageInput) { + analysis.fCanCombineOverlappedStencilAndCover = SkToBool( + props & GrXPFactory::AnalysisProperties::kCanCombineOverlappedStencilAndCover); + } else { + // If we have non-clipping coverage processors we don't try to merge stencil steps as its + // unclear whether it will be correct. We don't expect this to happen in practice. + analysis.fCanCombineOverlappedStencilAndCover = false; + } + analysis.fRequiresDstTexture = + SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresDstTexture); + analysis.fCompatibleWithCoverageAsAlpha &= + SkToBool(props & GrXPFactory::AnalysisProperties::kCompatibleWithAlphaAsCoverage); + analysis.fRequiresBarrierBetweenOverlappingDraws = SkToBool( + props & GrXPFactory::AnalysisProperties::kRequiresBarrierBetweenOverlappingDraws); + if (props & GrXPFactory::AnalysisProperties::kIgnoresInputColor) { + colorFPsToEliminate = this->numColorFragmentProcessors(); + analysis.fInputColorType = + static_cast(Analysis::kIgnored_InputColorType); + analysis.fUsesLocalCoords = coverageUsesLocalCoords; + } else { + analysis.fUsesLocalCoords = coverageUsesLocalCoords | colorAnalysis.usesLocalCoords(); + } + for (int i = 0; i < colorFPsToEliminate; ++i) { + fFragmentProcessors[i]->unref(); + fFragmentProcessors[i] = nullptr; + } + for (int i = colorFPsToEliminate; i < fFragmentProcessors.count(); ++i) { + fFragmentProcessors[i]->addPendingExecution(); + fFragmentProcessors[i]->unref(); + } + fFragmentProcessorOffset = colorFPsToEliminate; + fColorFragmentProcessorCnt -= colorFPsToEliminate; + + auto xp = GrXPFactory::MakeXferProcessor(this->xpFactory(), colorAnalysis.outputColor(), + outputCoverage, isMixedSamples, caps); + fXP.fProcessor = xp.release(); + + fFlags |= kFinalized_Flag; + analysis.fIsInitialized = true; + return analysis; +} diff --git a/gfx/skia/skia/src/gpu/GrProcessorSet.h b/gfx/skia/skia/src/gpu/GrProcessorSet.h new file mode 100644 index 000000000000..a632aa6cb99e --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrProcessorSet.h @@ -0,0 +1,158 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrProcessorSet_DEFINED +#define GrProcessorSet_DEFINED + +#include "GrFragmentProcessor.h" +#include "GrPaint.h" +#include "GrProcessorAnalysis.h" +#include "SkTemplates.h" + +class GrAppliedClip; +class GrXferProcessor; +class GrXPFactory; + +class GrProcessorSet : private SkNoncopyable { +public: + GrProcessorSet(GrPaint&& paint); + + ~GrProcessorSet(); + + int numColorFragmentProcessors() const { return fColorFragmentProcessorCnt; } + int numCoverageFragmentProcessors() const { + return this->numFragmentProcessors() - fColorFragmentProcessorCnt; + } + int numFragmentProcessors() const { + return fFragmentProcessors.count() - fFragmentProcessorOffset; + } + + const GrFragmentProcessor* colorFragmentProcessor(int idx) const { + SkASSERT(idx < fColorFragmentProcessorCnt); + return fFragmentProcessors[idx + fFragmentProcessorOffset]; + } + const GrFragmentProcessor* coverageFragmentProcessor(int idx) const { + return fFragmentProcessors[idx + fColorFragmentProcessorCnt + fFragmentProcessorOffset]; + } + + const GrXferProcessor* xferProcessor() const { + SkASSERT(this->isFinalized()); + return fXP.fProcessor; + } + sk_sp refXferProcessor() const { + SkASSERT(this->isFinalized()); + return sk_ref_sp(fXP.fProcessor); + } + + bool usesDistanceVectorField() const { return SkToBool(fFlags & kUseDistanceVectorField_Flag); } + bool disableOutputConversionToSRGB() const { + return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag); + } + bool allowSRGBInputs() const { return SkToBool(fFlags & kAllowSRGBInputs_Flag); } + + /** Comparisons are only legal on finalized processor sets. */ + bool operator==(const GrProcessorSet& that) const; + bool operator!=(const GrProcessorSet& that) const { return !(*this == that); } + + /** + * This is used to report results of processor analysis when a processor set is finalized (see + * below). + */ + class Analysis { + public: + Analysis(const Analysis&) = default; + Analysis() { *reinterpret_cast(this) = 0; } + + bool isInitialized() const { return fIsInitialized; } + bool usesLocalCoords() const { return fUsesLocalCoords; } + bool requiresDstTexture() const { return fRequiresDstTexture; } + bool canCombineOverlappedStencilAndCover() const { + return fCanCombineOverlappedStencilAndCover; + } + bool requiresBarrierBetweenOverlappingDraws() const { + return fRequiresBarrierBetweenOverlappingDraws; + } + bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; } + + bool inputColorIsIgnored() const { return fInputColorType == kIgnored_InputColorType; } + bool inputColorIsOverridden() const { + return fInputColorType == kOverridden_InputColorType; + } + + private: + enum InputColorType : uint32_t { + kOriginal_InputColorType, + kOverridden_InputColorType, + kIgnored_InputColorType + }; + + // MSVS 2015 won't pack different underlying types + using PackedBool = uint32_t; + using PackedInputColorType = uint32_t; + + PackedBool fUsesLocalCoords : 1; + PackedBool fCompatibleWithCoverageAsAlpha : 1; + PackedBool fRequiresDstTexture : 1; + PackedBool fCanCombineOverlappedStencilAndCover : 1; + PackedBool fRequiresBarrierBetweenOverlappingDraws : 1; + PackedBool fIsInitialized : 1; + PackedInputColorType fInputColorType : 2; + + friend class GrProcessorSet; + }; + GR_STATIC_ASSERT(sizeof(Analysis) <= sizeof(uint32_t)); + + /** + * This analyzes the processors given an op's input color and coverage as well as a clip. The + * state of the processor set may change to an equivalent but more optimal set of processors. + * This new state requires that the caller respect the returned 'inputColorOverride'. This is + * indicated by the returned Analysis's inputColorIsOverriden(). 'inputColorOverride' will not + * be written if the analysis does not override the input color. + * + * This must be called before the processor set is used to construct a GrPipeline and may only + * be called once. + * + * This also puts the processors in "pending execution" state and must be called when an op + * that owns a processor set is recorded to ensure pending and writes are propagated to + * resources referred to by the processors. Otherwise, data hazards may occur. + */ + Analysis finalize(const GrProcessorAnalysisColor& colorInput, + const GrProcessorAnalysisCoverage coverageInput, const GrAppliedClip*, + bool isMixedSamples, const GrCaps&, GrColor* inputColorOverride); + + bool isFinalized() const { return SkToBool(kFinalized_Flag & fFlags); } + +private: + // This absurdly large limit allows Analysis and this to pack fields together. + static constexpr int kMaxColorProcessors = UINT8_MAX; + + enum Flags : uint16_t { + kUseDistanceVectorField_Flag = 0x1, + kDisableOutputConversionToSRGB_Flag = 0x2, + kAllowSRGBInputs_Flag = 0x4, + kFinalized_Flag = 0x8 + }; + + union XP { + XP(const GrXPFactory* factory) : fFactory(factory) {} + const GrXPFactory* fFactory; + const GrXferProcessor* fProcessor; + }; + + const GrXPFactory* xpFactory() const { + SkASSERT(!this->isFinalized()); + return fXP.fFactory; + } + + SkAutoSTArray<4, const GrFragmentProcessor*> fFragmentProcessors; + XP fXP; + uint8_t fColorFragmentProcessorCnt; + uint8_t fFragmentProcessorOffset = 0; + uint8_t fFlags; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrProcessorUnitTest.cpp b/gfx/skia/skia/src/gpu/GrProcessorUnitTest.cpp index 3f43389fe06d..71b112d20f9c 100644 --- a/gfx/skia/skia/src/gpu/GrProcessorUnitTest.cpp +++ b/gfx/skia/skia/src/gpu/GrProcessorUnitTest.cpp @@ -8,6 +8,8 @@ #include "GrProcessorUnitTest.h" #include "GrFragmentProcessor.h" +#if GR_TEST_UTILS + sk_sp GrProcessorUnitTest::MakeChildFP(GrProcessorTestData* data) { #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS sk_sp fp; @@ -21,3 +23,4 @@ sk_sp GrProcessorUnitTest::MakeChildFP(GrProcessorTestData* return nullptr; #endif } +#endif diff --git a/gfx/skia/skia/src/gpu/GrProgramDesc.cpp b/gfx/skia/skia/src/gpu/GrProgramDesc.cpp index cfcdbb59c1de..86c653d647fa 100644 --- a/gfx/skia/skia/src/gpu/GrProgramDesc.cpp +++ b/gfx/skia/skia/src/gpu/GrProgramDesc.cpp @@ -5,56 +5,98 @@ * found in the LICENSE file. */ #include "GrProgramDesc.h" - -#include "GrProcessor.h" #include "GrPipeline.h" +#include "GrPrimitiveProcessor.h" +#include "GrProcessor.h" #include "GrRenderTargetPriv.h" +#include "GrShaderCaps.h" +#include "GrTexturePriv.h" #include "SkChecksum.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLCaps.h" -static uint16_t sampler_key(GrSLType samplerType, GrPixelConfig config, GrShaderFlags visibility, - const GrGLSLCaps& caps) { - enum { - kFirstSamplerType = kTexture2DSampler_GrSLType, - kLastSamplerType = kTextureBufferSampler_GrSLType, - kSamplerTypeKeyBits = 4 - }; - GR_STATIC_ASSERT(kLastSamplerType - kFirstSamplerType < (1 << kSamplerTypeKeyBits)); +enum { + kSamplerOrImageTypeKeyBits = 4 +}; - SkASSERT((int)samplerType >= kFirstSamplerType && (int)samplerType <= kLastSamplerType); - int samplerTypeKey = samplerType - kFirstSamplerType; +static inline uint16_t image_storage_or_sampler_uniform_type_key(GrSLType type ) { + int value = UINT16_MAX; + switch (type) { + case kTexture2DSampler_GrSLType: + value = 0; + break; + case kITexture2DSampler_GrSLType: + value = 1; + break; + case kTextureExternalSampler_GrSLType: + value = 2; + break; + case kTexture2DRectSampler_GrSLType: + value = 3; + break; + case kBufferSampler_GrSLType: + value = 4; + break; + case kImageStorage2D_GrSLType: + value = 5; + break; + case kIImageStorage2D_GrSLType: + value = 6; + break; - return SkToU16(caps.configTextureSwizzle(config).asKey() | - (samplerTypeKey << 8) | - (caps.samplerPrecision(config, visibility) << (8 + kSamplerTypeKeyBits))); + default: + break; + } + SkASSERT((value & ((1 << kSamplerOrImageTypeKeyBits) - 1)) == value); + return value; } -static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrProcessor& proc, - const GrGLSLCaps& caps) { - int numTextures = proc.numTextures(); - int numSamplers = numTextures + proc.numBuffers(); - // Need two bytes per key (swizzle, sampler type, and precision). - int word32Count = (numSamplers + 1) / 2; +static uint16_t sampler_key(GrSLType samplerType, GrPixelConfig config, GrShaderFlags visibility, + const GrShaderCaps& caps) { + int samplerTypeKey = image_storage_or_sampler_uniform_type_key(samplerType); + + GR_STATIC_ASSERT(1 == sizeof(caps.configTextureSwizzle(config).asKey())); + return SkToU16(samplerTypeKey | + caps.configTextureSwizzle(config).asKey() << kSamplerOrImageTypeKeyBits | + (caps.samplerPrecision(config, visibility) << (8 + kSamplerOrImageTypeKeyBits))); +} + +static uint16_t storage_image_key(const GrResourceIOProcessor::ImageStorageAccess& imageAccess) { + GrSLType type = imageAccess.texture()->texturePriv().imageStorageType(); + return image_storage_or_sampler_uniform_type_key(type) | + (int)imageAccess.format() << kSamplerOrImageTypeKeyBits; +} + +static void add_sampler_and_image_keys(GrProcessorKeyBuilder* b, const GrResourceIOProcessor& proc, + const GrShaderCaps& caps) { + int numTextureSamplers = proc.numTextureSamplers(); + int numBuffers = proc.numBuffers(); + int numImageStorages = proc.numImageStorages(); + int numUniforms = numTextureSamplers + numBuffers + numImageStorages; + // Need two bytes per key. + int word32Count = (numUniforms + 1) / 2; if (0 == word32Count) { return; } uint16_t* k16 = SkTCast(b->add32n(word32Count)); - int i = 0; - for (; i < numTextures; ++i) { - const GrTextureAccess& access = proc.textureAccess(i); - const GrTexture* tex = access.getTexture(); - k16[i] = sampler_key(tex->samplerType(), tex->config(), access.getVisibility(), caps); + int j = 0; + for (int i = 0; i < numTextureSamplers; ++i, ++j) { + const GrResourceIOProcessor::TextureSampler& sampler = proc.textureSampler(i); + const GrTexture* tex = sampler.texture(); + k16[j] = sampler_key(tex->texturePriv().samplerType(), tex->config(), sampler.visibility(), + caps); } - for (; i < numSamplers; ++i) { - const GrBufferAccess& access = proc.bufferAccess(i - numTextures); - k16[i] = sampler_key(kTextureBufferSampler_GrSLType, access.texelConfig(), - access.visibility(), caps); + for (int i = 0; i < numBuffers; ++i, ++j) { + const GrResourceIOProcessor::BufferAccess& access = proc.bufferAccess(i); + k16[j] = sampler_key(kBufferSampler_GrSLType, access.texelConfig(), access.visibility(), + caps); } - // zero the last 16 bits if the number of samplers is odd. - if (numSamplers & 0x1) { - k16[numSamplers] = 0; + for (int i = 0; i < numImageStorages; ++i, ++j) { + k16[j] = storage_image_key(proc.imageStorageAccess(i)); + } + // zero the last 16 bits if the number of uniforms for samplers and image storages is odd. + if (numUniforms & 0x1) { + k16[numUniforms] = 0; } } @@ -67,8 +109,8 @@ static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrProcessor& proc, * transforms, etc, for the space allotted in the meta-key. NOTE, both FPs and GPs share this * function because it is hairy, though FPs do not have attribs, and GPs do not have transforms */ -static bool gen_meta_key(const GrProcessor& proc, - const GrGLSLCaps& glslCaps, +static bool gen_meta_key(const GrResourceIOProcessor& proc, + const GrShaderCaps& shaderCaps, uint32_t transformKey, GrProcessorKeyBuilder* b) { size_t processorKeySize = b->size(); @@ -80,7 +122,7 @@ static bool gen_meta_key(const GrProcessor& proc, return false; } - add_sampler_keys(b, proc, glslCaps); + add_sampler_and_image_keys(b, proc, shaderCaps); uint32_t* key = b->add32n(2); key[0] = (classID << 16) | SkToU32(processorKeySize); @@ -88,27 +130,43 @@ static bool gen_meta_key(const GrProcessor& proc, return true; } +static bool gen_meta_key(const GrXferProcessor& xp, + const GrShaderCaps& shaderCaps, + GrProcessorKeyBuilder* b) { + size_t processorKeySize = b->size(); + uint32_t classID = xp.classID(); + + // Currently we allow 16 bits for the class id and the overall processor key size. + static const uint32_t kMetaKeyInvalidMask = ~((uint32_t)SK_MaxU16); + if ((processorKeySize | classID) & kMetaKeyInvalidMask) { + return false; + } + + b->add32((classID << 16) | SkToU32(processorKeySize)); + return true; +} + static bool gen_frag_proc_and_meta_keys(const GrPrimitiveProcessor& primProc, const GrFragmentProcessor& fp, - const GrGLSLCaps& glslCaps, + const GrShaderCaps& shaderCaps, GrProcessorKeyBuilder* b) { for (int i = 0; i < fp.numChildProcessors(); ++i) { - if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), glslCaps, b)) { + if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), shaderCaps, b)) { return false; } } - fp.getGLSLProcessorKey(glslCaps, b); + fp.getGLSLProcessorKey(shaderCaps, b); - return gen_meta_key(fp, glslCaps, primProc.getTransformKey(fp.coordTransforms(), - fp.numCoordTransforms()), b); + return gen_meta_key(fp, shaderCaps, primProc.getTransformKey(fp.coordTransforms(), + fp.numCoordTransforms()), b); } bool GrProgramDesc::Build(GrProgramDesc* desc, const GrPrimitiveProcessor& primProc, bool hasPointSize, const GrPipeline& pipeline, - const GrGLSLCaps& glslCaps) { + const GrShaderCaps& shaderCaps) { // The descriptor is used as a cache key. Thus when a field of the // descriptor will not affect program generation (because of the attribute // bindings in use or other descriptor field settings) it should be set @@ -121,8 +179,8 @@ bool GrProgramDesc::Build(GrProgramDesc* desc, GrProcessorKeyBuilder b(&desc->key()); - primProc.getGLSLProcessorKey(glslCaps, &b); - if (!gen_meta_key(primProc, glslCaps, 0, &b)) { + primProc.getGLSLProcessorKey(shaderCaps, &b); + if (!gen_meta_key(primProc, shaderCaps, 0, &b)) { desc->key().reset(); return false; } @@ -130,7 +188,7 @@ bool GrProgramDesc::Build(GrProgramDesc* desc, for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) { const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i); - if (!gen_frag_proc_and_meta_keys(primProc, fp, glslCaps, &b)) { + if (!gen_frag_proc_and_meta_keys(primProc, fp, shaderCaps, &b)) { desc->key().reset(); return false; } @@ -138,8 +196,14 @@ bool GrProgramDesc::Build(GrProgramDesc* desc, } const GrXferProcessor& xp = pipeline.getXferProcessor(); - xp.getGLSLProcessorKey(glslCaps, &b); - if (!gen_meta_key(xp, glslCaps, 0, &b)) { + const GrSurfaceOrigin* originIfDstTexture = nullptr; + GrSurfaceOrigin origin; + if (pipeline.dstTexture()) { + origin = pipeline.dstTexture()->origin(); + originIfDstTexture = &origin; + } + xp.getGLSLProcessorKey(shaderCaps, &b, originIfDstTexture); + if (!gen_meta_key(xp, shaderCaps, &b)) { desc->key().reset(); return false; } @@ -155,24 +219,15 @@ bool GrProgramDesc::Build(GrProgramDesc* desc, GrRenderTarget* rt = pipeline.getRenderTarget(); - if (requiredFeatures & (GrProcessor::kFragmentPosition_RequiredFeature | - GrProcessor::kSampleLocations_RequiredFeature)) { - header->fSurfaceOriginKey = GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(rt->origin()); - } else { - header->fSurfaceOriginKey = 0; - } - if (requiredFeatures & GrProcessor::kSampleLocations_RequiredFeature) { SkASSERT(pipeline.isHWAntialiasState()); header->fSamplePatternKey = - rt->renderTargetPriv().getMultisampleSpecs(pipeline.getStencil()).fUniqueID; + rt->renderTargetPriv().getMultisampleSpecs(pipeline).fUniqueID; } else { header->fSamplePatternKey = 0; } - header->fOutputSwizzle = glslCaps.configOutputSwizzle(rt->config()).asKey(); - - header->fIgnoresCoverage = pipeline.ignoresCoverage() ? 1 : 0; + header->fOutputSwizzle = shaderCaps.configOutputSwizzle(rt->config()).asKey(); header->fSnapVerticesToPixelCenters = pipeline.snapVerticesToPixelCenters(); header->fColorFragmentProcessorCnt = pipeline.numColorFragmentProcessors(); diff --git a/gfx/skia/skia/src/gpu/GrProgramDesc.h b/gfx/skia/skia/src/gpu/GrProgramDesc.h index f304ec53e14a..a20cdfc56bca 100644 --- a/gfx/skia/skia/src/gpu/GrProgramDesc.h +++ b/gfx/skia/skia/src/gpu/GrProgramDesc.h @@ -12,8 +12,9 @@ #include "GrTypesPriv.h" #include "SkOpts.h" #include "SkTArray.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" -class GrGLSLCaps; +class GrShaderCaps; class GrPipeline; class GrPrimitiveProcessor; @@ -34,14 +35,14 @@ public: * general draw information, as well as the specific color, geometry, * and coverage stages which will be used to generate the GL Program for * this optstate. - * @param GrGLSLCaps Capabilities of the GLSL backend. + * @param GrShaderCaps Capabilities of the shading language. * @param GrProgramDesc The built and finalized descriptor **/ static bool Build(GrProgramDesc*, const GrPrimitiveProcessor&, bool hasPointSize, const GrPipeline&, - const GrGLSLCaps&); + const GrShaderCaps&); // Returns this as a uint32_t array to be used as a key in the program cache. const uint32_t* asKey() const { @@ -80,6 +81,11 @@ public: return !(*this == other); } + void setSurfaceOriginKey(int key) { + KeyHeader* header = this->atOffset(); + header->fSurfaceOriginKey = key; + } + static bool Less(const GrProgramDesc& a, const GrProgramDesc& b) { SkASSERT(SkIsAlign4(a.keyLength())); int l = a.keyLength() >> 2; @@ -103,10 +109,9 @@ public: uint8_t fCoverageFragmentProcessorCnt : 4; // Set to uniquely identify the rt's origin, or 0 if the shader does not require this info. uint8_t fSurfaceOriginKey : 2; - uint8_t fIgnoresCoverage : 1; uint8_t fSnapVerticesToPixelCenters : 1; uint8_t fHasPointSize : 1; - uint8_t fPad : 3; + uint8_t fPad : 4; }; GR_STATIC_ASSERT(sizeof(KeyHeader) == 4); diff --git a/gfx/skia/skia/src/gpu/GrProgramElement.cpp b/gfx/skia/skia/src/gpu/GrProgramElement.cpp deleted file mode 100644 index f1f3f413434a..000000000000 --- a/gfx/skia/skia/src/gpu/GrProgramElement.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrProgramElement.h" -#include "GrGpuResourceRef.h" -#include "SkAtomics.h" - -uint32_t GrProgramElement::CreateUniqueID() { - static int32_t gUniqueID = SK_InvalidUniqueID; - uint32_t id; - do { - id = static_cast(sk_atomic_inc(&gUniqueID) + 1); - } while (id == SK_InvalidUniqueID); - return id; -} - -void GrProgramElement::addPendingIOs() const { - for (int i = 0; i < fGpuResources.count(); ++i) { - fGpuResources[i]->markPendingIO(); - } -} - -void GrProgramElement::removeRefs() const { - for (int i = 0; i < fGpuResources.count(); ++i) { - fGpuResources[i]->removeRef(); - } -} - -void GrProgramElement::pendingIOComplete() const { - for (int i = 0; i < fGpuResources.count(); ++i) { - fGpuResources[i]->pendingIOComplete(); - } -} diff --git a/gfx/skia/skia/src/gpu/GrRectanizer_pow2.h b/gfx/skia/skia/src/gpu/GrRectanizer_pow2.h index 296e0520bf4c..902895e820c8 100644 --- a/gfx/skia/skia/src/gpu/GrRectanizer_pow2.h +++ b/gfx/skia/skia/src/gpu/GrRectanizer_pow2.h @@ -10,6 +10,7 @@ #include "GrRectanizer.h" #include "SkMathPriv.h" +#include "SkMalloc.h" #include "SkPoint.h" // This Rectanizer quantizes the incoming rects to powers of 2. Each power @@ -23,7 +24,7 @@ public: this->reset(); } - virtual ~GrRectanizerPow2() { } + ~GrRectanizerPow2() override {} void reset() override { fNextStripY = 0; diff --git a/gfx/skia/skia/src/gpu/GrReducedClip.cpp b/gfx/skia/skia/src/gpu/GrReducedClip.cpp index 4a912d3b5937..4b7e69bc02ed 100644 --- a/gfx/skia/skia/src/gpu/GrReducedClip.cpp +++ b/gfx/skia/skia/src/gpu/GrReducedClip.cpp @@ -11,13 +11,15 @@ #include "GrClip.h" #include "GrColor.h" #include "GrContextPriv.h" -#include "GrDrawContext.h" -#include "GrDrawContextPriv.h" +#include "GrRenderTargetContext.h" +#include "GrRenderTargetContextPriv.h" #include "GrDrawingManager.h" #include "GrFixedClip.h" #include "GrPathRenderer.h" +#include "GrStencilSettings.h" #include "GrStyle.h" #include "GrUserStencilSettings.h" +#include "SkClipOpPriv.h" typedef SkClipStack::Element Element; @@ -74,7 +76,7 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds fHasIBounds = true; // Implement the clip with an AA rect element. - fElements.addToHead(stackBounds, SkCanvas::kReplace_Op, true/*doAA*/); + fElements.addToHead(stackBounds, kReplace_SkClipOp, true/*doAA*/); fElementsGenID = stack.getTopmostGenID(); fRequiresAA = true; @@ -146,7 +148,7 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound bool isFlip = false; // does this op just flip the in/out state of every point in the bounds switch (element->getOp()) { - case SkCanvas::kDifference_Op: + case kDifference_SkClipOp: // check if the shape subtracted either contains the entire bounds (and makes // the clip empty) or is outside the bounds and therefore can be skipped. if (element->isInverseFilled()) { @@ -172,7 +174,7 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound emsmallens = true; } break; - case SkCanvas::kIntersect_Op: + case kIntersect_SkClipOp: // check if the shape intersected contains the entire bounds and therefore can // be skipped or it is outside the entire bounds and therefore makes the clip // empty. @@ -205,7 +207,7 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound emsmallens = true; } break; - case SkCanvas::kUnion_Op: + case kUnion_SkClipOp: // If the union-ed shape contains the entire bounds then after this element // the bounds is entirely inside the clip. If the union-ed shape is outside the // bounds then this op can be skipped. @@ -228,7 +230,7 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound embiggens = true; } break; - case SkCanvas::kXOR_Op: + case kXOR_SkClipOp: // If the bounds is entirely inside the shape being xor-ed then the effect is // to flip the inside/outside state of every point in the bounds. We may be // able to take advantage of this in the forward pass. If the xor-ed shape @@ -250,7 +252,7 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound emsmallens = embiggens = true; } break; - case SkCanvas::kReverseDifference_Op: + case kReverseDifference_SkClipOp: // When the bounds is entirely within the rev-diff shape then this behaves like xor // and reverses every point inside the bounds. If the shape is completely outside // the bounds then we know after this element is applied that the bounds will be @@ -275,7 +277,7 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound } break; - case SkCanvas::kReplace_Op: + case kReplace_SkClipOp: // Replace will always terminate our walk. We will either begin the forward walk // at the replace op or detect here than the shape is either completely inside // or completely outside the bounds. In this latter case it can be skipped by @@ -325,9 +327,9 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound // if it is a flip, change it to a bounds-filling rect if (isFlip) { - SkASSERT(SkCanvas::kXOR_Op == element->getOp() || - SkCanvas::kReverseDifference_Op == element->getOp()); - fElements.addToHead(SkRect::Make(fIBounds), SkCanvas::kReverseDifference_Op, false); + SkASSERT(kXOR_SkClipOp == element->getOp() || + kReverseDifference_SkClipOp == element->getOp()); + fElements.addToHead(SkRect::Make(fIBounds), kReverseDifference_SkClipOp, false); } else { Element* newElement = fElements.addToHead(*element); if (newElement->isAA()) { @@ -336,11 +338,11 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound // Intersecting an inverse shape is the same as differencing the non-inverse shape. // Replacing with an inverse shape is the same as setting initialState=kAllIn and // differencing the non-inverse shape. - bool isReplace = SkCanvas::kReplace_Op == newElement->getOp(); + bool isReplace = kReplace_SkClipOp == newElement->getOp(); if (newElement->isInverseFilled() && - (SkCanvas::kIntersect_Op == newElement->getOp() || isReplace)) { + (kIntersect_SkClipOp == newElement->getOp() || isReplace)) { newElement->invertShapeFillType(); - newElement->setOp(SkCanvas::kDifference_Op); + newElement->setOp(kDifference_SkClipOp); if (isReplace) { SkASSERT(InitialTriState::kAllOut == initialTriState); initialTriState = InitialTriState::kAllIn; @@ -359,36 +361,36 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound while (element) { bool skippable = false; switch (element->getOp()) { - case SkCanvas::kDifference_Op: + case kDifference_SkClipOp: // subtracting from the empty set yields the empty set. skippable = InitialTriState::kAllOut == initialTriState; break; - case SkCanvas::kIntersect_Op: + case kIntersect_SkClipOp: // intersecting with the empty set yields the empty set if (InitialTriState::kAllOut == initialTriState) { skippable = true; } else { // We can clear to zero and then simply draw the clip element. initialTriState = InitialTriState::kAllOut; - element->setOp(SkCanvas::kReplace_Op); + element->setOp(kReplace_SkClipOp); } break; - case SkCanvas::kUnion_Op: + case kUnion_SkClipOp: if (InitialTriState::kAllIn == initialTriState) { // unioning the infinite plane with anything is a no-op. skippable = true; } else { // unioning the empty set with a shape is the shape. - element->setOp(SkCanvas::kReplace_Op); + element->setOp(kReplace_SkClipOp); } break; - case SkCanvas::kXOR_Op: + case kXOR_SkClipOp: if (InitialTriState::kAllOut == initialTriState) { // xor could be changed to diff in the kAllIn case, not sure it's a win. - element->setOp(SkCanvas::kReplace_Op); + element->setOp(kReplace_SkClipOp); } break; - case SkCanvas::kReverseDifference_Op: + case kReverseDifference_SkClipOp: if (InitialTriState::kAllIn == initialTriState) { // subtracting the whole plane will yield the empty set. skippable = true; @@ -401,11 +403,11 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound if (skippable) { initialTriState = InitialTriState::kAllIn; } else { - element->setOp(SkCanvas::kReplace_Op); + element->setOp(kReplace_SkClipOp); } } break; - case SkCanvas::kReplace_Op: + case kReplace_SkClipOp: skippable = false; // we would have skipped it in the backwards walk if we // could've. break; @@ -430,12 +432,12 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound fInitialState = static_cast(initialTriState); } -static bool element_is_pure_subtract(SkCanvas::ClipOp op) { - SkASSERT(op >= 0); - return op <= SkCanvas::kIntersect_Op; +static bool element_is_pure_subtract(SkClipOp op) { + SkASSERT(static_cast(op) >= 0); + return static_cast(op) <= static_cast(kIntersect_SkClipOp); - GR_STATIC_ASSERT(0 == SkCanvas::kDifference_Op); - GR_STATIC_ASSERT(1 == SkCanvas::kIntersect_Op); + GR_STATIC_ASSERT(0 == static_cast(kDifference_SkClipOp)); + GR_STATIC_ASSERT(1 == static_cast(kIntersect_SkClipOp)); } void GrReducedClip::addInteriorWindowRectangles(int maxWindowRectangles) { @@ -445,7 +447,7 @@ void GrReducedClip::addInteriorWindowRectangles(int maxWindowRectangles) { ElementList::Iter iter(fElements, ElementList::Iter::kTail_IterStart); for (; iter.get() && element_is_pure_subtract(iter.get()->getOp()); iter.prev()) { const Element* element = iter.get(); - if (SkCanvas::kDifference_Op != element->getOp()) { + if (kDifference_SkClipOp != element->getOp()) { continue; } @@ -523,23 +525,21 @@ inline bool GrReducedClip::intersectIBounds(const SkIRect& irect) { //////////////////////////////////////////////////////////////////////////////// // Create a 8-bit clip mask in alpha -static bool stencil_element(GrDrawContext* dc, +static bool stencil_element(GrRenderTargetContext* rtc, const GrFixedClip& clip, const GrUserStencilSettings* ss, const SkMatrix& viewMatrix, const SkClipStack::Element* element) { - - // TODO: Draw rrects directly here. + GrAA aa = GrBoolToAA(element->isAA()); switch (element->getType()) { case Element::kEmpty_Type: SkDEBUGFAIL("Should never get here with an empty element."); break; case Element::kRect_Type: - return dc->drawContextPriv().drawAndStencilRect(clip, ss, - (SkRegion::Op)element->getOp(), - element->isInverseFilled(), - element->isAA(), - viewMatrix, element->getRect()); + return rtc->priv().drawAndStencilRect(clip, ss, + (SkRegion::Op)element->getOp(), + element->isInverseFilled(), aa, viewMatrix, + element->getRect()); break; default: { SkPath path; @@ -548,10 +548,8 @@ static bool stencil_element(GrDrawContext* dc, path.toggleInverseFillType(); } - return dc->drawContextPriv().drawAndStencilPath(clip, ss, - (SkRegion::Op)element->getOp(), - element->isInverseFilled(), - element->isAA(), viewMatrix, path); + return rtc->priv().drawAndStencilPath(clip, ss, (SkRegion::Op)element->getOp(), + element->isInverseFilled(), aa, viewMatrix, path); break; } } @@ -559,19 +557,19 @@ static bool stencil_element(GrDrawContext* dc, return false; } -static void draw_element(GrDrawContext* dc, - const GrClip& clip, // TODO: can this just always be WideOpen? - const GrPaint &paint, +static void draw_element(GrRenderTargetContext* rtc, + const GrClip& clip, // TODO: can this just always be WideOpen? + GrPaint&& paint, + GrAA aa, const SkMatrix& viewMatrix, const SkClipStack::Element* element) { - // TODO: Draw rrects directly here. switch (element->getType()) { case Element::kEmpty_Type: SkDEBUGFAIL("Should never get here with an empty element."); break; case Element::kRect_Type: - dc->drawRect(clip, paint, viewMatrix, element->getRect()); + rtc->drawRect(clip, std::move(paint), aa, viewMatrix, element->getRect()); break; default: { SkPath path; @@ -580,26 +578,26 @@ static void draw_element(GrDrawContext* dc, path.toggleInverseFillType(); } - dc->drawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill()); + rtc->drawPath(clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill()); break; } } } -bool GrReducedClip::drawAlphaClipMask(GrDrawContext* dc) const { +bool GrReducedClip::drawAlphaClipMask(GrRenderTargetContext* rtc) const { // The texture may be larger than necessary, this rect represents the part of the texture // we populate with a rasterization of the clip. GrFixedClip clip(SkIRect::MakeWH(fIBounds.width(), fIBounds.height())); if (!fWindowRects.empty()) { - clip.setWindowRectangles(fWindowRects, {fIBounds.left(), fIBounds.top()}, + clip.setWindowRectangles(fWindowRects.makeOffset(-fIBounds.left(), -fIBounds.top()), GrWindowRectsState::Mode::kExclusive); } // The scratch texture that we are drawing into can be substantially larger than the mask. Only // clear the part that we care about. GrColor initialCoverage = InitialState::kAllIn == this->initialState() ? -1 : 0; - dc->drawContextPriv().clear(clip, initialCoverage, true); + rtc->priv().clear(clip, initialCoverage, true); // Set the matrix so that rendered clip elements are transformed to mask space from clip space. SkMatrix translate; @@ -609,6 +607,7 @@ bool GrReducedClip::drawAlphaClipMask(GrDrawContext* dc) const { for (ElementList::Iter iter(fElements); iter.get(); iter.next()) { const Element* element = iter.get(); SkRegion::Op op = (SkRegion::Op)element->getOp(); + GrAA aa = GrBoolToAA(element->isAA()); bool invert = element->isInverseFilled(); if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { // draw directly into the result with the stencil set to make the pixels affected @@ -622,7 +621,7 @@ bool GrReducedClip::drawAlphaClipMask(GrDrawContext* dc) const { GrUserStencilOp::kReplace, 0xffff>() ); - if (!stencil_element(dc, clip, &kStencilInElement, translate, element)) { + if (!stencil_element(rtc, clip, &kStencilInElement, translate, element)) { return false; } @@ -636,19 +635,16 @@ bool GrReducedClip::drawAlphaClipMask(GrDrawContext* dc) const { GrUserStencilOp::kZero, 0xffff>() ); - if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideElement, - op, !invert, false, - translate, - SkRect::Make(fIBounds))) { + if (!rtc->priv().drawAndStencilRect(clip, &kDrawOutsideElement, op, !invert, GrAA::kNo, + translate, SkRect::Make(fIBounds))) { return false; } } else { // all the remaining ops can just be directly draw into the accumulation buffer GrPaint paint; - paint.setAntiAlias(element->isAA()); paint.setCoverageSetOpXPFactory(op, false); - draw_element(dc, clip, paint, translate, element); + draw_element(rtc, clip, std::move(paint), aa, translate, element); } } @@ -663,9 +659,8 @@ public: StencilClip(const SkIRect& scissorRect) : fFixedClip(scissorRect) {} const GrFixedClip& fixedClip() const { return fFixedClip; } - void setWindowRectangles(const GrWindowRectangles& windows, const SkIPoint& origin, - GrWindowRectsState::Mode mode) { - fFixedClip.setWindowRectangles(windows, origin, mode); + void setWindowRectangles(const GrWindowRectangles& windows, GrWindowRectsState::Mode mode) { + fFixedClip.setWindowRectangles(windows, mode); } private: @@ -675,12 +670,13 @@ private: void getConservativeBounds(int width, int height, SkIRect* bounds, bool* iior) const override { fFixedClip.getConservativeBounds(width, height, bounds, iior); } - bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const override { + bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const override { return false; } - bool apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA, - bool hasUserStencilSettings, GrAppliedClip* out) const override { - if (!fFixedClip.apply(context, drawContext, useHWAA, hasUserStencilSettings, out)) { + bool apply(GrContext* context, GrRenderTargetContext* renderTargetContext, bool useHWAA, + bool hasUserStencilSettings, GrAppliedClip* out, SkRect* bounds) const override { + if (!fFixedClip.apply(context, renderTargetContext, useHWAA, hasUserStencilSettings, out, + bounds)) { return false; } out->addStencilClip(); @@ -693,28 +689,24 @@ private: }; bool GrReducedClip::drawStencilClipMask(GrContext* context, - GrDrawContext* drawContext, - const SkIPoint& clipOrigin) const { + GrRenderTargetContext* renderTargetContext) const { // We set the current clip to the bounds so that our recursive draws are scissored to them. - StencilClip stencilClip(fIBounds.makeOffset(-clipOrigin.x(), -clipOrigin.y())); + StencilClip stencilClip(fIBounds); if (!fWindowRects.empty()) { - stencilClip.setWindowRectangles(fWindowRects, clipOrigin, - GrWindowRectsState::Mode::kExclusive); + stencilClip.setWindowRectangles(fWindowRects, GrWindowRectsState::Mode::kExclusive); } bool initialState = InitialState::kAllIn == this->initialState(); - drawContext->drawContextPriv().clearStencilClip(stencilClip.fixedClip(), initialState); + renderTargetContext->priv().clearStencilClip(stencilClip.fixedClip(), initialState); - // Set the matrix so that rendered clip elements are transformed from clip to stencil space. - SkMatrix viewMatrix; - viewMatrix.setTranslate(SkIntToScalar(-clipOrigin.x()), SkIntToScalar(-clipOrigin.y())); - - // walk through each clip element and perform its set op - // with the existing clip. + // walk through each clip element and perform its set op with the existing clip. for (ElementList::Iter iter(fElements); iter.get(); iter.next()) { const Element* element = iter.get(); - bool useHWAA = element->isAA() && drawContext->isStencilBufferMultisampled(); + GrAAType aaType = GrAAType::kNone; + if (element->isAA() && renderTargetContext->isStencilBufferMultisampled()) { + aaType = GrAAType::kMSAA; + } bool fillInverted = false; @@ -739,15 +731,13 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context, GrShape shape(clipPath, GrStyle::SimpleFill()); GrPathRenderer::CanDrawPathArgs canDrawArgs; canDrawArgs.fShaderCaps = context->caps()->shaderCaps(); - canDrawArgs.fViewMatrix = &viewMatrix; + canDrawArgs.fViewMatrix = &SkMatrix::I(); canDrawArgs.fShape = &shape; - canDrawArgs.fAntiAlias = false; + canDrawArgs.fAAType = aaType; canDrawArgs.fHasUserStencilSettings = false; - canDrawArgs.fIsStencilBufferMSAA = drawContext->isStencilBufferMultisampled(); GrDrawingManager* dm = context->contextPriv().drawingManager(); - pr = dm->getPathRenderer(canDrawArgs, false, - GrPathRendererChain::kStencilOnly_DrawType, + pr = dm->getPathRenderer(canDrawArgs, false, GrPathRendererChain::DrawType::kStencil, &stencilSupport); if (!pr) { return false; @@ -776,35 +766,32 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context, 0xffff>() ); if (Element::kRect_Type == element->getType()) { - drawContext->drawContextPriv().stencilRect(stencilClip.fixedClip(), - &kDrawToStencil, useHWAA, - viewMatrix, element->getRect()); + renderTargetContext->priv().stencilRect(stencilClip.fixedClip(), &kDrawToStencil, + aaType, SkMatrix::I(), element->getRect()); } else { if (!clipPath.isEmpty()) { GrShape shape(clipPath, GrStyle::SimpleFill()); if (canRenderDirectToStencil) { GrPaint paint; - paint.setXPFactory(GrDisableColorXPFactory::Make()); - paint.setAntiAlias(element->isAA()); + paint.setXPFactory(GrDisableColorXPFactory::Get()); - GrPathRenderer::DrawPathArgs args; - args.fResourceProvider = context->resourceProvider(); - args.fPaint = &paint; - args.fUserStencilSettings = &kDrawToStencil; - args.fDrawContext = drawContext; - args.fClip = &stencilClip.fixedClip(); - args.fViewMatrix = &viewMatrix; - args.fShape = &shape; - args.fAntiAlias = false; - args.fGammaCorrect = false; + GrPathRenderer::DrawPathArgs args{context, + std::move(paint), + &kDrawToStencil, + renderTargetContext, + &stencilClip.fixedClip(), + &SkMatrix::I(), + &shape, + aaType, + false}; pr->drawPath(args); } else { GrPathRenderer::StencilPathArgs args; - args.fResourceProvider = context->resourceProvider(); - args.fDrawContext = drawContext; + args.fContext = context; + args.fRenderTargetContext = renderTargetContext; args.fClip = &stencilClip.fixedClip(); - args.fViewMatrix = &viewMatrix; - args.fIsAA = element->isAA(); + args.fViewMatrix = &SkMatrix::I(); + args.fAAType = aaType; args.fShape = &shape; pr->stencilPath(args); } @@ -817,31 +804,28 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context, for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) { if (drawDirectToClip) { if (Element::kRect_Type == element->getType()) { - drawContext->drawContextPriv().stencilRect(stencilClip, *pass, useHWAA, - viewMatrix, element->getRect()); + renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType, + SkMatrix::I(), element->getRect()); } else { GrShape shape(clipPath, GrStyle::SimpleFill()); GrPaint paint; - paint.setXPFactory(GrDisableColorXPFactory::Make()); - paint.setAntiAlias(element->isAA()); - GrPathRenderer::DrawPathArgs args; - args.fResourceProvider = context->resourceProvider(); - args.fPaint = &paint; - args.fUserStencilSettings = *pass; - args.fDrawContext = drawContext; - args.fClip = &stencilClip; - args.fViewMatrix = &viewMatrix; - args.fShape = &shape; - args.fAntiAlias = false; - args.fGammaCorrect = false; + paint.setXPFactory(GrDisableColorXPFactory::Get()); + GrPathRenderer::DrawPathArgs args{context, + std::move(paint), + *pass, + renderTargetContext, + &stencilClip, + &SkMatrix::I(), + &shape, + aaType, + false}; pr->drawPath(args); } } else { // The view matrix is setup to do clip space -> stencil space translation, so // draw rect in clip space. - drawContext->drawContextPriv().stencilRect(stencilClip, *pass, - false, viewMatrix, - SkRect::Make(fIBounds)); + renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType, SkMatrix::I(), + SkRect::Make(fIBounds)); } } } diff --git a/gfx/skia/skia/src/gpu/GrReducedClip.h b/gfx/skia/skia/src/gpu/GrReducedClip.h index b8413e6df419..6dceb004c256 100644 --- a/gfx/skia/skia/src/gpu/GrReducedClip.h +++ b/gfx/skia/skia/src/gpu/GrReducedClip.h @@ -13,7 +13,7 @@ #include "SkTLList.h" class GrContext; -class GrDrawContext; +class GrRenderTargetContext; /** * This class takes a clip stack and produces a reduced set of elements that are equivalent to @@ -70,8 +70,8 @@ public: InitialState initialState() const { return fInitialState; } - bool drawAlphaClipMask(GrDrawContext*) const; - bool drawStencilClipMask(GrContext*, GrDrawContext*, const SkIPoint& clipOrigin) const; + bool drawAlphaClipMask(GrRenderTargetContext*) const; + bool drawStencilClipMask(GrContext*, GrRenderTargetContext*) const; private: void walkStack(const SkClipStack&, const SkRect& queryBounds, int maxWindowRectangles); diff --git a/gfx/skia/skia/src/gpu/GrRenderTarget.cpp b/gfx/skia/skia/src/gpu/GrRenderTarget.cpp index 2053a166e57b..9ea8596050a5 100644 --- a/gfx/skia/skia/src/gpu/GrRenderTarget.cpp +++ b/gfx/skia/skia/src/gpu/GrRenderTarget.cpp @@ -10,47 +10,24 @@ #include "GrContext.h" #include "GrContextPriv.h" -#include "GrDrawContext.h" -#include "GrDrawTarget.h" +#include "GrRenderTargetContext.h" #include "GrGpu.h" +#include "GrRenderTargetOpList.h" #include "GrRenderTargetPriv.h" #include "GrStencilAttachment.h" +#include "GrStencilSettings.h" GrRenderTarget::GrRenderTarget(GrGpu* gpu, const GrSurfaceDesc& desc, Flags flags, GrStencilAttachment* stencil) : INHERITED(gpu, desc) , fStencilAttachment(stencil) , fMultisampleSpecsID(0) - , fFlags(flags) - , fLastDrawTarget(nullptr) { + , fFlags(flags) { SkASSERT(!(fFlags & Flags::kMixedSampled) || fDesc.fSampleCnt > 0); SkASSERT(!(fFlags & Flags::kWindowRectsSupport) || gpu->caps()->maxWindowRectangles() > 0); fResolveRect.setLargestInverted(); } -GrRenderTarget::~GrRenderTarget() { - if (fLastDrawTarget) { - fLastDrawTarget->clearRT(); - } - SkSafeUnref(fLastDrawTarget); -} - -void GrRenderTarget::discard() { - // go through context so that all necessary flushing occurs - GrContext* context = this->getContext(); - if (!context) { - return; - } - - sk_sp drawContext(context->contextPriv().makeWrappedDrawContext(sk_ref_sp(this), - nullptr)); - if (!drawContext) { - return; - } - - drawContext->discard(); -} - void GrRenderTarget::flagAsNeedingResolve(const SkIRect* rect) { if (kCanResolve_ResolveType == getResolveType()) { if (rect) { @@ -85,30 +62,18 @@ void GrRenderTarget::onAbandon() { SkSafeSetNull(fStencilAttachment); // The contents of this renderTarget are gone/invalid. It isn't useful to point back - // the creating drawTarget. - this->setLastDrawTarget(nullptr); + // the creating opList. + this->setLastOpList(nullptr); INHERITED::onAbandon(); } -void GrRenderTarget::setLastDrawTarget(GrDrawTarget* dt) { - if (fLastDrawTarget) { - // The non-MDB world never closes so we can't check this condition -#ifdef ENABLE_MDB - SkASSERT(fLastDrawTarget->isClosed()); -#endif - fLastDrawTarget->clearRT(); - } - - SkRefCnt_SafeAssign(fLastDrawTarget, dt); -} - /////////////////////////////////////////////////////////////////////////////// bool GrRenderTargetPriv::attachStencilAttachment(GrStencilAttachment* stencil) { if (!stencil && !fRenderTarget->fStencilAttachment) { // No need to do any work since we currently don't have a stencil attachment and - // we're not acctually adding one. + // we're not actually adding one. return true; } fRenderTarget->fStencilAttachment = stencil; @@ -120,15 +85,20 @@ bool GrRenderTargetPriv::attachStencilAttachment(GrStencilAttachment* stencil) { } int GrRenderTargetPriv::numStencilBits() const { - return fRenderTarget->fStencilAttachment ? fRenderTarget->fStencilAttachment->bits() : 0; + SkASSERT(this->getStencilAttachment()); + return this->getStencilAttachment()->bits(); } const GrGpu::MultisampleSpecs& -GrRenderTargetPriv::getMultisampleSpecs(const GrStencilSettings& stencil) const { - return fRenderTarget->getGpu()->getMultisampleSpecs(fRenderTarget, stencil); +GrRenderTargetPriv::getMultisampleSpecs(const GrPipeline& pipeline) const { + SkASSERT(fRenderTarget == pipeline.getRenderTarget()); // TODO: remove RT from pipeline. + GrGpu* gpu = fRenderTarget->getGpu(); + if (auto id = fRenderTarget->fMultisampleSpecsID) { + SkASSERT(gpu->queryMultisampleSpecs(pipeline).fUniqueID == id); + return gpu->getMultisampleSpecs(id); + } + const GrGpu::MultisampleSpecs& specs = gpu->queryMultisampleSpecs(pipeline); + fRenderTarget->fMultisampleSpecsID = specs.fUniqueID; + return specs; } -int GrRenderTargetPriv::maxWindowRectangles() const { - return (this->flags() & Flags::kWindowRectsSupport) ? - fRenderTarget->getGpu()->caps()->maxWindowRectangles() : 0; -} diff --git a/gfx/skia/skia/src/gpu/GrRenderTargetContext.cpp b/gfx/skia/skia/src/gpu/GrRenderTargetContext.cpp new file mode 100644 index 000000000000..be3ad8b29498 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrRenderTargetContext.cpp @@ -0,0 +1,1767 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrRenderTargetContext.h" +#include "GrAppliedClip.h" +#include "GrColor.h" +#include "GrContextPriv.h" +#include "GrDrawingManager.h" +#include "GrFixedClip.h" +#include "GrGpuResourcePriv.h" +#include "GrPathRenderer.h" +#include "GrPipelineBuilder.h" +#include "GrRenderTarget.h" +#include "GrRenderTargetContextPriv.h" +#include "GrRenderTargetPriv.h" +#include "GrResourceProvider.h" +#include "GrStencilAttachment.h" +#include "SkLatticeIter.h" +#include "SkMatrixPriv.h" +#include "SkSurfacePriv.h" +#include "effects/GrRRectEffect.h" +#include "instanced/InstancedRendering.h" +#include "ops/GrClearOp.h" +#include "ops/GrClearStencilClipOp.h" +#include "ops/GrDrawOp.h" +#include "ops/GrDrawAtlasOp.h" +#include "ops/GrDrawVerticesOp.h" +#include "ops/GrLatticeOp.h" +#include "ops/GrOp.h" +#include "ops/GrOvalOpFactory.h" +#include "ops/GrRectOpFactory.h" +#include "ops/GrRegionOp.h" +#include "ops/GrShadowRRectOp.h" +#include "ops/GrStencilPathOp.h" +#include "text/GrAtlasTextContext.h" +#include "text/GrStencilAndCoverTextContext.h" +#include "../private/GrAuditTrail.h" + +#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext()) +#define ASSERT_SINGLE_OWNER \ + SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());) +#define ASSERT_SINGLE_OWNER_PRIV \ + SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());) +#define RETURN_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return; } +#define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->drawingManager()->wasAbandoned()) { return; } +#define RETURN_FALSE_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return false; } +#define RETURN_FALSE_IF_ABANDONED_PRIV if (fRenderTargetContext->drawingManager()->wasAbandoned()) { return false; } +#define RETURN_NULL_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return nullptr; } + +using gr_instanced::InstancedRendering; + +class AutoCheckFlush { +public: + AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) { + SkASSERT(fDrawingManager); + } + ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); } + +private: + GrDrawingManager* fDrawingManager; +}; + +bool GrRenderTargetContext::wasAbandoned() const { + return this->drawingManager()->wasAbandoned(); +} + +// In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress +// GrOpLists to be picked up and added to by renderTargetContexts lower in the call +// stack. When this occurs with a closed GrOpList, a new one will be allocated +// when the renderTargetContext attempts to use it (via getOpList). +GrRenderTargetContext::GrRenderTargetContext(GrContext* context, + GrDrawingManager* drawingMgr, + sk_sp rtp, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps, + GrAuditTrail* auditTrail, + GrSingleOwner* singleOwner) + : GrSurfaceContext(context, drawingMgr, std::move(colorSpace), auditTrail, singleOwner) + , fRenderTargetProxy(std::move(rtp)) + , fOpList(SkSafeRef(fRenderTargetProxy->getLastRenderTargetOpList())) + , fInstancedPipelineInfo(fRenderTargetProxy.get()) + , fColorXformFromSRGB(nullptr) + , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) { + if (fColorSpace) { + // sRGB sources are very common (SkColor, etc...), so we cache that gamut transformation + auto srgbColorSpace = SkColorSpace::MakeSRGB(); + fColorXformFromSRGB = GrColorSpaceXform::Make(srgbColorSpace.get(), fColorSpace.get()); + } + SkDEBUGCODE(this->validate();) +} + +#ifdef SK_DEBUG +void GrRenderTargetContext::validate() const { + SkASSERT(fRenderTargetProxy); + fRenderTargetProxy->validate(fContext); + + if (fOpList && !fOpList->isClosed()) { + SkASSERT(fRenderTargetProxy->getLastOpList() == fOpList); + } +} +#endif + +GrRenderTargetContext::~GrRenderTargetContext() { + ASSERT_SINGLE_OWNER + SkSafeUnref(fOpList); +} + +GrTextureProxy* GrRenderTargetContext::asTextureProxy() { + return fRenderTargetProxy->asTextureProxy(); +} + +sk_sp GrRenderTargetContext::asTextureProxyRef() { + return sk_ref_sp(fRenderTargetProxy->asTextureProxy()); +} + +GrRenderTargetOpList* GrRenderTargetContext::getOpList() { + ASSERT_SINGLE_OWNER + SkDEBUGCODE(this->validate();) + + if (!fOpList || fOpList->isClosed()) { + fOpList = this->drawingManager()->newOpList(fRenderTargetProxy.get()); + } + + return fOpList; +} + +// TODO: move this (and GrTextContext::copy) to GrSurfaceContext? +bool GrRenderTargetContext::onCopy(GrSurfaceProxy* srcProxy, + const SkIRect& srcRect, + const SkIPoint& dstPoint) { + ASSERT_SINGLE_OWNER + RETURN_FALSE_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::onCopy"); + + return this->getOpList()->copySurface(fContext->resourceProvider(), + fRenderTargetProxy.get(), srcProxy, srcRect, dstPoint); +} + +void GrRenderTargetContext::drawText(const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, const char text[], + size_t byteLength, SkScalar x, SkScalar y, + const SkIRect& clipBounds) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawText"); + + GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext(); + atlasTextContext->drawText(fContext, this, clip, skPaint, viewMatrix, fSurfaceProps, text, + byteLength, x, y, clipBounds); +} + +void GrRenderTargetContext::drawPosText(const GrClip& clip, const SkPaint& paint, + const SkMatrix& viewMatrix, const char text[], + size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset, + const SkIRect& clipBounds) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawPosText"); + + GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext(); + atlasTextContext->drawPosText(fContext, this, clip, paint, viewMatrix, fSurfaceProps, text, + byteLength, pos, scalarsPerPosition, offset, clipBounds); +} + +void GrRenderTargetContext::drawTextBlob(const GrClip& clip, const SkPaint& paint, + const SkMatrix& viewMatrix, const SkTextBlob* blob, + SkScalar x, SkScalar y, SkDrawFilter* filter, + const SkIRect& clipBounds) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawTextBlob"); + + GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext(); + atlasTextContext->drawTextBlob(fContext, this, clip, paint, viewMatrix, fSurfaceProps, blob, x, + y, filter, clipBounds); +} + +void GrRenderTargetContext::discard() { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::discard"); + + AutoCheckFlush acf(this->drawingManager()); + + this->getOpList()->discard(this); +} + +void GrRenderTargetContext::clear(const SkIRect* rect, + const GrColor color, + bool canIgnoreRect) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::clear"); + + AutoCheckFlush acf(this->drawingManager()); + this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color, canIgnoreRect); +} + +void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const GrColor color) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_IF_ABANDONED_PRIV + SkDEBUGCODE(fRenderTargetContext->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail, + "GrRenderTargetContext::absClear"); + + AutoCheckFlush acf(fRenderTargetContext->drawingManager()); + + SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth( + *fRenderTargetContext->caps()), + fRenderTargetContext->fRenderTargetProxy->worstCaseHeight( + *fRenderTargetContext->caps())); + + if (clearRect) { + if (clearRect->contains(rtRect)) { + clearRect = nullptr; // full screen + } else { + if (!rtRect.intersect(*clearRect)) { + return; + } + } + } + + // TODO: in a post-MDB world this should be handled at the OpList level. + // An op-list that is initially cleared and has no other ops should receive an + // extra draw. + if (fRenderTargetContext->fContext->caps()->useDrawInsteadOfClear()) { + // This works around a driver bug with clear by drawing a rect instead. + // The driver will ignore a clear if it is the only thing rendered to a + // target before the target is read. + GrPaint paint; + paint.setColor4f(GrColor4f::FromGrColor(color)); + paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); + + // We don't call drawRect() here to avoid the cropping to the, possibly smaller, + // RenderTargetProxy bounds + fRenderTargetContext->drawNonAAFilledRect(GrNoClip(), std::move(paint), SkMatrix::I(), + SkRect::Make(rtRect), nullptr, nullptr, nullptr, + GrAAType::kNone); + + } else { + // This path doesn't handle coalescing of full screen clears b.c. it + // has to clear the entire render target - not just the content area. + // It could be done but will take more finagling. + std::unique_ptr op(GrClearOp::Make(rtRect, color, fRenderTargetContext, !clearRect)); + if (!op) { + return; + } + fRenderTargetContext->getOpList()->addOp(std::move(op), fRenderTargetContext); + } +} + +void GrRenderTargetContextPriv::clear(const GrFixedClip& clip, + const GrColor color, + bool canIgnoreClip) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_IF_ABANDONED_PRIV + SkDEBUGCODE(fRenderTargetContext->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail, + "GrRenderTargetContextPriv::clear"); + + AutoCheckFlush acf(fRenderTargetContext->drawingManager()); + fRenderTargetContext->internalClear(clip, color, canIgnoreClip); +} + +void GrRenderTargetContext::internalClear(const GrFixedClip& clip, + const GrColor color, + bool canIgnoreClip) { + bool isFull = false; + if (!clip.hasWindowRectangles()) { + isFull = !clip.scissorEnabled() || + (canIgnoreClip && fContext->caps()->fullClearIsFree()) || + clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height())); + } + + if (fContext->caps()->useDrawInsteadOfClear()) { + // This works around a driver bug with clear by drawing a rect instead. + // The driver will ignore a clear if it is the only thing rendered to a + // target before the target is read. + SkIRect clearRect = SkIRect::MakeWH(this->width(), this->height()); + if (isFull) { + this->discard(); + } else if (!clearRect.intersect(clip.scissorRect())) { + return; + } + + GrPaint paint; + paint.setColor4f(GrColor4f::FromGrColor(color)); + paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); + + this->drawRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::Make(clearRect)); + } else if (isFull) { + this->getOpList()->fullClear(this, color); + } else { + std::unique_ptr op(GrClearOp::Make(clip, color, this)); + if (!op) { + return; + } + this->getOpList()->addOp(std::move(op), this); + } +} + +void GrRenderTargetContext::drawPaint(const GrClip& clip, + GrPaint&& paint, + const SkMatrix& viewMatrix) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawPaint"); + + // set rect to be big enough to fill the space, but not super-huge, so we + // don't overflow fixed-point implementations + + SkRect r = fRenderTargetProxy->getBoundsRect(); + + SkRRect rrect; + GrAA aa; + // Check if we can replace a clipRRect()/drawPaint() with a drawRRect(). We only do the + // transformation for non-rect rrects. Rects caused a performance regression on an Android + // test that needs investigation. We also skip cases where there are fragment processors + // because they may depend on having correct local coords and this path draws in device space + // without a local matrix. + if (!paint.numTotalFragmentProcessors() && clip.isRRect(r, &rrect, &aa) && !rrect.isRect()) { + this->drawRRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect, + GrStyle::SimpleFill()); + return; + } + + + bool isPerspective = viewMatrix.hasPerspective(); + + // We attempt to map r by the inverse matrix and draw that. mapRect will + // map the four corners and bound them with a new rect. This will not + // produce a correct result for some perspective matrices. + if (!isPerspective) { + if (!SkMatrixPriv::InverseMapRect(viewMatrix, &r, r)) { + SkDebugf("Could not invert matrix\n"); + return; + } + this->drawRect(clip, std::move(paint), GrAA::kNo, viewMatrix, r); + } else { + SkMatrix localMatrix; + if (!viewMatrix.invert(&localMatrix)) { + SkDebugf("Could not invert matrix\n"); + return; + } + + AutoCheckFlush acf(this->drawingManager()); + + this->drawNonAAFilledRect(clip, std::move(paint), SkMatrix::I(), r, nullptr, &localMatrix, + nullptr, GrAAType::kNone); + } +} + +static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) { + return point.fX >= rect.fLeft && point.fX <= rect.fRight && + point.fY >= rect.fTop && point.fY <= rect.fBottom; +} + +static bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) { + return viewMatrix.preservesRightAngles(); +} + +// Attempts to crop a rect and optional local rect to the clip boundaries. +// Returns false if the draw can be skipped entirely. +static bool crop_filled_rect(int width, int height, const GrClip& clip, + const SkMatrix& viewMatrix, SkRect* rect, + SkRect* localRect = nullptr) { + if (!viewMatrix.rectStaysRect()) { + return true; + } + + SkIRect clipDevBounds; + SkRect clipBounds; + + clip.getConservativeBounds(width, height, &clipDevBounds); + if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) { + return false; + } + + if (localRect) { + if (!rect->intersects(clipBounds)) { + return false; + } + const SkScalar dx = localRect->width() / rect->width(); + const SkScalar dy = localRect->height() / rect->height(); + if (clipBounds.fLeft > rect->fLeft) { + localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx; + rect->fLeft = clipBounds.fLeft; + } + if (clipBounds.fTop > rect->fTop) { + localRect->fTop += (clipBounds.fTop - rect->fTop) * dy; + rect->fTop = clipBounds.fTop; + } + if (clipBounds.fRight < rect->fRight) { + localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx; + rect->fRight = clipBounds.fRight; + } + if (clipBounds.fBottom < rect->fBottom) { + localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy; + rect->fBottom = clipBounds.fBottom; + } + return true; + } + + return rect->intersect(clipBounds); +} + +bool GrRenderTargetContext::drawFilledRect(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRect& rect, + const GrUserStencilSettings* ss) { + SkRect croppedRect = rect; + if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) { + return true; + } + + if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() && + (!ss || ss->isDisabled(false))) { + InstancedRendering* ir = this->getOpList()->instancedRendering(); + std::unique_ptr op = ir->recordRect(croppedRect, viewMatrix, std::move(paint), aa, + fInstancedPipelineInfo); + if (op) { + this->addDrawOp(clip, std::move(op)); + return true; + } + } + GrAAType aaType = this->decideAAType(aa); + if (GrAAType::kCoverage == aaType) { + // The fill path can handle rotation but not skew. + if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) { + SkRect devBoundRect; + viewMatrix.mapRect(&devBoundRect, croppedRect); + std::unique_ptr op = + GrRectOpFactory::MakeAAFill(paint, viewMatrix, rect, croppedRect, devBoundRect); + if (op) { + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); + if (ss) { + pipelineBuilder.setUserStencil(ss); + } + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); + return true; + } + } + } else { + this->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, croppedRect, nullptr, nullptr, + ss, aaType); + return true; + } + + return false; +} + +void GrRenderTargetContext::drawRect(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRect& rect, + const GrStyle* style) { + if (!style) { + style = &GrStyle::SimpleFill(); + } + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawRect"); + + // Path effects should've been devolved to a path in SkGpuDevice + SkASSERT(!style->pathEffect()); + + AutoCheckFlush acf(this->drawingManager()); + + const SkStrokeRec& stroke = style->strokeRec(); + if (stroke.getStyle() == SkStrokeRec::kFill_Style) { + + if (!fContext->caps()->useDrawInsteadOfClear()) { + // Check if this is a full RT draw and can be replaced with a clear. We don't bother + // checking cases where the RT is fully inside a stroke. + SkRect rtRect = fRenderTargetProxy->getBoundsRect(); + // Does the clip contain the entire RT? + if (clip.quickContains(rtRect)) { + SkMatrix invM; + if (!viewMatrix.invert(&invM)) { + return; + } + // Does the rect bound the RT? + SkPoint srcSpaceRTQuad[4]; + invM.mapRectToQuad(srcSpaceRTQuad, rtRect); + if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) && + rect_contains_inclusive(rect, srcSpaceRTQuad[1]) && + rect_contains_inclusive(rect, srcSpaceRTQuad[2]) && + rect_contains_inclusive(rect, srcSpaceRTQuad[3])) { + // Will it blend? + GrColor clearColor; + if (paint.isConstantBlendedColor(&clearColor)) { + this->clear(nullptr, clearColor, true); + return; + } + } + } + } + + if (this->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, nullptr)) { + return; + } + } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style || + stroke.getStyle() == SkStrokeRec::kHairline_Style) { + if ((!rect.width() || !rect.height()) && + SkStrokeRec::kHairline_Style != stroke.getStyle()) { + SkScalar r = stroke.getWidth() / 2; + // TODO: Move these stroke->fill fallbacks to GrShape? + switch (stroke.getJoin()) { + case SkPaint::kMiter_Join: + this->drawRect( + clip, std::move(paint), aa, viewMatrix, + {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r}, + &GrStyle::SimpleFill()); + return; + case SkPaint::kRound_Join: + // Raster draws nothing when both dimensions are empty. + if (rect.width() || rect.height()){ + SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r); + this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, + GrStyle::SimpleFill()); + return; + } + case SkPaint::kBevel_Join: + if (!rect.width()) { + this->drawRect(clip, std::move(paint), aa, viewMatrix, + {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom}, + &GrStyle::SimpleFill()); + } else { + this->drawRect(clip, std::move(paint), aa, viewMatrix, + {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r}, + &GrStyle::SimpleFill()); + } + return; + } + } + + bool snapToPixelCenters = false; + std::unique_ptr op; + + GrColor color = paint.getColor(); + GrAAType aaType = this->decideAAType(aa); + if (GrAAType::kCoverage == aaType) { + // The stroke path needs the rect to remain axis aligned (no rotation or skew). + if (viewMatrix.rectStaysRect()) { + op = GrRectOpFactory::MakeAAStroke(color, viewMatrix, rect, stroke); + } + } else { + // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of + // hairline rects. We jam all the vertices to pixel centers to avoid this, but not + // when MSAA is enabled because it can cause ugly artifacts. + snapToPixelCenters = stroke.getStyle() == SkStrokeRec::kHairline_Style && + !fRenderTargetProxy->isUnifiedMultisampled(); + op = GrRectOpFactory::MakeNonAAStroke(color, viewMatrix, rect, stroke, + snapToPixelCenters); + } + + if (op) { + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); + pipelineBuilder.setSnapVerticesToPixelCenters(snapToPixelCenters); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); + return; + } + } + + SkPath path; + path.setIsVolatile(true); + path.addRect(rect); + this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, *style); +} + +int GrRenderTargetContextPriv::maxWindowRectangles() const { + return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles( + *fRenderTargetContext->fContext->caps()); +} + +void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_IF_ABANDONED_PRIV + SkDEBUGCODE(fRenderTargetContext->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail, + "GrRenderTargetContextPriv::clearStencilClip"); + + AutoCheckFlush acf(fRenderTargetContext->drawingManager()); + + std::unique_ptr op(GrClearStencilClipOp::Make(clip, insideStencilMask, + fRenderTargetContext)); + if (!op) { + return; + } + fRenderTargetContext->getOpList()->addOp(std::move(op), fRenderTargetContext); +} + +void GrRenderTargetContextPriv::stencilPath(const GrClip& clip, + GrAAType aaType, + const SkMatrix& viewMatrix, + const GrPath* path) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_IF_ABANDONED_PRIV + SkDEBUGCODE(fRenderTargetContext->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail, + "GrRenderTargetContext::stencilPath"); + + SkASSERT(aaType != GrAAType::kCoverage); + + bool useHWAA = GrAATypeIsHW(aaType); + // TODO: extract portions of checkDraw that are relevant to path stenciling. + SkASSERT(path); + SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport()); + + // FIXME: Use path bounds instead of this WAR once + // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved. + SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height()); + + // Setup clip + GrAppliedClip appliedClip; + if (!clip.apply(fRenderTargetContext->fContext, fRenderTargetContext, useHWAA, true, + &appliedClip, &bounds)) { + return; + } + + // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never + // attempt this in a situation that would require coverage AA. + SkASSERT(!appliedClip.clipCoverageFragmentProcessor()); + + GrRenderTarget* rt = fRenderTargetContext->accessRenderTarget(); + if (!rt) { + return; + } + GrStencilAttachment* stencilAttachment = + fRenderTargetContext->fContext->resourceProvider()->attachStencilAttachment(rt); + if (!stencilAttachment) { + SkDebugf("ERROR creating stencil attachment. Draw skipped.\n"); + return; + } + + std::unique_ptr op = GrStencilPathOp::Make(viewMatrix, + useHWAA, + path->getFillType(), + appliedClip.hasStencilClip(), + stencilAttachment->bits(), + appliedClip.scissorState(), + fRenderTargetContext, + path); + if (!op) { + return; + } + op->setClippedBounds(bounds); + fRenderTargetContext->getOpList()->addOp(std::move(op), fRenderTargetContext); +} + +void GrRenderTargetContextPriv::stencilRect(const GrClip& clip, + const GrUserStencilSettings* ss, + GrAAType aaType, + const SkMatrix& viewMatrix, + const SkRect& rect) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_IF_ABANDONED_PRIV + SkDEBUGCODE(fRenderTargetContext->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail, + "GrRenderTargetContext::stencilRect"); + SkASSERT(GrAAType::kCoverage != aaType); + AutoCheckFlush acf(fRenderTargetContext->drawingManager()); + + GrPaint paint; + paint.setXPFactory(GrDisableColorXPFactory::Get()); + + fRenderTargetContext->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, rect, nullptr, + nullptr, ss, aaType); +} + +bool GrRenderTargetContextPriv::drawAndStencilRect(const GrClip& clip, + const GrUserStencilSettings* ss, + SkRegion::Op op, + bool invert, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRect& rect) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_FALSE_IF_ABANDONED_PRIV + SkDEBUGCODE(fRenderTargetContext->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail, + "GrRenderTargetContext::drawAndStencilRect"); + + AutoCheckFlush acf(fRenderTargetContext->drawingManager()); + + GrPaint paint; + paint.setCoverageSetOpXPFactory(op, invert); + + if (fRenderTargetContext->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, ss)) { + return true; + } + SkPath path; + path.setIsVolatile(true); + path.addRect(rect); + return this->drawAndStencilPath(clip, ss, op, invert, aa, viewMatrix, path); +} + +void GrRenderTargetContext::fillRectToRect(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRect& rectToDraw, + const SkRect& localRect) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::fillRectToRect"); + + SkRect croppedRect = rectToDraw; + SkRect croppedLocalRect = localRect; + if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, + &croppedRect, &croppedLocalRect)) { + return; + } + + AutoCheckFlush acf(this->drawingManager()); + + if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) { + InstancedRendering* ir = this->getOpList()->instancedRendering(); + std::unique_ptr op(ir->recordRect(croppedRect, viewMatrix, std::move(paint), + croppedLocalRect, aa, fInstancedPipelineInfo)); + if (op) { + this->addDrawOp(clip, std::move(op)); + return; + } + } + + GrAAType aaType = this->decideAAType(aa); + if (GrAAType::kCoverage != aaType) { + this->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, croppedRect, + &croppedLocalRect, nullptr, nullptr, aaType); + return; + } + + if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) { + std::unique_ptr op = GrAAFillRectOp::MakeWithLocalRect( + paint.getColor(), viewMatrix, croppedRect, croppedLocalRect); + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); + return; + } + + SkMatrix viewAndUnLocalMatrix; + if (!viewAndUnLocalMatrix.setRectToRect(localRect, rectToDraw, SkMatrix::kFill_ScaleToFit)) { + SkDebugf("fillRectToRect called with empty local matrix.\n"); + return; + } + viewAndUnLocalMatrix.postConcat(viewMatrix); + + SkPath path; + path.setIsVolatile(true); + path.addRect(localRect); + this->internalDrawPath(clip, std::move(paint), aa, viewAndUnLocalMatrix, path, GrStyle()); +} + +void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRect& rectToDraw, + const SkMatrix& localMatrix) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::fillRectWithLocalMatrix"); + + SkRect croppedRect = rectToDraw; + if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) { + return; + } + + AutoCheckFlush acf(this->drawingManager()); + + if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) { + InstancedRendering* ir = this->getOpList()->instancedRendering(); + std::unique_ptr op(ir->recordRect(croppedRect, viewMatrix, std::move(paint), + localMatrix, aa, fInstancedPipelineInfo)); + if (op) { + this->addDrawOp(clip, std::move(op)); + return; + } + } + + GrAAType aaType = this->decideAAType(aa); + if (GrAAType::kCoverage != aaType) { + this->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, croppedRect, nullptr, + &localMatrix, nullptr, aaType); + return; + } + + if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) { + std::unique_ptr op = + GrAAFillRectOp::Make(paint.getColor(), viewMatrix, localMatrix, croppedRect); + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); + return; + } + + SkMatrix viewAndUnLocalMatrix; + if (!localMatrix.invert(&viewAndUnLocalMatrix)) { + SkDebugf("fillRectWithLocalMatrix called with degenerate local matrix.\n"); + return; + } + viewAndUnLocalMatrix.postConcat(viewMatrix); + + SkPath path; + path.setIsVolatile(true); + path.addRect(rectToDraw); + path.transform(localMatrix); + this->internalDrawPath(clip, std::move(paint), aa, viewAndUnLocalMatrix, path, GrStyle()); +} + +void GrRenderTargetContext::drawVertices(const GrClip& clip, + GrPaint&& paint, + const SkMatrix& viewMatrix, + GrPrimitiveType primitiveType, + int vertexCount, + const SkPoint positions[], + const SkPoint texCoords[], + const uint32_t colors[], + const uint16_t indices[], + int indexCount, + ColorArrayType colorArrayType) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawVertices"); + + AutoCheckFlush acf(this->drawingManager()); + + // TODO clients should give us bounds + SkRect bounds; + if (!bounds.setBoundsCheck(positions, vertexCount)) { + SkDebugf("drawVertices call empty bounds\n"); + return; + } + + std::unique_ptr op = GrDrawVerticesOp::Make( + paint.getColor(), primitiveType, viewMatrix, positions, vertexCount, indices, + indexCount, colors, texCoords, bounds, colorArrayType); + if (!op) { + return; + } + GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); +} + +void GrRenderTargetContext::drawVertices(const GrClip& clip, + GrPaint&& paint, + const SkMatrix& viewMatrix, + sk_sp vertices) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawVertices"); + + AutoCheckFlush acf(this->drawingManager()); + + SkASSERT(vertices); + std::unique_ptr op = + GrDrawVerticesOp::Make(paint.getColor(), std::move(vertices), viewMatrix); + if (!op) { + return; + } + GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); +} + +/////////////////////////////////////////////////////////////////////////////// + +void GrRenderTargetContext::drawAtlas(const GrClip& clip, + GrPaint&& paint, + const SkMatrix& viewMatrix, + int spriteCount, + const SkRSXform xform[], + const SkRect texRect[], + const SkColor colors[]) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawAtlas"); + + AutoCheckFlush acf(this->drawingManager()); + + std::unique_ptr op = + GrDrawAtlasOp::Make(paint.getColor(), viewMatrix, spriteCount, xform, texRect, colors); + GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); +} + +/////////////////////////////////////////////////////////////////////////////// + +void GrRenderTargetContext::drawRRect(const GrClip& origClip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRRect& rrect, + const GrStyle& style) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawRRect"); + if (rrect.isEmpty()) { + return; + } + + GrNoClip noclip; + const GrClip* clip = &origClip; +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + // The Android framework frequently clips rrects to themselves where the clip is non-aa and the + // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it + // doesn't detect that the clip can be ignored (modulo antialiasing). The following test + // attempts to mitigate the stencil clip cost but will only help when the entire clip stack + // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. + SkRRect devRRect; + if (rrect.transform(viewMatrix, &devRRect) && clip->quickContains(devRRect)) { + clip = &noclip; + } +#endif + SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice + + AutoCheckFlush acf(this->drawingManager()); + const SkStrokeRec stroke = style.strokeRec(); + + if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() && + stroke.isFillStyle()) { + InstancedRendering* ir = this->getOpList()->instancedRendering(); + std::unique_ptr op( + ir->recordRRect(rrect, viewMatrix, std::move(paint), aa, fInstancedPipelineInfo)); + if (op) { + this->addDrawOp(*clip, std::move(op)); + return; + } + } + + GrAAType aaType = this->decideAAType(aa); + if (GrAAType::kCoverage == aaType) { + const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); + std::unique_ptr op = + GrOvalOpFactory::MakeRRectOp(paint.getColor(), + paint.usesDistanceVectorField(), + viewMatrix, + rrect, + stroke, + shaderCaps); + if (op) { + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), *clip, std::move(op)); + return; + } + } + + SkPath path; + path.setIsVolatile(true); + path.addRRect(rrect); + this->internalDrawPath(*clip, std::move(paint), aa, viewMatrix, path, style); +} + +/////////////////////////////////////////////////////////////////////////////// + +void GrRenderTargetContext::drawShadowRRect(const GrClip& clip, + GrPaint&& paint, + const SkMatrix& viewMatrix, + const SkRRect& rrect, + SkScalar blurRadius, + const GrStyle& style) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawShadowRRect"); + if (rrect.isEmpty()) { + return; + } + + SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice + + AutoCheckFlush acf(this->drawingManager()); + const SkStrokeRec stroke = style.strokeRec(); + // TODO: add instancing support? + + const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); + std::unique_ptr op = GrShadowRRectOp::Make( + paint.getColor(), viewMatrix, rrect, blurRadius, stroke, shaderCaps); + if (op) { + GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); + return; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRRect& origOuter, + const SkRRect& origInner) { + SkASSERT(!origInner.isEmpty()); + SkASSERT(!origOuter.isEmpty()); + + if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) { + InstancedRendering* ir = this->getOpList()->instancedRendering(); + std::unique_ptr op(ir->recordDRRect( + origOuter, origInner, viewMatrix, std::move(paint), aa, fInstancedPipelineInfo)); + if (op) { + this->addDrawOp(clip, std::move(op)); + return true; + } + } + + GrAAType aaType = this->decideAAType(aa); + + GrPrimitiveEdgeType innerEdgeType, outerEdgeType; + if (GrAAType::kCoverage == aaType) { + innerEdgeType = kInverseFillAA_GrProcessorEdgeType; + outerEdgeType = kFillAA_GrProcessorEdgeType; + } else { + innerEdgeType = kInverseFillBW_GrProcessorEdgeType; + outerEdgeType = kFillBW_GrProcessorEdgeType; + } + + SkTCopyOnFirstWrite inner(origInner), outer(origOuter); + SkMatrix inverseVM; + if (!viewMatrix.isIdentity()) { + if (!origInner.transform(viewMatrix, inner.writable())) { + return false; + } + if (!origOuter.transform(viewMatrix, outer.writable())) { + return false; + } + if (!viewMatrix.invert(&inverseVM)) { + return false; + } + } else { + inverseVM.reset(); + } + + // TODO these need to be a geometry processors + sk_sp innerEffect(GrRRectEffect::Make(innerEdgeType, *inner)); + if (!innerEffect) { + return false; + } + + sk_sp outerEffect(GrRRectEffect::Make(outerEdgeType, *outer)); + if (!outerEffect) { + return false; + } + + paint.addCoverageFragmentProcessor(std::move(innerEffect)); + paint.addCoverageFragmentProcessor(std::move(outerEffect)); + + SkRect bounds = outer->getBounds(); + if (GrAAType::kCoverage == aaType) { + bounds.outset(SK_ScalarHalf, SK_ScalarHalf); + } + + this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds, + inverseVM); + return true; +} + +void GrRenderTargetContext::drawDRRect(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRRect& outer, + const SkRRect& inner) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawDRRect"); + + SkASSERT(!outer.isEmpty()); + SkASSERT(!inner.isEmpty()); + + AutoCheckFlush acf(this->drawingManager()); + + if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) { + return; + } + + SkPath path; + path.setIsVolatile(true); + path.addRRect(inner); + path.addRRect(outer); + path.setFillType(SkPath::kEvenOdd_FillType); + + this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill()); +} + +/////////////////////////////////////////////////////////////////////////////// + +static inline bool is_int(float x) { + return x == (float) sk_float_round2int(x); +} + +void GrRenderTargetContext::drawRegion(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRegion& region, + const GrStyle& style) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawRegion"); + + if (GrAA::kYes == aa) { + // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix + // to see whether aa is really required. + if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) && + is_int(viewMatrix.getTranslateX()) && + is_int(viewMatrix.getTranslateY())) { + aa = GrAA::kNo; + } + } + bool complexStyle = !style.isSimpleFill(); + if (complexStyle || GrAA::kYes == aa) { + SkPath path; + region.getBoundaryPath(&path); + return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style); + } + + std::unique_ptr op = GrRegionOp::Make(paint.getColor(), viewMatrix, region); + GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); +} + +void GrRenderTargetContext::drawOval(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRect& oval, + const GrStyle& style) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawOval"); + + if (oval.isEmpty()) { + return; + } + + SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice + + AutoCheckFlush acf(this->drawingManager()); + const SkStrokeRec& stroke = style.strokeRec(); + + if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() && + stroke.isFillStyle()) { + InstancedRendering* ir = this->getOpList()->instancedRendering(); + std::unique_ptr op( + ir->recordOval(oval, viewMatrix, std::move(paint), aa, fInstancedPipelineInfo)); + if (op) { + this->addDrawOp(clip, std::move(op)); + return; + } + } + + GrAAType aaType = this->decideAAType(aa); + if (GrAAType::kCoverage == aaType) { + const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); + std::unique_ptr op = + GrOvalOpFactory::MakeOvalOp(paint.getColor(), viewMatrix, oval, stroke, shaderCaps); + if (op) { + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); + return; + } + } + + SkPath path; + path.setIsVolatile(true); + path.addOval(oval); + this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style); +} + +void GrRenderTargetContext::drawArc(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRect& oval, + SkScalar startAngle, + SkScalar sweepAngle, + bool useCenter, + const GrStyle& style) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawArc"); + + AutoCheckFlush acf(this->drawingManager()); + + GrAAType aaType = this->decideAAType(aa); + if (GrAAType::kCoverage == aaType) { + const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); + std::unique_ptr op = GrOvalOpFactory::MakeArcOp(paint.getColor(), + viewMatrix, + oval, + startAngle, + sweepAngle, + useCenter, + style, + shaderCaps); + if (op) { + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); + return; + } + } + SkPath path; + SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter, + style.isSimpleFill()); + this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style); +} + +void GrRenderTargetContext::drawImageLattice(const GrClip& clip, + GrPaint&& paint, + const SkMatrix& viewMatrix, + int imageWidth, + int imageHeight, + std::unique_ptr iter, + const SkRect& dst) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawImageLattice"); + + AutoCheckFlush acf(this->drawingManager()); + + std::unique_ptr op = GrLatticeOp::MakeNonAA( + paint.getColor(), viewMatrix, imageWidth, imageHeight, std::move(iter), dst); + + GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); +} + +void GrRenderTargetContext::prepareForExternalIO() { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::prepareForExternalIO"); + + this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get()); +} + +void GrRenderTargetContext::drawNonAAFilledRect(const GrClip& clip, + GrPaint&& paint, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect* localRect, + const SkMatrix* localMatrix, + const GrUserStencilSettings* ss, + GrAAType hwOrNoneAAType) { + SkASSERT(GrAAType::kCoverage != hwOrNoneAAType); + SkASSERT(hwOrNoneAAType == GrAAType::kNone || this->isStencilBufferMultisampled()); + std::unique_ptr op = GrRectOpFactory::MakeNonAAFill( + paint.getColor(), viewMatrix, rect, localRect, localMatrix); + GrPipelineBuilder pipelineBuilder(std::move(paint), hwOrNoneAAType); + if (ss) { + pipelineBuilder.setUserStencil(ss); + } + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); +} + +// Can 'path' be drawn as a pair of filled nested rectangles? +static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) { + + if (path.isInverseFillType()) { + return false; + } + + // TODO: this restriction could be lifted if we were willing to apply + // the matrix to all the points individually rather than just to the rect + if (!viewMatrix.rectStaysRect()) { + return false; + } + + SkPath::Direction dirs[2]; + if (!path.isNestedFillRects(rects, dirs)) { + return false; + } + + if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) { + // The two rects need to be wound opposite to each other + return false; + } + + // Right now, nested rects where the margin is not the same width + // all around do not render correctly + const SkScalar* outer = rects[0].asScalars(); + const SkScalar* inner = rects[1].asScalars(); + + bool allEq = true; + + SkScalar margin = SkScalarAbs(outer[0] - inner[0]); + bool allGoE1 = margin >= SK_Scalar1; + + for (int i = 1; i < 4; ++i) { + SkScalar temp = SkScalarAbs(outer[i] - inner[i]); + if (temp < SK_Scalar1) { + allGoE1 = false; + } + if (!SkScalarNearlyEqual(margin, temp)) { + allEq = false; + } + } + + return allEq || allGoE1; +} + +void GrRenderTargetContext::drawPath(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkPath& path, + const GrStyle& style) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawPath"); + + if (path.isEmpty()) { + if (path.isInverseFillType()) { + this->drawPaint(clip, std::move(paint), viewMatrix); + } + return; + } + + AutoCheckFlush acf(this->drawingManager()); + + GrAAType aaType = this->decideAAType(aa); + if (GrAAType::kCoverage == aaType && !style.pathEffect()) { + if (style.isSimpleFill() && !path.isConvex()) { + // Concave AA paths are expensive - try to avoid them for special cases + SkRect rects[2]; + + if (fills_as_nested_rects(viewMatrix, path, rects)) { + std::unique_ptr op = + GrRectOpFactory::MakeAAFillNestedRects(paint.getColor(), viewMatrix, rects); + if (op) { + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); + } + return; + } + } + SkRect ovalRect; + bool isOval = path.isOval(&ovalRect); + + if (isOval && !path.isInverseFillType()) { + const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); + std::unique_ptr op = GrOvalOpFactory::MakeOvalOp( + paint.getColor(), viewMatrix, ovalRect, style.strokeRec(), shaderCaps); + if (op) { + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); + this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); + return; + } + } + } + + // Note that internalDrawPath may sw-rasterize the path into a scratch texture. + // Scratch textures can be recycled after they are returned to the texture + // cache. This presents a potential hazard for buffered drawing. However, + // the writePixels that uploads to the scratch will perform a flush so we're + // OK. + this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style); +} + +bool GrRenderTargetContextPriv::drawAndStencilPath(const GrClip& clip, + const GrUserStencilSettings* ss, + SkRegion::Op op, + bool invert, + GrAA aa, + const SkMatrix& viewMatrix, + const SkPath& path) { + ASSERT_SINGLE_OWNER_PRIV + RETURN_FALSE_IF_ABANDONED_PRIV + SkDEBUGCODE(fRenderTargetContext->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail, + "GrRenderTargetContextPriv::drawAndStencilPath"); + + if (path.isEmpty() && path.isInverseFillType()) { + this->drawAndStencilRect(clip, ss, op, invert, GrAA::kNo, SkMatrix::I(), + SkRect::MakeIWH(fRenderTargetContext->width(), + fRenderTargetContext->height())); + return true; + } + + AutoCheckFlush acf(fRenderTargetContext->drawingManager()); + + // An Assumption here is that path renderer would use some form of tweaking + // the src color (either the input alpha or in the frag shader) to implement + // aa. If we have some future driver-mojo path AA that can do the right + // thing WRT to the blend then we'll need some query on the PR. + GrAAType aaType = fRenderTargetContext->decideAAType(aa); + bool hasUserStencilSettings = !ss->isUnused(); + + GrShape shape(path, GrStyle::SimpleFill()); + GrPathRenderer::CanDrawPathArgs canDrawArgs; + canDrawArgs.fShaderCaps = + fRenderTargetContext->drawingManager()->getContext()->caps()->shaderCaps(); + canDrawArgs.fViewMatrix = &viewMatrix; + canDrawArgs.fShape = &shape; + canDrawArgs.fAAType = aaType; + canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings; + + // Don't allow the SW renderer + GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer( + canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor); + if (!pr) { + return false; + } + + GrPaint paint; + paint.setCoverageSetOpXPFactory(op, invert); + + GrPathRenderer::DrawPathArgs args{ + fRenderTargetContext->drawingManager()->getContext(), + std::move(paint), + ss, + fRenderTargetContext, + &clip, + &viewMatrix, + &shape, + aaType, + fRenderTargetContext->isGammaCorrect()}; + pr->drawPath(args); + return true; +} + +SkBudgeted GrRenderTargetContextPriv::isBudgeted() const { + ASSERT_SINGLE_OWNER_PRIV + + if (fRenderTargetContext->wasAbandoned()) { + return SkBudgeted::kNo; + } + + SkDEBUGCODE(fRenderTargetContext->validate();) + + return fRenderTargetContext->fRenderTargetProxy->isBudgeted(); +} + +void GrRenderTargetContext::internalDrawPath(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkPath& path, + const GrStyle& style) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkASSERT(!path.isEmpty()); + GrShape shape; + + GrAAType aaType = this->decideAAType(aa, /*allowMixedSamples*/ true); + if (style.isSimpleHairline() && aaType == GrAAType::kMixedSamples) { + // NVPR cannot handle hairlines, so this will would get picked up by a different stencil and + // cover path renderer (i.e. default path renderer). The hairline renderer produces much + // smoother hairlines than MSAA. + aaType = GrAAType::kCoverage; + } + GrPathRenderer::CanDrawPathArgs canDrawArgs; + canDrawArgs.fShaderCaps = this->drawingManager()->getContext()->caps()->shaderCaps(); + canDrawArgs.fViewMatrix = &viewMatrix; + canDrawArgs.fShape = &shape; + canDrawArgs.fHasUserStencilSettings = false; + + GrPathRenderer* pr; + static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor; + do { + shape = GrShape(path, style); + if (shape.isEmpty()) { + return; + } + + canDrawArgs.fAAType = aaType; + + // Try a 1st time without applying any of the style to the geometry (and barring sw) + pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType); + SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix); + + if (!pr && shape.style().pathEffect()) { + // It didn't work above, so try again with the path effect applied. + shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale); + if (shape.isEmpty()) { + return; + } + pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType); + } + if (!pr) { + if (shape.style().applies()) { + shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale); + if (shape.isEmpty()) { + return; + } + } + // This time, allow SW renderer + pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType); + } + if (!pr && GrAATypeIsHW(aaType)) { + // There are exceptional cases where we may wind up falling back to coverage based AA + // when the target is MSAA (e.g. through disabling path renderers via GrContextOptions). + aaType = GrAAType::kCoverage; + } else { + break; + } + } while(true); + + if (!pr) { +#ifdef SK_DEBUG + SkDebugf("Unable to find path renderer compatible with path.\n"); +#endif + return; + } + + GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(), + std::move(paint), + &GrUserStencilSettings::kUnused, + this, + &clip, + &viewMatrix, + &shape, + aaType, + this->isGammaCorrect()}; + pr->drawPath(args); +} + +static void op_bounds(SkRect* bounds, const GrOp* op) { + *bounds = op->bounds(); + if (op->hasZeroArea()) { + if (op->hasAABloat()) { + bounds->outset(0.5f, 0.5f); + } else { + // We don't know which way the particular GPU will snap lines or points at integer + // coords. So we ensure that the bounds is large enough for either snap. + SkRect before = *bounds; + bounds->roundOut(bounds); + if (bounds->fLeft == before.fLeft) { + bounds->fLeft -= 1; + } + if (bounds->fTop == before.fTop) { + bounds->fTop -= 1; + } + if (bounds->fRight == before.fRight) { + bounds->fRight += 1; + } + if (bounds->fBottom == before.fBottom) { + bounds->fBottom += 1; + } + } + } +} + +uint32_t GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr op) { + ASSERT_SINGLE_OWNER + if (this->drawingManager()->wasAbandoned()) { + return SK_InvalidUniqueID; + } + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::addDrawOp"); + + // Setup clip + SkRect bounds; + op_bounds(&bounds, op.get()); + GrAppliedClip appliedClip; + GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags(); + if (!clip.apply(fContext, this, fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA, + fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil, &appliedClip, + &bounds)) { + return SK_InvalidUniqueID; + } + + // This forces instantiation of the render target. + GrRenderTarget* rt = this->accessRenderTarget(); + if (!rt) { + return SK_InvalidUniqueID; + } + + if (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil || + appliedClip.hasStencilClip()) { + if (!fContext->resourceProvider()->attachStencilAttachment(rt)) { + SkDebugf("ERROR creating stencil attachment. Draw skipped.\n"); + return SK_InvalidUniqueID; + } + } + + GrXferProcessor::DstTexture dstTexture; + if (op->xpRequiresDstTexture(*this->caps(), &appliedClip)) { + if (!this->setupDstTexture(fRenderTargetProxy.get(), clip, op->bounds(), &dstTexture)) { + return SK_InvalidUniqueID; + } + } + + op->setClippedBounds(bounds); + return this->getOpList()->addOp(std::move(op), this, std::move(appliedClip), dstTexture); +} + +uint32_t GrRenderTargetContext::addLegacyMeshDrawOp(GrPipelineBuilder&& pipelineBuilder, + const GrClip& clip, + std::unique_ptr op) { + ASSERT_SINGLE_OWNER + if (this->drawingManager()->wasAbandoned()) { + return SK_InvalidUniqueID; + } + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::addLegacyMeshDrawOp"); + + // Setup clip + SkRect bounds; + op_bounds(&bounds, op.get()); + GrAppliedClip appliedClip; + if (!clip.apply(fContext, this, pipelineBuilder.isHWAntialias(), + pipelineBuilder.hasUserStencilSettings(), &appliedClip, &bounds)) { + return SK_InvalidUniqueID; + } + + // This forces instantiation of the render target. Pipeline creation is moving to flush time + // by which point instantiation must have occurred anyway. + GrRenderTarget* rt = this->accessRenderTarget(); + if (!rt) { + return SK_InvalidUniqueID; + } + + GrResourceProvider* resourceProvider = fContext->resourceProvider(); + bool usesStencil = pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip(); + if (usesStencil) { + if (!resourceProvider->attachStencilAttachment(this->accessRenderTarget())) { + SkDebugf("ERROR creating stencil attachment. Draw skipped.\n"); + return SK_InvalidUniqueID; + } + } + + bool isMixedSamples = fRenderTargetProxy->isMixedSampled() && + (pipelineBuilder.isHWAntialias() || usesStencil); + + GrColor overrideColor; + GrProcessorSet::Analysis analysis = op->analyzeUpdateAndRecordProcessors( + &pipelineBuilder, &appliedClip, isMixedSamples, *this->caps(), &overrideColor); + + GrPipeline::InitArgs args; + pipelineBuilder.getPipelineInitArgs(&args); + args.fAppliedClip = &appliedClip; + args.fRenderTarget = rt; + args.fCaps = this->caps(); + + if (analysis.requiresDstTexture()) { + if (!this->setupDstTexture(fRenderTargetProxy.get(), clip, bounds, &args.fDstTexture)) { + return SK_InvalidUniqueID; + } + } + op->initPipeline(args, analysis, overrideColor); + // TODO: We need to add pipeline dependencies on textures, etc before recording this op. + op->setClippedBounds(bounds); + return this->getOpList()->addOp(std::move(op), this); +} + +bool GrRenderTargetContext::setupDstTexture(GrRenderTargetProxy* rtProxy, const GrClip& clip, + const SkRect& opBounds, + GrXferProcessor::DstTexture* dstTexture) { + if (this->caps()->textureBarrierSupport()) { + if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) { + // MDB TODO: remove this instantiation. Blocked on making DstTexture be proxy-based + sk_sp tex(sk_ref_sp(texProxy->instantiate(fContext->resourceProvider()))); + if (!tex) { + SkDebugf("setupDstTexture: instantiation of src texture failed.\n"); + return false; // We have bigger problems now + } + + // The render target is a texture, so we can read from it directly in the shader. The XP + // will be responsible to detect this situation and request a texture barrier. + dstTexture->setTexture(std::move(tex)); + dstTexture->setOffset(0, 0); + return true; + } + } + + SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height()); + + SkIRect clippedRect; + clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect); + SkIRect drawIBounds; + opBounds.roundOut(&drawIBounds); + // Cover up for any precision issues by outsetting the op bounds a pixel in each direction. + drawIBounds.outset(1, 1); + if (!clippedRect.intersect(drawIBounds)) { +#ifdef SK_DEBUG + GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw."); +#endif + return false; + } + + // MSAA consideration: When there is support for reading MSAA samples in the shader we could + // have per-sample dst values by making the copy multisampled. + GrSurfaceDesc desc; + bool rectsMustMatch = false; + bool disallowSubrect = false; + if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &rectsMustMatch, &disallowSubrect)) { + desc.fOrigin = kBottomLeft_GrSurfaceOrigin; + desc.fFlags = kRenderTarget_GrSurfaceFlag; + desc.fConfig = rtProxy->config(); + } + + if (!disallowSubrect) { + copyRect = clippedRect; + } + + SkIPoint dstPoint, dstOffset; + SkBackingFit fit; + if (rectsMustMatch) { + SkASSERT(desc.fOrigin == rtProxy->origin()); + desc.fWidth = rtProxy->width(); + desc.fHeight = rtProxy->height(); + dstPoint = {copyRect.fLeft, copyRect.fTop}; + dstOffset = {0, 0}; + fit = SkBackingFit::kExact; + } else { + desc.fWidth = copyRect.width(); + desc.fHeight = copyRect.height(); + dstPoint = {0, 0}; + dstOffset = {copyRect.fLeft, copyRect.fTop}; + fit = SkBackingFit::kApprox; + } + + sk_sp sContext = fContext->contextPriv().makeDeferredSurfaceContext( + desc, + fit, + SkBudgeted::kYes); + if (!sContext) { + SkDebugf("setupDstTexture: surfaceContext creation failed.\n"); + return false; + } + + if (!sContext->copy(rtProxy, copyRect, dstPoint)) { + SkDebugf("setupDstTexture: copy failed.\n"); + return false; + } + + GrTextureProxy* copyProxy = sContext->asTextureProxy(); + // MDB TODO: remove this instantiation once DstTexture is proxy-backed + sk_sp copy(sk_ref_sp(copyProxy->instantiate(fContext->resourceProvider()))); + if (!copy) { + SkDebugf("setupDstTexture: instantiation of copied texture failed.\n"); + return false; + } + + dstTexture->setTexture(std::move(copy)); + dstTexture->setOffset(dstOffset); + return true; +} diff --git a/gfx/skia/skia/src/gpu/GrRenderTargetContext.h b/gfx/skia/skia/src/gpu/GrRenderTargetContext.h new file mode 100644 index 000000000000..1d1f9ecd18f9 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrRenderTargetContext.h @@ -0,0 +1,491 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRenderTargetContext_DEFINED +#define GrRenderTargetContext_DEFINED + +#include "GrColor.h" +#include "GrContext.h" +#include "GrPaint.h" +#include "GrSurfaceContext.h" +#include "GrXferProcessor.h" +#include "SkRefCnt.h" +#include "SkSurfaceProps.h" +#include "../private/GrInstancedPipelineInfo.h" +#include "../private/GrRenderTargetProxy.h" + +class GrClip; +class GrDrawingManager; +class GrDrawOp; +class GrFixedClip; +class GrLegacyMeshDrawOp; +class GrPipelineBuilder; +class GrRenderTarget; +class GrRenderTargetContextPriv; +class GrRenderTargetOpList; +class GrStyle; +class GrTextureProxy; +struct GrUserStencilSettings; +class SkDrawFilter; +struct SkIPoint; +struct SkIRect; +class SkLatticeIter; +class SkMatrix; +class SkPaint; +class SkPath; +struct SkPoint; +struct SkRect; +class SkRegion; +class SkRRect; +struct SkRSXform; +class SkTextBlob; +class SkVertices; + +/** + * A helper object to orchestrate commands (draws, etc...) for GrSurfaces that are GrRenderTargets. + */ +class SK_API GrRenderTargetContext : public GrSurfaceContext { +public: + ~GrRenderTargetContext() override; + + // MDB TODO: This access is mainly provided for the image filters. Remove it when they + // no longer need to pass it to the FragmentProcessor ctors. + GrResourceProvider* resourceProvider() { return fContext->resourceProvider(); } + + // We use SkPaint rather than GrPaint here for two reasons: + // * The SkPaint carries extra text settings. If these were extracted to a lighter object + // we could use GrPaint except that + // * SkPaint->GrPaint conversion depends upon whether the glyphs are color or grayscale and + // this can vary within a text run. + virtual void drawText(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, SkScalar x, SkScalar y, + const SkIRect& clipBounds); + virtual void drawPosText(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset, + const SkIRect& clipBounds); + virtual void drawTextBlob(const GrClip&, const SkPaint&, + const SkMatrix& viewMatrix, const SkTextBlob*, + SkScalar x, SkScalar y, + SkDrawFilter*, const SkIRect& clipBounds); + + /** + * Provides a perfomance hint that the render target's contents are allowed + * to become undefined. + */ + void discard(); + + /** + * Clear the entire or rect of the render target, ignoring any clips. + * @param rect the rect to clear or the whole thing if rect is NULL. + * @param color the color to clear to. + * @param canIgnoreRect allows partial clears to be converted to whole + * clears on platforms for which that is cheap + */ + void clear(const SkIRect* rect, GrColor color, bool canIgnoreRect); + + /** + * Draw everywhere (respecting the clip) with the paint. + */ + void drawPaint(const GrClip&, GrPaint&&, const SkMatrix& viewMatrix); + + /** + * Draw the rect using a paint. + * @param paint describes how to color pixels. + * @param GrAA Controls whether rect is antialiased + * @param viewMatrix transformation matrix + * @param style The style to apply. Null means fill. Currently path effects are not + * allowed. + * The rects coords are used to access the paint (through texture matrix) + */ + void drawRect(const GrClip&, + GrPaint&& paint, + GrAA, + const SkMatrix& viewMatrix, + const SkRect&, + const GrStyle* style = nullptr); + + /** + * Maps a rectangle of shader coordinates to a rectangle and fills that rectangle. + * + * @param paint describes how to color pixels. + * @param GrAA Controls whether rect is antialiased + * @param viewMatrix transformation matrix which applies to rectToDraw + * @param rectToDraw the rectangle to draw + * @param localRect the rectangle of shader coordinates applied to rectToDraw + */ + void fillRectToRect(const GrClip&, + GrPaint&& paint, + GrAA, + const SkMatrix& viewMatrix, + const SkRect& rectToDraw, + const SkRect& localRect); + + /** + * Fills a rect with a paint and a localMatrix. + */ + void fillRectWithLocalMatrix(const GrClip& clip, + GrPaint&& paint, + GrAA, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkMatrix& localMatrix); + + /** + * Draw a roundrect using a paint. + * + * @param paint describes how to color pixels. + * @param GrAA Controls whether rrect is antialiased. + * @param viewMatrix transformation matrix + * @param rrect the roundrect to draw + * @param style style to apply to the rrect. Currently path effects are not allowed. + */ + void drawRRect(const GrClip&, + GrPaint&&, + GrAA, + const SkMatrix& viewMatrix, + const SkRRect& rrect, + const GrStyle& style); + + /** + * Draw a roundrect using a paint and a shadow shader. This is separate from drawRRect + * because it uses different underlying geometry and GeometryProcessor + * + * @param paint describes how to color pixels. + * @param viewMatrix transformation matrix + * @param rrect the roundrect to draw + * @param blurRadius amount of shadow blur to apply (in device space) + * @param style style to apply to the rrect. Currently path effects are not allowed. + */ + void drawShadowRRect(const GrClip&, + GrPaint&&, + const SkMatrix& viewMatrix, + const SkRRect& rrect, + SkScalar blurRadius, + const GrStyle& style); + + /** + * Shortcut for filling a SkPath consisting of nested rrects using a paint. The result is + * undefined if outer does not contain inner. + * + * @param paint describes how to color pixels. + * @param GrAA Controls whether rrects edges are antialiased + * @param viewMatrix transformation matrix + * @param outer the outer roundrect + * @param inner the inner roundrect + */ + void drawDRRect(const GrClip&, + GrPaint&&, + GrAA, + const SkMatrix& viewMatrix, + const SkRRect& outer, + const SkRRect& inner); + + /** + * Draws a path. + * + * @param paint describes how to color pixels. + * @param GrAA Controls whether the path is antialiased. + * @param viewMatrix transformation matrix + * @param path the path to draw + * @param style style to apply to the path. + */ + void drawPath(const GrClip&, + GrPaint&&, + GrAA, + const SkMatrix& viewMatrix, + const SkPath&, + const GrStyle& style); + + enum class ColorArrayType { + kPremulGrColor, + kSkColor, + }; + /** + * Draws vertices with a paint. + * + * @param paint describes how to color pixels. + * @param viewMatrix transformation matrix + * @param primitiveType primitives type to draw. + * @param vertexCount number of vertices. + * @param positions array of vertex positions, required. + * @param texCoords optional array of texture coordinates used + * to access the paint. + * @param colors optional array of per-vertex colors, supercedes + * the paint's color field. + * @param indices optional array of indices. If NULL vertices + * are drawn non-indexed. + * @param indexCount if indices is non-null then this is the + * number of indices. + * @param ColorArrayType Determines how the color array should be interpreted. + */ + void drawVertices(const GrClip&, + GrPaint&& paint, + const SkMatrix& viewMatrix, + GrPrimitiveType primitiveType, + int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const uint32_t colors[], + const uint16_t indices[], + int indexCount, + ColorArrayType = ColorArrayType::kPremulGrColor); + + /** + * Draws vertices with a paint. + * + * @param paint describes how to color pixels. + * @param viewMatrix transformation matrix + * @param veritces specifies the mesh to draw. + * @param flags A bitfield of options specified by SkCanvas::VerticesFlags. + */ + void drawVertices(const GrClip&, + GrPaint&& paint, + const SkMatrix& viewMatrix, + sk_sp vertices); + + /** + * Draws textured sprites from an atlas with a paint. This currently does not support AA for the + * sprite rectangle edges. + * + * @param paint describes how to color pixels. + * @param viewMatrix transformation matrix + * @param spriteCount number of sprites. + * @param xform array of compressed transformation data, required. + * @param texRect array of texture rectangles used to access the paint. + * @param colors optional array of per-sprite colors, supercedes + * the paint's color field. + */ + void drawAtlas(const GrClip&, + GrPaint&& paint, + const SkMatrix& viewMatrix, + int spriteCount, + const SkRSXform xform[], + const SkRect texRect[], + const SkColor colors[]); + + /** + * Draws a region. + * + * @param paint describes how to color pixels + * @param viewMatrix transformation matrix + * @param aa should the rects of the region be antialiased. + * @param region the region to be drawn + * @param style style to apply to the region + */ + void drawRegion(const GrClip&, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRegion& region, + const GrStyle& style); + + /** + * Draws an oval. + * + * @param paint describes how to color pixels. + * @param GrAA Controls whether the oval is antialiased. + * @param viewMatrix transformation matrix + * @param oval the bounding rect of the oval. + * @param style style to apply to the oval. Currently path effects are not allowed. + */ + void drawOval(const GrClip&, + GrPaint&& paint, + GrAA, + const SkMatrix& viewMatrix, + const SkRect& oval, + const GrStyle& style); + /** + * Draws a partial arc of an oval. + * + * @param paint describes how to color pixels. + * @param GrGrAA Controls whether the arc is antialiased. + * @param viewMatrix transformation matrix. + * @param oval the bounding rect of the oval. + * @param startAngle starting angle in degrees. + * @param sweepAngle angle to sweep in degrees. Must be in (-360, 360) + * @param useCenter true means that the implied path begins at the oval center, connects as + * a line to the point indicated by the start contains the arc indicated by + * the sweep angle. If false the line beginning at the center point is + * omitted. + * @param style style to apply to the oval. + */ + void drawArc(const GrClip&, + GrPaint&& paint, + GrAA, + const SkMatrix& viewMatrix, + const SkRect& oval, + SkScalar startAngle, + SkScalar sweepAngle, + bool useCenter, + const GrStyle& style); + + /** + * Draw the image as a set of rects, specified by |iter|. + */ + void drawImageLattice(const GrClip&, + GrPaint&& paint, + const SkMatrix& viewMatrix, + int imageWidth, + int imageHeight, + std::unique_ptr iter, + const SkRect& dst); + + /** + * After this returns any pending surface IO will be issued to the backend 3D API and + * if the surface has MSAA it will be resolved. + */ + void prepareForExternalIO(); + + bool isStencilBufferMultisampled() const { + return fRenderTargetProxy->isStencilBufferMultisampled(); + } + bool isUnifiedMultisampled() const { return fRenderTargetProxy->isUnifiedMultisampled(); } + bool hasMixedSamples() const { return fRenderTargetProxy->isMixedSampled(); } + + const GrCaps* caps() const { return fContext->caps(); } + const GrSurfaceDesc& desc() const { return fRenderTargetProxy->desc(); } + int width() const { return fRenderTargetProxy->width(); } + int height() const { return fRenderTargetProxy->height(); } + GrPixelConfig config() const { return fRenderTargetProxy->config(); } + int numColorSamples() const { return fRenderTargetProxy->numColorSamples(); } + const SkSurfaceProps& surfaceProps() const { return fSurfaceProps; } + GrColorSpaceXform* getColorXformFromSRGB() const { return fColorXformFromSRGB.get(); } + GrSurfaceOrigin origin() const { return fRenderTargetProxy->origin(); } + + bool wasAbandoned() const; + + GrRenderTarget* accessRenderTarget() { + // TODO: usage of this entry point needs to be reduced and potentially eliminated + // since it ends the deferral of the GrRenderTarget's allocation + return fRenderTargetProxy->instantiate(fContext->resourceProvider()); + } + + GrSurfaceProxy* asSurfaceProxy() override { return fRenderTargetProxy.get(); } + const GrSurfaceProxy* asSurfaceProxy() const override { return fRenderTargetProxy.get(); } + sk_sp asSurfaceProxyRef() override { return fRenderTargetProxy; } + + GrTextureProxy* asTextureProxy() override; + sk_sp asTextureProxyRef() override; + + GrRenderTargetProxy* asRenderTargetProxy() override { return fRenderTargetProxy.get(); } + sk_sp asRenderTargetProxyRef() override { return fRenderTargetProxy; } + + GrRenderTargetContext* asRenderTargetContext() override { return this; } + + // Provides access to functions that aren't part of the public API. + GrRenderTargetContextPriv priv(); + const GrRenderTargetContextPriv priv() const; + + bool isWrapped_ForTesting() const; + +protected: + GrRenderTargetContext(GrContext*, GrDrawingManager*, sk_sp, + sk_sp, const SkSurfaceProps*, GrAuditTrail*, + GrSingleOwner*); + + SkDEBUGCODE(void validate() const;) + +private: + inline GrAAType decideAAType(GrAA aa, bool allowMixedSamples = false) { + if (GrAA::kNo == aa) { + return GrAAType::kNone; + } + if (this->isUnifiedMultisampled()) { + return GrAAType::kMSAA; + } + if (allowMixedSamples && this->isStencilBufferMultisampled()) { + return GrAAType::kMixedSamples; + } + return GrAAType::kCoverage; + } + + friend class GrAtlasTextBlob; // for access to add[Mesh]DrawOp + friend class GrStencilAndCoverTextContext; // for access to add[Mesh]DrawOp + + friend class GrDrawingManager; // for ctor + friend class GrRenderTargetContextPriv; + friend class GrSWMaskHelper; // for access to add[Mesh]DrawOp + + // All the path renderers currently make their own ops + friend class GrSoftwarePathRenderer; // for access to add[Mesh]DrawOp + friend class GrAAConvexPathRenderer; // for access to add[Mesh]DrawOp + friend class GrDashLinePathRenderer; // for access to add[Mesh]DrawOp + friend class GrAAHairLinePathRenderer; // for access to add[Mesh]DrawOp + friend class GrAALinearizingConvexPathRenderer; // for access to add[Mesh]DrawOp + friend class GrSmallPathRenderer; // for access to add[Mesh]DrawOp + friend class GrDefaultPathRenderer; // for access to add[Mesh]DrawOp + friend class GrMSAAPathRenderer; // for access to add[Mesh]DrawOp + friend class GrStencilAndCoverPathRenderer; // for access to add[Mesh]DrawOp + friend class GrTessellatingPathRenderer; // for access to add[Mesh]DrawOp + // for a unit test + friend void test_draw_op(GrRenderTargetContext*, + sk_sp, sk_sp); + + void internalClear(const GrFixedClip&, const GrColor, bool canIgnoreClip); + + // Only consumes the GrPaint if successful. + bool drawFilledDRRect(const GrClip& clip, + GrPaint&& paint, + GrAA, + const SkMatrix& viewMatrix, + const SkRRect& origOuter, + const SkRRect& origInner); + + // Only consumes the GrPaint if successful. + bool drawFilledRect(const GrClip& clip, + GrPaint&& paint, + GrAA, + const SkMatrix& viewMatrix, + const SkRect& rect, + const GrUserStencilSettings* ss); + + void drawNonAAFilledRect(const GrClip&, + GrPaint&&, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect* localRect, + const SkMatrix* localMatrix, + const GrUserStencilSettings* ss, + GrAAType hwOrNoneAAType); + + void internalDrawPath( + const GrClip&, GrPaint&&, GrAA, const SkMatrix&, const SkPath&, const GrStyle&); + + bool onCopy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override; + + // These perform processing specific to Gr[Mesh]DrawOp-derived ops before recording them into + // the op list. They return the id of the opList to which the op was added, or 0, if it was + // dropped (e.g., due to clipping). + uint32_t addDrawOp(const GrClip&, std::unique_ptr); + uint32_t addLegacyMeshDrawOp(GrPipelineBuilder&&, const GrClip&, + std::unique_ptr); + + // Makes a copy of the proxy if it is necessary for the draw and places the texture that should + // be used by GrXferProcessor to access the destination color in 'result'. If the return + // value is false then a texture copy could not be made. + bool SK_WARN_UNUSED_RESULT setupDstTexture(GrRenderTargetProxy*, + const GrClip&, + const SkRect& opBounds, + GrXferProcessor::DstTexture* result); + + GrRenderTargetOpList* getOpList(); + + sk_sp fRenderTargetProxy; + + // In MDB-mode the GrOpList can be closed by some other renderTargetContext that has picked + // it up. For this reason, the GrOpList should only ever be accessed via 'getOpList'. + GrRenderTargetOpList* fOpList; + GrInstancedPipelineInfo fInstancedPipelineInfo; + + sk_sp fColorXformFromSRGB; + SkSurfaceProps fSurfaceProps; + + typedef GrSurfaceContext INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrRenderTargetContextPriv.h b/gfx/skia/skia/src/gpu/GrRenderTargetContextPriv.h new file mode 100644 index 000000000000..e889317de4a0 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrRenderTargetContextPriv.h @@ -0,0 +1,137 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRenderTargetContextPriv_DEFINED +#define GrRenderTargetContextPriv_DEFINED + +#include "GrRenderTargetContext.h" +#include "GrRenderTargetOpList.h" +#include "GrPathRendering.h" + +class GrFixedClip; +class GrPath; +struct GrUserStencilSettings; + +/** Class that adds methods to GrRenderTargetContext that are only intended for use internal to + Skia. This class is purely a privileged window into GrRenderTargetContext. It should never have + additional data members or virtual methods. */ +class GrRenderTargetContextPriv { +public: + gr_instanced::InstancedRendering* accessInstancedRendering() const { + return fRenderTargetContext->getOpList()->instancedRendering(); + } + + // called to note the last clip drawn to the stencil buffer. + // TODO: remove after clipping overhaul. + void setLastClip(int32_t clipStackGenID, const SkIRect& devClipBounds) { + GrRenderTargetOpList* opList = fRenderTargetContext->getOpList(); + opList->fLastClipStackGenID = clipStackGenID; + opList->fLastDevClipBounds = devClipBounds; + } + + // called to determine if we have to render the clip into SB. + // TODO: remove after clipping overhaul. + bool mustRenderClip(int32_t clipStackGenID, const SkIRect& devClipBounds) const { + GrRenderTargetOpList* opList = fRenderTargetContext->getOpList(); + return opList->fLastClipStackGenID != clipStackGenID || + !opList->fLastDevClipBounds.contains(devClipBounds); + } + + void clear(const GrFixedClip&, const GrColor, bool canIgnoreClip); + + void clearStencilClip(const GrFixedClip&, bool insideStencilMask); + + /* + * Some portions of the code, which use approximate-match rendertargets (i.e., ImageFilters), + * rely on clears that lie outside of the content region to still have an effect. + * For example, when sampling a decimated blurred image back up to full size, the GaussianBlur + * code draws 1-pixel rects along the left and bottom edges to be able to use bilerp for + * upsampling. The "absClear" entry point ignores the content bounds but does use the + * worst case (instantiated) bounds. + * + * @param rect if (!null) the rect to clear, otherwise it is a full screen clear + * @param color the color to clear to + */ + void absClear(const SkIRect* rect, const GrColor color); + + void stencilRect(const GrClip& clip, + const GrUserStencilSettings* ss, + GrAAType, + const SkMatrix& viewMatrix, + const SkRect& rect); + + void stencilPath(const GrClip&, GrAAType, const SkMatrix& viewMatrix, const GrPath*); + + /** + * Draws a rect, either AA or not, and touches the stencil buffer with the user stencil settings + * for each color sample written. + */ + bool drawAndStencilRect(const GrClip&, + const GrUserStencilSettings*, + SkRegion::Op op, + bool invert, + GrAA, + const SkMatrix& viewMatrix, + const SkRect&); + + /** + * Draws a path, either AA or not, and touches the stencil buffer with the user stencil settings + * for each color sample written. + */ + bool drawAndStencilPath(const GrClip&, + const GrUserStencilSettings*, + SkRegion::Op op, + bool invert, + GrAA, + const SkMatrix& viewMatrix, + const SkPath&); + + SkBudgeted isBudgeted() const; + + int maxWindowRectangles() const; + + /* + * This unique ID will not change for a given RenderTargetContext. However, it is _NOT_ + * guaranteed to match the uniqueID of the underlying GrRenderTarget - beware! + */ + GrSurfaceProxy::UniqueID uniqueID() const { + return fRenderTargetContext->fRenderTargetProxy->uniqueID(); + } + + uint32_t testingOnly_addLegacyMeshDrawOp(GrPaint&&, GrAAType, + std::unique_ptr, + const GrUserStencilSettings* = nullptr, + bool snapToCenters = false); + + bool refsWrappedObjects() const { + return fRenderTargetContext->fRenderTargetProxy->refsWrappedObjects(); + } + +private: + explicit GrRenderTargetContextPriv(GrRenderTargetContext* renderTargetContext) + : fRenderTargetContext(renderTargetContext) {} + GrRenderTargetContextPriv(const GrRenderTargetPriv&) {} // unimpl + GrRenderTargetContextPriv& operator=(const GrRenderTargetPriv&); // unimpl + + // No taking addresses of this type. + const GrRenderTargetContextPriv* operator&() const; + GrRenderTargetContextPriv* operator&(); + + GrRenderTargetContext* fRenderTargetContext; + + friend class GrRenderTargetContext; // to construct/copy this type. +}; + +inline GrRenderTargetContextPriv GrRenderTargetContext::priv() { + return GrRenderTargetContextPriv(this); +} + +inline const GrRenderTargetContextPriv GrRenderTargetContext::priv() const { + return GrRenderTargetContextPriv(const_cast(this)); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/GrRenderTargetOpList.cpp b/gfx/skia/skia/src/gpu/GrRenderTargetOpList.cpp new file mode 100644 index 000000000000..2b1cc149b1e0 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrRenderTargetOpList.cpp @@ -0,0 +1,407 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrRenderTargetOpList.h" +#include "GrAuditTrail.h" +#include "GrCaps.h" +#include "GrGpu.h" +#include "GrGpuCommandBuffer.h" +#include "GrRenderTarget.h" +#include "GrRenderTargetContext.h" +#include "GrResourceProvider.h" +#include "ops/GrClearOp.h" +#include "ops/GrCopySurfaceOp.h" +#include "ops/GrDiscardOp.h" +#include "instanced/InstancedRendering.h" + +using gr_instanced::InstancedRendering; + +//////////////////////////////////////////////////////////////////////////////// + +// Experimentally we have found that most combining occurs within the first 10 comparisons. +static const int kDefaultMaxOpLookback = 10; +static const int kDefaultMaxOpLookahead = 10; + +GrRenderTargetOpList::GrRenderTargetOpList(GrRenderTargetProxy* rtp, GrGpu* gpu, + GrResourceProvider* resourceProvider, + GrAuditTrail* auditTrail, const Options& options) + : INHERITED(rtp, auditTrail) + , fGpu(SkRef(gpu)) + , fResourceProvider(resourceProvider) + , fLastClipStackGenID(SK_InvalidUniqueID) + , fClipAllocator(fClipAllocatorStorage, sizeof(fClipAllocatorStorage), + sizeof(fClipAllocatorStorage)) { + + fMaxOpLookback = (options.fMaxOpCombineLookback < 0) ? kDefaultMaxOpLookback + : options.fMaxOpCombineLookback; + fMaxOpLookahead = (options.fMaxOpCombineLookahead < 0) ? kDefaultMaxOpLookahead + : options.fMaxOpCombineLookahead; + + if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) { + fInstancedRendering.reset(fGpu->createInstancedRendering()); + } +} + +GrRenderTargetOpList::~GrRenderTargetOpList() { + fGpu->unref(); +} + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG +void GrRenderTargetOpList::dump() const { + INHERITED::dump(); + + SkDebugf("ops (%d):\n", fRecordedOps.count()); + for (int i = 0; i < fRecordedOps.count(); ++i) { + SkDebugf("*******************************\n"); + if (!fRecordedOps[i].fOp) { + SkDebugf("%d: \n", i); + } else { + SkDebugf("%d: %s\n", i, fRecordedOps[i].fOp->name()); + SkString str = fRecordedOps[i].fOp->dumpInfo(); + SkDebugf("%s\n", str.c_str()); + const SkRect& bounds = fRecordedOps[i].fOp->bounds(); + SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", bounds.fLeft, + bounds.fTop, bounds.fRight, bounds.fBottom); + } + } +} + +void GrRenderTargetOpList::validateTargetsSingleRenderTarget() const { + GrRenderTarget* rt = nullptr; + for (int i = 0; i < fRecordedOps.count(); ++i) { + if (!fRecordedOps[i].fOp) { + continue; // combined forward + } + + if (!rt) { + rt = fRecordedOps[i].fRenderTarget.get(); + } else { + SkASSERT(fRecordedOps[i].fRenderTarget.get() == rt); + } + } +} +#endif + +void GrRenderTargetOpList::prepareOps(GrOpFlushState* flushState) { + // MDB TODO: add SkASSERT(this->isClosed()); + + // Loop over the ops that haven't yet been prepared. + for (int i = 0; i < fRecordedOps.count(); ++i) { + if (fRecordedOps[i].fOp) { + GrOpFlushState::DrawOpArgs opArgs; + if (fRecordedOps[i].fRenderTarget) { + opArgs = { + fRecordedOps[i].fRenderTarget.get(), + fRecordedOps[i].fAppliedClip, + fRecordedOps[i].fDstTexture + }; + } + flushState->setDrawOpArgs(&opArgs); + fRecordedOps[i].fOp->prepare(flushState); + flushState->setDrawOpArgs(nullptr); + } + } + + if (fInstancedRendering) { + fInstancedRendering->beginFlush(flushState->resourceProvider()); + } +} + +// TODO: this is where GrOp::renderTarget is used (which is fine since it +// is at flush time). However, we need to store the RenderTargetProxy in the +// Ops and instantiate them here. +bool GrRenderTargetOpList::executeOps(GrOpFlushState* flushState) { + if (0 == fRecordedOps.count()) { + return false; + } + // Draw all the generated geometry. + SkRandom random; + const GrRenderTarget* currentRenderTarget = nullptr; + std::unique_ptr commandBuffer; + for (int i = 0; i < fRecordedOps.count(); ++i) { + if (!fRecordedOps[i].fOp) { + continue; + } + if (fRecordedOps[i].fRenderTarget.get() != currentRenderTarget) { + if (commandBuffer) { + commandBuffer->end(); + commandBuffer->submit(); + commandBuffer.reset(); + } + currentRenderTarget = fRecordedOps[i].fRenderTarget.get(); + if (currentRenderTarget) { + static const GrGpuCommandBuffer::LoadAndStoreInfo kBasicLoadStoreInfo + { GrGpuCommandBuffer::LoadOp::kLoad,GrGpuCommandBuffer::StoreOp::kStore, + GrColor_ILLEGAL }; + commandBuffer.reset(fGpu->createCommandBuffer(kBasicLoadStoreInfo, // Color + kBasicLoadStoreInfo)); // Stencil + } + flushState->setCommandBuffer(commandBuffer.get()); + } + GrOpFlushState::DrawOpArgs opArgs; + if (fRecordedOps[i].fRenderTarget) { + opArgs = { + fRecordedOps[i].fRenderTarget.get(), + fRecordedOps[i].fAppliedClip, + fRecordedOps[i].fDstTexture + }; + flushState->setDrawOpArgs(&opArgs); + } + fRecordedOps[i].fOp->execute(flushState); + flushState->setDrawOpArgs(nullptr); + } + if (commandBuffer) { + commandBuffer->end(); + commandBuffer->submit(); + flushState->setCommandBuffer(nullptr); + } + + fGpu->finishOpList(); + return true; +} + +void GrRenderTargetOpList::reset() { + fLastFullClearOp = nullptr; + fLastFullClearResourceID.makeInvalid(); + fLastFullClearProxyID.makeInvalid(); + fRecordedOps.reset(); + if (fInstancedRendering) { + fInstancedRendering->endFlush(); + } +} + +void GrRenderTargetOpList::abandonGpuResources() { + if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) { + InstancedRendering* ir = this->instancedRendering(); + ir->resetGpuResources(InstancedRendering::ResetType::kAbandon); + } +} + +void GrRenderTargetOpList::freeGpuResources() { + if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) { + InstancedRendering* ir = this->instancedRendering(); + ir->resetGpuResources(InstancedRendering::ResetType::kDestroy); + } +} + +void GrRenderTargetOpList::fullClear(GrRenderTargetContext* renderTargetContext, GrColor color) { + // MDB TODO: remove this. Right now we need the renderTargetContext for the + // accessRenderTarget call. This method should just take the renderTargetProxy. + GrRenderTarget* renderTarget = renderTargetContext->accessRenderTarget(); + if (!renderTarget) { + return; + } + + // Currently this just inserts or updates the last clear op. However, once in MDB this can + // remove all the previously recorded ops and change the load op to clear with supplied + // color. + // TODO: this needs to be updated to use GrSurfaceProxy::UniqueID + SkASSERT((fLastFullClearResourceID == renderTarget->uniqueID()) == + (fLastFullClearProxyID == renderTargetContext->asRenderTargetProxy()->uniqueID())); + if (fLastFullClearResourceID == renderTarget->uniqueID()) { + // As currently implemented, fLastFullClearOp should be the last op because we would + // have cleared it when another op was recorded. + SkASSERT(fRecordedOps.back().fOp.get() == fLastFullClearOp); + fLastFullClearOp->setColor(color); + return; + } + std::unique_ptr op(GrClearOp::Make(GrFixedClip::Disabled(), color, + renderTargetContext)); + if (!op) { + return; + } + if (GrOp* clearOp = this->recordOp(std::move(op), renderTargetContext)) { + // This is either the clear op we just created or another one that it combined with. + fLastFullClearOp = static_cast(clearOp); + fLastFullClearResourceID = renderTarget->uniqueID(); + fLastFullClearProxyID = renderTargetContext->asRenderTargetProxy()->uniqueID(); + } +} + +void GrRenderTargetOpList::discard(GrRenderTargetContext* renderTargetContext) { + // Currently this just inserts a discard op. However, once in MDB this can remove all the + // previously recorded ops and change the load op to discard. + if (this->caps()->discardRenderTargetSupport()) { + std::unique_ptr op(GrDiscardOp::Make(renderTargetContext)); + if (!op) { + return; + } + this->recordOp(std::move(op), renderTargetContext); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +bool GrRenderTargetOpList::copySurface(GrResourceProvider* resourceProvider, + GrSurfaceProxy* dst, + GrSurfaceProxy* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint) { + std::unique_ptr op = GrCopySurfaceOp::Make(resourceProvider, dst, src, srcRect, dstPoint); + if (!op) { + return false; + } +#ifdef ENABLE_MDB + this->addDependency(src); +#endif + + // Copy surface doesn't work through a GrGpuCommandBuffer. By passing nullptr for the context we + // force this to occur between command buffers and execute directly on GrGpu. This workaround + // goes away with MDB. + this->recordOp(std::move(op), nullptr); + return true; +} + +static inline bool can_reorder(const SkRect& a, const SkRect& b) { + return a.fRight <= b.fLeft || a.fBottom <= b.fTop || + b.fRight <= a.fLeft || b.fBottom <= a.fTop; +} + +bool GrRenderTargetOpList::combineIfPossible(const RecordedOp& a, GrOp* b, + const GrAppliedClip* bClip, + const DstTexture* bDstTexture) { + if (a.fAppliedClip) { + if (!bClip) { + return false; + } + if (*a.fAppliedClip != *bClip) { + return false; + } + } else if (bClip) { + return false; + } + if (bDstTexture) { + if (a.fDstTexture != *bDstTexture) { + return false; + } + } else if (a.fDstTexture.texture()) { + return false; + } + return a.fOp->combineIfPossible(b, *this->caps()); +} + +GrOp* GrRenderTargetOpList::recordOp(std::unique_ptr op, + GrRenderTargetContext* renderTargetContext, + GrAppliedClip* clip, + const DstTexture* dstTexture) { + GrRenderTarget* renderTarget = + renderTargetContext ? renderTargetContext->accessRenderTarget() + : nullptr; + + // A closed GrOpList should never receive new/more ops + SkASSERT(!this->isClosed()); + + // Check if there is an op we can combine with by linearly searching back until we either + // 1) check every op + // 2) intersect with something + // 3) find a 'blocker' + GR_AUDIT_TRAIL_ADD_OP(fAuditTrail, op.get(), renderTarget->uniqueID(), + renderTargetContext->asRenderTargetProxy()->uniqueID()); + GrOP_INFO("Recording (%s, opID: %u)\n" + "\tBounds: [L: %f T: %f R: %f B: %f]\n", + op->name(), + op->uniqueID(), + op->bounds().fLeft, op->bounds().fTop, + op->bounds().fRight, op->bounds().fBottom); + GrOP_INFO(SkTabString(op->dumpInfo(), 1).c_str()); + GrOP_INFO("\tClipped Bounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", op->bounds().fLeft, + op->bounds().fTop, op->bounds().fRight, op->bounds().fBottom); + GrOP_INFO("\tOutcome:\n"); + int maxCandidates = SkTMin(fMaxOpLookback, fRecordedOps.count()); + // If we don't have a valid destination render target then we cannot reorder. + if (maxCandidates && renderTarget) { + int i = 0; + while (true) { + const RecordedOp& candidate = fRecordedOps.fromBack(i); + // We cannot continue to search backwards if the render target changes + if (candidate.fRenderTarget.get() != renderTarget) { + GrOP_INFO("\t\tBreaking because of (%s, opID: %u) Rendertarget mismatch\n", + candidate.fOp->name(), + candidate.fOp->uniqueID()); + break; + } + if (this->combineIfPossible(candidate, op.get(), clip, dstTexture)) { + GrOP_INFO("\t\tCombining with (%s, opID: %u)\n", candidate.fOp->name(), + candidate.fOp->uniqueID()); + GrOP_INFO("\t\t\tCombined op info:\n"); + GrOP_INFO(SkTabString(candidate.fOp->dumpInfo(), 4).c_str()); + GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, candidate.fOp.get(), op.get()); + return candidate.fOp.get(); + } + // Stop going backwards if we would cause a painter's order violation. + if (!can_reorder(fRecordedOps.fromBack(i).fOp->bounds(), op->bounds())) { + GrOP_INFO("\t\tIntersects with (%s, opID: %u)\n", candidate.fOp->name(), + candidate.fOp->uniqueID()); + break; + } + ++i; + if (i == maxCandidates) { + GrOP_INFO("\t\tReached max lookback or beginning of op array %d\n", i); + break; + } + } + } else { + GrOP_INFO("\t\tFirstOp\n"); + } + GR_AUDIT_TRAIL_OP_RESULT_NEW(fAuditTrail, op); + if (clip) { + clip = fClipAllocator.make(std::move(*clip)); + } + fRecordedOps.emplace_back(std::move(op), renderTarget, clip, dstTexture); + fRecordedOps.back().fOp->wasRecorded(); + fLastFullClearOp = nullptr; + fLastFullClearResourceID.makeInvalid(); + fLastFullClearProxyID.makeInvalid(); + return fRecordedOps.back().fOp.get(); +} + +void GrRenderTargetOpList::forwardCombine() { + if (fMaxOpLookahead <= 0) { + return; + } + for (int i = 0; i < fRecordedOps.count() - 1; ++i) { + GrOp* op = fRecordedOps[i].fOp.get(); + GrRenderTarget* renderTarget = fRecordedOps[i].fRenderTarget.get(); + // If we don't have a valid destination render target ID then we cannot reorder. + if (!renderTarget) { + continue; + } + int maxCandidateIdx = SkTMin(i + fMaxOpLookahead, fRecordedOps.count() - 1); + int j = i + 1; + while (true) { + const RecordedOp& candidate = fRecordedOps[j]; + // We cannot continue to search if the render target changes + if (candidate.fRenderTarget.get() != renderTarget) { + GrOP_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate.fOp->name(), + candidate.fOp->uniqueID()); + break; + } + if (this->combineIfPossible(fRecordedOps[i], candidate.fOp.get(), + candidate.fAppliedClip, &candidate.fDstTexture)) { + GrOP_INFO("\t\tCombining with (%s, B%u)\n", candidate.fOp->name(), + candidate.fOp->uniqueID()); + GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, op, candidate.fOp.get()); + fRecordedOps[j].fOp = std::move(fRecordedOps[i].fOp); + break; + } + // Stop going traversing if we would cause a painter's order violation. + if (!can_reorder(fRecordedOps[j].fOp->bounds(), op->bounds())) { + GrOP_INFO("\t\tIntersects with (%s, B%u)\n", candidate.fOp->name(), + candidate.fOp->uniqueID()); + break; + } + ++j; + if (j > maxCandidateIdx) { + GrOP_INFO("\t\tReached max lookahead or end of op array %d\n", i); + break; + } + } + } +} + diff --git a/gfx/skia/skia/src/gpu/GrRenderTargetOpList.h b/gfx/skia/skia/src/gpu/GrRenderTargetOpList.h new file mode 100644 index 000000000000..be4deb30eaf1 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrRenderTargetOpList.h @@ -0,0 +1,174 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRenderTargetOpList_DEFINED +#define GrRenderTargetOpList_DEFINED + +#include "GrAppliedClip.h" +#include "GrOpList.h" +#include "GrPathRendering.h" +#include "GrPrimitiveProcessor.h" +#include "SkArenaAlloc.h" +#include "SkClipStack.h" +#include "SkMatrix.h" +#include "SkStringUtils.h" +#include "SkStrokeRec.h" +#include "SkTArray.h" +#include "SkTLazy.h" +#include "SkTypes.h" + +class GrAuditTrail; +class GrClearOp; +class GrCaps; +class GrOp; +class GrPipelineBuilder; +class GrRenderTargetProxy; + +class GrRenderTargetOpList final : public GrOpList { +private: + using DstTexture = GrXferProcessor::DstTexture; + +public: + /** Options for GrRenderTargetOpList behavior. */ + struct Options { + int fMaxOpCombineLookback = -1; + int fMaxOpCombineLookahead = -1; + }; + + GrRenderTargetOpList(GrRenderTargetProxy*, GrGpu*, GrResourceProvider*, + GrAuditTrail*, const Options&); + + ~GrRenderTargetOpList() override; + + void makeClosed() override { + INHERITED::makeClosed(); + + fLastFullClearOp = nullptr; + this->forwardCombine(); + } + + /** + * Empties the draw buffer of any queued up draws. + */ + void reset() override; + + void abandonGpuResources() override; + void freeGpuResources() override; + + /** + * Together these two functions flush all queued up draws to GrCommandBuffer. The return value + * of executeOps() indicates whether any commands were actually issued to the GPU. + */ + void prepareOps(GrOpFlushState* flushState) override; + bool executeOps(GrOpFlushState* flushState) override; + + /** + * Gets the capabilities of the draw target. + */ + const GrCaps* caps() const { return fGpu->caps(); } + + uint32_t addOp(std::unique_ptr op, GrRenderTargetContext* renderTargetContext) { + this->recordOp(std::move(op), renderTargetContext, nullptr, nullptr); + return this->uniqueID(); + } + uint32_t addOp(std::unique_ptr op, GrRenderTargetContext* renderTargetContext, + GrAppliedClip&& clip, const DstTexture& dstTexture) { + this->recordOp(std::move(op), renderTargetContext, clip.doesClip() ? &clip : nullptr, + &dstTexture); + return this->uniqueID(); + } + + /** Clears the entire render target */ + void fullClear(GrRenderTargetContext*, GrColor color); + + /** Discards the contents render target. */ + void discard(GrRenderTargetContext*); + + /** + * Copies a pixel rectangle from one surface to another. This call may finalize + * reserved vertex/index data (as though a draw call was made). The src pixels + * copied are specified by srcRect. They are copied to a rect of the same + * size in dst with top left at dstPoint. If the src rect is clipped by the + * src bounds then pixel values in the dst rect corresponding to area clipped + * by the src rect are not overwritten. This method is not guaranteed to succeed + * depending on the type of surface, configs, etc, and the backend-specific + * limitations. + */ + bool copySurface(GrResourceProvider* resourceProvider, + GrSurfaceProxy* dst, + GrSurfaceProxy* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint); + + gr_instanced::InstancedRendering* instancedRendering() const { + SkASSERT(fInstancedRendering); + return fInstancedRendering.get(); + } + + GrRenderTargetOpList* asRenderTargetOpList() override { return this; } + + SkDEBUGCODE(void dump() const override;) + + SkDEBUGCODE(void validateTargetsSingleRenderTarget() const;) + +private: + friend class GrRenderTargetContextPriv; // for stencil clip state. TODO: this is invasive + + struct RecordedOp { + RecordedOp(std::unique_ptr op, + GrRenderTarget* rt, + const GrAppliedClip* appliedClip, + const DstTexture* dstTexture) + : fOp(std::move(op)) + , fRenderTarget(rt) + , fAppliedClip(appliedClip) { + if (dstTexture) { + fDstTexture = *dstTexture; + } + } + std::unique_ptr fOp; + // TODO: These ops will all to target the same render target and this won't be needed. + GrPendingIOResource fRenderTarget; + DstTexture fDstTexture; + const GrAppliedClip* fAppliedClip; + }; + + // If the input op is combined with an earlier op, this returns the combined op. Otherwise, it + // returns the input op. + GrOp* recordOp(std::unique_ptr, GrRenderTargetContext*, GrAppliedClip* = nullptr, + const DstTexture* = nullptr); + + void forwardCombine(); + + // If this returns true then b has been merged into a's op. + bool combineIfPossible(const RecordedOp& a, GrOp* b, const GrAppliedClip* bClip, + const DstTexture* bDstTexture); + + GrClearOp* fLastFullClearOp = nullptr; + GrGpuResource::UniqueID fLastFullClearResourceID = GrGpuResource::UniqueID::InvalidID(); + GrSurfaceProxy::UniqueID fLastFullClearProxyID = GrSurfaceProxy::UniqueID::InvalidID(); + + GrGpu* fGpu; + GrResourceProvider* fResourceProvider; + + int fMaxOpLookback; + int fMaxOpLookahead; + + std::unique_ptr fInstancedRendering; + + int32_t fLastClipStackGenID; + SkIRect fLastDevClipBounds; + + SkSTArray<256, RecordedOp, true> fRecordedOps; + + char fClipAllocatorStorage[4096]; + SkArenaAlloc fClipAllocator; + + typedef GrOpList INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrRenderTargetPriv.h b/gfx/skia/skia/src/gpu/GrRenderTargetPriv.h index 698288e1cd97..89f4d5289ec6 100644 --- a/gfx/skia/skia/src/gpu/GrRenderTargetPriv.h +++ b/gfx/skia/skia/src/gpu/GrRenderTargetPriv.h @@ -32,13 +32,14 @@ public: int numStencilBits() const; - const GrGpu::MultisampleSpecs& getMultisampleSpecs(const GrStencilSettings& stencil) const; - uint8_t& accessMultisampleSpecsID() { return fRenderTarget->fMultisampleSpecsID; } + // Finds a render target's multisample specs. The pipeline is only needed in case the info isn't + // cached and we need to flush the draw state in order to query it. The pipeline is not expected + // to affect the multisample information itself. + const GrGpu::MultisampleSpecs& getMultisampleSpecs(const GrPipeline&) const; typedef GrRenderTarget::Flags Flags; Flags flags() const { return fRenderTarget->fFlags; } - int maxWindowRectangles() const; private: explicit GrRenderTargetPriv(GrRenderTarget* renderTarget) : fRenderTarget(renderTarget) {} diff --git a/gfx/skia/skia/src/gpu/GrRenderTargetProxy.cpp b/gfx/skia/skia/src/gpu/GrRenderTargetProxy.cpp index fa6bd26577a0..44f23d484b7e 100644 --- a/gfx/skia/skia/src/gpu/GrRenderTargetProxy.cpp +++ b/gfx/skia/skia/src/gpu/GrRenderTargetProxy.cpp @@ -8,91 +8,68 @@ #include "GrRenderTargetProxy.h" #include "GrCaps.h" -#include "GrDrawTarget.h" #include "GrGpuResourcePriv.h" +#include "GrRenderTargetOpList.h" +#include "GrRenderTargetPriv.h" +#include "GrResourceProvider.h" +#include "GrTextureRenderTargetProxy.h" // Deferred version // TODO: we can probably munge the 'desc' in both the wrapped and deferred // cases to make the sampleConfig/numSamples stuff more rational. GrRenderTargetProxy::GrRenderTargetProxy(const GrCaps& caps, const GrSurfaceDesc& desc, - SkBackingFit fit, SkBudgeted budgeted) - : INHERITED(desc, fit, budgeted) - , fTarget(nullptr) - , fFlags(GrRenderTargetPriv::Flags::kNone) - , fLastDrawTarget(nullptr) { + SkBackingFit fit, SkBudgeted budgeted, uint32_t flags) + : INHERITED(desc, fit, budgeted, flags) + , fRenderTargetFlags(GrRenderTarget::Flags::kNone) { // Since we know the newly created render target will be internal, we are able to precompute // what the flags will ultimately end up being. if (caps.usesMixedSamples() && fDesc.fSampleCnt > 0) { - fFlags |= GrRenderTargetPriv::Flags::kMixedSampled; + fRenderTargetFlags |= GrRenderTarget::Flags::kMixedSampled; } if (caps.maxWindowRectangles() > 0) { - fFlags |= GrRenderTargetPriv::Flags::kWindowRectsSupport; + fRenderTargetFlags |= GrRenderTarget::Flags::kWindowRectsSupport; } } // Wrapped version -GrRenderTargetProxy::GrRenderTargetProxy(const GrCaps& caps, sk_sp rt) - : INHERITED(rt->desc(), SkBackingFit::kExact, - rt->resourcePriv().isBudgeted(), rt->uniqueID()) - , fTarget(std::move(rt)) - , fFlags(fTarget->renderTargetPriv().flags()) - , fLastDrawTarget(nullptr) { +GrRenderTargetProxy::GrRenderTargetProxy(sk_sp surf) + : INHERITED(std::move(surf), SkBackingFit::kExact) + , fRenderTargetFlags(fTarget->asRenderTarget()->renderTargetPriv().flags()) { } -GrRenderTargetProxy::~GrRenderTargetProxy() { - if (fLastDrawTarget) { - fLastDrawTarget->clearRT(); - } - SkSafeUnref(fLastDrawTarget); +int GrRenderTargetProxy::maxWindowRectangles(const GrCaps& caps) const { + return (fRenderTargetFlags & GrRenderTarget::Flags::kWindowRectsSupport) + ? caps.maxWindowRectangles() + : 0; } -GrRenderTarget* GrRenderTargetProxy::instantiate(GrTextureProvider* texProvider) { - if (fTarget) { - return fTarget.get(); - } +GrRenderTarget* GrRenderTargetProxy::instantiate(GrResourceProvider* resourceProvider) { + SkASSERT(fDesc.fFlags & GrSurfaceFlags::kRenderTarget_GrSurfaceFlag); - // TODO: it would be nice to not have to copy the desc here - GrSurfaceDesc desc = fDesc; - desc.fFlags |= GrSurfaceFlags::kRenderTarget_GrSurfaceFlag; - - sk_sp tex; - if (SkBackingFit::kApprox == fFit) { - tex.reset(texProvider->createApproxTexture(desc)); - } else { - tex.reset(texProvider->createTexture(desc, fBudgeted)); - } - if (!tex || !tex->asRenderTarget()) { + GrSurface* surf = INHERITED::instantiate(resourceProvider); + if (!surf || !surf->asRenderTarget()) { return nullptr; } - fTarget = sk_ref_sp(tex->asRenderTarget()); - // Check that our a priori computation matched the ultimate reality - SkASSERT(fFlags == fTarget->renderTargetPriv().flags()); + SkASSERT(fRenderTargetFlags == surf->asRenderTarget()->renderTargetPriv().flags()); - return fTarget.get(); + return surf->asRenderTarget(); } -void GrRenderTargetProxy::setLastDrawTarget(GrDrawTarget* dt) { - if (fLastDrawTarget) { - // The non-MDB world never closes so we can't check this condition -#ifdef ENABLE_MDB - SkASSERT(fLastDrawTarget->isClosed()); -#endif - fLastDrawTarget->clearRT(); +size_t GrRenderTargetProxy::onGpuMemorySize() const { + if (fTarget) { + return fTarget->gpuMemorySize(); } - SkRefCnt_SafeAssign(fLastDrawTarget, dt); + // TODO: do we have enough information to improve this worst case estimate? + return GrSurface::ComputeSize(fDesc, fDesc.fSampleCnt+1, false, SkBackingFit::kApprox == fFit); } -sk_sp GrRenderTargetProxy::Make(const GrCaps& caps, - const GrSurfaceDesc& desc, - SkBackingFit fit, - SkBudgeted budgeted) { - return sk_sp(new GrRenderTargetProxy(caps, desc, fit, budgeted)); -} +bool GrRenderTargetProxy::refsWrappedObjects() const { + if (!fTarget) { + return false; + } -sk_sp GrRenderTargetProxy::Make(const GrCaps& caps, sk_sp rt) { - return sk_sp(new GrRenderTargetProxy(caps, rt)); + return fTarget->resourcePriv().refsWrappedObjects(); } - diff --git a/gfx/skia/skia/src/gpu/GrResourceCache.cpp b/gfx/skia/skia/src/gpu/GrResourceCache.cpp index 9462a7384d73..596af6d623a3 100644 --- a/gfx/skia/skia/src/gpu/GrResourceCache.cpp +++ b/gfx/skia/skia/src/gpu/GrResourceCache.cpp @@ -365,6 +365,7 @@ void GrResourceCache::notifyCntReachedZero(GrGpuResource* resource, uint32_t fla this->removeFromNonpurgeableArray(resource); fPurgeableQueue.insert(resource); resource->cacheAccess().setFlushCntWhenResourceBecamePurgeable(fExternalFlushCnt); + resource->cacheAccess().setTimeWhenResourceBecomePurgeable(); if (SkBudgeted::kNo == resource->resourcePriv().isBudgeted()) { // Check whether this resource could still be used as a scratch resource. @@ -504,6 +505,24 @@ void GrResourceCache::purgeAllUnlocked() { this->validate(); } +void GrResourceCache::purgeResourcesNotUsedSince(GrStdSteadyClock::time_point purgeTime) { + while (fPurgeableQueue.count()) { + const GrStdSteadyClock::time_point resourceTime = + fPurgeableQueue.peek()->cacheAccess().timeWhenResourceBecamePurgeable(); + if (resourceTime >= purgeTime) { + // Resources were given both LRU timestamps and tagged with a frame number when + // they first became purgeable. The LRU timestamp won't change again until the + // resource is made non-purgeable again. So, at this point all the remaining + // resources in the timestamp-sorted queue will have a frame number >= to this + // one. + break; + } + GrGpuResource* resource = fPurgeableQueue.peek(); + SkASSERT(resource->isPurgeable()); + resource->cacheAccess().release(); + } +} + void GrResourceCache::processInvalidUniqueKeys( const SkTArray& msgs) { for (int i = 0; i < msgs.count(); ++i) { diff --git a/gfx/skia/skia/src/gpu/GrResourceCache.h b/gfx/skia/skia/src/gpu/GrResourceCache.h index ae9a4e7ee7e3..d871c9ad1351 100644 --- a/gfx/skia/skia/src/gpu/GrResourceCache.h +++ b/gfx/skia/skia/src/gpu/GrResourceCache.h @@ -50,8 +50,9 @@ public: static const int kDefaultMaxCount = 2 * (1 << 12); // Default maximum number of bytes of gpu memory of budgeted resources in the cache. static const size_t kDefaultMaxSize = 96 * (1 << 20); - // Default number of external flushes a budgeted resources can go unused in the cache before it - // is purged. Using a value <= 0 disables this feature. + // Default number of external flushes a budgeted resources can go unused in the cache before it + // is purged. Using a value <= 0 disables this feature. This will be removed once Chrome + // starts using time-based purging. static const int kDefaultMaxUnusedFlushes = 1 * /* flushes per frame */ 60 * /* fps */ @@ -159,6 +160,9 @@ public: /** Purges all resources that don't have external owners. */ void purgeAllUnlocked(); + /** Purge all resources not used since the passed in time. */ + void purgeResourcesNotUsedSince(GrStdSteadyClock::time_point); + /** Returns true if the cache would like a flush to occur in order to make more resources purgeable. */ bool requestsFlush() const { return fRequestFlush; } @@ -211,6 +215,10 @@ public: void dumpStatsKeyValuePairs(SkTArray* keys, SkTArray* value) const; #endif +#ifdef SK_DEBUG + int countUniqueKeysWithTag(const char* tag) const; +#endif + // This function is for unit testing and is only defined in test tools. void changeTimestamp(uint32_t newTimestamp); diff --git a/gfx/skia/skia/src/gpu/GrResourceProvider.cpp b/gfx/skia/skia/src/gpu/GrResourceProvider.cpp index 7518378ad72f..d2ec204d6c78 100644 --- a/gfx/skia/skia/src/gpu/GrResourceProvider.cpp +++ b/gfx/skia/skia/src/gpu/GrResourceProvider.cpp @@ -9,23 +9,265 @@ #include "GrBuffer.h" #include "GrCaps.h" +#include "GrContext.h" +#include "GrContextPriv.h" #include "GrGpu.h" #include "GrPathRendering.h" #include "GrRenderTarget.h" #include "GrRenderTargetPriv.h" #include "GrResourceCache.h" #include "GrResourceKey.h" +#include "GrSemaphore.h" #include "GrStencilAttachment.h" +#include "GrSurfaceProxyPriv.h" +#include "GrTexturePriv.h" +#include "../private/GrSingleOwner.h" #include "SkMathPriv.h" GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); +const int GrResourceProvider::kMinScratchTextureSize = 16; + +#define ASSERT_SINGLE_OWNER \ + SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) + GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner) - : INHERITED(gpu, cache, owner) { + : fCache(cache) + , fGpu(gpu) +#ifdef SK_DEBUG + , fSingleOwner(owner) +#endif + { + fCaps = sk_ref_sp(fGpu->caps()); + GR_DEFINE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); fQuadIndexBufferKey = gQuadIndexBufferKey; } +bool GrResourceProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) { + return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height())); +} + +// MDB TODO: this should probably be a factory on GrSurfaceProxy +sk_sp GrResourceProvider::createMipMappedTexture( + const GrSurfaceDesc& desc, + SkBudgeted budgeted, + const GrMipLevel* texels, + int mipLevelCount, + uint32_t flags, + SkDestinationSurfaceColorMode mipColorMode) { + ASSERT_SINGLE_OWNER + + if (!mipLevelCount) { + if (texels) { + return nullptr; + } + return GrSurfaceProxy::MakeDeferred(this, desc, budgeted, nullptr, 0); + } + + if (this->isAbandoned()) { + return nullptr; + } + + for (int i = 0; i < mipLevelCount; ++i) { + if (!texels[i].fPixels) { + return nullptr; + } + } + if (mipLevelCount > 1 && GrPixelConfigIsSint(desc.fConfig)) { + return nullptr; + } + if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) && + !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { + return nullptr; + } + if (!GrPixelConfigIsCompressed(desc.fConfig)) { + if (mipLevelCount < 2) { + flags |= kExact_Flag | kNoCreate_Flag; + sk_sp tex(this->refScratchTexture(desc, flags)); + if (tex) { + sk_sp proxy = GrSurfaceProxy::MakeWrapped(tex); + + if (fGpu->getContext()->contextPriv().writeSurfacePixels( + proxy.get(), nullptr, 0, 0, desc.fWidth, desc.fHeight, desc.fConfig, + nullptr, texels[0].fPixels, texels[0].fRowBytes)) { + if (SkBudgeted::kNo == budgeted) { + tex->resourcePriv().makeUnbudgeted(); + } + tex->texturePriv().setMipColorMode(mipColorMode); + return proxy; + } + } + } + } + + SkTArray texelsShallowCopy(mipLevelCount); + for (int i = 0; i < mipLevelCount; ++i) { + texelsShallowCopy.push_back(texels[i]); + } + sk_sp tex(fGpu->createTexture(desc, budgeted, texelsShallowCopy)); + if (tex) { + tex->texturePriv().setMipColorMode(mipColorMode); + } + + return GrSurfaceProxy::MakeWrapped(std::move(tex)); +} + +sk_sp GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, + uint32_t flags) { + ASSERT_SINGLE_OWNER + + if (this->isAbandoned()) { + return nullptr; + } + + if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) && + !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { + return nullptr; + } + + if (!GrPixelConfigIsCompressed(desc.fConfig)) { + flags |= kExact_Flag | kNoCreate_Flag; + sk_sp tex(this->refScratchTexture(desc, flags)); + if (tex) { + if (SkBudgeted::kNo == budgeted) { + tex->resourcePriv().makeUnbudgeted(); + } + return tex; + } + } + + sk_sp tex(fGpu->createTexture(desc, budgeted)); + return tex; +} + +GrTexture* GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc, uint32_t flags) { + ASSERT_SINGLE_OWNER + SkASSERT(0 == flags || kNoPendingIO_Flag == flags); + + if (this->isAbandoned()) { + return nullptr; + } + + // Currently we don't recycle compressed textures as scratch. + if (GrPixelConfigIsCompressed(desc.fConfig)) { + return nullptr; + } + + return this->refScratchTexture(desc, flags); +} + +GrTexture* GrResourceProvider::refScratchTexture(const GrSurfaceDesc& inDesc, + uint32_t flags) { + ASSERT_SINGLE_OWNER + SkASSERT(!this->isAbandoned()); + SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig)); + + SkTCopyOnFirstWrite desc(inDesc); + + if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) { + if (!(kExact_Flag & flags)) { + // bin by pow2 with a reasonable min + GrSurfaceDesc* wdesc = desc.writable(); + wdesc->fWidth = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fWidth)); + wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fHeight)); + } + + GrScratchKey key; + GrTexturePriv::ComputeScratchKey(*desc, &key); + uint32_t scratchFlags = 0; + if (kNoPendingIO_Flag & flags) { + scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag; + } else if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) { + // If it is not a render target then it will most likely be populated by + // writePixels() which will trigger a flush if the texture has pending IO. + scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag; + } + GrGpuResource* resource = fCache->findAndRefScratchResource(key, + GrSurface::WorstCaseSize(*desc), + scratchFlags); + if (resource) { + GrSurface* surface = static_cast(resource); + return surface->asTexture(); + } + } + + if (!(kNoCreate_Flag & flags)) { + return fGpu->createTexture(*desc, SkBudgeted::kYes); + } + + return nullptr; +} + +sk_sp GrResourceProvider::wrapBackendTexture(const GrBackendTextureDesc& desc, + GrWrapOwnership ownership) { + ASSERT_SINGLE_OWNER + if (this->isAbandoned()) { + return nullptr; + } + return fGpu->wrapBackendTexture(desc, ownership); +} + +sk_sp GrResourceProvider::wrapBackendRenderTarget( + const GrBackendRenderTargetDesc& desc) +{ + ASSERT_SINGLE_OWNER + return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(desc); +} + +void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key, + GrGpuResource* resource) { + ASSERT_SINGLE_OWNER + if (this->isAbandoned() || !resource) { + return; + } + resource->resourcePriv().setUniqueKey(key); +} + +GrGpuResource* GrResourceProvider::findAndRefResourceByUniqueKey(const GrUniqueKey& key) { + ASSERT_SINGLE_OWNER + return this->isAbandoned() ? nullptr : fCache->findAndRefUniqueResource(key); +} + +GrTexture* GrResourceProvider::findAndRefTextureByUniqueKey(const GrUniqueKey& key) { + ASSERT_SINGLE_OWNER + GrGpuResource* resource = this->findAndRefResourceByUniqueKey(key); + if (resource) { + GrTexture* texture = static_cast(resource)->asTexture(); + SkASSERT(texture); + return texture; + } + return NULL; +} + +// MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs +void GrResourceProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) { + ASSERT_SINGLE_OWNER + SkASSERT(key.isValid()); + if (this->isAbandoned() || !proxy) { + return; + } + + GrTexture* texture = proxy->instantiate(this); + if (!texture) { + return; + } + + this->assignUniqueKeyToResource(key, texture); +} + +// MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs +sk_sp GrResourceProvider::findProxyByUniqueKey(const GrUniqueKey& key) { + ASSERT_SINGLE_OWNER + + sk_sp texture(this->findAndRefTextureByUniqueKey(key)); + if (!texture) { + return nullptr; + } + + return GrSurfaceProxy::MakeWrapped(std::move(texture)); +} + const GrBuffer* GrResourceProvider::createInstancedIndexBuffer(const uint16_t* pattern, int patternSize, int reps, @@ -33,7 +275,7 @@ const GrBuffer* GrResourceProvider::createInstancedIndexBuffer(const uint16_t* p const GrUniqueKey& key) { size_t bufferSize = patternSize * reps * sizeof(uint16_t); - // This is typically used in GrBatchs, so we assume kNoPendingIO. + // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO. GrBuffer* buffer = this->createBuffer(bufferSize, kIndex_GrBufferType, kStatic_GrAccessPattern, kNoPendingIO_Flag); if (!buffer) { @@ -110,10 +352,7 @@ GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedTyp // bin by pow2 with a reasonable min static const size_t MIN_SIZE = 1 << 12; - size_t allocSize = size > (1u << 31) - ? size_t(SkTMin(uint64_t(SIZE_MAX), uint64_t(GrNextPow2(uint32_t(uint64_t(size) >> 32))) << 32)) - : size_t(GrNextPow2(uint32_t(size))); - allocSize = SkTMax(allocSize, MIN_SIZE); + size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size)); GrScratchKey key; GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key); @@ -138,29 +377,6 @@ GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedTyp return buffer; } -GrBatchAtlas* GrResourceProvider::createAtlas(GrPixelConfig config, - int width, int height, - int numPlotsX, int numPlotsY, - GrBatchAtlas::EvictionFunc func, void* data) { - GrSurfaceDesc desc; - desc.fFlags = kNone_GrSurfaceFlags; - desc.fWidth = width; - desc.fHeight = height; - desc.fConfig = config; - - // We don't want to flush the context so we claim we're in the middle of flushing so as to - // guarantee we do not recieve a texture with pending IO - // TODO: Determine how to avoid having to do this. (https://bug.skia.org/4156) - static const uint32_t kFlags = GrResourceProvider::kNoPendingIO_Flag; - GrTexture* texture = this->createApproxTexture(desc, kFlags); - if (!texture) { - return nullptr; - } - GrBatchAtlas* atlas = new GrBatchAtlas(texture, numPlotsX, numPlotsY); - atlas->registerEvictionCallback(func, data); - return atlas; -} - GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) { SkASSERT(rt); if (rt->renderTargetPriv().getStencilAttachment()) { @@ -187,7 +403,7 @@ GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* // Need to try and create a new stencil stencil = this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height); if (stencil) { - stencil->resourcePriv().setUniqueKey(sbKey); + this->assignUniqueKeyToResource(sbKey, stencil); newStencil = true; } } @@ -208,10 +424,23 @@ GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* return rt->renderTargetPriv().getStencilAttachment(); } -GrRenderTarget* GrResourceProvider::wrapBackendTextureAsRenderTarget( - const GrBackendTextureDesc& desc) { +sk_sp GrResourceProvider::wrapBackendTextureAsRenderTarget( + const GrBackendTextureDesc& desc) +{ if (this->isAbandoned()) { return nullptr; } return this->gpu()->wrapBackendTextureAsRenderTarget(desc); } + +sk_sp SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore() { + return fGpu->makeSemaphore(); +} + +void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp semaphore) { + semaphore->resetGpu(fGpu); +} + +void GrResourceProvider::releaseOwnershipOfSemaphore(sk_sp semaphore) { + semaphore->resetGpu(nullptr); +} diff --git a/gfx/skia/skia/src/gpu/GrResourceProvider.h b/gfx/skia/skia/src/gpu/GrResourceProvider.h index c0922c0a0184..91dd09f01d7a 100644 --- a/gfx/skia/skia/src/gpu/GrResourceProvider.h +++ b/gfx/skia/skia/src/gpu/GrResourceProvider.h @@ -8,12 +8,10 @@ #ifndef GrResourceProvider_DEFINED #define GrResourceProvider_DEFINED -#include "GrBatchAtlas.h" #include "GrBuffer.h" -#include "GrTextureProvider.h" +#include "GrGpu.h" #include "GrPathRange.h" -class GrBatchAtlas; class GrPath; class GrRenderTarget; class GrSingleOwner; @@ -24,15 +22,12 @@ class SkPath; class SkTypeface; /** - * An extension of the texture provider for arbitrary resource types. This class is intended for - * use within the Gr code base, not by clients or extensions (e.g. third party GrProcessor - * derivatives). + * A factory for arbitrary resource types. This class is intended for use within the Gr code base. * - * This currently inherits from GrTextureProvider non-publically to force callers to provider - * make a flags (pendingIO) decision and not use the GrTP methods that don't take flags. This - * can be relaxed once https://bug.skia.org/4156 is fixed. + * Some members force callers to make a flags (pendingIO) decision. This can be relaxed once + * https://bug.skia.org/4156 is fixed. */ -class GrResourceProvider : protected GrTextureProvider { +class GrResourceProvider { public: GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner); @@ -40,6 +35,72 @@ public: return static_cast(this->findAndRefResourceByUniqueKey(key)); } + /////////////////////////////////////////////////////////////////////////// + // Textures + + /** + * Creates a new texture in the resource cache and returns it. The caller owns a + * ref on the returned texture which must be balanced by a call to unref. + * + * @param desc Description of the texture properties. + * @param budgeted Does the texture count against the resource cache budget? + * @param texels A contiguous array of mipmap levels + * @param mipLevelCount The amount of elements in the texels array + */ + sk_sp createMipMappedTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, + const GrMipLevel* texels, int mipLevelCount, + uint32_t flags = 0, + SkDestinationSurfaceColorMode mipColorMode = + SkDestinationSurfaceColorMode::kLegacy); + + /** Assigns a unique key to the texture. The texture will be findable via this key using + findTextureByUniqueKey(). If an existing texture has this key, it's key will be removed. */ + void assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy*); + + /** Finds a texture by unique key. If the texture is found it is ref'ed and returned. */ + sk_sp findProxyByUniqueKey(const GrUniqueKey& key); + + /** + * Finds a texture that approximately matches the descriptor. Will be at least as large in width + * and height as desc specifies. If desc specifies that the texture should be a render target + * then result will be a render target. Format and sample count will always match the request. + * The contents of the texture are undefined. The caller owns a ref on the returned texture and + * must balance with a call to unref. + */ + GrTexture* createApproxTexture(const GrSurfaceDesc&, uint32_t flags); + + /** Create an exact fit texture with no initial data to upload. + */ + sk_sp createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, + uint32_t flags = 0); + + /////////////////////////////////////////////////////////////////////////// + // Wrapped Backend Surfaces + + /** + * Wraps an existing texture with a GrTexture object. + * + * OpenGL: if the object is a texture Gr may change its GL texture params + * when it is drawn. + * + * @return GrTexture object or NULL on failure. + */ + sk_sp wrapBackendTexture(const GrBackendTextureDesc& desc, + GrWrapOwnership = kBorrow_GrWrapOwnership); + + /** + * Wraps an existing render target with a GrRenderTarget object. It is + * similar to wrapBackendTexture but can be used to draw into surfaces + * that are not also textures (e.g. FBO 0 in OpenGL, or an MSAA buffer that + * the client will resolve to a texture). Currently wrapped render targets + * always use the kBorrow_GrWrapOwnership semantics. + * + * @return GrRenderTarget object or NULL on failure. + */ + sk_sp wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc); + + static const int kMinScratchTextureSize; + /** * Either finds and refs, or creates an index buffer for instanced drawing with a specific * pattern if the index buffer is not found. If the return is non-null, the caller owns @@ -88,24 +149,24 @@ public: GrPathRange* createGlyphs(const SkTypeface*, const SkScalerContextEffects&, const SkDescriptor*, const GrStyle&); - using GrTextureProvider::assignUniqueKeyToResource; - using GrTextureProvider::findAndRefResourceByUniqueKey; - using GrTextureProvider::findAndRefTextureByUniqueKey; - using GrTextureProvider::abandon; - + /** These flags govern which scratch resources we are allowed to return */ enum Flags { + kExact_Flag = 0x1, + /** If the caller intends to do direct reads/writes to/from the CPU then this flag must be - * set when accessing resources during a GrDrawTarget flush. This includes the execution of - * GrBatch objects. The reason is that these memory operations are done immediately and + * set when accessing resources during a GrOpList flush. This includes the execution of + * GrOp objects. The reason is that these memory operations are done immediately and * will occur out of order WRT the operations being flushed. * Make this automatic: https://bug.skia.org/4156 */ - kNoPendingIO_Flag = 0x1, + kNoPendingIO_Flag = 0x2, + + kNoCreate_Flag = 0x4, /** Normally the caps may indicate a preference for client-side buffers. Set this flag when * creating a buffer to guarantee it resides in GPU memory. */ - kRequireGpuMemory_Flag = 0x2, + kRequireGpuMemory_Flag = 0x8, }; /** @@ -122,29 +183,6 @@ public: GrBuffer* createBuffer(size_t size, GrBufferType intendedType, GrAccessPattern, uint32_t flags, const void* data = nullptr); - GrTexture* createApproxTexture(const GrSurfaceDesc& desc, uint32_t flags) { - SkASSERT(0 == flags || kNoPendingIO_Flag == flags); - return this->internalCreateApproxTexture(desc, flags); - } - - /** Returns a GrBatchAtlas. This function can be called anywhere, but the returned atlas should - * only be used inside of GrBatch::generateGeometry - * @param GrPixelConfig The pixel config which this atlas will store - * @param width width in pixels of the atlas - * @param height height in pixels of the atlas - * @param numPlotsX The number of plots the atlas should be broken up into in the X - * direction - * @param numPlotsY The number of plots the atlas should be broken up into in the Y - * direction - * @param func An eviction function which will be called whenever the atlas has to - * evict data - * @param data User supplied data which will be passed into func whenver an - * eviction occurs - * - * @return An initialized GrBatchAtlas, or nullptr if creation fails - */ - GrBatchAtlas* createAtlas(GrPixelConfig, int width, int height, int numPlotsX, int numPlotsY, - GrBatchAtlas::EvictionFunc func, void* data); /** * If passed in render target already has a stencil buffer, return it. Otherwise attempt to @@ -152,8 +190,6 @@ public: */ GrStencilAttachment* attachStencilAttachment(GrRenderTarget* rt); - const GrCaps* caps() { return this->gpu()->caps(); } - /** * Wraps an existing texture with a GrRenderTarget object. This is useful when the provided * texture has a format that cannot be textured from by Skia, but we want to raster to it. @@ -163,9 +199,63 @@ public: * * @return GrRenderTarget object or NULL on failure. */ - GrRenderTarget* wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc& desc); + sk_sp wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc& desc); + + /** + * Assigns a unique key to a resource. If the key is associated with another resource that + * association is removed and replaced by this resource. + */ + void assignUniqueKeyToResource(const GrUniqueKey&, GrGpuResource*); + + /** + * Finds a resource in the cache, based on the specified key. This is intended for use in + * conjunction with addResourceToCache(). The return value will be NULL if not found. The + * caller must balance with a call to unref(). + */ + GrGpuResource* findAndRefResourceByUniqueKey(const GrUniqueKey&); + + sk_sp SK_WARN_UNUSED_RESULT makeSemaphore(); + + // Takes the GrSemaphore and sets the ownership of the semaphore to the GrGpu object used by + // this class. This call is only used when passing a GrSemaphore from one context to another. + void takeOwnershipOfSemaphore(sk_sp); + // Takes the GrSemaphore and resets the ownership of the semaphore so that it is not owned by + // any GrGpu. A follow up call to takeOwnershipofSemaphore must be made so that the underlying + // semaphore can be deleted. This call is only used when passing a GrSemaphore from one context + // to another. + void releaseOwnershipOfSemaphore(sk_sp); + + void abandon() { + fCache = nullptr; + fGpu = nullptr; + } + + // 'proxy' is about to be used as a texture src or drawn to. This query can be used to + // determine if it is going to need a texture domain or a full clear. + static bool IsFunctionallyExact(GrSurfaceProxy* proxy); + + const GrCaps* caps() const { return fCaps.get(); } private: + GrTexture* findAndRefTextureByUniqueKey(const GrUniqueKey& key); + void assignUniqueKeyToTexture(const GrUniqueKey& key, GrTexture* texture) { + SkASSERT(key.isValid()); + this->assignUniqueKeyToResource(key, texture); + } + + GrTexture* refScratchTexture(const GrSurfaceDesc&, uint32_t scratchTextureFlags); + + GrResourceCache* cache() { return fCache; } + const GrResourceCache* cache() const { return fCache; } + + GrGpu* gpu() { return fGpu; } + const GrGpu* gpu() const { return fGpu; } + + bool isAbandoned() const { + SkASSERT(SkToBool(fGpu) == SkToBool(fCache)); + return !SkToBool(fCache); + } + const GrBuffer* createInstancedIndexBuffer(const uint16_t* pattern, int patternSize, int reps, @@ -174,9 +264,13 @@ private: const GrBuffer* createQuadIndexBuffer(); - GrUniqueKey fQuadIndexBufferKey; + GrResourceCache* fCache; + GrGpu* fGpu; + sk_sp fCaps; + GrUniqueKey fQuadIndexBufferKey; - typedef GrTextureProvider INHERITED; + // In debug builds we guard against improper thread handling + SkDEBUGCODE(mutable GrSingleOwner* fSingleOwner;) }; #endif diff --git a/gfx/skia/skia/src/gpu/GrSWMaskHelper.cpp b/gfx/skia/skia/src/gpu/GrSWMaskHelper.cpp index 7bc26af145c5..2068734614ff 100644 --- a/gfx/skia/skia/src/gpu/GrSWMaskHelper.cpp +++ b/gfx/skia/skia/src/gpu/GrSWMaskHelper.cpp @@ -9,14 +9,17 @@ #include "GrCaps.h" #include "GrContext.h" -#include "batches/GrDrawBatch.h" -#include "GrDrawContext.h" +#include "GrContextPriv.h" #include "GrPipelineBuilder.h" +#include "GrRenderTargetContext.h" #include "GrShape.h" +#include "GrSurfaceContext.h" +#include "GrTextureProxy.h" +#include "ops/GrDrawOp.h" #include "SkDistanceFieldGen.h" -#include "batches/GrRectBatchFactory.h" +#include "ops/GrRectOpFactory.h" /* * Convert a boolean operation into a transfer mode code @@ -38,12 +41,11 @@ static SkBlendMode op_to_mode(SkRegion::Op op) { /** * Draw a single rect element of the clip stack into the accumulation bitmap */ -void GrSWMaskHelper::drawRect(const SkRect& rect, SkRegion::Op op, - bool antiAlias, uint8_t alpha) { +void GrSWMaskHelper::drawRect(const SkRect& rect, SkRegion::Op op, GrAA aa, uint8_t alpha) { SkPaint paint; paint.setBlendMode(op_to_mode(op)); - paint.setAntiAlias(antiAlias); + paint.setAntiAlias(GrAA::kYes == aa); paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha)); fDraw.drawRect(rect, paint); @@ -52,12 +54,11 @@ void GrSWMaskHelper::drawRect(const SkRect& rect, SkRegion::Op op, /** * Draw a single path element of the clip stack into the accumulation bitmap */ -void GrSWMaskHelper::drawShape(const GrShape& shape, SkRegion::Op op, bool antiAlias, - uint8_t alpha) { +void GrSWMaskHelper::drawShape(const GrShape& shape, SkRegion::Op op, GrAA aa, uint8_t alpha) { SkPaint paint; - paint.setPathEffect(sk_ref_sp(shape.style().pathEffect())); + paint.setPathEffect(shape.style().refPathEffect()); shape.style().strokeRec().applyToPaint(&paint); - paint.setAntiAlias(antiAlias); + paint.setAntiAlias(GrAA::kYes == aa); SkPath path; shape.asPath(&path); @@ -96,33 +97,27 @@ bool GrSWMaskHelper::init(const SkIRect& resultBounds, const SkMatrix* matrix) { return true; } -/** - * Get a texture (from the texture cache) of the correct size & format. - */ -GrTexture* GrSWMaskHelper::createTexture(TextureType textureType) { +sk_sp GrSWMaskHelper::toTextureProxy(GrContext* context, SkBackingFit fit) { GrSurfaceDesc desc; + desc.fOrigin = kTopLeft_GrSurfaceOrigin; desc.fWidth = fPixels.width(); desc.fHeight = fPixels.height(); desc.fConfig = kAlpha_8_GrPixelConfig; - if (TextureType::kApproximateFit == textureType) { - return fTexProvider->createApproxTexture(desc); - } else { - return fTexProvider->createTexture(desc, SkBudgeted::kYes); + sk_sp sContext = context->contextPriv().makeDeferredSurfaceContext( + desc, + fit, + SkBudgeted::kYes); + if (!sContext || !sContext->asTextureProxy()) { + return nullptr; } -} -/** - * Move the result of the software mask generation back to the gpu - */ -void GrSWMaskHelper::toTexture(GrTexture *texture) { - // Since we're uploading to it, and it's compressed, 'texture' shouldn't - // have a render target. - SkASSERT(!texture->asRenderTarget()); - - texture->writePixels(0, 0, fPixels.width(), fPixels.height(), texture->config(), - fPixels.addr(), fPixels.rowBytes()); + SkImageInfo ii = SkImageInfo::MakeA8(desc.fWidth, desc.fHeight); + if (!sContext->writePixels(ii, fPixels.addr(), fPixels.rowBytes(), 0, 0)) { + return nullptr; + } + return sContext->asTextureProxyRef(); } /** @@ -138,33 +133,26 @@ void GrSWMaskHelper::toSDF(unsigned char* sdf) { * Software rasterizes shape to A8 mask and uploads the result to a scratch texture. Returns the * resulting texture on success; nullptr on failure. */ -GrTexture* GrSWMaskHelper::DrawShapeMaskToTexture(GrTextureProvider* texProvider, - const GrShape& shape, - const SkIRect& resultBounds, - bool antiAlias, - TextureType textureType, - const SkMatrix* matrix) { - GrSWMaskHelper helper(texProvider); +sk_sp GrSWMaskHelper::DrawShapeMaskToTexture(GrContext* context, + const GrShape& shape, + const SkIRect& resultBounds, + GrAA aa, + SkBackingFit fit, + const SkMatrix* matrix) { + GrSWMaskHelper helper; if (!helper.init(resultBounds, matrix)) { return nullptr; } - helper.drawShape(shape, SkRegion::kReplace_Op, antiAlias, 0xFF); + helper.drawShape(shape, SkRegion::kReplace_Op, aa, 0xFF); - GrTexture* texture(helper.createTexture(textureType)); - if (!texture) { - return nullptr; - } - - helper.toTexture(texture); - - return texture; + return helper.toTextureProxy(context, fit); } -void GrSWMaskHelper::DrawToTargetWithShapeMask(GrTexture* texture, - GrDrawContext* drawContext, - const GrPaint& paint, +void GrSWMaskHelper::DrawToTargetWithShapeMask(sk_sp proxy, + GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, @@ -175,27 +163,22 @@ void GrSWMaskHelper::DrawToTargetWithShapeMask(GrTexture* texture, return; } + GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider(); + SkRect dstRect = SkRect::Make(deviceSpaceRectToDraw); // We use device coords to compute the texture coordinates. We take the device coords and apply // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling // matrix to normalized coords. - SkMatrix maskMatrix; - maskMatrix.setIDiv(texture->width(), texture->height()); - maskMatrix.preTranslate(SkIntToScalar(-textureOriginInDeviceSpace.fX), - SkIntToScalar(-textureOriginInDeviceSpace.fY)); + SkMatrix maskMatrix = SkMatrix::MakeTrans(SkIntToScalar(-textureOriginInDeviceSpace.fX), + SkIntToScalar(-textureOriginInDeviceSpace.fY)); maskMatrix.preConcat(viewMatrix); - GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint)); + std::unique_ptr op = GrRectOpFactory::MakeNonAAFill( + paint.getColor(), SkMatrix::I(), dstRect, nullptr, &invert); + paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make( + resourceProvider, std::move(proxy), nullptr, maskMatrix, + GrSamplerParams::kNone_FilterMode)); + GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); pipelineBuilder.setUserStencil(&userStencilSettings); - - pipelineBuilder.addCoverageFragmentProcessor( - GrSimpleTextureEffect::Make(texture, - nullptr, - maskMatrix, - GrTextureParams::kNone_FilterMode)); - - SkAutoTUnref batch(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), - SkMatrix::I(), - dstRect, nullptr, &invert)); - drawContext->drawBatch(pipelineBuilder, clip, batch); + renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); } diff --git a/gfx/skia/skia/src/gpu/GrSWMaskHelper.h b/gfx/skia/skia/src/gpu/GrSWMaskHelper.h index 46520a91bea3..62c1bbf29245 100644 --- a/gfx/skia/skia/src/gpu/GrSWMaskHelper.h +++ b/gfx/skia/skia/src/gpu/GrSWMaskHelper.h @@ -9,7 +9,7 @@ #define GrSWMaskHelper_DEFINED #include "GrColor.h" -#include "GrTextureProvider.h" +#include "GrRenderTargetContext.h" #include "SkAutoPixmapStorage.h" #include "SkBitmap.h" #include "SkDraw.h" @@ -21,7 +21,6 @@ class GrClip; class GrPaint; class GrShape; -class GrTextureProvider; class GrStyle; class GrTexture; struct GrUserStencilSettings; @@ -42,7 +41,7 @@ struct GrUserStencilSettings; */ class GrSWMaskHelper : SkNoncopyable { public: - GrSWMaskHelper(GrTextureProvider* texProvider) : fTexProvider(texProvider) { } + GrSWMaskHelper() { } // set up the internal state in preparation for draws. Since many masks // may be accumulated in the helper during creation, "resultBounds" @@ -51,13 +50,12 @@ public: bool init(const SkIRect& resultBounds, const SkMatrix* matrix); // Draw a single rect into the accumulation bitmap using the specified op - void drawRect(const SkRect& rect, SkRegion::Op op, bool antiAlias, uint8_t alpha); + void drawRect(const SkRect& rect, SkRegion::Op op, GrAA, uint8_t alpha); // Draw a single path into the accumuation bitmap using the specified op - void drawShape(const GrShape&, SkRegion::Op op, bool antiAlias, uint8_t alpha); + void drawShape(const GrShape&, SkRegion::Op op, GrAA, uint8_t alpha); - // Move the mask generation results from the internal bitmap to the gpu. - void toTexture(GrTexture* texture); + sk_sp toTextureProxy(GrContext*, SkBackingFit fit); // Convert mask generation results to a signed distance field void toSDF(unsigned char* sdf); @@ -67,27 +65,21 @@ public: fPixels.erase(SkColorSetARGB(alpha, 0xFF, 0xFF, 0xFF)); } - - enum class TextureType { - kExactFit, - kApproximateFit - }; - // Canonical usage utility that draws a single path and uploads it // to the GPU. The result is returned. - static GrTexture* DrawShapeMaskToTexture(GrTextureProvider*, - const GrShape&, - const SkIRect& resultBounds, - bool antiAlias, - TextureType, - const SkMatrix* matrix); + static sk_sp DrawShapeMaskToTexture(GrContext*, + const GrShape&, + const SkIRect& resultBounds, + GrAA, + SkBackingFit, + const SkMatrix* matrix); // This utility draws a path mask generated by DrawShapeMaskToTexture using a provided paint. // The rectangle is drawn in device space. The 'viewMatrix' will be used to ensure the correct // local coords are provided to any fragment processors in the paint. - static void DrawToTargetWithShapeMask(GrTexture* texture, - GrDrawContext*, - const GrPaint& paint, + static void DrawToTargetWithShapeMask(sk_sp, + GrRenderTargetContext*, + GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, const GrClip&, const SkMatrix& viewMatrix, @@ -95,11 +87,6 @@ public: const SkIRect& deviceSpaceRectToDraw); private: - // Helper function to get a scratch texture suitable for capturing the - // result (i.e., right size & format) - GrTexture* createTexture(TextureType); - - GrTextureProvider* fTexProvider; SkMatrix fMatrix; SkAutoPixmapStorage fPixels; SkDraw fDraw; diff --git a/gfx/skia/skia/src/gpu/GrSemaphore.h b/gfx/skia/skia/src/gpu/GrSemaphore.h new file mode 100644 index 000000000000..b4843ff78034 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrSemaphore.h @@ -0,0 +1,31 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSemaphore_DEFINED +#define GrSemaphore_DEFINED + +#include "SkRefCnt.h" + +class GrGpu; + +class GrSemaphore : public SkRefCnt { +private: + // This function should only be used in the case of exporting and importing a GrSemaphore object + // from one GrContext to another. When exporting, the GrSemaphore should be set to a null GrGpu, + // and when importing it should be set to the GrGpu of the current context. Once exported, a + // GrSemaphore should not be used with its old context. + void resetGpu(const GrGpu* gpu) { fGpu = gpu; } + +protected: + explicit GrSemaphore(const GrGpu* gpu) : fGpu(gpu) {} + + friend class GrResourceProvider; // resetGpu + + const GrGpu* fGpu; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.cpp b/gfx/skia/skia/src/gpu/GrShaderCaps.cpp similarity index 58% rename from gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.cpp rename to gfx/skia/skia/src/gpu/GrShaderCaps.cpp index b33e3082ecdc..636b955ab726 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.cpp +++ b/gfx/skia/skia/src/gpu/GrShaderCaps.cpp @@ -6,15 +6,49 @@ */ -#include "GrGLSLCaps.h" +#include "GrShaderCaps.h" #include "GrContextOptions.h" //////////////////////////////////////////////////////////////////////////////////////////// -GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) { - fGLSLGeneration = k330_GrGLSLGeneration; +static const char* shader_type_to_string(GrShaderType type) { + switch (type) { + case kVertex_GrShaderType: + return "vertex"; + case kGeometry_GrShaderType: + return "geometry"; + case kFragment_GrShaderType: + return "fragment"; + } + return ""; +} +static const char* precision_to_string(GrSLPrecision p) { + switch (p) { + case kLow_GrSLPrecision: + return "low"; + case kMedium_GrSLPrecision: + return "medium"; + case kHigh_GrSLPrecision: + return "high"; + default: + SkFAIL("Unexpected precision type."); + return ""; + } +} + +GrShaderCaps::GrShaderCaps(const GrContextOptions& options) { + fGLSLGeneration = k330_GrGLSLGeneration; + fShaderDerivativeSupport = false; + fGeometryShaderSupport = false; + fPathRenderingSupport = false; + fDstReadInShaderSupport = false; + fDualSourceBlendingSupport = false; + fIntegerSupport = false; + fTexelBufferSupport = false; + fImageLoadStoreSupport = false; + fShaderPrecisionVaries = false; fDropsTileOnZeroDivide = false; fFBFetchSupport = false; fFBFetchNeedsCustomOutput = false; @@ -23,7 +57,9 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) { fCanUseAnyFunctionInShader = true; fCanUseMinAndAbsTogether = true; fMustForceNegatedAtanParamToFloat = false; + fAtan2ImplementedAsAtanYOverX = false; fRequiresLocalOutputColorForFBFetch = false; + fMustImplementGSInvocationsWithLoop = false; fFlatInterpolationSupport = false; fNoPerspectiveInterpolationSupport = false; fMultisampleInterpolationSupport = false; @@ -31,6 +67,7 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) { fSampleMaskOverrideCoverageSupport = false; fExternalTextureSupport = false; fTexelFetchSupport = false; + fVersionDeclString = nullptr; fShaderDerivativeExtensionString = nullptr; fFragCoordConventionsExtensionString = nullptr; @@ -42,15 +79,46 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) { fSampleVariablesExtensionString = nullptr; fFBFetchColorName = nullptr; fFBFetchExtensionString = nullptr; + fImageLoadStoreExtensionString = nullptr; fMaxVertexSamplers = 0; fMaxGeometrySamplers = 0; fMaxFragmentSamplers = 0; fMaxCombinedSamplers = 0; + fMaxVertexImageStorages = 0; + fMaxGeometryImageStorages = 0; + fMaxFragmentImageStorages = 0; + fMaxCombinedImageStorages = 0; fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction; } -SkString GrGLSLCaps::dump() const { - SkString r = INHERITED::dump(); +SkString GrShaderCaps::dump() const { + SkString r; + static const char* gNY[] = { "NO", "YES" }; + r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]); + r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]); + r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]); + r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]); + r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]); + r.appendf("Integer Support : %s\n", gNY[fIntegerSupport]); + r.appendf("Texel Buffer Support : %s\n", gNY[fTexelBufferSupport]); + r.appendf("Image Load Store Support : %s\n", gNY[fImageLoadStoreSupport]); + + r.appendf("Shader Float Precisions (varies: %s):\n", gNY[fShaderPrecisionVaries]); + + for (int s = 0; s < kGrShaderTypeCount; ++s) { + GrShaderType shaderType = static_cast(s); + r.appendf("\t%s:\n", shader_type_to_string(shaderType)); + for (int p = 0; p < kGrSLPrecisionCount; ++p) { + if (fFloatPrecisions[s][p].supported()) { + GrSLPrecision precision = static_cast(p); + r.appendf("\t\t%s: log_low: %d log_high: %d bits: %d\n", + precision_to_string(precision), + fFloatPrecisions[s][p].fLogRangeLow, + fFloatPrecisions[s][p].fLogRangeHigh, + fFloatPrecisions[s][p].fBits); + } + } + } static const char* kAdvBlendEqInteractionStr[] = { "Not Supported", @@ -76,6 +144,8 @@ SkString GrGLSLCaps::dump() const { "YES" : "NO")); r.appendf("Must use local out color for FBFetch: %s\n", (fRequiresLocalOutputColorForFBFetch ? "YES" : "NO")); + r.appendf("Must implement geo shader invocations with loop : %s\n", + (fMustImplementGSInvocationsWithLoop ? "YES" : "NO")); r.appendf("Flat interpolation support: %s\n", (fFlatInterpolationSupport ? "YES" : "NO")); r.appendf("No perspective interpolation support: %s\n", (fNoPerspectiveInterpolationSupport ? "YES" : "NO")); @@ -90,12 +160,16 @@ SkString GrGLSLCaps::dump() const { r.appendf("Max GS Samplers: %d\n", fMaxGeometrySamplers); r.appendf("Max FS Samplers: %d\n", fMaxFragmentSamplers); r.appendf("Max Combined Samplers: %d\n", fMaxFragmentSamplers); + r.appendf("Max VS Image Storages: %d\n", fMaxVertexImageStorages); + r.appendf("Max GS Image Storages: %d\n", fMaxGeometryImageStorages); + r.appendf("Max FS Image Storages: %d\n", fMaxFragmentImageStorages); + r.appendf("Max Combined Image Storages: %d\n", fMaxFragmentImageStorages); r.appendf("Advanced blend equation interaction: %s\n", kAdvBlendEqInteractionStr[fAdvBlendEqInteraction]); return r; } -void GrGLSLCaps::initSamplerPrecisionTable() { +void GrShaderCaps::initSamplerPrecisionTable() { // Determine the largest precision qualifiers that are effectively the same as lowp/mediump. // e.g. if lowp == mediump, then use mediump instead of lowp. GrSLPrecision effectiveMediumP[kGrShaderTypeCount]; @@ -129,26 +203,26 @@ void GrGLSLCaps::initSamplerPrecisionTable() { } uint8_t* table = fSamplerPrecisions[visibility]; - table[kUnknown_GrPixelConfig] = kDefault_GrSLPrecision; - table[kAlpha_8_GrPixelConfig] = lowp; - table[kIndex_8_GrPixelConfig] = lowp; - table[kRGB_565_GrPixelConfig] = lowp; - table[kRGBA_4444_GrPixelConfig] = lowp; - table[kRGBA_8888_GrPixelConfig] = lowp; - table[kBGRA_8888_GrPixelConfig] = lowp; - table[kSRGBA_8888_GrPixelConfig] = lowp; - table[kSBGRA_8888_GrPixelConfig] = lowp; - table[kETC1_GrPixelConfig] = lowp; - table[kLATC_GrPixelConfig] = lowp; - table[kR11_EAC_GrPixelConfig] = lowp; - table[kASTC_12x12_GrPixelConfig] = lowp; - table[kRGBA_float_GrPixelConfig] = kHigh_GrSLPrecision; - table[kAlpha_half_GrPixelConfig] = mediump; - table[kRGBA_half_GrPixelConfig] = mediump; + table[kUnknown_GrPixelConfig] = lowp; + table[kAlpha_8_GrPixelConfig] = lowp; + table[kGray_8_GrPixelConfig] = lowp; + table[kRGB_565_GrPixelConfig] = lowp; + table[kRGBA_4444_GrPixelConfig] = lowp; + table[kRGBA_8888_GrPixelConfig] = lowp; + table[kBGRA_8888_GrPixelConfig] = lowp; + table[kSRGBA_8888_GrPixelConfig] = lowp; + table[kSBGRA_8888_GrPixelConfig] = lowp; + table[kRGBA_8888_sint_GrPixelConfig] = lowp; + table[kETC1_GrPixelConfig] = lowp; + table[kRGBA_float_GrPixelConfig] = kHigh_GrSLPrecision; + table[kRG_float_GrPixelConfig] = kHigh_GrSLPrecision; + table[kAlpha_half_GrPixelConfig] = mediump; + table[kRGBA_half_GrPixelConfig] = mediump; - GR_STATIC_ASSERT(16 == kGrPixelConfigCnt); + GR_STATIC_ASSERT(15 == kGrPixelConfigCnt); } } -void GrGLSLCaps::onApplyOptionsOverrides(const GrContextOptions& options) { +void GrShaderCaps::applyOptionsOverrides(const GrContextOptions& options) { + fDualSourceBlendingSupport = fDualSourceBlendingSupport && !options.fSuppressDualSourceBlending; } diff --git a/gfx/skia/skia/src/gpu/GrShaderVar.cpp b/gfx/skia/skia/src/gpu/GrShaderVar.cpp new file mode 100644 index 000000000000..e938c36d010f --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrShaderVar.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#include "GrShaderVar.h" +#include "GrShaderCaps.h" + +static const char* type_modifier_string(GrShaderVar::TypeModifier t) { + switch (t) { + case GrShaderVar::kNone_TypeModifier: return ""; + case GrShaderVar::kIn_TypeModifier: return "in"; + case GrShaderVar::kInOut_TypeModifier: return "inout"; + case GrShaderVar::kOut_TypeModifier: return "out"; + case GrShaderVar::kUniform_TypeModifier: return "uniform"; + } + SkFAIL("Unknown shader variable type modifier."); + return ""; +} + +void GrShaderVar::setImageStorageFormat(GrImageStorageFormat format) { + const char* formatStr = nullptr; + switch (format) { + case GrImageStorageFormat::kRGBA8: + formatStr = "rgba8"; + break; + case GrImageStorageFormat::kRGBA8i: + formatStr = "rgba8i"; + break; + case GrImageStorageFormat::kRGBA16f: + formatStr = "rgba16f"; + break; + case GrImageStorageFormat::kRGBA32f: + formatStr = "rgba32f"; + break; + } + this->addLayoutQualifier(formatStr); + SkASSERT(formatStr); +} + +void GrShaderVar::setMemoryModel(GrSLMemoryModel model) { + switch (model) { + case GrSLMemoryModel::kNone: + return; + case GrSLMemoryModel::kCoherent: + this->addModifier("coherent"); + return; + case GrSLMemoryModel::kVolatile: + this->addModifier("volatile"); + return; + } + SkFAIL("Unknown memory model."); +} + +void GrShaderVar::setRestrict(GrSLRestrict restrict) { + switch (restrict) { + case GrSLRestrict::kNo: + return; + case GrSLRestrict::kYes: + this->addModifier("restrict"); + return; + } + SkFAIL("Unknown restrict."); +} + +void GrShaderVar::setIOType(GrIOType ioType) { + switch (ioType) { + case kRW_GrIOType: + return; + case kRead_GrIOType: + this->addModifier("readonly"); + return; + case kWrite_GrIOType: + this->addModifier("writeonly"); + return; + } + SkFAIL("Unknown io type."); +} + +void GrShaderVar::appendDecl(const GrShaderCaps* shaderCaps, SkString* out) const { + SkASSERT(kDefault_GrSLPrecision == fPrecision || GrSLTypeAcceptsPrecision(fType)); + SkString layout = fLayoutQualifier; + if (!fLayoutQualifier.isEmpty()) { + out->appendf("layout(%s) ", fLayoutQualifier.c_str()); + } + out->append(fExtraModifiers); + if (this->getTypeModifier() != kNone_TypeModifier) { + out->append(type_modifier_string(this->getTypeModifier())); + out->append(" "); + } + GrSLType effectiveType = this->getType(); + if (shaderCaps->usesPrecisionModifiers() && GrSLTypeAcceptsPrecision(effectiveType)) { + // Desktop GLSL has added precision qualifiers but they don't do anything. + out->appendf("%s ", GrGLSLPrecisionString(fPrecision)); + } + if (this->isArray()) { + if (this->isUnsizedArray()) { + out->appendf("%s %s[]", + GrGLSLTypeString(effectiveType), + this->getName().c_str()); + } else { + SkASSERT(this->getArrayCount() > 0); + out->appendf("%s %s[%d]", + GrGLSLTypeString(effectiveType), + this->getName().c_str(), + this->getArrayCount()); + } + } else { + out->appendf("%s %s", + GrGLSLTypeString(effectiveType), + this->getName().c_str()); + } +} diff --git a/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.cpp b/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.cpp index c22ce6600547..0e7cecd97c32 100644 --- a/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.cpp @@ -8,17 +8,18 @@ #include "GrSoftwarePathRenderer.h" #include "GrAuditTrail.h" #include "GrClip.h" -#include "GrPipelineBuilder.h" #include "GrGpuResourcePriv.h" +#include "GrPipelineBuilder.h" +#include "GrResourceProvider.h" #include "GrSWMaskHelper.h" -#include "GrTextureProvider.h" -#include "batches/GrRectBatchFactory.h" +#include "ops/GrRectOpFactory.h" //////////////////////////////////////////////////////////////////////////////// bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { // Pass on any style that applies. The caller will apply the style if a suitable renderer is // not found and try again with the new GrShape. - return !args.fShape->style().applies() && SkToBool(fTexProvider); + return !args.fShape->style().applies() && SkToBool(fResourceProvider) && + (args.fAAType == GrAAType::kCoverage || args.fAAType == GrAAType::kNone); } //////////////////////////////////////////////////////////////////////////////// @@ -30,6 +31,14 @@ static bool get_unclipped_shape_dev_bounds(const GrShape& shape, const SkMatrix& } SkRect shapeDevBounds; matrix.mapRect(&shapeDevBounds, shapeBounds); + // Even though these are "unclipped" bounds we still clip to the int32_t range. + // This is the largest int32_t that is representable exactly as a float. The next 63 larger ints + // would round down to this value when cast to a float, but who really cares. + // INT32_MIN is exactly representable. + static constexpr int32_t kMaxInt = 2147483520; + if (!shapeDevBounds.intersect(SkRect::MakeLTRB(INT32_MIN, INT32_MIN, kMaxInt, kMaxInt))) { + return false; + } shapeDevBounds.roundOut(devBounds); return true; } @@ -60,25 +69,23 @@ static bool get_shape_and_clip_bounds(int width, int height, //////////////////////////////////////////////////////////////////////////////// -void GrSoftwarePathRenderer::DrawNonAARect(GrDrawContext* drawContext, - const GrPaint& paint, +void GrSoftwarePathRenderer::DrawNonAARect(GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, const SkRect& rect, const SkMatrix& localMatrix) { - SkAutoTUnref batch(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), - viewMatrix, rect, - nullptr, &localMatrix)); + std::unique_ptr op(GrRectOpFactory::MakeNonAAFill( + paint.getColor(), viewMatrix, rect, nullptr, &localMatrix)); - GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint)); + GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); pipelineBuilder.setUserStencil(&userStencilSettings); - - drawContext->drawBatch(pipelineBuilder, clip, batch); + renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); } -void GrSoftwarePathRenderer::DrawAroundInvPath(GrDrawContext* drawContext, - const GrPaint& paint, +void GrSoftwarePathRenderer::DrawAroundInvPath(GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, @@ -93,25 +100,25 @@ void GrSoftwarePathRenderer::DrawAroundInvPath(GrDrawContext* drawContext, if (devClipBounds.fTop < devPathBounds.fTop) { rect.iset(devClipBounds.fLeft, devClipBounds.fTop, devClipBounds.fRight, devPathBounds.fTop); - DrawNonAARect(drawContext, paint, userStencilSettings, clip, - SkMatrix::I(), rect, invert); + DrawNonAARect(renderTargetContext, GrPaint(paint), userStencilSettings, clip, SkMatrix::I(), + rect, invert); } if (devClipBounds.fLeft < devPathBounds.fLeft) { rect.iset(devClipBounds.fLeft, devPathBounds.fTop, devPathBounds.fLeft, devPathBounds.fBottom); - DrawNonAARect(drawContext, paint, userStencilSettings, clip, - SkMatrix::I(), rect, invert); + DrawNonAARect(renderTargetContext, GrPaint(paint), userStencilSettings, clip, SkMatrix::I(), + rect, invert); } if (devClipBounds.fRight > devPathBounds.fRight) { rect.iset(devPathBounds.fRight, devPathBounds.fTop, devClipBounds.fRight, devPathBounds.fBottom); - DrawNonAARect(drawContext, paint, userStencilSettings, clip, - SkMatrix::I(), rect, invert); + DrawNonAARect(renderTargetContext, GrPaint(paint), userStencilSettings, clip, SkMatrix::I(), + rect, invert); } if (devClipBounds.fBottom > devPathBounds.fBottom) { rect.iset(devClipBounds.fLeft, devPathBounds.fBottom, devClipBounds.fRight, devClipBounds.fBottom); - DrawNonAARect(drawContext, paint, userStencilSettings, clip, + DrawNonAARect(renderTargetContext, std::move(paint), userStencilSettings, clip, SkMatrix::I(), rect, invert); } } @@ -119,9 +126,9 @@ void GrSoftwarePathRenderer::DrawAroundInvPath(GrDrawContext* drawContext, //////////////////////////////////////////////////////////////////////////////// // return true on success; false on failure bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrSoftwarePathRenderer::onDrawPath"); - if (!fTexProvider) { + if (!fResourceProvider) { return false; } @@ -135,18 +142,18 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) { // To prevent overloading the cache with entries during animations we limit the cache of masks // to cases where the matrix preserves axis alignment. bool useCache = fAllowCaching && !inverseFilled && args.fViewMatrix->preservesAxisAlignment() && - args.fShape->hasUnstyledKey() && args.fAntiAlias; + args.fShape->hasUnstyledKey() && GrAAType::kCoverage == args.fAAType; - if (!get_shape_and_clip_bounds(args.fDrawContext->width(), args.fDrawContext->height(), + if (!get_shape_and_clip_bounds(args.fRenderTargetContext->width(), + args.fRenderTargetContext->height(), *args.fClip, *args.fShape, *args.fViewMatrix, &unclippedDevShapeBounds, &clippedDevShapeBounds, &devClipBounds)) { if (inverseFilled) { - DrawAroundInvPath(args.fDrawContext, *args.fPaint, *args.fUserStencilSettings, - *args.fClip, - *args.fViewMatrix, devClipBounds, unclippedDevShapeBounds); - + DrawAroundInvPath(args.fRenderTargetContext, std::move(args.fPaint), + *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, + devClipBounds, unclippedDevShapeBounds); } return true; } @@ -158,7 +165,7 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) { int unclippedHeight = unclippedDevShapeBounds.height(); int unclippedArea = unclippedWidth * unclippedHeight; int clippedArea = clippedDevShapeBounds.width() * clippedDevShapeBounds.height(); - int maxTextureSize = args.fDrawContext->caps()->maxTextureSize(); + int maxTextureSize = args.fRenderTargetContext->caps()->maxTextureSize(); if (unclippedArea > 2 * clippedArea || unclippedWidth > maxTextureSize || unclippedHeight > maxTextureSize) { useCache = false; @@ -192,37 +199,36 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) { builder[3] = SkFloat2Bits(ky); builder[4] = fracX | (fracY >> 8); args.fShape->writeUnstyledKey(&builder[5]); + // FIXME: Doesn't the key need to consider whether we're using AA or not? In practice that + // should always be true, though. } - sk_sp texture; + sk_sp proxy; if (useCache) { - texture.reset(args.fResourceProvider->findAndRefTextureByUniqueKey(maskKey)); + proxy = fResourceProvider->findProxyByUniqueKey(maskKey); } - if (!texture) { - GrSWMaskHelper::TextureType type = useCache ? GrSWMaskHelper::TextureType::kExactFit - : GrSWMaskHelper::TextureType::kApproximateFit; - texture.reset(GrSWMaskHelper::DrawShapeMaskToTexture(fTexProvider, *args.fShape, - *boundsForMask, args.fAntiAlias, - type, args.fViewMatrix)); - if (!texture) { - return false; - } - if (useCache) { - texture->resourcePriv().setUniqueKey(maskKey); - } + if (!proxy) { + SkBackingFit fit = useCache ? SkBackingFit::kExact : SkBackingFit::kApprox; + GrAA aa = GrAAType::kCoverage == args.fAAType ? GrAA::kYes : GrAA::kNo; + proxy = GrSWMaskHelper::DrawShapeMaskToTexture(args.fContext, *args.fShape, + *boundsForMask, aa, + fit, args.fViewMatrix); + if (!proxy) { + return false; + } + if (useCache) { + fResourceProvider->assignUniqueKeyToProxy(maskKey, proxy.get()); + } } - - GrSWMaskHelper::DrawToTargetWithShapeMask(texture.get(), args.fDrawContext, *args.fPaint, - *args.fUserStencilSettings, - *args.fClip, *args.fViewMatrix, - SkIPoint {boundsForMask->fLeft, boundsForMask->fTop}, - *boundsForMask); - if (inverseFilled) { - DrawAroundInvPath(args.fDrawContext, *args.fPaint, *args.fUserStencilSettings, - *args.fClip, - *args.fViewMatrix, devClipBounds, unclippedDevShapeBounds); + DrawAroundInvPath(args.fRenderTargetContext, GrPaint(args.fPaint), + *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, devClipBounds, + unclippedDevShapeBounds); } + GrSWMaskHelper::DrawToTargetWithShapeMask( + std::move(proxy), args.fRenderTargetContext, std::move(args.fPaint), + *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, + SkIPoint{boundsForMask->fLeft, boundsForMask->fTop}, *boundsForMask); return true; } diff --git a/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.h b/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.h index 72d967323ef3..c8d2f8b8d802 100644 --- a/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.h +++ b/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.h @@ -10,7 +10,7 @@ #include "GrPathRenderer.h" -class GrTextureProvider; +class GrResourceProvider; /** * This class uses the software side to render a path to an SkBitmap and @@ -18,19 +18,19 @@ class GrTextureProvider; */ class GrSoftwarePathRenderer : public GrPathRenderer { public: - GrSoftwarePathRenderer(GrTextureProvider* texProvider, bool allowCaching) - : fTexProvider(texProvider) + GrSoftwarePathRenderer(GrResourceProvider* resourceProvider, bool allowCaching) + : fResourceProvider(resourceProvider) , fAllowCaching(allowCaching) {} private: - static void DrawNonAARect(GrDrawContext* drawContext, - const GrPaint& paint, + static void DrawNonAARect(GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, const SkRect& rect, const SkMatrix& localMatrix); - static void DrawAroundInvPath(GrDrawContext* drawContext, - const GrPaint& paint, + static void DrawAroundInvPath(GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, @@ -46,7 +46,7 @@ private: bool onDrawPath(const DrawPathArgs&) override; private: - GrTextureProvider* fTexProvider; + GrResourceProvider* fResourceProvider; bool fAllowCaching; typedef GrPathRenderer INHERITED; diff --git a/gfx/skia/skia/src/gpu/GrStencilAttachment.h b/gfx/skia/skia/src/gpu/GrStencilAttachment.h index 0ed3c8b27cab..08d6799f6239 100644 --- a/gfx/skia/skia/src/gpu/GrStencilAttachment.h +++ b/gfx/skia/skia/src/gpu/GrStencilAttachment.h @@ -28,24 +28,6 @@ public: int bits() const { return fBits; } int numSamples() const { return fSampleCnt; } - // called to note the last clip drawn to this buffer. - void setLastClip(int32_t clipStackGenID, - const SkIRect& clipSpaceRect, - const SkIPoint clipOrigin) { - fLastClipStackGenID = clipStackGenID; - fLastClipStackRect = clipSpaceRect; - fLastClipOrigin = clipOrigin; - } - - // called to determine if we have to render the clip into SB. - bool mustRenderClip(int32_t clipStackGenID, - const SkIRect& clipSpaceRect, - const SkIPoint& clipOrigin) const { - return fLastClipStackGenID != clipStackGenID || - fLastClipOrigin != clipOrigin || - !fLastClipStackRect.contains(clipSpaceRect); - } - // We create a unique stencil buffer at each width, height and sampleCnt and share it for // all render targets that require a stencil with those params. static void ComputeSharedStencilAttachmentKey(int width, int height, int sampleCnt, @@ -57,9 +39,7 @@ protected: , fWidth(width) , fHeight(height) , fBits(bits) - , fSampleCnt(sampleCnt) - , fLastClipStackGenID(SkClipStack::kInvalidGenID) { - fLastClipStackRect.setEmpty(); + , fSampleCnt(sampleCnt) { } private: @@ -69,10 +49,6 @@ private: int fBits; int fSampleCnt; - int32_t fLastClipStackGenID; - SkIRect fLastClipStackRect; - SkIPoint fLastClipOrigin; - typedef GrGpuResource INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/GrStencilSettings.cpp b/gfx/skia/skia/src/gpu/GrStencilSettings.cpp index d3216db0ce65..7790c5506b57 100644 --- a/gfx/skia/skia/src/gpu/GrStencilSettings.cpp +++ b/gfx/skia/skia/src/gpu/GrStencilSettings.cpp @@ -28,6 +28,7 @@ void GrStencilSettings::reset(const GrUserStencilSettings& user, bool hasStencil int numStencilBits) { uint16_t frontFlags = user.fFrontFlags[hasStencilClip]; if (frontFlags & kSingleSided_StencilFlag) { + SkASSERT(frontFlags == user.fBackFlags[hasStencilClip]); fFlags = frontFlags; if (!this->isDisabled()) { fFront.reset(user.fFront, hasStencilClip, numStencilBits); @@ -77,6 +78,8 @@ bool GrStencilSettings::operator==(const GrStencilSettings& that) const { } if (kSingleSided_StencilFlag & (fFlags & that.fFlags)) { return 0 == memcmp(&fFront, &that.fFront, sizeof(Face)); // Both are single sided. + } else if (kSingleSided_StencilFlag & (fFlags | that.fFlags)) { + return false; } else { return 0 == memcmp(&fFront, &that.fFront, 2 * sizeof(Face)); GR_STATIC_ASSERT(sizeof(Face) == diff --git a/gfx/skia/skia/src/gpu/GrStyle.cpp b/gfx/skia/skia/src/gpu/GrStyle.cpp index 153cade919ef..69953558043c 100644 --- a/gfx/skia/skia/src/gpu/GrStyle.cpp +++ b/gfx/skia/skia/src/gpu/GrStyle.cpp @@ -103,7 +103,7 @@ void GrStyle::WriteKey(uint32_t *key, const GrStyle &style, Apply apply, SkScala SkASSERT(KeySize(style, apply) == i); } -void GrStyle::initPathEffect(SkPathEffect* pe) { +void GrStyle::initPathEffect(sk_sp pe) { SkASSERT(!fPathEffect); SkASSERT(SkPathEffect::kNone_DashType == fDashInfo.fType); SkASSERT(0 == fDashInfo.fIntervals.count()); @@ -119,10 +119,10 @@ void GrStyle::initPathEffect(SkPathEffect* pe) { fDashInfo.fPhase = info.fPhase; info.fIntervals = fDashInfo.fIntervals.get(); pe->asADash(&info); - fPathEffect.reset(SkSafeRef(pe)); + fPathEffect = std::move(pe); } } else { - fPathEffect.reset(SkSafeRef(pe)); + fPathEffect = std::move(pe); } } diff --git a/gfx/skia/skia/src/gpu/GrStyle.h b/gfx/skia/skia/src/gpu/GrStyle.h index 9091166fe1b5..a5599f9b1bdf 100644 --- a/gfx/skia/skia/src/gpu/GrStyle.h +++ b/gfx/skia/skia/src/gpu/GrStyle.h @@ -77,19 +77,19 @@ public: explicit GrStyle(SkStrokeRec::InitStyle initStyle) : fStrokeRec(initStyle) {} - GrStyle(const SkStrokeRec& strokeRec, SkPathEffect* pe) : fStrokeRec(strokeRec) { - this->initPathEffect(pe); + GrStyle(const SkStrokeRec& strokeRec, sk_sp pe) : fStrokeRec(strokeRec) { + this->initPathEffect(std::move(pe)); } GrStyle(const GrStyle& that) : fStrokeRec(SkStrokeRec::kFill_InitStyle) { *this = that; } explicit GrStyle(const SkPaint& paint) : fStrokeRec(paint) { - this->initPathEffect(paint.getPathEffect()); + this->initPathEffect(paint.refPathEffect()); } explicit GrStyle(const SkPaint& paint, SkPaint::Style overrideStyle) : fStrokeRec(paint, overrideStyle) { - this->initPathEffect(paint.getPathEffect()); + this->initPathEffect(paint.refPathEffect()); } GrStyle& operator=(const GrStyle& that) { @@ -116,6 +116,7 @@ public: bool isSimpleHairline() const { return fStrokeRec.isHairlineStyle() && !fPathEffect; } SkPathEffect* pathEffect() const { return fPathEffect.get(); } + sk_sp refPathEffect() const { return fPathEffect; } bool hasPathEffect() const { return SkToBool(fPathEffect.get()); } @@ -182,7 +183,7 @@ public: } private: - void initPathEffect(SkPathEffect* pe); + void initPathEffect(sk_sp pe); struct DashInfo { DashInfo() : fType(SkPathEffect::kNone_DashType) {} diff --git a/gfx/skia/skia/src/gpu/GrSurface.cpp b/gfx/skia/skia/src/gpu/GrSurface.cpp index 3c9368e67f16..4c9e3b4c1e38 100644 --- a/gfx/skia/skia/src/gpu/GrSurface.cpp +++ b/gfx/skia/skia/src/gpu/GrSurface.cpp @@ -7,16 +7,29 @@ #include "GrSurface.h" #include "GrContext.h" +#include "GrOpList.h" #include "GrSurfacePriv.h" +#include "GrTexture.h" -#include "SkBitmap.h" -#include "SkGrPriv.h" -#include "SkImageEncoder.h" -#include +#include "SkGr.h" +#include "SkMathPriv.h" -size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc) { +GrSurface::~GrSurface() { + if (fLastOpList) { + fLastOpList->clearTarget(); + } + SkSafeUnref(fLastOpList); + + // check that invokeReleaseProc has been called (if needed) + SkASSERT(NULL == fReleaseProc); +} + +size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2) { size_t size; + int width = useNextPow2 ? GrNextPow2(desc.fWidth) : desc.fWidth; + int height = useNextPow2 ? GrNextPow2(desc.fHeight) : desc.fHeight; + bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); if (isRenderTarget) { // We own one color value for each MSAA sample. @@ -27,15 +40,19 @@ size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc) { } SkASSERT(kUnknown_GrPixelConfig != desc.fConfig); SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig)); - size_t colorBytes = GrBytesPerPixel(desc.fConfig); - SkASSERT(colorBytes > 0); + size_t colorBytes = (size_t) width * height * GrBytesPerPixel(desc.fConfig); - size = (size_t) colorValuesPerPixel * desc.fWidth * desc.fHeight * colorBytes; + // This would be a nice assert to have (i.e., we aren't creating 0 width/height surfaces). + // Unfortunately Chromium seems to want to do this. + //SkASSERT(colorBytes > 0); + + size = colorValuesPerPixel * colorBytes; + size += colorBytes/3; // in case we have to mipmap } else { if (GrPixelConfigIsCompressed(desc.fConfig)) { - size = GrCompressedFormatDataSize(desc.fConfig, desc.fWidth, desc.fHeight); + size = GrCompressedFormatDataSize(desc.fConfig, width, height); } else { - size = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig); + size = (size_t) width * height * GrBytesPerPixel(desc.fConfig); } size += size/3; // in case we have to mipmap @@ -44,6 +61,35 @@ size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc) { return size; } +size_t GrSurface::ComputeSize(const GrSurfaceDesc& desc, + int colorSamplesPerPixel, + bool hasMIPMaps, + bool useNextPow2) { + size_t colorSize; + + int width = useNextPow2 ? GrNextPow2(desc.fWidth) : desc.fWidth; + int height = useNextPow2 ? GrNextPow2(desc.fHeight) : desc.fHeight; + + SkASSERT(kUnknown_GrPixelConfig != desc.fConfig); + if (GrPixelConfigIsCompressed(desc.fConfig)) { + colorSize = GrCompressedFormatDataSize(desc.fConfig, width, height); + } else { + colorSize = (size_t) width * height * GrBytesPerPixel(desc.fConfig); + } + SkASSERT(colorSize > 0); + + size_t finalSize = colorSamplesPerPixel * colorSize; + + if (hasMIPMaps) { + // We don't have to worry about the mipmaps being a different size than + // we'd expect because we never change fDesc.fWidth/fHeight. + finalSize += colorSize/3; + } + + SkASSERT(finalSize <= WorstCaseSize(desc, useNextPow2)); + return finalSize; +} + template static bool adjust_params(int surfaceWidth, int surfaceHeight, size_t bpp, @@ -93,63 +139,6 @@ bool GrSurfacePriv::AdjustWritePixelParams(int surfaceWidth, ////////////////////////////////////////////////////////////////////////////// -bool GrSurface::writePixels(int left, int top, int width, int height, - GrPixelConfig config, const void* buffer, size_t rowBytes, - uint32_t pixelOpsFlags) { - // go through context so that all necessary flushing occurs - GrContext* context = this->getContext(); - if (nullptr == context) { - return false; - } - return context->writeSurfacePixels(this, left, top, width, height, config, buffer, - rowBytes, pixelOpsFlags); -} - -bool GrSurface::readPixels(int left, int top, int width, int height, - GrPixelConfig config, void* buffer, size_t rowBytes, - uint32_t pixelOpsFlags) { - // go through context so that all necessary flushing occurs - GrContext* context = this->getContext(); - if (nullptr == context) { - return false; - } - return context->readSurfacePixels(this, left, top, width, height, config, buffer, - rowBytes, pixelOpsFlags); -} - -// TODO: This should probably be a non-member helper function. It might only be needed in -// debug or developer builds. -bool GrSurface::savePixels(const char* filename) { - SkBitmap bm; - if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(this->width(), this->height()))) { - return false; - } - - bool result = this->readPixels(0, 0, this->width(), this->height(), kSkia8888_GrPixelConfig, - bm.getPixels()); - if (!result) { - SkDebugf("------ failed to read pixels for %s\n", filename); - return false; - } - - // remove any previous version of this file - remove(filename); - - if (!SkImageEncoder::EncodeFile(filename, bm, SkImageEncoder::kPNG_Type, 100)) { - SkDebugf("------ failed to encode %s\n", filename); - remove(filename); // remove any partial file - return false; - } - - return true; -} - -void GrSurface::flushWrites() { - if (!this->wasDestroyed()) { - this->getContext()->flushSurfaceWrites(this); - } -} - bool GrSurface::hasPendingRead() const { const GrTexture* thisTex = this->asTexture(); if (thisTex && thisTex->internalHasPendingRead()) { @@ -195,3 +184,15 @@ void GrSurface::onAbandon() { this->invokeReleaseProc(); this->INHERITED::onAbandon(); } + +void GrSurface::setLastOpList(GrOpList* opList) { + if (fLastOpList) { + // The non-MDB world never closes so we can't check this condition +#ifdef ENABLE_MDB + SkASSERT(fLastOpList->isClosed()); +#endif + fLastOpList->clearTarget(); + } + + SkRefCnt_SafeAssign(fLastOpList, opList); +} diff --git a/gfx/skia/skia/src/gpu/GrSurfaceContext.cpp b/gfx/skia/skia/src/gpu/GrSurfaceContext.cpp new file mode 100644 index 000000000000..6b6a94272072 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrSurfaceContext.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrSurfaceContext.h" + +#include "GrContextPriv.h" +#include "SkColorSpace_Base.h" +#include "SkGr.h" + +#include "../private/GrAuditTrail.h" + + +// In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress +// GrOpLists to be picked up and added to by renderTargetContexts lower in the call +// stack. When this occurs with a closed GrOpList, a new one will be allocated +// when the renderTargetContext attempts to use it (via getOpList). +GrSurfaceContext::GrSurfaceContext(GrContext* context, + GrDrawingManager* drawingMgr, + sk_sp colorSpace, + GrAuditTrail* auditTrail, + GrSingleOwner* singleOwner) + : fContext(context) + , fColorSpace(std::move(colorSpace)) + , fAuditTrail(auditTrail) + , fDrawingManager(drawingMgr) +#ifdef SK_DEBUG + , fSingleOwner(singleOwner) +#endif +{ +} + +bool GrSurfaceContext::readPixels(const SkImageInfo& dstInfo, void* dstBuffer, + size_t dstRowBytes, int x, int y, uint32_t flags) { + // TODO: teach GrRenderTarget to take ImageInfo directly to specify the src pixels + GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo, *fContext->caps()); + if (kUnknown_GrPixelConfig == config) { + return false; + } + + // TODO: this seems to duplicate code in SkImage_Gpu::onReadPixels + if (kUnpremul_SkAlphaType == dstInfo.alphaType()) { + flags |= GrContextPriv::kUnpremul_PixelOpsFlag; + } + + return fContext->contextPriv().readSurfacePixels(this->asSurfaceProxy(), + this->getColorSpace(), x, y, + dstInfo.width(), dstInfo.height(), config, + dstInfo.colorSpace(), + dstBuffer, dstRowBytes, flags); +} + +bool GrSurfaceContext::writePixels(const SkImageInfo& srcInfo, const void* srcBuffer, + size_t srcRowBytes, int x, int y, uint32_t flags) { + // TODO: teach GrRenderTarget to take ImageInfo directly to specify the src pixels + GrPixelConfig config = SkImageInfo2GrPixelConfig(srcInfo, *fContext->caps()); + if (kUnknown_GrPixelConfig == config) { + return false; + } + if (kUnpremul_SkAlphaType == srcInfo.alphaType()) { + flags |= GrContextPriv::kUnpremul_PixelOpsFlag; + } + + return fContext->contextPriv().writeSurfacePixels(this->asSurfaceProxy(), + this->getColorSpace(), x, y, + srcInfo.width(), srcInfo.height(), + config, srcInfo.colorSpace(), + srcBuffer, srcRowBytes, flags); +} diff --git a/gfx/skia/skia/src/gpu/GrSurfaceContext.h b/gfx/skia/skia/src/gpu/GrSurfaceContext.h new file mode 100644 index 000000000000..bab753c06989 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrSurfaceContext.h @@ -0,0 +1,139 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSurfaceContext_DEFINED +#define GrSurfaceContext_DEFINED + +#include "../private/GrSurfaceProxy.h" + +#include "SkRefCnt.h" + +class GrAuditTrail; +class GrContext; +class GrDrawingManager; +class GrRenderTargetContext; +class GrRenderTargetProxy; +class GrSingleOwner; +class GrSurface; +class GrSurfaceContextPriv; +class GrSurfaceProxy; +class GrTextureProxy; +struct SkIPoint; +struct SkIRect; + +/** + * A helper object to orchestrate commands for a particular surface + */ +class SK_API GrSurfaceContext : public SkRefCnt { +public: + ~GrSurfaceContext() override {} + + SkColorSpace* getColorSpace() const { return fColorSpace.get(); } + sk_sp refColorSpace() const { return fColorSpace; } + bool isGammaCorrect() const { return fColorSpace; } + + // TODO: these two calls would be way cooler if this object had a GrSurfaceProxy pointer + int width() const { return this->asSurfaceProxy()->width(); } + int height() const { return this->asSurfaceProxy()->height(); } + + /* + * Copy 'src' into the proxy backing this context + * @param src src of pixels + * @param srcRect the subset of 'src' to copy + * @param dstPoint the origin of the 'srcRect' in the destination coordinate space + * @return true if the copy succeeded; false otherwise + * + * Note: Notionally, 'srcRect' is clipped to 'src's extent with 'dstPoint' being adjusted. + * Then the 'srcRect' offset by 'dstPoint' is clipped against the dst's extent. + * The end result is only valid src pixels and dst pixels will be touched but the copied + * regions will not be shifted. + */ + bool copy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { + return this->onCopy(src, srcRect, dstPoint); + } + + bool copy(GrSurfaceProxy* src) { + return this->onCopy(src, + SkIRect::MakeWH(src->width(), src->height()), + SkIPoint::Make(0, 0)); + } + + /** + * Reads a rectangle of pixels from the render target context. + * @param dstInfo image info for the destination + * @param dstBuffer destination pixels for the read + * @param dstRowBytes bytes in a row of 'dstBuffer' + * @param x x offset w/in the render target context from which to read + * @param y y offset w/in the render target context from which to read + * + * @return true if the read succeeded, false if not. The read can fail because of an + * unsupported pixel config. + */ + bool readPixels(const SkImageInfo& dstInfo, void* dstBuffer, size_t dstRowBytes, + int x, int y, uint32_t flags = 0); + + /** + * Writes a rectangle of pixels [srcInfo, srcBuffer, srcRowbytes] into the + * renderTargetContext at the specified position. + * @param srcInfo image info for the source pixels + * @param srcBuffer source for the write + * @param srcRowBytes bytes in a row of 'srcBuffer' + * @param x x offset w/in the render target context at which to write + * @param y y offset w/in the render target context at which to write + * + * @return true if the write succeeded, false if not. The write can fail because of an + * unsupported pixel config. + */ + bool writePixels(const SkImageInfo& srcInfo, const void* srcBuffer, size_t srcRowBytes, + int x, int y, uint32_t flags = 0); + + // TODO: this is virtual b.c. this object doesn't have a pointer to the wrapped GrSurfaceProxy? + virtual GrSurfaceProxy* asSurfaceProxy() = 0; + virtual const GrSurfaceProxy* asSurfaceProxy() const = 0; + virtual sk_sp asSurfaceProxyRef() = 0; + + virtual GrTextureProxy* asTextureProxy() = 0; + virtual sk_sp asTextureProxyRef() = 0; + + virtual GrRenderTargetProxy* asRenderTargetProxy() = 0; + virtual sk_sp asRenderTargetProxyRef() = 0; + + virtual GrRenderTargetContext* asRenderTargetContext() { return nullptr; } + + GrAuditTrail* auditTrail() { return fAuditTrail; } + + // Provides access to functions that aren't part of the public API. + GrSurfaceContextPriv surfPriv(); + const GrSurfaceContextPriv surfPriv() const; + +protected: + friend class GrSurfaceContextPriv; + + GrSurfaceContext(GrContext*, GrDrawingManager*, + sk_sp, GrAuditTrail*, GrSingleOwner*); + + GrDrawingManager* drawingManager() { return fDrawingManager; } + const GrDrawingManager* drawingManager() const { return fDrawingManager; } + + SkDEBUGCODE(GrSingleOwner* singleOwner() { return fSingleOwner; }) + + GrContext* fContext; + sk_sp fColorSpace; + GrAuditTrail* fAuditTrail; + +private: + virtual bool onCopy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) = 0; + + GrDrawingManager* fDrawingManager; + + // In debug builds we guard against improper thread handling + SkDEBUGCODE(mutable GrSingleOwner* fSingleOwner;) + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrSurfaceContextPriv.h b/gfx/skia/skia/src/gpu/GrSurfaceContextPriv.h new file mode 100644 index 000000000000..bd3d2de21747 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrSurfaceContextPriv.h @@ -0,0 +1,45 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSurfaceContextPriv_DEFINED +#define GrSurfaceContextPriv_DEFINED + +#include "GrSurfaceContext.h" + +/** Class that adds methods to GrSurfaceContext that are only intended for use internal to + Skia. This class is purely a privileged window into GrSurfaceContext. It should never have + additional data members or virtual methods. */ +class GrSurfaceContextPriv { +public: + GrContext* getContext() { return fSurfaceContext->fContext; } + +private: + explicit GrSurfaceContextPriv(GrSurfaceContext* surfaceContext) + : fSurfaceContext(surfaceContext) { + } + + GrSurfaceContextPriv(const GrSurfaceContextPriv&) {} // unimpl + GrSurfaceContextPriv& operator=(const GrSurfaceContextPriv&); // unimpl + + // No taking addresses of this type. + const GrSurfaceContextPriv* operator&() const; + GrSurfaceContextPriv* operator&(); + + GrSurfaceContext* fSurfaceContext; + + friend class GrSurfaceContext; // to construct/copy this type. +}; + +inline GrSurfaceContextPriv GrSurfaceContext::surfPriv() { + return GrSurfaceContextPriv(this); +} + +inline const GrSurfaceContextPriv GrSurfaceContext::surfPriv() const { + return GrSurfaceContextPriv(const_cast(this)); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/GrSurfacePriv.h b/gfx/skia/skia/src/gpu/GrSurfacePriv.h index f2ba7baca4cf..c7ae6a41497d 100644 --- a/gfx/skia/skia/src/gpu/GrSurfacePriv.h +++ b/gfx/skia/skia/src/gpu/GrSurfacePriv.h @@ -33,12 +33,6 @@ public: const void** data, size_t* rowBytes); - /** - * Write the contents of the surface to a PNG. Returns true if successful. - * @param filename Full path to desired file - */ - bool savePixels(const char* filename) { return fSurface->savePixels(filename); } - bool hasPendingRead() const { return fSurface->hasPendingRead(); } bool hasPendingWrite() const { return fSurface->hasPendingWrite(); } bool hasPendingIO() const { return fSurface->hasPendingIO(); } diff --git a/gfx/skia/skia/src/gpu/GrSurfaceProxy.cpp b/gfx/skia/skia/src/gpu/GrSurfaceProxy.cpp index f5c401f67049..c9a36289d869 100644 --- a/gfx/skia/skia/src/gpu/GrSurfaceProxy.cpp +++ b/gfx/skia/skia/src/gpu/GrSurfaceProxy.cpp @@ -6,4 +6,337 @@ */ #include "GrSurfaceProxy.h" +#include "GrSurfaceProxyPriv.h" + +#include "GrCaps.h" +#include "GrContext.h" +#include "GrContextPriv.h" +#include "GrGpuResourcePriv.h" +#include "GrOpList.h" +#include "GrResourceProvider.h" +#include "GrSurfaceContext.h" +#include "GrTexturePriv.h" +#include "GrTextureRenderTargetProxy.h" + +#include "SkMathPriv.h" + +GrSurfaceProxy::GrSurfaceProxy(sk_sp surface, SkBackingFit fit) + : INHERITED(std::move(surface)) + , fDesc(fTarget->desc()) + , fFit(fit) + , fBudgeted(fTarget->resourcePriv().isBudgeted()) + , fFlags(0) + , fUniqueID(fTarget->uniqueID()) // Note: converting from unique resource ID to a proxy ID! + , fGpuMemorySize(kInvalidGpuMemorySize) + , fLastOpList(nullptr) { +} + +GrSurfaceProxy::~GrSurfaceProxy() { + if (fLastOpList) { + fLastOpList->clearTarget(); + } + SkSafeUnref(fLastOpList); +} + +GrSurface* GrSurfaceProxy::instantiate(GrResourceProvider* resourceProvider) { + if (fTarget) { + return fTarget; + } + + if (SkBackingFit::kApprox == fFit) { + fTarget = resourceProvider->createApproxTexture(fDesc, fFlags); + } else { + fTarget = resourceProvider->createTexture(fDesc, fBudgeted, fFlags).release(); + } + if (!fTarget) { + return nullptr; + } + + fTarget->asTexture()->texturePriv().setMipColorMode(fMipColorMode); + this->INHERITED::transferRefs(); + +#ifdef SK_DEBUG + if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) { + SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly()); + } +#endif + + return fTarget; +} + +int GrSurfaceProxy::worstCaseWidth(const GrCaps& caps) const { + if (fTarget) { + return fTarget->width(); + } + + if (SkBackingFit::kExact == fFit) { + return fDesc.fWidth; + } + + if (caps.reuseScratchTextures() || fDesc.fFlags & kRenderTarget_GrSurfaceFlag) { + return SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(fDesc.fWidth)); + } + + return fDesc.fWidth; +} + +int GrSurfaceProxy::worstCaseHeight(const GrCaps& caps) const { + if (fTarget) { + return fTarget->height(); + } + + if (SkBackingFit::kExact == fFit) { + return fDesc.fHeight; + } + + if (caps.reuseScratchTextures() || fDesc.fFlags & kRenderTarget_GrSurfaceFlag) { + return SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(fDesc.fHeight)); + } + + return fDesc.fHeight; +} + +void GrSurfaceProxy::setLastOpList(GrOpList* opList) { + if (fLastOpList) { + // The non-MDB world never closes so we can't check this condition +#ifdef ENABLE_MDB + SkASSERT(fLastOpList->isClosed()); +#endif + fLastOpList->clearTarget(); + } + + SkRefCnt_SafeAssign(fLastOpList, opList); +} + +GrRenderTargetOpList* GrSurfaceProxy::getLastRenderTargetOpList() { + return fLastOpList ? fLastOpList->asRenderTargetOpList() : nullptr; +} + +GrTextureOpList* GrSurfaceProxy::getLastTextureOpList() { + return fLastOpList ? fLastOpList->asTextureOpList() : nullptr; +} + +sk_sp GrSurfaceProxy::MakeWrapped(sk_sp surf) { + if (!surf) { + return nullptr; + } + + if (surf->asTexture()) { + if (surf->asRenderTarget()) { + return sk_sp(new GrTextureRenderTargetProxy(std::move(surf))); + } else { + return sk_sp(new GrTextureProxy(std::move(surf))); + } + } else { + SkASSERT(surf->asRenderTarget()); + + // Not texturable + return sk_sp(new GrRenderTargetProxy(std::move(surf))); + } +} + +sk_sp GrSurfaceProxy::MakeWrapped(sk_sp tex) { + if (!tex) { + return nullptr; + } + + if (tex->asRenderTarget()) { + return sk_sp(new GrTextureRenderTargetProxy(std::move(tex))); + } else { + return sk_sp(new GrTextureProxy(std::move(tex))); + } +} + +#include "GrResourceProvider.h" + +sk_sp GrSurfaceProxy::MakeDeferred(GrResourceProvider* resourceProvider, + const GrSurfaceDesc& desc, + SkBackingFit fit, + SkBudgeted budgeted, + uint32_t flags) { + SkASSERT(0 == flags || GrResourceProvider::kNoPendingIO_Flag == flags); + + const GrCaps* caps = resourceProvider->caps(); + + // TODO: move this logic into GrResourceProvider! + // TODO: share this testing code with check_texture_creation_params + if (GrPixelConfigIsCompressed(desc.fConfig)) { + if (SkBackingFit::kApprox == fit || kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { + // We don't allow scratch compressed textures and, apparently can't Y-flip compressed + // textures + return nullptr; + } + + if (!caps->npotTextureTileSupport() && (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight))) { + return nullptr; + } + } + + if (!caps->isConfigTexturable(desc.fConfig)) { + return nullptr; + } + + bool willBeRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); + if (willBeRT && !caps->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { + return nullptr; + } + + // We currently do not support multisampled textures + if (!willBeRT && desc.fSampleCnt > 0) { + return nullptr; + } + + int maxSize; + if (willBeRT) { + maxSize = caps->maxRenderTargetSize(); + } else { + maxSize = caps->maxTextureSize(); + } + + if (desc.fWidth > maxSize || desc.fHeight > maxSize) { + return nullptr; + } + + GrSurfaceDesc copyDesc = desc; + copyDesc.fSampleCnt = SkTMin(desc.fSampleCnt, caps->maxSampleCount()); + +#ifdef SK_DISABLE_DEFERRED_PROXIES + sk_sp tex; + + if (SkBackingFit::kApprox == fit) { + tex.reset(resourceProvider->createApproxTexture(copyDesc, flags)); + } else { + tex = resourceProvider->createTexture(copyDesc, budgeted, flags); + } + + if (!tex) { + return nullptr; + } + + return GrSurfaceProxy::MakeWrapped(std::move(tex)); +#else + if (willBeRT) { + // We know anything we instantiate later from this deferred path will be + // both texturable and renderable + return sk_sp(new GrTextureRenderTargetProxy(*caps, copyDesc, fit, + budgeted, flags)); + } + + return sk_sp(new GrTextureProxy(copyDesc, fit, budgeted, nullptr, 0, flags)); +#endif +} + +sk_sp GrSurfaceProxy::MakeDeferred(GrResourceProvider* resourceProvider, + const GrSurfaceDesc& desc, + SkBudgeted budgeted, + const void* srcData, + size_t rowBytes) { + if (srcData) { + GrMipLevel tempTexels; + GrMipLevel* texels = nullptr; + int levelCount = 0; + if (srcData) { + tempTexels.fPixels = srcData; + tempTexels.fRowBytes = rowBytes; + texels = &tempTexels; + levelCount = 1; + } + return resourceProvider->createMipMappedTexture(desc, budgeted, texels, levelCount); + } + + return GrSurfaceProxy::MakeDeferred(resourceProvider, desc, SkBackingFit::kExact, budgeted); +} + +sk_sp GrSurfaceProxy::MakeWrappedBackend(GrContext* context, + GrBackendTextureDesc& desc) { + sk_sp tex(context->resourceProvider()->wrapBackendTexture(desc)); + return GrSurfaceProxy::MakeWrapped(std::move(tex)); +} + +#ifdef SK_DEBUG +void GrSurfaceProxy::validate(GrContext* context) const { + if (fTarget) { + SkASSERT(fTarget->getContext() == context); + } + + INHERITED::validate(); +} +#endif + +sk_sp GrSurfaceProxy::Copy(GrContext* context, + GrSurfaceProxy* src, + SkIRect srcRect, + SkBudgeted budgeted) { + if (!srcRect.intersect(SkIRect::MakeWH(src->width(), src->height()))) { + return nullptr; + } + + GrSurfaceDesc dstDesc = src->desc(); + dstDesc.fWidth = srcRect.width(); + dstDesc.fHeight = srcRect.height(); + + sk_sp dstContext(context->contextPriv().makeDeferredSurfaceContext( + dstDesc, + SkBackingFit::kExact, + budgeted)); + if (!dstContext) { + return nullptr; + } + + if (!dstContext->copy(src, srcRect, SkIPoint::Make(0, 0))) { + return nullptr; + } + + return dstContext->asTextureProxyRef(); +} + +sk_sp GrSurfaceProxy::Copy(GrContext* context, GrSurfaceProxy* src, + SkBudgeted budgeted) { + return Copy(context, src, SkIRect::MakeWH(src->width(), src->height()), budgeted); +} + +sk_sp GrSurfaceProxy::TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc, + GrSurfaceProxy* srcProxy) { + + sk_sp dstContext(context->contextPriv().makeDeferredSurfaceContext( + dstDesc, + SkBackingFit::kExact, + SkBudgeted::kYes)); + if (!dstContext) { + return nullptr; + } + + if (!dstContext->copy(srcProxy)) { + return nullptr; + } + + return dstContext; +} + +void GrSurfaceProxyPriv::exactify() { + if (this->isExact()) { + return; + } + + SkASSERT(SkBackingFit::kApprox == fProxy->fFit); + + if (fProxy->fTarget) { + // The kApprox but already instantiated case. Setting the proxy's width & height to + // the instantiated width & height could have side-effects going forward, since we're + // obliterating the area of interest information. This call (exactify) only used + // when converting an SkSpecialImage to an SkImage so the proxy shouldn't be + // used for additional draws. + fProxy->fDesc.fWidth = fProxy->fTarget->width(); + fProxy->fDesc.fHeight = fProxy->fTarget->height(); + return; + } + + // The kApprox uninstantiated case. Making this proxy be exact should be okay. + // It could mess things up if prior decisions were based on the approximate size. + fProxy->fFit = SkBackingFit::kExact; + // If fGpuMemorySize is used when caching specialImages for the image filter DAG. If it has + // already been computed we want to leave it alone so that amount will be removed when + // the special image goes away. If it hasn't been computed yet it might as well compute the + // exact amount. +} diff --git a/gfx/skia/skia/src/gpu/GrSurfaceProxyPriv.h b/gfx/skia/skia/src/gpu/GrSurfaceProxyPriv.h new file mode 100644 index 000000000000..24c69939b79c --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrSurfaceProxyPriv.h @@ -0,0 +1,60 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSurfaceProxyPriv_DEFINED +#define GrSurfaceProxyPriv_DEFINED + +#include "GrSurfaceProxy.h" + +/** Class that adds methods to GrSurfaceProxy that are only intended for use internal to Skia. + This class is purely a privileged window into GrSurfaceProxy. It should never have additional + data members or virtual methods. */ +class GrSurfaceProxyPriv { +public: + // If the proxy is already instantiated, return its backing GrTexture; if not, + // return null + const GrTexture* peekTexture() const { + return fProxy->fTarget ? fProxy->fTarget->asTexture() : nullptr; + } + + // Beware! This call is only guaranteed to tell you if the proxy in question has + // any pending IO in its current state. It won't tell you about the IO state in the + // future when the proxy is actually used/instantiated. + bool hasPendingIO() const { return fProxy->hasPendingIO(); } + + // Beware! This call is only guaranteed to tell you if the proxy in question has + // any pending writes in its current state. It won't tell you about the IO state in the + // future when the proxy is actually used/instantiated. + bool hasPendingWrite() const { return fProxy->hasPendingWrite(); } + + // Don't abuse this call!!!!!!! + bool isExact() const { return SkBackingFit::kExact == fProxy->fFit; } + + // Don't. Just don't. + void exactify(); + +private: + explicit GrSurfaceProxyPriv(GrSurfaceProxy* proxy) : fProxy(proxy) {} + GrSurfaceProxyPriv(const GrSurfaceProxyPriv&) {} // unimpl + GrSurfaceProxyPriv& operator=(const GrSurfaceProxyPriv&); // unimpl + + // No taking addresses of this type. + const GrSurfaceProxyPriv* operator&() const; + GrSurfaceProxyPriv* operator&(); + + GrSurfaceProxy* fProxy; + + friend class GrSurfaceProxy; // to construct/copy this type. +}; + +inline GrSurfaceProxyPriv GrSurfaceProxy::priv() { return GrSurfaceProxyPriv(this); } + +inline const GrSurfaceProxyPriv GrSurfaceProxy::priv () const { + return GrSurfaceProxyPriv(const_cast(this)); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/GrTessellator.cpp b/gfx/skia/skia/src/gpu/GrTessellator.cpp index b06cd6362468..0ced572ba4b3 100644 --- a/gfx/skia/skia/src/gpu/GrTessellator.cpp +++ b/gfx/skia/skia/src/gpu/GrTessellator.cpp @@ -10,7 +10,7 @@ #include "GrDefaultGeoProcFactory.h" #include "GrPathUtils.h" -#include "SkChunkAlloc.h" +#include "SkArenaAlloc.h" #include "SkGeometry.h" #include "SkPath.h" @@ -30,16 +30,16 @@ * * Run steps 1-5 above to produce polygons. * 5b) Apply fill rules to extract boundary contours from the polygons (extract_boundaries()). - * 5c) Simplify boundaries to remove "pointy" vertices which cause inversions (simplify_boundary()). + * 5c) Simplify boundaries to remove "pointy" vertices that cause inversions (simplify_boundary()). * 5d) Displace edges by half a pixel inward and outward along their normals. Intersect to find * new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a new - * antialiased mesh from those vertices (boundary_to_aa_mesh()). + * antialiased mesh from those vertices (stroke_boundary()). * Run steps 3-6 above on the new mesh, and produce antialiased triangles. * * The vertex sorting in step (3) is a merge sort, since it plays well with the linked list * of vertices (and the necessity of inserting new vertices on intersection). * - * Stages (4) and (5) use an active edge list, which a list of all edges for which the + * Stages (4) and (5) use an active edge list -- a list of all edges for which the * sweep line has crossed the top vertex, but not the bottom vertex. It's sorted * left-to-right based on the point where both edges are active (when both top vertices * have been seen, so the "lower" top vertex of the two). If the top vertices are equal @@ -90,10 +90,10 @@ #define LOG(...) #endif -#define ALLOC_NEW(Type, args, alloc) new (alloc.allocThrow(sizeof(Type))) Type args - namespace { +const int kArenaChunkSize = 16 * 1024; + struct Vertex; struct Edge; struct Poly; @@ -145,6 +145,7 @@ struct Vertex { : fPoint(point), fPrev(nullptr), fNext(nullptr) , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr) , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr) + , fPartner(nullptr) , fProcessed(false) , fAlpha(alpha) #if LOGGING_ENABLED @@ -158,6 +159,7 @@ struct Vertex { Edge* fLastEdgeAbove; // " Edge* fFirstEdgeBelow; // Linked list of edges below this vertex. Edge* fLastEdgeBelow; // " + Vertex* fPartner; // Corresponding inner or outer vertex (for AA). bool fProcessed; // Has this vertex been seen in simplify()? uint8_t fAlpha; #if LOGGING_ENABLED @@ -174,26 +176,22 @@ struct AAParams { typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b); -struct Comparator { - CompareFunc sweep_lt; - CompareFunc sweep_gt; -}; - bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) { - return a.fX == b.fX ? a.fY > b.fY : a.fX < b.fX; + return a.fX < b.fX || (a.fX == b.fX && a.fY > b.fY); } bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) { - return a.fY == b.fY ? a.fX < b.fX : a.fY < b.fY; + return a.fY < b.fY || (a.fY == b.fY && a.fX < b.fX); } -bool sweep_gt_horiz(const SkPoint& a, const SkPoint& b) { - return a.fX == b.fX ? a.fY < b.fY : a.fX > b.fX; -} - -bool sweep_gt_vert(const SkPoint& a, const SkPoint& b) { - return a.fY == b.fY ? a.fX > b.fX : a.fY > b.fY; -} +struct Comparator { + enum class Direction { kVertical, kHorizontal }; + Comparator(Direction direction) : fDirection(direction) {} + bool sweep_lt(const SkPoint& a, const SkPoint& b) const { + return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) : sweep_lt_vert(a, b); + } + Direction fDirection; +}; inline void* emit_vertex(Vertex* v, const AAParams* aaParams, void* data) { if (!aaParams) { @@ -217,6 +215,9 @@ inline void* emit_vertex(Vertex* v, const AAParams* aaParams, void* data) { } void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, const AAParams* aaParams, void* data) { + LOG("emit_triangle (%g, %g) %d\n", v0->fPoint.fX, v0->fPoint.fY, v0->fAlpha); + LOG(" (%g, %g) %d\n", v1->fPoint.fX, v1->fPoint.fY, v1->fAlpha); + LOG(" (%g, %g) %d\n", v2->fPoint.fX, v2->fPoint.fY, v2->fAlpha); #if TESSELLATOR_WIREFRAME data = emit_vertex(v0, aaParams, data); data = emit_vertex(v1, aaParams, data); @@ -234,6 +235,7 @@ void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, const AAParams* aaParams struct VertexList { VertexList() : fHead(nullptr), fTail(nullptr) {} + VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {} Vertex* fHead; Vertex* fTail; void insert(Vertex* v, Vertex* prev, Vertex* next) { @@ -242,9 +244,24 @@ struct VertexList { void append(Vertex* v) { insert(v, fTail, nullptr); } + void append(const VertexList& list) { + if (!list.fHead) { + return; + } + if (fTail) { + fTail->fNext = list.fHead; + list.fHead->fPrev = fTail; + } else { + fHead = list.fHead; + } + fTail = list.fTail; + } void prepend(Vertex* v) { insert(v, nullptr, fHead); } + void remove(Vertex* v) { + list_remove(v, &fHead, &fTail); + } void close() { if (fHead && fTail) { fTail->fNext = fHead; @@ -260,11 +277,41 @@ inline void round(SkPoint* p) { p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f); } +// A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line. +struct Line { + Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {} + Line(const SkPoint& p, const SkPoint& q) + : fA(static_cast(q.fY) - p.fY) // a = dY + , fB(static_cast(p.fX) - q.fX) // b = -dX + , fC(static_cast(p.fY) * q.fX - // c = cross(q, p) + static_cast(p.fX) * q.fY) {} + double dist(const SkPoint& p) const { + return fA * p.fX + fB * p.fY + fC; + } + double magSq() const { + return fA * fA + fB * fB; + } + + // Compute the intersection of two (infinite) Lines. + bool intersect(const Line& other, SkPoint* point) { + double denom = fA * other.fB - fB * other.fA; + if (denom == 0.0) { + return false; + } + double scale = 1.0f / denom; + point->fX = SkDoubleToScalar((fB * other.fC - other.fB * fC) * scale); + point->fY = SkDoubleToScalar((other.fA * fC - fA * other.fC) * scale); + round(point); + return true; + } + double fA, fB, fC; +}; + /** * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf(). * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating - * point). For speed, that case is only tested by the callers which require it (e.g., + * point). For speed, that case is only tested by the callers that require it (e.g., * cleanup_active_edges()). Edges also handle checking for intersection with other edges. * Currently, this converts the edges to the parametric form, in order to avoid doing a division * until an intersection has been confirmed. This is slightly slower in the "found" case, but @@ -279,10 +326,12 @@ inline void round(SkPoint* p) { */ struct Edge { - Edge(Vertex* top, Vertex* bottom, int winding) + enum class Type { kInner, kOuter, kConnector }; + Edge(Vertex* top, Vertex* bottom, int winding, Type type) : fWinding(winding) , fTop(top) , fBottom(bottom) + , fType(type) , fLeft(nullptr) , fRight(nullptr) , fPrevEdgeAbove(nullptr) @@ -296,12 +345,13 @@ struct Edge { , fRightPolyPrev(nullptr) , fRightPolyNext(nullptr) , fUsedInLeftPoly(false) - , fUsedInRightPoly(false) { - recompute(); + , fUsedInRightPoly(false) + , fLine(top, bottom) { } int fWinding; // 1 == edge goes downward; -1 = edge goes upward. Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt). Vertex* fBottom; // The bottom vertex in vertex-sort-order. + Type fType; Edge* fLeft; // The linked list of edges in the active edge list. Edge* fRight; // " Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above". @@ -316,39 +366,34 @@ struct Edge { Edge* fRightPolyNext; bool fUsedInLeftPoly; bool fUsedInRightPoly; - double fDX; // The line equation for this edge, in implicit form. - double fDY; // fDY * x + fDX * y + fC = 0, for point (x, y) on the line. - double fC; + Line fLine; double dist(const SkPoint& p) const { - return fDY * p.fX - fDX * p.fY + fC; + return fLine.dist(p); } bool isRightOf(Vertex* v) const { - return dist(v->fPoint) < 0.0; + return fLine.dist(v->fPoint) < 0.0; } bool isLeftOf(Vertex* v) const { - return dist(v->fPoint) > 0.0; + return fLine.dist(v->fPoint) > 0.0; } void recompute() { - fDX = static_cast(fBottom->fPoint.fX) - fTop->fPoint.fX; - fDY = static_cast(fBottom->fPoint.fY) - fTop->fPoint.fY; - fC = static_cast(fTop->fPoint.fY) * fBottom->fPoint.fX - - static_cast(fTop->fPoint.fX) * fBottom->fPoint.fY; + fLine = Line(fTop, fBottom); } - bool intersect(const Edge& other, SkPoint* p) { + bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) { LOG("intersecting %g -> %g with %g -> %g\n", fTop->fID, fBottom->fID, other.fTop->fID, other.fBottom->fID); if (fTop == other.fTop || fBottom == other.fBottom) { return false; } - double denom = fDX * other.fDY - fDY * other.fDX; + double denom = fLine.fA * other.fLine.fB - fLine.fB * other.fLine.fA; if (denom == 0.0) { return false; } - double dx = static_cast(fTop->fPoint.fX) - other.fTop->fPoint.fX; - double dy = static_cast(fTop->fPoint.fY) - other.fTop->fPoint.fY; - double sNumer = dy * other.fDX - dx * other.fDY; - double tNumer = dy * fDX - dx * fDY; + double dx = static_cast(other.fTop->fPoint.fX) - fTop->fPoint.fX; + double dy = static_cast(other.fTop->fPoint.fY) - fTop->fPoint.fY; + double sNumer = dy * other.fLine.fB + dx * other.fLine.fA; + double tNumer = dy * fLine.fB + dx * fLine.fA; // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early. // This saves us doing the divide below unless absolutely necessary. if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom) @@ -357,28 +402,41 @@ struct Edge { } double s = sNumer / denom; SkASSERT(s >= 0.0 && s <= 1.0); - p->fX = SkDoubleToScalar(fTop->fPoint.fX + s * fDX); - p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fDY); + p->fX = SkDoubleToScalar(fTop->fPoint.fX - s * fLine.fB); + p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fLine.fA); + if (alpha) { + if (fType == Type::kConnector) { + *alpha = (1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha; + } else if (other.fType == Type::kConnector) { + double t = tNumer / denom; + *alpha = (1.0 - t) * other.fTop->fAlpha + t * other.fBottom->fAlpha; + } else if (fType == Type::kOuter && other.fType == Type::kOuter) { + *alpha = 0; + } else { + *alpha = 255; + } + } return true; } }; struct EdgeList { - EdgeList() : fHead(nullptr), fTail(nullptr), fNext(nullptr), fCount(0) {} + EdgeList() : fHead(nullptr), fTail(nullptr) {} Edge* fHead; Edge* fTail; - EdgeList* fNext; - int fCount; void insert(Edge* edge, Edge* prev, Edge* next) { list_insert(edge, prev, next, &fHead, &fTail); - fCount++; } void append(Edge* e) { insert(e, fTail, nullptr); } void remove(Edge* edge) { list_remove(edge, &fHead, &fTail); - fCount--; + } + void removeAll() { + while (fHead) { + this->remove(fHead); + } } void close() { if (fHead && fTail) { @@ -440,11 +498,10 @@ struct Poly { void* emit(const AAParams* aaParams, void* data) { Edge* e = fFirstEdge; - e->fTop->fPrev = e->fTop->fNext = nullptr; VertexList vertices; vertices.append(e->fTop); + int count = 1; while (e != nullptr) { - e->fBottom->fPrev = e->fBottom->fNext = nullptr; if (kRight_Side == fSide) { vertices.append(e->fBottom); e = e->fRightPolyNext; @@ -452,6 +509,7 @@ struct Poly { vertices.prepend(e->fBottom); e = e->fLeftPolyNext; } + count++; } Vertex* first = vertices.fHead; Vertex* v = first->fNext; @@ -460,6 +518,9 @@ struct Poly { Vertex* prev = v->fPrev; Vertex* curr = v; Vertex* next = v->fNext; + if (count == 3) { + return emit_triangle(prev, curr, next, aaParams, data); + } double ax = static_cast(curr->fPoint.fX) - prev->fPoint.fX; double ay = static_cast(curr->fPoint.fY) - prev->fPoint.fY; double bx = static_cast(next->fPoint.fX) - curr->fPoint.fX; @@ -468,6 +529,7 @@ struct Poly { data = emit_triangle(prev, curr, next, aaParams, data); v->fPrev->fNext = v->fNext; v->fNext->fPrev = v->fPrev; + count--; if (v->fPrev == first) { v = v->fNext; } else { @@ -480,7 +542,7 @@ struct Poly { return data; } }; - Poly* addEdge(Edge* e, Side side, SkChunkAlloc& alloc) { + Poly* addEdge(Edge* e, Side side, SkArenaAlloc& alloc) { LOG("addEdge (%g -> %g) to poly %d, %s side\n", e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right"); Poly* partner = fPartner; @@ -498,7 +560,7 @@ struct Poly { fPartner = partner->fPartner = nullptr; } if (!fTail) { - fHead = fTail = ALLOC_NEW(MonotonePoly, (e, side), alloc); + fHead = fTail = alloc.make(e, side); fCount += 2; } else if (e->fBottom == fTail->fLastEdge->fBottom) { return poly; @@ -506,14 +568,14 @@ struct Poly { fTail->addEdge(e); fCount++; } else { - e = ALLOC_NEW(Edge, (fTail->fLastEdge->fBottom, e->fBottom, 1), alloc); + e = alloc.make(fTail->fLastEdge->fBottom, e->fBottom, 1, Edge::Type::kInner); fTail->addEdge(e); fCount++; if (partner) { partner->addEdge(e, side, alloc); poly = partner; } else { - MonotonePoly* m = ALLOC_NEW(MonotonePoly, (e, side), alloc); + MonotonePoly* m = alloc.make(e, side); m->fPrev = fTail; fTail->fNext = m; fTail = m; @@ -550,75 +612,67 @@ bool coincident(const SkPoint& a, const SkPoint& b) { return a == b; } -Poly* new_poly(Poly** head, Vertex* v, int winding, SkChunkAlloc& alloc) { - Poly* poly = ALLOC_NEW(Poly, (v, winding), alloc); +Poly* new_poly(Poly** head, Vertex* v, int winding, SkArenaAlloc& alloc) { + Poly* poly = alloc.make(v, winding); poly->fNext = *head; *head = poly; return poly; } -EdgeList* new_contour(EdgeList** head, SkChunkAlloc& alloc) { - EdgeList* contour = ALLOC_NEW(EdgeList, (), alloc); - contour->fNext = *head; - *head = contour; - return contour; -} - -Vertex* append_point_to_contour(const SkPoint& p, Vertex* prev, Vertex** head, - SkChunkAlloc& alloc) { - Vertex* v = ALLOC_NEW(Vertex, (p, 255), alloc); +void append_point_to_contour(const SkPoint& p, VertexList* contour, SkArenaAlloc& alloc) { + Vertex* v = alloc.make(p, 255); #if LOGGING_ENABLED static float gID = 0.0f; v->fID = gID++; #endif - if (prev) { - prev->fNext = v; - v->fPrev = prev; - } else { - *head = v; - } - return v; + contour->append(v); } -Vertex* generate_quadratic_points(const SkPoint& p0, - const SkPoint& p1, - const SkPoint& p2, - SkScalar tolSqd, - Vertex* prev, - Vertex** head, - int pointsLeft, - SkChunkAlloc& alloc) { - SkScalar d = p1.distanceToLineSegmentBetweenSqd(p0, p2); - if (pointsLeft < 2 || d < tolSqd || !SkScalarIsFinite(d)) { - return append_point_to_contour(p2, prev, head, alloc); - } - - const SkPoint q[] = { - { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, - { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) }, - }; - const SkPoint r = { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) }; - - pointsLeft >>= 1; - prev = generate_quadratic_points(p0, q[0], r, tolSqd, prev, head, pointsLeft, alloc); - prev = generate_quadratic_points(r, q[1], p2, tolSqd, prev, head, pointsLeft, alloc); - return prev; +SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) { + SkQuadCoeff quad(pts); + SkPoint p0 = to_point(quad.eval(t - 0.5f * u)); + SkPoint mid = to_point(quad.eval(t)); + SkPoint p1 = to_point(quad.eval(t + 0.5f * u)); + return mid.distanceToLineSegmentBetweenSqd(p0, p1); } -Vertex* generate_cubic_points(const SkPoint& p0, - const SkPoint& p1, - const SkPoint& p2, - const SkPoint& p3, - SkScalar tolSqd, - Vertex* prev, - Vertex** head, - int pointsLeft, - SkChunkAlloc& alloc) { +void append_quadratic_to_contour(const SkPoint pts[3], SkScalar toleranceSqd, VertexList* contour, + SkArenaAlloc& alloc) { + SkQuadCoeff quad(pts); + Sk2s aa = quad.fA * quad.fA; + SkScalar denom = 2.0f * (aa[0] + aa[1]); + Sk2s ab = quad.fA * quad.fB; + SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f; + int nPoints = 1; + SkScalar u; + // Test possible subdivision values only at the point of maximum curvature. + // If it passes the flatness metric there, it'll pass everywhere. + for (;;) { + u = 1.0f / nPoints; + if (quad_error_at(pts, t, u) < toleranceSqd) { + break; + } + nPoints++; + } + for (int j = 1; j <= nPoints; j++) { + append_point_to_contour(to_point(quad.eval(j * u)), contour, alloc); + } +} + +void generate_cubic_points(const SkPoint& p0, + const SkPoint& p1, + const SkPoint& p2, + const SkPoint& p3, + SkScalar tolSqd, + VertexList* contour, + int pointsLeft, + SkArenaAlloc& alloc) { SkScalar d1 = p1.distanceToLineSegmentBetweenSqd(p0, p3); SkScalar d2 = p2.distanceToLineSegmentBetweenSqd(p0, p3); if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) || !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) { - return append_point_to_contour(p3, prev, head, alloc); + append_point_to_contour(p3, contour, alloc); + return; } const SkPoint q[] = { { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, @@ -631,109 +685,79 @@ Vertex* generate_cubic_points(const SkPoint& p0, }; const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) }; pointsLeft >>= 1; - prev = generate_cubic_points(p0, q[0], r[0], s, tolSqd, prev, head, pointsLeft, alloc); - prev = generate_cubic_points(s, r[1], q[2], p3, tolSqd, prev, head, pointsLeft, alloc); - return prev; + generate_cubic_points(p0, q[0], r[0], s, tolSqd, contour, pointsLeft, alloc); + generate_cubic_points(s, r[1], q[2], p3, tolSqd, contour, pointsLeft, alloc); } // Stage 1: convert the input path to a set of linear contours (linked list of Vertices). void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, - Vertex** contours, SkChunkAlloc& alloc, bool *isLinear) { + VertexList* contours, SkArenaAlloc& alloc, bool *isLinear) { SkScalar toleranceSqd = tolerance * tolerance; SkPoint pts[4]; - bool done = false; *isLinear = true; + VertexList* contour = contours; SkPath::Iter iter(path, false); - Vertex* prev = nullptr; - Vertex* head = nullptr; if (path.isInverseFillType()) { SkPoint quad[4]; clipBounds.toQuad(quad); - for (int i = 0; i < 4; i++) { - prev = append_point_to_contour(quad[i], prev, &head, alloc); + for (int i = 3; i >= 0; i--) { + append_point_to_contour(quad[i], contours, alloc); } - head->fPrev = prev; - prev->fNext = head; - *contours++ = head; - head = prev = nullptr; + contour++; } SkAutoConicToQuads converter; - while (!done) { - SkPath::Verb verb = iter.next(pts); + SkPath::Verb verb; + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { switch (verb) { case SkPath::kConic_Verb: { SkScalar weight = iter.conicWeight(); const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd); for (int i = 0; i < converter.countQuads(); ++i) { - int pointsLeft = GrPathUtils::quadraticPointCount(quadPts, tolerance); - prev = generate_quadratic_points(quadPts[0], quadPts[1], quadPts[2], - toleranceSqd, prev, &head, pointsLeft, alloc); + append_quadratic_to_contour(quadPts, toleranceSqd, contour, alloc); quadPts += 2; } *isLinear = false; break; } case SkPath::kMove_Verb: - if (head) { - head->fPrev = prev; - prev->fNext = head; - *contours++ = head; + if (contour->fHead) { + contour++; } - head = prev = nullptr; - prev = append_point_to_contour(pts[0], prev, &head, alloc); + append_point_to_contour(pts[0], contour, alloc); break; case SkPath::kLine_Verb: { - prev = append_point_to_contour(pts[1], prev, &head, alloc); + append_point_to_contour(pts[1], contour, alloc); break; } case SkPath::kQuad_Verb: { - int pointsLeft = GrPathUtils::quadraticPointCount(pts, tolerance); - prev = generate_quadratic_points(pts[0], pts[1], pts[2], toleranceSqd, prev, - &head, pointsLeft, alloc); + append_quadratic_to_contour(pts, toleranceSqd, contour, alloc); *isLinear = false; break; } case SkPath::kCubic_Verb: { int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); - prev = generate_cubic_points(pts[0], pts[1], pts[2], pts[3], - toleranceSqd, prev, &head, pointsLeft, alloc); + generate_cubic_points(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour, + pointsLeft, alloc); *isLinear = false; break; } case SkPath::kClose_Verb: - if (head) { - head->fPrev = prev; - prev->fNext = head; - *contours++ = head; - } - head = prev = nullptr; - break; case SkPath::kDone_Verb: - if (head) { - head->fPrev = prev; - prev->fNext = head; - *contours++ = head; - } - done = true; break; } } } -inline bool apply_fill_type(SkPath::FillType fillType, Poly* poly) { - if (!poly) { - return false; - } - int winding = poly->fWinding; +inline bool apply_fill_type(SkPath::FillType fillType, int winding) { switch (fillType) { case SkPath::kWinding_FillType: return winding != 0; case SkPath::kEvenOdd_FillType: return (winding & 1) != 0; case SkPath::kInverseWinding_FillType: - return winding == -1; + return winding == 1; case SkPath::kInverseEvenOdd_FillType: return (winding & 1) == 1; default: @@ -742,12 +766,15 @@ inline bool apply_fill_type(SkPath::FillType fillType, Poly* poly) { } } -Edge* new_edge(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator& c, - int winding_scale = 1) { - int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? winding_scale : -winding_scale; +inline bool apply_fill_type(SkPath::FillType fillType, Poly* poly) { + return poly && apply_fill_type(fillType, poly->fWinding); +} + +Edge* new_edge(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc) { + int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; Vertex* top = winding < 0 ? next : prev; Vertex* bottom = winding < 0 ? prev : next; - return ALLOC_NEW(Edge, (top, bottom, winding), alloc); + return alloc.make(top, bottom, winding, type); } void remove_edge(Edge* edge, EdgeList* edges) { @@ -764,7 +791,7 @@ void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) { } void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) { - if (v->fFirstEdgeAbove) { + if (v->fFirstEdgeAbove && v->fLastEdgeAbove) { *left = v->fFirstEdgeAbove->fLeft; *right = v->fLastEdgeAbove->fRight; return; @@ -785,8 +812,8 @@ void find_enclosing_edges(Edge* edge, EdgeList* edges, Comparator& c, Edge** lef Edge* prev = nullptr; Edge* next; for (next = edges->fHead; next != nullptr; next = next->fRight) { - if ((c.sweep_gt(edge->fTop->fPoint, next->fTop->fPoint) && next->isRightOf(edge->fTop)) || - (c.sweep_gt(next->fTop->fPoint, edge->fTop->fPoint) && edge->isLeftOf(next->fTop)) || + if ((c.sweep_lt(next->fTop->fPoint, edge->fTop->fPoint) && next->isRightOf(edge->fTop)) || + (c.sweep_lt(edge->fTop->fPoint, next->fTop->fPoint) && edge->isLeftOf(next->fTop)) || (c.sweep_lt(edge->fBottom->fPoint, next->fBottom->fPoint) && next->isRightOf(edge->fBottom)) || (c.sweep_lt(next->fBottom->fPoint, edge->fBottom->fPoint) && @@ -800,7 +827,10 @@ void find_enclosing_edges(Edge* edge, EdgeList* edges, Comparator& c, Edge** lef } void fix_active_state(Edge* edge, EdgeList* activeEdges, Comparator& c) { - if (activeEdges && activeEdges->contains(edge)) { + if (!activeEdges) { + return; + } + if (activeEdges->contains(edge)) { if (edge->fBottom->fProcessed || !edge->fTop->fProcessed) { remove_edge(edge, activeEdges); } @@ -814,7 +844,7 @@ void fix_active_state(Edge* edge, EdgeList* activeEdges, Comparator& c) { void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) { if (edge->fTop->fPoint == edge->fBottom->fPoint || - c.sweep_gt(edge->fTop->fPoint, edge->fBottom->fPoint)) { + c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) { return; } LOG("insert edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID); @@ -832,7 +862,7 @@ void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) { void insert_edge_below(Edge* edge, Vertex* v, Comparator& c) { if (edge->fTop->fPoint == edge->fBottom->fPoint || - c.sweep_gt(edge->fTop->fPoint, edge->fBottom->fPoint)) { + c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) { return; } LOG("insert edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID); @@ -862,13 +892,15 @@ void remove_edge_below(Edge* edge) { edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow); } -void erase_edge_if_zero_winding(Edge* edge, EdgeList* edges) { - if (edge->fWinding != 0) { - return; - } - LOG("erasing edge (%g -> %g)\n", edge->fTop->fID, edge->fBottom->fID); +void disconnect(Edge* edge) +{ remove_edge_above(edge); remove_edge_below(edge); +} + +void erase_edge(Edge* edge, EdgeList* edges) { + LOG("erasing edge (%g -> %g)\n", edge->fTop->fID, edge->fBottom->fID); + disconnect(edge); if (edges && edges->contains(edge)) { remove_edge(edge, edges); } @@ -900,16 +932,12 @@ void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Comparato edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); other->fWinding += edge->fWinding; - erase_edge_if_zero_winding(other, activeEdges); - edge->fWinding = 0; - erase_edge_if_zero_winding(edge, activeEdges); + erase_edge(edge, activeEdges); } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) { other->fWinding += edge->fWinding; - erase_edge_if_zero_winding(other, activeEdges); set_bottom(edge, other->fTop, activeEdges, c); } else { edge->fWinding += other->fWinding; - erase_edge_if_zero_winding(edge, activeEdges); set_bottom(other, edge->fTop, activeEdges, c); } } @@ -920,16 +948,12 @@ void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Comparato edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); other->fWinding += edge->fWinding; - erase_edge_if_zero_winding(other, activeEdges); - edge->fWinding = 0; - erase_edge_if_zero_winding(edge, activeEdges); + erase_edge(edge, activeEdges); } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) { edge->fWinding += other->fWinding; - erase_edge_if_zero_winding(edge, activeEdges); set_top(other, edge->fBottom, activeEdges, c); } else { other->fWinding += edge->fWinding; - erase_edge_if_zero_winding(other, activeEdges); set_top(edge, other->fBottom, activeEdges, c); } } @@ -951,17 +975,17 @@ void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c) { } } -void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkChunkAlloc& alloc); +void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkArenaAlloc& alloc); -void cleanup_active_edges(Edge* edge, EdgeList* activeEdges, Comparator& c, SkChunkAlloc& alloc) { +void cleanup_active_edges(Edge* edge, EdgeList* activeEdges, Comparator& c, SkArenaAlloc& alloc) { Vertex* top = edge->fTop; Vertex* bottom = edge->fBottom; if (edge->fLeft) { Vertex* leftTop = edge->fLeft->fTop; Vertex* leftBottom = edge->fLeft->fBottom; - if (c.sweep_gt(top->fPoint, leftTop->fPoint) && !edge->fLeft->isLeftOf(top)) { + if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) { split_edge(edge->fLeft, edge->fTop, activeEdges, c, alloc); - } else if (c.sweep_gt(leftTop->fPoint, top->fPoint) && !edge->isRightOf(leftTop)) { + } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) { split_edge(edge, leftTop, activeEdges, c, alloc); } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) && !edge->fLeft->isLeftOf(bottom)) { @@ -973,9 +997,9 @@ void cleanup_active_edges(Edge* edge, EdgeList* activeEdges, Comparator& c, SkCh if (edge->fRight) { Vertex* rightTop = edge->fRight->fTop; Vertex* rightBottom = edge->fRight->fBottom; - if (c.sweep_gt(top->fPoint, rightTop->fPoint) && !edge->fRight->isRightOf(top)) { + if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) { split_edge(edge->fRight, top, activeEdges, c, alloc); - } else if (c.sweep_gt(rightTop->fPoint, top->fPoint) && !edge->isLeftOf(rightTop)) { + } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) { split_edge(edge, rightTop, activeEdges, c, alloc); } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) && !edge->fRight->isRightOf(bottom)) { @@ -987,16 +1011,16 @@ void cleanup_active_edges(Edge* edge, EdgeList* activeEdges, Comparator& c, SkCh } } -void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkChunkAlloc& alloc) { +void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkArenaAlloc& alloc) { LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n", edge->fTop->fID, edge->fBottom->fID, v->fID, v->fPoint.fX, v->fPoint.fY); if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) { set_top(edge, v, activeEdges, c); - } else if (c.sweep_gt(v->fPoint, edge->fBottom->fPoint)) { + } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) { set_bottom(edge, v, activeEdges, c); } else { - Edge* newEdge = ALLOC_NEW(Edge, (v, edge->fBottom, edge->fWinding), alloc); + Edge* newEdge = alloc.make(v, edge->fBottom, edge->fWinding, edge->fType); insert_edge_below(newEdge, v, c); insert_edge_above(newEdge, edge->fBottom, c); set_bottom(edge, v, activeEdges, c); @@ -1006,24 +1030,24 @@ void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkC } } -Edge* connect(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator c, +Edge* connect(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc, int winding_scale = 1) { - Edge* edge = new_edge(prev, next, alloc, c, winding_scale); - if (edge->fWinding > 0) { - insert_edge_below(edge, prev, c); - insert_edge_above(edge, next, c); - } else { - insert_edge_below(edge, next, c); - insert_edge_above(edge, prev, c); - } + Edge* edge = new_edge(prev, next, type, c, alloc); + insert_edge_below(edge, edge->fTop, c); + insert_edge_above(edge, edge->fBottom, c); + edge->fWinding *= winding_scale; merge_collinear_edges(edge, nullptr, c); return edge; } -void merge_vertices(Vertex* src, Vertex* dst, Vertex** head, Comparator& c, SkChunkAlloc& alloc) { +void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, Comparator& c, + SkArenaAlloc& alloc) { LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX, src->fPoint.fY, src->fID, dst->fID); dst->fAlpha = SkTMax(src->fAlpha, dst->fAlpha); + if (src->fPartner) { + src->fPartner->fPartner = dst; + } for (Edge* edge = src->fFirstEdgeAbove; edge;) { Edge* next = edge->fNextEdgeAbove; set_bottom(edge, dst, nullptr, c); @@ -1034,33 +1058,40 @@ void merge_vertices(Vertex* src, Vertex* dst, Vertex** head, Comparator& c, SkCh set_top(edge, dst, nullptr, c); edge = next; } - list_remove(src, head, nullptr); + mesh->remove(src); } uint8_t max_edge_alpha(Edge* a, Edge* b) { - return SkTMax(SkTMax(a->fTop->fAlpha, a->fBottom->fAlpha), - SkTMax(b->fTop->fAlpha, b->fBottom->fAlpha)); + if (a->fType == Edge::Type::kInner || b->fType == Edge::Type::kInner) { + return 255; + } else if (a->fType == Edge::Type::kOuter && b->fType == Edge::Type::kOuter) { + return 0; + } else { + return SkTMax(SkTMax(a->fTop->fAlpha, a->fBottom->fAlpha), + SkTMax(b->fTop->fAlpha, b->fBottom->fAlpha)); + } } Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c, - SkChunkAlloc& alloc) { - SkPoint p; + SkArenaAlloc& alloc) { if (!edge || !other) { return nullptr; } - if (edge->intersect(*other, &p)) { + SkPoint p; + uint8_t alpha; + if (edge->intersect(*other, &p, &alpha)) { Vertex* v; LOG("found intersection, pt is %g, %g\n", p.fX, p.fY); if (p == edge->fTop->fPoint || c.sweep_lt(p, edge->fTop->fPoint)) { split_edge(other, edge->fTop, activeEdges, c, alloc); v = edge->fTop; - } else if (p == edge->fBottom->fPoint || c.sweep_gt(p, edge->fBottom->fPoint)) { + } else if (p == edge->fBottom->fPoint || c.sweep_lt(edge->fBottom->fPoint, p)) { split_edge(other, edge->fBottom, activeEdges, c, alloc); v = edge->fBottom; } else if (p == other->fTop->fPoint || c.sweep_lt(p, other->fTop->fPoint)) { split_edge(edge, other->fTop, activeEdges, c, alloc); v = other->fTop; - } else if (p == other->fBottom->fPoint || c.sweep_gt(p, other->fBottom->fPoint)) { + } else if (p == other->fBottom->fPoint || c.sweep_lt(other->fBottom->fPoint, p)) { split_edge(edge, other->fBottom, activeEdges, c, alloc); v = other->fBottom; } else { @@ -1077,8 +1108,7 @@ Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, C } else if (coincident(nextV->fPoint, p)) { v = nextV; } else { - uint8_t alpha = max_edge_alpha(edge, other); - v = ALLOC_NEW(Vertex, (p, alpha), alloc); + v = alloc.make(p, alpha); LOG("inserting between %g (%g, %g) and %g (%g, %g)\n", prevV->fID, prevV->fPoint.fX, prevV->fPoint.fY, nextV->fID, nextV->fPoint.fX, nextV->fPoint.fY); @@ -1093,162 +1123,152 @@ Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, C split_edge(edge, v, activeEdges, c, alloc); split_edge(other, v, activeEdges, c, alloc); } + v->fAlpha = SkTMax(v->fAlpha, alpha); return v; } return nullptr; } -void sanitize_contours(Vertex** contours, int contourCnt, bool approximate) { - for (int i = 0; i < contourCnt; ++i) { - SkASSERT(contours[i]); - for (Vertex* v = contours[i];;) { +void sanitize_contours(VertexList* contours, int contourCnt, bool approximate) { + for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) { + SkASSERT(contour->fHead); + Vertex* prev = contour->fTail; + if (approximate) { + round(&prev->fPoint); + } + for (Vertex* v = contour->fHead; v;) { if (approximate) { round(&v->fPoint); } - if (coincident(v->fPrev->fPoint, v->fPoint)) { + Vertex* next = v->fNext; + if (coincident(prev->fPoint, v->fPoint)) { LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY); - if (v->fPrev == v) { - contours[i] = nullptr; - break; - } - v->fPrev->fNext = v->fNext; - v->fNext->fPrev = v->fPrev; - if (contours[i] == v) { - contours[i] = v->fNext; - } - v = v->fPrev; - } else { - v = v->fNext; - if (v == contours[i]) break; + contour->remove(v); } + prev = v; + v = next; } } } -void merge_coincident_vertices(Vertex** vertices, Comparator& c, SkChunkAlloc& alloc) { - for (Vertex* v = (*vertices)->fNext; v != nullptr; v = v->fNext) { +void merge_coincident_vertices(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { + if (!mesh->fHead) { + return; + } + for (Vertex* v = mesh->fHead->fNext; v != nullptr; v = v->fNext) { if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) { v->fPoint = v->fPrev->fPoint; } if (coincident(v->fPrev->fPoint, v->fPoint)) { - merge_vertices(v->fPrev, v, vertices, c, alloc); + merge_vertices(v->fPrev, v, mesh, c, alloc); } } } // Stage 2: convert the contours to a mesh of edges connecting the vertices. -Vertex* build_edges(Vertex** contours, int contourCnt, Comparator& c, SkChunkAlloc& alloc) { - Vertex* vertices = nullptr; - Vertex* prev = nullptr; - for (int i = 0; i < contourCnt; ++i) { - for (Vertex* v = contours[i]; v != nullptr;) { - Vertex* vNext = v->fNext; - connect(v->fPrev, v, alloc, c); - if (prev) { - prev->fNext = v; - v->fPrev = prev; - } else { - vertices = v; - } +void build_edges(VertexList* contours, int contourCnt, VertexList* mesh, Comparator& c, + SkArenaAlloc& alloc) { + for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) { + Vertex* prev = contour->fTail; + for (Vertex* v = contour->fHead; v;) { + Vertex* next = v->fNext; + connect(prev, v, Edge::Type::kInner, c, alloc); + mesh->append(v); prev = v; - v = vNext; - if (v == contours[i]) break; + v = next; } } - if (prev) { - prev->fNext = vertices->fPrev = nullptr; +} + +void connect_partners(VertexList* outerVertices, Comparator& c, SkArenaAlloc& alloc) { + for (Vertex* outer = outerVertices->fHead; outer; outer = outer->fNext) { + if (Vertex* inner = outer->fPartner) { + // Connector edges get zero winding, since they're only structural (i.e., to ensure + // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding number. + connect(outer, inner, Edge::Type::kConnector, c, alloc, 0); + inner->fPartner = outer->fPartner = nullptr; + } + } +} + +template +void sorted_merge(VertexList* front, VertexList* back, VertexList* result) { + Vertex* a = front->fHead; + Vertex* b = back->fHead; + while (a && b) { + if (sweep_lt(a->fPoint, b->fPoint)) { + front->remove(a); + result->append(a); + a = front->fHead; + } else { + back->remove(b); + result->append(b); + b = back->fHead; + } + } + result->append(*front); + result->append(*back); +} + +void sorted_merge(VertexList* front, VertexList* back, VertexList* result, Comparator& c) { + if (c.fDirection == Comparator::Direction::kHorizontal) { + sorted_merge(front, back, result); + } else { + sorted_merge(front, back, result); } - return vertices; } // Stage 3: sort the vertices by increasing sweep direction. -Vertex* sorted_merge(Vertex* a, Vertex* b, Comparator& c); - -void front_back_split(Vertex* v, Vertex** pFront, Vertex** pBack) { - Vertex* fast; - Vertex* slow; - if (!v || !v->fNext) { - *pFront = v; - *pBack = nullptr; - } else { - slow = v; - fast = v->fNext; - - while (fast != nullptr) { - fast = fast->fNext; - if (fast != nullptr) { - slow = slow->fNext; - fast = fast->fNext; - } - } - - *pFront = v; - *pBack = slow->fNext; - slow->fNext->fPrev = nullptr; - slow->fNext = nullptr; - } -} - -void merge_sort(Vertex** head, Comparator& c) { - if (!*head || !(*head)->fNext) { +template +void merge_sort(VertexList* vertices) { + Vertex* slow = vertices->fHead; + if (!slow) { return; } - - Vertex* a; - Vertex* b; - front_back_split(*head, &a, &b); - - merge_sort(&a, c); - merge_sort(&b, c); - - *head = sorted_merge(a, b, c); -} - -Vertex* sorted_merge(Vertex* a, Vertex* b, Comparator& c) { - VertexList vertices; - - while (a && b) { - if (c.sweep_lt(a->fPoint, b->fPoint)) { - Vertex* next = a->fNext; - vertices.append(a); - a = next; - } else { - Vertex* next = b->fNext; - vertices.append(b); - b = next; + Vertex* fast = slow->fNext; + if (!fast) { + return; + } + do { + fast = fast->fNext; + if (fast) { + fast = fast->fNext; + slow = slow->fNext; } - } - if (a) { - vertices.insert(a, vertices.fTail, a->fNext); - } - if (b) { - vertices.insert(b, vertices.fTail, b->fNext); - } - return vertices.fHead; + } while (fast); + VertexList front(vertices->fHead, slow); + VertexList back(slow->fNext, vertices->fTail); + front.fTail->fNext = back.fHead->fPrev = nullptr; + + merge_sort(&front); + merge_sort(&back); + + vertices->fHead = vertices->fTail = nullptr; + sorted_merge(&front, &back, vertices); } // Stage 4: Simplify the mesh by inserting new vertices at intersecting edges. -void simplify(Vertex* vertices, Comparator& c, SkChunkAlloc& alloc) { +void simplify(const VertexList& vertices, Comparator& c, SkArenaAlloc& alloc) { LOG("simplifying complex polygons\n"); EdgeList activeEdges; - for (Vertex* v = vertices; v != nullptr; v = v->fNext) { + for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) { if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) { continue; } #if LOGGING_ENABLED LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha); #endif - Edge* leftEnclosingEdge = nullptr; - Edge* rightEnclosingEdge = nullptr; + Edge* leftEnclosingEdge; + Edge* rightEnclosingEdge; bool restartChecks; do { restartChecks = false; find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); if (v->fFirstEdgeBelow) { - for (Edge* edge = v->fFirstEdgeBelow; edge != nullptr; edge = edge->fNextEdgeBelow) { + for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) { if (check_for_intersection(edge, leftEnclosingEdge, &activeEdges, c, alloc)) { restartChecks = true; break; @@ -1287,24 +1307,66 @@ void simplify(Vertex* vertices, Comparator& c, SkChunkAlloc& alloc) { } } +// This is a stripped-down version of simplify() (the Bentley-Ottmann algorithm) that +// early-returns true on the first found intersection, false if none. +bool is_complex(const VertexList& vertices) { + LOG("testing polygon complexity\n"); + EdgeList activeEdges; + for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) { + if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) { + continue; + } + Edge* leftEnclosingEdge; + Edge* rightEnclosingEdge; + find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); + SkPoint dummy; + if (v->fFirstEdgeBelow) { + for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) { + if (edge && leftEnclosingEdge && edge->intersect(*leftEnclosingEdge, &dummy)) { + activeEdges.removeAll(); + return true; + } + if (edge && rightEnclosingEdge && edge->intersect(*rightEnclosingEdge, &dummy)) { + activeEdges.removeAll(); + return true; + } + } + } else if (leftEnclosingEdge && rightEnclosingEdge && + leftEnclosingEdge->intersect(*rightEnclosingEdge, &dummy)) { + activeEdges.removeAll(); + return true; + } + for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { + remove_edge(e, &activeEdges); + } + Edge* leftEdge = leftEnclosingEdge; + for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { + insert_edge(e, leftEdge, &activeEdges); + leftEdge = e; + } + } + activeEdges.removeAll(); + return false; +} + // Stage 5: Tessellate the simplified mesh into monotone polygons. -Poly* tessellate(Vertex* vertices, SkChunkAlloc& alloc) { +Poly* tessellate(const VertexList& vertices, SkArenaAlloc& alloc) { LOG("tessellating simple polygons\n"); EdgeList activeEdges; Poly* polys = nullptr; - for (Vertex* v = vertices; v != nullptr; v = v->fNext) { + for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) { if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) { continue; } #if LOGGING_ENABLED LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha); #endif - Edge* leftEnclosingEdge = nullptr; - Edge* rightEnclosingEdge = nullptr; + Edge* leftEnclosingEdge; + Edge* rightEnclosingEdge; find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); - Poly* leftPoly = nullptr; - Poly* rightPoly = nullptr; + Poly* leftPoly; + Poly* rightPoly; if (v->fFirstEdgeAbove) { leftPoly = v->fFirstEdgeAbove->fLeftPoly; rightPoly = v->fLastEdgeAbove->fRightPoly; @@ -1332,14 +1394,13 @@ Poly* tessellate(Vertex* vertices, SkChunkAlloc& alloc) { rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, Poly::kLeft_Side, alloc); } for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) { - Edge* leftEdge = e; Edge* rightEdge = e->fNextEdgeAbove; - SkASSERT(rightEdge->isRightOf(leftEdge->fTop)); - remove_edge(leftEdge, &activeEdges); - if (leftEdge->fRightPoly) { - leftEdge->fRightPoly->addEdge(e, Poly::kLeft_Side, alloc); + SkASSERT(rightEdge->isRightOf(e->fTop)); + remove_edge(e, &activeEdges); + if (e->fRightPoly) { + e->fRightPoly->addEdge(e, Poly::kLeft_Side, alloc); } - if (rightEdge->fLeftPoly) { + if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) { rightEdge->fLeftPoly->addEdge(e, Poly::kRight_Side, alloc); } } @@ -1366,7 +1427,7 @@ Poly* tessellate(Vertex* vertices, SkChunkAlloc& alloc) { rightEnclosingEdge->fLeftPoly = rightPoly; } } - Edge* join = ALLOC_NEW(Edge, (leftPoly->lastVertex(), v, 1), alloc); + Edge* join = alloc.make(leftPoly->lastVertex(), v, 1, Edge::Type::kInner); leftPoly = leftPoly->addEdge(join, Poly::kRight_Side, alloc); rightPoly = rightPoly->addEdge(join, Poly::kLeft_Side, alloc); } @@ -1398,54 +1459,51 @@ Poly* tessellate(Vertex* vertices, SkChunkAlloc& alloc) { return polys; } -bool is_boundary_edge(Edge* edge, SkPath::FillType fillType) { - return apply_fill_type(fillType, edge->fLeftPoly) != - apply_fill_type(fillType, edge->fRightPoly); -} - -bool is_boundary_start(Edge* edge, SkPath::FillType fillType) { - return !apply_fill_type(fillType, edge->fLeftPoly) && - apply_fill_type(fillType, edge->fRightPoly); -} - -Vertex* remove_non_boundary_edges(Vertex* vertices, SkPath::FillType fillType, - SkChunkAlloc& alloc) { - for (Vertex* v = vertices; v != nullptr; v = v->fNext) { - for (Edge* e = v->fFirstEdgeBelow; e != nullptr;) { - Edge* next = e->fNextEdgeBelow; - if (!is_boundary_edge(e, fillType)) { - remove_edge_above(e); - remove_edge_below(e); +void remove_non_boundary_edges(const VertexList& mesh, SkPath::FillType fillType, + SkArenaAlloc& alloc) { + LOG("removing non-boundary edges\n"); + EdgeList activeEdges; + for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) { + if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) { + continue; + } + Edge* leftEnclosingEdge; + Edge* rightEnclosingEdge; + find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); + bool prevFilled = leftEnclosingEdge && + apply_fill_type(fillType, leftEnclosingEdge->fWinding); + for (Edge* e = v->fFirstEdgeAbove; e;) { + Edge* next = e->fNextEdgeAbove; + remove_edge(e, &activeEdges); + bool filled = apply_fill_type(fillType, e->fWinding); + if (filled == prevFilled) { + disconnect(e); } + prevFilled = filled; e = next; } + Edge* prev = leftEnclosingEdge; + for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { + if (prev) { + e->fWinding += prev->fWinding; + } + insert_edge(e, prev, &activeEdges); + prev = e; + } } - return vertices; -} - -// This is different from Edge::intersect, in that it intersects lines, not line segments. -bool intersect(const Edge& a, const Edge& b, SkPoint* point) { - double denom = a.fDX * b.fDY - a.fDY * b.fDX; - if (denom == 0.0) { - return false; - } - double scale = 1.0f / denom; - point->fX = SkDoubleToScalar((b.fDX * a.fC - a.fDX * b.fC) * scale); - point->fY = SkDoubleToScalar((b.fDY * a.fC - a.fDY * b.fC) * scale); - round(point); - return true; } +// Note: this is the normal to the edge, but not necessarily unit length. void get_edge_normal(const Edge* e, SkVector* normal) { - normal->setNormalize(SkDoubleToScalar(e->fDX) * e->fWinding, - SkDoubleToScalar(e->fDY) * e->fWinding); + normal->set(SkDoubleToScalar(e->fLine.fA) * e->fWinding, + SkDoubleToScalar(e->fLine.fB) * e->fWinding); } // Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions // and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to // invert on stroking. -void simplify_boundary(EdgeList* boundary, Comparator& c, SkChunkAlloc& alloc) { +void simplify_boundary(EdgeList* boundary, Comparator& c, SkArenaAlloc& alloc) { Edge* prevEdge = boundary->fTail; SkVector prevNormal; get_edge_normal(prevEdge, &prevNormal); @@ -1455,9 +1513,9 @@ void simplify_boundary(EdgeList* boundary, Comparator& c, SkChunkAlloc& alloc) { double dist = e->dist(prev->fPoint); SkVector normal; get_edge_normal(e, &normal); - float denom = 0.25f * static_cast(e->fDX * e->fDX + e->fDY * e->fDY); + double denom = 0.0625f * e->fLine.magSq(); if (prevNormal.dot(normal) < 0.0 && (dist * dist) <= denom) { - Edge* join = new_edge(prev, next, alloc, c); + Edge* join = new_edge(prev, next, Edge::Type::kInner, c, alloc); insert_edge(join, e, boundary); remove_edge(prevEdge, boundary); remove_edge(e, boundary); @@ -1477,93 +1535,93 @@ void simplify_boundary(EdgeList* boundary, Comparator& c, SkChunkAlloc& alloc) { } } +void fix_inversions(Vertex* prev, Vertex* next, Edge* prevBisector, Edge* nextBisector, + Edge* prevEdge, Comparator& c) { + if (!prev || !next) { + return; + } + int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; + SkPoint p; + uint8_t alpha; + if (winding != prevEdge->fWinding && prevBisector->intersect(*nextBisector, &p, &alpha)) { + prev->fPoint = next->fPoint = p; + prev->fAlpha = next->fAlpha = alpha; + } +} + // Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to // find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a // new antialiased mesh from those vertices. -void boundary_to_aa_mesh(EdgeList* boundary, VertexList* mesh, Comparator& c, SkChunkAlloc& alloc) { - EdgeList outerContour; +void stroke_boundary(EdgeList* boundary, VertexList* innerMesh, VertexList* outerMesh, + Comparator& c, SkArenaAlloc& alloc) { + // A boundary with fewer than 3 edges is degenerate. + if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) { + return; + } Edge* prevEdge = boundary->fTail; float radius = 0.5f; - double offset = radius * sqrt(prevEdge->fDX * prevEdge->fDX + prevEdge->fDY * prevEdge->fDY) - * prevEdge->fWinding; - Edge prevInner(prevEdge->fTop, prevEdge->fBottom, prevEdge->fWinding); + double offset = radius * sqrt(prevEdge->fLine.magSq()) * prevEdge->fWinding; + Line prevInner(prevEdge->fLine); prevInner.fC -= offset; - Edge prevOuter(prevEdge->fTop, prevEdge->fBottom, prevEdge->fWinding); + Line prevOuter(prevEdge->fLine); prevOuter.fC += offset; VertexList innerVertices; VertexList outerVertices; - SkScalar innerCount = SK_Scalar1, outerCount = SK_Scalar1; + Edge* prevBisector = nullptr; for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) { - double offset = radius * sqrt(e->fDX * e->fDX + e->fDY * e->fDY) * e->fWinding; - Edge inner(e->fTop, e->fBottom, e->fWinding); + double offset = radius * sqrt(e->fLine.magSq()) * e->fWinding; + Line inner(e->fLine); inner.fC -= offset; - Edge outer(e->fTop, e->fBottom, e->fWinding); + Line outer(e->fLine); outer.fC += offset; SkPoint innerPoint, outerPoint; - if (intersect(prevInner, inner, &innerPoint) && - intersect(prevOuter, outer, &outerPoint)) { - Vertex* innerVertex = ALLOC_NEW(Vertex, (innerPoint, 255), alloc); - Vertex* outerVertex = ALLOC_NEW(Vertex, (outerPoint, 0), alloc); - if (innerVertices.fTail && outerVertices.fTail) { - Edge innerEdge(innerVertices.fTail, innerVertex, 1); - Edge outerEdge(outerVertices.fTail, outerVertex, 1); - SkVector innerNormal; - get_edge_normal(&innerEdge, &innerNormal); - SkVector outerNormal; - get_edge_normal(&outerEdge, &outerNormal); - SkVector normal; - get_edge_normal(prevEdge, &normal); - if (normal.dot(innerNormal) < 0) { - innerPoint += innerVertices.fTail->fPoint * innerCount; - innerCount++; - innerPoint *= SkScalarInvert(innerCount); - innerVertices.fTail->fPoint = innerVertex->fPoint = innerPoint; - } else { - innerCount = SK_Scalar1; - } - if (normal.dot(outerNormal) < 0) { - outerPoint += outerVertices.fTail->fPoint * outerCount; - outerCount++; - outerPoint *= SkScalarInvert(outerCount); - outerVertices.fTail->fPoint = outerVertex->fPoint = outerPoint; - } else { - outerCount = SK_Scalar1; - } - } + if (prevInner.intersect(inner, &innerPoint) && + prevOuter.intersect(outer, &outerPoint)) { + Vertex* innerVertex = alloc.make(innerPoint, 255); + Vertex* outerVertex = alloc.make(outerPoint, 0); + Edge* bisector = new_edge(outerVertex, innerVertex, Edge::Type::kConnector, c, alloc); + fix_inversions(innerVertices.fTail, innerVertex, prevBisector, bisector, prevEdge, c); + fix_inversions(outerVertices.fTail, outerVertex, prevBisector, bisector, prevEdge, c); + innerVertex->fPartner = outerVertex; + outerVertex->fPartner = innerVertex; innerVertices.append(innerVertex); outerVertices.append(outerVertex); - prevEdge = e; + prevBisector = bisector; } prevInner = inner; prevOuter = outer; + prevEdge = e; } - innerVertices.close(); - outerVertices.close(); Vertex* innerVertex = innerVertices.fHead; Vertex* outerVertex = outerVertices.fHead; - // Alternate clockwise and counterclockwise polys, so the tesselator - // doesn't cancel out the interior edges. if (!innerVertex || !outerVertex) { return; } - do { - connect(outerVertex->fNext, outerVertex, alloc, c); - connect(innerVertex->fNext, innerVertex, alloc, c, 2); - connect(innerVertex, outerVertex->fNext, alloc, c, 2); - connect(outerVertex, innerVertex, alloc, c, 2); - Vertex* innerNext = innerVertex->fNext; - Vertex* outerNext = outerVertex->fNext; - mesh->append(innerVertex); - mesh->append(outerVertex); - innerVertex = innerNext; - outerVertex = outerNext; - } while (innerVertex != innerVertices.fHead && outerVertex != outerVertices.fHead); + Edge* bisector = new_edge(outerVertices.fHead, innerVertices.fHead, Edge::Type::kConnector, c, + alloc); + fix_inversions(innerVertices.fTail, innerVertices.fHead, prevBisector, bisector, prevEdge, c); + fix_inversions(outerVertices.fTail, outerVertices.fHead, prevBisector, bisector, prevEdge, c); + Vertex* prevInnerVertex = innerVertices.fTail; + Vertex* prevOuterVertex = outerVertices.fTail; + while (innerVertex && outerVertex) { + // Connect vertices into a quad mesh. Outer edges get default (1) winding. + // Inner edges get -2 winding. This ensures that the interior is always filled + // (-1 winding number for normal cases, 3 for thin features where the interior inverts). + connect(prevOuterVertex, outerVertex, Edge::Type::kOuter, c, alloc); + connect(prevInnerVertex, innerVertex, Edge::Type::kInner, c, alloc, -2); + prevInnerVertex = innerVertex; + prevOuterVertex = outerVertex; + innerVertex = innerVertex->fNext; + outerVertex = outerVertex->fNext; + } + innerMesh->append(innerVertices); + outerMesh->append(outerVertices); } -void extract_boundary(EdgeList* boundary, Edge* e, SkPath::FillType fillType, SkChunkAlloc& alloc) { - bool down = is_boundary_start(e, fillType); +void extract_boundary(EdgeList* boundary, Edge* e, SkPath::FillType fillType, SkArenaAlloc& alloc) { + bool down = apply_fill_type(fillType, e->fWinding); while (e) { e->fWinding = down ? 1 : -1; Edge* next; @@ -1587,89 +1645,96 @@ void extract_boundary(EdgeList* boundary, Edge* e, SkPath::FillType fillType, Sk down = true; } } - remove_edge_above(e); - remove_edge_below(e); + disconnect(e); e = next; } } -// Stage 5b: Extract boundary edges. +// Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh. -EdgeList* extract_boundaries(Vertex* vertices, SkPath::FillType fillType, SkChunkAlloc& alloc) { - LOG("extracting boundaries\n"); - vertices = remove_non_boundary_edges(vertices, fillType, alloc); - EdgeList* boundaries = nullptr; - for (Vertex* v = vertices; v != nullptr; v = v->fNext) { +void extract_boundaries(const VertexList& inMesh, VertexList* innerVertices, + VertexList* outerVertices, SkPath::FillType fillType, + Comparator& c, SkArenaAlloc& alloc) { + remove_non_boundary_edges(inMesh, fillType, alloc); + for (Vertex* v = inMesh.fHead; v; v = v->fNext) { while (v->fFirstEdgeBelow) { - EdgeList* boundary = new_contour(&boundaries, alloc); - extract_boundary(boundary, v->fFirstEdgeBelow, fillType, alloc); + EdgeList boundary; + extract_boundary(&boundary, v->fFirstEdgeBelow, fillType, alloc); + simplify_boundary(&boundary, c, alloc); + stroke_boundary(&boundary, innerVertices, outerVertices, c, alloc); } } - return boundaries; } -// This is a driver function which calls stages 2-5 in turn. +// This is a driver function that calls stages 2-5 in turn. -Vertex* contours_to_mesh(Vertex** contours, int contourCnt, bool antialias, - Comparator& c, SkChunkAlloc& alloc) { +void contours_to_mesh(VertexList* contours, int contourCnt, bool antialias, + VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { #if LOGGING_ENABLED for (int i = 0; i < contourCnt; ++i) { - Vertex* v = contours[i]; + Vertex* v = contours[i].fHead; SkASSERT(v); LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); - for (v = v->fNext; v != contours[i]; v = v->fNext) { + for (v = v->fNext; v; v = v->fNext) { LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); } } #endif sanitize_contours(contours, contourCnt, antialias); - return build_edges(contours, contourCnt, c, alloc); + build_edges(contours, contourCnt, mesh, c, alloc); } -Poly* mesh_to_polys(Vertex** vertices, SkPath::FillType fillType, Comparator& c, - SkChunkAlloc& alloc) { - if (!vertices || !*vertices) { - return nullptr; +void sort_mesh(VertexList* vertices, Comparator& c, SkArenaAlloc& alloc) { + if (!vertices || !vertices->fHead) { + return; } // Sort vertices in Y (secondarily in X). - merge_sort(vertices, c); - merge_coincident_vertices(vertices, c, alloc); + if (c.fDirection == Comparator::Direction::kHorizontal) { + merge_sort(vertices); + } else { + merge_sort(vertices); + } #if LOGGING_ENABLED - for (Vertex* v = *vertices; v != nullptr; v = v->fNext) { + for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) { static float gID = 0.0f; v->fID = gID++; } #endif - simplify(*vertices, c, alloc); - return tessellate(*vertices, alloc); } -Poly* contours_to_polys(Vertex** contours, int contourCnt, SkPath::FillType fillType, - const SkRect& pathBounds, bool antialias, - SkChunkAlloc& alloc) { - Comparator c; - if (pathBounds.width() > pathBounds.height()) { - c.sweep_lt = sweep_lt_horiz; - c.sweep_gt = sweep_gt_horiz; - } else { - c.sweep_lt = sweep_lt_vert; - c.sweep_gt = sweep_gt_vert; - } - Vertex* mesh = contours_to_mesh(contours, contourCnt, antialias, c, alloc); - Poly* polys = mesh_to_polys(&mesh, fillType, c, alloc); +Poly* contours_to_polys(VertexList* contours, int contourCnt, SkPath::FillType fillType, + const SkRect& pathBounds, bool antialias, VertexList* outerMesh, + SkArenaAlloc& alloc) { + Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal + : Comparator::Direction::kVertical); + VertexList mesh; + contours_to_mesh(contours, contourCnt, antialias, &mesh, c, alloc); + sort_mesh(&mesh, c, alloc); + merge_coincident_vertices(&mesh, c, alloc); + simplify(mesh, c, alloc); if (antialias) { - EdgeList* boundaries = extract_boundaries(mesh, fillType, alloc); - VertexList aaMesh; - for (EdgeList* boundary = boundaries; boundary != nullptr; boundary = boundary->fNext) { - simplify_boundary(boundary, c, alloc); - if (boundary->fCount > 2) { - boundary_to_aa_mesh(boundary, &aaMesh, c, alloc); - } + VertexList innerMesh; + extract_boundaries(mesh, &innerMesh, outerMesh, fillType, c, alloc); + sort_mesh(&innerMesh, c, alloc); + sort_mesh(outerMesh, c, alloc); + if (is_complex(innerMesh) || is_complex(*outerMesh)) { + LOG("found complex mesh; taking slow path\n"); + VertexList aaMesh; + connect_partners(outerMesh, c, alloc); + sorted_merge(&innerMesh, outerMesh, &aaMesh, c); + merge_coincident_vertices(&aaMesh, c, alloc); + simplify(aaMesh, c, alloc); + outerMesh->fHead = outerMesh->fTail = nullptr; + return tessellate(aaMesh, alloc); + } else { + LOG("no complex polygons; taking fast path\n"); + merge_coincident_vertices(&innerMesh, c, alloc); + return tessellate(innerMesh, alloc); } - return mesh_to_polys(&aaMesh.fHead, SkPath::kWinding_FillType, c, alloc); + } else { + return tessellate(mesh, alloc); } - return polys; } // Stage 6: Triangulate the monotone polygons into a vertex buffer. @@ -1684,35 +1749,30 @@ void* polys_to_triangles(Poly* polys, SkPath::FillType fillType, const AAParams* } Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, - int contourCnt, SkChunkAlloc& alloc, bool antialias, bool* isLinear) { + int contourCnt, SkArenaAlloc& alloc, bool antialias, bool* isLinear, + VertexList* outerMesh) { SkPath::FillType fillType = path.getFillType(); if (SkPath::IsInverseFillType(fillType)) { contourCnt++; } - SkAutoTDeleteArray contours(new Vertex* [contourCnt]); + std::unique_ptr contours(new VertexList[contourCnt]); path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, isLinear); return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(), - antialias, alloc); + antialias, outerMesh, alloc); } -void get_contour_count_and_size_estimate(const SkPath& path, SkScalar tolerance, int* contourCnt, - int* sizeEstimate) { - int maxPts = GrPathUtils::worstCasePointCount(path, contourCnt, tolerance); +int get_contour_count(const SkPath& path, SkScalar tolerance) { + int contourCnt; + int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tolerance); if (maxPts <= 0) { - *contourCnt = 0; - return; + return 0; } if (maxPts > ((int)SK_MaxU16 + 1)) { SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); - *contourCnt = 0; - return; + return 0; } - // For the initial size of the chunk allocator, estimate based on the point count: - // one vertex per point for the initial passes, plus two for the vertices in the - // resulting Polys, since the same point may end up in two Polys. Assume minimal - // connectivity of one Edge per Vertex (will grow for intersections). - *sizeEstimate = maxPts * (3 * sizeof(Vertex) + sizeof(Edge)); + return contourCnt; } int count_points(Poly* polys, SkPath::FillType fillType) { @@ -1725,6 +1785,30 @@ int count_points(Poly* polys, SkPath::FillType fillType) { return count; } +int count_outer_mesh_points(const VertexList& outerMesh) { + int count = 0; + for (Vertex* v = outerMesh.fHead; v; v = v->fNext) { + for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { + count += TESSELLATOR_WIREFRAME ? 12 : 6; + } + } + return count; +} + +void* outer_mesh_to_triangles(const VertexList& outerMesh, const AAParams* aaParams, void* data) { + for (Vertex* v = outerMesh.fHead; v; v = v->fNext) { + for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { + Vertex* v0 = e->fTop; + Vertex* v1 = e->fBottom; + Vertex* v2 = e->fBottom->fPartner; + Vertex* v3 = e->fTop->fPartner; + data = emit_triangle(v0, v1, v2, aaParams, data); + data = emit_triangle(v0, v2, v3, aaParams, data); + } + } + return data; +} + } // namespace namespace GrTessellator { @@ -1734,21 +1818,23 @@ namespace GrTessellator { int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, VertexAllocator* vertexAllocator, bool antialias, const GrColor& color, bool canTweakAlphaForCoverage, bool* isLinear) { - int contourCnt; - int sizeEstimate; - get_contour_count_and_size_estimate(path, tolerance, &contourCnt, &sizeEstimate); + int contourCnt = get_contour_count(path, tolerance); if (contourCnt <= 0) { *isLinear = true; return 0; } - SkChunkAlloc alloc(sizeEstimate); + SkArenaAlloc alloc(kArenaChunkSize); + VertexList outerMesh; Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, antialias, - isLinear); - SkPath::FillType fillType = path.getFillType(); + isLinear, &outerMesh); + SkPath::FillType fillType = antialias ? SkPath::kWinding_FillType : path.getFillType(); int count = count_points(polys, fillType); if (0 == count) { return 0; } + if (antialias) { + count += count_outer_mesh_points(outerMesh); + } void* verts = vertexAllocator->lock(count); if (!verts) { @@ -1762,6 +1848,7 @@ int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBo aaParams.fColor = color; void* end = polys_to_triangles(polys, fillType, antialias ? &aaParams : nullptr, verts); + end = outer_mesh_to_triangles(outerMesh, &aaParams, end); int actualCount = static_cast((static_cast(end) - static_cast(verts)) / vertexAllocator->stride()); SkASSERT(actualCount <= count); @@ -1771,15 +1858,14 @@ int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBo int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, GrTessellator::WindingVertex** verts) { - int contourCnt; - int sizeEstimate; - get_contour_count_and_size_estimate(path, tolerance, &contourCnt, &sizeEstimate); + int contourCnt = get_contour_count(path, tolerance); if (contourCnt <= 0) { return 0; } - SkChunkAlloc alloc(sizeEstimate); + SkArenaAlloc alloc(kArenaChunkSize); bool isLinear; - Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, false, &isLinear); + Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, false, &isLinear, + nullptr); SkPath::FillType fillType = path.getFillType(); int count = count_points(polys, fillType); if (0 == count) { diff --git a/gfx/skia/skia/src/gpu/GrTestUtils.cpp b/gfx/skia/skia/src/gpu/GrTestUtils.cpp index 2aae8df3750c..aad927ab3fe3 100644 --- a/gfx/skia/skia/src/gpu/GrTestUtils.cpp +++ b/gfx/skia/skia/src/gpu/GrTestUtils.cpp @@ -6,14 +6,15 @@ */ #include "GrTestUtils.h" +#include "GrProcessorUnitTest.h" #include "GrStyle.h" -#include "SkColorSpace.h" +#include "SkColorSpace_Base.h" #include "SkDashPathPriv.h" #include "SkMatrix.h" #include "SkPath.h" #include "SkRRect.h" -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS static const SkMatrix& test_matrix(SkRandom* random, bool includeNonPerspective, @@ -252,7 +253,7 @@ void TestStyle(SkRandom* random, GrStyle* style) { sk_sp pe; if (random->nextBool()) { int cnt = random->nextRangeU(1, 50) * 2; - SkAutoTDeleteArray intervals(new SkScalar[cnt]); + std::unique_ptr intervals(new SkScalar[cnt]); SkScalar sum = 0; for (int i = 0; i < cnt; i++) { intervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01), @@ -262,7 +263,7 @@ void TestStyle(SkRandom* random, GrStyle* style) { SkScalar phase = random->nextRangeScalar(0, sum); pe = TestDashPathEffect::Make(intervals.get(), cnt, phase); } - *style = GrStyle(stroke, pe.get()); + *style = GrStyle(stroke, std::move(pe)); } TestDashPathEffect::TestDashPathEffect(const SkScalar* intervals, int count, SkScalar phase) { @@ -298,8 +299,8 @@ sk_sp TestColorSpace(SkRandom* random) { // No color space (legacy mode) gColorSpaces[0] = nullptr; // sRGB or Adobe - gColorSpaces[1] = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); - gColorSpaces[2] = SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named); + gColorSpaces[1] = SkColorSpace::MakeSRGB(); + gColorSpaces[2] = SkColorSpace_Base::MakeNamed(SkColorSpace_Base::kAdobeRGB_Named); } return gColorSpaces[random->nextULessThan(static_cast(SK_ARRAY_COUNT(gColorSpaces)))]; } @@ -309,8 +310,8 @@ sk_sp TestColorXform(SkRandom* random) { static bool gOnce; if (!gOnce) { gOnce = true; - sk_sp srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); - sk_sp adobe = SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named); + sk_sp srgb = SkColorSpace::MakeSRGB(); + sk_sp adobe = SkColorSpace_Base::MakeNamed(SkColorSpace_Base::kAdobeRGB_Named); // No gamut change gXforms[0] = nullptr; // To larger gamut @@ -321,6 +322,17 @@ sk_sp TestColorXform(SkRandom* random) { return gXforms[random->nextULessThan(static_cast(SK_ARRAY_COUNT(gXforms)))]; } +TestAsFPArgs::TestAsFPArgs(GrProcessorTestData* d) { + fViewMatrixStorage = TestMatrix(d->fRandom); + fColorSpaceStorage = TestColorSpace(d->fRandom); + + fArgs.fContext = d->context(); + fArgs.fViewMatrix = &fViewMatrixStorage; + fArgs.fLocalMatrix = nullptr; + fArgs.fFilterQuality = kNone_SkFilterQuality; + fArgs.fDstColorSpace = fColorSpaceStorage.get(); +} + } // namespace GrTest #endif diff --git a/gfx/skia/skia/src/gpu/GrTexture.cpp b/gfx/skia/skia/src/gpu/GrTexture.cpp index bb1a6bb08111..ea0ed765172f 100644 --- a/gfx/skia/skia/src/gpu/GrTexture.cpp +++ b/gfx/skia/skia/src/gpu/GrTexture.cpp @@ -36,24 +36,7 @@ void GrTexture::dirtyMipMaps(bool mipMapsDirty) { } size_t GrTexture::onGpuMemorySize() const { - size_t textureSize; - - if (GrPixelConfigIsCompressed(fDesc.fConfig)) { - textureSize = GrCompressedFormatDataSize(fDesc.fConfig, fDesc.fWidth, fDesc.fHeight); - } else { - textureSize = (size_t) fDesc.fWidth * fDesc.fHeight * GrBytesPerPixel(fDesc.fConfig); - } - - if (this->texturePriv().hasMipMaps()) { - // We don't have to worry about the mipmaps being a different size than - // we'd expect because we never change fDesc.fWidth/fHeight. - textureSize += textureSize/3; - } - - SkASSERT(!SkToBool(fDesc.fFlags & kRenderTarget_GrSurfaceFlag)); - SkASSERT(textureSize <= WorstCaseSize(fDesc)); - - return textureSize; + return GrSurface::ComputeSize(fDesc, 1, this->texturePriv().hasMipMaps()); } void GrTexture::validateDesc() const { @@ -87,11 +70,12 @@ GrSurfaceOrigin resolve_origin(const GrSurfaceDesc& desc) { ////////////////////////////////////////////////////////////////////////////// GrTexture::GrTexture(GrGpu* gpu, const GrSurfaceDesc& desc, GrSLType samplerType, - bool wasMipMapDataProvided) + GrSamplerParams::FilterMode highestFilterMode, bool wasMipMapDataProvided) : INHERITED(gpu, desc) , fSamplerType(samplerType) - // Gamma treatment is explicitly set after creation via GrTexturePriv - , fGammaTreatment(SkSourceGammaTreatment::kIgnore) { + , fHighestFilterMode(highestFilterMode) + // Mip color mode is explicitly set after creation via GrTexturePriv + , fMipColorMode(SkDestinationSurfaceColorMode::kLegacy) { if (wasMipMapDataProvided) { fMipMapsStatus = kValid_MipMapsStatus; fMaxMipMapLevel = SkMipMap::ComputeLevelCount(fDesc.fWidth, fDesc.fHeight); diff --git a/gfx/skia/skia/src/gpu/GrTextureAccess.cpp b/gfx/skia/skia/src/gpu/GrTextureAccess.cpp deleted file mode 100644 index 675bc207777b..000000000000 --- a/gfx/skia/skia/src/gpu/GrTextureAccess.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrTextureAccess.h" -#include "GrColor.h" -#include "GrTexture.h" - -GrTextureAccess::GrTextureAccess() {} - -GrTextureAccess::GrTextureAccess(GrTexture* texture, const GrTextureParams& params) { - this->reset(texture, params); -} - -GrTextureAccess::GrTextureAccess(GrTexture* texture, - GrTextureParams::FilterMode filterMode, - SkShader::TileMode tileXAndY, - GrShaderFlags visibility) { - this->reset(texture, filterMode, tileXAndY, visibility); -} - -void GrTextureAccess::reset(GrTexture* texture, - const GrTextureParams& params, - GrShaderFlags visibility) { - SkASSERT(texture); - fTexture.set(SkRef(texture), kRead_GrIOType); - fParams = params; - fVisibility = visibility; -} - -void GrTextureAccess::reset(GrTexture* texture, - GrTextureParams::FilterMode filterMode, - SkShader::TileMode tileXAndY, - GrShaderFlags visibility) { - SkASSERT(texture); - fTexture.set(SkRef(texture), kRead_GrIOType); - fParams.reset(tileXAndY, filterMode); - fVisibility = visibility; -} diff --git a/gfx/skia/skia/src/gpu/GrTextureAdjuster.cpp b/gfx/skia/skia/src/gpu/GrTextureAdjuster.cpp new file mode 100644 index 000000000000..bb4d92aa549f --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureAdjuster.cpp @@ -0,0 +1,173 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrTextureAdjuster.h" + +#include "GrContext.h" +#include "GrGpu.h" +#include "GrGpuResourcePriv.h" +#include "GrResourceProvider.h" +#include "GrTexture.h" +#include "SkGr.h" + +GrTextureAdjuster::GrTextureAdjuster(GrContext* context, sk_sp original, + SkAlphaType alphaType, + const SkIRect& contentArea, uint32_t uniqueID, + SkColorSpace* cs) + : INHERITED(contentArea.width(), contentArea.height(), + GrPixelConfigIsAlphaOnly(original->config())) + , fContext(context) + , fOriginal(std::move(original)) + , fAlphaType(alphaType) + , fColorSpace(cs) + , fUniqueID(uniqueID) { + SkASSERT(SkIRect::MakeWH(fOriginal->width(), fOriginal->height()).contains(contentArea)); + if (contentArea.fLeft > 0 || contentArea.fTop > 0 || + contentArea.fRight < fOriginal->width() || contentArea.fBottom < fOriginal->height()) { + fContentArea.set(contentArea); + } +} + +void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey, + SkColorSpace* dstColorSpace) { + // Destination color space is irrelevant - we already have a texture so we're just sub-setting + GrUniqueKey baseKey; + GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeWH(this->width(), this->height())); + MakeCopyKeyFromOrigKey(baseKey, params, copyKey); +} + +void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) { + // We don't currently have a mechanism for notifications on Images! +} + +sk_sp GrTextureAdjuster::refTextureProxyCopy(const CopyParams& copyParams) { + GrUniqueKey key; + this->makeCopyKey(copyParams, &key, nullptr); + if (key.isValid()) { + sk_sp cachedCopy = fContext->resourceProvider()->findProxyByUniqueKey(key); + if (cachedCopy) { + return cachedCopy; + } + } + + sk_sp proxy = this->originalProxyRef(); + const SkIRect* contentArea = this->contentAreaOrNull(); + + sk_sp copy = CopyOnGpu(fContext, std::move(proxy), contentArea, copyParams); + if (copy) { + if (key.isValid()) { + fContext->resourceProvider()->assignUniqueKeyToProxy(key, copy.get()); + this->didCacheCopy(key); + } + } + return copy; +} + +sk_sp GrTextureAdjuster::refTextureProxySafeForParams( + const GrSamplerParams& params, + SkIPoint* outOffset, + SkScalar scaleAdjust[2]) { + sk_sp proxy = this->originalProxyRef(); + CopyParams copyParams; + const SkIRect* contentArea = this->contentAreaOrNull(); + + if (!fContext) { + // The texture was abandoned. + return nullptr; + } + + if (contentArea && GrSamplerParams::kMipMap_FilterMode == params.filterMode()) { + // If we generate a MIP chain for texture it will read pixel values from outside the content + // area. + copyParams.fWidth = contentArea->width(); + copyParams.fHeight = contentArea->height(); + copyParams.fFilter = GrSamplerParams::kBilerp_FilterMode; + } else if (!fContext->getGpu()->isACopyNeededForTextureParams(proxy.get(), params, ©Params, + scaleAdjust)) { + if (outOffset) { + if (contentArea) { + outOffset->set(contentArea->fLeft, contentArea->fRight); + } else { + outOffset->set(0, 0); + } + } + return proxy; + } + + sk_sp copy = this->refTextureProxyCopy(copyParams); + if (copy && outOffset) { + outOffset->set(0, 0); + } + return copy; +} + +sk_sp GrTextureAdjuster::createFragmentProcessor( + const SkMatrix& origTextureMatrix, + const SkRect& origConstraintRect, + FilterConstraint filterConstraint, + bool coordsLimitedToConstraintRect, + const GrSamplerParams::FilterMode* filterOrNullForBicubic, + SkColorSpace* dstColorSpace) { + + SkMatrix textureMatrix = origTextureMatrix; + const SkIRect* contentArea = this->contentAreaOrNull(); + // Convert the constraintRect to be relative to the texture rather than the content area so + // that both rects are in the same coordinate system. + SkTCopyOnFirstWrite constraintRect(origConstraintRect); + if (contentArea) { + SkScalar l = SkIntToScalar(contentArea->fLeft); + SkScalar t = SkIntToScalar(contentArea->fTop); + constraintRect.writable()->offset(l, t); + textureMatrix.postTranslate(l, t); + } + + SkRect domain; + GrSamplerParams params; + if (filterOrNullForBicubic) { + params.setFilterMode(*filterOrNullForBicubic); + } + SkScalar scaleAdjust[2] = { 1.0f, 1.0f }; + sk_sp proxy(this->refTextureProxySafeForParams(params, nullptr, scaleAdjust)); + if (!proxy) { + return nullptr; + } + // If we made a copy then we only copied the contentArea, in which case the new texture is all + // content. + if (proxy.get() != this->originalProxy()) { + contentArea = nullptr; + textureMatrix.postScale(scaleAdjust[0], scaleAdjust[1]); + } + + DomainMode domainMode = + DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect, + proxy.get(), + contentArea, filterOrNullForBicubic, + &domain); + if (kTightCopy_DomainMode == domainMode) { + // TODO: Copy the texture and adjust the texture matrix (both parts need to consider + // non-int constraint rect) + // For now: treat as bilerp and ignore what goes on above level 0. + + // We only expect MIP maps to require a tight copy. + SkASSERT(filterOrNullForBicubic && + GrSamplerParams::kMipMap_FilterMode == *filterOrNullForBicubic); + static const GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode; + domainMode = + DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect, + proxy.get(), + contentArea, &kBilerp, &domain); + SkASSERT(kTightCopy_DomainMode != domainMode); + } + SkASSERT(kNoDomain_DomainMode == domainMode || + (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom)); + sk_sp colorSpaceXform = GrColorSpaceXform::Make(fColorSpace, + dstColorSpace); + return CreateFragmentProcessorForDomainAndFilter(fContext->resourceProvider(), std::move(proxy), + std::move(colorSpaceXform), + textureMatrix, domainMode, domain, + filterOrNullForBicubic); +} diff --git a/gfx/skia/skia/src/gpu/GrTextureAdjuster.h b/gfx/skia/skia/src/gpu/GrTextureAdjuster.h new file mode 100644 index 000000000000..392af44439cc --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureAdjuster.h @@ -0,0 +1,67 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTextureAdjuster_DEFINED +#define GrTextureAdjuster_DEFINED + +#include "GrTextureProducer.h" +#include "SkTLazy.h" + +/** + * Base class for sources that start out as textures. Optionally allows for a content area subrect. + * The intent is not to use content area for subrect rendering. Rather, the pixels outside the + * content area have undefined values and shouldn't be read *regardless* of filtering mode or + * the SkCanvas::SrcRectConstraint used for subrect draws. + */ +class GrTextureAdjuster : public GrTextureProducer { +public: + /** Makes the subset of the texture safe to use with the given texture parameters. + outOffset will be the top-left corner of the subset if a copy is not made. Otherwise, + the copy will be tight to the contents and outOffset will be (0, 0). If the copy's size + does not match subset's dimensions then the contents are scaled to fit the copy.*/ + sk_sp refTextureProxySafeForParams(const GrSamplerParams&, SkIPoint* outOffset, + SkScalar scaleAdjust[2]); + + sk_sp createFragmentProcessor( + const SkMatrix& textureMatrix, + const SkRect& constraintRect, + FilterConstraint, + bool coordsLimitedToConstraintRect, + const GrSamplerParams::FilterMode* filterOrNullForBicubic, + SkColorSpace* dstColorSpace) override; + + // We do not ref the texture nor the colorspace, so the caller must keep them in scope while + // this Adjuster is alive. + GrTextureAdjuster(GrContext*, sk_sp, SkAlphaType, const SkIRect& area, + uint32_t uniqueID, SkColorSpace*); + +protected: + SkAlphaType alphaType() const override { return fAlphaType; } + void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey, + SkColorSpace* dstColorSpace) override; + void didCacheCopy(const GrUniqueKey& copyKey) override; + + GrTextureProxy* originalProxy() const { return fOriginal.get(); } + sk_sp originalProxyRef() const { return fOriginal; } + + /** Returns the content area or null for the whole original texture */ + const SkIRect* contentAreaOrNull() { return fContentArea.getMaybeNull(); } + +private: + SkTLazy fContentArea; + GrContext* fContext; + sk_sp fOriginal; + SkAlphaType fAlphaType; + SkColorSpace* fColorSpace; + uint32_t fUniqueID; + + sk_sp refTextureProxyCopy(const CopyParams ©Params); + + typedef GrTextureProducer INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrTextureContext.cpp b/gfx/skia/skia/src/gpu/GrTextureContext.cpp new file mode 100644 index 000000000000..76b7588e3990 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureContext.cpp @@ -0,0 +1,100 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrTextureContext.h" + +#include "GrContextPriv.h" +#include "GrDrawingManager.h" +#include "GrResourceProvider.h" +#include "GrTextureOpList.h" + +#include "../private/GrAuditTrail.h" + +#define ASSERT_SINGLE_OWNER \ + SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());) +#define RETURN_FALSE_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return false; } + +GrTextureContext::GrTextureContext(GrContext* context, + GrDrawingManager* drawingMgr, + sk_sp textureProxy, + sk_sp colorSpace, + GrAuditTrail* auditTrail, + GrSingleOwner* singleOwner) + : GrSurfaceContext(context, drawingMgr, std::move(colorSpace), auditTrail, singleOwner) + , fTextureProxy(std::move(textureProxy)) + , fOpList(SkSafeRef(fTextureProxy->getLastTextureOpList())) { + SkDEBUGCODE(this->validate();) +} + +#ifdef SK_DEBUG +void GrTextureContext::validate() const { + SkASSERT(fTextureProxy); + fTextureProxy->validate(fContext); + + if (fOpList && !fOpList->isClosed()) { + SkASSERT(fTextureProxy->getLastOpList() == fOpList); + } +} +#endif + +GrTextureContext::~GrTextureContext() { + ASSERT_SINGLE_OWNER + SkSafeUnref(fOpList); +} + +GrRenderTargetProxy* GrTextureContext::asRenderTargetProxy() { + // If the proxy can return an RTProxy it should've been wrapped in a RTContext + SkASSERT(!fTextureProxy->asRenderTargetProxy()); + return nullptr; +} + +sk_sp GrTextureContext::asRenderTargetProxyRef() { + // If the proxy can return an RTProxy it should've been wrapped in a RTContext + SkASSERT(!fTextureProxy->asRenderTargetProxy()); + return nullptr; +} + +GrTextureOpList* GrTextureContext::getOpList() { + ASSERT_SINGLE_OWNER + SkDEBUGCODE(this->validate();) + + if (!fOpList || fOpList->isClosed()) { + fOpList = this->drawingManager()->newOpList(fTextureProxy.get()); + } + + return fOpList; +} + +// TODO: move this (and GrRenderTargetContext::copy) to GrSurfaceContext? +bool GrTextureContext::onCopy(GrSurfaceProxy* srcProxy, + const SkIRect& srcRect, + const SkIPoint& dstPoint) { + ASSERT_SINGLE_OWNER + RETURN_FALSE_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrTextureContext::copy"); + +#ifndef ENABLE_MDB + // We can't yet fully defer copies to textures, so GrTextureContext::copySurface will + // execute the copy immediately. Ensure the data is ready. + fContext->contextPriv().flushSurfaceWrites(srcProxy); +#endif + + GrTextureOpList* opList = this->getOpList(); + bool result = opList->copySurface(fContext->resourceProvider(), + fTextureProxy.get(), srcProxy, srcRect, dstPoint); + +#ifndef ENABLE_MDB + GrOpFlushState flushState(fContext->getGpu(), nullptr); + opList->prepareOps(&flushState); + opList->executeOps(&flushState); + opList->reset(); +#endif + + return result; +} + diff --git a/gfx/skia/skia/src/gpu/GrTextureContext.h b/gfx/skia/skia/src/gpu/GrTextureContext.h new file mode 100644 index 000000000000..995ebf53d248 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureContext.h @@ -0,0 +1,62 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTextureContext_DEFINED +#define GrTextureContext_DEFINED + +#include "GrSurfaceContext.h" +#include "../private/GrTextureProxy.h" + +class GrContext; +class GrDrawingManager; +class GrSurface; +class GrTextureOpList; +class GrTextureProxy; +struct SkIPoint; +struct SkIRect; + +/** + * A helper object to orchestrate commands (currently just copies) for GrSurfaces that are + * GrTextures and not GrRenderTargets. + */ +class SK_API GrTextureContext : public GrSurfaceContext { +public: + ~GrTextureContext() override; + + GrSurfaceProxy* asSurfaceProxy() override { return fTextureProxy.get(); } + const GrSurfaceProxy* asSurfaceProxy() const override { return fTextureProxy.get(); } + sk_sp asSurfaceProxyRef() override { return fTextureProxy; } + + GrTextureProxy* asTextureProxy() override { return fTextureProxy.get(); } + sk_sp asTextureProxyRef() override { return fTextureProxy; } + + GrRenderTargetProxy* asRenderTargetProxy() override; + sk_sp asRenderTargetProxyRef() override; + +protected: + GrTextureContext(GrContext*, GrDrawingManager*, sk_sp, + sk_sp, GrAuditTrail*, GrSingleOwner*); + + SkDEBUGCODE(void validate() const;) + +private: + friend class GrDrawingManager; // for ctor + + bool onCopy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override; + + GrTextureOpList* getOpList(); + + sk_sp fTextureProxy; + + // In MDB-mode the GrOpList can be closed by some other renderTargetContext that has picked + // it up. For this reason, the GrOpList should only ever be accessed via 'getOpList'. + GrTextureOpList* fOpList; + + typedef GrSurfaceContext INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrTextureMaker.cpp b/gfx/skia/skia/src/gpu/GrTextureMaker.cpp new file mode 100644 index 000000000000..4fb0c0db41e8 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureMaker.cpp @@ -0,0 +1,115 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrTextureMaker.h" + +#include "GrContext.h" +#include "GrGpu.h" +#include "GrResourceProvider.h" + +sk_sp GrTextureMaker::refTextureProxyForParams(const GrSamplerParams& params, + SkColorSpace* dstColorSpace, + sk_sp* texColorSpace, + SkScalar scaleAdjust[2]) { + CopyParams copyParams; + bool willBeMipped = params.filterMode() == GrSamplerParams::kMipMap_FilterMode; + + if (!fContext->caps()->mipMapSupport()) { + willBeMipped = false; + } + + if (texColorSpace) { + *texColorSpace = this->getColorSpace(dstColorSpace); + } + + if (!fContext->getGpu()->isACopyNeededForTextureParams(this->width(), this->height(), params, + ©Params, scaleAdjust)) { + return this->refOriginalTextureProxy(willBeMipped, dstColorSpace); + } + GrUniqueKey copyKey; + this->makeCopyKey(copyParams, ©Key, dstColorSpace); + if (copyKey.isValid()) { + sk_sp result(fContext->resourceProvider()->findProxyByUniqueKey(copyKey)); + if (result) { + return result; + } + } + + sk_sp result(this->generateTextureProxyForParams(copyParams, willBeMipped, + dstColorSpace)); + if (!result) { + return nullptr; + } + + if (copyKey.isValid()) { + fContext->resourceProvider()->assignUniqueKeyToProxy(copyKey, result.get()); + this->didCacheCopy(copyKey); + } + return result; +} + +sk_sp GrTextureMaker::createFragmentProcessor( + const SkMatrix& textureMatrix, + const SkRect& constraintRect, + FilterConstraint filterConstraint, + bool coordsLimitedToConstraintRect, + const GrSamplerParams::FilterMode* filterOrNullForBicubic, + SkColorSpace* dstColorSpace) { + + const GrSamplerParams::FilterMode* fmForDetermineDomain = filterOrNullForBicubic; + if (filterOrNullForBicubic && GrSamplerParams::kMipMap_FilterMode == *filterOrNullForBicubic && + kYes_FilterConstraint == filterConstraint) { + // TODo: Here we should force a copy restricted to the constraintRect since MIP maps will + // read outside the constraint rect. However, as in the adjuster case, we aren't currently + // doing that. + // We instead we compute the domain as though were bilerping which is only correct if we + // only sample level 0. + static const GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode; + fmForDetermineDomain = &kBilerp; + } + + GrSamplerParams params; + if (filterOrNullForBicubic) { + params.reset(SkShader::kClamp_TileMode, *filterOrNullForBicubic); + } else { + // Bicubic doesn't use filtering for it's texture accesses. + params.reset(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode); + } + sk_sp texColorSpace; + SkScalar scaleAdjust[2] = { 1.0f, 1.0f }; + sk_sp proxy(this->refTextureProxyForParams(params, dstColorSpace, + &texColorSpace, + scaleAdjust)); + if (!proxy) { + return nullptr; + } + SkMatrix adjustedMatrix = textureMatrix; + adjustedMatrix.postScale(scaleAdjust[0], scaleAdjust[1]); + SkRect domain; + DomainMode domainMode = + DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, + proxy.get(), + nullptr, fmForDetermineDomain, &domain); + SkASSERT(kTightCopy_DomainMode != domainMode); + sk_sp colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(), + dstColorSpace); + return CreateFragmentProcessorForDomainAndFilter(fContext->resourceProvider(), std::move(proxy), + std::move(colorSpaceXform), + adjustedMatrix, domainMode, domain, + filterOrNullForBicubic); +} + +sk_sp GrTextureMaker::generateTextureProxyForParams(const CopyParams& copyParams, + bool willBeMipped, + SkColorSpace* dstColorSpace) { + sk_sp original(this->refOriginalTextureProxy(willBeMipped, dstColorSpace)); + if (!original) { + return nullptr; + } + + return CopyOnGpu(fContext, std::move(original), nullptr, copyParams); +} diff --git a/gfx/skia/skia/src/gpu/GrTextureMaker.h b/gfx/skia/skia/src/gpu/GrTextureMaker.h new file mode 100644 index 000000000000..909d3480bf6b --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureMaker.h @@ -0,0 +1,79 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTextureMaker_DEFINED +#define GrTextureMaker_DEFINED + +#include "GrTextureProducer.h" + +/** + * Base class for sources that start out as something other than a texture (encoded image, + * picture, ...). + */ +class GrTextureMaker : public GrTextureProducer { +public: + /** + * Returns a texture that is safe for use with the params. If the size of the returned texture + * does not match width()/height() then the contents of the original must be scaled to fit + * the texture. Additionally, the 'scaleAdjust' must be applied to the texture matrix + * in order to correct the absolute texture coordinates. + * Places the color space of the texture in (*texColorSpace). + */ + sk_sp refTextureProxyForParams(const GrSamplerParams&, + SkColorSpace* dstColorSpace, + sk_sp* texColorSpace, + SkScalar scaleAdjust[2]); + + sk_sp createFragmentProcessor( + const SkMatrix& textureMatrix, + const SkRect& constraintRect, + FilterConstraint filterConstraint, + bool coordsLimitedToConstraintRect, + const GrSamplerParams::FilterMode* filterOrNullForBicubic, + SkColorSpace* dstColorSpace) override; + +protected: + GrTextureMaker(GrContext* context, int width, int height, bool isAlphaOnly) + : INHERITED(width, height, isAlphaOnly) + , fContext(context) {} + + /** + * Return the maker's "original" texture. It is the responsibility of the maker to handle any + * caching of the original if desired. + */ + virtual sk_sp refOriginalTextureProxy(bool willBeMipped, + SkColorSpace* dstColorSpace) = 0; + + /** + * Returns the color space of the maker's "original" texture, assuming it was retrieved with + * the same destination color space. + */ + virtual sk_sp getColorSpace(SkColorSpace* dstColorSpace) = 0; + + /** + * Return a new (uncached) texture that is the stretch of the maker's original. + * + * The base-class handles general logic for this, and only needs access to the following + * method: + * - refOriginalTextureProxy() + * + * Subclass may override this if they can handle creating the texture more directly than + * by copying. + */ + virtual sk_sp generateTextureProxyForParams(const CopyParams&, + bool willBeMipped, + SkColorSpace* dstColorSpace); + + GrContext* context() const { return fContext; } + +private: + GrContext* fContext; + + typedef GrTextureProducer INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrTextureOpList.cpp b/gfx/skia/skia/src/gpu/GrTextureOpList.cpp new file mode 100644 index 000000000000..d2d922643a19 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureOpList.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrTextureOpList.h" + +#include "GrAuditTrail.h" +#include "GrGpu.h" +#include "GrTextureProxy.h" +#include "SkStringUtils.h" +#include "ops/GrCopySurfaceOp.h" + +//////////////////////////////////////////////////////////////////////////////// + +GrTextureOpList::GrTextureOpList(GrTextureProxy* tex, GrGpu* gpu, GrAuditTrail* auditTrail) + : INHERITED(tex, auditTrail) + , fGpu(SkRef(gpu)) { +} + +GrTextureOpList::~GrTextureOpList() { + fGpu->unref(); +} + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG +void GrTextureOpList::dump() const { + INHERITED::dump(); + + SkDebugf("ops (%d):\n", fRecordedOps.count()); + for (int i = 0; i < fRecordedOps.count(); ++i) { + SkDebugf("*******************************\n"); + SkDebugf("%d: %s\n", i, fRecordedOps[i]->name()); + SkString str = fRecordedOps[i]->dumpInfo(); + SkDebugf("%s\n", str.c_str()); + const SkRect& clippedBounds = fRecordedOps[i]->bounds(); + SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", + clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight, + clippedBounds.fBottom); + } +} +#endif + +void GrTextureOpList::prepareOps(GrOpFlushState* flushState) { + // MDB TODO: add SkASSERT(this->isClosed()); + + // Loop over the ops that haven't yet generated their geometry + for (int i = 0; i < fRecordedOps.count(); ++i) { + if (fRecordedOps[i]) { + // We do not call flushState->setDrawOpArgs as this op list does not support GrDrawOps. + fRecordedOps[i]->prepare(flushState); + } + } +} + +bool GrTextureOpList::executeOps(GrOpFlushState* flushState) { + if (0 == fRecordedOps.count()) { + return false; + } + + for (int i = 0; i < fRecordedOps.count(); ++i) { + // We do not call flushState->setDrawOpArgs as this op list does not support GrDrawOps. + fRecordedOps[i]->execute(flushState); + } + + fGpu->finishOpList(); + return true; +} + +void GrTextureOpList::reset() { + fRecordedOps.reset(); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool GrTextureOpList::copySurface(GrResourceProvider* resourceProvider, + GrSurfaceProxy* dst, + GrSurfaceProxy* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint) { + std::unique_ptr op = GrCopySurfaceOp::Make(resourceProvider, dst, src, srcRect, dstPoint); + if (!op) { + return false; + } +#ifdef ENABLE_MDB + this->addDependency(src); +#endif + + // See the comment in GrRenderTargetOpList about why we pass the invalid ID here. + this->recordOp(std::move(op), + GrGpuResource::UniqueID::InvalidID(), + GrSurfaceProxy::UniqueID::InvalidID()); + return true; +} + +void GrTextureOpList::recordOp(std::unique_ptr op, + GrGpuResource::UniqueID resourceUniqueID, + GrSurfaceProxy::UniqueID proxyUniqueID) { + // A closed GrOpList should never receive new/more ops + SkASSERT(!this->isClosed()); + + GR_AUDIT_TRAIL_ADD_OP(fAuditTrail, op.get(), resourceUniqueID, proxyUniqueID); + GrOP_INFO("Re-Recording (%s, B%u)\n" + "\tBounds LRTB (%f, %f, %f, %f)\n", + op->name(), + op->uniqueID(), + op->bounds().fLeft, op->bounds().fRight, + op->bounds().fTop, op->bounds().fBottom); + GrOP_INFO(SkTabString(op->dumpInfo(), 1).c_str()); + GR_AUDIT_TRAIL_OP_RESULT_NEW(fAuditTrail, op.get()); + + fRecordedOps.emplace_back(std::move(op)); +} diff --git a/gfx/skia/skia/src/gpu/GrTextureOpList.h b/gfx/skia/skia/src/gpu/GrTextureOpList.h new file mode 100644 index 000000000000..22828fd93669 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureOpList.h @@ -0,0 +1,78 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTexureOpList_DEFINED +#define GrTexureOpList_DEFINED + +#include "GrGpuResource.h" +#include "GrOpList.h" +#include "GrSurfaceProxy.h" + +#include "SkTArray.h" + +class GrAuditTrail; +class GrGpu; +class GrOp; +class GrTextureProxy; +struct SkIPoint; +struct SkIRect; + +class GrTextureOpList final : public GrOpList { +public: + GrTextureOpList(GrTextureProxy*, GrGpu*, GrAuditTrail*); + + ~GrTextureOpList() override; + + /** + * Empties the draw buffer of any queued ops. + */ + void reset() override; + + void abandonGpuResources() override {} + void freeGpuResources() override {} + + /** + * Together these two functions flush all queued ops to GrGpuCommandBuffer. The return value + * of executeOps() indicates whether any commands were actually issued to the GPU. + */ + void prepareOps(GrOpFlushState* flushState) override; + bool executeOps(GrOpFlushState* flushState) override; + + /** + * Copies a pixel rectangle from one surface to another. This call may finalize + * reserved vertex/index data (as though a draw call was made). The src pixels + * copied are specified by srcRect. They are copied to a rect of the same + * size in dst with top left at dstPoint. If the src rect is clipped by the + * src bounds then pixel values in the dst rect corresponding to area clipped + * by the src rect are not overwritten. This method is not guaranteed to succeed + * depending on the type of surface, configs, etc, and the backend-specific + * limitations. + */ + bool copySurface(GrResourceProvider* resourceProvider, + GrSurfaceProxy* dst, + GrSurfaceProxy* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint); + + GrTextureOpList* asTextureOpList() override { return this; } + + SkDEBUGCODE(void dump() const override;) + +private: + // MDB TODO: The unique IDs are only needed for the audit trail. There should only be one + // on the opList itself. + void recordOp(std::unique_ptr, + GrGpuResource::UniqueID resourceUniqueID, + GrSurfaceProxy::UniqueID proxyUniqueID); + + SkSTArray<2, std::unique_ptr, true> fRecordedOps; + GrGpu* fGpu; + + typedef GrOpList INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.cpp b/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.cpp deleted file mode 100644 index f51cc54aba77..000000000000 --- a/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.cpp +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrTextureParamsAdjuster.h" - -#include "GrCaps.h" -#include "GrColorSpaceXform.h" -#include "GrContext.h" -#include "GrDrawContext.h" -#include "GrGpu.h" -#include "GrGpuResourcePriv.h" -#include "GrResourceKey.h" -#include "GrTexture.h" -#include "GrTextureParams.h" -#include "GrTextureProvider.h" -#include "SkCanvas.h" -#include "SkGr.h" -#include "SkGrPriv.h" -#include "effects/GrBicubicEffect.h" -#include "effects/GrSimpleTextureEffect.h" -#include "effects/GrTextureDomain.h" - -typedef GrTextureProducer::CopyParams CopyParams; - -////////////////////////////////////////////////////////////////////////////// - -static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset, - const CopyParams& copyParams) { - SkASSERT(!subset || !subset->isEmpty()); - GrContext* context = inputTexture->getContext(); - SkASSERT(context); - - GrPixelConfig config = GrMakePixelConfigUncompressed(inputTexture->config()); - - sk_sp copyDC = context->makeDrawContextWithFallback(SkBackingFit::kExact, - copyParams.fWidth, - copyParams.fHeight, - config, nullptr); - if (!copyDC) { - return nullptr; - } - - GrPaint paint; - paint.setGammaCorrect(true); - - SkScalar sx SK_INIT_TO_AVOID_WARNING; - SkScalar sy SK_INIT_TO_AVOID_WARNING; - if (subset) { - sx = 1.f / inputTexture->width(); - sy = 1.f / inputTexture->height(); - } - - if (copyParams.fFilter != GrTextureParams::kNone_FilterMode && subset && - (subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) { - SkRect domain; - domain.fLeft = (subset->fLeft + 0.5f) * sx; - domain.fTop = (subset->fTop + 0.5f)* sy; - domain.fRight = (subset->fRight - 0.5f) * sx; - domain.fBottom = (subset->fBottom - 0.5f) * sy; - // This would cause us to read values from outside the subset. Surely, the caller knows - // better! - SkASSERT(copyParams.fFilter != GrTextureParams::kMipMap_FilterMode); - paint.addColorFragmentProcessor( - GrTextureDomainEffect::Make(inputTexture, nullptr, SkMatrix::I(), domain, - GrTextureDomain::kClamp_Mode, - copyParams.fFilter)); - } else { - GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter); - paint.addColorTextureProcessor(inputTexture, nullptr, SkMatrix::I(), params); - } - paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - - SkRect localRect; - if (subset) { - localRect = SkRect::Make(*subset); - localRect.fLeft *= sx; - localRect.fTop *= sy; - localRect.fRight *= sx; - localRect.fBottom *= sy; - } else { - localRect = SkRect::MakeWH(1.f, 1.f); - } - - SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight); - copyDC->fillRectToRect(GrNoClip(), paint, SkMatrix::I(), dstRect, localRect); - return copyDC->asTexture().release(); -} - -GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, SkAlphaType alphaType, - const SkIRect& contentArea, uint32_t uniqueID, - SkColorSpace* cs) - : INHERITED(contentArea.width(), contentArea.height(), - GrPixelConfigIsAlphaOnly(original->config())) - , fOriginal(original) - , fAlphaType(alphaType) - , fColorSpace(cs) - , fUniqueID(uniqueID) -{ - SkASSERT(SkIRect::MakeWH(original->width(), original->height()).contains(contentArea)); - if (contentArea.fLeft > 0 || contentArea.fTop > 0 || - contentArea.fRight < original->width() || contentArea.fBottom < original->height()) { - fContentArea.set(contentArea); - } -} - -void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) { - GrUniqueKey baseKey; - GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeWH(this->width(), this->height())); - MakeCopyKeyFromOrigKey(baseKey, params, copyKey); -} - -void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) { - // We don't currently have a mechanism for notifications on Images! -} - -SkColorSpace* GrTextureAdjuster::getColorSpace() { - return fColorSpace; -} - -GrTexture* GrTextureAdjuster::refCopy(const CopyParams& copyParams) { - GrTexture* texture = this->originalTexture(); - GrContext* context = texture->getContext(); - const SkIRect* contentArea = this->contentAreaOrNull(); - GrUniqueKey key; - this->makeCopyKey(copyParams, &key); - if (key.isValid()) { - GrTexture* cachedCopy = context->textureProvider()->findAndRefTextureByUniqueKey(key); - if (cachedCopy) { - return cachedCopy; - } - } - GrTexture* copy = copy_on_gpu(texture, contentArea, copyParams); - if (copy) { - if (key.isValid()) { - copy->resourcePriv().setUniqueKey(key); - this->didCacheCopy(key); - } - } - return copy; -} - -GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& params, - SkSourceGammaTreatment gammaTreatment, - SkIPoint* outOffset) { - GrTexture* texture = this->originalTexture(); - GrContext* context = texture->getContext(); - CopyParams copyParams; - const SkIRect* contentArea = this->contentAreaOrNull(); - - if (!context) { - // The texture was abandoned. - return nullptr; - } - - if (contentArea && GrTextureParams::kMipMap_FilterMode == params.filterMode()) { - // If we generate a MIP chain for texture it will read pixel values from outside the content - // area. - copyParams.fWidth = contentArea->width(); - copyParams.fHeight = contentArea->height(); - copyParams.fFilter = GrTextureParams::kBilerp_FilterMode; - } else if (!context->getGpu()->makeCopyForTextureParams(texture, params, ©Params)) { - if (outOffset) { - if (contentArea) { - outOffset->set(contentArea->fLeft, contentArea->fRight); - } else { - outOffset->set(0, 0); - } - } - return SkRef(texture); - } - - GrTexture* copy = this->refCopy(copyParams); - if (copy && outOffset) { - outOffset->set(0, 0); - } - return copy; -} - -enum DomainMode { - kNoDomain_DomainMode, - kDomain_DomainMode, - kTightCopy_DomainMode -}; - -/** Determines whether a texture domain is necessary and if so what domain to use. There are two - * rectangles to consider: - * - The first is the content area specified by the texture adjuster. We can *never* allow - * filtering to cause bleed of pixels outside this rectangle. - * - The second rectangle is the constraint rectangle, which is known to be contained by the - * content area. The filterConstraint specifies whether we are allowed to bleed across this - * rect. - * - * We want to avoid using a domain if possible. We consider the above rectangles, the filter type, - * and whether the coords generated by the draw would all fall within the constraint rect. If the - * latter is true we only need to consider whether the filter would extend beyond the rects. - */ -static DomainMode determine_domain_mode( - const SkRect& constraintRect, - GrTextureAdjuster::FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, - int texW, int texH, - const SkIRect* textureContentArea, - const GrTextureParams::FilterMode* filterModeOrNullForBicubic, - SkRect* domainRect) { - - SkASSERT(SkRect::MakeIWH(texW, texH).contains(constraintRect)); - // We only expect a content area rect if there is some non-content area. - SkASSERT(!textureContentArea || - (!textureContentArea->contains(SkIRect::MakeWH(texW, texH)) && - SkRect::Make(*textureContentArea).contains(constraintRect))); - - SkRect textureBounds = SkRect::MakeIWH(texW, texH); - // If the src rectangle contains the whole texture then no need for a domain. - if (constraintRect.contains(textureBounds)) { - return kNoDomain_DomainMode; - } - - bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint); - - // If we can filter outside the constraint rect, and there is no non-content area of the - // texture, and we aren't going to generate sample coords outside the constraint rect then we - // don't need a domain. - if (!restrictFilterToRect && !textureContentArea && coordsLimitedToConstraintRect) { - return kNoDomain_DomainMode; - } - - // Get the domain inset based on sampling mode (or bail if mipped) - SkScalar filterHalfWidth = 0.f; - if (filterModeOrNullForBicubic) { - switch (*filterModeOrNullForBicubic) { - case GrTextureParams::kNone_FilterMode: - if (coordsLimitedToConstraintRect) { - return kNoDomain_DomainMode; - } else { - filterHalfWidth = 0.f; - } - break; - case GrTextureParams::kBilerp_FilterMode: - filterHalfWidth = .5f; - break; - case GrTextureParams::kMipMap_FilterMode: - if (restrictFilterToRect || textureContentArea) { - // No domain can save us here. - return kTightCopy_DomainMode; - } - return kNoDomain_DomainMode; - } - } else { - // bicubic does nearest filtering internally. - filterHalfWidth = 1.5f; - } - - // Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center - // of the edge texel. Pinning to the texel center has no impact on nearest mode and MIP-maps - - static const SkScalar kDomainInset = 0.5f; - // Figure out the limits of pixels we're allowed to sample from. - // Unless we know the amount of outset and the texture matrix we have to conservatively enforce - // the domain. - if (restrictFilterToRect) { - domainRect->fLeft = constraintRect.fLeft + kDomainInset; - domainRect->fTop = constraintRect.fTop + kDomainInset; - domainRect->fRight = constraintRect.fRight - kDomainInset; - domainRect->fBottom = constraintRect.fBottom - kDomainInset; - } else if (textureContentArea) { - // If we got here then: there is a textureContentArea, the coords are limited to the - // constraint rect, and we're allowed to filter across the constraint rect boundary. So - // we check whether the filter would reach across the edge of the content area. - // We will only set the sides that are required. - - domainRect->setLargest(); - if (coordsLimitedToConstraintRect) { - // We may be able to use the fact that the texture coords are limited to the constraint - // rect in order to avoid having to add a domain. - bool needContentAreaConstraint = false; - if (textureContentArea->fLeft > 0 && - textureContentArea->fLeft + filterHalfWidth > constraintRect.fLeft) { - domainRect->fLeft = textureContentArea->fLeft + kDomainInset; - needContentAreaConstraint = true; - } - if (textureContentArea->fTop > 0 && - textureContentArea->fTop + filterHalfWidth > constraintRect.fTop) { - domainRect->fTop = textureContentArea->fTop + kDomainInset; - needContentAreaConstraint = true; - } - if (textureContentArea->fRight < texW && - textureContentArea->fRight - filterHalfWidth < constraintRect.fRight) { - domainRect->fRight = textureContentArea->fRight - kDomainInset; - needContentAreaConstraint = true; - } - if (textureContentArea->fBottom < texH && - textureContentArea->fBottom - filterHalfWidth < constraintRect.fBottom) { - domainRect->fBottom = textureContentArea->fBottom - kDomainInset; - needContentAreaConstraint = true; - } - if (!needContentAreaConstraint) { - return kNoDomain_DomainMode; - } - } else { - // Our sample coords for the texture are allowed to be outside the constraintRect so we - // don't consider it when computing the domain. - if (textureContentArea->fLeft != 0) { - domainRect->fLeft = textureContentArea->fLeft + kDomainInset; - } - if (textureContentArea->fTop != 0) { - domainRect->fTop = textureContentArea->fTop + kDomainInset; - } - if (textureContentArea->fRight != texW) { - domainRect->fRight = textureContentArea->fRight - kDomainInset; - } - if (textureContentArea->fBottom != texH) { - domainRect->fBottom = textureContentArea->fBottom - kDomainInset; - } - } - } else { - return kNoDomain_DomainMode; - } - - if (domainRect->fLeft > domainRect->fRight) { - domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight); - } - if (domainRect->fTop > domainRect->fBottom) { - domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, domainRect->fBottom); - } - domainRect->fLeft /= texW; - domainRect->fTop /= texH; - domainRect->fRight /= texW; - domainRect->fBottom /= texH; - return kDomain_DomainMode; -} - -static sk_sp create_fp_for_domain_and_filter( - GrTexture* texture, - sk_sp colorSpaceXform, - const SkMatrix& textureMatrix, - DomainMode domainMode, - const SkRect& domain, - const GrTextureParams::FilterMode* filterOrNullForBicubic) { - SkASSERT(kTightCopy_DomainMode != domainMode); - if (filterOrNullForBicubic) { - if (kDomain_DomainMode == domainMode) { - return GrTextureDomainEffect::Make(texture, std::move(colorSpaceXform), textureMatrix, - domain, GrTextureDomain::kClamp_Mode, - *filterOrNullForBicubic); - } else { - GrTextureParams params(SkShader::kClamp_TileMode, *filterOrNullForBicubic); - return GrSimpleTextureEffect::Make(texture, std::move(colorSpaceXform), textureMatrix, - params); - } - } else { - if (kDomain_DomainMode == domainMode) { - return GrBicubicEffect::Make(texture, std::move(colorSpaceXform), textureMatrix, - domain); - } else { - static const SkShader::TileMode kClampClamp[] = - { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode }; - return GrBicubicEffect::Make(texture, std::move(colorSpaceXform), textureMatrix, - kClampClamp); - } - } -} - -sk_sp GrTextureAdjuster::createFragmentProcessor( - const SkMatrix& origTextureMatrix, - const SkRect& origConstraintRect, - FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, - const GrTextureParams::FilterMode* filterOrNullForBicubic, - SkColorSpace* dstColorSpace, - SkSourceGammaTreatment gammaTreatment) { - - SkMatrix textureMatrix = origTextureMatrix; - const SkIRect* contentArea = this->contentAreaOrNull(); - // Convert the constraintRect to be relative to the texture rather than the content area so - // that both rects are in the same coordinate system. - SkTCopyOnFirstWrite constraintRect(origConstraintRect); - if (contentArea) { - SkScalar l = SkIntToScalar(contentArea->fLeft); - SkScalar t = SkIntToScalar(contentArea->fTop); - constraintRect.writable()->offset(l, t); - textureMatrix.postTranslate(l, t); - } - - SkRect domain; - GrTextureParams params; - if (filterOrNullForBicubic) { - params.setFilterMode(*filterOrNullForBicubic); - } - SkAutoTUnref texture(this->refTextureSafeForParams(params, gammaTreatment, nullptr)); - if (!texture) { - return nullptr; - } - // If we made a copy then we only copied the contentArea, in which case the new texture is all - // content. - if (texture != this->originalTexture()) { - contentArea = nullptr; - } - - DomainMode domainMode = - determine_domain_mode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect, - texture->width(), texture->height(), - contentArea, filterOrNullForBicubic, - &domain); - if (kTightCopy_DomainMode == domainMode) { - // TODO: Copy the texture and adjust the texture matrix (both parts need to consider - // non-int constraint rect) - // For now: treat as bilerp and ignore what goes on above level 0. - - // We only expect MIP maps to require a tight copy. - SkASSERT(filterOrNullForBicubic && - GrTextureParams::kMipMap_FilterMode == *filterOrNullForBicubic); - static const GrTextureParams::FilterMode kBilerp = GrTextureParams::kBilerp_FilterMode; - domainMode = - determine_domain_mode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect, - texture->width(), texture->height(), - contentArea, &kBilerp, &domain); - SkASSERT(kTightCopy_DomainMode != domainMode); - } - SkASSERT(kNoDomain_DomainMode == domainMode || - (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom)); - textureMatrix.postIDiv(texture->width(), texture->height()); - sk_sp colorSpaceXform = GrColorSpaceXform::Make(this->getColorSpace(), - dstColorSpace); - return create_fp_for_domain_and_filter(texture, std::move(colorSpaceXform), textureMatrix, - domainMode, domain, filterOrNullForBicubic); -} - -////////////////////////////////////////////////////////////////////////////// - -GrTexture* GrTextureMaker::refTextureForParams(const GrTextureParams& params, - SkSourceGammaTreatment gammaTreatment) { - CopyParams copyParams; - bool willBeMipped = params.filterMode() == GrTextureParams::kMipMap_FilterMode; - - if (!fContext->caps()->mipMapSupport()) { - willBeMipped = false; - } - - if (!fContext->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params, - ©Params)) { - return this->refOriginalTexture(willBeMipped, gammaTreatment); - } - GrUniqueKey copyKey; - this->makeCopyKey(copyParams, ©Key); - if (copyKey.isValid()) { - GrTexture* result = fContext->textureProvider()->findAndRefTextureByUniqueKey(copyKey); - if (result) { - return result; - } - } - - GrTexture* result = this->generateTextureForParams(copyParams, willBeMipped, gammaTreatment); - if (!result) { - return nullptr; - } - - if (copyKey.isValid()) { - fContext->textureProvider()->assignUniqueKeyToTexture(copyKey, result); - this->didCacheCopy(copyKey); - } - return result; -} - -sk_sp GrTextureMaker::createFragmentProcessor( - const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, - const GrTextureParams::FilterMode* filterOrNullForBicubic, - SkColorSpace* dstColorSpace, - SkSourceGammaTreatment gammaTreatment) { - - const GrTextureParams::FilterMode* fmForDetermineDomain = filterOrNullForBicubic; - if (filterOrNullForBicubic && GrTextureParams::kMipMap_FilterMode == *filterOrNullForBicubic && - kYes_FilterConstraint == filterConstraint) { - // TODo: Here we should force a copy restricted to the constraintRect since MIP maps will - // read outside the constraint rect. However, as in the adjuster case, we aren't currently - // doing that. - // We instead we compute the domain as though were bilerping which is only correct if we - // only sample level 0. - static const GrTextureParams::FilterMode kBilerp = GrTextureParams::kBilerp_FilterMode; - fmForDetermineDomain = &kBilerp; - } - - GrTextureParams params; - if (filterOrNullForBicubic) { - params.reset(SkShader::kClamp_TileMode, *filterOrNullForBicubic); - } else { - // Bicubic doesn't use filtering for it's texture accesses. - params.reset(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode); - } - SkAutoTUnref texture(this->refTextureForParams(params, gammaTreatment)); - if (!texture) { - return nullptr; - } - SkRect domain; - DomainMode domainMode = - determine_domain_mode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, - texture->width(), texture->height(), nullptr, fmForDetermineDomain, - &domain); - SkASSERT(kTightCopy_DomainMode != domainMode); - SkMatrix normalizedTextureMatrix = textureMatrix; - normalizedTextureMatrix.postIDiv(texture->width(), texture->height()); - sk_sp colorSpaceXform = GrColorSpaceXform::Make(this->getColorSpace(), - dstColorSpace); - return create_fp_for_domain_and_filter(texture, std::move(colorSpaceXform), - normalizedTextureMatrix, domainMode, domain, - filterOrNullForBicubic); -} - -GrTexture* GrTextureMaker::generateTextureForParams(const CopyParams& copyParams, bool willBeMipped, - SkSourceGammaTreatment gammaTreatment) { - SkAutoTUnref original(this->refOriginalTexture(willBeMipped, gammaTreatment)); - if (!original) { - return nullptr; - } - return copy_on_gpu(original, nullptr, copyParams); -} diff --git a/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.h b/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.h deleted file mode 100644 index 3de4db7441c4..000000000000 --- a/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrTextureMaker_DEFINED -#define GrTextureMaker_DEFINED - -#include "GrTextureParams.h" -#include "GrResourceKey.h" -#include "GrTexture.h" -#include "SkTLazy.h" - -class GrContext; -class GrTextureParams; -class GrUniqueKey; -class SkBitmap; - -/** - * Different GPUs and API extensions have different requirements with respect to what texture - * sampling parameters may be used with textures of various types. This class facilitates making - * texture compatible with a given GrTextureParams. There are two immediate subclasses defined - * below. One is a base class for sources that are inherently texture-backed (e.g. a texture-backed - * SkImage). It supports subsetting the original texture. The other is for use cases where the - * source can generate a texture that represents some content (e.g. cpu pixels, SkPicture, ...). - */ -class GrTextureProducer : public SkNoncopyable { -public: - struct CopyParams { - GrTextureParams::FilterMode fFilter; - int fWidth; - int fHeight; - }; - - enum FilterConstraint { - kYes_FilterConstraint, - kNo_FilterConstraint, - }; - - /** - * Helper for creating a fragment processor to sample the texture with a given filtering mode. - * It attempts to avoid making texture copies or using domains whenever possible. - * - * @param textureMatrix Matrix used to access the texture. It is applied to - * the local coords. The post-transformed coords should - * be in texel units (rather than normalized) with - * respect to this Producer's bounds (width()/height()). - * @param constraintRect A rect that represents the area of the texture to be - * sampled. It must be contained in the Producer's bounds - * as defined by width()/height(). - * @param filterConstriant Indicates whether filtering is limited to - * constraintRect. - * @param coordsLimitedToConstraintRect Is it known that textureMatrix*localCoords is bound - * by the portion of the texture indicated by - * constraintRect (without consideration of filter - * width, just the raw coords). - * @param filterOrNullForBicubic If non-null indicates the filter mode. If null means - * use bicubic filtering. - **/ - virtual sk_sp createFragmentProcessor( - const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, - const GrTextureParams::FilterMode* filterOrNullForBicubic, - SkColorSpace* dstColorSpace, - SkSourceGammaTreatment) = 0; - - virtual ~GrTextureProducer() {} - - int width() const { return fWidth; } - int height() const { return fHeight; } - bool isAlphaOnly() const { return fIsAlphaOnly; } - virtual SkAlphaType alphaType() const = 0; - virtual SkColorSpace* getColorSpace() = 0; - -protected: - GrTextureProducer(int width, int height, bool isAlphaOnly) - : fWidth(width) - , fHeight(height) - , fIsAlphaOnly(isAlphaOnly) {} - - /** Helper for creating a key for a copy from an original key. */ - static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey, - const CopyParams& copyParams, - GrUniqueKey* copyKey) { - SkASSERT(!copyKey->isValid()); - if (origKey.isValid()) { - static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3); - builder[0] = copyParams.fFilter; - builder[1] = copyParams.fWidth; - builder[2] = copyParams.fHeight; - } - } - - /** - * If we need to make a copy in order to be compatible with GrTextureParams producer is asked to - * return a key that identifies its original content + the CopyParms parameter. If the producer - * does not want to cache the stretched version (e.g. the producer is volatile), this should - * simply return without initializing the copyKey. - */ - virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey) = 0; - - /** - * If a stretched version of the texture is generated, it may be cached (assuming that - * makeCopyKey() returns true). In that case, the maker is notified in case it - * wants to note that for when the maker is destroyed. - */ - virtual void didCacheCopy(const GrUniqueKey& copyKey) = 0; - -private: - const int fWidth; - const int fHeight; - const bool fIsAlphaOnly; - - typedef SkNoncopyable INHERITED; -}; - -/** - * Base class for sources that start out as textures. Optionally allows for a content area subrect. - * The intent is not to use content area for subrect rendering. Rather, the pixels outside the - * content area have undefined values and shouldn't be read *regardless* of filtering mode or - * the SkCanvas::SrcRectConstraint used for subrect draws. - */ -class GrTextureAdjuster : public GrTextureProducer { -public: - /** Makes the subset of the texture safe to use with the given texture parameters. - outOffset will be the top-left corner of the subset if a copy is not made. Otherwise, - the copy will be tight to the contents and outOffset will be (0, 0). If the copy's size - does not match subset's dimensions then the contents are scaled to fit the copy.*/ - GrTexture* refTextureSafeForParams(const GrTextureParams&, SkSourceGammaTreatment, - SkIPoint* outOffset); - - sk_sp createFragmentProcessor( - const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint, - bool coordsLimitedToConstraintRect, - const GrTextureParams::FilterMode* filterOrNullForBicubic, - SkColorSpace* dstColorSpace, - SkSourceGammaTreatment) override; - - // We do not ref the texture nor the colorspace, so the caller must keep them in scope while - // this Adjuster is alive. - GrTextureAdjuster(GrTexture*, SkAlphaType, const SkIRect& area, uint32_t uniqueID, - SkColorSpace*); - -protected: - SkAlphaType alphaType() const override { return fAlphaType; } - SkColorSpace* getColorSpace() override; - void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) override; - void didCacheCopy(const GrUniqueKey& copyKey) override; - - GrTexture* originalTexture() const { return fOriginal; } - - /** Returns the content area or null for the whole original texture */ - const SkIRect* contentAreaOrNull() { return fContentArea.getMaybeNull(); } - -private: - SkTLazy fContentArea; - GrTexture* fOriginal; - SkAlphaType fAlphaType; - SkColorSpace* fColorSpace; - uint32_t fUniqueID; - - GrTexture* refCopy(const CopyParams ©Params); - - typedef GrTextureProducer INHERITED; -}; - -/** - * Base class for sources that start out as something other than a texture (encoded image, - * picture, ...). - */ -class GrTextureMaker : public GrTextureProducer { -public: - /** Returns a texture that is safe for use with the params. If the size of the returned texture - does not match width()/height() then the contents of the original must be scaled to fit - the texture. */ - GrTexture* refTextureForParams(const GrTextureParams&, SkSourceGammaTreatment); - - sk_sp createFragmentProcessor( - const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, - const GrTextureParams::FilterMode* filterOrNullForBicubic, - SkColorSpace* dstColorSpace, - SkSourceGammaTreatment) override; - -protected: - GrTextureMaker(GrContext* context, int width, int height, bool isAlphaOnly) - : INHERITED(width, height, isAlphaOnly) - , fContext(context) {} - - /** - * Return the maker's "original" texture. It is the responsibility of the maker to handle any - * caching of the original if desired. - */ - virtual GrTexture* refOriginalTexture(bool willBeMipped, SkSourceGammaTreatment) = 0; - - /** - * Return a new (uncached) texture that is the stretch of the maker's original. - * - * The base-class handles general logic for this, and only needs access to the following - * method: - * - refOriginalTexture() - * - * Subclass may override this if they can handle creating the texture more directly than - * by copying. - */ - virtual GrTexture* generateTextureForParams(const CopyParams&, bool willBeMipped, - SkSourceGammaTreatment); - - GrContext* context() const { return fContext; } - -private: - GrContext* fContext; - - typedef GrTextureProducer INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/GrTexturePriv.h b/gfx/skia/skia/src/gpu/GrTexturePriv.h index c4e6538d1664..cc0a05edfd88 100644 --- a/gfx/skia/skia/src/gpu/GrTexturePriv.h +++ b/gfx/skia/skia/src/gpu/GrTexturePriv.h @@ -8,6 +8,7 @@ #ifndef GrTexturePriv_DEFINED #define GrTexturePriv_DEFINED +#include "GrExternalTextureData.h" #include "GrTexture.h" /** Class that adds methods to GrTexture that are only intended for use internal to Skia. @@ -49,10 +50,32 @@ public: return fTexture->fMaxMipMapLevel; } - void setGammaTreatment(SkSourceGammaTreatment gammaTreatment) const { - fTexture->fGammaTreatment = gammaTreatment; + GrSLType imageStorageType() const { + if (GrPixelConfigIsSint(fTexture->config())) { + return kIImageStorage2D_GrSLType; + } else { + return kImageStorage2D_GrSLType; + } + } + + GrSLType samplerType() const { return fTexture->fSamplerType; } + + /** The filter used is clamped to this value in GrProcessor::TextureSampler. */ + GrSamplerParams::FilterMode highestFilterMode() const { return fTexture->fHighestFilterMode; } + + void setMipColorMode(SkDestinationSurfaceColorMode colorMode) const { + fTexture->fMipColorMode = colorMode; + } + SkDestinationSurfaceColorMode mipColorMode() const { return fTexture->fMipColorMode; } + + /** + * Return the native bookkeeping data for this texture, and detach the backend object from + * this GrTexture. It's lifetime will no longer be managed by Ganesh, and this GrTexture will + * no longer refer to it. Leaves this GrTexture in an orphan state. + */ + std::unique_ptr detachBackendTexture() { + return fTexture->detachBackendTexture(); } - SkSourceGammaTreatment gammaTreatment() const { return fTexture->fGammaTreatment; } static void ComputeScratchKey(const GrSurfaceDesc&, GrScratchKey*); diff --git a/gfx/skia/skia/src/gpu/GrTextureProducer.cpp b/gfx/skia/skia/src/gpu/GrTextureProducer.cpp new file mode 100644 index 000000000000..d226c3feb60c --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureProducer.cpp @@ -0,0 +1,260 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrTextureProducer.h" +#include "GrClip.h" +#include "GrRenderTargetContext.h" +#include "GrResourceProvider.h" +#include "GrSurfaceProxy.h" +#include "GrSurfaceProxyPriv.h" +#include "GrTexture.h" +#include "effects/GrBicubicEffect.h" +#include "effects/GrSimpleTextureEffect.h" +#include "effects/GrTextureDomain.h" + +sk_sp GrTextureProducer::CopyOnGpu(GrContext* context, + sk_sp inputProxy, + const SkIRect* subset, + const CopyParams& copyParams) { + SkASSERT(!subset || !subset->isEmpty()); + SkASSERT(context); + + GrPixelConfig config = GrMakePixelConfigUncompressed(inputProxy->config()); + + const SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight); + + sk_sp copyRTC = context->makeRenderTargetContextWithFallback( + SkBackingFit::kExact, dstRect.width(), dstRect.height(), config, nullptr); + if (!copyRTC) { + return nullptr; + } + + GrPaint paint; + paint.setGammaCorrect(true); + + SkRect localRect; + if (subset) { + localRect = SkRect::Make(*subset); + } else { + localRect = SkRect::MakeWH(inputProxy->width(), inputProxy->height()); + } + + bool needsDomain = false; + if (copyParams.fFilter != GrSamplerParams::kNone_FilterMode) { + bool resizing = localRect.width() != dstRect.width() || + localRect.height() != dstRect.height(); + + if (GrResourceProvider::IsFunctionallyExact(inputProxy.get())) { + needsDomain = subset && resizing; + } else { + needsDomain = resizing; + } + } + + if (needsDomain) { + const SkRect domain = localRect.makeInset(0.5f, 0.5f); + // This would cause us to read values from outside the subset. Surely, the caller knows + // better! + SkASSERT(copyParams.fFilter != GrSamplerParams::kMipMap_FilterMode); + paint.addColorFragmentProcessor( + GrTextureDomainEffect::Make(context->resourceProvider(), std::move(inputProxy), + nullptr, SkMatrix::I(), + domain, GrTextureDomain::kClamp_Mode, copyParams.fFilter)); + } else { + GrSamplerParams params(SkShader::kClamp_TileMode, copyParams.fFilter); + paint.addColorTextureProcessor(context->resourceProvider(), std::move(inputProxy), + nullptr, SkMatrix::I(), params); + } + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + + copyRTC->fillRectToRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect, + localRect); + return copyRTC->asTextureProxyRef(); +} + +/** Determines whether a texture domain is necessary and if so what domain to use. There are two + * rectangles to consider: + * - The first is the content area specified by the texture adjuster (i.e., textureContentArea). + * We can *never* allow filtering to cause bleed of pixels outside this rectangle. + * - The second rectangle is the constraint rectangle (i.e., constraintRect), which is known to + * be contained by the content area. The filterConstraint specifies whether we are allowed to + * bleed across this rect. + * + * We want to avoid using a domain if possible. We consider the above rectangles, the filter type, + * and whether the coords generated by the draw would all fall within the constraint rect. If the + * latter is true we only need to consider whether the filter would extend beyond the rects. + */ +GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode( + const SkRect& constraintRect, + FilterConstraint filterConstraint, + bool coordsLimitedToConstraintRect, + GrTextureProxy* proxy, + const SkIRect* contentRect, + const GrSamplerParams::FilterMode* filterModeOrNullForBicubic, + SkRect* domainRect) { + const SkIRect proxyBounds = SkIRect::MakeWH(proxy->width(), proxy->height()); + + SkASSERT(proxyBounds.contains(constraintRect)); + // We only expect a content area rect if there is some non-content area. + SkASSERT(!contentRect || + (!contentRect->contains(proxyBounds) && + proxyBounds.contains(*contentRect) && + contentRect->contains(constraintRect))); + + const bool proxyIsExact = GrResourceProvider::IsFunctionallyExact(proxy); + + // If the constraint rectangle contains the whole proxy then no need for a domain. + if (constraintRect.contains(proxyBounds) && proxyIsExact) { + return kNoDomain_DomainMode; + } + + if (!contentRect && !proxyIsExact) { + contentRect = &proxyBounds; + } + + bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint); + + // If we can filter outside the constraint rect, and there is no non-content area of the + // proxy, and we aren't going to generate sample coords outside the constraint rect then we + // don't need a domain. + if (!restrictFilterToRect && !contentRect && coordsLimitedToConstraintRect) { + return kNoDomain_DomainMode; + } + + // Get the domain inset based on sampling mode (or bail if mipped) + SkScalar filterHalfWidth = 0.f; + if (filterModeOrNullForBicubic) { + switch (*filterModeOrNullForBicubic) { + case GrSamplerParams::kNone_FilterMode: + if (coordsLimitedToConstraintRect) { + return kNoDomain_DomainMode; + } else { + filterHalfWidth = 0.f; + } + break; + case GrSamplerParams::kBilerp_FilterMode: + filterHalfWidth = .5f; + break; + case GrSamplerParams::kMipMap_FilterMode: + if (restrictFilterToRect || contentRect) { + // No domain can save us here. + return kTightCopy_DomainMode; + } + return kNoDomain_DomainMode; + } + } else { + // bicubic does nearest filtering internally. + filterHalfWidth = 1.5f; + } + + // Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center + // of the edge texel. Pinning to the texel center has no impact on nearest mode and MIP-maps + + static const SkScalar kDomainInset = 0.5f; + // Figure out the limits of pixels we're allowed to sample from. + // Unless we know the amount of outset and the texture matrix we have to conservatively enforce + // the domain. + if (restrictFilterToRect) { + *domainRect = constraintRect.makeInset(kDomainInset, kDomainInset); + } else if (contentRect) { + // If we got here then: there is a contentRect, the coords are limited to the + // constraint rect, and we're allowed to filter across the constraint rect boundary. So + // we check whether the filter would reach across the edge of the content area. + // We will only set the sides that are required. + + domainRect->setLargest(); + if (coordsLimitedToConstraintRect) { + // We may be able to use the fact that the texture coords are limited to the constraint + // rect in order to avoid having to add a domain. + bool needContentAreaConstraint = false; + if (contentRect->fLeft > 0 && + contentRect->fLeft + filterHalfWidth > constraintRect.fLeft) { + domainRect->fLeft = contentRect->fLeft + kDomainInset; + needContentAreaConstraint = true; + } + if (contentRect->fTop > 0 && + contentRect->fTop + filterHalfWidth > constraintRect.fTop) { + domainRect->fTop = contentRect->fTop + kDomainInset; + needContentAreaConstraint = true; + } + if ((!proxyIsExact || contentRect->fRight < proxy->width()) && + contentRect->fRight - filterHalfWidth < constraintRect.fRight) { + domainRect->fRight = contentRect->fRight - kDomainInset; + needContentAreaConstraint = true; + } + if ((!proxyIsExact || contentRect->fBottom < proxy->height()) && + contentRect->fBottom - filterHalfWidth < constraintRect.fBottom) { + domainRect->fBottom = contentRect->fBottom - kDomainInset; + needContentAreaConstraint = true; + } + if (!needContentAreaConstraint) { + return kNoDomain_DomainMode; + } + } else { + // Our sample coords for the texture are allowed to be outside the constraintRect so we + // don't consider it when computing the domain. + if (contentRect->fLeft > 0) { + domainRect->fLeft = contentRect->fLeft + kDomainInset; + } + if (contentRect->fTop > 0) { + domainRect->fTop = contentRect->fTop + kDomainInset; + } + if (!proxyIsExact || contentRect->fRight < proxy->width()) { + domainRect->fRight = contentRect->fRight - kDomainInset; + } + if (!proxyIsExact || contentRect->fBottom < proxy->height()) { + domainRect->fBottom = contentRect->fBottom - kDomainInset; + } + } + } else { + return kNoDomain_DomainMode; + } + + if (domainRect->fLeft > domainRect->fRight) { + domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight); + } + if (domainRect->fTop > domainRect->fBottom) { + domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, domainRect->fBottom); + } + return kDomain_DomainMode; +} + +sk_sp GrTextureProducer::CreateFragmentProcessorForDomainAndFilter( + GrResourceProvider* resourceProvider, + sk_sp proxy, + sk_sp colorSpaceXform, + const SkMatrix& textureMatrix, + DomainMode domainMode, + const SkRect& domain, + const GrSamplerParams::FilterMode* filterOrNullForBicubic) { + SkASSERT(kTightCopy_DomainMode != domainMode); + if (filterOrNullForBicubic) { + if (kDomain_DomainMode == domainMode) { + return GrTextureDomainEffect::Make(resourceProvider, std::move(proxy), + std::move(colorSpaceXform), textureMatrix, + domain, GrTextureDomain::kClamp_Mode, + *filterOrNullForBicubic); + } else { + GrSamplerParams params(SkShader::kClamp_TileMode, *filterOrNullForBicubic); + return GrSimpleTextureEffect::Make(resourceProvider, std::move(proxy), + std::move(colorSpaceXform), textureMatrix, + params); + } + } else { + if (kDomain_DomainMode == domainMode) { + return GrBicubicEffect::Make(resourceProvider, std::move(proxy), + std::move(colorSpaceXform), + textureMatrix, domain); + } else { + static const SkShader::TileMode kClampClamp[] = + { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode }; + return GrBicubicEffect::Make(resourceProvider, std::move(proxy), + std::move(colorSpaceXform), + textureMatrix, kClampClamp); + } + } +} diff --git a/gfx/skia/skia/src/gpu/GrTextureProducer.h b/gfx/skia/skia/src/gpu/GrTextureProducer.h new file mode 100644 index 000000000000..35e60f05526d --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureProducer.h @@ -0,0 +1,151 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTextureProducer_DEFINED +#define GrTextureProducer_DEFINED + +#include "GrSamplerParams.h" +#include "GrResourceKey.h" + +class GrColorSpaceXform; +class GrResourceProvider; +class GrTexture; +class GrTextureProxy; + +/** + * Different GPUs and API extensions have different requirements with respect to what texture + * sampling parameters may be used with textures of various types. This class facilitates making + * texture compatible with a given GrSamplerParams. There are two immediate subclasses defined + * below. One is a base class for sources that are inherently texture-backed (e.g. a texture-backed + * SkImage). It supports subsetting the original texture. The other is for use cases where the + * source can generate a texture that represents some content (e.g. cpu pixels, SkPicture, ...). + */ +class GrTextureProducer : public SkNoncopyable { +public: + struct CopyParams { + GrSamplerParams::FilterMode fFilter; + int fWidth; + int fHeight; + }; + + enum FilterConstraint { + kYes_FilterConstraint, + kNo_FilterConstraint, + }; + + /** + * Helper for creating a fragment processor to sample the texture with a given filtering mode. + * It attempts to avoid making texture copies or using domains whenever possible. + * + * @param textureMatrix Matrix used to access the texture. It is applied to + * the local coords. The post-transformed coords should + * be in texel units (rather than normalized) with + * respect to this Producer's bounds (width()/height()). + * @param constraintRect A rect that represents the area of the texture to be + * sampled. It must be contained in the Producer's + * bounds as defined by width()/height(). + * @param filterConstriant Indicates whether filtering is limited to + * constraintRect. + * @param coordsLimitedToConstraintRect Is it known that textureMatrix*localCoords is bound + * by the portion of the texture indicated by + * constraintRect (without consideration of filter + * width, just the raw coords). + * @param filterOrNullForBicubic If non-null indicates the filter mode. If null means + * use bicubic filtering. + **/ + virtual sk_sp createFragmentProcessor( + const SkMatrix& textureMatrix, + const SkRect& constraintRect, + FilterConstraint filterConstraint, + bool coordsLimitedToConstraintRect, + const GrSamplerParams::FilterMode* filterOrNullForBicubic, + SkColorSpace* dstColorSpace) = 0; + + virtual ~GrTextureProducer() {} + + int width() const { return fWidth; } + int height() const { return fHeight; } + bool isAlphaOnly() const { return fIsAlphaOnly; } + virtual SkAlphaType alphaType() const = 0; + +protected: + friend class GrTextureProducer_TestAccess; + + GrTextureProducer(int width, int height, bool isAlphaOnly) + : fWidth(width) + , fHeight(height) + , fIsAlphaOnly(isAlphaOnly) {} + + /** Helper for creating a key for a copy from an original key. */ + static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey, + const CopyParams& copyParams, + GrUniqueKey* copyKey) { + SkASSERT(!copyKey->isValid()); + if (origKey.isValid()) { + static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); + GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3); + builder[0] = copyParams.fFilter; + builder[1] = copyParams.fWidth; + builder[2] = copyParams.fHeight; + } + } + + /** + * If we need to make a copy in order to be compatible with GrTextureParams producer is asked to + * return a key that identifies its original content + the CopyParms parameter. If the producer + * does not want to cache the stretched version (e.g. the producer is volatile), this should + * simply return without initializing the copyKey. If the texture generated by this producer + * depends on the destination color space, then that information should also be incorporated + * in the key. + */ + virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey, + SkColorSpace* dstColorSpace) = 0; + + /** + * If a stretched version of the texture is generated, it may be cached (assuming that + * makeCopyKey() returns true). In that case, the maker is notified in case it + * wants to note that for when the maker is destroyed. + */ + virtual void didCacheCopy(const GrUniqueKey& copyKey) = 0; + + + enum DomainMode { + kNoDomain_DomainMode, + kDomain_DomainMode, + kTightCopy_DomainMode + }; + + static sk_sp CopyOnGpu(GrContext*, sk_sp inputProxy, + const SkIRect* subset, const CopyParams& copyParams); + + static DomainMode DetermineDomainMode( + const SkRect& constraintRect, + FilterConstraint filterConstraint, + bool coordsLimitedToConstraintRect, + GrTextureProxy*, + const SkIRect* textureContentArea, + const GrSamplerParams::FilterMode* filterModeOrNullForBicubic, + SkRect* domainRect); + + static sk_sp CreateFragmentProcessorForDomainAndFilter( + GrResourceProvider*, + sk_sp proxy, + sk_sp, + const SkMatrix& textureMatrix, + DomainMode, + const SkRect& domain, + const GrSamplerParams::FilterMode* filterOrNullForBicubic); + +private: + const int fWidth; + const int fHeight; + const bool fIsAlphaOnly; + + typedef SkNoncopyable INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrTextureProvider.cpp b/gfx/skia/skia/src/gpu/GrTextureProvider.cpp deleted file mode 100644 index 68a554048403..000000000000 --- a/gfx/skia/skia/src/gpu/GrTextureProvider.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrTextureProvider.h" - -#include "GrCaps.h" -#include "GrTexturePriv.h" -#include "GrResourceCache.h" -#include "GrGpu.h" -#include "../private/GrSingleOwner.h" -#include "SkMathPriv.h" -#include "SkTArray.h" - -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) - -enum ScratchTextureFlags { - kExact_ScratchTextureFlag = 0x1, - kNoPendingIO_ScratchTextureFlag = 0x2, - kNoCreate_ScratchTextureFlag = 0x4, -}; - -GrTextureProvider::GrTextureProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* singleOwner) - : fCache(cache) - , fGpu(gpu) -#ifdef SK_DEBUG - , fSingleOwner(singleOwner) -#endif - { -} - -GrTexture* GrTextureProvider::createMipMappedTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, - const GrMipLevel* texels, int mipLevelCount) { - ASSERT_SINGLE_OWNER - - if (this->isAbandoned()) { - return nullptr; - } - if (mipLevelCount && !texels) { - return nullptr; - } - for (int i = 0; i < mipLevelCount; ++i) { - if (!texels[i].fPixels) { - return nullptr; - } - } - - if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) && - !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { - return nullptr; - } - if (!GrPixelConfigIsCompressed(desc.fConfig)) { - if (mipLevelCount < 2) { - static const uint32_t kFlags = kExact_ScratchTextureFlag | - kNoCreate_ScratchTextureFlag; - if (GrTexture* texture = this->refScratchTexture(desc, kFlags)) { - if (!mipLevelCount || - texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, - texels[0].fPixels, texels[0].fRowBytes)) { - if (SkBudgeted::kNo == budgeted) { - texture->resourcePriv().makeUnbudgeted(); - } - return texture; - } - texture->unref(); - } - } - } - - SkTArray texelsShallowCopy(mipLevelCount); - for (int i = 0; i < mipLevelCount; ++i) { - texelsShallowCopy.push_back(texels[i]); - } - return fGpu->createTexture(desc, budgeted, texelsShallowCopy); -} - -GrTexture* GrTextureProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, - const void* srcData, size_t rowBytes) { - GrMipLevel tempTexels; - GrMipLevel* texels = nullptr; - int levelCount = 0; - if (srcData) { - tempTexels.fPixels = srcData; - tempTexels.fRowBytes = rowBytes; - texels = &tempTexels; - levelCount = 1; - } - return this->createMipMappedTexture(desc, budgeted, texels, levelCount); -} - -GrTexture* GrTextureProvider::createApproxTexture(const GrSurfaceDesc& desc) { - ASSERT_SINGLE_OWNER - return this->internalCreateApproxTexture(desc, 0); -} - -GrTexture* GrTextureProvider::internalCreateApproxTexture(const GrSurfaceDesc& desc, - uint32_t scratchFlags) { - ASSERT_SINGLE_OWNER - if (this->isAbandoned()) { - return nullptr; - } - // Currently we don't recycle compressed textures as scratch. - if (GrPixelConfigIsCompressed(desc.fConfig)) { - return nullptr; - } else { - return this->refScratchTexture(desc, scratchFlags); - } -} - -GrTexture* GrTextureProvider::refScratchTexture(const GrSurfaceDesc& inDesc, - uint32_t flags) { - ASSERT_SINGLE_OWNER - SkASSERT(!this->isAbandoned()); - SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig)); - - SkTCopyOnFirstWrite desc(inDesc); - - if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) { - if (!(kExact_ScratchTextureFlag & flags)) { - // bin by pow2 with a reasonable min - const int kMinSize = 16; - GrSurfaceDesc* wdesc = desc.writable(); - wdesc->fWidth = SkTMax(kMinSize, GrNextPow2(desc->fWidth)); - wdesc->fHeight = SkTMax(kMinSize, GrNextPow2(desc->fHeight)); - } - - GrScratchKey key; - GrTexturePriv::ComputeScratchKey(*desc, &key); - uint32_t scratchFlags = 0; - if (kNoPendingIO_ScratchTextureFlag & flags) { - scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag; - } else if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) { - // If it is not a render target then it will most likely be populated by - // writePixels() which will trigger a flush if the texture has pending IO. - scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag; - } - GrGpuResource* resource = fCache->findAndRefScratchResource(key, - GrSurface::WorstCaseSize(*desc), - scratchFlags); - if (resource) { - GrSurface* surface = static_cast(resource); - GrRenderTarget* rt = surface->asRenderTarget(); - if (rt && fGpu->caps()->discardRenderTargetSupport()) { - rt->discard(); - } - return surface->asTexture(); - } - } - - if (!(kNoCreate_ScratchTextureFlag & flags)) { - return fGpu->createTexture(*desc, SkBudgeted::kYes); - } - - return nullptr; -} - -GrTexture* GrTextureProvider::wrapBackendTexture(const GrBackendTextureDesc& desc, - GrWrapOwnership ownership) { - ASSERT_SINGLE_OWNER - if (this->isAbandoned()) { - return nullptr; - } - return fGpu->wrapBackendTexture(desc, ownership); -} - -GrRenderTarget* GrTextureProvider::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) { - ASSERT_SINGLE_OWNER - return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(desc, - kBorrow_GrWrapOwnership); -} - -void GrTextureProvider::assignUniqueKeyToResource(const GrUniqueKey& key, GrGpuResource* resource) { - ASSERT_SINGLE_OWNER - if (this->isAbandoned() || !resource) { - return; - } - resource->resourcePriv().setUniqueKey(key); -} - -bool GrTextureProvider::existsResourceWithUniqueKey(const GrUniqueKey& key) const { - ASSERT_SINGLE_OWNER - return this->isAbandoned() ? false : fCache->hasUniqueKey(key); -} - -GrGpuResource* GrTextureProvider::findAndRefResourceByUniqueKey(const GrUniqueKey& key) { - ASSERT_SINGLE_OWNER - return this->isAbandoned() ? nullptr : fCache->findAndRefUniqueResource(key); -} - -GrTexture* GrTextureProvider::findAndRefTextureByUniqueKey(const GrUniqueKey& key) { - ASSERT_SINGLE_OWNER - GrGpuResource* resource = this->findAndRefResourceByUniqueKey(key); - if (resource) { - GrTexture* texture = static_cast(resource)->asTexture(); - SkASSERT(texture); - return texture; - } - return NULL; -} diff --git a/gfx/skia/skia/src/gpu/GrTextureProxy.cpp b/gfx/skia/skia/src/gpu/GrTextureProxy.cpp index 205dfdd31353..ce7770d8ecb5 100644 --- a/gfx/skia/skia/src/gpu/GrTextureProxy.cpp +++ b/gfx/skia/skia/src/gpu/GrTextureProxy.cpp @@ -7,45 +7,44 @@ #include "GrTextureProxy.h" -#include "GrTextureProvider.h" -#include "GrGpuResourcePriv.h" +#include "GrResourceProvider.h" +#include "GrTexturePriv.h" GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit fit, SkBudgeted budgeted, - const void* /*srcData*/, size_t /*rowBytes*/) - : INHERITED(srcDesc, fit, budgeted) { - // TODO: Handle 'srcData' here + const void* srcData, size_t /*rowBytes*/, uint32_t flags) + : INHERITED(srcDesc, fit, budgeted, flags) { + SkASSERT(!srcData); // currently handled in Make() } -GrTextureProxy::GrTextureProxy(sk_sp tex) - : INHERITED(tex->desc(), SkBackingFit::kExact, - tex->resourcePriv().isBudgeted(), tex->uniqueID()) - , fTexture(std::move(tex)) { +GrTextureProxy::GrTextureProxy(sk_sp surf) + : INHERITED(std::move(surf), SkBackingFit::kExact) { } -GrTexture* GrTextureProxy::instantiate(GrTextureProvider* texProvider) { - if (fTexture) { - return fTexture.get(); +GrTexture* GrTextureProxy::instantiate(GrResourceProvider* resourceProvider) { + GrSurface* surf = this->INHERITED::instantiate(resourceProvider); + if (!surf) { + return nullptr; } - if (SkBackingFit::kApprox == fFit) { - fTexture.reset(texProvider->createApproxTexture(fDesc)); - } else { - fTexture.reset(texProvider->createTexture(fDesc, fBudgeted)); + return fTarget->asTexture(); +} + +void GrTextureProxy::setMipColorMode(SkDestinationSurfaceColorMode colorMode) { + SkASSERT(fTarget || fTarget->asTexture()); + + if (fTarget) { + fTarget->asTexture()->texturePriv().setMipColorMode(colorMode); } - return fTexture.get(); + fMipColorMode = colorMode; } -sk_sp GrTextureProxy::Make(const GrSurfaceDesc& desc, - SkBackingFit fit, - SkBudgeted budgeted, - const void* srcData, - size_t rowBytes) { - // TODO: handle 'srcData' (we could use the wrapped version if there is data) - SkASSERT(!srcData && !rowBytes); - return sk_sp(new GrTextureProxy(desc, fit, budgeted, srcData, rowBytes)); -} +size_t GrTextureProxy::onGpuMemorySize() const { + if (fTarget) { + return fTarget->gpuMemorySize(); + } -sk_sp GrTextureProxy::Make(sk_sp tex) { - return sk_sp(new GrTextureProxy(std::move(tex))); + static const bool kHasMipMaps = true; + // TODO: add tracking of mipmap state to improve the estimate + return GrSurface::ComputeSize(fDesc, 1, kHasMipMaps, SkBackingFit::kApprox == fFit); } diff --git a/gfx/skia/skia/src/gpu/GrTextureRenderTargetProxy.cpp b/gfx/skia/skia/src/gpu/GrTextureRenderTargetProxy.cpp new file mode 100644 index 000000000000..432d00854fef --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTextureRenderTargetProxy.cpp @@ -0,0 +1,43 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrTextureRenderTargetProxy.h" + +// Deferred version +// This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and +// GrRenderTargetProxy) so its constructor must be explicitly called. +GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps, + const GrSurfaceDesc& desc, + SkBackingFit fit, + SkBudgeted budgeted, + uint32_t flags) + : GrSurfaceProxy(desc, fit, budgeted, flags) + // for now textures w/ data are always wrapped + , GrTextureProxy(desc, fit, budgeted, nullptr, 0, flags) + , GrRenderTargetProxy(caps, desc, fit, budgeted, flags) { +} + +// Wrapped version +// This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and +// GrRenderTargetProxy) so its constructor must be explicitly called. +GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(sk_sp surf) + : GrSurfaceProxy(surf, SkBackingFit::kExact) + , GrTextureProxy(sk_ref_sp(surf->asTexture())) + , GrRenderTargetProxy(sk_ref_sp(surf->asRenderTarget())) { + SkASSERT(surf->asTexture()); + SkASSERT(surf->asRenderTarget()); +} + +size_t GrTextureRenderTargetProxy::onGpuMemorySize() const { + if (fTarget) { + return fTarget->gpuMemorySize(); + } + + // TODO: do we have enough information to improve this worst case estimate? + return GrSurface::ComputeSize(fDesc, fDesc.fSampleCnt+1, true, SkBackingFit::kApprox == fFit); +} + diff --git a/gfx/skia/skia/include/private/GrTextureStripAtlas.h b/gfx/skia/skia/src/gpu/GrTextureStripAtlas.h similarity index 97% rename from gfx/skia/skia/include/private/GrTextureStripAtlas.h rename to gfx/skia/skia/src/gpu/GrTextureStripAtlas.h index 5b90a342d7f9..5658b161edc1 100644 --- a/gfx/skia/skia/include/private/GrTextureStripAtlas.h +++ b/gfx/skia/skia/src/gpu/GrTextureStripAtlas.h @@ -15,6 +15,9 @@ #include "SkTDynamicHash.h" #include "SkTypes.h" +class GrSurfaceContext; +class GrTextureProxy; + /** * Maintains a single large texture whose rows store many textures of a small fixed height, * stored in rows across the x-axis such that we can safely wrap/repeat them horizontally. @@ -71,7 +74,8 @@ public: SkScalar getNormalizedTexelHeight() const { return fNormalizedYHeight; } GrContext* getContext() const { return fDesc.fContext; } - GrTexture* getTexture() const { return fTexture; } + + sk_sp asTextureProxyRef() const; private: @@ -168,7 +172,7 @@ private: const Desc fDesc; const uint16_t fNumRows; - GrTexture* fTexture; + sk_sp fTexContext; SkScalar fNormalizedYHeight; diff --git a/gfx/skia/skia/src/gpu/GrTextureToYUVPlanes.cpp b/gfx/skia/skia/src/gpu/GrTextureToYUVPlanes.cpp index 93a62d26433f..0a0edee4df66 100644 --- a/gfx/skia/skia/src/gpu/GrTextureToYUVPlanes.cpp +++ b/gfx/skia/skia/src/gpu/GrTextureToYUVPlanes.cpp @@ -10,29 +10,34 @@ #include "effects/GrYUVEffect.h" #include "GrClip.h" #include "GrContext.h" -#include "GrDrawContext.h" #include "GrPaint.h" -#include "GrTextureProvider.h" +#include "GrRenderTargetContext.h" +#include "GrResourceProvider.h" namespace { using MakeFPProc = sk_sp (*)(sk_sp, SkYUVColorSpace colorSpace); }; -static bool convert_texture(GrTexture* src, GrDrawContext* dst, int dstW, int dstH, - SkYUVColorSpace colorSpace, MakeFPProc proc) { +static bool convert_proxy(sk_sp src, + GrRenderTargetContext* dst, int dstW, int dstH, + SkYUVColorSpace colorSpace, MakeFPProc proc) { - SkScalar xScale = SkIntToScalar(src->width()) / dstW / src->width(); - SkScalar yScale = SkIntToScalar(src->height()) / dstH / src->height(); - GrTextureParams::FilterMode filter; + SkScalar xScale = SkIntToScalar(src->width()) / dstW; + SkScalar yScale = SkIntToScalar(src->height()) / dstH; + GrSamplerParams::FilterMode filter; if (dstW == src->width() && dstW == src->height()) { - filter = GrTextureParams::kNone_FilterMode; + filter = GrSamplerParams::kNone_FilterMode; } else { - filter = GrTextureParams::kBilerp_FilterMode; + filter = GrSamplerParams::kBilerp_FilterMode; } - sk_sp fp( - GrSimpleTextureEffect::Make(src, nullptr, SkMatrix::MakeScale(xScale, yScale), filter)); + GrResourceProvider* resourceProvider = dst->resourceProvider(); + + sk_sp fp(GrSimpleTextureEffect::Make(resourceProvider, std::move(src), + nullptr, + SkMatrix::MakeScale(xScale, yScale), + filter)); if (!fp) { return false; } @@ -43,113 +48,124 @@ static bool convert_texture(GrTexture* src, GrDrawContext* dst, int dstW, int ds GrPaint paint; paint.setPorterDuffXPFactory(SkBlendMode::kSrc); paint.addColorFragmentProcessor(std::move(fp)); - dst->drawRect(GrNoClip(), paint, SkMatrix::I(), SkRect::MakeIWH(dstW, dstH)); + dst->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::MakeIWH(dstW, dstH)); return true; } -bool GrTextureToYUVPlanes(GrTexture* texture, const SkISize sizes[3], void* const planes[3], +bool GrTextureToYUVPlanes(GrContext* context, sk_sp proxy, + const SkISize sizes[3], void* const planes[3], const size_t rowBytes[3], SkYUVColorSpace colorSpace) { - if (GrContext* context = texture->getContext()) { + if (!context) { + return false; + } + + { // Depending on the relative sizes of the y, u, and v planes we may do 1 to 3 draws/ // readbacks. - sk_sp yuvDrawContext; - sk_sp yDrawContext; - sk_sp uvDrawContext; - sk_sp uDrawContext; - sk_sp vDrawContext; + sk_sp yuvRenderTargetContext; + sk_sp yRenderTargetContext; + sk_sp uvRenderTargetContext; + sk_sp uRenderTargetContext; + sk_sp vRenderTargetContext; // We issue draw(s) to convert from RGBA to Y, U, and V. All three planes may have different // sizes however we optimize for two other cases - all planes are the same (1 draw to YUV), // and U and V are the same but Y differs (2 draws, one for Y, one for UV). if (sizes[0] == sizes[1] && sizes[1] == sizes[2]) { - yuvDrawContext = context->makeDrawContextWithFallback(SkBackingFit::kApprox, - sizes[0].fWidth, - sizes[0].fHeight, - kRGBA_8888_GrPixelConfig, - nullptr); - if (!yuvDrawContext) { + yuvRenderTargetContext = context->makeRenderTargetContextWithFallback( + SkBackingFit::kApprox, + sizes[0].fWidth, + sizes[0].fHeight, + kRGBA_8888_GrPixelConfig, + nullptr); + if (!yuvRenderTargetContext) { return false; } } else { - yDrawContext = context->makeDrawContextWithFallback(SkBackingFit::kApprox, - sizes[0].fWidth, - sizes[0].fHeight, - kAlpha_8_GrPixelConfig, - nullptr); - if (!yDrawContext) { + yRenderTargetContext = context->makeRenderTargetContextWithFallback( + SkBackingFit::kApprox, + sizes[0].fWidth, + sizes[0].fHeight, + kAlpha_8_GrPixelConfig, + nullptr); + if (!yRenderTargetContext) { return false; } if (sizes[1] == sizes[2]) { // TODO: Add support for GL_RG when available. - uvDrawContext = context->makeDrawContextWithFallback(SkBackingFit::kApprox, - sizes[1].fWidth, - sizes[1].fHeight, - kRGBA_8888_GrPixelConfig, - nullptr); - if (!uvDrawContext) { + uvRenderTargetContext = context->makeRenderTargetContextWithFallback( + SkBackingFit::kApprox, + sizes[1].fWidth, + sizes[1].fHeight, + kRGBA_8888_GrPixelConfig, + nullptr); + if (!uvRenderTargetContext) { return false; } } else { - uDrawContext = context->makeDrawContextWithFallback(SkBackingFit::kApprox, - sizes[1].fWidth, - sizes[1].fHeight, - kAlpha_8_GrPixelConfig, - nullptr); - vDrawContext = context->makeDrawContextWithFallback(SkBackingFit::kApprox, - sizes[2].fWidth, - sizes[2].fHeight, - kAlpha_8_GrPixelConfig, - nullptr); - if (!uDrawContext || !vDrawContext) { + uRenderTargetContext = context->makeRenderTargetContextWithFallback( + SkBackingFit::kApprox, + sizes[1].fWidth, + sizes[1].fHeight, + kAlpha_8_GrPixelConfig, + nullptr); + vRenderTargetContext = context->makeRenderTargetContextWithFallback( + SkBackingFit::kApprox, + sizes[2].fWidth, + sizes[2].fHeight, + kAlpha_8_GrPixelConfig, + nullptr); + if (!uRenderTargetContext || !vRenderTargetContext) { return false; } } } // Do all the draws before any readback. - if (yuvDrawContext) { - if (!convert_texture(texture, yuvDrawContext.get(), - sizes[0].fWidth, sizes[0].fHeight, - colorSpace, GrYUVEffect::MakeRGBToYUV)) { + if (yuvRenderTargetContext) { + if (!convert_proxy(std::move(proxy), yuvRenderTargetContext.get(), + sizes[0].fWidth, sizes[0].fHeight, + colorSpace, GrYUVEffect::MakeRGBToYUV)) { return false; } } else { - SkASSERT(yDrawContext); - if (!convert_texture(texture, yDrawContext.get(), - sizes[0].fWidth, sizes[0].fHeight, - colorSpace, GrYUVEffect::MakeRGBToY)) { + SkASSERT(yRenderTargetContext); + if (!convert_proxy(proxy, yRenderTargetContext.get(), + sizes[0].fWidth, sizes[0].fHeight, + colorSpace, GrYUVEffect::MakeRGBToY)) { return false; } - if (uvDrawContext) { - if (!convert_texture(texture, uvDrawContext.get(), - sizes[1].fWidth, sizes[1].fHeight, - colorSpace, GrYUVEffect::MakeRGBToUV)) { + if (uvRenderTargetContext) { + if (!convert_proxy(std::move(proxy), uvRenderTargetContext.get(), + sizes[1].fWidth, sizes[1].fHeight, + colorSpace, GrYUVEffect::MakeRGBToUV)) { return false; } } else { - SkASSERT(uDrawContext && vDrawContext); - if (!convert_texture(texture, uDrawContext.get(), - sizes[1].fWidth, sizes[1].fHeight, - colorSpace, GrYUVEffect::MakeRGBToU)) { + SkASSERT(uRenderTargetContext && vRenderTargetContext); + if (!convert_proxy(proxy, uRenderTargetContext.get(), + sizes[1].fWidth, sizes[1].fHeight, + colorSpace, GrYUVEffect::MakeRGBToU)) { return false; } - if (!convert_texture(texture, vDrawContext.get(), - sizes[2].fWidth, sizes[2].fHeight, - colorSpace, GrYUVEffect::MakeRGBToV)) { + if (!convert_proxy(std::move(proxy), vRenderTargetContext.get(), + sizes[2].fWidth, sizes[2].fHeight, + colorSpace, GrYUVEffect::MakeRGBToV)) { return false; } } } - if (yuvDrawContext) { + if (yuvRenderTargetContext) { SkASSERT(sizes[0] == sizes[1] && sizes[1] == sizes[2]); - sk_sp yuvTex(yuvDrawContext->asTexture()); - SkASSERT(yuvTex); SkISize yuvSize = sizes[0]; // We have no kRGB_888 pixel format, so readback rgba and then copy three channels. SkAutoSTMalloc<128 * 128, uint32_t> tempYUV(yuvSize.fWidth * yuvSize.fHeight); - if (!yuvTex->readPixels(0, 0, yuvSize.fWidth, yuvSize.fHeight, - kRGBA_8888_GrPixelConfig, tempYUV.get(), 0)) { + + const SkImageInfo ii = SkImageInfo::Make(yuvSize.fWidth, yuvSize.fHeight, + kRGBA_8888_SkColorType, kOpaque_SkAlphaType); + if (!yuvRenderTargetContext->readPixels(ii, tempYUV.get(), 0, 0, 0)) { return false; } size_t yRowBytes = rowBytes[0] ? rowBytes[0] : yuvSize.fWidth; @@ -175,22 +191,23 @@ bool GrTextureToYUVPlanes(GrTexture* texture, const SkISize sizes[3], void* cons } return true; } else { - SkASSERT(yDrawContext); - sk_sp yTex(yDrawContext->asTexture()); - SkASSERT(yTex); - if (!yTex->readPixels(0, 0, sizes[0].fWidth, sizes[0].fHeight, - kAlpha_8_GrPixelConfig, planes[0], rowBytes[0])) { + SkASSERT(yRenderTargetContext); + + SkImageInfo ii = SkImageInfo::MakeA8(sizes[0].fWidth, sizes[0].fHeight); + if (!yRenderTargetContext->readPixels(ii, planes[0], rowBytes[0], 0, 0)) { return false; } - if (uvDrawContext) { + + if (uvRenderTargetContext) { SkASSERT(sizes[1].fWidth == sizes[2].fWidth); - sk_sp uvTex(uvDrawContext->asTexture()); - SkASSERT(uvTex); SkISize uvSize = sizes[1]; // We have no kRG_88 pixel format, so readback rgba and then copy two channels. SkAutoSTMalloc<128 * 128, uint32_t> tempUV(uvSize.fWidth * uvSize.fHeight); - if (!uvTex->readPixels(0, 0, uvSize.fWidth, uvSize.fHeight, - kRGBA_8888_GrPixelConfig, tempUV.get(), 0)) { + + ii = SkImageInfo::Make(uvSize.fWidth, uvSize.fHeight, + kRGBA_8888_SkColorType, kOpaque_SkAlphaType); + + if (!uvRenderTargetContext->readPixels(ii, tempUV.get(), 0, 0, 0)) { return false; } @@ -212,19 +229,18 @@ bool GrTextureToYUVPlanes(GrTexture* texture, const SkISize sizes[3], void* cons } return true; } else { - SkASSERT(uDrawContext && vDrawContext); - sk_sp tex(uDrawContext->asTexture()); - SkASSERT(tex); - if (!tex->readPixels(0, 0, sizes[1].fWidth, sizes[1].fHeight, - kAlpha_8_GrPixelConfig, planes[1], rowBytes[1])) { + SkASSERT(uRenderTargetContext && vRenderTargetContext); + + ii = SkImageInfo::MakeA8(sizes[1].fWidth, sizes[1].fHeight); + if (!uRenderTargetContext->readPixels(ii, planes[1], rowBytes[1], 0, 0)) { return false; } - tex = vDrawContext->asTexture(); - SkASSERT(tex); - if (!tex->readPixels(0, 0, sizes[2].fWidth, sizes[2].fHeight, - kAlpha_8_GrPixelConfig, planes[2], rowBytes[2])) { + + ii = SkImageInfo::MakeA8(sizes[2].fWidth, sizes[2].fHeight); + if (!vRenderTargetContext->readPixels(ii, planes[2], rowBytes[2], 0, 0)) { return false; } + return true; } } diff --git a/gfx/skia/skia/src/gpu/GrTextureToYUVPlanes.h b/gfx/skia/skia/src/gpu/GrTextureToYUVPlanes.h index 67b6fce2eb1f..1dcbea3e9b35 100644 --- a/gfx/skia/skia/src/gpu/GrTextureToYUVPlanes.h +++ b/gfx/skia/skia/src/gpu/GrTextureToYUVPlanes.h @@ -11,9 +11,11 @@ #include "SkImageInfo.h" #include "SkSize.h" -class GrTexture; +class GrContext; +class GrTextureProxy; -bool GrTextureToYUVPlanes(GrTexture* texture, const SkISize[3], void* const planes[3], +bool GrTextureToYUVPlanes(GrContext*, sk_sp, + const SkISize[3], void* const planes[3], const size_t rowBytes[3], SkYUVColorSpace); #endif diff --git a/gfx/skia/skia/src/gpu/GrTracing.h b/gfx/skia/skia/src/gpu/GrTracing.h index 273aa65989f2..1f2a04ace4f6 100644 --- a/gfx/skia/skia/src/gpu/GrTracing.h +++ b/gfx/skia/skia/src/gpu/GrTracing.h @@ -57,7 +57,7 @@ private: /** * GR_CREATE_TRACE_MARKER will place begin and end trace markers for both * cpu and gpu (if gpu tracing enabled) for the current scope. - * name is of type const char* and target is of type GrDrawTarget* + * name is of type const char* and target is of type GrOpList* */ #define GR_CREATE_TRACE_MARKER(name, target) \ /* Chromium tracing */ \ diff --git a/gfx/skia/skia/src/gpu/GrUserStencilSettings.h b/gfx/skia/skia/src/gpu/GrUserStencilSettings.h index 32fb1396f94a..2549c4423725 100644 --- a/gfx/skia/skia/src/gpu/GrUserStencilSettings.h +++ b/gfx/skia/skia/src/gpu/GrUserStencilSettings.h @@ -13,12 +13,12 @@ /** * Gr uses the stencil buffer to implement complex clipping inside the - * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer + * GrOpList class. The GrOpList makes a subset of the stencil buffer * bits available for other uses by external code (user bits). Client code can - * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits + * modify these bits. GrOpList will ignore ref, mask, and writemask bits * provided by clients that fall outside the user range. * - * When code outside the GrDrawTarget class uses the stencil buffer the contract + * When code outside the GrOpList class uses the stencil buffer the contract * is as follows: * * > Normal stencil funcs allow the client to pass / fail regardless of the @@ -182,6 +182,19 @@ struct GrUserStencilSettings { GrUserStencilSettings() = delete; GrUserStencilSettings(const GrUserStencilSettings&) = delete; + uint16_t flags(bool hasStencilClip) const { + return fFrontFlags[hasStencilClip] & fBackFlags[hasStencilClip]; + } + bool isDisabled(bool hasStencilClip) const { + return this->flags(hasStencilClip) & kDisabled_StencilFlag; + } + bool isTwoSided(bool hasStencilClip) const { + return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag); + } + bool usesWrapOp(bool hasStencilClip) const { + return !(this->flags(hasStencilClip) & kNoWrapOps_StencilFlag); + } + const uint16_t fFrontFlags[2]; // frontFlagsForDraw = fFrontFlags[hasStencilClip]. const Face fFront; const uint16_t fBackFlags[2]; // backFlagsForDraw = fBackFlags[hasStencilClip]. diff --git a/gfx/skia/skia/src/gpu/GrWindowRectangles.h b/gfx/skia/skia/src/gpu/GrWindowRectangles.h index 076c40d7a455..4a375860e0de 100644 --- a/gfx/skia/skia/src/gpu/GrWindowRectangles.h +++ b/gfx/skia/skia/src/gpu/GrWindowRectangles.h @@ -19,6 +19,8 @@ public: GrWindowRectangles(const GrWindowRectangles& that) : fCount(0) { *this = that; } ~GrWindowRectangles() { SkSafeUnref(this->rec()); } + GrWindowRectangles makeOffset(int dx, int dy) const; + bool empty() const { return !fCount; } int count() const { return fCount; } const SkIRect* data() const; @@ -50,6 +52,7 @@ struct GrWindowRectangles::Rec : public GrNonAtomicRef { SkASSERT(numWindows < kMaxWindows); memcpy(fData, windows, sizeof(SkIRect) * numWindows); } + Rec() = default; SkIRect fData[kMaxWindows]; }; @@ -74,6 +77,25 @@ inline GrWindowRectangles& GrWindowRectangles::operator=(const GrWindowRectangle return *this; } +inline GrWindowRectangles GrWindowRectangles::makeOffset(int dx, int dy) const { + if (!dx && !dy) { + return *this; + } + GrWindowRectangles result; + result.fCount = fCount; + SkIRect* windows; + if (result.fCount > kNumLocalWindows) { + result.fRec = new Rec(); + windows = result.fRec->fData; + } else { + windows = result.fLocalWindows; + } + for (int i = 0; i < fCount; ++i) { + windows[i] = this->data()[i].makeOffset(dx, dy); + } + return result; +} + inline SkIRect& GrWindowRectangles::addWindow() { SkASSERT(fCount < kMaxWindows); if (fCount < kNumLocalWindows) { diff --git a/gfx/skia/skia/src/gpu/GrWindowRectsState.h b/gfx/skia/skia/src/gpu/GrWindowRectsState.h index 9d3b61b9cb35..bb9c608a8d7c 100644 --- a/gfx/skia/skia/src/gpu/GrWindowRectsState.h +++ b/gfx/skia/skia/src/gpu/GrWindowRectsState.h @@ -18,15 +18,13 @@ public: }; GrWindowRectsState() : fMode(Mode::kExclusive) {} - GrWindowRectsState(const GrWindowRectangles& windows, const SkIPoint& origin, Mode mode) + GrWindowRectsState(const GrWindowRectangles& windows, Mode mode) : fMode(mode) - , fOrigin(origin) , fWindows(windows) { } bool enabled() const { return Mode::kInclusive == fMode || !fWindows.empty(); } Mode mode() const { return fMode; } - const SkIPoint& origin() const { return fOrigin; } const GrWindowRectangles& windows() const { return fWindows; } int numWindows() const { return fWindows.count(); } @@ -35,25 +33,21 @@ public: fWindows.reset(); } - void set(const GrWindowRectangles& windows, const SkIPoint& origin, Mode mode) { + void set(const GrWindowRectangles& windows, Mode mode) { fMode = mode; - fOrigin = origin; fWindows = windows; } - bool cheapEqualTo(const GrWindowRectsState& that) const { + bool operator==(const GrWindowRectsState& that) const { if (fMode != that.fMode) { return false; } - if (!fWindows.empty() && fOrigin != that.fOrigin) { - return false; - } return fWindows == that.fWindows; } + bool operator!=(const GrWindowRectsState& that) const { return !(*this == that); } private: Mode fMode; - SkIPoint fOrigin; GrWindowRectangles fWindows; }; diff --git a/gfx/skia/skia/src/gpu/GrXferProcessor.cpp b/gfx/skia/skia/src/gpu/GrXferProcessor.cpp index 76e0ba0fc491..27c8a963e46d 100644 --- a/gfx/skia/skia/src/gpu/GrXferProcessor.cpp +++ b/gfx/skia/skia/src/gpu/GrXferProcessor.cpp @@ -7,49 +7,13 @@ #include "GrXferProcessor.h" #include "GrPipeline.h" -#include "GrProcOptInfo.h" #include "gl/GrGLCaps.h" -GrXferProcessor::GrXferProcessor() - : fWillReadDstColor(false) - , fDstReadUsesMixedSamples(false) - , fDstTextureOffset() { -} +GrXferProcessor::GrXferProcessor() : fWillReadDstColor(false), fDstReadUsesMixedSamples(false) {} -GrXferProcessor::GrXferProcessor(const DstTexture* dstTexture, - bool willReadDstColor, - bool hasMixedSamples) - : fWillReadDstColor(willReadDstColor) - , fDstReadUsesMixedSamples(willReadDstColor && hasMixedSamples) - , fDstTextureOffset() { - if (dstTexture && dstTexture->texture()) { - SkASSERT(willReadDstColor); - fDstTexture.reset(dstTexture->texture()); - fDstTextureOffset = dstTexture->offset(); - this->addTextureAccess(&fDstTexture); - this->setWillReadFragmentPosition(); - } -} - -GrXferProcessor::OptFlags GrXferProcessor::getOptimizations( - const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const { - GrXferProcessor::OptFlags flags = this->onGetOptimizations(optimizations, - doesStencilWrite, - overrideColor, - caps); - - if (this->willReadDstColor()) { - // When performing a dst read we handle coverage in the base class. - SkASSERT(!(flags & GrXferProcessor::kIgnoreCoverage_OptFlag)); - if (optimizations.fCoveragePOI.isSolidWhite()) { - flags |= GrXferProcessor::kIgnoreCoverage_OptFlag; - } - } - return flags; -} +GrXferProcessor::GrXferProcessor(bool willReadDstColor, bool hasMixedSamples) + : fWillReadDstColor(willReadDstColor) + , fDstReadUsesMixedSamples(willReadDstColor && hasMixedSamples) {} bool GrXferProcessor::hasSecondaryOutput() const { if (!this->willReadDstColor()) { @@ -67,12 +31,13 @@ void GrXferProcessor::getBlendInfo(BlendInfo* blendInfo) const { } } -void GrXferProcessor::getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { +void GrXferProcessor::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b, + const GrSurfaceOrigin* originIfDstTexture) const { uint32_t key = this->willReadDstColor() ? 0x1 : 0x0; if (key) { - if (const GrTexture* dstTexture = this->getDstTexture()) { + if (originIfDstTexture) { key |= 0x2; - if (kTopLeft_GrSurfaceOrigin == dstTexture->origin()) { + if (kTopLeft_GrSurfaceOrigin == *originIfDstTexture) { key |= 0x4; } } @@ -84,17 +49,6 @@ void GrXferProcessor::getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKey this->onGetGLSLProcessorKey(caps, b); } -GrXferBarrierType GrXferProcessor::xferBarrierType(const GrRenderTarget* rt, - const GrCaps& caps) const { - SkASSERT(rt); - if (static_cast(rt) == this->getDstTexture()) { - // Texture barriers are required when a shader reads and renders to the same texture. - SkASSERT(caps.textureBarrierSupport()); - return kTexture_GrXferBarrierType; - } - return this->onXferBarrier(rt, caps); -} - #ifdef SK_DEBUG static const char* equation_string(GrBlendEquation eq) { switch (eq) { @@ -191,32 +145,38 @@ SkString GrXferProcessor::BlendInfo::dump() const { /////////////////////////////////////////////////////////////////////////////// -GrXferProcessor* GrXPFactory::createXferProcessor(const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture* dstTexture, - const GrCaps& caps) const { -#ifdef SK_DEBUG - if (this->willReadDstColor(caps, optimizations)) { - if (!caps.shaderCaps()->dstReadInShaderSupport()) { - SkASSERT(dstTexture && dstTexture->texture()); - } else { - SkASSERT(!dstTexture || !dstTexture->texture()); - } +GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties( + const GrXPFactory* factory, + const GrProcessorAnalysisColor& color, + const GrProcessorAnalysisCoverage& coverage, + const GrCaps& caps) { + AnalysisProperties result; + if (factory) { + result = factory->analysisProperties(color, coverage, caps); } else { - SkASSERT(!dstTexture || !dstTexture->texture()); + result = GrPorterDuffXPFactory::SrcOverAnalysisProperties(color, coverage, caps); } + SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture)); + if ((result & AnalysisProperties::kReadsDstInShader) && + !caps.shaderCaps()->dstReadInShaderSupport()) { + result |= AnalysisProperties::kRequiresDstTexture; + if (caps.textureBarrierSupport()) { + result |= AnalysisProperties::kRequiresBarrierBetweenOverlappingDraws; + } + } + return result; +} + +sk_sp GrXPFactory::MakeXferProcessor(const GrXPFactory* factory, + const GrProcessorAnalysisColor& color, + GrProcessorAnalysisCoverage coverage, + bool hasMixedSamples, + const GrCaps& caps) { SkASSERT(!hasMixedSamples || caps.shaderCaps()->dualSourceBlendingSupport()); -#endif - return this->onCreateXferProcessor(caps, optimizations, hasMixedSamples, dstTexture); -} - -bool GrXPFactory::willNeedDstTexture(const GrCaps& caps, - const GrPipelineOptimizations& optimizations) const { - return (this->willReadDstColor(caps, optimizations) && - !caps.shaderCaps()->dstReadInShaderSupport()); -} - -bool GrXPFactory::willReadDstColor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations) const { - return optimizations.fOverrides.fUsePLSDstRead || this->onWillReadDstColor(caps, optimizations); + if (factory) { + return factory->makeXferProcessor(color, coverage, hasMixedSamples, caps); + } else { + return GrPorterDuffXPFactory::MakeSrcOverXferProcessor(color, coverage, hasMixedSamples, + caps); + } } diff --git a/gfx/skia/skia/src/gpu/GrXferProcessor.h b/gfx/skia/skia/src/gpu/GrXferProcessor.h new file mode 100644 index 000000000000..3aecf3e68681 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrXferProcessor.h @@ -0,0 +1,304 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrXferProcessor_DEFINED +#define GrXferProcessor_DEFINED + +#include "GrBlend.h" +#include "GrColor.h" +#include "GrNonAtomicRef.h" +#include "GrProcessor.h" +#include "GrProcessorSet.h" +#include "GrTexture.h" +#include "GrTypes.h" + +class GrShaderCaps; +class GrGLSLXferProcessor; + +/** + * Barriers for blending. When a shader reads the dst directly, an Xfer barrier is sometimes + * required after a pixel has been written, before it can be safely read again. + */ +enum GrXferBarrierType { + kNone_GrXferBarrierType = 0, // { +public: + /** + * A texture that contains the dst pixel values and an integer coord offset from device space + * to the space of the texture. Depending on GPU capabilities a DstTexture may be used by a + * GrXferProcessor for blending in the fragment shader. + */ + class DstTexture { + public: + DstTexture() { fOffset.set(0, 0); } + + DstTexture(const DstTexture& other) { + *this = other; + } + + DstTexture(GrTexture* texture, const SkIPoint& offset) + : fTexture(SkSafeRef(texture)), fOffset(texture ? offset : SkIPoint{0, 0}) {} + + DstTexture& operator=(const DstTexture& other) { + fTexture = other.fTexture; + fOffset = other.fOffset; + return *this; + } + + bool operator==(const DstTexture& that) const { + return fTexture == that.fTexture && fOffset == that.fOffset; + } + bool operator!=(const DstTexture& that) const { return !(*this == that); } + + const SkIPoint& offset() const { return fOffset; } + + void setOffset(const SkIPoint& offset) { fOffset = offset; } + void setOffset(int ox, int oy) { fOffset.set(ox, oy); } + + GrTexture* texture() const { return fTexture.get(); } + + void setTexture(sk_sp texture) { + fTexture = std::move(texture); + if (!fTexture) { + fOffset = {0, 0}; + } + } + + private: + sk_sp fTexture; + SkIPoint fOffset; + }; + + /** + * Sets a unique key on the GrProcessorKeyBuilder calls onGetGLSLProcessorKey(...) to get the + * specific subclass's key. + */ + void getGLSLProcessorKey(const GrShaderCaps&, + GrProcessorKeyBuilder*, + const GrSurfaceOrigin* originIfDstTexture) const; + + /** Returns a new instance of the appropriate *GL* implementation class + for the given GrXferProcessor; caller is responsible for deleting + the object. */ + virtual GrGLSLXferProcessor* createGLSLInstance() const = 0; + + /** + * Returns the barrier type, if any, that this XP will require. Note that the possibility + * that a kTexture type barrier is required is handled by the GrPipeline and need not be + * considered by subclass overrides of this function. + */ + virtual GrXferBarrierType xferBarrierType(const GrCaps& caps) const { + return kNone_GrXferBarrierType; + } + + struct BlendInfo { + void reset() { + fEquation = kAdd_GrBlendEquation; + fSrcBlend = kOne_GrBlendCoeff; + fDstBlend = kZero_GrBlendCoeff; + fBlendConstant = 0; + fWriteColor = true; + } + + SkDEBUGCODE(SkString dump() const;) + + GrBlendEquation fEquation; + GrBlendCoeff fSrcBlend; + GrBlendCoeff fDstBlend; + GrColor fBlendConstant; + bool fWriteColor; + }; + + void getBlendInfo(BlendInfo* blendInfo) const; + + bool willReadDstColor() const { return fWillReadDstColor; } + + /** + * If we are performing a dst read, returns whether the base class will use mixed samples to + * antialias the shader's final output. If not doing a dst read, the subclass is responsible + * for antialiasing and this returns false. + */ + bool dstReadUsesMixedSamples() const { return fDstReadUsesMixedSamples; } + + /** + * Returns whether or not this xferProcossor will set a secondary output to be used with dual + * source blending. + */ + bool hasSecondaryOutput() const; + + /** Returns true if this and other processor conservatively draw identically. It can only return + true when the two processor are of the same subclass (i.e. they return the same object from + from getFactory()). + + A return value of true from isEqual() should not be used to test whether the processor would + generate the same shader code. To test for identical code generation use getGLSLProcessorKey + */ + + bool isEqual(const GrXferProcessor& that) const { + if (this->classID() != that.classID()) { + return false; + } + if (this->fWillReadDstColor != that.fWillReadDstColor) { + return false; + } + if (this->fDstReadUsesMixedSamples != that.fDstReadUsesMixedSamples) { + return false; + } + return this->onIsEqual(that); + } + +protected: + GrXferProcessor(); + GrXferProcessor(bool willReadDstColor, bool hasMixedSamples); + +private: + /** + * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this xfer + * processor's GL backend implementation. + */ + virtual void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0; + + /** + * If we are not performing a dst read, returns whether the subclass will set a secondary + * output. When using dst reads, the base class controls the secondary output and this method + * will not be called. + */ + virtual bool onHasSecondaryOutput() const { return false; } + + /** + * If we are not performing a dst read, retrieves the fixed-function blend state required by the + * subclass. When using dst reads, the base class controls the fixed-function blend state and + * this method will not be called. The BlendInfo struct comes initialized to "no blending". + */ + virtual void onGetBlendInfo(BlendInfo*) const {} + + virtual bool onIsEqual(const GrXferProcessor&) const = 0; + + bool fWillReadDstColor; + bool fDstReadUsesMixedSamples; + + typedef GrFragmentProcessor INHERITED; +}; + +/** + * We install a GrXPFactory (XPF) early on in the pipeline before all the final draw information is + * known (e.g. whether there is fractional pixel coverage, will coverage be 1 or 4 channel, is the + * draw opaque, etc.). Once the state of the draw is finalized, we use the XPF along with all the + * draw information to create a GrXferProcessor (XP) which can implement the desired blending for + * the draw. + * + * Before the XP is created, the XPF is able to answer queries about what functionality the XPs it + * creates will have. For example, can it create an XP that supports RGB coverage or will the XP + * blend with the destination color. + * + * GrXPFactories are intended to be static immutable objects. We pass them around as raw pointers + * and expect the pointers to always be valid and for the factories to be reusable and thread safe. + * Equality is tested for using pointer comparison. GrXPFactory destructors must be no-ops. + */ + +// In order to construct GrXPFactory subclass instances as constexpr the subclass, and therefore +// GrXPFactory, must be a literal type. One requirement is having a trivial destructor. This is ok +// since these objects have no need for destructors. However, GCC and clang throw a warning when a +// class has virtual functions and a non-virtual destructor. We suppress that warning here and +// for the subclasses. +#if defined(__GNUC__) || defined(__clang) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif +class GrXPFactory { +public: + typedef GrXferProcessor::DstTexture DstTexture; + + enum class AnalysisProperties : unsigned { + kNone = 0x0, + /** + * The fragment shader will require the destination color. + */ + kReadsDstInShader = 0x1, + /** + * The op may apply coverage as alpha and still blend correctly. + */ + kCompatibleWithAlphaAsCoverage = 0x2, + /** + * The color input to the GrXferProcessor will be ignored. + */ + kIgnoresInputColor = 0x4, + /** + * If set overlapping stencil and cover operations can be replaced by a combined stencil + * followed by a combined cover. + */ + kCanCombineOverlappedStencilAndCover = 0x8, + /** + * The destination color will be provided to the fragment processor using a texture. This is + * additional information about the implementation of kReadsDstInShader. + */ + kRequiresDstTexture = 0x10, + /** + * If set overlapping draws may not be combined because a barrier must be inserted between + * them. + */ + kRequiresBarrierBetweenOverlappingDraws = 0x20, + }; + GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(AnalysisProperties); + + static sk_sp MakeXferProcessor(const GrXPFactory*, + const GrProcessorAnalysisColor&, + GrProcessorAnalysisCoverage, + bool hasMixedSamples, + const GrCaps& caps); + + static AnalysisProperties GetAnalysisProperties(const GrXPFactory*, + const GrProcessorAnalysisColor&, + const GrProcessorAnalysisCoverage&, + const GrCaps&); + +protected: + constexpr GrXPFactory() {} + +private: + virtual sk_sp makeXferProcessor(const GrProcessorAnalysisColor&, + GrProcessorAnalysisCoverage, + bool hasMixedSamples, + const GrCaps&) const = 0; + + /** + * Subclass analysis implementation. This should not return kNeedsDstInTexture as that will be + * inferred by the base class based on kReadsDstInShader and the caps. + */ + virtual AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&, + const GrProcessorAnalysisCoverage&, + const GrCaps&) const = 0; +}; +#if defined(__GNUC__) || defined(__clang) +#pragma GCC diagnostic pop +#endif + +GR_MAKE_BITFIELD_CLASS_OPS(GrXPFactory::AnalysisProperties); + +#endif diff --git a/gfx/skia/skia/src/gpu/GrYUVProvider.cpp b/gfx/skia/skia/src/gpu/GrYUVProvider.cpp index db58e0afed2f..cfd27d0d3939 100644 --- a/gfx/skia/skia/src/gpu/GrYUVProvider.cpp +++ b/gfx/skia/skia/src/gpu/GrYUVProvider.cpp @@ -5,16 +5,19 @@ * found in the LICENSE file. */ -#include "GrContext.h" -#include "GrDrawContext.h" #include "GrYUVProvider.h" -#include "effects/GrGammaEffect.h" -#include "effects/GrYUVEffect.h" - +#include "GrClip.h" +#include "GrContext.h" +#include "GrContextPriv.h" +#include "GrRenderTargetContext.h" +#include "GrTextureProxy.h" +#include "SkAutoMalloc.h" #include "SkCachedData.h" #include "SkRefCnt.h" #include "SkResourceCache.h" #include "SkYUVPlanesCache.h" +#include "effects/GrSRGBEffect.h" +#include "effects/GrYUVEffect.h" namespace { /** @@ -28,8 +31,8 @@ public: private: // we only use one or the other of these - SkAutoTUnref fCachedData; - SkAutoMalloc fStorage; + sk_sp fCachedData; + SkAutoMalloc fStorage; }; } @@ -75,15 +78,15 @@ bool YUVScoper::init(GrYUVProvider* provider, SkYUVPlanesCache::Info* yuvInfo, v if (useCache) { // Decoding is done, cache the resulting YUV planes - SkYUVPlanesCache::Add(provider->onGetID(), fCachedData, yuvInfo); + SkYUVPlanesCache::Add(provider->onGetID(), fCachedData.get(), yuvInfo); } } return true; } -sk_sp GrYUVProvider::refAsTexture(GrContext* ctx, - const GrSurfaceDesc& desc, - bool useCache) { +sk_sp GrYUVProvider::refAsTextureProxy(GrContext* ctx, + const GrSurfaceDesc& desc, + bool useCache) { SkYUVPlanesCache::Info yuvInfo; void* planes[3]; YUVScoper scoper; @@ -92,39 +95,47 @@ sk_sp GrYUVProvider::refAsTexture(GrContext* ctx, } GrSurfaceDesc yuvDesc; + yuvDesc.fOrigin = kTopLeft_GrSurfaceOrigin; yuvDesc.fConfig = kAlpha_8_GrPixelConfig; - SkAutoTUnref yuvTextures[3]; + sk_sp yuvTextureContexts[3]; for (int i = 0; i < 3; i++) { yuvDesc.fWidth = yuvInfo.fSizeInfo.fSizes[i].fWidth; yuvDesc.fHeight = yuvInfo.fSizeInfo.fSizes[i].fHeight; // TODO: why do we need this check? - bool needsExactTexture = + SkBackingFit fit = (yuvDesc.fWidth != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) || - (yuvDesc.fHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); - if (needsExactTexture) { - yuvTextures[i].reset(ctx->textureProvider()->createTexture(yuvDesc, SkBudgeted::kYes)); - } else { - yuvTextures[i].reset(ctx->textureProvider()->createApproxTexture(yuvDesc)); + (yuvDesc.fHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight) + ? SkBackingFit::kExact : SkBackingFit::kApprox; + + yuvTextureContexts[i] = ctx->contextPriv().makeDeferredSurfaceContext(yuvDesc, fit, + SkBudgeted::kYes); + if (!yuvTextureContexts[i]) { + return nullptr; + } + + const SkImageInfo ii = SkImageInfo::MakeA8(yuvDesc.fWidth, yuvDesc.fHeight); + if (!yuvTextureContexts[i]->writePixels(ii, planes[i], + yuvInfo.fSizeInfo.fWidthBytes[i], 0, 0)) { + return nullptr; } - if (!yuvTextures[i] || - !yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight, yuvDesc.fConfig, - planes[i], yuvInfo.fSizeInfo.fWidthBytes[i])) { - return nullptr; - } } // We never want to perform color-space conversion during the decode - sk_sp drawContext(ctx->makeDrawContext(SkBackingFit::kExact, - desc.fWidth, desc.fHeight, - desc.fConfig, nullptr, - desc.fSampleCnt)); - if (!drawContext) { + sk_sp renderTargetContext(ctx->makeRenderTargetContext( + SkBackingFit::kExact, + desc.fWidth, desc.fHeight, + desc.fConfig, nullptr, + desc.fSampleCnt)); + if (!renderTargetContext) { return nullptr; } GrPaint paint; sk_sp yuvToRgbProcessor( - GrYUVEffect::MakeYUVToRGB(yuvTextures[0], yuvTextures[1], yuvTextures[2], + GrYUVEffect::MakeYUVToRGB(ctx->resourceProvider(), + yuvTextureContexts[0]->asTextureProxyRef(), + yuvTextureContexts[1]->asTextureProxyRef(), + yuvTextureContexts[2]->asTextureProxyRef(), yuvInfo.fSizeInfo.fSizes, yuvInfo.fColorSpace, false)); paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor)); @@ -138,15 +149,15 @@ sk_sp GrYUVProvider::refAsTexture(GrContext* ctx, if (ctx->caps()->srgbWriteControl()) { paint.setDisableOutputConversionToSRGB(true); } else { - paint.addColorFragmentProcessor(GrGammaEffect::Make(2.2f)); + paint.addColorFragmentProcessor(GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear)); } } paint.setPorterDuffXPFactory(SkBlendMode::kSrc); const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth, - yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); + yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); - drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), r); + renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r); - return drawContext->asTexture(); + return renderTargetContext->asTextureProxyRef(); } diff --git a/gfx/skia/skia/src/gpu/GrYUVProvider.h b/gfx/skia/skia/src/gpu/GrYUVProvider.h index c32af15df005..af5a4a47c9ad 100644 --- a/gfx/skia/skia/src/gpu/GrYUVProvider.h +++ b/gfx/skia/skia/src/gpu/GrYUVProvider.h @@ -14,6 +14,7 @@ class GrContext; class GrTexture; +class GrTextureProxy; /** * There are at least 2 different ways to extract/retrieve YUV planar data... @@ -28,14 +29,14 @@ public: virtual ~GrYUVProvider() {} /** - * On success, this returns a texture that has converted the YUV data from the provider + * On success, this returns a texture proxy that has converted the YUV data from the provider * into a form that is supported by the GPU (typically transformed into RGB). If useCache * is true, then the texture will automatically have a key added, so it can be retrieved * from the cache (assuming it is requested by a provider w/ the same genID). * * On failure (e.g. the provider had no data), this returns NULL. */ - sk_sp refAsTexture(GrContext*, const GrSurfaceDesc&, bool useCache); + sk_sp refAsTextureProxy(GrContext*, const GrSurfaceDesc&, bool useCache); virtual uint32_t onGetID() = 0; diff --git a/gfx/skia/skia/src/gpu/SkGpuDevice.cpp b/gfx/skia/skia/src/gpu/SkGpuDevice.cpp index 248a240f0143..11ed63725066 100644 --- a/gfx/skia/skia/src/gpu/SkGpuDevice.cpp +++ b/gfx/skia/skia/src/gpu/SkGpuDevice.cpp @@ -7,31 +7,34 @@ #include "SkGpuDevice.h" +#include "GrBitmapTextureMaker.h" #include "GrBlurUtils.h" #include "GrContext.h" -#include "GrDrawContextPriv.h" #include "GrGpu.h" -#include "GrImageIDTextureAdjuster.h" +#include "GrImageTextureMaker.h" +#include "GrRenderTargetContextPriv.h" #include "GrStyle.h" +#include "GrSurfaceProxyPriv.h" +#include "GrTextureAdjuster.h" +#include "GrTextureProxy.h" #include "GrTracing.h" - #include "SkCanvasPriv.h" #include "SkDraw.h" -#include "SkErrorInternals.h" #include "SkGlyphCache.h" #include "SkGr.h" -#include "SkGrPriv.h" -#include "SkImage_Base.h" #include "SkImageCacherator.h" #include "SkImageFilter.h" #include "SkImageFilterCache.h" +#include "SkImageInfoPriv.h" +#include "SkImage_Base.h" #include "SkLatticeIter.h" #include "SkMaskFilter.h" #include "SkPathEffect.h" #include "SkPicture.h" #include "SkPictureData.h" -#include "SkRasterClip.h" #include "SkRRect.h" +#include "SkRasterClip.h" +#include "SkReadPixelsRec.h" #include "SkRecord.h" #include "SkSpecialImage.h" #include "SkStroke.h" @@ -40,10 +43,9 @@ #include "SkTLazy.h" #include "SkUtils.h" #include "SkVertState.h" -#include "SkXfermode.h" -#include "batches/GrRectBatchFactory.h" +#include "SkVertices.h" +#include "SkWritePixelsRec.h" #include "effects/GrBicubicEffect.h" -#include "effects/GrDashingEffect.h" #include "effects/GrSimpleTextureEffect.h" #include "effects/GrTextureDomain.h" #include "text/GrTextUtils.h" @@ -55,13 +57,12 @@ #if 0 extern bool (*gShouldDrawProc)(); - #define CHECK_SHOULD_DRAW(draw) \ + #define CHECK_SHOULD_DRAW() \ do { \ if (gShouldDrawProc && !gShouldDrawProc()) return; \ - this->prepareDraw(draw); \ } while (0) #else - #define CHECK_SHOULD_DRAW(draw) this->prepareDraw(draw) +#define CHECK_SHOULD_DRAW() #endif /////////////////////////////////////////////////////////////////////////////// @@ -88,17 +89,19 @@ bool SkGpuDevice::CheckAlphaTypeAndGetFlags( return true; } -sk_sp SkGpuDevice::Make(sk_sp drawContext, +sk_sp SkGpuDevice::Make(GrContext* context, + sk_sp renderTargetContext, int width, int height, InitContents init) { - if (!drawContext || drawContext->wasAbandoned()) { + if (!renderTargetContext || renderTargetContext->wasAbandoned()) { return nullptr; } unsigned flags; if (!CheckAlphaTypeAndGetFlags(nullptr, init, &flags)) { return nullptr; } - return sk_sp(new SkGpuDevice(std::move(drawContext), width, height, flags)); + return sk_sp(new SkGpuDevice(context, std::move(renderTargetContext), + width, height, flags)); } sk_sp SkGpuDevice::Make(GrContext* context, SkBudgeted budgeted, @@ -110,31 +113,33 @@ sk_sp SkGpuDevice::Make(GrContext* context, SkBudgeted budgeted, return nullptr; } - sk_sp drawContext(MakeDrawContext(context, budgeted, info, - sampleCount, origin, props)); - if (!drawContext) { + sk_sp renderTargetContext(MakeRenderTargetContext(context, budgeted, + info, sampleCount, + origin, props)); + if (!renderTargetContext) { return nullptr; } - return sk_sp(new SkGpuDevice(std::move(drawContext), + return sk_sp(new SkGpuDevice(context, std::move(renderTargetContext), info.width(), info.height(), flags)); } -static SkImageInfo make_info(GrDrawContext* context, int w, int h, bool opaque) { +static SkImageInfo make_info(GrRenderTargetContext* context, int w, int h, bool opaque) { SkColorType colorType; if (!GrPixelConfigToColorType(context->config(), &colorType)) { colorType = kUnknown_SkColorType; } return SkImageInfo::Make(w, h, colorType, opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType, - sk_ref_sp(context->getColorSpace())); + context->refColorSpace()); } -SkGpuDevice::SkGpuDevice(sk_sp drawContext, int width, int height, unsigned flags) - : INHERITED(make_info(drawContext.get(), width, height, SkToBool(flags & kIsOpaque_Flag)), - drawContext->surfaceProps()) - , fContext(SkRef(drawContext->accessRenderTarget()->getContext())) - , fDrawContext(std::move(drawContext)) +SkGpuDevice::SkGpuDevice(GrContext* context, sk_sp renderTargetContext, + int width, int height, unsigned flags) + : INHERITED(make_info(renderTargetContext.get(), width, height, + SkToBool(flags & kIsOpaque_Flag)), renderTargetContext->surfaceProps()) + , fContext(SkRef(context)) + , fRenderTargetContext(std::move(renderTargetContext)) { fSize.set(width, height); fOpaque = SkToBool(flags & kIsOpaque_Flag); @@ -144,12 +149,13 @@ SkGpuDevice::SkGpuDevice(sk_sp drawContext, int width, int height } } -sk_sp SkGpuDevice::MakeDrawContext(GrContext* context, - SkBudgeted budgeted, - const SkImageInfo& origInfo, - int sampleCount, - GrSurfaceOrigin origin, - const SkSurfaceProps* surfaceProps) { +sk_sp SkGpuDevice::MakeRenderTargetContext( + GrContext* context, + SkBudgeted budgeted, + const SkImageInfo& origInfo, + int sampleCount, + GrSurfaceOrigin origin, + const SkSurfaceProps* surfaceProps) { if (kUnknown_SkColorType == origInfo.colorType() || origInfo.width() < 0 || origInfo.height() < 0) { return nullptr; @@ -159,37 +165,27 @@ sk_sp SkGpuDevice::MakeDrawContext(GrContext* context, return nullptr; } - SkColorType ct = origInfo.colorType(); - SkAlphaType at = origInfo.alphaType(); - SkColorSpace* cs = origInfo.colorSpace(); - if (kRGB_565_SkColorType == ct || kGray_8_SkColorType == ct) { - at = kOpaque_SkAlphaType; // force this setting - } - if (kOpaque_SkAlphaType != at) { - at = kPremul_SkAlphaType; // force this setting - } - - GrPixelConfig config = SkImageInfo2GrPixelConfig(ct, at, cs, *context->caps()); - - return context->makeDrawContext(SkBackingFit::kExact, // Why exact? + GrPixelConfig config = SkImageInfo2GrPixelConfig(origInfo, *context->caps()); + // This method is used to create SkGpuDevice's for SkSurface_Gpus. In this case + // they need to be exact. + return context->makeRenderTargetContext(SkBackingFit::kExact, origInfo.width(), origInfo.height(), - config, sk_ref_sp(cs), sampleCount, + config, origInfo.refColorSpace(), sampleCount, origin, surfaceProps, budgeted); } -sk_sp SkGpuDevice::filterTexture(const SkDraw& draw, - SkSpecialImage* srcImg, +sk_sp SkGpuDevice::filterTexture(SkSpecialImage* srcImg, int left, int top, SkIPoint* offset, const SkImageFilter* filter) { SkASSERT(srcImg->isTextureBacked()); SkASSERT(filter); - SkMatrix matrix = *draw.fMatrix; + SkMatrix matrix = this->ctm(); matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top)); - const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-left, -top); - SkAutoTUnref cache(this->getImageFilterCache()); - SkImageFilter::OutputProperties outputProperties(fDrawContext->getColorSpace()); + const SkIRect clipBounds = this->devClipBounds().makeOffset(-left, -top); + sk_sp cache(this->getImageFilterCache()); + SkImageFilter::OutputProperties outputProperties(fRenderTargetContext->getColorSpace()); SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties); return filter->filterImage(srcImg, ctx, offset); @@ -201,14 +197,32 @@ bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size int x, int y) { ASSERT_SINGLE_OWNER - return fDrawContext->readPixels(dstInfo, dstPixels, dstRowBytes, x, y); + if (!SkImageInfoValidConversion(dstInfo, this->imageInfo())) { + return false; + } + + SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, x, y); + if (!rec.trim(this->width(), this->height())) { + return false; + } + + return fRenderTargetContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY); } bool SkGpuDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes, int x, int y) { ASSERT_SINGLE_OWNER - return fDrawContext->writePixels(srcInfo, srcPixels, srcRowBytes, x, y); + if (!SkImageInfoValidConversion(this->imageInfo(), srcInfo)) { + return false; + } + + SkWritePixelsRec rec(srcInfo, srcPixels, srcRowBytes, x, y); + if (!rec.trim(this->width(), this->height())) { + return false; + } + + return fRenderTargetContext->writePixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY); } bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) { @@ -216,67 +230,62 @@ bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) { return false; } -// call this every draw call, to ensure that the context reflects our state, -// and not the state from some other canvas/device -void SkGpuDevice::prepareDraw(const SkDraw& draw) { +GrRenderTargetContext* SkGpuDevice::accessRenderTargetContext() { ASSERT_SINGLE_OWNER - - fClip.reset(draw.fClipStack, &this->getOrigin()); -} - -GrDrawContext* SkGpuDevice::accessDrawContext() { - ASSERT_SINGLE_OWNER - return fDrawContext.get(); + return fRenderTargetContext.get(); } void SkGpuDevice::clearAll() { ASSERT_SINGLE_OWNER - GrColor color = 0; - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext.get()); + SkIRect rect = SkIRect::MakeWH(this->width(), this->height()); - fDrawContext->clear(&rect, color, true); + fRenderTargetContext->clear(&rect, 0x0, true); } -void SkGpuDevice::replaceDrawContext(bool shouldRetainContent) { +void SkGpuDevice::replaceRenderTargetContext(bool shouldRetainContent) { ASSERT_SINGLE_OWNER - SkBudgeted budgeted = fDrawContext->drawContextPriv().isBudgeted(); + SkBudgeted budgeted = fRenderTargetContext->priv().isBudgeted(); - sk_sp newDC(MakeDrawContext(this->context(), - budgeted, - this->imageInfo(), - fDrawContext->numColorSamples(), - fDrawContext->origin(), - &this->surfaceProps())); - if (!newDC) { + // This entry point is used by SkSurface_Gpu::onCopyOnWrite so it must create a + // kExact-backed render target context. + sk_sp newRTC(MakeRenderTargetContext( + this->context(), + budgeted, + this->imageInfo(), + fRenderTargetContext->numColorSamples(), + fRenderTargetContext->origin(), + &this->surfaceProps())); + if (!newRTC) { return; } + SkASSERT(newRTC->asSurfaceProxy()->priv().isExact()); if (shouldRetainContent) { - if (fDrawContext->wasAbandoned()) { + if (fRenderTargetContext->wasAbandoned()) { return; } - newDC->copySurface(fDrawContext->asTexture().get(), - SkIRect::MakeWH(this->width(), this->height()), - SkIPoint::Make(0, 0)); + newRTC->copy(fRenderTargetContext->asSurfaceProxy()); } - fDrawContext = newDC; + fRenderTargetContext = newRTC; } /////////////////////////////////////////////////////////////////////////////// -void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { +void SkGpuDevice::drawPaint(const SkPaint& paint) { ASSERT_SINGLE_OWNER - CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext); + CHECK_SHOULD_DRAW(); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext.get()); GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, &grPaint)) { + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(), + &grPaint)) { return; } - fDrawContext->drawPaint(fClip, grPaint, *draw.fMatrix); + fRenderTargetContext->drawPaint(this->clip(), std::move(grPaint), this->ctm()); } // must be in SkCanvas::PointMode order @@ -286,33 +295,38 @@ static const GrPrimitiveType gPointMode2PrimitiveType[] = { kLineStrip_GrPrimitiveType }; +static inline bool is_int(float x) { return x == (float) sk_float_round2int(x); } + // suppress antialiasing on axis-aligned integer-coordinate lines -static bool needs_antialiasing(SkCanvas::PointMode mode, size_t count, const SkPoint pts[]) { +static bool needs_antialiasing(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], + const SkMatrix& matrix) { if (mode == SkCanvas::PointMode::kPoints_PointMode) { return false; } if (count == 2) { - // We do not antialias as long as the primary axis of the line is integer-aligned, even if - // the other coordinates are not. This does mean the two end pixels of the line will be - // sharp even when they shouldn't be, but turning antialiasing on (as things stand - // currently) means that the line will turn into a two-pixel-wide blur. While obviously a - // more complete fix is possible down the road, for the time being we accept the error on - // the two end pixels as being the lesser of two evils. + // We do not antialias horizontal or vertical lines along pixel centers, even when the ends + // of the line do not fully cover the first and last pixel of the line, which is slightly + // wrong. + if (!matrix.isScaleTranslate()) { + return true; + } if (pts[0].fX == pts[1].fX) { - return ((int) pts[0].fX) != pts[0].fX; + SkScalar x = matrix.getScaleX() * pts[0].fX + matrix.getTranslateX(); + return !is_int(x + 0.5f); } if (pts[0].fY == pts[1].fY) { - return ((int) pts[0].fY) != pts[0].fY; + SkScalar y = matrix.getScaleY() * pts[0].fY + matrix.getTranslateY(); + return !is_int(y + 0.5f); } } return true; } -void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, +void SkGpuDevice::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { ASSERT_SINGLE_OWNER - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext); - CHECK_SHOULD_DRAW(draw); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext.get()); + CHECK_SHOULD_DRAW(); SkScalar width = paint.getStrokeWidth(); if (width < 0) { @@ -322,7 +336,7 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) { GrStyle style(paint, SkPaint::kStroke_Style); GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(), &grPaint)) { return; } @@ -330,25 +344,32 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, path.setIsVolatile(true); path.moveTo(pts[0]); path.lineTo(pts[1]); - fDrawContext->drawPath(fClip, grPaint, *draw.fMatrix, path, style); + fRenderTargetContext->drawPath(this->clip(), std::move(grPaint), + GrBoolToAA(paint.isAntiAlias()), this->ctm(), path, style); return; } SkScalar scales[2]; - bool isHairline = (0 == width) || (1 == width && draw.fMatrix->getMinMaxScales(scales) && + bool isHairline = (0 == width) || (1 == width && this->ctm().getMinMaxScales(scales) && SkScalarNearlyEqual(scales[0], 1.f) && SkScalarNearlyEqual(scales[1], 1.f)); // we only handle non-antialiased hairlines and paints without path effects or mask filters, // else we let the SkDraw call our drawPath() if (!isHairline || paint.getPathEffect() || paint.getMaskFilter() || - (paint.isAntiAlias() && needs_antialiasing(mode, count, pts))) { - draw.drawPoints(mode, count, pts, paint, true); + (paint.isAntiAlias() && needs_antialiasing(mode, count, pts, this->ctm()))) + { + SkRasterClip rc(this->devClipBounds()); + SkDraw draw; + draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0); + draw.fMatrix = &this->ctm(); + draw.fRC = &rc; + draw.drawPoints(mode, count, pts, paint, this); return; } GrPrimitiveType primitiveType = gPointMode2PrimitiveType[mode]; - const SkMatrix* viewMatrix = draw.fMatrix; + const SkMatrix* viewMatrix = &this->ctm(); #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK // This offsetting in device space matches the expectations of the Android framework for non-AA // points and lines. @@ -362,28 +383,29 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, #endif GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *viewMatrix, &grPaint)) { + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, *viewMatrix, + &grPaint)) { return; } - fDrawContext->drawVertices(fClip, - grPaint, - *viewMatrix, - primitiveType, - SkToS32(count), - (SkPoint*)pts, - nullptr, - nullptr, - nullptr, - 0); + fRenderTargetContext->drawVertices(this->clip(), + std::move(grPaint), + *viewMatrix, + primitiveType, + SkToS32(count), + (SkPoint*)pts, + nullptr, + nullptr, + nullptr, + 0); } /////////////////////////////////////////////////////////////////////////////// -void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint& paint) { +void SkGpuDevice::drawRect(const SkRect& rect, const SkPaint& paint) { ASSERT_SINGLE_OWNER - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext); - CHECK_SHOULD_DRAW(draw); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext.get()); + CHECK_SHOULD_DRAW(); // A couple reasons we might need to call drawPath. @@ -391,61 +413,60 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint SkPath path; path.setIsVolatile(true); path.addRect(rect); - GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext.get(), - fClip, path, paint, - *draw.fMatrix, nullptr, - draw.fRC->getBounds(), true); + GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(), + this->clip(), path, paint, this->ctm(), nullptr, + this->devClipBounds(), true); return; } GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, &grPaint)) { + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(), + &grPaint)) { return; } GrStyle style(paint); - fDrawContext->drawRect(fClip, grPaint, *draw.fMatrix, rect, &style); + fRenderTargetContext->drawRect(this->clip(), std::move(grPaint), + GrBoolToAA(paint.isAntiAlias()), this->ctm(), rect, &style); } /////////////////////////////////////////////////////////////////////////////// -void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, - const SkPaint& paint) { +void SkGpuDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) { ASSERT_SINGLE_OWNER - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext); - CHECK_SHOULD_DRAW(draw); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext.get()); + CHECK_SHOULD_DRAW(); GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, &grPaint)) { + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(), + &grPaint)) { return; } + SkMaskFilter* mf = paint.getMaskFilter(); + if (mf && mf->asFragmentProcessor(nullptr, nullptr, this->ctm())) { + mf = nullptr; // already handled in SkPaintToGrPaint + } + GrStyle style(paint); - if (paint.getMaskFilter()) { + if (mf) { // try to hit the fast path for drawing filtered round rects SkRRect devRRect; - if (rrect.transform(*draw.fMatrix, &devRRect)) { + if (rrect.transform(this->ctm(), &devRRect)) { if (devRRect.allCornersCircular()) { SkRect maskRect; - if (paint.getMaskFilter()->canFilterMaskGPU(devRRect, - draw.fRC->getBounds(), - *draw.fMatrix, - &maskRect)) { + if (mf->canFilterMaskGPU(devRRect, this->devClipBounds(), + this->ctm(), &maskRect)) { SkIRect finalIRect; maskRect.roundOut(&finalIRect); - if (draw.fRC->quickReject(finalIRect)) { - // clipped out - return; - } - if (paint.getMaskFilter()->directFilterRRectMaskGPU(fContext, - fDrawContext.get(), - &grPaint, - fClip, - *draw.fMatrix, - style.strokeRec(), - rrect, - devRRect)) { + + // we used to test finalIRect for quickReject, but that seems unlikely + // given that the original shape was not rejected... + + if (mf->directFilterRRectMaskGPU(this->context(), fRenderTargetContext.get(), + std::move(grPaint), this->clip(), this->ctm(), + style.strokeRec(), rrect, devRRect)) { return; } } @@ -454,50 +475,52 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, } } - if (paint.getMaskFilter() || style.pathEffect()) { + if (mf || style.pathEffect()) { // The only mask filter the native rrect drawing code could've handle was taken // care of above. // A path effect will presumably transform this rrect into something else. SkPath path; path.setIsVolatile(true); path.addRRect(rrect); - GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext.get(), - fClip, path, paint, - *draw.fMatrix, nullptr, - draw.fRC->getBounds(), true); + GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(), + this->clip(), path, paint, this->ctm(), nullptr, + this->devClipBounds(), true); return; } SkASSERT(!style.pathEffect()); - fDrawContext->drawRRect(fClip, grPaint, *draw.fMatrix, rrect, style); + fRenderTargetContext->drawRRect(this->clip(), std::move(grPaint), + GrBoolToAA(paint.isAntiAlias()), this->ctm(), rrect, style); } -void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, +void SkGpuDevice::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { ASSERT_SINGLE_OWNER - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext); - CHECK_SHOULD_DRAW(draw); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext.get()); + CHECK_SHOULD_DRAW(); if (outer.isEmpty()) { return; } if (inner.isEmpty()) { - return this->drawRRect(draw, outer, paint); + return this->drawRRect(outer, paint); } SkStrokeRec stroke(paint); if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) { GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(), &grPaint)) { return; } - fDrawContext->drawDRRect(fClip, grPaint, *draw.fMatrix, outer, inner); + fRenderTargetContext->drawDRRect(this->clip(), std::move(grPaint), + GrBoolToAA(paint.isAntiAlias()), this->ctm(), outer, + inner); return; } @@ -507,89 +530,95 @@ void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, path.addRRect(inner); path.setFillType(SkPath::kEvenOdd_FillType); - GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext.get(), - fClip, path, paint, - *draw.fMatrix, nullptr, - draw.fRC->getBounds(), true); + GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(), + path, paint, this->ctm(), nullptr, this->devClipBounds(), + true); } ///////////////////////////////////////////////////////////////////////////// -void SkGpuDevice::drawRegion(const SkDraw& draw, const SkRegion& region, const SkPaint& paint) { +void SkGpuDevice::drawRegion(const SkRegion& region, const SkPaint& paint) { if (paint.getMaskFilter()) { SkPath path; region.getBoundaryPath(&path); - return this->drawPath(draw, path, paint, nullptr, false); + return this->drawPath(path, paint, nullptr, false); } GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, &grPaint)) { + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(), + &grPaint)) { return; } - fDrawContext->drawRegion(fClip, grPaint, *draw.fMatrix, region, GrStyle(paint)); + fRenderTargetContext->drawRegion(this->clip(), std::move(grPaint), + GrBoolToAA(paint.isAntiAlias()), this->ctm(), region, + GrStyle(paint)); } -void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { +void SkGpuDevice::drawOval(const SkRect& oval, const SkPaint& paint) { ASSERT_SINGLE_OWNER - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext); - CHECK_SHOULD_DRAW(draw); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext.get()); + CHECK_SHOULD_DRAW(); // Presumably the path effect warps this to something other than an oval if (paint.getPathEffect()) { SkPath path; path.setIsVolatile(true); path.addOval(oval); - this->drawPath(draw, path, paint, nullptr, true); + this->drawPath(path, paint, nullptr, true); return; } if (paint.getMaskFilter()) { // The RRect path can handle special case blurring SkRRect rr = SkRRect::MakeOval(oval); - return this->drawRRect(draw, rr, paint); + return this->drawRRect(rr, paint); } GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, &grPaint)) { + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(), + &grPaint)) { return; } - fDrawContext->drawOval(fClip, grPaint, *draw.fMatrix, oval, GrStyle(paint)); + fRenderTargetContext->drawOval(this->clip(), std::move(grPaint), + GrBoolToAA(paint.isAntiAlias()), this->ctm(), oval, + GrStyle(paint)); } -void SkGpuDevice::drawArc(const SkDraw& draw, const SkRect& oval, SkScalar startAngle, +void SkGpuDevice::drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint& paint) { ASSERT_SINGLE_OWNER - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawArc", fContext); - CHECK_SHOULD_DRAW(draw); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawArc", fContext.get()); + CHECK_SHOULD_DRAW(); if (paint.getMaskFilter()) { - this->INHERITED::drawArc(draw, oval, startAngle, sweepAngle, useCenter, paint); + this->INHERITED::drawArc(oval, startAngle, sweepAngle, useCenter, paint); return; } GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, &grPaint)) { + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(), + &grPaint)) { return; } - fDrawContext->drawArc(fClip, grPaint, *draw.fMatrix, oval, startAngle, sweepAngle, useCenter, - GrStyle(paint)); + fRenderTargetContext->drawArc(this->clip(), std::move(grPaint), GrBoolToAA(paint.isAntiAlias()), + this->ctm(), oval, startAngle, sweepAngle, useCenter, + GrStyle(paint)); } #include "SkMaskFilter.h" /////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::drawStrokedLine(const SkPoint points[2], - const SkDraw& draw, const SkPaint& origPaint) { ASSERT_SINGLE_OWNER - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawStrokedLine", fContext); - CHECK_SHOULD_DRAW(draw); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawStrokedLine", fContext.get()); + CHECK_SHOULD_DRAW(); - // Adding support for round capping would require a GrDrawContext::fillRRectWithLocalMatrix - // entry point + // Adding support for round capping would require a + // GrRenderTargetContext::fillRRectWithLocalMatrix entry point SkASSERT(SkPaint::kRound_Cap != origPaint.getStrokeCap()); SkASSERT(SkPaint::kStroke_Style == origPaint.getStyle()); SkASSERT(!origPaint.getPathEffect()); @@ -624,17 +653,18 @@ void SkGpuDevice::drawStrokedLine(const SkPoint points[2], SkMatrix local = m; - m.postConcat(*draw.fMatrix); + m.postConcat(this->ctm()); GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), newPaint, m, &grPaint)) { + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), newPaint, m, &grPaint)) { return; } - fDrawContext->fillRectWithLocalMatrix(fClip, grPaint, m, rect, local); + fRenderTargetContext->fillRectWithLocalMatrix( + this->clip(), std::move(grPaint), GrBoolToAA(newPaint.isAntiAlias()), m, rect, local); } -void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, +void SkGpuDevice::drawPath(const SkPath& origSrcPath, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) { ASSERT_SINGLE_OWNER @@ -642,40 +672,39 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, SkPoint points[2]; if (SkPaint::kStroke_Style == paint.getStyle() && paint.getStrokeWidth() > 0 && !paint.getMaskFilter() && SkPaint::kRound_Cap != paint.getStrokeCap() && - draw.fMatrix->preservesRightAngles() && origSrcPath.isLine(points)) { + this->ctm().preservesRightAngles() && origSrcPath.isLine(points)) { // Path-based stroking looks better for thin rects - SkScalar strokeWidth = draw.fMatrix->getMaxScale() * paint.getStrokeWidth(); + SkScalar strokeWidth = this->ctm().getMaxScale() * paint.getStrokeWidth(); if (strokeWidth >= 1.0f) { - // Round capping support is currently disabled b.c. it would require - // a RRect batch that takes a localMatrix. - this->drawStrokedLine(points, draw, paint); + // Round capping support is currently disabled b.c. it would require a RRect + // GrDrawOp that takes a localMatrix. + this->drawStrokedLine(points, paint); return; } } bool isClosed; SkRect rect; if (origSrcPath.isRect(&rect, &isClosed) && isClosed) { - this->drawRect(draw, rect, paint); + this->drawRect(rect, paint); return; } if (origSrcPath.isOval(&rect)) { - this->drawOval(draw, rect, paint); + this->drawOval(rect, paint); return; } SkRRect rrect; if (origSrcPath.isRRect(&rrect)) { - this->drawRRect(draw, rrect, paint); + this->drawRRect(rrect, paint); return; } } - CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext); + CHECK_SHOULD_DRAW(); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext.get()); - GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext.get(), - fClip, origSrcPath, paint, - *draw.fMatrix, prePathMatrix, - draw.fRC->getBounds(), pathIsMutable); + GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(), + origSrcPath, paint, this->ctm(), prePathMatrix, + this->devClipBounds(), pathIsMutable); } static const int kBmpSmallTileSize = 1 << 10; @@ -737,7 +766,7 @@ static void determine_clipped_src_rect(int width, int height, bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect, const SkMatrix& viewMatrix, const SkMatrix& srcToDstRect, - const GrTextureParams& params, + const GrSamplerParams& params, const SkRect* srcRectPtr, int maxTileSize, int* tileSize, @@ -745,8 +774,9 @@ bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect, ASSERT_SINGLE_OWNER // if it's larger than the max tile size, then we have no choice but tiling. if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) { - determine_clipped_src_rect(fDrawContext->width(), fDrawContext->height(), fClip, viewMatrix, - srcToDstRect, imageRect.size(), srcRectPtr, clippedSubset); + determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(), + this->clip(), viewMatrix, srcToDstRect, imageRect.size(), + srcRectPtr, clippedSubset); *tileSize = determine_tile_size(*clippedSubset, maxTileSize); return true; } @@ -773,13 +803,15 @@ bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect, // Figure out how much of the src we will need based on the src rect and clipping. Reject if // tiling memory savings would be < 50%. - determine_clipped_src_rect(fDrawContext->width(), fDrawContext->height(), fClip, viewMatrix, - srcToDstRect, imageRect.size(), srcRectPtr, clippedSubset); + determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(), + this->clip(), viewMatrix, srcToDstRect, imageRect.size(), srcRectPtr, + clippedSubset); *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile. size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) * - kBmpSmallTileSize * kBmpSmallTileSize; + kBmpSmallTileSize * kBmpSmallTileSize * + sizeof(SkPMColor); // assume 32bit pixels; - return usedTileBytes < 2 * bmpSize; + return usedTileBytes * 2 < bmpSize; } bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr, @@ -788,19 +820,19 @@ bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr const SkMatrix& srcToDstRect) const { ASSERT_SINGLE_OWNER // if image is explictly texture backed then just use the texture - if (as_IB(image)->peekTexture()) { + if (image->isTextureBacked()) { return false; } - GrTextureParams params; + GrSamplerParams params; bool doBicubic; - GrTextureParams::FilterMode textureFilterMode = + GrSamplerParams::FilterMode textureFilterMode = GrSkFilterQualityToGrFilterMode(quality, viewMatrix, srcToDstRect, &doBicubic); int tileFilterPad; if (doBicubic) { tileFilterPad = GrBicubicEffect::kFilterTexelPad; - } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) { + } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) { tileFilterPad = 0; } else { tileFilterPad = 1; @@ -818,20 +850,19 @@ bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr &outClippedSrcRect); } -void SkGpuDevice::drawBitmap(const SkDraw& origDraw, - const SkBitmap& bitmap, +void SkGpuDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& m, const SkPaint& paint) { ASSERT_SINGLE_OWNER - CHECK_SHOULD_DRAW(origDraw); + CHECK_SHOULD_DRAW(); SkMatrix viewMatrix; - viewMatrix.setConcat(*origDraw.fMatrix, m); + viewMatrix.setConcat(this->ctm(), m); int maxTileSize = fContext->caps()->maxTileSize(); // The tile code path doesn't currently support AA, so if the paint asked for aa and we could // draw untiled, then we bypass checking for tiling purely for optimization reasons. - bool drawAA = !fDrawContext->isUnifiedMultisampled() && + bool drawAA = !fRenderTargetContext->isUnifiedMultisampled() && paint.isAntiAlias() && bitmap.width() <= maxTileSize && bitmap.height() <= maxTileSize; @@ -843,9 +874,9 @@ void SkGpuDevice::drawBitmap(const SkDraw& origDraw, int tileSize; SkIRect clippedSrcRect; - GrTextureParams params; + GrSamplerParams params; bool doBicubic; - GrTextureParams::FilterMode textureFilterMode = + GrSamplerParams::FilterMode textureFilterMode = GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, SkMatrix::I(), &doBicubic); @@ -853,7 +884,7 @@ void SkGpuDevice::drawBitmap(const SkDraw& origDraw, if (doBicubic) { tileFilterPad = GrBicubicEffect::kFilterTexelPad; - } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) { + } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) { tileFilterPad = 0; } else { tileFilterPad = 1; @@ -870,9 +901,9 @@ void SkGpuDevice::drawBitmap(const SkDraw& origDraw, return; } } - GrBitmapTextureMaker maker(fContext, bitmap); + GrBitmapTextureMaker maker(fContext.get(), bitmap); this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kStrict_SrcRectConstraint, - viewMatrix, fClip, paint); + viewMatrix, this->clip(), paint); } // This method outsets 'iRect' by 'outset' all around and then clamps its extents to @@ -915,7 +946,7 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, const SkMatrix& dstMatrix, const SkRect& srcRect, const SkIRect& clippedSrcIRect, - const GrTextureParams& params, + const GrSamplerParams& params, const SkPaint& origPaint, SkCanvas::SrcRectConstraint constraint, int tileSize, @@ -934,7 +965,7 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, const SkPaint* paint = &origPaint; SkPaint tempPaint; - if (origPaint.isAntiAlias() && !fDrawContext->isUnifiedMultisampled()) { + if (origPaint.isAntiAlias() && !fRenderTargetContext->isUnifiedMultisampled()) { // Drop antialiasing to avoid seams at tile boundaries. tempPaint = origPaint; tempPaint.setAntiAlias(false); @@ -964,10 +995,9 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, tileR.roundOut(&iTileR); SkVector offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft), SkIntToScalar(iTileR.fTop)); - SkRect rectToDraw = SkRect::MakeXYWH(offset.fX, offset.fY, - tileR.width(), tileR.height()); + SkRect rectToDraw = tileR; dstMatrix.mapRect(&rectToDraw); - if (GrTextureParams::kNone_FilterMode != params.filterMode() || bicubic) { + if (GrSamplerParams::kNone_FilterMode != params.filterMode() || bicubic) { SkIRect iClampRect; if (SkCanvas::kFast_SrcRectConstraint == constraint) { @@ -988,14 +1018,13 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, if (bitmap.extractSubset(&tmpB, iTileR)) { // now offset it to make it "local" to our tmp bitmap tileR.offset(-offset.fX, -offset.fY); - GrTextureParams paramsTemp = params; // de-optimized this determination bool needsTextureDomain = true; this->drawBitmapTile(tmpB, viewMatrix, rectToDraw, tileR, - paramsTemp, + params, *paint, constraint, bicubic, @@ -1009,7 +1038,7 @@ void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap, const SkMatrix& viewMatrix, const SkRect& dstRect, const SkRect& srcRect, - const GrTextureParams& params, + const GrSamplerParams& params, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint, bool bicubic, @@ -1021,21 +1050,20 @@ void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap, SkASSERT(bitmap.width() <= fContext->caps()->maxTileSize() && bitmap.height() <= fContext->caps()->maxTileSize()); - sk_sp texture = GrMakeCachedBitmapTexture(fContext, bitmap, params, - fDrawContext->sourceGammaTreatment()); - if (nullptr == texture) { + SkASSERT(SkShader::kClamp_TileMode == params.getTileModeX() && + SkShader::kClamp_TileMode == params.getTileModeY()); + + sk_sp proxy = GrRefCachedBitmapTextureProxy(fContext.get(), bitmap, + params, nullptr); + if (!proxy) { return; } sk_sp colorSpaceXform = - GrColorSpaceXform::Make(bitmap.colorSpace(), fDrawContext->getColorSpace()); + GrColorSpaceXform::Make(bitmap.colorSpace(), fRenderTargetContext->getColorSpace()); - SkScalar iw = 1.f / texture->width(); - SkScalar ih = 1.f / texture->height(); - - SkMatrix texMatrix; // Compute a matrix that maps the rect we will draw to the src rect. - texMatrix.setRectToRect(dstRect, srcRect, SkMatrix::kFill_ScaleToFit); - texMatrix.postScale(iw, ih); + const SkMatrix texMatrix = SkMatrix::MakeRectToRect(dstRect, srcRect, + SkMatrix::kFill_ScaleToFit); // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring // the rest from the SkPaint. @@ -1045,97 +1073,80 @@ void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap, // Use a constrained texture domain to avoid color bleeding SkRect domain; if (srcRect.width() > SK_Scalar1) { - domain.fLeft = (srcRect.fLeft + 0.5f) * iw; - domain.fRight = (srcRect.fRight - 0.5f) * iw; + domain.fLeft = srcRect.fLeft + 0.5f; + domain.fRight = srcRect.fRight - 0.5f; } else { - domain.fLeft = domain.fRight = srcRect.centerX() * iw; + domain.fLeft = domain.fRight = srcRect.centerX(); } if (srcRect.height() > SK_Scalar1) { - domain.fTop = (srcRect.fTop + 0.5f) * ih; - domain.fBottom = (srcRect.fBottom - 0.5f) * ih; + domain.fTop = srcRect.fTop + 0.5f; + domain.fBottom = srcRect.fBottom - 0.5f; } else { - domain.fTop = domain.fBottom = srcRect.centerY() * ih; + domain.fTop = domain.fBottom = srcRect.centerY(); } if (bicubic) { - fp = GrBicubicEffect::Make(texture.get(), std::move(colorSpaceXform), texMatrix, - domain); + fp = GrBicubicEffect::Make(this->context()->resourceProvider(), std::move(proxy), + std::move(colorSpaceXform), texMatrix, domain); } else { - fp = GrTextureDomainEffect::Make(texture.get(), std::move(colorSpaceXform), texMatrix, + fp = GrTextureDomainEffect::Make(this->context()->resourceProvider(), std::move(proxy), + std::move(colorSpaceXform), texMatrix, domain, GrTextureDomain::kClamp_Mode, params.filterMode()); } } else if (bicubic) { - SkASSERT(GrTextureParams::kNone_FilterMode == params.filterMode()); + SkASSERT(GrSamplerParams::kNone_FilterMode == params.filterMode()); SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() }; - fp = GrBicubicEffect::Make(texture.get(), std::move(colorSpaceXform), texMatrix, tileModes); + fp = GrBicubicEffect::Make(this->context()->resourceProvider(), std::move(proxy), + std::move(colorSpaceXform), texMatrix, tileModes); } else { - fp = GrSimpleTextureEffect::Make(texture.get(), std::move(colorSpaceXform), texMatrix, params); + fp = GrSimpleTextureEffect::Make(this->context()->resourceProvider(), std::move(proxy), + std::move(colorSpaceXform), texMatrix, params); } GrPaint grPaint; - if (!SkPaintToGrPaintWithTexture(this->context(), fDrawContext.get(), paint, viewMatrix, + if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint, viewMatrix, std::move(fp), kAlpha_8_SkColorType == bitmap.colorType(), &grPaint)) { return; } - fDrawContext->drawRect(fClip, grPaint, viewMatrix, dstRect); + // Coverage-based AA would cause seams between tiles. + GrAA aa = GrBoolToAA(paint.isAntiAlias() && + fRenderTargetContext->isStencilBufferMultisampled()); + fRenderTargetContext->drawRect(this->clip(), std::move(grPaint), aa, viewMatrix, dstRect); } -void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, +void SkGpuDevice::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint& paint) { ASSERT_SINGLE_OWNER - CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSprite", fContext); + CHECK_SHOULD_DRAW(); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSprite", fContext.get()); if (fContext->abandoned()) { return; } - sk_sp texture; - { - SkAutoLockPixels alp(bitmap, true); - if (!bitmap.readyToDraw()) { - return; - } - - // draw sprite neither filters nor tiles. - texture.reset(GrRefCachedBitmapTexture(fContext, bitmap, - GrTextureParams::ClampNoFilter(), - SkSourceGammaTreatment::kRespect)); - if (!texture) { - return; - } + sk_sp srcImg = this->makeSpecial(bitmap); + if (!srcImg) { + return; } - SkIRect srcRect = SkIRect::MakeXYWH(bitmap.pixelRefOrigin().fX, - bitmap.pixelRefOrigin().fY, - bitmap.width(), - bitmap.height()); - - sk_sp srcImg(SkSpecialImage::MakeFromGpu(srcRect, - bitmap.getGenerationID(), - std::move(texture), - sk_ref_sp(bitmap.colorSpace()), - &this->surfaceProps())); - - this->drawSpecial(draw, srcImg.get(), left, top, paint); + this->drawSpecial(srcImg.get(), left, top, paint); } -void SkGpuDevice::drawSpecial(const SkDraw& draw, - SkSpecialImage* special1, +void SkGpuDevice::drawSpecial(SkSpecialImage* special1, int left, int top, const SkPaint& paint) { ASSERT_SINGLE_OWNER - CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSpecial", fContext); + CHECK_SHOULD_DRAW(); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSpecial", fContext.get()); SkIPoint offset = { 0, 0 }; sk_sp result; if (paint.getImageFilter()) { - result = this->filterTexture(draw, special1, left, top, + result = this->filterTexture(special1, left, top, &offset, paint.getImageFilter()); if (!result) { @@ -1146,45 +1157,52 @@ void SkGpuDevice::drawSpecial(const SkDraw& draw, } SkASSERT(result->isTextureBacked()); - sk_sp texture = result->asTextureRef(fContext); + sk_sp proxy = result->asTextureProxyRef(this->context()); + if (!proxy) { + return; + } + + const GrPixelConfig config = proxy->config(); SkPaint tmpUnfiltered(paint); tmpUnfiltered.setImageFilter(nullptr); sk_sp colorSpaceXform = - GrColorSpaceXform::Make(result->getColorSpace(), fDrawContext->getColorSpace()); - GrPaint grPaint; - sk_sp fp(GrSimpleTextureEffect::Make(texture.get(), + GrColorSpaceXform::Make(result->getColorSpace(), fRenderTargetContext->getColorSpace()); + + sk_sp fp(GrSimpleTextureEffect::Make(this->context()->resourceProvider(), + std::move(proxy), std::move(colorSpaceXform), SkMatrix::I())); - if (GrPixelConfigIsAlphaOnly(texture->config())) { - fp = GrFragmentProcessor::MulOutputByInputUnpremulColor(std::move(fp)); + if (GrPixelConfigIsAlphaOnly(config)) { + fp = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp)); } else { fp = GrFragmentProcessor::MulOutputByInputAlpha(std::move(fp)); } - if (!SkPaintToGrPaintReplaceShader(this->context(), fDrawContext.get(), tmpUnfiltered, + + GrPaint grPaint; + if (!SkPaintToGrPaintReplaceShader(this->context(), fRenderTargetContext.get(), tmpUnfiltered, std::move(fp), &grPaint)) { return; } const SkIRect& subset = result->subset(); - fDrawContext->fillRectToRect(fClip, - grPaint, - SkMatrix::I(), - SkRect::Make(SkIRect::MakeXYWH(left + offset.fX, top + offset.fY, - subset.width(), subset.height())), - SkRect::MakeXYWH(SkIntToScalar(subset.fLeft) / texture->width(), - SkIntToScalar(subset.fTop) / texture->height(), - SkIntToScalar(subset.width()) / texture->width(), - SkIntToScalar(subset.height()) / texture->height())); + fRenderTargetContext->fillRectToRect( + this->clip(), + std::move(grPaint), + GrBoolToAA(paint.isAntiAlias()), + SkMatrix::I(), + SkRect::Make(SkIRect::MakeXYWH(left + offset.fX, top + offset.fY, subset.width(), + subset.height())), + SkRect::Make(subset)); } -void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, +void SkGpuDevice::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& origDst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { ASSERT_SINGLE_OWNER - CHECK_SHOULD_DRAW(draw); + CHECK_SHOULD_DRAW(); // The src rect is inferred to be the bmp bounds if not provided. Otherwise, the src rect must // be clipped to the bmp bounds. To determine tiling parameters we need the filter mode which @@ -1218,7 +1236,7 @@ void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, // The tile code path doesn't currently support AA, so if the paint asked for aa and we could // draw untiled, then we bypass checking for tiling purely for optimization reasons. - bool drawAA = !fDrawContext->isUnifiedMultisampled() && + bool drawAA = !fRenderTargetContext->isUnifiedMultisampled() && paint.isAntiAlias() && bitmap.width() <= maxTileSize && bitmap.height() <= maxTileSize; @@ -1229,17 +1247,17 @@ void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, int tileSize; SkIRect clippedSrcRect; - GrTextureParams params; + GrSamplerParams params; bool doBicubic; - GrTextureParams::FilterMode textureFilterMode = - GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), *draw.fMatrix, srcToDstMatrix, + GrSamplerParams::FilterMode textureFilterMode = + GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), this->ctm(), srcToDstMatrix, &doBicubic); int tileFilterPad; if (doBicubic) { tileFilterPad = GrBicubicEffect::kFilterTexelPad; - } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) { + } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) { tileFilterPad = 0; } else { tileFilterPad = 1; @@ -1247,48 +1265,49 @@ void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, params.setFilterMode(textureFilterMode); int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad; - if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), *draw.fMatrix, + if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), this->ctm(), srcToDstMatrix, params, src, maxTileSizeForFilter, &tileSize, &clippedSrcRect)) { - this->drawTiledBitmap(bitmap, *draw.fMatrix, srcToDstMatrix, *src, clippedSrcRect, + this->drawTiledBitmap(bitmap, this->ctm(), srcToDstMatrix, *src, clippedSrcRect, params, paint, constraint, tileSize, doBicubic); return; } } - GrBitmapTextureMaker maker(fContext, bitmap); - this->drawTextureProducer(&maker, src, dst, constraint, *draw.fMatrix, fClip, paint); + GrBitmapTextureMaker maker(fContext.get(), bitmap); + this->drawTextureProducer(&maker, src, dst, constraint, this->ctm(), this->clip(), paint); } sk_sp SkGpuDevice::makeSpecial(const SkBitmap& bitmap) { - SkAutoLockPixels alp(bitmap, true); - if (!bitmap.readyToDraw()) { + // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's + // semantics). Since this is cached we would have to bake the fit into the cache key though. + sk_sp proxy = GrMakeCachedBitmapProxy(fContext->resourceProvider(), bitmap); + if (!proxy) { return nullptr; } - sk_sp texture = GrMakeCachedBitmapTexture(fContext, bitmap, - GrTextureParams::ClampNoFilter(), - SkSourceGammaTreatment::kRespect); - if (!texture) { - return nullptr; - } + const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height()); - return SkSpecialImage::MakeFromGpu(bitmap.bounds(), - bitmap.getGenerationID(), - texture, - sk_ref_sp(bitmap.colorSpace()), - &this->surfaceProps()); + // GrMakeCachedBitmapProxy creates a tight copy of 'bitmap' so we don't have to subset + // the special image + return SkSpecialImage::MakeDeferredFromGpu(fContext.get(), + rect, + bitmap.getGenerationID(), + std::move(proxy), + bitmap.refColorSpace(), + &this->surfaceProps()); } sk_sp SkGpuDevice::makeSpecial(const SkImage* image) { SkPixmap pm; if (image->isTextureBacked()) { - GrTexture* texture = as_IB(image)->peekTexture(); + sk_sp proxy = as_IB(image)->asTextureProxyRef(); - return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(image->width(), image->height()), - image->uniqueID(), - sk_ref_sp(texture), - sk_ref_sp(as_IB(image)->onImageInfo().colorSpace()), - &this->surfaceProps()); + return SkSpecialImage::MakeDeferredFromGpu(fContext.get(), + SkIRect::MakeWH(image->width(), image->height()), + image->uniqueID(), + std::move(proxy), + as_IB(image)->onImageInfo().refColorSpace(), + &this->surfaceProps()); } else if (image->peekPixels(&pm)) { SkBitmap bm; @@ -1300,18 +1319,15 @@ sk_sp SkGpuDevice::makeSpecial(const SkImage* image) { } sk_sp SkGpuDevice::snapSpecial() { - sk_sp texture(this->accessDrawContext()->asTexture()); - if (!texture) { + sk_sp proxy(this->accessRenderTargetContext()->asTextureProxyRef()); + if (!proxy) { // When the device doesn't have a texture, we create a temporary texture. // TODO: we should actually only copy the portion of the source needed to apply the image // filter - texture.reset(fContext->textureProvider()->createTexture(this->accessDrawContext()->desc(), - SkBudgeted::kYes)); - if (!texture) { - return nullptr; - } - - if (!fContext->copySurface(texture.get(), this->accessDrawContext()->accessRenderTarget())){ + proxy = GrSurfaceProxy::Copy(fContext.get(), + this->accessRenderTargetContext()->asSurfaceProxy(), + SkBudgeted::kYes); + if (!proxy) { return nullptr; } } @@ -1319,23 +1335,25 @@ sk_sp SkGpuDevice::snapSpecial() { const SkImageInfo ii = this->imageInfo(); const SkIRect srcRect = SkIRect::MakeWH(ii.width(), ii.height()); - return SkSpecialImage::MakeFromGpu(srcRect, - kNeedNewImageUniqueID_SpecialImage, - std::move(texture), - sk_ref_sp(ii.colorSpace()), - &this->surfaceProps()); + SkASSERT(proxy->priv().isExact()); + return SkSpecialImage::MakeDeferredFromGpu(fContext.get(), + srcRect, + kNeedNewImageUniqueID_SpecialImage, + std::move(proxy), + ii.refColorSpace(), + &this->surfaceProps()); } -void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, +void SkGpuDevice::drawDevice(SkBaseDevice* device, int left, int top, const SkPaint& paint) { SkASSERT(!paint.getImageFilter()); ASSERT_SINGLE_OWNER // clear of the source device must occur before CHECK_SHOULD_DRAW - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext.get()); // drawDevice is defined to be in device coords. - CHECK_SHOULD_DRAW(draw); + CHECK_SHOULD_DRAW(); SkGpuDevice* dev = static_cast(device); sk_sp srcImg(dev->snapSpecial()); @@ -1343,420 +1361,385 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, return; } - this->drawSpecial(draw, srcImg.get(), left, top, paint); + this->drawSpecial(srcImg.get(), left, top, paint); } -void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y, +void SkGpuDevice::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint& paint) { ASSERT_SINGLE_OWNER - SkMatrix viewMatrix = *draw.fMatrix; + SkMatrix viewMatrix = this->ctm(); viewMatrix.preTranslate(x, y); uint32_t pinnedUniqueID; - if (sk_sp tex = as_IB(image)->refPinnedTexture(&pinnedUniqueID)) { - CHECK_SHOULD_DRAW(draw); - GrTextureAdjuster adjuster(tex.get(), image->alphaType(), image->bounds(), pinnedUniqueID, - as_IB(image)->onImageInfo().colorSpace()); + + if (sk_sp proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) { + CHECK_SHOULD_DRAW(); + GrTextureAdjuster adjuster(this->context(), std::move(proxy), + image->alphaType(), image->bounds(), + pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace()); this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, - viewMatrix, fClip, paint); + viewMatrix, this->clip(), paint); return; } else { SkBitmap bm; if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint, - paint.getFilterQuality(), *draw.fMatrix, SkMatrix::I())) { + paint.getFilterQuality(), this->ctm(), SkMatrix::I())) { // only support tiling as bitmap at the moment, so force raster-version - if (!as_IB(image)->getROPixels(&bm)) { + if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) { return; } - this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); + this->drawBitmap(bm, SkMatrix::MakeTrans(x, y), paint); } else if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { - CHECK_SHOULD_DRAW(draw); - GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint); + CHECK_SHOULD_DRAW(); + GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint); this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, - viewMatrix, fClip, paint); - } else if (as_IB(image)->getROPixels(&bm)) { - this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); + viewMatrix, this->clip(), paint); + } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) { + this->drawBitmap(bm, SkMatrix::MakeTrans(x, y), paint); } } } -void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src, +void SkGpuDevice::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { ASSERT_SINGLE_OWNER uint32_t pinnedUniqueID; - if (sk_sp tex = as_IB(image)->refPinnedTexture(&pinnedUniqueID)) { - CHECK_SHOULD_DRAW(draw); - GrTextureAdjuster adjuster(tex.get(), image->alphaType(), image->bounds(), pinnedUniqueID, + if (sk_sp proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) { + CHECK_SHOULD_DRAW(); + GrTextureAdjuster adjuster(this->context(), std::move(proxy), + image->alphaType(), image->bounds(), pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace()); - this->drawTextureProducer(&adjuster, src, &dst, constraint, *draw.fMatrix, fClip, paint); + this->drawTextureProducer(&adjuster, src, &dst, constraint, this->ctm(), this->clip(), + paint); return; } SkBitmap bm; SkMatrix srcToDstRect; srcToDstRect.setRectToRect((src ? *src : SkRect::MakeIWH(image->width(), image->height())), dst, SkMatrix::kFill_ScaleToFit); - if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), *draw.fMatrix, + if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), this->ctm(), srcToDstRect)) { // only support tiling as bitmap at the moment, so force raster-version - if (!as_IB(image)->getROPixels(&bm)) { + if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) { return; } - this->drawBitmapRect(draw, bm, src, dst, paint, constraint); + this->drawBitmapRect(bm, src, dst, paint, constraint); } else if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { - CHECK_SHOULD_DRAW(draw); - GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint); - this->drawTextureProducer(&maker, src, &dst, constraint, *draw.fMatrix, fClip, paint); - } else if (as_IB(image)->getROPixels(&bm)) { - this->drawBitmapRect(draw, bm, src, dst, paint, constraint); + CHECK_SHOULD_DRAW(); + GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint); + this->drawTextureProducer(&maker, src, &dst, constraint, this->ctm(), this->clip(), paint); + } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) { + this->drawBitmapRect(bm, src, dst, paint, constraint); } } -void SkGpuDevice::drawProducerNine(const SkDraw& draw, GrTextureProducer* producer, +void SkGpuDevice::drawProducerNine(GrTextureProducer* producer, const SkIRect& center, const SkRect& dst, const SkPaint& paint) { - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerNine", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerNine", fContext.get()); - CHECK_SHOULD_DRAW(draw); + CHECK_SHOULD_DRAW(); bool useFallback = paint.getMaskFilter() || paint.isAntiAlias() || - fDrawContext->isUnifiedMultisampled(); + fRenderTargetContext->isUnifiedMultisampled(); bool doBicubic; - GrTextureParams::FilterMode textureFilterMode = - GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), *draw.fMatrix, SkMatrix::I(), + GrSamplerParams::FilterMode textureFilterMode = + GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), this->ctm(), SkMatrix::I(), &doBicubic); - if (useFallback || doBicubic || GrTextureParams::kNone_FilterMode != textureFilterMode) { + if (useFallback || doBicubic || GrSamplerParams::kNone_FilterMode != textureFilterMode) { SkLatticeIter iter(producer->width(), producer->height(), center, dst); SkRect srcR, dstR; while (iter.next(&srcR, &dstR)) { this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint, - *draw.fMatrix, fClip, paint); + this->ctm(), this->clip(), paint); } return; } - static const GrTextureParams::FilterMode kMode = GrTextureParams::kNone_FilterMode; + static const GrSamplerParams::FilterMode kMode = GrSamplerParams::kNone_FilterMode; sk_sp fp( producer->createFragmentProcessor(SkMatrix::I(), SkRect::MakeIWH(producer->width(), producer->height()), GrTextureProducer::kNo_FilterConstraint, true, - &kMode, fDrawContext->getColorSpace(), - fDrawContext->sourceGammaTreatment())); + &kMode, fRenderTargetContext->getColorSpace())); GrPaint grPaint; - if (!SkPaintToGrPaintWithTexture(this->context(), fDrawContext.get(), paint, *draw.fMatrix, - std::move(fp), producer->isAlphaOnly(), &grPaint)) { + if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint, + this->ctm(), std::move(fp), producer->isAlphaOnly(), + &grPaint)) { return; } std::unique_ptr iter( new SkLatticeIter(producer->width(), producer->height(), center, dst)); - fDrawContext->drawImageLattice(fClip, grPaint, *draw.fMatrix, producer->width(), - producer->height(), std::move(iter), dst); + fRenderTargetContext->drawImageLattice(this->clip(), std::move(grPaint), this->ctm(), + producer->width(), producer->height(), std::move(iter), + dst); } -void SkGpuDevice::drawImageNine(const SkDraw& draw, const SkImage* image, +void SkGpuDevice::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, const SkPaint& paint) { ASSERT_SINGLE_OWNER uint32_t pinnedUniqueID; - if (sk_sp tex = as_IB(image)->refPinnedTexture(&pinnedUniqueID)) { - CHECK_SHOULD_DRAW(draw); - GrTextureAdjuster adjuster(tex.get(), image->alphaType(), image->bounds(), pinnedUniqueID, - as_IB(image)->onImageInfo().colorSpace()); - this->drawProducerNine(draw, &adjuster, center, dst, paint); + if (sk_sp proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) { + CHECK_SHOULD_DRAW(); + GrTextureAdjuster adjuster(this->context(), std::move(proxy), + image->alphaType(), image->bounds(), + pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace()); + this->drawProducerNine(&adjuster, center, dst, paint); } else { SkBitmap bm; if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { - GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint); - this->drawProducerNine(draw, &maker, center, dst, paint); - } else if (as_IB(image)->getROPixels(&bm)) { - this->drawBitmapNine(draw, bm, center, dst, paint); + GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint); + this->drawProducerNine(&maker, center, dst, paint); + } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) { + this->drawBitmapNine(bm, center, dst, paint); } } } -void SkGpuDevice::drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, const SkIRect& center, +void SkGpuDevice::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint& paint) { ASSERT_SINGLE_OWNER - GrBitmapTextureMaker maker(fContext, bitmap); - this->drawProducerNine(draw, &maker, center, dst, paint); + GrBitmapTextureMaker maker(fContext.get(), bitmap); + this->drawProducerNine(&maker, center, dst, paint); } -void SkGpuDevice::drawProducerLattice(const SkDraw& draw, GrTextureProducer* producer, +void SkGpuDevice::drawProducerLattice(GrTextureProducer* producer, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint& paint) { - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerLattice", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerLattice", fContext.get()); - CHECK_SHOULD_DRAW(draw); + CHECK_SHOULD_DRAW(); - static const GrTextureParams::FilterMode kMode = GrTextureParams::kNone_FilterMode; + static const GrSamplerParams::FilterMode kMode = GrSamplerParams::kNone_FilterMode; sk_sp fp( producer->createFragmentProcessor(SkMatrix::I(), SkRect::MakeIWH(producer->width(), producer->height()), GrTextureProducer::kNo_FilterConstraint, true, - &kMode, fDrawContext->getColorSpace(), - fDrawContext->sourceGammaTreatment())); + &kMode, fRenderTargetContext->getColorSpace())); GrPaint grPaint; - if (!SkPaintToGrPaintWithTexture(this->context(), fDrawContext.get(), paint, *draw.fMatrix, - std::move(fp), producer->isAlphaOnly(), &grPaint)) { + if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint, + this->ctm(), std::move(fp), producer->isAlphaOnly(), + &grPaint)) { return; } std::unique_ptr iter( new SkLatticeIter(lattice, dst)); - fDrawContext->drawImageLattice(fClip, grPaint, *draw.fMatrix, producer->width(), - producer->height(), std::move(iter), dst); + fRenderTargetContext->drawImageLattice(this->clip(), std::move(grPaint), this->ctm(), + producer->width(), producer->height(), std::move(iter), + dst); } -void SkGpuDevice::drawImageLattice(const SkDraw& draw, const SkImage* image, +void SkGpuDevice::drawImageLattice(const SkImage* image, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint& paint) { ASSERT_SINGLE_OWNER uint32_t pinnedUniqueID; - if (sk_sp tex = as_IB(image)->refPinnedTexture(&pinnedUniqueID)) { - CHECK_SHOULD_DRAW(draw); - GrTextureAdjuster adjuster(tex.get(), image->alphaType(), image->bounds(), pinnedUniqueID, - as_IB(image)->onImageInfo().colorSpace()); - this->drawProducerLattice(draw, &adjuster, lattice, dst, paint); + if (sk_sp proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) { + CHECK_SHOULD_DRAW(); + GrTextureAdjuster adjuster(this->context(), std::move(proxy), + image->alphaType(), image->bounds(), + pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace()); + this->drawProducerLattice(&adjuster, lattice, dst, paint); } else { SkBitmap bm; if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { - GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint); - this->drawProducerLattice(draw, &maker, lattice, dst, paint); - } else if (as_IB(image)->getROPixels(&bm)) { - this->drawBitmapLattice(draw, bm, lattice, dst, paint); + GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint); + this->drawProducerLattice(&maker, lattice, dst, paint); + } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) { + this->drawBitmapLattice(bm, lattice, dst, paint); } } } -void SkGpuDevice::drawBitmapLattice(const SkDraw& draw, const SkBitmap& bitmap, +void SkGpuDevice::drawBitmapLattice(const SkBitmap& bitmap, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint& paint) { ASSERT_SINGLE_OWNER - GrBitmapTextureMaker maker(fContext, bitmap); - this->drawProducerLattice(draw, &maker, lattice, dst, paint); + GrBitmapTextureMaker maker(fContext.get(), bitmap); + this->drawProducerLattice(&maker, lattice, dst, paint); } -/////////////////////////////////////////////////////////////////////////////// - -// must be in SkCanvas::VertexMode order -static const GrPrimitiveType gVertexMode2PrimitiveType[] = { - kTriangles_GrPrimitiveType, - kTriangleStrip_GrPrimitiveType, - kTriangleFan_GrPrimitiveType, -}; - -void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, - int vertexCount, const SkPoint vertices[], - const SkPoint texs[], const SkColor colors[], - SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { - ASSERT_SINGLE_OWNER - CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext); - - // If both textures and vertex-colors are nullptr, strokes hairlines with the paint's color. - if ((nullptr == texs || nullptr == paint.getShader()) && nullptr == colors) { - - texs = nullptr; - - SkPaint copy(paint); - copy.setStyle(SkPaint::kStroke_Style); - copy.setStrokeWidth(0); - - GrPaint grPaint; - // we ignore the shader if texs is null. - if (!SkPaintToGrPaintNoShader(this->context(), fDrawContext.get(), copy, &grPaint)) { - return; - } - - int triangleCount = 0; - int n = (nullptr == indices) ? vertexCount : indexCount; - switch (vmode) { - case SkCanvas::kTriangles_VertexMode: - triangleCount = n / 3; - break; - case SkCanvas::kTriangleStrip_VertexMode: - case SkCanvas::kTriangleFan_VertexMode: - triangleCount = n - 2; - break; - } - - VertState state(vertexCount, indices, indexCount); - VertState::Proc vertProc = state.chooseProc(vmode); - - //number of indices for lines per triangle with kLines - indexCount = triangleCount * 6; - - SkAutoTDeleteArray lineIndices(new uint16_t[indexCount]); - int i = 0; - while (vertProc(&state)) { - lineIndices[i] = state.f0; - lineIndices[i + 1] = state.f1; - lineIndices[i + 2] = state.f1; - lineIndices[i + 3] = state.f2; - lineIndices[i + 4] = state.f2; - lineIndices[i + 5] = state.f0; - i += 6; - } - fDrawContext->drawVertices(fClip, - grPaint, - *draw.fMatrix, - kLines_GrPrimitiveType, - vertexCount, - vertices, - texs, - colors, - lineIndices.get(), - indexCount); - return; - } - - GrPrimitiveType primType = gVertexMode2PrimitiveType[vmode]; - - SkAutoSTMalloc<128, GrColor> convertedColors(0); - if (colors) { - // need to convert byte order and from non-PM to PM. TODO: Keep unpremul until after - // interpolation. - convertedColors.reset(vertexCount); - for (int i = 0; i < vertexCount; ++i) { - convertedColors[i] = SkColorToPremulGrColor(colors[i]); - } - colors = convertedColors.get(); - } - GrPaint grPaint; - if (texs && paint.getShader()) { - if (colors) { - // When there are texs and colors the shader and colors are combined using xmode. A null - // xmode is defined to mean modulate. - SkXfermode::Mode colorMode; - if (xmode) { - if (!xmode->asMode(&colorMode)) { - return; - } - } else { - colorMode = SkXfermode::kModulate_Mode; - } - if (!SkPaintToGrPaintWithXfermode(this->context(), fDrawContext.get(), paint, - *draw.fMatrix, colorMode, false, &grPaint)) { - return; - } +static bool init_vertices_paint(GrContext* context, GrRenderTargetContext* rtc, + const SkPaint& skPaint, + const SkMatrix& matrix, SkBlendMode bmode, + bool hasTexs, bool hasColors, GrPaint* grPaint) { + if (hasTexs && skPaint.getShader()) { + if (hasColors) { + // When there are texs and colors the shader and colors are combined using bmode. + return SkPaintToGrPaintWithXfermode(context, rtc, skPaint, matrix, bmode, false, + grPaint); } else { // We have a shader, but no colors to blend it against. - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, - &grPaint)) { - return; - } + return SkPaintToGrPaint(context, rtc, skPaint, matrix, grPaint); } } else { - if (colors) { + if (hasColors) { // We have colors, but either have no shader or no texture coords (which implies that // we should ignore the shader). - if (!SkPaintToGrPaintWithPrimitiveColor(this->context(), fDrawContext.get(), paint, - &grPaint)) { - return; - } + return SkPaintToGrPaintWithPrimitiveColor(context, rtc, skPaint, grPaint); } else { // No colors and no shaders. Just draw with the paint color. - if (!SkPaintToGrPaintNoShader(this->context(), fDrawContext.get(), paint, &grPaint)) { - return; - } + return (!SkPaintToGrPaintNoShader(context, rtc, skPaint, grPaint)); } } +} - fDrawContext->drawVertices(fClip, - grPaint, - *draw.fMatrix, - primType, - vertexCount, - vertices, - texs, - colors, - indices, - indexCount); +void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCount, + const SkPoint vertices[], SkBlendMode bmode, + const uint16_t indices[], int indexCount, + const SkPaint& paint) { + ASSERT_SINGLE_OWNER + CHECK_SHOULD_DRAW(); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "wireframeVertices", fContext.get()); + + SkPaint copy(paint); + copy.setStyle(SkPaint::kStroke_Style); + copy.setStrokeWidth(0); + + GrPaint grPaint; + // we ignore the shader since we have no texture coordinates. + if (!SkPaintToGrPaintNoShader(this->context(), fRenderTargetContext.get(), copy, &grPaint)) { + return; + } + + int triangleCount = 0; + int n = (nullptr == indices) ? vertexCount : indexCount; + switch (vmode) { + case SkVertices::kTriangles_VertexMode: + triangleCount = n / 3; + break; + case SkVertices::kTriangleStrip_VertexMode: + case SkVertices::kTriangleFan_VertexMode: + triangleCount = n - 2; + break; + } + + VertState state(vertexCount, indices, indexCount); + VertState::Proc vertProc = state.chooseProc(vmode); + + //number of indices for lines per triangle with kLines + indexCount = triangleCount * 6; + + std::unique_ptr lineIndices(new uint16_t[indexCount]); + int i = 0; + while (vertProc(&state)) { + lineIndices[i] = state.f0; + lineIndices[i + 1] = state.f1; + lineIndices[i + 2] = state.f1; + lineIndices[i + 3] = state.f2; + lineIndices[i + 4] = state.f2; + lineIndices[i + 5] = state.f0; + i += 6; + } + fRenderTargetContext->drawVertices(this->clip(), + std::move(grPaint), + this->ctm(), + kLines_GrPrimitiveType, + vertexCount, + vertices, + nullptr, + nullptr, + lineIndices.get(), + indexCount); +} + +void SkGpuDevice::drawVertices(const SkVertices* vertices, SkBlendMode mode, + const SkPaint& paint) { + ASSERT_SINGLE_OWNER + CHECK_SHOULD_DRAW(); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get()); + + SkASSERT(vertices); + GrPaint grPaint; + bool hasColors = vertices->hasColors(); + bool hasTexs = vertices->hasTexCoords(); + if (!hasTexs && !hasColors) { + // The dreaded wireframe mode. Fallback to drawVertices and go so slooooooow. + this->wireframeVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), + mode, vertices->indices(), vertices->indexCount(), paint); + } + if (!init_vertices_paint(fContext.get(), fRenderTargetContext.get(), paint, this->ctm(), + mode, hasTexs, hasColors, &grPaint)) { + return; + } + fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->ctm(), + sk_ref_sp(const_cast(vertices))); } /////////////////////////////////////////////////////////////////////////////// -void SkGpuDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRSXform xform[], +void SkGpuDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect texRect[], const SkColor colors[], int count, - SkXfermode::Mode mode, const SkPaint& paint) { + SkBlendMode mode, const SkPaint& paint) { ASSERT_SINGLE_OWNER if (paint.isAntiAlias()) { - this->INHERITED::drawAtlas(draw, atlas, xform, texRect, colors, count, mode, paint); + this->INHERITED::drawAtlas(atlas, xform, texRect, colors, count, mode, paint); return; } - CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext); + CHECK_SHOULD_DRAW(); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get()); SkPaint p(paint); p.setShader(atlas->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)); GrPaint grPaint; if (colors) { - if (!SkPaintToGrPaintWithXfermode(this->context(), fDrawContext.get(), p, *draw.fMatrix, - mode, true, &grPaint)) { + if (!SkPaintToGrPaintWithXfermode(this->context(), fRenderTargetContext.get(), p, + this->ctm(), (SkBlendMode)mode, true, &grPaint)) { return; } } else { - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), p, *draw.fMatrix, &grPaint)) { + if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), p, this->ctm(), + &grPaint)) { return; } } SkDEBUGCODE(this->validate();) - fDrawContext->drawAtlas(fClip, grPaint, *draw.fMatrix, count, xform, texRect, colors); + fRenderTargetContext->drawAtlas( + this->clip(), std::move(grPaint), this->ctm(), count, xform, texRect, colors); } /////////////////////////////////////////////////////////////////////////////// -void SkGpuDevice::drawText(const SkDraw& draw, const void* text, +void SkGpuDevice::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { ASSERT_SINGLE_OWNER - CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext); - - GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, &grPaint)) { - return; - } - + CHECK_SHOULD_DRAW(); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get()); SkDEBUGCODE(this->validate();) - fDrawContext->drawText(fClip, grPaint, paint, *draw.fMatrix, - (const char *)text, byteLength, x, y, draw.fRC->getBounds()); + fRenderTargetContext->drawText(this->clip(), paint, this->ctm(), (const char*)text, byteLength, + x, y, this->devClipBounds()); } -void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, size_t byteLength, +void SkGpuDevice::drawPosText(const void* text, size_t byteLength, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { ASSERT_SINGLE_OWNER - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPosText", fContext); - CHECK_SHOULD_DRAW(draw); - - GrPaint grPaint; - if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, &grPaint)) { - return; - } - + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPosText", fContext.get()); + CHECK_SHOULD_DRAW(); SkDEBUGCODE(this->validate();) - fDrawContext->drawPosText(fClip, grPaint, paint, *draw.fMatrix, - (const char *)text, byteLength, pos, scalarsPerPos, offset, - draw.fRC->getBounds()); + fRenderTargetContext->drawPosText(this->clip(), paint, this->ctm(), (const char*)text, + byteLength, pos, scalarsPerPos, offset, + this->devClipBounds()); } -void SkGpuDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y, +void SkGpuDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint, SkDrawFilter* drawFilter) { ASSERT_SINGLE_OWNER - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawTextBlob", fContext); - CHECK_SHOULD_DRAW(draw); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawTextBlob", fContext.get()); + CHECK_SHOULD_DRAW(); SkDEBUGCODE(this->validate();) - fDrawContext->drawTextBlob(fClip, paint, *draw.fMatrix, - blob, x, y, drawFilter, draw.fRC->getBounds()); + fRenderTargetContext->drawTextBlob(this->clip(), paint, this->ctm(), blob, x, y, drawFilter, + this->devClipBounds()); } /////////////////////////////////////////////////////////////////////////////// @@ -1768,7 +1751,7 @@ bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const { void SkGpuDevice::flush() { ASSERT_SINGLE_OWNER - fDrawContext->prepareForExternalIO(); + fRenderTargetContext->prepareForExternalIO(); } /////////////////////////////////////////////////////////////////////////////// @@ -1783,34 +1766,32 @@ SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox : SkBackingFit::kExact; - sk_sp dc(fContext->makeDrawContext(fit, - cinfo.fInfo.width(), cinfo.fInfo.height(), - fDrawContext->config(), - sk_ref_sp(fDrawContext->getColorSpace()), - fDrawContext->desc().fSampleCnt, - kDefault_GrSurfaceOrigin, - &props)); - if (!dc) { - SkErrorInternals::SetError( kInternalError_SkError, - "---- failed to create gpu device texture [%d %d]\n", - cinfo.fInfo.width(), cinfo.fInfo.height()); - return nullptr; + sk_sp rtc(fContext->makeRenderTargetContext( + fit, + cinfo.fInfo.width(), cinfo.fInfo.height(), + fRenderTargetContext->config(), + fRenderTargetContext->refColorSpace(), + fRenderTargetContext->desc().fSampleCnt, + kDefault_GrSurfaceOrigin, + &props)); + if (!rtc) { + return nullptr; } // Skia's convention is to only clear a device if it is non-opaque. InitContents init = cinfo.fInfo.isOpaque() ? kUninit_InitContents : kClear_InitContents; - return SkGpuDevice::Make(std::move(dc), - cinfo.fInfo.width(), cinfo.fInfo.height(), - init).release(); + return SkGpuDevice::Make(fContext.get(), std::move(rtc), + cinfo.fInfo.width(), cinfo.fInfo.height(), init).release(); } sk_sp SkGpuDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) { ASSERT_SINGLE_OWNER // TODO: Change the signature of newSurface to take a budgeted parameter. static const SkBudgeted kBudgeted = SkBudgeted::kNo; - return SkSurface::MakeRenderTarget(fContext, kBudgeted, info, fDrawContext->desc().fSampleCnt, - fDrawContext->origin(), &props); + return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info, + fRenderTargetContext->desc().fSampleCnt, + fRenderTargetContext->origin(), &props); } SkImageFilterCache* SkGpuDevice::getImageFilterCache() { diff --git a/gfx/skia/skia/src/gpu/SkGpuDevice.h b/gfx/skia/skia/src/gpu/SkGpuDevice.h index a49d1607328d..4558c1b17a04 100644 --- a/gfx/skia/skia/src/gpu/SkGpuDevice.h +++ b/gfx/skia/skia/src/gpu/SkGpuDevice.h @@ -9,14 +9,13 @@ #define SkGpuDevice_DEFINED #include "SkGr.h" -#include "SkGrPriv.h" #include "SkBitmap.h" -#include "SkDevice.h" +#include "SkClipStackDevice.h" #include "SkPicture.h" #include "SkRegion.h" #include "SkSurface.h" #include "GrClipStackClip.h" -#include "GrDrawContext.h" +#include "GrRenderTargetContext.h" #include "GrContext.h" #include "GrSurfacePriv.h" #include "GrTypes.h" @@ -31,7 +30,7 @@ class SkSpecialImage; * Subclass of SkBaseDevice, which directs all drawing to the GrGpu owned by the * canvas. */ -class SK_API SkGpuDevice : public SkBaseDevice { +class SK_API SkGpuDevice : public SkClipStackDevice { public: enum InitContents { kClear_InitContents, @@ -39,80 +38,79 @@ public: }; /** - * Creates an SkGpuDevice from a GrDrawContext whose backing width/height is + * Creates an SkGpuDevice from a GrRenderTargetContext whose backing width/height is * different than its actual width/height (e.g., approx-match scratch texture). */ - static sk_sp Make(sk_sp drawContext, - int width, int height, - InitContents); + static sk_sp Make(GrContext*, sk_sp renderTargetContext, + int width, int height, InitContents); /** * New device that will create an offscreen renderTarget based on the ImageInfo and * sampleCount. The Budgeted param controls whether the device's backing store counts against * the resource cache budget. On failure, returns nullptr. + * This entry point creates a kExact backing store. It is used when creating SkGpuDevices + * for SkSurfaces. */ static sk_sp Make(GrContext*, SkBudgeted, const SkImageInfo&, - int sampleCount, GrSurfaceOrigin, + int sampleCount, GrSurfaceOrigin, const SkSurfaceProps*, InitContents); ~SkGpuDevice() override {} - GrContext* context() const override { return fContext; } + GrContext* context() const override { return fContext.get(); } // set all pixels to 0 void clearAll(); - void replaceDrawContext(bool shouldRetainContent); + void replaceRenderTargetContext(bool shouldRetainContent); - GrDrawContext* accessDrawContext() override; + GrRenderTargetContext* accessRenderTargetContext() override; - void drawPaint(const SkDraw&, const SkPaint& paint) override; - void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, const SkPoint[], + void drawPaint(const SkPaint& paint) override; + void drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint[], const SkPaint& paint) override; - void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) override; - void drawRRect(const SkDraw&, const SkRRect& r, const SkPaint& paint) override; - void drawDRRect(const SkDraw& draw, const SkRRect& outer, const SkRRect& inner, + void drawRect(const SkRect& r, const SkPaint& paint) override; + void drawRRect(const SkRRect& r, const SkPaint& paint) override; + void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override; - void drawRegion(const SkDraw&, const SkRegion& r, const SkPaint& paint) override; - void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) override; - void drawArc(const SkDraw&, const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, + void drawRegion(const SkRegion& r, const SkPaint& paint) override; + void drawOval(const SkRect& oval, const SkPaint& paint) override; + void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint& paint) override; - void drawPath(const SkDraw&, const SkPath& path, const SkPaint& paint, + void drawPath(const SkPath& path, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) override; - void drawBitmap(const SkDraw&, const SkBitmap& bitmap, const SkMatrix&, + void drawBitmap(const SkBitmap& bitmap, const SkMatrix&, const SkPaint&) override; - void drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* srcOrNull, const SkRect& dst, + void drawBitmapRect(const SkBitmap&, const SkRect* srcOrNull, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint) override; - void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, + void drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) override; - void drawText(const SkDraw&, const void* text, size_t len, SkScalar x, SkScalar y, + void drawText(const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint&) override; - void drawPosText(const SkDraw&, const void* text, size_t len, const SkScalar pos[], + void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint&) override; - void drawTextBlob(const SkDraw&, const SkTextBlob*, SkScalar x, SkScalar y, + void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y, const SkPaint& paint, SkDrawFilter* drawFilter) override; - void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, const SkPoint verts[], - const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, const SkPaint&) override; - void drawAtlas(const SkDraw&, const SkImage* atlas, const SkRSXform[], const SkRect[], - const SkColor[], int count, SkXfermode::Mode, const SkPaint&) override; - void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, const SkPaint&) override; + void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override; + void drawAtlas(const SkImage* atlas, const SkRSXform[], const SkRect[], + const SkColor[], int count, SkBlendMode, const SkPaint&) override; + void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; - void drawImage(const SkDraw&, const SkImage*, SkScalar x, SkScalar y, const SkPaint&) override; - void drawImageRect(const SkDraw&, const SkImage*, const SkRect* src, const SkRect& dst, + void drawImage(const SkImage*, SkScalar x, SkScalar y, const SkPaint&) override; + void drawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override; - void drawImageNine(const SkDraw& draw, const SkImage* image, const SkIRect& center, + void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, const SkPaint& paint) override; - void drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, const SkIRect& center, + void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint& paint) override; - void drawImageLattice(const SkDraw&, const SkImage*, const SkCanvas::Lattice&, + void drawImageLattice(const SkImage*, const SkCanvas::Lattice&, const SkRect& dst, const SkPaint&) override; - void drawBitmapLattice(const SkDraw&, const SkBitmap&, const SkCanvas::Lattice&, + void drawBitmapLattice(const SkBitmap&, const SkCanvas::Lattice&, const SkRect& dst, const SkPaint&) override; - void drawSpecial(const SkDraw&, SkSpecialImage*, + void drawSpecial(SkSpecialImage*, int left, int top, const SkPaint& paint) override; sk_sp makeSpecial(const SkBitmap&) override; sk_sp makeSpecial(const SkImage*) override; @@ -122,23 +120,18 @@ public: bool onAccessPixels(SkPixmap*) override; - // for debugging purposes only - void drawTexture(GrTexture*, const SkRect& dst, const SkPaint&); - protected: bool onReadPixels(const SkImageInfo&, void*, size_t, int, int) override; bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) override; bool onShouldDisableLCD(const SkPaint&) const final; private: - // We want these unreffed in DrawContext, GrContext order. - SkAutoTUnref fContext; - sk_sp fDrawContext; + // We want these unreffed in RenderTargetContext, GrContext order. + sk_sp fContext; + sk_sp fRenderTargetContext; - SkIPoint fClipOrigin; - GrClipStackClip fClip; - SkISize fSize; - bool fOpaque; + SkISize fSize; + bool fOpaque; enum Flags { kNeedClear_Flag = 1 << 0, //!< Surface requires an initial clear @@ -148,7 +141,7 @@ private: static bool CheckAlphaTypeAndGetFlags(const SkImageInfo* info, InitContents init, unsigned* flags); - SkGpuDevice(sk_sp, int width, int height, unsigned flags); + SkGpuDevice(GrContext*, sk_sp, int width, int height, unsigned flags); SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; @@ -158,8 +151,7 @@ private: bool forceConservativeRasterClip() const override { return true; } - // sets the render target and clip on context - void prepareDraw(const SkDraw&); + GrClipStackClip clip() const { return GrClipStackClip(&this->cs()); } /** * Helper functions called by drawBitmapCommon. By the time these are called the SkDraw's @@ -170,7 +162,7 @@ private: bool shouldTileImageID(uint32_t imageID, const SkIRect& imageRect, const SkMatrix& viewMatrix, const SkMatrix& srcToDstRectMatrix, - const GrTextureParams& params, + const GrSamplerParams& params, const SkRect* srcRectPtr, int maxTileSize, int* tileSize, @@ -181,8 +173,7 @@ private: SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality, const SkMatrix& viewMatrix, const SkMatrix& srcToDstRect) const; - sk_sp filterTexture(const SkDraw&, - SkSpecialImage*, + sk_sp filterTexture(SkSpecialImage*, int left, int top, SkIPoint* offset, const SkImageFilter* filter); @@ -193,7 +184,7 @@ private: const SkMatrix& srcToDstMatrix, const SkRect& srcRect, const SkIRect& clippedSrcRect, - const GrTextureParams& params, + const GrSamplerParams& params, const SkPaint& paint, SkCanvas::SrcRectConstraint, int tileSize, @@ -204,7 +195,7 @@ private: const SkMatrix& viewMatrix, const SkRect& dstRect, const SkRect& srcRect, - const GrTextureParams& params, + const GrSamplerParams& params, const SkPaint& paint, SkCanvas::SrcRectConstraint, bool bicubic, @@ -230,25 +221,28 @@ private: bool drawFilledDRRect(const SkMatrix& viewMatrix, const SkRRect& outer, const SkRRect& inner, const SkPaint& paint); - void drawProducerNine(const SkDraw&, GrTextureProducer*, const SkIRect& center, + void drawProducerNine(GrTextureProducer*, const SkIRect& center, const SkRect& dst, const SkPaint&); - void drawProducerLattice(const SkDraw&, GrTextureProducer*, const SkCanvas::Lattice& lattice, + void drawProducerLattice(GrTextureProducer*, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint&); bool drawDashLine(const SkPoint pts[2], const SkPaint& paint); - void drawStrokedLine(const SkPoint pts[2], const SkDraw&, const SkPaint&); + void drawStrokedLine(const SkPoint pts[2], const SkPaint&); - static sk_sp MakeDrawContext(GrContext*, - SkBudgeted, - const SkImageInfo&, - int sampleCount, - GrSurfaceOrigin, - const SkSurfaceProps*); + void wireframeVertices(SkVertices::VertexMode, int vertexCount, const SkPoint verts[], + SkBlendMode, const uint16_t indices[], int indexCount, const SkPaint&); + + static sk_sp MakeRenderTargetContext(GrContext*, + SkBudgeted, + const SkImageInfo&, + int sampleCount, + GrSurfaceOrigin, + const SkSurfaceProps*); friend class GrAtlasTextContext; friend class SkSurface_Gpu; // for access to surfaceProps - typedef SkBaseDevice INHERITED; + typedef SkClipStackDevice INHERITED; }; #endif diff --git a/gfx/skia/skia/src/gpu/SkGpuDevice_drawTexture.cpp b/gfx/skia/skia/src/gpu/SkGpuDevice_drawTexture.cpp index 46a3699bb0f8..f0dbeb92ff6f 100644 --- a/gfx/skia/skia/src/gpu/SkGpuDevice_drawTexture.cpp +++ b/gfx/skia/skia/src/gpu/SkGpuDevice_drawTexture.cpp @@ -9,11 +9,11 @@ #include "GrBlurUtils.h" #include "GrCaps.h" -#include "GrDrawContext.h" +#include "GrRenderTargetContext.h" #include "GrStyle.h" -#include "GrTextureParamsAdjuster.h" +#include "GrTextureAdjuster.h" #include "SkDraw.h" -#include "SkGrPriv.h" +#include "SkGr.h" #include "SkMaskFilter.h" #include "effects/GrBicubicEffect.h" #include "effects/GrSimpleTextureEffect.h" @@ -152,10 +152,10 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, const SkMatrix& srcToDstMatrix, const GrClip& clip, const SkPaint& paint) { - // Specifying the texture coords as local coordinates is an attempt to enable more batching - // by not baking anything about the srcRect, dstRect, or viewMatrix, into the texture FP. In - // the future this should be an opaque optimization enabled by the combination of batch/GP and - // FP. + // Specifying the texture coords as local coordinates is an attempt to enable more GrDrawOp + // combining by not baking anything about the srcRect, dstRect, or viewMatrix, into the texture + // FP. In the future this should be an opaque optimization enabled by the combination of + // GrDrawOp/GP and FP. const SkMaskFilter* mf = paint.getMaskFilter(); // The shader expects proper local coords, so we can't replace local coords with texture coords // if the shader will be used. If we have a mask filter we will change the underlying geometry @@ -163,12 +163,12 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, bool canUseTextureCoordsAsLocalCoords = !use_shader(producer->isAlphaOnly(), paint) && !mf; bool doBicubic; - GrTextureParams::FilterMode fm = + GrSamplerParams::FilterMode fm = GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, srcToDstMatrix, &doBicubic); - const GrTextureParams::FilterMode* filterMode = doBicubic ? nullptr : &fm; + const GrSamplerParams::FilterMode* filterMode = doBicubic ? nullptr : &fm; - GrTextureAdjuster::FilterConstraint constraintMode; + GrTextureProducer::FilterConstraint constraintMode; if (SkCanvas::kFast_SrcRectConstraint == constraint) { constraintMode = GrTextureAdjuster::kNo_FilterConstraint; } else { @@ -181,12 +181,12 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, bool coordsAllInsideSrcRect = !paint.isAntiAlias() && !mf; // Check for optimization to drop the src rect constraint when on bilerp. - if (filterMode && GrTextureParams::kBilerp_FilterMode == *filterMode && + if (filterMode && GrSamplerParams::kBilerp_FilterMode == *filterMode && GrTextureAdjuster::kYes_FilterConstraint == constraintMode && coordsAllInsideSrcRect) { SkMatrix combinedMatrix; combinedMatrix.setConcat(viewMatrix, srcToDstMatrix); if (can_ignore_bilerp_constraint(*producer, clippedSrcRect, combinedMatrix, - fDrawContext->isUnifiedMultisampled())) { + fRenderTargetContext->isUnifiedMultisampled())) { constraintMode = GrTextureAdjuster::kNo_FilterConstraint; } } @@ -203,24 +203,25 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, } sk_sp fp(producer->createFragmentProcessor( *textureMatrix, clippedSrcRect, constraintMode, coordsAllInsideSrcRect, filterMode, - fDrawContext->getColorSpace(), fDrawContext->sourceGammaTreatment())); + fRenderTargetContext->getColorSpace())); if (!fp) { return; } GrPaint grPaint; - if (!SkPaintToGrPaintWithTexture(fContext, fDrawContext.get(), paint, viewMatrix, fp, - producer->isAlphaOnly(), &grPaint)) { + if (!SkPaintToGrPaintWithTexture(fContext.get(), fRenderTargetContext.get(), paint, viewMatrix, + fp, producer->isAlphaOnly(), &grPaint)) { return; } - + GrAA aa = GrBoolToAA(paint.isAntiAlias()); if (canUseTextureCoordsAsLocalCoords) { - fDrawContext->fillRectToRect(clip, grPaint, viewMatrix, clippedDstRect, clippedSrcRect); + fRenderTargetContext->fillRectToRect(clip, std::move(grPaint), aa, viewMatrix, + clippedDstRect, clippedSrcRect); return; } if (!mf) { - fDrawContext->drawRect(clip, grPaint, viewMatrix, clippedDstRect); + fRenderTargetContext->drawRect(clip, std::move(grPaint), aa, viewMatrix, clippedDstRect); return; } @@ -230,14 +231,14 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, viewMatrix.mapRectScaleTranslate(&devClippedDstRect, clippedDstRect); SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); - if (mf->directFilterRRectMaskGPU(fContext, - fDrawContext.get(), - &grPaint, - clip, - viewMatrix, - rec, - SkRRect::MakeRect(clippedDstRect), - SkRRect::MakeRect(devClippedDstRect))) { + if (mf->directFilterRRectMaskGPU(fContext.get(), + fRenderTargetContext.get(), + std::move(grPaint), + clip, + viewMatrix, + rec, + SkRRect::MakeRect(clippedDstRect), + SkRRect::MakeRect(devClippedDstRect))) { return; } } @@ -245,7 +246,7 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, SkPath rectPath; rectPath.addRect(clippedDstRect); rectPath.setIsVolatile(true); - GrBlurUtils::drawPathWithMaskFilter(this->context(), fDrawContext.get(), fClip, - rectPath, &grPaint, viewMatrix, mf, GrStyle::SimpleFill(), - true); + GrBlurUtils::drawPathWithMaskFilter(this->context(), fRenderTargetContext.get(), this->clip(), + rectPath, std::move(grPaint), aa, viewMatrix, mf, + GrStyle::SimpleFill(), true); } diff --git a/gfx/skia/skia/src/gpu/SkGr.cpp b/gfx/skia/skia/src/gpu/SkGr.cpp index ee4e40a642e6..84be09e357eb 100644 --- a/gfx/skia/skia/src/gpu/SkGr.cpp +++ b/gfx/skia/skia/src/gpu/SkGr.cpp @@ -5,43 +5,39 @@ * found in the LICENSE file. */ - #include "SkGr.h" -#include "SkGrPriv.h" +#include "GrBitmapTextureMaker.h" #include "GrCaps.h" #include "GrContext.h" -#include "GrDrawContext.h" #include "GrGpuResourcePriv.h" -#include "GrImageIDTextureAdjuster.h" -#include "GrTextureParamsAdjuster.h" -#include "GrTexturePriv.h" +#include "GrRenderTargetContext.h" +#include "GrResourceProvider.h" +#include "GrTextureProxy.h" #include "GrTypes.h" #include "GrXferProcessor.h" -#include "GrYUVProvider.h" +#include "SkAutoMalloc.h" #include "SkBlendModePriv.h" -#include "SkColorFilter.h" -#include "SkConfig8888.h" #include "SkCanvas.h" +#include "SkColorFilter.h" +#include "SkConvertPixels.h" #include "SkData.h" -#include "SkErrorInternals.h" +#include "SkImageInfoPriv.h" +#include "SkMaskFilter.h" #include "SkMessageBus.h" #include "SkMipMap.h" -#include "SkPixelRef.h" #include "SkPM4fPriv.h" +#include "SkPixelRef.h" #include "SkResourceCache.h" #include "SkTemplates.h" -#include "SkYUVPlanesCache.h" #include "effects/GrBicubicEffect.h" #include "effects/GrConstColorProcessor.h" #include "effects/GrDitherEffect.h" #include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrXfermodeFragmentProcessor.h" -#include "effects/GrYUVEffect.h" #ifndef SK_IGNORE_ETC1_SUPPORT -# include "ktx.h" # include "etc1.h" #endif @@ -89,142 +85,14 @@ GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data, *outStartOfDataToUpload = bytes + ETC_PKM_HEADER_SIZE; return kETC1_GrPixelConfig; - } else if (SkKTXFile::is_ktx(bytes, data->size())) { - SkKTXFile ktx(data); - - // Is it actually an ETC1 texture? - if (!ktx.isCompressedFormat(SkTextureCompressor::kETC1_Format)) { - return kUnknown_GrPixelConfig; - } - - // Does the data match the dimensions of the bitmap? If not, - // then we don't know how to scale the image to match it... - if (ktx.width() != expectedW || ktx.height() != expectedH) { - return kUnknown_GrPixelConfig; - } - - *outStartOfDataToUpload = ktx.pixelData(); - return kETC1_GrPixelConfig; } #endif return kUnknown_GrPixelConfig; } ////////////////////////////////////////////////////////////////////////////// - -/** - * Fill out buffer with the compressed format Ganesh expects from a colortable - * based bitmap. [palette (colortable) + indices]. - * - * At the moment Ganesh only supports 8bit version. If Ganesh allowed we others - * we could detect that the colortable.count is <= 16, and then repack the - * indices as nibbles to save RAM, but it would take more time (i.e. a lot - * slower than memcpy), so skipping that for now. - * - * Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big - * as the colortable.count says it is. - */ -static void build_index8_data(void* buffer, const SkPixmap& pixmap) { - SkASSERT(kIndex_8_SkColorType == pixmap.colorType()); - - const SkColorTable* ctable = pixmap.ctable(); - char* dst = (char*)buffer; - - const int count = ctable->count(); - - SkDstPixelInfo dstPI; - dstPI.fColorType = kRGBA_8888_SkColorType; - dstPI.fAlphaType = kPremul_SkAlphaType; - dstPI.fPixels = buffer; - dstPI.fRowBytes = count * sizeof(SkPMColor); - - SkSrcPixelInfo srcPI; - srcPI.fColorType = kN32_SkColorType; - srcPI.fAlphaType = kPremul_SkAlphaType; - srcPI.fPixels = ctable->readColors(); - srcPI.fRowBytes = count * sizeof(SkPMColor); - - srcPI.convertPixelsTo(&dstPI, count, 1); - - // always skip a full 256 number of entries, even if we memcpy'd fewer - dst += 256 * sizeof(GrColor); - - if ((unsigned)pixmap.width() == pixmap.rowBytes()) { - memcpy(dst, pixmap.addr(), pixmap.getSafeSize()); - } else { - // need to trim off the extra bytes per row - size_t width = pixmap.width(); - size_t rowBytes = pixmap.rowBytes(); - const uint8_t* src = pixmap.addr8(); - for (int y = 0; y < pixmap.height(); y++) { - memcpy(dst, src, width); - src += rowBytes; - dst += width; - } - } -} - -/** - * Once we have made SkImages handle all lazy/deferred/generated content, the YUV apis will - * be gone from SkPixelRef, and we can remove this subclass entirely. - */ -class PixelRef_GrYUVProvider : public GrYUVProvider { - SkPixelRef* fPR; - -public: - PixelRef_GrYUVProvider(SkPixelRef* pr) : fPR(pr) {} - - uint32_t onGetID() override { return fPR->getGenerationID(); } - bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override { - return fPR->queryYUV8(sizeInfo, colorSpace); - } - bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override { - return fPR->getYUV8Planes(sizeInfo, planes); - } -}; - -static sk_sp create_texture_from_yuv(GrContext* ctx, const SkBitmap& bm, - const GrSurfaceDesc& desc) { - // Subsets are not supported, the whole pixelRef is loaded when using YUV decoding - SkPixelRef* pixelRef = bm.pixelRef(); - if ((nullptr == pixelRef) || - (pixelRef->info().width() != bm.info().width()) || - (pixelRef->info().height() != bm.info().height())) { - return nullptr; - } - - PixelRef_GrYUVProvider provider(pixelRef); - - return provider.refAsTexture(ctx, desc, !bm.isVolatile()); -} - -static GrTexture* load_etc1_texture(GrContext* ctx, const SkBitmap &bm, GrSurfaceDesc desc) { - sk_sp data(bm.pixelRef()->refEncodedData()); - if (!data) { - return nullptr; - } - - const void* startOfTexData; - desc.fConfig = GrIsCompressedTextureDataSupported(ctx, data.get(), bm.width(), bm.height(), - &startOfTexData); - if (kUnknown_GrPixelConfig == desc.fConfig) { - return nullptr; - } - - return ctx->textureProvider()->createTexture(desc, SkBudgeted::kYes, startOfTexData, 0); -} - -GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bitmap) { - GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap.info(), *ctx->caps()); - if (GrTexture *texture = load_etc1_texture(ctx, bitmap, desc)) { - return texture; - } - - sk_sp texture(create_texture_from_yuv(ctx, bitmap, desc)); - if (texture) { - return texture.release(); - } - +sk_sp GrUploadBitmapToTextureProxy(GrResourceProvider* resourceProvider, + const SkBitmap& bitmap) { SkAutoLockPixels alp(bitmap); if (!bitmap.readyToDraw()) { return nullptr; @@ -233,22 +101,22 @@ GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bitmap) { if (!bitmap.peekPixels(&pixmap)) { return nullptr; } - return GrUploadPixmapToTexture(ctx, pixmap, SkBudgeted::kYes); + return GrUploadPixmapToTextureProxy(resourceProvider, pixmap, SkBudgeted::kYes); } -GrTexture* GrUploadPixmapToTexture(GrContext* ctx, const SkPixmap& pixmap, SkBudgeted budgeted) { +static const SkPixmap* compute_desc(const GrCaps& caps, const SkPixmap& pixmap, + GrSurfaceDesc* desc, + SkBitmap* tmpBitmap, SkPixmap* tmpPixmap) { const SkPixmap* pmap = &pixmap; - SkPixmap tmpPixmap; - SkBitmap tmpBitmap; - const GrCaps* caps = ctx->caps(); - GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(pixmap.info(), *caps); + *desc = GrImageInfoToSurfaceDesc(pixmap.info(), caps); - if (caps->srgbSupport() && - pixmap.info().colorSpace() && pixmap.info().colorSpace()->gammaCloseToSRGB() && - !(GrPixelConfigIsSRGB(desc.fConfig) || - kRGBA_half_GrPixelConfig == desc.fConfig || - kRGBA_float_GrPixelConfig == desc.fConfig)) { + // TODO: We're checking for srgbSupport, but we can then end up picking sBGRA as our pixel + // config (which may not be supported). We need better fallback management here. + SkColorSpace* colorSpace = pixmap.colorSpace(); + + if (caps.srgbSupport() && + colorSpace && colorSpace->gammaCloseToSRGB() && !GrPixelConfigIsSRGB(desc->fConfig)) { // We were supplied an sRGB-like color space, but we don't have a suitable pixel config. // Convert to 8888 sRGB so we can handle the data correctly. The raster backend doesn't // handle sRGB Index8 -> sRGB 8888 correctly (yet), so lie about both the source and @@ -259,69 +127,62 @@ GrTexture* GrUploadPixmapToTexture(GrContext* ctx, const SkPixmap& pixmap, SkBud SkImageInfo dstInfo = SkImageInfo::Make(pixmap.width(), pixmap.height(), kN32_SkColorType, kPremul_SkAlphaType, - sk_ref_sp(pixmap.info().colorSpace())); + pixmap.info().refColorSpace()); - tmpBitmap.allocPixels(dstInfo); + tmpBitmap->allocPixels(dstInfo); SkImageInfo linDstInfo = SkImageInfo::MakeN32Premul(pixmap.width(), pixmap.height()); - if (!linSrcPixmap.readPixels(linDstInfo, tmpBitmap.getPixels(), tmpBitmap.rowBytes())) { + if (!linSrcPixmap.readPixels(linDstInfo, tmpBitmap->getPixels(), tmpBitmap->rowBytes())) { return nullptr; } - if (!tmpBitmap.peekPixels(&tmpPixmap)) { + if (!tmpBitmap->peekPixels(tmpPixmap)) { return nullptr; } - pmap = &tmpPixmap; + pmap = tmpPixmap; // must rebuild desc, since we've forced the info to be N32 - desc = GrImageInfoToSurfaceDesc(pmap->info(), *caps); - } else if (kGray_8_SkColorType == pixmap.colorType()) { - // We don't have Gray8 support as a pixel config, so expand to 8888 - - // We should have converted sRGB Gray8 above (if we have sRGB support): - SkASSERT(!caps->srgbSupport() || !pixmap.info().colorSpace() || - !pixmap.info().colorSpace()->gammaCloseToSRGB()); - - SkImageInfo info = SkImageInfo::MakeN32(pixmap.width(), pixmap.height(), - kOpaque_SkAlphaType); - tmpBitmap.allocPixels(info); - if (!pixmap.readPixels(info, tmpBitmap.getPixels(), tmpBitmap.rowBytes())) { - return nullptr; - } - if (!tmpBitmap.peekPixels(&tmpPixmap)) { - return nullptr; - } - pmap = &tmpPixmap; - // must rebuild desc, since we've forced the info to be N32 - desc = GrImageInfoToSurfaceDesc(pmap->info(), *caps); + *desc = GrImageInfoToSurfaceDesc(pmap->info(), caps); } else if (kIndex_8_SkColorType == pixmap.colorType()) { - if (caps->isConfigTexturable(kIndex_8_GrPixelConfig)) { - size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig, - pixmap.width(), pixmap.height()); - SkAutoMalloc storage(imageSize); - build_index8_data(storage.get(), pixmap); - - // our compressed data will be trimmed, so pass width() for its - // "rowBytes", since they are the same now. - return ctx->textureProvider()->createTexture(desc, budgeted, storage.get(), - pixmap.width()); - } else { - SkImageInfo info = SkImageInfo::MakeN32Premul(pixmap.width(), pixmap.height()); - tmpBitmap.allocPixels(info); - if (!pixmap.readPixels(info, tmpBitmap.getPixels(), tmpBitmap.rowBytes())) { - return nullptr; - } - if (!tmpBitmap.peekPixels(&tmpPixmap)) { - return nullptr; - } - pmap = &tmpPixmap; - // must rebuild desc, since we've forced the info to be N32 - desc = GrImageInfoToSurfaceDesc(pmap->info(), *caps); + SkImageInfo info = SkImageInfo::MakeN32Premul(pixmap.width(), pixmap.height()); + tmpBitmap->allocPixels(info); + if (!pixmap.readPixels(info, tmpBitmap->getPixels(), tmpBitmap->rowBytes())) { + return nullptr; } + if (!tmpBitmap->peekPixels(tmpPixmap)) { + return nullptr; + } + pmap = tmpPixmap; + // must rebuild desc, since we've forced the info to be N32 + *desc = GrImageInfoToSurfaceDesc(pmap->info(), caps); } - return ctx->textureProvider()->createTexture(desc, budgeted, pmap->addr(), - pmap->rowBytes()); + return pmap; } +sk_sp GrUploadPixmapToTextureProxyNoCheck(GrResourceProvider* resourceProvider, + const SkPixmap& pixmap, + SkBudgeted budgeted) { + SkBitmap tmpBitmap; + SkPixmap tmpPixmap; + GrSurfaceDesc desc; + + if (const SkPixmap* pmap = compute_desc(*resourceProvider->caps(), pixmap, &desc, + &tmpBitmap, &tmpPixmap)) { + return GrSurfaceProxy::MakeDeferred(resourceProvider, desc, + budgeted, pmap->addr(), pmap->rowBytes()); + } + + return nullptr; +} + +sk_sp GrUploadPixmapToTextureProxy(GrResourceProvider* resourceProvider, + const SkPixmap& pixmap, + SkBudgeted budgeted) { + if (!SkImageInfoIsValid(pixmap.info())) { + return nullptr; + } + + return GrUploadPixmapToTextureProxyNoCheck(resourceProvider, pixmap, budgeted); +} //////////////////////////////////////////////////////////////////////////////// @@ -338,35 +199,18 @@ void GrInstallBitmapUniqueKeyInvalidator(const GrUniqueKey& key, SkPixelRef* pix pixelRef->addGenIDChangeListener(new Invalidator(key)); } -GrTexture* GrGenerateMipMapsAndUploadToTexture(GrContext* ctx, const SkBitmap& bitmap, - SkSourceGammaTreatment gammaTreatment) -{ +sk_sp GrGenerateMipMapsAndUploadToTextureProxy(GrContext* ctx, + const SkBitmap& bitmap, + SkColorSpace* dstColorSpace) { + SkDestinationSurfaceColorMode colorMode = dstColorSpace + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; + + if (!SkImageInfoIsValid(bitmap.info())) { + return nullptr; + } + GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap.info(), *ctx->caps()); - if (kIndex_8_SkColorType != bitmap.colorType() && !bitmap.readyToDraw()) { - GrTexture* texture = load_etc1_texture(ctx, bitmap, desc); - if (texture) { - return texture; - } - } - - sk_sp texture(create_texture_from_yuv(ctx, bitmap, desc)); - if (texture) { - return texture.release(); - } - - // We don't support Gray8 directly in the GL backend, so fail-over to GrUploadBitmapToTexture. - // That will transform the Gray8 to 8888, then use the driver/GPU to build mipmaps. If we build - // the mips on the CPU here, they'll all be Gray8, which isn't useful. (They get treated as A8). - // TODO: A better option might be to transform the initial bitmap here to 8888, then run the - // CPU mip-mapper on that data before uploading. This is much less code for a rare case though: - if (kGray_8_SkColorType == bitmap.colorType()) { - return nullptr; - } - - SkASSERT(sizeof(int) <= sizeof(uint32_t)); - if (bitmap.width() < 0 || bitmap.height() < 0) { - return nullptr; - } SkAutoPixmapUnlock srcUnlocker; if (!bitmap.requestLock(&srcUnlocker)) { @@ -378,7 +222,7 @@ GrTexture* GrGenerateMipMapsAndUploadToTexture(GrContext* ctx, const SkBitmap& b sk_throw(); } - SkAutoTDelete mipmaps(SkMipMap::Build(pixmap, gammaTreatment, nullptr)); + std::unique_ptr mipmaps(SkMipMap::Build(pixmap, colorMode, nullptr)); if (!mipmaps) { return nullptr; } @@ -391,7 +235,7 @@ GrTexture* GrGenerateMipMapsAndUploadToTexture(GrContext* ctx, const SkBitmap& b const bool isMipMapped = mipLevelCount > 1; desc.fIsMipMapped = isMipMapped; - SkAutoTDeleteArray texels(new GrMipLevel[mipLevelCount]); + std::unique_ptr texels(new GrMipLevel[mipLevelCount]); texels[0].fPixels = pixmap.addr(); texels[0].fRowBytes = pixmap.rowBytes(); @@ -403,52 +247,93 @@ GrTexture* GrGenerateMipMapsAndUploadToTexture(GrContext* ctx, const SkBitmap& b texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes(); } - { - GrTexture* texture = ctx->textureProvider()->createMipMappedTexture(desc, - SkBudgeted::kYes, - texels.get(), - mipLevelCount); - if (texture) { - texture->texturePriv().setGammaTreatment(gammaTreatment); - } - return texture; + return ctx->resourceProvider()->createMipMappedTexture(desc, + SkBudgeted::kYes, + texels.get(), + mipLevelCount, + 0, colorMode); +} + +sk_sp GrUploadMipMapToTextureProxy(GrContext* ctx, const SkImageInfo& info, + const GrMipLevel* texels, + int mipLevelCount, + SkDestinationSurfaceColorMode colorMode) { + if (!SkImageInfoIsValid(info)) { + return nullptr; } -} -GrTexture* GrUploadMipMapToTexture(GrContext* ctx, const SkImageInfo& info, - const GrMipLevel* texels, int mipLevelCount) { const GrCaps* caps = ctx->caps(); - return ctx->textureProvider()->createMipMappedTexture(GrImageInfoToSurfaceDesc(info, *caps), - SkBudgeted::kYes, texels, - mipLevelCount); + return ctx->resourceProvider()->createMipMappedTexture(GrImageInfoToSurfaceDesc(info, *caps), + SkBudgeted::kYes, texels, + mipLevelCount, 0, colorMode); } -GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap, - const GrTextureParams& params, - SkSourceGammaTreatment gammaTreatment) { - return GrBitmapTextureMaker(ctx, bitmap).refTextureForParams(params, gammaTreatment); +sk_sp GrRefCachedBitmapTextureProxy(GrContext* ctx, + const SkBitmap& bitmap, + const GrSamplerParams& params, + SkScalar scaleAdjust[2]) { + // Caller doesn't care about the texture's color space (they can always get it from the bitmap) + return GrBitmapTextureMaker(ctx, bitmap).refTextureProxyForParams(params, nullptr, + nullptr, scaleAdjust); } -sk_sp GrMakeCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap, - const GrTextureParams& params, - SkSourceGammaTreatment gammaTreatment) { - GrTexture* tex = GrBitmapTextureMaker(ctx, bitmap).refTextureForParams(params, gammaTreatment); - return sk_sp(tex); +sk_sp GrMakeCachedBitmapProxy(GrResourceProvider* resourceProvider, + const SkBitmap& bitmap) { + GrUniqueKey originalKey; + + if (!bitmap.isVolatile()) { + SkIPoint origin = bitmap.pixelRefOrigin(); + SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bitmap.width(), bitmap.height()); + GrMakeKeyFromImageID(&originalKey, bitmap.pixelRef()->getGenerationID(), subset); + } + + sk_sp proxy; + + if (originalKey.isValid()) { + proxy = resourceProvider->findProxyByUniqueKey(originalKey); + } + if (!proxy) { + proxy = GrUploadBitmapToTextureProxy(resourceProvider, bitmap); + if (proxy && originalKey.isValid()) { + resourceProvider->assignUniqueKeyToProxy(originalKey, proxy.get()); + // MDB TODO (caching): this has to play nice with the GrSurfaceProxy's caching + GrInstallBitmapUniqueKeyInvalidator(originalKey, bitmap.pixelRef()); + } + } + + return proxy; } /////////////////////////////////////////////////////////////////////////////// -GrColor4f SkColorToPremulGrColor4f(SkColor c, bool gammaCorrect, GrColorSpaceXform* gamutXform) { +GrColor4f SkColorToPremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace) { // We want to premultiply after linearizing, so this is easy: - return SkColorToUnpremulGrColor4f(c, gammaCorrect, gamutXform).premul(); + return SkColorToUnpremulGrColor4f(c, dstColorSpace).premul(); } -GrColor4f SkColorToUnpremulGrColor4f(SkColor c, bool gammaCorrect, GrColorSpaceXform* gamutXform) { +GrColor4f SkColorToUnpremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace) { + if (dstColorSpace) { + auto srgbColorSpace = SkColorSpace::MakeSRGB(); + auto gamutXform = GrColorSpaceXform::Make(srgbColorSpace.get(), dstColorSpace); + return SkColorToUnpremulGrColor4f(c, dstColorSpace, gamutXform.get()); + } else { + return SkColorToUnpremulGrColor4f(c, nullptr, nullptr); + } +} + +GrColor4f SkColorToPremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace, + GrColorSpaceXform* gamutXform) { + // We want to premultiply after linearizing, so this is easy: + return SkColorToUnpremulGrColor4f(c, dstColorSpace, gamutXform).premul(); +} + +GrColor4f SkColorToUnpremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace, + GrColorSpaceXform* gamutXform) { // You can't be color-space aware in legacy mode - SkASSERT(gammaCorrect || !gamutXform); + SkASSERT(dstColorSpace || !gamutXform); GrColor4f color; - if (gammaCorrect) { + if (dstColorSpace) { // SkColor4f::FromColor does sRGB -> Linear color = GrColor4f::FromSkColor4f(SkColor4f::FromColor(c)); } else { @@ -465,13 +350,11 @@ GrColor4f SkColorToUnpremulGrColor4f(SkColor c, bool gammaCorrect, GrColorSpaceX /////////////////////////////////////////////////////////////////////////////// -// alphatype is ignore for now, but if GrPixelConfig is expanded to encompass -// alpha info, that will be considered. -GrPixelConfig SkImageInfo2GrPixelConfig(SkColorType ct, SkAlphaType, const SkColorSpace* cs, - const GrCaps& caps) { +GrPixelConfig SkImageInfo2GrPixelConfig(const SkImageInfo& info, const GrCaps& caps) { // We intentionally ignore profile type for non-8888 formats. Anything we can't support // in hardware will be expanded to sRGB 8888 in GrUploadPixmapToTexture. - switch (ct) { + SkColorSpace* cs = info.colorSpace(); + switch (info.colorType()) { case kUnknown_SkColorType: return kUnknown_GrPixelConfig; case kAlpha_8_SkColorType: @@ -487,9 +370,9 @@ GrPixelConfig SkImageInfo2GrPixelConfig(SkColorType ct, SkAlphaType, const SkCol return (caps.srgbSupport() && cs && cs->gammaCloseToSRGB()) ? kSBGRA_8888_GrPixelConfig : kBGRA_8888_GrPixelConfig; case kIndex_8_SkColorType: - return kIndex_8_GrPixelConfig; + return kSkia8888_GrPixelConfig; case kGray_8_SkColorType: - return kAlpha_8_GrPixelConfig; // TODO: gray8 support on gpu + return kGray_8_GrPixelConfig; case kRGBA_F16_SkColorType: return kRGBA_half_GrPixelConfig; } @@ -503,8 +386,8 @@ bool GrPixelConfigToColorType(GrPixelConfig config, SkColorType* ctOut) { case kAlpha_8_GrPixelConfig: ct = kAlpha_8_SkColorType; break; - case kIndex_8_GrPixelConfig: - ct = kIndex_8_SkColorType; + case kGray_8_GrPixelConfig: + ct = kGray_8_SkColorType; break; case kRGB_565_GrPixelConfig: ct = kRGB_565_SkColorType; @@ -551,28 +434,27 @@ GrPixelConfig GrRenderableConfigForColorSpace(const SkColorSpace* colorSpace) { //////////////////////////////////////////////////////////////////////////////////////////////// -static inline bool blend_requires_shader(const SkXfermode::Mode mode, bool primitiveIsSrc) { +static inline bool blend_requires_shader(const SkBlendMode mode, bool primitiveIsSrc) { if (primitiveIsSrc) { - return SkXfermode::kSrc_Mode != mode; + return SkBlendMode::kSrc != mode; } else { - return SkXfermode::kDst_Mode != mode; + return SkBlendMode::kDst != mode; } } static inline bool skpaint_to_grpaint_impl(GrContext* context, - GrDrawContext* dc, + GrRenderTargetContext* rtc, const SkPaint& skPaint, const SkMatrix& viewM, sk_sp* shaderProcessor, - SkXfermode::Mode* primColorMode, + SkBlendMode* primColorMode, bool primitiveIsSrc, GrPaint* grPaint) { - grPaint->setAntiAlias(skPaint.isAntiAlias()); - grPaint->setAllowSRGBInputs(dc->isGammaCorrect()); + grPaint->setAllowSRGBInputs(rtc->isGammaCorrect()); // Convert SkPaint color to 4f format, including optional linearizing and gamut conversion. - GrColor4f origColor = SkColorToUnpremulGrColor4f(skPaint.getColor(), dc->isGammaCorrect(), - dc->getColorXformFromSRGB()); + GrColor4f origColor = SkColorToUnpremulGrColor4f(skPaint.getColor(), rtc->getColorSpace(), + rtc->getColorXformFromSRGB()); // Setup the initial color considering the shader, the SkPaint color, and the presence or not // of per-vertex colors. @@ -583,8 +465,7 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context, } else if (const SkShader* shader = skPaint.getShader()) { shaderFP = shader->asFragmentProcessor(SkShader::AsFPArgs(context, &viewM, nullptr, skPaint.getFilterQuality(), - dc->getColorSpace(), - dc->sourceGammaTreatment())); + rtc->getColorSpace())); if (!shaderFP) { return false; } @@ -621,8 +502,11 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context, // We can ignore origColor here - alpha is unchanged by gamma GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != paintAlpha) { + // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all + // color channels. It's value should be treated as the same in ANY color space. grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make( - paintAlpha, GrConstColorProcessor::kModulateRGBA_InputMode)); + GrColor4f::FromGrColor(paintAlpha), + GrConstColorProcessor::kModulateRGBA_InputMode)); } } else { // The shader's FP sees the paint unpremul color @@ -633,10 +517,9 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context, if (primColorMode) { // There is a blend between the primitive color and the paint color. The blend considers // the opaque paint color. The paint's alpha is applied to the post-blended color. - // SRGBTODO: Preserve 4f on this code path sk_sp processor( - GrConstColorProcessor::Make(origColor.opaque().toGrColor(), - GrConstColorProcessor::kIgnore_InputMode)); + GrConstColorProcessor::Make(origColor.opaque(), + GrConstColorProcessor::kIgnore_InputMode)); if (primitiveIsSrc) { processor = GrXfermodeFragmentProcessor::MakeFromDstProcessor(std::move(processor), *primColorMode); @@ -653,8 +536,11 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context, // We can ignore origColor here - alpha is unchanged by gamma GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != paintAlpha) { + // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all + // color channels. It's value should be treated as the same in ANY color space. grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make( - paintAlpha, GrConstColorProcessor::kModulateRGBA_InputMode)); + GrColor4f::FromGrColor(paintAlpha), + GrConstColorProcessor::kModulateRGBA_InputMode)); } } else { // No shader, no primitive color. @@ -666,10 +552,18 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context, SkColorFilter* colorFilter = skPaint.getColorFilter(); if (colorFilter) { if (applyColorFilterToPaintColor) { - grPaint->setColor4f(GrColor4f::FromSkColor4f( - colorFilter->filterColor4f(origColor.toSkColor4f())).premul()); + // If we're in legacy mode, we *must* avoid using the 4f version of the color filter, + // because that will combine with the linearized version of the stored color. + if (rtc->isGammaCorrect()) { + grPaint->setColor4f(GrColor4f::FromSkColor4f( + colorFilter->filterColor4f(origColor.toSkColor4f())).premul()); + } else { + grPaint->setColor4f(SkColorToPremulGrColor4f( + colorFilter->filterColor(skPaint.getColor()), nullptr, nullptr)); + } } else { - sk_sp cfFP(colorFilter->asFragmentProcessor(context)); + sk_sp cfFP(colorFilter->asFragmentProcessor(context, + rtc->getColorSpace())); if (cfFP) { grPaint->addColorFragmentProcessor(std::move(cfFP)); } else { @@ -678,6 +572,14 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context, } } + SkMaskFilter* maskFilter = skPaint.getMaskFilter(); + if (maskFilter) { + GrFragmentProcessor* mfFP; + if (maskFilter->asFragmentProcessor(&mfFP, nullptr, viewM)) { + grPaint->addCoverageFragmentProcessor(sk_sp(mfFP)); + } + } + // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on // the GrPaint to also be null (also kSrcOver). SkASSERT(!grPaint->getXPFactory()); @@ -686,58 +588,58 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context, } #ifndef SK_IGNORE_GPU_DITHER - if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0 && !dc->isGammaCorrect()) { + if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0 && !rtc->isGammaCorrect()) { grPaint->addColorFragmentProcessor(GrDitherEffect::Make()); } #endif return true; } -bool SkPaintToGrPaint(GrContext* context, GrDrawContext* dc, const SkPaint& skPaint, +bool SkPaintToGrPaint(GrContext* context, GrRenderTargetContext* rtc, const SkPaint& skPaint, const SkMatrix& viewM, GrPaint* grPaint) { - return skpaint_to_grpaint_impl(context, dc, skPaint, viewM, nullptr, nullptr, false, grPaint); + return skpaint_to_grpaint_impl(context, rtc, skPaint, viewM, nullptr, nullptr, false, grPaint); } /** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. */ bool SkPaintToGrPaintReplaceShader(GrContext* context, - GrDrawContext* dc, + GrRenderTargetContext* rtc, const SkPaint& skPaint, sk_sp shaderFP, GrPaint* grPaint) { if (!shaderFP) { return false; } - return skpaint_to_grpaint_impl(context, dc, skPaint, SkMatrix::I(), &shaderFP, nullptr, false, + return skpaint_to_grpaint_impl(context, rtc, skPaint, SkMatrix::I(), &shaderFP, nullptr, false, grPaint); } /** Ignores the SkShader (if any) on skPaint. */ bool SkPaintToGrPaintNoShader(GrContext* context, - GrDrawContext* dc, + GrRenderTargetContext* rtc, const SkPaint& skPaint, GrPaint* grPaint) { // Use a ptr to a nullptr to to indicate that the SkShader is ignored and not replaced. static sk_sp kNullShaderFP(nullptr); static sk_sp* kIgnoreShader = &kNullShaderFP; - return skpaint_to_grpaint_impl(context, dc, skPaint, SkMatrix::I(), kIgnoreShader, nullptr, + return skpaint_to_grpaint_impl(context, rtc, skPaint, SkMatrix::I(), kIgnoreShader, nullptr, false, grPaint); } /** Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must -be setup as a vertex attribute using the specified SkXfermode::Mode. */ +be setup as a vertex attribute using the specified SkBlendMode. */ bool SkPaintToGrPaintWithXfermode(GrContext* context, - GrDrawContext* dc, + GrRenderTargetContext* rtc, const SkPaint& skPaint, const SkMatrix& viewM, - SkXfermode::Mode primColorMode, + SkBlendMode primColorMode, bool primitiveIsSrc, GrPaint* grPaint) { - return skpaint_to_grpaint_impl(context, dc, skPaint, viewM, nullptr, &primColorMode, + return skpaint_to_grpaint_impl(context, rtc, skPaint, viewM, nullptr, &primColorMode, primitiveIsSrc, grPaint); } bool SkPaintToGrPaintWithTexture(GrContext* context, - GrDrawContext* dc, + GrRenderTargetContext* rtc, const SkPaint& paint, const SkMatrix& viewM, sk_sp fp, @@ -750,47 +652,46 @@ bool SkPaintToGrPaintWithTexture(GrContext* context, &viewM, nullptr, paint.getFilterQuality(), - dc->getColorSpace(), - dc->sourceGammaTreatment())); + rtc->getColorSpace())); if (!shaderFP) { return false; } sk_sp fpSeries[] = { std::move(shaderFP), std::move(fp) }; shaderFP = GrFragmentProcessor::RunInSeries(fpSeries, 2); } else { - shaderFP = GrFragmentProcessor::MulOutputByInputUnpremulColor(fp); + shaderFP = GrFragmentProcessor::MakeInputPremulAndMulByOutput(fp); } } else { shaderFP = GrFragmentProcessor::MulOutputByInputAlpha(fp); } - return SkPaintToGrPaintReplaceShader(context, dc, paint, std::move(shaderFP), grPaint); + return SkPaintToGrPaintReplaceShader(context, rtc, paint, std::move(shaderFP), grPaint); } //////////////////////////////////////////////////////////////////////////////////////////////// -GrTextureParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality, +GrSamplerParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality, const SkMatrix& viewM, const SkMatrix& localM, bool* doBicubic) { *doBicubic = false; - GrTextureParams::FilterMode textureFilterMode; + GrSamplerParams::FilterMode textureFilterMode; switch (paintFilterQuality) { case kNone_SkFilterQuality: - textureFilterMode = GrTextureParams::kNone_FilterMode; + textureFilterMode = GrSamplerParams::kNone_FilterMode; break; case kLow_SkFilterQuality: - textureFilterMode = GrTextureParams::kBilerp_FilterMode; + textureFilterMode = GrSamplerParams::kBilerp_FilterMode; break; case kMedium_SkFilterQuality: { SkMatrix matrix; matrix.setConcat(viewM, localM); if (matrix.getMinScale() < SK_Scalar1) { - textureFilterMode = GrTextureParams::kMipMap_FilterMode; + textureFilterMode = GrSamplerParams::kMipMap_FilterMode; } else { // Don't trigger MIP level generation unnecessarily. - textureFilterMode = GrTextureParams::kBilerp_FilterMode; + textureFilterMode = GrSamplerParams::kBilerp_FilterMode; } break; } @@ -801,11 +702,8 @@ GrTextureParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality pain break; } default: - SkErrorInternals::SetError( kInvalidPaint_SkError, - "Sorry, I don't understand the filtering " - "mode you asked for. Falling back to " - "MIPMaps."); - textureFilterMode = GrTextureParams::kMipMap_FilterMode; + // Should be unreachable. If not, fall back to mipmaps. + textureFilterMode = GrSamplerParams::kMipMap_FilterMode; break; } diff --git a/gfx/skia/skia/src/gpu/SkGr.h b/gfx/skia/skia/src/gpu/SkGr.h new file mode 100644 index 000000000000..144a47785b58 --- /dev/null +++ b/gfx/skia/skia/src/gpu/SkGr.h @@ -0,0 +1,291 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkGr_DEFINED +#define SkGr_DEFINED + +#include "GrBlend.h" +#include "GrColor.h" +#include "GrSamplerParams.h" +#include "GrTypes.h" +#include "SkCanvas.h" +#include "SkColor.h" +#include "SkColorPriv.h" +#include "SkFilterQuality.h" +#include "SkImageInfo.h" +#include "SkMatrix.h" +#include "SkPM4f.h" +#include "SkVertices.h" +#include "SkXfermodePriv.h" + +class GrCaps; +class GrColorSpaceXform; +class GrContext; +class GrRenderTargetContext; +class GrFragmentProcessor; +class GrPaint; +class GrResourceProvider; +class GrTextureProxy; +class GrUniqueKey; +class SkBitmap; +class SkData; +class SkPaint; +class SkPixelRef; +class SkPixmap; +struct SkIRect; + +//////////////////////////////////////////////////////////////////////////////// +// Color type conversions + +static inline GrColor SkColorToPremulGrColor(SkColor c) { + SkPMColor pm = SkPreMultiplyColor(c); + unsigned r = SkGetPackedR32(pm); + unsigned g = SkGetPackedG32(pm); + unsigned b = SkGetPackedB32(pm); + unsigned a = SkGetPackedA32(pm); + return GrColorPackRGBA(r, g, b, a); +} + +static inline GrColor SkColorToUnpremulGrColor(SkColor c) { + unsigned r = SkColorGetR(c); + unsigned g = SkColorGetG(c); + unsigned b = SkColorGetB(c); + unsigned a = SkColorGetA(c); + return GrColorPackRGBA(r, g, b, a); +} + +/** Transform an SkColor (sRGB bytes) to GrColor4f for the specified color space. */ +GrColor4f SkColorToPremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace); +GrColor4f SkColorToUnpremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace); + +/** + * As above, but with a caller-supplied color space xform object. Faster for the cases where we + * have that cached. + */ +GrColor4f SkColorToPremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace, + GrColorSpaceXform* gamutXform); +GrColor4f SkColorToUnpremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace, + GrColorSpaceXform* gamutXform); + +/** Replicates the SkColor's alpha to all four channels of the GrColor. */ +static inline GrColor SkColorAlphaToGrColor(SkColor c) { + U8CPU a = SkColorGetA(c); + return GrColorPackRGBA(a, a, a, a); +} + +////////////////////////////////////////////////////////////////////////////// + +static inline SkPM4f GrColor4fToSkPM4f(const GrColor4f& c) { + SkPM4f pm4f; + pm4f.fVec[SkPM4f::R] = c.fRGBA[0]; + pm4f.fVec[SkPM4f::G] = c.fRGBA[1]; + pm4f.fVec[SkPM4f::B] = c.fRGBA[2]; + pm4f.fVec[SkPM4f::A] = c.fRGBA[3]; + return pm4f; +} + +static inline GrColor4f SkPM4fToGrColor4f(const SkPM4f& c) { + return GrColor4f{c.r(), c.g(), c.b(), c.a()}; +} + +//////////////////////////////////////////////////////////////////////////////// +// Paint conversion + +/** Converts an SkPaint to a GrPaint for a given GrContext. The matrix is required in order + to convert the SkShader (if any) on the SkPaint. The primitive itself has no color. */ +bool SkPaintToGrPaint(GrContext*, + GrRenderTargetContext*, + const SkPaint& skPaint, + const SkMatrix& viewM, + GrPaint* grPaint); + +/** Same as above but ignores the SkShader (if any) on skPaint. */ +bool SkPaintToGrPaintNoShader(GrContext* context, + GrRenderTargetContext* rtc, + const SkPaint& skPaint, + GrPaint* grPaint); + +/** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. The processor + should expect an unpremul input color and produce a premultiplied output color. There is + no primitive color. */ +bool SkPaintToGrPaintReplaceShader(GrContext*, + GrRenderTargetContext*, + const SkPaint& skPaint, + sk_sp shaderFP, + GrPaint* grPaint); + +/** Blends the SkPaint's shader (or color if no shader) with the color which specified via a + GrOp's GrPrimitiveProcesssor. Currently there is a bool param to indicate whether the + primitive color is the dst or src color to the blend in order to work around differences between + drawVertices and drawAtlas. */ +bool SkPaintToGrPaintWithXfermode(GrContext* context, + GrRenderTargetContext* rtc, + const SkPaint& skPaint, + const SkMatrix& viewM, + SkBlendMode primColorMode, + bool primitiveIsSrc, + GrPaint* grPaint); + +/** This is used when there is a primitive color, but the shader should be ignored. Currently, + the expectation is that the primitive color will be premultiplied, though it really should be + unpremultiplied so that interpolation is done in unpremul space. The paint's alpha will be + applied to the primitive color after interpolation. */ +inline bool SkPaintToGrPaintWithPrimitiveColor(GrContext* context, GrRenderTargetContext* rtc, + const SkPaint& skPaint, GrPaint* grPaint) { + return SkPaintToGrPaintWithXfermode(context, rtc, skPaint, SkMatrix::I(), SkBlendMode::kDst, + false, grPaint); +} + +/** This is used when there may or may not be a shader, and the caller wants to plugin a texture + lookup. If there is a shader, then its output will only be used if the texture is alpha8. */ +bool SkPaintToGrPaintWithTexture(GrContext* context, + GrRenderTargetContext* rtc, + const SkPaint& paint, + const SkMatrix& viewM, + sk_sp fp, + bool textureIsAlphaOnly, + GrPaint* grPaint); + +//////////////////////////////////////////////////////////////////////////////// +// Misc Sk to Gr type conversions + +GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo&, const GrCaps&); +GrPixelConfig SkImageInfo2GrPixelConfig(const SkImageInfo& info, const GrCaps& caps); + +bool GrPixelConfigToColorType(GrPixelConfig, SkColorType*); + +GrSamplerParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality, + const SkMatrix& viewM, + const SkMatrix& localM, + bool* doBicubic); + +////////////////////////////////////////////////////////////////////////////// + +static inline GrPrimitiveType SkVertexModeToGrPrimitiveType(SkVertices::VertexMode mode) { + switch (mode) { + case SkVertices::kTriangles_VertexMode: + return kTriangles_GrPrimitiveType; + case SkVertices::kTriangleStrip_VertexMode: + return kTriangleStrip_GrPrimitiveType; + case SkVertices::kTriangleFan_VertexMode: + return kTriangleFan_GrPrimitiveType; + } + SkFAIL("Invalid mode"); + return kPoints_GrPrimitiveType; +} + +////////////////////////////////////////////////////////////////////////////// + +GR_STATIC_ASSERT((int)kZero_GrBlendCoeff == (int)SkXfermode::kZero_Coeff); +GR_STATIC_ASSERT((int)kOne_GrBlendCoeff == (int)SkXfermode::kOne_Coeff); +GR_STATIC_ASSERT((int)kSC_GrBlendCoeff == (int)SkXfermode::kSC_Coeff); +GR_STATIC_ASSERT((int)kISC_GrBlendCoeff == (int)SkXfermode::kISC_Coeff); +GR_STATIC_ASSERT((int)kDC_GrBlendCoeff == (int)SkXfermode::kDC_Coeff); +GR_STATIC_ASSERT((int)kIDC_GrBlendCoeff == (int)SkXfermode::kIDC_Coeff); +GR_STATIC_ASSERT((int)kSA_GrBlendCoeff == (int)SkXfermode::kSA_Coeff); +GR_STATIC_ASSERT((int)kISA_GrBlendCoeff == (int)SkXfermode::kISA_Coeff); +GR_STATIC_ASSERT((int)kDA_GrBlendCoeff == (int)SkXfermode::kDA_Coeff); +GR_STATIC_ASSERT((int)kIDA_GrBlendCoeff == (int)SkXfermode::kIDA_Coeff); +GR_STATIC_ASSERT(SkXfermode::kCoeffCount == 10); + +#define SkXfermodeCoeffToGrBlendCoeff(X) ((GrBlendCoeff)(X)) + +//////////////////////////////////////////////////////////////////////////////// +// Texture management + +/** Returns a texture representing the bitmap that is compatible with the GrSamplerParams. The + * texture is inserted into the cache (unless the bitmap is marked volatile) and can be + * retrieved again via this function. + * The 'scaleAdjust' in/out parameter will be updated to hold any rescaling that needs to be + * performed on the absolute texture coordinates (e.g., if the texture is resized out to + * the next power of two). It can be null if the caller is sure the bitmap won't be resized. + */ +sk_sp GrRefCachedBitmapTextureProxy(GrContext*, + const SkBitmap&, + const GrSamplerParams&, + SkScalar scaleAdjust[2]); + +/** + * Creates a new texture for the bitmap. Does not concern itself with cache keys or texture params. + * The bitmap must have CPU-accessible pixels. Attempts to take advantage of faster paths for + * compressed textures and yuv planes. + */ +sk_sp GrUploadBitmapToTextureProxy(GrResourceProvider*, const SkBitmap&); + +sk_sp GrGenerateMipMapsAndUploadToTextureProxy(GrContext*, const SkBitmap&, + SkColorSpace* dstColorSpace); + +/** + * Creates a new texture for the pixmap. + */ +sk_sp GrUploadPixmapToTextureProxy(GrResourceProvider*, + const SkPixmap&, SkBudgeted); +sk_sp GrUploadPixmapToTextureProxyNoCheck(GrResourceProvider*, + const SkPixmap&, SkBudgeted); + +/** + * Creates a new texture populated with the mipmap levels. + */ +sk_sp GrUploadMipMapToTextureProxy(GrContext*, const SkImageInfo&, + const GrMipLevel* texels, + int mipLevelCount, + SkDestinationSurfaceColorMode colorMode); + +// This is intended to replace: +// SkAutoLockPixels alp(bitmap, true); +// if (!bitmap.readyToDraw()) { +// return nullptr; +// } +// sk_sp texture = GrMakeCachedBitmapTexture(fContext.get(), bitmap, +// GrSamplerParams::ClampNoFilter(), +// nullptr); +// if (!texture) { +// return nullptr; +// } +sk_sp GrMakeCachedBitmapProxy(GrResourceProvider*, const SkBitmap& bitmap); + + +/** + * Our key includes the offset, width, and height so that bitmaps created by extractSubset() + * are unique. + * + * The imageID is in the shared namespace (see SkNextID::ImageID()) + * - SkBitmap/SkPixelRef + * - SkImage + * - SkImageGenerator + * + * Note: width/height must fit in 16bits for this impl. + */ +void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds); + +/** Call this after installing a GrUniqueKey on texture. It will cause the texture's key to be + removed should the bitmap's contents change or be destroyed. */ +void GrInstallBitmapUniqueKeyInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef); + +////////////////////////////////////////////////////////////////////////////// + +/** When image filter code needs to construct a render target context to do intermediate rendering, + we need a renderable pixel config. The source (SkSpecialImage) may not be in a renderable + format, but we want to preserve the color space of that source. This picks an appropriate format + to use. */ +GrPixelConfig GrRenderableConfigForColorSpace(const SkColorSpace*); + +/** + * If the compressed data in the SkData is supported (as a texture format, this returns + * the pixel-config that should be used, and sets outStartOfDataToUpload to the ptr into + * the data where the actual raw data starts (skipping any header bytes). + * + * If the compressed data is not supported, this returns kUnknown_GrPixelConfig, and + * ignores outStartOfDataToUpload. + */ +GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data, + int expectedW, int expectedH, + const void** outStartOfDataToUpload); + + + +#endif diff --git a/gfx/skia/skia/src/gpu/SkGrPriv.h b/gfx/skia/skia/src/gpu/SkGrPriv.h deleted file mode 100644 index b658389ba2b1..000000000000 --- a/gfx/skia/skia/src/gpu/SkGrPriv.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkGrPriv_DEFINED -#define SkGrPriv_DEFINED - -#include "GrTypes.h" -#include "GrBlend.h" -#include "SkImageInfo.h" -#include "SkMatrix.h" -#include "SkXfermode.h" - -class GrCaps; -class GrContext; -class GrDrawContext; -class GrFragmentProcessor; -class GrPaint; -class GrTexture; -class GrTextureParams; -class GrUniqueKey; -class SkData; -class SkPaint; -class SkPixelRef; -struct SkIRect; - -/** - * Our key includes the offset, width, and height so that bitmaps created by extractSubset() - * are unique. - * - * The imageID is in the shared namespace (see SkNextID::ImageID()) - * - SkBitmap/SkPixelRef - * - SkImage - * - SkImageGenerator - * - * Note: width/height must fit in 16bits for this impl. - */ -void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds); - -/** Call this after installing a GrUniqueKey on texture. It will cause the texture's key to be - removed should the bitmap's contents change or be destroyed. */ -void GrInstallBitmapUniqueKeyInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef); - -/** Converts an SkPaint to a GrPaint for a given GrContext. The matrix is required in order - to convert the SkShader (if any) on the SkPaint. The primitive itself has no color. */ -bool SkPaintToGrPaint(GrContext*, - GrDrawContext*, - const SkPaint& skPaint, - const SkMatrix& viewM, - GrPaint* grPaint); - -/** Same as above but ignores the SkShader (if any) on skPaint. */ -bool SkPaintToGrPaintNoShader(GrContext* context, - GrDrawContext* dc, - const SkPaint& skPaint, - GrPaint* grPaint); - -/** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. The processor - should expect an unpremul input color and produce a premultiplied output color. There is - no primitive color. */ -bool SkPaintToGrPaintReplaceShader(GrContext*, - GrDrawContext*, - const SkPaint& skPaint, - sk_sp shaderFP, - GrPaint* grPaint); - -/** Blends the SkPaint's shader (or color if no shader) with the color which specified via a - GrBatch's GrPrimitiveProcesssor. Currently there is a bool param to indicate whether the - primitive color is the dst or src color to the blend in order to work around differences between - drawVertices and drawAtlas. */ -bool SkPaintToGrPaintWithXfermode(GrContext* context, - GrDrawContext* dc, - const SkPaint& skPaint, - const SkMatrix& viewM, - SkXfermode::Mode primColorMode, - bool primitiveIsSrc, - GrPaint* grPaint); - -/** This is used when there is a primitive color, but the shader should be ignored. Currently, - the expectation is that the primitive color will be premultiplied, though it really should be - unpremultiplied so that interpolation is done in unpremul space. The paint's alpha will be - applied to the primitive color after interpolation. */ -inline bool SkPaintToGrPaintWithPrimitiveColor(GrContext* context, GrDrawContext* dc, - const SkPaint& skPaint, GrPaint* grPaint) { - return SkPaintToGrPaintWithXfermode(context, dc, skPaint, SkMatrix::I(), SkXfermode::kDst_Mode, - false, grPaint); -} - -/** This is used when there may or may not be a shader, and the caller wants to plugin a texture - lookup. If there is a shader, then its output will only be used if the texture is alpha8. */ -bool SkPaintToGrPaintWithTexture(GrContext* context, - GrDrawContext* dc, - const SkPaint& paint, - const SkMatrix& viewM, - sk_sp fp, - bool textureIsAlphaOnly, - GrPaint* grPaint); - -////////////////////////////////////////////////////////////////////////////// - -GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo&, const GrCaps&); - -bool GrPixelConfigToColorType(GrPixelConfig, SkColorType*); - -/** When image filter code needs to construct a draw context to do intermediate rendering, we need - a renderable pixel config. The source (SkSpecialImage) may not be in a renderable format, but - we want to preserve the color space of that source. This picks an appropriate format to use. */ -GrPixelConfig GrRenderableConfigForColorSpace(const SkColorSpace*); - -/** - * If the compressed data in the SkData is supported (as a texture format, this returns - * the pixel-config that should be used, and sets outStartOfDataToUpload to the ptr into - * the data where the actual raw data starts (skipping any header bytes). - * - * If the compressed data is not supported, this returns kUnknown_GrPixelConfig, and - * ignores outStartOfDataToUpload. - */ -GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data, - int expectedW, int expectedH, - const void** outStartOfDataToUpload); - - -/** - * Creates a new texture for the bitmap. Does not concern itself with cache keys or texture params. - * The bitmap must have CPU-accessible pixels. Attempts to take advantage of faster paths for - * compressed textures and yuv planes. - */ -GrTexture* GrUploadBitmapToTexture(GrContext*, const SkBitmap&); - -GrTexture* GrGenerateMipMapsAndUploadToTexture(GrContext*, const SkBitmap&, SkSourceGammaTreatment); - -/** - * Creates a new texture for the pixmap. - */ -GrTexture* GrUploadPixmapToTexture(GrContext*, const SkPixmap&, SkBudgeted budgeted); - -/** - * Creates a new texture populated with the mipmap levels. - */ -GrTexture* GrUploadMipMapToTexture(GrContext*, const SkImageInfo&, const GrMipLevel* texels, - int mipLevelCount); - -////////////////////////////////////////////////////////////////////////////// - -GR_STATIC_ASSERT((int)kZero_GrBlendCoeff == (int)SkXfermode::kZero_Coeff); -GR_STATIC_ASSERT((int)kOne_GrBlendCoeff == (int)SkXfermode::kOne_Coeff); -GR_STATIC_ASSERT((int)kSC_GrBlendCoeff == (int)SkXfermode::kSC_Coeff); -GR_STATIC_ASSERT((int)kISC_GrBlendCoeff == (int)SkXfermode::kISC_Coeff); -GR_STATIC_ASSERT((int)kDC_GrBlendCoeff == (int)SkXfermode::kDC_Coeff); -GR_STATIC_ASSERT((int)kIDC_GrBlendCoeff == (int)SkXfermode::kIDC_Coeff); -GR_STATIC_ASSERT((int)kSA_GrBlendCoeff == (int)SkXfermode::kSA_Coeff); -GR_STATIC_ASSERT((int)kISA_GrBlendCoeff == (int)SkXfermode::kISA_Coeff); -GR_STATIC_ASSERT((int)kDA_GrBlendCoeff == (int)SkXfermode::kDA_Coeff); -GR_STATIC_ASSERT((int)kIDA_GrBlendCoeff == (int)SkXfermode::kIDA_Coeff); -GR_STATIC_ASSERT(SkXfermode::kCoeffCount == 10); - -#define SkXfermodeCoeffToGrBlendCoeff(X) ((GrBlendCoeff)(X)) - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp deleted file mode 100644 index 36a9ff01e755..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp +++ /dev/null @@ -1,621 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrAADistanceFieldPathRenderer.h" - -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" -#include "GrBuffer.h" -#include "GrContext.h" -#include "GrPipelineBuilder.h" -#include "GrResourceProvider.h" -#include "GrSurfacePriv.h" -#include "GrSWMaskHelper.h" -#include "GrTexturePriv.h" -#include "batches/GrVertexBatch.h" -#include "effects/GrDistanceFieldGeoProc.h" - -#include "SkDistanceFieldGen.h" - -#define ATLAS_TEXTURE_WIDTH 2048 -#define ATLAS_TEXTURE_HEIGHT 2048 -#define PLOT_WIDTH 512 -#define PLOT_HEIGHT 256 - -#define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) -#define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) - -#ifdef DF_PATH_TRACKING -static int g_NumCachedShapes = 0; -static int g_NumFreedShapes = 0; -#endif - -// mip levels -static const int kSmallMIP = 32; -static const int kMediumMIP = 73; -static const int kLargeMIP = 162; - -// Callback to clear out internal path cache when eviction occurs -void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, void* pr) { - GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr; - // remove any paths that use this plot - ShapeDataList::Iter iter; - iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart); - ShapeData* shapeData; - while ((shapeData = iter.get())) { - iter.next(); - if (id == shapeData->fID) { - dfpr->fShapeCache.remove(shapeData->fKey); - dfpr->fShapeList.remove(shapeData); - delete shapeData; -#ifdef DF_PATH_TRACKING - ++g_NumFreedPaths; -#endif - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer() : fAtlas(nullptr) {} - -GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { - ShapeDataList::Iter iter; - iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart); - ShapeData* shapeData; - while ((shapeData = iter.get())) { - iter.next(); - delete shapeData; - } - delete fAtlas; - -#ifdef DF_PATH_TRACKING - SkDebugf("Cached shapes: %d, freed shapes: %d\n", g_NumCachedShapes, g_NumFreedShapes); -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - if (!args.fShaderCaps->shaderDerivativeSupport()) { - return false; - } - // If the shape has no key then we won't get any reuse. - if (!args.fShape->hasUnstyledKey()) { - return false; - } - // This only supports filled paths, however, the caller may apply the style to make a filled - // path and try again. - if (!args.fShape->style().isSimpleFill()) { - return false; - } - // This does non-inverse antialiased fills. - if (!args.fAntiAlias) { - return false; - } - // TODO: Support inverse fill - if (args.fShape->inverseFilled()) { - return false; - } - // currently don't support perspective - if (args.fViewMatrix->hasPerspective()) { - return false; - } - - // only support paths with bounds within kMediumMIP by kMediumMIP, - // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP - // the goal is to accelerate rendering of lots of small paths that may be scaling - SkScalar maxScale = args.fViewMatrix->getMaxScale(); - SkRect bounds = args.fShape->styledBounds(); - SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); - - return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; -} - -//////////////////////////////////////////////////////////////////////////////// - -// padding around path bounds to allow for antialiased pixels -static const SkScalar kAntiAliasPad = 1.0f; - -class AADistanceFieldPathBatch : public GrVertexBatch { -public: - DEFINE_BATCH_CLASS_ID - - typedef GrAADistanceFieldPathRenderer::ShapeData ShapeData; - typedef SkTDynamicHash ShapeCache; - typedef GrAADistanceFieldPathRenderer::ShapeDataList ShapeDataList; - - AADistanceFieldPathBatch(GrColor color, - const GrShape& shape, - bool antiAlias, - const SkMatrix& viewMatrix, - GrBatchAtlas* atlas, - ShapeCache* shapeCache, ShapeDataList* shapeList, - bool gammaCorrect) - : INHERITED(ClassID()) { - SkASSERT(shape.hasUnstyledKey()); - fBatch.fViewMatrix = viewMatrix; - fGeoData.emplace_back(Geometry{color, shape, antiAlias}); - - fAtlas = atlas; - fShapeCache = shapeCache; - fShapeList = shapeList; - fGammaCorrect = gammaCorrect; - - // Compute bounds - this->setTransformedBounds(shape.bounds(), viewMatrix, HasAABloat::kYes, IsZeroArea::kNo); - } - - const char* name() const override { return "AADistanceFieldPathBatch"; } - - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); - } - -private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any color overrides - if (!overrides.readsColor()) { - fGeoData[0].fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); - - // setup batch properties - fBatch.fColorIgnored = !overrides.readsColor(); - fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); - fBatch.fCoverageIgnored = !overrides.readsCoverage(); - } - - struct FlushInfo { - SkAutoTUnref fVertexBuffer; - SkAutoTUnref fIndexBuffer; - sk_sp fGeometryProcessor; - int fVertexOffset; - int fInstancesToFlush; - }; - - void onPrepareDraws(Target* target) const override { - int instanceCount = fGeoData.count(); - - SkMatrix invert; - if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { - SkDebugf("Could not invert viewmatrix\n"); - return; - } - - const SkMatrix& ctm = this->viewMatrix(); - uint32_t flags = 0; - flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0; - flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; - flags |= fGammaCorrect ? kGammaCorrect_DistanceFieldEffectFlag : 0; - - GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode); - - FlushInfo flushInfo; - - // Setup GrGeometryProcessor - GrBatchAtlas* atlas = fAtlas; - flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make(this->color(), - this->viewMatrix(), - atlas->getTexture(), - params, - flags, - this->usesLocalCoords()); - - // allocate vertices - size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride(); - SkASSERT(vertexStride == 2 * sizeof(SkPoint) + sizeof(GrColor)); - - const GrBuffer* vertexBuffer; - void* vertices = target->makeVertexSpace(vertexStride, - kVerticesPerQuad * instanceCount, - &vertexBuffer, - &flushInfo.fVertexOffset); - flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer)); - flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer()); - if (!vertices || !flushInfo.fIndexBuffer) { - SkDebugf("Could not allocate vertices\n"); - return; - } - - flushInfo.fInstancesToFlush = 0; - // Pointer to the next set of vertices to write. - intptr_t offset = reinterpret_cast(vertices); - for (int i = 0; i < instanceCount; i++) { - const Geometry& args = fGeoData[i]; - - // get mip level - SkScalar maxScale = this->viewMatrix().getMaxScale(); - const SkRect& bounds = args.fShape.bounds(); - SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); - SkScalar size = maxScale * maxDim; - uint32_t desiredDimension; - if (size <= kSmallMIP) { - desiredDimension = kSmallMIP; - } else if (size <= kMediumMIP) { - desiredDimension = kMediumMIP; - } else { - desiredDimension = kLargeMIP; - } - - // check to see if path is cached - ShapeData::Key key(args.fShape, desiredDimension); - ShapeData* shapeData = fShapeCache->find(key); - if (nullptr == shapeData || !atlas->hasID(shapeData->fID)) { - // Remove the stale cache entry - if (shapeData) { - fShapeCache->remove(shapeData->fKey); - fShapeList->remove(shapeData); - delete shapeData; - } - SkScalar scale = desiredDimension/maxDim; - shapeData = new ShapeData; - if (!this->addPathToAtlas(target, - &flushInfo, - atlas, - shapeData, - args.fShape, - args.fAntiAlias, - desiredDimension, - scale)) { - delete shapeData; - SkDebugf("Can't rasterize path\n"); - continue; - } - } - - atlas->setLastUseToken(shapeData->fID, target->nextDrawToken()); - - this->writePathVertices(target, - atlas, - offset, - args.fColor, - vertexStride, - this->viewMatrix(), - shapeData); - offset += kVerticesPerQuad * vertexStride; - flushInfo.fInstancesToFlush++; - } - - this->flush(target, &flushInfo); - } - - bool addPathToAtlas(GrVertexBatch::Target* target, - FlushInfo* flushInfo, - GrBatchAtlas* atlas, - ShapeData* shapeData, - const GrShape& shape, - bool antiAlias, - uint32_t dimension, - SkScalar scale) const { - const SkRect& bounds = shape.bounds(); - - // generate bounding rect for bitmap draw - SkRect scaledBounds = bounds; - // scale to mip level size - scaledBounds.fLeft *= scale; - scaledBounds.fTop *= scale; - scaledBounds.fRight *= scale; - scaledBounds.fBottom *= scale; - // move the origin to an integer boundary (gives better results) - SkScalar dx = SkScalarFraction(scaledBounds.fLeft); - SkScalar dy = SkScalarFraction(scaledBounds.fTop); - scaledBounds.offset(-dx, -dy); - // get integer boundary - SkIRect devPathBounds; - scaledBounds.roundOut(&devPathBounds); - // pad to allow room for antialiasing - const int intPad = SkScalarCeilToInt(kAntiAliasPad); - // pre-move origin (after outset, will be 0,0) - int width = devPathBounds.width(); - int height = devPathBounds.height(); - devPathBounds.fLeft = intPad; - devPathBounds.fTop = intPad; - devPathBounds.fRight = intPad + width; - devPathBounds.fBottom = intPad + height; - devPathBounds.outset(intPad, intPad); - - // draw path to bitmap - SkMatrix drawMatrix; - drawMatrix.setTranslate(-bounds.left(), -bounds.top()); - drawMatrix.postScale(scale, scale); - drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); - - // setup bitmap backing - SkASSERT(devPathBounds.fLeft == 0); - SkASSERT(devPathBounds.fTop == 0); - SkAutoPixmapStorage dst; - if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), - devPathBounds.height()))) { - return false; - } - sk_bzero(dst.writable_addr(), dst.getSafeSize()); - - // rasterize path - SkPaint paint; - paint.setStyle(SkPaint::kFill_Style); - paint.setAntiAlias(antiAlias); - - SkDraw draw; - sk_bzero(&draw, sizeof(draw)); - - SkRasterClip rasterClip; - rasterClip.setRect(devPathBounds); - draw.fRC = &rasterClip; - draw.fMatrix = &drawMatrix; - draw.fDst = dst; - - SkPath path; - shape.asPath(&path); - draw.drawPathCoverage(path, paint); - - // generate signed distance field - devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); - width = devPathBounds.width(); - height = devPathBounds.height(); - // TODO We should really generate this directly into the plot somehow - SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); - - // Generate signed distance field - SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), - (const unsigned char*)dst.addr(), - dst.width(), dst.height(), dst.rowBytes()); - - // add to atlas - SkIPoint16 atlasLocation; - GrBatchAtlas::AtlasID id; - if (!atlas->addToAtlas(&id, target, width, height, dfStorage.get(), &atlasLocation)) { - this->flush(target, flushInfo); - if (!atlas->addToAtlas(&id, target, width, height, dfStorage.get(), &atlasLocation)) { - return false; - } - } - - // add to cache - shapeData->fKey.set(shape, dimension); - shapeData->fScale = scale; - shapeData->fID = id; - // change the scaled rect to match the size of the inset distance field - scaledBounds.fRight = scaledBounds.fLeft + - SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); - scaledBounds.fBottom = scaledBounds.fTop + - SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); - // shift the origin to the correct place relative to the distance field - // need to also restore the fractional translation - scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx, - -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy); - shapeData->fBounds = scaledBounds; - // origin we render from is inset from distance field edge - atlasLocation.fX += SK_DistanceFieldInset; - atlasLocation.fY += SK_DistanceFieldInset; - shapeData->fAtlasLocation = atlasLocation; - - fShapeCache->add(shapeData); - fShapeList->addToTail(shapeData); -#ifdef DF_PATH_TRACKING - ++g_NumCachedPaths; -#endif - return true; - } - - void writePathVertices(GrDrawBatch::Target* target, - GrBatchAtlas* atlas, - intptr_t offset, - GrColor color, - size_t vertexStride, - const SkMatrix& viewMatrix, - const ShapeData* shapeData) const { - GrTexture* texture = atlas->getTexture(); - - SkScalar dx = shapeData->fBounds.fLeft; - SkScalar dy = shapeData->fBounds.fTop; - SkScalar width = shapeData->fBounds.width(); - SkScalar height = shapeData->fBounds.height(); - - SkScalar invScale = 1.0f / shapeData->fScale; - dx *= invScale; - dy *= invScale; - width *= invScale; - height *= invScale; - - SkPoint* positions = reinterpret_cast(offset); - - // vertex positions - // TODO make the vertex attributes a struct - SkRect r = SkRect::MakeXYWH(dx, dy, width, height); - positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexStride); - - // colors - for (int i = 0; i < kVerticesPerQuad; i++) { - GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertexStride); - *colorPtr = color; - } - - const SkScalar tx = SkIntToScalar(shapeData->fAtlasLocation.fX); - const SkScalar ty = SkIntToScalar(shapeData->fAtlasLocation.fY); - - // vertex texture coords - SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(GrColor)); - textureCoords->setRectFan(tx / texture->width(), - ty / texture->height(), - (tx + shapeData->fBounds.width()) / texture->width(), - (ty + shapeData->fBounds.height()) / texture->height(), - vertexStride); - } - - void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const { - if (flushInfo->fInstancesToFlush) { - GrMesh mesh; - int maxInstancesPerDraw = - static_cast(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6); - mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, - flushInfo->fIndexBuffer, flushInfo->fVertexOffset, kVerticesPerQuad, - kIndicesPerQuad, flushInfo->fInstancesToFlush, maxInstancesPerDraw); - target->draw(flushInfo->fGeometryProcessor.get(), mesh); - flushInfo->fVertexOffset += kVerticesPerQuad * flushInfo->fInstancesToFlush; - flushInfo->fInstancesToFlush = 0; - } - } - - GrColor color() const { return fGeoData[0].fColor; } - const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } - - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - AADistanceFieldPathBatch* that = t->cast(); - if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), - that->bounds(), caps)) { - return false; - } - - // TODO We can position on the cpu - if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { - return false; - } - - fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); - this->joinBounds(*that); - return true; - } - - struct BatchTracker { - SkMatrix fViewMatrix; - bool fUsesLocalCoords; - bool fColorIgnored; - bool fCoverageIgnored; - }; - - struct Geometry { - GrColor fColor; - GrShape fShape; - bool fAntiAlias; - }; - - BatchTracker fBatch; - SkSTArray<1, Geometry> fGeoData; - GrBatchAtlas* fAtlas; - ShapeCache* fShapeCache; - ShapeDataList* fShapeList; - bool fGammaCorrect; - - typedef GrVertexBatch INHERITED; -}; - -bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), - "GrAADistanceFieldPathRenderer::onDrawPath"); - SkASSERT(!args.fDrawContext->isUnifiedMultisampled()); - SkASSERT(args.fShape->style().isSimpleFill()); - - // we've already bailed on inverse filled paths, so this is safe - SkASSERT(!args.fShape->isEmpty()); - SkASSERT(args.fShape->hasUnstyledKey()); - if (!fAtlas) { - fAtlas = args.fResourceProvider->createAtlas(kAlpha_8_GrPixelConfig, - ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT, - NUM_PLOTS_X, NUM_PLOTS_Y, - &GrAADistanceFieldPathRenderer::HandleEviction, - (void*)this); - if (!fAtlas) { - return false; - } - } - - SkAutoTUnref batch(new AADistanceFieldPathBatch(args.fPaint->getColor(), - *args.fShape, - args.fAntiAlias, *args.fViewMatrix, - fAtlas, &fShapeCache, &fShapeList, - args.fGammaCorrect)); - - GrPipelineBuilder pipelineBuilder(*args.fPaint); - pipelineBuilder.setUserStencil(args.fUserStencilSettings); - - args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef GR_TEST_UTILS - -struct PathTestStruct { - typedef GrAADistanceFieldPathRenderer::ShapeCache ShapeCache; - typedef GrAADistanceFieldPathRenderer::ShapeData ShapeData; - typedef GrAADistanceFieldPathRenderer::ShapeDataList ShapeDataList; - PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {} - ~PathTestStruct() { this->reset(); } - - void reset() { - ShapeDataList::Iter iter; - iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart); - ShapeData* shapeData; - while ((shapeData = iter.get())) { - iter.next(); - fShapeList.remove(shapeData); - delete shapeData; - } - delete fAtlas; - fShapeCache.reset(); - } - - static void HandleEviction(GrBatchAtlas::AtlasID id, void* pr) { - PathTestStruct* dfpr = (PathTestStruct*)pr; - // remove any paths that use this plot - ShapeDataList::Iter iter; - iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart); - ShapeData* shapeData; - while ((shapeData = iter.get())) { - iter.next(); - if (id == shapeData->fID) { - dfpr->fShapeCache.remove(shapeData->fKey); - dfpr->fShapeList.remove(shapeData); - delete shapeData; - } - } - } - - uint32_t fContextID; - GrBatchAtlas* fAtlas; - ShapeCache fShapeCache; - ShapeDataList fShapeList; -}; - -DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) { - static PathTestStruct gTestStruct; - - if (context->uniqueID() != gTestStruct.fContextID) { - gTestStruct.fContextID = context->uniqueID(); - gTestStruct.reset(); - gTestStruct.fAtlas = - context->resourceProvider()->createAtlas(kAlpha_8_GrPixelConfig, - ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT, - NUM_PLOTS_X, NUM_PLOTS_Y, - &PathTestStruct::HandleEviction, - (void*)&gTestStruct); - } - - SkMatrix viewMatrix = GrTest::TestMatrix(random); - GrColor color = GrRandomColor(random); - bool gammaCorrect = random->nextBool(); - - // This path renderer only allows fill styles. - GrShape shape(GrTest::TestPath(random), GrStyle::SimpleFill()); - bool antiAlias = random->nextBool(); - - return new AADistanceFieldPathBatch(color, - shape, - antiAlias, - viewMatrix, - gTestStruct.fAtlas, - &gTestStruct.fShapeCache, - &gTestStruct.fShapeList, - gammaCorrect); -} - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAADistanceFieldPathRenderer.h b/gfx/skia/skia/src/gpu/batches/GrAADistanceFieldPathRenderer.h deleted file mode 100644 index 985b2f1537dc..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrAADistanceFieldPathRenderer.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrAADistanceFieldPathRenderer_DEFINED -#define GrAADistanceFieldPathRenderer_DEFINED - -#include "GrBatchAtlas.h" -#include "GrPathRenderer.h" -#include "GrRect.h" -#include "GrShape.h" - -#include "SkOpts.h" -#include "SkTDynamicHash.h" - -class GrContext; - -class GrAADistanceFieldPathRenderer : public GrPathRenderer { -public: - GrAADistanceFieldPathRenderer(); - virtual ~GrAADistanceFieldPathRenderer(); - -private: - StencilSupport onGetStencilSupport(const GrShape&) const override { - return GrPathRenderer::kNoSupport_StencilSupport; - } - - bool onCanDrawPath(const CanDrawPathArgs&) const override; - - bool onDrawPath(const DrawPathArgs&) override; - - struct ShapeData { - class Key { - public: - Key() {} - Key(const Key& that) { *this = that; } - Key(const GrShape& shape, uint32_t dim) { this->set(shape, dim); } - - Key& operator=(const Key& that) { - fKey.reset(that.fKey.count()); - memcpy(fKey.get(), that.fKey.get(), fKey.count() * sizeof(uint32_t)); - return *this; - } - - void set(const GrShape& shape, uint32_t dim) { - // Shapes' keys are for their pre-style geometry, but by now we shouldn't have any - // relevant styling information. - SkASSERT(shape.style().isSimpleFill()); - SkASSERT(shape.hasUnstyledKey()); - int shapeKeySize = shape.unstyledKeySize(); - fKey.reset(1 + shapeKeySize); - fKey[0] = dim; - shape.writeUnstyledKey(&fKey[1]); - } - - bool operator==(const Key& that) const { - return fKey.count() == that.fKey.count() && - 0 == memcmp(fKey.get(), that.fKey.get(), sizeof(uint32_t) * fKey.count()); - } - - int count32() const { return fKey.count(); } - const uint32_t* data() const { return fKey.get(); } - - private: - // The key is composed of the dimensions of the DF generated for the path (32x32 max, - // 64x64 max, 128x128 max) and the GrShape's key. - SkAutoSTArray<24, uint32_t> fKey; - }; - Key fKey; - SkScalar fScale; - GrBatchAtlas::AtlasID fID; - SkRect fBounds; - SkIPoint16 fAtlasLocation; - SK_DECLARE_INTERNAL_LLIST_INTERFACE(ShapeData); - - static inline const Key& GetKey(const ShapeData& data) { - return data.fKey; - } - - static inline uint32_t Hash(Key key) { - return SkOpts::hash(key.data(), sizeof(uint32_t) * key.count32()); - } - }; - - static void HandleEviction(GrBatchAtlas::AtlasID, void*); - - typedef SkTDynamicHash ShapeCache; - typedef SkTInternalLList ShapeDataList; - - GrBatchAtlas* fAtlas; - ShapeCache fShapeCache; - ShapeDataList fShapeList; - - typedef GrPathRenderer INHERITED; - - friend class AADistanceFieldPathBatch; - friend struct PathTestStruct; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAAFillRectBatch.h b/gfx/skia/skia/src/gpu/batches/GrAAFillRectBatch.h deleted file mode 100644 index 1dbec995f713..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrAAFillRectBatch.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrAAFillRectBatch_DEFINED -#define GrAAFillRectBatch_DEFINED - -#include "GrColor.h" - -class GrBatch; -class GrDrawBatch; -class SkMatrix; -struct SkRect; - -namespace GrAAFillRectBatch { -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& devRect); - -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkMatrix& localMatrix, - const SkRect& rect); - -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkMatrix& localMatrix, - const SkRect& rect, - const SkRect& devRect); - -GrDrawBatch* CreateWithLocalRect(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& localRect); -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAAStrokeRectBatch.h b/gfx/skia/skia/src/gpu/batches/GrAAStrokeRectBatch.h deleted file mode 100644 index 964cc5b4b981..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrAAStrokeRectBatch.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrAAStrokeRectBatch_DEFINED -#define GrAAStrokeRectBatch_DEFINED - -#include "GrColor.h" - -class GrBatch; -class GrDrawBatch; -class GrResourceProvider; -class SkMatrix; -struct SkRect; -class SkStrokeRec; - -namespace GrAAStrokeRectBatch { - -GrDrawBatch* CreateFillBetweenRects(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& devOutside, - const SkRect& devInside); - -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkStrokeRec& stroke); - -} - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.h b/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.h deleted file mode 100644 index 32771832aa9c..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrAtlasTextBatch_DEFINED -#define GrAtlasTextBatch_DEFINED - -#include "batches/GrVertexBatch.h" - -#include "text/GrAtlasTextContext.h" -#include "text/GrDistanceFieldAdjustTable.h" - -class GrAtlasTextBatch : public GrVertexBatch { -public: - DEFINE_BATCH_CLASS_ID - - static const int kVerticesPerGlyph = GrAtlasTextBlob::kVerticesPerGlyph; - static const int kIndicesPerGlyph = 6; - - typedef GrAtlasTextBlob Blob; - struct Geometry { - SkMatrix fViewMatrix; - Blob* fBlob; - SkScalar fX; - SkScalar fY; - int fRun; - int fSubRun; - GrColor fColor; - }; - - static GrAtlasTextBatch* CreateBitmap(GrMaskFormat maskFormat, int glyphCount, - GrBatchFontCache* fontCache) { - GrAtlasTextBatch* batch = new GrAtlasTextBatch; - - batch->fFontCache = fontCache; - switch (maskFormat) { - case kA8_GrMaskFormat: - batch->fMaskType = kGrayscaleCoverageMask_MaskType; - break; - case kA565_GrMaskFormat: - batch->fMaskType = kLCDCoverageMask_MaskType; - break; - case kARGB_GrMaskFormat: - batch->fMaskType = kColorBitmapMask_MaskType; - break; - } - batch->fBatch.fNumGlyphs = glyphCount; - batch->fGeoCount = 1; - batch->fFilteredColor = 0; - batch->fFontCache = fontCache; - batch->fUseBGR = false; - return batch; - } - - static GrAtlasTextBatch* CreateDistanceField( - int glyphCount, GrBatchFontCache* fontCache, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - bool useGammaCorrectDistanceTable, - SkColor filteredColor, bool isLCD, - bool useBGR) { - GrAtlasTextBatch* batch = new GrAtlasTextBatch; - - batch->fFontCache = fontCache; - batch->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistanceField_MaskType; - batch->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable)); - batch->fUseGammaCorrectDistanceTable = useGammaCorrectDistanceTable; - batch->fFilteredColor = filteredColor; - batch->fUseBGR = useBGR; - batch->fBatch.fNumGlyphs = glyphCount; - batch->fGeoCount = 1; - return batch; - } - - // to avoid even the initial copy of the struct, we have a getter for the first item which - // is used to seed the batch with its initial geometry. After seeding, the client should call - // init() so the Batch can initialize itself - Geometry& geometry() { return fGeoData[0]; } - - void init() { - const Geometry& geo = fGeoData[0]; - fBatch.fColor = geo.fColor; - SkRect bounds; - geo.fBlob->computeSubRunBounds(&bounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX, - geo.fY); - // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds - // we treat this as a set of non-AA rects rendered with a texture. - this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); - } - - const char* name() const override { return "TextBatch"; } - - SkString dumpInfo() const override; - -protected: - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override; - - -private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override; - - struct FlushInfo { - SkAutoTUnref fVertexBuffer; - SkAutoTUnref fIndexBuffer; - sk_sp fGeometryProcessor; - int fGlyphsToFlush; - int fVertexOffset; - }; - - void onPrepareDraws(Target* target) const override; - - GrAtlasTextBatch() : INHERITED(ClassID()) {} // initialized in factory functions. - - ~GrAtlasTextBatch() { - for (int i = 0; i < fGeoCount; i++) { - fGeoData[i].fBlob->unref(); - } - } - - GrMaskFormat maskFormat() const { - switch (fMaskType) { - case kLCDCoverageMask_MaskType: - return kA565_GrMaskFormat; - case kColorBitmapMask_MaskType: - return kARGB_GrMaskFormat; - case kGrayscaleCoverageMask_MaskType: - case kGrayscaleDistanceField_MaskType: - case kLCDDistanceField_MaskType: - return kA8_GrMaskFormat; - } - return kA8_GrMaskFormat; // suppress warning - } - - bool usesDistanceFields() const { - return kGrayscaleDistanceField_MaskType == fMaskType || - kLCDDistanceField_MaskType == fMaskType; - } - - bool isLCD() const { - return kLCDCoverageMask_MaskType == fMaskType || - kLCDDistanceField_MaskType == fMaskType; - } - - inline void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const; - - GrColor color() const { return fBatch.fColor; } - const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } - int numGlyphs() const { return fBatch.fNumGlyphs; } - - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override; - - // TODO just use class params - // TODO trying to figure out why lcd is so whack - sk_sp setupDfProcessor(const SkMatrix& viewMatrix, SkColor filteredColor, - GrColor color, GrTexture* texture) const; - - struct BatchTracker { - GrColor fColor; - bool fUsesLocalCoords; - bool fColorIgnored; - bool fCoverageIgnored; - int fNumGlyphs; - }; - - BatchTracker fBatch; - // The minimum number of Geometry we will try to allocate. - enum { kMinGeometryAllocated = 4 }; - SkAutoSTMalloc fGeoData; - int fGeoCount; - - enum MaskType { - kGrayscaleCoverageMask_MaskType, - kLCDCoverageMask_MaskType, - kColorBitmapMask_MaskType, - kGrayscaleDistanceField_MaskType, - kLCDDistanceField_MaskType, - } fMaskType; - bool fUseBGR; // fold this into the enum? - - GrBatchFontCache* fFontCache; - - // Distance field properties - SkAutoTUnref fDistanceAdjustTable; - SkColor fFilteredColor; - bool fUseGammaCorrectDistanceTable; - - friend class GrBlobRegenHelper; // Needs to trigger flushes - - typedef GrVertexBatch INHERITED; -}; - -/* - * A simple helper class to abstract the interface GrAtlasTextBlob needs to regenerate itself. - * It'd be nicer if this was nested, but we need to forward declare it in GrAtlasTextBlob.h - */ -class GrBlobRegenHelper { -public: - GrBlobRegenHelper(const GrAtlasTextBatch* batch, - GrVertexBatch::Target* target, - GrAtlasTextBatch::FlushInfo* flushInfo) - : fBatch(batch) - , fTarget(target) - , fFlushInfo(flushInfo) {} - - void flush(); - - void incGlyphCount(int glyphCount = 1) { - fFlushInfo->fGlyphsToFlush += glyphCount; - } - -private: - const GrAtlasTextBatch* fBatch; - GrVertexBatch::Target* fTarget; - GrAtlasTextBatch::FlushInfo* fFlushInfo; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrClearBatch.h b/gfx/skia/skia/src/gpu/batches/GrClearBatch.h deleted file mode 100644 index 16f1ddd7f40d..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrClearBatch.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrClearBatch_DEFINED -#define GrClearBatch_DEFINED - -#include "GrBatch.h" -#include "GrBatchFlushState.h" -#include "GrFixedClip.h" -#include "GrGpu.h" -#include "GrGpuCommandBuffer.h" -#include "GrRenderTarget.h" - -class GrClearBatch final : public GrBatch { -public: - DEFINE_BATCH_CLASS_ID - - static sk_sp Make(const GrFixedClip& clip, GrColor color, GrRenderTarget* rt) { - sk_sp batch(new GrClearBatch(clip, color, rt)); - if (!batch->renderTarget()) { - return nullptr; // The clip did not contain any pixels within the render target. - } - return batch; - } - - const char* name() const override { return "Clear"; } - - uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->uniqueID(); } - GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); } - - SkString dumpInfo() const override { - SkString string("Scissor ["); - if (fClip.scissorEnabled()) { - const SkIRect& r = fClip.scissorRect(); - string.appendf("L: %d, T: %d, R: %d, B: %d", r.fLeft, r.fTop, r.fRight, r.fBottom); - } - string.appendf("], Color: 0x%08x, RT: %d", fColor, fRenderTarget.get()->uniqueID()); - string.append(INHERITED::dumpInfo()); - return string; - } - - void setColor(GrColor color) { fColor = color; } - -private: - GrClearBatch(const GrFixedClip& clip, GrColor color, GrRenderTarget* rt) - : INHERITED(ClassID()) - , fClip(clip) - , fColor(color) { - SkIRect rtRect = SkIRect::MakeWH(rt->width(), rt->height()); - if (fClip.scissorEnabled()) { - // Don't let scissors extend outside the RT. This may improve batching. - if (!fClip.intersect(rtRect)) { - return; - } - if (fClip.scissorRect() == rtRect) { - fClip.disableScissor(); - } - } - this->setBounds(SkRect::Make(fClip.scissorEnabled() ? fClip.scissorRect() : rtRect), - HasAABloat::kNo, IsZeroArea::kNo); - fRenderTarget.reset(rt); - } - - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - // This could be much more complicated. Currently we look at cases where the new clear - // contains the old clear, or when the new clear is a subset of the old clear and is the - // same color. - GrClearBatch* cb = t->cast(); - SkASSERT(cb->fRenderTarget == fRenderTarget); - if (!fClip.windowRectsState().cheapEqualTo(cb->fClip.windowRectsState())) { - return false; - } - if (cb->contains(this)) { - fClip = cb->fClip; - this->replaceBounds(*t); - fColor = cb->fColor; - return true; - } else if (cb->fColor == fColor && this->contains(cb)) { - return true; - } - return false; - } - - bool contains(const GrClearBatch* that) const { - // The constructor ensures that scissor gets disabled on any clip that fills the entire RT. - return !fClip.scissorEnabled() || - (that->fClip.scissorEnabled() && - fClip.scissorRect().contains(that->fClip.scissorRect())); - } - - void onPrepare(GrBatchFlushState*) override {} - - void onDraw(GrBatchFlushState* state) override { - state->commandBuffer()->clear(fClip, fColor, fRenderTarget.get()); - } - - GrFixedClip fClip; - GrColor fColor; - GrPendingIOResource fRenderTarget; - - typedef GrBatch INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrClearStencilClipBatch.h b/gfx/skia/skia/src/gpu/batches/GrClearStencilClipBatch.h deleted file mode 100644 index e5108219393c..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrClearStencilClipBatch.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrClearStencilClipBatch_DEFINED -#define GrClearStencilClipBatch_DEFINED - -#include "GrBatch.h" -#include "GrBatchFlushState.h" -#include "GrFixedClip.h" -#include "GrGpu.h" -#include "GrGpuCommandBuffer.h" -#include "GrRenderTarget.h" - -class GrClearStencilClipBatch final : public GrBatch { -public: - DEFINE_BATCH_CLASS_ID - - GrClearStencilClipBatch(const GrFixedClip& clip, bool insideStencilMask, GrRenderTarget* rt) - : INHERITED(ClassID()) - , fClip(clip) - , fInsideStencilMask(insideStencilMask) - , fRenderTarget(rt) { - const SkRect& bounds = fClip.scissorEnabled() ? SkRect::Make(fClip.scissorRect()) - : SkRect::MakeIWH(rt->width(), rt->height()); - this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); - } - - const char* name() const override { return "ClearStencilClip"; } - - uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->uniqueID(); } - GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); } - - SkString dumpInfo() const override { - SkString string("Scissor ["); - if (fClip.scissorEnabled()) { - const SkIRect& r = fClip.scissorRect(); - string.appendf("L: %d, T: %d, R: %d, B: %d", r.fLeft, r.fTop, r.fRight, r.fBottom); - } - string.appendf("], IC: %d, RT: %d", fInsideStencilMask, fRenderTarget.get()->uniqueID()); - string.append(INHERITED::dumpInfo()); - return string; - } - -private: - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { return false; } - - void onPrepare(GrBatchFlushState*) override {} - - void onDraw(GrBatchFlushState* state) override { - state->commandBuffer()->clearStencilClip(fClip, fInsideStencilMask, fRenderTarget.get()); - } - - const GrFixedClip fClip; - const bool fInsideStencilMask; - GrPendingIOResource fRenderTarget; - - typedef GrBatch INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrCopySurfaceBatch.h b/gfx/skia/skia/src/gpu/batches/GrCopySurfaceBatch.h deleted file mode 100644 index fea8aae2f3c5..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrCopySurfaceBatch.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrCopySurfaceBatch_DEFINED -#define GrCopySurfaceBatch_DEFINED - -#include "GrBatch.h" -#include "GrBatchFlushState.h" -#include "GrGpu.h" -#include "GrRenderTarget.h" - -class GrCopySurfaceBatch final : public GrBatch { -public: - DEFINE_BATCH_CLASS_ID - - /** This should not really be exposed as Create() will apply this clipping, but there is - * currently a workaround in GrContext::copySurface() for non-render target dsts that relies - * on it. */ - static bool ClipSrcRectAndDstPoint(const GrSurface* dst, - const GrSurface* src, - const SkIRect& srcRect, - const SkIPoint& dstPoint, - SkIRect* clippedSrcRect, - SkIPoint* clippedDstPoint); - - static GrBatch* Create(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, - const SkIPoint& dstPoint); - - const char* name() const override { return "CopySurface"; } - - uint32_t renderTargetUniqueID() const override { - GrRenderTarget* rt = fDst.get()->asRenderTarget(); - return rt ? rt->uniqueID() : 0; - } - GrRenderTarget* renderTarget() const override { return nullptr; } - - SkString dumpInfo() const override { - SkString string; - string.printf("SRC: 0x%p, DST: 0x%p, SRECT: [L: %d, T: %d, R: %d, B: %d], " - "DPT:[X: %d, Y: %d]", - fDst.get(), fSrc.get(), fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, - fSrcRect.fBottom, fDstPoint.fX, fDstPoint.fY); - string.append(INHERITED::dumpInfo()); - return string; - } - -private: - GrCopySurfaceBatch(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, - const SkIPoint& dstPoint) - : INHERITED(ClassID()) - , fDst(dst) - , fSrc(src) - , fSrcRect(srcRect) - , fDstPoint(dstPoint) { - SkRect bounds = - SkRect::MakeXYWH(SkIntToScalar(dstPoint.fX), SkIntToScalar(dstPoint.fY), - SkIntToScalar(srcRect.width()), SkIntToScalar(srcRect.height())); - this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); - } - - bool onCombineIfPossible(GrBatch* that, const GrCaps& caps) override { return false; } - - void onPrepare(GrBatchFlushState*) override {} - - void onDraw(GrBatchFlushState* state) override { - if (!state->commandBuffer()) { - state->gpu()->copySurface(fDst.get(), fSrc.get(), fSrcRect, fDstPoint); - } else { - // currently we are not sending copies through the GrGpuCommandBuffer - SkASSERT(false); - } - } - - GrPendingIOResource fDst; - GrPendingIOResource fSrc; - SkIRect fSrcRect; - SkIPoint fDstPoint; - - typedef GrBatch INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrDashLinePathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrDashLinePathRenderer.cpp deleted file mode 100644 index f2b75be1081b..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrDashLinePathRenderer.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrDashLinePathRenderer.h" - -#include "GrAuditTrail.h" -#include "GrGpu.h" -#include "GrPipelineBuilder.h" -#include "effects/GrDashingEffect.h" - -bool GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - SkPoint pts[2]; - bool inverted; - if (args.fShape->style().isDashed() && args.fShape->asLine(pts, &inverted)) { - // We should never have an inverse dashed case. - SkASSERT(!inverted); - return GrDashingEffect::CanDrawDashLine(pts, args.fShape->style(), *args.fViewMatrix); - } - return false; -} - -bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), - "GrDashLinePathRenderer::onDrawPath"); - bool useHWAA = args.fDrawContext->isUnifiedMultisampled(); - GrDashingEffect::AAMode aaMode; - if (useHWAA) { - // We ignore args.fAntiAlias here and force anti aliasing when using MSAA. Otherwise, - // we can wind up with external edges antialiased and internal edges unantialiased. - aaMode = GrDashingEffect::AAMode::kCoverageWithMSAA; - } else if (args.fAntiAlias) { - aaMode = GrDashingEffect::AAMode::kCoverage; - } else { - aaMode = GrDashingEffect::AAMode::kNone; - } - SkPoint pts[2]; - SkAssertResult(args.fShape->asLine(pts, nullptr)); - SkAutoTUnref batch(GrDashingEffect::CreateDashLineBatch(args.fPaint->getColor(), - *args.fViewMatrix, - pts, - aaMode, - args.fShape->style())); - if (!batch) { - return false; - } - - GrPipelineBuilder pipelineBuilder(*args.fPaint, useHWAA); - pipelineBuilder.setUserStencil(args.fUserStencilSettings); - - args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); - return true; -} diff --git a/gfx/skia/skia/src/gpu/batches/GrDiscardBatch.h b/gfx/skia/skia/src/gpu/batches/GrDiscardBatch.h deleted file mode 100644 index 04e0ddbce43c..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrDiscardBatch.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrDiscardBatch_DEFINED -#define GrDiscardBatch_DEFINED - -#include "GrBatch.h" -#include "GrBatchFlushState.h" -#include "GrGpu.h" -#include "GrRenderTarget.h" - -class GrDiscardBatch final : public GrBatch { -public: - DEFINE_BATCH_CLASS_ID - - GrDiscardBatch(GrRenderTarget* rt) - : INHERITED(ClassID()) - , fRenderTarget(rt) { - this->setBounds(SkRect::MakeIWH(rt->width(), rt->height()), HasAABloat::kNo, - IsZeroArea::kNo); - } - - const char* name() const override { return "Discard"; } - - uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->uniqueID(); } - GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); } - - SkString dumpInfo() const override { - SkString string; - string.printf("RT: %d", fRenderTarget.get()->uniqueID()); - string.append(INHERITED::dumpInfo()); - return string; - } - -private: - bool onCombineIfPossible(GrBatch* that, const GrCaps& caps) override { - return this->renderTargetUniqueID() == that->renderTargetUniqueID(); - } - - void onPrepare(GrBatchFlushState*) override {} - - void onDraw(GrBatchFlushState* state) override { - state->commandBuffer()->discard(fRenderTarget.get()); - } - - GrPendingIOResource fRenderTarget; - - typedef GrBatch INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawAtlasBatch.h b/gfx/skia/skia/src/gpu/batches/GrDrawAtlasBatch.h deleted file mode 100644 index d9adf22a60a9..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrDrawAtlasBatch.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrDrawAtlasBatch_DEFINED -#define GrDrawAtlasBatch_DEFINED - -#include "GrColor.h" -#include "GrDefaultGeoProcFactory.h" -#include "GrVertexBatch.h" - -class GrDrawAtlasBatch : public GrVertexBatch { -public: - DEFINE_BATCH_CLASS_ID - - GrDrawAtlasBatch(GrColor color, const SkMatrix& viewMatrix, int spriteCount, - const SkRSXform* xforms, const SkRect* rects, const SkColor* colors); - - const char* name() const override { return "DrawAtlasBatch"; } - - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - if (this->hasColors()) { - color->setUnknownFourComponents(); - } else { - color->setKnownFourComponents(fGeoData[0].fColor); - } - coverage->setKnownSingleComponent(0xff); - } - -private: - void onPrepareDraws(Target*) const override; - - void initBatchTracker(const GrXPOverridesForBatch&) override; - - GrColor color() const { return fColor; } - bool colorIgnored() const { return fColorIgnored; } - const SkMatrix& viewMatrix() const { return fViewMatrix; } - bool hasColors() const { return fHasColors; } - int quadCount() const { return fQuadCount; } - bool coverageIgnored() const { return fCoverageIgnored; } - - bool onCombineIfPossible(GrBatch* t, const GrCaps&) override; - - struct Geometry { - GrColor fColor; - SkTArray fVerts; - }; - - SkSTArray<1, Geometry, true> fGeoData; - - SkMatrix fViewMatrix; - GrColor fColor; - int fQuadCount; - bool fColorIgnored; - bool fCoverageIgnored; - bool fHasColors; - - typedef GrVertexBatch INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawBatch.cpp b/gfx/skia/skia/src/gpu/batches/GrDrawBatch.cpp deleted file mode 100644 index b73f7515ecd6..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrDrawBatch.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrDrawBatch.h" - -GrDrawBatch::GrDrawBatch(uint32_t classID) : INHERITED(classID), fPipelineInstalled(false) { } - -GrDrawBatch::~GrDrawBatch() { - if (fPipelineInstalled) { - this->pipeline()->~GrPipeline(); - } -} - -void GrDrawBatch::getPipelineOptimizations(GrPipelineOptimizations* opt) const { - GrInitInvariantOutput color; - GrInitInvariantOutput coverage; - this->computePipelineOptimizations(&color, &coverage, &opt->fOverrides); - opt->fColorPOI.initUsingInvariantOutput(color); - opt->fCoveragePOI.initUsingInvariantOutput(coverage); -} - -bool GrDrawBatch::installPipeline(const GrPipeline::CreateArgs& args) { - GrXPOverridesForBatch overrides; - void* location = fPipelineStorage.get(); - if (!GrPipeline::CreateAt(location, args, &overrides)) { - return false; - } - fPipelineInstalled = true; - this->initBatchTracker(overrides); - return true; -} diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawBatch.h b/gfx/skia/skia/src/gpu/batches/GrDrawBatch.h deleted file mode 100644 index 5f37b7b0001f..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrDrawBatch.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrDrawBatch_DEFINED -#define GrDrawBatch_DEFINED - -#include -#include "GrBatch.h" -#include "GrPipeline.h" - -struct GrInitInvariantOutput; - -/** - * GrDrawBatches are flushed in two phases (preDraw, and draw). In preDraw uploads to GrGpuResources - * and draws are determined and scheduled. They are issued in the draw phase. GrBatchToken is used - * to sequence the uploads relative to each other and to draws. - **/ - -class GrBatchDrawToken { -public: - static GrBatchDrawToken AlreadyFlushedToken() { return GrBatchDrawToken(0); } - - GrBatchDrawToken(const GrBatchDrawToken& that) : fSequenceNumber(that.fSequenceNumber) {} - GrBatchDrawToken& operator =(const GrBatchDrawToken& that) { - fSequenceNumber = that.fSequenceNumber; - return *this; - } - bool operator==(const GrBatchDrawToken& that) const { - return fSequenceNumber == that.fSequenceNumber; - } - bool operator!=(const GrBatchDrawToken& that) const { return !(*this == that); } - -private: - GrBatchDrawToken(); - explicit GrBatchDrawToken(uint64_t sequenceNumber) : fSequenceNumber(sequenceNumber) {} - friend class GrBatchFlushState; - uint64_t fSequenceNumber; -}; - -/** - * Base class for GrBatches that draw. These batches have a GrPipeline installed by GrDrawTarget. - */ -class GrDrawBatch : public GrBatch { -public: - /** Method that performs an upload on behalf of a DeferredUploadFn. */ - using WritePixelsFn = std::function; - /** See comments before GrDrawBatch::Target definition on how deferred uploaders work. */ - using DeferredUploadFn = std::function; - - class Target; - - GrDrawBatch(uint32_t classID); - ~GrDrawBatch() override; - - /** - * Fills in a structure informing the XP of overrides to its normal behavior. - */ - void getPipelineOptimizations(GrPipelineOptimizations* override) const; - - const GrPipeline* pipeline() const { - SkASSERT(fPipelineInstalled); - return reinterpret_cast(fPipelineStorage.get()); - } - - bool installPipeline(const GrPipeline::CreateArgs&); - - // TODO no GrPrimitiveProcessors yet read fragment position - bool willReadFragmentPosition() const { return false; } - - uint32_t renderTargetUniqueID() const final { - SkASSERT(fPipelineInstalled); - return this->pipeline()->getRenderTarget()->uniqueID(); - } - - GrRenderTarget* renderTarget() const final { - SkASSERT(fPipelineInstalled); - return this->pipeline()->getRenderTarget(); - } - - SkString dumpInfo() const override { - SkString string; - string.appendf("RT: %d\n", this->renderTargetUniqueID()); - string.append("ColorStages:\n"); - for (int i = 0; i < this->pipeline()->numColorFragmentProcessors(); i++) { - string.appendf("\t\t%s\n\t\t%s\n", - this->pipeline()->getColorFragmentProcessor(i).name(), - this->pipeline()->getColorFragmentProcessor(i).dumpInfo().c_str()); - } - string.append("CoverageStages:\n"); - for (int i = 0; i < this->pipeline()->numCoverageFragmentProcessors(); i++) { - string.appendf("\t\t%s\n\t\t%s\n", - this->pipeline()->getCoverageFragmentProcessor(i).name(), - this->pipeline()->getCoverageFragmentProcessor(i).dumpInfo().c_str()); - } - string.appendf("XP: %s\n", this->pipeline()->getXferProcessor().name()); - - bool scissorEnabled = this->pipeline()->getScissorState().enabled(); - string.appendf("Scissor: "); - if (scissorEnabled) { - string.appendf("[L: %d, T: %d, R: %d, B: %d]\n", - this->pipeline()->getScissorState().rect().fLeft, - this->pipeline()->getScissorState().rect().fTop, - this->pipeline()->getScissorState().rect().fRight, - this->pipeline()->getScissorState().rect().fBottom); - } else { - string.appendf("\n"); - } - string.append(INHERITED::dumpInfo()); - - return string; - } - -protected: - virtual void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const = 0; - -private: - /** - * initBatchTracker is a hook for the some additional overrides / optimization possibilities - * from the GrXferProcessor. - */ - virtual void initBatchTracker(const GrXPOverridesForBatch&) = 0; - -protected: - struct QueuedUpload { - QueuedUpload(DeferredUploadFn&& upload, GrBatchDrawToken token) - : fUpload(std::move(upload)) - , fUploadBeforeToken(token) {} - DeferredUploadFn fUpload; - GrBatchDrawToken fUploadBeforeToken; - }; - SkTArray fInlineUploads; - -private: - SkAlignedSTStorage<1, GrPipeline> fPipelineStorage; - bool fPipelineInstalled; - typedef GrBatch INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.h b/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.h deleted file mode 100644 index 33bf678eb521..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrDrawPathBatch_DEFINED -#define GrDrawPathBatch_DEFINED - -#include "GrBatchFlushState.h" -#include "GrDrawBatch.h" -#include "GrGpu.h" -#include "GrPath.h" -#include "GrPathRendering.h" -#include "GrPathProcessor.h" - -#include "SkTLList.h" - -class GrDrawPathBatchBase : public GrDrawBatch { -public: - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - color->setKnownFourComponents(fColor); - coverage->setKnownSingleComponent(0xff); - } - -protected: - GrDrawPathBatchBase(uint32_t classID, const SkMatrix& viewMatrix, GrColor initialColor, - GrPathRendering::FillType fill) - : INHERITED(classID) - , fViewMatrix(viewMatrix) - , fColor(initialColor) - , fFillType(fill) {} - - const GrStencilSettings& stencilPassSettings() const { - SkASSERT(!fStencilPassSettings.isDisabled()); // This shouldn't be called before onPrepare. - return fStencilPassSettings; - } - const GrXPOverridesForBatch& overrides() const { return fOverrides; } - const SkMatrix& viewMatrix() const { return fViewMatrix; } - GrColor color() const { return fColor; } - GrPathRendering::FillType fillType() const { return fFillType; } - -private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - overrides.getOverrideColorIfSet(&fColor); - fOverrides = overrides; - } - - void onPrepare(GrBatchFlushState*) override; // Initializes fStencilPassSettings. - - SkMatrix fViewMatrix; - GrColor fColor; - GrPathRendering::FillType fFillType; - GrStencilSettings fStencilPassSettings; - GrXPOverridesForBatch fOverrides; - - typedef GrDrawBatch INHERITED; -}; - -class GrDrawPathBatch final : public GrDrawPathBatchBase { -public: - DEFINE_BATCH_CLASS_ID - - static GrDrawBatch* Create(const SkMatrix& viewMatrix, GrColor color, const GrPath* path) { - return new GrDrawPathBatch(viewMatrix, color, path); - } - - const char* name() const override { return "DrawPath"; } - - SkString dumpInfo() const override; - -private: - GrDrawPathBatch(const SkMatrix& viewMatrix, GrColor color, const GrPath* path) - : INHERITED(ClassID(), viewMatrix, color, path->getFillType()) - , fPath(path) { - this->setTransformedBounds(path->getBounds(), viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); - } - - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { return false; } - - void onDraw(GrBatchFlushState* state) override; - - GrPendingIOResource fPath; - - typedef GrDrawPathBatchBase INHERITED; -}; - -// Template this if we decide to support index types other than 16bit -class GrDrawPathRangeBatch final : public GrDrawPathBatchBase { -public: - typedef GrPathRendering::PathTransformType TransformType; - - DEFINE_BATCH_CLASS_ID - - struct InstanceData : public SkNoncopyable { - public: - static InstanceData* Alloc(TransformType transformType, int reserveCnt) { - int transformSize = GrPathRendering::PathTransformSize(transformType); - uint8_t* ptr = (uint8_t*)sk_malloc_throw(Align32(sizeof(InstanceData)) + - Align32(reserveCnt * sizeof(uint16_t)) + - reserveCnt * transformSize * sizeof(float)); - InstanceData* instanceData = (InstanceData*)ptr; - instanceData->fIndices = (uint16_t*)&ptr[Align32(sizeof(InstanceData))]; - instanceData->fTransformValues = (float*)&ptr[Align32(sizeof(InstanceData)) + - Align32(reserveCnt * sizeof(uint16_t))]; - instanceData->fTransformType = transformType; - instanceData->fInstanceCount = 0; - instanceData->fRefCnt = 1; - SkDEBUGCODE(instanceData->fReserveCnt = reserveCnt;) - return instanceData; - } - - // Overload this method if we start using other transform types. - void append(uint16_t index, float x, float y) { - SkASSERT(GrPathRendering::kTranslate_PathTransformType == fTransformType); - SkASSERT(fInstanceCount < fReserveCnt); - fIndices[fInstanceCount] = index; - fTransformValues[2 * fInstanceCount] = x; - fTransformValues[2 * fInstanceCount + 1] = y; - ++fInstanceCount; - } - - TransformType transformType() const { return fTransformType; } - int count() const { return fInstanceCount; } - - const uint16_t* indices() const { return fIndices; } - uint16_t* indices() { return fIndices; } - - const float* transformValues() const { return fTransformValues; } - float* transformValues() { return fTransformValues; } - - void ref() const { ++fRefCnt; } - - void unref() const { - if (0 == --fRefCnt) { - sk_free(const_cast(this)); - } - } - - private: - static int Align32(int sizeInBytes) { return (sizeInBytes + 3) & ~3; } - - InstanceData() {} - ~InstanceData() {} - - uint16_t* fIndices; - float* fTransformValues; - TransformType fTransformType; - int fInstanceCount; - mutable int fRefCnt; - SkDEBUGCODE(int fReserveCnt;) - }; - - static GrDrawBatch* Create(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, SkScalar y, - GrColor color, GrPathRendering::FillType fill, GrPathRange* range, - const InstanceData* instanceData, const SkRect& bounds) { - return new GrDrawPathRangeBatch(viewMatrix, scale, x, y, color, fill, range, instanceData, - bounds); - } - - const char* name() const override { return "DrawPathRange"; } - - SkString dumpInfo() const override; - -private: - GrDrawPathRangeBatch(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, SkScalar y, - GrColor color, GrPathRendering::FillType fill, GrPathRange* range, - const InstanceData* instanceData, const SkRect& bounds); - - TransformType transformType() const { return fDraws.head()->fInstanceData->transformType(); } - - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override; - - void onDraw(GrBatchFlushState* state) override; - - struct Draw { - void set(const InstanceData* instanceData, SkScalar x, SkScalar y) { - fInstanceData.reset(SkRef(instanceData)); - fX = x; - fY = y; - } - - SkAutoTUnref fInstanceData; - SkScalar fX, fY; - }; - - typedef GrPendingIOResource PendingPathRange; - typedef SkTLList DrawList; - - PendingPathRange fPathRange; - DrawList fDraws; - int fTotalPathCount; - SkScalar fScale; - - typedef GrDrawPathBatchBase INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawVerticesBatch.cpp b/gfx/skia/skia/src/gpu/batches/GrDrawVerticesBatch.cpp deleted file mode 100644 index e56502205541..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrDrawVerticesBatch.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrDrawVerticesBatch.h" - -#include "GrBatchFlushState.h" -#include "GrInvariantOutput.h" -#include "GrDefaultGeoProcFactory.h" - -static sk_sp set_vertex_attributes(bool hasLocalCoords, - int* colorOffset, - int* texOffset, - const SkMatrix& viewMatrix, - bool coverageIgnored) { - using namespace GrDefaultGeoProcFactory; - *texOffset = -1; - *colorOffset = -1; - - Coverage coverage(coverageIgnored ? Coverage::kNone_Type : Coverage::kSolid_Type); - LocalCoords localCoords(hasLocalCoords ? LocalCoords::kHasExplicit_Type : - LocalCoords::kUsePosition_Type); - *colorOffset = sizeof(SkPoint); - if (hasLocalCoords) { - *texOffset = sizeof(SkPoint) + sizeof(GrColor); - } - return GrDefaultGeoProcFactory::Make(Color(Color::kAttribute_Type), - coverage, localCoords, viewMatrix); -} - -GrDrawVerticesBatch::GrDrawVerticesBatch(GrColor color, GrPrimitiveType primitiveType, - const SkMatrix& viewMatrix, - const SkPoint* positions, int vertexCount, - const uint16_t* indices, int indexCount, - const GrColor* colors, const SkPoint* localCoords, - const SkRect& bounds) - : INHERITED(ClassID()) { - SkASSERT(positions); - - fViewMatrix = viewMatrix; - Mesh& mesh = fMeshes.push_back(); - mesh.fColor = color; - - mesh.fPositions.append(vertexCount, positions); - if (indices) { - mesh.fIndices.append(indexCount, indices); - } - - if (colors) { - fVariableColor = true; - mesh.fColors.append(vertexCount, colors); - } else { - fVariableColor = false; - } - - if (localCoords) { - mesh.fLocalCoords.append(vertexCount, localCoords); - } - fVertexCount = vertexCount; - fIndexCount = indexCount; - fPrimitiveType = primitiveType; - - IsZeroArea zeroArea; - if (GrIsPrimTypeLines(primitiveType) || kPoints_GrPrimitiveType == primitiveType) { - zeroArea = IsZeroArea::kYes; - } else { - zeroArea = IsZeroArea::kNo; - } - this->setBounds(bounds, HasAABloat::kNo, zeroArea); -} - -void GrDrawVerticesBatch::computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const { - // When this is called on a batch, there is only one mesh - if (fVariableColor) { - color->setUnknownFourComponents(); - } else { - color->setKnownFourComponents(fMeshes[0].fColor); - } - coverage->setKnownSingleComponent(0xff); -} - -void GrDrawVerticesBatch::initBatchTracker(const GrXPOverridesForBatch& overrides) { - SkASSERT(fMeshes.count() == 1); - GrColor overrideColor; - if (overrides.getOverrideColorIfSet(&overrideColor)) { - fMeshes[0].fColor = overrideColor; - fMeshes[0].fColors.reset(); - fVariableColor = false; - } - fCoverageIgnored = !overrides.readsCoverage(); - if (!overrides.readsLocalCoords()) { - fMeshes[0].fLocalCoords.reset(); - } -} - -void GrDrawVerticesBatch::onPrepareDraws(Target* target) const { - bool hasLocalCoords = !fMeshes[0].fLocalCoords.isEmpty(); - int colorOffset = -1, texOffset = -1; - sk_sp gp(set_vertex_attributes(hasLocalCoords, &colorOffset, &texOffset, - fViewMatrix, fCoverageIgnored)); - size_t vertexStride = gp->getVertexStride(); - - SkASSERT(vertexStride == sizeof(SkPoint) + (hasLocalCoords ? sizeof(SkPoint) : 0) - + sizeof(GrColor)); - - int instanceCount = fMeshes.count(); - - const GrBuffer* vertexBuffer; - int firstVertex; - - void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex); - - if (!verts) { - SkDebugf("Could not allocate vertices\n"); - return; - } - - const GrBuffer* indexBuffer = nullptr; - int firstIndex = 0; - - uint16_t* indices = nullptr; - if (!fMeshes[0].fIndices.isEmpty()) { - indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex); - - if (!indices) { - SkDebugf("Could not allocate indices\n"); - return; - } - } - - int indexOffset = 0; - int vertexOffset = 0; - for (int i = 0; i < instanceCount; i++) { - const Mesh& mesh = fMeshes[i]; - - // TODO we can actually cache this interleaved and then just memcopy - if (indices) { - for (int j = 0; j < mesh.fIndices.count(); ++j, ++indexOffset) { - *(indices + indexOffset) = mesh.fIndices[j] + vertexOffset; - } - } - - for (int j = 0; j < mesh.fPositions.count(); ++j) { - *((SkPoint*)verts) = mesh.fPositions[j]; - if (mesh.fColors.isEmpty()) { - *(GrColor*)((intptr_t)verts + colorOffset) = mesh.fColor; - } else { - *(GrColor*)((intptr_t)verts + colorOffset) = mesh.fColors[j]; - } - if (hasLocalCoords) { - *(SkPoint*)((intptr_t)verts + texOffset) = mesh.fLocalCoords[j]; - } - verts = (void*)((intptr_t)verts + vertexStride); - vertexOffset++; - } - } - - GrMesh mesh; - if (indices) { - mesh.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex, - firstIndex, fVertexCount, fIndexCount); - - } else { - mesh.init(this->primitiveType(), vertexBuffer, firstVertex, fVertexCount); - } - target->draw(gp.get(), mesh); -} - -bool GrDrawVerticesBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { - GrDrawVerticesBatch* that = t->cast(); - - if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), - that->bounds(), caps)) { - return false; - } - - if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) { - return false; - } - - // We currently use a uniform viewmatrix for this batch - if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) { - return false; - } - - if (fMeshes[0].fIndices.isEmpty() != that->fMeshes[0].fIndices.isEmpty()) { - return false; - } - - if (fMeshes[0].fLocalCoords.isEmpty() != that->fMeshes[0].fLocalCoords.isEmpty()) { - return false; - } - - if (!fVariableColor) { - if (that->fVariableColor || that->fMeshes[0].fColor != fMeshes[0].fColor) { - fVariableColor = true; - } - } - - fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin()); - fVertexCount += that->fVertexCount; - fIndexCount += that->fIndexCount; - - this->joinBounds(*that); - return true; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef GR_TEST_UTILS - -#include "GrBatchTest.h" - -static uint32_t seed_vertices(GrPrimitiveType type) { - switch (type) { - case kTriangles_GrPrimitiveType: - case kTriangleStrip_GrPrimitiveType: - case kTriangleFan_GrPrimitiveType: - return 3; - case kPoints_GrPrimitiveType: - return 1; - case kLines_GrPrimitiveType: - case kLineStrip_GrPrimitiveType: - return 2; - } - SkFAIL("Incomplete switch\n"); - return 0; -} - -static uint32_t primitive_vertices(GrPrimitiveType type) { - switch (type) { - case kTriangles_GrPrimitiveType: - return 3; - case kLines_GrPrimitiveType: - return 2; - case kTriangleStrip_GrPrimitiveType: - case kTriangleFan_GrPrimitiveType: - case kPoints_GrPrimitiveType: - case kLineStrip_GrPrimitiveType: - return 1; - } - SkFAIL("Incomplete switch\n"); - return 0; -} - -static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) { - SkPoint p; - p.fX = random->nextRangeScalar(min, max); - p.fY = random->nextRangeScalar(min, max); - return p; -} - -static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max, - SkRandom* random, - SkTArray* positions, - SkTArray* texCoords, bool hasTexCoords, - SkTArray* colors, bool hasColors, - SkTArray* indices, bool hasIndices) { - for (uint32_t v = 0; v < count; v++) { - positions->push_back(random_point(random, min, max)); - if (hasTexCoords) { - texCoords->push_back(random_point(random, min, max)); - } - if (hasColors) { - colors->push_back(GrRandomColor(random)); - } - if (hasIndices) { - SkASSERT(maxVertex <= SK_MaxU16); - indices->push_back(random->nextULessThan((uint16_t)maxVertex)); - } - } -} - -DRAW_BATCH_TEST_DEFINE(VerticesBatch) { - GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1)); - uint32_t primitiveCount = random->nextRangeU(1, 100); - - // TODO make 'sensible' indexbuffers - SkTArray positions; - SkTArray texCoords; - SkTArray colors; - SkTArray indices; - - bool hasTexCoords = random->nextBool(); - bool hasIndices = random->nextBool(); - bool hasColors = random->nextBool(); - - uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type); - - static const SkScalar kMinVertExtent = -100.f; - static const SkScalar kMaxVertExtent = 100.f; - randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, - random, - &positions, - &texCoords, hasTexCoords, - &colors, hasColors, - &indices, hasIndices); - - for (uint32_t i = 1; i < primitiveCount; i++) { - randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, - random, - &positions, - &texCoords, hasTexCoords, - &colors, hasColors, - &indices, hasIndices); - } - - SkMatrix viewMatrix = GrTest::TestMatrix(random); - SkRect bounds; - SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexCount); - SkASSERT(result); - - viewMatrix.mapRect(&bounds); - - GrColor color = GrRandomColor(random); - return new GrDrawVerticesBatch(color, type, viewMatrix, positions.begin(), vertexCount, - indices.begin(), hasIndices ? vertexCount : 0, - colors.begin(), texCoords.begin(), bounds); -} - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawVerticesBatch.h b/gfx/skia/skia/src/gpu/batches/GrDrawVerticesBatch.h deleted file mode 100644 index 9665c1a905a8..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrDrawVerticesBatch.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrDrawVerticesBatch_DEFINED -#define GrDrawVerticesBatch_DEFINED - -#include "GrColor.h" -#include "GrTypes.h" -#include "GrVertexBatch.h" -#include "SkMatrix.h" -#include "SkRect.h" -#include "SkTDArray.h" - -class GrBatchFlushState; -struct GrInitInvariantOutput; - -class GrDrawVerticesBatch : public GrVertexBatch { -public: - DEFINE_BATCH_CLASS_ID - - - GrDrawVerticesBatch(GrColor color, GrPrimitiveType primitiveType, - const SkMatrix& viewMatrix, - const SkPoint* positions, int vertexCount, - const uint16_t* indices, int indexCount, - const GrColor* colors, const SkPoint* localCoords, const SkRect& bounds); - - const char* name() const override { return "DrawVerticesBatch"; } - - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override; - -private: - void onPrepareDraws(Target*) const override; - void initBatchTracker(const GrXPOverridesForBatch&) override; - - GrPrimitiveType primitiveType() const { return fPrimitiveType; } - bool batchablePrimitiveType() const { - return kTriangles_GrPrimitiveType == fPrimitiveType || - kLines_GrPrimitiveType == fPrimitiveType || - kPoints_GrPrimitiveType == fPrimitiveType; - } - - bool onCombineIfPossible(GrBatch* t, const GrCaps&) override; - - struct Mesh { - GrColor fColor; // Only used if there are no per-vertex colors - SkTDArray fPositions; - SkTDArray fIndices; - SkTDArray fColors; - SkTDArray fLocalCoords; - }; - - GrPrimitiveType fPrimitiveType; - SkMatrix fViewMatrix; - bool fVariableColor; - int fVertexCount; - int fIndexCount; - bool fCoverageIgnored; // comes from initBatchTracker. - - SkSTArray<1, Mesh, true> fMeshes; - - typedef GrVertexBatch INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrNinePatch.h b/gfx/skia/skia/src/gpu/batches/GrNinePatch.h deleted file mode 100644 index 02664c6449e8..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrNinePatch.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrNinePatch_DEFINED -#define GrNinePatch_DEFINED - -#include "GrColor.h" -#include "SkCanvas.h" - -class GrDrawBatch; -class SkBitmap; -class SkLatticeIter; -class SkMatrix; -struct SkIRect; -struct SkRect; - -namespace GrNinePatch { -GrDrawBatch* CreateNonAA(GrColor color, const SkMatrix& viewMatrix, int imageWidth, int imageHeight, - std::unique_ptr iter, const SkRect& dst); -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrNonAAFillRectBatch.h b/gfx/skia/skia/src/gpu/batches/GrNonAAFillRectBatch.h deleted file mode 100644 index ac28d0fb46dd..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrNonAAFillRectBatch.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrNonAAFillRectBatch_DEFINED -#define GrNonAAFillRectBatch_DEFINED - -#include "GrColor.h" - -class GrDrawBatch; -class SkMatrix; -struct SkRect; - -namespace GrNonAAFillRectBatch { - -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect* localRect, - const SkMatrix* localMatrix); - -GrDrawBatch* CreateWithPerspective(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect* localRect, - const SkMatrix* localMatrix); - -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrNonAAStrokeRectBatch.h b/gfx/skia/skia/src/gpu/batches/GrNonAAStrokeRectBatch.h deleted file mode 100644 index 4d94337cc067..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrNonAAStrokeRectBatch.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrNonAAStrokeRectBatch_DEFINED -#define GrNonAAStrokeRectBatch_DEFINED - -#include "GrColor.h" - -#include "SkTypes.h" - -class GrDrawBatch; -struct SkRect; -class SkStrokeRec; -class SkMatrix; - -namespace GrNonAAStrokeRectBatch { - -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkStrokeRec&, - bool snapToPixelCenters); - -} - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrPLSPathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrPLSPathRenderer.cpp deleted file mode 100644 index e8711c09de49..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrPLSPathRenderer.cpp +++ /dev/null @@ -1,959 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrPLSPathRenderer.h" - -#include "SkChunkAlloc.h" -#include "SkGeometry.h" -#include "SkPathPriv.h" -#include "SkString.h" -#include "SkTSort.h" -#include "SkTraceEvent.h" -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" -#include "GrCaps.h" -#include "GrContext.h" -#include "GrDefaultGeoProcFactory.h" -#include "GrPLSGeometryProcessor.h" -#include "GrInvariantOutput.h" -#include "GrPathUtils.h" -#include "GrProcessor.h" -#include "GrPipelineBuilder.h" -#include "GrStyle.h" -#include "GrTessellator.h" -#include "batches/GrVertexBatch.h" -#include "glsl/GrGLSLGeometryProcessor.h" -#include "gl/builders/GrGLProgramBuilder.h" -#include "glsl/GrGLSLPLSPathRendering.h" - -GrPLSPathRenderer::GrPLSPathRenderer() { -} - -struct PLSVertex { - SkPoint fPos; - // for triangles, these are the three triangle vertices - // for quads, vert1 is the texture UV coords, and vert2 and vert3 are the line segment - // comprising the flat edge of the quad - SkPoint fVert1; - SkPoint fVert2; - SkPoint fVert3; - int fWinding; -}; -typedef SkTArray PLSVertices; - -typedef SkTArray FinishVertices; - -static const float kCubicTolerance = 0.5f; -static const float kConicTolerance = 0.5f; - -static const float kBloatSize = 1.0f; - -static const float kBloatLimit = 640000.0f; - -#define kQuadNumVertices 5 -static void add_quad(SkPoint pts[3], PLSVertices& vertices) { - SkPoint normal = SkPoint::Make(pts[0].fY - pts[2].fY, - pts[2].fX - pts[0].fX); - normal.setLength(kBloatSize); - SkScalar cross = (pts[1] - pts[0]).cross(pts[2] - pts[0]); - if (cross < 0) { - normal = -normal; - } - PLSVertex quad[kQuadNumVertices]; - quad[0].fPos = pts[0] + normal; - quad[1].fPos = pts[0] - normal; - quad[2].fPos = pts[1] - normal; - quad[3].fPos = pts[2] - normal; - quad[4].fPos = pts[2] + normal; - for (int i = 0; i < kQuadNumVertices; i++) { - quad[i].fWinding = cross < 0 ? 1 : -1; - if (cross > 0.0) { - quad[i].fVert2 = pts[0]; - quad[i].fVert3 = pts[2]; - } - else { - quad[i].fVert2 = pts[2]; - quad[i].fVert3 = pts[0]; - } - } - GrPathUtils::QuadUVMatrix DevToUV(pts); - DevToUV.apply(quad); - for (int i = 2; i < kQuadNumVertices; i++) { - vertices.push_back(quad[0]); - vertices.push_back(quad[i - 1]); - vertices.push_back(quad[i]); - } -} - -/* Used by bloat_tri; outsets a single point. */ -static bool outset(SkPoint* p1, SkPoint line1, SkPoint line2) { - // rotate the two line vectors 90 degrees to form the normals, and compute - // the dot product of the normals - SkScalar dotProd = line1.fY * line2.fY + line1.fX * line2.fX; - SkScalar lengthSq = 1.0f / ((1.0f - dotProd) / 2.0f); - if (lengthSq > kBloatLimit) { - return false; - } - SkPoint bisector = line1 + line2; - bisector.setLength(SkScalarSqrt(lengthSq) * kBloatSize); - *p1 += bisector; - return true; -} - -/* Bloats a triangle so as to create a border kBloatSize pixels wide all around it. */ -static bool bloat_tri(SkPoint pts[3]) { - SkPoint line1 = pts[0] - pts[1]; - line1.normalize(); - SkPoint line2 = pts[0] - pts[2]; - line2.normalize(); - SkPoint line3 = pts[1] - pts[2]; - line3.normalize(); - - SkPoint result[3]; - result[0] = pts[0]; - if (!outset(&result[0], line1, line2)) { - return false; - } - result[1] = pts[1]; - if (!outset(&result[1], -line1, line3)) { - return false; - } - result[2] = pts[2]; - if (!outset(&result[2], -line3, -line2)) { - return false; - } - pts[0] = result[0]; - pts[1] = result[1]; - pts[2] = result[2]; - return true; -} - -static bool get_geometry(const SkPath& path, const SkMatrix& m, PLSVertices& triVertices, - PLSVertices& quadVertices, GrResourceProvider* resourceProvider, - SkRect bounds) { - SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; - SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, m, bounds); - int contourCnt; - int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol); - if (maxPts <= 0) { - return 0; - } - SkPath linesOnlyPath; - linesOnlyPath.setFillType(path.getFillType()); - SkSTArray<15, SkPoint, true> quadPoints; - SkPath::Iter iter(path, true); - bool done = false; - while (!done) { - SkPoint pts[4]; - SkPath::Verb verb = iter.next(pts); - switch (verb) { - case SkPath::kMove_Verb: - SkASSERT(quadPoints.count() % 3 == 0); - for (int i = 0; i < quadPoints.count(); i += 3) { - add_quad(&quadPoints[i], quadVertices); - } - quadPoints.reset(); - m.mapPoints(&pts[0], 1); - linesOnlyPath.moveTo(pts[0]); - break; - case SkPath::kLine_Verb: - m.mapPoints(&pts[1], 1); - linesOnlyPath.lineTo(pts[1]); - break; - case SkPath::kQuad_Verb: - m.mapPoints(pts, 3); - linesOnlyPath.lineTo(pts[2]); - quadPoints.push_back(pts[0]); - quadPoints.push_back(pts[1]); - quadPoints.push_back(pts[2]); - break; - case SkPath::kCubic_Verb: { - m.mapPoints(pts, 4); - SkSTArray<15, SkPoint, true> quads; - GrPathUtils::convertCubicToQuads(pts, kCubicTolerance, &quads); - int count = quads.count(); - for (int q = 0; q < count; q += 3) { - linesOnlyPath.lineTo(quads[q + 2]); - quadPoints.push_back(quads[q]); - quadPoints.push_back(quads[q + 1]); - quadPoints.push_back(quads[q + 2]); - } - break; - } - case SkPath::kConic_Verb: { - m.mapPoints(pts, 3); - SkScalar weight = iter.conicWeight(); - SkAutoConicToQuads converter; - const SkPoint* quads = converter.computeQuads(pts, weight, kConicTolerance); - int count = converter.countQuads(); - for (int i = 0; i < count; ++i) { - linesOnlyPath.lineTo(quads[2 * i + 2]); - quadPoints.push_back(quads[2 * i]); - quadPoints.push_back(quads[2 * i + 1]); - quadPoints.push_back(quads[2 * i + 2]); - } - break; - } - case SkPath::kClose_Verb: - linesOnlyPath.close(); - break; - case SkPath::kDone_Verb: - done = true; - break; - default: SkASSERT(false); - } - } - SkASSERT(quadPoints.count() % 3 == 0); - for (int i = 0; i < quadPoints.count(); i += 3) { - add_quad(&quadPoints[i], quadVertices); - } - - static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey key; - GrUniqueKey::Builder builder(&key, kDomain, 2); - builder[0] = path.getGenerationID(); - builder[1] = path.getFillType(); - builder.finish(); - GrTessellator::WindingVertex* windingVertices; - int triVertexCount = GrTessellator::PathToVertices(linesOnlyPath, 0, bounds, &windingVertices); - if (triVertexCount > 0) { - for (int i = 0; i < triVertexCount; i += 3) { - SkPoint p1 = windingVertices[i].fPos; - SkPoint p2 = windingVertices[i + 1].fPos; - SkPoint p3 = windingVertices[i + 2].fPos; - int winding = windingVertices[i].fWinding; - SkASSERT(windingVertices[i + 1].fWinding == winding); - SkASSERT(windingVertices[i + 2].fWinding == winding); - SkScalar cross = (p2 - p1).cross(p3 - p1); - SkPoint bloated[3] = { p1, p2, p3 }; - if (cross < 0.0f) { - SkTSwap(p1, p3); - } - if (bloat_tri(bloated)) { - triVertices.push_back({ bloated[0], p1, p2, p3, winding }); - triVertices.push_back({ bloated[1], p1, p2, p3, winding }); - triVertices.push_back({ bloated[2], p1, p2, p3, winding }); - } - else { - SkScalar minX = SkTMin(p1.fX, SkTMin(p2.fX, p3.fX)) - 1.0f; - SkScalar minY = SkTMin(p1.fY, SkTMin(p2.fY, p3.fY)) - 1.0f; - SkScalar maxX = SkTMax(p1.fX, SkTMax(p2.fX, p3.fX)) + 1.0f; - SkScalar maxY = SkTMax(p1.fY, SkTMax(p2.fY, p3.fY)) + 1.0f; - triVertices.push_back({ { minX, minY }, p1, p2, p3, winding }); - triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding }); - triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding }); - triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding }); - triVertices.push_back({ { maxX, maxY }, p1, p2, p3, winding }); - triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding }); - } - } - delete[] windingVertices; - } - return triVertexCount > 0 || quadVertices.count() > 0; -} - -class PLSAATriangleEffect : public GrPLSGeometryProcessor { -public: - - static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix, - bool usesLocalCoords) { - return new PLSAATriangleEffect(localMatrix, usesLocalCoords); - } - - virtual ~PLSAATriangleEffect() {} - - const char* name() const override { return "PLSAATriangle"; } - - const Attribute* inPosition() const { return fInPosition; } - const Attribute* inVertex1() const { return fInVertex1; } - const Attribute* inVertex2() const { return fInVertex2; } - const Attribute* inVertex3() const { return fInVertex3; } - const Attribute* inWindings() const { return fInWindings; } - const SkMatrix& localMatrix() const { return fLocalMatrix; } - bool usesLocalCoords() const { return fUsesLocalCoords; } - - class GLSLProcessor : public GrGLSLGeometryProcessor { - public: - GLSLProcessor(const GrGeometryProcessor&) {} - - void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { - const PLSAATriangleEffect& te = args.fGP.cast(); - GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; - GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - - varyingHandler->emitAttributes(te); - - this->setupPosition(vsBuilder, gpArgs, te.inPosition()->fName); - - GrGLSLVertToFrag v1(kVec2f_GrSLType); - varyingHandler->addVarying("Vertex1", &v1, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", - v1.vsOut(), - te.inVertex1()->fName, - te.inVertex1()->fName); - - GrGLSLVertToFrag v2(kVec2f_GrSLType); - varyingHandler->addVarying("Vertex2", &v2, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", - v2.vsOut(), - te.inVertex2()->fName, - te.inVertex2()->fName); - - GrGLSLVertToFrag v3(kVec2f_GrSLType); - varyingHandler->addVarying("Vertex3", &v3, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", - v3.vsOut(), - te.inVertex3()->fName, - te.inVertex3()->fName); - - GrGLSLVertToFrag delta1(kVec2f_GrSLType); - varyingHandler->addVarying("delta1", &delta1, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", - delta1.vsOut(), v1.vsOut(), v2.vsOut(), v2.vsOut(), v1.vsOut()); - - GrGLSLVertToFrag delta2(kVec2f_GrSLType); - varyingHandler->addVarying("delta2", &delta2, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", - delta2.vsOut(), v2.vsOut(), v3.vsOut(), v3.vsOut(), v2.vsOut()); - - GrGLSLVertToFrag delta3(kVec2f_GrSLType); - varyingHandler->addVarying("delta3", &delta3, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", - delta3.vsOut(), v3.vsOut(), v1.vsOut(), v1.vsOut(), v3.vsOut()); - - GrGLSLVertToFrag windings(kInt_GrSLType); - varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision); - vsBuilder->codeAppendf("%s = %s;", - windings.vsOut(), te.inWindings()->fName); - - // emit transforms - this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, - te.inPosition()->fName, te.localMatrix(), - args.fFPCoordTransformHandler); - - GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder; - SkAssertResult(fsBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); - SkAssertResult(fsBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); - fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); - // Compute four subsamples, each shifted a quarter pixel along x and y from - // gl_FragCoord. The oriented box positioning of the subsamples is of course not - // optimal, but it greatly simplifies the math and this simplification is necessary for - // performance reasons. - fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);", - fsBuilder->fragmentPosition()); - fsBuilder->codeAppendf("highp vec2 delta1 = %s;", delta1.fsIn()); - fsBuilder->codeAppendf("highp vec2 delta2 = %s;", delta2.fsIn()); - fsBuilder->codeAppendf("highp vec2 delta3 = %s;", delta3.fsIn()); - // Check whether first sample is inside the triangle by computing three dot products. If - // all are < 0, we're inside. The first vector in each case is half of what it is - // "supposed" to be, because we re-use them later as adjustment factors for which half - // is the correct value, so we multiply the dots by two to compensate. - fsBuilder->codeAppendf("highp float d1 = dot(delta1, (firstSample - %s).yx) * 2.0;", - v1.fsIn()); - fsBuilder->codeAppendf("highp float d2 = dot(delta2, (firstSample - %s).yx) * 2.0;", - v2.fsIn()); - fsBuilder->codeAppendf("highp float d3 = dot(delta3, (firstSample - %s).yx) * 2.0;", - v3.fsIn()); - fsBuilder->codeAppend("highp float dmax = max(d1, max(d2, d3));"); - fsBuilder->codeAppendf("pls.windings[0] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); - // for subsequent samples, we don't recalculate the entire dot product -- just adjust it - // to the value it would have if we did recompute it. - fsBuilder->codeAppend("d1 += delta1.x;"); - fsBuilder->codeAppend("d2 += delta2.x;"); - fsBuilder->codeAppend("d3 += delta3.x;"); - fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); - fsBuilder->codeAppendf("pls.windings[1] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); - fsBuilder->codeAppend("d1 += delta1.y;"); - fsBuilder->codeAppend("d2 += delta2.y;"); - fsBuilder->codeAppend("d3 += delta3.y;"); - fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); - fsBuilder->codeAppendf("pls.windings[2] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); - fsBuilder->codeAppend("d1 -= delta1.x;"); - fsBuilder->codeAppend("d2 -= delta2.x;"); - fsBuilder->codeAppend("d3 -= delta3.x;"); - fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); - fsBuilder->codeAppendf("pls.windings[3] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); - } - - static inline void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { - const PLSAATriangleEffect& te = gp.cast(); - uint32_t key = 0; - key |= te.localMatrix().hasPerspective() ? 0x1 : 0x0; - b->add32(key); - } - - void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp, - FPCoordTransformIter&& transformIter) override { - this->setTransformDataHelper(gp.cast().fLocalMatrix, pdman, - &transformIter); - } - - private: - typedef GrGLSLGeometryProcessor INHERITED; - }; - - virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const override { - GLSLProcessor::GenKey(*this, caps, b); - } - - virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { - return new GLSLProcessor(*this); - } - -private: - PLSAATriangleEffect(const SkMatrix& localMatrix, bool usesLocalCoords) - : fLocalMatrix(localMatrix) - , fUsesLocalCoords(usesLocalCoords) { - this->initClassID(); - fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInVertex1 = &this->addVertexAttrib("inVertex1", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInVertex2 = &this->addVertexAttrib("inVertex2", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInVertex3 = &this->addVertexAttrib("inVertex3", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInWindings = &this->addVertexAttrib("inWindings", kInt_GrVertexAttribType, - kLow_GrSLPrecision); - this->setWillReadFragmentPosition(); - } - - const Attribute* fInPosition; - const Attribute* fInVertex1; - const Attribute* fInVertex2; - const Attribute* fInVertex3; - const Attribute* fInWindings; - SkMatrix fLocalMatrix; - bool fUsesLocalCoords; - - GR_DECLARE_GEOMETRY_PROCESSOR_TEST; - - typedef GrGeometryProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -/* - * Quadratic specified by 0=u^2-v canonical coords. u and v are the first - * two components of the vertex attribute. Coverage is based on signed - * distance with negative being inside, positive outside. The edge is specified in - * window space (y-down). If either the third or fourth component of the interpolated - * vertex coord is > 0 then the pixel is considered outside the edge. This is used to - * attempt to trim to a portion of the infinite quad. - * Requires shader derivative instruction support. - */ - -class PLSQuadEdgeEffect : public GrPLSGeometryProcessor { -public: - - static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix, - bool usesLocalCoords) { - return new PLSQuadEdgeEffect(localMatrix, usesLocalCoords); - } - - virtual ~PLSQuadEdgeEffect() {} - - const char* name() const override { return "PLSQuadEdge"; } - - const Attribute* inPosition() const { return fInPosition; } - const Attribute* inUV() const { return fInUV; } - const Attribute* inEndpoint1() const { return fInEndpoint1; } - const Attribute* inEndpoint2() const { return fInEndpoint2; } - const Attribute* inWindings() const { return fInWindings; } - const SkMatrix& localMatrix() const { return fLocalMatrix; } - bool usesLocalCoords() const { return fUsesLocalCoords; } - - class GLSLProcessor : public GrGLSLGeometryProcessor { - public: - GLSLProcessor(const GrGeometryProcessor&) {} - - void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { - const PLSQuadEdgeEffect& qe = args.fGP.cast(); - GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; - GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - - // emit attributes - varyingHandler->emitAttributes(qe); - - GrGLSLVertToFrag uv(kVec2f_GrSLType); - varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qe.inUV()->fName); - - GrGLSLVertToFrag ep1(kVec2f_GrSLType); - varyingHandler->addVarying("endpoint1", &ep1, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep1.vsOut(), - qe.inEndpoint1()->fName, qe.inEndpoint1()->fName); - - GrGLSLVertToFrag ep2(kVec2f_GrSLType); - varyingHandler->addVarying("endpoint2", &ep2, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep2.vsOut(), - qe.inEndpoint2()->fName, qe.inEndpoint2()->fName); - - GrGLSLVertToFrag delta(kVec2f_GrSLType); - varyingHandler->addVarying("delta", &delta, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", - delta.vsOut(), ep1.vsOut(), ep2.vsOut(), ep2.vsOut(), - ep1.vsOut()); - - GrGLSLVertToFrag windings(kInt_GrSLType); - varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision); - vsBuilder->codeAppendf("%s = %s;", - windings.vsOut(), qe.inWindings()->fName); - - // Setup position - this->setupPosition(vsBuilder, gpArgs, qe.inPosition()->fName); - - // emit transforms - this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, - qe.inPosition()->fName, qe.localMatrix(), - args.fFPCoordTransformHandler); - - GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder; - SkAssertResult(fsBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); - SkAssertResult(fsBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); - static const int QUAD_ARGS = 2; - GrGLSLShaderVar inQuadArgs[QUAD_ARGS] = { - GrGLSLShaderVar("dot", kFloat_GrSLType, 0, kHigh_GrSLPrecision), - GrGLSLShaderVar("uv", kVec2f_GrSLType, 0, kHigh_GrSLPrecision) - }; - SkString inQuadName; - - const char* inQuadCode = "if (uv.x * uv.x <= uv.y) {" - "return dot >= 0.0;" - "} else {" - "return false;" - "}"; - fsBuilder->emitFunction(kBool_GrSLType, "in_quad", QUAD_ARGS, inQuadArgs, inQuadCode, - &inQuadName); - fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); - // keep the derivative instructions outside the conditional - fsBuilder->codeAppendf("highp vec2 uvdX = dFdx(%s);", uv.fsIn()); - fsBuilder->codeAppendf("highp vec2 uvdY = dFdy(%s);", uv.fsIn()); - fsBuilder->codeAppend("highp vec2 uvIncX = uvdX * 0.45 + uvdY * -0.1;"); - fsBuilder->codeAppend("highp vec2 uvIncY = uvdX * 0.1 + uvdY * 0.55;"); - fsBuilder->codeAppendf("highp vec2 uv = %s.xy - uvdX * 0.35 - uvdY * 0.25;", - uv.fsIn()); - fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);", - fsBuilder->fragmentPosition()); - fsBuilder->codeAppendf("highp float d = dot(%s, (firstSample - %s).yx) * 2.0;", - delta.fsIn(), ep1.fsIn()); - fsBuilder->codeAppendf("pls.windings[0] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), - windings.fsIn()); - fsBuilder->codeAppend("uv += uvIncX;"); - fsBuilder->codeAppendf("d += %s.x;", delta.fsIn()); - fsBuilder->codeAppendf("pls.windings[1] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), - windings.fsIn()); - fsBuilder->codeAppend("uv += uvIncY;"); - fsBuilder->codeAppendf("d += %s.y;", delta.fsIn()); - fsBuilder->codeAppendf("pls.windings[2] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), - windings.fsIn()); - fsBuilder->codeAppend("uv -= uvIncX;"); - fsBuilder->codeAppendf("d -= %s.x;", delta.fsIn()); - fsBuilder->codeAppendf("pls.windings[3] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), - windings.fsIn()); - } - - static inline void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { - const PLSQuadEdgeEffect& qee = gp.cast(); - uint32_t key = 0; - key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ? 0x1 : 0x0; - b->add32(key); - } - - void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp, - FPCoordTransformIter&& transformIter) override { - this->setTransformDataHelper(gp.cast().fLocalMatrix, pdman, - &transformIter); - } - - private: - typedef GrGLSLGeometryProcessor INHERITED; - }; - - virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const override { - GLSLProcessor::GenKey(*this, caps, b); - } - - virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { - return new GLSLProcessor(*this); - } - -private: - PLSQuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords) - : fLocalMatrix(localMatrix) - , fUsesLocalCoords(usesLocalCoords) { - this->initClassID(); - fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInUV = &this->addVertexAttrib("inUV", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision); - fInEndpoint1 = &this->addVertexAttrib("inEndpoint1", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInEndpoint2 = &this->addVertexAttrib("inEndpoint2", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInWindings = &this->addVertexAttrib("inWindings", kInt_GrVertexAttribType, - kLow_GrSLPrecision); - this->setWillReadFragmentPosition(); - } - - const Attribute* fInPosition; - const Attribute* fInUV; - const Attribute* fInEndpoint1; - const Attribute* fInEndpoint2; - const Attribute* fInWindings; - SkMatrix fLocalMatrix; - bool fUsesLocalCoords; - - GR_DECLARE_GEOMETRY_PROCESSOR_TEST; - - typedef GrGeometryProcessor INHERITED; -}; - -class PLSFinishEffect : public GrGeometryProcessor { -public: - - static GrGeometryProcessor* Create(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix, - bool usesLocalCoords) { - return new PLSFinishEffect(color, useEvenOdd, localMatrix, usesLocalCoords); - } - - virtual ~PLSFinishEffect() {} - - const char* name() const override { return "PLSFinish"; } - - const Attribute* inPosition() const { return fInPosition; } - GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } - const SkMatrix& localMatrix() const { return fLocalMatrix; } - bool usesLocalCoords() const { return fUsesLocalCoords; } - - GrPixelLocalStorageState getPixelLocalStorageState() const override { - return GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState; - } - - const char* getDestColorOverride() const override { - return GR_GL_PLS_DSTCOLOR_NAME; - } - - class GLSLProcessor : public GrGLSLGeometryProcessor { - public: - GLSLProcessor(const GrGeometryProcessor&) {} - - void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { - const PLSFinishEffect& fe = args.fGP.cast(); - GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; - GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - - fUseEvenOdd = uniformHandler->addUniform(kFragment_GrShaderFlag, - kFloat_GrSLType, kLow_GrSLPrecision, - "useEvenOdd"); - const char* useEvenOdd = uniformHandler->getUniformCStr(fUseEvenOdd); - - varyingHandler->emitAttributes(fe); - this->setupPosition(vsBuilder, gpArgs, fe.inPosition()->fName); - this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, - fe.inPosition()->fName, fe.localMatrix(), - args.fFPCoordTransformHandler); - - GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder; - SkAssertResult(fsBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); - fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); - fsBuilder->codeAppend("float coverage;"); - fsBuilder->codeAppendf("if (%s != 0.0) {", useEvenOdd); - fsBuilder->codeAppend("coverage = float(abs(pls.windings[0]) % 2) * 0.25;"); - fsBuilder->codeAppend("coverage += float(abs(pls.windings[1]) % 2) * 0.25;"); - fsBuilder->codeAppend("coverage += float(abs(pls.windings[2]) % 2) * 0.25;"); - fsBuilder->codeAppend("coverage += float(abs(pls.windings[3]) % 2) * 0.25;"); - fsBuilder->codeAppend("} else {"); - fsBuilder->codeAppend("coverage = pls.windings[0] != 0 ? 0.25 : 0.0;"); - fsBuilder->codeAppend("coverage += pls.windings[1] != 0 ? 0.25 : 0.0;"); - fsBuilder->codeAppend("coverage += pls.windings[2] != 0 ? 0.25 : 0.0;"); - fsBuilder->codeAppend("coverage += pls.windings[3] != 0 ? 0.25 : 0.0;"); - fsBuilder->codeAppend("}"); - if (!fe.colorIgnored()) { - this->setupUniformColor(fsBuilder, uniformHandler, args.fOutputColor, - &fColorUniform); - } - fsBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverage); - fsBuilder->codeAppendf("%s = vec4(1.0, 0.0, 1.0, 1.0);", args.fOutputColor); - } - - static inline void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { - const PLSFinishEffect& fe = gp.cast(); - uint32_t key = 0; - key |= fe.usesLocalCoords() && fe.localMatrix().hasPerspective() ? 0x1 : 0x0; - b->add32(key); - } - - void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp, - FPCoordTransformIter&& transformIter) override { - const PLSFinishEffect& fe = gp.cast(); - pdman.set1f(fUseEvenOdd, fe.fUseEvenOdd); - if (fe.color() != fColor && !fe.colorIgnored()) { - GrGLfloat c[4]; - GrColorToRGBAFloat(fe.color(), c); - pdman.set4fv(fColorUniform, 1, c); - fColor = fe.color(); - } - this->setTransformDataHelper(fe.fLocalMatrix, pdman, &transformIter); - } - - private: - GrColor fColor; - UniformHandle fColorUniform; - UniformHandle fUseEvenOdd; - - typedef GrGLSLGeometryProcessor INHERITED; - }; - - virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const override { - GLSLProcessor::GenKey(*this, caps, b); - } - - virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { - return new GLSLProcessor(*this); - } - -private: - PLSFinishEffect(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix, - bool usesLocalCoords) - : fColor(color) - , fUseEvenOdd(useEvenOdd) - , fLocalMatrix(localMatrix) - , fUsesLocalCoords(usesLocalCoords) { - this->initClassID(); - fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - } - - const Attribute* fInPosition; - GrColor fColor; - bool fUseEvenOdd; - SkMatrix fLocalMatrix; - bool fUsesLocalCoords; - - typedef GrGeometryProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -bool GrPLSPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - // We have support for even-odd rendering, but are having some troublesome - // seams. Disable in the presence of even-odd for now. - SkPath path; - args.fShape->asPath(&path); - return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias && - args.fShape->style().isSimpleFill() && !path.isInverseFillType() && - path.getFillType() == SkPath::FillType::kWinding_FillType; -} - -class PLSPathBatch : public GrVertexBatch { -public: - DEFINE_BATCH_CLASS_ID - PLSPathBatch(GrColor color, const SkPath& path, const SkMatrix& viewMatrix) - : INHERITED(ClassID()) - , fColor(color) - , fPath(path) - , fViewMatrix(viewMatrix) { - // compute bounds - this->setTransformedBounds(path.getBounds(), fViewMatrix, HasAABloat::kYes, - IsZeroArea::kNo); - } - - const char* name() const override { return "PLSBatch"; } - - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fColor); - coverage->setUnknownSingleComponent(); - overrides->fUsePLSDstRead = true; - } - - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any color overrides - if (!overrides.readsColor()) { - fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fColor); - - // setup batch properties - fUsesLocalCoords = overrides.readsLocalCoords(); - } - - void onPrepareDraws(Target* target) const override { - - SkMatrix invert; - if (fUsesLocalCoords && !fViewMatrix.invert(&invert)) { - SkDebugf("Could not invert viewmatrix\n"); - return; - } - - // Setup GrGeometryProcessors - SkAutoTUnref triangleProcessor( - PLSAATriangleEffect::Create(invert, fUsesLocalCoords)); - SkAutoTUnref quadProcessor( - PLSQuadEdgeEffect::Create(invert, fUsesLocalCoords)); - - GrResourceProvider* rp = target->resourceProvider(); - SkRect bounds; - this->bounds().roundOut(&bounds); - triangleProcessor->setBounds(bounds); - quadProcessor->setBounds(bounds); - - // We use the fact that SkPath::transform path does subdivision based on - // perspective. Otherwise, we apply the view matrix when copying to the - // segment representation. - const SkMatrix* viewMatrix = &fViewMatrix; - - // We avoid initializing the path unless we have to - const SkPath* pathPtr = &fPath; - SkTLazy tmpPath; - if (viewMatrix->hasPerspective()) { - SkPath* tmpPathPtr = tmpPath.init(*pathPtr); - tmpPathPtr->setIsVolatile(true); - tmpPathPtr->transform(*viewMatrix); - viewMatrix = &SkMatrix::I(); - pathPtr = tmpPathPtr; - } - - GrMesh mesh; - - PLSVertices triVertices; - PLSVertices quadVertices; - if (!get_geometry(*pathPtr, *viewMatrix, triVertices, quadVertices, rp, bounds)) { - return; - } - - if (triVertices.count()) { - const GrBuffer* triVertexBuffer; - int firstTriVertex; - size_t triStride = triangleProcessor->getVertexStride(); - PLSVertex* triVerts = reinterpret_cast(target->makeVertexSpace( - triStride, triVertices.count(), &triVertexBuffer, &firstTriVertex)); - if (!triVerts) { - SkDebugf("Could not allocate vertices\n"); - return; - } - for (int i = 0; i < triVertices.count(); ++i) { - triVerts[i] = triVertices[i]; - } - mesh.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriVertex, - triVertices.count()); - target->draw(triangleProcessor, mesh); - } - - if (quadVertices.count()) { - const GrBuffer* quadVertexBuffer; - int firstQuadVertex; - size_t quadStride = quadProcessor->getVertexStride(); - PLSVertex* quadVerts = reinterpret_cast(target->makeVertexSpace( - quadStride, quadVertices.count(), &quadVertexBuffer, &firstQuadVertex)); - if (!quadVerts) { - SkDebugf("Could not allocate vertices\n"); - return; - } - for (int i = 0; i < quadVertices.count(); ++i) { - quadVerts[i] = quadVertices[i]; - } - mesh.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex, - quadVertices.count()); - target->draw(quadProcessor, mesh); - } - - SkAutoTUnref finishProcessor( - PLSFinishEffect::Create(fColor, - pathPtr->getFillType() == - SkPath::FillType::kEvenOdd_FillType, - invert, - fUsesLocalCoords)); - const GrBuffer* rectVertexBuffer; - size_t finishStride = finishProcessor->getVertexStride(); - int firstRectVertex; - static const int kRectVertexCount = 6; - SkPoint* rectVerts = reinterpret_cast(target->makeVertexSpace( - finishStride, kRectVertexCount, &rectVertexBuffer, &firstRectVertex)); - if (!rectVerts) { - SkDebugf("Could not allocate vertices\n"); - return; - } - rectVerts[0] = { bounds.fLeft, bounds.fTop }; - rectVerts[1] = { bounds.fLeft, bounds.fBottom }; - rectVerts[2] = { bounds.fRight, bounds.fBottom }; - rectVerts[3] = { bounds.fLeft, bounds.fTop }; - rectVerts[4] = { bounds.fRight, bounds.fTop }; - rectVerts[5] = { bounds.fRight, bounds.fBottom }; - - mesh.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVertex, - kRectVertexCount); - target->draw(finishProcessor, mesh); - } - -private: - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - return false; - } - - bool fUsesLocalCoords; - - GrColor fColor; - SkPath fPath; - SkMatrix fViewMatrix; - typedef GrVertexBatch INHERITED; -}; - -SkDEBUGCODE(bool inPLSDraw = false;) -bool GrPLSPathRenderer::onDrawPath(const DrawPathArgs& args) { - SkASSERT(!args.fShape->isEmpty()); - SkASSERT(!inPLSDraw); - SkDEBUGCODE(inPLSDraw = true;) - SkPath path; - args.fShape->asPath(&path); - - SkAutoTUnref batch(new PLSPathBatch(args.fPaint->getColor(), - path, *args.fViewMatrix)); - - GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHWAA(*args.fPaint)); - pipelineBuilder.setUserStencil(args.fUserStencilSettings); - - args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); - - SkDEBUGCODE(inPLSDraw = false;) - return true; - -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef GR_TEST_UTILS - -DRAW_BATCH_TEST_DEFINE(PLSPathBatch) { - GrColor color = GrRandomColor(random); - SkMatrix vm = GrTest::TestMatrixInvertible(random); - SkPath path = GrTest::TestPathConvex(random); - - return new PLSPathBatch(color, path, vm); -} - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrPLSPathRenderer.h b/gfx/skia/skia/src/gpu/batches/GrPLSPathRenderer.h deleted file mode 100644 index 39f21ba68c1b..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrPLSPathRenderer.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrPLSPathRenderer_DEFINED -#define GrPLSPathRenderer_DEFINED - -#include "GrPathRenderer.h" - -/* - * Renders arbitrary antialiased paths using pixel local storage as a scratch buffer. The overall - * technique is very similar to the approach presented in "Resolution independent rendering of - * deformable vector objects using graphics hardware" by Kokojima et al. - - * We first render the straight-line portions of the path (essentially pretending as if all segments - * were kLine_Verb) as a triangle fan, using a fragment shader which updates the winding counts - * appropriately. We then render the curved portions of the path using a Loop-Blinn shader which - * calculates which portion of the triangle is covered by the quad (conics and cubics are split down - * to quads). Where we diverge from Kokojima is that, instead of rendering into the stencil buffer - * and using built-in MSAA to handle straight-line antialiasing, we use the pixel local storage area - * and calculate the MSAA ourselves in the fragment shader. Essentially, we manually evaluate the - * coverage of each pixel four times, storing four winding counts into the pixel local storage area, - * and compute the final coverage based on those winding counts. - * - * Our approach is complicated by the need to perform antialiasing on straight edges as well, - * without relying on hardware MSAA. We instead bloat the triangles to ensure complete coverage, - * pass the original (un-bloated) vertices in to the fragment shader, and then have the fragment - * shader use these vertices to evaluate whether a given sample is located within the triangle or - * not. This gives us MSAA4 edges on triangles which line up nicely with no seams. We similarly face - * problems on the back (flat) edges of quads, where we have to ensure that the back edge is - * antialiased in the same way. Similar to the triangle case, we pass in the two (unbloated) - * vertices defining the back edge of the quad and the fragment shader uses these vertex coordinates - * to discard samples falling on the other side of the quad's back edge. - */ -class GrPLSPathRenderer : public GrPathRenderer { -public: - GrPLSPathRenderer(); - - bool onCanDrawPath(const CanDrawPathArgs& args) const override; - -protected: - bool onDrawPath(const DrawPathArgs& args) override; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrRectBatchFactory.cpp b/gfx/skia/skia/src/gpu/batches/GrRectBatchFactory.cpp deleted file mode 100644 index d2ba7f4442d7..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrRectBatchFactory.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrRectBatchFactory.h" - -#include "GrAAStrokeRectBatch.h" - -#include "SkStrokeRec.h" - -namespace GrRectBatchFactory { - -GrDrawBatch* CreateAAFillNestedRects(GrColor color, - const SkMatrix& viewMatrix, - const SkRect rects[2]) { - SkASSERT(viewMatrix.rectStaysRect()); - SkASSERT(!rects[0].isEmpty() && !rects[1].isEmpty()); - - SkRect devOutside, devInside; - viewMatrix.mapRect(&devOutside, rects[0]); - viewMatrix.mapRect(&devInside, rects[1]); - if (devInside.isEmpty()) { - if (devOutside.isEmpty()) { - return nullptr; - } - return GrAAFillRectBatch::Create(color, viewMatrix, devOutside, devOutside); - } - - return GrAAStrokeRectBatch::CreateFillBetweenRects(color, viewMatrix, devOutside, devInside); -} - -}; diff --git a/gfx/skia/skia/src/gpu/batches/GrRectBatchFactory.h b/gfx/skia/skia/src/gpu/batches/GrRectBatchFactory.h deleted file mode 100644 index c9b6843596be..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrRectBatchFactory.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrRectBatchFactory_DEFINED -#define GrRectBatchFactory_DEFINED - -#include "GrAAFillRectBatch.h" -#include "GrAAStrokeRectBatch.h" -#include "GrAnalyticRectBatch.h" -#include "GrColor.h" -#include "GrNonAAFillRectBatch.h" -#include "GrNonAAStrokeRectBatch.h" -#include "GrPaint.h" -#include "SkMatrix.h" - -class GrBatch; -struct SkRect; -class SkStrokeRec; - -/* - * A factory for returning batches which can draw rectangles. - */ -namespace GrRectBatchFactory { - -inline GrDrawBatch* CreateNonAAFill(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect* localRect, - const SkMatrix* localMatrix) { - if (viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective())) { - return GrNonAAFillRectBatch::CreateWithPerspective(color, viewMatrix, rect, localRect, - localMatrix); - } else { - return GrNonAAFillRectBatch::Create(color, viewMatrix, rect, localRect, localMatrix); - } -} - -inline GrDrawBatch* CreateAAFill(const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& croppedRect, - const SkRect& devRect) { - if (!paint.usesDistanceVectorField()) { - return GrAAFillRectBatch::Create(paint.getColor(), viewMatrix, croppedRect, devRect); - } else { - return GrAnalyticRectBatch::CreateAnalyticRectBatch(paint.getColor(), viewMatrix, rect, - croppedRect, devRect); - } -} - -inline GrDrawBatch* CreateAAFill(GrColor color, - const SkMatrix& viewMatrix, - const SkMatrix& localMatrix, - const SkRect& rect, - const SkRect& devRect) { - return GrAAFillRectBatch::Create(color, viewMatrix, localMatrix, rect, devRect); -} - -inline GrDrawBatch* CreateNonAAStroke(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkStrokeRec& strokeRec, - bool snapToPixelCenters) { - return GrNonAAStrokeRectBatch::Create(color, viewMatrix, rect, strokeRec, snapToPixelCenters); -} - -inline GrDrawBatch* CreateAAStroke(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkStrokeRec& stroke) { - return GrAAStrokeRectBatch::Create(color, viewMatrix, rect, stroke); -} - -// First rect is outer; second rect is inner -GrDrawBatch* CreateAAFillNestedRects(GrColor, - const SkMatrix& viewMatrix, - const SkRect rects[2]); - -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrRegionBatch.h b/gfx/skia/skia/src/gpu/batches/GrRegionBatch.h deleted file mode 100644 index d928d0a9cdd9..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrRegionBatch.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrRegionBatch_DEFINED -#define GrRegionBatch_DEFINED - -#include "GrColor.h" - -class GrDrawBatch; -class SkMatrix; -class SkRegion; - -namespace GrRegionBatch { - -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRegion& region); - -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrStencilPathBatch.h b/gfx/skia/skia/src/gpu/batches/GrStencilPathBatch.h deleted file mode 100644 index f505a531d411..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrStencilPathBatch.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrStencilPathBatch_DEFINED -#define GrStencilPathBatch_DEFINED - -#include "GrBatch.h" -#include "GrBatchFlushState.h" -#include "GrGpu.h" -#include "GrPath.h" -#include "GrPathRendering.h" -#include "GrRenderTarget.h" - -class GrStencilPathBatch final : public GrBatch { -public: - DEFINE_BATCH_CLASS_ID - - static GrBatch* Create(const SkMatrix& viewMatrix, - bool useHWAA, - GrPathRendering::FillType fillType, - bool hasStencilClip, - int numStencilBits, - const GrScissorState& scissor, - GrRenderTarget* renderTarget, - const GrPath* path) { - return new GrStencilPathBatch(viewMatrix, useHWAA, fillType, hasStencilClip, - numStencilBits, scissor, renderTarget, path); - } - - const char* name() const override { return "StencilPath"; } - - uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->uniqueID(); } - GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); } - - SkString dumpInfo() const override { - SkString string; - string.printf("PATH: 0x%p, AA:%d", fPath.get(), fUseHWAA); - string.append(INHERITED::dumpInfo()); - return string; - } - -private: - GrStencilPathBatch(const SkMatrix& viewMatrix, - bool useHWAA, - GrPathRendering::FillType fillType, - bool hasStencilClip, - int numStencilBits, - const GrScissorState& scissor, - GrRenderTarget* renderTarget, - const GrPath* path) - : INHERITED(ClassID()) - , fViewMatrix(viewMatrix) - , fUseHWAA(useHWAA) - , fStencil(GrPathRendering::GetStencilPassSettings(fillType), hasStencilClip, numStencilBits) - , fScissor(scissor) - , fRenderTarget(renderTarget) - , fPath(path) { - this->setBounds(path->getBounds(), HasAABloat::kNo, IsZeroArea::kNo); - } - - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { return false; } - - void onPrepare(GrBatchFlushState*) override {} - - void onDraw(GrBatchFlushState* state) override { - GrPathRendering::StencilPathArgs args(fUseHWAA, fRenderTarget.get(), &fViewMatrix, - &fScissor, &fStencil); - state->gpu()->pathRendering()->stencilPath(args, fPath.get()); - } - - SkMatrix fViewMatrix; - bool fUseHWAA; - GrStencilSettings fStencil; - GrScissorState fScissor; - GrPendingIOResource fRenderTarget; - GrPendingIOResource fPath; - - typedef GrBatch INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrTestBatch.h b/gfx/skia/skia/src/gpu/batches/GrTestBatch.h deleted file mode 100644 index 5bac48ac014b..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrTestBatch.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrTestBatch_DEFINED -#define GrTestBatch_DEFINED - -#include "GrBatchFlushState.h" -#include "GrGeometryProcessor.h" - -#include "batches/GrVertexBatch.h" - -/* - * A simple solid color batch only for testing purposes which actually doesn't batch at all. It - * saves having to fill out some boiler plate methods. - */ -class GrTestBatch : public GrVertexBatch { -public: - virtual const char* name() const override = 0; - - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fColor); - coverage->setUnknownSingleComponent(); - } - - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - overrides.getOverrideColorIfSet(&fColor); - - fOptimizations.fColorIgnored = !overrides.readsColor(); - fOptimizations.fUsesLocalCoords = overrides.readsLocalCoords(); - fOptimizations.fCoverageIgnored = !overrides.readsCoverage(); - } - -protected: - GrTestBatch(uint32_t classID, const SkRect& bounds, GrColor color) - : INHERITED(classID) - , fColor(color) { - // Choose some conservative values for aa bloat and zero area. - this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kYes); - } - - struct Optimizations { - bool fColorIgnored = false; - bool fUsesLocalCoords = false; - bool fCoverageIgnored = false; - }; - - GrColor color() const { return fColor; } - const Optimizations optimizations() const { return fOptimizations; } - -private: - bool onCombineIfPossible(GrBatch* t, const GrCaps&) override { - return false; - } - - GrColor fColor; - Optimizations fOptimizations; - - typedef GrVertexBatch INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrVertexBatch.cpp b/gfx/skia/skia/src/gpu/batches/GrVertexBatch.cpp deleted file mode 100644 index af3a186e1353..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrVertexBatch.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrVertexBatch.h" -#include "GrBatchFlushState.h" -#include "GrResourceProvider.h" - -GrVertexBatch::GrVertexBatch(uint32_t classID) - : INHERITED(classID) - , fBaseDrawToken(GrBatchDrawToken::AlreadyFlushedToken()) { -} - -void GrVertexBatch::onPrepare(GrBatchFlushState* state) { - Target target(state, this); - this->onPrepareDraws(&target); -} - -void* GrVertexBatch::InstancedHelper::init(Target* target, GrPrimitiveType primType, - size_t vertexStride, const GrBuffer* indexBuffer, - int verticesPerInstance, int indicesPerInstance, - int instancesToDraw) { - SkASSERT(target); - if (!indexBuffer) { - return nullptr; - } - const GrBuffer* vertexBuffer; - int firstVertex; - int vertexCount = verticesPerInstance * instancesToDraw; - void* vertices = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); - if (!vertices) { - SkDebugf("Vertices could not be allocated for instanced rendering."); - return nullptr; - } - SkASSERT(vertexBuffer); - size_t ibSize = indexBuffer->gpuMemorySize(); - int maxInstancesPerDraw = static_cast(ibSize / (sizeof(uint16_t) * indicesPerInstance)); - - fMesh.initInstanced(primType, vertexBuffer, indexBuffer, - firstVertex, verticesPerInstance, indicesPerInstance, instancesToDraw, - maxInstancesPerDraw); - return vertices; -} - -void GrVertexBatch::InstancedHelper::recordDraw(Target* target, const GrGeometryProcessor* gp) { - SkASSERT(fMesh.instanceCount()); - target->draw(gp, fMesh); -} - -void* GrVertexBatch::QuadHelper::init(Target* target, size_t vertexStride, - int quadsToDraw) { - SkAutoTUnref quadIndexBuffer( - target->resourceProvider()->refQuadIndexBuffer()); - if (!quadIndexBuffer) { - SkDebugf("Could not get quad index buffer."); - return nullptr; - } - return this->INHERITED::init(target, kTriangles_GrPrimitiveType, vertexStride, - quadIndexBuffer, kVerticesPerQuad, kIndicesPerQuad, quadsToDraw); -} - -void GrVertexBatch::onDraw(GrBatchFlushState* state) { - int currUploadIdx = 0; - int currMeshIdx = 0; - - SkASSERT(fQueuedDraws.empty() || fBaseDrawToken == state->nextTokenToFlush()); - - for (int currDrawIdx = 0; currDrawIdx < fQueuedDraws.count(); ++currDrawIdx) { - GrBatchDrawToken drawToken = state->nextTokenToFlush(); - while (currUploadIdx < fInlineUploads.count() && - fInlineUploads[currUploadIdx].fUploadBeforeToken == drawToken) { - state->doUpload(fInlineUploads[currUploadIdx++].fUpload); - } - const QueuedDraw &draw = fQueuedDraws[currDrawIdx]; - state->commandBuffer()->draw(*this->pipeline(), *draw.fGeometryProcessor.get(), - fMeshes.begin() + currMeshIdx, draw.fMeshCnt); - currMeshIdx += draw.fMeshCnt; - state->flushToken(); - } - SkASSERT(currUploadIdx == fInlineUploads.count()); - SkASSERT(currMeshIdx == fMeshes.count()); - fQueuedDraws.reset(); - fInlineUploads.reset(); -} - -////////////////////////////////////////////////////////////////////////////// - -void GrVertexBatch::Target::draw(const GrGeometryProcessor* gp, const GrMesh& mesh) { - GrVertexBatch* batch = this->vertexBatch(); - batch->fMeshes.push_back(mesh); - if (!batch->fQueuedDraws.empty()) { - // If the last draw shares a geometry processor and there are no intervening uploads, - // add this mesh to it. - GrVertexBatch::QueuedDraw& lastDraw = this->vertexBatch()->fQueuedDraws.back(); - if (lastDraw.fGeometryProcessor == gp && - (batch->fInlineUploads.empty() || - batch->fInlineUploads.back().fUploadBeforeToken != this->nextDrawToken())) { - ++lastDraw.fMeshCnt; - return; - } - } - GrVertexBatch::QueuedDraw& draw = this->vertexBatch()->fQueuedDraws.push_back(); - GrBatchDrawToken token = this->state()->issueDrawToken(); - draw.fGeometryProcessor.reset(gp); - draw.fMeshCnt = 1; - if (batch->fQueuedDraws.count() == 1) { - batch->fBaseDrawToken = token; - } -} diff --git a/gfx/skia/skia/src/gpu/batches/GrVertexBatch.h b/gfx/skia/skia/src/gpu/batches/GrVertexBatch.h deleted file mode 100644 index 19475a7afd5e..000000000000 --- a/gfx/skia/skia/src/gpu/batches/GrVertexBatch.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrVertexBatch_DEFINED -#define GrVertexBatch_DEFINED - -#include "GrDrawBatch.h" -#include "GrGeometryProcessor.h" -#include "GrMesh.h" -#include "GrPendingProgramElement.h" - -#include "SkTLList.h" - -class GrBatchFlushState; - -/** - * Base class for vertex-based GrBatches. - */ -class GrVertexBatch : public GrDrawBatch { -public: - class Target; - - GrVertexBatch(uint32_t classID); - -protected: - /** Helper for rendering instances using an instanced index index buffer. This class creates the - space for the vertices and flushes the draws to the batch target. */ - class InstancedHelper { - public: - InstancedHelper() {} - /** Returns the allocated storage for the vertices. The caller should populate the vertices - before calling recordDraws(). */ - void* init(Target*, GrPrimitiveType, size_t vertexStride, - const GrBuffer*, int verticesPerInstance, int indicesPerInstance, - int instancesToDraw); - - /** Call after init() to issue draws to the batch target.*/ - void recordDraw(Target*, const GrGeometryProcessor*); - private: - GrMesh fMesh; - }; - - static const int kVerticesPerQuad = 4; - static const int kIndicesPerQuad = 6; - - /** A specialization of InstanceHelper for quad rendering. */ - class QuadHelper : private InstancedHelper { - public: - QuadHelper() : INHERITED() {} - /** Finds the cached quad index buffer and reserves vertex space. Returns nullptr on failure - and on success a pointer to the vertex data that the caller should populate before - calling recordDraws(). */ - void* init(Target*, size_t vertexStride, int quadsToDraw); - - using InstancedHelper::recordDraw; - private: - typedef InstancedHelper INHERITED; - }; - -private: - void onPrepare(GrBatchFlushState* state) final; - void onDraw(GrBatchFlushState* state) final; - - virtual void onPrepareDraws(Target*) const = 0; - - // A set of contiguous draws that share a draw token and primitive processor. The draws all use - // the batch's pipeline. The meshes for the draw are stored in the fMeshes array and each - // Queued draw uses fMeshCnt meshes from the fMeshes array. The reason for coallescing meshes - // that share a primitive processor into a QueuedDraw is that it allows the Gpu object to setup - // the shared state once and then issue draws for each mesh. - struct QueuedDraw { - int fMeshCnt = 0; - GrPendingProgramElement fGeometryProcessor; - }; - - // All draws in all the vertex batches have implicit tokens based on the order they are - // enqueued globally across all batches. This is the offset of the first entry in fQueuedDraws. - // fQueuedDraws[i]'s token is fBaseDrawToken + i. - GrBatchDrawToken fBaseDrawToken; - - SkSTArray<4, GrMesh> fMeshes; - SkSTArray<4, QueuedDraw, true> fQueuedDraws; - - typedef GrDrawBatch INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/effects/Gr1DKernelEffect.h b/gfx/skia/skia/src/gpu/effects/Gr1DKernelEffect.h index d7402e8c4594..c8d6a55f32cd 100644 --- a/gfx/skia/skia/src/gpu/effects/Gr1DKernelEffect.h +++ b/gfx/skia/skia/src/gpu/effects/Gr1DKernelEffect.h @@ -28,14 +28,14 @@ public: kY_Direction, }; - Gr1DKernelEffect(GrTexture* texture, - Direction direction, - int radius) - : INHERITED(texture, nullptr, GrCoordTransform::MakeDivByTextureWHMatrix(texture)) + Gr1DKernelEffect(GrResourceProvider* resourceProvider, OptimizationFlags optFlags, + sk_sp proxy, Direction direction, int radius) + : INHERITED(resourceProvider, optFlags, std::move(proxy), nullptr, SkMatrix::I()) , fDirection(direction) - , fRadius(radius) {} + , fRadius(radius) { + } - virtual ~Gr1DKernelEffect() {} + ~Gr1DKernelEffect() override {} static int WidthFromRadius(int radius) { return 2 * radius + 1; } @@ -51,7 +51,6 @@ public: } private: - Direction fDirection; int fRadius; diff --git a/gfx/skia/skia/src/gpu/effects/GrBezierEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrBezierEffect.cpp index 798695d4eced..58243ea635e1 100644 --- a/gfx/skia/skia/src/gpu/effects/GrBezierEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrBezierEffect.cpp @@ -6,7 +6,7 @@ */ #include "GrBezierEffect.h" - +#include "GrShaderCaps.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" @@ -22,7 +22,7 @@ public: void onEmitCode(EmitArgs&, GrGPArgs*) override; static inline void GenKey(const GrGeometryProcessor&, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder*); void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc, @@ -83,9 +83,7 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color - if (!gp.colorIgnored()) { - this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); - } + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); // Setup position this->setupPosition(vertBuilder, @@ -109,21 +107,21 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { // Additionally we should assert that the upstream code only lets us get here if // either high or medium provides the required number of bits. GrSLPrecision precision = kHigh_GrSLPrecision; - const GrShaderCaps::PrecisionInfo& highP = args.fGLSLCaps->getFloatShaderPrecisionInfo( + const GrShaderCaps::PrecisionInfo& highP = args.fShaderCaps->getFloatShaderPrecisionInfo( kFragment_GrShaderType, kHigh_GrSLPrecision); if (!highP.supported()) { precision = kMedium_GrSLPrecision; } - GrGLSLShaderVar edgeAlpha("edgeAlpha", kFloat_GrSLType, 0, precision); - GrGLSLShaderVar dklmdx("dklmdx", kVec3f_GrSLType, 0, precision); - GrGLSLShaderVar dklmdy("dklmdy", kVec3f_GrSLType, 0, precision); - GrGLSLShaderVar dfdx("dfdx", kFloat_GrSLType, 0, precision); - GrGLSLShaderVar dfdy("dfdy", kFloat_GrSLType, 0, precision); - GrGLSLShaderVar gF("gF", kVec2f_GrSLType, 0, precision); - GrGLSLShaderVar gFM("gFM", kFloat_GrSLType, 0, precision); - GrGLSLShaderVar func("func", kFloat_GrSLType, 0, precision); + GrShaderVar edgeAlpha("edgeAlpha", kFloat_GrSLType, 0, precision); + GrShaderVar dklmdx("dklmdx", kVec3f_GrSLType, 0, precision); + GrShaderVar dklmdy("dklmdy", kVec3f_GrSLType, 0, precision); + GrShaderVar dfdx("dfdx", kFloat_GrSLType, 0, precision); + GrShaderVar dfdy("dfdy", kFloat_GrSLType, 0, precision); + GrShaderVar gF("gF", kVec2f_GrSLType, 0, precision); + GrShaderVar gFM("gFM", kFloat_GrSLType, 0, precision); + GrShaderVar func("func", kFloat_GrSLType, 0, precision); fragBuilder->declAppend(edgeAlpha); fragBuilder->declAppend(dklmdx); @@ -136,8 +134,6 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { switch (fEdgeType) { case kHairlineAA_GrProcessorEdgeType: { - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", @@ -165,8 +161,6 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { break; } case kFillAA_GrProcessorEdgeType: { - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); fragBuilder->codeAppendf("%s =" @@ -188,7 +182,7 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); fragBuilder->codeAppendf("%s = %s / %s;", edgeAlpha.c_str(), func.c_str(), gFM.c_str()); - fragBuilder->codeAppendf("%s = clamp(1.0 - %s, 0.0, 1.0);", + fragBuilder->codeAppendf("%s = clamp(0.5 - %s, 0.0, 1.0);", edgeAlpha.c_str(), edgeAlpha.c_str()); // Add line below for smooth cubic ramp // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);"); @@ -221,11 +215,10 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { } void GrGLConicEffect::GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrConicEffect& ce = gp.cast(); uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2; - key |= GrColor_ILLEGAL != ce.color() ? 0x4 : 0x0; key |= 0xff != ce.coverageScale() ? 0x8 : 0x0; key |= ce.usesLocalCoords() && ce.localMatrix().hasPerspective() ? 0x10 : 0x0; key |= ComputePosKey(ce.viewMatrix()) << 5; @@ -236,12 +229,12 @@ void GrGLConicEffect::GenKey(const GrGeometryProcessor& gp, GrConicEffect::~GrConicEffect() {} -void GrConicEffect::getGLSLProcessorKey(const GrGLSLCaps& caps, +void GrConicEffect::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLConicEffect::GenKey(*this, caps, b); } -GrGLSLPrimitiveProcessor* GrConicEffect::createGLSLInstance(const GrGLSLCaps&) const { +GrGLSLPrimitiveProcessor* GrConicEffect::createGLSLInstance(const GrShaderCaps&) const { return new GrGLConicEffect(*this); } @@ -264,6 +257,7 @@ GrConicEffect::GrConicEffect(GrColor color, const SkMatrix& viewMatrix, uint8_t GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrConicEffect); +#if GR_TEST_UTILS sk_sp GrConicEffect::TestCreate(GrProcessorTestData* d) { sk_sp gp; do { @@ -271,11 +265,12 @@ sk_sp GrConicEffect::TestCreate(GrProcessorTestData* d) { static_cast( d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt)); gp = GrConicEffect::Make(GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom), - edgeType, *d->fCaps, - GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); + edgeType, *d->caps(), GrTest::TestMatrix(d->fRandom), + d->fRandom->nextBool()); } while (nullptr == gp); return gp; } +#endif ////////////////////////////////////////////////////////////////////////////// // Quad @@ -288,7 +283,7 @@ public: void onEmitCode(EmitArgs&, GrGPArgs*) override; static inline void GenKey(const GrGeometryProcessor&, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder*); void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc, @@ -349,9 +344,7 @@ void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color - if (!gp.colorIgnored()) { - this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); - } + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); // Setup position this->setupPosition(vertBuilder, @@ -374,8 +367,6 @@ void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { switch (fEdgeType) { case kHairlineAA_GrProcessorEdgeType: { - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); fragBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn()); fragBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn()); fragBuilder->codeAppendf("vec2 gF = vec2(2.0 * %s.x * duvdx.x - duvdx.y," @@ -390,8 +381,6 @@ void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { break; } case kFillAA_GrProcessorEdgeType: { - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); fragBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn()); fragBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn()); fragBuilder->codeAppendf("vec2 gF = vec2(2.0 * %s.x * duvdx.x - duvdx.y," @@ -400,7 +389,7 @@ void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { fragBuilder->codeAppendf("edgeAlpha = (%s.x * %s.x - %s.y);", v.fsIn(), v.fsIn(), v.fsIn()); fragBuilder->codeAppend("edgeAlpha = edgeAlpha / sqrt(dot(gF, gF));"); - fragBuilder->codeAppend("edgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);"); + fragBuilder->codeAppend("edgeAlpha = clamp(0.5 - edgeAlpha, 0.0, 1.0);"); // Add line below for smooth cubic ramp // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);"); break; @@ -429,11 +418,10 @@ void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { } void GrGLQuadEffect::GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrQuadEffect& ce = gp.cast(); uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2; - key |= ce.color() != GrColor_ILLEGAL ? 0x4 : 0x0; key |= ce.coverageScale() != 0xff ? 0x8 : 0x0; key |= ce.usesLocalCoords() && ce.localMatrix().hasPerspective() ? 0x10 : 0x0; key |= ComputePosKey(ce.viewMatrix()) << 5; @@ -444,12 +432,12 @@ void GrGLQuadEffect::GenKey(const GrGeometryProcessor& gp, GrQuadEffect::~GrQuadEffect() {} -void GrQuadEffect::getGLSLProcessorKey(const GrGLSLCaps& caps, +void GrQuadEffect::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLQuadEffect::GenKey(*this, caps, b); } -GrGLSLPrimitiveProcessor* GrQuadEffect::createGLSLInstance(const GrGLSLCaps&) const { +GrGLSLPrimitiveProcessor* GrQuadEffect::createGLSLInstance(const GrShaderCaps&) const { return new GrGLQuadEffect(*this); } @@ -472,19 +460,19 @@ GrQuadEffect::GrQuadEffect(GrColor color, const SkMatrix& viewMatrix, uint8_t co GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrQuadEffect); +#if GR_TEST_UTILS sk_sp GrQuadEffect::TestCreate(GrProcessorTestData* d) { sk_sp gp; do { GrPrimitiveEdgeType edgeType = static_cast( d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt)); - gp = GrQuadEffect::Make(GrRandomColor(d->fRandom), - GrTest::TestMatrix(d->fRandom), - edgeType, *d->fCaps, - GrTest::TestMatrix(d->fRandom), + gp = GrQuadEffect::Make(GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom), edgeType, + *d->caps(), GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); } while (nullptr == gp); return gp; } +#endif ////////////////////////////////////////////////////////////////////////////// // Cubic @@ -497,7 +485,7 @@ public: void onEmitCode(EmitArgs&, GrGPArgs*) override; static inline void GenKey(const GrGeometryProcessor&, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder*); void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc, @@ -572,14 +560,14 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { args.fFPCoordTransformHandler); - GrGLSLShaderVar edgeAlpha("edgeAlpha", kFloat_GrSLType, 0, kHigh_GrSLPrecision); - GrGLSLShaderVar dklmdx("dklmdx", kVec3f_GrSLType, 0, kHigh_GrSLPrecision); - GrGLSLShaderVar dklmdy("dklmdy", kVec3f_GrSLType, 0, kHigh_GrSLPrecision); - GrGLSLShaderVar dfdx("dfdx", kFloat_GrSLType, 0, kHigh_GrSLPrecision); - GrGLSLShaderVar dfdy("dfdy", kFloat_GrSLType, 0, kHigh_GrSLPrecision); - GrGLSLShaderVar gF("gF", kVec2f_GrSLType, 0, kHigh_GrSLPrecision); - GrGLSLShaderVar gFM("gFM", kFloat_GrSLType, 0, kHigh_GrSLPrecision); - GrGLSLShaderVar func("func", kFloat_GrSLType, 0, kHigh_GrSLPrecision); + GrShaderVar edgeAlpha("edgeAlpha", kFloat_GrSLType, 0, kHigh_GrSLPrecision); + GrShaderVar dklmdx("dklmdx", kVec3f_GrSLType, 0, kHigh_GrSLPrecision); + GrShaderVar dklmdy("dklmdy", kVec3f_GrSLType, 0, kHigh_GrSLPrecision); + GrShaderVar dfdx("dfdx", kFloat_GrSLType, 0, kHigh_GrSLPrecision); + GrShaderVar dfdy("dfdy", kFloat_GrSLType, 0, kHigh_GrSLPrecision); + GrShaderVar gF("gF", kVec2f_GrSLType, 0, kHigh_GrSLPrecision); + GrShaderVar gFM("gFM", kFloat_GrSLType, 0, kHigh_GrSLPrecision); + GrShaderVar func("func", kFloat_GrSLType, 0, kHigh_GrSLPrecision); fragBuilder->declAppend(edgeAlpha); fragBuilder->declAppend(dklmdx); @@ -592,8 +580,6 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { switch (fEdgeType) { case kHairlineAA_GrProcessorEdgeType: { - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); fragBuilder->codeAppendf("%s = 3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", @@ -620,8 +606,6 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { break; } case kFillAA_GrProcessorEdgeType: { - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); fragBuilder->codeAppendf("%s =" @@ -639,7 +623,7 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); fragBuilder->codeAppendf("%s = %s / %s;", edgeAlpha.c_str(), func.c_str(), gFM.c_str()); - fragBuilder->codeAppendf("%s = clamp(1.0 - %s, 0.0, 1.0);", + fragBuilder->codeAppendf("%s = clamp(0.5 - %s, 0.0, 1.0);", edgeAlpha.c_str(), edgeAlpha.c_str()); // Add line below for smooth cubic ramp // fragBuilder->codeAppendf("%s = %s * %s * (3.0 - 2.0 * %s);", @@ -663,11 +647,10 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { } void GrGLCubicEffect::GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrCubicEffect& ce = gp.cast(); uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2; - key |= ce.color() != GrColor_ILLEGAL ? 0x4 : 0x8; key |= ComputePosKey(ce.viewMatrix()) << 5; b->add32(key); } @@ -676,11 +659,11 @@ void GrGLCubicEffect::GenKey(const GrGeometryProcessor& gp, GrCubicEffect::~GrCubicEffect() {} -void GrCubicEffect::getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { +void GrCubicEffect::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLCubicEffect::GenKey(*this, caps, b); } -GrGLSLPrimitiveProcessor* GrCubicEffect::createGLSLInstance(const GrGLSLCaps&) const { +GrGLSLPrimitiveProcessor* GrCubicEffect::createGLSLInstance(const GrShaderCaps&) const { return new GrGLCubicEffect(*this); } @@ -699,14 +682,16 @@ GrCubicEffect::GrCubicEffect(GrColor color, const SkMatrix& viewMatrix, GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrCubicEffect); +#if GR_TEST_UTILS sk_sp GrCubicEffect::TestCreate(GrProcessorTestData* d) { sk_sp gp; do { GrPrimitiveEdgeType edgeType = static_cast( d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt)); - gp = GrCubicEffect::Make(GrRandomColor(d->fRandom), - GrTest::TestMatrix(d->fRandom), edgeType, *d->fCaps); + gp = GrCubicEffect::Make(GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom), + edgeType, *d->caps()); } while (nullptr == gp); return gp; } +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrBezierEffect.h b/gfx/skia/skia/src/gpu/effects/GrBezierEffect.h index 50dca99242d2..3a130ec187a4 100644 --- a/gfx/skia/skia/src/gpu/effects/GrBezierEffect.h +++ b/gfx/skia/skia/src/gpu/effects/GrBezierEffect.h @@ -11,7 +11,6 @@ #include "GrCaps.h" #include "GrProcessor.h" #include "GrGeometryProcessor.h" -#include "GrInvariantOutput.h" #include "GrTypesPriv.h" /** @@ -90,7 +89,7 @@ public: } } - virtual ~GrConicEffect(); + ~GrConicEffect() override; const char* name() const override { return "Conic"; } @@ -100,15 +99,14 @@ public: inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } const SkMatrix& viewMatrix() const { return fViewMatrix; } const SkMatrix& localMatrix() const { return fLocalMatrix; } bool usesLocalCoords() const { return fUsesLocalCoords; } uint8_t coverageScale() const { return fCoverageScale; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: GrConicEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType, @@ -173,7 +171,7 @@ public: } } - virtual ~GrQuadEffect(); + ~GrQuadEffect() override; const char* name() const override { return "Quad"; } @@ -183,15 +181,14 @@ public: inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } const SkMatrix& viewMatrix() const { return fViewMatrix; } const SkMatrix& localMatrix() const { return fLocalMatrix; } bool usesLocalCoords() const { return fUsesLocalCoords; } uint8_t coverageScale() const { return fCoverageScale; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: GrQuadEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType, @@ -251,7 +248,7 @@ public: } } - virtual ~GrCubicEffect(); + ~GrCubicEffect() override; const char* name() const override { return "Cubic"; } @@ -264,9 +261,9 @@ public: bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } const SkMatrix& viewMatrix() const { return fViewMatrix; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: GrCubicEffect(GrColor, const SkMatrix& viewMatrix, GrPrimitiveEdgeType); diff --git a/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.cpp index 737625ffed53..c60400e383f7 100644 --- a/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.cpp @@ -6,27 +6,20 @@ */ #include "GrBicubicEffect.h" -#include "GrInvariantOutput.h" + +#include "GrProxyMove.h" +#include "GrTextureProxy.h" #include "glsl/GrGLSLColorSpaceXformHelper.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" - -#define DS(x) SkDoubleToScalar(x) - -const SkScalar GrBicubicEffect::gMitchellCoefficients[16] = { - DS( 1.0 / 18.0), DS(-9.0 / 18.0), DS( 15.0 / 18.0), DS( -7.0 / 18.0), - DS(16.0 / 18.0), DS( 0.0 / 18.0), DS(-36.0 / 18.0), DS( 21.0 / 18.0), - DS( 1.0 / 18.0), DS( 9.0 / 18.0), DS( 27.0 / 18.0), DS(-21.0 / 18.0), - DS( 0.0 / 18.0), DS( 0.0 / 18.0), DS( -6.0 / 18.0), DS( 7.0 / 18.0), -}; - +#include "../private/GrGLSL.h" class GrGLBicubicEffect : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor& effect, const GrGLSLCaps&, + static inline void GenKey(const GrProcessor& effect, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrBicubicEffect& bicubicEffect = effect.cast(); b->add32(GrTextureDomain::GLDomain::DomainKey(bicubicEffect.domain())); @@ -34,14 +27,13 @@ public: } protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; - UniformHandle fCoefficientsUni; UniformHandle fImageIncrementUni; - UniformHandle fColorSpaceXformUni; + GrGLSLColorSpaceXformHelper fColorSpaceHelper; GrTextureDomain::GLDomain fDomain; typedef GrGLSLFragmentProcessor INHERITED; @@ -51,48 +43,51 @@ void GrGLBicubicEffect::emitCode(EmitArgs& args) { const GrBicubicEffect& bicubicEffect = args.fFp.cast(); GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - fCoefficientsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kMat44f_GrSLType, kDefault_GrSLPrecision, - "Coefficients"); fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, "ImageIncrement"); const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); - const char* coeff = uniformHandler->getUniformCStr(fCoefficientsUni); - GrGLSLColorSpaceXformHelper colorSpaceHelper(uniformHandler, bicubicEffect.colorSpaceXform(), - &fColorSpaceXformUni); + fColorSpaceHelper.emitCode(uniformHandler, bicubicEffect.colorSpaceXform()); - SkString cubicBlendName; - - static const GrGLSLShaderVar gCubicBlendArgs[] = { - GrGLSLShaderVar("coefficients", kMat44f_GrSLType), - GrGLSLShaderVar("t", kFloat_GrSLType), - GrGLSLShaderVar("c0", kVec4f_GrSLType), - GrGLSLShaderVar("c1", kVec4f_GrSLType), - GrGLSLShaderVar("c2", kVec4f_GrSLType), - GrGLSLShaderVar("c3", kVec4f_GrSLType), - }; GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); - fragBuilder->emitFunction(kVec4f_GrSLType, - "cubicBlend", - SK_ARRAY_COUNT(gCubicBlendArgs), - gCubicBlendArgs, - "\tvec4 ts = vec4(1.0, t, t * t, t * t * t);\n" - "\tvec4 c = coefficients * ts;\n" - "\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n", - &cubicBlendName); - fragBuilder->codeAppendf("\tvec2 coord = %s - %s * vec2(0.5);\n", coords2D.c_str(), imgInc); + + /* + * Filter weights come from Don Mitchell & Arun Netravali's 'Reconstruction Filters in Computer + * Graphics', ACM SIGGRAPH Computer Graphics 22, 4 (Aug. 1988). + * ACM DL: http://dl.acm.org/citation.cfm?id=378514 + * Free : http://www.cs.utexas.edu/users/fussell/courses/cs384g/lectures/mitchell/Mitchell.pdf + * + * The authors define a family of cubic filters with two free parameters (B and C): + * + * { (12 - 9B - 6C)|x|^3 + (-18 + 12B + 6C)|x|^2 + (6 - 2B) if |x| < 1 + * k(x) = 1/6 { (-B - 6C)|x|^3 + (6B + 30C)|x|^2 + (-12B - 48C)|x| + (8B + 24C) if 1 <= |x| < 2 + * { 0 otherwise + * + * Various well-known cubic splines can be generated, and the authors select (1/3, 1/3) as their + * favorite overall spline - this is now commonly known as the Mitchell filter, and is the + * source of the specific weights below. + * + * This is GLSL, so the matrix is column-major (transposed from standard matrix notation). + */ + fragBuilder->codeAppend("mat4 kMitchellCoefficients = mat4(" + " 1.0 / 18.0, 16.0 / 18.0, 1.0 / 18.0, 0.0 / 18.0," + "-9.0 / 18.0, 0.0 / 18.0, 9.0 / 18.0, 0.0 / 18.0," + "15.0 / 18.0, -36.0 / 18.0, 27.0 / 18.0, -6.0 / 18.0," + "-7.0 / 18.0, 21.0 / 18.0, -21.0 / 18.0, 7.0 / 18.0);"); + fragBuilder->codeAppendf("vec2 coord = %s - %s * vec2(0.5);", coords2D.c_str(), imgInc); // We unnormalize the coord in order to determine our fractional offset (f) within the texel // We then snap coord to a texel center and renormalize. The snap prevents cases where the // starting coords are near a texel boundary and accumulations of imgInc would cause us to skip/ // double hit a texel. - fragBuilder->codeAppendf("\tcoord /= %s;\n", imgInc); - fragBuilder->codeAppend("\tvec2 f = fract(coord);\n"); - fragBuilder->codeAppendf("\tcoord = (coord - f + vec2(0.5)) * %s;\n", imgInc); - fragBuilder->codeAppend("\tvec4 rowColors[4];\n"); + fragBuilder->codeAppendf("coord /= %s;", imgInc); + fragBuilder->codeAppend("vec2 f = fract(coord);"); + fragBuilder->codeAppendf("coord = (coord - f + vec2(0.5)) * %s;", imgInc); + fragBuilder->codeAppend("vec4 wx = kMitchellCoefficients * vec4(1.0, f.x, f.x * f.x, f.x * f.x * f.x);"); + fragBuilder->codeAppend("vec4 wy = kMitchellCoefficients * vec4(1.0, f.y, f.y * f.y, f.y * f.y * f.y);"); + fragBuilder->codeAppend("vec4 rowColors[4];"); for (int y = 0; y < 4; ++y) { for (int x = 0; x < 4; ++x) { SkString coord; @@ -101,82 +96,70 @@ void GrGLBicubicEffect::emitCode(EmitArgs& args) { sampleVar.printf("rowColors[%d]", x); fDomain.sampleTexture(fragBuilder, args.fUniformHandler, - args.fGLSLCaps, + args.fShaderCaps, bicubicEffect.domain(), sampleVar.c_str(), coord, args.fTexSamplers[0]); } fragBuilder->codeAppendf( - "\tvec4 s%d = %s(%s, f.x, rowColors[0], rowColors[1], rowColors[2], rowColors[3]);\n", - y, cubicBlendName.c_str(), coeff); + "vec4 s%d = wx.x * rowColors[0] + wx.y * rowColors[1] + wx.z * rowColors[2] + wx.w * rowColors[3];", + y); } - SkString bicubicColor; - bicubicColor.printf("%s(%s, f.y, s0, s1, s2, s3)", cubicBlendName.c_str(), coeff); - if (colorSpaceHelper.getXformMatrix()) { + SkString bicubicColor("(wy.x * s0 + wy.y * s1 + wy.z * s2 + wy.w * s3)"); + if (fColorSpaceHelper.isValid()) { SkString xformedColor; - fragBuilder->appendColorGamutXform(&xformedColor, bicubicColor.c_str(), &colorSpaceHelper); + fragBuilder->appendColorGamutXform(&xformedColor, bicubicColor.c_str(), &fColorSpaceHelper); bicubicColor.swap(xformedColor); } - fragBuilder->codeAppendf("\t%s = %s;\n", + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, (GrGLSLExpr4(bicubicColor.c_str()) * GrGLSLExpr4(args.fInputColor)).c_str()); } void GrGLBicubicEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrFragmentProcessor& processor) { const GrBicubicEffect& bicubicEffect = processor.cast(); - const GrTexture& texture = *processor.texture(0); + GrTexture* texture = processor.textureSampler(0).texture(); float imageIncrement[2]; - imageIncrement[0] = 1.0f / texture.width(); - imageIncrement[1] = 1.0f / texture.height(); + imageIncrement[0] = 1.0f / texture->width(); + imageIncrement[1] = 1.0f / texture->height(); pdman.set2fv(fImageIncrementUni, 1, imageIncrement); - pdman.setMatrix4f(fCoefficientsUni, bicubicEffect.coefficients()); - fDomain.setData(pdman, bicubicEffect.domain(), texture.origin()); + fDomain.setData(pdman, bicubicEffect.domain(), texture); if (SkToBool(bicubicEffect.colorSpaceXform())) { - pdman.setSkMatrix44(fColorSpaceXformUni, bicubicEffect.colorSpaceXform()->srcToDst()); + fColorSpaceHelper.setData(pdman, bicubicEffect.colorSpaceXform()); } } -static inline void convert_row_major_scalar_coeffs_to_column_major_floats(float dst[16], - const SkScalar src[16]) { - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 4; x++) { - dst[x * 4 + y] = SkScalarToFloat(src[y * 4 + x]); - } - } -} - -GrBicubicEffect::GrBicubicEffect(GrTexture* texture, +GrBicubicEffect::GrBicubicEffect(GrResourceProvider* resourceProvider, sk_sp proxy, sk_sp colorSpaceXform, - const SkScalar coefficients[16], const SkMatrix &matrix, const SkShader::TileMode tileModes[2]) - : INHERITED(texture, nullptr, matrix, - GrTextureParams(tileModes, GrTextureParams::kNone_FilterMode)) - , fDomain(GrTextureDomain::IgnoredDomain()) - , fColorSpaceXform(std::move(colorSpaceXform)) { + : INHERITED{resourceProvider, + ModulationFlags(proxy->config()), + GR_PROXY_MOVE(proxy), + std::move(colorSpaceXform), + matrix, + GrSamplerParams(tileModes, GrSamplerParams::kNone_FilterMode)} + , fDomain(GrTextureDomain::IgnoredDomain()) { this->initClassID(); - convert_row_major_scalar_coeffs_to_column_major_floats(fCoefficients, coefficients); } -GrBicubicEffect::GrBicubicEffect(GrTexture* texture, +GrBicubicEffect::GrBicubicEffect(GrResourceProvider* resourceProvider, sk_sp proxy, sk_sp colorSpaceXform, - const SkScalar coefficients[16], const SkMatrix &matrix, const SkRect& domain) - : INHERITED(texture, nullptr, matrix, - GrTextureParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode)) - , fDomain(domain, GrTextureDomain::kClamp_Mode) - , fColorSpaceXform(std::move(colorSpaceXform)) { + : INHERITED(resourceProvider, ModulationFlags(proxy->config()), proxy, + std::move(colorSpaceXform), matrix, + GrSamplerParams(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode)) + , fDomain(proxy.get(), domain, GrTextureDomain::kClamp_Mode) { this->initClassID(); - convert_row_major_scalar_coeffs_to_column_major_floats(fCoefficients, coefficients); } GrBicubicEffect::~GrBicubicEffect() { } -void GrBicubicEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrBicubicEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLBicubicEffect::GenKey(*this, caps, b); } @@ -187,34 +170,30 @@ GrGLSLFragmentProcessor* GrBicubicEffect::onCreateGLSLInstance() const { bool GrBicubicEffect::onIsEqual(const GrFragmentProcessor& sBase) const { const GrBicubicEffect& s = sBase.cast(); - return !memcmp(fCoefficients, s.coefficients(), 16) && - fDomain == s.fDomain; -} - -void GrBicubicEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - // FIXME: Perhaps we can do better. - inout->mulByUnknownSingleComponent(); + return fDomain == s.fDomain; } GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrBicubicEffect); +#if GR_TEST_UTILS sk_sp GrBicubicEffect::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; - SkScalar coefficients[16]; - for (int i = 0; i < 16; i++) { - coefficients[i] = d->fRandom->nextSScalar1(); - } - auto colorSpaceXform = GrTest::TestColorXform(d->fRandom); - return GrBicubicEffect::Make(d->fTextures[texIdx], colorSpaceXform, coefficients); + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp colorSpaceXform = GrTest::TestColorXform(d->fRandom); + static const SkShader::TileMode kClampClamp[] = + { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode }; + return GrBicubicEffect::Make(d->resourceProvider(), + d->textureProxy(texIdx), std::move(colorSpaceXform), + SkMatrix::I(), kClampClamp); } +#endif ////////////////////////////////////////////////////////////////////////////// bool GrBicubicEffect::ShouldUseBicubic(const SkMatrix& matrix, - GrTextureParams::FilterMode* filterMode) { + GrSamplerParams::FilterMode* filterMode) { if (matrix.isIdentity()) { - *filterMode = GrTextureParams::kNone_FilterMode; + *filterMode = GrSamplerParams::kNone_FilterMode; return false; } @@ -222,22 +201,22 @@ bool GrBicubicEffect::ShouldUseBicubic(const SkMatrix& matrix, if (!matrix.getMinMaxScales(scales) || scales[0] < SK_Scalar1) { // Bicubic doesn't handle arbitrary minimization well, as src texels can be skipped // entirely, - *filterMode = GrTextureParams::kMipMap_FilterMode; + *filterMode = GrSamplerParams::kMipMap_FilterMode; return false; } // At this point if scales[1] == SK_Scalar1 then the matrix doesn't do any scaling. if (scales[1] == SK_Scalar1) { if (matrix.rectStaysRect() && SkScalarIsInt(matrix.getTranslateX()) && SkScalarIsInt(matrix.getTranslateY())) { - *filterMode = GrTextureParams::kNone_FilterMode; + *filterMode = GrSamplerParams::kNone_FilterMode; } else { // Use bilerp to handle rotation or fractional translation. - *filterMode = GrTextureParams::kBilerp_FilterMode; + *filterMode = GrSamplerParams::kBilerp_FilterMode; } return false; } // When we use the bicubic filtering effect each sample is read from the texture using // nearest neighbor sampling. - *filterMode = GrTextureParams::kNone_FilterMode; + *filterMode = GrSamplerParams::kNone_FilterMode; return true; } diff --git a/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.h b/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.h index 58bb068d5f52..7cc8c1ef79d1 100644 --- a/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.h +++ b/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.h @@ -12,7 +12,6 @@ #include "GrTextureDomain.h" #include "glsl/GrGLSLFragmentProcessor.h" -class GrGLBicubicEffect; class GrInvariantOutput; class GrBicubicEffect : public GrSingleTextureEffect { @@ -21,68 +20,36 @@ public: kFilterTexelPad = 2, // Given a src rect in texels to be filtered, this number of // surrounding texels are needed by the kernel in x and y. }; - virtual ~GrBicubicEffect(); - - const float* coefficients() const { return fCoefficients; } + ~GrBicubicEffect() override; const char* name() const override { return "Bicubic"; } const GrTextureDomain& domain() const { return fDomain; } - GrColorSpaceXform* colorSpaceXform() const { return fColorSpaceXform.get(); } - - /** - * Create a simple filter effect with custom bicubic coefficients and optional domain. - */ - static sk_sp Make(GrTexture* tex, - sk_sp colorSpaceXform, - const SkScalar coefficients[16], - const SkRect* domain = nullptr) { - if (nullptr == domain) { - static const SkShader::TileMode kTileModes[] = { SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode }; - return Make(tex, std::move(colorSpaceXform), coefficients, - GrCoordTransform::MakeDivByTextureWHMatrix(tex), kTileModes); - } else { - return sk_sp( - new GrBicubicEffect(tex, std::move(colorSpaceXform), coefficients, - GrCoordTransform::MakeDivByTextureWHMatrix(tex), *domain)); - } - } - /** * Create a Mitchell filter effect with specified texture matrix and x/y tile modes. */ - static sk_sp Make(GrTexture* tex, + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, sk_sp colorSpaceXform, const SkMatrix& matrix, const SkShader::TileMode tileModes[2]) { - return Make(tex, std::move(colorSpaceXform), gMitchellCoefficients, matrix, tileModes); - } - - /** - * Create a filter effect with custom bicubic coefficients, the texture matrix, and the x/y - * tilemodes. - */ - static sk_sp Make(GrTexture* tex, - sk_sp colorSpaceXform, - const SkScalar coefficients[16], - const SkMatrix& matrix, - const SkShader::TileMode tileModes[2]) { - return sk_sp(new GrBicubicEffect(tex, std::move(colorSpaceXform), - coefficients, matrix, tileModes)); + return sk_sp(new GrBicubicEffect(resourceProvider, std::move(proxy), + std::move(colorSpaceXform), + matrix, tileModes)); } /** * Create a Mitchell filter effect with a texture matrix and a domain. */ - static sk_sp Make(GrTexture* tex, + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, sk_sp colorSpaceXform, const SkMatrix& matrix, const SkRect& domain) { - return sk_sp(new GrBicubicEffect(tex, std::move(colorSpaceXform), - gMitchellCoefficients, matrix, - domain)); + return sk_sp(new GrBicubicEffect(resourceProvider, std::move(proxy), + std::move(colorSpaceXform), + matrix, domain)); } /** @@ -93,30 +60,24 @@ public: * kNearest). */ static bool ShouldUseBicubic(const SkMatrix& localCoordsToDevice, - GrTextureParams::FilterMode* filterMode); + GrSamplerParams::FilterMode* filterMode); private: - GrBicubicEffect(GrTexture*, sk_sp, const SkScalar coefficients[16], + GrBicubicEffect(GrResourceProvider*, sk_sp, sk_sp, const SkMatrix &matrix, const SkShader::TileMode tileModes[2]); - GrBicubicEffect(GrTexture*, sk_sp, const SkScalar coefficients[16], + GrBicubicEffect(GrResourceProvider*, sk_sp, sk_sp, const SkMatrix &matrix, const SkRect& domain); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - float fCoefficients[16]; GrTextureDomain fDomain; - sk_sp fColorSpaceXform; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - static const SkScalar gMitchellCoefficients[16]; - typedef GrSingleTextureEffect INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp b/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp index 7f5366363f9d..527d5ce2765a 100644 --- a/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp @@ -6,7 +6,7 @@ */ #include "GrBitmapTextGeoProc.h" -#include "GrInvariantOutput.h" + #include "GrTexture.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" @@ -30,8 +30,8 @@ public: varyingHandler->emitAttributes(cte); // compute numbers to be hardcoded to convert texture coordinates from int to float - SkASSERT(cte.numTextures() == 1); - SkDEBUGCODE(GrTexture* atlas = cte.textureAccess(0).getTexture()); + SkASSERT(cte.numTextureSamplers() == 1); + SkDEBUGCODE(GrTexture* atlas = cte.textureSampler(0).texture()); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); GrGLSLVertToFrag v(kVec2f_GrSLType); @@ -41,13 +41,11 @@ public: GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color - if (!cte.colorIgnored()) { - if (cte.hasVertexColor()) { - varyingHandler->addPassThroughAttribute(cte.inColor(), args.fOutputColor); - } else { - this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, - &fColorUniform); - } + if (cte.hasVertexColor()) { + varyingHandler->addPassThroughAttribute(cte.inColor(), args.fOutputColor); + } else { + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, + &fColorUniform); } // Setup position @@ -96,18 +94,17 @@ public: } static inline void GenKey(const GrGeometryProcessor& proc, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrBitmapTextGeoProc& gp = proc.cast(); uint32_t key = 0; - key |= gp.usesLocalCoords() && gp.localMatrix().hasPerspective() ? 0x1 : 0x0; - key |= gp.colorIgnored() ? 0x2 : 0x0; - key |= gp.maskFormat() << 3; + key |= (gp.usesLocalCoords() && gp.localMatrix().hasPerspective()) ? 0x1 : 0x0; + key |= gp.maskFormat() << 1; b->add32(key); // Currently we hardcode numbers to convert atlas coordinates to normalized floating point - SkASSERT(gp.numTextures() == 1); - GrTexture* atlas = gp.textureAccess(0).getTexture(); + SkASSERT(gp.numTextureSamplers() == 1); + GrTexture* atlas = gp.textureSampler(0).texture(); SkASSERT(atlas); b->add32(atlas->width()); b->add32(atlas->height()); @@ -122,13 +119,14 @@ private: /////////////////////////////////////////////////////////////////////////////// -GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color, GrTexture* texture, - const GrTextureParams& params, GrMaskFormat format, +GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrResourceProvider* resourceProvider, GrColor color, + sk_sp proxy, + const GrSamplerParams& params, GrMaskFormat format, const SkMatrix& localMatrix, bool usesLocalCoords) : fColor(color) , fLocalMatrix(localMatrix) , fUsesLocalCoords(usesLocalCoords) - , fTextureAccess(texture, params) + , fTextureSampler(resourceProvider, std::move(proxy), params) , fInColor(nullptr) , fMaskFormat(format) { this->initClassID(); @@ -141,15 +139,15 @@ GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color, GrTexture* texture, } fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2us_GrVertexAttribType, kHigh_GrSLPrecision); - this->addTextureAccess(&fTextureAccess); + this->addTextureSampler(&fTextureSampler); } -void GrBitmapTextGeoProc::getGLSLProcessorKey(const GrGLSLCaps& caps, +void GrBitmapTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLBitmapTextGeoProc::GenKey(*this, caps, b); } -GrGLSLPrimitiveProcessor* GrBitmapTextGeoProc::createGLSLInstance(const GrGLSLCaps& caps) const { +GrGLSLPrimitiveProcessor* GrBitmapTextGeoProc::createGLSLInstance(const GrShaderCaps& caps) const { return new GrGLBitmapTextGeoProc(); } @@ -157,9 +155,12 @@ GrGLSLPrimitiveProcessor* GrBitmapTextGeoProc::createGLSLInstance(const GrGLSLCa GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc); +#if GR_TEST_UTILS sk_sp GrBitmapTextGeoProc::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); + static const SkShader::TileMode kTileModes[] = { SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, @@ -169,8 +170,8 @@ sk_sp GrBitmapTextGeoProc::TestCreate(GrProcessorTestData* kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))], kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))], }; - GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode : - GrTextureParams::kNone_FilterMode); + GrSamplerParams params(tileModes, d->fRandom->nextBool() ? GrSamplerParams::kBilerp_FilterMode + : GrSamplerParams::kNone_FilterMode); GrMaskFormat format = kARGB_GrMaskFormat; // init to avoid warning switch (d->fRandom->nextULessThan(3)) { @@ -185,7 +186,9 @@ sk_sp GrBitmapTextGeoProc::TestCreate(GrProcessorTestData* break; } - return GrBitmapTextGeoProc::Make(GrRandomColor(d->fRandom), d->fTextures[texIdx], params, - format, GrTest::TestMatrix(d->fRandom), + return GrBitmapTextGeoProc::Make(d->resourceProvider(), GrRandomColor(d->fRandom), + std::move(proxy), + params, format, GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); } +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.h b/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.h index 226ae770e77b..aa9afc2e5cfd 100644 --- a/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.h +++ b/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.h @@ -16,19 +16,21 @@ class GrInvariantOutput; /** * The output color of this effect is a modulation of the input color and a sample from a texture. - * It allows explicit specification of the filtering and wrap modes (GrTextureParams). The input + * It allows explicit specification of the filtering and wrap modes (GrSamplerParams). The input * coords are a custom attribute. */ class GrBitmapTextGeoProc : public GrGeometryProcessor { public: - static sk_sp Make(GrColor color, GrTexture* tex, const GrTextureParams& p, - GrMaskFormat format, const SkMatrix& localMatrix, - bool usesLocalCoords) { + static sk_sp Make(GrResourceProvider* resourceProvider, GrColor color, + sk_sp proxy, const GrSamplerParams& p, + GrMaskFormat format, const SkMatrix& localMatrix, + bool usesLocalCoords) { return sk_sp( - new GrBitmapTextGeoProc(color, tex, p, format, localMatrix, usesLocalCoords)); + new GrBitmapTextGeoProc(resourceProvider, color, std::move(proxy), p, format, + localMatrix, usesLocalCoords)); } - virtual ~GrBitmapTextGeoProc() {} + ~GrBitmapTextGeoProc() override {} const char* name() const override { return "Texture"; } @@ -37,23 +39,23 @@ public: const Attribute* inTextureCoords() const { return fInTextureCoords; } GrMaskFormat maskFormat() const { return fMaskFormat; } GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } bool hasVertexColor() const { return SkToBool(fInColor); } const SkMatrix& localMatrix() const { return fLocalMatrix; } bool usesLocalCoords() const { return fUsesLocalCoords; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps& caps) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override; private: - GrBitmapTextGeoProc(GrColor, GrTexture* texture, const GrTextureParams& params, + GrBitmapTextGeoProc(GrResourceProvider*, GrColor, sk_sp, + const GrSamplerParams& params, GrMaskFormat format, const SkMatrix& localMatrix, bool usesLocalCoords); GrColor fColor; SkMatrix fLocalMatrix; bool fUsesLocalCoords; - GrTextureAccess fTextureAccess; + TextureSampler fTextureSampler; const Attribute* fInPosition; const Attribute* fInColor; const Attribute* fInTextureCoords; diff --git a/gfx/skia/skia/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp b/gfx/skia/skia/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp new file mode 100644 index 000000000000..95b08d2f0dd1 --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "effects/GrBlurredEdgeFragmentProcessor.h" + +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" + +class GLSLBlurredEdgeFP : public GrGLSLFragmentProcessor { +public: + GLSLBlurredEdgeFP() {} + + void emitCode(EmitArgs& args) override { + + GrBlurredEdgeFP::Mode mode = args.fFp.cast().mode(); + + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + + fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor); + if (!args.fGpImplementsDistanceVector) { + fragBuilder->codeAppendf("// assuming interpolant is set in vertex colors\n"); + fragBuilder->codeAppendf("float factor = 1.0 - color.b;"); + } else { + fragBuilder->codeAppendf("// using distance to edge to compute interpolant\n"); + fragBuilder->codeAppend("float radius = color.r*256.0*64.0 + color.g*64.0;"); + fragBuilder->codeAppend("float pad = color.b*64.0;"); + + fragBuilder->codeAppendf("float factor = 1.0 - clamp((%s.z - pad)/radius, 0.0, 1.0);", + fragBuilder->distanceVectorName()); + } + switch (mode) { + case GrBlurredEdgeFP::kGaussian_Mode: + fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;"); + break; + case GrBlurredEdgeFP::kSmoothstep_Mode: + fragBuilder->codeAppend("factor = smoothstep(factor, 0.0, 1.0);"); + break; + } + if (!args.fGpImplementsDistanceVector) { + fragBuilder->codeAppendf("%s = vec4(factor*color.g);", args.fOutputColor); + } else { + fragBuilder->codeAppendf("%s = vec4(factor*color.a);", args.fOutputColor); + } + } + +protected: + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) override {} + + GrBlurredEdgeFP::Mode fMode; +}; + +GrGLSLFragmentProcessor* GrBlurredEdgeFP::onCreateGLSLInstance() const { + return new GLSLBlurredEdgeFP(); +} + +void GrBlurredEdgeFP::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const { + b->add32(fMode); +} + +bool GrBlurredEdgeFP::onIsEqual(const GrFragmentProcessor& other) const { + const GrBlurredEdgeFP& that = other.cast(); + return that.fMode == fMode; +} + + diff --git a/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.cpp index 80a0314ac274..566a1afac8c3 100644 --- a/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.cpp @@ -6,10 +6,10 @@ */ #include "GrConfigConversionEffect.h" +#include "../private/GrGLSL.h" +#include "GrClip.h" #include "GrContext.h" -#include "GrDrawContext.h" -#include "GrInvariantOutput.h" -#include "GrSimpleTextureEffect.h" +#include "GrRenderTargetContext.h" #include "SkMatrix.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" @@ -18,72 +18,63 @@ class GrGLConfigConversionEffect : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs& args) override { const GrConfigConversionEffect& cce = args.fFp.cast(); - const GrSwizzle& swizzle = cce.swizzle(); - GrConfigConversionEffect::PMConversion pmConversion = cce.pmConversion(); - - // Using highp for GLES here in order to avoid some precision issues on specific GPUs. - GrGLSLShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, kHigh_GrSLPrecision); - SkString tmpDecl; - tmpVar.appendDecl(args.fGLSLCaps, &tmpDecl); - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - fragBuilder->codeAppendf("%s;", tmpDecl.c_str()); + // Use highp throughout the shader to avoid some precision issues on specific GPUs. + fragBuilder->elevateDefaultPrecision(kHigh_GrSLPrecision); - fragBuilder->codeAppendf("%s = ", tmpVar.c_str()); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], args.fTransformedCoords[0].c_str(), - args.fTransformedCoords[0].getType()); - fragBuilder->codeAppend(";"); - - if (GrConfigConversionEffect::kNone_PMConversion == pmConversion) { - SkASSERT(GrSwizzle::RGBA() != swizzle); - fragBuilder->codeAppendf("%s = %s.%s;", args.fOutputColor, tmpVar.c_str(), - swizzle.c_str()); - } else { - switch (pmConversion) { - case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion: - fragBuilder->codeAppendf( - "%s = vec4(ceil(%s.rgb * %s.a * 255.0) / 255.0, %s.a);", - tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str()); - break; - case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion: - // Add a compensation(0.001) here to avoid the side effect of the floor operation. - // In Intel GPUs, the integer value converted from floor(%s.r * 255.0) / 255.0 - // is less than the integer value converted from %s.r by 1 when the %s.r is - // converted from the integer value 2^n, such as 1, 2, 4, 8, etc. - fragBuilder->codeAppendf( - "%s = vec4(floor(%s.rgb * %s.a * 255.0 + 0.001) / 255.0, %s.a);", - tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str()); - - break; - case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion: - fragBuilder->codeAppendf( - "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.rgb / %s.a * 255.0) / 255.0, %s.a);", - tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), - tmpVar.c_str()); - break; - case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion: - fragBuilder->codeAppendf( - "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.rgb / %s.a * 255.0) / 255.0, %s.a);", - tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), - tmpVar.c_str()); - break; - default: - SkFAIL("Unknown conversion op."); - break; - } - fragBuilder->codeAppendf("%s = %s.%s;", args.fOutputColor, tmpVar.c_str(), - swizzle.c_str()); + if (nullptr == args.fInputColor) { + // could optimize this case, but we aren't for now. + args.fInputColor = "vec4(1)"; } - SkString modulate; - GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); - fragBuilder->codeAppend(modulate.c_str()); + + // Aggressively round to the nearest exact (N / 255) floating point value. This lets us + // find a round-trip preserving pair on some GPUs that do odd byte to float conversion. + fragBuilder->codeAppendf("vec4 color = floor(%s * 255.0 + 0.5) / 255.0;", + args.fInputColor); + + switch (cce.pmConversion()) { + case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion: + fragBuilder->codeAppend( + "color.rgb = ceil(color.rgb * color.a * 255.0) / 255.0;"); + break; + case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion: + // Add a compensation(0.001) here to avoid the side effect of the floor operation. + // In Intel GPUs, the integer value converted from floor(%s.r * 255.0) / 255.0 + // is less than the integer value converted from %s.r by 1 when the %s.r is + // converted from the integer value 2^n, such as 1, 2, 4, 8, etc. + fragBuilder->codeAppend( + "color.rgb = floor(color.rgb * color.a * 255.0 + 0.001) / 255.0;"); + break; + case GrConfigConversionEffect::kMulByAlpha_RoundNearest_PMConversion: + fragBuilder->codeAppend( + "color.rgb = floor(color.rgb * color.a * 255.0 + 0.5) / 255.0;"); + break; + + case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion: + fragBuilder->codeAppend( + "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : ceil(color.rgb / color.a * 255.0) / 255.0;"); + break; + case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion: + fragBuilder->codeAppend( + "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : floor(color.rgb / color.a * 255.0) / 255.0;"); + break; + case GrConfigConversionEffect::kDivByAlpha_RoundNearest_PMConversion: + fragBuilder->codeAppend( + "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : floor(color.rgb / color.a * 255.0 + 0.5) / 255.0;"); + break; + + default: + SkFAIL("Unknown conversion op."); + break; + } + fragBuilder->codeAppendf("%s = color;", args.fOutputColor); } - static inline void GenKey(const GrProcessor& processor, const GrGLSLCaps&, + static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrConfigConversionEffect& cce = processor.cast(); - uint32_t key = (cce.swizzle().asKey()) | (cce.pmConversion() << 16); + uint32_t key = cce.pmConversion(); b->add32(key); } @@ -94,62 +85,31 @@ private: /////////////////////////////////////////////////////////////////////////////// -GrConfigConversionEffect::GrConfigConversionEffect(GrTexture* texture, - const GrSwizzle& swizzle, - PMConversion pmConversion, - const SkMatrix& matrix) - : INHERITED(texture, nullptr, matrix) - , fSwizzle(swizzle) - , fPMConversion(pmConversion) { +GrConfigConversionEffect::GrConfigConversionEffect(PMConversion pmConversion) + : INHERITED(kNone_OptimizationFlags) + , fPMConversion(pmConversion) { this->initClassID(); - // We expect to get here with non-BGRA/RGBA only if we're doing not doing a premul/unpremul - // conversion. - SkASSERT((kRGBA_8888_GrPixelConfig == texture->config() || - kBGRA_8888_GrPixelConfig == texture->config()) || - kNone_PMConversion == pmConversion); - // Why did we pollute our texture cache instead of using a GrSingleTextureEffect? - SkASSERT(swizzle != GrSwizzle::RGBA() || kNone_PMConversion != pmConversion); } bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const { const GrConfigConversionEffect& other = s.cast(); - return other.fSwizzle == fSwizzle && - other.fPMConversion == fPMConversion; -} - -void GrConfigConversionEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - this->updateInvariantOutputForModulation(inout); + return other.fPMConversion == fPMConversion; } /////////////////////////////////////////////////////////////////////////////// GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect); -#if !defined(__clang__) && _MSC_FULL_VER >= 190024213 -// Work around VS 2015 Update 3 optimizer bug that causes internal compiler error -//https://connect.microsoft.com/VisualStudio/feedback/details/3100520/internal-compiler-error -#pragma optimize("t", off) -#endif - +#if GR_TEST_UTILS sk_sp GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) { PMConversion pmConv = static_cast(d->fRandom->nextULessThan(kPMConversionCnt)); - GrSwizzle swizzle; - do { - swizzle = GrSwizzle::CreateRandom(d->fRandom); - } while (pmConv == kNone_PMConversion && swizzle == GrSwizzle::RGBA()); - return sk_sp( - new GrConfigConversionEffect(d->fTextures[GrProcessorUnitTest::kSkiaPMTextureIdx], - swizzle, pmConv, GrTest::TestMatrix(d->fRandom))); + return sk_sp(new GrConfigConversionEffect(pmConv)); } - -#if !defined(__clang__) && _MSC_FULL_VER >= 190024213 -// Restore optimization settings. -#pragma optimize("", on) #endif /////////////////////////////////////////////////////////////////////////////// -void GrConfigConversionEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrConfigConversionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLConfigConversionEffect::GenKey(*this, caps, b); } @@ -163,8 +123,8 @@ GrGLSLFragmentProcessor* GrConfigConversionEffect::onCreateGLSLInstance() const void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context, PMConversion* pmToUPMRule, PMConversion* upmToPMRule) { - *pmToUPMRule = kNone_PMConversion; - *upmToPMRule = kNone_PMConversion; + *pmToUPMRule = kPMConversionCnt; + *upmToPMRule = kPMConversionCnt; static constexpr int kSize = 256; static constexpr GrPixelConfig kConfig = kRGBA_8888_GrPixelConfig; SkAutoTMalloc data(kSize * kSize * 3); @@ -184,102 +144,119 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context } } - sk_sp readDC(context->makeDrawContext(SkBackingFit::kExact, kSize, kSize, - kConfig, nullptr)); - sk_sp tempDC(context->makeDrawContext(SkBackingFit::kExact, kSize, kSize, - kConfig, nullptr)); - if (!readDC || !tempDC) { + const SkImageInfo ii = SkImageInfo::Make(kSize, kSize, + kRGBA_8888_SkColorType, kPremul_SkAlphaType); + + sk_sp readRTC(context->makeRenderTargetContext(SkBackingFit::kExact, + kSize, kSize, + kConfig, nullptr)); + sk_sp tempRTC(context->makeRenderTargetContext(SkBackingFit::kExact, + kSize, kSize, + kConfig, nullptr)); + if (!readRTC || !tempRTC) { return; } GrSurfaceDesc desc; desc.fWidth = kSize; desc.fHeight = kSize; desc.fConfig = kConfig; - SkAutoTUnref dataTex(context->textureProvider()->createTexture( - desc, SkBudgeted::kYes, data, 0)); - if (!dataTex.get()) { + + GrResourceProvider* resourceProvider = context->resourceProvider(); + sk_sp dataProxy = GrSurfaceProxy::MakeDeferred(resourceProvider, desc, + SkBudgeted::kYes, data, 0); + if (!dataProxy) { return; } static const PMConversion kConversionRules[][2] = { + {kDivByAlpha_RoundNearest_PMConversion, kMulByAlpha_RoundNearest_PMConversion}, {kDivByAlpha_RoundDown_PMConversion, kMulByAlpha_RoundUp_PMConversion}, {kDivByAlpha_RoundUp_PMConversion, kMulByAlpha_RoundDown_PMConversion}, }; - bool failed = true; + uint32_t bestFailCount = 0xFFFFFFFF; + size_t bestRule = 0; - for (size_t i = 0; i < SK_ARRAY_COUNT(kConversionRules) && failed; ++i) { + for (size_t i = 0; i < SK_ARRAY_COUNT(kConversionRules) && bestFailCount; ++i) { *pmToUPMRule = kConversionRules[i][0]; *upmToPMRule = kConversionRules[i][1]; static const SkRect kDstRect = SkRect::MakeIWH(kSize, kSize); - static const SkRect kSrcRect = SkRect::MakeIWH(1, 1); + static const SkRect kSrcRect = SkRect::MakeIWH(kSize, kSize); // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data. // We then verify that two reads produced the same values. + if (!readRTC->asTextureProxy()) { + continue; + } GrPaint paint1; GrPaint paint2; GrPaint paint3; - sk_sp pmToUPM1(new GrConfigConversionEffect( - dataTex, GrSwizzle::RGBA(), *pmToUPMRule, SkMatrix::I())); - sk_sp upmToPM(new GrConfigConversionEffect( - readDC->asTexture().get(), GrSwizzle::RGBA(), *upmToPMRule, SkMatrix::I())); - sk_sp pmToUPM2(new GrConfigConversionEffect( - tempDC->asTexture().get(), GrSwizzle::RGBA(), *pmToUPMRule, SkMatrix::I())); + sk_sp pmToUPM(new GrConfigConversionEffect(*pmToUPMRule)); + sk_sp upmToPM(new GrConfigConversionEffect(*upmToPMRule)); - paint1.addColorFragmentProcessor(std::move(pmToUPM1)); + paint1.addColorTextureProcessor(resourceProvider, dataProxy, nullptr, SkMatrix::I()); + paint1.addColorFragmentProcessor(pmToUPM); paint1.setPorterDuffXPFactory(SkBlendMode::kSrc); - readDC->fillRectToRect(GrNoClip(), paint1, SkMatrix::I(), kDstRect, kSrcRect); + readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kDstRect, + kSrcRect); - readDC->asTexture()->readPixels(0, 0, kSize, kSize, kConfig, firstRead); + if (!readRTC->readPixels(ii, firstRead, 0, 0, 0)) { + continue; + } + paint2.addColorTextureProcessor(resourceProvider, readRTC->asTextureProxyRef(), nullptr, + SkMatrix::I()); paint2.addColorFragmentProcessor(std::move(upmToPM)); paint2.setPorterDuffXPFactory(SkBlendMode::kSrc); - tempDC->fillRectToRect(GrNoClip(), paint2, SkMatrix::I(), kDstRect, kSrcRect); + tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kDstRect, + kSrcRect); - paint3.addColorFragmentProcessor(std::move(pmToUPM2)); + paint3.addColorTextureProcessor(resourceProvider, tempRTC->asTextureProxyRef(), nullptr, + SkMatrix::I()); + paint3.addColorFragmentProcessor(std::move(pmToUPM)); paint3.setPorterDuffXPFactory(SkBlendMode::kSrc); - readDC->fillRectToRect(GrNoClip(), paint3, SkMatrix::I(), kDstRect, kSrcRect); + readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kDstRect, + kSrcRect); - readDC->asTexture()->readPixels(0, 0, kSize, kSize, kConfig, secondRead); + if (!readRTC->readPixels(ii, secondRead, 0, 0, 0)) { + continue; + } - failed = false; - for (int y = 0; y < kSize && !failed; ++y) { + uint32_t failCount = 0; + for (int y = 0; y < kSize; ++y) { for (int x = 0; x <= y; ++x) { if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) { - failed = true; - break; + if (++failCount >= bestFailCount) { + break; + } } } } + if (failCount < bestFailCount) { + bestFailCount = failCount; + bestRule = i; + } } - if (failed) { - *pmToUPMRule = kNone_PMConversion; - *upmToPMRule = kNone_PMConversion; + if (bestFailCount > 0) { + *pmToUPMRule = kPMConversionCnt; + *upmToPMRule = kPMConversionCnt; + } else { + *pmToUPMRule = kConversionRules[bestRule][0]; + *upmToPMRule = kConversionRules[bestRule][1]; } } -sk_sp GrConfigConversionEffect::Make(GrTexture* texture, - const GrSwizzle& swizzle, - PMConversion pmConversion, - const SkMatrix& matrix) { - if (swizzle == GrSwizzle::RGBA() && kNone_PMConversion == pmConversion) { - // If we returned a GrConfigConversionEffect that was equivalent to a GrSimpleTextureEffect - // then we may pollute our texture cache with redundant shaders. So in the case that no - // conversions were requested we instead return a GrSimpleTextureEffect. - return GrSimpleTextureEffect::Make(texture, nullptr, matrix); - } else { - if (kRGBA_8888_GrPixelConfig != texture->config() && - kBGRA_8888_GrPixelConfig != texture->config() && - kNone_PMConversion != pmConversion) { - // The PM conversions assume colors are 0..255 - return nullptr; - } - return sk_sp( - new GrConfigConversionEffect(texture, swizzle, pmConversion, matrix)); +sk_sp GrConfigConversionEffect::Make(sk_sp fp, + PMConversion pmConversion) { + if (!fp) { + return nullptr; } + sk_sp ccFP(new GrConfigConversionEffect(pmConversion)); + sk_sp fpPipeline[] = { fp, ccFP }; + return GrFragmentProcessor::RunInSeries(fpPipeline, 2); } diff --git a/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.h b/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.h index 93b49aa6560a..4cc2aeb80a0c 100644 --- a/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.h +++ b/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.h @@ -8,37 +8,37 @@ #ifndef GrConfigConversionEffect_DEFINED #define GrConfigConversionEffect_DEFINED -#include "GrSingleTextureEffect.h" -#include "GrSwizzle.h" - -class GrInvariantOutput; +#include "GrFragmentProcessor.h" /** * This class is used to perform config conversions. Clients may want to read/write data that is - * unpremultiplied. Additionally, the channels may also be swizzled for optimal readback/upload - * performance. + * unpremultiplied. */ -class GrConfigConversionEffect : public GrSingleTextureEffect { +class GrConfigConversionEffect : public GrFragmentProcessor { public: /** * The PM->UPM or UPM->PM conversions to apply. */ enum PMConversion { - kNone_PMConversion = 0, - kMulByAlpha_RoundUp_PMConversion, + kMulByAlpha_RoundUp_PMConversion = 0, kMulByAlpha_RoundDown_PMConversion, + kMulByAlpha_RoundNearest_PMConversion, + kDivByAlpha_RoundUp_PMConversion, kDivByAlpha_RoundDown_PMConversion, + kDivByAlpha_RoundNearest_PMConversion, kPMConversionCnt }; - static sk_sp Make(GrTexture*, const GrSwizzle&, PMConversion, - const SkMatrix&); + /** + * Returns a fragment processor that calls the passed in fragment processor, and then performs + * the requested premul or unpremul conversion. + */ + static sk_sp Make(sk_sp, PMConversion); const char* name() const override { return "Config Conversion"; } - const GrSwizzle& swizzle() const { return fSwizzle; } PMConversion pmConversion() const { return fPMConversion; } // This function determines whether it is possible to choose PM->UPM and UPM->PM conversions @@ -49,27 +49,20 @@ public: static void TestForPreservingPMConversions(GrContext* context, PMConversion* PMToUPMRule, PMConversion* UPMToPMRule); - private: - GrConfigConversionEffect(GrTexture*, - const GrSwizzle&, - PMConversion pmConversion, - const SkMatrix& matrix); + GrConfigConversionEffect(PMConversion); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - GrSwizzle fSwizzle; PMConversion fPMConversion; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - typedef GrSingleTextureEffect INHERITED; + typedef GrFragmentProcessor INHERITED; }; #endif diff --git a/gfx/skia/skia/src/gpu/effects/GrConstColorProcessor.cpp b/gfx/skia/skia/src/gpu/effects/GrConstColorProcessor.cpp index 0684c9cdb242..9f46712f2979 100644 --- a/gfx/skia/skia/src/gpu/effects/GrConstColorProcessor.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrConstColorProcessor.cpp @@ -6,7 +6,6 @@ */ #include "effects/GrConstColorProcessor.h" -#include "GrInvariantOutput.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" @@ -14,7 +13,7 @@ class GLConstColorProcessor : public GrGLSLFragmentProcessor { public: - GLConstColorProcessor() : fPrevColor(GrColor_ILLEGAL) {} + GLConstColorProcessor() : fPrevColor(GrColor4f::kIllegalConstructor) {} void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -43,58 +42,40 @@ public: } protected: - void onSetData(const GrGLSLProgramDataManager& pdm, const GrProcessor& processor) override { - GrColor color = processor.cast().color(); - // We use the "illegal" color value as an uninit sentinel. However, ut isn't inherently - // illegal to use this processor with unpremul colors. So we correctly handle the case - // when the "illegal" color is used but we will always upload it. - if (GrColor_ILLEGAL == color || fPrevColor != color) { - static const float scale = 1.f / 255.f; - float floatColor[4] = { - GrColorUnpackR(color) * scale, - GrColorUnpackG(color) * scale, - GrColorUnpackB(color) * scale, - GrColorUnpackA(color) * scale, - }; - pdm.set4fv(fColorUniform, 1, floatColor); + void onSetData(const GrGLSLProgramDataManager& pdm, + const GrFragmentProcessor& processor) override { + GrColor4f color = processor.cast().color(); + // We use the "illegal" color value as an uninit sentinel. With GrColor4f, the "illegal" + // color is *really* illegal (not just unpremultiplied), so this check is simple. + if (fPrevColor != color) { + pdm.set4fv(fColorUniform, 1, color.fRGBA); fPrevColor = color; } } private: GrGLSLProgramDataManager::UniformHandle fColorUniform; - GrColor fPrevColor; + GrColor4f fPrevColor; typedef GrGLSLFragmentProcessor INHERITED; }; /////////////////////////////////////////////////////////////////////////////// -void GrConstColorProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const { - if (kIgnore_InputMode == fMode) { - inout->setToOther(kRGBA_GrColorComponentFlags, fColor, - GrInvariantOutput::kWillNot_ReadInput); - } else { - GrColor r = GrColorUnpackR(fColor); - bool colorIsSingleChannel = r == GrColorUnpackG(fColor) && r == GrColorUnpackB(fColor) && - r == GrColorUnpackA(fColor); - if (kModulateRGBA_InputMode == fMode) { - if (colorIsSingleChannel) { - inout->mulByKnownSingleComponent(r); - } else { - inout->mulByKnownFourComponents(fColor); - } - } else { - if (colorIsSingleChannel) { - inout->mulAlphaByKnownSingleComponent(r); - } else { - inout->mulAlphaByKnownFourComponents(fColor); - } - } +GrColor4f GrConstColorProcessor::constantOutputForConstantInput(GrColor4f input) const { + switch (fMode) { + case kIgnore_InputMode: + return fColor; + case kModulateA_InputMode: + return fColor.mulByScalar(input.fRGBA[3]); + case kModulateRGBA_InputMode: + return fColor.modulate(input); } + SkFAIL("Unexpected mode"); + return GrColor4f::TransparentBlack(); } -void GrConstColorProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&, +void GrConstColorProcessor::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { b->add32(fMode); } @@ -112,8 +93,9 @@ bool GrConstColorProcessor::onIsEqual(const GrFragmentProcessor& other) const { GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConstColorProcessor); +#if GR_TEST_UTILS sk_sp GrConstColorProcessor::TestCreate(GrProcessorTestData* d) { - GrColor color SK_INIT_TO_AVOID_WARNING; + GrColor4f color; int colorPicker = d->fRandom->nextULessThan(3); switch (colorPicker) { case 0: { @@ -121,17 +103,18 @@ sk_sp GrConstColorProcessor::TestCreate(GrProcessorTestData uint32_t r = d->fRandom->nextULessThan(a+1); uint32_t g = d->fRandom->nextULessThan(a+1); uint32_t b = d->fRandom->nextULessThan(a+1); - color = GrColorPackRGBA(r, g, b, a); + color = GrColor4f::FromGrColor(GrColorPackRGBA(r, g, b, a)); break; } case 1: - color = 0; + color = GrColor4f::TransparentBlack(); break; case 2: - color = d->fRandom->nextULessThan(0x100); - color = color | (color << 8) | (color << 16) | (color << 24); + uint32_t c = d->fRandom->nextULessThan(0x100); + color = GrColor4f::FromGrColor(c | (c << 8) | (c << 16) | (c << 24)); break; } InputMode mode = static_cast(d->fRandom->nextULessThan(kInputModeCnt)); return GrConstColorProcessor::Make(color, mode); } +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.cpp index 5ce786799735..312c0382015b 100644 --- a/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.cpp @@ -6,13 +6,13 @@ */ #include "GrConvexPolyEffect.h" -#include "GrInvariantOutput.h" #include "SkPathPriv.h" #include "effects/GrConstColorProcessor.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" +#include "../private/GrGLSL.h" ////////////////////////////////////////////////////////////////////////////// class AARectEffect : public GrFragmentProcessor { @@ -27,13 +27,14 @@ public: const char* name() const override { return "AARect"; } - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; private: AARectEffect(GrPrimitiveEdgeType edgeType, const SkRect& rect) - : fRect(rect), fEdgeType(edgeType) { + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fRect(rect) + , fEdgeType(edgeType) { this->initClassID(); - this->setWillReadFragmentPosition(); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; @@ -43,15 +44,6 @@ private: return fRect == aare.fRect; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - if (fRect.isEmpty()) { - // An empty rect will have no coverage anywhere. - inout->mulByKnownSingleComponent(0); - } else { - inout->mulByUnknownSingleComponent(); - } - } - SkRect fRect; GrPrimitiveEdgeType fEdgeType; @@ -63,6 +55,7 @@ private: GR_DEFINE_FRAGMENT_PROCESSOR_TEST(AARectEffect); +#if GR_TEST_UTILS sk_sp AARectEffect::TestCreate(GrProcessorTestData* d) { SkRect rect = SkRect::MakeLTRB(d->fRandom->nextSScalar1(), d->fRandom->nextSScalar1(), @@ -77,6 +70,7 @@ sk_sp AARectEffect::TestCreate(GrProcessorTestData* d) { } while (nullptr == fp); return fp; } +#endif ////////////////////////////////////////////////////////////////////////////// @@ -88,10 +82,10 @@ public: void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fRectUniform; @@ -112,24 +106,27 @@ void GLAARectEffect::emitCode(EmitArgs& args) { &rectName); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const char* fragmentPos = fragBuilder->fragmentPosition(); if (GrProcessorEdgeTypeIsAA(aare.getEdgeType())) { // The amount of coverage removed in x and y by the edges is computed as a pair of negative // numbers, xSub and ySub. fragBuilder->codeAppend("\t\tfloat xSub, ySub;\n"); - fragBuilder->codeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName); - fragBuilder->codeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName); - fragBuilder->codeAppendf("\t\tySub += min(%s.w - %s.y, 0.0);\n", rectName, fragmentPos); + fragBuilder->codeAppendf("\t\txSub = min(sk_FragCoord.x - %s.x, 0.0);\n", rectName); + fragBuilder->codeAppendf("\t\txSub += min(%s.z - sk_FragCoord.x, 0.0);\n", rectName); + fragBuilder->codeAppendf("\t\tySub = min(sk_FragCoord.y - %s.y, 0.0);\n", rectName); + fragBuilder->codeAppendf("\t\tySub += min(%s.w - sk_FragCoord.y, 0.0);\n", rectName); // Now compute coverage in x and y and multiply them to get the fraction of the pixel // covered. fragBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n"); } else { fragBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n"); - fragBuilder->codeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); - fragBuilder->codeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); - fragBuilder->codeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); + fragBuilder->codeAppendf("\t\talpha *= (sk_FragCoord.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", + rectName); + fragBuilder->codeAppendf("\t\talpha *= (%s.z - sk_FragCoord.x) > -0.5 ? 1.0 : 0.0;\n", + rectName); + fragBuilder->codeAppendf("\t\talpha *= (sk_FragCoord.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", + rectName); + fragBuilder->codeAppendf("\t\talpha *= (%s.w - sk_FragCoord.y) > -0.5 ? 1.0 : 0.0;\n", + rectName); } if (GrProcessorEdgeTypeIsInverseFill(aare.getEdgeType())) { @@ -140,7 +137,7 @@ void GLAARectEffect::emitCode(EmitArgs& args) { } void GLAARectEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrFragmentProcessor& processor) { const AARectEffect& aare = processor.cast(); const SkRect& rect = aare.getRect(); if (rect != fPrevRect) { @@ -150,13 +147,13 @@ void GLAARectEffect::onSetData(const GrGLSLProgramDataManager& pdman, } } -void GLAARectEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&, +void GLAARectEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const AARectEffect& aare = processor.cast(); b->add32(aare.getEdgeType()); } -void AARectEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { +void AARectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLAARectEffect::GenKey(*this, caps, b); } @@ -169,15 +166,17 @@ GrGLSLFragmentProcessor* AARectEffect::onCreateGLSLInstance() const { class GrGLConvexPolyEffect : public GrGLSLFragmentProcessor { public: GrGLConvexPolyEffect() { - fPrevEdges[0] = SK_ScalarNaN; + for (size_t i = 0; i < SK_ARRAY_COUNT(fPrevEdges); ++i) { + fPrevEdges[i] = SK_ScalarNaN; + } } void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fEdgeUniform; @@ -198,10 +197,10 @@ void GrGLConvexPolyEffect::emitCode(EmitArgs& args) { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppend("\t\tfloat alpha = 1.0;\n"); fragBuilder->codeAppend("\t\tfloat edge;\n"); - const char* fragmentPos = fragBuilder->fragmentPosition(); for (int i = 0; i < cpe.getEdgeCount(); ++i) { - fragBuilder->codeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n", - edgeArrayName, i, fragmentPos, fragmentPos); + fragBuilder->codeAppendf("\t\tedge = dot(%s[%d], vec3(sk_FragCoord.x, sk_FragCoord.y, " + "1));\n", + edgeArrayName, i); if (GrProcessorEdgeTypeIsAA(cpe.getEdgeType())) { fragBuilder->codeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n"); } else { @@ -218,7 +217,7 @@ void GrGLConvexPolyEffect::emitCode(EmitArgs& args) { } void GrGLConvexPolyEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& effect) { + const GrFragmentProcessor& effect) { const GrConvexPolyEffect& cpe = effect.cast(); size_t byteSize = 3 * cpe.getEdgeCount() * sizeof(SkScalar); if (0 != memcmp(fPrevEdges, cpe.getEdges(), byteSize)) { @@ -227,7 +226,7 @@ void GrGLConvexPolyEffect::onSetData(const GrGLSLProgramDataManager& pdman, } } -void GrGLConvexPolyEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&, +void GrGLConvexPolyEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrConvexPolyEffect& cpe = processor.cast(); GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8); @@ -237,8 +236,7 @@ void GrGLConvexPolyEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps ////////////////////////////////////////////////////////////////////////////// -sk_sp GrConvexPolyEffect::Make(GrPrimitiveEdgeType type, const SkPath& path, - const SkVector* offset) { +sk_sp GrConvexPolyEffect::Make(GrPrimitiveEdgeType type, const SkPath& path) { if (kHairlineAA_GrProcessorEdgeType == type) { return nullptr; } @@ -253,17 +251,15 @@ sk_sp GrConvexPolyEffect::Make(GrPrimitiveEdgeType type, co // skip the draw or omit the clip element. if (!SkPathPriv::CheapComputeFirstDirection(path, &dir)) { if (GrProcessorEdgeTypeIsInverseFill(type)) { - return GrConstColorProcessor::Make(0xFFFFFFFF, + return GrConstColorProcessor::Make(GrColor4f::OpaqueWhite(), GrConstColorProcessor::kModulateRGBA_InputMode); } - return GrConstColorProcessor::Make(0, GrConstColorProcessor::kIgnore_InputMode); - } - - SkVector t; - if (nullptr == offset) { - t.set(0, 0); - } else { - t = *offset; + // This could use kIgnore instead of kModulateRGBA but it would trigger a debug print + // about a coverage processor not being compatible with the alpha-as-coverage optimization. + // We don't really care about this unlikely case so we just use kModulateRGBA to suppress + // the print. + return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), + GrConstColorProcessor::kModulateRGBA_InputMode); } SkScalar edges[3 * kMaxEdges]; @@ -295,8 +291,7 @@ sk_sp GrConvexPolyEffect::Make(GrPrimitiveEdgeType type, co edges[3 * n] = -v.fY; edges[3 * n + 1] = v.fX; } - SkPoint p = pts[1] + t; - edges[3 * n + 2] = -(edges[3 * n] * p.fX + edges[3 * n + 1] * p.fY); + edges[3 * n + 2] = -(edges[3 * n] * pts[1].fX + edges[3 * n + 1] * pts[1].fY); ++n; break; } @@ -321,11 +316,7 @@ sk_sp GrConvexPolyEffect::Make(GrPrimitiveEdgeType edgeType GrConvexPolyEffect::~GrConvexPolyEffect() {} -void GrConvexPolyEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->mulByUnknownSingleComponent(); -} - -void GrConvexPolyEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrConvexPolyEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLConvexPolyEffect::GenKey(*this, caps, b); } @@ -335,8 +326,9 @@ GrGLSLFragmentProcessor* GrConvexPolyEffect::onCreateGLSLInstance() const { } GrConvexPolyEffect::GrConvexPolyEffect(GrPrimitiveEdgeType edgeType, int n, const SkScalar edges[]) - : fEdgeType(edgeType) - , fEdgeCount(n) { + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fEdgeType(edgeType) + , fEdgeCount(n) { this->initClassID(); // Factory function should have already ensured this. SkASSERT(n <= kMaxEdges); @@ -346,7 +338,6 @@ GrConvexPolyEffect::GrConvexPolyEffect(GrPrimitiveEdgeType edgeType, int n, cons for (int i = 0; i < n; ++i) { fEdges[3 * i + 2] += SK_ScalarHalf; } - this->setWillReadFragmentPosition(); } bool GrConvexPolyEffect::onIsEqual(const GrFragmentProcessor& other) const { @@ -360,6 +351,7 @@ bool GrConvexPolyEffect::onIsEqual(const GrFragmentProcessor& other) const { GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConvexPolyEffect); +#if GR_TEST_UTILS sk_sp GrConvexPolyEffect::TestCreate(GrProcessorTestData* d) { int count = d->fRandom->nextULessThan(kMaxEdges) + 1; SkScalar edges[kMaxEdges * 3]; @@ -375,3 +367,4 @@ sk_sp GrConvexPolyEffect::TestCreate(GrProcessorTestData* d } while (nullptr == fp); return fp; } +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.h b/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.h index 8fc76feb5b03..34f8b22cffc8 100644 --- a/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.h +++ b/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.h @@ -48,18 +48,16 @@ public: /** * Creates an effect that clips against the path. If the path is not a convex polygon, is - * inverse filled, or has too many edges, this will return nullptr. If offset is non-nullptr, then - * the path is translated by the vector. + * inverse filled, or has too many edges, this will return nullptr. */ - static sk_sp Make(GrPrimitiveEdgeType, const SkPath&, - const SkVector* offset = nullptr); + static sk_sp Make(GrPrimitiveEdgeType, const SkPath&); /** * Creates an effect that fills inside the rect with AA edges.. */ static sk_sp Make(GrPrimitiveEdgeType, const SkRect&); - virtual ~GrConvexPolyEffect(); + ~GrConvexPolyEffect() override; const char* name() const override { return "ConvexPoly"; } @@ -74,12 +72,10 @@ private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor& other) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - GrPrimitiveEdgeType fEdgeType; int fEdgeCount; SkScalar fEdges[3 * kMaxEdges]; diff --git a/gfx/skia/skia/src/gpu/effects/GrConvolutionEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrConvolutionEffect.cpp deleted file mode 100644 index 59f7ab19e36c..000000000000 --- a/gfx/skia/skia/src/gpu/effects/GrConvolutionEffect.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrConvolutionEffect.h" -#include "glsl/GrGLSLFragmentProcessor.h" -#include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLUniformHandler.h" - -// For brevity -typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; - -class GrGLConvolutionEffect : public GrGLSLFragmentProcessor { -public: - void emitCode(EmitArgs&) override; - - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); - -protected: - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor&) override; - -private: - UniformHandle fKernelUni; - UniformHandle fImageIncrementUni; - UniformHandle fBoundsUni; - - typedef GrGLSLFragmentProcessor INHERITED; -}; - -void GrGLConvolutionEffect::emitCode(EmitArgs& args) { - const GrConvolutionEffect& ce = args.fFp.cast(); - - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "ImageIncrement"); - if (ce.useBounds()) { - fBoundsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "Bounds"); - } - - int width = Gr1DKernelEffect::WidthFromRadius(ce.radius()); - - int arrayCount = (width + 3) / 4; - SkASSERT(4 * arrayCount >= width); - - fKernelUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "Kernel", arrayCount); - - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); - - fragBuilder->codeAppendf("%s = vec4(0, 0, 0, 0);", args.fOutputColor); - - const GrGLSLShaderVar& kernel = uniformHandler->getUniformVariable(fKernelUni); - const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); - - fragBuilder->codeAppendf("vec2 coord = %s - %d.0 * %s;", coords2D.c_str(), ce.radius(), imgInc); - - // Manually unroll loop because some drivers don't; yields 20-30% speedup. - const char* kVecSuffix[4] = { ".x", ".y", ".z", ".w" }; - for (int i = 0; i < width; i++) { - SkString index; - SkString kernelIndex; - index.appendS32(i/4); - kernel.appendArrayAccess(index.c_str(), &kernelIndex); - kernelIndex.append(kVecSuffix[i & 0x3]); - - if (ce.useBounds()) { - // We used to compute a bool indicating whether we're in bounds or not, cast it to a - // float, and then mul weight*texture_sample by the float. However, the Adreno 430 seems - // to have a bug that caused corruption. - const char* bounds = uniformHandler->getUniformCStr(fBoundsUni); - const char* component = ce.direction() == Gr1DKernelEffect::kY_Direction ? "y" : "x"; - fragBuilder->codeAppendf("if (coord.%s >= %s.x && coord.%s <= %s.y) {", - component, bounds, component, bounds); - } - fragBuilder->codeAppendf("\t\t%s += ", args.fOutputColor); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord"); - fragBuilder->codeAppendf(" * %s;\n", kernelIndex.c_str()); - if (ce.useBounds()) { - fragBuilder->codeAppend("}"); - } - fragBuilder->codeAppendf("\t\tcoord += %s;\n", imgInc); - } - - SkString modulate; - GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); - fragBuilder->codeAppend(modulate.c_str()); -} - -void GrGLConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { - const GrConvolutionEffect& conv = processor.cast(); - GrTexture& texture = *conv.texture(0); - - float imageIncrement[2] = { 0 }; - float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; - switch (conv.direction()) { - case Gr1DKernelEffect::kX_Direction: - imageIncrement[0] = 1.0f / texture.width(); - break; - case Gr1DKernelEffect::kY_Direction: - imageIncrement[1] = ySign / texture.height(); - break; - default: - SkFAIL("Unknown filter direction."); - } - pdman.set2fv(fImageIncrementUni, 1, imageIncrement); - if (conv.useBounds()) { - const float* bounds = conv.bounds(); - if (Gr1DKernelEffect::kY_Direction == conv.direction() && - texture.origin() != kTopLeft_GrSurfaceOrigin) { - pdman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]); - } else { - pdman.set2f(fBoundsUni, bounds[0], bounds[1]); - } - } - int width = Gr1DKernelEffect::WidthFromRadius(conv.radius()); - - int arrayCount = (width + 3) / 4; - SkASSERT(4 * arrayCount >= width); - pdman.set4fv(fKernelUni, arrayCount, conv.kernel()); -} - -void GrGLConvolutionEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { - const GrConvolutionEffect& conv = processor.cast(); - uint32_t key = conv.radius(); - key <<= 2; - if (conv.useBounds()) { - key |= 0x2; - key |= GrConvolutionEffect::kY_Direction == conv.direction() ? 0x1 : 0x0; - } - b->add32(key); -} - -/////////////////////////////////////////////////////////////////////////////// - -GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, - Direction direction, - int radius, - const float* kernel, - bool useBounds, - float bounds[2]) - : INHERITED(texture, direction, radius), fUseBounds(useBounds) { - this->initClassID(); - SkASSERT(radius <= kMaxKernelRadius); - SkASSERT(kernel); - int width = this->width(); - for (int i = 0; i < width; i++) { - fKernel[i] = kernel[i]; - } - memcpy(fBounds, bounds, sizeof(fBounds)); -} - -GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, - Direction direction, - int radius, - float gaussianSigma, - bool useBounds, - float bounds[2]) - : INHERITED(texture, direction, radius), fUseBounds(useBounds) { - this->initClassID(); - SkASSERT(radius <= kMaxKernelRadius); - int width = this->width(); - - float sum = 0.0f; - float denom = 1.0f / (2.0f * gaussianSigma * gaussianSigma); - for (int i = 0; i < width; ++i) { - float x = static_cast(i - this->radius()); - // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian - // is dropped here, since we renormalize the kernel below. - fKernel[i] = sk_float_exp(- x * x * denom); - sum += fKernel[i]; - } - // Normalize the kernel - float scale = 1.0f / sum; - for (int i = 0; i < width; ++i) { - fKernel[i] *= scale; - } - memcpy(fBounds, bounds, sizeof(fBounds)); -} - -GrConvolutionEffect::~GrConvolutionEffect() { -} - -void GrConvolutionEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const { - GrGLConvolutionEffect::GenKey(*this, caps, b); -} - -GrGLSLFragmentProcessor* GrConvolutionEffect::onCreateGLSLInstance() const { - return new GrGLConvolutionEffect; -} - -bool GrConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) const { - const GrConvolutionEffect& s = sBase.cast(); - return (this->radius() == s.radius() && - this->direction() == s.direction() && - this->useBounds() == s.useBounds() && - 0 == memcmp(fBounds, s.fBounds, sizeof(fBounds)) && - 0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float))); -} - -/////////////////////////////////////////////////////////////////////////////// - -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConvolutionEffect); - -sk_sp GrConvolutionEffect::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; - Direction dir = d->fRandom->nextBool() ? kX_Direction : kY_Direction; - int radius = d->fRandom->nextRangeU(1, kMaxKernelRadius); - float kernel[kMaxKernelWidth]; - for (size_t i = 0; i < SK_ARRAY_COUNT(kernel); ++i) { - kernel[i] = d->fRandom->nextSScalar1(); - } - float bounds[2]; - for (size_t i = 0; i < SK_ARRAY_COUNT(bounds); ++i) { - bounds[i] = d->fRandom->nextF(); - } - - bool useBounds = d->fRandom->nextBool(); - return GrConvolutionEffect::Make(d->fTextures[texIdx], - dir, - radius, - kernel, - useBounds, - bounds); -} diff --git a/gfx/skia/skia/src/gpu/effects/GrConvolutionEffect.h b/gfx/skia/skia/src/gpu/effects/GrConvolutionEffect.h deleted file mode 100644 index c353542d030a..000000000000 --- a/gfx/skia/skia/src/gpu/effects/GrConvolutionEffect.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrConvolutionEffect_DEFINED -#define GrConvolutionEffect_DEFINED - -#include "Gr1DKernelEffect.h" -#include "GrInvariantOutput.h" - -/** - * A convolution effect. The kernel is specified as an array of 2 * half-width - * + 1 weights. Each texel is multiplied by it's weight and summed to determine - * the output color. The output color is modulated by the input color. - */ -class GrConvolutionEffect : public Gr1DKernelEffect { - -public: - - /// Convolve with an arbitrary user-specified kernel - static sk_sp Make(GrTexture* tex, - Direction dir, - int halfWidth, - const float* kernel, - bool useBounds, - float bounds[2]) { - return sk_sp( - new GrConvolutionEffect(tex, dir, halfWidth, kernel, useBounds, bounds)); - } - - /// Convolve with a Gaussian kernel - static sk_sp MakeGaussian(GrTexture* tex, - Direction dir, - int halfWidth, - float gaussianSigma, - bool useBounds, - float bounds[2]) { - return sk_sp( - new GrConvolutionEffect(tex, dir, halfWidth, gaussianSigma, useBounds, bounds)); - } - - virtual ~GrConvolutionEffect(); - - const float* kernel() const { return fKernel; } - - const float* bounds() const { return fBounds; } - bool useBounds() const { return fUseBounds; } - - const char* name() const override { return "Convolution"; } - - enum { - // This was decided based on the min allowed value for the max texture - // samples per fragment program run in DX9SM2 (32). A sigma param of 4.0 - // on a blur filter gives a kernel width of 25 while a sigma of 5.0 - // would exceed a 32 wide kernel. - kMaxKernelRadius = 12, - // With a C++11 we could have a constexpr version of WidthFromRadius() - // and not have to duplicate this calculation. - kMaxKernelWidth = 2 * kMaxKernelRadius + 1, - }; - -protected: - - float fKernel[kMaxKernelWidth]; - bool fUseBounds; - float fBounds[2]; - -private: - GrConvolutionEffect(GrTexture*, Direction, - int halfWidth, - const float* kernel, - bool useBounds, - float bounds[2]); - - /// Convolve with a Gaussian kernel - GrConvolutionEffect(GrTexture*, Direction, - int halfWidth, - float gaussianSigma, - bool useBounds, - float bounds[2]); - - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; - - bool onIsEqual(const GrFragmentProcessor&) const override; - - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - // If the texture was opaque we could know that the output color if we knew the sum of the - // kernel values. - inout->mulByUnknownFourComponents(); - } - - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - - typedef Gr1DKernelEffect INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.cpp b/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.cpp index c6abc696c292..e75a588cff40 100644 --- a/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.cpp @@ -8,10 +8,9 @@ #include "effects/GrCoverageSetOpXP.h" #include "GrCaps.h" #include "GrColor.h" -#include "GrDrawContext.h" #include "GrPipeline.h" #include "GrProcessor.h" -#include "GrProcOptInfo.h" +#include "GrRenderTargetContext.h" #include "glsl/GrGLSLBlend.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLUniformHandler.h" @@ -19,12 +18,11 @@ class CoverageSetOpXP : public GrXferProcessor { public: - static GrXferProcessor* Create(SkRegion::Op regionOp, bool invertCoverage) { - return new CoverageSetOpXP(regionOp, invertCoverage); + CoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage) + : fRegionOp(regionOp), fInvertCoverage(invertCoverage) { + this->initClassID(); } - ~CoverageSetOpXP() override; - const char* name() const override { return "Coverage Set Op"; } GrGLSLXferProcessor* createGLSLInstance() const override; @@ -32,14 +30,8 @@ public: bool invertCoverage() const { return fInvertCoverage; } private: - CoverageSetOpXP(SkRegion::Op regionOp, bool fInvertCoverage); - GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* color, - const GrCaps& caps) const override; - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override; @@ -63,7 +55,7 @@ public: ~GLCoverageSetOpXP() override {} - static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps, + static void GenKey(const GrProcessor& processor, const GrShaderCaps& caps, GrProcessorKeyBuilder* b) { const CoverageSetOpXP& xp = processor.cast(); uint32_t key = xp.invertCoverage() ? 0x0 : 0x1; @@ -89,16 +81,7 @@ private: /////////////////////////////////////////////////////////////////////////////// -CoverageSetOpXP::CoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage) - : fRegionOp(regionOp) - , fInvertCoverage(invertCoverage) { - this->initClassID(); -} - -CoverageSetOpXP::~CoverageSetOpXP() { -} - -void CoverageSetOpXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void CoverageSetOpXP::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLCoverageSetOpXP::GenKey(*this, caps, b); } @@ -107,15 +90,6 @@ GrGLSLXferProcessor* CoverageSetOpXP::createGLSLInstance() const { return new GLCoverageSetOpXP(*this); } -GrXferProcessor::OptFlags -CoverageSetOpXP::onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* color, - const GrCaps& caps) const { - // We never look at the color input - return GrXferProcessor::kIgnoreColor_OptFlag; -} - void CoverageSetOpXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const { switch (fRegionOp) { case SkRegion::kReplace_Op: @@ -148,173 +122,96 @@ void CoverageSetOpXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) cons /////////////////////////////////////////////////////////////////////////////// -class ShaderCSOXferProcessor : public GrXferProcessor { -public: - ShaderCSOXferProcessor(const DstTexture* dstTexture, - bool hasMixedSamples, - SkRegion::Op regionOp, - bool invertCoverage) - : INHERITED(dstTexture, true, hasMixedSamples) - , fRegionOp(regionOp) - , fInvertCoverage(invertCoverage) { - this->initClassID(); - } +constexpr GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp, + bool invertCoverage) + : fRegionOp(regionOp), fInvertCoverage(invertCoverage) {} - const char* name() const override { return "Coverage Set Op Shader"; } - - GrGLSLXferProcessor* createGLSLInstance() const override; - - SkRegion::Op regionOp() const { return fRegionOp; } - bool invertCoverage() const { return fInvertCoverage; } - -private: - GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations&, bool, GrColor*, - const GrCaps&) const override { - // We never look at the color input - return GrXferProcessor::kIgnoreColor_OptFlag; - } - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; - - bool onIsEqual(const GrXferProcessor& xpBase) const override { - const ShaderCSOXferProcessor& xp = xpBase.cast(); - return (fRegionOp == xp.fRegionOp && - fInvertCoverage == xp.fInvertCoverage); - } - - SkRegion::Op fRegionOp; - bool fInvertCoverage; - - typedef GrXferProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -class GLShaderCSOXferProcessor : public GrGLSLXferProcessor { -public: - static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) { - const ShaderCSOXferProcessor& xp = processor.cast(); - b->add32(xp.regionOp()); - uint32_t key = xp.invertCoverage() ? 0x0 : 0x1; - b->add32(key); - } - -private: - void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, - GrGLSLUniformHandler* uniformHandler, - const char* srcColor, - const char* srcCoverage, - const char* dstColor, - const char* outColor, - const char* outColorSecondary, - const GrXferProcessor& proc) override { - const ShaderCSOXferProcessor& xp = proc.cast(); - - if (xp.invertCoverage()) { - fragBuilder->codeAppendf("%s = 1.0 - %s;", outColor, srcCoverage); - } else { - fragBuilder->codeAppendf("%s = %s;", outColor, srcCoverage); - } - - GrGLSLBlend::AppendRegionOp(fragBuilder, outColor, dstColor, outColor, xp.regionOp()); - } - - void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {} - - typedef GrGLSLXferProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -void ShaderCSOXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&, - GrProcessorKeyBuilder* b) const { - GLShaderCSOXferProcessor::GenKey(*this, b); -} - -GrGLSLXferProcessor* ShaderCSOXferProcessor::createGLSLInstance() const { - return new GLShaderCSOXferProcessor; -} - -/////////////////////////////////////////////////////////////////////////////// -// -GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) - : fRegionOp(regionOp) - , fInvertCoverage(invertCoverage) { - this->initClassID(); -} - -sk_sp GrCoverageSetOpXPFactory::Make(SkRegion::Op regionOp, bool invertCoverage) { +const GrXPFactory* GrCoverageSetOpXPFactory::Get(SkRegion::Op regionOp, bool invertCoverage) { + // If these objects are constructed as static constexpr by cl.exe (2015 SP2) the vtables are + // null. +#ifdef SK_BUILD_FOR_WIN +#define _CONSTEXPR_ +#else +#define _CONSTEXPR_ constexpr +#endif switch (regionOp) { case SkRegion::kReplace_Op: { if (invertCoverage) { - static GrCoverageSetOpXPFactory gReplaceCDXPFI(regionOp, invertCoverage); - return sk_sp(SkRef(&gReplaceCDXPFI)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gReplaceCDXPFI( + SkRegion::kReplace_Op, true); + return &gReplaceCDXPFI; } else { - static GrCoverageSetOpXPFactory gReplaceCDXPF(regionOp, invertCoverage); - return sk_sp(SkRef(&gReplaceCDXPF)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gReplaceCDXPF( + SkRegion::kReplace_Op, false); + return &gReplaceCDXPF; } - break; } case SkRegion::kIntersect_Op: { if (invertCoverage) { - static GrCoverageSetOpXPFactory gIntersectCDXPFI(regionOp, invertCoverage); - return sk_sp(SkRef(&gIntersectCDXPFI)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gIntersectCDXPFI( + SkRegion::kIntersect_Op, true); + return &gIntersectCDXPFI; } else { - static GrCoverageSetOpXPFactory gIntersectCDXPF(regionOp, invertCoverage); - return sk_sp(SkRef(&gIntersectCDXPF)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gIntersectCDXPF( + SkRegion::kIntersect_Op, false); + return &gIntersectCDXPF; } - break; } case SkRegion::kUnion_Op: { if (invertCoverage) { - static GrCoverageSetOpXPFactory gUnionCDXPFI(regionOp, invertCoverage); - return sk_sp(SkRef(&gUnionCDXPFI)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gUnionCDXPFI(SkRegion::kUnion_Op, + true); + return &gUnionCDXPFI; } else { - static GrCoverageSetOpXPFactory gUnionCDXPF(regionOp, invertCoverage); - return sk_sp(SkRef(&gUnionCDXPF)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gUnionCDXPF(SkRegion::kUnion_Op, + false); + return &gUnionCDXPF; } - break; } case SkRegion::kXOR_Op: { if (invertCoverage) { - static GrCoverageSetOpXPFactory gXORCDXPFI(regionOp, invertCoverage); - return sk_sp(SkRef(&gXORCDXPFI)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gXORCDXPFI(SkRegion::kXOR_Op, + true); + return &gXORCDXPFI; } else { - static GrCoverageSetOpXPFactory gXORCDXPF(regionOp, invertCoverage); - return sk_sp(SkRef(&gXORCDXPF)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gXORCDXPF(SkRegion::kXOR_Op, + false); + return &gXORCDXPF; } - break; } case SkRegion::kDifference_Op: { if (invertCoverage) { - static GrCoverageSetOpXPFactory gDifferenceCDXPFI(regionOp, invertCoverage); - return sk_sp(SkRef(&gDifferenceCDXPFI)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gDifferenceCDXPFI( + SkRegion::kDifference_Op, true); + return &gDifferenceCDXPFI; } else { - static GrCoverageSetOpXPFactory gDifferenceCDXPF(regionOp, invertCoverage); - return sk_sp(SkRef(&gDifferenceCDXPF)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gDifferenceCDXPF( + SkRegion::kDifference_Op, false); + return &gDifferenceCDXPF; } - break; } case SkRegion::kReverseDifference_Op: { if (invertCoverage) { - static GrCoverageSetOpXPFactory gRevDiffCDXPFI(regionOp, invertCoverage); - return sk_sp(SkRef(&gRevDiffCDXPFI)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gRevDiffCDXPFI( + SkRegion::kReverseDifference_Op, true); + return &gRevDiffCDXPFI; } else { - static GrCoverageSetOpXPFactory gRevDiffCDXPF(regionOp, invertCoverage); - return sk_sp(SkRef(&gRevDiffCDXPF)); + static _CONSTEXPR_ const GrCoverageSetOpXPFactory gRevDiffCDXPF( + SkRegion::kReverseDifference_Op, false); + return &gRevDiffCDXPF; } - break; } - default: - return nullptr; } +#undef _CONSTEXPR_ + SkFAIL("Unknown region op."); + return nullptr; } -GrXferProcessor* -GrCoverageSetOpXPFactory::onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture* dst) const { +sk_sp GrCoverageSetOpXPFactory::makeXferProcessor( + const GrProcessorAnalysisColor&, + GrProcessorAnalysisCoverage, + bool hasMixedSamples, + const GrCaps& caps) const { // We don't support inverting coverage with mixed samples. We don't expect to ever want this in // the future, however we could at some point make this work using an inverted coverage // modulation table. Note that an inverted table still won't work if there are coverage procs. @@ -323,22 +220,15 @@ GrCoverageSetOpXPFactory::onCreateXferProcessor(const GrCaps& caps, return nullptr; } - if (optimizations.fOverrides.fUsePLSDstRead) { - return new ShaderCSOXferProcessor(dst, hasMixedSamples, fRegionOp, fInvertCoverage); - } - return CoverageSetOpXP::Create(fRegionOp, fInvertCoverage); -} - -void GrCoverageSetOpXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - InvariantBlendedColor* blendedColor) const { - blendedColor->fWillBlendWithDst = SkRegion::kReplace_Op != fRegionOp; - blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; + return sk_sp(new CoverageSetOpXP(fRegionOp, fInvertCoverage)); } GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory); -sk_sp GrCoverageSetOpXPFactory::TestCreate(GrProcessorTestData* d) { +#if GR_TEST_UTILS +const GrXPFactory* GrCoverageSetOpXPFactory::TestGet(GrProcessorTestData* d) { SkRegion::Op regionOp = SkRegion::Op(d->fRandom->nextULessThan(SkRegion::kLastOp + 1)); - bool invertCoverage = !d->fDrawContext->hasMixedSamples() && d->fRandom->nextBool(); - return GrCoverageSetOpXPFactory::Make(regionOp, invertCoverage); + bool invertCoverage = !d->fRenderTargetContext->hasMixedSamples() && d->fRandom->nextBool(); + return GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage); } +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.h b/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.h new file mode 100644 index 000000000000..ba04a2eb4c90 --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.h @@ -0,0 +1,56 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrCoverageSetOpXP_DEFINED +#define GrCoverageSetOpXP_DEFINED + +#include "GrTypes.h" +#include "GrXferProcessor.h" +#include "SkRegion.h" + +// See the comment above GrXPFactory's definition about this warning suppression. +#if defined(__GNUC__) || defined(__clang) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif + +/** + * This xfer processor directly blends the the src coverage with the dst using a set operator. It is + * useful for rendering coverage masks using CSG. It can optionally invert the src coverage before + * applying the set operator. + */ +class GrCoverageSetOpXPFactory : public GrXPFactory { +public: + static const GrXPFactory* Get(SkRegion::Op regionOp, bool invertCoverage = false); + +private: + constexpr GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage); + + sk_sp makeXferProcessor(const GrProcessorAnalysisColor&, + GrProcessorAnalysisCoverage, + bool hasMixedSamples, + const GrCaps&) const override; + + AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&, + const GrProcessorAnalysisCoverage&, + const GrCaps&) const override { + return AnalysisProperties::kIgnoresInputColor; + } + + + GR_DECLARE_XP_FACTORY_TEST; + + SkRegion::Op fRegionOp; + bool fInvertCoverage; + + typedef GrXPFactory INHERITED; +}; +#if defined(__GNUC__) || defined(__clang) +#pragma GCC diagnostic pop +#endif +#endif + diff --git a/gfx/skia/skia/src/gpu/effects/GrCustomXfermode.cpp b/gfx/skia/skia/src/gpu/effects/GrCustomXfermode.cpp index 1b94a6bee151..970c28909e17 100644 --- a/gfx/skia/skia/src/gpu/effects/GrCustomXfermode.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrCustomXfermode.cpp @@ -7,62 +7,57 @@ #include "effects/GrCustomXfermode.h" +#include "GrCaps.h" #include "GrCoordTransform.h" -#include "GrContext.h" #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" #include "GrPipeline.h" #include "GrProcessor.h" +#include "GrShaderCaps.h" #include "GrTexture.h" -#include "GrTextureAccess.h" -#include "SkXfermode.h" #include "glsl/GrGLSLBlend.h" -#include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLXferProcessor.h" -bool GrCustomXfermode::IsSupportedMode(SkXfermode::Mode mode) { - return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode; +bool GrCustomXfermode::IsSupportedMode(SkBlendMode mode) { + return (int)mode > (int)SkBlendMode::kLastCoeffMode && + (int)mode <= (int)SkBlendMode::kLastMode; } /////////////////////////////////////////////////////////////////////////////// // Static helpers /////////////////////////////////////////////////////////////////////////////// -static GrBlendEquation hw_blend_equation(SkXfermode::Mode mode) { - enum { kOffset = kOverlay_GrBlendEquation - SkXfermode::kOverlay_Mode }; - return static_cast(mode + kOffset); - - GR_STATIC_ASSERT(kOverlay_GrBlendEquation == SkXfermode::kOverlay_Mode + kOffset); - GR_STATIC_ASSERT(kDarken_GrBlendEquation == SkXfermode::kDarken_Mode + kOffset); - GR_STATIC_ASSERT(kLighten_GrBlendEquation == SkXfermode::kLighten_Mode + kOffset); - GR_STATIC_ASSERT(kColorDodge_GrBlendEquation == SkXfermode::kColorDodge_Mode + kOffset); - GR_STATIC_ASSERT(kColorBurn_GrBlendEquation == SkXfermode::kColorBurn_Mode + kOffset); - GR_STATIC_ASSERT(kHardLight_GrBlendEquation == SkXfermode::kHardLight_Mode + kOffset); - GR_STATIC_ASSERT(kSoftLight_GrBlendEquation == SkXfermode::kSoftLight_Mode + kOffset); - GR_STATIC_ASSERT(kDifference_GrBlendEquation == SkXfermode::kDifference_Mode + kOffset); - GR_STATIC_ASSERT(kExclusion_GrBlendEquation == SkXfermode::kExclusion_Mode + kOffset); - GR_STATIC_ASSERT(kMultiply_GrBlendEquation == SkXfermode::kMultiply_Mode + kOffset); - GR_STATIC_ASSERT(kHSLHue_GrBlendEquation == SkXfermode::kHue_Mode + kOffset); - GR_STATIC_ASSERT(kHSLSaturation_GrBlendEquation == SkXfermode::kSaturation_Mode + kOffset); - GR_STATIC_ASSERT(kHSLColor_GrBlendEquation == SkXfermode::kColor_Mode + kOffset); - GR_STATIC_ASSERT(kHSLLuminosity_GrBlendEquation == SkXfermode::kLuminosity_Mode + kOffset); - GR_STATIC_ASSERT(kGrBlendEquationCnt == SkXfermode::kLastMode + 1 + kOffset); +static constexpr GrBlendEquation hw_blend_equation(SkBlendMode mode) { +// In C++14 this could be a constexpr int variable. +#define EQ_OFFSET (kOverlay_GrBlendEquation - (int)SkBlendMode::kOverlay) + GR_STATIC_ASSERT(kOverlay_GrBlendEquation == (int)SkBlendMode::kOverlay + EQ_OFFSET); + GR_STATIC_ASSERT(kDarken_GrBlendEquation == (int)SkBlendMode::kDarken + EQ_OFFSET); + GR_STATIC_ASSERT(kLighten_GrBlendEquation == (int)SkBlendMode::kLighten + EQ_OFFSET); + GR_STATIC_ASSERT(kColorDodge_GrBlendEquation == (int)SkBlendMode::kColorDodge + EQ_OFFSET); + GR_STATIC_ASSERT(kColorBurn_GrBlendEquation == (int)SkBlendMode::kColorBurn + EQ_OFFSET); + GR_STATIC_ASSERT(kHardLight_GrBlendEquation == (int)SkBlendMode::kHardLight + EQ_OFFSET); + GR_STATIC_ASSERT(kSoftLight_GrBlendEquation == (int)SkBlendMode::kSoftLight + EQ_OFFSET); + GR_STATIC_ASSERT(kDifference_GrBlendEquation == (int)SkBlendMode::kDifference + EQ_OFFSET); + GR_STATIC_ASSERT(kExclusion_GrBlendEquation == (int)SkBlendMode::kExclusion + EQ_OFFSET); + GR_STATIC_ASSERT(kMultiply_GrBlendEquation == (int)SkBlendMode::kMultiply + EQ_OFFSET); + GR_STATIC_ASSERT(kHSLHue_GrBlendEquation == (int)SkBlendMode::kHue + EQ_OFFSET); + GR_STATIC_ASSERT(kHSLSaturation_GrBlendEquation == (int)SkBlendMode::kSaturation + EQ_OFFSET); + GR_STATIC_ASSERT(kHSLColor_GrBlendEquation == (int)SkBlendMode::kColor + EQ_OFFSET); + GR_STATIC_ASSERT(kHSLLuminosity_GrBlendEquation == (int)SkBlendMode::kLuminosity + EQ_OFFSET); + GR_STATIC_ASSERT(kGrBlendEquationCnt == (int)SkBlendMode::kLastMode + 1 + EQ_OFFSET); + return static_cast((int)mode + EQ_OFFSET); +#undef EQ_OFFSET } static bool can_use_hw_blend_equation(GrBlendEquation equation, - const GrPipelineOptimizations& opt, - const GrCaps& caps) { + GrProcessorAnalysisCoverage coverage, const GrCaps& caps) { if (!caps.advancedBlendEquationSupport()) { return false; } - if (opt.fOverrides.fUsePLSDstRead) { - return false; - } - if (opt.fCoveragePOI.isFourChannelOutput()) { + if (GrProcessorAnalysisCoverage::kLCD == coverage) { return false; // LCD coverage must be applied after the blend equation. } if (caps.canUseAdvancedBlendEquation(equation)) { @@ -77,16 +72,16 @@ static bool can_use_hw_blend_equation(GrBlendEquation equation, class CustomXP : public GrXferProcessor { public: - CustomXP(SkXfermode::Mode mode, GrBlendEquation hwBlendEquation) + CustomXP(SkBlendMode mode, GrBlendEquation hwBlendEquation) : fMode(mode), fHWBlendEquation(hwBlendEquation) { this->initClassID(); } - CustomXP(const DstTexture* dstTexture, bool hasMixedSamples, SkXfermode::Mode mode) - : INHERITED(dstTexture, true, hasMixedSamples), - fMode(mode), - fHWBlendEquation(static_cast(-1)) { + CustomXP(bool hasMixedSamples, SkBlendMode mode) + : INHERITED(true, hasMixedSamples) + , fMode(mode) + , fHWBlendEquation(static_cast(-1)) { this->initClassID(); } @@ -94,7 +89,7 @@ public: GrGLSLXferProcessor* createGLSLInstance() const override; - SkXfermode::Mode mode() const { return fMode; } + SkBlendMode mode() const { return fMode; } bool hasHWBlendEquation() const { return -1 != static_cast(fHWBlendEquation); } GrBlendEquation hwBlendEquation() const { @@ -102,21 +97,16 @@ public: return fHWBlendEquation; } + GrXferBarrierType xferBarrierType(const GrCaps&) const override; + private: - GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const override; - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; - - GrXferBarrierType onXferBarrier(const GrRenderTarget*, const GrCaps&) const override; + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; void onGetBlendInfo(BlendInfo*) const override; bool onIsEqual(const GrXferProcessor& xpBase) const override; - const SkXfermode::Mode fMode; + const SkBlendMode fMode; const GrBlendEquation fHWBlendEquation; typedef GrXferProcessor INHERITED; @@ -129,16 +119,17 @@ public: GLCustomXP(const GrXferProcessor&) {} ~GLCustomXP() override {} - static void GenKey(const GrXferProcessor& p, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) { + static void GenKey(const GrXferProcessor& p, const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) { const CustomXP& xp = p.cast(); uint32_t key = 0; if (xp.hasHWBlendEquation()) { SkASSERT(caps.advBlendEqInteraction() > 0); // 0 will mean !xp.hasHWBlendEquation(). key |= caps.advBlendEqInteraction(); - GR_STATIC_ASSERT(GrGLSLCaps::kLast_AdvBlendEqInteraction < 4); + GR_STATIC_ASSERT(GrShaderCaps::kLast_AdvBlendEqInteraction < 4); } if (!xp.hasHWBlendEquation() || caps.mustEnableSpecificAdvBlendEqs()) { - key |= xp.mode() << 3; + key |= (int)xp.mode() << 3; } b->add32(key); } @@ -153,12 +144,8 @@ private: // Apply coverage by multiplying it into the src color before blending. Mixed samples will // "just work" automatically. (See onGetOptimizations()) - if (args.fInputCoverage) { - fragBuilder->codeAppendf("%s = %s * %s;", - args.fOutputPrimary, args.fInputCoverage, args.fInputColor); - } else { - fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor); - } + fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputCoverage, + args.fInputColor); } void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, @@ -186,7 +173,7 @@ private: /////////////////////////////////////////////////////////////////////////////// -void CustomXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { +void CustomXP::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLCustomXP::GenKey(*this, caps, b); } @@ -200,117 +187,7 @@ bool CustomXP::onIsEqual(const GrXferProcessor& other) const { return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation; } -GrXferProcessor::OptFlags CustomXP::onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const { - /* - Most the optimizations we do here are based on tweaking alpha for coverage. - - The general SVG blend equation is defined in the spec as follows: - - Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa) - Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa) - - (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha, - and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied - RGB colors.) - - For every blend mode supported by this class, i.e. the "advanced" blend - modes, X=Y=Z=1 and this equation reduces to the PDF blend equation. - - It can be shown that when X=Y=Z=1, these equations can modulate alpha for - coverage. - - - == Color == - - We substitute Y=Z=1 and define a blend() function that calculates Dca' in - terms of premultiplied alpha only: - - blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0, - Sca : if Da == 0, - B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if Sa,Da != 0} - - And for coverage modulation, we use a post blend src-over model: - - Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca - - (Where f is the fractional coverage.) - - Next we show that canTweakAlphaForCoverage() is true by proving the - following relationship: - - blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca - - General case (f,Sa,Da != 0): - - f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca - = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca [Sa,Da != 0, definition of blend()] - = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca - = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca - = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca - = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca - = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) - = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0] - = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()] - - Corner cases (Sa=0, Da=0, and f=0): - - Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca - = f * Dca + (1-f) * Dca [Sa=0, definition of blend()] - = Dca - = blend(0, Dca, 0, Da) [definition of blend()] - = blend(f*Sca, Dca, f*Sa, Da) [Sa=0] - - Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca - = f * Sca + (1-f) * Dca [Da=0, definition of blend()] - = f * Sca [Da=0] - = blend(f*Sca, 0, f*Sa, 0) [definition of blend()] - = blend(f*Sca, Dca, f*Sa, Da) [Da=0] - - f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca - = Dca [f=0] - = blend(0, Dca, 0, Da) [definition of blend()] - = blend(f*Sca, Dca, f*Sa, Da) [f=0] - - == Alpha == - - We substitute X=Y=Z=1 and define a blend() function that calculates Da': - - blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa) - = Sa * Da + Sa - Sa * Da + Da - Da * Sa - = Sa + Da - Sa * Da - - We use the same model for coverage modulation as we did with color: - - Da'' = f * blend(Sa, Da) + (1-f) * Da - - And show that canTweakAlphaForCoverage() is true by proving the following - relationship: - - blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da - - - f * blend(Sa, Da) + (1-f) * Da - = f * (Sa + Da - Sa * Da) + (1-f) * Da - = f*Sa + f*Da - f*Sa * Da + Da - f*Da - = f*Sa - f*Sa * Da + Da - = f*Sa + Da - f*Sa * Da - = blend(f*Sa, Da) - */ - - OptFlags flags = kNone_OptFlags; - if (optimizations.fColorPOI.allStagesMultiplyInput()) { - flags |= kCanTweakAlphaForCoverage_OptFlag; - } - if (this->hasHWBlendEquation() && optimizations.fCoveragePOI.isSolidWhite()) { - flags |= kIgnoreCoverage_OptFlag; - } - return flags; -} - -GrXferBarrierType CustomXP::onXferBarrier(const GrRenderTarget* rt, const GrCaps& caps) const { +GrXferBarrierType CustomXP::xferBarrierType(const GrCaps& caps) const { if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) { return kBlend_GrXferBarrierType; } @@ -324,77 +201,226 @@ void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const { } /////////////////////////////////////////////////////////////////////////////// + +// See the comment above GrXPFactory's definition about this warning suppression. +#if defined(__GNUC__) || defined(__clang) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif class CustomXPFactory : public GrXPFactory { public: - CustomXPFactory(SkXfermode::Mode mode); - - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - GrXPFactory::InvariantBlendedColor*) const override; + constexpr CustomXPFactory(SkBlendMode mode) + : fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) {} private: - GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture*) const override; + sk_sp makeXferProcessor(const GrProcessorAnalysisColor&, + GrProcessorAnalysisCoverage, + bool hasMixedSamples, + const GrCaps&) const override; - bool onWillReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const override; - - bool onIsEqual(const GrXPFactory& xpfBase) const override { - const CustomXPFactory& xpf = xpfBase.cast(); - return fMode == xpf.fMode; - } + AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&, + const GrProcessorAnalysisCoverage&, + const GrCaps&) const override; GR_DECLARE_XP_FACTORY_TEST; - SkXfermode::Mode fMode; - GrBlendEquation fHWBlendEquation; + SkBlendMode fMode; + GrBlendEquation fHWBlendEquation; typedef GrXPFactory INHERITED; }; +#if defined(__GNUC__) || defined(__clang) +#pragma GCC diagnostic pop +#endif -CustomXPFactory::CustomXPFactory(SkXfermode::Mode mode) - : fMode(mode), - fHWBlendEquation(hw_blend_equation(mode)) { +sk_sp CustomXPFactory::makeXferProcessor( + const GrProcessorAnalysisColor&, + GrProcessorAnalysisCoverage coverage, + bool hasMixedSamples, + const GrCaps& caps) const { SkASSERT(GrCustomXfermode::IsSupportedMode(fMode)); - this->initClassID(); -} - -GrXferProcessor* CustomXPFactory::onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& opt, - bool hasMixedSamples, - const DstTexture* dstTexture) const { - if (can_use_hw_blend_equation(fHWBlendEquation, opt, caps)) { - SkASSERT(!dstTexture || !dstTexture->texture()); - return new CustomXP(fMode, fHWBlendEquation); + if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) { + return sk_sp(new CustomXP(fMode, fHWBlendEquation)); } - return new CustomXP(dstTexture, hasMixedSamples, fMode); + return sk_sp(new CustomXP(hasMixedSamples, fMode)); } -bool CustomXPFactory::onWillReadDstColor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations) const { - return !can_use_hw_blend_equation(fHWBlendEquation, optimizations, caps); -} +GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties( + const GrProcessorAnalysisColor&, const GrProcessorAnalysisCoverage& coverage, + const GrCaps& caps) const { + /* + The general SVG blend equation is defined in the spec as follows: -void CustomXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - InvariantBlendedColor* blendedColor) const { - blendedColor->fWillBlendWithDst = true; - blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; + Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa) + Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa) + + (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha, + and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied + RGB colors.) + + For every blend mode supported by this class, i.e. the "advanced" blend + modes, X=Y=Z=1 and this equation reduces to the PDF blend equation. + + It can be shown that when X=Y=Z=1, these equations can modulate alpha for + coverage. + + + == Color == + + We substitute Y=Z=1 and define a blend() function that calculates Dca' in + terms of premultiplied alpha only: + + blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0, + Sca : if Da == 0, + B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if + Sa,Da != 0} + + And for coverage modulation, we use a post blend src-over model: + + Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca + + (Where f is the fractional coverage.) + + Next we show that canTweakAlphaForCoverage() is true by proving the + following relationship: + + blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca + + General case (f,Sa,Da != 0): + + f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca + = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca [Sa,Da != + 0, definition of blend()] + = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca + = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca + = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca + = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca + = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) + = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0] + = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()] + + Corner cases (Sa=0, Da=0, and f=0): + + Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca + = f * Dca + (1-f) * Dca [Sa=0, definition of blend()] + = Dca + = blend(0, Dca, 0, Da) [definition of blend()] + = blend(f*Sca, Dca, f*Sa, Da) [Sa=0] + + Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca + = f * Sca + (1-f) * Dca [Da=0, definition of blend()] + = f * Sca [Da=0] + = blend(f*Sca, 0, f*Sa, 0) [definition of blend()] + = blend(f*Sca, Dca, f*Sa, Da) [Da=0] + + f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca + = Dca [f=0] + = blend(0, Dca, 0, Da) [definition of blend()] + = blend(f*Sca, Dca, f*Sa, Da) [f=0] + + == Alpha == + + We substitute X=Y=Z=1 and define a blend() function that calculates Da': + + blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa) + = Sa * Da + Sa - Sa * Da + Da - Da * Sa + = Sa + Da - Sa * Da + + We use the same model for coverage modulation as we did with color: + + Da'' = f * blend(Sa, Da) + (1-f) * Da + + And show that canTweakAlphaForCoverage() is true by proving the following + relationship: + + blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da + + + f * blend(Sa, Da) + (1-f) * Da + = f * (Sa + Da - Sa * Da) + (1-f) * Da + = f*Sa + f*Da - f*Sa * Da + Da - f*Da + = f*Sa - f*Sa * Da + Da + = f*Sa + Da - f*Sa * Da + = blend(f*Sa, Da) + */ + if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) { + if (caps.blendEquationSupport() == GrCaps::kAdvancedCoherent_BlendEquationSupport) { + return AnalysisProperties::kCompatibleWithAlphaAsCoverage; + } else { + return AnalysisProperties::kCompatibleWithAlphaAsCoverage | + AnalysisProperties::kRequiresBarrierBetweenOverlappingDraws; + } + } + return AnalysisProperties::kCompatibleWithAlphaAsCoverage | + AnalysisProperties::kReadsDstInShader; } GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory); -sk_sp CustomXPFactory::TestCreate(GrProcessorTestData* d) { - int mode = d->fRandom->nextRangeU(SkXfermode::kLastCoeffMode + 1, - SkXfermode::kLastSeparableMode); +#if GR_TEST_UTILS +const GrXPFactory* CustomXPFactory::TestGet(GrProcessorTestData* d) { + int mode = d->fRandom->nextRangeU((int)SkBlendMode::kLastCoeffMode + 1, + (int)SkBlendMode::kLastSeparableMode); - return sk_sp(new CustomXPFactory(static_cast(mode))); + return GrCustomXfermode::Get((SkBlendMode)mode); } +#endif /////////////////////////////////////////////////////////////////////////////// -sk_sp GrCustomXfermode::MakeXPFactory(SkXfermode::Mode mode) { - if (!GrCustomXfermode::IsSupportedMode(mode)) { - return nullptr; - } else { - return sk_sp(new CustomXPFactory(mode)); +const GrXPFactory* GrCustomXfermode::Get(SkBlendMode mode) { + // If these objects are constructed as static constexpr by cl.exe (2015 SP2) the vtables are + // null. +#ifdef SK_BUILD_FOR_WIN +#define _CONSTEXPR_ +#else +#define _CONSTEXPR_ constexpr +#endif + static _CONSTEXPR_ const CustomXPFactory gOverlay(SkBlendMode::kOverlay); + static _CONSTEXPR_ const CustomXPFactory gDarken(SkBlendMode::kDarken); + static _CONSTEXPR_ const CustomXPFactory gLighten(SkBlendMode::kLighten); + static _CONSTEXPR_ const CustomXPFactory gColorDodge(SkBlendMode::kColorDodge); + static _CONSTEXPR_ const CustomXPFactory gColorBurn(SkBlendMode::kColorBurn); + static _CONSTEXPR_ const CustomXPFactory gHardLight(SkBlendMode::kHardLight); + static _CONSTEXPR_ const CustomXPFactory gSoftLight(SkBlendMode::kSoftLight); + static _CONSTEXPR_ const CustomXPFactory gDifference(SkBlendMode::kDifference); + static _CONSTEXPR_ const CustomXPFactory gExclusion(SkBlendMode::kExclusion); + static _CONSTEXPR_ const CustomXPFactory gMultiply(SkBlendMode::kMultiply); + static _CONSTEXPR_ const CustomXPFactory gHue(SkBlendMode::kHue); + static _CONSTEXPR_ const CustomXPFactory gSaturation(SkBlendMode::kSaturation); + static _CONSTEXPR_ const CustomXPFactory gColor(SkBlendMode::kColor); + static _CONSTEXPR_ const CustomXPFactory gLuminosity(SkBlendMode::kLuminosity); +#undef _CONSTEXPR_ + switch (mode) { + case SkBlendMode::kOverlay: + return &gOverlay; + case SkBlendMode::kDarken: + return &gDarken; + case SkBlendMode::kLighten: + return &gLighten; + case SkBlendMode::kColorDodge: + return &gColorDodge; + case SkBlendMode::kColorBurn: + return &gColorBurn; + case SkBlendMode::kHardLight: + return &gHardLight; + case SkBlendMode::kSoftLight: + return &gSoftLight; + case SkBlendMode::kDifference: + return &gDifference; + case SkBlendMode::kExclusion: + return &gExclusion; + case SkBlendMode::kMultiply: + return &gMultiply; + case SkBlendMode::kHue: + return &gHue; + case SkBlendMode::kSaturation: + return &gSaturation; + case SkBlendMode::kColor: + return &gColor; + case SkBlendMode::kLuminosity: + return &gLuminosity; + default: + SkASSERT(!GrCustomXfermode::IsSupportedMode(mode)); + return nullptr; } } diff --git a/gfx/skia/skia/include/gpu/effects/GrCustomXfermode.h b/gfx/skia/skia/src/gpu/effects/GrCustomXfermode.h similarity index 71% rename from gfx/skia/skia/include/gpu/effects/GrCustomXfermode.h rename to gfx/skia/skia/src/gpu/effects/GrCustomXfermode.h index 3bd321447552..54309ddafc39 100644 --- a/gfx/skia/skia/include/gpu/effects/GrCustomXfermode.h +++ b/gfx/skia/skia/src/gpu/effects/GrCustomXfermode.h @@ -8,17 +8,19 @@ #ifndef GrCustomXfermode_DEFINED #define GrCustomXfermode_DEFINED -#include "SkXfermode.h" +#include "SkBlendMode.h" +#include "SkRefCnt.h" class GrTexture; +class GrXPFactory; /** * Custom Xfer modes are used for blending when the blend mode cannot be represented using blend * coefficients. */ namespace GrCustomXfermode { - bool IsSupportedMode(SkXfermode::Mode mode); - sk_sp MakeXPFactory(SkXfermode::Mode mode); + bool IsSupportedMode(SkBlendMode mode); + const GrXPFactory* Get(SkBlendMode mode); }; #endif diff --git a/gfx/skia/skia/src/gpu/effects/GrDashingEffect.h b/gfx/skia/skia/src/gpu/effects/GrDashingEffect.h deleted file mode 100644 index b2d052347938..000000000000 --- a/gfx/skia/skia/src/gpu/effects/GrDashingEffect.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrDashingEffect_DEFINED -#define GrDashingEffect_DEFINED - -#include "GrColor.h" -#include "GrTypesPriv.h" -#include "SkPathEffect.h" - -class GrClip; -class GrDrawBatch; -class GrStyle; - -namespace GrDashingEffect { - enum class AAMode { - kNone, - kCoverage, - kCoverageWithMSAA, - }; - static const int kAAModeCnt = static_cast(AAMode::kCoverageWithMSAA) + 1; - - GrDrawBatch* CreateDashLineBatch(GrColor, - const SkMatrix& viewMatrix, - const SkPoint pts[2], - AAMode, - const GrStyle& style); - bool CanDrawDashLine(const SkPoint pts[2], const GrStyle& style, - const SkMatrix& viewMatrix); -} - -#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.cpp b/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.cpp index 35009e1a07a1..14464f78e32d 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.cpp @@ -18,25 +18,15 @@ */ class DisableColorXP : public GrXferProcessor { public: - static GrXferProcessor* Create() { return new DisableColorXP; } - - ~DisableColorXP() override {} + DisableColorXP() { this->initClassID(); } const char* name() const override { return "Disable Color"; } GrGLSLXferProcessor* createGLSLInstance() const override; private: - DisableColorXP(); - GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* color, - const GrCaps& caps) const override { - return GrXferProcessor::kIgnoreColor_OptFlag | GrXferProcessor::kIgnoreCoverage_OptFlag; - } - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override; @@ -55,7 +45,7 @@ public: ~GLDisableColorXP() override {} - static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) {} + static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {} private: void emitOutputsForBlendState(const EmitArgs& args) override { @@ -73,11 +63,7 @@ private: /////////////////////////////////////////////////////////////////////////////// -DisableColorXP::DisableColorXP() { - this->initClassID(); -} - -void DisableColorXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { +void DisableColorXP::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLDisableColorXP::GenKey(*this, caps, b); } @@ -88,22 +74,18 @@ void DisableColorXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const } /////////////////////////////////////////////////////////////////////////////// - -GrDisableColorXPFactory::GrDisableColorXPFactory() { - this->initClassID(); -} - -GrXferProcessor* -GrDisableColorXPFactory::onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture* dst) const { - SkASSERT(!optimizations.fOverrides.fUsePLSDstRead); - return DisableColorXP::Create(); +sk_sp GrDisableColorXPFactory::makeXferProcessor( + const GrProcessorAnalysisColor&, + GrProcessorAnalysisCoverage, + bool hasMixedSamples, + const GrCaps& caps) const { + return sk_sp(new DisableColorXP); } GR_DEFINE_XP_FACTORY_TEST(GrDisableColorXPFactory); -sk_sp GrDisableColorXPFactory::TestCreate(GrProcessorTestData*) { - return GrDisableColorXPFactory::Make(); +#if GR_TEST_UTILS +const GrXPFactory* GrDisableColorXPFactory::TestGet(GrProcessorTestData*) { + return GrDisableColorXPFactory::Get(); } +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.h b/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.h index 4aed6b671eb6..7470444a21bd 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.h +++ b/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.h @@ -12,37 +12,46 @@ #include "GrXferProcessor.h" #include "SkRefCnt.h" -class GrProcOptInfo; - +// See the comment above GrXPFactory's definition about this warning suppression. +#if defined(__GNUC__) || defined(__clang) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif class GrDisableColorXPFactory : public GrXPFactory { public: - static sk_sp Make() { return sk_sp(new GrDisableColorXPFactory); } - - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - GrXPFactory::InvariantBlendedColor* blendedColor) const override { - blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; - blendedColor->fWillBlendWithDst = false; - } + static const GrXPFactory* Get(); private: - GrDisableColorXPFactory(); + constexpr GrDisableColorXPFactory() {} - GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture* dstTexture) const override; - - bool onWillReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const override { - return false; + AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&, + const GrProcessorAnalysisCoverage&, + const GrCaps&) const override { + return AnalysisProperties::kCompatibleWithAlphaAsCoverage | + AnalysisProperties::kIgnoresInputColor; } - bool onIsEqual(const GrXPFactory& xpfBase) const override { - return true; - } + sk_sp makeXferProcessor(const GrProcessorAnalysisColor&, + GrProcessorAnalysisCoverage, + bool hasMixedSamples, + const GrCaps&) const override; GR_DECLARE_XP_FACTORY_TEST; typedef GrXPFactory INHERITED; }; +#if defined(__GNUC__) || defined(__clang) +#pragma GCC diagnostic pop +#endif + +inline const GrXPFactory* GrDisableColorXPFactory::Get() { + // If this is constructed as static constexpr by cl.exe (2015 SP2) the vtable is null. +#ifdef SK_BUILD_FOR_WIN + static const GrDisableColorXPFactory gDisableColorXPFactory; +#else + static constexpr const GrDisableColorXPFactory gDisableColorXPFactory; +#endif + return &gDisableColorXPFactory; +} #endif diff --git a/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp index 5404b0c80570..82f888053089 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp @@ -6,11 +6,9 @@ */ #include "GrDistanceFieldGeoProc.h" -#include "GrInvariantOutput.h" + #include "GrTexture.h" - #include "SkDistanceFieldGen.h" - #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" @@ -35,8 +33,6 @@ public: const GrDistanceFieldA8TextGeoProc& dfTexEffect = args.fGP.cast(); GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; @@ -55,9 +51,7 @@ public: #endif // Setup pass through color - if (!dfTexEffect.colorIgnored()) { - varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); - } + varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); // Setup position this->setupPosition(vertBuilder, @@ -87,8 +81,8 @@ public: vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName); // compute numbers to be hardcoded to convert texture coordinates from float to int - SkASSERT(dfTexEffect.numTextures() == 1); - GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture(); + SkASSERT(dfTexEffect.numTextureSamplers() == 1); + GrTexture* atlas = dfTexEffect.textureSampler(0).texture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); GrGLSLVertToFrag st(kVec2f_GrSLType); @@ -98,8 +92,7 @@ public: dfTexEffect.inTextureCoords()->fName); // Use highp to work around aliasing issues - fragBuilder->appendPrecisionModifier(kHigh_GrSLPrecision); - fragBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); + fragBuilder->codeAppendf("highp vec2 uv = %s;\n", uv.fsIn()); fragBuilder->codeAppend("\tfloat texColor = "); fragBuilder->appendTextureLookup(args.fTexSamplers[0], @@ -200,17 +193,16 @@ public: } static inline void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast(); uint32_t key = dfTexEffect.getFlags(); - key |= dfTexEffect.colorIgnored() << 16; - key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25; + key |= ComputePosKey(dfTexEffect.viewMatrix()) << 16; b->add32(key); // Currently we hardcode numbers to convert atlas coordinates to normalized floating point - SkASSERT(gp.numTextures() == 1); - GrTexture* atlas = gp.textureAccess(0).getTexture(); + SkASSERT(gp.numTextureSamplers() == 1); + GrTexture* atlas = gp.textureSampler(0).texture(); SkASSERT(atlas); b->add32(atlas->width()); b->add32(atlas->height()); @@ -229,10 +221,11 @@ private: /////////////////////////////////////////////////////////////////////////////// -GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color, +GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrResourceProvider* resourceProvider, + GrColor color, const SkMatrix& viewMatrix, - GrTexture* texture, - const GrTextureParams& params, + sk_sp proxy, + const GrSamplerParams& params, #ifdef SK_GAMMA_APPLY_TO_A8 float distanceAdjust, #endif @@ -240,7 +233,7 @@ GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color, bool usesLocalCoords) : fColor(color) , fViewMatrix(viewMatrix) - , fTextureAccess(texture, params) + , fTextureSampler(resourceProvider, std::move(proxy), params) #ifdef SK_GAMMA_APPLY_TO_A8 , fDistanceAdjust(distanceAdjust) #endif @@ -254,15 +247,16 @@ GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color, fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2us_GrVertexAttribType, kHigh_GrSLPrecision); - this->addTextureAccess(&fTextureAccess); + this->addTextureSampler(&fTextureSampler); } -void GrDistanceFieldA8TextGeoProc::getGLSLProcessorKey(const GrGLSLCaps& caps, +void GrDistanceFieldA8TextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLDistanceFieldA8TextGeoProc::GenKey(*this, caps, b); } -GrGLSLPrimitiveProcessor* GrDistanceFieldA8TextGeoProc::createGLSLInstance(const GrGLSLCaps&) const { +GrGLSLPrimitiveProcessor* +GrDistanceFieldA8TextGeoProc::createGLSLInstance(const GrShaderCaps&) const { return new GrGLDistanceFieldA8TextGeoProc(); } @@ -270,9 +264,12 @@ GrGLSLPrimitiveProcessor* GrDistanceFieldA8TextGeoProc::createGLSLInstance(const GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc); +#if GR_TEST_UTILS sk_sp GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); + static const SkShader::TileMode kTileModes[] = { SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, @@ -282,8 +279,8 @@ sk_sp GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorT kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))], kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))], }; - GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode : - GrTextureParams::kNone_FilterMode); + GrSamplerParams params(tileModes, d->fRandom->nextBool() ? GrSamplerParams::kBilerp_FilterMode + : GrSamplerParams::kNone_FilterMode); uint32_t flags = 0; flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0; @@ -291,15 +288,17 @@ sk_sp GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorT flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0; } - return GrDistanceFieldA8TextGeoProc::Make(GrRandomColor(d->fRandom), + return GrDistanceFieldA8TextGeoProc::Make(d->resourceProvider(), + GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom), - d->fTextures[texIdx], params, + std::move(proxy), params, #ifdef SK_GAMMA_APPLY_TO_A8 d->fRandom->nextF(), #endif flags, d->fRandom->nextBool()); } +#endif /////////////////////////////////////////////////////////////////////////////// @@ -313,8 +312,6 @@ public: const GrDistanceFieldPathGeoProc& dfTexEffect = args.fGP.cast(); GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; @@ -327,9 +324,7 @@ public: varyingHandler->addVarying("TextureCoords", &v, kHigh_GrSLPrecision); // setup pass through color - if (!dfTexEffect.colorIgnored()) { - varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); - } + varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); vertBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName); // Setup position @@ -354,8 +349,7 @@ public: "TextureSize", &textureSizeUniName); // Use highp to work around aliasing issues - fragBuilder->appendPrecisionModifier(kHigh_GrSLPrecision); - fragBuilder->codeAppendf("vec2 uv = %s;", v.fsIn()); + fragBuilder->codeAppendf("highp vec2 uv = %s;", v.fsIn()); fragBuilder->codeAppend("float texColor = "); fragBuilder->appendTextureLookup(args.fTexSamplers[0], @@ -365,8 +359,7 @@ public: fragBuilder->codeAppend("float distance = " SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");"); - fragBuilder->appendPrecisionModifier(kHigh_GrSLPrecision); - fragBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName); + fragBuilder->codeAppendf("highp vec2 st = uv*%s;", textureSizeUniName); fragBuilder->codeAppend("float afwidth;"); bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) == kUniformScale_DistanceFieldEffectMask; @@ -437,7 +430,7 @@ public: FPCoordTransformIter&& transformIter) override { SkASSERT(fTextureSizeUni.isValid()); - GrTexture* texture = proc.texture(0); + GrTexture* texture = proc.textureSampler(0).texture(); if (texture->width() != fTextureSize.width() || texture->height() != fTextureSize.height()) { fTextureSize = SkISize::Make(texture->width(), texture->height()); @@ -458,13 +451,12 @@ public: } static inline void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast(); uint32_t key = dfTexEffect.getFlags(); - key |= dfTexEffect.colorIgnored() << 16; - key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25; + key |= ComputePosKey(dfTexEffect.viewMatrix()) << 16; b->add32(key); } @@ -478,17 +470,17 @@ private: }; /////////////////////////////////////////////////////////////////////////////// - GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc( + GrResourceProvider* resourceProvider, GrColor color, const SkMatrix& viewMatrix, - GrTexture* texture, - const GrTextureParams& params, + sk_sp proxy, + const GrSamplerParams& params, uint32_t flags, bool usesLocalCoords) : fColor(color) , fViewMatrix(viewMatrix) - , fTextureAccess(texture, params) + , fTextureSampler(resourceProvider, std::move(proxy), params) , fFlags(flags & kNonLCD_DistanceFieldEffectMask) , fInColor(nullptr) , fUsesLocalCoords(usesLocalCoords) { @@ -497,16 +489,17 @@ GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc( fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision); fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); - fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2f_GrVertexAttribType); - this->addTextureAccess(&fTextureAccess); + fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2us_GrVertexAttribType); + this->addTextureSampler(&fTextureSampler); } -void GrDistanceFieldPathGeoProc::getGLSLProcessorKey(const GrGLSLCaps& caps, +void GrDistanceFieldPathGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLDistanceFieldPathGeoProc::GenKey(*this, caps, b); } -GrGLSLPrimitiveProcessor* GrDistanceFieldPathGeoProc::createGLSLInstance(const GrGLSLCaps&) const { +GrGLSLPrimitiveProcessor* +GrDistanceFieldPathGeoProc::createGLSLInstance(const GrShaderCaps&) const { return new GrGLDistanceFieldPathGeoProc(); } @@ -514,9 +507,12 @@ GrGLSLPrimitiveProcessor* GrDistanceFieldPathGeoProc::createGLSLInstance(const G GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc); +#if GR_TEST_UTILS sk_sp GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* d) { int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); + static const SkShader::TileMode kTileModes[] = { SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, @@ -526,8 +522,8 @@ sk_sp GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTes kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))], kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))], }; - GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode - : GrTextureParams::kNone_FilterMode); + GrSamplerParams params(tileModes, d->fRandom->nextBool() ? GrSamplerParams::kBilerp_FilterMode + : GrSamplerParams::kNone_FilterMode); uint32_t flags = 0; flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0; @@ -535,13 +531,15 @@ sk_sp GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTes flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0; } - return GrDistanceFieldPathGeoProc::Make(GrRandomColor(d->fRandom), + return GrDistanceFieldPathGeoProc::Make(d->resourceProvider(), + GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom), - d->fTextures[texIdx], + std::move(proxy), params, flags, d->fRandom->nextBool()); } +#endif /////////////////////////////////////////////////////////////////////////////// @@ -566,9 +564,7 @@ public: GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // setup pass through color - if (!dfTexEffect.colorIgnored()) { - varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); - } + varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); // Setup position this->setupPosition(vertBuilder, @@ -598,8 +594,8 @@ public: vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName); // compute numbers to be hardcoded to convert texture coordinates from float to int - SkASSERT(dfTexEffect.numTextures() == 1); - GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture(); + SkASSERT(dfTexEffect.numTextureSamplers() == 1); + GrTexture* atlas = dfTexEffect.textureSampler(0).texture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); GrGLSLVertToFrag st(kVec2f_GrSLType); @@ -610,20 +606,15 @@ public: // add frag shader code - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); - // create LCD offset adjusted by inverse of transform // Use highp to work around aliasing issues - fragBuilder->appendPrecisionModifier(kHigh_GrSLPrecision); - fragBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); - fragBuilder->appendPrecisionModifier(kHigh_GrSLPrecision); + fragBuilder->codeAppendf("highp vec2 uv = %s;\n", uv.fsIn()); SkScalar lcdDelta = 1.0f / (3.0f * atlas->width()); if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) { - fragBuilder->codeAppendf("float delta = -%.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta); + fragBuilder->codeAppendf("highp float delta = -%.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta); } else { - fragBuilder->codeAppendf("float delta = %.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta); + fragBuilder->codeAppendf("highp float delta = %.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta); } if (isUniformScale) { #ifdef SK_VULKAN @@ -757,18 +748,17 @@ public: } static inline void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast(); uint32_t key = dfTexEffect.getFlags(); - key |= dfTexEffect.colorIgnored() << 16; - key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25; + key |= ComputePosKey(dfTexEffect.viewMatrix()) << 16; b->add32(key); // Currently we hardcode numbers to convert atlas coordinates to normalized floating point - SkASSERT(gp.numTextures() == 1); - GrTexture* atlas = gp.textureAccess(0).getTexture(); + SkASSERT(gp.numTextureSamplers() == 1); + GrTexture* atlas = gp.textureSampler(0).texture(); SkASSERT(atlas); b->add32(atlas->width()); b->add32(atlas->height()); @@ -785,15 +775,16 @@ private: }; /////////////////////////////////////////////////////////////////////////////// - GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc( + GrResourceProvider* resourceProvider, GrColor color, const SkMatrix& viewMatrix, - GrTexture* texture, const GrTextureParams& params, + sk_sp proxy, + const GrSamplerParams& params, DistanceAdjust distanceAdjust, uint32_t flags, bool usesLocalCoords) : fColor(color) , fViewMatrix(viewMatrix) - , fTextureAccess(texture, params) + , fTextureSampler(resourceProvider, std::move(proxy), params) , fDistanceAdjust(distanceAdjust) , fFlags(flags & kLCD_DistanceFieldEffectMask) , fUsesLocalCoords(usesLocalCoords) { @@ -804,15 +795,15 @@ GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc( fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2us_GrVertexAttribType, kHigh_GrSLPrecision); - this->addTextureAccess(&fTextureAccess); + this->addTextureSampler(&fTextureSampler); } -void GrDistanceFieldLCDTextGeoProc::getGLSLProcessorKey(const GrGLSLCaps& caps, +void GrDistanceFieldLCDTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, caps, b); } -GrGLSLPrimitiveProcessor* GrDistanceFieldLCDTextGeoProc::createGLSLInstance(const GrGLSLCaps&) const { +GrGLSLPrimitiveProcessor* GrDistanceFieldLCDTextGeoProc::createGLSLInstance(const GrShaderCaps&) const { return new GrGLDistanceFieldLCDTextGeoProc(); } @@ -820,9 +811,12 @@ GrGLSLPrimitiveProcessor* GrDistanceFieldLCDTextGeoProc::createGLSLInstance(cons GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc); +#if GR_TEST_UTILS sk_sp GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessorTestData* d) { int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); + static const SkShader::TileMode kTileModes[] = { SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, @@ -832,8 +826,8 @@ sk_sp GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessor kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))], kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))], }; - GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode : - GrTextureParams::kNone_FilterMode); + GrSamplerParams params(tileModes, d->fRandom->nextBool() ? GrSamplerParams::kBilerp_FilterMode + : GrSamplerParams::kNone_FilterMode); DistanceAdjust wa = { 0.0f, 0.1f, -0.1f }; uint32_t flags = kUseLCD_DistanceFieldEffectFlag; flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0; @@ -841,10 +835,12 @@ sk_sp GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessor flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0; } flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0; - return GrDistanceFieldLCDTextGeoProc::Make(GrRandomColor(d->fRandom), + return GrDistanceFieldLCDTextGeoProc::Make(d->resourceProvider(), + GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom), - d->fTextures[texIdx], params, + std::move(proxy), params, wa, flags, d->fRandom->nextBool()); } +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.h b/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.h index 339c063b301c..1384d2fc63e6 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.h +++ b/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.h @@ -43,30 +43,34 @@ enum GrDistanceFieldEffectFlags { /** * The output color of this effect is a modulation of the input color and a sample from a * distance field texture (using a smoothed step function near 0.5). - * It allows explicit specification of the filtering and wrap modes (GrTextureParams). The input + * It allows explicit specification of the filtering and wrap modes (GrSamplerParams). The input * coords are a custom attribute. Gamma correction is handled via a texture LUT. */ class GrDistanceFieldA8TextGeoProc : public GrGeometryProcessor { public: #ifdef SK_GAMMA_APPLY_TO_A8 - static sk_sp Make(GrColor color, const SkMatrix& viewMatrix, - GrTexture* tex, const GrTextureParams& params, + static sk_sp Make(GrResourceProvider* resourceProvider, + GrColor color, const SkMatrix& viewMatrix, + sk_sp proxy, + const GrSamplerParams& params, float lum, uint32_t flags, bool usesLocalCoords) { return sk_sp( - new GrDistanceFieldA8TextGeoProc(color, viewMatrix, tex, params, lum, flags, - usesLocalCoords)); + new GrDistanceFieldA8TextGeoProc(resourceProvider, color, viewMatrix, std::move(proxy), + params, lum, flags, usesLocalCoords)); } #else - static sk_sp Make(GrColor color, const SkMatrix& viewMatrix, - GrTexture* tex, const GrTextureParams& params, + static sk_sp Make(GrResourceProvider* resourceProvider, + GrColor color, const SkMatrix& viewMatrix, + sk_sp proxy, + const GrSamplerParams& params, uint32_t flags, bool usesLocalCoords) { return sk_sp( - new GrDistanceFieldA8TextGeoProc(color, viewMatrix, tex, params, flags, - usesLocalCoords)); + new GrDistanceFieldA8TextGeoProc(resourceProvider, color, viewMatrix, std::move(proxy), + params, flags, usesLocalCoords)); } #endif - virtual ~GrDistanceFieldA8TextGeoProc() {} + ~GrDistanceFieldA8TextGeoProc() override {} const char* name() const override { return "DistanceFieldA8Text"; } @@ -74,7 +78,6 @@ public: const Attribute* inColor() const { return fInColor; } const Attribute* inTextureCoords() const { return fInTextureCoords; } GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } const SkMatrix& viewMatrix() const { return fViewMatrix; } bool usesLocalCoords() const { return fUsesLocalCoords; } #ifdef SK_GAMMA_APPLY_TO_A8 @@ -82,13 +85,13 @@ public: #endif uint32_t getFlags() const { return fFlags; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: - GrDistanceFieldA8TextGeoProc(GrColor, const SkMatrix& viewMatrix, - GrTexture* texture, const GrTextureParams& params, + GrDistanceFieldA8TextGeoProc(GrResourceProvider*, GrColor, const SkMatrix& viewMatrix, + sk_sp proxy, const GrSamplerParams& params, #ifdef SK_GAMMA_APPLY_TO_A8 float distanceAdjust, #endif @@ -96,7 +99,7 @@ private: GrColor fColor; SkMatrix fViewMatrix; - GrTextureAccess fTextureAccess; + TextureSampler fTextureSampler; #ifdef SK_GAMMA_APPLY_TO_A8 float fDistanceAdjust; #endif @@ -115,19 +118,21 @@ private: /** * The output color of this effect is a modulation of the input color and a sample from a * distance field texture (using a smoothed step function near 0.5). -* It allows explicit specification of the filtering and wrap modes (GrTextureParams). The input +* It allows explicit specification of the filtering and wrap modes (GrSamplerParams). The input * coords are a custom attribute. No gamma correct blending is applied. Used for paths only. */ class GrDistanceFieldPathGeoProc : public GrGeometryProcessor { public: - static sk_sp Make(GrColor color, const SkMatrix& viewMatrix, - GrTexture* tex, const GrTextureParams& params, + static sk_sp Make(GrResourceProvider* resourceProvider, GrColor color, + const SkMatrix& viewMatrix, sk_sp proxy, + const GrSamplerParams& params, uint32_t flags, bool usesLocalCoords) { return sk_sp( - new GrDistanceFieldPathGeoProc(color, viewMatrix, tex, params, flags, usesLocalCoords)); + new GrDistanceFieldPathGeoProc(resourceProvider, color, viewMatrix, std::move(proxy), + params, flags, usesLocalCoords)); } - virtual ~GrDistanceFieldPathGeoProc() {} + ~GrDistanceFieldPathGeoProc() override {} const char* name() const override { return "DistanceFieldPath"; } @@ -135,23 +140,22 @@ public: const Attribute* inColor() const { return fInColor; } const Attribute* inTextureCoords() const { return fInTextureCoords; } GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } const SkMatrix& viewMatrix() const { return fViewMatrix; } uint32_t getFlags() const { return fFlags; } bool usesLocalCoords() const { return fUsesLocalCoords; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: - GrDistanceFieldPathGeoProc(GrColor, const SkMatrix& viewMatrix, GrTexture* texture, - const GrTextureParams& params, uint32_t flags, + GrDistanceFieldPathGeoProc(GrResourceProvider*, GrColor, const SkMatrix& viewMatrix, + sk_sp, const GrSamplerParams&, uint32_t flags, bool usesLocalCoords); GrColor fColor; SkMatrix fViewMatrix; - GrTextureAccess fTextureAccess; + TextureSampler fTextureSampler; uint32_t fFlags; const Attribute* fInPosition; const Attribute* fInColor; @@ -166,7 +170,7 @@ private: /** * The output color of this effect is a modulation of the input color and samples from a * distance field texture (using a smoothed step function near 0.5), adjusted for LCD displays. - * It allows explicit specification of the filtering and wrap modes (GrTextureParams). The input + * It allows explicit specification of the filtering and wrap modes (GrSamplerParams). The input * coords are a custom attribute. Gamma correction is handled via a texture LUT. */ class GrDistanceFieldLCDTextGeoProc : public GrGeometryProcessor { @@ -186,16 +190,19 @@ public: } }; - static sk_sp Make(GrColor color, const SkMatrix& viewMatrix, - GrTexture* tex, const GrTextureParams& params, + static sk_sp Make(GrResourceProvider* resourceProvider, GrColor color, + const SkMatrix& viewMatrix, + sk_sp proxy, + const GrSamplerParams& params, DistanceAdjust distanceAdjust, uint32_t flags, bool usesLocalCoords) { return sk_sp( - new GrDistanceFieldLCDTextGeoProc(color, viewMatrix, tex, params, distanceAdjust, + new GrDistanceFieldLCDTextGeoProc(resourceProvider, color, viewMatrix, std::move(proxy), + params, distanceAdjust, flags, usesLocalCoords)); } - virtual ~GrDistanceFieldLCDTextGeoProc() {} + ~GrDistanceFieldLCDTextGeoProc() override {} const char* name() const override { return "DistanceFieldLCDText"; } @@ -204,24 +211,23 @@ public: const Attribute* inTextureCoords() const { return fInTextureCoords; } DistanceAdjust getDistanceAdjust() const { return fDistanceAdjust; } GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } const SkMatrix& viewMatrix() const { return fViewMatrix; } uint32_t getFlags() const { return fFlags; } bool usesLocalCoords() const { return fUsesLocalCoords; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: - GrDistanceFieldLCDTextGeoProc(GrColor, const SkMatrix& viewMatrix, - GrTexture* texture, const GrTextureParams& params, + GrDistanceFieldLCDTextGeoProc(GrResourceProvider*, GrColor, const SkMatrix& viewMatrix, + sk_sp proxy, const GrSamplerParams& params, DistanceAdjust wa, uint32_t flags, bool usesLocalCoords); GrColor fColor; SkMatrix fViewMatrix; - GrTextureAccess fTextureAccess; + TextureSampler fTextureSampler; DistanceAdjust fDistanceAdjust; uint32_t fFlags; const Attribute* fInPosition; diff --git a/gfx/skia/skia/src/gpu/effects/GrDitherEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrDitherEffect.cpp index 1fddec6629d6..864a5d2d8152 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDitherEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrDitherEffect.cpp @@ -7,10 +7,10 @@ #include "GrDitherEffect.h" #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" #include "SkRect.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "../private/GrGLSL.h" ////////////////////////////////////////////////////////////////////////////// @@ -20,41 +20,34 @@ public: return sk_sp(new DitherEffect); } - virtual ~DitherEffect() {} + ~DitherEffect() override {} const char* name() const override { return "Dither"; } private: - DitherEffect() { - this->initClassID(); - this->setWillReadFragmentPosition(); - } + DitherEffect() : INHERITED(kNone_OptimizationFlags) { this->initClassID(); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; // All dither effects are equal bool onIsEqual(const GrFragmentProcessor&) const override { return true; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; typedef GrFragmentProcessor INHERITED; }; -void DitherEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); -} - ////////////////////////////////////////////////////////////////////////////// GR_DEFINE_FRAGMENT_PROCESSOR_TEST(DitherEffect); +#if GR_TEST_UTILS sk_sp DitherEffect::TestCreate(GrProcessorTestData*) { return DitherEffect::Make(); } +#endif ////////////////////////////////////////////////////////////////////////////// @@ -78,15 +71,15 @@ void GLDitherEffect::emitCode(EmitArgs& args) { // For each channel c, add the random offset to the pixel to either bump // it up or let it remain constant during quantization. fragBuilder->codeAppendf("\t\tfloat r = " - "fract(sin(dot(%s.xy ,vec2(12.9898,78.233))) * 43758.5453);\n", - fragBuilder->fragmentPosition()); - fragBuilder->codeAppendf("\t\t%s = (1.0/255.0) * vec4(r, r, r, r) + %s;\n", + "fract(sin(dot(sk_FragCoord.xy, vec2(12.9898,78.233))) * " + "43758.5453);\n"); + fragBuilder->codeAppendf("\t\t%s = clamp((1.0/255.0) * vec4(r, r, r, r) + %s, 0, 1);\n", args.fOutputColor, GrGLSLExpr4(args.fInputColor).c_str()); } ////////////////////////////////////////////////////////////////////////////// -void DitherEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void DitherEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLDitherEffect::GenKey(*this, caps, b); } diff --git a/gfx/skia/skia/src/gpu/effects/GrGammaEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrGammaEffect.cpp deleted file mode 100644 index 63ffc3242473..000000000000 --- a/gfx/skia/skia/src/gpu/effects/GrGammaEffect.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrGammaEffect.h" - -#include "GrContext.h" -#include "GrCoordTransform.h" -#include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" -#include "GrProcessor.h" -#include "glsl/GrGLSLFragmentProcessor.h" -#include "glsl/GrGLSLFragmentShaderBuilder.h" - -class GrGLGammaEffect : public GrGLSLFragmentProcessor { -public: - void emitCode(EmitArgs& args) override { - const GrGammaEffect& ge = args.fFp.cast(); - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - - const char* gammaUniName = nullptr; - if (GrGammaEffect::Mode::kExponential == ge.mode()) { - fGammaUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, - kDefault_GrSLPrecision, "Gamma", &gammaUniName); - } - - SkString srgbFuncName; - static const GrGLSLShaderVar gSrgbArgs[] = { - GrGLSLShaderVar("x", kFloat_GrSLType), - }; - switch (ge.mode()) { - case GrGammaEffect::Mode::kLinearToSRGB: - fragBuilder->emitFunction(kFloat_GrSLType, - "linear_to_srgb", - SK_ARRAY_COUNT(gSrgbArgs), - gSrgbArgs, - "return (x <= 0.0031308) ? (x * 12.92) " - ": (1.055 * pow(x, 0.416666667) - 0.055);", - &srgbFuncName); - break; - case GrGammaEffect::Mode::kSRGBToLinear: - fragBuilder->emitFunction(kFloat_GrSLType, - "srgb_to_linear", - SK_ARRAY_COUNT(gSrgbArgs), - gSrgbArgs, - "return (x <= 0.04045) ? (x / 12.92) " - ": pow((x + 0.055) / 1.055, 2.4);", - &srgbFuncName); - default: - // No helper function needed - break; - } - - if (nullptr == args.fInputColor) { - args.fInputColor = "vec4(1)"; - } - - if (GrGammaEffect::Mode::kExponential == ge.mode()) { - fragBuilder->codeAppendf("%s = vec4(pow(%s.rgb, vec3(%s)), %s.a);", - args.fOutputColor, args.fInputColor, gammaUniName, - args.fInputColor); - } else { - fragBuilder->codeAppendf("%s = vec4(%s(%s.r), %s(%s.g), %s(%s.b), %s.a);", - args.fOutputColor, - srgbFuncName.c_str(), args.fInputColor, - srgbFuncName.c_str(), args.fInputColor, - srgbFuncName.c_str(), args.fInputColor, - args.fInputColor); - } - } - - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { - const GrGammaEffect& ge = proc.cast(); - if (GrGammaEffect::Mode::kExponential == ge.mode()) { - pdman.set1f(fGammaUni, ge.gamma()); - } - } - - static inline void GenKey(const GrProcessor& processor, const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { - const GrGammaEffect& ge = processor.cast(); - uint32_t key = static_cast(ge.mode()); - b->add32(key); - } - -private: - GrGLSLProgramDataManager::UniformHandle fGammaUni; - - typedef GrGLSLFragmentProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -GrGammaEffect::GrGammaEffect(Mode mode, SkScalar gamma) - : fMode(mode) - , fGamma(gamma) { - this->initClassID(); -} - -bool GrGammaEffect::onIsEqual(const GrFragmentProcessor& s) const { - const GrGammaEffect& other = s.cast(); - return - other.fMode == fMode && - (fMode != Mode::kExponential || other.fGamma == fGamma); -} - -void GrGammaEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); -} - -/////////////////////////////////////////////////////////////////////////////// - -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrGammaEffect); - -sk_sp GrGammaEffect::TestCreate(GrProcessorTestData* d) { - // We want to be sure and test sRGB sometimes - Mode testMode = static_cast(d->fRandom->nextRangeU(0, 2)); - SkScalar gamma = d->fRandom->nextRangeScalar(0.5f, 2.0f); - return sk_sp(new GrGammaEffect(testMode, gamma)); -} - -/////////////////////////////////////////////////////////////////////////////// - -void GrGammaEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const { - GrGLGammaEffect::GenKey(*this, caps, b); -} - -GrGLSLFragmentProcessor* GrGammaEffect::onCreateGLSLInstance() const { - return new GrGLGammaEffect(); -} - -sk_sp GrGammaEffect::Make(SkScalar gamma) { - // TODO: Once our public-facing API for specifying gamma curves settles down, expose this, - // and allow clients to explicitly request sRGB, rather than inferring from the exponent. - // Note that AdobeRGB (for example) is speficied as x^2.2, not the Rec.709 curves. - if (SkScalarNearlyEqual(gamma, 2.2f)) { - return sk_sp(new GrGammaEffect(Mode::kSRGBToLinear, 2.2f)); - } else if (SkScalarNearlyEqual(gamma, 1.0f / 2.2f)) { - return sk_sp(new GrGammaEffect(Mode::kLinearToSRGB, 1.0f / 2.2f)); - } else { - return sk_sp(new GrGammaEffect(Mode::kExponential, gamma)); - } -} diff --git a/gfx/skia/skia/src/gpu/effects/GrGammaEffect.h b/gfx/skia/skia/src/gpu/effects/GrGammaEffect.h deleted file mode 100644 index 3f84ac91e0fe..000000000000 --- a/gfx/skia/skia/src/gpu/effects/GrGammaEffect.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrGammaEffect_DEFINED -#define GrGammaEffect_DEFINED - -#include "GrFragmentProcessor.h" - -class GrGammaEffect : public GrFragmentProcessor { -public: - enum class Mode { - kLinearToSRGB, - kSRGBToLinear, - kExponential, - }; - - /** - * Creates an effect that applies a gamma curve. - */ - static sk_sp Make(SkScalar gamma); - - const char* name() const override { return "Gamma"; } - - Mode mode() const { return fMode; } - SkScalar gamma() const { return fGamma; } - -private: - GrGammaEffect(Mode mode, SkScalar gamma); - - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; - bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - Mode fMode; - SkScalar fGamma; - - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - - typedef GrFragmentProcessor INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp b/gfx/skia/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp new file mode 100644 index 000000000000..b4f13143d879 --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp @@ -0,0 +1,246 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrGaussianConvolutionFragmentProcessor.h" + +#include "GrProxyMove.h" +#include "GrTextureProxy.h" +#include "../private/GrGLSL.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" + +// For brevity +typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; + +class GrGLConvolutionEffect : public GrGLSLFragmentProcessor { +public: + void emitCode(EmitArgs&) override; + + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); + +protected: + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; + +private: + UniformHandle fKernelUni; + UniformHandle fImageIncrementUni; + UniformHandle fBoundsUni; + + typedef GrGLSLFragmentProcessor INHERITED; +}; + +void GrGLConvolutionEffect::emitCode(EmitArgs& args) { + const GrGaussianConvolutionFragmentProcessor& ce = + args.fFp.cast(); + + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, + kDefault_GrSLPrecision, "ImageIncrement"); + if (ce.useBounds()) { + fBoundsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, + kDefault_GrSLPrecision, "Bounds"); + } + + int width = Gr1DKernelEffect::WidthFromRadius(ce.radius()); + + int arrayCount = (width + 3) / 4; + SkASSERT(4 * arrayCount >= width); + + fKernelUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag, kVec4f_GrSLType, + kDefault_GrSLPrecision, "Kernel", arrayCount); + + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); + + fragBuilder->codeAppendf("%s = vec4(0, 0, 0, 0);", args.fOutputColor); + + const GrShaderVar& kernel = uniformHandler->getUniformVariable(fKernelUni); + const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); + + fragBuilder->codeAppendf("vec2 coord = %s - %d.0 * %s;", coords2D.c_str(), ce.radius(), imgInc); + + // Manually unroll loop because some drivers don't; yields 20-30% speedup. + const char* kVecSuffix[4] = {".x", ".y", ".z", ".w"}; + for (int i = 0; i < width; i++) { + SkString index; + SkString kernelIndex; + index.appendS32(i / 4); + kernel.appendArrayAccess(index.c_str(), &kernelIndex); + kernelIndex.append(kVecSuffix[i & 0x3]); + + if (ce.useBounds()) { + // We used to compute a bool indicating whether we're in bounds or not, cast it to a + // float, and then mul weight*texture_sample by the float. However, the Adreno 430 seems + // to have a bug that caused corruption. + const char* bounds = uniformHandler->getUniformCStr(fBoundsUni); + const char* component = ce.direction() == Gr1DKernelEffect::kY_Direction ? "y" : "x"; + fragBuilder->codeAppendf("if (coord.%s >= %s.x && coord.%s <= %s.y) {", component, + bounds, component, bounds); + } + fragBuilder->codeAppendf("%s += ", args.fOutputColor); + fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord"); + fragBuilder->codeAppendf(" * %s;\n", kernelIndex.c_str()); + if (ce.useBounds()) { + fragBuilder->codeAppend("}"); + } + fragBuilder->codeAppendf("coord += %s;\n", imgInc); + } + + SkString modulate; + GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); + fragBuilder->codeAppend(modulate.c_str()); +} + +void GrGLConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& processor) { + const GrGaussianConvolutionFragmentProcessor& conv = + processor.cast(); + GrTexture& texture = *conv.textureSampler(0).texture(); + + float imageIncrement[2] = {0}; + float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; + switch (conv.direction()) { + case Gr1DKernelEffect::kX_Direction: + imageIncrement[0] = 1.0f / texture.width(); + break; + case Gr1DKernelEffect::kY_Direction: + imageIncrement[1] = ySign / texture.height(); + break; + default: + SkFAIL("Unknown filter direction."); + } + pdman.set2fv(fImageIncrementUni, 1, imageIncrement); + if (conv.useBounds()) { + const int* bounds = conv.bounds(); + if (Gr1DKernelEffect::kX_Direction == conv.direction()) { + SkScalar inv = SkScalarInvert(SkIntToScalar(texture.width())); + pdman.set2f(fBoundsUni, inv * bounds[0], inv * bounds[1]); + } else { + SkScalar inv = SkScalarInvert(SkIntToScalar(texture.height())); + if (texture.origin() != kTopLeft_GrSurfaceOrigin) { + pdman.set2f(fBoundsUni, 1.0f - (inv * bounds[1]), 1.0f - (inv * bounds[0])); + } else { + pdman.set2f(fBoundsUni, inv * bounds[1], inv * bounds[0]); + } + } + } + int width = Gr1DKernelEffect::WidthFromRadius(conv.radius()); + + int arrayCount = (width + 3) / 4; + SkASSERT(4 * arrayCount >= width); + pdman.set4fv(fKernelUni, arrayCount, conv.kernel()); +} + +void GrGLConvolutionEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, + GrProcessorKeyBuilder* b) { + const GrGaussianConvolutionFragmentProcessor& conv = + processor.cast(); + uint32_t key = conv.radius(); + key <<= 2; + if (conv.useBounds()) { + key |= 0x2; + key |= GrGaussianConvolutionFragmentProcessor::kY_Direction == conv.direction() ? 0x1 : 0x0; + } + b->add32(key); +} + +/////////////////////////////////////////////////////////////////////////////// +static void fill_in_1D_guassian_kernel(float* kernel, int width, float gaussianSigma, int radius) { + const float denom = 1.0f / (2.0f * gaussianSigma * gaussianSigma); + + float sum = 0.0f; + for (int i = 0; i < width; ++i) { + float x = static_cast(i - radius); + // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian + // is dropped here, since we renormalize the kernel below. + kernel[i] = sk_float_exp(-x * x * denom); + sum += kernel[i]; + } + // Normalize the kernel + float scale = 1.0f / sum; + for (int i = 0; i < width; ++i) { + kernel[i] *= scale; + } +} + +GrGaussianConvolutionFragmentProcessor::GrGaussianConvolutionFragmentProcessor( + GrResourceProvider* resourceProvider, + sk_sp proxy, + Direction direction, + int radius, + float gaussianSigma, + bool useBounds, + int bounds[2]) + : INHERITED{resourceProvider, + ModulationFlags(proxy->config()), + GR_PROXY_MOVE(proxy), + direction, + radius} + , fUseBounds(useBounds) { + this->initClassID(); + SkASSERT(radius <= kMaxKernelRadius); + + fill_in_1D_guassian_kernel(fKernel, this->width(), gaussianSigma, this->radius()); + + memcpy(fBounds, bounds, sizeof(fBounds)); +} + +GrGaussianConvolutionFragmentProcessor::~GrGaussianConvolutionFragmentProcessor() {} + +void GrGaussianConvolutionFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const { + GrGLConvolutionEffect::GenKey(*this, caps, b); +} + +GrGLSLFragmentProcessor* GrGaussianConvolutionFragmentProcessor::onCreateGLSLInstance() const { + return new GrGLConvolutionEffect; +} + +bool GrGaussianConvolutionFragmentProcessor::onIsEqual(const GrFragmentProcessor& sBase) const { + const GrGaussianConvolutionFragmentProcessor& s = + sBase.cast(); + return (this->radius() == s.radius() && this->direction() == s.direction() && + this->useBounds() == s.useBounds() && + 0 == memcmp(fBounds, s.fBounds, sizeof(fBounds)) && + 0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float))); +} + +/////////////////////////////////////////////////////////////////////////////// + +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrGaussianConvolutionFragmentProcessor); + +#if GR_TEST_UTILS +sk_sp GrGaussianConvolutionFragmentProcessor::TestCreate( + GrProcessorTestData* d) { + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); + + bool useBounds = d->fRandom->nextBool(); + int bounds[2]; + + Direction dir; + if (d->fRandom->nextBool()) { + dir = kX_Direction; + bounds[0] = d->fRandom->nextRangeU(0, proxy->width()-1); + bounds[1] = d->fRandom->nextRangeU(bounds[0], proxy->width()-1); + } else { + dir = kY_Direction; + bounds[0] = d->fRandom->nextRangeU(0, proxy->height()-1); + bounds[1] = d->fRandom->nextRangeU(bounds[0], proxy->height()-1); + } + + int radius = d->fRandom->nextRangeU(1, kMaxKernelRadius); + float sigma = radius / 3.f; + + return GrGaussianConvolutionFragmentProcessor::Make( + d->resourceProvider(), d->textureProxy(texIdx), + dir, radius, sigma, useBounds, bounds); +} +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h b/gfx/skia/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h new file mode 100644 index 000000000000..dfe423466dc6 --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h @@ -0,0 +1,73 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGaussianConvolutionFragmentProcessor_DEFINED +#define GrGaussianConvolutionFragmentProcessor_DEFINED + +#include "Gr1DKernelEffect.h" + +/** + * A 1D Gaussian convolution effect. The kernel is computed as an array of 2 * half-width weights. + * Each texel is multiplied by it's weight and summed to determine the filtered color. The output + * color is set to a modulation of the filtered and input colors. + */ +class GrGaussianConvolutionFragmentProcessor : public Gr1DKernelEffect { +public: + /// Convolve with a Gaussian kernel + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, + Direction dir, + int halfWidth, + float gaussianSigma, + bool useBounds, + int* bounds) { + return sk_sp(new GrGaussianConvolutionFragmentProcessor( + resourceProvider, std::move(proxy), dir, halfWidth, gaussianSigma, useBounds, bounds)); + } + + ~GrGaussianConvolutionFragmentProcessor() override; + + const float* kernel() const { return fKernel; } + + const int* bounds() const { return fBounds; } + bool useBounds() const { return fUseBounds; } + + const char* name() const override { return "GaussianConvolution"; } + + // This was decided based on the min allowed value for the max texture + // samples per fragment program run in DX9SM2 (32). A sigma param of 4.0 + // on a blur filter gives a kernel width of 25 while a sigma of 5.0 + // would exceed a 32 wide kernel. + static const int kMaxKernelRadius = 12; + // With a C++11 we could have a constexpr version of WidthFromRadius() + // and not have to duplicate this calculation. + static const int kMaxKernelWidth = 2 * kMaxKernelRadius + 1; + +private: + /// Convolve with a Gaussian kernel + GrGaussianConvolutionFragmentProcessor(GrResourceProvider*, sk_sp, Direction, + int halfWidth, float gaussianSigma, bool useBounds, + int bounds[2]); + + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; + + bool onIsEqual(const GrFragmentProcessor&) const override; + + GR_DECLARE_FRAGMENT_PROCESSOR_TEST; + + // TODO: Inline the kernel constants into the generated shader code. This may involve pulling + // some of the logic from SkGpuBlurUtils into this class related to radius/sigma calculations. + float fKernel[kMaxKernelWidth]; + bool fUseBounds; + int fBounds[2]; + + typedef Gr1DKernelEffect INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp index a07b67128bac..03d90ea67558 100644 --- a/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp @@ -5,19 +5,22 @@ * found in the LICENSE file. */ #include "GrMatrixConvolutionEffect.h" + +#include "GrTextureProxy.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" +#include "../private/GrGLSL.h" class GrGLMatrixConvolutionEffect : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; @@ -82,7 +85,7 @@ void GrGLMatrixConvolutionEffect::emitCode(EmitArgs& args) { coord.printf("coord + vec2(%d, %d) * %s", x, y, imgInc); fDomain.sampleTexture(fragBuilder, uniformHandler, - args.fGLSLCaps, + args.fShaderCaps, domain, "c", coord, @@ -96,18 +99,19 @@ void GrGLMatrixConvolutionEffect::emitCode(EmitArgs& args) { } if (mce.convolveAlpha()) { fragBuilder->codeAppendf("%s = sum * %s + %s;", args.fOutputColor, gain, bias); + fragBuilder->codeAppendf("%s.a = clamp(%s.a, 0, 1);", args.fOutputColor, args.fOutputColor); fragBuilder->codeAppendf("%s.rgb = clamp(%s.rgb, 0.0, %s.a);", args.fOutputColor, args.fOutputColor, args.fOutputColor); } else { fDomain.sampleTexture(fragBuilder, uniformHandler, - args.fGLSLCaps, + args.fShaderCaps, domain, "c", coords2D, args.fTexSamplers[0]); fragBuilder->codeAppendf("%s.a = c.a;", args.fOutputColor); - fragBuilder->codeAppendf("%s.rgb = sum.rgb * %s + %s;", args.fOutputColor, gain, bias); + fragBuilder->codeAppendf("%s.rgb = clamp(sum.rgb * %s + %s, 0, 1);", args.fOutputColor, gain, bias); fragBuilder->codeAppendf("%s.rgb *= %s.a;", args.fOutputColor, args.fOutputColor); } @@ -117,7 +121,7 @@ void GrGLMatrixConvolutionEffect::emitCode(EmitArgs& args) { } void GrGLMatrixConvolutionEffect::GenKey(const GrProcessor& processor, - const GrGLSLCaps&, GrProcessorKeyBuilder* b) { + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrMatrixConvolutionEffect& m = processor.cast(); SkASSERT(m.kernelSize().width() <= 0x7FFF && m.kernelSize().height() <= 0xFFFF); uint32_t key = m.kernelSize().width() << 16 | m.kernelSize().height(); @@ -127,14 +131,14 @@ void GrGLMatrixConvolutionEffect::GenKey(const GrProcessor& processor, } void GrGLMatrixConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrFragmentProcessor& processor) { const GrMatrixConvolutionEffect& conv = processor.cast(); - GrTexture& texture = *conv.texture(0); + GrTexture* texture = conv.textureSampler(0).texture(); float imageIncrement[2]; - float ySign = texture.origin() == kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; - imageIncrement[0] = 1.0f / texture.width(); - imageIncrement[1] = ySign / texture.height(); + float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; + imageIncrement[0] = 1.0f / texture->width(); + imageIncrement[1] = ySign / texture->height(); pdman.set2fv(fImageIncrementUni, 1, imageIncrement); pdman.set2fv(fKernelOffsetUni, 1, conv.kernelOffset()); int kernelCount = conv.kernelSize().width() * conv.kernelSize().height(); @@ -143,10 +147,11 @@ void GrGLMatrixConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdma pdman.set4fv(fKernelUni, arrayCount, conv.kernel()); pdman.set1f(fGainUni, conv.gain()); pdman.set1f(fBiasUni, conv.bias()); - fDomain.setData(pdman, conv.domain(), texture.origin()); + fDomain.setData(pdman, conv.domain(), texture); } -GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture, +GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, const SkIRect& bounds, const SkISize& kernelSize, const SkScalar* kernel, @@ -155,12 +160,14 @@ GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture, const SkIPoint& kernelOffset, GrTextureDomain::Mode tileMode, bool convolveAlpha) - : INHERITED(texture, nullptr, GrCoordTransform::MakeDivByTextureWHMatrix(texture)), - fKernelSize(kernelSize), - fGain(SkScalarToFloat(gain)), - fBias(SkScalarToFloat(bias) / 255.0f), - fConvolveAlpha(convolveAlpha), - fDomain(GrTextureDomain::MakeTexelDomainForMode(texture, bounds, tileMode), tileMode) { + // To advertise either the modulation or opaqueness optimizations we'd have to examine the + // parameters. + : INHERITED(resourceProvider, kNone_OptimizationFlags, proxy, nullptr, SkMatrix::I()) + , fKernelSize(kernelSize) + , fGain(SkScalarToFloat(gain)) + , fBias(SkScalarToFloat(bias) / 255.0f) + , fConvolveAlpha(convolveAlpha) + , fDomain(proxy.get(), GrTextureDomain::MakeTexelDomainForMode(bounds, tileMode), tileMode) { this->initClassID(); for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) { fKernel[i] = SkScalarToFloat(kernel[i]); @@ -169,7 +176,7 @@ GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture, fKernelOffset[1] = static_cast(kernelOffset.y()); } -void GrMatrixConvolutionEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrMatrixConvolutionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLMatrixConvolutionEffect::GenKey(*this, caps, b); } @@ -190,58 +197,69 @@ bool GrMatrixConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) cons fDomain == s.domain(); } -// Static function to create a 2D convolution -sk_sp -GrMatrixConvolutionEffect::MakeGaussian(GrTexture* texture, - const SkIRect& bounds, - const SkISize& kernelSize, - SkScalar gain, - SkScalar bias, - const SkIPoint& kernelOffset, - GrTextureDomain::Mode tileMode, - bool convolveAlpha, - SkScalar sigmaX, - SkScalar sigmaY) { - float kernel[MAX_KERNEL_SIZE]; - int width = kernelSize.width(); - int height = kernelSize.height(); +static void fill_in_2D_gaussian_kernel(float* kernel, int width, int height, + SkScalar sigmaX, SkScalar sigmaY) { SkASSERT(width * height <= MAX_KERNEL_SIZE); + const float sigmaXDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaX))); + const float sigmaYDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaY))); + const int xRadius = width / 2; + const int yRadius = height / 2; + float sum = 0.0f; - float sigmaXDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaX))); - float sigmaYDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaY))); - int xRadius = width / 2; - int yRadius = height / 2; for (int x = 0; x < width; x++) { - float xTerm = static_cast(x - xRadius); - xTerm = xTerm * xTerm * sigmaXDenom; - for (int y = 0; y < height; y++) { - float yTerm = static_cast(y - yRadius); - float xyTerm = sk_float_exp(-(xTerm + yTerm * yTerm * sigmaYDenom)); - // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian - // is dropped here, since we renormalize the kernel below. - kernel[y * width + x] = xyTerm; - sum += xyTerm; - } + float xTerm = static_cast(x - xRadius); + xTerm = xTerm * xTerm * sigmaXDenom; + for (int y = 0; y < height; y++) { + float yTerm = static_cast(y - yRadius); + float xyTerm = sk_float_exp(-(xTerm + yTerm * yTerm * sigmaYDenom)); + // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian + // is dropped here, since we renormalize the kernel below. + kernel[y * width + x] = xyTerm; + sum += xyTerm; + } } // Normalize the kernel float scale = 1.0f / sum; for (int i = 0; i < width * height; ++i) { kernel[i] *= scale; } +} + + +// Static function to create a 2D convolution +sk_sp GrMatrixConvolutionEffect::MakeGaussian( + GrResourceProvider* resourceProvider, + sk_sp proxy, + const SkIRect& bounds, + const SkISize& kernelSize, + SkScalar gain, + SkScalar bias, + const SkIPoint& kernelOffset, + GrTextureDomain::Mode tileMode, + bool convolveAlpha, + SkScalar sigmaX, + SkScalar sigmaY) { + float kernel[MAX_KERNEL_SIZE]; + + fill_in_2D_gaussian_kernel(kernel, kernelSize.width(), kernelSize.height(), sigmaX, sigmaY); + return sk_sp( - new GrMatrixConvolutionEffect(texture, bounds, kernelSize, kernel, gain, bias, - kernelOffset, tileMode, convolveAlpha)); + new GrMatrixConvolutionEffect(resourceProvider, std::move(proxy), bounds, kernelSize, + kernel, gain, bias, kernelOffset, tileMode, convolveAlpha)); } GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMatrixConvolutionEffect); +#if GR_TEST_UTILS sk_sp GrMatrixConvolutionEffect::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); + int width = d->fRandom->nextRangeU(1, MAX_KERNEL_SIZE); int height = d->fRandom->nextRangeU(1, MAX_KERNEL_SIZE / width); SkISize kernelSize = SkISize::Make(width, height); - SkAutoTDeleteArray kernel(new SkScalar[width * height]); + std::unique_ptr kernel(new SkScalar[width * height]); for (int i = 0; i < width * height; i++) { kernel.get()[i] = d->fRandom->nextSScalar1(); } @@ -249,14 +267,15 @@ sk_sp GrMatrixConvolutionEffect::TestCreate(GrProcessorTest SkScalar bias = d->fRandom->nextSScalar1(); SkIPoint kernelOffset = SkIPoint::Make(d->fRandom->nextRangeU(0, kernelSize.width()), d->fRandom->nextRangeU(0, kernelSize.height())); - SkIRect bounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, d->fTextures[texIdx]->width()), - d->fRandom->nextRangeU(0, d->fTextures[texIdx]->height()), - d->fRandom->nextRangeU(0, d->fTextures[texIdx]->width()), - d->fRandom->nextRangeU(0, d->fTextures[texIdx]->height())); + SkIRect bounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, proxy->width()), + d->fRandom->nextRangeU(0, proxy->height()), + d->fRandom->nextRangeU(0, proxy->width()), + d->fRandom->nextRangeU(0, proxy->height())); GrTextureDomain::Mode tileMode = static_cast(d->fRandom->nextRangeU(0, 2)); bool convolveAlpha = d->fRandom->nextBool(); - return GrMatrixConvolutionEffect::Make(d->fTextures[texIdx], + return GrMatrixConvolutionEffect::Make(d->resourceProvider(), + std::move(proxy), bounds, kernelSize, kernel.get(), @@ -266,3 +285,4 @@ sk_sp GrMatrixConvolutionEffect::TestCreate(GrProcessorTest tileMode, convolveAlpha); } +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.h b/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.h index b8df43768125..6104f11402b9 100644 --- a/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.h +++ b/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.h @@ -9,7 +9,6 @@ #define GrMatrixConvolutionEffect_DEFINED #include "GrSingleTextureEffect.h" -#include "GrInvariantOutput.h" #include "GrTextureDomain.h" // A little bit less than the minimum # uniforms required by DX9SM2 (32). @@ -18,7 +17,8 @@ class GrMatrixConvolutionEffect : public GrSingleTextureEffect { public: - static sk_sp Make(GrTexture* texture, + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, const SkIRect& bounds, const SkISize& kernelSize, const SkScalar* kernel, @@ -28,11 +28,12 @@ public: GrTextureDomain::Mode tileMode, bool convolveAlpha) { return sk_sp( - new GrMatrixConvolutionEffect(texture, bounds, kernelSize, kernel, gain, bias, - kernelOffset, tileMode, convolveAlpha)); + new GrMatrixConvolutionEffect(resourceProvider, std::move(proxy), bounds, kernelSize, + kernel, gain, bias, kernelOffset, tileMode, convolveAlpha)); } - static sk_sp MakeGaussian(GrTexture* texture, + static sk_sp MakeGaussian(GrResourceProvider*, + sk_sp proxy, const SkIRect& bounds, const SkISize& kernelSize, SkScalar gain, @@ -55,7 +56,8 @@ public: const char* name() const override { return "MatrixConvolution"; } private: - GrMatrixConvolutionEffect(GrTexture*, + GrMatrixConvolutionEffect(GrResourceProvider*, + sk_sp proxy, const SkIRect& bounds, const SkISize& kernelSize, const SkScalar* kernel, @@ -67,15 +69,10 @@ private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - // TODO: Try to do better? - inout->mulByUnknownFourComponents(); - } - SkIRect fBounds; SkISize fKernelSize; float fKernel[MAX_KERNEL_SIZE]; diff --git a/gfx/skia/skia/src/gpu/effects/GrNonlinearColorSpaceXformEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrNonlinearColorSpaceXformEffect.cpp new file mode 100644 index 000000000000..c6c0c26574b0 --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrNonlinearColorSpaceXformEffect.cpp @@ -0,0 +1,245 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrNonlinearColorSpaceXformEffect.h" + +#include "GrProcessor.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" + +#include "SkColorSpace_Base.h" + +class GrGLNonlinearColorSpaceXformEffect : public GrGLSLFragmentProcessor { +public: + void emitCode(EmitArgs& args) override { + const GrNonlinearColorSpaceXformEffect& csxe = + args.fFp.cast(); + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + + const char* srcCoeffsName = nullptr; + if (SkToBool(csxe.ops() & GrNonlinearColorSpaceXformEffect::kSrcTransfer_Op)) { + fSrcTransferFnUni = uniformHandler->addUniformArray( + kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, + "SrcTransferFn", GrNonlinearColorSpaceXformEffect::kNumTransferFnCoeffs, + &srcCoeffsName); + } + + const char* dstCoeffsName = nullptr; + if (SkToBool(csxe.ops() & GrNonlinearColorSpaceXformEffect::kDstTransfer_Op)) { + fDstTransferFnUni = uniformHandler->addUniformArray( + kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, + "DstTransferFn", GrNonlinearColorSpaceXformEffect::kNumTransferFnCoeffs, + &dstCoeffsName); + } + + const char* gamutXformName = nullptr; + if (SkToBool(csxe.ops() & GrNonlinearColorSpaceXformEffect::kGamutXform_Op)) { + fGamutXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kMat44f_GrSLType, + kDefault_GrSLPrecision, "GamutXform", + &gamutXformName); + } + + // Helper function to apply a transfer function to a single value + SkString tfFuncNameString; + static const GrShaderVar gTransferFnFuncArgs[] = { + GrShaderVar("x", kFloat_GrSLType), + GrShaderVar("coeffs", kFloat_GrSLType, + GrNonlinearColorSpaceXformEffect::kNumTransferFnCoeffs), + }; + SkString transferFnBody; + // Temporaries to make evaluation line readable + transferFnBody.printf("float A = coeffs[0];"); + transferFnBody.append("float B = coeffs[1];"); + transferFnBody.append("float C = coeffs[2];"); + transferFnBody.append("float D = coeffs[3];"); + transferFnBody.append("float E = coeffs[4];"); + transferFnBody.append("float F = coeffs[5];"); + transferFnBody.append("float G = coeffs[6];"); + transferFnBody.appendf("return (x < D) ? (C * x) + F : pow(A * x + B, G) + E;"); + fragBuilder->emitFunction(kFloat_GrSLType, "transfer_fn", + SK_ARRAY_COUNT(gTransferFnFuncArgs), gTransferFnFuncArgs, + transferFnBody.c_str(), &tfFuncNameString); + const char* tfFuncName = tfFuncNameString.c_str(); + + if (nullptr == args.fInputColor) { + args.fInputColor = "vec4(1)"; + } + fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor); + + // 1: Un-premultiply the input color (if necessary) + fragBuilder->codeAppendf("float nonZeroAlpha = max(color.a, 0.00001);"); + fragBuilder->codeAppendf("color = vec4(color.rgb / nonZeroAlpha, nonZeroAlpha);"); + + // 2: Apply src transfer function (to get to linear RGB) + if (srcCoeffsName) { + fragBuilder->codeAppendf("color.r = %s(color.r, %s);", tfFuncName, srcCoeffsName); + fragBuilder->codeAppendf("color.g = %s(color.g, %s);", tfFuncName, srcCoeffsName); + fragBuilder->codeAppendf("color.b = %s(color.b, %s);", tfFuncName, srcCoeffsName); + } + + // 3: Apply gamut matrix + if (gamutXformName) { + // Color is unpremultiplied at this point, so clamp to [0, 1] + fragBuilder->codeAppendf( + "color.rgb = clamp((%s * vec4(color.rgb, 1.0)).rgb, 0.0, 1.0);", gamutXformName); + } + + // 4: Apply dst transfer fn + if (dstCoeffsName) { + fragBuilder->codeAppendf("color.r = %s(color.r, %s);", tfFuncName, dstCoeffsName); + fragBuilder->codeAppendf("color.g = %s(color.g, %s);", tfFuncName, dstCoeffsName); + fragBuilder->codeAppendf("color.b = %s(color.b, %s);", tfFuncName, dstCoeffsName); + } + + // 5: Premultiply again + fragBuilder->codeAppendf("%s = vec4(color.rgb * color.a, color.a);", args.fOutputColor); + } + + static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&, + GrProcessorKeyBuilder* b) { + const GrNonlinearColorSpaceXformEffect& csxe = + processor.cast(); + b->add32(csxe.ops()); + } + +protected: + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& processor) override { + const GrNonlinearColorSpaceXformEffect& csxe = + processor.cast(); + if (SkToBool(csxe.ops() & GrNonlinearColorSpaceXformEffect::kSrcTransfer_Op)) { + pdman.set1fv(fSrcTransferFnUni, GrNonlinearColorSpaceXformEffect::kNumTransferFnCoeffs, + csxe.srcTransferFnCoeffs()); + } + if (SkToBool(csxe.ops() & GrNonlinearColorSpaceXformEffect::kDstTransfer_Op)) { + pdman.set1fv(fDstTransferFnUni, GrNonlinearColorSpaceXformEffect::kNumTransferFnCoeffs, + csxe.dstTransferFnCoeffs()); + } + if (SkToBool(csxe.ops() & GrNonlinearColorSpaceXformEffect::kGamutXform_Op)) { + pdman.setSkMatrix44(fGamutXformUni, csxe.gamutXform()); + } + } + +private: + GrGLSLProgramDataManager::UniformHandle fSrcTransferFnUni; + GrGLSLProgramDataManager::UniformHandle fDstTransferFnUni; + GrGLSLProgramDataManager::UniformHandle fGamutXformUni; + + typedef GrGLSLFragmentProcessor INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +GrNonlinearColorSpaceXformEffect::GrNonlinearColorSpaceXformEffect( + uint32_t ops, const SkColorSpaceTransferFn& srcTransferFn, + const SkColorSpaceTransferFn& dstTransferFn, const SkMatrix44& gamutXform) + : INHERITED(kPreservesOpaqueInput_OptimizationFlag) + , fGamutXform(gamutXform) + , fOps(ops) { + this->initClassID(); + + fSrcTransferFnCoeffs[0] = srcTransferFn.fA; + fSrcTransferFnCoeffs[1] = srcTransferFn.fB; + fSrcTransferFnCoeffs[2] = srcTransferFn.fC; + fSrcTransferFnCoeffs[3] = srcTransferFn.fD; + fSrcTransferFnCoeffs[4] = srcTransferFn.fE; + fSrcTransferFnCoeffs[5] = srcTransferFn.fF; + fSrcTransferFnCoeffs[6] = srcTransferFn.fG; + + fDstTransferFnCoeffs[0] = dstTransferFn.fA; + fDstTransferFnCoeffs[1] = dstTransferFn.fB; + fDstTransferFnCoeffs[2] = dstTransferFn.fC; + fDstTransferFnCoeffs[3] = dstTransferFn.fD; + fDstTransferFnCoeffs[4] = dstTransferFn.fE; + fDstTransferFnCoeffs[5] = dstTransferFn.fF; + fDstTransferFnCoeffs[6] = dstTransferFn.fG; +} + +bool GrNonlinearColorSpaceXformEffect::onIsEqual(const GrFragmentProcessor& s) const { + const GrNonlinearColorSpaceXformEffect& other = s.cast(); + if (other.fOps != fOps) { + return false; + } + if (SkToBool(fOps & kSrcTransfer_Op) && + memcmp(&other.fSrcTransferFnCoeffs, &fSrcTransferFnCoeffs, sizeof(fSrcTransferFnCoeffs))) { + return false; + } + if (SkToBool(fOps & kDstTransfer_Op) && + memcmp(&other.fDstTransferFnCoeffs, &fDstTransferFnCoeffs, sizeof(fDstTransferFnCoeffs))) { + return false; + } + if (SkToBool(fOps & kGamutXform_Op) && other.fGamutXform != fGamutXform) { + return false; + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrNonlinearColorSpaceXformEffect); + +#if GR_TEST_UTILS +sk_sp GrNonlinearColorSpaceXformEffect::TestCreate(GrProcessorTestData* d) { + // TODO: Generate a random variety of color spaces for this effect (it can handle wacky + // transfer functions, etc...) + sk_sp srcSpace = SkColorSpace::MakeSRGBLinear(); + sk_sp dstSpace = SkColorSpace::MakeSRGB(); + return GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), dstSpace.get()); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// + +void GrNonlinearColorSpaceXformEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const { + GrGLNonlinearColorSpaceXformEffect::GenKey(*this, caps, b); +} + +GrGLSLFragmentProcessor* GrNonlinearColorSpaceXformEffect::onCreateGLSLInstance() const { + return new GrGLNonlinearColorSpaceXformEffect(); +} + +sk_sp GrNonlinearColorSpaceXformEffect::Make(const SkColorSpace* src, + const SkColorSpace* dst) { + if (!src || !dst || SkColorSpace::Equals(src, dst)) { + // No conversion possible (or necessary) + return nullptr; + } + + uint32_t ops = 0; + + // We rely on GrColorSpaceXform to build the gamut xform matrix for us (to get caching) + auto gamutXform = GrColorSpaceXform::Make(src, dst); + SkMatrix44 srcToDstMtx(SkMatrix44::kUninitialized_Constructor); + if (gamutXform) { + ops |= kGamutXform_Op; + srcToDstMtx = gamutXform->srcToDst(); + } + + SkColorSpaceTransferFn srcTransferFn; + if (!src->gammaIsLinear()) { + if (src->isNumericalTransferFn(&srcTransferFn)) { + ops |= kSrcTransfer_Op; + } else { + return nullptr; + } + } + + SkColorSpaceTransferFn dstTransferFn; + if (!dst->gammaIsLinear()) { + if (dst->isNumericalTransferFn(&dstTransferFn)) { + dstTransferFn = dstTransferFn.invert(); + ops |= kDstTransfer_Op; + } else { + return nullptr; + } + } + + return sk_sp(new GrNonlinearColorSpaceXformEffect( + ops, srcTransferFn, dstTransferFn, srcToDstMtx)); +} diff --git a/gfx/skia/skia/src/gpu/effects/GrNonlinearColorSpaceXformEffect.h b/gfx/skia/skia/src/gpu/effects/GrNonlinearColorSpaceXformEffect.h new file mode 100644 index 000000000000..36f778398eff --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrNonlinearColorSpaceXformEffect.h @@ -0,0 +1,72 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrNonlinearColorSpaceXformEffect_DEFINED +#define GrNonlinearColorSpaceXformEffect_DEFINED + +#include "GrFragmentProcessor.h" +#include "SkColorSpace.h" +#include "SkMatrix44.h" + +/** + * The output of this effect is the input, transformed into a different color space. + * This effect is used for nonlinear blending color space support - it does not assume HW sRGB + * capabilities, and performs both the source and destination transfer functions numerically in + * the shader. Any parametric transfer function is supported. Because of the nonlinear blending, + * premultiplication is also nonlinear - source pixels are unpremultiplied before the source + * transfer function, and then premultiplied after the destination transfer function. + */ +class GrNonlinearColorSpaceXformEffect : public GrFragmentProcessor { +public: + /** + * The conversion effect is only well defined with a valid source and destination color space. + * This will return nullptr if either space is nullptr, if both spaces are equal, or if either + * space has a non-parametric transfer funcion (e.g. lookup table or A2B). + */ + static sk_sp Make(const SkColorSpace* src, const SkColorSpace* dst); + + const char* name() const override { return "NonlinearColorSpaceXform"; } + + static const int kNumTransferFnCoeffs = 7; + + /** + * Flags that specify which operations are performed for one particular conversion. + * Some color space pairs may not need all operations, if one or both transfer functions + * is linear, or if the gamuts are the same. + */ + enum Ops { + kSrcTransfer_Op = 0x1, + kGamutXform_Op = 0x2, + kDstTransfer_Op = 0x4, + }; + + uint32_t ops() const { return fOps; } + const float* srcTransferFnCoeffs() const { return fSrcTransferFnCoeffs; } + const float* dstTransferFnCoeffs() const { return fDstTransferFnCoeffs; } + const SkMatrix44& gamutXform() const { return fGamutXform; } + +private: + GrNonlinearColorSpaceXformEffect(uint32_t ops, + const SkColorSpaceTransferFn& srcTransferFn, + const SkColorSpaceTransferFn& dstTransferFn, + const SkMatrix44& gamutXform); + + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; + bool onIsEqual(const GrFragmentProcessor&) const override; + + float fSrcTransferFnCoeffs[kNumTransferFnCoeffs]; + float fDstTransferFnCoeffs[kNumTransferFnCoeffs]; + SkMatrix44 fGamutXform; + uint32_t fOps; + + GR_DECLARE_FRAGMENT_PROCESSOR_TEST; + + typedef GrFragmentProcessor INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrOvalEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrOvalEffect.cpp index 97ea1e6d0ab9..672f5d873c7d 100644 --- a/gfx/skia/skia/src/gpu/effects/GrOvalEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrOvalEffect.cpp @@ -8,12 +8,13 @@ #include "GrOvalEffect.h" #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" #include "SkRect.h" +#include "GrShaderCaps.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" +#include "../private/GrGLSL.h" ////////////////////////////////////////////////////////////////////////////// @@ -22,7 +23,7 @@ public: static sk_sp Make(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius); - virtual ~CircleEffect() {} + ~CircleEffect() override {} const char* name() const override { return "Circle"; } @@ -36,12 +37,10 @@ private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - SkPoint fCenter; SkScalar fRadius; GrPrimitiveEdgeType fEdgeType; @@ -57,16 +56,12 @@ sk_sp CircleEffect::Make(GrPrimitiveEdgeType edgeType, cons return sk_sp(new CircleEffect(edgeType, center, radius)); } -void CircleEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->mulByUnknownSingleComponent(); -} - CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r) - : fCenter(c) - , fRadius(r) - , fEdgeType(edgeType) { + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fCenter(c) + , fRadius(r) + , fEdgeType(edgeType) { this->initClassID(); - this->setWillReadFragmentPosition(); } bool CircleEffect::onIsEqual(const GrFragmentProcessor& other) const { @@ -78,6 +73,7 @@ bool CircleEffect::onIsEqual(const GrFragmentProcessor& other) const { GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleEffect); +#if GR_TEST_UTILS sk_sp CircleEffect::TestCreate(GrProcessorTestData* d) { SkPoint center; center.fX = d->fRandom->nextRangeScalar(0.f, 1000.f); @@ -89,6 +85,7 @@ sk_sp CircleEffect::TestCreate(GrProcessorTestData* d) { } while (kHairlineAA_GrProcessorEdgeType == et); return CircleEffect::Make(et, center, radius); } +#endif ////////////////////////////////////////////////////////////////////////////// @@ -98,10 +95,10 @@ public: virtual void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fCircleUniform; @@ -122,7 +119,6 @@ void GLCircleEffect::emitCode(EmitArgs& args) { &circleName); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const char* fragmentPos = fragBuilder->fragmentPosition(); SkASSERT(kHairlineAA_GrProcessorEdgeType != ce.getEdgeType()); // TODO: Right now the distance to circle caclulation is performed in a space normalized to the @@ -130,11 +126,13 @@ void GLCircleEffect::emitCode(EmitArgs& args) { // mediump. It'd be nice to only to this on mediump devices but we currently don't have the // caps here. if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) { - fragBuilder->codeAppendf("float d = (length((%s.xy - %s.xy) * %s.w) - 1.0) * %s.z;", - circleName, fragmentPos, circleName, circleName); + fragBuilder->codeAppendf("float d = (length((%s.xy - sk_FragCoord.xy) * %s.w) - 1.0) * " + "%s.z;", + circleName, circleName, circleName); } else { - fragBuilder->codeAppendf("float d = (1.0 - length((%s.xy - %s.xy) * %s.w)) * %s.z;", - circleName, fragmentPos, circleName, circleName); + fragBuilder->codeAppendf("float d = (1.0 - length((%s.xy - sk_FragCoord.xy) * %s.w)) * " + "%s.z;", + circleName, circleName, circleName); } if (GrProcessorEdgeTypeIsAA(ce.getEdgeType())) { fragBuilder->codeAppend("d = clamp(d, 0.0, 1.0);"); @@ -146,14 +144,14 @@ void GLCircleEffect::emitCode(EmitArgs& args) { (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("d")).c_str()); } -void GLCircleEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&, +void GLCircleEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const CircleEffect& ce = processor.cast(); b->add32(ce.getEdgeType()); } void GLCircleEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrFragmentProcessor& processor) { const CircleEffect& ce = processor.cast(); if (ce.getRadius() != fPrevRadius || ce.getCenter() != fPrevCenter) { SkScalar radius = ce.getRadius(); @@ -171,7 +169,7 @@ void GLCircleEffect::onSetData(const GrGLSLProgramDataManager& pdman, /////////////////////////////////////////////////////////////////////////////////////////////////// -void CircleEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void CircleEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLCircleEffect::GenKey(*this, caps, b); } @@ -187,7 +185,7 @@ public: static sk_sp Make(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry); - virtual ~EllipseEffect() {} + ~EllipseEffect() override {} const char* name() const override { return "Ellipse"; } @@ -201,12 +199,10 @@ private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - SkPoint fCenter; SkVector fRadii; GrPrimitiveEdgeType fEdgeType; @@ -224,16 +220,13 @@ sk_sp EllipseEffect::Make(GrPrimitiveEdgeType edgeType, return sk_sp(new EllipseEffect(edgeType, center, rx, ry)); } -void EllipseEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->mulByUnknownSingleComponent(); -} - -EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx, SkScalar ry) - : fCenter(c) - , fRadii(SkVector::Make(rx, ry)) - , fEdgeType(edgeType) { +EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx, + SkScalar ry) + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fCenter(c) + , fRadii(SkVector::Make(rx, ry)) + , fEdgeType(edgeType) { this->initClassID(); - this->setWillReadFragmentPosition(); } bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const { @@ -245,6 +238,7 @@ bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const { GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipseEffect); +#if GR_TEST_UTILS sk_sp EllipseEffect::TestCreate(GrProcessorTestData* d) { SkPoint center; center.fX = d->fRandom->nextRangeScalar(0.f, 1000.f); @@ -257,6 +251,7 @@ sk_sp EllipseEffect::TestCreate(GrProcessorTestData* d) { } while (kHairlineAA_GrProcessorEdgeType == et); return EllipseEffect::Make(et, center, rx, ry); } +#endif ////////////////////////////////////////////////////////////////////////////// @@ -268,10 +263,10 @@ public: void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fEllipseUniform; @@ -296,17 +291,16 @@ void GLEllipseEffect::emitCode(EmitArgs& args) { // inverse squared radii uniform values are already in this normalized space. The center is // not. const char* scaleName = nullptr; - if (args.fGLSLCaps->floatPrecisionVaries()) { + if (args.fShaderCaps->floatPrecisionVaries()) { fScaleUniform = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, "scale", &scaleName); } GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const char* fragmentPos = fragBuilder->fragmentPosition(); // d is the offset to the ellipse center - fragBuilder->codeAppendf("vec2 d = %s.xy - %s.xy;", fragmentPos, ellipseName); + fragBuilder->codeAppendf("vec2 d = sk_FragCoord.xy - %s.xy;", ellipseName); if (scaleName) { fragBuilder->codeAppendf("d *= %s.y;", scaleName); } @@ -343,14 +337,14 @@ void GLEllipseEffect::emitCode(EmitArgs& args) { (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); } -void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrGLSLCaps&, +void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const EllipseEffect& ee = effect.cast(); b->add32(ee.getEdgeType()); } void GLEllipseEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& effect) { + const GrFragmentProcessor& effect) { const EllipseEffect& ee = effect.cast(); if (ee.getRadii() != fPrevRadii || ee.getCenter() != fPrevCenter) { float invRXSqd; @@ -381,7 +375,7 @@ void GLEllipseEffect::onSetData(const GrGLSLProgramDataManager& pdman, /////////////////////////////////////////////////////////////////////////////////////////////////// -void EllipseEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void EllipseEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLEllipseEffect::GenKey(*this, caps, b); } diff --git a/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp index f51e94ba82b1..e3548ad6dc40 100644 --- a/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -11,7 +11,7 @@ #include "GrCaps.h" #include "GrPipeline.h" #include "GrProcessor.h" -#include "GrProcOptInfo.h" +#include "GrProcessorAnalysis.h" #include "GrTypes.h" #include "GrXferProcessor.h" #include "glsl/GrGLSLBlend.h" @@ -19,12 +19,11 @@ #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLXferProcessor.h" -#include /** * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage. */ -struct BlendFormula { +class BlendFormula { public: /** * Values the shader can write to primary and secondary outputs. These must all be modulated by @@ -41,6 +40,76 @@ public: kLast_OutputType = kISCModulate_OutputType }; + BlendFormula() = default; + + constexpr BlendFormula(OutputType primaryOut, OutputType secondaryOut, GrBlendEquation equation, + GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) + : fPrimaryOutputType(primaryOut) + , fSecondaryOutputType(secondaryOut) + , fBlendEquation(equation) + , fSrcCoeff(srcCoeff) + , fDstCoeff(dstCoeff) + , fProps(GetProperties(primaryOut, secondaryOut, equation, srcCoeff, dstCoeff)) {} + + BlendFormula& operator=(const BlendFormula& other) { + SkDEBUGCODE(other.validatePreoptimized()); + fData = other.fData; + return *this; + } + + bool operator==(const BlendFormula& other) const { + SkDEBUGCODE(this->validatePreoptimized()); + SkDEBUGCODE(other.validatePreoptimized()); + return fData == other.fData; + } + + bool hasSecondaryOutput() const { + SkDEBUGCODE(this->validatePreoptimized()); + return kNone_OutputType != fSecondaryOutputType; + } + bool modifiesDst() const { + SkDEBUGCODE(this->validatePreoptimized()); + return SkToBool(fProps & kModifiesDst_Property); + } + bool usesDstColor() const { + SkDEBUGCODE(this->validatePreoptimized()); + return SkToBool(fProps & kUsesDstColor_Property); + } + bool usesInputColor() const { + SkDEBUGCODE(this->validatePreoptimized()); + return SkToBool(fProps & kUsesInputColor_Property); + } + bool canTweakAlphaForCoverage() const { + SkDEBUGCODE(this->validatePreoptimized()); + return SkToBool(fProps & kCanTweakAlphaForCoverage_Property); + } + + GrBlendEquation equation() const { + SkDEBUGCODE(this->validatePreoptimized()); + return fBlendEquation; + } + + GrBlendCoeff srcCoeff() const { + SkDEBUGCODE(this->validatePreoptimized()); + return fSrcCoeff; + } + + GrBlendCoeff dstCoeff() const { + SkDEBUGCODE(this->validatePreoptimized()); + return fDstCoeff; + } + + OutputType primaryOutput() const { + SkDEBUGCODE(this->validatePreoptimized()); + return fPrimaryOutputType; + } + + OutputType secondaryOutput() const { + SkDEBUGCODE(this->validatePreoptimized()); + return fSecondaryOutputType; + } + +private: enum Properties { kModifiesDst_Property = 1, kUsesDstColor_Property = 1 << 1, @@ -49,55 +118,30 @@ public: kLast_Property = kCanTweakAlphaForCoverage_Property }; + GR_DECL_BITFIELD_OPS_FRIENDS(Properties) - BlendFormula& operator =(const BlendFormula& other) { - fData = other.fData; - return *this; - } - - bool operator ==(const BlendFormula& other) const { - return fData == other.fData; - } - - bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutputType; } - bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); } - bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property); } - bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Property); } - bool canTweakAlphaForCoverage() const { - return SkToBool(fProps & kCanTweakAlphaForCoverage_Property); +#ifdef SK_DEBUG + void validatePreoptimized() const { + // The provided formula should already be optimized before a BlendFormula is constructed. + // Preferably these asserts would be done statically in the constexpr constructor, but this + // is not allowed in C++11. + SkASSERT((kNone_OutputType == fPrimaryOutputType) == + !GrBlendCoeffsUseSrcColor(fSrcCoeff, fDstCoeff)); + SkASSERT(!GrBlendCoeffRefsSrc2(fSrcCoeff)); + SkASSERT((kNone_OutputType == fSecondaryOutputType) == !GrBlendCoeffRefsSrc2(fDstCoeff)); + SkASSERT(fPrimaryOutputType != fSecondaryOutputType || + kNone_OutputType == fPrimaryOutputType); + SkASSERT(kNone_OutputType != fPrimaryOutputType || + kNone_OutputType == fSecondaryOutputType); } +#endif /** - * Deduce the properties of a compile-time constant BlendFormula. + * Deduce the properties of a BlendFormula. */ - template - struct get_properties : std::integral_constant( - - (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ? - kModifiesDst_Property : 0) | - - (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ? - kUsesDstColor_Property : 0) | - - ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff,DstCoeff)) || - (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ? - kUsesInputColor_Property : 0) | // We assert later that SrcCoeff doesn't ref src2. - - (kModulate_OutputType == PrimaryOut && - kNone_OutputType == SecondaryOut && - GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ? - kCanTweakAlphaForCoverage_Property : 0))> { - - // The provided formula should already be optimized. - GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) == - !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff)); - GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff)); - GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) == - !GR_BLEND_COEFF_REFS_SRC2(DstCoeff)); - GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut); - GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut); - }; + static constexpr Properties GetProperties(OutputType PrimaryOut, OutputType SecondaryOut, + GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, + GrBlendCoeff DstCoeff); union { struct { @@ -123,51 +167,48 @@ GR_STATIC_ASSERT(4 == sizeof(BlendFormula)); GR_MAKE_BITFIELD_OPS(BlendFormula::Properties); -/** - * Initialize a compile-time constant BlendFormula and automatically deduce fProps. - */ -#define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF, DST_COEFF) \ - {{{PRIMARY_OUT, \ - SECONDARY_OUT, \ - BLEND_EQUATION, SRC_COEFF, DST_COEFF, \ - BlendFormula::get_properties::value}}} +constexpr BlendFormula::Properties BlendFormula::GetProperties(OutputType PrimaryOut, + OutputType SecondaryOut, + GrBlendEquation BlendEquation, + GrBlendCoeff SrcCoeff, + GrBlendCoeff DstCoeff) { + return static_cast( + (GrBlendModifiesDst(BlendEquation, SrcCoeff, DstCoeff) ? kModifiesDst_Property : 0) | + (GrBlendCoeffsUseDstColor(SrcCoeff, DstCoeff) ? kUsesDstColor_Property : 0) | + ((PrimaryOut >= kModulate_OutputType && GrBlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)) || + (SecondaryOut >= kModulate_OutputType && + GrBlendCoeffRefsSrc2(DstCoeff)) + ? kUsesInputColor_Property + : 0) | // We assert later that SrcCoeff doesn't ref src2. + ((kModulate_OutputType == PrimaryOut || kNone_OutputType == PrimaryOut) && + kNone_OutputType == SecondaryOut && + GrBlendAllowsCoverageAsAlpha(BlendEquation, SrcCoeff, DstCoeff) + ? kCanTweakAlphaForCoverage_Property + : 0)); +} /** * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard * Porter Duff formula. */ -#define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \ - INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \ - BlendFormula::kNone_OutputType, \ - kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF) +static constexpr BlendFormula MakeCoeffFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { + // When the coeffs are (Zero, Zero) or (Zero, One) we set the primary output to none. + return (kZero_GrBlendCoeff == srcCoeff && + (kZero_GrBlendCoeff == dstCoeff || kOne_GrBlendCoeff == dstCoeff)) + ? BlendFormula(BlendFormula::kNone_OutputType, BlendFormula::kNone_OutputType, + kAdd_GrBlendEquation, kZero_GrBlendCoeff, dstCoeff) + : BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kNone_OutputType, + kAdd_GrBlendEquation, srcCoeff, dstCoeff); +} /** - * Basic coeff formula similar to COEFF_FORMULA but we will make the src f*Sa. This is used in + * Basic coeff formula similar to MakeCoeffFormula but we will make the src f*Sa. This is used in * LCD dst-out. */ -#define COEFF_FORMULA_SA_MODULATE(SRC_COEFF, DST_COEFF) \ - INIT_BLEND_FORMULA(BlendFormula::kSAModulate_OutputType, \ - BlendFormula::kNone_OutputType, \ - kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF) - -/** - * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set - * the primary output type to none. - */ -#define DST_CLEAR_FORMULA \ - INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \ - BlendFormula::kNone_OutputType, \ - kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCoeff) - -/** - * When the coeffs are (Zero, One), we don't write to the dst at all. This formula has its own macro - * so we can set the primary output type to none. - */ -#define NO_DST_WRITE_FORMULA \ - INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \ - BlendFormula::kNone_OutputType, \ - kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoeff) +static constexpr BlendFormula MakeSAModulateFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { + return BlendFormula(BlendFormula::kSAModulate_OutputType, BlendFormula::kNone_OutputType, + kAdd_GrBlendEquation, srcCoeff, dstCoeff); +} /** * When there is coverage, the equation with f=coverage is: @@ -183,10 +224,11 @@ GR_MAKE_BITFIELD_OPS(BlendFormula::Properties); * * Xfer modes: dst-atop (Sa!=1) */ -#define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \ - INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \ - ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \ - kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff) +static constexpr BlendFormula MakeCoverageFormula( + BlendFormula::OutputType oneMinusDstCoeffModulateOutput, GrBlendCoeff srcCoeff) { + return BlendFormula(BlendFormula::kModulate_OutputType, oneMinusDstCoeffModulateOutput, + kAdd_GrBlendEquation, srcCoeff, kIS2C_GrBlendCoeff); +} /** * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes: @@ -202,10 +244,11 @@ GR_MAKE_BITFIELD_OPS(BlendFormula::Properties); * * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1) */ -#define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \ - INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \ - BlendFormula::kNone_OutputType, \ - kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff) +static constexpr BlendFormula MakeCoverageSrcCoeffZeroFormula( + BlendFormula::OutputType oneMinusDstCoeffModulateOutput) { + return BlendFormula(oneMinusDstCoeffModulateOutput, BlendFormula::kNone_OutputType, + kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff); +} /** * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes: @@ -217,126 +260,132 @@ GR_MAKE_BITFIELD_OPS(BlendFormula::Properties); * * Xfer modes (Sa!=1): src, src-in, src-out */ -#define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \ - INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \ - BlendFormula::kCoverage_OutputType, \ - kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff) +static constexpr BlendFormula MakeCoverageDstCoeffZeroFormula(GrBlendCoeff srcCoeff) { + return BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kCoverage_OutputType, + kAdd_GrBlendEquation, srcCoeff, kIS2A_GrBlendCoeff); +} + +// Older GCC won't like the constexpr arrays because of +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61484. +// MSVC crashes with an internal compiler error. +#if !defined(__clang__) && ((defined(__GNUC__) && __GNUC__ < 5) || defined(_MSC_VER)) +# define MAYBE_CONSTEXPR const +#else +# define MAYBE_CONSTEXPR constexpr +#endif /** * This table outlines the blend formulas we will use with each xfermode, with and without coverage, * with and without an opaque input color. Optimization properties are deduced at compile time so we * can make runtime decisions quickly. RGB coverage is not supported. */ -static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = { - +static MAYBE_CONSTEXPR BlendFormula gBlendTable[2][2][(int)SkBlendMode::kLastCoeffMode + 1] = { /*>> No coverage, input color unknown <<*/ {{ - /* clear */ DST_CLEAR_FORMULA, - /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff), - /* dst */ NO_DST_WRITE_FORMULA, - /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff), - /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), - /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff), - /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff), - /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff), - /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff), - /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff), - /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff), - /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), - /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), - /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff), - /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), + /* clear */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff), + /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kZero_GrBlendCoeff), + /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff), + /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff), + /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kSA_GrBlendCoeff), + /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff), + /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff), + /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff), + /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kSA_GrBlendCoeff), + /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff), + /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff), + /* modulate */ MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff), + /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff), }, /*>> Has coverage, input color unknown <<*/ { - /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType), - /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff), - /* dst */ NO_DST_WRITE_FORMULA, - /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff), - /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), - /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff), - /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType), - /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff), - /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff), - /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff), - /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff), - /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), - /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), - /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType), - /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), + /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType), + /* src */ MakeCoverageDstCoeffZeroFormula(kOne_GrBlendCoeff), + /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff), + /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-in */ MakeCoverageDstCoeffZeroFormula(kDA_GrBlendCoeff), + /* dst-in */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType), + /* src-out */ MakeCoverageDstCoeffZeroFormula(kIDA_GrBlendCoeff), + /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff), + /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff), + /* dst-atop */ MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff), + /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff), + /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff), + /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType), + /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff), }}, /*>> No coverage, input color opaque <<*/ {{ - /* clear */ DST_CLEAR_FORMULA, - /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff), - /* dst */ NO_DST_WRITE_FORMULA, - /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff), - /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), - /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff), - /* dst-in */ NO_DST_WRITE_FORMULA, - /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff), - /* dst-out */ DST_CLEAR_FORMULA, - /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff), - /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), - /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff), - /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), - /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff), - /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), + /* clear */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff), + /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kZero_GrBlendCoeff), + /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kZero_GrBlendCoeff), + /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff), + /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff), + /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff), + /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff), + /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), + /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff), + /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff), + /* modulate */ MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff), + /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff), }, /*>> Has coverage, input color opaque <<*/ { - /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType), - /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff), - /* dst */ NO_DST_WRITE_FORMULA, - /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff), - /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), - /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff), - /* dst-in */ NO_DST_WRITE_FORMULA, - /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), - /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType), - /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff), - /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), - /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), - /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), - /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType), - /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), + /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType), + /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff), + /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff), + /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff), + /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff), + /* dst-out */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType), + /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff), + /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), + /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff), + /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff), + /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType), + /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff), }}}; -static const BlendFormula gLCDBlendTable[SkXfermode::kLastCoeffMode + 1] = { - /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType), - /* src */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff), - /* dst */ NO_DST_WRITE_FORMULA, - /* src-over */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff), - /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), - /* src-in */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff), - /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType), - /* src-out */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff), - /* dst-out */ COEFF_FORMULA_SA_MODULATE( kZero_GrBlendCoeff, kISC_GrBlendCoeff), - /* src-atop */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff), - /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff), - /* xor */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff), - /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), - /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType), - /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), +static MAYBE_CONSTEXPR BlendFormula gLCDBlendTable[(int)SkBlendMode::kLastCoeffMode + 1] = { + /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType), + /* src */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff), + /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-over */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff), + /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), + /* src-in */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff), + /* dst-in */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType), + /* src-out */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff), + /* dst-out */ MakeSAModulateFormula(kZero_GrBlendCoeff, kISC_GrBlendCoeff), + /* src-atop */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff), + /* dst-atop */ MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff), + /* xor */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff), + /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff), + /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType), + /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff), }; -static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - bool hasMixedSamples, - SkXfermode::Mode xfermode) { - SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode); - SkASSERT(!coveragePOI.isFourChannelOutput()); +#undef MAYBE_CONSTEXPR - bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples; - return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode]; +static BlendFormula get_blend_formula(bool isOpaque, + bool hasCoverage, + bool hasMixedSamples, + SkBlendMode xfermode) { + SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode); + bool conflatesCoverage = hasCoverage || hasMixedSamples; + return gBlendTable[isOpaque][conflatesCoverage][(int)xfermode]; } -static BlendFormula get_lcd_blend_formula(const GrProcOptInfo& coveragePOI, - SkXfermode::Mode xfermode) { - SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode); - SkASSERT(coveragePOI.isFourChannelOutput()); +static BlendFormula get_lcd_blend_formula(SkBlendMode xfermode) { + SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode); - return gLCDBlendTable[xfermode]; + return gLCDBlendTable[(int)xfermode]; } /////////////////////////////////////////////////////////////////////////////// @@ -354,19 +403,14 @@ public: BlendFormula getBlendFormula() const { return fBlendFormula; } private: - GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const override; - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); } void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { - blendInfo->fEquation = fBlendFormula.fBlendEquation; - blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff; - blendInfo->fDstBlend = fBlendFormula.fDstCoeff; + blendInfo->fEquation = fBlendFormula.equation(); + blendInfo->fSrcBlend = fBlendFormula.srcCoeff(); + blendInfo->fDstBlend = fBlendFormula.dstCoeff(); blendInfo->fWriteColor = fBlendFormula.modifiesDst(); } @@ -386,45 +430,27 @@ static void append_color_output(const PorterDuffXferProcessor& xp, GrGLSLXPFragmentBuilder* fragBuilder, BlendFormula::OutputType outputType, const char* output, const char* inColor, const char* inCoverage) { + SkASSERT(inCoverage); + SkASSERT(inColor); switch (outputType) { case BlendFormula::kNone_OutputType: fragBuilder->codeAppendf("%s = vec4(0.0);", output); break; case BlendFormula::kCoverage_OutputType: // We can have a coverage formula while not reading coverage if there are mixed samples. - if (inCoverage) { - fragBuilder->codeAppendf("%s = %s;", output, inCoverage); - } else { - fragBuilder->codeAppendf("%s = vec4(1.0);", output); - } + fragBuilder->codeAppendf("%s = %s;", output, inCoverage); break; case BlendFormula::kModulate_OutputType: - if (inCoverage) { - fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage); - } else { - fragBuilder->codeAppendf("%s = %s;", output, inColor); - } + fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage); break; case BlendFormula::kSAModulate_OutputType: - if (inCoverage) { - fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage); - } else { - fragBuilder->codeAppendf("%s = %s;", output, inColor); - } + fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage); break; case BlendFormula::kISAModulate_OutputType: - if (inCoverage) { - fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage); - } else { - fragBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor); - } + fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage); break; case BlendFormula::kISCModulate_OutputType: - if (inCoverage) { - fragBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage); - } else { - fragBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor); - } + fragBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage); break; default: SkFAIL("Unsupported output type."); @@ -436,8 +462,8 @@ class GLPorterDuffXferProcessor : public GrGLSLXferProcessor { public: static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) { const PorterDuffXferProcessor& xp = processor.cast(); - b->add32(xp.getBlendFormula().fPrimaryOutputType | - (xp.getBlendFormula().fSecondaryOutputType << 3)); + b->add32(xp.getBlendFormula().primaryOutput() | + (xp.getBlendFormula().secondaryOutput() << 3)); GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8); } @@ -448,11 +474,11 @@ private: BlendFormula blendFormula = xp.getBlendFormula(); if (blendFormula.hasSecondaryOutput()) { - append_color_output(xp, fragBuilder, blendFormula.fSecondaryOutputType, + append_color_output(xp, fragBuilder, blendFormula.secondaryOutput(), args.fOutputSecondary, args.fInputColor, args.fInputCoverage); } - append_color_output(xp, fragBuilder, blendFormula.fPrimaryOutputType, - args.fOutputPrimary, args.fInputColor, args.fInputCoverage); + append_color_output(xp, fragBuilder, blendFormula.primaryOutput(), args.fOutputPrimary, + args.fInputColor, args.fInputCoverage); } void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {} @@ -462,7 +488,7 @@ private: /////////////////////////////////////////////////////////////////////////////// -void PorterDuffXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&, +void PorterDuffXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { GLPorterDuffXferProcessor::GenKey(*this, b); } @@ -471,44 +497,12 @@ GrGLSLXferProcessor* PorterDuffXferProcessor::createGLSLInstance() const { return new GLPorterDuffXferProcessor; } -GrXferProcessor::OptFlags -PorterDuffXferProcessor::onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const { - GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags; - if (!fBlendFormula.modifiesDst()) { - if (!doesStencilWrite) { - optFlags |= GrXferProcessor::kSkipDraw_OptFlag; - } - optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag | - GrXferProcessor::kIgnoreCoverage_OptFlag | - GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag); - } else { - if (!fBlendFormula.usesInputColor()) { - optFlags |= GrXferProcessor::kIgnoreColor_OptFlag; - } - if (optimizations.fCoveragePOI.isSolidWhite()) { - optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag; - } - if (optimizations.fColorPOI.allStagesMultiplyInput() && - fBlendFormula.canTweakAlphaForCoverage() && - !optimizations.fCoveragePOI.isFourChannelOutput()) { - optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; - } - } - return optFlags; -} - /////////////////////////////////////////////////////////////////////////////// class ShaderPDXferProcessor : public GrXferProcessor { public: - ShaderPDXferProcessor(const DstTexture* dstTexture, - bool hasMixedSamples, - SkXfermode::Mode xfermode) - : INHERITED(dstTexture, true, hasMixedSamples) - , fXfermode(xfermode) { + ShaderPDXferProcessor(bool hasMixedSamples, SkBlendMode xfermode) + : INHERITED(true, hasMixedSamples), fXfermode(xfermode) { this->initClassID(); } @@ -516,22 +510,17 @@ public: GrGLSLXferProcessor* createGLSLInstance() const override; - SkXfermode::Mode getXfermode() const { return fXfermode; } + SkBlendMode getXfermode() const { return fXfermode; } private: - GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations&, bool, GrColor*, - const GrCaps&) const override { - return kNone_OptFlags; - } - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; bool onIsEqual(const GrXferProcessor& xpBase) const override { const ShaderPDXferProcessor& xp = xpBase.cast(); return fXfermode == xp.fXfermode; } - const SkXfermode::Mode fXfermode; + const SkBlendMode fXfermode; typedef GrXferProcessor INHERITED; }; @@ -542,7 +531,7 @@ class GLShaderPDXferProcessor : public GrGLSLXferProcessor { public: static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) { const ShaderPDXferProcessor& xp = processor.cast(); - b->add32(xp.getXfermode()); + b->add32((int)xp.getXfermode()); } private: @@ -570,7 +559,7 @@ private: /////////////////////////////////////////////////////////////////////////////// -void ShaderPDXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&, +void ShaderPDXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { GLShaderPDXferProcessor::GenKey(*this, b); } @@ -583,7 +572,8 @@ GrGLSLXferProcessor* ShaderPDXferProcessor::createGLSLInstance() const { class PDLCDXferProcessor : public GrXferProcessor { public: - static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI); + static sk_sp Make(SkBlendMode mode, + const GrProcessorAnalysisColor& inputColor); ~PDLCDXferProcessor() override; @@ -591,15 +581,12 @@ public: GrGLSLXferProcessor* createGLSLInstance() const override; + uint8_t alpha() const { return fAlpha; } + private: PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha); - GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const override; - - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { blendInfo->fSrcBlend = kConstC_GrBlendCoeff; @@ -609,15 +596,14 @@ private: bool onIsEqual(const GrXferProcessor& xpBase) const override { const PDLCDXferProcessor& xp = xpBase.cast(); - if (fBlendConstant != xp.fBlendConstant || - fAlpha != xp.fAlpha) { + if (fBlendConstant != xp.fBlendConstant || fAlpha != xp.fAlpha) { return false; } return true; } - GrColor fBlendConstant; - uint8_t fAlpha; + GrColor fBlendConstant; + uint8_t fAlpha; typedef GrXferProcessor INHERITED; }; @@ -626,23 +612,37 @@ private: class GLPDLCDXferProcessor : public GrGLSLXferProcessor { public: - GLPDLCDXferProcessor(const GrProcessor&) {} + GLPDLCDXferProcessor(const GrProcessor&) : fLastAlpha(SK_MaxU32) {} - virtual ~GLPDLCDXferProcessor() {} + ~GLPDLCDXferProcessor() override {} - static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps, + static void GenKey(const GrProcessor& processor, const GrShaderCaps& caps, GrProcessorKeyBuilder* b) {} private: void emitOutputsForBlendState(const EmitArgs& args) override { + const char* alpha; + fAlphaUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, + kDefault_GrSLPrecision, "alpha", &alpha); GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder; + // We want to force our primary output to be alpha * Coverage, where alpha is the alpha + // value of the src color. We know that there are no color stages (or we wouldn't have + // created this xp) and the r,g, and b channels of the op's input color are baked into the + // blend constant. SkASSERT(args.fInputCoverage); - fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor, - args.fInputCoverage); + fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, alpha, args.fInputCoverage); } - void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {} + void onSetData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) override { + uint32_t alpha = SkToU32(xp.cast().alpha()); + if (fLastAlpha != alpha) { + pdm.set1f(fAlphaUniform, alpha / 255.f); + fLastAlpha = alpha; + } + } + GrGLSLUniformHandler::UniformHandle fAlphaUniform; + uint32_t fLastAlpha; typedef GrGLSLXferProcessor INHERITED; }; @@ -654,27 +654,25 @@ PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha) this->initClassID(); } -GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode, - const GrProcOptInfo& colorPOI) { - if (SkXfermode::kSrcOver_Mode != xfermode) { +sk_sp PDLCDXferProcessor::Make(SkBlendMode mode, + const GrProcessorAnalysisColor& color) { + if (SkBlendMode::kSrcOver != mode) { return nullptr; } - - if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) { + GrColor blendConstant; + if (!color.isConstant(&blendConstant)) { return nullptr; } - - GrColor blendConstant = GrUnpremulColor(colorPOI.color()); + blendConstant = GrUnpremulColor(blendConstant); uint8_t alpha = GrColorUnpackA(blendConstant); blendConstant |= (0xff << GrColor_SHIFT_A); - - return new PDLCDXferProcessor(blendConstant, alpha); + return sk_sp(new PDLCDXferProcessor(blendConstant, alpha)); } PDLCDXferProcessor::~PDLCDXferProcessor() { } -void PDLCDXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void PDLCDXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLPDLCDXferProcessor::GenKey(*this, caps, b); } @@ -683,153 +681,157 @@ GrGLSLXferProcessor* PDLCDXferProcessor::createGLSLInstance() const { return new GLPDLCDXferProcessor(*this); } -GrXferProcessor::OptFlags -PDLCDXferProcessor::onGetOptimizations(const GrPipelineOptimizations& optimizations, - bool doesStencilWrite, - GrColor* overrideColor, - const GrCaps& caps) const { - // We want to force our primary output to be alpha * Coverage, where alpha is the alpha - // value of the blend the constant. We should already have valid blend coeff's if we are at - // a point where we have RGB coverage. We don't need any color stages since the known color - // output is already baked into the blendConstant. - *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha); - return GrXferProcessor::kOverrideColor_OptFlag; -} - /////////////////////////////////////////////////////////////////////////////// -GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode) - : fXfermode(xfermode) { - SkASSERT(fXfermode <= SkXfermode::kLastCoeffMode); - this->initClassID(); +constexpr GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkBlendMode xfermode) + : fBlendMode(xfermode) {} + +const GrXPFactory* GrPorterDuffXPFactory::Get(SkBlendMode blendMode) { + SkASSERT((unsigned)blendMode <= (unsigned)SkBlendMode::kLastCoeffMode); + + // If these objects are constructed as static constexpr by cl.exe (2015 SP2) the vtables are + // null. +#ifdef SK_BUILD_FOR_WIN +#define _CONSTEXPR_ +#else +#define _CONSTEXPR_ constexpr +#endif + static _CONSTEXPR_ const GrPorterDuffXPFactory gClearPDXPF(SkBlendMode::kClear); + static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcPDXPF(SkBlendMode::kSrc); + static _CONSTEXPR_ const GrPorterDuffXPFactory gDstPDXPF(SkBlendMode::kDst); + static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcOverPDXPF(SkBlendMode::kSrcOver); + static _CONSTEXPR_ const GrPorterDuffXPFactory gDstOverPDXPF(SkBlendMode::kDstOver); + static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcInPDXPF(SkBlendMode::kSrcIn); + static _CONSTEXPR_ const GrPorterDuffXPFactory gDstInPDXPF(SkBlendMode::kDstIn); + static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcOutPDXPF(SkBlendMode::kSrcOut); + static _CONSTEXPR_ const GrPorterDuffXPFactory gDstOutPDXPF(SkBlendMode::kDstOut); + static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcATopPDXPF(SkBlendMode::kSrcATop); + static _CONSTEXPR_ const GrPorterDuffXPFactory gDstATopPDXPF(SkBlendMode::kDstATop); + static _CONSTEXPR_ const GrPorterDuffXPFactory gXorPDXPF(SkBlendMode::kXor); + static _CONSTEXPR_ const GrPorterDuffXPFactory gPlusPDXPF(SkBlendMode::kPlus); + static _CONSTEXPR_ const GrPorterDuffXPFactory gModulatePDXPF(SkBlendMode::kModulate); + static _CONSTEXPR_ const GrPorterDuffXPFactory gScreenPDXPF(SkBlendMode::kScreen); +#undef _CONSTEXPR_ + + switch (blendMode) { + case SkBlendMode::kClear: + return &gClearPDXPF; + case SkBlendMode::kSrc: + return &gSrcPDXPF; + case SkBlendMode::kDst: + return &gDstPDXPF; + case SkBlendMode::kSrcOver: + return &gSrcOverPDXPF; + case SkBlendMode::kDstOver: + return &gDstOverPDXPF; + case SkBlendMode::kSrcIn: + return &gSrcInPDXPF; + case SkBlendMode::kDstIn: + return &gDstInPDXPF; + case SkBlendMode::kSrcOut: + return &gSrcOutPDXPF; + case SkBlendMode::kDstOut: + return &gDstOutPDXPF; + case SkBlendMode::kSrcATop: + return &gSrcATopPDXPF; + case SkBlendMode::kDstATop: + return &gDstATopPDXPF; + case SkBlendMode::kXor: + return &gXorPDXPF; + case SkBlendMode::kPlus: + return &gPlusPDXPF; + case SkBlendMode::kModulate: + return &gModulatePDXPF; + case SkBlendMode::kScreen: + return &gScreenPDXPF; + default: + SkFAIL("Unexpected blend mode."); + return nullptr; + } } -sk_sp GrPorterDuffXPFactory::Make(SkXfermode::Mode xfermode) { - static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode); - static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode); - static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode); - static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode); - static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode); - static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode); - static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode); - static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode); - static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode); - static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode); - static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode); - static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode); - static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode); - static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode); - static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode); - - static GrPorterDuffXPFactory* gFactories[] = { - &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF, - &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF, - &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF - }; - GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1); - - if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) { - return nullptr; - } - return sk_sp(SkRef(gFactories[xfermode])); -} - -GrXferProcessor* -GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const DstTexture* dstTexture) const { - if (optimizations.fOverrides.fUsePLSDstRead) { - return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode); - } +sk_sp GrPorterDuffXPFactory::makeXferProcessor( + const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage, + bool hasMixedSamples, const GrCaps& caps) const { BlendFormula blendFormula; - if (optimizations.fCoveragePOI.isFourChannelOutput()) { - if (SkXfermode::kSrcOver_Mode == fXfermode && - kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() && + if (coverage == GrProcessorAnalysisCoverage::kLCD) { + if (SkBlendMode::kSrcOver == fBlendMode && color.isConstant() && !caps.shaderCaps()->dualSourceBlendingSupport() && !caps.shaderCaps()->dstReadInShaderSupport()) { // If we don't have dual source blending or in shader dst reads, we fall back to this // trick for rendering SrcOver LCD text instead of doing a dst copy. - SkASSERT(!dstTexture || !dstTexture->texture()); - return PDLCDXferProcessor::Create(fXfermode, optimizations.fColorPOI); + return PDLCDXferProcessor::Make(fBlendMode, color); } - blendFormula = get_lcd_blend_formula(optimizations.fCoveragePOI, fXfermode); + blendFormula = get_lcd_blend_formula(fBlendMode); } else { - blendFormula = get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI, - hasMixedSamples, fXfermode); + blendFormula = + get_blend_formula(color.isOpaque(), GrProcessorAnalysisCoverage::kNone != coverage, + hasMixedSamples, fBlendMode); } if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) { - return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode); + return sk_sp(new ShaderPDXferProcessor(hasMixedSamples, fBlendMode)); } - - SkASSERT(!dstTexture || !dstTexture->texture()); - return new PorterDuffXferProcessor(blendFormula); + return sk_sp(new PorterDuffXferProcessor(blendFormula)); } -void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - InvariantBlendedColor* blendedColor) const { - // Find the blended color info based on the formula that does not have coverage. - BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode]; - if (colorFormula.usesDstColor()) { - blendedColor->fWillBlendWithDst = true; - blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; - return; +static inline GrXPFactory::AnalysisProperties analysis_properties( + const GrProcessorAnalysisColor& color, const GrProcessorAnalysisCoverage& coverage, + const GrCaps& caps, SkBlendMode mode) { + using AnalysisProperties = GrXPFactory::AnalysisProperties; + AnalysisProperties props = AnalysisProperties::kNone; + bool hasCoverage = GrProcessorAnalysisCoverage::kNone != coverage; + auto formula = gBlendTable[color.isOpaque()][hasCoverage][(int)mode]; + if (formula.canTweakAlphaForCoverage()) { + props |= AnalysisProperties::kCompatibleWithAlphaAsCoverage; } - - blendedColor->fWillBlendWithDst = false; - - SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation); - - switch (colorFormula.fSrcCoeff) { - case kZero_GrBlendCoeff: - blendedColor->fKnownColor = 0; - blendedColor->fKnownColorFlags = kRGBA_GrColorComponentFlags; - return; - - case kOne_GrBlendCoeff: - blendedColor->fKnownColor = colorPOI.color(); - blendedColor->fKnownColorFlags = colorPOI.validFlags(); - return; - - default: - blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; - return; - } -} - -bool GrPorterDuffXPFactory::onWillReadDstColor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations) const { - if (caps.shaderCaps()->dualSourceBlendingSupport()) { - return false; - } - - // When we have four channel coverage we always need to read the dst in order to correctly - // blend. The one exception is when we are using srcover mode and we know the input color into - // the XP. - if (optimizations.fCoveragePOI.isFourChannelOutput()) { - if (SkXfermode::kSrcOver_Mode == fXfermode && - kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() && - !caps.shaderCaps()->dstReadInShaderSupport()) { - return false; + // With dual-source blending we never need the destination color in the shader. + if (!caps.shaderCaps()->dualSourceBlendingSupport()) { + // Mixed samples implicity computes a fractional coverage from sample coverage. This could + // affect the formula used. However, we don't expect to have mixed samples without dual + // source blending. + SkASSERT(!caps.usesMixedSamples()); + if (GrProcessorAnalysisCoverage::kLCD == coverage) { + // Check for special case of srcover with a known color which can be done using the + // blend constant. + if (SkBlendMode::kSrcOver == mode && color.isConstant()) { + props |= AnalysisProperties::kIgnoresInputColor; + } else { + if (get_lcd_blend_formula(mode).hasSecondaryOutput()) { + props |= AnalysisProperties::kReadsDstInShader; + } + } + } else if (formula.hasSecondaryOutput()) { + props |= AnalysisProperties::kReadsDstInShader; } - return get_lcd_blend_formula(optimizations.fCoveragePOI, fXfermode).hasSecondaryOutput(); } + if (!formula.modifiesDst() || !formula.usesInputColor()) { + props |= AnalysisProperties::kIgnoresInputColor; + } + // Ignore the effect of coverage here for overlap stencil and cover property + auto colorFormula = gBlendTable[color.isOpaque()][0][(int)mode]; + SkASSERT(kAdd_GrBlendEquation == colorFormula.equation()); + if (!colorFormula.usesDstColor()) { + props |= AnalysisProperties::kCanCombineOverlappedStencilAndCover; + } + return props; +} - // We fallback on the shader XP when the blend formula would use dual source blending but we - // don't have support for it. - static const bool kHasMixedSamples = false; - SkASSERT(!caps.usesMixedSamples()); // We never use mixed samples without dual source blending. - return get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI, kHasMixedSamples, - fXfermode).hasSecondaryOutput(); +GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::analysisProperties( + const GrProcessorAnalysisColor& color, + const GrProcessorAnalysisCoverage& coverage, + const GrCaps& caps) const { + return analysis_properties(color, coverage, caps, fBlendMode); } GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); -sk_sp GrPorterDuffXPFactory::TestCreate(GrProcessorTestData* d) { - SkXfermode::Mode mode = SkXfermode::Mode(d->fRandom->nextULessThan(SkXfermode::kLastCoeffMode)); - return GrPorterDuffXPFactory::Make(mode); +#if GR_TEST_UTILS +const GrXPFactory* GrPorterDuffXPFactory::TestGet(GrProcessorTestData* d) { + SkBlendMode mode = SkBlendMode(d->fRandom->nextULessThan((int)SkBlendMode::kLastCoeffMode)); + return GrPorterDuffXPFactory::Get(mode); } +#endif void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp, int* outPrimary, @@ -839,35 +841,28 @@ void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp, return; } BlendFormula blendFormula = static_cast(xp)->getBlendFormula(); - *outPrimary = blendFormula.fPrimaryOutputType; - *outSecondary = blendFormula.fSecondaryOutputType; + *outPrimary = blendFormula.primaryOutput(); + *outSecondary = blendFormula.secondaryOutput(); } - //////////////////////////////////////////////////////////////////////////////////////////////// // SrcOver Global functions //////////////////////////////////////////////////////////////////////////////////////////////// const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() { - static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff, - kISA_GrBlendCoeff); + static BlendFormula gSrcOverBlendFormula = + MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff); static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula); return gSrcOverXP; } -GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor( - const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples, - const GrXferProcessor::DstTexture* dstTexture) { - if (optimizations.fOverrides.fUsePLSDstRead) { - return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkXfermode::kSrcOver_Mode); - } - +sk_sp GrPorterDuffXPFactory::MakeSrcOverXferProcessor( + const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage, + bool hasMixedSamples, const GrCaps& caps) { // We want to not make an xfer processor if possible. Thus for the simple case where we are not // doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from // the general case where we convert a src-over blend that has solid coverage and an opaque // color to src-mode, which allows disabling of blending. - if (!optimizations.fCoveragePOI.isFourChannelOutput()) { + if (coverage != GrProcessorAnalysisCoverage::kLCD) { // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP". // We don't simply return the address of that XP here because our caller would have to unref // it and since it is a global object and GrProgramElement's ref-cnting system is not thread @@ -875,49 +870,31 @@ GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor( return nullptr; } - if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() && - !caps.shaderCaps()->dualSourceBlendingSupport() && + if (color.isConstant() && !caps.shaderCaps()->dualSourceBlendingSupport() && !caps.shaderCaps()->dstReadInShaderSupport()) { // If we don't have dual source blending or in shader dst reads, we fall // back to this trick for rendering SrcOver LCD text instead of doing a // dst copy. - SkASSERT(!dstTexture || !dstTexture->texture()); - return PDLCDXferProcessor::Create(SkXfermode::kSrcOver_Mode, optimizations.fColorPOI); + return PDLCDXferProcessor::Make(SkBlendMode::kSrcOver, color); } BlendFormula blendFormula; - blendFormula = get_lcd_blend_formula(optimizations.fCoveragePOI, SkXfermode::kSrcOver_Mode); + blendFormula = get_lcd_blend_formula(SkBlendMode::kSrcOver); if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) { - return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkXfermode::kSrcOver_Mode); + return sk_sp( + new ShaderPDXferProcessor(hasMixedSamples, SkBlendMode::kSrcOver)); } - - SkASSERT(!dstTexture || !dstTexture->texture()); - return new PorterDuffXferProcessor(blendFormula); + return sk_sp(new PorterDuffXferProcessor(blendFormula)); } -bool GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(const GrCaps& caps, - const GrPipelineOptimizations& optimizations) { - if (caps.shaderCaps()->dstReadInShaderSupport() || - caps.shaderCaps()->dualSourceBlendingSupport()) { - return false; - } - - // When we have four channel coverage we always need to read the dst in order to correctly - // blend. The one exception is when we are using srcover mode and we know the input color - // into the XP. - if (optimizations.fCoveragePOI.isFourChannelOutput()) { - if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() && - !caps.shaderCaps()->dstReadInShaderSupport()) { - return false; - } - return get_lcd_blend_formula(optimizations.fCoveragePOI, - SkXfermode::kSrcOver_Mode).hasSecondaryOutput(); - } - - // We fallback on the shader XP when the blend formula would use dual source blending but we - // don't have support for it. - static const bool kHasMixedSamples = false; - SkASSERT(!caps.usesMixedSamples()); // We never use mixed samples without dual source blending. - return get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI, - kHasMixedSamples, SkXfermode::kSrcOver_Mode).hasSecondaryOutput(); +sk_sp GrPorterDuffXPFactory::MakeNoCoverageXP(SkBlendMode blendmode) { + BlendFormula formula = get_blend_formula(false, false, false, blendmode); + return sk_make_sp(formula); +} + +GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::SrcOverAnalysisProperties( + const GrProcessorAnalysisColor& color, + const GrProcessorAnalysisCoverage& coverage, + const GrCaps& caps) { + return analysis_properties(color, coverage, caps, SkBlendMode::kSrcOver); } diff --git a/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.h b/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.h new file mode 100644 index 000000000000..c5680ca294fa --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.h @@ -0,0 +1,66 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrPorterDuffXferProcessor_DEFINED +#define GrPorterDuffXferProcessor_DEFINED + +#include "GrTypes.h" +#include "GrXferProcessor.h" +#include "SkBlendMode.h" + +// See the comment above GrXPFactory's definition about this warning suppression. +#if defined(__GNUC__) || defined(__clang) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif +class GrPorterDuffXPFactory : public GrXPFactory { +public: + static const GrXPFactory* Get(SkBlendMode blendMode); + + /** Because src-over is so common we special case it for performance reasons. If this returns + null then the SimpleSrcOverXP() below should be used. */ + static sk_sp MakeSrcOverXferProcessor(const GrProcessorAnalysisColor&, + GrProcessorAnalysisCoverage, + bool hasMixedSamples, + const GrCaps&); + + /** Returns a simple non-LCD porter duff blend XP with no optimizations or coverage. */ + static sk_sp MakeNoCoverageXP(SkBlendMode); + + /** This XP implements non-LCD src-over using hw blend with no optimizations. It is returned + by reference because it is global and its ref-cnting methods are not thread safe. */ + static const GrXferProcessor& SimpleSrcOverXP(); + + static AnalysisProperties SrcOverAnalysisProperties(const GrProcessorAnalysisColor&, + const GrProcessorAnalysisCoverage&, + const GrCaps&); + +private: + constexpr GrPorterDuffXPFactory(SkBlendMode); + + sk_sp makeXferProcessor(const GrProcessorAnalysisColor&, + GrProcessorAnalysisCoverage, + bool hasMixedSamples, + const GrCaps&) const override; + + AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&, + const GrProcessorAnalysisCoverage&, + const GrCaps&) const override; + + GR_DECLARE_XP_FACTORY_TEST; + static void TestGetXPOutputTypes(const GrXferProcessor*, int* outPrimary, int* outSecondary); + + SkBlendMode fBlendMode; + + friend class GrPorterDuffTest; // for TestGetXPOutputTypes() + typedef GrXPFactory INHERITED; +}; +#if defined(__GNUC__) || defined(__clang) +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrProxyMove.h b/gfx/skia/skia/src/gpu/effects/GrProxyMove.h new file mode 100644 index 000000000000..4fbf1a008d99 --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrProxyMove.h @@ -0,0 +1,39 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrProxyMove_DEFINED +#define GrProxyMove_DEFINED + +// In a few places below we rely on braced initialization order being defined by the C++ spec (left +// to right). We use operator-> on a sk_sp and then in a later argument std::move() the sk_sp. GCC +// 4.9.0 and earlier has a bug where the left to right order evaluation isn't implemented correctly. +// +// Clang has the same bug when targeting Windows (http://crbug.com/687259). +// TODO(hans): Remove work-around once Clang is fixed. +#if defined(__GNUC__) && !defined(__clang__) +# define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +# if (GCC_VERSION > 40900) +# define GCC_EVAL_ORDER_BUG 0 +# else +# define GCC_EVAL_ORDER_BUG 1 +# endif +# undef GCC_VERSION +#elif defined(_MSC_VER) && defined(__clang__) +# define GCC_EVAL_ORDER_BUG 1 +#else +# define GCC_EVAL_ORDER_BUG 0 +#endif + +#if GCC_EVAL_ORDER_BUG +# define GR_PROXY_MOVE(X) (X) +#else +# define GR_PROXY_MOVE(X) (std::move(X)) +#endif + +#undef GCC_EVAL_ORDER_BUG + +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrRRectEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrRRectEffect.cpp index 37bb3f884890..887bc00bda69 100644 --- a/gfx/skia/skia/src/gpu/effects/GrRRectEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrRRectEffect.cpp @@ -9,8 +9,8 @@ #include "GrConvexPolyEffect.h" #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" #include "GrOvalEffect.h" +#include "GrShaderCaps.h" #include "SkRRect.h" #include "SkTLazy.h" #include "glsl/GrGLSLFragmentProcessor.h" @@ -48,7 +48,7 @@ public: static sk_sp Make(GrPrimitiveEdgeType, uint32_t circularCornerFlags, const SkRRect&); - virtual ~CircularRRectEffect() {} + ~CircularRRectEffect() override {} const char* name() const override { return "CircularRRect"; } @@ -63,12 +63,10 @@ private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor& other) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - SkRRect fRRect; GrPrimitiveEdgeType fEdgeType; uint32_t fCircularCornerFlags; @@ -88,17 +86,13 @@ sk_sp CircularRRectEffect::Make(GrPrimitiveEdgeType edgeTyp new CircularRRectEffect(edgeType, circularCornerFlags, rrect)); } -void CircularRRectEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->mulByUnknownSingleComponent(); -} - CircularRRectEffect::CircularRRectEffect(GrPrimitiveEdgeType edgeType, uint32_t circularCornerFlags, const SkRRect& rrect) - : fRRect(rrect) - , fEdgeType(edgeType) - , fCircularCornerFlags(circularCornerFlags) { + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fRRect(rrect) + , fEdgeType(edgeType) + , fCircularCornerFlags(circularCornerFlags) { this->initClassID(); - this->setWillReadFragmentPosition(); } bool CircularRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { @@ -111,6 +105,7 @@ bool CircularRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircularRRectEffect); +#if GR_TEST_UTILS sk_sp CircularRRectEffect::TestCreate(GrProcessorTestData* d) { SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f); SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f); @@ -125,6 +120,7 @@ sk_sp CircularRRectEffect::TestCreate(GrProcessorTestData* } while (nullptr == fp); return fp; } +#endif ////////////////////////////////////////////////////////////////////////////// @@ -136,10 +132,10 @@ public: virtual void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; @@ -169,7 +165,7 @@ void GLCircularRRectEffect::emitCode(EmitArgs& args) { // If we're on a device with a "real" mediump then the length calculation could overflow. SkString clampedCircleDistance; - if (args.fGLSLCaps->floatPrecisionVaries()) { + if (args.fShaderCaps->floatPrecisionVaries()) { clampedCircleDistance.printf("clamp(%s.x * (1.0 - length(dxy * %s.y)), 0.0, 1.0);", radiusPlusHalfName, radiusPlusHalfName); } else { @@ -177,7 +173,6 @@ void GLCircularRRectEffect::emitCode(EmitArgs& args) { } GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const char* fragmentPos = fragBuilder->fragmentPosition(); // At each quarter-circle corner we compute a vector that is the offset of the fragment position // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant // to that corner. This means that points near the interior near the rrect top edge will have @@ -195,84 +190,86 @@ void GLCircularRRectEffect::emitCode(EmitArgs& args) { // alphas together. switch (crre.getCircularCornerFlags()) { case CircularRRectEffect::kAll_CornerFlags: - fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos); - fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName); + fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); + fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);"); fragBuilder->codeAppendf("float alpha = %s;", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kTopLeft_CornerFlag: - fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - %s.xy, 0.0);", - rectName, fragmentPos); - fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);", - rectName, fragmentPos); - fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);", - rectName, fragmentPos); + fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - sk_FragCoord.xy, 0.0);", + rectName); + fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);", + rectName); + fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);", + rectName); fragBuilder->codeAppendf("float alpha = bottomAlpha * rightAlpha * %s;", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kTopRight_CornerFlag: - fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);", - fragmentPos, rectName, rectName, fragmentPos); - fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);", - fragmentPos, rectName); - fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);", - rectName, fragmentPos); + fragBuilder->codeAppendf("vec2 dxy = max(vec2(sk_FragCoord.x - %s.z, " + "%s.y - sk_FragCoord.y), 0.0);", + rectName, rectName); + fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);", + rectName); + fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);", + rectName); fragBuilder->codeAppendf("float alpha = bottomAlpha * leftAlpha * %s;", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kBottomRight_CornerFlag: - fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - %s.zw, 0.0);", - fragmentPos, rectName); - fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);", - fragmentPos, rectName); - fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);", - fragmentPos, rectName); + fragBuilder->codeAppendf("vec2 dxy = max(sk_FragCoord.xy - %s.zw, 0.0);", + rectName); + fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);", + rectName); + fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);", + rectName); fragBuilder->codeAppendf("float alpha = topAlpha * leftAlpha * %s;", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kBottomLeft_CornerFlag: - fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);", - rectName, fragmentPos, fragmentPos, rectName); - fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);", - rectName, fragmentPos); - fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);", - fragmentPos, rectName); + fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - sk_FragCoord.x, sk_FragCoord.y - " + "%s.w), 0.0);", + rectName, rectName); + fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);", + rectName); + fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);", + rectName); fragBuilder->codeAppendf("float alpha = topAlpha * rightAlpha * %s;", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kLeft_CornerFlags: - fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos); - fragBuilder->codeAppendf("float dy1 = %s.y - %s.w;", fragmentPos, rectName); + fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); + fragBuilder->codeAppendf("float dy1 = sk_FragCoord.y - %s.w;", rectName); fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);"); - fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);", - rectName, fragmentPos); + fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);", + rectName); fragBuilder->codeAppendf("float alpha = rightAlpha * %s;", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kTop_CornerFlags: - fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos); - fragBuilder->codeAppendf("float dx1 = %s.x - %s.z;", fragmentPos, rectName); + fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); + fragBuilder->codeAppendf("float dx1 = sk_FragCoord.x - %s.z;", rectName); fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);"); - fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);", - rectName, fragmentPos); + fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);", + rectName); fragBuilder->codeAppendf("float alpha = bottomAlpha * %s;", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kRight_CornerFlags: - fragBuilder->codeAppendf("float dy0 = %s.y - %s.y;", rectName, fragmentPos); - fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName); + fragBuilder->codeAppendf("float dy0 = %s.y - sk_FragCoord.y;", rectName); + fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);"); - fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);", - fragmentPos, rectName); + fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);", + rectName); fragBuilder->codeAppendf("float alpha = leftAlpha * %s;", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kBottom_CornerFlags: - fragBuilder->codeAppendf("float dx0 = %s.x - %s.x;", rectName, fragmentPos); - fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName); + fragBuilder->codeAppendf("float dx0 = %s.x - sk_FragCoord.x;", rectName); + fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);"); - fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);", - fragmentPos, rectName); + fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);", + rectName); fragBuilder->codeAppendf("float alpha = topAlpha * %s;", clampedCircleDistance.c_str()); break; @@ -286,7 +283,7 @@ void GLCircularRRectEffect::emitCode(EmitArgs& args) { (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); } -void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&, +void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const CircularRRectEffect& crre = processor.cast(); GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8); @@ -294,7 +291,7 @@ void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrGLSLCap } void GLCircularRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) { + const GrFragmentProcessor& processor) { const CircularRRectEffect& crre = processor.cast(); const SkRRect& rrect = crre.getRRect(); if (rrect != fPrevRRect) { @@ -375,7 +372,7 @@ void GLCircularRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, //////////////////////////////////////////////////////////////////////////////////////////////////// -void CircularRRectEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void CircularRRectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLCircularRRectEffect::GenKey(*this, caps, b); } @@ -390,7 +387,7 @@ class EllipticalRRectEffect : public GrFragmentProcessor { public: static sk_sp Make(GrPrimitiveEdgeType, const SkRRect&); - virtual ~EllipticalRRectEffect() {} + ~EllipticalRRectEffect() override {} const char* name() const override { return "EllipticalRRect"; } @@ -403,14 +400,12 @@ private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor& other) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - SkRRect fRRect; - GrPrimitiveEdgeType fEdgeType; + SkRRect fRRect; + GrPrimitiveEdgeType fEdgeType; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; @@ -425,15 +420,11 @@ EllipticalRRectEffect::Make(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) return sk_sp(new EllipticalRRectEffect(edgeType, rrect)); } -void EllipticalRRectEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->mulByUnknownSingleComponent(); -} - EllipticalRRectEffect::EllipticalRRectEffect(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) - : fRRect(rrect) - , fEdgeType(edgeType) { + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fRRect(rrect) + , fEdgeType(edgeType) { this->initClassID(); - this->setWillReadFragmentPosition(); } bool EllipticalRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { @@ -445,6 +436,7 @@ bool EllipticalRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipticalRRectEffect); +#if GR_TEST_UTILS sk_sp EllipticalRRectEffect::TestCreate(GrProcessorTestData* d) { SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f); SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f); @@ -480,6 +472,7 @@ sk_sp EllipticalRRectEffect::TestCreate(GrProcessorTestData } while (nullptr == fp); return fp; } +#endif ////////////////////////////////////////////////////////////////////////////// @@ -491,10 +484,10 @@ public: void emitCode(EmitArgs&) override; - static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); + static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); protected: - void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; + void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; private: GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; @@ -515,7 +508,6 @@ void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { &rectName); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const char* fragmentPos = fragBuilder->fragmentPosition(); // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant // to that corner. This means that points near the interior near the rrect top edge will have @@ -528,14 +520,14 @@ void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { // The code below is a simplified version of the above that performs maxs on the vector // components before computing distances and alpha values so that only one distance computation // need be computed to determine the min alpha. - fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos); - fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName); + fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); + fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); // If we're on a device with a "real" mediump then we'll do the distance computation in a space // that is normalized by the largest radius. The scale uniform will be scale, 1/scale. The // radii uniform values are already in this normalized space. const char* scaleName = nullptr; - if (args.fGLSLCaps->floatPrecisionVaries()) { + if (args.fShaderCaps->floatPrecisionVaries()) { fScaleUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, "scale", &scaleName); @@ -602,7 +594,7 @@ void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); } -void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrGLSLCaps&, +void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const EllipticalRRectEffect& erre = effect.cast(); GR_STATIC_ASSERT(kLast_GrProcessorEdgeType < (1 << 3)); @@ -610,7 +602,7 @@ void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrGLSLCaps } void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& effect) { + const GrFragmentProcessor& effect) { const EllipticalRRectEffect& erre = effect.cast(); const SkRRect& rrect = erre.getRRect(); // If we're using a scale factor to work around precision issues, choose the largest radius @@ -670,7 +662,7 @@ void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, //////////////////////////////////////////////////////////////////////////////////////////////////// -void EllipticalRRectEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void EllipticalRRectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLEllipticalRRectEffect::GenKey(*this, caps, b); } diff --git a/gfx/skia/skia/src/gpu/effects/GrSRGBEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrSRGBEffect.cpp new file mode 100644 index 000000000000..7ca79c74526c --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrSRGBEffect.cpp @@ -0,0 +1,127 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrSRGBEffect.h" + +#include "GrFragmentProcessor.h" +#include "GrProcessor.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" + +class GrGLSRGBEffect : public GrGLSLFragmentProcessor { +public: + void emitCode(EmitArgs& args) override { + const GrSRGBEffect& srgbe = args.fFp.cast(); + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + + SkString srgbFuncName; + static const GrShaderVar gSrgbArgs[] = { + GrShaderVar("x", kFloat_GrSLType), + }; + switch (srgbe.mode()) { + case GrSRGBEffect::Mode::kLinearToSRGB: + fragBuilder->emitFunction(kFloat_GrSLType, + "linear_to_srgb", + SK_ARRAY_COUNT(gSrgbArgs), + gSrgbArgs, + "return (x <= 0.0031308) ? (x * 12.92) " + ": (1.055 * pow(x, 0.416666667) - 0.055);", + &srgbFuncName); + break; + case GrSRGBEffect::Mode::kSRGBToLinear: + fragBuilder->emitFunction(kFloat_GrSLType, + "srgb_to_linear", + SK_ARRAY_COUNT(gSrgbArgs), + gSrgbArgs, + "return (x <= 0.04045) ? (x / 12.92) " + ": pow((x + 0.055) / 1.055, 2.4);", + &srgbFuncName); + break; + } + + if (nullptr == args.fInputColor) { + args.fInputColor = "vec4(1)"; + } + + fragBuilder->codeAppendf("%s = vec4(%s(%s.r), %s(%s.g), %s(%s.b), %s.a);", + args.fOutputColor, + srgbFuncName.c_str(), args.fInputColor, + srgbFuncName.c_str(), args.fInputColor, + srgbFuncName.c_str(), args.fInputColor, + args.fInputColor); + } + + static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&, + GrProcessorKeyBuilder* b) { + const GrSRGBEffect& srgbe = processor.cast(); + uint32_t key = static_cast(srgbe.mode()); + b->add32(key); + } + +private: + typedef GrGLSLFragmentProcessor INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +GrSRGBEffect::GrSRGBEffect(Mode mode) + : INHERITED(kPreservesOpaqueInput_OptimizationFlag | + kConstantOutputForConstantInput_OptimizationFlag) + , fMode(mode) { + this->initClassID(); +} + +bool GrSRGBEffect::onIsEqual(const GrFragmentProcessor& s) const { + const GrSRGBEffect& other = s.cast(); + return other.fMode == fMode; +} + +static inline float srgb_to_linear(float srgb) { + return (srgb <= 0.04045f) ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f); +} +static inline float linear_to_srgb(float linear) { + return (linear <= 0.0031308) ? linear * 12.92f : 1.055f * powf(linear, 1.f / 2.4f) - 0.055f; +} + +GrColor4f GrSRGBEffect::constantOutputForConstantInput(GrColor4f input) const { + switch (fMode) { + case Mode::kLinearToSRGB: + return GrColor4f(linear_to_srgb(input.fRGBA[0]), linear_to_srgb(input.fRGBA[1]), + linear_to_srgb(input.fRGBA[2]), input.fRGBA[3]); + case Mode::kSRGBToLinear: + return GrColor4f(srgb_to_linear(input.fRGBA[0]), srgb_to_linear(input.fRGBA[1]), + srgb_to_linear(input.fRGBA[2]), input.fRGBA[3]); + } + SkFAIL("Unexpected mode"); + return GrColor4f::TransparentBlack(); +} + +/////////////////////////////////////////////////////////////////////////////// + +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSRGBEffect); + +#if GR_TEST_UTILS +sk_sp GrSRGBEffect::TestCreate(GrProcessorTestData* d) { + Mode testMode = static_cast(d->fRandom->nextRangeU(0, 1)); + return sk_sp(new GrSRGBEffect(testMode)); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// + +void GrSRGBEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const { + GrGLSRGBEffect::GenKey(*this, caps, b); +} + +GrGLSLFragmentProcessor* GrSRGBEffect::onCreateGLSLInstance() const { + return new GrGLSRGBEffect(); +} + +sk_sp GrSRGBEffect::Make(Mode mode) { + return sk_sp(new GrSRGBEffect(mode)); +} diff --git a/gfx/skia/skia/src/gpu/effects/GrSRGBEffect.h b/gfx/skia/skia/src/gpu/effects/GrSRGBEffect.h new file mode 100644 index 000000000000..17afa5e5bdda --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrSRGBEffect.h @@ -0,0 +1,45 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSRGBEffect_DEFINED +#define GrSRGBEffect_DEFINED + +#include "GrFragmentProcessor.h" + +class GrSRGBEffect : public GrFragmentProcessor { +public: + enum class Mode { + kLinearToSRGB, + kSRGBToLinear, + }; + + /** + * Creates an effect that applies the sRGB transfer function (or its inverse) + */ + static sk_sp Make(Mode mode); + + const char* name() const override { return "sRGB"; } + + Mode mode() const { return fMode; } + +private: + GrSRGBEffect(Mode mode); + + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; + bool onIsEqual(const GrFragmentProcessor&) const override; + + GrColor4f constantOutputForConstantInput(GrColor4f input) const override; + + Mode fMode; + + GR_DECLARE_FRAGMENT_PROCESSOR_TEST; + + typedef GrFragmentProcessor INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrShadowGeoProc.cpp b/gfx/skia/skia/src/gpu/effects/GrShadowGeoProc.cpp new file mode 100644 index 000000000000..e11a672dbab5 --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrShadowGeoProc.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrShadowGeoProc.h" + +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLGeometryProcessor.h" +#include "glsl/GrGLSLUniformHandler.h" +#include "glsl/GrGLSLVarying.h" +#include "glsl/GrGLSLVertexShaderBuilder.h" + +class GrGLSLRRectShadowGeoProc : public GrGLSLGeometryProcessor { +public: + GrGLSLRRectShadowGeoProc() {} + + void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { + const GrRRectShadowGeoProc& rsgp = args.fGP.cast(); + GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; + GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; + + // emit attributes + varyingHandler->emitAttributes(rsgp); + fragBuilder->codeAppend("vec4 shadowParams;"); + varyingHandler->addPassThroughAttribute(rsgp.inShadowParams(), "shadowParams"); + + // setup pass through color + varyingHandler->addPassThroughAttribute(rsgp.inColor(), args.fOutputColor); + + // Setup position + this->setupPosition(vertBuilder, gpArgs, rsgp.inPosition()->fName); + + // emit transforms + this->emitTransforms(vertBuilder, + varyingHandler, + uniformHandler, + gpArgs->fPositionVar, + rsgp.inPosition()->fName, + rsgp.localMatrix(), + args.fFPCoordTransformHandler); + + fragBuilder->codeAppend("float d = length(shadowParams.xy);"); + fragBuilder->codeAppend("float distance = shadowParams.z * (1.0 - d);"); + + fragBuilder->codeAppend("float radius = shadowParams.w;"); + + fragBuilder->codeAppend("float factor = 1.0 - clamp(distance/radius, 0.0, 1.0);"); + fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;"); + fragBuilder->codeAppendf("%s = vec4(factor);", + args.fOutputCoverage); + } + + void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc, + FPCoordTransformIter&& transformIter) override { + this->setTransformDataHelper(proc.cast().localMatrix(), + pdman, &transformIter); + } + + static inline void GenKey(const GrGeometryProcessor& gp, + const GrShaderCaps&, + GrProcessorKeyBuilder* b) { + const GrRRectShadowGeoProc& rsgp = gp.cast(); + uint16_t key; + key = rsgp.localMatrix().hasPerspective() ? 0x1 : 0x0; + b->add32(key); + } + +private: + typedef GrGLSLGeometryProcessor INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +GrRRectShadowGeoProc::GrRRectShadowGeoProc(const SkMatrix& localMatrix) + : fLocalMatrix(localMatrix) { + + this->initClassID(); + fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, + kHigh_GrSLPrecision); + fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); + fInShadowParams = &this->addVertexAttrib("inShadowParams", kVec4f_GrVertexAttribType); +} + +void GrRRectShadowGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const { + GrGLSLRRectShadowGeoProc::GenKey(*this, caps, b); +} + +GrGLSLPrimitiveProcessor* GrRRectShadowGeoProc::createGLSLInstance(const GrShaderCaps&) const { + return new GrGLSLRRectShadowGeoProc(); +} + +/////////////////////////////////////////////////////////////////////////////// + +GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrRRectShadowGeoProc); + +#if GR_TEST_UTILS +sk_sp GrRRectShadowGeoProc::TestCreate(GrProcessorTestData* d) { + return GrRRectShadowGeoProc::Make(GrTest::TestMatrix(d->fRandom)); +} +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrShadowGeoProc.h b/gfx/skia/skia/src/gpu/effects/GrShadowGeoProc.h new file mode 100644 index 000000000000..b0631efd9e4b --- /dev/null +++ b/gfx/skia/skia/src/gpu/effects/GrShadowGeoProc.h @@ -0,0 +1,55 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrShadowGeoProc_DEFINED +#define GrShadowGeoProc_DEFINED + +#include "GrProcessor.h" +#include "GrGeometryProcessor.h" + +class GrGLRRectShadowGeoProc; + +/** + * The output color of this effect is a coverage mask for a rrect shadow, + * assuming circular corner geometry. + */ +class GrRRectShadowGeoProc : public GrGeometryProcessor { +public: + static sk_sp Make(const SkMatrix& localMatrix) { + return sk_sp(new GrRRectShadowGeoProc(localMatrix)); + } + + ~GrRRectShadowGeoProc() override {} + + const char* name() const override { return "RRectShadow"; } + + const Attribute* inPosition() const { return fInPosition; } + const Attribute* inColor() const { return fInColor; } + const Attribute* inShadowParams() const { return fInShadowParams; } + GrColor color() const { return fColor; } + const SkMatrix& localMatrix() const { return fLocalMatrix; } + + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; + + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; + +private: + GrRRectShadowGeoProc(const SkMatrix& localMatrix); + + GrColor fColor; + SkMatrix fLocalMatrix; + const Attribute* fInPosition; + const Attribute* fInColor; + const Attribute* fInShadowParams; + + GR_DECLARE_GEOMETRY_PROCESSOR_TEST; + + typedef GrGeometryProcessor INHERITED; +}; + + +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.cpp index beb64d582d0a..a41ed8b0b99b 100644 --- a/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.cpp @@ -6,19 +6,45 @@ */ #include "GrSimpleTextureEffect.h" -#include "GrInvariantOutput.h" +#include "GrProxyMove.h" #include "GrTexture.h" #include "glsl/GrGLSLColorSpaceXformHelper.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" +GrSimpleTextureEffect::GrSimpleTextureEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, + sk_sp colorSpaceXform, + const SkMatrix& matrix, + GrSamplerParams::FilterMode filterMode) + : INHERITED{resourceProvider, + ModulationFlags(proxy->config()), + GR_PROXY_MOVE(proxy), + std::move(colorSpaceXform), + matrix, + filterMode} { + this->initClassID(); +} + +GrSimpleTextureEffect::GrSimpleTextureEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, + sk_sp colorSpaceXform, + const SkMatrix& matrix, + const GrSamplerParams& params) + : INHERITED{resourceProvider, + ModulationFlags(proxy->config()), + GR_PROXY_MOVE(proxy), + std::move(colorSpaceXform), + matrix, + params} { + this->initClassID(); +} + class GrGLSimpleTextureEffect : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs& args) override { const GrSimpleTextureEffect& textureEffect = args.fFp.cast(); - GrGLSLColorSpaceXformHelper colorSpaceHelper(args.fUniformHandler, - textureEffect.colorSpaceXform(), - &fColorSpaceXformUni); + fColorSpaceHelper.emitCode(args.fUniformHandler, textureEffect.colorSpaceXform()); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("%s = ", args.fOutputColor); @@ -26,37 +52,34 @@ public: args.fTexSamplers[0], args.fTransformedCoords[0].c_str(), args.fTransformedCoords[0].getType(), - &colorSpaceHelper); + &fColorSpaceHelper); fragBuilder->codeAppend(";"); } - static inline void GenKey(const GrProcessor& effect, const GrGLSLCaps&, + static inline void GenKey(const GrProcessor& effect, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrSimpleTextureEffect& textureEffect = effect.cast(); b->add32(GrColorSpaceXform::XformKey(textureEffect.colorSpaceXform())); } protected: - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& processor) override { + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& processor) override { const GrSimpleTextureEffect& textureEffect = processor.cast(); if (SkToBool(textureEffect.colorSpaceXform())) { - pdman.setSkMatrix44(fColorSpaceXformUni, textureEffect.colorSpaceXform()->srcToDst()); + fColorSpaceHelper.setData(pdman, textureEffect.colorSpaceXform()); } } private: typedef GrGLSLFragmentProcessor INHERITED; - UniformHandle fColorSpaceXformUni; + GrGLSLColorSpaceXformHelper fColorSpaceHelper; }; /////////////////////////////////////////////////////////////////////////////// -void GrSimpleTextureEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - this->updateInvariantOutputForModulation(inout); -} - -void GrSimpleTextureEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrSimpleTextureEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GrGLSimpleTextureEffect::GenKey(*this, caps, b); } @@ -69,9 +92,10 @@ GrGLSLFragmentProcessor* GrSimpleTextureEffect::onCreateGLSLInstance() const { GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSimpleTextureEffect); +#if GR_TEST_UTILS sk_sp GrSimpleTextureEffect::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; static const SkShader::TileMode kTileModes[] = { SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, @@ -81,10 +105,12 @@ sk_sp GrSimpleTextureEffect::TestCreate(GrProcessorTestData kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))], kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))], }; - GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode : - GrTextureParams::kNone_FilterMode); + GrSamplerParams params(tileModes, d->fRandom->nextBool() ? GrSamplerParams::kBilerp_FilterMode + : GrSamplerParams::kNone_FilterMode); const SkMatrix& matrix = GrTest::TestMatrix(d->fRandom); - auto colorSpaceXform = GrTest::TestColorXform(d->fRandom); - return GrSimpleTextureEffect::Make(d->fTextures[texIdx], colorSpaceXform, matrix); + sk_sp colorSpaceXform = GrTest::TestColorXform(d->fRandom); + return GrSimpleTextureEffect::Make(d->resourceProvider(), d->textureProxy(texIdx), + std::move(colorSpaceXform), matrix); } +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.h b/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.h index 8242362a9c40..8edec81a83cb 100644 --- a/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.h +++ b/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.h @@ -9,71 +9,70 @@ #define GrSimpleTextureEffect_DEFINED #include "GrSingleTextureEffect.h" +#include "GrTextureProxy.h" class GrInvariantOutput; /** * The output color of this effect is a modulation of the input color and a sample from a texture. - * It allows explicit specification of the filtering and wrap modes (GrTextureParams) and accepts + * It allows explicit specification of the filtering and wrap modes (GrSamplerParams) and accepts * a matrix that is used to compute texture coordinates from local coordinates. */ class GrSimpleTextureEffect : public GrSingleTextureEffect { public: /* unfiltered, clamp mode */ - static sk_sp Make(GrTexture* tex, + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, sk_sp colorSpaceXform, const SkMatrix& matrix) { return sk_sp( - new GrSimpleTextureEffect(tex, std::move(colorSpaceXform), matrix, - GrTextureParams::kNone_FilterMode)); + new GrSimpleTextureEffect(resourceProvider, std::move(proxy), + std::move(colorSpaceXform), matrix, + GrSamplerParams::kNone_FilterMode)); } /* clamp mode */ - static sk_sp Make(GrTexture* tex, - sk_sp colorSpaceXform, - const SkMatrix& matrix, - GrTextureParams::FilterMode filterMode) { - return sk_sp( - new GrSimpleTextureEffect(tex, std::move(colorSpaceXform), matrix, filterMode)); - } - - static sk_sp Make(GrTexture* tex, + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, sk_sp colorSpaceXform, const SkMatrix& matrix, - const GrTextureParams& p) { - return sk_sp(new GrSimpleTextureEffect(tex, std::move(colorSpaceXform), + GrSamplerParams::FilterMode filterMode) { + return sk_sp( + new GrSimpleTextureEffect(resourceProvider, std::move(proxy), + std::move(colorSpaceXform), + matrix, filterMode)); + } + + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp proxy, + sk_sp colorSpaceXform, + const SkMatrix& matrix, + const GrSamplerParams& p) { + return sk_sp(new GrSimpleTextureEffect(resourceProvider, + std::move(proxy), + std::move(colorSpaceXform), matrix, p)); } - virtual ~GrSimpleTextureEffect() {} + ~GrSimpleTextureEffect() override {} const char* name() const override { return "SimpleTexture"; } private: - GrSimpleTextureEffect(GrTexture* texture, - sk_sp colorSpaceXform, - const SkMatrix& matrix, - GrTextureParams::FilterMode filterMode) - : GrSingleTextureEffect(texture, std::move(colorSpaceXform), matrix, filterMode) { - this->initClassID(); - } + GrSimpleTextureEffect(GrResourceProvider*, sk_sp, + sk_sp, const SkMatrix& matrix, + GrSamplerParams::FilterMode); - GrSimpleTextureEffect(GrTexture* texture, - sk_sp colorSpaceXform, - const SkMatrix& matrix, - const GrTextureParams& params) - : GrSingleTextureEffect(texture, std::move(colorSpaceXform), matrix, params) { - this->initClassID(); - } + GrSimpleTextureEffect(GrResourceProvider*, sk_sp, + sk_sp, const SkMatrix& matrix, + const GrSamplerParams&); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor& other) const override { return true; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; typedef GrSingleTextureEffect INHERITED; diff --git a/gfx/skia/skia/src/gpu/effects/GrSingleTextureEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrSingleTextureEffect.cpp index 26837894315e..f5d70003e674 100644 --- a/gfx/skia/skia/src/gpu/effects/GrSingleTextureEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrSingleTextureEffect.cpp @@ -7,37 +7,44 @@ #include "effects/GrSingleTextureEffect.h" -GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, +#include "GrTextureProxy.h" + +GrSingleTextureEffect::GrSingleTextureEffect(GrResourceProvider* resourceProvider, + OptimizationFlags optFlags, + sk_sp proxy, sk_sp colorSpaceXform, const SkMatrix& m) - : fCoordTransform(m, texture, GrTextureParams::kNone_FilterMode) - , fTextureAccess(texture) - , fColorSpaceXform(std::move(colorSpaceXform)) { + : INHERITED(optFlags) + , fCoordTransform(resourceProvider, m, proxy.get()) + , fTextureSampler(resourceProvider, std::move(proxy)) + , fColorSpaceXform(std::move(colorSpaceXform)) { this->addCoordTransform(&fCoordTransform); - this->addTextureAccess(&fTextureAccess); + this->addTextureSampler(&fTextureSampler); } -GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, +GrSingleTextureEffect::GrSingleTextureEffect(GrResourceProvider* resourceProvider, + OptimizationFlags optFlags, + sk_sp proxy, sk_sp colorSpaceXform, const SkMatrix& m, - GrTextureParams::FilterMode filterMode) - : fCoordTransform(m, texture, filterMode) - , fTextureAccess(texture, filterMode) - , fColorSpaceXform(std::move(colorSpaceXform)) { + GrSamplerParams::FilterMode filterMode) + : INHERITED(optFlags) + , fCoordTransform(resourceProvider, m, proxy.get()) + , fTextureSampler(resourceProvider, std::move(proxy), filterMode) + , fColorSpaceXform(std::move(colorSpaceXform)) { this->addCoordTransform(&fCoordTransform); - this->addTextureAccess(&fTextureAccess); + this->addTextureSampler(&fTextureSampler); } -GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, +GrSingleTextureEffect::GrSingleTextureEffect(GrResourceProvider* resourceProvider, + OptimizationFlags optFlags, + sk_sp proxy, sk_sp colorSpaceXform, - const SkMatrix& m, - const GrTextureParams& params) - : fCoordTransform(m, texture, params.filterMode()) - , fTextureAccess(texture, params) - , fColorSpaceXform(std::move(colorSpaceXform)) { + const SkMatrix& m, const GrSamplerParams& params) + : INHERITED(optFlags) + , fCoordTransform(resourceProvider, m, proxy.get()) + , fTextureSampler(resourceProvider, std::move(proxy), params) + , fColorSpaceXform(std::move(colorSpaceXform)) { this->addCoordTransform(&fCoordTransform); - this->addTextureAccess(&fTextureAccess); -} - -GrSingleTextureEffect::~GrSingleTextureEffect() { + this->addTextureSampler(&fTextureSampler); } diff --git a/gfx/skia/skia/src/gpu/effects/GrSingleTextureEffect.h b/gfx/skia/skia/src/gpu/effects/GrSingleTextureEffect.h index 7d110bf2ae3d..fb945dea6bdd 100644 --- a/gfx/skia/skia/src/gpu/effects/GrSingleTextureEffect.h +++ b/gfx/skia/skia/src/gpu/effects/GrSingleTextureEffect.h @@ -11,10 +11,10 @@ #include "GrFragmentProcessor.h" #include "GrColorSpaceXform.h" #include "GrCoordTransform.h" -#include "GrInvariantOutput.h" #include "SkMatrix.h" class GrTexture; +class GrTextureProxy; /** * A base class for effects that draw a single texture with a texture matrix. This effect has no @@ -22,11 +22,9 @@ class GrTexture; */ class GrSingleTextureEffect : public GrFragmentProcessor { public: - ~GrSingleTextureEffect() override; - SkString dumpInfo() const override { SkString str; - str.appendf("Texture: %d", fTextureAccess.getTexture()->uniqueID()); + str.appendf("Texture: %d", fTextureSampler.texture()->uniqueID().asUInt()); return str; } @@ -34,33 +32,33 @@ public: protected: /** unfiltered, clamp mode */ - GrSingleTextureEffect(GrTexture*, sk_sp, const SkMatrix&); + GrSingleTextureEffect(GrResourceProvider*, OptimizationFlags, sk_sp, + sk_sp, const SkMatrix&); /** clamp mode */ - GrSingleTextureEffect(GrTexture*, sk_sp, const SkMatrix&, - GrTextureParams::FilterMode filterMode); - GrSingleTextureEffect(GrTexture*, - sk_sp, - const SkMatrix&, - const GrTextureParams&); + GrSingleTextureEffect(GrResourceProvider*, OptimizationFlags, sk_sp, + sk_sp, const SkMatrix&, + GrSamplerParams::FilterMode filterMode); + GrSingleTextureEffect(GrResourceProvider*, OptimizationFlags, sk_sp, + sk_sp, const SkMatrix&, const GrSamplerParams&); /** - * Can be used as a helper to implement subclass onComputeInvariantOutput(). It assumes that - * the subclass output color will be a modulation of the input color with a value read from the - * texture. + * Can be used as a helper to decide which fragment processor OptimizationFlags should be set. + * This assumes that the subclass output color will be a modulation of the input color with a + * value read from the texture and that the texture contains premultiplied color or alpha values + * that are in range. */ - void updateInvariantOutputForModulation(GrInvariantOutput* inout) const { - if (GrPixelConfigIsAlphaOnly(this->texture(0)->config())) { - inout->mulByUnknownSingleComponent(); - } else if (GrPixelConfigIsOpaque(this->texture(0)->config())) { - inout->mulByUnknownOpaqueFourComponents(); + static OptimizationFlags ModulationFlags(GrPixelConfig config) { + if (GrPixelConfigIsOpaque(config)) { + return kCompatibleWithCoverageAsAlpha_OptimizationFlag | + kPreservesOpaqueInput_OptimizationFlag; } else { - inout->mulByUnknownFourComponents(); + return kCompatibleWithCoverageAsAlpha_OptimizationFlag; } } private: GrCoordTransform fCoordTransform; - GrTextureAccess fTextureAccess; + TextureSampler fTextureSampler; sk_sp fColorSpaceXform; typedef GrFragmentProcessor INHERITED; diff --git a/gfx/skia/skia/src/gpu/effects/GrTextureDomain.cpp b/gfx/skia/skia/src/gpu/effects/GrTextureDomain.cpp index 55d69bf5cc6a..ee21841656f7 100644 --- a/gfx/skia/skia/src/gpu/effects/GrTextureDomain.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrTextureDomain.cpp @@ -6,51 +6,106 @@ */ #include "GrTextureDomain.h" -#include "GrInvariantOutput.h" + +#include "GrResourceProvider.h" +#include "GrShaderCaps.h" #include "GrSimpleTextureEffect.h" +#include "GrSurfaceProxyPriv.h" #include "SkFloatingPoint.h" +#include "glsl/GrGLSLColorSpaceXformHelper.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLSampler.h" #include "glsl/GrGLSLShaderBuilder.h" #include "glsl/GrGLSLUniformHandler.h" -GrTextureDomain::GrTextureDomain(const SkRect& domain, Mode mode, int index) - : fIndex(index) { +static bool can_ignore_rect(GrTextureProxy* proxy, const SkRect& domain) { + if (GrResourceProvider::IsFunctionallyExact(proxy)) { + const SkIRect kFullRect = SkIRect::MakeWH(proxy->width(), proxy->height()); - static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1}; - if (domain.contains(kFullRect) && kClamp_Mode == mode) { + return domain.contains(kFullRect); + } + + return false; +} + +static bool can_ignore_rect(GrTexture* tex, const SkRect& domain) { + // This logic is relying on the instantiated size of 'tex'. In the deferred world it + // will have to change so this logic only fires for kExact texture proxies. This shouldn't + // change the actual behavior of Ganesh since shaders shouldn't be accessing pixels outside + // of the content rectangle. + const SkIRect kFullRect = SkIRect::MakeWH(tex->width(), tex->height()); + + return domain.contains(kFullRect); +} + +GrTextureDomain::GrTextureDomain(GrTexture* tex, const SkRect& domain, Mode mode, int index) + : fMode(mode) + , fIndex(index) { + + if (kIgnore_Mode == fMode) { + return; + } + + if (kClamp_Mode == mode && can_ignore_rect(tex, domain)) { fMode = kIgnore_Mode; - } else { - fMode = mode; + return; } - if (fMode != kIgnore_Mode) { - // We don't currently handle domains that are empty or don't intersect the texture. - // It is OK if the domain rect is a line or point, but it should not be inverted. We do not - // handle rects that do not intersect the [0..1]x[0..1] rect. - SkASSERT(domain.fLeft <= domain.fRight); - SkASSERT(domain.fTop <= domain.fBottom); - fDomain.fLeft = SkScalarPin(domain.fLeft, kFullRect.fLeft, kFullRect.fRight); - fDomain.fRight = SkScalarPin(domain.fRight, kFullRect.fLeft, kFullRect.fRight); - fDomain.fTop = SkScalarPin(domain.fTop, kFullRect.fTop, kFullRect.fBottom); - fDomain.fBottom = SkScalarPin(domain.fBottom, kFullRect.fTop, kFullRect.fBottom); - SkASSERT(fDomain.fLeft <= fDomain.fRight); - SkASSERT(fDomain.fTop <= fDomain.fBottom); + const SkRect kFullRect = SkRect::MakeIWH(tex->width(), tex->height()); + + // We don't currently handle domains that are empty or don't intersect the texture. + // It is OK if the domain rect is a line or point, but it should not be inverted. We do not + // handle rects that do not intersect the [0..1]x[0..1] rect. + SkASSERT(domain.fLeft <= domain.fRight); + SkASSERT(domain.fTop <= domain.fBottom); + fDomain.fLeft = SkScalarPin(domain.fLeft, 0.0f, kFullRect.fRight); + fDomain.fRight = SkScalarPin(domain.fRight, fDomain.fLeft, kFullRect.fRight); + fDomain.fTop = SkScalarPin(domain.fTop, 0.0f, kFullRect.fBottom); + fDomain.fBottom = SkScalarPin(domain.fBottom, fDomain.fTop, kFullRect.fBottom); + SkASSERT(fDomain.fLeft <= fDomain.fRight); + SkASSERT(fDomain.fTop <= fDomain.fBottom); +} + +GrTextureDomain::GrTextureDomain(GrTextureProxy* proxy, const SkRect& domain, Mode mode, int index) + : fMode(mode) + , fIndex(index) { + + if (kIgnore_Mode == fMode) { + return; } + + if (kClamp_Mode == mode && can_ignore_rect(proxy, domain)) { + fMode = kIgnore_Mode; + return; + } + + const SkRect kFullRect = SkRect::MakeIWH(proxy->width(), proxy->height()); + + // We don't currently handle domains that are empty or don't intersect the texture. + // It is OK if the domain rect is a line or point, but it should not be inverted. We do not + // handle rects that do not intersect the [0..1]x[0..1] rect. + SkASSERT(domain.fLeft <= domain.fRight); + SkASSERT(domain.fTop <= domain.fBottom); + fDomain.fLeft = SkScalarPin(domain.fLeft, 0.0f, kFullRect.fRight); + fDomain.fRight = SkScalarPin(domain.fRight, fDomain.fLeft, kFullRect.fRight); + fDomain.fTop = SkScalarPin(domain.fTop, 0.0f, kFullRect.fBottom); + fDomain.fBottom = SkScalarPin(domain.fBottom, fDomain.fTop, kFullRect.fBottom); + SkASSERT(fDomain.fLeft <= fDomain.fRight); + SkASSERT(fDomain.fTop <= fDomain.fBottom); } ////////////////////////////////////////////////////////////////////////////// void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, GrGLSLUniformHandler* uniformHandler, - const GrGLSLCaps* glslCaps, + const GrShaderCaps* shaderCaps, const GrTextureDomain& textureDomain, const char* outColor, const SkString& inCoords, GrGLSLFragmentProcessor::SamplerHandle sampler, - const char* inModulateColor) { + const char* inModulateColor, + GrGLSLColorSpaceXformHelper* colorXformHelper) { SkASSERT((Mode)-1 == fMode || textureDomain.mode() == fMode); SkDEBUGCODE(fMode = textureDomain.mode();) @@ -69,8 +124,8 @@ void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, switch (textureDomain.mode()) { case kIgnore_Mode: { builder->codeAppendf("%s = ", outColor); - builder->appendTextureLookupAndModulate(inModulateColor, sampler, - inCoords.c_str()); + builder->appendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str(), + kVec2f_GrSLType, colorXformHelper); builder->codeAppend(";"); break; } @@ -80,8 +135,8 @@ void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, inCoords.c_str(), fDomainName.c_str(), fDomainName.c_str()); builder->codeAppendf("%s = ", outColor); - builder->appendTextureLookupAndModulate(inModulateColor, sampler, - clampedCoords.c_str()); + builder->appendTextureLookupAndModulate(inModulateColor, sampler, clampedCoords.c_str(), + kVec2f_GrSLType, colorXformHelper); builder->codeAppend(";"); break; } @@ -90,7 +145,7 @@ void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, GrGLSLShaderBuilder::ShaderBlock block(builder); const char* domain = fDomainName.c_str(); - if (!glslCaps->canUseAnyFunctionInShader()) { + if (!shaderCaps->canUseAnyFunctionInShader()) { // On the NexusS and GalaxyNexus, the other path (with the 'any' // call) causes the compilation error "Calls to any function that // may require a gradient calculation inside a conditional block @@ -99,14 +154,12 @@ void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, // result=white;" code fails to compile. builder->codeAppend("vec4 outside = vec4(0.0, 0.0, 0.0, 0.0);"); builder->codeAppend("vec4 inside = "); - builder->appendTextureLookupAndModulate(inModulateColor, sampler, - inCoords.c_str()); + builder->appendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str(), + kVec2f_GrSLType, colorXformHelper); builder->codeAppend(";"); - builder->appendPrecisionModifier(kHigh_GrSLPrecision); - builder->codeAppendf("float x = (%s).x;", inCoords.c_str()); - builder->appendPrecisionModifier(kHigh_GrSLPrecision); - builder->codeAppendf("float y = (%s).y;", inCoords.c_str()); + builder->codeAppendf("highp float x = (%s).x;", inCoords.c_str()); + builder->codeAppendf("highp float y = (%s).y;", inCoords.c_str()); builder->codeAppendf("x = abs(2.0*(x - %s.x)/(%s.z - %s.x) - 1.0);", domain, domain, domain); @@ -122,8 +175,8 @@ void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, domain); builder->codeAppendf("%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outColor); - builder->appendTextureLookupAndModulate(inModulateColor, sampler, - inCoords.c_str()); + builder->appendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str(), + kVec2f_GrSLType, colorXformHelper); builder->codeAppend(";"); } break; @@ -135,8 +188,8 @@ void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, fDomainName.c_str(), fDomainName.c_str()); builder->codeAppendf("%s = ", outColor); - builder->appendTextureLookupAndModulate(inModulateColor, sampler, - clampedCoords.c_str()); + builder->appendTextureLookupAndModulate(inModulateColor, sampler, clampedCoords.c_str(), + kVec2f_GrSLType, colorXformHelper); builder->codeAppend(";"); break; } @@ -145,17 +198,26 @@ void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, void GrTextureDomain::GLDomain::setData(const GrGLSLProgramDataManager& pdman, const GrTextureDomain& textureDomain, - GrSurfaceOrigin textureOrigin) { + GrTexture* tex) { SkASSERT(textureDomain.mode() == fMode); if (kIgnore_Mode != textureDomain.mode()) { + SkScalar wInv = SK_Scalar1 / tex->width(); + SkScalar hInv = SK_Scalar1 / tex->height(); + float values[kPrevDomainCount] = { - SkScalarToFloat(textureDomain.domain().left()), - SkScalarToFloat(textureDomain.domain().top()), - SkScalarToFloat(textureDomain.domain().right()), - SkScalarToFloat(textureDomain.domain().bottom()) + SkScalarToFloat(textureDomain.domain().fLeft * wInv), + SkScalarToFloat(textureDomain.domain().fTop * hInv), + SkScalarToFloat(textureDomain.domain().fRight * wInv), + SkScalarToFloat(textureDomain.domain().fBottom * hInv) }; + + SkASSERT(values[0] >= 0.0f && values[0] <= 1.0f); + SkASSERT(values[1] >= 0.0f && values[1] <= 1.0f); + SkASSERT(values[2] >= 0.0f && values[2] <= 1.0f); + SkASSERT(values[3] >= 0.0f && values[3] <= 1.0f); + // vertical flip if necessary - if (kBottomLeft_GrSurfaceOrigin == textureOrigin) { + if (kBottomLeft_GrSurfaceOrigin == tex->origin()) { values[1] = 1.0f - values[1]; values[3] = 1.0f - values[3]; // The top and bottom were just flipped, so correct the ordering @@ -170,40 +232,54 @@ void GrTextureDomain::GLDomain::setData(const GrGLSLProgramDataManager& pdman, } /////////////////////////////////////////////////////////////////////////////// +inline GrFragmentProcessor::OptimizationFlags GrTextureDomainEffect::OptFlags( + GrPixelConfig config, GrTextureDomain::Mode mode) { + if (mode == GrTextureDomain::kDecal_Mode || !GrPixelConfigIsOpaque(config)) { + return GrFragmentProcessor::kCompatibleWithCoverageAsAlpha_OptimizationFlag; + } else { + return GrFragmentProcessor::kCompatibleWithCoverageAsAlpha_OptimizationFlag | + GrFragmentProcessor::kPreservesOpaqueInput_OptimizationFlag; + } +} -sk_sp GrTextureDomainEffect::Make(GrTexture* texture, +sk_sp GrTextureDomainEffect::Make(GrResourceProvider* resourceProvider, + sk_sp proxy, sk_sp colorSpaceXform, const SkMatrix& matrix, const SkRect& domain, GrTextureDomain::Mode mode, - GrTextureParams::FilterMode filterMode) { - static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1}; + GrSamplerParams::FilterMode filterMode) { if (GrTextureDomain::kIgnore_Mode == mode || - (GrTextureDomain::kClamp_Mode == mode && domain.contains(kFullRect))) { - return GrSimpleTextureEffect::Make(texture, std::move(colorSpaceXform), matrix, filterMode); + (GrTextureDomain::kClamp_Mode == mode && can_ignore_rect(proxy.get(), domain))) { + return GrSimpleTextureEffect::Make(resourceProvider, std::move(proxy), + std::move(colorSpaceXform), matrix, filterMode); } else { return sk_sp( - new GrTextureDomainEffect(texture, std::move(colorSpaceXform), matrix, domain, mode, - filterMode)); + new GrTextureDomainEffect(resourceProvider, std::move(proxy), + std::move(colorSpaceXform), + matrix, domain, mode, filterMode)); } } -GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture, +GrTextureDomainEffect::GrTextureDomainEffect(GrResourceProvider* resourceProvider, + sk_sp proxy, sk_sp colorSpaceXform, const SkMatrix& matrix, const SkRect& domain, GrTextureDomain::Mode mode, - GrTextureParams::FilterMode filterMode) - : GrSingleTextureEffect(texture, std::move(colorSpaceXform), matrix, filterMode) - , fTextureDomain(domain, mode) { + GrSamplerParams::FilterMode filterMode) + : GrSingleTextureEffect(resourceProvider, OptFlags(proxy->config(), mode), proxy, + std::move(colorSpaceXform), matrix, filterMode) + , fTextureDomain(proxy.get(), domain, mode) { SkASSERT(mode != GrTextureDomain::kRepeat_Mode || - filterMode == GrTextureParams::kNone_FilterMode); + filterMode == GrSamplerParams::kNone_FilterMode); this->initClassID(); } -void GrTextureDomainEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, +void GrTextureDomainEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { b->add32(GrTextureDomain::GLDomain::DomainKey(fTextureDomain)); + b->add32(GrColorSpaceXform::XformKey(this->colorSpaceXform())); } GrGLSLFragmentProcessor* GrTextureDomainEffect::onCreateGLSLInstance() const { @@ -215,26 +291,33 @@ GrGLSLFragmentProcessor* GrTextureDomainEffect::onCreateGLSLInstance() const { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); + + fColorSpaceHelper.emitCode(args.fUniformHandler, tde.colorSpaceXform()); fGLDomain.sampleTexture(fragBuilder, args.fUniformHandler, - args.fGLSLCaps, + args.fShaderCaps, domain, args.fOutputColor, coords2D, args.fTexSamplers[0], - args.fInputColor); + args.fInputColor, + &fColorSpaceHelper); } protected: - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& fp) override { + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& fp) override { const GrTextureDomainEffect& tde = fp.cast(); const GrTextureDomain& domain = tde.fTextureDomain; - fGLDomain.setData(pdman, domain, tde.texture(0)->origin()); + fGLDomain.setData(pdman, domain, tde.textureSampler(0).texture()); + if (SkToBool(tde.colorSpaceXform())) { + fColorSpaceHelper.setData(pdman, tde.colorSpaceXform()); + } } private: GrTextureDomain::GLDomain fGLDomain; - + GrGLSLColorSpaceXformHelper fColorSpaceHelper; }; return new GLSLProcessor; @@ -242,67 +325,62 @@ GrGLSLFragmentProcessor* GrTextureDomainEffect::onCreateGLSLInstance() const { bool GrTextureDomainEffect::onIsEqual(const GrFragmentProcessor& sBase) const { const GrTextureDomainEffect& s = sBase.cast(); - return this->fTextureDomain == s.fTextureDomain && s.texture(0) == this->texture(0) && - s.textureAccess(0).getParams().filterMode() == - this->textureAccess(0).getParams().filterMode(); -} - -void GrTextureDomainEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - if (GrTextureDomain::kDecal_Mode == fTextureDomain.mode()) { - if (GrPixelConfigIsAlphaOnly(this->texture(0)->config())) { - inout->mulByUnknownSingleComponent(); - } else { - inout->mulByUnknownFourComponents(); - } - } else { - this->updateInvariantOutputForModulation(inout); - } + return this->fTextureDomain == s.fTextureDomain; } /////////////////////////////////////////////////////////////////////////////// GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrTextureDomainEffect); +#if GR_TEST_UTILS sk_sp GrTextureDomainEffect::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); SkRect domain; - domain.fLeft = d->fRandom->nextUScalar1(); - domain.fRight = d->fRandom->nextRangeScalar(domain.fLeft, SK_Scalar1); - domain.fTop = d->fRandom->nextUScalar1(); - domain.fBottom = d->fRandom->nextRangeScalar(domain.fTop, SK_Scalar1); + domain.fLeft = d->fRandom->nextRangeScalar(0, proxy->width()); + domain.fRight = d->fRandom->nextRangeScalar(domain.fLeft, proxy->width()); + domain.fTop = d->fRandom->nextRangeScalar(0, proxy->height()); + domain.fBottom = d->fRandom->nextRangeScalar(domain.fTop, proxy->height()); GrTextureDomain::Mode mode = (GrTextureDomain::Mode) d->fRandom->nextULessThan(GrTextureDomain::kModeCount); const SkMatrix& matrix = GrTest::TestMatrix(d->fRandom); bool bilerp = mode != GrTextureDomain::kRepeat_Mode ? d->fRandom->nextBool() : false; - auto colorSpaceXform = GrTest::TestColorXform(d->fRandom); - return GrTextureDomainEffect::Make( - d->fTextures[texIdx], - colorSpaceXform, - matrix, - domain, - mode, - bilerp ? GrTextureParams::kBilerp_FilterMode : GrTextureParams::kNone_FilterMode); + sk_sp colorSpaceXform = GrTest::TestColorXform(d->fRandom); + return GrTextureDomainEffect::Make(d->resourceProvider(), + std::move(proxy), + std::move(colorSpaceXform), + matrix, + domain, + mode, + bilerp ? GrSamplerParams::kBilerp_FilterMode + : GrSamplerParams::kNone_FilterMode); } +#endif /////////////////////////////////////////////////////////////////////////////// - -sk_sp GrDeviceSpaceTextureDecalFragmentProcessor::Make(GrTexture* texture, - const SkIRect& subset, const SkIPoint& deviceSpaceOffset) { +sk_sp GrDeviceSpaceTextureDecalFragmentProcessor::Make( + GrResourceProvider* resourceProvider, + sk_sp proxy, + const SkIRect& subset, + const SkIPoint& deviceSpaceOffset) { return sk_sp(new GrDeviceSpaceTextureDecalFragmentProcessor( - texture, subset, deviceSpaceOffset)); + resourceProvider, std::move(proxy), subset, deviceSpaceOffset)); } GrDeviceSpaceTextureDecalFragmentProcessor::GrDeviceSpaceTextureDecalFragmentProcessor( - GrTexture* texture, const SkIRect& subset, const SkIPoint& deviceSpaceOffset) - : fTextureAccess(texture, GrTextureParams::ClampNoFilter()) - , fTextureDomain(GrTextureDomain::MakeTexelDomain(texture, subset), + GrResourceProvider* resourceProvider, + sk_sp proxy, + const SkIRect& subset, + const SkIPoint& deviceSpaceOffset) + : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fTextureSampler(resourceProvider, proxy, GrSamplerParams::ClampNoFilter()) + , fTextureDomain(proxy.get(), GrTextureDomain::MakeTexelDomain(subset), GrTextureDomain::kDecal_Mode) { - this->addTextureAccess(&fTextureAccess); + this->addTextureSampler(&fTextureSampler); fDeviceSpaceOffset.fX = deviceSpaceOffset.fX - subset.fLeft; fDeviceSpaceOffset.fY = deviceSpaceOffset.fY - subset.fTop; this->initClassID(); - this->setWillReadFragmentPosition(); } GrGLSLFragmentProcessor* GrDeviceSpaceTextureDecalFragmentProcessor::onCreateGLSLInstance() const { @@ -317,12 +395,11 @@ GrGLSLFragmentProcessor* GrDeviceSpaceTextureDecalFragmentProcessor::onCreateGLS kDefault_GrSLPrecision, "scaleAndTranslate", &scaleAndTranslateName); - args.fFragBuilder->codeAppendf("vec2 coords = %s.xy * %s.xy + %s.zw;", - args.fFragBuilder->fragmentPosition(), + args.fFragBuilder->codeAppendf("vec2 coords = sk_FragCoord.xy * %s.xy + %s.zw;", scaleAndTranslateName, scaleAndTranslateName); fGLDomain.sampleTexture(args.fFragBuilder, args.fUniformHandler, - args.fGLSLCaps, + args.fShaderCaps, dstdfp.fTextureDomain, args.fOutputColor, SkString("coords"), @@ -331,17 +408,19 @@ GrGLSLFragmentProcessor* GrDeviceSpaceTextureDecalFragmentProcessor::onCreateGLS } protected: - void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& fp) override { + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& fp) override { const GrDeviceSpaceTextureDecalFragmentProcessor& dstdfp = fp.cast(); - fGLDomain.setData(pdman, dstdfp.fTextureDomain, dstdfp.texture(0)->origin()); - float iw = 1.f / dstdfp.texture(0)->width(); - float ih = 1.f / dstdfp.texture(0)->height(); + GrTexture* texture = dstdfp.textureSampler(0).texture(); + fGLDomain.setData(pdman, dstdfp.fTextureDomain, texture); + float iw = 1.f / texture->width(); + float ih = 1.f / texture->height(); float scaleAndTransData[4] = { iw, ih, -dstdfp.fDeviceSpaceOffset.fX * iw, -dstdfp.fDeviceSpaceOffset.fY * ih }; - if (dstdfp.texture(0)->origin() == kBottomLeft_GrSurfaceOrigin) { + if (texture->origin() == kBottomLeft_GrSurfaceOrigin) { scaleAndTransData[1] = -scaleAndTransData[1]; scaleAndTransData[3] = 1 - scaleAndTransData[3]; } @@ -359,35 +438,30 @@ GrGLSLFragmentProcessor* GrDeviceSpaceTextureDecalFragmentProcessor::onCreateGLS bool GrDeviceSpaceTextureDecalFragmentProcessor::onIsEqual(const GrFragmentProcessor& fp) const { const GrDeviceSpaceTextureDecalFragmentProcessor& dstdfp = fp.cast(); - return dstdfp.fTextureAccess.getTexture() == fTextureAccess.getTexture() && + return dstdfp.fTextureSampler.texture() == fTextureSampler.texture() && dstdfp.fDeviceSpaceOffset == fDeviceSpaceOffset && dstdfp.fTextureDomain == fTextureDomain; } -void GrDeviceSpaceTextureDecalFragmentProcessor::onComputeInvariantOutput( - GrInvariantOutput* inout) const { - if (GrPixelConfigIsAlphaOnly(this->texture(0)->config())) { - inout->mulByUnknownSingleComponent(); - } else { - inout->mulByUnknownFourComponents(); - } -} - /////////////////////////////////////////////////////////////////////////////// GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDeviceSpaceTextureDecalFragmentProcessor); +#if GR_TEST_UTILS sk_sp GrDeviceSpaceTextureDecalFragmentProcessor::TestCreate( GrProcessorTestData* d) { int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : GrProcessorUnitTest::kAlphaTextureIdx; + sk_sp proxy = d->textureProxy(texIdx); SkIRect subset; - subset.fLeft = d->fRandom->nextULessThan(d->fTextures[texIdx]->width() - 1); - subset.fRight = d->fRandom->nextRangeU(subset.fLeft, d->fTextures[texIdx]->width()); - subset.fTop = d->fRandom->nextULessThan(d->fTextures[texIdx]->height() - 1); - subset.fBottom = d->fRandom->nextRangeU(subset.fTop, d->fTextures[texIdx]->height()); + subset.fLeft = d->fRandom->nextULessThan(proxy->width() - 1); + subset.fRight = d->fRandom->nextRangeU(subset.fLeft, proxy->width()); + subset.fTop = d->fRandom->nextULessThan(proxy->height() - 1); + subset.fBottom = d->fRandom->nextRangeU(subset.fTop, proxy->height()); SkIPoint pt; pt.fX = d->fRandom->nextULessThan(2048); pt.fY = d->fRandom->nextULessThan(2048); - return GrDeviceSpaceTextureDecalFragmentProcessor::Make(d->fTextures[texIdx], subset, pt); + return GrDeviceSpaceTextureDecalFragmentProcessor::Make(d->resourceProvider(), + std::move(proxy), subset, pt); } +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrTextureDomain.h b/gfx/skia/skia/src/gpu/effects/GrTextureDomain.h index 82ff73c06620..d8cd69569b1f 100644 --- a/gfx/skia/skia/src/gpu/effects/GrTextureDomain.h +++ b/gfx/skia/skia/src/gpu/effects/GrTextureDomain.h @@ -13,9 +13,9 @@ #include "glsl/GrGLSLProgramDataManager.h" class GrGLProgramBuilder; +class GrGLSLColorSpaceXformHelper; class GrGLSLShaderBuilder; class GrInvariantOutput; -class GrGLSLSampler; class GrGLSLUniformHandler; struct SkRect; @@ -44,8 +44,8 @@ public: static const int kModeCount = kLastMode + 1; static const GrTextureDomain& IgnoredDomain() { - static const SkRect gDummyRect = {0, 0, 0, 0}; - static const GrTextureDomain gDomain(gDummyRect, kIgnore_Mode); + static const GrTextureDomain gDomain((GrTextureProxy*)nullptr, + SkRect::MakeEmpty(), kIgnore_Mode); return gDomain; } @@ -53,36 +53,24 @@ public: * @param index Pass a value >= 0 if using multiple texture domains in the same effect. * It is used to keep inserted variables from causing name collisions. */ - GrTextureDomain(const SkRect& domain, Mode, int index = -1); + GrTextureDomain(GrTexture*, const SkRect& domain, Mode, int index = -1); + + GrTextureDomain(GrTextureProxy*, const SkRect& domain, Mode, int index = -1); const SkRect& domain() const { return fDomain; } Mode mode() const { return fMode; } /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled texels neighboring the domain may be read. */ - static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) { - SkScalar wInv = SK_Scalar1 / texture->width(); - SkScalar hInv = SK_Scalar1 / texture->height(); - SkRect result = { - texelRect.fLeft * wInv, - texelRect.fTop * hInv, - texelRect.fRight * wInv, - texelRect.fBottom * hInv - }; - return result; + static const SkRect MakeTexelDomain(const SkIRect& texelRect) { + return SkRect::Make(texelRect); } - static const SkRect MakeTexelDomainForMode(const GrTexture* texture, const SkIRect& texelRect, Mode mode) { + static const SkRect MakeTexelDomainForMode(const SkIRect& texelRect, Mode mode) { // For Clamp mode, inset by half a texel. - SkScalar wInv = SK_Scalar1 / texture->width(); - SkScalar hInv = SK_Scalar1 / texture->height(); SkScalar inset = (mode == kClamp_Mode && !texelRect.isEmpty()) ? SK_ScalarHalf : 0; - return SkRect::MakeLTRB( - (texelRect.fLeft + inset) * wInv, - (texelRect.fTop + inset) * hInv, - (texelRect.fRight - inset) * wInv, - (texelRect.fBottom - inset) * hInv - ); + return SkRect::MakeLTRB(texelRect.fLeft + inset, texelRect.fTop + inset, + texelRect.fRight - inset, texelRect.fBottom - inset); } bool operator==(const GrTextureDomain& that) const { @@ -116,12 +104,13 @@ public: */ void sampleTexture(GrGLSLShaderBuilder* builder, GrGLSLUniformHandler* uniformHandler, - const GrGLSLCaps* glslCaps, + const GrShaderCaps* shaderCaps, const GrTextureDomain& textureDomain, const char* outColor, const SkString& inCoords, GrGLSLFragmentProcessor::SamplerHandle sampler, - const char* inModulateColor = nullptr); + const char* inModulateColor = nullptr, + GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr); /** * Call this from GrGLSLFragmentProcessor::setData() to upload uniforms necessary for the @@ -129,7 +118,7 @@ public: * origin. */ void setData(const GrGLSLProgramDataManager& pdman, const GrTextureDomain& textureDomain, - GrSurfaceOrigin textureOrigin); + GrTexture* texure); enum { kDomainKeyBits = 2, // See DomainKey(). @@ -156,8 +145,6 @@ protected: Mode fMode; SkRect fDomain; int fIndex; - - typedef GrSingleTextureEffect INHERITED; }; /** @@ -166,12 +153,13 @@ protected: class GrTextureDomainEffect : public GrSingleTextureEffect { public: - static sk_sp Make(GrTexture*, + static sk_sp Make(GrResourceProvider*, + sk_sp, sk_sp, const SkMatrix&, const SkRect& domain, GrTextureDomain::Mode, - GrTextureParams::FilterMode filterMode); + GrSamplerParams::FilterMode filterMode); const char* name() const override { return "TextureDomain"; } @@ -187,21 +175,22 @@ public: private: GrTextureDomain fTextureDomain; - GrTextureDomainEffect(GrTexture*, + GrTextureDomainEffect(GrResourceProvider*, + sk_sp, sk_sp, const SkMatrix&, const SkRect& domain, GrTextureDomain::Mode, - GrTextureParams::FilterMode); + GrSamplerParams::FilterMode); + + static OptimizationFlags OptFlags(GrPixelConfig config, GrTextureDomain::Mode mode); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; typedef GrSingleTextureEffect INHERITED; @@ -209,7 +198,8 @@ private: class GrDeviceSpaceTextureDecalFragmentProcessor : public GrFragmentProcessor { public: - static sk_sp Make(GrTexture*, const SkIRect& subset, + static sk_sp Make(GrResourceProvider*, sk_sp, + const SkIRect& subset, const SkIPoint& deviceSpaceOffset); const char* name() const override { return "GrDeviceSpaceTextureDecalFragmentProcessor"; } @@ -225,19 +215,19 @@ public: } private: - GrTextureAccess fTextureAccess; + TextureSampler fTextureSampler; GrTextureDomain fTextureDomain; SkIPoint fDeviceSpaceOffset; - GrDeviceSpaceTextureDecalFragmentProcessor(GrTexture*, const SkIRect&, const SkIPoint&); + GrDeviceSpaceTextureDecalFragmentProcessor(GrResourceProvider*, sk_sp, + const SkIRect&, const SkIPoint&); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; // Since we always use decal mode, there is no need for key data. - void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override {} + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} bool onIsEqual(const GrFragmentProcessor& fp) const override; - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; diff --git a/gfx/skia/skia/src/gpu/effects/GrTextureStripAtlas.cpp b/gfx/skia/skia/src/gpu/effects/GrTextureStripAtlas.cpp index 2c882508f5f9..26ef5963c1ab 100644 --- a/gfx/skia/skia/src/gpu/effects/GrTextureStripAtlas.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrTextureStripAtlas.cpp @@ -7,7 +7,9 @@ #include "GrTextureStripAtlas.h" #include "GrContext.h" -#include "GrTexture.h" +#include "GrContextPriv.h" +#include "GrResourceProvider.h" +#include "GrSurfaceContext.h" #include "SkGr.h" #include "SkPixelRef.h" #include "SkTSearch.h" @@ -73,7 +75,6 @@ GrTextureStripAtlas::GrTextureStripAtlas(GrTextureStripAtlas::Desc desc) , fLockedRows(0) , fDesc(desc) , fNumRows(desc.fHeight / desc.fRowHeight) - , fTexture(nullptr) , fRows(new AtlasRow[fNumRows]) , fLRUFront(nullptr) , fLRUBack(nullptr) { @@ -85,16 +86,16 @@ GrTextureStripAtlas::GrTextureStripAtlas(GrTextureStripAtlas::Desc desc) GrTextureStripAtlas::~GrTextureStripAtlas() { delete[] fRows; } -int GrTextureStripAtlas::lockRow(const SkBitmap& data) { +int GrTextureStripAtlas::lockRow(const SkBitmap& bitmap) { VALIDATE; if (0 == fLockedRows) { this->lockTexture(); - if (!fTexture) { + if (!fTexContext) { return -1; } } - int key = data.getGenerationID(); + int key = bitmap.getGenerationID(); int rowNumber = -1; int index = this->searchByKey(key); @@ -121,7 +122,7 @@ int GrTextureStripAtlas::lockRow(const SkBitmap& data) { if (nullptr == row) { // force a flush, which should unlock all the rows; then try again - fDesc.fContext->flush(); + fDesc.fContext->contextPriv().flush(nullptr); // tighten this up? row = this->getLRU(); if (nullptr == row) { --fLockedRows; @@ -152,16 +153,16 @@ int GrTextureStripAtlas::lockRow(const SkBitmap& data) { fKeyTable.insert(index, 1, &row); rowNumber = static_cast(row - fRows); - SkAutoLockPixels lock(data); + SkAutoLockPixels lock(bitmap); + + SkASSERT(bitmap.width() == fDesc.fWidth); + SkASSERT(bitmap.height() == fDesc.fRowHeight); // Pass in the kDontFlush flag, since we know we're writing to a part of this texture // that is not currently in use - fTexture->writePixels(0, rowNumber * fDesc.fRowHeight, - fDesc.fWidth, fDesc.fRowHeight, - SkImageInfo2GrPixelConfig(data.info(), *this->getContext()->caps()), - data.getPixels(), - data.rowBytes(), - GrContext::kDontFlush_PixelOpsFlag); + fTexContext->writePixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(), + 0, rowNumber * fDesc.fRowHeight, + GrContextPriv::kDontFlush_PixelOpsFlag); } SkASSERT(rowNumber >= 0); @@ -169,6 +170,10 @@ int GrTextureStripAtlas::lockRow(const SkBitmap& data) { return rowNumber; } +sk_sp GrTextureStripAtlas::asTextureProxyRef() const { + return fTexContext->asTextureProxyRef(); +} + void GrTextureStripAtlas::unlockRow(int row) { VALIDATE; --fRows[row].fLocks; @@ -191,10 +196,10 @@ GrTextureStripAtlas::AtlasRow* GrTextureStripAtlas::getLRU() { void GrTextureStripAtlas::lockTexture() { GrSurfaceDesc texDesc; + texDesc.fOrigin = kTopLeft_GrSurfaceOrigin; texDesc.fWidth = fDesc.fWidth; texDesc.fHeight = fDesc.fHeight; texDesc.fConfig = fDesc.fConfig; - texDesc.fIsMipMapped = false; static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey key; @@ -202,29 +207,29 @@ void GrTextureStripAtlas::lockTexture() { builder[0] = static_cast(fCacheKey); builder.finish(); - fTexture = fDesc.fContext->textureProvider()->findAndRefTextureByUniqueKey(key); - if (nullptr == fTexture) { - fTexture = fDesc.fContext->textureProvider()->createTexture(texDesc, SkBudgeted::kYes, - nullptr, 0); - if (!fTexture) { + sk_sp proxy = fDesc.fContext->resourceProvider()->findProxyByUniqueKey(key); + if (!proxy) { + proxy = GrSurfaceProxy::MakeDeferred(fDesc.fContext->resourceProvider(), + texDesc, SkBackingFit::kExact, + SkBudgeted::kYes, + GrResourceProvider::kNoPendingIO_Flag); + if (!proxy) { return; } - // We will be issuing writes to the surface using kDontFlush_PixelOpsFlag, so we - // need to make sure any existing IO is flushed - fDesc.fContext->flushSurfaceIO(fTexture); - fDesc.fContext->textureProvider()->assignUniqueKeyToTexture(key, fTexture); + fDesc.fContext->resourceProvider()->assignUniqueKeyToProxy(key, proxy.get()); // This is a new texture, so all of our cache info is now invalid this->initLRU(); fKeyTable.rewind(); } - SkASSERT(fTexture); + SkASSERT(proxy); + fTexContext = fDesc.fContext->contextPriv().makeWrappedSurfaceContext(std::move(proxy), + nullptr); } void GrTextureStripAtlas::unlockTexture() { - SkASSERT(fTexture && 0 == fLockedRows); - fTexture->unref(); - fTexture = nullptr; + SkASSERT(fTexContext && 0 == fLockedRows); + fTexContext.reset(); } void GrTextureStripAtlas::initLRU() { @@ -348,9 +353,9 @@ void GrTextureStripAtlas::validate() { // If we have locked rows, we should have a locked texture, otherwise // it should be unlocked if (fLockedRows == 0) { - SkASSERT(nullptr == fTexture); + SkASSERT(!fTexContext); } else { - SkASSERT(fTexture); + SkASSERT(fTexContext); } } #endif diff --git a/gfx/skia/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/gfx/skia/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp index 051061ffa897..9671919decb7 100644 --- a/gfx/skia/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp @@ -1,25 +1,36 @@ /* -* Copyright 2015 Google Inc. -* -* Use of this source code is governed by a BSD-style license that can be -* found in the LICENSE file. -*/ + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ #include "effects/GrXfermodeFragmentProcessor.h" #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" #include "effects/GrConstColorProcessor.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLBlend.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "SkGrPriv.h" +#include "SkGr.h" + +// Some of the cpu implementations of blend modes differ too much from the GPU enough that +// we can't use the cpu implementation to implement constantOutputForConstantInput. +static inline bool does_cpu_blend_impl_match_gpu(SkBlendMode mode) { + // The non-seperable modes differ too much. So does SoftLight. ColorBurn differs too much on our + // test iOS device (but we just disable it across the aboard since it may happen on untested + // GPUs). + return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight && + mode != SkBlendMode::kColorBurn; +} + +////////////////////////////////////////////////////////////////////////////// class ComposeTwoFragmentProcessor : public GrFragmentProcessor { public: ComposeTwoFragmentProcessor(sk_sp src, sk_sp dst, - SkXfermode::Mode mode) - : fMode(mode) { + SkBlendMode mode) + : INHERITED(OptFlags(src.get(), dst.get(), mode)), fMode(mode) { this->initClassID(); SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(std::move(src)); SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(std::move(dst)); @@ -29,26 +40,115 @@ public: const char* name() const override { return "ComposeTwo"; } - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { - b->add32(fMode); + SkString dumpInfo() const override { + SkString str; + + str.appendf("Mode: %s", SkBlendMode_Name(fMode)); + + for (int i = 0; i < this->numChildProcessors(); ++i) { + str.appendf(" [%s %s]", + this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str()); + } + return str; } - SkXfermode::Mode getMode() const { return fMode; } + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { + b->add32((int)fMode); + } + + SkBlendMode getMode() const { return fMode; } + +private: + static OptimizationFlags OptFlags(const GrFragmentProcessor* src, + const GrFragmentProcessor* dst, SkBlendMode mode) { + OptimizationFlags flags; + switch (mode) { + case SkBlendMode::kClear: + case SkBlendMode::kSrc: + case SkBlendMode::kDst: + SkFAIL("Should never create clear, src, or dst compose two FP."); + flags = kNone_OptimizationFlags; + break; + + // Produces opaque if both src and dst are opaque. + case SkBlendMode::kSrcIn: + case SkBlendMode::kDstIn: + case SkBlendMode::kModulate: + flags = src->preservesOpaqueInput() && dst->preservesOpaqueInput() + ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags; + break; + + // Produces zero when both are opaque, indeterminate if one is opaque. + case SkBlendMode::kSrcOut: + case SkBlendMode::kDstOut: + case SkBlendMode::kXor: + flags = kNone_OptimizationFlags; + break; + + // Is opaque if the dst is opaque. + case SkBlendMode::kSrcATop: + flags = dst->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags; + break; + + // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque. + case SkBlendMode::kDstATop: + case SkBlendMode::kScreen: + flags = src->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags; + break; + + // These modes are all opaque if either src or dst is opaque. All the advanced modes + // compute alpha as src-over. + case SkBlendMode::kSrcOver: + case SkBlendMode::kDstOver: + case SkBlendMode::kPlus: + case SkBlendMode::kOverlay: + case SkBlendMode::kDarken: + case SkBlendMode::kLighten: + case SkBlendMode::kColorDodge: + case SkBlendMode::kColorBurn: + case SkBlendMode::kHardLight: + case SkBlendMode::kSoftLight: + case SkBlendMode::kDifference: + case SkBlendMode::kExclusion: + case SkBlendMode::kMultiply: + case SkBlendMode::kHue: + case SkBlendMode::kSaturation: + case SkBlendMode::kColor: + case SkBlendMode::kLuminosity: + flags = src->preservesOpaqueInput() || dst->preservesOpaqueInput() + ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags; + break; + } + if (does_cpu_blend_impl_match_gpu(mode) && src->hasConstantOutputForConstantInput() && + dst->hasConstantOutputForConstantInput()) { + flags |= kConstantOutputForConstantInput_OptimizationFlag; + } + return flags; + } -protected: bool onIsEqual(const GrFragmentProcessor& other) const override { const ComposeTwoFragmentProcessor& cs = other.cast(); return fMode == cs.fMode; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); + GrColor4f constantOutputForConstantInput(GrColor4f input) const override { + float alpha = input.fRGBA[3]; + input = input.opaque(); + GrColor4f srcColor = ConstantOutputForConstantInput(this->childProcessor(0), input); + GrColor4f dstColor = ConstantOutputForConstantInput(this->childProcessor(1), input); + SkPM4f src = GrColor4fToSkPM4f(srcColor); + SkPM4f dst = GrColor4fToSkPM4f(dstColor); + auto proc = SkXfermode::GetProc4f(fMode); + return SkPM4fToGrColor4f(proc(src, dst)).mulByScalar(alpha); } -private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - SkXfermode::Mode fMode; + SkBlendMode fMode; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; @@ -69,16 +169,20 @@ private: GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor); +#if GR_TEST_UTILS sk_sp ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) { // Create two random frag procs. sk_sp fpA(GrProcessorUnitTest::MakeChildFP(d)); sk_sp fpB(GrProcessorUnitTest::MakeChildFP(d)); - SkXfermode::Mode mode = static_cast( - d->fRandom->nextRangeU(0, SkXfermode::kLastMode)); + SkBlendMode mode; + do { + mode = static_cast(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode)); + } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode); return sk_sp( new ComposeTwoFragmentProcessor(std::move(fpA), std::move(fpB), mode)); } +#endif GrGLSLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLSLInstance() const{ return new GLComposeTwoFragmentProcessor; @@ -98,14 +202,14 @@ void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) { } // declare outputColor and emit the code for each of the two children - SkString srcColor("src"); + SkString srcColor("xfer_src"); this->emitChild(0, inputColor, &srcColor, args); - SkString dstColor("dst"); + SkString dstColor("xfer_dst"); this->emitChild(1, inputColor, &dstColor, args); // emit blend code - SkXfermode::Mode mode = cs.getMode(); + SkBlendMode mode = cs.getMode(); fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode)); GrGLSLBlend::AppendMode(fragBuilder, srcColor.c_str(), @@ -120,14 +224,14 @@ void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) { } sk_sp GrXfermodeFragmentProcessor::MakeFromTwoProcessors( - sk_sp src, sk_sp dst, SkXfermode::Mode mode) { + sk_sp src, sk_sp dst, SkBlendMode mode) { switch (mode) { - case SkXfermode::kClear_Mode: - return GrConstColorProcessor::Make(GrColor_TRANSPARENT_BLACK, + case SkBlendMode::kClear: + return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), GrConstColorProcessor::kIgnore_InputMode); - case SkXfermode::kSrc_Mode: + case SkBlendMode::kSrc: return src; - case SkXfermode::kDst_Mode: + case SkBlendMode::kDst: return dst; default: return sk_sp( @@ -144,11 +248,10 @@ public: kSrc_Child, }; - ComposeOneFragmentProcessor(sk_sp dst, SkXfermode::Mode mode, Child child) - : fMode(mode) - , fChild(child) { + ComposeOneFragmentProcessor(sk_sp fp, SkBlendMode mode, Child child) + : INHERITED(OptFlags(fp.get(), mode, child)), fMode(mode), fChild(child) { this->initClassID(); - SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(std::move(dst)); + SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(fp)); SkASSERT(0 == dstIndex); } @@ -157,68 +260,145 @@ public: SkString dumpInfo() const override { SkString str; + str.appendf("Mode: %s, Child: %s", + SkBlendMode_Name(fMode), kDst_Child == fChild ? "Dst" : "Src"); + for (int i = 0; i < this->numChildProcessors(); ++i) { - str.append(this->childProcessor(i).dumpInfo()); + str.appendf(" [%s %s]", + this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str()); } return str; } - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { - GR_STATIC_ASSERT((SkXfermode::kLastMode & SK_MaxU16) == SkXfermode::kLastMode); - b->add32(fMode | (fChild << 16)); + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { + GR_STATIC_ASSERT(((int)SkBlendMode::kLastMode & SK_MaxU16) == (int)SkBlendMode::kLastMode); + b->add32((int)fMode | (fChild << 16)); } - SkXfermode::Mode mode() const { return fMode; } + SkBlendMode mode() const { return fMode; } Child child() const { return fChild; } -protected: +private: + OptimizationFlags OptFlags(const GrFragmentProcessor* fp, SkBlendMode mode, Child child) { + OptimizationFlags flags; + switch (mode) { + case SkBlendMode::kClear: + SkFAIL("Should never create clear compose one FP."); + flags = kNone_OptimizationFlags; + break; + + case SkBlendMode::kSrc: + SkASSERT(child == kSrc_Child); + flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags; + break; + + case SkBlendMode::kDst: + SkASSERT(child == kDst_Child); + flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags; + break; + + // Produces opaque if both src and dst are opaque. These also will modulate the child's + // output by either the input color or alpha. However, if the child is not compatible + // with the coverage as alpha then it may produce a color that is not valid premul. + case SkBlendMode::kSrcIn: + case SkBlendMode::kDstIn: + case SkBlendMode::kModulate: + if (fp->compatibleWithCoverageAsAlpha()) { + if (fp->preservesOpaqueInput()) { + flags = kPreservesOpaqueInput_OptimizationFlag | + kCompatibleWithCoverageAsAlpha_OptimizationFlag; + } else { + flags = kCompatibleWithCoverageAsAlpha_OptimizationFlag; + } + } else { + flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags; + } + break; + + // Produces zero when both are opaque, indeterminate if one is opaque. + case SkBlendMode::kSrcOut: + case SkBlendMode::kDstOut: + case SkBlendMode::kXor: + flags = kNone_OptimizationFlags; + break; + + // Is opaque if the dst is opaque. + case SkBlendMode::kSrcATop: + if (child == kDst_Child) { + flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags; + } else { + flags = kPreservesOpaqueInput_OptimizationFlag; + } + break; + + // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque. + case SkBlendMode::kDstATop: + case SkBlendMode::kScreen: + if (child == kSrc_Child) { + flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags; + } else { + flags = kPreservesOpaqueInput_OptimizationFlag; + } + break; + + // These modes are all opaque if either src or dst is opaque. All the advanced modes + // compute alpha as src-over. + case SkBlendMode::kSrcOver: + case SkBlendMode::kDstOver: + case SkBlendMode::kPlus: + case SkBlendMode::kOverlay: + case SkBlendMode::kDarken: + case SkBlendMode::kLighten: + case SkBlendMode::kColorDodge: + case SkBlendMode::kColorBurn: + case SkBlendMode::kHardLight: + case SkBlendMode::kSoftLight: + case SkBlendMode::kDifference: + case SkBlendMode::kExclusion: + case SkBlendMode::kMultiply: + case SkBlendMode::kHue: + case SkBlendMode::kSaturation: + case SkBlendMode::kColor: + case SkBlendMode::kLuminosity: + flags = kPreservesOpaqueInput_OptimizationFlag; + break; + } + if (does_cpu_blend_impl_match_gpu(mode) && fp->hasConstantOutputForConstantInput()) { + flags |= kConstantOutputForConstantInput_OptimizationFlag; + } + return flags; + } + bool onIsEqual(const GrFragmentProcessor& that) const override { return fMode == that.cast().fMode; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - SkXfermode::Coeff skSrcCoeff, skDstCoeff; - if (SkXfermode::ModeAsCoeff(fMode, &skSrcCoeff, &skDstCoeff)) { - GrBlendCoeff srcCoeff = SkXfermodeCoeffToGrBlendCoeff(skSrcCoeff); - GrBlendCoeff dstCoeff = SkXfermodeCoeffToGrBlendCoeff(skDstCoeff); - GrInvariantOutput childOutput(0xFFFFFFFF, kRGBA_GrColorComponentFlags, false); - this->childProcessor(0).computeInvariantOutput(&childOutput); - GrColor blendColor; - GrColorComponentFlags blendFlags; - if (kDst_Child == fChild) { - GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff, - inout->color(), inout->validFlags(), - childOutput.color(), childOutput.validFlags(), - &blendColor, &blendFlags); - } else { - GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff, - childOutput.color(), childOutput.validFlags(), - inout->color(), inout->validFlags(), - &blendColor, &blendFlags); - } - // will the shader code reference the input color? - GrInvariantOutput::ReadInput readsInput = GrInvariantOutput::kWillNot_ReadInput; - if (kDst_Child == fChild) { - if (kZero_GrBlendCoeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff)) { - readsInput = GrInvariantOutput::kWill_ReadInput; - } - } else { - if (kZero_GrBlendCoeff != dstCoeff || GrBlendCoeffRefsDst(srcCoeff)) { - readsInput = GrInvariantOutput::kWill_ReadInput; - } - } - inout->setToOther(blendFlags, blendColor, readsInput); + GrColor4f constantOutputForConstantInput(GrColor4f inputColor) const override { + GrColor4f childColor = + ConstantOutputForConstantInput(this->childProcessor(0), GrColor4f::OpaqueWhite()); + SkPM4f src, dst; + if (kSrc_Child == fChild) { + src = GrColor4fToSkPM4f(childColor); + dst = GrColor4fToSkPM4f(inputColor); } else { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); + src = GrColor4fToSkPM4f(inputColor); + dst = GrColor4fToSkPM4f(childColor); } + auto proc = SkXfermode::GetProc4f(fMode); + return SkPM4fToGrColor4f(proc(src, dst)); } private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - SkXfermode::Mode fMode; - Child fChild; + SkBlendMode fMode; + Child fChild; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; @@ -231,7 +411,7 @@ class GLComposeOneFragmentProcessor : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - SkXfermode::Mode mode = args.fFp.cast().mode(); + SkBlendMode mode = args.fFp.cast().mode(); ComposeOneFragmentProcessor::Child child = args.fFp.cast().child(); SkString childColor("child"); @@ -262,18 +442,22 @@ private: GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor); +#if GR_TEST_UTILS sk_sp ComposeOneFragmentProcessor::TestCreate(GrProcessorTestData* d) { // Create one random frag procs. // For now, we'll prevent either children from being a shader with children to prevent the // possibility of an arbitrarily large tree of procs. sk_sp dst(GrProcessorUnitTest::MakeChildFP(d)); - SkXfermode::Mode mode = static_cast( - d->fRandom->nextRangeU(0, SkXfermode::kLastMode)); - ComposeOneFragmentProcessor::Child child = d->fRandom->nextBool() ? - ComposeOneFragmentProcessor::kDst_Child : - ComposeOneFragmentProcessor::kSrc_Child; + SkBlendMode mode; + ComposeOneFragmentProcessor::Child child; + do { + mode = static_cast(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode)); + child = d->fRandom->nextBool() ? kDst_Child : kSrc_Child; + } while (SkBlendMode::kClear == mode || (SkBlendMode::kDst == mode && child == kSrc_Child) || + (SkBlendMode::kSrc == mode && child == kDst_Child)); return sk_sp(new ComposeOneFragmentProcessor(std::move(dst), mode, child)); } +#endif GrGLSLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLSLInstance() const { return new GLComposeOneFragmentProcessor; @@ -281,13 +465,19 @@ GrGLSLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLSLInstance() con ////////////////////////////////////////////////////////////////////////////// +// It may seems as though when the input FP is the dst and the mode is kDst (or same for src/kSrc) +// that these factories could simply return the input FP. However, that doesn't have quite +// the same effect as the returned compose FP will replace the FP's input with solid white and +// ignore the original input. This could be implemented as: +// RunInSeries(ConstColor(GrColor_WHITE, kIgnoreInput), inputFP). + sk_sp GrXfermodeFragmentProcessor::MakeFromDstProcessor( - sk_sp dst, SkXfermode::Mode mode) { + sk_sp dst, SkBlendMode mode) { switch (mode) { - case SkXfermode::kClear_Mode: - return GrConstColorProcessor::Make(GrColor_TRANSPARENT_BLACK, - GrConstColorProcessor::kIgnore_InputMode); - case SkXfermode::kSrc_Mode: + case SkBlendMode::kClear: + return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), + GrConstColorProcessor::kIgnore_InputMode); + case SkBlendMode::kSrc: return nullptr; default: return sk_sp( @@ -297,16 +487,16 @@ sk_sp GrXfermodeFragmentProcessor::MakeFromDstProcessor( } sk_sp GrXfermodeFragmentProcessor::MakeFromSrcProcessor( - sk_sp src, SkXfermode::Mode mode) { + sk_sp src, SkBlendMode mode) { switch (mode) { - case SkXfermode::kClear_Mode: - return GrConstColorProcessor::Make(GrColor_TRANSPARENT_BLACK, - GrConstColorProcessor::kIgnore_InputMode); - case SkXfermode::kDst_Mode: + case SkBlendMode::kClear: + return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), + GrConstColorProcessor::kIgnore_InputMode); + case SkBlendMode::kDst: return nullptr; default: return sk_sp( - new ComposeOneFragmentProcessor(src, mode, + new ComposeOneFragmentProcessor(std::move(src), mode, ComposeOneFragmentProcessor::kSrc_Child)); } } diff --git a/gfx/skia/skia/src/gpu/effects/GrYUVEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrYUVEffect.cpp index cbe25e82f8de..be4d6c2d5c36 100644 --- a/gfx/skia/skia/src/gpu/effects/GrYUVEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrYUVEffect.cpp @@ -9,8 +9,8 @@ #include "GrCoordTransform.h" #include "GrFragmentProcessor.h" -#include "GrInvariantOutput.h" #include "GrProcessor.h" +#include "GrTextureProxy.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" @@ -62,31 +62,33 @@ static const float kRec709InverseConversionMatrix[16] = { class YUVtoRGBEffect : public GrFragmentProcessor { public: - static sk_sp Make(GrTexture* yTexture, GrTexture* uTexture, - GrTexture* vTexture, const SkISize sizes[3], + static sk_sp Make(GrResourceProvider* resourceProvider, + sk_sp yProxy, + sk_sp uProxy, + sk_sp vProxy, const SkISize sizes[3], SkYUVColorSpace colorSpace, bool nv12) { SkScalar w[3], h[3]; - w[0] = SkIntToScalar(sizes[0].fWidth) / SkIntToScalar(yTexture->width()); - h[0] = SkIntToScalar(sizes[0].fHeight) / SkIntToScalar(yTexture->height()); - w[1] = SkIntToScalar(sizes[1].fWidth) / SkIntToScalar(uTexture->width()); - h[1] = SkIntToScalar(sizes[1].fHeight) / SkIntToScalar(uTexture->height()); - w[2] = SkIntToScalar(sizes[2].fWidth) / SkIntToScalar(vTexture->width()); - h[2] = SkIntToScalar(sizes[2].fHeight) / SkIntToScalar(vTexture->height()); - SkMatrix yuvMatrix[3]; - yuvMatrix[0] = GrCoordTransform::MakeDivByTextureWHMatrix(yTexture); - yuvMatrix[1] = yuvMatrix[0]; - yuvMatrix[1].preScale(w[1] / w[0], h[1] / h[0]); - yuvMatrix[2] = yuvMatrix[0]; - yuvMatrix[2].preScale(w[2] / w[0], h[2] / h[0]); - GrTextureParams::FilterMode uvFilterMode = + w[0] = SkIntToScalar(sizes[0].fWidth); + h[0] = SkIntToScalar(sizes[0].fHeight); + w[1] = SkIntToScalar(sizes[1].fWidth); + h[1] = SkIntToScalar(sizes[1].fHeight); + w[2] = SkIntToScalar(sizes[2].fWidth); + h[2] = SkIntToScalar(sizes[2].fHeight); + const SkMatrix yuvMatrix[3] = { + SkMatrix::I(), + SkMatrix::MakeScale(w[1] / w[0], h[1] / h[0]), + SkMatrix::MakeScale(w[2] / w[0], h[2] / h[0]) + }; + GrSamplerParams::FilterMode uvFilterMode = ((sizes[1].fWidth != sizes[0].fWidth) || (sizes[1].fHeight != sizes[0].fHeight) || (sizes[2].fWidth != sizes[0].fWidth) || (sizes[2].fHeight != sizes[0].fHeight)) ? - GrTextureParams::kBilerp_FilterMode : - GrTextureParams::kNone_FilterMode; + GrSamplerParams::kBilerp_FilterMode : + GrSamplerParams::kNone_FilterMode; return sk_sp(new YUVtoRGBEffect( - yTexture, uTexture, vTexture, yuvMatrix, uvFilterMode, colorSpace, nv12)); + resourceProvider, std::move(yProxy), std::move(uProxy), std::move(vProxy), + yuvMatrix, uvFilterMode, colorSpace, nv12)); } const char* name() const override { return "YUV to RGB"; } @@ -129,7 +131,7 @@ public: protected: void onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) override { + const GrFragmentProcessor& processor) override { const YUVtoRGBEffect& yuvEffect = processor.cast(); switch (yuvEffect.getColorSpace()) { case kJPEG_SkYUVColorSpace: @@ -151,25 +153,27 @@ public: }; private: - YUVtoRGBEffect(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture, - const SkMatrix yuvMatrix[3], GrTextureParams::FilterMode uvFilterMode, - SkYUVColorSpace colorSpace, bool nv12) - : fYTransform(yuvMatrix[0], yTexture, GrTextureParams::kNone_FilterMode) - , fYAccess(yTexture) - , fUTransform(yuvMatrix[1], uTexture, uvFilterMode) - , fUAccess(uTexture, uvFilterMode) - , fVAccess(vTexture, uvFilterMode) - , fColorSpace(colorSpace) - , fNV12(nv12) { + YUVtoRGBEffect(GrResourceProvider* resourceProvider, + sk_sp yProxy, sk_sp uProxy, + sk_sp vProxy, const SkMatrix yuvMatrix[3], + GrSamplerParams::FilterMode uvFilterMode, SkYUVColorSpace colorSpace, bool nv12) + : INHERITED(kPreservesOpaqueInput_OptimizationFlag) + , fYTransform(resourceProvider, yuvMatrix[0], yProxy.get()) + , fYSampler(resourceProvider, std::move(yProxy)) + , fUTransform(resourceProvider, yuvMatrix[1], uProxy.get()) + , fUSampler(resourceProvider, std::move(uProxy), uvFilterMode) + , fVSampler(resourceProvider, vProxy, uvFilterMode) + , fColorSpace(colorSpace) + , fNV12(nv12) { this->initClassID(); this->addCoordTransform(&fYTransform); - this->addTextureAccess(&fYAccess); + this->addTextureSampler(&fYSampler); this->addCoordTransform(&fUTransform); - this->addTextureAccess(&fUAccess); + this->addTextureSampler(&fUSampler); if (!fNV12) { - fVTransform = GrCoordTransform(yuvMatrix[2], vTexture, uvFilterMode); + fVTransform = GrCoordTransform(resourceProvider, yuvMatrix[2], vProxy.get()); this->addCoordTransform(&fVTransform); - this->addTextureAccess(&fVAccess); + this->addTextureSampler(&fVSampler); } } @@ -177,7 +181,7 @@ private: return new GLSLProcessor; } - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { b->add32(fNV12); } @@ -186,18 +190,12 @@ private: return (fColorSpace == s.getColorSpace()) && (fNV12 == s.isNV12()); } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - // YUV is opaque - inout->setToOther(kA_GrColorComponentFlag, 0xFF << GrColor_SHIFT_A, - GrInvariantOutput::kWillNot_ReadInput); - } - GrCoordTransform fYTransform; - GrTextureAccess fYAccess; + TextureSampler fYSampler; GrCoordTransform fUTransform; - GrTextureAccess fUAccess; + TextureSampler fUSampler; GrCoordTransform fVTransform; - GrTextureAccess fVAccess; + TextureSampler fVSampler; SkYUVColorSpace fColorSpace; bool fNV12; @@ -222,8 +220,10 @@ public: RGBToYUVEffect(sk_sp rgbFP, SkYUVColorSpace colorSpace, OutputChannels output) - : fColorSpace(colorSpace) - , fOutputChannels(output) { + // This could advertise kConstantOutputForConstantInput, but doesn't seem useful. + : INHERITED(kPreservesOpaqueInput_OptimizationFlag) + , fColorSpace(colorSpace) + , fOutputChannels(output) { this->initClassID(); this->registerChildProcessor(std::move(rgbFP)); } @@ -285,7 +285,7 @@ public: private: void onSetData(const GrGLSLProgramDataManager& pdman, - const GrProcessor& processor) override { + const GrFragmentProcessor& processor) override { const RGBToYUVEffect& effect = processor.cast(); OutputChannels oc = effect.outputChannels(); if (effect.getColorSpace() != fLastColorSpace || oc != fLastOutputChannels) { @@ -334,7 +334,7 @@ private: return new GLSLProcessor; } - void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { // kY, kU, and kV all generate the same code, just upload different coefficients. if (kU_OutputChannels == fOutputChannels || kV_OutputChannels == fOutputChannels) { b->add32(kY_OutputChannels); @@ -348,12 +348,8 @@ private: return fColorSpace == s.getColorSpace() && fOutputChannels == s.outputChannels(); } - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput); - } - GrCoordTransform fTransform; - GrTextureAccess fAccess; + TextureSampler fTextureSampler; SkYUVColorSpace fColorSpace; OutputChannels fOutputChannels; @@ -364,11 +360,16 @@ private: ////////////////////////////////////////////////////////////////////////////// -sk_sp GrYUVEffect::MakeYUVToRGB(GrTexture* yTexture, GrTexture* uTexture, - GrTexture* vTexture, const SkISize sizes[3], +sk_sp GrYUVEffect::MakeYUVToRGB(GrResourceProvider* resourceProvider, + sk_sp yProxy, + sk_sp uProxy, + sk_sp vProxy, + const SkISize sizes[3], SkYUVColorSpace colorSpace, bool nv12) { - SkASSERT(yTexture && uTexture && vTexture && sizes); - return YUVtoRGBEffect::Make(yTexture, uTexture, vTexture, sizes, colorSpace, nv12); + SkASSERT(yProxy && uProxy && vProxy && sizes); + return YUVtoRGBEffect::Make(resourceProvider, + std::move(yProxy), std::move(uProxy), std::move(vProxy), + sizes, colorSpace, nv12); } sk_sp diff --git a/gfx/skia/skia/src/gpu/effects/GrYUVEffect.h b/gfx/skia/skia/src/gpu/effects/GrYUVEffect.h index 902a181fd4ca..7b05f905487d 100644 --- a/gfx/skia/skia/src/gpu/effects/GrYUVEffect.h +++ b/gfx/skia/skia/src/gpu/effects/GrYUVEffect.h @@ -10,16 +10,19 @@ #include "SkImageInfo.h" +class GrResourceProvider; class GrFragmentProcessor; -class GrTexture; +class GrTextureProxy; namespace GrYUVEffect { /** * Creates an effect that performs color conversion from YUV to RGB. The input textures are * assumed to be kA8_GrPixelConfig. */ - sk_sp MakeYUVToRGB(GrTexture* yTexture, GrTexture* uTexture, - GrTexture* vTexture, const SkISize sizes[3], + sk_sp MakeYUVToRGB(GrResourceProvider* resourceProvider, + sk_sp yProxy, + sk_sp uProxy, + sk_sp vProxy, const SkISize sizes[3], SkYUVColorSpace colorSpace, bool nv12); /** @@ -27,24 +30,22 @@ namespace GrYUVEffect { * channels to Y, U ,and V channels. The output color is (y, u, v, a) where a is the passed in * processor's alpha output. */ - sk_sp MakeRGBToYUV(sk_sp, - SkYUVColorSpace colorSpace); + sk_sp MakeRGBToYUV(sk_sp, SkYUVColorSpace); /** * Creates a processor that performs color conversion from the passed in processor's RGB * channels to U and V channels. The output color is (u, v, 0, a) where a is the passed in * processor's alpha output. */ - sk_sp MakeRGBToUV(sk_sp, - SkYUVColorSpace colorSpace); + sk_sp MakeRGBToUV(sk_sp, SkYUVColorSpace); /** * Creates a processor that performs color conversion from the passed in fragment processors's * RGB channels to Y, U, or V (replicated across all four output color channels). The alpha * output of the passed in fragment processor is ignored. */ - sk_sp MakeRGBToY(sk_sp, SkYUVColorSpace colorSpace); - sk_sp MakeRGBToU(sk_sp, SkYUVColorSpace colorSpace); - sk_sp MakeRGBToV(sk_sp, SkYUVColorSpace colorSpace); + sk_sp MakeRGBToY(sk_sp, SkYUVColorSpace); + sk_sp MakeRGBToU(sk_sp, SkYUVColorSpace); + sk_sp MakeRGBToV(sk_sp, SkYUVColorSpace); }; #endif diff --git a/gfx/skia/skia/src/gpu/gl/GrGLAssembleInterface.cpp b/gfx/skia/skia/src/gpu/gl/GrGLAssembleInterface.cpp index b435655a5f87..83920dba8d33 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLAssembleInterface.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLAssembleInterface.cpp @@ -158,7 +158,6 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { GET_PROC(Flush); GET_PROC(FrontFace); GET_PROC(GenBuffers); - GET_PROC(GenerateMipmap); GET_PROC(GetBufferParameteriv); GET_PROC(GetError); GET_PROC(GetIntegerv); @@ -198,6 +197,7 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { } GET_PROC(PixelStorei); + GET_PROC(PolygonMode); if (extensions.has("GL_EXT_raster_multisample")) { GET_PROC_SUFFIX(RasterSamples, EXT); } @@ -288,6 +288,7 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since // GL_ARB_framebuffer_object doesn't use ARB suffix.) if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) { + GET_PROC(GenerateMipmap); GET_PROC(GenFramebuffers); GET_PROC(GetFramebufferAttachmentParameteriv); GET_PROC(GetRenderbufferParameteriv); @@ -303,6 +304,7 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { GET_PROC(RenderbufferStorageMultisample); GET_PROC(BlitFramebuffer); } else if (extensions.has("GL_EXT_framebuffer_object")) { + GET_PROC_SUFFIX(GenerateMipmap, EXT); GET_PROC_SUFFIX(GenFramebuffers, EXT); GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT); GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT); @@ -529,9 +531,18 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { if (glVer >= GR_GL_VER(3, 2) || extensions.has("GL_ARB_sync")) { GET_PROC(FenceSync); GET_PROC(ClientWaitSync); + GET_PROC(WaitSync); GET_PROC(DeleteSync); } + if (glVer >= GR_GL_VER(4, 2) || extensions.has("GL_ARB_shader_image_load_store")) { + GET_PROC(BindImageTexture); + GET_PROC(MemoryBarrier); + } + if (glVer >= GR_GL_VER(4, 5) || extensions.has("GL_ARB_ES3_1_compatibility")) { + GET_PROC(MemoryBarrierByRegion); + } + interface->fStandard = kGL_GrGLStandard; interface->fExtensions.swap(&extensions); @@ -748,12 +759,19 @@ const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) { GET_PROC(FramebufferRenderbuffer); GET_PROC(FramebufferTexture2D); - if (extensions.has("GL_CHROMIUM_framebuffer_multisample")) { - GET_PROC_SUFFIX(RenderbufferStorageMultisample, CHROMIUM); - GET_PROC_SUFFIX(BlitFramebuffer, CHROMIUM); - } else if (version >= GR_GL_VER(3,0)) { + if (version >= GR_GL_VER(3,0)) { GET_PROC(RenderbufferStorageMultisample); GET_PROC(BlitFramebuffer); + } else if (extensions.has("GL_CHROMIUM_framebuffer_multisample")) { + GET_PROC_SUFFIX(RenderbufferStorageMultisample, CHROMIUM); + GET_PROC_SUFFIX(BlitFramebuffer, CHROMIUM); + } else { + if (extensions.has("GL_ANGLE_framebuffer_multisample")) { + GET_PROC_SUFFIX(RenderbufferStorageMultisample, ANGLE); + } + if (extensions.has("GL_ANGLE_framebuffer_blit")) { + GET_PROC_SUFFIX(BlitFramebuffer, ANGLE); + } } if (extensions.has("GL_CHROMIUM_map_sub")) { @@ -792,16 +810,9 @@ const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) { } if (extensions.has("GL_EXT_debug_marker")) { - GET_PROC(InsertEventMarker); - GET_PROC(PushGroupMarker); - GET_PROC(PopGroupMarker); - // The below check is here because a device has been found that has the extension string but - // returns nullptr from the eglGetProcAddress for the functions - if (nullptr == functions->fInsertEventMarker || - nullptr == functions->fPushGroupMarker || - nullptr == functions->fPopGroupMarker) { - extensions.remove("GL_EXT_debug_marker"); - } + GET_PROC_SUFFIX(InsertEventMarker, EXT); + GET_PROC_SUFFIX(PushGroupMarker, EXT); + GET_PROC_SUFFIX(PopGroupMarker, EXT); } GET_PROC(InvalidateFramebuffer); @@ -928,9 +939,16 @@ const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) { if (version >= GR_GL_VER(3, 0)) { GET_PROC(FenceSync); GET_PROC(ClientWaitSync); + GET_PROC(WaitSync); GET_PROC(DeleteSync); } + if (version >= GR_GL_VER(3, 1)) { + GET_PROC(BindImageTexture); + GET_PROC(MemoryBarrier); + GET_PROC(MemoryBarrierByRegion); + } + interface->fStandard = kGLES_GrGLStandard; interface->fExtensions.swap(&extensions); diff --git a/gfx/skia/skia/src/gpu/gl/GrGLBuffer.cpp b/gfx/skia/skia/src/gpu/gl/GrGLBuffer.cpp index 96226b912194..250c7119a927 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLBuffer.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLBuffer.cpp @@ -30,7 +30,7 @@ GrGLBuffer* GrGLBuffer::Create(GrGLGpu* gpu, size_t size, GrBufferType intendedType, GrAccessPattern accessPattern, const void* data) { - SkAutoTUnref buffer(new GrGLBuffer(gpu, size, intendedType, accessPattern, data)); + sk_sp buffer(new GrGLBuffer(gpu, size, intendedType, accessPattern, data)); if (0 == buffer->bufferID()) { return nullptr; } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLBuffer.h b/gfx/skia/skia/src/gpu/gl/GrGLBuffer.h index 6a90d0334c79..3400819a5d66 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLBuffer.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLBuffer.h @@ -19,7 +19,7 @@ public: static GrGLBuffer* Create(GrGLGpu*, size_t size, GrBufferType intendedType, GrAccessPattern, const void* data = nullptr); - ~GrGLBuffer() { + ~GrGLBuffer() override { // either release or abandon should have been called by the owner of this object. SkASSERT(0 == fBufferID); } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLCaps.cpp b/gfx/skia/skia/src/gpu/gl/GrGLCaps.cpp index 1a7b105a2179..bc894c30d13d 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLCaps.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLCaps.cpp @@ -5,16 +5,16 @@ * found in the LICENSE file. */ - #include "GrGLCaps.h" - #include "GrContextOptions.h" #include "GrGLContext.h" #include "GrGLRenderTarget.h" -#include "glsl/GrGLSLCaps.h" -#include "instanced/GLInstancedRendering.h" +#include "GrGLTexture.h" +#include "GrShaderCaps.h" +#include "GrSurfaceProxyPriv.h" #include "SkTSearch.h" #include "SkTSort.h" +#include "instanced/GLInstancedRendering.h" GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, const GrGLContextInfo& ctxInfo, @@ -51,10 +51,12 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, fMipMapLevelAndLodControlSupport = false; fRGBAToBGRAReadbackConversionsAreSlow = false; fDoManualMipmapping = false; + fSRGBDecodeDisableSupport = false; + fSRGBDecodeDisableAffectsMipmaps = false; - fBlitFramebufferSupport = kNone_BlitFramebufferSupport; + fBlitFramebufferFlags = kNoSupport_BlitFramebufferFlag; - fShaderCaps.reset(new GrGLSLCaps(contextOptions)); + fShaderCaps.reset(new GrShaderCaps(contextOptions)); this->init(contextOptions, ctxInfo, glInterface); } @@ -118,9 +120,9 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fSampleLocationsSupport = version >= GR_GL_VER(3,1); } - // ARB_texture_rg is part of OpenGL 3.0, but mesa doesn't support GL_RED + // ARB_texture_rg is part of OpenGL 3.0, but osmesa doesn't support GL_RED // and GL_RG on FBO textures. - if (kMesa_GrGLDriver != ctxInfo.driver()) { + if (kOSMesa_GrGLRenderer != ctxInfo.renderer()) { if (kGL_GrGLStandard == standard) { fTextureRedSupport = version >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_ARB_texture_rg"); @@ -254,70 +256,101 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, // This must be called after fCoreProfile is set on the GrGLCaps this->initGLSL(ctxInfo); - GrGLSLCaps* glslCaps = static_cast(fShaderCaps.get()); + GrShaderCaps* shaderCaps = fShaderCaps.get(); - glslCaps->fPathRenderingSupport = this->hasPathRenderingSupport(ctxInfo, gli); + if (!contextOptions.fSuppressPathRendering) { + shaderCaps->fPathRenderingSupport = this->hasPathRenderingSupport(ctxInfo, gli); + } // For now these two are equivalent but we could have dst read in shader via some other method. // Before setting this, initGLSL() must have been called. - glslCaps->fDstReadInShaderSupport = glslCaps->fFBFetchSupport; + shaderCaps->fDstReadInShaderSupport = shaderCaps->fFBFetchSupport; // Enable supported shader-related caps if (kGL_GrGLStandard == standard) { - glslCaps->fDualSourceBlendingSupport = (ctxInfo.version() >= GR_GL_VER(3, 3) || + shaderCaps->fDualSourceBlendingSupport = (ctxInfo.version() >= GR_GL_VER(3, 3) || ctxInfo.hasExtension("GL_ARB_blend_func_extended")) && GrGLSLSupportsNamedFragmentShaderOutputs(ctxInfo.glslGeneration()); - glslCaps->fShaderDerivativeSupport = true; + shaderCaps->fShaderDerivativeSupport = true; // we don't support GL_ARB_geometry_shader4, just GL 3.2+ GS - glslCaps->fGeometryShaderSupport = ctxInfo.version() >= GR_GL_VER(3, 2) && + shaderCaps->fGeometryShaderSupport = ctxInfo.version() >= GR_GL_VER(3, 2) && ctxInfo.glslGeneration() >= k150_GrGLSLGeneration; - glslCaps->fIntegerSupport = ctxInfo.version() >= GR_GL_VER(3, 0) && + shaderCaps->fIntegerSupport = ctxInfo.version() >= GR_GL_VER(3, 0) && ctxInfo.glslGeneration() >= k130_GrGLSLGeneration; } else { - glslCaps->fDualSourceBlendingSupport = ctxInfo.hasExtension("GL_EXT_blend_func_extended"); + shaderCaps->fDualSourceBlendingSupport = ctxInfo.hasExtension("GL_EXT_blend_func_extended"); - glslCaps->fShaderDerivativeSupport = ctxInfo.version() >= GR_GL_VER(3, 0) || + shaderCaps->fShaderDerivativeSupport = ctxInfo.version() >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_OES_standard_derivatives"); - glslCaps->fIntegerSupport = ctxInfo.version() >= GR_GL_VER(3, 0) && - ctxInfo.glslGeneration() >= k330_GrGLSLGeneration; // We use this value for GLSL ES 3.0. - } + shaderCaps->fGeometryShaderSupport = ctxInfo.hasExtension("GL_EXT_geometry_shader"); - if (ctxInfo.hasExtension("GL_EXT_shader_pixel_local_storage")) { - #define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT 0x8F63 - GR_GL_GetIntegerv(gli, GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT, - &glslCaps->fPixelLocalStorageSize); - glslCaps->fPLSPathRenderingSupport = glslCaps->fFBFetchSupport; - } - else { - glslCaps->fPixelLocalStorageSize = 0; - glslCaps->fPLSPathRenderingSupport = false; + shaderCaps->fIntegerSupport = ctxInfo.version() >= GR_GL_VER(3, 0) && + ctxInfo.glslGeneration() >= k330_GrGLSLGeneration; // We use this value for GLSL ES 3.0. } // Protect ourselves against tracking huge amounts of texture state. static const uint8_t kMaxSaneSamplers = 32; GrGLint maxSamplers; GR_GL_GetIntegerv(gli, GR_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxSamplers); - glslCaps->fMaxVertexSamplers = SkTMin(kMaxSaneSamplers, maxSamplers); - if (glslCaps->fGeometryShaderSupport) { + shaderCaps->fMaxVertexSamplers = SkTMin(kMaxSaneSamplers, maxSamplers); + if (shaderCaps->fGeometryShaderSupport) { GR_GL_GetIntegerv(gli, GR_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &maxSamplers); - glslCaps->fMaxGeometrySamplers = SkTMin(kMaxSaneSamplers, maxSamplers); + shaderCaps->fMaxGeometrySamplers = SkTMin(kMaxSaneSamplers, maxSamplers); } GR_GL_GetIntegerv(gli, GR_GL_MAX_TEXTURE_IMAGE_UNITS, &maxSamplers); - glslCaps->fMaxFragmentSamplers = SkTMin(kMaxSaneSamplers, maxSamplers); + shaderCaps->fMaxFragmentSamplers = SkTMin(kMaxSaneSamplers, maxSamplers); GR_GL_GetIntegerv(gli, GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxSamplers); - glslCaps->fMaxCombinedSamplers = SkTMin(kMaxSaneSamplers, maxSamplers); + shaderCaps->fMaxCombinedSamplers = SkTMin(kMaxSaneSamplers, maxSamplers); + + if (kGL_GrGLStandard == standard) { + shaderCaps->fImageLoadStoreSupport = ctxInfo.version() >= GR_GL_VER(4, 2); + if (!shaderCaps->fImageLoadStoreSupport && + ctxInfo.hasExtension("GL_ARB_shader_image_load_store")) { + shaderCaps->fImageLoadStoreSupport = true; + shaderCaps->fImageLoadStoreExtensionString = "GL_ARB_shader_image_load_store"; + } + } else { + shaderCaps->fImageLoadStoreSupport = ctxInfo.version() >= GR_GL_VER(3, 1); + } + if (shaderCaps->fImageLoadStoreSupport) { + // Protect ourselves against tracking huge amounts of image state. + static constexpr int kMaxSaneImages = 4; + GrGLint maxUnits; + GR_GL_GetIntegerv(gli, GR_GL_MAX_IMAGE_UNITS, &maxUnits); + GR_GL_GetIntegerv(gli, GR_GL_MAX_VERTEX_IMAGE_UNIFORMS, + &shaderCaps->fMaxVertexImageStorages); + if (shaderCaps->fGeometryShaderSupport) { + GR_GL_GetIntegerv(gli, GR_GL_MAX_GEOMETRY_IMAGE_UNIFORMS, + &shaderCaps->fMaxGeometryImageStorages); + } + GR_GL_GetIntegerv(gli, GR_GL_MAX_FRAGMENT_IMAGE_UNIFORMS, + &shaderCaps->fMaxFragmentImageStorages); + GR_GL_GetIntegerv(gli, GR_GL_MAX_COMBINED_IMAGE_UNIFORMS, + &shaderCaps->fMaxCombinedImageStorages); + // We use one unit for every image uniform + shaderCaps->fMaxCombinedImageStorages = SkTMin(SkTMin(shaderCaps->fMaxCombinedImageStorages, + maxUnits), kMaxSaneImages); + shaderCaps->fMaxVertexImageStorages = SkTMin(maxUnits, + shaderCaps->fMaxVertexImageStorages); + shaderCaps->fMaxGeometryImageStorages = SkTMin(maxUnits, + shaderCaps->fMaxGeometryImageStorages); + shaderCaps->fMaxFragmentImageStorages = SkTMin(maxUnits, + shaderCaps->fMaxFragmentImageStorages); + } /************************************************************************** * GrCaps fields **************************************************************************/ // We need dual source blending and the ability to disable multisample in order to support mixed - // samples in every corner case. + // samples in every corner case. We only use mixed samples if the stencil-and-cover path + // renderer is available and enabled; no other path renderers support this feature. if (fMultisampleDisableSupport && - glslCaps->dualSourceBlendingSupport() && - fShaderCaps->pathRenderingSupport()) { + shaderCaps->dualSourceBlendingSupport() && + fShaderCaps->pathRenderingSupport() && + (contextOptions.fGpuPathRenderers & GrContextOptions::GpuPathRenderers::kStencilAndCover)) { fUsesMixedSamples = ctxInfo.hasExtension("GL_NV_framebuffer_mixed_samples") || ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_mixed_samples"); // Workaround NVIDIA bug related to glInvalidateFramebuffer and mixed samples. @@ -398,10 +431,10 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, // On many GPUs, map memory is very expensive, so we effectively disable it here by setting the // threshold to the maximum unless the client gives us a hint that map memory is cheap. if (fBufferMapThreshold < 0) { - // We think mapping on Chromium will be cheaper once we know ahead of time how much space - // we will use for all GrBatchs. Right now we might wind up mapping a large buffer and using - // a small subset. #if 0 + // We think mapping on Chromium will be cheaper once we know ahead of time how much space + // we will use for all GrMeshDrawOps. Right now we might wind up mapping a large buffer and + // using a small subset. fBufferMapThreshold = kChromium_GrGLDriver == ctxInfo.driver() ? 0 : SK_MaxS32; #else fBufferMapThreshold = SK_MaxS32; @@ -467,7 +500,8 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, if (kPowerVR54x_GrGLRenderer == ctxInfo.renderer() || kPowerVRRogue_GrGLRenderer == ctxInfo.renderer() || - kAdreno3xx_GrGLRenderer == ctxInfo.renderer()) { + (kAdreno3xx_GrGLRenderer == ctxInfo.renderer() && + ctxInfo.driver() != kChromium_GrGLDriver)) { fUseDrawInsteadOfClear = true; } @@ -535,7 +569,7 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fDrawRangeElementsSupport = version >= GR_GL_VER(3,0); } - this->initShaderPrecisionTable(ctxInfo, gli, glslCaps); + this->initShaderPrecisionTable(ctxInfo, gli, shaderCaps); if (contextOptions.fUseShaderSwizzling) { fTextureSwizzleSupport = false; @@ -559,6 +593,15 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fFenceSyncSupport = true; } + // Safely moving textures between contexts requires fences. The Windows Intel driver has a + // bug with deleting and reusing texture IDs across contexts, so disallow this feature. + fCrossContextTextureSupport = fFenceSyncSupport; +#ifdef SK_BUILD_FOR_WIN + if (kIntel_GrGLVendor == ctxInfo.vendor()) { + fCrossContextTextureSupport = false; + } +#endif + // We support manual mip-map generation (via iterative downsampling draw calls). This fixes // bugs on some cards/drivers that produce incorrect mip-maps for sRGB textures when using // glGenerateMipmap. Our implementation requires mip-level sampling control. Additionally, @@ -571,12 +614,16 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fDoManualMipmapping = true; } + fSRGBDecodeDisableSupport = ctxInfo.hasExtension("GL_EXT_texture_sRGB_decode"); + fSRGBDecodeDisableAffectsMipmaps = fSRGBDecodeDisableSupport && + kChromium_GrGLDriver != ctxInfo.driver(); + // Requires fTextureRedSupport, fTextureSwizzleSupport, msaa support, ES compatibility have // already been detected. - this->initConfigTable(ctxInfo, gli, glslCaps); + this->initConfigTable(contextOptions, ctxInfo, gli, shaderCaps); this->applyOptionsOverrides(contextOptions); - glslCaps->applyOptionsOverrides(contextOptions); + shaderCaps->applyOptionsOverrides(contextOptions); } const char* get_glsl_version_decl_string(GrGLStandard standard, GrGLSLGeneration generation, @@ -622,6 +669,14 @@ const char* get_glsl_version_decl_string(GrGLStandard standard, GrGLSLGeneration } else { return "#version 400 compatibility\n"; } + case k420_GrGLSLGeneration: + SkASSERT(kGL_GrGLStandard == standard); + if (isCoreProfile) { + return "#version 420\n"; + } + else { + return "#version 420 compatibility\n"; + } case k310es_GrGLSLGeneration: SkASSERT(kGLES_GrGLStandard == standard); return "#version 310 es\n"; @@ -637,109 +692,110 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo) { GrGLVersion version = ctxInfo.version(); /************************************************************************** - * Caps specific to GrGLSLCaps + * Caps specific to GrShaderCaps **************************************************************************/ - GrGLSLCaps* glslCaps = static_cast(fShaderCaps.get()); - glslCaps->fGLSLGeneration = ctxInfo.glslGeneration(); + GrShaderCaps* shaderCaps = fShaderCaps.get(); + shaderCaps->fGLSLGeneration = ctxInfo.glslGeneration(); if (kGLES_GrGLStandard == standard) { if (ctxInfo.hasExtension("GL_EXT_shader_framebuffer_fetch")) { - glslCaps->fFBFetchNeedsCustomOutput = (version >= GR_GL_VER(3, 0)); - glslCaps->fFBFetchSupport = true; - glslCaps->fFBFetchColorName = "gl_LastFragData[0]"; - glslCaps->fFBFetchExtensionString = "GL_EXT_shader_framebuffer_fetch"; + shaderCaps->fFBFetchNeedsCustomOutput = (version >= GR_GL_VER(3, 0)); + shaderCaps->fFBFetchSupport = true; + shaderCaps->fFBFetchColorName = "gl_LastFragData[0]"; + shaderCaps->fFBFetchExtensionString = "GL_EXT_shader_framebuffer_fetch"; } else if (ctxInfo.hasExtension("GL_NV_shader_framebuffer_fetch")) { // Actually, we haven't seen an ES3.0 device with this extension yet, so we don't know - glslCaps->fFBFetchNeedsCustomOutput = false; - glslCaps->fFBFetchSupport = true; - glslCaps->fFBFetchColorName = "gl_LastFragData[0]"; - glslCaps->fFBFetchExtensionString = "GL_NV_shader_framebuffer_fetch"; + shaderCaps->fFBFetchNeedsCustomOutput = false; + shaderCaps->fFBFetchSupport = true; + shaderCaps->fFBFetchColorName = "gl_LastFragData[0]"; + shaderCaps->fFBFetchExtensionString = "GL_NV_shader_framebuffer_fetch"; } else if (ctxInfo.hasExtension("GL_ARM_shader_framebuffer_fetch")) { // The arm extension also requires an additional flag which we will set onResetContext - glslCaps->fFBFetchNeedsCustomOutput = false; - glslCaps->fFBFetchSupport = true; - glslCaps->fFBFetchColorName = "gl_LastFragColorARM"; - glslCaps->fFBFetchExtensionString = "GL_ARM_shader_framebuffer_fetch"; + shaderCaps->fFBFetchNeedsCustomOutput = false; + shaderCaps->fFBFetchSupport = true; + shaderCaps->fFBFetchColorName = "gl_LastFragColorARM"; + shaderCaps->fFBFetchExtensionString = "GL_ARM_shader_framebuffer_fetch"; } - glslCaps->fUsesPrecisionModifiers = true; + shaderCaps->fUsesPrecisionModifiers = true; } // Currently the extension is advertised but fb fetch is broken on 500 series Adrenos like the // Galaxy S7. // TODO: Once this is fixed we can update the check here to look at a driver version number too. if (kAdreno5xx_GrGLRenderer == ctxInfo.renderer()) { - glslCaps->fFBFetchSupport = false; + shaderCaps->fFBFetchSupport = false; } - glslCaps->fBindlessTextureSupport = ctxInfo.hasExtension("GL_NV_bindless_texture"); + shaderCaps->fBindlessTextureSupport = ctxInfo.hasExtension("GL_NV_bindless_texture"); if (kGL_GrGLStandard == standard) { - glslCaps->fFlatInterpolationSupport = ctxInfo.glslGeneration() >= k130_GrGLSLGeneration; + shaderCaps->fFlatInterpolationSupport = ctxInfo.glslGeneration() >= k130_GrGLSLGeneration; } else { - glslCaps->fFlatInterpolationSupport = + shaderCaps->fFlatInterpolationSupport = ctxInfo.glslGeneration() >= k330_GrGLSLGeneration; // This is the value for GLSL ES 3.0. } if (kGL_GrGLStandard == standard) { - glslCaps->fNoPerspectiveInterpolationSupport = + shaderCaps->fNoPerspectiveInterpolationSupport = ctxInfo.glslGeneration() >= k130_GrGLSLGeneration; } else { if (ctxInfo.hasExtension("GL_NV_shader_noperspective_interpolation")) { - glslCaps->fNoPerspectiveInterpolationSupport = true; - glslCaps->fNoPerspectiveInterpolationExtensionString = + shaderCaps->fNoPerspectiveInterpolationSupport = true; + shaderCaps->fNoPerspectiveInterpolationExtensionString = "GL_NV_shader_noperspective_interpolation"; } } if (kGL_GrGLStandard == standard) { - glslCaps->fMultisampleInterpolationSupport = + shaderCaps->fMultisampleInterpolationSupport = ctxInfo.glslGeneration() >= k400_GrGLSLGeneration; } else { if (ctxInfo.glslGeneration() >= k320es_GrGLSLGeneration) { - glslCaps->fMultisampleInterpolationSupport = true; + shaderCaps->fMultisampleInterpolationSupport = true; } else if (ctxInfo.hasExtension("GL_OES_shader_multisample_interpolation")) { - glslCaps->fMultisampleInterpolationSupport = true; - glslCaps->fMultisampleInterpolationExtensionString = + shaderCaps->fMultisampleInterpolationSupport = true; + shaderCaps->fMultisampleInterpolationExtensionString = "GL_OES_shader_multisample_interpolation"; } } if (kGL_GrGLStandard == standard) { - glslCaps->fSampleVariablesSupport = ctxInfo.glslGeneration() >= k400_GrGLSLGeneration; + shaderCaps->fSampleVariablesSupport = ctxInfo.glslGeneration() >= k400_GrGLSLGeneration; } else { if (ctxInfo.glslGeneration() >= k320es_GrGLSLGeneration) { - glslCaps->fSampleVariablesSupport = true; + shaderCaps->fSampleVariablesSupport = true; } else if (ctxInfo.hasExtension("GL_OES_sample_variables")) { - glslCaps->fSampleVariablesSupport = true; - glslCaps->fSampleVariablesExtensionString = "GL_OES_sample_variables"; + shaderCaps->fSampleVariablesSupport = true; + shaderCaps->fSampleVariablesExtensionString = "GL_OES_sample_variables"; } } - if (glslCaps->fSampleVariablesSupport && + if (shaderCaps->fSampleVariablesSupport && ctxInfo.hasExtension("GL_NV_sample_mask_override_coverage")) { // Pre-361 NVIDIA has a bug with NV_sample_mask_override_coverage. - glslCaps->fSampleMaskOverrideCoverageSupport = + shaderCaps->fSampleMaskOverrideCoverageSupport = kNVIDIA_GrGLDriver != ctxInfo.driver() || ctxInfo.driverVersion() >= GR_GL_DRIVER_VER(361,00); } // Adreno GPUs have a tendency to drop tiles when there is a divide-by-zero in a shader - glslCaps->fDropsTileOnZeroDivide = kQualcomm_GrGLVendor == ctxInfo.vendor(); + shaderCaps->fDropsTileOnZeroDivide = kQualcomm_GrGLVendor == ctxInfo.vendor(); // On the NexusS and GalaxyNexus, the use of 'any' causes the compilation error "Calls to any // function that may require a gradient calculation inside a conditional block may return // undefined results". This appears to be an issue with the 'any' call since even the simple // "result=black; if (any()) result=white;" code fails to compile. This issue comes into play // from our GrTextureDomain processor. - glslCaps->fCanUseAnyFunctionInShader = kImagination_GrGLVendor != ctxInfo.vendor(); + shaderCaps->fCanUseAnyFunctionInShader = kImagination_GrGLVendor != ctxInfo.vendor(); - glslCaps->fVersionDeclString = get_glsl_version_decl_string(standard, glslCaps->fGLSLGeneration, - fIsCoreProfile); + shaderCaps->fVersionDeclString = get_glsl_version_decl_string(standard, + shaderCaps->fGLSLGeneration, + fIsCoreProfile); - if (kGLES_GrGLStandard == standard && k110_GrGLSLGeneration == glslCaps->fGLSLGeneration) { - glslCaps->fShaderDerivativeExtensionString = "GL_OES_standard_derivatives"; + if (kGLES_GrGLStandard == standard && k110_GrGLSLGeneration == shaderCaps->fGLSLGeneration) { + shaderCaps->fShaderDerivativeExtensionString = "GL_OES_standard_derivatives"; } // Frag Coords Convention support is not part of ES @@ -749,52 +805,52 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo) { kGLES_GrGLStandard != standard && (ctxInfo.glslGeneration() >= k150_GrGLSLGeneration || ctxInfo.hasExtension("GL_ARB_fragment_coord_conventions"))) { - glslCaps->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions"; + shaderCaps->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions"; } if (kGLES_GrGLStandard == standard) { - glslCaps->fSecondaryOutputExtensionString = "GL_EXT_blend_func_extended"; + shaderCaps->fSecondaryOutputExtensionString = "GL_EXT_blend_func_extended"; } if (ctxInfo.hasExtension("GL_OES_EGL_image_external")) { if (ctxInfo.glslGeneration() == k110_GrGLSLGeneration) { - glslCaps->fExternalTextureSupport = true; + shaderCaps->fExternalTextureSupport = true; } else if (ctxInfo.hasExtension("GL_OES_EGL_image_external_essl3") || ctxInfo.hasExtension("OES_EGL_image_external_essl3")) { // At least one driver has been found that has this extension without the "GL_" prefix. - glslCaps->fExternalTextureSupport = true; + shaderCaps->fExternalTextureSupport = true; } } - if (glslCaps->fExternalTextureSupport) { + if (shaderCaps->fExternalTextureSupport) { if (ctxInfo.glslGeneration() == k110_GrGLSLGeneration) { - glslCaps->fExternalTextureExtensionString = "GL_OES_EGL_image_external"; + shaderCaps->fExternalTextureExtensionString = "GL_OES_EGL_image_external"; } else { - glslCaps->fExternalTextureExtensionString = "GL_OES_EGL_image_external_essl3"; + shaderCaps->fExternalTextureExtensionString = "GL_OES_EGL_image_external_essl3"; } } if (kGL_GrGLStandard == standard) { - glslCaps->fTexelFetchSupport = ctxInfo.glslGeneration() >= k130_GrGLSLGeneration; + shaderCaps->fTexelFetchSupport = ctxInfo.glslGeneration() >= k130_GrGLSLGeneration; } else { - glslCaps->fTexelFetchSupport = + shaderCaps->fTexelFetchSupport = ctxInfo.glslGeneration() >= k330_GrGLSLGeneration; // We use this value for GLSL ES 3.0. } - if (glslCaps->fTexelFetchSupport) { + if (shaderCaps->fTexelFetchSupport) { if (kGL_GrGLStandard == standard) { - glslCaps->fTexelBufferSupport = ctxInfo.version() >= GR_GL_VER(3, 1) && + shaderCaps->fTexelBufferSupport = ctxInfo.version() >= GR_GL_VER(3, 1) && ctxInfo.glslGeneration() >= k330_GrGLSLGeneration; } else { if (ctxInfo.version() >= GR_GL_VER(3, 2) && ctxInfo.glslGeneration() >= k320es_GrGLSLGeneration) { - glslCaps->fTexelBufferSupport = true; + shaderCaps->fTexelBufferSupport = true; } else if (ctxInfo.hasExtension("GL_OES_texture_buffer")) { - glslCaps->fTexelBufferSupport = true; - glslCaps->fTexelBufferExtensionString = "GL_OES_texture_buffer"; + shaderCaps->fTexelBufferSupport = true; + shaderCaps->fTexelBufferExtensionString = "GL_OES_texture_buffer"; } else if (ctxInfo.hasExtension("GL_EXT_texture_buffer")) { - glslCaps->fTexelBufferSupport = true; - glslCaps->fTexelBufferExtensionString = "GL_EXT_texture_buffer"; + shaderCaps->fTexelBufferSupport = true; + shaderCaps->fTexelBufferExtensionString = "GL_EXT_texture_buffer"; } } } @@ -802,21 +858,28 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo) { // The Tegra3 compiler will sometimes never return if we have min(abs(x), 1.0), so we must do // the abs first in a separate expression. if (kTegra3_GrGLRenderer == ctxInfo.renderer()) { - glslCaps->fCanUseMinAndAbsTogether = false; + shaderCaps->fCanUseMinAndAbsTogether = false; } // On Intel GPU there is an issue where it reads the second argument to atan "- %s.x" as an int // thus must us -1.0 * %s.x to work correctly if (kIntel_GrGLVendor == ctxInfo.vendor()) { - glslCaps->fMustForceNegatedAtanParamToFloat = true; + shaderCaps->fMustForceNegatedAtanParamToFloat = true; } // On Adreno devices with framebuffer fetch support, there is a bug where they always return // the original dst color when reading the outColor even after being written to. By using a // local outColor we can work around this bug. - if (glslCaps->fFBFetchSupport && kQualcomm_GrGLVendor == ctxInfo.vendor()) { - glslCaps->fRequiresLocalOutputColorForFBFetch = true; + if (shaderCaps->fFBFetchSupport && kQualcomm_GrGLVendor == ctxInfo.vendor()) { + shaderCaps->fRequiresLocalOutputColorForFBFetch = true; } + +#ifdef SK_BUILD_FOR_MAC + // On at least some MacBooks, geometry shaders fall apart if we use more than one invocation. To + // work around this, we always use a single invocation and wrap the shader in a loop. The long- + // term plan for this WAR is for it to eventually be baked into SkSL. + shaderCaps->fMustImplementGSInvocationsWithLoop = true; +#endif } bool GrGLCaps::hasPathRenderingSupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { @@ -852,19 +915,24 @@ bool GrGLCaps::hasPathRenderingSupport(const GrGLContextInfo& ctxInfo, const GrG return true; } -bool GrGLCaps::readPixelsSupported(GrPixelConfig rtConfig, +bool GrGLCaps::readPixelsSupported(GrPixelConfig surfaceConfig, GrPixelConfig readConfig, std::function getIntegerv, - std::function bindRenderTarget) const { - // If it's not possible to even have a render target of rtConfig then read pixels is + std::function bindRenderTarget, + std::function unbindRenderTarget) const { + // If it's not possible to even have a color attachment of surfaceConfig then read pixels is // not supported regardless of readConfig. - if (!this->isConfigRenderable(rtConfig, false)) { + if (!this->canConfigBeFBOColorAttachment(surfaceConfig)) { + return false; + } + + if (GrPixelConfigIsSint(surfaceConfig) != GrPixelConfigIsSint(readConfig)) { return false; } GrGLenum readFormat; GrGLenum readType; - if (!this->getReadPixelsFormat(rtConfig, readConfig, &readFormat, &readType)) { + if (!this->getReadPixelsFormat(surfaceConfig, readConfig, &readFormat, &readType)) { return false; } @@ -873,8 +941,12 @@ bool GrGLCaps::readPixelsSupported(GrPixelConfig rtConfig, // the manual (https://www.opengl.org/sdk/docs/man/) says only these formats are allowed: // GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL, GL_RED, GL_GREEN, GL_BLUE, // GL_RGB, GL_BGR, GL_RGBA, and GL_BGRA. We check for the subset that we would use. - if (readFormat != GR_GL_RED && readFormat != GR_GL_RGB && readFormat != GR_GL_RGBA && - readFormat != GR_GL_BGRA) { + // The manual does not seem to fully match the spec as the spec allows integer formats + // when the bound color buffer is an integer buffer. It doesn't specify which integer + // formats are allowed, so perhaps all of them are. We only use GL_RGBA_INTEGER currently. + if (readFormat != GR_GL_RED && readFormat != GR_GL_RG && readFormat != GR_GL_RGB && + readFormat != GR_GL_RGBA && readFormat != GR_GL_BGRA && + readFormat != GR_GL_RGBA_INTEGER) { return false; } // There is also a set of allowed types, but all the types we use are in the set: @@ -889,21 +961,27 @@ bool GrGLCaps::readPixelsSupported(GrPixelConfig rtConfig, } // See Section 16.1.2 in the ES 3.2 specification. - - if (kNormalizedFixedPoint_FormatType == fConfigTable[rtConfig].fFormatType) { - if (GR_GL_RGBA == readFormat && GR_GL_UNSIGNED_BYTE == readType) { - return true; - } - } else { - SkASSERT(kFloat_FormatType == fConfigTable[rtConfig].fFormatType); - if (GR_GL_RGBA == readFormat && GR_GL_FLOAT == readType) { - return true; - } + switch (fConfigTable[surfaceConfig].fFormatType) { + case kNormalizedFixedPoint_FormatType: + if (GR_GL_RGBA == readFormat && GR_GL_UNSIGNED_BYTE == readType) { + return true; + } + break; + case kInteger_FormatType: + if (GR_GL_RGBA_INTEGER == readFormat && GR_GL_INT == readType) { + return true; + } + break; + case kFloat_FormatType: + if (GR_GL_RGBA == readFormat && GR_GL_FLOAT == readType) { + return true; + } + break; } - if (0 == fConfigTable[rtConfig].fSecondReadPixelsFormat.fFormat) { + if (0 == fConfigTable[surfaceConfig].fSecondReadPixelsFormat.fFormat) { ReadPixelsFormat* rpFormat = - const_cast(&fConfigTable[rtConfig].fSecondReadPixelsFormat); + const_cast(&fConfigTable[surfaceConfig].fSecondReadPixelsFormat); GrGLint format = 0, type = 0; if (!bindRenderTarget()) { return false; @@ -912,15 +990,14 @@ bool GrGLCaps::readPixelsSupported(GrPixelConfig rtConfig, getIntegerv(GR_GL_IMPLEMENTATION_COLOR_READ_TYPE, &type); rpFormat->fFormat = format; rpFormat->fType = type; + unbindRenderTarget(); } - return fConfigTable[rtConfig].fSecondReadPixelsFormat.fFormat == readFormat && - fConfigTable[rtConfig].fSecondReadPixelsFormat.fType == readType; + return fConfigTable[surfaceConfig].fSecondReadPixelsFormat.fFormat == readFormat && + fConfigTable[surfaceConfig].fSecondReadPixelsFormat.fType == readType; } void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { - - fMSFBOType = kNone_MSFBOType; if (kGL_GrGLStandard != ctxInfo.standard()) { // We prefer the EXT/IMG extension over ES3 MSAA because we've observed // ES3 driver bugs on at least one device with a tiled GPU (N10). @@ -930,12 +1007,10 @@ void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterfa fMSFBOType = kES_IMG_MsToTexture_MSFBOType; } else if (fUsesMixedSamples) { fMSFBOType = kMixedSamples_MSFBOType; - } else if (ctxInfo.version() >= GR_GL_VER(3,0)) { - fMSFBOType = GrGLCaps::kES_3_0_MSFBOType; - } else if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample")) { - // chrome's extension is equivalent to the EXT msaa - // and fbo_blit extensions. - fMSFBOType = kDesktop_EXT_MSFBOType; + } else if (ctxInfo.version() >= GR_GL_VER(3,0) || + ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample") || + ctxInfo.hasExtension("GL_ANGLE_framebuffer_multisample")) { + fMSFBOType = kStandard_MSFBOType; } else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) { fMSFBOType = kES_Apple_MSFBOType; } @@ -943,34 +1018,42 @@ void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterfa // Above determined the preferred MSAA approach, now decide whether glBlitFramebuffer // is available. if (ctxInfo.version() >= GR_GL_VER(3, 0)) { - fBlitFramebufferSupport = kFull_BlitFramebufferSupport; - } else if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample")) { + fBlitFramebufferFlags = kNoFormatConversionForMSAASrc_BlitFramebufferFlag | + kNoMSAADst_BlitFramebufferFlag | + kRectsMustMatchForMSAASrc_BlitFramebufferFlag; + } else if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample") || + ctxInfo.hasExtension("GL_ANGLE_framebuffer_blit")) { // The CHROMIUM extension uses the ANGLE version of glBlitFramebuffer and includes its // limitations. - fBlitFramebufferSupport = kNoScalingNoMirroring_BlitFramebufferSupport; + fBlitFramebufferFlags = kNoScalingOrMirroring_BlitFramebufferFlag | + kResolveMustBeFull_BlitFrambufferFlag | + kNoMSAADst_BlitFramebufferFlag | + kNoFormatConversion_BlitFramebufferFlag | + kRectsMustMatchForMSAASrc_BlitFramebufferFlag; } } else { if (fUsesMixedSamples) { fMSFBOType = kMixedSamples_MSFBOType; - fBlitFramebufferSupport = kFull_BlitFramebufferSupport; - } else if ((ctxInfo.version() >= GR_GL_VER(3,0)) || - ctxInfo.hasExtension("GL_ARB_framebuffer_object")) { - fMSFBOType = GrGLCaps::kDesktop_ARB_MSFBOType; - fBlitFramebufferSupport = kFull_BlitFramebufferSupport; + fBlitFramebufferFlags = 0; + } else if (ctxInfo.version() >= GR_GL_VER(3,0) || + ctxInfo.hasExtension("GL_ARB_framebuffer_object")) { + fMSFBOType = kStandard_MSFBOType; + fBlitFramebufferFlags = 0; } else if (ctxInfo.hasExtension("GL_EXT_framebuffer_multisample") && ctxInfo.hasExtension("GL_EXT_framebuffer_blit")) { - fMSFBOType = GrGLCaps::kDesktop_EXT_MSFBOType; - fBlitFramebufferSupport = kFull_BlitFramebufferSupport; + fMSFBOType = kEXT_MSFBOType; + fBlitFramebufferFlags = 0; } } } void GrGLCaps::initBlendEqationSupport(const GrGLContextInfo& ctxInfo) { - GrGLSLCaps* glslCaps = static_cast(fShaderCaps.get()); + GrShaderCaps* shaderCaps = static_cast(fShaderCaps.get()); // Disabling advanced blend on various platforms with major known issues. We also block Chrome // for now until its own blacklists can be updated. if (kAdreno4xx_GrGLRenderer == ctxInfo.renderer() || + kAdreno5xx_GrGLRenderer == ctxInfo.renderer() || kIntel_GrGLDriver == ctxInfo.driver() || kChromium_GrGLDriver == ctxInfo.driver()) { return; @@ -978,20 +1061,20 @@ void GrGLCaps::initBlendEqationSupport(const GrGLContextInfo& ctxInfo) { if (ctxInfo.hasExtension("GL_NV_blend_equation_advanced_coherent")) { fBlendEquationSupport = kAdvancedCoherent_BlendEquationSupport; - glslCaps->fAdvBlendEqInteraction = GrGLSLCaps::kAutomatic_AdvBlendEqInteraction; + shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kAutomatic_AdvBlendEqInteraction; } else if (ctxInfo.hasExtension("GL_KHR_blend_equation_advanced_coherent")) { fBlendEquationSupport = kAdvancedCoherent_BlendEquationSupport; - glslCaps->fAdvBlendEqInteraction = GrGLSLCaps::kGeneralEnable_AdvBlendEqInteraction; + shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kGeneralEnable_AdvBlendEqInteraction; } else if (kNVIDIA_GrGLDriver == ctxInfo.driver() && ctxInfo.driverVersion() < GR_GL_DRIVER_VER(337,00)) { // Non-coherent advanced blend has an issue on NVIDIA pre 337.00. return; } else if (ctxInfo.hasExtension("GL_NV_blend_equation_advanced")) { fBlendEquationSupport = kAdvanced_BlendEquationSupport; - glslCaps->fAdvBlendEqInteraction = GrGLSLCaps::kAutomatic_AdvBlendEqInteraction; + shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kAutomatic_AdvBlendEqInteraction; } else if (ctxInfo.hasExtension("GL_KHR_blend_equation_advanced")) { fBlendEquationSupport = kAdvanced_BlendEquationSupport; - glslCaps->fAdvBlendEqInteraction = GrGLSLCaps::kGeneralEnable_AdvBlendEqInteraction; + shaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kGeneralEnable_AdvBlendEqInteraction; // TODO: Use kSpecificEnables_AdvBlendEqInteraction if "blend_support_all_equations" is // slow on a particular platform. } else { @@ -1082,22 +1165,20 @@ SkString GrGLCaps::dump() const { static const char* kMSFBOExtStr[] = { "None", - "ARB", "EXT", - "ES 3.0", + "Standard", "Apple", "IMG MS To Texture", "EXT MS To Texture", "MixedSamples", }; GR_STATIC_ASSERT(0 == kNone_MSFBOType); - GR_STATIC_ASSERT(1 == kDesktop_ARB_MSFBOType); - GR_STATIC_ASSERT(2 == kDesktop_EXT_MSFBOType); - GR_STATIC_ASSERT(3 == kES_3_0_MSFBOType); - GR_STATIC_ASSERT(4 == kES_Apple_MSFBOType); - GR_STATIC_ASSERT(5 == kES_IMG_MsToTexture_MSFBOType); - GR_STATIC_ASSERT(6 == kES_EXT_MsToTexture_MSFBOType); - GR_STATIC_ASSERT(7 == kMixedSamples_MSFBOType); + GR_STATIC_ASSERT(1 == kEXT_MSFBOType); + GR_STATIC_ASSERT(2 == kStandard_MSFBOType); + GR_STATIC_ASSERT(3 == kES_Apple_MSFBOType); + GR_STATIC_ASSERT(4 == kES_IMG_MsToTexture_MSFBOType); + GR_STATIC_ASSERT(5 == kES_EXT_MsToTexture_MSFBOType); + GR_STATIC_ASSERT(6 == kMixedSamples_MSFBOType); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kMSFBOExtStr) == kLast_MSFBOType + 1); static const char* kInvalidateFBTypeStr[] = { @@ -1177,9 +1258,10 @@ static GrGLenum precision_to_gl_float_type(GrSLPrecision p) { return GR_GL_MEDIUM_FLOAT; case kHigh_GrSLPrecision: return GR_GL_HIGH_FLOAT; + default: + SkFAIL("Unexpected precision type."); + return -1; } - SkFAIL("Unknown precision."); - return -1; } static GrGLenum shader_type_to_gl_shader(GrShaderType type) { @@ -1197,7 +1279,7 @@ static GrGLenum shader_type_to_gl_shader(GrShaderType type) { void GrGLCaps::initShaderPrecisionTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* intf, - GrGLSLCaps* glslCaps) { + GrShaderCaps* shaderCaps) { if (kGLES_GrGLStandard == ctxInfo.standard() || ctxInfo.version() >= GR_GL_VER(4, 1) || ctxInfo.hasExtension("GL_ARB_ES2_compatibility")) { for (int s = 0; s < kGrShaderTypeCount; ++s) { @@ -1205,7 +1287,7 @@ void GrGLCaps::initShaderPrecisionTable(const GrGLContextInfo& ctxInfo, GrShaderType shaderType = static_cast(s); GrGLenum glShader = shader_type_to_gl_shader(shaderType); GrShaderCaps::PrecisionInfo* first = nullptr; - glslCaps->fShaderPrecisionVaries = false; + shaderCaps->fShaderPrecisionVaries = false; for (int p = 0; p < kGrSLPrecisionCount; ++p) { GrSLPrecision precision = static_cast(p); GrGLenum glPrecision = precision_to_gl_float_type(precision); @@ -1213,15 +1295,15 @@ void GrGLCaps::initShaderPrecisionTable(const GrGLContextInfo& ctxInfo, GrGLint bits; GR_GL_GetShaderPrecisionFormat(intf, glShader, glPrecision, range, &bits); if (bits) { - glslCaps->fFloatPrecisions[s][p].fLogRangeLow = range[0]; - glslCaps->fFloatPrecisions[s][p].fLogRangeHigh = range[1]; - glslCaps->fFloatPrecisions[s][p].fBits = bits; + shaderCaps->fFloatPrecisions[s][p].fLogRangeLow = range[0]; + shaderCaps->fFloatPrecisions[s][p].fLogRangeHigh = range[1]; + shaderCaps->fFloatPrecisions[s][p].fBits = bits; if (!first) { - first = &glslCaps->fFloatPrecisions[s][p]; + first = &shaderCaps->fFloatPrecisions[s][p]; } - else if (!glslCaps->fShaderPrecisionVaries) { - glslCaps->fShaderPrecisionVaries = - (*first != glslCaps->fFloatPrecisions[s][p]); + else if (!shaderCaps->fShaderPrecisionVaries) { + shaderCaps->fShaderPrecisionVaries = + (*first != shaderCaps->fFloatPrecisions[s][p]); } } } @@ -1230,13 +1312,13 @@ void GrGLCaps::initShaderPrecisionTable(const GrGLContextInfo& ctxInfo, } else { // We're on a desktop GL that doesn't have precision info. Assume they're all 32bit float. - glslCaps->fShaderPrecisionVaries = false; + shaderCaps->fShaderPrecisionVaries = false; for (int s = 0; s < kGrShaderTypeCount; ++s) { if (kGeometry_GrShaderType != s) { for (int p = 0; p < kGrSLPrecisionCount; ++p) { - glslCaps->fFloatPrecisions[s][p].fLogRangeLow = 127; - glslCaps->fFloatPrecisions[s][p].fLogRangeHigh = 127; - glslCaps->fFloatPrecisions[s][p].fBits = 23; + shaderCaps->fFloatPrecisions[s][p].fLogRangeLow = 127; + shaderCaps->fFloatPrecisions[s][p].fLogRangeHigh = 127; + shaderCaps->fFloatPrecisions[s][p].fBits = 23; } } } @@ -1245,13 +1327,13 @@ void GrGLCaps::initShaderPrecisionTable(const GrGLContextInfo& ctxInfo, // the same as the vertex shader. Only fragment shaders were ever allowed to omit support for // highp. GS was added after GetShaderPrecisionFormat was added to the list of features that // are recommended against. - if (glslCaps->fGeometryShaderSupport) { + if (shaderCaps->fGeometryShaderSupport) { for (int p = 0; p < kGrSLPrecisionCount; ++p) { - glslCaps->fFloatPrecisions[kGeometry_GrShaderType][p] = - glslCaps->fFloatPrecisions[kVertex_GrShaderType][p]; + shaderCaps->fFloatPrecisions[kGeometry_GrShaderType][p] = + shaderCaps->fFloatPrecisions[kVertex_GrShaderType][p]; } } - glslCaps->initSamplerPrecisionTable(); + shaderCaps->initSamplerPrecisionTable(); } bool GrGLCaps::bgraIsInternalFormat() const { @@ -1329,8 +1411,9 @@ bool GrGLCaps::getExternalFormat(GrPixelConfig surfaceConfig, GrPixelConfig memo return true; } -void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli, - GrGLSLCaps* glslCaps) { +void GrGLCaps::initConfigTable(const GrContextOptions& contextOptions, + const GrGLContextInfo& ctxInfo, const GrGLInterface* gli, + GrShaderCaps* shaderCaps) { /* Comments on renderability of configs on various GL versions. OpenGL < 3.0: @@ -1400,11 +1483,12 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa ES 3.2 Adds R16F, RG16F, RGBA16F, R32F, RG32F, RGBA32F, R11F_G11F_B10F. */ - uint32_t allRenderFlags = ConfigInfo::kRenderable_Flag; + uint32_t nonMSAARenderFlags = ConfigInfo::kRenderable_Flag | + ConfigInfo::kFBOColorAttachment_Flag; + uint32_t allRenderFlags = nonMSAARenderFlags; if (kNone_MSFBOType != fMSFBOType) { allRenderFlags |= ConfigInfo::kRenderableWithMSAA_Flag; } - GrGLStandard standard = ctxInfo.standard(); GrGLVersion version = ctxInfo.version(); @@ -1415,10 +1499,8 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa ctxInfo.hasExtension("GL_ARB_texture_storage") || ctxInfo.hasExtension("GL_EXT_texture_storage"); } else { - // Qualcomm Adreno drivers appear to have issues with texture storage. - texStorageSupported = (version >= GR_GL_VER(3,0) && - kQualcomm_GrGLVendor != ctxInfo.vendor()) && - ctxInfo.hasExtension("GL_EXT_texture_storage"); + texStorageSupported = version >= GR_GL_VER(3,0) || + ctxInfo.hasExtension("GL_EXT_texture_storage"); } // TODO: remove after command buffer supports full ES 3.0 @@ -1487,7 +1569,7 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa } } else if (ctxInfo.hasExtension("GL_EXT_texture_format_BGRA8888")) { fConfigTable[kBGRA_8888_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag | - ConfigInfo::kRenderable_Flag; + nonMSAARenderFlags; if (ctxInfo.hasExtension("GL_CHROMIUM_renderbuffer_format_BGRA8888") && (this->usesMSAARenderBuffers() || this->fMSFBOType == kMixedSamples_MSFBOType)) { fConfigTable[kBGRA_8888_GrPixelConfig].fFlags |= @@ -1516,19 +1598,37 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa fSRGBWriteControl = true; } } else { - // See https://bug.skia.org/4148 for PowerVR issue. - fSRGBSupport = kPowerVRRogue_GrGLRenderer != ctxInfo.renderer() && - (ctxInfo.version() >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_EXT_sRGB")); + fSRGBSupport = ctxInfo.version() >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_EXT_sRGB"); +#if defined(SK_CPU_X86) + if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) { + // NexusPlayer has strange bugs with sRGB (skbug.com/4148). This is a targeted fix to + // blacklist that device (and any others that might be sharing the same driver). + fSRGBSupport = false; + } +#endif // ES through 3.1 requires EXT_srgb_write_control to support toggling // sRGB writing for destinations. // See https://bug.skia.org/5329 for Adreno4xx issue. fSRGBWriteControl = kAdreno4xx_GrGLRenderer != ctxInfo.renderer() && ctxInfo.hasExtension("GL_EXT_sRGB_write_control"); } - if (!ctxInfo.hasExtension("GL_EXT_texture_sRGB_decode")) { - // To support "legacy" L32 mode, we require the ability to turn off sRGB decode: + if (contextOptions.fRequireDecodeDisableForSRGB && !fSRGBDecodeDisableSupport) { + // To support "legacy" L32 mode, we require the ability to turn off sRGB decode. Clients + // can opt-out of that requirement, if they intend to always do linear blending. fSRGBSupport = false; } + + // This is very conservative, if we're on a platform where N32 is BGRA, and using ES, disable + // all sRGB support. Too much code relies on creating surfaces with N32 + sRGB colorspace, + // and sBGRA is basically impossible to support on any version of ES (with our current code). + // In particular, ES2 doesn't support sBGRA at all, and even in ES3, there is no valid pair + // of formats that can be used for TexImage calls to upload BGRA data to sRGBA (which is what + // we *have* to use as the internal format, because sBGRA doesn't exist). This primarily + // affects Windows. + if (kSkia8888_GrPixelConfig == kBGRA_8888_GrPixelConfig && kGLES_GrGLStandard == standard) { + fSRGBSupport = false; + } + fConfigTable[kSRGBA_8888_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_SRGB_ALPHA; fConfigTable[kSRGBA_8888_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_SRGB8_ALPHA8; // GL does not do srgb<->rgb conversions when transferring between cpu and gpu. Thus, the @@ -1566,6 +1666,33 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa } fConfigTable[kSBGRA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + bool hasIntegerTextures; + if (standard == kGL_GrGLStandard) { + hasIntegerTextures = version >= GR_GL_VER(3, 0) || + ctxInfo.hasExtension("GL_EXT_texture_integer"); + } else { + hasIntegerTextures = (version >= GR_GL_VER(3, 0)); + } + // We may have limited GLSL to an earlier version that doesn't have integer sampler types. + if (ctxInfo.glslGeneration() == k110_GrGLSLGeneration) { + hasIntegerTextures = false; + } + fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA_INTEGER; + fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA8I; + fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = GR_GL_RGBA_INTEGER; + fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFormats.fExternalType = GR_GL_BYTE; + fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFormatType = kInteger_FormatType; + // We currently only support using integer textures as srcs, not for rendering (even though GL + // allows it). + if (hasIntegerTextures) { + fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag | + ConfigInfo::kFBOColorAttachment_Flag; + if (texStorageSupported) { + fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFlags |= + ConfigInfo::kCanUseTexStorage_Flag; + } + } + fConfigTable[kRGB_565_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGB; if (this->ES2CompatibilitySupport()) { fConfigTable[kRGB_565_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGB565; @@ -1578,7 +1705,7 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa fConfigTable[kRGB_565_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; fConfigTable[kRGB_565_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; if (kGL_GrGLStandard == standard) { - if (version >= GR_GL_VER(4, 2) || ctxInfo.hasExtension("GL_ES2_compatibility")) { + if (version >= GR_GL_VER(4, 2) || ctxInfo.hasExtension("GL_ARB_ES2_compatibility")) { fConfigTable[kRGB_565_GrPixelConfig].fFlags |= allRenderFlags; } } else { @@ -1615,6 +1742,9 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa } fConfigTable[kRGBA_4444_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fExternalType = GR_GL_UNSIGNED_BYTE; + fConfigTable[kAlpha_8_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + fConfigTable[kAlpha_8_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; if (this->textureRedSupport()) { fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RED; fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_R8; @@ -1631,13 +1761,9 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa GR_GL_ALPHA; fConfigTable[kAlpha_8_GrPixelConfig].fSwizzle = GrSwizzle::AAAA(); } - fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fExternalType = GR_GL_UNSIGNED_BYTE; - fConfigTable[kAlpha_8_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; - fConfigTable[kAlpha_8_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; if (this->textureRedSupport() || - (kDesktop_ARB_MSFBOType == this->msFBOType() && - ctxInfo.renderer() != kOSMesa_GrGLRenderer)) { - // desktop ARB extension/3.0+ supports ALPHA8 as renderable. + (kStandard_MSFBOType == this->msFBOType() && ctxInfo.renderer() != kOSMesa_GrGLRenderer)) { + // OpenGL 3.0+ (and GL_ARB_framebuffer_object) supports ALPHA8 as renderable. // However, osmesa fails if it used even when GL_ARB_framebuffer_object is present. // Core profile removes ALPHA8 support, but we should have chosen R8 in that case. fConfigTable[kAlpha_8_GrPixelConfig].fFlags |= allRenderFlags; @@ -1646,6 +1772,39 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa fConfigTable[kAlpha_8_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag; } + fConfigTable[kGray_8_GrPixelConfig].fFormats.fExternalType = GR_GL_UNSIGNED_BYTE; + fConfigTable[kGray_8_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + fConfigTable[kGray_8_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + if (this->textureRedSupport()) { + fConfigTable[kGray_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RED; + fConfigTable[kGray_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_R8; + fConfigTable[kGray_8_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_RED; + fConfigTable[kGray_8_GrPixelConfig].fSwizzle = GrSwizzle::RRRA(); + if (texelBufferSupport) { + fConfigTable[kGray_8_GrPixelConfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag; + } + } else { + fConfigTable[kGray_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_LUMINANCE; + fConfigTable[kGray_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_LUMINANCE8; + fConfigTable[kGray_8_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_LUMINANCE; + fConfigTable[kGray_8_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + } +#if 0 // Leaving Gray8 as non-renderable, to keep things simple and match raster + if (this->textureRedSupport() || + (kDesktop_ARB_MSFBOType == this->msFBOType() && + ctxInfo.renderer() != kOSMesa_GrGLRenderer)) { + // desktop ARB extension/3.0+ supports LUMINANCE8 as renderable. + // However, osmesa fails if it used even when GL_ARB_framebuffer_object is present. + // Core profile removes LUMINANCE8 support, but we should have chosen R8 in that case. + fConfigTable[kGray_8_GrPixelConfig].fFlags |= allRenderFlags; + } +#endif + if (texStorageSupported) { + fConfigTable[kGray_8_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag; + } + // Check for [half] floating point texture support // NOTE: We disallow floating point textures on ES devices if linear filtering modes are not // supported. This is for simplicity, but a more granular approach is possible. Coincidentally, @@ -1653,8 +1812,7 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa bool hasFPTextures = false; bool hasHalfFPTextures = false; // for now we don't support floating point MSAA on ES - uint32_t fpRenderFlags = (kGL_GrGLStandard == standard) ? - allRenderFlags : (uint32_t)ConfigInfo::kRenderable_Flag; + uint32_t fpRenderFlags = (kGL_GrGLStandard == standard) ? allRenderFlags : nonMSAARenderFlags; if (kGL_GrGLStandard == standard) { if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_texture_float")) { @@ -1677,28 +1835,31 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa } } - fConfigTable[kRGBA_float_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA; - fConfigTable[kRGBA_float_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA32F; - fConfigTable[kRGBA_float_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = - GR_GL_RGBA; - fConfigTable[kRGBA_float_GrPixelConfig].fFormats.fExternalType = GR_GL_FLOAT; - fConfigTable[kRGBA_float_GrPixelConfig].fFormatType = kFloat_FormatType; - if (hasFPTextures) { - fConfigTable[kRGBA_float_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; - // For now we only enable rendering to float on desktop, because on ES we'd have to solve - // many precision issues and no clients actually want this yet. - if (kGL_GrGLStandard == standard /* || version >= GR_GL_VER(3,2) || - ctxInfo.hasExtension("GL_EXT_color_buffer_float")*/) { - fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= fpRenderFlags; + for (auto fpconfig : {kRGBA_float_GrPixelConfig, kRG_float_GrPixelConfig}) { + const GrGLenum format = kRGBA_float_GrPixelConfig == fpconfig ? GR_GL_RGBA : GR_GL_RG; + fConfigTable[fpconfig].fFormats.fBaseInternalFormat = format; + fConfigTable[fpconfig].fFormats.fSizedInternalFormat = + kRGBA_float_GrPixelConfig == fpconfig ? GR_GL_RGBA32F : GR_GL_RG32F; + fConfigTable[fpconfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = format; + fConfigTable[fpconfig].fFormats.fExternalType = GR_GL_FLOAT; + fConfigTable[fpconfig].fFormatType = kFloat_FormatType; + if (hasFPTextures) { + fConfigTable[fpconfig].fFlags = ConfigInfo::kTextureable_Flag; + // For now we only enable rendering to float on desktop, because on ES we'd have to + // solve many precision issues and no clients actually want this yet. + if (kGL_GrGLStandard == standard /* || version >= GR_GL_VER(3,2) || + ctxInfo.hasExtension("GL_EXT_color_buffer_float")*/) { + fConfigTable[fpconfig].fFlags |= fpRenderFlags; + } } + if (texStorageSupported) { + fConfigTable[fpconfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag; + } + if (texelBufferSupport) { + fConfigTable[fpconfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag; + } + fConfigTable[fpconfig].fSwizzle = GrSwizzle::RGBA(); } - if (texStorageSupported) { - fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag; - } - if (texelBufferSupport) { - fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag; - } - fConfigTable[kRGBA_float_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); if (this->textureRedSupport()) { fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RED; @@ -1717,31 +1878,37 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa = GR_GL_ALPHA; fConfigTable[kAlpha_half_GrPixelConfig].fSwizzle = GrSwizzle::AAAA(); } - if (kGL_GrGLStandard == ctxInfo.standard() || ctxInfo.version() >= GR_GL_VER(3, 0)) { + // ANGLE always returns GL_HALF_FLOAT_OES for GL_IMPLEMENTATION_COLOR_READ_TYPE, even though + // ES3 would typically return GL_HALF_FLOAT. The correct fix is for us to respect the value + // returned when we query, but that turns into a bigger refactor, so just work around it. + if (kGL_GrGLStandard == ctxInfo.standard() || + (ctxInfo.version() >= GR_GL_VER(3, 0) && kANGLE_GrGLDriver != ctxInfo.driver())) { fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalType = GR_GL_HALF_FLOAT; } else { fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalType = GR_GL_HALF_FLOAT_OES; } fConfigTable[kAlpha_half_GrPixelConfig].fFormatType = kFloat_FormatType; + if (texStorageSupported) { + fConfigTable[kAlpha_half_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag; + } if (hasHalfFPTextures) { fConfigTable[kAlpha_half_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; // ES requires either 3.2 or the combination of EXT_color_buffer_half_float and support for // GL_RED internal format. - if (kGL_GrGLStandard == standard || version >= GR_GL_VER(3,2) || + if (kGL_GrGLStandard == standard || version >= GR_GL_VER(3, 2) || (this->textureRedSupport() && ctxInfo.hasExtension("GL_EXT_color_buffer_half_float"))) { fConfigTable[kAlpha_half_GrPixelConfig].fFlags |= fpRenderFlags; } } - if (texStorageSupported) { - fConfigTable[kAlpha_half_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag; - } fConfigTable[kRGBA_half_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA; fConfigTable[kRGBA_half_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA16F; fConfigTable[kRGBA_half_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = GR_GL_RGBA; - if (kGL_GrGLStandard == ctxInfo.standard() || ctxInfo.version() >= GR_GL_VER(3, 0)) { + // See comment above, re: ANGLE and ES3. + if (kGL_GrGLStandard == ctxInfo.standard() || + (ctxInfo.version() >= GR_GL_VER(3, 0) && kANGLE_GrGLDriver != ctxInfo.driver())) { fConfigTable[kRGBA_half_GrPixelConfig].fFormats.fExternalType = GR_GL_HALF_FLOAT; } else { fConfigTable[kRGBA_half_GrPixelConfig].fFormats.fExternalType = GR_GL_HALF_FLOAT_OES; @@ -1773,105 +1940,28 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa // No sized/unsized internal format distinction for compressed formats, no external format. // Below we set the external formats and types to 0. - - fConfigTable[kIndex_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_PALETTE8_RGBA8; - fConfigTable[kIndex_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_PALETTE8_RGBA8; - fConfigTable[kIndex_8_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; - fConfigTable[kIndex_8_GrPixelConfig].fFormats.fExternalType = 0; - fConfigTable[kIndex_8_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; - // Disable this for now, while we investigate https://bug.skia.org/4333 - if (false) { - // Check for 8-bit palette.. - GrGLint numFormats; - GR_GL_GetIntegerv(gli, GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats); - if (numFormats) { - SkAutoSTMalloc<10, GrGLint> formats(numFormats); - GR_GL_GetIntegerv(gli, GR_GL_COMPRESSED_TEXTURE_FORMATS, formats); - for (int i = 0; i < numFormats; ++i) { - if (GR_GL_PALETTE8_RGBA8 == formats[i]) { - fConfigTable[kIndex_8_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; - break; - } + { + fConfigTable[kETC1_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_COMPRESSED_ETC1_RGB8; + fConfigTable[kETC1_GrPixelConfig].fFormats.fSizedInternalFormat = + GR_GL_COMPRESSED_ETC1_RGB8; + fConfigTable[kETC1_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; + fConfigTable[kETC1_GrPixelConfig].fFormats.fExternalType = 0; + fConfigTable[kETC1_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + if (kGL_GrGLStandard == standard) { + if (version >= GR_GL_VER(4, 3) || ctxInfo.hasExtension("GL_ARB_ES3_compatibility")) { + fConfigTable[kETC1_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + } + } else { + if (version >= GR_GL_VER(3, 0) || + ctxInfo.hasExtension("GL_OES_compressed_ETC1_RGB8_texture") || + // ETC2 is a superset of ETC1, so we can just check for that, too. + (ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGB8_texture") && + ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGBA8_texture"))) { + fConfigTable[kETC1_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; } } + fConfigTable[kETC1_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); } - fConfigTable[kIndex_8_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); - - // May change the internal format based on extensions. - fConfigTable[kLATC_GrPixelConfig].fFormats.fBaseInternalFormat = - GR_GL_COMPRESSED_LUMINANCE_LATC1; - fConfigTable[kLATC_GrPixelConfig].fFormats.fSizedInternalFormat = - GR_GL_COMPRESSED_LUMINANCE_LATC1; - if (ctxInfo.hasExtension("GL_EXT_texture_compression_latc") || - ctxInfo.hasExtension("GL_NV_texture_compression_latc")) { - fConfigTable[kLATC_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; - } else if ((kGL_GrGLStandard == standard && version >= GR_GL_VER(3, 0)) || - ctxInfo.hasExtension("GL_EXT_texture_compression_rgtc") || - ctxInfo.hasExtension("GL_ARB_texture_compression_rgtc")) { - // RGTC is identical and available on OpenGL 3.0+ as well as with extensions - fConfigTable[kLATC_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; - fConfigTable[kLATC_GrPixelConfig].fFormats.fBaseInternalFormat = - GR_GL_COMPRESSED_RED_RGTC1; - fConfigTable[kLATC_GrPixelConfig].fFormats.fSizedInternalFormat = - GR_GL_COMPRESSED_RED_RGTC1; - } else if (ctxInfo.hasExtension("GL_AMD_compressed_3DC_texture")) { - fConfigTable[kLATC_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; - fConfigTable[kLATC_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_COMPRESSED_3DC_X; - fConfigTable[kLATC_GrPixelConfig].fFormats.fSizedInternalFormat = - GR_GL_COMPRESSED_3DC_X; - - } - fConfigTable[kLATC_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; - fConfigTable[kLATC_GrPixelConfig].fFormats.fExternalType = 0; - fConfigTable[kLATC_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; - fConfigTable[kLATC_GrPixelConfig].fSwizzle = GrSwizzle::RRRR(); - - fConfigTable[kETC1_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_COMPRESSED_ETC1_RGB8; - fConfigTable[kETC1_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_COMPRESSED_ETC1_RGB8; - fConfigTable[kETC1_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; - fConfigTable[kETC1_GrPixelConfig].fFormats.fExternalType = 0; - fConfigTable[kETC1_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; - if (kGL_GrGLStandard == standard) { - if (version >= GR_GL_VER(4, 3) || ctxInfo.hasExtension("GL_ARB_ES3_compatibility")) { - fConfigTable[kETC1_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; - } - } else { - if (version >= GR_GL_VER(3, 0) || - ctxInfo.hasExtension("GL_OES_compressed_ETC1_RGB8_texture") || - // ETC2 is a superset of ETC1, so we can just check for that, too. - (ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGB8_texture") && - ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGBA8_texture"))) { - fConfigTable[kETC1_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; - } - } - fConfigTable[kETC1_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); - - fConfigTable[kR11_EAC_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_COMPRESSED_R11_EAC; - fConfigTable[kR11_EAC_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_COMPRESSED_R11_EAC; - fConfigTable[kR11_EAC_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; - fConfigTable[kR11_EAC_GrPixelConfig].fFormats.fExternalType = 0; - fConfigTable[kR11_EAC_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; - // Check for R11_EAC. We don't support R11_EAC on desktop, as most cards default to - // decompressing the textures in the driver, and is generally slower. - if (kGLES_GrGLStandard == standard && version >= GR_GL_VER(3,0)) { - fConfigTable[kR11_EAC_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; - } - fConfigTable[kR11_EAC_GrPixelConfig].fSwizzle = GrSwizzle::RRRR(); - - fConfigTable[kASTC_12x12_GrPixelConfig].fFormats.fBaseInternalFormat = - GR_GL_COMPRESSED_RGBA_ASTC_12x12; - fConfigTable[kASTC_12x12_GrPixelConfig].fFormats.fSizedInternalFormat = - GR_GL_COMPRESSED_RGBA_ASTC_12x12; - fConfigTable[kASTC_12x12_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = - 0; - fConfigTable[kASTC_12x12_GrPixelConfig].fFormats.fExternalType = 0; - fConfigTable[kASTC_12x12_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; - if (ctxInfo.hasExtension("GL_KHR_texture_compression_astc_hdr") || - ctxInfo.hasExtension("GL_KHR_texture_compression_astc_ldr") || - ctxInfo.hasExtension("GL_OES_texture_compression_astc")) { - fConfigTable[kASTC_12x12_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; - } - fConfigTable[kASTC_12x12_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); // Bulk populate the texture internal/external formats here and then deal with exceptions below. @@ -1926,7 +2016,7 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa // swizzle into shader code. if (!this->textureSwizzleSupport()) { for (int i = 0; i < kGrPixelConfigCnt; ++i) { - glslCaps->fConfigTextureSwizzle[i] = fConfigTable[i].fSwizzle; + shaderCaps->fConfigTextureSwizzle[i] = fConfigTable[i].fSwizzle; } } @@ -1938,15 +2028,37 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa GrPixelConfig config = static_cast(i); if (GrPixelConfigIsAlphaOnly(config) && fConfigTable[i].fFormats.fBaseInternalFormat == GR_GL_RED) { - glslCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA(); + shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA(); } } } + // We currently only support images on rgba textures formats. We could add additional formats + // if desired. The shader builder would have to be updated to add swizzles where appropriate + // (e.g. where we use GL_RED textures to implement alpha configs). + if (this->shaderCaps()->imageLoadStoreSupport()) { + fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFlags |= + ConfigInfo::kCanUseAsImageStorage_Flag; + // In OpenGL ES a texture may only be used with BindImageTexture if it has been made + // immutable via TexStorage. We create non-integer textures as mutable textures using + // TexImage because we may lazily add MIP levels. Thus, on ES we currently disable image + // storage support for non-integer textures. + if (kGL_GrGLStandard == ctxInfo.standard()) { + fConfigTable[kRGBA_8888_GrPixelConfig].fFlags |= ConfigInfo::kCanUseAsImageStorage_Flag; + fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= + ConfigInfo::kCanUseAsImageStorage_Flag; + fConfigTable[kRGBA_half_GrPixelConfig].fFlags |= ConfigInfo::kCanUseAsImageStorage_Flag; + } + } + #ifdef SK_DEBUG // Make sure we initialized everything. ConfigInfo defaultEntry; for (int i = 0; i < kGrPixelConfigCnt; ++i) { + // Make sure we didn't set renderable and not blittable or renderable with msaa and not + // renderable. + SkASSERT(!((ConfigInfo::kRenderable_Flag) && !(ConfigInfo::kFBOColorAttachment_Flag))); + SkASSERT(!((ConfigInfo::kRenderableWithMSAA_Flag) && !(ConfigInfo::kRenderable_Flag))); SkASSERT(defaultEntry.fFormats.fBaseInternalFormat != fConfigTable[i].fFormats.fBaseInternalFormat); SkASSERT(defaultEntry.fFormats.fSizedInternalFormat != @@ -1960,6 +2072,93 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa #endif } +bool GrGLCaps::initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, + bool* rectsMustMatch, bool* disallowSubrect) const { + // By default, we don't require rects to match. + *rectsMustMatch = false; + + // By default, we allow subrects. + *disallowSubrect = false; + + // If the src is a texture, we can implement the blit as a draw assuming the config is + // renderable. + if (src->asTextureProxy() && this->isConfigRenderable(src->config(), false)) { + desc->fOrigin = kBottomLeft_GrSurfaceOrigin; + desc->fFlags = kRenderTarget_GrSurfaceFlag; + desc->fConfig = src->config(); + return true; + } + + { + // The only way we could see a non-GR_GL_TEXTURE_2D texture would be if it were + // wrapped. In that case the proxy would already be instantiated. + const GrTexture* srcTexture = src->priv().peekTexture(); + const GrGLTexture* glSrcTexture = static_cast(srcTexture); + if (glSrcTexture && glSrcTexture->target() != GR_GL_TEXTURE_2D) { + // Not supported for FBO blit or CopyTexSubImage + return false; + } + } + + // We look for opportunities to use CopyTexSubImage, or fbo blit. If neither are + // possible and we return false to fallback to creating a render target dst for render-to- + // texture. This code prefers CopyTexSubImage to fbo blit and avoids triggering temporary fbo + // creation. It isn't clear that avoiding temporary fbo creation is actually optimal. + GrSurfaceOrigin originForBlitFramebuffer = kDefault_GrSurfaceOrigin; + bool rectsMustMatchForBlitFramebuffer = false; + bool disallowSubrectForBlitFramebuffer = false; + if (src->numColorSamples() && + (this->blitFramebufferSupportFlags() & kResolveMustBeFull_BlitFrambufferFlag)) { + rectsMustMatchForBlitFramebuffer = true; + disallowSubrectForBlitFramebuffer = true; + // Mirroring causes rects to mismatch later, don't allow it. + originForBlitFramebuffer = src->origin(); + } else if (src->numColorSamples() && (this->blitFramebufferSupportFlags() & + kRectsMustMatchForMSAASrc_BlitFramebufferFlag)) { + rectsMustMatchForBlitFramebuffer = true; + // Mirroring causes rects to mismatch later, don't allow it. + originForBlitFramebuffer = src->origin(); + } else if (this->blitFramebufferSupportFlags() & kNoScalingOrMirroring_BlitFramebufferFlag) { + originForBlitFramebuffer = src->origin(); + } + + // Check for format issues with glCopyTexSubImage2D + if (this->bgraIsInternalFormat() && kBGRA_8888_GrPixelConfig == src->config()) { + // glCopyTexSubImage2D doesn't work with this config. If the bgra can be used with fbo blit + // then we set up for that, otherwise fail. + if (this->canConfigBeFBOColorAttachment(kBGRA_8888_GrPixelConfig)) { + desc->fOrigin = originForBlitFramebuffer; + desc->fConfig = kBGRA_8888_GrPixelConfig; + *rectsMustMatch = rectsMustMatchForBlitFramebuffer; + *disallowSubrect = disallowSubrectForBlitFramebuffer; + return true; + } + return false; + } + + { + bool srcIsMSAARenderbuffer = src->desc().fSampleCnt > 0 && this->usesMSAARenderBuffers(); + if (srcIsMSAARenderbuffer) { + // It's illegal to call CopyTexSubImage2D on a MSAA renderbuffer. Set up for FBO + // blit or fail. + if (this->canConfigBeFBOColorAttachment(src->config())) { + desc->fOrigin = originForBlitFramebuffer; + desc->fConfig = src->config(); + *rectsMustMatch = rectsMustMatchForBlitFramebuffer; + *disallowSubrect = disallowSubrectForBlitFramebuffer; + return true; + } + return false; + } + } + + // We'll do a CopyTexSubImage. Make the dst a plain old texture. + desc->fConfig = src->config(); + desc->fOrigin = src->origin(); + desc->fFlags = kNone_GrSurfaceFlags; + return true; +} + void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) { if (options.fEnableInstancedRendering) { fInstancedSupport = gr_instanced::GLInstancedRendering::CheckSupport(*this); diff --git a/gfx/skia/skia/src/gpu/gl/GrGLCaps.h b/gfx/skia/skia/src/gpu/gl/GrGLCaps.h index f0b09407aaf6..7439711c6dbe 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLCaps.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLCaps.h @@ -11,16 +11,15 @@ #include -#include "glsl/GrGLSL.h" #include "GrCaps.h" #include "GrGLStencilAttachment.h" #include "GrSwizzle.h" #include "SkChecksum.h" #include "SkTHash.h" #include "SkTArray.h" +#include "../private/GrGLSL.h" class GrGLContextInfo; -class GrGLSLCaps; class GrGLRenderTarget; /** @@ -42,17 +41,13 @@ public: */ kNone_MSFBOType = 0, /** - * GL3.0-style MSAA FBO (GL_ARB_framebuffer_object). + * OpenGL < 3.0 with GL_EXT_framebuffer_object. Doesn't allow rendering to ALPHA. */ - kDesktop_ARB_MSFBOType, + kEXT_MSFBOType, /** - * earlier GL_EXT_framebuffer* extensions + * OpenGL 3.0+, OpenGL ES 3.0+, and GL_ARB_framebuffer_object. */ - kDesktop_EXT_MSFBOType, - /** - * Similar to kDesktop_ARB but with additional restrictions on glBlitFramebuffer. - */ - kES_3_0_MSFBOType, + kStandard_MSFBOType, /** * GL_APPLE_framebuffer_multisample ES extension */ @@ -77,14 +72,14 @@ public: kLast_MSFBOType = kMixedSamples_MSFBOType }; - enum BlitFramebufferSupport { - kNone_BlitFramebufferSupport, - /** - * ANGLE exposes a limited blit framebuffer extension that does not allow for stretching - * or mirroring. - */ - kNoScalingNoMirroring_BlitFramebufferSupport, - kFull_BlitFramebufferSupport + enum BlitFramebufferFlags { + kNoSupport_BlitFramebufferFlag = 1 << 0, + kNoScalingOrMirroring_BlitFramebufferFlag = 1 << 1, + kResolveMustBeFull_BlitFrambufferFlag = 1 << 2, + kNoMSAADst_BlitFramebufferFlag = 1 << 3, + kNoFormatConversion_BlitFramebufferFlag = 1 << 4, + kNoFormatConversionForMSAASrc_BlitFramebufferFlag = 1 << 5, + kRectsMustMatchForMSAASrc_BlitFramebufferFlag = 1 << 6, }; enum InvalidateFBType { @@ -130,6 +125,12 @@ public: return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag); } } + bool canConfigBeImageStorage(GrPixelConfig config) const override { + return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kCanUseAsImageStorage_Flag); + } + bool canConfigBeFBOColorAttachment(GrPixelConfig config) const { + return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kFBOColorAttachment_Flag); + } bool isConfigTexSupportEnabled(GrPixelConfig config) const { return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kCanUseTexStorage_Flag); @@ -159,6 +160,11 @@ public: bool getRenderbufferFormat(GrPixelConfig config, GrGLenum* internalFormat) const; + /** The format to use read/write a texture as an image in a shader */ + GrGLenum getImageFormat(GrPixelConfig config) const { + return fConfigTable[config].fFormats.fSizedInternalFormat; + } + /** * Gets an array of legal stencil formats. These formats are not guaranteed * to be supported by the driver but are legal GLenum names given the GL @@ -234,7 +240,7 @@ public: /** * What functionality is supported by glBlitFramebuffer. */ - BlitFramebufferSupport blitFramebufferSupport() const { return fBlitFramebufferSupport; } + uint32_t blitFramebufferSupportFlags() const { return fBlitFramebufferFlags; } /** * Is the MSAA FBO extension one where the texture is multisampled when bound to an FBO and @@ -316,11 +322,12 @@ public: /// Use indices or vertices in CPU arrays rather than VBOs for dynamic content. bool useNonVBOVertexAndIndexDynamicData() const { return fUseNonVBOVertexAndIndexDynamicData; } - /// Does ReadPixels support reading readConfig pixels from a FBO that is renderTargetConfig? - bool readPixelsSupported(GrPixelConfig renderTargetConfig, + /// Does ReadPixels support reading readConfig pixels from a FBO that is surfaceConfig? + bool readPixelsSupported(GrPixelConfig surfaceConfig, GrPixelConfig readConfig, std::function getIntegerv, - std::function bindRenderTarget) const; + std::function bindRenderTarget, + std::function unbindRenderTarget) const; bool isCoreProfile() const { return fIsCoreProfile; } @@ -338,6 +345,9 @@ public: bool doManualMipmapping() const { return fDoManualMipmapping; } + bool srgbDecodeDisableSupport() const { return fSRGBDecodeDisableSupport; } + bool srgbDecodeDisableAffectsMipmaps() const { return fSRGBDecodeDisableAffectsMipmaps; } + /** * Returns a string containing the caps info. */ @@ -349,7 +359,8 @@ public: return fRGBAToBGRAReadbackConversionsAreSlow; } - const GrGLSLCaps* glslCaps() const { return reinterpret_cast(fShaderCaps.get()); } + bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, + bool* rectsMustMatch, bool* disallowSubrect) const override; private: enum ExternalFormatUsage { @@ -373,11 +384,10 @@ private: void initBlendEqationSupport(const GrGLContextInfo&); void initStencilFormats(const GrGLContextInfo&); // This must be called after initFSAASupport(). - void initConfigTable(const GrGLContextInfo&, const GrGLInterface* gli, GrGLSLCaps* glslCaps); + void initConfigTable(const GrContextOptions&, const GrGLContextInfo&, const GrGLInterface*, + GrShaderCaps*); - void initShaderPrecisionTable(const GrGLContextInfo& ctxInfo, - const GrGLInterface* intf, - GrGLSLCaps* glslCaps); + void initShaderPrecisionTable(const GrGLContextInfo&, const GrGLInterface*, GrShaderCaps*); GrGLStandard fStandard; @@ -417,13 +427,16 @@ private: bool fMipMapLevelAndLodControlSupport : 1; bool fRGBAToBGRAReadbackConversionsAreSlow : 1; bool fDoManualMipmapping : 1; + bool fSRGBDecodeDisableSupport : 1; + bool fSRGBDecodeDisableAffectsMipmaps : 1; - BlitFramebufferSupport fBlitFramebufferSupport; + uint32_t fBlitFramebufferFlags; /** Number type of the components (with out considering number of bits.) */ enum FormatType { kNormalizedFixedPoint_FormatType, kFloat_FormatType, + kInteger_FormatType, }; struct ReadPixelsFormat { @@ -449,7 +462,6 @@ private: GrGLenum fExternalFormat[kExternalFormatUsageCnt]; GrGLenum fExternalType; - // Either the base or sized internal format depending on the GL and config. GrGLenum fInternalFormatTexImage; GrGLenum fInternalFormatRenderbuffer; @@ -482,8 +494,12 @@ private: kTextureable_Flag = 0x2, kRenderable_Flag = 0x4, kRenderableWithMSAA_Flag = 0x8, - kCanUseTexStorage_Flag = 0x10, - kCanUseWithTexelBuffer_Flag = 0x20, + /** kFBOColorAttachment means that even if the config cannot be a GrRenderTarget, we can + still attach it to a FBO for blitting or reading pixels. */ + kFBOColorAttachment_Flag = 0x10, + kCanUseTexStorage_Flag = 0x20, + kCanUseWithTexelBuffer_Flag = 0x40, + kCanUseAsImageStorage_Flag = 0x80, }; uint32_t fFlags; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLContext.cpp b/gfx/skia/skia/src/gpu/gl/GrGLContext.cpp index 9e70b472c537..5adba5a0f17f 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLContext.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLContext.cpp @@ -7,6 +7,7 @@ #include "GrGLContext.h" #include "GrGLGLSL.h" +#include "SkSLCompiler.h" //////////////////////////////////////////////////////////////////////////////// @@ -63,6 +64,17 @@ GrGLContext* GrGLContext::Create(const GrGLInterface* interface, const GrContext return new GrGLContext(args); } +GrGLContext::~GrGLContext() { + delete fCompiler; +} + +SkSL::Compiler* GrGLContext::compiler() const { + if (!fCompiler) { + fCompiler = new SkSL::Compiler(); + } + return fCompiler; +} + GrGLContextInfo::GrGLContextInfo(const ConstructorArgs& args) { fInterface.reset(SkRef(args.fInterface)); fGLVersion = args.fGLVersion; @@ -72,5 +84,5 @@ GrGLContextInfo::GrGLContextInfo(const ConstructorArgs& args) { fDriver = args.fDriver; fDriverVersion = args.fDriverVersion; - fGLCaps.reset(new GrGLCaps(*args.fContextOptions, *this, fInterface)); + fGLCaps = sk_make_sp(*args.fContextOptions, *this, fInterface.get()); } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLContext.h b/gfx/skia/skia/src/gpu/gl/GrGLContext.h index 6016f6859a35..0bf045a7db40 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLContext.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLContext.h @@ -15,6 +15,9 @@ #include "GrGLUtil.h" struct GrContextOptions; +namespace SkSL { + class Compiler; +} /** * Encapsulates information about an OpenGL context including the OpenGL @@ -32,13 +35,15 @@ public: GrGLDriver driver() const { return fDriver; } GrGLDriverVersion driverVersion() const { return fDriverVersion; } const GrGLCaps* caps() const { return fGLCaps.get(); } - GrGLCaps* caps() { return fGLCaps; } + GrGLCaps* caps() { return fGLCaps.get(); } bool hasExtension(const char* ext) const { return fInterface->hasExtension(ext); } const GrGLExtensions& extensions() const { return fInterface->fExtensions; } + virtual ~GrGLContextInfo() {} + protected: struct ConstructorArgs { const GrGLInterface* fInterface; @@ -53,18 +58,18 @@ protected: GrGLContextInfo(const ConstructorArgs& args); - SkAutoTUnref fInterface; - GrGLVersion fGLVersion; - GrGLSLGeneration fGLSLGeneration; - GrGLVendor fVendor; - GrGLRenderer fRenderer; - GrGLDriver fDriver; - GrGLDriverVersion fDriverVersion; - SkAutoTUnref fGLCaps; + sk_sp fInterface; + GrGLVersion fGLVersion; + GrGLSLGeneration fGLSLGeneration; + GrGLVendor fVendor; + GrGLRenderer fRenderer; + GrGLDriver fDriver; + GrGLDriverVersion fDriverVersion; + sk_sp fGLCaps; }; /** - * Extension of GrGLContextInfo that also provides access to GrGLInterface. + * Extension of GrGLContextInfo that also provides access to GrGLInterface and SkSL::Compiler. */ class GrGLContext : public GrGLContextInfo { public: @@ -74,10 +79,18 @@ public: */ static GrGLContext* Create(const GrGLInterface* interface, const GrContextOptions& options); - const GrGLInterface* interface() const { return fInterface; } + const GrGLInterface* interface() const { return fInterface.get(); } + + SkSL::Compiler* compiler() const; + + ~GrGLContext() override; private: - GrGLContext(const ConstructorArgs& args) : INHERITED(args) {} + GrGLContext(const ConstructorArgs& args) + : INHERITED(args) + , fCompiler(nullptr) {} + + mutable SkSL::Compiler* fCompiler; typedef GrGLContextInfo INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLCreateNullInterface.cpp b/gfx/skia/skia/src/gpu/gl/GrGLCreateNullInterface.cpp index 61f638b6824d..7611f597c123 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLCreateNullInterface.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLCreateNullInterface.cpp @@ -176,7 +176,7 @@ public: void notifyAttachmentDeleteWhileBound(const FramebufferAttachment* deleted) { for (auto& attachment : fAttachments) { - if (attachment == deleted) { + if (attachment.get() == deleted) { attachment.reset(nullptr); } } @@ -206,7 +206,7 @@ private: }; constexpr int static kNumAttachmentPoints = 1 + (int)AttachmentPoint::kColor; - SkAutoTUnref fAttachments[kNumAttachmentPoints]; + sk_sp fAttachments[kNumAttachmentPoints]; typedef GLObject INHERITED; }; @@ -224,17 +224,17 @@ public: , fCurrUniformLocation(0) , fCurrPathID(0) { memset(fBoundBuffers, 0, sizeof(fBoundBuffers)); - fExtensions.push_back("GL_ARB_framebuffer_object"); - fExtensions.push_back("GL_ARB_blend_func_extended"); - fExtensions.push_back("GL_ARB_timer_query"); - fExtensions.push_back("GL_ARB_draw_buffers"); - fExtensions.push_back("GL_ARB_occlusion_query"); - fExtensions.push_back("GL_EXT_stencil_wrap"); + fAdvertisedExtensions.push_back("GL_ARB_framebuffer_object"); + fAdvertisedExtensions.push_back("GL_ARB_blend_func_extended"); + fAdvertisedExtensions.push_back("GL_ARB_timer_query"); + fAdvertisedExtensions.push_back("GL_ARB_draw_buffers"); + fAdvertisedExtensions.push_back("GL_ARB_occlusion_query"); + fAdvertisedExtensions.push_back("GL_EXT_stencil_wrap"); if (enableNVPR) { - fExtensions.push_back("GL_NV_path_rendering"); - fExtensions.push_back("GL_ARB_program_interface_query"); + fAdvertisedExtensions.push_back("GL_NV_path_rendering"); + fAdvertisedExtensions.push_back("GL_ARB_program_interface_query"); } - fExtensions.push_back(nullptr); + fAdvertisedExtensions.push_back(nullptr); this->init(kGL_GrGLStandard); } @@ -522,7 +522,7 @@ public: break; case GR_GL_NUM_EXTENSIONS: { GrGLint i = 0; - while (fExtensions[i++]); + while (fAdvertisedExtensions[i++]); *params = i; break; } @@ -606,7 +606,7 @@ public: GrGLint count; this->getIntegerv(GR_GL_NUM_EXTENSIONS, &count); if ((GrGLint)i <= count) { - return (const GrGLubyte*) fExtensions[i]; + return (const GrGLubyte*) fAdvertisedExtensions[i]; } else { return nullptr; } @@ -710,8 +710,8 @@ private: GrGLuint fCurrGenericID; GrGLuint fCurrUniformLocation; GrGLuint fCurrPathID; - SkAutoTUnref fSingleTextureObject; - SkTArray fExtensions; + sk_sp fSingleTextureObject; + SkTArray fAdvertisedExtensions; // the OpenGLES 2.0 spec says this must be >= 128 static const GrGLint kDefaultMaxVertexUniformVectors = 128; @@ -746,7 +746,7 @@ private: if (!fSingleTextureObject) { fSingleTextureObject.reset(new Texture); } - return fSingleTextureObject; + return fSingleTextureObject.get(); } const GrGLubyte* CombinedExtensionString() { @@ -755,11 +755,11 @@ private: gMutex.acquire(); if (0 == gExtString.size()) { int i = 0; - while (fExtensions[i]) { + while (fAdvertisedExtensions[i]) { if (i > 0) { gExtString.append(" "); } - gExtString.append(fExtensions[i]); + gExtString.append(fAdvertisedExtensions[i]); ++i; } } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLDefines.h b/gfx/skia/skia/src/gpu/gl/GrGLDefines.h index 8dc7af14248e..f3c5f5c99aad 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLDefines.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLDefines.h @@ -242,6 +242,14 @@ #define GR_GL_MULTISAMPLE_COVERAGE_MODES 0x8E12 #define GR_GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GR_GL_MAX_IMAGE_UNITS 0x8F38 +#define GR_GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 +#define GR_GL_MAX_IMAGE_SAMPLES 0x906D +#define GR_GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define GR_GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define GR_GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define GR_GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF + /* GetTextureParameter */ /* GL_TEXTURE_MAG_FILTER */ /* GL_TEXTURE_MIN_FILTER */ @@ -408,24 +416,121 @@ #define GR_GL_LINE_WIDTH_GRANULARITY 0x0B23 #define GR_GL_LINE_WIDTH_RANGE 0x0B22 -/* PixelFormat */ +/* PolygonMode */ +#define GR_GL_POINT 0x1B00 +#define GR_GL_LINE 0x1B01 +#define GR_GL_FILL 0x1B02 + +/* Unsized formats */ +#define GR_GL_STENCIL_INDEX 0x1901 #define GR_GL_DEPTH_COMPONENT 0x1902 +#define GR_GL_DEPTH_STENCIL 0x84F9 #define GR_GL_RED 0x1903 +#define GR_GL_RED_INTEGER 0x8D94 #define GR_GL_GREEN 0x1904 #define GR_GL_BLUE 0x1905 #define GR_GL_ALPHA 0x1906 -#define GR_GL_RGB 0x1907 -#define GR_GL_RGBA 0x1908 -#define GR_GL_BGRA 0x80E1 #define GR_GL_LUMINANCE 0x1909 #define GR_GL_LUMINANCE_ALPHA 0x190A -#define GR_GL_PALETTE8_RGBA8 0x8B96 -#define GR_GL_ALPHA8 0x803C +#define GR_GL_RG_INTEGER 0x8228 +#define GR_GL_RGB 0x1907 +#define GR_GL_RGB_INTEGER 0x8D98 +#define GR_GL_SRGB 0x8C40 +#define GR_GL_RGBA 0x1908 +#define GR_GL_RG 0x8227 +#define GR_GL_SRGB_ALPHA 0x8C42 +#define GR_GL_RGBA_INTEGER 0x8D99 +#define GR_GL_BGRA 0x80E1 +/* Stencil index sized formats */ +#define GR_GL_STENCIL_INDEX4 0x8D47 +#define GR_GL_STENCIL_INDEX8 0x8D48 +#define GR_GL_STENCIL_INDEX16 0x8D49 + +/* Depth component sized formats */ +#define GR_GL_DEPTH_COMPONENT16 0x81A5 + +/* Depth stencil sized formats */ +#define GR_GL_DEPTH24_STENCIL8 0x88F0 + +/* Red sized formats */ #define GR_GL_R8 0x8229 +#define GR_GL_R16 0x822A #define GR_GL_R16F 0x822D -#define GR_GL_RGBA16F 0x881A +#define GR_GL_R32F 0x822E + +/* Red integer sized formats */ +#define GR_GL_R8I 0x8231 +#define GR_GL_R8UI 0x8232 +#define GR_GL_R16I 0x8233 +#define GR_GL_R16UI 0x8234 +#define GR_GL_R32I 0x8235 +#define GR_GL_R32UI 0x8236 + +/* Luminance sized formats */ +#define GR_GL_LUMINANCE8 0x8040 + +/* Alpha sized formats */ +#define GR_GL_ALPHA8 0x803C +#define GR_GL_ALPHA16 0x803E #define GR_GL_ALPHA16F 0x881C +#define GR_GL_ALPHA32F 0x8816 + +/* Alpha integer sized formats */ +#define GR_GL_ALPHA8I 0x8D90 +#define GR_GL_ALPHA8UI 0x8D7E +#define GR_GL_ALPHA16I 0x8D8A +#define GR_GL_ALPHA16UI 0x8D78 +#define GR_GL_ALPHA32I 0x8D84 +#define GR_GL_ALPHA32UI 0x8D72 + +/* RG sized formats */ +#define GR_GL_RG8 0x822B +#define GR_GL_RG16 0x822C +#define GR_GL_R16F 0x822D +#define GR_GL_R32F 0x822E + +/* RG sized integer formats */ +#define GR_GL_RG8I 0x8237 +#define GR_GL_RG8UI 0x8238 +#define GR_GL_RG16I 0x8239 +#define GR_GL_RG16UI 0x823A +#define GR_GL_RG32I 0x823B +#define GR_GL_RG32UI 0x823C + +/* RGB sized formats */ +#define GR_GL_RGB5 0x8050 +#define GR_GL_RGB565 0x8D62 +#define GR_GL_RGB8 0x8051 +#define GR_GL_SRGB8 0x8C41 + +/* RGB integer sized formats */ +#define GR_GL_RGB8I 0x8D8F +#define GR_GL_RGB8UI 0x8D7D +#define GR_GL_RGB16I 0x8D89 +#define GR_GL_RGB16UI 0x8D77 +#define GR_GL_RGB32I 0x8D83 +#define GR_GL_RGB32UI 0x8D71 + +/* RGBA sized formats */ +#define GR_GL_RGBA4 0x8056 +#define GR_GL_RGB5_A1 0x8057 +#define GR_GL_RGBA8 0x8058 +#define GR_GL_SRGB8_ALPHA8 0x8C43 +#define GR_GL_RGBA16F 0x881A +#define GR_GL_RGBA32F 0x8814 +#define GR_GL_RG32F 0x8230 + +/* RGBA integer sized formats */ +#define GR_GL_RGBA8I 0x8D8E +#define GR_GL_RGBA8UI 0x8D7C +#define GR_GL_RGBA16I 0x8D88 +#define GR_GL_RGBA16UI 0x8D76 +#define GR_GL_RGBA32I 0x8D82 +#define GR_GL_RGBA32UI 0x8D70 + +/* BGRA sized formats */ +#define GR_GL_BGRA8 0x93A1 /* PixelType */ /* GL_UNSIGNED_BYTE */ @@ -731,6 +836,7 @@ /* Buffer Object */ #define GR_GL_READ_ONLY 0x88B8 #define GR_GL_WRITE_ONLY 0x88B9 +#define GR_GL_READ_WRITE 0x88BA #define GR_GL_BUFFER_MAPPED 0x88BC #define GR_GL_MAP_READ_BIT 0x0001 @@ -782,26 +888,6 @@ #define GR_GL_RENDERBUFFER 0x8D41 -#define GR_GL_RGBA4 0x8056 -#define GR_GL_RGB5_A1 0x8057 -#define GR_GL_RGB565 0x8D62 -#define GR_GL_RGBA8 0x8058 -#define GR_GL_RGBA32F 0x8814 -#define GR_GL_RGB5 0x8050 -#define GR_GL_RGB8 0x8051 -#define GR_GL_BGRA8 0x93A1 -#define GR_GL_SRGB 0x8C40 -#define GR_GL_SRGB8 0x8C41 -#define GR_GL_SRGB_ALPHA 0x8C42 -#define GR_GL_SRGB8_ALPHA8 0x8C43 -#define GR_GL_DEPTH_COMPONENT16 0x81A5 -#define GR_GL_STENCIL_INDEX 0x1901 -#define GR_GL_STENCIL_INDEX4 0x8D47 -#define GR_GL_STENCIL_INDEX8 0x8D48 -#define GR_GL_STENCIL_INDEX16 0x8D49 -#define GR_GL_DEPTH_STENCIL 0x84F9 -#define GR_GL_DEPTH24_STENCIL8 0x88F0 - #define GR_GL_MAX_SAMPLES 0x8D57 // GL_IMG_multisampled_render_to_texture uses a different value for GL_MAX_SAMPLES #define GR_GL_MAX_SAMPLES_IMG 0x9135 @@ -974,6 +1060,7 @@ #define GR_GL_CONDITION_SATISFIED 0x911C #define GR_GL_WAIT_FAILED 0x911D #define GR_GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GR_GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull /* EGL Defines */ #define GR_EGL_NO_DISPLAY ((GrEGLDisplay)0) diff --git a/gfx/skia/skia/src/gpu/gl/GrGLExtensions.cpp b/gfx/skia/skia/src/gpu/gl/GrGLExtensions.cpp index 43a147d76313..29f7799462f9 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLExtensions.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLExtensions.cpp @@ -9,6 +9,7 @@ #include "gl/GrGLDefines.h" #include "gl/GrGLUtil.h" +#include "SkMakeUnique.h" #include "SkTSearch.h" #include "SkTSort.h" @@ -99,12 +100,12 @@ bool GrGLExtensions::init(GrGLStandard standard, if (!extensions) { return false; } - eat_space_sep_strings(fStrings, extensions); + eat_space_sep_strings(fStrings.get(), extensions); } if (queryString) { const char* extensions = queryString(eglDisplay, GR_EGL_EXTENSIONS); - eat_space_sep_strings(fStrings, extensions); + eat_space_sep_strings(fStrings.get(), extensions); } if (!fStrings->empty()) { SkTLessFunctionToFunctorAdaptor cmp; @@ -122,27 +123,26 @@ bool GrGLExtensions::has(const char ext[]) const { bool GrGLExtensions::remove(const char ext[]) { SkASSERT(fInitialized); int idx = find_string(*fStrings, ext); - if (idx >= 0) { - // This is not terribly effecient but we really only expect this function to be called at - // most a handful of times when our test programs start. - SkAutoTDelete< SkTArray > oldStrings(fStrings.release()); - fStrings.reset(new SkTArray(oldStrings->count() - 1)); - fStrings->push_back_n(idx, &oldStrings->front()); - fStrings->push_back_n(oldStrings->count() - idx - 1, &(*oldStrings)[idx] + 1); - return true; - } else { + if (idx < 0) { return false; } + + // This is not terribly effecient but we really only expect this function to be called at + // most a handful of times when our test programs start. + fStrings->removeShuffle(idx); + SkTLessFunctionToFunctorAdaptor cmp; + SkTInsertionSort(&(fStrings->operator[](idx)), &fStrings->back(), cmp); + return true; } void GrGLExtensions::add(const char ext[]) { int idx = find_string(*fStrings, ext); if (idx < 0) { - // This is not the most effecient approach since we end up doing a full sort of the + // This is not the most effecient approach since we end up looking at all of the // extensions after the add - fStrings->push_back().set(ext); + fStrings->emplace_back(ext); SkTLessFunctionToFunctorAdaptor cmp; - SkTQSort(&fStrings->front(), &fStrings->back(), cmp); + SkTInsertionSort(&fStrings->front(), &fStrings->back(), cmp); } } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLExternalTextureData.cpp b/gfx/skia/skia/src/gpu/gl/GrGLExternalTextureData.cpp new file mode 100644 index 000000000000..1087830947a8 --- /dev/null +++ b/gfx/skia/skia/src/gpu/gl/GrGLExternalTextureData.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrContext.h" +#include "GrContextPriv.h" +#include "GrGpu.h" +#include "GrResourceProvider.h" +#include "GrSemaphore.h" +#include "gl/GrGLTypes.h" + +GrGLExternalTextureData::GrGLExternalTextureData(const GrGLTextureInfo& info, + sk_sp semaphore, + GrContext* context) + : fInfo(info) + , fSemaphore(std::move(semaphore)) { + SkASSERT(fSemaphore->unique()); + context->resourceProvider()->releaseOwnershipOfSemaphore(fSemaphore); +} + +void GrGLExternalTextureData::attachToContext(GrContext* context) { + context->resourceProvider()->takeOwnershipOfSemaphore(fSemaphore); + // Ideally we don't want to get the Gpu off of the context here. However, eventually this + // semaphore will live on a GrTexture object and the wait will be called from there. At that + // point we can use the GrGpu already stored directly on the GrTexture. + context->getGpu()->waitSemaphore(fSemaphore); +} diff --git a/gfx/skia/skia/src/gpu/gl/GrGLGLSL.cpp b/gfx/skia/skia/src/gpu/gl/GrGLGLSL.cpp index e5aed0355787..7ceb639ee017 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLGLSL.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLGLSL.cpp @@ -5,10 +5,10 @@ * found in the LICENSE file. */ -#include "GrGLGLSL.h" #include "GrGLContext.h" #include "GrGLUtil.h" #include "SkString.h" +#include "../private/GrGLSL.h" bool GrGLGetGLSLGeneration(const GrGLInterface* gl, GrGLSLGeneration* generation) { SkASSERT(generation); @@ -19,7 +19,9 @@ bool GrGLGetGLSLGeneration(const GrGLInterface* gl, GrGLSLGeneration* generation switch (gl->fStandard) { case kGL_GrGLStandard: SkASSERT(ver >= GR_GLSL_VER(1,10)); - if (ver >= GR_GLSL_VER(4,00)) { + if (ver >= GR_GLSL_VER(4,20)) { + *generation = k420_GrGLSLGeneration; + } else if (ver >= GR_GLSL_VER(4,00)) { *generation = k400_GrGLSLGeneration; } else if (ver >= GR_GLSL_VER(3,30)) { *generation = k330_GrGLSLGeneration; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLGLSL.h b/gfx/skia/skia/src/gpu/gl/GrGLGLSL.h index 31e2de7d7403..88bb273d9292 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLGLSL.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLGLSL.h @@ -9,10 +9,10 @@ #define GrGLInitGLSL_DEFINED #include "gl/GrGLInterface.h" -#include "glsl/GrGLSL.h" #include "GrColor.h" #include "GrTypesPriv.h" #include "SkString.h" +#include "../private/GrGLSL.h" class GrGLContextInfo; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLGpu.cpp b/gfx/skia/skia/src/gpu/gl/GrGLGpu.cpp index 9341355f9428..5cc81a450aa5 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLGpu.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLGpu.cpp @@ -6,30 +6,33 @@ */ #include "GrGLGpu.h" + +#include "../private/GrGLSL.h" +#include "GrFixedClip.h" #include "GrGLBuffer.h" -#include "GrGLGLSL.h" #include "GrGLGpuCommandBuffer.h" +#include "GrGLSemaphore.h" #include "GrGLStencilAttachment.h" #include "GrGLTextureRenderTarget.h" -#include "GrFixedClip.h" #include "GrGpuResourcePriv.h" #include "GrMesh.h" #include "GrPipeline.h" -#include "GrPLSGeometryProcessor.h" #include "GrRenderTargetPriv.h" +#include "GrShaderCaps.h" #include "GrSurfacePriv.h" +#include "GrSurfaceProxyPriv.h" #include "GrTexturePriv.h" #include "GrTypes.h" -#include "builders/GrGLShaderStringBuilder.h" -#include "glsl/GrGLSL.h" -#include "glsl/GrGLSLCaps.h" -#include "glsl/GrGLSLPLSPathRendering.h" -#include "instanced/GLInstancedRendering.h" +#include "SkAutoMalloc.h" +#include "SkMakeUnique.h" #include "SkMipMap.h" #include "SkPixmap.h" +#include "SkSLCompiler.h" #include "SkStrokeRec.h" #include "SkTemplates.h" #include "SkTypes.h" +#include "builders/GrGLShaderStringBuilder.h" +#include "instanced/GLInstancedRendering.h" #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X) #define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glInterface(), RET, X) @@ -46,6 +49,8 @@ #define CHECK_ALLOC_ERROR(iface) GR_GL_NO_ERROR #endif +//#define USE_NSIGHT + /////////////////////////////////////////////////////////////////////////////// using gr_instanced::InstancedRendering; @@ -172,7 +177,7 @@ bool GrGLGpu::BlendCoeffReferencesConstant(GrBlendCoeff coeff) { GrGpu* GrGLGpu::Create(GrBackendContext backendContext, const GrContextOptions& options, GrContext* context) { - SkAutoTUnref glInterface( + sk_sp glInterface( reinterpret_cast(backendContext)); if (!glInterface) { glInterface.reset(GrGLDefaultInterface()); @@ -182,7 +187,7 @@ GrGpu* GrGLGpu::Create(GrBackendContext backendContext, const GrContextOptions& if (!glInterface) { return nullptr; } - GrGLContext* glContext = GrGLContext::Create(glInterface, options); + GrGLContext* glContext = GrGLContext::Create(glInterface.get(), options); if (glContext) { return new GrGLGpu(glContext, context); } @@ -200,8 +205,6 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) , fTempDstFBOID(0) , fStencilClearFBOID(0) , fHWMaxUsedBufferTextureUnit(-1) - , fHWPLSEnabled(false) - , fPLSHasBeenUsed(false) , fHWMinSampleShading(0.0) { for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) { fCopyPrograms[i].fProgram = 0; @@ -210,12 +213,12 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) fMipmapPrograms[i].fProgram = 0; } fWireRectProgram.fProgram = 0; - fPLSSetupProgram.fProgram = 0; SkASSERT(ctx); fCaps.reset(SkRef(ctx->caps())); - fHWBoundTextureUniqueIDs.reset(this->glCaps().glslCaps()->maxCombinedSamplers()); + fHWBoundTextureUniqueIDs.reset(this->caps()->shaderCaps()->maxCombinedSamplers()); + fHWBoundImageStorages.reset(this->caps()->shaderCaps()->maxCombinedImageStorages()); fHWBufferState[kVertex_GrBufferType].fGLTarget = GR_GL_ARRAY_BUFFER; fHWBufferState[kIndex_GrBufferType].fGLTarget = GR_GL_ELEMENT_ARRAY_BUFFER; @@ -233,7 +236,7 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) GR_STATIC_ASSERT(6 == SK_ARRAY_COUNT(fHWBufferState)); if (this->caps()->shaderCaps()->texelBufferSupport()) { - fHWBufferTextures.reset(this->glCaps().glslCaps()->maxCombinedSamplers()); + fHWBufferTextures.reset(this->caps()->shaderCaps()->maxCombinedSamplers()); } if (this->glCaps().shaderCaps()->pathRenderingSupport()) { @@ -267,7 +270,6 @@ GrGLGpu::~GrGLGpu() { fCopyProgramArrayBuffer.reset(); fMipmapProgramArrayBuffer.reset(); fWireRectArrayBuffer.reset(); - fPLSSetupProgram.fArrayBuffer.reset(); if (0 != fHWProgramID) { // detach the current program so there is no confusion on OpenGL's part @@ -301,122 +303,9 @@ GrGLGpu::~GrGLGpu() { GL_CALL(DeleteProgram(fWireRectProgram.fProgram)); } - if (0 != fPLSSetupProgram.fProgram) { - GL_CALL(DeleteProgram(fPLSSetupProgram.fProgram)); - } - delete fProgramCache; } -bool GrGLGpu::createPLSSetupProgram() { - if (!fPLSSetupProgram.fArrayBuffer) { - static const GrGLfloat vdata[] = { - 0, 0, - 0, 1, - 1, 0, - 1, 1 - }; - fPLSSetupProgram.fArrayBuffer.reset(GrGLBuffer::Create(this, sizeof(vdata), - kVertex_GrBufferType, - kStatic_GrAccessPattern, vdata)); - if (!fPLSSetupProgram.fArrayBuffer) { - return false; - } - } - - SkASSERT(!fPLSSetupProgram.fProgram); - GL_CALL_RET(fPLSSetupProgram.fProgram, CreateProgram()); - if (!fPLSSetupProgram.fProgram) { - return false; - } - - const GrGLSLCaps* glslCaps = this->glCaps().glslCaps(); - const char* version = glslCaps->versionDeclString(); - - GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier); - GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType, - GrShaderVar::kUniform_TypeModifier); - GrGLSLShaderVar uPosXform("u_posXform", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); - GrGLSLShaderVar uTexture("u_texture", kTexture2DSampler_GrSLType, - GrShaderVar::kUniform_TypeModifier); - GrGLSLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier); - - SkString vshaderTxt(version); - if (glslCaps->noperspectiveInterpolationSupport()) { - if (const char* extension = glslCaps->noperspectiveInterpolationExtensionString()) { - vshaderTxt.appendf("#extension %s : require\n", extension); - } - vTexCoord.addModifier("noperspective"); - } - aVertex.appendDecl(glslCaps, &vshaderTxt); - vshaderTxt.append(";"); - uTexCoordXform.appendDecl(glslCaps, &vshaderTxt); - vshaderTxt.append(";"); - uPosXform.appendDecl(glslCaps, &vshaderTxt); - vshaderTxt.append(";"); - vTexCoord.appendDecl(glslCaps, &vshaderTxt); - vshaderTxt.append(";"); - - vshaderTxt.append( - "// PLS Setup Program VS\n" - "void main() {" - " gl_Position.xy = a_vertex * u_posXform.xy + u_posXform.zw;" - " gl_Position.zw = vec2(0, 1);" - "}" - ); - - SkString fshaderTxt(version); - if (glslCaps->noperspectiveInterpolationSupport()) { - if (const char* extension = glslCaps->noperspectiveInterpolationExtensionString()) { - fshaderTxt.appendf("#extension %s : require\n", extension); - } - } - fshaderTxt.append("#extension "); - fshaderTxt.append(glslCaps->fbFetchExtensionString()); - fshaderTxt.append(" : require\n"); - fshaderTxt.append("#extension GL_EXT_shader_pixel_local_storage : require\n"); - GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, *glslCaps, &fshaderTxt); - vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); - vTexCoord.appendDecl(glslCaps, &fshaderTxt); - fshaderTxt.append(";"); - uTexture.appendDecl(glslCaps, &fshaderTxt); - fshaderTxt.append(";"); - - fshaderTxt.appendf( - "// PLS Setup Program FS\n" - GR_GL_PLS_PATH_DATA_DECL - "void main() {\n" - " " GR_GL_PLS_DSTCOLOR_NAME " = gl_LastFragColorARM;\n" - " pls.windings = ivec4(0, 0, 0, 0);\n" - "}" - ); - - const char* str; - GrGLint length; - - str = vshaderTxt.c_str(); - length = SkToInt(vshaderTxt.size()); - GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fPLSSetupProgram.fProgram, - GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats); - - str = fshaderTxt.c_str(); - length = SkToInt(fshaderTxt.size()); - GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fPLSSetupProgram.fProgram, - GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats); - - GL_CALL(LinkProgram(fPLSSetupProgram.fProgram)); - - GL_CALL_RET(fPLSSetupProgram.fPosXformUniform, GetUniformLocation(fPLSSetupProgram.fProgram, - "u_posXform")); - - GL_CALL(BindAttribLocation(fPLSSetupProgram.fProgram, 0, "a_vertex")); - - GL_CALL(DeleteShader(vshader)); - GL_CALL(DeleteShader(fshader)); - - return true; -} - void GrGLGpu::disconnect(DisconnectType type) { INHERITED::disconnect(type); if (DisconnectType::kCleanup == type) { @@ -445,9 +334,6 @@ void GrGLGpu::disconnect(DisconnectType type) { if (fWireRectProgram.fProgram) { GL_CALL(DeleteProgram(fWireRectProgram.fProgram)); } - if (fPLSSetupProgram.fProgram) { - GL_CALL(DeleteProgram(fPLSSetupProgram.fProgram)); - } } else { if (fProgramCache) { fProgramCache->abandon(); @@ -471,8 +357,6 @@ void GrGLGpu::disconnect(DisconnectType type) { } fWireRectProgram.fProgram = 0; fWireRectArrayBuffer.reset(); - fPLSSetupProgram.fProgram = 0; - fPLSSetupProgram.fArrayBuffer.reset(); if (this->glCaps().shaderCaps()->pathRenderingSupport()) { this->glPathRendering()->disconnect(type); } @@ -492,8 +376,8 @@ void GrGLGpu::onResetContext(uint32_t resetBits) { fHWBufferState[kXferGpuToCpu_GrBufferType].invalidate(); fHWDrawFace = GrDrawFace::kInvalid; - if (kGL_GrGLStandard == this->glStandard()) { +#ifndef USE_NSIGHT // Desktop-only state that we never change if (!this->glCaps().isCoreProfile()) { GL_CALL(Disable(GR_GL_POINT_SMOOTH)); @@ -510,13 +394,13 @@ void GrGLGpu::onResetContext(uint32_t resetBits) { GL_CALL(Disable(GR_GL_COLOR_TABLE)); } GL_CALL(Disable(GR_GL_POLYGON_OFFSET_FILL)); + + GL_CALL(PolygonMode(GR_GL_FRONT_AND_BACK, GR_GL_FILL)); +#endif // Since ES doesn't support glPointSize at all we always use the VS to // set the point size GL_CALL(Enable(GR_GL_VERTEX_PROGRAM_POINT_SIZE)); - // We should set glPolygonMode(FRONT_AND_BACK,FILL) here, too. It isn't - // currently part of our gl interface. There are probably others as - // well. } if (kGLES_GrGLStandard == this->glStandard() && @@ -550,12 +434,16 @@ void GrGLGpu::onResetContext(uint32_t resetBits) { if (resetBits & kTextureBinding_GrGLBackendState) { for (int s = 0; s < fHWBoundTextureUniqueIDs.count(); ++s) { - fHWBoundTextureUniqueIDs[s] = SK_InvalidUniqueID; + fHWBoundTextureUniqueIDs[s].makeInvalid(); } for (int b = 0; b < fHWBufferTextures.count(); ++b) { SkASSERT(this->caps()->shaderCaps()->texelBufferSupport()); fHWBufferTextures[b].fKnownBound = false; } + for (int i = 0; i < fHWBoundImageStorages.count(); ++i) { + SkASSERT(this->caps()->shaderCaps()->imageLoadStoreSupport()); + fHWBoundImageStorages[i].fTextureUniqueID.makeInvalid(); + } } if (resetBits & kBlend_GrGLBackendState) { @@ -581,7 +469,7 @@ void GrGLGpu::onResetContext(uint32_t resetBits) { } if (resetBits & kRenderTarget_GrGLBackendState) { - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fHWBoundRenderTargetUniqueID.makeInvalid(); fHWSRGBFramebuffer = kUnknown_TriState; } @@ -623,42 +511,26 @@ static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin, bool renderTarget) } } -GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, - GrWrapOwnership ownership) { -#ifdef SK_IGNORE_GL_TEXTURE_TARGET - if (!desc.fTextureHandle) { - return nullptr; - } -#else +sk_sp GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, + GrWrapOwnership ownership) { const GrGLTextureInfo* info = reinterpret_cast(desc.fTextureHandle); if (!info || !info->fID) { return nullptr; } -#endif // next line relies on GrBackendTextureDesc's flags matching GrTexture's bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag); + SkASSERT(!renderTarget || kAdoptAndCache_GrWrapOwnership != ownership); // Not supported GrGLTexture::IDDesc idDesc; - GrSurfaceDesc surfDesc; - -#ifdef SK_IGNORE_GL_TEXTURE_TARGET - idDesc.fInfo.fID = static_cast(desc.fTextureHandle); - // When we create the texture, we only - // create GL_TEXTURE_2D at the moment. - // External clients can do something different. - - idDesc.fInfo.fTarget = GR_GL_TEXTURE_2D; -#else idDesc.fInfo = *info; -#endif if (GR_GL_TEXTURE_EXTERNAL == idDesc.fInfo.fTarget) { if (renderTarget) { // This combination is not supported. return nullptr; } - if (!this->glCaps().glslCaps()->externalTextureSupport()) { + if (!this->caps()->shaderCaps()->externalTextureSupport()) { return nullptr; } } else if (GR_GL_TEXTURE_RECTANGLE == idDesc.fInfo.fTarget) { @@ -675,12 +547,13 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, return nullptr; } - if (kAdopt_GrWrapOwnership == ownership) { - idDesc.fOwnership = GrBackendObjectOwnership::kOwned; - } else { + if (kBorrow_GrWrapOwnership == ownership) { idDesc.fOwnership = GrBackendObjectOwnership::kBorrowed; + } else { + idDesc.fOwnership = GrBackendObjectOwnership::kOwned; } + GrSurfaceDesc surfDesc; surfDesc.fFlags = (GrSurfaceFlags) desc.fFlags; surfDesc.fWidth = desc.fWidth; surfDesc.fHeight = desc.fHeight; @@ -696,34 +569,27 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, surfDesc.fOrigin = desc.fOrigin; } - GrGLTexture* texture = nullptr; if (renderTarget) { GrGLRenderTarget::IDDesc rtIDDesc; if (!this->createRenderTargetObjects(surfDesc, idDesc.fInfo, &rtIDDesc)) { return nullptr; } - texture = GrGLTextureRenderTarget::CreateWrapped(this, surfDesc, idDesc, rtIDDesc); - } else { - texture = GrGLTexture::CreateWrapped(this, surfDesc, idDesc); - } - if (nullptr == texture) { - return nullptr; + return GrGLTextureRenderTarget::MakeWrapped(this, surfDesc, idDesc, rtIDDesc); } - return texture; + if (kAdoptAndCache_GrWrapOwnership == ownership) { + return sk_sp(new GrGLTexture(this, SkBudgeted::kYes, surfDesc, idDesc)); + } else { + return GrGLTexture::MakeWrapped(this, surfDesc, idDesc); + } } -GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& wrapDesc, - GrWrapOwnership ownership) { +sk_sp GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& wrapDesc){ GrGLRenderTarget::IDDesc idDesc; idDesc.fRTFBOID = static_cast(wrapDesc.fRenderTargetHandle); idDesc.fMSColorRenderbufferID = 0; idDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID; - if (kAdopt_GrWrapOwnership == ownership) { - idDesc.fRTFBOOwnership = GrBackendObjectOwnership::kOwned; - } else { - idDesc.fRTFBOOwnership = GrBackendObjectOwnership::kBorrowed; - } + idDesc.fRTFBOOwnership = GrBackendObjectOwnership::kBorrowed; idDesc.fIsMixedSampled = false; GrSurfaceDesc desc; @@ -734,31 +600,17 @@ GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDe desc.fSampleCnt = SkTMin(wrapDesc.fSampleCnt, this->caps()->maxSampleCount()); desc.fOrigin = resolve_origin(wrapDesc.fOrigin, true); - return GrGLRenderTarget::CreateWrapped(this, desc, idDesc, wrapDesc.fStencilBits); + return GrGLRenderTarget::MakeWrapped(this, desc, idDesc, wrapDesc.fStencilBits); } -GrRenderTarget* GrGLGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc& desc) { -#ifdef SK_IGNORE_GL_TEXTURE_TARGET - if (!desc.fTextureHandle) { - return nullptr; - } -#else +sk_sp GrGLGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc& desc){ const GrGLTextureInfo* info = reinterpret_cast(desc.fTextureHandle); if (!info || !info->fID) { return nullptr; } -#endif GrGLTextureInfo texInfo; - GrSurfaceDesc surfDesc; - -#ifdef SK_IGNORE_GL_TEXTURE_TARGET - texInfo.fID = static_cast(desc.fTextureHandle); - // We only support GL_TEXTURE_2D at the moment. - texInfo.fTarget = GR_GL_TEXTURE_2D; -#else texInfo = *info; -#endif if (GR_GL_TEXTURE_RECTANGLE != texInfo.fTarget && GR_GL_TEXTURE_2D != texInfo.fTarget) { @@ -768,6 +620,7 @@ GrRenderTarget* GrGLGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTextu return nullptr; } + GrSurfaceDesc surfDesc; surfDesc.fFlags = (GrSurfaceFlags) desc.fFlags; surfDesc.fWidth = desc.fWidth; surfDesc.fHeight = desc.fHeight; @@ -787,7 +640,7 @@ GrRenderTarget* GrGLGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTextu if (!this->createRenderTargetObjects(surfDesc, texInfo, &rtIDDesc)) { return nullptr; } - return GrGLRenderTarget::CreateWrapped(this, surfDesc, rtIDDesc, 0); + return GrGLRenderTarget::MakeWrapped(this, surfDesc, rtIDDesc, 0); } //////////////////////////////////////////////////////////////////////////////// @@ -796,7 +649,7 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height, GrPixelConfig srcConfig, DrawPreference* drawPreference, WritePixelTempDrawInfo* tempDrawInfo) { - if (kIndex_8_GrPixelConfig == srcConfig || GrPixelConfigIsCompressed(dstSurface->config())) { + if (GrPixelConfigIsCompressed(dstSurface->config())) { return false; } @@ -947,6 +800,7 @@ static inline GrGLint config_alignment(GrPixelConfig config) { SkASSERT(!GrPixelConfigIsCompressed(config)); switch (config) { case kAlpha_8_GrPixelConfig: + case kGray_8_GrPixelConfig: return 1; case kRGB_565_GrPixelConfig: case kRGBA_4444_GrPixelConfig: @@ -957,11 +811,16 @@ static inline GrGLint config_alignment(GrPixelConfig config) { case kBGRA_8888_GrPixelConfig: case kSRGBA_8888_GrPixelConfig: case kSBGRA_8888_GrPixelConfig: + case kRGBA_8888_sint_GrPixelConfig: case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: return 4; - default: + case kUnknown_GrPixelConfig: + case kETC1_GrPixelConfig: return 0; } + SkFAIL("Invalid pixel config"); + return 0; } static inline GrGLenum check_alloc_error(const GrSurfaceDesc& desc, @@ -1006,14 +865,14 @@ static bool allocate_and_populate_uncompressed_texture(const GrSurfaceDesc& desc // This means if we may later want to add mipmaps, we cannot use TexStorage. // Right now, we cannot know if we will later add mipmaps or not. // The only time we can use TexStorage is when we already have the - // mipmaps. - useTexStorage &= texels.count() > 1; + // mipmaps or are using a format incompatible with MIP maps. + useTexStorage &= texels.count() > 1 || GrPixelConfigIsSint(desc.fConfig); if (useTexStorage) { // We never resize or change formats of textures. GL_ALLOC_CALL(&interface, TexStorage2D(target, - texels.count(), + SkTMax(texels.count(), 1), internalFormatForTexStorage, desc.fWidth, desc.fHeight)); GrGLenum error = check_alloc_error(desc, &interface); @@ -1436,10 +1295,6 @@ bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc, return allocate_and_populate_compressed_texture(desc, *interface, caps, target, internalFormat, texels, width, height); } else { - // Paletted textures can't be updated. - if (GR_GL_PALETTE8_RGBA8 == internalFormat) { - return false; - } for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { SkASSERT(texels[currentMipLevel].fPixels || kTransfer_UploadType == uploadType); @@ -1472,10 +1327,9 @@ static bool renderbuffer_storage_msaa(const GrGLContext& ctx, CLEAR_ERROR_BEFORE_ALLOC(ctx.interface()); SkASSERT(GrGLCaps::kNone_MSFBOType != ctx.caps()->msFBOType()); switch (ctx.caps()->msFBOType()) { - case GrGLCaps::kDesktop_ARB_MSFBOType: - case GrGLCaps::kDesktop_EXT_MSFBOType: + case GrGLCaps::kEXT_MSFBOType: + case GrGLCaps::kStandard_MSFBOType: case GrGLCaps::kMixedSamples_MSFBOType: - case GrGLCaps::kES_3_0_MSFBOType: GL_ALLOC_CALL(ctx.interface(), RenderbufferStorageMultisample(GR_GL_RENDERBUFFER, sampleCount, @@ -1547,7 +1401,7 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, } // below here we may bind the FBO - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fHWBoundRenderTargetUniqueID.makeInvalid(); if (idDesc->fRTFBOID != idDesc->fTexFBOID) { SkASSERT(desc.fSampleCnt > 0); GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID)); @@ -1678,6 +1532,11 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, return return_null_texture(); } + bool wasMipMapDataProvided = false; + if (texels.count() > 1) { + wasMipMapDataProvided = true; + } + GrGLTexture* tex; if (renderTarget) { // unbind the texture from the texture unit before binding it to the frame buffer @@ -1688,12 +1547,9 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, GL_CALL(DeleteTextures(1, &idDesc.fInfo.fID)); return return_null_texture(); } - tex = new GrGLTextureRenderTarget(this, budgeted, desc, idDesc, rtIDDesc); + tex = new GrGLTextureRenderTarget(this, budgeted, desc, idDesc, rtIDDesc, + wasMipMapDataProvided); } else { - bool wasMipMapDataProvided = false; - if (texels.count() > 1) { - wasMipMapDataProvided = true; - } tex = new GrGLTexture(this, budgeted, desc, idDesc, wasMipMapDataProvided); } tex->setCachedTexParams(initialTexParams, this->getResetTimestamp()); @@ -1817,7 +1673,7 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { GrGLuint fb = 0; GL_CALL(GenFramebuffers(1, &fb)); GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fb)); - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fHWBoundRenderTargetUniqueID.makeInvalid(); GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D, @@ -2005,6 +1861,7 @@ void GrGLGpu::flushScissor(const GrScissorState& scissorState, void GrGLGpu::flushWindowRectangles(const GrWindowRectsState& windowState, const GrGLRenderTarget* rt) { +#ifndef USE_NSIGHT typedef GrWindowRectsState::Mode Mode; SkASSERT(!windowState.enabled() || rt->renderFBOID()); // Window rects can't be used on-screen. SkASSERT(windowState.numWindows() <= this->caps()->maxWindowRectangles()); @@ -2021,24 +1878,25 @@ void GrGLGpu::flushWindowRectangles(const GrWindowRectsState& windowState, GrGLIRect glwindows[GrWindowRectangles::kMaxWindows]; const SkIRect* skwindows = windowState.windows().data(); - int dx = -windowState.origin().x(), dy = -windowState.origin().y(); for (int i = 0; i < numWindows; ++i) { - const SkIRect& skwindow = skwindows[i].makeOffset(dx, dy); - glwindows[i].setRelativeTo(rt->getViewport(), skwindow, rt->origin()); + glwindows[i].setRelativeTo(rt->getViewport(), skwindows[i], rt->origin()); } GrGLenum glmode = (Mode::kExclusive == windowState.mode()) ? GR_GL_EXCLUSIVE : GR_GL_INCLUSIVE; GL_CALL(WindowRectangles(glmode, numWindows, glwindows->asInts())); fHWWindowRectsState.set(rt->origin(), rt->getViewport(), windowState); +#endif } void GrGLGpu::disableWindowRectangles() { +#ifndef USE_NSIGHT if (!this->caps()->maxWindowRectangles() || fHWWindowRectsState.knownDisabled()) { return; } GL_CALL(WindowRectangles(GR_GL_EXCLUSIVE, 0, nullptr)); fHWWindowRectsState.setDisabled(); +#endif } void GrGLGpu::flushMinSampleShading(float minSampleShading) { @@ -2056,8 +1914,7 @@ void GrGLGpu::flushMinSampleShading(float minSampleShading) { bool GrGLGpu::flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, bool willDrawPoints) { - SkAutoTUnref program(fProgramCache->refProgram(this, pipeline, primProc, - willDrawPoints)); + sk_sp program(fProgramCache->refProgram(this, pipeline, primProc, willDrawPoints)); if (!program) { GrCapsDebugf(this->caps(), "Failed to create program!\n"); return false; @@ -2080,7 +1937,7 @@ bool GrGLGpu::flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcesso if (blendInfo.fWriteColor) { // Swizzle the blend to match what the shader will output. - const GrSwizzle& swizzle = this->glCaps().glslCaps()->configOutputSwizzle( + const GrSwizzle& swizzle = this->caps()->shaderCaps()->configOutputSwizzle( pipeline.getRenderTarget()->config()); this->flushBlend(blendInfo, swizzle); } @@ -2088,10 +1945,17 @@ bool GrGLGpu::flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcesso program->setData(primProc, pipeline); GrGLRenderTarget* glRT = static_cast(pipeline.getRenderTarget()); - this->flushStencil(pipeline.getStencil()); + GrStencilSettings stencil; + if (pipeline.isStencilEnabled()) { + // TODO: attach stencil and create settings during render target flush. + SkASSERT(glRT->renderTargetPriv().getStencilAttachment()); + stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(), + glRT->renderTargetPriv().numStencilBits()); + } + this->flushStencil(stencil); this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->origin()); this->flushWindowRectangles(pipeline.getWindowRectsState(), glRT); - this->flushHWAAState(glRT, pipeline.isHWAntialiasState(), !pipeline.getStencil().isDisabled()); + this->flushHWAAState(glRT, pipeline.isHWAntialiasState(), !stencil.isDisabled()); // This must come after textures are flushed because a texture may need // to be msaa-resolved (which will modify bound FBO state). @@ -2179,7 +2043,7 @@ GrGLenum GrGLGpu::bindBuffer(GrBufferType type, const GrBuffer* buffer) { void GrGLGpu::notifyBufferReleased(const GrGLBuffer* buffer) { if (buffer->hasAttachedToTexture()) { // Detach this buffer from any textures to ensure the underlying memory is freed. - uint32_t uniqueID = buffer->uniqueID(); + GrGpuResource::UniqueID uniqueID = buffer->uniqueID(); for (int i = fHWMaxUsedBufferTextureUnit; i >= 0; --i) { auto& buffTex = fHWBufferTextures[i]; if (uniqueID != buffTex.fAttachedBufferUniqueID) { @@ -2267,7 +2131,7 @@ void GrGLGpu::clearStencilClip(const GrFixedClip& clip, #else // we could just clear the clip bit but when we go through // ANGLE a partial stencil mask will cause clears to be - // turned into draws. Our contract on GrDrawTarget says that + // turned into draws. Our contract on GrOpList says that // changing the clip between stencil passes may or may not // zero the client's clip bits. So we just clear the whole thing. static const GrGLint clipStencilMask = ~0; @@ -2290,11 +2154,11 @@ void GrGLGpu::clearStencilClip(const GrFixedClip& clip, fHWStencilSettings.invalidate(); } -static bool read_pixels_pays_for_y_flip(GrRenderTarget* renderTarget, const GrGLCaps& caps, +static bool read_pixels_pays_for_y_flip(GrSurfaceOrigin origin, const GrGLCaps& caps, int width, int height, GrPixelConfig config, size_t rowBytes) { - // If this render target is already TopLeft, we don't need to flip. - if (kTopLeft_GrSurfaceOrigin == renderTarget->origin()) { + // If the surface is already TopLeft, we don't need to flip. + if (kTopLeft_GrSurfaceOrigin == origin) { return false; } @@ -2317,36 +2181,64 @@ static bool read_pixels_pays_for_y_flip(GrRenderTarget* renderTarget, const GrGL } bool GrGLGpu::readPixelsSupported(GrRenderTarget* target, GrPixelConfig readConfig) { +#ifdef SK_BUILD_FOR_MAC + // Chromium may ask us to read back from locked IOSurfaces. Calling the command buffer's + // glGetIntegerv() with GL_IMPLEMENTATION_COLOR_READ_FORMAT/_TYPE causes the command buffer + // to make a call to check the framebuffer status which can hang the driver. So in Mac Chromium + // we always use a temporary surface to test for read pixels support. + // https://www.crbug.com/662802 + if (this->glContext().driver() == kChromium_GrGLDriver) { + return this->readPixelsSupported(target->config(), readConfig); + } +#endif auto bindRenderTarget = [this, target]() -> bool { this->flushRenderTarget(static_cast(target), &SkIRect::EmptyIRect()); return true; }; + auto unbindRenderTarget = []{}; auto getIntegerv = [this](GrGLenum query, GrGLint* value) { GR_GL_GetIntegerv(this->glInterface(), query, value); }; GrPixelConfig rtConfig = target->config(); - return this->glCaps().readPixelsSupported(rtConfig, readConfig, getIntegerv, bindRenderTarget); + return this->glCaps().readPixelsSupported(rtConfig, readConfig, getIntegerv, bindRenderTarget, + unbindRenderTarget); } bool GrGLGpu::readPixelsSupported(GrPixelConfig rtConfig, GrPixelConfig readConfig) { - auto bindRenderTarget = [this, rtConfig]() -> bool { + sk_sp temp; + auto bindRenderTarget = [this, rtConfig, &temp]() -> bool { GrTextureDesc desc; desc.fConfig = rtConfig; desc.fWidth = desc.fHeight = 16; - desc.fFlags = kRenderTarget_GrSurfaceFlag; - SkAutoTUnref temp(this->createTexture(desc, - SkBudgeted::kNo)); - if (!temp) { - return false; + if (this->glCaps().isConfigRenderable(rtConfig, false)) { + desc.fFlags = kRenderTarget_GrSurfaceFlag; + temp.reset(this->createTexture(desc, SkBudgeted::kNo)); + if (!temp) { + return false; + } + GrGLRenderTarget* glrt = static_cast(temp->asRenderTarget()); + this->flushRenderTarget(glrt, &SkIRect::EmptyIRect()); + return true; + } else if (this->glCaps().canConfigBeFBOColorAttachment(rtConfig)) { + temp.reset(this->createTexture(desc, SkBudgeted::kNo)); + if (!temp) { + return false; + } + GrGLIRect vp; + this->bindSurfaceFBOForPixelOps(temp.get(), GR_GL_FRAMEBUFFER, &vp, kDst_TempFBOTarget); + fHWBoundRenderTargetUniqueID.makeInvalid(); + return true; } - GrGLRenderTarget* glrt = static_cast(temp->asRenderTarget()); - this->flushRenderTarget(glrt, &SkIRect::EmptyIRect()); - return true; + return false; + }; + auto unbindRenderTarget = [this, &temp]() { + this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, temp.get()); }; auto getIntegerv = [this](GrGLenum query, GrGLint* value) { GR_GL_GetIntegerv(this->glInterface(), query, value); }; - return this->glCaps().readPixelsSupported(rtConfig, readConfig, getIntegerv, bindRenderTarget); + return this->glCaps().readPixelsSupported(rtConfig, readConfig, getIntegerv, bindRenderTarget, + unbindRenderTarget); } bool GrGLGpu::readPixelsSupported(GrSurface* surfaceForConfig, GrPixelConfig readConfig) { @@ -2401,12 +2293,6 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, return true; } - GrRenderTarget* srcAsRT = srcSurface->asRenderTarget(); - if (!srcAsRT) { - // For now keep assuming the draw is not a format transformation, just a draw to get to a - // RT. We may add additional transformations below. - ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); - } if (this->glCaps().rgba8888PixelsOpsAreSlow() && kRGBA_8888_GrPixelConfig == readConfig && this->readPixelsSupported(kBGRA_8888_GrPixelConfig, kBGRA_8888_GrPixelConfig)) { tempDrawInfo->fTempSurfaceDesc.fConfig = kBGRA_8888_GrPixelConfig; @@ -2425,7 +2311,7 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference); } else if (!this->readPixelsSupported(srcSurface, readConfig)) { if (readConfig == kBGRA_8888_GrPixelConfig && - this->glCaps().isConfigRenderable(kRGBA_8888_GrPixelConfig, false) && + this->glCaps().canConfigBeFBOColorAttachment(kRGBA_8888_GrPixelConfig) && this->readPixelsSupported(kRGBA_8888_GrPixelConfig, kRGBA_8888_GrPixelConfig)) { // We're trying to read BGRA but it's not supported. If RGBA is renderable and // we can read it back, then do a swizzling draw to a RGBA and read it back (which @@ -2435,7 +2321,7 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, tempDrawInfo->fReadConfig = kRGBA_8888_GrPixelConfig; ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); } else if (readConfig == kSBGRA_8888_GrPixelConfig && - this->glCaps().isConfigRenderable(kSRGBA_8888_GrPixelConfig, false) && + this->glCaps().canConfigBeFBOColorAttachment(kSRGBA_8888_GrPixelConfig) && this->readPixelsSupported(kSRGBA_8888_GrPixelConfig, kSRGBA_8888_GrPixelConfig)) { // We're trying to read sBGRA but it's not supported. If sRGBA is renderable and // we can read it back, then do a swizzling draw to a sRGBA and read it back (which @@ -2455,7 +2341,7 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, if (!this->readPixelsSupported(srcSurface, cpuTempConfig)) { // If we can't read RGBA from the src try to draw to a kRGBA_8888 (or kSRGBA_8888) // first and then onReadPixels will read that to a 32bit temporary buffer. - if (this->caps()->isConfigRenderable(cpuTempConfig, false)) { + if (this->glCaps().canConfigBeFBOColorAttachment(cpuTempConfig)) { ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); tempDrawInfo->fTempSurfaceDesc.fConfig = cpuTempConfig; tempDrawInfo->fReadConfig = kAlpha_8_GrPixelConfig; @@ -2466,7 +2352,7 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, SkASSERT(tempDrawInfo->fTempSurfaceDesc.fConfig == srcConfig); SkASSERT(tempDrawInfo->fReadConfig == kAlpha_8_GrPixelConfig); } - } else if (this->caps()->isConfigRenderable(readConfig, false) && + } else if (this->glCaps().canConfigBeFBOColorAttachment(readConfig) && this->readPixelsSupported(readConfig, readConfig)) { // Do a draw to convert from the src config to the read config. ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); @@ -2477,8 +2363,9 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, } } - if (srcAsRT && - read_pixels_pays_for_y_flip(srcAsRT, this->glCaps(), width, height, readConfig, rowBytes)) { + if ((srcSurface->asRenderTarget() || this->glCaps().canConfigBeFBOColorAttachment(srcConfig)) && + read_pixels_pays_for_y_flip(srcSurface->origin(), this->glCaps(), width, height, readConfig, + rowBytes)) { ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference); } @@ -2494,7 +2381,7 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, SkASSERT(surface); GrGLRenderTarget* renderTarget = static_cast(surface->asRenderTarget()); - if (!renderTarget) { + if (!renderTarget && !this->glCaps().canConfigBeFBOColorAttachment(surface->config())) { return false; } @@ -2505,16 +2392,16 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, // We have a special case fallback for reading eight bit alpha. We will read back all four 8 // bit channels as RGBA and then extract A. - if (!this->readPixelsSupported(renderTarget, config)) { + if (!this->readPixelsSupported(surface, config)) { // Don't attempt to do any srgb conversions since we only care about alpha. GrPixelConfig tempConfig = kRGBA_8888_GrPixelConfig; - if (GrPixelConfigIsSRGB(renderTarget->config())) { + if (GrPixelConfigIsSRGB(surface->config())) { tempConfig = kSRGBA_8888_GrPixelConfig; } if (kAlpha_8_GrPixelConfig == config && - this->readPixelsSupported(renderTarget, tempConfig)) { - SkAutoTDeleteArray temp(new uint32_t[width * height * 4]); - if (this->onReadPixels(renderTarget, left, top, width, height, tempConfig, temp.get(), + this->readPixelsSupported(surface, tempConfig)) { + std::unique_ptr temp(new uint32_t[width * height * 4]); + if (this->onReadPixels(surface, left, top, width, height, tempConfig, temp.get(), width*4)) { uint8_t* dst = reinterpret_cast(buffer); for (int j = 0; j < height; ++j) { @@ -2530,34 +2417,40 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, GrGLenum externalFormat; GrGLenum externalType; - if (!this->glCaps().getReadPixelsFormat(renderTarget->config(), config, &externalFormat, + if (!this->glCaps().getReadPixelsFormat(surface->config(), config, &externalFormat, &externalType)) { return false; } bool flipY = kBottomLeft_GrSurfaceOrigin == surface->origin(); - // resolve the render target if necessary - switch (renderTarget->getResolveType()) { - case GrGLRenderTarget::kCantResolve_ResolveType: - return false; - case GrGLRenderTarget::kAutoResolves_ResolveType: - this->flushRenderTarget(renderTarget, &SkIRect::EmptyIRect()); - break; - case GrGLRenderTarget::kCanResolve_ResolveType: - this->onResolveRenderTarget(renderTarget); - // we don't track the state of the READ FBO ID. - fStats.incRenderTargetBinds(); - GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, renderTarget->textureFBOID())); - break; - default: - SkFAIL("Unknown resolve type"); + GrGLIRect glvp; + if (renderTarget) { + // resolve the render target if necessary + switch (renderTarget->getResolveType()) { + case GrGLRenderTarget::kCantResolve_ResolveType: + return false; + case GrGLRenderTarget::kAutoResolves_ResolveType: + this->flushRenderTarget(renderTarget, &SkIRect::EmptyIRect()); + break; + case GrGLRenderTarget::kCanResolve_ResolveType: + this->onResolveRenderTarget(renderTarget); + // we don't track the state of the READ FBO ID. + fStats.incRenderTargetBinds(); + GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, renderTarget->textureFBOID())); + break; + default: + SkFAIL("Unknown resolve type"); + } + glvp = renderTarget->getViewport(); + } else { + // Use a temporary FBO. + this->bindSurfaceFBOForPixelOps(surface, GR_GL_FRAMEBUFFER, &glvp, kSrc_TempFBOTarget); + fHWBoundRenderTargetUniqueID.makeInvalid(); } - const GrGLIRect& glvp = renderTarget->getViewport(); - // the read rect is viewport-relative GrGLIRect readRect; - readRect.setRelativeTo(glvp, left, top, width, height, renderTarget->origin()); + readRect.setRelativeTo(glvp, left, top, width, height, surface->origin()); size_t bytesPerPixel = GrBytesPerPixel(config); size_t tightRowBytes = bytesPerPixel * width; @@ -2635,39 +2528,22 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, } } } + if (!renderTarget) { + this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, surface); + } return true; } GrGpuCommandBuffer* GrGLGpu::createCommandBuffer( - GrRenderTarget* target, const GrGpuCommandBuffer::LoadAndStoreInfo& colorInfo, const GrGpuCommandBuffer::LoadAndStoreInfo& stencilInfo) { return new GrGLGpuCommandBuffer(this); } -void GrGLGpu::finishDrawTarget() { - if (fPLSHasBeenUsed) { - /* There is an ARM driver bug where if we use PLS, and then draw a frame which does not - * use PLS, it leaves garbage all over the place. As a workaround, we use PLS in a - * trivial way every frame. And since we use it every frame, there's never a point at which - * it becomes safe to stop using this workaround once we start. - */ - this->disableScissor(); - this->disableWindowRectangles(); - // using PLS in the presence of MSAA results in GL_INVALID_OPERATION - this->flushHWAAState(nullptr, false, false); - SkASSERT(!fHWPLSEnabled); - SkASSERT(fMSAAEnabled != kYes_TriState); - GL_CALL(Enable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); - this->stampPLSSetupRect(SkRect::MakeXYWH(-100.0f, -100.0f, 0.01f, 0.01f)); - GL_CALL(Disable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); - } -} - void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bounds, bool disableSRGB) { SkASSERT(target); - uint32_t rtID = target->uniqueID(); + GrGpuResource::UniqueID rtID = target->uniqueID(); if (fHWBoundRenderTargetUniqueID != rtID) { fStats.incRenderTargetBinds(); GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, target->renderFBOID())); @@ -2759,18 +2635,6 @@ void GrGLGpu::draw(const GrPipeline& pipeline, if (!this->flushGLState(pipeline, primProc, hasPoints)) { return; } - GrPixelLocalStorageState plsState = primProc.getPixelLocalStorageState(); - if (!fHWPLSEnabled && plsState != - GrPixelLocalStorageState::kDisabled_GrPixelLocalStorageState) { - GL_CALL(Enable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); - this->setupPixelLocalStorage(pipeline, primProc); - fHWPLSEnabled = true; - } - if (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState) { - GrStencilSettings stencil; - stencil.setDisabled(); - this->flushStencil(stencil); - } for (int i = 0; i < meshCount; ++i) { if (GrXferBarrierType barrierType = pipeline.xferBarrierType(*this->caps())) { @@ -2789,7 +2653,7 @@ void GrGLGpu::draw(const GrPipeline& pipeline, sizeof(uint16_t) * nonInstMesh->startIndex()); // info.startVertex() was accounted for by setupGeometry. if (this->glCaps().drawRangeElementsSupport()) { - // We assume here that the batch that generated the mesh used the full + // We assume here that the GrMeshDrawOps that generated the mesh used the full // 0..vertexCount()-1 range. int start = 0; int end = nonInstMesh->vertexCount() - 1; @@ -2815,16 +2679,6 @@ void GrGLGpu::draw(const GrPipeline& pipeline, } while ((nonInstMesh = iter.next())); } - if (fHWPLSEnabled && plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState) { - // PLS draws always involve multiple draws, finishing up with a non-PLS - // draw that writes to the color buffer. That draw ends up here; we wait - // until after it is complete to actually disable PLS. - GL_CALL(Disable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); - fHWPLSEnabled = false; - this->disableScissor(); - this->disableWindowRectangles(); - } - #if SWAP_PER_DRAW glFlush(); #if defined(SK_BUILD_FOR_MAC) @@ -2839,65 +2693,6 @@ void GrGLGpu::draw(const GrPipeline& pipeline, #endif } -void GrGLGpu::stampPLSSetupRect(const SkRect& bounds) { - SkASSERT(this->glCaps().glslCaps()->plsPathRenderingSupport()); - - if (!fPLSSetupProgram.fProgram) { - if (!this->createPLSSetupProgram()) { - SkDebugf("Failed to create PLS setup program.\n"); - return; - } - } - - GL_CALL(UseProgram(fPLSSetupProgram.fProgram)); - this->fHWVertexArrayState.setVertexArrayID(this, 0); - - GrGLAttribArrayState* attribs = this->fHWVertexArrayState.bindInternalVertexArray(this); - attribs->set(this, 0, fPLSSetupProgram.fArrayBuffer, kVec2f_GrVertexAttribType, - 2 * sizeof(GrGLfloat), 0); - attribs->disableUnusedArrays(this, 0x1); - - GL_CALL(Uniform4f(fPLSSetupProgram.fPosXformUniform, bounds.width(), bounds.height(), - bounds.left(), bounds.top())); - - GrXferProcessor::BlendInfo blendInfo; - blendInfo.reset(); - this->flushBlend(blendInfo, GrSwizzle()); - this->flushColorWrite(true); - this->flushDrawFace(GrDrawFace::kBoth); - if (!fHWStencilSettings.isDisabled()) { - GL_CALL(Disable(GR_GL_STENCIL_TEST)); - } - GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4)); - GL_CALL(UseProgram(fHWProgramID)); - if (!fHWStencilSettings.isDisabled()) { - GL_CALL(Enable(GR_GL_STENCIL_TEST)); - } -} - -void GrGLGpu::setupPixelLocalStorage(const GrPipeline& pipeline, - const GrPrimitiveProcessor& primProc) { - fPLSHasBeenUsed = true; - const SkRect& bounds = - static_cast(primProc).getBounds(); - // setup pixel local storage -- this means capturing and storing the current framebuffer color - // and initializing the winding counts to zero - GrRenderTarget* rt = pipeline.getRenderTarget(); - SkScalar width = SkIntToScalar(rt->width()); - SkScalar height = SkIntToScalar(rt->height()); - // dst rect edges in NDC (-1 to 1) - // having some issues with rounding, just expand the bounds by 1 and trust the scissor to keep - // it contained properly - GrGLfloat dx0 = 2.0f * (bounds.left() - 1) / width - 1.0f; - GrGLfloat dx1 = 2.0f * (bounds.right() + 1) / width - 1.0f; - GrGLfloat dy0 = -2.0f * (bounds.top() - 1) / height + 1.0f; - GrGLfloat dy1 = -2.0f * (bounds.bottom() + 1) / height + 1.0f; - SkRect deviceBounds = SkRect::MakeXYWH(dx0, dy0, dx1 - dx0, dy1 - dy0); - - GL_CALL(Enable(GR_GL_FETCH_PER_SAMPLE_ARM)); - this->stampPLSSetupRect(deviceBounds); -} - void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) { GrGLRenderTarget* rt = static_cast(target); if (rt->needsResolve()) { @@ -2910,7 +2705,7 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) { GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->textureFBOID())); // make sure we go through flushRenderTarget() since we've modified // the bound DRAW FBO ID. - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fHWBoundRenderTargetUniqueID.makeInvalid(); const GrGLIRect& vp = rt->getViewport(); const SkIRect dirtyRect = rt->getResolveRect(); @@ -2922,18 +2717,27 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) { this->disableWindowRectangles(); GL_CALL(ResolveMultisampleFramebuffer()); } else { - GrGLIRect r; - r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, - dirtyRect.width(), dirtyRect.height(), target->origin()); - - int right = r.fLeft + r.fWidth; - int top = r.fBottom + r.fHeight; + int l, b, r, t; + if (GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag & + this->glCaps().blitFramebufferSupportFlags()) { + l = 0; + b = 0; + r = target->width(); + t = target->height(); + } else { + GrGLIRect rect; + rect.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, + dirtyRect.width(), dirtyRect.height(), target->origin()); + l = rect.fLeft; + b = rect.fBottom; + r = rect.fLeft + rect.fWidth; + t = rect.fBottom + rect.fHeight; + } // BlitFrameBuffer respects the scissor, so disable it. this->disableScissor(); this->disableWindowRectangles(); - GL_CALL(BlitFramebuffer(r.fLeft, r.fBottom, right, top, - r.fLeft, r.fBottom, right, top, + GL_CALL(BlitFramebuffer(l, b, r, t, l, b, r, t, GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); } } @@ -2993,37 +2797,38 @@ void set_gl_stencil(const GrGLInterface* gl, } void GrGLGpu::flushStencil(const GrStencilSettings& stencilSettings) { - if (fHWStencilSettings != stencilSettings) { - if (stencilSettings.isDisabled()) { - if (kNo_TriState != fHWStencilTestEnabled) { - GL_CALL(Disable(GR_GL_STENCIL_TEST)); - fHWStencilTestEnabled = kNo_TriState; - } - } else { - if (kYes_TriState != fHWStencilTestEnabled) { - GL_CALL(Enable(GR_GL_STENCIL_TEST)); - fHWStencilTestEnabled = kYes_TriState; - } + if (stencilSettings.isDisabled()) { + this->disableStencil(); + } else if (fHWStencilSettings != stencilSettings) { + if (kYes_TriState != fHWStencilTestEnabled) { + GL_CALL(Enable(GR_GL_STENCIL_TEST)); + fHWStencilTestEnabled = kYes_TriState; } - if (!stencilSettings.isDisabled()) { - if (stencilSettings.isTwoSided()) { - SkASSERT(this->caps()->twoSidedStencilSupport()); - set_gl_stencil(this->glInterface(), - stencilSettings.front(), - GR_GL_FRONT); - set_gl_stencil(this->glInterface(), - stencilSettings.back(), - GR_GL_BACK); - } else { - set_gl_stencil(this->glInterface(), - stencilSettings.front(), - GR_GL_FRONT_AND_BACK); - } + if (stencilSettings.isTwoSided()) { + SkASSERT(this->caps()->twoSidedStencilSupport()); + set_gl_stencil(this->glInterface(), + stencilSettings.front(), + GR_GL_FRONT); + set_gl_stencil(this->glInterface(), + stencilSettings.back(), + GR_GL_BACK); + } else { + set_gl_stencil(this->glInterface(), + stencilSettings.front(), + GR_GL_FRONT_AND_BACK); } fHWStencilSettings = stencilSettings; } } +void GrGLGpu::disableStencil() { + if (kNo_TriState != fHWStencilTestEnabled) { + GL_CALL(Disable(GR_GL_STENCIL_TEST)); + fHWStencilTestEnabled = kNo_TriState; + fHWStencilSettings.invalidate(); + } +} + void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled) { // rt is only optional if useHWAA is false. SkASSERT(rt || !useHWAA); @@ -3172,7 +2977,7 @@ static void get_tex_param_swizzle(GrPixelConfig config, } } -void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, bool allowSRGBInputs, +void GrGLGpu::bindTexture(int unitIdx, const GrSamplerParams& params, bool allowSRGBInputs, GrGLTexture* texture) { SkASSERT(texture); @@ -3196,7 +3001,7 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, bool allow this->onResolveRenderTarget(texRT); } - uint32_t textureID = texture->uniqueID(); + GrGpuResource::UniqueID textureID = texture->uniqueID(); GrGLenum target = texture->target(); if (fHWBoundTextureUniqueIDs[unitIdx] != textureID) { this->setTextureUnit(unitIdx); @@ -3219,18 +3024,18 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, bool allow GR_GL_LINEAR, GR_GL_LINEAR }; - GrTextureParams::FilterMode filterMode = params.filterMode(); + GrSamplerParams::FilterMode filterMode = params.filterMode(); - if (GrTextureParams::kMipMap_FilterMode == filterMode) { + if (GrSamplerParams::kMipMap_FilterMode == filterMode) { if (!this->caps()->mipMapSupport() || GrPixelConfigIsCompressed(texture->config())) { - filterMode = GrTextureParams::kBilerp_FilterMode; + filterMode = GrSamplerParams::kBilerp_FilterMode; } } newTexParams.fMinFilter = glMinFilterModes[filterMode]; newTexParams.fMagFilter = glMagFilterModes[filterMode]; - if (GrPixelConfigIsSRGB(texture->config())) { + if (this->glCaps().srgbDecodeDisableSupport() && GrPixelConfigIsSRGB(texture->config())) { newTexParams.fSRGBDecode = allowSRGBInputs ? GR_GL_DECODE_EXT : GR_GL_SKIP_DECODE_EXT; if (setAll || newTexParams.fSRGBDecode != oldTexParams.fSRGBDecode) { this->setTextureUnit(unitIdx); @@ -3240,12 +3045,13 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, bool allow #ifdef SK_DEBUG // We were supposed to ensure MipMaps were up-to-date and built correctly before getting here. - if (GrTextureParams::kMipMap_FilterMode == filterMode) { + if (GrSamplerParams::kMipMap_FilterMode == filterMode) { SkASSERT(!texture->texturePriv().mipMapsAreDirty()); if (GrPixelConfigIsSRGB(texture->config())) { - SkSourceGammaTreatment gammaTreatment = allowSRGBInputs ? - SkSourceGammaTreatment::kRespect : SkSourceGammaTreatment::kIgnore; - SkASSERT(texture->texturePriv().gammaTreatment() == gammaTreatment); + SkDestinationSurfaceColorMode colorMode = allowSRGBInputs + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; + SkASSERT(texture->texturePriv().mipColorMode() == colorMode); } } #endif @@ -3338,30 +3144,52 @@ void GrGLGpu::bindTexelBuffer(int unitIdx, GrPixelConfig texelConfig, GrGLBuffer } } -void GrGLGpu::generateMipmaps(const GrTextureParams& params, bool allowSRGBInputs, +void GrGLGpu::bindImageStorage(int unitIdx, GrIOType ioType, GrGLTexture *texture) { + SkASSERT(texture); + if (texture->uniqueID() != fHWBoundImageStorages[unitIdx].fTextureUniqueID || + ioType != fHWBoundImageStorages[unitIdx].fIOType) { + GrGLenum access = GR_GL_READ_ONLY; + switch (ioType) { + case kRead_GrIOType: + access = GR_GL_READ_ONLY; + break; + case kWrite_GrIOType: + access = GR_GL_WRITE_ONLY; + break; + case kRW_GrIOType: + access = GR_GL_READ_WRITE; + break; + } + GrGLenum format = this->glCaps().getImageFormat(texture->config()); + GL_CALL(BindImageTexture(unitIdx, texture->textureID(), 0, GR_GL_FALSE, 0, access, format)); + } +} + +void GrGLGpu::generateMipmaps(const GrSamplerParams& params, bool allowSRGBInputs, GrGLTexture* texture) { SkASSERT(texture); // First, figure out if we need mips for this texture at all: - GrTextureParams::FilterMode filterMode = params.filterMode(); + GrSamplerParams::FilterMode filterMode = params.filterMode(); - if (GrTextureParams::kMipMap_FilterMode == filterMode) { + if (GrSamplerParams::kMipMap_FilterMode == filterMode) { if (!this->caps()->mipMapSupport() || GrPixelConfigIsCompressed(texture->config())) { - filterMode = GrTextureParams::kBilerp_FilterMode; + filterMode = GrSamplerParams::kBilerp_FilterMode; } } - if (GrTextureParams::kMipMap_FilterMode != filterMode) { + if (GrSamplerParams::kMipMap_FilterMode != filterMode) { return; } // If this is an sRGB texture and the mips were previously built the "other" way // (gamma-correct vs. not), then we need to rebuild them. We don't need to check for // srgbSupport - we'll *never* get an sRGB pixel config if we don't support it. - SkSourceGammaTreatment gammaTreatment = allowSRGBInputs - ? SkSourceGammaTreatment::kRespect : SkSourceGammaTreatment::kIgnore; + SkDestinationSurfaceColorMode colorMode = allowSRGBInputs + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; if (GrPixelConfigIsSRGB(texture->config()) && - gammaTreatment != texture->texturePriv().gammaTreatment()) { + colorMode != texture->texturePriv().mipColorMode()) { texture->texturePriv().dirtyMipMaps(true); } @@ -3383,9 +3211,17 @@ void GrGLGpu::generateMipmaps(const GrTextureParams& params, bool allowSRGBInput // Configure sRGB decode, if necessary. This state is the only thing needed for the driver // call (glGenerateMipmap) to work correctly. Our manual method dirties other state, too. - if (GrPixelConfigIsSRGB(texture->config())) { - GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SRGB_DECODE_EXT, - allowSRGBInputs ? GR_GL_DECODE_EXT : GR_GL_SKIP_DECODE_EXT)); + if (this->glCaps().srgbDecodeDisableSupport() && GrPixelConfigIsSRGB(texture->config())) { + GrGLenum srgbDecode = allowSRGBInputs ? GR_GL_DECODE_EXT : GR_GL_SKIP_DECODE_EXT; + // Command buffer's sRGB decode extension doesn't influence mipmap generation correctly. + // If we set this to skip_decode, it appears to suppress sRGB -> Linear for each downsample, + // but not the Linear -> sRGB when writing the next level. The result is that mip-chains + // get progressively brighter as you go down. Forcing this to 'decode' gives predictable + // (and only slightly incorrect) results. See crbug.com/655247 (~comment 28) + if (!this->glCaps().srgbDecodeDisableAffectsMipmaps()) { + srgbDecode = GR_GL_DECODE_EXT; + } + GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SRGB_DECODE_EXT, srgbDecode)); } // Either do manual mipmap generation or (if that fails), just rely on the driver: @@ -3396,7 +3232,7 @@ void GrGLGpu::generateMipmaps(const GrTextureParams& params, bool allowSRGBInput texture->texturePriv().dirtyMipMaps(false); texture->texturePriv().setMaxMipMapLevel(SkMipMap::ComputeLevelCount( texture->width(), texture->height())); - texture->texturePriv().setGammaTreatment(gammaTreatment); + texture->texturePriv().setMipColorMode(colorMode); // We have potentially set lots of state on the texture. Easiest to dirty it all: texture->textureParamsModified(); @@ -3470,45 +3306,79 @@ void GrGLGpu::setScratchTextureUnit() { } // clear out the this field so that if a program does use this unit it will rebind the correct // texture. - fHWBoundTextureUniqueIDs[lastUnitIdx] = SK_InvalidUniqueID; + fHWBoundTextureUniqueIDs[lastUnitIdx].makeInvalid(); } -// Determines whether glBlitFramebuffer could be used between src and dst. -static inline bool can_blit_framebuffer(const GrSurface* dst, - const GrSurface* src, - const GrGLGpu* gpu) { - if (gpu->glCaps().isConfigRenderable(dst->config(), dst->desc().fSampleCnt > 0) && - gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0)) { - switch (gpu->glCaps().blitFramebufferSupport()) { - case GrGLCaps::kNone_BlitFramebufferSupport: - return false; - case GrGLCaps::kNoScalingNoMirroring_BlitFramebufferSupport: - // Our copy surface doesn't support scaling so just check for mirroring. - if (dst->origin() != src->origin()) { - return false; - } - break; - case GrGLCaps::kFull_BlitFramebufferSupport: - break; - } - // ES3 doesn't allow framebuffer blits when the src has MSAA and the configs don't match - // or the rects are not the same (not just the same size but have the same edges). - if (GrGLCaps::kES_3_0_MSFBOType == gpu->glCaps().msFBOType() && - (src->desc().fSampleCnt > 0 || src->config() != dst->config())) { - return false; - } - const GrGLTexture* dstTex = static_cast(dst->asTexture()); - if (dstTex && dstTex->target() != GR_GL_TEXTURE_2D) { - return false; - } - const GrGLTexture* srcTex = static_cast(dst->asTexture()); - if (srcTex && srcTex->target() != GR_GL_TEXTURE_2D) { - return false; - } - return true; - } else { +// Determines whether glBlitFramebuffer could be used between src and dst by onCopySurface. +static inline bool can_blit_framebuffer_for_copy_surface(const GrSurface* dst, + const GrSurface* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint, + const GrGLGpu* gpu) { + auto blitFramebufferFlags = gpu->glCaps().blitFramebufferSupportFlags(); + if (!gpu->glCaps().canConfigBeFBOColorAttachment(dst->config()) || + !gpu->glCaps().canConfigBeFBOColorAttachment(src->config())) { return false; } + // Blits are not allowed between int color buffers and float/fixed color buffers. GrGpu should + // have filtered such cases out. + SkASSERT(GrPixelConfigIsSint(dst->config()) == GrPixelConfigIsSint(src->config())); + const GrGLTexture* dstTex = static_cast(dst->asTexture()); + const GrGLTexture* srcTex = static_cast(dst->asTexture()); + const GrRenderTarget* dstRT = dst->asRenderTarget(); + const GrRenderTarget* srcRT = src->asRenderTarget(); + if (dstTex && dstTex->target() != GR_GL_TEXTURE_2D) { + return false; + } + if (srcTex && srcTex->target() != GR_GL_TEXTURE_2D) { + return false; + } + if (GrGLCaps::kNoSupport_BlitFramebufferFlag & blitFramebufferFlags) { + return false; + } + if (GrGLCaps::kNoScalingOrMirroring_BlitFramebufferFlag & blitFramebufferFlags) { + // We would mirror to compensate for origin changes. Note that copySurface is + // specified such that the src and dst rects are the same. + if (dst->origin() != src->origin()) { + return false; + } + } + if (GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag & blitFramebufferFlags) { + if (srcRT && srcRT->numColorSamples()) { + if (dstRT && !dstRT->numColorSamples()) { + return false; + } + if (SkRect::Make(srcRect) != srcRT->getBoundsRect()) { + return false; + } + } + } + if (GrGLCaps::kNoMSAADst_BlitFramebufferFlag & blitFramebufferFlags) { + if (dstRT && dstRT->numColorSamples() > 0) { + return false; + } + } + if (GrGLCaps::kNoFormatConversion_BlitFramebufferFlag & blitFramebufferFlags) { + if (dst->config() != src->config()) { + return false; + } + } else if (GrGLCaps::kNoFormatConversionForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) { + const GrRenderTarget* srcRT = src->asRenderTarget(); + if (srcRT && srcRT->numColorSamples() && dst->config() != src->config()) { + return false; + } + } + if (GrGLCaps::kRectsMustMatchForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) { + if (srcRT && srcRT->numColorSamples()) { + if (dstPoint.fX != srcRect.fLeft || dstPoint.fY != srcRect.fTop) { + return false; + } + if (dst->origin() != src->origin()) { + return false; + } + } + } + return true; } static inline bool can_copy_texsubimage(const GrSurface* dst, @@ -3545,10 +3415,9 @@ static inline bool can_copy_texsubimage(const GrSurface* dst, // Check that we could wrap the source in an FBO, that the dst is TEXTURE_2D, that no mirroring // is required. - if (gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) && + if (gpu->glCaps().canConfigBeFBOColorAttachment(src->config()) && !GrPixelConfigIsCompressed(src->config()) && - (!srcTex || srcTex->target() == GR_GL_TEXTURE_2D) && - dstTex->target() == GR_GL_TEXTURE_2D && + (!srcTex || srcTex->target() == GR_GL_TEXTURE_2D) && dstTex->target() == GR_GL_TEXTURE_2D && dst->origin() == src->origin()) { return true; } else { @@ -3558,8 +3427,8 @@ static inline bool can_copy_texsubimage(const GrSurface* dst, // If a temporary FBO was created, its non-zero ID is returned. The viewport that the copy rect is // relative to is output. -void GrGLGpu::bindSurfaceFBOForCopy(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, - TempFBOTarget tempFBOTarget) { +void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, + TempFBOTarget tempFBOTarget) { GrGLRenderTarget* rt = static_cast(surface->asRenderTarget()); if (!rt) { SkASSERT(surface->asTexture()); @@ -3590,8 +3459,8 @@ void GrGLGpu::bindSurfaceFBOForCopy(GrSurface* surface, GrGLenum fboTarget, GrGL } } -void GrGLGpu::unbindTextureFBOForCopy(GrGLenum fboTarget, GrSurface* surface) { - // bindSurfaceFBOForCopy temporarily binds textures that are not render targets to +void GrGLGpu::unbindTextureFBOForPixelOps(GrGLenum fboTarget, GrSurface* surface) { + // bindSurfaceFBOForPixelOps temporarily binds textures that are not render targets to if (!surface->asRenderTarget()) { SkASSERT(surface->asTexture()); GrGLenum textureTarget = static_cast(surface->asTexture())->target(); @@ -3603,75 +3472,14 @@ void GrGLGpu::unbindTextureFBOForCopy(GrGLenum fboTarget, GrSurface* surface) { } } -bool GrGLGpu::initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const { - // If the src is a texture, we can implement the blit as a draw assuming the config is - // renderable. - if (src->asTexture() && this->caps()->isConfigRenderable(src->config(), false)) { - desc->fOrigin = kDefault_GrSurfaceOrigin; - desc->fFlags = kRenderTarget_GrSurfaceFlag; - desc->fConfig = src->config(); - return true; - } - - const GrGLTexture* srcTexture = static_cast(src->asTexture()); - if (srcTexture && srcTexture->target() != GR_GL_TEXTURE_2D) { - // Not supported for FBO blit or CopyTexSubImage - return false; - } - - // We look for opportunities to use CopyTexSubImage, or fbo blit. If neither are - // possible and we return false to fallback to creating a render target dst for render-to- - // texture. This code prefers CopyTexSubImage to fbo blit and avoids triggering temporary fbo - // creation. It isn't clear that avoiding temporary fbo creation is actually optimal. - - GrSurfaceOrigin originForBlitFramebuffer = kDefault_GrSurfaceOrigin; - if (this->glCaps().blitFramebufferSupport() == - GrGLCaps::kNoScalingNoMirroring_BlitFramebufferSupport) { - originForBlitFramebuffer = src->origin(); - } - - // Check for format issues with glCopyTexSubImage2D - if (kGLES_GrGLStandard == this->glStandard() && this->glCaps().bgraIsInternalFormat() && - kBGRA_8888_GrPixelConfig == src->config()) { - // glCopyTexSubImage2D doesn't work with this config. If the bgra can be used with fbo blit - // then we set up for that, otherwise fail. - if (this->caps()->isConfigRenderable(kBGRA_8888_GrPixelConfig, false)) { - desc->fOrigin = originForBlitFramebuffer; - desc->fFlags = kRenderTarget_GrSurfaceFlag; - desc->fConfig = kBGRA_8888_GrPixelConfig; - return true; - } - return false; - } - - const GrGLRenderTarget* srcRT = static_cast(src); - if (srcRT->renderFBOID() != srcRT->textureFBOID()) { - // It's illegal to call CopyTexSubImage2D on a MSAA renderbuffer. Set up for FBO blit or - // fail. - if (this->caps()->isConfigRenderable(src->config(), false)) { - desc->fOrigin = originForBlitFramebuffer; - desc->fFlags = kRenderTarget_GrSurfaceFlag; - desc->fConfig = src->config(); - return true; - } - return false; - } - - // We'll do a CopyTexSubImage. Make the dst a plain old texture. - desc->fConfig = src->config(); - desc->fOrigin = src->origin(); - desc->fFlags = kNone_GrSurfaceFlags; - return true; -} - bool GrGLGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { // None of our copy methods can handle a swizzle. TODO: Make copySurfaceAsDraw handle the // swizzle. - if (this->glCaps().glslCaps()->configOutputSwizzle(src->config()) != - this->glCaps().glslCaps()->configOutputSwizzle(dst->config())) { + if (this->caps()->shaderCaps()->configOutputSwizzle(src->config()) != + this->caps()->shaderCaps()->configOutputSwizzle(dst->config())) { return false; } // Don't prefer copying as a draw if the dst doesn't already have a FBO object. @@ -3687,7 +3495,7 @@ bool GrGLGpu::onCopySurface(GrSurface* dst, return true; } - if (can_blit_framebuffer(dst, src, this)) { + if (can_blit_framebuffer_for_copy_surface(dst, src, srcRect, dstPoint, this)) { return this->copySurfaceAsBlitFramebuffer(dst, src, srcRect, dstPoint); } @@ -3700,19 +3508,10 @@ bool GrGLGpu::onCopySurface(GrSurface* dst, return false; } -bool GrGLGpu::createCopyProgram(int progIdx) { - const GrGLSLCaps* glslCaps = this->glCaps().glslCaps(); - static const GrSLType kSamplerTypes[3] = { kTexture2DSampler_GrSLType, - kTextureExternalSampler_GrSLType, - kTexture2DRectSampler_GrSLType }; - if (kTextureExternalSampler_GrSLType == kSamplerTypes[progIdx] && - !this->glCaps().glslCaps()->externalTextureSupport()) { - return false; - } - if (kTexture2DRectSampler_GrSLType == kSamplerTypes[progIdx] && - !this->glCaps().rectangleTextureSupport()) { - return false; - } +bool GrGLGpu::createCopyProgram(GrTexture* srcTex) { + int progIdx = TextureToCopyProgramIdx(srcTex); + const GrShaderCaps* shaderCaps = this->caps()->shaderCaps(); + GrSLType samplerType = srcTex->texturePriv().samplerType(); if (!fCopyProgramArrayBuffer) { static const GrGLfloat vdata[] = { @@ -3734,34 +3533,30 @@ bool GrGLGpu::createCopyProgram(int progIdx) { return false; } - const char* version = glslCaps->versionDeclString(); - GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier); - GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType, - GrShaderVar::kUniform_TypeModifier); - GrGLSLShaderVar uPosXform("u_posXform", kVec4f_GrSLType, - GrShaderVar::kUniform_TypeModifier); - GrGLSLShaderVar uTexture("u_texture", kSamplerTypes[progIdx], - GrShaderVar::kUniform_TypeModifier); - GrGLSLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, - GrShaderVar::kVaryingOut_TypeModifier); - GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, - GrShaderVar::kOut_TypeModifier); + const char* version = shaderCaps->versionDeclString(); + GrShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kIn_TypeModifier); + GrShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType, + GrShaderVar::kUniform_TypeModifier); + GrShaderVar uPosXform("u_posXform", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); + GrShaderVar uTexture("u_texture", samplerType, GrShaderVar::kUniform_TypeModifier); + GrShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, GrShaderVar::kOut_TypeModifier); + GrShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier); SkString vshaderTxt(version); - if (glslCaps->noperspectiveInterpolationSupport()) { - if (const char* extension = glslCaps->noperspectiveInterpolationExtensionString()) { + if (shaderCaps->noperspectiveInterpolationSupport()) { + if (const char* extension = shaderCaps->noperspectiveInterpolationExtensionString()) { vshaderTxt.appendf("#extension %s : require\n", extension); } vTexCoord.addModifier("noperspective"); } - aVertex.appendDecl(glslCaps, &vshaderTxt); + aVertex.appendDecl(shaderCaps, &vshaderTxt); vshaderTxt.append(";"); - uTexCoordXform.appendDecl(glslCaps, &vshaderTxt); + uTexCoordXform.appendDecl(shaderCaps, &vshaderTxt); vshaderTxt.append(";"); - uPosXform.appendDecl(glslCaps, &vshaderTxt); + uPosXform.appendDecl(shaderCaps, &vshaderTxt); vshaderTxt.append(";"); - vTexCoord.appendDecl(glslCaps, &vshaderTxt); + vTexCoord.appendDecl(shaderCaps, &vshaderTxt); vshaderTxt.append(";"); vshaderTxt.append( @@ -3774,37 +3569,27 @@ bool GrGLGpu::createCopyProgram(int progIdx) { ); SkString fshaderTxt(version); - if (glslCaps->noperspectiveInterpolationSupport()) { - if (const char* extension = glslCaps->noperspectiveInterpolationExtensionString()) { + if (shaderCaps->noperspectiveInterpolationSupport()) { + if (const char* extension = shaderCaps->noperspectiveInterpolationExtensionString()) { fshaderTxt.appendf("#extension %s : require\n", extension); } } - if (kSamplerTypes[progIdx] == kTextureExternalSampler_GrSLType) { + if (samplerType == kTextureExternalSampler_GrSLType) { fshaderTxt.appendf("#extension %s : require\n", - glslCaps->externalTextureExtensionString()); + shaderCaps->externalTextureExtensionString()); } - GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, *glslCaps, + GrGLSLAppendDefaultFloatPrecisionDeclaration(kMedium_GrSLPrecision, *shaderCaps, &fshaderTxt); - vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); - vTexCoord.appendDecl(glslCaps, &fshaderTxt); + vTexCoord.setTypeModifier(GrShaderVar::kIn_TypeModifier); + vTexCoord.appendDecl(shaderCaps, &fshaderTxt); fshaderTxt.append(";"); - uTexture.appendDecl(glslCaps, &fshaderTxt); + uTexture.appendDecl(shaderCaps, &fshaderTxt); fshaderTxt.append(";"); - const char* fsOutName; - if (glslCaps->mustDeclareFragmentShaderOutput()) { - oFragColor.appendDecl(glslCaps, &fshaderTxt); - fshaderTxt.append(";"); - fsOutName = oFragColor.c_str(); - } else { - fsOutName = "gl_FragColor"; - } fshaderTxt.appendf( "// Copy Program FS\n" "void main() {" - " %s = %s(u_texture, v_texCoord);" - "}", - fsOutName, - GrGLSLTexture2DFunctionName(kVec2f_GrSLType, kSamplerTypes[progIdx], this->glslGeneration()) + " sk_FragColor = texture(u_texture, v_texCoord);" + "}" ); const char* str; @@ -3812,15 +3597,20 @@ bool GrGLGpu::createCopyProgram(int progIdx) { str = vshaderTxt.c_str(); length = SkToInt(vshaderTxt.size()); + SkSL::Program::Settings settings; + settings.fCaps = shaderCaps; + SkSL::Program::Inputs inputs; GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram, GR_GL_VERTEX_SHADER, &str, &length, 1, - &fStats); + &fStats, settings, &inputs); + SkASSERT(inputs.isEmpty()); str = fshaderTxt.c_str(); length = SkToInt(fshaderTxt.size()); GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram, GR_GL_FRAGMENT_SHADER, &str, &length, 1, - &fStats); + &fStats, settings, &inputs); + SkASSERT(inputs.isEmpty()); GL_CALL(LinkProgram(fCopyPrograms[progIdx].fProgram)); @@ -3844,7 +3634,7 @@ bool GrGLGpu::createMipmapProgram(int progIdx) { const bool oddHeight = SkToBool(progIdx & 0x1); const int numTaps = (oddWidth ? 2 : 1) * (oddHeight ? 2 : 1); - const GrGLSLCaps* glslCaps = this->glCaps().glslCaps(); + const GrShaderCaps* shaderCaps = this->caps()->shaderCaps(); SkASSERT(!fMipmapPrograms[progIdx].fProgram); GL_CALL_RET(fMipmapPrograms[progIdx].fProgram, CreateProgram()); @@ -3852,25 +3642,24 @@ bool GrGLGpu::createMipmapProgram(int progIdx) { return false; } - const char* version = glslCaps->versionDeclString(); - GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier); - GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType, - GrShaderVar::kUniform_TypeModifier); - GrGLSLShaderVar uTexture("u_texture", kTexture2DSampler_GrSLType, - GrShaderVar::kUniform_TypeModifier); + const char* version = shaderCaps->versionDeclString(); + GrShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kIn_TypeModifier); + GrShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType, + GrShaderVar::kUniform_TypeModifier); + GrShaderVar uTexture("u_texture", kTexture2DSampler_GrSLType, + GrShaderVar::kUniform_TypeModifier); // We need 1, 2, or 4 texture coordinates (depending on parity of each dimension): - GrGLSLShaderVar vTexCoords[] = { - GrGLSLShaderVar("v_texCoord0", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier), - GrGLSLShaderVar("v_texCoord1", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier), - GrGLSLShaderVar("v_texCoord2", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier), - GrGLSLShaderVar("v_texCoord3", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier), + GrShaderVar vTexCoords[] = { + GrShaderVar("v_texCoord0", kVec2f_GrSLType, GrShaderVar::kOut_TypeModifier), + GrShaderVar("v_texCoord1", kVec2f_GrSLType, GrShaderVar::kOut_TypeModifier), + GrShaderVar("v_texCoord2", kVec2f_GrSLType, GrShaderVar::kOut_TypeModifier), + GrShaderVar("v_texCoord3", kVec2f_GrSLType, GrShaderVar::kOut_TypeModifier), }; - GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, - GrShaderVar::kOut_TypeModifier); + GrShaderVar oFragColor("o_FragColor", kVec4f_GrSLType,GrShaderVar::kOut_TypeModifier); SkString vshaderTxt(version); - if (glslCaps->noperspectiveInterpolationSupport()) { - if (const char* extension = glslCaps->noperspectiveInterpolationExtensionString()) { + if (shaderCaps->noperspectiveInterpolationSupport()) { + if (const char* extension = shaderCaps->noperspectiveInterpolationExtensionString()) { vshaderTxt.appendf("#extension %s : require\n", extension); } vTexCoords[0].addModifier("noperspective"); @@ -3879,12 +3668,12 @@ bool GrGLGpu::createMipmapProgram(int progIdx) { vTexCoords[3].addModifier("noperspective"); } - aVertex.appendDecl(glslCaps, &vshaderTxt); + aVertex.appendDecl(shaderCaps, &vshaderTxt); vshaderTxt.append(";"); - uTexCoordXform.appendDecl(glslCaps, &vshaderTxt); + uTexCoordXform.appendDecl(shaderCaps, &vshaderTxt); vshaderTxt.append(";"); for (int i = 0; i < numTaps; ++i) { - vTexCoords[i].appendDecl(glslCaps, &vshaderTxt); + vTexCoords[i].appendDecl(shaderCaps, &vshaderTxt); vshaderTxt.append(";"); } @@ -3922,51 +3711,40 @@ bool GrGLGpu::createMipmapProgram(int progIdx) { vshaderTxt.append("}"); SkString fshaderTxt(version); - if (glslCaps->noperspectiveInterpolationSupport()) { - if (const char* extension = glslCaps->noperspectiveInterpolationExtensionString()) { + if (shaderCaps->noperspectiveInterpolationSupport()) { + if (const char* extension = shaderCaps->noperspectiveInterpolationExtensionString()) { fshaderTxt.appendf("#extension %s : require\n", extension); } } - GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, *glslCaps, + GrGLSLAppendDefaultFloatPrecisionDeclaration(kMedium_GrSLPrecision, *shaderCaps, &fshaderTxt); for (int i = 0; i < numTaps; ++i) { - vTexCoords[i].setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); - vTexCoords[i].appendDecl(glslCaps, &fshaderTxt); + vTexCoords[i].setTypeModifier(GrShaderVar::kIn_TypeModifier); + vTexCoords[i].appendDecl(shaderCaps, &fshaderTxt); fshaderTxt.append(";"); } - uTexture.appendDecl(glslCaps, &fshaderTxt); + uTexture.appendDecl(shaderCaps, &fshaderTxt); fshaderTxt.append(";"); - const char* fsOutName; - if (glslCaps->mustDeclareFragmentShaderOutput()) { - oFragColor.appendDecl(glslCaps, &fshaderTxt); - fshaderTxt.append(";"); - fsOutName = oFragColor.c_str(); - } else { - fsOutName = "gl_FragColor"; - } - const char* sampleFunction = GrGLSLTexture2DFunctionName(kVec2f_GrSLType, - kTexture2DSampler_GrSLType, - this->glslGeneration()); fshaderTxt.append( "// Mipmap Program FS\n" "void main() {" ); if (oddWidth && oddHeight) { - fshaderTxt.appendf( - " %s = (%s(u_texture, v_texCoord0) + %s(u_texture, v_texCoord1) + " - " %s(u_texture, v_texCoord2) + %s(u_texture, v_texCoord3)) * 0.25;", - fsOutName, sampleFunction, sampleFunction, sampleFunction, sampleFunction + fshaderTxt.append( + " sk_FragColor = (texture(u_texture, v_texCoord0) + " + " texture(u_texture, v_texCoord1) + " + " texture(u_texture, v_texCoord2) + " + " texture(u_texture, v_texCoord3)) * 0.25;" ); } else if (oddWidth || oddHeight) { - fshaderTxt.appendf( - " %s = (%s(u_texture, v_texCoord0) + %s(u_texture, v_texCoord1)) * 0.5;", - fsOutName, sampleFunction, sampleFunction + fshaderTxt.append( + " sk_FragColor = (texture(u_texture, v_texCoord0) + " + " texture(u_texture, v_texCoord1)) * 0.5;" ); } else { - fshaderTxt.appendf( - " %s = %s(u_texture, v_texCoord0);", - fsOutName, sampleFunction + fshaderTxt.append( + " sk_FragColor = texture(u_texture, v_texCoord0);" ); } @@ -3977,15 +3755,20 @@ bool GrGLGpu::createMipmapProgram(int progIdx) { str = vshaderTxt.c_str(); length = SkToInt(vshaderTxt.size()); + SkSL::Program::Settings settings; + settings.fCaps = shaderCaps; + SkSL::Program::Inputs inputs; GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram, GR_GL_VERTEX_SHADER, &str, &length, 1, - &fStats); + &fStats, settings, &inputs); + SkASSERT(inputs.isEmpty()); str = fshaderTxt.c_str(); length = SkToInt(fshaderTxt.size()); GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram, GR_GL_FRAGMENT_SHADER, &str, &length, 1, - &fStats); + &fStats, settings, &inputs); + SkASSERT(inputs.isEmpty()); GL_CALL(LinkProgram(fMipmapPrograms[progIdx].fProgram)); @@ -4023,18 +3806,18 @@ bool GrGLGpu::createWireRectProgram() { return false; } - GrGLSLShaderVar uColor("u_color", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); - GrGLSLShaderVar uRect("u_rect", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); - GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier); - const char* version = this->glCaps().glslCaps()->versionDeclString(); + GrShaderVar uColor("u_color", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); + GrShaderVar uRect("u_rect", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); + GrShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kIn_TypeModifier); + const char* version = this->caps()->shaderCaps()->versionDeclString(); // The rect uniform specifies the rectangle in NDC space as a vec4 (left,top,right,bottom). The // program is used with a vbo containing the unit square. Vertices are computed from the rect // uniform using the 4 vbo vertices. SkString vshaderTxt(version); - aVertex.appendDecl(this->glCaps().glslCaps(), &vshaderTxt); + aVertex.appendDecl(this->caps()->shaderCaps(), &vshaderTxt); vshaderTxt.append(";"); - uRect.appendDecl(this->glCaps().glslCaps(), &vshaderTxt); + uRect.appendDecl(this->caps()->shaderCaps(), &vshaderTxt); vshaderTxt.append(";"); vshaderTxt.append( "// Wire Rect Program VS\n" @@ -4045,28 +3828,19 @@ bool GrGLGpu::createWireRectProgram() { "}" ); - GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier); + GrShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier); SkString fshaderTxt(version); - GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, - *this->glCaps().glslCaps(), + GrGLSLAppendDefaultFloatPrecisionDeclaration(kMedium_GrSLPrecision, + *this->caps()->shaderCaps(), &fshaderTxt); - uColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt); + uColor.appendDecl(this->caps()->shaderCaps(), &fshaderTxt); fshaderTxt.append(";"); - const char* fsOutName; - if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) { - oFragColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt); - fshaderTxt.append(";"); - fsOutName = oFragColor.c_str(); - } else { - fsOutName = "gl_FragColor"; - } fshaderTxt.appendf( "// Write Rect Program FS\n" "void main() {" - " %s = %s;" + " sk_FragColor = %s;" "}", - fsOutName, uColor.c_str() ); @@ -4075,15 +3849,20 @@ bool GrGLGpu::createWireRectProgram() { str = vshaderTxt.c_str(); length = SkToInt(vshaderTxt.size()); + SkSL::Program::Settings settings; + settings.fCaps = this->caps()->shaderCaps(); + SkSL::Program::Inputs inputs; GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fWireRectProgram.fProgram, GR_GL_VERTEX_SHADER, &str, &length, 1, - &fStats); + &fStats, settings, &inputs); + SkASSERT(inputs.isEmpty()); str = fshaderTxt.c_str(); length = SkToInt(fshaderTxt.size()); GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fWireRectProgram.fProgram, GR_GL_FRAGMENT_SHADER, &str, &length, 1, - &fStats); + &fStats, settings, &inputs); + SkASSERT(inputs.isEmpty()); GL_CALL(LinkProgram(fWireRectProgram.fProgram)); @@ -4147,8 +3926,8 @@ void GrGLGpu::drawDebugWireRect(GrRenderTarget* rt, const SkIRect& rect, GrColor fHWVertexArrayState.setVertexArrayID(this, 0); GrGLAttribArrayState* attribs = fHWVertexArrayState.bindInternalVertexArray(this); - attribs->set(this, 0, fWireRectArrayBuffer, kVec2f_GrVertexAttribType, 2 * sizeof(GrGLfloat), - 0); + attribs->set(this, 0, fWireRectArrayBuffer.get(), kVec2f_GrVertexAttribType, + 2 * sizeof(GrGLfloat), 0); attribs->disableUnusedArrays(this, 0x1); GL_CALL(Uniform4fv(fWireRectProgram.fRectUniform, 1, edges)); @@ -4162,9 +3941,7 @@ void GrGLGpu::drawDebugWireRect(GrRenderTarget* rt, const SkIRect& rect, GrColor this->flushHWAAState(glRT, false, false); this->disableScissor(); this->disableWindowRectangles(); - GrStencilSettings stencil; - stencil.setDisabled(); - this->flushStencil(stencil); + this->disableStencil(); GL_CALL(DrawArrays(GR_GL_LINE_LOOP, 0, 4)); } @@ -4175,10 +3952,10 @@ bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, const SkIRect& srcRect, const SkIPoint& dstPoint) { GrGLTexture* srcTex = static_cast(src->asTexture()); - int progIdx = TextureTargetToCopyProgramIdx(srcTex->target()); + int progIdx = TextureToCopyProgramIdx(srcTex); if (!fCopyPrograms[progIdx].fProgram) { - if (!this->createCopyProgram(progIdx)) { + if (!this->createCopyProgram(srcTex)) { SkDebugf("Failed to create copy program.\n"); return false; } @@ -4187,13 +3964,13 @@ bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, int w = srcRect.width(); int h = srcRect.height(); - GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode); + GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode); this->bindTexture(0, params, true, srcTex); GrGLIRect dstVP; - this->bindSurfaceFBOForCopy(dst, GR_GL_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget); + this->bindSurfaceFBOForPixelOps(dst, GR_GL_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget); this->flushViewport(dstVP); - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fHWBoundRenderTargetUniqueID.makeInvalid(); SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h); @@ -4203,8 +3980,8 @@ bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, fHWVertexArrayState.setVertexArrayID(this, 0); GrGLAttribArrayState* attribs = fHWVertexArrayState.bindInternalVertexArray(this); - attribs->set(this, 0, fCopyProgramArrayBuffer, kVec2f_GrVertexAttribType, 2 * sizeof(GrGLfloat), - 0); + attribs->set(this, 0, fCopyProgramArrayBuffer.get(), kVec2f_GrVertexAttribType, + 2 * sizeof(GrGLfloat), 0); attribs->disableUnusedArrays(this, 0x1); // dst rect edges in NDC (-1 to 1) @@ -4251,12 +4028,10 @@ bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, this->flushHWAAState(nullptr, false, false); this->disableScissor(); this->disableWindowRectangles(); - GrStencilSettings stencil; - stencil.setDisabled(); - this->flushStencil(stencil); + this->disableStencil(); GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4)); - this->unbindTextureFBOForCopy(GR_GL_FRAMEBUFFER, dst); + this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, dst); this->didWriteToSurface(dst, &dstRect); return true; @@ -4268,11 +4043,11 @@ void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, const SkIPoint& dstPoint) { SkASSERT(can_copy_texsubimage(dst, src, this)); GrGLIRect srcVP; - this->bindSurfaceFBOForCopy(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); + this->bindSurfaceFBOForPixelOps(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); GrGLTexture* dstTex = static_cast(dst->asTexture()); SkASSERT(dstTex); // We modified the bound FBO - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fHWBoundRenderTargetUniqueID.makeInvalid(); GrGLIRect srcGLRect; srcGLRect.setRelativeTo(srcVP, srcRect.fLeft, @@ -4293,7 +4068,7 @@ void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, dstPoint.fX, dstY, srcGLRect.fLeft, srcGLRect.fBottom, srcGLRect.fWidth, srcGLRect.fHeight)); - this->unbindTextureFBOForCopy(GR_GL_FRAMEBUFFER, src); + this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, src); SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, srcRect.width(), srcRect.height()); this->didWriteToSurface(dst, &dstRect); @@ -4303,7 +4078,7 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { - SkASSERT(can_blit_framebuffer(dst, src, this)); + SkASSERT(can_blit_framebuffer_for_copy_surface(dst, src, srcRect, dstPoint, this)); SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, srcRect.width(), srcRect.height()); if (dst == src) { @@ -4314,10 +4089,10 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, GrGLIRect dstVP; GrGLIRect srcVP; - this->bindSurfaceFBOForCopy(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget); - this->bindSurfaceFBOForCopy(src, GR_GL_READ_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); + this->bindSurfaceFBOForPixelOps(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget); + this->bindSurfaceFBOForPixelOps(src, GR_GL_READ_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); // We modified the bound FBO - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fHWBoundRenderTargetUniqueID.makeInvalid(); GrGLIRect srcGLRect; GrGLIRect dstGLRect; srcGLRect.setRelativeTo(srcVP, @@ -4356,8 +4131,8 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, dstGLRect.fLeft + dstGLRect.fWidth, dstGLRect.fBottom + dstGLRect.fHeight, GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); - this->unbindTextureFBOForCopy(GR_GL_DRAW_FRAMEBUFFER, dst); - this->unbindTextureFBOForCopy(GR_GL_READ_FRAMEBUFFER, src); + this->unbindTextureFBOForPixelOps(GR_GL_DRAW_FRAMEBUFFER, dst); + this->unbindTextureFBOForPixelOps(GR_GL_READ_FRAMEBUFFER, src); this->didWriteToSurface(dst, &dstRect); return true; } @@ -4366,6 +4141,7 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, // Uses draw calls to do a series of downsample operations to successive mips. // If this returns false, then the calling code falls back to using glGenerateMipmap. bool GrGLGpu::generateMipmap(GrGLTexture* texture, bool gammaCorrect) { + SkASSERT(!GrPixelConfigIsSint(texture->config())); // Our iterative downsample requires the ability to limit which level we're sampling: if (!this->glCaps().doManualMipmapping()) { return false; @@ -4377,7 +4153,7 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, bool gammaCorrect) { } // We need to be able to render to the texture for this to work: - if (!this->caps()->isConfigRenderable(texture->config(), false)) { + if (!this->glCaps().canConfigBeFBOColorAttachment(texture->config())) { return false; } @@ -4421,12 +4197,12 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, bool gammaCorrect) { GL_CALL(GenFramebuffers(1, &fTempDstFBOID)); } GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fTempDstFBOID)); - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fHWBoundRenderTargetUniqueID.makeInvalid(); // Bind the texture, to get things configured for filtering. // We'll be changing our base level further below: this->setTextureUnit(0); - GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); + GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode); this->bindTexture(0, params, gammaCorrect, texture); // Vertex data: @@ -4448,7 +4224,7 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, bool gammaCorrect) { fHWVertexArrayState.setVertexArrayID(this, 0); GrGLAttribArrayState* attribs = fHWVertexArrayState.bindInternalVertexArray(this); - attribs->set(this, 0, fMipmapProgramArrayBuffer, kVec2f_GrVertexAttribType, + attribs->set(this, 0, fMipmapProgramArrayBuffer.get(), kVec2f_GrVertexAttribType, 2 * sizeof(GrGLfloat), 0); attribs->disableUnusedArrays(this, 0x1); @@ -4461,9 +4237,7 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, bool gammaCorrect) { this->flushHWAAState(nullptr, false, false); this->disableScissor(); this->disableWindowRectangles(); - GrStencilSettings stencil; - stencil.setDisabled(); - this->flushStencil(stencil); + this->disableStencil(); // Do all the blits: width = texture->width(); @@ -4512,8 +4286,8 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, bool gammaCorrect) { return true; } -void GrGLGpu::onGetMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings& stencil, - int* effectiveSampleCnt, SamplePattern* samplePattern) { +void GrGLGpu::onQueryMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings& stencil, + int* effectiveSampleCnt, SamplePattern* samplePattern) { SkASSERT(!rt->isMixedSampled() || rt->renderTargetPriv().getStencilAttachment() || stencil.isDisabled()); @@ -4572,14 +4346,14 @@ GrBackendObject GrGLGpu::createTestingOnlyBackendTexture(void* pixels, int w, in if (!this->caps()->isConfigTexturable(config)) { return false; } - GrGLTextureInfo* info = new GrGLTextureInfo; + std::unique_ptr info = skstd::make_unique(); info->fTarget = GR_GL_TEXTURE_2D; info->fID = 0; GL_CALL(GenTextures(1, &info->fID)); GL_CALL(ActiveTexture(GR_GL_TEXTURE0)); GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1)); GL_CALL(BindTexture(info->fTarget, info->fID)); - fHWBoundTextureUniqueIDs[0] = 0; + fHWBoundTextureUniqueIDs[0].makeInvalid(); GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST)); GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST)); GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE)); @@ -4591,32 +4365,17 @@ GrBackendObject GrGLGpu::createTestingOnlyBackendTexture(void* pixels, int w, in if (!this->glCaps().getTexImageFormats(config, config, &internalFormat, &externalFormat, &externalType)) { - delete info; -#ifdef SK_IGNORE_GL_TEXTURE_TARGET - return 0; -#else return reinterpret_cast(nullptr); -#endif } GL_CALL(TexImage2D(info->fTarget, 0, internalFormat, w, h, 0, externalFormat, externalType, pixels)); -#ifdef SK_IGNORE_GL_TEXTURE_TARGET - GrGLuint id = info->fID; - delete info; - return id; -#else - return reinterpret_cast(info); -#endif + return reinterpret_cast(info.release()); } bool GrGLGpu::isTestingOnlyBackendTexture(GrBackendObject id) const { -#ifdef SK_IGNORE_GL_TEXTURE_TARGET - GrGLuint texID = (GrGLuint)id; -#else GrGLuint texID = reinterpret_cast(id)->fID; -#endif GrGLboolean result; GL_CALL_RET(result, IsTexture(texID)); @@ -4625,20 +4384,12 @@ bool GrGLGpu::isTestingOnlyBackendTexture(GrBackendObject id) const { } void GrGLGpu::deleteTestingOnlyBackendTexture(GrBackendObject id, bool abandonTexture) { -#ifdef SK_IGNORE_GL_TEXTURE_TARGET - GrGLuint texID = (GrGLuint)id; -#else - const GrGLTextureInfo* info = reinterpret_cast(id); + std::unique_ptr info(reinterpret_cast(id)); GrGLuint texID = info->fID; -#endif if (!abandonTexture) { GL_CALL(DeleteTextures(1, &texID)); } - -#ifndef SK_IGNORE_GL_TEXTURE_TARGET - delete info; -#endif } void GrGLGpu::resetShaderCacheForTesting() const { @@ -4679,14 +4430,23 @@ GrGLAttribArrayState* GrGLGpu::HWVertexArrayState::bindInternalVertexArray(GrGLG return attribState; } -bool GrGLGpu::onMakeCopyForTextureParams(GrTexture* texture, const GrTextureParams& textureParams, - GrTextureProducer::CopyParams* copyParams) const { +bool GrGLGpu::onIsACopyNeededForTextureParams(GrTextureProxy* proxy, + const GrSamplerParams& textureParams, + GrTextureProducer::CopyParams* copyParams, + SkScalar scaleAdjust[2]) const { + const GrTexture* texture = proxy->priv().peekTexture(); + if (!texture) { + // The only way to get and EXTERNAL or RECTANGLE texture in Ganesh is to wrap them. + // In that case the proxy should already be instantiated. + return false; + } + if (textureParams.isTiled() || - GrTextureParams::kMipMap_FilterMode == textureParams.filterMode()) { - GrGLTexture* glTexture = static_cast(texture); + GrSamplerParams::kMipMap_FilterMode == textureParams.filterMode()) { + const GrGLTexture* glTexture = static_cast(texture); if (GR_GL_TEXTURE_EXTERNAL == glTexture->target() || GR_GL_TEXTURE_RECTANGLE == glTexture->target()) { - copyParams->fFilter = GrTextureParams::kNone_FilterMode; + copyParams->fFilter = GrSamplerParams::kNone_FilterMode; copyParams->fWidth = texture->width(); copyParams->fHeight = texture->height(); return true; @@ -4695,18 +4455,45 @@ bool GrGLGpu::onMakeCopyForTextureParams(GrTexture* texture, const GrTexturePara return false; } -GrFence SK_WARN_UNUSED_RESULT GrGLGpu::insertFence() const { - GrGLsync fence; - GL_CALL_RET(fence, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); - return (GrFence)fence; +GrFence SK_WARN_UNUSED_RESULT GrGLGpu::insertFence() { + GrGLsync sync; + GL_CALL_RET(sync, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); + GR_STATIC_ASSERT(sizeof(GrFence) >= sizeof(GrGLsync)); + return (GrFence)sync; } -bool GrGLGpu::waitFence(GrFence fence, uint64_t timeout) const { +bool GrGLGpu::waitFence(GrFence fence, uint64_t timeout) { GrGLenum result; GL_CALL_RET(result, ClientWaitSync((GrGLsync)fence, GR_GL_SYNC_FLUSH_COMMANDS_BIT, timeout)); return (GR_GL_CONDITION_SATISFIED == result); } void GrGLGpu::deleteFence(GrFence fence) const { - GL_CALL(DeleteSync((GrGLsync)fence)); + this->deleteSync((GrGLsync)fence); +} + +sk_sp SK_WARN_UNUSED_RESULT GrGLGpu::makeSemaphore() { + return GrGLSemaphore::Make(this); +} + +void GrGLGpu::insertSemaphore(sk_sp semaphore) { + GrGLSemaphore* glSem = static_cast(semaphore.get()); + + GrGLsync sync; + GL_CALL_RET(sync, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); + glSem->setSync(sync); +} + +void GrGLGpu::waitSemaphore(sk_sp semaphore) { + GrGLSemaphore* glSem = static_cast(semaphore.get()); + + GL_CALL(WaitSync(glSem->sync(), 0, GR_GL_TIMEOUT_IGNORED)); +} + +void GrGLGpu::deleteSync(GrGLsync sync) const { + GL_CALL(DeleteSync(sync)); +} + +void GrGLGpu::flush() { + GL_CALL(Flush()); } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLGpu.h b/gfx/skia/skia/src/gpu/gl/GrGLGpu.h index 7ba79b2eea08..1fc25576fe9b 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLGpu.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLGpu.h @@ -17,9 +17,10 @@ #include "GrGLTexture.h" #include "GrGLVertexArray.h" #include "GrGpu.h" -#include "GrTypes.h" +#include "GrTexturePriv.h" #include "GrWindowRectsState.h" #include "GrXferProcessor.h" +#include "SkLRUCache.h" #include "SkTArray.h" #include "SkTypes.h" @@ -57,12 +58,14 @@ public: } // Used by GrGLProgram to configure OpenGL state. - void bindTexture(int unitIdx, const GrTextureParams& params, bool allowSRGBInputs, + void bindTexture(int unitIdx, const GrSamplerParams& params, bool allowSRGBInputs, GrGLTexture* texture); void bindTexelBuffer(int unitIdx, GrPixelConfig, GrGLBuffer*); - void generateMipmaps(const GrTextureParams& params, bool allowSRGBInputs, GrGLTexture* texture); + void bindImageStorage(int unitIdx, GrIOType, GrGLTexture *); + + void generateMipmaps(const GrSamplerParams& params, bool allowSRGBInputs, GrGLTexture* texture); bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes, GrPixelConfig readConfig, DrawPreference*, @@ -72,8 +75,6 @@ public: GrPixelConfig srcConfig, DrawPreference*, WritePixelTempDrawInfo*) override; - bool initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const override; - // These functions should be used to bind GL objects. They track the GL state and skip redundant // bindings. Making the equivalent glBind calls directly will confuse the state tracking. void bindVertexArray(GrGLuint id) { @@ -120,12 +121,11 @@ public: void clearStencil(GrRenderTarget*) override; GrGpuCommandBuffer* createCommandBuffer( - GrRenderTarget* target, const GrGpuCommandBuffer::LoadAndStoreInfo& colorInfo, const GrGpuCommandBuffer::LoadAndStoreInfo& stencilInfo) override; void invalidateBoundRenderTarget() { - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fHWBoundRenderTargetUniqueID.makeInvalid(); } GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget* rt, @@ -142,12 +142,18 @@ public: void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override; - void finishDrawTarget() override; - - GrFence SK_WARN_UNUSED_RESULT insertFence() const override; - bool waitFence(GrFence, uint64_t timeout) const override; + GrFence SK_WARN_UNUSED_RESULT insertFence() override; + bool waitFence(GrFence, uint64_t timeout) override; void deleteFence(GrFence) const override; + sk_sp SK_WARN_UNUSED_RESULT makeSemaphore() override; + void insertSemaphore(sk_sp semaphore) override; + void waitSemaphore(sk_sp semaphore) override; + + void deleteSync(GrGLsync) const; + + void flush() override; + private: GrGLGpu(GrGLContext* ctx, GrContext* context); @@ -164,10 +170,9 @@ private: GrBuffer* onCreateBuffer(size_t size, GrBufferType intendedType, GrAccessPattern, const void* data) override; - GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) override; - GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&, - GrWrapOwnership) override; - GrRenderTarget* onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&) override; + sk_sp onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) override; + sk_sp onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) override; + sk_sp onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&) override; gr_instanced::InstancedRendering* onCreateInstancedRendering() override; @@ -184,8 +189,9 @@ private: bool renderTarget, GrGLTexture::TexParams* initialTexParams, const SkTArray& texels); - bool onMakeCopyForTextureParams(GrTexture*, const GrTextureParams&, - GrTextureProducer::CopyParams*) const override; + bool onIsACopyNeededForTextureParams(GrTextureProxy*, const GrSamplerParams&, + GrTextureProducer::CopyParams*, + SkScalar scaleAdjust[2]) const override; // Checks whether glReadPixels can be called to get pixel values in readConfig from the // render target. @@ -225,8 +231,8 @@ private: const SkIRect& srcRect, const SkIPoint& dstPoint) override; - void onGetMultisampleSpecs(GrRenderTarget*, const GrStencilSettings&, - int* effectiveSampleCnt, SamplePattern*) override; + void onQueryMultisampleSpecs(GrRenderTarget*, const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) override; // binds texture unit in GL void setTextureUnit(int unitIdx); @@ -262,10 +268,6 @@ private: const SkIPoint& dstPoint); bool generateMipmap(GrGLTexture* texture, bool gammaCorrect); - void stampPLSSetupRect(const SkRect& bounds); - - void setupPixelLocalStorage(const GrPipeline&, const GrPrimitiveProcessor&); - static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff); class ProgramCache : public ::SkNoncopyable { @@ -278,29 +280,24 @@ private: bool hasPointSize); private: - enum { - // We may actually have kMaxEntries+1 shaders in the GL context because we create a new - // shader before evicting from the cache. - kMaxEntries = 128, - kHashBits = 6, - }; + // We may actually have kMaxEntries+1 shaders in the GL context because we create a new + // shader before evicting from the cache. + static const int kMaxEntries = 128; struct Entry; - struct ProgDescLess; - // binary search for entry matching desc. returns index into fEntries that matches desc or ~ // of the index of where it should be inserted. int search(const GrProgramDesc& desc) const; - // sorted array of all the entries - Entry* fEntries[kMaxEntries]; - // hash table based on lowest kHashBits bits of the program key. Used to avoid binary - // searching fEntries. - Entry* fHashTable[1 << kHashBits]; + struct DescHash { + uint32_t operator()(const GrProgramDesc& desc) const { + return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0); + } + }; + + SkLRUCache, DescHash> fMap; - int fCount; - unsigned int fCurrLRUStamp; GrGLGpu* fGpu; #ifdef PROGRAM_CACHE_STATS int fTotalRequests; @@ -341,6 +338,7 @@ private: void flushViewport(const GrGLIRect&); void flushStencil(const GrStencilSettings&); + void disableStencil(); // rt is used only if useHWAA is true. void flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled); @@ -383,21 +381,20 @@ private: kDst_TempFBOTarget }; - // Binds a surface as a FBO for a copy operation. If the surface already owns an FBO ID then + // Binds a surface as a FBO for copying or reading. If the surface already owns an FBO ID then // that ID is bound. If not the surface is temporarily bound to a FBO and that FBO is bound. - // This must be paired with a call to unbindSurfaceFBOForCopy(). - void bindSurfaceFBOForCopy(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, - TempFBOTarget tempFBOTarget); + // This must be paired with a call to unbindSurfaceFBOForPixelOps(). + void bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, + TempFBOTarget tempFBOTarget); - // Must be called if bindSurfaceFBOForCopy was used to bind a surface for copying. - void unbindTextureFBOForCopy(GrGLenum fboTarget, GrSurface* surface); + // Must be called if bindSurfaceFBOForPixelOps was used to bind a surface for copying. + void unbindTextureFBOForPixelOps(GrGLenum fboTarget, GrSurface* surface); - SkAutoTUnref fGLContext; + sk_sp fGLContext; - bool createCopyProgram(int progIdx); + bool createCopyProgram(GrTexture* srcTexture); bool createMipmapProgram(int progIdx); bool createWireRectProgram(); - bool createPLSSetupProgram(); // GL program-related state ProgramCache* fProgramCache; @@ -454,7 +451,7 @@ private: if (fWindowState.numWindows() && (fRTOrigin != rtOrigin || fViewport != viewport)) { return false; } - return fWindowState.cheapEqualTo(windowState); + return fWindowState == windowState; } private: @@ -516,28 +513,28 @@ private: GrGLAttribArrayState* bindInternalVertexArray(GrGLGpu*, const GrBuffer* ibuff = nullptr); private: - GrGLuint fBoundVertexArrayID; - bool fBoundVertexArrayIDIsValid; + GrGLuint fBoundVertexArrayID; + bool fBoundVertexArrayIDIsValid; // We return a non-const pointer to this from bindArrayAndBuffersToDraw when vertex array 0 // is bound. However, this class is internal to GrGLGpu and this object never leaks out of // GrGLGpu. - GrGLAttribArrayState fDefaultVertexArrayAttribState; + GrGLAttribArrayState fDefaultVertexArrayAttribState; // This is used when we're using a core profile. - GrGLVertexArray* fCoreProfileVertexArray; - } fHWVertexArrayState; + GrGLVertexArray* fCoreProfileVertexArray; + } fHWVertexArrayState; struct { - GrGLenum fGLTarget; - uint32_t fBoundBufferUniqueID; - bool fBufferZeroKnownBound; + GrGLenum fGLTarget; + GrGpuResource::UniqueID fBoundBufferUniqueID; + bool fBufferZeroKnownBound; void invalidate() { - fBoundBufferUniqueID = SK_InvalidUniqueID; + fBoundBufferUniqueID.makeInvalid(); fBufferZeroKnownBound = false; } - } fHWBufferState[kGrBufferTypeCount]; + } fHWBufferState[kGrBufferTypeCount]; struct { GrBlendEquation fEquation; @@ -554,74 +551,82 @@ private: fConstColorValid = false; fEnabled = kUnknown_TriState; } - } fHWBlendState; + } fHWBlendState; TriState fMSAAEnabled; - GrStencilSettings fHWStencilSettings; - TriState fHWStencilTestEnabled; + GrStencilSettings fHWStencilSettings; + TriState fHWStencilTestEnabled; - GrDrawFace fHWDrawFace; - TriState fHWWriteToColor; - uint32_t fHWBoundRenderTargetUniqueID; - TriState fHWSRGBFramebuffer; - SkTArray fHWBoundTextureUniqueIDs; + GrDrawFace fHWDrawFace; + TriState fHWWriteToColor; + GrGpuResource::UniqueID fHWBoundRenderTargetUniqueID; + TriState fHWSRGBFramebuffer; + SkTArray fHWBoundTextureUniqueIDs; + + struct Image { + GrGpuResource::UniqueID fTextureUniqueID; + GrIOType fIOType; + }; + SkTArray fHWBoundImageStorages; struct BufferTexture { BufferTexture() : fTextureID(0), fKnownBound(false), fAttachedBufferUniqueID(SK_InvalidUniqueID), fSwizzle(GrSwizzle::RGBA()) {} - GrGLuint fTextureID; - bool fKnownBound; - GrPixelConfig fTexelConfig; - uint32_t fAttachedBufferUniqueID; - GrSwizzle fSwizzle; + GrGLuint fTextureID; + bool fKnownBound; + GrPixelConfig fTexelConfig; + GrGpuResource::UniqueID fAttachedBufferUniqueID; + GrSwizzle fSwizzle; }; - SkTArray fHWBufferTextures; - int fHWMaxUsedBufferTextureUnit; + SkTArray fHWBufferTextures; + int fHWMaxUsedBufferTextureUnit; // EXT_raster_multisample. - TriState fHWRasterMultisampleEnabled; - int fHWNumRasterSamples; + TriState fHWRasterMultisampleEnabled; + int fHWNumRasterSamples; ///@} - /** IDs for copy surface program. */ + /** IDs for copy surface program. (4 sampler types) */ struct { GrGLuint fProgram; GrGLint fTextureUniform; GrGLint fTexCoordXformUniform; GrGLint fPosXformUniform; - } fCopyPrograms[3]; - SkAutoTUnref fCopyProgramArrayBuffer; + } fCopyPrograms[4]; + sk_sp fCopyProgramArrayBuffer; /** IDs for texture mipmap program. (4 filter configurations) */ struct { GrGLuint fProgram; GrGLint fTextureUniform; GrGLint fTexCoordXformUniform; - } fMipmapPrograms[4]; - SkAutoTUnref fMipmapProgramArrayBuffer; + } fMipmapPrograms[4]; + sk_sp fMipmapProgramArrayBuffer; struct { - GrGLuint fProgram; - GrGLint fColorUniform; - GrGLint fRectUniform; - } fWireRectProgram; - SkAutoTUnref fWireRectArrayBuffer; + GrGLuint fProgram; + GrGLint fColorUniform; + GrGLint fRectUniform; + } fWireRectProgram; + sk_sp fWireRectArrayBuffer; - static int TextureTargetToCopyProgramIdx(GrGLenum target) { - switch (target) { - case GR_GL_TEXTURE_2D: + static int TextureToCopyProgramIdx(GrTexture* texture) { + switch (texture->texturePriv().samplerType()) { + case kTexture2DSampler_GrSLType: return 0; - case GR_GL_TEXTURE_EXTERNAL: + case kITexture2DSampler_GrSLType: return 1; - case GR_GL_TEXTURE_RECTANGLE: + case kTexture2DRectSampler_GrSLType: return 2; + case kTextureExternalSampler_GrSLType: + return 3; default: - SkFAIL("Unexpected texture target type."); + SkFAIL("Unexpected samper type"); return 0; } } @@ -632,16 +637,7 @@ private: return (wide ? 0x2 : 0x0) | (tall ? 0x1 : 0x0); } - struct { - GrGLuint fProgram; - GrGLint fPosXformUniform; - SkAutoTUnref fArrayBuffer; - } fPLSSetupProgram; - - bool fHWPLSEnabled; - bool fPLSHasBeenUsed; - - float fHWMinSampleShading; + float fHWMinSampleShading; typedef GrGpu INHERITED; friend class GrGLPathRendering; // For accessing setTextureUnit. diff --git a/gfx/skia/skia/src/gpu/gl/GrGLGpuCommandBuffer.h b/gfx/skia/skia/src/gpu/gl/GrGLGpuCommandBuffer.h index 4ad2b13ada24..c7c76a4a9c7d 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLGpuCommandBuffer.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLGpuCommandBuffer.h @@ -11,6 +11,9 @@ #include "GrGpuCommandBuffer.h" #include "GrGLGpu.h" +#include "GrOpFlushState.h" + +class GrGLRenderTarget; class GrGLGpuCommandBuffer : public GrGpuCommandBuffer { /** @@ -19,37 +22,65 @@ class GrGLGpuCommandBuffer : public GrGpuCommandBuffer { * pass through functions to corresponding calls in the GrGLGpu class. */ public: - GrGLGpuCommandBuffer(GrGLGpu* gpu) : fGpu(gpu) {} + GrGLGpuCommandBuffer(GrGLGpu* gpu) : fGpu(gpu), fRenderTarget(nullptr) {} - virtual ~GrGLGpuCommandBuffer() {} + ~GrGLGpuCommandBuffer() override {} void end() override {} - void discard(GrRenderTarget* rt) override {} + void discard(GrRenderTarget* rt) override { + GrGLRenderTarget* target = static_cast(rt); + if (!fRenderTarget) { + fRenderTarget = target; + } + SkASSERT(target == fRenderTarget); + } + + void inlineUpload(GrOpFlushState* state, GrDrawOp::DeferredUploadFn& upload, + GrRenderTarget*) override { + state->doUpload(upload); + } private: GrGpu* gpu() override { return fGpu; } + GrRenderTarget* renderTarget() override { return fRenderTarget; } - void onSubmit(const SkIRect& bounds) override {} + void onSubmit() override {} void onDraw(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, const GrMesh* mesh, - int meshCount) override { + int meshCount, + const SkRect& bounds) override { + GrGLRenderTarget* target = static_cast(pipeline.getRenderTarget()); + if (!fRenderTarget) { + fRenderTarget = target; + } + SkASSERT(target == fRenderTarget); fGpu->draw(pipeline, primProc, mesh, meshCount); } void onClear(GrRenderTarget* rt, const GrFixedClip& clip, GrColor color) override { - fGpu->clear(clip, color, rt); + GrGLRenderTarget* target = static_cast(rt); + if (!fRenderTarget) { + fRenderTarget = target; + } + SkASSERT(target == fRenderTarget); + fGpu->clear(clip, color, fRenderTarget); } - void onClearStencilClip(GrRenderTarget* rt, - const GrFixedClip& clip, + void onClearStencilClip(GrRenderTarget* rt, const GrFixedClip& clip, bool insideStencilMask) override { - fGpu->clearStencilClip(clip, insideStencilMask, rt); + GrGLRenderTarget* target = static_cast(rt); + if (!fRenderTarget) { + fRenderTarget = target; + } + SkASSERT(target == fRenderTarget); + fGpu->clearStencilClip(clip, insideStencilMask, fRenderTarget); } GrGLGpu* fGpu; + GrGLRenderTarget* fRenderTarget; typedef GrGpuCommandBuffer INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLGpuProgramCache.cpp b/gfx/skia/skia/src/gpu/gl/GrGLGpuProgramCache.cpp index 260e256dbef6..2ff5dc79b497 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLGpuProgramCache.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLGpuProgramCache.cpp @@ -23,44 +23,23 @@ static const bool c_DisplayCache{false}; typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; struct GrGLGpu::ProgramCache::Entry { + Entry(sk_sp program) + : fProgram(std::move(program)) {} - Entry() : fProgram(nullptr), fLRUStamp(0) {} - - SkAutoTUnref fProgram; - unsigned int fLRUStamp; -}; - -struct GrGLGpu::ProgramCache::ProgDescLess { - bool operator() (const GrProgramDesc& desc, const Entry* entry) { - SkASSERT(entry->fProgram.get()); - return GrProgramDesc::Less(desc, entry->fProgram->getDesc()); - } - - bool operator() (const Entry* entry, const GrProgramDesc& desc) { - SkASSERT(entry->fProgram.get()); - return GrProgramDesc::Less(entry->fProgram->getDesc(), desc); - } + sk_sp fProgram; }; GrGLGpu::ProgramCache::ProgramCache(GrGLGpu* gpu) - : fCount(0) - , fCurrLRUStamp(0) + : fMap(kMaxEntries) , fGpu(gpu) #ifdef PROGRAM_CACHE_STATS , fTotalRequests(0) , fCacheMisses(0) , fHashMisses(0) #endif -{ - for (int i = 0; i < 1 << kHashBits; ++i) { - fHashTable[i] = nullptr; - } -} +{} GrGLGpu::ProgramCache::~ProgramCache() { - for (int i = 0; i < fCount; ++i){ - delete fEntries[i]; - } // dump stats #ifdef PROGRAM_CACHE_STATS if (c_DisplayCache) { @@ -78,20 +57,6 @@ GrGLGpu::ProgramCache::~ProgramCache() { } void GrGLGpu::ProgramCache::abandon() { - for (int i = 0; i < fCount; ++i) { - SkASSERT(fEntries[i]->fProgram.get()); - fEntries[i]->fProgram->abandon(); - delete fEntries[i]; - fEntries[i] = nullptr; - } - fCount = 0; - - // zero out hash table - for (int i = 0; i < 1 << kHashBits; i++) { - fHashTable[i] = nullptr; - } - - fCurrLRUStamp = 0; #ifdef PROGRAM_CACHE_STATS fTotalRequests = 0; fCacheMisses = 0; @@ -99,11 +64,6 @@ void GrGLGpu::ProgramCache::abandon() { #endif } -int GrGLGpu::ProgramCache::search(const GrProgramDesc& desc) const { - ProgDescLess less; - return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less); -} - GrGLProgram* GrGLGpu::ProgramCache::refProgram(const GrGLGpu* gpu, const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, @@ -114,109 +74,30 @@ GrGLProgram* GrGLGpu::ProgramCache::refProgram(const GrGLGpu* gpu, // Get GrGLProgramDesc GrProgramDesc desc; - if (!GrProgramDesc::Build(&desc, primProc, isPoints, pipeline, *gpu->glCaps().glslCaps())) { + if (!GrProgramDesc::Build(&desc, primProc, isPoints, pipeline, *gpu->caps()->shaderCaps())) { GrCapsDebugf(gpu->caps(), "Failed to gl program descriptor!\n"); return nullptr; } desc.finalize(); - - Entry* entry = nullptr; - - uint32_t hashIdx = desc.getChecksum(); - hashIdx ^= hashIdx >> 16; - if (kHashBits <= 8) { - hashIdx ^= hashIdx >> 8; + std::unique_ptr* entry = fMap.find(desc); + if (!entry) { + // Didn't find an origin-independent version, check with the specific origin + GrSurfaceOrigin origin = pipeline.getRenderTarget()->origin(); + desc.setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(origin)); + desc.finalize(); + entry = fMap.find(desc); } - hashIdx &=((1 << kHashBits) - 1); - Entry* hashedEntry = fHashTable[hashIdx]; - if (hashedEntry && hashedEntry->fProgram->getDesc() == desc) { - SkASSERT(hashedEntry->fProgram); - entry = hashedEntry; - } - - int entryIdx; - if (nullptr == entry) { - entryIdx = this->search(desc); - if (entryIdx >= 0) { - entry = fEntries[entryIdx]; -#ifdef PROGRAM_CACHE_STATS - ++fHashMisses; -#endif - } - } - - if (nullptr == entry) { + if (!entry) { // We have a cache miss #ifdef PROGRAM_CACHE_STATS ++fCacheMisses; #endif - GrGLProgram* program = GrGLProgramBuilder::CreateProgram(pipeline, primProc, desc, fGpu); + GrGLProgram* program = GrGLProgramBuilder::CreateProgram(pipeline, primProc, &desc, fGpu); if (nullptr == program) { return nullptr; } - int purgeIdx = 0; - if (fCount < kMaxEntries) { - entry = new Entry; - purgeIdx = fCount++; - fEntries[purgeIdx] = entry; - } else { - SkASSERT(fCount == kMaxEntries); - purgeIdx = 0; - for (int i = 1; i < kMaxEntries; ++i) { - if (fEntries[i]->fLRUStamp < fEntries[purgeIdx]->fLRUStamp) { - purgeIdx = i; - } - } - entry = fEntries[purgeIdx]; - int purgedHashIdx = entry->fProgram->getDesc().getChecksum() & ((1 << kHashBits) - 1); - if (fHashTable[purgedHashIdx] == entry) { - fHashTable[purgedHashIdx] = nullptr; - } - } - SkASSERT(fEntries[purgeIdx] == entry); - entry->fProgram.reset(program); - // We need to shift fEntries around so that the entry currently at purgeIdx is placed - // just before the entry at ~entryIdx (in order to keep fEntries sorted by descriptor). - entryIdx = ~entryIdx; - if (entryIdx < purgeIdx) { - // Let E and P be the entries at index entryIdx and purgeIdx, respectively. - // If the entries array looks like this: - // aaaaEbbbbbPccccc - // we rearrange it to look like this: - // aaaaPEbbbbbccccc - size_t copySize = (purgeIdx - entryIdx) * sizeof(Entry*); - memmove(fEntries + entryIdx + 1, fEntries + entryIdx, copySize); - fEntries[entryIdx] = entry; - } else if (purgeIdx < entryIdx) { - // If the entries array looks like this: - // aaaaPbbbbbEccccc - // we rearrange it to look like this: - // aaaabbbbbPEccccc - size_t copySize = (entryIdx - purgeIdx - 1) * sizeof(Entry*); - memmove(fEntries + purgeIdx, fEntries + purgeIdx + 1, copySize); - fEntries[entryIdx - 1] = entry; - } -#ifdef SK_DEBUG - SkASSERT(fEntries[0]->fProgram.get()); - for (int i = 0; i < fCount - 1; ++i) { - SkASSERT(fEntries[i + 1]->fProgram.get()); - const GrProgramDesc& a = fEntries[i]->fProgram->getDesc(); - const GrProgramDesc& b = fEntries[i + 1]->fProgram->getDesc(); - SkASSERT(GrProgramDesc::Less(a, b)); - SkASSERT(!GrProgramDesc::Less(b, a)); - } -#endif + entry = fMap.insert(desc, std::unique_ptr(new Entry(sk_sp(program)))); } - fHashTable[hashIdx] = entry; - entry->fLRUStamp = fCurrLRUStamp; - - if (SK_MaxU32 == fCurrLRUStamp) { - // wrap around! just trash our LRU, one time hit. - for (int i = 0; i < fCount; ++i) { - fEntries[i]->fLRUStamp = 0; - } - } - ++fCurrLRUStamp; - return SkRef(entry->fProgram.get()); + return SkRef((*entry)->fProgram.get()); } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLInterface.cpp b/gfx/skia/skia/src/gpu/gl/GrGLInterface.cpp index 0a157dda1111..c196b4bb9745 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLInterface.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLInterface.cpp @@ -29,37 +29,6 @@ const GrGLInterface* GrGLInterfaceAddTestDebugMarker(const GrGLInterface* interf return newInterface; } -const GrGLInterface* GrGLInterfaceRemoveNVPR(const GrGLInterface* interface) { - GrGLInterface* newInterface = GrGLInterface::NewClone(interface); - - newInterface->fExtensions.remove("GL_NV_path_rendering"); - newInterface->fExtensions.remove("GL_CHROMIUM_path_rendering"); - newInterface->fFunctions.fMatrixLoadf = nullptr; - newInterface->fFunctions.fMatrixLoadIdentity = nullptr; - newInterface->fFunctions.fPathCommands = nullptr; - newInterface->fFunctions.fPathParameteri = nullptr; - newInterface->fFunctions.fPathParameterf = nullptr; - newInterface->fFunctions.fGenPaths = nullptr; - newInterface->fFunctions.fDeletePaths = nullptr; - newInterface->fFunctions.fIsPath = nullptr; - newInterface->fFunctions.fPathStencilFunc = nullptr; - newInterface->fFunctions.fStencilFillPath = nullptr; - newInterface->fFunctions.fStencilStrokePath = nullptr; - newInterface->fFunctions.fStencilFillPathInstanced = nullptr; - newInterface->fFunctions.fStencilStrokePathInstanced = nullptr; - newInterface->fFunctions.fCoverFillPath = nullptr; - newInterface->fFunctions.fCoverStrokePath = nullptr; - newInterface->fFunctions.fCoverFillPathInstanced = nullptr; - newInterface->fFunctions.fCoverStrokePathInstanced = nullptr; - newInterface->fFunctions.fStencilThenCoverFillPath = nullptr; - newInterface->fFunctions.fStencilThenCoverStrokePath = nullptr; - newInterface->fFunctions.fStencilThenCoverFillPathInstanced = nullptr; - newInterface->fFunctions.fStencilThenCoverStrokePathInstanced = nullptr; - newInterface->fFunctions.fProgramPathFragmentInputGen = nullptr; - newInterface->fFunctions.fBindFragmentInputLocation = nullptr; - return newInterface; -} - GrGLInterface::GrGLInterface() { fStandard = kNone_GrGLStandard; } @@ -220,7 +189,8 @@ bool GrGLInterface::validate() const { if (glVer >= GR_GL_VER(2,0)) { if (nullptr == fFunctions.fStencilFuncSeparate || nullptr == fFunctions.fStencilMaskSeparate || - nullptr == fFunctions.fStencilOpSeparate) { + nullptr == fFunctions.fStencilOpSeparate || + nullptr == fFunctions.fPolygonMode) { RETURN_FALSE_INTERFACE } } @@ -348,6 +318,15 @@ bool GrGLInterface::validate() const { nullptr == fFunctions.fBlitFramebuffer) { RETURN_FALSE_INTERFACE } + } else { + if (fExtensions.has("GL_ANGLE_framebuffer_multisample") && + nullptr == fFunctions.fRenderbufferStorageMultisample) { + RETURN_FALSE_INTERFACE + } + if (fExtensions.has("GL_ANGLE_framebuffer_blit") && + nullptr == fFunctions.fBlitFramebuffer) { + RETURN_FALSE_INTERFACE + } } if (fExtensions.has("GL_APPLE_framebuffer_multisample")) { if (nullptr == fFunctions.fRenderbufferStorageMultisampleES2APPLE || @@ -790,6 +769,7 @@ bool GrGLInterface::validate() const { if (glVer >= GR_GL_VER(3, 2) || fExtensions.has("GL_ARB_sync")) { if (nullptr == fFunctions.fFenceSync || nullptr == fFunctions.fClientWaitSync || + nullptr == fFunctions.fWaitSync || nullptr == fFunctions.fDeleteSync) { RETURN_FALSE_INTERFACE } @@ -798,6 +778,7 @@ bool GrGLInterface::validate() const { if (glVer >= GR_GL_VER(3, 0)) { if (nullptr == fFunctions.fFenceSync || nullptr == fFunctions.fClientWaitSync || + nullptr == fFunctions.fWaitSync || nullptr == fFunctions.fDeleteSync) { RETURN_FALSE_INTERFACE } @@ -821,5 +802,25 @@ bool GrGLInterface::validate() const { } } + if (kGL_GrGLStandard == fStandard) { + if (glVer >= GR_GL_VER(4,2) || fExtensions.has("GL_ARB_shader_image_load_store")) { + if (nullptr == fFunctions.fBindImageTexture || + nullptr == fFunctions.fMemoryBarrier) { + RETURN_FALSE_INTERFACE; + } + } + if (glVer >= GR_GL_VER(4,5) || fExtensions.has("GL_ARB_ES3_1_compatibility")) { + if (nullptr == fFunctions.fMemoryBarrierByRegion) { + RETURN_FALSE_INTERFACE; + } + } + } else if (kGLES_GrGLStandard == fStandard && glVer >= GR_GL_VER(3,1)) { + if (nullptr == fFunctions.fBindImageTexture || + nullptr == fFunctions.fMemoryBarrier || + nullptr == fFunctions.fMemoryBarrierByRegion) { + RETURN_FALSE_INTERFACE; + } + } + return true; } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLPath.cpp b/gfx/skia/skia/src/gpu/gl/GrGLPath.cpp index 05460187ef98..f7e6bd16de08 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLPath.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLPath.cpp @@ -218,7 +218,7 @@ void GrGLPath::InitPathObjectPathData(GrGLGpu* gpu, const SkPath& skPath) { SkASSERT(!skPath.isEmpty()); -#ifdef SK_SCALAR_IS_FLOAT +#if 1 // SK_SCALAR_IS_FLOAT // This branch does type punning, converting SkPoint* to GrGLfloat*. if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) { int verbCnt = skPath.countVerbs(); diff --git a/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.h b/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.h index 40f72ccd7bdc..8c3cd47f8fcb 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.h @@ -10,12 +10,12 @@ #include "SkRefCnt.h" #include "GrPathRendering.h" +#include "GrStencilSettings.h" #include "gl/GrGLTypes.h" #include "glsl/GrGLSLUtil.h" class GrGLNameAllocator; class GrGLGpu; -class GrStencilSettings; class GrStyle; /** @@ -31,7 +31,7 @@ public: * Create a new GrGLPathRendering object from a given GrGLGpu. */ GrGLPathRendering(GrGLGpu* gpu); - virtual ~GrGLPathRendering(); + ~GrGLPathRendering() override; // GrPathRendering implementations. GrPath* createPath(const SkPath&, const GrStyle&) override; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLProgram.cpp b/gfx/skia/skia/src/gpu/gl/GrGLProgram.cpp index 86b237266b78..e208e7447e3d 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLProgram.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLProgram.cpp @@ -19,7 +19,6 @@ #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLXferProcessor.h" -#include "SkXfermode.h" #define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X) #define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X) @@ -31,7 +30,8 @@ GrGLProgram::GrGLProgram(GrGLGpu* gpu, const BuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, - const SkTArray& samplers, + const UniformInfoArray& samplers, + const UniformInfoArray& imageStorages, const VaryingInfoArray& pathProcVaryings, GrGLSLPrimitiveProcessor* geometryProcessor, GrGLSLXferProcessor* xferProcessor, @@ -47,6 +47,7 @@ GrGLProgram::GrGLProgram(GrGLGpu* gpu, // Assign texture units to sampler uniforms one time up front. GL_CALL(UseProgram(fProgramID)); fProgramDataManager.setSamplers(samplers); + fProgramDataManager.setImageStorages(imageStorages); } GrGLProgram::~GrGLProgram() { @@ -65,7 +66,7 @@ void GrGLProgram::abandon() { /////////////////////////////////////////////////////////////////////////////// void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline) { - this->setRenderTargetState(primProc, pipeline); + this->setRenderTargetState(primProc, pipeline.getRenderTarget()); // we set the textures, and uniforms for installed processors in a generic way, but subclasses // of GLProgram determine how to set coord transforms @@ -76,11 +77,13 @@ void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline this->setFragmentData(primProc, pipeline, &nextSamplerIdx); - if (primProc.getPixelLocalStorageState() != - GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) { - const GrXferProcessor& xp = pipeline.getXferProcessor(); - fXferProcessor->setData(fProgramDataManager, xp); - this->bindTextures(xp, pipeline.getAllowSRGBInputs(), &nextSamplerIdx); + const GrXferProcessor& xp = pipeline.getXferProcessor(); + SkIPoint offset; + GrTexture* dstTexture = pipeline.dstTexture(&offset); + fXferProcessor->setData(fProgramDataManager, xp, dstTexture, offset); + if (dstTexture) { + fGpu->bindTexture(nextSamplerIdx++, GrSamplerParams::ClampNoFilter(), true, + static_cast(dstTexture)); } } @@ -92,12 +95,6 @@ void GrGLProgram::generateMipmaps(const GrPrimitiveProcessor& primProc, while (const GrFragmentProcessor* fp = iter.next()) { this->generateMipmaps(*fp, pipeline.getAllowSRGBInputs()); } - - if (primProc.getPixelLocalStorageState() != - GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) { - const GrXferProcessor& xp = pipeline.getXferProcessor(); - this->generateMipmaps(xp, pipeline.getAllowSRGBInputs()); - } } void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc, @@ -119,16 +116,14 @@ void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc, void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc, - const GrPipeline& pipeline) { + const GrRenderTarget* rt) { // Load the RT height uniform if it is needed to y-flip gl_FragCoord. if (fBuiltinUniformHandles.fRTHeightUni.isValid() && - fRenderTargetState.fRenderTargetSize.fHeight != pipeline.getRenderTarget()->height()) { - fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, - SkIntToScalar(pipeline.getRenderTarget()->height())); + fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) { + fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height())); } // set RT adjustment - const GrRenderTarget* rt = pipeline.getRenderTarget(); SkISize size; size.set(rt->width(), rt->height()); if (!primProc.isPathRendering()) { @@ -149,26 +144,30 @@ void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc, } } -void GrGLProgram::bindTextures(const GrProcessor& processor, +void GrGLProgram::bindTextures(const GrResourceIOProcessor& processor, bool allowSRGBInputs, int* nextSamplerIdx) { - for (int i = 0; i < processor.numTextures(); ++i) { - const GrTextureAccess& access = processor.textureAccess(i); - fGpu->bindTexture((*nextSamplerIdx)++, access.getParams(), - allowSRGBInputs, static_cast(access.getTexture())); + for (int i = 0; i < processor.numTextureSamplers(); ++i) { + const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i); + fGpu->bindTexture((*nextSamplerIdx)++, sampler.params(), + allowSRGBInputs, static_cast(sampler.texture())); } for (int i = 0; i < processor.numBuffers(); ++i) { - const GrBufferAccess& access = processor.bufferAccess(i); + const GrResourceIOProcessor::BufferAccess& access = processor.bufferAccess(i); fGpu->bindTexelBuffer((*nextSamplerIdx)++, access.texelConfig(), static_cast(access.buffer())); } -} - -void GrGLProgram::generateMipmaps(const GrProcessor& processor, - bool allowSRGBInputs) { - for (int i = 0; i < processor.numTextures(); ++i) { - const GrTextureAccess& access = processor.textureAccess(i); - fGpu->generateMipmaps(access.getParams(), allowSRGBInputs, - static_cast(access.getTexture())); + for (int i = 0; i < processor.numImageStorages(); ++i) { + const GrResourceIOProcessor::ImageStorageAccess& access = processor.imageStorageAccess(i); + fGpu->bindImageStorage((*nextSamplerIdx)++, access.ioType(), + static_cast(access.texture())); + } +} + +void GrGLProgram::generateMipmaps(const GrResourceIOProcessor& processor, bool allowSRGBInputs) { + for (int i = 0; i < processor.numTextureSamplers(); ++i) { + const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i); + fGpu->generateMipmaps(sampler.params(), allowSRGBInputs, + static_cast(sampler.texture())); } } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLProgram.h b/gfx/skia/skia/src/gpu/gl/GrGLProgram.h index 34037a24063e..f9b84d8031f5 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLProgram.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLProgram.h @@ -17,7 +17,6 @@ #include "glsl/GrGLSLUniformHandler.h" #include "SkString.h" -#include "SkXfermode.h" #include "builders/GrGLProgramBuilder.h" @@ -103,16 +102,17 @@ public: void generateMipmaps(const GrPrimitiveProcessor&, const GrPipeline&); protected: - typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; - typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray; - typedef GrGLProgramDataManager::VaryingInfoArray VaryingInfoArray; + using UniformHandle = GrGLSLProgramDataManager::UniformHandle ; + using UniformInfoArray = GrGLProgramDataManager::UniformInfoArray; + using VaryingInfoArray = GrGLProgramDataManager::VaryingInfoArray; GrGLProgram(GrGLGpu*, const GrProgramDesc&, const BuiltinUniformHandles&, GrGLuint programID, - const UniformInfoArray&, - const SkTArray&, + const UniformInfoArray& uniforms, + const UniformInfoArray& samplers, + const UniformInfoArray& imageStorages, const VaryingInfoArray&, // used for NVPR only currently GrGLSLPrimitiveProcessor* geometryProcessor, GrGLSLXferProcessor* xferProcessor, @@ -122,13 +122,13 @@ protected: void setFragmentData(const GrPrimitiveProcessor&, const GrPipeline&, int* nextSamplerIdx); // Helper for setData() that sets the view matrix and loads the render target height uniform - void setRenderTargetState(const GrPrimitiveProcessor&, const GrPipeline&); + void setRenderTargetState(const GrPrimitiveProcessor&, const GrRenderTarget*); // Helper for setData() that binds textures and texel buffers to the appropriate texture units - void bindTextures(const GrProcessor&, bool allowSRGBInputs, int* nextSamplerIdx); + void bindTextures(const GrResourceIOProcessor&, bool allowSRGBInputs, int* nextSamplerIdx); // Helper for generateMipmaps() that ensures mipmaps are up to date - void generateMipmaps(const GrProcessor&, bool allowSRGBInputs); + void generateMipmaps(const GrResourceIOProcessor&, bool allowSRGBInputs); // these reflect the current values of uniforms (GL uniform values travel with program) RenderTargetState fRenderTargetState; @@ -136,8 +136,8 @@ protected: GrGLuint fProgramID; // the installed effects - SkAutoTDelete fGeometryProcessor; - SkAutoTDelete fXferProcessor; + std::unique_ptr fGeometryProcessor; + std::unique_ptr fXferProcessor; GrGLSLFragProcs fFragmentProcessors; GrProgramDesc fDesc; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.cpp b/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.cpp index 9fe7d3b4f768..2a3422e308c1 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.cpp @@ -12,7 +12,7 @@ #define ASSERT_ARRAY_UPLOAD_IN_BOUNDS(UNI, COUNT) \ SkASSERT((COUNT) <= (UNI).fArrayCount || \ - (1 == (COUNT) && GrGLSLShaderVar::kNonArray == (UNI).fArrayCount)) + (1 == (COUNT) && GrShaderVar::kNonArray == (UNI).fArrayCount)) GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID, const UniformInfoArray& uniforms, @@ -24,24 +24,13 @@ GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID, for (int i = 0; i < count; i++) { Uniform& uniform = fUniforms[i]; const UniformInfo& builderUniform = uniforms[i]; - SkASSERT(GrGLSLShaderVar::kNonArray == builderUniform.fVariable.getArrayCount() || + SkASSERT(GrShaderVar::kNonArray == builderUniform.fVariable.getArrayCount() || builderUniform.fVariable.getArrayCount() > 0); SkDEBUGCODE( uniform.fArrayCount = builderUniform.fVariable.getArrayCount(); uniform.fType = builderUniform.fVariable.getType(); ); - // TODO: Move the Xoom uniform array in both FS and VS bug workaround here. - - if (kVertex_GrShaderFlag & builderUniform.fVisibility) { - uniform.fVSLocation = builderUniform.fLocation; - } else { - uniform.fVSLocation = kUnusedUniform; - } - if (kFragment_GrShaderFlag & builderUniform.fVisibility) { - uniform.fFSLocation = builderUniform.fLocation; - } else { - uniform.fFSLocation = kUnusedUniform; - } + uniform.fLocation = builderUniform.fLocation; } // NVPR programs have separable varyings @@ -51,7 +40,7 @@ GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID, SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport()); PathProcVarying& pathProcVarying = fPathProcVaryings[i]; const VaryingInfo& builderPathProcVarying = pathProcVaryings[i]; - SkASSERT(GrGLSLShaderVar::kNonArray == builderPathProcVarying.fVariable.getArrayCount() || + SkASSERT(GrShaderVar::kNonArray == builderPathProcVarying.fVariable.getArrayCount() || builderPathProcVarying.fVariable.getArrayCount() > 0); SkDEBUGCODE( pathProcVarying.fArrayCount = builderPathProcVarying.fVariable.getArrayCount(); @@ -61,30 +50,22 @@ GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID, } } -void GrGLProgramDataManager::setSamplers(const SkTArray& samplers) const { +void GrGLProgramDataManager::setSamplers(const UniformInfoArray& samplers) const { for (int i = 0; i < samplers.count(); ++i) { - GrGLint vsLocation; - GrGLint fsLocation; - const GrGLSampler& sampler = samplers[i]; - if (kVertex_GrShaderFlag & sampler.visibility()) { - vsLocation = sampler.location(); - } else { - vsLocation = kUnusedUniform; + const UniformInfo& sampler = samplers[i]; + SkASSERT(sampler.fVisibility); + if (kUnusedUniform != sampler.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform1i(sampler.fLocation, i)); } - if (kFragment_GrShaderFlag & sampler.visibility()) { - fsLocation = sampler.location(); - } else { - fsLocation = kUnusedUniform; - } - // FIXME: We still insert a single sampler uniform for every stage. If the shader does not - // reference the sampler then the compiler may have optimized it out. Uncomment this assert - // once stages insert their own samplers. - // this->printUnused(uni); - if (kUnusedUniform != fsLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform1i(fsLocation, i)); - } - if (kUnusedUniform != vsLocation && vsLocation != fsLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform1i(vsLocation, i)); + } +} + +void GrGLProgramDataManager::setImageStorages(const UniformInfoArray& images) const { + for (int i = 0; i < images.count(); ++i) { + const UniformInfo& image = images[i]; + SkASSERT(image.fVisibility); + if (kUnusedUniform != image.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform1i(image.fLocation, i)); } } } @@ -92,13 +73,9 @@ void GrGLProgramDataManager::setSamplers(const SkTArray& samplers) void GrGLProgramDataManager::set1i(UniformHandle u, int32_t i) const { const Uniform& uni = fUniforms[u.toIndex()]; SkASSERT(uni.fType == kInt_GrSLType); - SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); - SkDEBUGCODE(this->printUnused(uni)); - if (kUnusedUniform != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform1i(uni.fFSLocation, i)); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform1i(uni.fVSLocation, i)); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + if (kUnusedUniform != uni.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform1i(uni.fLocation, i)); } } @@ -109,24 +86,17 @@ void GrGLProgramDataManager::set1iv(UniformHandle u, SkASSERT(uni.fType == kInt_GrSLType); SkASSERT(arrayCount > 0); ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount); - if (kUnusedUniform != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform1iv(uni.fFSLocation, arrayCount, v)); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform1iv(uni.fVSLocation, arrayCount, v)); + if (kUnusedUniform != uni.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform1iv(uni.fLocation, arrayCount, v)); } } void GrGLProgramDataManager::set1f(UniformHandle u, float v0) const { const Uniform& uni = fUniforms[u.toIndex()]; SkASSERT(uni.fType == kFloat_GrSLType); - SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); - SkDEBUGCODE(this->printUnused(uni);) - if (kUnusedUniform != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform1f(uni.fFSLocation, v0)); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform1f(uni.fVSLocation, v0)); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + if (kUnusedUniform != uni.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform1f(uni.fLocation, v0)); } } @@ -141,24 +111,17 @@ void GrGLProgramDataManager::set1fv(UniformHandle u, // Once the uniform manager is responsible for inserting the duplicate uniform // arrays in VS and FS driver bug workaround, this can be enabled. // this->printUni(uni); - if (kUnusedUniform != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform1fv(uni.fFSLocation, arrayCount, v)); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform1fv(uni.fVSLocation, arrayCount, v)); + if (kUnusedUniform != uni.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform1fv(uni.fLocation, arrayCount, v)); } } void GrGLProgramDataManager::set2f(UniformHandle u, float v0, float v1) const { const Uniform& uni = fUniforms[u.toIndex()]; SkASSERT(uni.fType == kVec2f_GrSLType); - SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); - SkDEBUGCODE(this->printUnused(uni);) - if (kUnusedUniform != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform2f(uni.fFSLocation, v0, v1)); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform2f(uni.fVSLocation, v0, v1)); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + if (kUnusedUniform != uni.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform2f(uni.fLocation, v0, v1)); } } @@ -169,25 +132,17 @@ void GrGLProgramDataManager::set2fv(UniformHandle u, SkASSERT(uni.fType == kVec2f_GrSLType); SkASSERT(arrayCount > 0); ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount); - SkDEBUGCODE(this->printUnused(uni);) - if (kUnusedUniform != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform2fv(uni.fFSLocation, arrayCount, v)); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform2fv(uni.fVSLocation, arrayCount, v)); + if (kUnusedUniform != uni.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform2fv(uni.fLocation, arrayCount, v)); } } void GrGLProgramDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const { const Uniform& uni = fUniforms[u.toIndex()]; SkASSERT(uni.fType == kVec3f_GrSLType); - SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); - SkDEBUGCODE(this->printUnused(uni);) - if (kUnusedUniform != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform3f(uni.fFSLocation, v0, v1, v2)); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform3f(uni.fVSLocation, v0, v1, v2)); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + if (kUnusedUniform != uni.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform3f(uni.fLocation, v0, v1, v2)); } } @@ -198,12 +153,8 @@ void GrGLProgramDataManager::set3fv(UniformHandle u, SkASSERT(uni.fType == kVec3f_GrSLType); SkASSERT(arrayCount > 0); ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount); - SkDEBUGCODE(this->printUnused(uni);) - if (kUnusedUniform != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform3fv(uni.fFSLocation, arrayCount, v)); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform3fv(uni.fVSLocation, arrayCount, v)); + if (kUnusedUniform != uni.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform3fv(uni.fLocation, arrayCount, v)); } } @@ -214,13 +165,9 @@ void GrGLProgramDataManager::set4f(UniformHandle u, float v3) const { const Uniform& uni = fUniforms[u.toIndex()]; SkASSERT(uni.fType == kVec4f_GrSLType); - SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); - SkDEBUGCODE(this->printUnused(uni);) - if (kUnusedUniform != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform4f(uni.fFSLocation, v0, v1, v2, v3)); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform4f(uni.fVSLocation, v0, v1, v2, v3)); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + if (kUnusedUniform != uni.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform4f(uni.fLocation, v0, v1, v2, v3)); } } @@ -231,12 +178,8 @@ void GrGLProgramDataManager::set4fv(UniformHandle u, SkASSERT(uni.fType == kVec4f_GrSLType); SkASSERT(arrayCount > 0); ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount); - SkDEBUGCODE(this->printUnused(uni);) - if (kUnusedUniform != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform4fv(uni.fFSLocation, arrayCount, v)); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - GR_GL_CALL(fGpu->glInterface(), Uniform4fv(uni.fVSLocation, arrayCount, v)); + if (kUnusedUniform != uni.fLocation) { + GR_GL_CALL(fGpu->glInterface(), Uniform4fv(uni.fLocation, arrayCount, v)); } } @@ -273,12 +216,8 @@ template inline void GrGLProgramDataManager::setMatrices(UniformHandle u, SkASSERT(uni.fType == kMat22f_GrSLType + (N - 2)); SkASSERT(arrayCount > 0); ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount); - SkDEBUGCODE(this->printUnused(uni);) - if (kUnusedUniform != uni.fFSLocation) { - set_uniform_matrix::set(fGpu->glInterface(), uni.fFSLocation, arrayCount, matrices); - } - if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) { - set_uniform_matrix::set(fGpu->glInterface(), uni.fVSLocation, arrayCount, matrices); + if (kUnusedUniform != uni.fLocation) { + set_uniform_matrix::set(fGpu->glInterface(), uni.fLocation, arrayCount, matrices); } } @@ -315,11 +254,3 @@ void GrGLProgramDataManager::setPathFragmentInputTransform(VaryingHandle u, components, matrix); } - -#ifdef SK_DEBUG -void GrGLProgramDataManager::printUnused(const Uniform& uni) const { - if (kUnusedUniform == uni.fFSLocation && kUnusedUniform == uni.fVSLocation) { - GrCapsDebugf(fGpu->caps(), "Unused uniform in shader\n"); - } -} -#endif diff --git a/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.h b/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.h index 30c4a63ebce6..42e065691504 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.h @@ -8,12 +8,10 @@ #ifndef GrGLProgramDataManager_DEFINED #define GrGLProgramDataManager_DEFINED -#include "glsl/GrGLSLProgramDataManager.h" - #include "GrAllocator.h" -#include "gl/GrGLSampler.h" +#include "GrShaderVar.h" #include "gl/GrGLTypes.h" -#include "glsl/GrGLSLShaderVar.h" +#include "glsl/GrGLSLProgramDataManager.h" #include "SkTArray.h" @@ -28,17 +26,17 @@ class GrGLProgram; class GrGLProgramDataManager : public GrGLSLProgramDataManager { public: struct UniformInfo { - GrGLSLShaderVar fVariable; + GrShaderVar fVariable; uint32_t fVisibility; GrGLint fLocation; }; struct VaryingInfo { - GrGLSLShaderVar fVariable; + GrShaderVar fVariable; GrGLint fLocation; }; - // This uses an allocator rather than array so that the GrGLSLShaderVars don't move in memory + // This uses an allocator rather than array so that the GrShaderVars don't move in memory // after they are inserted. Users of GrGLShaderBuilder get refs to the vars and ptrs to their // name strings. Otherwise, we'd have to hand out copies. typedef GrTAllocator UniformInfoArray; @@ -48,7 +46,8 @@ public: const VaryingInfoArray&); - void setSamplers(const SkTArray& samplers) const; + void setSamplers(const UniformInfoArray& samplers) const; + void setImageStorages(const UniformInfoArray &images) const; /** Functions for uploading uniform values. The varities ending in v can be used to upload to an * array of uniforms. arrayCount must be <= the array count of the uniform. @@ -82,12 +81,11 @@ private: }; struct Uniform { - GrGLint fVSLocation; - GrGLint fFSLocation; - SkDEBUGCODE( - GrSLType fType; - int fArrayCount; - ); + GrGLint fLocation; +#ifdef SK_DEBUG + GrSLType fType; + int fArrayCount; +#endif }; enum { @@ -101,8 +99,6 @@ private: ); }; - SkDEBUGCODE(void printUnused(const Uniform&) const;) - template inline void setMatrices(UniformHandle, int arrayCount, const float matrices[]) const; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLRenderTarget.cpp b/gfx/skia/skia/src/gpu/gl/GrGLRenderTarget.cpp index f6ad3ba611af..45efba2f1757 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLRenderTarget.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLRenderTarget.cpp @@ -59,15 +59,13 @@ void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) { fViewport.fWidth = desc.fWidth; fViewport.fHeight = desc.fHeight; - fGpuMemorySize = this->totalSamples() * this->totalBytesPerSample(); - - SkASSERT(fGpuMemorySize <= WorstCaseSize(desc)); + fNumSamplesOwnedPerPixel = this->totalSamples(); } -GrGLRenderTarget* GrGLRenderTarget::CreateWrapped(GrGLGpu* gpu, - const GrSurfaceDesc& desc, - const IDDesc& idDesc, - int stencilBits) { +sk_sp GrGLRenderTarget::MakeWrapped(GrGLGpu* gpu, + const GrSurfaceDesc& desc, + const IDDesc& idDesc, + int stencilBits) { GrGLStencilAttachment* sb = nullptr; if (stencilBits) { GrGLStencilAttachment::IDDesc sbDesc; @@ -80,11 +78,11 @@ GrGLRenderTarget* GrGLRenderTarget::CreateWrapped(GrGLGpu* gpu, sb = new GrGLStencilAttachment(gpu, sbDesc, desc.fWidth, desc.fHeight, desc.fSampleCnt, format); } - return (new GrGLRenderTarget(gpu, desc, idDesc, sb)); + return sk_sp(new GrGLRenderTarget(gpu, desc, idDesc, sb)); } size_t GrGLRenderTarget::onGpuMemorySize() const { - return fGpuMemorySize; + return GrSurface::ComputeSize(fDesc, fNumSamplesOwnedPerPixel, false); } bool GrGLRenderTarget::completeStencilAttachment() { @@ -185,12 +183,12 @@ void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) // Log any renderbuffer's contribution to memory. We only do this if we own the renderbuffer // (have a fMSColorRenderbufferID). if (fMSColorRenderbufferID) { - size_t size = this->msaaSamples() * this->totalBytesPerSample(); + size_t size = GrSurface::ComputeSize(fDesc, this->msaaSamples(), false); // Due to this resource having both a texture and a renderbuffer component, dump as // skia/gpu_resources/resource_#/renderbuffer SkString dumpName("skia/gpu_resources/resource_"); - dumpName.appendS32(this->uniqueID()); + dumpName.appendU32(this->uniqueID().asUInt()); dumpName.append("/renderbuffer"); traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", size); @@ -206,15 +204,6 @@ void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) } } -size_t GrGLRenderTarget::totalBytesPerSample() const { - SkASSERT(kUnknown_GrPixelConfig != fDesc.fConfig); - SkASSERT(!GrPixelConfigIsCompressed(fDesc.fConfig)); - size_t colorBytes = GrBytesPerPixel(fDesc.fConfig); - SkASSERT(colorBytes > 0); - - return fDesc.fWidth * fDesc.fHeight * colorBytes; -} - int GrGLRenderTarget::msaaSamples() const { if (fTexFBOID == kUnresolvableFBOID || fTexFBOID != fRTFBOID) { // If the render target's FBO is external (fTexFBOID == kUnresolvableFBOID), or if we own diff --git a/gfx/skia/skia/src/gpu/gl/GrGLRenderTarget.h b/gfx/skia/skia/src/gpu/gl/GrGLRenderTarget.h index 85e377f69acd..e4efc94a9227 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLRenderTarget.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLRenderTarget.h @@ -31,17 +31,16 @@ public: bool fIsMixedSampled; }; - static GrGLRenderTarget* CreateWrapped(GrGLGpu*, - const GrSurfaceDesc&, - const IDDesc&, - int stencilBits); + static sk_sp MakeWrapped(GrGLGpu*, + const GrSurfaceDesc&, + const IDDesc&, + int stencilBits); void setViewport(const GrGLIRect& rect) { fViewport = rect; } const GrGLIRect& getViewport() const { return fViewport; } - // The following two functions return the same ID when a - // texture/render target is multisampled, and different IDs when - // it is. + // The following two functions return the same ID when a texture/render target is not + // multisampled, and different IDs when it is multisampled. // FBO ID used to render into GrGLuint renderFBOID() const { return fRTFBOID; } // FBO ID that has texture ID attached. @@ -77,8 +76,7 @@ protected: void onAbandon() override; void onRelease() override; - // In protected because subclass GrGLTextureRenderTarget calls this version. - size_t onGpuMemorySize() const override; + int numSamplesOwnedPerPixel() const { return fNumSamplesOwnedPerPixel; } private: // Constructor for instances wrapping backend objects. @@ -89,8 +87,8 @@ private: GrGLGpu* getGLGpu() const; bool completeStencilAttachment() override; - // The total size of the resource (including all pixels) for a single sample. - size_t totalBytesPerSample() const; + size_t onGpuMemorySize() const override; + int msaaSamples() const; // The number total number of samples, including both MSAA and resolve texture samples. int totalSamples() const; @@ -106,9 +104,10 @@ private: // we want the rendering to be at top left (GL has origin in bottom left) GrGLIRect fViewport; - // onGpuMemorySize() needs to know the VRAM footprint of the FBO(s). However, abandon and - // release zero out the IDs and the cache needs to know the size even after those actions. - size_t fGpuMemorySize; + // The RenderTarget needs to be able to report its VRAM footprint even after abandon and + // release have potentially zeroed out the IDs (e.g., so the cache can reset itself). Since + // the IDs are just required for the computation in totalSamples we cache that result here. + int fNumSamplesOwnedPerPixel; typedef GrRenderTarget INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLSampler.h b/gfx/skia/skia/src/gpu/gl/GrGLSampler.h deleted file mode 100644 index 1f67ac9a5e8c..000000000000 --- a/gfx/skia/skia/src/gpu/gl/GrGLSampler.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -* Copyright 2016 Google Inc. -* -* Use of this source code is governed by a BSD-style license that can be -* found in the LICENSE file. -*/ - -#ifndef GrGLSampler_DEFINED -#define GrGLSampler_DEFINED - -#include "glsl/GrGLSLSampler.h" - -#include "gl/GrGLTypes.h" -#include "glsl/GrGLSLShaderVar.h" - -class GrGLSampler : public GrGLSLSampler { -public: - GrGLSampler(uint32_t visibility, - GrPixelConfig config, - GrSLType type, - GrSLPrecision precision, - const char* name) : INHERITED(visibility, config) { - SkASSERT(GrSLTypeIsCombinedSamplerType(type)); - fShaderVar.setType(type); - fShaderVar.setTypeModifier(GrGLSLShaderVar::kUniform_TypeModifier); - fShaderVar.setPrecision(precision); - fShaderVar.accessName()->set(name); - } - - GrGLint location() const { return fLocation; } - GrSLType type() const override { return fShaderVar.getType(); } - - const char* onGetSamplerNameForTexture2D() const override { return fShaderVar.c_str(); } - const char* getSamplerNameForTexelFetch() const override { return fShaderVar.c_str(); } - -private: - GrGLSLShaderVar fShaderVar; - GrGLint fLocation; - - friend class GrGLUniformHandler; - - typedef GrGLSLSampler INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/gl/GrGLSemaphore.h b/gfx/skia/skia/src/gpu/gl/GrGLSemaphore.h new file mode 100644 index 000000000000..40dc53b396f6 --- /dev/null +++ b/gfx/skia/skia/src/gpu/gl/GrGLSemaphore.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLSemaphore_DEFINED +#define GrGLSemaphore_DEFINED + +#include "GrSemaphore.h" + +#include "GrGLGpu.h" + +class GrGLSemaphore : public GrSemaphore { +public: + static sk_sp Make(const GrGLGpu* gpu) { + return sk_sp(new GrGLSemaphore(gpu)); + } + + ~GrGLSemaphore() override { + if (fGpu) { + static_cast(fGpu)->deleteSync(fSync); + } + } + + GrGLsync sync() const { return fSync; } + void setSync(const GrGLsync& sync) { fSync = sync; } + +private: + GrGLSemaphore(const GrGLGpu* gpu) : INHERITED(gpu), fSync(0) {} + + GrGLsync fSync; + + typedef GrSemaphore INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/gl/GrGLTestInterface.cpp b/gfx/skia/skia/src/gpu/gl/GrGLTestInterface.cpp index d871ef6285d7..25d66a94fc0b 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLTestInterface.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLTestInterface.cpp @@ -119,6 +119,7 @@ GrGLTestInterface::GrGLTestInterface() { fFunctions.fMapTexSubImage2D = bind_to_member(this, &GrGLTestInterface::mapTexSubImage2D); fFunctions.fMinSampleShading = bind_to_member(this, &GrGLTestInterface::minSampleShading); fFunctions.fPixelStorei = bind_to_member(this, &GrGLTestInterface::pixelStorei); + fFunctions.fPolygonMode = bind_to_member(this, &GrGLTestInterface::polygonMode); fFunctions.fPopGroupMarker = bind_to_member(this, &GrGLTestInterface::popGroupMarker); fFunctions.fPushGroupMarker = bind_to_member(this, &GrGLTestInterface::pushGroupMarker); fFunctions.fQueryCounter = bind_to_member(this, &GrGLTestInterface::queryCounter); @@ -314,6 +315,7 @@ GrGLTestInterface::GrGLTestInterface() { fFunctions.fTextureBuffer = bind_to_member(this, &GrGLTestInterface::textureBuffer); fFunctions.fFenceSync = bind_to_member(this, &GrGLTestInterface::fenceSync); fFunctions.fClientWaitSync = bind_to_member(this, &GrGLTestInterface::clientWaitSync); + fFunctions.fWaitSync = bind_to_member(this, &GrGLTestInterface::waitSync); fFunctions.fDeleteSync = bind_to_member(this, &GrGLTestInterface::deleteSync); fFunctions.fDebugMessageControl = bind_to_member(this, &GrGLTestInterface::debugMessageControl); fFunctions.fDebugMessageInsert = bind_to_member(this, &GrGLTestInterface::debugMessageInsert); diff --git a/gfx/skia/skia/src/gpu/gl/GrGLTestInterface.h b/gfx/skia/skia/src/gpu/gl/GrGLTestInterface.h index ef00df397359..636f49303739 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLTestInterface.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLTestInterface.h @@ -120,6 +120,7 @@ public: virtual GrGLvoid* mapTexSubImage2D(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLenum access) { return nullptr; } virtual GrGLvoid minSampleShading(GrGLfloat value) {} virtual GrGLvoid pixelStorei(GrGLenum pname, GrGLint param) {} + virtual GrGLvoid polygonMode(GrGLenum face, GrGLenum mode) {} virtual GrGLvoid popGroupMarker() {} virtual GrGLvoid pushGroupMarker(GrGLsizei length, const char* marker) {} virtual GrGLvoid queryCounter(GrGLuint id, GrGLenum target) {} @@ -319,6 +320,7 @@ public: virtual GrGLvoid textureBuffer(GrGLuint texture, GrGLenum target, GrGLenum internalformat, GrGLuint buffer) {} virtual GrGLsync fenceSync(GrGLenum condition, GrGLbitfield flags) { return nullptr; } virtual GrGLenum clientWaitSync(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout) { return GR_GL_WAIT_FAILED; } + virtual GrGLvoid waitSync(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout) {} virtual GrGLvoid deleteSync(GrGLsync sync) {} virtual GrGLvoid debugMessageControl(GrGLenum source, GrGLenum type, GrGLenum severity, GrGLsizei count, const GrGLuint* ids, GrGLboolean enabled) {} virtual GrGLvoid debugMessageInsert(GrGLenum source, GrGLenum type, GrGLuint id, GrGLenum severity, GrGLsizei length, const GrGLchar* buf) {} diff --git a/gfx/skia/skia/src/gpu/gl/GrGLTexture.cpp b/gfx/skia/skia/src/gpu/gl/GrGLTexture.cpp index 9fd9ad87831e..95c8c8fa5ed9 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLTexture.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLTexture.cpp @@ -5,31 +5,56 @@ * found in the LICENSE file. */ +#include "GrContext.h" #include "GrGLTexture.h" #include "GrGLGpu.h" +#include "GrResourceProvider.h" +#include "GrSemaphore.h" +#include "GrShaderCaps.h" +#include "SkMakeUnique.h" #include "SkTraceMemoryDump.h" #define GPUGL static_cast(this->getGpu()) #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X) -inline static GrSLType sampler_type(const GrGLTexture::IDDesc& idDesc, const GrGLGpu* gpu) { +static inline GrSLType sampler_type(const GrGLTexture::IDDesc& idDesc, GrPixelConfig config, + const GrGLGpu* gpu) { if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_EXTERNAL) { - SkASSERT(gpu->glCaps().glslCaps()->externalTextureSupport()); + SkASSERT(gpu->caps()->shaderCaps()->externalTextureSupport()); + SkASSERT(!GrPixelConfigIsSint(config)); return kTextureExternalSampler_GrSLType; } else if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_RECTANGLE) { SkASSERT(gpu->glCaps().rectangleTextureSupport()); + SkASSERT(!GrPixelConfigIsSint(config)); return kTexture2DRectSampler_GrSLType; + } else if (GrPixelConfigIsSint(config)) { + return kITexture2DSampler_GrSLType; } else { SkASSERT(idDesc.fInfo.fTarget == GR_GL_TEXTURE_2D); return kTexture2DSampler_GrSLType; } } +static inline GrSamplerParams::FilterMode highest_filter_mode(const GrGLTexture::IDDesc& idDesc, + GrPixelConfig config) { + if (GrPixelConfigIsSint(config)) { + // Integer textures in GL can use GL_NEAREST_MIPMAP_NEAREST. This is a mode we don't support + // and don't currently have a use for. + return GrSamplerParams::kNone_FilterMode; + } + if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_RECTANGLE || + idDesc.fInfo.fTarget == GR_GL_TEXTURE_EXTERNAL) { + return GrSamplerParams::kBilerp_FilterMode; + } + return GrSamplerParams::kMipMap_FilterMode; +} + // Because this class is virtually derived from GrSurface we must explicitly call its constructor. GrGLTexture::GrGLTexture(GrGLGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc, const IDDesc& idDesc) : GrSurface(gpu, desc) - , INHERITED(gpu, desc, sampler_type(idDesc, gpu), false) { + , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu), + highest_filter_mode(idDesc, desc.fConfig), false) { this->init(desc, idDesc); this->registerWithCache(budgeted); } @@ -38,21 +63,27 @@ GrGLTexture::GrGLTexture(GrGLGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& const IDDesc& idDesc, bool wasMipMapDataProvided) : GrSurface(gpu, desc) - , INHERITED(gpu, desc, sampler_type(idDesc, gpu), wasMipMapDataProvided) { + , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu), + highest_filter_mode(idDesc, desc.fConfig), + wasMipMapDataProvided) { this->init(desc, idDesc); this->registerWithCache(budgeted); } GrGLTexture::GrGLTexture(GrGLGpu* gpu, Wrapped, const GrSurfaceDesc& desc, const IDDesc& idDesc) : GrSurface(gpu, desc) - , INHERITED(gpu, desc, sampler_type(idDesc, gpu), false) { + , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu), + highest_filter_mode(idDesc, desc.fConfig), false) { this->init(desc, idDesc); this->registerWithCacheWrapped(); } -GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc) +GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc, + bool wasMipMapDataProvided) : GrSurface(gpu, desc) - , INHERITED(gpu, desc, sampler_type(idDesc, gpu), false) { + , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu), + highest_filter_mode(idDesc, desc.fConfig), + wasMipMapDataProvided) { this->init(desc, idDesc); } @@ -81,11 +112,29 @@ void GrGLTexture::onAbandon() { } GrBackendObject GrGLTexture::getTextureHandle() const { -#ifdef SK_IGNORE_GL_TEXTURE_TARGET - return static_cast(this->textureID()); -#else return reinterpret_cast(&fInfo); -#endif +} + +std::unique_ptr GrGLTexture::detachBackendTexture() { + SkASSERT(!this->hasPendingIO()); + + // Set up a semaphore to be signaled once the data is ready, and flush GL + sk_sp semaphore = this->getContext()->resourceProvider()->makeSemaphore(); + this->getGpu()->insertSemaphore(semaphore); + this->getGpu()->flush(); + + // Make a copy of our GL-specific information + auto data = skstd::make_unique(fInfo, std::move(semaphore), + this->getContext()); + + // Ensure the cache can't reach this texture anymore + this->detachFromCache(); + + // Detach from the GL object, so we don't use it (or try to delete it when we're freed) + fInfo.fTarget = 0; + fInfo.fID = 0; + + return std::move(data); } void GrGLTexture::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump, @@ -96,8 +145,8 @@ void GrGLTexture::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump, texture_id.c_str()); } -GrGLTexture* GrGLTexture::CreateWrapped(GrGLGpu* gpu, const GrSurfaceDesc& desc, - const IDDesc& idDesc) { - return new GrGLTexture(gpu, kWrapped, desc, idDesc); +sk_sp GrGLTexture::MakeWrapped(GrGLGpu* gpu, const GrSurfaceDesc& desc, + const IDDesc& idDesc) { + return sk_sp(new GrGLTexture(gpu, kWrapped, desc, idDesc)); } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLTexture.h b/gfx/skia/skia/src/gpu/gl/GrGLTexture.h index 05d26c8de821..16b47f1f07ce 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLTexture.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLTexture.h @@ -56,10 +56,10 @@ public: GrGLenum target() const { return fInfo.fTarget; } - static GrGLTexture* CreateWrapped(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&); + static sk_sp MakeWrapped(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&); protected: // Constructor for subclasses. - GrGLTexture(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&); + GrGLTexture(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&, bool wasMipMapDataProvided); enum Wrapped { kWrapped }; // Constructor for instances wrapping backend objects. @@ -71,6 +71,7 @@ protected: void onRelease() override; void setMemoryBacking(SkTraceMemoryDump* traceMemoryDump, const SkString& dumpName) const override; + std::unique_ptr detachBackendTexture() override; private: TexParams fTexParams; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLTextureRenderTarget.cpp b/gfx/skia/skia/src/gpu/gl/GrGLTextureRenderTarget.cpp index 2ba469a9f2aa..0abeb8ea61b9 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLTextureRenderTarget.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLTextureRenderTarget.cpp @@ -18,7 +18,7 @@ void GrGLTextureRenderTarget::dumpMemoryStatistics( // texture and a // renderbuffer component, dump as skia/gpu_resources/resource_#/texture SkString dumpName("skia/gpu_resources/resource_"); - dumpName.appendS32(this->uniqueID()); + dumpName.appendU32(this->uniqueID().asUInt()); dumpName.append("/texture"); // Use the texture's gpuMemorySize, not our own, which includes the @@ -44,9 +44,10 @@ bool GrGLTextureRenderTarget::canAttemptStencilAttachment() const { return true; } -GrGLTextureRenderTarget* GrGLTextureRenderTarget::CreateWrapped(GrGLGpu* gpu, - const GrSurfaceDesc& desc, - const GrGLTexture::IDDesc& texIDDesc, - const GrGLRenderTarget::IDDesc& rtIDDesc) { - return new GrGLTextureRenderTarget(gpu, desc, texIDDesc, rtIDDesc); +sk_sp GrGLTextureRenderTarget::MakeWrapped( + GrGLGpu* gpu, const GrSurfaceDesc& desc, + const GrGLTexture::IDDesc& texIDDesc, const GrGLRenderTarget::IDDesc& rtIDDesc) +{ + return sk_sp( + new GrGLTextureRenderTarget(gpu, desc, texIDDesc, rtIDDesc, false)); } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLTextureRenderTarget.h b/gfx/skia/skia/src/gpu/gl/GrGLTextureRenderTarget.h index 0826cf3a714d..7ff8d490e038 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLTextureRenderTarget.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLTextureRenderTarget.h @@ -12,6 +12,7 @@ #include "GrGLGpu.h" #include "GrGLTexture.h" #include "GrGLRenderTarget.h" +#include "GrTexturePriv.h" class GrGLGpu; @@ -29,9 +30,10 @@ public: SkBudgeted budgeted, const GrSurfaceDesc& desc, const GrGLTexture::IDDesc& texIDDesc, - const GrGLRenderTarget::IDDesc& rtIDDesc) + const GrGLRenderTarget::IDDesc& rtIDDesc, + bool wasMipMapDataProvided) : GrSurface(gpu, desc) - , GrGLTexture(gpu, desc, texIDDesc) + , GrGLTexture(gpu, desc, texIDDesc, wasMipMapDataProvided) , GrGLRenderTarget(gpu, desc, rtIDDesc) { this->registerWithCache(budgeted); } @@ -40,9 +42,9 @@ public: void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const override; - static GrGLTextureRenderTarget* CreateWrapped(GrGLGpu* gpu, const GrSurfaceDesc& desc, - const GrGLTexture::IDDesc& texIDDesc, - const GrGLRenderTarget::IDDesc& rtIDDesc); + static sk_sp MakeWrapped(GrGLGpu* gpu, const GrSurfaceDesc& desc, + const GrGLTexture::IDDesc& texIDDesc, + const GrGLRenderTarget::IDDesc& rtIDDesc); protected: void onAbandon() override { GrGLRenderTarget::onAbandon(); @@ -59,16 +61,18 @@ private: GrGLTextureRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, const GrGLTexture::IDDesc& texIDDesc, - const GrGLRenderTarget::IDDesc& rtIDDesc) + const GrGLRenderTarget::IDDesc& rtIDDesc, + bool wasMipMapDataProvided) : GrSurface(gpu, desc) - , GrGLTexture(gpu, desc, texIDDesc) + , GrGLTexture(gpu, desc, texIDDesc, wasMipMapDataProvided) , GrGLRenderTarget(gpu, desc, rtIDDesc) { this->registerWithCacheWrapped(); } - // GrGLRenderTarget accounts for the texture's memory and any MSAA renderbuffer's memory. size_t onGpuMemorySize() const override { - return GrGLRenderTarget::onGpuMemorySize(); + return GrSurface::ComputeSize(fDesc, + this->numSamplesOwnedPerPixel(), + this->texturePriv().hasMipMaps()); } }; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.cpp b/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.cpp index c388e4621be2..b00779bf5dfb 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.cpp @@ -23,14 +23,12 @@ GrGLSLUniformHandler::UniformHandle GrGLUniformHandler::internalAddUniformArray( int arrayCount, const char** outName) { SkASSERT(name && strlen(name)); - SkDEBUGCODE(static const uint32_t kVisMask = kVertex_GrShaderFlag | kFragment_GrShaderFlag); - SkASSERT(0 == (~kVisMask & visibility)); SkASSERT(0 != visibility); SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type)); UniformInfo& uni = fUniforms.push_back(); uni.fVariable.setType(type); - uni.fVariable.setTypeModifier(GrGLSLShaderVar::kUniform_TypeModifier); + uni.fVariable.setTypeModifier(GrShaderVar::kUniform_TypeModifier); // TODO this is a bit hacky, lets think of a better way. Basically we need to be able to use // the uniform view matrix name in the GP, and the GP is immutable so it has to tell the PB // exactly what name it wants to use for the uniform view matrix. If we prefix anythings, then @@ -45,6 +43,7 @@ GrGLSLUniformHandler::UniformHandle GrGLUniformHandler::internalAddUniformArray( uni.fVariable.setArrayCount(arrayCount); uni.fVisibility = visibility; uni.fVariable.setPrecision(precision); + uni.fLocation = -1; if (outName) { *outName = uni.fVariable.c_str(); @@ -52,48 +51,92 @@ GrGLSLUniformHandler::UniformHandle GrGLUniformHandler::internalAddUniformArray( return GrGLSLUniformHandler::UniformHandle(fUniforms.count() - 1); } -GrGLSLUniformHandler::SamplerHandle GrGLUniformHandler::internalAddSampler(uint32_t visibility, - GrPixelConfig config, - GrSLType type, - GrSLPrecision precision, - const char* name) { +GrGLSLUniformHandler::SamplerHandle GrGLUniformHandler::addSampler(uint32_t visibility, + GrSwizzle swizzle, + GrSLType type, + GrSLPrecision precision, + const char* name) { + SkASSERT(name && strlen(name)); + SkASSERT(0 != visibility); + + SkString mangleName; + char prefix = 'u'; + fProgramBuilder->nameVariable(&mangleName, prefix, name, true); + + UniformInfo& sampler = fSamplers.push_back(); + SkASSERT(GrSLTypeIsCombinedSamplerType(type)); + sampler.fVariable.setType(type); + sampler.fVariable.setTypeModifier(GrShaderVar::kUniform_TypeModifier); + sampler.fVariable.setPrecision(precision); + sampler.fVariable.setName(mangleName); + sampler.fLocation = -1; + sampler.fVisibility = visibility; + fSamplerSwizzles.push_back(swizzle); + SkASSERT(fSamplers.count() == fSamplerSwizzles.count()); + return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1); +} + +GrGLSLUniformHandler::ImageStorageHandle GrGLUniformHandler::addImageStorage( + uint32_t visibility, GrSLType type, GrImageStorageFormat format, GrSLMemoryModel model, + GrSLRestrict restrict, GrIOType ioType, const char* name) { SkASSERT(name && strlen(name)); - SkDEBUGCODE(static const uint32_t kVisMask = kVertex_GrShaderFlag | kFragment_GrShaderFlag); - SkASSERT(0 == (~kVisMask & visibility)); SkASSERT(0 != visibility); SkString mangleName; char prefix = 'u'; fProgramBuilder->nameVariable(&mangleName, prefix, name, true); - fSamplers.emplace_back(visibility, config, type, precision, mangleName.c_str()); - return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1); + + UniformInfo& imageStorage = fImageStorages.push_back(); + imageStorage.fVariable.setName(mangleName); + + SkASSERT(GrSLTypeIsImageStorage(type)); + imageStorage.fVariable.setType(type); + imageStorage.fVariable.setTypeModifier(GrShaderVar::kUniform_TypeModifier); + imageStorage.fVariable.setImageStorageFormat(format); + imageStorage.fVariable.setMemoryModel(model); + imageStorage.fVariable.setRestrict(restrict); + imageStorage.fVariable.setIOType(ioType); + imageStorage.fVariable.setPrecision(kHigh_GrSLPrecision); + imageStorage.fLocation = -1; + imageStorage.fVisibility = visibility; + return GrGLSLUniformHandler::ImageStorageHandle(fImageStorages.count() - 1); } void GrGLUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const { for (int i = 0; i < fUniforms.count(); ++i) { if (fUniforms[i].fVisibility & visibility) { - fUniforms[i].fVariable.appendDecl(fProgramBuilder->glslCaps(), out); - out->append(";\n"); + fUniforms[i].fVariable.appendDecl(fProgramBuilder->shaderCaps(), out); + out->append(";"); } } for (int i = 0; i < fSamplers.count(); ++i) { - if (fSamplers[i].visibility() & visibility) { - fSamplers[i].fShaderVar.appendDecl(fProgramBuilder->glslCaps(), out); + if (fSamplers[i].fVisibility & visibility) { + fSamplers[i].fVariable.appendDecl(fProgramBuilder->shaderCaps(), out); out->append(";\n"); } } + for (int i = 0; i < fImageStorages.count(); ++i) { + if (fImageStorages[i].fVisibility & visibility) { + fImageStorages[i].fVariable.appendDecl(fProgramBuilder->shaderCaps(), out); + out->append(";"); + } + } } void GrGLUniformHandler::bindUniformLocations(GrGLuint programID, const GrGLCaps& caps) { if (caps.bindUniformLocationSupport()) { - int uniformCnt = fUniforms.count(); - for (int i = 0; i < uniformCnt; ++i) { - GL_CALL(BindUniformLocation(programID, i, fUniforms[i].fVariable.c_str())); - fUniforms[i].fLocation = i; + int currUniform = 0; + for (int i = 0; i < fUniforms.count(); ++i, ++currUniform) { + GL_CALL(BindUniformLocation(programID, currUniform, fUniforms[i].fVariable.c_str())); + fUniforms[i].fLocation = currUniform; } - for (int i = 0; i < fSamplers.count(); ++i) { - GrGLint location = i + uniformCnt; - GL_CALL(BindUniformLocation(programID, location, fSamplers[i].fShaderVar.c_str())); - fSamplers[i].fLocation = location; + for (int i = 0; i < fSamplers.count(); ++i, ++currUniform) { + GL_CALL(BindUniformLocation(programID, currUniform, fSamplers[i].fVariable.c_str())); + fSamplers[i].fLocation = currUniform; + } + for (int i = 0; i < fImageStorages.count(); ++i) { + GL_CALL(BindUniformLocation(programID, currUniform, + fImageStorages[i].fVariable.c_str())); + fImageStorages[i].fLocation = currUniform; } } } @@ -108,9 +151,15 @@ void GrGLUniformHandler::getUniformLocations(GrGLuint programID, const GrGLCaps& } for (int i = 0; i < fSamplers.count(); ++i) { GrGLint location; - GL_CALL_RET(location, GetUniformLocation(programID, fSamplers[i].fShaderVar.c_str())); + GL_CALL_RET(location, GetUniformLocation(programID, fSamplers[i].fVariable.c_str())); fSamplers[i].fLocation = location; } + for (int i = 0; i < fImageStorages.count(); ++i) { + GrGLint location; + GL_CALL_RET(location, GetUniformLocation(programID, + fImageStorages[i].fVariable.c_str())); + fImageStorages[i].fLocation = location; + } } } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.h b/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.h index 3656d3a10810..da7b13c4f5c1 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.h @@ -11,7 +11,6 @@ #include "glsl/GrGLSLUniformHandler.h" #include "gl/GrGLProgramDataManager.h" -#include "gl/GrGLSampler.h" class GrGLCaps; @@ -19,7 +18,7 @@ class GrGLUniformHandler : public GrGLSLUniformHandler { public: static const int kUniformsPerBlock = 8; - const GrGLSLShaderVar& getUniformVariable(UniformHandle u) const override { + const GrShaderVar& getUniformVariable(UniformHandle u) const override { return fUniforms[u.toIndex()].fVariable; } @@ -29,7 +28,9 @@ public: private: explicit GrGLUniformHandler(GrGLSLProgramBuilder* program) : INHERITED(program) - , fUniforms(kUniformsPerBlock) {} + , fUniforms(kUniformsPerBlock) + , fSamplers(kUniformsPerBlock) + , fImageStorages(kUniformsPerBlock) {} UniformHandle internalAddUniformArray(uint32_t visibility, GrSLType type, @@ -39,15 +40,23 @@ private: int arrayCount, const char** outName) override; - SamplerHandle internalAddSampler(uint32_t visibility, - GrPixelConfig config, - GrSLType type, - GrSLPrecision precision, - const char* name) override; + SamplerHandle addSampler(uint32_t visibility, GrSwizzle, GrSLType, GrSLPrecision, + const char* name) override; - int numSamplers() const override { return fSamplers.count(); } - const GrGLSLSampler& getSampler(SamplerHandle handle) const override { - return fSamplers[handle.toIndex()]; + const GrShaderVar& samplerVariable(SamplerHandle handle) const override { + return fSamplers[handle.toIndex()].fVariable; + } + + ImageStorageHandle addImageStorage(uint32_t visibility, GrSLType, GrImageStorageFormat, + GrSLMemoryModel, GrSLRestrict, GrIOType, + const char* name) override; + + GrSwizzle samplerSwizzle(SamplerHandle handle) const override { + return fSamplerSwizzles[handle.toIndex()]; + } + + const GrShaderVar& imageStorageVariable(ImageStorageHandle handle) const override { + return fImageStorages[handle.toIndex()].fVariable; } void appendUniformDecls(GrShaderFlags visibility, SkString*) const override; @@ -63,9 +72,10 @@ private: typedef GrGLProgramDataManager::UniformInfo UniformInfo; typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray; - UniformInfoArray fUniforms; - - SkTArray fSamplers; + UniformInfoArray fUniforms; + UniformInfoArray fSamplers; + SkTArray fSamplerSwizzles; + UniformInfoArray fImageStorages; friend class GrGLProgramBuilder; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLUtil.cpp b/gfx/skia/skia/src/gpu/gl/GrGLUtil.cpp index 23544fee9aff..443d77c3ef42 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLUtil.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLUtil.cpp @@ -111,7 +111,11 @@ void GrGLGetDriverInfo(GrGLStandard standard, versionString = ""; } - if (0 == strcmp(rendererString, "Chromium")) { + static const char kChromium[] = "Chromium"; + char suffix[SK_ARRAY_COUNT(kChromium)]; + if (0 == strcmp(rendererString, kChromium) || + (3 == sscanf(versionString, "OpenGL ES %d.%d %8s", &major, &minor, suffix) && + 0 == strcmp(kChromium, suffix))) { *outDriver = kChromium_GrGLDriver; return; } @@ -309,7 +313,7 @@ GrGLRenderer GrGLGetRendererFromString(const char* rendererString) { } } } - if (strcmp("Mesa Offscreen", rendererString)) { + if (0 == strcmp("Mesa Offscreen", rendererString)) { return kOSMesa_GrGLRenderer; } } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLVertexArray.cpp b/gfx/skia/skia/src/gpu/gl/GrGLVertexArray.cpp index 04299d7854f0..807b9d091b20 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLVertexArray.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLVertexArray.cpp @@ -10,32 +10,43 @@ #include "GrGLGpu.h" struct AttribLayout { - GrGLint fCount; - GrGLenum fType; - GrGLboolean fNormalized; // Only used by floating point types. + bool fNormalized; // Only used by floating point types. + uint8_t fCount; + uint16_t fType; }; -static const AttribLayout gLayouts[kGrVertexAttribTypeCount] = { - {1, GR_GL_FLOAT, false}, // kFloat_GrVertexAttribType - {2, GR_GL_FLOAT, false}, // kVec2f_GrVertexAttribType - {3, GR_GL_FLOAT, false}, // kVec3f_GrVertexAttribType - {4, GR_GL_FLOAT, false}, // kVec4f_GrVertexAttribType - {1, GR_GL_UNSIGNED_BYTE, true}, // kUByte_GrVertexAttribType - {4, GR_GL_UNSIGNED_BYTE, true}, // kVec4ub_GrVertexAttribType - {2, GR_GL_UNSIGNED_SHORT, true}, // kVec2s_GrVertexAttribType - {1, GR_GL_INT, false}, // kInt_GrVertexAttribType - {1, GR_GL_UNSIGNED_INT, false}, // kUint_GrVertexAttribType -}; +GR_STATIC_ASSERT(4 == sizeof(AttribLayout)); -GR_STATIC_ASSERT(0 == kFloat_GrVertexAttribType); -GR_STATIC_ASSERT(1 == kVec2f_GrVertexAttribType); -GR_STATIC_ASSERT(2 == kVec3f_GrVertexAttribType); -GR_STATIC_ASSERT(3 == kVec4f_GrVertexAttribType); -GR_STATIC_ASSERT(4 == kUByte_GrVertexAttribType); -GR_STATIC_ASSERT(5 == kVec4ub_GrVertexAttribType); -GR_STATIC_ASSERT(6 == kVec2us_GrVertexAttribType); -GR_STATIC_ASSERT(7 == kInt_GrVertexAttribType); -GR_STATIC_ASSERT(8 == kUint_GrVertexAttribType); +static AttribLayout attrib_layout(GrVertexAttribType type) { + switch (type) { + case kFloat_GrVertexAttribType: + return {false, 1, GR_GL_FLOAT}; + case kVec2f_GrVertexAttribType: + return {false, 2, GR_GL_FLOAT}; + case kVec3f_GrVertexAttribType: + return {false, 3, GR_GL_FLOAT}; + case kVec4f_GrVertexAttribType: + return {false, 4, GR_GL_FLOAT}; + case kVec2i_GrVertexAttribType: + return {false, 2, GR_GL_INT}; + case kVec3i_GrVertexAttribType: + return {false, 3, GR_GL_INT}; + case kVec4i_GrVertexAttribType: + return {false, 4, GR_GL_INT}; + case kUByte_GrVertexAttribType: + return {true, 1, GR_GL_UNSIGNED_BYTE}; + case kVec4ub_GrVertexAttribType: + return {true, 4, GR_GL_UNSIGNED_BYTE}; + case kVec2us_GrVertexAttribType: + return {true, 2, GR_GL_UNSIGNED_SHORT}; + case kInt_GrVertexAttribType: + return {false, 1, GR_GL_INT}; + case kUint_GrVertexAttribType: + return {false, 1, GR_GL_UNSIGNED_INT}; + } + SkFAIL("Unknown vertex attrib type"); + return {false, 0, 0}; +}; void GrGLAttribArrayState::set(GrGLGpu* gpu, int index, @@ -55,7 +66,7 @@ void GrGLAttribArrayState::set(GrGLGpu* gpu, array->fStride != stride || array->fOffset != offset) { gpu->bindBuffer(kVertex_GrBufferType, vertexBuffer); - const AttribLayout& layout = gLayouts[type]; + const AttribLayout& layout = attrib_layout(type); if (!GrVertexAttribTypeIsIntType(type)) { GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index, layout.fCount, @@ -129,5 +140,5 @@ GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(GrGLGpu* gpu, const G void GrGLVertexArray::invalidateCachedState() { fAttribArrays.invalidate(); - fIndexBufferUniqueID = SK_InvalidUniqueID; + fIndexBufferUniqueID.makeInvalid(); } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLVertexArray.h b/gfx/skia/skia/src/gpu/gl/GrGLVertexArray.h index 639892690f7c..4c77d2b5824c 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLVertexArray.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLVertexArray.h @@ -8,6 +8,7 @@ #ifndef GrGLVertexArray_DEFINED #define GrGLVertexArray_DEFINED +#include "GrGpuResource.h" #include "GrTypesPriv.h" #include "gl/GrGLDefines.h" #include "gl/GrGLTypes.h" @@ -68,17 +69,17 @@ private: * Tracks the state of glVertexAttribArray for an attribute index. */ struct AttribArrayState { - void invalidate() { - fEnableIsValid = false; - fVertexBufferUniqueID = SK_InvalidUniqueID; - } + void invalidate() { + fEnableIsValid = false; + fVertexBufferUniqueID.makeInvalid(); + } - bool fEnableIsValid; - bool fEnabled; - uint32_t fVertexBufferUniqueID; - GrVertexAttribType fType; - GrGLsizei fStride; - GrGLvoid* fOffset; + bool fEnableIsValid; + bool fEnabled; + GrGpuResource::UniqueID fVertexBufferUniqueID; + GrVertexAttribType fType; + GrGLsizei fStride; + GrGLvoid* fOffset; }; SkSTArray<16, AttribArrayState, true> fAttribArrayStates; @@ -110,9 +111,9 @@ public: void invalidateCachedState(); private: - GrGLuint fID; - GrGLAttribArrayState fAttribArrays; - uint32_t fIndexBufferUniqueID; + GrGLuint fID; + GrGLAttribArrayState fAttribArrays; + GrGpuResource::UniqueID fIndexBufferUniqueID; }; #endif diff --git a/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 370cee6a0e7b..9ddfa80baf64 100644 --- a/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -11,18 +11,19 @@ #include "GrCoordTransform.h" #include "GrGLProgramBuilder.h" #include "GrProgramDesc.h" +#include "GrShaderCaps.h" #include "GrSwizzle.h" #include "GrTexture.h" +#include "SkAutoMalloc.h" +#include "SkATrace.h" #include "SkTraceEvent.h" #include "gl/GrGLGpu.h" #include "gl/GrGLProgram.h" #include "gl/GrGLSLPrettyPrint.h" #include "gl/builders/GrGLShaderStringBuilder.h" -#include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLSampler.h" #include "glsl/GrGLSLXferProcessor.h" #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) @@ -30,8 +31,9 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, - const GrProgramDesc& desc, + GrProgramDesc* desc, GrGLGpu* gpu) { + ATRACE_ANDROID_FRAMEWORK("Shader Compile"); GrAutoLocaleSetter als("C"); // create a builder. This will be handed off to effects so they can use it to add @@ -56,7 +58,7 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPipeline& pipeline, GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, - const GrProgramDesc& desc) + GrProgramDesc* desc) : INHERITED(pipeline, primProc, desc) , fGpu(gpu) , fVaryingHandler(this) @@ -67,14 +69,12 @@ const GrCaps* GrGLProgramBuilder::caps() const { return fGpu->caps(); } -const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const { - return fGpu->ctxInfo().caps()->glslCaps(); -} - bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader, GrGLuint programId, GrGLenum type, - SkTDArray* shaderIds) { + SkTDArray* shaderIds, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs) { GrGLGpu* gpu = this->gpu(); GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(), programId, @@ -82,13 +82,21 @@ bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader, shader.fCompilerStrings.begin(), shader.fCompilerStringLengths.begin(), shader.fCompilerStrings.count(), - gpu->stats()); + gpu->stats(), + settings, + outInputs); if (!shaderId) { return false; } *shaderIds->append() = shaderId; + if (outInputs->fFlipY) { + GrProgramDesc* d = this->desc(); + d->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin( + this->pipeline().getRenderTarget()->origin())); + d->finalize(); + } return true; } @@ -105,28 +113,44 @@ GrGLProgram* GrGLProgramBuilder::finalize() { this->finalizeShaders(); // compile shaders and bind attributes / uniforms + SkSL::Program::Settings settings; + settings.fCaps = this->gpu()->glCaps().shaderCaps(); + settings.fFlipY = this->pipeline().getRenderTarget()->origin() != kTopLeft_GrSurfaceOrigin; + SkSL::Program::Inputs inputs; SkTDArray shadersToDelete; - if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete)) { + if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete, + settings, &inputs)) { this->cleanupProgram(programID, shadersToDelete); return nullptr; } // NVPR actually requires a vertex shader to compile - bool useNvpr = primitiveProcessor().isPathRendering(); + const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); + bool useNvpr = primProc.isPathRendering(); if (!useNvpr) { - const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); - int vaCount = primProc.numAttribs(); for (int i = 0; i < vaCount; i++) { GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName)); } } - if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete)) { + if (primProc.willUseGeoShader() && + !this->compileAndAttachShaders(fGS, programID, GR_GL_GEOMETRY_SHADER, &shadersToDelete, + settings, &inputs)) { this->cleanupProgram(programID, shadersToDelete); return nullptr; } + if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete, + settings, &inputs)) { + this->cleanupProgram(programID, shadersToDelete); + return nullptr; + } + + if (inputs.fRTHeight) { + this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); + } + this->bindProgramResourceLocations(programID); GL_CALL(LinkProgram(programID)); @@ -154,7 +178,7 @@ void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) { GL_CALL(BindFragDataLocation(programID, 0, GrGLSLFragmentShaderBuilder::DeclaredColorOutputName())); } - if (fFS.hasSecondaryOutput() && caps.glslCaps()->mustDeclareFragmentShaderOutput()) { + if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) { GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName())); } @@ -228,11 +252,12 @@ void GrGLProgramBuilder::cleanupShaders(const SkTDArray& shaderIDs) { GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) { return new GrGLProgram(fGpu, - this->desc(), + *this->desc(), fUniformHandles, programID, fUniformHandler.fUniforms, fUniformHandler.fSamplers, + fUniformHandler.fImageStorages, fVaryingHandler.fPathProcVaryingInfos, fGeometryProcessor, fXferProcessor, diff --git a/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.h b/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.h index 253f9e632812..cfbb73415568 100644 --- a/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.h +++ b/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.h @@ -14,12 +14,13 @@ #include "gl/GrGLVaryingHandler.h" #include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "ir/SkSLProgram.h" class GrFragmentProcessor; class GrGLContextInfo; class GrProgramDesc; class GrGLSLShaderBuilder; -class GrGLSLCaps; +class GrShaderCaps; class GrGLProgramBuilder : public GrGLSLProgramBuilder { public: @@ -28,26 +29,30 @@ public: * The program implements what is specified in the stages given as input. * After successful generation, the builder result objects are available * to be used. + * This function may modify the GrProgramDesc by setting the surface origin + * key to 0 (unspecified) if it turns out the program does not care about + * the surface origin. * @return true if generation was successful. */ static GrGLProgram* CreateProgram(const GrPipeline&, const GrPrimitiveProcessor&, - const GrProgramDesc&, + GrProgramDesc*, GrGLGpu*); const GrCaps* caps() const override; - const GrGLSLCaps* glslCaps() const override; GrGLGpu* gpu() const { return fGpu; } private: GrGLProgramBuilder(GrGLGpu*, const GrPipeline&, const GrPrimitiveProcessor&, - const GrProgramDesc&); + GrProgramDesc*); bool compileAndAttachShaders(GrGLSLShaderBuilder& shader, GrGLuint programId, GrGLenum type, - SkTDArray* shaderIds); + SkTDArray* shaderIds, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs); GrGLProgram* finalize(); void bindProgramResourceLocations(GrGLuint programID); bool checkLinkStatus(GrGLuint programID); diff --git a/gfx/skia/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp b/gfx/skia/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp index d2e49a5cfb0b..e3d2defdef7c 100644 --- a/gfx/skia/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp +++ b/gfx/skia/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp @@ -6,9 +6,13 @@ */ #include "GrGLShaderStringBuilder.h" +#include "SkAutoMalloc.h" +#include "SkSLCompiler.h" +#include "SkSLGLSLCodeGenerator.h" +#include "SkTraceEvent.h" #include "gl/GrGLGpu.h" #include "gl/GrGLSLPrettyPrint.h" -#include "SkTraceEvent.h" +#include "ir/SkSLProgram.h" #define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X) #define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X) @@ -16,7 +20,7 @@ // Print the source code for all shaders generated. static const bool c_PrintShaders{false}; -static void print_shader_source(const char** strings, int* lengths, int count); +static void print_source_with_line_numbers(const SkString&); GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, GrGLuint programId, @@ -24,7 +28,9 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, const char** strings, int* lengths, int count, - GrGpu::Stats* stats) { + GrGpu::Stats* stats, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs) { const GrGLInterface* gli = glCtx.interface(); GrGLuint shaderId; @@ -33,15 +39,42 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, return 0; } + SkString sksl; #ifdef SK_DEBUG - SkString prettySource = GrGLSLPrettyPrint::PrettyPrintGLSL(strings, lengths, count, false); - const GrGLchar* sourceStr = prettySource.c_str(); - GrGLint sourceLength = static_cast(prettySource.size()); - GR_GL_CALL(gli, ShaderSource(shaderId, 1, &sourceStr, &sourceLength)); + sksl = GrGLSLPrettyPrint::PrettyPrintGLSL(strings, lengths, count, false); #else - GR_GL_CALL(gli, ShaderSource(shaderId, count, strings, lengths)); + for (int i = 0; i < count; i++) { + sksl.append(strings[i], lengths[i]); + } #endif + SkSL::String glsl; + if (type == GR_GL_VERTEX_SHADER || type == GR_GL_FRAGMENT_SHADER) { + SkSL::Compiler& compiler = *glCtx.compiler(); + std::unique_ptr program; + program = compiler.convertProgram( + type == GR_GL_VERTEX_SHADER ? SkSL::Program::kVertex_Kind + : SkSL::Program::kFragment_Kind, + sksl, + settings); + if (!program || !compiler.toGLSL(*program, &glsl)) { + SkDebugf("SKSL compilation error\n----------------------\n"); + SkDebugf("SKSL:\n"); + print_source_with_line_numbers(sksl); + SkDebugf("\nErrors:\n%s\n", compiler.errorText().c_str()); + SkDEBUGFAIL("SKSL compilation failed!\n"); + } + *outInputs = program->fInputs; + } else { + // TODO: geometry shader support in sksl. + SkASSERT(type == GR_GL_GEOMETRY_SHADER); + glsl = sksl; + } + + const char* glslChars = glsl.c_str(); + GrGLint glslLength = (GrGLint) glsl.size(); + GR_GL_CALL(gli, ShaderSource(shaderId, 1, &glslChars, &glslLength)); + // If tracing is enabled in chrome then we pretty print bool traceShader; TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), &traceShader); @@ -72,17 +105,28 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, // buffer param validation. GrGLsizei length = GR_GL_INIT_ZERO; GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, &length, (char*)log.get())); - print_shader_source(strings, lengths, count); - SkDebugf("\n%s", (const char*)log.get()); + SkDebugf("GLSL compilation error\n----------------------\n"); + SkDebugf("SKSL:\n"); + print_source_with_line_numbers(sksl); + SkDebugf("GLSL:\n"); + print_source_with_line_numbers(glsl); + SkDebugf("Errors:\n%s\n", (const char*) log.get()); } - SkDEBUGFAIL("Shader compilation failed!"); + SkDEBUGFAIL("GLSL compilation failed!"); GR_GL_CALL(gli, DeleteShader(shaderId)); return 0; } } if (c_PrintShaders) { - print_shader_source(strings, lengths, count); + const char* typeName = "Unknown"; + switch (type) { + case GR_GL_VERTEX_SHADER: typeName = "Vertex"; break; + case GR_GL_GEOMETRY_SHADER: typeName = "Geometry"; break; + case GR_GL_FRAGMENT_SHADER: typeName = "Fragment"; break; + } + SkDebugf("---- %s shader ----------------------------------------------------\n", typeName); + print_source_with_line_numbers(sksl); } // Attach the shader, but defer deletion until after we have linked the program. @@ -94,12 +138,11 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, return shaderId; } -static void print_shader_source(const char** strings, int* lengths, int count) { - const SkString& pretty = GrGLSLPrettyPrint::PrettyPrintGLSL(strings, lengths, count, true); +static void print_source_with_line_numbers(const SkString& source) { SkTArray lines; - SkStrSplit(pretty.c_str(), "\n", &lines); - for (const SkString& line : lines) { + SkStrSplit(source.c_str(), "\n", kStrict_SkStrSplitMode, &lines); + for (int line = 0; line < lines.count(); ++line) { // Print the shader one line at the time so it doesn't get truncated by the adb log. - SkDebugf("%s\n", line.c_str()); + SkDebugf("%4i\t%s\n", line + 1, lines[line].c_str()); } } diff --git a/gfx/skia/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.h b/gfx/skia/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.h index 062e229cdf87..242fe617e07d 100644 --- a/gfx/skia/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.h +++ b/gfx/skia/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.h @@ -11,6 +11,7 @@ #include "GrAllocator.h" #include "GrGpu.h" #include "gl/GrGLContext.h" +#include "SkSLGLSLCodeGenerator.h" #include "SkTypes.h" GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, @@ -19,6 +20,8 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, const char** strings, int* lengths, int count, - GrGpu::Stats*); + GrGpu::Stats*, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* inputs); #endif diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSL.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSL.cpp index bec4784db25f..d54ddee0d647 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSL.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSL.cpp @@ -5,9 +5,9 @@ * found in the LICENSE file. */ -#include "GrGLSL.h" -#include "GrGLSLCaps.h" +#include "GrShaderCaps.h" #include "SkString.h" +#include "../private/GrGLSL.h" bool GrGLSLSupportsNamedFragmentShaderOutputs(GrGLSLGeneration gen) { switch (gen) { @@ -18,6 +18,7 @@ bool GrGLSLSupportsNamedFragmentShaderOutputs(GrGLSLGeneration gen) { case k150_GrGLSLGeneration: case k330_GrGLSLGeneration: case k400_GrGLSLGeneration: + case k420_GrGLSLGeneration: case k310es_GrGLSLGeneration: case k320es_GrGLSLGeneration: return true; @@ -26,9 +27,9 @@ bool GrGLSLSupportsNamedFragmentShaderOutputs(GrGLSLGeneration gen) { } void GrGLSLAppendDefaultFloatPrecisionDeclaration(GrSLPrecision p, - const GrGLSLCaps& glslCaps, + const GrShaderCaps& shaderCaps, SkString* out) { - if (glslCaps.usesPrecisionModifiers()) { + if (shaderCaps.usesPrecisionModifiers()) { switch (p) { case kHigh_GrSLPrecision: out->append("precision highp float;\n"); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLBlend.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLBlend.cpp index d2c364035b0e..2f41c4e58863 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLBlend.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLBlend.cpp @@ -4,8 +4,10 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ + #include "GrGLSLBlend.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "SkXfermodePriv.h" ////////////////////////////////////////////////////////////////////////////// // Advanced (non-coeff) blend helpers @@ -122,8 +124,8 @@ static void soft_light_component_pos_dst_alpha(GrGLSLFragmentBuilder* fsBuilder, static void add_lum_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setLumFunction) { // Emit a helper that gets the luminance of a color. SkString getFunction; - GrGLSLShaderVar getLumArgs[] = { - GrGLSLShaderVar("color", kVec3f_GrSLType), + GrShaderVar getLumArgs[] = { + GrShaderVar("color", kVec3f_GrSLType), }; SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);"); fsBuilder->emitFunction(kFloat_GrSLType, @@ -133,10 +135,10 @@ static void add_lum_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setLumF &getFunction); // Emit the set luminance function. - GrGLSLShaderVar setLumArgs[] = { - GrGLSLShaderVar("hueSat", kVec3f_GrSLType), - GrGLSLShaderVar("alpha", kFloat_GrSLType), - GrGLSLShaderVar("lumColor", kVec3f_GrSLType), + GrShaderVar setLumArgs[] = { + GrShaderVar("hueSat", kVec3f_GrSLType), + GrShaderVar("alpha", kFloat_GrSLType), + GrShaderVar("lumColor", kVec3f_GrSLType), }; SkString setLumBody; setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str()); @@ -167,7 +169,7 @@ static void add_lum_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setLumF static void add_sat_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setSatFunction) { // Emit a helper that gets the saturation of a color SkString getFunction; - GrGLSLShaderVar getSatArgs[] = { GrGLSLShaderVar("color", kVec3f_GrSLType) }; + GrShaderVar getSatArgs[] = { GrShaderVar("color", kVec3f_GrSLType) }; SkString getSatBody; getSatBody.printf("return max(max(color.r, color.g), color.b) - " "min(min(color.r, color.g), color.b);"); @@ -182,11 +184,11 @@ static void add_sat_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setSatF // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the // adjusted min, mid, and max inputs, respectively. SkString helperFunction; - GrGLSLShaderVar helperArgs[] = { - GrGLSLShaderVar("minComp", kFloat_GrSLType), - GrGLSLShaderVar("midComp", kFloat_GrSLType), - GrGLSLShaderVar("maxComp", kFloat_GrSLType), - GrGLSLShaderVar("sat", kFloat_GrSLType), + GrShaderVar helperArgs[] = { + GrShaderVar("minComp", kFloat_GrSLType), + GrShaderVar("midComp", kFloat_GrSLType), + GrShaderVar("maxComp", kFloat_GrSLType), + GrShaderVar("sat", kFloat_GrSLType), }; static const char kHelperBody[] = "if (minComp < maxComp) {" "vec3 result;" @@ -203,9 +205,9 @@ static void add_sat_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setSatF kHelperBody, &helperFunction); - GrGLSLShaderVar setSatArgs[] = { - GrGLSLShaderVar("hueLumColor", kVec3f_GrSLType), - GrGLSLShaderVar("satColor", kVec3f_GrSLType), + GrShaderVar setSatArgs[] = { + GrShaderVar("hueLumColor", kVec3f_GrSLType), + GrShaderVar("satColor", kVec3f_GrSLType), }; const char* helpFunc = helperFunction.c_str(); SkString setSatBody; @@ -237,7 +239,7 @@ static void add_sat_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setSatF static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor, const char* dstColor, const char* outputColor, - SkXfermode::Mode mode) { + SkBlendMode mode) { SkASSERT(srcColor); SkASSERT(dstColor); SkASSERT(outputColor); @@ -246,38 +248,38 @@ static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const outputColor, srcColor, srcColor, dstColor); switch (mode) { - case SkXfermode::kOverlay_Mode: + case SkBlendMode::kOverlay: // Overlay is Hard-Light with the src and dst reversed hard_light(fsBuilder, outputColor, dstColor, srcColor); break; - case SkXfermode::kDarken_Mode: + case SkBlendMode::kDarken: fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, " "(1.0 - %s.a) * %s.rgb + %s.rgb);", outputColor, srcColor, dstColor, srcColor, dstColor, srcColor, dstColor); break; - case SkXfermode::kLighten_Mode: + case SkBlendMode::kLighten: fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, " "(1.0 - %s.a) * %s.rgb + %s.rgb);", outputColor, srcColor, dstColor, srcColor, dstColor, srcColor, dstColor); break; - case SkXfermode::kColorDodge_Mode: + case SkBlendMode::kColorDodge: color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'r'); color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'g'); color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'b'); break; - case SkXfermode::kColorBurn_Mode: + case SkBlendMode::kColorBurn: color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'r'); color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'g'); color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'b'); break; - case SkXfermode::kHardLight_Mode: + case SkBlendMode::kHardLight: hard_light(fsBuilder, outputColor, srcColor, dstColor); break; - case SkXfermode::kSoftLight_Mode: + case SkBlendMode::kSoftLight: fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor); fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, srcColor); fsBuilder->codeAppendf("} else {"); @@ -286,25 +288,25 @@ static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'b'); fsBuilder->codeAppendf("}"); break; - case SkXfermode::kDifference_Mode: + case SkBlendMode::kDifference: fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -" "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);", outputColor, srcColor, dstColor, srcColor, dstColor, dstColor, srcColor); break; - case SkXfermode::kExclusion_Mode: + case SkBlendMode::kExclusion: fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - " "2.0 * %s.rgb * %s.rgb;", outputColor, dstColor, srcColor, dstColor, srcColor); break; - case SkXfermode::kMultiply_Mode: + case SkBlendMode::kMultiply: fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + " "(1.0 - %s.a) * %s.rgb + " "%s.rgb * %s.rgb;", outputColor, srcColor, dstColor, dstColor, srcColor, srcColor, dstColor); break; - case SkXfermode::kHue_Mode: { + case SkBlendMode::kHue: { // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S SkString setSat, setLum; add_sat_function(fsBuilder, &setSat); @@ -319,7 +321,7 @@ static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const outputColor, srcColor, dstColor, dstColor, srcColor); break; } - case SkXfermode::kSaturation_Mode: { + case SkBlendMode::kSaturation: { // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S SkString setSat, setLum; add_sat_function(fsBuilder, &setSat); @@ -334,7 +336,7 @@ static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const outputColor, srcColor, dstColor, dstColor, srcColor); break; } - case SkXfermode::kColor_Mode: { + case SkBlendMode::kColor: { // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S SkString setLum; add_lum_function(fsBuilder, &setLum); @@ -346,7 +348,7 @@ static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const outputColor, srcColor, dstColor, dstColor, srcColor); break; } - case SkXfermode::kLuminosity_Mode: { + case SkBlendMode::kLuminosity: { // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S SkString setLum; add_lum_function(fsBuilder, &setLum); @@ -416,11 +418,17 @@ static bool append_porterduff_term(GrGLSLFragmentBuilder* fsBuilder, SkXfermode: void GrGLSLBlend::AppendMode(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor, const char* dstColor, const char* outColor, - SkXfermode::Mode mode) { + SkBlendMode mode) { SkXfermode::Coeff srcCoeff, dstCoeff; if (SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff)) { + // The only coeff mode that can go out of range is plus. + bool clamp = mode == SkBlendMode::kPlus; + fsBuilder->codeAppendf("%s = ", outColor); + if (clamp) { + fsBuilder->codeAppend("clamp("); + } // append src blend bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor, false); @@ -428,6 +436,9 @@ void GrGLSLBlend::AppendMode(GrGLSLFragmentBuilder* fsBuilder, const char* srcCo if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) { fsBuilder->codeAppend("vec4(0, 0, 0, 0)"); } + if (clamp) { + fsBuilder->codeAppend(", 0, 1);"); + } fsBuilder->codeAppend(";"); } else { emit_advanced_xfermode_code(fsBuilder, srcColor, dstColor, outColor, mode); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLBlend.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLBlend.h index c8047f8af5f9..fb0fb0b9353e 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLBlend.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLBlend.h @@ -8,8 +8,8 @@ #ifndef GrGLBlend_DEFINED #define GrGLBlend_DEFINED +#include "SkBlendMode.h" #include "SkRegion.h" -#include "SkXfermode.h" class GrGLSLFragmentBuilder; @@ -19,7 +19,7 @@ namespace GrGLSLBlend { * variables to the outColor variable. */ void AppendMode(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor, - const char* dstColor, const char* outColor, SkXfermode::Mode mode); + const char* dstColor, const char* outColor, SkBlendMode mode); void AppendRegionOp(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor, const char* dstColor, const char* outColor, SkRegion::Op regionOp); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLColorSpaceXformHelper.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLColorSpaceXformHelper.h index 5e112f9f9173..1571b0623172 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLColorSpaceXformHelper.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLColorSpaceXformHelper.h @@ -12,29 +12,33 @@ #include "GrGLSLUniformHandler.h" /** - * Stack helper class to assist with using GrColorSpaceXform within an FP's emitCode function. - * This injects the uniform declaration, and stores the information needed to generate correct - * gamut-transformation shader code. + * Helper class to assist with using GrColorSpaceXform within an FP. This manages all of the + * uniforms needed, and can be passed to shader builder functions to automatically generate the + * correct color space transformation code. */ class GrGLSLColorSpaceXformHelper : public SkNoncopyable { public: - GrGLSLColorSpaceXformHelper(GrGLSLUniformHandler* uniformHandler, - GrColorSpaceXform* colorSpaceXform, - GrGLSLProgramDataManager::UniformHandle* handle) { - SkASSERT(uniformHandler && handle); + GrGLSLColorSpaceXformHelper() : fValid(false) {} + + void emitCode(GrGLSLUniformHandler* uniformHandler, GrColorSpaceXform* colorSpaceXform) { + SkASSERT(uniformHandler); if (colorSpaceXform) { - *handle = uniformHandler->addUniform(kFragment_GrShaderFlag, kMat44f_GrSLType, - kDefault_GrSLPrecision, "ColorXform", - &fXformMatrix); - } else { - fXformMatrix = nullptr; + fGamutXformVar = uniformHandler->addUniform(kFragment_GrShaderFlag, kMat44f_GrSLType, + kDefault_GrSLPrecision, "ColorXform"); + fValid = true; } } - const char* getXformMatrix() const { return fXformMatrix; } + void setData(const GrGLSLProgramDataManager& pdman, GrColorSpaceXform* colorSpaceXform) { + pdman.setSkMatrix44(fGamutXformVar, colorSpaceXform->srcToDst()); + } + + bool isValid() const { return fValid; } + GrGLSLProgramDataManager::UniformHandle const gamutXformUniform() { return fGamutXformVar; } private: - const char* fXformMatrix; + GrGLSLProgramDataManager::UniformHandle fGamutXformVar; + bool fValid; }; #endif diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp index 5ae7fee7db09..a779accab2ac 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp @@ -49,15 +49,17 @@ void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inpu TransformedCoordVars coordVars = args.fTransformedCoords.childInputs(childIndex); TextureSamplers textureSamplers = args.fTexSamplers.childInputs(childIndex); BufferSamplers bufferSamplers = args.fBufferSamplers.childInputs(childIndex); + ImageStorages imageStorages = args.fImageStorages.childInputs(childIndex); EmitArgs childArgs(fragBuilder, args.fUniformHandler, - args.fGLSLCaps, + args.fShaderCaps, childProc, outputColor, inputColor, coordVars, textureSamplers, bufferSamplers, + imageStorages, args.fGpImplementsDistanceVector); this->childProcessor(childIndex)->emitCode(childArgs); fragBuilder->codeAppend("}\n"); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.h index d2f00f8b336c..1cf0d1d000c4 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.h @@ -11,14 +11,12 @@ #include "GrFragmentProcessor.h" #include "GrShaderVar.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLSampler.h" +#include "glsl/GrGLSLUniformHandler.h" class GrProcessor; class GrProcessorKeyBuilder; -class GrGLSLCaps; class GrGLSLFPBuilder; class GrGLSLFPFragmentBuilder; -class GrGLSLUniformHandler; class GrGLSLFragmentProcessor { public: @@ -30,8 +28,9 @@ public: } } - typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; - typedef GrGLSLProgramDataManager::UniformHandle SamplerHandle; + using UniformHandle = GrGLSLUniformHandler::UniformHandle; + using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; + using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle; private: /** @@ -71,10 +70,12 @@ private: public: using TransformedCoordVars = BuilderInputProvider; - using TextureSamplers = BuilderInputProvider; - using BufferSamplers = BuilderInputProvider; + using TextureSamplers = BuilderInputProvider; + using BufferSamplers = BuilderInputProvider; + using ImageStorages = BuilderInputProvider; /** Called when the program stage should insert its code into the shaders. The code in each shader will be in its own block ({}) and so locally scoped names will not collide across @@ -94,43 +95,52 @@ public: info about its output. @param transformedCoords Fragment shader variables containing the coords computed using each of the GrFragmentProcessor's GrCoordTransforms. - @param texSamplers Contains one entry for each GrTextureAccess of the GrProcessor. + @param texSamplers Contains one entry for each TextureSampler of the GrProcessor. These can be passed to the builder to emit texture reads in the generated code. - @param bufferSamplers Contains one entry for each GrBufferAccess of the GrProcessor. - These can be passed to the builder to emit buffer reads in the - generated code. + @param bufferSamplers Contains one entry for each BufferAccess of the GrProcessor. These + can be passed to the builder to emit buffer reads in the generated + code. + @param imageStorages Contains one entry for each ImageStorageAccess of the GrProcessor. + These can be passed to the builder to emit image loads and stores + in the generated code. + @param gpImplementsDistanceVector + Does the GrGeometryProcessor implement the feature where it + provides a vector to the nearest edge of the shape being rendered. */ struct EmitArgs { EmitArgs(GrGLSLFPFragmentBuilder* fragBuilder, GrGLSLUniformHandler* uniformHandler, - const GrGLSLCaps* caps, + const GrShaderCaps* caps, const GrFragmentProcessor& fp, const char* outputColor, const char* inputColor, const TransformedCoordVars& transformedCoordVars, const TextureSamplers& textureSamplers, const BufferSamplers& bufferSamplers, + const ImageStorages& imageStorages, bool gpImplementsDistanceVector) : fFragBuilder(fragBuilder) , fUniformHandler(uniformHandler) - , fGLSLCaps(caps) + , fShaderCaps(caps) , fFp(fp) , fOutputColor(outputColor) , fInputColor(inputColor) , fTransformedCoords(transformedCoordVars) , fTexSamplers(textureSamplers) , fBufferSamplers(bufferSamplers) + , fImageStorages(imageStorages) , fGpImplementsDistanceVector(gpImplementsDistanceVector) {} GrGLSLFPFragmentBuilder* fFragBuilder; GrGLSLUniformHandler* fUniformHandler; - const GrGLSLCaps* fGLSLCaps; + const GrShaderCaps* fShaderCaps; const GrFragmentProcessor& fFp; const char* fOutputColor; const char* fInputColor; const TransformedCoordVars& fTransformedCoords; const TextureSamplers& fTexSamplers; const BufferSamplers& fBufferSamplers; + const ImageStorages& fImageStorages; bool fGpImplementsDistanceVector; }; @@ -138,7 +148,7 @@ public: void setData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor); - static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) {} + static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {} int numChildProcessors() const { return fChildProcessors.count(); } @@ -184,8 +194,7 @@ protected: uniform variables required by the shaders created in emitCode(). The GrFragmentProcessor parameter is guaranteed to be of the same type that created this GrGLSLFragmentProcessor and to have an identical processor key as the one that created this GrGLSLFragmentProcessor. */ - // TODO update this to pass in GrFragmentProcessor - virtual void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) {} + virtual void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) {} private: void internalEmitChild(int, const char*, const char*, EmitArgs&); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp index d35730f63301..484bd7821157 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp @@ -8,12 +8,12 @@ #include "GrGLSLFragmentShaderBuilder.h" #include "GrRenderTarget.h" #include "GrRenderTargetPriv.h" +#include "GrShaderCaps.h" #include "gl/GrGLGpu.h" -#include "glsl/GrGLSL.h" -#include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" +#include "../private/GrGLSL.h" const char* GrGLSLFragmentShaderBuilder::kDstColorName = "_dstColor"; @@ -85,7 +85,8 @@ GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* p , fCustomColorOutputIndex(-1) , fHasSecondaryOutput(false) , fUsedSampleOffsetArrays(0) - , fHasInitializedSampleMask(false) { + , fHasInitializedSampleMask(false) + , fDefaultPrecision(kMedium_GrSLPrecision) { fSubstageIndices.push_back(0); #ifdef SK_DEBUG fUsedProcessorFeatures = GrProcessor::kNone_RequiredFeatures; @@ -94,28 +95,13 @@ GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* p } bool GrGLSLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { - const GrGLSLCaps& glslCaps = *fProgramBuilder->glslCaps(); + const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps(); switch (feature) { - case kStandardDerivatives_GLSLFeature: - if (!glslCaps.shaderDerivativeSupport()) { - return false; - } - if (const char* extension = glslCaps.shaderDerivativeExtensionString()) { - this->addFeature(1 << kStandardDerivatives_GLSLFeature, extension); - } - return true; - case kPixelLocalStorage_GLSLFeature: - if (glslCaps.pixelLocalStorageSize() <= 0) { - return false; - } - this->addFeature(1 << kPixelLocalStorage_GLSLFeature, - "GL_EXT_shader_pixel_local_storage"); - return true; case kMultisampleInterpolation_GLSLFeature: - if (!glslCaps.multisampleInterpolationSupport()) { + if (!shaderCaps.multisampleInterpolationSupport()) { return false; } - if (const char* extension = glslCaps.multisampleInterpolationExtensionString()) { + if (const char* extension = shaderCaps.multisampleInterpolationExtensionString()) { this->addFeature(1 << kMultisampleInterpolation_GLSLFeature, extension); } return true; @@ -138,54 +124,6 @@ SkString GrGLSLFragmentShaderBuilder::ensureCoords2D(const GrShaderVar& coords) return coords2D; } -const char* GrGLSLFragmentShaderBuilder::fragmentPosition() { - SkDEBUGCODE(fUsedProcessorFeatures |= GrProcessor::kFragmentPosition_RequiredFeature;) - - const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps(); - // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers - // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the - // declaration varies in earlier GLSL specs. So it is simpler to omit it. - if (kTopLeft_GrSurfaceOrigin == this->getSurfaceOrigin()) { - fSetupFragPosition = true; - return "gl_FragCoord"; - } else if (const char* extension = glslCaps->fragCoordConventionsExtensionString()) { - if (!fSetupFragPosition) { - if (glslCaps->generation() < k150_GrGLSLGeneration) { - this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, - extension); - } - fInputs.push_back().set(kVec4f_GrSLType, - GrGLSLShaderVar::kIn_TypeModifier, - "gl_FragCoord", - kDefault_GrSLPrecision, - "origin_upper_left"); - fSetupFragPosition = true; - } - return "gl_FragCoord"; - } else { - static const char* kTempName = "tmpXYFragCoord"; - static const char* kCoordName = "fragCoordYDown"; - if (!fSetupFragPosition) { - const char* rtHeightName; - - fProgramBuilder->addRTHeightUniform("RTHeight", &rtHeightName); - - // The Adreno compiler seems to be very touchy about access to "gl_FragCoord". - // Accessing glFragCoord.zw can cause a program to fail to link. Additionally, - // depending on the surrounding code, accessing .xy with a uniform involved can - // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand - // (and only accessing .xy) seems to "fix" things. - const char* precision = glslCaps->usesPrecisionModifiers() ? "highp " : ""; - this->codePrependf("\t%svec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n", - precision, kCoordName, kTempName, rtHeightName, kTempName); - this->codePrependf("%svec2 %s = gl_FragCoord.xy;", precision, kTempName); - fSetupFragPosition = true; - } - SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); - return kCoordName; - } -} - const char* GrGLSLFragmentShaderBuilder::distanceVectorName() const { return "fsDistanceVector"; } @@ -202,12 +140,12 @@ void GrGLSLFragmentShaderBuilder::appendOffsetToSample(const char* sampleIdx, Co } void GrGLSLFragmentShaderBuilder::maskSampleCoverage(const char* mask, bool invert) { - const GrGLSLCaps& glslCaps = *fProgramBuilder->glslCaps(); - if (!glslCaps.sampleVariablesSupport()) { + const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps(); + if (!shaderCaps.sampleVariablesSupport()) { SkDEBUGFAIL("Attempted to mask sample coverage without support."); return; } - if (const char* extension = glslCaps.sampleVariablesExtensionString()) { + if (const char* extension = shaderCaps.sampleVariablesExtensionString()) { this->addFeature(1 << kSampleVariables_GLSLPrivateFeature, extension); } if (!fHasInitializedSampleMask) { @@ -222,26 +160,29 @@ void GrGLSLFragmentShaderBuilder::maskSampleCoverage(const char* mask, bool inve } void GrGLSLFragmentShaderBuilder::overrideSampleCoverage(const char* mask) { - const GrGLSLCaps& glslCaps = *fProgramBuilder->glslCaps(); - if (!glslCaps.sampleMaskOverrideCoverageSupport()) { + const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps(); + if (!shaderCaps.sampleMaskOverrideCoverageSupport()) { SkDEBUGFAIL("Attempted to override sample coverage without support."); return; } - SkASSERT(glslCaps.sampleVariablesSupport()); - if (const char* extension = glslCaps.sampleVariablesExtensionString()) { + SkASSERT(shaderCaps.sampleVariablesSupport()); + if (const char* extension = shaderCaps.sampleVariablesExtensionString()) { this->addFeature(1 << kSampleVariables_GLSLPrivateFeature, extension); } if (this->addFeature(1 << kSampleMaskOverrideCoverage_GLSLPrivateFeature, "GL_NV_sample_mask_override_coverage")) { // Redeclare gl_SampleMask with layout(override_coverage) if we haven't already. - fOutputs.push_back().set(kInt_GrSLType, GrShaderVar::kOut_TypeModifier, - "gl_SampleMask", 1, kHigh_GrSLPrecision, - "override_coverage"); + fOutputs.push_back().set(kInt_GrSLType, "gl_SampleMask", 1, GrShaderVar::kOut_TypeModifier, + kHigh_GrSLPrecision, "override_coverage"); } this->codeAppendf("gl_SampleMask[0] = %s;", mask); fHasInitializedSampleMask = true; } +void GrGLSLFragmentShaderBuilder::elevateDefaultPrecision(GrSLPrecision precision) { + fDefaultPrecision = SkTMax(fDefaultPrecision, precision); +} + const char* GrGLSLFragmentShaderBuilder::dstColor() { SkDEBUGCODE(fHasReadDstColor = true;) @@ -250,14 +191,14 @@ const char* GrGLSLFragmentShaderBuilder::dstColor() { return override; } - const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps(); - if (glslCaps->fbFetchSupport()) { + const GrShaderCaps* shaderCaps = fProgramBuilder->shaderCaps(); + if (shaderCaps->fbFetchSupport()) { this->addFeature(1 << kFramebufferFetch_GLSLPrivateFeature, - glslCaps->fbFetchExtensionString()); + shaderCaps->fbFetchExtensionString()); // Some versions of this extension string require declaring custom color output on ES 3.0+ - const char* fbFetchColorName = glslCaps->fbFetchColorName(); - if (glslCaps->fbFetchNeedsCustomOutput()) { + const char* fbFetchColorName = shaderCaps->fbFetchColorName(); + if (shaderCaps->fbFetchNeedsCustomOutput()) { this->enableCustomOutput(); fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOut_TypeModifier); fbFetchColorName = DeclaredColorOutputName(); @@ -273,7 +214,7 @@ const char* GrGLSLFragmentShaderBuilder::dstColor() { void GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) { SkASSERT(GrBlendEquationIsAdvanced(equation)); - const GrGLSLCaps& caps = *fProgramBuilder->glslCaps(); + const GrShaderCaps& caps = *fProgramBuilder->shaderCaps(); if (!caps.mustEnableAdvBlendEqs()) { return; } @@ -291,17 +232,16 @@ void GrGLSLFragmentShaderBuilder::enableCustomOutput() { if (!fHasCustomColorOutput) { fHasCustomColorOutput = true; fCustomColorOutputIndex = fOutputs.count(); - fOutputs.push_back().set(kVec4f_GrSLType, - GrGLSLShaderVar::kOut_TypeModifier, - DeclaredColorOutputName()); - fProgramBuilder->finalizeFragmentOutputColor(fOutputs.back()); + fOutputs.push_back().set(kVec4f_GrSLType, DeclaredColorOutputName(), + GrShaderVar::kOut_TypeModifier); + fProgramBuilder->finalizeFragmentOutputColor(fOutputs.back()); } } void GrGLSLFragmentShaderBuilder::enableSecondaryOutput() { SkASSERT(!fHasSecondaryOutput); fHasSecondaryOutput = true; - const GrGLSLCaps& caps = *fProgramBuilder->glslCaps(); + const GrShaderCaps& caps = *fProgramBuilder->shaderCaps(); if (const char* extension = caps.secondaryOutputExtensionString()) { this->addFeature(1 << kBlendFuncExtended_GLSLPrivateFeature, extension); } @@ -311,14 +251,14 @@ void GrGLSLFragmentShaderBuilder::enableSecondaryOutput() { // output. The condition also co-incides with the condition in whici GLES SL 2.0 // requires the built-in gl_SecondaryFragColorEXT, where as 3.0 requires a custom output. if (caps.mustDeclareFragmentShaderOutput()) { - fOutputs.push_back().set(kVec4f_GrSLType, GrGLSLShaderVar::kOut_TypeModifier, - DeclaredSecondaryColorOutputName()); + fOutputs.push_back().set(kVec4f_GrSLType, DeclaredSecondaryColorOutputName(), + GrShaderVar::kOut_TypeModifier); fProgramBuilder->finalizeFragmentSecondaryColor(fOutputs.back()); } } const char* GrGLSLFragmentShaderBuilder::getPrimaryColorOutputName() const { - return fHasCustomColorOutput ? DeclaredColorOutputName() : "gl_FragColor"; + return fHasCustomColorOutput ? DeclaredColorOutputName() : "sk_FragColor"; } void GrGLSLFragmentBuilder::declAppendf(const char* fmt, ...) { @@ -329,7 +269,7 @@ void GrGLSLFragmentBuilder::declAppendf(const char* fmt, ...) { } const char* GrGLSLFragmentShaderBuilder::getSecondaryColorOutputName() const { - const GrGLSLCaps& caps = *fProgramBuilder->glslCaps(); + const GrShaderCaps& caps = *fProgramBuilder->shaderCaps(); return caps.mustDeclareFragmentShaderOutput() ? DeclaredSecondaryColorOutputName() : "gl_SecondaryFragColorEXT"; } @@ -344,8 +284,8 @@ GrSurfaceOrigin GrGLSLFragmentShaderBuilder::getSurfaceOrigin() const { void GrGLSLFragmentShaderBuilder::onFinalize() { fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs()); - GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, - *fProgramBuilder->glslCaps(), + GrGLSLAppendDefaultFloatPrecisionDeclaration(fDefaultPrecision, + *fProgramBuilder->shaderCaps(), &this->precisionQualifier()); if (fUsedSampleOffsetArrays & (1 << kSkiaDevice_Coordinates)) { this->defineSampleOffsetArray(sample_offset_array_name(kSkiaDevice_Coordinates), @@ -365,15 +305,11 @@ void GrGLSLFragmentShaderBuilder::defineSampleOffsetArray(const char* name, cons SkASSERT(fProgramBuilder->caps()->sampleLocationsSupport()); const GrPipeline& pipeline = fProgramBuilder->pipeline(); const GrRenderTargetPriv& rtp = pipeline.getRenderTarget()->renderTargetPriv(); - const GrGpu::MultisampleSpecs& specs = rtp.getMultisampleSpecs(pipeline.getStencil()); + const GrGpu::MultisampleSpecs& specs = rtp.getMultisampleSpecs(pipeline); SkSTArray<16, SkPoint, true> offsets; offsets.push_back_n(specs.fEffectiveSampleCnt); m.mapPoints(offsets.begin(), specs.fSampleLocations, specs.fEffectiveSampleCnt); - this->definitions().append("const "); - if (fProgramBuilder->glslCaps()->usesPrecisionModifiers()) { - this->definitions().append("highp "); - } - this->definitions().appendf("vec2 %s[] = vec2[](", name); + this->definitions().appendf("const highp vec2 %s[] = vec2[](", name); for (int i = 0; i < specs.fEffectiveSampleCnt; ++i) { this->definitions().appendf("vec2(%f, %f)", offsets[i].x(), offsets[i].y()); this->definitions().append(i + 1 != specs.fEffectiveSampleCnt ? ", " : ");\n"); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h index ecb6d455ddef..65bcb8dae6f5 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h @@ -8,8 +8,8 @@ #ifndef GrGLSLFragmentShaderBuilder_DEFINED #define GrGLSLFragmentShaderBuilder_DEFINED +#include "GrBlend.h" #include "GrGLSLShaderBuilder.h" - #include "GrProcessor.h" class GrRenderTarget; @@ -29,8 +29,6 @@ public: * if code is added that uses one of these features without calling enableFeature() */ enum GLSLFeature { - kStandardDerivatives_GLSLFeature = kLastGLSLPrivateFeature + 1, - kPixelLocalStorage_GLSLFeature, kMultisampleInterpolation_GLSLFeature }; @@ -48,11 +46,6 @@ public: */ virtual SkString ensureCoords2D(const GrShaderVar&) = 0; - - /** Returns a variable name that represents the position of the fragment in the FS. The position - is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */ - virtual const char* fragmentPosition() = 0; - // TODO: remove this method. void declAppendf(const char* fmt, ...); @@ -100,6 +93,13 @@ public: space coordinates. */ virtual const char* distanceVectorName() const = 0; + /** + * Overrides the default precision for the entire fragment program. Processors that require + * high precision input (eg from incoming texture samples) may use this. For calculations that + * are limited to a single processor's code, it is better to annotate individual declarations. + */ + virtual void elevateDefaultPrecision(GrSLPrecision) = 0; + /** * Fragment procs with child procs should call these functions before/after calling emitCode * on a child proc. @@ -168,13 +168,13 @@ public: // Shared GrGLSLFragmentBuilder interface. bool enableFeature(GLSLFeature) override; virtual SkString ensureCoords2D(const GrShaderVar&) override; - const char* fragmentPosition() override; const char* distanceVectorName() const override; // GrGLSLFPFragmentBuilder interface. void appendOffsetToSample(const char* sampleIdx, Coordinates) override; void maskSampleCoverage(const char* mask, bool invert = false) override; void overrideSampleCoverage(const char* mask) override; + void elevateDefaultPrecision(GrSLPrecision) override; const SkString& getMangleString() const override { return fMangleString; } void onBeforeChildProcEmitCode() override; void onAfterChildProcEmitCode() override; @@ -203,7 +203,7 @@ private: } #endif - static const char* DeclaredColorOutputName() { return "fsColorOut"; } + static const char* DeclaredColorOutputName() { return "sk_FragColor"; } static const char* DeclaredSecondaryColorOutputName() { return "fsSecondaryColorOut"; } GrSurfaceOrigin getSurfaceOrigin() const; @@ -233,13 +233,14 @@ private: */ SkString fMangleString; - bool fSetupFragPosition; - bool fHasCustomColorOutput; - int fCustomColorOutputIndex; - bool fHasSecondaryOutput; - uint8_t fUsedSampleOffsetArrays; - bool fHasInitializedSampleMask; - SkString fDistanceVectorOutput; + bool fSetupFragPosition; + bool fHasCustomColorOutput; + int fCustomColorOutputIndex; + bool fHasSecondaryOutput; + uint8_t fUsedSampleOffsetArrays; + bool fHasInitializedSampleMask; + SkString fDistanceVectorOutput; + GrSLPrecision fDefaultPrecision; #ifdef SK_DEBUG // some state to verify shaders and effects are consistent, this is reset between effects by diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp index 0d5ed93ed30e..9dd1cba418ab 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp @@ -17,7 +17,7 @@ void GrGLSLGeometryProcessor::emitCode(EmitArgs& args) { GrGLSLVertexBuilder* vBuilder = args.fVertBuilder; GrGPArgs gpArgs; this->onEmitCode(args, &gpArgs); - vBuilder->transformToNormalizedDeviceSpace(gpArgs.fPositionVar); + vBuilder->transformToNormalizedDeviceSpace(gpArgs.fPositionVar, args.fRTAdjustName); if (kVec2f_GrSLType == gpArgs.fPositionVar.getType()) { args.fVaryingHandler->setNoPerspective(); } @@ -41,7 +41,8 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb, varyingType = SkToBool(SkMatrix::kPerspective_Mask & type) ? kVec3f_GrSLType : kVec2f_GrSLType; - GrSLPrecision precision = coordTransform->precision(); + // Coord transforms are always handled at high precision + const GrSLPrecision precision = kHigh_GrSLPrecision; const char* uniName; @@ -108,7 +109,7 @@ void GrGLSLGeometryProcessor::setupPosition(GrGLSLVertexBuilder* vertBuilder, &viewMatrixName); if (!mat.hasPerspective()) { gpArgs->fPositionVar.set(kVec2f_GrSLType, "pos2"); - vertBuilder->codeAppendf("vec2 %s = vec2(%s * vec3(%s, 1));", + vertBuilder->codeAppendf("vec2 %s = (%s * vec3(%s, 1)).xy;", gpArgs->fPositionVar.c_str(), viewMatrixName, posName); } else { gpArgs->fPositionVar.set(kVec3f_GrSLType, "pos3"); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp index eddd69f7cdc4..01f223f4b3d1 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp @@ -9,11 +9,65 @@ #include "GrGLSLProgramBuilder.h" #include "GrGLSLVarying.h" -GrGLSLGeometryBuilder::GrGLSLGeometryBuilder(GrGLSLProgramBuilder* program) - : INHERITED(program) { +static const char* input_type_name(GrGLSLGeometryBuilder::InputType in) { + using InputType = GrGLSLGeometryBuilder::InputType; + switch (in) { + case InputType::kPoints: return "points"; + case InputType::kLines: return "lines"; + case InputType::kLinesAdjacency: return "lines_adjacency"; + case InputType::kTriangles: return "triangles"; + case InputType::kTrianglesAdjacency: return "triangles_adjacency"; + } + SkFAIL("invalid input type"); + return "unknown_input"; +} +static const char* output_type_name(GrGLSLGeometryBuilder::OutputType out) { + using OutputType = GrGLSLGeometryBuilder::OutputType; + switch (out) { + case OutputType::kPoints: return "points"; + case OutputType::kLineStrip: return "line_strip"; + case OutputType::kTriangleStrip: return "triangle_strip"; + } + SkFAIL("invalid output type"); + return "unknown_output"; +} + +GrGLSLGeometryBuilder::GrGLSLGeometryBuilder(GrGLSLProgramBuilder* program) + : INHERITED(program) + , fNumInvocations(0) { +} + +void GrGLSLGeometryBuilder::configure(InputType inputType, OutputType outputType, int maxVertices, + int numInvocations) { + SkASSERT(!this->isConfigured()); + fNumInvocations = numInvocations; + if (this->getProgramBuilder()->shaderCaps()->mustImplementGSInvocationsWithLoop()) { + maxVertices *= numInvocations; + numInvocations = 1; + } + this->addLayoutQualifier(input_type_name(inputType), kIn_InterfaceQualifier); + this->addLayoutQualifier(SkStringPrintf("invocations = %i", numInvocations).c_str(), + kIn_InterfaceQualifier); + this->addLayoutQualifier(output_type_name(outputType), kOut_InterfaceQualifier); + this->addLayoutQualifier(SkStringPrintf("max_vertices = %i", maxVertices).c_str(), + kOut_InterfaceQualifier); } void GrGLSLGeometryBuilder::onFinalize() { + SkASSERT(this->isConfigured()); fProgramBuilder->varyingHandler()->getGeomDecls(&this->inputs(), &this->outputs()); + GrShaderVar sk_InvocationID("sk_InvocationID", kInt_GrSLType); + this->declareGlobal(sk_InvocationID); + SkASSERT(sk_InvocationID.getName() == SkString("sk_InvocationID")); + if (this->getProgramBuilder()->shaderCaps()->mustImplementGSInvocationsWithLoop()) { + SkString invokeFn; + this->emitFunction(kVoid_GrSLType, "invoke", 0, nullptr, this->code().c_str(), &invokeFn); + this->code().printf("for (sk_InvocationID = 0; sk_InvocationID < %i; ++sk_InvocationID) {" + "%s();" + "EndPrimitive();" + "}", fNumInvocations, invokeFn.c_str()); + } else { + this->codePrependf("sk_InvocationID = gl_InvocationID;"); + } } diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.h index f5e09f11a2ef..04be53030e06 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.h @@ -16,9 +16,28 @@ class GrGLSLGeometryBuilder : public GrGLSLShaderBuilder { public: GrGLSLGeometryBuilder(GrGLSLProgramBuilder* program); + enum class InputType { + kPoints, + kLines, + kLinesAdjacency, + kTriangles, + kTrianglesAdjacency + }; + + enum class OutputType { + kPoints, + kLineStrip, + kTriangleStrip + }; + + void configure(InputType, OutputType, int maxVertices, int numInvocations = 1); + bool isConfigured() const { return fNumInvocations; } + private: void onFinalize() override; + int fNumInvocations; + friend class GrGLProgramBuilder; typedef GrGLSLShaderBuilder INHERITED; diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLPLSPathRendering.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLPLSPathRendering.h deleted file mode 100644 index 60889e98d21c..000000000000 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLPLSPathRendering.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#define GR_GL_PLS_DSTCOLOR_NAME "pls.dstColor" -#define GR_GL_PLS_PATH_DATA_DECL "__pixel_localEXT PLSData {\n"\ - " layout(rgba8i) ivec4 windings;\n"\ - " layout(rgba8) vec4 dstColor;\n"\ - "} pls;\n" diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp index 24f21ffe7a77..f39fff2a0743 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp @@ -16,6 +16,11 @@ SkMatrix GrGLSLPrimitiveProcessor::GetTransformMatrix(const SkMatrix& localMatri const GrCoordTransform& coordTransform) { SkMatrix combined; combined.setConcat(coordTransform.getMatrix(), localMatrix); + if (coordTransform.normalize()) { + SkASSERT(coordTransform.texture()); + combined.postIDiv(coordTransform.texture()->width(), coordTransform.texture()->height()); + } + if (coordTransform.reverseY()) { // combined.postScale(1,-1); // combined.postTranslate(0,1); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.h index d270fa18fe37..5fbf9bd42f65 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.h @@ -11,16 +11,15 @@ #include "GrFragmentProcessor.h" #include "GrPrimitiveProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLSampler.h" +#include "glsl/GrGLSLUniformHandler.h" -class GrBatchTracker; class GrPrimitiveProcessor; -class GrGLSLCaps; class GrGLSLPPFragmentBuilder; +class GrGLSLGeometryBuilder; class GrGLSLGPBuilder; -class GrGLSLUniformHandler; class GrGLSLVaryingHandler; class GrGLSLVertexBuilder; +class GrShaderCaps; class GrGLSLPrimitiveProcessor { public: @@ -28,8 +27,9 @@ public: virtual ~GrGLSLPrimitiveProcessor() {} - typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; - typedef GrGLSLProgramDataManager::UniformHandle SamplerHandle; + using UniformHandle = GrGLSLProgramDataManager::UniformHandle; + using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; + using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle; /** * This class provides access to the GrCoordTransforms across all GrFragmentProcessors in a @@ -66,40 +66,49 @@ public: struct EmitArgs { EmitArgs(GrGLSLVertexBuilder* vertBuilder, + GrGLSLGeometryBuilder* geomBuilder, GrGLSLPPFragmentBuilder* fragBuilder, GrGLSLVaryingHandler* varyingHandler, GrGLSLUniformHandler* uniformHandler, - const GrGLSLCaps* caps, + const GrShaderCaps* caps, const GrPrimitiveProcessor& gp, const char* outputColor, const char* outputCoverage, const char* distanceVectorName, + const char* rtAdjustName, const SamplerHandle* texSamplers, const SamplerHandle* bufferSamplers, + const ImageStorageHandle* imageStorages, FPCoordTransformHandler* transformHandler) : fVertBuilder(vertBuilder) + , fGeomBuilder(geomBuilder) , fFragBuilder(fragBuilder) , fVaryingHandler(varyingHandler) , fUniformHandler(uniformHandler) - , fGLSLCaps(caps) + , fShaderCaps(caps) , fGP(gp) , fOutputColor(outputColor) , fOutputCoverage(outputCoverage) , fDistanceVectorName(distanceVectorName) + , fRTAdjustName(rtAdjustName) , fTexSamplers(texSamplers) , fBufferSamplers(bufferSamplers) + , fImageStorages(imageStorages) , fFPCoordTransformHandler(transformHandler) {} GrGLSLVertexBuilder* fVertBuilder; + GrGLSLGeometryBuilder* fGeomBuilder; GrGLSLPPFragmentBuilder* fFragBuilder; GrGLSLVaryingHandler* fVaryingHandler; GrGLSLUniformHandler* fUniformHandler; - const GrGLSLCaps* fGLSLCaps; + const GrShaderCaps* fShaderCaps; const GrPrimitiveProcessor& fGP; const char* fOutputColor; const char* fOutputCoverage; const char* fDistanceVectorName; + const char* fRTAdjustName; const SamplerHandle* fTexSamplers; const SamplerHandle* fBufferSamplers; + const ImageStorageHandle* fImageStorages; FPCoordTransformHandler* fFPCoordTransformHandler; }; diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp index abfeafda0c79..12e7ca2c1da0 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp @@ -7,7 +7,10 @@ #include "glsl/GrGLSLProgramBuilder.h" +#include "GrCaps.h" #include "GrPipeline.h" +#include "GrShaderCaps.h" +#include "GrTexturePriv.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLVarying.h" @@ -17,7 +20,7 @@ const int GrGLSLProgramBuilder::kVarsPerBlock = 8; GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, - const GrProgramDesc& desc) + GrProgramDesc* desc) : fVS(this) , fGS(this) , fFS(this) @@ -29,7 +32,10 @@ GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrPipeline& pipeline, , fXferProcessor(nullptr) , fNumVertexSamplers(0) , fNumGeometrySamplers(0) - , fNumFragmentSamplers(0) { + , fNumFragmentSamplers(0) + , fNumVertexImageStorages(0) + , fNumGeometryImageStorages(0) + , fNumFragmentImageStorages(0) { } void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders, @@ -39,7 +45,7 @@ void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders, fVS.addFeature(featureBit, extensionName); } if (shaders & kGeometry_GrShaderFlag) { - SkASSERT(this->glslCaps()->geometryShaderSupport()); + SkASSERT(this->primitiveProcessor().willUseGeoShader()); fGS.addFeature(featureBit, extensionName); } if (shaders & kFragment_GrShaderFlag) { @@ -56,15 +62,10 @@ bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage); this->emitAndInstallFragProcs(inputColor, inputCoverage); - if (primProc.getPixelLocalStorageState() != - GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) { - this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, - *inputCoverage, this->pipeline().ignoresCoverage(), - primProc.getPixelLocalStorageState()); - this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput()); - } + this->emitAndInstallXferProc(*inputColor, *inputCoverage); + this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput()); - return this->checkSamplerCounts(); + return this->checkSamplerCounts() && this->checkImageStorageCounts(); } void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc, @@ -86,6 +87,18 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr fFS.codeAppendf("vec4 %s;", distanceVectorName); } + SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid()); + GrShaderFlags rtAdjustVisibility = kVertex_GrShaderFlag; + if (proc.willUseGeoShader()) { + rtAdjustVisibility |= kGeometry_GrShaderFlag; + } + fUniformHandles.fRTAdjustmentUni = this->uniformHandler()->addUniform(rtAdjustVisibility, + kVec4f_GrSLType, + kHigh_GrSLPrecision, + "rtAdjustment"); + const char* rtAdjustName = + this->uniformHandler()->getUniformCStr(fUniformHandles.fRTAdjustmentUni); + // Enclose custom code in a block to avoid namespace conflicts SkString openBrace; openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name()); @@ -93,25 +106,29 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr fVS.codeAppendf("// Primitive Processor %s\n", proc.name()); SkASSERT(!fGeometryProcessor); - fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps()); + fGeometryProcessor = proc.createGLSLInstance(*this->shaderCaps()); - SkSTArray<4, SamplerHandle> texSamplers(proc.numTextures()); - SkSTArray<2, SamplerHandle> bufferSamplers(proc.numBuffers()); - this->emitSamplers(proc, &texSamplers, &bufferSamplers); + SkSTArray<4, SamplerHandle> texSamplers(proc.numTextureSamplers()); + SkSTArray<2, SamplerHandle> bufferSamplers(proc.numBuffers()); + SkSTArray<2, ImageStorageHandle> imageStorages(proc.numImageStorages()); + this->emitSamplersAndImageStorages(proc, &texSamplers, &bufferSamplers, &imageStorages); GrGLSLPrimitiveProcessor::FPCoordTransformHandler transformHandler(fPipeline, &fTransformedCoordVars); GrGLSLGeometryProcessor::EmitArgs args(&fVS, + proc.willUseGeoShader() ? &fGS : nullptr, &fFS, this->varyingHandler(), this->uniformHandler(), - this->glslCaps(), + this->shaderCaps(), proc, outputColor->c_str(), outputCoverage->c_str(), distanceVectorName, + rtAdjustName, texSamplers.begin(), bufferSamplers.begin(), + imageStorages.begin(), &transformHandler); fGeometryProcessor->emitCode(args); @@ -158,26 +175,30 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance(); - SkSTArray<4, SamplerHandle> textureSamplerArray(fp.numTextures()); + SkSTArray<4, SamplerHandle> textureSamplerArray(fp.numTextureSamplers()); SkSTArray<2, SamplerHandle> bufferSamplerArray(fp.numBuffers()); + SkSTArray<2, ImageStorageHandle> imageStorageArray(fp.numImageStorages()); GrFragmentProcessor::Iter iter(&fp); while (const GrFragmentProcessor* subFP = iter.next()) { - this->emitSamplers(*subFP, &textureSamplerArray, &bufferSamplerArray); + this->emitSamplersAndImageStorages(*subFP, &textureSamplerArray, &bufferSamplerArray, + &imageStorageArray); } const GrShaderVar* coordVars = fTransformedCoordVars.begin() + transformedCoordVarsIdx; GrGLSLFragmentProcessor::TransformedCoordVars coords(&fp, coordVars); GrGLSLFragmentProcessor::TextureSamplers textureSamplers(&fp, textureSamplerArray.begin()); GrGLSLFragmentProcessor::BufferSamplers bufferSamplers(&fp, bufferSamplerArray.begin()); + GrGLSLFragmentProcessor::ImageStorages imageStorages(&fp, imageStorageArray.begin()); GrGLSLFragmentProcessor::EmitArgs args(&fFS, this->uniformHandler(), - this->glslCaps(), + this->shaderCaps(), fp, output->c_str(), input.isOnes() ? nullptr : input.c_str(), coords, textureSamplers, bufferSamplers, + imageStorages, this->primitiveProcessor().implementsDistanceVector()); fragProc->emitCode(args); @@ -190,15 +211,13 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, fFS.codeAppend("}"); } -void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, - const GrGLSLExpr4& colorIn, - const GrGLSLExpr4& coverageIn, - bool ignoresCoverage, - GrPixelLocalStorageState plsState) { +void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrGLSLExpr4& colorIn, + const GrGLSLExpr4& coverageIn) { // Program builders have a bit of state we need to clear with each effect AutoStageAdvance adv(this); SkASSERT(!fXferProcessor); + const GrXferProcessor& xp = fPipeline.getXferProcessor(); fXferProcessor = xp.createGLSLInstance(); // Enable dual source secondary output if we have one @@ -206,7 +225,7 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, fFS.enableSecondaryOutput(); } - if (this->glslCaps()->mustDeclareFragmentShaderOutput()) { + if (this->shaderCaps()->mustDeclareFragmentShaderOutput()) { fFS.enableCustomOutput(); } @@ -214,21 +233,28 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, openBrace.printf("{ // Xfer Processor: %s\n", xp.name()); fFS.codeAppend(openBrace.c_str()); - SkSTArray<4, SamplerHandle> texSamplers(xp.numTextures()); - SkSTArray<2, SamplerHandle> bufferSamplers(xp.numBuffers()); - this->emitSamplers(xp, &texSamplers, &bufferSamplers); + SamplerHandle dstTextureSamplerHandle; + GrSurfaceOrigin dstTextureOrigin = kTopLeft_GrSurfaceOrigin; + if (GrTexture* dstTexture = fPipeline.dstTexture()) { + // GrProcessor::TextureSampler sampler(dstTexture); + SkString name("DstTextureSampler"); + dstTextureSamplerHandle = + this->emitSampler(dstTexture->texturePriv().samplerType(), dstTexture->config(), + "DstTextureSampler", kFragment_GrShaderFlag); + dstTextureOrigin = dstTexture->origin(); + SkASSERT(kTextureExternalSampler_GrSLType != dstTexture->texturePriv().samplerType()); + } - bool usePLSDstRead = (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState); GrGLSLXferProcessor::EmitArgs args(&fFS, this->uniformHandler(), - this->glslCaps(), - xp, colorIn.c_str(), - ignoresCoverage ? nullptr : coverageIn.c_str(), + this->shaderCaps(), + xp, + colorIn.c_str(), + coverageIn.c_str(), fFS.getPrimaryColorOutputName(), fFS.getSecondaryColorOutputName(), - texSamplers.begin(), - bufferSamplers.begin(), - usePLSDstRead); + dstTextureSamplerHandle, + dstTextureOrigin); fXferProcessor->emitCode(args); // We have to check that effects and the code they emit are consistent, ie if an effect @@ -237,52 +263,62 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, fFS.codeAppend("}"); } -void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor, - SkTArray* outTexSamplers, - SkTArray* outBufferSamplers) { +void GrGLSLProgramBuilder::emitSamplersAndImageStorages( + const GrResourceIOProcessor& processor, + SkTArray* outTexSamplerHandles, + SkTArray* outBufferSamplerHandles, + SkTArray* outImageStorageHandles) { SkString name; - int numTextures = processor.numTextures(); - for (int t = 0; t < numTextures; ++t) { - const GrTextureAccess& access = processor.textureAccess(t); - GrSLType samplerType = access.getTexture()->samplerType(); + int numTextureSamplers = processor.numTextureSamplers(); + for (int t = 0; t < numTextureSamplers; ++t) { + const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(t); + name.printf("TextureSampler_%d", outTexSamplerHandles->count()); + GrSLType samplerType = sampler.texture()->texturePriv().samplerType(); if (kTextureExternalSampler_GrSLType == samplerType) { - const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString(); + const char* externalFeatureString = + this->shaderCaps()->externalTextureExtensionString(); // We shouldn't ever create a GrGLTexture that requires external sampler type SkASSERT(externalFeatureString); - this->addFeature(access.getVisibility(), + this->addFeature(sampler.visibility(), 1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature, externalFeatureString); } - name.printf("TextureSampler_%d", outTexSamplers->count()); - this->emitSampler(samplerType, access.getTexture()->config(), - name.c_str(), access.getVisibility(), outTexSamplers); + outTexSamplerHandles->emplace_back(this->emitSampler( + samplerType, sampler.texture()->config(), name.c_str(), sampler.visibility())); } - if (int numBuffers = processor.numBuffers()) { - SkASSERT(this->glslCaps()->texelBufferSupport()); + SkASSERT(this->shaderCaps()->texelBufferSupport()); GrShaderFlags texelBufferVisibility = kNone_GrShaderFlags; for (int b = 0; b < numBuffers; ++b) { - const GrBufferAccess& access = processor.bufferAccess(b); - name.printf("BufferSampler_%d", outBufferSamplers->count()); - this->emitSampler(kTextureBufferSampler_GrSLType, access.texelConfig(), name.c_str(), - access.visibility(), outBufferSamplers); + const GrResourceIOProcessor::BufferAccess& access = processor.bufferAccess(b); + name.printf("BufferSampler_%d", outBufferSamplerHandles->count()); + outBufferSamplerHandles->emplace_back( + this->emitSampler(kBufferSampler_GrSLType, access.texelConfig(), name.c_str(), + access.visibility())); texelBufferVisibility |= access.visibility(); } - if (const char* extension = this->glslCaps()->texelBufferExtensionString()) { + if (const char* extension = this->shaderCaps()->texelBufferExtensionString()) { this->addFeature(texelBufferVisibility, 1 << GrGLSLShaderBuilder::kTexelBuffer_GLSLPrivateFeature, extension); } } + int numImageStorages = processor.numImageStorages(); + for (int i = 0; i < numImageStorages; ++i) { + const GrResourceIOProcessor::ImageStorageAccess& imageStorageAccess = + processor.imageStorageAccess(i); + name.printf("Image_%d", outImageStorageHandles->count()); + outImageStorageHandles->emplace_back( + this->emitImageStorage(imageStorageAccess, name.c_str())); + } } -void GrGLSLProgramBuilder::emitSampler(GrSLType samplerType, - GrPixelConfig config, - const char* name, - GrShaderFlags visibility, - SkTArray* outSamplers) { +GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitSampler(GrSLType samplerType, + GrPixelConfig config, + const char* name, + GrShaderFlags visibility) { if (visibility & kVertex_GrShaderFlag) { ++fNumVertexSamplers; } @@ -293,19 +329,33 @@ void GrGLSLProgramBuilder::emitSampler(GrSLType samplerType, if (visibility & kFragment_GrShaderFlag) { ++fNumFragmentSamplers; } - GrSLPrecision precision = this->glslCaps()->samplerPrecision(config, visibility); - SamplerHandle handle = this->uniformHandler()->addSampler(visibility, - config, - samplerType, - precision, - name); - outSamplers->emplace_back(handle); + GrSLPrecision precision = this->shaderCaps()->samplerPrecision(config, visibility); + GrSwizzle swizzle = this->shaderCaps()->configTextureSwizzle(config); + return this->uniformHandler()->addSampler(visibility, swizzle, samplerType, precision, name); +} + +GrGLSLProgramBuilder::ImageStorageHandle GrGLSLProgramBuilder::emitImageStorage( + const GrResourceIOProcessor::ImageStorageAccess& access, const char* name) { + if (access.visibility() & kVertex_GrShaderFlag) { + ++fNumVertexImageStorages; + } + if (access.visibility() & kGeometry_GrShaderFlag) { + SkASSERT(this->primitiveProcessor().willUseGeoShader()); + ++fNumGeometryImageStorages; + } + if (access.visibility() & kFragment_GrShaderFlag) { + ++fNumFragmentImageStorages; + } + GrSLType uniformType = access.texture()->texturePriv().imageStorageType(); + return this->uniformHandler()->addImageStorage(access.visibility(), uniformType, + access.format(), access.memoryModel(), + access.restrict(), access.ioType(), name); } void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) { // Swizzle the fragment shader outputs if necessary. GrSwizzle swizzle; - swizzle.setFromKey(this->desc().header().fOutputSwizzle); + swizzle.setFromKey(this->desc()->header().fOutputSwizzle); if (swizzle != GrSwizzle::RGBA()) { fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(), fFS.getPrimaryColorOutputName(), @@ -319,28 +369,52 @@ void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) { } bool GrGLSLProgramBuilder::checkSamplerCounts() { - const GrGLSLCaps& glslCaps = *this->glslCaps(); - if (fNumVertexSamplers > glslCaps.maxVertexSamplers()) { + const GrShaderCaps& shaderCaps = *this->shaderCaps(); + if (fNumVertexSamplers > shaderCaps.maxVertexSamplers()) { GrCapsDebugf(this->caps(), "Program would use too many vertex samplers\n"); return false; } - if (fNumGeometrySamplers > glslCaps.maxGeometrySamplers()) { + if (fNumGeometrySamplers > shaderCaps.maxGeometrySamplers()) { GrCapsDebugf(this->caps(), "Program would use too many geometry samplers\n"); return false; } - if (fNumFragmentSamplers > glslCaps.maxFragmentSamplers()) { + if (fNumFragmentSamplers > shaderCaps.maxFragmentSamplers()) { GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n"); return false; } // If the same sampler is used in two different shaders, it counts as two combined samplers. int numCombinedSamplers = fNumVertexSamplers + fNumGeometrySamplers + fNumFragmentSamplers; - if (numCombinedSamplers > glslCaps.maxCombinedSamplers()) { + if (numCombinedSamplers > shaderCaps.maxCombinedSamplers()) { GrCapsDebugf(this->caps(), "Program would use too many combined samplers\n"); return false; } return true; } +bool GrGLSLProgramBuilder::checkImageStorageCounts() { + const GrShaderCaps& shaderCaps = *this->shaderCaps(); + if (fNumVertexImageStorages > shaderCaps.maxVertexImageStorages()) { + GrCapsDebugf(this->caps(), "Program would use too many vertex images\n"); + return false; + } + if (fNumGeometryImageStorages > shaderCaps.maxGeometryImageStorages()) { + GrCapsDebugf(this->caps(), "Program would use too many geometry images\n"); + return false; + } + if (fNumFragmentImageStorages > shaderCaps.maxFragmentImageStorages()) { + GrCapsDebugf(this->caps(), "Program would use too many fragment images\n"); + return false; + } + // If the same image is used in two different shaders, it counts as two combined images. + int numCombinedImages = fNumVertexImageStorages + fNumGeometryImageStorages + + fNumFragmentImageStorages; + if (numCombinedImages > shaderCaps.maxCombinedImageStorages()) { + GrCapsDebugf(this->caps(), "Program would use too many combined images\n"); + return false; + } + return true; +} + #ifdef SK_DEBUG void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { SkASSERT(fFS.usedProcessorFeatures() == gp.requiredFeatures()); @@ -389,29 +463,13 @@ void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString this->uniformHandler()->appendUniformDecls(visibility, out); } -const GrGLSLSampler& GrGLSLProgramBuilder::getSampler(SamplerHandle handle) const { - return this->uniformHandler()->getSampler(handle); -} - -void GrGLSLProgramBuilder::addRTAdjustmentUniform(GrSLPrecision precision, - const char* name, - const char** outName) { - SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid()); - fUniformHandles.fRTAdjustmentUni = - this->uniformHandler()->addUniform(kVertex_GrShaderFlag, - kVec4f_GrSLType, - precision, - name, - outName); -} - -void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** outName) { +void GrGLSLProgramBuilder::addRTHeightUniform(const char* name) { SkASSERT(!fUniformHandles.fRTHeightUni.isValid()); GrGLSLUniformHandler* uniformHandler = this->uniformHandler(); fUniformHandles.fRTHeightUni = uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, - name, false, 0, outName); + name, false, 0, nullptr); } void GrGLSLProgramBuilder::cleanupFragmentProcessors() { @@ -423,5 +481,9 @@ void GrGLSLProgramBuilder::cleanupFragmentProcessors() { void GrGLSLProgramBuilder::finalizeShaders() { this->varyingHandler()->finalize(); fVS.finalize(kVertex_GrShaderFlag); + if (this->primitiveProcessor().willUseGeoShader()) { + SkASSERT(this->shaderCaps()->geometryShaderSupport()); + fGS.finalize(kGeometry_GrShaderFlag); + } fFS.finalize(kFragment_GrShaderFlag); } diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.h index 8a8cff55add2..147eb98c98a7 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.h @@ -8,6 +8,7 @@ #ifndef GrGLSLProgramBuilder_DEFINED #define GrGLSLProgramBuilder_DEFINED +#include "GrCaps.h" #include "GrGeometryProcessor.h" #include "GrGpu.h" #include "glsl/GrGLSLFragmentProcessor.h" @@ -16,35 +17,45 @@ #include "glsl/GrGLSLPrimitiveProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" -#include "glsl/GrGLSLSampler.h" #include "glsl/GrGLSLVertexShaderBuilder.h" #include "glsl/GrGLSLXferProcessor.h" -class GrGLSLCaps; -class GrGLSLShaderVar; +class GrShaderVar; class GrGLSLVaryingHandler; +class GrGLSLExpr4; +class GrShaderCaps; typedef SkSTArray<8, GrGLSLFragmentProcessor*, true> GrGLSLFragProcs; class GrGLSLProgramBuilder { public: - typedef GrGLSLUniformHandler::UniformHandle UniformHandle; + using UniformHandle = GrGLSLUniformHandler::UniformHandle; + using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; + using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle; virtual ~GrGLSLProgramBuilder() {} virtual const GrCaps* caps() const = 0; - virtual const GrGLSLCaps* glslCaps() const = 0; + const GrShaderCaps* shaderCaps() const { return this->caps()->shaderCaps(); } const GrPrimitiveProcessor& primitiveProcessor() const { return fPrimProc; } const GrPipeline& pipeline() const { return fPipeline; } - const GrProgramDesc& desc() const { return fDesc; } - const GrProgramDesc::KeyHeader& header() const { return fDesc.header(); } + GrProgramDesc* desc() { return fDesc; } + const GrProgramDesc::KeyHeader& header() const { return fDesc->header(); } void appendUniformDecls(GrShaderFlags visibility, SkString*) const; - typedef GrGLSLUniformHandler::SamplerHandle SamplerHandle; + const GrShaderVar& samplerVariable(SamplerHandle handle) const { + return this->uniformHandler()->samplerVariable(handle); + } - const GrGLSLSampler& getSampler(SamplerHandle handle) const; + GrSwizzle samplerSwizzle(SamplerHandle handle) const { + return this->uniformHandler()->samplerSwizzle(handle); + } + + const GrShaderVar& imageStorageVariable(ImageStorageHandle handle) const { + return this->uniformHandler()->imageStorageVariable(handle); + } // Handles for program uniforms (other than per-effect uniforms) struct BuiltinUniformHandles { @@ -55,13 +66,9 @@ public: UniformHandle fRTHeightUni; }; - // Used to add a uniform in the vertex shader for transforming into normalized device space. - void addRTAdjustmentUniform(GrSLPrecision precision, const char* name, const char** outName); - const char* rtAdjustment() const { return "rtAdjustment"; } - // Used to add a uniform for the RenderTarget height (used for frag position) without mangling // the name of the uniform inside of a stage. - void addRTHeightUniform(const char* name, const char** outName); + void addRTHeightUniform(const char* name); // Generates a name for a variable. The generated string will be name prefixed by the prefix // char (unless the prefix is '\0'). It also will mangle the name to be stage-specific unless @@ -74,8 +81,8 @@ public: // Used for backend customization of the output color and secondary color variables from the // fragment processor. Only used if the outputs are explicitly declared in the shaders - virtual void finalizeFragmentOutputColor(GrGLSLShaderVar& outputColor) {} - virtual void finalizeFragmentSecondaryColor(GrGLSLShaderVar& outputColor) {} + virtual void finalizeFragmentOutputColor(GrShaderVar& outputColor) {} + virtual void finalizeFragmentSecondaryColor(GrShaderVar& outputColor) {} // number of each input/output type in a single allocation block, used by many builders static const int kVarsPerBlock; @@ -88,7 +95,7 @@ public: const GrPipeline& fPipeline; const GrPrimitiveProcessor& fPrimProc; - const GrProgramDesc& fDesc; + GrProgramDesc* fDesc; BuiltinUniformHandles fUniformHandles; @@ -99,7 +106,7 @@ public: protected: explicit GrGLSLProgramBuilder(const GrPipeline&, const GrPrimitiveProcessor&, - const GrProgramDesc&); + GrProgramDesc*); void addFeature(GrShaderFlags shaders, uint32_t featureBit, const char* extensionName); @@ -145,22 +152,18 @@ private: int transformedCoordVarsIdx, const GrGLSLExpr4& input, GrGLSLExpr4* output); - void emitAndInstallXferProc(const GrXferProcessor&, - const GrGLSLExpr4& colorIn, - const GrGLSLExpr4& coverageIn, - bool ignoresCoverage, - GrPixelLocalStorageState plsState); - - void emitSamplers(const GrProcessor& processor, - SkTArray* outTexSamplers, - SkTArray* outBufferSamplers); - void emitSampler(GrSLType samplerType, - GrPixelConfig, - const char* name, - GrShaderFlags visibility, - SkTArray* outSamplers); + void emitAndInstallXferProc(const GrGLSLExpr4& colorIn, const GrGLSLExpr4& coverageIn); + void emitSamplersAndImageStorages(const GrResourceIOProcessor& processor, + SkTArray* outTexSamplerHandles, + SkTArray* outBufferSamplerHandles, + SkTArray* outImageStorageHandles); + SamplerHandle emitSampler(GrSLType samplerType, GrPixelConfig, const char* name, + GrShaderFlags visibility); + ImageStorageHandle emitImageStorage(const GrResourceIOProcessor::ImageStorageAccess&, + const char* name); void emitFSOutputSwizzle(bool hasSecondaryOutput); bool checkSamplerCounts(); + bool checkImageStorageCounts(); #ifdef SK_DEBUG void verify(const GrPrimitiveProcessor&); @@ -171,6 +174,9 @@ private: int fNumVertexSamplers; int fNumGeometrySamplers; int fNumFragmentSamplers; + int fNumVertexImageStorages; + int fNumGeometryImageStorages; + int fNumFragmentImageStorages; SkSTArray<4, GrShaderVar> fTransformedCoordVars; }; diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLSampler.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLSampler.h deleted file mode 100644 index bc90769295cb..000000000000 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLSampler.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrGLSLSampler_DEFINED -#define GrGLSLSampler_DEFINED - -#include "GrTypes.h" -#include "GrTypesPriv.h" -#include "SkString.h" - -class GrGLSLSampler { -public: - virtual ~GrGLSLSampler() {} - - explicit GrGLSLSampler(uint32_t visibility, GrPixelConfig config) - : fVisibility(visibility) - , fConfig(config) { - SkASSERT(kUnknown_GrPixelConfig != fConfig); - } - - uint32_t visibility() const { return fVisibility; } - GrPixelConfig config() const { return fConfig; } - virtual GrSLType type() const = 0; - - // Returns the string to be used for the sampler in glsl 2D texture functions (texture, - // texture2D, etc.) - const char* getSamplerNameForTexture2D() const { - SkASSERT(GrSLTypeIs2DCombinedSamplerType(this->type())); - return this->onGetSamplerNameForTexture2D(); - } - - // Returns the string to be used for the sampler in glsl texelFetch. - virtual const char* getSamplerNameForTexelFetch() const = 0; - -private: - virtual const char* onGetSamplerNameForTexture2D() const = 0; - uint32_t fVisibility; - GrPixelConfig fConfig; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp index 6d77bdbf9a5c..865876611ab8 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp @@ -5,12 +5,11 @@ * found in the LICENSE file. */ +#include "GrShaderVar.h" +#include "GrShaderCaps.h" #include "GrSwizzle.h" #include "glsl/GrGLSLShaderBuilder.h" -#include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLColorSpaceXformHelper.h" -#include "glsl/GrGLSLShaderVar.h" -#include "glsl/GrGLSLSampler.h" #include "glsl/GrGLSLProgramBuilder.h" GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program) @@ -30,22 +29,21 @@ GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program) this->main() = "void main() {"; } -void GrGLSLShaderBuilder::declAppend(const GrGLSLShaderVar& var) { +void GrGLSLShaderBuilder::declAppend(const GrShaderVar& var) { SkString tempDecl; - var.appendDecl(fProgramBuilder->glslCaps(), &tempDecl); + var.appendDecl(fProgramBuilder->shaderCaps(), &tempDecl); this->codeAppendf("%s;", tempDecl.c_str()); } -void GrGLSLShaderBuilder::appendPrecisionModifier(GrSLPrecision precision) { - if (fProgramBuilder->glslCaps()->usesPrecisionModifiers()) { - this->codeAppendf("%s ", GrGLSLPrecisionString(precision)); - } +void GrGLSLShaderBuilder::declareGlobal(const GrShaderVar& v) { + v.appendDecl(this->getProgramBuilder()->shaderCaps(), &this->definitions()); + this->definitions().append(";"); } void GrGLSLShaderBuilder::emitFunction(GrSLType returnType, const char* name, int argCnt, - const GrGLSLShaderVar* args, + const GrShaderVar* args, const char* body, SkString* outName) { this->functions().append(GrGLSLTypeString(returnType)); @@ -53,7 +51,7 @@ void GrGLSLShaderBuilder::emitFunction(GrSLType returnType, this->functions().appendf(" %s", outName->c_str()); this->functions().append("("); for (int i = 0; i < argCnt; ++i) { - args[i].appendDecl(fProgramBuilder->glslCaps(), &this->functions()); + args[i].appendDecl(fProgramBuilder->shaderCaps(), &this->functions()); if (i < argCnt - 1) { this->functions().append(", "); } @@ -63,45 +61,37 @@ void GrGLSLShaderBuilder::emitFunction(GrSLType returnType, this->functions().append("}\n\n"); } +static inline void append_texture_swizzle(SkString* out, GrSwizzle swizzle) { + if (swizzle != GrSwizzle::RGBA()) { + out->appendf(".%s", swizzle.c_str()); + } +} + void GrGLSLShaderBuilder::appendTextureLookup(SkString* out, SamplerHandle samplerHandle, const char* coordName, GrSLType varyingType) const { - const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps(); - const GrGLSLSampler& sampler = fProgramBuilder->getSampler(samplerHandle); - GrSLType samplerType = sampler.type(); + const GrShaderVar& sampler = fProgramBuilder->samplerVariable(samplerHandle); + GrSLType samplerType = sampler.getType(); if (samplerType == kTexture2DRectSampler_GrSLType) { if (varyingType == kVec2f_GrSLType) { - out->appendf("%s(%s, textureSize(%s) * %s)", - GrGLSLTexture2DFunctionName(varyingType, samplerType, - glslCaps->generation()), - sampler.getSamplerNameForTexture2D(), - sampler.getSamplerNameForTexture2D(), - coordName); + out->appendf("texture(%s, textureSize(%s) * %s)", + sampler.c_str(), sampler.c_str(), coordName); } else { - out->appendf("%s(%s, vec3(textureSize(%s) * %s.xy, %s.z))", - GrGLSLTexture2DFunctionName(varyingType, samplerType, - glslCaps->generation()), - sampler.getSamplerNameForTexture2D(), - sampler.getSamplerNameForTexture2D(), - coordName, - coordName); + out->appendf("texture(%s, vec3(textureSize(%s) * %s.xy, %s.z))", + sampler.c_str(), sampler.c_str(), coordName, coordName); } } else { - out->appendf("%s(%s, %s)", - GrGLSLTexture2DFunctionName(varyingType, samplerType, glslCaps->generation()), - sampler.getSamplerNameForTexture2D(), - coordName); + out->appendf("texture(%s, %s)", sampler.c_str(), coordName); } - - this->appendTextureSwizzle(out, sampler.config()); + append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle)); } void GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle, const char* coordName, GrSLType varyingType, GrGLSLColorSpaceXformHelper* colorXformHelper) { - if (colorXformHelper && colorXformHelper->getXformMatrix()) { + if (colorXformHelper && colorXformHelper->isValid()) { // With a color gamut transform, we need to wrap the lookup in another function call SkString lookup; this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType); @@ -119,7 +109,7 @@ void GrGLSLShaderBuilder::appendTextureLookupAndModulate( GrGLSLColorSpaceXformHelper* colorXformHelper) { SkString lookup; this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType); - if (colorXformHelper && colorXformHelper->getXformMatrix()) { + if (colorXformHelper && colorXformHelper->isValid()) { SkString xform; this->appendColorGamutXform(&xform, lookup.c_str(), colorXformHelper); this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(xform)).c_str()); @@ -134,13 +124,14 @@ void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out, // Our color is (r, g, b, a), but we want to multiply (r, g, b, 1) by our matrix, then // re-insert the original alpha. The supplied srcColor is likely to be of the form // "texture(...)", and we don't want to evaluate that twice, so wrap everything in a function. - static const GrGLSLShaderVar gColorGamutXformArgs[] = { - GrGLSLShaderVar("color", kVec4f_GrSLType), - GrGLSLShaderVar("xform", kMat44f_GrSLType), + static const GrShaderVar gColorGamutXformArgs[] = { + GrShaderVar("color", kVec4f_GrSLType), + GrShaderVar("xform", kMat44f_GrSLType), }; SkString functionBody; - // Gamut xform, clamp to destination gamut - functionBody.append("\tcolor.rgb = clamp((xform * vec4(color.rgb, 1.0)).rgb, 0.0, 1.0);\n"); + // Gamut xform, clamp to destination gamut. We only support/have premultiplied textures, so we + // always just clamp to alpha. + functionBody.append("\tcolor.rgb = clamp((xform * vec4(color.rgb, 1.0)).rgb, 0.0, color.a);\n"); functionBody.append("\treturn color;"); SkString colorGamutXformFuncName; this->emitFunction(kVec4f_GrSLType, @@ -150,8 +141,9 @@ void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out, functionBody.c_str(), &colorGamutXformFuncName); + GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler(); out->appendf("%s(%s, %s)", colorGamutXformFuncName.c_str(), srcColor, - colorXformHelper->getXformMatrix()); + uniformHandler->getUniformCStr(colorXformHelper->gamutXformUniform())); } void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor, @@ -164,25 +156,27 @@ void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor, void GrGLSLShaderBuilder::appendTexelFetch(SkString* out, SamplerHandle samplerHandle, const char* coordExpr) const { - const GrGLSLSampler& sampler = fProgramBuilder->getSampler(samplerHandle); - SkASSERT(fProgramBuilder->glslCaps()->texelFetchSupport()); - SkASSERT(GrSLTypeIsCombinedSamplerType(sampler.type())); + const GrShaderVar& sampler = fProgramBuilder->samplerVariable(samplerHandle); + SkASSERT(fProgramBuilder->shaderCaps()->texelFetchSupport()); + SkASSERT(GrSLTypeIsCombinedSamplerType(sampler.getType())); - out->appendf("texelFetch(%s, %s)", sampler.getSamplerNameForTexelFetch(), coordExpr); + out->appendf("texelFetch(%s, %s)", sampler.c_str(), coordExpr); - this->appendTextureSwizzle(out, sampler.config()); + append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle)); } void GrGLSLShaderBuilder::appendTexelFetch(SamplerHandle samplerHandle, const char* coordExpr) { this->appendTexelFetch(&this->code(), samplerHandle, coordExpr); } -void GrGLSLShaderBuilder::appendTextureSwizzle(SkString* out, GrPixelConfig config) const { - const GrSwizzle& configSwizzle = fProgramBuilder->glslCaps()->configTextureSwizzle(config); +void GrGLSLShaderBuilder::appendImageStorageLoad(SkString* out, ImageStorageHandle handle, + const char* coordExpr) { + const GrShaderVar& imageStorage = fProgramBuilder->imageStorageVariable(handle); + out->appendf("imageLoad(%s, %s)", imageStorage.c_str(), coordExpr); +} - if (configSwizzle != GrSwizzle::RGBA()) { - out->appendf(".%s", configSwizzle.c_str()); - } +void GrGLSLShaderBuilder::appendImageStorageLoad(ImageStorageHandle handle, const char* coordExpr) { + this->appendImageStorageLoad(&this->code(), handle, coordExpr); } bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) { @@ -196,19 +190,20 @@ bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionN void GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const { for (int i = 0; i < vars.count(); ++i) { - vars[i].appendDecl(fProgramBuilder->glslCaps(), out); + vars[i].appendDecl(fProgramBuilder->shaderCaps(), out); out->append(";\n"); } } void GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) { - SkASSERT(fProgramBuilder->glslCaps()->generation() >= k330_GrGLSLGeneration || - fProgramBuilder->glslCaps()->mustEnableAdvBlendEqs()); + SkASSERT(fProgramBuilder->shaderCaps()->generation() >= k330_GrGLSLGeneration || + fProgramBuilder->shaderCaps()->mustEnableAdvBlendEqs()); fLayoutParams[interface].push_back() = param; } void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() { static const char* interfaceQualifierNames[] = { + "in", "out" }; @@ -224,13 +219,14 @@ void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() { this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]); } - GR_STATIC_ASSERT(0 == GrGLSLShaderBuilder::kOut_InterfaceQualifier); + GR_STATIC_ASSERT(0 == GrGLSLShaderBuilder::kIn_InterfaceQualifier); + GR_STATIC_ASSERT(1 == GrGLSLShaderBuilder::kOut_InterfaceQualifier); GR_STATIC_ASSERT(SK_ARRAY_COUNT(interfaceQualifierNames) == kLastInterfaceQualifier + 1); } void GrGLSLShaderBuilder::finalize(uint32_t visibility) { SkASSERT(!fFinalized); - this->versionDecl() = fProgramBuilder->glslCaps()->versionDeclString(); + this->versionDecl() = fProgramBuilder->shaderCaps()->versionDeclString(); this->compileAndAppendLayoutQualifiers(); SkASSERT(visibility); fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms()); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.h index a6ff96dd1b08..2d6aaf08fa5c 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.h @@ -9,8 +9,8 @@ #define GrGLSLShaderBuilder_DEFINED #include "GrAllocator.h" +#include "GrShaderVar.h" #include "glsl/GrGLSLUniformHandler.h" -#include "glsl/GrGLSLShaderVar.h" #include "SkTDArray.h" #include @@ -25,11 +25,13 @@ public: GrGLSLShaderBuilder(GrGLSLProgramBuilder* program); virtual ~GrGLSLShaderBuilder() {} - typedef GrGLSLUniformHandler::SamplerHandle SamplerHandle; + using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; + using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle; /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle - order of the result depends on the GrTextureAccess associated with the GrGLSLSampler. + order of the result depends on the GrProcessor::TextureSampler associated with the + SamplerHandle. */ void appendTextureLookup(SkString* out, SamplerHandle, @@ -44,7 +46,7 @@ public: /** Does the work of appendTextureLookup and modulates the result by modulation. The result is - always a vec4. modulation and the swizzle specified by GrGLSLSampler must both be + always a vec4. modulation and the swizzle specified by SamplerHandle must both be vec4 or float. If modulation is "" or nullptr it this function acts as though appendTextureLookup were called. */ void appendTextureLookupAndModulate(const char* modulation, @@ -71,26 +73,37 @@ public: /** Version of above that appends the result to the shader code instead.*/ void appendTexelFetch(SamplerHandle, const char* coordExpr); + /** Creates a string of shader code that performs an image load. */ + void appendImageStorageLoad(SkString* out, ImageStorageHandle, const char* coordExpr); + /** Version of above that appends the result to the shader code instead. */ + void appendImageStorageLoad(ImageStorageHandle, const char* coordExpr); + /** - * Adds a #define directive to the top of the shader. + * Adds a constant declaration to the top of the shader. */ - void define(const char* macro, const char* replacement) { - this->definitions().appendf("#define %s %s\n", macro, replacement); + void defineConstant(const char* type, const char* name, const char* value) { + this->definitions().appendf("const %s %s = %s;\n", type, name, value); } - void define(const char* macro, int replacement) { - this->definitions().appendf("#define %s %i\n", macro, replacement); + void defineConstant(const char* name, int value) { + this->definitions().appendf("const int %s = %i;\n", name, value); } - void definef(const char* macro, const char* replacement, ...) { - this->definitions().appendf("#define %s ", macro); + void defineConstant(const char* name, float value) { + this->definitions().appendf("const float %s = %f;\n", name, value); + } + + void defineConstantf(const char* type, const char* name, const char* fmt, ...) { + this->definitions().appendf("const %s %s = ", type, name); va_list args; - va_start(args, replacement); - this->definitions().appendVAList(replacement, args); + va_start(args, fmt); + this->definitions().appendVAList(fmt, args); va_end(args); - this->definitions().append("\n"); + this->definitions().append(";\n"); } + void declareGlobal(const GrShaderVar&); + /** * Called by GrGLSLProcessors to add code to one of the shaders. */ @@ -113,18 +126,13 @@ public: /** * Appends a variable declaration to one of the shaders */ - void declAppend(const GrGLSLShaderVar& var); - - /** - * Appends a precision qualifier followed by a space, if relevant for the GLSL version. - */ - void appendPrecisionModifier(GrSLPrecision); + void declAppend(const GrShaderVar& var); /** Emits a helper function outside of main() in the fragment shader. */ void emitFunction(GrSLType returnType, const char* name, int argCnt, - const GrGLSLShaderVar* args, + const GrShaderVar* args, const char* body, SkString* outName); @@ -156,7 +164,7 @@ public: }; protected: - typedef GrTAllocator VarArray; + typedef GrTAllocator VarArray; void appendDecls(const VarArray& vars, SkString* out) const; /** @@ -183,6 +191,7 @@ protected: bool addFeature(uint32_t featureBit, const char* extensionName); enum InterfaceQualifier { + kIn_InterfaceQualifier, kOut_InterfaceQualifier, kLastInterfaceQualifier = kOut_InterfaceQualifier }; @@ -198,12 +207,6 @@ protected: void compileAndAppendLayoutQualifiers(); - /* Appends any swizzling we may need to get from some backend internal format to the format used - * in GrPixelConfig. If this is implemented by the GrGpu object, then swizzle will be rgba. For - * shader prettiness we omit the swizzle rather than appending ".rgba". - */ - void appendTextureSwizzle(SkString* out, GrPixelConfig) const; - void nextStage() { fShaderStrings.push_back(); fCompilerStrings.push_back(this->code().c_str()); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderVar.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderVar.h deleted file mode 100644 index 9d162ecaa4b5..000000000000 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderVar.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrGLSLShaderVar_DEFINED -#define GrGLSLShaderVar_DEFINED - -#include "GrShaderVar.h" -#include "../glsl/GrGLSL.h" -#include "../glsl/GrGLSLCaps.h" - -#define USE_UNIFORM_FLOAT_ARRAYS true - -/** - * Represents a variable in a shader - */ -class GrGLSLShaderVar : public GrShaderVar { -public: - /** - * Defaults to a float with no precision specifier - */ - GrGLSLShaderVar() - : GrShaderVar() - , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) { - } - - GrGLSLShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray, - GrSLPrecision precision = kDefault_GrSLPrecision) - : GrShaderVar(name, type, arrayCount, precision) - , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) { - SkASSERT(kVoid_GrSLType != type); - fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS; - } - - GrGLSLShaderVar(const char* name, GrSLType type, TypeModifier typeModifier, - int arrayCount = kNonArray, GrSLPrecision precision = kDefault_GrSLPrecision) - : GrShaderVar(name, type, typeModifier, arrayCount, precision) - , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) { - SkASSERT(kVoid_GrSLType != type); - } - - GrGLSLShaderVar(const GrShaderVar& var) - : GrShaderVar(var) - , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) { - SkASSERT(kVoid_GrSLType != var.getType()); - } - - GrGLSLShaderVar(const GrGLSLShaderVar& var) - : GrShaderVar(var.c_str(), var.getType(), var.getTypeModifier(), - var.getArrayCount(), var.getPrecision()) - , fUseUniformFloatArrays(var.fUseUniformFloatArrays) - , fLayoutQualifier(var.fLayoutQualifier) - , fExtraModifiers(var.fExtraModifiers) { - SkASSERT(kVoid_GrSLType != var.getType()); - } - - /** - * Values for array count that have special meaning. We allow 1-sized arrays. - */ - enum { - kNonArray = 0, // not an array - kUnsizedArray = -1, // an unsized array (declared with []) - }; - - /** - * Sets as a non-array. - */ - void set(GrSLType type, - TypeModifier typeModifier, - const SkString& name, - GrSLPrecision precision = kDefault_GrSLPrecision, - const char* layoutQualifier = nullptr, - const char* extraModifiers = nullptr, - bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { - SkASSERT(kVoid_GrSLType != type); - SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type)); - INHERITED::set(type, name, typeModifier, precision); - fLayoutQualifier = layoutQualifier; - if (extraModifiers) { - fExtraModifiers.printf("%s ", extraModifiers); - } - fUseUniformFloatArrays = useUniformFloatArrays; - } - - /** - * Sets as a non-array. - */ - void set(GrSLType type, - TypeModifier typeModifier, - const char* name, - GrSLPrecision precision = kDefault_GrSLPrecision, - const char* layoutQualifier = nullptr, - const char* extraModifiers = nullptr, - bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { - SkASSERT(kVoid_GrSLType != type); - SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type)); - INHERITED::set(type, name, typeModifier, precision); - fLayoutQualifier = layoutQualifier; - if (extraModifiers) { - fExtraModifiers.printf("%s ", extraModifiers); - } - fUseUniformFloatArrays = useUniformFloatArrays; - } - - /** - * Set all var options - */ - void set(GrSLType type, - TypeModifier typeModifier, - const SkString& name, - int count, - GrSLPrecision precision = kDefault_GrSLPrecision, - const char* layoutQualifier = nullptr, - const char* extraModifiers = nullptr, - bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { - SkASSERT(kVoid_GrSLType != type); - SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type)); - INHERITED::set(type, name, typeModifier, precision, count); - fLayoutQualifier = layoutQualifier; - if (extraModifiers) { - fExtraModifiers.printf("%s ", extraModifiers); - } - fUseUniformFloatArrays = useUniformFloatArrays; - } - - /** - * Set all var options - */ - void set(GrSLType type, - TypeModifier typeModifier, - const char* name, - int count, - GrSLPrecision precision = kDefault_GrSLPrecision, - const char* layoutQualifier = nullptr, - const char* extraModifiers = nullptr, - bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { - SkASSERT(kVoid_GrSLType != type); - SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type)); - INHERITED::set(type, name, typeModifier, precision, count); - fLayoutQualifier = layoutQualifier; - if (extraModifiers) { - fExtraModifiers.printf("%s ", extraModifiers); - } - fUseUniformFloatArrays = useUniformFloatArrays; - } - - /** - * Set the layout qualifier - */ - void setLayoutQualifier(const char* layoutQualifier) { - fLayoutQualifier = layoutQualifier; - } - - void addModifier(const char* modifier) { - if (modifier) { - fExtraModifiers.appendf("%s ", modifier); - } - } - - /** - * Write a declaration of this variable to out. - */ - void appendDecl(const GrGLSLCaps* glslCaps, SkString* out) const { - SkASSERT(kDefault_GrSLPrecision == fPrecision || GrSLTypeAcceptsPrecision(fType)); - if (!fLayoutQualifier.isEmpty()) { - out->appendf("layout(%s) ", fLayoutQualifier.c_str()); - } - out->append(fExtraModifiers); - if (this->getTypeModifier() != kNone_TypeModifier) { - out->append(TypeModifierString(glslCaps, this->getTypeModifier())); - out->append(" "); - } - GrSLType effectiveType = this->getType(); - if (glslCaps->usesPrecisionModifiers() && GrSLTypeAcceptsPrecision(effectiveType)) { - // Desktop GLSL has added precision qualifiers but they don't do anything. - out->appendf("%s ", GrGLSLPrecisionString(fPrecision)); - } - if (this->isArray()) { - if (this->isUnsizedArray()) { - out->appendf("%s %s[]", - GrGLSLTypeString(effectiveType), - this->getName().c_str()); - } else { - SkASSERT(this->getArrayCount() > 0); - out->appendf("%s %s[%d]", - GrGLSLTypeString(effectiveType), - this->getName().c_str(), - this->getArrayCount()); - } - } else { - out->appendf("%s %s", - GrGLSLTypeString(effectiveType), - this->getName().c_str()); - } - } - - void appendArrayAccess(int index, SkString* out) const { - out->appendf("%s[%d]%s", - this->getName().c_str(), - index, - fUseUniformFloatArrays ? "" : ".x"); - } - - void appendArrayAccess(const char* indexName, SkString* out) const { - out->appendf("%s[%s]%s", - this->getName().c_str(), - indexName, - fUseUniformFloatArrays ? "" : ".x"); - } - -private: - static const char* TypeModifierString(const GrGLSLCaps* glslCaps, TypeModifier t) { - GrGLSLGeneration gen = glslCaps->generation(); - switch (t) { - case kNone_TypeModifier: - return ""; - case kIn_TypeModifier: - return "in"; - case kInOut_TypeModifier: - return "inout"; - case kOut_TypeModifier: - return "out"; - case kUniform_TypeModifier: - return "uniform"; - case kAttribute_TypeModifier: - return k110_GrGLSLGeneration == gen ? "attribute" : "in"; - case kVaryingIn_TypeModifier: - return k110_GrGLSLGeneration == gen ? "varying" : "in"; - case kVaryingOut_TypeModifier: - return k110_GrGLSLGeneration == gen ? "varying" : "out"; - default: - SkFAIL("Unknown shader variable type modifier."); - return ""; // suppress warning - } - } - - /// Work around driver bugs on some hardware that don't correctly - /// support uniform float [] - bool fUseUniformFloatArrays; - - SkString fLayoutQualifier; - SkString fExtraModifiers; - - typedef GrShaderVar INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLUniformHandler.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLUniformHandler.h index d7b213869c7d..3d21c1cc4b55 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLUniformHandler.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLUniformHandler.h @@ -9,17 +9,18 @@ #define GrGLSLUniformHandler_DEFINED #include "GrGLSLProgramDataManager.h" -#include "GrGLSLShaderVar.h" +#include "GrShaderVar.h" +#include "GrSwizzle.h" class GrGLSLProgramBuilder; -class GrGLSLSampler; class GrGLSLUniformHandler { public: virtual ~GrGLSLUniformHandler() {} - typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; - typedef GrGLSLProgramDataManager::UniformHandle SamplerHandle; + using UniformHandle = GrGLSLProgramDataManager::UniformHandle; + GR_DEFINE_RESOURCE_HANDLE_CLASS(SamplerHandle); + GR_DEFINE_RESOURCE_HANDLE_CLASS(ImageStorageHandle); /** Add a uniform variable to the current program, that has visibility in one or more shaders. visibility is a bitfield of GrShaderFlag values indicating from which shaders the uniform @@ -47,7 +48,7 @@ public: outName); } - virtual const GrGLSLShaderVar& getUniformVariable(UniformHandle u) const = 0; + virtual const GrShaderVar& getUniformVariable(UniformHandle u) const = 0; /** * Shortcut for getUniformVariable(u).c_str() @@ -61,22 +62,16 @@ protected: GrGLSLProgramBuilder* fProgramBuilder; private: - virtual int numSamplers() const = 0; - virtual const GrGLSLSampler& getSampler(SamplerHandle handle) const = 0; + virtual const GrShaderVar& samplerVariable(SamplerHandle) const = 0; + virtual GrSwizzle samplerSwizzle(SamplerHandle) const = 0; - SamplerHandle addSampler(uint32_t visibility, - GrPixelConfig config, - GrSLType type, - GrSLPrecision precision, - const char* name) { - return this->internalAddSampler(visibility, config, type, precision, name); - } + virtual SamplerHandle addSampler(uint32_t visibility, GrSwizzle, GrSLType, GrSLPrecision, + const char* name) = 0; - virtual SamplerHandle internalAddSampler(uint32_t visibility, - GrPixelConfig config, - GrSLType type, - GrSLPrecision precision, - const char* name) = 0; + virtual const GrShaderVar& imageStorageVariable(ImageStorageHandle) const = 0; + virtual ImageStorageHandle addImageStorage(uint32_t visibility, GrSLType type, + GrImageStorageFormat, GrSLMemoryModel, GrSLRestrict, + GrIOType, const char* name) = 0; virtual UniformHandle internalAddUniformArray(uint32_t visibility, GrSLType type, diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLVarying.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLVarying.cpp index f3b0405ff582..ef3fe8af2377 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLVarying.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLVarying.cpp @@ -5,8 +5,8 @@ * found in the LICENSE file. */ +#include "GrShaderCaps.h" #include "glsl/GrGLSLVarying.h" - #include "glsl/GrGLSLProgramBuilder.h" void GrGLSLVaryingHandler::addPassThroughAttribute(const GrGeometryProcessor::Attribute* input, @@ -28,12 +28,8 @@ void GrGLSLVaryingHandler::addFlatPassThroughAttribute(const GrGeometryProcessor void GrGLSLVaryingHandler::writePassThroughAttribute(const GrGeometryProcessor::Attribute* input, const char* output, const GrGLSLVarying& v) { + SkASSERT(!fProgramBuilder->primitiveProcessor().willUseGeoShader()); fProgramBuilder->fVS.codeAppendf("%s = %s;", v.vsOut(), input->fName); - - if (fProgramBuilder->primitiveProcessor().willUseGeoShader()) { - fProgramBuilder->fGS.codeAppendf("%s = %s[0];", v.gsOut(), v.gsIn()); - } - fProgramBuilder->fFS.codeAppendf("%s = %s;", output, v.fsIn()); } @@ -46,7 +42,7 @@ void GrGLSLVaryingHandler::internalAddVarying(const char* name, SkASSERT(varying); v.fType = varying->fType; - v.fPrecision = precision; + v.fPrecision = (kDefault_GrSLPrecision == precision) ? kMedium_GrSLPrecision : precision; v.fIsFlat = flat; fProgramBuilder->nameVariable(&v.fVsOut, 'v', name); v.fVisibility = kNone_GrShaderFlags; @@ -72,16 +68,16 @@ void GrGLSLVaryingHandler::emitAttributes(const GrGeometryProcessor& gp) { const GrGeometryProcessor::Attribute& attr = gp.getAttrib(i); this->addAttribute(GrShaderVar(attr.fName, GrVertexAttribTypeToSLType(attr.fType), - GrShaderVar::kAttribute_TypeModifier, + GrShaderVar::kIn_TypeModifier, GrShaderVar::kNonArray, attr.fPrecision)); } } void GrGLSLVaryingHandler::addAttribute(const GrShaderVar& var) { - SkASSERT(GrShaderVar::kAttribute_TypeModifier == var.getTypeModifier()); + SkASSERT(GrShaderVar::kIn_TypeModifier == var.getTypeModifier()); for (int j = 0; j < fVertexInputs.count(); ++j) { - const GrGLSLShaderVar& attr = fVertexInputs[j]; + const GrShaderVar& attr = fVertexInputs[j]; // if attribute already added, don't add it again if (attr.getName().equals(var.getName())) { return; @@ -91,7 +87,7 @@ void GrGLSLVaryingHandler::addAttribute(const GrShaderVar& var) { } void GrGLSLVaryingHandler::setNoPerspective() { - const GrGLSLCaps& caps = *fProgramBuilder->glslCaps(); + const GrShaderCaps& caps = *fProgramBuilder->shaderCaps(); if (!caps.noperspectiveInterpolationSupport()) { return; } @@ -111,23 +107,23 @@ void GrGLSLVaryingHandler::finalize() { const VaryingInfo& v = this->fVaryings[i]; const char* modifier = v.fIsFlat ? "flat" : fDefaultInterpolationModifier; if (v.fVisibility & kVertex_GrShaderFlag) { - fVertexOutputs.push_back().set(v.fType, GrShaderVar::kVaryingOut_TypeModifier, v.fVsOut, + fVertexOutputs.push_back().set(v.fType, v.fVsOut, GrShaderVar::kOut_TypeModifier, v.fPrecision, nullptr, modifier); if (v.fVisibility & kGeometry_GrShaderFlag) { - fGeomInputs.push_back().set(v.fType, GrShaderVar::kVaryingIn_TypeModifier, v.fVsOut, - GrShaderVar::kUnsizedArray, v.fPrecision, nullptr, + fGeomInputs.push_back().set(v.fType, v.fVsOut, GrShaderVar::kUnsizedArray, + GrShaderVar::kIn_TypeModifier, v.fPrecision, nullptr, modifier); } } if (v.fVisibility & kFragment_GrShaderFlag) { const char* fsIn = v.fVsOut.c_str(); if (v.fVisibility & kGeometry_GrShaderFlag) { - fGeomOutputs.push_back().set(v.fType, GrGLSLShaderVar::kVaryingOut_TypeModifier, - v.fGsOut, v.fPrecision, nullptr, modifier); + fGeomOutputs.push_back().set(v.fType, v.fGsOut, GrShaderVar::kOut_TypeModifier, + v.fPrecision, nullptr, modifier); fsIn = v.fGsOut.c_str(); } - fFragInputs.push_back().set(v.fType, GrShaderVar::kVaryingIn_TypeModifier, fsIn, - v.fPrecision, nullptr, modifier); + fFragInputs.push_back().set(v.fType, fsIn, GrShaderVar::kIn_TypeModifier, v.fPrecision, + nullptr, modifier); } } this->onFinalize(); @@ -135,7 +131,7 @@ void GrGLSLVaryingHandler::finalize() { void GrGLSLVaryingHandler::appendDecls(const VarArray& vars, SkString* out) const { for (int i = 0; i < vars.count(); ++i) { - vars[i].appendDecl(fProgramBuilder->glslCaps(), out); + vars[i].appendDecl(fProgramBuilder->shaderCaps(), out); out->append(";"); } } @@ -152,7 +148,7 @@ void GrGLSLVaryingHandler::getGeomDecls(SkString* inputDecls, SkString* outputDe void GrGLSLVaryingHandler::getFragDecls(SkString* inputDecls, SkString* outputDecls) const { // We should not have any outputs in the fragment shader when using version 1.10 - SkASSERT(k110_GrGLSLGeneration != fProgramBuilder->glslCaps()->generation() || + SkASSERT(k110_GrGLSLGeneration != fProgramBuilder->shaderCaps()->generation() || fFragOutputs.empty()); this->appendDecls(fFragInputs, inputDecls); this->appendDecls(fFragOutputs, outputDecls); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLVarying.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLVarying.h index 5867361ce4a4..e9378a8887f1 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLVarying.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLVarying.h @@ -10,9 +10,9 @@ #include "GrAllocator.h" #include "GrGeometryProcessor.h" +#include "GrShaderVar.h" #include "GrTypesPriv.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLShaderVar.h" class GrGLSLProgramBuilder; @@ -152,7 +152,7 @@ protected: }; typedef GrTAllocator VaryingList; - typedef GrTAllocator VarArray; + typedef GrTAllocator VarArray; typedef GrGLSLProgramDataManager::VaryingHandle VaryingHandle; VaryingList fVaryings; diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp index f8302b38fea8..627b11d685c0 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp @@ -11,18 +11,13 @@ #include "glsl/GrGLSLVarying.h" GrGLSLVertexBuilder::GrGLSLVertexBuilder(GrGLSLProgramBuilder* program) - : INHERITED(program) - , fRtAdjustName(nullptr) { + : INHERITED(program) { } -void GrGLSLVertexBuilder::transformToNormalizedDeviceSpace(const GrShaderVar& posVar) { - SkASSERT(!fRtAdjustName); - +void GrGLSLVertexBuilder::transformToNormalizedDeviceSpace(const GrShaderVar& posVar, + const char* rtAdjustName) { // setup RT Uniform - fProgramBuilder->addRTAdjustmentUniform(kHigh_GrSLPrecision, - fProgramBuilder->rtAdjustment(), - &fRtAdjustName); - if (this->getProgramBuilder()->desc().header().fSnapVerticesToPixelCenters) { + if (this->getProgramBuilder()->desc()->header().fSnapVerticesToPixelCenters) { if (kVec3f_GrSLType == posVar.getType()) { const char* p = posVar.c_str(); this->codeAppendf("{vec2 _posTmp = vec2(%s.x/%s.z, %s.y/%s.z);", p, p, p, p); @@ -33,21 +28,21 @@ void GrGLSLVertexBuilder::transformToNormalizedDeviceSpace(const GrShaderVar& po this->codeAppendf("_posTmp = floor(_posTmp) + vec2(0.5, 0.5);" "gl_Position = vec4(_posTmp.x * %s.x + %s.y," "_posTmp.y * %s.z + %s.w, 0, 1);}", - fRtAdjustName, fRtAdjustName, fRtAdjustName, fRtAdjustName); + rtAdjustName, rtAdjustName, rtAdjustName, rtAdjustName); } else if (kVec3f_GrSLType == posVar.getType()) { this->codeAppendf("gl_Position = vec4(dot(%s.xz, %s.xy), dot(%s.yz, %s.zw), 0, %s.z);", - posVar.c_str(), fRtAdjustName, - posVar.c_str(), fRtAdjustName, + posVar.c_str(), rtAdjustName, + posVar.c_str(), rtAdjustName, posVar.c_str()); } else { SkASSERT(kVec2f_GrSLType == posVar.getType()); this->codeAppendf("gl_Position = vec4(%s.x * %s.x + %s.y, %s.y * %s.z + %s.w, 0, 1);", - posVar.c_str(), fRtAdjustName, fRtAdjustName, - posVar.c_str(), fRtAdjustName, fRtAdjustName); + posVar.c_str(), rtAdjustName, rtAdjustName, + posVar.c_str(), rtAdjustName, rtAdjustName); } // We could have the GrGeometryProcessor do this, but its just easier to have it performed // here. If we ever need to set variable pointsize, then we can reinvestigate. - if (this->getProgramBuilder()->desc().header().fHasPointSize) { + if (this->getProgramBuilder()->desc()->header().fHasPointSize) { this->codeAppend("gl_PointSize = 1.0;"); } } diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.h index af8d10c2cb8d..5d7156505674 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.h @@ -20,12 +20,10 @@ class GrGLSLVertexBuilder : public GrGLSLShaderBuilder { public: GrGLSLVertexBuilder(GrGLSLProgramBuilder* program); - void transformToNormalizedDeviceSpace(const GrShaderVar& posVar); + void transformToNormalizedDeviceSpace(const GrShaderVar& posVar, const char* rtAdjustName); private: void onFinalize() override; - const char* fRtAdjustName; - friend class GrGLProgramBuilder; typedef GrGLSLShaderBuilder INHERITED; diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.cpp index 0f7a3db718fa..545a9fd1f712 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.cpp @@ -7,6 +7,7 @@ #include "glsl/GrGLSLXferProcessor.h" +#include "GrShaderCaps.h" #include "GrXferProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" @@ -24,8 +25,8 @@ void GrGLSLXferProcessor::emitCode(const EmitArgs& args) { bool needsLocalOutColor = false; - if (args.fXP.getDstTexture()) { - bool topDown = kTopLeft_GrSurfaceOrigin == args.fXP.getDstTexture()->origin(); + if (args.fDstTextureSamplerHandle.isValid()) { + bool flipY = kBottomLeft_GrSurfaceOrigin == args.fDstTextureOrigin; if (args.fInputCoverage) { // We don't think any shaders actually output negative coverage, but just as a safety @@ -48,21 +49,21 @@ void GrGLSLXferProcessor::emitCode(const EmitArgs& args) { kDefault_GrSLPrecision, "DstTextureCoordScale", &dstCoordScaleName); - const char* fragPos = fragBuilder->fragmentPosition(); fragBuilder->codeAppend("// Read color from copy of the destination.\n"); - fragBuilder->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;", - fragPos, dstTopLeftName, dstCoordScaleName); + fragBuilder->codeAppendf("vec2 _dstTexCoord = (sk_FragCoord.xy - %s) * %s;", + dstTopLeftName, dstCoordScaleName); - if (!topDown) { + if (flipY) { fragBuilder->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;"); } fragBuilder->codeAppendf("vec4 %s = ", dstColor); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], "_dstTexCoord", kVec2f_GrSLType); + fragBuilder->appendTextureLookup(args.fDstTextureSamplerHandle, "_dstTexCoord", + kVec2f_GrSLType); fragBuilder->codeAppend(";"); } else { - needsLocalOutColor = args.fGLSLCaps->requiresLocalOutputColorForFBFetch(); + needsLocalOutColor = args.fShaderCaps->requiresLocalOutputColorForFBFetch(); } const char* outColor = "_localColorOut"; @@ -85,13 +86,13 @@ void GrGLSLXferProcessor::emitCode(const EmitArgs& args) { } } -void GrGLSLXferProcessor::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) { - if (xp.getDstTexture()) { +void GrGLSLXferProcessor::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp, + const GrTexture* dstTexture, const SkIPoint& dstTextureOffset) { + if (dstTexture) { if (fDstTopLeftUni.isValid()) { - pdm.set2f(fDstTopLeftUni, static_cast(xp.dstTextureOffset().fX), - static_cast(xp.dstTextureOffset().fY)); - pdm.set2f(fDstScaleUni, 1.f / xp.getDstTexture()->width(), - 1.f / xp.getDstTexture()->height()); + pdm.set2f(fDstTopLeftUni, static_cast(dstTextureOffset.fX), + static_cast(dstTextureOffset.fY)); + pdm.set2f(fDstScaleUni, 1.f / dstTexture->width(), 1.f / dstTexture->height()); } else { SkASSERT(!fDstScaleUni.isValid()); } diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.h index f4a8ebdfa029..791bb068e201 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.h @@ -8,57 +8,55 @@ #ifndef GrGLSLXferProcessor_DEFINED #define GrGLSLXferProcessor_DEFINED +#include "SkPoint.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLSampler.h" +#include "glsl/GrGLSLUniformHandler.h" class GrXferProcessor; -class GrGLSLCaps; -class GrGLSLUniformHandler; class GrGLSLXPBuilder; class GrGLSLXPFragmentBuilder; +class GrShaderCaps; +class GrTexture; class GrGLSLXferProcessor { public: GrGLSLXferProcessor() {} virtual ~GrGLSLXferProcessor() {} - typedef GrGLSLProgramDataManager::UniformHandle SamplerHandle; + using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; + using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle; struct EmitArgs { EmitArgs(GrGLSLXPFragmentBuilder* fragBuilder, GrGLSLUniformHandler* uniformHandler, - const GrGLSLCaps* caps, + const GrShaderCaps* caps, const GrXferProcessor& xp, const char* inputColor, const char* inputCoverage, const char* outputPrimary, const char* outputSecondary, - const SamplerHandle* texSamplers, - const SamplerHandle* bufferSamplers, - const bool usePLSDstRead) - : fXPFragBuilder(fragBuilder) - , fUniformHandler(uniformHandler) - , fGLSLCaps(caps) - , fXP(xp) - , fInputColor(inputColor) - , fInputCoverage(inputCoverage) - , fOutputPrimary(outputPrimary) - , fOutputSecondary(outputSecondary) - , fTexSamplers(texSamplers) - , fBufferSamplers(bufferSamplers) - , fUsePLSDstRead(usePLSDstRead) {} - + const SamplerHandle dstTextureSamplerHandle, + GrSurfaceOrigin dstTextureOrigin) + : fXPFragBuilder(fragBuilder) + , fUniformHandler(uniformHandler) + , fShaderCaps(caps) + , fXP(xp) + , fInputColor(inputColor) + , fInputCoverage(inputCoverage) + , fOutputPrimary(outputPrimary) + , fOutputSecondary(outputSecondary) + , fDstTextureSamplerHandle(dstTextureSamplerHandle) + , fDstTextureOrigin(dstTextureOrigin) {} GrGLSLXPFragmentBuilder* fXPFragBuilder; GrGLSLUniformHandler* fUniformHandler; - const GrGLSLCaps* fGLSLCaps; + const GrShaderCaps* fShaderCaps; const GrXferProcessor& fXP; const char* fInputColor; const char* fInputCoverage; const char* fOutputPrimary; const char* fOutputSecondary; - const SamplerHandle* fTexSamplers; - const SamplerHandle* fBufferSamplers; - bool fUsePLSDstRead; + const SamplerHandle fDstTextureSamplerHandle; + GrSurfaceOrigin fDstTextureOrigin; }; /** * This is similar to emitCode() in the base class, except it takes a full shader builder. @@ -73,7 +71,8 @@ public: to have an identical processor key as the one that created this GrGLSLXferProcessor. This function calls onSetData on the subclass of GrGLSLXferProcessor */ - void setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp); + void setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp, + const GrTexture* dstTexture, const SkIPoint& dstTextureOffset); protected: static void DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder, diff --git a/gfx/skia/skia/src/gpu/instanced/GLInstancedRendering.cpp b/gfx/skia/skia/src/gpu/instanced/GLInstancedRendering.cpp index dabfe4e02d45..bfdb9601f924 100644 --- a/gfx/skia/skia/src/gpu/instanced/GLInstancedRendering.cpp +++ b/gfx/skia/skia/src/gpu/instanced/GLInstancedRendering.cpp @@ -15,11 +15,12 @@ namespace gr_instanced { -class GLInstancedRendering::GLBatch : public InstancedRendering::Batch { +class GLInstancedRendering::GLOp final : public InstancedRendering::Op { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - GLBatch(GLInstancedRendering* instRendering) : INHERITED(ClassID(), instRendering) {} + GLOp(GLInstancedRendering* instRendering, GrPaint&& paint) + : INHERITED(ClassID(), std::move(paint), instRendering) {} int numGLCommands() const { return 1 + fNumChangesInGeometry; } private: @@ -28,7 +29,7 @@ private: friend class GLInstancedRendering; - typedef Batch INHERITED; + typedef Op INHERITED; }; GrCaps::InstancedSupport GLInstancedRendering::CheckSupport(const GrGLCaps& glCaps) { @@ -38,7 +39,7 @@ GrCaps::InstancedSupport GLInstancedRendering::CheckSupport(const GrGLCaps& glCa (!glCaps.drawIndirectSupport() && !glCaps.drawInstancedSupport())) { return GrCaps::InstancedSupport::kNone; } - return InstanceProcessor::CheckSupport(*glCaps.glslCaps(), glCaps); + return InstanceProcessor::CheckSupport(*glCaps.shaderCaps(), glCaps); } GLInstancedRendering::GLInstancedRendering(GrGLGpu* gpu) @@ -60,22 +61,22 @@ inline GrGLGpu* GLInstancedRendering::glGpu() const { return static_cast(this->gpu()); } -InstancedRendering::Batch* GLInstancedRendering::createBatch() { - return new GLBatch(this); +std::unique_ptr GLInstancedRendering::makeOp(GrPaint&& paint) { + return std::unique_ptr(new GLOp(this, std::move(paint))); } void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) { // Count what there is to draw. - BatchList::Iter iter; - iter.init(this->trackedBatches(), BatchList::Iter::kHead_IterStart); + OpList::Iter iter; + iter.init(this->trackedOps(), OpList::Iter::kHead_IterStart); int numGLInstances = 0; int numGLDrawCmds = 0; - while (Batch* b = iter.get()) { - GLBatch* batch = static_cast(b); + while (Op* o = iter.get()) { + GLOp* op = static_cast(o); iter.next(); - numGLInstances += batch->fNumDraws; - numGLDrawCmds += batch->numGLCommands(); + numGLInstances += op->fNumDraws; + numGLDrawCmds += op->numGLCommands(); } if (!numGLDrawCmds) { return; @@ -104,7 +105,7 @@ void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) { GL_CALL(VertexAttribIPointer((int)Attrib::kVertexAttrs, 1, GR_GL_INT, sizeof(ShapeVertex), (void*) offsetof(ShapeVertex, fAttrs))); - SkASSERT(SK_InvalidUniqueID == fInstanceAttribsBufferUniqueId); + SkASSERT(fInstanceAttribsBufferUniqueId.isInvalid()); } // Create and map instance and draw-indirect buffers. @@ -145,20 +146,20 @@ void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) { SkASSERT(!baseInstanceSupport || fDrawIndirectBuffer); SkASSERT(!fGLDrawCmdsInfo); - if (GR_GL_LOG_INSTANCED_BATCHES || !baseInstanceSupport) { + if (GR_GL_LOG_INSTANCED_OPS || !baseInstanceSupport) { fGLDrawCmdsInfo.reset(numGLDrawCmds); } - // Generate the instance and draw-indirect buffer contents based on the tracked batches. - iter.init(this->trackedBatches(), BatchList::Iter::kHead_IterStart); - while (Batch* b = iter.get()) { - GLBatch* batch = static_cast(b); + // Generate the instance and draw-indirect buffer contents based on the tracked ops. + iter.init(this->trackedOps(), OpList::Iter::kHead_IterStart); + while (Op* o = iter.get()) { + GLOp* op = static_cast(o); iter.next(); - batch->fEmulatedBaseInstance = baseInstanceSupport ? 0 : glInstancesIdx; - batch->fGLDrawCmdsIdx = glDrawCmdsIdx; + op->fEmulatedBaseInstance = baseInstanceSupport ? 0 : glInstancesIdx; + op->fGLDrawCmdsIdx = glDrawCmdsIdx; - const Batch::Draw* draw = batch->fHeadDraw; + const Op::Draw* draw = op->fHeadDraw; SkASSERT(draw); do { int instanceCount = 0; @@ -179,7 +180,7 @@ void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) { glCmd.fBaseInstance = baseInstanceSupport ? glInstancesIdx : 0; } - if (GR_GL_LOG_INSTANCED_BATCHES || !baseInstanceSupport) { + if (GR_GL_LOG_INSTANCED_OPS || !baseInstanceSupport) { GLDrawCmdInfo& cmdInfo = fGLDrawCmdsInfo[glDrawCmdsIdx]; cmdInfo.fGeometry = geometry; cmdInfo.fInstanceCount = instanceCount; @@ -200,7 +201,7 @@ void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) { } void GLInstancedRendering::onDraw(const GrPipeline& pipeline, const InstanceProcessor& instProc, - const Batch* baseBatch) { + const Op* baseOp) { if (!fDrawIndirectBuffer && !fGLDrawCmdsInfo) { return; // beginFlush was not successful. } @@ -213,14 +214,14 @@ void GLInstancedRendering::onDraw(const GrPipeline& pipeline, const InstanceProc } const GrGLCaps& glCaps = this->glGpu()->glCaps(); - const GLBatch* batch = static_cast(baseBatch); - int numCommands = batch->numGLCommands(); + const GLOp* op = static_cast(baseOp); + int numCommands = op->numGLCommands(); -#if GR_GL_LOG_INSTANCED_BATCHES +#if GR_GL_LOG_INSTANCED_OPS SkASSERT(fGLDrawCmdsInfo); - SkDebugf("Instanced batch: ["); + SkDebugf("Instanced op: ["); for (int i = 0; i < numCommands; ++i) { - int glCmdIdx = batch->fGLDrawCmdsIdx + i; + int glCmdIdx = op->fGLDrawCmdsIdx + i; SkDebugf("%s%i * %s", (i ? ", " : ""), fGLDrawCmdsInfo[glCmdIdx].fInstanceCount, InstanceProcessor::GetNameOfIndexRange(fGLDrawCmdsInfo[glCmdIdx].fGeometry)); } @@ -231,17 +232,17 @@ void GLInstancedRendering::onDraw(const GrPipeline& pipeline, const InstanceProc if (numCommands > 1 && glCaps.multiDrawIndirectSupport() && glCaps.baseInstanceSupport()) { SkASSERT(fDrawIndirectBuffer); - int glCmdsIdx = batch->fGLDrawCmdsIdx; - this->flushInstanceAttribs(batch->fEmulatedBaseInstance); + int glCmdsIdx = op->fGLDrawCmdsIdx; + this->flushInstanceAttribs(op->fEmulatedBaseInstance); GL_CALL(MultiDrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE, (GrGLDrawElementsIndirectCommand*) nullptr + glCmdsIdx, numCommands, 0)); return; } - int emulatedBaseInstance = batch->fEmulatedBaseInstance; + int emulatedBaseInstance = op->fEmulatedBaseInstance; for (int i = 0; i < numCommands; ++i) { - int glCmdIdx = batch->fGLDrawCmdsIdx + i; + int glCmdIdx = op->fGLDrawCmdsIdx + i; this->flushInstanceAttribs(emulatedBaseInstance); if (fDrawIndirectBuffer) { GL_CALL(DrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE, @@ -318,7 +319,7 @@ void GLInstancedRendering::onResetGpuResources(ResetType resetType) { fVertexArrayID = 0; fInstanceBuffer.reset(); fDrawIndirectBuffer.reset(); - fInstanceAttribsBufferUniqueId = SK_InvalidUniqueID; + fInstanceAttribsBufferUniqueId.makeInvalid(); } } diff --git a/gfx/skia/skia/src/gpu/instanced/GLInstancedRendering.h b/gfx/skia/skia/src/gpu/instanced/GLInstancedRendering.h index ce1638c7fc5b..d1affba2bd5d 100644 --- a/gfx/skia/skia/src/gpu/instanced/GLInstancedRendering.h +++ b/gfx/skia/skia/src/gpu/instanced/GLInstancedRendering.h @@ -15,7 +15,7 @@ class GrGLCaps; class GrGLGpu; -#define GR_GL_LOG_INSTANCED_BATCHES 0 +#define GR_GL_LOG_INSTANCED_OPS 0 namespace gr_instanced { @@ -33,10 +33,10 @@ private: GrGLGpu* glGpu() const; - Batch* createBatch() override; + std::unique_ptr makeOp(GrPaint&& paint) override; void onBeginFlush(GrResourceProvider*) override; - void onDraw(const GrPipeline&, const InstanceProcessor&, const Batch*) override; + void onDraw(const GrPipeline&, const InstanceProcessor&, const Op*) override; void onEndFlush() override; void onResetGpuResources(ResetType) override; @@ -48,13 +48,13 @@ private: }; GrGLuint fVertexArrayID; - SkAutoTUnref fInstanceBuffer; - SkAutoTUnref fDrawIndirectBuffer; + sk_sp fInstanceBuffer; + sk_sp fDrawIndirectBuffer; SkAutoSTMalloc<1024, GLDrawCmdInfo> fGLDrawCmdsInfo; - uint32_t fInstanceAttribsBufferUniqueId; + GrGpuResource::UniqueID fInstanceAttribsBufferUniqueId; int fInstanceAttribsBaseInstance; - class GLBatch; + class GLOp; friend class ::GrGLCaps; // For CheckSupport. diff --git a/gfx/skia/skia/src/gpu/instanced/InstanceProcessor.cpp b/gfx/skia/skia/src/gpu/instanced/InstanceProcessor.cpp index 480155b683c8..efbf8251c48e 100644 --- a/gfx/skia/skia/src/gpu/instanced/InstanceProcessor.cpp +++ b/gfx/skia/skia/src/gpu/instanced/InstanceProcessor.cpp @@ -11,6 +11,7 @@ #include "GrRenderTargetPriv.h" #include "GrResourceCache.h" #include "GrResourceProvider.h" +#include "GrShaderCaps.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramBuilder.h" @@ -18,30 +19,29 @@ namespace gr_instanced { -GrCaps::InstancedSupport InstanceProcessor::CheckSupport(const GrGLSLCaps& glslCaps, +GrCaps::InstancedSupport InstanceProcessor::CheckSupport(const GrShaderCaps& shaderCaps, const GrCaps& caps) { - if (!glslCaps.canUseAnyFunctionInShader() || - !glslCaps.flatInterpolationSupport() || - !glslCaps.integerSupport() || - 0 == glslCaps.maxVertexSamplers() || + if (!shaderCaps.canUseAnyFunctionInShader() || + !shaderCaps.flatInterpolationSupport() || + !shaderCaps.integerSupport() || + 0 == shaderCaps.maxVertexSamplers() || !caps.shaderCaps()->texelBufferSupport() || caps.maxVertexAttributes() < kNumAttribs) { return GrCaps::InstancedSupport::kNone; } if (!caps.sampleLocationsSupport() || - !glslCaps.sampleVariablesSupport() || - !glslCaps.shaderDerivativeSupport()) { + !shaderCaps.sampleVariablesSupport() || + !shaderCaps.shaderDerivativeSupport()) { return GrCaps::InstancedSupport::kBasic; } if (0 == caps.maxRasterSamples() || - !glslCaps.sampleMaskOverrideCoverageSupport()) { + !shaderCaps.sampleMaskOverrideCoverageSupport()) { return GrCaps::InstancedSupport::kMultisampled; } return GrCaps::InstancedSupport::kMixedSampled; } -InstanceProcessor::InstanceProcessor(BatchInfo batchInfo, GrBuffer* paramsBuffer) - : fBatchInfo(batchInfo) { +InstanceProcessor::InstanceProcessor(OpInfo opInfo, GrBuffer* paramsBuffer) : fOpInfo(opInfo) { this->initClassID(); this->addVertexAttrib("shapeCoords", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision); @@ -61,15 +61,14 @@ InstanceProcessor::InstanceProcessor(BatchInfo batchInfo, GrBuffer* paramsBuffer GR_STATIC_ASSERT(6 == (int)Attrib::kLocalRect); GR_STATIC_ASSERT(7 == kNumAttribs); - if (fBatchInfo.fHasParams) { + if (fOpInfo.fHasParams) { SkASSERT(paramsBuffer); fParamsAccess.reset(kRGBA_float_GrPixelConfig, paramsBuffer, kVertex_GrShaderFlag); this->addBufferAccess(&fParamsAccess); } - if (fBatchInfo.fAntialiasMode >= AntialiasMode::kMSAA) { - if (!fBatchInfo.isSimpleRects() || - AntialiasMode::kMixedSamples == fBatchInfo.fAntialiasMode) { + if (GrAATypeIsHW(fOpInfo.aaType())) { + if (!fOpInfo.isSimpleRects() || GrAAType::kMixedSamples == fOpInfo.aaType()) { this->setWillUseSampleLocations(); } } @@ -94,7 +93,7 @@ private: typedef GrGLSLGeometryProcessor INHERITED; }; -GrGLSLPrimitiveProcessor* InstanceProcessor::createGLSLInstance(const GrGLSLCaps&) const { +GrGLSLPrimitiveProcessor* InstanceProcessor::createGLSLInstance(const GrShaderCaps&) const { return new GLSLInstanceProcessor(); } @@ -107,22 +106,35 @@ public: void initParams(const SamplerHandle paramsBuffer) { fParamsBuffer = paramsBuffer; - fVertexBuilder->definef("PARAMS_IDX_MASK", "0x%xu", kParamsIdx_InfoMask); - fVertexBuilder->appendPrecisionModifier(kHigh_GrSLPrecision); - fVertexBuilder->codeAppendf("int paramsIdx = int(%s & PARAMS_IDX_MASK);", - this->attr(Attrib::kInstanceInfo)); + fVertexBuilder->codeAppendf("highp int paramsIdx = int(%s & 0x%x);", + this->attr(Attrib::kInstanceInfo), + kParamsIdx_InfoMask); } const char* attr(Attrib attr) const { return fInstProc.getAttrib((int)attr).fName; } void fetchNextParam(GrSLType type = kVec4f_GrSLType) const { SkASSERT(fParamsBuffer.isValid()); - if (type != kVec4f_GrSLType) { - fVertexBuilder->codeAppendf("%s(", GrGLSLTypeString(type)); + switch (type) { + case kVec2f_GrSLType: // fall through + case kVec3f_GrSLType: // fall through + case kVec4f_GrSLType: + break; + default: + fVertexBuilder->codeAppendf("%s(", GrGLSLTypeString(type)); } fVertexBuilder->appendTexelFetch(fParamsBuffer, "paramsIdx++"); - if (type != kVec4f_GrSLType) { - fVertexBuilder->codeAppend(")"); + switch (type) { + case kVec2f_GrSLType: + fVertexBuilder->codeAppend(".xy"); + break; + case kVec3f_GrSLType: + fVertexBuilder->codeAppend(".xyz"); + break; + case kVec4f_GrSLType: + break; + default: + fVertexBuilder->codeAppend(")"); } } @@ -139,7 +151,7 @@ private: class GLSLInstanceProcessor::Backend { public: - static Backend* SK_WARN_UNUSED_RESULT Create(const GrPipeline&, BatchInfo, const VertexInputs&); + static Backend* SK_WARN_UNUSED_RESULT Create(const GrPipeline&, OpInfo, const VertexInputs&); virtual ~Backend() {} void init(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*); @@ -160,19 +172,19 @@ public: const char* outColor); protected: - Backend(BatchInfo batchInfo, const VertexInputs& inputs) - : fBatchInfo(batchInfo), - fInputs(inputs), - fModifiesCoverage(false), - fModifiesColor(false), - fNeedsNeighborRadii(false), - fColor(kVec4f_GrSLType), - fTriangleIsArc(kInt_GrSLType), - fArcCoords(kVec2f_GrSLType), - fInnerShapeCoords(kVec2f_GrSLType), - fInnerRRect(kVec4f_GrSLType), - fModifiedShapeCoords(nullptr) { - if (fBatchInfo.fShapeTypes & kRRect_ShapesMask) { + Backend(OpInfo opInfo, const VertexInputs& inputs) + : fOpInfo(opInfo) + , fInputs(inputs) + , fModifiesCoverage(false) + , fModifiesColor(false) + , fNeedsNeighborRadii(false) + , fColor(kVec4f_GrSLType) + , fTriangleIsArc(kInt_GrSLType) + , fArcCoords(kVec2f_GrSLType) + , fInnerShapeCoords(kVec2f_GrSLType) + , fInnerRRect(kVec4f_GrSLType) + , fModifiedShapeCoords(nullptr) { + if (fOpInfo.fShapeTypes & kRRect_ShapesMask) { fModifiedShapeCoords = "adjustedShapeCoords"; } } @@ -191,17 +203,17 @@ protected: void setupNinePatchRadii(GrGLSLVertexBuilder*); void setupComplexRadii(GrGLSLVertexBuilder*); - const BatchInfo fBatchInfo; - const VertexInputs& fInputs; - bool fModifiesCoverage; - bool fModifiesColor; - bool fNeedsNeighborRadii; - GrGLSLVertToFrag fColor; - GrGLSLVertToFrag fTriangleIsArc; - GrGLSLVertToFrag fArcCoords; - GrGLSLVertToFrag fInnerShapeCoords; - GrGLSLVertToFrag fInnerRRect; - const char* fModifiedShapeCoords; + const OpInfo fOpInfo; + const VertexInputs& fInputs; + bool fModifiesCoverage; + bool fModifiesColor; + bool fNeedsNeighborRadii; + GrGLSLVertToFrag fColor; + GrGLSLVertToFrag fTriangleIsArc; + GrGLSLVertToFrag fArcCoords; + GrGLSLVertToFrag fInnerShapeCoords; + GrGLSLVertToFrag fInnerRRect; + const char* fModifiedShapeCoords; }; void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { @@ -215,19 +227,19 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { varyingHandler->emitAttributes(ip); VertexInputs inputs(ip, v); - if (ip.batchInfo().fHasParams) { + if (ip.opInfo().fHasParams) { SkASSERT(1 == ip.numBuffers()); inputs.initParams(args.fBufferSamplers[0]); } - if (!ip.batchInfo().fHasPerspective) { + if (!ip.opInfo().fHasPerspective) { v->codeAppendf("mat2x3 shapeMatrix = mat2x3(%s, %s);", inputs.attr(Attrib::kShapeMatrixX), inputs.attr(Attrib::kShapeMatrixY)); } else { - v->definef("PERSPECTIVE_FLAG", "0x%xu", kPerspective_InfoFlag); + v->defineConstantf("int", "PERSPECTIVE_FLAG", "0x%x", kPerspective_InfoFlag); v->codeAppendf("mat3 shapeMatrix = mat3(%s, %s, vec3(0, 0, 1));", inputs.attr(Attrib::kShapeMatrixX), inputs.attr(Attrib::kShapeMatrixY)); - v->codeAppendf("if (0u != (%s & PERSPECTIVE_FLAG)) {", + v->codeAppendf("if (0 != (%s & PERSPECTIVE_FLAG)) {", inputs.attr(Attrib::kInstanceInfo)); v->codeAppend ( "shapeMatrix[2] = "); inputs.fetchNextParam(kVec3f_GrSLType); @@ -235,36 +247,36 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { v->codeAppend ("}"); } - bool hasSingleShapeType = SkIsPow2(ip.batchInfo().fShapeTypes); + bool hasSingleShapeType = SkIsPow2(ip.opInfo().fShapeTypes); if (!hasSingleShapeType) { - v->define("SHAPE_TYPE_BIT", kShapeType_InfoBit); + v->defineConstant("SHAPE_TYPE_BIT", kShapeType_InfoBit); v->codeAppendf("uint shapeType = %s >> SHAPE_TYPE_BIT;", inputs.attr(Attrib::kInstanceInfo)); } - SkAutoTDelete backend(Backend::Create(pipeline, ip.batchInfo(), inputs)); + std::unique_ptr backend(Backend::Create(pipeline, ip.opInfo(), inputs)); backend->init(varyingHandler, v); int usedShapeDefinitions = 0; - if (hasSingleShapeType || !(ip.batchInfo().fShapeTypes & ~kRRect_ShapesMask)) { - if (kRect_ShapeFlag == ip.batchInfo().fShapeTypes) { + if (hasSingleShapeType || !(ip.opInfo().fShapeTypes & ~kRRect_ShapesMask)) { + if (kRect_ShapeFlag == ip.opInfo().fShapeTypes) { backend->setupRect(v); - } else if (kOval_ShapeFlag == ip.batchInfo().fShapeTypes) { + } else if (kOval_ShapeFlag == ip.opInfo().fShapeTypes) { backend->setupOval(v); } else { backend->setupRRect(v, &usedShapeDefinitions); } } else { - if (ip.batchInfo().fShapeTypes & kRRect_ShapesMask) { + if (ip.opInfo().fShapeTypes & kRRect_ShapesMask) { v->codeAppend ("if (shapeType >= SIMPLE_R_RECT_SHAPE_TYPE) {"); backend->setupRRect(v, &usedShapeDefinitions); v->codeAppend ("}"); usedShapeDefinitions |= kSimpleRRect_ShapeFlag; } - if (ip.batchInfo().fShapeTypes & kOval_ShapeFlag) { - if (ip.batchInfo().fShapeTypes & kRect_ShapeFlag) { - if (ip.batchInfo().fShapeTypes & kRRect_ShapesMask) { + if (ip.opInfo().fShapeTypes & kOval_ShapeFlag) { + if (ip.opInfo().fShapeTypes & kRect_ShapeFlag) { + if (ip.opInfo().fShapeTypes & kRRect_ShapesMask) { v->codeAppend ("else "); } v->codeAppend ("if (OVAL_SHAPE_TYPE == shapeType) {"); @@ -275,18 +287,18 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { backend->setupOval(v); v->codeAppend ("}"); } - if (ip.batchInfo().fShapeTypes & kRect_ShapeFlag) { + if (ip.opInfo().fShapeTypes & kRect_ShapeFlag) { v->codeAppend ("else {"); backend->setupRect(v); v->codeAppend ("}"); } } - if (ip.batchInfo().fInnerShapeTypes) { - bool hasSingleInnerShapeType = SkIsPow2(ip.batchInfo().fInnerShapeTypes); + if (ip.opInfo().fInnerShapeTypes) { + bool hasSingleInnerShapeType = SkIsPow2(ip.opInfo().fInnerShapeTypes); if (!hasSingleInnerShapeType) { - v->definef("INNER_SHAPE_TYPE_MASK", "0x%xu", kInnerShapeType_InfoMask); - v->define("INNER_SHAPE_TYPE_BIT", kInnerShapeType_InfoBit); + v->defineConstantf("int", "INNER_SHAPE_TYPE_MASK", "0x%x", kInnerShapeType_InfoMask); + v->defineConstant("INNER_SHAPE_TYPE_BIT", kInnerShapeType_InfoBit); v->codeAppendf("uint innerShapeType = ((%s & INNER_SHAPE_TYPE_MASK) >> " "INNER_SHAPE_TYPE_BIT);", inputs.attr(Attrib::kInstanceInfo)); @@ -306,27 +318,27 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { backend->initInnerShape(varyingHandler, v); - SkASSERT(0 == (ip.batchInfo().fInnerShapeTypes & kRRect_ShapesMask) || - kSimpleRRect_ShapeFlag == (ip.batchInfo().fInnerShapeTypes & kRRect_ShapesMask)); + SkASSERT(0 == (ip.opInfo().fInnerShapeTypes & kRRect_ShapesMask) || + kSimpleRRect_ShapeFlag == (ip.opInfo().fInnerShapeTypes & kRRect_ShapesMask)); if (hasSingleInnerShapeType) { - if (kRect_ShapeFlag == ip.batchInfo().fInnerShapeTypes) { + if (kRect_ShapeFlag == ip.opInfo().fInnerShapeTypes) { backend->setupInnerRect(v); - } else if (kOval_ShapeFlag == ip.batchInfo().fInnerShapeTypes) { + } else if (kOval_ShapeFlag == ip.opInfo().fInnerShapeTypes) { backend->setupInnerOval(v); } else { backend->setupInnerSimpleRRect(v); } } else { - if (ip.batchInfo().fInnerShapeTypes & kSimpleRRect_ShapeFlag) { + if (ip.opInfo().fInnerShapeTypes & kSimpleRRect_ShapeFlag) { v->codeAppend ("if (SIMPLE_R_RECT_SHAPE_TYPE == innerShapeType) {"); backend->setupInnerSimpleRRect(v); v->codeAppend("}"); usedShapeDefinitions |= kSimpleRRect_ShapeFlag; } - if (ip.batchInfo().fInnerShapeTypes & kOval_ShapeFlag) { - if (ip.batchInfo().fInnerShapeTypes & kRect_ShapeFlag) { - if (ip.batchInfo().fInnerShapeTypes & kSimpleRRect_ShapeFlag) { + if (ip.opInfo().fInnerShapeTypes & kOval_ShapeFlag) { + if (ip.opInfo().fInnerShapeTypes & kRect_ShapeFlag) { + if (ip.opInfo().fInnerShapeTypes & kSimpleRRect_ShapeFlag) { v->codeAppend ("else "); } v->codeAppend ("if (OVAL_SHAPE_TYPE == innerShapeType) {"); @@ -337,7 +349,7 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { backend->setupInnerOval(v); v->codeAppend("}"); } - if (ip.batchInfo().fInnerShapeTypes & kRect_ShapeFlag) { + if (ip.opInfo().fInnerShapeTypes & kRect_ShapeFlag) { v->codeAppend("else {"); backend->setupInnerRect(v); v->codeAppend("}"); @@ -346,31 +358,30 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { } if (usedShapeDefinitions & kOval_ShapeFlag) { - v->definef("OVAL_SHAPE_TYPE", "%du", (int)ShapeType::kOval); + v->defineConstant("OVAL_SHAPE_TYPE", (int)ShapeType::kOval); } if (usedShapeDefinitions & kSimpleRRect_ShapeFlag) { - v->definef("SIMPLE_R_RECT_SHAPE_TYPE", "%du", (int)ShapeType::kSimpleRRect); + v->defineConstant("SIMPLE_R_RECT_SHAPE_TYPE", (int)ShapeType::kSimpleRRect); } if (usedShapeDefinitions & kNinePatch_ShapeFlag) { - v->definef("NINE_PATCH_SHAPE_TYPE", "%du", (int)ShapeType::kNinePatch); + v->defineConstant("NINE_PATCH_SHAPE_TYPE", (int)ShapeType::kNinePatch); } SkASSERT(!(usedShapeDefinitions & (kRect_ShapeFlag | kComplexRRect_ShapeFlag))); - backend->emitCode(v, f, pipeline.ignoresCoverage() ? nullptr : args.fOutputCoverage, - args.fOutputColor); + backend->emitCode(v, f, args.fOutputCoverage, args.fOutputColor); const char* localCoords = nullptr; - if (ip.batchInfo().fUsesLocalCoords) { + if (ip.opInfo().fUsesLocalCoords) { localCoords = "localCoords"; v->codeAppendf("vec2 t = 0.5 * (%s + vec2(1));", backend->outShapeCoords()); v->codeAppendf("vec2 localCoords = (1.0 - t) * %s.xy + t * %s.zw;", inputs.attr(Attrib::kLocalRect), inputs.attr(Attrib::kLocalRect)); } - if (ip.batchInfo().fHasLocalMatrix && ip.batchInfo().fHasParams) { - v->definef("LOCAL_MATRIX_FLAG", "0x%xu", kLocalMatrix_InfoFlag); - v->codeAppendf("if (0u != (%s & LOCAL_MATRIX_FLAG)) {", + if (ip.opInfo().fHasLocalMatrix && ip.opInfo().fHasParams) { + v->defineConstantf("int", "LOCAL_MATRIX_FLAG", "0x%x", kLocalMatrix_InfoFlag); + v->codeAppendf("if (0 != (%s & LOCAL_MATRIX_FLAG)) {", inputs.attr(Attrib::kInstanceInfo)); - if (!ip.batchInfo().fUsesLocalCoords) { + if (!ip.opInfo().fUsesLocalCoords) { inputs.skipParams(2); } else { v->codeAppendf( "mat2x3 localMatrix;"); @@ -385,7 +396,7 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { v->codeAppend("}"); } - GrSLType positionType = ip.batchInfo().fHasPerspective ? kVec3f_GrSLType : kVec2f_GrSLType; + GrSLType positionType = ip.opInfo().fHasPerspective ? kVec3f_GrSLType : kVec2f_GrSLType; v->codeAppendf("%s deviceCoords = vec3(%s, 1) * shapeMatrix;", GrGLSLTypeString(positionType), backend->outShapeCoords()); gpArgs->fPositionVar.set(positionType, "deviceCoords"); @@ -418,7 +429,7 @@ void GLSLInstanceProcessor::Backend::setupRRect(GrGLSLVertexBuilder* v, int* use v->codeAppend ("mat2 p = "); fInputs.fetchNextParam(kMat22f_GrSLType); v->codeAppend (";"); - uint8_t types = fBatchInfo.fShapeTypes & kRRect_ShapesMask; + uint8_t types = fOpInfo.fShapeTypes & kRRect_ShapesMask; if (0 == (types & (types - 1))) { if (kSimpleRRect_ShapeFlag == types) { this->setupSimpleRadii(v); @@ -520,7 +531,7 @@ void GLSLInstanceProcessor::Backend::adjustRRectVertices(GrGLSLVertexBuilder* v) void GLSLInstanceProcessor::Backend::initInnerShape(GrGLSLVaryingHandler* varyingHandler, GrGLSLVertexBuilder* v) { - SkASSERT(!(fBatchInfo.fInnerShapeTypes & (kNinePatch_ShapeFlag | kComplexRRect_ShapeFlag))); + SkASSERT(!(fOpInfo.fInnerShapeTypes & (kNinePatch_ShapeFlag | kComplexRRect_ShapeFlag))); this->onInitInnerShape(varyingHandler, v); @@ -556,10 +567,9 @@ void GLSLInstanceProcessor::Backend::emitCode(GrGLSLVertexBuilder* v, GrGLSLPPFr class GLSLInstanceProcessor::BackendNonAA : public Backend { public: - BackendNonAA(BatchInfo batchInfo, const VertexInputs& inputs) - : INHERITED(batchInfo, inputs) { - if (fBatchInfo.fCannotDiscard && !fBatchInfo.isSimpleRects()) { - fModifiesColor = !fBatchInfo.fCannotTweakAlphaForCoverage; + BackendNonAA(OpInfo opInfo, const VertexInputs& inputs) : INHERITED(opInfo, inputs) { + if (fOpInfo.fCannotDiscard && !fOpInfo.isSimpleRects()) { + fModifiesColor = !fOpInfo.fCannotTweakAlphaForCoverage; fModifiesCoverage = !fModifiesColor; } } @@ -582,7 +592,7 @@ private: void GLSLInstanceProcessor::BackendNonAA::onInit(GrGLSLVaryingHandler* varyingHandler, GrGLSLVertexBuilder*) { - if (kRect_ShapeFlag != fBatchInfo.fShapeTypes) { + if (kRect_ShapeFlag != fOpInfo.fShapeTypes) { varyingHandler->addFlatVarying("triangleIsArc", &fTriangleIsArc, kLow_GrSLPrecision); varyingHandler->addVarying("arcCoords", &fArcCoords, kMedium_GrSLPrecision); } @@ -604,8 +614,8 @@ void GLSLInstanceProcessor::BackendNonAA::setupOval(GrGLSLVertexBuilder* v) { void GLSLInstanceProcessor::BackendNonAA::onInitInnerShape(GrGLSLVaryingHandler* varyingHandler, GrGLSLVertexBuilder*) { varyingHandler->addVarying("innerShapeCoords", &fInnerShapeCoords, kMedium_GrSLPrecision); - if (kRect_ShapeFlag != fBatchInfo.fInnerShapeTypes && - kOval_ShapeFlag != fBatchInfo.fInnerShapeTypes) { + if (kRect_ShapeFlag != fOpInfo.fInnerShapeTypes && + kOval_ShapeFlag != fOpInfo.fInnerShapeTypes) { varyingHandler->addFlatVarying("innerRRect", &fInnerRRect, kMedium_GrSLPrecision); } } @@ -631,15 +641,13 @@ void GLSLInstanceProcessor::BackendNonAA::onEmitCode(GrGLSLVertexBuilder*, const char* outCoverage, const char* outColor) { const char* dropFragment = nullptr; - if (!fBatchInfo.fCannotDiscard) { + if (!fOpInfo.fCannotDiscard) { dropFragment = "discard"; } else if (fModifiesCoverage) { - f->appendPrecisionModifier(kLow_GrSLPrecision); - f->codeAppend ("float covered = 1.0;"); + f->codeAppend ("lowp float covered = 1.0;"); dropFragment = "covered = 0.0"; } else if (fModifiesColor) { - f->appendPrecisionModifier(kLow_GrSLPrecision); - f->codeAppendf("vec4 color = %s;", fColor.fsIn()); + f->codeAppendf("lowp vec4 color = %s;", fColor.fsIn()); dropFragment = "color = vec4(0)"; } if (fTriangleIsArc.fsIn()) { @@ -647,13 +655,13 @@ void GLSLInstanceProcessor::BackendNonAA::onEmitCode(GrGLSLVertexBuilder*, f->codeAppendf("if (%s != 0 && dot(%s, %s) > 1.0) %s;", fTriangleIsArc.fsIn(), fArcCoords.fsIn(), fArcCoords.fsIn(), dropFragment); } - if (fBatchInfo.fInnerShapeTypes) { + if (fOpInfo.fInnerShapeTypes) { SkASSERT(dropFragment); f->codeAppendf("// Inner shape.\n"); - if (kRect_ShapeFlag == fBatchInfo.fInnerShapeTypes) { + if (kRect_ShapeFlag == fOpInfo.fInnerShapeTypes) { f->codeAppendf("if (all(lessThanEqual(abs(%s), vec2(1)))) %s;", fInnerShapeCoords.fsIn(), dropFragment); - } else if (kOval_ShapeFlag == fBatchInfo.fInnerShapeTypes) { + } else if (kOval_ShapeFlag == fOpInfo.fInnerShapeTypes) { f->codeAppendf("if ((dot(%s, %s) <= 1.0)) %s;", fInnerShapeCoords.fsIn(), fInnerShapeCoords.fsIn(), dropFragment); } else { @@ -683,20 +691,19 @@ void GLSLInstanceProcessor::BackendNonAA::onEmitCode(GrGLSLVertexBuilder*, class GLSLInstanceProcessor::BackendCoverage : public Backend { public: - BackendCoverage(BatchInfo batchInfo, const VertexInputs& inputs) - : INHERITED(batchInfo, inputs), - fColorTimesRectCoverage(kVec4f_GrSLType), - fRectCoverage(kFloat_GrSLType), - fEllipseCoords(kVec2f_GrSLType), - fEllipseName(kVec2f_GrSLType), - fBloatedRadius(kFloat_GrSLType), - fDistanceToInnerEdge(kVec2f_GrSLType), - fInnerShapeBloatedHalfSize(kVec2f_GrSLType), - fInnerEllipseCoords(kVec2f_GrSLType), - fInnerEllipseName(kVec2f_GrSLType) { - fShapeIsCircle = !fBatchInfo.fNonSquare && !(fBatchInfo.fShapeTypes & kRRect_ShapesMask); - fTweakAlphaForCoverage = !fBatchInfo.fCannotTweakAlphaForCoverage && - !fBatchInfo.fInnerShapeTypes; + BackendCoverage(OpInfo opInfo, const VertexInputs& inputs) + : INHERITED(opInfo, inputs) + , fColorTimesRectCoverage(kVec4f_GrSLType) + , fRectCoverage(kFloat_GrSLType) + , fEllipseCoords(kVec2f_GrSLType) + , fEllipseName(kVec2f_GrSLType) + , fBloatedRadius(kFloat_GrSLType) + , fDistanceToInnerEdge(kVec2f_GrSLType) + , fInnerShapeBloatedHalfSize(kVec2f_GrSLType) + , fInnerEllipseCoords(kVec2f_GrSLType) + , fInnerEllipseName(kVec2f_GrSLType) { + fShapeIsCircle = !fOpInfo.fNonSquare && !(fOpInfo.fShapeTypes & kRRect_ShapesMask); + fTweakAlphaForCoverage = !fOpInfo.fCannotTweakAlphaForCoverage && !fOpInfo.fInnerShapeTypes; fModifiesCoverage = !fTweakAlphaForCoverage; fModifiesColor = fTweakAlphaForCoverage; fModifiedShapeCoords = "bloatedShapeCoords"; @@ -747,11 +754,11 @@ void GLSLInstanceProcessor::BackendCoverage::onInit(GrGLSLVaryingHandler* varyin v->codeAppend ("vec2 bloat = 0.5 / shapeHalfSize;"); v->codeAppendf("bloatedShapeCoords = %s * (1.0 + bloat);", fInputs.attr(Attrib::kShapeCoords)); - if (kOval_ShapeFlag != fBatchInfo.fShapeTypes) { + if (kOval_ShapeFlag != fOpInfo.fShapeTypes) { if (fTweakAlphaForCoverage) { varyingHandler->addVarying("colorTimesRectCoverage", &fColorTimesRectCoverage, kLow_GrSLPrecision); - if (kRect_ShapeFlag == fBatchInfo.fShapeTypes) { + if (kRect_ShapeFlag == fOpInfo.fShapeTypes) { fColor = fColorTimesRectCoverage; } } else { @@ -759,7 +766,7 @@ void GLSLInstanceProcessor::BackendCoverage::onInit(GrGLSLVaryingHandler* varyin } v->codeAppend("float rectCoverage = 0.0;"); } - if (kRect_ShapeFlag != fBatchInfo.fShapeTypes) { + if (kRect_ShapeFlag != fOpInfo.fShapeTypes) { varyingHandler->addFlatVarying("triangleIsArc", &fTriangleIsArc, kLow_GrSLPrecision); if (!fShapeIsCircle) { varyingHandler->addVarying("ellipseCoords", &fEllipseCoords, kMedium_GrSLPrecision); @@ -864,7 +871,7 @@ void GLSLInstanceProcessor::BackendCoverage::onInitInnerShape(GrGLSLVaryingHandl GrGLSLVertexBuilder* v) { v->codeAppend("vec2 innerShapeHalfSize = shapeHalfSize / outer2Inner.xy;"); - if (kOval_ShapeFlag == fBatchInfo.fInnerShapeTypes) { + if (kOval_ShapeFlag == fOpInfo.fInnerShapeTypes) { varyingHandler->addVarying("innerEllipseCoords", &fInnerEllipseCoords, kMedium_GrSLPrecision); varyingHandler->addFlatVarying("innerEllipseName", &fInnerEllipseName, kHigh_GrSLPrecision); @@ -873,7 +880,7 @@ void GLSLInstanceProcessor::BackendCoverage::onInitInnerShape(GrGLSLVaryingHandl kMedium_GrSLPrecision); varyingHandler->addFlatVarying("innerShapeBloatedHalfSize", &fInnerShapeBloatedHalfSize, kMedium_GrSLPrecision); - if (kRect_ShapeFlag != fBatchInfo.fInnerShapeTypes) { + if (kRect_ShapeFlag != fOpInfo.fInnerShapeTypes) { varyingHandler->addVarying("innerShapeCoords", &fInnerShapeCoords, kMedium_GrSLPrecision); varyingHandler->addFlatVarying("innerEllipseName", &fInnerEllipseName, @@ -927,11 +934,8 @@ void GLSLInstanceProcessor::BackendCoverage::onEmitCode(GrGLSLVertexBuilder* v, v->codeAppendf("%s = rectCoverage;", fRectCoverage.vsOut()); } - SkString coverage("float coverage"); - if (f->getProgramBuilder()->glslCaps()->usesPrecisionModifiers()) { - coverage.prependf("lowp "); - } - if (fBatchInfo.fInnerShapeTypes || (!fTweakAlphaForCoverage && fTriangleIsArc.fsIn())) { + SkString coverage("lowp float coverage"); + if (fOpInfo.fInnerShapeTypes || (!fTweakAlphaForCoverage && fTriangleIsArc.fsIn())) { f->codeAppendf("%s;", coverage.c_str()); coverage = "coverage"; } @@ -942,7 +946,7 @@ void GLSLInstanceProcessor::BackendCoverage::onEmitCode(GrGLSLVertexBuilder* v, if (fShapeIsCircle) { this->emitCircle(f, coverage.c_str()); } else { - bool ellipseCoordsMayBeNegative = SkToBool(fBatchInfo.fShapeTypes & kOval_ShapeFlag); + bool ellipseCoordsMayBeNegative = SkToBool(fOpInfo.fShapeTypes & kOval_ShapeFlag); this->emitArc(f, fEllipseCoords.fsIn(), fEllipseName.fsIn(), true /*ellipseCoordsNeedClamp*/, ellipseCoordsMayBeNegative, coverage.c_str()); @@ -955,13 +959,10 @@ void GLSLInstanceProcessor::BackendCoverage::onEmitCode(GrGLSLVertexBuilder* v, this->emitRect(f, coverage.c_str(), outColor); } - if (fBatchInfo.fInnerShapeTypes) { + if (fOpInfo.fInnerShapeTypes) { f->codeAppendf("// Inner shape.\n"); - SkString innerCoverageDecl("float innerCoverage"); - if (f->getProgramBuilder()->glslCaps()->usesPrecisionModifiers()) { - innerCoverageDecl.prependf("lowp "); - } - if (kOval_ShapeFlag == fBatchInfo.fInnerShapeTypes) { + SkString innerCoverageDecl("lowp float innerCoverage"); + if (kOval_ShapeFlag == fOpInfo.fInnerShapeTypes) { this->emitArc(f, fInnerEllipseCoords.fsIn(), fInnerEllipseName.fsIn(), true /*ellipseCoordsNeedClamp*/, true /*ellipseCoordsMayBeNegative*/, innerCoverageDecl.c_str()); @@ -970,18 +971,16 @@ void GLSLInstanceProcessor::BackendCoverage::onEmitCode(GrGLSLVertexBuilder* v, fDistanceToInnerEdge.vsOut()); v->codeAppendf("%s = innerShapeHalfSize + 0.5;", fInnerShapeBloatedHalfSize.vsOut()); - if (kRect_ShapeFlag == fBatchInfo.fInnerShapeTypes) { + if (kRect_ShapeFlag == fOpInfo.fInnerShapeTypes) { this->emitInnerRect(f, innerCoverageDecl.c_str()); } else { f->codeAppendf("%s = 0.0;", innerCoverageDecl.c_str()); - f->appendPrecisionModifier(kMedium_GrSLPrecision); - f->codeAppendf("vec2 distanceToArcEdge = abs(%s) - %s.xy;", + f->codeAppendf("mediump vec2 distanceToArcEdge = abs(%s) - %s.xy;", fInnerShapeCoords.fsIn(), fInnerRRect.fsIn()); f->codeAppend ("if (any(lessThan(distanceToArcEdge, vec2(1e-5)))) {"); this->emitInnerRect(f, "innerCoverage"); f->codeAppend ("} else {"); - f->appendPrecisionModifier(kMedium_GrSLPrecision); - f->codeAppendf( "vec2 ellipseCoords = distanceToArcEdge * %s.zw;", + f->codeAppendf( "mediump vec2 ellipseCoords = distanceToArcEdge * %s.zw;", fInnerRRect.fsIn()); this->emitArc(f, "ellipseCoords", fInnerEllipseName.fsIn(), false /*ellipseCoordsNeedClamp*/, @@ -1013,9 +1012,8 @@ void GLSLInstanceProcessor::BackendCoverage::emitRect(GrGLSLPPFragmentBuilder* f void GLSLInstanceProcessor::BackendCoverage::emitCircle(GrGLSLPPFragmentBuilder* f, const char* outCoverage) { // TODO: circleCoords = max(circleCoords, 0) if we decide to do this optimization on rrects. - SkASSERT(!(kRRect_ShapesMask & fBatchInfo.fShapeTypes)); - f->appendPrecisionModifier(kMedium_GrSLPrecision); - f->codeAppendf("float distanceToEdge = %s - length(%s);", + SkASSERT(!(kRRect_ShapesMask & fOpInfo.fShapeTypes)); + f->codeAppendf("mediump float distanceToEdge = %s - length(%s);", fBloatedRadius.fsIn(), fEllipseCoords.fsIn()); f->codeAppendf("%s = clamp(distanceToEdge, 0.0, 1.0);", outCoverage); } @@ -1031,32 +1029,28 @@ void GLSLInstanceProcessor::BackendCoverage::emitArc(GrGLSLPPFragmentBuilder* f, // This serves two purposes: // - To restrict the arcs of rounded rects to their positive quadrants. // - To avoid inversesqrt(0) in the ellipse formula. - f->appendPrecisionModifier(kMedium_GrSLPrecision); if (ellipseCoordsMayBeNegative) { - f->codeAppendf("vec2 ellipseClampedCoords = max(abs(%s), vec2(1e-4));", ellipseCoords); + f->codeAppendf("mediump vec2 ellipseClampedCoords = max(abs(%s), vec2(1e-4));", + ellipseCoords); } else { - f->codeAppendf("vec2 ellipseClampedCoords = max(%s, vec2(1e-4));", ellipseCoords); + f->codeAppendf("mediump vec2 ellipseClampedCoords = max(%s, vec2(1e-4));", + ellipseCoords); } ellipseCoords = "ellipseClampedCoords"; } // ellipseCoords are in pixel space and ellipseName is 1 / rx^2, 1 / ry^2. - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf("vec2 Z = %s * %s;", ellipseCoords, ellipseName); + f->codeAppendf("highp vec2 Z = %s * %s;", ellipseCoords, ellipseName); // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1. - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf("float implicit = dot(Z, %s) - 1.0;", ellipseCoords); + f->codeAppendf("highp float implicit = dot(Z, %s) - 1.0;", ellipseCoords); // gradDot is the squared length of the gradient of the implicit. - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf("float gradDot = 4.0 * dot(Z, Z);"); - f->appendPrecisionModifier(kMedium_GrSLPrecision); - f->codeAppend ("float approxDist = implicit * inversesqrt(gradDot);"); + f->codeAppendf("highp float gradDot = 4.0 * dot(Z, Z);"); + f->codeAppend ("mediump float approxDist = implicit * inversesqrt(gradDot);"); f->codeAppendf("%s = clamp(0.5 - approxDist, 0.0, 1.0);", outCoverage); } void GLSLInstanceProcessor::BackendCoverage::emitInnerRect(GrGLSLPPFragmentBuilder* f, const char* outCoverage) { - f->appendPrecisionModifier(kLow_GrSLPrecision); - f->codeAppendf("vec2 c = %s - abs(%s);", + f->codeAppendf("lowp vec2 c = %s - abs(%s);", fInnerShapeBloatedHalfSize.fsIn(), fDistanceToInnerEdge.fsIn()); f->codeAppendf("%s = clamp(min(c.x, c.y), 0.0, 1.0);", outCoverage); } @@ -1065,24 +1059,24 @@ void GLSLInstanceProcessor::BackendCoverage::emitInnerRect(GrGLSLPPFragmentBuild class GLSLInstanceProcessor::BackendMultisample : public Backend { public: - BackendMultisample(BatchInfo batchInfo, const VertexInputs& inputs, int effectiveSampleCnt) - : INHERITED(batchInfo, inputs), - fEffectiveSampleCnt(effectiveSampleCnt), - fShapeCoords(kVec2f_GrSLType), - fShapeInverseMatrix(kMat22f_GrSLType), - fFragShapeHalfSpan(kVec2f_GrSLType), - fArcTest(kVec2f_GrSLType), - fArcInverseMatrix(kMat22f_GrSLType), - fFragArcHalfSpan(kVec2f_GrSLType), - fEarlyAccept(kInt_GrSLType), - fInnerShapeInverseMatrix(kMat22f_GrSLType), - fFragInnerShapeHalfSpan(kVec2f_GrSLType) { - fRectTrianglesMaySplit = fBatchInfo.fHasPerspective; - fNeedsNeighborRadii = this->isMixedSampled() && !fBatchInfo.fHasPerspective; + BackendMultisample(OpInfo opInfo, const VertexInputs& inputs, int effectiveSampleCnt) + : INHERITED(opInfo, inputs) + , fEffectiveSampleCnt(effectiveSampleCnt) + , fShapeCoords(kVec2f_GrSLType) + , fShapeInverseMatrix(kMat22f_GrSLType) + , fFragShapeHalfSpan(kVec2f_GrSLType) + , fArcTest(kVec2f_GrSLType) + , fArcInverseMatrix(kMat22f_GrSLType) + , fFragArcHalfSpan(kVec2f_GrSLType) + , fEarlyAccept(kInt_GrSLType) + , fInnerShapeInverseMatrix(kMat22f_GrSLType) + , fFragInnerShapeHalfSpan(kVec2f_GrSLType) { + fRectTrianglesMaySplit = fOpInfo.fHasPerspective; + fNeedsNeighborRadii = this->isMixedSampled() && !fOpInfo.fHasPerspective; } private: - bool isMixedSampled() const { return AntialiasMode::kMixedSamples == fBatchInfo.fAntialiasMode; } + bool isMixedSampled() const { return GrAAType::kMixedSamples == fOpInfo.aaType(); } void onInit(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*) override; void setupRect(GrGLSLVertexBuilder*) override; @@ -1140,50 +1134,50 @@ private: void GLSLInstanceProcessor::BackendMultisample::onInit(GrGLSLVaryingHandler* varyingHandler, GrGLSLVertexBuilder* v) { if (!this->isMixedSampled()) { - if (kRect_ShapeFlag != fBatchInfo.fShapeTypes) { + if (kRect_ShapeFlag != fOpInfo.fShapeTypes) { varyingHandler->addFlatVarying("triangleIsArc", &fTriangleIsArc, kLow_GrSLPrecision); varyingHandler->addVarying("arcCoords", &fArcCoords, kHigh_GrSLPrecision); - if (!fBatchInfo.fHasPerspective) { + if (!fOpInfo.fHasPerspective) { varyingHandler->addFlatVarying("arcInverseMatrix", &fArcInverseMatrix, kHigh_GrSLPrecision); varyingHandler->addFlatVarying("fragArcHalfSpan", &fFragArcHalfSpan, kHigh_GrSLPrecision); } - } else if (!fBatchInfo.fInnerShapeTypes) { + } else if (!fOpInfo.fInnerShapeTypes) { return; } } else { varyingHandler->addVarying("shapeCoords", &fShapeCoords, kHigh_GrSLPrecision); - if (!fBatchInfo.fHasPerspective) { + if (!fOpInfo.fHasPerspective) { varyingHandler->addFlatVarying("shapeInverseMatrix", &fShapeInverseMatrix, kHigh_GrSLPrecision); varyingHandler->addFlatVarying("fragShapeHalfSpan", &fFragShapeHalfSpan, kHigh_GrSLPrecision); } - if (fBatchInfo.fShapeTypes & kRRect_ShapesMask) { + if (fOpInfo.fShapeTypes & kRRect_ShapesMask) { varyingHandler->addVarying("arcCoords", &fArcCoords, kHigh_GrSLPrecision); varyingHandler->addVarying("arcTest", &fArcTest, kHigh_GrSLPrecision); - if (!fBatchInfo.fHasPerspective) { + if (!fOpInfo.fHasPerspective) { varyingHandler->addFlatVarying("arcInverseMatrix", &fArcInverseMatrix, kHigh_GrSLPrecision); varyingHandler->addFlatVarying("fragArcHalfSpan", &fFragArcHalfSpan, kHigh_GrSLPrecision); } - } else if (fBatchInfo.fShapeTypes & kOval_ShapeFlag) { + } else if (fOpInfo.fShapeTypes & kOval_ShapeFlag) { fArcCoords = fShapeCoords; fArcInverseMatrix = fShapeInverseMatrix; fFragArcHalfSpan = fFragShapeHalfSpan; - if (fBatchInfo.fShapeTypes & kRect_ShapeFlag) { + if (fOpInfo.fShapeTypes & kRect_ShapeFlag) { varyingHandler->addFlatVarying("triangleIsArc", &fTriangleIsArc, kLow_GrSLPrecision); } } - if (kRect_ShapeFlag != fBatchInfo.fShapeTypes) { - v->definef("SAMPLE_MASK_ALL", "0x%x", (1 << fEffectiveSampleCnt) - 1); - varyingHandler->addFlatVarying("earlyAccept", &fEarlyAccept, kHigh_GrSLPrecision); + if (kRect_ShapeFlag != fOpInfo.fShapeTypes) { + v->defineConstantf("int", "SAMPLE_MASK_ALL", "0x%x", (1 << fEffectiveSampleCnt) - 1); + varyingHandler->addFlatVarying("earlyAccept", &fEarlyAccept, kHigh_GrSLPrecision); } } - if (!fBatchInfo.fHasPerspective) { + if (!fOpInfo.fHasPerspective) { v->codeAppend("mat2 shapeInverseMatrix = inverse(mat2(shapeMatrix));"); v->codeAppend("vec2 fragShapeSpan = abs(vec4(shapeInverseMatrix).xz) + " "abs(vec4(shapeInverseMatrix).yw);"); @@ -1246,7 +1240,7 @@ void GLSLInstanceProcessor::BackendMultisample::adjustRRectVertices(GrGLSLVertex return; } - if (!fBatchInfo.fHasPerspective) { + if (!fOpInfo.fHasPerspective) { // For the mixed samples algorithm it's best to bloat the corner triangles a bit so that // more of the pixels that cross into the arc region are completely inside the shared edges. // We also snap to a regular rect if the radii shrink smaller than a pixel. @@ -1295,7 +1289,7 @@ void GLSLInstanceProcessor::BackendMultisample::onSetupRRect(GrGLSLVertexBuilder v->codeAppendf("%s = (cornerSize == vec2(0)) ? vec2(0) : " "cornerSign * %s * mat2(1, cornerSize.x - 1.0, cornerSize.y - 1.0, 1);", fArcTest.vsOut(), fModifiedShapeCoords); - if (!fBatchInfo.fHasPerspective) { + if (!fOpInfo.fHasPerspective) { // Shift the point at which distances to edges are measured from the center of the pixel // to the corner. This way the sign of fArcTest will quickly tell us whether a pixel // is completely inside the shared edge. Perspective mode will accomplish this same task @@ -1315,11 +1309,11 @@ void GLSLInstanceProcessor::BackendMultisample::onInitInnerShape(GrGLSLVaryingHandler* varyingHandler, GrGLSLVertexBuilder* v) { varyingHandler->addVarying("innerShapeCoords", &fInnerShapeCoords, kHigh_GrSLPrecision); - if (kOval_ShapeFlag != fBatchInfo.fInnerShapeTypes && - kRect_ShapeFlag != fBatchInfo.fInnerShapeTypes) { + if (kOval_ShapeFlag != fOpInfo.fInnerShapeTypes && + kRect_ShapeFlag != fOpInfo.fInnerShapeTypes) { varyingHandler->addFlatVarying("innerRRect", &fInnerRRect, kHigh_GrSLPrecision); } - if (!fBatchInfo.fHasPerspective) { + if (!fOpInfo.fHasPerspective) { varyingHandler->addFlatVarying("innerShapeInverseMatrix", &fInnerShapeInverseMatrix, kHigh_GrSLPrecision); v->codeAppendf("%s = shapeInverseMatrix * mat2(outer2Inner.x, 0, 0, outer2Inner.y);", @@ -1360,14 +1354,14 @@ void GLSLInstanceProcessor::BackendMultisample::onSetupInnerSimpleRRect(GrGLSLVe void GLSLInstanceProcessor::BackendMultisample::onEmitCode(GrGLSLVertexBuilder*, GrGLSLPPFragmentBuilder* f, const char*, const char*) { - f->define("SAMPLE_COUNT", fEffectiveSampleCnt); + f->defineConstant("SAMPLE_COUNT", fEffectiveSampleCnt); if (this->isMixedSampled()) { - f->definef("SAMPLE_MASK_ALL", "0x%x", (1 << fEffectiveSampleCnt) - 1); - f->definef("SAMPLE_MASK_MSB", "0x%x", 1 << (fEffectiveSampleCnt - 1)); + f->defineConstantf("int", "SAMPLE_MASK_ALL", "0x%x", (1 << fEffectiveSampleCnt) - 1); + f->defineConstantf("int", "SAMPLE_MASK_MSB", "0x%x", 1 << (fEffectiveSampleCnt - 1)); } - if (kRect_ShapeFlag != (fBatchInfo.fShapeTypes | fBatchInfo.fInnerShapeTypes)) { - GrGLSLShaderVar x("x", kVec2f_GrSLType, GrGLSLShaderVar::kNonArray, kHigh_GrSLPrecision); + if (kRect_ShapeFlag != (fOpInfo.fShapeTypes | fOpInfo.fInnerShapeTypes)) { + GrShaderVar x("x", kVec2f_GrSLType, GrShaderVar::kNonArray, kHigh_GrSLPrecision); f->emitFunction(kFloat_GrSLType, "square", 1, &x, "return dot(x, x);", &fSquareFun); } @@ -1380,18 +1374,17 @@ void GLSLInstanceProcessor::BackendMultisample::onEmitCode(GrGLSLVertexBuilder*, arcCoords.fVarying = &fArcCoords; arcCoords.fInverseMatrix = fArcInverseMatrix.fsIn(); arcCoords.fFragHalfSpan = fFragArcHalfSpan.fsIn(); - bool clampArcCoords = this->isMixedSampled() && (fBatchInfo.fShapeTypes & kRRect_ShapesMask); + bool clampArcCoords = this->isMixedSampled() && (fOpInfo.fShapeTypes & kRRect_ShapesMask); EmitShapeOpts opts; opts.fIsTightGeometry = true; opts.fResolveMixedSamples = this->isMixedSampled(); opts.fInvertCoverage = false; - if (fBatchInfo.fHasPerspective && fBatchInfo.fInnerShapeTypes) { + if (fOpInfo.fHasPerspective && fOpInfo.fInnerShapeTypes) { // This determines if the fragment should consider the inner shape in its sample mask. // We take the derivative early in case discards may occur before we get to the inner shape. - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf("vec2 fragInnerShapeApproxHalfSpan = 0.5 * fwidth(%s);", + f->codeAppendf("highp vec2 fragInnerShapeApproxHalfSpan = 0.5 * fwidth(%s);", fInnerShapeCoords.fsIn()); } @@ -1405,12 +1398,10 @@ void GLSLInstanceProcessor::BackendMultisample::onEmitCode(GrGLSLVertexBuilder*, } } else { const char* arcTest = fArcTest.fsIn(); - if (arcTest && fBatchInfo.fHasPerspective) { + if (arcTest && fOpInfo.fHasPerspective) { // The non-perspective version accounts for fwidth() in the vertex shader. // We make sure to take the derivative here, before a neighbor pixel may early accept. - f->enableFeature(GrGLSLPPFragmentBuilder::kStandardDerivatives_GLSLFeature); - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf("vec2 arcTest = %s - 0.5 * fwidth(%s);", + f->codeAppendf("highp vec2 arcTest = %s - 0.5 * fwidth(%s);", fArcTest.fsIn(), fArcTest.fsIn()); arcTest = "arcTest"; } @@ -1432,21 +1423,21 @@ void GLSLInstanceProcessor::BackendMultisample::onEmitCode(GrGLSLVertexBuilder*, f->codeAppend ("} else {"); this->emitArc(f, arcCoords, false, clampArcCoords, opts); f->codeAppend ("}"); - } else if (fBatchInfo.fShapeTypes == kOval_ShapeFlag) { + } else if (fOpInfo.fShapeTypes == kOval_ShapeFlag) { this->emitArc(f, arcCoords, false, clampArcCoords, opts); } else { - SkASSERT(fBatchInfo.fShapeTypes == kRect_ShapeFlag); + SkASSERT(fOpInfo.fShapeTypes == kRect_ShapeFlag); this->emitRect(f, shapeCoords, opts); } f->codeAppend ("}"); } - if (fBatchInfo.fInnerShapeTypes) { + if (fOpInfo.fInnerShapeTypes) { f->codeAppendf("// Inner shape.\n"); EmitShapeCoords innerShapeCoords; innerShapeCoords.fVarying = &fInnerShapeCoords; - if (!fBatchInfo.fHasPerspective) { + if (!fOpInfo.fHasPerspective) { innerShapeCoords.fInverseMatrix = fInnerShapeInverseMatrix.fsIn(); innerShapeCoords.fFragHalfSpan = fFragInnerShapeHalfSpan.fsIn(); } @@ -1456,13 +1447,13 @@ void GLSLInstanceProcessor::BackendMultisample::onEmitCode(GrGLSLVertexBuilder*, innerOpts.fResolveMixedSamples = false; // Mixed samples are resolved in the outer shape. innerOpts.fInvertCoverage = true; - if (kOval_ShapeFlag == fBatchInfo.fInnerShapeTypes) { + if (kOval_ShapeFlag == fOpInfo.fInnerShapeTypes) { this->emitArc(f, innerShapeCoords, true, false, innerOpts); } else { f->codeAppendf("if (all(lessThan(abs(%s), 1.0 + %s))) {", fInnerShapeCoords.fsIn(), - !fBatchInfo.fHasPerspective ? innerShapeCoords.fFragHalfSpan - : "fragInnerShapeApproxHalfSpan"); // Above. - if (kRect_ShapeFlag == fBatchInfo.fInnerShapeTypes) { + !fOpInfo.fHasPerspective ? innerShapeCoords.fFragHalfSpan + : "fragInnerShapeApproxHalfSpan"); // Above. + if (kRect_ShapeFlag == fOpInfo.fInnerShapeTypes) { this->emitRect(f, innerShapeCoords, innerOpts); } else { this->emitSimpleRRect(f, innerShapeCoords, fInnerRRect.fsIn(), innerOpts); @@ -1494,8 +1485,7 @@ void GLSLInstanceProcessor::BackendMultisample::emitRect(GrGLSLPPFragmentBuilder } f->codeAppend ("int rectMask = 0;"); f->codeAppend ("for (int i = 0; i < SAMPLE_COUNT; i++) {"); - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppend ( "vec2 pt = "); + f->codeAppend ( "highp vec2 pt = "); this->interpolateAtSample(f, *coords.fVarying, "i", coords.fInverseMatrix); f->codeAppend ( ";"); f->codeAppend ( "if (all(lessThan(abs(pt), vec2(1)))) rectMask |= (1 << i);"); @@ -1530,8 +1520,7 @@ void GLSLInstanceProcessor::BackendMultisample::emitArc(GrGLSLPPFragmentBuilder* } f->codeAppend ( "int arcMask = 0;"); f->codeAppend ( "for (int i = 0; i < SAMPLE_COUNT; i++) {"); - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppend ( "vec2 pt = "); + f->codeAppend ( "highp vec2 pt = "); this->interpolateAtSample(f, *coords.fVarying, "i", coords.fInverseMatrix); f->codeAppend ( ";"); if (clampCoords) { @@ -1550,16 +1539,14 @@ void GLSLInstanceProcessor::BackendMultisample::emitSimpleRRect(GrGLSLPPFragment const EmitShapeCoords& coords, const char* rrect, const EmitShapeOpts& opts) { - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf("vec2 distanceToArcEdge = abs(%s) - %s.xy;", coords.fVarying->fsIn(), rrect); + f->codeAppendf("highp vec2 distanceToArcEdge = abs(%s) - %s.xy;", coords.fVarying->fsIn(), + rrect); f->codeAppend ("if (any(lessThan(distanceToArcEdge, vec2(0)))) {"); this->emitRect(f, coords, opts); f->codeAppend ("} else {"); if (coords.fInverseMatrix && coords.fFragHalfSpan) { - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf("vec2 rrectCoords = distanceToArcEdge * %s.zw;", rrect); - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf("vec2 fragRRectHalfSpan = %s * %s.zw;", coords.fFragHalfSpan, rrect); + f->codeAppendf("highp vec2 rrectCoords = distanceToArcEdge * %s.zw;", rrect); + f->codeAppendf("highp vec2 fragRRectHalfSpan = %s * %s.zw;", coords.fFragHalfSpan, rrect); f->codeAppendf("if (%s(rrectCoords + fragRRectHalfSpan) <= 1.0) {", fSquareFun.c_str()); // The entire pixel is inside the round rect. this->acceptOrRejectWholeFragment(f, true, opts); @@ -1568,16 +1555,12 @@ void GLSLInstanceProcessor::BackendMultisample::emitSimpleRRect(GrGLSLPPFragment // The entire pixel is outside the round rect. this->acceptOrRejectWholeFragment(f, false, opts); f->codeAppend ("} else {"); - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf( "vec2 s = %s.zw * sign(%s);", rrect, coords.fVarying->fsIn()); - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf( "mat2 innerRRectInverseMatrix = %s * mat2(s.x, 0, 0, s.y);", + f->codeAppendf( "highp vec2 s = %s.zw * sign(%s);", rrect, coords.fVarying->fsIn()); + f->codeAppendf( "highp mat2 innerRRectInverseMatrix = %s * mat2(s.x, 0, 0, s.y);", coords.fInverseMatrix); - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppend ( "int rrectMask = 0;"); + f->codeAppend ( "highp int rrectMask = 0;"); f->codeAppend ( "for (int i = 0; i < SAMPLE_COUNT; i++) {"); - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppend ( "vec2 pt = rrectCoords + "); + f->codeAppend ( "highp vec2 pt = rrectCoords + "); f->appendOffsetToSample("i", GrGLSLFPFragmentBuilder::kSkiaDevice_Coordinates); f->codeAppend ( "* innerRRectInverseMatrix;"); f->codeAppendf( "if (%s(max(pt, vec2(0))) < 1.0) rrectMask |= (1 << i);", @@ -1588,12 +1571,10 @@ void GLSLInstanceProcessor::BackendMultisample::emitSimpleRRect(GrGLSLPPFragment } else { f->codeAppend ("int rrectMask = 0;"); f->codeAppend ("for (int i = 0; i < SAMPLE_COUNT; i++) {"); - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppend ( "vec2 shapePt = "); + f->codeAppend ( "highp vec2 shapePt = "); this->interpolateAtSample(f, *coords.fVarying, "i", nullptr); f->codeAppend ( ";"); - f->appendPrecisionModifier(kHigh_GrSLPrecision); - f->codeAppendf( "vec2 rrectPt = max(abs(shapePt) - %s.xy, vec2(0)) * %s.zw;", + f->codeAppendf( "highp vec2 rrectPt = max(abs(shapePt) - %s.xy, vec2(0)) * %s.zw;", rrect, rrect); f->codeAppendf( "if (%s(rrectPt) < 1.0) rrectMask |= (1 << i);", fSquareFun.c_str()); f->codeAppend ("}"); @@ -1634,7 +1615,7 @@ GLSLInstanceProcessor::BackendMultisample::acceptOrRejectWholeFragment(GrGLSLPPF // fragment. f->codeAppend("if ((gl_SampleMaskIn[0] & SAMPLE_MASK_MSB) == 0) {"); // Drop this fragment. - if (!fBatchInfo.fCannotDiscard) { + if (!fOpInfo.fCannotDiscard) { f->codeAppend("discard;"); } else { f->overrideSampleCoverage("0"); @@ -1645,7 +1626,7 @@ GLSLInstanceProcessor::BackendMultisample::acceptOrRejectWholeFragment(GrGLSLPPF f->codeAppend("}"); } } else { // Reject the entire fragment. - if (!fBatchInfo.fCannotDiscard) { + if (!fOpInfo.fCannotDiscard) { f->codeAppend("discard;"); } else if (opts.fResolveMixedSamples) { f->overrideSampleCoverage("0"); @@ -1670,7 +1651,7 @@ void GLSLInstanceProcessor::BackendMultisample::acceptCoverageMask(GrGLSLPPFragm SkASSERT(!opts.fInvertCoverage); f->codeAppendf("if ((gl_SampleMaskIn[0] & (1 << findMSB(%s))) == 0) {", shapeMask); // Drop this fragment. - if (!fBatchInfo.fCannotDiscard) { + if (!fOpInfo.fCannotDiscard) { f->codeAppend ("discard;"); } else { f->overrideSampleCoverage("0"); @@ -1689,21 +1670,21 @@ void GLSLInstanceProcessor::BackendMultisample::acceptCoverageMask(GrGLSLPPFragm //////////////////////////////////////////////////////////////////////////////////////////////////// -GLSLInstanceProcessor::Backend* -GLSLInstanceProcessor::Backend::Create(const GrPipeline& pipeline, BatchInfo batchInfo, - const VertexInputs& inputs) { - switch (batchInfo.fAntialiasMode) { +GLSLInstanceProcessor::Backend* GLSLInstanceProcessor::Backend::Create(const GrPipeline& pipeline, + OpInfo opInfo, + const VertexInputs& inputs) { + switch (opInfo.aaType()) { default: SkFAIL("Unexpected antialias mode."); - case AntialiasMode::kNone: - return new BackendNonAA(batchInfo, inputs); - case AntialiasMode::kCoverage: - return new BackendCoverage(batchInfo, inputs); - case AntialiasMode::kMSAA: - case AntialiasMode::kMixedSamples: { + case GrAAType::kNone: + return new BackendNonAA(opInfo, inputs); + case GrAAType::kCoverage: + return new BackendCoverage(opInfo, inputs); + case GrAAType::kMSAA: + case GrAAType::kMixedSamples: { const GrRenderTargetPriv& rtp = pipeline.getRenderTarget()->renderTargetPriv(); - const GrGpu::MultisampleSpecs& specs = rtp.getMultisampleSpecs(pipeline.getStencil()); - return new BackendMultisample(batchInfo, inputs, specs.fEffectiveSampleCnt); + const GrGpu::MultisampleSpecs& specs = rtp.getMultisampleSpecs(pipeline); + return new BackendMultisample(opInfo, inputs, specs.fEffectiveSampleCnt); } } } @@ -2046,60 +2027,50 @@ const GrBuffer* InstanceProcessor::FindOrCreateIndex8Buffer(GrGpu* gpu) { return nullptr; } -IndexRange InstanceProcessor::GetIndexRangeForRect(AntialiasMode aa) { - static constexpr IndexRange kRectRanges[kNumAntialiasModes] = { - {kRect_FirstIndex, 3 * kRect_TriCount}, // kNone - {kFramedRect_FirstIndex, 3 * kFramedRect_TriCount}, // kCoverage - {kRect_FirstIndex, 3 * kRect_TriCount}, // kMSAA - {kRect_FirstIndex, 3 * kRect_TriCount} // kMixedSamples - }; - - SkASSERT(aa >= AntialiasMode::kNone && aa <= AntialiasMode::kMixedSamples); - return kRectRanges[(int)aa]; - - GR_STATIC_ASSERT(0 == (int)AntialiasMode::kNone); - GR_STATIC_ASSERT(1 == (int)AntialiasMode::kCoverage); - GR_STATIC_ASSERT(2 == (int)AntialiasMode::kMSAA); - GR_STATIC_ASSERT(3 == (int)AntialiasMode::kMixedSamples); +IndexRange InstanceProcessor::GetIndexRangeForRect(GrAAType aaType) { + switch (aaType) { + case GrAAType::kCoverage: + return {kFramedRect_FirstIndex, 3 * kFramedRect_TriCount}; + case GrAAType::kNone: + case GrAAType::kMSAA: + case GrAAType::kMixedSamples: + return {kRect_FirstIndex, 3 * kRect_TriCount}; + } + SkFAIL("Unexpected aa type!"); + return {0, 0}; } -IndexRange InstanceProcessor::GetIndexRangeForOval(AntialiasMode aa, const SkRect& devBounds) { - if (AntialiasMode::kCoverage == aa && devBounds.height() * devBounds.width() >= 256 * 256) { +IndexRange InstanceProcessor::GetIndexRangeForOval(GrAAType aaType, const SkRect& devBounds) { + if (GrAAType::kCoverage == aaType && devBounds.height() * devBounds.width() >= 256 * 256) { // This threshold was chosen quasi-scientifically on Tegra X1. return {kDisjoint16Gons_FirstIndex, 3 * kDisjoint16Gons_TriCount}; } - static constexpr IndexRange kOvalRanges[kNumAntialiasModes] = { - {kOctagons_FirstIndex, 3 * kOctagons_TriCount}, // kNone - {kDisjointOctagons_FirstIndex, 3 * kDisjointOctagons_TriCount}, // kCoverage - {kOctagons_FirstIndex, 3 * kOctagons_TriCount}, // kMSAA - {kOctagonsFanned_FirstIndex, 3 * kOctagonsFanned_TriCount} // kMixedSamples - }; - - SkASSERT(aa >= AntialiasMode::kNone && aa <= AntialiasMode::kMixedSamples); - return kOvalRanges[(int)aa]; - - GR_STATIC_ASSERT(0 == (int)AntialiasMode::kNone); - GR_STATIC_ASSERT(1 == (int)AntialiasMode::kCoverage); - GR_STATIC_ASSERT(2 == (int)AntialiasMode::kMSAA); - GR_STATIC_ASSERT(3 == (int)AntialiasMode::kMixedSamples); + switch (aaType) { + case GrAAType::kNone: + case GrAAType::kMSAA: + return {kOctagons_FirstIndex, 3 * kOctagons_TriCount}; + case GrAAType::kCoverage: + return {kDisjointOctagons_FirstIndex, 3 * kDisjointOctagons_TriCount}; + case GrAAType::kMixedSamples: + return {kOctagonsFanned_FirstIndex, 3 * kOctagonsFanned_TriCount}; + } + SkFAIL("Unexpected aa type!"); + return {0, 0}; } -IndexRange InstanceProcessor::GetIndexRangeForRRect(AntialiasMode aa) { - static constexpr IndexRange kRRectRanges[kNumAntialiasModes] = { - {kCorneredRect_FirstIndex, 3 * kCorneredRect_TriCount}, // kNone - {kCorneredFramedRect_FirstIndex, 3 * kCorneredFramedRect_TriCount}, // kCoverage - {kCorneredRect_FirstIndex, 3 * kCorneredRect_TriCount}, // kMSAA - {kCorneredRectFanned_FirstIndex, 3 * kCorneredRectFanned_TriCount} // kMixedSamples - }; - - SkASSERT(aa >= AntialiasMode::kNone && aa <= AntialiasMode::kMixedSamples); - return kRRectRanges[(int)aa]; - - GR_STATIC_ASSERT(0 == (int)AntialiasMode::kNone); - GR_STATIC_ASSERT(1 == (int)AntialiasMode::kCoverage); - GR_STATIC_ASSERT(2 == (int)AntialiasMode::kMSAA); - GR_STATIC_ASSERT(3 == (int)AntialiasMode::kMixedSamples); +IndexRange InstanceProcessor::GetIndexRangeForRRect(GrAAType aaType) { + switch (aaType) { + case GrAAType::kNone: + case GrAAType::kMSAA: + return {kCorneredRect_FirstIndex, 3 * kCorneredRect_TriCount}; + case GrAAType::kCoverage: + return {kCorneredFramedRect_FirstIndex, 3 * kCorneredFramedRect_TriCount}; + case GrAAType::kMixedSamples: + return {kCorneredRectFanned_FirstIndex, 3 * kCorneredRectFanned_TriCount}; + } + SkFAIL("Unexpected aa type!"); + return {0, 0}; } const char* InstanceProcessor::GetNameOfIndexRange(IndexRange range) { diff --git a/gfx/skia/skia/src/gpu/instanced/InstanceProcessor.h b/gfx/skia/skia/src/gpu/instanced/InstanceProcessor.h index 0b3a16d5a4b3..8cde30f73f20 100644 --- a/gfx/skia/skia/src/gpu/instanced/InstanceProcessor.h +++ b/gfx/skia/skia/src/gpu/instanced/InstanceProcessor.h @@ -9,7 +9,6 @@ #define gr_instanced_InstanceProcessor_DEFINED #include "GrCaps.h" -#include "GrBufferAccess.h" #include "GrGeometryProcessor.h" #include "instanced/InstancedRenderingTypes.h" @@ -23,15 +22,15 @@ namespace gr_instanced { */ class InstanceProcessor : public GrGeometryProcessor { public: - InstanceProcessor(BatchInfo, GrBuffer* paramsBuffer); + InstanceProcessor(OpInfo, GrBuffer* paramsBuffer); const char* name() const override { return "Instance Processor"; } - BatchInfo batchInfo() const { return fBatchInfo; } + OpInfo opInfo() const { return fOpInfo; } - void getGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder* b) const override { - b->add32(fBatchInfo.fData); + void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { + b->add32(fOpInfo.fData); } - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; /** * Returns a buffer of ShapeVertex that defines the canonical instanced geometry. @@ -44,9 +43,9 @@ public: */ static const GrBuffer* SK_WARN_UNUSED_RESULT FindOrCreateIndex8Buffer(GrGpu*); - static IndexRange GetIndexRangeForRect(AntialiasMode); - static IndexRange GetIndexRangeForOval(AntialiasMode, const SkRect& devBounds); - static IndexRange GetIndexRangeForRRect(AntialiasMode); + static IndexRange GetIndexRangeForRect(GrAAType); + static IndexRange GetIndexRangeForOval(GrAAType, const SkRect& devBounds); + static IndexRange GetIndexRangeForRRect(GrAAType); static const char* GetNameOfIndexRange(IndexRange); @@ -55,10 +54,10 @@ private: * Called by the platform-specific instanced rendering implementation to determine the level of * support this class can offer on the given GLSL platform. */ - static GrCaps::InstancedSupport CheckSupport(const GrGLSLCaps&, const GrCaps&); + static GrCaps::InstancedSupport CheckSupport(const GrShaderCaps&, const GrCaps&); - const BatchInfo fBatchInfo; - GrBufferAccess fParamsAccess; + OpInfo fOpInfo; + BufferAccess fParamsAccess; friend class GLInstancedRendering; // For CheckSupport. diff --git a/gfx/skia/skia/src/gpu/instanced/InstancedRendering.cpp b/gfx/skia/skia/src/gpu/instanced/InstancedRendering.cpp index 66e53dd5dbf8..9d17a82fc1fc 100644 --- a/gfx/skia/skia/src/gpu/instanced/InstancedRendering.cpp +++ b/gfx/skia/skia/src/gpu/instanced/InstancedRendering.cpp @@ -6,9 +6,9 @@ */ #include "InstancedRendering.h" - -#include "GrBatchFlushState.h" +#include "GrAppliedClip.h" #include "GrCaps.h" +#include "GrOpFlushState.h" #include "GrPipeline.h" #include "GrResourceProvider.h" #include "instanced/InstanceProcessor.h" @@ -18,114 +18,116 @@ namespace gr_instanced { InstancedRendering::InstancedRendering(GrGpu* gpu) : fGpu(SkRef(gpu)), fState(State::kRecordingDraws), - fDrawPool(1024 * sizeof(Batch::Draw), 1024 * sizeof(Batch::Draw)) { + fDrawPool(1024, 1024) { } -GrDrawBatch* InstancedRendering::recordRect(const SkRect& rect, const SkMatrix& viewMatrix, - GrColor color, bool antialias, - const GrInstancedPipelineInfo& info, bool* useHWAA) { - return this->recordShape(ShapeType::kRect, rect, viewMatrix, color, rect, antialias, info, - useHWAA); +std::unique_ptr InstancedRendering::recordRect(const SkRect& rect, + const SkMatrix& viewMatrix, + GrPaint&& paint, GrAA aa, + const GrInstancedPipelineInfo& info) { + return this->recordShape(ShapeType::kRect, rect, viewMatrix, std::move(paint), rect, aa, info); } -GrDrawBatch* InstancedRendering::recordRect(const SkRect& rect, const SkMatrix& viewMatrix, - GrColor color, const SkRect& localRect, bool antialias, - const GrInstancedPipelineInfo& info, bool* useHWAA) { - return this->recordShape(ShapeType::kRect, rect, viewMatrix, color, localRect, antialias, info, - useHWAA); +std::unique_ptr InstancedRendering::recordRect(const SkRect& rect, + const SkMatrix& viewMatrix, + GrPaint&& paint, const SkRect& localRect, + GrAA aa, + const GrInstancedPipelineInfo& info) { + return this->recordShape(ShapeType::kRect, rect, viewMatrix, std::move(paint), localRect, aa, + info); } -GrDrawBatch* InstancedRendering::recordRect(const SkRect& rect, const SkMatrix& viewMatrix, - GrColor color, const SkMatrix& localMatrix, - bool antialias, const GrInstancedPipelineInfo& info, - bool* useHWAA) { +std::unique_ptr InstancedRendering::recordRect(const SkRect& rect, + const SkMatrix& viewMatrix, + GrPaint&& paint, + const SkMatrix& localMatrix, GrAA aa, + const GrInstancedPipelineInfo& info) { if (localMatrix.hasPerspective()) { return nullptr; // Perspective is not yet supported in the local matrix. } - if (Batch* batch = this->recordShape(ShapeType::kRect, rect, viewMatrix, color, rect, antialias, - info, useHWAA)) { - batch->getSingleInstance().fInfo |= kLocalMatrix_InfoFlag; - batch->appendParamsTexel(localMatrix.getScaleX(), localMatrix.getSkewX(), - localMatrix.getTranslateX()); - batch->appendParamsTexel(localMatrix.getSkewY(), localMatrix.getScaleY(), - localMatrix.getTranslateY()); - batch->fInfo.fHasLocalMatrix = true; - return batch; + if (std::unique_ptr op = this->recordShape(ShapeType::kRect, rect, viewMatrix, + std::move(paint), rect, aa, info)) { + op->getSingleInstance().fInfo |= kLocalMatrix_InfoFlag; + op->appendParamsTexel(localMatrix.getScaleX(), localMatrix.getSkewX(), + localMatrix.getTranslateX()); + op->appendParamsTexel(localMatrix.getSkewY(), localMatrix.getScaleY(), + localMatrix.getTranslateY()); + op->fInfo.fHasLocalMatrix = true; + return std::move(op); } return nullptr; } -GrDrawBatch* InstancedRendering::recordOval(const SkRect& oval, const SkMatrix& viewMatrix, - GrColor color, bool antialias, - const GrInstancedPipelineInfo& info, bool* useHWAA) { - return this->recordShape(ShapeType::kOval, oval, viewMatrix, color, oval, antialias, info, - useHWAA); +std::unique_ptr InstancedRendering::recordOval(const SkRect& oval, + const SkMatrix& viewMatrix, + GrPaint&& paint, GrAA aa, + const GrInstancedPipelineInfo& info) { + return this->recordShape(ShapeType::kOval, oval, viewMatrix, std::move(paint), oval, aa, info); } -GrDrawBatch* InstancedRendering::recordRRect(const SkRRect& rrect, const SkMatrix& viewMatrix, - GrColor color, bool antialias, - const GrInstancedPipelineInfo& info, bool* useHWAA) { - if (Batch* batch = this->recordShape(GetRRectShapeType(rrect), rrect.rect(), viewMatrix, color, - rrect.rect(), antialias, info, useHWAA)) { - batch->appendRRectParams(rrect); - return batch; +std::unique_ptr InstancedRendering::recordRRect(const SkRRect& rrect, + const SkMatrix& viewMatrix, + GrPaint&& paint, GrAA aa, + const GrInstancedPipelineInfo& info) { + if (std::unique_ptr op = + this->recordShape(GetRRectShapeType(rrect), rrect.rect(), viewMatrix, + std::move(paint), rrect.rect(), aa, info)) { + op->appendRRectParams(rrect); + return std::move(op); } return nullptr; } -GrDrawBatch* InstancedRendering::recordDRRect(const SkRRect& outer, const SkRRect& inner, - const SkMatrix& viewMatrix, GrColor color, - bool antialias, const GrInstancedPipelineInfo& info, - bool* useHWAA) { +std::unique_ptr InstancedRendering::recordDRRect(const SkRRect& outer, + const SkRRect& inner, + const SkMatrix& viewMatrix, + GrPaint&& paint, GrAA aa, + const GrInstancedPipelineInfo& info) { if (inner.getType() > SkRRect::kSimple_Type) { return nullptr; // Complex inner round rects are not yet supported. } if (SkRRect::kEmpty_Type == inner.getType()) { - return this->recordRRect(outer, viewMatrix, color, antialias, info, useHWAA); + return this->recordRRect(outer, viewMatrix, std::move(paint), aa, info); } - if (Batch* batch = this->recordShape(GetRRectShapeType(outer), outer.rect(), viewMatrix, color, - outer.rect(), antialias, info, useHWAA)) { - batch->appendRRectParams(outer); + if (std::unique_ptr op = + this->recordShape(GetRRectShapeType(outer), outer.rect(), viewMatrix, + std::move(paint), outer.rect(), aa, info)) { + op->appendRRectParams(outer); ShapeType innerShapeType = GetRRectShapeType(inner); - batch->fInfo.fInnerShapeTypes |= GetShapeFlag(innerShapeType); - batch->getSingleInstance().fInfo |= ((int)innerShapeType << kInnerShapeType_InfoBit); - batch->appendParamsTexel(inner.rect().asScalars(), 4); - batch->appendRRectParams(inner); - return batch; + op->fInfo.fInnerShapeTypes |= GetShapeFlag(innerShapeType); + op->getSingleInstance().fInfo |= ((int)innerShapeType << kInnerShapeType_InfoBit); + op->appendParamsTexel(inner.rect().asScalars(), 4); + op->appendRRectParams(inner); + return std::move(op); } return nullptr; } -InstancedRendering::Batch* InstancedRendering::recordShape(ShapeType type, const SkRect& bounds, - const SkMatrix& viewMatrix, - GrColor color, const SkRect& localRect, - bool antialias, - const GrInstancedPipelineInfo& info, - bool* useHWAA) { +std::unique_ptr InstancedRendering::recordShape( + ShapeType type, const SkRect& bounds, const SkMatrix& viewMatrix, GrPaint&& paint, + const SkRect& localRect, GrAA aa, const GrInstancedPipelineInfo& info) { SkASSERT(State::kRecordingDraws == fState); if (info.fIsRenderingToFloat && fGpu->caps()->avoidInstancedDrawsToFPTargets()) { return nullptr; } - AntialiasMode antialiasMode; - if (!this->selectAntialiasMode(viewMatrix, antialias, info, useHWAA, &antialiasMode)) { + GrAAType aaType; + if (!this->selectAntialiasMode(viewMatrix, aa, info, &aaType)) { return nullptr; } - Batch* batch = this->createBatch(); - batch->fInfo.fAntialiasMode = antialiasMode; - batch->fInfo.fShapeTypes = GetShapeFlag(type); - batch->fInfo.fCannotDiscard = !info.fCanDiscard; - - Instance& instance = batch->getSingleInstance(); + GrColor color = paint.getColor(); + std::unique_ptr op = this->makeOp(std::move(paint)); + op->fInfo.setAAType(aaType); + op->fInfo.fShapeTypes = GetShapeFlag(type); + op->fInfo.fCannotDiscard = true; + Instance& instance = op->getSingleInstance(); instance.fInfo = (int)type << kShapeType_InfoBit; - Batch::HasAABloat aaBloat = (antialiasMode == AntialiasMode::kCoverage) - ? Batch::HasAABloat::kYes - : Batch::HasAABloat::kNo; - Batch::IsZeroArea zeroArea = (bounds.isEmpty()) ? Batch::IsZeroArea::kYes - : Batch::IsZeroArea::kNo; + Op::HasAABloat aaBloat = + (aaType == GrAAType::kCoverage) ? Op::HasAABloat::kYes : Op::HasAABloat::kNo; + Op::IsZeroArea zeroArea = (bounds.isEmpty()) ? Op::IsZeroArea::kYes : Op::IsZeroArea::kNo; // The instanced shape renderer draws rectangles of [-1, -1, +1, +1], so we find the matrix that // will map this rectangle to the same device coordinates as "viewMatrix * bounds". @@ -149,18 +151,19 @@ InstancedRendering::Batch* InstancedRendering::recordShape(ShapeType type, const // it's quite simple to find the bounding rectangle: float devBoundsHalfWidth = fabsf(m[0]) + fabsf(m[1]); float devBoundsHalfHeight = fabsf(m[3]) + fabsf(m[4]); - SkRect batchBounds; - batchBounds.fLeft = m[2] - devBoundsHalfWidth; - batchBounds.fRight = m[2] + devBoundsHalfWidth; - batchBounds.fTop = m[5] - devBoundsHalfHeight; - batchBounds.fBottom = m[5] + devBoundsHalfHeight; - batch->setBounds(batchBounds, aaBloat, zeroArea); + SkRect opBounds; + opBounds.fLeft = m[2] - devBoundsHalfWidth; + opBounds.fRight = m[2] + devBoundsHalfWidth; + opBounds.fTop = m[5] - devBoundsHalfHeight; + opBounds.fBottom = m[5] + devBoundsHalfHeight; + op->setBounds(opBounds, aaBloat, zeroArea); // TODO: Is this worth the CPU overhead? - batch->fInfo.fNonSquare = - fabsf(devBoundsHalfHeight - devBoundsHalfWidth) > 0.5f || // Early out. - fabs(m[0] * m[3] + m[1] * m[4]) > 1e-3f || // Skew? - fabs(m[0] * m[0] + m[1] * m[1] - m[3] * m[3] - m[4] * m[4]) > 1e-2f; // Diff. lengths? + op->fInfo.fNonSquare = + fabsf(devBoundsHalfHeight - devBoundsHalfWidth) > 0.5f || // Early out. + fabs(m[0] * m[3] + m[1] * m[4]) > 1e-3f || // Skew? + fabs(m[0] * m[0] + m[1] * m[1] - m[3] * m[3] - m[4] * m[4]) > + 1e-2f; // Diff. lengths? } else { SkMatrix shapeMatrix(viewMatrix); shapeMatrix.preTranslate(tx, ty); @@ -176,12 +179,12 @@ InstancedRendering::Batch* InstancedRendering::recordShape(ShapeType type, const m[5] = SkScalarToFloat(shapeMatrix.getTranslateY()); // Send the perspective column as a param. - batch->appendParamsTexel(shapeMatrix[SkMatrix::kMPersp0], shapeMatrix[SkMatrix::kMPersp1], - shapeMatrix[SkMatrix::kMPersp2]); - batch->fInfo.fHasPerspective = true; + op->appendParamsTexel(shapeMatrix[SkMatrix::kMPersp0], shapeMatrix[SkMatrix::kMPersp1], + shapeMatrix[SkMatrix::kMPersp2]); + op->fInfo.fHasPerspective = true; - batch->setBounds(bounds, aaBloat, zeroArea); - batch->fInfo.fNonSquare = true; + op->setBounds(bounds, aaBloat, zeroArea); + op->fInfo.fNonSquare = true; } instance.fColor = color; @@ -189,45 +192,36 @@ InstancedRendering::Batch* InstancedRendering::recordShape(ShapeType type, const const float* rectAsFloats = localRect.asScalars(); // Ensure SkScalar == float. memcpy(&instance.fLocalRect, rectAsFloats, 4 * sizeof(float)); - batch->fPixelLoad = batch->bounds().height() * batch->bounds().width(); - return batch; + op->fPixelLoad = op->bounds().height() * op->bounds().width(); + return op; } -inline bool InstancedRendering::selectAntialiasMode(const SkMatrix& viewMatrix, bool antialias, +inline bool InstancedRendering::selectAntialiasMode(const SkMatrix& viewMatrix, GrAA aa, const GrInstancedPipelineInfo& info, - bool* useHWAA, AntialiasMode* antialiasMode) { - SkASSERT(!info.fColorDisabled || info.fDrawingShapeToStencil); + GrAAType* aaType) { SkASSERT(!info.fIsMixedSampled || info.fIsMultisampled); SkASSERT(GrCaps::InstancedSupport::kNone != fGpu->caps()->instancedSupport()); if (!info.fIsMultisampled || fGpu->caps()->multisampleDisableSupport()) { - if (!antialias) { - if (info.fDrawingShapeToStencil && !info.fCanDiscard) { - // We can't draw to the stencil buffer without discard (or sample mask if MSAA). - return false; - } - *antialiasMode = AntialiasMode::kNone; - *useHWAA = false; + if (GrAA::kNo == aa) { + *aaType = GrAAType::kNone; return true; } if (info.canUseCoverageAA() && viewMatrix.preservesRightAngles()) { - *antialiasMode = AntialiasMode::kCoverage; - *useHWAA = false; + *aaType = GrAAType::kCoverage; return true; } } if (info.fIsMultisampled && fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMultisampled) { - if (!info.fIsMixedSampled || info.fColorDisabled) { - *antialiasMode = AntialiasMode::kMSAA; - *useHWAA = true; + if (!info.fIsMixedSampled) { + *aaType = GrAAType::kMSAA; return true; } if (fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMixedSampled) { - *antialiasMode = AntialiasMode::kMixedSamples; - *useHWAA = true; + *aaType = GrAAType::kMixedSamples; return true; } } @@ -235,22 +229,24 @@ inline bool InstancedRendering::selectAntialiasMode(const SkMatrix& viewMatrix, return false; } -InstancedRendering::Batch::Batch(uint32_t classID, InstancedRendering* ir) - : INHERITED(classID), - fInstancedRendering(ir), - fIsTracked(false), - fNumDraws(1), - fNumChangesInGeometry(0) { - fHeadDraw = fTailDraw = (Draw*)fInstancedRendering->fDrawPool.allocate(sizeof(Draw)); +InstancedRendering::Op::Op(uint32_t classID, GrPaint&& paint, InstancedRendering* ir) + : INHERITED(classID) + , fInstancedRendering(ir) + , fProcessors(std::move(paint)) + , fIsTracked(false) + , fRequiresBarrierOnOverlap(false) + , fNumDraws(1) + , fNumChangesInGeometry(0) { + fHeadDraw = fTailDraw = fInstancedRendering->fDrawPool.allocate(); #ifdef SK_DEBUG fHeadDraw->fGeometry = {-1, 0}; #endif fHeadDraw->fNext = nullptr; } -InstancedRendering::Batch::~Batch() { +InstancedRendering::Op::~Op() { if (fIsTracked) { - fInstancedRendering->fTrackedBatches.remove(this); + fInstancedRendering->fTrackedOps.remove(this); } Draw* draw = fHeadDraw; @@ -261,7 +257,7 @@ InstancedRendering::Batch::~Batch() { } } -void InstancedRendering::Batch::appendRRectParams(const SkRRect& rrect) { +void InstancedRendering::Op::appendRRectParams(const SkRRect& rrect) { SkASSERT(!fIsTracked); switch (rrect.getType()) { case SkRRect::kSimple_Type: { @@ -308,7 +304,7 @@ void InstancedRendering::Batch::appendRRectParams(const SkRRect& rrect) { } } -void InstancedRendering::Batch::appendParamsTexel(const SkScalar* vals, int count) { +void InstancedRendering::Op::appendParamsTexel(const SkScalar* vals, int count) { SkASSERT(!fIsTracked); SkASSERT(count <= 4 && count >= 0); const float* valsAsFloats = vals; // Ensure SkScalar == float. @@ -316,7 +312,7 @@ void InstancedRendering::Batch::appendParamsTexel(const SkScalar* vals, int coun fInfo.fHasParams = true; } -void InstancedRendering::Batch::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z, SkScalar w) { +void InstancedRendering::Op::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z, SkScalar w) { SkASSERT(!fIsTracked); ParamsTexel& texel = fParams.push_back(); texel.fX = SkScalarToFloat(x); @@ -326,7 +322,7 @@ void InstancedRendering::Batch::appendParamsTexel(SkScalar x, SkScalar y, SkScal fInfo.fHasParams = true; } -void InstancedRendering::Batch::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z) { +void InstancedRendering::Op::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z) { SkASSERT(!fIsTracked); ParamsTexel& texel = fParams.push_back(); texel.fX = SkScalarToFloat(x); @@ -335,33 +331,32 @@ void InstancedRendering::Batch::appendParamsTexel(SkScalar x, SkScalar y, SkScal fInfo.fHasParams = true; } -void InstancedRendering::Batch::computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const { - color->setKnownFourComponents(this->getSingleInstance().fColor); - - if (AntialiasMode::kCoverage == fInfo.fAntialiasMode || - (AntialiasMode::kNone == fInfo.fAntialiasMode && - !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) { - coverage->setUnknownSingleComponent(); +bool InstancedRendering::Op::xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) { + SkASSERT(State::kRecordingDraws == fInstancedRendering->fState); + GrProcessorAnalysisCoverage coverageInput; + bool isMixedSamples = false; + if (GrAAType::kCoverage == fInfo.aaType() || + (GrAAType::kNone == fInfo.aaType() && !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) { + coverageInput = GrProcessorAnalysisCoverage::kSingleChannel; } else { - coverage->setKnownSingleComponent(255); + coverageInput = GrProcessorAnalysisCoverage::kNone; + isMixedSamples = GrAAType::kMixedSamples == fInfo.aaType(); } -} + GrProcessorSet::Analysis analysis = + fProcessors.finalize(this->getSingleInstance().fColor, coverageInput, clip, + isMixedSamples, caps, &this->getSingleDraw().fInstance.fColor); -void InstancedRendering::Batch::initBatchTracker(const GrXPOverridesForBatch& overrides) { Draw& draw = this->getSingleDraw(); // This will assert if we have > 1 command. SkASSERT(draw.fGeometry.isEmpty()); SkASSERT(SkIsPow2(fInfo.fShapeTypes)); SkASSERT(!fIsTracked); if (kRect_ShapeFlag == fInfo.fShapeTypes) { - draw.fGeometry = InstanceProcessor::GetIndexRangeForRect(fInfo.fAntialiasMode); + draw.fGeometry = InstanceProcessor::GetIndexRangeForRect(fInfo.aaType()); } else if (kOval_ShapeFlag == fInfo.fShapeTypes) { - draw.fGeometry = InstanceProcessor::GetIndexRangeForOval(fInfo.fAntialiasMode, - this->bounds()); + draw.fGeometry = InstanceProcessor::GetIndexRangeForOval(fInfo.aaType(), this->bounds()); } else { - draw.fGeometry = InstanceProcessor::GetIndexRangeForRRect(fInfo.fAntialiasMode); + draw.fGeometry = InstanceProcessor::GetIndexRangeForRRect(fInfo.aaType()); } if (!fParams.empty()) { @@ -370,31 +365,34 @@ void InstancedRendering::Batch::initBatchTracker(const GrXPOverridesForBatch& ov fInstancedRendering->fParams.push_back_n(fParams.count(), fParams.begin()); } - GrColor overrideColor; - if (overrides.getOverrideColorIfSet(&overrideColor)) { - SkASSERT(State::kRecordingDraws == fInstancedRendering->fState); - this->getSingleInstance().fColor = overrideColor; - } - fInfo.fUsesLocalCoords = overrides.readsLocalCoords(); - fInfo.fCannotTweakAlphaForCoverage = !overrides.canTweakAlphaForCoverage(); + fInfo.fCannotTweakAlphaForCoverage = !analysis.isCompatibleWithCoverageAsAlpha(); - fInstancedRendering->fTrackedBatches.addToTail(this); + fInfo.fUsesLocalCoords = analysis.usesLocalCoords(); + fRequiresBarrierOnOverlap = analysis.requiresBarrierBetweenOverlappingDraws(); + return analysis.requiresDstTexture(); +} + +void InstancedRendering::Op::wasRecorded() { + SkASSERT(!fIsTracked); + fInstancedRendering->fTrackedOps.addToTail(this); fIsTracked = true; } -bool InstancedRendering::Batch::onCombineIfPossible(GrBatch* other, const GrCaps& caps) { - Batch* that = static_cast(other); +bool InstancedRendering::Op::onCombineIfPossible(GrOp* other, const GrCaps& caps) { + Op* that = static_cast(other); SkASSERT(fInstancedRendering == that->fInstancedRendering); SkASSERT(fTailDraw); SkASSERT(that->fTailDraw); - if (!BatchInfo::CanCombine(fInfo, that->fInfo) || - !GrPipeline::CanCombine(*this->pipeline(), this->bounds(), - *that->pipeline(), that->bounds(), caps)) { + if (!OpInfo::CanCombine(fInfo, that->fInfo) || fProcessors != that->fProcessors) { return false; } - BatchInfo combinedInfo = fInfo | that->fInfo; + SkASSERT(fRequiresBarrierOnOverlap == that->fRequiresBarrierOnOverlap); + if (fRequiresBarrierOnOverlap && this->bounds().intersects(that->bounds())) { + return false; + } + OpInfo combinedInfo = fInfo | that->fInfo; if (!combinedInfo.isSimpleRects()) { // This threshold was chosen with the "shapes_mixed" bench on a MacBook with Intel graphics. // There seems to be a wide range where it doesn't matter if we combine or not. What matters @@ -411,8 +409,7 @@ bool InstancedRendering::Batch::onCombineIfPossible(GrBatch* other, const GrCaps this->joinBounds(*that); fInfo = combinedInfo; fPixelLoad += that->fPixelLoad; - - // Adopt the other batch's draws. + // Adopt the other op's draws. fNumDraws += that->fNumDraws; fNumChangesInGeometry += that->fNumChangesInGeometry; if (fTailDraw->fGeometry != that->fHeadDraw->fGeometry) { @@ -430,19 +427,19 @@ void InstancedRendering::beginFlush(GrResourceProvider* rp) { SkASSERT(State::kRecordingDraws == fState); fState = State::kFlushing; - if (fTrackedBatches.isEmpty()) { + if (fTrackedOps.isEmpty()) { return; } if (!fVertexBuffer) { - fVertexBuffer.reset(InstanceProcessor::FindOrCreateVertexBuffer(fGpu)); + fVertexBuffer.reset(InstanceProcessor::FindOrCreateVertexBuffer(fGpu.get())); if (!fVertexBuffer) { return; } } if (!fIndexBuffer) { - fIndexBuffer.reset(InstanceProcessor::FindOrCreateIndex8Buffer(fGpu)); + fIndexBuffer.reset(InstanceProcessor::FindOrCreateIndex8Buffer(fGpu.get())); if (!fIndexBuffer) { return; } @@ -462,23 +459,33 @@ void InstancedRendering::beginFlush(GrResourceProvider* rp) { this->onBeginFlush(rp); } -void InstancedRendering::Batch::onDraw(GrBatchFlushState* state) { +void InstancedRendering::Op::onExecute(GrOpFlushState* state) { SkASSERT(State::kFlushing == fInstancedRendering->fState); SkASSERT(state->gpu() == fInstancedRendering->gpu()); state->gpu()->handleDirtyContext(); - if (GrXferBarrierType barrierType = this->pipeline()->xferBarrierType(*state->gpu()->caps())) { - state->gpu()->xferBarrier(this->pipeline()->getRenderTarget(), barrierType); - } - InstanceProcessor instProc(fInfo, fInstancedRendering->fParamsBuffer); - fInstancedRendering->onDraw(*this->pipeline(), instProc, this); + GrPipeline pipeline; + GrPipeline::InitArgs args; + args.fAppliedClip = state->drawOpArgs().fAppliedClip; + args.fCaps = &state->caps(); + args.fProcessors = &fProcessors; + args.fFlags = GrAATypeIsHW(fInfo.aaType()) ? GrPipeline::kHWAntialias_Flag : 0; + args.fRenderTarget = state->drawOpArgs().fRenderTarget; + args.fDstTexture = state->drawOpArgs().fDstTexture; + pipeline.init(args); + + if (GrXferBarrierType barrierType = pipeline.xferBarrierType(*state->gpu()->caps())) { + state->gpu()->xferBarrier(pipeline.getRenderTarget(), barrierType); + } + InstanceProcessor instProc(fInfo, fInstancedRendering->fParamsBuffer.get()); + fInstancedRendering->onDraw(pipeline, instProc, this); } void InstancedRendering::endFlush() { - // The caller is expected to delete all tracked batches (i.e. batches whose initBatchTracker + // The caller is expected to delete all tracked ops (i.e. ops whose applyPipelineOptimizations // method has been called) before ending the flush. - SkASSERT(fTrackedBatches.isEmpty()); + SkASSERT(fTrackedOps.isEmpty()); fParams.reset(); fParamsBuffer.reset(); this->onEndFlush(); diff --git a/gfx/skia/skia/src/gpu/instanced/InstancedRendering.h b/gfx/skia/skia/src/gpu/instanced/InstancedRendering.h index b2c360b25253..a8b9530228fe 100644 --- a/gfx/skia/skia/src/gpu/instanced/InstancedRendering.h +++ b/gfx/skia/skia/src/gpu/instanced/InstancedRendering.h @@ -8,11 +8,12 @@ #ifndef gr_instanced_InstancedRendering_DEFINED #define gr_instanced_InstancedRendering_DEFINED +#include "../private/GrInstancedPipelineInfo.h" +#include "GrGpu.h" #include "GrMemoryPool.h" #include "SkTInternalLList.h" -#include "batches/GrDrawBatch.h" #include "instanced/InstancedRenderingTypes.h" -#include "../private/GrInstancedPipelineInfo.h" +#include "ops/GrDrawOp.h" class GrResourceProvider; @@ -22,11 +23,11 @@ class InstanceProcessor; /** * This class serves as a centralized clearinghouse for instanced rendering. It accumulates data for - * instanced draws into one location, and creates special batches that pull from this data. The - * nature of instanced rendering allows these batches to combine well and render efficiently. + * instanced draws into one location, and creates special ops that pull from this data. The + * nature of instanced rendering allows these ops to combine well and render efficiently. * * During a flush, this class assembles the accumulated draw data into a single vertex and texel - * buffer, and its subclass draws the batches using backend-specific instanced rendering APIs. + * buffer, and its subclass draws the ops using backend-specific instanced rendering APIs. * * This class is responsible for the CPU side of instanced rendering. Shaders are implemented by * InstanceProcessor. @@ -35,47 +36,50 @@ class InstancedRendering : public SkNoncopyable { public: virtual ~InstancedRendering() { SkASSERT(State::kRecordingDraws == fState); } - GrGpu* gpu() const { return fGpu; } + GrGpu* gpu() const { return fGpu.get(); } /** - * These methods make a new record internally for an instanced draw, and return a batch that is - * effectively just an index to that record. The returned batch is not self-contained, but + * These methods make a new record internally for an instanced draw, and return an op that is + * effectively just an index to that record. The returned op is not self-contained, but * rather relies on this class to handle the rendering. The client must call beginFlush() on - * this class before attempting to flush batches returned by it. It is invalid to record new + * this class before attempting to flush ops returned by it. It is invalid to record new * draws between beginFlush() and endFlush(). */ - GrDrawBatch* SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&, GrColor, - bool antialias, const GrInstancedPipelineInfo&, - bool* useHWAA); + std::unique_ptr SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&, + GrPaint&&, GrAA, + const GrInstancedPipelineInfo&); - GrDrawBatch* SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&, GrColor, - const SkRect& localRect, bool antialias, - const GrInstancedPipelineInfo&, bool* useHWAA); + std::unique_ptr SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&, + GrPaint&&, const SkRect& localRect, + GrAA, + const GrInstancedPipelineInfo&); - GrDrawBatch* SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&, GrColor, - const SkMatrix& localMatrix, bool antialias, - const GrInstancedPipelineInfo&, bool* useHWAA); + std::unique_ptr SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&, + GrPaint&&, + const SkMatrix& localMatrix, GrAA, + const GrInstancedPipelineInfo&); - GrDrawBatch* SK_WARN_UNUSED_RESULT recordOval(const SkRect&, const SkMatrix&, GrColor, - bool antialias, const GrInstancedPipelineInfo&, - bool* useHWAA); + std::unique_ptr SK_WARN_UNUSED_RESULT recordOval(const SkRect&, const SkMatrix&, + GrPaint&&, GrAA, + const GrInstancedPipelineInfo&); - GrDrawBatch* SK_WARN_UNUSED_RESULT recordRRect(const SkRRect&, const SkMatrix&, GrColor, - bool antialias, const GrInstancedPipelineInfo&, - bool* useHWAA); + std::unique_ptr SK_WARN_UNUSED_RESULT recordRRect(const SkRRect&, const SkMatrix&, + GrPaint&&, GrAA, + const GrInstancedPipelineInfo&); - GrDrawBatch* SK_WARN_UNUSED_RESULT recordDRRect(const SkRRect& outer, const SkRRect& inner, - const SkMatrix&, GrColor, bool antialias, - const GrInstancedPipelineInfo&, bool* useHWAA); + std::unique_ptr SK_WARN_UNUSED_RESULT recordDRRect(const SkRRect& outer, + const SkRRect& inner, + const SkMatrix&, GrPaint&&, GrAA, + const GrInstancedPipelineInfo&); /** * Compiles all recorded draws into GPU buffers and allows the client to begin flushing the - * batches created by this class. + * ops created by this class. */ void beginFlush(GrResourceProvider*); /** - * Called once the batches created previously by this class have all been released. Allows the + * Called once the ops created previously by this class have all been released. Allows the * client to begin recording draws again. */ void endFlush(); @@ -92,12 +96,31 @@ public: void resetGpuResources(ResetType); protected: - class Batch : public GrDrawBatch { + class Op : public GrDrawOp { public: - SK_DECLARE_INTERNAL_LLIST_INTERFACE(Batch); + SK_DECLARE_INTERNAL_LLIST_INTERFACE(Op); - ~Batch() override; - const char* name() const override { return "Instanced Batch"; } + ~Op() override; + const char* name() const override { return "InstancedRendering::Op"; } + + SkString dumpInfo() const override { + SkString string; + string.printf( + "AA: %d, ShapeTypes: 0x%02x, IShapeTypes: 0x%02x, Persp %d, " + "NonSquare: %d, PLoad: %0.2f, Tracked: %d, NumDraws: %d, " + "GeomChanges: %d\n", + (unsigned)fInfo.fAAType, + fInfo.fShapeTypes, + fInfo.fInnerShapeTypes, + fInfo.fHasPerspective, + fInfo.fNonSquare, + fPixelLoad, + fIsTracked, + fNumDraws, + fNumChangesInGeometry); + string.append(INHERITED::dumpInfo()); + return string; + } struct Draw { Instance fInstance; @@ -112,45 +135,50 @@ protected: void appendParamsTexel(const SkScalar* vals, int count); void appendParamsTexel(SkScalar x, SkScalar y, SkScalar z, SkScalar w); void appendParamsTexel(SkScalar x, SkScalar y, SkScalar z); + FixedFunctionFlags fixedFunctionFlags() const override { + return GrAATypeIsHW(fInfo.aaType()) ? FixedFunctionFlags::kUsesHWAA + : FixedFunctionFlags::kNone; + } + bool xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*) override; + + // Registers the op with the InstancedRendering list of tracked ops. + void wasRecorded() override; protected: - Batch(uint32_t classID, InstancedRendering* ir); + Op(uint32_t classID, GrPaint&&, InstancedRendering*); - void initBatchTracker(const GrXPOverridesForBatch&) override; - bool onCombineIfPossible(GrBatch* other, const GrCaps& caps) override; + InstancedRendering* const fInstancedRendering; + OpInfo fInfo; + SkScalar fPixelLoad; + GrProcessorSet fProcessors; + SkSTArray<5, ParamsTexel, true> fParams; + bool fIsTracked : 1; + bool fRequiresBarrierOnOverlap : 1; + int fNumDraws; + int fNumChangesInGeometry; + Draw* fHeadDraw; + Draw* fTailDraw; - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides*) const override; + private: + bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override; + void onPrepare(GrOpFlushState*) override {} + void onExecute(GrOpFlushState*) override; - void onPrepare(GrBatchFlushState*) override {} - void onDraw(GrBatchFlushState*) override; - - InstancedRendering* const fInstancedRendering; - BatchInfo fInfo; - SkScalar fPixelLoad; - SkSTArray<5, ParamsTexel, true> fParams; - bool fIsTracked; - int fNumDraws; - int fNumChangesInGeometry; - Draw* fHeadDraw; - Draw* fTailDraw; - - typedef GrDrawBatch INHERITED; + typedef GrDrawOp INHERITED; friend class InstancedRendering; }; - typedef SkTInternalLList BatchList; + typedef SkTInternalLList OpList; InstancedRendering(GrGpu* gpu); - const BatchList& trackedBatches() const { return fTrackedBatches; } - const GrBuffer* vertexBuffer() const { SkASSERT(fVertexBuffer); return fVertexBuffer; } - const GrBuffer* indexBuffer() const { SkASSERT(fIndexBuffer); return fIndexBuffer; } + const OpList& trackedOps() const { return fTrackedOps; } + const GrBuffer* vertexBuffer() const { SkASSERT(fVertexBuffer); return fVertexBuffer.get(); } + const GrBuffer* indexBuffer() const { SkASSERT(fIndexBuffer); return fIndexBuffer.get(); } virtual void onBeginFlush(GrResourceProvider*) = 0; - virtual void onDraw(const GrPipeline&, const InstanceProcessor&, const Batch*) = 0; + virtual void onDraw(const GrPipeline&, const InstanceProcessor&, const Op*) = 0; virtual void onEndFlush() = 0; virtual void onResetGpuResources(ResetType) = 0; @@ -160,24 +188,24 @@ private: kFlushing }; - Batch* SK_WARN_UNUSED_RESULT recordShape(ShapeType, const SkRect& bounds, - const SkMatrix& viewMatrix, GrColor, - const SkRect& localRect, bool antialias, - const GrInstancedPipelineInfo&, bool* requireHWAA); + std::unique_ptr SK_WARN_UNUSED_RESULT recordShape(ShapeType, const SkRect& bounds, + const SkMatrix& viewMatrix, GrPaint&&, + const SkRect& localRect, GrAA aa, + const GrInstancedPipelineInfo&); - bool selectAntialiasMode(const SkMatrix& viewMatrix, bool antialias, - const GrInstancedPipelineInfo&, bool* useHWAA, AntialiasMode*); + bool selectAntialiasMode(const SkMatrix& viewMatrix, GrAA aa, const GrInstancedPipelineInfo&, + GrAAType*); - virtual Batch* createBatch() = 0; + virtual std::unique_ptr makeOp(GrPaint&&) = 0; - const SkAutoTUnref fGpu; - State fState; - GrMemoryPool fDrawPool; - SkSTArray<1024, ParamsTexel, true> fParams; - BatchList fTrackedBatches; - SkAutoTUnref fVertexBuffer; - SkAutoTUnref fIndexBuffer; - SkAutoTUnref fParamsBuffer; + const sk_sp fGpu; + State fState; + GrObjectMemoryPool fDrawPool; + SkSTArray<1024, ParamsTexel, true> fParams; + OpList fTrackedOps; + sk_sp fVertexBuffer; + sk_sp fIndexBuffer; + sk_sp fParamsBuffer; }; } diff --git a/gfx/skia/skia/src/gpu/instanced/InstancedRenderingTypes.h b/gfx/skia/skia/src/gpu/instanced/InstancedRenderingTypes.h index 97f8946d0333..55102fce8e08 100644 --- a/gfx/skia/skia/src/gpu/instanced/InstancedRenderingTypes.h +++ b/gfx/skia/skia/src/gpu/instanced/InstancedRenderingTypes.h @@ -9,6 +9,7 @@ #define gr_instanced_InstancedRenderingTypes_DEFINED #include "GrTypes.h" +#include "GrTypesPriv.h" #include "SkRRect.h" namespace gr_instanced { @@ -42,14 +43,6 @@ enum class Attrib : uint8_t { }; constexpr int kNumAttribs = 1 + (int)Attrib::kLocalRect; -enum class AntialiasMode : uint8_t { - kNone, - kCoverage, - kMSAA, - kMixedSamples -}; -constexpr int kNumAntialiasModes = 1 + (int)AntialiasMode::kMixedSamples; - enum class ShapeType : uint8_t { kRect, kOval, @@ -119,22 +112,25 @@ GR_STATIC_ASSERT(0 == offsetof(ParamsTexel, fX)); GR_STATIC_ASSERT(4 * 4 == sizeof(ParamsTexel)); /** - * Tracks all information needed in order to draw a batch of instances. This struct also serves - * as an all-in-one shader key for the batch. + * Tracks all information needed in order to draw a op of instances. This struct also serves + * as an all-in-one shader key for the op. */ -struct BatchInfo { - BatchInfo() : fData(0) {} - explicit BatchInfo(uint32_t data) : fData(data) {} +struct OpInfo { + OpInfo() : fData(0) {} + explicit OpInfo(uint32_t data) : fData(data) {} - static bool CanCombine(const BatchInfo& a, const BatchInfo& b); + static bool CanCombine(const OpInfo& a, const OpInfo& b); bool isSimpleRects() const { return !((fShapeTypes & ~kRect_ShapeFlag) | fInnerShapeTypes); } + GrAAType aaType() const { return static_cast(fAAType); } + void setAAType(GrAAType aaType) { fAAType = static_cast(aaType); } + union { struct { - AntialiasMode fAntialiasMode; + uint8_t fAAType; // GrAAType uint8_t fShapeTypes; uint8_t fInnerShapeTypes; bool fHasPerspective : 1; @@ -149,8 +145,8 @@ struct BatchInfo { }; }; -inline bool BatchInfo::CanCombine(const BatchInfo& a, const BatchInfo& b) { - if (a.fAntialiasMode != b.fAntialiasMode) { +inline bool OpInfo::CanCombine(const OpInfo& a, const OpInfo& b) { + if (a.fAAType != b.fAAType) { return false; } if (SkToBool(a.fInnerShapeTypes) != SkToBool(b.fInnerShapeTypes)) { @@ -164,13 +160,13 @@ inline bool BatchInfo::CanCombine(const BatchInfo& a, const BatchInfo& b) { return true; } -inline BatchInfo operator|(const BatchInfo& a, const BatchInfo& b) { - SkASSERT(BatchInfo::CanCombine(a, b)); - return BatchInfo(a.fData | b.fData); +inline OpInfo operator|(const OpInfo& a, const OpInfo& b) { + SkASSERT(OpInfo::CanCombine(a, b)); + return OpInfo(a.fData | b.fData); } // This is required since all the data must fit into 32 bits of a shader key. -GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(BatchInfo)); +GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(OpInfo)); GR_STATIC_ASSERT(kNumShapeTypes <= 8); struct IndexRange { diff --git a/gfx/skia/skia/src/gpu/batches/GrAAConvexPathRenderer.cpp b/gfx/skia/skia/src/gpu/ops/GrAAConvexPathRenderer.cpp similarity index 83% rename from gfx/skia/skia/src/gpu/batches/GrAAConvexPathRenderer.cpp rename to gfx/skia/skia/src/gpu/ops/GrAAConvexPathRenderer.cpp index c71f46de6628..efc6622c1532 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAAConvexPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrAAConvexPathRenderer.cpp @@ -8,27 +8,26 @@ #include "GrAAConvexPathRenderer.h" #include "GrAAConvexTessellator.h" -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" #include "GrCaps.h" #include "GrContext.h" #include "GrDefaultGeoProcFactory.h" +#include "GrDrawOpTest.h" #include "GrGeometryProcessor.h" -#include "GrInvariantOutput.h" +#include "GrOpFlushState.h" #include "GrPathUtils.h" -#include "GrProcessor.h" #include "GrPipelineBuilder.h" +#include "GrProcessor.h" #include "SkGeometry.h" #include "SkPathPriv.h" #include "SkString.h" #include "SkTraceEvent.h" -#include "batches/GrVertexBatch.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" #include "glsl/GrGLSLVertexShaderBuilder.h" +#include "ops/GrMeshDrawOp.h" GrAAConvexPathRenderer::GrAAConvexPathRenderer() { } @@ -184,7 +183,7 @@ struct DegenerateTestData { }; static const SkScalar kClose = (SK_Scalar1 / 16); -static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose); +static const SkScalar kCloseSqd = kClose * kClose; static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) { switch (data->fStage) { @@ -219,8 +218,8 @@ static inline bool get_direction(const SkPath& path, const SkMatrix& m, } // check whether m reverses the orientation SkASSERT(!m.hasPerspective()); - SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) - - SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY)); + SkScalar det2x2 = m.get(SkMatrix::kMScaleX) * m.get(SkMatrix::kMScaleY) - + m.get(SkMatrix::kMSkewX) * m.get(SkMatrix::kMSkewY); if (det2x2 < 0) { *dir = SkPathPriv::OppositeFirstDirection(*dir); } @@ -282,7 +281,7 @@ static bool get_segments(const SkPath& path, for (;;) { SkPoint pts[4]; - SkPath::Verb verb = iter.next(pts); + SkPath::Verb verb = iter.next(pts, true, true); switch (verb) { case SkPath::kMove_Verb: m.mapPoints(pts, 1); @@ -531,21 +530,19 @@ public: return sk_sp(new QuadEdgeEffect(color, localMatrix, usesLocalCoords)); } - virtual ~QuadEdgeEffect() {} + ~QuadEdgeEffect() override {} const char* name() const override { return "QuadEdge"; } const Attribute* inPosition() const { return fInPosition; } const Attribute* inQuadEdge() const { return fInQuadEdge; } GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } const SkMatrix& localMatrix() const { return fLocalMatrix; } bool usesLocalCoords() const { return fUsesLocalCoords; } class GLSLProcessor : public GrGLSLGeometryProcessor { public: - GLSLProcessor() - : fColor(GrColor_ILLEGAL) {} + GLSLProcessor() : fColor(GrColor_ILLEGAL) {} void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const QuadEdgeEffect& qe = args.fGP.cast(); @@ -562,10 +559,8 @@ public: GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color - if (!qe.colorIgnored()) { - this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, - &fColorUniform); - } + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, + &fColorUniform); // Setup position this->setupPosition(vertBuilder, gpArgs, qe.inPosition()->fName); @@ -579,8 +574,6 @@ public: qe.localMatrix(), args.fFPCoordTransformHandler); - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); fragBuilder->codeAppendf("float edgeAlpha;"); // keep the derivative instructions outside the conditional @@ -603,13 +596,10 @@ public: } static inline void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const QuadEdgeEffect& qee = gp.cast(); - uint32_t key = 0; - key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ? 0x1 : 0x0; - key |= qee.colorIgnored() ? 0x2 : 0x0; - b->add32(key); + b->add32(SkToBool(qee.usesLocalCoords() && qee.localMatrix().hasPerspective())); } void setData(const GrGLSLProgramDataManager& pdman, @@ -632,11 +622,11 @@ public: typedef GrGLSLGeometryProcessor INHERITED; }; - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLProcessor::GenKey(*this, caps, b); } - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { return new GLSLProcessor(); } @@ -663,18 +653,21 @@ private: GR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect); +#if GR_TEST_UTILS sk_sp QuadEdgeEffect::TestCreate(GrProcessorTestData* d) { // Doesn't work without derivative instructions. - return d->fCaps->shaderCaps()->shaderDerivativeSupport() ? - QuadEdgeEffect::Make(GrRandomColor(d->fRandom), - GrTest::TestMatrix(d->fRandom), - d->fRandom->nextBool()) : nullptr; + return d->caps()->shaderCaps()->shaderDerivativeSupport() + ? QuadEdgeEffect::Make(GrRandomColor(d->fRandom), + GrTest::TestMatrix(d->fRandom), + d->fRandom->nextBool()) + : nullptr; } +#endif /////////////////////////////////////////////////////////////////////////////// bool GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - return (args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias && + return (args.fShaderCaps->shaderDerivativeSupport() && (GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() && !args.fShape->inverseFilled() && args.fShape->knownToBeConvex()); } @@ -714,71 +707,66 @@ static void extract_verts(const GrAAConvexTessellator& tess, static sk_sp create_fill_gp(bool tweakAlphaForCoverage, const SkMatrix& viewMatrix, - bool usesLocalCoords, - bool coverageIgnored) { + bool usesLocalCoords) { using namespace GrDefaultGeoProcFactory; - Color color(Color::kAttribute_Type); Coverage::Type coverageType; - // TODO remove coverage if coverage is ignored - /*if (coverageIgnored) { - coverageType = Coverage::kNone_Type; - } else*/ if (tweakAlphaForCoverage) { + if (tweakAlphaForCoverage) { coverageType = Coverage::kSolid_Type; } else { coverageType = Coverage::kAttribute_Type; } - Coverage coverage(coverageType); - LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type : - LocalCoords::kUnused_Type); - return MakeForDeviceSpace(color, coverage, localCoords, viewMatrix); + LocalCoords::Type localCoordsType = + usesLocalCoords ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type; + return MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type, coverageType, localCoordsType, + viewMatrix); } -class AAConvexPathBatch : public GrVertexBatch { +class AAConvexPathOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID - AAConvexPathBatch(GrColor color, const SkMatrix& viewMatrix, const SkPath& path) - : INHERITED(ClassID()) { - fGeoData.emplace_back(Geometry{color, viewMatrix, path}); - this->setTransformedBounds(path.getBounds(), viewMatrix, HasAABloat::kYes, - IsZeroArea::kNo); + DEFINE_OP_CLASS_ID + static std::unique_ptr Make(GrColor color, const SkMatrix& viewMatrix, + const SkPath& path) { + return std::unique_ptr(new AAConvexPathOp(color, viewMatrix, path)); } - const char* name() const override { return "AAConvexBatch"; } + const char* name() const override { return "AAConvexPathOp"; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); + SkString dumpInfo() const override { + SkString string; + string.appendf("Color: 0x%08x, Count: %d\n", fColor, fPaths.count()); + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; } private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any color overrides - if (!overrides.readsColor()) { - fGeoData[0].fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); + AAConvexPathOp(GrColor color, const SkMatrix& viewMatrix, const SkPath& path) + : INHERITED(ClassID()), fColor(color) { + fPaths.emplace_back(PathData{viewMatrix, path}); + this->setTransformedBounds(path.getBounds(), viewMatrix, HasAABloat::kYes, IsZeroArea::kNo); + } - // setup batch properties - fBatch.fColorIgnored = !overrides.readsColor(); - fBatch.fColor = fGeoData[0].fColor; - fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); - fBatch.fCoverageIgnored = !overrides.readsCoverage(); - fBatch.fLinesOnly = SkPath::kLine_SegmentMask == fGeoData[0].fPath.getSegmentMasks(); - fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage(); + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fColor); + + fUsesLocalCoords = optimizations.readsLocalCoords(); + fLinesOnly = SkPath::kLine_SegmentMask == fPaths[0].fPath.getSegmentMasks(); + fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage(); } void prepareLinesOnlyDraws(Target* target) const { bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage(); // Setup GrGeometryProcessor - sk_sp gp(create_fill_gp(canTweakAlphaForCoverage, - this->viewMatrix(), - this->usesLocalCoords(), - this->coverageIgnored())); + sk_sp gp(create_fill_gp( + canTweakAlphaForCoverage, this->viewMatrix(), this->usesLocalCoords())); if (!gp) { SkDebugf("Could not create GrGeometryProcessor\n"); return; @@ -792,12 +780,12 @@ private: GrAAConvexTessellator tess; - int instanceCount = fGeoData.count(); + int instanceCount = fPaths.count(); for (int i = 0; i < instanceCount; i++) { tess.rewind(); - const Geometry& args = fGeoData[i]; + const PathData& args = fPaths[i]; if (!tess.tessellate(args.fViewMatrix, args.fPath)) { continue; @@ -822,14 +810,14 @@ private: return; } - extract_verts(tess, verts, vertexStride, args.fColor, idxs, canTweakAlphaForCoverage); + extract_verts(tess, verts, vertexStride, fColor, idxs, canTweakAlphaForCoverage); GrMesh mesh; mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex, tess.numPts(), tess.numIndices()); - target->draw(gp.get(), mesh); + target->draw(gp.get(), this->pipeline(), mesh); } } @@ -841,7 +829,7 @@ private: } #endif - int instanceCount = fGeoData.count(); + int instanceCount = fPaths.count(); SkMatrix invert; if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { @@ -855,7 +843,7 @@ private: // TODO generate all segments for all paths and use one vertex buffer for (int i = 0; i < instanceCount; i++) { - const Geometry& args = fGeoData[i]; + const PathData& args = fPaths[i]; // We use the fact that SkPath::transform path does subdivision based on // perspective. Otherwise, we apply the view matrix when copying to the @@ -917,15 +905,15 @@ private: const Draw& draw = draws[j]; mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex, draw.fVertexCnt, draw.fIndexCnt); - target->draw(quadProcessor.get(), mesh); + target->draw(quadProcessor.get(), this->pipeline(), mesh); firstVertex += draw.fVertexCnt; firstIndex += draw.fIndexCnt; } } } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - AAConvexPathBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + AAConvexPathOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; @@ -944,61 +932,55 @@ private: return false; } - // In the event of two batches, one who can tweak, one who cannot, we just fall back to - // not tweaking + // In the event of two ops, one who can tweak, one who cannot, we just fall back to not + // tweaking if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) { - fBatch.fCanTweakAlphaForCoverage = false; + fCanTweakAlphaForCoverage = false; } - fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); + fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin()); this->joinBounds(*that); return true; } - GrColor color() const { return fBatch.fColor; } - bool linesOnly() const { return fBatch.fLinesOnly; } - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } - bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; } - const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } - bool coverageIgnored() const { return fBatch.fCoverageIgnored; } + GrColor color() const { return fColor; } + bool linesOnly() const { return fLinesOnly; } + bool usesLocalCoords() const { return fUsesLocalCoords; } + bool canTweakAlphaForCoverage() const { return fCanTweakAlphaForCoverage; } + const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; } - struct BatchTracker { - GrColor fColor; - bool fUsesLocalCoords; - bool fColorIgnored; - bool fCoverageIgnored; - bool fLinesOnly; - bool fCanTweakAlphaForCoverage; - }; + GrColor fColor; + bool fUsesLocalCoords; + bool fLinesOnly; + bool fCanTweakAlphaForCoverage; - struct Geometry { - GrColor fColor; + struct PathData { SkMatrix fViewMatrix; SkPath fPath; }; - BatchTracker fBatch; - SkSTArray<1, Geometry, true> fGeoData; + SkSTArray<1, PathData, true> fPaths; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; bool GrAAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrAAConvexPathRenderer::onDrawPath"); - SkASSERT(!args.fDrawContext->isUnifiedMultisampled()); + SkASSERT(!args.fRenderTargetContext->isUnifiedMultisampled()); SkASSERT(!args.fShape->isEmpty()); SkPath path; args.fShape->asPath(&path); - SkAutoTUnref batch(new AAConvexPathBatch(args.fPaint->getColor(), - *args.fViewMatrix, path)); + std::unique_ptr op = + AAConvexPathOp::Make(args.fPaint.getColor(), *args.fViewMatrix, path); - GrPipelineBuilder pipelineBuilder(*args.fPaint); + GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), args.fAAType); pipelineBuilder.setUserStencil(args.fUserStencilSettings); - args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); + args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip, + std::move(op)); return true; @@ -1006,14 +988,14 @@ bool GrAAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -DRAW_BATCH_TEST_DEFINE(AAConvexPathBatch) { +DRAW_OP_TEST_DEFINE(AAConvexPathOp) { GrColor color = GrRandomColor(random); SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); SkPath path = GrTest::TestPathConvex(random); - return new AAConvexPathBatch(color, viewMatrix, path); + return AAConvexPathOp::Make(color, viewMatrix, path); } #endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAAConvexPathRenderer.h b/gfx/skia/skia/src/gpu/ops/GrAAConvexPathRenderer.h similarity index 100% rename from gfx/skia/skia/src/gpu/batches/GrAAConvexPathRenderer.h rename to gfx/skia/skia/src/gpu/ops/GrAAConvexPathRenderer.h diff --git a/gfx/skia/skia/src/gpu/batches/GrAAConvexTessellator.cpp b/gfx/skia/skia/src/gpu/ops/GrAAConvexTessellator.cpp similarity index 99% rename from gfx/skia/skia/src/gpu/batches/GrAAConvexTessellator.cpp rename to gfx/skia/skia/src/gpu/ops/GrAAConvexTessellator.cpp index b9c44ff9b7ec..5fa07fbcf969 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAAConvexTessellator.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrAAConvexTessellator.cpp @@ -19,7 +19,7 @@ // The tolerance for fusing vertices and eliminating colinear lines (It is in device space). static const SkScalar kClose = (SK_Scalar1 / 16); -static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose); +static const SkScalar kCloseSqd = kClose * kClose; // tesselation tolerance values, in device space pixels static const SkScalar kQuadTolerance = 0.2f; @@ -365,7 +365,7 @@ bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat SkPath::Iter iter(path, true); SkPoint pts[4]; SkPath::Verb verb; - while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { + while ((verb = iter.next(pts, true, true)) != SkPath::kDone_Verb) { switch (verb) { case SkPath::kLine_Verb: this->lineTo(m, pts[1], kSharp_CurveState); @@ -503,9 +503,9 @@ void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o int prev = numPts - 1; int lastPerpIdx = -1, firstPerpIdx = -1; - const SkScalar outsetSq = SkScalarMul(outset, outset); - SkScalar miterLimitSq = SkScalarMul(outset, fMiterLimit); - miterLimitSq = SkScalarMul(miterLimitSq, miterLimitSq); + const SkScalar outsetSq = outset * outset; + SkScalar miterLimitSq = outset * fMiterLimit; + miterLimitSq = miterLimitSq * miterLimitSq; for (int cur = 0; cur < numPts; ++cur) { int originalIdx = previousRing.index(cur); // For each vertex of the original polygon we add at least two points to the diff --git a/gfx/skia/skia/src/gpu/batches/GrAAConvexTessellator.h b/gfx/skia/skia/src/gpu/ops/GrAAConvexTessellator.h similarity index 100% rename from gfx/skia/skia/src/gpu/batches/GrAAConvexTessellator.h rename to gfx/skia/skia/src/gpu/ops/GrAAConvexTessellator.h diff --git a/gfx/skia/skia/src/gpu/batches/GrAAFillRectBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrAAFillRectOp.cpp similarity index 61% rename from gfx/skia/skia/src/gpu/batches/GrAAFillRectBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrAAFillRectOp.cpp index 4f93adf07429..15fb645abca3 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAAFillRectBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrAAFillRectOp.cpp @@ -5,24 +5,22 @@ * found in the LICENSE file. */ -#include "GrAAFillRectBatch.h" +#include "GrAAFillRectOp.h" -#include "GrBatchFlushState.h" #include "GrColor.h" #include "GrDefaultGeoProcFactory.h" +#include "GrMeshDrawOp.h" +#include "GrOpFlushState.h" #include "GrResourceKey.h" #include "GrResourceProvider.h" #include "GrTypes.h" -#include "GrVertexBatch.h" #include "SkMatrix.h" #include "SkRect.h" GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey); -static void set_inset_fan(SkPoint* pts, size_t stride, - const SkRect& r, SkScalar dx, SkScalar dy) { - pts->setRectFan(r.fLeft + dx, r.fTop + dy, - r.fRight - dx, r.fBottom - dy, stride); +static void set_inset_fan(SkPoint* pts, size_t stride, const SkRect& r, SkScalar dx, SkScalar dy) { + pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride); } static const int kNumAAFillRectsInIndexBuffer = 256; @@ -32,6 +30,7 @@ static const int kIndicesPerAAFillRect = 30; const GrBuffer* get_index_buffer(GrResourceProvider* resourceProvider) { GR_DEFINE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey); + // clang-format off static const uint16_t gFillAARectIdx[] = { 0, 1, 5, 5, 4, 0, 1, 2, 6, 6, 5, 1, @@ -39,10 +38,12 @@ const GrBuffer* get_index_buffer(GrResourceProvider* resourceProvider) { 3, 0, 4, 4, 7, 3, 4, 5, 6, 6, 7, 4, }; + // clang-format on + GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFillAARectIdx) == kIndicesPerAAFillRect); - return resourceProvider->findOrCreateInstancedIndexBuffer(gFillAARectIdx, - kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer, kVertsPerAAFillRect, - gAAFillRectIndexBufferKey); + return resourceProvider->findOrCreateInstancedIndexBuffer( + gFillAARectIdx, kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer, + kVertsPerAAFillRect, gAAFillRectIndexBufferKey); } static void generate_aa_fill_rect_geometry(intptr_t verts, @@ -51,7 +52,7 @@ static void generate_aa_fill_rect_geometry(intptr_t verts, const SkMatrix& viewMatrix, const SkRect& rect, const SkRect& devRect, - const GrXPOverridesForBatch& overrides, + bool tweakAlphaForCoverage, const SkMatrix* localMatrix) { SkPoint* fan0Pos = reinterpret_cast(verts); SkPoint* fan1Pos = reinterpret_cast(verts + 4 * vertexStride); @@ -63,13 +64,11 @@ static void generate_aa_fill_rect_geometry(intptr_t verts, inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height()); set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf); - set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset); + set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset); } else { // compute transformed (1, 0) and (0, 1) vectors - SkVector vec[2] = { - { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] }, - { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] } - }; + SkVector vec[2] = {{viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY]}, + {viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY]}}; SkScalar len1 = SkPoint::Normalize(&vec[0]); vec[0].scale(SK_ScalarHalf); @@ -80,8 +79,7 @@ static void generate_aa_fill_rect_geometry(intptr_t verts, inset = SK_ScalarHalf * SkMinScalar(inset, len2 * rect.height()); // create the rotated rect - fan0Pos->setRectFan(rect.fLeft, rect.fTop, - rect.fRight, rect.fBottom, vertexStride); + fan0Pos->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4); // Now create the inset points and then outset the original @@ -89,19 +87,19 @@ static void generate_aa_fill_rect_geometry(intptr_t verts, // TL *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) = - *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1]; + *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1]; // BL *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) = - *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1]; + *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1]; // BR *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) = - *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1]; + *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1]; // TR *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) = - *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1]; + *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1]; *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1]; } @@ -117,8 +115,6 @@ static void generate_aa_fill_rect_geometry(intptr_t verts, localCoordMatrix.mapPointsWithStride(fan0Loc, fan0Pos, vertexStride, 8); } - bool tweakAlphaForCoverage = overrides.canTweakAlphaForCoverage(); - // Make verts point to vertex color and then set all the color and coverage vertex attrs // values. verts += sizeof(SkPoint); @@ -152,20 +148,21 @@ static void generate_aa_fill_rect_geometry(intptr_t verts, *reinterpret_cast(verts + i * vertexStride) = scaledColor; } else { *reinterpret_cast(verts + i * vertexStride) = color; - *reinterpret_cast(verts + i * vertexStride + - coverageOffset) = innerCoverage; + *reinterpret_cast(verts + i * vertexStride + coverageOffset) = innerCoverage; } } } -class AAFillRectBatch : public GrVertexBatch { -public: - DEFINE_BATCH_CLASS_ID - AAFillRectBatch(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& devRect, - const SkMatrix* localMatrix) : INHERITED(ClassID()) { +class AAFillRectOp final : public GrLegacyMeshDrawOp { +public: + DEFINE_OP_CLASS_ID + + AAFillRectOp(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect& devRect, + const SkMatrix* localMatrix) + : INHERITED(ClassID()) { if (localMatrix) { void* mem = fRectData.push_back_n(sizeof(RectWithLocalMatrixInfo)); new (mem) RectWithLocalMatrixInfo(color, viewMatrix, rect, devRect, *localMatrix); @@ -173,61 +170,59 @@ public: void* mem = fRectData.push_back_n(sizeof(RectInfo)); new (mem) RectInfo(color, viewMatrix, rect, devRect); } - IsZeroArea zeroArea = (!rect.width() || !rect.height()) ? IsZeroArea::kYes - : IsZeroArea::kNo; + IsZeroArea zeroArea = + (!rect.width() || !rect.height()) ? IsZeroArea::kYes : IsZeroArea::kNo; this->setBounds(devRect, HasAABloat::kYes, zeroArea); fRectCnt = 1; } - const char* name() const override { return "AAFillRectBatch"; } + const char* name() const override { return "AAFillRectOp"; } SkString dumpInfo() const override { SkString str; - str.appendf("# batched: %d\n", fRectCnt); + str.appendf("# combined: %d\n", fRectCnt); const RectInfo* info = this->first(); for (int i = 0; i < fRectCnt; ++i) { const SkRect& rect = info->rect(); - str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", - i, info->color(), rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); + str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i, + info->color(), rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); info = this->next(info); } + str.append(DumpPipelineInfo(*this->pipeline())); str.append(INHERITED::dumpInfo()); return str; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one rect - color->setKnownFourComponents(this->first()->color()); - coverage->setUnknownSingleComponent(); - } - - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { GrColor color; - if (overrides.getOverrideColorIfSet(&color)) { + if (optimizations.getOverrideColorIfSet(&color)) { this->first()->setColor(color); } - fOverrides = overrides; + fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage(); + fNeedsLocalCoords = optimizations.readsLocalCoords(); } private: + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(this->first()->color()); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } + void onPrepareDraws(Target* target) const override { - bool needLocalCoords = fOverrides.readsLocalCoords(); using namespace GrDefaultGeoProcFactory; - Color color(Color::kAttribute_Type); + Color color(Color::kPremulGrColorAttribute_Type); Coverage::Type coverageType; - if (fOverrides.canTweakAlphaForCoverage()) { + if (fCanTweakAlphaForCoverage) { coverageType = Coverage::kSolid_Type; } else { coverageType = Coverage::kAttribute_Type; } - Coverage coverage(coverageType); - LocalCoords lc = needLocalCoords ? LocalCoords::kHasExplicit_Type - : LocalCoords::kUnused_Type; - sk_sp gp = GrDefaultGeoProcFactory::Make(color, coverage, lc, - SkMatrix::I()); + LocalCoords lc = + fNeedsLocalCoords ? LocalCoords::kHasExplicit_Type : LocalCoords::kUnused_Type; + sk_sp gp = + GrDefaultGeoProcFactory::Make(color, coverageType, lc, SkMatrix::I()); if (!gp) { SkDebugf("Couldn't create GrGeometryProcessor\n"); return; @@ -235,11 +230,11 @@ private: size_t vertexStride = gp->getVertexStride(); - SkAutoTUnref indexBuffer(get_index_buffer(target->resourceProvider())); + sk_sp indexBuffer(get_index_buffer(target->resourceProvider())); InstancedHelper helper; - void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, - indexBuffer, kVertsPerAAFillRect, - kIndicesPerAAFillRect, fRectCnt); + void* vertices = + helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(), + kVertsPerAAFillRect, kIndicesPerAAFillRect, fRectCnt); if (!vertices || !indexBuffer) { SkDebugf("Could not allocate vertices\n"); return; @@ -248,34 +243,36 @@ private: const RectInfo* info = this->first(); const SkMatrix* localMatrix = nullptr; for (int i = 0; i < fRectCnt; i++) { - intptr_t verts = reinterpret_cast(vertices) + - i * kVertsPerAAFillRect * vertexStride; - if (needLocalCoords) { + intptr_t verts = + reinterpret_cast(vertices) + i * kVertsPerAAFillRect * vertexStride; + if (fNeedsLocalCoords) { if (info->hasLocalMatrix()) { localMatrix = &static_cast(info)->localMatrix(); } else { localMatrix = &SkMatrix::I(); } } - generate_aa_fill_rect_geometry(verts, vertexStride, info->color(), - info->viewMatrix(), info->rect(), - info->devRect(), fOverrides, localMatrix); + generate_aa_fill_rect_geometry(verts, vertexStride, info->color(), info->viewMatrix(), + info->rect(), info->devRect(), fCanTweakAlphaForCoverage, + localMatrix); info = this->next(info); } - helper.recordDraw(target, gp.get()); + helper.recordDraw(target, gp.get(), this->pipeline()); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - AAFillRectBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + AAFillRectOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; } - // In the event of two batches, one who can tweak, one who cannot, we just fall back to - // not tweaking - if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) { - fOverrides = that->fOverrides; + SkASSERT(fNeedsLocalCoords == that->fNeedsLocalCoords); + + // In the event of two ops, one who can tweak, one who cannot, we just fall back to not + // tweaking. + if (fCanTweakAlphaForCoverage && !that->fCanTweakAlphaForCoverage) { + fCanTweakAlphaForCoverage = false; } fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin()); @@ -288,7 +285,7 @@ private: public: RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, const SkRect& devRect) - : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {} + : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {} bool hasLocalMatrix() const { return HasLocalMatrix::kYes == fHasLocalMatrix; } GrColor color() const { return fColor; } const SkMatrix& viewMatrix() const { return fViewMatrix; } @@ -296,6 +293,7 @@ private: const SkRect& devRect() const { return fDevRect; } void setColor(GrColor color) { fColor = color; } + protected: enum class HasLocalMatrix : uint32_t { kNo, kYes }; @@ -318,9 +316,10 @@ private: public: RectWithLocalMatrixInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, const SkRect& devRect, const SkMatrix& localMatrix) - : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes) - , fLocalMatrix(localMatrix) {} + : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes) + , fLocalMatrix(localMatrix) {} const SkMatrix& localMatrix() const { return fLocalMatrix; } + private: SkMatrix fLocalMatrix; }; @@ -328,81 +327,83 @@ private: RectInfo* first() { return reinterpret_cast(fRectData.begin()); } const RectInfo* first() const { return reinterpret_cast(fRectData.begin()); } const RectInfo* next(const RectInfo* prev) const { - intptr_t next = reinterpret_cast(prev) + - (prev->hasLocalMatrix() ? sizeof(RectWithLocalMatrixInfo) - : sizeof(RectInfo)); + intptr_t next = + reinterpret_cast(prev) + + (prev->hasLocalMatrix() ? sizeof(RectWithLocalMatrixInfo) : sizeof(RectInfo)); return reinterpret_cast(next); } - GrXPOverridesForBatch fOverrides; + bool fNeedsLocalCoords; + bool fCanTweakAlphaForCoverage; SkSTArray<4 * sizeof(RectWithLocalMatrixInfo), uint8_t, true> fRectData; int fRectCnt; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -namespace GrAAFillRectBatch { +namespace GrAAFillRectOp { -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& devRect) { - return new AAFillRectBatch(color, viewMatrix, rect, devRect, nullptr); +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect& devRect) { + return std::unique_ptr( + new AAFillRectOp(color, viewMatrix, rect, devRect, nullptr)); } -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkMatrix& localMatrix, - const SkRect& rect, - const SkRect& devRect) { - return new AAFillRectBatch(color, viewMatrix, rect, devRect, &localMatrix); +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, + const SkRect& rect, + const SkRect& devRect) { + return std::unique_ptr( + new AAFillRectOp(color, viewMatrix, rect, devRect, &localMatrix)); } -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkMatrix& localMatrix, - const SkRect& rect) { +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, + const SkRect& rect) { SkRect devRect; viewMatrix.mapRect(&devRect, rect); - return Create(color, viewMatrix, localMatrix, rect, devRect); + return Make(color, viewMatrix, localMatrix, rect, devRect); } -GrDrawBatch* CreateWithLocalRect(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& localRect) { +std::unique_ptr MakeWithLocalRect(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect& localRect) { SkRect devRect; viewMatrix.mapRect(&devRect, rect); SkMatrix localMatrix; if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) { return nullptr; } - return Create(color, viewMatrix, localMatrix, rect, devRect); + return Make(color, viewMatrix, localMatrix, rect, devRect); } - }; /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -#include "GrBatchTest.h" +#include "GrDrawOpTest.h" -DRAW_BATCH_TEST_DEFINE(AAFillRectBatch) { +DRAW_OP_TEST_DEFINE(AAFillRectOp) { GrColor color = GrRandomColor(random); SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); SkRect rect = GrTest::TestRect(random); SkRect devRect = GrTest::TestRect(random); - return GrAAFillRectBatch::Create(color, viewMatrix, rect, devRect); + return GrAAFillRectOp::Make(color, viewMatrix, rect, devRect); } -DRAW_BATCH_TEST_DEFINE(AAFillRectBatchLocalMatrix) { +DRAW_OP_TEST_DEFINE(AAFillRectOpLocalMatrix) { GrColor color = GrRandomColor(random); SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); SkMatrix localMatrix = GrTest::TestMatrix(random); SkRect rect = GrTest::TestRect(random); SkRect devRect = GrTest::TestRect(random); - return GrAAFillRectBatch::Create(color, viewMatrix, localMatrix, rect, devRect); + return GrAAFillRectOp::Make(color, viewMatrix, localMatrix, rect, devRect); } #endif diff --git a/gfx/skia/skia/src/gpu/ops/GrAAFillRectOp.h b/gfx/skia/skia/src/gpu/ops/GrAAFillRectOp.h new file mode 100644 index 000000000000..7d977164fccf --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrAAFillRectOp.h @@ -0,0 +1,41 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrAAFillRectOp_DEFINED +#define GrAAFillRectOp_DEFINED + +#include "GrColor.h" +#include "SkRefCnt.h" + +class GrLegacyMeshDrawOp; +class SkMatrix; +struct SkRect; + +namespace GrAAFillRectOp { +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect& devRect); + +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, + const SkRect& rect); + +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, + const SkRect& rect, + const SkRect& devRect); + +std::unique_ptr MakeWithLocalRect(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect& localRect); +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp b/gfx/skia/skia/src/gpu/ops/GrAAHairLinePathRenderer.cpp similarity index 84% rename from gfx/skia/skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp rename to gfx/skia/skia/src/gpu/ops/GrAAHairLinePathRenderer.cpp index 9d73cf4f17cd..274e30846571 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrAAHairLinePathRenderer.cpp @@ -6,13 +6,13 @@ */ #include "GrAAHairLinePathRenderer.h" - -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" #include "GrBuffer.h" #include "GrCaps.h" +#include "GrClip.h" #include "GrContext.h" #include "GrDefaultGeoProcFactory.h" +#include "GrDrawOpTest.h" +#include "GrOpFlushState.h" #include "GrPathUtils.h" #include "GrPipelineBuilder.h" #include "GrProcessor.h" @@ -20,10 +20,8 @@ #include "SkGeometry.h" #include "SkStroke.h" #include "SkTemplates.h" - -#include "batches/GrVertexBatch.h" - #include "effects/GrBezierEffect.h" +#include "ops/GrMeshDrawOp.h" #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> @@ -175,7 +173,7 @@ static int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weigh static int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) { static const SkScalar gDegenerateToLineTol = GrPathUtils::kDefaultTolerance; static const SkScalar gDegenerateToLineTolSqd = - SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); + gDegenerateToLineTol * gDegenerateToLineTol; if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { @@ -212,7 +210,7 @@ static int num_quad_subdivs(const SkPoint p[3]) { // maybe different when do this using gpu (geo or tess shaders) static const SkScalar gSubdivTol = 175 * SK_Scalar1; - if (dsqd <= SkScalarMul(gSubdivTol, gSubdivTol)) { + if (dsqd <= gSubdivTol * gSubdivTol) { return 0; } else { static const int kMaxSub = 4; @@ -411,9 +409,7 @@ struct BezierVertex { SkPoint fPos; union { struct { - SkScalar fK; - SkScalar fL; - SkScalar fM; + SkScalar fKLM[3]; } fConic; SkVector fQuadCoord; struct { @@ -431,15 +427,14 @@ static void intersect_lines(const SkPoint& ptA, const SkVector& normA, SkScalar lineAW = -normA.dot(ptA); SkScalar lineBW = -normB.dot(ptB); - SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - - SkScalarMul(normA.fY, normB.fX); + SkScalar wInv = normA.fX * normB.fY - normA.fY * normB.fX; wInv = SkScalarInvert(wInv); - result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); - result->fX = SkScalarMul(result->fX, wInv); + result->fX = normA.fY * lineBW - lineAW * normB.fY; + result->fX *= wInv; - result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); - result->fY = SkScalarMul(result->fY, wInv); + result->fY = lineAW * normB.fX - normA.fX * lineBW; + result->fY *= wInv; } static void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) { @@ -529,15 +524,13 @@ static void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, // k, l, m are calculated in function GrPathUtils::getConicKLM static void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices], const SkScalar weight) { - SkScalar klm[9]; + SkMatrix klm; - GrPathUtils::getConicKLM(p, weight, klm); + GrPathUtils::getConicKLM(p, weight, &klm); for (int i = 0; i < kQuadNumVertices; ++i) { - const SkPoint pnt = verts[i].fPos; - verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; - verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; - verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; + const SkScalar pt3[3] = {verts[i].fPos.x(), verts[i].fPos.y(), 1.f}; + klm.mapHomogeneousPoints(verts[i].fConic.fKLM, pt3, 1); } } @@ -617,7 +610,7 @@ static void add_line(const SkPoint p[2], /////////////////////////////////////////////////////////////////////////////// bool GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - if (!args.fAntiAlias) { + if (GrAAType::kCoverage != args.fAAType) { return false; } @@ -675,45 +668,57 @@ bool check_bounds(const SkMatrix& viewMatrix, const SkRect& devBounds, void* ver return true; } -class AAHairlineBatch : public GrVertexBatch { +class AAHairlineOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - AAHairlineBatch(GrColor color, - uint8_t coverage, - const SkMatrix& viewMatrix, - const SkPath& path, - SkIRect devClipBounds) : INHERITED(ClassID()) { - fGeoData.emplace_back(Geometry{color, coverage, viewMatrix, path, devClipBounds}); + static std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkPath& path, + const GrStyle& style, + const SkIRect& devClipBounds) { + SkScalar hairlineCoverage; + uint8_t newCoverage = 0xff; + if (GrPathRenderer::IsStrokeHairlineOrEquivalent(style, viewMatrix, &hairlineCoverage)) { + newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); + } + + return std::unique_ptr( + new AAHairlineOp(color, newCoverage, viewMatrix, path, devClipBounds)); + } + + const char* name() const override { return "AAHairlineOp"; } + + SkString dumpInfo() const override { + SkString string; + string.appendf("Color: 0x%08x Coverage: 0x%02x, Count: %d\n", fColor, fCoverage, + fPaths.count()); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + AAHairlineOp(GrColor color, + uint8_t coverage, + const SkMatrix& viewMatrix, + const SkPath& path, + SkIRect devClipBounds) + : INHERITED(ClassID()), fColor(color), fCoverage(coverage) { + fPaths.emplace_back(PathData{viewMatrix, path, devClipBounds}); this->setTransformedBounds(path.getBounds(), viewMatrix, HasAABloat::kYes, IsZeroArea::kYes); } - const char* name() const override { return "AAHairlineBatch"; } - - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; } -private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any color overrides - if (!overrides.readsColor()) { - fGeoData[0].fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); - - // setup batch properties - fBatch.fColorIgnored = !overrides.readsColor(); - fBatch.fColor = fGeoData[0].fColor; - fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); - fBatch.fCoverageIgnored = !overrides.readsCoverage(); - fBatch.fCoverage = fGeoData[0].fCoverage; + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fColor); + fUsesLocalCoords = optimizations.readsLocalCoords(); } void onPrepareDraws(Target*) const override; @@ -722,8 +727,8 @@ private: typedef SkTArray IntArray; typedef SkTArray FloatArray; - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - AAHairlineBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + AAHairlineOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { @@ -740,8 +745,8 @@ private: return false; } - // TODO we can actually batch hairlines if they are the same color in a kind of bulk method - // but we haven't implemented this yet + // TODO we can actually combine hairlines if they are the same color in a kind of bulk + // method but we haven't implemented this yet // TODO investigate going to vertex color and coverage? if (this->coverage() != that->coverage()) { return false; @@ -756,42 +761,32 @@ private: return false; } - fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); + fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin()); this->joinBounds(*that); return true; } - GrColor color() const { return fBatch.fColor; } - uint8_t coverage() const { return fBatch.fCoverage; } - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } - const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } - bool coverageIgnored() const { return fBatch.fCoverageIgnored; } + GrColor color() const { return fColor; } + uint8_t coverage() const { return fCoverage; } + bool usesLocalCoords() const { return fUsesLocalCoords; } + const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; } - - struct Geometry { - GrColor fColor; - uint8_t fCoverage; + struct PathData { SkMatrix fViewMatrix; SkPath fPath; SkIRect fDevClipBounds; }; - struct BatchTracker { - GrColor fColor; - uint8_t fCoverage; - SkRect fDevBounds; - bool fUsesLocalCoords; - bool fColorIgnored; - bool fCoverageIgnored; - }; + GrColor fColor; + uint8_t fCoverage; + bool fUsesLocalCoords; - BatchTracker fBatch; - SkSTArray<1, Geometry, true> fGeoData; + SkSTArray<1, PathData, true> fPaths; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -void AAHairlineBatch::onPrepareDraws(Target* target) const { +void AAHairlineOp::onPrepareDraws(Target* target) const { // Setup the viewmatrix and localmatrix for the GrGeometryProcessor. SkMatrix invert; if (!this->viewMatrix().invert(&invert)) { @@ -819,9 +814,9 @@ void AAHairlineBatch::onPrepareDraws(Target* target) const { FloatArray cWeights; int quadCount = 0; - int instanceCount = fGeoData.count(); + int instanceCount = fPaths.count(); for (int i = 0; i < instanceCount; i++) { - const Geometry& args = fGeoData[i]; + const PathData& args = fPaths[i]; quadCount += gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds, &lines, &quads, &conics, &qSubdivs, &cWeights); } @@ -836,15 +831,14 @@ void AAHairlineBatch::onPrepareDraws(Target* target) const { using namespace GrDefaultGeoProcFactory; Color color(this->color()); - Coverage coverage(Coverage::kAttribute_Type); LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type); localCoords.fMatrix = geometryProcessorLocalM; - lineGP = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, + lineGP = GrDefaultGeoProcFactory::Make(color, Coverage::kAttribute_Type, localCoords, *geometryProcessorViewM); } - SkAutoTUnref linesIndexBuffer( + sk_sp linesIndexBuffer( ref_lines_index_buffer(target->resourceProvider())); const GrBuffer* vertexBuffer; @@ -867,10 +861,10 @@ void AAHairlineBatch::onPrepareDraws(Target* target) const { } GrMesh mesh; - mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, linesIndexBuffer, + mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, linesIndexBuffer.get(), firstVertex, kLineSegNumVertices, kIdxsPerLineSeg, lineCount, kLineSegsNumInIdxBuffer); - target->draw(lineGP.get(), mesh); + target->draw(lineGP.get(), this->pipeline(), mesh); } if (quadCount || conicCount) { @@ -895,7 +889,7 @@ void AAHairlineBatch::onPrepareDraws(Target* target) const { const GrBuffer* vertexBuffer; int firstVertex; - SkAutoTUnref quadsIndexBuffer( + sk_sp quadsIndexBuffer( ref_quads_index_buffer(target->resourceProvider())); size_t vertexStride = sizeof(BezierVertex); @@ -924,70 +918,54 @@ void AAHairlineBatch::onPrepareDraws(Target* target) const { if (quadCount > 0) { GrMesh mesh; - mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer, + mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer.get(), firstVertex, kQuadNumVertices, kIdxsPerQuad, quadCount, kQuadsNumInIdxBuffer); - target->draw(quadGP.get(), mesh); + target->draw(quadGP.get(), this->pipeline(), mesh); firstVertex += quadCount * kQuadNumVertices; } if (conicCount > 0) { GrMesh mesh; - mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer, + mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer.get(), firstVertex, kQuadNumVertices, kIdxsPerQuad, conicCount, kQuadsNumInIdxBuffer); - target->draw(conicGP.get(), mesh); + target->draw(conicGP.get(), this->pipeline(), mesh); } } } -static GrDrawBatch* create_hairline_batch(GrColor color, - const SkMatrix& viewMatrix, - const SkPath& path, - const GrStyle& style, - const SkIRect& devClipBounds) { - SkScalar hairlineCoverage; - uint8_t newCoverage = 0xff; - if (GrPathRenderer::IsStrokeHairlineOrEquivalent(style, viewMatrix, &hairlineCoverage)) { - newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); - } - - return new AAHairlineBatch(color, newCoverage, viewMatrix, path, devClipBounds); -} - bool GrAAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrAAHairlinePathRenderer::onDrawPath"); - SkASSERT(!args.fDrawContext->isUnifiedMultisampled()); + SkASSERT(!args.fRenderTargetContext->isUnifiedMultisampled()); SkIRect devClipBounds; - args.fClip->getConservativeBounds(args.fDrawContext->width(), args.fDrawContext->height(), + args.fClip->getConservativeBounds(args.fRenderTargetContext->width(), + args.fRenderTargetContext->height(), &devClipBounds); - SkPath path; args.fShape->asPath(&path); - SkAutoTUnref batch(create_hairline_batch(args.fPaint->getColor(), - *args.fViewMatrix, path, - args.fShape->style(), devClipBounds)); - - GrPipelineBuilder pipelineBuilder(*args.fPaint); + std::unique_ptr op = AAHairlineOp::Make( + args.fPaint.getColor(), *args.fViewMatrix, path, args.fShape->style(), devClipBounds); + GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), args.fAAType); pipelineBuilder.setUserStencil(args.fUserStencilSettings); - args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); - + args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip, + std::move(op)); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -DRAW_BATCH_TEST_DEFINE(AAHairlineBatch) { +DRAW_OP_TEST_DEFINE(AAHairlineOp) { GrColor color = GrRandomColor(random); SkMatrix viewMatrix = GrTest::TestMatrix(random); SkPath path = GrTest::TestPath(random); SkIRect devClipBounds; devClipBounds.setEmpty(); - return create_hairline_batch(color, viewMatrix, path, GrStyle::SimpleHairline(), devClipBounds); + return AAHairlineOp::Make(color, viewMatrix, path, GrStyle::SimpleHairline(), devClipBounds); } #endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAAHairLinePathRenderer.h b/gfx/skia/skia/src/gpu/ops/GrAAHairLinePathRenderer.h similarity index 100% rename from gfx/skia/skia/src/gpu/batches/GrAAHairLinePathRenderer.h rename to gfx/skia/skia/src/gpu/ops/GrAAHairLinePathRenderer.h diff --git a/gfx/skia/skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp b/gfx/skia/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp similarity index 66% rename from gfx/skia/skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp rename to gfx/skia/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp index c2873b6a404b..2a5464c1306f 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp @@ -8,22 +8,21 @@ #include "GrAALinearizingConvexPathRenderer.h" #include "GrAAConvexTessellator.h" -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" #include "GrContext.h" #include "GrDefaultGeoProcFactory.h" +#include "GrDrawOpTest.h" #include "GrGeometryProcessor.h" -#include "GrInvariantOutput.h" +#include "GrOpFlushState.h" #include "GrPathUtils.h" -#include "GrProcessor.h" #include "GrPipelineBuilder.h" +#include "GrProcessor.h" #include "GrStyle.h" #include "SkGeometry.h" +#include "SkPathPriv.h" #include "SkString.h" #include "SkTraceEvent.h" -#include "SkPathPriv.h" -#include "batches/GrVertexBatch.h" #include "glsl/GrGLSLGeometryProcessor.h" +#include "ops/GrMeshDrawOp.h" static const int DEFAULT_BUFFER_SIZE = 100; @@ -37,7 +36,7 @@ GrAALinearizingConvexPathRenderer::GrAALinearizingConvexPathRenderer() { /////////////////////////////////////////////////////////////////////////////// bool GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - if (!args.fAntiAlias) { + if (GrAAType::kCoverage != args.fAAType) { return false; } if (!args.fShape->knownToBeConvex()) { @@ -103,39 +102,61 @@ static void extract_verts(const GrAAConvexTessellator& tess, static sk_sp create_fill_gp(bool tweakAlphaForCoverage, const SkMatrix& viewMatrix, - bool usesLocalCoords, - bool coverageIgnored) { + bool usesLocalCoords) { using namespace GrDefaultGeoProcFactory; - Color color(Color::kAttribute_Type); Coverage::Type coverageType; - // TODO remove coverage if coverage is ignored - /*if (coverageIgnored) { - coverageType = Coverage::kNone_Type; - } else*/ if (tweakAlphaForCoverage) { + if (tweakAlphaForCoverage) { coverageType = Coverage::kSolid_Type; } else { coverageType = Coverage::kAttribute_Type; } - Coverage coverage(coverageType); - LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type : - LocalCoords::kUnused_Type); - return MakeForDeviceSpace(color, coverage, localCoords, viewMatrix); + LocalCoords::Type localCoordsType = + usesLocalCoords ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type; + return MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type, coverageType, localCoordsType, + viewMatrix); } -class AAFlatteningConvexPathBatch : public GrVertexBatch { +class AAFlatteningConvexPathOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID + static std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkPath& path, + SkScalar strokeWidth, + SkStrokeRec::Style style, + SkPaint::Join join, + SkScalar miterLimit) { + return std::unique_ptr(new AAFlatteningConvexPathOp( + color, viewMatrix, path, strokeWidth, style, join, miterLimit)); + } - AAFlatteningConvexPathBatch(GrColor color, - const SkMatrix& viewMatrix, - const SkPath& path, - SkScalar strokeWidth, - SkStrokeRec::Style style, - SkPaint::Join join, - SkScalar miterLimit) : INHERITED(ClassID()) { - fGeoData.emplace_back(Geometry{ color, viewMatrix, path, - strokeWidth, style, join, miterLimit }); + const char* name() const override { return "AAFlatteningConvexPathOp"; } + + SkString dumpInfo() const override { + SkString string; + for (const auto& path : fPaths) { + string.appendf( + "Color: 0x%08x, StrokeWidth: %.2f, Style: %d, Join: %d, " + "MiterLimit: %.2f\n", + path.fColor, path.fStrokeWidth, path.fStyle, path.fJoin, path.fMiterLimit); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + AAFlatteningConvexPathOp(GrColor color, + const SkMatrix& viewMatrix, + const SkPath& path, + SkScalar strokeWidth, + SkStrokeRec::Style style, + SkPaint::Join join, + SkScalar miterLimit) + : INHERITED(ClassID()) { + fPaths.emplace_back( + PathData{color, viewMatrix, path, strokeWidth, style, join, miterLimit}); // compute bounds SkRect bounds = path.getBounds(); @@ -151,34 +172,19 @@ public: this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kYes, IsZeroArea::kNo); } - const char* name() const override { return "AAConvexBatch"; } - - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fPaths[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; } -private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any color overrides - if (!overrides.readsColor()) { - fGeoData[0].fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); - - // setup batch properties - fBatch.fColorIgnored = !overrides.readsColor(); - fBatch.fColor = fGeoData[0].fColor; - fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); - fBatch.fCoverageIgnored = !overrides.readsCoverage(); - fBatch.fLinesOnly = SkPath::kLine_SegmentMask == fGeoData[0].fPath.getSegmentMasks(); - fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage(); + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fPaths[0].fColor); + fUsesLocalCoords = optimizations.readsLocalCoords(); + fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage(); } - void draw(GrVertexBatch::Target* target, const GrGeometryProcessor* gp, int vertexCount, + void draw(GrLegacyMeshDrawOp::Target* target, const GrGeometryProcessor* gp, int vertexCount, size_t vertexStride, void* vertices, int indexCount, uint16_t* indices) const { if (vertexCount == 0 || indexCount == 0) { return; @@ -204,17 +210,15 @@ private: memcpy(idxs, indices, indexCount * sizeof(uint16_t)); mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex, vertexCount, indexCount); - target->draw(gp, mesh); + target->draw(gp, this->pipeline(), mesh); } void onPrepareDraws(Target* target) const override { bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage(); // Setup GrGeometryProcessor - sk_sp gp(create_fill_gp(canTweakAlphaForCoverage, - this->viewMatrix(), - this->usesLocalCoords(), - this->coverageIgnored())); + sk_sp gp(create_fill_gp( + canTweakAlphaForCoverage, this->viewMatrix(), this->usesLocalCoords())); if (!gp) { SkDebugf("Couldn't create a GrGeometryProcessor\n"); return; @@ -226,7 +230,7 @@ private: vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr)); - int instanceCount = fGeoData.count(); + int instanceCount = fPaths.count(); int vertexCount = 0; int indexCount = 0; @@ -235,7 +239,7 @@ private: uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride); uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t)); for (int i = 0; i < instanceCount; i++) { - const Geometry& args = fGeoData[i]; + const PathData& args = fPaths[i]; GrAAConvexTessellator tess(args.fStyle, args.fStrokeWidth, args.fJoin, args.fMiterLimit); @@ -273,8 +277,8 @@ private: sk_free(indices); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - AAFlatteningConvexPathBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + AAFlatteningConvexPathOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; @@ -285,34 +289,22 @@ private: return false; } - // In the event of two batches, one who can tweak, one who cannot, we just fall back to - // not tweaking + // In the event of two ops, one who can tweak, one who cannot, we just fall back to not + // tweaking if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) { - fBatch.fCanTweakAlphaForCoverage = false; + fCanTweakAlphaForCoverage = false; } - fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); + fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin()); this->joinBounds(*that); return true; } - GrColor color() const { return fBatch.fColor; } - bool linesOnly() const { return fBatch.fLinesOnly; } - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } - bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; } - const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } - bool coverageIgnored() const { return fBatch.fCoverageIgnored; } + bool usesLocalCoords() const { return fUsesLocalCoords; } + bool canTweakAlphaForCoverage() const { return fCanTweakAlphaForCoverage; } + const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; } - struct BatchTracker { - GrColor fColor; - bool fUsesLocalCoords; - bool fColorIgnored; - bool fCoverageIgnored; - bool fLinesOnly; - bool fCanTweakAlphaForCoverage; - }; - - struct Geometry { + struct PathData { GrColor fColor; SkMatrix fViewMatrix; SkPath fPath; @@ -322,16 +314,17 @@ private: SkScalar fMiterLimit; }; - BatchTracker fBatch; - SkSTArray<1, Geometry, true> fGeoData; + bool fUsesLocalCoords; + bool fCanTweakAlphaForCoverage; + SkSTArray<1, PathData, true> fPaths; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrAALinearizingConvexPathRenderer::onDrawPath"); - SkASSERT(!args.fDrawContext->isUnifiedMultisampled()); + SkASSERT(!args.fRenderTargetContext->isUnifiedMultisampled()); SkASSERT(!args.fShape->isEmpty()); SkASSERT(!args.fShape->style().pathEffect()); @@ -343,31 +336,30 @@ bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin(); SkScalar miterLimit = stroke.getMiter(); - SkAutoTUnref batch(new AAFlatteningConvexPathBatch(args.fPaint->getColor(), - *args.fViewMatrix, - path, strokeWidth, - stroke.getStyle(), - join, miterLimit)); + std::unique_ptr op = + AAFlatteningConvexPathOp::Make(args.fPaint.getColor(), *args.fViewMatrix, path, + strokeWidth, stroke.getStyle(), join, miterLimit); - GrPipelineBuilder pipelineBuilder(*args.fPaint); + GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), args.fAAType); pipelineBuilder.setUserStencil(args.fUserStencilSettings); - args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); + args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip, + std::move(op)); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -DRAW_BATCH_TEST_DEFINE(AAFlatteningConvexPathBatch) { +DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) { GrColor color = GrRandomColor(random); - SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); + SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random); SkPath path = GrTest::TestPathConvex(random); SkStrokeRec::Style styles[3] = { SkStrokeRec::kFill_Style, - SkStrokeRec::kStroke_Style, + SkStrokeRec::kStroke_Style, SkStrokeRec::kStrokeAndFill_Style }; SkStrokeRec::Style style = styles[random->nextU() % 3]; @@ -386,8 +378,8 @@ DRAW_BATCH_TEST_DEFINE(AAFlatteningConvexPathBatch) { miterLimit = random->nextRangeF(0.5f, 2.0f); } - return new AAFlatteningConvexPathBatch(color, viewMatrix, path, strokeWidth, - style, join, miterLimit); + return AAFlatteningConvexPathOp::Make(color, viewMatrix, path, strokeWidth, style, join, + miterLimit); } #endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.h b/gfx/skia/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.h similarity index 100% rename from gfx/skia/skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.h rename to gfx/skia/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.h diff --git a/gfx/skia/skia/src/gpu/batches/GrAAStrokeRectBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrAAStrokeRectOp.cpp similarity index 62% rename from gfx/skia/skia/src/gpu/batches/GrAAStrokeRectBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrAAStrokeRectOp.cpp index bbee3f878afd..8b47f5e30fc7 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAAStrokeRectBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrAAStrokeRectOp.cpp @@ -5,20 +5,19 @@ * found in the LICENSE file. */ -#include "GrAAStrokeRectBatch.h" +#include "GrAAStrokeRectOp.h" -#include "GrBatchFlushState.h" #include "GrDefaultGeoProcFactory.h" +#include "GrOpFlushState.h" #include "GrResourceKey.h" #include "GrResourceProvider.h" +#include "SkStrokeRec.h" GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey); GR_DECLARE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey); -static void set_inset_fan(SkPoint* pts, size_t stride, - const SkRect& r, SkScalar dx, SkScalar dy) { - pts->setRectFan(r.fLeft + dx, r.fTop + dy, - r.fRight - dx, r.fBottom - dy, stride); +static void set_inset_fan(SkPoint* pts, size_t stride, const SkRect& r, SkScalar dx, SkScalar dy) { + pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride); } // We support all hairlines, bevels, and miters, but not round joins. Also, check whether the miter @@ -59,8 +58,8 @@ static void compute_rects(SkRect* devOutside, SkRect* devOutsideAssist, SkRect* const SkScalar dx = devStrokeSize.fX; const SkScalar dy = devStrokeSize.fY; - const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf); - const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf); + const SkScalar rx = SkScalarHalf(dx); + const SkScalar ry = SkScalarHalf(dy); *devOutside = devRect; *devOutsideAssist = devRect; @@ -96,75 +95,92 @@ static void compute_rects(SkRect* devOutside, SkRect* devOutsideAssist, SkRect* static sk_sp create_stroke_rect_gp(bool tweakAlphaForCoverage, const SkMatrix& viewMatrix, - bool usesLocalCoords, - bool coverageIgnored) { + bool usesLocalCoords) { using namespace GrDefaultGeoProcFactory; - Color color(Color::kAttribute_Type); Coverage::Type coverageType; - // TODO remove coverage if coverage is ignored - /*if (coverageIgnored) { - coverageType = Coverage::kNone_Type; - } else*/ if (tweakAlphaForCoverage) { + if (tweakAlphaForCoverage) { coverageType = Coverage::kSolid_Type; } else { coverageType = Coverage::kAttribute_Type; } - Coverage coverage(coverageType); - LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type : - LocalCoords::kUnused_Type); - return MakeForDeviceSpace(color, coverage, localCoords, viewMatrix); + LocalCoords::Type localCoordsType = + usesLocalCoords ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type; + return MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type, coverageType, localCoordsType, + viewMatrix); } -class AAStrokeRectBatch : public GrVertexBatch { +class AAStrokeRectOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - AAStrokeRectBatch(GrColor color, const SkMatrix& viewMatrix, - const SkRect& devOutside, const SkRect& devInside) - : INHERITED(ClassID()) - , fViewMatrix(viewMatrix) { + AAStrokeRectOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& devOutside, + const SkRect& devInside) + : INHERITED(ClassID()), fViewMatrix(viewMatrix) { SkASSERT(!devOutside.isEmpty()); SkASSERT(!devInside.isEmpty()); - fGeoData.emplace_back(Geometry{color, devOutside, devOutside, devInside, false}); + fRects.emplace_back(RectInfo{color, devOutside, devOutside, devInside, false}); this->setBounds(devOutside, HasAABloat::kYes, IsZeroArea::kNo); fMiterStroke = true; } - static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, - const SkStrokeRec& stroke) { + static std::unique_ptr Make(GrColor color, const SkMatrix& viewMatrix, + const SkRect& rect, const SkStrokeRec& stroke) { bool isMiter; if (!allowed_stroke(stroke, &isMiter)) { return nullptr; } - AAStrokeRectBatch* batch = new AAStrokeRectBatch(); - batch->fMiterStroke = isMiter; - Geometry& geo = batch->fGeoData.push_back(); - compute_rects(&geo.fDevOutside, &geo.fDevOutsideAssist, &geo.fDevInside, &geo.fDegenerate, - viewMatrix, rect, stroke.getWidth(), isMiter); - geo.fColor = color; - batch->setBounds(geo.fDevOutside, HasAABloat::kYes, IsZeroArea::kNo); - batch->fViewMatrix = viewMatrix; - return batch; + AAStrokeRectOp* op = new AAStrokeRectOp(); + op->fMiterStroke = isMiter; + RectInfo& info = op->fRects.push_back(); + compute_rects(&info.fDevOutside, &info.fDevOutsideAssist, &info.fDevInside, + &info.fDegenerate, viewMatrix, rect, stroke.getWidth(), isMiter); + info.fColor = color; + if (isMiter) { + op->setBounds(info.fDevOutside, HasAABloat::kYes, IsZeroArea::kNo); + } else { + // The outer polygon of the bevel stroke is an octagon specified by the points of a + // pair of overlapping rectangles where one is wide and the other is narrow. + SkRect bounds = info.fDevOutside; + bounds.joinPossiblyEmptyRect(info.fDevOutsideAssist); + op->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo); + } + op->fViewMatrix = viewMatrix; + return std::unique_ptr(op); } const char* name() const override { return "AAStrokeRect"; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); + SkString dumpInfo() const override { + SkString string; + for (const auto& info : fRects) { + string.appendf( + "Color: 0x%08x, ORect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], " + "AssistORect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], " + "IRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], Degen: %d", + info.fColor, info.fDevOutside.fLeft, info.fDevOutside.fTop, + info.fDevOutside.fRight, info.fDevOutside.fBottom, info.fDevOutsideAssist.fLeft, + info.fDevOutsideAssist.fTop, info.fDevOutsideAssist.fRight, + info.fDevOutsideAssist.fBottom, info.fDevInside.fLeft, info.fDevInside.fTop, + info.fDevInside.fRight, info.fDevInside.fBottom, info.fDegenerate); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; } private: - AAStrokeRectBatch() : INHERITED(ClassID()) {} + AAStrokeRectOp() : INHERITED(ClassID()) {} + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fRects[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } + void applyPipelineOptimizations(const PipelineOptimizations&) override; void onPrepareDraws(Target*) const override; - void initBatchTracker(const GrXPOverridesForBatch&) override; static const int kMiterIndexCnt = 3 * 24; static const int kMiterVertexCnt = 16; @@ -176,15 +192,12 @@ private: static const GrBuffer* GetIndexBuffer(GrResourceProvider* resourceProvider, bool miterStroke); - GrColor color() const { return fBatch.fColor; } - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } - bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; } - bool colorIgnored() const { return fBatch.fColorIgnored; } - bool coverageIgnored() const { return fBatch.fCoverageIgnored; } + bool usesLocalCoords() const { return fUsesLocalCoords; } + bool canTweakAlphaForCoverage() const { return fCanTweakAlphaForCoverage; } const SkMatrix& viewMatrix() const { return fViewMatrix; } bool miterStroke() const { return fMiterStroke; } - bool onCombineIfPossible(GrBatch* t, const GrCaps&) override; + bool onCombineIfPossible(GrOp* t, const GrCaps&) override; void generateAAStrokeRectGeometry(void* vertices, size_t offset, @@ -199,16 +212,8 @@ private: bool degenerate, bool tweakAlphaForCoverage) const; - struct BatchTracker { - GrColor fColor; - bool fUsesLocalCoords; - bool fColorIgnored; - bool fCoverageIgnored; - bool fCanTweakAlphaForCoverage; - }; - // TODO support AA rotated stroke rects by copying around view matrices - struct Geometry { + struct RectInfo { GrColor fColor; SkRect fDevOutside; SkRect fDevOutsideAssist; @@ -216,36 +221,29 @@ private: bool fDegenerate; }; - BatchTracker fBatch; - SkSTArray<1, Geometry, true> fGeoData; + SkSTArray<1, RectInfo, true> fRects; + bool fUsesLocalCoords; + bool fCanTweakAlphaForCoverage; SkMatrix fViewMatrix; bool fMiterStroke; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -void AAStrokeRectBatch::initBatchTracker(const GrXPOverridesForBatch& overrides) { - // Handle any color overrides - if (!overrides.readsColor()) { - fGeoData[0].fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); +void AAStrokeRectOp::applyPipelineOptimizations(const PipelineOptimizations& optimizations) { + optimizations.getOverrideColorIfSet(&fRects[0].fColor); - // setup batch properties - fBatch.fColorIgnored = !overrides.readsColor(); - fBatch.fColor = fGeoData[0].fColor; - fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); - fBatch.fCoverageIgnored = !overrides.readsCoverage(); - fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage(); + fUsesLocalCoords = optimizations.readsLocalCoords(); + fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage(); + fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage(); } -void AAStrokeRectBatch::onPrepareDraws(Target* target) const { +void AAStrokeRectOp::onPrepareDraws(Target* target) const { bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage(); sk_sp gp(create_stroke_rect_gp(canTweakAlphaForCoverage, this->viewMatrix(), - this->usesLocalCoords(), - this->coverageIgnored())); + this->usesLocalCoords())); if (!gp) { SkDebugf("Couldn't create GrGeometryProcessor\n"); return; @@ -253,48 +251,48 @@ void AAStrokeRectBatch::onPrepareDraws(Target* target) const { size_t vertexStride = gp->getVertexStride(); - SkASSERT(canTweakAlphaForCoverage ? - vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) : - vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr)); + SkASSERT(canTweakAlphaForCoverage + ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) + : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr)); int innerVertexNum = 4; int outerVertexNum = this->miterStroke() ? 4 : 8; int verticesPerInstance = (outerVertexNum + innerVertexNum) * 2; int indicesPerInstance = this->miterStroke() ? kMiterIndexCnt : kBevelIndexCnt; - int instanceCount = fGeoData.count(); + int instanceCount = fRects.count(); - const SkAutoTUnref indexBuffer( - GetIndexBuffer(target->resourceProvider(), this->miterStroke())); + const sk_sp indexBuffer( + GetIndexBuffer(target->resourceProvider(), this->miterStroke())); InstancedHelper helper; - void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, - indexBuffer, verticesPerInstance, indicesPerInstance, - instanceCount); + void* vertices = + helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(), + verticesPerInstance, indicesPerInstance, instanceCount); if (!vertices || !indexBuffer) { - SkDebugf("Could not allocate vertices\n"); - return; - } + SkDebugf("Could not allocate vertices\n"); + return; + } for (int i = 0; i < instanceCount; i++) { - const Geometry& args = fGeoData[i]; + const RectInfo& info = fRects[i]; this->generateAAStrokeRectGeometry(vertices, i * verticesPerInstance * vertexStride, vertexStride, outerVertexNum, innerVertexNum, - args.fColor, - args.fDevOutside, - args.fDevOutsideAssist, - args.fDevInside, + info.fColor, + info.fDevOutside, + info.fDevOutsideAssist, + info.fDevInside, fMiterStroke, - args.fDegenerate, + info.fDegenerate, canTweakAlphaForCoverage); } - helper.recordDraw(target, gp.get()); + helper.recordDraw(target, gp.get(), this->pipeline()); } -const GrBuffer* AAStrokeRectBatch::GetIndexBuffer(GrResourceProvider* resourceProvider, - bool miterStroke) { - +const GrBuffer* AAStrokeRectOp::GetIndexBuffer(GrResourceProvider* resourceProvider, + bool miterStroke) { if (miterStroke) { + // clang-format off static const uint16_t gMiterIndices[] = { 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, @@ -311,11 +309,12 @@ const GrBuffer* AAStrokeRectBatch::GetIndexBuffer(GrResourceProvider* resourcePr 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8, 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, }; + // clang-format on GR_STATIC_ASSERT(SK_ARRAY_COUNT(gMiterIndices) == kMiterIndexCnt); GR_DEFINE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey); - return resourceProvider->findOrCreateInstancedIndexBuffer(gMiterIndices, - kMiterIndexCnt, kNumMiterRectsInIndexBuffer, kMiterVertexCnt, - gMiterIndexBufferKey); + return resourceProvider->findOrCreateInstancedIndexBuffer( + gMiterIndices, kMiterIndexCnt, kNumMiterRectsInIndexBuffer, kMiterVertexCnt, + gMiterIndexBufferKey); } else { /** * As in miter-stroke, index = a + b, and a is the current index, b is the shift @@ -346,6 +345,7 @@ const GrBuffer* AAStrokeRectBatch::GetIndexBuffer(GrResourceProvider* resourcePr * ********************************** * 5 6 */ + // clang-format off static const uint16_t gBevelIndices[] = { // Draw outer AA, from outer AA line to outer edge, shift is 0. 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0, @@ -373,45 +373,43 @@ const GrBuffer* AAStrokeRectBatch::GetIndexBuffer(GrResourceProvider* resourcePr 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16, 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16, }; + // clang-format on GR_STATIC_ASSERT(SK_ARRAY_COUNT(gBevelIndices) == kBevelIndexCnt); GR_DEFINE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey); - return resourceProvider->findOrCreateInstancedIndexBuffer(gBevelIndices, - kBevelIndexCnt, kNumBevelRectsInIndexBuffer, kBevelVertexCnt, - gBevelIndexBufferKey); + return resourceProvider->findOrCreateInstancedIndexBuffer( + gBevelIndices, kBevelIndexCnt, kNumBevelRectsInIndexBuffer, kBevelVertexCnt, + gBevelIndexBufferKey); } } -bool AAStrokeRectBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { - AAStrokeRectBatch* that = t->cast(); +bool AAStrokeRectOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { + AAStrokeRectOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; } - // TODO batch across miterstroke changes + // TODO combine across miterstroke changes if (this->miterStroke() != that->miterStroke()) { return false; } // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses - // local coords then we won't be able to batch. We could actually upload the viewmatrix + // local coords then we won't be able to combine. We could actually upload the viewmatrix // using vertex attributes in these cases, but haven't investigated that if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { return false; } - // In the event of two batches, one who can tweak, one who cannot, we just fall back to - // not tweaking + // In the event of two ops, one who can tweak, one who cannot, we just fall back to not + // tweaking. if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) { - fBatch.fCanTweakAlphaForCoverage = false; + fCanTweakAlphaForCoverage = false; } - if (this->color() != that->color()) { - fBatch.fColor = GrColor_ILLEGAL; - } - fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); + fRects.push_back_n(that->fRects.count(), that->fRects.begin()); this->joinBounds(*that); return true; } @@ -425,18 +423,18 @@ static void setup_scale(int* scale, SkScalar inset) { } } -void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, - size_t offset, - size_t vertexStride, - int outerVertexNum, - int innerVertexNum, - GrColor color, - const SkRect& devOutside, - const SkRect& devOutsideAssist, - const SkRect& devInside, - bool miterStroke, - bool degenerate, - bool tweakAlphaForCoverage) const { +void AAStrokeRectOp::generateAAStrokeRectGeometry(void* vertices, + size_t offset, + size_t vertexStride, + int outerVertexNum, + int innerVertexNum, + GrColor color, + const SkRect& devOutside, + const SkRect& devOutsideAssist, + const SkRect& devInside, + bool miterStroke, + bool degenerate, + bool tweakAlphaForCoverage) const { intptr_t verts = reinterpret_cast(vertices) + offset; // We create vertices for four nested rectangles. There are two ramps from 0 to full @@ -445,9 +443,8 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, SkPoint* fan0Pos = reinterpret_cast(verts); SkPoint* fan1Pos = reinterpret_cast(verts + outerVertexNum * vertexStride); SkPoint* fan2Pos = reinterpret_cast(verts + 2 * outerVertexNum * vertexStride); - SkPoint* fan3Pos = reinterpret_cast(verts + - (2 * outerVertexNum + innerVertexNum) * - vertexStride); + SkPoint* fan3Pos = reinterpret_cast( + verts + (2 * outerVertexNum + innerVertexNum) * vertexStride); #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX // TODO: this only really works if the X & Y margins are the same all around @@ -460,15 +457,15 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, if (miterStroke) { inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom); } else { - inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - - devInside.fBottom); + inset = SK_ScalarHalf * + SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom); } SkASSERT(inset >= 0); } else { // TODO use real devRect here inset = SkMinScalar(devOutside.width(), SK_Scalar1); - inset = SK_ScalarHalf * SkMinScalar(inset, SkTMax(devOutside.height(), - devOutsideAssist.height())); + inset = SK_ScalarHalf * + SkMinScalar(inset, SkTMax(devOutside.height(), devOutsideAssist.height())); } #else SkScalar inset; @@ -477,8 +474,8 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, } else { // TODO use real devRect here inset = SkMinScalar(devOutside.width(), SK_Scalar1); - inset = SK_ScalarHalf * SkMinScalar(inset, SkTMax(devOutside.height(), - devOutsideAssist.height())); + inset = SK_ScalarHalf * + SkMinScalar(inset, SkTMax(devOutside.height(), devOutsideAssist.height())); } #endif @@ -486,45 +483,42 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, // outermost set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); // inner two - set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset); + set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset); if (!degenerate) { - set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); + set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); // innermost - set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf); + set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf); } else { // When the interior rect has become degenerate we smoosh to a single point - SkASSERT(devInside.fLeft == devInside.fRight && - devInside.fTop == devInside.fBottom); - fan2Pos->setRectFan(devInside.fLeft, devInside.fTop, - devInside.fRight, devInside.fBottom, vertexStride); - fan3Pos->setRectFan(devInside.fLeft, devInside.fTop, - devInside.fRight, devInside.fBottom, vertexStride); + SkASSERT(devInside.fLeft == devInside.fRight && devInside.fTop == devInside.fBottom); + fan2Pos->setRectFan(devInside.fLeft, devInside.fTop, devInside.fRight, + devInside.fBottom, vertexStride); + fan3Pos->setRectFan(devInside.fLeft, devInside.fTop, devInside.fRight, + devInside.fBottom, vertexStride); } } else { SkPoint* fan0AssistPos = reinterpret_cast(verts + 4 * vertexStride); - SkPoint* fan1AssistPos = reinterpret_cast(verts + - (outerVertexNum + 4) * - vertexStride); + SkPoint* fan1AssistPos = + reinterpret_cast(verts + (outerVertexNum + 4) * vertexStride); // outermost set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); set_inset_fan(fan0AssistPos, vertexStride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf); // outer one of the inner two - set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset); - set_inset_fan(fan1AssistPos, vertexStride, devOutsideAssist, inset, inset); + set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset); + set_inset_fan(fan1AssistPos, vertexStride, devOutsideAssist, inset, inset); if (!degenerate) { // inner one of the inner two - set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); + set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); // innermost - set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf); + set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf); } else { // When the interior rect has become degenerate we smoosh to a single point - SkASSERT(devInside.fLeft == devInside.fRight && - devInside.fTop == devInside.fBottom); - fan2Pos->setRectFan(devInside.fLeft, devInside.fTop, - devInside.fRight, devInside.fBottom, vertexStride); - fan3Pos->setRectFan(devInside.fLeft, devInside.fTop, - devInside.fRight, devInside.fBottom, vertexStride); + SkASSERT(devInside.fLeft == devInside.fRight && devInside.fTop == devInside.fBottom); + fan2Pos->setRectFan(devInside.fLeft, devInside.fTop, devInside.fRight, + devInside.fBottom, vertexStride); + fan3Pos->setRectFan(devInside.fLeft, devInside.fTop, devInside.fRight, + devInside.fBottom, vertexStride); } } @@ -575,36 +569,36 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, } } -namespace GrAAStrokeRectBatch { +namespace GrAAStrokeRectOp { -GrDrawBatch* CreateFillBetweenRects(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& devOutside, - const SkRect& devInside) { - return new AAStrokeRectBatch(color, viewMatrix, devOutside, devInside); +std::unique_ptr MakeFillBetweenRects(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& devOutside, + const SkRect& devInside) { + return std::unique_ptr( + new AAStrokeRectOp(color, viewMatrix, devOutside, devInside)); } -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkStrokeRec& stroke) { - return AAStrokeRectBatch::Create(color, viewMatrix, rect, stroke); +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkStrokeRec& stroke) { + return AAStrokeRectOp::Make(color, viewMatrix, rect, stroke); } - } /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -#include "GrBatchTest.h" +#include "GrDrawOpTest.h" -DRAW_BATCH_TEST_DEFINE(AAStrokeRectBatch) { +DRAW_OP_TEST_DEFINE(AAStrokeRectOp) { bool miterStroke = random->nextBool(); // Create either a empty rect or a non-empty rect. - SkRect rect = random->nextBool() ? SkRect::MakeXYWH(10, 10, 50, 40) : - SkRect::MakeXYWH(6, 7, 0, 0); + SkRect rect = + random->nextBool() ? SkRect::MakeXYWH(10, 10, 50, 40) : SkRect::MakeXYWH(6, 7, 0, 0); SkScalar minDim = SkMinScalar(rect.width(), rect.height()); SkScalar strokeWidth = random->nextUScalar1() * minDim; @@ -613,10 +607,9 @@ DRAW_BATCH_TEST_DEFINE(AAStrokeRectBatch) { SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); rec.setStrokeStyle(strokeWidth); rec.setStrokeParams(SkPaint::kButt_Cap, - miterStroke ? SkPaint::kMiter_Join : SkPaint::kBevel_Join, - 1.f); + miterStroke ? SkPaint::kMiter_Join : SkPaint::kBevel_Join, 1.f); SkMatrix matrix = GrTest::TestMatrixRectStaysRect(random); - return GrAAStrokeRectBatch::Create(color, matrix, rect, rec); + return GrAAStrokeRectOp::Make(color, matrix, rect, rec); } #endif diff --git a/gfx/skia/skia/src/gpu/ops/GrAAStrokeRectOp.h b/gfx/skia/skia/src/gpu/ops/GrAAStrokeRectOp.h new file mode 100644 index 000000000000..074f8e00e91e --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrAAStrokeRectOp.h @@ -0,0 +1,32 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrAAStrokeRectOp_DEFINED +#define GrAAStrokeRectOp_DEFINED + +#include "GrColor.h" +#include "SkRefCnt.h" + +class GrLegacyMeshDrawOp; +class SkMatrix; +struct SkRect; +class SkStrokeRec; + +namespace GrAAStrokeRectOp { + +std::unique_ptr MakeFillBetweenRects(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& devOutside, + const SkRect& devInside); + +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkStrokeRec& stroke); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAnalyticRectBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrAnalyticRectOp.cpp similarity index 69% rename from gfx/skia/skia/src/gpu/batches/GrAnalyticRectBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrAnalyticRectOp.cpp index 311c6521372b..6a9daf305ae1 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAnalyticRectBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrAnalyticRectOp.cpp @@ -5,37 +5,34 @@ * found in the LICENSE file. */ -#include "GrAnalyticRectBatch.h" +#include "GrAnalyticRectOp.h" -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" +#include "GrDrawOpTest.h" #include "GrGeometryProcessor.h" -#include "GrInvariantOutput.h" +#include "GrOpFlushState.h" #include "GrProcessor.h" #include "GrResourceProvider.h" #include "SkRRect.h" #include "SkStrokeRec.h" -#include "batches/GrVertexBatch.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" -#include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLVarying.h" -#include "glsl/GrGLSLVertexShaderBuilder.h" #include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLUtil.h" +#include "glsl/GrGLSLVarying.h" +#include "glsl/GrGLSLVertexShaderBuilder.h" +#include "ops/GrMeshDrawOp.h" namespace { struct RectVertex { - SkPoint fPos; - GrColor fColor; - SkPoint fCenter; + SkPoint fPos; + GrColor fColor; + SkPoint fCenter; SkVector fDownDir; SkScalar fHalfWidth; SkScalar fHalfHeight; }; - } /////////////////////////////////////////////////////////////////////////////// @@ -56,23 +53,23 @@ class RectGeometryProcessor : public GrGeometryProcessor { public: RectGeometryProcessor(const SkMatrix& localMatrix) : fLocalMatrix(localMatrix) { this->initClassID(); - fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); - fInRectEdge = &this->addVertexAttrib("inRectEdge", kVec4f_GrVertexAttribType); + fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, + kHigh_GrSLPrecision); + fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); + fInRectEdge = &this->addVertexAttrib("inRectEdge", kVec4f_GrVertexAttribType); fInWidthHeight = &this->addVertexAttrib("inWidthHeight", kVec2f_GrVertexAttribType); } bool implementsDistanceVector() const override { return true; } - const Attribute* inPosition() const { return fInPosition; } - const Attribute* inColor() const { return fInColor; } - const Attribute* inRectEdge() const { return fInRectEdge; } + const Attribute* inPosition() const { return fInPosition; } + const Attribute* inColor() const { return fInColor; } + const Attribute* inRectEdge() const { return fInRectEdge; } const Attribute* inWidthHeight() const { return fInWidthHeight; } const SkMatrix& localMatrix() const { return fLocalMatrix; } - virtual ~RectGeometryProcessor() {} + ~RectGeometryProcessor() override {} const char* name() const override { return "RectEdge"; } @@ -80,7 +77,7 @@ public: public: GLSLProcessor() {} - void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ + void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const RectGeometryProcessor& rgp = args.fGP.cast(); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; @@ -103,8 +100,8 @@ public: // setup the varying for the width/2+.5 and height/2+.5 GrGLSLVertToFrag widthHeightVary(kVec2f_GrSLType); varyingHandler->addVarying("WidthHeight", &widthHeightVary); - vertBuilder->codeAppendf("%s = %s;", - widthHeightVary.vsOut(), rgp.inWidthHeight()->fName); + vertBuilder->codeAppendf("%s = %s;", widthHeightVary.vsOut(), + rgp.inWidthHeight()->fName); GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -139,8 +136,8 @@ public: fragBuilder->codeAppend("float scaleW = min(1.0, 2.0*insetW/spanW);"); fragBuilder->codeAppend("float scaleH = min(1.0, 2.0*insetH/spanH);"); // Compute the coverage for the rect's width - fragBuilder->codeAppendf("vec2 offset = %s.xy - %s.xy;", - positionVary.fsIn(), rectEdgeVary.fsIn()); + fragBuilder->codeAppendf("vec2 offset = %s.xy - %s.xy;", positionVary.fsIn(), + rectEdgeVary.fsIn()); fragBuilder->codeAppendf("float perpDot = abs(offset.x * %s.w - offset.y * %s.z);", rectEdgeVary.fsIn(), rectEdgeVary.fsIn()); @@ -153,8 +150,7 @@ public: "float coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);", widthHeightVary.fsIn()); // Compute the coverage for the rect's height and merge with the width - fragBuilder->codeAppendf("perpDot = abs(dot(offset, %s.zw));", - rectEdgeVary.fsIn()); + fragBuilder->codeAppendf("perpDot = abs(dot(offset, %s.zw));", rectEdgeVary.fsIn()); if (args.fDistanceVectorName) { fragBuilder->codeAppendf("float heightDistance = %s.y - perpDot;", @@ -168,28 +164,27 @@ public: fragBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverage); if (args.fDistanceVectorName) { - fragBuilder->codeAppend( "// Calculating distance vector\n"); - fragBuilder->codeAppend( "vec2 dvAxis;"); - fragBuilder->codeAppend( "float dvLength;"); + fragBuilder->codeAppend("// Calculating distance vector\n"); + fragBuilder->codeAppend("vec2 dvAxis;"); + fragBuilder->codeAppend("float dvLength;"); - fragBuilder->codeAppend( "if (heightDistance < widthDistance) {"); + fragBuilder->codeAppend("if (heightDistance < widthDistance) {"); fragBuilder->codeAppendf(" dvAxis = %s.zw;", rectEdgeVary.fsIn()); - fragBuilder->codeAppend( " dvLength = heightDistance;"); - fragBuilder->codeAppend( "} else {"); - fragBuilder->codeAppendf(" dvAxis = vec2(-%s.w, %s.z);", - rectEdgeVary.fsIn(), rectEdgeVary.fsIn()); - fragBuilder->codeAppend( " dvLength = widthDistance;"); - fragBuilder->codeAppend( "}"); + fragBuilder->codeAppend(" dvLength = heightDistance;"); + fragBuilder->codeAppend("} else {"); + fragBuilder->codeAppendf(" dvAxis = vec2(-%s.w, %s.z);", rectEdgeVary.fsIn(), + rectEdgeVary.fsIn()); + fragBuilder->codeAppend(" dvLength = widthDistance;"); + fragBuilder->codeAppend("}"); - fragBuilder->codeAppend( "float dvSign = sign(dot(offset, dvAxis));"); + fragBuilder->codeAppend("float dvSign = sign(dot(offset, dvAxis));"); fragBuilder->codeAppendf("%s = vec4(dvSign * dvAxis, dvLength, 0.0);", args.fDistanceVectorName); - } } static void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { b->add32(0x0); } @@ -197,23 +192,23 @@ public: void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc, FPCoordTransformIter&& transformIter) override { const RectGeometryProcessor& rgp = primProc.cast(); - this->setTransformDataHelper(rgp.fLocalMatrix, pdman,&transformIter); + this->setTransformDataHelper(rgp.fLocalMatrix, pdman, &transformIter); } private: typedef GrGLSLGeometryProcessor INHERITED; }; - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLProcessor::GenKey(*this, caps, b); } - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { return new GLSLProcessor(); } private: - SkMatrix fLocalMatrix; + SkMatrix fLocalMatrix; const Attribute* fInPosition; const Attribute* fInColor; @@ -227,21 +222,21 @@ private: GR_DEFINE_GEOMETRY_PROCESSOR_TEST(RectGeometryProcessor); +#if GR_TEST_UTILS sk_sp RectGeometryProcessor::TestCreate(GrProcessorTestData* d) { - return sk_sp( - new RectGeometryProcessor(GrTest::TestMatrix(d->fRandom))); + return sk_sp(new RectGeometryProcessor(GrTest::TestMatrix(d->fRandom))); } +#endif /////////////////////////////////////////////////////////////////////////////// -class AnalyticRectBatch : public GrVertexBatch { +class AnalyticRectOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - AnalyticRectBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, - const SkRect& croppedRect, const SkRect& bounds) - : INHERITED(ClassID()) - , fViewMatrixIfUsingLocalCoords(viewMatrix) { + AnalyticRectOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, + const SkRect& croppedRect, const SkRect& bounds) + : INHERITED(ClassID()), fViewMatrixIfUsingLocalCoords(viewMatrix) { SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY()); viewMatrix.mapPoints(¢er, 1); SkScalar halfWidth = viewMatrix.mapRadius(SkScalarHalf(rect.width())); @@ -252,41 +247,37 @@ public: SkRect deviceSpaceCroppedRect = croppedRect; viewMatrix.mapRect(&deviceSpaceCroppedRect); - fGeoData.emplace_back(Geometry {color, center, downDir, halfWidth, halfHeight, - deviceSpaceCroppedRect}); + fGeoData.emplace_back( + Geometry{color, center, downDir, halfWidth, halfHeight, deviceSpaceCroppedRect}); this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo); } - const char* name() const override { return "AnalyticRectBatch"; } + const char* name() const override { return "AnalyticRectOp"; } SkString dumpInfo() const override { SkString string; for (int i = 0; i < fGeoData.count(); ++i) { string.appendf("Color: 0x%08x Rect [C:(%.2f, %.2f) D:<%.2f,%.3f> W/2:%.2f H/2:%.2f]\n", - fGeoData[i].fColor, - fGeoData[i].fCenter.x(), fGeoData[i].fCenter.y(), + fGeoData[i].fColor, fGeoData[i].fCenter.x(), fGeoData[i].fCenter.y(), fGeoData[i].fDownDir.x(), fGeoData[i].fDownDir.y(), - fGeoData[i].fHalfWidth, - fGeoData[i].fHalfHeight); + fGeoData[i].fHalfWidth, fGeoData[i].fHalfHeight); } + string.append(DumpPipelineInfo(*this->pipeline())); string.append(INHERITED::dumpInfo()); return string; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); +private: + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fGeoData[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; } -private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any overrides that affect our GP. - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); - if (!overrides.readsLocalCoords()) { + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fGeoData[0].fColor); + if (!optimizations.readsLocalCoords()) { fViewMatrixIfUsingLocalCoords.reset(); } } @@ -298,14 +289,14 @@ private: } // Setup geometry processor - SkAutoTUnref gp(new RectGeometryProcessor(localMatrix)); + sk_sp gp(new RectGeometryProcessor(localMatrix)); int instanceCount = fGeoData.count(); size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(RectVertex)); QuadHelper helper; - RectVertex* verts = reinterpret_cast(helper.init(target, vertexStride, - instanceCount)); + RectVertex* verts = + reinterpret_cast(helper.init(target, vertexStride, instanceCount)); if (!verts) { return; } @@ -313,12 +304,12 @@ private: for (int i = 0; i < instanceCount; i++) { const Geometry& geom = fGeoData[i]; - GrColor color = geom.fColor; - SkPoint center = geom.fCenter; - SkVector downDir = geom.fDownDir; - SkScalar halfWidth = geom.fHalfWidth; - SkScalar halfHeight = geom.fHalfHeight; - SkRect croppedRect = geom.fCroppedRect; + GrColor color = geom.fColor; + SkPoint center = geom.fCenter; + SkVector downDir = geom.fDownDir; + SkScalar halfWidth = geom.fHalfWidth; + SkScalar halfHeight = geom.fHalfHeight; + SkRect croppedRect = geom.fCroppedRect; SkVector rightDir; downDir.rotateCCW(&rightDir); @@ -353,11 +344,11 @@ private: verts += kVerticesPerQuad; } - helper.recordDraw(target, gp); + helper.recordDraw(target, gp.get(), this->pipeline()); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - AnalyticRectBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + AnalyticRectOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; @@ -373,37 +364,39 @@ private: } struct Geometry { - GrColor fColor; - SkPoint fCenter; + GrColor fColor; + SkPoint fCenter; SkVector fDownDir; SkScalar fHalfWidth; SkScalar fHalfHeight; - SkRect fCroppedRect; + SkRect fCroppedRect; }; - SkMatrix fViewMatrixIfUsingLocalCoords; + SkMatrix fViewMatrixIfUsingLocalCoords; SkSTArray<1, Geometry, true> fGeoData; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -GrDrawBatch* GrAnalyticRectBatch::CreateAnalyticRectBatch(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& croppedRect, - const SkRect& bounds) { - return new AnalyticRectBatch(color, viewMatrix, rect, croppedRect, bounds); +std::unique_ptr GrAnalyticRectOp::Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect& croppedRect, + const SkRect& bounds) { + return std::unique_ptr( + new AnalyticRectOp(color, viewMatrix, rect, croppedRect, bounds)); } -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -DRAW_BATCH_TEST_DEFINE(AnalyticRectBatch) { +DRAW_OP_TEST_DEFINE(AnalyticRectOp) { SkMatrix viewMatrix = GrTest::TestMatrix(random); GrColor color = GrRandomColor(random); SkRect rect = GrTest::TestSquare(random); SkRect croppedRect = GrTest::TestSquare(random); SkRect bounds = GrTest::TestSquare(random); - return new AnalyticRectBatch(color, viewMatrix, rect, croppedRect, bounds); + return std::unique_ptr( + new AnalyticRectOp(color, viewMatrix, rect, croppedRect, bounds)); } #endif diff --git a/gfx/skia/skia/src/gpu/batches/GrAnalyticRectBatch.h b/gfx/skia/skia/src/gpu/ops/GrAnalyticRectOp.h similarity index 53% rename from gfx/skia/skia/src/gpu/batches/GrAnalyticRectBatch.h rename to gfx/skia/skia/src/gpu/ops/GrAnalyticRectOp.h index cdb6118c6ec3..9907de0e6315 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAnalyticRectBatch.h +++ b/gfx/skia/skia/src/gpu/ops/GrAnalyticRectOp.h @@ -5,12 +5,13 @@ * found in the LICENSE file. */ -#ifndef GrAnalyticRectBatch_DEFINED -#define GrAnalyticRectBatch_DEFINED +#ifndef GrAnalyticRectOp_DEFINED +#define GrAnalyticRectOp_DEFINED #include "GrColor.h" +#include "SkRefCnt.h" -class GrDrawBatch; +class GrLegacyMeshDrawOp; class SkMatrix; struct SkRect; @@ -24,13 +25,13 @@ struct SkRect; * @param croppedRect the shape in device space, clipped to the device's bounds * @param bounds the axis aligned bounds of the shape in device space */ -class GrAnalyticRectBatch { +class GrAnalyticRectOp { public: - static GrDrawBatch* CreateAnalyticRectBatch(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& croppedRect, - const SkRect& bounds); + static std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect& croppedRect, + const SkRect& bounds); }; -#endif // GrAnalyticRectBatch_DEFINED +#endif // GrAnalyticRectOp_DEFINED diff --git a/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrAtlasTextOp.cpp similarity index 51% rename from gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrAtlasTextOp.cpp index 6427bc0844e4..64710e7d8de4 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrAtlasTextOp.cpp @@ -5,9 +5,10 @@ * found in the LICENSE file. */ -#include "GrAtlasTextBatch.h" +#include "GrAtlasTextOp.h" -#include "GrBatchFlushState.h" +#include "GrContext.h" +#include "GrOpFlushState.h" #include "GrResourceProvider.h" #include "SkGlyphCache.h" @@ -15,7 +16,7 @@ #include "effects/GrBitmapTextGeoProc.h" #include "effects/GrDistanceFieldGeoProc.h" -#include "text/GrBatchFontCache.h" +#include "text/GrAtlasGlyphCache.h" /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -28,7 +29,7 @@ static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { static const int kDistanceAdjustLumShift = 5; -SkString GrAtlasTextBatch::dumpInfo() const { +SkString GrAtlasTextOp::dumpInfo() const { SkString str; for (int i = 0; i < fGeoCount; ++i) { @@ -40,48 +41,41 @@ SkString GrAtlasTextBatch::dumpInfo() const { fGeoData[i].fBlob->runCount()); } + str.append(DumpPipelineInfo(*this->pipeline())); str.append(INHERITED::dumpInfo()); return str; } -void GrAtlasTextBatch::computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const { +void GrAtlasTextOp::getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const { if (kColorBitmapMask_MaskType == fMaskType) { - color->setUnknownFourComponents(); + color->setToUnknown(); } else { - color->setKnownFourComponents(fBatch.fColor); + color->setToConstant(fColor); } switch (fMaskType) { case kGrayscaleDistanceField_MaskType: case kGrayscaleCoverageMask_MaskType: - coverage->setUnknownSingleComponent(); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; break; case kLCDCoverageMask_MaskType: case kLCDDistanceField_MaskType: - coverage->setUnknownOpaqueFourComponents(); - coverage->setUsingLCDCoverage(); + *coverage = GrProcessorAnalysisCoverage::kLCD; break; case kColorBitmapMask_MaskType: - coverage->setKnownSingleComponent(0xff); + *coverage = GrProcessorAnalysisCoverage::kNone; + break; } } -void GrAtlasTextBatch::initBatchTracker(const GrXPOverridesForBatch& overrides) { - // Handle any color overrides - if (!overrides.readsColor()) { - fGeoData[0].fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); +void GrAtlasTextOp::applyPipelineOptimizations(const PipelineOptimizations& optimizations) { + optimizations.getOverrideColorIfSet(&fGeoData[0].fColor); - // setup batch properties - fBatch.fColorIgnored = !overrides.readsColor(); - fBatch.fColor = fGeoData[0].fColor; - fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); - fBatch.fCoverageIgnored = !overrides.readsCoverage(); + fColor = fGeoData[0].fColor; + fUsesLocalCoords = optimizations.readsLocalCoords(); } -void GrAtlasTextBatch::onPrepareDraws(Target* target) const { +void GrAtlasTextOp::onPrepareDraws(Target* target) const { // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix. // TODO actually only invert if we don't have RGBA SkMatrix localMatrix; @@ -90,8 +84,8 @@ void GrAtlasTextBatch::onPrepareDraws(Target* target) const { return; } - GrTexture* texture = fFontCache->getTexture(this->maskFormat()); - if (!texture) { + sk_sp proxy = fFontCache->getProxy(this->maskFormat()); + if (!proxy) { SkDebugf("Could not allocate backing texture for atlas\n"); return; } @@ -101,15 +95,15 @@ void GrAtlasTextBatch::onPrepareDraws(Target* target) const { FlushInfo flushInfo; if (this->usesDistanceFields()) { flushInfo.fGeometryProcessor = - this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(), texture); + this->setupDfProcessor(fFontCache->context()->resourceProvider(), + this->viewMatrix(), + fFilteredColor, this->color(), std::move(proxy)); } else { - GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode); - flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(this->color(), - texture, - params, - maskFormat, - localMatrix, - this->usesLocalCoords()); + GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode); + flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( + fFontCache->context()->resourceProvider(), + this->color(), std::move(proxy), params, + maskFormat, localMatrix, this->usesLocalCoords()); } flushInfo.fGlyphsToFlush = 0; @@ -119,10 +113,8 @@ void GrAtlasTextBatch::onPrepareDraws(Target* target) const { int glyphCount = this->numGlyphs(); const GrBuffer* vertexBuffer; - void* vertices = target->makeVertexSpace(vertexStride, - glyphCount * kVerticesPerGlyph, - &vertexBuffer, - &flushInfo.fVertexOffset); + void* vertices = target->makeVertexSpace( + vertexStride, glyphCount * kVerticesPerGlyph, &vertexBuffer, &flushInfo.fVertexOffset); flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer)); flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer()); if (!vertices || !flushInfo.fVertexBuffer) { @@ -140,50 +132,33 @@ void GrAtlasTextBatch::onPrepareDraws(Target* target) const { size_t byteCount; void* blobVertices; int subRunGlyphCount; - blob->regenInBatch(target, fFontCache, &helper, args.fRun, args.fSubRun, &glyphCache, - vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor, - &blobVertices, &byteCount, &subRunGlyphCount); + blob->regenInOp(target, fFontCache, &helper, args.fRun, args.fSubRun, &glyphCache, + vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor, + &blobVertices, &byteCount, &subRunGlyphCount); // now copy all vertices memcpy(currVertex, blobVertices, byteCount); -#ifdef SK_DEBUG - // bounds sanity check - SkRect rect; - rect.setLargestInverted(); - SkPoint* vertex = (SkPoint*) ((char*)blobVertices); - rect.growToInclude(vertex, vertexStride, kVerticesPerGlyph * subRunGlyphCount); - - if (this->usesDistanceFields()) { - args.fViewMatrix.mapRect(&rect); - } - // Allow for small numerical error in the bounds. - SkRect bounds = this->bounds(); - bounds.outset(0.001f, 0.001f); - SkASSERT(bounds.contains(rect)); -#endif - currVertex += byteCount; } this->flush(target, &flushInfo); } -void GrAtlasTextBatch::flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const { +void GrAtlasTextOp::flush(GrLegacyMeshDrawOp::Target* target, FlushInfo* flushInfo) const { GrMesh mesh; int maxGlyphsPerDraw = - static_cast(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6); - mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, - flushInfo->fIndexBuffer, flushInfo->fVertexOffset, - kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyphsToFlush, - maxGlyphsPerDraw); - target->draw(flushInfo->fGeometryProcessor.get(), mesh); + static_cast(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6); + mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer.get(), + flushInfo->fIndexBuffer.get(), flushInfo->fVertexOffset, kVerticesPerGlyph, + kIndicesPerGlyph, flushInfo->fGlyphsToFlush, maxGlyphsPerDraw); + target->draw(flushInfo->fGeometryProcessor.get(), this->pipeline(), mesh); flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush; flushInfo->fGlyphsToFlush = 0; } -bool GrAtlasTextBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { - GrAtlasTextBatch* that = t->cast(); +bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { + GrAtlasTextOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; @@ -214,7 +189,7 @@ bool GrAtlasTextBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { } } - fBatch.fNumGlyphs += that->numGlyphs(); + fNumGlyphs += that->numGlyphs(); // Reallocate space for geo data if necessary and then import that's geo data. int newGeoCount = that->fGeoCount + fGeoCount; @@ -228,9 +203,9 @@ bool GrAtlasTextBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { fGeoData.realloc(newAllocSize); } - memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry)); - // We steal the ref on the blobs from the other TextBatch and set its count to 0 so that + // We steal the ref on the blobs from the other AtlasTextOp and set its count to 0 so that // it doesn't try to unref them. + memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry)); #ifdef SK_DEBUG for (int i = 0; i < that->fGeoCount; ++i) { that->fGeoData.get()[i].fBlob = (Blob*)0x1; @@ -245,11 +220,12 @@ bool GrAtlasTextBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { // TODO just use class params // TODO trying to figure out why lcd is so whack -sk_sp GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatrix, - SkColor filteredColor, - GrColor color, - GrTexture* texture) const { - GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); +sk_sp GrAtlasTextOp::setupDfProcessor(GrResourceProvider* resourceProvider, + const SkMatrix& viewMatrix, + SkColor filteredColor, + GrColor color, + sk_sp proxy) const { + GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode); bool isLCD = this->isLCD(); // set up any flags uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; @@ -264,50 +240,37 @@ sk_sp GrAtlasTextBatch::setupDfProcessor(const SkMatrix& vi GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor); float redCorrection = fDistanceAdjustTable->getAdjustment( - GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift, - fUseGammaCorrectDistanceTable); + GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift, + fUseGammaCorrectDistanceTable); float greenCorrection = fDistanceAdjustTable->getAdjustment( - GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift, - fUseGammaCorrectDistanceTable); + GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift, + fUseGammaCorrectDistanceTable); float blueCorrection = fDistanceAdjustTable->getAdjustment( - GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift, - fUseGammaCorrectDistanceTable); + GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift, + fUseGammaCorrectDistanceTable); GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust = - GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrection, - greenCorrection, - blueCorrection); + GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make( + redCorrection, greenCorrection, blueCorrection); - return GrDistanceFieldLCDTextGeoProc::Make(color, - viewMatrix, - texture, - params, - widthAdjust, - flags, + return GrDistanceFieldLCDTextGeoProc::Make(resourceProvider, + color, viewMatrix, std::move(proxy), + params, widthAdjust, flags, this->usesLocalCoords()); } else { #ifdef SK_GAMMA_APPLY_TO_A8 U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor); - float correction = fDistanceAdjustTable->getAdjustment( - lum >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable); - return GrDistanceFieldA8TextGeoProc::Make(color, - viewMatrix, - texture, - params, - correction, - flags, + float correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift, + fUseGammaCorrectDistanceTable); + return GrDistanceFieldA8TextGeoProc::Make(resourceProvider, color, + viewMatrix, std::move(proxy), + params, correction, flags, this->usesLocalCoords()); #else - return GrDistanceFieldA8TextGeoProc::Make(color, - viewMatrix, - texture, - params, - flags, - this->usesLocalCoords()); + return GrDistanceFieldA8TextGeoProc::Make(resourceProvider, color, + viewMatrix, std::move(proxy), + params, flags, this->usesLocalCoords()); #endif } - } -void GrBlobRegenHelper::flush() { - fBatch->flush(fTarget, fFlushInfo); -} +void GrBlobRegenHelper::flush() { fOp->flush(fTarget, fFlushInfo); } diff --git a/gfx/skia/skia/src/gpu/ops/GrAtlasTextOp.h b/gfx/skia/skia/src/gpu/ops/GrAtlasTextOp.h new file mode 100644 index 000000000000..8b65fb9aff87 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrAtlasTextOp.h @@ -0,0 +1,206 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrAtlasTextOp_DEFINED +#define GrAtlasTextOp_DEFINED + +#include "ops/GrMeshDrawOp.h" + +#include "text/GrAtlasTextContext.h" +#include "text/GrDistanceFieldAdjustTable.h" + +class GrAtlasTextOp final : public GrLegacyMeshDrawOp { +public: + DEFINE_OP_CLASS_ID + + ~GrAtlasTextOp() override { + for (int i = 0; i < fGeoCount; i++) { + fGeoData[i].fBlob->unref(); + } + } + + static const int kVerticesPerGlyph = GrAtlasTextBlob::kVerticesPerGlyph; + static const int kIndicesPerGlyph = 6; + + typedef GrAtlasTextBlob Blob; + struct Geometry { + SkMatrix fViewMatrix; + Blob* fBlob; + SkScalar fX; + SkScalar fY; + int fRun; + int fSubRun; + GrColor fColor; + }; + + static std::unique_ptr MakeBitmap(GrMaskFormat maskFormat, int glyphCount, + GrAtlasGlyphCache* fontCache) { + std::unique_ptr op(new GrAtlasTextOp); + + op->fFontCache = fontCache; + switch (maskFormat) { + case kA8_GrMaskFormat: + op->fMaskType = kGrayscaleCoverageMask_MaskType; + break; + case kA565_GrMaskFormat: + op->fMaskType = kLCDCoverageMask_MaskType; + break; + case kARGB_GrMaskFormat: + op->fMaskType = kColorBitmapMask_MaskType; + break; + } + op->fNumGlyphs = glyphCount; + op->fGeoCount = 1; + op->fFilteredColor = 0; + op->fFontCache = fontCache; + op->fUseBGR = false; + return op; + } + + static std::unique_ptr MakeDistanceField( + int glyphCount, GrAtlasGlyphCache* fontCache, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + bool useGammaCorrectDistanceTable, SkColor filteredColor, bool isLCD, bool useBGR) { + std::unique_ptr op(new GrAtlasTextOp); + + op->fFontCache = fontCache; + op->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistanceField_MaskType; + op->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable)); + op->fUseGammaCorrectDistanceTable = useGammaCorrectDistanceTable; + op->fFilteredColor = filteredColor; + op->fUseBGR = useBGR; + op->fNumGlyphs = glyphCount; + op->fGeoCount = 1; + return op; + } + + // To avoid even the initial copy of the struct, we have a getter for the first item which + // is used to seed the op with its initial geometry. After seeding, the client should call + // init() so the op can initialize itself + Geometry& geometry() { return fGeoData[0]; } + + void init() { + const Geometry& geo = fGeoData[0]; + fColor = geo.fColor; + SkRect bounds; + geo.fBlob->computeSubRunBounds(&bounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX, + geo.fY); + // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds + // we treat this as a set of non-AA rects rendered with a texture. + this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); + } + + const char* name() const override { return "AtlasTextOp"; } + + SkString dumpInfo() const override; + +private: + void getProcessorAnalysisInputs(GrProcessorAnalysisColor*, + GrProcessorAnalysisCoverage*) const override; + void applyPipelineOptimizations(const PipelineOptimizations&) override; + + struct FlushInfo { + sk_sp fVertexBuffer; + sk_sp fIndexBuffer; + sk_sp fGeometryProcessor; + int fGlyphsToFlush; + int fVertexOffset; + }; + + void onPrepareDraws(Target* target) const override; + + GrAtlasTextOp() : INHERITED(ClassID()) {} // initialized in factory functions. + + GrMaskFormat maskFormat() const { + switch (fMaskType) { + case kLCDCoverageMask_MaskType: + return kA565_GrMaskFormat; + case kColorBitmapMask_MaskType: + return kARGB_GrMaskFormat; + case kGrayscaleCoverageMask_MaskType: + case kGrayscaleDistanceField_MaskType: + case kLCDDistanceField_MaskType: + return kA8_GrMaskFormat; + } + return kA8_GrMaskFormat; // suppress warning + } + + bool usesDistanceFields() const { + return kGrayscaleDistanceField_MaskType == fMaskType || + kLCDDistanceField_MaskType == fMaskType; + } + + bool isLCD() const { + return kLCDCoverageMask_MaskType == fMaskType || kLCDDistanceField_MaskType == fMaskType; + } + + inline void flush(GrLegacyMeshDrawOp::Target* target, FlushInfo* flushInfo) const; + + GrColor color() const { return fColor; } + const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } + bool usesLocalCoords() const { return fUsesLocalCoords; } + int numGlyphs() const { return fNumGlyphs; } + + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override; + + // TODO just use class params + // TODO trying to figure out why lcd is so whack + sk_sp setupDfProcessor(GrResourceProvider*, + const SkMatrix& viewMatrix, SkColor filteredColor, + GrColor color, sk_sp proxy) const; + + GrColor fColor; + bool fUsesLocalCoords; + int fNumGlyphs; + + // The minimum number of Geometry we will try to allocate. + enum { kMinGeometryAllocated = 4 }; + SkAutoSTMalloc fGeoData; + int fGeoCount; + + enum MaskType { + kGrayscaleCoverageMask_MaskType, + kLCDCoverageMask_MaskType, + kColorBitmapMask_MaskType, + kGrayscaleDistanceField_MaskType, + kLCDDistanceField_MaskType, + } fMaskType; + bool fUseBGR; // fold this into the enum? + + GrAtlasGlyphCache* fFontCache; + + // Distance field properties + sk_sp fDistanceAdjustTable; + SkColor fFilteredColor; + bool fUseGammaCorrectDistanceTable; + + friend class GrBlobRegenHelper; // Needs to trigger flushes + + typedef GrLegacyMeshDrawOp INHERITED; +}; + +/* + * A simple helper class to abstract the interface GrAtlasTextBlob needs to regenerate itself. + * It'd be nicer if this was nested, but we need to forward declare it in GrAtlasTextBlob.h + */ +class GrBlobRegenHelper { +public: + GrBlobRegenHelper(const GrAtlasTextOp* op, GrLegacyMeshDrawOp::Target* target, + GrAtlasTextOp::FlushInfo* flushInfo) + : fOp(op), fTarget(target), fFlushInfo(flushInfo) {} + + void flush(); + + void incGlyphCount(int glyphCount = 1) { fFlushInfo->fGlyphsToFlush += glyphCount; } + +private: + const GrAtlasTextOp* fOp; + GrLegacyMeshDrawOp::Target* fTarget; + GrAtlasTextOp::FlushInfo* fFlushInfo; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrClearOp.h b/gfx/skia/skia/src/gpu/ops/GrClearOp.h new file mode 100644 index 000000000000..5340af11729e --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrClearOp.h @@ -0,0 +1,158 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrClearOp_DEFINED +#define GrClearOp_DEFINED + +#include "GrFixedClip.h" +#include "GrGpu.h" +#include "GrGpuCommandBuffer.h" +#include "GrOp.h" +#include "GrOpFlushState.h" +#include "GrRenderTarget.h" + +class GrClearOp final : public GrOp { +public: + DEFINE_OP_CLASS_ID + + // MDB TODO: replace the renderTargetContext with just the renderTargetProxy. + // For now, we need the renderTargetContext for its accessRenderTarget powers. + static std::unique_ptr Make(const GrFixedClip& clip, GrColor color, + GrRenderTargetContext* rtc) { + const SkIRect rtRect = SkIRect::MakeWH(rtc->width(), rtc->height()); + if (clip.scissorEnabled() && !SkIRect::Intersects(clip.scissorRect(), rtRect)) { + return nullptr; + } + + // MDB TODO: remove this. In this hybrid state we need to be sure the RT is instantiable + // so it can carry the IO refs. In the future we will just get the proxy and + // it carry the IO refs. + if (!rtc->accessRenderTarget()) { + return nullptr; + } + + return std::unique_ptr(new GrClearOp(clip, color, rtc)); + } + + // MDB TODO: replace the renderTargetContext with just the renderTargetProxy. + static std::unique_ptr Make(const SkIRect& rect, GrColor color, + GrRenderTargetContext* rtc, + bool fullScreen) { + SkASSERT(fullScreen || !rect.isEmpty()); + + // MDB TODO: remove this. See above comment. + if (!rtc->accessRenderTarget()) { + return nullptr; + } + + return std::unique_ptr(new GrClearOp(rect, color, rtc, fullScreen)); + } + + const char* name() const override { return "Clear"; } + + SkString dumpInfo() const override { + SkString string; + string.appendf("rtID: %d proxyID: %d Scissor [", + fRenderTarget.get()->uniqueID().asUInt(), + fProxyUniqueID.asUInt()); + if (fClip.scissorEnabled()) { + const SkIRect& r = fClip.scissorRect(); + string.appendf("L: %d, T: %d, R: %d, B: %d", r.fLeft, r.fTop, r.fRight, r.fBottom); + } else { + string.append("disabled"); + } + string.appendf("], Color: 0x%08x ", fColor); + string.append(INHERITED::dumpInfo()); + return string; + } + + void setColor(GrColor color) { fColor = color; } + +private: + GrClearOp(const GrFixedClip& clip, GrColor color, GrRenderTargetContext* rtc) + : INHERITED(ClassID()) + , fClip(clip) + , fColor(color) + , fProxyUniqueID(rtc->asSurfaceProxy()->uniqueID()) { + + GrSurfaceProxy* proxy = rtc->asSurfaceProxy(); + const SkIRect rtRect = SkIRect::MakeWH(proxy->width(), proxy->height()); + if (fClip.scissorEnabled()) { + // Don't let scissors extend outside the RT. This may improve op combining. + if (!fClip.intersect(rtRect)) { + SkASSERT(0); // should be caught upstream + fClip = GrFixedClip(SkIRect::MakeEmpty()); + } + + if (GrResourceProvider::IsFunctionallyExact(proxy) && fClip.scissorRect() == rtRect) { + fClip.disableScissor(); + } + } + this->setBounds(SkRect::Make(fClip.scissorEnabled() ? fClip.scissorRect() : rtRect), + HasAABloat::kNo, IsZeroArea::kNo); + fRenderTarget.reset(rtc->accessRenderTarget()); + } + + GrClearOp(const SkIRect& rect, GrColor color, GrRenderTargetContext* rtc, bool fullScreen) + : INHERITED(ClassID()) + , fClip(GrFixedClip(rect)) + , fColor(color) + , fProxyUniqueID(rtc->asSurfaceProxy()->uniqueID()) { + + if (fullScreen) { + fClip.disableScissor(); + } + this->setBounds(SkRect::Make(rect), HasAABloat::kNo, IsZeroArea::kNo); + fRenderTarget.reset(rtc->accessRenderTarget()); + } + + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + // This could be much more complicated. Currently we look at cases where the new clear + // contains the old clear, or when the new clear is a subset of the old clear and is the + // same color. + GrClearOp* cb = t->cast(); + SkASSERT(cb->fRenderTarget == fRenderTarget); + SkASSERT(cb->fProxyUniqueID == fProxyUniqueID); + if (fClip.windowRectsState() != cb->fClip.windowRectsState()) { + return false; + } + if (cb->contains(this)) { + fClip = cb->fClip; + this->replaceBounds(*t); + fColor = cb->fColor; + return true; + } else if (cb->fColor == fColor && this->contains(cb)) { + return true; + } + return false; + } + + bool contains(const GrClearOp* that) const { + // The constructor ensures that scissor gets disabled on any clip that fills the entire RT. + return !fClip.scissorEnabled() || + (that->fClip.scissorEnabled() && + fClip.scissorRect().contains(that->fClip.scissorRect())); + } + + void onPrepare(GrOpFlushState*) override {} + + void onExecute(GrOpFlushState* state) override { + // MDB TODO: instantiate the renderTarget from the proxy in here + state->commandBuffer()->clear(fRenderTarget.get(), fClip, fColor); + } + + GrFixedClip fClip; + GrColor fColor; + + // MDB TODO: remove this. When the renderTargetProxy carries the refs this will be redundant. + GrSurfaceProxy::UniqueID fProxyUniqueID; + GrPendingIOResource fRenderTarget; + + typedef GrOp INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrClearStencilClipOp.h b/gfx/skia/skia/src/gpu/ops/GrClearStencilClipOp.h new file mode 100644 index 000000000000..1b7d103998c1 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrClearStencilClipOp.h @@ -0,0 +1,86 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrClearStencilClipOp_DEFINED +#define GrClearStencilClipOp_DEFINED + +#include "GrFixedClip.h" +#include "GrGpu.h" +#include "GrGpuCommandBuffer.h" +#include "GrOp.h" +#include "GrOpFlushState.h" +#include "GrRenderTarget.h" + +class GrClearStencilClipOp final : public GrOp { +public: + DEFINE_OP_CLASS_ID + + // MDB TODO: replace the renderTargetContext with just the renderTargetProxy. + // For now, we need the renderTargetContext for its accessRenderTarget powers. + static std::unique_ptr Make(const GrFixedClip& clip, bool insideStencilMask, + GrRenderTargetContext* rtc) { + + // MDB TODO: remove this. In this hybrid state we need to be sure the RT is instantiable + // so it can carry the IO refs. In the future we will just get the proxy and + // it carry the IO refs. + if (!rtc->accessRenderTarget()) { + return nullptr; + } + + return std::unique_ptr(new GrClearStencilClipOp(clip, insideStencilMask, rtc)); + } + + const char* name() const override { return "ClearStencilClip"; } + + SkString dumpInfo() const override { + SkString string("Scissor ["); + if (fClip.scissorEnabled()) { + const SkIRect& r = fClip.scissorRect(); + string.appendf("L: %d, T: %d, R: %d, B: %d", r.fLeft, r.fTop, r.fRight, r.fBottom); + } + string.appendf("], IC: %d, rtID: %d proxyID: %d", + fInsideStencilMask, + fRenderTarget.get()->uniqueID().asUInt(), + fProxyUniqueID.asUInt()); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + GrClearStencilClipOp(const GrFixedClip& clip, bool insideStencilMask, + GrRenderTargetContext* rtc) + : INHERITED(ClassID()) + , fClip(clip) + , fInsideStencilMask(insideStencilMask) + , fProxyUniqueID(rtc->asSurfaceProxy()->uniqueID()) { + const SkRect& bounds = fClip.scissorEnabled() + ? SkRect::Make(fClip.scissorRect()) + : SkRect::MakeIWH(rtc->width(), rtc->height()); + this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); + + fRenderTarget.reset(rtc->accessRenderTarget()); + } + + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { return false; } + + void onPrepare(GrOpFlushState*) override {} + + void onExecute(GrOpFlushState* state) override { + // MDB TODO: instantiate the renderTarget from the proxy in here + state->commandBuffer()->clearStencilClip(fRenderTarget.get(), fClip, fInsideStencilMask); + } + + const GrFixedClip fClip; + const bool fInsideStencilMask; + // MDB TODO: remove this. When the renderTargetProxy carries the refs this will be redundant. + GrSurfaceProxy::UniqueID fProxyUniqueID; + GrPendingIOResource fRenderTarget; + + typedef GrOp INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrCopySurfaceBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrCopySurfaceOp.cpp similarity index 51% rename from gfx/skia/skia/src/gpu/batches/GrCopySurfaceBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrCopySurfaceOp.cpp index a59ed38f51e6..5feed18f76fb 100644 --- a/gfx/skia/skia/src/gpu/batches/GrCopySurfaceBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrCopySurfaceOp.cpp @@ -5,16 +5,15 @@ * found in the LICENSE file. */ - -#include "GrCopySurfaceBatch.h" +#include "GrCopySurfaceOp.h" // returns true if the read/written rect intersects the src/dst and false if not. -bool GrCopySurfaceBatch::ClipSrcRectAndDstPoint(const GrSurface* dst, - const GrSurface* src, - const SkIRect& srcRect, - const SkIPoint& dstPoint, - SkIRect* clippedSrcRect, - SkIPoint* clippedDstPoint) { +static bool clip_src_rect_and_dst_point(const GrSurfaceProxy* dst, + const GrSurfaceProxy* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint, + SkIRect* clippedSrcRect, + SkIPoint* clippedDstPoint) { *clippedSrcRect = srcRect; *clippedDstPoint = dstPoint; @@ -59,16 +58,37 @@ bool GrCopySurfaceBatch::ClipSrcRectAndDstPoint(const GrSurface* dst, return !clippedSrcRect->isEmpty(); } -GrBatch* GrCopySurfaceBatch::Create(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, - const SkIPoint& dstPoint) { - SkASSERT(dst); - SkASSERT(src); - - SkIRect clippedSrcRect; - SkIPoint clippedDstPoint; - // If the rect is outside the src or dst then we've already succeeded. - if (!ClipSrcRectAndDstPoint(dst, src, srcRect, dstPoint, &clippedSrcRect, &clippedDstPoint)) { +std::unique_ptr GrCopySurfaceOp::Make(GrResourceProvider* resourceProvider, + GrSurfaceProxy* dstProxy, GrSurfaceProxy* srcProxy, + const SkIRect& srcRect, + const SkIPoint& dstPoint) { + SkASSERT(dstProxy); + SkASSERT(srcProxy); + if (GrPixelConfigIsSint(dstProxy->config()) != GrPixelConfigIsSint(srcProxy->config())) { return nullptr; } - return new GrCopySurfaceBatch(dst, src, clippedSrcRect, clippedDstPoint); + if (GrPixelConfigIsCompressed(dstProxy->config())) { + return nullptr; + } + SkIRect clippedSrcRect; + SkIPoint clippedDstPoint; + // If the rect is outside the srcProxy or dstProxy then we've already succeeded. + if (!clip_src_rect_and_dst_point(dstProxy, srcProxy, srcRect, dstPoint, + &clippedSrcRect, &clippedDstPoint)) { + return nullptr; + } + + // MDB TODO: remove this instantiation + GrSurface* dstTex = dstProxy->instantiate(resourceProvider); + if (!dstTex) { + return nullptr; + } + GrSurface* srcTex = srcProxy->instantiate(resourceProvider); + if (!srcTex) { + return nullptr; + } + + return std::unique_ptr(new GrCopySurfaceOp(dstTex, srcTex, + dstProxy->uniqueID(), srcProxy->uniqueID(), + clippedSrcRect, clippedDstPoint)); } diff --git a/gfx/skia/skia/src/gpu/ops/GrCopySurfaceOp.h b/gfx/skia/skia/src/gpu/ops/GrCopySurfaceOp.h new file mode 100644 index 000000000000..05ee8d0a0043 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrCopySurfaceOp.h @@ -0,0 +1,81 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrCopySurfaceOp_DEFINED +#define GrCopySurfaceOp_DEFINED + +#include "GrOp.h" +#include "GrOpFlushState.h" + +class GrCopySurfaceOp final : public GrOp { +public: + DEFINE_OP_CLASS_ID + + // MDB TODO: remove the resourceProvider parameter + static std::unique_ptr Make(GrResourceProvider*, + GrSurfaceProxy* dst, GrSurfaceProxy* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint); + + const char* name() const override { return "CopySurface"; } + + SkString dumpInfo() const override { + SkString string; + string.printf("src: (proxyID: %d, rtID: %d), dst: (proxyID: %d, rtID: %d), " + "srcRect: [L: %d, T: %d, R: %d, B: %d], dstPt: [X: %d, Y: %d]", + fSrcProxyID.asUInt(), fSrc.get()->uniqueID().asUInt(), + fDstProxyID.asUInt(), fDst.get()->uniqueID().asUInt(), + fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom, + fDstPoint.fX, fDstPoint.fY); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + GrCopySurfaceOp(GrSurface* dst, GrSurface* src, + GrSurfaceProxy::UniqueID dstID, GrSurfaceProxy::UniqueID srcID, + const SkIRect& srcRect, const SkIPoint& dstPoint) + : INHERITED(ClassID()) + , fDstProxyID(dstID) + , fSrcProxyID(srcID) + , fDst(dst) + , fSrc(src) + , fSrcRect(srcRect) + , fDstPoint(dstPoint) { + SkRect bounds = + SkRect::MakeXYWH(SkIntToScalar(dstPoint.fX), SkIntToScalar(dstPoint.fY), + SkIntToScalar(srcRect.width()), SkIntToScalar(srcRect.height())); + this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); + } + + bool onCombineIfPossible(GrOp* that, const GrCaps& caps) override { return false; } + + void onPrepare(GrOpFlushState*) override {} + + void onExecute(GrOpFlushState* state) override { + if (!state->commandBuffer()) { + state->gpu()->copySurface(fDst.get(), fSrc.get(), fSrcRect, fDstPoint); + } else { + // Currently we are not sending copies through the GrGpuCommandBuffer. See comment in + // renderTargetUniqueID(). + SkASSERT(false); + } + } + + // MDB TODO: remove the proxy IDs once the GrSurfaceProxy carries the ref since they will + // be redundant + GrSurfaceProxy::UniqueID fDstProxyID; + GrSurfaceProxy::UniqueID fSrcProxyID; + GrPendingIOResource fDst; + GrPendingIOResource fSrc; + SkIRect fSrcRect; + SkIPoint fDstPoint; + + typedef GrOp INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrDashLinePathRenderer.cpp b/gfx/skia/skia/src/gpu/ops/GrDashLinePathRenderer.cpp new file mode 100644 index 000000000000..cafe2474c763 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrDashLinePathRenderer.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrDashLinePathRenderer.h" + +#include "GrAuditTrail.h" +#include "GrGpu.h" +#include "GrPipelineBuilder.h" +#include "ops/GrDashOp.h" +#include "ops/GrMeshDrawOp.h" + +bool GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { + SkPoint pts[2]; + bool inverted; + if (args.fShape->style().isDashed() && args.fShape->asLine(pts, &inverted)) { + if (args.fAAType == GrAAType::kMixedSamples) { + return false; + } + // We should never have an inverse dashed case. + SkASSERT(!inverted); + return GrDashOp::CanDrawDashLine(pts, args.fShape->style(), *args.fViewMatrix); + } + return false; +} + +bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), + "GrDashLinePathRenderer::onDrawPath"); + GrDashOp::AAMode aaMode = GrDashOp::AAMode::kNone; + switch (args.fAAType) { + case GrAAType::kNone: + break; + case GrAAType::kCoverage: + case GrAAType::kMixedSamples: + aaMode = GrDashOp::AAMode::kCoverage; + break; + case GrAAType::kMSAA: + // In this mode we will use aa between dashes but the outer border uses MSAA. Otherwise, + // we can wind up with external edges antialiased and internal edges unantialiased. + aaMode = GrDashOp::AAMode::kCoverageWithMSAA; + break; + } + SkPoint pts[2]; + SkAssertResult(args.fShape->asLine(pts, nullptr)); + std::unique_ptr op = GrDashOp::MakeDashLineOp( + args.fPaint.getColor(), *args.fViewMatrix, pts, aaMode, args.fShape->style()); + if (!op) { + return false; + } + + GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), args.fAAType); + pipelineBuilder.setUserStencil(args.fUserStencilSettings); + + args.fRenderTargetContext->addLegacyMeshDrawOp( + std::move(pipelineBuilder), *args.fClip, std::move(op)); + return true; +} diff --git a/gfx/skia/skia/src/gpu/batches/GrDashLinePathRenderer.h b/gfx/skia/skia/src/gpu/ops/GrDashLinePathRenderer.h similarity index 93% rename from gfx/skia/skia/src/gpu/batches/GrDashLinePathRenderer.h rename to gfx/skia/skia/src/gpu/ops/GrDashLinePathRenderer.h index d95942177652..482c1a024eec 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDashLinePathRenderer.h +++ b/gfx/skia/skia/src/gpu/ops/GrDashLinePathRenderer.h @@ -10,6 +10,8 @@ #include "GrPathRenderer.h" +#include "GrGpu.h" + class GrDashLinePathRenderer : public GrPathRenderer { private: bool onCanDrawPath(const CanDrawPathArgs&) const override; @@ -20,7 +22,7 @@ private: bool onDrawPath(const DrawPathArgs&) override; - SkAutoTUnref fGpu; + sk_sp fGpu; typedef GrPathRenderer INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/effects/GrDashingEffect.cpp b/gfx/skia/skia/src/gpu/ops/GrDashOp.cpp similarity index 87% rename from gfx/skia/skia/src/gpu/effects/GrDashingEffect.cpp rename to gfx/skia/skia/src/gpu/ops/GrDashOp.cpp index 9ce725b7e65e..01ae34b98c09 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDashingEffect.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrDashOp.cpp @@ -5,34 +5,33 @@ * found in the LICENSE file. */ -#include "GrDashingEffect.h" +#include "GrDashOp.h" -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" #include "GrCaps.h" -#include "GrGeometryProcessor.h" #include "GrContext.h" #include "GrCoordTransform.h" #include "GrDefaultGeoProcFactory.h" -#include "GrInvariantOutput.h" +#include "GrDrawOpTest.h" +#include "GrGeometryProcessor.h" +#include "GrOpFlushState.h" #include "GrProcessor.h" #include "GrStyle.h" #include "SkGr.h" -#include "batches/GrVertexBatch.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" #include "glsl/GrGLSLVertexShaderBuilder.h" +#include "ops/GrMeshDrawOp.h" -using AAMode = GrDashingEffect::AAMode; +using AAMode = GrDashOp::AAMode; /////////////////////////////////////////////////////////////////////////////// // Returns whether or not the gpu can fast path the dash line effect. -bool GrDashingEffect::CanDrawDashLine(const SkPoint pts[2], const GrStyle& style, - const SkMatrix& viewMatrix) { +bool GrDashOp::CanDrawDashLine(const SkPoint pts[2], const GrStyle& style, + const SkMatrix& viewMatrix) { // Pts must be either horizontal or vertical in src space if (pts[0].fX != pts[1].fX && pts[0].fY != pts[1].fY) { return false; @@ -238,10 +237,10 @@ static sk_sp make_dash_gp(GrColor, const SkMatrix& localMatrix, bool usesLocalCoords); -class DashBatch : public GrVertexBatch { +class DashOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID - struct Geometry { + DEFINE_OP_CLASS_ID + struct LineData { SkMatrix fViewMatrix; SkMatrix fSrcRotInv; SkPoint fPtsRot[2]; @@ -250,34 +249,38 @@ public: SkScalar fIntervals[2]; SkScalar fParallelScale; SkScalar fPerpendicularScale; - GrColor fColor; }; - static GrDrawBatch* Create(const Geometry& geometry, SkPaint::Cap cap, AAMode aaMode, - bool fullDash) { - return new DashBatch(geometry, cap, aaMode, fullDash); + static std::unique_ptr Make(const LineData& geometry, GrColor color, + SkPaint::Cap cap, AAMode aaMode, + bool fullDash) { + return std::unique_ptr( + new DashOp(geometry, color, cap, aaMode, fullDash)); } - const char* name() const override { return "DashBatch"; } + const char* name() const override { return "DashOp"; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); + SkString dumpInfo() const override { + SkString string; + for (const auto& geo : fLines) { + string.appendf("Pt0: [%.2f, %.2f], Pt1: [%.2f, %.2f], Width: %.2f, Ival0: %.2f, " + "Ival1 : %.2f, Phase: %.2f\n", + geo.fPtsRot[0].fX, geo.fPtsRot[0].fY, + geo.fPtsRot[1].fX, geo.fPtsRot[1].fY, + geo.fSrcStrokeWidth, + geo.fIntervals[0], + geo.fIntervals[1], + geo.fPhase); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; } - SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } - private: - DashBatch(const Geometry& geometry, SkPaint::Cap cap, AAMode aaMode, bool fullDash) - : INHERITED(ClassID()) { - fGeoData.push_back(geometry); - - fBatch.fAAMode = aaMode; - fBatch.fCap = cap; - fBatch.fFullDash = fullDash; + DashOp(const LineData& geometry, GrColor color, SkPaint::Cap cap, AAMode aaMode, bool fullDash) + : INHERITED(ClassID()), fColor(color), fCap(cap), fAAMode(aaMode), fFullDash(fullDash) { + fLines.push_back(geometry); // compute bounds SkScalar halfStrokeWidth = 0.5f * geometry.fSrcStrokeWidth; @@ -287,7 +290,7 @@ private: bounds.outset(xBloat, halfStrokeWidth); // Note, we actually create the combined matrix here, and save the work - SkMatrix& combinedMatrix = fGeoData[0].fSrcRotInv; + SkMatrix& combinedMatrix = fLines[0].fSrcRotInv; combinedMatrix.postConcat(geometry.fViewMatrix); IsZeroArea zeroArea = geometry.fSrcStrokeWidth ? IsZeroArea::kNo : IsZeroArea::kYes; @@ -295,22 +298,20 @@ private: this->setTransformedBounds(bounds, combinedMatrix, aaBloat, zeroArea); } - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any color overrides - if (!overrides.readsColor()) { - fGeoData[0].fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } - // setup batch properties - fBatch.fColorIgnored = !overrides.readsColor(); - fBatch.fColor = fGeoData[0].fColor; - fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); - fBatch.fCoverageIgnored = !overrides.readsCoverage(); + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fColor); + + fUsesLocalCoords = optimizations.readsLocalCoords(); } struct DashDraw { - DashDraw(const Geometry& geo) { + DashDraw(const LineData& geo) { memcpy(fPtsRot, geo.fPtsRot, sizeof(geo.fPtsRot)); memcpy(fIntervals, geo.fIntervals, sizeof(geo.fIntervals)); fPhase = geo.fPhase; @@ -330,7 +331,7 @@ private: }; void onPrepareDraws(Target* target) const override { - int instanceCount = fGeoData.count(); + int instanceCount = fLines.count(); SkPaint::Cap cap = this->cap(); bool isRoundCap = SkPaint::kRound_Cap == cap; DashCap capType = isRoundCap ? kRound_DashCap : kNonRound_DashCap; @@ -343,11 +344,11 @@ private: // Set up the vertex data for the line and start/end dashes using namespace GrDefaultGeoProcFactory; Color color(this->color()); - Coverage coverage(this->coverageIgnored() ? Coverage::kNone_Type : - Coverage::kSolid_Type); - LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : - LocalCoords::kUnused_Type); - gp = MakeForDeviceSpace(color, coverage, localCoords, this->viewMatrix()); + LocalCoords::Type localCoordsType = this->usesLocalCoords() + ? LocalCoords::kUsePosition_Type + : LocalCoords::kUnused_Type; + gp = MakeForDeviceSpace(color, Coverage::kSolid_Type, localCoordsType, + this->viewMatrix()); } if (!gp) { @@ -370,7 +371,7 @@ private: int rectOffset = 0; rects.push_back_n(3 * instanceCount); for (int i = 0; i < instanceCount; i++) { - const Geometry& args = fGeoData[i]; + const LineData& args = fLines[i]; DashDraw& draw = draws.push_back(args); @@ -572,7 +573,7 @@ private: int curVIdx = 0; int rectIndex = 0; for (int i = 0; i < instanceCount; i++) { - const Geometry& geom = fGeoData[i]; + const LineData& geom = fLines[i]; if (!draws[i].fLineDone) { if (fullDash) { @@ -626,11 +627,11 @@ private: rectIndex++; } SkASSERT(0 == (curVIdx % 4) && (curVIdx / 4) == totalRectCount); - helper.recordDraw(target, gp.get()); + helper.recordDraw(target, gp.get(), this->pipeline()); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - DashBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + DashOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; @@ -658,51 +659,44 @@ private: return false; } - fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); + fLines.push_back_n(that->fLines.count(), that->fLines.begin()); this->joinBounds(*that); return true; } - GrColor color() const { return fBatch.fColor; } - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } - const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } - AAMode aaMode() const { return fBatch.fAAMode; } - bool fullDash() const { return fBatch.fFullDash; } - SkPaint::Cap cap() const { return fBatch.fCap; } - bool coverageIgnored() const { return fBatch.fCoverageIgnored; } - - struct BatchTracker { - GrColor fColor; - bool fUsesLocalCoords; - bool fColorIgnored; - bool fCoverageIgnored; - SkPaint::Cap fCap; - AAMode fAAMode; - bool fFullDash; - }; + GrColor color() const { return fColor; } + bool usesLocalCoords() const { return fUsesLocalCoords; } + const SkMatrix& viewMatrix() const { return fLines[0].fViewMatrix; } + AAMode aaMode() const { return fAAMode; } + bool fullDash() const { return fFullDash; } + SkPaint::Cap cap() const { return fCap; } static const int kVertsPerDash = 4; static const int kIndicesPerDash = 6; - BatchTracker fBatch; - SkSTArray<1, Geometry, true> fGeoData; + GrColor fColor; + bool fUsesLocalCoords; + SkPaint::Cap fCap; + AAMode fAAMode; + bool fFullDash; + SkSTArray<1, LineData, true> fLines; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -GrDrawBatch* GrDashingEffect::CreateDashLineBatch(GrColor color, - const SkMatrix& viewMatrix, - const SkPoint pts[2], - AAMode aaMode, - const GrStyle& style) { - SkASSERT(GrDashingEffect::CanDrawDashLine(pts, style, viewMatrix)); +std::unique_ptr GrDashOp::MakeDashLineOp(GrColor color, + const SkMatrix& viewMatrix, + const SkPoint pts[2], + AAMode aaMode, + const GrStyle& style) { + SkASSERT(GrDashOp::CanDrawDashLine(pts, style, viewMatrix)); const SkScalar* intervals = style.dashIntervals(); SkScalar phase = style.dashPhase(); SkPaint::Cap cap = style.strokeRec().getCap(); - DashBatch::Geometry geometry; - geometry.fSrcStrokeWidth = style.strokeRec().getWidth(); + DashOp::LineData lineData; + lineData.fSrcStrokeWidth = style.strokeRec().getWidth(); // the phase should be normalized to be [0, sum of all intervals) SkASSERT(phase >= 0 && phase < intervals[0] + intervals[1]); @@ -710,24 +704,24 @@ GrDrawBatch* GrDashingEffect::CreateDashLineBatch(GrColor color, // Rotate the src pts so they are aligned horizontally with pts[0].fX < pts[1].fX if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) { SkMatrix rotMatrix; - align_to_x_axis(pts, &rotMatrix, geometry.fPtsRot); - if(!rotMatrix.invert(&geometry.fSrcRotInv)) { + align_to_x_axis(pts, &rotMatrix, lineData.fPtsRot); + if (!rotMatrix.invert(&lineData.fSrcRotInv)) { SkDebugf("Failed to create invertible rotation matrix!\n"); return nullptr; } } else { - geometry.fSrcRotInv.reset(); - memcpy(geometry.fPtsRot, pts, 2 * sizeof(SkPoint)); + lineData.fSrcRotInv.reset(); + memcpy(lineData.fPtsRot, pts, 2 * sizeof(SkPoint)); } // Scale corrections of intervals and stroke from view matrix - calc_dash_scaling(&geometry.fParallelScale, &geometry.fPerpendicularScale, viewMatrix, - geometry.fPtsRot); + calc_dash_scaling(&lineData.fParallelScale, &lineData.fPerpendicularScale, viewMatrix, + lineData.fPtsRot); - SkScalar offInterval = intervals[1] * geometry.fParallelScale; - SkScalar strokeWidth = geometry.fSrcStrokeWidth * geometry.fPerpendicularScale; + SkScalar offInterval = intervals[1] * lineData.fParallelScale; + SkScalar strokeWidth = lineData.fSrcStrokeWidth * lineData.fPerpendicularScale; - if (SkPaint::kSquare_Cap == cap && 0 != geometry.fSrcStrokeWidth) { + if (SkPaint::kSquare_Cap == cap && 0 != lineData.fSrcStrokeWidth) { // add cap to on interveal and remove from off interval offInterval -= strokeWidth; } @@ -735,13 +729,12 @@ GrDrawBatch* GrDashingEffect::CreateDashLineBatch(GrColor color, // TODO we can do a real rect call if not using fulldash(ie no off interval, not using AA) bool fullDash = offInterval > 0.f || aaMode != AAMode::kNone; - geometry.fColor = color; - geometry.fViewMatrix = viewMatrix; - geometry.fPhase = phase; - geometry.fIntervals[0] = intervals[0]; - geometry.fIntervals[1] = intervals[1]; + lineData.fViewMatrix = viewMatrix; + lineData.fPhase = phase; + lineData.fIntervals[0] = intervals[0]; + lineData.fIntervals[1] = intervals[1]; - return DashBatch::Create(geometry, cap, aaMode, fullDash); + return DashOp::Make(lineData, color, cap, aaMode, fullDash); } ////////////////////////////////////////////////////////////////////////////// @@ -778,15 +771,13 @@ public: GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } - const SkMatrix& localMatrix() const { return fLocalMatrix; } bool usesLocalCoords() const { return fUsesLocalCoords; } - void getGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder* b) const override; + void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override; - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: DashingCircleEffect(GrColor, AAMode aaMode, const SkMatrix& localMatrix, @@ -814,7 +805,7 @@ public: void onEmitCode(EmitArgs&, GrGPArgs*) override; static inline void GenKey(const GrGeometryProcessor&, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder*); void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&, @@ -857,9 +848,7 @@ void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color - if (!dce.colorIgnored()) { - this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); - } + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); // Setup position this->setupPosition(vertBuilder, gpArgs, dce.inPosition()->fName); @@ -905,13 +894,12 @@ void GLDashingCircleEffect::setData(const GrGLSLProgramDataManager& pdman, } void GLDashingCircleEffect::GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const DashingCircleEffect& dce = gp.cast(); uint32_t key = 0; key |= dce.usesLocalCoords() && dce.localMatrix().hasPerspective() ? 0x1 : 0x0; - key |= dce.colorIgnored() ? 0x2 : 0x0; - key |= static_cast(dce.aaMode()) << 8; + key |= static_cast(dce.aaMode()) << 1; b->add32(key); } @@ -925,12 +913,12 @@ sk_sp DashingCircleEffect::Make(GrColor color, new DashingCircleEffect(color, aaMode, localMatrix, usesLocalCoords)); } -void DashingCircleEffect::getGLSLProcessorKey(const GrGLSLCaps& caps, +void DashingCircleEffect::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLDashingCircleEffect::GenKey(*this, caps, b); } -GrGLSLPrimitiveProcessor* DashingCircleEffect::createGLSLInstance(const GrGLSLCaps&) const { +GrGLSLPrimitiveProcessor* DashingCircleEffect::createGLSLInstance(const GrShaderCaps&) const { return new GLDashingCircleEffect(); } @@ -950,12 +938,14 @@ DashingCircleEffect::DashingCircleEffect(GrColor color, GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingCircleEffect); +#if GR_TEST_UTILS sk_sp DashingCircleEffect::TestCreate(GrProcessorTestData* d) { - AAMode aaMode = static_cast(d->fRandom->nextULessThan(GrDashingEffect::kAAModeCnt)); + AAMode aaMode = static_cast(d->fRandom->nextULessThan(GrDashOp::kAAModeCnt)); return DashingCircleEffect::Make(GrRandomColor(d->fRandom), aaMode, GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); } +#endif ////////////////////////////////////////////////////////////////////////////// @@ -991,15 +981,13 @@ public: GrColor color() const { return fColor; } - bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } - - const SkMatrix& localMatrix() const { return fLocalMatrix; } + const SkMatrix& localMatrix() const { return fLocalMatrix; } bool usesLocalCoords() const { return fUsesLocalCoords; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: DashingLineEffect(GrColor, AAMode aaMode, const SkMatrix& localMatrix, @@ -1027,7 +1015,7 @@ public: void onEmitCode(EmitArgs&, GrGPArgs*) override; static inline void GenKey(const GrGeometryProcessor&, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder*); void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&, @@ -1039,9 +1027,7 @@ private: typedef GrGLSLGeometryProcessor INHERITED; }; -GLDashingLineEffect::GLDashingLineEffect() { - fColor = GrColor_ILLEGAL; -} +GLDashingLineEffect::GLDashingLineEffect() : fColor(GrColor_ILLEGAL) {} void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { const DashingLineEffect& de = args.fGP.cast(); @@ -1066,9 +1052,7 @@ void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color - if (!de.colorIgnored()) { - this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); - } + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); // Setup position this->setupPosition(vertBuilder, gpArgs, de.inPosition()->fName); @@ -1132,12 +1116,11 @@ void GLDashingLineEffect::setData(const GrGLSLProgramDataManager& pdman, } void GLDashingLineEffect::GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const DashingLineEffect& de = gp.cast(); uint32_t key = 0; key |= de.usesLocalCoords() && de.localMatrix().hasPerspective() ? 0x1 : 0x0; - key |= de.colorIgnored() ? 0x2 : 0x0; key |= static_cast(de.aaMode()) << 8; b->add32(key); } @@ -1152,12 +1135,12 @@ sk_sp DashingLineEffect::Make(GrColor color, new DashingLineEffect(color, aaMode, localMatrix, usesLocalCoords)); } -void DashingLineEffect::getGLSLProcessorKey(const GrGLSLCaps& caps, +void DashingLineEffect::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { GLDashingLineEffect::GenKey(*this, caps, b); } -GrGLSLPrimitiveProcessor* DashingLineEffect::createGLSLInstance(const GrGLSLCaps&) const { +GrGLSLPrimitiveProcessor* DashingLineEffect::createGLSLInstance(const GrShaderCaps&) const { return new GLDashingLineEffect(); } @@ -1177,12 +1160,14 @@ DashingLineEffect::DashingLineEffect(GrColor color, GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingLineEffect); +#if GR_TEST_UTILS sk_sp DashingLineEffect::TestCreate(GrProcessorTestData* d) { - AAMode aaMode = static_cast(d->fRandom->nextULessThan(GrDashingEffect::kAAModeCnt)); + AAMode aaMode = static_cast(d->fRandom->nextULessThan(GrDashOp::kAAModeCnt)); return DashingLineEffect::Make(GrRandomColor(d->fRandom), aaMode, GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); } +#endif ////////////////////////////////////////////////////////////////////////////// @@ -1208,12 +1193,12 @@ static sk_sp make_dash_gp(GrColor color, ///////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -DRAW_BATCH_TEST_DEFINE(DashBatch) { +DRAW_OP_TEST_DEFINE(DashOp) { GrColor color = GrRandomColor(random); SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random); - AAMode aaMode = static_cast(random->nextULessThan(GrDashingEffect::kAAModeCnt)); + AAMode aaMode = static_cast(random->nextULessThan(GrDashOp::kAAModeCnt)); // We can only dash either horizontal or vertical lines SkPoint pts[2]; @@ -1275,7 +1260,7 @@ DRAW_BATCH_TEST_DEFINE(DashBatch) { GrStyle style(p); - return GrDashingEffect::CreateDashLineBatch(color, viewMatrix, pts, aaMode, style); + return GrDashOp::MakeDashLineOp(color, viewMatrix, pts, aaMode, style); } #endif diff --git a/gfx/skia/skia/src/gpu/ops/GrDashOp.h b/gfx/skia/skia/src/gpu/ops/GrDashOp.h new file mode 100644 index 000000000000..d3e0b6f9b239 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrDashOp.h @@ -0,0 +1,32 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDashOp_DEFINED +#define GrDashOp_DEFINED + +#include "GrColor.h" +#include "GrTypesPriv.h" +#include "SkPathEffect.h" + +class GrLegacyMeshDrawOp; +class GrStyle; + +namespace GrDashOp { +enum class AAMode { + kNone, + kCoverage, + kCoverageWithMSAA, +}; +static const int kAAModeCnt = static_cast(AAMode::kCoverageWithMSAA) + 1; + +std::unique_ptr MakeDashLineOp(GrColor, const SkMatrix& viewMatrix, + const SkPoint pts[2], AAMode, + const GrStyle& style); +bool CanDrawDashLine(const SkPoint pts[2], const GrStyle& style, const SkMatrix& viewMatrix); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrDefaultPathRenderer.cpp b/gfx/skia/skia/src/gpu/ops/GrDefaultPathRenderer.cpp similarity index 77% rename from gfx/skia/skia/src/gpu/batches/GrDefaultPathRenderer.cpp rename to gfx/skia/skia/src/gpu/ops/GrDefaultPathRenderer.cpp index 7dbdd4b48fdd..762084cba894 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDefaultPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrDefaultPathRenderer.cpp @@ -7,12 +7,12 @@ #include "GrDefaultPathRenderer.h" -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" #include "GrContext.h" #include "GrDefaultGeoProcFactory.h" +#include "GrDrawOpTest.h" #include "GrFixedClip.h" #include "GrMesh.h" +#include "GrOpFlushState.h" #include "GrPathUtils.h" #include "GrPipelineBuilder.h" #include "SkGeometry.h" @@ -21,8 +21,8 @@ #include "SkTLazy.h" #include "SkTraceEvent.h" -#include "batches/GrRectBatchFactory.h" -#include "batches/GrVertexBatch.h" +#include "ops/GrMeshDrawOp.h" +#include "ops/GrRectOpFactory.h" GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport, bool stencilWrapOpsSupport) @@ -94,46 +94,55 @@ static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint p } } -class DefaultPathBatch : public GrVertexBatch { +class DefaultPathOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - DefaultPathBatch(GrColor color, const SkPath& path, SkScalar tolerance, - uint8_t coverage, const SkMatrix& viewMatrix, bool isHairline, - const SkRect& devBounds) - : INHERITED(ClassID()) { - fBatch.fCoverage = coverage; - fBatch.fIsHairline = isHairline; - fBatch.fViewMatrix = viewMatrix; - fGeoData.emplace_back(Geometry{color, path, tolerance}); + static std::unique_ptr Make(GrColor color, const SkPath& path, + SkScalar tolerance, uint8_t coverage, + const SkMatrix& viewMatrix, bool isHairline, + const SkRect& devBounds) { + return std::unique_ptr(new DefaultPathOp( + color, path, tolerance, coverage, viewMatrix, isHairline, devBounds)); + } + + const char* name() const override { return "DefaultPathOp"; } + + SkString dumpInfo() const override { + SkString string; + string.appendf("Color: 0x%08x Count: %d\n", fColor, fPaths.count()); + for (const auto& path : fPaths) { + string.appendf("Tolerance: %.2f\n", path.fTolerance); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + DefaultPathOp(GrColor color, const SkPath& path, SkScalar tolerance, uint8_t coverage, + const SkMatrix& viewMatrix, bool isHairline, const SkRect& devBounds) + : INHERITED(ClassID()) + , fColor(color) + , fCoverage(coverage) + , fViewMatrix(viewMatrix) + , fIsHairline(isHairline) { + fPaths.emplace_back(PathData{path, tolerance}); this->setBounds(devBounds, HasAABloat::kNo, isHairline ? IsZeroArea::kYes : IsZeroArea::kNo); } - const char* name() const override { return "DefaultPathBatch"; } - - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setKnownSingleComponent(this->coverage()); + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fColor); + *coverage = this->coverage() == 0xff ? GrProcessorAnalysisCoverage::kNone + : GrProcessorAnalysisCoverage::kSingleChannel; } -private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any color overrides - if (!overrides.readsColor()) { - fGeoData[0].fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); - - // setup batch properties - fBatch.fColorIgnored = !overrides.readsColor(); - fBatch.fColor = fGeoData[0].fColor; - fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); - fBatch.fCoverageIgnored = !overrides.readsCoverage(); + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fColor); + fUsesLocalCoords = optimizations.readsLocalCoords(); } void onPrepareDraws(Target* target) const override { @@ -142,9 +151,6 @@ private: using namespace GrDefaultGeoProcFactory; Color color(this->color()); Coverage coverage(this->coverage()); - if (this->coverageIgnored()) { - coverage.fType = Coverage::kNone_Type; - } LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type); gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, this->viewMatrix()); @@ -153,7 +159,7 @@ private: size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(SkPoint)); - int instanceCount = fGeoData.count(); + int instanceCount = fPaths.count(); // compute number of vertices int maxVertices = 0; @@ -161,7 +167,7 @@ private: // We will use index buffers if we have multiple paths or one path with multiple contours bool isIndexed = instanceCount > 1; for (int i = 0; i < instanceCount; i++) { - const Geometry& args = fGeoData[i]; + const PathData& args = fPaths[i]; int contourCount; maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount, @@ -223,7 +229,7 @@ private: int vertexOffset = 0; int indexOffset = 0; for (int i = 0; i < instanceCount; i++) { - const Geometry& args = fGeoData[i]; + const PathData& args = fPaths[i]; int vertexCnt = 0; int indexCnt = 0; @@ -251,17 +257,17 @@ private: } else { mesh.init(primitiveType, vertexBuffer, firstVertex, vertexOffset); } - target->draw(gp.get(), mesh); + target->draw(gp.get(), this->pipeline(), mesh); // put back reserves target->putBackIndices((size_t)(maxIndices - indexOffset)); target->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - DefaultPathBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + DefaultPathOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), - that->bounds(), caps)) { + that->bounds(), caps)) { return false; } @@ -281,7 +287,7 @@ private: return false; } - fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); + fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin()); this->joinBounds(*that); return true; } @@ -295,8 +301,7 @@ private: const SkPath& path, SkScalar srcSpaceTol, bool isIndexed) const { - { - SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol); + SkScalar srcSpaceTolSqd = srcSpaceTol * srcSpaceTol; uint16_t indexOffsetU16 = (uint16_t)indexOffset; uint16_t vertexOffsetU16 = (uint16_t)vertexOffset; @@ -339,9 +344,7 @@ private: case SkPath::kConic_Verb: { SkScalar weight = iter.conicWeight(); SkAutoConicToQuads converter; - // Converting in src-space, hance the finer tolerance (0.25) - // TODO: find a way to do this in dev-space so the tolerance means something - const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f); + const SkPoint* quadPts = converter.computeQuads(pts, weight, srcSpaceTol); for (int i = 0; i < converter.countQuads(); ++i) { add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol, isIndexed, this->isHairline(), subpathIdxStart, @@ -378,47 +381,39 @@ private: *vertexCnt = static_cast(vert - base); *indexCnt = static_cast(idx - idxBase); - - } return true; } - GrColor color() const { return fBatch.fColor; } - uint8_t coverage() const { return fBatch.fCoverage; } - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } - const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } - bool isHairline() const { return fBatch.fIsHairline; } - bool coverageIgnored() const { return fBatch.fCoverageIgnored; } + GrColor color() const { return fColor; } + uint8_t coverage() const { return fCoverage; } + bool usesLocalCoords() const { return fUsesLocalCoords; } + const SkMatrix& viewMatrix() const { return fViewMatrix; } + bool isHairline() const { return fIsHairline; } - struct BatchTracker { - GrColor fColor; - uint8_t fCoverage; - SkMatrix fViewMatrix; - bool fUsesLocalCoords; - bool fColorIgnored; - bool fCoverageIgnored; - bool fIsHairline; - }; - - struct Geometry { - GrColor fColor; + struct PathData { SkPath fPath; SkScalar fTolerance; }; - BatchTracker fBatch; - SkSTArray<1, Geometry, true> fGeoData; + GrColor fColor; + uint8_t fCoverage; + SkMatrix fViewMatrix; + bool fUsesLocalCoords; + bool fIsHairline; + SkSTArray<1, PathData, true> fPaths; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -bool GrDefaultPathRenderer::internalDrawPath(GrDrawContext* drawContext, - const GrPaint& paint, +bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, + GrAAType aaType, const GrUserStencilSettings& userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, const GrShape& shape, bool stencilOnly) { + SkASSERT(GrAAType::kCoverage != aaType); SkPath path; shape.asPath(&path); @@ -528,7 +523,8 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawContext* drawContext, SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds()); SkRect devBounds; - GetPathDevBounds(path, drawContext->width(), drawContext->height(), viewMatrix, &devBounds); + GetPathDevBounds(path, renderTargetContext->width(), renderTargetContext->height(), viewMatrix, + &devBounds); for (int p = 0; p < passCount; ++p) { if (lastPassIsBounds && (p == passCount-1)) { @@ -551,47 +547,47 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawContext* drawContext, } const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix; - SkAutoTUnref batch( - GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewM, bounds, nullptr, - &localMatrix)); + std::unique_ptr op(GrRectOpFactory::MakeNonAAFill( + paint.getColor(), viewM, bounds, nullptr, &localMatrix)); SkASSERT(GrDrawFace::kBoth == drawFace[p]); - GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint)); + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); pipelineBuilder.setDrawFace(drawFace[p]); pipelineBuilder.setUserStencil(passes[p]); - - drawContext->drawBatch(pipelineBuilder, clip, batch); + renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, + std::move(op)); } else { - SkAutoTUnref batch(new DefaultPathBatch(paint.getColor(), path, - srcSpaceTol, - newCoverage, viewMatrix, - isHairline, devBounds)); - - GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint)); + std::unique_ptr op = + DefaultPathOp::Make(paint.getColor(), path, srcSpaceTol, newCoverage, + viewMatrix, isHairline, devBounds); + bool stencilPass = stencilOnly || passCount > 1; + GrPaint::MoveOrNew passPaint(paint, stencilPass); + if (stencilPass) { + passPaint.paint().setXPFactory(GrDisableColorXPFactory::Get()); + } + GrPipelineBuilder pipelineBuilder(std::move(passPaint), aaType); pipelineBuilder.setDrawFace(drawFace[p]); pipelineBuilder.setUserStencil(passes[p]); - if (passCount > 1) { - pipelineBuilder.setDisableColorXPFactory(); - } - - drawContext->drawBatch(pipelineBuilder, clip, batch); + renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, + std::move(op)); } } return true; } bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - // this class can draw any path with any simple fill style but doesn't do any anti-aliasing. - return !args.fAntiAlias && + // This can draw any path with any simple fill style but doesn't do coverage-based antialiasing. + return GrAAType::kCoverage != args.fAAType && (args.fShape->style().isSimpleFill() || IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr)); } bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrDefaultPathRenderer::onDrawPath"); - return this->internalDrawPath(args.fDrawContext, - *args.fPaint, + return this->internalDrawPath(args.fRenderTargetContext, + std::move(args.fPaint), + args.fAAType, *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, @@ -600,28 +596,28 @@ bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { } void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrDefaultPathRenderer::onStencilPath"); SkASSERT(!args.fShape->inverseFilled()); GrPaint paint; - paint.setXPFactory(GrDisableColorXPFactory::Make()); - paint.setAntiAlias(args.fIsAA); + paint.setXPFactory(GrDisableColorXPFactory::Get()); - this->internalDrawPath(args.fDrawContext, paint, GrUserStencilSettings::kUnused, *args.fClip, - *args.fViewMatrix, *args.fShape, true); + this->internalDrawPath(args.fRenderTargetContext, std::move(paint), args.fAAType, + GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix, + *args.fShape, true); } /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -DRAW_BATCH_TEST_DEFINE(DefaultPathBatch) { +DRAW_OP_TEST_DEFINE(DefaultPathOp) { GrColor color = GrRandomColor(random); SkMatrix viewMatrix = GrTest::TestMatrix(random); - // For now just hairlines because the other types of draws require two batches. - // TODO we should figure out a way to combine the stencil and cover steps into one batch + // For now just hairlines because the other types of draws require two ops. + // TODO we should figure out a way to combine the stencil and cover steps into one op. GrStyle style(SkStrokeRec::kHairline_InitStyle); SkPath path = GrTest::TestPath(random); @@ -632,7 +628,7 @@ DRAW_BATCH_TEST_DEFINE(DefaultPathBatch) { viewMatrix.mapRect(&bounds); uint8_t coverage = GrRandomCoverage(random); - return new DefaultPathBatch(color, path, srcSpaceTol, coverage, viewMatrix, true, bounds); + return DefaultPathOp::Make(color, path, srcSpaceTol, coverage, viewMatrix, true, bounds); } #endif diff --git a/gfx/skia/skia/src/gpu/batches/GrDefaultPathRenderer.h b/gfx/skia/skia/src/gpu/ops/GrDefaultPathRenderer.h similarity index 90% rename from gfx/skia/skia/src/gpu/batches/GrDefaultPathRenderer.h rename to gfx/skia/skia/src/gpu/ops/GrDefaultPathRenderer.h index 9ae23e48d99c..0a84eb935617 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDefaultPathRenderer.h +++ b/gfx/skia/skia/src/gpu/ops/GrDefaultPathRenderer.h @@ -30,8 +30,9 @@ private: void onStencilPath(const StencilPathArgs&) override; - bool internalDrawPath(GrDrawContext*, - const GrPaint&, + bool internalDrawPath(GrRenderTargetContext*, + GrPaint&&, + GrAAType, const GrUserStencilSettings&, const GrClip&, const SkMatrix& viewMatrix, diff --git a/gfx/skia/skia/src/gpu/ops/GrDiscardOp.h b/gfx/skia/skia/src/gpu/ops/GrDiscardOp.h new file mode 100644 index 000000000000..ca7f0007dea2 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrDiscardOp.h @@ -0,0 +1,72 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDiscardOp_DEFINED +#define GrDiscardOp_DEFINED + +#include "GrGpu.h" +#include "GrOp.h" +#include "GrOpFlushState.h" +#include "GrRenderTarget.h" + +class GrDiscardOp final : public GrOp { +public: + DEFINE_OP_CLASS_ID + + // MDB TODO: replace the renderTargetContext with just the renderTargetProxy. + // For now, we need the renderTargetContext for its accessRenderTarget powers. + static std::unique_ptr Make(GrRenderTargetContext* rtc) { + + // MDB TODO: remove this. In this hybrid state we need to be sure the RT is instantiable + // so it can carry the IO refs. In the future we will just get the proxy and + // it carry the IO refs. + if (!rtc->accessRenderTarget()) { + return nullptr; + } + + return std::unique_ptr(new GrDiscardOp(rtc)); + } + + const char* name() const override { return "Discard"; } + + SkString dumpInfo() const override { + SkString string; + string.printf("rtID: %d proxyID: %d ", fRenderTarget.get()->uniqueID().asUInt(), + fProxyUniqueID.asUInt()); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + GrDiscardOp(GrRenderTargetContext* rtc) + : INHERITED(ClassID()) + , fProxyUniqueID(rtc->asSurfaceProxy()->uniqueID()) { + this->setBounds(SkRect::MakeIWH(rtc->width(), rtc->height()), HasAABloat::kNo, + IsZeroArea::kNo); + + fRenderTarget.reset(rtc->accessRenderTarget()); + } + + bool onCombineIfPossible(GrOp* that, const GrCaps& caps) override { + return fRenderTarget.get() == that->cast()->fRenderTarget.get(); + } + + void onPrepare(GrOpFlushState*) override {} + + void onExecute(GrOpFlushState* state) override { + // MDB TODO: instantiate the renderTarget from the proxy in here + state->commandBuffer()->discard(fRenderTarget.get()); + } + + // MDB TODO: remove this. When the renderTargetProxy carries the refs this will be redundant. + GrSurfaceProxy::UniqueID fProxyUniqueID; + GrPendingIOResource fRenderTarget; + + typedef GrOp INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawAtlasBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrDrawAtlasOp.cpp similarity index 58% rename from gfx/skia/skia/src/gpu/batches/GrDrawAtlasBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrDrawAtlasOp.cpp index 6f1bfedfecd5..4b3d0d3e48c6 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDrawAtlasBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrDrawAtlasOp.cpp @@ -5,63 +5,51 @@ * found in the LICENSE file. */ -#include "GrDrawAtlasBatch.h" -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" +#include "GrDrawAtlasOp.h" +#include "GrDrawOpTest.h" +#include "GrOpFlushState.h" #include "SkGr.h" -#include "SkRandom.h" #include "SkRSXform.h" +#include "SkRandom.h" -void GrDrawAtlasBatch::initBatchTracker(const GrXPOverridesForBatch& overrides) { +void GrDrawAtlasOp::applyPipelineOptimizations(const PipelineOptimizations& optimizations) { SkASSERT(fGeoData.count() == 1); - // Handle any color overrides - if (!overrides.readsColor()) { - fGeoData[0].fColor = GrColor_ILLEGAL; - } - if (overrides.getOverrideColorIfSet(&fGeoData[0].fColor) && fHasColors) { - size_t vertexStride = sizeof(SkPoint) + sizeof(SkPoint) + - (this->hasColors() ? sizeof(GrColor) : 0); + if (optimizations.getOverrideColorIfSet(&fGeoData[0].fColor) && fHasColors) { + size_t vertexStride = + sizeof(SkPoint) + sizeof(SkPoint) + (this->hasColors() ? sizeof(GrColor) : 0); uint8_t* currVertex = fGeoData[0].fVerts.begin(); - for (int i = 0; i < 4*fQuadCount; ++i) { + for (int i = 0; i < 4 * fQuadCount; ++i) { *(reinterpret_cast(currVertex + sizeof(SkPoint))) = fGeoData[0].fColor; currVertex += vertexStride; } } - // setup batch properties - fColorIgnored = !overrides.readsColor(); fColor = fGeoData[0].fColor; // We'd like to assert this, but we can't because of GLPrograms test - //SkASSERT(init.readsLocalCoords()); - fCoverageIgnored = !overrides.readsCoverage(); + // SkASSERT(init.readsLocalCoords()); } -static sk_sp set_vertex_attributes(bool hasColors, - GrColor color, - const SkMatrix& viewMatrix, - bool coverageIgnored) { +static sk_sp make_gp(bool hasColors, + GrColor color, + const SkMatrix& viewMatrix) { using namespace GrDefaultGeoProcFactory; Color gpColor(color); if (hasColors) { - gpColor.fType = Color::kAttribute_Type; + gpColor.fType = Color::kPremulGrColorAttribute_Type; } - Coverage coverage(coverageIgnored ? Coverage::kNone_Type : Coverage::kSolid_Type); - LocalCoords localCoords(LocalCoords::kHasExplicit_Type); - return GrDefaultGeoProcFactory::Make(gpColor, coverage, localCoords, viewMatrix); + return GrDefaultGeoProcFactory::Make(gpColor, Coverage::kSolid_Type, + LocalCoords::kHasExplicit_Type, viewMatrix); } -void GrDrawAtlasBatch::onPrepareDraws(Target* target) const { +void GrDrawAtlasOp::onPrepareDraws(Target* target) const { // Setup geometry processor - sk_sp gp(set_vertex_attributes(this->hasColors(), - this->color(), - this->viewMatrix(), - this->coverageIgnored())); + sk_sp gp(make_gp(this->hasColors(), this->color(), this->viewMatrix())); int instanceCount = fGeoData.count(); size_t vertexStride = gp->getVertexStride(); - SkASSERT(vertexStride == sizeof(SkPoint) + sizeof(SkPoint) - + (this->hasColors() ? sizeof(GrColor) : 0)); + SkASSERT(vertexStride == + sizeof(SkPoint) + sizeof(SkPoint) + (this->hasColors() ? sizeof(GrColor) : 0)); QuadHelper helper; int numQuads = this->quadCount(); @@ -79,12 +67,11 @@ void GrDrawAtlasBatch::onPrepareDraws(Target* target) const { memcpy(vertPtr, args.fVerts.begin(), allocSize); vertPtr += allocSize; } - helper.recordDraw(target, gp.get()); + helper.recordDraw(target, gp.get(), this->pipeline()); } -GrDrawAtlasBatch::GrDrawAtlasBatch(GrColor color, const SkMatrix& viewMatrix, int spriteCount, - const SkRSXform* xforms, const SkRect* rects, - const SkColor* colors) +GrDrawAtlasOp::GrDrawAtlasOp(GrColor color, const SkMatrix& viewMatrix, int spriteCount, + const SkRSXform* xforms, const SkRect* rects, const SkColor* colors) : INHERITED(ClassID()) { SkASSERT(xforms); SkASSERT(rects); @@ -96,7 +83,7 @@ GrDrawAtlasBatch::GrDrawAtlasBatch(GrColor color, const SkMatrix& viewMatrix, in // Figure out stride and offsets // Order within the vertex is: position [color] texCoord size_t texOffset = sizeof(SkPoint); - size_t vertexStride = 2*sizeof(SkPoint); + size_t vertexStride = 2 * sizeof(SkPoint); fHasColors = SkToBool(colors); if (colors) { texOffset += sizeof(GrColor); @@ -105,7 +92,7 @@ GrDrawAtlasBatch::GrDrawAtlasBatch(GrColor color, const SkMatrix& viewMatrix, in // Compute buffer size and alloc buffer fQuadCount = spriteCount; - int allocSize = static_cast(4*vertexStride*spriteCount); + int allocSize = static_cast(4 * vertexStride * spriteCount); installedGeo.fVerts.reset(allocSize); uint8_t* currVertex = installedGeo.fVerts.begin(); @@ -127,34 +114,36 @@ GrDrawAtlasBatch::GrDrawAtlasBatch(GrColor color, const SkMatrix& viewMatrix, in } GrColor grColor = SkColorToPremulGrColor(color); - *(reinterpret_cast(currVertex+sizeof(SkPoint))) = grColor; - *(reinterpret_cast(currVertex+vertexStride+sizeof(SkPoint))) = grColor; - *(reinterpret_cast(currVertex+2*vertexStride+sizeof(SkPoint))) = grColor; - *(reinterpret_cast(currVertex+3*vertexStride+sizeof(SkPoint))) = grColor; + *(reinterpret_cast(currVertex + sizeof(SkPoint))) = grColor; + *(reinterpret_cast(currVertex + vertexStride + sizeof(SkPoint))) = grColor; + *(reinterpret_cast(currVertex + 2 * vertexStride + sizeof(SkPoint))) = + grColor; + *(reinterpret_cast(currVertex + 3 * vertexStride + sizeof(SkPoint))) = + grColor; } // Copy position and uv to verts *(reinterpret_cast(currVertex)) = quad[0]; - *(reinterpret_cast(currVertex+texOffset)) = SkPoint::Make(currRect.fLeft, - currRect.fTop); + *(reinterpret_cast(currVertex + texOffset)) = + SkPoint::Make(currRect.fLeft, currRect.fTop); bounds.growToInclude(quad[0].fX, quad[0].fY); currVertex += vertexStride; *(reinterpret_cast(currVertex)) = quad[1]; - *(reinterpret_cast(currVertex+texOffset)) = SkPoint::Make(currRect.fRight, - currRect.fTop); + *(reinterpret_cast(currVertex + texOffset)) = + SkPoint::Make(currRect.fRight, currRect.fTop); bounds.growToInclude(quad[1].fX, quad[1].fY); currVertex += vertexStride; *(reinterpret_cast(currVertex)) = quad[2]; - *(reinterpret_cast(currVertex+texOffset)) = SkPoint::Make(currRect.fRight, - currRect.fBottom); + *(reinterpret_cast(currVertex + texOffset)) = + SkPoint::Make(currRect.fRight, currRect.fBottom); bounds.growToInclude(quad[2].fX, quad[2].fY); currVertex += vertexStride; *(reinterpret_cast(currVertex)) = quad[3]; - *(reinterpret_cast(currVertex+texOffset)) = SkPoint::Make(currRect.fLeft, - currRect.fBottom); + *(reinterpret_cast(currVertex + texOffset)) = + SkPoint::Make(currRect.fLeft, currRect.fBottom); bounds.growToInclude(quad[3].fX, quad[3].fY); currVertex += vertexStride; } @@ -162,15 +151,15 @@ GrDrawAtlasBatch::GrDrawAtlasBatch(GrColor color, const SkMatrix& viewMatrix, in this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); } -bool GrDrawAtlasBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { - GrDrawAtlasBatch* that = t->cast(); +bool GrDrawAtlasOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { + GrDrawAtlasOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; } - // We currently use a uniform viewmatrix for this batch + // We currently use a uniform viewmatrix for this op. if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { return false; } @@ -183,9 +172,6 @@ bool GrDrawAtlasBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { return false; } - if (this->color() != that->color()) { - fColor = GrColor_ILLEGAL; - } fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); fQuadCount += that->quadCount(); @@ -193,7 +179,7 @@ bool GrDrawAtlasBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { return true; } -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS static SkRSXform random_xform(SkRandom* random) { static const SkScalar kMinExtent = -100.f; @@ -224,10 +210,9 @@ static SkRect random_texRect(SkRandom* random) { return texRect; } -static void randomize_params(uint32_t count, SkRandom* random, - SkTArray* xforms, - SkTArray* texRects, - SkTArray* colors, bool hasColors) { +static void randomize_params(uint32_t count, SkRandom* random, SkTArray* xforms, + SkTArray* texRects, SkTArray* colors, + bool hasColors) { for (uint32_t v = 0; v < count; v++) { xforms->push_back(random_xform(random)); texRects->push_back(random_texRect(random)); @@ -237,7 +222,7 @@ static void randomize_params(uint32_t count, SkRandom* random, } } -DRAW_BATCH_TEST_DEFINE(GrDrawAtlasBatch) { +DRAW_OP_TEST_DEFINE(GrDrawAtlasOp) { uint32_t spriteCount = random->nextRangeU(1, 100); SkTArray xforms(spriteCount); @@ -246,17 +231,13 @@ DRAW_BATCH_TEST_DEFINE(GrDrawAtlasBatch) { bool hasColors = random->nextBool(); - randomize_params(spriteCount, - random, - &xforms, - &texRects, - &colors, hasColors); + randomize_params(spriteCount, random, &xforms, &texRects, &colors, hasColors); SkMatrix viewMatrix = GrTest::TestMatrix(random); GrColor color = GrRandomColor(random); - return new GrDrawAtlasBatch(color, viewMatrix, spriteCount, xforms.begin(), texRects.begin(), - hasColors ? colors.begin() : nullptr); + return GrDrawAtlasOp::Make(color, viewMatrix, spriteCount, xforms.begin(), texRects.begin(), + hasColors ? colors.begin() : nullptr); } #endif diff --git a/gfx/skia/skia/src/gpu/ops/GrDrawAtlasOp.h b/gfx/skia/skia/src/gpu/ops/GrDrawAtlasOp.h new file mode 100644 index 000000000000..79a60988f062 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrDrawAtlasOp.h @@ -0,0 +1,78 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDrawAtlasOp_DEFINED +#define GrDrawAtlasOp_DEFINED + +#include "GrColor.h" +#include "GrDefaultGeoProcFactory.h" +#include "GrMeshDrawOp.h" + +class GrDrawAtlasOp final : public GrLegacyMeshDrawOp { +public: + DEFINE_OP_CLASS_ID + + static std::unique_ptr Make(GrColor color, const SkMatrix& viewMatrix, + int spriteCount, const SkRSXform* xforms, + const SkRect* rects, const SkColor* colors) { + return std::unique_ptr( + new GrDrawAtlasOp(color, viewMatrix, spriteCount, xforms, rects, colors)); + } + + const char* name() const override { return "DrawAtlasOp"; } + + SkString dumpInfo() const override { + SkString string; + for (const auto& geo : fGeoData) { + string.appendf("Color: 0x%08x, Quads: %d\n", geo.fColor, geo.fVerts.count() / 4); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + GrDrawAtlasOp(GrColor color, const SkMatrix& viewMatrix, int spriteCount, + const SkRSXform* xforms, const SkRect* rects, const SkColor* colors); + + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + if (this->hasColors()) { + color->setToUnknown(); + } else { + color->setToConstant(fGeoData[0].fColor); + } + *coverage = GrProcessorAnalysisCoverage::kNone; + } + + void onPrepareDraws(Target*) const override; + + void applyPipelineOptimizations(const PipelineOptimizations&) override; + + GrColor color() const { return fColor; } + const SkMatrix& viewMatrix() const { return fViewMatrix; } + bool hasColors() const { return fHasColors; } + int quadCount() const { return fQuadCount; } + + bool onCombineIfPossible(GrOp* t, const GrCaps&) override; + + struct Geometry { + GrColor fColor; + SkTArray fVerts; + }; + + SkSTArray<1, Geometry, true> fGeoData; + + SkMatrix fViewMatrix; + GrColor fColor; + int fQuadCount; + bool fHasColors; + + typedef GrLegacyMeshDrawOp INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrDrawOp.h b/gfx/skia/skia/src/gpu/ops/GrDrawOp.h new file mode 100644 index 000000000000..dbdd9d87a0c3 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrDrawOp.h @@ -0,0 +1,132 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDrawOp_DEFINED +#define GrDrawOp_DEFINED + +#include +#include "GrOp.h" +#include "GrPipeline.h" + +class GrAppliedClip; + +/** + * GrDrawOps are flushed in two phases (preDraw, and draw). In preDraw uploads to GrGpuResources + * and draws are determined and scheduled. They are issued in the draw phase. GrDrawOpUploadToken is + * used to sequence the uploads relative to each other and to draws. + **/ + +class GrDrawOpUploadToken { +public: + static GrDrawOpUploadToken AlreadyFlushedToken() { return GrDrawOpUploadToken(0); } + + GrDrawOpUploadToken(const GrDrawOpUploadToken& that) : fSequenceNumber(that.fSequenceNumber) {} + GrDrawOpUploadToken& operator =(const GrDrawOpUploadToken& that) { + fSequenceNumber = that.fSequenceNumber; + return *this; + } + bool operator==(const GrDrawOpUploadToken& that) const { + return fSequenceNumber == that.fSequenceNumber; + } + bool operator!=(const GrDrawOpUploadToken& that) const { return !(*this == that); } + +private: + GrDrawOpUploadToken(); + explicit GrDrawOpUploadToken(uint64_t sequenceNumber) : fSequenceNumber(sequenceNumber) {} + friend class GrOpFlushState; + uint64_t fSequenceNumber; +}; + +/** + * Base class for GrOps that draw. These ops have a GrPipeline installed by GrOpList. + */ +class GrDrawOp : public GrOp { +public: + /** Method that performs an upload on behalf of a DeferredUploadFn. */ + using WritePixelsFn = std::function; + /** See comments before GrDrawOp::Target definition on how deferred uploaders work. */ + using DeferredUploadFn = std::function; + + class Target; + + GrDrawOp(uint32_t classID) : INHERITED(classID) {} + + /** + * This information is required to determine how to compute a GrAppliedClip from a GrClip for + * this op. + */ + enum class FixedFunctionFlags : uint32_t { + kNone = 0x0, + /** Indices that the op will enable MSAA or mixed samples rendering. */ + kUsesHWAA = 0x1, + /** Indices that the op reads and/or writes the stencil buffer */ + kUsesStencil = 0x2, + }; + GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(FixedFunctionFlags); + virtual FixedFunctionFlags fixedFunctionFlags() const = 0; + + /** + * This is called after the GrAppliedClip has been computed and just prior to recording the op + * or combining it with a previously recorded op. It is used to determine whether a copy of the + * destination (or destination texture itself) needs to be provided to the xp when this op + * executes. This is guaranteed to be called before an op is recorded. However, this is also + * called on ops that are not recorded because they combine with a previously recorded op. + */ + virtual bool xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*) = 0; + +protected: + static SkString DumpPipelineInfo(const GrPipeline& pipeline) { + SkString string; + string.appendf("RT: %d\n", pipeline.getRenderTarget()->uniqueID().asUInt()); + string.append("ColorStages:\n"); + for (int i = 0; i < pipeline.numColorFragmentProcessors(); i++) { + string.appendf("\t\t%s\n\t\t%s\n", + pipeline.getColorFragmentProcessor(i).name(), + pipeline.getColorFragmentProcessor(i).dumpInfo().c_str()); + } + string.append("CoverageStages:\n"); + for (int i = 0; i < pipeline.numCoverageFragmentProcessors(); i++) { + string.appendf("\t\t%s\n\t\t%s\n", + pipeline.getCoverageFragmentProcessor(i).name(), + pipeline.getCoverageFragmentProcessor(i).dumpInfo().c_str()); + } + string.appendf("XP: %s\n", pipeline.getXferProcessor().name()); + + bool scissorEnabled = pipeline.getScissorState().enabled(); + string.appendf("Scissor: "); + if (scissorEnabled) { + string.appendf("[L: %d, T: %d, R: %d, B: %d]\n", + pipeline.getScissorState().rect().fLeft, + pipeline.getScissorState().rect().fTop, + pipeline.getScissorState().rect().fRight, + pipeline.getScissorState().rect().fBottom); + } else { + string.appendf("\n"); + } + return string; + } + + struct QueuedUpload { + QueuedUpload(DeferredUploadFn&& upload, GrDrawOpUploadToken token) + : fUpload(std::move(upload)) + , fUploadBeforeToken(token) {} + DeferredUploadFn fUpload; + GrDrawOpUploadToken fUploadBeforeToken; + }; + + SkTArray fInlineUploads; + +private: + typedef GrOp INHERITED; +}; + +GR_MAKE_BITFIELD_CLASS_OPS(GrDrawOp::FixedFunctionFlags); + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrDrawPathOp.cpp similarity index 63% rename from gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrDrawPathOp.cpp index 815fe746366d..3632787e0602 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrDrawPathOp.cpp @@ -5,38 +5,77 @@ * found in the LICENSE file. */ -#include "GrDrawPathBatch.h" - +#include "GrDrawPathOp.h" +#include "GrAppliedClip.h" +#include "GrRenderTargetContext.h" #include "GrRenderTargetPriv.h" +#include "SkTemplates.h" -static void pre_translate_transform_values(const float* xforms, - GrPathRendering::PathTransformType type, int count, - SkScalar x, SkScalar y, float* dst); - -void GrDrawPathBatchBase::onPrepare(GrBatchFlushState*) { - const GrRenderTargetPriv& rtPriv = this->pipeline()->getRenderTarget()->renderTargetPriv(); - fStencilPassSettings.reset(GrPathRendering::GetStencilPassSettings(fFillType), - this->pipeline()->hasStencilClip(), rtPriv.numStencilBits()); +GrDrawPathOpBase::GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint, + GrPathRendering::FillType fill, GrAAType aaType) + : INHERITED(classID) + , fViewMatrix(viewMatrix) + , fInputColor(paint.getColor()) + , fProcessorSet(std::move(paint)) + , fFillType(fill) + , fAAType(aaType) { + SkASSERT(fAAType != GrAAType::kCoverage); } -SkString GrDrawPathBatch::dumpInfo() const { +SkString GrDrawPathOp::dumpInfo() const { SkString string; string.printf("PATH: 0x%p", fPath.get()); string.append(INHERITED::dumpInfo()); return string; } -void GrDrawPathBatch::onDraw(GrBatchFlushState* state) { - GrProgramDesc desc; +void GrDrawPathOpBase::initPipeline(const GrOpFlushState& state, GrPipeline* pipeline) { + static constexpr GrUserStencilSettings kCoverPass{ + GrUserStencilSettings::StaticInit< + 0x0000, + GrUserStencilTest::kNotEqual, + 0xffff, + GrUserStencilOp::kZero, + GrUserStencilOp::kKeep, + 0xffff>() + }; + GrPipeline::InitArgs args; + args.fProcessors = &this->processors(); + args.fFlags = GrAATypeIsHW(fAAType) ? GrPipeline::kHWAntialias_Flag : 0; + args.fUserStencil = &kCoverPass; + args.fAppliedClip = state.drawOpArgs().fAppliedClip; + args.fRenderTarget = state.drawOpArgs().fRenderTarget; + args.fCaps = &state.caps(); + args.fDstTexture = state.drawOpArgs().fDstTexture; - SkAutoTUnref pathProc(GrPathProcessor::Create(this->color(), - this->overrides(), - this->viewMatrix())); - state->gpu()->pathRendering()->drawPath(*this->pipeline(), *pathProc, - this->stencilPassSettings(), fPath.get()); + return pipeline->init(args); } -SkString GrDrawPathRangeBatch::dumpInfo() const { +////////////////////////////////////////////////////////////////////////////// + +void init_stencil_pass_settings(const GrOpFlushState& flushState, + GrPathRendering::FillType fillType, GrStencilSettings* stencil) { + const GrAppliedClip* appliedClip = flushState.drawOpArgs().fAppliedClip; + bool stencilClip = appliedClip && appliedClip->hasStencilClip(); + stencil->reset(GrPathRendering::GetStencilPassSettings(fillType), stencilClip, + flushState.drawOpArgs().fRenderTarget->renderTargetPriv().numStencilBits()); +} + +////////////////////////////////////////////////////////////////////////////// + +void GrDrawPathOp::onExecute(GrOpFlushState* state) { + GrPipeline pipeline; + this->initPipeline(*state, &pipeline); + sk_sp pathProc(GrPathProcessor::Create(this->color(), this->viewMatrix())); + + GrStencilSettings stencil; + init_stencil_pass_settings(*state, this->fillType(), &stencil); + state->gpu()->pathRendering()->drawPath(pipeline, *pathProc, stencil, fPath.get()); +} + +////////////////////////////////////////////////////////////////////////////// + +SkString GrDrawPathRangeOp::dumpInfo() const { SkString string; string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get()); for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { @@ -48,28 +87,30 @@ SkString GrDrawPathRangeBatch::dumpInfo() const { return string; } -GrDrawPathRangeBatch::GrDrawPathRangeBatch(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, - SkScalar y, GrColor color, - GrPathRendering::FillType fill, GrPathRange* range, - const InstanceData* instanceData, const SkRect& bounds) - : INHERITED(ClassID(), viewMatrix, color, fill) - , fPathRange(range) - , fTotalPathCount(instanceData->count()) - , fScale(scale) { +GrDrawPathRangeOp::GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, + SkScalar y, GrPaint&& paint, GrPathRendering::FillType fill, + GrAAType aaType, GrPathRange* range, + const InstanceData* instanceData, const SkRect& bounds) + : INHERITED(ClassID(), viewMatrix, std::move(paint), fill, aaType) + , fPathRange(range) + , fTotalPathCount(instanceData->count()) + , fScale(scale) { fDraws.addToHead()->set(instanceData, x, y); this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); } -bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { - GrDrawPathRangeBatch* that = t->cast(); +static void pre_translate_transform_values(const float* xforms, + GrPathRendering::PathTransformType type, int count, + SkScalar x, SkScalar y, float* dst); + +bool GrDrawPathRangeOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { + GrDrawPathRangeOp* that = t->cast(); if (this->fPathRange.get() != that->fPathRange.get() || - this->transformType() != that->transformType() || - this->fScale != that->fScale || - this->color() != that->color() || - !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { + this->transformType() != that->transformType() || this->fScale != that->fScale || + this->color() != that->color() || !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { return false; } - if (!GrPipeline::AreEqual(*this->pipeline(), *that->pipeline())) { + if (this->processors() != that->processors()) { return false; } switch (fDraws.head()->fInstanceData->transformType()) { @@ -89,7 +130,8 @@ bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { return false; } break; - default: break; + default: + break; } // TODO: Check some other things here. (winding, opaque, pathProc color, vm, ...) // Try to combine this call with the previous DrawPaths. We do this by stenciling all the @@ -98,12 +140,14 @@ bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { // work). Note that it's also possible for overlapping paths to cancel each other's winding // numbers, and we only partially account for this by not allowing even/odd paths to be // combined. (Glyphs in the same font tend to wind the same direction so it works out OK.) + if (GrPathRendering::kWinding_FillType != this->fillType() || - GrPathRendering::kWinding_FillType != that->fillType() || - this->overrides().willColorBlendWithDst()) { + GrPathRendering::kWinding_FillType != that->fillType()) { + return false; + } + if (!this->processorAnalysis().canCombineOverlappedStencilAndCover()) { return false; } - SkASSERT(!that->overrides().willColorBlendWithDst()); fTotalPathCount += that->fTotalPathCount; while (Draw* head = that->fDraws.head()) { Draw* draw = fDraws.addToTail(); @@ -116,7 +160,7 @@ bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { return true; } -void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) { +void GrDrawPathRangeOp::onExecute(GrOpFlushState* state) { const Draw& head = *fDraws.head(); SkMatrix drawMatrix(this->viewMatrix()); @@ -127,16 +171,18 @@ void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) { localMatrix.setScale(fScale, fScale); localMatrix.preTranslate(head.fX, head.fY); - SkAutoTUnref pathProc(GrPathProcessor::Create(this->color(), - this->overrides(), - drawMatrix, - localMatrix)); + sk_sp pathProc( + GrPathProcessor::Create(this->color(), drawMatrix, localMatrix)); + GrPipeline pipeline; + this->initPipeline(*state, &pipeline); + GrStencilSettings stencil; + init_stencil_pass_settings(*state, this->fillType(), &stencil); if (fDraws.count() == 1) { const InstanceData& instances = *head.fInstanceData; - state->gpu()->pathRendering()->drawPaths(*this->pipeline(), + state->gpu()->pathRendering()->drawPaths(pipeline, *pathProc, - this->stencilPassSettings(), + stencil, fPathRange.get(), instances.indices(), GrPathRange::kU16_PathIndexType, @@ -153,8 +199,7 @@ void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) { const InstanceData& instances = *draw.fInstanceData; memcpy(&indexStorage[idx], instances.indices(), instances.count() * sizeof(uint16_t)); pre_translate_transform_values(instances.transformValues(), this->transformType(), - instances.count(), - draw.fX - head.fX, draw.fY - head.fY, + instances.count(), draw.fX - head.fX, draw.fY - head.fY, &transformStorage[floatsPerTransform * idx]); idx += instances.count(); @@ -163,9 +208,9 @@ void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) { } SkASSERT(idx == fTotalPathCount); - state->gpu()->pathRendering()->drawPaths(*this->pipeline(), + state->gpu()->pathRendering()->drawPaths(pipeline, *pathProc, - this->stencilPassSettings(), + stencil, fPathRange.get(), indexStorage, GrPathRange::kU16_PathIndexType, diff --git a/gfx/skia/skia/src/gpu/ops/GrDrawPathOp.h b/gfx/skia/skia/src/gpu/ops/GrDrawPathOp.h new file mode 100644 index 000000000000..8995de4bbd92 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrDrawPathOp.h @@ -0,0 +1,212 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDrawPathOp_DEFINED +#define GrDrawPathOp_DEFINED + +#include "GrDrawOp.h" +#include "GrGpu.h" +#include "GrOpFlushState.h" +#include "GrPath.h" +#include "GrPathProcessor.h" +#include "GrPathRendering.h" +#include "GrProcessorSet.h" +#include "GrStencilSettings.h" + +#include "SkTLList.h" + +class GrPaint; + +class GrDrawPathOpBase : public GrDrawOp { +protected: + GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&&, + GrPathRendering::FillType, GrAAType); + FixedFunctionFlags fixedFunctionFlags() const override { + if (GrAATypeIsHW(fAAType)) { + return FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil; + } + return FixedFunctionFlags::kUsesStencil; + } + bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override { + return this->doProcessorAnalysis(caps, clip).requiresDstTexture(); + } + +protected: + const SkMatrix& viewMatrix() const { return fViewMatrix; } + GrColor color() const { return fInputColor; } + GrPathRendering::FillType fillType() const { return fFillType; } + const GrProcessorSet& processors() const { return fProcessorSet; } + void initPipeline(const GrOpFlushState&, GrPipeline*); + const GrProcessorSet::Analysis& doProcessorAnalysis(const GrCaps& caps, + const GrAppliedClip* clip) { + bool isMixedSamples = GrAAType::kMixedSamples == fAAType; + fAnalysis = fProcessorSet.finalize(fInputColor, GrProcessorAnalysisCoverage::kNone, clip, + isMixedSamples, caps, &fInputColor); + return fAnalysis; + } + const GrProcessorSet::Analysis& processorAnalysis() const { + SkASSERT(fAnalysis.isInitialized()); + return fAnalysis; + } + +private: + void onPrepare(GrOpFlushState*) final {} + + SkMatrix fViewMatrix; + GrColor fInputColor; + GrProcessorSet fProcessorSet; + GrProcessorSet::Analysis fAnalysis; + GrPathRendering::FillType fFillType; + GrAAType fAAType; + + typedef GrDrawOp INHERITED; +}; + +class GrDrawPathOp final : public GrDrawPathOpBase { +public: + DEFINE_OP_CLASS_ID + + static std::unique_ptr Make(const SkMatrix& viewMatrix, GrPaint&& paint, + GrAAType aaType, GrPath* path) { + return std::unique_ptr( + new GrDrawPathOp(viewMatrix, std::move(paint), aaType, path)); + } + + const char* name() const override { return "DrawPath"; } + + SkString dumpInfo() const override; + +private: + GrDrawPathOp(const SkMatrix& viewMatrix, GrPaint&& paint, GrAAType aaType, const GrPath* path) + : GrDrawPathOpBase(ClassID(), viewMatrix, std::move(paint), path->getFillType(), aaType) + , fPath(path) { + this->setTransformedBounds(path->getBounds(), viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); + } + + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { return false; } + + void onExecute(GrOpFlushState* state) override; + + GrPendingIOResource fPath; + + typedef GrDrawPathOpBase INHERITED; +}; + +// Template this if we decide to support index types other than 16bit +class GrDrawPathRangeOp final : public GrDrawPathOpBase { +public: + typedef GrPathRendering::PathTransformType TransformType; + + DEFINE_OP_CLASS_ID + + struct InstanceData : private ::SkNoncopyable { + public: + static InstanceData* Alloc(TransformType transformType, int reserveCnt) { + int transformSize = GrPathRendering::PathTransformSize(transformType); + uint8_t* ptr = (uint8_t*)sk_malloc_throw(Align32(sizeof(InstanceData)) + + Align32(reserveCnt * sizeof(uint16_t)) + + reserveCnt * transformSize * sizeof(float)); + InstanceData* instanceData = (InstanceData*)ptr; + instanceData->fIndices = (uint16_t*)&ptr[Align32(sizeof(InstanceData))]; + instanceData->fTransformValues = (float*)&ptr[Align32(sizeof(InstanceData)) + + Align32(reserveCnt * sizeof(uint16_t))]; + instanceData->fTransformType = transformType; + instanceData->fInstanceCount = 0; + instanceData->fRefCnt = 1; + SkDEBUGCODE(instanceData->fReserveCnt = reserveCnt); + return instanceData; + } + + // Overload this method if we start using other transform types. + void append(uint16_t index, float x, float y) { + SkASSERT(GrPathRendering::kTranslate_PathTransformType == fTransformType); + SkASSERT(fInstanceCount < fReserveCnt); + fIndices[fInstanceCount] = index; + fTransformValues[2 * fInstanceCount] = x; + fTransformValues[2 * fInstanceCount + 1] = y; + ++fInstanceCount; + } + + TransformType transformType() const { return fTransformType; } + int count() const { return fInstanceCount; } + + const uint16_t* indices() const { return fIndices; } + uint16_t* indices() { return fIndices; } + + const float* transformValues() const { return fTransformValues; } + float* transformValues() { return fTransformValues; } + + void ref() const { ++fRefCnt; } + + void unref() const { + if (0 == --fRefCnt) { + sk_free(const_cast(this)); + } + } + + private: + static int Align32(int sizeInBytes) { return (sizeInBytes + 3) & ~3; } + + InstanceData() {} + ~InstanceData() {} + + uint16_t* fIndices; + float* fTransformValues; + TransformType fTransformType; + int fInstanceCount; + mutable int fRefCnt; + SkDEBUGCODE(int fReserveCnt;) + }; + + static std::unique_ptr Make(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, + SkScalar y, GrPaint&& paint, + GrPathRendering::FillType fill, GrAAType aaType, + GrPathRange* range, const InstanceData* instanceData, + const SkRect& bounds) { + return std::unique_ptr(new GrDrawPathRangeOp(viewMatrix, scale, x, y, + std::move(paint), fill, aaType, + range, instanceData, bounds)); + } + + const char* name() const override { return "DrawPathRange"; } + + SkString dumpInfo() const override; + +private: + GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, SkScalar y, + GrPaint&& paint, GrPathRendering::FillType fill, GrAAType aaType, + GrPathRange* range, const InstanceData* instanceData, const SkRect& bounds); + + TransformType transformType() const { return fDraws.head()->fInstanceData->transformType(); } + + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override; + + void onExecute(GrOpFlushState* state) override; + + struct Draw { + void set(const InstanceData* instanceData, SkScalar x, SkScalar y) { + fInstanceData.reset(SkRef(instanceData)); + fX = x; + fY = y; + } + + sk_sp fInstanceData; + SkScalar fX, fY; + }; + + typedef GrPendingIOResource PendingPathRange; + typedef SkTLList DrawList; + + PendingPathRange fPathRange; + DrawList fDraws; + int fTotalPathCount; + SkScalar fScale; + + typedef GrDrawPathOpBase INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrDrawVerticesOp.cpp b/gfx/skia/skia/src/gpu/ops/GrDrawVerticesOp.cpp new file mode 100644 index 000000000000..c67233c9edaf --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrDrawVerticesOp.cpp @@ -0,0 +1,401 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrDrawVerticesOp.h" +#include "GrDefaultGeoProcFactory.h" +#include "GrOpFlushState.h" +#include "SkGr.h" + +std::unique_ptr GrDrawVerticesOp::Make( + GrColor color, GrPrimitiveType primitiveType, const SkMatrix& viewMatrix, + const SkPoint* positions, int vertexCount, const uint16_t* indices, int indexCount, + const uint32_t* colors, const SkPoint* localCoords, const SkRect& bounds, + GrRenderTargetContext::ColorArrayType colorArrayType) { + static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode; + SkASSERT(positions); + if (!colors) { + // When we tessellate we will fill a color array with the GrColor value passed above as + // 'color'. + colorArrayType = GrRenderTargetContext::ColorArrayType::kPremulGrColor; + } + sk_sp vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions, + localCoords, colors, indexCount, indices); + if (!vertices) { + return nullptr; + } + return std::unique_ptr(new GrDrawVerticesOp( + std::move(vertices), primitiveType, color, colorArrayType, viewMatrix)); +} + +std::unique_ptr GrDrawVerticesOp::Make(GrColor color, + sk_sp vertices, + const SkMatrix& viewMatrix) { + SkASSERT(vertices); + GrPrimitiveType primType = SkVertexModeToGrPrimitiveType(vertices->mode()); + return std::unique_ptr( + new GrDrawVerticesOp(std::move(vertices), primType, color, + GrRenderTargetContext::ColorArrayType::kSkColor, viewMatrix)); +} + +GrDrawVerticesOp::GrDrawVerticesOp(sk_sp vertices, GrPrimitiveType primitiveType, + GrColor color, + GrRenderTargetContext::ColorArrayType colorArrayType, + const SkMatrix& viewMatrix, uint32_t flags) + : INHERITED(ClassID()), fColorArrayType(colorArrayType) { + SkASSERT(vertices); + + fVertexCount = vertices->vertexCount(); + fIndexCount = vertices->indexCount(); + fPrimitiveType = primitiveType; + + Mesh& mesh = fMeshes.push_back(); + mesh.fColor = color; + mesh.fViewMatrix = viewMatrix; + mesh.fVertices = std::move(vertices); + mesh.fFlags = flags; + + fFlags = 0; + if (mesh.hasPerVertexColors()) { + fFlags |= kRequiresPerVertexColors_Flag; + } + if (mesh.hasExplicitLocalCoords()) { + fFlags |= kAnyMeshHasExplicitLocalCoords; + } + + IsZeroArea zeroArea; + if (GrIsPrimTypeLines(primitiveType) || kPoints_GrPrimitiveType == primitiveType) { + zeroArea = IsZeroArea::kYes; + } else { + zeroArea = IsZeroArea::kNo; + } + this->setTransformedBounds(mesh.fVertices->bounds(), viewMatrix, HasAABloat::kNo, zeroArea); +} + +void GrDrawVerticesOp::getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const { + if (this->requiresPerVertexColors()) { + color->setToUnknown(); + } else { + color->setToConstant(fMeshes[0].fColor); + } + *coverage = GrProcessorAnalysisCoverage::kNone; +} + +void GrDrawVerticesOp::applyPipelineOptimizations(const PipelineOptimizations& optimizations) { + SkASSERT(fMeshes.count() == 1); + GrColor overrideColor; + if (optimizations.getOverrideColorIfSet(&overrideColor)) { + fMeshes[0].fColor = overrideColor; + fMeshes[0].fFlags |= kIgnoreColors_VerticesFlag; + fFlags &= ~kRequiresPerVertexColors_Flag; + fColorArrayType = GrRenderTargetContext::ColorArrayType::kPremulGrColor; + } + if (optimizations.readsLocalCoords()) { + fFlags |= kPipelineRequiresLocalCoords_Flag; + } else { + fFlags |= kIgnoreTexCoords_VerticesFlag; + fFlags &= ~kAnyMeshHasExplicitLocalCoords; + } +} + +sk_sp GrDrawVerticesOp::makeGP(bool* hasColorAttribute, + bool* hasLocalCoordAttribute) const { + using namespace GrDefaultGeoProcFactory; + LocalCoords::Type localCoordsType; + if (this->pipelineRequiresLocalCoords()) { + // If we have multiple view matrices we will transform the positions into device space. We + // must then also provide untransformed positions as local coords. + if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) { + *hasLocalCoordAttribute = true; + localCoordsType = LocalCoords::kHasExplicit_Type; + } else { + *hasLocalCoordAttribute = false; + localCoordsType = LocalCoords::kUsePosition_Type; + } + } else { + localCoordsType = LocalCoords::kUnused_Type; + *hasLocalCoordAttribute = false; + } + + Color color(fMeshes[0].fColor); + if (this->requiresPerVertexColors()) { + color.fType = (fColorArrayType == GrRenderTargetContext::ColorArrayType::kPremulGrColor) + ? Color::kPremulGrColorAttribute_Type + : Color::kUnpremulSkColorAttribute_Type; + *hasColorAttribute = true; + } else { + *hasColorAttribute = false; + }; + const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix; + return GrDefaultGeoProcFactory::Make(color, Coverage::kSolid_Type, localCoordsType, vm); +} + +void GrDrawVerticesOp::onPrepareDraws(Target* target) const { + bool hasColorAttribute; + bool hasLocalCoordsAttribute; + sk_sp gp = this->makeGP(&hasColorAttribute, &hasLocalCoordsAttribute); + size_t vertexStride = gp->getVertexStride(); + + SkASSERT(vertexStride == sizeof(SkPoint) + (hasColorAttribute ? sizeof(uint32_t) : 0) + + (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0)); + + int instanceCount = fMeshes.count(); + + const GrBuffer* vertexBuffer; + int firstVertex; + + void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex); + + if (!verts) { + SkDebugf("Could not allocate vertices\n"); + return; + } + + const GrBuffer* indexBuffer = nullptr; + int firstIndex = 0; + + uint16_t* indices = nullptr; + if (this->isIndexed()) { + indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex); + + if (!indices) { + SkDebugf("Could not allocate indices\n"); + return; + } + } + + int vertexOffset = 0; + // We have a fast case below for uploading the vertex data when the matrix is translate + // only and there are colors but not local coords. + bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute; + for (int i = 0; i < instanceCount; i++) { + const Mesh& mesh = fMeshes[i]; + if (indices) { + int indexCount = mesh.fVertices->indexCount(); + for (int j = 0; j < indexCount; ++j) { + *indices++ = mesh.fVertices->indices()[j] + vertexOffset; + } + } + int vertexCount = mesh.fVertices->vertexCount(); + const SkPoint* positions = mesh.fVertices->positions(); + const SkColor* colors = mesh.fVertices->colors(); + const SkPoint* localCoords = mesh.fVertices->texCoords(); + bool fastMesh = (!this->hasMultipleViewMatrices() || + mesh.fViewMatrix.getType() <= SkMatrix::kTranslate_Mask) && + mesh.hasPerVertexColors(); + if (fastAttrs && fastMesh) { + struct V { + SkPoint fPos; + uint32_t fColor; + }; + SkASSERT(sizeof(V) == vertexStride); + V* v = (V*)verts; + Sk2f t(0, 0); + if (this->hasMultipleViewMatrices()) { + t = Sk2f(mesh.fViewMatrix.getTranslateX(), mesh.fViewMatrix.getTranslateY()); + } + for (int j = 0; j < vertexCount; ++j) { + Sk2f p = Sk2f::Load(positions++) + t; + p.store(&v[j].fPos); + v[j].fColor = colors[j]; + } + verts = v + vertexCount; + } else { + static constexpr size_t kColorOffset = sizeof(SkPoint); + size_t localCoordOffset = + hasColorAttribute ? kColorOffset + sizeof(uint32_t) : kColorOffset; + + for (int j = 0; j < vertexCount; ++j) { + if (this->hasMultipleViewMatrices()) { + mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1); + } else { + *((SkPoint*)verts) = positions[j]; + } + if (hasColorAttribute) { + if (mesh.hasPerVertexColors()) { + *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j]; + } else { + *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColor; + } + } + if (hasLocalCoordsAttribute) { + if (mesh.hasExplicitLocalCoords()) { + *(SkPoint*)((intptr_t)verts + localCoordOffset) = localCoords[j]; + } else { + *(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j]; + } + } + verts = (void*)((intptr_t)verts + vertexStride); + } + } + vertexOffset += vertexCount; + } + + GrMesh mesh; + if (indices) { + mesh.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex, firstIndex, + fVertexCount, fIndexCount); + + } else { + mesh.init(this->primitiveType(), vertexBuffer, firstVertex, fVertexCount); + } + target->draw(gp.get(), this->pipeline(), mesh); +} + +bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { + GrDrawVerticesOp* that = t->cast(); + + if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), + that->bounds(), caps)) { + return false; + } + + if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) { + return false; + } + + if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) { + return false; + } + + if (fColorArrayType != that->fColorArrayType) { + return false; + } + + if (fVertexCount + that->fVertexCount > SK_MaxU16) { + return false; + } + + // If either op required explicit local coords or per-vertex colors the combined mesh does. Same + // with multiple view matrices. + fFlags |= that->fFlags; + + if (!this->requiresPerVertexColors() && this->fMeshes[0].fColor != that->fMeshes[0].fColor) { + fFlags |= kRequiresPerVertexColors_Flag; + } + // Check whether we are about to acquire a mesh with a different view matrix. + if (!this->hasMultipleViewMatrices() && + !this->fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) { + fFlags |= kHasMultipleViewMatrices_Flag; + } + + fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin()); + fVertexCount += that->fVertexCount; + fIndexCount += that->fIndexCount; + + this->joinBounds(*that); + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#if GR_TEST_UTILS + +#include "GrDrawOpTest.h" + +static uint32_t seed_vertices(GrPrimitiveType type) { + switch (type) { + case kTriangles_GrPrimitiveType: + case kTriangleStrip_GrPrimitiveType: + case kTriangleFan_GrPrimitiveType: + return 3; + case kPoints_GrPrimitiveType: + return 1; + case kLines_GrPrimitiveType: + case kLineStrip_GrPrimitiveType: + return 2; + } + SkFAIL("Incomplete switch\n"); + return 0; +} + +static uint32_t primitive_vertices(GrPrimitiveType type) { + switch (type) { + case kTriangles_GrPrimitiveType: + return 3; + case kLines_GrPrimitiveType: + return 2; + case kTriangleStrip_GrPrimitiveType: + case kTriangleFan_GrPrimitiveType: + case kPoints_GrPrimitiveType: + case kLineStrip_GrPrimitiveType: + return 1; + } + SkFAIL("Incomplete switch\n"); + return 0; +} + +static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) { + SkPoint p; + p.fX = random->nextRangeScalar(min, max); + p.fY = random->nextRangeScalar(min, max); + return p; +} + +static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max, + SkRandom* random, SkTArray* positions, + SkTArray* texCoords, bool hasTexCoords, + SkTArray* colors, bool hasColors, + SkTArray* indices, bool hasIndices) { + for (uint32_t v = 0; v < count; v++) { + positions->push_back(random_point(random, min, max)); + if (hasTexCoords) { + texCoords->push_back(random_point(random, min, max)); + } + if (hasColors) { + colors->push_back(GrRandomColor(random)); + } + if (hasIndices) { + SkASSERT(maxVertex <= SK_MaxU16); + indices->push_back(random->nextULessThan((uint16_t)maxVertex)); + } + } +} + +DRAW_OP_TEST_DEFINE(VerticesOp) { + GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1)); + uint32_t primitiveCount = random->nextRangeU(1, 100); + + // TODO make 'sensible' indexbuffers + SkTArray positions; + SkTArray texCoords; + SkTArray colors; + SkTArray indices; + + bool hasTexCoords = random->nextBool(); + bool hasIndices = random->nextBool(); + bool hasColors = random->nextBool(); + + uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type); + + static const SkScalar kMinVertExtent = -100.f; + static const SkScalar kMaxVertExtent = 100.f; + randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random, + &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices, + hasIndices); + + for (uint32_t i = 1; i < primitiveCount; i++) { + randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, + random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices, + hasIndices); + } + + GrRenderTargetContext::ColorArrayType colorArrayType = + random->nextBool() ? GrRenderTargetContext::ColorArrayType::kPremulGrColor + : GrRenderTargetContext::ColorArrayType::kSkColor; + SkMatrix viewMatrix = GrTest::TestMatrix(random); + SkRect bounds; + SkDEBUGCODE(bool result =) bounds.setBoundsCheck(positions.begin(), vertexCount); + SkASSERT(result); + + GrColor color = GrRandomColor(random); + return GrDrawVerticesOp::Make(color, type, viewMatrix, positions.begin(), vertexCount, + indices.begin(), hasIndices ? indices.count() : 0, colors.begin(), + texCoords.begin(), bounds, colorArrayType); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrDrawVerticesOp.h b/gfx/skia/skia/src/gpu/ops/GrDrawVerticesOp.h new file mode 100644 index 000000000000..4bd14afad3b5 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrDrawVerticesOp.h @@ -0,0 +1,144 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDrawVerticesOp_DEFINED +#define GrDrawVerticesOp_DEFINED + +#include "GrColor.h" +#include "GrMeshDrawOp.h" +#include "GrRenderTargetContext.h" +#include "GrTypes.h" +#include "SkMatrix.h" +#include "SkRect.h" +#include "SkTDArray.h" +#include "SkVertices.h" + +class GrOpFlushState; +class SkVertices; +struct GrInitInvariantOutput; + +class GrDrawVerticesOp final : public GrLegacyMeshDrawOp { +public: + DEFINE_OP_CLASS_ID + + enum { + kIgnoreTexCoords_VerticesFlag = 1 << 0, + kIgnoreColors_VerticesFlag = 1 << 1, + }; + + /** + * The 'color' param is used if the 'colors' array is null. 'bounds' is the bounds of the + * 'positions' array (in local space prior to application of 'viewMatrix'). If 'indices' is null + * then 'indexCnt' must be zero and vice versa. In this case the vertices are indexed as 0, 1, + * ..., 'vertexCount' - 1. 'localCoords' are optional and if null the vertex positions are used + * as local coords. 'colorArrayType' specifies whether the colors are premul GrColors or + * unpremul SkColors. + */ + static std::unique_ptr Make( + GrColor color, GrPrimitiveType primitiveType, const SkMatrix& viewMatrix, + const SkPoint* positions, int vertexCount, const uint16_t* indices, int indexCount, + const uint32_t* colors, const SkPoint* localCoords, const SkRect& bounds, + GrRenderTargetContext::ColorArrayType colorArrayType); + + /** + * Draw a SkVertices. The GrColor param is used if the vertices lack per-vertex color or 'flags' + * indicates that the per-vertex color should be ignored. The 'flags' options are those + * specified by SkCanvas::VerticesFlags. If the vertices lack local coords or 'flags' indicates + * that they should be ignored then the vertex positions are used as local coords. + */ + static std::unique_ptr Make(GrColor color, sk_sp, + const SkMatrix& viewMatrix); + + const char* name() const override { return "DrawVerticesOp"; } + + SkString dumpInfo() const override { + SkString string; + string.appendf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n", fPrimitiveType, + fMeshes.count(), fVertexCount, fIndexCount); + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + GrDrawVerticesOp(sk_sp, GrPrimitiveType, GrColor, + GrRenderTargetContext::ColorArrayType, const SkMatrix& viewMatrix, + uint32_t flags = 0); + + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override; + void applyPipelineOptimizations(const PipelineOptimizations&) override; + void onPrepareDraws(Target*) const override; + + sk_sp makeGP(bool* hasColorAttribute, bool* hasLocalCoordAttribute) const; + + GrPrimitiveType primitiveType() const { return fPrimitiveType; } + bool combinablePrimitive() const { + return kTriangles_GrPrimitiveType == fPrimitiveType || + kLines_GrPrimitiveType == fPrimitiveType || + kPoints_GrPrimitiveType == fPrimitiveType; + } + + bool onCombineIfPossible(GrOp* t, const GrCaps&) override; + + struct Mesh { + GrColor fColor; // Used if this->hasPerVertexColors() is false. + sk_sp fVertices; + SkMatrix fViewMatrix; + uint32_t fFlags; + + bool hasExplicitLocalCoords() const { + return fVertices->hasTexCoords() && !(kIgnoreTexCoords_VerticesFlag & fFlags); + } + + bool hasPerVertexColors() const { + return fVertices->hasColors() && !(kIgnoreColors_VerticesFlag & fFlags); + } + }; + + bool isIndexed() const { + // Consistency enforced in onCombineIfPossible. + return fMeshes[0].fVertices->hasIndices(); + } + + bool requiresPerVertexColors() const { + return SkToBool(kRequiresPerVertexColors_Flag & fFlags); + } + + bool anyMeshHasExplicitLocalCoords() const { + return SkToBool(kAnyMeshHasExplicitLocalCoords & fFlags); + } + + bool pipelineRequiresLocalCoords() const { + return SkToBool(kPipelineRequiresLocalCoords_Flag & fFlags); + } + + bool hasMultipleViewMatrices() const { + return SkToBool(kHasMultipleViewMatrices_Flag & fFlags); + } + + enum Flags { + kRequiresPerVertexColors_Flag = 0x1, + kAnyMeshHasExplicitLocalCoords = 0x2, + kPipelineRequiresLocalCoords_Flag = 0x4, + kHasMultipleViewMatrices_Flag = 0x8 + + }; + + // GrPrimitiveType is more expressive than fVertices.mode() so it is used instead and we ignore + // the SkVertices mode (though fPrimitiveType may have been inferred from it). + GrPrimitiveType fPrimitiveType; + uint32_t fFlags; + int fVertexCount; + int fIndexCount; + GrRenderTargetContext::ColorArrayType fColorArrayType; + SkSTArray<1, Mesh, true> fMeshes; + + typedef GrLegacyMeshDrawOp INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrNinePatch.cpp b/gfx/skia/skia/src/gpu/ops/GrLatticeOp.cpp similarity index 57% rename from gfx/skia/skia/src/gpu/batches/GrNinePatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrLatticeOp.cpp index 522e775c3339..4b8f5e3c73cc 100644 --- a/gfx/skia/skia/src/gpu/batches/GrNinePatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrLatticeOp.cpp @@ -5,34 +5,32 @@ * found in the LICENSE file. */ -#include "GrNinePatch.h" +#include "GrLatticeOp.h" -#include "GrBatchFlushState.h" #include "GrDefaultGeoProcFactory.h" +#include "GrMeshDrawOp.h" +#include "GrOpFlushState.h" #include "GrResourceProvider.h" -#include "GrVertexBatch.h" #include "SkBitmap.h" #include "SkLatticeIter.h" #include "SkRect.h" -static sk_sp create_gp(bool readsCoverage) { +static sk_sp create_gp() { using namespace GrDefaultGeoProcFactory; - Color color(Color::kAttribute_Type); - Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Type); - LocalCoords localCoords(LocalCoords::kHasExplicit_Type); - return GrDefaultGeoProcFactory::Make(color, coverage, localCoords, SkMatrix::I()); + return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type, + LocalCoords::kHasExplicit_Type, SkMatrix::I()); } -class GrNonAANinePatchBatch : public GrVertexBatch { +class NonAALatticeOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID static const int kVertsPerRect = 4; static const int kIndicesPerRect = 6; - GrNonAANinePatchBatch(GrColor color, const SkMatrix& viewMatrix, int imageWidth, - int imageHeight, std::unique_ptr iter, const SkRect &dst) - : INHERITED(ClassID()) { + NonAALatticeOp(GrColor color, const SkMatrix& viewMatrix, int imageWidth, int imageHeight, + std::unique_ptr iter, const SkRect& dst) + : INHERITED(ClassID()) { Patch& patch = fPatches.push_back(); patch.fViewMatrix = viewMatrix; patch.fColor = color; @@ -46,33 +44,35 @@ public: this->setTransformedBounds(patch.fDst, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); } - const char* name() const override { return "NonAANinePatchBatch"; } + const char* name() const override { return "NonAALatticeOp"; } SkString dumpInfo() const override { SkString str; for (int i = 0; i < fPatches.count(); ++i) { - str.appendf("%d: Color: 0x%08x Dst [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", - i, - fPatches[i].fColor, - fPatches[i].fDst.fLeft, fPatches[i].fDst.fTop, + str.appendf("%d: Color: 0x%08x Dst [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i, + fPatches[i].fColor, fPatches[i].fDst.fLeft, fPatches[i].fDst.fTop, fPatches[i].fDst.fRight, fPatches[i].fDst.fBottom); } + str.append(DumpPipelineInfo(*this->pipeline())); str.append(INHERITED::dumpInfo()); return str; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - color->setUnknownFourComponents(); - coverage->setKnownSingleComponent(0xff); +private: + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToUnknown(); + *coverage = GrProcessorAnalysisCoverage::kNone; + } + + void applyPipelineOptimizations(const PipelineOptimizations& analysioptimizations) override { + analysioptimizations.getOverrideColorIfSet(&fPatches[0].fColor); } -private: void onPrepareDraws(Target* target) const override { - sk_sp gp(create_gp(fOverrides.readsCoverage())); + sk_sp gp(create_gp()); if (!gp) { SkDebugf("Couldn't create GrGeometryProcessor\n"); return; @@ -85,12 +85,10 @@ private: numRects += fPatches[i].fIter->numRectsToDraw(); } - SkAutoTUnref indexBuffer( - target->resourceProvider()->refQuadIndexBuffer()); + sk_sp indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); InstancedHelper helper; void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, - indexBuffer, kVertsPerRect, - kIndicesPerRect, numRects); + indexBuffer.get(), kVertsPerRect, kIndicesPerRect, numRects); if (!vertices || !indexBuffer) { SkDebugf("Could not allocate vertices\n"); return; @@ -111,8 +109,8 @@ private: intptr_t patchVerts = verts; while (patch.fIter->next(&srcR, &dstR)) { SkPoint* positions = reinterpret_cast(verts); - positions->setRectFan(dstR.fLeft, dstR.fTop, - dstR.fRight, dstR.fBottom, vertexStride); + positions->setRectFan(dstR.fLeft, dstR.fTop, dstR.fRight, dstR.fBottom, + vertexStride); // Setup local coords static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); @@ -123,7 +121,7 @@ private: GrColor* vertColor = reinterpret_cast(verts + kColorOffset); for (int j = 0; j < 4; ++j) { *vertColor = patch.fColor; - vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); + vertColor = (GrColor*)((intptr_t)vertColor + vertexStride); } verts += kVertsPerRect * vertexStride; } @@ -131,20 +129,15 @@ private: // If we didn't handle it above, apply the matrix here. if (!isScaleTranslate) { SkPoint* positions = reinterpret_cast(patchVerts); - patch.fViewMatrix.mapPointsWithStride(positions, vertexStride, - kVertsPerRect * patch.fIter->numRectsToDraw()); + patch.fViewMatrix.mapPointsWithStride( + positions, vertexStride, kVertsPerRect * patch.fIter->numRectsToDraw()); } } - helper.recordDraw(target, gp.get()); + helper.recordDraw(target, gp.get(), this->pipeline()); } - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - overrides.getOverrideColorIfSet(&fPatches[0].fColor); - fOverrides = overrides; - } - - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - GrNonAANinePatchBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + NonAALatticeOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; @@ -153,12 +146,6 @@ private: SkASSERT(this->fImageWidth == that->fImageWidth && this->fImageHeight == that->fImageHeight); - // In the event of two batches, one who can tweak, one who cannot, we just fall back to - // not tweaking - if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) { - fOverrides = that->fOverrides; - } - fPatches.move_back_n(that->fPatches.count(), that->fPatches.begin()); this->joinBounds(*that); return true; @@ -171,18 +158,19 @@ private: GrColor fColor; }; - GrXPOverridesForBatch fOverrides; int fImageWidth; int fImageHeight; SkSTArray<1, Patch, true> fPatches; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -namespace GrNinePatch { -GrDrawBatch* CreateNonAA(GrColor color, const SkMatrix& viewMatrix, int imageWidth, int imageHeight, - std::unique_ptr iter, const SkRect& dst) { - return new GrNonAANinePatchBatch(color, viewMatrix, imageWidth, imageHeight, std::move(iter), - dst); +namespace GrLatticeOp { +std::unique_ptr MakeNonAA(GrColor color, const SkMatrix& viewMatrix, + int imageWidth, int imageHeight, + std::unique_ptr iter, + const SkRect& dst) { + return std::unique_ptr( + new NonAALatticeOp(color, viewMatrix, imageWidth, imageHeight, std::move(iter), dst)); } }; diff --git a/gfx/skia/skia/src/gpu/ops/GrLatticeOp.h b/gfx/skia/skia/src/gpu/ops/GrLatticeOp.h new file mode 100644 index 000000000000..65aa6228946d --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrLatticeOp.h @@ -0,0 +1,26 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GLatticeOp_DEFINED +#define GLatticeOp_DEFINED + +#include "GrColor.h" +#include "SkRefCnt.h" + +class GrLegacyMeshDrawOp; +class SkLatticeIter; +class SkMatrix; +struct SkRect; + +namespace GrLatticeOp { +std::unique_ptr MakeNonAA(GrColor color, const SkMatrix& viewMatrix, + int imageWidth, int imageHeight, + std::unique_ptr iter, + const SkRect& dst); +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrMSAAPathRenderer.cpp b/gfx/skia/skia/src/gpu/ops/GrMSAAPathRenderer.cpp similarity index 73% rename from gfx/skia/skia/src/gpu/batches/GrMSAAPathRenderer.cpp rename to gfx/skia/skia/src/gpu/ops/GrMSAAPathRenderer.cpp index d01323535754..8e320063e3df 100644 --- a/gfx/skia/skia/src/gpu/batches/GrMSAAPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrMSAAPathRenderer.cpp @@ -8,24 +8,25 @@ #include "GrMSAAPathRenderer.h" #include "GrAuditTrail.h" -#include "GrBatchFlushState.h" #include "GrClip.h" #include "GrDefaultGeoProcFactory.h" #include "GrFixedClip.h" +#include "GrMesh.h" +#include "GrOpFlushState.h" #include "GrPathStencilSettings.h" #include "GrPathUtils.h" #include "GrPipelineBuilder.h" -#include "GrMesh.h" +#include "SkAutoMalloc.h" #include "SkGeometry.h" #include "SkTraceEvent.h" -#include "glsl/GrGLSLGeometryProcessor.h" +#include "gl/GrGLVaryingHandler.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLVertexShaderBuilder.h" +#include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUtil.h" -#include "gl/GrGLVaryingHandler.h" -#include "batches/GrRectBatchFactory.h" -#include "batches/GrVertexBatch.h" +#include "glsl/GrGLSLVertexShaderBuilder.h" +#include "ops/GrMeshDrawOp.h" +#include "ops/GrRectOpFactory.h" static const float kTolerance = 0.5f; @@ -115,7 +116,7 @@ public: return new MSAAQuadProcessor(viewMatrix); } - virtual ~MSAAQuadProcessor() {} + ~MSAAQuadProcessor() override {} const char* name() const override { return "MSAAQuadProcessor"; } @@ -158,7 +159,7 @@ public: } static inline void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const MSAAQuadProcessor& qp = gp.cast(); uint32_t key = 0; @@ -184,12 +185,12 @@ public: UniformHandle fViewMatrixUniform; }; - virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, + virtual void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLProcessor::GenKey(*this, caps, b); } - virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { + virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { return new GLSLProcessor(*this); } @@ -214,48 +215,65 @@ private: typedef GrGeometryProcessor INHERITED; }; -class MSAAPathBatch : public GrVertexBatch { +class MSAAPathOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID - - MSAAPathBatch(GrColor color, const SkPath& path, const SkMatrix& viewMatrix, - const SkRect& devBounds) - : INHERITED(ClassID()) - , fViewMatrix(viewMatrix) { - fPaths.emplace_back(PathInfo{color, path}); - this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo); + DEFINE_OP_CLASS_ID + static std::unique_ptr Make(GrColor color, const SkPath& path, + const SkMatrix& viewMatrix, + const SkRect& devBounds) { int contourCount; - this->computeWorstCasePointCount(path, &contourCount, &fMaxLineVertices, &fMaxQuadVertices); - fMaxLineIndices = fMaxLineVertices * 3; - fMaxQuadIndices = fMaxQuadVertices * 3; - fIsIndexed = contourCount > 1; + int maxLineVertices; + int maxQuadVertices; + ComputeWorstCasePointCount(path, viewMatrix, &contourCount, &maxLineVertices, + &maxQuadVertices); + bool isIndexed = contourCount > 1; + if (isIndexed && + (maxLineVertices > kMaxIndexedVertexCnt || maxQuadVertices > kMaxIndexedVertexCnt)) { + return nullptr; + } + + return std::unique_ptr(new MSAAPathOp( + color, path, viewMatrix, devBounds, maxLineVertices, maxQuadVertices, isIndexed)); } - const char* name() const override { return "MSAAPathBatch"; } + const char* name() const override { return "MSAAPathOp"; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one path - color->setKnownFourComponents(fPaths[0].fColor); - coverage->setKnownSingleComponent(0xff); - } - - bool isValid() const { - return !fIsIndexed || fMaxLineIndices <= SK_MaxU16; + SkString dumpInfo() const override { + SkString string; + string.appendf("Indexed: %d\n", fIsIndexed); + for (const auto& path : fPaths) { + string.appendf("Color: 0x%08x\n", path.fColor); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; } private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any color overrides - if (!overrides.readsColor()) { - fPaths[0].fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fPaths[0].fColor); + MSAAPathOp(GrColor color, const SkPath& path, const SkMatrix& viewMatrix, + const SkRect& devBounds, int maxLineVertices, int maxQuadVertices, bool isIndexed) + : INHERITED(ClassID()) + , fViewMatrix(viewMatrix) + , fMaxLineVertices(maxLineVertices) + , fMaxQuadVertices(maxQuadVertices) + , fIsIndexed(isIndexed) { + fPaths.emplace_back(PathInfo{color, path}); + this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo); } - void computeWorstCasePointCount(const SkPath& path, int* subpaths, int* outLinePointCount, - int* outQuadPointCount) const { + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fPaths[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kNone; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fPaths[0].fColor); + } + + static void ComputeWorstCasePointCount(const SkPath& path, const SkMatrix& m, int* subpaths, + int* outLinePointCount, int* outQuadPointCount) { + SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m, path.getBounds()); int linePointCount = 0; int quadPointCount = 0; *subpaths = 1; @@ -274,7 +292,7 @@ private: case SkPath::kConic_Verb: { SkScalar weight = iter.conicWeight(); SkAutoConicToQuads converter; - converter.computeQuads(pts, weight, kTolerance); + converter.computeQuads(pts, weight, tolerance); int quadPts = converter.countQuads(); linePointCount += quadPts; quadPointCount += 3 * quadPts; @@ -285,7 +303,7 @@ private: break; case SkPath::kCubic_Verb: { SkSTArray<15, SkPoint, true> quadPts; - GrPathUtils::convertCubicToQuads(pts, kTolerance, &quadPts); + GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts); int count = quadPts.count(); linePointCount += count / 3; quadPointCount += count; @@ -307,7 +325,6 @@ private: } void onPrepareDraws(Target* target) const override { - SkASSERT(this->isValid()); if (fMaxLineVertices == 0) { SkASSERT(fMaxQuadVertices == 0); return; @@ -334,7 +351,7 @@ private: MSAAQuadVertices quads; size_t quadVertexStride = sizeof(MSAAQuadVertices::Vertex); - SkAutoFree quadVertexPtr(sk_malloc_throw(fMaxQuadVertices * quadVertexStride)); + SkAutoMalloc quadVertexPtr(fMaxQuadVertices * quadVertexStride); quads.vertices = (MSAAQuadVertices::Vertex*) quadVertexPtr.get(); quads.nextVertex = quads.vertices; SkDEBUGCODE(quads.verticesEnd = quads.vertices + fMaxQuadVertices;) @@ -342,8 +359,8 @@ private: const GrBuffer* lineIndexBuffer = nullptr; int firstLineIndex; if (fIsIndexed) { - lines.indices = target->makeIndexSpace(fMaxLineIndices, &lineIndexBuffer, - &firstLineIndex); + lines.indices = + target->makeIndexSpace(3 * fMaxLineVertices, &lineIndexBuffer, &firstLineIndex); if (!lines.indices) { SkDebugf("Could not allocate indices\n"); return; @@ -356,8 +373,8 @@ private: SkAutoFree quadIndexPtr; if (fIsIndexed) { - quads.indices = (uint16_t*) sk_malloc_throw(fMaxQuadIndices * sizeof(uint16_t)); - quadIndexPtr.set(quads.indices); + quads.indices = (uint16_t*)sk_malloc_throw(3 * fMaxQuadVertices * sizeof(uint16_t)); + quadIndexPtr.reset(quads.indices); quads.nextIndex = quads.indices; } else { quads.indices = nullptr; @@ -379,17 +396,17 @@ private: } int lineVertexOffset = (int) (lines.nextVertex - lines.vertices); int lineIndexOffset = (int) (lines.nextIndex - lines.indices); - SkASSERT(lineVertexOffset <= fMaxLineVertices && lineIndexOffset <= fMaxLineIndices); + SkASSERT(lineVertexOffset <= fMaxLineVertices && lineIndexOffset <= 3 * fMaxLineVertices); int quadVertexOffset = (int) (quads.nextVertex - quads.vertices); int quadIndexOffset = (int) (quads.nextIndex - quads.indices); - SkASSERT(quadVertexOffset <= fMaxQuadVertices && quadIndexOffset <= fMaxQuadIndices); + SkASSERT(quadVertexOffset <= fMaxQuadVertices && quadIndexOffset <= 3 * fMaxQuadVertices); if (lineVertexOffset) { sk_sp lineGP; { using namespace GrDefaultGeoProcFactory; - lineGP = GrDefaultGeoProcFactory::Make(Color(Color::kAttribute_Type), - Coverage(255), + lineGP = GrDefaultGeoProcFactory::Make(Color(Color::kPremulGrColorAttribute_Type), + Coverage::kSolid_Type, LocalCoords(LocalCoords::kUnused_Type), fViewMatrix); } @@ -404,11 +421,11 @@ private: lineMeshes.init(primitiveType, lineVertexBuffer, firstLineVertex, lineVertexOffset); } - target->draw(lineGP.get(), lineMeshes); + target->draw(lineGP.get(), this->pipeline(), lineMeshes); } if (quadVertexOffset) { - SkAutoTUnref quadGP(MSAAQuadProcessor::Create(fViewMatrix)); + sk_sp quadGP(MSAAQuadProcessor::Create(fViewMatrix)); SkASSERT(quadVertexStride == quadGP->getVertexStride()); const GrBuffer* quadVertexBuffer; @@ -432,14 +449,18 @@ private: quadMeshes.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex, quadVertexOffset); } - target->draw(quadGP, quadMeshes); + target->draw(quadGP.get(), this->pipeline(), quadMeshes); } } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - MSAAPathBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + MSAAPathOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), - that->bounds(), caps)) { + that->bounds(), caps)) { + return false; + } + + if (this->bounds().intersects(that->bounds())) { return false; } @@ -447,8 +468,9 @@ private: return false; } - if ((fMaxLineIndices + that->fMaxLineIndices > SK_MaxU16) || - (fMaxQuadIndices + that->fMaxQuadIndices > SK_MaxU16)) { + // If we grow to include 2+ paths we will be indexed. + if (((fMaxLineVertices + that->fMaxLineVertices) > kMaxIndexedVertexCnt) || + ((fMaxQuadVertices + that->fMaxQuadVertices) > kMaxIndexedVertexCnt)) { return false; } @@ -457,8 +479,6 @@ private: fIsIndexed = true; fMaxLineVertices += that->fMaxLineVertices; fMaxQuadVertices += that->fMaxQuadVertices; - fMaxLineIndices += that->fMaxLineIndices; - fMaxQuadIndices += that->fMaxQuadIndices; return true; } @@ -469,6 +489,8 @@ private: SkColor color, bool isIndexed) const { { + const SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m, + path.getBounds()); uint16_t subpathIdxStart = (uint16_t) (lines.nextVertex - lines.vertices); SkPoint pts[4]; @@ -501,7 +523,7 @@ private: case SkPath::kConic_Verb: { SkScalar weight = iter.conicWeight(); SkAutoConicToQuads converter; - const SkPoint* quadPts = converter.computeQuads(pts, weight, kTolerance); + const SkPoint* quadPts = converter.computeQuads(pts, weight, tolerance); for (int i = 0; i < converter.countQuads(); ++i) { add_quad(lines, quads, quadPts + i * 2, color, isIndexed, subpathIdxStart); @@ -514,7 +536,7 @@ private: } case SkPath::kCubic_Verb: { SkSTArray<15, SkPoint, true> quadPts; - GrPathUtils::convertCubicToQuads(pts, kTolerance, &quadPts); + GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts); int count = quadPts.count(); for (int i = 0; i < count; i += 3) { add_quad(lines, quads, &quadPts[i], color, isIndexed, subpathIdxStart); @@ -532,6 +554,9 @@ private: return true; } + // Lines and quads may render with an index buffer. However, we don't have any support for + // overflowing the max index. + static constexpr int kMaxIndexedVertexCnt = SK_MaxU16 / 3; struct PathInfo { GrColor fColor; SkPath fPath; @@ -542,15 +567,14 @@ private: SkMatrix fViewMatrix; int fMaxLineVertices; int fMaxQuadVertices; - int fMaxLineIndices; - int fMaxQuadIndices; bool fIsIndexed; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -bool GrMSAAPathRenderer::internalDrawPath(GrDrawContext* drawContext, - const GrPaint& paint, +bool GrMSAAPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, + GrAAType aaType, const GrUserStencilSettings& userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, @@ -560,21 +584,15 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawContext* drawContext, SkPath path; shape.asPath(&path); - static const int kMaxNumPasses = 2; - - int passCount = 0; - const GrUserStencilSettings* passes[kMaxNumPasses]; + const GrUserStencilSettings* passes[2] = {nullptr, nullptr}; bool reverse = false; - bool lastPassIsBounds; if (single_pass_shape(shape)) { - passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = &userStencilSettings; } - lastPassIsBounds = false; } else { switch (path.getFillType()) { case SkPath::kInverseEvenOdd_FillType: @@ -582,17 +600,8 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawContext* drawContext, // fallthrough case SkPath::kEvenOdd_FillType: passes[0] = &gEOStencilPass; - if (stencilOnly) { - passCount = 1; - lastPassIsBounds = false; - } else { - passCount = 2; - lastPassIsBounds = true; - if (reverse) { - passes[1] = &gInvEOColorPass; - } else { - passes[1] = &gEOColorPass; - } + if (!stencilOnly) { + passes[1] = reverse ? &gInvEOColorPass : &gEOColorPass; } break; @@ -601,17 +610,8 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawContext* drawContext, // fallthrough case SkPath::kWinding_FillType: passes[0] = &gWindStencilSeparateWithWrap; - passCount = 2; - if (stencilOnly) { - lastPassIsBounds = false; - passCount = 1; - } else { - lastPassIsBounds = true; - if (reverse) { - passes[1] = &gInvWindColorPass; - } else { - passes[1] = &gWindColorPass; - } + if (!stencilOnly) { + passes[1] = reverse ? &gInvWindColorPass : &gWindColorPass; } break; default: @@ -621,54 +621,55 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawContext* drawContext, } SkRect devBounds; - GetPathDevBounds(path, drawContext->width(), drawContext->height(), viewMatrix, &devBounds); + GetPathDevBounds(path, renderTargetContext->width(), renderTargetContext->height(), viewMatrix, + &devBounds); - SkASSERT(passCount <= kMaxNumPasses); - - for (int p = 0; p < passCount; ++p) { - if (lastPassIsBounds && (p == passCount-1)) { - SkRect bounds; - SkMatrix localMatrix = SkMatrix::I(); - if (reverse) { - // draw over the dev bounds (which will be the whole dst surface for inv fill). - bounds = devBounds; - SkMatrix vmi; - // mapRect through persp matrix may not be correct - if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { - vmi.mapRect(&bounds); - } else { - if (!viewMatrix.invert(&localMatrix)) { - return false; - } - } - } else { - bounds = path.getBounds(); - } - const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : - viewMatrix; - SkAutoTUnref batch( - GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewM, bounds, nullptr, - &localMatrix)); - - GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint)); - pipelineBuilder.setUserStencil(passes[p]); - - drawContext->drawBatch(pipelineBuilder, clip, batch); - } else { - SkAutoTUnref batch(new MSAAPathBatch(paint.getColor(), path, - viewMatrix, devBounds)); - if (!batch->isValid()) { - return false; - } - - GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint)); - pipelineBuilder.setUserStencil(passes[p]); - if (passCount > 1) { - pipelineBuilder.setDisableColorXPFactory(); - } - - drawContext->drawBatch(pipelineBuilder, clip, batch); + SkASSERT(passes[0]); + { // First pass + std::unique_ptr op = + MSAAPathOp::Make(paint.getColor(), path, viewMatrix, devBounds); + if (!op) { + return false; } + bool firstPassIsStencil = stencilOnly || passes[1]; + // If we have a cover pass then we ignore the paint in the first pass and apply it in the + // second. + GrPaint::MoveOrNew firstPassPaint(paint, firstPassIsStencil); + if (firstPassIsStencil) { + firstPassPaint.paint().setXPFactory(GrDisableColorXPFactory::Get()); + } + GrPipelineBuilder pipelineBuilder(std::move(firstPassPaint), aaType); + pipelineBuilder.setUserStencil(passes[0]); + renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); + } + + if (passes[1]) { + SkRect bounds; + SkMatrix localMatrix = SkMatrix::I(); + if (reverse) { + // draw over the dev bounds (which will be the whole dst surface for inv fill). + bounds = devBounds; + SkMatrix vmi; + // mapRect through persp matrix may not be correct + if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { + vmi.mapRect(&bounds); + } else { + if (!viewMatrix.invert(&localMatrix)) { + return false; + } + } + } else { + bounds = path.getBounds(); + } + const SkMatrix& viewM = + (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix; + std::unique_ptr op(GrRectOpFactory::MakeNonAAFill( + paint.getColor(), viewM, bounds, nullptr, &localMatrix)); + + GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); + pipelineBuilder.setUserStencil(passes[1]); + + renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); } return true; } @@ -677,11 +678,11 @@ bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { // This path renderer only fills and relies on MSAA for antialiasing. Stroked shapes are // handled by passing on the original shape and letting the caller compute the stroked shape // which will have a fill style. - return args.fShape->style().isSimpleFill() && !args.fAntiAlias; + return args.fShape->style().isSimpleFill() && (GrAAType::kCoverage != args.fAAType); } bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrMSAAPathRenderer::onDrawPath"); SkTLazy tmpShape; const GrShape* shape = args.fShape; @@ -690,8 +691,9 @@ bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) { tmpShape.init(args.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale)); shape = tmpShape.get(); } - return this->internalDrawPath(args.fDrawContext, - *args.fPaint, + return this->internalDrawPath(args.fRenderTargetContext, + std::move(args.fPaint), + args.fAAType, *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, @@ -700,17 +702,17 @@ bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) { } void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrMSAAPathRenderer::onStencilPath"); SkASSERT(args.fShape->style().isSimpleFill()); SkASSERT(!args.fShape->mayBeInverseFilledAfterStyling()); GrPaint paint; - paint.setXPFactory(GrDisableColorXPFactory::Make()); - paint.setAntiAlias(args.fIsAA); + paint.setXPFactory(GrDisableColorXPFactory::Get()); - this->internalDrawPath(args.fDrawContext, paint, GrUserStencilSettings::kUnused, *args.fClip, - *args.fViewMatrix, *args.fShape, true); + this->internalDrawPath(args.fRenderTargetContext, std::move(paint), args.fAAType, + GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix, + *args.fShape, true); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/gpu/batches/GrMSAAPathRenderer.h b/gfx/skia/skia/src/gpu/ops/GrMSAAPathRenderer.h similarity index 87% rename from gfx/skia/skia/src/gpu/batches/GrMSAAPathRenderer.h rename to gfx/skia/skia/src/gpu/ops/GrMSAAPathRenderer.h index 3bc4ee6f7bdb..13d3e15a7e17 100644 --- a/gfx/skia/skia/src/gpu/batches/GrMSAAPathRenderer.h +++ b/gfx/skia/skia/src/gpu/ops/GrMSAAPathRenderer.h @@ -21,8 +21,9 @@ private: void onStencilPath(const StencilPathArgs&) override; - bool internalDrawPath(GrDrawContext*, - const GrPaint&, + bool internalDrawPath(GrRenderTargetContext*, + GrPaint&&, + GrAAType, const GrUserStencilSettings&, const GrClip&, const SkMatrix& viewMatrix, diff --git a/gfx/skia/skia/src/gpu/ops/GrMeshDrawOp.cpp b/gfx/skia/skia/src/gpu/ops/GrMeshDrawOp.cpp new file mode 100644 index 000000000000..378524541b4e --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrMeshDrawOp.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrMeshDrawOp.h" +#include "GrOpFlushState.h" +#include "GrResourceProvider.h" + +GrMeshDrawOp::GrMeshDrawOp(uint32_t classID) + : INHERITED(classID), fBaseDrawToken(GrDrawOpUploadToken::AlreadyFlushedToken()) {} + +void GrMeshDrawOp::onPrepare(GrOpFlushState* state) { + Target target(state, this); + this->onPrepareDraws(&target); +} + +void* GrMeshDrawOp::InstancedHelper::init(Target* target, GrPrimitiveType primType, + size_t vertexStride, const GrBuffer* indexBuffer, + int verticesPerInstance, int indicesPerInstance, + int instancesToDraw) { + SkASSERT(target); + if (!indexBuffer) { + return nullptr; + } + const GrBuffer* vertexBuffer; + int firstVertex; + int vertexCount = verticesPerInstance * instancesToDraw; + void* vertices = + target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); + if (!vertices) { + SkDebugf("Vertices could not be allocated for instanced rendering."); + return nullptr; + } + SkASSERT(vertexBuffer); + size_t ibSize = indexBuffer->gpuMemorySize(); + int maxInstancesPerDraw = static_cast(ibSize / (sizeof(uint16_t) * indicesPerInstance)); + + fMesh.initInstanced(primType, vertexBuffer, indexBuffer, firstVertex, verticesPerInstance, + indicesPerInstance, instancesToDraw, maxInstancesPerDraw); + return vertices; +} + +void GrMeshDrawOp::InstancedHelper::recordDraw(Target* target, const GrGeometryProcessor* gp, + const GrPipeline* pipeline) { + SkASSERT(fMesh.instanceCount()); + target->draw(gp, pipeline, fMesh); +} + +void* GrMeshDrawOp::QuadHelper::init(Target* target, size_t vertexStride, int quadsToDraw) { + sk_sp quadIndexBuffer(target->resourceProvider()->refQuadIndexBuffer()); + if (!quadIndexBuffer) { + SkDebugf("Could not get quad index buffer."); + return nullptr; + } + return this->INHERITED::init(target, kTriangles_GrPrimitiveType, vertexStride, + quadIndexBuffer.get(), kVerticesPerQuad, kIndicesPerQuad, + quadsToDraw); +} + +void GrMeshDrawOp::onExecute(GrOpFlushState* state) { + SkASSERT(!state->drawOpArgs().fAppliedClip); + SkASSERT(!state->drawOpArgs().fDstTexture.texture()); + int currUploadIdx = 0; + int currMeshIdx = 0; + + SkASSERT(fQueuedDraws.empty() || fBaseDrawToken == state->nextTokenToFlush()); + + for (int currDrawIdx = 0; currDrawIdx < fQueuedDraws.count(); ++currDrawIdx) { + GrDrawOpUploadToken drawToken = state->nextTokenToFlush(); + while (currUploadIdx < fInlineUploads.count() && + fInlineUploads[currUploadIdx].fUploadBeforeToken == drawToken) { + state->commandBuffer()->inlineUpload(state, fInlineUploads[currUploadIdx++].fUpload, + state->drawOpArgs().fRenderTarget); + } + const QueuedDraw& draw = fQueuedDraws[currDrawIdx]; + SkASSERT(draw.fPipeline->getRenderTarget() == state->drawOpArgs().fRenderTarget); + state->commandBuffer()->draw(*draw.fPipeline, *draw.fGeometryProcessor.get(), + fMeshes.begin() + currMeshIdx, draw.fMeshCnt, this->bounds()); + currMeshIdx += draw.fMeshCnt; + state->flushToken(); + } + SkASSERT(currUploadIdx == fInlineUploads.count()); + SkASSERT(currMeshIdx == fMeshes.count()); + fQueuedDraws.reset(); + fInlineUploads.reset(); +} + +////////////////////////////////////////////////////////////////////////////// + +void GrMeshDrawOp::Target::draw(const GrGeometryProcessor* gp, const GrPipeline* pipeline, + const GrMesh& mesh) { + GrMeshDrawOp* op = this->meshDrawOp(); + op->fMeshes.push_back(mesh); + if (!op->fQueuedDraws.empty()) { + // If the last draw shares a geometry processor and pipeline and there are no intervening + // uploads, add this mesh to it. + GrLegacyMeshDrawOp::QueuedDraw& lastDraw = op->fQueuedDraws.back(); + if (lastDraw.fGeometryProcessor == gp && lastDraw.fPipeline == pipeline && + (op->fInlineUploads.empty() || + op->fInlineUploads.back().fUploadBeforeToken != this->nextDrawToken())) { + ++lastDraw.fMeshCnt; + return; + } + } + GrLegacyMeshDrawOp::QueuedDraw& draw = op->fQueuedDraws.push_back(); + GrDrawOpUploadToken token = this->state()->issueDrawToken(); + draw.fGeometryProcessor.reset(gp); + draw.fPipeline = pipeline; + draw.fMeshCnt = 1; + if (op->fQueuedDraws.count() == 1) { + op->fBaseDrawToken = token; + } +} diff --git a/gfx/skia/skia/src/gpu/ops/GrMeshDrawOp.h b/gfx/skia/skia/src/gpu/ops/GrMeshDrawOp.h new file mode 100644 index 000000000000..8fbd30d2802e --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrMeshDrawOp.h @@ -0,0 +1,218 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrMeshDrawOp_DEFINED +#define GrMeshDrawOp_DEFINED + +#include "GrDrawOp.h" +#include "GrGeometryProcessor.h" +#include "GrMesh.h" +#include "GrPendingProgramElement.h" +#include "GrPipelineBuilder.h" + +#include "SkTLList.h" + +class GrCaps; +class GrOpFlushState; + +/** + * Base class for mesh-drawing GrDrawOps. + */ +class GrMeshDrawOp : public GrDrawOp { +public: + class Target; + +protected: + GrMeshDrawOp(uint32_t classID); + + /** Helper for rendering instances using an instanced index buffer. This class creates the space + for the vertices and flushes the draws to the GrMeshDrawOp::Target. */ + class InstancedHelper { + public: + InstancedHelper() {} + /** Returns the allocated storage for the vertices. The caller should populate the vertices + before calling recordDraws(). */ + void* init(Target*, GrPrimitiveType, size_t vertexStride, const GrBuffer*, + int verticesPerInstance, int indicesPerInstance, int instancesToDraw); + + /** Call after init() to issue draws to the GrMeshDrawOp::Target.*/ + void recordDraw(Target*, const GrGeometryProcessor*, const GrPipeline*); + + private: + GrMesh fMesh; + }; + + static const int kVerticesPerQuad = 4; + static const int kIndicesPerQuad = 6; + + /** A specialization of InstanceHelper for quad rendering. */ + class QuadHelper : private InstancedHelper { + public: + QuadHelper() : INHERITED() {} + /** Finds the cached quad index buffer and reserves vertex space. Returns nullptr on failure + and on success a pointer to the vertex data that the caller should populate before + calling recordDraws(). */ + void* init(Target*, size_t vertexStride, int quadsToDraw); + + using InstancedHelper::recordDraw; + + private: + typedef InstancedHelper INHERITED; + }; + +private: + void onPrepare(GrOpFlushState* state) final; + void onExecute(GrOpFlushState* state) final; + + virtual void onPrepareDraws(Target*) const = 0; + + // A set of contiguous draws that share a draw token and primitive processor. The draws all use + // the op's pipeline. The meshes for the draw are stored in the fMeshes array and each + // Queued draw uses fMeshCnt meshes from the fMeshes array. The reason for coallescing meshes + // that share a primitive processor into a QueuedDraw is that it allows the Gpu object to setup + // the shared state once and then issue draws for each mesh. + struct QueuedDraw { + int fMeshCnt = 0; + GrPendingProgramElement fGeometryProcessor; + const GrPipeline* fPipeline; + }; + + // All draws in all the GrMeshDrawOps have implicit tokens based on the order they are enqueued + // globally across all ops. This is the offset of the first entry in fQueuedDraws. + // fQueuedDraws[i]'s token is fBaseDrawToken + i. + GrDrawOpUploadToken fBaseDrawToken; + SkSTArray<4, GrMesh> fMeshes; + SkSTArray<4, QueuedDraw, true> fQueuedDraws; + + typedef GrDrawOp INHERITED; +}; + +/** + * Many of our ops derive from this class which initializes a GrPipeline just before being recorded. + * We are migrating away from use of this class. + */ +class GrLegacyMeshDrawOp : public GrMeshDrawOp { +public: + /** + * Performs analysis of the fragment processors in GrProcessorSet and GrAppliedClip using the + * initial color and coverage from this op's geometry processor. + */ + GrProcessorSet::Analysis analyzeUpdateAndRecordProcessors(GrPipelineBuilder* pipelineBuilder, + const GrAppliedClip* appliedClip, + bool isMixedSamples, + const GrCaps& caps, + GrColor* overrideColor) const { + GrProcessorAnalysisColor inputColor; + GrProcessorAnalysisCoverage inputCoverage; + this->getProcessorAnalysisInputs(&inputColor, &inputCoverage); + return pipelineBuilder->finalizeProcessors(inputColor, inputCoverage, appliedClip, + isMixedSamples, caps, overrideColor); + } + + void initPipeline(const GrPipeline::InitArgs& args, const GrProcessorSet::Analysis& analysis, + GrColor overrideColor) { + fPipeline.init(args); + this->applyPipelineOptimizations(PipelineOptimizations(analysis, overrideColor)); + } + + /** + * Mesh draw ops use a legacy system in GrRenderTargetContext where the pipeline is created when + * the op is recorded. These methods are unnecessary as this information is in the pipeline. + */ + FixedFunctionFlags fixedFunctionFlags() const override { + SkFAIL("This should never be called for legacy mesh draw ops."); + return FixedFunctionFlags::kNone; + } + bool xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*) override { + SkFAIL("Should never be called for legacy mesh draw ops."); + return false; + } + +protected: + GrLegacyMeshDrawOp(uint32_t classID) : INHERITED(classID) {} + /** + * This is a legacy class only used by GrLegacyMeshDrawOp and will be removed. It presents some + * aspects of GrProcessorSet::Analysis to GrLegacyMeshDrawOp subclasses. + */ + class PipelineOptimizations { + public: + PipelineOptimizations(const GrProcessorSet::Analysis& analysis, GrColor overrideColor) { + fFlags = 0; + if (analysis.inputColorIsOverridden()) { + fFlags |= kUseOverrideColor_Flag; + fOverrideColor = overrideColor; + } + if (analysis.usesLocalCoords()) { + fFlags |= kReadsLocalCoords_Flag; + } + if (analysis.isCompatibleWithCoverageAsAlpha()) { + fFlags |= kCanTweakAlphaForCoverage_Flag; + } + } + + /** Does the pipeline require access to (implicit or explicit) local coordinates? */ + bool readsLocalCoords() const { return SkToBool(kReadsLocalCoords_Flag & fFlags); } + + /** Does the pipeline allow the GrPrimitiveProcessor to combine color and coverage into one + color output ? */ + bool canTweakAlphaForCoverage() const { + return SkToBool(kCanTweakAlphaForCoverage_Flag & fFlags); + } + + /** Does the pipeline require the GrPrimitiveProcessor to specify a specific color (and if + so get the color)? */ + bool getOverrideColorIfSet(GrColor* overrideColor) const { + if (SkToBool(kUseOverrideColor_Flag & fFlags)) { + if (overrideColor) { + *overrideColor = fOverrideColor; + } + return true; + } + return false; + } + + private: + enum { + // If this is not set the primitive processor need not produce local coordinates + kReadsLocalCoords_Flag = 0x1, + // If this flag is set then the primitive processor may produce color*coverage as + // its color output (and not output a separate coverage). + kCanTweakAlphaForCoverage_Flag = 0x2, + // If this flag is set the GrPrimitiveProcessor must produce fOverrideColor as its + // output color. If not set fOverrideColor is to be ignored. + kUseOverrideColor_Flag = 0x4, + }; + + uint32_t fFlags; + GrColor fOverrideColor; + }; + + const GrPipeline* pipeline() const { + SkASSERT(fPipeline.isInitialized()); + return &fPipeline; + } + +private: + /** + * Provides information about the GrPrimitiveProccesor color and coverage outputs which become + * inputs to the first color and coverage fragment processors. + */ + virtual void getProcessorAnalysisInputs(GrProcessorAnalysisColor*, + GrProcessorAnalysisCoverage*) const = 0; + + /** + * After processor analysis is complete this is called so that the op can use the analysis + * results when constructing its GrPrimitiveProcessor. + */ + virtual void applyPipelineOptimizations(const PipelineOptimizations&) = 0; + + GrPipeline fPipeline; + + typedef GrMeshDrawOp INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrNonAAFillRectBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrNonAAFillRectOp.cpp similarity index 54% rename from gfx/skia/skia/src/gpu/batches/GrNonAAFillRectBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrNonAAFillRectOp.cpp index 1422951d240d..99cb2bd9dff9 100644 --- a/gfx/skia/skia/src/gpu/batches/GrNonAAFillRectBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrNonAAFillRectOp.cpp @@ -5,22 +5,22 @@ * found in the LICENSE file. */ -#include "GrNonAAFillRectBatch.h" +#include "GrNonAAFillRectOp.h" -#include "GrBatchFlushState.h" #include "GrColor.h" #include "GrDefaultGeoProcFactory.h" +#include "GrMeshDrawOp.h" +#include "GrOpFlushState.h" #include "GrPrimitiveProcessor.h" -#include "GrResourceProvider.h" #include "GrQuad.h" -#include "GrVertexBatch.h" +#include "GrResourceProvider.h" #include "SkMatrixPriv.h" static const int kVertsPerInstance = 4; static const int kIndicesPerInstance = 6; -/** We always use per-vertex colors so that rects can be batched across color changes. Sometimes +/** We always use per-vertex colors so that rects can be combined across color changes. Sometimes we have explicit local coords and sometimes not. We *could* always provide explicit local coords and just duplicate the positions when the caller hasn't provided a local coord rect, but we haven't seen a use case which frequently switches between local rect and no local @@ -28,13 +28,10 @@ static const int kIndicesPerInstance = 6; The vertex attrib order is always pos, color, [local coords]. */ -static sk_sp make_gp(bool readsCoverage) { +static sk_sp make_gp() { using namespace GrDefaultGeoProcFactory; - Color color(Color::kAttribute_Type); - Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Type); - - LocalCoords localCoords(LocalCoords::kHasExplicit_Type); - return GrDefaultGeoProcFactory::Make(color, coverage, localCoords, SkMatrix::I()); + return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type, + LocalCoords::kHasExplicit_Type, SkMatrix::I()); } static void tesselate(intptr_t vertices, @@ -45,8 +42,7 @@ static void tesselate(intptr_t vertices, const GrQuad* localQuad) { SkPoint* positions = reinterpret_cast(vertices); - positions->setRectFan(rect.fLeft, rect.fTop, - rect.fRight, rect.fBottom, vertexStride); + positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); if (viewMatrix) { SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerInstance); @@ -57,8 +53,8 @@ static void tesselate(intptr_t vertices, if (localQuad) { static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); for (int i = 0; i < kVertsPerInstance; i++) { - SkPoint* coords = reinterpret_cast(vertices + kLocalOffset + - i * vertexStride); + SkPoint* coords = + reinterpret_cast(vertices + kLocalOffset + i * vertexStride); *coords = localQuad->point(i); } } @@ -67,19 +63,18 @@ static void tesselate(intptr_t vertices, GrColor* vertColor = reinterpret_cast(vertices + kColorOffset); for (int j = 0; j < 4; ++j) { *vertColor = color; - vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); + vertColor = (GrColor*)((intptr_t)vertColor + vertexStride); } } -class NonAAFillRectBatch : public GrVertexBatch { +class NonAAFillRectOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - NonAAFillRectBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, - const SkRect* localRect, const SkMatrix* localMatrix) + NonAAFillRectOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, + const SkRect* localRect, const SkMatrix* localMatrix) : INHERITED(ClassID()) { - SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || - !localMatrix->hasPerspective())); + SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective())); RectInfo& info = fRects.push_back(); info.fColor = color; info.fViewMatrix = viewMatrix; @@ -96,39 +91,37 @@ public: this->setTransformedBounds(fRects[0].fRect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); } - const char* name() const override { return "NonAAFillRectBatch"; } + const char* name() const override { return "NonAAFillRectOp"; } SkString dumpInfo() const override { SkString str; - str.appendf("# batched: %d\n", fRects.count()); + str.appendf("# combined: %d\n", fRects.count()); for (int i = 0; i < fRects.count(); ++i) { const RectInfo& info = fRects[i]; - str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", - i, info.fColor, - info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight, info.fRect.fBottom); + str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i, + info.fColor, info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight, + info.fRect.fBottom); } + str.append(DumpPipelineInfo(*this->pipeline())); str.append(INHERITED::dumpInfo()); return str; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fRects[0].fColor); - coverage->setKnownSingleComponent(0xff); - } - - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - overrides.getOverrideColorIfSet(&fRects[0].fColor); - fOverrides = overrides; - } - private: - NonAAFillRectBatch() : INHERITED(ClassID()) {} + NonAAFillRectOp() : INHERITED(ClassID()) {} + + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fRects[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kNone; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fRects[0].fColor); + } void onPrepareDraws(Target* target) const override { - sk_sp gp = make_gp(fOverrides.readsCoverage()); + sk_sp gp = make_gp(); if (!gp) { SkDebugf("Couldn't create GrGeometryProcessor\n"); return; @@ -139,38 +132,32 @@ private: size_t vertexStride = gp->getVertexStride(); int instanceCount = fRects.count(); - SkAutoTUnref indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); + sk_sp indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); InstancedHelper helper; - void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, - indexBuffer, kVertsPerInstance, - kIndicesPerInstance, instanceCount); + void* vertices = + helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(), + kVertsPerInstance, kIndicesPerInstance, instanceCount); if (!vertices || !indexBuffer) { SkDebugf("Could not allocate vertices\n"); return; } for (int i = 0; i < instanceCount; i++) { - intptr_t verts = reinterpret_cast(vertices) + - i * kVertsPerInstance * vertexStride; + intptr_t verts = + reinterpret_cast(vertices) + i * kVertsPerInstance * vertexStride; tesselate(verts, vertexStride, fRects[i].fColor, &fRects[i].fViewMatrix, fRects[i].fRect, &fRects[i].fLocalQuad); } - helper.recordDraw(target, gp.get()); + helper.recordDraw(target, gp.get(), this->pipeline()); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - NonAAFillRectBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + NonAAFillRectOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; } - // In the event of two batches, one who can tweak, one who cannot, we just fall back to - // not tweaking - if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) { - fOverrides = that->fOverrides; - } - fRects.push_back_n(that->fRects.count(), that->fRects.begin()); this->joinBounds(*that); return true; @@ -183,31 +170,30 @@ private: GrQuad fLocalQuad; }; - GrXPOverridesForBatch fOverrides; SkSTArray<1, RectInfo, true> fRects; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -namespace GrNonAAFillRectBatch { +namespace GrNonAAFillRectOp { -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect* localRect, - const SkMatrix* localMatrix) { - return new NonAAFillRectBatch(color, viewMatrix, rect, localRect, localMatrix); +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect* localRect, + const SkMatrix* localMatrix) { + return std::unique_ptr( + new NonAAFillRectOp(color, viewMatrix, rect, localRect, localMatrix)); } - }; /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -#include "GrBatchTest.h" +#include "GrDrawOpTest.h" -DRAW_BATCH_TEST_DEFINE(RectBatch) { +DRAW_OP_TEST_DEFINE(NonAAFillRectOp) { GrColor color = GrRandomColor(random); SkRect rect = GrTest::TestRect(random); SkRect localRect = GrTest::TestRect(random); @@ -216,9 +202,11 @@ DRAW_BATCH_TEST_DEFINE(RectBatch) { bool hasLocalRect = random->nextBool(); bool hasLocalMatrix = random->nextBool(); - return GrNonAAFillRectBatch::Create(color, viewMatrix, rect, - hasLocalRect ? &localRect : nullptr, - hasLocalMatrix ? &localMatrix : nullptr); + return GrNonAAFillRectOp::Make(color, + viewMatrix, + rect, + hasLocalRect ? &localRect : nullptr, + hasLocalMatrix ? &localMatrix : nullptr); } #endif diff --git a/gfx/skia/skia/src/gpu/ops/GrNonAAFillRectOp.h b/gfx/skia/skia/src/gpu/ops/GrNonAAFillRectOp.h new file mode 100644 index 000000000000..89722818479e --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrNonAAFillRectOp.h @@ -0,0 +1,33 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrNonAAFillRectOp_DEFINED +#define GrNonAAFillRectOp_DEFINED + +#include "GrColor.h" +#include "SkRefCnt.h" + +class GrLegacyMeshDrawOp; +class SkMatrix; +struct SkRect; + +namespace GrNonAAFillRectOp { + +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect* localRect, + const SkMatrix* localMatrix); + +std::unique_ptr MakeWithPerspective(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect* localRect, + const SkMatrix* localMatrix); +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrNonAAFillRectPerspectiveBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrNonAAFillRectPerspectiveOp.cpp similarity index 57% rename from gfx/skia/skia/src/gpu/batches/GrNonAAFillRectPerspectiveBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrNonAAFillRectPerspectiveOp.cpp index aa5a4203cf6a..fef515421f65 100644 --- a/gfx/skia/skia/src/gpu/batches/GrNonAAFillRectPerspectiveBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrNonAAFillRectPerspectiveOp.cpp @@ -5,20 +5,20 @@ * found in the LICENSE file. */ -#include "GrNonAAFillRectBatch.h" +#include "GrNonAAFillRectOp.h" -#include "GrBatchFlushState.h" #include "GrColor.h" #include "GrDefaultGeoProcFactory.h" +#include "GrMeshDrawOp.h" +#include "GrOpFlushState.h" #include "GrPrimitiveProcessor.h" -#include "GrResourceProvider.h" #include "GrQuad.h" -#include "GrVertexBatch.h" +#include "GrResourceProvider.h" static const int kVertsPerInstance = 4; static const int kIndicesPerInstance = 6; -/** We always use per-vertex colors so that rects can be batched across color changes. Sometimes +/** We always use per-vertex colors so that rects can be combined across color changes. Sometimes we have explicit local coords and sometimes not. We *could* always provide explicit local coords and just duplicate the positions when the caller hasn't provided a local coord rect, but we haven't seen a use case which frequently switches between local rect and no local @@ -27,30 +27,30 @@ static const int kIndicesPerInstance = 6; The vertex attrib order is always pos, color, [local coords]. */ static sk_sp make_persp_gp(const SkMatrix& viewMatrix, - bool readsCoverage, bool hasExplicitLocalCoords, const SkMatrix* localMatrix) { SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective())); using namespace GrDefaultGeoProcFactory; - Color color(Color::kAttribute_Type); - Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Type); // If we have perspective on the viewMatrix then we won't map on the CPU, nor will we map // the local rect on the cpu (in case the localMatrix also has perspective). // Otherwise, if we have a local rect, then we apply the localMatrix directly to the localRect // to generate vertex local coords if (viewMatrix.hasPerspective()) { - LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type : - LocalCoords::kUsePosition_Type, + LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type + : LocalCoords::kUsePosition_Type, localMatrix); - return GrDefaultGeoProcFactory::Make(color, coverage, localCoords, viewMatrix); + return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, + Coverage::kSolid_Type, localCoords, viewMatrix); } else if (hasExplicitLocalCoords) { LocalCoords localCoords(LocalCoords::kHasExplicit_Type, localMatrix); - return GrDefaultGeoProcFactory::Make(color, coverage, localCoords, SkMatrix::I()); + return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, + Coverage::kSolid_Type, localCoords, SkMatrix::I()); } else { LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix); - return GrDefaultGeoProcFactory::MakeForDeviceSpace(color, coverage, localCoords, + return GrDefaultGeoProcFactory::MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type, + Coverage::kSolid_Type, localCoords, viewMatrix); } } @@ -63,8 +63,7 @@ static void tesselate(intptr_t vertices, const GrQuad* localQuad) { SkPoint* positions = reinterpret_cast(vertices); - positions->setRectFan(rect.fLeft, rect.fTop, - rect.fRight, rect.fBottom, vertexStride); + positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); if (viewMatrix) { viewMatrix->mapPointsWithStride(positions, vertexStride, kVertsPerInstance); @@ -75,8 +74,8 @@ static void tesselate(intptr_t vertices, if (localQuad) { static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); for (int i = 0; i < kVertsPerInstance; i++) { - SkPoint* coords = reinterpret_cast(vertices + kLocalOffset + - i * vertexStride); + SkPoint* coords = + reinterpret_cast(vertices + kLocalOffset + i * vertexStride); *coords = localQuad->point(i); } } @@ -85,21 +84,19 @@ static void tesselate(intptr_t vertices, GrColor* vertColor = reinterpret_cast(vertices + kColorOffset); for (int j = 0; j < 4; ++j) { *vertColor = color; - vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); + vertColor = (GrColor*)((intptr_t)vertColor + vertexStride); } } -// We handle perspective in the local matrix or viewmatrix with special batches -class GrNonAAFillRectPerspectiveBatch : public GrVertexBatch { +// We handle perspective in the local matrix or viewmatrix with special ops. +class NonAAFillRectPerspectiveOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - GrNonAAFillRectPerspectiveBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, - const SkRect* localRect, const SkMatrix* localMatrix) - : INHERITED(ClassID()) - , fViewMatrix(viewMatrix) { - SkASSERT(viewMatrix.hasPerspective() || (localMatrix && - localMatrix->hasPerspective())); + NonAAFillRectPerspectiveOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, + const SkRect* localRect, const SkMatrix* localMatrix) + : INHERITED(ClassID()), fViewMatrix(viewMatrix) { + SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective())); RectInfo& info = fRects.push_back(); info.fColor = color; info.fRect = rect; @@ -114,40 +111,37 @@ public: this->setTransformedBounds(rect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); } - const char* name() const override { return "NonAAFillRectPerspectiveBatch"; } + const char* name() const override { return "NonAAFillRectPerspectiveOp"; } SkString dumpInfo() const override { SkString str; - str.appendf("# batched: %d\n", fRects.count()); + str.appendf("# combined: %d\n", fRects.count()); for (int i = 0; i < fRects.count(); ++i) { const RectInfo& geo = fRects[0]; - str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", - i, geo.fColor, - geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight, geo.fRect.fBottom); + str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i, + geo.fColor, geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight, + geo.fRect.fBottom); } + str.append(DumpPipelineInfo(*this->pipeline())); str.append(INHERITED::dumpInfo()); return str; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fRects[0].fColor); - coverage->setKnownSingleComponent(0xff); - } - - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - overrides.getOverrideColorIfSet(&fRects[0].fColor); - fOverrides = overrides; - } - private: - GrNonAAFillRectPerspectiveBatch() : INHERITED(ClassID()) {} + NonAAFillRectPerspectiveOp() : INHERITED(ClassID()) {} + + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fRects[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kNone; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fRects[0].fColor); + } void onPrepareDraws(Target* target) const override { sk_sp gp = make_persp_gp(fViewMatrix, - fOverrides.readsCoverage(), fHasLocalRect, fHasLocalMatrix ? &fLocalMatrix : nullptr); if (!gp) { @@ -155,18 +149,19 @@ private: return; } SkASSERT(fHasLocalRect - ? gp->getVertexStride() == - sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) - : gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); + ? gp->getVertexStride() == + sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) + : gp->getVertexStride() == + sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); size_t vertexStride = gp->getVertexStride(); int instanceCount = fRects.count(); - SkAutoTUnref indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); + sk_sp indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); InstancedHelper helper; - void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, - indexBuffer, kVertsPerInstance, - kIndicesPerInstance, instanceCount); + void* vertices = + helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(), + kVertsPerInstance, kIndicesPerInstance, instanceCount); if (!vertices || !indexBuffer) { SkDebugf("Could not allocate vertices\n"); return; @@ -174,8 +169,8 @@ private: for (int i = 0; i < instanceCount; i++) { const RectInfo& info = fRects[i]; - intptr_t verts = reinterpret_cast(vertices) + - i * kVertsPerInstance * vertexStride; + intptr_t verts = + reinterpret_cast(vertices) + i * kVertsPerInstance * vertexStride; if (fHasLocalRect) { GrQuad quad(info.fLocalRect); tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, &quad); @@ -183,17 +178,17 @@ private: tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, nullptr); } } - helper.recordDraw(target, gp.get()); + helper.recordDraw(target, gp.get(), this->pipeline()); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - GrNonAAFillRectPerspectiveBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + NonAAFillRectPerspectiveOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; } - // We could batch across perspective vm changes if we really wanted to + // We could combine across perspective vm changes if we really wanted to. if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) { return false; } @@ -204,12 +199,6 @@ private: return false; } - // In the event of two batches, one who can tweak, one who cannot, we just fall back to - // not tweaking - if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) { - fOverrides = that->fOverrides; - } - fRects.push_back_n(that->fRects.count(), that->fRects.begin()); this->joinBounds(*that); return true; @@ -221,35 +210,34 @@ private: SkRect fLocalRect; }; - GrXPOverridesForBatch fOverrides; SkSTArray<1, RectInfo, true> fRects; bool fHasLocalMatrix; bool fHasLocalRect; SkMatrix fLocalMatrix; SkMatrix fViewMatrix; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -namespace GrNonAAFillRectBatch { +namespace GrNonAAFillRectOp { -GrDrawBatch* CreateWithPerspective(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect* localRect, - const SkMatrix* localMatrix) { - return new GrNonAAFillRectPerspectiveBatch(color, viewMatrix, rect, localRect, localMatrix); +std::unique_ptr MakeWithPerspective(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect* localRect, + const SkMatrix* localMatrix) { + return std::unique_ptr( + new NonAAFillRectPerspectiveOp(color, viewMatrix, rect, localRect, localMatrix)); } - }; /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -#include "GrBatchTest.h" +#include "GrDrawOpTest.h" -DRAW_BATCH_TEST_DEFINE(PerspRectBatch) { +DRAW_OP_TEST_DEFINE(NonAAFillRectPerspectiveOp) { GrColor color = GrRandomColor(random); SkRect rect = GrTest::TestRect(random); SkRect localRect = GrTest::TestRect(random); @@ -262,9 +250,9 @@ DRAW_BATCH_TEST_DEFINE(PerspRectBatch) { } bool hasLocalRect = random->nextBool(); - return GrNonAAFillRectBatch::CreateWithPerspective(color, viewMatrix, rect, - hasLocalRect ? &localRect : nullptr, - hasLocalMatrix ? &localMatrix : nullptr); + return GrNonAAFillRectOp::MakeWithPerspective(color, viewMatrix, rect, + hasLocalRect ? &localRect : nullptr, + hasLocalMatrix ? &localMatrix : nullptr); } #endif diff --git a/gfx/skia/skia/src/gpu/batches/GrNonAAStrokeRectBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrNonAAStrokeRectOp.cpp similarity index 56% rename from gfx/skia/skia/src/gpu/batches/GrNonAAStrokeRectBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrNonAAStrokeRectOp.cpp index f443b32f19f8..69958c0d41b7 100644 --- a/gfx/skia/skia/src/gpu/batches/GrNonAAStrokeRectBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrNonAAStrokeRectOp.cpp @@ -5,13 +5,14 @@ * found in the LICENSE file. */ -#include "GrNonAAStrokeRectBatch.h" +#include "GrNonAAStrokeRectOp.h" -#include "GrBatchTest.h" -#include "GrBatchFlushState.h" #include "GrColor.h" #include "GrDefaultGeoProcFactory.h" -#include "GrVertexBatch.h" +#include "GrDrawOpTest.h" +#include "GrMeshDrawOp.h" +#include "GrOpFlushState.h" +#include "SkStrokeRec.h" #include "SkRandom.h" /* create a triangle strip that strokes the specified rect. There are 8 @@ -23,7 +24,7 @@ static void init_stroke_rect_strip(SkPoint verts[10], const SkRect& rect, SkScal const SkScalar rad = SkScalarHalf(width); // TODO we should be able to enable this assert, but we'd have to filter these draws // this is a bug - //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2); + // SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2); verts[0].set(rect.fLeft + rad, rect.fTop + rad); verts[1].set(rect.fLeft - rad, rect.fTop - rad); @@ -45,34 +46,38 @@ inline static bool allowed_stroke(const SkStrokeRec& stroke) { (stroke.getJoin() == SkPaint::kMiter_Join && stroke.getMiter() > SK_ScalarSqrt2); } -class NonAAStrokeRectBatch : public GrVertexBatch { +class NonAAStrokeRectOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - const char* name() const override { return "NonAAStrokeRectBatch"; } + const char* name() const override { return "NonAAStrokeRectOp"; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fColor); - coverage->setKnownSingleComponent(0xff); + SkString dumpInfo() const override { + SkString string; + string.appendf( + "Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], " + "StrokeWidth: %.2f\n", + fColor, fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom, fStrokeWidth); + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; } - static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, - const SkStrokeRec& stroke, bool snapToPixelCenters) { + static std::unique_ptr Make(GrColor color, const SkMatrix& viewMatrix, + const SkRect& rect, const SkStrokeRec& stroke, + bool snapToPixelCenters) { if (!allowed_stroke(stroke)) { return nullptr; } - NonAAStrokeRectBatch* batch = new NonAAStrokeRectBatch(); - batch->fColor = color; - batch->fViewMatrix = viewMatrix; - batch->fRect = rect; + NonAAStrokeRectOp* op = new NonAAStrokeRectOp(); + op->fColor = color; + op->fViewMatrix = viewMatrix; + op->fRect = rect; // Sort the rect for hairlines - batch->fRect.sort(); - batch->fStrokeWidth = stroke.getWidth(); + op->fRect.sort(); + op->fStrokeWidth = stroke.getWidth(); - SkScalar rad = SkScalarHalf(batch->fStrokeWidth); + SkScalar rad = SkScalarHalf(op->fStrokeWidth); SkRect bounds = rect; bounds.outset(rad, rad); @@ -87,27 +92,32 @@ public: SkScalarFloorToScalar(bounds.fRight), SkScalarFloorToScalar(bounds.fBottom)); bounds.offset(0.5f, 0.5f); - batch->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); + op->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); } else { - batch->setTransformedBounds(bounds, batch->fViewMatrix, HasAABloat ::kNo, - IsZeroArea::kNo); + op->setTransformedBounds(bounds, op->fViewMatrix, HasAABloat::kNo, IsZeroArea::kNo); } - return batch; + return std::unique_ptr(op); } private: - NonAAStrokeRectBatch() : INHERITED(ClassID()) {} + NonAAStrokeRectOp() : INHERITED(ClassID()) {} + + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fColor); + *coverage = GrProcessorAnalysisCoverage::kNone; + } void onPrepareDraws(Target* target) const override { sk_sp gp; { using namespace GrDefaultGeoProcFactory; Color color(fColor); - Coverage coverage(fOverrides.readsCoverage() ? Coverage::kSolid_Type - : Coverage::kNone_Type); - LocalCoords localCoords(fOverrides.readsLocalCoords() ? LocalCoords::kUsePosition_Type : - LocalCoords::kUnused_Type); - gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fViewMatrix); + LocalCoords::Type localCoordsType = fNeedsLocalCoords + ? LocalCoords::kUsePosition_Type + : LocalCoords::kUnused_Type; + gp = GrDefaultGeoProcFactory::Make(color, Coverage::kSolid_Type, localCoordsType, + fViewMatrix); } size_t vertexStride = gp->getVertexStride(); @@ -122,8 +132,8 @@ private: const GrBuffer* vertexBuffer; int firstVertex; - void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, - &firstVertex); + void* verts = + target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); if (!verts) { SkDebugf("Could not allocate vertices\n"); @@ -148,17 +158,17 @@ private: GrMesh mesh; mesh.init(primType, vertexBuffer, firstVertex, vertexCount); - target->draw(gp.get(), mesh); + target->draw(gp.get(), this->pipeline(), mesh); } - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - overrides.getOverrideColorIfSet(&fColor); - fOverrides = overrides; + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fColor); + fNeedsLocalCoords = optimizations.readsLocalCoords(); } - bool onCombineIfPossible(GrBatch* t, const GrCaps&) override { - // NonAA stroke rects cannot batch right now - // TODO make these batchable + bool onCombineIfPossible(GrOp* t, const GrCaps&) override { + // NonAA stroke rects cannot combine right now + // TODO make these combinable. return false; } @@ -166,31 +176,28 @@ private: SkMatrix fViewMatrix; SkRect fRect; SkScalar fStrokeWidth; - - GrXPOverridesForBatch fOverrides; + bool fNeedsLocalCoords; const static int kVertsPerHairlineRect = 5; const static int kVertsPerStrokeRect = 10; - - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -namespace GrNonAAStrokeRectBatch { +namespace GrNonAAStrokeRectOp { -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkStrokeRec& stroke, - bool snapToPixelCenters) { - return NonAAStrokeRectBatch::Create(color, viewMatrix, rect, stroke, snapToPixelCenters); +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkStrokeRec& stroke, + bool snapToPixelCenters) { + return NonAAStrokeRectOp::Make(color, viewMatrix, rect, stroke, snapToPixelCenters); +} } -} +#if GR_TEST_UTILS -#ifdef GR_TEST_UTILS - -DRAW_BATCH_TEST_DEFINE(NonAAStrokeRectBatch) { +DRAW_OP_TEST_DEFINE(NonAAStrokeRectOp) { SkMatrix viewMatrix = GrTest::TestMatrix(random); GrColor color = GrRandomColor(random); SkRect rect = GrTest::TestRect(random); @@ -200,7 +207,7 @@ DRAW_BATCH_TEST_DEFINE(NonAAStrokeRectBatch) { paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeJoin(SkPaint::kMiter_Join); SkStrokeRec strokeRec(paint); - return GrNonAAStrokeRectBatch::Create(color, viewMatrix, rect, strokeRec, random->nextBool()); + return GrNonAAStrokeRectOp::Make(color, viewMatrix, rect, strokeRec, random->nextBool()); } #endif diff --git a/gfx/skia/skia/src/gpu/ops/GrNonAAStrokeRectOp.h b/gfx/skia/skia/src/gpu/ops/GrNonAAStrokeRectOp.h new file mode 100644 index 000000000000..4071cfd2a932 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrNonAAStrokeRectOp.h @@ -0,0 +1,28 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrNonAAStrokeRectOp_DEFINED +#define GrNonAAStrokeRectOp_DEFINED + +#include "GrColor.h" +#include "SkRefCnt.h" + +class GrLegacyMeshDrawOp; +struct SkRect; +class SkStrokeRec; +class SkMatrix; + +namespace GrNonAAStrokeRectOp { + +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkStrokeRec&, + bool snapToPixelCenters); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrOp.cpp similarity index 64% rename from gfx/skia/skia/src/gpu/batches/GrBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrOp.cpp index 6755cf94f76a..7762a5a84040 100644 --- a/gfx/skia/skia/src/gpu/batches/GrBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrOp.cpp @@ -5,14 +5,14 @@ * found in the LICENSE file. */ -#include "GrBatch.h" +#include "GrOp.h" #include "GrMemoryPool.h" #include "SkSpinlock.h" -// TODO I noticed a small benefit to using a larger exclusive pool for batches. Its very small, -// but seems to be mostly consistent. There is a lot in flux right now, but we should really -// revisit this when batch is everywhere +// TODO I noticed a small benefit to using a larger exclusive pool for ops. Its very small, but +// seems to be mostly consistent. There is a lot in flux right now, but we should really revisit +// this. // We use a global pool protected by a mutex(spinlock). Chrome may use the same GrContext on @@ -20,7 +20,7 @@ // memory barrier between accesses of a context on different threads. Also, there may be multiple // GrContexts and those contexts may be in use concurrently on different threads. namespace { -static SkSpinlock gBatchSpinlock; +static SkSpinlock gOpPoolSpinLock; class MemoryPoolAccessor { public: @@ -29,8 +29,8 @@ public: MemoryPoolAccessor() {} ~MemoryPoolAccessor() {} #else - MemoryPoolAccessor() { gBatchSpinlock.acquire(); } - ~MemoryPoolAccessor() { gBatchSpinlock.release(); } + MemoryPoolAccessor() { gOpPoolSpinLock.acquire(); } + ~MemoryPoolAccessor() { gOpPoolSpinLock.release(); } #endif GrMemoryPool* pool() const { @@ -40,24 +40,23 @@ public: }; } -int32_t GrBatch::gCurrBatchClassID = GrBatch::kIllegalBatchID; +int32_t GrOp::gCurrOpClassID = GrOp::kIllegalOpID; -int32_t GrBatch::gCurrBatchUniqueID = GrBatch::kIllegalBatchID; +int32_t GrOp::gCurrOpUniqueID = GrOp::kIllegalOpID; -void* GrBatch::operator new(size_t size) { +void* GrOp::operator new(size_t size) { return MemoryPoolAccessor().pool()->allocate(size); } -void GrBatch::operator delete(void* target) { +void GrOp::operator delete(void* target) { return MemoryPoolAccessor().pool()->release(target); } -GrBatch::GrBatch(uint32_t classID) +GrOp::GrOp(uint32_t classID) : fClassID(classID) - , fUniqueID(kIllegalBatchID) { + , fUniqueID(kIllegalOpID) { SkASSERT(classID == SkToU32(fClassID)); - SkDEBUGCODE(fUsed = false;) SkDEBUGCODE(fBoundsFlags = kUninitialized_BoundsFlag); } -GrBatch::~GrBatch() {} +GrOp::~GrOp() {} diff --git a/gfx/skia/skia/src/gpu/batches/GrBatch.h b/gfx/skia/skia/src/gpu/ops/GrOp.h similarity index 56% rename from gfx/skia/skia/src/gpu/batches/GrBatch.h rename to gfx/skia/skia/src/gpu/ops/GrOp.h index 8dafe9fba39c..ef752b5d0c29 100644 --- a/gfx/skia/skia/src/gpu/batches/GrBatch.h +++ b/gfx/skia/skia/src/gpu/ops/GrOp.h @@ -5,11 +5,13 @@ * found in the LICENSE file. */ -#ifndef GrBatch_DEFINED -#define GrBatch_DEFINED +#ifndef GrOp_DEFINED +#define GrOp_DEFINED #include "../private/SkAtomics.h" +#include "GrGpuResource.h" #include "GrNonAtomicRef.h" +#include "GrXferProcessor.h" #include "SkMatrix.h" #include "SkRect.h" #include "SkString.h" @@ -18,52 +20,51 @@ class GrCaps; class GrGpuCommandBuffer; -class GrBatchFlushState; -class GrRenderTarget; +class GrOpFlushState; /** - * GrBatch is the base class for all Ganesh deferred geometry generators. To facilitate - * reorderable batching, Ganesh does not generate geometry inline with draw calls. Instead, it - * captures the arguments to the draw and then generates the geometry on demand. This gives GrBatch - * subclasses complete freedom to decide how / what they can batch. + * GrOp is the base class for all Ganesh deferred GPU operations. To facilitate reordering and to + * minimize draw calls, Ganesh does not generate geometry inline with draw calls. Instead, it + * captures the arguments to the draw and then generates the geometry when flushing. This gives GrOp + * subclasses complete freedom to decide how/when to combine in order to produce fewer draw calls + * and minimize state changes. * - * Batches are created when GrContext processes a draw call. Batches of the same subclass may be - * merged using combineIfPossible. When two batches merge, one takes on the union of the data - * and the other is left empty. The merged batch becomes responsible for drawing the data from both - * the original batches. + * Ops of the same subclass may be merged using combineIfPossible. When two ops merge, one + * takes on the union of the data and the other is left empty. The merged op becomes responsible + * for drawing the data from both the original ops. * * If there are any possible optimizations which might require knowing more about the full state of - * the draw, ie whether or not the GrBatch is allowed to tweak alpha for coverage, then this - * information will be communicated to the GrBatch prior to geometry generation. + * the draw, e.g. whether or not the GrOp is allowed to tweak alpha for coverage, then this + * information will be communicated to the GrOp prior to geometry generation. * - * The bounds of the batch must contain all the vertices in device space *irrespective* of the clip. + * The bounds of the op must contain all the vertices in device space *irrespective* of the clip. * The bounds are used in determining which clip elements must be applied and thus the bounds cannot * in turn depend upon the clip. */ -#define GR_BATCH_SPEW 0 -#if GR_BATCH_SPEW - #define GrBATCH_INFO(...) SkDebugf(__VA_ARGS__) - #define GrBATCH_SPEW(code) code +#define GR_OP_SPEW 0 +#if GR_OP_SPEW + #define GrOP_SPEW(code) code + #define GrOP_INFO(...) SkDebugf(__VA_ARGS__) #else - #define GrBATCH_SPEW(code) - #define GrBATCH_INFO(...) + #define GrOP_SPEW(code) + #define GrOP_INFO(...) #endif // A helper macro to generate a class static id -#define DEFINE_BATCH_CLASS_ID \ +#define DEFINE_OP_CLASS_ID \ static uint32_t ClassID() { \ - static uint32_t kClassID = GenBatchClassID(); \ + static uint32_t kClassID = GenOpClassID(); \ return kClassID; \ } -class GrBatch : public GrNonAtomicRef { +class GrOp : private SkNoncopyable { public: - GrBatch(uint32_t classID); - virtual ~GrBatch(); + GrOp(uint32_t classID); + virtual ~GrOp(); virtual const char* name() const = 0; - bool combineIfPossible(GrBatch* that, const GrCaps& caps) { + bool combineIfPossible(GrOp* that, const GrCaps& caps) { if (this->classID() != that->classID()) { return false; } @@ -76,6 +77,12 @@ public: return fBounds; } + void setClippedBounds(const SkRect& clippedBounds) { + fBounds = clippedBounds; + // The clipped bounds already incorporate any effect of the bounds flags. + fBoundsFlags = 0; + } + bool hasAABloat() const { SkASSERT(fBoundsFlags != kUninitialized_BoundsFlag); return SkToBool(fBoundsFlags & kAABloat_BoundsFlag); @@ -97,7 +104,7 @@ public: } /** - * Helper for safely down-casting to a GrBatch subclass + * Helper for safely down-casting to a GrOp subclass */ template const T& cast() const { SkASSERT(T::ClassID() == this->classID()); @@ -109,42 +116,44 @@ public: return static_cast(this); } - uint32_t classID() const { SkASSERT(kIllegalBatchID != fClassID); return fClassID; } + uint32_t classID() const { SkASSERT(kIllegalOpID != fClassID); return fClassID; } // We lazily initialize the uniqueID because currently the only user is GrAuditTrail uint32_t uniqueID() const { - if (kIllegalBatchID == fUniqueID) { - fUniqueID = GenBatchID(); + if (kIllegalOpID == fUniqueID) { + fUniqueID = GenOpID(); } return fUniqueID; } - SkDEBUGCODE(bool isUsed() const { return fUsed; }) - /** Called prior to drawing. The batch should perform any resource creation necessary to - to quickly issue its draw when draw is called. */ - void prepare(GrBatchFlushState* state) { this->onPrepare(state); } + /** + * This is called to notify the op that it has been recorded into a GrOpList. Ops can use this + * to begin preparations for the flush of the op list. Note that the op still may either be + * combined into another op or have another op combined into it via combineIfPossible() after + * this call is made. + */ + virtual void wasRecorded() {} - /** Issues the batches commands to GrGpu. */ - void draw(GrBatchFlushState* state) { this->onDraw(state); } + /** + * Called prior to executing. The op should perform any resource creation or data transfers + * necessary before execute() is called. + */ + void prepare(GrOpFlushState* state) { this->onPrepare(state); } - /** Used to block batching across render target changes. Remove this once we store - GrBatches for different RTs in different targets. */ - virtual uint32_t renderTargetUniqueID() const = 0; + /** Issues the op's commands to GrGpu. */ + void execute(GrOpFlushState* state) { this->onExecute(state); } - /** Used for spewing information about batches when debugging. */ + /** Used for spewing information about ops when debugging. */ virtual SkString dumpInfo() const { SkString string; - string.appendf("BatchBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", + string.appendf("OpBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom); return string; } - /** Can remove this when multi-draw-buffer lands */ - virtual GrRenderTarget* renderTarget() const = 0; - protected: /** - * Indicates that the batch will produce geometry that extends beyond its bounds for the + * Indicates that the op will produce geometry that extends beyond its bounds for the * purpose of ensuring that the fragment shader runs on partially covered pixels for * non-MSAA antialiasing. */ @@ -153,8 +162,8 @@ protected: kNo }; /** - * Indicates that the geometry represented by the batch has zero area (i.e. it is hairline - * or points). + * Indicates that the geometry represented by the op has zero area (e.g. it is hairline or + * points). */ enum class IsZeroArea { kYes, @@ -170,7 +179,7 @@ protected: this->setBoundsFlags(aabloat, zeroArea); } - void joinBounds(const GrBatch& that) { + void joinBounds(const GrOp& that) { if (that.hasAABloat()) { fBoundsFlags |= kAABloat_BoundsFlag; } @@ -180,25 +189,25 @@ protected: return fBounds.joinPossiblyEmptyRect(that.fBounds); } - void replaceBounds(const GrBatch& that) { + void replaceBounds(const GrOp& that) { fBounds = that.fBounds; fBoundsFlags = that.fBoundsFlags; } - static uint32_t GenBatchClassID() { return GenID(&gCurrBatchClassID); } + static uint32_t GenOpClassID() { return GenID(&gCurrOpClassID); } private: - virtual bool onCombineIfPossible(GrBatch*, const GrCaps& caps) = 0; + virtual bool onCombineIfPossible(GrOp*, const GrCaps& caps) = 0; - virtual void onPrepare(GrBatchFlushState*) = 0; - virtual void onDraw(GrBatchFlushState*) = 0; + virtual void onPrepare(GrOpFlushState*) = 0; + virtual void onExecute(GrOpFlushState*) = 0; static uint32_t GenID(int32_t* idCounter) { // The atomic inc returns the old value not the incremented value. So we add // 1 to the returned value. uint32_t id = static_cast(sk_atomic_inc(idCounter)) + 1; if (!id) { - SkFAIL("This should never wrap as it should only be called once for each GrBatch " + SkFAIL("This should never wrap as it should only be called once for each GrOp " "subclass."); } return id; @@ -211,7 +220,7 @@ private: } enum { - kIllegalBatchID = 0, + kIllegalOpID = 0, }; enum BoundsFlags { @@ -220,16 +229,15 @@ private: SkDEBUGCODE(kUninitialized_BoundsFlag = 0x4) }; - SkDEBUGCODE(bool fUsed;) const uint16_t fClassID; uint16_t fBoundsFlags; - static uint32_t GenBatchID() { return GenID(&gCurrBatchUniqueID); } + static uint32_t GenOpID() { return GenID(&gCurrOpUniqueID); } mutable uint32_t fUniqueID; SkRect fBounds; - static int32_t gCurrBatchUniqueID; - static int32_t gCurrBatchClassID; + static int32_t gCurrOpUniqueID; + static int32_t gCurrOpClassID; }; #endif diff --git a/gfx/skia/skia/src/gpu/GrOvalRenderer.cpp b/gfx/skia/skia/src/gpu/ops/GrOvalOpFactory.cpp similarity index 56% rename from gfx/skia/skia/src/gpu/GrOvalRenderer.cpp rename to gfx/skia/skia/src/gpu/ops/GrOvalOpFactory.cpp index 68b3f11d1d4f..e00ee0b24d06 100644 --- a/gfx/skia/skia/src/gpu/GrOvalRenderer.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrOvalOpFactory.cpp @@ -5,49 +5,46 @@ * found in the LICENSE file. */ -#include "GrOvalRenderer.h" +#include "GrOvalOpFactory.h" -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" +#include "GrDrawOpTest.h" #include "GrGeometryProcessor.h" -#include "GrInvariantOutput.h" +#include "GrOpFlushState.h" #include "GrProcessor.h" #include "GrResourceProvider.h" +#include "GrShaderCaps.h" #include "GrStyle.h" #include "SkRRect.h" #include "SkStrokeRec.h" -#include "batches/GrVertexBatch.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLVarying.h" -#include "glsl/GrGLSLVertexShaderBuilder.h" #include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLUtil.h" +#include "glsl/GrGLSLVarying.h" +#include "glsl/GrGLSLVertexShaderBuilder.h" +#include "ops/GrMeshDrawOp.h" -// TODO(joshualitt) - Break this file up during GrBatch post implementation cleanup +// TODO(joshualitt) - Break this file up during GrOp post implementation cleanup namespace { struct EllipseVertex { - SkPoint fPos; - GrColor fColor; - SkPoint fOffset; - SkPoint fOuterRadii; - SkPoint fInnerRadii; + SkPoint fPos; + GrColor fColor; + SkPoint fOffset; + SkPoint fOuterRadii; + SkPoint fInnerRadii; }; struct DIEllipseVertex { - SkPoint fPos; - GrColor fColor; - SkPoint fOuterOffset; - SkPoint fInnerOffset; + SkPoint fPos; + GrColor fColor; + SkPoint fOuterOffset; + SkPoint fInnerOffset; }; -inline bool circle_stays_circle(const SkMatrix& m) { - return m.isSimilarity(); -} - +static inline bool circle_stays_circle(const SkMatrix& m) { return m.isSimilarity(); } } /////////////////////////////////////////////////////////////////////////////// @@ -71,7 +68,7 @@ inline bool circle_stays_circle(const SkMatrix& m) { * Additional clip planes are supported for rendering circular arcs. The additional planes are * either intersected or unioned together. Up to three planes are supported (an initial plane, * a plane intersected with the initial plane, and a plane unioned with the first two). Only two - * are useful for any given arc, but having all three in one instance allows batching different + * are useful for any given arc, but having all three in one instance allows combining different * types of arcs. */ @@ -84,7 +81,8 @@ public: fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision); fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); - fInCircleEdge = &this->addVertexAttrib("inCircleEdge", kVec4f_GrVertexAttribType); + fInCircleEdge = &this->addVertexAttrib("inCircleEdge", kVec4f_GrVertexAttribType, + kHigh_GrSLPrecision); if (clipPlane) { fInClipPlane = &this->addVertexAttrib("inClipPlane", kVec3f_GrVertexAttribType); } else { @@ -105,15 +103,15 @@ public: bool implementsDistanceVector() const override { return !fInClipPlane; } - virtual ~CircleGeometryProcessor() {} + ~CircleGeometryProcessor() override {} const char* name() const override { return "CircleEdge"; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLProcessor::GenKey(*this, caps, b); } - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { return new GLSLProcessor(); } @@ -122,7 +120,7 @@ private: public: GLSLProcessor() {} - void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ + void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const CircleGeometryProcessor& cgp = args.fGP.cast(); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; @@ -131,8 +129,9 @@ private: // emit attributes varyingHandler->emitAttributes(cgp); - fragBuilder->codeAppend("vec4 circleEdge;"); - varyingHandler->addPassThroughAttribute(cgp.fInCircleEdge, "circleEdge"); + fragBuilder->codeAppend("highp vec4 circleEdge;"); + varyingHandler->addPassThroughAttribute(cgp.fInCircleEdge, "circleEdge", + kHigh_GrSLPrecision); if (cgp.fInClipPlane) { fragBuilder->codeAppend("vec3 clipPlane;"); varyingHandler->addPassThroughAttribute(cgp.fInClipPlane, "clipPlane"); @@ -163,33 +162,44 @@ private: cgp.fLocalMatrix, args.fFPCoordTransformHandler); - fragBuilder->codeAppend("float d = length(circleEdge.xy);"); + fragBuilder->codeAppend("highp float d = length(circleEdge.xy);"); fragBuilder->codeAppend("float distanceToOuterEdge = circleEdge.z * (1.0 - d);"); fragBuilder->codeAppend("float edgeAlpha = clamp(distanceToOuterEdge, 0.0, 1.0);"); if (cgp.fStroke) { - fragBuilder->codeAppend("float distanceToInnerEdge = circleEdge.z * (d - circleEdge.w);"); + fragBuilder->codeAppend( + "float distanceToInnerEdge = circleEdge.z * (d - circleEdge.w);"); fragBuilder->codeAppend("float innerAlpha = clamp(distanceToInnerEdge, 0.0, 1.0);"); fragBuilder->codeAppend("edgeAlpha *= innerAlpha;"); } if (args.fDistanceVectorName) { const char* innerEdgeDistance = cgp.fStroke ? "distanceToInnerEdge" : "0.0"; - fragBuilder->codeAppend ("if (d == 0.0) {"); // if on the center of the circle - fragBuilder->codeAppendf(" %s = vec4(1.0, 0.0, distanceToOuterEdge, " - "%s);", // no normalize - args.fDistanceVectorName, innerEdgeDistance); - fragBuilder->codeAppend ("} else {"); - fragBuilder->codeAppendf(" %s = vec4(normalize(circleEdge.xy), distanceToOuterEdge, %s);", - args.fDistanceVectorName, innerEdgeDistance); - fragBuilder->codeAppend ("}"); + fragBuilder->codeAppendf( + "if (d == 0.0) {" // if on the center of the circle + " %s = vec4(1.0, 0.0, distanceToOuterEdge, " + " %s);", // no normalize + args.fDistanceVectorName, + innerEdgeDistance); + fragBuilder->codeAppendf( + "} else {" + " %s = vec4(normalize(circleEdge.xy)," + " distanceToOuterEdge, %s);" + "}", + args.fDistanceVectorName, innerEdgeDistance); } if (cgp.fInClipPlane) { - fragBuilder->codeAppend("float clip = clamp(circleEdge.z * dot(circleEdge.xy, clipPlane.xy) + clipPlane.z, 0.0, 1.0);"); + fragBuilder->codeAppend( + "float clip = clamp(circleEdge.z * dot(circleEdge.xy, clipPlane.xy) + " + "clipPlane.z, 0.0, 1.0);"); if (cgp.fInIsectPlane) { - fragBuilder->codeAppend("clip *= clamp(circleEdge.z * dot(circleEdge.xy, isectPlane.xy) + isectPlane.z, 0.0, 1.0);"); + fragBuilder->codeAppend( + "clip *= clamp(circleEdge.z * dot(circleEdge.xy, isectPlane.xy) + " + "isectPlane.z, 0.0, 1.0);"); } if (cgp.fInUnionPlane) { - fragBuilder->codeAppend("clip += (1.0 - clip)*clamp(circleEdge.z * dot(circleEdge.xy, unionPlane.xy) + unionPlane.z, 0.0, 1.0);"); + fragBuilder->codeAppend( + "clip += (1.0 - clip)*clamp(circleEdge.z * dot(circleEdge.xy, " + "unionPlane.xy) + unionPlane.z, 0.0, 1.0);"); } fragBuilder->codeAppend("edgeAlpha *= clip;"); } @@ -197,15 +207,15 @@ private: } static void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const CircleGeometryProcessor& cgp = gp.cast(); uint16_t key; - key = cgp.fStroke ? 0x01 : 0x0; + key = cgp.fStroke ? 0x01 : 0x0; key |= cgp.fLocalMatrix.hasPerspective() ? 0x02 : 0x0; - key |= cgp.fInClipPlane ? 0x04 : 0x0; - key |= cgp.fInIsectPlane ? 0x08 : 0x0; - key |= cgp.fInUnionPlane ? 0x10 : 0x0; + key |= cgp.fInClipPlane ? 0x04 : 0x0; + key |= cgp.fInIsectPlane ? 0x08 : 0x0; + key |= cgp.fInUnionPlane ? 0x10 : 0x0; b->add32(key); } @@ -219,14 +229,14 @@ private: typedef GrGLSLGeometryProcessor INHERITED; }; - SkMatrix fLocalMatrix; + SkMatrix fLocalMatrix; const Attribute* fInPosition; const Attribute* fInColor; const Attribute* fInCircleEdge; const Attribute* fInClipPlane; const Attribute* fInIsectPlane; const Attribute* fInUnionPlane; - bool fStroke; + bool fStroke; GR_DECLARE_GEOMETRY_PROCESSOR_TEST; @@ -235,12 +245,13 @@ private: GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleGeometryProcessor); +#if GR_TEST_UTILS sk_sp CircleGeometryProcessor::TestCreate(GrProcessorTestData* d) { - return sk_sp( - new CircleGeometryProcessor(d->fRandom->nextBool(), d->fRandom->nextBool(), - d->fRandom->nextBool(), d->fRandom->nextBool(), - GrTest::TestMatrix(d->fRandom))); + return sk_sp(new CircleGeometryProcessor( + d->fRandom->nextBool(), d->fRandom->nextBool(), d->fRandom->nextBool(), + d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom))); } +#endif /////////////////////////////////////////////////////////////////////////////// @@ -254,8 +265,7 @@ sk_sp CircleGeometryProcessor::TestCreate(GrProcessorTestDa class EllipseGeometryProcessor : public GrGeometryProcessor { public: - EllipseGeometryProcessor(bool stroke, const SkMatrix& localMatrix) - : fLocalMatrix(localMatrix) { + EllipseGeometryProcessor(bool stroke, const SkMatrix& localMatrix) : fLocalMatrix(localMatrix) { this->initClassID(); fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType); fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); @@ -264,15 +274,15 @@ public: fStroke = stroke; } - virtual ~EllipseGeometryProcessor() {} + ~EllipseGeometryProcessor() override {} const char* name() const override { return "EllipseEdge"; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLProcessor::GenKey(*this, caps, b); } - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { return new GLSLProcessor(); } @@ -281,7 +291,7 @@ private: public: GLSLProcessor() {} - void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ + void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const EllipseGeometryProcessor& egp = args.fGP.cast(); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; @@ -297,8 +307,7 @@ private: GrGLSLVertToFrag ellipseRadii(kVec4f_GrSLType); varyingHandler->addVarying("EllipseRadii", &ellipseRadii); - vertBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(), - egp.fInEllipseRadii->fName); + vertBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(), egp.fInEllipseRadii->fName); GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // setup pass through color @@ -330,11 +339,10 @@ private: // for inner curve if (egp.fStroke) { - fragBuilder->codeAppendf("scaledOffset = %s*%s.zw;", - ellipseOffsets.fsIn(), ellipseRadii.fsIn()); - fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;"); - fragBuilder->codeAppendf("grad = 2.0*scaledOffset*%s.zw;", + fragBuilder->codeAppendf("scaledOffset = %s*%s.zw;", ellipseOffsets.fsIn(), ellipseRadii.fsIn()); + fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;"); + fragBuilder->codeAppendf("grad = 2.0*scaledOffset*%s.zw;", ellipseRadii.fsIn()); fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));"); fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);"); } @@ -343,7 +351,7 @@ private: } static void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const EllipseGeometryProcessor& egp = gp.cast(); uint16_t key = egp.fStroke ? 0x1 : 0x0; @@ -375,10 +383,12 @@ private: GR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseGeometryProcessor); +#if GR_TEST_UTILS sk_sp EllipseGeometryProcessor::TestCreate(GrProcessorTestData* d) { return sk_sp( - new EllipseGeometryProcessor(d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom))); + new EllipseGeometryProcessor(d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom))); } +#endif /////////////////////////////////////////////////////////////////////////////// @@ -396,7 +406,7 @@ enum class DIEllipseStyle { kStroke = 0, kHairline, kFill }; class DIEllipseGeometryProcessor : public GrGeometryProcessor { public: DIEllipseGeometryProcessor(const SkMatrix& viewMatrix, DIEllipseStyle style) - : fViewMatrix(viewMatrix) { + : fViewMatrix(viewMatrix) { this->initClassID(); fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision); @@ -406,24 +416,22 @@ public: fStyle = style; } - - virtual ~DIEllipseGeometryProcessor() {} + ~DIEllipseGeometryProcessor() override {} const char* name() const override { return "DIEllipseEdge"; } - void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { GLSLProcessor::GenKey(*this, caps, b); } - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { return new GLSLProcessor(); } private: class GLSLProcessor : public GrGLSLGeometryProcessor { public: - GLSLProcessor() - : fViewMatrix(SkMatrix::InvalidMatrix()) {} + GLSLProcessor() : fViewMatrix(SkMatrix::InvalidMatrix()) {} void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const DIEllipseGeometryProcessor& diegp = args.fGP.cast(); @@ -436,13 +444,11 @@ private: GrGLSLVertToFrag offsets0(kVec2f_GrSLType); varyingHandler->addVarying("EllipseOffsets0", &offsets0); - vertBuilder->codeAppendf("%s = %s;", offsets0.vsOut(), - diegp.fInEllipseOffsets0->fName); + vertBuilder->codeAppendf("%s = %s;", offsets0.vsOut(), diegp.fInEllipseOffsets0->fName); GrGLSLVertToFrag offsets1(kVec2f_GrSLType); varyingHandler->addVarying("EllipseOffsets1", &offsets1); - vertBuilder->codeAppendf("%s = %s;", offsets1.vsOut(), - diegp.fInEllipseOffsets1->fName); + vertBuilder->codeAppendf("%s = %s;", offsets1.vsOut(), diegp.fInEllipseOffsets1->fName); GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; varyingHandler->addPassThroughAttribute(diegp.fInColor, args.fOutputColor); @@ -463,17 +469,15 @@ private: diegp.fInPosition->fName, args.fFPCoordTransformHandler); - SkAssertResult(fragBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); // for outer curve fragBuilder->codeAppendf("vec2 scaledOffset = %s.xy;", offsets0.fsIn()); fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;"); fragBuilder->codeAppendf("vec2 duvdx = dFdx(%s);", offsets0.fsIn()); fragBuilder->codeAppendf("vec2 duvdy = dFdy(%s);", offsets0.fsIn()); - fragBuilder->codeAppendf("vec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y," - " 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);", - offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn(), - offsets0.fsIn()); + fragBuilder->codeAppendf( + "vec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y," + " 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);", + offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn()); fragBuilder->codeAppend("float grad_dot = dot(grad, grad);"); // avoid calling inversesqrt on zero. @@ -493,10 +497,10 @@ private: fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;"); fragBuilder->codeAppendf("duvdx = dFdx(%s);", offsets1.fsIn()); fragBuilder->codeAppendf("duvdy = dFdy(%s);", offsets1.fsIn()); - fragBuilder->codeAppendf("grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y," - " 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);", - offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn(), - offsets1.fsIn()); + fragBuilder->codeAppendf( + "grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y," + " 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);", + offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn()); fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));"); fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);"); } @@ -505,7 +509,7 @@ private: } static void GenKey(const GrGeometryProcessor& gp, - const GrGLSLCaps&, + const GrShaderCaps&, GrProcessorKeyBuilder* b) { const DIEllipseGeometryProcessor& diegp = gp.cast(); uint16_t key = static_cast(diegp.fStyle); @@ -537,8 +541,8 @@ private: const Attribute* fInColor; const Attribute* fInEllipseOffsets0; const Attribute* fInEllipseOffsets1; - SkMatrix fViewMatrix; - DIEllipseStyle fStyle; + SkMatrix fViewMatrix; + DIEllipseStyle fStyle; GR_DECLARE_GEOMETRY_PROCESSOR_TEST; @@ -547,17 +551,66 @@ private: GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseGeometryProcessor); +#if GR_TEST_UTILS sk_sp DIEllipseGeometryProcessor::TestCreate(GrProcessorTestData* d) { - return sk_sp( - new DIEllipseGeometryProcessor(GrTest::TestMatrix(d->fRandom), - (DIEllipseStyle)(d->fRandom->nextRangeU(0,2)))); + return sk_sp(new DIEllipseGeometryProcessor( + GrTest::TestMatrix(d->fRandom), (DIEllipseStyle)(d->fRandom->nextRangeU(0, 2)))); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// We have two possible cases for geometry for a circle: + +// In the case of a normal fill, we draw geometry for the circle as an octagon. +static const uint16_t gFillCircleIndices[] = { + // enter the octagon + // clang-format off + 0, 1, 8, 1, 2, 8, + 2, 3, 8, 3, 4, 8, + 4, 5, 8, 5, 6, 8, + 6, 7, 8, 7, 0, 8 + // clang-format on +}; + +// For stroked circles, we use two nested octagons. +static const uint16_t gStrokeCircleIndices[] = { + // enter the octagon + // clang-format off + 0, 1, 9, 0, 9, 8, + 1, 2, 10, 1, 10, 9, + 2, 3, 11, 2, 11, 10, + 3, 4, 12, 3, 12, 11, + 4, 5, 13, 4, 13, 12, + 5, 6, 14, 5, 14, 13, + 6, 7, 15, 6, 15, 14, + 7, 0, 8, 7, 8, 15, + // clang-format on +}; + + +static const int kIndicesPerFillCircle = SK_ARRAY_COUNT(gFillCircleIndices); +static const int kIndicesPerStrokeCircle = SK_ARRAY_COUNT(gStrokeCircleIndices); +static const int kVertsPerStrokeCircle = 16; +static const int kVertsPerFillCircle = 9; + +static int circle_type_to_vert_count(bool stroked) { + return stroked ? kVertsPerStrokeCircle : kVertsPerFillCircle; +} + +static int circle_type_to_index_count(bool stroked) { + return stroked ? kIndicesPerStrokeCircle : kIndicesPerFillCircle; +} + +static const uint16_t* circle_type_to_indices(bool stroked) { + return stroked ? gStrokeCircleIndices : gFillCircleIndices; } /////////////////////////////////////////////////////////////////////////////// -class CircleBatch : public GrVertexBatch { +class CircleOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID /** Optional extra params to render a partial arc rather than a full circle. */ struct ArcParams { @@ -565,9 +618,10 @@ public: SkScalar fSweepAngleRadians; bool fUseCenter; }; - static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, SkPoint center, - SkScalar radius, const GrStyle& style, - const ArcParams* arcParams = nullptr) { + static std::unique_ptr Make(GrColor color, const SkMatrix& viewMatrix, + SkPoint center, SkScalar radius, + const GrStyle& style, + const ArcParams* arcParams = nullptr) { SkASSERT(circle_stays_circle(viewMatrix)); const SkStrokeRec& stroke = style.strokeRec(); if (style.hasPathEffect()) { @@ -578,12 +632,12 @@ public: // Arc support depends on the style. switch (recStyle) { case SkStrokeRec::kStrokeAndFill_Style: - // This produces a strange result that this batch doesn't implement. + // This produces a strange result that this op doesn't implement. return nullptr; case SkStrokeRec::kFill_Style: // This supports all fills. break; - case SkStrokeRec::kStroke_Style: // fall through + case SkStrokeRec::kStroke_Style: // fall through case SkStrokeRec::kHairline_Style: // Strokes that don't use the center point are supported with butt cap. if (arcParams->fUseCenter || stroke.getCap() != SkPaint::kButt_Cap) { @@ -597,11 +651,11 @@ public: radius = viewMatrix.mapRadius(radius); SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth()); - bool isStrokeOnly = SkStrokeRec::kStroke_Style == recStyle || - SkStrokeRec::kHairline_Style == recStyle; + bool isStrokeOnly = + SkStrokeRec::kStroke_Style == recStyle || SkStrokeRec::kHairline_Style == recStyle; bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == recStyle; - SkScalar innerRadius = 0.0f; + SkScalar innerRadius = -SK_ScalarHalf; SkScalar outerRadius = radius; SkScalar halfWidth = 0; if (hasStroke) { @@ -623,8 +677,9 @@ public: // rendered and the outset ensures the box will cover all partially covered by the circle. outerRadius += SK_ScalarHalf; innerRadius -= SK_ScalarHalf; - CircleBatch* batch = new CircleBatch(); - batch->fViewMatrixIfUsingLocalCoords = viewMatrix; + bool stroked = isStrokeOnly && innerRadius > 0.0f; + std::unique_ptr op(new CircleOp()); + op->fViewMatrixIfUsingLocalCoords = viewMatrix; // This makes every point fully inside the intersection plane. static constexpr SkScalar kUnusedIsectPlane[] = {0.f, 0.f, 1.f}; @@ -632,7 +687,6 @@ public: static constexpr SkScalar kUnusedUnionPlane[] = {0.f, 0.f, 0.f}; SkRect devBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius, center.fX + outerRadius, center.fY + outerRadius); - if (arcParams) { // The shader operates in a space where the circle is translated to be centered at the // origin. Here we compute points on the unit circle at the starting and ending angles. @@ -645,9 +699,9 @@ public: // case. In that case the two radial lines are equal and so that edge gets clipped // twice. Since the shared edge goes through the center we fall back on the useCenter // case. - bool useCenter = (arcParams->fUseCenter || isStrokeOnly) && - !SkScalarNearlyEqual(SkScalarAbs(arcParams->fSweepAngleRadians), - SK_ScalarPI); + bool useCenter = + (arcParams->fUseCenter || isStrokeOnly) && + !SkScalarNearlyEqual(SkScalarAbs(arcParams->fSweepAngleRadians), SK_ScalarPI); if (useCenter) { SkVector norm0 = {startPoint.fY, -startPoint.fX}; SkVector norm1 = {stopPoint.fY, -stopPoint.fX}; @@ -656,31 +710,31 @@ public: } else { norm1.negate(); } - batch->fClipPlane = true; + op->fClipPlane = true; if (SkScalarAbs(arcParams->fSweepAngleRadians) > SK_ScalarPI) { - batch->fGeoData.emplace_back(Geometry { + op->fGeoData.emplace_back(Geometry{ color, innerRadius, outerRadius, {norm0.fX, norm0.fY, 0.5f}, {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]}, {norm1.fX, norm1.fY, 0.5f}, - devBounds - }); - batch->fClipPlaneIsect = false; - batch->fClipPlaneUnion = true; + devBounds, + stroked}); + op->fClipPlaneIsect = false; + op->fClipPlaneUnion = true; } else { - batch->fGeoData.emplace_back(Geometry { + op->fGeoData.emplace_back(Geometry{ color, innerRadius, outerRadius, {norm0.fX, norm0.fY, 0.5f}, {norm1.fX, norm1.fY, 0.5f}, {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnusedUnionPlane[2]}, - devBounds - }); - batch->fClipPlaneIsect = true; - batch->fClipPlaneUnion = false; + devBounds, + stroked}); + op->fClipPlaneIsect = true; + op->fClipPlaneUnion = false; } } else { // We clip to a secant of the original circle. @@ -693,74 +747,74 @@ public: } SkScalar d = -norm.dot(startPoint) + 0.5f; - batch->fGeoData.emplace_back(Geometry { - color, - innerRadius, - outerRadius, - {norm.fX, norm.fY, d}, - {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]}, - {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnusedUnionPlane[2]}, - devBounds - }); - batch->fClipPlane = true; - batch->fClipPlaneIsect = false; - batch->fClipPlaneUnion = false; + op->fGeoData.emplace_back( + Geometry{color, + innerRadius, + outerRadius, + {norm.fX, norm.fY, d}, + {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]}, + {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnusedUnionPlane[2]}, + devBounds, + stroked}); + op->fClipPlane = true; + op->fClipPlaneIsect = false; + op->fClipPlaneUnion = false; } } else { - batch->fGeoData.emplace_back(Geometry { - color, - innerRadius, - outerRadius, - {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]}, - {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]}, - {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnusedUnionPlane[2]}, - devBounds - }); - batch->fClipPlane = false; - batch->fClipPlaneIsect = false; - batch->fClipPlaneUnion = false; + op->fGeoData.emplace_back( + Geometry{color, + innerRadius, + outerRadius, + {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]}, + {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]}, + {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnusedUnionPlane[2]}, + devBounds, + stroked}); + op->fClipPlane = false; + op->fClipPlaneIsect = false; + op->fClipPlaneUnion = false; } // Use the original radius and stroke radius for the bounds so that it does not include the // AA bloat. radius += halfWidth; - batch->setBounds({center.fX - radius, center.fY - radius, - center.fX + radius, center.fY + radius}, - HasAABloat::kYes, IsZeroArea::kNo); - batch->fStroked = isStrokeOnly && innerRadius > 0; - return batch; + op->setBounds( + {center.fX - radius, center.fY - radius, center.fX + radius, center.fY + radius}, + HasAABloat::kYes, IsZeroArea::kNo); + op->fVertCount = circle_type_to_vert_count(stroked); + op->fIndexCount = circle_type_to_index_count(stroked); + op->fAllFill = !stroked; + return std::move(op); } - const char* name() const override { return "CircleBatch"; } + const char* name() const override { return "CircleOp"; } SkString dumpInfo() const override { SkString string; for (int i = 0; i < fGeoData.count(); ++i) { - string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]," - "InnerRad: %.2f, OuterRad: %.2f\n", - fGeoData[i].fColor, - fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop, - fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom, - fGeoData[i].fInnerRadius, - fGeoData[i].fOuterRadius); + string.appendf( + "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]," + "InnerRad: %.2f, OuterRad: %.2f\n", + fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop, + fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom, + fGeoData[i].fInnerRadius, fGeoData[i].fOuterRadius); } + string.append(DumpPipelineInfo(*this->pipeline())); string.append(INHERITED::dumpInfo()); return string; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); +private: + CircleOp() : INHERITED(ClassID()) {} + + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fGeoData[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; } -private: - CircleBatch() : INHERITED(ClassID()) {} - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any overrides that affect our GP. - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); - if (!overrides.readsLocalCoords()) { + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fGeoData[0].fColor); + if (!optimizations.readsLocalCoords()) { fViewMatrixIfUsingLocalCoords.reset(); } } @@ -772,15 +826,13 @@ private: } // Setup geometry processor - SkAutoTUnref gp(new CircleGeometryProcessor(fStroked, fClipPlane, - fClipPlaneIsect, - fClipPlaneUnion, - localMatrix)); + sk_sp gp(new CircleGeometryProcessor( + !fAllFill, fClipPlane, fClipPlaneIsect, fClipPlaneUnion, localMatrix)); struct CircleVertex { - SkPoint fPos; - GrColor fColor; - SkPoint fOffset; + SkPoint fPos; + GrColor fColor; + SkPoint fOffset; SkScalar fOuterRadius; SkScalar fInnerRadius; // These planes may or may not be present in the vertex buffer. @@ -789,15 +841,29 @@ private: int instanceCount = fGeoData.count(); size_t vertexStride = gp->getVertexStride(); - SkASSERT(vertexStride == sizeof(CircleVertex) - (fClipPlane ? 0 : 3 * sizeof(SkScalar)) - - (fClipPlaneIsect? 0 : 3 * sizeof(SkScalar)) - - (fClipPlaneUnion? 0 : 3 * sizeof(SkScalar))); - QuadHelper helper; - char* vertices = reinterpret_cast(helper.init(target, vertexStride, instanceCount)); + SkASSERT(vertexStride == + sizeof(CircleVertex) - (fClipPlane ? 0 : 3 * sizeof(SkScalar)) - + (fClipPlaneIsect ? 0 : 3 * sizeof(SkScalar)) - + (fClipPlaneUnion ? 0 : 3 * sizeof(SkScalar))); + + const GrBuffer* vertexBuffer; + int firstVertex; + char* vertices = (char*)target->makeVertexSpace(vertexStride, fVertCount, &vertexBuffer, + &firstVertex); if (!vertices) { + SkDebugf("Could not allocate vertices\n"); return; } + const GrBuffer* indexBuffer = nullptr; + int firstIndex = 0; + uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex); + if (!indices) { + SkDebugf("Could not allocate indices\n"); + return; + } + + int currStartVertex = 0; for (int i = 0; i < instanceCount; i++) { const Geometry& geom = fGeoData[i]; @@ -806,42 +872,79 @@ private: SkScalar outerRadius = geom.fOuterRadius; const SkRect& bounds = geom.fDevBounds; - CircleVertex* v0 = reinterpret_cast(vertices + (4 * i + 0)*vertexStride); - CircleVertex* v1 = reinterpret_cast(vertices + (4 * i + 1)*vertexStride); - CircleVertex* v2 = reinterpret_cast(vertices + (4 * i + 2)*vertexStride); - CircleVertex* v3 = reinterpret_cast(vertices + (4 * i + 3)*vertexStride); + CircleVertex* v0 = reinterpret_cast(vertices + 0 * vertexStride); + CircleVertex* v1 = reinterpret_cast(vertices + 1 * vertexStride); + CircleVertex* v2 = reinterpret_cast(vertices + 2 * vertexStride); + CircleVertex* v3 = reinterpret_cast(vertices + 3 * vertexStride); + CircleVertex* v4 = reinterpret_cast(vertices + 4 * vertexStride); + CircleVertex* v5 = reinterpret_cast(vertices + 5 * vertexStride); + CircleVertex* v6 = reinterpret_cast(vertices + 6 * vertexStride); + CircleVertex* v7 = reinterpret_cast(vertices + 7 * vertexStride); // The inner radius in the vertex data must be specified in normalized space. innerRadius = innerRadius / outerRadius; - v0->fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); + + SkPoint center = SkPoint::Make(bounds.centerX(), bounds.centerY()); + SkScalar halfWidth = 0.5f * bounds.width(); + SkScalar octOffset = 0.41421356237f; // sqrt(2) - 1 + + v0->fPos = center + SkPoint::Make(-octOffset * halfWidth, -halfWidth); v0->fColor = color; - v0->fOffset = SkPoint::Make(-1, -1); + v0->fOffset = SkPoint::Make(-octOffset, -1); v0->fOuterRadius = outerRadius; v0->fInnerRadius = innerRadius; - v1->fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); + v1->fPos = center + SkPoint::Make(octOffset * halfWidth, -halfWidth); v1->fColor = color; - v1->fOffset = SkPoint::Make(-1, 1); + v1->fOffset = SkPoint::Make(octOffset, -1); v1->fOuterRadius = outerRadius; v1->fInnerRadius = innerRadius; - v2->fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); + v2->fPos = center + SkPoint::Make(halfWidth, -octOffset * halfWidth); v2->fColor = color; - v2->fOffset = SkPoint::Make(1, 1); + v2->fOffset = SkPoint::Make(1, -octOffset); v2->fOuterRadius = outerRadius; v2->fInnerRadius = innerRadius; - v3->fPos = SkPoint::Make(bounds.fRight, bounds.fTop); + v3->fPos = center + SkPoint::Make(halfWidth, octOffset * halfWidth); v3->fColor = color; - v3->fOffset = SkPoint::Make(1, -1); + v3->fOffset = SkPoint::Make(1, octOffset); v3->fOuterRadius = outerRadius; v3->fInnerRadius = innerRadius; + v4->fPos = center + SkPoint::Make(octOffset * halfWidth, halfWidth); + v4->fColor = color; + v4->fOffset = SkPoint::Make(octOffset, 1); + v4->fOuterRadius = outerRadius; + v4->fInnerRadius = innerRadius; + + v5->fPos = center + SkPoint::Make(-octOffset * halfWidth, halfWidth); + v5->fColor = color; + v5->fOffset = SkPoint::Make(-octOffset, 1); + v5->fOuterRadius = outerRadius; + v5->fInnerRadius = innerRadius; + + v6->fPos = center + SkPoint::Make(-halfWidth, octOffset * halfWidth); + v6->fColor = color; + v6->fOffset = SkPoint::Make(-1, octOffset); + v6->fOuterRadius = outerRadius; + v6->fInnerRadius = innerRadius; + + v7->fPos = center + SkPoint::Make(-halfWidth, -octOffset * halfWidth); + v7->fColor = color; + v7->fOffset = SkPoint::Make(-1, -octOffset); + v7->fOuterRadius = outerRadius; + v7->fInnerRadius = innerRadius; + if (fClipPlane) { memcpy(v0->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); memcpy(v1->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); memcpy(v2->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); memcpy(v3->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v4->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v5->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v6->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v7->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); } int unionIdx = 1; if (fClipPlaneIsect) { @@ -849,6 +952,10 @@ private: memcpy(v1->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); memcpy(v2->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); memcpy(v3->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v4->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v5->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v6->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v7->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); unionIdx = 2; } if (fClipPlaneUnion) { @@ -856,64 +963,207 @@ private: memcpy(v1->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); memcpy(v2->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); memcpy(v3->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v4->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v5->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v6->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v7->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); } + + if (geom.fStroked) { + // compute the inner ring + CircleVertex* v0 = reinterpret_cast(vertices + 8 * vertexStride); + CircleVertex* v1 = reinterpret_cast(vertices + 9 * vertexStride); + CircleVertex* v2 = reinterpret_cast(vertices + 10 * vertexStride); + CircleVertex* v3 = reinterpret_cast(vertices + 11 * vertexStride); + CircleVertex* v4 = reinterpret_cast(vertices + 12 * vertexStride); + CircleVertex* v5 = reinterpret_cast(vertices + 13 * vertexStride); + CircleVertex* v6 = reinterpret_cast(vertices + 14 * vertexStride); + CircleVertex* v7 = reinterpret_cast(vertices + 15 * vertexStride); + + // cosine and sine of pi/8 + SkScalar c = 0.923579533f; + SkScalar s = 0.382683432f; + SkScalar r = geom.fInnerRadius; + + v0->fPos = center + SkPoint::Make(-s * r, -c * r); + v0->fColor = color; + v0->fOffset = SkPoint::Make(-s * innerRadius, -c * innerRadius); + v0->fOuterRadius = outerRadius; + v0->fInnerRadius = innerRadius; + + v1->fPos = center + SkPoint::Make(s * r, -c * r); + v1->fColor = color; + v1->fOffset = SkPoint::Make(s * innerRadius, -c * innerRadius); + v1->fOuterRadius = outerRadius; + v1->fInnerRadius = innerRadius; + + v2->fPos = center + SkPoint::Make(c * r, -s * r); + v2->fColor = color; + v2->fOffset = SkPoint::Make(c * innerRadius, -s * innerRadius); + v2->fOuterRadius = outerRadius; + v2->fInnerRadius = innerRadius; + + v3->fPos = center + SkPoint::Make(c * r, s * r); + v3->fColor = color; + v3->fOffset = SkPoint::Make(c * innerRadius, s * innerRadius); + v3->fOuterRadius = outerRadius; + v3->fInnerRadius = innerRadius; + + v4->fPos = center + SkPoint::Make(s * r, c * r); + v4->fColor = color; + v4->fOffset = SkPoint::Make(s * innerRadius, c * innerRadius); + v4->fOuterRadius = outerRadius; + v4->fInnerRadius = innerRadius; + + v5->fPos = center + SkPoint::Make(-s * r, c * r); + v5->fColor = color; + v5->fOffset = SkPoint::Make(-s * innerRadius, c * innerRadius); + v5->fOuterRadius = outerRadius; + v5->fInnerRadius = innerRadius; + + v6->fPos = center + SkPoint::Make(-c * r, s * r); + v6->fColor = color; + v6->fOffset = SkPoint::Make(-c * innerRadius, s * innerRadius); + v6->fOuterRadius = outerRadius; + v6->fInnerRadius = innerRadius; + + v7->fPos = center + SkPoint::Make(-c * r, -s * r); + v7->fColor = color; + v7->fOffset = SkPoint::Make(-c * innerRadius, -s * innerRadius); + v7->fOuterRadius = outerRadius; + v7->fInnerRadius = innerRadius; + + if (fClipPlane) { + memcpy(v0->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v1->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v2->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v3->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v4->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v5->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v6->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + memcpy(v7->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + } + int unionIdx = 1; + if (fClipPlaneIsect) { + memcpy(v0->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v1->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v2->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v3->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v4->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v5->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v6->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + memcpy(v7->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + unionIdx = 2; + } + if (fClipPlaneUnion) { + memcpy(v0->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v1->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v2->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v3->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v4->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v5->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v6->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + memcpy(v7->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + } + } else { + // filled + CircleVertex* v8 = reinterpret_cast(vertices + 8 * vertexStride); + v8->fPos = center; + v8->fColor = color; + v8->fOffset = SkPoint::Make(0, 0); + v8->fOuterRadius = outerRadius; + v8->fInnerRadius = innerRadius; + if (fClipPlane) { + memcpy(v8->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)); + } + int unionIdx = 1; + if (fClipPlaneIsect) { + memcpy(v8->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar)); + unionIdx = 2; + } + if (fClipPlaneUnion) { + memcpy(v8->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar)); + } + } + + const uint16_t* primIndices = circle_type_to_indices(geom.fStroked); + const int primIndexCount = circle_type_to_index_count(geom.fStroked); + for (int i = 0; i < primIndexCount; ++i) { + *indices++ = primIndices[i] + currStartVertex; + } + + currStartVertex += circle_type_to_vert_count(geom.fStroked); + vertices += circle_type_to_vert_count(geom.fStroked) * vertexStride; } - helper.recordDraw(target, gp); + + GrMesh mesh; + mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex, + firstIndex, fVertCount, fIndexCount); + target->draw(gp.get(), this->pipeline(), mesh); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - CircleBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + CircleOp* that = t->cast(); + + // can only represent 65535 unique vertices with 16-bit indices + if (fVertCount + that->fVertCount > 65536) { + return false; + } + if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; } - if (this->fStroked != that->fStroked) { - return false; - } - - // Because we've set up the batches that don't use the planes with noop values - // we can just accumulate used planes by later batches. - fClipPlane |= that->fClipPlane; - fClipPlaneIsect |= that->fClipPlaneIsect; - fClipPlaneUnion |= that->fClipPlaneUnion; - if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) { return false; } + // Because we've set up the ops that don't use the planes with noop values + // we can just accumulate used planes by later ops. + fClipPlane |= that->fClipPlane; + fClipPlaneIsect |= that->fClipPlaneIsect; + fClipPlaneUnion |= that->fClipPlaneUnion; + fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); this->joinBounds(*that); + fVertCount += that->fVertCount; + fIndexCount += that->fIndexCount; + fAllFill = fAllFill && that->fAllFill; return true; } struct Geometry { - GrColor fColor; + GrColor fColor; SkScalar fInnerRadius; SkScalar fOuterRadius; SkScalar fClipPlane[3]; SkScalar fIsectPlane[3]; SkScalar fUnionPlane[3]; - SkRect fDevBounds; + SkRect fDevBounds; + bool fStroked; }; - bool fStroked; - bool fClipPlane; - bool fClipPlaneIsect; - bool fClipPlaneUnion; - SkMatrix fViewMatrixIfUsingLocalCoords; SkSTArray<1, Geometry, true> fGeoData; + SkMatrix fViewMatrixIfUsingLocalCoords; + int fVertCount; + int fIndexCount; + bool fAllFill; + bool fClipPlane; + bool fClipPlaneIsect; + bool fClipPlaneUnion; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; /////////////////////////////////////////////////////////////////////////////// -class EllipseBatch : public GrVertexBatch { +class EllipseOp : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID - static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& ellipse, - const SkStrokeRec& stroke) { + DEFINE_OP_CLASS_ID + static std::unique_ptr Make(GrColor color, const SkMatrix& viewMatrix, + const SkRect& ellipse, + const SkStrokeRec& stroke) { SkASSERT(viewMatrix.rectStaysRect()); // do any matrix crunching before we reset the draw state for device coords @@ -921,22 +1171,22 @@ public: viewMatrix.mapPoints(¢er, 1); SkScalar ellipseXRadius = SkScalarHalf(ellipse.width()); SkScalar ellipseYRadius = SkScalarHalf(ellipse.height()); - SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRadius + - viewMatrix[SkMatrix::kMSkewY]*ellipseYRadius); - SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRadius + - viewMatrix[SkMatrix::kMScaleY]*ellipseYRadius); + SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX] * ellipseXRadius + + viewMatrix[SkMatrix::kMSkewY] * ellipseYRadius); + SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX] * ellipseXRadius + + viewMatrix[SkMatrix::kMScaleY] * ellipseYRadius); // do (potentially) anisotropic mapping of stroke SkVector scaledStroke; SkScalar strokeWidth = stroke.getWidth(); - scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] + - viewMatrix[SkMatrix::kMSkewY])); - scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] + - viewMatrix[SkMatrix::kMScaleY])); + scaledStroke.fX = SkScalarAbs( + strokeWidth * (viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewY])); + scaledStroke.fY = SkScalarAbs( + strokeWidth * (viewMatrix[SkMatrix::kMSkewX] + viewMatrix[SkMatrix::kMScaleY])); SkStrokeRec::Style style = stroke.getStyle(); - bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || - SkStrokeRec::kHairline_Style == style; + bool isStrokeOnly = + SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style; bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; SkScalar innerXRadius = 0; @@ -950,13 +1200,15 @@ public: // we only handle thick strokes for near-circular ellipses if (scaledStroke.length() > SK_ScalarHalf && - (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) { + (SK_ScalarHalf * xRadius > yRadius || SK_ScalarHalf * yRadius > xRadius)) { return nullptr; } // we don't handle it if curvature of the stroke is less than curvature of the ellipse - if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius || - scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) { + if (scaledStroke.fX * (yRadius * yRadius) < + (scaledStroke.fY * scaledStroke.fY) * xRadius || + scaledStroke.fY * (xRadius * xRadius) < + (scaledStroke.fX * scaledStroke.fX) * yRadius) { return nullptr; } @@ -970,46 +1222,51 @@ public: yRadius += scaledStroke.fY; } - EllipseBatch* batch = new EllipseBatch(); - batch->fGeoData.emplace_back(Geometry { - color, - xRadius, - yRadius, - innerXRadius, - innerYRadius, - SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRadius, - center.fX + xRadius, center.fY + yRadius) - }); + std::unique_ptr op(new EllipseOp()); + op->fGeoData.emplace_back( + Geometry{color, xRadius, yRadius, innerXRadius, innerYRadius, + SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRadius, + center.fX + xRadius, center.fY + yRadius)}); - batch->setBounds(batch->fGeoData.back().fDevBounds, HasAABloat::kYes, IsZeroArea::kNo); + op->setBounds(op->fGeoData.back().fDevBounds, HasAABloat::kYes, IsZeroArea::kNo); // Outset bounds to include half-pixel width antialiasing. - batch->fGeoData[0].fDevBounds.outset(SK_ScalarHalf, SK_ScalarHalf); + op->fGeoData[0].fDevBounds.outset(SK_ScalarHalf, SK_ScalarHalf); - batch->fStroked = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0; - batch->fViewMatrixIfUsingLocalCoords = viewMatrix; - return batch; + op->fStroked = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0; + op->fViewMatrixIfUsingLocalCoords = viewMatrix; + return std::move(op); } - const char* name() const override { return "EllipseBatch"; } + const char* name() const override { return "EllipseOp"; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); + SkString dumpInfo() const override { + SkString string; + string.appendf("Stroked: %d\n", fStroked); + for (const auto& geo : fGeoData) { + string.appendf( + "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], " + "XRad: %.2f, YRad: %.2f, InnerXRad: %.2f, InnerYRad: %.2f\n", + geo.fColor, geo.fDevBounds.fLeft, geo.fDevBounds.fTop, geo.fDevBounds.fRight, + geo.fDevBounds.fBottom, geo.fXRadius, geo.fYRadius, geo.fInnerXRadius, + geo.fInnerYRadius); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; } private: - EllipseBatch() : INHERITED(ClassID()) {} + EllipseOp() : INHERITED(ClassID()) {} - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any overrides that affect our GP. - if (!overrides.readsCoverage()) { - fGeoData[0].fColor = GrColor_ILLEGAL; - } - if (!overrides.readsLocalCoords()) { + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fGeoData[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + if (!optimizations.readsLocalCoords()) { fViewMatrixIfUsingLocalCoords.reset(); } } @@ -1021,14 +1278,14 @@ private: } // Setup geometry processor - SkAutoTUnref gp(new EllipseGeometryProcessor(fStroked, localMatrix)); + sk_sp gp(new EllipseGeometryProcessor(fStroked, localMatrix)); int instanceCount = fGeoData.count(); QuadHelper helper; size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(EllipseVertex)); - EllipseVertex* verts = reinterpret_cast( - helper.init(target, vertexStride, instanceCount)); + EllipseVertex* verts = + reinterpret_cast(helper.init(target, vertexStride, instanceCount)); if (!verts) { return; } @@ -1053,13 +1310,13 @@ private: SkScalar yMaxOffset = yRadius + SK_ScalarHalf; // The inner radius in the vertex data must be specified in normalized space. - verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); + verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); verts[0].fColor = color; verts[0].fOffset = SkPoint::Make(-xMaxOffset, -yMaxOffset); verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); - verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); + verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); verts[1].fColor = color; verts[1].fOffset = SkPoint::Make(-xMaxOffset, yMaxOffset); verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); @@ -1079,11 +1336,11 @@ private: verts += kVerticesPerQuad; } - helper.recordDraw(target, gp); + helper.recordDraw(target, gp.get(), this->pipeline()); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - EllipseBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + EllipseOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { @@ -1112,32 +1369,33 @@ private: SkRect fDevBounds; }; - bool fStroked; - SkMatrix fViewMatrixIfUsingLocalCoords; + bool fStroked; + SkMatrix fViewMatrixIfUsingLocalCoords; SkSTArray<1, Geometry, true> fGeoData; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; ///////////////////////////////////////////////////////////////////////////////////////////////// -class DIEllipseBatch : public GrVertexBatch { +class DIEllipseOp : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - static GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& ellipse, - const SkStrokeRec& stroke) { + static std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& ellipse, + const SkStrokeRec& stroke) { SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY()); SkScalar xRadius = SkScalarHalf(ellipse.width()); SkScalar yRadius = SkScalarHalf(ellipse.height()); SkStrokeRec::Style style = stroke.getStyle(); - DIEllipseStyle dieStyle = (SkStrokeRec::kStroke_Style == style) ? - DIEllipseStyle::kStroke : - (SkStrokeRec::kHairline_Style == style) ? - DIEllipseStyle::kHairline : DIEllipseStyle::kFill; + DIEllipseStyle dieStyle = (SkStrokeRec::kStroke_Style == style) + ? DIEllipseStyle::kStroke + : (SkStrokeRec::kHairline_Style == style) + ? DIEllipseStyle::kHairline + : DIEllipseStyle::kFill; SkScalar innerXRadius = 0; SkScalar innerYRadius = 0; @@ -1152,13 +1410,13 @@ public: // we only handle thick strokes for near-circular ellipses if (strokeWidth > SK_ScalarHalf && - (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) { + (SK_ScalarHalf * xRadius > yRadius || SK_ScalarHalf * yRadius > xRadius)) { return nullptr; } // we don't handle it if curvature of the stroke is less than curvature of the ellipse - if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius || - strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) { + if (strokeWidth * (yRadius * yRadius) < (strokeWidth * strokeWidth) * xRadius || + strokeWidth * (xRadius * xRadius) < (strokeWidth * strokeWidth) * yRadius) { return nullptr; } @@ -1172,8 +1430,8 @@ public: yRadius += strokeWidth; } if (DIEllipseStyle::kStroke == dieStyle) { - dieStyle = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseStyle ::kStroke : - DIEllipseStyle ::kFill; + dieStyle = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseStyle::kStroke + : DIEllipseStyle::kFill; } // This expands the outer rect so that after CTM we end up with a half-pixel border @@ -1181,59 +1439,63 @@ public: SkScalar b = viewMatrix[SkMatrix::kMSkewX]; SkScalar c = viewMatrix[SkMatrix::kMSkewY]; SkScalar d = viewMatrix[SkMatrix::kMScaleY]; - SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c); - SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d); + SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a * a + c * c); + SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b * b + d * d); - DIEllipseBatch* batch = new DIEllipseBatch(); - batch->fGeoData.emplace_back(Geometry { - viewMatrix, - color, - xRadius, - yRadius, - innerXRadius, - innerYRadius, - geoDx, - geoDy, - dieStyle, - SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy, - center.fX + xRadius + geoDx, center.fY + yRadius + geoDy) - }); - batch->setTransformedBounds(batch->fGeoData[0].fBounds, viewMatrix, HasAABloat::kYes, - IsZeroArea::kNo); - return batch; + std::unique_ptr op(new DIEllipseOp()); + op->fGeoData.emplace_back(Geometry{ + viewMatrix, color, xRadius, yRadius, innerXRadius, innerYRadius, geoDx, geoDy, + dieStyle, + SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy, + center.fX + xRadius + geoDx, center.fY + yRadius + geoDy)}); + op->setTransformedBounds(op->fGeoData[0].fBounds, viewMatrix, HasAABloat::kYes, + IsZeroArea::kNo); + return std::move(op); } - const char* name() const override { return "DIEllipseBatch"; } + const char* name() const override { return "DIEllipseOp"; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); + SkString dumpInfo() const override { + SkString string; + for (const auto& geo : fGeoData) { + string.appendf( + "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], XRad: %.2f, " + "YRad: %.2f, InnerXRad: %.2f, InnerYRad: %.2f, GeoDX: %.2f, " + "GeoDY: %.2f\n", + geo.fColor, geo.fBounds.fLeft, geo.fBounds.fTop, geo.fBounds.fRight, + geo.fBounds.fBottom, geo.fXRadius, geo.fYRadius, geo.fInnerXRadius, + geo.fInnerYRadius, geo.fGeoDx, geo.fGeoDy); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; } private: + DIEllipseOp() : INHERITED(ClassID()) {} - DIEllipseBatch() : INHERITED(ClassID()) {} + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fGeoData[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any overrides that affect our GP. - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); - fUsesLocalCoords = overrides.readsLocalCoords(); + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fGeoData[0].fColor); + fUsesLocalCoords = optimizations.readsLocalCoords(); } void onPrepareDraws(Target* target) const override { // Setup geometry processor - SkAutoTUnref gp(new DIEllipseGeometryProcessor(this->viewMatrix(), - this->style())); + sk_sp gp( + new DIEllipseGeometryProcessor(this->viewMatrix(), this->style())); int instanceCount = fGeoData.count(); size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(DIEllipseVertex)); QuadHelper helper; DIEllipseVertex* verts = reinterpret_cast( - helper.init(target, vertexStride, instanceCount)); + helper.init(target, vertexStride, instanceCount)); if (!verts) { return; } @@ -1259,7 +1521,7 @@ private: verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy); verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy); - verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); + verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); verts[1].fColor = color; verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy); verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy); @@ -1276,11 +1538,11 @@ private: verts += kVerticesPerQuad; } - helper.recordDraw(target, gp); + helper.recordDraw(target, gp.get(), this->pipeline()); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - DIEllipseBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + DIEllipseOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; @@ -1316,10 +1578,10 @@ private: SkRect fBounds; }; - bool fUsesLocalCoords; + bool fUsesLocalCoords; SkSTArray<1, Geometry, true> fGeoData; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; /////////////////////////////////////////////////////////////////////////////// @@ -1350,38 +1612,45 @@ private: // |_|________|_| // // We don't draw the center quad from the fill rect in this case. +// +// For filled rrects that need to provide a distance vector we resuse the overstroke +// geometry but make the inner rect degenerate (either a point or a horizontal or +// vertical line). static const uint16_t gOverstrokeRRectIndices[] = { - // overstroke quads - // we place this at the beginning so that we can skip these indices when rendering normally - 16, 17, 19, 16, 19, 18, - 19, 17, 23, 19, 23, 21, - 21, 23, 22, 21, 22, 20, - 22, 16, 18, 22, 18, 20, + // clang-format off + // overstroke quads + // we place this at the beginning so that we can skip these indices when rendering normally + 16, 17, 19, 16, 19, 18, + 19, 17, 23, 19, 23, 21, + 21, 23, 22, 21, 22, 20, + 22, 16, 18, 22, 18, 20, - // corners - 0, 1, 5, 0, 5, 4, - 2, 3, 7, 2, 7, 6, - 8, 9, 13, 8, 13, 12, - 10, 11, 15, 10, 15, 14, + // corners + 0, 1, 5, 0, 5, 4, + 2, 3, 7, 2, 7, 6, + 8, 9, 13, 8, 13, 12, + 10, 11, 15, 10, 15, 14, - // edges - 1, 2, 6, 1, 6, 5, - 4, 5, 9, 4, 9, 8, - 6, 7, 11, 6, 11, 10, - 9, 10, 14, 9, 14, 13, + // edges + 1, 2, 6, 1, 6, 5, + 4, 5, 9, 4, 9, 8, + 6, 7, 11, 6, 11, 10, + 9, 10, 14, 9, 14, 13, - // center - // we place this at the end so that we can ignore these indices when not rendering as filled - 5, 6, 10, 5, 10, 9, + // center + // we place this at the end so that we can ignore these indices when not rendering as filled + 5, 6, 10, 5, 10, 9, + // clang-format on }; + // fill and standard stroke indices skip the overstroke "ring" -static const uint16_t* gStandardRRectIndices = gOverstrokeRRectIndices + 6*4; +static const uint16_t* gStandardRRectIndices = gOverstrokeRRectIndices + 6 * 4; // overstroke count is arraysize minus the center indices static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gOverstrokeRRectIndices) - 6; // fill count skips overstroke indices and includes center -static const int kIndicesPerFillRRect = kIndicesPerOverstrokeRRect - 6*4 + 6; +static const int kIndicesPerFillRRect = kIndicesPerOverstrokeRRect - 6 * 4 + 6; // stroke count is fill count minus center indices static const int kIndicesPerStrokeRRect = kIndicesPerFillRRect - 6; static const int kVertsPerStandardRRect = 16; @@ -1391,50 +1660,69 @@ enum RRectType { kFill_RRectType, kStroke_RRectType, kOverstroke_RRectType, + kFillWithDist_RRectType }; static int rrect_type_to_vert_count(RRectType type) { - static const int kTypeToVertCount[] = { - kVertsPerStandardRRect, - kVertsPerStandardRRect, - kVertsPerOverstrokeRRect, - }; - - return kTypeToVertCount[type]; + switch (type) { + case kFill_RRectType: + case kStroke_RRectType: + return kVertsPerStandardRRect; + case kOverstroke_RRectType: + case kFillWithDist_RRectType: + return kVertsPerOverstrokeRRect; + } + SkFAIL("Invalid type"); + return 0; } static int rrect_type_to_index_count(RRectType type) { - static const int kTypeToIndexCount[] = { - kIndicesPerFillRRect, - kIndicesPerStrokeRRect, - kIndicesPerOverstrokeRRect, - }; - - return kTypeToIndexCount[type]; + switch (type) { + case kFill_RRectType: + return kIndicesPerFillRRect; + case kStroke_RRectType: + return kIndicesPerStrokeRRect; + case kOverstroke_RRectType: + case kFillWithDist_RRectType: + return kIndicesPerOverstrokeRRect; + } + SkFAIL("Invalid type"); + return 0; } static const uint16_t* rrect_type_to_indices(RRectType type) { - static const uint16_t* kTypeToIndices[] = { - gStandardRRectIndices, - gStandardRRectIndices, - gOverstrokeRRectIndices, - }; - - return kTypeToIndices[type]; + switch (type) { + case kFill_RRectType: + case kStroke_RRectType: + return gStandardRRectIndices; + case kOverstroke_RRectType: + case kFillWithDist_RRectType: + return gOverstrokeRRectIndices; + } + SkFAIL("Invalid type"); + return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////// -class RRectCircleRendererBatch : public GrVertexBatch { +// For distance computations in the interior of filled rrects we: +// +// add a interior degenerate (point or line) rect +// each vertex of that rect gets -outerRad as its radius +// this makes the computation of the distance to the outer edge be negative +// negative values are caught and then handled differently in the GP's onEmitCode +// each vertex is also given the normalized x & y distance from the interior rect's edge +// the GP takes the min of those depths +1 to get the normalized distance to the outer edge + +class CircularRRectOp : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then strokeOnly indicates // whether the rrect is only stroked or stroked and filled. - RRectCircleRendererBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect, - float devRadius, float devStrokeWidth, bool strokeOnly) - : INHERITED(ClassID()) - , fViewMatrixIfUsingLocalCoords(viewMatrix) { + CircularRRectOp(GrColor color, bool needsDistance, const SkMatrix& viewMatrix, + const SkRect& devRect, float devRadius, float devStrokeWidth, bool strokeOnly) + : INHERITED(ClassID()), fViewMatrixIfUsingLocalCoords(viewMatrix) { SkRect bounds = devRect; SkASSERT(!(devStrokeWidth <= 0 && strokeOnly)); SkScalar innerRadius = 0.0f; @@ -1453,8 +1741,7 @@ public: devStrokeWidth += 0.25f; // If stroke is greater than width or height, this is still a fill // Otherwise we compute stroke params - if (devStrokeWidth <= devRect.width() && - devStrokeWidth <= devRect.height()) { + if (devStrokeWidth <= devRect.width() && devStrokeWidth <= devRect.height()) { innerRadius = devRadius - halfWidth; type = (innerRadius >= 0) ? kStroke_RRectType : kOverstroke_RRectType; } @@ -1462,6 +1749,9 @@ public: outerRadius += halfWidth; bounds.outset(halfWidth, halfWidth); } + if (kFill_RRectType == type && needsDistance) { + type = kFillWithDist_RRectType; + } // The radii are outset for two reasons. First, it allows the shader to simply perform // simpler computation because the computed alpha is zero, rather than 50%, at the radius. @@ -1476,46 +1766,118 @@ public: // Expand the rect for aa to generate correct vertices. bounds.outset(SK_ScalarHalf, SK_ScalarHalf); - fGeoData.emplace_back(Geometry{ color, innerRadius, outerRadius, bounds, type }); + fGeoData.emplace_back(Geometry{color, innerRadius, outerRadius, bounds, type}); fVertCount = rrect_type_to_vert_count(type); fIndexCount = rrect_type_to_index_count(type); fAllFill = (kFill_RRectType == type); } - const char* name() const override { return "RRectCircleBatch"; } + const char* name() const override { return "CircularRRectOp"; } SkString dumpInfo() const override { SkString string; for (int i = 0; i < fGeoData.count(); ++i) { - string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]," - "InnerRad: %.2f, OuterRad: %.2f\n", - fGeoData[i].fColor, - fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop, - fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom, - fGeoData[i].fInnerRadius, - fGeoData[i].fOuterRadius); + string.appendf( + "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]," + "InnerRad: %.2f, OuterRad: %.2f\n", + fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop, + fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom, + fGeoData[i].fInnerRadius, fGeoData[i].fOuterRadius); } + string.append(DumpPipelineInfo(*this->pipeline())); string.append(INHERITED::dumpInfo()); return string; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); +private: + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fGeoData[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; } -private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any overrides that affect our GP. - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); - if (!overrides.readsLocalCoords()) { + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fGeoData[0].fColor); + if (!optimizations.readsLocalCoords()) { fViewMatrixIfUsingLocalCoords.reset(); } } + struct CircleVertex { + SkPoint fPos; + GrColor fColor; + SkPoint fOffset; + SkScalar fOuterRadius; + SkScalar fInnerRadius; + // No half plane, we don't use it here. + }; + + static void FillInOverstrokeVerts(CircleVertex** verts, const SkRect& bounds, SkScalar smInset, + SkScalar bigInset, SkScalar xOffset, SkScalar outerRadius, + SkScalar innerRadius, GrColor color) { + SkASSERT(smInset < bigInset); + + // TL + (*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fTop + smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = innerRadius; + (*verts)++; + + // TR + (*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fTop + smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = innerRadius; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fTop + bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = innerRadius; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fTop + bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = innerRadius; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fBottom - bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = innerRadius; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fBottom - bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = innerRadius; + (*verts)++; + + // BL + (*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fBottom - smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = innerRadius; + (*verts)++; + + // BR + (*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fBottom - smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = innerRadius; + (*verts)++; + } + void onPrepareDraws(Target* target) const override { // Invert the view matrix as a local matrix (if any other processors require coords). SkMatrix localMatrix; @@ -1524,17 +1886,8 @@ private: } // Setup geometry processor - SkAutoTUnref gp(new CircleGeometryProcessor(!fAllFill, - false, false, - false, localMatrix)); - struct CircleVertex { - SkPoint fPos; - GrColor fColor; - SkPoint fOffset; - SkScalar fOuterRadius; - SkScalar fInnerRadius; - // No half plane, we don't use it here. - }; + sk_sp gp( + new CircleGeometryProcessor(!fAllFill, false, false, false, localMatrix)); int instanceCount = fGeoData.count(); size_t vertexStride = gp->getVertexStride(); @@ -1543,8 +1896,8 @@ private: const GrBuffer* vertexBuffer; int firstVertex; - CircleVertex* verts = (CircleVertex*) target->makeVertexSpace(vertexStride, fVertCount, - &vertexBuffer, &firstVertex); + CircleVertex* verts = (CircleVertex*)target->makeVertexSpace(vertexStride, fVertCount, + &vertexBuffer, &firstVertex); if (!verts) { SkDebugf("Could not allocate vertices\n"); return; @@ -1567,19 +1920,16 @@ private: const SkRect& bounds = args.fDevBounds; - SkScalar yCoords[4] = { - bounds.fTop, - bounds.fTop + outerRadius, - bounds.fBottom - outerRadius, - bounds.fBottom - }; + SkScalar yCoords[4] = {bounds.fTop, bounds.fTop + outerRadius, + bounds.fBottom - outerRadius, bounds.fBottom}; - SkScalar yOuterRadii[4] = {-1, 0, 0, 1 }; + SkScalar yOuterRadii[4] = {-1, 0, 0, 1}; // The inner radius in the vertex data must be specified in normalized space. // For fills, specifying -1/outerRadius guarantees an alpha of 1.0 at the inner radius. - SkScalar innerRadius = args.fType != kFill_RRectType - ? args.fInnerRadius / args.fOuterRadius - : -1.0f / args.fOuterRadius; + SkScalar innerRadius = + args.fType != kFill_RRectType && args.fType != kFillWithDist_RRectType + ? args.fInnerRadius / args.fOuterRadius + : -1.0f / args.fOuterRadius; for (int i = 0; i < 4; ++i) { verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); verts->fColor = color; @@ -1618,70 +1968,24 @@ private: // Also, the outer offset is a constant vector pointing to the right, which // guarantees that the distance value along the outer rectangle is constant. if (kOverstroke_RRectType == args.fType) { + SkASSERT(args.fInnerRadius <= 0.0f); + SkScalar overstrokeOuterRadius = outerRadius - args.fInnerRadius; // this is the normalized distance from the outer rectangle of this // geometry to the outer edge SkScalar maxOffset = -args.fInnerRadius / overstrokeOuterRadius; - verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[1]); - verts->fColor = color; - verts->fOffset = SkPoint::Make(maxOffset, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; + FillInOverstrokeVerts(&verts, bounds, outerRadius, overstrokeOuterRadius, maxOffset, + overstrokeOuterRadius, 0.0f, color); + } - verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[1]); - verts->fColor = color; - verts->fOffset = SkPoint::Make(maxOffset, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; + if (kFillWithDist_RRectType == args.fType) { + SkScalar halfMinDim = 0.5f * SkTMin(bounds.width(), bounds.height()); - verts->fPos = SkPoint::Make(bounds.fLeft + overstrokeOuterRadius, - bounds.fTop + overstrokeOuterRadius); - verts->fColor = color; - verts->fOffset = SkPoint::Make(0, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; + SkScalar xOffset = 1.0f - outerRadius / halfMinDim; - verts->fPos = SkPoint::Make(bounds.fRight - overstrokeOuterRadius, - bounds.fTop + overstrokeOuterRadius); - verts->fColor = color; - verts->fOffset = SkPoint::Make(0, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; - - verts->fPos = SkPoint::Make(bounds.fLeft + overstrokeOuterRadius, - bounds.fBottom - overstrokeOuterRadius); - verts->fColor = color; - verts->fOffset = SkPoint::Make(0, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; - - verts->fPos = SkPoint::Make(bounds.fRight - overstrokeOuterRadius, - bounds.fBottom - overstrokeOuterRadius); - verts->fColor = color; - verts->fOffset = SkPoint::Make(0, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; - - verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[2]); - verts->fColor = color; - verts->fOffset = SkPoint::Make(maxOffset, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; - - verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[2]); - verts->fColor = color; - verts->fOffset = SkPoint::Make(maxOffset, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; + FillInOverstrokeVerts(&verts, bounds, outerRadius, halfMinDim, xOffset, halfMinDim, + -1.0f, color); } const uint16_t* primIndices = rrect_type_to_indices(args.fType); @@ -1696,11 +2000,17 @@ private: GrMesh mesh; mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex, fVertCount, fIndexCount); - target->draw(gp.get(), mesh); + target->draw(gp.get(), this->pipeline(), mesh); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - RRectCircleRendererBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + CircularRRectOp* that = t->cast(); + + // can only represent 65535 unique vertices with 16-bit indices + if (fVertCount + that->fVertCount > 65536) { + return false; + } + if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; @@ -1719,7 +2029,7 @@ private: } struct Geometry { - GrColor fColor; + GrColor fColor; SkScalar fInnerRadius; SkScalar fOuterRadius; SkRect fDevBounds; @@ -1727,12 +2037,12 @@ private: }; SkSTArray<1, Geometry, true> fGeoData; - SkMatrix fViewMatrixIfUsingLocalCoords; - int fVertCount; - int fIndexCount; - bool fAllFill; + SkMatrix fViewMatrixIfUsingLocalCoords; + int fVertCount; + int fIndexCount; + bool fAllFill; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; static const int kNumRRectsInIndexBuffer = 256; @@ -1746,27 +2056,28 @@ static const GrBuffer* ref_rrect_index_buffer(RRectType type, switch (type) { case kFill_RRectType: return resourceProvider->findOrCreateInstancedIndexBuffer( - gStandardRRectIndices, kIndicesPerFillRRect, kNumRRectsInIndexBuffer, - kVertsPerStandardRRect, gRRectOnlyIndexBufferKey); + gStandardRRectIndices, kIndicesPerFillRRect, kNumRRectsInIndexBuffer, + kVertsPerStandardRRect, gRRectOnlyIndexBufferKey); case kStroke_RRectType: return resourceProvider->findOrCreateInstancedIndexBuffer( - gStandardRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, - kVertsPerStandardRRect, gStrokeRRectOnlyIndexBufferKey); + gStandardRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, + kVertsPerStandardRRect, gStrokeRRectOnlyIndexBufferKey); default: SkASSERT(false); return nullptr; }; } -class RRectEllipseRendererBatch : public GrVertexBatch { +class EllipticalRRectOp : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID // If devStrokeWidths values are <= 0 indicates then fill only. Otherwise, strokeOnly indicates // whether the rrect is only stroked or stroked and filled. - static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect, - float devXRadius, float devYRadius, SkVector devStrokeWidths, - bool strokeOnly) { + static std::unique_ptr Make(GrColor color, const SkMatrix& viewMatrix, + const SkRect& devRect, float devXRadius, + float devYRadius, SkVector devStrokeWidths, + bool strokeOnly) { SkASSERT(devXRadius > 0.5); SkASSERT(devYRadius > 0.5); SkASSERT((devStrokeWidths.fX > 0) == (devStrokeWidths.fY > 0)); @@ -1784,17 +2095,18 @@ public: // we only handle thick strokes for near-circular ellipses if (devStrokeWidths.length() > SK_ScalarHalf && - (SK_ScalarHalf*devXRadius > devYRadius || SK_ScalarHalf*devYRadius > devXRadius)) { + (SK_ScalarHalf * devXRadius > devYRadius || + SK_ScalarHalf * devYRadius > devXRadius)) { return nullptr; } // we don't handle it if curvature of the stroke is less than curvature of the ellipse - if (devStrokeWidths.fX*(devYRadius*devYRadius) < - (devStrokeWidths.fY*devStrokeWidths.fY)*devXRadius) { + if (devStrokeWidths.fX * (devYRadius * devYRadius) < + (devStrokeWidths.fY * devStrokeWidths.fY) * devXRadius) { return nullptr; } - if (devStrokeWidths.fY*(devXRadius*devXRadius) < - (devStrokeWidths.fX*devStrokeWidths.fX)*devYRadius) { + if (devStrokeWidths.fY * (devXRadius * devXRadius) < + (devStrokeWidths.fX * devStrokeWidths.fX) * devYRadius) { return nullptr; } @@ -1810,34 +2122,47 @@ public: bounds.outset(devStrokeWidths.fX, devStrokeWidths.fY); } - RRectEllipseRendererBatch* batch = new RRectEllipseRendererBatch(); - batch->fStroked = stroked; - batch->fViewMatrixIfUsingLocalCoords = viewMatrix; - batch->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo); + std::unique_ptr op(new EllipticalRRectOp()); + op->fStroked = stroked; + op->fViewMatrixIfUsingLocalCoords = viewMatrix; + op->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo); // Expand the rect for aa in order to generate the correct vertices. bounds.outset(SK_ScalarHalf, SK_ScalarHalf); - batch->fGeoData.emplace_back( - Geometry {color, devXRadius, devYRadius, innerXRadius, innerYRadius, bounds}); - return batch; + op->fGeoData.emplace_back( + Geometry{color, devXRadius, devYRadius, innerXRadius, innerYRadius, bounds}); + return std::move(op); } - const char* name() const override { return "RRectEllipseRendererBatch"; } + const char* name() const override { return "EllipticalRRectOp"; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one geometry bundle - color->setKnownFourComponents(fGeoData[0].fColor); - coverage->setUnknownSingleComponent(); + SkString dumpInfo() const override { + SkString string; + string.appendf("Stroked: %d\n", fStroked); + for (const auto& geo : fGeoData) { + string.appendf( + "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], " + "XRad: %.2f, YRad: %.2f, InnerXRad: %.2f, InnerYRad: %.2f\n", + geo.fColor, geo.fDevBounds.fLeft, geo.fDevBounds.fTop, geo.fDevBounds.fRight, + geo.fDevBounds.fBottom, geo.fXRadius, geo.fYRadius, geo.fInnerXRadius, + geo.fInnerYRadius); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; } private: - RRectEllipseRendererBatch() : INHERITED(ClassID()) {} + EllipticalRRectOp() : INHERITED(ClassID()) {} - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle overrides that affect our GP. - overrides.getOverrideColorIfSet(&fGeoData[0].fColor); - if (!overrides.readsLocalCoords()) { + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fGeoData[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fGeoData[0].fColor); + if (!optimizations.readsLocalCoords()) { fViewMatrixIfUsingLocalCoords.reset(); } } @@ -1849,7 +2174,7 @@ private: } // Setup geometry processor - SkAutoTUnref gp(new EllipseGeometryProcessor(fStroked, localMatrix)); + sk_sp gp(new EllipseGeometryProcessor(fStroked, localMatrix)); int instanceCount = fGeoData.count(); size_t vertexStride = gp->getVertexStride(); @@ -1857,14 +2182,13 @@ private: // drop out the middle quad if we're stroked int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPerFillRRect; - SkAutoTUnref indexBuffer( - ref_rrect_index_buffer(fStroked ? kStroke_RRectType : kFill_RRectType, - target->resourceProvider())); + sk_sp indexBuffer(ref_rrect_index_buffer( + fStroked ? kStroke_RRectType : kFill_RRectType, target->resourceProvider())); InstancedHelper helper; EllipseVertex* verts = reinterpret_cast( - helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer, - kVertsPerStandardRRect, indicesPerInstance, instanceCount)); + helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(), + kVertsPerStandardRRect, indicesPerInstance, instanceCount)); if (!verts || !indexBuffer) { SkDebugf("Could not allocate vertices\n"); return; @@ -1887,18 +2211,12 @@ private: const SkRect& bounds = args.fDevBounds; - SkScalar yCoords[4] = { - bounds.fTop, - bounds.fTop + yOuterRadius, - bounds.fBottom - yOuterRadius, - bounds.fBottom - }; - SkScalar yOuterOffsets[4] = { - yOuterRadius, - SK_ScalarNearlyZero, // we're using inversesqrt() in shader, so can't be exactly 0 - SK_ScalarNearlyZero, - yOuterRadius - }; + SkScalar yCoords[4] = {bounds.fTop, bounds.fTop + yOuterRadius, + bounds.fBottom - yOuterRadius, bounds.fBottom}; + SkScalar yOuterOffsets[4] = {yOuterRadius, + SK_ScalarNearlyZero, // we're using inversesqrt() in + // shader, so can't be exactly 0 + SK_ScalarNearlyZero, yOuterRadius}; for (int i = 0; i < 4; ++i) { verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); @@ -1930,11 +2248,11 @@ private: verts++; } } - helper.recordDraw(target, gp); + helper.recordDraw(target, gp.get(), this->pipeline()); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - RRectEllipseRendererBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + EllipticalRRectOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { @@ -1963,32 +2281,33 @@ private: SkRect fDevBounds; }; - bool fStroked; - SkMatrix fViewMatrixIfUsingLocalCoords; - SkSTArray<1, Geometry, true> fGeoData; + bool fStroked; + SkMatrix fViewMatrixIfUsingLocalCoords; + SkSTArray<1, Geometry, true> fGeoData; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -static GrDrawBatch* create_rrect_batch(GrColor color, - const SkMatrix& viewMatrix, - const SkRRect& rrect, - const SkStrokeRec& stroke) { +static std::unique_ptr make_rrect_op(GrColor color, + bool needsDistance, + const SkMatrix& viewMatrix, + const SkRRect& rrect, + const SkStrokeRec& stroke) { SkASSERT(viewMatrix.rectStaysRect()); SkASSERT(rrect.isSimple()); SkASSERT(!rrect.isOval()); - // RRect batchs only handle simple, but not too simple, rrects - // do any matrix crunching before we reset the draw state for device coords + // RRect ops only handle simple, but not too simple, rrects. + // Do any matrix crunching before we reset the draw state for device coords. const SkRect& rrectBounds = rrect.getBounds(); SkRect bounds; viewMatrix.mapRect(&bounds, rrectBounds); SkVector radii = rrect.getSimpleRadii(); - SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX + - viewMatrix[SkMatrix::kMSkewY]*radii.fY); - SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX + - viewMatrix[SkMatrix::kMScaleY]*radii.fY); + SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX] * radii.fX + + viewMatrix[SkMatrix::kMSkewY] * radii.fY); + SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX] * radii.fX + + viewMatrix[SkMatrix::kMScaleY] * radii.fY); SkStrokeRec::Style style = stroke.getStyle(); @@ -1996,8 +2315,8 @@ static GrDrawBatch* create_rrect_batch(GrColor color, SkVector scaledStroke = {-1, -1}; SkScalar strokeWidth = stroke.getWidth(); - bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || - SkStrokeRec::kHairline_Style == style; + bool isStrokeOnly = + SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style; bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; bool isCircular = (xRadius == yRadius); @@ -2005,17 +2324,17 @@ static GrDrawBatch* create_rrect_batch(GrColor color, if (SkStrokeRec::kHairline_Style == style) { scaledStroke.set(1, 1); } else { - scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] + - viewMatrix[SkMatrix::kMSkewY])); - scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] + - viewMatrix[SkMatrix::kMScaleY])); + scaledStroke.fX = SkScalarAbs( + strokeWidth * (viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewY])); + scaledStroke.fY = SkScalarAbs( + strokeWidth * (viewMatrix[SkMatrix::kMSkewX] + viewMatrix[SkMatrix::kMScaleY])); } isCircular = isCircular && scaledStroke.fX == scaledStroke.fY; // for non-circular rrects, if half of strokewidth is greater than radius, // we don't handle that right now - if (!isCircular && - (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius)) { + if (!isCircular && (SK_ScalarHalf * scaledStroke.fX > xRadius || + SK_ScalarHalf * scaledStroke.fY > yRadius)) { return nullptr; } } @@ -2031,55 +2350,54 @@ static GrDrawBatch* create_rrect_batch(GrColor color, // if the corners are circles, use the circle renderer if (isCircular) { - return new RRectCircleRendererBatch(color, viewMatrix, bounds, xRadius, scaledStroke.fX, - isStrokeOnly); - // otherwise we use the ellipse renderer + return std::unique_ptr(new CircularRRectOp( + color, needsDistance, viewMatrix, bounds, xRadius, scaledStroke.fX, isStrokeOnly)); + // otherwise we use the ellipse renderer } else { - return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRadius, yRadius, - scaledStroke, isStrokeOnly); - + return EllipticalRRectOp::Make(color, viewMatrix, bounds, xRadius, yRadius, scaledStroke, + isStrokeOnly); } } -GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color, - const SkMatrix& viewMatrix, - const SkRRect& rrect, - const SkStrokeRec& stroke, - const GrShaderCaps* shaderCaps) { +std::unique_ptr GrOvalOpFactory::MakeRRectOp(GrColor color, + bool needsDistance, + const SkMatrix& viewMatrix, + const SkRRect& rrect, + const SkStrokeRec& stroke, + const GrShaderCaps* shaderCaps) { if (rrect.isOval()) { - return CreateOvalBatch(color, viewMatrix, rrect.getBounds(), stroke, shaderCaps); + return MakeOvalOp(color, viewMatrix, rrect.getBounds(), stroke, shaderCaps); } if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) { return nullptr; } - return create_rrect_batch(color, viewMatrix, rrect, stroke); + return make_rrect_op(color, needsDistance, viewMatrix, rrect, stroke); } /////////////////////////////////////////////////////////////////////////////// -GrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& oval, - const SkStrokeRec& stroke, - const GrShaderCaps* shaderCaps) { +std::unique_ptr GrOvalOpFactory::MakeOvalOp(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& oval, + const SkStrokeRec& stroke, + const GrShaderCaps* shaderCaps) { // we can draw circles SkScalar width = oval.width(); if (SkScalarNearlyEqual(width, oval.height()) && circle_stays_circle(viewMatrix)) { SkPoint center = {oval.centerX(), oval.centerY()}; - return CircleBatch::Create(color, viewMatrix, center, width / 2.f, - GrStyle(stroke, nullptr)); + return CircleOp::Make(color, viewMatrix, center, width / 2.f, GrStyle(stroke, nullptr)); } - // if we have shader derivative support, render as device-independent - if (shaderCaps->shaderDerivativeSupport()) { - return DIEllipseBatch::Create(color, viewMatrix, oval, stroke); - } - - // otherwise axis-aligned ellipses only + // prefer the device space ellipse op for batchability if (viewMatrix.rectStaysRect()) { - return EllipseBatch::Create(color, viewMatrix, oval, stroke); + return EllipseOp::Make(color, viewMatrix, oval, stroke); + } + + // Otherwise, if we have shader derivative support, render as device-independent + if (shaderCaps->shaderDerivativeSupport()) { + return DIEllipseOp::Make(color, viewMatrix, oval, stroke); } return nullptr; @@ -2087,13 +2405,9 @@ GrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color, /////////////////////////////////////////////////////////////////////////////// -GrDrawBatch* GrOvalRenderer::CreateArcBatch(GrColor color, - const SkMatrix& viewMatrix, - const SkRect& oval, - SkScalar startAngle, SkScalar sweepAngle, - bool useCenter, - const GrStyle& style, - const GrShaderCaps* shaderCaps) { +std::unique_ptr GrOvalOpFactory::MakeArcOp( + GrColor color, const SkMatrix& viewMatrix, const SkRect& oval, SkScalar startAngle, + SkScalar sweepAngle, bool useCenter, const GrStyle& style, const GrShaderCaps* shaderCaps) { SkASSERT(!oval.isEmpty()); SkASSERT(sweepAngle); SkScalar width = oval.width(); @@ -2104,19 +2418,16 @@ GrDrawBatch* GrOvalRenderer::CreateArcBatch(GrColor color, return nullptr; } SkPoint center = {oval.centerX(), oval.centerY()}; - CircleBatch::ArcParams arcParams = { - SkDegreesToRadians(startAngle), - SkDegreesToRadians(sweepAngle), - useCenter - }; - return CircleBatch::Create(color, viewMatrix, center, width/2.f, style, &arcParams); + CircleOp::ArcParams arcParams = {SkDegreesToRadians(startAngle), SkDegreesToRadians(sweepAngle), + useCenter}; + return CircleOp::Make(color, viewMatrix, center, width / 2.f, style, &arcParams); } /////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -DRAW_BATCH_TEST_DEFINE(CircleBatch) { +DRAW_OP_TEST_DEFINE(CircleOp) { do { SkScalar rotate = random->nextSScalar1() * 360.f; SkScalar translateX = random->nextSScalar1() * 1000.f; @@ -2131,41 +2442,42 @@ DRAW_BATCH_TEST_DEFINE(CircleBatch) { SkPoint center = {circle.centerX(), circle.centerY()}; SkScalar radius = circle.width() / 2.f; SkStrokeRec stroke = GrTest::TestStrokeRec(random); - CircleBatch::ArcParams arcParamsTmp; - const CircleBatch::ArcParams* arcParams = nullptr; + CircleOp::ArcParams arcParamsTmp; + const CircleOp::ArcParams* arcParams = nullptr; if (random->nextBool()) { arcParamsTmp.fStartAngleRadians = random->nextSScalar1() * SK_ScalarPI * 2; arcParamsTmp.fSweepAngleRadians = random->nextSScalar1() * SK_ScalarPI * 2 - .01f; arcParamsTmp.fUseCenter = random->nextBool(); arcParams = &arcParamsTmp; } - GrDrawBatch* batch = CircleBatch::Create(color, viewMatrix, center, radius, - GrStyle(stroke, nullptr), arcParams); - if (batch) { - return batch; + std::unique_ptr op = CircleOp::Make( + color, viewMatrix, center, radius, GrStyle(stroke, nullptr), arcParams); + if (op) { + return op; } } while (true); } -DRAW_BATCH_TEST_DEFINE(EllipseBatch) { +DRAW_OP_TEST_DEFINE(EllipseOp) { SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); GrColor color = GrRandomColor(random); SkRect ellipse = GrTest::TestSquare(random); - return EllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random)); + return EllipseOp::Make(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random)); } -DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) { +DRAW_OP_TEST_DEFINE(DIEllipseOp) { SkMatrix viewMatrix = GrTest::TestMatrix(random); GrColor color = GrRandomColor(random); SkRect ellipse = GrTest::TestSquare(random); - return DIEllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random)); + return DIEllipseOp::Make(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random)); } -DRAW_BATCH_TEST_DEFINE(RRectBatch) { +DRAW_OP_TEST_DEFINE(RRectOp) { SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); GrColor color = GrRandomColor(random); const SkRRect& rrect = GrTest::TestRRectSimple(random); - return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(random)); + bool needsDistance = random->nextBool(); + return make_rrect_op(color, needsDistance, viewMatrix, rrect, GrTest::TestStrokeRec(random)); } #endif diff --git a/gfx/skia/skia/src/gpu/ops/GrOvalOpFactory.h b/gfx/skia/skia/src/gpu/ops/GrOvalOpFactory.h new file mode 100644 index 000000000000..72e0fa28a450 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrOvalOpFactory.h @@ -0,0 +1,49 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrOvalOpFactory_DEFINED +#define GrOvalOpFactory_DEFINED + +#include "GrColor.h" +#include "SkRefCnt.h" + +class GrLegacyMeshDrawOp; +class GrShaderCaps; +class GrStyle; +class SkMatrix; +struct SkRect; +class SkRRect; +class SkStrokeRec; + +/* + * This namespace wraps helper functions that draw ovals, rrects, and arcs (filled & stroked) + */ +class GrOvalOpFactory { +public: + static std::unique_ptr MakeOvalOp(GrColor, + const SkMatrix& viewMatrix, + const SkRect& oval, + const SkStrokeRec& stroke, + const GrShaderCaps* shaderCaps); + static std::unique_ptr MakeRRectOp(GrColor, + bool needsDistance, + const SkMatrix& viewMatrix, + const SkRRect& rrect, + const SkStrokeRec& stroke, + const GrShaderCaps* shaderCaps); + + static std::unique_ptr MakeArcOp(GrColor, + const SkMatrix& viewMatrix, + const SkRect& oval, + SkScalar startAngle, + SkScalar sweepAngle, + bool useCenter, + const GrStyle&, + const GrShaderCaps* shaderCaps); +}; + +#endif // GrOvalOpFactory_DEFINED diff --git a/gfx/skia/skia/src/gpu/batches/GrPathStencilSettings.h b/gfx/skia/skia/src/gpu/ops/GrPathStencilSettings.h similarity index 100% rename from gfx/skia/skia/src/gpu/batches/GrPathStencilSettings.h rename to gfx/skia/skia/src/gpu/ops/GrPathStencilSettings.h diff --git a/gfx/skia/skia/src/gpu/ops/GrRectOpFactory.cpp b/gfx/skia/skia/src/gpu/ops/GrRectOpFactory.cpp new file mode 100644 index 000000000000..45e2053f8ddc --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrRectOpFactory.cpp @@ -0,0 +1,34 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrRectOpFactory.h" + +#include "GrAAStrokeRectOp.h" +#include "GrMeshDrawOp.h" +#include "SkStrokeRec.h" + +namespace GrRectOpFactory { + +std::unique_ptr MakeAAFillNestedRects(GrColor color, + const SkMatrix& viewMatrix, + const SkRect rects[2]) { + SkASSERT(viewMatrix.rectStaysRect()); + SkASSERT(!rects[0].isEmpty() && !rects[1].isEmpty()); + + SkRect devOutside, devInside; + viewMatrix.mapRect(&devOutside, rects[0]); + viewMatrix.mapRect(&devInside, rects[1]); + if (devInside.isEmpty()) { + if (devOutside.isEmpty()) { + return nullptr; + } + return GrAAFillRectOp::Make(color, viewMatrix, devOutside, devOutside); + } + + return GrAAStrokeRectOp::MakeFillBetweenRects(color, viewMatrix, devOutside, devInside); +} +}; diff --git a/gfx/skia/skia/src/gpu/ops/GrRectOpFactory.h b/gfx/skia/skia/src/gpu/ops/GrRectOpFactory.h new file mode 100644 index 000000000000..fef88e6d31df --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrRectOpFactory.h @@ -0,0 +1,83 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRectOpFactory_DEFINED +#define GrRectOpFactory_DEFINED + +#include "GrAAFillRectOp.h" +#include "GrAAStrokeRectOp.h" +#include "GrAnalyticRectOp.h" +#include "GrColor.h" +#include "GrMeshDrawOp.h" +#include "GrNonAAFillRectOp.h" +#include "GrNonAAStrokeRectOp.h" +#include "GrPaint.h" +#include "SkMatrix.h" +#include "SkRefCnt.h" + +struct SkRect; +class SkStrokeRec; + +/** + * A factory for returning GrDrawOps which can draw rectangles. + */ +namespace GrRectOpFactory { + +inline std::unique_ptr MakeNonAAFill(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect* localRect, + const SkMatrix* localMatrix) { + if (viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective())) { + return GrNonAAFillRectOp::MakeWithPerspective(color, viewMatrix, rect, localRect, + localMatrix); + } else { + return GrNonAAFillRectOp::Make(color, viewMatrix, rect, localRect, localMatrix); + } +} + +inline std::unique_ptr MakeAAFill(const GrPaint& paint, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect& croppedRect, + const SkRect& devRect) { + if (!paint.usesDistanceVectorField()) { + return GrAAFillRectOp::Make(paint.getColor(), viewMatrix, croppedRect, devRect); + } else { + return GrAnalyticRectOp::Make(paint.getColor(), viewMatrix, rect, croppedRect, devRect); + } +} + +inline std::unique_ptr MakeAAFill(GrColor color, + const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, + const SkRect& rect, + const SkRect& devRect) { + return GrAAFillRectOp::Make(color, viewMatrix, localMatrix, rect, devRect); +} + +inline std::unique_ptr MakeNonAAStroke(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkStrokeRec& strokeRec, + bool snapToPixelCenters) { + return GrNonAAStrokeRectOp::Make(color, viewMatrix, rect, strokeRec, snapToPixelCenters); +} + +inline std::unique_ptr MakeAAStroke(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkStrokeRec& stroke) { + return GrAAStrokeRectOp::Make(color, viewMatrix, rect, stroke); +} + +// First rect is outer; second rect is inner +std::unique_ptr MakeAAFillNestedRects(GrColor, const SkMatrix& viewMatrix, + const SkRect rects[2]); +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrRegionBatch.cpp b/gfx/skia/skia/src/gpu/ops/GrRegionOp.cpp similarity index 55% rename from gfx/skia/skia/src/gpu/batches/GrRegionBatch.cpp rename to gfx/skia/skia/src/gpu/ops/GrRegionOp.cpp index 058baf0ef8fb..91191f3a3fec 100644 --- a/gfx/skia/skia/src/gpu/batches/GrRegionBatch.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrRegionOp.cpp @@ -5,44 +5,41 @@ * found in the LICENSE file. */ -#include "GrRegionBatch.h" +#include "GrRegionOp.h" #include "GrDefaultGeoProcFactory.h" -#include "GrBatchFlushState.h" +#include "GrMeshDrawOp.h" +#include "GrOpFlushState.h" #include "GrResourceProvider.h" -#include "GrVertexBatch.h" #include "SkMatrixPriv.h" #include "SkRegion.h" static const int kVertsPerInstance = 4; static const int kIndicesPerInstance = 6; -static sk_sp make_gp(bool readsCoverage, const SkMatrix& viewMatrix) { +static sk_sp make_gp(const SkMatrix& viewMatrix) { using namespace GrDefaultGeoProcFactory; - Color color(Color::kAttribute_Type); - Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Type); - - LocalCoords localCoords(LocalCoords::kUsePosition_Type); - return GrDefaultGeoProcFactory::Make(color, coverage, localCoords, viewMatrix); + return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type, + LocalCoords::kUsePosition_Type, viewMatrix); } static void tesselate_region(intptr_t vertices, - size_t vertexStride, - GrColor color, - const SkRegion& region) { + size_t vertexStride, + GrColor color, + const SkRegion& region) { SkRegion::Iterator iter(region); intptr_t verts = vertices; while (!iter.done()) { SkRect rect = SkRect::Make(iter.rect()); - SkPoint* position = (SkPoint*) verts; + SkPoint* position = (SkPoint*)verts; position->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = reinterpret_cast(verts + kColorOffset); for (int i = 0; i < kVertsPerInstance; i++) { *vertColor = color; - vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); + vertColor = (GrColor*)((intptr_t)vertColor + vertexStride); } verts += vertexStride * kVertsPerInstance; @@ -50,14 +47,12 @@ static void tesselate_region(intptr_t vertices, } } -class RegionBatch : public GrVertexBatch { +class RegionOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - RegionBatch(GrColor color, const SkMatrix& viewMatrix, const SkRegion& region) - : INHERITED(ClassID()) - , fViewMatrix(viewMatrix) - { + RegionOp(GrColor color, const SkMatrix& viewMatrix, const SkRegion& region) + : INHERITED(ClassID()), fViewMatrix(viewMatrix) { RegionInfo& info = fRegions.push_back(); info.fColor = color; info.fRegion = region; @@ -66,37 +61,34 @@ public: this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); } - const char* name() const override { return "GrRegionBatch"; } + const char* name() const override { return "GrRegionOp"; } SkString dumpInfo() const override { SkString str; - str.appendf("# batched: %d\n", fRegions.count()); + str.appendf("# combined: %d\n", fRegions.count()); for (int i = 0; i < fRegions.count(); ++i) { const RegionInfo& info = fRegions[i]; - str.appendf("%d: Color: 0x%08x, Region with %d rects\n", - i, info.fColor, info.fRegion.computeRegionComplexity()); + str.appendf("%d: Color: 0x%08x, Region with %d rects\n", i, info.fColor, + info.fRegion.computeRegionComplexity()); } + str.append(DumpPipelineInfo(*this->pipeline())); str.append(INHERITED::dumpInfo()); return str; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - // When this is called on a batch, there is only one region. - color->setKnownFourComponents(fRegions[0].fColor); - coverage->setKnownSingleComponent(0xff); - } - - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - overrides.getOverrideColorIfSet(&fRegions[0].fColor); - fOverrides = overrides; - } - private: + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fRegions[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kNone; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fRegions[0].fColor); + } void onPrepareDraws(Target* target) const override { - sk_sp gp = make_gp(fOverrides.readsCoverage(), fViewMatrix); + sk_sp gp = make_gp(fViewMatrix); if (!gp) { SkDebugf("Couldn't create GrGeometryProcessor\n"); return; @@ -110,10 +102,11 @@ private: } size_t vertexStride = gp->getVertexStride(); - SkAutoTUnref indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); + sk_sp indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); InstancedHelper helper; - void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, - indexBuffer, kVertsPerInstance, kIndicesPerInstance, numRects); + void* vertices = + helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(), + kVertsPerInstance, kIndicesPerInstance, numRects); if (!vertices || !indexBuffer) { SkDebugf("Could not allocate vertices\n"); return; @@ -125,11 +118,11 @@ private: int numRectsInRegion = fRegions[i].fRegion.computeRegionComplexity(); verts += numRectsInRegion * kVertsPerInstance * vertexStride; } - helper.recordDraw(target, gp.get()); + helper.recordDraw(target, gp.get(), this->pipeline()); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { - RegionBatch* that = t->cast(); + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + RegionOp* that = t->cast(); if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), that->bounds(), caps)) { return false; @@ -150,18 +143,15 @@ private: }; SkMatrix fViewMatrix; - GrXPOverridesForBatch fOverrides; SkSTArray<1, RegionInfo, true> fRegions; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; -namespace GrRegionBatch { +namespace GrRegionOp { -GrDrawBatch* Create(GrColor color, - const SkMatrix& viewMatrix, - const SkRegion& region) { - return new RegionBatch(color, viewMatrix, region); +std::unique_ptr Make(GrColor color, const SkMatrix& viewMatrix, + const SkRegion& region) { + return std::unique_ptr(new RegionOp(color, viewMatrix, region)); +} } - -}; diff --git a/gfx/skia/skia/src/gpu/ops/GrRegionOp.h b/gfx/skia/skia/src/gpu/ops/GrRegionOp.h new file mode 100644 index 000000000000..2170667582b9 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrRegionOp.h @@ -0,0 +1,23 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRegionOp_DEFINED +#define GrRegionOp_DEFINED + +#include "GrColor.h" +#include "SkRefCnt.h" + +class GrLegacyMeshDrawOp; +class SkMatrix; +class SkRegion; + +namespace GrRegionOp { +std::unique_ptr Make(GrColor color, const SkMatrix& viewMatrix, + const SkRegion& region); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrSemaphoreOp.cpp b/gfx/skia/skia/src/gpu/ops/GrSemaphoreOp.cpp new file mode 100644 index 000000000000..e83096d52a32 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrSemaphoreOp.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrSemaphoreOp.h" + +#include "GrGpu.h" +#include "GrOpFlushState.h" + +class GrSignalSemaphoreOp final : public GrSemaphoreOp { +public: + DEFINE_OP_CLASS_ID + + static std::unique_ptr Make(sk_sp semaphore) { + return std::unique_ptr(new GrSignalSemaphoreOp(std::move(semaphore))); + } + + const char* name() const override { return "SignalSemaphore"; } + +private: + explicit GrSignalSemaphoreOp(sk_sp semaphore) + : INHERITED(ClassID(), std::move(semaphore)) {} + + void onExecute(GrOpFlushState* state) override { + state->gpu()->insertSemaphore(fSemaphore); + } + + typedef GrSemaphoreOp INHERITED; +}; + +class GrWaitSemaphoreOp final : public GrSemaphoreOp { +public: + DEFINE_OP_CLASS_ID + + static std::unique_ptr Make(sk_sp semaphore) { + return std::unique_ptr(new GrWaitSemaphoreOp(std::move(semaphore))); + } + + const char* name() const override { return "WaitSemaphore"; } + +private: + explicit GrWaitSemaphoreOp(sk_sp semaphore) + : INHERITED(ClassID(), std::move(semaphore)) {} + + void onExecute(GrOpFlushState* state) override { + state->gpu()->waitSemaphore(fSemaphore); + } + + typedef GrSemaphoreOp INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +std::unique_ptr GrSemaphoreOp::MakeSignal(sk_sp semaphore) { + return GrSignalSemaphoreOp::Make(std::move(semaphore)); +} + +std::unique_ptr GrSemaphoreOp::MakeWait(sk_sp semaphore) { + return GrWaitSemaphoreOp::Make(std::move(semaphore)); +} + + diff --git a/gfx/skia/skia/src/gpu/ops/GrSemaphoreOp.h b/gfx/skia/skia/src/gpu/ops/GrSemaphoreOp.h new file mode 100644 index 000000000000..a88b66cfc754 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrSemaphoreOp.h @@ -0,0 +1,35 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSemaphoreOp_DEFINED +#define GrSemaphoreOp_DEFINED + +#include "GrOp.h" + +#include "GrSemaphore.h" +#include "SkRefCnt.h" + +class GrSemaphoreOp : public GrOp { +public: + static std::unique_ptr MakeSignal(sk_sp semaphore); + + static std::unique_ptr MakeWait(sk_sp semaphore); + +protected: + GrSemaphoreOp(uint32_t classId, sk_sp semaphore) + : INHERITED(classId), fSemaphore(std::move(semaphore)) {} + + sk_sp fSemaphore; + +private: + bool onCombineIfPossible(GrOp* that, const GrCaps& caps) override { return false; } + void onPrepare(GrOpFlushState*) override {} + + typedef GrOp INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrShadowRRectOp.cpp b/gfx/skia/skia/src/gpu/ops/GrShadowRRectOp.cpp new file mode 100644 index 000000000000..00ec35fba8d9 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrShadowRRectOp.cpp @@ -0,0 +1,942 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrShadowRRectOp.h" + +#include "GrDrawOpTest.h" +#include "GrOpFlushState.h" +#include "GrResourceProvider.h" +#include "GrStyle.h" + +#include "effects/GrShadowGeoProc.h" + +/////////////////////////////////////////////////////////////////////////////// + +// We have two possible cases for geometry for a circle: + +// In the case of a normal fill, we draw geometry for the circle as an octagon. +static const uint16_t gFillCircleIndices[] = { + // enter the octagon + // clang-format off + 0, 1, 8, 1, 2, 8, + 2, 3, 8, 3, 4, 8, + 4, 5, 8, 5, 6, 8, + 6, 7, 8, 7, 0, 8, + // clang-format on +}; + +// For stroked circles, we use two nested octagons. +static const uint16_t gStrokeCircleIndices[] = { + // enter the octagon + // clang-format off + 0, 1, 9, 0, 9, 8, + 1, 2, 10, 1, 10, 9, + 2, 3, 11, 2, 11, 10, + 3, 4, 12, 3, 12, 11, + 4, 5, 13, 4, 13, 12, + 5, 6, 14, 5, 14, 13, + 6, 7, 15, 6, 15, 14, + 7, 0, 8, 7, 8, 15, + // clang-format on +}; + +static const int kIndicesPerFillCircle = SK_ARRAY_COUNT(gFillCircleIndices); +static const int kIndicesPerStrokeCircle = SK_ARRAY_COUNT(gStrokeCircleIndices); +static const int kVertsPerStrokeCircle = 16; +static const int kVertsPerFillCircle = 9; + +static int circle_type_to_vert_count(bool stroked) { + return stroked ? kVertsPerStrokeCircle : kVertsPerFillCircle; +} + +static int circle_type_to_index_count(bool stroked) { + return stroked ? kIndicesPerStrokeCircle : kIndicesPerFillCircle; +} + +static const uint16_t* circle_type_to_indices(bool stroked) { + return stroked ? gStrokeCircleIndices : gFillCircleIndices; +} + +/////////////////////////////////////////////////////////////////////////////// + +class ShadowCircleOp final : public GrLegacyMeshDrawOp { +public: + DEFINE_OP_CLASS_ID + + static std::unique_ptr Make(GrColor color, const SkMatrix& viewMatrix, + SkPoint center, SkScalar radius, + SkScalar blurRadius, const GrStyle& style) { + SkASSERT(viewMatrix.isSimilarity()); + const SkStrokeRec& stroke = style.strokeRec(); + if (style.hasPathEffect()) { + return nullptr; + } + SkStrokeRec::Style recStyle = stroke.getStyle(); + + viewMatrix.mapPoints(¢er, 1); + radius = viewMatrix.mapRadius(radius); + SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth()); + + bool isStrokeOnly = + SkStrokeRec::kStroke_Style == recStyle || SkStrokeRec::kHairline_Style == recStyle; + bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == recStyle; + + SkScalar innerRadius = -SK_ScalarHalf; + SkScalar outerRadius = radius; + SkScalar halfWidth = 0; + if (hasStroke) { + if (SkScalarNearlyZero(strokeWidth)) { + halfWidth = SK_ScalarHalf; + } else { + halfWidth = SkScalarHalf(strokeWidth); + } + + outerRadius += halfWidth; + if (isStrokeOnly) { + innerRadius = radius - halfWidth; + } + } + + bool stroked = isStrokeOnly && innerRadius > 0.0f; + std::unique_ptr op(new ShadowCircleOp()); + op->fViewMatrixIfUsingLocalCoords = viewMatrix; + + SkRect devBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius, + center.fX + outerRadius, center.fY + outerRadius); + + op->fCircles.emplace_back( + Circle{color, outerRadius, innerRadius, blurRadius, devBounds, stroked}); + + // Use the original radius and stroke radius for the bounds so that it does not include the + // AA bloat. + radius += halfWidth; + op->setBounds( + {center.fX - radius, center.fY - radius, center.fX + radius, center.fY + radius}, + HasAABloat::kNo, IsZeroArea::kNo); + op->fVertCount = circle_type_to_vert_count(stroked); + op->fIndexCount = circle_type_to_index_count(stroked); + return std::move(op); + } + + const char* name() const override { return "ShadowCircleOp"; } + + SkString dumpInfo() const override { + SkString string; + for (int i = 0; i < fCircles.count(); ++i) { + string.appendf( + "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], " + "OuterRad: %.2f, InnerRad: %.2f, BlurRad: %.2f\n", + fCircles[i].fColor, fCircles[i].fDevBounds.fLeft, fCircles[i].fDevBounds.fTop, + fCircles[i].fDevBounds.fRight, fCircles[i].fDevBounds.fBottom, + fCircles[i].fOuterRadius, fCircles[i].fInnerRadius, fCircles[i].fBlurRadius); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + ShadowCircleOp() : INHERITED(ClassID()) {} + + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fCircles[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fCircles[0].fColor); + if (!optimizations.readsLocalCoords()) { + fViewMatrixIfUsingLocalCoords.reset(); + } + } + + void onPrepareDraws(Target* target) const override { + SkMatrix localMatrix; + if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { + return; + } + + // Setup geometry processor + sk_sp gp(GrRRectShadowGeoProc::Make(localMatrix)); + + struct CircleVertex { + SkPoint fPos; + GrColor fColor; + SkPoint fOffset; + SkScalar fOuterRadius; + SkScalar fBlurRadius; + }; + + int instanceCount = fCircles.count(); + size_t vertexStride = gp->getVertexStride(); + SkASSERT(vertexStride == sizeof(CircleVertex)); + + const GrBuffer* vertexBuffer; + int firstVertex; + char* vertices = (char*)target->makeVertexSpace(vertexStride, fVertCount, &vertexBuffer, + &firstVertex); + if (!vertices) { + SkDebugf("Could not allocate vertices\n"); + return; + } + + const GrBuffer* indexBuffer = nullptr; + int firstIndex = 0; + uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex); + if (!indices) { + SkDebugf("Could not allocate indices\n"); + return; + } + + int currStartVertex = 0; + for (int i = 0; i < instanceCount; i++) { + const Circle& circle = fCircles[i]; + + GrColor color = circle.fColor; + SkScalar outerRadius = circle.fOuterRadius; + SkScalar innerRadius = circle.fInnerRadius; + SkScalar blurRadius = circle.fBlurRadius; + + const SkRect& bounds = circle.fDevBounds; + CircleVertex* ov0 = reinterpret_cast(vertices + 0 * vertexStride); + CircleVertex* ov1 = reinterpret_cast(vertices + 1 * vertexStride); + CircleVertex* ov2 = reinterpret_cast(vertices + 2 * vertexStride); + CircleVertex* ov3 = reinterpret_cast(vertices + 3 * vertexStride); + CircleVertex* ov4 = reinterpret_cast(vertices + 4 * vertexStride); + CircleVertex* ov5 = reinterpret_cast(vertices + 5 * vertexStride); + CircleVertex* ov6 = reinterpret_cast(vertices + 6 * vertexStride); + CircleVertex* ov7 = reinterpret_cast(vertices + 7 * vertexStride); + + // The inner radius in the vertex data must be specified in normalized space. + innerRadius = innerRadius / outerRadius; + + SkPoint center = SkPoint::Make(bounds.centerX(), bounds.centerY()); + SkScalar halfWidth = 0.5f * bounds.width(); + SkScalar octOffset = 0.41421356237f; // sqrt(2) - 1 + + ov0->fPos = center + SkPoint::Make(-octOffset * halfWidth, -halfWidth); + ov0->fColor = color; + ov0->fOffset = SkPoint::Make(-octOffset, -1); + ov0->fOuterRadius = outerRadius; + ov0->fBlurRadius = blurRadius; + + ov1->fPos = center + SkPoint::Make(octOffset * halfWidth, -halfWidth); + ov1->fColor = color; + ov1->fOffset = SkPoint::Make(octOffset, -1); + ov1->fOuterRadius = outerRadius; + ov1->fBlurRadius = blurRadius; + + ov2->fPos = center + SkPoint::Make(halfWidth, -octOffset * halfWidth); + ov2->fColor = color; + ov2->fOffset = SkPoint::Make(1, -octOffset); + ov2->fOuterRadius = outerRadius; + ov2->fBlurRadius = blurRadius; + + ov3->fPos = center + SkPoint::Make(halfWidth, octOffset * halfWidth); + ov3->fColor = color; + ov3->fOffset = SkPoint::Make(1, octOffset); + ov3->fOuterRadius = outerRadius; + ov3->fBlurRadius = blurRadius; + + ov4->fPos = center + SkPoint::Make(octOffset * halfWidth, halfWidth); + ov4->fColor = color; + ov4->fOffset = SkPoint::Make(octOffset, 1); + ov4->fOuterRadius = outerRadius; + ov4->fBlurRadius = blurRadius; + + ov5->fPos = center + SkPoint::Make(-octOffset * halfWidth, halfWidth); + ov5->fColor = color; + ov5->fOffset = SkPoint::Make(-octOffset, 1); + ov5->fOuterRadius = outerRadius; + ov5->fBlurRadius = blurRadius; + + ov6->fPos = center + SkPoint::Make(-halfWidth, octOffset * halfWidth); + ov6->fColor = color; + ov6->fOffset = SkPoint::Make(-1, octOffset); + ov6->fOuterRadius = outerRadius; + ov6->fBlurRadius = blurRadius; + + ov7->fPos = center + SkPoint::Make(-halfWidth, -octOffset * halfWidth); + ov7->fColor = color; + ov7->fOffset = SkPoint::Make(-1, -octOffset); + ov7->fOuterRadius = outerRadius; + ov7->fBlurRadius = blurRadius; + + if (circle.fStroked) { + // compute the inner ring + CircleVertex* iv0 = reinterpret_cast(vertices + 8 * vertexStride); + CircleVertex* iv1 = reinterpret_cast(vertices + 9 * vertexStride); + CircleVertex* iv2 = reinterpret_cast(vertices + 10 * vertexStride); + CircleVertex* iv3 = reinterpret_cast(vertices + 11 * vertexStride); + CircleVertex* iv4 = reinterpret_cast(vertices + 12 * vertexStride); + CircleVertex* iv5 = reinterpret_cast(vertices + 13 * vertexStride); + CircleVertex* iv6 = reinterpret_cast(vertices + 14 * vertexStride); + CircleVertex* iv7 = reinterpret_cast(vertices + 15 * vertexStride); + + // cosine and sine of pi/8 + SkScalar c = 0.923579533f; + SkScalar s = 0.382683432f; + SkScalar r = circle.fInnerRadius; + + iv0->fPos = center + SkPoint::Make(-s * r, -c * r); + iv0->fColor = color; + iv0->fOffset = SkPoint::Make(-s * innerRadius, -c * innerRadius); + iv0->fOuterRadius = outerRadius; + iv0->fBlurRadius = blurRadius; + + iv1->fPos = center + SkPoint::Make(s * r, -c * r); + iv1->fColor = color; + iv1->fOffset = SkPoint::Make(s * innerRadius, -c * innerRadius); + iv1->fOuterRadius = outerRadius; + iv1->fBlurRadius = blurRadius; + + iv2->fPos = center + SkPoint::Make(c * r, -s * r); + iv2->fColor = color; + iv2->fOffset = SkPoint::Make(c * innerRadius, -s * innerRadius); + iv2->fOuterRadius = outerRadius; + iv2->fBlurRadius = blurRadius; + + iv3->fPos = center + SkPoint::Make(c * r, s * r); + iv3->fColor = color; + iv3->fOffset = SkPoint::Make(c * innerRadius, s * innerRadius); + iv3->fOuterRadius = outerRadius; + iv3->fBlurRadius = blurRadius; + + iv4->fPos = center + SkPoint::Make(s * r, c * r); + iv4->fColor = color; + iv4->fOffset = SkPoint::Make(s * innerRadius, c * innerRadius); + iv4->fOuterRadius = outerRadius; + iv4->fBlurRadius = blurRadius; + + iv5->fPos = center + SkPoint::Make(-s * r, c * r); + iv5->fColor = color; + iv5->fOffset = SkPoint::Make(-s * innerRadius, c * innerRadius); + iv5->fOuterRadius = outerRadius; + iv5->fBlurRadius = blurRadius; + + iv6->fPos = center + SkPoint::Make(-c * r, s * r); + iv6->fColor = color; + iv6->fOffset = SkPoint::Make(-c * innerRadius, s * innerRadius); + iv6->fOuterRadius = outerRadius; + iv6->fBlurRadius = blurRadius; + + iv7->fPos = center + SkPoint::Make(-c * r, -s * r); + iv7->fColor = color; + iv7->fOffset = SkPoint::Make(-c * innerRadius, -s * innerRadius); + iv7->fOuterRadius = outerRadius; + iv7->fBlurRadius = blurRadius; + } else { + // filled + CircleVertex* iv = reinterpret_cast(vertices + 8 * vertexStride); + iv->fPos = center; + iv->fColor = color; + iv->fOffset = SkPoint::Make(0, 0); + iv->fOuterRadius = outerRadius; + iv->fBlurRadius = blurRadius; + } + + const uint16_t* primIndices = circle_type_to_indices(circle.fStroked); + const int primIndexCount = circle_type_to_index_count(circle.fStroked); + for (int i = 0; i < primIndexCount; ++i) { + *indices++ = primIndices[i] + currStartVertex; + } + + currStartVertex += circle_type_to_vert_count(circle.fStroked); + vertices += circle_type_to_vert_count(circle.fStroked) * vertexStride; + } + + GrMesh mesh; + mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex, + firstIndex, fVertCount, fIndexCount); + target->draw(gp.get(), this->pipeline(), mesh); + } + + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + ShadowCircleOp* that = t->cast(); + if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), + that->bounds(), caps)) { + return false; + } + + if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) { + return false; + } + + fCircles.push_back_n(that->fCircles.count(), that->fCircles.begin()); + this->joinBounds(*that); + fVertCount += that->fVertCount; + fIndexCount += that->fIndexCount; + return true; + } + + struct Circle { + GrColor fColor; + SkScalar fOuterRadius; + SkScalar fInnerRadius; + SkScalar fBlurRadius; + SkRect fDevBounds; + bool fStroked; + }; + + SkSTArray<1, Circle, true> fCircles; + SkMatrix fViewMatrixIfUsingLocalCoords; + int fVertCount; + int fIndexCount; + + typedef GrLegacyMeshDrawOp INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// We have two possible cases for geometry for a shadow roundrect. +// +// In the case of a normal stroke, we draw the roundrect as a 9-patch without the center quad. +// ____________ +// |_|________|_| +// | | | | +// | | | | +// | | | | +// |_|________|_| +// |_|________|_| +// +// In the case where the stroke width is greater than twice the corner radius (overstroke), +// we add additional geometry to mark out the rectangle in the center. The shared vertices +// are duplicated so we can set a different outer radius for the fill calculation. +// ____________ +// |_|________|_| +// | |\ ____ /| | +// | | | | | | +// | | |____| | | +// |_|/______\|_| +// |_|________|_| +// +// For filled rrects we reuse the overstroke geometry but make the inner rect degenerate +// (either a point or a horizontal or vertical line). + +static const uint16_t gOverstrokeRRectIndices[] = { + // clang-format off + // corners + 0, 1, 5, 0, 5, 4, + 2, 3, 7, 2, 7, 6, + 8, 9, 13, 8, 13, 12, + 10, 11, 15, 10, 15, 14, + + // edges + 1, 2, 6, 1, 6, 5, + 4, 5, 9, 4, 9, 8, + 6, 7, 11, 6, 11, 10, + 9, 10, 14, 9, 14, 13, + + // overstroke quads + // we place this at the end so that we can skip these indices when rendering as stroked + 16, 17, 19, 16, 19, 18, + 19, 17, 23, 19, 23, 21, + 21, 23, 22, 21, 22, 20, + 22, 16, 18, 22, 18, 20, + // clang-format on +}; +// standard stroke indices start at the same place, but will skip the overstroke "ring" +static const uint16_t* gStrokeRRectIndices = gOverstrokeRRectIndices; + +// overstroke count +static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gOverstrokeRRectIndices); +// simple stroke count skips overstroke indices +static const int kIndicesPerStrokeRRect = kIndicesPerOverstrokeRRect - 6 * 4 + 6; +static const int kVertsPerStrokeRRect = 16; +static const int kVertsPerOverstrokeRRect = 24; + +enum RRectType { + kFill_RRectType, + kStroke_RRectType, + kOverstroke_RRectType, +}; + +static int rrect_type_to_vert_count(RRectType type) { + switch (type) { + case kFill_RRectType: + return kVertsPerOverstrokeRRect; + case kStroke_RRectType: + return kVertsPerStrokeRRect; + case kOverstroke_RRectType: + return kVertsPerOverstrokeRRect; + } + SkFAIL("Invalid type"); + return 0; +} + +static int rrect_type_to_index_count(RRectType type) { + switch (type) { + case kFill_RRectType: + return kIndicesPerOverstrokeRRect; + case kStroke_RRectType: + return kIndicesPerStrokeRRect; + case kOverstroke_RRectType: + return kIndicesPerOverstrokeRRect; + } + SkFAIL("Invalid type"); + return 0; +} + +static const uint16_t* rrect_type_to_indices(RRectType type) { + switch (type) { + case kFill_RRectType: + return gOverstrokeRRectIndices; + case kStroke_RRectType: + return gStrokeRRectIndices; + case kOverstroke_RRectType: + return gOverstrokeRRectIndices; + } + SkFAIL("Invalid type"); + return nullptr; +} + +// For distance computations in the interior of filled rrects we: +// +// add a interior degenerate (point or line) rect +// each vertex of that rect gets -outerRad as its radius +// this makes the computation of the distance to the outer edge be negative +// negative values are caught and then handled differently in the GP's onEmitCode +// each vertex is also given the normalized x & y distance from the interior rect's edge +// the GP takes the min of those depths +1 to get the normalized distance to the outer edge + +class ShadowCircularRRectOp final : public GrLegacyMeshDrawOp { +public: + DEFINE_OP_CLASS_ID + + // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then strokeOnly indicates + // whether the rrect is only stroked or stroked and filled. + ShadowCircularRRectOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect, + float devRadius, float blurRadius, float devStrokeWidth, bool strokeOnly) + : INHERITED(ClassID()), fViewMatrixIfUsingLocalCoords(viewMatrix) { + SkRect bounds = devRect; + SkASSERT(!(devStrokeWidth <= 0 && strokeOnly)); + SkScalar innerRadius = 0.0f; + SkScalar outerRadius = devRadius; + SkScalar halfWidth = 0; + RRectType type = kFill_RRectType; + if (devStrokeWidth > 0) { + if (SkScalarNearlyZero(devStrokeWidth)) { + halfWidth = SK_ScalarHalf; + } else { + halfWidth = SkScalarHalf(devStrokeWidth); + } + + if (strokeOnly) { + // If stroke is greater than width or height, this is still a fill + // Otherwise we compute stroke params + if (devStrokeWidth <= devRect.width() && devStrokeWidth <= devRect.height()) { + innerRadius = devRadius - halfWidth; + type = (innerRadius >= 0) ? kStroke_RRectType : kOverstroke_RRectType; + } + } + outerRadius += halfWidth; + bounds.outset(halfWidth, halfWidth); + } + + this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); + + fGeoData.emplace_back(Geometry{color, outerRadius, innerRadius, blurRadius, bounds, type}); + fVertCount = rrect_type_to_vert_count(type); + fIndexCount = rrect_type_to_index_count(type); + } + + const char* name() const override { return "ShadowCircularRRectOp"; } + + SkString dumpInfo() const override { + SkString string; + for (int i = 0; i < fGeoData.count(); ++i) { + string.appendf( + "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]," + "OuterRad: %.2f, InnerRad: %.2f, BlurRad: %.2f\n", + fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop, + fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom, + fGeoData[i].fOuterRadius, fGeoData[i].fInnerRadius, fGeoData[i].fBlurRadius); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fGeoData[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fGeoData[0].fColor); + if (!optimizations.readsLocalCoords()) { + fViewMatrixIfUsingLocalCoords.reset(); + } + } + + struct CircleVertex { + SkPoint fPos; + GrColor fColor; + SkPoint fOffset; + SkScalar fOuterRadius; + SkScalar fBlurRadius; + }; + + static void FillInOverstrokeVerts(CircleVertex** verts, const SkRect& bounds, SkScalar smInset, + SkScalar bigInset, SkScalar xOffset, SkScalar outerRadius, + GrColor color, SkScalar blurRadius) { + SkASSERT(smInset < bigInset); + + // TL + (*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fTop + smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fBlurRadius = blurRadius; + (*verts)++; + + // TR + (*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fTop + smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fBlurRadius = blurRadius; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fTop + bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fBlurRadius = blurRadius; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fTop + bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fBlurRadius = blurRadius; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fBottom - bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fBlurRadius = blurRadius; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fBottom - bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fBlurRadius = blurRadius; + (*verts)++; + + // BL + (*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fBottom - smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fBlurRadius = blurRadius; + (*verts)++; + + // BR + (*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fBottom - smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fBlurRadius = blurRadius; + (*verts)++; + } + + void onPrepareDraws(Target* target) const override { + // Invert the view matrix as a local matrix (if any other processors require coords). + SkMatrix localMatrix; + if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { + return; + } + + // Setup geometry processor + sk_sp gp(GrRRectShadowGeoProc::Make(localMatrix)); + + int instanceCount = fGeoData.count(); + size_t vertexStride = gp->getVertexStride(); + SkASSERT(sizeof(CircleVertex) == vertexStride); + + const GrBuffer* vertexBuffer; + int firstVertex; + + CircleVertex* verts = (CircleVertex*)target->makeVertexSpace(vertexStride, fVertCount, + &vertexBuffer, &firstVertex); + if (!verts) { + SkDebugf("Could not allocate vertices\n"); + return; + } + + const GrBuffer* indexBuffer = nullptr; + int firstIndex = 0; + uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex); + if (!indices) { + SkDebugf("Could not allocate indices\n"); + return; + } + + int currStartVertex = 0; + for (int i = 0; i < instanceCount; i++) { + const Geometry& args = fGeoData[i]; + + GrColor color = args.fColor; + SkScalar outerRadius = args.fOuterRadius; + + const SkRect& bounds = args.fDevBounds; + + SkScalar yCoords[4] = {bounds.fTop, bounds.fTop + outerRadius, + bounds.fBottom - outerRadius, bounds.fBottom}; + + SkScalar yOuterRadii[4] = {-1, 0, 0, 1}; + // The inner radius in the vertex data must be specified in normalized space. + // For fills, specifying -1/outerRadius guarantees an alpha of 1.0 at the inner radius. + SkScalar blurRadius = args.fBlurRadius; + for (int i = 0; i < 4; ++i) { + verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); + verts->fColor = color; + verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]); + verts->fOuterRadius = outerRadius; + verts->fBlurRadius = blurRadius; + verts++; + + verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]); + verts->fColor = color; + verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); + verts->fOuterRadius = outerRadius; + verts->fBlurRadius = blurRadius; + verts++; + + verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]); + verts->fColor = color; + verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); + verts->fOuterRadius = outerRadius; + verts->fBlurRadius = blurRadius; + verts++; + + verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); + verts->fColor = color; + verts->fOffset = SkPoint::Make(1, yOuterRadii[i]); + verts->fOuterRadius = outerRadius; + verts->fBlurRadius = blurRadius; + verts++; + } + // Add the additional vertices for overstroked rrects. + // Effectively this is an additional stroked rrect, with its + // outer radius = outerRadius - innerRadius, and inner radius = 0. + // This will give us correct AA in the center and the correct + // distance to the outer edge. + // + // Also, the outer offset is a constant vector pointing to the right, which + // guarantees that the distance value along the outer rectangle is constant. + if (kOverstroke_RRectType == args.fType) { + SkASSERT(args.fInnerRadius <= 0.0f); + + SkScalar overstrokeOuterRadius = outerRadius - args.fInnerRadius; + // this is the normalized distance from the outer rectangle of this + // geometry to the outer edge + SkScalar maxOffset = -args.fInnerRadius / overstrokeOuterRadius; + + FillInOverstrokeVerts(&verts, bounds, outerRadius, overstrokeOuterRadius, maxOffset, + overstrokeOuterRadius, color, blurRadius); + } + + if (kFill_RRectType == args.fType) { + SkScalar halfMinDim = 0.5f * SkTMin(bounds.width(), bounds.height()); + + SkScalar xOffset = 1.0f - outerRadius / halfMinDim; + + FillInOverstrokeVerts(&verts, bounds, outerRadius, halfMinDim, xOffset, halfMinDim, + color, blurRadius); + } + + const uint16_t* primIndices = rrect_type_to_indices(args.fType); + const int primIndexCount = rrect_type_to_index_count(args.fType); + for (int i = 0; i < primIndexCount; ++i) { + *indices++ = primIndices[i] + currStartVertex; + } + + currStartVertex += rrect_type_to_vert_count(args.fType); + } + + GrMesh mesh; + mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex, + firstIndex, fVertCount, fIndexCount); + target->draw(gp.get(), this->pipeline(), mesh); + } + + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + ShadowCircularRRectOp* that = t->cast(); + if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), + that->bounds(), caps)) { + return false; + } + + if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) { + return false; + } + + fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); + this->joinBounds(*that); + fVertCount += that->fVertCount; + fIndexCount += that->fIndexCount; + return true; + } + + struct Geometry { + GrColor fColor; + SkScalar fOuterRadius; + SkScalar fInnerRadius; + SkScalar fBlurRadius; + SkRect fDevBounds; + RRectType fType; + }; + + SkSTArray<1, Geometry, true> fGeoData; + SkMatrix fViewMatrixIfUsingLocalCoords; + int fVertCount; + int fIndexCount; + + typedef GrLegacyMeshDrawOp INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +std::unique_ptr make_shadow_circle_op(GrColor color, + const SkMatrix& viewMatrix, + const SkRect& oval, + SkScalar blurRadius, + const SkStrokeRec& stroke, + const GrShaderCaps* shaderCaps) { + // we can only draw circles + SkScalar width = oval.width(); + SkASSERT(SkScalarNearlyEqual(width, oval.height()) && viewMatrix.isSimilarity()); + SkPoint center = {oval.centerX(), oval.centerY()}; + return ShadowCircleOp::Make(color, viewMatrix, center, width / 2.f, blurRadius, + GrStyle(stroke, nullptr)); +} + +static std::unique_ptr make_shadow_rrect_op(GrColor color, + const SkMatrix& viewMatrix, + const SkRRect& rrect, + SkScalar blurRadius, + const SkStrokeRec& stroke) { + SkASSERT(viewMatrix.rectStaysRect()); + SkASSERT(rrect.isSimple()); + SkASSERT(!rrect.isOval()); + + // Shadow rrect ops only handle simple circular rrects. + // Do any matrix crunching before we reset the draw state for device coords. + const SkRect& rrectBounds = rrect.getBounds(); + SkRect bounds; + viewMatrix.mapRect(&bounds, rrectBounds); + + SkVector radii = rrect.getSimpleRadii(); + SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX] * radii.fX + + viewMatrix[SkMatrix::kMSkewY] * radii.fY); + SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX] * radii.fX + + viewMatrix[SkMatrix::kMScaleY] * radii.fY); + SkASSERT(SkScalarNearlyEqual(xRadius, yRadius)); + + SkStrokeRec::Style style = stroke.getStyle(); + + // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill-only draws. + SkVector scaledStroke = {-1, -1}; + SkScalar strokeWidth = stroke.getWidth(); + + bool isStrokeOnly = + SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style; + bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; + + if (hasStroke) { + if (SkStrokeRec::kHairline_Style == style) { + scaledStroke.set(1, 1); + } else { + scaledStroke.fX = SkScalarAbs( + strokeWidth * (viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewY])); + scaledStroke.fY = SkScalarAbs( + strokeWidth * (viewMatrix[SkMatrix::kMSkewX] + viewMatrix[SkMatrix::kMScaleY])); + } + + // we don't handle anisotropic strokes + if (!SkScalarNearlyEqual(scaledStroke.fX, scaledStroke.fY)) { + return nullptr; + } + } + + // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on + // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine- + // patch will have fractional coverage. This only matters when the interior is actually filled. + // We could consider falling back to rect rendering here, since a tiny radius is + // indistinguishable from a square corner. + if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) { + return nullptr; + } + + return std::unique_ptr(new ShadowCircularRRectOp( + color, viewMatrix, bounds, xRadius, blurRadius, scaledStroke.fX, isStrokeOnly)); +} + +namespace GrShadowRRectOp { +std::unique_ptr Make(GrColor color, + const SkMatrix& viewMatrix, + const SkRRect& rrect, + const SkScalar blurRadius, + const SkStrokeRec& stroke, + const GrShaderCaps* shaderCaps) { + if (rrect.isOval()) { + return make_shadow_circle_op(color, viewMatrix, rrect.getBounds(), blurRadius, stroke, + shaderCaps); + } + + if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) { + return nullptr; + } + + return make_shadow_rrect_op(color, viewMatrix, rrect, blurRadius, stroke); +} +} +/////////////////////////////////////////////////////////////////////////////// + +#if GR_TEST_UTILS + +DRAW_OP_TEST_DEFINE(ShadowCircleOp) { + do { + SkScalar rotate = random->nextSScalar1() * 360.f; + SkScalar translateX = random->nextSScalar1() * 1000.f; + SkScalar translateY = random->nextSScalar1() * 1000.f; + SkScalar scale = random->nextSScalar1() * 100.f; + SkMatrix viewMatrix; + viewMatrix.setRotate(rotate); + viewMatrix.postTranslate(translateX, translateY); + viewMatrix.postScale(scale, scale); + GrColor color = GrRandomColor(random); + SkRect circle = GrTest::TestSquare(random); + SkPoint center = {circle.centerX(), circle.centerY()}; + SkScalar radius = circle.width() / 2.f; + SkStrokeRec stroke = GrTest::TestStrokeRec(random); + SkScalar blurRadius = random->nextSScalar1() * 72.f; + std::unique_ptr op = ShadowCircleOp::Make( + color, viewMatrix, center, radius, blurRadius, GrStyle(stroke, nullptr)); + if (op) { + return op; + } + } while (true); +} + +DRAW_OP_TEST_DEFINE(ShadowRRectOp) { + SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); + GrColor color = GrRandomColor(random); + const SkRRect& rrect = GrTest::TestRRectSimple(random); + SkScalar blurRadius = random->nextSScalar1() * 72.f; + return make_shadow_rrect_op(color, viewMatrix, rrect, blurRadius, + GrTest::TestStrokeRec(random)); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrShadowRRectOp.h b/gfx/skia/skia/src/gpu/ops/GrShadowRRectOp.h new file mode 100644 index 000000000000..9b9993e5bec6 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrShadowRRectOp.h @@ -0,0 +1,27 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrShadowRRectOp_DEFINED +#define GrShadowRRectOp_DEFINED + +#include "GrColor.h" +#include "SkRefCnt.h" + +class GrLegacyMeshDrawOp; +class GrShaderCaps; +class SkMatrix; +class SkRRect; +class SkStrokeRec; + +namespace GrShadowRRectOp { + +std::unique_ptr Make(GrColor, const SkMatrix& viewMatrix, const SkRRect& rrect, + const SkScalar blurRadius, const SkStrokeRec& stroke, + const GrShaderCaps* shaderCaps); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.cpp b/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.cpp new file mode 100644 index 000000000000..0986a0914138 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.cpp @@ -0,0 +1,845 @@ +/* + * Copyright 2014 Google Inc. + * Copyright 2017 ARM Ltd. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrSmallPathRenderer.h" + +#include "GrBuffer.h" +#include "GrContext.h" +#include "GrDistanceFieldGenFromVector.h" +#include "GrDrawOpTest.h" +#include "GrOpFlushState.h" +#include "GrPipelineBuilder.h" +#include "GrResourceProvider.h" +#include "GrSWMaskHelper.h" +#include "GrSurfacePriv.h" +#include "GrSurfaceProxyPriv.h" +#include "GrTexturePriv.h" +#include "effects/GrBitmapTextGeoProc.h" +#include "effects/GrDistanceFieldGeoProc.h" +#include "ops/GrMeshDrawOp.h" + +#include "SkAutoMalloc.h" +#include "SkDistanceFieldGen.h" +#include "SkPathOps.h" + +#define ATLAS_TEXTURE_WIDTH 2048 +#define ATLAS_TEXTURE_HEIGHT 2048 +#define PLOT_WIDTH 512 +#define PLOT_HEIGHT 256 + +#define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) +#define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) + +#ifdef DF_PATH_TRACKING +static int g_NumCachedShapes = 0; +static int g_NumFreedShapes = 0; +#endif + +// mip levels +static const SkScalar kIdealMinMIP = 12; +static const SkScalar kMaxMIP = 162; + +static const SkScalar kMaxDim = 73; +static const SkScalar kMinSize = SK_ScalarHalf; +static const SkScalar kMaxSize = 2*kMaxMIP; + +// Callback to clear out internal path cache when eviction occurs +void GrSmallPathRenderer::HandleEviction(GrDrawOpAtlas::AtlasID id, void* pr) { + GrSmallPathRenderer* dfpr = (GrSmallPathRenderer*)pr; + // remove any paths that use this plot + ShapeDataList::Iter iter; + iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart); + ShapeData* shapeData; + while ((shapeData = iter.get())) { + iter.next(); + if (id == shapeData->fID) { + dfpr->fShapeCache.remove(shapeData->fKey); + dfpr->fShapeList.remove(shapeData); + delete shapeData; +#ifdef DF_PATH_TRACKING + ++g_NumFreedPaths; +#endif + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +GrSmallPathRenderer::GrSmallPathRenderer() : fAtlas(nullptr) {} + +GrSmallPathRenderer::~GrSmallPathRenderer() { + ShapeDataList::Iter iter; + iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart); + ShapeData* shapeData; + while ((shapeData = iter.get())) { + iter.next(); + delete shapeData; + } + +#ifdef DF_PATH_TRACKING + SkDebugf("Cached shapes: %d, freed shapes: %d\n", g_NumCachedShapes, g_NumFreedShapes); +#endif +} + +//////////////////////////////////////////////////////////////////////////////// +bool GrSmallPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { + if (!args.fShaderCaps->shaderDerivativeSupport()) { + return false; + } + // If the shape has no key then we won't get any reuse. + if (!args.fShape->hasUnstyledKey()) { + return false; + } + // This only supports filled paths, however, the caller may apply the style to make a filled + // path and try again. + if (!args.fShape->style().isSimpleFill()) { + return false; + } + // This does non-inverse coverage-based antialiased fills. + if (GrAAType::kCoverage != args.fAAType) { + return false; + } + // TODO: Support inverse fill + if (args.fShape->inverseFilled()) { + return false; + } + // currently don't support perspective + if (args.fViewMatrix->hasPerspective()) { + return false; + } + + // Only support paths with bounds within kMaxDim by kMaxDim, + // scaled to have bounds within kMaxSize by kMaxSize. + // The goal is to accelerate rendering of lots of small paths that may be scaling. + SkScalar scaleFactors[2]; + if (!args.fViewMatrix->getMinMaxScales(scaleFactors)) { + return false; + } + SkRect bounds = args.fShape->styledBounds(); + SkScalar minDim = SkMinScalar(bounds.width(), bounds.height()); + SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); + SkScalar minSize = minDim * SkScalarAbs(scaleFactors[0]); + SkScalar maxSize = maxDim * SkScalarAbs(scaleFactors[1]); + + return maxDim <= kMaxDim && kMinSize <= minSize && maxSize <= kMaxSize; +} + +//////////////////////////////////////////////////////////////////////////////// + +// padding around path bounds to allow for antialiased pixels +static const SkScalar kAntiAliasPad = 1.0f; + +class SmallPathOp final : public GrLegacyMeshDrawOp { +public: + DEFINE_OP_CLASS_ID + + using ShapeData = GrSmallPathRenderer::ShapeData; + using ShapeCache = SkTDynamicHash; + using ShapeDataList = GrSmallPathRenderer::ShapeDataList; + + static std::unique_ptr Make(GrColor color, const GrShape& shape, + const SkMatrix& viewMatrix, + GrDrawOpAtlas* atlas, ShapeCache* shapeCache, + ShapeDataList* shapeList, bool gammaCorrect) { + return std::unique_ptr(new SmallPathOp( + color, shape, viewMatrix, atlas, shapeCache, shapeList, gammaCorrect)); + } + + const char* name() const override { return "SmallPathOp"; } + + SkString dumpInfo() const override { + SkString string; + for (const auto& geo : fShapes) { + string.appendf("Color: 0x%08x\n", geo.fColor); + } + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + SmallPathOp(GrColor color, const GrShape& shape, const SkMatrix& viewMatrix, + GrDrawOpAtlas* atlas, ShapeCache* shapeCache, ShapeDataList* shapeList, + bool gammaCorrect) + : INHERITED(ClassID()) { + SkASSERT(shape.hasUnstyledKey()); + // Compute bounds + this->setTransformedBounds(shape.bounds(), viewMatrix, HasAABloat::kYes, IsZeroArea::kNo); + +#if defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) + fUsesDistanceField = true; +#else + // only use distance fields on desktop and Android framework to save space in the atlas + fUsesDistanceField = this->bounds().width() > kMaxMIP || this->bounds().height() > kMaxMIP; +#endif + fViewMatrix = viewMatrix; + SkVector translate = SkVector::Make(0, 0); + if (!fUsesDistanceField) { + // In this case we don't apply a view matrix, so we need to remove the non-subpixel + // translation and add it back when we generate the quad for the path + SkScalar translateX = viewMatrix.getTranslateX(); + SkScalar translateY = viewMatrix.getTranslateY(); + translate = SkVector::Make(SkScalarFloorToScalar(translateX), + SkScalarFloorToScalar(translateY)); + // Only store the fractional part of the translation in the view matrix + fViewMatrix.setTranslateX(translateX - translate.fX); + fViewMatrix.setTranslateY(translateY - translate.fY); + } + + fShapes.emplace_back(Entry{color, shape, translate}); + + fAtlas = atlas; + fShapeCache = shapeCache; + fShapeList = shapeList; + fGammaCorrect = gammaCorrect; + + } + + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fShapes[0].fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fShapes[0].fColor); + fUsesLocalCoords = optimizations.readsLocalCoords(); + } + + struct FlushInfo { + sk_sp fVertexBuffer; + sk_sp fIndexBuffer; + sk_sp fGeometryProcessor; + int fVertexOffset; + int fInstancesToFlush; + }; + + void onPrepareDraws(Target* target) const override { + int instanceCount = fShapes.count(); + + const SkMatrix& ctm = this->viewMatrix(); + + FlushInfo flushInfo; + + // Setup GrGeometryProcessor + GrDrawOpAtlas* atlas = fAtlas; + if (fUsesDistanceField) { + GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode); + + uint32_t flags = 0; + flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0; + flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; + flags |= fGammaCorrect ? kGammaCorrect_DistanceFieldEffectFlag : 0; + + flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make( + atlas->context()->resourceProvider(), + this->color(), this->viewMatrix(), atlas->getProxy(), params, flags, + this->usesLocalCoords()); + } else { + GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode); + + SkMatrix invert; + if (this->usesLocalCoords()) { + if (!this->viewMatrix().invert(&invert)) { + SkDebugf("Could not invert viewmatrix\n"); + return; + } + // for local coords, we need to add the translation back in that we removed + // from the stored view matrix + invert.preTranslate(-fShapes[0].fTranslate.fX, -fShapes[0].fTranslate.fY); + } + + flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( + atlas->context()->resourceProvider(), + this->color(), atlas->getProxy(), params, kA8_GrMaskFormat, invert, + this->usesLocalCoords()); + } + + // allocate vertices + size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride(); + SkASSERT(vertexStride == sizeof(SkPoint) + sizeof(GrColor) + 2*sizeof(uint16_t)); + + const GrBuffer* vertexBuffer; + void* vertices = target->makeVertexSpace(vertexStride, + kVerticesPerQuad * instanceCount, + &vertexBuffer, + &flushInfo.fVertexOffset); + flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer)); + flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer()); + if (!vertices || !flushInfo.fIndexBuffer) { + SkDebugf("Could not allocate vertices\n"); + return; + } + + flushInfo.fInstancesToFlush = 0; + // Pointer to the next set of vertices to write. + intptr_t offset = reinterpret_cast(vertices); + for (int i = 0; i < instanceCount; i++) { + const Entry& args = fShapes[i]; + + ShapeData* shapeData; + SkScalar maxScale; + if (fUsesDistanceField) { + // get mip level + maxScale = SkScalarAbs(this->viewMatrix().getMaxScale()); + const SkRect& bounds = args.fShape.bounds(); + SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); + // We try to create the DF at a 2^n scaled path resolution (1/2, 1, 2, 4, etc.) + // In the majority of cases this will yield a crisper rendering. + SkScalar mipScale = 1.0f; + // Our mipscale is the maxScale clamped to the next highest power of 2 + if (maxScale <= SK_ScalarHalf) { + SkScalar log = SkScalarFloorToScalar(SkScalarLog2(SkScalarInvert(maxScale))); + mipScale = SkScalarPow(2, -log); + } else if (maxScale > SK_Scalar1) { + SkScalar log = SkScalarCeilToScalar(SkScalarLog2(maxScale)); + mipScale = SkScalarPow(2, log); + } + SkASSERT(maxScale <= mipScale); + + SkScalar mipSize = mipScale*SkScalarAbs(maxDim); + // For sizes less than kIdealMinMIP we want to use as large a distance field as we can + // so we can preserve as much detail as possible. However, we can't scale down more + // than a 1/4 of the size without artifacts. So the idea is that we pick the mipsize + // just bigger than the ideal, and then scale down until we are no more than 4x the + // original mipsize. + if (mipSize < kIdealMinMIP) { + SkScalar newMipSize = mipSize; + do { + newMipSize *= 2; + } while (newMipSize < kIdealMinMIP); + while (newMipSize > 4 * mipSize) { + newMipSize *= 0.25f; + } + mipSize = newMipSize; + } + SkScalar desiredDimension = SkTMin(mipSize, kMaxMIP); + + // check to see if df path is cached + ShapeData::Key key(args.fShape, SkScalarCeilToInt(desiredDimension)); + shapeData = fShapeCache->find(key); + if (nullptr == shapeData || !atlas->hasID(shapeData->fID)) { + // Remove the stale cache entry + if (shapeData) { + fShapeCache->remove(shapeData->fKey); + fShapeList->remove(shapeData); + delete shapeData; + } + SkScalar scale = desiredDimension / maxDim; + + shapeData = new ShapeData; + if (!this->addDFPathToAtlas(target, + &flushInfo, + atlas, + shapeData, + args.fShape, + SkScalarCeilToInt(desiredDimension), + scale)) { + delete shapeData; + SkDebugf("Can't rasterize path\n"); + continue; + } + } + } else { + // check to see if bitmap path is cached + ShapeData::Key key(args.fShape, this->viewMatrix()); + shapeData = fShapeCache->find(key); + if (nullptr == shapeData || !atlas->hasID(shapeData->fID)) { + // Remove the stale cache entry + if (shapeData) { + fShapeCache->remove(shapeData->fKey); + fShapeList->remove(shapeData); + delete shapeData; + } + + shapeData = new ShapeData; + if (!this->addBMPathToAtlas(target, + &flushInfo, + atlas, + shapeData, + args.fShape, + this->viewMatrix())) { + delete shapeData; + SkDebugf("Can't rasterize path\n"); + continue; + } + } + maxScale = 1; + } + + atlas->setLastUseToken(shapeData->fID, target->nextDrawToken()); + + this->writePathVertices(target, + atlas, + offset, + args.fColor, + vertexStride, + maxScale, + args.fTranslate, + shapeData); + offset += kVerticesPerQuad * vertexStride; + flushInfo.fInstancesToFlush++; + } + + this->flush(target, &flushInfo); + } + + bool addDFPathToAtlas(GrLegacyMeshDrawOp::Target* target, FlushInfo* flushInfo, + GrDrawOpAtlas* atlas, ShapeData* shapeData, const GrShape& shape, + uint32_t dimension, SkScalar scale) const { + const SkRect& bounds = shape.bounds(); + + // generate bounding rect for bitmap draw + SkRect scaledBounds = bounds; + // scale to mip level size + scaledBounds.fLeft *= scale; + scaledBounds.fTop *= scale; + scaledBounds.fRight *= scale; + scaledBounds.fBottom *= scale; + // subtract out integer portion of origin + // (SDF created will be placed with fractional offset burnt in) + SkScalar dx = SkScalarFloorToScalar(scaledBounds.fLeft); + SkScalar dy = SkScalarFloorToScalar(scaledBounds.fTop); + scaledBounds.offset(-dx, -dy); + // get integer boundary + SkIRect devPathBounds; + scaledBounds.roundOut(&devPathBounds); + // pad to allow room for antialiasing + const int intPad = SkScalarCeilToInt(kAntiAliasPad); + // place devBounds at origin + int width = devPathBounds.width() + 2*intPad; + int height = devPathBounds.height() + 2*intPad; + devPathBounds = SkIRect::MakeWH(width, height); + + // draw path to bitmap + SkMatrix drawMatrix; + drawMatrix.setScale(scale, scale); + drawMatrix.postTranslate(intPad - dx, intPad - dy); + + SkASSERT(devPathBounds.fLeft == 0); + SkASSERT(devPathBounds.fTop == 0); + SkASSERT(devPathBounds.width() > 0); + SkASSERT(devPathBounds.height() > 0); + + // setup signed distance field storage + SkIRect dfBounds = devPathBounds.makeOutset(SK_DistanceFieldPad, SK_DistanceFieldPad); + width = dfBounds.width(); + height = dfBounds.height(); + // TODO We should really generate this directly into the plot somehow + SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); + + SkPath path; + shape.asPath(&path); +#ifndef SK_USE_LEGACY_DISTANCE_FIELDS + // Generate signed distance field directly from SkPath + bool succeed = GrGenerateDistanceFieldFromPath((unsigned char*)dfStorage.get(), + path, drawMatrix, + width, height, width * sizeof(unsigned char)); + if (!succeed) { +#endif + // setup bitmap backing + SkAutoPixmapStorage dst; + if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), + devPathBounds.height()))) { + return false; + } + sk_bzero(dst.writable_addr(), dst.getSafeSize()); + + // rasterize path + SkPaint paint; + paint.setStyle(SkPaint::kFill_Style); + paint.setAntiAlias(true); + + SkDraw draw; + sk_bzero(&draw, sizeof(draw)); + + SkRasterClip rasterClip; + rasterClip.setRect(devPathBounds); + draw.fRC = &rasterClip; + draw.fMatrix = &drawMatrix; + draw.fDst = dst; + + draw.drawPathCoverage(path, paint); + + // Generate signed distance field + SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), + (const unsigned char*)dst.addr(), + dst.width(), dst.height(), dst.rowBytes()); +#ifndef SK_USE_LEGACY_DISTANCE_FIELDS + } +#endif + + // add to atlas + SkIPoint16 atlasLocation; + GrDrawOpAtlas::AtlasID id; + if (!atlas->addToAtlas(&id, target, width, height, dfStorage.get(), &atlasLocation)) { + this->flush(target, flushInfo); + if (!atlas->addToAtlas(&id, target, width, height, dfStorage.get(), &atlasLocation)) { + return false; + } + } + + // add to cache + shapeData->fKey.set(shape, dimension); + shapeData->fID = id; + + // set the bounds rect to the original bounds + shapeData->fBounds = bounds; + + // set up path to texture coordinate transform + shapeData->fScale = scale; + dx -= SK_DistanceFieldPad + kAntiAliasPad; + dy -= SK_DistanceFieldPad + kAntiAliasPad; + shapeData->fTranslate.fX = atlasLocation.fX - dx; + shapeData->fTranslate.fY = atlasLocation.fY - dy; + + fShapeCache->add(shapeData); + fShapeList->addToTail(shapeData); +#ifdef DF_PATH_TRACKING + ++g_NumCachedPaths; +#endif + return true; + } + + bool addBMPathToAtlas(GrLegacyMeshDrawOp::Target* target, FlushInfo* flushInfo, + GrDrawOpAtlas* atlas, ShapeData* shapeData, const GrShape& shape, + const SkMatrix& ctm) const { + const SkRect& bounds = shape.bounds(); + if (bounds.isEmpty()) { + return false; + } + SkMatrix drawMatrix(ctm); + drawMatrix.set(SkMatrix::kMTransX, SkScalarFraction(ctm.get(SkMatrix::kMTransX))); + drawMatrix.set(SkMatrix::kMTransY, SkScalarFraction(ctm.get(SkMatrix::kMTransY))); + SkRect shapeDevBounds; + drawMatrix.mapRect(&shapeDevBounds, bounds); + SkScalar dx = SkScalarFloorToScalar(shapeDevBounds.fLeft); + SkScalar dy = SkScalarFloorToScalar(shapeDevBounds.fTop); + + // get integer boundary + SkIRect devPathBounds; + shapeDevBounds.roundOut(&devPathBounds); + // pad to allow room for antialiasing + const int intPad = SkScalarCeilToInt(kAntiAliasPad); + // place devBounds at origin + int width = devPathBounds.width() + 2 * intPad; + int height = devPathBounds.height() + 2 * intPad; + devPathBounds = SkIRect::MakeWH(width, height); + SkScalar translateX = intPad - dx; + SkScalar translateY = intPad - dy; + + SkASSERT(devPathBounds.fLeft == 0); + SkASSERT(devPathBounds.fTop == 0); + SkASSERT(devPathBounds.width() > 0); + SkASSERT(devPathBounds.height() > 0); + + SkPath path; + shape.asPath(&path); + // setup bitmap backing + SkAutoPixmapStorage dst; + if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), + devPathBounds.height()))) { + return false; + } + sk_bzero(dst.writable_addr(), dst.getSafeSize()); + + // rasterize path + SkPaint paint; + paint.setStyle(SkPaint::kFill_Style); + paint.setAntiAlias(true); + + SkDraw draw; + sk_bzero(&draw, sizeof(draw)); + + SkRasterClip rasterClip; + rasterClip.setRect(devPathBounds); + draw.fRC = &rasterClip; + drawMatrix.postTranslate(translateX, translateY); + draw.fMatrix = &drawMatrix; + draw.fDst = dst; + + draw.drawPathCoverage(path, paint); + + // add to atlas + SkIPoint16 atlasLocation; + GrDrawOpAtlas::AtlasID id; + if (!atlas->addToAtlas(&id, target, dst.width(), dst.height(), dst.addr(), + &atlasLocation)) { + this->flush(target, flushInfo); + if (!atlas->addToAtlas(&id, target, dst.width(), dst.height(), dst.addr(), + &atlasLocation)) { + return false; + } + } + + // add to cache + shapeData->fKey.set(shape, ctm); + shapeData->fID = id; + + // set the bounds rect to the original bounds + shapeData->fBounds = SkRect::Make(devPathBounds); + shapeData->fBounds.offset(-translateX, -translateY); + + // set up path to texture coordinate transform + shapeData->fScale = SK_Scalar1; + shapeData->fTranslate.fX = atlasLocation.fX + translateX; + shapeData->fTranslate.fY = atlasLocation.fY + translateY; + + fShapeCache->add(shapeData); + fShapeList->addToTail(shapeData); +#ifdef DF_PATH_TRACKING + ++g_NumCachedPaths; +#endif + return true; + } + + void writePathVertices(GrDrawOp::Target* target, + GrDrawOpAtlas* atlas, + intptr_t offset, + GrColor color, + size_t vertexStride, + SkScalar maxScale, + const SkVector& preTranslate, + const ShapeData* shapeData) const { + SkPoint* positions = reinterpret_cast(offset); + + SkRect bounds = shapeData->fBounds; + if (fUsesDistanceField) { + // outset bounds to include ~1 pixel of AA in device space + SkScalar outset = SkScalarInvert(maxScale); + bounds.outset(outset, outset); + } + + // vertex positions + // TODO make the vertex attributes a struct + positions->setRectFan(bounds.left() + preTranslate.fX, + bounds.top() + preTranslate.fY, + bounds.right() + preTranslate.fX, + bounds.bottom() + preTranslate.fY, + vertexStride); + + // colors + for (int i = 0; i < kVerticesPerQuad; i++) { + GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertexStride); + *colorPtr = color; + } + + // set up texture coordinates + SkScalar texLeft = bounds.fLeft; + SkScalar texTop = bounds.fTop; + SkScalar texRight = bounds.fRight; + SkScalar texBottom = bounds.fBottom; + + // transform original path's bounds to texture space + SkScalar scale = shapeData->fScale; + const SkVector& translate = shapeData->fTranslate; + texLeft *= scale; + texTop *= scale; + texRight *= scale; + texBottom *= scale; + texLeft += translate.fX; + texTop += translate.fY; + texRight += translate.fX; + texBottom += translate.fY; + + // convert texcoords to unsigned short format + sk_sp proxy = atlas->getProxy(); + + // The proxy must be functionally exact for this normalization to work correctly + SkASSERT(GrResourceProvider::IsFunctionallyExact(proxy.get())); + SkScalar uFactor = 65535.f / proxy->width(); + SkScalar vFactor = 65535.f / proxy->height(); + uint16_t l = (uint16_t)(texLeft*uFactor); + uint16_t t = (uint16_t)(texTop*vFactor); + uint16_t r = (uint16_t)(texRight*uFactor); + uint16_t b = (uint16_t)(texBottom*vFactor); + + // set vertex texture coords + intptr_t textureCoordOffset = offset + sizeof(SkPoint) + sizeof(GrColor); + uint16_t* textureCoords = (uint16_t*) textureCoordOffset; + textureCoords[0] = l; + textureCoords[1] = t; + textureCoordOffset += vertexStride; + textureCoords = (uint16_t*)textureCoordOffset; + textureCoords[0] = l; + textureCoords[1] = b; + textureCoordOffset += vertexStride; + textureCoords = (uint16_t*)textureCoordOffset; + textureCoords[0] = r; + textureCoords[1] = b; + textureCoordOffset += vertexStride; + textureCoords = (uint16_t*)textureCoordOffset; + textureCoords[0] = r; + textureCoords[1] = t; + } + + void flush(GrLegacyMeshDrawOp::Target* target, FlushInfo* flushInfo) const { + if (flushInfo->fInstancesToFlush) { + GrMesh mesh; + int maxInstancesPerDraw = + static_cast(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6); + mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer.get(), + flushInfo->fIndexBuffer.get(), flushInfo->fVertexOffset, kVerticesPerQuad, + kIndicesPerQuad, flushInfo->fInstancesToFlush, maxInstancesPerDraw); + target->draw(flushInfo->fGeometryProcessor.get(), this->pipeline(), mesh); + flushInfo->fVertexOffset += kVerticesPerQuad * flushInfo->fInstancesToFlush; + flushInfo->fInstancesToFlush = 0; + } + } + + GrColor color() const { return fShapes[0].fColor; } + const SkMatrix& viewMatrix() const { return fViewMatrix; } + bool usesLocalCoords() const { return fUsesLocalCoords; } + bool usesDistanceField() const { return fUsesDistanceField; } + + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + SmallPathOp* that = t->cast(); + if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), + that->bounds(), caps)) { + return false; + } + + if (this->usesDistanceField() != that->usesDistanceField()) { + return false; + } + + // TODO We can position on the cpu for distance field paths + if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { + return false; + } + + if (!this->usesDistanceField() && this->usesLocalCoords() && + !this->fShapes[0].fTranslate.equalsWithinTolerance(that->fShapes[0].fTranslate)) { + return false; + } + + fShapes.push_back_n(that->fShapes.count(), that->fShapes.begin()); + this->joinBounds(*that); + return true; + } + + SkMatrix fViewMatrix; + bool fUsesLocalCoords; + bool fUsesDistanceField; + + struct Entry { + GrColor fColor; + GrShape fShape; + SkVector fTranslate; + }; + + SkSTArray<1, Entry> fShapes; + GrDrawOpAtlas* fAtlas; + ShapeCache* fShapeCache; + ShapeDataList* fShapeList; + bool fGammaCorrect; + + typedef GrLegacyMeshDrawOp INHERITED; +}; + +bool GrSmallPathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), + "GrSmallPathRenderer::onDrawPath"); + + // we've already bailed on inverse filled paths, so this is safe + SkASSERT(!args.fShape->isEmpty()); + SkASSERT(args.fShape->hasUnstyledKey()); + if (!fAtlas) { + fAtlas = GrDrawOpAtlas::Make(args.fContext, + kAlpha_8_GrPixelConfig, + ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT, + NUM_PLOTS_X, NUM_PLOTS_Y, + &GrSmallPathRenderer::HandleEviction, + (void*)this); + if (!fAtlas) { + return false; + } + } + + std::unique_ptr op = + SmallPathOp::Make(args.fPaint.getColor(), *args.fShape, *args.fViewMatrix, fAtlas.get(), + &fShapeCache, &fShapeList, args.fGammaCorrect); + GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), args.fAAType); + pipelineBuilder.setUserStencil(args.fUserStencilSettings); + + args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip, + std::move(op)); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#if GR_TEST_UTILS + +struct PathTestStruct { + typedef GrSmallPathRenderer::ShapeCache ShapeCache; + typedef GrSmallPathRenderer::ShapeData ShapeData; + typedef GrSmallPathRenderer::ShapeDataList ShapeDataList; + PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {} + ~PathTestStruct() { this->reset(); } + + void reset() { + ShapeDataList::Iter iter; + iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart); + ShapeData* shapeData; + while ((shapeData = iter.get())) { + iter.next(); + fShapeList.remove(shapeData); + delete shapeData; + } + fAtlas = nullptr; + fShapeCache.reset(); + } + + static void HandleEviction(GrDrawOpAtlas::AtlasID id, void* pr) { + PathTestStruct* dfpr = (PathTestStruct*)pr; + // remove any paths that use this plot + ShapeDataList::Iter iter; + iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart); + ShapeData* shapeData; + while ((shapeData = iter.get())) { + iter.next(); + if (id == shapeData->fID) { + dfpr->fShapeCache.remove(shapeData->fKey); + dfpr->fShapeList.remove(shapeData); + delete shapeData; + } + } + } + + uint32_t fContextID; + std::unique_ptr fAtlas; + ShapeCache fShapeCache; + ShapeDataList fShapeList; +}; + +DRAW_OP_TEST_DEFINE(SmallPathOp) { + static PathTestStruct gTestStruct; + + if (context->uniqueID() != gTestStruct.fContextID) { + gTestStruct.fContextID = context->uniqueID(); + gTestStruct.reset(); + gTestStruct.fAtlas = GrDrawOpAtlas::Make(context, kAlpha_8_GrPixelConfig, + ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT, + NUM_PLOTS_X, NUM_PLOTS_Y, + &PathTestStruct::HandleEviction, + (void*)&gTestStruct); + } + + SkMatrix viewMatrix = GrTest::TestMatrix(random); + GrColor color = GrRandomColor(random); + bool gammaCorrect = random->nextBool(); + + // This path renderer only allows fill styles. + GrShape shape(GrTest::TestPath(random), GrStyle::SimpleFill()); + + return SmallPathOp::Make(color, shape, viewMatrix, gTestStruct.fAtlas.get(), + &gTestStruct.fShapeCache, &gTestStruct.fShapeList, gammaCorrect); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.h b/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.h new file mode 100644 index 000000000000..d43da8381c99 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.h @@ -0,0 +1,136 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSmallPathRenderer_DEFINED +#define GrSmallPathRenderer_DEFINED + +#include "GrDrawOpAtlas.h" +#include "GrPathRenderer.h" +#include "GrRect.h" +#include "GrShape.h" + +#include "SkOpts.h" +#include "SkTDynamicHash.h" + +class GrContext; + +class GrSmallPathRenderer : public GrPathRenderer { +public: + GrSmallPathRenderer(); + ~GrSmallPathRenderer() override; + +private: + StencilSupport onGetStencilSupport(const GrShape&) const override { + return GrPathRenderer::kNoSupport_StencilSupport; + } + + bool onCanDrawPath(const CanDrawPathArgs&) const override; + + bool onDrawPath(const DrawPathArgs&) override; + + struct ShapeData { + class Key { + public: + Key() {} + Key(const Key& that) { *this = that; } + Key(const GrShape& shape, uint32_t dim) { this->set(shape, dim); } + Key(const GrShape& shape, const SkMatrix& ctm) { this->set(shape, ctm); } + + Key& operator=(const Key& that) { + fKey.reset(that.fKey.count()); + memcpy(fKey.get(), that.fKey.get(), fKey.count() * sizeof(uint32_t)); + return *this; + } + + void set(const GrShape& shape, uint32_t dim) { + // Shapes' keys are for their pre-style geometry, but by now we shouldn't have any + // relevant styling information. + SkASSERT(shape.style().isSimpleFill()); + SkASSERT(shape.hasUnstyledKey()); + int shapeKeySize = shape.unstyledKeySize(); + fKey.reset(1 + shapeKeySize); + fKey[0] = dim; + shape.writeUnstyledKey(&fKey[1]); + } + + void set(const GrShape& shape, const SkMatrix& ctm) { + GrUniqueKey maskKey; + struct KeyData { + SkScalar fFractionalTranslateX; + SkScalar fFractionalTranslateY; + }; + + // Shapes' keys are for their pre-style geometry, but by now we shouldn't have any + // relevant styling information. + SkASSERT(shape.style().isSimpleFill()); + SkASSERT(shape.hasUnstyledKey()); + // We require the upper left 2x2 of the matrix to match exactly for a cache hit. + SkScalar sx = ctm.get(SkMatrix::kMScaleX); + SkScalar sy = ctm.get(SkMatrix::kMScaleY); + SkScalar kx = ctm.get(SkMatrix::kMSkewX); + SkScalar ky = ctm.get(SkMatrix::kMSkewY); + SkScalar tx = ctm.get(SkMatrix::kMTransX); + SkScalar ty = ctm.get(SkMatrix::kMTransY); + // Allow 8 bits each in x and y of subpixel positioning. + SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00; + SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00; + int shapeKeySize = shape.unstyledKeySize(); + fKey.reset(5 + shapeKeySize); + fKey[0] = SkFloat2Bits(sx); + fKey[1] = SkFloat2Bits(sy); + fKey[2] = SkFloat2Bits(kx); + fKey[3] = SkFloat2Bits(ky); + fKey[4] = fracX | (fracY >> 8); + shape.writeUnstyledKey(&fKey[5]); + } + + bool operator==(const Key& that) const { + return fKey.count() == that.fKey.count() && + 0 == memcmp(fKey.get(), that.fKey.get(), sizeof(uint32_t) * fKey.count()); + } + + int count32() const { return fKey.count(); } + const uint32_t* data() const { return fKey.get(); } + + private: + // The key is composed of the GrShape's key, and either the dimensions of the DF + // generated for the path (32x32 max, 64x64 max, 128x128 max) if an SDF image or + // the matrix for the path with only fractional translation. + SkAutoSTArray<24, uint32_t> fKey; + }; + Key fKey; + GrDrawOpAtlas::AtlasID fID; + SkRect fBounds; + SkScalar fScale; + SkVector fTranslate; + SK_DECLARE_INTERNAL_LLIST_INTERFACE(ShapeData); + + static inline const Key& GetKey(const ShapeData& data) { + return data.fKey; + } + + static inline uint32_t Hash(Key key) { + return SkOpts::hash(key.data(), sizeof(uint32_t) * key.count32()); + } + }; + + static void HandleEviction(GrDrawOpAtlas::AtlasID, void*); + + typedef SkTDynamicHash ShapeCache; + typedef SkTInternalLList ShapeDataList; + + std::unique_ptr fAtlas; + ShapeCache fShapeCache; + ShapeDataList fShapeList; + + typedef GrPathRenderer INHERITED; + + friend class SmallPathOp; + friend struct PathTestStruct; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp b/gfx/skia/skia/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp similarity index 61% rename from gfx/skia/skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp rename to gfx/skia/skia/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp index 3bbd1574a94c..bd5c297cd8bd 100644 --- a/gfx/skia/skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp @@ -5,21 +5,20 @@ * found in the LICENSE file. */ - #include "GrStencilAndCoverPathRenderer.h" #include "GrCaps.h" #include "GrContext.h" -#include "GrDrawContextPriv.h" -#include "GrDrawPathBatch.h" +#include "GrDrawPathOp.h" #include "GrFixedClip.h" #include "GrGpu.h" #include "GrPath.h" #include "GrPipelineBuilder.h" #include "GrRenderTarget.h" +#include "GrRenderTargetContextPriv.h" #include "GrResourceProvider.h" -#include "GrStencilPathBatch.h" +#include "GrStencilPathOp.h" #include "GrStyle.h" -#include "batches/GrRectBatchFactory.h" +#include "ops/GrRectOpFactory.h" GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider, const GrCaps& caps) { @@ -44,11 +43,8 @@ bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c if (args.fHasUserStencilSettings) { return false; } - if (args.fAntiAlias) { - return args.fIsStencilBufferMSAA; - } else { - return true; // doesn't do per-path AA, relies on the target having MSAA - } + // doesn't do per-path AA, relies on the target having MSAA. + return (GrAAType::kCoverage != args.fAAType); } static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const GrShape& shape) { @@ -78,31 +74,29 @@ static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const GrShape& } void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrStencilAndCoverPathRenderer::onStencilPath"); - SkASSERT(!args.fIsAA || args.fDrawContext->isStencilBufferMultisampled()); - - SkAutoTUnref p(get_gr_path(fResourceProvider, *args.fShape)); - args.fDrawContext->drawContextPriv().stencilPath(*args.fClip, args.fIsAA, *args.fViewMatrix, p); + sk_sp p(get_gr_path(fResourceProvider, *args.fShape)); + args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType, + *args.fViewMatrix, p.get()); } bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrStencilAndCoverPathRenderer::onDrawPath"); - SkASSERT(!args.fPaint->isAntiAlias() || args.fDrawContext->isStencilBufferMultisampled()); SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle()); const SkMatrix& viewMatrix = *args.fViewMatrix; - SkAutoTUnref path(get_gr_path(fResourceProvider, *args.fShape)); + sk_sp path(get_gr_path(fResourceProvider, *args.fShape)); if (args.fShape->inverseFilled()) { SkMatrix invert = SkMatrix::I(); SkRect bounds = SkRect::MakeLTRB(0, 0, - SkIntToScalar(args.fDrawContext->width()), - SkIntToScalar(args.fDrawContext->height())); + SkIntToScalar(args.fRenderTargetContext->width()), + SkIntToScalar(args.fRenderTargetContext->height())); SkMatrix vmi; // mapRect through persp matrix may not be correct if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { @@ -118,13 +112,12 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { } const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix; - SkAutoTUnref coverBatch( - GrRectBatchFactory::CreateNonAAFill(args.fPaint->getColor(), viewM, bounds, - nullptr, &invert)); + std::unique_ptr coverOp(GrRectOpFactory::MakeNonAAFill( + args.fPaint.getColor(), viewM, bounds, nullptr, &invert)); // fake inverse with a stencil and cover - args.fDrawContext->drawContextPriv().stencilPath(*args.fClip, args.fPaint->isAntiAlias(), - viewMatrix, path); + args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType, viewMatrix, + path.get()); { static constexpr GrUserStencilSettings kInvertedCoverPass( @@ -139,36 +132,22 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { GrUserStencilOp::kZero, 0xffff>() ); - - GrPipelineBuilder pipelineBuilder(*args.fPaint, - args.fPaint->isAntiAlias() && - !args.fDrawContext->hasMixedSamples()); + // We have to suppress enabling MSAA for mixed samples or we will get seams due to + // coverage modulation along the edge where two triangles making up the rect meet. + GrAAType coverAAType = args.fAAType; + if (GrAAType::kMixedSamples == coverAAType) { + coverAAType = GrAAType::kNone; + } + GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), coverAAType); pipelineBuilder.setUserStencil(&kInvertedCoverPass); - args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, coverBatch); + args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip, + std::move(coverOp)); } } else { - static constexpr GrUserStencilSettings kCoverPass( - GrUserStencilSettings::StaticInit< - 0x0000, - GrUserStencilTest::kNotEqual, - 0xffff, - GrUserStencilOp::kZero, - GrUserStencilOp::kKeep, - 0xffff>() - ); - - SkAutoTUnref batch(GrDrawPathBatch::Create(viewMatrix, args.fPaint->getColor(), - path)); - - GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fPaint->isAntiAlias()); - pipelineBuilder.setUserStencil(&kCoverPass); - if (args.fAntiAlias) { - SkASSERT(args.fDrawContext->isStencilBufferMultisampled()); - pipelineBuilder.enableState(GrPipelineBuilder::kHWAntialias_Flag); - } - - args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); + std::unique_ptr op = + GrDrawPathOp::Make(viewMatrix, std::move(args.fPaint), args.fAAType, path.get()); + args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); } return true; diff --git a/gfx/skia/skia/src/gpu/batches/GrStencilAndCoverPathRenderer.h b/gfx/skia/skia/src/gpu/ops/GrStencilAndCoverPathRenderer.h similarity index 100% rename from gfx/skia/skia/src/gpu/batches/GrStencilAndCoverPathRenderer.h rename to gfx/skia/skia/src/gpu/ops/GrStencilAndCoverPathRenderer.h diff --git a/gfx/skia/skia/src/gpu/ops/GrStencilPathOp.h b/gfx/skia/skia/src/gpu/ops/GrStencilPathOp.h new file mode 100644 index 000000000000..93357f74fc41 --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrStencilPathOp.h @@ -0,0 +1,102 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrStencilPathOp_DEFINED +#define GrStencilPathOp_DEFINED + +#include "GrGpu.h" +#include "GrOp.h" +#include "GrOpFlushState.h" +#include "GrPath.h" +#include "GrPathRendering.h" +#include "GrRenderTarget.h" +#include "GrStencilSettings.h" + +class GrStencilPathOp final : public GrOp { +public: + DEFINE_OP_CLASS_ID + + // MDB TODO: replace the renderTargetContext with just the renderTargetProxy. + // For now, we need the renderTargetContext for its accessRenderTarget powers. + static std::unique_ptr Make(const SkMatrix& viewMatrix, + bool useHWAA, + GrPathRendering::FillType fillType, + bool hasStencilClip, + int numStencilBits, + const GrScissorState& scissor, + GrRenderTargetContext* renderTargetContext, + const GrPath* path) { + + // MDB TODO: remove this. In this hybrid state we need to be sure the RT is instantiable + // so it can carry the IO refs. In the future we will just get the proxy and + // it will carry the IO refs. + if (!renderTargetContext->accessRenderTarget()) { + return nullptr; + } + + return std::unique_ptr(new GrStencilPathOp(viewMatrix, useHWAA, fillType, + hasStencilClip, numStencilBits, scissor, + renderTargetContext, path)); + } + + const char* name() const override { return "StencilPathOp"; } + + SkString dumpInfo() const override { + SkString string; + string.printf("Path: 0x%p, AA: %d", fPath.get(), fUseHWAA); + string.appendf("rtID: %d proxyID: %d", + fRenderTarget.get()->uniqueID().asUInt(), fProxyUniqueID.asUInt()); + string.append(INHERITED::dumpInfo()); + return string; + } + +private: + GrStencilPathOp(const SkMatrix& viewMatrix, + bool useHWAA, + GrPathRendering::FillType fillType, + bool hasStencilClip, + int numStencilBits, + const GrScissorState& scissor, + GrRenderTargetContext* renderTargetContext, + const GrPath* path) + : INHERITED(ClassID()) + , fViewMatrix(viewMatrix) + , fUseHWAA(useHWAA) + , fStencil(GrPathRendering::GetStencilPassSettings(fillType), hasStencilClip, + numStencilBits) + , fScissor(scissor) + , fProxyUniqueID(renderTargetContext->asSurfaceProxy()->uniqueID()) + , fPath(path) { + this->setBounds(path->getBounds(), HasAABloat::kNo, IsZeroArea::kNo); + + fRenderTarget.reset(renderTargetContext->accessRenderTarget()); + } + + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { return false; } + + void onPrepare(GrOpFlushState*) override {} + + void onExecute(GrOpFlushState* state) override { + // MDB TODO: instantiate the renderTarget from the proxy in here + GrPathRendering::StencilPathArgs args(fUseHWAA, fRenderTarget.get(), &fViewMatrix, + &fScissor, &fStencil); + state->gpu()->pathRendering()->stencilPath(args, fPath.get()); + } + + SkMatrix fViewMatrix; + bool fUseHWAA; + GrStencilSettings fStencil; + GrScissorState fScissor; + // MDB TODO: remove this. When the renderTargetProxy carries the refs this will be redundant. + GrSurfaceProxy::UniqueID fProxyUniqueID; + GrPendingIOResource fRenderTarget; + GrPendingIOResource fPath; + + typedef GrOp INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/batches/GrTessellatingPathRenderer.cpp b/gfx/skia/skia/src/gpu/ops/GrTessellatingPathRenderer.cpp similarity index 72% rename from gfx/skia/skia/src/gpu/batches/GrTessellatingPathRenderer.cpp rename to gfx/skia/skia/src/gpu/ops/GrTessellatingPathRenderer.cpp index 57eac3c4b245..059d8314c41a 100644 --- a/gfx/skia/skia/src/gpu/batches/GrTessellatingPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/ops/GrTessellatingPathRenderer.cpp @@ -8,12 +8,11 @@ #include "GrTessellatingPathRenderer.h" #include "GrAuditTrail.h" -#include "GrBatchFlushState.h" -#include "GrBatchTest.h" #include "GrClip.h" #include "GrDefaultGeoProcFactory.h" -#include "GrDrawTarget.h" +#include "GrDrawOpTest.h" #include "GrMesh.h" +#include "GrOpFlushState.h" #include "GrPathUtils.h" #include "GrPipelineBuilder.h" #include "GrResourceCache.h" @@ -21,7 +20,7 @@ #include "GrTessellator.h" #include "SkGeometry.h" -#include "batches/GrVertexBatch.h" +#include "ops/GrMeshDrawOp.h" #include @@ -96,7 +95,7 @@ public: } GrBuffer* vertexBuffer() { return fVertexBuffer.get(); } private: - SkAutoTUnref fVertexBuffer; + sk_sp fVertexBuffer; GrResourceProvider* fResourceProvider; bool fCanMapVB; void* fVertices; @@ -104,12 +103,11 @@ private: class DynamicVertexAllocator : public GrTessellator::VertexAllocator { public: - DynamicVertexAllocator(size_t stride, GrVertexBatch::Target* target) - : VertexAllocator(stride) - , fTarget(target) - , fVertexBuffer(nullptr) - , fVertices(nullptr) { - } + DynamicVertexAllocator(size_t stride, GrLegacyMeshDrawOp::Target* target) + : VertexAllocator(stride) + , fTarget(target) + , fVertexBuffer(nullptr) + , fVertices(nullptr) {} void* lock(int vertexCount) override { fVertexCount = vertexCount; fVertices = fTarget->makeVertexSpace(stride(), vertexCount, &fVertexBuffer, &fFirstVertex); @@ -122,7 +120,7 @@ public: const GrBuffer* vertexBuffer() const { return fVertexBuffer; } int firstVertex() const { return fFirstVertex; } private: - GrVertexBatch::Target* fTarget; + GrLegacyMeshDrawOp::Target* fTarget; const GrBuffer* fVertexBuffer; int fVertexCount; int fFirstVertex; @@ -145,7 +143,7 @@ bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) { return false; } - if (args.fAntiAlias) { + if (GrAAType::kCoverage == args.fAAType) { #ifdef SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER return false; #else @@ -161,35 +159,40 @@ bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons return true; } -class TessellatingPathBatch : public GrVertexBatch { +class TessellatingPathOp final : public GrLegacyMeshDrawOp { public: - DEFINE_BATCH_CLASS_ID + DEFINE_OP_CLASS_ID - static GrDrawBatch* Create(const GrColor& color, - const GrShape& shape, - const SkMatrix& viewMatrix, - SkIRect devClipBounds, - bool antiAlias) { - return new TessellatingPathBatch(color, shape, viewMatrix, devClipBounds, antiAlias); + static std::unique_ptr Make(const GrColor& color, + const GrShape& shape, + const SkMatrix& viewMatrix, + SkIRect devClipBounds, + bool antiAlias) { + return std::unique_ptr( + new TessellatingPathOp(color, shape, viewMatrix, devClipBounds, antiAlias)); } - const char* name() const override { return "TessellatingPathBatch"; } + const char* name() const override { return "TessellatingPathOp"; } - void computePipelineOptimizations(GrInitInvariantOutput* color, - GrInitInvariantOutput* coverage, - GrBatchToXPOverrides* overrides) const override { - color->setKnownFourComponents(fColor); - coverage->setUnknownSingleComponent(); + SkString dumpInfo() const override { + SkString string; + string.appendf("Color 0x%08x, aa: %d\n", fColor, fAntiAlias); + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; } private: - void initBatchTracker(const GrXPOverridesForBatch& overrides) override { - // Handle any color overrides - if (!overrides.readsColor()) { - fColor = GrColor_ILLEGAL; - } - overrides.getOverrideColorIfSet(&fColor); - fPipelineInfo = overrides; + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fColor); + fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage(); + fNeedsLocalCoords = optimizations.readsLocalCoords(); } SkPath getPath() const { @@ -218,7 +221,7 @@ private: memset(&builder[shapeKeyDataCnt], 0, sizeof(fDevClipBounds)); } builder.finish(); - SkAutoTUnref cachedVertexBuffer(rp->findAndRefTByUniqueKey(key)); + sk_sp cachedVertexBuffer(rp->findAndRefTByUniqueKey(key)); int actualCount; SkScalar tol = GrPathUtils::kDefaultTolerance; tol = GrPathUtils::scaleToleranceToSrc(tol, fViewMatrix, fShape.bounds()); @@ -261,9 +264,8 @@ private: SkScalar tol = GrPathUtils::kDefaultTolerance; bool isLinear; DynamicVertexAllocator allocator(gp->getVertexStride(), target); - bool canTweakAlphaForCoverage = fPipelineInfo.canTweakAlphaForCoverage(); int count = GrTessellator::PathToTriangles(path, tol, clipBounds, &allocator, - true, fColor, canTweakAlphaForCoverage, + true, fColor, fCanTweakAlphaForCoverage, &isLinear); if (count == 0) { return; @@ -277,30 +279,31 @@ private: using namespace GrDefaultGeoProcFactory; Color color(fColor); - LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? - LocalCoords::kUsePosition_Type : - LocalCoords::kUnused_Type); + LocalCoords::Type localCoordsType = fNeedsLocalCoords + ? LocalCoords::kUsePosition_Type + : LocalCoords::kUnused_Type; Coverage::Type coverageType; if (fAntiAlias) { - color = Color(Color::kAttribute_Type); - if (fPipelineInfo.canTweakAlphaForCoverage()) { + color = Color(Color::kPremulGrColorAttribute_Type); + if (fCanTweakAlphaForCoverage) { coverageType = Coverage::kSolid_Type; } else { coverageType = Coverage::kAttribute_Type; } - } else if (fPipelineInfo.readsCoverage()) { + } else { coverageType = Coverage::kSolid_Type; - } else { - coverageType = Coverage::kNone_Type; } - Coverage coverage(coverageType); if (fAntiAlias) { - gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(color, coverage, localCoords, - fViewMatrix); + gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(color, coverageType, + localCoordsType, fViewMatrix); } else { - gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fViewMatrix); + gp = GrDefaultGeoProcFactory::Make(color, coverageType, localCoordsType, + fViewMatrix); } } + if (!gp.get()) { + return; + } if (fAntiAlias) { this->drawAA(target, gp.get()); } else { @@ -314,22 +317,22 @@ private: : kTriangles_GrPrimitiveType; GrMesh mesh; mesh.init(primitiveType, vb, firstVertex, count); - target->draw(gp, mesh); + target->draw(gp, this->pipeline(), mesh); } - bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } + bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; } - TessellatingPathBatch(const GrColor& color, - const GrShape& shape, - const SkMatrix& viewMatrix, - const SkIRect& devClipBounds, - bool antiAlias) - : INHERITED(ClassID()) - , fColor(color) - , fShape(shape) - , fViewMatrix(viewMatrix) - , fDevClipBounds(devClipBounds) - , fAntiAlias(antiAlias) { + TessellatingPathOp(const GrColor& color, + const GrShape& shape, + const SkMatrix& viewMatrix, + const SkIRect& devClipBounds, + bool antiAlias) + : INHERITED(ClassID()) + , fColor(color) + , fShape(shape) + , fViewMatrix(viewMatrix) + , fDevClipBounds(devClipBounds) + , fAntiAlias(antiAlias) { SkRect devBounds; viewMatrix.mapRect(&devBounds, shape.bounds()); if (shape.inverseFilled()) { @@ -345,36 +348,37 @@ private: SkMatrix fViewMatrix; SkIRect fDevClipBounds; bool fAntiAlias; - GrXPOverridesForBatch fPipelineInfo; + bool fCanTweakAlphaForCoverage; + bool fNeedsLocalCoords; - typedef GrVertexBatch INHERITED; + typedef GrLegacyMeshDrawOp INHERITED; }; bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { - GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), + GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrTessellatingPathRenderer::onDrawPath"); SkIRect clipBoundsI; - args.fClip->getConservativeBounds(args.fDrawContext->width(), args.fDrawContext->height(), + args.fClip->getConservativeBounds(args.fRenderTargetContext->width(), + args.fRenderTargetContext->height(), &clipBoundsI); - SkAutoTUnref batch(TessellatingPathBatch::Create(args.fPaint->getColor(), - *args.fShape, - *args.fViewMatrix, - clipBoundsI, - args.fAntiAlias)); - - GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHWAA(*args.fPaint)); + std::unique_ptr op = + TessellatingPathOp::Make(args.fPaint.getColor(), + *args.fShape, + *args.fViewMatrix, + clipBoundsI, + GrAAType::kCoverage == args.fAAType); + GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), args.fAAType); pipelineBuilder.setUserStencil(args.fUserStencilSettings); - - args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); - + args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip, + std::move(op)); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { +DRAW_OP_TEST_DEFINE(TesselatingPathOp) { GrColor color = GrRandomColor(random); SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); SkPath path = GrTest::TestPath(random); @@ -387,7 +391,7 @@ DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { GrTest::TestStyle(random, &style); } while (!style.isSimpleFill()); GrShape shape(path, style); - return TessellatingPathBatch::Create(color, shape, viewMatrix, devClipBounds, antiAlias); + return TessellatingPathOp::Make(color, shape, viewMatrix, devClipBounds, antiAlias); } #endif diff --git a/gfx/skia/skia/src/gpu/batches/GrTessellatingPathRenderer.h b/gfx/skia/skia/src/gpu/ops/GrTessellatingPathRenderer.h similarity index 100% rename from gfx/skia/skia/src/gpu/batches/GrTessellatingPathRenderer.h rename to gfx/skia/skia/src/gpu/ops/GrTessellatingPathRenderer.h diff --git a/gfx/skia/skia/src/gpu/ops/GrTestMeshDrawOp.h b/gfx/skia/skia/src/gpu/ops/GrTestMeshDrawOp.h new file mode 100644 index 000000000000..aad6774eb20b --- /dev/null +++ b/gfx/skia/skia/src/gpu/ops/GrTestMeshDrawOp.h @@ -0,0 +1,55 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTestMeshDrawOp_DEFINED +#define GrTestMeshDrawOp_DEFINED + +#include "GrGeometryProcessor.h" +#include "GrOpFlushState.h" + +#include "ops/GrMeshDrawOp.h" + +/* + * A simple solid color GrLegacyMeshDrawOp for testing purposes which doesn't ever combine. + * Subclassing this in tests saves having to fill out some boiler plate methods. + */ +class GrTestMeshDrawOp : public GrLegacyMeshDrawOp { +public: + const char* name() const override = 0; + +protected: + GrTestMeshDrawOp(uint32_t classID, const SkRect& bounds, GrColor color) + : INHERITED(classID), fColor(color) { + // Choose some conservative values for aa bloat and zero area. + this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kYes); + } + + GrColor color() const { return fColor; } + + bool usesLocalCoords() const { return fUsesLocalCoords; } + +private: + void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color, + GrProcessorAnalysisCoverage* coverage) const override { + color->setToConstant(fColor); + *coverage = GrProcessorAnalysisCoverage::kSingleChannel; + } + + void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override { + optimizations.getOverrideColorIfSet(&fColor); + fUsesLocalCoords = optimizations.readsLocalCoords(); + } + + bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; } + + GrColor fColor; + bool fUsesLocalCoords = false; + + typedef GrLegacyMeshDrawOp INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/text/GrBatchFontCache.cpp b/gfx/skia/skia/src/gpu/text/GrAtlasGlyphCache.cpp similarity index 66% rename from gfx/skia/skia/src/gpu/text/GrBatchFontCache.cpp rename to gfx/skia/skia/src/gpu/text/GrAtlasGlyphCache.cpp index 3e212cd1713b..213ecfc3dab7 100644 --- a/gfx/skia/skia/src/gpu/text/GrBatchFontCache.cpp +++ b/gfx/skia/skia/src/gpu/text/GrAtlasGlyphCache.cpp @@ -5,17 +5,19 @@ * found in the LICENSE file. */ -#include "GrBatchFontCache.h" +#include "GrAtlasGlyphCache.h" #include "GrContext.h" #include "GrGpu.h" #include "GrRectanizer.h" #include "GrResourceProvider.h" #include "GrSurfacePriv.h" +#include "SkAutoMalloc.h" #include "SkString.h" #include "SkDistanceFieldGen.h" +#include "GrDistanceFieldGenFromVector.h" -bool GrBatchFontCache::initAtlas(GrMaskFormat format) { +bool GrAtlasGlyphCache::initAtlas(GrMaskFormat format) { int index = MaskFormatToAtlasIndex(format); if (!fAtlases[index]) { GrPixelConfig config = MaskFormatToPixelConfig(format, *fContext->caps()); @@ -24,11 +26,9 @@ bool GrBatchFontCache::initAtlas(GrMaskFormat format) { int numPlotsX = fAtlasConfigs[index].numPlotsX(); int numPlotsY = fAtlasConfigs[index].numPlotsY(); - fAtlases[index] = - fContext->resourceProvider()->createAtlas(config, width, height, - numPlotsX, numPlotsY, - &GrBatchFontCache::HandleEviction, - (void*)this); + fAtlases[index] = GrDrawOpAtlas::Make( + fContext, config, width, height, numPlotsX, numPlotsY, + &GrAtlasGlyphCache::HandleEviction, (void*)this); if (!fAtlases[index]) { return false; } @@ -36,12 +36,9 @@ bool GrBatchFontCache::initAtlas(GrMaskFormat format) { return true; } -GrBatchFontCache::GrBatchFontCache(GrContext* context) +GrAtlasGlyphCache::GrAtlasGlyphCache(GrContext* context) : fContext(context) , fPreserveStrike(nullptr) { - for (int i = 0; i < kMaskFormatCount; ++i) { - fAtlases[i] = nullptr; - } // setup default atlas configs fAtlasConfigs[kA8_GrMaskFormat].fWidth = 2048; @@ -66,19 +63,16 @@ GrBatchFontCache::GrBatchFontCache(GrContext* context) fAtlasConfigs[kARGB_GrMaskFormat].fPlotHeight = 256; } -GrBatchFontCache::~GrBatchFontCache() { +GrAtlasGlyphCache::~GrAtlasGlyphCache() { StrikeHash::Iter iter(&fCache); while (!iter.done()) { (*iter).fIsAbandoned = true; (*iter).unref(); ++iter; } - for (int i = 0; i < kMaskFormatCount; ++i) { - delete fAtlases[i]; - } } -void GrBatchFontCache::freeAll() { +void GrAtlasGlyphCache::freeAll() { StrikeHash::Iter iter(&fCache); while (!iter.done()) { (*iter).fIsAbandoned = true; @@ -87,56 +81,113 @@ void GrBatchFontCache::freeAll() { } fCache.rewind(); for (int i = 0; i < kMaskFormatCount; ++i) { - delete fAtlases[i]; fAtlases[i] = nullptr; } } -void GrBatchFontCache::HandleEviction(GrBatchAtlas::AtlasID id, void* ptr) { - GrBatchFontCache* fontCache = reinterpret_cast(ptr); +void GrAtlasGlyphCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) { + GrAtlasGlyphCache* fontCache = reinterpret_cast(ptr); StrikeHash::Iter iter(&fontCache->fCache); for (; !iter.done(); ++iter) { - GrBatchTextStrike* strike = &*iter; + GrAtlasTextStrike* strike = &*iter; strike->removeID(id); // clear out any empty strikes. We will preserve the strike whose call to addToAtlas // triggered the eviction if (strike != fontCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) { - fontCache->fCache.remove(GrBatchTextStrike::GetKey(*strike)); + fontCache->fCache.remove(GrAtlasTextStrike::GetKey(*strike)); strike->fIsAbandoned = true; strike->unref(); } } } -void GrBatchFontCache::dump() const { +#ifdef SK_DEBUG +#include "GrContextPriv.h" +#include "GrSurfaceProxy.h" +#include "GrSurfaceContext.h" +#include "GrTextureProxy.h" + +#include "SkBitmap.h" +#include "SkImageEncoder.h" +#include "SkStream.h" +#include + +/** + * Write the contents of the surface proxy to a PNG. Returns true if successful. + * @param filename Full path to desired file + */ +static bool save_pixels(GrContext* context, GrSurfaceProxy* sProxy, const char* filename) { + if (!sProxy) { + return false; + } + + SkImageInfo ii = SkImageInfo::Make(sProxy->width(), sProxy->height(), + kRGBA_8888_SkColorType, kPremul_SkAlphaType); + SkBitmap bm; + if (!bm.tryAllocPixels(ii)) { + return false; + } + + sk_sp sContext(context->contextPriv().makeWrappedSurfaceContext( + sk_ref_sp(sProxy), + nullptr)); + if (!sContext || !sContext->asTextureProxy()) { + return false; + } + + bool result = sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), 0, 0); + if (!result) { + SkDebugf("------ failed to read pixels for %s\n", filename); + return false; + } + + // remove any previous version of this file + remove(filename); + + SkFILEWStream file(filename); + if (!file.isValid()) { + SkDebugf("------ failed to create file: %s\n", filename); + remove(filename); // remove any partial file + return false; + } + + if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) { + SkDebugf("------ failed to encode %s\n", filename); + remove(filename); // remove any partial file + return false; + } + + return true; +} + +void GrAtlasGlyphCache::dump() const { static int gDumpCount = 0; for (int i = 0; i < kMaskFormatCount; ++i) { if (fAtlases[i]) { - GrTexture* texture = fAtlases[i]->getTexture(); - if (texture) { + sk_sp proxy = fAtlases[i]->getProxy(); + if (proxy) { SkString filename; #ifdef SK_BUILD_FOR_ANDROID filename.printf("/sdcard/fontcache_%d%d.png", gDumpCount, i); #else filename.printf("fontcache_%d%d.png", gDumpCount, i); #endif - texture->surfacePriv().savePixels(filename.c_str()); + + save_pixels(fContext, proxy.get(), filename.c_str()); } } } ++gDumpCount; } +#endif -void GrBatchFontCache::setAtlasSizes_ForTesting(const GrBatchAtlasConfig configs[3]) { - // delete any old atlases, this should be safe to do as long as we are not in the middle of a - // flush +void GrAtlasGlyphCache::setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]) { + // Delete any old atlases. + // This should be safe to do as long as we are not in the middle of a flush. for (int i = 0; i < kMaskFormatCount; i++) { - if (fAtlases[i]) { - delete fAtlases[i]; - fAtlases[i] = nullptr; - } + fAtlases[i] = nullptr; } memcpy(fAtlasConfigs, configs, sizeof(fAtlasConfigs)); } @@ -269,29 +320,57 @@ static bool get_packed_glyph_df_image(SkGlyphCache* cache, const SkGlyph& glyph, int width, int height, void* dst) { SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width); SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height); - const void* image = cache->findImage(glyph); - if (nullptr == image) { - return false; - } - // now generate the distance field - SkASSERT(dst); - SkMask::Format maskFormat = static_cast(glyph.fMaskFormat); - if (SkMask::kA8_Format == maskFormat) { - // make the distance field from the image - SkGenerateDistanceFieldFromA8Image((unsigned char*)dst, - (unsigned char*)image, - glyph.fWidth, glyph.fHeight, - glyph.rowBytes()); - } else if (SkMask::kBW_Format == maskFormat) { - // make the distance field from the image - SkGenerateDistanceFieldFromBWImage((unsigned char*)dst, - (unsigned char*)image, - glyph.fWidth, glyph.fHeight, - glyph.rowBytes()); - } else { + +#ifndef SK_USE_LEGACY_DISTANCE_FIELDS + const SkPath* path = cache->findPath(glyph); + if (nullptr == path) { return false; } + SkDEBUGCODE(SkRect glyphBounds = SkRect::MakeXYWH(glyph.fLeft, + glyph.fTop, + glyph.fWidth, + glyph.fHeight)); + SkASSERT(glyphBounds.contains(path->getBounds())); + + // now generate the distance field + SkASSERT(dst); + SkMatrix drawMatrix; + drawMatrix.setTranslate((SkScalar)-glyph.fLeft, (SkScalar)-glyph.fTop); + + // Generate signed distance field directly from SkPath + bool succeed = GrGenerateDistanceFieldFromPath((unsigned char*)dst, + *path, drawMatrix, + width, height, width * sizeof(unsigned char)); + + if (!succeed) { +#endif + const void* image = cache->findImage(glyph); + if (nullptr == image) { + return false; + } + + // now generate the distance field + SkASSERT(dst); + SkMask::Format maskFormat = static_cast(glyph.fMaskFormat); + if (SkMask::kA8_Format == maskFormat) { + // make the distance field from the image + SkGenerateDistanceFieldFromA8Image((unsigned char*)dst, + (unsigned char*)image, + glyph.fWidth, glyph.fHeight, + glyph.rowBytes()); + } else if (SkMask::kBW_Format == maskFormat) { + // make the distance field from the image + SkGenerateDistanceFieldFromBWImage((unsigned char*)dst, + (unsigned char*)image, + glyph.fWidth, glyph.fHeight, + glyph.rowBytes()); + } else { + return false; + } +#ifndef SK_USE_LEGACY_DISTANCE_FIELDS + } +#endif return true; } @@ -305,14 +384,14 @@ static bool get_packed_glyph_df_image(SkGlyphCache* cache, const SkGlyph& glyph, atlas and a position within that texture. */ -GrBatchTextStrike::GrBatchTextStrike(GrBatchFontCache* owner, const SkDescriptor& key) +GrAtlasTextStrike::GrAtlasTextStrike(GrAtlasGlyphCache* owner, const SkDescriptor& key) : fFontScalerKey(key) , fPool(9/*start allocations at 512 bytes*/) - , fBatchFontCache(owner) // no need to ref, it won't go away before we do + , fAtlasGlyphCache(owner) // no need to ref, it won't go away before we do , fAtlasedGlyphs(0) , fIsAbandoned(false) {} -GrBatchTextStrike::~GrBatchTextStrike() { +GrAtlasTextStrike::~GrAtlasTextStrike() { SkTDynamicHash::Iter iter(&fCache); while (!iter.done()) { (*iter).reset(); @@ -320,7 +399,7 @@ GrBatchTextStrike::~GrBatchTextStrike() { } } -GrGlyph* GrBatchTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed, +GrGlyph* GrAtlasTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed, SkGlyphCache* cache) { SkIRect bounds; if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(packed)) { @@ -340,11 +419,11 @@ GrGlyph* GrBatchTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::Packe return glyph; } -void GrBatchTextStrike::removeID(GrBatchAtlas::AtlasID id) { +void GrAtlasTextStrike::removeID(GrDrawOpAtlas::AtlasID id) { SkTDynamicHash::Iter iter(&fCache); while (!iter.done()) { if (id == (*iter).fID) { - (*iter).fID = GrBatchAtlas::kInvalidAtlasID; + (*iter).fID = GrDrawOpAtlas::kInvalidAtlasID; fAtlasedGlyphs--; SkASSERT(fAtlasedGlyphs >= 0); } @@ -352,7 +431,7 @@ void GrBatchTextStrike::removeID(GrBatchAtlas::AtlasID id) { } } -bool GrBatchTextStrike::addGlyphToAtlas(GrDrawBatch::Target* target, +bool GrAtlasTextStrike::addGlyphToAtlas(GrDrawOp::Target* target, GrGlyph* glyph, SkGlyphCache* cache, GrMaskFormat expectedMaskFormat) { @@ -379,11 +458,11 @@ bool GrBatchTextStrike::addGlyphToAtlas(GrDrawBatch::Target* target, } } - bool success = fBatchFontCache->addToAtlas(this, &glyph->fID, target, expectedMaskFormat, + bool success = fAtlasGlyphCache->addToAtlas(this, &glyph->fID, target, expectedMaskFormat, glyph->width(), glyph->height(), storage.get(), &glyph->fAtlasLocation); if (success) { - SkASSERT(GrBatchAtlas::kInvalidAtlasID != glyph->fID); + SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID); fAtlasedGlyphs++; } return success; diff --git a/gfx/skia/skia/src/gpu/text/GrBatchFontCache.h b/gfx/skia/skia/src/gpu/text/GrAtlasGlyphCache.h similarity index 65% rename from gfx/skia/skia/src/gpu/text/GrBatchFontCache.h rename to gfx/skia/skia/src/gpu/text/GrAtlasGlyphCache.h index 9e08c5303f57..9e97966952d5 100644 --- a/gfx/skia/skia/src/gpu/text/GrBatchFontCache.h +++ b/gfx/skia/skia/src/gpu/text/GrAtlasGlyphCache.h @@ -5,31 +5,31 @@ * found in the LICENSE file. */ -#ifndef GrBatchFontCache_DEFINED -#define GrBatchFontCache_DEFINED +#ifndef GrAtlasGlyphCache_DEFINED +#define GrAtlasGlyphCache_DEFINED -#include "GrBatchAtlas.h" #include "GrCaps.h" +#include "GrDrawOpAtlas.h" #include "GrGlyph.h" #include "SkGlyphCache.h" #include "SkTDynamicHash.h" #include "SkVarAlloc.h" -class GrBatchFontCache; +class GrAtlasGlyphCache; class GrGpu; /** - * The GrBatchTextStrike manages a pool of CPU backing memory for GrGlyphs. This backing memory + * The GrAtlasTextStrike manages a pool of CPU backing memory for GrGlyphs. This backing memory * is indexed by a PackedID and SkGlyphCache. The SkGlyphCache is what actually creates the mask. - * The GrBatchTextStrike may outlive the generating SkGlyphCache. However, it retains a copy - * of it's SkDescriptor as a key to access (or regenerate) the SkGlyphCache. GrBatchTextStrikes are - * created by and owned by a GrBatchFontCache. + * The GrAtlasTextStrike may outlive the generating SkGlyphCache. However, it retains a copy + * of it's SkDescriptor as a key to access (or regenerate) the SkGlyphCache. GrAtlasTextStrike are + * created by and owned by a GrAtlasGlyphCache. */ -class GrBatchTextStrike : public SkNVRefCnt { +class GrAtlasTextStrike : public SkNVRefCnt { public: /** Owner is the cache that owns this strike. */ - GrBatchTextStrike(GrBatchFontCache* owner, const SkDescriptor& fontScalerKey); - ~GrBatchTextStrike(); + GrAtlasTextStrike(GrAtlasGlyphCache* owner, const SkDescriptor& fontScalerKey); + ~GrAtlasTextStrike(); inline GrGlyph* getGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed, SkGlyphCache* cache) { @@ -40,7 +40,7 @@ public: return glyph; } - // This variant of the above function is called by TextBatch. At this point, it is possible + // This variant of the above function is called by GrAtlasTextOp. At this point, it is possible // that the maskformat of the glyph differs from what we expect. In these cases we will just // draw a clear square. // skbug:4143 crbug:510931 @@ -64,19 +64,19 @@ public: // happen. // TODO we can handle some of these cases if we really want to, but the long term solution is to // get the actual glyph image itself when we get the glyph metrics. - bool addGlyphToAtlas(GrDrawBatch::Target*, GrGlyph*, SkGlyphCache*, + bool addGlyphToAtlas(GrDrawOp::Target*, GrGlyph*, SkGlyphCache*, GrMaskFormat expectedMaskFormat); // testing int countGlyphs() const { return fCache.count(); } // remove any references to this plot - void removeID(GrBatchAtlas::AtlasID); + void removeID(GrDrawOpAtlas::AtlasID); // If a TextStrike is abandoned by the cache, then the caller must get a new strike bool isAbandoned() const { return fIsAbandoned; } - static const SkDescriptor& GetKey(const GrBatchTextStrike& ts) { + static const SkDescriptor& GetKey(const GrAtlasTextStrike& ts) { return *ts.fFontScalerKey.getDesc(); } @@ -87,7 +87,7 @@ private: SkAutoDescriptor fFontScalerKey; SkVarAlloc fPool; - GrBatchFontCache* fBatchFontCache; + GrAtlasGlyphCache* fAtlasGlyphCache; int fAtlasedGlyphs; bool fIsAbandoned; @@ -99,27 +99,25 @@ private: GrGlyph* generateGlyph(const SkGlyph&, GrGlyph::PackedID, SkGlyphCache*); - friend class GrBatchFontCache; + friend class GrAtlasGlyphCache; }; -/* - * GrBatchFontCache manages strikes which are indexed by a SkGlyphCache. These strikes can then be - * used to individual Glyph Masks. The GrBatchFontCache also manages GrBatchAtlases, though this is - * more or less transparent to the client(aside from atlasGeneration, described below). - * Note - we used to initialize the backing atlas for the GrBatchFontCache at initialization time. - * However, this caused a regression, even when the GrBatchFontCache was unused. We now initialize - * the backing atlases lazily. Its not immediately clear why this improves the situation. +/** + * GrAtlasGlyphCache manages strikes which are indexed by a SkGlyphCache. These strikes can then be + * used to generate individual Glyph Masks. The GrAtlasGlyphCache also manages GrDrawOpAtlases, + * though this is more or less transparent to the client(aside from atlasGeneration, described + * below). */ -class GrBatchFontCache { +class GrAtlasGlyphCache { public: - GrBatchFontCache(GrContext*); - ~GrBatchFontCache(); + GrAtlasGlyphCache(GrContext*); + ~GrAtlasGlyphCache(); // The user of the cache may hold a long-lived ref to the returned strike. However, actions by // another client of the cache may cause the strike to be purged while it is still reffed. - // Therefore, the caller must check GrBatchTextStrike::isAbandoned() if there are other + // Therefore, the caller must check GrAtlasTextStrike::isAbandoned() if there are other // interactions with the cache since the strike was received. - inline GrBatchTextStrike* getStrike(const SkGlyphCache* cache) { - GrBatchTextStrike* strike = fCache.find(cache->getDescriptor()); + inline GrAtlasTextStrike* getStrike(const SkGlyphCache* cache) { + GrAtlasTextStrike* strike = fCache.find(cache->getDescriptor()); if (nullptr == strike) { strike = this->generateStrike(cache); } @@ -128,12 +126,12 @@ public: void freeAll(); - // if getTexture returns nullptr, the client must not try to use other functions on the - // GrBatchFontCache which use the atlas. This function *must* be called first, before other + // if getProxy returns nullptr, the client must not try to use other functions on the + // GrAtlasGlyphCache which use the atlas. This function *must* be called first, before other // functions which use the atlas. - GrTexture* getTexture(GrMaskFormat format) { + sk_sp getProxy(GrMaskFormat format) { if (this->initAtlas(format)) { - return this->getAtlas(format)->getTexture(); + return this->getAtlas(format)->getProxy(); } return nullptr; } @@ -143,27 +141,26 @@ public: return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID); } - // To ensure the GrBatchAtlas does not evict the Glyph Mask from its texture backing store, - // the client must pass in the current batch token along with the GrGlyph. + // To ensure the GrDrawOpAtlas does not evict the Glyph Mask from its texture backing store, + // the client must pass in the current op token along with the GrGlyph. // A BulkUseTokenUpdater is used to manage bulk last use token updating in the Atlas. // For convenience, this function will also set the use token for the current glyph if required // NOTE: the bulk uploader is only valid if the subrun has a valid atlasGeneration - void addGlyphToBulkAndSetUseToken(GrBatchAtlas::BulkUseTokenUpdater* updater, - GrGlyph* glyph, GrBatchDrawToken token) { + void addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater* updater, GrGlyph* glyph, + GrDrawOpUploadToken token) { SkASSERT(glyph); updater->add(glyph->fID); this->getAtlas(glyph->fMaskFormat)->setLastUseToken(glyph->fID, token); } - void setUseTokenBulk(const GrBatchAtlas::BulkUseTokenUpdater& updater, - GrBatchDrawToken token, + void setUseTokenBulk(const GrDrawOpAtlas::BulkUseTokenUpdater& updater, + GrDrawOpUploadToken token, GrMaskFormat format) { this->getAtlas(format)->setLastUseTokenBulk(updater, token); } // add to texture atlas that matches this format - bool addToAtlas(GrBatchTextStrike* strike, GrBatchAtlas::AtlasID* id, - GrDrawBatch::Target* target, + bool addToAtlas(GrAtlasTextStrike* strike, GrDrawOpAtlas::AtlasID* id, GrDrawOp::Target* target, GrMaskFormat format, int width, int height, const void* image, SkIPoint16* loc) { fPreserveStrike = strike; @@ -171,8 +168,8 @@ public: } // Some clients may wish to verify the integrity of the texture backing store of the - // GrBatchAtlas. The atlasGeneration returned below is a monitonically increasing number which - // changes everytime something is removed from the texture backing store. + // GrDrawOpAtlas. The atlasGeneration returned below is a monotonically increasing number which + // changes every time something is removed from the texture backing store. uint64_t atlasGeneration(GrMaskFormat format) const { return this->getAtlas(format)->atlasGeneration(); } @@ -182,9 +179,13 @@ public: /////////////////////////////////////////////////////////////////////////// // Functions intended debug only +#ifdef SK_DEBUG void dump() const; +#endif - void setAtlasSizes_ForTesting(const GrBatchAtlasConfig configs[3]); + void setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]); + + GrContext* context() const { return fContext; } private: static GrPixelConfig MaskFormatToPixelConfig(GrMaskFormat format, const GrCaps& caps) { @@ -194,7 +195,7 @@ private: case kA565_GrMaskFormat: return kRGB_565_GrPixelConfig; case kARGB_GrMaskFormat: - return caps.srgbSupport() ? kSkiaGamma8888_GrPixelConfig : kSkia8888_GrPixelConfig; + return caps.srgbSupport() ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig; default: SkDEBUGFAIL("unsupported GrMaskFormat"); return kAlpha_8_GrPixelConfig; @@ -216,26 +217,26 @@ private: bool initAtlas(GrMaskFormat); - GrBatchTextStrike* generateStrike(const SkGlyphCache* cache) { - GrBatchTextStrike* strike = new GrBatchTextStrike(this, cache->getDescriptor()); + GrAtlasTextStrike* generateStrike(const SkGlyphCache* cache) { + GrAtlasTextStrike* strike = new GrAtlasTextStrike(this, cache->getDescriptor()); fCache.add(strike); return strike; } - GrBatchAtlas* getAtlas(GrMaskFormat format) const { + GrDrawOpAtlas* getAtlas(GrMaskFormat format) const { int atlasIndex = MaskFormatToAtlasIndex(format); SkASSERT(fAtlases[atlasIndex]); - return fAtlases[atlasIndex]; + return fAtlases[atlasIndex].get(); } - static void HandleEviction(GrBatchAtlas::AtlasID, void*); + static void HandleEviction(GrDrawOpAtlas::AtlasID, void*); - using StrikeHash = SkTDynamicHash; + using StrikeHash = SkTDynamicHash; GrContext* fContext; StrikeHash fCache; - GrBatchAtlas* fAtlases[kMaskFormatCount]; - GrBatchTextStrike* fPreserveStrike; - GrBatchAtlasConfig fAtlasConfigs[kMaskFormatCount]; + std::unique_ptr fAtlases[kMaskFormatCount]; + GrAtlasTextStrike* fPreserveStrike; + GrDrawOpAtlasConfig fAtlasConfigs[kMaskFormatCount]; }; #endif diff --git a/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.cpp b/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.cpp index 4b7dec7d1f97..d3aa7e49f2a6 100644 --- a/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.cpp +++ b/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.cpp @@ -6,19 +6,18 @@ */ #include "GrAtlasTextBlob.h" - #include "GrBlurUtils.h" #include "GrContext.h" -#include "GrDrawContext.h" #include "GrPipelineBuilder.h" +#include "GrRenderTargetContext.h" #include "GrTextUtils.h" #include "SkColorFilter.h" #include "SkDrawFilter.h" #include "SkGlyphCache.h" #include "SkTextBlobRunIterator.h" -#include "batches/GrAtlasTextBatch.h" +#include "ops/GrAtlasTextOp.h" -GrAtlasTextBlob* GrAtlasTextBlob::Create(GrMemoryPool* pool, int glyphCount, int runCount) { +sk_sp GrAtlasTextBlob::Make(GrMemoryPool* pool, int glyphCount, int runCount) { // We allocate size for the GrAtlasTextBlob itself, plus size for the vertices array, // and size for the glyphIds array. size_t verticesCount = glyphCount * kVerticesPerGlyph * kMaxVASize; @@ -32,11 +31,12 @@ GrAtlasTextBlob* GrAtlasTextBlob::Create(GrMemoryPool* pool, int glyphCount, int sk_bzero(allocation, size); } - GrAtlasTextBlob* cacheBlob = new (allocation) GrAtlasTextBlob; + sk_sp cacheBlob(new (allocation) GrAtlasTextBlob); cacheBlob->fSize = size; // setup offsets for vertices / glyphs - cacheBlob->fVertices = sizeof(GrAtlasTextBlob) + reinterpret_cast(cacheBlob); + cacheBlob->fVertices = sizeof(GrAtlasTextBlob) + + reinterpret_cast(cacheBlob.get()); cacheBlob->fGlyphs = reinterpret_cast(cacheBlob->fVertices + verticesCount); cacheBlob->fRuns = reinterpret_cast(cacheBlob->fGlyphs + glyphCount); @@ -65,23 +65,23 @@ SkGlyphCache* GrAtlasTextBlob::setupCache(int runIndex, run->fPathEffect = sk_ref_sp(effects.fPathEffect); run->fRasterizer = sk_ref_sp(effects.fRasterizer); run->fMaskFilter = sk_ref_sp(effects.fMaskFilter); - return SkGlyphCache::DetachCache(run->fTypeface, effects, desc->getDesc()); + return SkGlyphCache::DetachCache(run->fTypeface.get(), effects, desc->getDesc()); } void GrAtlasTextBlob::appendGlyph(int runIndex, const SkRect& positions, GrColor color, - GrBatchTextStrike* strike, + GrAtlasTextStrike* strike, GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph, - SkScalar x, SkScalar y, SkScalar scale, bool applyVM) { + SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP) { if (positions.isEmpty()) { return; } // If the glyph is too large we fall back to paths if (glyph->fTooLargeForAtlas) { - this->appendLargeGlyph(glyph, cache, skGlyph, x, y, scale, applyVM); + this->appendLargeGlyph(glyph, cache, skGlyph, x, y, scale, treatAsBMP); return; } @@ -160,7 +160,7 @@ void GrAtlasTextBlob::appendGlyph(int runIndex, } void GrAtlasTextBlob::appendLargeGlyph(GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph, - SkScalar x, SkScalar y, SkScalar scale, bool applyVM) { + SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP) { if (nullptr == glyph->fPath) { const SkPath* glyphPath = cache->findPath(skGlyph); if (!glyphPath) { @@ -169,17 +169,17 @@ void GrAtlasTextBlob::appendLargeGlyph(GrGlyph* glyph, SkGlyphCache* cache, cons glyph->fPath = new SkPath(*glyphPath); } - fBigGlyphs.push_back(GrAtlasTextBlob::BigGlyph(*glyph->fPath, x, y, scale, applyVM)); + fBigGlyphs.push_back(GrAtlasTextBlob::BigGlyph(*glyph->fPath, x, y, scale, treatAsBMP)); } -bool GrAtlasTextBlob::mustRegenerate(const SkPaint& paint, - GrColor color, const SkMaskFilter::BlurRec& blurRec, +bool GrAtlasTextBlob::mustRegenerate(const GrTextUtils::Paint& paint, + const SkMaskFilter::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { // If we have LCD text then our canonical color will be set to transparent, in this case we have // to regenerate the blob on any color change // We use the grPaint to get any color filter effects if (fKey.fCanonicalColor == SK_ColorTRANSPARENT && - fPaintColor != color) { + fFilteredPaintColor != paint.filteredSkColor()) { return true; } @@ -201,9 +201,9 @@ bool GrAtlasTextBlob::mustRegenerate(const SkPaint& paint, // Similarly, we only cache one version for each style if (fKey.fStyle != SkPaint::kFill_Style && - (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() || - fStrokeInfo.fMiterLimit != paint.getStrokeMiter() || - fStrokeInfo.fJoin != paint.getStrokeJoin())) { + (fStrokeInfo.fFrameWidth != paint.skPaint().getStrokeWidth() || + fStrokeInfo.fMiterLimit != paint.skPaint().getStrokeMiter() || + fStrokeInfo.fJoin != paint.skPaint().getStrokeJoin())) { return true; } @@ -257,79 +257,60 @@ bool GrAtlasTextBlob::mustRegenerate(const SkPaint& paint, return false; } -inline GrDrawBatch* GrAtlasTextBlob::createBatch( - const Run::SubRunInfo& info, - int glyphCount, int run, int subRun, - const SkMatrix& viewMatrix, SkScalar x, SkScalar y, - GrColor color, - const SkPaint& skPaint, const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - bool useGammaCorrectDistanceTable, - GrBatchFontCache* cache) { +inline std::unique_ptr GrAtlasTextBlob::makeOp( + const Run::SubRunInfo& info, int glyphCount, int run, int subRun, + const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const GrTextUtils::Paint& paint, + const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, + bool useGammaCorrectDistanceTable, GrAtlasGlyphCache* cache) { GrMaskFormat format = info.maskFormat(); - GrColor subRunColor; - if (kARGB_GrMaskFormat == format) { - uint8_t paintAlpha = skPaint.getAlpha(); - subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha); - } else { - subRunColor = color; - } - GrAtlasTextBatch* batch; + std::unique_ptr op; if (info.drawAsDistanceFields()) { - SkColor filteredColor; - SkColorFilter* colorFilter = skPaint.getColorFilter(); - if (colorFilter) { - filteredColor = colorFilter->filterColor(skPaint.getColor()); - } else { - filteredColor = skPaint.getColor(); - } + SkColor filteredColor = paint.filteredSkColor(); bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry()); - batch = GrAtlasTextBatch::CreateDistanceField(glyphCount, cache, - distanceAdjustTable, - useGammaCorrectDistanceTable, - filteredColor, info.hasUseLCDText(), useBGR); + op = GrAtlasTextOp::MakeDistanceField(glyphCount, cache, distanceAdjustTable, + useGammaCorrectDistanceTable, filteredColor, + info.hasUseLCDText(), useBGR); } else { - batch = GrAtlasTextBatch::CreateBitmap(format, glyphCount, cache); + op = GrAtlasTextOp::MakeBitmap(format, glyphCount, cache); } - GrAtlasTextBatch::Geometry& geometry = batch->geometry(); + GrAtlasTextOp::Geometry& geometry = op->geometry(); geometry.fViewMatrix = viewMatrix; geometry.fBlob = SkRef(this); geometry.fRun = run; geometry.fSubRun = subRun; - geometry.fColor = subRunColor; + geometry.fColor = + info.maskFormat() == kARGB_GrMaskFormat ? GrColor_WHITE : paint.filteredPremulGrColor(); geometry.fX = x; geometry.fY = y; - batch->init(); + op->init(); - return batch; + return std::move(op); } -inline -void GrAtlasTextBlob::flushRun(GrDrawContext* dc, const GrPaint& grPaint, - const GrClip& clip, int run, const SkMatrix& viewMatrix, SkScalar x, - SkScalar y, - const SkPaint& skPaint, const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - GrBatchFontCache* cache) { - for (int subRun = 0; subRun < fRuns[run].fSubRunInfo.count(); subRun++) { +inline void GrAtlasTextBlob::flushRun(GrRenderTargetContext* rtc, const GrClip& clip, int run, + const SkMatrix& viewMatrix, SkScalar x, SkScalar y, + const GrTextUtils::Paint& paint, const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + GrAtlasGlyphCache* cache) { + int lastRun = fRuns[run].fSubRunInfo.count() - 1; + for (int subRun = 0; subRun <= lastRun; subRun++) { const Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun]; + GrPaint grPaint; + if (!paint.toGrPaint(info.maskFormat(), rtc, viewMatrix, &grPaint)) { + continue; + } int glyphCount = info.glyphCount(); if (0 == glyphCount) { continue; } - GrColor color = grPaint.getColor(); + std::unique_ptr op( + this->makeOp(info, glyphCount, run, subRun, viewMatrix, x, y, paint, props, + distanceAdjustTable, rtc->isGammaCorrect(), cache)); + GrPipelineBuilder pipelineBuilder(std::move(grPaint), GrAAType::kNone); - SkAutoTUnref batch(this->createBatch(info, glyphCount, run, - subRun, viewMatrix, x, y, color, - skPaint, props, - distanceAdjustTable, dc->isGammaCorrect(), - cache)); - - GrPipelineBuilder pipelineBuilder(grPaint, dc->mustUseHWAA(grPaint)); - - dc->drawBatch(pipelineBuilder, clip, batch); + rtc->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); } } @@ -353,125 +334,104 @@ static void calculate_translation(bool applyVM, } } - -void GrAtlasTextBlob::flushBigGlyphs(GrContext* context, GrDrawContext* dc, - const GrClip& clip, const SkPaint& skPaint, +void GrAtlasTextBlob::flushBigGlyphs(GrContext* context, GrRenderTargetContext* rtc, + const GrClip& clip, const SkPaint& paint, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipBounds) { SkScalar transX, transY; for (int i = 0; i < fBigGlyphs.count(); i++) { GrAtlasTextBlob::BigGlyph& bigGlyph = fBigGlyphs[i]; - calculate_translation(bigGlyph.fApplyVM, viewMatrix, x, y, + calculate_translation(bigGlyph.fTreatAsBMP, viewMatrix, x, y, fInitialViewMatrix, fInitialX, fInitialY, &transX, &transY); SkMatrix ctm; ctm.setScale(bigGlyph.fScale, bigGlyph.fScale); ctm.postTranslate(bigGlyph.fX + transX, bigGlyph.fY + transY); - if (bigGlyph.fApplyVM) { + if (!bigGlyph.fTreatAsBMP) { ctm.postConcat(viewMatrix); } - GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, bigGlyph.fPath, - skPaint, ctm, nullptr, clipBounds, false); + GrBlurUtils::drawPathWithMaskFilter(context, rtc, clip, bigGlyph.fPath, paint, ctm, nullptr, + clipBounds, false); } } -void GrAtlasTextBlob::flushRunAsPaths(GrContext* context, GrDrawContext* dc, - const SkSurfaceProps& props, - const SkTextBlobRunIterator& it, - const GrClip& clip, const SkPaint& skPaint, +void GrAtlasTextBlob::flushRunAsPaths(GrContext* context, GrRenderTargetContext* rtc, + const SkSurfaceProps& props, const SkTextBlobRunIterator& it, + const GrClip& clip, const GrTextUtils::Paint& paint, SkDrawFilter* drawFilter, const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y) { - SkPaint runPaint = skPaint; - size_t textLen = it.glyphCount() * sizeof(uint16_t); const SkPoint& offset = it.offset(); - it.applyFontToPaint(&runPaint); - - if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) { + GrTextUtils::RunPaint runPaint(&paint, drawFilter, props); + if (!runPaint.modifyForRun(it)) { return; } - runPaint.setFlags(GrTextUtils::FilterTextFlags(props, runPaint)); - switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: - GrTextUtils::DrawTextAsPath(context, dc, clip, runPaint, viewMatrix, - (const char *)it.glyphs(), - textLen, x + offset.x(), y + offset.y(), clipBounds); + GrTextUtils::DrawTextAsPath(context, rtc, clip, runPaint, viewMatrix, + (const char*)it.glyphs(), textLen, x + offset.x(), + y + offset.y(), clipBounds); break; case SkTextBlob::kHorizontal_Positioning: - GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, runPaint, viewMatrix, - (const char*)it.glyphs(), - textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), - clipBounds); + GrTextUtils::DrawPosTextAsPath(context, rtc, props, clip, runPaint, viewMatrix, + (const char*)it.glyphs(), textLen, it.pos(), 1, + SkPoint::Make(x, y + offset.y()), clipBounds); break; case SkTextBlob::kFull_Positioning: - GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, runPaint, viewMatrix, - (const char*)it.glyphs(), - textLen, it.pos(), 2, SkPoint::Make(x, y), clipBounds); + GrTextUtils::DrawPosTextAsPath(context, rtc, props, clip, runPaint, viewMatrix, + (const char*)it.glyphs(), textLen, it.pos(), 2, + SkPoint::Make(x, y), clipBounds); break; } } -void GrAtlasTextBlob::flushCached(GrContext* context, - GrDrawContext* dc, - const SkTextBlob* blob, - const SkSurfaceProps& props, +void GrAtlasTextBlob::flushCached(GrContext* context, GrRenderTargetContext* rtc, + const SkTextBlob* blob, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, - const SkPaint& skPaint, - const GrPaint& grPaint, - SkDrawFilter* drawFilter, - const GrClip& clip, - const SkMatrix& viewMatrix, - const SkIRect& clipBounds, - SkScalar x, SkScalar y) { + const GrTextUtils::Paint& paint, SkDrawFilter* drawFilter, + const GrClip& clip, const SkMatrix& viewMatrix, + const SkIRect& clipBounds, SkScalar x, SkScalar y) { // We loop through the runs of the blob, flushing each. If any run is too large, then we flush // it as paths SkTextBlobRunIterator it(blob); for (int run = 0; !it.done(); it.next(), run++) { if (fRuns[run].fDrawAsPaths) { - this->flushRunAsPaths(context, dc, props, it, clip, skPaint, - drawFilter, viewMatrix, clipBounds, x, y); + this->flushRunAsPaths(context, rtc, props, it, clip, paint, drawFilter, viewMatrix, + clipBounds, x, y); continue; } - this->flushRun(dc, grPaint, clip, run, viewMatrix, x, y, skPaint, props, - distanceAdjustTable, context->getBatchFontCache()); + this->flushRun(rtc, clip, run, viewMatrix, x, y, paint, props, distanceAdjustTable, + context->getAtlasGlyphCache()); } // Now flush big glyphs - this->flushBigGlyphs(context, dc, clip, skPaint, viewMatrix, x, y, clipBounds); + this->flushBigGlyphs(context, rtc, clip, paint, viewMatrix, x, y, clipBounds); } -void GrAtlasTextBlob::flushThrowaway(GrContext* context, - GrDrawContext* dc, +void GrAtlasTextBlob::flushThrowaway(GrContext* context, GrRenderTargetContext* rtc, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, - const SkPaint& skPaint, - const GrPaint& grPaint, - const GrClip& clip, - const SkMatrix& viewMatrix, - const SkIRect& clipBounds, + const GrTextUtils::Paint& paint, const GrClip& clip, + const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y) { for (int run = 0; run < fRunCount; run++) { - this->flushRun(dc, grPaint, clip, run, viewMatrix, x, y, skPaint, props, - distanceAdjustTable, context->getBatchFontCache()); + this->flushRun(rtc, clip, run, viewMatrix, x, y, paint, props, distanceAdjustTable, + context->getAtlasGlyphCache()); } // Now flush big glyphs - this->flushBigGlyphs(context, dc, clip, skPaint, viewMatrix, x, y, clipBounds); + this->flushBigGlyphs(context, rtc, clip, paint, viewMatrix, x, y, clipBounds); } -GrDrawBatch* GrAtlasTextBlob::test_createBatch( - int glyphCount, int run, int subRun, - const SkMatrix& viewMatrix, SkScalar x, SkScalar y, - GrColor color, - const SkPaint& skPaint, const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - GrBatchFontCache* cache) { +std::unique_ptr GrAtlasTextBlob::test_makeOp( + int glyphCount, int run, int subRun, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, + const GrTextUtils::Paint& paint, const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, GrAtlasGlyphCache* cache) { const GrAtlasTextBlob::Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun]; - return this->createBatch(info, glyphCount, run, subRun, viewMatrix, x, y, color, skPaint, - props, distanceAdjustTable, false, cache); + return this->makeOp(info, glyphCount, run, subRun, viewMatrix, x, y, paint, props, + distanceAdjustTable, false, cache); } void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlob& r) { @@ -508,7 +468,7 @@ void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlo if (lRun.fTypeface.get()) { SkASSERT_RELEASE(rRun.fTypeface.get()); - SkASSERT_RELEASE(SkTypeface::Equal(lRun.fTypeface, rRun.fTypeface)); + SkASSERT_RELEASE(SkTypeface::Equal(lRun.fTypeface.get(), rRun.fTypeface.get())); } else { SkASSERT_RELEASE(!rRun.fTypeface.get()); } @@ -542,8 +502,8 @@ void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlo if (lSubRun.strike()) { SkASSERT_RELEASE(rSubRun.strike()); - SkASSERT_RELEASE(GrBatchTextStrike::GetKey(*lSubRun.strike()) == - GrBatchTextStrike::GetKey(*rSubRun.strike())); + SkASSERT_RELEASE(GrAtlasTextStrike::GetKey(*lSubRun.strike()) == + GrAtlasTextStrike::GetKey(*rSubRun.strike())); } else { SkASSERT_RELEASE(!rSubRun.strike()); diff --git a/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.h b/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.h index afc11a9bd481..855413bcd140 100644 --- a/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.h +++ b/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.h @@ -8,10 +8,11 @@ #ifndef GrAtlasTextBlob_DEFINED #define GrAtlasTextBlob_DEFINED -#include "GrBatchAtlas.h" -#include "GrBatchFontCache.h" +#include "GrAtlasGlyphCache.h" #include "GrColor.h" +#include "GrDrawOpAtlas.h" #include "GrMemoryPool.h" +#include "GrTextUtils.h" #include "SkDescriptor.h" #include "SkMaskFilter.h" #include "SkOpts.h" @@ -23,6 +24,7 @@ class GrBlobRegenHelper; struct GrDistanceFieldAdjustTable; class GrMemoryPool; +class GrLegacyMeshDrawOp; class SkDrawFilter; class SkTextBlob; class SkTextBlobRunIterator; @@ -49,7 +51,7 @@ class GrAtlasTextBlob : public SkNVRefCnt { public: SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob); - static GrAtlasTextBlob* Create(GrMemoryPool* pool, int glyphCount, int runCount); + static sk_sp Make(GrMemoryPool* pool, int glyphCount, int runCount); struct Key { Key() { @@ -161,10 +163,10 @@ public: void appendGlyph(int runIndex, const SkRect& positions, GrColor color, - GrBatchTextStrike* strike, + GrAtlasTextStrike* strike, GrGlyph* glyph, SkGlyphCache*, const SkGlyph& skGlyph, - SkScalar x, SkScalar y, SkScalar scale, bool applyVM); + SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP); static size_t GetVertexStride(GrMaskFormat maskFormat) { switch (maskFormat) { @@ -177,34 +179,22 @@ public: } } - bool mustRegenerate(const SkPaint& paint, GrColor color, const SkMaskFilter::BlurRec& blurRec, + bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilter::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y); // flush a GrAtlasTextBlob associated with a SkTextBlob - void flushCached(GrContext* context, - GrDrawContext* dc, - const SkTextBlob* blob, + void flushCached(GrContext* context, GrRenderTargetContext* rtc, const SkTextBlob* blob, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, - const SkPaint& skPaint, - const GrPaint& grPaint, - SkDrawFilter* drawFilter, - const GrClip& clip, - const SkMatrix& viewMatrix, - const SkIRect& clipBounds, - SkScalar x, SkScalar y); + const GrTextUtils::Paint&, SkDrawFilter* drawFilter, const GrClip& clip, + const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y); // flush a throwaway GrAtlasTextBlob *not* associated with an SkTextBlob - void flushThrowaway(GrContext* context, - GrDrawContext* dc, - const SkSurfaceProps& props, + void flushThrowaway(GrContext* context, GrRenderTargetContext* rtc, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, - const SkPaint& skPaint, - const GrPaint& grPaint, - const GrClip& clip, - const SkMatrix& viewMatrix, - const SkIRect& clipBounds, - SkScalar x, SkScalar y); + const GrTextUtils::Paint& paint, const GrClip& clip, + const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, + SkScalar y); void computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { @@ -250,8 +240,9 @@ public: // The color here is the GrPaint color, and it is used to determine whether we // have to regenerate LCD text blobs. // We use this color vs the SkPaint color because it has the colorfilter applied. - void initReusableBlob(GrColor color, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { - fPaintColor = color; + void initReusableBlob(SkColor filteredColor, const SkMatrix& viewMatrix, SkScalar x, + SkScalar y) { + fFilteredPaintColor = filteredColor; this->setupViewMatrix(viewMatrix, x, y); } @@ -260,14 +251,14 @@ public: } /** - * Consecutive calls to regenInBatch often use the same SkGlyphCache. If the same instance of - * SkAutoGlyphCache is passed to multiple calls of regenInBatch then it can save the cost of + * Consecutive calls to regenInOp often use the same SkGlyphCache. If the same instance of + * SkAutoGlyphCache is passed to multiple calls of regenInOp then it can save the cost of * multiple detach/attach operations of SkGlyphCache. */ - void regenInBatch(GrDrawBatch::Target* target, GrBatchFontCache* fontCache, - GrBlobRegenHelper *helper, int run, int subRun, SkAutoGlyphCache*, - size_t vertexStride, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, - GrColor color, void** vertices, size_t* byteCount, int* glyphCount); + void regenInOp(GrDrawOp::Target* target, GrAtlasGlyphCache* fontCache, + GrBlobRegenHelper* helper, int run, int subRun, SkAutoGlyphCache*, + size_t vertexStride, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, + GrColor color, void** vertices, size_t* byteCount, int* glyphCount); const Key& key() const { return fKey; } @@ -279,11 +270,10 @@ public: //////////////////////////////////////////////////////////////////////////////////////////////// // Internal test methods - GrDrawBatch* test_createBatch(int glyphCount, int run, int subRun, - const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color, - const SkPaint& skPaint, const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - GrBatchFontCache* cache); + std::unique_ptr test_makeOp( + int glyphCount, int run, int subRun, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, + const GrTextUtils::Paint& paint, const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, GrAtlasGlyphCache* cache); private: GrAtlasTextBlob() @@ -292,24 +282,21 @@ private: , fTextType(0) {} void appendLargeGlyph(GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph, - SkScalar x, SkScalar y, SkScalar scale, bool applyVM); + SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP); - inline void flushRun(GrDrawContext* dc, const GrPaint&, const GrClip&, - int run, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, - const SkPaint& skPaint, const SkSurfaceProps& props, + inline void flushRun(GrRenderTargetContext* rtc, const GrClip&, int run, + const SkMatrix& viewMatrix, SkScalar x, SkScalar y, + const GrTextUtils::Paint& paint, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, - GrBatchFontCache* cache); + GrAtlasGlyphCache* cache); - void flushBigGlyphs(GrContext* context, GrDrawContext* dc, - const GrClip& clip, const SkPaint& skPaint, - const SkMatrix& viewMatrix, SkScalar x, SkScalar y, + void flushBigGlyphs(GrContext* context, GrRenderTargetContext* rtc, const GrClip& clip, + const SkPaint& paint, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipBounds); - void flushRunAsPaths(GrContext* context, - GrDrawContext* dc, - const SkSurfaceProps& props, - const SkTextBlobRunIterator& it, - const GrClip& clip, const SkPaint& skPaint, + void flushRunAsPaths(GrContext* context, GrRenderTargetContext* rtc, + const SkSurfaceProps& props, const SkTextBlobRunIterator& it, + const GrClip& clip, const GrTextUtils::Paint& paint, SkDrawFilter* drawFilter, const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y); @@ -364,15 +351,15 @@ private: } struct SubRunInfo { SubRunInfo() - : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration) - , fVertexStartIndex(0) - , fVertexEndIndex(0) - , fGlyphStartIndex(0) - , fGlyphEndIndex(0) - , fColor(GrColor_ILLEGAL) - , fMaskFormat(kA8_GrMaskFormat) - , fDrawAsDistanceFields(false) - , fUseLCDText(false) { + : fAtlasGeneration(GrDrawOpAtlas::kInvalidAtlasGeneration) + , fVertexStartIndex(0) + , fVertexEndIndex(0) + , fGlyphStartIndex(0) + , fGlyphEndIndex(0) + , fColor(GrColor_ILLEGAL) + , fMaskFormat(kA8_GrMaskFormat) + , fDrawAsDistanceFields(false) + , fUseLCDText(false) { fVertexBounds.setLargestInverted(); } SubRunInfo(const SubRunInfo& that) @@ -395,9 +382,9 @@ private: // TODO when this object is more internal, drop the privacy void resetBulkUseToken() { fBulkUseToken.reset(); } - GrBatchAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; } - void setStrike(GrBatchTextStrike* strike) { fStrike.reset(SkRef(strike)); } - GrBatchTextStrike* strike() const { return fStrike.get(); } + GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; } + void setStrike(GrAtlasTextStrike* strike) { fStrike.reset(SkRef(strike)); } + GrAtlasTextStrike* strike() const { return fStrike.get(); } void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;} uint64_t atlasGeneration() const { return fAtlasGeneration; } @@ -451,8 +438,8 @@ private: bool drawAsDistanceFields() const { return fDrawAsDistanceFields; } private: - GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken; - SkAutoTUnref fStrike; + GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken; + sk_sp fStrike; SkMatrix fCurrentViewMatrix; SkRect fVertexBounds; uint64_t fAtlasGeneration; @@ -477,7 +464,7 @@ private: return newSubRun; } static const int kMinSubRuns = 1; - SkAutoTUnref fTypeface; + sk_sp fTypeface; SkSTArray fSubRunInfo; SkAutoDescriptor fDescriptor; @@ -490,42 +477,34 @@ private: // though the distance field text and the coloremoji may share the same run, they // will have different descriptors. If fOverrideDescriptor is non-nullptr, then it // will be used in place of the run's descriptor to regen texture coords - SkAutoTDelete fOverrideDescriptor; // df properties + std::unique_ptr fOverrideDescriptor; // df properties bool fInitialized; bool fDrawAsPaths; }; template - void regenInBatch(GrDrawBatch::Target* target, - GrBatchFontCache* fontCache, - GrBlobRegenHelper* helper, - Run* run, Run::SubRunInfo* info, - SkAutoGlyphCache*, int glyphCount, - size_t vertexStride, - GrColor color, SkScalar transX, - SkScalar transY) const; + void regenInOp(GrDrawOp::Target* target, GrAtlasGlyphCache* fontCache, GrBlobRegenHelper* helper, + Run* run, Run::SubRunInfo* info, SkAutoGlyphCache*, int glyphCount, + size_t vertexStride, GrColor color, SkScalar transX, SkScalar transY) const; - inline GrDrawBatch* createBatch(const Run::SubRunInfo& info, - int glyphCount, int run, int subRun, - const SkMatrix& viewMatrix, SkScalar x, SkScalar y, - GrColor color, - const SkPaint& skPaint, const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - bool useGammaCorrectDistanceTable, - GrBatchFontCache* cache); + inline std::unique_ptr makeOp( + const Run::SubRunInfo& info, int glyphCount, int run, int subRun, + const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const GrTextUtils::Paint& paint, + const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, + bool useGammaCorrectDistanceTable, GrAtlasGlyphCache* cache); struct BigGlyph { - BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy, SkScalar scale, bool applyVM) + BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy, SkScalar scale, bool treatAsBMP) : fPath(path) , fScale(scale) , fX(vx) , fY(vy) - , fApplyVM(applyVM) {} + , fTreatAsBMP(treatAsBMP) {} SkPath fPath; SkScalar fScale; SkScalar fX; SkScalar fY; - bool fApplyVM; + bool fTreatAsBMP; }; struct StrokeInfo { @@ -551,7 +530,7 @@ private: SkMatrix fInitialViewMatrix; SkMatrix fInitialViewMatrixInverse; size_t fSize; - GrColor fPaintColor; + SkColor fFilteredPaintColor; SkScalar fInitialX; SkScalar fInitialY; diff --git a/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob_regenInBatch.cpp b/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp similarity index 79% rename from gfx/skia/skia/src/gpu/text/GrAtlasTextBlob_regenInBatch.cpp rename to gfx/skia/skia/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp index 59df1fa81d8a..3150988fdbc8 100644 --- a/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob_regenInBatch.cpp +++ b/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp @@ -7,13 +7,13 @@ #include "GrAtlasTextBlob.h" -#include "GrBatchFlushState.h" +#include "GrOpFlushState.h" #include "GrTextUtils.h" #include "SkDistanceFieldGen.h" #include "SkGlyphCache.h" -#include "batches/GrAtlasTextBatch.h" +#include "ops/GrAtlasTextOp.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // A large template to handle regenerating the vertices of a textblob with as few branches as @@ -138,18 +138,13 @@ inline void regen_vertices(intptr_t vertex, const GrGlyph* glyph, size_t vertexS } template -void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target, - GrBatchFontCache* fontCache, - GrBlobRegenHelper *helper, - Run* run, - Run::SubRunInfo* info, - SkAutoGlyphCache* lazyCache, - int glyphCount, size_t vertexStride, - GrColor color, SkScalar transX, - SkScalar transY) const { +void GrAtlasTextBlob::regenInOp(GrDrawOp::Target* target, GrAtlasGlyphCache* fontCache, + GrBlobRegenHelper* helper, Run* run, Run::SubRunInfo* info, + SkAutoGlyphCache* lazyCache, int glyphCount, size_t vertexStride, + GrColor color, SkScalar transX, SkScalar transY) const { SkASSERT(lazyCache); static_assert(!regenGlyphs || regenTexCoords, "must regenTexCoords along regenGlyphs"); - GrBatchTextStrike* strike = nullptr; + GrAtlasTextStrike* strike = nullptr; if (regenTexCoords) { info->resetBulkUseToken(); @@ -162,7 +157,7 @@ void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target, effects.fPathEffect = run->fPathEffect.get(); effects.fRasterizer = run->fRasterizer.get(); effects.fMaskFilter = run->fMaskFilter.get(); - lazyCache->reset(SkGlyphCache::DetachCache(run->fTypeface, effects, desc)); + lazyCache->reset(SkGlyphCache::DetachCache(run->fTypeface.get(), effects, desc)); } if (regenGlyphs) { @@ -208,7 +203,7 @@ void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target, intptr_t vertex = reinterpret_cast(fVertices); vertex += info->vertexStartIndex(); - vertex += vertexStride * glyphIdx * GrAtlasTextBatch::kVerticesPerGlyph; + vertex += vertexStride * glyphIdx * GrAtlasTextOp::kVerticesPerGlyph; regen_vertices(vertex, glyph, vertexStride, info->drawAsDistanceFields(), transX, transY, log2Width, log2Height, color); @@ -221,8 +216,8 @@ void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target, if (regenGlyphs) { info->setStrike(strike); } - info->setAtlasGeneration(brokenRun ? GrBatchAtlas::kInvalidAtlasGeneration : - fontCache->atlasGeneration(info->maskFormat())); + info->setAtlasGeneration(brokenRun ? GrDrawOpAtlas::kInvalidAtlasGeneration + : fontCache->atlasGeneration(info->maskFormat())); } } @@ -246,13 +241,13 @@ enum RegenMask { #define REGEN_ARGS target, fontCache, helper, &run, &info, lazyCache, \ *glyphCount, vertexStride, color, transX, transY -void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target, - GrBatchFontCache* fontCache, - GrBlobRegenHelper *helper, - int runIndex, int subRunIndex, SkAutoGlyphCache* lazyCache, - size_t vertexStride, const SkMatrix& viewMatrix, - SkScalar x, SkScalar y, GrColor color, - void** vertices, size_t* byteCount, int* glyphCount) { +void GrAtlasTextBlob::regenInOp(GrDrawOp::Target* target, + GrAtlasGlyphCache* fontCache, + GrBlobRegenHelper* helper, + int runIndex, int subRunIndex, SkAutoGlyphCache* lazyCache, + size_t vertexStride, const SkMatrix& viewMatrix, + SkScalar x, SkScalar y, GrColor color, + void** vertices, size_t* byteCount, int* glyphCount) { Run& run = fRuns[runIndex]; Run::SubRunInfo& info = run.fSubRunInfo[subRunIndex]; @@ -262,7 +257,7 @@ void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target, SkScalar transX, transY; info.computeTranslation(viewMatrix, x, y, &transX, &transY); - // Because the GrBatchFontCache may evict the strike a blob depends on using for + // Because the GrAtlasGlyphCache may evict the strike a blob depends on using for // generating its texture coords, we have to track whether or not the strike has // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is // otherwise we have to get the new strike, and use that to get the correct glyphs. @@ -286,19 +281,41 @@ void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target, RegenMask regenMask = (RegenMask)regenMaskBits; switch (regenMask) { - case kRegenPos: this->regenInBatch(REGEN_ARGS); break; - case kRegenCol: this->regenInBatch(REGEN_ARGS); break; - case kRegenTex: this->regenInBatch(REGEN_ARGS); break; - case kRegenGlyph: this->regenInBatch(REGEN_ARGS); break; + case kRegenPos: + this->regenInOp(REGEN_ARGS); + break; + case kRegenCol: + this->regenInOp(REGEN_ARGS); + break; + case kRegenTex: + this->regenInOp(REGEN_ARGS); + break; + case kRegenGlyph: + this->regenInOp(REGEN_ARGS); + break; - // combinations - case kRegenPosCol: this->regenInBatch(REGEN_ARGS); break; - case kRegenPosTex: this->regenInBatch(REGEN_ARGS); break; - case kRegenPosTexGlyph: this->regenInBatch(REGEN_ARGS); break; - case kRegenPosColTex: this->regenInBatch(REGEN_ARGS); break; - case kRegenPosColTexGlyph: this->regenInBatch(REGEN_ARGS); break; - case kRegenColTex: this->regenInBatch(REGEN_ARGS); break; - case kRegenColTexGlyph: this->regenInBatch(REGEN_ARGS); break; + // combinations + case kRegenPosCol: + this->regenInOp(REGEN_ARGS); + break; + case kRegenPosTex: + this->regenInOp(REGEN_ARGS); + break; + case kRegenPosTexGlyph: + this->regenInOp(REGEN_ARGS); + break; + case kRegenPosColTex: + this->regenInOp(REGEN_ARGS); + break; + case kRegenPosColTexGlyph: + this->regenInOp(REGEN_ARGS); + break; + case kRegenColTex: + this->regenInOp(REGEN_ARGS); + break; + case kRegenColTexGlyph: + this->regenInOp(REGEN_ARGS); + break; case kNoRegen: helper->incGlyphCount(*glyphCount); diff --git a/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.cpp b/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.cpp index 285aea4d2ac6..4e377c9595a1 100644 --- a/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.cpp +++ b/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.cpp @@ -5,21 +5,18 @@ * found in the LICENSE file. */ #include "GrAtlasTextContext.h" - #include "GrContext.h" -#include "GrDrawContext.h" +#include "GrRenderTargetContext.h" #include "GrTextBlobCache.h" -#include "GrTextUtils.h" - #include "SkDraw.h" #include "SkDrawFilter.h" -#include "SkGrPriv.h" +#include "SkGr.h" +#include "ops/GrMeshDrawOp.h" GrAtlasTextContext::GrAtlasTextContext() : fDistanceAdjustTable(new GrDistanceFieldAdjustTable) { } - GrAtlasTextContext* GrAtlasTextContext::Create() { return new GrAtlasTextContext(); } @@ -32,8 +29,8 @@ bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); } -GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd) { - GrColor canonicalColor = paint.computeLuminanceColor(); +SkColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd) { + SkColor canonicalColor = paint.computeLuminanceColor(); if (lcd) { // This is the correct computation, but there are tons of cases where LCD can be overridden. // For now we just regenerate if any run in a textblob has LCD. @@ -53,10 +50,10 @@ GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd return canonicalColor; } -uint32_t GrAtlasTextContext::ComputeScalerContextFlags(GrDrawContext* dc) { +uint32_t GrAtlasTextContext::ComputeScalerContextFlags(GrRenderTargetContext* rtc) { // If we're doing gamma-correct rendering, then we can disable the gamma hacks. // Otherwise, leave them on. In either case, we still want the contrast boost: - if (dc->isGammaCorrect()) { + if (rtc->isGammaCorrect()) { return SkPaint::kBoostContrast_ScalerContextFlag; } else { return SkPaint::kFakeGammaAndBoostContrast_ScalerContextFlags; @@ -76,7 +73,7 @@ bool GrAtlasTextContext::HasLCD(const SkTextBlob* blob) { return false; } -void GrAtlasTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc, +void GrAtlasTextContext::drawTextBlob(GrContext* context, GrRenderTargetContext* rtc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const SkTextBlob* blob, @@ -87,7 +84,7 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc, return; } - SkAutoTUnref cacheBlob; + sk_sp cacheBlob; SkMaskFilter::BlurRec blurRec; GrAtlasTextBlob::Key key; // It might be worth caching these things, but its not clear at this time @@ -96,7 +93,7 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc, bool canCache = !(skPaint.getPathEffect() || (mf && !mf->asABlur(&blurRec)) || drawFilter); - uint32_t scalerContextFlags = ComputeScalerContextFlags(dc); + uint32_t scalerContextFlags = ComputeScalerContextFlags(rtc); GrTextBlobCache* cache = context->getTextBlobCache(); if (canCache) { @@ -118,114 +115,91 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc, key.fHasBlur = SkToBool(mf); key.fCanonicalColor = canonicalColor; key.fScalerContextFlags = scalerContextFlags; - cacheBlob.reset(SkSafeRef(cache->find(key))); - } - - // Though for the time being runs in the textblob can override the paint, they only touch font - // info. - GrPaint grPaint; - if (!SkPaintToGrPaint(context, dc, skPaint, viewMatrix, &grPaint)) { - return; + cacheBlob = cache->find(key); } + GrTextUtils::Paint paint(&skPaint); if (cacheBlob) { - if (cacheBlob->mustRegenerate(skPaint, grPaint.getColor(), blurRec, viewMatrix, x, y)) { + if (cacheBlob->mustRegenerate(paint, blurRec, viewMatrix, x, y)) { // We have to remake the blob because changes may invalidate our masks. // TODO we could probably get away reuse most of the time if the pointer is unique, // but we'd have to clear the subrun information - cache->remove(cacheBlob); - cacheBlob.reset(SkRef(cache->createCachedBlob(blob, key, blurRec, skPaint))); - RegenerateTextBlob(cacheBlob, context->getBatchFontCache(), - *context->caps()->shaderCaps(), skPaint, grPaint.getColor(), - scalerContextFlags, viewMatrix, props, - blob, x, y, drawFilter); + cache->remove(cacheBlob.get()); + cacheBlob = cache->makeCachedBlob(blob, key, blurRec, skPaint); + RegenerateTextBlob(cacheBlob.get(), context->getAtlasGlyphCache(), + *context->caps()->shaderCaps(), paint, scalerContextFlags, + viewMatrix, props, blob, x, y, drawFilter); } else { - cache->makeMRU(cacheBlob); + cache->makeMRU(cacheBlob.get()); if (CACHE_SANITY_CHECK) { int glyphCount = 0; int runCount = 0; GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob); - SkAutoTUnref sanityBlob(cache->createBlob(glyphCount, runCount)); + sk_sp sanityBlob(cache->makeBlob(glyphCount, runCount)); sanityBlob->setupKey(key, blurRec, skPaint); - RegenerateTextBlob(sanityBlob, context->getBatchFontCache(), - *context->caps()->shaderCaps(), skPaint, - grPaint.getColor(), scalerContextFlags, viewMatrix, props, - blob, x, y, drawFilter); + RegenerateTextBlob(sanityBlob.get(), context->getAtlasGlyphCache(), + *context->caps()->shaderCaps(), paint, scalerContextFlags, + viewMatrix, props, blob, x, y, drawFilter); GrAtlasTextBlob::AssertEqual(*sanityBlob, *cacheBlob); } } } else { if (canCache) { - cacheBlob.reset(SkRef(cache->createCachedBlob(blob, key, blurRec, skPaint))); + cacheBlob = cache->makeCachedBlob(blob, key, blurRec, skPaint); } else { - cacheBlob.reset(cache->createBlob(blob)); + cacheBlob = cache->makeBlob(blob); } - RegenerateTextBlob(cacheBlob, context->getBatchFontCache(), - *context->caps()->shaderCaps(), skPaint, grPaint.getColor(), - scalerContextFlags, viewMatrix, props, - blob, x, y, drawFilter); + RegenerateTextBlob(cacheBlob.get(), context->getAtlasGlyphCache(), + *context->caps()->shaderCaps(), paint, scalerContextFlags, viewMatrix, + props, blob, x, y, drawFilter); } - cacheBlob->flushCached(context, dc, blob, props, fDistanceAdjustTable, skPaint, - grPaint, drawFilter, clip, viewMatrix, clipBounds, x, y); + cacheBlob->flushCached(context, rtc, blob, props, fDistanceAdjustTable.get(), paint, drawFilter, + clip, viewMatrix, clipBounds, x, y); } void GrAtlasTextContext::RegenerateTextBlob(GrAtlasTextBlob* cacheBlob, - GrBatchFontCache* fontCache, + GrAtlasGlyphCache* fontCache, const GrShaderCaps& shaderCaps, - const SkPaint& skPaint, GrColor color, - uint32_t scalerContextFlags, - const SkMatrix& viewMatrix, - const SkSurfaceProps& props, - const SkTextBlob* blob, SkScalar x, SkScalar y, - SkDrawFilter* drawFilter) { - cacheBlob->initReusableBlob(color, viewMatrix, x, y); + const GrTextUtils::Paint& paint, + uint32_t scalerContextFlags, const SkMatrix& viewMatrix, + const SkSurfaceProps& props, const SkTextBlob* blob, + SkScalar x, SkScalar y, SkDrawFilter* drawFilter) { + cacheBlob->initReusableBlob(paint.filteredSkColor(), viewMatrix, x, y); // Regenerate textblob - SkPaint runPaint = skPaint; SkTextBlobRunIterator it(blob); + GrTextUtils::RunPaint runPaint(&paint, drawFilter, props); for (int run = 0; !it.done(); it.next(), run++) { int glyphCount = it.glyphCount(); size_t textLen = glyphCount * sizeof(uint16_t); const SkPoint& offset = it.offset(); - // applyFontToPaint() always overwrites the exact same attributes, - // so it is safe to not re-seed the paint for this reason. - it.applyFontToPaint(&runPaint); - - if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) { - // A false return from filter() means we should abort the current draw. - runPaint = skPaint; + cacheBlob->push_back_run(run); + if (!runPaint.modifyForRun(it)) { continue; } - - runPaint.setFlags(GrTextUtils::FilterTextFlags(props, runPaint)); - - cacheBlob->push_back_run(run); - if (GrTextUtils::CanDrawAsDistanceFields(runPaint, viewMatrix, props, shaderCaps)) { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: { - GrTextUtils::DrawDFText(cacheBlob, run, fontCache, - props, runPaint, color, scalerContextFlags, - viewMatrix, (const char *)it.glyphs(), textLen, - x + offset.x(), y + offset.y()); + GrTextUtils::DrawDFText(cacheBlob, run, fontCache, props, runPaint, + scalerContextFlags, viewMatrix, + (const char*)it.glyphs(), textLen, x + offset.x(), + y + offset.y()); break; } case SkTextBlob::kHorizontal_Positioning: { SkPoint dfOffset = SkPoint::Make(x, y + offset.y()); - GrTextUtils::DrawDFPosText(cacheBlob, run, fontCache, - props, runPaint, color, scalerContextFlags, - viewMatrix, (const char*)it.glyphs(), textLen, - it.pos(), 1, dfOffset); + GrTextUtils::DrawDFPosText( + cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, + viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 1, dfOffset); break; } case SkTextBlob::kFull_Positioning: { SkPoint dfOffset = SkPoint::Make(x, y); - GrTextUtils::DrawDFPosText(cacheBlob, run, fontCache, - props, runPaint, color, scalerContextFlags, - viewMatrix, (const char*)it.glyphs(), textLen, - it.pos(), 2, dfOffset); + GrTextUtils::DrawDFPosText( + cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, + viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2, dfOffset); break; } } @@ -234,149 +208,138 @@ void GrAtlasTextContext::RegenerateTextBlob(GrAtlasTextBlob* cacheBlob, } else { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: - GrTextUtils::DrawBmpText(cacheBlob, run, fontCache, - props, runPaint, color, scalerContextFlags, - viewMatrix, (const char *)it.glyphs(), textLen, - x + offset.x(), y + offset.y()); + GrTextUtils::DrawBmpText(cacheBlob, run, fontCache, props, runPaint, + scalerContextFlags, viewMatrix, + (const char*)it.glyphs(), textLen, x + offset.x(), + y + offset.y()); break; case SkTextBlob::kHorizontal_Positioning: - GrTextUtils::DrawBmpPosText(cacheBlob, run, fontCache, - props, runPaint, color, scalerContextFlags, - viewMatrix, (const char*)it.glyphs(), textLen, - it.pos(), 1, SkPoint::Make(x, y + offset.y())); + GrTextUtils::DrawBmpPosText(cacheBlob, run, fontCache, props, runPaint, + scalerContextFlags, viewMatrix, + (const char*)it.glyphs(), textLen, it.pos(), 1, + SkPoint::Make(x, y + offset.y())); break; case SkTextBlob::kFull_Positioning: - GrTextUtils::DrawBmpPosText(cacheBlob, run, fontCache, - props, runPaint, color, scalerContextFlags, - viewMatrix, (const char*)it.glyphs(), textLen, - it.pos(), 2, SkPoint::Make(x, y)); + GrTextUtils::DrawBmpPosText(cacheBlob, run, fontCache, props, runPaint, + scalerContextFlags, viewMatrix, + (const char*)it.glyphs(), textLen, it.pos(), 2, + SkPoint::Make(x, y)); break; } } - - if (drawFilter) { - // A draw filter may change the paint arbitrarily, so we must re-seed in this case. - runPaint = skPaint; - } } } -inline GrAtlasTextBlob* -GrAtlasTextContext::CreateDrawTextBlob(GrTextBlobCache* blobCache, - GrBatchFontCache* fontCache, - const GrShaderCaps& shaderCaps, - const GrPaint& paint, - const SkPaint& skPaint, - uint32_t scalerContextFlags, - const SkMatrix& viewMatrix, - const SkSurfaceProps& props, - const char text[], size_t byteLength, - SkScalar x, SkScalar y) { - int glyphCount = skPaint.countText(text, byteLength); - - GrAtlasTextBlob* blob = blobCache->createBlob(glyphCount, 1); - blob->initThrowawayBlob(viewMatrix, x, y); - - if (GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, props, shaderCaps)) { - GrTextUtils::DrawDFText(blob, 0, fontCache, props, skPaint, paint.getColor(), - scalerContextFlags, viewMatrix, text, byteLength, x, y); - } else { - GrTextUtils::DrawBmpText(blob, 0, fontCache, props, skPaint, paint.getColor(), - scalerContextFlags, viewMatrix, text, byteLength, x, y); - } - return blob; -} - -inline GrAtlasTextBlob* -GrAtlasTextContext::CreateDrawPosTextBlob(GrTextBlobCache* blobCache, GrBatchFontCache* fontCache, - const GrShaderCaps& shaderCaps, const GrPaint& paint, - const SkPaint& skPaint, uint32_t scalerContextFlags, - const SkMatrix& viewMatrix, const SkSurfaceProps& props, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset) { - int glyphCount = skPaint.countText(text, byteLength); - - GrAtlasTextBlob* blob = blobCache->createBlob(glyphCount, 1); - blob->initThrowawayBlob(viewMatrix, offset.x(), offset.y()); - - if (GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, props, shaderCaps)) { - GrTextUtils::DrawDFPosText(blob, 0, fontCache, props, - skPaint, paint.getColor(), scalerContextFlags, viewMatrix, text, - byteLength, pos, scalarsPerPosition, offset); - } else { - GrTextUtils::DrawBmpPosText(blob, 0, fontCache, props, skPaint, - paint.getColor(), scalerContextFlags, viewMatrix, text, - byteLength, pos, scalarsPerPosition, offset); - } - return blob; -} - -void GrAtlasTextContext::drawText(GrContext* context, - GrDrawContext* dc, - const GrClip& clip, - const GrPaint& paint, const SkPaint& skPaint, - const SkMatrix& viewMatrix, - const SkSurfaceProps& props, - const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkIRect& regionClipBounds) { - if (context->abandoned()) { - return; - } else if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) { - SkAutoTUnref blob( - CreateDrawTextBlob(context->getTextBlobCache(), context->getBatchFontCache(), - *context->caps()->shaderCaps(), - paint, skPaint, - ComputeScalerContextFlags(dc), - viewMatrix, props, - text, byteLength, x, y)); - blob->flushThrowaway(context, dc, props, fDistanceAdjustTable, skPaint, paint, - clip, viewMatrix, regionClipBounds, x, y); - return; - } - - // fall back to drawing as a path - GrTextUtils::DrawTextAsPath(context, dc, clip, skPaint, viewMatrix, text, byteLength, x, y, - regionClipBounds); -} - -void GrAtlasTextContext::drawPosText(GrContext* context, - GrDrawContext* dc, - const GrClip& clip, - const GrPaint& paint, const SkPaint& skPaint, +inline sk_sp +GrAtlasTextContext::MakeDrawTextBlob(GrTextBlobCache* blobCache, + GrAtlasGlyphCache* fontCache, + const GrShaderCaps& shaderCaps, + const GrTextUtils::Paint& paint, + uint32_t scalerContextFlags, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkIRect& regionClipBounds) { + SkScalar x, SkScalar y) { + int glyphCount = paint.skPaint().countText(text, byteLength); + + sk_sp blob = blobCache->makeBlob(glyphCount, 1); + blob->initThrowawayBlob(viewMatrix, x, y); + + if (GrTextUtils::CanDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) { + GrTextUtils::DrawDFText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, + viewMatrix, text, byteLength, x, y); + } else { + GrTextUtils::DrawBmpText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, + viewMatrix, text, byteLength, x, y); + } + return blob; +} + +inline sk_sp +GrAtlasTextContext::MakeDrawPosTextBlob(GrTextBlobCache* blobCache, + GrAtlasGlyphCache* fontCache, + const GrShaderCaps& shaderCaps, + const GrTextUtils::Paint& paint, + uint32_t scalerContextFlags, + const SkMatrix& viewMatrix, + const SkSurfaceProps& props, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, const + SkPoint& offset) { + int glyphCount = paint.skPaint().countText(text, byteLength); + + sk_sp blob = blobCache->makeBlob(glyphCount, 1); + blob->initThrowawayBlob(viewMatrix, offset.x(), offset.y()); + + if (GrTextUtils::CanDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) { + GrTextUtils::DrawDFPosText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, + viewMatrix, text, byteLength, pos, scalarsPerPosition, offset); + } else { + GrTextUtils::DrawBmpPosText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, + viewMatrix, text, byteLength, pos, scalarsPerPosition, offset); + } + return blob; +} + +void GrAtlasTextContext::drawText(GrContext* context, GrRenderTargetContext* rtc, + const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, const SkSurfaceProps& props, + const char text[], size_t byteLength, SkScalar x, SkScalar y, + const SkIRect& regionClipBounds) { if (context->abandoned()) { return; - } else if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) { - SkAutoTUnref blob( - CreateDrawPosTextBlob(context->getTextBlobCache(), - context->getBatchFontCache(), - *context->caps()->shaderCaps(), - paint, skPaint, - ComputeScalerContextFlags(dc), - viewMatrix, props, - text, byteLength, - pos, scalarsPerPosition, - offset)); - blob->flushThrowaway(context, dc, props, fDistanceAdjustTable, skPaint, paint, - clip, viewMatrix, regionClipBounds, offset.fX, offset.fY); + } + GrTextUtils::Paint paint(&skPaint); + if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) { + sk_sp blob( + MakeDrawTextBlob(context->getTextBlobCache(), context->getAtlasGlyphCache(), + *context->caps()->shaderCaps(), + paint, ComputeScalerContextFlags(rtc), + viewMatrix, props, + text, byteLength, x, y)); + blob->flushThrowaway(context, rtc, props, fDistanceAdjustTable.get(), paint, clip, + viewMatrix, regionClipBounds, x, y); return; } // fall back to drawing as a path - GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, skPaint, viewMatrix, text, - byteLength, pos, scalarsPerPosition, offset, regionClipBounds); + GrTextUtils::DrawTextAsPath(context, rtc, clip, paint, viewMatrix, text, byteLength, x, y, + regionClipBounds); +} + +void GrAtlasTextContext::drawPosText(GrContext* context, GrRenderTargetContext* rtc, + const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, const SkSurfaceProps& props, + const char text[], size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset, + const SkIRect& regionClipBounds) { + GrTextUtils::Paint paint(&skPaint); + if (context->abandoned()) { + return; + } else if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) { + sk_sp blob( + MakeDrawPosTextBlob(context->getTextBlobCache(), context->getAtlasGlyphCache(), + *context->caps()->shaderCaps(), + paint, ComputeScalerContextFlags(rtc), + viewMatrix, props, + text, byteLength, + pos, scalarsPerPosition, + offset)); + blob->flushThrowaway(context, rtc, props, fDistanceAdjustTable.get(), paint, clip, + viewMatrix, regionClipBounds, offset.fX, offset.fY); + return; + } + + // fall back to drawing as a path + GrTextUtils::DrawPosTextAsPath(context, rtc, props, clip, paint, viewMatrix, text, byteLength, + pos, scalarsPerPosition, offset, regionClipBounds); } /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef GR_TEST_UTILS +#if GR_TEST_UTILS -DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { +DRAW_OP_TEST_DEFINE(TextBlobOp) { static uint32_t gContextID = SK_InvalidGenID; static GrAtlasTextContext* gTextContext = nullptr; static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType); @@ -388,23 +351,17 @@ DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { gTextContext = GrAtlasTextContext::Create(); } - // Setup dummy SkPaint / GrPaint / GrDrawContext - sk_sp drawContext(context->makeDrawContext(SkBackingFit::kApprox, 1024, 1024, - kSkia8888_GrPixelConfig, nullptr)); + // Setup dummy SkPaint / GrPaint / GrRenderTargetContext + sk_sp renderTargetContext(context->makeRenderTargetContext( + SkBackingFit::kApprox, 1024, 1024, kRGBA_8888_GrPixelConfig, nullptr)); - GrColor color = GrRandomColor(random); SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); SkPaint skPaint; - skPaint.setColor(color); + skPaint.setColor(random->nextU()); skPaint.setLCDRenderText(random->nextBool()); skPaint.setAntiAlias(skPaint.isLCDRenderText() ? true : random->nextBool()); skPaint.setSubpixelText(random->nextBool()); - GrPaint grPaint; - if (!SkPaintToGrPaint(context, drawContext.get(), skPaint, viewMatrix, &grPaint)) { - SkFAIL("couldn't convert paint\n"); - } - const char* text = "The quick brown fox jumps over the lazy dog."; int textLen = (int)strlen(text); @@ -417,20 +374,17 @@ DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { SkScalar x = SkIntToScalar(xInt); SkScalar y = SkIntToScalar(yInt); - // right now we don't handle textblobs, nor do we handle drawPosText. Since we only - // intend to test the batch with this unit test, that is okay. - SkAutoTUnref blob( - GrAtlasTextContext::CreateDrawTextBlob(context->getTextBlobCache(), - context->getBatchFontCache(), - *context->caps()->shaderCaps(), grPaint, skPaint, - GrAtlasTextContext::kTextBlobBatchScalerContextFlags, - viewMatrix, - gSurfaceProps, text, - static_cast(textLen), x, y)); + GrTextUtils::Paint paint(&skPaint); + // right now we don't handle textblobs, nor do we handle drawPosText. Since we only intend to + // test the text op with this unit test, that is okay. + sk_sp blob(GrAtlasTextContext::MakeDrawTextBlob( + context->getTextBlobCache(), context->getAtlasGlyphCache(), + *context->caps()->shaderCaps(), paint, + GrAtlasTextContext::kTextBlobOpScalerContextFlags, viewMatrix, gSurfaceProps, text, + static_cast(textLen), x, y)); - return blob->test_createBatch(textLen, 0, 0, viewMatrix, x, y, color, skPaint, - gSurfaceProps, gTextContext->dfAdjustTable(), - context->getBatchFontCache()); + return blob->test_makeOp(textLen, 0, 0, viewMatrix, x, y, paint, gSurfaceProps, + gTextContext->dfAdjustTable(), context->getAtlasGlyphCache()); } #endif diff --git a/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.h b/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.h index 5bf7662c48de..7438b647b2f2 100644 --- a/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.h +++ b/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.h @@ -11,14 +11,15 @@ #include "GrAtlasTextBlob.h" #include "GrDistanceFieldAdjustTable.h" #include "GrGeometryProcessor.h" +#include "GrTextUtils.h" #include "SkTextBlobRunIterator.h" -#ifdef GR_TEST_UTILS -#include "GrBatchTest.h" +#if GR_TEST_UTILS +#include "GrDrawOpTest.h" #endif -class GrDrawBatch; -class GrDrawContext; +class GrDrawOp; +class GrRenderTargetContext; class GrPipelineBuilder; class GrTextBlobCache; class SkGlyph; @@ -32,16 +33,15 @@ public: bool canDraw(const SkPaint&, const SkMatrix& viewMatrix, const SkSurfaceProps&, const GrShaderCaps&); - void drawText(GrContext*, GrDrawContext*, const GrClip&, const GrPaint&, const SkPaint&, + + void drawText(GrContext*, GrRenderTargetContext*, const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[], - size_t byteLength, SkScalar x, SkScalar y, - const SkIRect& regionClipBounds); - void drawPosText(GrContext*, GrDrawContext*, const GrClip&, const GrPaint&, - const SkPaint&, const SkMatrix& viewMatrix, const SkSurfaceProps&, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, + size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds); + void drawPosText(GrContext*, GrRenderTargetContext*, const GrClip&, const SkPaint&, + const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[], + size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& regionClipBounds); - void drawTextBlob(GrContext*, GrDrawContext*, const GrClip&, const SkPaint&, + void drawTextBlob(GrContext*, GrRenderTargetContext*, const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const SkSurfaceProps&, const SkTextBlob*, SkScalar x, SkScalar y, SkDrawFilter*, const SkIRect& clipBounds); @@ -50,13 +50,13 @@ private: GrAtlasTextContext(); // sets up the descriptor on the blob and returns a detached cache. Client must attach - inline static GrColor ComputeCanonicalColor(const SkPaint&, bool lcd); + inline static SkColor ComputeCanonicalColor(const SkPaint&, bool lcd); // Determines if we need to use fake gamma (and contrast boost): - inline static uint32_t ComputeScalerContextFlags(GrDrawContext*); + inline static uint32_t ComputeScalerContextFlags(GrRenderTargetContext*); static void RegenerateTextBlob(GrAtlasTextBlob* bmp, - GrBatchFontCache*, + GrAtlasGlyphCache*, const GrShaderCaps&, - const SkPaint& skPaint, GrColor, + const GrTextUtils::Paint&, uint32_t scalerContextFlags, const SkMatrix& viewMatrix, const SkSurfaceProps&, @@ -64,34 +64,32 @@ private: SkDrawFilter* drawFilter); inline static bool HasLCD(const SkTextBlob*); - static inline GrAtlasTextBlob* CreateDrawTextBlob(GrTextBlobCache*, - GrBatchFontCache*, const GrShaderCaps&, - const GrPaint&, - const SkPaint&, - uint32_t scalerContextFlags, - const SkMatrix& viewMatrix, - const SkSurfaceProps&, - const char text[], size_t byteLength, - SkScalar x, SkScalar y); - static inline GrAtlasTextBlob* CreateDrawPosTextBlob(GrTextBlobCache*, GrBatchFontCache*, - const GrShaderCaps&, - const GrPaint&, - const SkPaint&, - uint32_t scalerContextFlags, - const SkMatrix& viewMatrix, - const SkSurfaceProps&, - const char text[], size_t byteLength, - const SkScalar pos[], - int scalarsPerPosition, - const SkPoint& offset); - const GrDistanceFieldAdjustTable* dfAdjustTable() const { return fDistanceAdjustTable; } + static inline sk_sp MakeDrawTextBlob(GrTextBlobCache*, GrAtlasGlyphCache*, + const GrShaderCaps&, + const GrTextUtils::Paint&, + uint32_t scalerContextFlags, + const SkMatrix& viewMatrix, + const SkSurfaceProps&, + const char text[], size_t byteLength, + SkScalar x, SkScalar y); + static inline sk_sp MakeDrawPosTextBlob(GrTextBlobCache*, GrAtlasGlyphCache*, + const GrShaderCaps&, + const GrTextUtils::Paint&, + uint32_t scalerContextFlags, + const SkMatrix& viewMatrix, + const SkSurfaceProps&, + const char text[], size_t byteLength, + const SkScalar pos[], + int scalarsPerPosition, + const SkPoint& offset); + const GrDistanceFieldAdjustTable* dfAdjustTable() const { return fDistanceAdjustTable.get(); } - SkAutoTUnref fDistanceAdjustTable; + sk_sp fDistanceAdjustTable; -#ifdef GR_TEST_UTILS - static const uint32_t kTextBlobBatchScalerContextFlags = - SkPaint::kFakeGammaAndBoostContrast_ScalerContextFlags; - DRAW_BATCH_TEST_FRIEND(TextBlobBatch); +#if GR_TEST_UTILS + static const uint32_t kTextBlobOpScalerContextFlags = + SkPaint::kFakeGammaAndBoostContrast_ScalerContextFlags; + DRAW_OP_TEST_FRIEND(TextBlobOp); #endif }; diff --git a/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.cpp b/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.cpp index 32d80218d32c..0ae4023b1cce 100644 --- a/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.cpp +++ b/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.cpp @@ -8,24 +8,24 @@ #include "GrStencilAndCoverTextContext.h" #include "GrAtlasTextContext.h" #include "GrContext.h" -#include "GrDrawContext.h" #include "GrPath.h" #include "GrPathRange.h" #include "GrPipelineBuilder.h" +#include "GrRenderTargetContext.h" #include "GrResourceProvider.h" #include "GrTextUtils.h" #include "SkAutoKern.h" #include "SkDraw.h" +#include "SkDrawFilter.h" #include "SkDrawProcs.h" #include "SkGlyphCache.h" -#include "SkGrPriv.h" -#include "SkDrawFilter.h" +#include "SkGr.h" #include "SkPath.h" #include "SkTextBlobRunIterator.h" -#include "SkTextMapStateProc.h" #include "SkTextFormatParams.h" +#include "SkTextMapStateProc.h" -#include "batches/GrDrawPathBatch.h" +#include "ops/GrDrawPathOp.h" template static void delete_hash_map_entry(const Key&, Val* val) { SkASSERT(*val); @@ -68,45 +68,39 @@ bool GrStencilAndCoverTextContext::internalCanDraw(const SkPaint& skPaint) { return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrokeWidth(); } -void GrStencilAndCoverTextContext::drawText(GrContext* context, GrDrawContext* dc, - const GrClip& clip, const GrPaint& paint, - const SkPaint& skPaint, const SkMatrix& viewMatrix, - const SkSurfaceProps& props, - const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkIRect& clipBounds) { +void GrStencilAndCoverTextContext::drawText(GrContext* context, GrRenderTargetContext* rtc, + const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, const SkSurfaceProps& props, + const char text[], size_t byteLength, SkScalar x, + SkScalar y, const SkIRect& clipBounds) { if (context->abandoned()) { return; } else if (this->canDraw(skPaint, viewMatrix)) { if (skPaint.getTextSize() > 0) { TextRun run(skPaint); run.setText(text, byteLength, x, y); - run.draw(context, dc, paint, clip, viewMatrix, props, 0, 0, - clipBounds, fFallbackTextContext, skPaint); + run.draw(context, rtc, clip, viewMatrix, props, 0, 0, clipBounds, fFallbackTextContext, + skPaint); } return; } else if (fFallbackTextContext->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) { - fFallbackTextContext->drawText(context, dc, clip, paint, skPaint, viewMatrix, props, text, + fFallbackTextContext->drawText(context, rtc, clip, skPaint, viewMatrix, props, text, byteLength, x, y, clipBounds); return; } // fall back to drawing as a path - GrTextUtils::DrawTextAsPath(context, dc, clip, skPaint, viewMatrix, text, byteLength, x, y, + GrTextUtils::DrawTextAsPath(context, rtc, clip, skPaint, viewMatrix, text, byteLength, x, y, clipBounds); } -void GrStencilAndCoverTextContext::drawPosText(GrContext* context, GrDrawContext* dc, - const GrClip& clip, - const GrPaint& paint, - const SkPaint& skPaint, +void GrStencilAndCoverTextContext::drawPosText(GrContext* context, GrRenderTargetContext* rtc, + const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, - const SkSurfaceProps& props, - const char text[], - size_t byteLength, - const SkScalar pos[], - int scalarsPerPosition, - const SkPoint& offset, + const SkSurfaceProps& props, const char text[], + size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds) { if (context->abandoned()) { return; @@ -114,25 +108,24 @@ void GrStencilAndCoverTextContext::drawPosText(GrContext* context, GrDrawContext if (skPaint.getTextSize() > 0) { TextRun run(skPaint); run.setPosText(text, byteLength, pos, scalarsPerPosition, offset); - run.draw(context, dc, paint, clip, viewMatrix, props, 0, 0, - clipBounds, fFallbackTextContext, skPaint); + run.draw(context, rtc, clip, viewMatrix, props, 0, 0, clipBounds, fFallbackTextContext, + skPaint); } return; } else if (fFallbackTextContext->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) { - fFallbackTextContext->drawPosText(context, dc, clip, paint, skPaint, viewMatrix, props, - text, byteLength, pos, - scalarsPerPosition, offset, clipBounds); + fFallbackTextContext->drawPosText(context, rtc, clip, skPaint, viewMatrix, props, text, + byteLength, pos, scalarsPerPosition, offset, clipBounds); return; } // fall back to drawing as a path - GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, skPaint, viewMatrix, text, + GrTextUtils::DrawPosTextAsPath(context, rtc, props, clip, skPaint, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset, clipBounds); } void GrStencilAndCoverTextContext::uncachedDrawTextBlob(GrContext* context, - GrDrawContext* dc, + GrRenderTargetContext* rtc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, @@ -141,57 +134,37 @@ void GrStencilAndCoverTextContext::uncachedDrawTextBlob(GrContext* context, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { - SkPaint runPaint = skPaint; - + GrTextUtils::Paint paint(&skPaint); + GrTextUtils::RunPaint runPaint(&paint, drawFilter, props); SkTextBlobRunIterator it(blob); for (;!it.done(); it.next()) { + if (!runPaint.modifyForRun(it)) { + continue; + } size_t textLen = it.glyphCount() * sizeof(uint16_t); const SkPoint& offset = it.offset(); - // applyFontToPaint() always overwrites the exact same attributes, - // so it is safe to not re-seed the paint for this reason. - it.applyFontToPaint(&runPaint); - - if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) { - // A false return from filter() means we should abort the current draw. - runPaint = skPaint; - continue; - } - - runPaint.setFlags(GrTextUtils::FilterTextFlags(props, runPaint)); - - GrPaint grPaint; - if (!SkPaintToGrPaint(context, dc, runPaint, viewMatrix, &grPaint)) { - return; - } - switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: - this->drawText(context, dc, clip, grPaint, runPaint, viewMatrix, props, - (const char *)it.glyphs(), - textLen, x + offset.x(), y + offset.y(), clipBounds); + this->drawText(context, rtc, clip, runPaint, viewMatrix, props, + (const char*)it.glyphs(), textLen, x + offset.x(), y + offset.y(), + clipBounds); break; case SkTextBlob::kHorizontal_Positioning: - this->drawPosText(context, dc, clip, grPaint, runPaint, viewMatrix, props, - (const char*)it.glyphs(), - textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), - clipBounds); + this->drawPosText(context, rtc, clip, runPaint, viewMatrix, props, + (const char*)it.glyphs(), textLen, it.pos(), 1, + SkPoint::Make(x, y + offset.y()), clipBounds); break; case SkTextBlob::kFull_Positioning: - this->drawPosText(context, dc, clip, grPaint, runPaint, viewMatrix, props, - (const char*)it.glyphs(), - textLen, it.pos(), 2, SkPoint::Make(x, y), clipBounds); + this->drawPosText(context, rtc, clip, runPaint, viewMatrix, props, + (const char*)it.glyphs(), textLen, it.pos(), 2, + SkPoint::Make(x, y), clipBounds); break; } - - if (drawFilter) { - // A draw filter may change the paint arbitrarily, so we must re-seed in this case. - runPaint = skPaint; - } } } -void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc, +void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrRenderTargetContext* rtc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, @@ -203,31 +176,25 @@ void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrDrawContex } if (!this->internalCanDraw(skPaint)) { - fFallbackTextContext->drawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, + fFallbackTextContext->drawTextBlob(context, rtc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } if (drawFilter || skPaint.getPathEffect()) { // This draw can't be cached. - this->uncachedDrawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, x, y, + this->uncachedDrawTextBlob(context, rtc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } - GrPaint paint; - if (!SkPaintToGrPaint(context, dc, skPaint, viewMatrix, &paint)) { - return; - } - const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); TextBlob::Iter iter(blob); - for (TextRun* run = iter.get(); run; run = iter.next()) { - // The run's "font" overrides the anti-aliasing of the passed in paint! - paint.setAntiAlias(run->isAntiAlias()); - run->draw(context, dc, paint, clip, viewMatrix, props, x, y, - clipBounds, fFallbackTextContext, skPaint); + for (TextRun *run = iter.get(), *nextRun; run; run = nextRun) { + nextRun = iter.next(); + run->draw(context, rtc, clip, viewMatrix, props, x, y, clipBounds, fFallbackTextContext, + skPaint); run->releaseGlyphCache(); } } @@ -351,7 +318,7 @@ private: void flush(); - SkAutoTDelete fBuilder; + std::unique_ptr fBuilder; SkPaint fFont; int fBuffIdx; int fCount; @@ -383,12 +350,12 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) kStdFakeBoldInterpKeys, kStdFakeBoldInterpValues, kStdFakeBoldInterpLength); - SkScalar extra = SkScalarMul(fFont.getTextSize(), fakeBoldScale); + SkScalar extra = fFont.getTextSize() * fakeBoldScale; SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle); strokeRec.setStrokeStyle(stroke.needToApply() ? stroke.getWidth() + extra : extra, true /*strokeAndFill*/); - fStyle = GrStyle(strokeRec, fStyle.pathEffect()); + fStyle = GrStyle(strokeRec, fStyle.refPathEffect()); fFont.setFakeBoldText(false); } @@ -403,7 +370,7 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle); strokeRec.setStrokeStyle(stroke.getWidth() / fTextRatio, SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()); - fStyle = GrStyle(strokeRec, fStyle.pathEffect()); + fStyle = GrStyle(strokeRec, fStyle.refPathEffect()); } fFont.setLinearText(true); @@ -560,22 +527,23 @@ void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t fFallbackTextBlob = fallback.makeIfNeeded(&fFallbackGlyphCount); } -GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx) const { +GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs( + GrResourceProvider* resourceProvider) const { GrPathRange* glyphs = static_cast( - ctx->resourceProvider()->findAndRefResourceByUniqueKey(fGlyphPathsKey)); + resourceProvider->findAndRefResourceByUniqueKey(fGlyphPathsKey)); if (nullptr == glyphs) { if (fUsingRawGlyphPaths) { SkScalerContextEffects noeffects; - glyphs = ctx->resourceProvider()->createGlyphs(fFont.getTypeface(), noeffects, - nullptr, fStyle); + glyphs = resourceProvider->createGlyphs(fFont.getTypeface(), noeffects, + nullptr, fStyle); } else { SkGlyphCache* cache = this->getGlyphCache(); - glyphs = ctx->resourceProvider()->createGlyphs(cache->getScalerContext()->getTypeface(), - cache->getScalerContext()->getEffects(), - &cache->getDescriptor(), - fStyle); + glyphs = resourceProvider->createGlyphs(cache->getScalerContext()->getTypeface(), + cache->getScalerContext()->getEffects(), + &cache->getDescriptor(), + fStyle); } - ctx->resourceProvider()->assignUniqueKeyToResource(fGlyphPathsKey, glyphs); + resourceProvider->assignUniqueKeyToResource(fGlyphPathsKey, glyphs); } return glyphs; } @@ -596,17 +564,13 @@ inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& gl } void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, - GrDrawContext* drawContext, - const GrPaint& grPaint, - const GrClip& clip, - const SkMatrix& viewMatrix, - const SkSurfaceProps& props, - SkScalar x, SkScalar y, - const SkIRect& clipBounds, + GrRenderTargetContext* renderTargetContext, + const GrClip& clip, const SkMatrix& viewMatrix, + const SkSurfaceProps& props, SkScalar x, + SkScalar y, const SkIRect& clipBounds, GrAtlasTextContext* fallbackTextContext, const SkPaint& originalSkPaint) const { SkASSERT(fInstanceData); - SkASSERT(drawContext->isStencilBufferMultisampled() || !grPaint.isAntiAlias()); if (fInstanceData->count()) { static constexpr GrUserStencilSettings kCoverPass( @@ -619,31 +583,42 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, 0xffff>() ); - SkAutoTUnref glyphs(this->createGlyphs(ctx)); + sk_sp glyphs(this->createGlyphs(ctx->resourceProvider())); if (fLastDrawnGlyphsID != glyphs->uniqueID()) { // Either this is the first draw or the glyphs object was purged since last draw. glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count()); fLastDrawnGlyphsID = glyphs->uniqueID(); } + GrPaint grPaint; + if (!SkPaintToGrPaint(ctx, renderTargetContext, originalSkPaint, viewMatrix, &grPaint)) { + return; + } + // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy // the entire dst. Realistically this is a moot point, because any context that supports // NV_path_rendering will also support NV_blend_equation_advanced. // For clipping we'll just skip any optimizations based on the bounds. This does, however, - // hurt batching. - const SkRect bounds = SkRect::MakeIWH(drawContext->width(), drawContext->height()); + // hurt GrOp combining. + const SkRect bounds = SkRect::MakeIWH(renderTargetContext->width(), + renderTargetContext->height()); - SkAutoTUnref batch( - GrDrawPathRangeBatch::Create(viewMatrix, fTextRatio, fTextInverseRatio * x, - fTextInverseRatio * y, grPaint.getColor(), - GrPathRendering::kWinding_FillType, glyphs, fInstanceData, - bounds)); + // The run's "font" overrides the anti-aliasing of the passed in SkPaint! + GrAAType aaType; + if (this->aa() == GrAA::kYes) { + SkASSERT(renderTargetContext->isStencilBufferMultisampled()); + aaType = renderTargetContext->isUnifiedMultisampled() ? GrAAType::kMSAA + : GrAAType::kMixedSamples; + } else { + aaType = GrAAType::kNone; + } - GrPipelineBuilder pipelineBuilder(grPaint); - pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, grPaint.isAntiAlias()); - pipelineBuilder.setUserStencil(&kCoverPass); + std::unique_ptr op = GrDrawPathRangeOp::Make( + viewMatrix, fTextRatio, fTextInverseRatio * x, fTextInverseRatio * y, + std::move(grPaint), GrPathRendering::kWinding_FillType, aaType, glyphs.get(), + fInstanceData.get(), bounds); - drawContext->drawBatch(pipelineBuilder, clip, batch); + renderTargetContext->addDrawOp(clip, std::move(op)); } if (fFallbackTextBlob) { @@ -653,8 +628,8 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, fallbackSkPaint.setStrokeWidth(fStyle.strokeRec().getWidth() * fTextRatio); } - fallbackTextContext->drawTextBlob(ctx, drawContext, clip, fallbackSkPaint, viewMatrix, - props, fFallbackTextBlob.get(), x, y, nullptr, + fallbackTextContext->drawTextBlob(ctx, renderTargetContext, clip, fallbackSkPaint, + viewMatrix, props, fFallbackTextBlob.get(), x, y, nullptr, clipBounds); } } diff --git a/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.h b/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.h index 0f6735e1333a..54c0a9d75877 100644 --- a/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.h +++ b/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.h @@ -8,15 +8,15 @@ #ifndef GrStencilAndCoverTextContext_DEFINED #define GrStencilAndCoverTextContext_DEFINED -#include "GrDrawContext.h" +#include "GrRenderTargetContext.h" #include "GrStyle.h" #include "SkDrawFilter.h" #include "SkOpts.h" -#include "SkTextBlob.h" #include "SkTHash.h" #include "SkTInternalLList.h" #include "SkTLList.h" -#include "batches/GrDrawPathBatch.h" +#include "SkTextBlob.h" +#include "ops/GrDrawPathOp.h" class GrAtlasTextContext; class GrTextStrike; @@ -25,24 +25,20 @@ class SkSurfaceProps; /* * This class implements text rendering using stencil and cover path rendering - * (by the means of GrDrawTarget::drawPath). + * (by the means of GrOpList::drawPath). */ class GrStencilAndCoverTextContext { public: static GrStencilAndCoverTextContext* Create(GrAtlasTextContext* fallbackTextContext); - void drawText(GrContext*, GrDrawContext* dc, - const GrClip&, const GrPaint&, const SkPaint&, + void drawText(GrContext*, GrRenderTargetContext* rtc, const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[], - size_t byteLength, SkScalar x, - SkScalar y, const SkIRect& clipBounds); - void drawPosText(GrContext*, GrDrawContext*, - const GrClip&, const GrPaint&, const SkPaint&, - const SkMatrix& viewMatrix, const SkSurfaceProps&, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, + size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds); + void drawPosText(GrContext*, GrRenderTargetContext*, const GrClip&, const SkPaint&, + const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[], + size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds); - void drawTextBlob(GrContext*, GrDrawContext*, const GrClip&, const SkPaint&, + void drawTextBlob(GrContext*, GrRenderTargetContext*, const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const SkSurfaceProps&, const SkTextBlob*, SkScalar x, SkScalar y, SkDrawFilter*, const SkIRect& clipBounds); @@ -58,7 +54,7 @@ private: bool internalCanDraw(const SkPaint&); - void uncachedDrawTextBlob(GrContext*, GrDrawContext* dc, + void uncachedDrawTextBlob(GrContext*, GrRenderTargetContext* rtc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps&, @@ -79,36 +75,35 @@ private: void setPosText(const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset); - void draw(GrContext*, GrDrawContext*, const GrPaint&, const GrClip&, - const SkMatrix&, const SkSurfaceProps&, - SkScalar x, SkScalar y, const SkIRect& clipBounds, + void draw(GrContext*, GrRenderTargetContext*, const GrClip&, const SkMatrix&, + const SkSurfaceProps&, SkScalar x, SkScalar y, const SkIRect& clipBounds, GrAtlasTextContext* fallbackTextContext, const SkPaint& originalSkPaint) const; void releaseGlyphCache() const; size_t computeSizeInCache() const; - bool isAntiAlias() const { return fFont.isAntiAlias(); } + GrAA aa() const { return fFont.isAntiAlias() ? GrAA::kYes : GrAA::kNo; } private: - typedef GrDrawPathRangeBatch::InstanceData InstanceData; + typedef GrDrawPathRangeOp::InstanceData InstanceData; SkGlyphCache* getGlyphCache() const; - GrPathRange* createGlyphs(GrContext*) const; + GrPathRange* createGlyphs(GrResourceProvider*) const; void appendGlyph(const SkGlyph&, const SkPoint&, FallbackBlobBuilder*); - GrStyle fStyle; - SkPaint fFont; - SkScalar fTextRatio; - float fTextInverseRatio; - bool fUsingRawGlyphPaths; - GrUniqueKey fGlyphPathsKey; - int fTotalGlyphCount; - SkAutoTUnref fInstanceData; - int fFallbackGlyphCount; - sk_sp fFallbackTextBlob; - mutable SkGlyphCache* fDetachedGlyphCache; - mutable uint32_t fLastDrawnGlyphsID; + GrStyle fStyle; + SkPaint fFont; + SkScalar fTextRatio; + float fTextInverseRatio; + bool fUsingRawGlyphPaths; + GrUniqueKey fGlyphPathsKey; + int fTotalGlyphCount; + sk_sp fInstanceData; + int fFallbackGlyphCount; + sk_sp fFallbackTextBlob; + mutable SkGlyphCache* fDetachedGlyphCache; + mutable GrGpuResource::UniqueID fLastDrawnGlyphsID; }; // Text blobs/caches. diff --git a/gfx/skia/skia/src/gpu/text/GrTextBlobCache.cpp b/gfx/skia/skia/src/gpu/text/GrTextBlobCache.cpp index ce74977e49fa..f1162e2634c1 100644 --- a/gfx/skia/skia/src/gpu/text/GrTextBlobCache.cpp +++ b/gfx/skia/skia/src/gpu/text/GrTextBlobCache.cpp @@ -7,20 +7,27 @@ #include "GrTextBlobCache.h" +DECLARE_SKMESSAGEBUS_MESSAGE(GrTextBlobCache::PurgeBlobMessage) + GrTextBlobCache::~GrTextBlobCache() { - this->freeAll(); + SkDEBUGCODE(this->freeAll();) } void GrTextBlobCache::freeAll() { - SkTDynamicHash::Iter iter(&fCache); - while (!iter.done()) { - GrAtlasTextBlob* blob = &(*iter); - fBlobList.remove(blob); - blob->unref(); - ++iter; - } - fCache.rewind(); + fBlobIDCache.foreach([this](uint32_t, BlobIDCacheEntry* entry) { + for (const auto& blob : entry->fBlobs) { + fBlobList.remove(blob.get()); + } + }); + + fBlobIDCache.reset(); // There should be no allocations in the memory pool at this point SkASSERT(fPool.isEmpty()); + SkASSERT(fBlobList.isEmpty()); +} + +void GrTextBlobCache::PostPurgeBlobMessage(uint32_t id) { + SkASSERT(id != SK_InvalidGenID); + SkMessageBus::Post(PurgeBlobMessage({id})); } diff --git a/gfx/skia/skia/src/gpu/text/GrTextBlobCache.h b/gfx/skia/skia/src/gpu/text/GrTextBlobCache.h index e3b2ca73fb62..87a3751bf86f 100644 --- a/gfx/skia/skia/src/gpu/text/GrTextBlobCache.h +++ b/gfx/skia/skia/src/gpu/text/GrTextBlobCache.h @@ -9,8 +9,11 @@ #define GrTextBlobCache_DEFINED #include "GrAtlasTextContext.h" -#include "SkTDynamicHash.h" +#include "SkMessageBus.h" +#include "SkRefCnt.h" +#include "SkTArray.h" #include "SkTextBlobRunIterator.h" +#include "SkTHash.h" class GrTextBlobCache { public: @@ -30,45 +33,43 @@ public: ~GrTextBlobCache(); // creates an uncached blob - GrAtlasTextBlob* createBlob(int glyphCount, int runCount) { - return GrAtlasTextBlob::Create(&fPool, glyphCount, runCount); - } - GrAtlasTextBlob* createBlob(const SkTextBlob* blob) { - int glyphCount = 0; - int runCount = 0; - BlobGlyphCount(&glyphCount, &runCount, blob); - GrAtlasTextBlob* cacheBlob = GrAtlasTextBlob::Create(&fPool, glyphCount, runCount); - return cacheBlob; + sk_sp makeBlob(int glyphCount, int runCount) { + return GrAtlasTextBlob::Make(&fPool, glyphCount, runCount); } - GrAtlasTextBlob* createCachedBlob(const SkTextBlob* blob, - const GrAtlasTextBlob::Key& key, - const SkMaskFilter::BlurRec& blurRec, - const SkPaint& paint) { + sk_sp makeBlob(const SkTextBlob* blob) { int glyphCount = 0; int runCount = 0; BlobGlyphCount(&glyphCount, &runCount, blob); - GrAtlasTextBlob* cacheBlob = GrAtlasTextBlob::Create(&fPool, glyphCount, runCount); + return GrAtlasTextBlob::Make(&fPool, glyphCount, runCount); + } + + sk_sp makeCachedBlob(const SkTextBlob* blob, + const GrAtlasTextBlob::Key& key, + const SkMaskFilter::BlurRec& blurRec, + const SkPaint& paint) { + sk_sp cacheBlob(this->makeBlob(blob)); cacheBlob->setupKey(key, blurRec, paint); this->add(cacheBlob); + blob->notifyAddedToCache(); return cacheBlob; } - GrAtlasTextBlob* find(const GrAtlasTextBlob::Key& key) { - return fCache.find(key); + sk_sp find(const GrAtlasTextBlob::Key& key) const { + const auto* idEntry = fBlobIDCache.find(key.fUniqueID); + return idEntry ? idEntry->find(key) : nullptr; } void remove(GrAtlasTextBlob* blob) { - fCache.remove(blob->key()); + auto id = GrAtlasTextBlob::GetKey(*blob).fUniqueID; + auto* idEntry = fBlobIDCache.find(id); + SkASSERT(idEntry); + fBlobList.remove(blob); - blob->unref(); - } - - void add(GrAtlasTextBlob* blob) { - fCache.add(blob); - fBlobList.addToHead(blob); - - this->checkPurge(blob); + idEntry->removeBlob(blob); + if (idEntry->fBlobs.empty()) { + fBlobIDCache.remove(id); + } } void makeMRU(GrAtlasTextBlob* blob) { @@ -95,22 +96,109 @@ public: this->checkPurge(); } + struct PurgeBlobMessage { + uint32_t fID; + }; + + static void PostPurgeBlobMessage(uint32_t); + private: - typedef SkTInternalLList BitmapBlobList; + using BitmapBlobList = SkTInternalLList; + + struct BlobIDCacheEntry { + BlobIDCacheEntry() : fID(SK_InvalidGenID) {} + explicit BlobIDCacheEntry(uint32_t id) : fID(id) {} + + static uint32_t GetKey(const BlobIDCacheEntry& entry) { + return entry.fID; + } + + void addBlob(sk_sp blob) { + SkASSERT(blob); + SkASSERT(GrAtlasTextBlob::GetKey(*blob).fUniqueID == fID); + SkASSERT(!this->find(GrAtlasTextBlob::GetKey(*blob))); + + fBlobs.emplace_back(std::move(blob)); + } + + void removeBlob(GrAtlasTextBlob* blob) { + SkASSERT(blob); + SkASSERT(GrAtlasTextBlob::GetKey(*blob).fUniqueID == fID); + + auto index = this->findBlobIndex(GrAtlasTextBlob::GetKey(*blob)); + SkASSERT(index >= 0); + + fBlobs.removeShuffle(index); + } + + sk_sp find(const GrAtlasTextBlob::Key& key) const { + auto index = this->findBlobIndex(key); + return index < 0 ? nullptr : fBlobs[index]; + } + + int findBlobIndex(const GrAtlasTextBlob::Key& key) const{ + for (int i = 0; i < fBlobs.count(); ++i) { + if (GrAtlasTextBlob::GetKey(*fBlobs[i]) == key) { + return i; + } + } + return -1; + } + + uint32_t fID; + // Current clients don't generate multiple GrAtlasTextBlobs per SkTextBlob, so an array w/ + // linear search is acceptable. If usage changes, we should re-evaluate this structure. + SkSTArray<1, sk_sp, true> fBlobs; + }; + + void add(sk_sp blob) { + auto id = GrAtlasTextBlob::GetKey(*blob).fUniqueID; + auto* idEntry = fBlobIDCache.find(id); + if (!idEntry) { + idEntry = fBlobIDCache.set(id, BlobIDCacheEntry(id)); + } + + // Safe to retain a raw ptr temporarily here, because the cache will hold a ref. + GrAtlasTextBlob* rawBlobPtr = blob.get(); + fBlobList.addToHead(rawBlobPtr); + idEntry->addBlob(std::move(blob)); + + this->checkPurge(rawBlobPtr); + } void checkPurge(GrAtlasTextBlob* blob = nullptr) { - // If we are overbudget, then unref until we are below budget again + // First, purge all stale blob IDs. + { + SkTArray msgs; + fPurgeBlobInbox.poll(&msgs); + + for (const auto& msg : msgs) { + auto* idEntry = fBlobIDCache.find(msg.fID); + if (!idEntry) { + // no cache entries for id + continue; + } + + // remove all blob entries from the LRU list + for (const auto& blob : idEntry->fBlobs) { + fBlobList.remove(blob.get()); + } + + // drop the idEntry itself (unrefs all blobs) + fBlobIDCache.remove(msg.fID); + } + } + + // If we are still overbudget, then unref until we are below budget again if (fPool.size() > fBudget) { BitmapBlobList::Iter iter; iter.init(fBlobList, BitmapBlobList::Iter::kTail_IterStart); GrAtlasTextBlob* lruBlob = nullptr; while (fPool.size() > fBudget && (lruBlob = iter.get()) && lruBlob != blob) { - fCache.remove(lruBlob->key()); - // Backup the iterator before removing and unrefing the blob iter.prev(); - fBlobList.remove(lruBlob); - lruBlob->unref(); + + this->remove(lruBlob); } // If we break out of the loop with lruBlob == blob, then we haven't purged enough @@ -133,12 +221,13 @@ private: static const int kPreAllocSize = 1 << 17; static const int kMinGrowthSize = 1 << 17; static const int kDefaultBudget = 1 << 22; - BitmapBlobList fBlobList; - SkTDynamicHash fCache; GrMemoryPool fPool; + BitmapBlobList fBlobList; + SkTHashMap fBlobIDCache; PFOverBudgetCB fCallback; void* fData; size_t fBudget; + SkMessageBus::Inbox fPurgeBlobInbox; }; #endif diff --git a/gfx/skia/skia/src/gpu/text/GrTextUtils.cpp b/gfx/skia/skia/src/gpu/text/GrTextUtils.cpp index a5685f03815d..31d0291b6799 100644 --- a/gfx/skia/skia/src/gpu/text/GrTextUtils.cpp +++ b/gfx/skia/skia/src/gpu/text/GrTextUtils.cpp @@ -6,20 +6,22 @@ */ #include "GrTextUtils.h" - +#include "GrAtlasGlyphCache.h" #include "GrAtlasTextBlob.h" -#include "GrBatchFontCache.h" #include "GrBlurUtils.h" #include "GrCaps.h" #include "GrContext.h" -#include "GrDrawContext.h" - +#include "GrRenderTargetContext.h" +#include "GrSurfaceContextPriv.h" #include "SkDistanceFieldGen.h" +#include "SkDrawFilter.h" #include "SkDrawProcs.h" #include "SkFindAndPlaceGlyph.h" #include "SkGlyphCache.h" +#include "SkGr.h" #include "SkPaint.h" #include "SkRect.h" +#include "SkTextBlobRunIterator.h" #include "SkTextMapStateProc.h" #include "SkTextToPathIter.h" @@ -37,13 +39,44 @@ static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; #endif }; -void GrTextUtils::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, - GrBatchFontCache* fontCache, - const SkSurfaceProps& props, const SkPaint& skPaint, - GrColor color, uint32_t scalerContextFlags, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - SkScalar x, SkScalar y) { +bool GrTextUtils::Paint::toGrPaint(GrMaskFormat maskFormat, GrRenderTargetContext* rtc, + const SkMatrix& viewMatrix, GrPaint* grPaint) const { + // TODO: this is the last use of GrSurfaceContextPriv + GrContext* context = rtc->surfPriv().getContext(); + if (kARGB_GrMaskFormat == maskFormat) { + return SkPaintToGrPaintWithPrimitiveColor(context, rtc, this->skPaint(), grPaint); + } else { + return SkPaintToGrPaint(context, rtc, this->skPaint(), viewMatrix, grPaint); + } +} + +bool GrTextUtils::RunPaint::modifyForRun(const SkTextBlobRunIterator& run) { + if (!fModifiedPaint.isValid()) { + fModifiedPaint.init(fOriginalPaint->skPaint()); + fPaint = fModifiedPaint.get(); + } else if (fFilter) { + // We have to reset before applying the run because the filter could have arbitrary + // changed the paint. + *fModifiedPaint.get() = fOriginalPaint->skPaint(); + } + run.applyFontToPaint(fModifiedPaint.get()); + + if (fFilter) { + if (!fFilter->filter(fModifiedPaint.get(), SkDrawFilter::kText_Type)) { + // A false return from filter() means we should abort the current draw. + return false; + } + // The draw filter could have changed either the paint color or color filter. + this->initFilteredColor(); + } + fModifiedPaint.get()->setFlags(FilterTextFlags(fProps, *fModifiedPaint.get())); + return true; +} + +void GrTextUtils::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache* fontCache, + const SkSurfaceProps& props, const GrTextUtils::Paint& paint, + uint32_t scalerContextFlags, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, SkScalar x, SkScalar y) { SkASSERT(byteLength == 0 || text != nullptr); // nothing to draw @@ -54,34 +87,30 @@ void GrTextUtils::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, // Ensure the blob is set for bitmaptext blob->setHasBitmap(); - GrBatchTextStrike* currStrike = nullptr; + GrAtlasTextStrike* currStrike = nullptr; - SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, skPaint, - &viewMatrix); + SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix); SkFindAndPlaceGlyph::ProcessText( - skPaint.getTextEncoding(), text, byteLength, - {x, y}, viewMatrix, skPaint.getTextAlign(), + paint.skPaint().getTextEncoding(), text, byteLength, + {x, y}, viewMatrix, paint.skPaint().getTextAlign(), cache, [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { - position += rounding; - BmpAppendGlyph( - blob, runIndex, fontCache, &currStrike, glyph, - SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY), - color, cache); + position += rounding; + BmpAppendGlyph( + blob, runIndex, fontCache, &currStrike, glyph, + SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY), + paint.filteredPremulGrColor(), cache); } ); SkGlyphCache::AttachCache(cache); } -void GrTextUtils::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, - GrBatchFontCache* fontCache, - const SkSurfaceProps& props, const SkPaint& skPaint, - GrColor color, uint32_t scalerContextFlags, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset) { +void GrTextUtils::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache* fontCache, + const SkSurfaceProps& props, const GrTextUtils::Paint& paint, + uint32_t scalerContextFlags, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset) { SkASSERT(byteLength == 0 || text != nullptr); SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); @@ -93,21 +122,20 @@ void GrTextUtils::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, // Ensure the blob is set for bitmaptext blob->setHasBitmap(); - GrBatchTextStrike* currStrike = nullptr; + GrAtlasTextStrike* currStrike = nullptr; - SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, skPaint, - &viewMatrix); + SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix); SkFindAndPlaceGlyph::ProcessPosText( - skPaint.getTextEncoding(), text, byteLength, + paint.skPaint().getTextEncoding(), text, byteLength, offset, viewMatrix, pos, scalarsPerPosition, - skPaint.getTextAlign(), cache, + paint.skPaint().getTextAlign(), cache, [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { position += rounding; BmpAppendGlyph( blob, runIndex, fontCache, &currStrike, glyph, SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY), - color, cache); + paint.filteredPremulGrColor(), cache); } ); @@ -115,8 +143,8 @@ void GrTextUtils::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, } void GrTextUtils::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, - GrBatchFontCache* fontCache, - GrBatchTextStrike** strike, const SkGlyph& skGlyph, + GrAtlasGlyphCache* fontCache, + GrAtlasTextStrike** strike, const SkGlyph& skGlyph, int vx, int vy, GrColor color, SkGlyphCache* cache) { if (!*strike) { *strike = fontCache->getStrike(cache); @@ -145,7 +173,7 @@ void GrTextUtils::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, r.fBottom = r.fTop + SkIntToScalar(height); blob->appendGlyph(runIndex, r, color, *strike, glyph, cache, skGlyph, - SkIntToScalar(vx), SkIntToScalar(vy), 1.0f, false); + SkIntToScalar(vx), SkIntToScalar(vy), 1.0f, true); } bool GrTextUtils::CanDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix, @@ -156,7 +184,7 @@ bool GrTextUtils::CanDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix } SkScalar maxScale = viewMatrix.getMaxScale(); - SkScalar scaledTextSize = maxScale*skPaint.getTextSize(); + SkScalar scaledTextSize = maxScale * skPaint.getTextSize(); // Hinted text looks far better at small resolutions // Scaling up beyond 2x yields undesireable artifacts if (scaledTextSize < kMinDFFontSize || @@ -241,8 +269,8 @@ void GrTextUtils::InitDistanceFieldPaint(GrAtlasTextBlob* blob, } void GrTextUtils::DrawDFText(GrAtlasTextBlob* blob, int runIndex, - GrBatchFontCache* fontCache, const SkSurfaceProps& props, - const SkPaint& skPaint, GrColor color, uint32_t scalerContextFlags, + GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, + const GrTextUtils::Paint& paint, uint32_t scalerContextFlags, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y) { @@ -253,6 +281,7 @@ void GrTextUtils::DrawDFText(GrAtlasTextBlob* blob, int runIndex, return; } + const SkPaint& skPaint = paint.skPaint(); SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(), skPaint.isDevKernText(), true); @@ -311,18 +340,15 @@ void GrTextUtils::DrawDFText(GrAtlasTextBlob* blob, int runIndex, y -= alignY; SkPoint offset = SkPoint::Make(x, y); - DrawDFPosText(blob, runIndex, fontCache, props, skPaint, color, scalerContextFlags, viewMatrix, - text, byteLength, positions.begin(), 2, offset); + DrawDFPosText(blob, runIndex, fontCache, props, paint, scalerContextFlags, viewMatrix, text, + byteLength, positions.begin(), 2, offset); } -void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, - GrBatchFontCache* fontCache, const SkSurfaceProps& props, - const SkPaint& origPaint, - GrColor color, uint32_t scalerContextFlags, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset) { +void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache* fontCache, + const SkSurfaceProps& props, const GrTextUtils::Paint& paint, + uint32_t scalerContextFlags, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset) { SkASSERT(byteLength == 0 || text != nullptr); SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); @@ -336,12 +362,12 @@ void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, // Setup distance field paint and text ratio SkScalar textRatio; - SkPaint dfPaint(origPaint); + SkPaint dfPaint(paint); GrTextUtils::InitDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix); blob->setHasDistanceField(); - blob->setSubRunHasDistanceFields(runIndex, origPaint.isLCDRenderText()); + blob->setSubRunHasDistanceFields(runIndex, paint.skPaint().isLCDRenderText()); - GrBatchTextStrike* currStrike = nullptr; + GrAtlasTextStrike* currStrike = nullptr; // We apply the fake-gamma by altering the distance in the shader, so we ignore the // passed-in scaler context flags. (It's only used when we fall-back to bitmap text). @@ -363,13 +389,8 @@ void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkScalar x = offset.x() + pos[0]; SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0); - if (!DfAppendGlyph(blob, - runIndex, - fontCache, - &currStrike, - glyph, - x, y, color, cache, - textRatio, viewMatrix)) { + if (!DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, x, y, + paint.filteredPremulGrColor(), cache, textRatio, viewMatrix)) { // couldn't append, send to fallback fallbackTxt.append(SkToInt(text-lastText), lastText); *fallbackPos.append() = pos[0]; @@ -395,14 +416,8 @@ void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkScalar advanceX = SkFloatToScalar(glyph.fAdvanceX) * alignMul * textRatio; SkScalar advanceY = SkFloatToScalar(glyph.fAdvanceY) * alignMul * textRatio; - if (!DfAppendGlyph(blob, - runIndex, - fontCache, - &currStrike, - glyph, - x - advanceX, y - advanceY, color, - cache, - textRatio, + if (!DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, x - advanceX, + y - advanceY, paint.filteredPremulGrColor(), cache, textRatio, viewMatrix)) { // couldn't append, send to fallback fallbackTxt.append(SkToInt(text-lastText), lastText); @@ -419,15 +434,14 @@ void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkGlyphCache::AttachCache(cache); if (fallbackTxt.count()) { blob->initOverride(runIndex); - GrTextUtils::DrawBmpPosText(blob, runIndex, fontCache, props, - origPaint, origPaint.getColor(), scalerContextFlags, viewMatrix, - fallbackTxt.begin(), fallbackTxt.count(), + GrTextUtils::DrawBmpPosText(blob, runIndex, fontCache, props, paint, scalerContextFlags, + viewMatrix, fallbackTxt.begin(), fallbackTxt.count(), fallbackPos.begin(), scalarsPerPosition, offset); } } -bool GrTextUtils::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrBatchFontCache* cache, - GrBatchTextStrike** strike, const SkGlyph& skGlyph, +bool GrTextUtils::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache* cache, + GrAtlasTextStrike** strike, const SkGlyph& skGlyph, SkScalar sx, SkScalar sy, GrColor color, SkGlyphCache* glyphCache, SkScalar textRatio, const SkMatrix& viewMatrix) { @@ -464,16 +478,15 @@ bool GrTextUtils::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrBatchFont SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, glyphCache, skGlyph, - sx - dx, sy - dy, scale, true); + sx - dx, sy - dy, scale, false); return true; } -void GrTextUtils::DrawTextAsPath(GrContext* context, GrDrawContext* dc, - const GrClip& clip, - const SkPaint& skPaint, const SkMatrix& viewMatrix, +void GrTextUtils::DrawTextAsPath(GrContext* context, GrRenderTargetContext* rtc, const GrClip& clip, + const SkPaint& paint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds) { - SkTextToPathIter iter(text, byteLength, skPaint, true); + SkTextToPathIter iter(text, byteLength, paint, true); SkMatrix matrix; matrix.setScale(iter.getPathScale(), iter.getPathScale()); @@ -486,7 +499,7 @@ void GrTextUtils::DrawTextAsPath(GrContext* context, GrDrawContext* dc, matrix.postTranslate(xpos - prevXPos, 0); if (iterPath) { const SkPaint& pnt = iter.getPaint(); - GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, *iterPath, + GrBlurUtils::drawPathWithMaskFilter(context, rtc, clip, *iterPath, pnt, viewMatrix, &matrix, clipBounds, false); } prevXPos = xpos; @@ -494,7 +507,7 @@ void GrTextUtils::DrawTextAsPath(GrContext* context, GrDrawContext* dc, } void GrTextUtils::DrawPosTextAsPath(GrContext* context, - GrDrawContext* dc, + GrRenderTargetContext* rtc, const SkSurfaceProps& props, const GrClip& clip, const SkPaint& origPaint, const SkMatrix& viewMatrix, @@ -524,7 +537,7 @@ void GrTextUtils::DrawPosTextAsPath(GrContext* context, // Now restore the original settings, so we "draw" with whatever style/stroking. paint.setStyle(origPaint.getStyle()); - paint.setPathEffect(sk_ref_sp(origPaint.getPathEffect())); + paint.setPathEffect(origPaint.refPathEffect()); while (text < stop) { const SkGlyph& glyph = glyphCacheProc(cache, &text); @@ -538,7 +551,7 @@ void GrTextUtils::DrawPosTextAsPath(GrContext* context, matrix[SkMatrix::kMTransX] = loc.fX; matrix[SkMatrix::kMTransY] = loc.fY; - GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, *path, paint, + GrBlurUtils::drawPathWithMaskFilter(context, rtc, clip, *path, paint, viewMatrix, &matrix, clipBounds, false); } } diff --git a/gfx/skia/skia/src/gpu/text/GrTextUtils.h b/gfx/skia/skia/src/gpu/text/GrTextUtils.h index c218ab7da197..c5daa42a1530 100644 --- a/gfx/skia/skia/src/gpu/text/GrTextUtils.h +++ b/gfx/skia/skia/src/gpu/text/GrTextUtils.h @@ -9,95 +9,153 @@ #define GrTextUtils_DEFINED #include "GrColor.h" +#include "SkColorFilter.h" +#include "SkGr.h" #include "SkPaint.h" #include "SkScalar.h" +#include "SkTLazy.h" +class GrAtlasGlyphCache; class GrAtlasTextBlob; -class GrBatchFontCache; -class GrBatchTextStrike; +class GrAtlasTextStrike; class GrClip; class GrContext; -class GrDrawContext; +class GrPaint; +class GrRenderTargetContext; class GrShaderCaps; +class SkDrawFilter; class SkGlyph; class SkMatrix; struct SkIRect; struct SkPoint; class SkGlyphCache; +class SkTextBlobRunIterator; class SkSurfaceProps; -/* +/** * A class to house a bunch of common text utilities. This class should *ONLY* have static * functions. It is not a namespace only because we wish to friend SkPaint - * */ class GrTextUtils { public: + /** + * This is used to wrap a SkPaint and its post-color filter color. It is also used by RunPaint + * (below). This keeps a pointer to the SkPaint it is initialized with and expects it to remain + * const. It is also used to transform to GrPaint. + */ + class Paint { + public: + explicit Paint(const SkPaint* paint) : fPaint(paint) { this->initFilteredColor(); } + + // These expose the paint's color run through its color filter (if any). This is only valid + // when drawing grayscale/lcd glyph masks and not when drawing color glyphs. + SkColor filteredSkColor() const { return fFilteredSkColor; } + GrColor filteredPremulGrColor() const { return fFilteredGrColor; } + + const SkPaint& skPaint() const { return *fPaint; } + operator const SkPaint&() const { return this->skPaint(); } + + bool toGrPaint(GrMaskFormat, GrRenderTargetContext*, const SkMatrix& viewMatrix, + GrPaint*) const; + + protected: + void initFilteredColor() { + fFilteredSkColor = fPaint->getColor(); + if (fPaint->getColorFilter()) { + fFilteredSkColor = fPaint->getColorFilter()->filterColor(fFilteredSkColor); + } + fFilteredGrColor = SkColorToPremulGrColor(fFilteredSkColor); + } + Paint() = default; + const SkPaint* fPaint; + // This is the paint's color run through its color filter, if present. This color should + // be used except when rendering bitmap text, in which case the bitmap must be filtered in + // the fragment shader. + SkColor fFilteredSkColor; + SkColor fFilteredGrColor; + }; + + /** + * An extension of Paint that incorporated per-run modifications to the paint text settings and + * application of a draw filter. It expects its constructor arguments to remain alive and const + * during its lifetime. + */ + class RunPaint : public Paint { + public: + RunPaint(const Paint* paint, SkDrawFilter* filter, const SkSurfaceProps& props) + : fOriginalPaint(paint), fFilter(filter), fProps(props) { + // Initially we represent the original paint. + fPaint = &fOriginalPaint->skPaint(); + fFilteredSkColor = fOriginalPaint->filteredSkColor(); + fFilteredGrColor = fOriginalPaint->filteredPremulGrColor(); + } + + bool modifyForRun(const SkTextBlobRunIterator&); + + private: + SkTLazy fModifiedPaint; + const Paint* fOriginalPaint; + SkDrawFilter* fFilter; + const SkSurfaceProps& fProps; + }; + // Functions for appending BMP text to GrAtlasTextBlob - static void DrawBmpText(GrAtlasTextBlob*, int runIndex, - GrBatchFontCache*, const SkSurfaceProps&, - const SkPaint&, - GrColor, uint32_t scalerContextFlags, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, + static void DrawBmpText(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, + const SkSurfaceProps&, const Paint& paint, uint32_t scalerContextFlags, + const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y); - static void DrawBmpPosText(GrAtlasTextBlob*, int runIndex, - GrBatchFontCache*, const SkSurfaceProps&, const SkPaint&, - GrColor, uint32_t scalerContextFlags, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset); + static void DrawBmpPosText(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, + const SkSurfaceProps&, const Paint& paint, + uint32_t scalerContextFlags, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset); // functions for appending distance field text static bool CanDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const GrShaderCaps& caps); - static void DrawDFText(GrAtlasTextBlob* blob, int runIndex, - GrBatchFontCache*, const SkSurfaceProps&, - const SkPaint& skPaint, GrColor color, uint32_t scalerContextFlags, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, + static void DrawDFText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache*, + const SkSurfaceProps&, const Paint& paint, uint32_t scalerContextFlags, + const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y); - static void DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, - GrBatchFontCache*, const SkSurfaceProps&, const SkPaint&, - GrColor color, uint32_t scalerContextFlags, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset); + static void DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache*, + const SkSurfaceProps&, const Paint& paint, + uint32_t scalerContextFlags, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset); // Functions for drawing text as paths - static void DrawTextAsPath(GrContext*, GrDrawContext*, const GrClip& clip, - const SkPaint& origPaint, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, SkScalar x, SkScalar y, + static void DrawTextAsPath(GrContext*, GrRenderTargetContext*, const GrClip& clip, + const SkPaint& paint, const SkMatrix& viewMatrix, const char text[], + size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds); - static void DrawPosTextAsPath(GrContext* context, - GrDrawContext* dc, - const SkSurfaceProps& props, - const GrClip& clip, - const SkPaint& origPaint, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkIRect& clipBounds); + static void DrawPosTextAsPath(GrContext* context, GrRenderTargetContext* rtc, + const SkSurfaceProps& props, const GrClip& clip, + const SkPaint& paint, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, const SkScalar pos[], + int scalarsPerPosition, const SkPoint& offset, + const SkIRect& clipBounds); static bool ShouldDisableLCD(const SkPaint& paint); - static uint32_t FilterTextFlags(const SkSurfaceProps& surfaceProps, const SkPaint& paint); private: + static uint32_t FilterTextFlags(const SkSurfaceProps& surfaceProps, const SkPaint& paint); + static void InitDistanceFieldPaint(GrAtlasTextBlob* blob, SkPaint* skPaint, SkScalar* textRatio, const SkMatrix& viewMatrix); - static void BmpAppendGlyph(GrAtlasTextBlob*, int runIndex, GrBatchFontCache*, - GrBatchTextStrike**, const SkGlyph&, int left, int top, + static void BmpAppendGlyph(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, + GrAtlasTextStrike**, const SkGlyph&, int left, int top, GrColor color, SkGlyphCache*); - static bool DfAppendGlyph(GrAtlasTextBlob*, int runIndex, GrBatchFontCache*, - GrBatchTextStrike**, const SkGlyph&, + static bool DfAppendGlyph(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, + GrAtlasTextStrike**, const SkGlyph&, SkScalar sx, SkScalar sy, GrColor color, SkGlyphCache* cache, SkScalar textRatio, const SkMatrix& viewMatrix); diff --git a/gfx/skia/skia/src/gpu/vk/GrVkBackendContext.cpp b/gfx/skia/skia/src/gpu/vk/GrVkBackendContext.cpp index a2165b410707..3b53f8368718 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkBackendContext.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkBackendContext.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkAutoMalloc.h" #include "vk/GrVkBackendContext.h" #include "vk/GrVkExtensions.h" #include "vk/GrVkInterface.h" @@ -18,7 +19,6 @@ const char* kDebugLayerNames[] = { // elements of VK_LAYER_LUNARG_standard_validation "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", - "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_core_validation", @@ -38,9 +38,32 @@ const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 3); const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 8); #endif +#define ACQUIRE_VK_PROC(name, instance, device) \ + PFN_vk##name grVk##name = \ + reinterpret_cast(getProc("vk" #name, instance, device)); \ + if (grVk##name == nullptr) { \ + SkDebugf("Function ptr for vk%s could not be acquired\n", #name); \ + return nullptr; \ + } + // Create the base Vulkan objects needed by the GrVkGpu object const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndexPtr, - CanPresentFn canPresent) { + CanPresentFn canPresent, + GrVkInterface::GetProc getProc) { +#ifdef SK_LINK_WITH_VULKAN + if (getProc == nullptr) { + getProc = [](const char* proc_name, + VkInstance instance, VkDevice device) { + if (device != VK_NULL_HANDLE) { + return vkGetDeviceProcAddr(device, proc_name); + } + return vkGetInstanceProcAddr(instance, proc_name); + }; + } +#else + SkASSERT(getProc != nullptr); +#endif + VkPhysicalDevice physDev; VkDevice device; VkInstance inst; @@ -56,7 +79,7 @@ const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndex kGrVkMinimumVersion, // apiVersion }; - GrVkExtensions extensions; + GrVkExtensions extensions(getProc); extensions.initInstance(kGrVkMinimumVersion); SkTArray instanceLayerNames; @@ -92,7 +115,7 @@ const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndex instanceExtensionNames.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); extensionFlags |= kKHR_android_surface_GrVkExtensionFlag; } -#elif defined(SK_BUILD_FOR_UNIX) +#elif defined(SK_BUILD_FOR_UNIX) && !defined(__Fuchsia__) if (extensions.hasInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) { instanceExtensionNames.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); extensionFlags |= kKHR_xcb_surface_GrVkExtensionFlag; @@ -110,40 +133,50 @@ const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndex instanceExtensionNames.begin(), // ppEnabledExtensionNames }; - err = vkCreateInstance(&instance_create, nullptr, &inst); + ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE); + err = grVkCreateInstance(&instance_create, nullptr, &inst); if (err < 0) { SkDebugf("vkCreateInstance failed: %d\n", err); return nullptr; } + ACQUIRE_VK_PROC(DestroyInstance, inst, VK_NULL_HANDLE); + ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE); + ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE); + ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE); + ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE); + ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE); + ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE); + ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE); + uint32_t gpuCount; - err = vkEnumeratePhysicalDevices(inst, &gpuCount, nullptr); + err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr); if (err) { SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err); - vkDestroyInstance(inst, nullptr); + grVkDestroyInstance(inst, nullptr); return nullptr; } SkASSERT(gpuCount > 0); // Just returning the first physical device instead of getting the whole array. // TODO: find best match for our needs gpuCount = 1; - err = vkEnumeratePhysicalDevices(inst, &gpuCount, &physDev); + err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev); if (err) { SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err); - vkDestroyInstance(inst, nullptr); + grVkDestroyInstance(inst, nullptr); return nullptr; } // query to get the initial queue props size uint32_t queueCount; - vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr); + grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr); SkASSERT(queueCount >= 1); SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties)); // now get the actual queue props VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get(); - vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps); + grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps); // iterate to find the graphics queue uint32_t graphicsQueueIndex = queueCount; @@ -190,7 +223,7 @@ const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndex // query to get the physical device properties VkPhysicalDeviceFeatures deviceFeatures; - vkGetPhysicalDeviceFeatures(physDev, &deviceFeatures); + grVkGetPhysicalDeviceFeatures(physDev, &deviceFeatures); // this looks like it would slow things down, // and we can't depend on it on all platforms deviceFeatures.robustBufferAccess = VK_FALSE; @@ -242,15 +275,25 @@ const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndex &deviceFeatures // ppEnabledFeatures }; - err = vkCreateDevice(physDev, &deviceInfo, nullptr, &device); + err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device); if (err) { SkDebugf("CreateDevice failed: %d\n", err); - vkDestroyInstance(inst, nullptr); + grVkDestroyInstance(inst, nullptr); + return nullptr; + } + + auto interface = + sk_make_sp(getProc, inst, device, extensionFlags); + if (!interface->validate(extensionFlags)) { + SkDebugf("Vulkan interface validation failed\n"); + grVkDeviceWaitIdle(device); + grVkDestroyDevice(device, nullptr); + grVkDestroyInstance(inst, nullptr); return nullptr; } VkQueue queue; - vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue); + grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue); GrVkBackendContext* ctx = new GrVkBackendContext(); ctx->fInstance = inst; @@ -261,15 +304,19 @@ const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndex ctx->fMinAPIVersion = kGrVkMinimumVersion; ctx->fExtensions = extensionFlags; ctx->fFeatures = featureFlags; - ctx->fInterface.reset(GrVkCreateInterface(inst, device, extensionFlags)); + ctx->fInterface.reset(interface.release()); return ctx; } GrVkBackendContext::~GrVkBackendContext() { - vkDeviceWaitIdle(fDevice); - vkDestroyDevice(fDevice, nullptr); + if (fInterface == nullptr) { + return; + } + + fInterface->fFunctions.fDeviceWaitIdle(fDevice); + fInterface->fFunctions.fDestroyDevice(fDevice, nullptr); fDevice = VK_NULL_HANDLE; - vkDestroyInstance(fInstance, nullptr); + fInterface->fFunctions.fDestroyInstance(fInstance, nullptr); fInstance = VK_NULL_HANDLE; } diff --git a/gfx/skia/skia/src/gpu/vk/GrVkBuffer.cpp b/gfx/skia/skia/src/gpu/vk/GrVkBuffer.cpp index 82674b4cfbfe..a0faa21b62ac 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkBuffer.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkBuffer.cpp @@ -110,6 +110,9 @@ void GrVkBuffer::vkRelease(const GrVkGpu* gpu) { VALIDATE(); fResource->recycle(const_cast(gpu)); fResource = nullptr; + if (!fDesc.fDynamic) { + delete[] (unsigned char*)fMapPtr; + } fMapPtr = nullptr; VALIDATE(); } @@ -117,6 +120,9 @@ void GrVkBuffer::vkRelease(const GrVkGpu* gpu) { void GrVkBuffer::vkAbandon() { fResource->unrefAndAbandon(); fResource = nullptr; + if (!fDesc.fDynamic) { + delete[] (unsigned char*)fMapPtr; + } fMapPtr = nullptr; VALIDATE(); } diff --git a/gfx/skia/skia/src/gpu/vk/GrVkCaps.cpp b/gfx/skia/skia/src/gpu/vk/GrVkCaps.cpp index d982756cc331..4f05b4fc96be 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkCaps.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkCaps.cpp @@ -6,20 +6,21 @@ */ #include "GrVkCaps.h" - +#include "GrRenderTargetProxy.h" +#include "GrShaderCaps.h" #include "GrVkUtil.h" -#include "glsl/GrGLSLCaps.h" -#include "vk/GrVkInterface.h" #include "vk/GrVkBackendContext.h" +#include "vk/GrVkInterface.h" GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface, VkPhysicalDevice physDev, uint32_t featureFlags, uint32_t extensionFlags) : INHERITED(contextOptions) { fCanUseGLSLForShaderModule = false; fMustDoCopiesFromOrigin = false; - fAllowInitializationErrorOnTearDown = false; fSupportsCopiesAsDraws = false; fMustSubmitCommandsBeforeCopyOp = false; + fMustSleepOnTearDown = false; + fNewSecondaryCBOnPipelineChange = false; /************************************************************************** * GrDrawTargetCaps fields @@ -37,6 +38,7 @@ GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* fUseDrawInsteadOfClear = false; fFenceSyncSupport = true; // always available in Vulkan + fCrossContextTextureSupport = false; // TODO: Add thread-safe memory pools so we can enable this fMapBufferFlags = kNone_MapFlags; //TODO: figure this out fBufferMapThreshold = SK_MaxS32; //TODO: figure this out @@ -46,11 +48,32 @@ GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* fMaxColorSampleCount = 4; // minimum required by spec fMaxStencilSampleCount = 4; // minimum required by spec - fShaderCaps.reset(new GrGLSLCaps(contextOptions)); + fShaderCaps.reset(new GrShaderCaps(contextOptions)); this->init(contextOptions, vkInterface, physDev, featureFlags, extensionFlags); } +bool GrVkCaps::initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, + bool* rectsMustMatch, bool* disallowSubrect) const { + // Vk doesn't use rectsMustMatch or disallowSubrect. Always return false. + *rectsMustMatch = false; + *disallowSubrect = false; + + // We can always succeed here with either a CopyImage (none msaa src) or ResolveImage (msaa). + // For CopyImage we can make a simple texture, for ResolveImage we require the dst to be a + // render target as well. + desc->fOrigin = src->origin(); + desc->fConfig = src->config(); + if (src->numColorSamples() > 1 || (src->asTextureProxy() && this->supportsCopiesAsDraws())) { + desc->fFlags = kRenderTarget_GrSurfaceFlag; + } else { + // Just going to use CopyImage here + desc->fFlags = kNone_GrSurfaceFlags; + } + + return true; +} + void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface, VkPhysicalDevice physDev, uint32_t featureFlags, uint32_t extensionFlags) { @@ -61,7 +84,7 @@ void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface* GR_VK_CALL(vkInterface, GetPhysicalDeviceMemoryProperties(physDev, &memoryProperties)); this->initGrCaps(properties, memoryProperties, featureFlags); - this->initGLSLCaps(properties, featureFlags); + this->initShaderCaps(properties, featureFlags); this->initConfigTable(vkInterface, physDev); this->initStencilFormat(vkInterface, physDev); @@ -73,7 +96,6 @@ void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface* if (kQualcomm_VkVendor == properties.vendorID) { fMustDoCopiesFromOrigin = true; - fAllowInitializationErrorOnTearDown = true; } if (kNvidia_VkVendor == properties.vendorID) { @@ -81,9 +103,18 @@ void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface* fMustSubmitCommandsBeforeCopyOp = true; } +#if defined(SK_BUILD_FOR_WIN) + if (kNvidia_VkVendor == properties.vendorID) { + fMustSleepOnTearDown = true; + } +#elif defined(SK_BUILD_FOR_ANDROID) + if (kImagination_VkVendor == properties.vendorID) { + fMustSleepOnTearDown = true; + } +#endif + this->applyOptionsOverrides(contextOptions); - GrGLSLCaps* glslCaps = static_cast(fShaderCaps.get()); - glslCaps->applyOptionsOverrides(contextOptions); + fShaderCaps->applyOptionsOverrides(contextOptions); } int get_max_sample_count(VkSampleCountFlags flags) { @@ -120,7 +151,17 @@ void GrVkCaps::initSampleCount(const VkPhysicalDeviceProperties& properties) { void GrVkCaps::initGrCaps(const VkPhysicalDeviceProperties& properties, const VkPhysicalDeviceMemoryProperties& memoryProperties, uint32_t featureFlags) { - fMaxVertexAttributes = SkTMin(properties.limits.maxVertexInputAttributes, (uint32_t)INT_MAX); + // So GPUs, like AMD, are reporting MAX_INT support vertex attributes. In general, there is no + // need for us ever to support that amount, and it makes tests which tests all the vertex + // attribs timeout looping over that many. For now, we'll cap this at 64 max and can raise it if + // we ever find that need. + static const uint32_t kMaxVertexAttributes = 64; + fMaxVertexAttributes = SkTMin(properties.limits.maxVertexInputAttributes, kMaxVertexAttributes); + // AMD advertises support for MAX_UINT vertex input attributes, but in reality only supports 32. + if (kAMD_VkVendor == properties.vendorID) { + fMaxVertexAttributes = SkTMin(fMaxVertexAttributes, 32); + } + // We could actually query and get a max size for each config, however maxImageDimension2D will // give the minimum max size across all configs. So for simplicity we will use that for now. fMaxRenderTargetSize = SkTMin(properties.limits.maxImageDimension2D, (uint32_t)INT_MAX); @@ -137,70 +178,89 @@ void GrVkCaps::initGrCaps(const VkPhysicalDeviceProperties& properties, fStencilWrapOpsSupport = true; fOversizedStencilSupport = true; fSampleShadingSupport = SkToBool(featureFlags & kSampleRateShading_GrVkFeatureFlag); + + // AMD seems to have issues binding new VkPipelines inside a secondary command buffer. + // Current workaround is to use a different secondary command buffer for each new VkPipeline. + if (kAMD_VkVendor == properties.vendorID) { + fNewSecondaryCBOnPipelineChange = true; + } } -void GrVkCaps::initGLSLCaps(const VkPhysicalDeviceProperties& properties, - uint32_t featureFlags) { - GrGLSLCaps* glslCaps = static_cast(fShaderCaps.get()); - glslCaps->fVersionDeclString = "#version 330\n"; +void GrVkCaps::initShaderCaps(const VkPhysicalDeviceProperties& properties, uint32_t featureFlags) { + GrShaderCaps* shaderCaps = fShaderCaps.get(); + shaderCaps->fVersionDeclString = "#version 330\n"; // fConfigOutputSwizzle will default to RGBA so we only need to set it for alpha only config. for (int i = 0; i < kGrPixelConfigCnt; ++i) { GrPixelConfig config = static_cast(i); if (GrPixelConfigIsAlphaOnly(config)) { - glslCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRR(); - glslCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA(); + shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRR(); + shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA(); } else { - if (kRGBA_4444_GrPixelConfig == config) { + if (kGray_8_GrPixelConfig == config) { + shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRA(); + } else if (kRGBA_4444_GrPixelConfig == config) { // The vulkan spec does not require R4G4B4A4 to be supported for texturing so we // store the data in a B4G4R4A4 texture and then swizzle it when doing texture reads // or writing to outputs. Since we're not actually changing the data at all, the // only extra work is the swizzle in the shader for all operations. - glslCaps->fConfigTextureSwizzle[i] = GrSwizzle::BGRA(); - glslCaps->fConfigOutputSwizzle[i] = GrSwizzle::BGRA(); + shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::BGRA(); + shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::BGRA(); } else { - glslCaps->fConfigTextureSwizzle[i] = GrSwizzle::RGBA(); + shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RGBA(); } } } + if (kImagination_VkVendor == properties.vendorID) { + shaderCaps->fAtan2ImplementedAsAtanYOverX = true; + } + // Vulkan is based off ES 3.0 so the following should all be supported - glslCaps->fUsesPrecisionModifiers = true; - glslCaps->fFlatInterpolationSupport = true; + shaderCaps->fUsesPrecisionModifiers = true; + shaderCaps->fFlatInterpolationSupport = true; // GrShaderCaps - glslCaps->fShaderDerivativeSupport = true; - glslCaps->fGeometryShaderSupport = SkToBool(featureFlags & kGeometryShader_GrVkFeatureFlag); + shaderCaps->fShaderDerivativeSupport = true; + shaderCaps->fGeometryShaderSupport = SkToBool(featureFlags & kGeometryShader_GrVkFeatureFlag); - glslCaps->fDualSourceBlendingSupport = SkToBool(featureFlags & kDualSrcBlend_GrVkFeatureFlag); + shaderCaps->fDualSourceBlendingSupport = SkToBool(featureFlags & kDualSrcBlend_GrVkFeatureFlag); + if (kAMD_VkVendor == properties.vendorID) { + // Currently DualSourceBlending is not working on AMD. vkCreateGraphicsPipeline fails when + // using a draw with dual source. Looking into whether it is driver bug or issue with our + // SPIR-V. Bug skia:6405 + shaderCaps->fDualSourceBlendingSupport = false; + } - glslCaps->fIntegerSupport = true; + shaderCaps->fIntegerSupport = true; // Assume the minimum precisions mandated by the SPIR-V spec. - glslCaps->fShaderPrecisionVaries = true; + shaderCaps->fShaderPrecisionVaries = true; for (int s = 0; s < kGrShaderTypeCount; ++s) { - auto& highp = glslCaps->fFloatPrecisions[s][kHigh_GrSLPrecision]; + auto& highp = shaderCaps->fFloatPrecisions[s][kHigh_GrSLPrecision]; highp.fLogRangeLow = highp.fLogRangeHigh = 127; highp.fBits = 23; - auto& mediump = glslCaps->fFloatPrecisions[s][kMedium_GrSLPrecision]; + auto& mediump = shaderCaps->fFloatPrecisions[s][kMedium_GrSLPrecision]; mediump.fLogRangeLow = mediump.fLogRangeHigh = 14; mediump.fBits = 10; - glslCaps->fFloatPrecisions[s][kLow_GrSLPrecision] = mediump; + shaderCaps->fFloatPrecisions[s][kLow_GrSLPrecision] = mediump; } - glslCaps->initSamplerPrecisionTable(); + shaderCaps->initSamplerPrecisionTable(); - glslCaps->fMaxVertexSamplers = - glslCaps->fMaxGeometrySamplers = - glslCaps->fMaxFragmentSamplers = SkTMin(SkTMin(properties.limits.maxPerStageDescriptorSampledImages, - properties.limits.maxPerStageDescriptorSamplers), - (uint32_t)INT_MAX); - glslCaps->fMaxCombinedSamplers = SkTMin(SkTMin(properties.limits.maxDescriptorSetSampledImages, - properties.limits.maxDescriptorSetSamplers), - (uint32_t)INT_MAX); + shaderCaps->fMaxVertexSamplers = + shaderCaps->fMaxGeometrySamplers = + shaderCaps->fMaxFragmentSamplers = SkTMin( + SkTMin(properties.limits.maxPerStageDescriptorSampledImages, + properties.limits.maxPerStageDescriptorSamplers), + (uint32_t)INT_MAX); + shaderCaps->fMaxCombinedSamplers = SkTMin( + SkTMin(properties.limits.maxDescriptorSetSampledImages, + properties.limits.maxDescriptorSetSamplers), + (uint32_t)INT_MAX); } bool stencil_format_supported(const GrVkInterface* interface, @@ -240,6 +300,11 @@ void GrVkCaps::initConfigTable(const GrVkInterface* interface, VkPhysicalDevice fConfigTable[i].init(interface, physDev, format); } } + + // We currently do not support compressed textures in Vulkan + const uint16_t kFlagsToRemove = ConfigInfo::kTextureable_Flag|ConfigInfo::kRenderable_Flag; + fConfigTable[kETC1_GrPixelConfig].fOptimalFlags &= ~kFlagsToRemove; + fConfigTable[kETC1_GrPixelConfig].fLinearFlags &= ~kFlagsToRemove; } void GrVkCaps::ConfigInfo::InitConfigFlags(VkFormatFeatureFlags vkFlags, uint16_t* flags) { diff --git a/gfx/skia/skia/src/gpu/vk/GrVkCaps.h b/gfx/skia/skia/src/gpu/vk/GrVkCaps.h index a4ce35aa03de..e7ffe053e0bc 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkCaps.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkCaps.h @@ -13,7 +13,7 @@ #include "vk/GrVkDefines.h" struct GrVkInterface; -class GrGLSLCaps; +class GrShaderCaps; /** * Stores some capabilities of a Vk backend. @@ -37,6 +37,8 @@ public: return SkToBool(ConfigInfo::kRenderable_Flag & fConfigTable[config].fOptimalFlags); } + bool canConfigBeImageStorage(GrPixelConfig) const override { return false; } + bool isConfigTexturableLinearly(GrPixelConfig config) const { return SkToBool(ConfigInfo::kTextureable_Flag & fConfigTable[config].fLinearFlags); } @@ -58,26 +60,43 @@ public: return SkToBool(ConfigInfo::kBlitSrc_Flag & flags); } + // Tells of if we can pass in straight GLSL string into vkCreateShaderModule bool canUseGLSLForShaderModule() const { return fCanUseGLSLForShaderModule; } + // On Adreno vulkan, they do not respect the imageOffset parameter at least in + // copyImageToBuffer. This flag says that we must do the copy starting from the origin always. bool mustDoCopiesFromOrigin() const { return fMustDoCopiesFromOrigin; } - bool allowInitializationErrorOnTearDown() const { - return fAllowInitializationErrorOnTearDown; - } - + // Check whether we support using draws for copies. bool supportsCopiesAsDraws() const { return fSupportsCopiesAsDraws; } + // On Nvidia there is a current bug where we must the current command buffer before copy + // operations or else the copy will not happen. This includes copies, blits, resolves, and copy + // as draws. bool mustSubmitCommandsBeforeCopyOp() const { return fMustSubmitCommandsBeforeCopyOp; } + // Sometimes calls to QueueWaitIdle return before actually signalling the fences + // on the command buffers even though they have completed. This causes an assert to fire when + // destroying the command buffers. Therefore we add a sleep to make sure the fence signals. + bool mustSleepOnTearDown() const { + return fMustSleepOnTearDown; + } + + // Returns true if while adding commands to secondary command buffers, we must make a new + // secondary command buffer everytime we want to bind a new VkPipeline. This is to work around a + // driver bug specifically on AMD. + bool newSecondaryCBOnPipelineChange() const { + return fNewSecondaryCBOnPipelineChange; + } + /** * Returns both a supported and most prefered stencil format to use in draws. */ @@ -85,12 +104,15 @@ public: return fPreferedStencilFormat; } - GrGLSLCaps* glslCaps() const { return reinterpret_cast(fShaderCaps.get()); } + bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, + bool* rectsMustMatch, bool* disallowSubrect) const override; private: enum VkVendor { - kQualcomm_VkVendor = 20803, + kAMD_VkVendor = 4098, + kImagination_VkVendor = 4112, kNvidia_VkVendor = 4318, + kQualcomm_VkVendor = 20803, }; void init(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface, @@ -98,7 +120,7 @@ private: void initGrCaps(const VkPhysicalDeviceProperties&, const VkPhysicalDeviceMemoryProperties&, uint32_t featureFlags); - void initGLSLCaps(const VkPhysicalDeviceProperties&, uint32_t featureFlags); + void initShaderCaps(const VkPhysicalDeviceProperties&, uint32_t featureFlags); void initSampleCount(const VkPhysicalDeviceProperties& properties); @@ -125,26 +147,18 @@ private: StencilFormat fPreferedStencilFormat; - // Tells of if we can pass in straight GLSL string into vkCreateShaderModule bool fCanUseGLSLForShaderModule; - // On Adreno vulkan, they do not respect the imageOffset parameter at least in - // copyImageToBuffer. This flag says that we must do the copy starting from the origin always. bool fMustDoCopiesFromOrigin; - // On Adreno, there is a bug where vkQueueWaitIdle will once in a while return - // VK_ERROR_INITIALIZATION_FAILED instead of the required VK_SUCCESS or VK_DEVICE_LOST. This - // flag says we will accept VK_ERROR_INITIALIZATION_FAILED as well. - bool fAllowInitializationErrorOnTearDown; - - // Check whether we support using draws for copies. bool fSupportsCopiesAsDraws; - // On Nvidia there is a current bug where we must the current command buffer before copy - // operations or else the copy will not happen. This includes copies, blits, resolves, and copy - // as draws. bool fMustSubmitCommandsBeforeCopyOp; + bool fMustSleepOnTearDown; + + bool fNewSecondaryCBOnPipelineChange; + typedef GrCaps INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkCommandBuffer.cpp b/gfx/skia/skia/src/gpu/vk/GrVkCommandBuffer.cpp index bc6272c0c632..64c1c88e9c2d 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkCommandBuffer.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkCommandBuffer.cpp @@ -345,7 +345,6 @@ void GrVkPrimaryCommandBuffer::end(const GrVkGpu* gpu) { void GrVkPrimaryCommandBuffer::beginRenderPass(const GrVkGpu* gpu, const GrVkRenderPass* renderPass, - uint32_t clearCount, const VkClearValue* clearValues, const GrVkRenderTarget& target, const SkIRect& bounds, @@ -365,7 +364,7 @@ void GrVkPrimaryCommandBuffer::beginRenderPass(const GrVkGpu* gpu, beginInfo.renderPass = renderPass->vkRenderPass(); beginInfo.framebuffer = target.framebuffer()->framebuffer(); beginInfo.renderArea = renderArea; - beginInfo.clearValueCount = clearCount; + beginInfo.clearValueCount = renderPass->clearValueCount(); beginInfo.pClearValues = clearValues; VkSubpassContents contents = forSecondaryCB ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS @@ -387,6 +386,7 @@ void GrVkPrimaryCommandBuffer::endRenderPass(const GrVkGpu* gpu) { void GrVkPrimaryCommandBuffer::executeCommands(const GrVkGpu* gpu, GrVkSecondaryCommandBuffer* buffer) { SkASSERT(fIsActive); + SkASSERT(!buffer->fIsActive); SkASSERT(fActiveRenderPass); SkASSERT(fActiveRenderPass->isCompatible(*buffer->fActiveRenderPass)); @@ -398,9 +398,12 @@ void GrVkPrimaryCommandBuffer::executeCommands(const GrVkGpu* gpu, this->invalidateState(); } -void GrVkPrimaryCommandBuffer::submitToQueue(const GrVkGpu* gpu, - VkQueue queue, - GrVkGpu::SyncQueue sync) { +void GrVkPrimaryCommandBuffer::submitToQueue( + const GrVkGpu* gpu, + VkQueue queue, + GrVkGpu::SyncQueue sync, + const GrVkSemaphore::Resource* signalSemaphore, + SkTArray& waitSemaphores) { SkASSERT(!fIsActive); VkResult err; @@ -415,17 +418,36 @@ void GrVkPrimaryCommandBuffer::submitToQueue(const GrVkGpu* gpu, GR_VK_CALL(gpu->vkInterface(), ResetFences(gpu->device(), 1, &fSubmitFence)); } + if (signalSemaphore) { + this->addResource(signalSemaphore); + } + + int waitCount = waitSemaphores.count(); + SkTArray vkWaitSems(waitCount); + SkTArray vkWaitStages(waitCount); + if (waitCount) { + for (int i = 0; i < waitCount; ++i) { + this->addResource(waitSemaphores[i]); + vkWaitSems.push_back(waitSemaphores[i]->semaphore()); + vkWaitStages.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + } + } + SkTArray vkSignalSem; + if (signalSemaphore) { + vkSignalSem.push_back(signalSemaphore->semaphore()); + } + VkSubmitInfo submitInfo; memset(&submitInfo, 0, sizeof(VkSubmitInfo)); submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pNext = nullptr; - submitInfo.waitSemaphoreCount = 0; - submitInfo.pWaitSemaphores = nullptr; - submitInfo.pWaitDstStageMask = 0; + submitInfo.waitSemaphoreCount = waitCount; + submitInfo.pWaitSemaphores = vkWaitSems.begin(); + submitInfo.pWaitDstStageMask = vkWaitStages.begin(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &fCmdBuffer; - submitInfo.signalSemaphoreCount = 0; - submitInfo.pSignalSemaphores = nullptr; + submitInfo.signalSemaphoreCount = vkSignalSem.count(); + submitInfo.pSignalSemaphores = vkSignalSem.begin(); GR_VK_CALL_ERRCHECK(gpu->vkInterface(), QueueSubmit(queue, 1, &submitInfo, fSubmitFence)); if (GrVkGpu::kForce_SyncQueue == sync) { diff --git a/gfx/skia/skia/src/gpu/vk/GrVkCommandBuffer.h b/gfx/skia/skia/src/gpu/vk/GrVkCommandBuffer.h index 8020c7db142c..e15686190cd2 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkCommandBuffer.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkCommandBuffer.h @@ -10,6 +10,7 @@ #include "GrVkGpu.h" #include "GrVkResource.h" +#include "GrVkSemaphore.h" #include "GrVkUtil.h" #include "vk/GrVkDefines.h" @@ -210,7 +211,6 @@ public: // in the render pass. void beginRenderPass(const GrVkGpu* gpu, const GrVkRenderPass* renderPass, - uint32_t clearCount, const VkClearValue* clearValues, const GrVkRenderTarget& target, const SkIRect& bounds, @@ -299,7 +299,9 @@ public: uint32_t regionCount, const VkImageResolve* regions); - void submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync); + void submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync, + const GrVkSemaphore::Resource* signalSemaphore, + SkTArray& waitSemaphores); bool finished(const GrVkGpu* gpu) const; #ifdef SK_TRACE_VK_RESOURCES diff --git a/gfx/skia/skia/src/gpu/vk/GrVkCopyManager.cpp b/gfx/skia/skia/src/gpu/vk/GrVkCopyManager.cpp index 68f7c317d18f..91c9b1a73743 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkCopyManager.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkCopyManager.cpp @@ -7,8 +7,9 @@ #include "GrVkCopyManager.h" +#include "GrSamplerParams.h" +#include "GrShaderCaps.h" #include "GrSurface.h" -#include "GrTextureParams.h" #include "GrTexturePriv.h" #include "GrVkCommandBuffer.h" #include "GrVkCopyPipeline.h" @@ -24,9 +25,16 @@ #include "SkPoint.h" #include "SkRect.h" +GrVkCopyManager::GrVkCopyManager() + : fVertShaderModule(VK_NULL_HANDLE) + , fFragShaderModule(VK_NULL_HANDLE) + , fPipelineLayout(VK_NULL_HANDLE) {} + +GrVkCopyManager::~GrVkCopyManager() {} + bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) { - const GrGLSLCaps* glslCaps = gpu->vkCaps().glslCaps(); - const char* version = glslCaps->versionDeclString(); + const GrShaderCaps* shaderCaps = gpu->caps()->shaderCaps(); + const char* version = shaderCaps->versionDeclString(); SkString vertShaderText(version); vertShaderText.append( "#extension GL_ARB_separate_shader_objects : enable\n" @@ -64,19 +72,21 @@ bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) { "}" ); - if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(), - VK_SHADER_STAGE_VERTEX_BIT, - &fVertShaderModule, &fShaderStageInfo[0])) { + SkSL::Program::Settings settings; + SkSL::Program::Inputs inputs; + if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(), VK_SHADER_STAGE_VERTEX_BIT, + &fVertShaderModule, &fShaderStageInfo[0], settings, &inputs)) { this->destroyResources(gpu); return false; } + SkASSERT(inputs.isEmpty()); - if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(), - VK_SHADER_STAGE_FRAGMENT_BIT, - &fFragShaderModule, &fShaderStageInfo[1])) { + if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT, + &fFragShaderModule, &fShaderStageInfo[1], settings, &inputs)) { this->destroyResources(gpu); return false; } + SkASSERT(inputs.isEmpty()); VkDescriptorSetLayout dsLayout[2]; @@ -122,8 +132,8 @@ bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) { fVertexBuffer->updateData(vdata, sizeof(vdata)); // We use 2 vec4's for uniforms - fUniformBuffer = GrVkUniformBuffer::Create(gpu, 8 * sizeof(float)); - SkASSERT(fUniformBuffer); + fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, 8 * sizeof(float))); + SkASSERT(fUniformBuffer.get()); return true; } @@ -151,7 +161,7 @@ bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu, SkASSERT(VK_NULL_HANDLE == fFragShaderModule && VK_NULL_HANDLE == fPipelineLayout && nullptr == fVertexBuffer.get() && - nullptr == fUniformBuffer); + nullptr == fUniformBuffer.get()); if (!this->createCopyProgram(gpu)) { SkDebugf("Failed to create copy program.\n"); return false; @@ -234,7 +244,7 @@ bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu, const GrVkDescriptorSet* samplerDS = gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle); - GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode); + GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode); GrVkSampler* sampler = resourceProv.findOrCreateCompatibleSampler(params, srcTex->texturePriv().maxMipMapLevel()); @@ -292,7 +302,7 @@ bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu, GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); - GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE, + GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE); const GrVkRenderPass* renderPass; const GrVkResourceProvider::CompatibleRPHandle& rpHandle = @@ -310,7 +320,7 @@ bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu, SkASSERT(renderPass->isCompatible(*rt->simpleRenderPass())); - cmdBuffer->beginRenderPass(gpu, renderPass, 0, nullptr, *rt, bounds, false); + cmdBuffer->beginRenderPass(gpu, renderPass, nullptr, *rt, bounds, false); cmdBuffer->bindPipeline(gpu, pipeline); // Uniform DescriptorSet, Sampler DescriptorSet, and vertex shader uniformBuffer @@ -354,7 +364,7 @@ bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu, scissor.offset.y = 0; cmdBuffer->setScissor(gpu, 0, 1, &scissor); - cmdBuffer->bindVertexBuffer(gpu, fVertexBuffer); + cmdBuffer->bindVertexBuffer(gpu, fVertexBuffer.get()); cmdBuffer->draw(gpu, 4, 1, 0, 0); cmdBuffer->endRenderPass(gpu); @@ -389,7 +399,7 @@ void GrVkCopyManager::destroyResources(GrVkGpu* gpu) { if (fUniformBuffer) { fUniformBuffer->release(gpu); - fUniformBuffer = nullptr; + fUniformBuffer.reset(); } } @@ -400,6 +410,6 @@ void GrVkCopyManager::abandonResources() { if (fUniformBuffer) { fUniformBuffer->abandon(); - fUniformBuffer = nullptr; + fUniformBuffer.reset(); } } diff --git a/gfx/skia/skia/src/gpu/vk/GrVkCopyManager.h b/gfx/skia/skia/src/gpu/vk/GrVkCopyManager.h index e19a14402d07..36a08be81937 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkCopyManager.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkCopyManager.h @@ -22,11 +22,9 @@ struct SkIRect; class GrVkCopyManager { public: - GrVkCopyManager() - : fVertShaderModule(VK_NULL_HANDLE) - , fFragShaderModule(VK_NULL_HANDLE) - , fPipelineLayout(VK_NULL_HANDLE) - , fUniformBuffer(nullptr) {} + GrVkCopyManager(); + + ~GrVkCopyManager(); bool copySurfaceAsDraw(GrVkGpu* gpu, GrSurface* dst, @@ -48,8 +46,8 @@ private: GrVkDescriptorSetManager::Handle fSamplerDSHandle; VkPipelineLayout fPipelineLayout; - SkAutoTUnref fVertexBuffer; - GrVkUniformBuffer* fUniformBuffer; + sk_sp fVertexBuffer; + std::unique_ptr fUniformBuffer; }; #endif diff --git a/gfx/skia/skia/src/gpu/vk/GrVkDescriptorSetManager.cpp b/gfx/skia/skia/src/gpu/vk/GrVkDescriptorSetManager.cpp index 868a5ce96c6c..f523cee96051 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkDescriptorSetManager.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkDescriptorSetManager.cpp @@ -11,7 +11,6 @@ #include "GrVkDescriptorSet.h" #include "GrVkGpu.h" #include "GrVkUniformHandler.h" -#include "glsl/GrGLSLSampler.h" GrVkDescriptorSetManager::GrVkDescriptorSetManager(GrVkGpu* gpu, VkDescriptorType type, @@ -20,7 +19,7 @@ GrVkDescriptorSetManager::GrVkDescriptorSetManager(GrVkGpu* gpu, if (type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { SkASSERT(uniformHandler); for (int i = 0; i < uniformHandler->numSamplers(); ++i) { - fBindingVisibilities.push_back(uniformHandler->getSampler(i).visibility()); + fBindingVisibilities.push_back(uniformHandler->samplerVisibility(i)); } } else { SkASSERT(type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); @@ -103,7 +102,7 @@ bool GrVkDescriptorSetManager::isCompatible(VkDescriptorType type, return false; } for (int i = 0; i < uniHandler->numSamplers(); ++i) { - if (uniHandler->getSampler(i).visibility() != fBindingVisibilities[i]) { + if (uniHandler->samplerVisibility(i) != fBindingVisibilities[i]) { return false; } } @@ -180,15 +179,12 @@ void GrVkDescriptorSetManager::DescriptorPoolManager::init(GrVkGpu* gpu, numSamplers = (uint32_t)visibilities->count(); } - SkAutoTDeleteArray dsSamplerBindings( + std::unique_ptr dsSamplerBindings( new VkDescriptorSetLayoutBinding[numSamplers]); for (uint32_t i = 0; i < numSamplers; ++i) { uint32_t visibility; if (uniformHandler) { - const GrVkGLSLSampler& sampler = - static_cast(uniformHandler->getSampler(i)); - SkASSERT(sampler.binding() == i); - visibility = sampler.visibility(); + visibility = uniformHandler->samplerVisibility(i); } else { visibility = (*visibilities)[i]; } diff --git a/gfx/skia/skia/src/gpu/vk/GrVkExtensions.cpp b/gfx/skia/skia/src/gpu/vk/GrVkExtensions.cpp index 03b453090fdf..17737f17998f 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkExtensions.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkExtensions.cpp @@ -30,17 +30,21 @@ static int find_string(const SkTArray& strings, const char ext[]) { return idx; } -#define GET_PROC_LOCAL(inst, F) PFN_vk ## F F = (PFN_vk ## F) vkGetInstanceProcAddr(inst, "vk" #F) +#define GET_PROC_LOCAL(F, inst, device) PFN_vk ## F F = (PFN_vk ## F) fGetProc("vk" #F, inst, device) static uint32_t remove_patch_version(uint32_t specVersion) { return (specVersion >> 12) << 12; } bool GrVkExtensions::initInstance(uint32_t specVersion) { + if (fGetProc == nullptr) { + return false; + } + uint32_t nonPatchVersion = remove_patch_version(specVersion); - GET_PROC_LOCAL(nullptr, EnumerateInstanceExtensionProperties); - GET_PROC_LOCAL(nullptr, EnumerateInstanceLayerProperties); + GET_PROC_LOCAL(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE, VK_NULL_HANDLE); + GET_PROC_LOCAL(EnumerateInstanceLayerProperties, VK_NULL_HANDLE, VK_NULL_HANDLE); SkTLessFunctionToFunctorAdaptor cmp; @@ -126,10 +130,14 @@ bool GrVkExtensions::initInstance(uint32_t specVersion) { } bool GrVkExtensions::initDevice(uint32_t specVersion, VkInstance inst, VkPhysicalDevice physDev) { + if (fGetProc == nullptr) { + return false; + } + uint32_t nonPatchVersion = remove_patch_version(specVersion); - GET_PROC_LOCAL(inst, EnumerateDeviceExtensionProperties); - GET_PROC_LOCAL(inst, EnumerateDeviceLayerProperties); + GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst, VK_NULL_HANDLE); + GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE); SkTLessFunctionToFunctorAdaptor cmp; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkExtensions.h b/gfx/skia/skia/src/gpu/vk/GrVkExtensions.h index 6c395fdddd08..8de28f4d49c9 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkExtensions.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkExtensions.h @@ -11,6 +11,7 @@ #include "../private/SkTArray.h" #include "SkString.h" #include "vk/GrVkDefines.h" +#include "vk/GrVkInterface.h" /** * This helper queries the Vulkan driver for available extensions and layers, remembers them, @@ -18,7 +19,9 @@ */ class SK_API GrVkExtensions { public: - GrVkExtensions() : fInstanceExtensionStrings(new SkTArray) + GrVkExtensions(GrVkInterface::GetProc getProc) + : fGetProc(getProc) + , fInstanceExtensionStrings(new SkTArray) , fDeviceExtensionStrings(new SkTArray) , fInstanceLayerStrings(new SkTArray) , fDeviceLayerStrings(new SkTArray) {} @@ -37,10 +40,11 @@ public: void print(const char* sep = "\n") const; private: - SkAutoTDelete > fInstanceExtensionStrings; - SkAutoTDelete > fDeviceExtensionStrings; - SkAutoTDelete > fInstanceLayerStrings; - SkAutoTDelete > fDeviceLayerStrings; + GrVkInterface::GetProc fGetProc; + std::unique_ptr> fInstanceExtensionStrings; + std::unique_ptr> fDeviceExtensionStrings; + std::unique_ptr> fInstanceLayerStrings; + std::unique_ptr> fDeviceLayerStrings; }; #endif diff --git a/gfx/skia/skia/src/gpu/vk/GrVkGLSLSampler.h b/gfx/skia/skia/src/gpu/vk/GrVkGLSLSampler.h deleted file mode 100644 index f0ba7fa33599..000000000000 --- a/gfx/skia/skia/src/gpu/vk/GrVkGLSLSampler.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -* Copyright 2016 Google Inc. -* -* Use of this source code is governed by a BSD-style license that can be -* found in the LICENSE file. -*/ - -#ifndef GrVkGLSLSampler_DEFINED -#define GrVkGLSLSampler_DEFINED - -#include "glsl/GrGLSLSampler.h" - -#include "glsl/GrGLSLShaderVar.h" - -class GrVkGLSLSampler : public GrGLSLSampler { -public: - GrVkGLSLSampler(uint32_t visibility, - GrPixelConfig config, - GrSLType type, - GrSLPrecision precision, - const char* name, - uint32_t binding, - uint32_t set) : INHERITED(visibility, config), fBinding(binding) { - SkASSERT(GrSLTypeIsCombinedSamplerType(type)); - fShaderVar.setType(type); - fShaderVar.setTypeModifier(GrGLSLShaderVar::kUniform_TypeModifier); - fShaderVar.setPrecision(precision); - fShaderVar.accessName()->set(name); - SkString layoutQualifier; - layoutQualifier.appendf("set=%d, binding=%d", set, binding); - fShaderVar.setLayoutQualifier(layoutQualifier.c_str()); - } - - GrSLType type() const override { return fShaderVar.getType(); } - uint32_t binding() const { return fBinding; } - - const char* onGetSamplerNameForTexture2D() const override { return fShaderVar.c_str(); } - const char* getSamplerNameForTexelFetch() const override { return fShaderVar.c_str(); } - -private: - GrGLSLShaderVar fShaderVar; - uint32_t fBinding; - - friend class GrVkUniformHandler; - - typedef GrGLSLSampler INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/vk/GrVkGpu.cpp b/gfx/skia/skia/src/gpu/vk/GrVkGpu.cpp index 60a876373caf..b3401e12b606 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkGpu.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkGpu.cpp @@ -25,20 +25,23 @@ #include "GrVkPipelineState.h" #include "GrVkRenderPass.h" #include "GrVkResourceProvider.h" +#include "GrVkSemaphore.h" #include "GrVkTexture.h" #include "GrVkTextureRenderTarget.h" #include "GrVkTransferBuffer.h" #include "GrVkVertexBuffer.h" -#include "SkConfig8888.h" +#include "SkConvertPixels.h" #include "SkMipMap.h" #include "vk/GrVkInterface.h" #include "vk/GrVkTypes.h" -#if USE_SKSL #include "SkSLCompiler.h" -#endif + +#if !defined(SK_BUILD_FOR_WIN) +#include +#endif // !defined(SK_BUILD_FOR_WIN) #define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X) #define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X) @@ -56,6 +59,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback( void* pUserData) { if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { SkDebugf("Vulkan error [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage); + return VK_TRUE; // skip further layers } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { SkDebugf("Vulkan warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage); } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { @@ -80,6 +84,10 @@ GrGpu* GrVkGpu::Create(GrBackendContext backendContext, const GrContextOptions& vkBackendContext->ref(); } + if (!vkBackendContext->fInterface->validate(vkBackendContext->fExtensions)) { + return nullptr; + } + return new GrVkGpu(context, options, vkBackendContext); } @@ -114,11 +122,7 @@ GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options, } #endif -#if USE_SKSL fCompiler = new SkSL::Compiler(); -#else - fCompiler = shaderc_compiler_initialize(); -#endif fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendCtx->fPhysicalDevice, backendCtx->fFeatures, backendCtx->fExtensions)); @@ -162,43 +166,39 @@ GrVkGpu::~GrVkGpu() { // wait for all commands to finish fResourceProvider.checkCommandBuffers(); - SkDEBUGCODE(VkResult res = ) VK_CALL(QueueWaitIdle(fQueue)); + VkResult res = VK_CALL(QueueWaitIdle(fQueue)); // On windows, sometimes calls to QueueWaitIdle return before actually signalling the fences // on the command buffers even though they have completed. This causes an assert to fire when // destroying the command buffers. Currently this ony seems to happen on windows, so we add a - // sleep to make sure the fence singals. + // sleep to make sure the fence signals. #ifdef SK_DEBUG + if (this->vkCaps().mustSleepOnTearDown()) { #if defined(SK_BUILD_FOR_WIN) - Sleep(10); // In milliseconds + Sleep(10); // In milliseconds #else - // Uncomment if above bug happens on non windows build. - // sleep(1); // In seconds + sleep(1); // In seconds #endif -#endif - -#ifdef SK_DEBUG - if (this->vkCaps().allowInitializationErrorOnTearDown()) { - SkASSERT(VK_SUCCESS == res || - VK_ERROR_DEVICE_LOST == res || - VK_ERROR_INITIALIZATION_FAILED == res); - } else { - SkASSERT(VK_SUCCESS == res || VK_ERROR_DEVICE_LOST == res); } #endif +#ifdef SK_DEBUG + SkASSERT(VK_SUCCESS == res || VK_ERROR_DEVICE_LOST == res); +#endif + + for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) { + fSemaphoresToWaitOn[i]->unref(this); + } + fSemaphoresToWaitOn.reset(); + fCopyManager.destroyResources(this); - // must call this just before we destroy the VkDevice - fResourceProvider.destroyResources(); + // must call this just before we destroy the command pool and VkDevice + fResourceProvider.destroyResources(VK_ERROR_DEVICE_LOST == res); VK_CALL(DestroyCommandPool(fDevice, fCmdPool, nullptr)); -#if USE_SKSL delete fCompiler; -#else - shaderc_compiler_release(fCompiler); -#endif #ifdef SK_ENABLE_VK_LAYERS if (fCallback) { @@ -211,18 +211,23 @@ GrVkGpu::~GrVkGpu() { /////////////////////////////////////////////////////////////////////////////// GrGpuCommandBuffer* GrVkGpu::createCommandBuffer( - GrRenderTarget* target, const GrGpuCommandBuffer::LoadAndStoreInfo& colorInfo, const GrGpuCommandBuffer::LoadAndStoreInfo& stencilInfo) { - GrVkRenderTarget* vkRT = static_cast(target); - return new GrVkGpuCommandBuffer(this, vkRT, colorInfo, stencilInfo); + return new GrVkGpuCommandBuffer(this, colorInfo, stencilInfo); } -void GrVkGpu::submitCommandBuffer(SyncQueue sync) { +void GrVkGpu::submitCommandBuffer(SyncQueue sync, + const GrVkSemaphore::Resource* signalSemaphore) { SkASSERT(fCurrentCmdBuffer); fCurrentCmdBuffer->end(this); - fCurrentCmdBuffer->submitToQueue(this, fQueue, sync); + fCurrentCmdBuffer->submitToQueue(this, fQueue, sync, signalSemaphore, fSemaphoresToWaitOn); + + for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) { + fSemaphoresToWaitOn[i]->unref(this); + } + fSemaphoresToWaitOn.reset(); + fResourceProvider.checkCommandBuffers(); // Release old command buffer and create a new one @@ -270,7 +275,7 @@ GrBuffer* GrVkGpu::onCreateBuffer(size_t size, GrBufferType type, GrAccessPatter bool GrVkGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height, GrPixelConfig srcConfig, DrawPreference* drawPreference, WritePixelTempDrawInfo* tempDrawInfo) { - if (kIndex_8_GrPixelConfig == srcConfig || GrPixelConfigIsCompressed(dstSurface->config())) { + if (GrPixelConfigIsCompressed(dstSurface->config())) { return false; } @@ -363,7 +368,7 @@ bool GrVkGpu::onWritePixels(GrSurface* surface, } else { int newMipLevels = texels.count(); int currentMipLevels = vkTex->texturePriv().maxMipMapLevel() + 1; - if (newMipLevels != currentMipLevels) { + if (newMipLevels > currentMipLevels) { if (!vkTex->reallocForMipmap(this, newMipLevels)) { return false; } @@ -400,8 +405,6 @@ void GrVkGpu::resolveImage(GrVkRenderTarget* dst, GrVkRenderTarget* src, const S resolveInfo.srcOffset = { srcVkRect.fLeft, srcVkRect.fTop, 0 }; resolveInfo.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; resolveInfo.dstOffset = { dstPoint.fX, dstY, 0 }; - // By the spec the depth of the extent should be ignored for 2D images, but certain devices - // (e.g. nexus 5x) currently fail if it is not 1 resolveInfo.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 1 }; dst->setImageLayout(this, @@ -419,17 +422,21 @@ void GrVkGpu::resolveImage(GrVkRenderTarget* dst, GrVkRenderTarget* src, const S fCurrentCmdBuffer->resolveImage(this, *src->msaaImage(), *dst, 1, &resolveInfo); } -void GrVkGpu::onResolveRenderTarget(GrRenderTarget* target) { +void GrVkGpu::internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit) { if (target->needsResolve()) { SkASSERT(target->numColorSamples() > 1); GrVkRenderTarget* rt = static_cast(target); SkASSERT(rt->msaaImage()); - + const SkIRect& srcRect = rt->getResolveRect(); this->resolveImage(rt, rt, srcRect, SkIPoint::Make(srcRect.fLeft, srcRect.fTop)); rt->flagAsResolved(); + + if (requiresSubmit) { + this->submitCommandBuffer(kSkip_SyncQueue); + } } } @@ -491,13 +498,8 @@ bool GrVkGpu::uploadTexDataLinear(GrVkTexture* tex, dstRow -= layout.rowPitch; } } else { - // If there is no padding on the src (rowBytes) or dst (layout.rowPitch) we can memcpy - if (trimRowBytes == rowBytes && trimRowBytes == layout.rowPitch) { - memcpy(mapPtr, data, trimRowBytes * height); - } else { - SkRectMemcpy(mapPtr, static_cast(layout.rowPitch), data, rowBytes, trimRowBytes, - height); - } + SkRectMemcpy(mapPtr, static_cast(layout.rowPitch), data, rowBytes, trimRowBytes, + height); } GrVkMemory::FlushMappedAlloc(this, alloc); @@ -515,6 +517,10 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, SkASSERT(1 == texels.count() || (0 == left && 0 == top && width == tex->width() && height == tex->height())); + // We assume that if the texture has mip levels, we either upload to all the levels or just the + // first. + SkASSERT(1 == texels.count() || texels.count() == (tex->texturePriv().maxMipMapLevel() + 1)); + // If we're uploading compressed data then we should be using uploadCompressedTexData SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); @@ -556,6 +562,10 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, size_t combinedBufferSize = width * bpp * height; int currentWidth = width; int currentHeight = height; + // The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image + // config. This works with the assumption that the bytes in pixel config is always a power of 2. + SkASSERT((bpp & (bpp - 1)) == 0); + const size_t alignmentMask = 0x3 | (bpp - 1); for (int currentMipLevel = 1; currentMipLevel < texelsShallowCopy.count(); currentMipLevel++) { currentWidth = SkTMax(1, currentWidth/2); currentHeight = SkTMax(1, currentHeight/2); @@ -567,6 +577,10 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, return false; } const size_t trimmedSize = currentWidth * bpp * currentHeight; + const size_t alignmentDiff = combinedBufferSize & alignmentMask; + if (alignmentDiff != 0) { + combinedBufferSize += alignmentMask - alignmentDiff + 1; + } individualMipOffsets.push_back(combinedBufferSize); combinedBufferSize += trimmedSize; } @@ -580,7 +594,9 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, currentWidth = width; currentHeight = height; + int layerHeight = tex->height(); for (int currentMipLevel = 0; currentMipLevel < texelsShallowCopy.count(); currentMipLevel++) { + SkASSERT(1 == texelsShallowCopy.count() || currentHeight == layerHeight); const size_t trimRowBytes = currentWidth * bpp; const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes; @@ -594,8 +610,6 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, src -= rowBytes; dst += trimRowBytes; } - } else if (trimRowBytes == rowBytes) { - memcpy(dst, src, trimRowBytes * currentHeight); } else { SkRectMemcpy(dst, trimRowBytes, src, rowBytes, trimRowBytes, currentHeight); } @@ -606,11 +620,12 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, region.bufferRowLength = currentWidth; region.bufferImageHeight = currentHeight; region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, SkToU32(currentMipLevel), 0, 1 }; - region.imageOffset = { left, flipY ? tex->height() - top - currentHeight : top, 0 }; + region.imageOffset = { left, flipY ? layerHeight - top - currentHeight : top, 0 }; region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 }; currentWidth = SkTMax(1, currentWidth/2); currentHeight = SkTMax(1, currentHeight/2); + layerHeight = currentHeight; } // no need to flush non-coherent memory, unmap will do that for us @@ -631,6 +646,9 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, regions.count(), regions.begin()); transferBuffer->unref(); + if (1 == texelsShallowCopy.count()) { + tex->texturePriv().dirtyMipMaps(true); + } return true; } @@ -752,8 +770,8 @@ static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin) { } } -GrTexture* GrVkGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, - GrWrapOwnership ownership) { +sk_sp GrVkGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, + GrWrapOwnership ownership) { if (0 == desc.fTextureHandle) { return nullptr; } @@ -783,49 +801,37 @@ GrTexture* GrVkGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, surfDesc.fConfig = desc.fConfig; surfDesc.fSampleCnt = SkTMin(desc.fSampleCnt, this->caps()->maxSampleCount()); bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag); + SkASSERT(!renderTarget || kAdoptAndCache_GrWrapOwnership != ownership); // Not supported // In GL, Chrome assumes all textures are BottomLeft // In VK, we don't have this restriction surfDesc.fOrigin = resolve_origin(desc.fOrigin); - GrVkTexture* texture = nullptr; - if (renderTarget) { - texture = GrVkTextureRenderTarget::CreateWrappedTextureRenderTarget(this, surfDesc, - ownership, info); - } else { - texture = GrVkTexture::CreateWrappedTexture(this, surfDesc, ownership, info); + if (!renderTarget) { + return GrVkTexture::MakeWrappedTexture(this, surfDesc, ownership, info); } - if (!texture) { - return nullptr; - } - - return texture; + return GrVkTextureRenderTarget::MakeWrappedTextureRenderTarget(this, surfDesc, ownership, info); } -GrRenderTarget* GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& wrapDesc, - GrWrapOwnership ownership) { +sk_sp GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& wrapDesc){ const GrVkImageInfo* info = reinterpret_cast(wrapDesc.fRenderTargetHandle); - if (VK_NULL_HANDLE == info->fImage || - (VK_NULL_HANDLE == info->fAlloc.fMemory && kAdopt_GrWrapOwnership == ownership)) { + if (VK_NULL_HANDLE == info->fImage) { return nullptr; } GrSurfaceDesc desc; desc.fConfig = wrapDesc.fConfig; - desc.fFlags = kCheckAllocation_GrSurfaceFlag; + desc.fFlags = kCheckAllocation_GrSurfaceFlag | kRenderTarget_GrSurfaceFlag; desc.fWidth = wrapDesc.fWidth; desc.fHeight = wrapDesc.fHeight; desc.fSampleCnt = SkTMin(wrapDesc.fSampleCnt, this->caps()->maxSampleCount()); desc.fOrigin = resolve_origin(wrapDesc.fOrigin); - GrVkRenderTarget* tgt = GrVkRenderTarget::CreateWrappedRenderTarget(this, desc, - ownership, - info); + sk_sp tgt = GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, info); if (tgt && wrapDesc.fStencilBits) { - if (!createStencilAttachmentForRenderTarget(tgt, desc.fWidth, desc.fHeight)) { - tgt->unref(); + if (!createStencilAttachmentForRenderTarget(tgt.get(), desc.fWidth, desc.fHeight)) { return nullptr; } } @@ -854,7 +860,7 @@ void GrVkGpu::generateMipmap(GrVkTexture* tex) { // We may need to resolve the texture first if it is also a render target GrVkRenderTarget* texRT = static_cast(tex->asRenderTarget()); if (texRT) { - this->onResolveRenderTarget(texRT); + this->internalResolveRenderTarget(texRT, false); } int width = tex->width(); @@ -988,13 +994,22 @@ bool copy_testing_data(GrVkGpu* gpu, void* srcData, const GrVkAlloc& alloc, return false; } - // If there is no padding on dst we can do a single memcopy. - // This assumes the srcData comes in with no padding. - if (srcRowBytes == dstRowBytes) { - memcpy(mapPtr, srcData, srcRowBytes * h); + if (srcData) { + // If there is no padding on dst we can do a single memcopy. + // This assumes the srcData comes in with no padding. + SkRectMemcpy(mapPtr, static_cast(dstRowBytes), + srcData, srcRowBytes, srcRowBytes, h); } else { - SkRectMemcpy(mapPtr, static_cast(dstRowBytes), srcData, srcRowBytes, - srcRowBytes, h); + // If there is no srcdata we always copy 0's into the textures so that it is initialized + // with some data. + if (srcRowBytes == static_cast(dstRowBytes)) { + memset(mapPtr, 0, srcRowBytes * h); + } else { + for (int i = 0; i < h; ++i) { + memset(mapPtr, 0, srcRowBytes); + mapPtr = SkTAddOffset(mapPtr, static_cast(dstRowBytes)); + } + } } GrVkMemory::FlushMappedAlloc(gpu, alloc); GR_VK_CALL(gpu->vkInterface(), UnmapMemory(gpu->device(), alloc.fMemory)); @@ -1070,172 +1085,170 @@ GrBackendObject GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, i return 0; } - if (srcData) { - size_t bpp = GrBytesPerPixel(config); - size_t rowCopyBytes = bpp * w; - if (linearTiling) { - const VkImageSubresource subres = { - VK_IMAGE_ASPECT_COLOR_BIT, - 0, // mipLevel - 0, // arraySlice - }; - VkSubresourceLayout layout; + size_t bpp = GrBytesPerPixel(config); + size_t rowCopyBytes = bpp * w; + if (linearTiling) { + const VkImageSubresource subres = { + VK_IMAGE_ASPECT_COLOR_BIT, + 0, // mipLevel + 0, // arraySlice + }; + VkSubresourceLayout layout; - VK_CALL(GetImageSubresourceLayout(fDevice, image, &subres, &layout)); + VK_CALL(GetImageSubresourceLayout(fDevice, image, &subres, &layout)); - if (!copy_testing_data(this, srcData, alloc, rowCopyBytes, - static_cast(layout.rowPitch), h)) { - GrVkMemory::FreeImageMemory(this, linearTiling, alloc); - VK_CALL(DestroyImage(fDevice, image, nullptr)); - return 0; - } - } else { - SkASSERT(w && h); + if (!copy_testing_data(this, srcData, alloc, rowCopyBytes, + static_cast(layout.rowPitch), h)) { + GrVkMemory::FreeImageMemory(this, linearTiling, alloc); + VK_CALL(DestroyImage(fDevice, image, nullptr)); + return 0; + } + } else { + SkASSERT(w && h); - VkBuffer buffer; - VkBufferCreateInfo bufInfo; - memset(&bufInfo, 0, sizeof(VkBufferCreateInfo)); - bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufInfo.flags = 0; - bufInfo.size = rowCopyBytes * h; - bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - bufInfo.queueFamilyIndexCount = 0; - bufInfo.pQueueFamilyIndices = nullptr; - VkResult err; - err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer)); + VkBuffer buffer; + VkBufferCreateInfo bufInfo; + memset(&bufInfo, 0, sizeof(VkBufferCreateInfo)); + bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufInfo.flags = 0; + bufInfo.size = rowCopyBytes * h; + bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bufInfo.queueFamilyIndexCount = 0; + bufInfo.pQueueFamilyIndices = nullptr; + VkResult err; + err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer)); - if (err) { - GrVkMemory::FreeImageMemory(this, linearTiling, alloc); - VK_CALL(DestroyImage(fDevice, image, nullptr)); - return 0; - } + if (err) { + GrVkMemory::FreeImageMemory(this, linearTiling, alloc); + VK_CALL(DestroyImage(fDevice, image, nullptr)); + return 0; + } - GrVkAlloc bufferAlloc = { VK_NULL_HANDLE, 0, 0, 0 }; - if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type, - true, &bufferAlloc)) { - GrVkMemory::FreeImageMemory(this, linearTiling, alloc); - VK_CALL(DestroyImage(fDevice, image, nullptr)); - VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); - return 0; - } + GrVkAlloc bufferAlloc = { VK_NULL_HANDLE, 0, 0, 0 }; + if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type, + true, &bufferAlloc)) { + GrVkMemory::FreeImageMemory(this, linearTiling, alloc); + VK_CALL(DestroyImage(fDevice, image, nullptr)); + VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); + return 0; + } - if (!copy_testing_data(this, srcData, bufferAlloc, rowCopyBytes, rowCopyBytes, h)) { - GrVkMemory::FreeImageMemory(this, linearTiling, alloc); - VK_CALL(DestroyImage(fDevice, image, nullptr)); - GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); - VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); - return 0; - } + if (!copy_testing_data(this, srcData, bufferAlloc, rowCopyBytes, rowCopyBytes, h)) { + GrVkMemory::FreeImageMemory(this, linearTiling, alloc); + VK_CALL(DestroyImage(fDevice, image, nullptr)); + GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); + VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); + return 0; + } - const VkCommandBufferAllocateInfo cmdInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType - NULL, // pNext - fCmdPool, // commandPool - VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level - 1 // bufferCount - }; + const VkCommandBufferAllocateInfo cmdInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType + NULL, // pNext + fCmdPool, // commandPool + VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level + 1 // bufferCount + }; - VkCommandBuffer cmdBuffer; - err = VK_CALL(AllocateCommandBuffers(fDevice, &cmdInfo, &cmdBuffer)); - if (err) { - GrVkMemory::FreeImageMemory(this, linearTiling, alloc); - VK_CALL(DestroyImage(fDevice, image, nullptr)); - GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); - VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); - return 0; - } + VkCommandBuffer cmdBuffer; + err = VK_CALL(AllocateCommandBuffers(fDevice, &cmdInfo, &cmdBuffer)); + if (err) { + GrVkMemory::FreeImageMemory(this, linearTiling, alloc); + VK_CALL(DestroyImage(fDevice, image, nullptr)); + GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); + VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); + return 0; + } - VkCommandBufferBeginInfo cmdBufferBeginInfo; - memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo)); - cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdBufferBeginInfo.pNext = nullptr; - cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - cmdBufferBeginInfo.pInheritanceInfo = nullptr; + VkCommandBufferBeginInfo cmdBufferBeginInfo; + memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo)); + cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdBufferBeginInfo.pNext = nullptr; + cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdBufferBeginInfo.pInheritanceInfo = nullptr; - err = VK_CALL(BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo)); - SkASSERT(!err); + err = VK_CALL(BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo)); + SkASSERT(!err); - // Set image layout and add barrier - VkImageMemoryBarrier barrier; - memset(&barrier, 0, sizeof(VkImageMemoryBarrier)); - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.pNext = nullptr; - barrier.srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(initialLayout); - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0 , 1}; + // Set image layout and add barrier + VkImageMemoryBarrier barrier; + memset(&barrier, 0, sizeof(VkImageMemoryBarrier)); + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.pNext = nullptr; + barrier.srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(initialLayout); + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0 , 1}; - VK_CALL(CmdPipelineBarrier(cmdBuffer, - GrVkMemory::LayoutToPipelineStageFlags(initialLayout), - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, nullptr, - 0, nullptr, - 1, &barrier)); - initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + VK_CALL(CmdPipelineBarrier(cmdBuffer, + GrVkMemory::LayoutToPipelineStageFlags(initialLayout), + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, nullptr, + 0, nullptr, + 1, &barrier)); + initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - // Submit copy command - VkBufferImageCopy region; - memset(®ion, 0, sizeof(VkBufferImageCopy)); - region.bufferOffset = 0; - region.bufferRowLength = w; - region.bufferImageHeight = h; - region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; - region.imageOffset = { 0, 0, 0 }; - region.imageExtent = { (uint32_t)w, (uint32_t)h, 1 }; + // Submit copy command + VkBufferImageCopy region; + memset(®ion, 0, sizeof(VkBufferImageCopy)); + region.bufferOffset = 0; + region.bufferRowLength = w; + region.bufferImageHeight = h; + region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + region.imageOffset = { 0, 0, 0 }; + region.imageExtent = { (uint32_t)w, (uint32_t)h, 1 }; - VK_CALL(CmdCopyBufferToImage(cmdBuffer, buffer, image, initialLayout, 1, ®ion)); + VK_CALL(CmdCopyBufferToImage(cmdBuffer, buffer, image, initialLayout, 1, ®ion)); - // End CommandBuffer - err = VK_CALL(EndCommandBuffer(cmdBuffer)); - SkASSERT(!err); + // End CommandBuffer + err = VK_CALL(EndCommandBuffer(cmdBuffer)); + SkASSERT(!err); - // Create Fence for queue - VkFence fence; - VkFenceCreateInfo fenceInfo; - memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo)); - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + // Create Fence for queue + VkFence fence; + VkFenceCreateInfo fenceInfo; + memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo)); + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - err = VK_CALL(CreateFence(fDevice, &fenceInfo, nullptr, &fence)); - SkASSERT(!err); + err = VK_CALL(CreateFence(fDevice, &fenceInfo, nullptr, &fence)); + SkASSERT(!err); - VkSubmitInfo submitInfo; - memset(&submitInfo, 0, sizeof(VkSubmitInfo)); - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.pNext = nullptr; - submitInfo.waitSemaphoreCount = 0; - submitInfo.pWaitSemaphores = nullptr; - submitInfo.pWaitDstStageMask = 0; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &cmdBuffer; - submitInfo.signalSemaphoreCount = 0; - submitInfo.pSignalSemaphores = nullptr; - err = VK_CALL(QueueSubmit(this->queue(), 1, &submitInfo, fence)); - SkASSERT(!err); + VkSubmitInfo submitInfo; + memset(&submitInfo, 0, sizeof(VkSubmitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitSemaphores = nullptr; + submitInfo.pWaitDstStageMask = 0; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &cmdBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + err = VK_CALL(QueueSubmit(this->queue(), 1, &submitInfo, fence)); + SkASSERT(!err); - err = VK_CALL(WaitForFences(fDevice, 1, &fence, true, UINT64_MAX)); - if (VK_TIMEOUT == err) { - GrVkMemory::FreeImageMemory(this, linearTiling, alloc); - VK_CALL(DestroyImage(fDevice, image, nullptr)); - GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); - VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); - VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer)); - VK_CALL(DestroyFence(fDevice, fence, nullptr)); - SkDebugf("Fence failed to signal: %d\n", err); - SkFAIL("failing"); - } - SkASSERT(!err); - - // Clean up transfer resources + err = VK_CALL(WaitForFences(fDevice, 1, &fence, true, UINT64_MAX)); + if (VK_TIMEOUT == err) { + GrVkMemory::FreeImageMemory(this, linearTiling, alloc); + VK_CALL(DestroyImage(fDevice, image, nullptr)); GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer)); VK_CALL(DestroyFence(fDevice, fence, nullptr)); + SkDebugf("Fence failed to signal: %d\n", err); + SkFAIL("failing"); } + SkASSERT(!err); + + // Clean up transfer resources + GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); + VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); + VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer)); + VK_CALL(DestroyFence(fDevice, fence, nullptr)); } GrVkImageInfo* info = new GrVkImageInfo; @@ -1319,7 +1332,7 @@ void GrVkGpu::addImageMemoryBarrier(VkPipelineStageFlags srcStageMask, barrier); } -void GrVkGpu::finishDrawTarget() { +void GrVkGpu::finishOpList() { // Submit the current command buffer to the Queue this->submitCommandBuffer(kSkip_SyncQueue); } @@ -1374,7 +1387,7 @@ inline bool can_copy_image(const GrSurface* dst, } } - // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src + // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src // as image usage flags. if (src->origin() == dst->origin() && GrBytesPerPixel(src->config()) == GrBytesPerPixel(dst->config())) { @@ -1423,9 +1436,6 @@ void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, copyRegion.srcOffset = { srcVkRect.fLeft, srcVkRect.fTop, 0 }; copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; copyRegion.dstOffset = { dstPoint.fX, dstY, 0 }; - // The depth value of the extent is ignored according the vulkan spec for 2D images. However, on - // at least the nexus 5X it seems to be checking it. Thus as a working around we must have the - // depth value be 1. copyRegion.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 1 }; fCurrentCmdBuffer->copyImage(this, @@ -1517,10 +1527,10 @@ void GrVkGpu::copySurfaceAsBlit(GrSurface* dst, memset(&blitRegion, 0, sizeof(VkImageBlit)); blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; blitRegion.srcOffsets[0] = { srcVkRect.fLeft, srcVkRect.fTop, 0 }; - blitRegion.srcOffsets[1] = { srcVkRect.fRight, srcVkRect.fBottom, 0 }; + blitRegion.srcOffsets[1] = { srcVkRect.fRight, srcVkRect.fBottom, 1 }; blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; blitRegion.dstOffsets[0] = { dstRect.fLeft, dstRect.fTop, 0 }; - blitRegion.dstOffsets[1] = { dstRect.fRight, dstRect.fBottom, 0 }; + blitRegion.dstOffsets[1] = { dstRect.fRight, dstRect.fBottom, 1 }; fCurrentCmdBuffer->blitImage(this, *srcImage, @@ -1563,19 +1573,6 @@ void GrVkGpu::copySurfaceAsResolve(GrSurface* dst, this->resolveImage(dstRT, srcRT, srcRect, dstPoint); } -inline bool can_copy_as_draw(const GrSurface* dst, - const GrSurface* src, - const GrVkGpu* gpu) { - return false; -} - -void GrVkGpu::copySurfaceAsDraw(GrSurface* dst, - GrSurface* src, - const SkIRect& srcRect, - const SkIPoint& dstPoint) { - SkASSERT(false); -} - bool GrVkGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, @@ -1625,25 +1622,8 @@ bool GrVkGpu::onCopySurface(GrSurface* dst, return false; } -bool GrVkGpu::initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const { - // We can always succeed here with either a CopyImage (none msaa src) or ResolveImage (msaa). - // For CopyImage we can make a simple texture, for ResolveImage we require the dst to be a - // render target as well. - desc->fOrigin = src->origin(); - desc->fConfig = src->config(); - if (src->numColorSamples() > 1 || - (src->asTexture() && this->vkCaps().supportsCopiesAsDraws())) { - desc->fFlags = kRenderTarget_GrSurfaceFlag; - } else { - // Just going to use CopyImage here - desc->fFlags = kNone_GrSurfaceFlags; - } - - return true; -} - -void GrVkGpu::onGetMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&, - int* effectiveSampleCnt, SamplePattern*) { +void GrVkGpu::onQueryMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) { // TODO: stub. SkASSERT(!this->caps()->sampleLocationsSupport()); *effectiveSampleCnt = rt->desc().fSampleCnt; @@ -1704,7 +1684,7 @@ bool GrVkGpu::onReadPixels(GrSurface* surface, case GrVkRenderTarget::kAutoResolves_ResolveType: break; case GrVkRenderTarget::kCanResolve_ResolveType: - this->onResolveRenderTarget(rt); + this->internalResolveRenderTarget(rt, false); break; default: SkFAIL("Unknown resolve type"); @@ -1796,12 +1776,7 @@ bool GrVkGpu::onReadPixels(GrSurface* surface, dstRow -= rowBytes; } } else { - if (transBufferRowBytes == rowBytes) { - memcpy(buffer, mappedMemory, rowBytes*height); - } else { - SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, tightRowBytes, - height); - } + SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, tightRowBytes, height); } transferBuffer->unmap(); @@ -1853,7 +1828,7 @@ void adjust_bounds_to_granularity(SkIRect* dstBounds, const SkIRect& srcBounds, } } -void GrVkGpu::submitSecondaryCommandBuffer(GrVkSecondaryCommandBuffer* buffer, +void GrVkGpu::submitSecondaryCommandBuffer(const SkTArray& buffers, const GrVkRenderPass* renderPass, const VkClearValue* colorClear, GrVkRenderTarget* target, @@ -1878,41 +1853,59 @@ void GrVkGpu::submitSecondaryCommandBuffer(GrVkSecondaryCommandBuffer* buffer, pBounds = &adjustedBounds; } - // Currently it is fine for us to always pass in 1 for the clear count even if no attachment - // uses it. In the current state, we also only use the LOAD_OP_CLEAR for the color attachment - // which is always at the first attachment. - fCurrentCmdBuffer->beginRenderPass(this, renderPass, 1, colorClear, *target, *pBounds, true); - fCurrentCmdBuffer->executeCommands(this, buffer); + fCurrentCmdBuffer->beginRenderPass(this, renderPass, colorClear, *target, *pBounds, true); + for (int i = 0; i < buffers.count(); ++i) { + fCurrentCmdBuffer->executeCommands(this, buffers[i]); + } fCurrentCmdBuffer->endRenderPass(this); this->didWriteToSurface(target, &bounds); } -GrFence SK_WARN_UNUSED_RESULT GrVkGpu::insertFence() const { +GrFence SK_WARN_UNUSED_RESULT GrVkGpu::insertFence() { VkFenceCreateInfo createInfo; memset(&createInfo, 0, sizeof(VkFenceCreateInfo)); createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; createInfo.pNext = nullptr; createInfo.flags = 0; VkFence fence = VK_NULL_HANDLE; - VkResult result = GR_VK_CALL(this->vkInterface(), CreateFence(this->device(), &createInfo, - nullptr, &fence)); - // TODO: verify that all QueueSubmits before this will finish before this fence signals - if (VK_SUCCESS == result) { - GR_VK_CALL(this->vkInterface(), QueueSubmit(this->queue(), 0, nullptr, fence)); - } + + VK_CALL_ERRCHECK(CreateFence(this->device(), &createInfo, nullptr, &fence)); + VK_CALL(QueueSubmit(this->queue(), 0, nullptr, fence)); + + GR_STATIC_ASSERT(sizeof(GrFence) >= sizeof(VkFence)); return (GrFence)fence; } -bool GrVkGpu::waitFence(GrFence fence, uint64_t timeout) const { - VkResult result = GR_VK_CALL(this->vkInterface(), WaitForFences(this->device(), 1, - (VkFence*)&fence, - VK_TRUE, - timeout)); +bool GrVkGpu::waitFence(GrFence fence, uint64_t timeout) { + SkASSERT(VK_NULL_HANDLE != (VkFence)fence); + + VkResult result = VK_CALL(WaitForFences(this->device(), 1, (VkFence*)&fence, VK_TRUE, timeout)); return (VK_SUCCESS == result); } void GrVkGpu::deleteFence(GrFence fence) const { - GR_VK_CALL(this->vkInterface(), DestroyFence(this->device(), (VkFence)fence, nullptr)); + VK_CALL(DestroyFence(this->device(), (VkFence)fence, nullptr)); } +sk_sp SK_WARN_UNUSED_RESULT GrVkGpu::makeSemaphore() { + return GrVkSemaphore::Make(this); +} + +void GrVkGpu::insertSemaphore(sk_sp semaphore) { + GrVkSemaphore* vkSem = static_cast(semaphore.get()); + + this->submitCommandBuffer(kSkip_SyncQueue, vkSem->getResource()); +} + +void GrVkGpu::waitSemaphore(sk_sp semaphore) { + GrVkSemaphore* vkSem = static_cast(semaphore.get()); + + const GrVkSemaphore::Resource* resource = vkSem->getResource(); + resource->ref(); + fSemaphoresToWaitOn.push_back(resource); +} + +void GrVkGpu::flush() { + // We submit the command buffer to the queue whenever Ganesh is flushed, so nothing is needed +} diff --git a/gfx/skia/skia/src/gpu/vk/GrVkGpu.h b/gfx/skia/skia/src/gpu/vk/GrVkGpu.h index 273f28c5dbfb..db77443e431c 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkGpu.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkGpu.h @@ -8,8 +8,6 @@ #ifndef GrVkGpu_DEFINED #define GrVkGpu_DEFINED -#define USE_SKSL 1 - #include "GrGpu.h" #include "GrGpuFactory.h" #include "vk/GrVkBackendContext.h" @@ -18,17 +16,9 @@ #include "GrVkIndexBuffer.h" #include "GrVkMemory.h" #include "GrVkResourceProvider.h" +#include "GrVkSemaphore.h" #include "GrVkVertexBuffer.h" #include "GrVkUtil.h" - -#if USE_SKSL -namespace SkSL { - class Compiler; -} -#else -#include "shaderc/shaderc.h" -#endif - #include "vk/GrVkDefines.h" class GrPipeline; @@ -43,6 +33,10 @@ class GrVkSecondaryCommandBuffer; class GrVkTexture; struct GrVkInterface; +namespace SkSL { + class Compiler; +} + class GrVkGpu : public GrGpu { public: static GrGpu* Create(GrBackendContext backendContext, const GrContextOptions& options, @@ -50,7 +44,7 @@ public: ~GrVkGpu() override; - const GrVkInterface* vkInterface() const { return fBackendContext->fInterface; } + const GrVkInterface* vkInterface() const { return fBackendContext->fInterface.get(); } const GrVkCaps& vkCaps() const { return *fVkCaps; } VkDevice device() const { return fDevice; } @@ -82,10 +76,8 @@ public: const SkIRect& srcRect, const SkIPoint& dstPoint) override; - void onGetMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&, - int* effectiveSampleCnt, SamplePattern*) override; - - bool initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const override; + void onQueryMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) override; void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {} @@ -102,7 +94,6 @@ public: void clearStencil(GrRenderTarget* target) override; GrGpuCommandBuffer* createCommandBuffer( - GrRenderTarget* target, const GrGpuCommandBuffer::LoadAndStoreInfo& colorInfo, const GrGpuCommandBuffer::LoadAndStoreInfo& stencilInfo) override; @@ -121,30 +112,32 @@ public: bool byRegion, VkImageMemoryBarrier* barrier) const; -#if USE_SKSL SkSL::Compiler* shaderCompiler() const { return fCompiler; } -#else - shaderc_compiler_t shadercCompiler() const { - return fCompiler; + + void onResolveRenderTarget(GrRenderTarget* target) override { + this->internalResolveRenderTarget(target, true); } -#endif - void onResolveRenderTarget(GrRenderTarget* target) override; - - void submitSecondaryCommandBuffer(GrVkSecondaryCommandBuffer*, + void submitSecondaryCommandBuffer(const SkTArray&, const GrVkRenderPass*, const VkClearValue*, GrVkRenderTarget*, const SkIRect& bounds); - void finishDrawTarget() override; + void finishOpList() override; - GrFence SK_WARN_UNUSED_RESULT insertFence() const override; - bool waitFence(GrFence, uint64_t timeout) const override; + GrFence SK_WARN_UNUSED_RESULT insertFence() override; + bool waitFence(GrFence, uint64_t timeout) override; void deleteFence(GrFence) const override; + sk_sp SK_WARN_UNUSED_RESULT makeSemaphore() override; + void insertSemaphore(sk_sp semaphore) override; + void waitSemaphore(sk_sp semaphore) override; + + void flush() override; + void generateMipmap(GrVkTexture* tex); bool updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size); @@ -168,7 +161,7 @@ public: }; static const int kHeapCount = kLastHeap + 1; - GrVkHeap* getHeap(Heap heap) const { return fHeaps[heap]; } + GrVkHeap* getHeap(Heap heap) const { return fHeaps[heap].get(); } private: GrVkGpu(GrContext* context, const GrContextOptions& options, @@ -182,11 +175,12 @@ private: GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, SkBudgeted, const SkTArray&) override { return NULL; } - GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) override; + sk_sp onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) override; - GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&, - GrWrapOwnership) override; - GrRenderTarget* onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&) override { return NULL; } + sk_sp onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) override; + sk_sp onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&) override { + return nullptr; + } GrBuffer* onCreateBuffer(size_t size, GrBufferType type, GrAccessPattern, const void* data) override; @@ -210,8 +204,14 @@ private: // Ends and submits the current command buffer to the queue and then creates a new command // buffer and begins it. If sync is set to kForce_SyncQueue, the function will wait for all - // work in the queue to finish before returning. - void submitCommandBuffer(SyncQueue sync); + // work in the queue to finish before returning. If the signalSemaphore is not VK_NULL_HANDLE, + // we will signal the semaphore at the end of this command buffer. If this GrVkGpu object has + // any semaphores in fSemaphoresToWaitOn, we will add those wait semaphores to this command + // buffer when submitting. + void submitCommandBuffer(SyncQueue sync, + const GrVkSemaphore::Resource* signalSemaphore = nullptr); + + void internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit); void copySurfaceAsCopyImage(GrSurface* dst, GrSurface* src, @@ -232,11 +232,6 @@ private: const SkIRect& srcRect, const SkIPoint& dstPoint); - void copySurfaceAsDraw(GrSurface* dst, - GrSurface* src, - const SkIRect& srcRect, - const SkIPoint& dstPoint); - // helpers for onCreateTexture and writeTexturePixels bool uploadTexDataLinear(GrVkTexture* tex, int left, int top, int width, int height, @@ -253,36 +248,36 @@ private: const SkIRect& srcRect, const SkIPoint& dstPoint); - SkAutoTUnref fBackendContext; - SkAutoTUnref fVkCaps; + sk_sp fBackendContext; + sk_sp fVkCaps; // These Vulkan objects are provided by the client, and also stored in fBackendContext. // They're copied here for convenient access. - VkDevice fDevice; - VkQueue fQueue; // Must be Graphics queue + VkDevice fDevice; + VkQueue fQueue; // Must be Graphics queue // Created by GrVkGpu - GrVkResourceProvider fResourceProvider; - VkCommandPool fCmdPool; - GrVkPrimaryCommandBuffer* fCurrentCmdBuffer; - VkPhysicalDeviceMemoryProperties fPhysDevMemProps; + GrVkResourceProvider fResourceProvider; + VkCommandPool fCmdPool; - SkAutoTDelete fHeaps[kHeapCount]; + GrVkPrimaryCommandBuffer* fCurrentCmdBuffer; - GrVkCopyManager fCopyManager; + SkSTArray<1, const GrVkSemaphore::Resource*> fSemaphoresToWaitOn; + + VkPhysicalDeviceMemoryProperties fPhysDevMemProps; + + std::unique_ptr fHeaps[kHeapCount]; + + GrVkCopyManager fCopyManager; #ifdef SK_ENABLE_VK_LAYERS // For reporting validation layer errors VkDebugReportCallbackEXT fCallback; #endif -#if USE_SKSL + // compiler used for compiling sksl into spirv. We only want to create the compiler once since + // there is significant overhead to the first compile of any compiler. SkSL::Compiler* fCompiler; -#else - // Shaderc compiler used for compiling glsl in spirv. We only want to create the compiler once - // since there is significant overhead to the first compile of any compiler. - shaderc_compiler_t fCompiler; -#endif typedef GrGpu INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/gfx/skia/skia/src/gpu/vk/GrVkGpuCommandBuffer.cpp index e0cfce3dc2cb..e6593eff9a89 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkGpuCommandBuffer.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkGpuCommandBuffer.cpp @@ -9,9 +9,9 @@ #include "GrFixedClip.h" #include "GrMesh.h" +#include "GrOpFlushState.h" #include "GrPipeline.h" #include "GrRenderTargetPriv.h" -#include "GrTextureAccess.h" #include "GrTexturePriv.h" #include "GrVkCommandBuffer.h" #include "GrVkGpu.h" @@ -20,6 +20,7 @@ #include "GrVkRenderTarget.h" #include "GrVkResourceProvider.h" #include "GrVkTexture.h" +#include "SkRect.h" void get_vk_load_store_ops(const GrGpuCommandBuffer::LoadAndStoreInfo& info, VkAttachmentLoadOp* loadOp, VkAttachmentStoreOp* storeOp) { @@ -52,63 +53,79 @@ void get_vk_load_store_ops(const GrGpuCommandBuffer::LoadAndStoreInfo& info, } GrVkGpuCommandBuffer::GrVkGpuCommandBuffer(GrVkGpu* gpu, - GrVkRenderTarget* target, const LoadAndStoreInfo& colorInfo, const LoadAndStoreInfo& stencilInfo) : fGpu(gpu) - , fRenderTarget(target) - , fIsEmpty(true) - , fStartsWithClear(false) { - VkAttachmentLoadOp vkLoadOp; - VkAttachmentStoreOp vkStoreOp; + , fRenderTarget(nullptr) + , fClearColor(GrColor4f::FromGrColor(colorInfo.fClearColor)) + , fLastPipelineState(nullptr) { - get_vk_load_store_ops(colorInfo, &vkLoadOp, &vkStoreOp); - GrVkRenderPass::LoadStoreOps vkColorOps(vkLoadOp, vkStoreOp); + get_vk_load_store_ops(colorInfo, &fVkColorLoadOp, &fVkColorStoreOp); - get_vk_load_store_ops(stencilInfo, &vkLoadOp, &vkStoreOp); - GrVkRenderPass::LoadStoreOps vkStencilOps(vkLoadOp, vkStoreOp); + get_vk_load_store_ops(stencilInfo, &fVkStencilLoadOp, &fVkStencilStoreOp); + + fCurrentCmdInfo = -1; +} + +void GrVkGpuCommandBuffer::init(GrVkRenderTarget* target) { + SkASSERT(!fRenderTarget); + fRenderTarget = target; + + GrVkRenderPass::LoadStoreOps vkColorOps(fVkColorLoadOp, fVkColorStoreOp); + GrVkRenderPass::LoadStoreOps vkStencilOps(fVkStencilLoadOp, fVkStencilStoreOp); + + CommandBufferInfo& cbInfo = fCommandBufferInfos.push_back(); + SkASSERT(fCommandBufferInfos.count() == 1); + fCurrentCmdInfo = 0; const GrVkResourceProvider::CompatibleRPHandle& rpHandle = target->compatibleRenderPassHandle(); if (rpHandle.isValid()) { - fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle, - vkColorOps, - vkStencilOps); + cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle, + vkColorOps, + vkStencilOps); } else { - fRenderPass = fGpu->resourceProvider().findRenderPass(*target, - vkColorOps, - vkStencilOps); + cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*target, + vkColorOps, + vkStencilOps); } - GrColorToRGBAFloat(colorInfo.fClearColor, fColorClearValue.color.float32); + cbInfo.fColorClearValue.color.float32[0] = fClearColor.fRGBA[0]; + cbInfo.fColorClearValue.color.float32[1] = fClearColor.fRGBA[1]; + cbInfo.fColorClearValue.color.float32[2] = fClearColor.fRGBA[2]; + cbInfo.fColorClearValue.color.float32[3] = fClearColor.fRGBA[3]; - fCommandBuffer = gpu->resourceProvider().findOrCreateSecondaryCommandBuffer(); - fCommandBuffer->begin(gpu, target->framebuffer(), fRenderPass); + cbInfo.fBounds.setEmpty(); + cbInfo.fIsEmpty = true; + cbInfo.fStartsWithClear = false; + + cbInfo.fCommandBuffers.push_back(fGpu->resourceProvider().findOrCreateSecondaryCommandBuffer()); + cbInfo.currentCmdBuf()->begin(fGpu, target->framebuffer(), cbInfo.fRenderPass); } + GrVkGpuCommandBuffer::~GrVkGpuCommandBuffer() { - fCommandBuffer->unref(fGpu); - fRenderPass->unref(fGpu); + for (int i = 0; i < fCommandBufferInfos.count(); ++i) { + CommandBufferInfo& cbInfo = fCommandBufferInfos[i]; + for (int j = 0; j < cbInfo.fCommandBuffers.count(); ++j) { + cbInfo.fCommandBuffers[j]->unref(fGpu); + } + cbInfo.fRenderPass->unref(fGpu); + } } GrGpu* GrVkGpuCommandBuffer::gpu() { return fGpu; } +GrRenderTarget* GrVkGpuCommandBuffer::renderTarget() { return fRenderTarget; } void GrVkGpuCommandBuffer::end() { - fCommandBuffer->end(fGpu); + if (fCurrentCmdInfo >= 0) { + fCommandBufferInfos[fCurrentCmdInfo].currentCmdBuf()->end(fGpu); + } } -void GrVkGpuCommandBuffer::onSubmit(const SkIRect& bounds) { - // TODO: We can't add this optimization yet since many things create a scratch texture which - // adds the discard immediately, but then don't draw to it right away. This causes the discard - // to be ignored and we get yelled at for loading uninitialized data. However, once MDP lands, - // the discard will get reordered with the rest of the draw commands and we can re-enable this. -#if 0 - if (fIsEmpty && !fStartsWithClear) { - // We have sumbitted no actual draw commands to the command buffer and we are not using - // the render pass to do a clear so there is no need to submit anything. +void GrVkGpuCommandBuffer::onSubmit() { + if (!fRenderTarget) { return; } -#endif - // Change layout of our render target so it can be used as the color attachment. Currently // we don't attach the resolve to the framebuffer so no need to change its layout. GrVkImage* targetImage = fRenderTarget->msaaImage() ? fRenderTarget->msaaImage() @@ -132,47 +149,87 @@ void GrVkGpuCommandBuffer::onSubmit(const SkIRect& bounds) { false); } - fGpu->submitSecondaryCommandBuffer(fCommandBuffer, fRenderPass, &fColorClearValue, - fRenderTarget, bounds); + for (int i = 0; i < fCommandBufferInfos.count(); ++i) { + CommandBufferInfo& cbInfo = fCommandBufferInfos[i]; + + for (int j = 0; j < cbInfo.fPreDrawUploads.count(); ++j) { + InlineUploadInfo& iuInfo = cbInfo.fPreDrawUploads[j]; + iuInfo.fFlushState->doUpload(iuInfo.fUpload); + } + + // TODO: We can't add this optimization yet since many things create a scratch texture which + // adds the discard immediately, but then don't draw to it right away. This causes the + // discard to be ignored and we get yelled at for loading uninitialized data. However, once + // MDP lands, the discard will get reordered with the rest of the draw commands and we can + // re-enable this. +#if 0 + if (cbInfo.fIsEmpty && !cbInfo.fStartsWithClear) { + // We have sumbitted no actual draw commands to the command buffer and we are not using + // the render pass to do a clear so there is no need to submit anything. + continue; + } +#endif + if (cbInfo.fBounds.intersect(0, 0, + SkIntToScalar(fRenderTarget->width()), + SkIntToScalar(fRenderTarget->height()))) { + SkIRect iBounds; + cbInfo.fBounds.roundOut(&iBounds); + + fGpu->submitSecondaryCommandBuffer(cbInfo.fCommandBuffers, cbInfo.fRenderPass, + &cbInfo.fColorClearValue, fRenderTarget, iBounds); + } + } } -void GrVkGpuCommandBuffer::discard(GrRenderTarget* target) { - if (fIsEmpty) { +void GrVkGpuCommandBuffer::discard(GrRenderTarget* rt) { + GrVkRenderTarget* target = static_cast(rt); + if (!fRenderTarget) { + this->init(target); + } + SkASSERT(target == fRenderTarget); + + CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo]; + if (cbInfo.fIsEmpty) { // We will change the render pass to do a clear load instead GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); - const GrVkRenderPass* oldRP = fRenderPass; + const GrVkRenderPass* oldRP = cbInfo.fRenderPass; - GrVkRenderTarget* vkRT = static_cast(target); const GrVkResourceProvider::CompatibleRPHandle& rpHandle = - vkRT->compatibleRenderPassHandle(); + fRenderTarget->compatibleRenderPassHandle(); if (rpHandle.isValid()) { - fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle, - vkColorOps, - vkStencilOps); + cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle, + vkColorOps, + vkStencilOps); } else { - fRenderPass = fGpu->resourceProvider().findRenderPass(*vkRT, - vkColorOps, - vkStencilOps); + cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*fRenderTarget, + vkColorOps, + vkStencilOps); } - SkASSERT(fRenderPass->isCompatible(*oldRP)); + SkASSERT(cbInfo.fRenderPass->isCompatible(*oldRP)); oldRP->unref(fGpu); - fStartsWithClear = false; + cbInfo.fBounds.join(fRenderTarget->getBoundsRect()); + cbInfo.fStartsWithClear = false; } } -void GrVkGpuCommandBuffer::onClearStencilClip(GrRenderTarget* target, - const GrFixedClip& clip, +void GrVkGpuCommandBuffer::onClearStencilClip(GrRenderTarget* rt, const GrFixedClip& clip, bool insideStencilMask) { - SkASSERT(target); SkASSERT(!clip.hasWindowRectangles()); - GrVkRenderTarget* vkRT = static_cast(target); - GrStencilAttachment* sb = target->renderTargetPriv().getStencilAttachment(); + GrVkRenderTarget* target = static_cast(rt); + if (!fRenderTarget) { + this->init(target); + } + SkASSERT(target == fRenderTarget); + + CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo]; + + GrStencilAttachment* sb = fRenderTarget->renderTargetPriv().getStencilAttachment(); // this should only be called internally when we know we have a // stencil buffer. SkASSERT(sb); @@ -193,13 +250,13 @@ void GrVkGpuCommandBuffer::onClearStencilClip(GrRenderTarget* target, // Flip rect if necessary SkIRect vkRect; if (!clip.scissorEnabled()) { - vkRect.setXYWH(0, 0, vkRT->width(), vkRT->height()); - } else if (kBottomLeft_GrSurfaceOrigin != vkRT->origin()) { + vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height()); + } else if (kBottomLeft_GrSurfaceOrigin != fRenderTarget->origin()) { vkRect = clip.scissorRect(); } else { const SkIRect& scissor = clip.scissorRect(); - vkRect.setLTRB(scissor.fLeft, vkRT->height() - scissor.fBottom, - scissor.fRight, vkRT->height() - scissor.fTop); + vkRect.setLTRB(scissor.fLeft, fRenderTarget->height() - scissor.fBottom, + scissor.fRight, fRenderTarget->height() - scissor.fTop); } clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop }; @@ -209,53 +266,68 @@ void GrVkGpuCommandBuffer::onClearStencilClip(GrRenderTarget* target, clearRect.layerCount = 1; uint32_t stencilIndex; - SkAssertResult(fRenderPass->stencilAttachmentIndex(&stencilIndex)); + SkAssertResult(cbInfo.fRenderPass->stencilAttachmentIndex(&stencilIndex)); VkClearAttachment attachment; attachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; attachment.colorAttachment = 0; // this value shouldn't matter attachment.clearValue.depthStencil = vkStencilColor; - fCommandBuffer->clearAttachments(fGpu, 1, &attachment, 1, &clearRect); - fIsEmpty = false; + cbInfo.currentCmdBuf()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect); + cbInfo.fIsEmpty = false; + + // Update command buffer bounds + if (!clip.scissorEnabled()) { + cbInfo.fBounds.join(fRenderTarget->getBoundsRect()); + } else { + cbInfo.fBounds.join(SkRect::Make(clip.scissorRect())); + } } -void GrVkGpuCommandBuffer::onClear(GrRenderTarget* target, const GrFixedClip& clip, GrColor color) { +void GrVkGpuCommandBuffer::onClear(GrRenderTarget* rt, const GrFixedClip& clip, GrColor color) { // parent class should never let us get here with no RT - SkASSERT(target); SkASSERT(!clip.hasWindowRectangles()); + GrVkRenderTarget* target = static_cast(rt); + if (!fRenderTarget) { + this->init(target); + } + SkASSERT(target == fRenderTarget); + + CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo]; + VkClearColorValue vkColor; GrColorToRGBAFloat(color, vkColor.float32); - GrVkRenderTarget* vkRT = static_cast(target); - - if (fIsEmpty && !clip.scissorEnabled()) { + if (cbInfo.fIsEmpty && !clip.scissorEnabled()) { // We will change the render pass to do a clear load instead GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE); - const GrVkRenderPass* oldRP = fRenderPass; + const GrVkRenderPass* oldRP = cbInfo.fRenderPass; const GrVkResourceProvider::CompatibleRPHandle& rpHandle = - vkRT->compatibleRenderPassHandle(); + fRenderTarget->compatibleRenderPassHandle(); if (rpHandle.isValid()) { - fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle, - vkColorOps, - vkStencilOps); + cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle, + vkColorOps, + vkStencilOps); } else { - fRenderPass = fGpu->resourceProvider().findRenderPass(*vkRT, - vkColorOps, - vkStencilOps); + cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*fRenderTarget, + vkColorOps, + vkStencilOps); } - SkASSERT(fRenderPass->isCompatible(*oldRP)); + SkASSERT(cbInfo.fRenderPass->isCompatible(*oldRP)); oldRP->unref(fGpu); - GrColorToRGBAFloat(color, fColorClearValue.color.float32); - fStartsWithClear = true; + GrColorToRGBAFloat(color, cbInfo.fColorClearValue.color.float32); + cbInfo.fStartsWithClear = true; + + // Update command buffer bounds + cbInfo.fBounds.join(fRenderTarget->getBoundsRect()); return; } @@ -264,13 +336,13 @@ void GrVkGpuCommandBuffer::onClear(GrRenderTarget* target, const GrFixedClip& cl // Flip rect if necessary SkIRect vkRect; if (!clip.scissorEnabled()) { - vkRect.setXYWH(0, 0, vkRT->width(), vkRT->height()); - } else if (kBottomLeft_GrSurfaceOrigin != vkRT->origin()) { + vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height()); + } else if (kBottomLeft_GrSurfaceOrigin != fRenderTarget->origin()) { vkRect = clip.scissorRect(); } else { const SkIRect& scissor = clip.scissorRect(); - vkRect.setLTRB(scissor.fLeft, vkRT->height() - scissor.fBottom, - scissor.fRight, vkRT->height() - scissor.fTop); + vkRect.setLTRB(scissor.fLeft, fRenderTarget->height() - scissor.fBottom, + scissor.fRight, fRenderTarget->height() - scissor.fTop); } clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop }; clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() }; @@ -278,22 +350,83 @@ void GrVkGpuCommandBuffer::onClear(GrRenderTarget* target, const GrFixedClip& cl clearRect.layerCount = 1; uint32_t colorIndex; - SkAssertResult(fRenderPass->colorAttachmentIndex(&colorIndex)); + SkAssertResult(cbInfo.fRenderPass->colorAttachmentIndex(&colorIndex)); VkClearAttachment attachment; attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; attachment.colorAttachment = colorIndex; attachment.clearValue.color = vkColor; - fCommandBuffer->clearAttachments(fGpu, 1, &attachment, 1, &clearRect); - fIsEmpty = false; + cbInfo.currentCmdBuf()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect); + cbInfo.fIsEmpty = false; + + // Update command buffer bounds + if (!clip.scissorEnabled()) { + cbInfo.fBounds.join(fRenderTarget->getBoundsRect()); + } else { + cbInfo.fBounds.join(SkRect::Make(clip.scissorRect())); + } return; } +void GrVkGpuCommandBuffer::addAdditionalCommandBuffer() { + CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo]; + cbInfo.currentCmdBuf()->end(fGpu); + cbInfo.fCommandBuffers.push_back(fGpu->resourceProvider().findOrCreateSecondaryCommandBuffer()); + cbInfo.currentCmdBuf()->begin(fGpu, fRenderTarget->framebuffer(), cbInfo.fRenderPass); +} + +void GrVkGpuCommandBuffer::addAdditionalRenderPass() { + fCommandBufferInfos[fCurrentCmdInfo].currentCmdBuf()->end(fGpu); + + CommandBufferInfo& cbInfo = fCommandBufferInfos.push_back(); + fCurrentCmdInfo++; + + GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE); + GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE); + + const GrVkResourceProvider::CompatibleRPHandle& rpHandle = + fRenderTarget->compatibleRenderPassHandle(); + if (rpHandle.isValid()) { + cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle, + vkColorOps, + vkStencilOps); + } else { + cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*fRenderTarget, + vkColorOps, + vkStencilOps); + } + + cbInfo.fCommandBuffers.push_back(fGpu->resourceProvider().findOrCreateSecondaryCommandBuffer()); + // It shouldn't matter what we set the clear color to here since we will assume loading of the + // attachment. + memset(&cbInfo.fColorClearValue, 0, sizeof(VkClearValue)); + cbInfo.fBounds.setEmpty(); + cbInfo.fIsEmpty = true; + cbInfo.fStartsWithClear = false; + + cbInfo.currentCmdBuf()->begin(fGpu, fRenderTarget->framebuffer(), cbInfo.fRenderPass); +} + +void GrVkGpuCommandBuffer::inlineUpload(GrOpFlushState* state, GrDrawOp::DeferredUploadFn& upload, + GrRenderTarget* rt) { + GrVkRenderTarget* target = static_cast(rt); + if (!fRenderTarget) { + this->init(target); + } + if (!fCommandBufferInfos[fCurrentCmdInfo].fIsEmpty) { + this->addAdditionalRenderPass(); + } + fCommandBufferInfos[fCurrentCmdInfo].fPreDrawUploads.emplace_back(state, upload); +} + //////////////////////////////////////////////////////////////////////////////// void GrVkGpuCommandBuffer::bindGeometry(const GrPrimitiveProcessor& primProc, const GrNonInstancedMesh& mesh) { + CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo]; // There is no need to put any memory barriers to make sure host writes have finished here. // When a command buffer is submitted to a queue, there is an implicit memory barrier that // occurs for all host writes. Additionally, BufferMemoryBarriers are not allowed inside of @@ -304,7 +437,7 @@ void GrVkGpuCommandBuffer::bindGeometry(const GrPrimitiveProcessor& primProc, SkASSERT(vbuf); SkASSERT(!vbuf->isMapped()); - fCommandBuffer->bindVertexBuffer(fGpu, vbuf); + cbInfo.currentCmdBuf()->bindVertexBuffer(fGpu, vbuf); if (mesh.isIndexed()) { SkASSERT(!mesh.indexBuffer()->isCPUBacked()); @@ -312,37 +445,57 @@ void GrVkGpuCommandBuffer::bindGeometry(const GrPrimitiveProcessor& primProc, SkASSERT(ibuf); SkASSERT(!ibuf->isMapped()); - fCommandBuffer->bindIndexBuffer(fGpu, ibuf); + cbInfo.currentCmdBuf()->bindIndexBuffer(fGpu, ibuf); } } sk_sp GrVkGpuCommandBuffer::prepareDrawState( const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, - GrPrimitiveType primitiveType, - const GrVkRenderPass& renderPass) { + GrPrimitiveType primitiveType) { + CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo]; + SkASSERT(cbInfo.fRenderPass); + sk_sp pipelineState = fGpu->resourceProvider().findOrCreateCompatiblePipelineState(pipeline, primProc, primitiveType, - renderPass); + *cbInfo.fRenderPass); if (!pipelineState) { return pipelineState; } + if (!cbInfo.fIsEmpty && + fLastPipelineState && fLastPipelineState != pipelineState.get() && + fGpu->vkCaps().newSecondaryCBOnPipelineChange()) { + this->addAdditionalCommandBuffer(); + } + fLastPipelineState = pipelineState.get(); + pipelineState->setData(fGpu, primProc, pipeline); - pipelineState->bind(fGpu, fCommandBuffer); + pipelineState->bind(fGpu, cbInfo.currentCmdBuf()); - GrVkPipeline::SetDynamicState(fGpu, fCommandBuffer, pipeline); + GrVkPipeline::SetDynamicState(fGpu, cbInfo.currentCmdBuf(), pipeline); return pipelineState; } -static void prepare_sampled_images(const GrProcessor& processor, GrVkGpu* gpu) { - for (int i = 0; i < processor.numTextures(); ++i) { - const GrTextureAccess& texAccess = processor.textureAccess(i); - GrVkTexture* vkTexture = static_cast(processor.texture(i)); +static void set_texture_layout(GrVkTexture* vkTexture, GrVkGpu* gpu) { + // TODO: If we ever decide to create the secondary command buffers ahead of time before we + // are actually going to submit them, we will need to track the sampled images and delay + // adding the layout change/barrier until we are ready to submit. + vkTexture->setImageLayout(gpu, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, + false); +} + +static void prepare_sampled_images(const GrResourceIOProcessor& processor, GrVkGpu* gpu) { + for (int i = 0; i < processor.numTextureSamplers(); ++i) { + const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i); + GrVkTexture* vkTexture = static_cast(sampler.texture()); SkASSERT(vkTexture); // We may need to resolve the texture first if it is also a render target @@ -351,54 +504,51 @@ static void prepare_sampled_images(const GrProcessor& processor, GrVkGpu* gpu) { gpu->onResolveRenderTarget(texRT); } - const GrTextureParams& params = texAccess.getParams(); + const GrSamplerParams& params = sampler.params(); // Check if we need to regenerate any mip maps - if (GrTextureParams::kMipMap_FilterMode == params.filterMode()) { + if (GrSamplerParams::kMipMap_FilterMode == params.filterMode()) { if (vkTexture->texturePriv().mipMapsAreDirty()) { gpu->generateMipmap(vkTexture); vkTexture->texturePriv().dirtyMipMaps(false); } } - - // TODO: If we ever decide to create the secondary command buffers ahead of time before we - // are actually going to submit them, we will need to track the sampled images and delay - // adding the layout change/barrier until we are ready to submit. - vkTexture->setImageLayout(gpu, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_ACCESS_SHADER_READ_BIT, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, - false); + set_texture_layout(vkTexture, gpu); } } void GrVkGpuCommandBuffer::onDraw(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, const GrMesh* meshes, - int meshCount) { + int meshCount, + const SkRect& bounds) { + GrVkRenderTarget* target = static_cast(pipeline.getRenderTarget()); + if (!fRenderTarget) { + this->init(target); + } + SkASSERT(target == fRenderTarget); + if (!meshCount) { return; } - GrRenderTarget* rt = pipeline.getRenderTarget(); - GrVkRenderTarget* vkRT = static_cast(rt); - const GrVkRenderPass* renderPass = vkRT->simpleRenderPass(); - SkASSERT(renderPass); - prepare_sampled_images(primProc, fGpu); GrFragmentProcessor::Iter iter(pipeline); while (const GrFragmentProcessor* fp = iter.next()) { prepare_sampled_images(*fp, fGpu); } - prepare_sampled_images(pipeline.getXferProcessor(), fGpu); + if (GrVkTexture* dstTexture = static_cast(pipeline.dstTexture())) { + set_texture_layout(dstTexture, fGpu); + } GrPrimitiveType primitiveType = meshes[0].primitiveType(); sk_sp pipelineState = this->prepareDrawState(pipeline, primProc, - primitiveType, - *renderPass); + primitiveType); if (!pipelineState) { return; } + CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo]; + for (int i = 0; i < meshCount; ++i) { const GrMesh& mesh = meshes[i]; GrMesh::Iterator iter; @@ -413,8 +563,7 @@ void GrVkGpuCommandBuffer::onDraw(const GrPipeline& pipeline, primitiveType = nonIdxMesh->primitiveType(); pipelineState = this->prepareDrawState(pipeline, primProc, - primitiveType, - *renderPass); + primitiveType); if (!pipelineState) { return; } @@ -423,25 +572,28 @@ void GrVkGpuCommandBuffer::onDraw(const GrPipeline& pipeline, this->bindGeometry(primProc, *nonIdxMesh); if (nonIdxMesh->isIndexed()) { - fCommandBuffer->drawIndexed(fGpu, - nonIdxMesh->indexCount(), + cbInfo.currentCmdBuf()->drawIndexed(fGpu, + nonIdxMesh->indexCount(), + 1, + nonIdxMesh->startIndex(), + nonIdxMesh->startVertex(), + 0); + } else { + cbInfo.currentCmdBuf()->draw(fGpu, + nonIdxMesh->vertexCount(), 1, - nonIdxMesh->startIndex(), nonIdxMesh->startVertex(), 0); - } else { - fCommandBuffer->draw(fGpu, - nonIdxMesh->vertexCount(), - 1, - nonIdxMesh->startVertex(), - 0); } - fIsEmpty = false; + cbInfo.fIsEmpty = false; fGpu->stats()->incNumDraws(); } while ((nonIdxMesh = iter.next())); } + // Update command buffer bounds + cbInfo.fBounds.join(bounds); + // Technically we don't have to call this here (since there is a safety check in // pipelineState:setData but this will allow for quicker freeing of resources if the // pipelineState sits in a cache for a while. diff --git a/gfx/skia/skia/src/gpu/vk/GrVkGpuCommandBuffer.h b/gfx/skia/skia/src/gpu/vk/GrVkGpuCommandBuffer.h index d91271e8c893..519edb37b69e 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkGpuCommandBuffer.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkGpuCommandBuffer.h @@ -24,46 +24,80 @@ class GrVkSecondaryCommandBuffer; class GrVkGpuCommandBuffer : public GrGpuCommandBuffer { public: GrVkGpuCommandBuffer(GrVkGpu* gpu, - GrVkRenderTarget*, const LoadAndStoreInfo& colorInfo, const LoadAndStoreInfo& stencilInfo); - virtual ~GrVkGpuCommandBuffer(); + ~GrVkGpuCommandBuffer() override; void end() override; - void discard(GrRenderTarget* rt) override; + void discard(GrRenderTarget*) override; + + void inlineUpload(GrOpFlushState* state, GrDrawOp::DeferredUploadFn& upload, + GrRenderTarget*) override; private: - GrGpu* gpu() override; + // Performs lazy initialization on the first operation seen by the command buffer. + void init(GrVkRenderTarget* rt); - void onSubmit(const SkIRect& bounds) override; + GrGpu* gpu() override; + GrRenderTarget* renderTarget() override; + + void onSubmit() override; // Bind vertex and index buffers void bindGeometry(const GrPrimitiveProcessor&, const GrNonInstancedMesh&); sk_sp prepareDrawState(const GrPipeline&, const GrPrimitiveProcessor&, - GrPrimitiveType, - const GrVkRenderPass&); + GrPrimitiveType); void onDraw(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, const GrMesh* mesh, - int meshCount) override; + int meshCount, + const SkRect& bounds) override; - void onClear(GrRenderTarget* rt, const GrFixedClip&, GrColor color) override; + void onClear(GrRenderTarget*, const GrFixedClip&, GrColor color) override; void onClearStencilClip(GrRenderTarget*, const GrFixedClip&, bool insideStencilMask) override; - const GrVkRenderPass* fRenderPass; - GrVkSecondaryCommandBuffer* fCommandBuffer; + void addAdditionalCommandBuffer(); + void addAdditionalRenderPass(); + + struct InlineUploadInfo { + InlineUploadInfo(GrOpFlushState* state, const GrDrawOp::DeferredUploadFn& upload) + : fFlushState(state), fUpload(upload) {} + + GrOpFlushState* fFlushState; + GrDrawOp::DeferredUploadFn fUpload; + }; + + struct CommandBufferInfo { + const GrVkRenderPass* fRenderPass; + SkTArray fCommandBuffers; + VkClearValue fColorClearValue; + SkRect fBounds; + bool fIsEmpty; + bool fStartsWithClear; + SkTArray fPreDrawUploads; + + GrVkSecondaryCommandBuffer* currentCmdBuf() { + return fCommandBuffers.back(); + } + }; + + SkTArray fCommandBufferInfos; + int fCurrentCmdInfo; + GrVkGpu* fGpu; GrVkRenderTarget* fRenderTarget; - VkClearValue fColorClearValue; - - bool fIsEmpty; - bool fStartsWithClear; + VkAttachmentLoadOp fVkColorLoadOp; + VkAttachmentStoreOp fVkColorStoreOp; + VkAttachmentLoadOp fVkStencilLoadOp; + VkAttachmentStoreOp fVkStencilStoreOp; + GrColor4f fClearColor; + GrVkPipelineState* fLastPipelineState; typedef GrGpuCommandBuffer INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkImage.cpp b/gfx/skia/skia/src/gpu/vk/GrVkImage.cpp index d0457ca28b68..c3302a2b04ef 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkImage.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkImage.cpp @@ -33,11 +33,12 @@ void GrVkImage::setImageLayout(const GrVkGpu* gpu, VkImageLayout newLayout, VK_IMAGE_LAYOUT_PREINITIALIZED != newLayout); VkImageLayout currentLayout = this->currentLayout(); - // If the old and new layout are the same, there is no reason to put in a barrier since the - // operations used for each layout are implicitly synchronized with eachother. The one exception - // is if the layout is GENERAL. In this case the image could have been used for any operation so - // we must respect the barrier. - if (newLayout == currentLayout && VK_IMAGE_LAYOUT_GENERAL != currentLayout) { + // If the old and new layout are the same and the layout is a read only layout, there is no need + // to put in a barrier. + if (newLayout == currentLayout && + (VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == currentLayout || + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == currentLayout || + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == currentLayout)) { return; } diff --git a/gfx/skia/skia/src/gpu/vk/GrVkInterface.cpp b/gfx/skia/skia/src/gpu/vk/GrVkInterface.cpp index 17b254eb6aa7..b08f7ba851c3 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkInterface.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkInterface.cpp @@ -9,169 +9,176 @@ #include "vk/GrVkBackendContext.h" #include "vk/GrVkUtil.h" -GrVkInterface::GrVkInterface() { -} +#define ACQUIRE_PROC(name, instance, device) fFunctions.f##name = \ + reinterpret_cast(getProc("vk"#name, instance, device)); -#define GET_PROC(F) functions->f ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F) -#define GET_PROC_LOCAL(inst, F) PFN_vk ## F F = (PFN_vk ## F) vkGetInstanceProcAddr(inst, "vk" #F) -#define GET_DEV_PROC(F) functions->f ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F) +GrVkInterface::GrVkInterface(GetProc getProc, + VkInstance instance, + VkDevice device, + uint32_t extensionFlags) { + if (getProc == nullptr) { + return; + } + // Global/Loader Procs. + ACQUIRE_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE); + ACQUIRE_PROC(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE, VK_NULL_HANDLE); + ACQUIRE_PROC(EnumerateInstanceLayerProperties, VK_NULL_HANDLE, VK_NULL_HANDLE); -const GrVkInterface* GrVkCreateInterface(VkInstance instance, VkDevice device, - uint32_t extensionFlags) { - - GrVkInterface* interface = new GrVkInterface(); - GrVkInterface::Functions* functions = &interface->fFunctions; - - GET_PROC(CreateInstance); - GET_PROC(DestroyInstance); - GET_PROC(EnumeratePhysicalDevices); - GET_PROC(GetPhysicalDeviceFeatures); - GET_PROC(GetPhysicalDeviceFormatProperties); - GET_PROC(GetPhysicalDeviceImageFormatProperties); - GET_PROC(GetPhysicalDeviceProperties); - GET_PROC(GetPhysicalDeviceQueueFamilyProperties); - GET_PROC(GetPhysicalDeviceMemoryProperties); - GET_PROC(CreateDevice); - GET_PROC(DestroyDevice); - GET_PROC(EnumerateInstanceExtensionProperties); - GET_PROC(EnumerateDeviceExtensionProperties); - GET_PROC(EnumerateInstanceLayerProperties); - GET_PROC(EnumerateDeviceLayerProperties); - GET_DEV_PROC(GetDeviceQueue); - GET_DEV_PROC(QueueSubmit); - GET_DEV_PROC(QueueWaitIdle); - GET_DEV_PROC(DeviceWaitIdle); - GET_DEV_PROC(AllocateMemory); - GET_DEV_PROC(FreeMemory); - GET_DEV_PROC(MapMemory); - GET_DEV_PROC(UnmapMemory); - GET_DEV_PROC(FlushMappedMemoryRanges); - GET_DEV_PROC(InvalidateMappedMemoryRanges); - GET_DEV_PROC(GetDeviceMemoryCommitment); - GET_DEV_PROC(BindBufferMemory); - GET_DEV_PROC(BindImageMemory); - GET_DEV_PROC(GetBufferMemoryRequirements); - GET_DEV_PROC(GetImageMemoryRequirements); - GET_DEV_PROC(GetImageSparseMemoryRequirements); - GET_PROC(GetPhysicalDeviceSparseImageFormatProperties); - GET_DEV_PROC(QueueBindSparse); - GET_DEV_PROC(CreateFence); - GET_DEV_PROC(DestroyFence); - GET_DEV_PROC(ResetFences); - GET_DEV_PROC(GetFenceStatus); - GET_DEV_PROC(WaitForFences); - GET_DEV_PROC(CreateSemaphore); - GET_DEV_PROC(DestroySemaphore); - GET_DEV_PROC(CreateEvent); - GET_DEV_PROC(DestroyEvent); - GET_DEV_PROC(GetEventStatus); - GET_DEV_PROC(SetEvent); - GET_DEV_PROC(ResetEvent); - GET_DEV_PROC(CreateQueryPool); - GET_DEV_PROC(DestroyQueryPool); - GET_DEV_PROC(GetQueryPoolResults); - GET_DEV_PROC(CreateBuffer); - GET_DEV_PROC(DestroyBuffer); - GET_DEV_PROC(CreateBufferView); - GET_DEV_PROC(DestroyBufferView); - GET_DEV_PROC(CreateImage); - GET_DEV_PROC(DestroyImage); - GET_DEV_PROC(GetImageSubresourceLayout); - GET_DEV_PROC(CreateImageView); - GET_DEV_PROC(DestroyImageView); - GET_DEV_PROC(CreateShaderModule); - GET_DEV_PROC(DestroyShaderModule); - GET_DEV_PROC(CreatePipelineCache); - GET_DEV_PROC(DestroyPipelineCache); - GET_DEV_PROC(GetPipelineCacheData); - GET_DEV_PROC(MergePipelineCaches); - GET_DEV_PROC(CreateGraphicsPipelines); - GET_DEV_PROC(CreateComputePipelines); - GET_DEV_PROC(DestroyPipeline); - GET_DEV_PROC(CreatePipelineLayout); - GET_DEV_PROC(DestroyPipelineLayout); - GET_DEV_PROC(CreateSampler); - GET_DEV_PROC(DestroySampler); - GET_DEV_PROC(CreateDescriptorSetLayout); - GET_DEV_PROC(DestroyDescriptorSetLayout); - GET_DEV_PROC(CreateDescriptorPool); - GET_DEV_PROC(DestroyDescriptorPool); - GET_DEV_PROC(ResetDescriptorPool); - GET_DEV_PROC(AllocateDescriptorSets); - GET_DEV_PROC(FreeDescriptorSets); - GET_DEV_PROC(UpdateDescriptorSets); - GET_DEV_PROC(CreateFramebuffer); - GET_DEV_PROC(DestroyFramebuffer); - GET_DEV_PROC(CreateRenderPass); - GET_DEV_PROC(DestroyRenderPass); - GET_DEV_PROC(GetRenderAreaGranularity); - GET_DEV_PROC(CreateCommandPool); - GET_DEV_PROC(DestroyCommandPool); - GET_DEV_PROC(ResetCommandPool); - GET_DEV_PROC(AllocateCommandBuffers); - GET_DEV_PROC(FreeCommandBuffers); - GET_DEV_PROC(BeginCommandBuffer); - GET_DEV_PROC(EndCommandBuffer); - GET_DEV_PROC(ResetCommandBuffer); - GET_DEV_PROC(CmdBindPipeline); - GET_DEV_PROC(CmdSetViewport); - GET_DEV_PROC(CmdSetScissor); - GET_DEV_PROC(CmdSetLineWidth); - GET_DEV_PROC(CmdSetDepthBias); - GET_DEV_PROC(CmdSetBlendConstants); - GET_DEV_PROC(CmdSetDepthBounds); - GET_DEV_PROC(CmdSetStencilCompareMask); - GET_DEV_PROC(CmdSetStencilWriteMask); - GET_DEV_PROC(CmdSetStencilReference); - GET_DEV_PROC(CmdBindDescriptorSets); - GET_DEV_PROC(CmdBindIndexBuffer); - GET_DEV_PROC(CmdBindVertexBuffers); - GET_DEV_PROC(CmdDraw); - GET_DEV_PROC(CmdDrawIndexed); - GET_DEV_PROC(CmdDrawIndirect); - GET_DEV_PROC(CmdDrawIndexedIndirect); - GET_DEV_PROC(CmdDispatch); - GET_DEV_PROC(CmdDispatchIndirect); - GET_DEV_PROC(CmdCopyBuffer); - GET_DEV_PROC(CmdCopyImage); - GET_DEV_PROC(CmdBlitImage); - GET_DEV_PROC(CmdCopyBufferToImage); - GET_DEV_PROC(CmdCopyImageToBuffer); - GET_DEV_PROC(CmdUpdateBuffer); - GET_DEV_PROC(CmdFillBuffer); - GET_DEV_PROC(CmdClearColorImage); - GET_DEV_PROC(CmdClearDepthStencilImage); - GET_DEV_PROC(CmdClearAttachments); - GET_DEV_PROC(CmdResolveImage); - GET_DEV_PROC(CmdSetEvent); - GET_DEV_PROC(CmdResetEvent); - GET_DEV_PROC(CmdWaitEvents); - GET_DEV_PROC(CmdPipelineBarrier); - GET_DEV_PROC(CmdBeginQuery); - GET_DEV_PROC(CmdEndQuery); - GET_DEV_PROC(CmdResetQueryPool); - GET_DEV_PROC(CmdWriteTimestamp); - GET_DEV_PROC(CmdCopyQueryPoolResults); - GET_DEV_PROC(CmdPushConstants); - GET_DEV_PROC(CmdBeginRenderPass); - GET_DEV_PROC(CmdNextSubpass); - GET_DEV_PROC(CmdEndRenderPass); - GET_DEV_PROC(CmdExecuteCommands); + // Instance Procs. + ACQUIRE_PROC(EnumeratePhysicalDevices, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(GetPhysicalDeviceFeatures, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(GetPhysicalDeviceFormatProperties, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(GetPhysicalDeviceImageFormatProperties, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(GetPhysicalDeviceProperties, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(GetPhysicalDeviceQueueFamilyProperties, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(GetPhysicalDeviceMemoryProperties, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(GetPhysicalDeviceSparseImageFormatProperties, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(DestroyInstance, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(CreateDevice, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(DestroyDevice, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(EnumerateDeviceExtensionProperties, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(EnumerateDeviceLayerProperties, instance, VK_NULL_HANDLE); if (extensionFlags & kEXT_debug_report_GrVkExtensionFlag) { - GET_PROC(CreateDebugReportCallbackEXT); - GET_PROC(DebugReportMessageEXT); - GET_PROC(DestroyDebugReportCallbackEXT); + // Also instance Procs. + ACQUIRE_PROC(CreateDebugReportCallbackEXT, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(DebugReportMessageEXT, instance, VK_NULL_HANDLE); + ACQUIRE_PROC(DestroyDebugReportCallbackEXT, instance, VK_NULL_HANDLE); } - return interface; + // Device Procs. + ACQUIRE_PROC(GetDeviceQueue, VK_NULL_HANDLE, device); + ACQUIRE_PROC(QueueSubmit, VK_NULL_HANDLE, device); + ACQUIRE_PROC(QueueWaitIdle, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DeviceWaitIdle, VK_NULL_HANDLE, device); + ACQUIRE_PROC(AllocateMemory, VK_NULL_HANDLE, device); + ACQUIRE_PROC(FreeMemory, VK_NULL_HANDLE, device); + ACQUIRE_PROC(MapMemory, VK_NULL_HANDLE, device); + ACQUIRE_PROC(UnmapMemory, VK_NULL_HANDLE, device); + ACQUIRE_PROC(FlushMappedMemoryRanges, VK_NULL_HANDLE, device); + ACQUIRE_PROC(InvalidateMappedMemoryRanges, VK_NULL_HANDLE, device); + ACQUIRE_PROC(GetDeviceMemoryCommitment, VK_NULL_HANDLE, device); + ACQUIRE_PROC(BindBufferMemory, VK_NULL_HANDLE, device); + ACQUIRE_PROC(BindImageMemory, VK_NULL_HANDLE, device); + ACQUIRE_PROC(GetBufferMemoryRequirements, VK_NULL_HANDLE, device); + ACQUIRE_PROC(GetImageMemoryRequirements, VK_NULL_HANDLE, device); + ACQUIRE_PROC(GetImageSparseMemoryRequirements, VK_NULL_HANDLE, device); + ACQUIRE_PROC(QueueBindSparse, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateFence, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyFence, VK_NULL_HANDLE, device); + ACQUIRE_PROC(ResetFences, VK_NULL_HANDLE, device); + ACQUIRE_PROC(GetFenceStatus, VK_NULL_HANDLE, device); + ACQUIRE_PROC(WaitForFences, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateSemaphore, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroySemaphore, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateEvent, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyEvent, VK_NULL_HANDLE, device); + ACQUIRE_PROC(GetEventStatus, VK_NULL_HANDLE, device); + ACQUIRE_PROC(SetEvent, VK_NULL_HANDLE, device); + ACQUIRE_PROC(ResetEvent, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateQueryPool, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyQueryPool, VK_NULL_HANDLE, device); + ACQUIRE_PROC(GetQueryPoolResults, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateBuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyBuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateBufferView, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyBufferView, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateImage, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyImage, VK_NULL_HANDLE, device); + ACQUIRE_PROC(GetImageSubresourceLayout, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateImageView, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyImageView, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateShaderModule, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyShaderModule, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreatePipelineCache, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyPipelineCache, VK_NULL_HANDLE, device); + ACQUIRE_PROC(GetPipelineCacheData, VK_NULL_HANDLE, device); + ACQUIRE_PROC(MergePipelineCaches, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateGraphicsPipelines, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateComputePipelines, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyPipeline, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreatePipelineLayout, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyPipelineLayout, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateSampler, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroySampler, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateDescriptorSetLayout, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyDescriptorSetLayout, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateDescriptorPool, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyDescriptorPool, VK_NULL_HANDLE, device); + ACQUIRE_PROC(ResetDescriptorPool, VK_NULL_HANDLE, device); + ACQUIRE_PROC(AllocateDescriptorSets, VK_NULL_HANDLE, device); + ACQUIRE_PROC(FreeDescriptorSets, VK_NULL_HANDLE, device); + ACQUIRE_PROC(UpdateDescriptorSets, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateFramebuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyFramebuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateRenderPass, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyRenderPass, VK_NULL_HANDLE, device); + ACQUIRE_PROC(GetRenderAreaGranularity, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CreateCommandPool, VK_NULL_HANDLE, device); + ACQUIRE_PROC(DestroyCommandPool, VK_NULL_HANDLE, device); + ACQUIRE_PROC(ResetCommandPool, VK_NULL_HANDLE, device); + ACQUIRE_PROC(AllocateCommandBuffers, VK_NULL_HANDLE, device); + ACQUIRE_PROC(FreeCommandBuffers, VK_NULL_HANDLE, device); + ACQUIRE_PROC(BeginCommandBuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(EndCommandBuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(ResetCommandBuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdBindPipeline, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdSetViewport, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdSetScissor, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdSetLineWidth, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdSetDepthBias, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdSetBlendConstants, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdSetDepthBounds, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdSetStencilCompareMask, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdSetStencilWriteMask, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdSetStencilReference, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdBindDescriptorSets, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdBindIndexBuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdBindVertexBuffers, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdDraw, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdDrawIndexed, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdDrawIndirect, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdDrawIndexedIndirect, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdDispatch, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdDispatchIndirect, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdCopyBuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdCopyImage, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdBlitImage, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdCopyBufferToImage, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdCopyImageToBuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdUpdateBuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdFillBuffer, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdClearColorImage, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdClearDepthStencilImage, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdClearAttachments, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdResolveImage, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdSetEvent, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdResetEvent, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdWaitEvents, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdPipelineBarrier, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdBeginQuery, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdEndQuery, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdResetQueryPool, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdWriteTimestamp, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdCopyQueryPoolResults, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdPushConstants, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdBeginRenderPass, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdNextSubpass, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdEndRenderPass, VK_NULL_HANDLE, device); + ACQUIRE_PROC(CmdExecuteCommands, VK_NULL_HANDLE, device); } +#ifdef SK_DEBUG + static int kIsDebug = 1; +#else + static int kIsDebug = 0; +#endif + #define RETURN_FALSE_INTERFACE \ if (kIsDebug) { SkDebugf("%s:%d GrVkInterface::validate() failed.\n", __FILE__, __LINE__); } \ return false; -bool GrVkInterface::validate() const { +bool GrVkInterface::validate(uint32_t extensionFlags) const { // functions that are always required if (NULL == fFunctions.fCreateInstance || NULL == fFunctions.fDestroyInstance || @@ -307,12 +314,17 @@ bool GrVkInterface::validate() const { NULL == fFunctions.fCmdBeginRenderPass || NULL == fFunctions.fCmdNextSubpass || NULL == fFunctions.fCmdEndRenderPass || - NULL == fFunctions.fCmdExecuteCommands || - NULL == fFunctions.fCreateDebugReportCallbackEXT || - NULL == fFunctions.fDebugReportMessageEXT || - NULL == fFunctions.fDestroyDebugReportCallbackEXT) { + NULL == fFunctions.fCmdExecuteCommands) { + RETURN_FALSE_INTERFACE + } - return false; + if (extensionFlags & kEXT_debug_report_GrVkExtensionFlag) { + if (NULL == fFunctions.fCreateDebugReportCallbackEXT || + NULL == fFunctions.fDebugReportMessageEXT || + NULL == fFunctions.fDestroyDebugReportCallbackEXT) { + RETURN_FALSE_INTERFACE + } } return true; } + diff --git a/gfx/skia/skia/src/gpu/vk/GrVkMemory.cpp b/gfx/skia/skia/src/gpu/vk/GrVkMemory.cpp index 2853c89fee86..27641028c002 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkMemory.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkMemory.cpp @@ -561,7 +561,7 @@ bool GrVkHeap::subAlloc(VkDeviceSize size, VkDeviceSize alignment, } // need to allocate a new subheap - SkAutoTDelete& subHeap = fSubHeaps.push_back(); + std::unique_ptr& subHeap = fSubHeaps.push_back(); subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, fSubHeapSize, alignment)); // try to recover from failed allocation by only allocating what we need if (subHeap->size() == 0) { @@ -609,7 +609,7 @@ bool GrVkHeap::singleAlloc(VkDeviceSize size, VkDeviceSize alignment, } // need to allocate a new subheap - SkAutoTDelete& subHeap = fSubHeaps.push_back(); + std::unique_ptr& subHeap = fSubHeaps.push_back(); subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, alignedSize, alignment)); fAllocSize += alignedSize; if (subHeap->alloc(size, alloc)) { diff --git a/gfx/skia/skia/src/gpu/vk/GrVkMemory.h b/gfx/skia/skia/src/gpu/vk/GrVkMemory.h index a1d4392ebed8..77267ab48c47 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkMemory.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkMemory.h @@ -162,6 +162,6 @@ private: VkDeviceSize fAllocSize; VkDeviceSize fUsedSize; AllocFunc fAllocFunc; - SkTArray> fSubHeaps; + SkTArray> fSubHeaps; }; #endif diff --git a/gfx/skia/skia/src/gpu/vk/GrVkPipeline.cpp b/gfx/skia/skia/src/gpu/vk/GrVkPipeline.cpp index 910398183b19..7c0aeb4b1561 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkPipeline.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkPipeline.cpp @@ -14,26 +14,35 @@ #include "GrVkRenderTarget.h" #include "GrVkUtil.h" -static inline const VkFormat& attrib_type_to_vkformat(GrVertexAttribType type) { - SkASSERT(type >= 0 && type < kGrVertexAttribTypeCount); - static const VkFormat kFormats[kGrVertexAttribTypeCount] = { - VK_FORMAT_R32_SFLOAT, // kFloat_GrVertexAttribType - VK_FORMAT_R32G32_SFLOAT, // kVec2f_GrVertexAttribType - VK_FORMAT_R32G32B32_SFLOAT, // kVec3f_GrVertexAttribType - VK_FORMAT_R32G32B32A32_SFLOAT, // kVec4f_GrVertexAttribType - VK_FORMAT_R8_UNORM, // kUByte_GrVertexAttribType - VK_FORMAT_R8G8B8A8_UNORM, // kVec4ub_GrVertexAttribType - VK_FORMAT_R16G16_UNORM, // kVec2us_GrVertexAttribType - }; - GR_STATIC_ASSERT(0 == kFloat_GrVertexAttribType); - GR_STATIC_ASSERT(1 == kVec2f_GrVertexAttribType); - GR_STATIC_ASSERT(2 == kVec3f_GrVertexAttribType); - GR_STATIC_ASSERT(3 == kVec4f_GrVertexAttribType); - GR_STATIC_ASSERT(4 == kUByte_GrVertexAttribType); - GR_STATIC_ASSERT(5 == kVec4ub_GrVertexAttribType); - GR_STATIC_ASSERT(6 == kVec2us_GrVertexAttribType); - GR_STATIC_ASSERT(SK_ARRAY_COUNT(kFormats) == kGrVertexAttribTypeCount); - return kFormats[type]; +static inline VkFormat attrib_type_to_vkformat(GrVertexAttribType type) { + switch (type) { + case kFloat_GrVertexAttribType: + return VK_FORMAT_R32_SFLOAT; + case kVec2f_GrVertexAttribType: + return VK_FORMAT_R32G32_SFLOAT; + case kVec3f_GrVertexAttribType: + return VK_FORMAT_R32G32B32_SFLOAT; + case kVec4f_GrVertexAttribType: + return VK_FORMAT_R32G32B32A32_SFLOAT; + case kVec2i_GrVertexAttribType: + return VK_FORMAT_R32G32_SINT; + case kVec3i_GrVertexAttribType: + return VK_FORMAT_R32G32B32_SINT; + case kVec4i_GrVertexAttribType: + return VK_FORMAT_R32G32B32A32_SINT; + case kUByte_GrVertexAttribType: + return VK_FORMAT_R8_UNORM; + case kVec4ub_GrVertexAttribType: + return VK_FORMAT_R8G8B8A8_UNORM; + case kVec2us_GrVertexAttribType: + return VK_FORMAT_R16G16_UNORM; + case kInt_GrVertexAttribType: + return VK_FORMAT_R32_SINT; + case kUint_GrVertexAttribType: + return VK_FORMAT_R32_UINT; + } + SkFAIL("Unknown vertex attrib type"); + return VK_FORMAT_UNDEFINED; } static void setup_vertex_input_state(const GrPrimitiveProcessor& primProc, @@ -397,6 +406,7 @@ static void setup_dynamic_state(VkPipelineDynamicStateCreateInfo* dynamicInfo, } GrVkPipeline* GrVkPipeline::Create(GrVkGpu* gpu, const GrPipeline& pipeline, + const GrStencilSettings& stencil, const GrPrimitiveProcessor& primProc, VkPipelineShaderStageCreateInfo* shaderStageInfo, int shaderStageCount, @@ -415,7 +425,7 @@ GrVkPipeline* GrVkPipeline::Create(GrVkGpu* gpu, const GrPipeline& pipeline, setup_input_assembly_state(primitiveType, &inputAssemblyInfo); VkPipelineDepthStencilStateCreateInfo depthStencilInfo; - setup_depth_stencil_state(pipeline.getStencil(), &depthStencilInfo); + setup_depth_stencil_state(stencil, &depthStencilInfo); VkPipelineViewportStateCreateInfo viewportInfo; setup_viewport_scissor_state(&viewportInfo); diff --git a/gfx/skia/skia/src/gpu/vk/GrVkPipeline.h b/gfx/skia/skia/src/gpu/vk/GrVkPipeline.h index 2565185712d1..b4788deee9e1 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkPipeline.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkPipeline.h @@ -17,6 +17,7 @@ class GrNonInstancedVertices; class GrPipeline; class GrPrimitiveProcessor; +class GrStencilSettings; class GrVkCommandBuffer; class GrVkGpu; class GrVkRenderPass; @@ -25,6 +26,7 @@ class GrVkPipeline : public GrVkResource { public: static GrVkPipeline* Create(GrVkGpu* gpu, const GrPipeline& pipeline, + const GrStencilSettings&, const GrPrimitiveProcessor& primProc, VkPipelineShaderStageCreateInfo* shaderStageInfo, int shaderStageCount, diff --git a/gfx/skia/skia/src/gpu/vk/GrVkPipelineState.cpp b/gfx/skia/skia/src/gpu/vk/GrVkPipelineState.cpp index 71ce831d65e3..4ce7681b15be 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkPipelineState.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkPipelineState.cpp @@ -75,7 +75,7 @@ GrVkPipelineState::GrVkPipelineState(GrVkGpu* gpu, } GrVkPipelineState::~GrVkPipelineState() { - // Must of freed all GPU resources before this is destroyed + // Must have freed all GPU resources before this is destroyed SkASSERT(!fPipeline); SkASSERT(!fPipelineLayout); SkASSERT(!fSamplers.count()); @@ -172,14 +172,18 @@ void GrVkPipelineState::abandonGPUResources() { } } -static void append_texture_bindings(const GrProcessor& processor, - SkTArray* textureBindings) { - if (int numTextures = processor.numTextures()) { - const GrTextureAccess** bindings = textureBindings->push_back_n(numTextures); +static void append_texture_bindings( + const GrResourceIOProcessor& processor, + SkTArray* textureBindings) { + // We don't support image storages in VK. + SkASSERT(!processor.numImageStorages()); + if (int numTextureSamplers = processor.numTextureSamplers()) { + const GrResourceIOProcessor::TextureSampler** bindings = + textureBindings->push_back_n(numTextureSamplers); int i = 0; do { - bindings[i] = &processor.textureAccess(i); - } while (++i < numTextures); + bindings[i] = &processor.textureSampler(i); + } while (++i < numTextureSamplers); } } @@ -190,9 +194,9 @@ void GrVkPipelineState::setData(GrVkGpu* gpu, // freeing the tempData between calls. this->freeTempResources(gpu); - this->setRenderTargetState(pipeline); + this->setRenderTargetState(pipeline.getRenderTarget()); - SkSTArray<8, const GrTextureAccess*> textureBindings; + SkSTArray<8, const GrResourceIOProcessor::TextureSampler*> textureBindings; fGeometryProcessor->setData(fDataManager, primProc, GrFragmentProcessor::CoordTransformIter(pipeline)); @@ -211,8 +215,14 @@ void GrVkPipelineState::setData(GrVkGpu* gpu, } SkASSERT(!fp && !glslFP); - fXferProcessor->setData(fDataManager, pipeline.getXferProcessor()); - append_texture_bindings(pipeline.getXferProcessor(), &textureBindings); + SkIPoint offset; + GrTexture* dstTexture = pipeline.dstTexture(&offset); + fXferProcessor->setData(fDataManager, pipeline.getXferProcessor(), dstTexture, offset); + GrResourceIOProcessor::TextureSampler dstTextureSampler; + if (dstTexture) { + dstTextureSampler.reset(dstTexture); + textureBindings.push_back(&dstTextureSampler); + } // Get new descriptor sets if (fNumSamplers) { @@ -226,8 +236,11 @@ void GrVkPipelineState::setData(GrVkGpu* gpu, } if (fVertexUniformBuffer.get() || fFragmentUniformBuffer.get()) { - if (fDataManager.uploadUniformBuffers(gpu, fVertexUniformBuffer, fFragmentUniformBuffer) || - !fUniformDescriptorSet) { + if (fDataManager.uploadUniformBuffers(gpu, + fVertexUniformBuffer.get(), + fFragmentUniformBuffer.get()) + || !fUniformDescriptorSet) + { if (fUniformDescriptorSet) { fUniformDescriptorSet->recycle(gpu); } @@ -299,15 +312,16 @@ void GrVkPipelineState::writeUniformBuffers(const GrVkGpu* gpu) { } } -void GrVkPipelineState::writeSamplers(GrVkGpu* gpu, - const SkTArray& textureBindings, - bool allowSRGBInputs) { +void GrVkPipelineState::writeSamplers( + GrVkGpu* gpu, + const SkTArray& textureBindings, + bool allowSRGBInputs) { SkASSERT(fNumSamplers == textureBindings.count()); for (int i = 0; i < textureBindings.count(); ++i) { - const GrTextureParams& params = textureBindings[i]->getParams(); + const GrSamplerParams& params = textureBindings[i]->params(); - GrVkTexture* texture = static_cast(textureBindings[i]->getTexture()); + GrVkTexture* texture = static_cast(textureBindings[i]->texture()); fSamplers.push(gpu->resourceProvider().findOrCreateCompatibleSampler(params, texture->texturePriv().maxMipMapLevel())); @@ -347,16 +361,14 @@ void GrVkPipelineState::writeSamplers(GrVkGpu* gpu, } } -void GrVkPipelineState::setRenderTargetState(const GrPipeline& pipeline) { +void GrVkPipelineState::setRenderTargetState(const GrRenderTarget* rt) { // Load the RT height uniform if it is needed to y-flip gl_FragCoord. if (fBuiltinUniformHandles.fRTHeightUni.isValid() && - fRenderTargetState.fRenderTargetSize.fHeight != pipeline.getRenderTarget()->height()) { - fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, - SkIntToScalar(pipeline.getRenderTarget()->height())); + fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) { + fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height())); } // set RT adjustment - const GrRenderTarget* rt = pipeline.getRenderTarget(); SkISize size; size.set(rt->width(), rt->height()); SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid()); @@ -492,8 +504,9 @@ uint32_t get_blend_info_key(const GrPipeline& pipeline) { bool GrVkPipelineState::Desc::Build(Desc* desc, const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, + const GrStencilSettings& stencil, GrPrimitiveType primitiveType, - const GrGLSLCaps& caps) { + const GrShaderCaps& caps) { if (!INHERITED::Build(desc, primProc, primitiveType == kPoints_GrPrimitiveType, pipeline, caps)) { return false; @@ -503,7 +516,7 @@ bool GrVkPipelineState::Desc::Build(Desc* desc, GrVkRenderTarget* vkRT = (GrVkRenderTarget*)pipeline.getRenderTarget(); vkRT->simpleRenderPass()->genKey(&b); - pipeline.getStencil().genKey(&b); + stencil.genKey(&b); SkASSERT(sizeof(GrDrawFace) <= sizeof(uint32_t)); b.add32((int32_t)pipeline.getDrawFace()); diff --git a/gfx/skia/skia/src/gpu/vk/GrVkPipelineState.h b/gfx/skia/skia/src/gpu/vk/GrVkPipelineState.h index d15fef487a63..4d23364b83a4 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkPipelineState.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkPipelineState.h @@ -74,8 +74,9 @@ public: static bool Build(Desc*, const GrPrimitiveProcessor&, const GrPipeline&, + const GrStencilSettings&, GrPrimitiveType primitiveType, - const GrGLSLCaps&); + const GrShaderCaps&); private: typedef GrProgramDesc INHERITED; }; @@ -140,8 +141,10 @@ private: void writeUniformBuffers(const GrVkGpu* gpu); - void writeSamplers(GrVkGpu* gpu, const SkTArray& textureBindings, - bool allowSRGBInputs); + void writeSamplers( + GrVkGpu* gpu, + const SkTArray& textureBindings, + bool allowSRGBInputs); /** * We use the RT's size and origin to adjust from Skia device space to vulkan normalized device @@ -180,7 +183,7 @@ private: }; // Helper for setData() that sets the view matrix and loads the render target height uniform - void setRenderTargetState(const GrPipeline&); + void setRenderTargetState(const GrRenderTarget*); // GrVkResources GrVkPipeline* fPipeline; @@ -207,8 +210,8 @@ private: int fStartDS; int fDSCount; - SkAutoTDelete fVertexUniformBuffer; - SkAutoTDelete fFragmentUniformBuffer; + std::unique_ptr fVertexUniformBuffer; + std::unique_ptr fFragmentUniformBuffer; // GrVkResources used for sampling textures SkTDArray fSamplers; @@ -220,8 +223,8 @@ private: BuiltinUniformHandles fBuiltinUniformHandles; // Processors in the GrVkPipelineState - SkAutoTDelete fGeometryProcessor; - SkAutoTDelete fXferProcessor; + std::unique_ptr fGeometryProcessor; + std::unique_ptr fXferProcessor; GrGLSLFragProcs fFragmentProcessors; Desc fDesc; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateBuilder.cpp index 69ae4a4989de..1363045bd6ad 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateBuilder.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateBuilder.cpp @@ -7,16 +7,19 @@ #include "vk/GrVkPipelineStateBuilder.h" +#include "GrShaderCaps.h" #include "vk/GrVkDescriptorSetManager.h" #include "vk/GrVkGpu.h" #include "vk/GrVkRenderPass.h" + GrVkPipelineState* GrVkPipelineStateBuilder::CreatePipelineState( GrVkGpu* gpu, const GrPipeline& pipeline, + const GrStencilSettings& stencil, const GrPrimitiveProcessor& primProc, GrPrimitiveType primitiveType, - const GrVkPipelineState::Desc& desc, + GrVkPipelineState::Desc* desc, const GrVkRenderPass& renderPass) { // create a builder. This will be handed off to effects so they can use it to add // uniforms, varyings, textures, etc @@ -30,13 +33,13 @@ GrVkPipelineState* GrVkPipelineStateBuilder::CreatePipelineState( return nullptr; } - return builder.finalize(primitiveType, renderPass, desc); + return builder.finalize(stencil, primitiveType, renderPass, desc); } GrVkPipelineStateBuilder::GrVkPipelineStateBuilder(GrVkGpu* gpu, const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, - const GrProgramDesc& desc) + GrProgramDesc* desc) : INHERITED(pipeline, primProc, desc) , fGpu(gpu) , fVaryingHandler(this) @@ -46,23 +49,21 @@ GrVkPipelineStateBuilder::GrVkPipelineStateBuilder(GrVkGpu* gpu, const GrCaps* GrVkPipelineStateBuilder::caps() const { return fGpu->caps(); } -const GrGLSLCaps* GrVkPipelineStateBuilder::glslCaps() const { - return fGpu->vkCaps().glslCaps(); + +void GrVkPipelineStateBuilder::finalizeFragmentOutputColor(GrShaderVar& outputColor) { + outputColor.addLayoutQualifier("location = 0, index = 0"); } -void GrVkPipelineStateBuilder::finalizeFragmentOutputColor(GrGLSLShaderVar& outputColor) { - outputColor.setLayoutQualifier("location = 0, index = 0"); +void GrVkPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) { + outputColor.addLayoutQualifier("location = 0, index = 1"); } -void GrVkPipelineStateBuilder::finalizeFragmentSecondaryColor(GrGLSLShaderVar& outputColor) { - outputColor.setLayoutQualifier("location = 0, index = 1"); -} - -bool GrVkPipelineStateBuilder::CreateVkShaderModule(const GrVkGpu* gpu, - VkShaderStageFlagBits stage, +bool GrVkPipelineStateBuilder::createVkShaderModule(VkShaderStageFlagBits stage, const GrGLSLShaderBuilder& builder, VkShaderModule* shaderModule, - VkPipelineShaderStageCreateInfo* stageInfo) { + VkPipelineShaderStageCreateInfo* stageInfo, + const SkSL::Program::Settings& settings, + GrVkPipelineState::Desc* desc) { SkString shaderString; for (int i = 0; i < builder.fCompilerStrings.count(); ++i) { if (builder.fCompilerStrings[i]) { @@ -70,19 +71,35 @@ bool GrVkPipelineStateBuilder::CreateVkShaderModule(const GrVkGpu* gpu, shaderString.append("\n"); } } - return GrCompileVkShaderModule(gpu, shaderString.c_str(), stage, shaderModule, stageInfo); + + SkSL::Program::Inputs inputs; + bool result = GrCompileVkShaderModule(fGpu, shaderString.c_str(), stage, shaderModule, + stageInfo, settings, &inputs); + if (!result) { + return false; + } + if (inputs.fRTHeight) { + this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); + } + if (inputs.fFlipY) { + desc->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin( + this->pipeline().getRenderTarget()->origin())); + desc->finalize(); + } + return result; } -GrVkPipelineState* GrVkPipelineStateBuilder::finalize(GrPrimitiveType primitiveType, +GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& stencil, + GrPrimitiveType primitiveType, const GrVkRenderPass& renderPass, - const GrVkPipelineState::Desc& desc) { + GrVkPipelineState::Desc* desc) { VkDescriptorSetLayout dsLayout[2]; VkPipelineLayout pipelineLayout; VkShaderModule vertShaderModule; VkShaderModule fragShaderModule; GrVkResourceProvider& resourceProvider = fGpu->resourceProvider(); - // This layout is not owned by the PipelineStateBuilder and thus should no be destroyed + // These layouts are not owned by the PipelineStateBuilder and thus should not be destroyed dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout(); GrVkDescriptorSetManager::Handle samplerDSHandle; @@ -116,19 +133,27 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(GrPrimitiveType primitiveT this->finalizeShaders(); VkPipelineShaderStageCreateInfo shaderStageInfo[2]; - SkAssertResult(CreateVkShaderModule(fGpu, - VK_SHADER_STAGE_VERTEX_BIT, - fVS, - &vertShaderModule, - &shaderStageInfo[0])); + SkSL::Program::Settings settings; + settings.fFlipY = this->pipeline().getRenderTarget()->origin() != kTopLeft_GrSurfaceOrigin; + SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT, + fVS, + &vertShaderModule, + &shaderStageInfo[0], + settings, + desc)); - SkAssertResult(CreateVkShaderModule(fGpu, - VK_SHADER_STAGE_FRAGMENT_BIT, - fFS, - &fragShaderModule, - &shaderStageInfo[1])); + // TODO: geometry shader support. + SkASSERT(!this->primitiveProcessor().willUseGeoShader()); + + SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT, + fFS, + &fragShaderModule, + &shaderStageInfo[1], + settings, + desc)); GrVkPipeline* pipeline = resourceProvider.createPipeline(fPipeline, + stencil, fPrimProc, shaderStageInfo, 2, @@ -143,17 +168,12 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(GrPrimitiveType primitiveT if (!pipeline) { GR_VK_CALL(fGpu->vkInterface(), DestroyPipelineLayout(fGpu->device(), pipelineLayout, nullptr)); - GR_VK_CALL(fGpu->vkInterface(), - DestroyDescriptorSetLayout(fGpu->device(), - dsLayout[GrVkUniformHandler::kSamplerDescSet], - nullptr)); - this->cleanupFragmentProcessors(); return nullptr; } return new GrVkPipelineState(fGpu, - desc, + *desc, pipeline, pipelineLayout, samplerDSHandle, diff --git a/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateBuilder.h b/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateBuilder.h index c887e36d43ef..ae59ec4e021b 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateBuilder.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateBuilder.h @@ -14,6 +14,7 @@ #include "GrVkPipelineState.h" #include "GrVkUniformHandler.h" #include "GrVkVaryingHandler.h" +#include "SkSLCompiler.h" #include "vk/GrVkDefines.h" @@ -27,38 +28,42 @@ public: * * The GrVkPipelineState implements what is specified in the GrPipeline and GrPrimitiveProcessor * as input. After successful generation, the builder result objects are available to be used. + * This function may modify the program key by setting the surface origin key to 0 (unspecified) + * if it turns out the program does not care about the surface origin. * @return true if generation was successful. */ static GrVkPipelineState* CreatePipelineState(GrVkGpu*, const GrPipeline&, + const GrStencilSettings&, const GrPrimitiveProcessor&, GrPrimitiveType, - const GrVkPipelineState::Desc&, + GrVkPipelineState::Desc*, const GrVkRenderPass& renderPass); const GrCaps* caps() const override; - const GrGLSLCaps* glslCaps() const override; GrVkGpu* gpu() const { return fGpu; } - void finalizeFragmentOutputColor(GrGLSLShaderVar& outputColor) override; - void finalizeFragmentSecondaryColor(GrGLSLShaderVar& outputColor) override; + void finalizeFragmentOutputColor(GrShaderVar& outputColor) override; + void finalizeFragmentSecondaryColor(GrShaderVar& outputColor) override; private: GrVkPipelineStateBuilder(GrVkGpu*, const GrPipeline&, const GrPrimitiveProcessor&, - const GrProgramDesc&); + GrProgramDesc*); - GrVkPipelineState* finalize(GrPrimitiveType primitiveType, + GrVkPipelineState* finalize(const GrStencilSettings&, + GrPrimitiveType primitiveType, const GrVkRenderPass& renderPass, - const GrVkPipelineState::Desc&); + GrVkPipelineState::Desc*); - static bool CreateVkShaderModule(const GrVkGpu* gpu, - VkShaderStageFlagBits stage, - const GrGLSLShaderBuilder& builder, - VkShaderModule* shaderModule, - VkPipelineShaderStageCreateInfo* stageInfo); + bool createVkShaderModule(VkShaderStageFlagBits stage, + const GrGLSLShaderBuilder& builder, + VkShaderModule* shaderModule, + VkPipelineShaderStageCreateInfo* stageInfo, + const SkSL::Program::Settings& settings, + GrVkPipelineState::Desc* desc); GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; } const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; } diff --git a/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateCache.cpp b/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateCache.cpp index 2e6a85bb2c67..f8d77a96d6fa 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateCache.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateCache.cpp @@ -9,6 +9,7 @@ #include "GrVkGpu.h" #include "GrProcessor.h" +#include "GrRenderTargetPriv.h" // TODO: remove once refPipelineState gets passed stencil settings. #include "GrVkPipelineState.h" #include "GrVkPipelineStateBuilder.h" #include "SkOpts.h" @@ -21,25 +22,22 @@ static const bool c_DisplayVkPipelineCache{false}; #endif struct GrVkResourceProvider::PipelineStateCache::Entry { + Entry(GrVkGpu* gpu, sk_sp pipelineState) + : fGpu(gpu) + , fPipelineState(pipelineState) {} - Entry() : fPipelineState(nullptr) {} - - static const GrVkPipelineState::Desc& GetKey(const Entry* entry) { - return entry->fPipelineState->getDesc(); - } - - static uint32_t Hash(const GrVkPipelineState::Desc& key) { - return key.getChecksum(); + ~Entry() { + if (fPipelineState) { + fPipelineState->freeGPUResources(fGpu); + } } + GrVkGpu* fGpu; sk_sp fPipelineState; - -private: - SK_DECLARE_INTERNAL_LLIST_INTERFACE(Entry); }; GrVkResourceProvider::PipelineStateCache::PipelineStateCache(GrVkGpu* gpu) - : fCount(0) + : fMap(kMaxEntries) , fGpu(gpu) #ifdef GR_PIPELINE_STATE_CACHE_STATS , fTotalRequests(0) @@ -48,7 +46,7 @@ GrVkResourceProvider::PipelineStateCache::PipelineStateCache(GrVkGpu* gpu) {} GrVkResourceProvider::PipelineStateCache::~PipelineStateCache() { - SkASSERT(0 == fCount); + SkASSERT(0 == fMap.count()); // dump stats #ifdef GR_PIPELINE_STATE_CACHE_STATS if (c_DisplayVkPipelineCache) { @@ -63,30 +61,16 @@ GrVkResourceProvider::PipelineStateCache::~PipelineStateCache() { #endif } -void GrVkResourceProvider::PipelineStateCache::reset() { - fHashTable.foreach([](Entry** entry) { - delete *entry; - }); - fHashTable.reset(); - fCount = 0; -} - void GrVkResourceProvider::PipelineStateCache::abandon() { - fHashTable.foreach([](Entry** entry) { - SkASSERT((*entry)->fPipelineState.get()); - (*entry)->fPipelineState->abandonGPUResources(); + fMap.foreach([](std::unique_ptr* e) { + (*e)->fPipelineState->abandonGPUResources(); + (*e)->fPipelineState = nullptr; }); - - this->reset(); + fMap.reset(); } void GrVkResourceProvider::PipelineStateCache::release() { - fHashTable.foreach([this](Entry** entry) { - SkASSERT((*entry)->fPipelineState.get()); - (*entry)->fPipelineState->freeGPUResources(fGpu); - }); - - this->reset(); + fMap.reset(); } sk_sp GrVkResourceProvider::PipelineStateCache::refPipelineState( @@ -97,19 +81,31 @@ sk_sp GrVkResourceProvider::PipelineStateCache::refPipelineSt #ifdef GR_PIPELINE_STATE_CACHE_STATS ++fTotalRequests; #endif + GrStencilSettings stencil; + if (pipeline.isStencilEnabled()) { + GrRenderTarget* rt = pipeline.getRenderTarget(); + // TODO: attach stencil and create settings during render target flush. + SkASSERT(rt->renderTargetPriv().getStencilAttachment()); + stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(), + rt->renderTargetPriv().numStencilBits()); + } + // Get GrVkProgramDesc GrVkPipelineState::Desc desc; - if (!GrVkPipelineState::Desc::Build(&desc, primProc, pipeline, primitiveType, - *fGpu->vkCaps().glslCaps())) { + if (!GrVkPipelineState::Desc::Build(&desc, primProc, pipeline, stencil, + primitiveType, *fGpu->caps()->shaderCaps())) { GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n"); return nullptr; } desc.finalize(); - Entry* entry = nullptr; - if (Entry** entryptr = fHashTable.find(desc)) { - SkASSERT(*entryptr); - entry = *entryptr; + std::unique_ptr* entry = fMap.find(desc); + if (!entry) { + // Didn't find an origin-independent version, check with the specific origin + GrSurfaceOrigin origin = pipeline.getRenderTarget()->origin(); + desc.setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(origin)); + desc.finalize(); + entry = fMap.find(desc); } if (!entry) { #ifdef GR_PIPELINE_STATE_CACHE_STATS @@ -118,30 +114,17 @@ sk_sp GrVkResourceProvider::PipelineStateCache::refPipelineSt sk_sp pipelineState( GrVkPipelineStateBuilder::CreatePipelineState(fGpu, pipeline, + stencil, primProc, primitiveType, - desc, + &desc, renderPass)); if (nullptr == pipelineState) { return nullptr; } - if (fCount < kMaxEntries) { - entry = new Entry; - fCount++; - } else { - SkASSERT(fCount == kMaxEntries); - entry = fLRUList.head(); - fLRUList.remove(entry); - entry->fPipelineState->freeGPUResources(fGpu); - fHashTable.remove(entry->fPipelineState->getDesc()); - } - entry->fPipelineState = std::move(pipelineState); - fHashTable.set(entry); - fLRUList.addToTail(entry); - return entry->fPipelineState; - } else { - fLRUList.remove(entry); - fLRUList.addToTail(entry); + entry = fMap.insert(desc, std::unique_ptr(new Entry(fGpu, + std::move(pipelineState)))); + return (*entry)->fPipelineState; } - return entry->fPipelineState; + return (*entry)->fPipelineState; } diff --git a/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateDataManager.cpp b/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateDataManager.cpp index ef75bd3b9d07..88176da26502 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateDataManager.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateDataManager.cpp @@ -26,7 +26,7 @@ GrVkPipelineStateDataManager::GrVkPipelineStateDataManager(const UniformInfoArra for (int i = 0; i < count; i++) { Uniform& uniform = fUniforms[i]; const GrVkUniformHandler::UniformInfo uniformInfo = uniforms[i]; - SkASSERT(GrGLSLShaderVar::kNonArray == uniformInfo.fVariable.getArrayCount() || + SkASSERT(GrShaderVar::kNonArray == uniformInfo.fVariable.getArrayCount() || uniformInfo.fVariable.getArrayCount() > 0); SkDEBUGCODE( uniform.fArrayCount = uniformInfo.fVariable.getArrayCount(); @@ -57,7 +57,7 @@ void* GrVkPipelineStateDataManager::getBufferPtrAndMarkDirty(const Uniform& uni) void GrVkPipelineStateDataManager::set1i(UniformHandle u, int32_t i) const { const Uniform& uni = fUniforms[u.toIndex()]; SkASSERT(uni.fType == kInt_GrSLType); - SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); void* buffer = this->getBufferPtrAndMarkDirty(uni); memcpy(buffer, &i, sizeof(int32_t)); } @@ -69,7 +69,7 @@ void GrVkPipelineStateDataManager::set1iv(UniformHandle u, SkASSERT(uni.fType == kInt_GrSLType); SkASSERT(arrayCount > 0); SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrGLSLShaderVar::kNonArray == uni.fArrayCount)); + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); void* buffer = this->getBufferPtrAndMarkDirty(uni); SkASSERT(sizeof(int32_t) == 4); @@ -83,7 +83,7 @@ void GrVkPipelineStateDataManager::set1iv(UniformHandle u, void GrVkPipelineStateDataManager::set1f(UniformHandle u, float v0) const { const Uniform& uni = fUniforms[u.toIndex()]; SkASSERT(uni.fType == kFloat_GrSLType); - SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); void* buffer = this->getBufferPtrAndMarkDirty(uni); SkASSERT(sizeof(float) == 4); memcpy(buffer, &v0, sizeof(float)); @@ -96,7 +96,7 @@ void GrVkPipelineStateDataManager::set1fv(UniformHandle u, SkASSERT(uni.fType == kFloat_GrSLType); SkASSERT(arrayCount > 0); SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrGLSLShaderVar::kNonArray == uni.fArrayCount)); + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); void* buffer = this->getBufferPtrAndMarkDirty(uni); SkASSERT(sizeof(float) == 4); @@ -110,7 +110,7 @@ void GrVkPipelineStateDataManager::set1fv(UniformHandle u, void GrVkPipelineStateDataManager::set2f(UniformHandle u, float v0, float v1) const { const Uniform& uni = fUniforms[u.toIndex()]; SkASSERT(uni.fType == kVec2f_GrSLType); - SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); void* buffer = this->getBufferPtrAndMarkDirty(uni); SkASSERT(sizeof(float) == 4); float v[2] = { v0, v1 }; @@ -124,7 +124,7 @@ void GrVkPipelineStateDataManager::set2fv(UniformHandle u, SkASSERT(uni.fType == kVec2f_GrSLType); SkASSERT(arrayCount > 0); SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrGLSLShaderVar::kNonArray == uni.fArrayCount)); + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); void* buffer = this->getBufferPtrAndMarkDirty(uni); SkASSERT(sizeof(float) == 4); @@ -138,7 +138,7 @@ void GrVkPipelineStateDataManager::set2fv(UniformHandle u, void GrVkPipelineStateDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const { const Uniform& uni = fUniforms[u.toIndex()]; SkASSERT(uni.fType == kVec3f_GrSLType); - SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); void* buffer = this->getBufferPtrAndMarkDirty(uni); SkASSERT(sizeof(float) == 4); float v[3] = { v0, v1, v2 }; @@ -152,7 +152,7 @@ void GrVkPipelineStateDataManager::set3fv(UniformHandle u, SkASSERT(uni.fType == kVec3f_GrSLType); SkASSERT(arrayCount > 0); SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrGLSLShaderVar::kNonArray == uni.fArrayCount)); + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); void* buffer = this->getBufferPtrAndMarkDirty(uni); SkASSERT(sizeof(float) == 4); @@ -170,7 +170,7 @@ void GrVkPipelineStateDataManager::set4f(UniformHandle u, float v3) const { const Uniform& uni = fUniforms[u.toIndex()]; SkASSERT(uni.fType == kVec4f_GrSLType); - SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); void* buffer = this->getBufferPtrAndMarkDirty(uni); SkASSERT(sizeof(float) == 4); float v[4] = { v0, v1, v2, v3 }; @@ -184,7 +184,7 @@ void GrVkPipelineStateDataManager::set4fv(UniformHandle u, SkASSERT(uni.fType == kVec4f_GrSLType); SkASSERT(arrayCount > 0); SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrGLSLShaderVar::kNonArray == uni.fArrayCount)); + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); void* buffer = this->getBufferPtrAndMarkDirty(uni); SkASSERT(sizeof(float) == 4); @@ -230,7 +230,7 @@ template inline void GrVkPipelineStateDataManager::setMatrices(UniformHan SkASSERT(uni.fType == kMat22f_GrSLType + (N - 2)); SkASSERT(arrayCount > 0); SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrGLSLShaderVar::kNonArray == uni.fArrayCount)); + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); void* buffer; if (GrVkUniformHandler::kVertexBinding == uni.fBinding) { diff --git a/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateDataManager.h b/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateDataManager.h index 312c6c659db3..4a061a66f945 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateDataManager.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkPipelineStateDataManager.h @@ -10,6 +10,7 @@ #include "glsl/GrGLSLProgramDataManager.h" +#include "SkAutoMalloc.h" #include "vk/GrVkUniformHandler.h" class GrVkGpu; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkRenderPass.cpp b/gfx/skia/skia/src/gpu/vk/GrVkRenderPass.cpp index ee2d3d9f0e94..a6a6afbbbd16 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkRenderPass.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkRenderPass.cpp @@ -84,6 +84,10 @@ void GrVkRenderPass::init(const GrVkGpu* gpu, colorRef.attachment = currentAttachment++; colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; subpassDesc.colorAttachmentCount = 1; + + if (VK_ATTACHMENT_LOAD_OP_CLEAR == colorOp.fLoadOp) { + fClearValueCount++; + } } else { // I don't think there should ever be a time where we don't have a color attachment SkASSERT(false); @@ -102,6 +106,9 @@ void GrVkRenderPass::init(const GrVkGpu* gpu, // setup subpass use of attachment stencilRef.attachment = currentAttachment++; stencilRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + if (VK_ATTACHMENT_LOAD_OP_CLEAR == stencilOp.fLoadOp) { + fClearValueCount++; + } } else { stencilRef.attachment = VK_ATTACHMENT_UNUSED; stencilRef.layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -147,7 +154,7 @@ void GrVkRenderPass::init(const GrVkGpu* gpu, } void GrVkRenderPass::init(const GrVkGpu* gpu, - const GrVkRenderTarget& target, + const GrVkRenderTarget& target, const LoadStoreOps& colorOp, const LoadStoreOps& stencilOp) { // Get attachment information from render target. This includes which attachments the render @@ -183,29 +190,6 @@ bool GrVkRenderPass::stencilAttachmentIndex(uint32_t* index) const { return false; } -void GrVkRenderPass::getBeginInfo(const GrVkRenderTarget& target, - VkRenderPassBeginInfo* beginInfo, - VkSubpassContents* contents) const { - SkASSERT(this->isCompatible(target)); - - VkRect2D renderArea; - renderArea.offset = { 0, 0 }; - renderArea.extent = { (uint32_t)target.width(), (uint32_t)target.height() }; - - memset(beginInfo, 0, sizeof(VkRenderPassBeginInfo)); - beginInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - beginInfo->pNext = nullptr; - beginInfo->renderPass = fRenderPass; - beginInfo->framebuffer = target.framebuffer()->framebuffer(); - beginInfo->renderArea = renderArea; - beginInfo->clearValueCount = 0; - beginInfo->pClearValues = nullptr; - - // Currently just assuming no secondary cmd buffers. This value will need to be update if we - // have them. - *contents = VK_SUBPASS_CONTENTS_INLINE; -} - bool GrVkRenderPass::isCompatible(const AttachmentsDescriptor& desc, const AttachmentFlags& flags) const { if (flags != fAttachmentFlags) { diff --git a/gfx/skia/skia/src/gpu/vk/GrVkRenderPass.h b/gfx/skia/skia/src/gpu/vk/GrVkRenderPass.h index d59b5fa1dc72..b3b6092a5e68 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkRenderPass.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkRenderPass.h @@ -20,7 +20,7 @@ class GrVkRenderTarget; class GrVkRenderPass : public GrVkResource { public: - GrVkRenderPass() : INHERITED(), fRenderPass(VK_NULL_HANDLE) {} + GrVkRenderPass() : INHERITED(), fRenderPass(VK_NULL_HANDLE), fClearValueCount(0) {} struct LoadStoreOps { VkAttachmentLoadOp fLoadOp; @@ -89,16 +89,6 @@ public: bool colorAttachmentIndex(uint32_t* index) const; bool stencilAttachmentIndex(uint32_t* index) const; - // Sets the VkRenderPassBeginInfo and VkRenderPassContents need to begin a render pass. - // TODO: In the future I expect this function will also take an optional render area instead of - // defaulting to the entire render target. - // TODO: Figure out if load clear values should be passed into this function or should be stored - // on the GrVkRenderPass at create time since we'll know at that point if we want to do a load - // clear. - void getBeginInfo(const GrVkRenderTarget& target, - VkRenderPassBeginInfo* beginInfo, - VkSubpassContents* contents) const; - // Returns whether or not the structure of a RenderTarget matches that of the VkRenderPass in // this object. Specifically this compares that the number of attachments, format of // attachments, and sample counts are all the same. This function is used in the creation of @@ -114,6 +104,11 @@ public: const VkExtent2D& granularity() const { return fGranularity; } + // Returns the number of clear colors needed to begin this render pass. Currently this will + // either only be 0 or 1 since we only ever clear the color attachment. + uint32_t clearValueCount() const { return fClearValueCount; } + + void genKey(GrProcessorKeyBuilder* b) const; #ifdef SK_TRACE_VK_RESOURCES @@ -137,6 +132,7 @@ private: AttachmentFlags fAttachmentFlags; AttachmentsDescriptor fAttachmentsDescriptor; VkExtent2D fGranularity; + uint32_t fClearValueCount; typedef GrVkResource INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkRenderTarget.cpp b/gfx/skia/skia/src/gpu/vk/GrVkRenderTarget.cpp index d6895d25fc75..d5719fdd5e57 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkRenderTarget.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkRenderTarget.cpp @@ -39,8 +39,6 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(desc.fSampleCnt); - // The plus 1 is to account for the resolve texture. - fColorValuesPerPixel = desc.fSampleCnt + 1; // TODO: this still correct? this->createFramebuffer(gpu); this->registerWithCache(budgeted); } @@ -64,8 +62,6 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(desc.fSampleCnt); - // The plus 1 is to account for the resolve texture. - fColorValuesPerPixel = desc.fSampleCnt + 1; // TODO: this still correct? this->createFramebuffer(gpu); } @@ -86,7 +82,6 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(!desc.fSampleCnt); - fColorValuesPerPixel = 1; this->createFramebuffer(gpu); this->registerWithCache(budgeted); } @@ -107,7 +102,6 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(!desc.fSampleCnt); - fColorValuesPerPixel = 1; this->createFramebuffer(gpu); } @@ -201,22 +195,15 @@ GrVkRenderTarget::CreateNewRenderTarget(GrVkGpu* gpu, return rt; } -GrVkRenderTarget* -GrVkRenderTarget::CreateWrappedRenderTarget(GrVkGpu* gpu, - const GrSurfaceDesc& desc, - GrWrapOwnership ownership, - const GrVkImageInfo* info) { +sk_sp +GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu, + const GrSurfaceDesc& desc, + const GrVkImageInfo* info) { SkASSERT(info); - // We can wrap a rendertarget without its allocation, as long as we don't take ownership SkASSERT(VK_NULL_HANDLE != info->fImage); - SkASSERT(VK_NULL_HANDLE != info->fAlloc.fMemory || kAdopt_GrWrapOwnership != ownership); - GrVkImage::Wrapped wrapped = kBorrow_GrWrapOwnership == ownership ? GrVkImage::kBorrowed_Wrapped - : GrVkImage::kAdopted_Wrapped; - - GrVkRenderTarget* rt = GrVkRenderTarget::Create(gpu, SkBudgeted::kNo, desc, *info, wrapped); - - return rt; + return sk_sp( + GrVkRenderTarget::Create(gpu, SkBudgeted::kNo, desc, *info, GrVkImage::kBorrowed_Wrapped)); } bool GrVkRenderTarget::completeStencilAttachment() { @@ -294,7 +281,7 @@ void GrVkRenderTarget::releaseInternalObjects() { if (fMSAAImage) { fMSAAImage->releaseImage(gpu); - fMSAAImage = nullptr; + fMSAAImage.reset(); } if (fResolveAttachmentView) { @@ -318,7 +305,7 @@ void GrVkRenderTarget::releaseInternalObjects() { void GrVkRenderTarget::abandonInternalObjects() { if (fMSAAImage) { fMSAAImage->abandonImage(); - fMSAAImage = nullptr; + fMSAAImage.reset(); } if (fResolveAttachmentView) { diff --git a/gfx/skia/skia/src/gpu/vk/GrVkRenderTarget.h b/gfx/skia/skia/src/gpu/vk/GrVkRenderTarget.h index e3ebefba5ada..cf425fb0a2de 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkRenderTarget.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkRenderTarget.h @@ -34,9 +34,8 @@ public: static GrVkRenderTarget* CreateNewRenderTarget(GrVkGpu*, SkBudgeted, const GrSurfaceDesc&, const GrVkImage::ImageDesc&); - static GrVkRenderTarget* CreateWrappedRenderTarget(GrVkGpu*, const GrSurfaceDesc&, - GrWrapOwnership, - const GrVkImageInfo*); + static sk_sp MakeWrappedRenderTarget(GrVkGpu*, const GrSurfaceDesc&, + const GrVkImageInfo*); ~GrVkRenderTarget() override; @@ -48,7 +47,7 @@ public: } return nullptr; } - GrVkImage* msaaImage() { return fMSAAImage; } + GrVkImage* msaaImage() { return fMSAAImage.get(); } const GrVkImageView* resolveAttachmentView() const { return fResolveAttachmentView; } const GrVkResource* stencilImageResource() const; const GrVkImageView* stencilAttachmentView() const; @@ -99,17 +98,15 @@ protected: // This accounts for the texture's memory and any MSAA renderbuffer's memory. size_t onGpuMemorySize() const override { - SkASSERT(kUnknown_GrPixelConfig != fDesc.fConfig); - SkASSERT(!GrPixelConfigIsCompressed(fDesc.fConfig)); - size_t colorBytes = GrBytesPerPixel(fDesc.fConfig); - SkASSERT(colorBytes > 0); - return fColorValuesPerPixel * fDesc.fWidth * fDesc.fHeight * colorBytes; + // The plus 1 is to account for the resolve texture. + // TODO: is this still correct? + return GrSurface::ComputeSize(fDesc, fDesc.fSampleCnt+1, false); } void createFramebuffer(GrVkGpu* gpu); const GrVkImageView* fColorAttachmentView; - GrVkImage* fMSAAImage; + std::unique_ptr fMSAAImage; const GrVkImageView* fResolveAttachmentView; private: @@ -138,7 +135,6 @@ private: void abandonInternalObjects(); const GrVkFramebuffer* fFramebuffer; - int fColorValuesPerPixel; // This is a cached pointer to a simple render pass. The render target should unref it // once it is done with it. diff --git a/gfx/skia/skia/src/gpu/vk/GrVkResourceProvider.cpp b/gfx/skia/skia/src/gpu/vk/GrVkResourceProvider.cpp index 3027c2d34977..487633d3dcd1 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkResourceProvider.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkResourceProvider.cpp @@ -7,10 +7,9 @@ #include "GrVkResourceProvider.h" -#include "GrTextureParams.h" +#include "GrSamplerParams.h" #include "GrVkCommandBuffer.h" #include "GrVkCopyPipeline.h" -#include "GrVkGLSLSampler.h" #include "GrVkPipeline.h" #include "GrVkRenderTarget.h" #include "GrVkSampler.h" @@ -57,6 +56,7 @@ void GrVkResourceProvider::init() { } GrVkPipeline* GrVkResourceProvider::createPipeline(const GrPipeline& pipeline, + const GrStencilSettings& stencil, const GrPrimitiveProcessor& primProc, VkPipelineShaderStageCreateInfo* shaderStageInfo, int shaderStageCount, @@ -64,8 +64,9 @@ GrVkPipeline* GrVkResourceProvider::createPipeline(const GrPipeline& pipeline, const GrVkRenderPass& renderPass, VkPipelineLayout layout) { - return GrVkPipeline::Create(fGpu, pipeline, primProc, shaderStageInfo, shaderStageCount, - primitiveType, renderPass, layout, fPipelineCache); + return GrVkPipeline::Create(fGpu, pipeline, stencil, primProc, shaderStageInfo, + shaderStageCount, primitiveType, renderPass, layout, + fPipelineCache); } GrVkCopyPipeline* GrVkResourceProvider::findOrCreateCopyPipeline( @@ -162,7 +163,7 @@ GrVkDescriptorPool* GrVkResourceProvider::findOrCreateCompatibleDescriptorPool( return new GrVkDescriptorPool(fGpu, type, count); } -GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrTextureParams& params, +GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrSamplerParams& params, uint32_t mipLevels) { GrVkSampler* sampler = fSamplers.find(GrVkSampler::GenerateKey(params, mipLevels)); if (!sampler) { @@ -305,10 +306,10 @@ void GrVkResourceProvider::recycleStandardUniformBufferResource(const GrVkResour fAvailableUniformBufferResources.push_back(resource); } -void GrVkResourceProvider::destroyResources() { +void GrVkResourceProvider::destroyResources(bool deviceLost) { // release our active command buffers for (int i = 0; i < fActiveCommandBuffers.count(); ++i) { - SkASSERT(fActiveCommandBuffers[i]->finished(fGpu)); + SkASSERT(deviceLost || fActiveCommandBuffers[i]->finished(fGpu)); SkASSERT(fActiveCommandBuffers[i]->unique()); fActiveCommandBuffers[i]->reset(fGpu); fActiveCommandBuffers[i]->unref(fGpu); @@ -316,7 +317,7 @@ void GrVkResourceProvider::destroyResources() { fActiveCommandBuffers.reset(); // release our available command buffers for (int i = 0; i < fAvailableCommandBuffers.count(); ++i) { - SkASSERT(fAvailableCommandBuffers[i]->finished(fGpu)); + SkASSERT(deviceLost || fAvailableCommandBuffers[i]->finished(fGpu)); SkASSERT(fAvailableCommandBuffers[i]->unique()); fAvailableCommandBuffers[i]->unref(fGpu); } diff --git a/gfx/skia/skia/src/gpu/vk/GrVkResourceProvider.h b/gfx/skia/skia/src/gpu/vk/GrVkResourceProvider.h index 8200123e254b..903223af8cb2 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkResourceProvider.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkResourceProvider.h @@ -16,16 +16,16 @@ #include "GrVkRenderPass.h" #include "GrVkResource.h" #include "GrVkUtil.h" +#include "SkLRUCache.h" #include "SkTArray.h" #include "SkTDynamicHash.h" -#include "SkTHash.h" #include "SkTInternalLList.h" #include "vk/GrVkDefines.h" class GrPipeline; class GrPrimitiveProcessor; -class GrTextureParams; +class GrSamplerParams; class GrVkCopyPipeline; class GrVkGpu; class GrVkPipeline; @@ -44,6 +44,7 @@ public: void init(); GrVkPipeline* createPipeline(const GrPipeline& pipeline, + const GrStencilSettings& stencil, const GrPrimitiveProcessor& primProc, VkPipelineShaderStageCreateInfo* shaderStageInfo, int shaderStageCount, @@ -96,9 +97,9 @@ public: // of our cache of GrVkDescriptorPools. GrVkDescriptorPool* findOrCreateCompatibleDescriptorPool(VkDescriptorType type, uint32_t count); - // Finds or creates a compatible GrVkSampler based on the GrTextureParams. + // Finds or creates a compatible GrVkSampler based on the GrSamplerParams. // The refcount is incremented and a pointer returned. - GrVkSampler* findOrCreateCompatibleSampler(const GrTextureParams&, uint32_t mipLevels); + GrVkSampler* findOrCreateCompatibleSampler(const GrSamplerParams&, uint32_t mipLevels); sk_sp findOrCreateCompatiblePipelineState(const GrPipeline&, const GrPrimitiveProcessor&, @@ -147,7 +148,9 @@ public: // The assumption is that all queues are idle and all command buffers are finished. // For resource tracing to work properly, this should be called after unrefing all other // resource usages. - void destroyResources(); + // If deviceLost is true, then resources will not be checked to see if they've finished + // before deleting (see section 4.2.4 of the Vulkan spec). + void destroyResources(bool deviceLost); // Abandon any cached resources. To be used when the context/VkDevice is lost. // For resource tracing to work properly, this should be called after unrefing all other @@ -180,11 +183,13 @@ private: struct Entry; - void reset(); + struct DescHash { + uint32_t operator()(const GrProgramDesc& desc) const { + return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0); + } + }; - int fCount; - SkTHashTable fHashTable; - SkTInternalLList fLRUList; + SkLRUCache, DescHash> fMap; GrVkGpu* fGpu; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkSampler.cpp b/gfx/skia/skia/src/gpu/vk/GrVkSampler.cpp index 1d4e7066a6fa..39016344c7e4 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkSampler.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkSampler.cpp @@ -7,7 +7,6 @@ #include "GrVkSampler.h" -#include "GrTextureAccess.h" #include "GrVkGpu.h" static inline VkSamplerAddressMode tile_to_vk_sampler_address(SkShader::TileMode tm) { @@ -23,7 +22,7 @@ static inline VkSamplerAddressMode tile_to_vk_sampler_address(SkShader::TileMode return gWrapModes[tm]; } -GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrTextureParams& params, +GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrSamplerParams& params, uint32_t mipLevels) { static VkFilter vkMinFilterModes[] = { VK_FILTER_NEAREST, @@ -58,7 +57,7 @@ GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrTextureParams& para // level mip). If the filters weren't the same we could set min = 0 and max = 0.25 to force // the minFilter on mip level 0. createInfo.minLod = 0.0f; - bool useMipMaps = GrTextureParams::kMipMap_FilterMode == params.filterMode() && mipLevels > 1; + bool useMipMaps = GrSamplerParams::kMipMap_FilterMode == params.filterMode() && mipLevels > 1; createInfo.maxLod = !useMipMaps ? 0.0f : (float)(mipLevels); createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; createInfo.unnormalizedCoordinates = VK_FALSE; @@ -77,7 +76,7 @@ void GrVkSampler::freeGPUData(const GrVkGpu* gpu) const { GR_VK_CALL(gpu->vkInterface(), DestroySampler(gpu->device(), fSampler, nullptr)); } -uint16_t GrVkSampler::GenerateKey(const GrTextureParams& params, uint32_t mipLevels) { +uint16_t GrVkSampler::GenerateKey(const GrSamplerParams& params, uint32_t mipLevels) { const int kTileModeXShift = 2; const int kTileModeYShift = 4; const int kMipLevelShift = 6; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkSampler.h b/gfx/skia/skia/src/gpu/vk/GrVkSampler.h index c0f60e4217ce..963060239fb5 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkSampler.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkSampler.h @@ -12,19 +12,18 @@ #include "vk/GrVkDefines.h" -class GrTextureAccess; -class GrTextureParams; +class GrSamplerParams; class GrVkGpu; class GrVkSampler : public GrVkResource { public: - static GrVkSampler* Create(const GrVkGpu* gpu, const GrTextureParams&, uint32_t mipLevels); + static GrVkSampler* Create(const GrVkGpu* gpu, const GrSamplerParams&, uint32_t mipLevels); VkSampler sampler() const { return fSampler; } // Helpers for hashing GrVkSampler - static uint16_t GenerateKey(const GrTextureParams&, uint32_t mipLevels); + static uint16_t GenerateKey(const GrSamplerParams&, uint32_t mipLevels); static const uint16_t& GetKey(const GrVkSampler& sampler) { return sampler.fKey; } static uint32_t Hash(const uint16_t& key) { return key; } diff --git a/gfx/skia/skia/src/gpu/vk/GrVkSemaphore.cpp b/gfx/skia/skia/src/gpu/vk/GrVkSemaphore.cpp new file mode 100644 index 000000000000..d84635f85e99 --- /dev/null +++ b/gfx/skia/skia/src/gpu/vk/GrVkSemaphore.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrVkSemaphore.h" + +#include "GrVkGpu.h" +#include "GrVkUtil.h" + +#ifdef VK_USE_PLATFORM_WIN32_KHR +// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW +#undef CreateSemaphore +#endif + +sk_sp GrVkSemaphore::Make(const GrVkGpu* gpu) { + VkSemaphoreCreateInfo createInfo; + memset(&createInfo, 0, sizeof(VkFenceCreateInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + createInfo.pNext = nullptr; + createInfo.flags = 0; + VkSemaphore semaphore = VK_NULL_HANDLE; + GR_VK_CALL_ERRCHECK(gpu->vkInterface(), + CreateSemaphore(gpu->device(), &createInfo, nullptr, &semaphore)); + + return sk_sp(new GrVkSemaphore(gpu, semaphore)); +} + +GrVkSemaphore::GrVkSemaphore(const GrVkGpu* gpu, VkSemaphore semaphore) : INHERITED(gpu) { + fResource = new Resource(semaphore); +} + +GrVkSemaphore::~GrVkSemaphore() { + if (fGpu) { + fResource->unref(static_cast(fGpu)); + } else { + fResource->unrefAndAbandon(); + } +} + +void GrVkSemaphore::Resource::freeGPUData(const GrVkGpu* gpu) const { + GR_VK_CALL(gpu->vkInterface(), + DestroySemaphore(gpu->device(), fSemaphore, nullptr)); +} + diff --git a/gfx/skia/skia/src/gpu/vk/GrVkSemaphore.h b/gfx/skia/skia/src/gpu/vk/GrVkSemaphore.h new file mode 100644 index 000000000000..0a3bc1742b91 --- /dev/null +++ b/gfx/skia/skia/src/gpu/vk/GrVkSemaphore.h @@ -0,0 +1,55 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrVkSemaphore_DEFINED +#define GrVkSemaphore_DEFINED + +#include "GrSemaphore.h" +#include "GrVkResource.h" + +#include "vk/GrVkTypes.h" + +class GrVkGpu; + +class GrVkSemaphore : public GrSemaphore { +public: + static sk_sp Make(const GrVkGpu* gpu); + + ~GrVkSemaphore() override; + + class Resource : public GrVkResource { + public: + Resource(VkSemaphore semaphore) : INHERITED(), fSemaphore(semaphore) {} + + ~Resource() override {} + + VkSemaphore semaphore() const { return fSemaphore; } + +#ifdef SK_TRACE_VK_RESOURCES + void dumpInfo() const override { + SkDebugf("GrVkSemaphore: %d (%d refs)\n", fSemaphore, this->getRefCnt()); + } +#endif + private: + void freeGPUData(const GrVkGpu* gpu) const override; + + VkSemaphore fSemaphore; + + typedef GrVkResource INHERITED; + }; + + const Resource* getResource() const { return fResource; } + +private: + GrVkSemaphore(const GrVkGpu* gpu, VkSemaphore semaphore); + + const Resource* fResource; + + typedef GrSemaphore INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/vk/GrVkTexture.cpp b/gfx/skia/skia/src/gpu/vk/GrVkTexture.cpp index bf399a8352f5..fb6b94fbc953 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkTexture.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkTexture.cpp @@ -24,7 +24,8 @@ GrVkTexture::GrVkTexture(GrVkGpu* gpu, const GrVkImageView* view) : GrSurface(gpu, desc) , GrVkImage(info, GrVkImage::kNot_Wrapped) - , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, desc.fIsMipMapped) + , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, GrSamplerParams::kMipMap_FilterMode, + desc.fIsMipMapped) , fTextureView(view) , fLinearTextureView(nullptr) { this->registerWithCache(budgeted); @@ -38,7 +39,8 @@ GrVkTexture::GrVkTexture(GrVkGpu* gpu, GrVkImage::Wrapped wrapped) : GrSurface(gpu, desc) , GrVkImage(info, wrapped) - , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, desc.fIsMipMapped) + , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, GrSamplerParams::kMipMap_FilterMode, + desc.fIsMipMapped) , fTextureView(view) , fLinearTextureView(nullptr) { this->registerWithCacheWrapped(); @@ -52,7 +54,8 @@ GrVkTexture::GrVkTexture(GrVkGpu* gpu, GrVkImage::Wrapped wrapped) : GrSurface(gpu, desc) , GrVkImage(info, wrapped) - , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, desc.fIsMipMapped) + , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, GrSamplerParams::kMipMap_FilterMode, + desc.fIsMipMapped) , fTextureView(view) , fLinearTextureView(nullptr) { } @@ -78,10 +81,10 @@ GrVkTexture* GrVkTexture::CreateNewTexture(GrVkGpu* gpu, SkBudgeted budgeted, return new GrVkTexture(gpu, budgeted, desc, info, imageView); } -GrVkTexture* GrVkTexture::CreateWrappedTexture(GrVkGpu* gpu, - const GrSurfaceDesc& desc, - GrWrapOwnership ownership, - const GrVkImageInfo* info) { +sk_sp GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu, + const GrSurfaceDesc& desc, + GrWrapOwnership ownership, + const GrVkImageInfo* info) { SkASSERT(info); // Wrapped textures require both image and allocation (because they can be mapped) SkASSERT(VK_NULL_HANDLE != info->fImage && VK_NULL_HANDLE != info->fAlloc.fMemory); @@ -93,10 +96,13 @@ GrVkTexture* GrVkTexture::CreateWrappedTexture(GrVkGpu* gpu, return nullptr; } - GrVkImage::Wrapped wrapped = kBorrow_GrWrapOwnership == ownership ? GrVkImage::kBorrowed_Wrapped - : GrVkImage::kAdopted_Wrapped; - - return new GrVkTexture(gpu, kWrapped, desc, *info, imageView, wrapped); + if (kAdoptAndCache_GrWrapOwnership == ownership) { + return sk_sp(new GrVkTexture(gpu, SkBudgeted::kYes, desc, *info, imageView)); + } else { + GrVkImage::Wrapped wrapped = kBorrow_GrWrapOwnership == ownership + ? GrVkImage::kBorrowed_Wrapped : GrVkImage::kAdopted_Wrapped; + return sk_sp(new GrVkTexture(gpu, kWrapped, desc, *info, imageView, wrapped)); + } } GrVkTexture::~GrVkTexture() { @@ -141,6 +147,12 @@ GrBackendObject GrVkTexture::getTextureHandle() const { return (GrBackendObject)&fInfo; } +std::unique_ptr GrVkTexture::detachBackendTexture() { + // Not supported on Vulkan yet + // TODO: Add thread-safe memory pools, and implement this. + return nullptr; +} + GrVkGpu* GrVkTexture::getVkGpu() const { SkASSERT(!this->wasDestroyed()); return static_cast(this->getGpu()); diff --git a/gfx/skia/skia/src/gpu/vk/GrVkTexture.h b/gfx/skia/skia/src/gpu/vk/GrVkTexture.h index 06d147584a35..db7124e2b809 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkTexture.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkTexture.h @@ -21,8 +21,8 @@ public: static GrVkTexture* CreateNewTexture(GrVkGpu*, SkBudgeted budgeted, const GrSurfaceDesc&, const GrVkImage::ImageDesc&); - static GrVkTexture* CreateWrappedTexture(GrVkGpu*, const GrSurfaceDesc&, - GrWrapOwnership, const GrVkImageInfo*); + static sk_sp MakeWrappedTexture(GrVkGpu*, const GrSurfaceDesc&, + GrWrapOwnership, const GrVkImageInfo*); ~GrVkTexture() override; @@ -42,6 +42,7 @@ protected: void onAbandon() override; void onRelease() override; + std::unique_ptr detachBackendTexture() override; private: enum Wrapped { kWrapped }; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkTextureRenderTarget.cpp b/gfx/skia/skia/src/gpu/vk/GrVkTextureRenderTarget.cpp index 37b68af82761..1d7d75683f33 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkTextureRenderTarget.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkTextureRenderTarget.cpp @@ -135,21 +135,20 @@ GrVkTextureRenderTarget::CreateNewTextureRenderTarget(GrVkGpu* gpu, return trt; } -GrVkTextureRenderTarget* -GrVkTextureRenderTarget::CreateWrappedTextureRenderTarget(GrVkGpu* gpu, - const GrSurfaceDesc& desc, - GrWrapOwnership ownership, - const GrVkImageInfo* info) { +sk_sp +GrVkTextureRenderTarget::MakeWrappedTextureRenderTarget(GrVkGpu* gpu, + const GrSurfaceDesc& desc, + GrWrapOwnership ownership, + const GrVkImageInfo* info) { SkASSERT(info); // Wrapped textures require both image and allocation (because they can be mapped) SkASSERT(VK_NULL_HANDLE != info->fImage && VK_NULL_HANDLE != info->fAlloc.fMemory); + SkASSERT(kAdoptAndCache_GrWrapOwnership != ownership); // Not supported GrVkImage::Wrapped wrapped = kBorrow_GrWrapOwnership == ownership ? GrVkImage::kBorrowed_Wrapped : GrVkImage::kAdopted_Wrapped; - GrVkTextureRenderTarget* trt = Create(gpu, desc, *info, SkBudgeted::kNo, wrapped); - - return trt; + return sk_sp(Create(gpu, desc, *info, SkBudgeted::kNo, wrapped)); } bool GrVkTextureRenderTarget::updateForMipmap(GrVkGpu* gpu, const GrVkImageInfo& newInfo) { diff --git a/gfx/skia/skia/src/gpu/vk/GrVkTextureRenderTarget.h b/gfx/skia/skia/src/gpu/vk/GrVkTextureRenderTarget.h index 225951106612..2877a3626556 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkTextureRenderTarget.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkTextureRenderTarget.h @@ -13,6 +13,8 @@ #include "GrVkRenderTarget.h" #include "GrVkGpu.h" +#include "GrTexturePriv.h" + #ifdef SK_BUILD_FOR_WIN // Windows gives bogus warnings about inheriting asTexture/asRenderTarget via dominance. #pragma warning(push) @@ -28,10 +30,10 @@ public: const GrSurfaceDesc&, const GrVkImage::ImageDesc&); - static GrVkTextureRenderTarget* CreateWrappedTextureRenderTarget(GrVkGpu*, - const GrSurfaceDesc&, - GrWrapOwnership, - const GrVkImageInfo*); + static sk_sp MakeWrappedTextureRenderTarget(GrVkGpu*, + const GrSurfaceDesc&, + GrWrapOwnership, + const GrVkImageInfo*); bool updateForMipmap(GrVkGpu* gpu, const GrVkImageInfo& newInfo); @@ -112,7 +114,9 @@ private: // GrGLRenderTarget accounts for the texture's memory and any MSAA renderbuffer's memory. size_t onGpuMemorySize() const override { - return GrVkRenderTarget::onGpuMemorySize(); + // The plus 1 is to account for the resolve texture. + return GrSurface::ComputeSize(fDesc, fDesc.fSampleCnt+1, // TODO: this still correct? + this->texturePriv().hasMipMaps()); } }; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkUniformHandler.cpp b/gfx/skia/skia/src/gpu/vk/GrVkUniformHandler.cpp index 4a6e977a8c3d..f69c9d16f9e5 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkUniformHandler.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkUniformHandler.cpp @@ -15,91 +15,97 @@ // the std140 alignment, you can use this, but then make sure if you have an array type it is // aligned to 16 bytes (i.e. has mask of 0xF). uint32_t grsltype_to_alignment_mask(GrSLType type) { - SkASSERT(GrSLTypeIsFloatType(type)); - static const uint32_t kAlignmentMask[] = { - 0x0, // kVoid_GrSLType, should never return this - 0x3, // kFloat_GrSLType - 0x7, // kVec2f_GrSLType - 0xF, // kVec3f_GrSLType - 0xF, // kVec4f_GrSLType - 0x7, // kMat22f_GrSLType - 0xF, // kMat33f_GrSLType - 0xF, // kMat44f_GrSLType - 0x0, // Sampler2D_GrSLType, should never return this - 0x0, // SamplerExternal_GrSLType, should never return this - 0x0, // Sampler2DRect_GrSLType, should never return this - 0x0, // SamplerBuffer_GrSLType, should never return this - 0x0, // kBool_GrSLType - 0x7, // kInt_GrSLType - 0x7, // kUint_GrSLType - 0x0, // Texture2D_GrSLType, should never return this - 0x0, // Sampler_GrSLType, should never return this - }; - GR_STATIC_ASSERT(0 == kVoid_GrSLType); - GR_STATIC_ASSERT(1 == kFloat_GrSLType); - GR_STATIC_ASSERT(2 == kVec2f_GrSLType); - GR_STATIC_ASSERT(3 == kVec3f_GrSLType); - GR_STATIC_ASSERT(4 == kVec4f_GrSLType); - GR_STATIC_ASSERT(5 == kMat22f_GrSLType); - GR_STATIC_ASSERT(6 == kMat33f_GrSLType); - GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); - GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); - GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); - GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); - GR_STATIC_ASSERT(12 == kBool_GrSLType); - GR_STATIC_ASSERT(13 == kInt_GrSLType); - GR_STATIC_ASSERT(14 == kUint_GrSLType); - GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); - GR_STATIC_ASSERT(16 == kSampler_GrSLType); - GR_STATIC_ASSERT(SK_ARRAY_COUNT(kAlignmentMask) == kGrSLTypeCount); - return kAlignmentMask[type]; + switch(type) { + case kInt_GrSLType: + return 0x3; + case kUint_GrSLType: + return 0x3; + case kFloat_GrSLType: + return 0x3; + case kVec2f_GrSLType: + return 0x7; + case kVec3f_GrSLType: + return 0xF; + case kVec4f_GrSLType: + return 0xF; + case kVec2i_GrSLType: + return 0x7; + case kVec3i_GrSLType: + return 0xF; + case kVec4i_GrSLType: + return 0xF; + case kMat22f_GrSLType: + return 0x7; + case kMat33f_GrSLType: + return 0xF; + case kMat44f_GrSLType: + return 0xF; + + // This query is only valid for certain types. + case kVoid_GrSLType: + case kBool_GrSLType: + case kTexture2DSampler_GrSLType: + case kITexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + case kBufferSampler_GrSLType: + case kTexture2D_GrSLType: + case kSampler_GrSLType: + case kImageStorage2D_GrSLType: + case kIImageStorage2D_GrSLType: + break; + } + SkFAIL("Unexpected type"); + return 0; } /** Returns the size in bytes taken up in vulkanbuffers for floating point GrSLTypes. For non floating point type returns 0. Currently this reflects the std140 alignment so a mat22 takes up 8 floats. */ static inline uint32_t grsltype_to_vk_size(GrSLType type) { - SkASSERT(GrSLTypeIsFloatType(type)); - static const uint32_t kSizes[] = { - 0, // kVoid_GrSLType - sizeof(float), // kFloat_GrSLType - 2 * sizeof(float), // kVec2f_GrSLType - 3 * sizeof(float), // kVec3f_GrSLType - 4 * sizeof(float), // kVec4f_GrSLType - 8 * sizeof(float), // kMat22f_GrSLType. TODO: this will be 4 * szof(float) on std430. - 12 * sizeof(float), // kMat33f_GrSLType - 16 * sizeof(float), // kMat44f_GrSLType - 0, // kTexture2DSampler_GrSLType - 0, // kTextureExternalSampler_GrSLType - 0, // kTexture2DRectSampler_GrSLType - 0, // kTextureBufferSampler_GrSLType - 1, // kBool_GrSLType - 4, // kInt_GrSLType - 4, // kUint_GrSLType - 0, // kTexture2D_GrSLType - 0, // kSampler_GrSLType - }; - return kSizes[type]; + switch(type) { + case kInt_GrSLType: + return sizeof(int32_t); + case kUint_GrSLType: + return sizeof(int32_t); + case kFloat_GrSLType: + return sizeof(float); + case kVec2f_GrSLType: + return 2 * sizeof(float); + case kVec3f_GrSLType: + return 3 * sizeof(float); + case kVec4f_GrSLType: + return 4 * sizeof(float); + case kVec2i_GrSLType: + return 2 * sizeof(int32_t); + case kVec3i_GrSLType: + return 3 * sizeof(int32_t); + case kVec4i_GrSLType: + return 4 * sizeof(int32_t); + case kMat22f_GrSLType: + //TODO: this will be 4 * szof(float) on std430. + return 8 * sizeof(float); + case kMat33f_GrSLType: + return 12 * sizeof(float); + case kMat44f_GrSLType: + return 16 * sizeof(float); - GR_STATIC_ASSERT(0 == kVoid_GrSLType); - GR_STATIC_ASSERT(1 == kFloat_GrSLType); - GR_STATIC_ASSERT(2 == kVec2f_GrSLType); - GR_STATIC_ASSERT(3 == kVec3f_GrSLType); - GR_STATIC_ASSERT(4 == kVec4f_GrSLType); - GR_STATIC_ASSERT(5 == kMat22f_GrSLType); - GR_STATIC_ASSERT(6 == kMat33f_GrSLType); - GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); - GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); - GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); - GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); - GR_STATIC_ASSERT(12 == kBool_GrSLType); - GR_STATIC_ASSERT(13 == kInt_GrSLType); - GR_STATIC_ASSERT(14 == kUint_GrSLType); - GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); - GR_STATIC_ASSERT(16 == kSampler_GrSLType); - GR_STATIC_ASSERT(SK_ARRAY_COUNT(kSizes) == kGrSLTypeCount); + // This query is only valid for certain types. + case kVoid_GrSLType: + case kBool_GrSLType: + case kTexture2DSampler_GrSLType: + case kITexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + case kBufferSampler_GrSLType: + case kTexture2D_GrSLType: + case kSampler_GrSLType: + case kImageStorage2D_GrSLType: + case kIImageStorage2D_GrSLType: + break; + } + SkFAIL("Unexpected type"); + return 0; } @@ -165,12 +171,16 @@ GrGLSLUniformHandler::UniformHandle GrVkUniformHandler::internalAddUniformArray( uni.fVariable.setPrecision(precision); // When outputing the GLSL, only the outer uniform block will get the Uniform modifier. Thus // we set the modifier to none for all uniforms declared inside the block. - uni.fVariable.setTypeModifier(GrGLSLShaderVar::kNone_TypeModifier); + uni.fVariable.setTypeModifier(GrShaderVar::kNone_TypeModifier); uint32_t* currentOffset = kVertex_GrShaderFlag == visibility ? &fCurrentVertexUBOOffset - : &fCurrentFragmentUBOOffset; + : &fCurrentFragmentUBOOffset; get_ubo_aligned_offset(&uni.fUBOffset, currentOffset, type, arrayCount); + SkString layoutQualifier; + layoutQualifier.appendf("offset=%d", uni.fUBOffset); + uni.fVariable.addLayoutQualifier(layoutQualifier.c_str()); + if (outName) { *outName = uni.fVariable.c_str(); } @@ -178,11 +188,11 @@ GrGLSLUniformHandler::UniformHandle GrVkUniformHandler::internalAddUniformArray( return GrGLSLUniformHandler::UniformHandle(fUniforms.count() - 1); } -GrGLSLUniformHandler::SamplerHandle GrVkUniformHandler::internalAddSampler(uint32_t visibility, - GrPixelConfig config, - GrSLType type, - GrSLPrecision precision, - const char* name) { +GrGLSLUniformHandler::SamplerHandle GrVkUniformHandler::addSampler(uint32_t visibility, + GrSwizzle swizzle, + GrSLType type, + GrSLPrecision precision, + const char* name) { SkASSERT(name && strlen(name)); SkDEBUGCODE(static const uint32_t kVisMask = kVertex_GrShaderFlag | kFragment_GrShaderFlag); SkASSERT(0 == (~kVisMask & visibility)); @@ -190,8 +200,20 @@ GrGLSLUniformHandler::SamplerHandle GrVkUniformHandler::internalAddSampler(uint3 SkString mangleName; char prefix = 'u'; fProgramBuilder->nameVariable(&mangleName, prefix, name, true); - fSamplers.emplace_back(visibility, config, type, precision, mangleName.c_str(), - (uint32_t)fSamplers.count(), kSamplerDescSet); + + UniformInfo& info = fSamplers.push_back(); + SkASSERT(GrSLTypeIsCombinedSamplerType(type)); + info.fVariable.setType(type); + info.fVariable.setTypeModifier(GrShaderVar::kUniform_TypeModifier); + info.fVariable.setPrecision(precision); + info.fVariable.setName(mangleName); + SkString layoutQualifier; + layoutQualifier.appendf("set=%d, binding=%d", kSamplerDescSet, fSamplers.count() - 1); + info.fVariable.addLayoutQualifier(layoutQualifier.c_str()); + info.fVisibility = visibility; + info.fUBOffset = 0; + fSamplerSwizzles.push_back(swizzle); + SkASSERT(fSamplerSwizzles.count() == fSamplers.count()); return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1); } @@ -199,20 +221,29 @@ void GrVkUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* SkASSERT(kVertex_GrShaderFlag == visibility || kFragment_GrShaderFlag == visibility); for (int i = 0; i < fSamplers.count(); ++i) { - const GrVkGLSLSampler& sampler = fSamplers[i]; - SkASSERT(sampler.type() == kTexture2DSampler_GrSLType); - if (visibility == sampler.visibility()) { - sampler.fShaderVar.appendDecl(fProgramBuilder->glslCaps(), out); + const UniformInfo& sampler = fSamplers[i]; + SkASSERT(sampler.fVariable.getType() == kTexture2DSampler_GrSLType); + if (visibility == sampler.fVisibility) { + sampler.fVariable.appendDecl(fProgramBuilder->shaderCaps(), out); out->append(";\n"); } } + SkDEBUGCODE(bool firstOffsetCheck = false); SkString uniformsString; for (int i = 0; i < fUniforms.count(); ++i) { const UniformInfo& localUniform = fUniforms[i]; if (visibility == localUniform.fVisibility) { if (GrSLTypeIsFloatType(localUniform.fVariable.getType())) { - localUniform.fVariable.appendDecl(fProgramBuilder->glslCaps(), &uniformsString); +#ifdef SK_DEBUG + if (!firstOffsetCheck) { + // Check to make sure we are starting our offset at 0 so the offset qualifier we + // set on each variable in the uniform block is valid. + SkASSERT(0 == localUniform.fUBOffset); + firstOffsetCheck = true; + } +#endif + localUniform.fVariable.appendDecl(fProgramBuilder->shaderCaps(), &uniformsString); uniformsString.append(";\n"); } } diff --git a/gfx/skia/skia/src/gpu/vk/GrVkUniformHandler.h b/gfx/skia/skia/src/gpu/vk/GrVkUniformHandler.h index a6ea936737bf..808eed7fb346 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkUniformHandler.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkUniformHandler.h @@ -8,11 +8,9 @@ #ifndef GrVkUniformHandler_DEFINED #define GrVkUniformHandler_DEFINED -#include "glsl/GrGLSLUniformHandler.h" - #include "GrAllocator.h" -#include "GrVkGLSLSampler.h" -#include "glsl/GrGLSLShaderVar.h" +#include "GrShaderVar.h" +#include "glsl/GrGLSLUniformHandler.h" class GrVkUniformHandler : public GrGLSLUniformHandler { public: @@ -29,13 +27,13 @@ public: // fUBOffset is only valid if the GrSLType of the fVariable is not a sampler struct UniformInfo { - GrGLSLShaderVar fVariable; + GrShaderVar fVariable; uint32_t fVisibility; uint32_t fUBOffset; }; typedef GrTAllocator UniformInfoArray; - const GrGLSLShaderVar& getUniformVariable(UniformHandle u) const override { + const GrShaderVar& getUniformVariable(UniformHandle u) const override { return fUniforms[u.toIndex()].fVariable; } @@ -47,6 +45,7 @@ private: explicit GrVkUniformHandler(GrGLSLProgramBuilder* program) : INHERITED(program) , fUniforms(kUniformsPerBlock) + , fSamplers(kUniformsPerBlock) , fCurrentVertexUBOOffset(0) , fCurrentFragmentUBOOffset(0) , fCurrentSamplerBinding(0) { @@ -60,15 +59,34 @@ private: int arrayCount, const char** outName) override; - SamplerHandle internalAddSampler(uint32_t visibility, - GrPixelConfig config, - GrSLType type, - GrSLPrecision precision, - const char* name) override; + SamplerHandle addSampler(uint32_t visibility, + GrSwizzle swizzle, + GrSLType type, + GrSLPrecision precision, + const char* name) override; - int numSamplers() const override { return fSamplers.count(); } - const GrGLSLSampler& getSampler(SamplerHandle handle) const override { - return fSamplers[handle.toIndex()]; + int numSamplers() const { return fSamplers.count(); } + const GrShaderVar& samplerVariable(SamplerHandle handle) const override { + return fSamplers[handle.toIndex()].fVariable; + } + GrSwizzle samplerSwizzle(SamplerHandle handle) const override { + return fSamplerSwizzles[handle.toIndex()]; + } + uint32_t samplerVisibility(SamplerHandle handle) const { + return fSamplers[handle.toIndex()].fVisibility; + } + + ImageStorageHandle addImageStorage(uint32_t visibility, GrSLType, GrImageStorageFormat, + GrSLMemoryModel, GrSLRestrict, GrIOType, + const char* name) override { + SkFAIL("Image storages not implemented for Vulkan."); + return 0; + } + + const GrShaderVar& imageStorageVariable(ImageStorageHandle handle) const override { + SkFAIL("Image storages not implemented for Vulkan."); + static const GrShaderVar* gVar = nullptr; + return *gVar; } void appendUniformDecls(GrShaderFlags, SkString*) const override; @@ -82,12 +100,13 @@ private: } - UniformInfoArray fUniforms; - SkTArray fSamplers; + UniformInfoArray fUniforms; + UniformInfoArray fSamplers; + SkTArray fSamplerSwizzles; - uint32_t fCurrentVertexUBOOffset; - uint32_t fCurrentFragmentUBOOffset; - uint32_t fCurrentSamplerBinding; + uint32_t fCurrentVertexUBOOffset; + uint32_t fCurrentFragmentUBOOffset; + uint32_t fCurrentSamplerBinding; friend class GrVkPipelineStateBuilder; friend class GrVkDescriptorSetManager; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkUtil.cpp b/gfx/skia/skia/src/gpu/vk/GrVkUtil.cpp index a14f827dcb02..1fdf69cdd873 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkUtil.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkUtil.cpp @@ -8,9 +8,7 @@ #include "GrVkUtil.h" #include "vk/GrVkGpu.h" -#if USE_SKSL #include "SkSLCompiler.h" -#endif bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format) { VkFormat dontCare; @@ -19,58 +17,56 @@ bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format) { } switch (config) { + case kUnknown_GrPixelConfig: + return false; case kRGBA_8888_GrPixelConfig: *format = VK_FORMAT_R8G8B8A8_UNORM; - break; + return true; case kBGRA_8888_GrPixelConfig: *format = VK_FORMAT_B8G8R8A8_UNORM; - break; + return true; case kSRGBA_8888_GrPixelConfig: *format = VK_FORMAT_R8G8B8A8_SRGB; - break; + return true; case kSBGRA_8888_GrPixelConfig: *format = VK_FORMAT_B8G8R8A8_SRGB; - break; + return true; + case kRGBA_8888_sint_GrPixelConfig: + *format = VK_FORMAT_R8G8B8A8_SINT; + return true; case kRGB_565_GrPixelConfig: *format = VK_FORMAT_R5G6B5_UNORM_PACK16; - break; + return true; case kRGBA_4444_GrPixelConfig: // R4G4B4A4 is not required to be supported so we actually // store the data is if it was B4G4R4A4 and swizzle in shaders *format = VK_FORMAT_B4G4R4A4_UNORM_PACK16; - break; - case kIndex_8_GrPixelConfig: - // No current vulkan support for this config - return false; + return true; case kAlpha_8_GrPixelConfig: *format = VK_FORMAT_R8_UNORM; - break; + return true; + case kGray_8_GrPixelConfig: + *format = VK_FORMAT_R8_UNORM; + return true; case kETC1_GrPixelConfig: // converting to ETC2 which is a superset of ETC1 *format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; - break; - case kLATC_GrPixelConfig: - // No current vulkan support for this config - return false; - case kR11_EAC_GrPixelConfig: - *format = VK_FORMAT_EAC_R11_UNORM_BLOCK; - break; - case kASTC_12x12_GrPixelConfig: - *format = VK_FORMAT_ASTC_12x12_UNORM_BLOCK; - break; + return true; case kRGBA_float_GrPixelConfig: *format = VK_FORMAT_R32G32B32A32_SFLOAT; - break; + return true; + case kRG_float_GrPixelConfig: + *format = VK_FORMAT_R32G32_SFLOAT; + return true; case kRGBA_half_GrPixelConfig: *format = VK_FORMAT_R16G16B16A16_SFLOAT; - break; + return true; case kAlpha_half_GrPixelConfig: *format = VK_FORMAT_R16_SFLOAT; - break; - default: - return false; + return true; } - return true; + SkFAIL("Unexpected config"); + return false; } bool GrVkFormatToPixelConfig(VkFormat format, GrPixelConfig* config) { @@ -92,6 +88,9 @@ bool GrVkFormatToPixelConfig(VkFormat format, GrPixelConfig* config) { case VK_FORMAT_B8G8R8A8_SRGB: *config = kSBGRA_8888_GrPixelConfig; break; + case VK_FORMAT_R8G8B8A8_SINT: + *config = kRGBA_8888_sint_GrPixelConfig; + break; case VK_FORMAT_R5G6B5_UNORM_PACK16: *config = kRGB_565_GrPixelConfig; break; @@ -104,17 +103,14 @@ bool GrVkFormatToPixelConfig(VkFormat format, GrPixelConfig* config) { *config = kAlpha_8_GrPixelConfig; break; case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: - *config = kETC1_GrPixelConfig; - break; - case VK_FORMAT_EAC_R11_UNORM_BLOCK: - *config = kR11_EAC_GrPixelConfig; - break; - case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: - *config = kASTC_12x12_GrPixelConfig; + *config = kETC1_GrPixelConfig; // this conversion seems a bit sketchy break; case VK_FORMAT_R32G32B32A32_SFLOAT: *config = kRGBA_float_GrPixelConfig; break; + case VK_FORMAT_R32G32_SFLOAT: + *config = kRG_float_GrPixelConfig; + break; case VK_FORMAT_R16G16B16A16_SFLOAT: *config = kRGBA_half_GrPixelConfig; break; @@ -255,7 +251,6 @@ bool GrSampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits* vkSam } } -#if USE_SKSL SkSL::Program::Kind vk_shader_stage_to_skiasl_kind(VkShaderStageFlagBits stage) { if (VK_SHADER_STAGE_VERTEX_BIT == stage) { return SkSL::Program::kVertex_Kind; @@ -263,85 +258,49 @@ SkSL::Program::Kind vk_shader_stage_to_skiasl_kind(VkShaderStageFlagBits stage) SkASSERT(VK_SHADER_STAGE_FRAGMENT_BIT == stage); return SkSL::Program::kFragment_Kind; } -#else -shaderc_shader_kind vk_shader_stage_to_shaderc_kind(VkShaderStageFlagBits stage) { - if (VK_SHADER_STAGE_VERTEX_BIT == stage) { - return shaderc_glsl_vertex_shader; + +VkShaderStageFlagBits skiasl_kind_to_vk_shader_stage(SkSL::Program::Kind kind) { + if (SkSL::Program::kVertex_Kind == kind) { + return VK_SHADER_STAGE_VERTEX_BIT; } - SkASSERT(VK_SHADER_STAGE_FRAGMENT_BIT == stage); - return shaderc_glsl_fragment_shader; + SkASSERT(SkSL::Program::kFragment_Kind == kind); + return VK_SHADER_STAGE_FRAGMENT_BIT; } -#endif bool GrCompileVkShaderModule(const GrVkGpu* gpu, const char* shaderString, VkShaderStageFlagBits stage, VkShaderModule* shaderModule, - VkPipelineShaderStageCreateInfo* stageInfo) { + VkPipelineShaderStageCreateInfo* stageInfo, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs) { + std::unique_ptr program = gpu->shaderCompiler()->convertProgram( + vk_shader_stage_to_skiasl_kind(stage), + SkString(shaderString), + settings); + if (!program) { + SkDebugf("SkSL error:\n%s\n", gpu->shaderCompiler()->errorText().c_str()); + SkASSERT(false); + } + *outInputs = program->fInputs; + SkSL::String code; + if (!gpu->shaderCompiler()->toSPIRV(*program, &code)) { + SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str()); + return false; + } + VkShaderModuleCreateInfo moduleCreateInfo; memset(&moduleCreateInfo, 0, sizeof(VkShaderModuleCreateInfo)); moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleCreateInfo.pNext = nullptr; moduleCreateInfo.flags = 0; - -#if USE_SKSL - std::string code; -#else - shaderc_compilation_result_t result = nullptr; -#endif - - if (gpu->vkCaps().canUseGLSLForShaderModule()) { - moduleCreateInfo.codeSize = strlen(shaderString); - moduleCreateInfo.pCode = (const uint32_t*)shaderString; - } else { - -#if USE_SKSL - bool result = gpu->shaderCompiler()->toSPIRV(vk_shader_stage_to_skiasl_kind(stage), - std::string(shaderString), - &code); - if (!result) { - SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str()); - return false; - } - moduleCreateInfo.codeSize = code.size(); - moduleCreateInfo.pCode = (const uint32_t*)code.c_str(); -#else - shaderc_compiler_t compiler = gpu->shadercCompiler(); - - shaderc_compile_options_t options = shaderc_compile_options_initialize(); - - shaderc_shader_kind shadercStage = vk_shader_stage_to_shaderc_kind(stage); - result = shaderc_compile_into_spv(compiler, - shaderString, - strlen(shaderString), - shadercStage, - "shader", - "main", - options); - shaderc_compile_options_release(options); -#ifdef SK_DEBUG - if (shaderc_result_get_num_errors(result)) { - SkDebugf("%s\n", shaderString); - SkDebugf("%s\n", shaderc_result_get_error_message(result)); - return false; - } -#endif // SK_DEBUG - - moduleCreateInfo.codeSize = shaderc_result_get_length(result); - moduleCreateInfo.pCode = (const uint32_t*)shaderc_result_get_bytes(result); -#endif // USE_SKSL - } + moduleCreateInfo.codeSize = code.size(); + moduleCreateInfo.pCode = (const uint32_t*)code.c_str(); VkResult err = GR_VK_CALL(gpu->vkInterface(), CreateShaderModule(gpu->device(), &moduleCreateInfo, nullptr, shaderModule)); - - if (!gpu->vkCaps().canUseGLSLForShaderModule()) { -#if !USE_SKSL - shaderc_result_release(result); -#endif - } if (err) { return false; } @@ -350,7 +309,7 @@ bool GrCompileVkShaderModule(const GrVkGpu* gpu, stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stageInfo->pNext = nullptr; stageInfo->flags = 0; - stageInfo->stage = stage; + stageInfo->stage = skiasl_kind_to_vk_shader_stage(program->fKind); stageInfo->module = *shaderModule; stageInfo->pName = "main"; stageInfo->pSpecializationInfo = nullptr; diff --git a/gfx/skia/skia/src/gpu/vk/GrVkUtil.h b/gfx/skia/skia/src/gpu/vk/GrVkUtil.h index fae3c200d8a3..ba07bcad4c13 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkUtil.h +++ b/gfx/skia/skia/src/gpu/vk/GrVkUtil.h @@ -12,6 +12,7 @@ #include "GrTypes.h" #include "vk/GrVkDefines.h" #include "vk/GrVkInterface.h" +#include "ir/SkSLProgram.h" class GrVkGpu; @@ -48,6 +49,8 @@ bool GrCompileVkShaderModule(const GrVkGpu* gpu, const char* shaderString, VkShaderStageFlagBits stage, VkShaderModule* shaderModule, - VkPipelineShaderStageCreateInfo* stageInfo); + VkPipelineShaderStageCreateInfo* stageInfo, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs); #endif diff --git a/gfx/skia/skia/src/gpu/vk/GrVkVaryingHandler.cpp b/gfx/skia/skia/src/gpu/vk/GrVkVaryingHandler.cpp index f6fed2195578..d936e2bd1a40 100644 --- a/gfx/skia/skia/src/gpu/vk/GrVkVaryingHandler.cpp +++ b/gfx/skia/skia/src/gpu/vk/GrVkVaryingHandler.cpp @@ -10,54 +10,65 @@ /** Returns the number of locations take up by a given GrSLType. We assume that all scalar values are 32 bits. */ static inline int grsltype_to_location_size(GrSLType type) { - static const uint32_t kSizes[] = { - 0, // kVoid_GrSLType - 1, // kFloat_GrSLType - 1, // kVec2f_GrSLType - 1, // kVec3f_GrSLType - 1, // kVec4f_GrSLType - 2, // kMat22f_GrSLType - 3, // kMat33f_GrSLType - 4, // kMat44f_GrSLType - 0, // kTexture2DSampler_GrSLType - 0, // kTextureExternalSampler_GrSLType - 0, // kTexture2DRectSampler_GrSLType - 0, // kTextureBufferSampler_GrSLType - 1, // kBool_GrSLType - 1, // kInt_GrSLType - 1, // kUint_GrSLType - 0, // kTexture2D_GrSLType - 0, // kSampler_GrSLType - }; - return kSizes[type]; - - GR_STATIC_ASSERT(0 == kVoid_GrSLType); - GR_STATIC_ASSERT(1 == kFloat_GrSLType); - GR_STATIC_ASSERT(2 == kVec2f_GrSLType); - GR_STATIC_ASSERT(3 == kVec3f_GrSLType); - GR_STATIC_ASSERT(4 == kVec4f_GrSLType); - GR_STATIC_ASSERT(5 == kMat22f_GrSLType); - GR_STATIC_ASSERT(6 == kMat33f_GrSLType); - GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); - GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); - GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); - GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); - GR_STATIC_ASSERT(12 == kBool_GrSLType); - GR_STATIC_ASSERT(13 == kInt_GrSLType); - GR_STATIC_ASSERT(14 == kUint_GrSLType); - GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); - GR_STATIC_ASSERT(16 == kSampler_GrSLType); - GR_STATIC_ASSERT(SK_ARRAY_COUNT(kSizes) == kGrSLTypeCount); + switch(type) { + case kVoid_GrSLType: + return 0; + case kFloat_GrSLType: + return 1; + case kVec2f_GrSLType: + return 1; + case kVec3f_GrSLType: + return 1; + case kVec4f_GrSLType: + return 1; + case kVec2i_GrSLType: + return 1; + case kVec3i_GrSLType: + return 1; + case kVec4i_GrSLType: + return 1; + case kMat22f_GrSLType: + return 2; + case kMat33f_GrSLType: + return 3; + case kMat44f_GrSLType: + return 4; + case kTexture2DSampler_GrSLType: + return 0; + case kITexture2DSampler_GrSLType: + return 0; + case kTextureExternalSampler_GrSLType: + return 0; + case kTexture2DRectSampler_GrSLType: + return 0; + case kBufferSampler_GrSLType: + return 0; + case kBool_GrSLType: + return 1; + case kInt_GrSLType: + return 1; + case kUint_GrSLType: + return 1; + case kTexture2D_GrSLType: + return 0; + case kSampler_GrSLType: + return 0; + case kImageStorage2D_GrSLType: + return 0; + case kIImageStorage2D_GrSLType: + return 0; + } + SkFAIL("Unexpected type"); + return -1; } void finalize_helper(GrVkVaryingHandler::VarArray& vars) { int locationIndex = 0; for (int i = 0; i < vars.count(); ++i) { - GrGLSLShaderVar& var = vars[i]; + GrShaderVar& var = vars[i]; SkString location; location.appendf("location = %d", locationIndex); - var.setLayoutQualifier(location.c_str()); + var.addLayoutQualifier(location.c_str()); int elementSize = grsltype_to_location_size(var.getType()); SkASSERT(elementSize); diff --git a/gfx/skia/skia/src/image/SkImage.cpp b/gfx/skia/skia/src/image/SkImage.cpp index 67779ba14698..0847eb1c572d 100644 --- a/gfx/skia/skia/src/image/SkImage.cpp +++ b/gfx/skia/skia/src/image/SkImage.cpp @@ -8,6 +8,8 @@ #include "SkBitmap.h" #include "SkBitmapCache.h" #include "SkCanvas.h" +#include "SkColorSpace_Base.h" +#include "SkCrossContextImageData.h" #include "SkData.h" #include "SkImageEncoder.h" #include "SkImageFilter.h" @@ -20,8 +22,10 @@ #include "SkPicture.h" #include "SkPixelRef.h" #include "SkPixelSerializer.h" +#include "SkRGBAToYUV.h" #include "SkReadPixelsRec.h" #include "SkSpecialImage.h" +#include "SkStream.h" #include "SkString.h" #include "SkSurface.h" @@ -48,29 +52,9 @@ bool SkImage::peekPixels(SkPixmap* pm) const { return as_IB(this)->onPeekPixels(pm); } -#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS -const void* SkImage::peekPixels(SkImageInfo* info, size_t* rowBytes) const { - SkPixmap pm; - if (this->peekPixels(&pm)) { - if (info) { - *info = pm.info(); - } - if (rowBytes) { - *rowBytes = pm.rowBytes(); - } - return pm.addr(); - } - return nullptr; -} -#endif - bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint chint) const { - SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, srcX, srcY); - if (!rec.trim(this->width(), this->height())) { - return false; - } - return as_IB(this)->onReadPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, chint); + return as_IB(this)->onReadPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint); } bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingHint chint) const { @@ -82,7 +66,7 @@ bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingH // can scale more efficiently) we should take advantage of it here. // SkBitmap bm; - if (as_IB(this)->getROPixels(&bm, chint)) { + if (as_IB(this)->getROPixels(&bm, dst.info().colorSpace(), chint)) { bm.lockPixels(); SkPixmap pmap; // Note: By calling the pixmap scaler, we never cache the final result, so the chint @@ -94,60 +78,54 @@ bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingH return false; } -void SkImage::preroll(GrContext* ctx) const { - // For now, and to maintain parity w/ previous pixelref behavior, we just force the image - // to produce a cached raster-bitmap form, so that drawing to a raster canvas should be fast. - // - SkBitmap bm; - if (as_IB(this)->getROPixels(&bm)) { - bm.lockPixels(); - bm.unlockPixels(); - } -} - /////////////////////////////////////////////////////////////////////////////////////////////////// SkAlphaType SkImage::alphaType() const { return as_IB(this)->onAlphaType(); } +SkColorSpace* SkImage::colorSpace() const { + return as_IB(this)->onImageInfo().colorSpace(); +} + +sk_sp SkImage::refColorSpace() const { + return as_IB(this)->onImageInfo().refColorSpace(); +} + sk_sp SkImage::makeShader(SkShader::TileMode tileX, SkShader::TileMode tileY, const SkMatrix* localMatrix) const { return SkImageShader::Make(sk_ref_sp(const_cast(this)), tileX, tileY, localMatrix); } -#ifdef SK_SUPPORT_LEGACY_CREATESHADER_PTR -SkShader* SkImage::newShader(SkShader::TileMode tileX, SkShader::TileMode tileY, - const SkMatrix* localMatrix) const { - return this->makeShader(tileX, tileY, localMatrix).release(); -} -#endif - -SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const { +SkData* SkImage::encode(SkEncodedImageFormat type, int quality) const { SkBitmap bm; - if (as_IB(this)->getROPixels(&bm)) { - return SkImageEncoder::EncodeData(bm, type, quality); + SkColorSpace* legacyColorSpace = nullptr; + if (as_IB(this)->getROPixels(&bm, legacyColorSpace)) { + SkDynamicMemoryWStream buf; + return SkEncodeImage(&buf, bm, type, quality) ? buf.detachAsData().release() : nullptr; } return nullptr; } SkData* SkImage::encode(SkPixelSerializer* serializer) const { - SkAutoTUnref defaultSerializer; - SkPixelSerializer* effectiveSerializer = serializer; - if (!effectiveSerializer) { - defaultSerializer.reset(SkImageEncoder::CreatePixelSerializer()); - SkASSERT(defaultSerializer.get()); - effectiveSerializer = defaultSerializer.get(); - } sk_sp encoded(this->refEncoded()); - if (encoded && effectiveSerializer->useEncodedData(encoded->data(), encoded->size())) { + if (encoded && + (!serializer || serializer->useEncodedData(encoded->data(), encoded->size()))) { return encoded.release(); } SkBitmap bm; SkAutoPixmapUnlock apu; - if (as_IB(this)->getROPixels(&bm) && bm.requestLock(&apu)) { - return effectiveSerializer->encode(apu.pixmap()); + SkColorSpace* legacyColorSpace = nullptr; + if (as_IB(this)->getROPixels(&bm, legacyColorSpace) && + bm.requestLock(&apu)) { + if (serializer) { + return serializer->encode(apu.pixmap()); + } else { + SkDynamicMemoryWStream buf; + return SkEncodeImage(&buf, apu.pixmap(), SkEncodedImageFormat::kPNG, 100) + ? buf.detachAsData().release() : nullptr; + } } return nullptr; @@ -162,8 +140,7 @@ sk_sp SkImage::MakeFromEncoded(sk_sp encoded, const SkIRect* su if (nullptr == encoded || 0 == encoded->size()) { return nullptr; } - SkImageGenerator* generator = SkImageGenerator::NewFromEncoded(encoded.get()); - return SkImage::MakeFromGenerator(generator, subset); + return SkImage::MakeFromGenerator(SkImageGenerator::MakeFromEncoded(encoded), subset); } const char* SkImage::toString(SkString* str) const { @@ -192,23 +169,14 @@ sk_sp SkImage::makeSubset(const SkIRect& subset) const { #if SK_SUPPORT_GPU GrTexture* SkImage::getTexture() const { - return as_IB(this)->peekTexture(); + return as_IB(this)->onGetTexture(); } -bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->peekTexture()); } +bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->peekProxy()); } -GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO) const { - GrTexture* texture = as_IB(this)->peekTexture(); - if (texture) { - GrContext* context = texture->getContext(); - if (context) { - if (flushPendingGrContextIO) { - context->prepareSurfaceForExternalIO(texture); - } - } - return texture->getTextureHandle(); - } - return 0; +GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO, + GrSurfaceOrigin* origin) const { + return as_IB(this)->onGetTextureHandle(flushPendingGrContextIO, origin); } #else @@ -217,26 +185,12 @@ GrTexture* SkImage::getTexture() const { return nullptr; } bool SkImage::isTextureBacked() const { return false; } -GrBackendObject SkImage::getTextureHandle(bool) const { return 0; } +GrBackendObject SkImage::getTextureHandle(bool, GrSurfaceOrigin*) const { return 0; } #endif /////////////////////////////////////////////////////////////////////////////// -static bool raster_canvas_supports(const SkImageInfo& info) { - switch (info.colorType()) { - case kN32_SkColorType: - return kUnpremul_SkAlphaType != info.alphaType(); - case kRGB_565_SkColorType: - return true; - case kAlpha_8_SkColorType: - return true; - default: - break; - } - return false; -} - SkImage_Base::SkImage_Base(int width, int height, uint32_t uniqueID) : INHERITED(width, height, uniqueID) , fAddedToCache(false) @@ -248,21 +202,9 @@ SkImage_Base::~SkImage_Base() { } } -bool SkImage_Base::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, - int srcX, int srcY, CachingHint) const { - if (!raster_canvas_supports(dstInfo)) { - return false; - } - - SkBitmap bm; - bm.installPixels(dstInfo, dstPixels, dstRowBytes); - SkCanvas canvas(bm); - - SkPaint paint; - paint.setBlendMode(SkBlendMode::kSrc); - canvas.drawImage(this, -SkIntToScalar(srcX), -SkIntToScalar(srcY), &paint); - - return true; +bool SkImage_Base::onReadYUV8Planes(const SkISize sizes[3], void* const planes[3], + const size_t rowBytes[3], SkYUVColorSpace colorSpace) const { + return SkRGBAToYUV(this, sizes, planes, rowBytes, colorSpace); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -271,22 +213,9 @@ bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint c return this->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX, srcY, chint); } -#if SK_SUPPORT_GPU -#include "GrTextureToYUVPlanes.h" -#endif - -#include "SkRGBAToYUV.h" - bool SkImage::readYUV8Planes(const SkISize sizes[3], void* const planes[3], const size_t rowBytes[3], SkYUVColorSpace colorSpace) const { -#if SK_SUPPORT_GPU - if (GrTexture* texture = as_IB(this)->peekTexture()) { - if (GrTextureToYUVPlanes(texture, sizes, planes, rowBytes, colorSpace)) { - return true; - } - } -#endif - return SkRGBAToYUV(this, sizes, planes, rowBytes, colorSpace); + return as_IB(this)->onReadYUV8Planes(sizes, planes, rowBytes, colorSpace); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -307,8 +236,7 @@ bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { // As the base-class, all we can do is make a copy (regardless of mode). // Subclasses that want to be more optimal should override. - SkImageInfo info = this->onImageInfo().makeColorType(kN32_SkColorType) - .makeAlphaType(this->alphaType()); + SkImageInfo info = this->onImageInfo().makeColorType(kN32_SkColorType).makeColorSpace(nullptr); if (!bitmap->tryAllocPixels(info)) { return false; } @@ -324,12 +252,11 @@ bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) con } sk_sp SkImage::MakeFromPicture(sk_sp picture, const SkISize& dimensions, - const SkMatrix* matrix, const SkPaint* paint) { - if (!picture) { - return nullptr; - } - return MakeFromGenerator(SkImageGenerator::NewFromPicture(dimensions, picture.get(), - matrix, paint)); + const SkMatrix* matrix, const SkPaint* paint, + BitDepth bitDepth, sk_sp colorSpace) { + return MakeFromGenerator(SkImageGenerator::MakeFromPicture(dimensions, std::move(picture), + matrix, paint, bitDepth, + std::move(colorSpace))); } sk_sp SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRect& subset, @@ -338,56 +265,74 @@ sk_sp SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRec if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) { return nullptr; } + SkColorSpace* colorSpace = as_IB(this)->onImageInfo().colorSpace(); sk_sp srcSpecialImage = SkSpecialImage::MakeFromImage( - subset, sk_ref_sp(const_cast(this))); + subset, sk_ref_sp(const_cast(this)), colorSpace); if (!srcSpecialImage) { return nullptr; } - SkAutoTUnref cache( + sk_sp cache( SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize)); - SkImageFilter::OutputProperties outputProperties(as_IB(this)->onImageInfo().colorSpace()); + SkImageFilter::OutputProperties outputProperties(colorSpace); SkImageFilter::Context context(SkMatrix::I(), clipBounds, cache.get(), outputProperties); - sk_sp result = - filter->filterImage(srcSpecialImage.get(), context, offset); - + sk_sp result = filter->filterImage(srcSpecialImage.get(), context, offset); if (!result) { return nullptr; } - SkIRect fullSize = SkIRect::MakeWH(result->width(), result->height()); -#if SK_SUPPORT_GPU - if (result->isTextureBacked()) { - GrContext* context = result->getContext(); - sk_sp texture = result->asTextureRef(context); - fullSize = SkIRect::MakeWH(texture->width(), texture->height()); - } -#endif *outSubset = SkIRect::MakeWH(result->width(), result->height()); if (!outSubset->intersect(clipBounds.makeOffset(-offset->x(), -offset->y()))) { return nullptr; } offset->fX += outSubset->x(); offset->fY += outSubset->y(); - // This isn't really a "tight" subset, but includes any texture padding. - return result->makeTightSubset(fullSize); + + // Note that here we're returning the special image's entire backing store, loose padding + // and all! + return result->asImage(); } bool SkImage::isLazyGenerated() const { return as_IB(this)->onIsLazyGenerated(); } +bool SkImage::isAlphaOnly() const { + return as_IB(this)->onImageInfo().colorType() == kAlpha_8_SkColorType; +} + +sk_sp SkImage::makeColorSpace(sk_sp target, + SkTransferFunctionBehavior premulBehavior) const { + if (SkTransferFunctionBehavior::kRespect == premulBehavior) { + // TODO (msarett, brianosman): Implement this. + return nullptr; + } + + SkColorSpaceTransferFn fn; + if (!target || !target->isNumericalTransferFn(&fn)) { + return nullptr; + } + + // No need to create a new image if: + // (1) The color spaces are equal (nullptr is considered to be sRGB). + // (2) The color type is kAlpha8. + if ((!this->colorSpace() && target->isSRGB()) || + SkColorSpace::Equals(this->colorSpace(), target.get()) || + kAlpha_8_SkColorType == as_IB(this)->onImageInfo().colorType()) { + return sk_ref_sp(const_cast(this)); + } + + // TODO: We might consider making this a deferred conversion? + return as_IB(this)->onMakeColorSpace(std::move(target)); +} + ////////////////////////////////////////////////////////////////////////////////////// #if !SK_SUPPORT_GPU -sk_sp SkImage::MakeTextureFromPixmap(GrContext*, const SkPixmap&, SkBudgeted budgeted) { - return nullptr; -} - sk_sp MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMipLevel* texels, - int mipLevelCount, SkBudgeted, SkSourceGammaTreatment) { + int mipLevelCount, SkBudgeted, SkDestinationSurfaceColorMode) { return nullptr; } @@ -399,7 +344,7 @@ sk_sp SkImage::MakeFromTexture(GrContext*, const GrBackendTextureDesc&, size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy&, const DeferredTextureImageUsageParams[], int paramCnt, void* buffer, - SkSourceGammaTreatment treatment) const { + SkColorSpace* dstColorSpace) const { return 0; } @@ -421,10 +366,25 @@ sk_sp SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace return nullptr; } -sk_sp SkImage::makeTextureImage(GrContext*) const { +sk_sp SkImage::makeTextureImage(GrContext*, SkColorSpace* dstColorSpace) const { return nullptr; } +std::unique_ptr SkCrossContextImageData::MakeFromEncoded( + GrContext*, sk_sp encoded, SkColorSpace* dstColorSpace) { + sk_sp image = SkImage::MakeFromEncoded(std::move(encoded)); + if (!image) { + return nullptr; + } + // TODO: Force decode to raster here? + return std::unique_ptr(new SkCrossContextImageData(std::move(image))); +} + +sk_sp SkImage::MakeFromCrossContextImageData( + GrContext*, std::unique_ptr ccid) { + return ccid->fImage; +} + sk_sp SkImage::makeNonTextureImage() const { return sk_ref_sp(const_cast(this)); } @@ -433,66 +393,6 @@ sk_sp SkImage::makeNonTextureImage() const { /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef SK_SUPPORT_LEGACY_IMAGEFACTORY -SkImage* SkImage::NewRasterCopy(const Info& info, const void* pixels, size_t rowBytes, - SkColorTable* ctable) { - return MakeRasterCopy(SkPixmap(info, pixels, rowBytes, ctable)).release(); -} - -SkImage* SkImage::NewRasterData(const Info& info, SkData* pixels, size_t rowBytes) { - return MakeRasterData(info, sk_ref_sp(pixels), rowBytes).release(); -} - -SkImage* SkImage::NewFromRaster(const Info& info, const void* pixels, size_t rowBytes, - RasterReleaseProc proc, ReleaseContext releasectx) { - return MakeFromRaster(SkPixmap(info, pixels, rowBytes), proc, releasectx).release(); -} - -SkImage* SkImage::NewFromBitmap(const SkBitmap& bm) { - return MakeFromBitmap(bm).release(); -} - -SkImage* SkImage::NewFromGenerator(SkImageGenerator* gen, const SkIRect* subset) { - return MakeFromGenerator(gen, subset).release(); -} - -SkImage* SkImage::NewFromEncoded(SkData* encoded, const SkIRect* subset) { - return MakeFromEncoded(sk_ref_sp(encoded), subset).release(); -} - -SkImage* SkImage::NewFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc, SkAlphaType at, - TextureReleaseProc proc, ReleaseContext releasectx) { - return MakeFromTexture(ctx, desc, at, proc, releasectx).release(); -} - -SkImage* SkImage::NewFromAdoptedTexture(GrContext* ctx, const GrBackendTextureDesc& desc, - SkAlphaType at) { - return MakeFromAdoptedTexture(ctx, desc, at).release(); -} - -SkImage* SkImage::NewFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace space, - const GrBackendObject yuvTextureHandles[3], - const SkISize yuvSizes[3], - GrSurfaceOrigin origin) { - return MakeFromYUVTexturesCopy(ctx, space, yuvTextureHandles, yuvSizes, origin).release(); -} - -SkImage* SkImage::NewFromPicture(const SkPicture* picture, const SkISize& dimensions, - const SkMatrix* matrix, const SkPaint* paint) { - return MakeFromPicture(sk_ref_sp(const_cast(picture)), dimensions, - matrix, paint).release(); -} - -SkImage* SkImage::NewTextureFromPixmap(GrContext* ctx, const SkPixmap& pmap, SkBudgeted budgeted) { - return MakeTextureFromPixmap(ctx, pmap, budgeted).release(); -} - -SkImage* SkImage::NewFromDeferredTextureImageData(GrContext* ctx, const void* data, - SkBudgeted budgeted) { - return MakeFromDeferredTextureImageData(ctx, data, budgeted).release(); -} -#endif - sk_sp MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMipLevel* texels, int mipLevelCount, SkBudgeted) { return nullptr; @@ -511,10 +411,10 @@ sk_sp SkImageDeserializer::makeFromMemory(const void* data, size_t leng /////////////////////////////////////////////////////////////////////////////////////////////////// -void SkImage_pinAsTexture(const SkImage* image, GrContext* ctx) { +bool SkImage_pinAsTexture(const SkImage* image, GrContext* ctx) { SkASSERT(image); SkASSERT(ctx); - as_IB(image)->onPinAsTexture(ctx); + return as_IB(image)->onPinAsTexture(ctx); } void SkImage_unpinAsTexture(const SkImage* image, GrContext* ctx) { @@ -522,3 +422,30 @@ void SkImage_unpinAsTexture(const SkImage* image, GrContext* ctx) { SkASSERT(ctx); as_IB(image)->onUnpinAsTexture(ctx); } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +sk_sp SkImageMakeRasterCopyAndAssignColorSpace(const SkImage* src, + SkColorSpace* colorSpace) { + // Read the pixels out of the source image, with no conversion + SkImageInfo info = as_IB(src)->onImageInfo(); + if (kUnknown_SkColorType == info.colorType()) { + SkDEBUGFAIL("Unexpected color type"); + return nullptr; + } + + size_t rowBytes = info.minRowBytes(); + size_t size = info.getSafeSize(rowBytes); + auto data = SkData::MakeUninitialized(size); + if (!data) { + return nullptr; + } + + SkPixmap pm(info, data->writable_data(), rowBytes); + if (!src->readPixels(pm, 0, 0, SkImage::kDisallow_CachingHint)) { + return nullptr; + } + + // Wrap them in a new image with a different color space + return SkImage::MakeRasterData(info.makeColorSpace(sk_ref_sp(colorSpace)), data, rowBytes); +} diff --git a/gfx/skia/skia/src/image/SkImageShader.cpp b/gfx/skia/skia/src/image/SkImageShader.cpp index 8407f1008699..ce0d6f504b86 100644 --- a/gfx/skia/skia/src/image/SkImageShader.cpp +++ b/gfx/skia/skia/src/image/SkImageShader.cpp @@ -5,15 +5,18 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" +#include "SkBitmapController.h" #include "SkBitmapProcShader.h" #include "SkBitmapProvider.h" -#include "SkColorShader.h" #include "SkColorTable.h" #include "SkEmptyShader.h" #include "SkImage_Base.h" #include "SkImageShader.h" +#include "SkPM4fPriv.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" +#include "../jumper/SkJumper.h" SkImageShader::SkImageShader(sk_sp img, TileMode tmx, TileMode tmy, const SkMatrix* matrix) : INHERITED(matrix) @@ -45,13 +48,10 @@ bool SkImageShader::isOpaque() const { return fImage->isOpaque(); } -size_t SkImageShader::onContextSize(const ContextRec& rec) const { - return SkBitmapProcLegacyShader::ContextSize(rec, SkBitmapProvider(fImage.get()).info()); -} - -SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const { +SkShader::Context* SkImageShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const { return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY, - SkBitmapProvider(fImage.get()), rec, storage); + SkBitmapProvider(fImage.get(), rec.fDstColorSpace), + rec, alloc); } SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const { @@ -92,70 +92,17 @@ static bool bitmap_is_too_big(int w, int h) { // widen that, we have to reject bitmaps that are larger. // static const int kMaxSize = 65535; - + return w > kMaxSize || h > kMaxSize; } -// returns true and set color if the bitmap can be drawn as a single color -// (for efficiency) -static bool can_use_color_shader(const SkImage* image, SkColor* color) { -#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK - // HWUI does not support color shaders (see b/22390304) - return false; -#endif - - if (1 != image->width() || 1 != image->height()) { - return false; - } - - SkPixmap pmap; - if (!image->peekPixels(&pmap)) { - return false; - } - - switch (pmap.colorType()) { - case kN32_SkColorType: - *color = SkUnPreMultiply::PMColorToColor(*pmap.addr32(0, 0)); - return true; - case kRGB_565_SkColorType: - *color = SkPixel16ToColor(*pmap.addr16(0, 0)); - return true; - case kIndex_8_SkColorType: { - const SkColorTable& ctable = *pmap.ctable(); - *color = SkUnPreMultiply::PMColorToColor(ctable[*pmap.addr8(0, 0)]); - return true; - } - default: // just skip the other configs for now - break; - } - return false; -} - sk_sp SkImageShader::Make(sk_sp image, TileMode tx, TileMode ty, - const SkMatrix* localMatrix, - SkTBlitterAllocator* allocator) { - SkShader* shader; - SkColor color; + const SkMatrix* localMatrix) { if (!image || bitmap_is_too_big(image->width(), image->height())) { - if (nullptr == allocator) { - shader = new SkEmptyShader; - } else { - shader = allocator->createT(); - } - } else if (can_use_color_shader(image.get(), &color)) { - if (nullptr == allocator) { - shader = new SkColorShader(color); - } else { - shader = allocator->createT(color); - } + return sk_make_sp(); } else { - if (nullptr == allocator) { - shader = new SkImageShader(image, tx, ty, localMatrix); - } else { - shader = allocator->createT(image, tx, ty, localMatrix); - } + return sk_make_sp(image, tx, ty, localMatrix); } - return sk_sp(shader); } #ifndef SK_IGNORE_TO_STRING @@ -175,16 +122,13 @@ void SkImageShader::toString(SkString* str) const { #if SK_SUPPORT_GPU -#include "GrTextureAccess.h" #include "SkGr.h" -#include "SkGrPriv.h" +#include "GrContext.h" #include "effects/GrSimpleTextureEffect.h" #include "effects/GrBicubicEffect.h" #include "effects/GrSimpleTextureEffect.h" sk_sp SkImageShader::asFragmentProcessor(const AsFPArgs& args) const { - SkMatrix matrix; - matrix.setIDiv(fImage->width(), fImage->height()); SkMatrix lmInverse; if (!this->getLocalMatrix().invert(&lmInverse)) { @@ -197,7 +141,6 @@ sk_sp SkImageShader::asFragmentProcessor(const AsFPArgs& ar } lmInverse.postConcat(inv); } - matrix.preConcat(lmInverse); SkShader::TileMode tm[] = { fTileModeX, fTileModeY }; @@ -206,27 +149,35 @@ sk_sp SkImageShader::asFragmentProcessor(const AsFPArgs& ar // This completely ignores the complexity of the drawVertices case where explicit local coords // are provided by the caller. bool doBicubic; - GrTextureParams::FilterMode textureFilterMode = + GrSamplerParams::FilterMode textureFilterMode = GrSkFilterQualityToGrFilterMode(args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(), &doBicubic); - GrTextureParams params(tm, textureFilterMode); - SkAutoTUnref texture(as_IB(fImage)->asTextureRef(args.fContext, params, - args.fGammaTreatment)); - if (!texture) { + GrSamplerParams params(tm, textureFilterMode); + sk_sp texColorSpace; + SkScalar scaleAdjust[2] = { 1.0f, 1.0f }; + sk_sp proxy(as_IB(fImage)->asTextureProxyRef(args.fContext, params, + args.fDstColorSpace, + &texColorSpace, scaleAdjust)); + if (!proxy) { return nullptr; } - SkImageInfo info = as_IB(fImage)->onImageInfo(); - sk_sp colorSpaceXform = GrColorSpaceXform::Make(info.colorSpace(), + bool isAlphaOnly = GrPixelConfigIsAlphaOnly(proxy->config()); + + lmInverse.postScale(scaleAdjust[0], scaleAdjust[1]); + + sk_sp colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(), args.fDstColorSpace); sk_sp inner; if (doBicubic) { - inner = GrBicubicEffect::Make(texture, std::move(colorSpaceXform), matrix, tm); + inner = GrBicubicEffect::Make(args.fContext->resourceProvider(), std::move(proxy), + std::move(colorSpaceXform), lmInverse, tm); } else { - inner = GrSimpleTextureEffect::Make(texture, std::move(colorSpaceXform), matrix, params); + inner = GrSimpleTextureEffect::Make(args.fContext->resourceProvider(), std::move(proxy), + std::move(colorSpaceXform), lmInverse, params); } - if (GrPixelConfigIsAlphaOnly(texture->config())) { + if (isAlphaOnly) { return inner; } return sk_sp(GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner))); @@ -239,15 +190,9 @@ sk_sp SkImageShader::asFragmentProcessor(const AsFPArgs& ar sk_sp SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, SkShader::TileMode tmy, const SkMatrix* localMatrix, - SkCopyPixelsMode cpm, SkTBlitterAllocator* allocator) { - // Until we learn otherwise, it seems that any caller that is passing an allocator must be - // assuming that the returned shader will have a stack-frame lifetime, so we assert that - // they are also asking for kNever_SkCopyPixelsMode. If that proves otherwise, we can remove - // or modify this assert. - SkASSERT(!allocator || (kNever_SkCopyPixelsMode == cpm)); - - return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm, allocator), - tmx, tmy, localMatrix, allocator); + SkCopyPixelsMode cpm) { + return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm), + tmx, tmy, localMatrix); } static sk_sp SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) { @@ -264,3 +209,173 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader) SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShader_Type); SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END + +bool SkImageShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* dst, SkArenaAlloc* scratch, + const SkMatrix& ctm, const SkPaint& paint, + const SkMatrix* localM) const { + auto matrix = SkMatrix::Concat(ctm, this->getLocalMatrix()); + if (localM) { + matrix.preConcat(*localM); + } + + if (!matrix.invert(&matrix)) { + return false; + } + auto quality = paint.getFilterQuality(); + + SkBitmapProvider provider(fImage.get(), dst); + SkDefaultBitmapController controller(SkDefaultBitmapController::CanShadeHQ::kYes); + std::unique_ptr state { + controller.requestBitmap(provider, matrix, quality) + }; + if (!state) { + return false; + } + + const SkPixmap& pm = state->pixmap(); + matrix = state->invMatrix(); + quality = state->quality(); + auto info = pm.info(); + + // When the matrix is just an integer translate, bilerp == nearest neighbor. + if (quality == kLow_SkFilterQuality && + matrix.getType() <= SkMatrix::kTranslate_Mask && + matrix.getTranslateX() == (int)matrix.getTranslateX() && + matrix.getTranslateY() == (int)matrix.getTranslateY()) { + quality = kNone_SkFilterQuality; + } + + // See skia:4649 and the GM image_scale_aligned. + if (quality == kNone_SkFilterQuality) { + if (matrix.getScaleX() >= 0) { + matrix.setTranslateX(nextafterf(matrix.getTranslateX(), + floorf(matrix.getTranslateX()))); + } + if (matrix.getScaleY() >= 0) { + matrix.setTranslateY(nextafterf(matrix.getTranslateY(), + floorf(matrix.getTranslateY()))); + } + } + + + struct MiscCtx { + std::unique_ptr state; + SkColor4f paint_color; + float width; + float height; + float matrix[9]; + }; + auto misc = scratch->make(); + misc->state = std::move(state); // Extend lifetime to match the pipeline's. + misc->paint_color = SkColor4f_from_SkColor(paint.getColor(), dst); + misc->width = (float)pm.width(); + misc->height = (float)pm.height(); + if (matrix.asAffine(misc->matrix)) { + p->append(SkRasterPipeline::matrix_2x3, misc->matrix); + } else { + matrix.get9(misc->matrix); + p->append(SkRasterPipeline::matrix_perspective, misc->matrix); + } + + auto gather = scratch->make(); + gather->pixels = pm.addr(); + gather->ctable = pm.ctable() ? pm.ctable()->readColors() : nullptr; + gather->stride = pm.rowBytesAsPixels(); + + auto append_tiling_and_gather = [&] { + switch (fTileModeX) { + case kClamp_TileMode: p->append(SkRasterPipeline::clamp_x, &misc->width); break; + case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, &misc->width); break; + case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, &misc->width); break; + } + switch (fTileModeY) { + case kClamp_TileMode: p->append(SkRasterPipeline::clamp_y, &misc->height); break; + case kMirror_TileMode: p->append(SkRasterPipeline::mirror_y, &misc->height); break; + case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, &misc->height); break; + } + switch (info.colorType()) { + case kAlpha_8_SkColorType: p->append(SkRasterPipeline::gather_a8, gather); break; + case kIndex_8_SkColorType: p->append(SkRasterPipeline::gather_i8, gather); break; + case kGray_8_SkColorType: p->append(SkRasterPipeline::gather_g8, gather); break; + case kRGB_565_SkColorType: p->append(SkRasterPipeline::gather_565, gather); break; + case kARGB_4444_SkColorType: p->append(SkRasterPipeline::gather_4444, gather); break; + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: p->append(SkRasterPipeline::gather_8888, gather); break; + case kRGBA_F16_SkColorType: p->append(SkRasterPipeline::gather_f16, gather); break; + default: SkASSERT(false); + } + if (info.gammaCloseToSRGB() && dst != nullptr) { + p->append_from_srgb(info.alphaType()); + } + }; + + SkJumper_SamplerCtx* sampler = nullptr; + if (quality != kNone_SkFilterQuality) { + sampler = scratch->make(); + } + + auto sample = [&](SkRasterPipeline::StockStage setup_x, + SkRasterPipeline::StockStage setup_y) { + p->append(setup_x, sampler); + p->append(setup_y, sampler); + append_tiling_and_gather(); + p->append(SkRasterPipeline::accumulate, sampler); + }; + + if (quality == kNone_SkFilterQuality) { + append_tiling_and_gather(); + } else if (quality == kLow_SkFilterQuality) { + p->append(SkRasterPipeline::save_xy, sampler); + + sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_ny); + sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_ny); + sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_py); + sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_py); + + p->append(SkRasterPipeline::move_dst_src); + } else { + p->append(SkRasterPipeline::save_xy, sampler); + + sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n3y); + sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n3y); + sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n3y); + sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n3y); + + sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n1y); + sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n1y); + sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n1y); + sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n1y); + + sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p1y); + sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p1y); + sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p1y); + sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p1y); + + sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p3y); + sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p3y); + sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p3y); + sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p3y); + + p->append(SkRasterPipeline::move_dst_src); + } + + auto effective_color_type = [](SkColorType ct) { + return ct == kIndex_8_SkColorType ? kN32_SkColorType : ct; + }; + + if (effective_color_type(info.colorType()) == kBGRA_8888_SkColorType) { + p->append(SkRasterPipeline::swap_rb); + } + if (info.colorType() == kAlpha_8_SkColorType) { + p->append(SkRasterPipeline::set_rgb, &misc->paint_color); + } + if (info.colorType() == kAlpha_8_SkColorType || info.alphaType() == kUnpremul_SkAlphaType) { + p->append(SkRasterPipeline::premul); + } + if (quality > kLow_SkFilterQuality) { + // Bicubic filtering naturally produces out of range values on both sides. + p->append(SkRasterPipeline::clamp_0); + p->append(SkRasterPipeline::clamp_a); + } + return append_gamut_transform(p, scratch, info.colorSpace(), dst); +} diff --git a/gfx/skia/skia/src/image/SkImageShader.h b/gfx/skia/skia/src/image/SkImageShader.h index 8905881a9999..8960812a0632 100644 --- a/gfx/skia/skia/src/image/SkImageShader.h +++ b/gfx/skia/skia/src/image/SkImageShader.h @@ -15,7 +15,7 @@ class SkImageShader : public SkShader { public: static sk_sp Make(sk_sp, TileMode tx, TileMode ty, - const SkMatrix* localMatrix, SkTBlitterAllocator* = nullptr); + const SkMatrix* localMatrix); bool isOpaque() const override; @@ -30,13 +30,15 @@ public: protected: void flatten(SkWriteBuffer&) const override; - size_t onContextSize(const ContextRec&) const override; - Context* onCreateContext(const ContextRec&, void* storage) const override; + Context* onMakeContext(const ContextRec&, SkArenaAlloc* storage) const override; #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode*) const override; #endif SkImage* onIsAImage(SkMatrix*, TileMode*) const override; + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + const SkMatrix& ctm, const SkPaint&, const SkMatrix*) const override; + sk_sp fImage; const TileMode fTileModeX; const TileMode fTileModeY; diff --git a/gfx/skia/skia/src/image/SkImage_Base.h b/gfx/skia/skia/src/image/SkImage_Base.h index b314cc6c2ff0..062d78567938 100644 --- a/gfx/skia/skia/src/image/SkImage_Base.h +++ b/gfx/skia/skia/src/image/SkImage_Base.h @@ -14,11 +14,12 @@ #if SK_SUPPORT_GPU #include "GrTexture.h" + #include "GrTextureProxy.h" #endif #include -class GrTextureParams; +class GrSamplerParams; class SkImageCacherator; enum { @@ -40,23 +41,35 @@ public: virtual const SkBitmap* onPeekBitmap() const { return nullptr; } - // Default impl calls onDraw - virtual bool onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, - int srcX, int srcY, CachingHint) const; + virtual bool onReadYUV8Planes(const SkISize sizes[3], void* const planes[3], + const size_t rowBytes[3], SkYUVColorSpace colorSpace) const; + virtual bool onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, + int srcX, int srcY, CachingHint) const = 0; + + // MDB TODO: this entry point needs to go away virtual GrTexture* peekTexture() const { return nullptr; } #if SK_SUPPORT_GPU - virtual sk_sp refPinnedTexture(uint32_t* uniqueID) const { return nullptr; } + virtual GrTextureProxy* peekProxy() const { return nullptr; } + virtual sk_sp asTextureProxyRef() const { return nullptr; } + virtual sk_sp asTextureProxyRef(GrContext*, const GrSamplerParams&, + SkColorSpace*, sk_sp*, + SkScalar scaleAdjust[2]) const = 0; + virtual sk_sp refPinnedTextureProxy(uint32_t* uniqueID) const { + return nullptr; + } + virtual GrBackendObject onGetTextureHandle(bool flushPendingGrContextIO, + GrSurfaceOrigin* origin) const { + return 0; + } + virtual GrTexture* onGetTexture() const { return nullptr; } #endif virtual SkImageCacherator* peekCacherator() const { return nullptr; } // return a read-only copy of the pixels. We promise to not modify them, // but only inspect them (or encode them). - virtual bool getROPixels(SkBitmap*, CachingHint = kAllow_CachingHint) const = 0; - - // Caller must call unref when they are done. - virtual GrTexture* asTextureRef(GrContext*, const GrTextureParams&, - SkSourceGammaTreatment) const = 0; + virtual bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, + CachingHint = kAllow_CachingHint) const = 0; virtual sk_sp onMakeSubset(const SkIRect&) const = 0; @@ -73,9 +86,11 @@ public: fAddedToCache.store(true); } - virtual void onPinAsTexture(GrContext*) const {} + virtual bool onPinAsTexture(GrContext*) const { return false; } virtual void onUnpinAsTexture(GrContext*) const {} + virtual sk_sp onMakeColorSpace(sk_sp) const = 0; + private: // Set true by caches when they cache content that's derived from the current pixels. mutable SkAtomic fAddedToCache; diff --git a/gfx/skia/skia/src/image/SkImage_Generator.cpp b/gfx/skia/skia/src/image/SkImage_Generator.cpp index 412f573ba6db..51fb281c2615 100644 --- a/gfx/skia/skia/src/image/SkImage_Generator.cpp +++ b/gfx/skia/skia/src/image/SkImage_Generator.cpp @@ -7,38 +7,41 @@ #include "SkImage_Base.h" #include "SkBitmap.h" -#include "SkCanvas.h" #include "SkData.h" #include "SkImageCacherator.h" #include "SkImagePriv.h" #include "SkPixelRef.h" -#include "SkSurface.h" class SkImage_Generator : public SkImage_Base { public: - SkImage_Generator(SkImageCacherator* cache) - : INHERITED(cache->info().width(), cache->info().height(), cache->uniqueID()) - , fCache(cache) // take ownership + SkImage_Generator(SkImageCacherator::Validator* validator) + : INHERITED(validator->fInfo.width(), validator->fInfo.height(), validator->fUniqueID) + , fCache(validator) {} virtual SkImageInfo onImageInfo() const override { - return fCache->info(); + return fCache.info(); } SkAlphaType onAlphaType() const override { - return fCache->info().alphaType(); + return fCache.info().alphaType(); } - bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override; - SkImageCacherator* peekCacherator() const override { return fCache; } + bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, + CachingHint) const override; +#if SK_SUPPORT_GPU + sk_sp asTextureProxyRef(GrContext*, const GrSamplerParams&, + SkColorSpace*, sk_sp*, + SkScalar scaleAdjust[2]) const override; +#endif + SkImageCacherator* peekCacherator() const override { return &fCache; } SkData* onRefEncoded(GrContext*) const override; sk_sp onMakeSubset(const SkIRect&) const override; - bool getROPixels(SkBitmap*, CachingHint) const override; - GrTexture* asTextureRef(GrContext*, const GrTextureParams&, - SkSourceGammaTreatment) const override; + bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override; bool onIsLazyGenerated() const override { return true; } + sk_sp onMakeColorSpace(sk_sp) const override; private: - SkAutoTDelete fCache; + mutable SkImageCacherator fCache; typedef SkImage_Base INHERITED; }; @@ -47,63 +50,84 @@ private: bool SkImage_Generator::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int srcX, int srcY, CachingHint chint) const { + SkColorSpace* dstColorSpace = dstInfo.colorSpace(); SkBitmap bm; if (kDisallow_CachingHint == chint) { - if (fCache->lockAsBitmapOnlyIfAlreadyCached(&bm)) { + SkImageCacherator::CachedFormat cacheFormat = fCache.chooseCacheFormat(dstColorSpace); + if (fCache.lockAsBitmapOnlyIfAlreadyCached(&bm, cacheFormat)) { return bm.readPixels(dstInfo, dstPixels, dstRB, srcX, srcY); } else { // Try passing the caller's buffer directly down to the generator. If this fails we // may still succeed in the general case, as the generator may prefer some other // config, which we could then convert via SkBitmap::readPixels. - if (fCache->directGeneratePixels(dstInfo, dstPixels, dstRB, srcX, srcY)) { + if (fCache.directGeneratePixels(dstInfo, dstPixels, dstRB, srcX, srcY, + SkTransferFunctionBehavior::kRespect)) { return true; } // else fall through } } - if (this->getROPixels(&bm, chint)) { + if (this->getROPixels(&bm, dstColorSpace, chint)) { return bm.readPixels(dstInfo, dstPixels, dstRB, srcX, srcY); } return false; } SkData* SkImage_Generator::onRefEncoded(GrContext* ctx) const { - return fCache->refEncoded(ctx); + return fCache.refEncoded(ctx); } -bool SkImage_Generator::getROPixels(SkBitmap* bitmap, CachingHint chint) const { - return fCache->lockAsBitmap(bitmap, this, chint); +bool SkImage_Generator::getROPixels(SkBitmap* bitmap, SkColorSpace* dstColorSpace, + CachingHint chint) const { + return fCache.lockAsBitmap(nullptr, bitmap, this, dstColorSpace, chint); } -GrTexture* SkImage_Generator::asTextureRef(GrContext* ctx, const GrTextureParams& params, - SkSourceGammaTreatment gammaTreatment) const { - return fCache->lockAsTexture(ctx, params, gammaTreatment, this); +#if SK_SUPPORT_GPU +sk_sp SkImage_Generator::asTextureProxyRef(GrContext* context, + const GrSamplerParams& params, + SkColorSpace* dstColorSpace, + sk_sp* texColorSpace, + SkScalar scaleAdjust[2]) const { + return fCache.lockAsTextureProxy(context, params, dstColorSpace, + texColorSpace, this, scaleAdjust); } +#endif sk_sp SkImage_Generator::onMakeSubset(const SkIRect& subset) const { - // TODO: make this lazy, by wrapping the subset inside a new generator or something - // For now, we do effectively what we did before, make it a raster + SkASSERT(fCache.info().bounds().contains(subset)); + SkASSERT(fCache.info().bounds() != subset); - const SkImageInfo info = SkImageInfo::MakeN32(subset.width(), subset.height(), - this->alphaType()); - auto surface(SkSurface::MakeRaster(info)); - if (!surface) { - return nullptr; - } - surface->getCanvas()->clear(0); - surface->getCanvas()->drawImage(this, SkIntToScalar(-subset.x()), SkIntToScalar(-subset.y()), - nullptr); - return surface->makeImageSnapshot(); + const SkIRect generatorSubset = subset.makeOffset(fCache.fOrigin.x(), fCache.fOrigin.y()); + SkImageCacherator::Validator validator(fCache.fSharedGenerator, &generatorSubset); + return validator ? sk_sp(new SkImage_Generator(&validator)) : nullptr; } -sk_sp SkImage::MakeFromGenerator(SkImageGenerator* generator, const SkIRect* subset) { - if (!generator) { +sk_sp SkImage_Generator::onMakeColorSpace(sk_sp target) const { + SkBitmap dst; + SkImageInfo dstInfo = fCache.info().makeColorSpace(target); + if (kIndex_8_SkColorType == dstInfo.colorType() || + kGray_8_SkColorType == dstInfo.colorType() || + kRGB_565_SkColorType == dstInfo.colorType()) { + dstInfo = dstInfo.makeColorType(kN32_SkColorType); + } + dst.allocPixels(dstInfo); + + // Use kIgnore for transfer function behavior. This is used by the SkColorSpaceXformCanvas, + // which wants to pre-xform the inputs but ignore the transfer function on blends. + if (!fCache.directGeneratePixels(dstInfo, dst.getPixels(), dst.rowBytes(), 0, 0, + SkTransferFunctionBehavior::kIgnore)) { return nullptr; } - SkImageCacherator* cache = SkImageCacherator::NewFromGenerator(generator, subset); - if (!cache) { - return nullptr; - } - return sk_make_sp(cache); + + dst.setImmutable(); + return SkImage::MakeFromBitmap(dst); +} + +sk_sp SkImage::MakeFromGenerator(std::unique_ptr generator, + const SkIRect* subset) { + SkImageCacherator::Validator validator( + SkImageCacherator::SharedGenerator::Make(std::move(generator)), subset); + + return validator ? sk_make_sp(&validator) : nullptr; } diff --git a/gfx/skia/skia/src/image/SkImage_Gpu.cpp b/gfx/skia/skia/src/image/SkImage_Gpu.cpp index da7a5a7183b4..ad6fe3266ca2 100644 --- a/gfx/skia/skia/src/image/SkImage_Gpu.cpp +++ b/gfx/skia/skia/src/image/SkImage_Gpu.cpp @@ -6,30 +6,42 @@ */ #include "SkAutoPixmapStorage.h" +#include "GrBitmapTextureMaker.h" #include "GrCaps.h" #include "GrContext.h" -#include "GrDrawContext.h" -#include "GrImageIDTextureAdjuster.h" +#include "GrContextPriv.h" +#include "GrGpu.h" +#include "GrImageTextureMaker.h" +#include "GrRenderTargetContext.h" +#include "GrResourceProvider.h" +#include "GrSemaphore.h" +#include "GrTextureAdjuster.h" #include "GrTexturePriv.h" +#include "GrTextureProxy.h" +#include "GrTextureToYUVPlanes.h" +#include "effects/GrNonlinearColorSpaceXformEffect.h" #include "effects/GrYUVEffect.h" #include "SkCanvas.h" +#include "SkCrossContextImageData.h" #include "SkBitmapCache.h" -#include "SkGrPriv.h" +#include "SkGr.h" #include "SkImage_Gpu.h" +#include "SkImageCacherator.h" +#include "SkImageInfoPriv.h" #include "SkMipMap.h" #include "SkPixelRef.h" +#include "SkReadPixelsRec.h" -SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrTexture* tex, +SkImage_Gpu::SkImage_Gpu(GrContext* context, uint32_t uniqueID, SkAlphaType at, + sk_sp proxy, sk_sp colorSpace, SkBudgeted budgeted) - : INHERITED(w, h, uniqueID) - , fTexture(SkRef(tex)) + : INHERITED(proxy->width(), proxy->height(), uniqueID) + , fContext(context) + , fProxy(std::move(proxy)) , fAlphaType(at) , fBudgeted(budgeted) , fColorSpace(std::move(colorSpace)) - , fAddedRasterVersionToCache(false) -{ - SkASSERT(tex->width() == w); - SkASSERT(tex->height() == h); + , fAddedRasterVersionToCache(false) { } SkImage_Gpu::~SkImage_Gpu() { @@ -38,54 +50,77 @@ SkImage_Gpu::~SkImage_Gpu() { } } -extern void SkTextureImageApplyBudgetedDecision(SkImage* image) { - if (image->isTextureBacked()) { - ((SkImage_Gpu*)image)->applyBudgetDecision(); - } -} - SkImageInfo SkImage_Gpu::onImageInfo() const { SkColorType ct; - if (!GrPixelConfigToColorType(fTexture->config(), &ct)) { + if (!GrPixelConfigToColorType(fProxy->config(), &ct)) { ct = kUnknown_SkColorType; } - return SkImageInfo::Make(fTexture->width(), fTexture->height(), ct, fAlphaType, fColorSpace); + return SkImageInfo::Make(fProxy->width(), fProxy->height(), ct, fAlphaType, fColorSpace); } static SkImageInfo make_info(int w, int h, SkAlphaType at, sk_sp colorSpace) { return SkImageInfo::MakeN32(w, h, at, std::move(colorSpace)); } -bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const { - if (SkBitmapCache::Find(this->uniqueID(), dst)) { +bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace* dstColorSpace, CachingHint chint) const { + const auto desc = SkBitmapCacheDesc::Make(this); + if (SkBitmapCache::Find(desc, dst)) { SkASSERT(dst->getGenerationID() == this->uniqueID()); SkASSERT(dst->isImmutable()); SkASSERT(dst->getPixels()); return true; } - if (!dst->tryAllocPixels(make_info(this->width(), this->height(), this->alphaType(), - this->fColorSpace))) { - return false; + SkImageInfo ii = make_info(this->width(), this->height(), this->alphaType(), + sk_ref_sp(dstColorSpace)); + SkBitmapCache::RecPtr rec = nullptr; + SkPixmap pmap; + if (kAllow_CachingHint == chint) { + rec = SkBitmapCache::Alloc(desc, ii, &pmap); + if (!rec) { + return false; + } + } else { + if (!dst->tryAllocPixels(ii)) { + return false; + } } - if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig, - dst->getPixels(), dst->rowBytes())) { + + sk_sp sContext = fContext->contextPriv().makeWrappedSurfaceContext( + fProxy, + fColorSpace); + if (!sContext) { return false; } - dst->pixelRef()->setImmutableWithID(this->uniqueID()); - if (kAllow_CachingHint == chint) { - SkBitmapCache::Add(this->uniqueID(), *dst); + if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) { + return false; + } + + if (rec) { + SkBitmapCache::Add(std::move(rec), dst); fAddedRasterVersionToCache.store(true); } return true; } -GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& params, - SkSourceGammaTreatment gammaTreatment) const { - GrTextureAdjuster adjuster(this->peekTexture(), this->alphaType(), this->bounds(), this->uniqueID(), - this->onImageInfo().colorSpace()); - return adjuster.refTextureSafeForParams(params, gammaTreatment, nullptr); +sk_sp SkImage_Gpu::asTextureProxyRef(GrContext* context, + const GrSamplerParams& params, + SkColorSpace* dstColorSpace, + sk_sp* texColorSpace, + SkScalar scaleAdjust[2]) const { + if (context != fContext) { + SkASSERT(0); + return nullptr; + } + + if (texColorSpace) { + *texColorSpace = this->fColorSpace; + } + + GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->bounds(), + this->uniqueID(), this->fColorSpace.get()); + return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust); } static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) { @@ -109,18 +144,71 @@ static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) } } -bool SkImage_Gpu::onReadPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, - int srcX, int srcY, CachingHint) const { - GrPixelConfig config = SkImageInfo2GrPixelConfig(info, *fTexture->getContext()->caps()); - uint32_t flags = 0; - if (kUnpremul_SkAlphaType == info.alphaType() && kPremul_SkAlphaType == fAlphaType) { - // let the GPU perform this transformation for us - flags = GrContext::kUnpremul_PixelOpsFlag; +GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO, + GrSurfaceOrigin* origin) const { + SkASSERT(fProxy); + + GrSurface* surface = fProxy->instantiate(fContext->resourceProvider()); + if (surface && surface->asTexture()) { + if (flushPendingGrContextIO) { + fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get()); + } + if (origin) { + *origin = fProxy->origin(); + } + return surface->asTexture()->getTextureHandle(); } - if (!fTexture->readPixels(srcX, srcY, info.width(), info.height(), config, - pixels, rowBytes, flags)) { + return 0; +} + +GrTexture* SkImage_Gpu::onGetTexture() const { + GrTextureProxy* proxy = this->peekProxy(); + if (!proxy) { + return nullptr; + } + + return proxy->instantiate(fContext->resourceProvider()); +} + +bool SkImage_Gpu::onReadYUV8Planes(const SkISize sizes[3], void* const planes[3], + const size_t rowBytes[3], SkYUVColorSpace colorSpace) const { + if (GrTextureToYUVPlanes(fContext, fProxy, sizes, planes, rowBytes, colorSpace)) { + return true; + } + + return INHERITED::onReadYUV8Planes(sizes, planes, rowBytes, colorSpace); +} + +bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, + int srcX, int srcY, CachingHint) const { + if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) { return false; } + + SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY); + if (!rec.trim(this->width(), this->height())) { + return false; + } + + // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and + // GrRenderTargetContext::onReadPixels + uint32_t flags = 0; + if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) { + // let the GPU perform this transformation for us + flags = GrContextPriv::kUnpremul_PixelOpsFlag; + } + + sk_sp sContext = fContext->contextPriv().makeWrappedSurfaceContext( + fProxy, + fColorSpace); + if (!sContext) { + return false; + } + + if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) { + return false; + } + // do we have to manually fix-up the alpha channel? // src dst // unpremul premul fix manually @@ -129,25 +217,33 @@ bool SkImage_Gpu::onReadPixels(const SkImageInfo& info, void* pixels, size_t row // // Should this be handled by Ganesh? todo:? // - if (kPremul_SkAlphaType == info.alphaType() && kUnpremul_SkAlphaType == fAlphaType) { - apply_premul(info, pixels, rowBytes); + if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) { + apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes); } return true; } sk_sp SkImage_Gpu::onMakeSubset(const SkIRect& subset) const { - GrContext* ctx = fTexture->getContext(); - GrSurfaceDesc desc = fTexture->desc(); + GrSurfaceDesc desc = fProxy->desc(); desc.fWidth = subset.width(); desc.fHeight = subset.height(); - sk_sp subTx(ctx->textureProvider()->createTexture(desc, fBudgeted)); - if (!subTx) { + sk_sp sContext(fContext->contextPriv().makeDeferredSurfaceContext( + desc, + SkBackingFit::kExact, + fBudgeted)); + if (!sContext) { return nullptr; } - ctx->copySurface(subTx.get(), fTexture, subset, SkIPoint::Make(0, 0)); - return sk_make_sp(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID, - fAlphaType, subTx.get(), fColorSpace, fBudgeted); + + if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) { + return nullptr; + } + + // MDB: this call is okay bc we know 'sContext' was kExact + return sk_make_sp(fContext, kNeedNewImageUniqueID, + fAlphaType, sContext->asTextureProxyRef(), + fColorSpace, fBudgeted); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -160,7 +256,8 @@ static sk_sp new_wrapped_texture_common(GrContext* ctx, const GrBackend if (desc.fWidth <= 0 || desc.fHeight <= 0) { return nullptr; } - SkAutoTUnref tex(ctx->textureProvider()->wrapBackendTexture(desc, ownership)); + + sk_sp tex = ctx->resourceProvider()->wrapBackendTexture(desc, ownership); if (!tex) { return nullptr; } @@ -168,9 +265,11 @@ static sk_sp new_wrapped_texture_common(GrContext* ctx, const GrBackend tex->setRelease(releaseProc, releaseCtx); } - const SkBudgeted budgeted = SkBudgeted::kNo; - return sk_make_sp(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID, - at, tex, colorSpace, budgeted); + const SkBudgeted budgeted = (kAdoptAndCache_GrWrapOwnership == ownership) + ? SkBudgeted::kYes : SkBudgeted::kNo; + sk_sp proxy(GrSurfaceProxy::MakeWrapped(std::move(tex))); + return sk_make_sp(ctx, kNeedNewImageUniqueID, + at, std::move(proxy), std::move(colorSpace), budgeted); } sk_sp SkImage::MakeFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc, @@ -220,13 +319,12 @@ static sk_sp make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpac uDesc.fWidth = yuvSizes[1].fWidth; uDesc.fHeight = yuvSizes[1].fHeight; - sk_sp yTex( - ctx->textureProvider()->wrapBackendTexture(yDesc, kBorrow_GrWrapOwnership)); - sk_sp uTex( - ctx->textureProvider()->wrapBackendTexture(uDesc, kBorrow_GrWrapOwnership)); - sk_sp vTex; + sk_sp yProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, yDesc); + sk_sp uProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, uDesc); + sk_sp vProxy; + if (nv12) { - vTex = uTex; + vProxy = uProxy; } else { GrBackendTextureDesc vDesc; vDesc.fConfig = kConfig; @@ -236,10 +334,9 @@ static sk_sp make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpac vDesc.fWidth = yuvSizes[2].fWidth; vDesc.fHeight = yuvSizes[2].fHeight; - vTex = sk_sp( - ctx->textureProvider()->wrapBackendTexture(vDesc, kBorrow_GrWrapOwnership)); + vProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, vDesc); } - if (!yTex || !uTex || !vTex) { + if (!yProxy || !uProxy || !vProxy) { return nullptr; } @@ -247,28 +344,38 @@ static sk_sp make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpac const int height = yuvSizes[0].fHeight; // Needs to be a render target in order to draw to it for the yuv->rgb conversion. - sk_sp drawContext(ctx->makeDrawContext(SkBackingFit::kExact, - width, height, - kRGBA_8888_GrPixelConfig, - std::move(imageColorSpace), - 0, - origin)); - if (!drawContext) { + sk_sp renderTargetContext(ctx->makeRenderTargetContext( + SkBackingFit::kExact, + width, height, + kRGBA_8888_GrPixelConfig, + std::move(imageColorSpace), + 0, + origin)); + if (!renderTargetContext) { return nullptr; } GrPaint paint; - paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); paint.addColorFragmentProcessor( - GrYUVEffect::MakeYUVToRGB(yTex.get(), uTex.get(), vTex.get(), yuvSizes, colorSpace, nv12)); + GrYUVEffect::MakeYUVToRGB(ctx->resourceProvider(), + sk_ref_sp(yProxy->asTextureProxy()), + sk_ref_sp(uProxy->asTextureProxy()), + sk_ref_sp(vProxy->asTextureProxy()), yuvSizes, colorSpace, nv12)); - const SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); + const SkRect rect = SkRect::MakeIWH(width, height); - drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), rect); - ctx->flushSurfaceWrites(drawContext->accessRenderTarget()); - return sk_make_sp(width, height, kNeedNewImageUniqueID, - kOpaque_SkAlphaType, drawContext->asTexture().get(), - sk_ref_sp(drawContext->getColorSpace()), budgeted); + renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect); + + if (!renderTargetContext->asSurfaceProxy()) { + return nullptr; + } + ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy()); + + // MDB: this call is okay bc we know 'renderTargetContext' was exact + return sk_make_sp(ctx, kNeedNewImageUniqueID, + kOpaque_SkAlphaType, renderTargetContext->asTextureProxyRef(), + renderTargetContext->refColorSpace(), budgeted); } sk_sp SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace, @@ -288,17 +395,21 @@ sk_sp SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace std::move(imageColorSpace)); } -static sk_sp create_image_from_maker(GrTextureMaker* maker, SkAlphaType at, uint32_t id) { - SkAutoTUnref texture(maker->refTextureForParams(GrTextureParams::ClampNoFilter(), - SkSourceGammaTreatment::kRespect)); - if (!texture) { +static sk_sp create_image_from_maker(GrContext* context, GrTextureMaker* maker, + SkAlphaType at, uint32_t id, + SkColorSpace* dstColorSpace) { + sk_sp texColorSpace; + sk_sp proxy(maker->refTextureProxyForParams(GrSamplerParams::ClampNoFilter(), + dstColorSpace, + &texColorSpace, nullptr)); + if (!proxy) { return nullptr; } - return sk_make_sp(texture->width(), texture->height(), id, at, texture, - sk_ref_sp(maker->getColorSpace()), SkBudgeted::kNo); + return sk_make_sp(context, id, at, + std::move(proxy), std::move(texColorSpace), SkBudgeted::kNo); } -sk_sp SkImage::makeTextureImage(GrContext *context) const { +sk_sp SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const { if (!context) { return nullptr; } @@ -308,16 +419,78 @@ sk_sp SkImage::makeTextureImage(GrContext *context) const { if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) { GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint); - return create_image_from_maker(&maker, this->alphaType(), this->uniqueID()); + return create_image_from_maker(context, &maker, this->alphaType(), + this->uniqueID(), dstColorSpace); } if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) { GrBitmapTextureMaker maker(context, *bmp); - return create_image_from_maker(&maker, this->alphaType(), this->uniqueID()); + return create_image_from_maker(context, &maker, this->alphaType(), + this->uniqueID(), dstColorSpace); } return nullptr; } +std::unique_ptr SkCrossContextImageData::MakeFromEncoded( + GrContext* context, sk_sp encoded, SkColorSpace* dstColorSpace) { + sk_sp codecImage = SkImage::MakeFromEncoded(std::move(encoded)); + if (!codecImage) { + return nullptr; + } + + // Some backends or drivers don't support (safely) moving resources between contexts + if (!context->caps()->crossContextTextureSupport()) { + return std::unique_ptr( + new SkCrossContextImageData(std::move(codecImage))); + } + + sk_sp textureImage = codecImage->makeTextureImage(context, dstColorSpace); + if (!textureImage) { + // TODO: Force decode to raster here? Do mip-mapping, like getDeferredTextureImageData? + return std::unique_ptr( + new SkCrossContextImageData(std::move(codecImage))); + } + + // Crack open the gpu image, extract the backend data, stick it in the SkCCID + GrTexture* texture = as_IB(textureImage)->peekTexture(); + SkASSERT(texture); + + GrBackendTextureDesc desc; + desc.fFlags = kNone_GrBackendTextureFlag; + desc.fOrigin = texture->origin(); + desc.fWidth = texture->width(); + desc.fHeight = texture->height(); + desc.fConfig = texture->config(); + desc.fSampleCnt = 0; + + context->contextPriv().prepareSurfaceForExternalIO(as_IB(textureImage)->peekProxy()); + auto textureData = texture->texturePriv().detachBackendTexture(); + SkASSERT(textureData); + + SkImageInfo info = as_IB(textureImage)->onImageInfo(); + return std::unique_ptr(new SkCrossContextImageData( + desc, std::move(textureData), info.alphaType(), info.refColorSpace())); +} + +sk_sp SkImage::MakeFromCrossContextImageData( + GrContext* context, std::unique_ptr ccid) { + if (ccid->fImage) { + // No pre-existing GPU resource. We could upload it now (with makeTextureImage), + // but we'd need a dstColorSpace. + return ccid->fImage; + } + + if (ccid->fTextureData) { + ccid->fTextureData->attachToContext(context); + } + + // This texture was created by Ganesh on another thread (see MakeFromEncoded, above). + // Thus, we can import it back into our cache and treat it as our own (again). + GrWrapOwnership ownership = kAdoptAndCache_GrWrapOwnership; + return new_wrapped_texture_common(context, ccid->fDesc, ccid->fAlphaType, + std::move(ccid->fColorSpace), ownership, nullptr, nullptr); +} + sk_sp SkImage::makeNonTextureImage() const { if (!this->isTextureBacked()) { return sk_ref_sp(const_cast(this)); @@ -336,20 +509,6 @@ sk_sp SkImage::makeNonTextureImage() const { return MakeRasterData(info, data, rowBytes); } -sk_sp SkImage::MakeTextureFromPixmap(GrContext* ctx, const SkPixmap& pixmap, - SkBudgeted budgeted) { - if (!ctx) { - return nullptr; - } - SkAutoTUnref texture(GrUploadPixmapToTexture(ctx, pixmap, budgeted)); - if (!texture) { - return nullptr; - } - return sk_make_sp(texture->width(), texture->height(), kNeedNewImageUniqueID, - pixmap.alphaType(), texture, - sk_ref_sp(pixmap.info().colorSpace()), budgeted); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// namespace { @@ -359,45 +518,29 @@ struct MipMapLevelData { }; struct DeferredTextureImage { - uint32_t fContextUniqueID; - // Right now, the gamma treatment is only considered when generating mipmaps - SkSourceGammaTreatment fGammaTreatment; + uint32_t fContextUniqueID; + // Right now, the destination color mode is only considered when generating mipmaps + SkDestinationSurfaceColorMode fColorMode; // We don't store a SkImageInfo because it contains a ref-counted SkColorSpace. - int fWidth; - int fHeight; - SkColorType fColorType; - SkAlphaType fAlphaType; - void* fColorSpace; - size_t fColorSpaceSize; - int fColorTableCnt; - uint32_t* fColorTableData; - int fMipMapLevelCount; + int fWidth; + int fHeight; + SkColorType fColorType; + SkAlphaType fAlphaType; + void* fColorSpace; + size_t fColorSpaceSize; + int fMipMapLevelCount; // The fMipMapLevelData array may contain more than 1 element. // It contains fMipMapLevelCount elements. // That means this struct's size is not known at compile-time. - MipMapLevelData fMipMapLevelData[1]; + MipMapLevelData fMipMapLevelData[1]; }; } // anonymous namespace static bool should_use_mip_maps(const SkImage::DeferredTextureImageUsageParams & param) { - bool shouldUseMipMaps = false; - - // Use mipmaps if either - // 1.) it is a perspective matrix, or - // 2.) the quality is med/high and the scale is < 1 - if (param.fMatrix.hasPerspective()) { - shouldUseMipMaps = true; - } - if (param.fQuality == kMedium_SkFilterQuality || - param.fQuality == kHigh_SkFilterQuality) { - SkScalar minAxisScale = param.fMatrix.getMinScale(); - if (minAxisScale != -1.f && minAxisScale < 1.f) { - shouldUseMipMaps = true; - } - } - - - return shouldUseMipMaps; + // There is a bug in the mipmap pre-generation logic in use in getDeferredTextureImageData. + // This can cause runaway memory leaks, so we are disabling this path until we can + // investigate further. crbug.com/669775 + return false; } namespace { @@ -426,7 +569,7 @@ private: size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy, const DeferredTextureImageUsageParams params[], int paramCnt, void* buffer, - SkSourceGammaTreatment gammaTreatment) const { + SkColorSpace* dstColorSpace) const { // Extract relevant min/max values from the params array. int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel; SkFilterQuality highestFilterQuality = params[0].fQuality; @@ -471,15 +614,9 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox SkAutoPixmapStorage pixmap; SkImageInfo info; size_t pixelSize = 0; - size_t ctSize = 0; - int ctCount = 0; - if (!isScaled && this->peekPixels(&pixmap)) { + if (!isScaled && this->peekPixels(&pixmap) && !pixmap.ctable()) { info = pixmap.info(); pixelSize = SkAlign8(pixmap.getSafeSize()); - if (pixmap.ctable()) { - ctCount = pixmap.ctable()->count(); - ctSize = SkAlign8(pixmap.ctable()->count() * 4); - } } else { // Here we're just using presence of data to know whether there is a codec behind the image. // In the future we will access the cacherator and get the exact data that we want to (e.g. @@ -488,7 +625,19 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox if (!data && !this->peekPixels(nullptr)) { return 0; } - info = SkImageInfo::MakeN32(scaledSize.width(), scaledSize.height(), this->alphaType()); + if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) { + // Generator backed image. Tweak info to trigger correct kind of decode. + SkImageCacherator::CachedFormat cacheFormat = cacher->chooseCacheFormat( + dstColorSpace, proxy.fCaps.get()); + info = cacher->buildCacheInfo(cacheFormat).makeWH(scaledSize.width(), + scaledSize.height()); + } else { + info = as_IB(this)->onImageInfo().makeWH(scaledSize.width(), scaledSize.height()); + } + if (kIndex_8_SkColorType == info.colorType()) { + // Force Index8 to be N32 instead. Index8 is unsupported in Ganesh. + info = info.makeColorType(kN32_SkColorType); + } pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr)); if (fillMode) { pixmap.alloc(info); @@ -505,7 +654,6 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox SkASSERT(!pixmap.ctable()); } } - SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType; int mipMapLevelCount = 1; if (useMipMaps) { // SkMipMap only deals with the mipmap levels it generates, which does @@ -524,7 +672,7 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox currentMipMapLevelIndex--) { SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), scaledSize.height(), currentMipMapLevelIndex); - SkImageInfo mipInfo = SkImageInfo::MakeN32(mipSize.fWidth, mipSize.fHeight, at); + SkImageInfo mipInfo = info.makeWH(mipSize.fWidth, mipSize.fHeight); pixelSize += SkAlign8(SkAutoPixmapStorage::AllocSize(mipInfo, nullptr)); } } @@ -536,14 +684,20 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox // level in its size size_t pixelOffset = size; size += pixelSize; - size_t ctOffset = size; - size += ctSize; size_t colorSpaceOffset = 0; size_t colorSpaceSize = 0; + SkColorSpaceTransferFn fn; if (info.colorSpace()) { colorSpaceOffset = size; colorSpaceSize = info.colorSpace()->writeToMemory(nullptr); size += colorSpaceSize; + } else if (this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)) { + // In legacy mode, preserve the color space tag on the SkImage. This is only + // supported if the color space has a parametric transfer function. + SkASSERT(!dstColorSpace); + colorSpaceOffset = size; + colorSpaceSize = this->colorSpace()->writeToMemory(nullptr); + size += colorSpaceSize; } if (!fillMode) { return size; @@ -551,15 +705,17 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox char* bufferAsCharPtr = reinterpret_cast(buffer); char* pixelsAsCharPtr = bufferAsCharPtr + pixelOffset; void* pixels = pixelsAsCharPtr; - void* ct = nullptr; - if (ctSize) { - ct = bufferAsCharPtr + ctOffset; - } memcpy(reinterpret_cast(SkAlign8(reinterpret_cast(pixelsAsCharPtr))), pixmap.addr(), pixmap.getSafeSize()); - if (ctSize) { - memcpy(ct, pixmap.ctable()->readColors(), ctSize); + + // If the context has sRGB support, and we're intending to render to a surface with an attached + // color space, and the image has an sRGB-like color space attached, then use our gamma (sRGB) + // aware mip-mapping. + SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy; + if (proxy.fCaps->srgbSupport() && SkToBool(dstColorSpace) && + info.colorSpace() && info.colorSpace()->gammaCloseToSRGB()) { + colorMode = SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware; } SkASSERT(info == pixmap.info()); @@ -567,7 +723,7 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox static_assert(std::is_standard_layout::value, "offsetof, which we use below, requires the type have standard layout"); auto dtiBufferFiller = DTIBufferFiller{bufferAsCharPtr}; - FILL_MEMBER(dtiBufferFiller, fGammaTreatment, &gammaTreatment); + FILL_MEMBER(dtiBufferFiller, fColorMode, &colorMode); FILL_MEMBER(dtiBufferFiller, fContextUniqueID, &proxy.fContextUniqueID); int width = info.width(); FILL_MEMBER(dtiBufferFiller, fWidth, &width); @@ -577,8 +733,6 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox FILL_MEMBER(dtiBufferFiller, fColorType, &colorType); SkAlphaType alphaType = info.alphaType(); FILL_MEMBER(dtiBufferFiller, fAlphaType, &alphaType); - FILL_MEMBER(dtiBufferFiller, fColorTableCnt, &ctCount); - FILL_MEMBER(dtiBufferFiller, fColorTableData, &ct); FILL_MEMBER(dtiBufferFiller, fMipMapLevelCount, &mipMapLevelCount); memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fPixelData), &pixels, sizeof(pixels)); @@ -588,7 +742,13 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox void* colorSpace = bufferAsCharPtr + colorSpaceOffset; FILL_MEMBER(dtiBufferFiller, fColorSpace, &colorSpace); FILL_MEMBER(dtiBufferFiller, fColorSpaceSize, &colorSpaceSize); - info.colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset); + if (info.colorSpace()) { + info.colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset); + } else { + SkASSERT(this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)); + SkASSERT(!dstColorSpace); + this->colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset); + } } else { memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpace), 0, sizeof(DeferredTextureImage::fColorSpace)); @@ -603,17 +763,13 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox static_assert(std::is_standard_layout::value, "offsetof, which we use below, requires the type have a standard layout"); - SkAutoTDelete mipmaps(SkMipMap::Build(pixmap, gammaTreatment, nullptr)); + std::unique_ptr mipmaps(SkMipMap::Build(pixmap, colorMode, nullptr)); // SkMipMap holds only the mipmap levels it generates. // A programmer can use the data they provided to SkMipMap::Build as level 0. // So the SkMipMap provides levels 1-x but it stores them in its own // range 0-(x-1). for (int generatedMipLevelIndex = 0; generatedMipLevelIndex < mipMapLevelCount - 1; generatedMipLevelIndex++) { - SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), scaledSize.height(), - generatedMipLevelIndex); - - SkImageInfo mipInfo = SkImageInfo::MakeN32(mipSize.fWidth, mipSize.fHeight, at); SkMipMap::Level mipLevel; mipmaps->getLevel(generatedMipLevelIndex, &mipLevel); @@ -654,11 +810,6 @@ sk_sp SkImage::MakeFromDeferredTextureImageData(GrContext* context, con if (!context || context->uniqueID() != dti->fContextUniqueID) { return nullptr; } - SkAutoTUnref colorTable; - if (dti->fColorTableCnt) { - SkASSERT(dti->fColorTableData); - colorTable.reset(new SkColorTable(dti->fColorTableData, dti->fColorTableCnt)); - } int mipLevelCount = dti->fMipMapLevelCount; SkASSERT(mipLevelCount >= 1); sk_sp colorSpace; @@ -669,11 +820,22 @@ sk_sp SkImage::MakeFromDeferredTextureImageData(GrContext* context, con dti->fColorType, dti->fAlphaType, colorSpace); if (mipLevelCount == 1) { SkPixmap pixmap; - pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, - dti->fMipMapLevelData[0].fRowBytes, colorTable.get()); - return SkImage::MakeTextureFromPixmap(context, pixmap, budgeted); + pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, dti->fMipMapLevelData[0].fRowBytes); + + // Use the NoCheck version because we have already validated the SkImage. The |data| + // used to be an SkImage before calling getDeferredTextureImageData(). In legacy mode, + // getDeferredTextureImageData() will allow parametric transfer functions for images + // generated from codecs - which is slightly more lenient than typical SkImage + // constructors. + sk_sp proxy(GrUploadPixmapToTextureProxyNoCheck( + context->resourceProvider(), pixmap, budgeted)); + if (!proxy) { + return nullptr; + } + return sk_make_sp(context, kNeedNewImageUniqueID, pixmap.alphaType(), + std::move(proxy), std::move(colorSpace), budgeted); } else { - SkAutoTDeleteArray texels(new GrMipLevel[mipLevelCount]); + std::unique_ptr texels(new GrMipLevel[mipLevelCount]); for (int i = 0; i < mipLevelCount; i++) { texels[i].fPixels = dti->fMipMapLevelData[i].fPixelData; texels[i].fRowBytes = dti->fMipMapLevelData[i].fRowBytes; @@ -681,7 +843,7 @@ sk_sp SkImage::MakeFromDeferredTextureImageData(GrContext* context, con return SkImage::MakeTextureFromMipMap(context, info, texels.get(), mipLevelCount, SkBudgeted::kYes, - dti->fGammaTreatment); + dti->fColorMode); } } @@ -690,16 +852,52 @@ sk_sp SkImage::MakeFromDeferredTextureImageData(GrContext* context, con sk_sp SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo& info, const GrMipLevel* texels, int mipLevelCount, SkBudgeted budgeted, - SkSourceGammaTreatment gammaTreatment) { + SkDestinationSurfaceColorMode colorMode) { + SkASSERT(mipLevelCount >= 1); if (!ctx) { return nullptr; } - SkAutoTUnref texture(GrUploadMipMapToTexture(ctx, info, texels, mipLevelCount)); - if (!texture) { + sk_sp proxy(GrUploadMipMapToTextureProxy(ctx, info, texels, mipLevelCount, + colorMode)); + if (!proxy) { return nullptr; } - texture->texturePriv().setGammaTreatment(gammaTreatment); - return sk_make_sp(texture->width(), texture->height(), kNeedNewImageUniqueID, - info.alphaType(), texture, sk_ref_sp(info.colorSpace()), - budgeted); + + SkASSERT(proxy->priv().isExact()); + return sk_make_sp(ctx, kNeedNewImageUniqueID, + info.alphaType(), std::move(proxy), + info.refColorSpace(), budgeted); +} + +sk_sp SkImage_Gpu::onMakeColorSpace(sk_sp colorSpace) const { + sk_sp srcSpace = fColorSpace ? fColorSpace : SkColorSpace::MakeSRGB(); + auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), colorSpace.get()); + if (!xform) { + return sk_ref_sp(const_cast(this)); + } + + sk_sp renderTargetContext(fContext->makeRenderTargetContext( + SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, nullptr)); + if (!renderTargetContext) { + return nullptr; + } + + GrPaint paint; + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + paint.addColorTextureProcessor(fContext->resourceProvider(), fProxy, nullptr, SkMatrix::I()); + paint.addColorFragmentProcessor(std::move(xform)); + + const SkRect rect = SkRect::MakeIWH(this->width(), this->height()); + + renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect); + + if (!renderTargetContext->asTextureProxy()) { + return nullptr; + } + + // MDB: this call is okay bc we know 'renderTargetContext' was exact + return sk_make_sp(fContext, kNeedNewImageUniqueID, + fAlphaType, renderTargetContext->asTextureProxyRef(), + std::move(colorSpace), fBudgeted); + } diff --git a/gfx/skia/skia/src/image/SkImage_Gpu.h b/gfx/skia/skia/src/image/SkImage_Gpu.h index 02260bcca5d3..8c3df394f3ac 100644 --- a/gfx/skia/skia/src/image/SkImage_Gpu.h +++ b/gfx/skia/skia/src/image/SkImage_Gpu.h @@ -8,55 +8,69 @@ #ifndef SkImage_Gpu_DEFINED #define SkImage_Gpu_DEFINED -#include "SkAtomics.h" -#include "GrTexture.h" +#include "GrClip.h" +#include "GrContext.h" #include "GrGpuResourcePriv.h" +#include "GrSurfaceProxyPriv.h" +#include "GrTexture.h" +#include "SkAtomics.h" #include "SkBitmap.h" #include "SkGr.h" -#include "SkImage_Base.h" #include "SkImagePriv.h" +#include "SkImage_Base.h" #include "SkSurface.h" class SkImage_Gpu : public SkImage_Base { public: - /** - * An "image" can be a subset/window into a larger texture, so we explicit take the - * width and height. - */ - SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType, GrTexture*, sk_sp, - SkBudgeted); + SkImage_Gpu(GrContext*, uint32_t uniqueID, SkAlphaType, sk_sp, + sk_sp, SkBudgeted); ~SkImage_Gpu() override; SkImageInfo onImageInfo() const override; SkAlphaType onAlphaType() const override { return fAlphaType; } - void applyBudgetDecision() const { - if (SkBudgeted::kYes == fBudgeted) { - fTexture->resourcePriv().makeBudgeted(); - } else { - fTexture->resourcePriv().makeUnbudgeted(); - } - } - - bool getROPixels(SkBitmap*, CachingHint) const override; - GrTexture* asTextureRef(GrContext* ctx, const GrTextureParams& params, - SkSourceGammaTreatment) const override; + bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override; sk_sp onMakeSubset(const SkIRect&) const override; - GrTexture* peekTexture() const override { return fTexture; } - sk_sp refPinnedTexture(uint32_t* uniqueID) const override { - *uniqueID = this->uniqueID(); - return sk_ref_sp(fTexture.get()); + GrTextureProxy* peekProxy() const override { + return fProxy.get(); } + GrTexture* peekTexture() const override { + return fProxy->instantiate(fContext->resourceProvider()); + } + sk_sp asTextureProxyRef() const override { + return fProxy; + } + sk_sp asTextureProxyRef(GrContext*, const GrSamplerParams&, SkColorSpace*, + sk_sp*, + SkScalar scaleAdjust[2]) const override; + + sk_sp refPinnedTextureProxy(uint32_t* uniqueID) const override { + *uniqueID = this->uniqueID(); + return fProxy; + } + GrBackendObject onGetTextureHandle(bool flushPendingGrContextIO, + GrSurfaceOrigin* origin) const override; + GrTexture* onGetTexture() const override; + + bool onReadYUV8Planes(const SkISize sizes[3], void* const planes[3], + const size_t rowBytes[3], SkYUVColorSpace colorSpace) const override; + bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint) const override; + GrContext* context() { return fContext; } + sk_sp refColorSpace() { return fColorSpace; } + + sk_sp onMakeColorSpace(sk_sp) const override; + private: - SkAutoTUnref fTexture; - const SkAlphaType fAlphaType; - const SkBudgeted fBudgeted; - sk_sp fColorSpace; - mutable SkAtomic fAddedRasterVersionToCache; + GrContext* fContext; + sk_sp fProxy; + const SkAlphaType fAlphaType; + const SkBudgeted fBudgeted; + sk_sp fColorSpace; + mutable SkAtomic fAddedRasterVersionToCache; typedef SkImage_Base INHERITED; diff --git a/gfx/skia/skia/src/image/SkImage_Raster.cpp b/gfx/skia/skia/src/image/SkImage_Raster.cpp index 5799f0b3ef93..1aca5a9c5233 100644 --- a/gfx/skia/skia/src/image/SkImage_Raster.cpp +++ b/gfx/skia/skia/src/image/SkImage_Raster.cpp @@ -9,17 +9,20 @@ #include "SkBitmap.h" #include "SkBitmapProcShader.h" #include "SkCanvas.h" +#include "SkColorSpaceXform_Base.h" +#include "SkColorSpaceXformPriv.h" #include "SkColorTable.h" #include "SkData.h" #include "SkImagePriv.h" #include "SkPixelRef.h" #include "SkSurface.h" +#include "SkTLazy.h" +#include "SkUnPreMultiplyPriv.h" #if SK_SUPPORT_GPU #include "GrContext.h" -#include "GrImageIDTextureAdjuster.h" +#include "GrTextureAdjuster.h" #include "SkGr.h" -#include "SkGrPriv.h" #endif // fixes https://bug.skia.org/5096 @@ -74,7 +77,7 @@ public: } SkImage_Raster(const SkImageInfo&, sk_sp, size_t rb, SkColorTable*); - virtual ~SkImage_Raster(); + ~SkImage_Raster() override; SkImageInfo onImageInfo() const override { return fBitmap.info(); @@ -87,14 +90,14 @@ public: bool onPeekPixels(SkPixmap*) const override; const SkBitmap* onPeekBitmap() const override { return &fBitmap; } - SkData* onRefEncoded(GrContext*) const override; - bool getROPixels(SkBitmap*, CachingHint) const override; - GrTexture* asTextureRef(GrContext*, const GrTextureParams&, - SkSourceGammaTreatment) const override; - sk_sp onMakeSubset(const SkIRect&) const override; +#if SK_SUPPORT_GPU + sk_sp asTextureProxyRef(GrContext*, const GrSamplerParams&, + SkColorSpace*, sk_sp*, + SkScalar scaleAdjust[2]) const override; +#endif - // exposed for SkSurface_Raster via SkNewImageFromPixelRef - SkImage_Raster(const SkImageInfo&, SkPixelRef*, const SkIPoint& origin, size_t rowBytes); + bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override; + sk_sp onMakeSubset(const SkIRect&) const override; SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); } @@ -114,13 +117,11 @@ public: SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable()); } - bool onIsLazyGenerated() const override { - return fBitmap.pixelRef() && fBitmap.pixelRef()->isLazyGenerated(); - } + sk_sp onMakeColorSpace(sk_sp) const override; #if SK_SUPPORT_GPU - sk_sp refPinnedTexture(uint32_t* uniqueID) const override; - void onPinAsTexture(GrContext*) const override; + sk_sp refPinnedTextureProxy(uint32_t* uniqueID) const override; + bool onPinAsTexture(GrContext*) const override; void onUnpinAsTexture(GrContext*) const override; #endif @@ -128,7 +129,7 @@ private: SkBitmap fBitmap; #if SK_SUPPORT_GPU - mutable sk_sp fPinnedTexture; + mutable sk_sp fPinnedProxy; mutable int32_t fPinnedCount = 0; mutable uint32_t fPinnedUniqueID = 0; #endif @@ -154,19 +155,9 @@ SkImage_Raster::SkImage_Raster(const Info& info, sk_sp data, size_t rowB fBitmap.lockPixels(); } -SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, const SkIPoint& pixelRefOrigin, - size_t rowBytes) - : INHERITED(info.width(), info.height(), pr->getGenerationID()) -{ - fBitmap.setInfo(info, rowBytes); - fBitmap.setPixelRef(pr, pixelRefOrigin); - fBitmap.lockPixels(); - SkASSERT(fBitmap.isImmutable()); -} - SkImage_Raster::~SkImage_Raster() { #if SK_SUPPORT_GPU - SkASSERT(nullptr == fPinnedTexture.get()); // want the caller to have manually unpinned + SkASSERT(nullptr == fPinnedProxy.get()); // want the caller to have manually unpinned #endif } @@ -180,83 +171,76 @@ bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const { return fBitmap.peekPixels(pm); } -SkData* SkImage_Raster::onRefEncoded(GrContext*) const { - SkPixelRef* pr = fBitmap.pixelRef(); - const SkImageInfo prInfo = pr->info(); - const SkImageInfo bmInfo = fBitmap.info(); - - // we only try if we (the image) cover the entire area of the pixelRef - if (prInfo.width() == bmInfo.width() && prInfo.height() == bmInfo.height()) { - return pr->refEncodedData(); - } - return nullptr; -} - -bool SkImage_Raster::getROPixels(SkBitmap* dst, CachingHint) const { +bool SkImage_Raster::getROPixels(SkBitmap* dst, SkColorSpace* dstColorSpace, CachingHint) const { *dst = fBitmap; return true; } -GrTexture* SkImage_Raster::asTextureRef(GrContext* ctx, const GrTextureParams& params, - SkSourceGammaTreatment gammaTreatment) const { #if SK_SUPPORT_GPU - if (!ctx) { +sk_sp SkImage_Raster::asTextureProxyRef(GrContext* context, + const GrSamplerParams& params, + SkColorSpace* dstColorSpace, + sk_sp* texColorSpace, + SkScalar scaleAdjust[2]) const { + if (!context) { return nullptr; } - uint32_t uniqueID; - sk_sp tex = this->refPinnedTexture(&uniqueID); - if (tex) { - GrTextureAdjuster adjuster(fPinnedTexture.get(), fBitmap.alphaType(), fBitmap.bounds(), - fPinnedUniqueID, fBitmap.colorSpace()); - return adjuster.refTextureSafeForParams(params, gammaTreatment, nullptr); + if (texColorSpace) { + *texColorSpace = sk_ref_sp(fBitmap.colorSpace()); } - return GrRefCachedBitmapTexture(ctx, fBitmap, params, gammaTreatment); -#endif + uint32_t uniqueID; + sk_sp tex = this->refPinnedTextureProxy(&uniqueID); + if (tex) { + GrTextureAdjuster adjuster(context, fPinnedProxy, + fBitmap.alphaType(), fBitmap.bounds(), + fPinnedUniqueID, fBitmap.colorSpace()); + return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust); + } - return nullptr; + return GrRefCachedBitmapTextureProxy(context, fBitmap, params, scaleAdjust); } +#endif #if SK_SUPPORT_GPU -sk_sp SkImage_Raster::refPinnedTexture(uint32_t* uniqueID) const { - if (fPinnedTexture) { +sk_sp SkImage_Raster::refPinnedTextureProxy(uint32_t* uniqueID) const { + if (fPinnedProxy) { SkASSERT(fPinnedCount > 0); SkASSERT(fPinnedUniqueID != 0); *uniqueID = fPinnedUniqueID; - return fPinnedTexture; + return fPinnedProxy; } return nullptr; } -void SkImage_Raster::onPinAsTexture(GrContext* ctx) const { - if (fPinnedTexture) { +bool SkImage_Raster::onPinAsTexture(GrContext* ctx) const { + if (fPinnedProxy) { SkASSERT(fPinnedCount > 0); SkASSERT(fPinnedUniqueID != 0); - SkASSERT(fPinnedTexture->getContext() == ctx); } else { SkASSERT(fPinnedCount == 0); SkASSERT(fPinnedUniqueID == 0); - fPinnedTexture.reset(GrRefCachedBitmapTexture(ctx, fBitmap, - GrTextureParams::ClampNoFilter(), - SkSourceGammaTreatment::kRespect)); + fPinnedProxy = GrRefCachedBitmapTextureProxy(ctx, fBitmap, + GrSamplerParams::ClampNoFilter(), nullptr); + if (!fPinnedProxy) { + return false; + } fPinnedUniqueID = fBitmap.getGenerationID(); } - // Note: we always increment, even if we failed to create the pinned texture + // Note: we only increment if the texture was successfully pinned ++fPinnedCount; + return true; } void SkImage_Raster::onUnpinAsTexture(GrContext* ctx) const { // Note: we always decrement, even if fPinnedTexture is null SkASSERT(fPinnedCount > 0); SkASSERT(fPinnedUniqueID != 0); - if (fPinnedTexture) { - SkASSERT(fPinnedTexture->getContext() == ctx); - } if (0 == --fPinnedCount) { - fPinnedTexture.reset(nullptr); + fPinnedProxy.reset(nullptr); fPinnedUniqueID = 0; } } @@ -310,7 +294,9 @@ sk_sp SkImage::MakeRasterData(const SkImageInfo& info, sk_sp da sk_sp SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc, ReleaseContext ctx) { size_t size; - if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), false, &size) || !pmap.addr()) { + if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), pmap.ctable(), &size) || + !pmap.addr()) + { return nullptr; } @@ -318,16 +304,7 @@ sk_sp SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc p return sk_make_sp(pmap.info(), std::move(data), pmap.rowBytes(), pmap.ctable()); } -sk_sp SkMakeImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr, - const SkIPoint& pixelRefOrigin, size_t rowBytes) { - if (!SkImage_Raster::ValidArgs(info, rowBytes, false, nullptr)) { - return nullptr; - } - return sk_make_sp(info, pr, pixelRefOrigin, rowBytes); -} - -sk_sp SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm, - SkTBlitterAllocator* allocator) { +sk_sp SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) { bool hasColorTable = false; if (kIndex_8_SkColorType == bm.colorType()) { SkAutoLockPixels autoLockPixels(bm); @@ -338,23 +315,17 @@ sk_sp SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode return nullptr; } - sk_sp image; if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) { SkBitmap tmp(bm); tmp.lockPixels(); SkPixmap pmap; if (tmp.getPixels() && tmp.peekPixels(&pmap)) { - image = SkImage::MakeRasterCopy(pmap); + return SkImage::MakeRasterCopy(pmap); } } else { - if (allocator) { - image.reset(allocator->createT(bm, kNever_SkCopyPixelsMode == cpm)); - image.get()->ref(); // account for the allocator being an owner - } else { - image = sk_make_sp(bm, kNever_SkCopyPixelsMode == cpm); - } + return sk_make_sp(bm, kNever_SkCopyPixelsMode == cpm); } - return image; + return sk_sp(); } const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) { @@ -369,9 +340,81 @@ bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) c // (thus changing our state). if (fBitmap.isImmutable()) { bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes()); - bitmap->setPixelRef(fBitmap.pixelRef(), fBitmap.pixelRefOrigin()); + bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()), + fBitmap.pixelRefOrigin().x(), + fBitmap.pixelRefOrigin().y()); return true; } } return this->INHERITED::onAsLegacyBitmap(bitmap, mode); } + +/////////////////////////////////////////////////////////////////////////////// + +static inline void do_color_xform_non_linear_blending(SkBitmap* dst, const SkPixmap& src) { + SkDEBUGCODE(SkColorSpaceTransferFn fn;); + SkASSERT(dst->colorSpace()->isNumericalTransferFn(&fn) && + src.colorSpace()->isNumericalTransferFn(&fn)); + + void* dstPixels = dst->getPixels(); + const void* srcPixels = src.addr(); + size_t dstRowBytes = dst->rowBytes(); + size_t srcRowBytes = src.rowBytes(); + if (kN32_SkColorType != src.colorType()) { + SkAssertResult(src.readPixels(src.info().makeColorType(kN32_SkColorType), dstPixels, + dstRowBytes, 0, 0)); + + srcPixels = dstPixels; + srcRowBytes = dstRowBytes; + } + + std::unique_ptr xform = SkColorSpaceXform_Base::New( + src.colorSpace(), dst->colorSpace(), SkTransferFunctionBehavior::kIgnore); + + void* dstRow = dstPixels; + const void* srcRow = srcPixels; + for (int y = 0; y < dst->height(); y++) { + // This function assumes non-linear blending. Which means that we must start by + // unpremultiplying in the gamma encoded space. + const void* tmpRow = srcRow; + if (kPremul_SkAlphaType == src.alphaType()) { + SkUnpremultiplyRow((uint32_t*) dstRow, (const uint32_t*) srcRow, dst->width()); + tmpRow = dstRow; + } + + SkColorSpaceXform::ColorFormat fmt = select_xform_format(kN32_SkColorType); + SkAssertResult(xform->apply(fmt, dstRow, fmt, tmpRow, dst->width(), dst->alphaType())); + + dstRow = SkTAddOffset(dstRow, dstRowBytes); + srcRow = SkTAddOffset(srcRow, srcRowBytes); + } +} + +sk_sp SkImage_Raster::onMakeColorSpace(sk_sp target) const { + // Force the color type of the new image to be kN32_SkColorType. + // (1) This means we lose precision on F16 images. This is necessary while this function is + // used to pre-transform inputs to a legacy canvas. Legacy canvases do not handle F16. + // (2) kIndex8 and kGray8 must be expanded in order perform a color space transformation. + // (3) Seems reasonable to expand k565 and k4444. It's nice to avoid these color types for + // clients who opt into color space support. + SkImageInfo dstInfo = fBitmap.info().makeColorType(kN32_SkColorType).makeColorSpace(target); + SkBitmap dst; + dst.allocPixels(dstInfo); + + SkPixmap src; + SkTLazy tmp; + if (!fBitmap.peekPixels(&src)) { + tmp.init(fBitmap); + tmp.get()->lockPixels(); + SkAssertResult(tmp.get()->peekPixels(&src)); + } + + // Treat nullptr srcs as sRGB. + if (!src.colorSpace()) { + src.setColorSpace(SkColorSpace::MakeSRGB()); + } + + do_color_xform_non_linear_blending(&dst, src); + dst.setImmutable(); + return SkImage::MakeFromBitmap(dst); +} diff --git a/gfx/skia/skia/src/image/SkSurface.cpp b/gfx/skia/skia/src/image/SkSurface.cpp index a0b9059e7033..55aab3e99239 100644 --- a/gfx/skia/skia/src/image/SkSurface.cpp +++ b/gfx/skia/skia/src/image/SkSurface.cpp @@ -56,17 +56,11 @@ SkSurfaceProps::SkSurfaceProps(const SkSurfaceProps& other) /////////////////////////////////////////////////////////////////////////////// SkSurface_Base::SkSurface_Base(int width, int height, const SkSurfaceProps* props) - : INHERITED(width, height, props) -{ - fCachedCanvas = nullptr; - fCachedImage = nullptr; + : INHERITED(width, height, props) { } SkSurface_Base::SkSurface_Base(const SkImageInfo& info, const SkSurfaceProps* props) - : INHERITED(info, props) -{ - fCachedCanvas = nullptr; - fCachedImage = nullptr; + : INHERITED(info, props) { } SkSurface_Base::~SkSurface_Base() { @@ -74,13 +68,10 @@ SkSurface_Base::~SkSurface_Base() { if (fCachedCanvas) { fCachedCanvas->setSurfaceBase(nullptr); } - - SkSafeUnref(fCachedImage); - SkSafeUnref(fCachedCanvas); } void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) { - auto image = this->makeImageSnapshot(SkBudgeted::kYes); + auto image = this->makeImageSnapshot(); if (image) { canvas->drawImage(image, x, y, paint); } @@ -106,8 +97,7 @@ void SkSurface_Base::aboutToDraw(ContentChangeMode mode) { // regardless of copy-on-write, we must drop our cached image now, so // that the next request will get our new contents. - fCachedImage->unref(); - fCachedImage = nullptr; + fCachedImage.reset(); if (unique) { // Our content isn't held by any image now, so we can consider that content mutable. @@ -163,14 +153,8 @@ SkCanvas* SkSurface::getCanvas() { return asSB(this)->getCachedCanvas(); } -sk_sp SkSurface::makeImageSnapshot(SkBudgeted budgeted) { - // the caller will call unref() to balance this - return asSB(this)->refCachedImage(budgeted, kNo_ForceUnique); -} - -sk_sp SkSurface::makeImageSnapshot(SkBudgeted budgeted, ForceUnique unique) { - // the caller will call unref() to balance this - return asSB(this)->refCachedImage(budgeted, unique); +sk_sp SkSurface::makeImageSnapshot() { + return asSB(this)->refCachedImage(); } sk_sp SkSurface::makeSurface(const SkImageInfo& info) { @@ -186,22 +170,6 @@ bool SkSurface::peekPixels(SkPixmap* pmap) { return this->getCanvas()->peekPixels(pmap); } -#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS -const void* SkSurface::peekPixels(SkImageInfo* info, size_t* rowBytes) { - SkPixmap pm; - if (this->peekPixels(&pm)) { - if (info) { - *info = pm.info(); - } - if (rowBytes) { - *rowBytes = pm.rowBytes(); - } - return pm.addr(); - } - return nullptr; -} -#endif - bool SkSurface::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY) { return this->getCanvas()->readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY); diff --git a/gfx/skia/skia/src/image/SkSurface_Base.h b/gfx/skia/skia/src/image/SkSurface_Base.h index 8351bb87e60c..1b0f9ff97524 100644 --- a/gfx/skia/skia/src/image/SkSurface_Base.h +++ b/gfx/skia/skia/src/image/SkSurface_Base.h @@ -43,7 +43,7 @@ public: * must faithfully represent the current contents, even if the surface * is changed after this called (e.g. it is drawn to via its canvas). */ - virtual sk_sp onNewImageSnapshot(SkBudgeted, SkCopyPixelsMode) = 0; + virtual sk_sp onNewImageSnapshot() = 0; /** * Default implementation: @@ -81,7 +81,7 @@ public: virtual void onPrepareForExternalIO() {} inline SkCanvas* getCachedCanvas(); - inline sk_sp refCachedImage(SkBudgeted, ForceUnique); + inline sk_sp refCachedImage(); bool hasCachedImage() const { return fCachedImage != nullptr; } @@ -89,8 +89,8 @@ public: uint32_t newGenerationID(); private: - SkCanvas* fCachedCanvas; - SkImage* fCachedImage; + std::unique_ptr fCachedCanvas; + sk_sp fCachedImage; void aboutToDraw(ContentChangeMode mode); @@ -106,31 +106,23 @@ private: SkCanvas* SkSurface_Base::getCachedCanvas() { if (nullptr == fCachedCanvas) { - fCachedCanvas = this->onNewCanvas(); + fCachedCanvas = std::unique_ptr(this->onNewCanvas()); if (fCachedCanvas) { fCachedCanvas->setSurfaceBase(this); } } - return fCachedCanvas; + return fCachedCanvas.get(); } -sk_sp SkSurface_Base::refCachedImage(SkBudgeted budgeted, ForceUnique unique) { - SkImage* snap = fCachedImage; - if (kYes_ForceUnique == unique && snap && !snap->unique()) { - snap = nullptr; - } - if (snap) { - return sk_ref_sp(snap); - } - SkCopyPixelsMode cpm = (kYes_ForceUnique == unique) ? kAlways_SkCopyPixelsMode : - kIfMutable_SkCopyPixelsMode; - snap = this->onNewImageSnapshot(budgeted, cpm).release(); - if (kNo_ForceUnique == unique) { - SkASSERT(!fCachedImage); - fCachedImage = SkSafeRef(snap); +sk_sp SkSurface_Base::refCachedImage() { + if (fCachedImage) { + return fCachedImage; } + + fCachedImage = this->onNewImageSnapshot(); + SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this); - return sk_sp(snap); + return fCachedImage; } #endif diff --git a/gfx/skia/skia/src/image/SkSurface_Gpu.cpp b/gfx/skia/skia/src/image/SkSurface_Gpu.cpp index 3007313118c9..cef355e0919b 100644 --- a/gfx/skia/skia/src/image/SkSurface_Gpu.cpp +++ b/gfx/skia/skia/src/image/SkSurface_Gpu.cpp @@ -8,8 +8,11 @@ #include "SkSurface_Gpu.h" #include "GrContextPriv.h" +#include "GrRenderTargetContextPriv.h" #include "GrResourceProvider.h" + #include "SkCanvas.h" +#include "SkColorSpace_Base.h" #include "SkGpuDevice.h" #include "SkImage_Base.h" #include "SkImage_Gpu.h" @@ -21,6 +24,7 @@ SkSurface_Gpu::SkSurface_Gpu(sk_sp device) : INHERITED(device->width(), device->height(), &device->surfaceProps()) , fDevice(std::move(device)) { + SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact()); } SkSurface_Gpu::~SkSurface_Gpu() { @@ -40,12 +44,15 @@ static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface, // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in. surface->getDevice()->flush(); - GrDrawContext* dc = surface->getDevice()->accessDrawContext(); - return dc->accessRenderTarget(); + GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext(); + return rtc->accessRenderTarget(); } GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) { GrRenderTarget* rt = prepare_rt_for_external_access(this, access); + if (!rt) { + return 0; + } GrTexture* texture = rt->asTexture(); if (texture) { return texture->getTextureHandle(); @@ -55,6 +62,9 @@ GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) { bool SkSurface_Gpu::onGetRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) { GrRenderTarget* rt = prepare_rt_for_external_access(this, access); + if (!rt) { + return false; + } *obj = rt->getRenderTargetHandle(); return true; } @@ -67,41 +77,61 @@ SkCanvas* SkSurface_Gpu::onNewCanvas() { } sk_sp SkSurface_Gpu::onNewSurface(const SkImageInfo& info) { - int sampleCount = fDevice->accessDrawContext()->numColorSamples(); - GrSurfaceOrigin origin = fDevice->accessDrawContext()->origin(); + int sampleCount = fDevice->accessRenderTargetContext()->numColorSamples(); + GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin(); // TODO: Make caller specify this (change virtual signature of onNewSurface). static const SkBudgeted kBudgeted = SkBudgeted::kNo; return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount, origin, &this->props()); } -sk_sp SkSurface_Gpu::onNewImageSnapshot(SkBudgeted budgeted, SkCopyPixelsMode cpm) { - GrRenderTarget* rt = fDevice->accessDrawContext()->accessRenderTarget(); - SkASSERT(rt); - GrTexture* tex = rt->asTexture(); - SkAutoTUnref copy; +sk_sp SkSurface_Gpu::onNewImageSnapshot() { + GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext(); + if (!rtc) { + return nullptr; + } + + GrContext* ctx = fDevice->context(); + + if (!rtc->asSurfaceProxy()) { + return nullptr; + } + + SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted(); + + sk_sp srcProxy = rtc->asTextureProxyRef(); // If the original render target is a buffer originally created by the client, then we don't // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid // copy-on-write. - if (kAlways_SkCopyPixelsMode == cpm || !tex || rt->resourcePriv().refsWrappedObjects()) { - GrSurfaceDesc desc = fDevice->accessDrawContext()->desc(); - GrContext* ctx = fDevice->context(); + if (!srcProxy || rtc->priv().refsWrappedObjects()) { + // MDB TODO: replace this with GrSurfaceProxy::Copy? + GrSurfaceDesc desc = rtc->desc(); desc.fFlags = desc.fFlags & ~kRenderTarget_GrSurfaceFlag; - copy.reset(ctx->textureProvider()->createTexture(desc, budgeted)); - if (!copy) { + + sk_sp copyCtx = ctx->contextPriv().makeDeferredSurfaceContext( + desc, + SkBackingFit::kExact, + budgeted); + if (!copyCtx) { return nullptr; } - if (!ctx->copySurface(copy, rt)) { + + if (!copyCtx->copy(rtc->asSurfaceProxy())) { return nullptr; } - tex = copy; + + srcProxy = copyCtx->asTextureProxyRef(); } + const SkImageInfo info = fDevice->imageInfo(); sk_sp image; - if (tex) { - image = sk_make_sp(info.width(), info.height(), kNeedNewImageUniqueID, - info.alphaType(), tex, sk_ref_sp(info.colorSpace()), - budgeted); + if (srcProxy) { + // The renderTargetContext coming out of SkGpuDevice should always be exact and the + // above copy creates a kExact surfaceContext. + SkASSERT(srcProxy->priv().isExact()); + image = sk_make_sp(ctx, kNeedNewImageUniqueID, + info.alphaType(), std::move(srcProxy), + info.refColorSpace(), budgeted); } return image; } @@ -110,21 +140,26 @@ sk_sp SkSurface_Gpu::onNewImageSnapshot(SkBudgeted budgeted, SkCopyPixe // render target into it. Note that this flushes the SkGpuDevice but // doesn't force an OpenGL flush. void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) { - GrRenderTarget* rt = fDevice->accessDrawContext()->accessRenderTarget(); + GrRenderTarget* rt = fDevice->accessRenderTargetContext()->accessRenderTarget(); + if (!rt) { + return; + } // are we sharing our render target with the image? Note this call should never create a new // image because onCopyOnWrite is only called when there is a cached image. - sk_sp image(this->refCachedImage(SkBudgeted::kNo, kNo_ForceUnique)); + sk_sp image(this->refCachedImage()); SkASSERT(image); - if (rt->asTexture() == as_IB(image)->peekTexture()) { - this->fDevice->replaceDrawContext(SkSurface::kRetain_ContentChangeMode == mode); - SkTextureImageApplyBudgetedDecision(image.get()); + // MDB TODO: this is unfortunate. The snapping of an Image_Gpu from a surface currently + // funnels down to a GrTexture. Once Image_Gpus are proxy-backed we should be able to + // compare proxy uniqueIDs. + if (rt->asTexture()->getTextureHandle() == image->getTextureHandle(false)) { + fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode); } else if (kDiscard_ContentChangeMode == mode) { this->SkSurface_Gpu::onDiscard(); } } void SkSurface_Gpu::onDiscard() { - fDevice->accessDrawContext()->discard(); + fDevice->accessRenderTargetContext()->discard(); } void SkSurface_Gpu::onPrepareForExternalIO() { @@ -136,7 +171,7 @@ void SkSurface_Gpu::onPrepareForExternalIO() { bool SkSurface_Gpu::Valid(const SkImageInfo& info) { switch (info.colorType()) { case kRGBA_F16_SkColorType: - return info.colorSpace() && info.colorSpace()->gammaIsLinear(); + return !info.colorSpace() || info.colorSpace()->gammaIsLinear(); case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: return !info.colorSpace() || info.colorSpace()->gammaCloseToSRGB(); @@ -148,7 +183,7 @@ bool SkSurface_Gpu::Valid(const SkImageInfo& info) { bool SkSurface_Gpu::Valid(GrContext* context, GrPixelConfig config, SkColorSpace* colorSpace) { switch (config) { case kRGBA_half_GrPixelConfig: - return colorSpace && colorSpace->gammaIsLinear(); + return !colorSpace || colorSpace->gammaIsLinear(); case kSRGBA_8888_GrPixelConfig: case kSBGRA_8888_GrPixelConfig: return context->caps()->srgbSupport() && colorSpace && colorSpace->gammaCloseToSRGB(); @@ -157,7 +192,7 @@ bool SkSurface_Gpu::Valid(GrContext* context, GrPixelConfig config, SkColorSpace // If we don't have sRGB support, we may get here with a color space. It still needs // to be sRGB-like (so that the application will work correctly on sRGB devices.) return !colorSpace || - (!context->caps()->srgbSupport() && colorSpace->gammaCloseToSRGB()); + (colorSpace->gammaCloseToSRGB() && !context->caps()->srgbSupport()); default: return !colorSpace; } @@ -192,16 +227,15 @@ sk_sp SkSurface::MakeFromBackendTexture(GrContext* context, return nullptr; } - sk_sp dc(context->contextPriv().makeBackendTextureDrawContext( + sk_sp rtc(context->contextPriv().makeBackendTextureRenderTargetContext( desc, std::move(colorSpace), - props, - kBorrow_GrWrapOwnership)); - if (!dc) { + props)); + if (!rtc) { return nullptr; } - sk_sp device(SkGpuDevice::Make(std::move(dc), desc.fWidth, desc.fHeight, + sk_sp device(SkGpuDevice::Make(context, std::move(rtc), desc.fWidth, desc.fHeight, SkGpuDevice::kUninit_InitContents)); if (!device) { return nullptr; @@ -220,15 +254,15 @@ sk_sp SkSurface::MakeFromBackendRenderTarget(GrContext* context, return nullptr; } - sk_sp dc(context->contextPriv().makeBackendRenderTargetDrawContext( - desc, - std::move(colorSpace), - props)); - if (!dc) { + sk_sp rtc( + context->contextPriv().makeBackendRenderTargetRenderTargetContext(desc, + std::move(colorSpace), + props)); + if (!rtc) { return nullptr; } - sk_sp device(SkGpuDevice::Make(std::move(dc), desc.fWidth, desc.fHeight, + sk_sp device(SkGpuDevice::Make(context, std::move(rtc), desc.fWidth, desc.fHeight, SkGpuDevice::kUninit_InitContents)); if (!device) { return nullptr; @@ -248,15 +282,16 @@ sk_sp SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* cont return nullptr; } - sk_sp dc(context->contextPriv().makeBackendTextureAsRenderTargetDrawContext( - desc, - std::move(colorSpace), - props)); - if (!dc) { + sk_sp rtc( + context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext( + desc, + std::move(colorSpace), + props)); + if (!rtc) { return nullptr; } - sk_sp device(SkGpuDevice::Make(std::move(dc), desc.fWidth, desc.fHeight, + sk_sp device(SkGpuDevice::Make(context, std::move(rtc), desc.fWidth, desc.fHeight, SkGpuDevice::kUninit_InitContents)); if (!device) { return nullptr; diff --git a/gfx/skia/skia/src/image/SkSurface_Gpu.h b/gfx/skia/skia/src/image/SkSurface_Gpu.h index b7088ea6f851..cc8b87dc41d3 100644 --- a/gfx/skia/skia/src/image/SkSurface_Gpu.h +++ b/gfx/skia/skia/src/image/SkSurface_Gpu.h @@ -17,13 +17,13 @@ class SkGpuDevice; class SkSurface_Gpu : public SkSurface_Base { public: SkSurface_Gpu(sk_sp); - virtual ~SkSurface_Gpu(); + ~SkSurface_Gpu() override; GrBackendObject onGetTextureHandle(BackendHandleAccess) override; bool onGetRenderTargetHandle(GrBackendObject*, BackendHandleAccess) override; SkCanvas* onNewCanvas() override; sk_sp onNewSurface(const SkImageInfo&) override; - sk_sp onNewImageSnapshot(SkBudgeted, SkCopyPixelsMode) override; + sk_sp onNewImageSnapshot() override; void onCopyOnWrite(ContentChangeMode) override; void onDiscard() override; void onPrepareForExternalIO() override; diff --git a/gfx/skia/skia/src/image/SkSurface_Raster.cpp b/gfx/skia/skia/src/image/SkSurface_Raster.cpp index 2b2bf645260e..92f53010613d 100644 --- a/gfx/skia/skia/src/image/SkSurface_Raster.cpp +++ b/gfx/skia/skia/src/image/SkSurface_Raster.cpp @@ -20,11 +20,11 @@ public: SkSurface_Raster(const SkImageInfo&, void*, size_t rb, void (*releaseProc)(void* pixels, void* context), void* context, const SkSurfaceProps*); - SkSurface_Raster(SkPixelRef*, const SkSurfaceProps*); + SkSurface_Raster(sk_sp, const SkSurfaceProps*); SkCanvas* onNewCanvas() override; sk_sp onNewSurface(const SkImageInfo&) override; - sk_sp onNewImageSnapshot(SkBudgeted, SkCopyPixelsMode) override; + sk_sp onNewImageSnapshot() override; void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override; void onCopyOnWrite(ContentChangeMode) override; void onRestoreBackingMutability() override; @@ -67,7 +67,7 @@ bool SkSurface_Raster::Valid(const SkImageInfo& info, size_t rowBytes) { shift = 2; break; case kRGBA_F16_SkColorType: - if (!info.colorSpace() || !info.colorSpace()->gammaIsLinear()) { + if (info.colorSpace() && !info.colorSpace()->gammaIsLinear()) { return false; } shift = 3; @@ -108,14 +108,14 @@ SkSurface_Raster::SkSurface_Raster(const SkImageInfo& info, void* pixels, size_t fWeOwnThePixels = false; // We are "Direct" } -SkSurface_Raster::SkSurface_Raster(SkPixelRef* pr, const SkSurfaceProps* props) +SkSurface_Raster::SkSurface_Raster(sk_sp pr, const SkSurfaceProps* props) : INHERITED(pr->info().width(), pr->info().height(), props) { const SkImageInfo& info = pr->info(); fBitmap.setInfo(info, pr->rowBytes()); - fBitmap.setPixelRef(pr); fRowBytes = pr->rowBytes(); // we track this, so that subsequent re-allocs will match + fBitmap.setPixelRef(std::move(pr), 0, 0); fWeOwnThePixels = true; } @@ -130,7 +130,8 @@ void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, canvas->drawBitmap(fBitmap, x, y, paint); } -sk_sp SkSurface_Raster::onNewImageSnapshot(SkBudgeted, SkCopyPixelsMode cpm) { +sk_sp SkSurface_Raster::onNewImageSnapshot() { + SkCopyPixelsMode cpm = kIfMutable_SkCopyPixelsMode; if (fWeOwnThePixels) { // SkImage_raster requires these pixels are immutable for its full lifetime. // We'll undo this via onRestoreBackingMutability() if we can avoid the COW. @@ -155,7 +156,7 @@ void SkSurface_Raster::onRestoreBackingMutability() { void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) { // are we sharing pixelrefs with the image? - sk_sp cached(this->refCachedImage(SkBudgeted::kNo, kNo_ForceUnique)); + sk_sp cached(this->refCachedImage()); SkASSERT(cached); if (SkBitmapImageGetPixelRef(cached.get()) == fBitmap.pixelRef()) { SkASSERT(fWeOwnThePixels); @@ -208,16 +209,12 @@ sk_sp SkSurface::MakeRaster(const SkImageInfo& info, size_t rowBytes, return nullptr; } - // If the requested alpha type is opaque, then leave the pixels uninitialized. - // Alpha formats can be safely initialiezd to zero. - SkAutoTUnref pr(info.isOpaque() - ? SkMallocPixelRef::NewAllocate(info, rowBytes, nullptr) - : SkMallocPixelRef::NewZeroed(info, rowBytes, nullptr)); - if (nullptr == pr.get()) { + sk_sp pr = SkMallocPixelRef::MakeZeroed(info, rowBytes, nullptr); + if (!pr) { return nullptr; } if (rowBytes) { SkASSERT(pr->rowBytes() == rowBytes); } - return sk_make_sp(pr, props); + return sk_make_sp(std::move(pr), props); } diff --git a/gfx/skia/skia/src/images/SkForceLinking.cpp b/gfx/skia/skia/src/images/SkForceLinking.cpp deleted file mode 100644 index 81d485c882fe..000000000000 --- a/gfx/skia/skia/src/images/SkForceLinking.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkImageEncoder.h" -#include "SkForceLinking.h" - -// This method is required to fool the linker into not discarding the pre-main -// initialization and registration of the encoder classes. Passing true will -// cause memory leaks. -int SkForceLinking(bool doNotPassTrue) { - if (doNotPassTrue) { - SkASSERT(false); -#if defined(SK_HAS_JPEG_LIBRARY) && !defined(SK_USE_CG_ENCODER) && !defined(SK_USE_WIC_ENCODER) - CreateJPEGImageEncoder(); -#endif -#if defined(SK_HAS_WEBP_LIBRARY) && !defined(SK_USE_CG_ENCODER) && !defined(SK_USE_WIC_ENCODER) - CreateWEBPImageEncoder(); -#endif -#if defined(SK_HAS_PNG_LIBRARY) && !defined(SK_USE_CG_ENCODER) && !defined(SK_USE_WIC_ENCODER) - CreatePNGImageEncoder(); -#endif - - // Only link hardware texture codecs on platforms that build them. See images.gyp -#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK - CreateKTXImageEncoder(); -#endif - -#if defined (SK_USE_CG_ENCODER) - CreateImageEncoder_CG(SkImageEncoder::kPNG_Type); -#endif -#if defined (SK_USE_WIC_ENCODER) - CreateImageEncoder_WIC(SkImageEncoder::kPNG_Type); -#endif - return -1; - } - return 0; -} diff --git a/gfx/skia/skia/src/images/SkGIFMovie.cpp b/gfx/skia/skia/src/images/SkGIFMovie.cpp deleted file mode 100644 index 00df53d237ed..000000000000 --- a/gfx/skia/skia/src/images/SkGIFMovie.cpp +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkMovie.h" -#include "SkColor.h" -#include "SkColorPriv.h" -#include "SkStream.h" -#include "SkTemplates.h" -#include "SkUtils.h" - -#include "gif_lib.h" - -#if GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0) -#define DGifCloseFile(a, b) DGifCloseFile(a) -#endif - -class SkGIFMovie : public SkMovie { -public: - SkGIFMovie(SkStream* stream); - virtual ~SkGIFMovie(); - -protected: - virtual bool onGetInfo(Info*); - virtual bool onSetTime(SkMSec); - virtual bool onGetBitmap(SkBitmap*); - -private: - GifFileType* fGIF; - int fCurrIndex; - int fLastDrawIndex; - SkBitmap fBackup; - SkColor fPaintingColor; -}; - -static int Decode(GifFileType* fileType, GifByteType* out, int size) { - SkStream* stream = (SkStream*) fileType->UserData; - return (int) stream->read(out, size); -} - -SkGIFMovie::SkGIFMovie(SkStream* stream) -{ -#if GIFLIB_MAJOR < 5 - fGIF = DGifOpen( stream, Decode ); -#else - fGIF = DGifOpen( stream, Decode, nullptr ); -#endif - if (nullptr == fGIF) - return; - - if (DGifSlurp(fGIF) != GIF_OK) - { - DGifCloseFile(fGIF, nullptr); - fGIF = nullptr; - } - fCurrIndex = -1; - fLastDrawIndex = -1; - fPaintingColor = SkPackARGB32(0, 0, 0, 0); -} - -SkGIFMovie::~SkGIFMovie() -{ - if (fGIF) - DGifCloseFile(fGIF, nullptr); -} - -static SkMSec savedimage_duration(const SavedImage* image) -{ - for (int j = 0; j < image->ExtensionBlockCount; j++) - { - if (image->ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE) - { - SkASSERT(image->ExtensionBlocks[j].ByteCount >= 4); - const uint8_t* b = (const uint8_t*)image->ExtensionBlocks[j].Bytes; - return ((b[2] << 8) | b[1]) * 10; - } - } - return 0; -} - -bool SkGIFMovie::onGetInfo(Info* info) -{ - if (nullptr == fGIF) - return false; - - SkMSec dur = 0; - for (int i = 0; i < fGIF->ImageCount; i++) - dur += savedimage_duration(&fGIF->SavedImages[i]); - - info->fDuration = dur; - info->fWidth = fGIF->SWidth; - info->fHeight = fGIF->SHeight; - info->fIsOpaque = false; // how to compute? - return true; -} - -bool SkGIFMovie::onSetTime(SkMSec time) -{ - if (nullptr == fGIF) - return false; - - SkMSec dur = 0; - for (int i = 0; i < fGIF->ImageCount; i++) - { - dur += savedimage_duration(&fGIF->SavedImages[i]); - if (dur >= time) - { - fCurrIndex = i; - return fLastDrawIndex != fCurrIndex; - } - } - fCurrIndex = fGIF->ImageCount - 1; - return true; -} - -static void copyLine(uint32_t* dst, const unsigned char* src, const ColorMapObject* cmap, - int transparent, int width) -{ - for (; width > 0; width--, src++, dst++) { - if (*src != transparent) { - const GifColorType& col = cmap->Colors[*src]; - *dst = SkPackARGB32(0xFF, col.Red, col.Green, col.Blue); - } - } -} - -#if GIFLIB_MAJOR < 5 -static void copyInterlaceGroup(SkBitmap* bm, const unsigned char*& src, - const ColorMapObject* cmap, int transparent, int copyWidth, - int copyHeight, const GifImageDesc& imageDesc, int rowStep, - int startRow) -{ - int row; - // every 'rowStep'th row, starting with row 'startRow' - for (row = startRow; row < copyHeight; row += rowStep) { - uint32_t* dst = bm->getAddr32(imageDesc.Left, imageDesc.Top + row); - copyLine(dst, src, cmap, transparent, copyWidth); - src += imageDesc.Width; - } - - // pad for rest height - src += imageDesc.Width * ((imageDesc.Height - row + rowStep - 1) / rowStep); -} - -static void blitInterlace(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap, - int transparent) -{ - int width = bm->width(); - int height = bm->height(); - GifWord copyWidth = frame->ImageDesc.Width; - if (frame->ImageDesc.Left + copyWidth > width) { - copyWidth = width - frame->ImageDesc.Left; - } - - GifWord copyHeight = frame->ImageDesc.Height; - if (frame->ImageDesc.Top + copyHeight > height) { - copyHeight = height - frame->ImageDesc.Top; - } - - // deinterlace - const unsigned char* src = (unsigned char*)frame->RasterBits; - - // group 1 - every 8th row, starting with row 0 - copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 0); - - // group 2 - every 8th row, starting with row 4 - copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 4); - - // group 3 - every 4th row, starting with row 2 - copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 4, 2); - - copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 2, 1); -} -#endif - -static void blitNormal(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap, - int transparent) -{ - int width = bm->width(); - int height = bm->height(); - const unsigned char* src = (unsigned char*)frame->RasterBits; - uint32_t* dst = bm->getAddr32(frame->ImageDesc.Left, frame->ImageDesc.Top); - GifWord copyWidth = frame->ImageDesc.Width; - if (frame->ImageDesc.Left + copyWidth > width) { - copyWidth = width - frame->ImageDesc.Left; - } - - GifWord copyHeight = frame->ImageDesc.Height; - if (frame->ImageDesc.Top + copyHeight > height) { - copyHeight = height - frame->ImageDesc.Top; - } - - for (; copyHeight > 0; copyHeight--) { - copyLine(dst, src, cmap, transparent, copyWidth); - src += frame->ImageDesc.Width; - dst += width; - } -} - -static void fillRect(SkBitmap* bm, GifWord left, GifWord top, GifWord width, GifWord height, - uint32_t col) -{ - int bmWidth = bm->width(); - int bmHeight = bm->height(); - uint32_t* dst = bm->getAddr32(left, top); - GifWord copyWidth = width; - if (left + copyWidth > bmWidth) { - copyWidth = bmWidth - left; - } - - GifWord copyHeight = height; - if (top + copyHeight > bmHeight) { - copyHeight = bmHeight - top; - } - - for (; copyHeight > 0; copyHeight--) { - sk_memset32(dst, col, copyWidth); - dst += bmWidth; - } -} - -static void drawFrame(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap) -{ - int transparent = -1; - - for (int i = 0; i < frame->ExtensionBlockCount; ++i) { - ExtensionBlock* eb = frame->ExtensionBlocks + i; - if (eb->Function == GRAPHICS_EXT_FUNC_CODE && - eb->ByteCount == 4) { - bool has_transparency = ((eb->Bytes[0] & 1) == 1); - if (has_transparency) { - transparent = (unsigned char)eb->Bytes[3]; - } - } - } - - if (frame->ImageDesc.ColorMap != nullptr) { - // use local color table - cmap = frame->ImageDesc.ColorMap; - } - - if (cmap == nullptr || cmap->ColorCount != (1 << cmap->BitsPerPixel)) { - SkDEBUGFAIL("bad colortable setup"); - return; - } - -#if GIFLIB_MAJOR < 5 - // before GIFLIB 5, de-interlacing wasn't done by library at load time - if (frame->ImageDesc.Interlace) { - blitInterlace(bm, frame, cmap, transparent); - return; - } -#endif - - blitNormal(bm, frame, cmap, transparent); -} - -static bool checkIfWillBeCleared(const SavedImage* frame) -{ - for (int i = 0; i < frame->ExtensionBlockCount; ++i) { - ExtensionBlock* eb = frame->ExtensionBlocks + i; - if (eb->Function == GRAPHICS_EXT_FUNC_CODE && - eb->ByteCount == 4) { - // check disposal method - int disposal = ((eb->Bytes[0] >> 2) & 7); - if (disposal == 2 || disposal == 3) { - return true; - } - } - } - return false; -} - -static void getTransparencyAndDisposalMethod(const SavedImage* frame, bool* trans, int* disposal) -{ - *trans = false; - *disposal = 0; - for (int i = 0; i < frame->ExtensionBlockCount; ++i) { - ExtensionBlock* eb = frame->ExtensionBlocks + i; - if (eb->Function == GRAPHICS_EXT_FUNC_CODE && - eb->ByteCount == 4) { - *trans = ((eb->Bytes[0] & 1) == 1); - *disposal = ((eb->Bytes[0] >> 2) & 7); - } - } -} - -// return true if area of 'target' is completely covers area of 'covered' -static bool checkIfCover(const SavedImage* target, const SavedImage* covered) -{ - if (target->ImageDesc.Left <= covered->ImageDesc.Left - && covered->ImageDesc.Left + covered->ImageDesc.Width <= - target->ImageDesc.Left + target->ImageDesc.Width - && target->ImageDesc.Top <= covered->ImageDesc.Top - && covered->ImageDesc.Top + covered->ImageDesc.Height <= - target->ImageDesc.Top + target->ImageDesc.Height) { - return true; - } - return false; -} - -static void disposeFrameIfNeeded(SkBitmap* bm, const SavedImage* cur, const SavedImage* next, - SkBitmap* backup, SkColor color) -{ - // We can skip disposal process if next frame is not transparent - // and completely covers current area - bool curTrans; - int curDisposal; - getTransparencyAndDisposalMethod(cur, &curTrans, &curDisposal); - bool nextTrans; - int nextDisposal; - getTransparencyAndDisposalMethod(next, &nextTrans, &nextDisposal); - if ((curDisposal == 2 || curDisposal == 3) - && (nextTrans || !checkIfCover(next, cur))) { - switch (curDisposal) { - // restore to background color - // -> 'background' means background under this image. - case 2: - fillRect(bm, cur->ImageDesc.Left, cur->ImageDesc.Top, - cur->ImageDesc.Width, cur->ImageDesc.Height, - color); - break; - - // restore to previous - case 3: - bm->swap(*backup); - break; - } - } - - // Save current image if next frame's disposal method == 3 - if (nextDisposal == 3) { - const uint32_t* src = bm->getAddr32(0, 0); - uint32_t* dst = backup->getAddr32(0, 0); - int cnt = bm->width() * bm->height(); - memcpy(dst, src, cnt*sizeof(uint32_t)); - } -} - -bool SkGIFMovie::onGetBitmap(SkBitmap* bm) -{ - const GifFileType* gif = fGIF; - if (nullptr == gif) - return false; - - if (gif->ImageCount < 1) { - return false; - } - - const int width = gif->SWidth; - const int height = gif->SHeight; - if (width <= 0 || height <= 0) { - return false; - } - - // no need to draw - if (fLastDrawIndex >= 0 && fLastDrawIndex == fCurrIndex) { - return true; - } - - int startIndex = fLastDrawIndex + 1; - if (fLastDrawIndex < 0 || !bm->readyToDraw()) { - // first time - - startIndex = 0; - - // create bitmap - if (!bm->tryAllocN32Pixels(width, height)) { - return false; - } - // create bitmap for backup - if (!fBackup.tryAllocN32Pixels(width, height)) { - return false; - } - } else if (startIndex > fCurrIndex) { - // rewind to 1st frame for repeat - startIndex = 0; - } - - int lastIndex = fCurrIndex; - if (lastIndex < 0) { - // first time - lastIndex = 0; - } else if (lastIndex > fGIF->ImageCount - 1) { - // this block must not be reached. - lastIndex = fGIF->ImageCount - 1; - } - - SkColor bgColor = SkPackARGB32(0, 0, 0, 0); - if (gif->SColorMap != nullptr) { - const GifColorType& col = gif->SColorMap->Colors[fGIF->SBackGroundColor]; - bgColor = SkColorSetARGB(0xFF, col.Red, col.Green, col.Blue); - } - - // draw each frames - not intelligent way - for (int i = startIndex; i <= lastIndex; i++) { - const SavedImage* cur = &fGIF->SavedImages[i]; - if (i == 0) { - bool trans; - int disposal; - getTransparencyAndDisposalMethod(cur, &trans, &disposal); - if (!trans && gif->SColorMap != nullptr) { - fPaintingColor = bgColor; - } else { - fPaintingColor = SkColorSetARGB(0, 0, 0, 0); - } - - bm->eraseColor(fPaintingColor); - fBackup.eraseColor(fPaintingColor); - } else { - // Dispose previous frame before move to next frame. - const SavedImage* prev = &fGIF->SavedImages[i-1]; - disposeFrameIfNeeded(bm, prev, cur, &fBackup, fPaintingColor); - } - - // Draw frame - // We can skip this process if this index is not last and disposal - // method == 2 or method == 3 - if (i == lastIndex || !checkIfWillBeCleared(cur)) { - drawFrame(bm, cur, gif->SColorMap); - } - } - - // save index - fLastDrawIndex = lastIndex; - return true; -} - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkTRegistry.h" - -SkMovie* Factory(SkStreamRewindable* stream) { - char buf[GIF_STAMP_LEN]; - if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) { - if (memcmp(GIF_STAMP, buf, GIF_STAMP_LEN) == 0 || - memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 || - memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) { - // must rewind here, since our construct wants to re-read the data - stream->rewind(); - return new SkGIFMovie(stream); - } - } - return nullptr; -} - -static SkTRegistry gReg(Factory); diff --git a/gfx/skia/skia/src/images/SkImageEncoder.cpp b/gfx/skia/skia/src/images/SkImageEncoder.cpp index 023885f45918..fecadbf82acd 100644 --- a/gfx/skia/skia/src/images/SkImageEncoder.cpp +++ b/gfx/skia/skia/src/images/SkImageEncoder.cpp @@ -5,84 +5,25 @@ * found in the LICENSE file. */ -#include "SkImageEncoder.h" -#include "SkBitmap.h" -#include "SkPixelSerializer.h" -#include "SkPixmap.h" -#include "SkStream.h" -#include "SkTemplates.h" +#include "SkImageEncoderPriv.h" -SkImageEncoder::~SkImageEncoder() {} - -bool SkImageEncoder::encodeStream(SkWStream* stream, const SkBitmap& bm, - int quality) { - quality = SkMin32(100, SkMax32(0, quality)); - return this->onEncode(stream, bm, quality); -} - -bool SkImageEncoder::encodeFile(const char file[], const SkBitmap& bm, - int quality) { - quality = SkMin32(100, SkMax32(0, quality)); - SkFILEWStream stream(file); - return this->onEncode(&stream, bm, quality); -} - -SkData* SkImageEncoder::encodeData(const SkBitmap& bm, int quality) { - SkDynamicMemoryWStream stream; - quality = SkMin32(100, SkMax32(0, quality)); - if (this->onEncode(&stream, bm, quality)) { - return stream.detachAsData().release(); - } - return nullptr; -} - -bool SkImageEncoder::EncodeFile(const char file[], const SkBitmap& bm, Type t, - int quality) { - SkAutoTDelete enc(SkImageEncoder::Create(t)); - return enc.get() && enc.get()->encodeFile(file, bm, quality); -} - -bool SkImageEncoder::EncodeStream(SkWStream* stream, const SkBitmap& bm, Type t, - int quality) { - SkAutoTDelete enc(SkImageEncoder::Create(t)); - return enc.get() && enc.get()->encodeStream(stream, bm, quality); -} - -SkData* SkImageEncoder::EncodeData(const SkBitmap& bm, Type t, int quality) { - SkAutoTDelete enc(SkImageEncoder::Create(t)); - return enc.get() ? enc.get()->encodeData(bm, quality) : nullptr; -} - -SkData* SkImageEncoder::EncodeData(const SkImageInfo& info, const void* pixels, size_t rowBytes, - Type t, int quality) { - SkBitmap bm; - if (!bm.installPixels(info, const_cast(pixels), rowBytes)) { - return nullptr; - } - bm.setImmutable(); - return SkImageEncoder::EncodeData(bm, t, quality); -} - -SkData* SkImageEncoder::EncodeData(const SkPixmap& pixmap, - Type t, int quality) { - SkBitmap bm; - if (!bm.installPixels(pixmap)) { - return nullptr; - } - bm.setImmutable(); - return SkImageEncoder::EncodeData(bm, t, quality); -} - -namespace { -class ImageEncoderPixelSerializer final : public SkPixelSerializer { -protected: - bool onUseEncodedData(const void*, size_t) override { return true; } - SkData* onEncode(const SkPixmap& pmap) override { - return SkImageEncoder::EncodeData(pmap, SkImageEncoder::kPNG_Type, 100); - } -}; -} // namespace - -SkPixelSerializer* SkImageEncoder::CreatePixelSerializer() { - return new ImageEncoderPixelSerializer; +bool SkEncodeImage(SkWStream* dst, const SkPixmap& src, + SkEncodedImageFormat format, int quality) { + #ifdef SK_USE_CG_ENCODER + (void)quality; + return SkEncodeImageWithCG(dst, src, format); + #elif SK_USE_WIC_ENCODER + return SkEncodeImageWithWIC(dst, src, format, quality); + #else + switch(format) { + case SkEncodedImageFormat::kJPEG: + return SkEncodeImageAsJPEG(dst, src, quality); + case SkEncodedImageFormat::kPNG: + return SkEncodeImageAsPNG(dst, src, SkEncodeOptions()); + case SkEncodedImageFormat::kWEBP: + return SkEncodeImageAsWEBP(dst, src, quality); + default: + return false; + } + #endif } diff --git a/gfx/skia/skia/src/images/SkImageEncoderFns.h b/gfx/skia/skia/src/images/SkImageEncoderFns.h new file mode 100644 index 000000000000..5120570c484a --- /dev/null +++ b/gfx/skia/skia/src/images/SkImageEncoderFns.h @@ -0,0 +1,290 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageEncoderFns_DEFINED +#define SkImageEncoderFns_DEFINED + +/** + * Functions to transform scanlines between packed-pixel formats. + */ + +#include "SkBitmap.h" +#include "SkColor.h" +#include "SkColorPriv.h" +#include "SkICC.h" +#include "SkPreConfig.h" +#include "SkRasterPipeline.h" +#include "SkUnPreMultiply.h" +#include "SkUnPreMultiplyPriv.h" + +/** + * Function template for transforming scanlines. + * Transform 'width' pixels from 'src' buffer into 'dst' buffer, + * repacking color channel data as appropriate for the given transformation. + * 'bpp' is bytes per pixel in the 'src' buffer. + */ +typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int bpp, const SkPMColor* colors); + +/** + * Identity transformation: just copy bytes from src to dst. + */ +static inline void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int bpp, const SkPMColor*) { + memcpy(dst, src, width * bpp); +} + +static inline void transform_scanline_index8_opaque(char* SK_RESTRICT dst, + const char* SK_RESTRICT src, int width, int, + const SkPMColor* colors) { + for (int i = 0; i < width; i++) { + const uint32_t c = colors[(uint8_t)*src++]; + dst[0] = SkGetPackedR32(c); + dst[1] = SkGetPackedG32(c); + dst[2] = SkGetPackedB32(c); + dst += 3; + } +} + +static inline void transform_scanline_index8_unpremul(char* SK_RESTRICT dst, + const char* SK_RESTRICT src, int width, int, + const SkPMColor* colors) { + uint32_t* SK_RESTRICT dst32 = (uint32_t*) dst; + for (int i = 0; i < width; i++) { + // This function swizzles R and B on platforms where SkPMColor is BGRA. This is + // exactly what we want. + dst32[i] = SkSwizzle_RGBA_to_PMColor(colors[(uint8_t)*src++]); + } +} + +static inline void transform_scanline_gray(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor* colors) { + for (int i = 0; i < width; i++) { + const uint8_t g = (uint8_t) *src++; + dst[0] = g; + dst[1] = g; + dst[2] = g; + dst += 3; + } +} + +/** + * Transform from kRGB_565_Config to 3-bytes-per-pixel RGB. + * Alpha channel data is not present in kRGB_565_Config format, so there is no + * alpha channel data to preserve. + */ +static inline void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + const uint16_t* srcP = (const uint16_t*)src; + for (int i = 0; i < width; i++) { + unsigned c = *srcP++; + *dst++ = SkPacked16ToR32(c); + *dst++ = SkPacked16ToG32(c); + *dst++ = SkPacked16ToB32(c); + } +} + +/** + * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB. + * Alpha channel data is abandoned. + */ +static inline void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + const uint32_t* srcP = (const SkPMColor*)src; + for (int i = 0; i < width; i++) { + uint32_t c = *srcP++; + *dst++ = (c >> 0) & 0xFF; + *dst++ = (c >> 8) & 0xFF; + *dst++ = (c >> 16) & 0xFF; + } +} + +/** + * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB. + * Alpha channel data is abandoned. + */ +static inline void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + const uint32_t* srcP = (const SkPMColor*)src; + for (int i = 0; i < width; i++) { + uint32_t c = *srcP++; + *dst++ = (c >> 16) & 0xFF; + *dst++ = (c >> 8) & 0xFF; + *dst++ = (c >> 0) & 0xFF; + } +} + +/** + * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB. + * Alpha channel data, if any, is abandoned. + */ +static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + const SkPMColor16* srcP = (const SkPMColor16*)src; + for (int i = 0; i < width; i++) { + SkPMColor16 c = *srcP++; + *dst++ = SkPacked4444ToR32(c); + *dst++ = SkPacked4444ToG32(c); + *dst++ = SkPacked4444ToB32(c); + } +} + +/** + * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. + */ +static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + SkUnpremultiplyRow((uint32_t*) dst, (const uint32_t*) src, width); +} + +/** + * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. + */ +static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + SkUnpremultiplyRow((uint32_t*) dst, (const uint32_t*) src, width); +} + +template +static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) { + SkRasterPipeline p; + p.append(SkRasterPipeline::load_8888, &src); + if (!kIsRGBA) { + p.append(SkRasterPipeline::swap_rb); + } + + p.append_from_srgb(kPremul_SkAlphaType); + p.append(SkRasterPipeline::unpremul); + p.append(SkRasterPipeline::to_srgb); + p.append(SkRasterPipeline::store_8888, &dst); + p.run(0, width); +} + +/** + * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. + */ +static inline void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + transform_scanline_unpremultiply_sRGB(dst, src, width); +} + +/** + * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. + */ +static inline void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + transform_scanline_unpremultiply_sRGB(dst, src, width); +} + +/** + * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. + */ +static inline void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + const uint32_t* srcP = (const SkPMColor*)src; + for (int i = 0; i < width; i++) { + uint32_t c = *srcP++; + *dst++ = (c >> 16) & 0xFF; + *dst++ = (c >> 8) & 0xFF; + *dst++ = (c >> 0) & 0xFF; + *dst++ = (c >> 24) & 0xFF; + } +} + +/** + * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA, + * with scaling of RGB based on alpha channel. + */ +static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + const SkPMColor16* srcP = (const SkPMColor16*)src; + const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); + + for (int i = 0; i < width; i++) { + SkPMColor16 c = *srcP++; + unsigned a = SkPacked4444ToA32(c); + unsigned r = SkPacked4444ToR32(c); + unsigned g = SkPacked4444ToG32(c); + unsigned b = SkPacked4444ToB32(c); + + if (0 != a && 255 != a) { + SkUnPreMultiply::Scale scale = table[a]; + r = SkUnPreMultiply::ApplyScale(scale, r); + g = SkUnPreMultiply::ApplyScale(scale, g); + b = SkUnPreMultiply::ApplyScale(scale, b); + } + *dst++ = r; + *dst++ = g; + *dst++ = b; + *dst++ = a; + } +} + +/** + * Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA. + */ +static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + SkRasterPipeline p; + p.append(SkRasterPipeline::load_f16, (const void**) &src); + p.append(SkRasterPipeline::to_srgb); + p.append(SkRasterPipeline::store_u16_be, (void**) &dst); + p.run(0, width); +} + +/** + * Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA. + */ +static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int, const SkPMColor*) { + SkRasterPipeline p; + p.append(SkRasterPipeline::load_f16, (const void**) &src); + p.append(SkRasterPipeline::unpremul); + p.append(SkRasterPipeline::to_srgb); + p.append(SkRasterPipeline::store_u16_be, (void**) &dst); + p.run(0, width); +} + +/** + * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA. + */ +static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst, + const char* SK_RESTRICT src, int width, int, + const SkPMColor*) { + SkRasterPipeline p; + p.append(SkRasterPipeline::load_f16, (const void**) &src); + p.append(SkRasterPipeline::to_srgb); + p.append(SkRasterPipeline::store_8888, (void**) &dst); + p.run(0, width); +} + +/** + * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA. + */ +static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst, + const char* SK_RESTRICT src, int width, + int, const SkPMColor*) { + SkRasterPipeline p; + p.append(SkRasterPipeline::load_f16, (const void**) &src); + p.append(SkRasterPipeline::unpremul); + p.append(SkRasterPipeline::to_srgb); + p.append(SkRasterPipeline::store_8888, (void**) &dst); + p.run(0, width); +} + +static inline sk_sp icc_from_color_space(const SkColorSpace& cs) { + SkColorSpaceTransferFn fn; + SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); + if (cs.isNumericalTransferFn(&fn) && cs.toXYZD50(&toXYZD50)) { + return SkICC::WriteToICC(fn, toXYZD50); + } + + // TODO: Should we support writing ICC profiles for additional color spaces? + return nullptr; +} + +#endif // SkImageEncoderFns_DEFINED diff --git a/gfx/skia/skia/src/images/SkImageEncoderPriv.h b/gfx/skia/skia/src/images/SkImageEncoderPriv.h new file mode 100644 index 000000000000..540d93093b48 --- /dev/null +++ b/gfx/skia/skia/src/images/SkImageEncoderPriv.h @@ -0,0 +1,49 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageEncoderPriv_DEFINED +#define SkImageEncoderPriv_DEFINED + +#include "SkImageEncoder.h" + +struct SkEncodeOptions { + SkTransferFunctionBehavior fUnpremulBehavior = SkTransferFunctionBehavior::kIgnore; +}; + +#ifdef SK_HAS_JPEG_LIBRARY + bool SkEncodeImageAsJPEG(SkWStream*, const SkPixmap&, const SkEncodeOptions&); + bool SkEncodeImageAsJPEG(SkWStream*, const SkPixmap&, int quality); +#else + #define SkEncodeImageAsJPEG(...) false +#endif + +#ifdef SK_HAS_PNG_LIBRARY + bool SkEncodeImageAsPNG(SkWStream*, const SkPixmap&, const SkEncodeOptions&); +#else + #define SkEncodeImageAsPNG(...) false +#endif + +#ifdef SK_HAS_WEBP_LIBRARY + bool SkEncodeImageAsWEBP(SkWStream*, const SkPixmap&, const SkEncodeOptions&); + bool SkEncodeImageAsWEBP(SkWStream*, const SkPixmap&, int quality); +#else + #define SkEncodeImageAsWEBP(...) false +#endif + +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + bool SkEncodeImageWithCG(SkWStream*, const SkPixmap&, SkEncodedImageFormat); +#else + #define SkEncodeImageWithCG(...) false +#endif + +#ifdef SK_BUILD_FOR_WIN + bool SkEncodeImageWithWIC(SkWStream*, const SkPixmap&, SkEncodedImageFormat, int quality); +#else + #define SkEncodeImageWithWIC(...) false +#endif + +#endif // SkImageEncoderPriv_DEFINED diff --git a/gfx/skia/skia/src/images/SkImageEncoder_Factory.cpp b/gfx/skia/skia/src/images/SkImageEncoder_Factory.cpp deleted file mode 100644 index 887ce55ddac8..000000000000 --- a/gfx/skia/skia/src/images/SkImageEncoder_Factory.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2009 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkImageEncoder.h" - -template SkImageEncoder_EncodeReg* SkImageEncoder_EncodeReg::gHead; - -SkImageEncoder* SkImageEncoder::Create(Type t) { - SkImageEncoder* codec = nullptr; - const SkImageEncoder_EncodeReg* curr = SkImageEncoder_EncodeReg::Head(); - while (curr) { - if ((codec = curr->factory()(t)) != nullptr) { - return codec; - } - curr = curr->next(); - } - return nullptr; -} diff --git a/gfx/skia/skia/src/images/SkJPEGImageEncoder.cpp b/gfx/skia/skia/src/images/SkJPEGImageEncoder.cpp index 66b2440c2009..764e9c43b0de 100644 --- a/gfx/skia/skia/src/images/SkJPEGImageEncoder.cpp +++ b/gfx/skia/skia/src/images/SkJPEGImageEncoder.cpp @@ -5,180 +5,174 @@ * found in the LICENSE file. */ +#include "SkImageEncoderPriv.h" + +#ifdef SK_HAS_JPEG_LIBRARY -#include "SkImageEncoder.h" #include "SkColorPriv.h" -#include "SkDither.h" +#include "SkImageEncoderFns.h" +#include "SkJPEGWriteUtility.h" #include "SkStream.h" #include "SkTemplates.h" -#include "SkTime.h" -#include "SkUtils.h" -#include "SkRect.h" -#include "SkCanvas.h" - #include -#include "SkJPEGWriteUtility.h" + extern "C" { #include "jpeglib.h" #include "jerror.h" } -// These enable timing code that report milliseconds for an encoding -//#define TIME_ENCODE - -typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, - const void* SK_RESTRICT src, int width, - const SkPMColor* SK_RESTRICT ctable); - -static void Write_32_RGB(uint8_t* SK_RESTRICT dst, - const void* SK_RESTRICT srcRow, int width, - const SkPMColor*) { - const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; - while (--width >= 0) { - uint32_t c = *src++; - dst[0] = SkGetPackedR32(c); - dst[1] = SkGetPackedG32(c); - dst[2] = SkGetPackedB32(c); - dst += 3; - } -} - -static void Write_4444_RGB(uint8_t* SK_RESTRICT dst, - const void* SK_RESTRICT srcRow, int width, - const SkPMColor*) { - const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; - while (--width >= 0) { - SkPMColor16 c = *src++; - dst[0] = SkPacked4444ToR32(c); - dst[1] = SkPacked4444ToG32(c); - dst[2] = SkPacked4444ToB32(c); - dst += 3; - } -} - -static void Write_16_RGB(uint8_t* SK_RESTRICT dst, - const void* SK_RESTRICT srcRow, int width, - const SkPMColor*) { - const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; - while (--width >= 0) { - uint16_t c = *src++; - dst[0] = SkPacked16ToR32(c); - dst[1] = SkPacked16ToG32(c); - dst[2] = SkPacked16ToB32(c); - dst += 3; - } -} - -static void Write_Index_RGB(uint8_t* SK_RESTRICT dst, - const void* SK_RESTRICT srcRow, int width, - const SkPMColor* SK_RESTRICT ctable) { - const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; - while (--width >= 0) { - uint32_t c = ctable[*src++]; - dst[0] = SkGetPackedR32(c); - dst[1] = SkGetPackedG32(c); - dst[2] = SkGetPackedB32(c); - dst += 3; - } -} - -static WriteScanline ChooseWriter(const SkBitmap& bm) { - switch (bm.colorType()) { - case kN32_SkColorType: - return Write_32_RGB; +/** + * Returns true if |info| is supported by the jpeg encoder and false otherwise. + * |jpegColorType| will be set to the proper libjpeg-turbo type for input to the library. + * |numComponents| will be set to the number of components in the |jpegColorType|. + * |proc| will be set if we need to pre-convert the input before passing to + * libjpeg-turbo. Otherwise will be set to nullptr. + */ +// TODO (skbug.com/1501): +// Should we fail on non-opaque encodes? +// Or should we change alpha behavior (ex: unpremultiply when the input is premul)? +// Or is ignoring the alpha type and alpha channel ok here? +static bool set_encode_config(J_COLOR_SPACE* jpegColorType, int* numComponents, + transform_scanline_proc* proc, const SkImageInfo& info) { + *proc = nullptr; + switch (info.colorType()) { + case kRGBA_8888_SkColorType: + *jpegColorType = JCS_EXT_RGBA; + *numComponents = 4; + return true; + case kBGRA_8888_SkColorType: + *jpegColorType = JCS_EXT_BGRA; + *numComponents = 4; + return true; case kRGB_565_SkColorType: - return Write_16_RGB; + *proc = transform_scanline_565; + *jpegColorType = JCS_RGB; + *numComponents = 3; + return true; case kARGB_4444_SkColorType: - return Write_4444_RGB; + *proc = transform_scanline_444; + *jpegColorType = JCS_RGB; + *numComponents = 3; + return true; case kIndex_8_SkColorType: - return Write_Index_RGB; + *proc = transform_scanline_index8_opaque; + *jpegColorType = JCS_RGB; + *numComponents = 3; + return true; + case kGray_8_SkColorType: + SkASSERT(info.isOpaque()); + *jpegColorType = JCS_GRAYSCALE; + *numComponents = 1; + return true; + case kRGBA_F16_SkColorType: + if (!info.colorSpace() || !info.colorSpace()->gammaIsLinear()) { + return false; + } + + *proc = transform_scanline_F16_to_8888; + *jpegColorType = JCS_EXT_RGBA; + *numComponents = 4; + return true; default: - return nullptr; + return false; } + + } -class SkJPEGImageEncoder : public SkImageEncoder { -protected: - virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { -#ifdef TIME_ENCODE - SkAutoTime atm("JPEG Encode"); +bool SkEncodeImageAsJPEG(SkWStream* stream, const SkPixmap& pixmap, const SkEncodeOptions& opts) { + if (SkTransferFunctionBehavior::kRespect == opts.fUnpremulBehavior) { + // Respecting the transfer function requries a color space. It's not actually critical + // in the jpeg case (since jpegs are opaque), but Skia color correct behavior generally + // requires pixels to be tagged with color spaces. + if (!pixmap.colorSpace() || (!pixmap.colorSpace()->gammaCloseToSRGB() && + !pixmap.colorSpace()->gammaIsLinear())) { + return false; + } + } + + return SkEncodeImageAsJPEG(stream, pixmap, 100); +} + +bool SkEncodeImageAsJPEG(SkWStream* stream, const SkPixmap& pixmap, int quality) { + if (!pixmap.addr()) { + return false; + } + jpeg_compress_struct cinfo; + skjpeg_error_mgr sk_err; + skjpeg_destination_mgr sk_wstream(stream); + + // Declare before calling setjmp. + SkAutoTMalloc storage; + + cinfo.err = jpeg_std_error(&sk_err); + sk_err.error_exit = skjpeg_error_exit; + if (setjmp(sk_err.fJmpBuf)) { + return false; + } + + J_COLOR_SPACE jpegColorSpace; + int numComponents; + transform_scanline_proc proc; + if (!set_encode_config(&jpegColorSpace, &numComponents, &proc, pixmap.info())) { + return false; + } + + jpeg_create_compress(&cinfo); + cinfo.dest = &sk_wstream; + cinfo.image_width = pixmap.width(); + cinfo.image_height = pixmap.height(); + cinfo.input_components = numComponents; + cinfo.in_color_space = jpegColorSpace; + + jpeg_set_defaults(&cinfo); + + // Tells libjpeg-turbo to compute optimal Huffman coding tables + // for the image. This improves compression at the cost of + // slower encode performance. + cinfo.optimize_coding = TRUE; + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + jpeg_start_compress(&cinfo, TRUE); + + if (pixmap.colorSpace()) { + sk_sp icc = icc_from_color_space(*pixmap.colorSpace()); + if (icc) { + // Create a contiguous block of memory with the icc signature followed by the profile. + sk_sp markerData = + SkData::MakeUninitialized(kICCMarkerHeaderSize + icc->size()); + uint8_t* ptr = (uint8_t*) markerData->writable_data(); + memcpy(ptr, kICCSig, sizeof(kICCSig)); + ptr += sizeof(kICCSig); + *ptr++ = 1; // This is the first marker. + *ptr++ = 1; // Out of one total markers. + memcpy(ptr, icc->data(), icc->size()); + + jpeg_write_marker(&cinfo, kICCMarker, markerData->bytes(), markerData->size()); + } + } + + if (proc) { + storage.reset(numComponents * pixmap.width()); + } + + const void* srcRow = pixmap.addr(); + const SkPMColor* colors = pixmap.ctable() ? pixmap.ctable()->readColors() : nullptr; + while (cinfo.next_scanline < cinfo.image_height) { + JSAMPLE* jpegSrcRow = (JSAMPLE*) srcRow; + if (proc) { + proc((char*)storage.get(), (const char*)srcRow, pixmap.width(), numComponents, colors); + jpegSrcRow = storage.get(); + } + + (void) jpeg_write_scanlines(&cinfo, &jpegSrcRow, 1); + srcRow = SkTAddOffset(srcRow, pixmap.rowBytes()); + } + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + return true; +} #endif - - SkAutoLockPixels alp(bm); - if (nullptr == bm.getPixels()) { - return false; - } - - jpeg_compress_struct cinfo; - skjpeg_error_mgr sk_err; - skjpeg_destination_mgr sk_wstream(stream); - - // allocate these before set call setjmp - SkAutoTMalloc oneRow; - - cinfo.err = jpeg_std_error(&sk_err); - sk_err.error_exit = skjpeg_error_exit; - if (setjmp(sk_err.fJmpBuf)) { - return false; - } - - // Keep after setjmp or mark volatile. - const WriteScanline writer = ChooseWriter(bm); - if (nullptr == writer) { - return false; - } - - jpeg_create_compress(&cinfo); - cinfo.dest = &sk_wstream; - cinfo.image_width = bm.width(); - cinfo.image_height = bm.height(); - cinfo.input_components = 3; - - // FIXME: Can we take advantage of other in_color_spaces in libjpeg-turbo? - cinfo.in_color_space = JCS_RGB; - - // The gamma value is ignored by libjpeg-turbo. - cinfo.input_gamma = 1; - - jpeg_set_defaults(&cinfo); - - // Tells libjpeg-turbo to compute optimal Huffman coding tables - // for the image. This improves compression at the cost of - // slower encode performance. - cinfo.optimize_coding = TRUE; - jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); - - jpeg_start_compress(&cinfo, TRUE); - - const int width = bm.width(); - uint8_t* oneRowP = oneRow.reset(width * 3); - - const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readColors() : nullptr; - const void* srcRow = bm.getPixels(); - - while (cinfo.next_scanline < cinfo.image_height) { - JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ - - writer(oneRowP, srcRow, width, colors); - row_pointer[0] = oneRowP; - (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); - srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); - } - - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - - return true; - } -}; - -/////////////////////////////////////////////////////////////////////////////// -DEFINE_ENCODER_CREATOR(JPEGImageEncoder); -/////////////////////////////////////////////////////////////////////////////// - -static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { - return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; -} - -static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); diff --git a/gfx/skia/skia/src/images/SkJPEGWriteUtility.h b/gfx/skia/skia/src/images/SkJPEGWriteUtility.h index 91d07a3616bb..3765e7e674ed 100644 --- a/gfx/skia/skia/src/images/SkJPEGWriteUtility.h +++ b/gfx/skia/skia/src/images/SkJPEGWriteUtility.h @@ -9,6 +9,7 @@ #ifndef SkJpegUtility_DEFINED #define SkJpegUtility_DEFINED +#include "SkJpegPriv.h" #include "SkStream.h" extern "C" { @@ -18,14 +19,6 @@ extern "C" { #include -/* Our error-handling struct. - * -*/ -struct skjpeg_error_mgr : jpeg_error_mgr { - jmp_buf fJmpBuf; -}; - - void skjpeg_error_exit(j_common_ptr cinfo); ///////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/images/SkKTXImageEncoder.cpp b/gfx/skia/skia/src/images/SkKTXImageEncoder.cpp deleted file mode 100644 index 078cec6b4d3f..000000000000 --- a/gfx/skia/skia/src/images/SkKTXImageEncoder.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkColorPriv.h" -#include "SkImageEncoder.h" -#include "SkImageGenerator.h" -#include "SkPixelRef.h" -#include "SkStream.h" -#include "SkStreamPriv.h" -#include "SkTypes.h" - -#include "ktx.h" -#include "etc1.h" - -/////////////////////////////////////////////////////////////////////////////// - -// KTX Image Encoder -// -// KTX is a general texture data storage file format ratified by the Khronos Group. As an -// overview, a KTX file contains all of the appropriate values needed to fully specify a -// texture in an OpenGL application, including the use of compressed data. -// -// This encoder takes a best guess at how to encode the bitmap passed to it. If -// there is an installed discardable pixel ref with existing PKM data, then we -// will repurpose the existing ETC1 data into a KTX file. If the data contains -// KTX data, then we simply return a copy of the same data. For all other files, -// the underlying KTX library tries to do its best to encode the appropriate -// data specified by the bitmap based on the config. (i.e. kAlpha8_Config will -// be represented as a full resolution 8-bit image dump with the appropriate -// OpenGL defines in the header). - -class SkKTXImageEncoder : public SkImageEncoder { -protected: - bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; - -private: - virtual bool encodePKM(SkWStream* stream, const SkData *data); - typedef SkImageEncoder INHERITED; -}; - -bool SkKTXImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) { - if (!bitmap.pixelRef()) { - return false; - } - sk_sp data(bitmap.pixelRef()->refEncodedData()); - - // Is this even encoded data? - if (data) { - const uint8_t *bytes = data->bytes(); - if (etc1_pkm_is_valid(bytes)) { - return this->encodePKM(stream, data.get()); - } - - // Is it a KTX file?? - if (SkKTXFile::is_ktx(bytes, data->size())) { - return stream->write(bytes, data->size()); - } - - // If it's neither a KTX nor a PKM, then we need to - // get at the actual pixels, so fall through and decompress... - } - - return SkKTXFile::WriteBitmapToKTX(stream, bitmap); -} - -bool SkKTXImageEncoder::encodePKM(SkWStream* stream, const SkData *data) { - const uint8_t* bytes = data->bytes(); - SkASSERT(etc1_pkm_is_valid(bytes)); - - etc1_uint32 width = etc1_pkm_get_width(bytes); - etc1_uint32 height = etc1_pkm_get_height(bytes); - - // ETC1 Data is stored as compressed 4x4 pixel blocks, so we must make sure - // that our dimensions are valid. - if (width == 0 || (width & 3) != 0 || height == 0 || (height & 3) != 0) { - return false; - } - - // Advance pointer to etc1 data. - bytes += ETC_PKM_HEADER_SIZE; - - return SkKTXFile::WriteETC1ToKTX(stream, bytes, width, height); -} - -///////////////////////////////////////////////////////////////////////////////////////// -DEFINE_ENCODER_CREATOR(KTXImageEncoder); -///////////////////////////////////////////////////////////////////////////////////////// - -SkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) { - return (SkImageEncoder::kKTX_Type == t) ? new SkKTXImageEncoder : nullptr; -} - -static SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory); diff --git a/gfx/skia/skia/src/images/SkMovie.cpp b/gfx/skia/skia/src/images/SkMovie.cpp deleted file mode 100644 index a0a37dcffa36..000000000000 --- a/gfx/skia/skia/src/images/SkMovie.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkMovie.h" -#include "SkCanvas.h" -#include "SkPaint.h" - -// We should never see this in normal operation since our time values are -// 0-based. So we use it as a sentinal. -#define UNINITIALIZED_MSEC ((SkMSec)-1) - -SkMovie::SkMovie() -{ - fInfo.fDuration = UNINITIALIZED_MSEC; // uninitialized - fCurrTime = UNINITIALIZED_MSEC; // uninitialized - fNeedBitmap = true; -} - -void SkMovie::ensureInfo() -{ - if (fInfo.fDuration == UNINITIALIZED_MSEC && !this->onGetInfo(&fInfo)) - memset(&fInfo, 0, sizeof(fInfo)); // failure -} - -SkMSec SkMovie::duration() -{ - this->ensureInfo(); - return fInfo.fDuration; -} - -int SkMovie::width() -{ - this->ensureInfo(); - return fInfo.fWidth; -} - -int SkMovie::height() -{ - this->ensureInfo(); - return fInfo.fHeight; -} - -int SkMovie::isOpaque() -{ - this->ensureInfo(); - return fInfo.fIsOpaque; -} - -bool SkMovie::setTime(SkMSec time) -{ - SkMSec dur = this->duration(); - if (time > dur) - time = dur; - - bool changed = false; - if (time != fCurrTime) - { - fCurrTime = time; - changed = this->onSetTime(time); - fNeedBitmap |= changed; - } - return changed; -} - -const SkBitmap& SkMovie::bitmap() -{ - if (fCurrTime == UNINITIALIZED_MSEC) // uninitialized - this->setTime(0); - - if (fNeedBitmap) - { - if (!this->onGetBitmap(&fBitmap)) // failure - fBitmap.reset(); - fNeedBitmap = false; - } - return fBitmap; -} - -//////////////////////////////////////////////////////////////////// - -#include "SkStream.h" - -SkMovie* SkMovie::DecodeMemory(const void* data, size_t length) { - SkMemoryStream stream(data, length, false); - return SkMovie::DecodeStream(&stream); -} - -SkMovie* SkMovie::DecodeFile(const char path[]) { - std::unique_ptr stream = SkStream::MakeFromFile(path); - return stream ? SkMovie::DecodeStream(stream.get()) : nullptr; -} diff --git a/gfx/skia/skia/src/images/SkMovie_FactoryDefault.cpp b/gfx/skia/skia/src/images/SkMovie_FactoryDefault.cpp deleted file mode 100644 index 84ae78a88005..000000000000 --- a/gfx/skia/skia/src/images/SkMovie_FactoryDefault.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkMovie.h" -#include "SkStream.h" - -typedef SkTRegistry MovieReg; - -SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) { - const MovieReg* curr = MovieReg::Head(); - while (curr) { - SkMovie* movie = curr->factory()(stream); - if (movie) { - return movie; - } - // we must rewind only if we got nullptr, since we gave the stream to the - // movie, who may have already started reading from it - stream->rewind(); - curr = curr->next(); - } - return nullptr; -} diff --git a/gfx/skia/skia/src/images/SkPNGImageEncoder.cpp b/gfx/skia/skia/src/images/SkPNGImageEncoder.cpp index 69a53fb2a467..b57c32a0fc4d 100644 --- a/gfx/skia/skia/src/images/SkPNGImageEncoder.cpp +++ b/gfx/skia/skia/src/images/SkPNGImageEncoder.cpp @@ -5,44 +5,25 @@ * found in the LICENSE file. */ -#include "SkImageEncoder.h" +#include "SkImageEncoderPriv.h" + +#ifdef SK_HAS_PNG_LIBRARY + #include "SkColor.h" #include "SkColorPriv.h" #include "SkDither.h" +#include "SkImageEncoderFns.h" #include "SkMath.h" #include "SkStream.h" +#include "SkString.h" #include "SkTemplates.h" +#include "SkUnPreMultiply.h" #include "SkUtils.h" -#include "transform_scanline.h" #include "png.h" -/* These were dropped in libpng >= 1.4 */ -#ifndef png_infopp_NULL -#define png_infopp_NULL nullptr -#endif - -#ifndef png_bytepp_NULL -#define png_bytepp_NULL nullptr -#endif - -#ifndef int_p_NULL -#define int_p_NULL nullptr -#endif - -#ifndef png_flush_ptr_NULL -#define png_flush_ptr_NULL nullptr -#endif - -#define DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS true // Suppress most PNG warnings when calling image decode functions. -static const bool c_suppressPNGImageDecoderWarnings{ - DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS}; - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkColorPriv.h" -#include "SkUnPreMultiply.h" +static const bool c_suppressPNGImageDecoderWarnings = true; static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { if (!c_suppressPNGImageDecoderWarnings) { @@ -58,49 +39,80 @@ static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { } } -static transform_scanline_proc choose_proc(SkColorType ct, SkAlphaType alphaType) { - static const struct { - SkColorType fColorType; - SkAlphaType fAlphaType; - transform_scanline_proc fProc; - } gMap[] = { - { kRGB_565_SkColorType, kOpaque_SkAlphaType, transform_scanline_565 }, - { kRGBA_8888_SkColorType, kOpaque_SkAlphaType, transform_scanline_RGBX }, - { kBGRA_8888_SkColorType, kOpaque_SkAlphaType, transform_scanline_BGRX }, - { kRGBA_8888_SkColorType, kPremul_SkAlphaType, transform_scanline_rgbA }, - { kBGRA_8888_SkColorType, kPremul_SkAlphaType, transform_scanline_bgrA }, - { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, transform_scanline_memcpy }, - { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, transform_scanline_BGRA }, - { kARGB_4444_SkColorType, kOpaque_SkAlphaType, transform_scanline_444 }, - { kARGB_4444_SkColorType, kPremul_SkAlphaType, transform_scanline_4444 }, - { kIndex_8_SkColorType, kOpaque_SkAlphaType, transform_scanline_memcpy }, - { kIndex_8_SkColorType, kPremul_SkAlphaType, transform_scanline_memcpy }, - { kIndex_8_SkColorType, kUnpremul_SkAlphaType, transform_scanline_memcpy }, - { kGray_8_SkColorType, kOpaque_SkAlphaType, transform_scanline_memcpy }, - }; - - for (auto entry : gMap) { - if (entry.fColorType == ct && entry.fAlphaType == alphaType) { - return entry.fProc; - } - } - sk_throw(); - return nullptr; +static void set_icc(png_structp png_ptr, png_infop info_ptr, sk_sp icc) { +#if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5) + const char* name = "Skia"; + png_const_bytep iccPtr = icc->bytes(); +#else + SkString str("Skia"); + char* name = str.writable_str(); + png_charp iccPtr = (png_charp) icc->writable_data(); +#endif + png_set_iCCP(png_ptr, info_ptr, name, 0, iccPtr, icc->size()); } -// return the minimum legal bitdepth (by png standards) for this many colortable -// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16, -// we can use fewer bits per in png -static int computeBitDepth(int colorCount) { -#if 0 - int bits = SkNextLog2(colorCount); - SkASSERT(bits >= 1 && bits <= 8); - // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) - return SkNextPow2(bits); -#else - // for the moment, we don't know how to pack bitdepth < 8 - return 8; -#endif +static transform_scanline_proc choose_proc(const SkImageInfo& info, + SkTransferFunctionBehavior unpremulBehavior) { + const bool isSRGBTransferFn = + (SkTransferFunctionBehavior::kRespect == unpremulBehavior) && info.gammaCloseToSRGB(); + switch (info.colorType()) { + case kRGBA_8888_SkColorType: + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + return transform_scanline_RGBX; + case kUnpremul_SkAlphaType: + return transform_scanline_memcpy; + case kPremul_SkAlphaType: + return isSRGBTransferFn ? transform_scanline_srgbA : + transform_scanline_rgbA; + default: + SkASSERT(false); + return nullptr; + } + case kBGRA_8888_SkColorType: + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + return transform_scanline_BGRX; + case kUnpremul_SkAlphaType: + return transform_scanline_BGRA; + case kPremul_SkAlphaType: + return isSRGBTransferFn ? transform_scanline_sbgrA : + transform_scanline_bgrA; + default: + SkASSERT(false); + return nullptr; + } + case kRGB_565_SkColorType: + return transform_scanline_565; + case kARGB_4444_SkColorType: + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + return transform_scanline_444; + case kPremul_SkAlphaType: + // 4444 is assumed to be legacy premul. + return transform_scanline_4444; + default: + SkASSERT(false); + return nullptr; + } + case kIndex_8_SkColorType: + case kGray_8_SkColorType: + return transform_scanline_memcpy; + case kRGBA_F16_SkColorType: + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + case kUnpremul_SkAlphaType: + return transform_scanline_F16; + case kPremul_SkAlphaType: + return transform_scanline_F16_premul; + default: + SkASSERT(false); + return nullptr; + } + default: + SkASSERT(false); + return nullptr; + } } /* Pack palette[] with the corresponding colors, and if the image has alpha, also @@ -108,29 +120,29 @@ static int computeBitDepth(int colorCount) { opaque, the return value will always be 0. */ static inline int pack_palette(SkColorTable* ctable, png_color* SK_RESTRICT palette, - png_byte* SK_RESTRICT alphas, SkAlphaType alphaType) { - const SkPMColor* SK_RESTRICT colors = ctable->readColors(); + png_byte* SK_RESTRICT alphas, const SkImageInfo& info, + SkTransferFunctionBehavior unpremulBehavior) { + const SkPMColor* colors = ctable->readColors(); const int count = ctable->count(); - int numWithAlpha = 0; - if (kOpaque_SkAlphaType != alphaType) { - auto getUnpremulColor = [alphaType](uint8_t color, uint8_t alpha) { - if (kPremul_SkAlphaType == alphaType) { - const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); - const SkUnPreMultiply::Scale scale = table[alpha]; - return (uint8_t) SkUnPreMultiply::ApplyScale(scale, color); - } else { - return color; - } - }; + SkPMColor storage[256]; + if (kPremul_SkAlphaType == info.alphaType()) { + // Unpremultiply the colors. + const SkImageInfo rgbaInfo = info.makeColorType(kRGBA_8888_SkColorType); + transform_scanline_proc proc = choose_proc(rgbaInfo, unpremulBehavior); + proc((char*) storage, (const char*) colors, ctable->count(), 4, nullptr); + colors = storage; + } + int numWithAlpha = 0; + if (kOpaque_SkAlphaType != info.alphaType()) { // PNG requires that all non-opaque colors come first in the palette. Write these first. for (int i = 0; i < count; i++) { uint8_t alpha = SkGetPackedA32(colors[i]); if (0xFF != alpha) { alphas[numWithAlpha] = alpha; - palette[numWithAlpha].red = getUnpremulColor(SkGetPackedR32(colors[i]), alpha); - palette[numWithAlpha].green = getUnpremulColor(SkGetPackedG32(colors[i]), alpha); - palette[numWithAlpha].blue = getUnpremulColor(SkGetPackedB32(colors[i]), alpha); + palette[numWithAlpha].red = SkGetPackedR32(colors[i]); + palette[numWithAlpha].green = SkGetPackedG32(colors[i]); + palette[numWithAlpha].blue = SkGetPackedB32(colors[i]); numWithAlpha++; } } @@ -165,38 +177,26 @@ static inline int pack_palette(SkColorTable* ctable, png_color* SK_RESTRICT pale return numWithAlpha; } -class SkPNGImageEncoder : public SkImageEncoder { -protected: - bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; -private: - bool doEncode(SkWStream* stream, const SkBitmap& bm, - SkAlphaType alphaType, int colorType, - int bitDepth, SkColorType ct, - png_color_8& sig_bit); +static bool do_encode(SkWStream*, const SkPixmap&, int, int, png_color_8&, + SkTransferFunctionBehavior unpremulBehavior); - typedef SkImageEncoder INHERITED; -}; - -bool SkPNGImageEncoder::onEncode(SkWStream* stream, - const SkBitmap& bitmap, - int /*quality*/) { - const SkColorType ct = bitmap.colorType(); - switch (ct) { - case kIndex_8_SkColorType: - case kGray_8_SkColorType: - case kRGBA_8888_SkColorType: - case kBGRA_8888_SkColorType: - case kARGB_4444_SkColorType: - case kRGB_565_SkColorType: - break; - default: +bool SkEncodeImageAsPNG(SkWStream* stream, const SkPixmap& pixmap, const SkEncodeOptions& opts) { + if (SkTransferFunctionBehavior::kRespect == opts.fUnpremulBehavior) { + if (!pixmap.colorSpace() || (!pixmap.colorSpace()->gammaCloseToSRGB() && + !pixmap.colorSpace()->gammaIsLinear())) { return false; + } } - const SkAlphaType alphaType = bitmap.alphaType(); + if (!pixmap.addr() || pixmap.info().isEmpty()) { + return false; + } + + const SkColorType colorType = pixmap.colorType(); + const SkAlphaType alphaType = pixmap.alphaType(); switch (alphaType) { case kUnpremul_SkAlphaType: - if (kARGB_4444_SkColorType == ct) { + if (kARGB_4444_SkColorType == colorType) { return false; } @@ -209,22 +209,33 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, } const bool isOpaque = (kOpaque_SkAlphaType == alphaType); - int bitDepth = 8; // default for color + int bitDepth = 8; png_color_8 sig_bit; sk_bzero(&sig_bit, sizeof(png_color_8)); + int pngColorType; + switch (colorType) { + case kRGBA_F16_SkColorType: + if (!pixmap.colorSpace() || !pixmap.colorSpace()->gammaIsLinear()) { + return false; + } - int colorType; - switch (ct) { + sig_bit.red = 16; + sig_bit.green = 16; + sig_bit.blue = 16; + sig_bit.alpha = 16; + bitDepth = 16; + pngColorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; + break; case kIndex_8_SkColorType: sig_bit.red = 8; sig_bit.green = 8; sig_bit.blue = 8; sig_bit.alpha = 8; - colorType = PNG_COLOR_TYPE_PALETTE; + pngColorType = PNG_COLOR_TYPE_PALETTE; break; case kGray_8_SkColorType: sig_bit.gray = 8; - colorType = PNG_COLOR_TYPE_GRAY; + pngColorType = PNG_COLOR_TYPE_GRAY; SkASSERT(isOpaque); break; case kRGBA_8888_SkColorType: @@ -233,62 +244,68 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, sig_bit.green = 8; sig_bit.blue = 8; sig_bit.alpha = 8; - colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; + pngColorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; break; case kARGB_4444_SkColorType: sig_bit.red = 4; sig_bit.green = 4; sig_bit.blue = 4; sig_bit.alpha = 4; - colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; + pngColorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; break; case kRGB_565_SkColorType: sig_bit.red = 5; sig_bit.green = 6; sig_bit.blue = 5; - colorType = PNG_COLOR_TYPE_RGB; + pngColorType = PNG_COLOR_TYPE_RGB; SkASSERT(isOpaque); break; default: return false; } - SkAutoLockPixels alp(bitmap); - // readyToDraw checks for pixels (and colortable if that is required) - if (!bitmap.readyToDraw()) { - return false; - } - - // we must do this after we have locked the pixels - SkColorTable* ctable = bitmap.getColorTable(); - if (ctable) { - if (ctable->count() == 0) { + if (kIndex_8_SkColorType == colorType) { + SkColorTable* ctable = pixmap.ctable(); + if (!ctable || ctable->count() == 0) { return false; } - // check if we can store in fewer than 8 bits - bitDepth = computeBitDepth(ctable->count()); + + // Currently, we always use 8-bit indices for paletted pngs. + // When ctable->count() <= 16, we could potentially use 1, 2, + // or 4 bit indices. } - return doEncode(stream, bitmap, alphaType, colorType, bitDepth, ct, sig_bit); + return do_encode(stream, pixmap, pngColorType, bitDepth, sig_bit, opts.fUnpremulBehavior); } -bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, - SkAlphaType alphaType, int colorType, - int bitDepth, SkColorType ct, - png_color_8& sig_bit) { +static int num_components(int pngColorType) { + switch (pngColorType) { + case PNG_COLOR_TYPE_PALETTE: + case PNG_COLOR_TYPE_GRAY: + return 1; + case PNG_COLOR_TYPE_RGB: + return 3; + case PNG_COLOR_TYPE_RGBA: + return 4; + default: + SkASSERT(false); + return 0; + } +} +static bool do_encode(SkWStream* stream, const SkPixmap& pixmap, int pngColorType, int bitDepth, + png_color_8& sig_bit, SkTransferFunctionBehavior unpremulBehavior) { png_structp png_ptr; png_infop info_ptr; - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, sk_error_fn, - nullptr); + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, sk_error_fn, nullptr); if (nullptr == png_ptr) { return false; } info_ptr = png_create_info_struct(png_ptr); if (nullptr == info_ptr) { - png_destroy_write_struct(&png_ptr, png_infopp_NULL); + png_destroy_write_struct(&png_ptr, nullptr); return false; } @@ -300,7 +317,7 @@ bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, return false; } - png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL); + png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, nullptr); /* Set the image information here. Width and height are up to 2^31, * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on @@ -311,37 +328,56 @@ bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED */ - png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), - bitDepth, colorType, + png_set_IHDR(png_ptr, info_ptr, pixmap.width(), pixmap.height(), + bitDepth, pngColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // set our colortable/trans arrays if needed png_color paletteColors[256]; png_byte trans[256]; - if (kIndex_8_SkColorType == ct) { - SkColorTable* colorTable = bitmap.getColorTable(); + if (kIndex_8_SkColorType == pixmap.colorType()) { + SkColorTable* colorTable = pixmap.ctable(); SkASSERT(colorTable); - int numTrans = pack_palette(colorTable, paletteColors, trans, alphaType); + int numTrans = pack_palette(colorTable, paletteColors, trans, pixmap.info(), + unpremulBehavior); png_set_PLTE(png_ptr, info_ptr, paletteColors, colorTable->count()); if (numTrans > 0) { png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); } } + if (pixmap.colorSpace()) { + if (pixmap.colorSpace()->isSRGB()) { + png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); + } else { + sk_sp icc = icc_from_color_space(*pixmap.colorSpace()); + if (icc) { + set_icc(png_ptr, info_ptr, std::move(icc)); + } + } + } + png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_write_info(png_ptr, info_ptr); + int pngBytesPerPixel = num_components(pngColorType) * (bitDepth / 8); + if (kRGBA_F16_SkColorType == pixmap.colorType() && kOpaque_SkAlphaType == pixmap.alphaType()) { + // For kOpaque, kRGBA_F16, we will keep the row as RGBA and tell libpng + // to skip the alpha channel. + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + pngBytesPerPixel = 8; + } - const char* srcImage = (const char*)bitmap.getPixels(); - SkAutoSTMalloc<1024, char> rowStorage(bitmap.width() << 2); + SkAutoSTMalloc<1024, char> rowStorage(pixmap.width() * pngBytesPerPixel); char* storage = rowStorage.get(); - transform_scanline_proc proc = choose_proc(ct, alphaType); - - for (int y = 0; y < bitmap.height(); y++) { + const char* srcImage = (const char*)pixmap.addr(); + transform_scanline_proc proc = choose_proc(pixmap.info(), unpremulBehavior); + for (int y = 0; y < pixmap.height(); y++) { png_bytep row_ptr = (png_bytep)storage; - proc(storage, srcImage, bitmap.width(), SkColorTypeBytesPerPixel(ct)); + proc(storage, srcImage, pixmap.width(), SkColorTypeBytesPerPixel(pixmap.colorType()), + nullptr); png_write_rows(png_ptr, &row_ptr, 1); - srcImage += bitmap.rowBytes(); + srcImage += pixmap.rowBytes(); } png_write_end(png_ptr, info_ptr); @@ -351,12 +387,4 @@ bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, return true; } -/////////////////////////////////////////////////////////////////////////////// -DEFINE_ENCODER_CREATOR(PNGImageEncoder); -/////////////////////////////////////////////////////////////////////////////// - -SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { - return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; -} - -static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); +#endif diff --git a/gfx/skia/skia/src/images/SkWEBPImageEncoder.cpp b/gfx/skia/skia/src/images/SkWEBPImageEncoder.cpp index 116608a253e2..c0cd4a6caec9 100644 --- a/gfx/skia/skia/src/images/SkWEBPImageEncoder.cpp +++ b/gfx/skia/skia/src/images/SkWEBPImageEncoder.cpp @@ -14,14 +14,19 @@ * limitations under the License. */ +#include "SkImageEncoderPriv.h" + +#ifdef SK_HAS_WEBP_LIBRARY + #include "SkBitmap.h" -#include "SkImageEncoder.h" #include "SkColorPriv.h" +#include "SkImageEncoderFns.h" #include "SkStream.h" #include "SkTemplates.h" +#include "SkUnPreMultiply.h" #include "SkUtils.h" -// A WebP decoder only, on top of (subset of) libwebp +// A WebP encoder only, on top of (subset of) libwebp // For more information on WebP image format, and libwebp library, see: // http://code.google.com/speed/webp/ // http://www.webmproject.org/code/#libwebp_webp_image_decoder_library @@ -32,135 +37,81 @@ extern "C" { // If moving libwebp out of skia source tree, path for webp headers must be // updated accordingly. Here, we enforce using local copy in webp sub-directory. #include "webp/encode.h" +#include "webp/mux.h" } -#include "SkUnPreMultiply.h" - -typedef void (*ScanlineImporter)(const uint8_t* in, uint8_t* out, int width, - const SkPMColor* SK_RESTRICT ctable); - -static void ARGB_8888_To_RGB(const uint8_t* in, uint8_t* rgb, int width, - const SkPMColor*) { - const uint32_t* SK_RESTRICT src = (const uint32_t*)in; - for (int i = 0; i < width; ++i) { - const uint32_t c = *src++; - rgb[0] = SkGetPackedR32(c); - rgb[1] = SkGetPackedG32(c); - rgb[2] = SkGetPackedB32(c); - rgb += 3; - } -} - -static void ARGB_8888_To_RGBA(const uint8_t* in, uint8_t* rgb, int width, - const SkPMColor*) { - const uint32_t* SK_RESTRICT src = (const uint32_t*)in; - const SkUnPreMultiply::Scale* SK_RESTRICT table = - SkUnPreMultiply::GetScaleTable(); - for (int i = 0; i < width; ++i) { - const uint32_t c = *src++; - uint8_t a = SkGetPackedA32(c); - uint8_t r = SkGetPackedR32(c); - uint8_t g = SkGetPackedG32(c); - uint8_t b = SkGetPackedB32(c); - if (0 != a && 255 != a) { - SkUnPreMultiply::Scale scale = table[a]; - r = SkUnPreMultiply::ApplyScale(scale, r); - g = SkUnPreMultiply::ApplyScale(scale, g); - b = SkUnPreMultiply::ApplyScale(scale, b); - } - rgb[0] = r; - rgb[1] = g; - rgb[2] = b; - rgb[3] = a; - rgb += 4; - } -} - -static void RGB_565_To_RGB(const uint8_t* in, uint8_t* rgb, int width, - const SkPMColor*) { - const uint16_t* SK_RESTRICT src = (const uint16_t*)in; - for (int i = 0; i < width; ++i) { - const uint16_t c = *src++; - rgb[0] = SkPacked16ToR32(c); - rgb[1] = SkPacked16ToG32(c); - rgb[2] = SkPacked16ToB32(c); - rgb += 3; - } -} - -static void ARGB_4444_To_RGB(const uint8_t* in, uint8_t* rgb, int width, - const SkPMColor*) { - const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)in; - for (int i = 0; i < width; ++i) { - const SkPMColor16 c = *src++; - rgb[0] = SkPacked4444ToR32(c); - rgb[1] = SkPacked4444ToG32(c); - rgb[2] = SkPacked4444ToB32(c); - rgb += 3; - } -} - -static void ARGB_4444_To_RGBA(const uint8_t* in, uint8_t* rgb, int width, - const SkPMColor*) { - const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)in; - const SkUnPreMultiply::Scale* SK_RESTRICT table = - SkUnPreMultiply::GetScaleTable(); - for (int i = 0; i < width; ++i) { - const SkPMColor16 c = *src++; - uint8_t a = SkPacked4444ToA32(c); - uint8_t r = SkPacked4444ToR32(c); - uint8_t g = SkPacked4444ToG32(c); - uint8_t b = SkPacked4444ToB32(c); - if (0 != a && 255 != a) { - SkUnPreMultiply::Scale scale = table[a]; - r = SkUnPreMultiply::ApplyScale(scale, r); - g = SkUnPreMultiply::ApplyScale(scale, g); - b = SkUnPreMultiply::ApplyScale(scale, b); - } - rgb[0] = r; - rgb[1] = g; - rgb[2] = b; - rgb[3] = a; - rgb += 4; - } -} - -static void Index8_To_RGB(const uint8_t* in, uint8_t* rgb, int width, - const SkPMColor* SK_RESTRICT ctable) { - const uint8_t* SK_RESTRICT src = (const uint8_t*)in; - for (int i = 0; i < width; ++i) { - const uint32_t c = ctable[*src++]; - rgb[0] = SkGetPackedR32(c); - rgb[1] = SkGetPackedG32(c); - rgb[2] = SkGetPackedB32(c); - rgb += 3; - } -} - -static ScanlineImporter ChooseImporter(SkColorType ct, bool hasAlpha, int* bpp) { - switch (ct) { - case kN32_SkColorType: - if (hasAlpha) { - *bpp = 4; - return ARGB_8888_To_RGBA; - } else { - *bpp = 3; - return ARGB_8888_To_RGB; +static transform_scanline_proc choose_proc(const SkImageInfo& info, + SkTransferFunctionBehavior unpremulBehavior) { + const bool isSRGBTransferFn = + (SkTransferFunctionBehavior::kRespect == unpremulBehavior) && info.gammaCloseToSRGB(); + switch (info.colorType()) { + case kRGBA_8888_SkColorType: + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + return transform_scanline_RGBX; + case kUnpremul_SkAlphaType: + return transform_scanline_memcpy; + case kPremul_SkAlphaType: + return isSRGBTransferFn ? transform_scanline_srgbA : + transform_scanline_rgbA; + default: + return nullptr; } - case kARGB_4444_SkColorType: - if (hasAlpha) { - *bpp = 4; - return ARGB_4444_To_RGBA; - } else { - *bpp = 3; - return ARGB_4444_To_RGB; + case kBGRA_8888_SkColorType: + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + return transform_scanline_BGRX; + case kUnpremul_SkAlphaType: + return transform_scanline_BGRA; + case kPremul_SkAlphaType: + return isSRGBTransferFn ? transform_scanline_sbgrA : + transform_scanline_bgrA; + default: + return nullptr; } case kRGB_565_SkColorType: - *bpp = 3; - return RGB_565_To_RGB; + if (!info.isOpaque()) { + return nullptr; + } + + return transform_scanline_565; + case kARGB_4444_SkColorType: + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + return transform_scanline_444; + case kPremul_SkAlphaType: + return transform_scanline_4444; + default: + return nullptr; + } case kIndex_8_SkColorType: - *bpp = 3; - return Index8_To_RGB; + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + return transform_scanline_index8_opaque; + case kUnpremul_SkAlphaType: + case kPremul_SkAlphaType: + // If the color table is premultiplied, we'll fix it before calling the + // scanline proc. + return transform_scanline_index8_unpremul; + default: + return nullptr; + } + case kGray_8_SkColorType: + return transform_scanline_gray; + case kRGBA_F16_SkColorType: + if (!info.colorSpace() || !info.colorSpace()->gammaIsLinear()) { + return nullptr; + } + + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + case kUnpremul_SkAlphaType: + return transform_scanline_F16_to_8888; + case kPremul_SkAlphaType: + return transform_scanline_F16_premul_to_8888; + default: + return nullptr; + } default: return nullptr; } @@ -172,31 +123,48 @@ static int stream_writer(const uint8_t* data, size_t data_size, return stream->write(data, data_size) ? 1 : 0; } -class SkWEBPImageEncoder : public SkImageEncoder { -protected: - bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; - -private: - typedef SkImageEncoder INHERITED; -}; - -bool SkWEBPImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bm, - int quality) { - const bool hasAlpha = !bm.isOpaque(); - int bpp = -1; - const ScanlineImporter scanline_import = ChooseImporter(bm.colorType(), hasAlpha, &bpp); - if (nullptr == scanline_import) { - return false; +static bool do_encode(SkWStream* stream, const SkPixmap& pixmap, const SkEncodeOptions& opts, + int quality) { + if (SkTransferFunctionBehavior::kRespect == opts.fUnpremulBehavior) { + if (!pixmap.colorSpace() || (!pixmap.colorSpace()->gammaCloseToSRGB() && + !pixmap.colorSpace()->gammaIsLinear())) { + return false; + } } - if (-1 == bpp) { + + const transform_scanline_proc proc = choose_proc(pixmap.info(), opts.fUnpremulBehavior); + if (!proc) { return false; } - SkAutoLockPixels alp(bm); - if (nullptr == bm.getPixels()) { + int bpp; + if (kRGBA_F16_SkColorType == pixmap.colorType()) { + bpp = 4; + } else { + bpp = pixmap.isOpaque() ? 3 : 4; + } + + if (nullptr == pixmap.addr()) { return false; } + const SkPMColor* colors = nullptr; + SkPMColor storage[256]; + if (kIndex_8_SkColorType == pixmap.colorType()) { + if (!pixmap.ctable()) { + return false; + } + + colors = pixmap.ctable()->readColors(); + if (kPremul_SkAlphaType == pixmap.alphaType()) { + // Unpremultiply the colors. + const SkImageInfo rgbaInfo = pixmap.info().makeColorType(kRGBA_8888_SkColorType); + transform_scanline_proc proc = choose_proc(rgbaInfo, opts.fUnpremulBehavior); + proc((char*) storage, (const char*) colors, pixmap.ctable()->count(), 4, nullptr); + colors = storage; + } + } + WebPConfig webp_config; if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, (float) quality)) { return false; @@ -204,44 +172,78 @@ bool SkWEBPImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bm, WebPPicture pic; WebPPictureInit(&pic); - pic.width = bm.width(); - pic.height = bm.height(); + SkAutoTCallVProc autoPic(&pic); + pic.width = pixmap.width(); + pic.height = pixmap.height(); pic.writer = stream_writer; - pic.custom_ptr = (void*)stream; - const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readColors() : nullptr; - const uint8_t* src = (uint8_t*)bm.getPixels(); + // If there is no need to embed an ICC profile, we write directly to the input stream. + // Otherwise, we will first encode to |tmp| and use a mux to add the ICC chunk. libwebp + // forces us to have an encoded image before we can add a profile. + sk_sp icc = pixmap.colorSpace() ? icc_from_color_space(*pixmap.colorSpace()) : nullptr; + SkDynamicMemoryWStream tmp; + pic.custom_ptr = icc ? (void*)&tmp : (void*)stream; + + const uint8_t* src = (uint8_t*)pixmap.addr(); const int rgbStride = pic.width * bpp; + const size_t rowBytes = pixmap.rowBytes(); // Import (for each scanline) the bit-map image (in appropriate color-space) // to RGB color space. - uint8_t* rgb = new uint8_t[rgbStride * pic.height]; + std::unique_ptr rgb(new uint8_t[rgbStride * pic.height]); for (int y = 0; y < pic.height; ++y) { - scanline_import(src + y * bm.rowBytes(), rgb + y * rgbStride, - pic.width, colors); + proc((char*) &rgb[y * rgbStride], (const char*) &src[y * rowBytes], pic.width, bpp, colors); } - bool ok; - if (bpp == 3) { - ok = SkToBool(WebPPictureImportRGB(&pic, rgb, rgbStride)); - } else { - ok = SkToBool(WebPPictureImportRGBA(&pic, rgb, rgbStride)); + auto importProc = WebPPictureImportRGB; + if (3 != bpp) { + if (pixmap.isOpaque()) { + importProc = WebPPictureImportRGBX; + } else { + importProc = WebPPictureImportRGBA; + } } - delete[] rgb; - ok = ok && WebPEncode(&webp_config, &pic); - WebPPictureFree(&pic); + if (!importProc(&pic, &rgb[0], rgbStride)) { + return false; + } - return ok; + if (!WebPEncode(&webp_config, &pic)) { + return false; + } + + if (icc) { + sk_sp encodedData = tmp.detachAsData(); + WebPData encoded = { encodedData->bytes(), encodedData->size() }; + WebPData iccChunk = { icc->bytes(), icc->size() }; + + SkAutoTCallVProc mux(WebPMuxNew()); + if (WEBP_MUX_OK != WebPMuxSetImage(mux, &encoded, 0)) { + return false; + } + + if (WEBP_MUX_OK != WebPMuxSetChunk(mux, "ICCP", &iccChunk, 0)) { + return false; + } + + WebPData assembled; + if (WEBP_MUX_OK != WebPMuxAssemble(mux, &assembled)) { + return false; + } + + stream->write(assembled.bytes, assembled.size); + WebPDataClear(&assembled); + } + + return true; } - -/////////////////////////////////////////////////////////////////////////////// -DEFINE_ENCODER_CREATOR(WEBPImageEncoder); -/////////////////////////////////////////////////////////////////////////////// - -static SkImageEncoder* sk_libwebp_efactory(SkImageEncoder::Type t) { - return (SkImageEncoder::kWEBP_Type == t) ? new SkWEBPImageEncoder : nullptr; +bool SkEncodeImageAsWEBP(SkWStream* stream, const SkPixmap& src, int quality) { + return do_encode(stream, src, SkEncodeOptions(), quality); } -static SkImageEncoder_EncodeReg gEReg(sk_libwebp_efactory); +bool SkEncodeImageAsWEBP(SkWStream* stream, const SkPixmap& src, const SkEncodeOptions& opts) { + return do_encode(stream, src, opts, 100); +} + +#endif diff --git a/gfx/skia/skia/src/images/transform_scanline.h b/gfx/skia/skia/src/images/transform_scanline.h deleted file mode 100644 index a02e98ab0732..000000000000 --- a/gfx/skia/skia/src/images/transform_scanline.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2012 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/** - * Functions to transform scanlines between packed-pixel formats. - */ - -#include "SkBitmap.h" -#include "SkColor.h" -#include "SkColorPriv.h" -#include "SkPreConfig.h" -#include "SkUnPreMultiply.h" - -/** - * Function template for transforming scanlines. - * Transform 'width' pixels from 'src' buffer into 'dst' buffer, - * repacking color channel data as appropriate for the given transformation. - * 'bpp' is bytes per pixel in the 'src' buffer. - */ -typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src, - int width, int bpp); - -/** - * Identity transformation: just copy bytes from src to dst. - */ -static void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src, - int width, int bpp) { - memcpy(dst, src, width * bpp); -} - -/** - * Transform from kRGB_565_Config to 3-bytes-per-pixel RGB. - * Alpha channel data is not present in kRGB_565_Config format, so there is no - * alpha channel data to preserve. - */ -static void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src, - int width, int) { - const uint16_t* srcP = (const uint16_t*)src; - for (int i = 0; i < width; i++) { - unsigned c = *srcP++; - *dst++ = SkPacked16ToR32(c); - *dst++ = SkPacked16ToG32(c); - *dst++ = SkPacked16ToB32(c); - } -} - -/** - * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB. - * Alpha channel data is abandoned. - */ -static void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src, - int width, int) { - const uint32_t* srcP = (const SkPMColor*)src; - for (int i = 0; i < width; i++) { - uint32_t c = *srcP++; - *dst++ = (c >> 0) & 0xFF; - *dst++ = (c >> 8) & 0xFF; - *dst++ = (c >> 16) & 0xFF; - } -} - -/** - * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB. - * Alpha channel data is abandoned. - */ -static void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src, - int width, int) { - const uint32_t* srcP = (const SkPMColor*)src; - for (int i = 0; i < width; i++) { - uint32_t c = *srcP++; - *dst++ = (c >> 16) & 0xFF; - *dst++ = (c >> 8) & 0xFF; - *dst++ = (c >> 0) & 0xFF; - } -} - -/** - * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB. - * Alpha channel data, if any, is abandoned. - */ -static void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src, - int width, int) { - const SkPMColor16* srcP = (const SkPMColor16*)src; - for (int i = 0; i < width; i++) { - SkPMColor16 c = *srcP++; - *dst++ = SkPacked4444ToR32(c); - *dst++ = SkPacked4444ToG32(c); - *dst++ = SkPacked4444ToB32(c); - } -} - -template -static inline void transform_scanline_unpremultiply(char* SK_RESTRICT dst, - const char* SK_RESTRICT src, int width, int) { - const uint32_t* srcP = (const SkPMColor*)src; - const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); - - for (int i = 0; i < width; i++) { - uint32_t c = *srcP++; - unsigned r, g, b, a; - if (kIsRGBA) { - r = (c >> 0) & 0xFF; - g = (c >> 8) & 0xFF; - b = (c >> 16) & 0xFF; - a = (c >> 24) & 0xFF; - } else { - r = (c >> 16) & 0xFF; - g = (c >> 8) & 0xFF; - b = (c >> 0) & 0xFF; - a = (c >> 24) & 0xFF; - } - - if (0 != a && 255 != a) { - SkUnPreMultiply::Scale scale = table[a]; - r = SkUnPreMultiply::ApplyScale(scale, r); - g = SkUnPreMultiply::ApplyScale(scale, g); - b = SkUnPreMultiply::ApplyScale(scale, b); - } - *dst++ = r; - *dst++ = g; - *dst++ = b; - *dst++ = a; - } -} - -/** - * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. - */ -static void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, - int width, int bpp) { - transform_scanline_unpremultiply(dst, src, width, bpp); -} - -/** - * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. - */ -static void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, - int width, int bpp) { - transform_scanline_unpremultiply(dst, src, width, bpp); -} - -/** - * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. - */ -static void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, - int width, int) { - const uint32_t* srcP = (const SkPMColor*)src; - for (int i = 0; i < width; i++) { - uint32_t c = *srcP++; - *dst++ = (c >> 16) & 0xFF; - *dst++ = (c >> 8) & 0xFF; - *dst++ = (c >> 0) & 0xFF; - *dst++ = (c >> 24) & 0xFF; - } -} - -/** - * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA, - * with scaling of RGB based on alpha channel. - */ -static void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src, - int width, int) { - const SkPMColor16* srcP = (const SkPMColor16*)src; - const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); - - for (int i = 0; i < width; i++) { - SkPMColor16 c = *srcP++; - unsigned a = SkPacked4444ToA32(c); - unsigned r = SkPacked4444ToR32(c); - unsigned g = SkPacked4444ToG32(c); - unsigned b = SkPacked4444ToB32(c); - - if (0 != a && 255 != a) { - SkUnPreMultiply::Scale scale = table[a]; - r = SkUnPreMultiply::ApplyScale(scale, r); - g = SkUnPreMultiply::ApplyScale(scale, g); - b = SkUnPreMultiply::ApplyScale(scale, b); - } - *dst++ = r; - *dst++ = g; - *dst++ = b; - *dst++ = a; - } -} diff --git a/gfx/skia/skia/src/jumper/SkJumper.cpp b/gfx/skia/skia/src/jumper/SkJumper.cpp new file mode 100644 index 000000000000..0d4446ce479a --- /dev/null +++ b/gfx/skia/skia/src/jumper/SkJumper.cpp @@ -0,0 +1,359 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorPriv.h" +#include "SkCpu.h" +#include "SkJumper.h" +#include "SkRasterPipeline.h" +#include "SkTemplates.h" + +// A debugging mode that helps prioritize porting stages to SkJumper. +#if 0 + #include "SkOnce.h" + #include + + #define M(st) {0}, + static std::atomic gMissing[] = { SK_RASTER_PIPELINE_STAGES(M) }; + #undef M + + #define M(st) #st, + static const char* gNames[] = { SK_RASTER_PIPELINE_STAGES(M) }; + #undef M + + #define WHATS_NEXT +#endif + +// We'll use __has_feature(memory_sanitizer) to detect MSAN. +// SkJumper_generated.S is not compiled with MSAN, so MSAN would yell really loud. +#if !defined(__has_feature) + #define __has_feature(x) 0 +#endif + +// Stages expect these constants to be set to these values. +// It's fine to rearrange and add new ones if you update SkJumper_constants. +using K = const SkJumper_constants; +static K kConstants = { + {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f}, +}; + +#define STAGES(M) \ + M(seed_shader) \ + M(constant_color) \ + M(clear) \ + M(srcatop) \ + M(dstatop) \ + M(srcin) \ + M(dstin) \ + M(srcout) \ + M(dstout) \ + M(srcover) \ + M(dstover) \ + M(modulate) \ + M(multiply) \ + M(plus_) \ + M(screen) \ + M(xor_) \ + M(darken) \ + M(lighten) \ + M(difference) \ + M(exclusion) \ + M(colorburn) \ + M(colordodge) \ + M(hardlight) \ + M(overlay) \ + M(softlight) \ + M(clamp_0) \ + M(clamp_1) \ + M(clamp_a) \ + M(set_rgb) \ + M(swap_rb) \ + M(swap) \ + M(move_src_dst) \ + M(move_dst_src) \ + M(premul) \ + M(unpremul) \ + M(from_srgb) \ + M(to_srgb) \ + M(from_2dot2) \ + M(to_2dot2) \ + M(rgb_to_hsl) \ + M(hsl_to_rgb) \ + M(scale_1_float) \ + M(scale_u8) \ + M(lerp_1_float) \ + M(lerp_u8) \ + M(lerp_565) \ + M(load_tables) \ + M(byte_tables) \ + M(byte_tables_rgb) \ + M(load_a8) \ + M(gather_a8) \ + M(store_a8) \ + M(load_g8) \ + M(gather_g8) \ + M(gather_i8) \ + M(load_565) \ + M(gather_565) \ + M(store_565) \ + M(load_4444) \ + M(gather_4444) \ + M(store_4444) \ + M(load_8888) \ + M(gather_8888) \ + M(store_8888) \ + M(load_f16) \ + M(gather_f16) \ + M(store_f16) \ + M(load_u16_be) \ + M(store_u16_be) \ + M(load_f32) \ + M(store_f32) \ + M(luminance_to_alpha) \ + M(matrix_2x3) \ + M(matrix_3x4) \ + M(matrix_4x5) \ + M(matrix_perspective) \ + M(clamp_x) \ + M(clamp_y) \ + M(repeat_x) \ + M(repeat_y) \ + M(mirror_x) \ + M(mirror_y) \ + M(save_xy) \ + M(accumulate) \ + M(bilinear_nx) M(bilinear_px) M(bilinear_ny) M(bilinear_py) \ + M(bicubic_n3x) M(bicubic_n1x) M(bicubic_p1x) M(bicubic_p3x) \ + M(bicubic_n3y) M(bicubic_n1y) M(bicubic_p1y) M(bicubic_p3y) \ + M(linear_gradient) \ + M(linear_gradient_2stops) + +// We can't express the real types of most stage functions portably, so we use a stand-in. +// We'll only ever call start_pipeline(), which then chains into the rest for us. +using StageFn = void(void); + +// Some platforms expect C "name" maps to asm "_name", others to "name". +#if defined(__APPLE__) + #define ASM(name, suffix) sk_##name##_##suffix +#else + #define ASM(name, suffix) _sk_##name##_##suffix +#endif + +extern "C" { + +#if __has_feature(memory_sanitizer) + // We'll just run portable code. + +#elif defined(__aarch64__) + size_t ASM(start_pipeline,aarch64)(size_t, void**, K*, size_t); + StageFn ASM(just_return,aarch64); + #define M(st) StageFn ASM(st,aarch64); + STAGES(M) + #undef M + +#elif defined(__arm__) + size_t ASM(start_pipeline,vfp4)(size_t, void**, K*, size_t); + StageFn ASM(just_return,vfp4); + #define M(st) StageFn ASM(st,vfp4); + STAGES(M) + #undef M + +#elif defined(__x86_64__) || defined(_M_X64) + size_t ASM(start_pipeline,hsw )(size_t, void**, K*, size_t); + size_t ASM(start_pipeline,avx )(size_t, void**, K*, size_t); + size_t ASM(start_pipeline,sse41)(size_t, void**, K*, size_t); + size_t ASM(start_pipeline,sse2 )(size_t, void**, K*, size_t); + + StageFn ASM(just_return,hsw), + ASM(just_return,avx), + ASM(just_return,sse41), + ASM(just_return,sse2); + + #define M(st) StageFn ASM(st,hsw); + STAGES(M) + #undef M + #define M(st) StageFn ASM(st,avx); + STAGES(M) + #undef M + #define M(st) StageFn ASM(st,sse41); + STAGES(M) + #undef M + #define M(st) StageFn ASM(st,sse2); + STAGES(M) + #undef M +#endif + + // Portable, single-pixel stages. + size_t sk_start_pipeline(size_t, void**, K*, size_t); + StageFn sk_just_return; + #define M(st) StageFn sk_##st; + STAGES(M) + #undef M +} + +// Translate SkRasterPipeline's StockStage enum to StageFn function pointers. + +#if __has_feature(memory_sanitizer) + // We'll just run portable code. + +#elif defined(__aarch64__) + static StageFn* lookup_aarch64(SkRasterPipeline::StockStage st) { + switch (st) { + default: return nullptr; + #define M(st) case SkRasterPipeline::st: return ASM(st,aarch64); + STAGES(M) + #undef M + } + } + +#elif defined(__arm__) + static StageFn* lookup_vfp4(SkRasterPipeline::StockStage st) { + switch (st) { + default: return nullptr; + #define M(st) case SkRasterPipeline::st: return ASM(st,vfp4); + STAGES(M) + #undef M + } + } + +#elif defined(__x86_64__) || defined(_M_X64) + static StageFn* lookup_hsw(SkRasterPipeline::StockStage st) { + switch (st) { + default: + #ifdef WHATS_NEXT + gMissing[st]++; + #endif + return nullptr; + #define M(st) case SkRasterPipeline::st: return ASM(st,hsw); + STAGES(M) + #undef M + } + } + static StageFn* lookup_avx(SkRasterPipeline::StockStage st) { + switch (st) { + default: + #ifdef WHATS_NEXT + gMissing[st]++; + #endif + return nullptr; + #define M(st) case SkRasterPipeline::st: return ASM(st,avx); + STAGES(M) + #undef M + } + } + static StageFn* lookup_sse41(SkRasterPipeline::StockStage st) { + switch (st) { + default: + #ifdef WHATS_NEXT + gMissing[st]++; + #endif + return nullptr; + #define M(st) case SkRasterPipeline::st: return ASM(st,sse41); + STAGES(M) + #undef M + } + } + static StageFn* lookup_sse2(SkRasterPipeline::StockStage st) { + switch (st) { + default: return nullptr; + #define M(st) case SkRasterPipeline::st: return ASM(st,sse2); + STAGES(M) + #undef M + } + } +#endif + +static StageFn* lookup_portable(SkRasterPipeline::StockStage st) { + switch (st) { + default: return nullptr; + #define M(st) case SkRasterPipeline::st: return sk_##st; + STAGES(M) + #undef M + } +} + +bool SkRasterPipeline::run_with_jumper(size_t x, size_t n) const { +#ifdef WHATS_NEXT + static SkOnce once; + once([] { + atexit([] { + for (int i = 0; i < (int)SK_ARRAY_COUNT(gMissing); i++) { + if (int n = gMissing[i].load()) { + SkDebugf("%10d %s\n", n, gNames[i]); + } + } + }); + }); +#endif + + SkAutoSTMalloc<64, void*> program(2*fStages.size() + 1); + const size_t limit = x+n; + + auto build_and_run = [&](size_t min_stride, + StageFn* (*lookup)(SkRasterPipeline::StockStage), + StageFn* just_return, + size_t (*start_pipeline)(size_t, void**, K*, size_t)) { + if (x + min_stride <= limit) { + void** ip = program.get(); + for (auto&& st : fStages) { + auto fn = lookup(st.stage); + if (!fn) { + return false; + } + *ip++ = (void*)fn; + if (st.ctx) { + *ip++ = st.ctx; + } + } + *ip = (void*)just_return; + + x = start_pipeline(x, program.get(), &kConstants, limit); + } + return true; + }; + + // While possible, build and run at full vector stride. +#if __has_feature(memory_sanitizer) + // We'll just run portable code. + +#elif defined(__aarch64__) + if (!build_and_run(4, lookup_aarch64, ASM(just_return,aarch64), ASM(start_pipeline,aarch64))) { + return false; + } + +#elif defined(__arm__) + if (1 && SkCpu::Supports(SkCpu::NEON|SkCpu::NEON_FMA|SkCpu::VFP_FP16)) { + if (!build_and_run(2, lookup_vfp4, ASM(just_return,vfp4), ASM(start_pipeline,vfp4))) { + return false; + } + } + +#elif defined(__x86_64__) || defined(_M_X64) + if (1 && SkCpu::Supports(SkCpu::HSW)) { + if (!build_and_run(1, lookup_hsw, ASM(just_return,hsw), ASM(start_pipeline,hsw))) { + return false; + } + } + if (1 && SkCpu::Supports(SkCpu::AVX)) { + if (!build_and_run(1, lookup_avx, ASM(just_return,avx), ASM(start_pipeline,avx))) { + return false; + } + } + if (1 && SkCpu::Supports(SkCpu::SSE41)) { + if (!build_and_run(4, lookup_sse41, ASM(just_return,sse41), ASM(start_pipeline,sse41))) { + return false; + } + } + if (1 && SkCpu::Supports(SkCpu::SSE2)) { + if (!build_and_run(4, lookup_sse2, ASM(just_return,sse2), ASM(start_pipeline,sse2))) { + return false; + } + } +#endif + + // Finish up any leftover with portable code one pixel at a time. + return build_and_run(1, lookup_portable, sk_just_return, sk_start_pipeline); +} diff --git a/gfx/skia/skia/src/jumper/SkJumper.h b/gfx/skia/skia/src/jumper/SkJumper.h new file mode 100644 index 000000000000..7a3f4e85f508 --- /dev/null +++ b/gfx/skia/skia/src/jumper/SkJumper.h @@ -0,0 +1,77 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkJumper_DEFINED +#define SkJumper_DEFINED + +// This file contains definitions shared by SkJumper.cpp (compiled normally as part of Skia) +// and SkJumper_stages.cpp (compiled into Skia _and_ offline into SkJumper_generated.h). +// Keep it simple! + +#if defined(JUMPER) && (defined(__aarch64__) || defined(__arm__)) + // To reduce SkJumper's dependency on the Android NDK, + // we provide what we need from , , and ourselves. + #define memcpy __builtin_memcpy + + using int8_t = signed char; + using uint8_t = unsigned char; + using int16_t = signed short; + using uint16_t = unsigned short; + using int32_t = signed int; + using uint32_t = unsigned int; + #if defined(__aarch64__) + using int64_t = signed long; + using uint64_t = unsigned long; + using size_t = uint64_t; + #else + using int64_t = signed long long; + using uint64_t = unsigned long long; + using size_t = uint32_t; + #endif + + // Now pretend we've included (or it'll be included again by ). + #define __CLANG_STDINT_H + #define _STDINT_H_ +#else + #include + #include +#endif + +// SkJumper_stages.cpp has some unusual constraints on what constants it can use. +// +// If the constant is baked into the instruction, that's ok. +// If the constant is synthesized through code, that's ok. +// If the constant is loaded from memory, that's no good. +// +// We offer a couple facilities to get at any other constants you need: +// - the C() function usually constrains constants to be directly baked into an instruction; or +// - the _i and _f user-defined literal operators call C() for you in a prettier way; or +// - you can load values from this struct. + +static const int SkJumper_kMaxStride = 8; + +struct SkJumper_constants { + float iota[SkJumper_kMaxStride]; // 0,1,2,3,4,... +}; + +struct SkJumper_GatherCtx { + const void* pixels; + const uint32_t* ctable; + int stride; +}; + +// State shared by save_xy, accumulate, and bilinear_* / bicubic_*. +struct SkJumper_SamplerCtx { + float x[SkJumper_kMaxStride]; + float y[SkJumper_kMaxStride]; + float fx[SkJumper_kMaxStride]; + float fy[SkJumper_kMaxStride]; + float scalex[SkJumper_kMaxStride]; + float scaley[SkJumper_kMaxStride]; +}; + +#endif//SkJumper_DEFINED diff --git a/gfx/skia/skia/src/jumper/SkJumper_generated.S b/gfx/skia/skia/src/jumper/SkJumper_generated.S new file mode 100644 index 000000000000..80a08b990fb3 --- /dev/null +++ b/gfx/skia/skia/src/jumper/SkJumper_generated.S @@ -0,0 +1,21578 @@ +# Copyright 2017 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file is generated semi-automatically with this command: +# $ src/jumper/build_stages.py + +#if defined(__MACH__) + #define HIDDEN .private_extern +#else + #define HIDDEN .hidden + .section .note.GNU-stack,"",%progbits +#endif +.text +#if defined(__aarch64__) +.balign 4 + +HIDDEN _sk_start_pipeline_aarch64 +.globl _sk_start_pipeline_aarch64 +_sk_start_pipeline_aarch64: + .long 0xa9bd5bf7 // stp x23, x22, [sp, #-48]! + .long 0xa90153f5 // stp x21, x20, [sp, #16] + .long 0xa9027bf3 // stp x19, x30, [sp, #32] + .long 0xaa0103f4 // mov x20, x1 + .long 0xf8408697 // ldr x23, [x20], #8 + .long 0xaa0003f5 // mov x21, x0 + .long 0xaa0303f3 // mov x19, x3 + .long 0x910012a8 // add x8, x21, #0x4 + .long 0xeb13011f // cmp x8, x19 + .long 0xaa0203f6 // mov x22, x2 + .long 0x54000069 // b.ls 34 // b.plast + .long 0xaa1503e0 // mov x0, x21 + .long 0x14000012 // b 78 + .long 0x6f00e400 // movi v0.2d, #0x0 + .long 0x6f00e401 // movi v1.2d, #0x0 + .long 0x6f00e402 // movi v2.2d, #0x0 + .long 0x6f00e403 // movi v3.2d, #0x0 + .long 0x6f00e404 // movi v4.2d, #0x0 + .long 0x6f00e405 // movi v5.2d, #0x0 + .long 0x6f00e406 // movi v6.2d, #0x0 + .long 0x6f00e407 // movi v7.2d, #0x0 + .long 0xaa1503e0 // mov x0, x21 + .long 0xaa1403e1 // mov x1, x20 + .long 0xaa1603e2 // mov x2, x22 + .long 0xd63f02e0 // blr x23 + .long 0x910012a0 // add x0, x21, #0x4 + .long 0x910022a8 // add x8, x21, #0x8 + .long 0xeb13011f // cmp x8, x19 + .long 0xaa0003f5 // mov x21, x0 + .long 0x54fffe09 // b.ls 34 // b.plast + .long 0xa9427bf3 // ldp x19, x30, [sp, #32] + .long 0xa94153f5 // ldp x21, x20, [sp, #16] + .long 0xa8c35bf7 // ldp x23, x22, [sp], #48 + .long 0xd65f03c0 // ret + +HIDDEN _sk_just_return_aarch64 +.globl _sk_just_return_aarch64 +_sk_just_return_aarch64: + .long 0xd65f03c0 // ret + +HIDDEN _sk_seed_shader_aarch64 +.globl _sk_seed_shader_aarch64 +_sk_seed_shader_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x3dc00046 // ldr q6, [x2] + .long 0x4e040c00 // dup v0.4s, w0 + .long 0x4f0167e7 // movi v7.4s, #0x3f, lsl #24 + .long 0x4d40c901 // ld1r {v1.4s}, [x8] + .long 0x4e21d800 // scvtf v0.4s, v0.4s + .long 0x4e27d400 // fadd v0.4s, v0.4s, v7.4s + .long 0x4f03f602 // fmov v2.4s, #1.000000000000000000e+00 + .long 0x4e21d821 // scvtf v1.4s, v1.4s + .long 0x6f00e403 // movi v3.2d, #0x0 + .long 0x6f00e404 // movi v4.2d, #0x0 + .long 0x6f00e405 // movi v5.2d, #0x0 + .long 0x4e26d400 // fadd v0.4s, v0.4s, v6.4s + .long 0x6f00e406 // movi v6.2d, #0x0 + .long 0x4e27d421 // fadd v1.4s, v1.4s, v7.4s + .long 0x6f00e407 // movi v7.2d, #0x0 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_constant_color_aarch64 +.globl _sk_constant_color_aarch64 +_sk_constant_color_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xaa0803ea // mov x10, x8 + .long 0x4ddfc940 // ld1r {v0.4s}, [x10], #4 + .long 0x91002109 // add x9, x8, #0x8 + .long 0x91003108 // add x8, x8, #0xc + .long 0x4d40c922 // ld1r {v2.4s}, [x9] + .long 0x4d40c903 // ld1r {v3.4s}, [x8] + .long 0x4d40c941 // ld1r {v1.4s}, [x10] + .long 0xd61f0060 // br x3 + +HIDDEN _sk_clear_aarch64 +.globl _sk_clear_aarch64 +_sk_clear_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6f00e400 // movi v0.2d, #0x0 + .long 0x6f00e401 // movi v1.2d, #0x0 + .long 0x6f00e402 // movi v2.2d, #0x0 + .long 0x6f00e403 // movi v3.2d, #0x0 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_srcatop_aarch64 +.globl _sk_srcatop_aarch64 +_sk_srcatop_aarch64: + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x6e27dc00 // fmul v0.4s, v0.4s, v7.4s + .long 0x6e27dc21 // fmul v1.4s, v1.4s, v7.4s + .long 0x6e27dc42 // fmul v2.4s, v2.4s, v7.4s + .long 0x4ea3d610 // fsub v16.4s, v16.4s, v3.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4e30cc80 // fmla v0.4s, v4.4s, v16.4s + .long 0x4e30cca1 // fmla v1.4s, v5.4s, v16.4s + .long 0x4e30ccc2 // fmla v2.4s, v6.4s, v16.4s + .long 0x6e27de10 // fmul v16.4s, v16.4s, v7.4s + .long 0x4e23ccf0 // fmla v16.4s, v7.4s, v3.4s + .long 0x4eb01e03 // mov v3.16b, v16.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_dstatop_aarch64 +.globl _sk_dstatop_aarch64 +_sk_dstatop_aarch64: + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x4ea7d610 // fsub v16.4s, v16.4s, v7.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e20de00 // fmul v0.4s, v16.4s, v0.4s + .long 0x6e21de01 // fmul v1.4s, v16.4s, v1.4s + .long 0x6e22de02 // fmul v2.4s, v16.4s, v2.4s + .long 0x6e23de10 // fmul v16.4s, v16.4s, v3.4s + .long 0x4e23ccf0 // fmla v16.4s, v7.4s, v3.4s + .long 0x4e23cc80 // fmla v0.4s, v4.4s, v3.4s + .long 0x4e23cca1 // fmla v1.4s, v5.4s, v3.4s + .long 0x4e23ccc2 // fmla v2.4s, v6.4s, v3.4s + .long 0x4eb01e03 // mov v3.16b, v16.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_srcin_aarch64 +.globl _sk_srcin_aarch64 +_sk_srcin_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e27dc00 // fmul v0.4s, v0.4s, v7.4s + .long 0x6e27dc21 // fmul v1.4s, v1.4s, v7.4s + .long 0x6e27dc42 // fmul v2.4s, v2.4s, v7.4s + .long 0x6e27dc63 // fmul v3.4s, v3.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_dstin_aarch64 +.globl _sk_dstin_aarch64 +_sk_dstin_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e24dc60 // fmul v0.4s, v3.4s, v4.4s + .long 0x6e25dc61 // fmul v1.4s, v3.4s, v5.4s + .long 0x6e26dc62 // fmul v2.4s, v3.4s, v6.4s + .long 0x6e27dc63 // fmul v3.4s, v3.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_srcout_aarch64 +.globl _sk_srcout_aarch64 +_sk_srcout_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x4ea7d610 // fsub v16.4s, v16.4s, v7.4s + .long 0x6e20de00 // fmul v0.4s, v16.4s, v0.4s + .long 0x6e21de01 // fmul v1.4s, v16.4s, v1.4s + .long 0x6e22de02 // fmul v2.4s, v16.4s, v2.4s + .long 0x6e23de03 // fmul v3.4s, v16.4s, v3.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_dstout_aarch64 +.globl _sk_dstout_aarch64 +_sk_dstout_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4f03f600 // fmov v0.4s, #1.000000000000000000e+00 + .long 0x4ea3d403 // fsub v3.4s, v0.4s, v3.4s + .long 0x6e24dc60 // fmul v0.4s, v3.4s, v4.4s + .long 0x6e25dc61 // fmul v1.4s, v3.4s, v5.4s + .long 0x6e26dc62 // fmul v2.4s, v3.4s, v6.4s + .long 0x6e27dc63 // fmul v3.4s, v3.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_srcover_aarch64 +.globl _sk_srcover_aarch64 +_sk_srcover_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x4ea3d610 // fsub v16.4s, v16.4s, v3.4s + .long 0x4e24ce00 // fmla v0.4s, v16.4s, v4.4s + .long 0x4e25ce01 // fmla v1.4s, v16.4s, v5.4s + .long 0x4e26ce02 // fmla v2.4s, v16.4s, v6.4s + .long 0x4e27ce03 // fmla v3.4s, v16.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_dstover_aarch64 +.globl _sk_dstover_aarch64 +_sk_dstover_aarch64: + .long 0x4f03f611 // fmov v17.4s, #1.000000000000000000e+00 + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4ea41c90 // mov v16.16b, v4.16b + .long 0x4ea7d634 // fsub v20.4s, v17.4s, v7.4s + .long 0x4ea51cb1 // mov v17.16b, v5.16b + .long 0x4ea61cd2 // mov v18.16b, v6.16b + .long 0x4ea71cf3 // mov v19.16b, v7.16b + .long 0x4e20ce90 // fmla v16.4s, v20.4s, v0.4s + .long 0x4e21ce91 // fmla v17.4s, v20.4s, v1.4s + .long 0x4e22ce92 // fmla v18.4s, v20.4s, v2.4s + .long 0x4e23ce93 // fmla v19.4s, v20.4s, v3.4s + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0x4eb11e21 // mov v1.16b, v17.16b + .long 0x4eb21e42 // mov v2.16b, v18.16b + .long 0x4eb31e63 // mov v3.16b, v19.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_modulate_aarch64 +.globl _sk_modulate_aarch64 +_sk_modulate_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e24dc00 // fmul v0.4s, v0.4s, v4.4s + .long 0x6e25dc21 // fmul v1.4s, v1.4s, v5.4s + .long 0x6e26dc42 // fmul v2.4s, v2.4s, v6.4s + .long 0x6e27dc63 // fmul v3.4s, v3.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_multiply_aarch64 +.globl _sk_multiply_aarch64 +_sk_multiply_aarch64: + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x4ea7d613 // fsub v19.4s, v16.4s, v7.4s + .long 0x4ea3d614 // fsub v20.4s, v16.4s, v3.4s + .long 0x6e20de70 // fmul v16.4s, v19.4s, v0.4s + .long 0x6e21de71 // fmul v17.4s, v19.4s, v1.4s + .long 0x6e22de72 // fmul v18.4s, v19.4s, v2.4s + .long 0x6e23de73 // fmul v19.4s, v19.4s, v3.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4e34cc90 // fmla v16.4s, v4.4s, v20.4s + .long 0x4e34ccb1 // fmla v17.4s, v5.4s, v20.4s + .long 0x4e34ccd2 // fmla v18.4s, v6.4s, v20.4s + .long 0x4e34ccf3 // fmla v19.4s, v7.4s, v20.4s + .long 0x4e20cc90 // fmla v16.4s, v4.4s, v0.4s + .long 0x4e21ccb1 // fmla v17.4s, v5.4s, v1.4s + .long 0x4e22ccd2 // fmla v18.4s, v6.4s, v2.4s + .long 0x4e23ccf3 // fmla v19.4s, v7.4s, v3.4s + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0x4eb11e21 // mov v1.16b, v17.16b + .long 0x4eb21e42 // mov v2.16b, v18.16b + .long 0x4eb31e63 // mov v3.16b, v19.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_plus__aarch64 +.globl _sk_plus__aarch64 +_sk_plus__aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4e24d400 // fadd v0.4s, v0.4s, v4.4s + .long 0x4e25d421 // fadd v1.4s, v1.4s, v5.4s + .long 0x4e26d442 // fadd v2.4s, v2.4s, v6.4s + .long 0x4e27d463 // fadd v3.4s, v3.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_screen_aarch64 +.globl _sk_screen_aarch64 +_sk_screen_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4e24d410 // fadd v16.4s, v0.4s, v4.4s + .long 0x4e25d431 // fadd v17.4s, v1.4s, v5.4s + .long 0x4e26d452 // fadd v18.4s, v2.4s, v6.4s + .long 0x4e27d473 // fadd v19.4s, v3.4s, v7.4s + .long 0x4ea4cc10 // fmls v16.4s, v0.4s, v4.4s + .long 0x4ea5cc31 // fmls v17.4s, v1.4s, v5.4s + .long 0x4ea6cc52 // fmls v18.4s, v2.4s, v6.4s + .long 0x4ea7cc73 // fmls v19.4s, v3.4s, v7.4s + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0x4eb11e21 // mov v1.16b, v17.16b + .long 0x4eb21e42 // mov v2.16b, v18.16b + .long 0x4eb31e63 // mov v3.16b, v19.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_xor__aarch64 +.globl _sk_xor__aarch64 +_sk_xor__aarch64: + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4ea7d611 // fsub v17.4s, v16.4s, v7.4s + .long 0x4ea3d610 // fsub v16.4s, v16.4s, v3.4s + .long 0x6e20de20 // fmul v0.4s, v17.4s, v0.4s + .long 0x6e21de21 // fmul v1.4s, v17.4s, v1.4s + .long 0x6e22de22 // fmul v2.4s, v17.4s, v2.4s + .long 0x6e23de23 // fmul v3.4s, v17.4s, v3.4s + .long 0x4e30cc80 // fmla v0.4s, v4.4s, v16.4s + .long 0x4e30cca1 // fmla v1.4s, v5.4s, v16.4s + .long 0x4e30ccc2 // fmla v2.4s, v6.4s, v16.4s + .long 0x4e30cce3 // fmla v3.4s, v7.4s, v16.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_darken_aarch64 +.globl _sk_darken_aarch64 +_sk_darken_aarch64: + .long 0x6e27dc10 // fmul v16.4s, v0.4s, v7.4s + .long 0x6e24dc71 // fmul v17.4s, v3.4s, v4.4s + .long 0x6e27dc32 // fmul v18.4s, v1.4s, v7.4s + .long 0x6e25dc73 // fmul v19.4s, v3.4s, v5.4s + .long 0x4e31f610 // fmax v16.4s, v16.4s, v17.4s + .long 0x4e24d400 // fadd v0.4s, v0.4s, v4.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e27dc51 // fmul v17.4s, v2.4s, v7.4s + .long 0x4e33f652 // fmax v18.4s, v18.4s, v19.4s + .long 0x6e26dc73 // fmul v19.4s, v3.4s, v6.4s + .long 0x4eb0d400 // fsub v0.4s, v0.4s, v16.4s + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x4e33f631 // fmax v17.4s, v17.4s, v19.4s + .long 0x4e25d421 // fadd v1.4s, v1.4s, v5.4s + .long 0x4e26d442 // fadd v2.4s, v2.4s, v6.4s + .long 0x4ea3d610 // fsub v16.4s, v16.4s, v3.4s + .long 0x4eb2d421 // fsub v1.4s, v1.4s, v18.4s + .long 0x4eb1d442 // fsub v2.4s, v2.4s, v17.4s + .long 0x4e27ce03 // fmla v3.4s, v16.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_lighten_aarch64 +.globl _sk_lighten_aarch64 +_sk_lighten_aarch64: + .long 0x6e27dc10 // fmul v16.4s, v0.4s, v7.4s + .long 0x6e24dc71 // fmul v17.4s, v3.4s, v4.4s + .long 0x6e27dc32 // fmul v18.4s, v1.4s, v7.4s + .long 0x6e25dc73 // fmul v19.4s, v3.4s, v5.4s + .long 0x4eb1f610 // fmin v16.4s, v16.4s, v17.4s + .long 0x4e24d400 // fadd v0.4s, v0.4s, v4.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e27dc51 // fmul v17.4s, v2.4s, v7.4s + .long 0x4eb3f652 // fmin v18.4s, v18.4s, v19.4s + .long 0x6e26dc73 // fmul v19.4s, v3.4s, v6.4s + .long 0x4eb0d400 // fsub v0.4s, v0.4s, v16.4s + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x4eb3f631 // fmin v17.4s, v17.4s, v19.4s + .long 0x4e25d421 // fadd v1.4s, v1.4s, v5.4s + .long 0x4e26d442 // fadd v2.4s, v2.4s, v6.4s + .long 0x4ea3d610 // fsub v16.4s, v16.4s, v3.4s + .long 0x4eb2d421 // fsub v1.4s, v1.4s, v18.4s + .long 0x4eb1d442 // fsub v2.4s, v2.4s, v17.4s + .long 0x4e27ce03 // fmla v3.4s, v16.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_difference_aarch64 +.globl _sk_difference_aarch64 +_sk_difference_aarch64: + .long 0x6e27dc10 // fmul v16.4s, v0.4s, v7.4s + .long 0x6e24dc71 // fmul v17.4s, v3.4s, v4.4s + .long 0x6e27dc32 // fmul v18.4s, v1.4s, v7.4s + .long 0x6e25dc73 // fmul v19.4s, v3.4s, v5.4s + .long 0x4eb1f610 // fmin v16.4s, v16.4s, v17.4s + .long 0x4eb3f652 // fmin v18.4s, v18.4s, v19.4s + .long 0x4e24d400 // fadd v0.4s, v0.4s, v4.4s + .long 0x4e30d610 // fadd v16.4s, v16.4s, v16.4s + .long 0x6e27dc51 // fmul v17.4s, v2.4s, v7.4s + .long 0x6e26dc73 // fmul v19.4s, v3.4s, v6.4s + .long 0x4eb0d400 // fsub v0.4s, v0.4s, v16.4s + .long 0x4e25d421 // fadd v1.4s, v1.4s, v5.4s + .long 0x4e32d650 // fadd v16.4s, v18.4s, v18.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4eb3f631 // fmin v17.4s, v17.4s, v19.4s + .long 0x4eb0d421 // fsub v1.4s, v1.4s, v16.4s + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x4e26d442 // fadd v2.4s, v2.4s, v6.4s + .long 0x4e31d631 // fadd v17.4s, v17.4s, v17.4s + .long 0x4ea3d610 // fsub v16.4s, v16.4s, v3.4s + .long 0x4eb1d442 // fsub v2.4s, v2.4s, v17.4s + .long 0x4e27ce03 // fmla v3.4s, v16.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_exclusion_aarch64 +.globl _sk_exclusion_aarch64 +_sk_exclusion_aarch64: + .long 0x4e24d410 // fadd v16.4s, v0.4s, v4.4s + .long 0x6e24dc00 // fmul v0.4s, v0.4s, v4.4s + .long 0x4e20d400 // fadd v0.4s, v0.4s, v0.4s + .long 0x4ea0d600 // fsub v0.4s, v16.4s, v0.4s + .long 0x4e25d430 // fadd v16.4s, v1.4s, v5.4s + .long 0x6e25dc21 // fmul v1.4s, v1.4s, v5.4s + .long 0x4e21d421 // fadd v1.4s, v1.4s, v1.4s + .long 0x4ea1d601 // fsub v1.4s, v16.4s, v1.4s + .long 0x4e26d450 // fadd v16.4s, v2.4s, v6.4s + .long 0x6e26dc42 // fmul v2.4s, v2.4s, v6.4s + .long 0x4e22d442 // fadd v2.4s, v2.4s, v2.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4ea2d602 // fsub v2.4s, v16.4s, v2.4s + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x4ea3d610 // fsub v16.4s, v16.4s, v3.4s + .long 0x4e27ce03 // fmla v3.4s, v16.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_colorburn_aarch64 +.globl _sk_colorburn_aarch64 +_sk_colorburn_aarch64: + .long 0x4ea4d4f3 // fsub v19.4s, v7.4s, v4.4s + .long 0x6e23de73 // fmul v19.4s, v19.4s, v3.4s + .long 0x4f03f611 // fmov v17.4s, #1.000000000000000000e+00 + .long 0x6e20fe73 // fdiv v19.4s, v19.4s, v0.4s + .long 0x4ea7d634 // fsub v20.4s, v17.4s, v7.4s + .long 0x4eb3f4f3 // fmin v19.4s, v7.4s, v19.4s + .long 0x6e20de95 // fmul v21.4s, v20.4s, v0.4s + .long 0x4eb3d4f3 // fsub v19.4s, v7.4s, v19.4s + .long 0x4e24d6b6 // fadd v22.4s, v21.4s, v4.4s + .long 0x4e33cc75 // fmla v21.4s, v3.4s, v19.4s + .long 0x4ea5d4f3 // fsub v19.4s, v7.4s, v5.4s + .long 0x6e23de73 // fmul v19.4s, v19.4s, v3.4s + .long 0x6e21fe73 // fdiv v19.4s, v19.4s, v1.4s + .long 0x4ea0d812 // fcmeq v18.4s, v0.4s, #0.0 + .long 0x4eb3f4f3 // fmin v19.4s, v7.4s, v19.4s + .long 0x6e751c12 // bsl v18.16b, v0.16b, v21.16b + .long 0x6e21de80 // fmul v0.4s, v20.4s, v1.4s + .long 0x4eb3d4f3 // fsub v19.4s, v7.4s, v19.4s + .long 0x4e25d415 // fadd v21.4s, v0.4s, v5.4s + .long 0x4e33cc60 // fmla v0.4s, v3.4s, v19.4s + .long 0x4ea0d833 // fcmeq v19.4s, v1.4s, #0.0 + .long 0x6e601c33 // bsl v19.16b, v1.16b, v0.16b + .long 0x4ea6d4e0 // fsub v0.4s, v7.4s, v6.4s + .long 0x6e23dc00 // fmul v0.4s, v0.4s, v3.4s + .long 0x6e22fc00 // fdiv v0.4s, v0.4s, v2.4s + .long 0x4ea0f4e0 // fmin v0.4s, v7.4s, v0.4s + .long 0x6e22de81 // fmul v1.4s, v20.4s, v2.4s + .long 0x4ea0d4e0 // fsub v0.4s, v7.4s, v0.4s + .long 0x4e26d434 // fadd v20.4s, v1.4s, v6.4s + .long 0x4e20cc61 // fmla v1.4s, v3.4s, v0.4s + .long 0x4ea0d840 // fcmeq v0.4s, v2.4s, #0.0 + .long 0x4ea3d631 // fsub v17.4s, v17.4s, v3.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4e27e490 // fcmeq v16.4s, v4.4s, v7.4s + .long 0x6e611c40 // bsl v0.16b, v2.16b, v1.16b + .long 0x4e31cc92 // fmla v18.4s, v4.4s, v17.4s + .long 0x4e27e4a1 // fcmeq v1.4s, v5.4s, v7.4s + .long 0x4e27e4c2 // fcmeq v2.4s, v6.4s, v7.4s + .long 0x4e31ccb3 // fmla v19.4s, v5.4s, v17.4s + .long 0x4e31ccc0 // fmla v0.4s, v6.4s, v17.4s + .long 0x6e721ed0 // bsl v16.16b, v22.16b, v18.16b + .long 0x6e731ea1 // bsl v1.16b, v21.16b, v19.16b + .long 0x6e601e82 // bsl v2.16b, v20.16b, v0.16b + .long 0x4e27ce23 // fmla v3.4s, v17.4s, v7.4s + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_colordodge_aarch64 +.globl _sk_colordodge_aarch64 +_sk_colordodge_aarch64: + .long 0x4f03f612 // fmov v18.4s, #1.000000000000000000e+00 + .long 0x6e24dc71 // fmul v17.4s, v3.4s, v4.4s + .long 0x4ea0d474 // fsub v20.4s, v3.4s, v0.4s + .long 0x6e25dc75 // fmul v21.4s, v3.4s, v5.4s + .long 0x4ea1d476 // fsub v22.4s, v3.4s, v1.4s + .long 0x4ea7d657 // fsub v23.4s, v18.4s, v7.4s + .long 0x6e34fe31 // fdiv v17.4s, v17.4s, v20.4s + .long 0x6e36feb4 // fdiv v20.4s, v21.4s, v22.4s + .long 0x6e20def5 // fmul v21.4s, v23.4s, v0.4s + .long 0x4eb1f4f1 // fmin v17.4s, v7.4s, v17.4s + .long 0x4e23e413 // fcmeq v19.4s, v0.4s, v3.4s + .long 0x4e24d6b6 // fadd v22.4s, v21.4s, v4.4s + .long 0x4e31cc75 // fmla v21.4s, v3.4s, v17.4s + .long 0x6e751c13 // bsl v19.16b, v0.16b, v21.16b + .long 0x6e21dee0 // fmul v0.4s, v23.4s, v1.4s + .long 0x4eb4f4f4 // fmin v20.4s, v7.4s, v20.4s + .long 0x4e25d415 // fadd v21.4s, v0.4s, v5.4s + .long 0x4e34cc60 // fmla v0.4s, v3.4s, v20.4s + .long 0x4e23e434 // fcmeq v20.4s, v1.4s, v3.4s + .long 0x6e601c34 // bsl v20.16b, v1.16b, v0.16b + .long 0x6e26dc60 // fmul v0.4s, v3.4s, v6.4s + .long 0x4ea2d461 // fsub v1.4s, v3.4s, v2.4s + .long 0x6e21fc00 // fdiv v0.4s, v0.4s, v1.4s + .long 0x6e22dee1 // fmul v1.4s, v23.4s, v2.4s + .long 0x4ea0f4e0 // fmin v0.4s, v7.4s, v0.4s + .long 0x4e26d437 // fadd v23.4s, v1.4s, v6.4s + .long 0x4e20cc61 // fmla v1.4s, v3.4s, v0.4s + .long 0x4e23e440 // fcmeq v0.4s, v2.4s, v3.4s + .long 0x6e611c40 // bsl v0.16b, v2.16b, v1.16b + .long 0x4ea3d641 // fsub v1.4s, v18.4s, v3.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4ea0d890 // fcmeq v16.4s, v4.4s, #0.0 + .long 0x4ea0d8b1 // fcmeq v17.4s, v5.4s, #0.0 + .long 0x4e21cc93 // fmla v19.4s, v4.4s, v1.4s + .long 0x4e21ccb4 // fmla v20.4s, v5.4s, v1.4s + .long 0x4ea0d8c2 // fcmeq v2.4s, v6.4s, #0.0 + .long 0x4e21ccc0 // fmla v0.4s, v6.4s, v1.4s + .long 0x6e731ed0 // bsl v16.16b, v22.16b, v19.16b + .long 0x6e741eb1 // bsl v17.16b, v21.16b, v20.16b + .long 0x6e601ee2 // bsl v2.16b, v23.16b, v0.16b + .long 0x4e27cc23 // fmla v3.4s, v1.4s, v7.4s + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0x4eb11e21 // mov v1.16b, v17.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_hardlight_aarch64 +.globl _sk_hardlight_aarch64 +_sk_hardlight_aarch64: + .long 0x4ea4d4f4 // fsub v20.4s, v7.4s, v4.4s + .long 0x4ea0d475 // fsub v21.4s, v3.4s, v0.4s + .long 0x6e34deb4 // fmul v20.4s, v21.4s, v20.4s + .long 0x4e20d411 // fadd v17.4s, v0.4s, v0.4s + .long 0x6e24dc12 // fmul v18.4s, v0.4s, v4.4s + .long 0x6e27dc73 // fmul v19.4s, v3.4s, v7.4s + .long 0x4e34d694 // fadd v20.4s, v20.4s, v20.4s + .long 0x6e31e471 // fcmge v17.4s, v3.4s, v17.4s + .long 0x4e32d652 // fadd v18.4s, v18.4s, v18.4s + .long 0x4eb4d674 // fsub v20.4s, v19.4s, v20.4s + .long 0x6e741e51 // bsl v17.16b, v18.16b, v20.16b + .long 0x4ea5d4f2 // fsub v18.4s, v7.4s, v5.4s + .long 0x4ea1d474 // fsub v20.4s, v3.4s, v1.4s + .long 0x6e32de92 // fmul v18.4s, v20.4s, v18.4s + .long 0x4e21d436 // fadd v22.4s, v1.4s, v1.4s + .long 0x6e25dc35 // fmul v21.4s, v1.4s, v5.4s + .long 0x4e32d652 // fadd v18.4s, v18.4s, v18.4s + .long 0x6e36e476 // fcmge v22.4s, v3.4s, v22.4s + .long 0x4e35d6b5 // fadd v21.4s, v21.4s, v21.4s + .long 0x4eb2d672 // fsub v18.4s, v19.4s, v18.4s + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x6e721eb6 // bsl v22.16b, v21.16b, v18.16b + .long 0x4ea6d4f2 // fsub v18.4s, v7.4s, v6.4s + .long 0x4ea2d475 // fsub v21.4s, v3.4s, v2.4s + .long 0x6e32deb2 // fmul v18.4s, v21.4s, v18.4s + .long 0x4ea7d615 // fsub v21.4s, v16.4s, v7.4s + .long 0x4e22d454 // fadd v20.4s, v2.4s, v2.4s + .long 0x6e20dea0 // fmul v0.4s, v21.4s, v0.4s + .long 0x6e21dea1 // fmul v1.4s, v21.4s, v1.4s + .long 0x6e22deb5 // fmul v21.4s, v21.4s, v2.4s + .long 0x6e26dc42 // fmul v2.4s, v2.4s, v6.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4e32d652 // fadd v18.4s, v18.4s, v18.4s + .long 0x4ea3d610 // fsub v16.4s, v16.4s, v3.4s + .long 0x6e34e474 // fcmge v20.4s, v3.4s, v20.4s + .long 0x4e22d442 // fadd v2.4s, v2.4s, v2.4s + .long 0x4eb2d672 // fsub v18.4s, v19.4s, v18.4s + .long 0x4e30cc80 // fmla v0.4s, v4.4s, v16.4s + .long 0x4e30cca1 // fmla v1.4s, v5.4s, v16.4s + .long 0x4e30ccd5 // fmla v21.4s, v6.4s, v16.4s + .long 0x6e721c54 // bsl v20.16b, v2.16b, v18.16b + .long 0x4e31d400 // fadd v0.4s, v0.4s, v17.4s + .long 0x4e36d421 // fadd v1.4s, v1.4s, v22.4s + .long 0x4e34d6a2 // fadd v2.4s, v21.4s, v20.4s + .long 0x4e27ce03 // fmla v3.4s, v16.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_overlay_aarch64 +.globl _sk_overlay_aarch64 +_sk_overlay_aarch64: + .long 0x4ea4d4f4 // fsub v20.4s, v7.4s, v4.4s + .long 0x4ea0d475 // fsub v21.4s, v3.4s, v0.4s + .long 0x6e34deb4 // fmul v20.4s, v21.4s, v20.4s + .long 0x4e24d491 // fadd v17.4s, v4.4s, v4.4s + .long 0x6e24dc12 // fmul v18.4s, v0.4s, v4.4s + .long 0x6e27dc73 // fmul v19.4s, v3.4s, v7.4s + .long 0x4e34d694 // fadd v20.4s, v20.4s, v20.4s + .long 0x6e31e4f1 // fcmge v17.4s, v7.4s, v17.4s + .long 0x4e32d652 // fadd v18.4s, v18.4s, v18.4s + .long 0x4eb4d674 // fsub v20.4s, v19.4s, v20.4s + .long 0x6e741e51 // bsl v17.16b, v18.16b, v20.16b + .long 0x4ea5d4f2 // fsub v18.4s, v7.4s, v5.4s + .long 0x4ea1d474 // fsub v20.4s, v3.4s, v1.4s + .long 0x6e32de92 // fmul v18.4s, v20.4s, v18.4s + .long 0x4e25d4b6 // fadd v22.4s, v5.4s, v5.4s + .long 0x6e25dc35 // fmul v21.4s, v1.4s, v5.4s + .long 0x4e32d652 // fadd v18.4s, v18.4s, v18.4s + .long 0x6e36e4f6 // fcmge v22.4s, v7.4s, v22.4s + .long 0x4e35d6b5 // fadd v21.4s, v21.4s, v21.4s + .long 0x4eb2d672 // fsub v18.4s, v19.4s, v18.4s + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x6e721eb6 // bsl v22.16b, v21.16b, v18.16b + .long 0x4ea6d4f2 // fsub v18.4s, v7.4s, v6.4s + .long 0x4ea2d475 // fsub v21.4s, v3.4s, v2.4s + .long 0x6e32deb2 // fmul v18.4s, v21.4s, v18.4s + .long 0x4ea7d615 // fsub v21.4s, v16.4s, v7.4s + .long 0x4e26d4d4 // fadd v20.4s, v6.4s, v6.4s + .long 0x6e20dea0 // fmul v0.4s, v21.4s, v0.4s + .long 0x6e21dea1 // fmul v1.4s, v21.4s, v1.4s + .long 0x6e22deb5 // fmul v21.4s, v21.4s, v2.4s + .long 0x6e26dc42 // fmul v2.4s, v2.4s, v6.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4e32d652 // fadd v18.4s, v18.4s, v18.4s + .long 0x4ea3d610 // fsub v16.4s, v16.4s, v3.4s + .long 0x6e34e4f4 // fcmge v20.4s, v7.4s, v20.4s + .long 0x4e22d442 // fadd v2.4s, v2.4s, v2.4s + .long 0x4eb2d672 // fsub v18.4s, v19.4s, v18.4s + .long 0x4e30cc80 // fmla v0.4s, v4.4s, v16.4s + .long 0x4e30cca1 // fmla v1.4s, v5.4s, v16.4s + .long 0x4e30ccd5 // fmla v21.4s, v6.4s, v16.4s + .long 0x6e721c54 // bsl v20.16b, v2.16b, v18.16b + .long 0x4e31d400 // fadd v0.4s, v0.4s, v17.4s + .long 0x4e36d421 // fadd v1.4s, v1.4s, v22.4s + .long 0x4e34d6a2 // fadd v2.4s, v21.4s, v20.4s + .long 0x4e27ce03 // fmla v3.4s, v16.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_softlight_aarch64 +.globl _sk_softlight_aarch64 +_sk_softlight_aarch64: + .long 0x4ea0c8f5 // fcmgt v21.4s, v7.4s, #0.0 + .long 0x6e27fc96 // fdiv v22.4s, v4.4s, v7.4s + .long 0x6e27fcb8 // fdiv v24.4s, v5.4s, v7.4s + .long 0x6e27fcd9 // fdiv v25.4s, v6.4s, v7.4s + .long 0x4e351ed6 // and v22.16b, v22.16b, v21.16b + .long 0x4e351f18 // and v24.16b, v24.16b, v21.16b + .long 0x4e351f35 // and v21.16b, v25.16b, v21.16b + .long 0x6ea1dad9 // frsqrte v25.4s, v22.4s + .long 0x6e39df3d // fmul v29.4s, v25.4s, v25.4s + .long 0x4ebdfedd // frsqrts v29.4s, v22.4s, v29.4s + .long 0x6e3ddf39 // fmul v25.4s, v25.4s, v29.4s + .long 0x4ea1db3d // frecpe v29.4s, v25.4s + .long 0x6ea0fada // fneg v26.4s, v22.4s + .long 0x6ea1db1b // frsqrte v27.4s, v24.4s + .long 0x4e3dff39 // frecps v25.4s, v25.4s, v29.4s + .long 0x4e3dcf3a // fmla v26.4s, v25.4s, v29.4s + .long 0x6e3bdf7d // fmul v29.4s, v27.4s, v27.4s + .long 0x4ebdff1d // frsqrts v29.4s, v24.4s, v29.4s + .long 0x6e3ddf7b // fmul v27.4s, v27.4s, v29.4s + .long 0x4ea1db7d // frecpe v29.4s, v27.4s + .long 0x6ea0fb1c // fneg v28.4s, v24.4s + .long 0x6ea1dab9 // frsqrte v25.4s, v21.4s + .long 0x4e3dff7b // frecps v27.4s, v27.4s, v29.4s + .long 0x4e3dcf7c // fmla v28.4s, v27.4s, v29.4s + .long 0x6e39df3d // fmul v29.4s, v25.4s, v25.4s + .long 0x4ebdfebd // frsqrts v29.4s, v21.4s, v29.4s + .long 0x6e3ddf39 // fmul v25.4s, v25.4s, v29.4s + .long 0x4ea1db3d // frecpe v29.4s, v25.4s + .long 0x6ea0fabb // fneg v27.4s, v21.4s + .long 0x4e3dff39 // frecps v25.4s, v25.4s, v29.4s + .long 0x4e3dcf3b // fmla v27.4s, v25.4s, v29.4s + .long 0x4e36d6d9 // fadd v25.4s, v22.4s, v22.4s + .long 0x4f07f613 // fmov v19.4s, #-1.000000000000000000e+00 + .long 0x4e39d739 // fadd v25.4s, v25.4s, v25.4s + .long 0x4e24d497 // fadd v23.4s, v4.4s, v4.4s + .long 0x4e33d6dd // fadd v29.4s, v22.4s, v19.4s + .long 0x4e39cf39 // fmla v25.4s, v25.4s, v25.4s + .long 0x4f00f794 // fmov v20.4s, #7.000000000000000000e+00 + .long 0x6e39dfb9 // fmul v25.4s, v29.4s, v25.4s + .long 0x4e37d6f7 // fadd v23.4s, v23.4s, v23.4s + .long 0x6e37e4f7 // fcmge v23.4s, v7.4s, v23.4s + .long 0x4e36ce99 // fmla v25.4s, v20.4s, v22.4s + .long 0x6e7a1f37 // bsl v23.16b, v25.16b, v26.16b + .long 0x4e38d719 // fadd v25.4s, v24.4s, v24.4s + .long 0x4e39d739 // fadd v25.4s, v25.4s, v25.4s + .long 0x4e33d71a // fadd v26.4s, v24.4s, v19.4s + .long 0x4e39cf39 // fmla v25.4s, v25.4s, v25.4s + .long 0x6e39df59 // fmul v25.4s, v26.4s, v25.4s + .long 0x4e25d4ba // fadd v26.4s, v5.4s, v5.4s + .long 0x4e3ad75a // fadd v26.4s, v26.4s, v26.4s + .long 0x6e3ae4fa // fcmge v26.4s, v7.4s, v26.4s + .long 0x4e38ce99 // fmla v25.4s, v20.4s, v24.4s + .long 0x6e7c1f3a // bsl v26.16b, v25.16b, v28.16b + .long 0x4e35d6bc // fadd v28.4s, v21.4s, v21.4s + .long 0x4e3cd79c // fadd v28.4s, v28.4s, v28.4s + .long 0x4e33d6b3 // fadd v19.4s, v21.4s, v19.4s + .long 0x4e3ccf9c // fmla v28.4s, v28.4s, v28.4s + .long 0x6e3cde73 // fmul v19.4s, v19.4s, v28.4s + .long 0x4e35ce93 // fmla v19.4s, v20.4s, v21.4s + .long 0x4e26d4d4 // fadd v20.4s, v6.4s, v6.4s + .long 0x4e34d694 // fadd v20.4s, v20.4s, v20.4s + .long 0x4f03f612 // fmov v18.4s, #1.000000000000000000e+00 + .long 0x6e34e4f4 // fcmge v20.4s, v7.4s, v20.4s + .long 0x4e20d411 // fadd v17.4s, v0.4s, v0.4s + .long 0x6e7b1e74 // bsl v20.16b, v19.16b, v27.16b + .long 0x4ea7d65b // fsub v27.4s, v18.4s, v7.4s + .long 0x4ea31c70 // mov v16.16b, v3.16b + .long 0x4e21d43d // fadd v29.4s, v1.4s, v1.4s + .long 0x4e22d45c // fadd v28.4s, v2.4s, v2.4s + .long 0x6e20df60 // fmul v0.4s, v27.4s, v0.4s + .long 0x6e21df61 // fmul v1.4s, v27.4s, v1.4s + .long 0x6e22df62 // fmul v2.4s, v27.4s, v2.4s + .long 0x4ea3d63b // fsub v27.4s, v17.4s, v3.4s + .long 0x4eb6d656 // fsub v22.4s, v18.4s, v22.4s + .long 0x4ea31c79 // mov v25.16b, v3.16b + .long 0x4e3bced0 // fmla v16.4s, v22.4s, v27.4s + .long 0x4ea3d7b6 // fsub v22.4s, v29.4s, v3.4s + .long 0x4eb8d658 // fsub v24.4s, v18.4s, v24.4s + .long 0x4ea31c73 // mov v19.16b, v3.16b + .long 0x4e36cf19 // fmla v25.4s, v24.4s, v22.4s + .long 0x4ea3d798 // fsub v24.4s, v28.4s, v3.4s + .long 0x4eb5d655 // fsub v21.4s, v18.4s, v21.4s + .long 0x4e38ceb3 // fmla v19.4s, v21.4s, v24.4s + .long 0x6e27df7b // fmul v27.4s, v27.4s, v7.4s + .long 0x6e27ded6 // fmul v22.4s, v22.4s, v7.4s + .long 0x6e27df18 // fmul v24.4s, v24.4s, v7.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e37df77 // fmul v23.4s, v27.4s, v23.4s + .long 0x6e3aded6 // fmul v22.4s, v22.4s, v26.4s + .long 0x6e34df14 // fmul v20.4s, v24.4s, v20.4s + .long 0x4ea3d652 // fsub v18.4s, v18.4s, v3.4s + .long 0x6e31e471 // fcmge v17.4s, v3.4s, v17.4s + .long 0x6e3de475 // fcmge v21.4s, v3.4s, v29.4s + .long 0x6e3ce47c // fcmge v28.4s, v3.4s, v28.4s + .long 0x6e24de10 // fmul v16.4s, v16.4s, v4.4s + .long 0x6e25df39 // fmul v25.4s, v25.4s, v5.4s + .long 0x6e26de73 // fmul v19.4s, v19.4s, v6.4s + .long 0x4e23cc97 // fmla v23.4s, v4.4s, v3.4s + .long 0x4e23ccb6 // fmla v22.4s, v5.4s, v3.4s + .long 0x4e23ccd4 // fmla v20.4s, v6.4s, v3.4s + .long 0x4e32cc80 // fmla v0.4s, v4.4s, v18.4s + .long 0x4e32cca1 // fmla v1.4s, v5.4s, v18.4s + .long 0x4e32ccc2 // fmla v2.4s, v6.4s, v18.4s + .long 0x6e771e11 // bsl v17.16b, v16.16b, v23.16b + .long 0x6e761f35 // bsl v21.16b, v25.16b, v22.16b + .long 0x6e741e7c // bsl v28.16b, v19.16b, v20.16b + .long 0x4e31d400 // fadd v0.4s, v0.4s, v17.4s + .long 0x4e35d421 // fadd v1.4s, v1.4s, v21.4s + .long 0x4e3cd442 // fadd v2.4s, v2.4s, v28.4s + .long 0x4e27ce43 // fmla v3.4s, v18.4s, v7.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_clamp_0_aarch64 +.globl _sk_clamp_0_aarch64 +_sk_clamp_0_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6f00e410 // movi v16.2d, #0x0 + .long 0x4e30f400 // fmax v0.4s, v0.4s, v16.4s + .long 0x4e30f421 // fmax v1.4s, v1.4s, v16.4s + .long 0x4e30f442 // fmax v2.4s, v2.4s, v16.4s + .long 0x4e30f463 // fmax v3.4s, v3.4s, v16.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_clamp_1_aarch64 +.globl _sk_clamp_1_aarch64 +_sk_clamp_1_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x4eb0f400 // fmin v0.4s, v0.4s, v16.4s + .long 0x4eb0f421 // fmin v1.4s, v1.4s, v16.4s + .long 0x4eb0f442 // fmin v2.4s, v2.4s, v16.4s + .long 0x4eb0f463 // fmin v3.4s, v3.4s, v16.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_clamp_a_aarch64 +.globl _sk_clamp_a_aarch64 +_sk_clamp_a_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4f03f610 // fmov v16.4s, #1.000000000000000000e+00 + .long 0x4eb0f463 // fmin v3.4s, v3.4s, v16.4s + .long 0x4ea3f400 // fmin v0.4s, v0.4s, v3.4s + .long 0x4ea3f421 // fmin v1.4s, v1.4s, v3.4s + .long 0x4ea3f442 // fmin v2.4s, v2.4s, v3.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_set_rgb_aarch64 +.globl _sk_set_rgb_aarch64 +_sk_set_rgb_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xaa0803e9 // mov x9, x8 + .long 0x4ddfc920 // ld1r {v0.4s}, [x9], #4 + .long 0x91002108 // add x8, x8, #0x8 + .long 0x4d40c902 // ld1r {v2.4s}, [x8] + .long 0x4d40c921 // ld1r {v1.4s}, [x9] + .long 0xd61f0060 // br x3 + +HIDDEN _sk_swap_rb_aarch64 +.globl _sk_swap_rb_aarch64 +_sk_swap_rb_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4ea01c10 // mov v16.16b, v0.16b + .long 0x4ea21c40 // mov v0.16b, v2.16b + .long 0x4eb01e02 // mov v2.16b, v16.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_swap_aarch64 +.globl _sk_swap_aarch64 +_sk_swap_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4ea31c70 // mov v16.16b, v3.16b + .long 0x4ea21c51 // mov v17.16b, v2.16b + .long 0x4ea11c32 // mov v18.16b, v1.16b + .long 0x4ea01c13 // mov v19.16b, v0.16b + .long 0x4ea41c80 // mov v0.16b, v4.16b + .long 0x4ea51ca1 // mov v1.16b, v5.16b + .long 0x4ea61cc2 // mov v2.16b, v6.16b + .long 0x4ea71ce3 // mov v3.16b, v7.16b + .long 0x4eb31e64 // mov v4.16b, v19.16b + .long 0x4eb21e45 // mov v5.16b, v18.16b + .long 0x4eb11e26 // mov v6.16b, v17.16b + .long 0x4eb01e07 // mov v7.16b, v16.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_move_src_dst_aarch64 +.globl _sk_move_src_dst_aarch64 +_sk_move_src_dst_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4ea01c04 // mov v4.16b, v0.16b + .long 0x4ea11c25 // mov v5.16b, v1.16b + .long 0x4ea21c46 // mov v6.16b, v2.16b + .long 0x4ea31c67 // mov v7.16b, v3.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_move_dst_src_aarch64 +.globl _sk_move_dst_src_aarch64 +_sk_move_dst_src_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4ea41c80 // mov v0.16b, v4.16b + .long 0x4ea51ca1 // mov v1.16b, v5.16b + .long 0x4ea61cc2 // mov v2.16b, v6.16b + .long 0x4ea71ce3 // mov v3.16b, v7.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_premul_aarch64 +.globl _sk_premul_aarch64 +_sk_premul_aarch64: + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e23dc00 // fmul v0.4s, v0.4s, v3.4s + .long 0x6e23dc21 // fmul v1.4s, v1.4s, v3.4s + .long 0x6e23dc42 // fmul v2.4s, v2.4s, v3.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_unpremul_aarch64 +.globl _sk_unpremul_aarch64 +_sk_unpremul_aarch64: + .long 0x4f03f611 // fmov v17.4s, #1.000000000000000000e+00 + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4ea0d870 // fcmeq v16.4s, v3.4s, #0.0 + .long 0x6e23fe31 // fdiv v17.4s, v17.4s, v3.4s + .long 0x4e701e30 // bic v16.16b, v17.16b, v16.16b + .long 0x6e20de00 // fmul v0.4s, v16.4s, v0.4s + .long 0x6e21de01 // fmul v1.4s, v16.4s, v1.4s + .long 0x6e22de02 // fmul v2.4s, v16.4s, v2.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_from_srgb_aarch64 +.globl _sk_from_srgb_aarch64 +_sk_from_srgb_aarch64: + .long 0x52a7d328 // mov w8, #0x3e990000 + .long 0x72933348 // movk w8, #0x999a + .long 0x4e040d10 // dup v16.4s, w8 + .long 0x52a7e648 // mov w8, #0x3f320000 + .long 0x7291eb88 // movk w8, #0x8f5c + .long 0x4e040d11 // dup v17.4s, w8 + .long 0x52a76468 // mov w8, #0x3b230000 + .long 0x729ae148 // movk w8, #0xd70a + .long 0x4e040d12 // dup v18.4s, w8 + .long 0x52a7b3c8 // mov w8, #0x3d9e0000 + .long 0x72907228 // movk w8, #0x8391 + .long 0x6e22dc54 // fmul v20.4s, v2.4s, v2.4s + .long 0x4eb11e35 // mov v21.16b, v17.16b + .long 0x4eb11e37 // mov v23.16b, v17.16b + .long 0x4e22ce11 // fmla v17.4s, v16.4s, v2.4s + .long 0x4eb21e56 // mov v22.16b, v18.16b + .long 0x4eb21e58 // mov v24.16b, v18.16b + .long 0x4e34ce32 // fmla v18.4s, v17.4s, v20.4s + .long 0x4e040d11 // dup v17.4s, w8 + .long 0x52a7ac28 // mov w8, #0x3d610000 + .long 0x6e20dc13 // fmul v19.4s, v0.4s, v0.4s + .long 0x7288f5c8 // movk w8, #0x47ae + .long 0x4e20ce15 // fmla v21.4s, v16.4s, v0.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e21dc34 // fmul v20.4s, v1.4s, v1.4s + .long 0x4e33ceb6 // fmla v22.4s, v21.4s, v19.4s + .long 0x4e040d13 // dup v19.4s, w8 + .long 0x4e21ce17 // fmla v23.4s, v16.4s, v1.4s + .long 0x6e31dc15 // fmul v21.4s, v0.4s, v17.4s + .long 0x6ea0e660 // fcmgt v0.4s, v19.4s, v0.4s + .long 0x6e31dc30 // fmul v16.4s, v1.4s, v17.4s + .long 0x6ea1e661 // fcmgt v1.4s, v19.4s, v1.4s + .long 0x6e31dc51 // fmul v17.4s, v2.4s, v17.4s + .long 0x6ea2e662 // fcmgt v2.4s, v19.4s, v2.4s + .long 0x4e34cef8 // fmla v24.4s, v23.4s, v20.4s + .long 0x6e761ea0 // bsl v0.16b, v21.16b, v22.16b + .long 0x6e781e01 // bsl v1.16b, v16.16b, v24.16b + .long 0x6e721e22 // bsl v2.16b, v17.16b, v18.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_to_srgb_aarch64 +.globl _sk_to_srgb_aarch64 +_sk_to_srgb_aarch64: + .long 0x52a828e8 // mov w8, #0x41470000 + .long 0x728b8528 // movk w8, #0x5c29 + .long 0x4e040d12 // dup v18.4s, w8 + .long 0x52a7e608 // mov w8, #0x3f300000 + .long 0x728df9c8 // movk w8, #0x6fce + .long 0x6ea1d811 // frsqrte v17.4s, v0.4s + .long 0x4e040d13 // dup v19.4s, w8 + .long 0x52b7b948 // mov w8, #0xbdca0000 + .long 0x728af508 // movk w8, #0x57a8 + .long 0x6ea1d834 // frsqrte v20.4s, v1.4s + .long 0x6e31de36 // fmul v22.4s, v17.4s, v17.4s + .long 0x4e040d10 // dup v16.4s, w8 + .long 0x52a77188 // mov w8, #0x3b8c0000 + .long 0x6ea1d855 // frsqrte v21.4s, v2.4s + .long 0x6e34de98 // fmul v24.4s, v20.4s, v20.4s + .long 0x4eb6fc16 // frsqrts v22.4s, v0.4s, v22.4s + .long 0x729ce088 // movk w8, #0xe704 + .long 0x6e35deb9 // fmul v25.4s, v21.4s, v21.4s + .long 0x4eb8fc38 // frsqrts v24.4s, v1.4s, v24.4s + .long 0x6e36de31 // fmul v17.4s, v17.4s, v22.4s + .long 0x4e040d17 // dup v23.4s, w8 + .long 0x4eb9fc59 // frsqrts v25.4s, v2.4s, v25.4s + .long 0x6e38de94 // fmul v20.4s, v20.4s, v24.4s + .long 0x4ea1da36 // frecpe v22.4s, v17.4s + .long 0x6e32dc1a // fmul v26.4s, v0.4s, v18.4s + .long 0x6ea0e6e0 // fcmgt v0.4s, v23.4s, v0.4s + .long 0x6e32dc3c // fmul v28.4s, v1.4s, v18.4s + .long 0x6ea1e6e1 // fcmgt v1.4s, v23.4s, v1.4s + .long 0x6e32dc52 // fmul v18.4s, v2.4s, v18.4s + .long 0x6ea2e6e2 // fcmgt v2.4s, v23.4s, v2.4s + .long 0x6e39deb5 // fmul v21.4s, v21.4s, v25.4s + .long 0x4ea1da97 // frecpe v23.4s, v20.4s + .long 0x4e36fe39 // frecps v25.4s, v17.4s, v22.4s + .long 0x4ea1dab8 // frecpe v24.4s, v21.4s + .long 0x6e39ded6 // fmul v22.4s, v22.4s, v25.4s + .long 0x4e37fe99 // frecps v25.4s, v20.4s, v23.4s + .long 0x4eb01e1b // mov v27.16b, v16.16b + .long 0x6e39def7 // fmul v23.4s, v23.4s, v25.4s + .long 0x4e38feb9 // frecps v25.4s, v21.4s, v24.4s + .long 0x6e39df18 // fmul v24.4s, v24.4s, v25.4s + .long 0x4eb01e19 // mov v25.16b, v16.16b + .long 0x4e36ce7b // fmla v27.4s, v19.4s, v22.4s + .long 0x6ea1da36 // frsqrte v22.4s, v17.4s + .long 0x4e37ce79 // fmla v25.4s, v19.4s, v23.4s + .long 0x6ea1da97 // frsqrte v23.4s, v20.4s + .long 0x4e38ce70 // fmla v16.4s, v19.4s, v24.4s + .long 0x6e36ded8 // fmul v24.4s, v22.4s, v22.4s + .long 0x6ea1dab3 // frsqrte v19.4s, v21.4s + .long 0x4eb8fe31 // frsqrts v17.4s, v17.4s, v24.4s + .long 0x6e37def8 // fmul v24.4s, v23.4s, v23.4s + .long 0x4eb8fe94 // frsqrts v20.4s, v20.4s, v24.4s + .long 0x6e33de78 // fmul v24.4s, v19.4s, v19.4s + .long 0x52a7da48 // mov w8, #0x3ed20000 + .long 0x4eb8feb5 // frsqrts v21.4s, v21.4s, v24.4s + .long 0x7290f848 // movk w8, #0x87c2 + .long 0x6e31ded1 // fmul v17.4s, v22.4s, v17.4s + .long 0x6e34def4 // fmul v20.4s, v23.4s, v20.4s + .long 0x6e35de73 // fmul v19.4s, v19.4s, v21.4s + .long 0x4e040d15 // dup v21.4s, w8 + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4e31cebb // fmla v27.4s, v21.4s, v17.4s + .long 0x4f03f611 // fmov v17.4s, #1.000000000000000000e+00 + .long 0x4e34ceb9 // fmla v25.4s, v21.4s, v20.4s + .long 0x4e33ceb0 // fmla v16.4s, v21.4s, v19.4s + .long 0x4ebbf633 // fmin v19.4s, v17.4s, v27.4s + .long 0x4eb9f634 // fmin v20.4s, v17.4s, v25.4s + .long 0x4eb0f630 // fmin v16.4s, v17.4s, v16.4s + .long 0x6e731f40 // bsl v0.16b, v26.16b, v19.16b + .long 0x6e741f81 // bsl v1.16b, v28.16b, v20.16b + .long 0x6e701e42 // bsl v2.16b, v18.16b, v16.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_from_2dot2_aarch64 +.globl _sk_from_2dot2_aarch64 +_sk_from_2dot2_aarch64: + .long 0x6ea1d810 // frsqrte v16.4s, v0.4s + .long 0x6ea1d832 // frsqrte v18.4s, v1.4s + .long 0x6e30de15 // fmul v21.4s, v16.4s, v16.4s + .long 0x6e20dc11 // fmul v17.4s, v0.4s, v0.4s + .long 0x6ea1d854 // frsqrte v20.4s, v2.4s + .long 0x6e32de56 // fmul v22.4s, v18.4s, v18.4s + .long 0x4eb5fc00 // frsqrts v0.4s, v0.4s, v21.4s + .long 0x6e21dc33 // fmul v19.4s, v1.4s, v1.4s + .long 0x6e34de97 // fmul v23.4s, v20.4s, v20.4s + .long 0x4eb6fc21 // frsqrts v1.4s, v1.4s, v22.4s + .long 0x6e20de00 // fmul v0.4s, v16.4s, v0.4s + .long 0x4eb7fc55 // frsqrts v21.4s, v2.4s, v23.4s + .long 0x6e21de41 // fmul v1.4s, v18.4s, v1.4s + .long 0x6ea1d812 // frsqrte v18.4s, v0.4s + .long 0x6e35de90 // fmul v16.4s, v20.4s, v21.4s + .long 0x6ea1d834 // frsqrte v20.4s, v1.4s + .long 0x6e32de56 // fmul v22.4s, v18.4s, v18.4s + .long 0x6ea1da15 // frsqrte v21.4s, v16.4s + .long 0x6e34de97 // fmul v23.4s, v20.4s, v20.4s + .long 0x4eb6fc00 // frsqrts v0.4s, v0.4s, v22.4s + .long 0x6e35deb6 // fmul v22.4s, v21.4s, v21.4s + .long 0x4eb7fc21 // frsqrts v1.4s, v1.4s, v23.4s + .long 0x6e20de40 // fmul v0.4s, v18.4s, v0.4s + .long 0x4eb6fe10 // frsqrts v16.4s, v16.4s, v22.4s + .long 0x6e21de81 // fmul v1.4s, v20.4s, v1.4s + .long 0x6ea1d812 // frsqrte v18.4s, v0.4s + .long 0x6e30deb0 // fmul v16.4s, v21.4s, v16.4s + .long 0x6ea1d834 // frsqrte v20.4s, v1.4s + .long 0x6e32de56 // fmul v22.4s, v18.4s, v18.4s + .long 0x6ea1da15 // frsqrte v21.4s, v16.4s + .long 0x6e34de97 // fmul v23.4s, v20.4s, v20.4s + .long 0x4eb6fc00 // frsqrts v0.4s, v0.4s, v22.4s + .long 0x6e35deb6 // fmul v22.4s, v21.4s, v21.4s + .long 0x4eb7fc21 // frsqrts v1.4s, v1.4s, v23.4s + .long 0x6e20de40 // fmul v0.4s, v18.4s, v0.4s + .long 0x4eb6fe10 // frsqrts v16.4s, v16.4s, v22.4s + .long 0x6e21de81 // fmul v1.4s, v20.4s, v1.4s + .long 0x6ea1d812 // frsqrte v18.4s, v0.4s + .long 0x6e30deb0 // fmul v16.4s, v21.4s, v16.4s + .long 0x6ea1d834 // frsqrte v20.4s, v1.4s + .long 0x6e32de56 // fmul v22.4s, v18.4s, v18.4s + .long 0x6ea1da15 // frsqrte v21.4s, v16.4s + .long 0x6e34de97 // fmul v23.4s, v20.4s, v20.4s + .long 0x4eb6fc00 // frsqrts v0.4s, v0.4s, v22.4s + .long 0x6e35deb6 // fmul v22.4s, v21.4s, v21.4s + .long 0x4eb7fc21 // frsqrts v1.4s, v1.4s, v23.4s + .long 0x6e20de40 // fmul v0.4s, v18.4s, v0.4s + .long 0x4eb6fe10 // frsqrts v16.4s, v16.4s, v22.4s + .long 0x6e21de81 // fmul v1.4s, v20.4s, v1.4s + .long 0x6ea1d812 // frsqrte v18.4s, v0.4s + .long 0x6e20dc14 // fmul v20.4s, v0.4s, v0.4s + .long 0x6e30deb0 // fmul v16.4s, v21.4s, v16.4s + .long 0x6ea1d835 // frsqrte v21.4s, v1.4s + .long 0x6e21dc36 // fmul v22.4s, v1.4s, v1.4s + .long 0x6e32de57 // fmul v23.4s, v18.4s, v18.4s + .long 0x6e34dc14 // fmul v20.4s, v0.4s, v20.4s + .long 0x4eb7fc00 // frsqrts v0.4s, v0.4s, v23.4s + .long 0x6ea1da17 // frsqrte v23.4s, v16.4s + .long 0x6e34de31 // fmul v17.4s, v17.4s, v20.4s + .long 0x6e35deb4 // fmul v20.4s, v21.4s, v21.4s + .long 0x6e36dc36 // fmul v22.4s, v1.4s, v22.4s + .long 0x4eb4fc21 // frsqrts v1.4s, v1.4s, v20.4s + .long 0x6e30de14 // fmul v20.4s, v16.4s, v16.4s + .long 0x6e36de73 // fmul v19.4s, v19.4s, v22.4s + .long 0x6e37def6 // fmul v22.4s, v23.4s, v23.4s + .long 0x6e20de40 // fmul v0.4s, v18.4s, v0.4s + .long 0x6e34de14 // fmul v20.4s, v16.4s, v20.4s + .long 0x4eb6fe10 // frsqrts v16.4s, v16.4s, v22.4s + .long 0x6e22dc42 // fmul v2.4s, v2.4s, v2.4s + .long 0x6e21dea1 // fmul v1.4s, v21.4s, v1.4s + .long 0x6ea1d812 // frsqrte v18.4s, v0.4s + .long 0x6e34dc42 // fmul v2.4s, v2.4s, v20.4s + .long 0x6e30def0 // fmul v16.4s, v23.4s, v16.4s + .long 0x6ea1d834 // frsqrte v20.4s, v1.4s + .long 0x6e32de56 // fmul v22.4s, v18.4s, v18.4s + .long 0x6ea1da15 // frsqrte v21.4s, v16.4s + .long 0x4eb6fc00 // frsqrts v0.4s, v0.4s, v22.4s + .long 0x6e34de96 // fmul v22.4s, v20.4s, v20.4s + .long 0x4eb6fc21 // frsqrts v1.4s, v1.4s, v22.4s + .long 0x6e35deb6 // fmul v22.4s, v21.4s, v21.4s + .long 0x4eb6fe10 // frsqrts v16.4s, v16.4s, v22.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e20de40 // fmul v0.4s, v18.4s, v0.4s + .long 0x6e21de81 // fmul v1.4s, v20.4s, v1.4s + .long 0x6e30deb0 // fmul v16.4s, v21.4s, v16.4s + .long 0x6f00e412 // movi v18.2d, #0x0 + .long 0x6e20de20 // fmul v0.4s, v17.4s, v0.4s + .long 0x6e21de61 // fmul v1.4s, v19.4s, v1.4s + .long 0x6e30dc42 // fmul v2.4s, v2.4s, v16.4s + .long 0x4e32f400 // fmax v0.4s, v0.4s, v18.4s + .long 0x4e32f421 // fmax v1.4s, v1.4s, v18.4s + .long 0x4e32f442 // fmax v2.4s, v2.4s, v18.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_to_2dot2_aarch64 +.globl _sk_to_2dot2_aarch64 +_sk_to_2dot2_aarch64: + .long 0x6ea1d810 // frsqrte v16.4s, v0.4s + .long 0x6e30de13 // fmul v19.4s, v16.4s, v16.4s + .long 0x6ea1d831 // frsqrte v17.4s, v1.4s + .long 0x4eb3fc00 // frsqrts v0.4s, v0.4s, v19.4s + .long 0x6ea1d852 // frsqrte v18.4s, v2.4s + .long 0x6e31de34 // fmul v20.4s, v17.4s, v17.4s + .long 0x6e20de00 // fmul v0.4s, v16.4s, v0.4s + .long 0x6e32de55 // fmul v21.4s, v18.4s, v18.4s + .long 0x4eb4fc21 // frsqrts v1.4s, v1.4s, v20.4s + .long 0x6ea1d810 // frsqrte v16.4s, v0.4s + .long 0x4eb5fc42 // frsqrts v2.4s, v2.4s, v21.4s + .long 0x6e21de21 // fmul v1.4s, v17.4s, v1.4s + .long 0x4ea1d811 // frecpe v17.4s, v0.4s + .long 0x6e30de16 // fmul v22.4s, v16.4s, v16.4s + .long 0x6e22de42 // fmul v2.4s, v18.4s, v2.4s + .long 0x6ea1d832 // frsqrte v18.4s, v1.4s + .long 0x4eb6fc16 // frsqrts v22.4s, v0.4s, v22.4s + .long 0x4e31fc00 // frecps v0.4s, v0.4s, v17.4s + .long 0x4ea1d833 // frecpe v19.4s, v1.4s + .long 0x6e20de20 // fmul v0.4s, v17.4s, v0.4s + .long 0x6e32de51 // fmul v17.4s, v18.4s, v18.4s + .long 0x6ea1d854 // frsqrte v20.4s, v2.4s + .long 0x4eb1fc31 // frsqrts v17.4s, v1.4s, v17.4s + .long 0x4e33fc21 // frecps v1.4s, v1.4s, v19.4s + .long 0x6e21de61 // fmul v1.4s, v19.4s, v1.4s + .long 0x6e34de93 // fmul v19.4s, v20.4s, v20.4s + .long 0x4eb3fc53 // frsqrts v19.4s, v2.4s, v19.4s + .long 0x6e36de10 // fmul v16.4s, v16.4s, v22.4s + .long 0x6e31de51 // fmul v17.4s, v18.4s, v17.4s + .long 0x6e33de92 // fmul v18.4s, v20.4s, v19.4s + .long 0x6ea1da13 // frsqrte v19.4s, v16.4s + .long 0x4ea1d855 // frecpe v21.4s, v2.4s + .long 0x6e33de76 // fmul v22.4s, v19.4s, v19.4s + .long 0x4e35fc42 // frecps v2.4s, v2.4s, v21.4s + .long 0x6ea1da34 // frsqrte v20.4s, v17.4s + .long 0x4eb6fe10 // frsqrts v16.4s, v16.4s, v22.4s + .long 0x6e22dea2 // fmul v2.4s, v21.4s, v2.4s + .long 0x6ea1da55 // frsqrte v21.4s, v18.4s + .long 0x6e34de96 // fmul v22.4s, v20.4s, v20.4s + .long 0x6e30de70 // fmul v16.4s, v19.4s, v16.4s + .long 0x4eb6fe31 // frsqrts v17.4s, v17.4s, v22.4s + .long 0x6e35deb6 // fmul v22.4s, v21.4s, v21.4s + .long 0x6ea1da13 // frsqrte v19.4s, v16.4s + .long 0x4eb6fe52 // frsqrts v18.4s, v18.4s, v22.4s + .long 0x6e31de91 // fmul v17.4s, v20.4s, v17.4s + .long 0x6e33de76 // fmul v22.4s, v19.4s, v19.4s + .long 0x6e32deb2 // fmul v18.4s, v21.4s, v18.4s + .long 0x6ea1da34 // frsqrte v20.4s, v17.4s + .long 0x4eb6fe10 // frsqrts v16.4s, v16.4s, v22.4s + .long 0x6ea1da55 // frsqrte v21.4s, v18.4s + .long 0x6e34de96 // fmul v22.4s, v20.4s, v20.4s + .long 0x6e30de70 // fmul v16.4s, v19.4s, v16.4s + .long 0x4eb6fe31 // frsqrts v17.4s, v17.4s, v22.4s + .long 0x6e35deb6 // fmul v22.4s, v21.4s, v21.4s + .long 0x6ea1da13 // frsqrte v19.4s, v16.4s + .long 0x4eb6fe52 // frsqrts v18.4s, v18.4s, v22.4s + .long 0x6e31de91 // fmul v17.4s, v20.4s, v17.4s + .long 0x6e33de76 // fmul v22.4s, v19.4s, v19.4s + .long 0x6e32deb2 // fmul v18.4s, v21.4s, v18.4s + .long 0x6ea1da34 // frsqrte v20.4s, v17.4s + .long 0x4eb6fe10 // frsqrts v16.4s, v16.4s, v22.4s + .long 0x6ea1da55 // frsqrte v21.4s, v18.4s + .long 0x6e34de96 // fmul v22.4s, v20.4s, v20.4s + .long 0x6e30de70 // fmul v16.4s, v19.4s, v16.4s + .long 0x4eb6fe31 // frsqrts v17.4s, v17.4s, v22.4s + .long 0x6e35deb6 // fmul v22.4s, v21.4s, v21.4s + .long 0x6ea1da13 // frsqrte v19.4s, v16.4s + .long 0x4eb6fe52 // frsqrts v18.4s, v18.4s, v22.4s + .long 0x6e31de91 // fmul v17.4s, v20.4s, v17.4s + .long 0x6e33de76 // fmul v22.4s, v19.4s, v19.4s + .long 0x6e20de00 // fmul v0.4s, v16.4s, v0.4s + .long 0x6ea1da34 // frsqrte v20.4s, v17.4s + .long 0x4eb6fe10 // frsqrts v16.4s, v16.4s, v22.4s + .long 0x6e32deb2 // fmul v18.4s, v21.4s, v18.4s + .long 0x6e34de96 // fmul v22.4s, v20.4s, v20.4s + .long 0x6e30de70 // fmul v16.4s, v19.4s, v16.4s + .long 0x6e21de21 // fmul v1.4s, v17.4s, v1.4s + .long 0x6ea1da55 // frsqrte v21.4s, v18.4s + .long 0x4eb6fe31 // frsqrts v17.4s, v17.4s, v22.4s + .long 0x4ea1da13 // frecpe v19.4s, v16.4s + .long 0x6e35deb6 // fmul v22.4s, v21.4s, v21.4s + .long 0x6e31de91 // fmul v17.4s, v20.4s, v17.4s + .long 0x4e33fe10 // frecps v16.4s, v16.4s, v19.4s + .long 0x6e22de42 // fmul v2.4s, v18.4s, v2.4s + .long 0x4eb6fe52 // frsqrts v18.4s, v18.4s, v22.4s + .long 0x6e30de70 // fmul v16.4s, v19.4s, v16.4s + .long 0x4ea1da33 // frecpe v19.4s, v17.4s + .long 0x6e32deb2 // fmul v18.4s, v21.4s, v18.4s + .long 0x4e33fe31 // frecps v17.4s, v17.4s, v19.4s + .long 0x6e31de71 // fmul v17.4s, v19.4s, v17.4s + .long 0x4ea1da53 // frecpe v19.4s, v18.4s + .long 0x4e33fe52 // frecps v18.4s, v18.4s, v19.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6e32de72 // fmul v18.4s, v19.4s, v18.4s + .long 0x6f00e413 // movi v19.2d, #0x0 + .long 0x6e30dc00 // fmul v0.4s, v0.4s, v16.4s + .long 0x6e31dc21 // fmul v1.4s, v1.4s, v17.4s + .long 0x6e32dc42 // fmul v2.4s, v2.4s, v18.4s + .long 0x4e33f400 // fmax v0.4s, v0.4s, v19.4s + .long 0x4e33f421 // fmax v1.4s, v1.4s, v19.4s + .long 0x4e33f442 // fmax v2.4s, v2.4s, v19.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_rgb_to_hsl_aarch64 +.globl _sk_rgb_to_hsl_aarch64 +_sk_rgb_to_hsl_aarch64: + .long 0x4e21f410 // fmax v16.4s, v0.4s, v1.4s + .long 0x4ea1f411 // fmin v17.4s, v0.4s, v1.4s + .long 0x6ea1e454 // fcmgt v20.4s, v2.4s, v1.4s + .long 0x4f00f715 // fmov v21.4s, #6.000000000000000000e+00 + .long 0x4e22f610 // fmax v16.4s, v16.4s, v2.4s + .long 0x4ea2f631 // fmin v17.4s, v17.4s, v2.4s + .long 0x4f03f612 // fmov v18.4s, #1.000000000000000000e+00 + .long 0x4e341eb4 // and v20.16b, v21.16b, v20.16b + .long 0x4eb1d615 // fsub v21.4s, v16.4s, v17.4s + .long 0x4ea2d433 // fsub v19.4s, v1.4s, v2.4s + .long 0x4ea0d456 // fsub v22.4s, v2.4s, v0.4s + .long 0x4f026417 // movi v23.4s, #0x40, lsl #24 + .long 0x6e35fe42 // fdiv v2.4s, v18.4s, v21.4s + .long 0x4ea1d418 // fsub v24.4s, v0.4s, v1.4s + .long 0x4f00f619 // fmov v25.4s, #4.000000000000000000e+00 + .long 0x4f0167fa // movi v26.4s, #0x3f, lsl #24 + .long 0x4eb0d6f2 // fsub v18.4s, v23.4s, v16.4s + .long 0x4e36cc57 // fmla v23.4s, v2.4s, v22.4s + .long 0x4e31e616 // fcmeq v22.4s, v16.4s, v17.4s + .long 0x4e20e600 // fcmeq v0.4s, v16.4s, v0.4s + .long 0x4e21e601 // fcmeq v1.4s, v16.4s, v1.4s + .long 0x4e31d610 // fadd v16.4s, v16.4s, v17.4s + .long 0x52a7c548 // mov w8, #0x3e2a0000 + .long 0x4e33cc54 // fmla v20.4s, v2.4s, v19.4s + .long 0x4e38cc59 // fmla v25.4s, v2.4s, v24.4s + .long 0x6e3ade02 // fmul v2.4s, v16.4s, v26.4s + .long 0x72955568 // movk w8, #0xaaab + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4eb1d651 // fsub v17.4s, v18.4s, v17.4s + .long 0x6ebae452 // fcmgt v18.4s, v2.4s, v26.4s + .long 0x6e791ee1 // bsl v1.16b, v23.16b, v25.16b + .long 0x4e040d13 // dup v19.4s, w8 + .long 0x6e701e32 // bsl v18.16b, v17.16b, v16.16b + .long 0x6e611e80 // bsl v0.16b, v20.16b, v1.16b + .long 0x6e32fea1 // fdiv v1.4s, v21.4s, v18.4s + .long 0x6e33dc00 // fmul v0.4s, v0.4s, v19.4s + .long 0x4e761c00 // bic v0.16b, v0.16b, v22.16b + .long 0x4e761c21 // bic v1.16b, v1.16b, v22.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_hsl_to_rgb_aarch64 +.globl _sk_hsl_to_rgb_aarch64 +_sk_hsl_to_rgb_aarch64: + .long 0x52a7d548 // mov w8, #0x3eaa0000 + .long 0x72955568 // movk w8, #0xaaab + .long 0x4e040d17 // dup v23.4s, w8 + .long 0x52a7c548 // mov w8, #0x3e2a0000 + .long 0x72955568 // movk w8, #0xaaab + .long 0x4e040d13 // dup v19.4s, w8 + .long 0x52a7e548 // mov w8, #0x3f2a0000 + .long 0x4f03f612 // fmov v18.4s, #1.000000000000000000e+00 + .long 0x4f07f616 // fmov v22.4s, #-1.000000000000000000e+00 + .long 0x72955568 // movk w8, #0xaaab + .long 0x4e22d435 // fadd v21.4s, v1.4s, v2.4s + .long 0x4e040d1a // dup v26.4s, w8 + .long 0x52b7d548 // mov w8, #0xbeaa0000 + .long 0x6eb2e41d // fcmgt v29.4s, v0.4s, v18.4s + .long 0x4e36d41e // fadd v30.4s, v0.4s, v22.4s + .long 0x4f0167f1 // movi v17.4s, #0x3f, lsl #24 + .long 0x4ea0d830 // fcmeq v16.4s, v1.4s, #0.0 + .long 0x4ea0e819 // fcmlt v25.4s, v0.4s, #0.0 + .long 0x72955568 // movk w8, #0xaaab + .long 0x4e32d43c // fadd v28.4s, v1.4s, v18.4s + .long 0x4ea2cc35 // fmls v21.4s, v1.4s, v2.4s + .long 0x4e32d401 // fadd v1.4s, v0.4s, v18.4s + .long 0x6e601fdd // bsl v29.16b, v30.16b, v0.16b + .long 0x4e37d417 // fadd v23.4s, v0.4s, v23.4s + .long 0x6ea2e63b // fcmgt v27.4s, v17.4s, v2.4s + .long 0x4e040d1e // dup v30.4s, w8 + .long 0x6e22df9c // fmul v28.4s, v28.4s, v2.4s + .long 0x6e7d1c39 // bsl v25.16b, v1.16b, v29.16b + .long 0x6eb2e6e1 // fcmgt v1.4s, v23.4s, v18.4s + .long 0x4e36d6fd // fadd v29.4s, v23.4s, v22.4s + .long 0x4e3ed41e // fadd v30.4s, v0.4s, v30.4s + .long 0x6e751f9b // bsl v27.16b, v28.16b, v21.16b + .long 0x4ea0eaf5 // fcmlt v21.4s, v23.4s, #0.0 + .long 0x4e32d6fc // fadd v28.4s, v23.4s, v18.4s + .long 0x6e771fa1 // bsl v1.16b, v29.16b, v23.16b + .long 0x4f026414 // movi v20.4s, #0x40, lsl #24 + .long 0x6e611f95 // bsl v21.16b, v28.16b, v1.16b + .long 0x4e32d7c1 // fadd v1.4s, v30.4s, v18.4s + .long 0x6eb2e7d2 // fcmgt v18.4s, v30.4s, v18.4s + .long 0x4e36d7d6 // fadd v22.4s, v30.4s, v22.4s + .long 0x6ea0fb7c // fneg v28.4s, v27.4s + .long 0x4ea0ebdd // fcmlt v29.4s, v30.4s, #0.0 + .long 0x6e7e1ed2 // bsl v18.16b, v22.16b, v30.16b + .long 0x4e22ce9c // fmla v28.4s, v20.4s, v2.4s + .long 0x4f00f718 // fmov v24.4s, #6.000000000000000000e+00 + .long 0x6e721c3d // bsl v29.16b, v1.16b, v18.16b + .long 0x4ebcd761 // fsub v1.4s, v27.4s, v28.4s + .long 0x4eb5d752 // fsub v18.4s, v26.4s, v21.4s + .long 0x4ebc1f94 // mov v20.16b, v28.16b + .long 0x6e38dc38 // fmul v24.4s, v1.4s, v24.4s + .long 0x4eb9d756 // fsub v22.4s, v26.4s, v25.4s + .long 0x4ebc1f9f // mov v31.16b, v28.16b + .long 0x4e32cf14 // fmla v20.4s, v24.4s, v18.4s + .long 0x4ebc1f81 // mov v1.16b, v28.16b + .long 0x4ebc1f92 // mov v18.16b, v28.16b + .long 0x4e38cc1f // fmla v31.4s, v0.4s, v24.4s + .long 0x4e36cf01 // fmla v1.4s, v24.4s, v22.4s + .long 0x4ebdd740 // fsub v0.4s, v26.4s, v29.4s + .long 0x4e3ecf12 // fmla v18.4s, v24.4s, v30.4s + .long 0x4ebc1f96 // mov v22.16b, v28.16b + .long 0x6eb5e75e // fcmgt v30.4s, v26.4s, v21.4s + .long 0x4e20cf16 // fmla v22.4s, v24.4s, v0.4s + .long 0x6e7c1e9e // bsl v30.16b, v20.16b, v28.16b + .long 0x6eb9e754 // fcmgt v20.4s, v26.4s, v25.4s + .long 0x6ebde75a // fcmgt v26.4s, v26.4s, v29.4s + .long 0x6e7c1c34 // bsl v20.16b, v1.16b, v28.16b + .long 0x6e7c1eda // bsl v26.16b, v22.16b, v28.16b + .long 0x4e37cf1c // fmla v28.4s, v24.4s, v23.4s + .long 0x6eb9e637 // fcmgt v23.4s, v17.4s, v25.4s + .long 0x6eb5e678 // fcmgt v24.4s, v19.4s, v21.4s + .long 0x6eb5e635 // fcmgt v21.4s, v17.4s, v21.4s + .long 0x6ebde631 // fcmgt v17.4s, v17.4s, v29.4s + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x6eb9e676 // fcmgt v22.4s, v19.4s, v25.4s + .long 0x6ebde673 // fcmgt v19.4s, v19.4s, v29.4s + .long 0x6e7a1f71 // bsl v17.16b, v27.16b, v26.16b + .long 0x6e7e1f75 // bsl v21.16b, v27.16b, v30.16b + .long 0x6e741f77 // bsl v23.16b, v27.16b, v20.16b + .long 0x6e711e53 // bsl v19.16b, v18.16b, v17.16b + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0x4eb01e01 // mov v1.16b, v16.16b + .long 0x6e751f98 // bsl v24.16b, v28.16b, v21.16b + .long 0x6e771ff6 // bsl v22.16b, v31.16b, v23.16b + .long 0x6e731c50 // bsl v16.16b, v2.16b, v19.16b + .long 0x6e781c40 // bsl v0.16b, v2.16b, v24.16b + .long 0x6e761c41 // bsl v1.16b, v2.16b, v22.16b + .long 0x4eb01e02 // mov v2.16b, v16.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_scale_1_float_aarch64 +.globl _sk_scale_1_float_aarch64 +_sk_scale_1_float_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xbd400110 // ldr s16, [x8] + .long 0x4f909000 // fmul v0.4s, v0.4s, v16.s[0] + .long 0x4f909021 // fmul v1.4s, v1.4s, v16.s[0] + .long 0x4f909042 // fmul v2.4s, v2.4s, v16.s[0] + .long 0x4f909063 // fmul v3.4s, v3.4s, v16.s[0] + .long 0xd61f0060 // br x3 + +HIDDEN _sk_scale_u8_aarch64 +.globl _sk_scale_u8_aarch64 +_sk_scale_u8_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x52a77009 // mov w9, #0x3b800000 + .long 0x72901029 // movk w9, #0x8081 + .long 0x4e040d30 // dup v16.4s, w9 + .long 0xf9400108 // ldr x8, [x8] + .long 0x8b000108 // add x8, x8, x0 + .long 0x39400109 // ldrb w9, [x8] + .long 0x3940050a // ldrb w10, [x8, #1] + .long 0x3940090b // ldrb w11, [x8, #2] + .long 0x39400d08 // ldrb w8, [x8, #3] + .long 0x4e021d31 // mov v17.h[0], w9 + .long 0x4e061d51 // mov v17.h[1], w10 + .long 0x4e0a1d71 // mov v17.h[2], w11 + .long 0x4e0e1d11 // mov v17.h[3], w8 + .long 0x2f10a631 // uxtl v17.4s, v17.4h + .long 0x6e21da31 // ucvtf v17.4s, v17.4s + .long 0x6e30de30 // fmul v16.4s, v17.4s, v16.4s + .long 0x6e20de00 // fmul v0.4s, v16.4s, v0.4s + .long 0x6e21de01 // fmul v1.4s, v16.4s, v1.4s + .long 0x6e22de02 // fmul v2.4s, v16.4s, v2.4s + .long 0x6e23de03 // fmul v3.4s, v16.4s, v3.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_lerp_1_float_aarch64 +.globl _sk_lerp_1_float_aarch64 +_sk_lerp_1_float_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x4ea4d411 // fsub v17.4s, v0.4s, v4.4s + .long 0x4ea41c80 // mov v0.16b, v4.16b + .long 0x4ea5d432 // fsub v18.4s, v1.4s, v5.4s + .long 0xbd400110 // ldr s16, [x8] + .long 0x4ea51ca1 // mov v1.16b, v5.16b + .long 0x4f901220 // fmla v0.4s, v17.4s, v16.s[0] + .long 0x4ea6d451 // fsub v17.4s, v2.4s, v6.4s + .long 0x4f901241 // fmla v1.4s, v18.4s, v16.s[0] + .long 0x4ea61cc2 // mov v2.16b, v6.16b + .long 0x4ea7d472 // fsub v18.4s, v3.4s, v7.4s + .long 0x4ea71ce3 // mov v3.16b, v7.16b + .long 0x4f901222 // fmla v2.4s, v17.4s, v16.s[0] + .long 0x4f901243 // fmla v3.4s, v18.4s, v16.s[0] + .long 0xd61f0060 // br x3 + +HIDDEN _sk_lerp_u8_aarch64 +.globl _sk_lerp_u8_aarch64 +_sk_lerp_u8_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x52a77009 // mov w9, #0x3b800000 + .long 0x72901029 // movk w9, #0x8081 + .long 0x4e040d30 // dup v16.4s, w9 + .long 0xf9400108 // ldr x8, [x8] + .long 0x4ea4d412 // fsub v18.4s, v0.4s, v4.4s + .long 0x8b000108 // add x8, x8, x0 + .long 0x3940010a // ldrb w10, [x8] + .long 0x39400509 // ldrb w9, [x8, #1] + .long 0x3940090b // ldrb w11, [x8, #2] + .long 0x39400d08 // ldrb w8, [x8, #3] + .long 0x4e021d51 // mov v17.h[0], w10 + .long 0x4e061d31 // mov v17.h[1], w9 + .long 0x4e0a1d71 // mov v17.h[2], w11 + .long 0x4e0e1d11 // mov v17.h[3], w8 + .long 0x2f10a620 // uxtl v0.4s, v17.4h + .long 0x6e21d800 // ucvtf v0.4s, v0.4s + .long 0x6e30dc10 // fmul v16.4s, v0.4s, v16.4s + .long 0x4ea41c80 // mov v0.16b, v4.16b + .long 0x4ea5d431 // fsub v17.4s, v1.4s, v5.4s + .long 0x4ea51ca1 // mov v1.16b, v5.16b + .long 0x4e32ce00 // fmla v0.4s, v16.4s, v18.4s + .long 0x4ea6d452 // fsub v18.4s, v2.4s, v6.4s + .long 0x4e31ce01 // fmla v1.4s, v16.4s, v17.4s + .long 0x4ea61cc2 // mov v2.16b, v6.16b + .long 0x4ea7d471 // fsub v17.4s, v3.4s, v7.4s + .long 0x4ea71ce3 // mov v3.16b, v7.16b + .long 0x4e32ce02 // fmla v2.4s, v16.4s, v18.4s + .long 0x4e31ce03 // fmla v3.4s, v16.4s, v17.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_lerp_565_aarch64 +.globl _sk_lerp_565_aarch64 +_sk_lerp_565_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xd37ff809 // lsl x9, x0, #1 + .long 0x4f072710 // movi v16.4s, #0xf8, lsl #8 + .long 0x4ea4d413 // fsub v19.4s, v0.4s, v4.4s + .long 0xf9400108 // ldr x8, [x8] + .long 0xfc696903 // ldr d3, [x8, x9] + .long 0x52a6f088 // mov w8, #0x37840000 + .long 0x72842108 // movk w8, #0x2108 + .long 0x4e040d11 // dup v17.4s, w8 + .long 0x2f10a463 // uxtl v3.4s, v3.4h + .long 0x321b17e8 // orr w8, wzr, #0x7e0 + .long 0x4e301c60 // and v0.16b, v3.16b, v16.16b + .long 0x4e040d12 // dup v18.4s, w8 + .long 0x52a74048 // mov w8, #0x3a020000 + .long 0x4e21d800 // scvtf v0.4s, v0.4s + .long 0x72810428 // movk w8, #0x821 + .long 0x6e31dc10 // fmul v16.4s, v0.4s, v17.4s + .long 0x4ea41c80 // mov v0.16b, v4.16b + .long 0x4e33ce00 // fmla v0.4s, v16.4s, v19.4s + .long 0x4f0007f0 // movi v16.4s, #0x1f + .long 0x4e040d11 // dup v17.4s, w8 + .long 0x52a7a088 // mov w8, #0x3d040000 + .long 0x4e321c72 // and v18.16b, v3.16b, v18.16b + .long 0x72842108 // movk w8, #0x2108 + .long 0x4e301c63 // and v3.16b, v3.16b, v16.16b + .long 0x4ea6d450 // fsub v16.4s, v2.4s, v6.4s + .long 0x4e21da42 // scvtf v2.4s, v18.4s + .long 0x6e31dc51 // fmul v17.4s, v2.4s, v17.4s + .long 0x4e040d02 // dup v2.4s, w8 + .long 0x4e21d863 // scvtf v3.4s, v3.4s + .long 0x4ea5d433 // fsub v19.4s, v1.4s, v5.4s + .long 0x4ea51ca1 // mov v1.16b, v5.16b + .long 0x6e22dc63 // fmul v3.4s, v3.4s, v2.4s + .long 0x4ea61cc2 // mov v2.16b, v6.16b + .long 0x4e33ce21 // fmla v1.4s, v17.4s, v19.4s + .long 0x4e30cc62 // fmla v2.4s, v3.4s, v16.4s + .long 0x4f03f603 // fmov v3.4s, #1.000000000000000000e+00 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_load_tables_aarch64 +.globl _sk_load_tables_aarch64 +_sk_load_tables_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xd37ef409 // lsl x9, x0, #2 + .long 0x6f00e620 // movi v0.2d, #0xff000000ff + .long 0x52a7700b // mov w11, #0x3b800000 + .long 0xa940310a // ldp x10, x12, [x8] + .long 0x7290102b // movk w11, #0x8081 + .long 0x4e040d63 // dup v3.4s, w11 + .long 0x3ce96942 // ldr q2, [x10, x9] + .long 0xa9412109 // ldp x9, x8, [x8, #16] + .long 0x4e201c41 // and v1.16b, v2.16b, v0.16b + .long 0x1e26002e // fmov w14, s1 + .long 0x6f380450 // ushr v16.4s, v2.4s, #8 + .long 0x6f300451 // ushr v17.4s, v2.4s, #16 + .long 0x8b2e498e // add x14, x12, w14, uxtw #2 + .long 0x0e0c3c2a // mov w10, v1.s[1] + .long 0x0e143c2b // mov w11, v1.s[2] + .long 0x0e1c3c2d // mov w13, v1.s[3] + .long 0x4e201e01 // and v1.16b, v16.16b, v0.16b + .long 0x4e201e30 // and v16.16b, v17.16b, v0.16b + .long 0x0d4081c0 // ld1 {v0.s}[0], [x14] + .long 0x8b2a498a // add x10, x12, w10, uxtw #2 + .long 0xbc6b5991 // ldr s17, [x12, w11, uxtw #2] + .long 0xbc6d5992 // ldr s18, [x12, w13, uxtw #2] + .long 0x0e0c3c2b // mov w11, v1.s[1] + .long 0x0e143c2c // mov w12, v1.s[2] + .long 0x0e1c3c2d // mov w13, v1.s[3] + .long 0x1e26002e // fmov w14, s1 + .long 0x8b2e492e // add x14, x9, w14, uxtw #2 + .long 0xbc6c5933 // ldr s19, [x9, w12, uxtw #2] + .long 0xbc6d5934 // ldr s20, [x9, w13, uxtw #2] + .long 0x8b2b4929 // add x9, x9, w11, uxtw #2 + .long 0x1e26020b // fmov w11, s16 + .long 0x6f280442 // ushr v2.4s, v2.4s, #24 + .long 0x0d409140 // ld1 {v0.s}[1], [x10] + .long 0x4e21d842 // scvtf v2.4s, v2.4s + .long 0x8b2b490a // add x10, x8, w11, uxtw #2 + .long 0x0d4081c1 // ld1 {v1.s}[0], [x14] + .long 0x6e23dc43 // fmul v3.4s, v2.4s, v3.4s + .long 0x0d408142 // ld1 {v2.s}[0], [x10] + .long 0x0e0c3e0f // mov w15, v16.s[1] + .long 0x0e143e0c // mov w12, v16.s[2] + .long 0x8b2f490a // add x10, x8, w15, uxtw #2 + .long 0x0e1c3e0d // mov w13, v16.s[3] + .long 0xbc6c5910 // ldr s16, [x8, w12, uxtw #2] + .long 0x0d409121 // ld1 {v1.s}[1], [x9] + .long 0x0d409142 // ld1 {v2.s}[1], [x10] + .long 0x6e140620 // mov v0.s[2], v17.s[0] + .long 0xbc6d5911 // ldr s17, [x8, w13, uxtw #2] + .long 0x6e140661 // mov v1.s[2], v19.s[0] + .long 0x6e140602 // mov v2.s[2], v16.s[0] + .long 0x6e1c0640 // mov v0.s[3], v18.s[0] + .long 0x6e1c0681 // mov v1.s[3], v20.s[0] + .long 0x6e1c0622 // mov v2.s[3], v17.s[0] + .long 0xd61f0060 // br x3 + +HIDDEN _sk_byte_tables_aarch64 +.globl _sk_byte_tables_aarch64 +_sk_byte_tables_aarch64: + .long 0xd10083ff // sub sp, sp, #0x20 + .long 0xaa0103e8 // mov x8, x1 + .long 0x91002109 // add x9, x8, #0x8 + .long 0xa9014ff4 // stp x20, x19, [sp, #16] + .long 0xf90007e9 // str x9, [sp, #8] + .long 0xf8410429 // ldr x9, [x1], #16 + .long 0x52a86fea // mov w10, #0x437f0000 + .long 0x4e040d51 // dup v17.4s, w10 + .long 0x52a7700b // mov w11, #0x3b800000 + .long 0xa9405126 // ldp x6, x20, [x9] + .long 0x6e31dc00 // fmul v0.4s, v0.4s, v17.4s + .long 0x7290102b // movk w11, #0x8081 + .long 0x6e21a800 // fcvtnu v0.4s, v0.4s + .long 0x4e040d70 // dup v16.4s, w11 + .long 0x0e0c3c0a // mov w10, v0.s[1] + .long 0x0e143c0b // mov w11, v0.s[2] + .long 0x0e1c3c0c // mov w12, v0.s[3] + .long 0x1e26000d // fmov w13, s0 + .long 0x386d48cd // ldrb w13, [x6, w13, uxtw] + .long 0x386a48ca // ldrb w10, [x6, w10, uxtw] + .long 0x386b48cb // ldrb w11, [x6, w11, uxtw] + .long 0x386c48cc // ldrb w12, [x6, w12, uxtw] + .long 0xa9412526 // ldp x6, x9, [x9, #16] + .long 0x6e31dc42 // fmul v2.4s, v2.4s, v17.4s + .long 0x6e31dc21 // fmul v1.4s, v1.4s, v17.4s + .long 0x6e31dc63 // fmul v3.4s, v3.4s, v17.4s + .long 0x6e21a842 // fcvtnu v2.4s, v2.4s + .long 0x6e21a821 // fcvtnu v1.4s, v1.4s + .long 0x6e21a863 // fcvtnu v3.4s, v3.4s + .long 0x0e0c3c52 // mov w18, v2.s[1] + .long 0x0e143c43 // mov w3, v2.s[2] + .long 0x0e1c3c44 // mov w4, v2.s[3] + .long 0x1e260045 // fmov w5, s2 + .long 0x1e260031 // fmov w17, s1 + .long 0x386548c5 // ldrb w5, [x6, w5, uxtw] + .long 0x387248d2 // ldrb w18, [x6, w18, uxtw] + .long 0x386348c3 // ldrb w3, [x6, w3, uxtw] + .long 0x386448c4 // ldrb w4, [x6, w4, uxtw] + .long 0x1e260066 // fmov w6, s3 + .long 0x0e0c3c2e // mov w14, v1.s[1] + .long 0x0e0c3c67 // mov w7, v3.s[1] + .long 0x38714a91 // ldrb w17, [x20, w17, uxtw] + .long 0x38664926 // ldrb w6, [x9, w6, uxtw] + .long 0x0e143c2f // mov w15, v1.s[2] + .long 0x0e1c3c30 // mov w16, v1.s[3] + .long 0x0e143c73 // mov w19, v3.s[2] + .long 0x386e4a8e // ldrb w14, [x20, w14, uxtw] + .long 0x38674927 // ldrb w7, [x9, w7, uxtw] + .long 0x386f4a8f // ldrb w15, [x20, w15, uxtw] + .long 0x38704a90 // ldrb w16, [x20, w16, uxtw] + .long 0x0e1c3c74 // mov w20, v3.s[3] + .long 0x38734933 // ldrb w19, [x9, w19, uxtw] + .long 0x38744929 // ldrb w9, [x9, w20, uxtw] + .long 0x4e021da0 // mov v0.h[0], w13 + .long 0x4e021e21 // mov v1.h[0], w17 + .long 0x4e021ca2 // mov v2.h[0], w5 + .long 0x4e021cc3 // mov v3.h[0], w6 + .long 0x4e061d40 // mov v0.h[1], w10 + .long 0x4e061dc1 // mov v1.h[1], w14 + .long 0x4e061e42 // mov v2.h[1], w18 + .long 0x4e061ce3 // mov v3.h[1], w7 + .long 0x4e0a1d60 // mov v0.h[2], w11 + .long 0x4e0a1de1 // mov v1.h[2], w15 + .long 0x4e0a1c62 // mov v2.h[2], w3 + .long 0x4e0a1e63 // mov v3.h[2], w19 + .long 0x4e0e1d80 // mov v0.h[3], w12 + .long 0x4e0e1e01 // mov v1.h[3], w16 + .long 0x4e0e1c82 // mov v2.h[3], w4 + .long 0x4e0e1d23 // mov v3.h[3], w9 + .long 0xf9400505 // ldr x5, [x8, #8] + .long 0x2f07b7e0 // bic v0.4h, #0xff, lsl #8 + .long 0x2f07b7e1 // bic v1.4h, #0xff, lsl #8 + .long 0x2f07b7e2 // bic v2.4h, #0xff, lsl #8 + .long 0x2f07b7e3 // bic v3.4h, #0xff, lsl #8 + .long 0xa9414ff4 // ldp x20, x19, [sp, #16] + .long 0x2f10a400 // uxtl v0.4s, v0.4h + .long 0x2f10a421 // uxtl v1.4s, v1.4h + .long 0x2f10a442 // uxtl v2.4s, v2.4h + .long 0x2f10a463 // uxtl v3.4s, v3.4h + .long 0x6e21d800 // ucvtf v0.4s, v0.4s + .long 0x6e21d821 // ucvtf v1.4s, v1.4s + .long 0x6e21d842 // ucvtf v2.4s, v2.4s + .long 0x6e21d863 // ucvtf v3.4s, v3.4s + .long 0x6e30dc00 // fmul v0.4s, v0.4s, v16.4s + .long 0x6e30dc21 // fmul v1.4s, v1.4s, v16.4s + .long 0x6e30dc42 // fmul v2.4s, v2.4s, v16.4s + .long 0x6e30dc63 // fmul v3.4s, v3.4s, v16.4s + .long 0x910083ff // add sp, sp, #0x20 + .long 0xd61f00a0 // br x5 + +HIDDEN _sk_byte_tables_rgb_aarch64 +.globl _sk_byte_tables_rgb_aarch64 +_sk_byte_tables_rgb_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x52a77009 // mov w9, #0x3b800000 + .long 0x72901029 // movk w9, #0x8081 + .long 0x4e040d30 // dup v16.4s, w9 + .long 0xb9401909 // ldr w9, [x8, #24] + .long 0xa9402d0a // ldp x10, x11, [x8] + .long 0xf9400908 // ldr x8, [x8, #16] + .long 0x51000529 // sub w9, w9, #0x1 + .long 0x4e040d31 // dup v17.4s, w9 + .long 0x4e21da31 // scvtf v17.4s, v17.4s + .long 0x6e21de21 // fmul v1.4s, v17.4s, v1.4s + .long 0x6e20de20 // fmul v0.4s, v17.4s, v0.4s + .long 0x6e22de22 // fmul v2.4s, v17.4s, v2.4s + .long 0x6e21a821 // fcvtnu v1.4s, v1.4s + .long 0x6e21a800 // fcvtnu v0.4s, v0.4s + .long 0x6e21a842 // fcvtnu v2.4s, v2.4s + .long 0x0e0c3c2f // mov w15, v1.s[1] + .long 0x0e143c30 // mov w16, v1.s[2] + .long 0x0e1c3c31 // mov w17, v1.s[3] + .long 0x1e260032 // fmov w18, s1 + .long 0x1e26000e // fmov w14, s0 + .long 0x38724972 // ldrb w18, [x11, w18, uxtw] + .long 0x386f496f // ldrb w15, [x11, w15, uxtw] + .long 0x38704970 // ldrb w16, [x11, w16, uxtw] + .long 0x3871496b // ldrb w11, [x11, w17, uxtw] + .long 0x1e260051 // fmov w17, s2 + .long 0x0e0c3c09 // mov w9, v0.s[1] + .long 0x386e494e // ldrb w14, [x10, w14, uxtw] + .long 0x0e0c3c44 // mov w4, v2.s[1] + .long 0x38714911 // ldrb w17, [x8, w17, uxtw] + .long 0x0e143c0c // mov w12, v0.s[2] + .long 0x0e1c3c0d // mov w13, v0.s[3] + .long 0x0e143c45 // mov w5, v2.s[2] + .long 0x38694949 // ldrb w9, [x10, w9, uxtw] + .long 0x38644904 // ldrb w4, [x8, w4, uxtw] + .long 0x386c494c // ldrb w12, [x10, w12, uxtw] + .long 0x386d494a // ldrb w10, [x10, w13, uxtw] + .long 0x0e1c3c4d // mov w13, v2.s[3] + .long 0x38654905 // ldrb w5, [x8, w5, uxtw] + .long 0x386d4908 // ldrb w8, [x8, w13, uxtw] + .long 0x4e021dc0 // mov v0.h[0], w14 + .long 0x4e021e41 // mov v1.h[0], w18 + .long 0x4e021e22 // mov v2.h[0], w17 + .long 0x4e061d20 // mov v0.h[1], w9 + .long 0x4e061de1 // mov v1.h[1], w15 + .long 0x4e061c82 // mov v2.h[1], w4 + .long 0x4e0a1d80 // mov v0.h[2], w12 + .long 0x4e0a1e01 // mov v1.h[2], w16 + .long 0x4e0a1ca2 // mov v2.h[2], w5 + .long 0x4e0e1d40 // mov v0.h[3], w10 + .long 0x4e0e1d61 // mov v1.h[3], w11 + .long 0x4e0e1d02 // mov v2.h[3], w8 + .long 0x2f07b7e0 // bic v0.4h, #0xff, lsl #8 + .long 0x2f07b7e1 // bic v1.4h, #0xff, lsl #8 + .long 0x2f07b7e2 // bic v2.4h, #0xff, lsl #8 + .long 0x2f10a400 // uxtl v0.4s, v0.4h + .long 0x2f10a421 // uxtl v1.4s, v1.4h + .long 0x2f10a442 // uxtl v2.4s, v2.4h + .long 0x6e21d800 // ucvtf v0.4s, v0.4s + .long 0x6e21d821 // ucvtf v1.4s, v1.4s + .long 0x6e21d842 // ucvtf v2.4s, v2.4s + .long 0x6e30dc00 // fmul v0.4s, v0.4s, v16.4s + .long 0x6e30dc21 // fmul v1.4s, v1.4s, v16.4s + .long 0x6e30dc42 // fmul v2.4s, v2.4s, v16.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_load_a8_aarch64 +.globl _sk_load_a8_aarch64 +_sk_load_a8_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x52a77009 // mov w9, #0x3b800000 + .long 0x72901029 // movk w9, #0x8081 + .long 0x4e040d22 // dup v2.4s, w9 + .long 0xf9400108 // ldr x8, [x8] + .long 0x6f00e400 // movi v0.2d, #0x0 + .long 0x6f00e401 // movi v1.2d, #0x0 + .long 0x8b000108 // add x8, x8, x0 + .long 0x3940010a // ldrb w10, [x8] + .long 0x3940050b // ldrb w11, [x8, #1] + .long 0x3940090c // ldrb w12, [x8, #2] + .long 0x39400d08 // ldrb w8, [x8, #3] + .long 0x4e021d43 // mov v3.h[0], w10 + .long 0x4e061d63 // mov v3.h[1], w11 + .long 0x4e0a1d83 // mov v3.h[2], w12 + .long 0x4e0e1d03 // mov v3.h[3], w8 + .long 0x2f10a463 // uxtl v3.4s, v3.4h + .long 0x6e21d863 // ucvtf v3.4s, v3.4s + .long 0x6e22dc63 // fmul v3.4s, v3.4s, v2.4s + .long 0x6f00e402 // movi v2.2d, #0x0 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_gather_a8_aarch64 +.globl _sk_gather_a8_aarch64 +_sk_gather_a8_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x4ea1b821 // fcvtzs v1.4s, v1.4s + .long 0x4ea1b800 // fcvtzs v0.4s, v0.4s + .long 0x91004109 // add x9, x8, #0x10 + .long 0x4d40c922 // ld1r {v2.4s}, [x9] + .long 0xf9400108 // ldr x8, [x8] + .long 0x52a77009 // mov w9, #0x3b800000 + .long 0x72901029 // movk w9, #0x8081 + .long 0x4ea19440 // mla v0.4s, v2.4s, v1.4s + .long 0x1e26000c // fmov w12, s0 + .long 0x4e040d23 // dup v3.4s, w9 + .long 0x0e0c3c09 // mov w9, v0.s[1] + .long 0x386c490c // ldrb w12, [x8, w12, uxtw] + .long 0x0e143c0a // mov w10, v0.s[2] + .long 0x38694909 // ldrb w9, [x8, w9, uxtw] + .long 0x0e1c3c0b // mov w11, v0.s[3] + .long 0x386a490a // ldrb w10, [x8, w10, uxtw] + .long 0x386b4908 // ldrb w8, [x8, w11, uxtw] + .long 0x4e021d82 // mov v2.h[0], w12 + .long 0x4e061d22 // mov v2.h[1], w9 + .long 0x4e0a1d42 // mov v2.h[2], w10 + .long 0x4e0e1d02 // mov v2.h[3], w8 + .long 0x2f07b7e2 // bic v2.4h, #0xff, lsl #8 + .long 0x2f10a442 // uxtl v2.4s, v2.4h + .long 0x6e21d842 // ucvtf v2.4s, v2.4s + .long 0x6f00e400 // movi v0.2d, #0x0 + .long 0x6f00e401 // movi v1.2d, #0x0 + .long 0x6e23dc43 // fmul v3.4s, v2.4s, v3.4s + .long 0x6f00e402 // movi v2.2d, #0x0 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_store_a8_aarch64 +.globl _sk_store_a8_aarch64 +_sk_store_a8_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x52a86fe9 // mov w9, #0x437f0000 + .long 0x4e040d30 // dup v16.4s, w9 + .long 0x6e30dc70 // fmul v16.4s, v3.4s, v16.4s + .long 0xf9400108 // ldr x8, [x8] + .long 0x6e21aa10 // fcvtnu v16.4s, v16.4s + .long 0x0e612a10 // xtn v16.4h, v16.4s + .long 0x0e0e3e09 // umov w9, v16.h[3] + .long 0x8b000108 // add x8, x8, x0 + .long 0x39000d09 // strb w9, [x8, #3] + .long 0x0e0a3e09 // umov w9, v16.h[2] + .long 0x39000909 // strb w9, [x8, #2] + .long 0x0e063e09 // umov w9, v16.h[1] + .long 0x39000509 // strb w9, [x8, #1] + .long 0x0e023e09 // umov w9, v16.h[0] + .long 0x39000109 // strb w9, [x8] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_load_g8_aarch64 +.globl _sk_load_g8_aarch64 +_sk_load_g8_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x52a77009 // mov w9, #0x3b800000 + .long 0x72901029 // movk w9, #0x8081 + .long 0x4e040d20 // dup v0.4s, w9 + .long 0xf9400108 // ldr x8, [x8] + .long 0x4f03f603 // fmov v3.4s, #1.000000000000000000e+00 + .long 0x8b000108 // add x8, x8, x0 + .long 0x3940010a // ldrb w10, [x8] + .long 0x39400509 // ldrb w9, [x8, #1] + .long 0x3940090b // ldrb w11, [x8, #2] + .long 0x39400d08 // ldrb w8, [x8, #3] + .long 0x4e021d41 // mov v1.h[0], w10 + .long 0x4e061d21 // mov v1.h[1], w9 + .long 0x4e0a1d61 // mov v1.h[2], w11 + .long 0x4e0e1d01 // mov v1.h[3], w8 + .long 0x2f10a421 // uxtl v1.4s, v1.4h + .long 0x6e21d821 // ucvtf v1.4s, v1.4s + .long 0x6e20dc20 // fmul v0.4s, v1.4s, v0.4s + .long 0x4ea01c01 // mov v1.16b, v0.16b + .long 0x4ea01c02 // mov v2.16b, v0.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_gather_g8_aarch64 +.globl _sk_gather_g8_aarch64 +_sk_gather_g8_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x4ea1b821 // fcvtzs v1.4s, v1.4s + .long 0x4ea1b800 // fcvtzs v0.4s, v0.4s + .long 0x91004109 // add x9, x8, #0x10 + .long 0x4d40c922 // ld1r {v2.4s}, [x9] + .long 0xf9400108 // ldr x8, [x8] + .long 0x52a77009 // mov w9, #0x3b800000 + .long 0x72901029 // movk w9, #0x8081 + .long 0x4ea19440 // mla v0.4s, v2.4s, v1.4s + .long 0x1e26000c // fmov w12, s0 + .long 0x4e040d23 // dup v3.4s, w9 + .long 0x0e0c3c09 // mov w9, v0.s[1] + .long 0x386c490c // ldrb w12, [x8, w12, uxtw] + .long 0x0e143c0a // mov w10, v0.s[2] + .long 0x38694909 // ldrb w9, [x8, w9, uxtw] + .long 0x0e1c3c0b // mov w11, v0.s[3] + .long 0x386a490a // ldrb w10, [x8, w10, uxtw] + .long 0x386b4908 // ldrb w8, [x8, w11, uxtw] + .long 0x4e021d80 // mov v0.h[0], w12 + .long 0x4e061d20 // mov v0.h[1], w9 + .long 0x4e0a1d40 // mov v0.h[2], w10 + .long 0x4e0e1d00 // mov v0.h[3], w8 + .long 0x2f07b7e0 // bic v0.4h, #0xff, lsl #8 + .long 0x2f10a400 // uxtl v0.4s, v0.4h + .long 0x6e21d800 // ucvtf v0.4s, v0.4s + .long 0x6e23dc00 // fmul v0.4s, v0.4s, v3.4s + .long 0x4f03f603 // fmov v3.4s, #1.000000000000000000e+00 + .long 0x4ea01c01 // mov v1.16b, v0.16b + .long 0x4ea01c02 // mov v2.16b, v0.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_gather_i8_aarch64 +.globl _sk_gather_i8_aarch64 +_sk_gather_i8_aarch64: + .long 0xaa0103e8 // mov x8, x1 + .long 0xf8408429 // ldr x9, [x1], #8 + .long 0xb4000069 // cbz x9, 17e4 + .long 0xaa0903ea // mov x10, x9 + .long 0x14000003 // b 17ec + .long 0xf940050a // ldr x10, [x8, #8] + .long 0x91004101 // add x1, x8, #0x10 + .long 0xf8410548 // ldr x8, [x10], #16 + .long 0x4ea1b821 // fcvtzs v1.4s, v1.4s + .long 0x4ea1b800 // fcvtzs v0.4s, v0.4s + .long 0xf9400529 // ldr x9, [x9, #8] + .long 0x4d40c942 // ld1r {v2.4s}, [x10] + .long 0x6f00e623 // movi v3.2d, #0xff000000ff + .long 0x4ea19440 // mla v0.4s, v2.4s, v1.4s + .long 0x1e26000d // fmov w13, s0 + .long 0x0e0c3c0a // mov w10, v0.s[1] + .long 0x386d490d // ldrb w13, [x8, w13, uxtw] + .long 0x0e143c0b // mov w11, v0.s[2] + .long 0x386a490a // ldrb w10, [x8, w10, uxtw] + .long 0x0e1c3c0c // mov w12, v0.s[3] + .long 0x386b490b // ldrb w11, [x8, w11, uxtw] + .long 0x386c4908 // ldrb w8, [x8, w12, uxtw] + .long 0x4e021da0 // mov v0.h[0], w13 + .long 0x4e061d40 // mov v0.h[1], w10 + .long 0x4e0a1d60 // mov v0.h[2], w11 + .long 0x4e0e1d00 // mov v0.h[3], w8 + .long 0x2f10a400 // uxtl v0.4s, v0.4h + .long 0x4e231c00 // and v0.16b, v0.16b, v3.16b + .long 0x1e26000c // fmov w12, s0 + .long 0x8b2c492c // add x12, x9, w12, uxtw #2 + .long 0x0e0c3c08 // mov w8, v0.s[1] + .long 0x0e143c0a // mov w10, v0.s[2] + .long 0x0e1c3c0b // mov w11, v0.s[3] + .long 0x0d408180 // ld1 {v0.s}[0], [x12] + .long 0x8b284928 // add x8, x9, w8, uxtw #2 + .long 0xb86a592a // ldr w10, [x9, w10, uxtw #2] + .long 0x52a7700c // mov w12, #0x3b800000 + .long 0x0d409100 // ld1 {v0.s}[1], [x8] + .long 0xb86b5928 // ldr w8, [x9, w11, uxtw #2] + .long 0x7290102c // movk w12, #0x8081 + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x4e141d40 // mov v0.s[2], w10 + .long 0x4e1c1d00 // mov v0.s[3], w8 + .long 0x4e231c01 // and v1.16b, v0.16b, v3.16b + .long 0x6f380402 // ushr v2.4s, v0.4s, #8 + .long 0x6f300411 // ushr v17.4s, v0.4s, #16 + .long 0x4e040d90 // dup v16.4s, w12 + .long 0x6f280400 // ushr v0.4s, v0.4s, #24 + .long 0x4e21d821 // scvtf v1.4s, v1.4s + .long 0x4e231c42 // and v2.16b, v2.16b, v3.16b + .long 0x4e231e23 // and v3.16b, v17.16b, v3.16b + .long 0x4e21d811 // scvtf v17.4s, v0.4s + .long 0x6e30dc20 // fmul v0.4s, v1.4s, v16.4s + .long 0x4e21d841 // scvtf v1.4s, v2.4s + .long 0x4e21d862 // scvtf v2.4s, v3.4s + .long 0x6e30dc21 // fmul v1.4s, v1.4s, v16.4s + .long 0x6e30dc42 // fmul v2.4s, v2.4s, v16.4s + .long 0x6e30de23 // fmul v3.4s, v17.4s, v16.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_load_565_aarch64 +.globl _sk_load_565_aarch64 +_sk_load_565_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xd37ff809 // lsl x9, x0, #1 + .long 0x4f072701 // movi v1.4s, #0xf8, lsl #8 + .long 0x4f0007e3 // movi v3.4s, #0x1f + .long 0xf9400108 // ldr x8, [x8] + .long 0xfc696900 // ldr d0, [x8, x9] + .long 0x321b17e8 // orr w8, wzr, #0x7e0 + .long 0x4e040d02 // dup v2.4s, w8 + .long 0x52a6f088 // mov w8, #0x37840000 + .long 0x72842108 // movk w8, #0x2108 + .long 0x2f10a400 // uxtl v0.4s, v0.4h + .long 0x4e211c01 // and v1.16b, v0.16b, v1.16b + .long 0x4e221c02 // and v2.16b, v0.16b, v2.16b + .long 0x4e231c03 // and v3.16b, v0.16b, v3.16b + .long 0x4e040d00 // dup v0.4s, w8 + .long 0x52a74048 // mov w8, #0x3a020000 + .long 0x72810428 // movk w8, #0x821 + .long 0x4e21d821 // scvtf v1.4s, v1.4s + .long 0x6e20dc20 // fmul v0.4s, v1.4s, v0.4s + .long 0x4e040d01 // dup v1.4s, w8 + .long 0x52a7a088 // mov w8, #0x3d040000 + .long 0x72842108 // movk w8, #0x2108 + .long 0x4e21d842 // scvtf v2.4s, v2.4s + .long 0x6e21dc41 // fmul v1.4s, v2.4s, v1.4s + .long 0x4e040d02 // dup v2.4s, w8 + .long 0x4e21d863 // scvtf v3.4s, v3.4s + .long 0x6e22dc62 // fmul v2.4s, v3.4s, v2.4s + .long 0x4f03f603 // fmov v3.4s, #1.000000000000000000e+00 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_gather_565_aarch64 +.globl _sk_gather_565_aarch64 +_sk_gather_565_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x4ea1b821 // fcvtzs v1.4s, v1.4s + .long 0x4ea1b800 // fcvtzs v0.4s, v0.4s + .long 0x91004109 // add x9, x8, #0x10 + .long 0x4d40c922 // ld1r {v2.4s}, [x9] + .long 0xf9400108 // ldr x8, [x8] + .long 0x321b17e9 // orr w9, wzr, #0x7e0 + .long 0x4e040d23 // dup v3.4s, w9 + .long 0x4ea19440 // mla v0.4s, v2.4s, v1.4s + .long 0x1e26000c // fmov w12, s0 + .long 0x0e0c3c09 // mov w9, v0.s[1] + .long 0x8b2c450c // add x12, x8, w12, uxtw #1 + .long 0x0e143c0a // mov w10, v0.s[2] + .long 0x0e1c3c0b // mov w11, v0.s[3] + .long 0x0d404180 // ld1 {v0.h}[0], [x12] + .long 0x78695909 // ldrh w9, [x8, w9, uxtw #1] + .long 0x786a590a // ldrh w10, [x8, w10, uxtw #1] + .long 0x786b5908 // ldrh w8, [x8, w11, uxtw #1] + .long 0x4f072701 // movi v1.4s, #0xf8, lsl #8 + .long 0x4e061d20 // mov v0.h[1], w9 + .long 0x4e0a1d40 // mov v0.h[2], w10 + .long 0x4e0e1d00 // mov v0.h[3], w8 + .long 0x52a6f08b // mov w11, #0x37840000 + .long 0x2f10a400 // uxtl v0.4s, v0.4h + .long 0x7284210b // movk w11, #0x2108 + .long 0x52a74049 // mov w9, #0x3a020000 + .long 0x4f0007e2 // movi v2.4s, #0x1f + .long 0x4e211c01 // and v1.16b, v0.16b, v1.16b + .long 0x72810429 // movk w9, #0x821 + .long 0x52a7a08a // mov w10, #0x3d040000 + .long 0x4e231c03 // and v3.16b, v0.16b, v3.16b + .long 0x4e221c02 // and v2.16b, v0.16b, v2.16b + .long 0x4e040d60 // dup v0.4s, w11 + .long 0x4e21d821 // scvtf v1.4s, v1.4s + .long 0x7284210a // movk w10, #0x2108 + .long 0x6e20dc20 // fmul v0.4s, v1.4s, v0.4s + .long 0x4e040d21 // dup v1.4s, w9 + .long 0x4e21d863 // scvtf v3.4s, v3.4s + .long 0x6e21dc61 // fmul v1.4s, v3.4s, v1.4s + .long 0x4e040d43 // dup v3.4s, w10 + .long 0x4e21d842 // scvtf v2.4s, v2.4s + .long 0x6e23dc42 // fmul v2.4s, v2.4s, v3.4s + .long 0x4f03f603 // fmov v3.4s, #1.000000000000000000e+00 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_store_565_aarch64 +.globl _sk_store_565_aarch64 +_sk_store_565_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x52a84f8a // mov w10, #0x427c0000 + .long 0x4f01f7f0 // fmov v16.4s, #3.100000000000000000e+01 + .long 0x4e040d52 // dup v18.4s, w10 + .long 0x6e30dc11 // fmul v17.4s, v0.4s, v16.4s + .long 0x6e32dc32 // fmul v18.4s, v1.4s, v18.4s + .long 0x6e21aa31 // fcvtnu v17.4s, v17.4s + .long 0x6e21aa52 // fcvtnu v18.4s, v18.4s + .long 0x6e30dc50 // fmul v16.4s, v2.4s, v16.4s + .long 0x4f2b5631 // shl v17.4s, v17.4s, #11 + .long 0xf9400108 // ldr x8, [x8] + .long 0x4f255652 // shl v18.4s, v18.4s, #5 + .long 0x4eb11e51 // orr v17.16b, v18.16b, v17.16b + .long 0x6e21aa10 // fcvtnu v16.4s, v16.4s + .long 0x4eb01e30 // orr v16.16b, v17.16b, v16.16b + .long 0xd37ff809 // lsl x9, x0, #1 + .long 0x0e612a10 // xtn v16.4h, v16.4s + .long 0xfc296910 // str d16, [x8, x9] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_load_4444_aarch64 +.globl _sk_load_4444_aarch64 +_sk_load_4444_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xd37ff809 // lsl x9, x0, #1 + .long 0x4f072601 // movi v1.4s, #0xf0, lsl #8 + .long 0x4f0025e2 // movi v2.4s, #0xf, lsl #8 + .long 0xf9400108 // ldr x8, [x8] + .long 0x4f070603 // movi v3.4s, #0xf0 + .long 0x4f0005f0 // movi v16.4s, #0xf + .long 0xfc696900 // ldr d0, [x8, x9] + .long 0x52a6f108 // mov w8, #0x37880000 + .long 0x72911128 // movk w8, #0x8889 + .long 0x2f10a400 // uxtl v0.4s, v0.4h + .long 0x4e211c01 // and v1.16b, v0.16b, v1.16b + .long 0x4e221c02 // and v2.16b, v0.16b, v2.16b + .long 0x4e231c03 // and v3.16b, v0.16b, v3.16b + .long 0x4e301c10 // and v16.16b, v0.16b, v16.16b + .long 0x4e040d00 // dup v0.4s, w8 + .long 0x52a73108 // mov w8, #0x39880000 + .long 0x72911128 // movk w8, #0x8889 + .long 0x4e21d821 // scvtf v1.4s, v1.4s + .long 0x6e20dc20 // fmul v0.4s, v1.4s, v0.4s + .long 0x4e040d01 // dup v1.4s, w8 + .long 0x52a77108 // mov w8, #0x3b880000 + .long 0x72911128 // movk w8, #0x8889 + .long 0x4e21d842 // scvtf v2.4s, v2.4s + .long 0x6e21dc41 // fmul v1.4s, v2.4s, v1.4s + .long 0x4e040d02 // dup v2.4s, w8 + .long 0x52a7b108 // mov w8, #0x3d880000 + .long 0x72911128 // movk w8, #0x8889 + .long 0x4e21d863 // scvtf v3.4s, v3.4s + .long 0x6e22dc62 // fmul v2.4s, v3.4s, v2.4s + .long 0x4e040d03 // dup v3.4s, w8 + .long 0x4e21da10 // scvtf v16.4s, v16.4s + .long 0x6e23de03 // fmul v3.4s, v16.4s, v3.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_gather_4444_aarch64 +.globl _sk_gather_4444_aarch64 +_sk_gather_4444_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x4ea1b821 // fcvtzs v1.4s, v1.4s + .long 0x4ea1b800 // fcvtzs v0.4s, v0.4s + .long 0x4f070603 // movi v3.4s, #0xf0 + .long 0x91004109 // add x9, x8, #0x10 + .long 0x4d40c922 // ld1r {v2.4s}, [x9] + .long 0xf9400108 // ldr x8, [x8] + .long 0x4f0005f0 // movi v16.4s, #0xf + .long 0x4ea19440 // mla v0.4s, v2.4s, v1.4s + .long 0x1e26000c // fmov w12, s0 + .long 0x0e0c3c09 // mov w9, v0.s[1] + .long 0x8b2c450c // add x12, x8, w12, uxtw #1 + .long 0x0e143c0a // mov w10, v0.s[2] + .long 0x0e1c3c0b // mov w11, v0.s[3] + .long 0x0d404180 // ld1 {v0.h}[0], [x12] + .long 0x78695909 // ldrh w9, [x8, w9, uxtw #1] + .long 0x786a590a // ldrh w10, [x8, w10, uxtw #1] + .long 0x786b5908 // ldrh w8, [x8, w11, uxtw #1] + .long 0x4f072601 // movi v1.4s, #0xf0, lsl #8 + .long 0x4e061d20 // mov v0.h[1], w9 + .long 0x4e0a1d40 // mov v0.h[2], w10 + .long 0x4e0e1d00 // mov v0.h[3], w8 + .long 0x52a6f10b // mov w11, #0x37880000 + .long 0x2f10a400 // uxtl v0.4s, v0.4h + .long 0x7291112b // movk w11, #0x8889 + .long 0x4f0025e2 // movi v2.4s, #0xf, lsl #8 + .long 0x52a73109 // mov w9, #0x39880000 + .long 0x4e211c01 // and v1.16b, v0.16b, v1.16b + .long 0x72911129 // movk w9, #0x8889 + .long 0x52a7710a // mov w10, #0x3b880000 + .long 0x4e221c02 // and v2.16b, v0.16b, v2.16b + .long 0x4e231c03 // and v3.16b, v0.16b, v3.16b + .long 0x4e301c10 // and v16.16b, v0.16b, v16.16b + .long 0x4e040d60 // dup v0.4s, w11 + .long 0x4e21d821 // scvtf v1.4s, v1.4s + .long 0x7291112a // movk w10, #0x8889 + .long 0x52a7b108 // mov w8, #0x3d880000 + .long 0x6e20dc20 // fmul v0.4s, v1.4s, v0.4s + .long 0x4e040d21 // dup v1.4s, w9 + .long 0x4e21d842 // scvtf v2.4s, v2.4s + .long 0x72911128 // movk w8, #0x8889 + .long 0x6e21dc41 // fmul v1.4s, v2.4s, v1.4s + .long 0x4e040d42 // dup v2.4s, w10 + .long 0x4e21d863 // scvtf v3.4s, v3.4s + .long 0x6e22dc62 // fmul v2.4s, v3.4s, v2.4s + .long 0x4e040d03 // dup v3.4s, w8 + .long 0x4e21da10 // scvtf v16.4s, v16.4s + .long 0x6e23de03 // fmul v3.4s, v16.4s, v3.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_store_4444_aarch64 +.globl _sk_store_4444_aarch64 +_sk_store_4444_aarch64: + .long 0x4f01f5d0 // fmov v16.4s, #1.500000000000000000e+01 + .long 0x6e30dc11 // fmul v17.4s, v0.4s, v16.4s + .long 0x6e30dc32 // fmul v18.4s, v1.4s, v16.4s + .long 0xf9400028 // ldr x8, [x1] + .long 0x6e21aa31 // fcvtnu v17.4s, v17.4s + .long 0x6e21aa52 // fcvtnu v18.4s, v18.4s + .long 0x4f2c5631 // shl v17.4s, v17.4s, #12 + .long 0x4f285652 // shl v18.4s, v18.4s, #8 + .long 0x4eb11e51 // orr v17.16b, v18.16b, v17.16b + .long 0x6e30dc52 // fmul v18.4s, v2.4s, v16.4s + .long 0x6e21aa52 // fcvtnu v18.4s, v18.4s + .long 0x6e30dc70 // fmul v16.4s, v3.4s, v16.4s + .long 0x4f245652 // shl v18.4s, v18.4s, #4 + .long 0xf9400108 // ldr x8, [x8] + .long 0x4eb21e31 // orr v17.16b, v17.16b, v18.16b + .long 0x6e21aa10 // fcvtnu v16.4s, v16.4s + .long 0x4eb01e30 // orr v16.16b, v17.16b, v16.16b + .long 0xd37ff809 // lsl x9, x0, #1 + .long 0x0e612a10 // xtn v16.4h, v16.4s + .long 0xfc296910 // str d16, [x8, x9] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_load_8888_aarch64 +.globl _sk_load_8888_aarch64 +_sk_load_8888_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xd37ef409 // lsl x9, x0, #2 + .long 0x6f00e621 // movi v1.2d, #0xff000000ff + .long 0xf9400108 // ldr x8, [x8] + .long 0x3ce96900 // ldr q0, [x8, x9] + .long 0x52a77008 // mov w8, #0x3b800000 + .long 0x72901028 // movk w8, #0x8081 + .long 0x4e040d02 // dup v2.4s, w8 + .long 0x6f380410 // ushr v16.4s, v0.4s, #8 + .long 0x6f300411 // ushr v17.4s, v0.4s, #16 + .long 0x4e211c03 // and v3.16b, v0.16b, v1.16b + .long 0x6f280400 // ushr v0.4s, v0.4s, #24 + .long 0x4e211e10 // and v16.16b, v16.16b, v1.16b + .long 0x4e211e21 // and v1.16b, v17.16b, v1.16b + .long 0x4e21d863 // scvtf v3.4s, v3.4s + .long 0x4e21d811 // scvtf v17.4s, v0.4s + .long 0x4e21da10 // scvtf v16.4s, v16.4s + .long 0x4e21d832 // scvtf v18.4s, v1.4s + .long 0x6e22dc60 // fmul v0.4s, v3.4s, v2.4s + .long 0x6e22de23 // fmul v3.4s, v17.4s, v2.4s + .long 0x6e22de01 // fmul v1.4s, v16.4s, v2.4s + .long 0x6e22de42 // fmul v2.4s, v18.4s, v2.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_gather_8888_aarch64 +.globl _sk_gather_8888_aarch64 +_sk_gather_8888_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x4ea1b821 // fcvtzs v1.4s, v1.4s + .long 0x4ea1b800 // fcvtzs v0.4s, v0.4s + .long 0x91004109 // add x9, x8, #0x10 + .long 0x4d40c922 // ld1r {v2.4s}, [x9] + .long 0xf9400108 // ldr x8, [x8] + .long 0x4ea19440 // mla v0.4s, v2.4s, v1.4s + .long 0x1e26000c // fmov w12, s0 + .long 0x8b2c490c // add x12, x8, w12, uxtw #2 + .long 0x0e0c3c09 // mov w9, v0.s[1] + .long 0x0e143c0a // mov w10, v0.s[2] + .long 0x0e1c3c0b // mov w11, v0.s[3] + .long 0x0d408180 // ld1 {v0.s}[0], [x12] + .long 0x8b294909 // add x9, x8, w9, uxtw #2 + .long 0xb86a590a // ldr w10, [x8, w10, uxtw #2] + .long 0xb86b5908 // ldr w8, [x8, w11, uxtw #2] + .long 0x0d409120 // ld1 {v0.s}[1], [x9] + .long 0x6f00e621 // movi v1.2d, #0xff000000ff + .long 0x52a77009 // mov w9, #0x3b800000 + .long 0x72901029 // movk w9, #0x8081 + .long 0x4e141d40 // mov v0.s[2], w10 + .long 0x4e1c1d00 // mov v0.s[3], w8 + .long 0x6f380410 // ushr v16.4s, v0.4s, #8 + .long 0x6f300411 // ushr v17.4s, v0.4s, #16 + .long 0x4e211c03 // and v3.16b, v0.16b, v1.16b + .long 0x6f280400 // ushr v0.4s, v0.4s, #24 + .long 0x4e211e10 // and v16.16b, v16.16b, v1.16b + .long 0x4e211e21 // and v1.16b, v17.16b, v1.16b + .long 0x4e040d22 // dup v2.4s, w9 + .long 0x4e21d863 // scvtf v3.4s, v3.4s + .long 0x4e21d811 // scvtf v17.4s, v0.4s + .long 0x4e21da10 // scvtf v16.4s, v16.4s + .long 0x4e21d832 // scvtf v18.4s, v1.4s + .long 0x6e22dc60 // fmul v0.4s, v3.4s, v2.4s + .long 0x6e22de23 // fmul v3.4s, v17.4s, v2.4s + .long 0x6e22de01 // fmul v1.4s, v16.4s, v2.4s + .long 0x6e22de42 // fmul v2.4s, v18.4s, v2.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_store_8888_aarch64 +.globl _sk_store_8888_aarch64 +_sk_store_8888_aarch64: + .long 0x52a86fea // mov w10, #0x437f0000 + .long 0x4e040d50 // dup v16.4s, w10 + .long 0xf9400028 // ldr x8, [x1] + .long 0x6e30dc32 // fmul v18.4s, v1.4s, v16.4s + .long 0x6e30dc11 // fmul v17.4s, v0.4s, v16.4s + .long 0x6e21aa52 // fcvtnu v18.4s, v18.4s + .long 0x6e21aa31 // fcvtnu v17.4s, v17.4s + .long 0x4f285652 // shl v18.4s, v18.4s, #8 + .long 0x4eb11e51 // orr v17.16b, v18.16b, v17.16b + .long 0x6e30dc52 // fmul v18.4s, v2.4s, v16.4s + .long 0x6e30dc70 // fmul v16.4s, v3.4s, v16.4s + .long 0x6e21aa52 // fcvtnu v18.4s, v18.4s + .long 0xf9400108 // ldr x8, [x8] + .long 0x6e21aa10 // fcvtnu v16.4s, v16.4s + .long 0x4f305652 // shl v18.4s, v18.4s, #16 + .long 0x4eb21e31 // orr v17.16b, v17.16b, v18.16b + .long 0x4f385610 // shl v16.4s, v16.4s, #24 + .long 0xd37ef409 // lsl x9, x0, #2 + .long 0x4eb01e30 // orr v16.16b, v17.16b, v16.16b + .long 0x3ca96910 // str q16, [x8, x9] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_load_f16_aarch64 +.globl _sk_load_f16_aarch64 +_sk_load_f16_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xf9400108 // ldr x8, [x8] + .long 0x8b000d08 // add x8, x8, x0, lsl #3 + .long 0x0c400510 // ld4 {v16.4h-v19.4h}, [x8] + .long 0x0e217a00 // fcvtl v0.4s, v16.4h + .long 0x0e217a21 // fcvtl v1.4s, v17.4h + .long 0x0e217a42 // fcvtl v2.4s, v18.4h + .long 0x0e217a63 // fcvtl v3.4s, v19.4h + .long 0xd61f0060 // br x3 + +HIDDEN _sk_gather_f16_aarch64 +.globl _sk_gather_f16_aarch64 +_sk_gather_f16_aarch64: + .long 0xa9bf7bfd // stp x29, x30, [sp, #-16]! + .long 0xd100c3e9 // sub x9, sp, #0x30 + .long 0x910003fd // mov x29, sp + .long 0x927be93f // and sp, x9, #0xffffffffffffffe0 + .long 0xf9400028 // ldr x8, [x1] + .long 0x4ea1b821 // fcvtzs v1.4s, v1.4s + .long 0x4ea1b800 // fcvtzs v0.4s, v0.4s + .long 0x91004109 // add x9, x8, #0x10 + .long 0x4d40c922 // ld1r {v2.4s}, [x9] + .long 0xf9400108 // ldr x8, [x8] + .long 0x4ea19440 // mla v0.4s, v2.4s, v1.4s + .long 0x0e143c0a // mov w10, v0.s[2] + .long 0x1e26000c // fmov w12, s0 + .long 0x8b2c4d0c // add x12, x8, w12, uxtw #3 + .long 0x8b2a4d0a // add x10, x8, w10, uxtw #3 + .long 0x0e0c3c09 // mov w9, v0.s[1] + .long 0x0e1c3c0b // mov w11, v0.s[3] + .long 0x0d408540 // ld1 {v0.d}[0], [x10] + .long 0x0d408581 // ld1 {v1.d}[0], [x12] + .long 0x8b294d09 // add x9, x8, w9, uxtw #3 + .long 0x8b2b4d08 // add x8, x8, w11, uxtw #3 + .long 0x4d408500 // ld1 {v0.d}[1], [x8] + .long 0x4d408521 // ld1 {v1.d}[1], [x9] + .long 0x910003e8 // mov x8, sp + .long 0xad0003e1 // stp q1, q0, [sp] + .long 0x0c400510 // ld4 {v16.4h-v19.4h}, [x8] + .long 0xf9400428 // ldr x8, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0x0e217a00 // fcvtl v0.4s, v16.4h + .long 0x0e217a21 // fcvtl v1.4s, v17.4h + .long 0x0e217a42 // fcvtl v2.4s, v18.4h + .long 0x0e217a63 // fcvtl v3.4s, v19.4h + .long 0xd63f0100 // blr x8 + .long 0x910003bf // mov sp, x29 + .long 0xa8c17bfd // ldp x29, x30, [sp], #16 + .long 0xd65f03c0 // ret + +HIDDEN _sk_store_f16_aarch64 +.globl _sk_store_f16_aarch64 +_sk_store_f16_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x0e216810 // fcvtn v16.4h, v0.4s + .long 0x0e216831 // fcvtn v17.4h, v1.4s + .long 0x0e216852 // fcvtn v18.4h, v2.4s + .long 0xf9400108 // ldr x8, [x8] + .long 0x0e216873 // fcvtn v19.4h, v3.4s + .long 0x8b000d08 // add x8, x8, x0, lsl #3 + .long 0x0c000510 // st4 {v16.4h-v19.4h}, [x8] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_load_u16_be_aarch64 +.globl _sk_load_u16_be_aarch64 +_sk_load_u16_be_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xf9400108 // ldr x8, [x8] + .long 0x8b000d08 // add x8, x8, x0, lsl #3 + .long 0x0c400500 // ld4 {v0.4h-v3.4h}, [x8] + .long 0x52a6f008 // mov w8, #0x37800000 + .long 0x72801008 // movk w8, #0x80 + .long 0x0f185410 // shl v16.4h, v0.4h, #8 + .long 0x2f180411 // ushr v17.4h, v0.4h, #8 + .long 0x0f185432 // shl v18.4h, v1.4h, #8 + .long 0x2f180433 // ushr v19.4h, v1.4h, #8 + .long 0x0f185454 // shl v20.4h, v2.4h, #8 + .long 0x2f180455 // ushr v21.4h, v2.4h, #8 + .long 0x0f185476 // shl v22.4h, v3.4h, #8 + .long 0x2f180460 // ushr v0.4h, v3.4h, #8 + .long 0x0eb11e01 // orr v1.8b, v16.8b, v17.8b + .long 0x0eb31e42 // orr v2.8b, v18.8b, v19.8b + .long 0x0eb51e90 // orr v16.8b, v20.8b, v21.8b + .long 0x0ea01ec0 // orr v0.8b, v22.8b, v0.8b + .long 0x2f10a421 // uxtl v1.4s, v1.4h + .long 0x2f10a442 // uxtl v2.4s, v2.4h + .long 0x2f10a610 // uxtl v16.4s, v16.4h + .long 0x2f10a400 // uxtl v0.4s, v0.4h + .long 0x4e040d03 // dup v3.4s, w8 + .long 0x6e21d821 // ucvtf v1.4s, v1.4s + .long 0x6e21d842 // ucvtf v2.4s, v2.4s + .long 0x6e21da10 // ucvtf v16.4s, v16.4s + .long 0x6e21d811 // ucvtf v17.4s, v0.4s + .long 0x6e23dc20 // fmul v0.4s, v1.4s, v3.4s + .long 0x6e23dc41 // fmul v1.4s, v2.4s, v3.4s + .long 0x6e23de02 // fmul v2.4s, v16.4s, v3.4s + .long 0x6e23de23 // fmul v3.4s, v17.4s, v3.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_store_u16_be_aarch64 +.globl _sk_store_u16_be_aarch64 +_sk_store_u16_be_aarch64: + .long 0x52a8efe9 // mov w9, #0x477f0000 + .long 0x729fe009 // movk w9, #0xff00 + .long 0x4e040d30 // dup v16.4s, w9 + .long 0x6e30dc11 // fmul v17.4s, v0.4s, v16.4s + .long 0xf9400028 // ldr x8, [x1] + .long 0x6e21aa31 // fcvtnu v17.4s, v17.4s + .long 0x0e612a31 // xtn v17.4h, v17.4s + .long 0x6e30dc32 // fmul v18.4s, v1.4s, v16.4s + .long 0x0f185633 // shl v19.4h, v17.4h, #8 + .long 0x2f180631 // ushr v17.4h, v17.4h, #8 + .long 0x6e21aa52 // fcvtnu v18.4s, v18.4s + .long 0x0eb11e75 // orr v21.8b, v19.8b, v17.8b + .long 0x6e30dc51 // fmul v17.4s, v2.4s, v16.4s + .long 0x0e612a52 // xtn v18.4h, v18.4s + .long 0x6e30dc70 // fmul v16.4s, v3.4s, v16.4s + .long 0x6e21aa31 // fcvtnu v17.4s, v17.4s + .long 0xf9400108 // ldr x8, [x8] + .long 0x0f185654 // shl v20.4h, v18.4h, #8 + .long 0x2f180652 // ushr v18.4h, v18.4h, #8 + .long 0x6e21aa10 // fcvtnu v16.4s, v16.4s + .long 0x0e612a31 // xtn v17.4h, v17.4s + .long 0x0eb21e96 // orr v22.8b, v20.8b, v18.8b + .long 0x0e612a10 // xtn v16.4h, v16.4s + .long 0x0f185632 // shl v18.4h, v17.4h, #8 + .long 0x2f180631 // ushr v17.4h, v17.4h, #8 + .long 0x0eb11e57 // orr v23.8b, v18.8b, v17.8b + .long 0x0f185611 // shl v17.4h, v16.4h, #8 + .long 0x2f180610 // ushr v16.4h, v16.4h, #8 + .long 0x8b000d08 // add x8, x8, x0, lsl #3 + .long 0x0eb01e38 // orr v24.8b, v17.8b, v16.8b + .long 0x0c000515 // st4 {v21.4h-v24.4h}, [x8] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_load_f32_aarch64 +.globl _sk_load_f32_aarch64 +_sk_load_f32_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xf9400108 // ldr x8, [x8] + .long 0x8b001108 // add x8, x8, x0, lsl #4 + .long 0x4c400900 // ld4 {v0.4s-v3.4s}, [x8] + .long 0xd61f0060 // br x3 + +HIDDEN _sk_store_f32_aarch64 +.globl _sk_store_f32_aarch64 +_sk_store_f32_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0xf9400108 // ldr x8, [x8] + .long 0x8b001108 // add x8, x8, x0, lsl #4 + .long 0x4c000900 // st4 {v0.4s-v3.4s}, [x8] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_clamp_x_aarch64 +.globl _sk_clamp_x_aarch64 +_sk_clamp_x_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x6f00e411 // movi v17.2d, #0x0 + .long 0x4e20f620 // fmax v0.4s, v17.4s, v0.4s + .long 0x6f07e7f1 // movi v17.2d, #0xffffffffffffffff + .long 0x4d40c910 // ld1r {v16.4s}, [x8] + .long 0x4eb18610 // add v16.4s, v16.4s, v17.4s + .long 0x4eb0f400 // fmin v0.4s, v0.4s, v16.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_clamp_y_aarch64 +.globl _sk_clamp_y_aarch64 +_sk_clamp_y_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x6f00e411 // movi v17.2d, #0x0 + .long 0x4e21f621 // fmax v1.4s, v17.4s, v1.4s + .long 0x6f07e7f1 // movi v17.2d, #0xffffffffffffffff + .long 0x4d40c910 // ld1r {v16.4s}, [x8] + .long 0x4eb18610 // add v16.4s, v16.4s, v17.4s + .long 0x4eb0f421 // fmin v1.4s, v1.4s, v16.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_repeat_x_aarch64 +.globl _sk_repeat_x_aarch64 +_sk_repeat_x_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x6f07e7f1 // movi v17.2d, #0xffffffffffffffff + .long 0xbd400110 // ldr s16, [x8] + .long 0x4e040612 // dup v18.4s, v16.s[0] + .long 0x4eb18651 // add v17.4s, v18.4s, v17.4s + .long 0x6e32fc12 // fdiv v18.4s, v0.4s, v18.4s + .long 0x4e219a52 // frintm v18.4s, v18.4s + .long 0x4f905240 // fmls v0.4s, v18.4s, v16.s[0] + .long 0x4eb1f400 // fmin v0.4s, v0.4s, v17.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_repeat_y_aarch64 +.globl _sk_repeat_y_aarch64 +_sk_repeat_y_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x6f07e7f1 // movi v17.2d, #0xffffffffffffffff + .long 0xbd400110 // ldr s16, [x8] + .long 0x4e040612 // dup v18.4s, v16.s[0] + .long 0x4eb18651 // add v17.4s, v18.4s, v17.4s + .long 0x6e32fc32 // fdiv v18.4s, v1.4s, v18.4s + .long 0x4e219a52 // frintm v18.4s, v18.4s + .long 0x4f905241 // fmls v1.4s, v18.4s, v16.s[0] + .long 0x4eb1f421 // fmin v1.4s, v1.4s, v17.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_mirror_x_aarch64 +.globl _sk_mirror_x_aarch64 +_sk_mirror_x_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xbd400110 // ldr s16, [x8] + .long 0x4e040611 // dup v17.4s, v16.s[0] + .long 0x1e302a10 // fadd s16, s16, s16 + .long 0x4eb1d400 // fsub v0.4s, v0.4s, v17.4s + .long 0x4e040612 // dup v18.4s, v16.s[0] + .long 0x6e32fc12 // fdiv v18.4s, v0.4s, v18.4s + .long 0x4e219a52 // frintm v18.4s, v18.4s + .long 0x4f905240 // fmls v0.4s, v18.4s, v16.s[0] + .long 0x6f07e7f0 // movi v16.2d, #0xffffffffffffffff + .long 0x4eb1d400 // fsub v0.4s, v0.4s, v17.4s + .long 0x4eb08630 // add v16.4s, v17.4s, v16.4s + .long 0x4ea0f800 // fabs v0.4s, v0.4s + .long 0x4eb0f400 // fmin v0.4s, v0.4s, v16.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_mirror_y_aarch64 +.globl _sk_mirror_y_aarch64 +_sk_mirror_y_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xbd400110 // ldr s16, [x8] + .long 0x4e040611 // dup v17.4s, v16.s[0] + .long 0x1e302a10 // fadd s16, s16, s16 + .long 0x4eb1d421 // fsub v1.4s, v1.4s, v17.4s + .long 0x4e040612 // dup v18.4s, v16.s[0] + .long 0x6e32fc32 // fdiv v18.4s, v1.4s, v18.4s + .long 0x4e219a52 // frintm v18.4s, v18.4s + .long 0x4f905241 // fmls v1.4s, v18.4s, v16.s[0] + .long 0x6f07e7f0 // movi v16.2d, #0xffffffffffffffff + .long 0x4eb1d421 // fsub v1.4s, v1.4s, v17.4s + .long 0x4eb08630 // add v16.4s, v17.4s, v16.4s + .long 0x4ea0f821 // fabs v1.4s, v1.4s + .long 0x4eb0f421 // fmin v1.4s, v1.4s, v16.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_luminance_to_alpha_aarch64 +.globl _sk_luminance_to_alpha_aarch64 +_sk_luminance_to_alpha_aarch64: + .long 0x52a7cb28 // mov w8, #0x3e590000 + .long 0x72967a08 // movk w8, #0xb3d0 + .long 0x4e040d11 // dup v17.4s, w8 + .long 0x52a7e6e8 // mov w8, #0x3f370000 + .long 0x7282eb28 // movk w8, #0x1759 + .long 0x4ea01c10 // mov v16.16b, v0.16b + .long 0x4e040d00 // dup v0.4s, w8 + .long 0x52a7b268 // mov w8, #0x3d930000 + .long 0xf8408423 // ldr x3, [x1], #8 + .long 0x729bb308 // movk w8, #0xdd98 + .long 0x6e20dc23 // fmul v3.4s, v1.4s, v0.4s + .long 0x4e30ce23 // fmla v3.4s, v17.4s, v16.4s + .long 0x4e040d10 // dup v16.4s, w8 + .long 0x6f00e400 // movi v0.2d, #0x0 + .long 0x6f00e401 // movi v1.2d, #0x0 + .long 0x4e22ce03 // fmla v3.4s, v16.4s, v2.4s + .long 0x6f00e402 // movi v2.2d, #0x0 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_matrix_2x3_aarch64 +.globl _sk_matrix_2x3_aarch64 +_sk_matrix_2x3_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xaa0803e9 // mov x9, x8 + .long 0x9100410a // add x10, x8, #0x10 + .long 0x4ddfc932 // ld1r {v18.4s}, [x9], #4 + .long 0x4d40c950 // ld1r {v16.4s}, [x10] + .long 0x2d415113 // ldp s19, s20, [x8, #8] + .long 0x9100510a // add x10, x8, #0x14 + .long 0x4d40c951 // ld1r {v17.4s}, [x10] + .long 0x4f931030 // fmla v16.4s, v1.4s, v19.s[0] + .long 0xbd400133 // ldr s19, [x9] + .long 0x4f941031 // fmla v17.4s, v1.4s, v20.s[0] + .long 0x4e20ce50 // fmla v16.4s, v18.4s, v0.4s + .long 0x4f931011 // fmla v17.4s, v0.4s, v19.s[0] + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0x4eb11e21 // mov v1.16b, v17.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_matrix_3x4_aarch64 +.globl _sk_matrix_3x4_aarch64 +_sk_matrix_3x4_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xaa0803e9 // mov x9, x8 + .long 0x9100910a // add x10, x8, #0x24 + .long 0x4ddfc933 // ld1r {v19.4s}, [x9], #4 + .long 0x4d40c950 // ld1r {v16.4s}, [x10] + .long 0x9100a10a // add x10, x8, #0x28 + .long 0x4d40c951 // ld1r {v17.4s}, [x10] + .long 0x9100b10a // add x10, x8, #0x2c + .long 0x2d435514 // ldp s20, s21, [x8, #24] + .long 0xbd402116 // ldr s22, [x8, #32] + .long 0x4d40c952 // ld1r {v18.4s}, [x10] + .long 0x4f941050 // fmla v16.4s, v2.4s, v20.s[0] + .long 0x4f951051 // fmla v17.4s, v2.4s, v21.s[0] + .long 0x4f961052 // fmla v18.4s, v2.4s, v22.s[0] + .long 0x2d425502 // ldp s2, s21, [x8, #16] + .long 0x2d415d14 // ldp s20, s23, [x8, #8] + .long 0x4f821031 // fmla v17.4s, v1.4s, v2.s[0] + .long 0xbd400122 // ldr s2, [x9] + .long 0x4f971030 // fmla v16.4s, v1.4s, v23.s[0] + .long 0x4f951032 // fmla v18.4s, v1.4s, v21.s[0] + .long 0x4e20ce70 // fmla v16.4s, v19.4s, v0.4s + .long 0x4f941012 // fmla v18.4s, v0.4s, v20.s[0] + .long 0x4f821011 // fmla v17.4s, v0.4s, v2.s[0] + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0x4eb11e21 // mov v1.16b, v17.16b + .long 0x4eb21e42 // mov v2.16b, v18.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_matrix_4x5_aarch64 +.globl _sk_matrix_4x5_aarch64 +_sk_matrix_4x5_aarch64: + .long 0xf9400029 // ldr x9, [x1] + .long 0xaa0903e8 // mov x8, x9 + .long 0x9101012a // add x10, x9, #0x40 + .long 0x4ddfc914 // ld1r {v20.4s}, [x8], #4 + .long 0x4d40c950 // ld1r {v16.4s}, [x10] + .long 0x9101112a // add x10, x9, #0x44 + .long 0x4d40c951 // ld1r {v17.4s}, [x10] + .long 0x9101212a // add x10, x9, #0x48 + .long 0x4d40c952 // ld1r {v18.4s}, [x10] + .long 0x2d465533 // ldp s19, s21, [x9, #48] + .long 0x2d475d36 // ldp s22, s23, [x9, #56] + .long 0x9101312a // add x10, x9, #0x4c + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f931070 // fmla v16.4s, v3.4s, v19.s[0] + .long 0x4d40c953 // ld1r {v19.4s}, [x10] + .long 0x4f951071 // fmla v17.4s, v3.4s, v21.s[0] + .long 0x4f961072 // fmla v18.4s, v3.4s, v22.s[0] + .long 0x2d445935 // ldp s21, s22, [x9, #32] + .long 0x4f971073 // fmla v19.4s, v3.4s, v23.s[0] + .long 0x2d455d23 // ldp s3, s23, [x9, #40] + .long 0x91004021 // add x1, x1, #0x10 + .long 0x4f951050 // fmla v16.4s, v2.4s, v21.s[0] + .long 0x4f961051 // fmla v17.4s, v2.4s, v22.s[0] + .long 0x2d425935 // ldp s21, s22, [x9, #16] + .long 0x4f971053 // fmla v19.4s, v2.4s, v23.s[0] + .long 0x4f831052 // fmla v18.4s, v2.4s, v3.s[0] + .long 0x2d410d22 // ldp s2, s3, [x9, #8] + .long 0x4f951030 // fmla v16.4s, v1.4s, v21.s[0] + .long 0x2d435d35 // ldp s21, s23, [x9, #24] + .long 0x4f961031 // fmla v17.4s, v1.4s, v22.s[0] + .long 0xbd400116 // ldr s22, [x8] + .long 0x4e20ce90 // fmla v16.4s, v20.4s, v0.4s + .long 0x4f951032 // fmla v18.4s, v1.4s, v21.s[0] + .long 0x4f971033 // fmla v19.4s, v1.4s, v23.s[0] + .long 0x4f821012 // fmla v18.4s, v0.4s, v2.s[0] + .long 0x4f831013 // fmla v19.4s, v0.4s, v3.s[0] + .long 0x4f961011 // fmla v17.4s, v0.4s, v22.s[0] + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0x4eb11e21 // mov v1.16b, v17.16b + .long 0x4eb21e42 // mov v2.16b, v18.16b + .long 0x4eb31e63 // mov v3.16b, v19.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_matrix_perspective_aarch64 +.globl _sk_matrix_perspective_aarch64 +_sk_matrix_perspective_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xaa0803e9 // mov x9, x8 + .long 0x9100510a // add x10, x8, #0x14 + .long 0x4ddfc930 // ld1r {v16.4s}, [x9], #4 + .long 0x4d40c951 // ld1r {v17.4s}, [x10] + .long 0x9100810a // add x10, x8, #0x20 + .long 0x4d40c952 // ld1r {v18.4s}, [x10] + .long 0x2d41d113 // ldp s19, s20, [x8, #12] + .long 0x2d435915 // ldp s21, s22, [x8, #24] + .long 0x91002108 // add x8, x8, #0x8 + .long 0x4f941031 // fmla v17.4s, v1.4s, v20.s[0] + .long 0x4d40c914 // ld1r {v20.4s}, [x8] + .long 0x4f961032 // fmla v18.4s, v1.4s, v22.s[0] + .long 0xbd400136 // ldr s22, [x9] + .long 0x4f951012 // fmla v18.4s, v0.4s, v21.s[0] + .long 0x4f931011 // fmla v17.4s, v0.4s, v19.s[0] + .long 0x4f961034 // fmla v20.4s, v1.4s, v22.s[0] + .long 0x4ea1da41 // frecpe v1.4s, v18.4s + .long 0x4e21fe52 // frecps v18.4s, v18.4s, v1.4s + .long 0x6e32dc32 // fmul v18.4s, v1.4s, v18.4s + .long 0x4e20ce14 // fmla v20.4s, v16.4s, v0.4s + .long 0x6e32de21 // fmul v1.4s, v17.4s, v18.4s + .long 0x6e32de80 // fmul v0.4s, v20.4s, v18.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_linear_gradient_aarch64 +.globl _sk_linear_gradient_aarch64 +_sk_linear_gradient_aarch64: + .long 0xf9400029 // ldr x9, [x1] + .long 0x91004128 // add x8, x9, #0x10 + .long 0x9100512a // add x10, x9, #0x14 + .long 0x4d40c910 // ld1r {v16.4s}, [x8] + .long 0x91006128 // add x8, x9, #0x18 + .long 0x4d40c941 // ld1r {v1.4s}, [x10] + .long 0x9100712a // add x10, x9, #0x1c + .long 0x4d40c902 // ld1r {v2.4s}, [x8] + .long 0xf9400128 // ldr x8, [x9] + .long 0x4d40c943 // ld1r {v3.4s}, [x10] + .long 0xb40006c8 // cbz x8, 2348 + .long 0x6dbf23e9 // stp d9, d8, [sp, #-16]! + .long 0xf9400529 // ldr x9, [x9, #8] + .long 0x6f00e413 // movi v19.2d, #0x0 + .long 0x6f00e411 // movi v17.2d, #0x0 + .long 0x6f00e412 // movi v18.2d, #0x0 + .long 0x91004129 // add x9, x9, #0x10 + .long 0x6f00e414 // movi v20.2d, #0x0 + .long 0xd100412a // sub x10, x9, #0x10 + .long 0x4d40c955 // ld1r {v21.4s}, [x10] + .long 0xd100312b // sub x11, x9, #0xc + .long 0xd100212a // sub x10, x9, #0x8 + .long 0x4d40c976 // ld1r {v22.4s}, [x11] + .long 0xd100112b // sub x11, x9, #0x4 + .long 0x4d40c957 // ld1r {v23.4s}, [x10] + .long 0xaa0903ea // mov x10, x9 + .long 0x4d40c978 // ld1r {v24.4s}, [x11] + .long 0x4ddfc959 // ld1r {v25.4s}, [x10], #4 + .long 0x9100412b // add x11, x9, #0x10 + .long 0x4ea31c7b // mov v27.16b, v3.16b + .long 0x6ea0e6a3 // fcmgt v3.4s, v21.4s, v0.4s + .long 0x4d40c97a // ld1r {v26.4s}, [x11] + .long 0x4eb41e95 // mov v21.16b, v20.16b + .long 0x4ea31c74 // mov v20.16b, v3.16b + .long 0x9100212b // add x11, x9, #0x8 + .long 0x4eb31e69 // mov v9.16b, v19.16b + .long 0x4ea31c73 // mov v19.16b, v3.16b + .long 0x6e771eb4 // bsl v20.16b, v21.16b, v23.16b + .long 0x4d40c975 // ld1r {v21.4s}, [x11] + .long 0x9100312b // add x11, x9, #0xc + .long 0x6e761d33 // bsl v19.16b, v9.16b, v22.16b + .long 0x4d40c976 // ld1r {v22.4s}, [x11] + .long 0x4d40c957 // ld1r {v23.4s}, [x10] + .long 0x4eb21e5c // mov v28.16b, v18.16b + .long 0x4eb11e3d // mov v29.16b, v17.16b + .long 0x4eb01e1e // mov v30.16b, v16.16b + .long 0x4ea11c3f // mov v31.16b, v1.16b + .long 0x4ea21c48 // mov v8.16b, v2.16b + .long 0x4ea31c72 // mov v18.16b, v3.16b + .long 0x4ea31c71 // mov v17.16b, v3.16b + .long 0x4ea31c70 // mov v16.16b, v3.16b + .long 0x4ea31c61 // mov v1.16b, v3.16b + .long 0x4ea31c62 // mov v2.16b, v3.16b + .long 0x6e7a1f63 // bsl v3.16b, v27.16b, v26.16b + .long 0x6e781f92 // bsl v18.16b, v28.16b, v24.16b + .long 0x6e791fb1 // bsl v17.16b, v29.16b, v25.16b + .long 0x6e751fe1 // bsl v1.16b, v31.16b, v21.16b + .long 0x6e761d02 // bsl v2.16b, v8.16b, v22.16b + .long 0xd1000508 // sub x8, x8, #0x1 + .long 0x6e771fd0 // bsl v16.16b, v30.16b, v23.16b + .long 0x91009129 // add x9, x9, #0x24 + .long 0xb5fffaa8 // cbnz x8, 2290 + .long 0x6cc123e9 // ldp d9, d8, [sp], #16 + .long 0x14000005 // b 2358 + .long 0x6f00e414 // movi v20.2d, #0x0 + .long 0x6f00e412 // movi v18.2d, #0x0 + .long 0x6f00e411 // movi v17.2d, #0x0 + .long 0x6f00e413 // movi v19.2d, #0x0 + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4e20ce70 // fmla v16.4s, v19.4s, v0.4s + .long 0x4e20ce81 // fmla v1.4s, v20.4s, v0.4s + .long 0x4e20ce42 // fmla v2.4s, v18.4s, v0.4s + .long 0x4e20ce23 // fmla v3.4s, v17.4s, v0.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_linear_gradient_2stops_aarch64 +.globl _sk_linear_gradient_2stops_aarch64 +_sk_linear_gradient_2stops_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0xaa0803e9 // mov x9, x8 + .long 0x9100410a // add x10, x8, #0x10 + .long 0x4ddfc931 // ld1r {v17.4s}, [x9], #4 + .long 0x4d40c950 // ld1r {v16.4s}, [x10] + .long 0x9100510a // add x10, x8, #0x14 + .long 0x4d40c941 // ld1r {v1.4s}, [x10] + .long 0x9100610a // add x10, x8, #0x18 + .long 0x4d40c942 // ld1r {v2.4s}, [x10] + .long 0x9100710a // add x10, x8, #0x1c + .long 0x2d414d12 // ldp s18, s19, [x8, #8] + .long 0x4d40c943 // ld1r {v3.4s}, [x10] + .long 0x4e20ce30 // fmla v16.4s, v17.4s, v0.4s + .long 0xbd400131 // ldr s17, [x9] + .long 0x4f921002 // fmla v2.4s, v0.4s, v18.s[0] + .long 0x4f931003 // fmla v3.4s, v0.4s, v19.s[0] + .long 0x4f911001 // fmla v1.4s, v0.4s, v17.s[0] + .long 0x4eb01e00 // mov v0.16b, v16.16b + .long 0xd61f0060 // br x3 + +HIDDEN _sk_save_xy_aarch64 +.globl _sk_save_xy_aarch64 +_sk_save_xy_aarch64: + .long 0x4f0167f0 // movi v16.4s, #0x3f, lsl #24 + .long 0xf9400028 // ldr x8, [x1] + .long 0x4e30d411 // fadd v17.4s, v0.4s, v16.4s + .long 0x4e30d430 // fadd v16.4s, v1.4s, v16.4s + .long 0x4e219a32 // frintm v18.4s, v17.4s + .long 0x4eb2d631 // fsub v17.4s, v17.4s, v18.4s + .long 0x4e219a12 // frintm v18.4s, v16.4s + .long 0x4eb2d610 // fsub v16.4s, v16.4s, v18.4s + .long 0x3d800100 // str q0, [x8] + .long 0x3d800901 // str q1, [x8, #32] + .long 0x3d801111 // str q17, [x8, #64] + .long 0x3d801910 // str q16, [x8, #96] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_accumulate_aarch64 +.globl _sk_accumulate_aarch64 +_sk_accumulate_aarch64: + .long 0xa8c10c28 // ldp x8, x3, [x1], #16 + .long 0x3dc02110 // ldr q16, [x8, #128] + .long 0x3dc02911 // ldr q17, [x8, #160] + .long 0x6e31de10 // fmul v16.4s, v16.4s, v17.4s + .long 0x4e30cc04 // fmla v4.4s, v0.4s, v16.4s + .long 0x4e30cc25 // fmla v5.4s, v1.4s, v16.4s + .long 0x4e30cc46 // fmla v6.4s, v2.4s, v16.4s + .long 0x4e30cc67 // fmla v7.4s, v3.4s, v16.4s + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bilinear_nx_aarch64 +.globl _sk_bilinear_nx_aarch64 +_sk_bilinear_nx_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x4f03f611 // fmov v17.4s, #1.000000000000000000e+00 + .long 0x3dc01100 // ldr q0, [x8, #64] + .long 0x3dc00110 // ldr q16, [x8] + .long 0x4ea0d620 // fsub v0.4s, v17.4s, v0.4s + .long 0x3d802100 // str q0, [x8, #128] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f0567e0 // movi v0.4s, #0xbf, lsl #24 + .long 0x4e20d600 // fadd v0.4s, v16.4s, v0.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bilinear_px_aarch64 +.globl _sk_bilinear_px_aarch64 +_sk_bilinear_px_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x3dc01100 // ldr q0, [x8, #64] + .long 0x3dc00110 // ldr q16, [x8] + .long 0x3d802100 // str q0, [x8, #128] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f0167e0 // movi v0.4s, #0x3f, lsl #24 + .long 0x4e20d600 // fadd v0.4s, v16.4s, v0.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bilinear_ny_aarch64 +.globl _sk_bilinear_ny_aarch64 +_sk_bilinear_ny_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x4f03f611 // fmov v17.4s, #1.000000000000000000e+00 + .long 0x3dc01901 // ldr q1, [x8, #96] + .long 0x3dc00910 // ldr q16, [x8, #32] + .long 0x4ea1d621 // fsub v1.4s, v17.4s, v1.4s + .long 0x3d802901 // str q1, [x8, #160] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f0567e1 // movi v1.4s, #0xbf, lsl #24 + .long 0x4e21d601 // fadd v1.4s, v16.4s, v1.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bilinear_py_aarch64 +.globl _sk_bilinear_py_aarch64 +_sk_bilinear_py_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x3dc01901 // ldr q1, [x8, #96] + .long 0x3dc00910 // ldr q16, [x8, #32] + .long 0x3d802901 // str q1, [x8, #160] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f0167e1 // movi v1.4s, #0x3f, lsl #24 + .long 0x4e21d601 // fadd v1.4s, v16.4s, v1.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bicubic_n3x_aarch64 +.globl _sk_bicubic_n3x_aarch64 +_sk_bicubic_n3x_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x52a7d8e9 // mov w9, #0x3ec70000 + .long 0x72838e49 // movk w9, #0x1c72 + .long 0x4e040d30 // dup v16.4s, w9 + .long 0x3dc01111 // ldr q17, [x8, #64] + .long 0x52b7d549 // mov w9, #0xbeaa0000 + .long 0x4f03f600 // fmov v0.4s, #1.000000000000000000e+00 + .long 0x72955569 // movk w9, #0xaaab + .long 0x4e040d32 // dup v18.4s, w9 + .long 0x4eb1d400 // fsub v0.4s, v0.4s, v17.4s + .long 0x6e20dc11 // fmul v17.4s, v0.4s, v0.4s + .long 0x4e20ce12 // fmla v18.4s, v16.4s, v0.4s + .long 0x6e32de20 // fmul v0.4s, v17.4s, v18.4s + .long 0x3dc00113 // ldr q19, [x8] + .long 0x3d802100 // str q0, [x8, #128] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f07f700 // fmov v0.4s, #-1.500000000000000000e+00 + .long 0x4e20d660 // fadd v0.4s, v19.4s, v0.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bicubic_n1x_aarch64 +.globl _sk_bicubic_n1x_aarch64 +_sk_bicubic_n1x_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x52b7f2a9 // mov w9, #0xbf950000 + .long 0x4f03f600 // fmov v0.4s, #1.000000000000000000e+00 + .long 0x728aaaa9 // movk w9, #0x5555 + .long 0x3dc01110 // ldr q16, [x8, #64] + .long 0x4f03f711 // fmov v17.4s, #1.500000000000000000e+00 + .long 0x4f0167f2 // movi v18.4s, #0x3f, lsl #24 + .long 0x4eb0d400 // fsub v0.4s, v0.4s, v16.4s + .long 0x4e040d30 // dup v16.4s, w9 + .long 0x52a7ac69 // mov w9, #0x3d630000 + .long 0x7291c729 // movk w9, #0x8e39 + .long 0x4e20ce11 // fmla v17.4s, v16.4s, v0.4s + .long 0x4e20ce32 // fmla v18.4s, v17.4s, v0.4s + .long 0x4e040d31 // dup v17.4s, w9 + .long 0x4e20ce51 // fmla v17.4s, v18.4s, v0.4s + .long 0x3dc00110 // ldr q16, [x8] + .long 0x3d802111 // str q17, [x8, #128] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f0567e0 // movi v0.4s, #0xbf, lsl #24 + .long 0x4e20d600 // fadd v0.4s, v16.4s, v0.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bicubic_p1x_aarch64 +.globl _sk_bicubic_p1x_aarch64 +_sk_bicubic_p1x_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x52b7f2a9 // mov w9, #0xbf950000 + .long 0x728aaaa9 // movk w9, #0x5555 + .long 0x4f03f711 // fmov v17.4s, #1.500000000000000000e+00 + .long 0x3dc01112 // ldr q18, [x8, #64] + .long 0x3dc00100 // ldr q0, [x8] + .long 0x4e040d33 // dup v19.4s, w9 + .long 0x52a7ac69 // mov w9, #0x3d630000 + .long 0x4f0167f0 // movi v16.4s, #0x3f, lsl #24 + .long 0x7291c729 // movk w9, #0x8e39 + .long 0x4e32ce71 // fmla v17.4s, v19.4s, v18.4s + .long 0x4e30d400 // fadd v0.4s, v0.4s, v16.4s + .long 0x4e32ce30 // fmla v16.4s, v17.4s, v18.4s + .long 0x4e040d31 // dup v17.4s, w9 + .long 0x4e32ce11 // fmla v17.4s, v16.4s, v18.4s + .long 0x3d802111 // str q17, [x8, #128] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bicubic_p3x_aarch64 +.globl _sk_bicubic_p3x_aarch64 +_sk_bicubic_p3x_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x52a7d8e9 // mov w9, #0x3ec70000 + .long 0x72838e49 // movk w9, #0x1c72 + .long 0x4e040d20 // dup v0.4s, w9 + .long 0x3dc01110 // ldr q16, [x8, #64] + .long 0x52b7d549 // mov w9, #0xbeaa0000 + .long 0x72955569 // movk w9, #0xaaab + .long 0x4e040d31 // dup v17.4s, w9 + .long 0x6e30de13 // fmul v19.4s, v16.4s, v16.4s + .long 0x4e30cc11 // fmla v17.4s, v0.4s, v16.4s + .long 0x6e31de60 // fmul v0.4s, v19.4s, v17.4s + .long 0x3dc00112 // ldr q18, [x8] + .long 0x3d802100 // str q0, [x8, #128] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f03f700 // fmov v0.4s, #1.500000000000000000e+00 + .long 0x4e20d640 // fadd v0.4s, v18.4s, v0.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bicubic_n3y_aarch64 +.globl _sk_bicubic_n3y_aarch64 +_sk_bicubic_n3y_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x52a7d8e9 // mov w9, #0x3ec70000 + .long 0x72838e49 // movk w9, #0x1c72 + .long 0x4e040d30 // dup v16.4s, w9 + .long 0x3dc01911 // ldr q17, [x8, #96] + .long 0x52b7d549 // mov w9, #0xbeaa0000 + .long 0x4f03f601 // fmov v1.4s, #1.000000000000000000e+00 + .long 0x72955569 // movk w9, #0xaaab + .long 0x4e040d32 // dup v18.4s, w9 + .long 0x4eb1d421 // fsub v1.4s, v1.4s, v17.4s + .long 0x6e21dc31 // fmul v17.4s, v1.4s, v1.4s + .long 0x4e21ce12 // fmla v18.4s, v16.4s, v1.4s + .long 0x6e32de21 // fmul v1.4s, v17.4s, v18.4s + .long 0x3dc00913 // ldr q19, [x8, #32] + .long 0x3d802901 // str q1, [x8, #160] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f07f701 // fmov v1.4s, #-1.500000000000000000e+00 + .long 0x4e21d661 // fadd v1.4s, v19.4s, v1.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bicubic_n1y_aarch64 +.globl _sk_bicubic_n1y_aarch64 +_sk_bicubic_n1y_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x52b7f2a9 // mov w9, #0xbf950000 + .long 0x4f03f601 // fmov v1.4s, #1.000000000000000000e+00 + .long 0x728aaaa9 // movk w9, #0x5555 + .long 0x3dc01910 // ldr q16, [x8, #96] + .long 0x4f03f711 // fmov v17.4s, #1.500000000000000000e+00 + .long 0x4f0167f2 // movi v18.4s, #0x3f, lsl #24 + .long 0x4eb0d421 // fsub v1.4s, v1.4s, v16.4s + .long 0x4e040d30 // dup v16.4s, w9 + .long 0x52a7ac69 // mov w9, #0x3d630000 + .long 0x7291c729 // movk w9, #0x8e39 + .long 0x4e21ce11 // fmla v17.4s, v16.4s, v1.4s + .long 0x4e21ce32 // fmla v18.4s, v17.4s, v1.4s + .long 0x4e040d31 // dup v17.4s, w9 + .long 0x4e21ce51 // fmla v17.4s, v18.4s, v1.4s + .long 0x3dc00910 // ldr q16, [x8, #32] + .long 0x3d802911 // str q17, [x8, #160] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f0567e1 // movi v1.4s, #0xbf, lsl #24 + .long 0x4e21d601 // fadd v1.4s, v16.4s, v1.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bicubic_p1y_aarch64 +.globl _sk_bicubic_p1y_aarch64 +_sk_bicubic_p1y_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x52b7f2a9 // mov w9, #0xbf950000 + .long 0x728aaaa9 // movk w9, #0x5555 + .long 0x4f03f711 // fmov v17.4s, #1.500000000000000000e+00 + .long 0x3dc01912 // ldr q18, [x8, #96] + .long 0x3dc00901 // ldr q1, [x8, #32] + .long 0x4e040d33 // dup v19.4s, w9 + .long 0x52a7ac69 // mov w9, #0x3d630000 + .long 0x4f0167f0 // movi v16.4s, #0x3f, lsl #24 + .long 0x7291c729 // movk w9, #0x8e39 + .long 0x4e32ce71 // fmla v17.4s, v19.4s, v18.4s + .long 0x4e30d421 // fadd v1.4s, v1.4s, v16.4s + .long 0x4e32ce30 // fmla v16.4s, v17.4s, v18.4s + .long 0x4e040d31 // dup v17.4s, w9 + .long 0x4e32ce11 // fmla v17.4s, v16.4s, v18.4s + .long 0x3d802911 // str q17, [x8, #160] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 + +HIDDEN _sk_bicubic_p3y_aarch64 +.globl _sk_bicubic_p3y_aarch64 +_sk_bicubic_p3y_aarch64: + .long 0xf9400028 // ldr x8, [x1] + .long 0x52a7d8e9 // mov w9, #0x3ec70000 + .long 0x72838e49 // movk w9, #0x1c72 + .long 0x4e040d21 // dup v1.4s, w9 + .long 0x3dc01910 // ldr q16, [x8, #96] + .long 0x52b7d549 // mov w9, #0xbeaa0000 + .long 0x72955569 // movk w9, #0xaaab + .long 0x4e040d31 // dup v17.4s, w9 + .long 0x6e30de13 // fmul v19.4s, v16.4s, v16.4s + .long 0x4e30cc31 // fmla v17.4s, v1.4s, v16.4s + .long 0x6e31de61 // fmul v1.4s, v19.4s, v17.4s + .long 0x3dc00912 // ldr q18, [x8, #32] + .long 0x3d802901 // str q1, [x8, #160] + .long 0xf9400423 // ldr x3, [x1, #8] + .long 0x4f03f701 // fmov v1.4s, #1.500000000000000000e+00 + .long 0x4e21d641 // fadd v1.4s, v18.4s, v1.4s + .long 0x91004021 // add x1, x1, #0x10 + .long 0xd61f0060 // br x3 +#elif defined(__arm__) +.balign 4 + +HIDDEN _sk_start_pipeline_vfp4 +.globl _sk_start_pipeline_vfp4 +_sk_start_pipeline_vfp4: + .long 0xe92d41f0 // push {r4, r5, r6, r7, r8, lr} + .long 0xe1a04000 // mov r4, r0 + .long 0xe2840002 // add r0, r4, #2 + .long 0xe1a05003 // mov r5, r3 + .long 0xe1a08002 // mov r8, r2 + .long 0xe1a07001 // mov r7, r1 + .long 0xe1500005 // cmp r0, r5 + .long 0x8a000010 // bhi 64 + .long 0xe4976004 // ldr r6, [r7], #4 + .long 0xf2800010 // vmov.i32 d0, #0 + .long 0xe1a00004 // mov r0, r4 + .long 0xf2801010 // vmov.i32 d1, #0 + .long 0xe1a01007 // mov r1, r7 + .long 0xf2802010 // vmov.i32 d2, #0 + .long 0xe1a02008 // mov r2, r8 + .long 0xf2803010 // vmov.i32 d3, #0 + .long 0xf2804010 // vmov.i32 d4, #0 + .long 0xf2805010 // vmov.i32 d5, #0 + .long 0xf2806010 // vmov.i32 d6, #0 + .long 0xf2807010 // vmov.i32 d7, #0 + .long 0xe12fff36 // blx r6 + .long 0xe2840004 // add r0, r4, #4 + .long 0xe2844002 // add r4, r4, #2 + .long 0xe1500005 // cmp r0, r5 + .long 0x9affffef // bls 24 + .long 0xe1a00004 // mov r0, r4 + .long 0xe8bd81f0 // pop {r4, r5, r6, r7, r8, pc} + +HIDDEN _sk_just_return_vfp4 +.globl _sk_just_return_vfp4 +_sk_just_return_vfp4: + .long 0xe12fff1e // bx lr + +HIDDEN _sk_seed_shader_vfp4 +.globl _sk_seed_shader_vfp4 +_sk_seed_shader_vfp4: + .long 0xee800b90 // vdup.32 d16, r0 + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf2c3161f // vmov.i32 d17, #1056964608 + .long 0xedd23b00 // vldr d19, [r2] + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf2872f10 // vmov.f32 d2, #1 + .long 0xf3fb2622 // vcvt.f32.s32 d18, d18 + .long 0xe2811008 // add r1, r1, #8 + .long 0xf2400da1 // vadd.f32 d16, d16, d17 + .long 0xf2803010 // vmov.i32 d3, #0 + .long 0xf2804010 // vmov.i32 d4, #0 + .long 0xf2021da1 // vadd.f32 d1, d18, d17 + .long 0xf2000da3 // vadd.f32 d0, d16, d19 + .long 0xf2805010 // vmov.i32 d5, #0 + .long 0xf2806010 // vmov.i32 d6, #0 + .long 0xf2807010 // vmov.i32 d7, #0 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_constant_color_vfp4 +.globl _sk_constant_color_vfp4 +_sk_constant_color_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xe283400c // add r4, r3, #12 + .long 0xe1a0e003 // mov lr, r3 + .long 0xe2833008 // add r3, r3, #8 + .long 0xf4ae0c9d // vld1.32 {d0[]}, [lr :32]! + .long 0xf4a43c9f // vld1.32 {d3[]}, [r4 :32] + .long 0xf4a32c9f // vld1.32 {d2[]}, [r3 :32] + .long 0xf4ae1c9f // vld1.32 {d1[]}, [lr :32] + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff1c // bx ip + +HIDDEN _sk_clear_vfp4 +.globl _sk_clear_vfp4 +_sk_clear_vfp4: + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2800010 // vmov.i32 d0, #0 + .long 0xf2801010 // vmov.i32 d1, #0 + .long 0xf2802010 // vmov.i32 d2, #0 + .long 0xf2803010 // vmov.i32 d3, #0 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_srcatop_vfp4 +.globl _sk_srcatop_vfp4 +_sk_srcatop_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2603d83 // vsub.f32 d19, d16, d3 + .long 0xf3033d17 // vmul.f32 d3, d3, d7 + .long 0xf3430d94 // vmul.f32 d16, d19, d4 + .long 0xf3431d95 // vmul.f32 d17, d19, d5 + .long 0xf3432d96 // vmul.f32 d18, d19, d6 + .long 0xf2400c17 // vfma.f32 d16, d0, d7 + .long 0xf2411c17 // vfma.f32 d17, d1, d7 + .long 0xf2422c17 // vfma.f32 d18, d2, d7 + .long 0xf2033c97 // vfma.f32 d3, d19, d7 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xf22221b2 // vorr d2, d18, d18 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_dstatop_vfp4 +.globl _sk_dstatop_vfp4 +_sk_dstatop_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3431d15 // vmul.f32 d17, d3, d5 + .long 0xf2604d87 // vsub.f32 d20, d16, d7 + .long 0xf3430d14 // vmul.f32 d16, d3, d4 + .long 0xf3432d16 // vmul.f32 d18, d3, d6 + .long 0xf3433d17 // vmul.f32 d19, d3, d7 + .long 0xf2440c90 // vfma.f32 d16, d20, d0 + .long 0xf2441c91 // vfma.f32 d17, d20, d1 + .long 0xf2442c92 // vfma.f32 d18, d20, d2 + .long 0xf2443c93 // vfma.f32 d19, d20, d3 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xf22221b2 // vorr d2, d18, d18 + .long 0xf22331b3 // vorr d3, d19, d19 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_srcin_vfp4 +.globl _sk_srcin_vfp4 +_sk_srcin_vfp4: + .long 0xf3000d17 // vmul.f32 d0, d0, d7 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3011d17 // vmul.f32 d1, d1, d7 + .long 0xf3022d17 // vmul.f32 d2, d2, d7 + .long 0xf3033d17 // vmul.f32 d3, d3, d7 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_dstin_vfp4 +.globl _sk_dstin_vfp4 +_sk_dstin_vfp4: + .long 0xf3030d14 // vmul.f32 d0, d3, d4 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3031d15 // vmul.f32 d1, d3, d5 + .long 0xf3032d16 // vmul.f32 d2, d3, d6 + .long 0xf3033d17 // vmul.f32 d3, d3, d7 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_srcout_vfp4 +.globl _sk_srcout_vfp4 +_sk_srcout_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2600d87 // vsub.f32 d16, d16, d7 + .long 0xf3000d90 // vmul.f32 d0, d16, d0 + .long 0xf3001d91 // vmul.f32 d1, d16, d1 + .long 0xf3002d92 // vmul.f32 d2, d16, d2 + .long 0xf3003d93 // vmul.f32 d3, d16, d3 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_dstout_vfp4 +.globl _sk_dstout_vfp4 +_sk_dstout_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2600d83 // vsub.f32 d16, d16, d3 + .long 0xf3000d94 // vmul.f32 d0, d16, d4 + .long 0xf3001d95 // vmul.f32 d1, d16, d5 + .long 0xf3002d96 // vmul.f32 d2, d16, d6 + .long 0xf3003d97 // vmul.f32 d3, d16, d7 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_srcover_vfp4 +.globl _sk_srcover_vfp4 +_sk_srcover_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2600d83 // vsub.f32 d16, d16, d3 + .long 0xf2040c30 // vfma.f32 d0, d4, d16 + .long 0xf2051c30 // vfma.f32 d1, d5, d16 + .long 0xf2062c30 // vfma.f32 d2, d6, d16 + .long 0xf2073c30 // vfma.f32 d3, d7, d16 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_dstover_vfp4 +.globl _sk_dstover_vfp4 +_sk_dstover_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2651115 // vorr d17, d5, d5 + .long 0xf2604d87 // vsub.f32 d20, d16, d7 + .long 0xf2640114 // vorr d16, d4, d4 + .long 0xf2662116 // vorr d18, d6, d6 + .long 0xf2673117 // vorr d19, d7, d7 + .long 0xf2400c34 // vfma.f32 d16, d0, d20 + .long 0xf2411c34 // vfma.f32 d17, d1, d20 + .long 0xf2422c34 // vfma.f32 d18, d2, d20 + .long 0xf2433c34 // vfma.f32 d19, d3, d20 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xf22221b2 // vorr d2, d18, d18 + .long 0xf22331b3 // vorr d3, d19, d19 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_modulate_vfp4 +.globl _sk_modulate_vfp4 +_sk_modulate_vfp4: + .long 0xf3000d14 // vmul.f32 d0, d0, d4 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3011d15 // vmul.f32 d1, d1, d5 + .long 0xf3022d16 // vmul.f32 d2, d2, d6 + .long 0xf3033d17 // vmul.f32 d3, d3, d7 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_multiply_vfp4 +.globl _sk_multiply_vfp4 +_sk_multiply_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2601d87 // vsub.f32 d17, d16, d7 + .long 0xf2600d83 // vsub.f32 d16, d16, d3 + .long 0xf3412d90 // vmul.f32 d18, d17, d0 + .long 0xf3403d94 // vmul.f32 d19, d16, d4 + .long 0xf3414d91 // vmul.f32 d20, d17, d1 + .long 0xf3405d95 // vmul.f32 d21, d16, d5 + .long 0xf3416d92 // vmul.f32 d22, d17, d2 + .long 0xf3418d93 // vmul.f32 d24, d17, d3 + .long 0xf3407d96 // vmul.f32 d23, d16, d6 + .long 0xf3409d97 // vmul.f32 d25, d16, d7 + .long 0xf2430da2 // vadd.f32 d16, d19, d18 + .long 0xf2451da4 // vadd.f32 d17, d21, d20 + .long 0xf2472da6 // vadd.f32 d18, d23, d22 + .long 0xf2493da8 // vadd.f32 d19, d25, d24 + .long 0xf2400c14 // vfma.f32 d16, d0, d4 + .long 0xf2411c15 // vfma.f32 d17, d1, d5 + .long 0xf2422c16 // vfma.f32 d18, d2, d6 + .long 0xf2433c17 // vfma.f32 d19, d3, d7 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xf22221b2 // vorr d2, d18, d18 + .long 0xf22331b3 // vorr d3, d19, d19 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_plus__vfp4 +.globl _sk_plus__vfp4 +_sk_plus__vfp4: + .long 0xf2000d04 // vadd.f32 d0, d0, d4 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2011d05 // vadd.f32 d1, d1, d5 + .long 0xf2022d06 // vadd.f32 d2, d2, d6 + .long 0xf2033d07 // vadd.f32 d3, d3, d7 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_screen_vfp4 +.globl _sk_screen_vfp4 +_sk_screen_vfp4: + .long 0xf2400d04 // vadd.f32 d16, d0, d4 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2411d05 // vadd.f32 d17, d1, d5 + .long 0xf2422d06 // vadd.f32 d18, d2, d6 + .long 0xf2433d07 // vadd.f32 d19, d3, d7 + .long 0xf2600c14 // vfms.f32 d16, d0, d4 + .long 0xf2611c15 // vfms.f32 d17, d1, d5 + .long 0xf2622c16 // vfms.f32 d18, d2, d6 + .long 0xf2633c17 // vfms.f32 d19, d3, d7 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xf22221b2 // vorr d2, d18, d18 + .long 0xf22331b3 // vorr d3, d19, d19 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_xor__vfp4 +.globl _sk_xor__vfp4 +_sk_xor__vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2603d83 // vsub.f32 d19, d16, d3 + .long 0xf2604d87 // vsub.f32 d20, d16, d7 + .long 0xf3430d94 // vmul.f32 d16, d19, d4 + .long 0xf3431d95 // vmul.f32 d17, d19, d5 + .long 0xf3432d96 // vmul.f32 d18, d19, d6 + .long 0xf3433d97 // vmul.f32 d19, d19, d7 + .long 0xf2440c90 // vfma.f32 d16, d20, d0 + .long 0xf2441c91 // vfma.f32 d17, d20, d1 + .long 0xf2442c92 // vfma.f32 d18, d20, d2 + .long 0xf2443c93 // vfma.f32 d19, d20, d3 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xf22221b2 // vorr d2, d18, d18 + .long 0xf22331b3 // vorr d3, d19, d19 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_darken_vfp4 +.globl _sk_darken_vfp4 +_sk_darken_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3431d14 // vmul.f32 d17, d3, d4 + .long 0xf3402d17 // vmul.f32 d18, d0, d7 + .long 0xf3433d15 // vmul.f32 d19, d3, d5 + .long 0xf3414d17 // vmul.f32 d20, d1, d7 + .long 0xf3435d16 // vmul.f32 d21, d3, d6 + .long 0xf2600d83 // vsub.f32 d16, d16, d3 + .long 0xf3426d17 // vmul.f32 d22, d2, d7 + .long 0xf2421fa1 // vmax.f32 d17, d18, d17 + .long 0xf2407d04 // vadd.f32 d23, d0, d4 + .long 0xf2443fa3 // vmax.f32 d19, d20, d19 + .long 0xf2412d05 // vadd.f32 d18, d1, d5 + .long 0xf2424d06 // vadd.f32 d20, d2, d6 + .long 0xf2465fa5 // vmax.f32 d21, d22, d21 + .long 0xf2073c30 // vfma.f32 d3, d7, d16 + .long 0xf2270da1 // vsub.f32 d0, d23, d17 + .long 0xf2221da3 // vsub.f32 d1, d18, d19 + .long 0xf2242da5 // vsub.f32 d2, d20, d21 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_lighten_vfp4 +.globl _sk_lighten_vfp4 +_sk_lighten_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3431d14 // vmul.f32 d17, d3, d4 + .long 0xf3402d17 // vmul.f32 d18, d0, d7 + .long 0xf3433d15 // vmul.f32 d19, d3, d5 + .long 0xf3414d17 // vmul.f32 d20, d1, d7 + .long 0xf3435d16 // vmul.f32 d21, d3, d6 + .long 0xf2600d83 // vsub.f32 d16, d16, d3 + .long 0xf3426d17 // vmul.f32 d22, d2, d7 + .long 0xf2621fa1 // vmin.f32 d17, d18, d17 + .long 0xf2407d04 // vadd.f32 d23, d0, d4 + .long 0xf2643fa3 // vmin.f32 d19, d20, d19 + .long 0xf2412d05 // vadd.f32 d18, d1, d5 + .long 0xf2424d06 // vadd.f32 d20, d2, d6 + .long 0xf2665fa5 // vmin.f32 d21, d22, d21 + .long 0xf2073c30 // vfma.f32 d3, d7, d16 + .long 0xf2270da1 // vsub.f32 d0, d23, d17 + .long 0xf2221da3 // vsub.f32 d1, d18, d19 + .long 0xf2242da5 // vsub.f32 d2, d20, d21 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_difference_vfp4 +.globl _sk_difference_vfp4 +_sk_difference_vfp4: + .long 0xf3430d14 // vmul.f32 d16, d3, d4 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3401d17 // vmul.f32 d17, d0, d7 + .long 0xf3432d15 // vmul.f32 d18, d3, d5 + .long 0xf3413d17 // vmul.f32 d19, d1, d7 + .long 0xf3434d16 // vmul.f32 d20, d3, d6 + .long 0xf3425d17 // vmul.f32 d21, d2, d7 + .long 0xf2c76f10 // vmov.f32 d22, #1 + .long 0xf2610fa0 // vmin.f32 d16, d17, d16 + .long 0xf2631fa2 // vmin.f32 d17, d19, d18 + .long 0xf2662d83 // vsub.f32 d18, d22, d3 + .long 0xf2653fa4 // vmin.f32 d19, d21, d20 + .long 0xf2404d04 // vadd.f32 d20, d0, d4 + .long 0xf2400da0 // vadd.f32 d16, d16, d16 + .long 0xf2073c32 // vfma.f32 d3, d7, d18 + .long 0xf2415d05 // vadd.f32 d21, d1, d5 + .long 0xf2411da1 // vadd.f32 d17, d17, d17 + .long 0xf2426d06 // vadd.f32 d22, d2, d6 + .long 0xf2432da3 // vadd.f32 d18, d19, d19 + .long 0xf2240da0 // vsub.f32 d0, d20, d16 + .long 0xf2251da1 // vsub.f32 d1, d21, d17 + .long 0xf2262da2 // vsub.f32 d2, d22, d18 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_exclusion_vfp4 +.globl _sk_exclusion_vfp4 +_sk_exclusion_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3401d14 // vmul.f32 d17, d0, d4 + .long 0xf3412d15 // vmul.f32 d18, d1, d5 + .long 0xf3423d16 // vmul.f32 d19, d2, d6 + .long 0xf2600d83 // vsub.f32 d16, d16, d3 + .long 0xf2404d04 // vadd.f32 d20, d0, d4 + .long 0xf2411da1 // vadd.f32 d17, d17, d17 + .long 0xf2415d05 // vadd.f32 d21, d1, d5 + .long 0xf2422da2 // vadd.f32 d18, d18, d18 + .long 0xf2426d06 // vadd.f32 d22, d2, d6 + .long 0xf2433da3 // vadd.f32 d19, d19, d19 + .long 0xf2073c30 // vfma.f32 d3, d7, d16 + .long 0xf2240da1 // vsub.f32 d0, d20, d17 + .long 0xf2251da2 // vsub.f32 d1, d21, d18 + .long 0xf2262da3 // vsub.f32 d2, d22, d19 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_colorburn_vfp4 +.globl _sk_colorburn_vfp4 +_sk_colorburn_vfp4: + .long 0xed2d8b08 // vpush {d8-d11} + .long 0xf2670d04 // vsub.f32 d16, d7, d4 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2671d06 // vsub.f32 d17, d7, d6 + .long 0xf2672d05 // vsub.f32 d18, d7, d5 + .long 0xf3008d93 // vmul.f32 d8, d16, d3 + .long 0xf3019d93 // vmul.f32 d9, d17, d3 + .long 0xf302ad93 // vmul.f32 d10, d18, d3 + .long 0xf2c71f10 // vmov.f32 d17, #1 + .long 0xeec8baa0 // vdiv.f32 s23, s17, s1 + .long 0xee88ba00 // vdiv.f32 s22, s16, s0 + .long 0xeec98aa2 // vdiv.f32 s17, s19, s5 + .long 0xee898a02 // vdiv.f32 s16, s18, s4 + .long 0xeeca9aa1 // vdiv.f32 s19, s21, s3 + .long 0xee8a9a01 // vdiv.f32 s18, s20, s2 + .long 0xf2672f08 // vmin.f32 d18, d7, d8 + .long 0xf2673f09 // vmin.f32 d19, d7, d9 + .long 0xf2670f0b // vmin.f32 d16, d7, d11 + .long 0xf2614d87 // vsub.f32 d20, d17, d7 + .long 0xf2672d22 // vsub.f32 d18, d7, d18 + .long 0xf2673d23 // vsub.f32 d19, d7, d19 + .long 0xf2611d83 // vsub.f32 d17, d17, d3 + .long 0xf2670d20 // vsub.f32 d16, d7, d16 + .long 0xf3445d90 // vmul.f32 d21, d20, d0 + .long 0xf3446d92 // vmul.f32 d22, d20, d2 + .long 0xf3422d93 // vmul.f32 d18, d18, d3 + .long 0xf3444d91 // vmul.f32 d20, d20, d1 + .long 0xf3433d93 // vmul.f32 d19, d19, d3 + .long 0xf3400d93 // vmul.f32 d16, d16, d3 + .long 0xf3417d95 // vmul.f32 d23, d17, d5 + .long 0xf3418d94 // vmul.f32 d24, d17, d4 + .long 0xf3419d96 // vmul.f32 d25, d17, d6 + .long 0xf2443da3 // vadd.f32 d19, d20, d19 + .long 0xf2462da2 // vadd.f32 d18, d22, d18 + .long 0xf245ada0 // vadd.f32 d26, d21, d16 + .long 0xf247bd81 // vadd.f32 d27, d23, d1 + .long 0xf248cd80 // vadd.f32 d28, d24, d0 + .long 0xf249dd82 // vadd.f32 d29, d25, d2 + .long 0xf2073c31 // vfma.f32 d3, d7, d17 + .long 0xf2499da2 // vadd.f32 d25, d25, d18 + .long 0xf2473da3 // vadd.f32 d19, d23, d19 + .long 0xf3f97501 // vceq.f32 d23, d1, #0 + .long 0xf2455d84 // vadd.f32 d21, d21, d4 + .long 0xf2444d85 // vadd.f32 d20, d20, d5 + .long 0xf2440e07 // vceq.f32 d16, d4, d7 + .long 0xf2466d86 // vadd.f32 d22, d22, d6 + .long 0xf2451e07 // vceq.f32 d17, d5, d7 + .long 0xf2462e07 // vceq.f32 d18, d6, d7 + .long 0xf35b71b3 // vbsl d23, d27, d19 + .long 0xf3f93500 // vceq.f32 d19, d0, #0 + .long 0xf2488daa // vadd.f32 d24, d24, d26 + .long 0xf35c31b8 // vbsl d19, d28, d24 + .long 0xf3f98502 // vceq.f32 d24, d2, #0 + .long 0xf35d81b9 // vbsl d24, d29, d25 + .long 0xf35501b3 // vbsl d16, d21, d19 + .long 0xf35411b7 // vbsl d17, d20, d23 + .long 0xf35621b8 // vbsl d18, d22, d24 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xf22221b2 // vorr d2, d18, d18 + .long 0xecbd8b08 // vpop {d8-d11} + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_colordodge_vfp4 +.globl _sk_colordodge_vfp4 +_sk_colordodge_vfp4: + .long 0xed2d8b0e // vpush {d8-d14} + .long 0xf2238d02 // vsub.f32 d8, d3, d2 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3039d16 // vmul.f32 d9, d3, d6 + .long 0xf223ad01 // vsub.f32 d10, d3, d1 + .long 0xf303bd15 // vmul.f32 d11, d3, d5 + .long 0xf223cd00 // vsub.f32 d12, d3, d0 + .long 0xf303dd14 // vmul.f32 d13, d3, d4 + .long 0xeec9eaa8 // vdiv.f32 s29, s19, s17 + .long 0xee89ea08 // vdiv.f32 s28, s18, s16 + .long 0xeecb8aaa // vdiv.f32 s17, s23, s21 + .long 0xeecd9aac // vdiv.f32 s19, s27, s25 + .long 0xee8b8a0a // vdiv.f32 s16, s22, s20 + .long 0xee8d9a0c // vdiv.f32 s18, s26, s24 + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xf2672f0e // vmin.f32 d18, d7, d14 + .long 0xf2601d87 // vsub.f32 d17, d16, d7 + .long 0xf2673f08 // vmin.f32 d19, d7, d8 + .long 0xf2674f09 // vmin.f32 d20, d7, d9 + .long 0xf2600d83 // vsub.f32 d16, d16, d3 + .long 0xf3415d92 // vmul.f32 d21, d17, d2 + .long 0xf3422d93 // vmul.f32 d18, d18, d3 + .long 0xf3416d91 // vmul.f32 d22, d17, d1 + .long 0xf3433d93 // vmul.f32 d19, d19, d3 + .long 0xf3411d90 // vmul.f32 d17, d17, d0 + .long 0xf3444d93 // vmul.f32 d20, d20, d3 + .long 0xf3407d95 // vmul.f32 d23, d16, d5 + .long 0xf3408d94 // vmul.f32 d24, d16, d4 + .long 0xf3409d96 // vmul.f32 d25, d16, d6 + .long 0xf2452da2 // vadd.f32 d18, d21, d18 + .long 0xf2463da3 // vadd.f32 d19, d22, d19 + .long 0xf2414da4 // vadd.f32 d20, d17, d20 + .long 0xf241ae03 // vceq.f32 d26, d1, d3 + .long 0xf247bd81 // vadd.f32 d27, d23, d1 + .long 0xf3b91505 // vceq.f32 d1, d5, #0 + .long 0xf240ce03 // vceq.f32 d28, d0, d3 + .long 0xf248dd80 // vadd.f32 d29, d24, d0 + .long 0xf3b90504 // vceq.f32 d0, d4, #0 + .long 0xf242ee03 // vceq.f32 d30, d2, d3 + .long 0xf249fd82 // vadd.f32 d31, d25, d2 + .long 0xf3b92506 // vceq.f32 d2, d6, #0 + .long 0xf2073c30 // vfma.f32 d3, d7, d16 + .long 0xf2410d84 // vadd.f32 d16, d17, d4 + .long 0xf2491da2 // vadd.f32 d17, d25, d18 + .long 0xf2462d85 // vadd.f32 d18, d22, d5 + .long 0xf2455d86 // vadd.f32 d21, d21, d6 + .long 0xf2473da3 // vadd.f32 d19, d23, d19 + .long 0xf2484da4 // vadd.f32 d20, d24, d20 + .long 0xf35fe1b1 // vbsl d30, d31, d17 + .long 0xf35ba1b3 // vbsl d26, d27, d19 + .long 0xf35dc1b4 // vbsl d28, d29, d20 + .long 0xf31001bc // vbsl d0, d16, d28 + .long 0xf31211ba // vbsl d1, d18, d26 + .long 0xf31521be // vbsl d2, d21, d30 + .long 0xecbd8b0e // vpop {d8-d14} + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_hardlight_vfp4 +.globl _sk_hardlight_vfp4 +_sk_hardlight_vfp4: + .long 0xf2c71f10 // vmov.f32 d17, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2670d04 // vsub.f32 d16, d7, d4 + .long 0xf2617d87 // vsub.f32 d23, d17, d7 + .long 0xf2611d83 // vsub.f32 d17, d17, d3 + .long 0xf2672d05 // vsub.f32 d18, d7, d5 + .long 0xf2674d06 // vsub.f32 d20, d7, d6 + .long 0xf2633d00 // vsub.f32 d19, d3, d0 + .long 0xf2635d01 // vsub.f32 d21, d3, d1 + .long 0xf2636d02 // vsub.f32 d22, d3, d2 + .long 0xf347bd90 // vmul.f32 d27, d23, d0 + .long 0xf341cd94 // vmul.f32 d28, d17, d4 + .long 0xf3430db0 // vmul.f32 d16, d19, d16 + .long 0xf3463db4 // vmul.f32 d19, d22, d20 + .long 0xf3452db2 // vmul.f32 d18, d21, d18 + .long 0xf2404d00 // vadd.f32 d20, d0, d0 + .long 0xf3405d14 // vmul.f32 d21, d0, d4 + .long 0xf2416d01 // vadd.f32 d22, d1, d1 + .long 0xf3418d15 // vmul.f32 d24, d1, d5 + .long 0xf2429d02 // vadd.f32 d25, d2, d2 + .long 0xf342ad16 // vmul.f32 d26, d2, d6 + .long 0xf347dd91 // vmul.f32 d29, d23, d1 + .long 0xf341fd95 // vmul.f32 d31, d17, d5 + .long 0xf24cbdab // vadd.f32 d27, d28, d27 + .long 0xf3477d92 // vmul.f32 d23, d23, d2 + .long 0xf341cd96 // vmul.f32 d28, d17, d6 + .long 0xf2400da0 // vadd.f32 d16, d16, d16 + .long 0xf343ed17 // vmul.f32 d30, d3, d7 + .long 0xf2422da2 // vadd.f32 d18, d18, d18 + .long 0xf2433da3 // vadd.f32 d19, d19, d19 + .long 0xf3434e24 // vcge.f32 d20, d3, d20 + .long 0xf2455da5 // vadd.f32 d21, d21, d21 + .long 0xf3436e26 // vcge.f32 d22, d3, d22 + .long 0xf3439e29 // vcge.f32 d25, d3, d25 + .long 0xf2488da8 // vadd.f32 d24, d24, d24 + .long 0xf24aadaa // vadd.f32 d26, d26, d26 + .long 0xf2073c31 // vfma.f32 d3, d7, d17 + .long 0xf24fddad // vadd.f32 d29, d31, d29 + .long 0xf24c1da7 // vadd.f32 d17, d28, d23 + .long 0xf26e0da0 // vsub.f32 d16, d30, d16 + .long 0xf26e2da2 // vsub.f32 d18, d30, d18 + .long 0xf26e3da3 // vsub.f32 d19, d30, d19 + .long 0xf35541b0 // vbsl d20, d21, d16 + .long 0xf35861b2 // vbsl d22, d24, d18 + .long 0xf35a91b3 // vbsl d25, d26, d19 + .long 0xf20b0da4 // vadd.f32 d0, d27, d20 + .long 0xf20d1da6 // vadd.f32 d1, d29, d22 + .long 0xf2012da9 // vadd.f32 d2, d17, d25 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_overlay_vfp4 +.globl _sk_overlay_vfp4 +_sk_overlay_vfp4: + .long 0xf2c71f10 // vmov.f32 d17, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2670d04 // vsub.f32 d16, d7, d4 + .long 0xf2617d87 // vsub.f32 d23, d17, d7 + .long 0xf2611d83 // vsub.f32 d17, d17, d3 + .long 0xf2672d05 // vsub.f32 d18, d7, d5 + .long 0xf2674d06 // vsub.f32 d20, d7, d6 + .long 0xf2633d00 // vsub.f32 d19, d3, d0 + .long 0xf2635d01 // vsub.f32 d21, d3, d1 + .long 0xf2636d02 // vsub.f32 d22, d3, d2 + .long 0xf347bd90 // vmul.f32 d27, d23, d0 + .long 0xf341cd94 // vmul.f32 d28, d17, d4 + .long 0xf3430db0 // vmul.f32 d16, d19, d16 + .long 0xf3463db4 // vmul.f32 d19, d22, d20 + .long 0xf3452db2 // vmul.f32 d18, d21, d18 + .long 0xf2444d04 // vadd.f32 d20, d4, d4 + .long 0xf3405d14 // vmul.f32 d21, d0, d4 + .long 0xf2456d05 // vadd.f32 d22, d5, d5 + .long 0xf3418d15 // vmul.f32 d24, d1, d5 + .long 0xf2469d06 // vadd.f32 d25, d6, d6 + .long 0xf342ad16 // vmul.f32 d26, d2, d6 + .long 0xf347dd91 // vmul.f32 d29, d23, d1 + .long 0xf341fd95 // vmul.f32 d31, d17, d5 + .long 0xf24cbdab // vadd.f32 d27, d28, d27 + .long 0xf3477d92 // vmul.f32 d23, d23, d2 + .long 0xf341cd96 // vmul.f32 d28, d17, d6 + .long 0xf343ed17 // vmul.f32 d30, d3, d7 + .long 0xf2400da0 // vadd.f32 d16, d16, d16 + .long 0xf2422da2 // vadd.f32 d18, d18, d18 + .long 0xf2433da3 // vadd.f32 d19, d19, d19 + .long 0xf3474e24 // vcge.f32 d20, d7, d20 + .long 0xf2455da5 // vadd.f32 d21, d21, d21 + .long 0xf3476e26 // vcge.f32 d22, d7, d22 + .long 0xf2488da8 // vadd.f32 d24, d24, d24 + .long 0xf3479e29 // vcge.f32 d25, d7, d25 + .long 0xf24aadaa // vadd.f32 d26, d26, d26 + .long 0xf2073c31 // vfma.f32 d3, d7, d17 + .long 0xf24fddad // vadd.f32 d29, d31, d29 + .long 0xf24c1da7 // vadd.f32 d17, d28, d23 + .long 0xf26e0da0 // vsub.f32 d16, d30, d16 + .long 0xf26e2da2 // vsub.f32 d18, d30, d18 + .long 0xf26e3da3 // vsub.f32 d19, d30, d19 + .long 0xf35541b0 // vbsl d20, d21, d16 + .long 0xf35861b2 // vbsl d22, d24, d18 + .long 0xf35a91b3 // vbsl d25, d26, d19 + .long 0xf20b0da4 // vadd.f32 d0, d27, d20 + .long 0xf20d1da6 // vadd.f32 d1, d29, d22 + .long 0xf2012da9 // vadd.f32 d2, d17, d25 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_softlight_vfp4 +.globl _sk_softlight_vfp4 +_sk_softlight_vfp4: + .long 0xed2d8b06 // vpush {d8-d10} + .long 0xeec58aa7 // vdiv.f32 s17, s11, s15 + .long 0xf3f90407 // vcgt.f32 d16, d7, #0 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xeec49aa7 // vdiv.f32 s19, s9, s15 + .long 0xeec6aaa7 // vdiv.f32 s21, s13, s15 + .long 0xee858a07 // vdiv.f32 s16, s10, s14 + .long 0xee849a07 // vdiv.f32 s18, s8, s14 + .long 0xee86aa07 // vdiv.f32 s20, s12, s14 + .long 0xf26021b0 // vorr d18, d16, d16 + .long 0xf2c01010 // vmov.i32 d17, #0 + .long 0xf3582131 // vbsl d18, d8, d17 + .long 0xf26031b0 // vorr d19, d16, d16 + .long 0xf3fb45a2 // vrsqrte.f32 d20, d18 + .long 0xf3593131 // vbsl d19, d9, d17 + .long 0xf35a0131 // vbsl d16, d10, d17 + .long 0xf3fb15a3 // vrsqrte.f32 d17, d19 + .long 0xf3fb55a0 // vrsqrte.f32 d21, d16 + .long 0xf3446db4 // vmul.f32 d22, d20, d20 + .long 0xf243ada3 // vadd.f32 d26, d19, d19 + .long 0xf240bda0 // vadd.f32 d27, d16, d16 + .long 0xf3417db1 // vmul.f32 d23, d17, d17 + .long 0xf3458db5 // vmul.f32 d24, d21, d21 + .long 0xf2626fb6 // vrsqrts.f32 d22, d18, d22 + .long 0xf2429da2 // vadd.f32 d25, d18, d18 + .long 0xf2637fb7 // vrsqrts.f32 d23, d19, d23 + .long 0xf2608fb8 // vrsqrts.f32 d24, d16, d24 + .long 0xf2818f1c // vmov.f32 d8, #7 + .long 0xf2499da9 // vadd.f32 d25, d25, d25 + .long 0xf3444db6 // vmul.f32 d20, d20, d22 + .long 0xf24a6daa // vadd.f32 d22, d26, d26 + .long 0xf24badab // vadd.f32 d26, d27, d27 + .long 0xf3411db7 // vmul.f32 d17, d17, d23 + .long 0xf3455db8 // vmul.f32 d21, d21, d24 + .long 0xf3fb7524 // vrecpe.f32 d23, d20 + .long 0xf3498db9 // vmul.f32 d24, d25, d25 + .long 0xf3fbd521 // vrecpe.f32 d29, d17 + .long 0xf34aedba // vmul.f32 d30, d26, d26 + .long 0xf3fbf525 // vrecpe.f32 d31, d21 + .long 0xf2444fb7 // vrecps.f32 d20, d20, d23 + .long 0xf346cdb6 // vmul.f32 d28, d22, d22 + .long 0xf2411fbd // vrecps.f32 d17, d17, d29 + .long 0xf3c7bf10 // vmov.f32 d27, #-1 + .long 0xf2455fbf // vrecps.f32 d21, d21, d31 + .long 0xf24aadae // vadd.f32 d26, d26, d30 + .long 0xf2498da8 // vadd.f32 d24, d25, d24 + .long 0xf2429dab // vadd.f32 d25, d18, d27 + .long 0xf2466dac // vadd.f32 d22, d22, d28 + .long 0xf243cdab // vadd.f32 d28, d19, d27 + .long 0xf240bdab // vadd.f32 d27, d16, d27 + .long 0xf3474db4 // vmul.f32 d20, d23, d20 + .long 0xf2c7ef10 // vmov.f32 d30, #1 + .long 0xf34d1db1 // vmul.f32 d17, d29, d17 + .long 0xf34badba // vmul.f32 d26, d27, d26 + .long 0xf242bd02 // vadd.f32 d27, d2, d2 + .long 0xf26edda0 // vsub.f32 d29, d30, d16 + .long 0xf3498db8 // vmul.f32 d24, d25, d24 + .long 0xf3429d98 // vmul.f32 d25, d18, d8 + .long 0xf34f5db5 // vmul.f32 d21, d31, d21 + .long 0xf26efda2 // vsub.f32 d31, d30, d18 + .long 0xf2642da2 // vsub.f32 d18, d20, d18 + .long 0xf26b4d83 // vsub.f32 d20, d27, d3 + .long 0xf2498da8 // vadd.f32 d24, d25, d24 + .long 0xf34c6db6 // vmul.f32 d22, d28, d22 + .long 0xf3437d98 // vmul.f32 d23, d19, d8 + .long 0xf3449dbd // vmul.f32 d25, d20, d29 + .long 0xf245dd05 // vadd.f32 d29, d5, d5 + .long 0xf340cd98 // vmul.f32 d28, d16, d8 + .long 0xf2476da6 // vadd.f32 d22, d23, d22 + .long 0xf2611da3 // vsub.f32 d17, d17, d19 + .long 0xf24dddad // vadd.f32 d29, d29, d29 + .long 0xf24c7daa // vadd.f32 d23, d28, d26 + .long 0xf2650da0 // vsub.f32 d16, d21, d16 + .long 0xf26e3da3 // vsub.f32 d19, d30, d19 + .long 0xf347de2d // vcge.f32 d29, d7, d29 + .long 0xf241ad01 // vadd.f32 d26, d1, d1 + .long 0xf3444d97 // vmul.f32 d20, d20, d7 + .long 0xf358d1b2 // vbsl d29, d24, d18 + .long 0xf2448d04 // vadd.f32 d24, d4, d4 + .long 0xf2462d06 // vadd.f32 d18, d6, d6 + .long 0xf26a5d83 // vsub.f32 d21, d26, d3 + .long 0xf2488da8 // vadd.f32 d24, d24, d24 + .long 0xf2422da2 // vadd.f32 d18, d18, d18 + .long 0xf345cdbf // vmul.f32 d28, d21, d31 + .long 0xf3455d97 // vmul.f32 d21, d21, d7 + .long 0xf3478e28 // vcge.f32 d24, d7, d24 + .long 0xf3472e22 // vcge.f32 d18, d7, d18 + .long 0xf343fd14 // vmul.f32 d31, d3, d4 + .long 0xf3455dbd // vmul.f32 d21, d21, d29 + .long 0xf35681b1 // vbsl d24, d22, d17 + .long 0xf2401d00 // vadd.f32 d17, d0, d0 + .long 0xf35721b0 // vbsl d18, d23, d16 + .long 0xf24c0d83 // vadd.f32 d16, d28, d3 + .long 0xf2496d83 // vadd.f32 d22, d25, d3 + .long 0xf2617d83 // vsub.f32 d23, d17, d3 + .long 0xf3442db2 // vmul.f32 d18, d20, d18 + .long 0xf3434e2a // vcge.f32 d20, d3, d26 + .long 0xf343ae2b // vcge.f32 d26, d3, d27 + .long 0xf3473db3 // vmul.f32 d19, d23, d19 + .long 0xf3477d97 // vmul.f32 d23, d23, d7 + .long 0xf3431e21 // vcge.f32 d17, d3, d17 + .long 0xf3400d95 // vmul.f32 d16, d16, d5 + .long 0xf2433d83 // vadd.f32 d19, d19, d3 + .long 0xf3477db8 // vmul.f32 d23, d23, d24 + .long 0xf26e8d87 // vsub.f32 d24, d30, d7 + .long 0xf26eed83 // vsub.f32 d30, d30, d3 + .long 0xf3433d94 // vmul.f32 d19, d19, d4 + .long 0xf24f7da7 // vadd.f32 d23, d31, d23 + .long 0xf3489d91 // vmul.f32 d25, d24, d1 + .long 0xf348cd90 // vmul.f32 d28, d24, d0 + .long 0xf34edd94 // vmul.f32 d29, d30, d4 + .long 0xf34ebd95 // vmul.f32 d27, d30, d5 + .long 0xf3488d92 // vmul.f32 d24, d24, d2 + .long 0xf34efd96 // vmul.f32 d31, d30, d6 + .long 0xf24dcdac // vadd.f32 d28, d29, d28 + .long 0xf343dd15 // vmul.f32 d29, d3, d5 + .long 0xf24b9da9 // vadd.f32 d25, d27, d25 + .long 0xf343bd16 // vmul.f32 d27, d3, d6 + .long 0xf3466d96 // vmul.f32 d22, d22, d6 + .long 0xf24f8da8 // vadd.f32 d24, d31, d24 + .long 0xf24d5da5 // vadd.f32 d21, d29, d21 + .long 0xf24b2da2 // vadd.f32 d18, d27, d18 + .long 0xf35311b7 // vbsl d17, d19, d23 + .long 0xf35041b5 // vbsl d20, d16, d21 + .long 0xf356a1b2 // vbsl d26, d22, d18 + .long 0xf2073c3e // vfma.f32 d3, d7, d30 + .long 0xf20c0da1 // vadd.f32 d0, d28, d17 + .long 0xf2091da4 // vadd.f32 d1, d25, d20 + .long 0xf2082daa // vadd.f32 d2, d24, d26 + .long 0xecbd8b06 // vpop {d8-d10} + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_clamp_0_vfp4 +.globl _sk_clamp_0_vfp4 +_sk_clamp_0_vfp4: + .long 0xf2c00010 // vmov.i32 d16, #0 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2000f20 // vmax.f32 d0, d0, d16 + .long 0xf2011f20 // vmax.f32 d1, d1, d16 + .long 0xf2022f20 // vmax.f32 d2, d2, d16 + .long 0xf2033f20 // vmax.f32 d3, d3, d16 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_clamp_1_vfp4 +.globl _sk_clamp_1_vfp4 +_sk_clamp_1_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2200f20 // vmin.f32 d0, d0, d16 + .long 0xf2211f20 // vmin.f32 d1, d1, d16 + .long 0xf2222f20 // vmin.f32 d2, d2, d16 + .long 0xf2233f20 // vmin.f32 d3, d3, d16 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_clamp_a_vfp4 +.globl _sk_clamp_a_vfp4 +_sk_clamp_a_vfp4: + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf2233f20 // vmin.f32 d3, d3, d16 + .long 0xf2200f03 // vmin.f32 d0, d0, d3 + .long 0xf2211f03 // vmin.f32 d1, d1, d3 + .long 0xf2222f03 // vmin.f32 d2, d2, d3 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_set_rgb_vfp4 +.globl _sk_set_rgb_vfp4 +_sk_set_rgb_vfp4: + .long 0xe92d4800 // push {fp, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xe283e008 // add lr, r3, #8 + .long 0xf4a30c9d // vld1.32 {d0[]}, [r3 :32]! + .long 0xf4ae2c9f // vld1.32 {d2[]}, [lr :32] + .long 0xf4a31c9f // vld1.32 {d1[]}, [r3 :32] + .long 0xe8bd4800 // pop {fp, lr} + .long 0xe12fff1c // bx ip + +HIDDEN _sk_swap_rb_vfp4 +.globl _sk_swap_rb_vfp4 +_sk_swap_rb_vfp4: + .long 0xeef00b40 // vmov.f64 d16, d0 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xeeb00b42 // vmov.f64 d0, d2 + .long 0xeeb02b60 // vmov.f64 d2, d16 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_swap_vfp4 +.globl _sk_swap_vfp4 +_sk_swap_vfp4: + .long 0xeef00b43 // vmov.f64 d16, d3 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xeef01b42 // vmov.f64 d17, d2 + .long 0xeef02b41 // vmov.f64 d18, d1 + .long 0xeef03b40 // vmov.f64 d19, d0 + .long 0xeeb00b44 // vmov.f64 d0, d4 + .long 0xeeb01b45 // vmov.f64 d1, d5 + .long 0xeeb02b46 // vmov.f64 d2, d6 + .long 0xeeb03b47 // vmov.f64 d3, d7 + .long 0xeeb04b63 // vmov.f64 d4, d19 + .long 0xeeb05b62 // vmov.f64 d5, d18 + .long 0xeeb06b61 // vmov.f64 d6, d17 + .long 0xeeb07b60 // vmov.f64 d7, d16 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_move_src_dst_vfp4 +.globl _sk_move_src_dst_vfp4 +_sk_move_src_dst_vfp4: + .long 0xeeb04b40 // vmov.f64 d4, d0 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xeeb05b41 // vmov.f64 d5, d1 + .long 0xeeb06b42 // vmov.f64 d6, d2 + .long 0xeeb07b43 // vmov.f64 d7, d3 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_move_dst_src_vfp4 +.globl _sk_move_dst_src_vfp4 +_sk_move_dst_src_vfp4: + .long 0xeeb00b44 // vmov.f64 d0, d4 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xeeb01b45 // vmov.f64 d1, d5 + .long 0xeeb02b46 // vmov.f64 d2, d6 + .long 0xeeb03b47 // vmov.f64 d3, d7 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_premul_vfp4 +.globl _sk_premul_vfp4 +_sk_premul_vfp4: + .long 0xf3000d13 // vmul.f32 d0, d0, d3 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3011d13 // vmul.f32 d1, d1, d3 + .long 0xf3022d13 // vmul.f32 d2, d2, d3 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_unpremul_vfp4 +.globl _sk_unpremul_vfp4 +_sk_unpremul_vfp4: + .long 0xed2d8b04 // vpush {d8-d9} + .long 0xeeb78a00 // vmov.f32 s16, #112 + .long 0xf3f91503 // vceq.f32 d17, d3, #0 + .long 0xf2c00010 // vmov.i32 d16, #0 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xeec89a23 // vdiv.f32 s19, s16, s7 + .long 0xee889a03 // vdiv.f32 s18, s16, s6 + .long 0xf3501199 // vbsl d17, d16, d9 + .long 0xf3010d90 // vmul.f32 d0, d17, d0 + .long 0xf3011d91 // vmul.f32 d1, d17, d1 + .long 0xf3012d92 // vmul.f32 d2, d17, d2 + .long 0xecbd8b04 // vpop {d8-d9} + .long 0xe12fff13 // bx r3 + .long 0xe320f000 // nop {0} + +HIDDEN _sk_from_srgb_vfp4 +.globl _sk_from_srgb_vfp4 +_sk_from_srgb_vfp4: + .long 0xeddf3b20 // vldr d19, [pc, #128] + .long 0xf3408d10 // vmul.f32 d24, d0, d0 + .long 0xeddf0b1c // vldr d16, [pc, #112] + .long 0xf26341b3 // vorr d20, d19, d19 + .long 0xf26351b3 // vorr d21, d19, d19 + .long 0xeddf9b1f // vldr d25, [pc, #124] + .long 0xf2404c30 // vfma.f32 d20, d0, d16 + .long 0xeddf2b1b // vldr d18, [pc, #108] + .long 0xf2415c30 // vfma.f32 d21, d1, d16 + .long 0xeddfcb1d // vldr d28, [pc, #116] + .long 0xf2423c30 // vfma.f32 d19, d2, d16 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3426d12 // vmul.f32 d22, d2, d2 + .long 0xf3417d11 // vmul.f32 d23, d1, d1 + .long 0xf3620e80 // vcgt.f32 d16, d18, d0 + .long 0xf3621e81 // vcgt.f32 d17, d18, d1 + .long 0xf341ad39 // vmul.f32 d26, d1, d25 + .long 0xf342bd39 // vmul.f32 d27, d2, d25 + .long 0xf3622e82 // vcgt.f32 d18, d18, d2 + .long 0xf3409d39 // vmul.f32 d25, d0, d25 + .long 0xf26cd1bc // vorr d29, d28, d28 + .long 0xf248dcb4 // vfma.f32 d29, d24, d20 + .long 0xf26c41bc // vorr d20, d28, d28 + .long 0xf2474cb5 // vfma.f32 d20, d23, d21 + .long 0xf246ccb3 // vfma.f32 d28, d22, d19 + .long 0xf35901bd // vbsl d16, d25, d29 + .long 0xf35a11b4 // vbsl d17, d26, d20 + .long 0xf35b21bc // vbsl d18, d27, d28 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xf22221b2 // vorr d2, d18, d18 + .long 0xe12fff13 // bx r3 + .long 0x3e99999a // .word 0x3e99999a + .long 0x3e99999a // .word 0x3e99999a + .long 0x3f328f5c // .word 0x3f328f5c + .long 0x3f328f5c // .word 0x3f328f5c + .long 0x3d6147ae // .word 0x3d6147ae + .long 0x3d6147ae // .word 0x3d6147ae + .long 0x3d9e8391 // .word 0x3d9e8391 + .long 0x3d9e8391 // .word 0x3d9e8391 + .long 0x3b23d70a // .word 0x3b23d70a + .long 0x3b23d70a // .word 0x3b23d70a + +HIDDEN _sk_to_srgb_vfp4 +.globl _sk_to_srgb_vfp4 +_sk_to_srgb_vfp4: + .long 0xf3fb0582 // vrsqrte.f32 d16, d2 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3fb1581 // vrsqrte.f32 d17, d1 + .long 0xf3fb2580 // vrsqrte.f32 d18, d0 + .long 0xf3403db0 // vmul.f32 d19, d16, d16 + .long 0xf3414db1 // vmul.f32 d20, d17, d17 + .long 0xf3425db2 // vmul.f32 d21, d18, d18 + .long 0xf2623f33 // vrsqrts.f32 d19, d2, d19 + .long 0xf2614f34 // vrsqrts.f32 d20, d1, d20 + .long 0xf2605f35 // vrsqrts.f32 d21, d0, d21 + .long 0xf3400db3 // vmul.f32 d16, d16, d19 + .long 0xf3411db4 // vmul.f32 d17, d17, d20 + .long 0xf3422db5 // vmul.f32 d18, d18, d21 + .long 0xf3fb3520 // vrecpe.f32 d19, d16 + .long 0xf3fb4521 // vrecpe.f32 d20, d17 + .long 0xf3fb6522 // vrecpe.f32 d22, d18 + .long 0xf3fb55a0 // vrsqrte.f32 d21, d16 + .long 0xf3fb75a1 // vrsqrte.f32 d23, d17 + .long 0xf3fb85a2 // vrsqrte.f32 d24, d18 + .long 0xf2409fb3 // vrecps.f32 d25, d16, d19 + .long 0xf241afb4 // vrecps.f32 d26, d17, d20 + .long 0xf242bfb6 // vrecps.f32 d27, d18, d22 + .long 0xf345cdb5 // vmul.f32 d28, d21, d21 + .long 0xf347ddb7 // vmul.f32 d29, d23, d23 + .long 0xf348edb8 // vmul.f32 d30, d24, d24 + .long 0xf2600fbc // vrsqrts.f32 d16, d16, d28 + .long 0xf2611fbd // vrsqrts.f32 d17, d17, d29 + .long 0xf2622fbe // vrsqrts.f32 d18, d18, d30 + .long 0xf3433db9 // vmul.f32 d19, d19, d25 + .long 0xeddf9b21 // vldr d25, [pc, #132] + .long 0xf3444dba // vmul.f32 d20, d20, d26 + .long 0xeddfab21 // vldr d26, [pc, #132] + .long 0xf3466dbb // vmul.f32 d22, d22, d27 + .long 0xf26ab1ba // vorr d27, d26, d26 + .long 0xf243bcb9 // vfma.f32 d27, d19, d25 + .long 0xf26a31ba // vorr d19, d26, d26 + .long 0xf2443cb9 // vfma.f32 d19, d20, d25 + .long 0xeddf4b1d // vldr d20, [pc, #116] + .long 0xf246acb9 // vfma.f32 d26, d22, d25 + .long 0xf3450db0 // vmul.f32 d16, d21, d16 + .long 0xeddf5b1c // vldr d21, [pc, #112] + .long 0xf3471db1 // vmul.f32 d17, d23, d17 + .long 0xf3482db2 // vmul.f32 d18, d24, d18 + .long 0xf3406d35 // vmul.f32 d22, d0, d21 + .long 0xf240bcb4 // vfma.f32 d27, d16, d20 + .long 0xf2413cb4 // vfma.f32 d19, d17, d20 + .long 0xf242acb4 // vfma.f32 d26, d18, d20 + .long 0xeddf2b17 // vldr d18, [pc, #92] + .long 0xf3417d35 // vmul.f32 d23, d1, d21 + .long 0xf3620e80 // vcgt.f32 d16, d18, d0 + .long 0xf3621e81 // vcgt.f32 d17, d18, d1 + .long 0xf3622e82 // vcgt.f32 d18, d18, d2 + .long 0xf3425d35 // vmul.f32 d21, d2, d21 + .long 0xf2c74f10 // vmov.f32 d20, #1 + .long 0xf2648faa // vmin.f32 d24, d20, d26 + .long 0xf2643fa3 // vmin.f32 d19, d20, d19 + .long 0xf2644fab // vmin.f32 d20, d20, d27 + .long 0xf35601b8 // vbsl d16, d22, d24 + .long 0xf35711b3 // vbsl d17, d23, d19 + .long 0xf35521b4 // vbsl d18, d21, d20 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xf22221b2 // vorr d2, d18, d18 + .long 0xe12fff13 // bx r3 + .long 0x3f306fce // .word 0x3f306fce + .long 0x3f306fce // .word 0x3f306fce + .long 0xbdca57a8 // .word 0xbdca57a8 + .long 0xbdca57a8 // .word 0xbdca57a8 + .long 0x3ed287c2 // .word 0x3ed287c2 + .long 0x3ed287c2 // .word 0x3ed287c2 + .long 0x41475c29 // .word 0x41475c29 + .long 0x41475c29 // .word 0x41475c29 + .long 0x3b8ce704 // .word 0x3b8ce704 + .long 0x3b8ce704 // .word 0x3b8ce704 + +HIDDEN _sk_from_2dot2_vfp4 +.globl _sk_from_2dot2_vfp4 +_sk_from_2dot2_vfp4: + .long 0xf3fb0580 // vrsqrte.f32 d16, d0 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3fb1581 // vrsqrte.f32 d17, d1 + .long 0xf3fb2582 // vrsqrte.f32 d18, d2 + .long 0xf3403db0 // vmul.f32 d19, d16, d16 + .long 0xf3414db1 // vmul.f32 d20, d17, d17 + .long 0xf3425db2 // vmul.f32 d21, d18, d18 + .long 0xf2603f33 // vrsqrts.f32 d19, d0, d19 + .long 0xf2614f34 // vrsqrts.f32 d20, d1, d20 + .long 0xf2625f35 // vrsqrts.f32 d21, d2, d21 + .long 0xf3400db3 // vmul.f32 d16, d16, d19 + .long 0xf3411db4 // vmul.f32 d17, d17, d20 + .long 0xf3422db5 // vmul.f32 d18, d18, d21 + .long 0xf3fb35a0 // vrsqrte.f32 d19, d16 + .long 0xf3fb45a1 // vrsqrte.f32 d20, d17 + .long 0xf3fb55a2 // vrsqrte.f32 d21, d18 + .long 0xf3436db3 // vmul.f32 d22, d19, d19 + .long 0xf3447db4 // vmul.f32 d23, d20, d20 + .long 0xf3458db5 // vmul.f32 d24, d21, d21 + .long 0xf2600fb6 // vrsqrts.f32 d16, d16, d22 + .long 0xf2611fb7 // vrsqrts.f32 d17, d17, d23 + .long 0xf2622fb8 // vrsqrts.f32 d18, d18, d24 + .long 0xf3430db0 // vmul.f32 d16, d19, d16 + .long 0xf3441db1 // vmul.f32 d17, d20, d17 + .long 0xf3452db2 // vmul.f32 d18, d21, d18 + .long 0xf3fb35a0 // vrsqrte.f32 d19, d16 + .long 0xf3fb45a1 // vrsqrte.f32 d20, d17 + .long 0xf3fb55a2 // vrsqrte.f32 d21, d18 + .long 0xf3436db3 // vmul.f32 d22, d19, d19 + .long 0xf3447db4 // vmul.f32 d23, d20, d20 + .long 0xf3458db5 // vmul.f32 d24, d21, d21 + .long 0xf2600fb6 // vrsqrts.f32 d16, d16, d22 + .long 0xf2611fb7 // vrsqrts.f32 d17, d17, d23 + .long 0xf2622fb8 // vrsqrts.f32 d18, d18, d24 + .long 0xf3430db0 // vmul.f32 d16, d19, d16 + .long 0xf3441db1 // vmul.f32 d17, d20, d17 + .long 0xf3452db2 // vmul.f32 d18, d21, d18 + .long 0xf3fb35a0 // vrsqrte.f32 d19, d16 + .long 0xf3fb45a1 // vrsqrte.f32 d20, d17 + .long 0xf3fb55a2 // vrsqrte.f32 d21, d18 + .long 0xf3436db3 // vmul.f32 d22, d19, d19 + .long 0xf3447db4 // vmul.f32 d23, d20, d20 + .long 0xf3458db5 // vmul.f32 d24, d21, d21 + .long 0xf2600fb6 // vrsqrts.f32 d16, d16, d22 + .long 0xf2611fb7 // vrsqrts.f32 d17, d17, d23 + .long 0xf2622fb8 // vrsqrts.f32 d18, d18, d24 + .long 0xf3430db0 // vmul.f32 d16, d19, d16 + .long 0xf3441db1 // vmul.f32 d17, d20, d17 + .long 0xf3452db2 // vmul.f32 d18, d21, d18 + .long 0xf3fb35a0 // vrsqrte.f32 d19, d16 + .long 0xf3fb45a1 // vrsqrte.f32 d20, d17 + .long 0xf3fb55a2 // vrsqrte.f32 d21, d18 + .long 0xf340bdb0 // vmul.f32 d27, d16, d16 + .long 0xf341ddb1 // vmul.f32 d29, d17, d17 + .long 0xf3436db3 // vmul.f32 d22, d19, d19 + .long 0xf3447db4 // vmul.f32 d23, d20, d20 + .long 0xf3458db5 // vmul.f32 d24, d21, d21 + .long 0xf2606fb6 // vrsqrts.f32 d22, d16, d22 + .long 0xf2617fb7 // vrsqrts.f32 d23, d17, d23 + .long 0xf2628fb8 // vrsqrts.f32 d24, d18, d24 + .long 0xf3400dbb // vmul.f32 d16, d16, d27 + .long 0xf3411dbd // vmul.f32 d17, d17, d29 + .long 0xf341bd11 // vmul.f32 d27, d1, d1 + .long 0xf3433db6 // vmul.f32 d19, d19, d22 + .long 0xf3444db7 // vmul.f32 d20, d20, d23 + .long 0xf3455db8 // vmul.f32 d21, d21, d24 + .long 0xf34b1db1 // vmul.f32 d17, d27, d17 + .long 0xf3fb65a3 // vrsqrte.f32 d22, d19 + .long 0xf3fb75a4 // vrsqrte.f32 d23, d20 + .long 0xf3fb85a5 // vrsqrte.f32 d24, d21 + .long 0xf3469db6 // vmul.f32 d25, d22, d22 + .long 0xf347adb7 // vmul.f32 d26, d23, d23 + .long 0xf348cdb8 // vmul.f32 d28, d24, d24 + .long 0xf2633fb9 // vrsqrts.f32 d19, d19, d25 + .long 0xf2644fba // vrsqrts.f32 d20, d20, d26 + .long 0xf3429db2 // vmul.f32 d25, d18, d18 + .long 0xf2655fbc // vrsqrts.f32 d21, d21, d28 + .long 0xf340ad10 // vmul.f32 d26, d0, d0 + .long 0xf3422db9 // vmul.f32 d18, d18, d25 + .long 0xf3429d12 // vmul.f32 d25, d2, d2 + .long 0xf3463db3 // vmul.f32 d19, d22, d19 + .long 0xf3474db4 // vmul.f32 d20, d23, d20 + .long 0xf34a0db0 // vmul.f32 d16, d26, d16 + .long 0xf3485db5 // vmul.f32 d21, d24, d21 + .long 0xf3492db2 // vmul.f32 d18, d25, d18 + .long 0xf3400db3 // vmul.f32 d16, d16, d19 + .long 0xf3411db4 // vmul.f32 d17, d17, d20 + .long 0xf3422db5 // vmul.f32 d18, d18, d21 + .long 0xf2c03010 // vmov.i32 d19, #0 + .long 0xf2000fa3 // vmax.f32 d0, d16, d19 + .long 0xf2011fa3 // vmax.f32 d1, d17, d19 + .long 0xf2022fa3 // vmax.f32 d2, d18, d19 + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_to_2dot2_vfp4 +.globl _sk_to_2dot2_vfp4 +_sk_to_2dot2_vfp4: + .long 0xf3fb0580 // vrsqrte.f32 d16, d0 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3fb1581 // vrsqrte.f32 d17, d1 + .long 0xf3fb3582 // vrsqrte.f32 d19, d2 + .long 0xf3402db0 // vmul.f32 d18, d16, d16 + .long 0xf3414db1 // vmul.f32 d20, d17, d17 + .long 0xf3435db3 // vmul.f32 d21, d19, d19 + .long 0xf2602f32 // vrsqrts.f32 d18, d0, d18 + .long 0xf2614f34 // vrsqrts.f32 d20, d1, d20 + .long 0xf2625f35 // vrsqrts.f32 d21, d2, d21 + .long 0xf3402db2 // vmul.f32 d18, d16, d18 + .long 0xf3411db4 // vmul.f32 d17, d17, d20 + .long 0xf3430db5 // vmul.f32 d16, d19, d21 + .long 0xf3fb35a2 // vrsqrte.f32 d19, d18 + .long 0xf3fb45a1 // vrsqrte.f32 d20, d17 + .long 0xf3fb55a0 // vrsqrte.f32 d21, d16 + .long 0xf3fbc522 // vrecpe.f32 d28, d18 + .long 0xf3436db3 // vmul.f32 d22, d19, d19 + .long 0xf3447db4 // vmul.f32 d23, d20, d20 + .long 0xf3458db5 // vmul.f32 d24, d21, d21 + .long 0xf2626fb6 // vrsqrts.f32 d22, d18, d22 + .long 0xf2617fb7 // vrsqrts.f32 d23, d17, d23 + .long 0xf2608fb8 // vrsqrts.f32 d24, d16, d24 + .long 0xf2422fbc // vrecps.f32 d18, d18, d28 + .long 0xf3433db6 // vmul.f32 d19, d19, d22 + .long 0xf3444db7 // vmul.f32 d20, d20, d23 + .long 0xf3455db8 // vmul.f32 d21, d21, d24 + .long 0xf34c2db2 // vmul.f32 d18, d28, d18 + .long 0xf3fb65a3 // vrsqrte.f32 d22, d19 + .long 0xf3fb75a4 // vrsqrte.f32 d23, d20 + .long 0xf3fb85a5 // vrsqrte.f32 d24, d21 + .long 0xf3469db6 // vmul.f32 d25, d22, d22 + .long 0xf347adb7 // vmul.f32 d26, d23, d23 + .long 0xf348bdb8 // vmul.f32 d27, d24, d24 + .long 0xf2633fb9 // vrsqrts.f32 d19, d19, d25 + .long 0xf2644fba // vrsqrts.f32 d20, d20, d26 + .long 0xf2655fbb // vrsqrts.f32 d21, d21, d27 + .long 0xf3463db3 // vmul.f32 d19, d22, d19 + .long 0xf3474db4 // vmul.f32 d20, d23, d20 + .long 0xf3485db5 // vmul.f32 d21, d24, d21 + .long 0xf3fb65a3 // vrsqrte.f32 d22, d19 + .long 0xf3fb75a4 // vrsqrte.f32 d23, d20 + .long 0xf3fb85a5 // vrsqrte.f32 d24, d21 + .long 0xf3469db6 // vmul.f32 d25, d22, d22 + .long 0xf347adb7 // vmul.f32 d26, d23, d23 + .long 0xf348bdb8 // vmul.f32 d27, d24, d24 + .long 0xf2633fb9 // vrsqrts.f32 d19, d19, d25 + .long 0xf2644fba // vrsqrts.f32 d20, d20, d26 + .long 0xf2655fbb // vrsqrts.f32 d21, d21, d27 + .long 0xf3463db3 // vmul.f32 d19, d22, d19 + .long 0xf3474db4 // vmul.f32 d20, d23, d20 + .long 0xf3485db5 // vmul.f32 d21, d24, d21 + .long 0xf3fb65a3 // vrsqrte.f32 d22, d19 + .long 0xf3fb75a4 // vrsqrte.f32 d23, d20 + .long 0xf3fb85a5 // vrsqrte.f32 d24, d21 + .long 0xf3469db6 // vmul.f32 d25, d22, d22 + .long 0xf347adb7 // vmul.f32 d26, d23, d23 + .long 0xf348bdb8 // vmul.f32 d27, d24, d24 + .long 0xf2633fb9 // vrsqrts.f32 d19, d19, d25 + .long 0xf2644fba // vrsqrts.f32 d20, d20, d26 + .long 0xf2655fbb // vrsqrts.f32 d21, d21, d27 + .long 0xf3463db3 // vmul.f32 d19, d22, d19 + .long 0xf3474db4 // vmul.f32 d20, d23, d20 + .long 0xf3485db5 // vmul.f32 d21, d24, d21 + .long 0xf3fb65a3 // vrsqrte.f32 d22, d19 + .long 0xf3fb75a4 // vrsqrte.f32 d23, d20 + .long 0xf3fb85a5 // vrsqrte.f32 d24, d21 + .long 0xf3432db2 // vmul.f32 d18, d19, d18 + .long 0xf3469db6 // vmul.f32 d25, d22, d22 + .long 0xf347adb7 // vmul.f32 d26, d23, d23 + .long 0xf348bdb8 // vmul.f32 d27, d24, d24 + .long 0xf2639fb9 // vrsqrts.f32 d25, d19, d25 + .long 0xf264afba // vrsqrts.f32 d26, d20, d26 + .long 0xf265bfbb // vrsqrts.f32 d27, d21, d27 + .long 0xf3466db9 // vmul.f32 d22, d22, d25 + .long 0xf3fb9521 // vrecpe.f32 d25, d17 + .long 0xf3477dba // vmul.f32 d23, d23, d26 + .long 0xf3fba520 // vrecpe.f32 d26, d16 + .long 0xf3488dbb // vmul.f32 d24, d24, d27 + .long 0xf2411fb9 // vrecps.f32 d17, d17, d25 + .long 0xf3fbb526 // vrecpe.f32 d27, d22 + .long 0xf3fbd527 // vrecpe.f32 d29, d23 + .long 0xf2400fba // vrecps.f32 d16, d16, d26 + .long 0xf3fbe528 // vrecpe.f32 d30, d24 + .long 0xf2466fbb // vrecps.f32 d22, d22, d27 + .long 0xf2477fbd // vrecps.f32 d23, d23, d29 + .long 0xf2488fbe // vrecps.f32 d24, d24, d30 + .long 0xf3491db1 // vmul.f32 d17, d25, d17 + .long 0xf34a0db0 // vmul.f32 d16, d26, d16 + .long 0xf34b6db6 // vmul.f32 d22, d27, d22 + .long 0xf3441db1 // vmul.f32 d17, d20, d17 + .long 0xf34d3db7 // vmul.f32 d19, d29, d23 + .long 0xf34e4db8 // vmul.f32 d20, d30, d24 + .long 0xf3450db0 // vmul.f32 d16, d21, d16 + .long 0xf3422db6 // vmul.f32 d18, d18, d22 + .long 0xf3411db3 // vmul.f32 d17, d17, d19 + .long 0xf3400db4 // vmul.f32 d16, d16, d20 + .long 0xf2c03010 // vmov.i32 d19, #0 + .long 0xf2020fa3 // vmax.f32 d0, d18, d19 + .long 0xf2011fa3 // vmax.f32 d1, d17, d19 + .long 0xf2002fa3 // vmax.f32 d2, d16, d19 + .long 0xe12fff13 // bx r3 + .long 0xe320f000 // nop {0} + +HIDDEN _sk_rgb_to_hsl_vfp4 +.globl _sk_rgb_to_hsl_vfp4 +_sk_rgb_to_hsl_vfp4: + .long 0xed2d8b08 // vpush {d8-d11} + .long 0xf2401f01 // vmax.f32 d17, d0, d1 + .long 0xeddf9b2c // vldr d25, [pc, #176] + .long 0xf2600f01 // vmin.f32 d16, d0, d1 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xeeb78a00 // vmov.f32 s16, #112 + .long 0xf2c3461f // vmov.i32 d20, #1056964608 + .long 0xf2411f82 // vmax.f32 d17, d17, d2 + .long 0xf2602f82 // vmin.f32 d18, d16, d2 + .long 0xf2c45610 // vmov.i32 d21, #1073741824 + .long 0xf2607d01 // vsub.f32 d23, d0, d1 + .long 0xf2656da1 // vsub.f32 d22, d21, d17 + .long 0xf221ada2 // vsub.f32 d10, d17, d18 + .long 0xf2413da2 // vadd.f32 d19, d17, d18 + .long 0xf2c08010 // vmov.i32 d24, #0 + .long 0xf2666da2 // vsub.f32 d22, d22, d18 + .long 0xf241ae80 // vceq.f32 d26, d17, d0 + .long 0xeec8ba2a // vdiv.f32 s23, s16, s21 + .long 0xf3430db4 // vmul.f32 d16, d19, d20 + .long 0xee88ba0a // vdiv.f32 s22, s16, s20 + .long 0xf3209ea4 // vcgt.f32 d9, d16, d20 + .long 0xf2614d02 // vsub.f32 d20, d1, d2 + .long 0xf3477d9b // vmul.f32 d23, d23, d11 + .long 0xf31691b3 // vbsl d9, d22, d19 + .long 0xf2623d00 // vsub.f32 d19, d2, d0 + .long 0xf3626e01 // vcgt.f32 d22, d2, d1 + .long 0xeeca8aa9 // vdiv.f32 s17, s21, s19 + .long 0xee8a8a09 // vdiv.f32 s16, s20, s18 + .long 0xf3433d9b // vmul.f32 d19, d19, d11 + .long 0xf3444d9b // vmul.f32 d20, d20, d11 + .long 0xf35961b8 // vbsl d22, d25, d24 + .long 0xf2419e81 // vceq.f32 d25, d17, d1 + .long 0xf2011ea2 // vceq.f32 d1, d17, d18 + .long 0xf2433da5 // vadd.f32 d19, d19, d21 + .long 0xf2c15f10 // vmov.f32 d21, #4 + .long 0xf2464da4 // vadd.f32 d20, d22, d20 + .long 0xf2471da5 // vadd.f32 d17, d23, d21 + .long 0xf35391b1 // vbsl d25, d19, d17 + .long 0xeddf1b0a // vldr d17, [pc, #40] + .long 0xf2612111 // vorr d18, d1, d1 + .long 0xf354a1b9 // vbsl d26, d20, d25 + .long 0xf35821ba // vbsl d18, d24, d26 + .long 0xf3181198 // vbsl d1, d24, d8 + .long 0xf3020db1 // vmul.f32 d0, d18, d17 + .long 0xf22021b0 // vorr d2, d16, d16 + .long 0xecbd8b08 // vpop {d8-d11} + .long 0xe12fff13 // bx r3 + .long 0xe320f000 // nop {0} + .long 0x40c00000 // .word 0x40c00000 + .long 0x40c00000 // .word 0x40c00000 + .long 0x3e2aaaab // .word 0x3e2aaaab + .long 0x3e2aaaab // .word 0x3e2aaaab + +HIDDEN _sk_hsl_to_rgb_vfp4 +.globl _sk_hsl_to_rgb_vfp4 +_sk_hsl_to_rgb_vfp4: + .long 0xf2c72f10 // vmov.f32 d18, #1 + .long 0xeddf0b4f // vldr d16, [pc, #316] + .long 0xf2c3161f // vmov.i32 d17, #1056964608 + .long 0xeddf9b4f // vldr d25, [pc, #316] + .long 0xf2415d22 // vadd.f32 d21, d1, d18 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3414d12 // vmul.f32 d20, d1, d2 + .long 0xf2416d02 // vadd.f32 d22, d1, d2 + .long 0xf2407d20 // vadd.f32 d23, d0, d16 + .long 0xf3610e82 // vcgt.f32 d16, d17, d2 + .long 0xf3455d92 // vmul.f32 d21, d21, d2 + .long 0xf2664da4 // vsub.f32 d20, d22, d20 + .long 0xf2426d02 // vadd.f32 d22, d2, d2 + .long 0xf3c73f10 // vmov.f32 d19, #-1 + .long 0xf35501b4 // vbsl d16, d21, d20 + .long 0xf2409d29 // vadd.f32 d25, d0, d25 + .long 0xf2408d23 // vadd.f32 d24, d0, d19 + .long 0xf3f9e629 // vclt.f32 d30, d25, #0 + .long 0xf360ae22 // vcgt.f32 d26, d0, d18 + .long 0xf247cda3 // vadd.f32 d28, d23, d19 + .long 0xf367dea2 // vcgt.f32 d29, d23, d18 + .long 0xf240bd22 // vadd.f32 d27, d0, d18 + .long 0xf2666da0 // vsub.f32 d22, d22, d16 + .long 0xf2474da2 // vadd.f32 d20, d23, d18 + .long 0xf358a190 // vbsl d26, d24, d0 + .long 0xf3f98600 // vclt.f32 d24, d0, #0 + .long 0xf3695ea2 // vcgt.f32 d21, d25, d18 + .long 0xf2493da3 // vadd.f32 d19, d25, d19 + .long 0xf35b81ba // vbsl d24, d27, d26 + .long 0xf3f9a627 // vclt.f32 d26, d23, #0 + .long 0xf35cd1b7 // vbsl d29, d28, d23 + .long 0xeddfcb35 // vldr d28, [pc, #212] + .long 0xf2492da2 // vadd.f32 d18, d25, d18 + .long 0xf260bda6 // vsub.f32 d27, d16, d22 + .long 0xf354a1bd // vbsl d26, d20, d29 + .long 0xf2c14f18 // vmov.f32 d20, #6 + .long 0xf35351b9 // vbsl d21, d19, d25 + .long 0xf26cddaa // vsub.f32 d29, d28, d26 + .long 0xf352e1b5 // vbsl d30, d18, d21 + .long 0xf34b2db4 // vmul.f32 d18, d27, d20 + .long 0xf26c3da8 // vsub.f32 d19, d28, d24 + .long 0xf26c4dae // vsub.f32 d20, d28, d30 + .long 0xf36cbeaa // vcgt.f32 d27, d28, d26 + .long 0xf3425dbd // vmul.f32 d21, d18, d29 + .long 0xf3477db2 // vmul.f32 d23, d23, d18 + .long 0xf3423db3 // vmul.f32 d19, d18, d19 + .long 0xf3444db2 // vmul.f32 d20, d20, d18 + .long 0xf2465da5 // vadd.f32 d21, d22, d21 + .long 0xf342dd90 // vmul.f32 d29, d18, d0 + .long 0xf3210eaa // vcgt.f32 d0, d17, d26 + .long 0xf3492db2 // vmul.f32 d18, d25, d18 + .long 0xf355b1b6 // vbsl d27, d21, d22 + .long 0xeddf5b22 // vldr d21, [pc, #136] + .long 0xf36cfea8 // vcgt.f32 d31, d28, d24 + .long 0xf2463da3 // vadd.f32 d19, d22, d19 + .long 0xf36cceae // vcgt.f32 d28, d28, d30 + .long 0xf2464da4 // vadd.f32 d20, d22, d20 + .long 0xf365aeaa // vcgt.f32 d26, d21, d26 + .long 0xf2467da7 // vadd.f32 d23, d22, d23 + .long 0xf3619ea8 // vcgt.f32 d25, d17, d24 + .long 0xf3611eae // vcgt.f32 d17, d17, d30 + .long 0xf31001bb // vbsl d0, d16, d27 + .long 0xf353f1b6 // vbsl d31, d19, d22 + .long 0xf354c1b6 // vbsl d28, d20, d22 + .long 0xf357a190 // vbsl d26, d23, d0 + .long 0xf3b90501 // vceq.f32 d0, d1, #0 + .long 0xf3658ea8 // vcgt.f32 d24, d21, d24 + .long 0xf246ddad // vadd.f32 d29, d22, d29 + .long 0xf3653eae // vcgt.f32 d19, d21, d30 + .long 0xf2462da2 // vadd.f32 d18, d22, d18 + .long 0xf35091bf // vbsl d25, d16, d31 + .long 0xf35011bc // vbsl d17, d16, d28 + .long 0xf2600110 // vorr d16, d0, d0 + .long 0xf2201110 // vorr d1, d0, d0 + .long 0xf352013a // vbsl d16, d2, d26 + .long 0xf35d81b9 // vbsl d24, d29, d25 + .long 0xf35231b1 // vbsl d19, d18, d17 + .long 0xf3121138 // vbsl d1, d2, d24 + .long 0xf3120133 // vbsl d0, d2, d19 + .long 0xf22021b0 // vorr d2, d16, d16 + .long 0xe12fff13 // bx r3 + .long 0xe320f000 // nop {0} + .long 0xbeaaaaab // .word 0xbeaaaaab + .long 0xbeaaaaab // .word 0xbeaaaaab + .long 0x3eaaaaab // .word 0x3eaaaaab + .long 0x3eaaaaab // .word 0x3eaaaaab + .long 0x3f2aaaab // .word 0x3f2aaaab + .long 0x3f2aaaab // .word 0x3f2aaaab + .long 0x3e2aaaab // .word 0x3e2aaaab + .long 0x3e2aaaab // .word 0x3e2aaaab + +HIDDEN _sk_scale_1_float_vfp4 +.globl _sk_scale_1_float_vfp4 +_sk_scale_1_float_vfp4: + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xf4e30c9f // vld1.32 {d16[]}, [r3 :32] + .long 0xf3000d90 // vmul.f32 d0, d16, d0 + .long 0xf3001d91 // vmul.f32 d1, d16, d1 + .long 0xf3002d92 // vmul.f32 d2, d16, d2 + .long 0xf3003d93 // vmul.f32 d3, d16, d3 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_scale_u8_vfp4 +.globl _sk_scale_u8_vfp4 +_sk_scale_u8_vfp4: + .long 0xe24dd004 // sub sp, sp, #4 + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xe5933000 // ldr r3, [r3] + .long 0xe0833000 // add r3, r3, r0 + .long 0xe1d330b0 // ldrh r3, [r3] + .long 0xe1cd30b0 // strh r3, [sp] + .long 0xe1a0300d // mov r3, sp + .long 0xf4e3041f // vld1.16 {d16[0]}, [r3 :16] + .long 0xf3c80a30 // vmovl.u8 q8, d16 + .long 0xf3d00a30 // vmovl.u16 q8, d16 + .long 0xf3fb06a0 // vcvt.f32.u32 d16, d16 + .long 0xeddf1b06 // vldr d17, [pc, #24] + .long 0xf3400db1 // vmul.f32 d16, d16, d17 + .long 0xf3000d90 // vmul.f32 d0, d16, d0 + .long 0xf3001d91 // vmul.f32 d1, d16, d1 + .long 0xf3002d92 // vmul.f32 d2, d16, d2 + .long 0xf3003d93 // vmul.f32 d3, d16, d3 + .long 0xe28dd004 // add sp, sp, #4 + .long 0xe12fff1c // bx ip + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_lerp_1_float_vfp4 +.globl _sk_lerp_1_float_vfp4 +_sk_lerp_1_float_vfp4: + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2600d04 // vsub.f32 d16, d0, d4 + .long 0xf2611d05 // vsub.f32 d17, d1, d5 + .long 0xf2622d06 // vsub.f32 d18, d2, d6 + .long 0xe2811008 // add r1, r1, #8 + .long 0xf2633d07 // vsub.f32 d19, d3, d7 + .long 0xf4e34c9f // vld1.32 {d20[]}, [r3 :32] + .long 0xf2240114 // vorr d0, d4, d4 + .long 0xf2251115 // vorr d1, d5, d5 + .long 0xf2262116 // vorr d2, d6, d6 + .long 0xf2273117 // vorr d3, d7, d7 + .long 0xf2000cb4 // vfma.f32 d0, d16, d20 + .long 0xf2011cb4 // vfma.f32 d1, d17, d20 + .long 0xf2022cb4 // vfma.f32 d2, d18, d20 + .long 0xf2033cb4 // vfma.f32 d3, d19, d20 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_lerp_u8_vfp4 +.globl _sk_lerp_u8_vfp4 +_sk_lerp_u8_vfp4: + .long 0xe24dd004 // sub sp, sp, #4 + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2602d04 // vsub.f32 d18, d0, d4 + .long 0xf2623d06 // vsub.f32 d19, d2, d6 + .long 0xf2634d07 // vsub.f32 d20, d3, d7 + .long 0xe2811008 // add r1, r1, #8 + .long 0xe5933000 // ldr r3, [r3] + .long 0xf2240114 // vorr d0, d4, d4 + .long 0xf2262116 // vorr d2, d6, d6 + .long 0xe0833000 // add r3, r3, r0 + .long 0xf2273117 // vorr d3, d7, d7 + .long 0xe1d330b0 // ldrh r3, [r3] + .long 0xe1cd30b0 // strh r3, [sp] + .long 0xe1a0300d // mov r3, sp + .long 0xf4e3041f // vld1.16 {d16[0]}, [r3 :16] + .long 0xf3c80a30 // vmovl.u8 q8, d16 + .long 0xf3d00a30 // vmovl.u16 q8, d16 + .long 0xf3fb06a0 // vcvt.f32.u32 d16, d16 + .long 0xeddf1b08 // vldr d17, [pc, #32] + .long 0xf3400db1 // vmul.f32 d16, d16, d17 + .long 0xf2611d05 // vsub.f32 d17, d1, d5 + .long 0xf2251115 // vorr d1, d5, d5 + .long 0xf2020cb0 // vfma.f32 d0, d18, d16 + .long 0xf2011cb0 // vfma.f32 d1, d17, d16 + .long 0xf2032cb0 // vfma.f32 d2, d19, d16 + .long 0xf2043cb0 // vfma.f32 d3, d20, d16 + .long 0xe28dd004 // add sp, sp, #4 + .long 0xe12fff1c // bx ip + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_lerp_565_vfp4 +.globl _sk_lerp_565_vfp4 +_sk_lerp_565_vfp4: + .long 0xe24dd004 // sub sp, sp, #4 + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf3c72218 // vmov.i32 d18, #63488 + .long 0xf2c1101f // vmov.i32 d17, #31 + .long 0xf2603d04 // vsub.f32 d19, d0, d4 + .long 0xe2811008 // add r1, r1, #8 + .long 0xe5933000 // ldr r3, [r3] + .long 0xf2616d05 // vsub.f32 d22, d1, d5 + .long 0xf2240114 // vorr d0, d4, d4 + .long 0xf2251115 // vorr d1, d5, d5 + .long 0xe7933080 // ldr r3, [r3, r0, lsl #1] + .long 0xf2873f10 // vmov.f32 d3, #1 + .long 0xe58d3000 // str r3, [sp] + .long 0xe1a0300d // mov r3, sp + .long 0xf4e3083f // vld1.32 {d16[0]}, [r3 :32] + .long 0xe3a03e7e // mov r3, #2016 + .long 0xf3d04a30 // vmovl.u16 q10, d16 + .long 0xee803b90 // vdup.32 d16, r3 + .long 0xf24421b2 // vand d18, d20, d18 + .long 0xf24411b1 // vand d17, d20, d17 + .long 0xeddf5b12 // vldr d21, [pc, #72] + .long 0xf24401b0 // vand d16, d20, d16 + .long 0xeddf4b0e // vldr d20, [pc, #56] + .long 0xf3fb2622 // vcvt.f32.s32 d18, d18 + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3fb1621 // vcvt.f32.s32 d17, d17 + .long 0xf3422db4 // vmul.f32 d18, d18, d20 + .long 0xeddf4b0d // vldr d20, [pc, #52] + .long 0xf3400db5 // vmul.f32 d16, d16, d21 + .long 0xf2625d06 // vsub.f32 d21, d2, d6 + .long 0xf3411db4 // vmul.f32 d17, d17, d20 + .long 0xf2262116 // vorr d2, d6, d6 + .long 0xf2030cb2 // vfma.f32 d0, d19, d18 + .long 0xf2061cb0 // vfma.f32 d1, d22, d16 + .long 0xf2052cb1 // vfma.f32 d2, d21, d17 + .long 0xe28dd004 // add sp, sp, #4 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x37842108 // .word 0x37842108 + .long 0x37842108 // .word 0x37842108 + .long 0x3a020821 // .word 0x3a020821 + .long 0x3a020821 // .word 0x3a020821 + .long 0x3d042108 // .word 0x3d042108 + .long 0x3d042108 // .word 0x3d042108 + +HIDDEN _sk_load_tables_vfp4 +.globl _sk_load_tables_vfp4 +_sk_load_tables_vfp4: + .long 0xe92d48f0 // push {r4, r5, r6, r7, fp, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf3c7001f // vmov.i32 d16, #255 + .long 0xe2811008 // add r1, r1, #8 + .long 0xe593e000 // ldr lr, [r3] + .long 0xe99300b0 // ldmib r3, {r4, r5, r7} + .long 0xe08e3100 // add r3, lr, r0, lsl #2 + .long 0xedd31b00 // vldr d17, [r3] + .long 0xf24121b0 // vand d18, d17, d16 + .long 0xf3f83031 // vshr.u32 d19, d17, #8 + .long 0xee323b90 // vmov.32 r3, d18[1] + .long 0xee126b90 // vmov.32 r6, d18[0] + .long 0xf3f02031 // vshr.u32 d18, d17, #16 + .long 0xf24221b0 // vand d18, d18, d16 + .long 0xf24301b0 // vand d16, d19, d16 + .long 0xe0843103 // add r3, r4, r3, lsl #2 + .long 0xedd30a00 // vldr s1, [r3] + .long 0xe0843106 // add r3, r4, r6, lsl #2 + .long 0xee326b90 // vmov.32 r6, d18[1] + .long 0xed930a00 // vldr s0, [r3] + .long 0xee303b90 // vmov.32 r3, d16[1] + .long 0xee104b90 // vmov.32 r4, d16[0] + .long 0xf3e80031 // vshr.u32 d16, d17, #24 + .long 0xeddf1b0d // vldr d17, [pc, #52] + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3003db1 // vmul.f32 d3, d16, d17 + .long 0xe087e106 // add lr, r7, r6, lsl #2 + .long 0xee126b90 // vmov.32 r6, d18[0] + .long 0xe0853103 // add r3, r5, r3, lsl #2 + .long 0xedde2a00 // vldr s5, [lr] + .long 0xedd31a00 // vldr s3, [r3] + .long 0xe0853104 // add r3, r5, r4, lsl #2 + .long 0xed931a00 // vldr s2, [r3] + .long 0xe0873106 // add r3, r7, r6, lsl #2 + .long 0xed932a00 // vldr s4, [r3] + .long 0xe8bd48f0 // pop {r4, r5, r6, r7, fp, lr} + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_byte_tables_vfp4 +.globl _sk_byte_tables_vfp4 +_sk_byte_tables_vfp4: + .long 0xe92d4bf0 // push {r4, r5, r6, r7, r8, r9, fp, lr} + .long 0xeddf0b37 // vldr d16, [pc, #220] + .long 0xf2c3261f // vmov.i32 d18, #1056964608 + .long 0xf2c3361f // vmov.i32 d19, #1056964608 + .long 0xe8911010 // ldm r1, {r4, ip} + .long 0xf2422c30 // vfma.f32 d18, d2, d16 + .long 0xf2413c30 // vfma.f32 d19, d1, d16 + .long 0xe2811008 // add r1, r1, #8 + .long 0xf2c3461f // vmov.i32 d20, #1056964608 + .long 0xe89402e0 // ldm r4, {r5, r6, r7, r9} + .long 0xf2404c30 // vfma.f32 d20, d0, d16 + .long 0xf2c3161f // vmov.i32 d17, #1056964608 + .long 0xf2431c30 // vfma.f32 d17, d3, d16 + .long 0xf3fb27a2 // vcvt.u32.f32 d18, d18 + .long 0xf3fb37a3 // vcvt.u32.f32 d19, d19 + .long 0xf3fb47a4 // vcvt.u32.f32 d20, d20 + .long 0xee123b90 // vmov.32 r3, d18[0] + .long 0xf3fb07a1 // vcvt.u32.f32 d16, d17 + .long 0xee13eb90 // vmov.32 lr, d19[0] + .long 0xee144b90 // vmov.32 r4, d20[0] + .long 0xe7d78003 // ldrb r8, [r7, r3] + .long 0xe7d6300e // ldrb r3, [r6, lr] + .long 0xee053b90 // vmov.32 d21[0], r3 + .long 0xe7d53004 // ldrb r3, [r5, r4] + .long 0xee344b90 // vmov.32 r4, d20[1] + .long 0xee013b90 // vmov.32 d17[0], r3 + .long 0xee103b90 // vmov.32 r3, d16[0] + .long 0xee048b90 // vmov.32 d20[0], r8 + .long 0xe7d5e004 // ldrb lr, [r5, r4] + .long 0xee334b90 // vmov.32 r4, d19[1] + .long 0xee325b90 // vmov.32 r5, d18[1] + .long 0xf3c7201f // vmov.i32 d18, #255 + .long 0xe7d93003 // ldrb r3, [r9, r3] + .long 0xee21eb90 // vmov.32 d17[1], lr + .long 0xf24111b2 // vand d17, d17, d18 + .long 0xf3fb16a1 // vcvt.f32.u32 d17, d17 + .long 0xe7d64004 // ldrb r4, [r6, r4] + .long 0xee306b90 // vmov.32 r6, d16[1] + .long 0xee003b90 // vmov.32 d16[0], r3 + .long 0xee254b90 // vmov.32 d21[1], r4 + .long 0xe7d74005 // ldrb r4, [r7, r5] + .long 0xf24531b2 // vand d19, d21, d18 + .long 0xee244b90 // vmov.32 d20[1], r4 + .long 0xf24441b2 // vand d20, d20, d18 + .long 0xf3fb46a4 // vcvt.f32.u32 d20, d20 + .long 0xe7d93006 // ldrb r3, [r9, r6] + .long 0xee203b90 // vmov.32 d16[1], r3 + .long 0xf24001b2 // vand d16, d16, d18 + .long 0xf3fb26a3 // vcvt.f32.u32 d18, d19 + .long 0xeddf3b09 // vldr d19, [pc, #36] + .long 0xf3fb06a0 // vcvt.f32.u32 d16, d16 + .long 0xf3010db3 // vmul.f32 d0, d17, d19 + .long 0xf3042db3 // vmul.f32 d2, d20, d19 + .long 0xf3021db3 // vmul.f32 d1, d18, d19 + .long 0xf3003db3 // vmul.f32 d3, d16, d19 + .long 0xe8bd4bf0 // pop {r4, r5, r6, r7, r8, r9, fp, lr} + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x437f0000 // .word 0x437f0000 + .long 0x437f0000 // .word 0x437f0000 + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_byte_tables_rgb_vfp4 +.globl _sk_byte_tables_rgb_vfp4 +_sk_byte_tables_rgb_vfp4: + .long 0xe92d41f0 // push {r4, r5, r6, r7, r8, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2c3261f // vmov.i32 d18, #1056964608 + .long 0xf2c3161f // vmov.i32 d17, #1056964608 + .long 0xf3c7301f // vmov.i32 d19, #255 + .long 0xe2811008 // add r1, r1, #8 + .long 0xe593e000 // ldr lr, [r3] + .long 0xe9930110 // ldmib r3, {r4, r8} + .long 0xe593300c // ldr r3, [r3, #12] + .long 0xe2433001 // sub r3, r3, #1 + .long 0xee803b90 // vdup.32 d16, r3 + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf2402c30 // vfma.f32 d18, d0, d16 + .long 0xf2411c30 // vfma.f32 d17, d1, d16 + .long 0xf3fb27a2 // vcvt.u32.f32 d18, d18 + .long 0xf3fb17a1 // vcvt.u32.f32 d17, d17 + .long 0xee123b90 // vmov.32 r3, d18[0] + .long 0xee326b90 // vmov.32 r6, d18[1] + .long 0xf2c3261f // vmov.i32 d18, #1056964608 + .long 0xf2422c30 // vfma.f32 d18, d2, d16 + .long 0xf3fb07a2 // vcvt.u32.f32 d16, d18 + .long 0xee107b90 // vmov.32 r7, d16[0] + .long 0xee305b90 // vmov.32 r5, d16[1] + .long 0xe7de3003 // ldrb r3, [lr, r3] + .long 0xe7dee006 // ldrb lr, [lr, r6] + .long 0xee116b90 // vmov.32 r6, d17[0] + .long 0xee023b90 // vmov.32 d18[0], r3 + .long 0xee313b90 // vmov.32 r3, d17[1] + .long 0xee22eb90 // vmov.32 d18[1], lr + .long 0xf24221b3 // vand d18, d18, d19 + .long 0xf3fb26a2 // vcvt.f32.u32 d18, d18 + .long 0xe7d87007 // ldrb r7, [r8, r7] + .long 0xee017b90 // vmov.32 d17[0], r7 + .long 0xe7d46006 // ldrb r6, [r4, r6] + .long 0xe7d43003 // ldrb r3, [r4, r3] + .long 0xee006b90 // vmov.32 d16[0], r6 + .long 0xe7d84005 // ldrb r4, [r8, r5] + .long 0xee203b90 // vmov.32 d16[1], r3 + .long 0xee214b90 // vmov.32 d17[1], r4 + .long 0xf24001b3 // vand d16, d16, d19 + .long 0xf24111b3 // vand d17, d17, d19 + .long 0xeddf3b07 // vldr d19, [pc, #28] + .long 0xf3fb06a0 // vcvt.f32.u32 d16, d16 + .long 0xf3fb16a1 // vcvt.f32.u32 d17, d17 + .long 0xf3020db3 // vmul.f32 d0, d18, d19 + .long 0xf3001db3 // vmul.f32 d1, d16, d19 + .long 0xf3012db3 // vmul.f32 d2, d17, d19 + .long 0xe8bd41f0 // pop {r4, r5, r6, r7, r8, lr} + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_load_a8_vfp4 +.globl _sk_load_a8_vfp4 +_sk_load_a8_vfp4: + .long 0xe24dd004 // sub sp, sp, #4 + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xf2800010 // vmov.i32 d0, #0 + .long 0xf2801010 // vmov.i32 d1, #0 + .long 0xe5933000 // ldr r3, [r3] + .long 0xf2802010 // vmov.i32 d2, #0 + .long 0xe0833000 // add r3, r3, r0 + .long 0xe1d330b0 // ldrh r3, [r3] + .long 0xe1cd30b0 // strh r3, [sp] + .long 0xe1a0300d // mov r3, sp + .long 0xf4e3041f // vld1.16 {d16[0]}, [r3 :16] + .long 0xf3c80a30 // vmovl.u8 q8, d16 + .long 0xf3d00a30 // vmovl.u16 q8, d16 + .long 0xf3fb06a0 // vcvt.f32.u32 d16, d16 + .long 0xeddf1b03 // vldr d17, [pc, #12] + .long 0xf3003db1 // vmul.f32 d3, d16, d17 + .long 0xe28dd004 // add sp, sp, #4 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_gather_a8_vfp4 +.globl _sk_gather_a8_vfp4 +_sk_gather_a8_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf3fb0701 // vcvt.s32.f32 d16, d1 + .long 0xf3fb1700 // vcvt.s32.f32 d17, d0 + .long 0xe2811008 // add r1, r1, #8 + .long 0xf2800010 // vmov.i32 d0, #0 + .long 0xe493e008 // ldr lr, [r3], #8 + .long 0xf2801010 // vmov.i32 d1, #0 + .long 0xf2802010 // vmov.i32 d2, #0 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf26219a0 // vmla.i32 d17, d18, d16 + .long 0xee113b90 // vmov.32 r3, d17[0] + .long 0xee314b90 // vmov.32 r4, d17[1] + .long 0xf3c7101f // vmov.i32 d17, #255 + .long 0xe7de3003 // ldrb r3, [lr, r3] + .long 0xe7de4004 // ldrb r4, [lr, r4] + .long 0xee003b90 // vmov.32 d16[0], r3 + .long 0xee204b90 // vmov.32 d16[1], r4 + .long 0xf24001b1 // vand d16, d16, d17 + .long 0xeddf1b03 // vldr d17, [pc, #12] + .long 0xf3fb06a0 // vcvt.f32.u32 d16, d16 + .long 0xf3003db1 // vmul.f32 d3, d16, d17 + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff1c // bx ip + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_store_a8_vfp4 +.globl _sk_store_a8_vfp4 +_sk_store_a8_vfp4: + .long 0xe92d4800 // push {fp, lr} + .long 0xeddf0b0d // vldr d16, [pc, #52] + .long 0xf2c3161f // vmov.i32 d17, #1056964608 + .long 0xf2431c30 // vfma.f32 d17, d3, d16 + .long 0xe5913000 // ldr r3, [r1] + .long 0xe5933000 // ldr r3, [r3] + .long 0xf3fb07a1 // vcvt.u32.f32 d16, d17 + .long 0xee10eb90 // vmov.32 lr, d16[0] + .long 0xee30cb90 // vmov.32 ip, d16[1] + .long 0xe7e3e000 // strb lr, [r3, r0]! + .long 0xe5c3c001 // strb ip, [r3, #1] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe8bd4800 // pop {fp, lr} + .long 0xe12fff1c // bx ip + .long 0x437f0000 // .word 0x437f0000 + .long 0x437f0000 // .word 0x437f0000 + +HIDDEN _sk_load_g8_vfp4 +.globl _sk_load_g8_vfp4 +_sk_load_g8_vfp4: + .long 0xe24dd004 // sub sp, sp, #4 + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xf2873f10 // vmov.f32 d3, #1 + .long 0xe5933000 // ldr r3, [r3] + .long 0xe0833000 // add r3, r3, r0 + .long 0xe1d330b0 // ldrh r3, [r3] + .long 0xe1cd30b0 // strh r3, [sp] + .long 0xe1a0300d // mov r3, sp + .long 0xf4e3041f // vld1.16 {d16[0]}, [r3 :16] + .long 0xf3c80a30 // vmovl.u8 q8, d16 + .long 0xf3d00a30 // vmovl.u16 q8, d16 + .long 0xf3fb06a0 // vcvt.f32.u32 d16, d16 + .long 0xeddf1b05 // vldr d17, [pc, #20] + .long 0xf3000db1 // vmul.f32 d0, d16, d17 + .long 0xf2201110 // vorr d1, d0, d0 + .long 0xf2202110 // vorr d2, d0, d0 + .long 0xe28dd004 // add sp, sp, #4 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_gather_g8_vfp4 +.globl _sk_gather_g8_vfp4 +_sk_gather_g8_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf3fb0701 // vcvt.s32.f32 d16, d1 + .long 0xf3fb1700 // vcvt.s32.f32 d17, d0 + .long 0xe2811008 // add r1, r1, #8 + .long 0xf2873f10 // vmov.f32 d3, #1 + .long 0xe493e008 // ldr lr, [r3], #8 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf26219a0 // vmla.i32 d17, d18, d16 + .long 0xee113b90 // vmov.32 r3, d17[0] + .long 0xee314b90 // vmov.32 r4, d17[1] + .long 0xf3c7101f // vmov.i32 d17, #255 + .long 0xe7de3003 // ldrb r3, [lr, r3] + .long 0xe7de4004 // ldrb r4, [lr, r4] + .long 0xee003b90 // vmov.32 d16[0], r3 + .long 0xee204b90 // vmov.32 d16[1], r4 + .long 0xf24001b1 // vand d16, d16, d17 + .long 0xeddf1b05 // vldr d17, [pc, #20] + .long 0xf3fb06a0 // vcvt.f32.u32 d16, d16 + .long 0xf3000db1 // vmul.f32 d0, d16, d17 + .long 0xf2201110 // vorr d1, d0, d0 + .long 0xf2202110 // vorr d2, d0, d0 + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff1c // bx ip + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_gather_i8_vfp4 +.globl _sk_gather_i8_vfp4 +_sk_gather_i8_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe1a0e001 // mov lr, r1 + .long 0xe491c004 // ldr ip, [r1], #4 + .long 0xf3fb0701 // vcvt.s32.f32 d16, d1 + .long 0xe35c0000 // cmp ip, #0 + .long 0xf3fb1700 // vcvt.s32.f32 d17, d0 + .long 0xe1a0300c // mov r3, ip + .long 0x028e1008 // addeq r1, lr, #8 + .long 0x059e3004 // ldreq r3, [lr, #4] + .long 0xe493e008 // ldr lr, [r3], #8 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf26219a0 // vmla.i32 d17, d18, d16 + .long 0xee113b90 // vmov.32 r3, d17[0] + .long 0xee314b90 // vmov.32 r4, d17[1] + .long 0xf3c7101f // vmov.i32 d17, #255 + .long 0xe7de3003 // ldrb r3, [lr, r3] + .long 0xe7de4004 // ldrb r4, [lr, r4] + .long 0xee003b90 // vmov.32 d16[0], r3 + .long 0xee204b90 // vmov.32 d16[1], r4 + .long 0xe59c4004 // ldr r4, [ip, #4] + .long 0xf24001b1 // vand d16, d16, d17 + .long 0xee103b90 // vmov.32 r3, d16[0] + .long 0xee30eb90 // vmov.32 lr, d16[1] + .long 0xe0843103 // add r3, r4, r3, lsl #2 + .long 0xf4e3083f // vld1.32 {d16[0]}, [r3 :32] + .long 0xe084310e // add r3, r4, lr, lsl #2 + .long 0xf4e308bf // vld1.32 {d16[1]}, [r3 :32] + .long 0xf24021b1 // vand d18, d16, d17 + .long 0xf3f83030 // vshr.u32 d19, d16, #8 + .long 0xf3e84030 // vshr.u32 d20, d16, #24 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3f00030 // vshr.u32 d16, d16, #16 + .long 0xf24331b1 // vand d19, d19, d17 + .long 0xf24001b1 // vand d16, d16, d17 + .long 0xeddf1b0a // vldr d17, [pc, #40] + .long 0xf3fb2622 // vcvt.f32.s32 d18, d18 + .long 0xf3fb4624 // vcvt.f32.s32 d20, d20 + .long 0xf3fb3623 // vcvt.f32.s32 d19, d19 + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3020db1 // vmul.f32 d0, d18, d17 + .long 0xf3043db1 // vmul.f32 d3, d20, d17 + .long 0xf3031db1 // vmul.f32 d1, d19, d17 + .long 0xf3002db1 // vmul.f32 d2, d16, d17 + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff13 // bx r3 + .long 0xe320f000 // nop {0} + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_load_565_vfp4 +.globl _sk_load_565_vfp4 +_sk_load_565_vfp4: + .long 0xe24dd004 // sub sp, sp, #4 + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2c1101f // vmov.i32 d17, #31 + .long 0xf3c72218 // vmov.i32 d18, #63488 + .long 0xeddf3b16 // vldr d19, [pc, #88] + .long 0xe2811008 // add r1, r1, #8 + .long 0xe5933000 // ldr r3, [r3] + .long 0xf2873f10 // vmov.f32 d3, #1 + .long 0xe7933080 // ldr r3, [r3, r0, lsl #1] + .long 0xe58d3000 // str r3, [sp] + .long 0xe1a0300d // mov r3, sp + .long 0xf4e3083f // vld1.32 {d16[0]}, [r3 :32] + .long 0xe3a03e7e // mov r3, #2016 + .long 0xf3d04a30 // vmovl.u16 q10, d16 + .long 0xee803b90 // vdup.32 d16, r3 + .long 0xf24411b1 // vand d17, d20, d17 + .long 0xeddf5b0e // vldr d21, [pc, #56] + .long 0xf24421b2 // vand d18, d20, d18 + .long 0xf24401b0 // vand d16, d20, d16 + .long 0xeddf4b09 // vldr d20, [pc, #36] + .long 0xf3fb2622 // vcvt.f32.s32 d18, d18 + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3fb1621 // vcvt.f32.s32 d17, d17 + .long 0xf3020db3 // vmul.f32 d0, d18, d19 + .long 0xf3001db4 // vmul.f32 d1, d16, d20 + .long 0xf3012db5 // vmul.f32 d2, d17, d21 + .long 0xe28dd004 // add sp, sp, #4 + .long 0xe12fff1c // bx ip + .long 0x37842108 // .word 0x37842108 + .long 0x37842108 // .word 0x37842108 + .long 0x3a020821 // .word 0x3a020821 + .long 0x3a020821 // .word 0x3a020821 + .long 0x3d042108 // .word 0x3d042108 + .long 0x3d042108 // .word 0x3d042108 + +HIDDEN _sk_gather_565_vfp4 +.globl _sk_gather_565_vfp4 +_sk_gather_565_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf3fb0701 // vcvt.s32.f32 d16, d1 + .long 0xf3fb1700 // vcvt.s32.f32 d17, d0 + .long 0xeddf4b20 // vldr d20, [pc, #128] + .long 0xe2811008 // add r1, r1, #8 + .long 0xe493e008 // ldr lr, [r3], #8 + .long 0xf2873f10 // vmov.f32 d3, #1 + .long 0xeddf5b1e // vldr d21, [pc, #120] + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf26219a0 // vmla.i32 d17, d18, d16 + .long 0xf2c1201f // vmov.i32 d18, #31 + .long 0xee113b90 // vmov.32 r3, d17[0] + .long 0xee314b90 // vmov.32 r4, d17[1] + .long 0xf3c71218 // vmov.i32 d17, #63488 + .long 0xe08e3083 // add r3, lr, r3, lsl #1 + .long 0xe08e4084 // add r4, lr, r4, lsl #1 + .long 0xe1d330b0 // ldrh r3, [r3] + .long 0xe1d440b0 // ldrh r4, [r4] + .long 0xee003b90 // vmov.32 d16[0], r3 + .long 0xe3a03e7e // mov r3, #2016 + .long 0xee833b90 // vdup.32 d19, r3 + .long 0xee204b90 // vmov.32 d16[1], r4 + .long 0xf24011b1 // vand d17, d16, d17 + .long 0xf24031b3 // vand d19, d16, d19 + .long 0xf24001b2 // vand d16, d16, d18 + .long 0xf3fb2623 // vcvt.f32.s32 d18, d19 + .long 0xeddf3b07 // vldr d19, [pc, #28] + .long 0xf3fb1621 // vcvt.f32.s32 d17, d17 + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3021db4 // vmul.f32 d1, d18, d20 + .long 0xf3010db3 // vmul.f32 d0, d17, d19 + .long 0xf3002db5 // vmul.f32 d2, d16, d21 + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x37842108 // .word 0x37842108 + .long 0x37842108 // .word 0x37842108 + .long 0x3a020821 // .word 0x3a020821 + .long 0x3a020821 // .word 0x3a020821 + .long 0x3d042108 // .word 0x3d042108 + .long 0x3d042108 // .word 0x3d042108 + +HIDDEN _sk_store_565_vfp4 +.globl _sk_store_565_vfp4 +_sk_store_565_vfp4: + .long 0xf2c30f1f // vmov.f32 d16, #31 + .long 0xeddf1b15 // vldr d17, [pc, #84] + .long 0xf2c3361f // vmov.i32 d19, #1056964608 + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2413c31 // vfma.f32 d19, d1, d17 + .long 0xf2c3161f // vmov.i32 d17, #1056964608 + .long 0xf2401c30 // vfma.f32 d17, d0, d16 + .long 0xe5933000 // ldr r3, [r3] + .long 0xf2c3261f // vmov.i32 d18, #1056964608 + .long 0xf2422c30 // vfma.f32 d18, d2, d16 + .long 0xe0833080 // add r3, r3, r0, lsl #1 + .long 0xf3fb07a3 // vcvt.u32.f32 d16, d19 + .long 0xf3fb17a1 // vcvt.u32.f32 d17, d17 + .long 0xf3fb27a2 // vcvt.u32.f32 d18, d18 + .long 0xf2e50530 // vshl.s32 d16, d16, #5 + .long 0xf2eb1531 // vshl.s32 d17, d17, #11 + .long 0xf26001b1 // vorr d16, d16, d17 + .long 0xf26001b2 // vorr d16, d16, d18 + .long 0xf3f60121 // vuzp.16 d16, d17 + .long 0xf4c3080f // vst1.32 {d16[0]}, [r3] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0x427c0000 // .word 0x427c0000 + .long 0x427c0000 // .word 0x427c0000 + +HIDDEN _sk_load_4444_vfp4 +.globl _sk_load_4444_vfp4 +_sk_load_4444_vfp4: + .long 0xe24dd004 // sub sp, sp, #4 + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf3c71210 // vmov.i32 d17, #61440 + .long 0xf3c74010 // vmov.i32 d20, #240 + .long 0xf2c0501f // vmov.i32 d21, #15 + .long 0xeddf6b1d // vldr d22, [pc, #116] + .long 0xe5933000 // ldr r3, [r3] + .long 0xe2811008 // add r1, r1, #8 + .long 0xe7933080 // ldr r3, [r3, r0, lsl #1] + .long 0xe58d3000 // str r3, [sp] + .long 0xe1a0300d // mov r3, sp + .long 0xf4e3083f // vld1.32 {d16[0]}, [r3 :32] + .long 0xf3d02a30 // vmovl.u16 q9, d16 + .long 0xf2c0021f // vmov.i32 d16, #3840 + .long 0xf24211b1 // vand d17, d18, d17 + .long 0xf24201b0 // vand d16, d18, d16 + .long 0xf24241b4 // vand d20, d18, d20 + .long 0xf24221b5 // vand d18, d18, d21 + .long 0xeddf3b0c // vldr d19, [pc, #48] + .long 0xf3fb1621 // vcvt.f32.s32 d17, d17 + .long 0xeddf5b0c // vldr d21, [pc, #48] + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3fb4624 // vcvt.f32.s32 d20, d20 + .long 0xf3fb2622 // vcvt.f32.s32 d18, d18 + .long 0xf3010db3 // vmul.f32 d0, d17, d19 + .long 0xeddf1b0b // vldr d17, [pc, #44] + .long 0xf3001db5 // vmul.f32 d1, d16, d21 + .long 0xf3042db6 // vmul.f32 d2, d20, d22 + .long 0xf3023db1 // vmul.f32 d3, d18, d17 + .long 0xe28dd004 // add sp, sp, #4 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x37888889 // .word 0x37888889 + .long 0x37888889 // .word 0x37888889 + .long 0x39888889 // .word 0x39888889 + .long 0x39888889 // .word 0x39888889 + .long 0x3b888889 // .word 0x3b888889 + .long 0x3b888889 // .word 0x3b888889 + .long 0x3d888889 // .word 0x3d888889 + .long 0x3d888889 // .word 0x3d888889 + +HIDDEN _sk_gather_4444_vfp4 +.globl _sk_gather_4444_vfp4 +_sk_gather_4444_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf3fb0701 // vcvt.s32.f32 d16, d1 + .long 0xf3fb1700 // vcvt.s32.f32 d17, d0 + .long 0xf3c73010 // vmov.i32 d19, #240 + .long 0xeddf5b21 // vldr d21, [pc, #132] + .long 0xe493e008 // ldr lr, [r3], #8 + .long 0xf2c0401f // vmov.i32 d20, #15 + .long 0xeddf6b20 // vldr d22, [pc, #128] + .long 0xe2811008 // add r1, r1, #8 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf26219a0 // vmla.i32 d17, d18, d16 + .long 0xf2c0221f // vmov.i32 d18, #3840 + .long 0xee113b90 // vmov.32 r3, d17[0] + .long 0xee314b90 // vmov.32 r4, d17[1] + .long 0xf3c71210 // vmov.i32 d17, #61440 + .long 0xe08e3083 // add r3, lr, r3, lsl #1 + .long 0xe08e4084 // add r4, lr, r4, lsl #1 + .long 0xe1d330b0 // ldrh r3, [r3] + .long 0xe1d440b0 // ldrh r4, [r4] + .long 0xee003b90 // vmov.32 d16[0], r3 + .long 0xee204b90 // vmov.32 d16[1], r4 + .long 0xf24011b1 // vand d17, d16, d17 + .long 0xf24021b2 // vand d18, d16, d18 + .long 0xf24031b3 // vand d19, d16, d19 + .long 0xf24001b4 // vand d16, d16, d20 + .long 0xeddf4b0a // vldr d20, [pc, #40] + .long 0xf3fb1621 // vcvt.f32.s32 d17, d17 + .long 0xf3fb2622 // vcvt.f32.s32 d18, d18 + .long 0xf3fb3623 // vcvt.f32.s32 d19, d19 + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3010db4 // vmul.f32 d0, d17, d20 + .long 0xeddf1b0a // vldr d17, [pc, #40] + .long 0xf3021db5 // vmul.f32 d1, d18, d21 + .long 0xf3032db6 // vmul.f32 d2, d19, d22 + .long 0xf3003db1 // vmul.f32 d3, d16, d17 + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff1c // bx ip + .long 0x37888889 // .word 0x37888889 + .long 0x37888889 // .word 0x37888889 + .long 0x39888889 // .word 0x39888889 + .long 0x39888889 // .word 0x39888889 + .long 0x3b888889 // .word 0x3b888889 + .long 0x3b888889 // .word 0x3b888889 + .long 0x3d888889 // .word 0x3d888889 + .long 0x3d888889 // .word 0x3d888889 + +HIDDEN _sk_store_4444_vfp4 +.globl _sk_store_4444_vfp4 +_sk_store_4444_vfp4: + .long 0xf2c20f1e // vmov.f32 d16, #15 + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c3261f // vmov.i32 d18, #1056964608 + .long 0xf2c3361f // vmov.i32 d19, #1056964608 + .long 0xf2402c30 // vfma.f32 d18, d0, d16 + .long 0xe5933000 // ldr r3, [r3] + .long 0xf2413c30 // vfma.f32 d19, d1, d16 + .long 0xf2c3461f // vmov.i32 d20, #1056964608 + .long 0xe0833080 // add r3, r3, r0, lsl #1 + .long 0xf2424c30 // vfma.f32 d20, d2, d16 + .long 0xf2c3161f // vmov.i32 d17, #1056964608 + .long 0xf2431c30 // vfma.f32 d17, d3, d16 + .long 0xf3fb07a2 // vcvt.u32.f32 d16, d18 + .long 0xf3fb27a3 // vcvt.u32.f32 d18, d19 + .long 0xf3fb37a4 // vcvt.u32.f32 d19, d20 + .long 0xf2ec0530 // vshl.s32 d16, d16, #12 + .long 0xf2e82532 // vshl.s32 d18, d18, #8 + .long 0xf3fb17a1 // vcvt.u32.f32 d17, d17 + .long 0xf2e43533 // vshl.s32 d19, d19, #4 + .long 0xf26201b0 // vorr d16, d18, d16 + .long 0xf26001b3 // vorr d16, d16, d19 + .long 0xf26001b1 // vorr d16, d16, d17 + .long 0xf3f60121 // vuzp.16 d16, d17 + .long 0xf4c3080f // vst1.32 {d16[0]}, [r3] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_load_8888_vfp4 +.globl _sk_load_8888_vfp4 +_sk_load_8888_vfp4: + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf3c7001f // vmov.i32 d16, #255 + .long 0xe2811008 // add r1, r1, #8 + .long 0xe5933000 // ldr r3, [r3] + .long 0xe0833100 // add r3, r3, r0, lsl #2 + .long 0xedd31b00 // vldr d17, [r3] + .long 0xf24121b0 // vand d18, d17, d16 + .long 0xf3f83031 // vshr.u32 d19, d17, #8 + .long 0xf3e84031 // vshr.u32 d20, d17, #24 + .long 0xf3f01031 // vshr.u32 d17, d17, #16 + .long 0xf24331b0 // vand d19, d19, d16 + .long 0xf24101b0 // vand d16, d17, d16 + .long 0xeddf1b08 // vldr d17, [pc, #32] + .long 0xf3fb2622 // vcvt.f32.s32 d18, d18 + .long 0xf3fb4624 // vcvt.f32.s32 d20, d20 + .long 0xf3fb3623 // vcvt.f32.s32 d19, d19 + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3020db1 // vmul.f32 d0, d18, d17 + .long 0xf3043db1 // vmul.f32 d3, d20, d17 + .long 0xf3031db1 // vmul.f32 d1, d19, d17 + .long 0xf3002db1 // vmul.f32 d2, d16, d17 + .long 0xe12fff1c // bx ip + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_gather_8888_vfp4 +.globl _sk_gather_8888_vfp4 +_sk_gather_8888_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf3fb0701 // vcvt.s32.f32 d16, d1 + .long 0xf3fb1700 // vcvt.s32.f32 d17, d0 + .long 0xe2811008 // add r1, r1, #8 + .long 0xe493e008 // ldr lr, [r3], #8 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf26219a0 // vmla.i32 d17, d18, d16 + .long 0xee113b90 // vmov.32 r3, d17[0] + .long 0xee314b90 // vmov.32 r4, d17[1] + .long 0xf3c7101f // vmov.i32 d17, #255 + .long 0xe08e3103 // add r3, lr, r3, lsl #2 + .long 0xf4e3083f // vld1.32 {d16[0]}, [r3 :32] + .long 0xe08e3104 // add r3, lr, r4, lsl #2 + .long 0xf4e308bf // vld1.32 {d16[1]}, [r3 :32] + .long 0xf24021b1 // vand d18, d16, d17 + .long 0xf3f83030 // vshr.u32 d19, d16, #8 + .long 0xf3e84030 // vshr.u32 d20, d16, #24 + .long 0xf3f00030 // vshr.u32 d16, d16, #16 + .long 0xf24331b1 // vand d19, d19, d17 + .long 0xf24001b1 // vand d16, d16, d17 + .long 0xeddf1b09 // vldr d17, [pc, #36] + .long 0xf3fb2622 // vcvt.f32.s32 d18, d18 + .long 0xf3fb4624 // vcvt.f32.s32 d20, d20 + .long 0xf3fb3623 // vcvt.f32.s32 d19, d19 + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3020db1 // vmul.f32 d0, d18, d17 + .long 0xf3043db1 // vmul.f32 d3, d20, d17 + .long 0xf3031db1 // vmul.f32 d1, d19, d17 + .long 0xf3002db1 // vmul.f32 d2, d16, d17 + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff1c // bx ip + .long 0x3b808081 // .word 0x3b808081 + .long 0x3b808081 // .word 0x3b808081 + +HIDDEN _sk_store_8888_vfp4 +.globl _sk_store_8888_vfp4 +_sk_store_8888_vfp4: + .long 0xeddf0b1a // vldr d16, [pc, #104] + .long 0xf2c3261f // vmov.i32 d18, #1056964608 + .long 0xf2412c30 // vfma.f32 d18, d1, d16 + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c3361f // vmov.i32 d19, #1056964608 + .long 0xf2c3161f // vmov.i32 d17, #1056964608 + .long 0xf2423c30 // vfma.f32 d19, d2, d16 + .long 0xe5933000 // ldr r3, [r3] + .long 0xf2c3461f // vmov.i32 d20, #1056964608 + .long 0xf2401c30 // vfma.f32 d17, d0, d16 + .long 0xe0833100 // add r3, r3, r0, lsl #2 + .long 0xf2434c30 // vfma.f32 d20, d3, d16 + .long 0xf3fb07a2 // vcvt.u32.f32 d16, d18 + .long 0xf3fb27a3 // vcvt.u32.f32 d18, d19 + .long 0xf3fb17a1 // vcvt.u32.f32 d17, d17 + .long 0xf3fb37a4 // vcvt.u32.f32 d19, d20 + .long 0xf2e80530 // vshl.s32 d16, d16, #8 + .long 0xf2f02532 // vshl.s32 d18, d18, #16 + .long 0xf26001b1 // vorr d16, d16, d17 + .long 0xf2f81533 // vshl.s32 d17, d19, #24 + .long 0xf26001b2 // vorr d16, d16, d18 + .long 0xf26001b1 // vorr d16, d16, d17 + .long 0xedc30b00 // vstr d16, [r3] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x437f0000 // .word 0x437f0000 + .long 0x437f0000 // .word 0x437f0000 + +HIDDEN _sk_load_f16_vfp4 +.globl _sk_load_f16_vfp4 +_sk_load_f16_vfp4: + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xe5933000 // ldr r3, [r3] + .long 0xe0833180 // add r3, r3, r0, lsl #3 + .long 0xf4e3070d // vld4.16 {d16[0],d17[0],d18[0],d19[0]}, [r3]! + .long 0xf4e3074f // vld4.16 {d16[1],d17[1],d18[1],d19[1]}, [r3] + .long 0xf3b60720 // vcvt.f32.f16 q0, d16 + .long 0xf3b62722 // vcvt.f32.f16 q1, d18 + .long 0xf3f64721 // vcvt.f32.f16 q10, d17 + .long 0xf3f60723 // vcvt.f32.f16 q8, d19 + .long 0xf22411b4 // vorr d1, d20, d20 + .long 0xf22031b0 // vorr d3, d16, d16 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_gather_f16_vfp4 +.globl _sk_gather_f16_vfp4 +_sk_gather_f16_vfp4: + .long 0xe92d4c10 // push {r4, sl, fp, lr} + .long 0xe28db008 // add fp, sp, #8 + .long 0xe24dd010 // sub sp, sp, #16 + .long 0xe7c3d01f // bfc sp, #0, #4 + .long 0xe5913000 // ldr r3, [r1] + .long 0xf3fb0701 // vcvt.s32.f32 d16, d1 + .long 0xf3fb1700 // vcvt.s32.f32 d17, d0 + .long 0xe493c008 // ldr ip, [r3], #8 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf26219a0 // vmla.i32 d17, d18, d16 + .long 0xee113b90 // vmov.32 r3, d17[0] + .long 0xee31eb90 // vmov.32 lr, d17[1] + .long 0xe08c4183 // add r4, ip, r3, lsl #3 + .long 0xe08c318e // add r3, ip, lr, lsl #3 + .long 0xedd31b00 // vldr d17, [r3] + .long 0xe1a0300d // mov r3, sp + .long 0xedd40b00 // vldr d16, [r4] + .long 0xf4430aef // vst1.64 {d16-d17}, [r3 :128] + .long 0xf4e3071f // vld4.16 {d16[0],d17[0],d18[0],d19[0]}, [r3 :64] + .long 0xe3833008 // orr r3, r3, #8 + .long 0xf4e3075f // vld4.16 {d16[1],d17[1],d18[1],d19[1]}, [r3 :64] + .long 0xf3b60720 // vcvt.f32.f16 q0, d16 + .long 0xf3b62722 // vcvt.f32.f16 q1, d18 + .long 0xe5913004 // ldr r3, [r1, #4] + .long 0xe2811008 // add r1, r1, #8 + .long 0xf3f64721 // vcvt.f32.f16 q10, d17 + .long 0xf3f60723 // vcvt.f32.f16 q8, d19 + .long 0xf22411b4 // vorr d1, d20, d20 + .long 0xf22031b0 // vorr d3, d16, d16 + .long 0xe12fff33 // blx r3 + .long 0xe24bd008 // sub sp, fp, #8 + .long 0xe8bd8c10 // pop {r4, sl, fp, pc} + +HIDDEN _sk_store_f16_vfp4 +.globl _sk_store_f16_vfp4 +_sk_store_f16_vfp4: + .long 0xf2630113 // vorr d16, d3, d3 + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2612111 // vorr d18, d1, d1 + .long 0xf3f67620 // vcvt.f16.f32 d23, q8 + .long 0xe5933000 // ldr r3, [r3] + .long 0xf3f66602 // vcvt.f16.f32 d22, q1 + .long 0xe0833180 // add r3, r3, r0, lsl #3 + .long 0xf3f65622 // vcvt.f16.f32 d21, q9 + .long 0xf3f64600 // vcvt.f16.f32 d20, q0 + .long 0xf22211b2 // vorr d1, d18, d18 + .long 0xf22031b0 // vorr d3, d16, d16 + .long 0xf4c3470d // vst4.16 {d20[0],d21[0],d22[0],d23[0]}, [r3]! + .long 0xf4c3474f // vst4.16 {d20[1],d21[1],d22[1],d23[1]}, [r3] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_load_u16_be_vfp4 +.globl _sk_load_u16_be_vfp4 +_sk_load_u16_be_vfp4: + .long 0xe92d48f0 // push {r4, r5, r6, r7, fp, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xe5933000 // ldr r3, [r3] + .long 0xe0833180 // add r3, r3, r0, lsl #3 + .long 0xf4e3070d // vld4.16 {d16[0],d17[0],d18[0],d19[0]}, [r3]! + .long 0xf4e3074f // vld4.16 {d16[1],d17[1],d18[1],d19[1]}, [r3] + .long 0xee903bb0 // vmov.u16 r3, d16[0] + .long 0xee92ebb0 // vmov.u16 lr, d18[0] + .long 0xee914bb0 // vmov.u16 r4, d17[0] + .long 0xee937bb0 // vmov.u16 r7, d19[0] + .long 0xee905bf0 // vmov.u16 r5, d16[1] + .long 0xee926bf0 // vmov.u16 r6, d18[1] + .long 0xee043b90 // vmov.32 d20[0], r3 + .long 0xee05eb90 // vmov.32 d21[0], lr + .long 0xee93ebf0 // vmov.u16 lr, d19[1] + .long 0xee913bf0 // vmov.u16 r3, d17[1] + .long 0xf3c71c1f // vmov.i32 d17, #65535 + .long 0xee004b90 // vmov.32 d16[0], r4 + .long 0xee027b90 // vmov.32 d18[0], r7 + .long 0xee245b90 // vmov.32 d20[1], r5 + .long 0xf24431b1 // vand d19, d20, d17 + .long 0xee256b90 // vmov.32 d21[1], r6 + .long 0xf2e84534 // vshl.s32 d20, d20, #8 + .long 0xf24561b1 // vand d22, d21, d17 + .long 0xf3f83033 // vshr.u32 d19, d19, #8 + .long 0xf2e85535 // vshl.s32 d21, d21, #8 + .long 0xf26431b3 // vorr d19, d20, d19 + .long 0xf3f86036 // vshr.u32 d22, d22, #8 + .long 0xf24331b1 // vand d19, d19, d17 + .long 0xf26551b6 // vorr d21, d21, d22 + .long 0xf3fb36a3 // vcvt.f32.u32 d19, d19 + .long 0xee22eb90 // vmov.32 d18[1], lr + .long 0xee203b90 // vmov.32 d16[1], r3 + .long 0xf24281b1 // vand d24, d18, d17 + .long 0xf2e82532 // vshl.s32 d18, d18, #8 + .long 0xf24071b1 // vand d23, d16, d17 + .long 0xf3f84038 // vshr.u32 d20, d24, #8 + .long 0xf2e80530 // vshl.s32 d16, d16, #8 + .long 0xf3f87037 // vshr.u32 d23, d23, #8 + .long 0xf26221b4 // vorr d18, d18, d20 + .long 0xf26001b7 // vorr d16, d16, d23 + .long 0xf24541b1 // vand d20, d21, d17 + .long 0xf24001b1 // vand d16, d16, d17 + .long 0xf24211b1 // vand d17, d18, d17 + .long 0xeddf2b09 // vldr d18, [pc, #36] + .long 0xf3fb06a0 // vcvt.f32.u32 d16, d16 + .long 0xf3fb46a4 // vcvt.f32.u32 d20, d20 + .long 0xf3fb16a1 // vcvt.f32.u32 d17, d17 + .long 0xf3030db2 // vmul.f32 d0, d19, d18 + .long 0xf3001db2 // vmul.f32 d1, d16, d18 + .long 0xf3042db2 // vmul.f32 d2, d20, d18 + .long 0xf3013db2 // vmul.f32 d3, d17, d18 + .long 0xe8bd48f0 // pop {r4, r5, r6, r7, fp, lr} + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x37800080 // .word 0x37800080 + .long 0x37800080 // .word 0x37800080 + +HIDDEN _sk_store_u16_be_vfp4 +.globl _sk_store_u16_be_vfp4 +_sk_store_u16_be_vfp4: + .long 0xeddf0b2a // vldr d16, [pc, #168] + .long 0xf2c3261f // vmov.i32 d18, #1056964608 + .long 0xf2c3361f // vmov.i32 d19, #1056964608 + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2432c30 // vfma.f32 d18, d3, d16 + .long 0xf2c3461f // vmov.i32 d20, #1056964608 + .long 0xf2423c30 // vfma.f32 d19, d2, d16 + .long 0xf2c3161f // vmov.i32 d17, #1056964608 + .long 0xf2414c30 // vfma.f32 d20, d1, d16 + .long 0xf2401c30 // vfma.f32 d17, d0, d16 + .long 0xf3fb07a2 // vcvt.u32.f32 d16, d18 + .long 0xf3fb27a3 // vcvt.u32.f32 d18, d19 + .long 0xf3c73c1f // vmov.i32 d19, #65535 + .long 0xf3fb47a4 // vcvt.u32.f32 d20, d20 + .long 0xf3fb17a1 // vcvt.u32.f32 d17, d17 + .long 0xf24051b3 // vand d21, d16, d19 + .long 0xf24261b3 // vand d22, d18, d19 + .long 0xf24471b3 // vand d23, d20, d19 + .long 0xf24131b3 // vand d19, d17, d19 + .long 0xf2e80530 // vshl.s32 d16, d16, #8 + .long 0xf3f85035 // vshr.u32 d21, d21, #8 + .long 0xf2e82532 // vshl.s32 d18, d18, #8 + .long 0xf3f86036 // vshr.u32 d22, d22, #8 + .long 0xf260b1b5 // vorr d27, d16, d21 + .long 0xf2e84534 // vshl.s32 d20, d20, #8 + .long 0xf3f87037 // vshr.u32 d23, d23, #8 + .long 0xf262a1b6 // vorr d26, d18, d22 + .long 0xf2e81531 // vshl.s32 d17, d17, #8 + .long 0xf3f83033 // vshr.u32 d19, d19, #8 + .long 0xf26491b7 // vorr d25, d20, d23 + .long 0xf26181b3 // vorr d24, d17, d19 + .long 0xf3f6b120 // vuzp.16 d27, d16 + .long 0xe5933000 // ldr r3, [r3] + .long 0xf3f6a120 // vuzp.16 d26, d16 + .long 0xe0833180 // add r3, r3, r0, lsl #3 + .long 0xf3f69120 // vuzp.16 d25, d16 + .long 0xf3f68120 // vuzp.16 d24, d16 + .long 0xf4c3870d // vst4.16 {d24[0],d25[0],d26[0],d27[0]}, [r3]! + .long 0xf4c3874f // vst4.16 {d24[1],d25[1],d26[1],d27[1]}, [r3] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x477fff00 // .word 0x477fff00 + .long 0x477fff00 // .word 0x477fff00 + +HIDDEN _sk_load_f32_vfp4 +.globl _sk_load_f32_vfp4 +_sk_load_f32_vfp4: + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xe5933000 // ldr r3, [r3] + .long 0xe0833200 // add r3, r3, r0, lsl #4 + .long 0xf423008f // vld4.32 {d0-d3}, [r3] + .long 0xe12fff1c // bx ip + +HIDDEN _sk_store_f32_vfp4 +.globl _sk_store_f32_vfp4 +_sk_store_f32_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xe5933000 // ldr r3, [r3] + .long 0xe0833200 // add r3, r3, r0, lsl #4 + .long 0xf403008f // vst4.32 {d0-d3}, [r3] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_clamp_x_vfp4 +.globl _sk_clamp_x_vfp4 +_sk_clamp_x_vfp4: + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2c00010 // vmov.i32 d16, #0 + .long 0xf3c71e1f // vmov.i8 d17, #255 + .long 0xf2400f80 // vmax.f32 d16, d16, d0 + .long 0xe2811008 // add r1, r1, #8 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf26218a1 // vadd.i32 d17, d18, d17 + .long 0xf2200fa1 // vmin.f32 d0, d16, d17 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_clamp_y_vfp4 +.globl _sk_clamp_y_vfp4 +_sk_clamp_y_vfp4: + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2c00010 // vmov.i32 d16, #0 + .long 0xf3c71e1f // vmov.i8 d17, #255 + .long 0xf2400f81 // vmax.f32 d16, d16, d1 + .long 0xe2811008 // add r1, r1, #8 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf26218a1 // vadd.i32 d17, d18, d17 + .long 0xf2201fa1 // vmin.f32 d1, d16, d17 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_repeat_x_vfp4 +.globl _sk_repeat_x_vfp4 +_sk_repeat_x_vfp4: + .long 0xed2d8b04 // vpush {d8-d9} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2c02010 // vmov.i32 d18, #0 + .long 0xe2811008 // add r1, r1, #8 + .long 0xeddf3b10 // vldr d19, [pc, #64] + .long 0xed938a00 // vldr s16, [r3] + .long 0xeec09a88 // vdiv.f32 s19, s1, s16 + .long 0xee809a08 // vdiv.f32 s18, s0, s16 + .long 0xf3fb0709 // vcvt.s32.f32 d16, d9 + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3601e89 // vcgt.f32 d17, d16, d9 + .long 0xf35311b2 // vbsl d17, d19, d18 + .long 0xf3f42c08 // vdup.32 d18, d8[0] + .long 0xf2600da1 // vsub.f32 d16, d16, d17 + .long 0xf3c71e1f // vmov.i8 d17, #255 + .long 0xf26218a1 // vadd.i32 d17, d18, d17 + .long 0xf2e009c8 // vmul.f32 d16, d16, d8[0] + .long 0xf2600d20 // vsub.f32 d16, d0, d16 + .long 0xf2200fa1 // vmin.f32 d0, d16, d17 + .long 0xecbd8b04 // vpop {d8-d9} + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3f800000 // .word 0x3f800000 + .long 0x3f800000 // .word 0x3f800000 + +HIDDEN _sk_repeat_y_vfp4 +.globl _sk_repeat_y_vfp4 +_sk_repeat_y_vfp4: + .long 0xed2d8b04 // vpush {d8-d9} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2c02010 // vmov.i32 d18, #0 + .long 0xe2811008 // add r1, r1, #8 + .long 0xeddf3b10 // vldr d19, [pc, #64] + .long 0xed938a00 // vldr s16, [r3] + .long 0xeec19a88 // vdiv.f32 s19, s3, s16 + .long 0xee819a08 // vdiv.f32 s18, s2, s16 + .long 0xf3fb0709 // vcvt.s32.f32 d16, d9 + .long 0xf3fb0620 // vcvt.f32.s32 d16, d16 + .long 0xf3601e89 // vcgt.f32 d17, d16, d9 + .long 0xf35311b2 // vbsl d17, d19, d18 + .long 0xf3f42c08 // vdup.32 d18, d8[0] + .long 0xf2600da1 // vsub.f32 d16, d16, d17 + .long 0xf3c71e1f // vmov.i8 d17, #255 + .long 0xf26218a1 // vadd.i32 d17, d18, d17 + .long 0xf2e009c8 // vmul.f32 d16, d16, d8[0] + .long 0xf2610d20 // vsub.f32 d16, d1, d16 + .long 0xf2201fa1 // vmin.f32 d1, d16, d17 + .long 0xecbd8b04 // vpop {d8-d9} + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3f800000 // .word 0x3f800000 + .long 0x3f800000 // .word 0x3f800000 + +HIDDEN _sk_mirror_x_vfp4 +.globl _sk_mirror_x_vfp4 +_sk_mirror_x_vfp4: + .long 0xed2d8b04 // vpush {d8-d9} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2c03010 // vmov.i32 d19, #0 + .long 0xe2811008 // add r1, r1, #8 + .long 0xeddf4b14 // vldr d20, [pc, #80] + .long 0xed938a00 // vldr s16, [r3] + .long 0xee389a08 // vadd.f32 s18, s16, s16 + .long 0xf3f40c08 // vdup.32 d16, d8[0] + .long 0xf2200d20 // vsub.f32 d0, d0, d16 + .long 0xeec08a89 // vdiv.f32 s17, s1, s18 + .long 0xee808a09 // vdiv.f32 s16, s0, s18 + .long 0xf3fb1708 // vcvt.s32.f32 d17, d8 + .long 0xf3fb1621 // vcvt.f32.s32 d17, d17 + .long 0xf3612e88 // vcgt.f32 d18, d17, d8 + .long 0xf35421b3 // vbsl d18, d20, d19 + .long 0xf2611da2 // vsub.f32 d17, d17, d18 + .long 0xf3c72e1f // vmov.i8 d18, #255 + .long 0xf2e119c9 // vmul.f32 d17, d17, d9[0] + .long 0xf2601d21 // vsub.f32 d17, d0, d17 + .long 0xf2611da0 // vsub.f32 d17, d17, d16 + .long 0xf26008a2 // vadd.i32 d16, d16, d18 + .long 0xf3f91721 // vabs.f32 d17, d17 + .long 0xf2210fa0 // vmin.f32 d0, d17, d16 + .long 0xecbd8b04 // vpop {d8-d9} + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3f800000 // .word 0x3f800000 + .long 0x3f800000 // .word 0x3f800000 + +HIDDEN _sk_mirror_y_vfp4 +.globl _sk_mirror_y_vfp4 +_sk_mirror_y_vfp4: + .long 0xed2d8b04 // vpush {d8-d9} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2c03010 // vmov.i32 d19, #0 + .long 0xe2811008 // add r1, r1, #8 + .long 0xeddf4b14 // vldr d20, [pc, #80] + .long 0xed938a00 // vldr s16, [r3] + .long 0xee389a08 // vadd.f32 s18, s16, s16 + .long 0xf3f40c08 // vdup.32 d16, d8[0] + .long 0xf2211d20 // vsub.f32 d1, d1, d16 + .long 0xeec18a89 // vdiv.f32 s17, s3, s18 + .long 0xee818a09 // vdiv.f32 s16, s2, s18 + .long 0xf3fb1708 // vcvt.s32.f32 d17, d8 + .long 0xf3fb1621 // vcvt.f32.s32 d17, d17 + .long 0xf3612e88 // vcgt.f32 d18, d17, d8 + .long 0xf35421b3 // vbsl d18, d20, d19 + .long 0xf2611da2 // vsub.f32 d17, d17, d18 + .long 0xf3c72e1f // vmov.i8 d18, #255 + .long 0xf2e119c9 // vmul.f32 d17, d17, d9[0] + .long 0xf2611d21 // vsub.f32 d17, d1, d17 + .long 0xf2611da0 // vsub.f32 d17, d17, d16 + .long 0xf26008a2 // vadd.i32 d16, d16, d18 + .long 0xf3f91721 // vabs.f32 d17, d17 + .long 0xf2211fa0 // vmin.f32 d1, d17, d16 + .long 0xecbd8b04 // vpop {d8-d9} + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3f800000 // .word 0x3f800000 + .long 0x3f800000 // .word 0x3f800000 + +HIDDEN _sk_luminance_to_alpha_vfp4 +.globl _sk_luminance_to_alpha_vfp4 +_sk_luminance_to_alpha_vfp4: + .long 0xeddf0b0a // vldr d16, [pc, #40] + .long 0xeddf1b0b // vldr d17, [pc, #44] + .long 0xf3410d30 // vmul.f32 d16, d1, d16 + .long 0xe4913004 // ldr r3, [r1], #4 + .long 0xf3401d31 // vmul.f32 d17, d0, d17 + .long 0xf2800010 // vmov.i32 d0, #0 + .long 0xf2801010 // vmov.i32 d1, #0 + .long 0xf2013da0 // vadd.f32 d3, d17, d16 + .long 0xeddf0b06 // vldr d16, [pc, #24] + .long 0xf2023c30 // vfma.f32 d3, d2, d16 + .long 0xf2802010 // vmov.i32 d2, #0 + .long 0xe12fff13 // bx r3 + .long 0x3f371759 // .word 0x3f371759 + .long 0x3f371759 // .word 0x3f371759 + .long 0x3e59b3d0 // .word 0x3e59b3d0 + .long 0x3e59b3d0 // .word 0x3e59b3d0 + .long 0x3d93dd98 // .word 0x3d93dd98 + .long 0x3d93dd98 // .word 0x3d93dd98 + +HIDDEN _sk_matrix_2x3_vfp4 +.globl _sk_matrix_2x3_vfp4 +_sk_matrix_2x3_vfp4: + .long 0xe92d4800 // push {fp, lr} + .long 0xe591e000 // ldr lr, [r1] + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe2811008 // add r1, r1, #8 + .long 0xe28e300c // add r3, lr, #12 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xe28e3008 // add r3, lr, #8 + .long 0xf4e31c9f // vld1.32 {d17[]}, [r3 :32] + .long 0xe28e3010 // add r3, lr, #16 + .long 0xf4e30c9f // vld1.32 {d16[]}, [r3 :32] + .long 0xe28e3014 // add r3, lr, #20 + .long 0xf2410c31 // vfma.f32 d16, d1, d17 + .long 0xf4e31c9f // vld1.32 {d17[]}, [r3 :32] + .long 0xf2411c32 // vfma.f32 d17, d1, d18 + .long 0xf4ee2c9d // vld1.32 {d18[]}, [lr :32]! + .long 0xf4ee3c9f // vld1.32 {d19[]}, [lr :32] + .long 0xf2400c32 // vfma.f32 d16, d0, d18 + .long 0xf2401c33 // vfma.f32 d17, d0, d19 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xe8bd4800 // pop {fp, lr} + .long 0xe12fff1c // bx ip + +HIDDEN _sk_matrix_3x4_vfp4 +.globl _sk_matrix_3x4_vfp4 +_sk_matrix_3x4_vfp4: + .long 0xe92d4800 // push {fp, lr} + .long 0xe591e000 // ldr lr, [r1] + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe2811008 // add r1, r1, #8 + .long 0xe28e3020 // add r3, lr, #32 + .long 0xf4e33c9f // vld1.32 {d19[]}, [r3 :32] + .long 0xe28e302c // add r3, lr, #44 + .long 0xf4e30c9f // vld1.32 {d16[]}, [r3 :32] + .long 0xe28e301c // add r3, lr, #28 + .long 0xf2420c33 // vfma.f32 d16, d2, d19 + .long 0xf4e34c9f // vld1.32 {d20[]}, [r3 :32] + .long 0xe28e3018 // add r3, lr, #24 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xe28e3024 // add r3, lr, #36 + .long 0xf4e31c9f // vld1.32 {d17[]}, [r3 :32] + .long 0xe28e3028 // add r3, lr, #40 + .long 0xf2421c32 // vfma.f32 d17, d2, d18 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xe28e3010 // add r3, lr, #16 + .long 0xf2422c34 // vfma.f32 d18, d2, d20 + .long 0xf4e33c9f // vld1.32 {d19[]}, [r3 :32] + .long 0xe28e300c // add r3, lr, #12 + .long 0xf4e34c9f // vld1.32 {d20[]}, [r3 :32] + .long 0xe28e3014 // add r3, lr, #20 + .long 0xf2411c34 // vfma.f32 d17, d1, d20 + .long 0xf4e34c9f // vld1.32 {d20[]}, [r3 :32] + .long 0xf2410c34 // vfma.f32 d16, d1, d20 + .long 0xe28e3008 // add r3, lr, #8 + .long 0xf2412c33 // vfma.f32 d18, d1, d19 + .long 0xf4ee3c9d // vld1.32 {d19[]}, [lr :32]! + .long 0xf4ee4c9f // vld1.32 {d20[]}, [lr :32] + .long 0xf2401c33 // vfma.f32 d17, d0, d19 + .long 0xf4e33c9f // vld1.32 {d19[]}, [r3 :32] + .long 0xf2400c33 // vfma.f32 d16, d0, d19 + .long 0xf2402c34 // vfma.f32 d18, d0, d20 + .long 0xf22101b1 // vorr d0, d17, d17 + .long 0xf22021b0 // vorr d2, d16, d16 + .long 0xf22211b2 // vorr d1, d18, d18 + .long 0xe8bd4800 // pop {fp, lr} + .long 0xe12fff1c // bx ip + +HIDDEN _sk_matrix_4x5_vfp4 +.globl _sk_matrix_4x5_vfp4 +_sk_matrix_4x5_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xf2620112 // vorr d16, d2, d2 + .long 0xe2811008 // add r1, r1, #8 + .long 0xe2834014 // add r4, r3, #20 + .long 0xe1a0e003 // mov lr, r3 + .long 0xf4e45c9f // vld1.32 {d21[]}, [r4 :32] + .long 0xe2834028 // add r4, r3, #40 + .long 0xf4e46c9f // vld1.32 {d22[]}, [r4 :32] + .long 0xe2834038 // add r4, r3, #56 + .long 0xf4e47c9f // vld1.32 {d23[]}, [r4 :32] + .long 0xe2834048 // add r4, r3, #72 + .long 0xf4a42c9f // vld1.32 {d2[]}, [r4 :32] + .long 0xe2834034 // add r4, r3, #52 + .long 0xf2032c37 // vfma.f32 d2, d3, d23 + .long 0xf4e48c9f // vld1.32 {d24[]}, [r4 :32] + .long 0xe2834044 // add r4, r3, #68 + .long 0xf4e41c9f // vld1.32 {d17[]}, [r4 :32] + .long 0xe2834030 // add r4, r3, #48 + .long 0xf2431c38 // vfma.f32 d17, d3, d24 + .long 0xf4e49c9f // vld1.32 {d25[]}, [r4 :32] + .long 0xe283403c // add r4, r3, #60 + .long 0xf4e43c9f // vld1.32 {d19[]}, [r4 :32] + .long 0xe283404c // add r4, r3, #76 + .long 0xf2002cb6 // vfma.f32 d2, d16, d22 + .long 0xf4e42c9f // vld1.32 {d18[]}, [r4 :32] + .long 0xe2834040 // add r4, r3, #64 + .long 0xf2432c33 // vfma.f32 d18, d3, d19 + .long 0xf4e43c9f // vld1.32 {d19[]}, [r4 :32] + .long 0xe2834020 // add r4, r3, #32 + .long 0xf2433c39 // vfma.f32 d19, d3, d25 + .long 0xf4e47c9f // vld1.32 {d23[]}, [r4 :32] + .long 0xe283402c // add r4, r3, #44 + .long 0xf4e48c9f // vld1.32 {d24[]}, [r4 :32] + .long 0xe2834024 // add r4, r3, #36 + .long 0xf2402cb8 // vfma.f32 d18, d16, d24 + .long 0xf4e48c9f // vld1.32 {d24[]}, [r4 :32] + .long 0xf2401cb8 // vfma.f32 d17, d16, d24 + .long 0xe2834010 // add r4, r3, #16 + .long 0xf2403cb7 // vfma.f32 d19, d16, d23 + .long 0xf4ee4c9d // vld1.32 {d20[]}, [lr :32]! + .long 0xf4e40c9f // vld1.32 {d16[]}, [r4 :32] + .long 0xe283401c // add r4, r3, #28 + .long 0xf4e46c9f // vld1.32 {d22[]}, [r4 :32] + .long 0xe2834018 // add r4, r3, #24 + .long 0xf2412c36 // vfma.f32 d18, d1, d22 + .long 0xf2411c35 // vfma.f32 d17, d1, d21 + .long 0xf4ee5c9f // vld1.32 {d21[]}, [lr :32] + .long 0xf2413c30 // vfma.f32 d19, d1, d16 + .long 0xf4e40c9f // vld1.32 {d16[]}, [r4 :32] + .long 0xe2834008 // add r4, r3, #8 + .long 0xe283300c // add r3, r3, #12 + .long 0xf2012c30 // vfma.f32 d2, d1, d16 + .long 0xf4e40c9f // vld1.32 {d16[]}, [r4 :32] + .long 0xf2401c35 // vfma.f32 d17, d0, d21 + .long 0xf2403c34 // vfma.f32 d19, d0, d20 + .long 0xf4e34c9f // vld1.32 {d20[]}, [r3 :32] + .long 0xf2402c34 // vfma.f32 d18, d0, d20 + .long 0xf2002c30 // vfma.f32 d2, d0, d16 + .long 0xf22111b1 // vorr d1, d17, d17 + .long 0xf22301b3 // vorr d0, d19, d19 + .long 0xf22231b2 // vorr d3, d18, d18 + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff1c // bx ip + +HIDDEN _sk_matrix_perspective_vfp4 +.globl _sk_matrix_perspective_vfp4 +_sk_matrix_perspective_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe591e000 // ldr lr, [r1] + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe2811008 // add r1, r1, #8 + .long 0xe28e301c // add r3, lr, #28 + .long 0xe28e4010 // add r4, lr, #16 + .long 0xf4e30c9f // vld1.32 {d16[]}, [r3 :32] + .long 0xe28e3020 // add r3, lr, #32 + .long 0xf4e31c9f // vld1.32 {d17[]}, [r3 :32] + .long 0xe28e3018 // add r3, lr, #24 + .long 0xf2411c30 // vfma.f32 d17, d1, d16 + .long 0xf4e30c9f // vld1.32 {d16[]}, [r3 :32] + .long 0xe1a0300e // mov r3, lr + .long 0xf4e42c9f // vld1.32 {d18[]}, [r4 :32] + .long 0xe28e4008 // add r4, lr, #8 + .long 0xf4e43c9f // vld1.32 {d19[]}, [r4 :32] + .long 0xf2401c30 // vfma.f32 d17, d0, d16 + .long 0xf4e30c9d // vld1.32 {d16[]}, [r3 :32]! + .long 0xf4e35c9f // vld1.32 {d21[]}, [r3 :32] + .long 0xe28e3014 // add r3, lr, #20 + .long 0xf2413c35 // vfma.f32 d19, d1, d21 + .long 0xf4e35c9f // vld1.32 {d21[]}, [r3 :32] + .long 0xe28e300c // add r3, lr, #12 + .long 0xf2415c32 // vfma.f32 d21, d1, d18 + .long 0xf4e32c9f // vld1.32 {d18[]}, [r3 :32] + .long 0xf3fb4521 // vrecpe.f32 d20, d17 + .long 0xf2403c30 // vfma.f32 d19, d0, d16 + .long 0xf2411fb4 // vrecps.f32 d17, d17, d20 + .long 0xf2405c32 // vfma.f32 d21, d0, d18 + .long 0xf3440db1 // vmul.f32 d16, d20, d17 + .long 0xf3030db0 // vmul.f32 d0, d19, d16 + .long 0xf3051db0 // vmul.f32 d1, d21, d16 + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff1c // bx ip + +HIDDEN _sk_linear_gradient_vfp4 +.globl _sk_linear_gradient_vfp4 +_sk_linear_gradient_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe591e000 // ldr lr, [r1] + .long 0xe28e3014 // add r3, lr, #20 + .long 0xe1a0400e // mov r4, lr + .long 0xf4a33c9f // vld1.32 {d3[]}, [r3 :32] + .long 0xe28e3010 // add r3, lr, #16 + .long 0xf4a32c9f // vld1.32 {d2[]}, [r3 :32] + .long 0xe28e3008 // add r3, lr, #8 + .long 0xf4e30c9f // vld1.32 {d16[]}, [r3 :32] + .long 0xe494c00c // ldr ip, [r4], #12 + .long 0xf4a41c9f // vld1.32 {d1[]}, [r4 :32] + .long 0xe35c0000 // cmp ip, #0 + .long 0x0a000036 // beq 2680 + .long 0xe59e3004 // ldr r3, [lr, #4] + .long 0xf2c01010 // vmov.i32 d17, #0 + .long 0xf2c07010 // vmov.i32 d23, #0 + .long 0xf2c08010 // vmov.i32 d24, #0 + .long 0xe2833020 // add r3, r3, #32 + .long 0xf2c06010 // vmov.i32 d22, #0 + .long 0xe2434018 // sub r4, r3, #24 + .long 0xf4e33c9f // vld1.32 {d19[]}, [r3 :32] + .long 0xe25cc001 // subs ip, ip, #1 + .long 0xf4e4dc9f // vld1.32 {d29[]}, [r4 :32] + .long 0xe2434014 // sub r4, r3, #20 + .long 0xf4e45c9f // vld1.32 {d21[]}, [r4 :32] + .long 0xe243400c // sub r4, r3, #12 + .long 0xf4e44c9f // vld1.32 {d20[]}, [r4 :32] + .long 0xe2434020 // sub r4, r3, #32 + .long 0xf4e42c9f // vld1.32 {d18[]}, [r4 :32] + .long 0xe2434004 // sub r4, r3, #4 + .long 0xf3622e80 // vcgt.f32 d18, d18, d0 + .long 0xf4e4bc9f // vld1.32 {d27[]}, [r4 :32] + .long 0xe2434008 // sub r4, r3, #8 + .long 0xf4e4cc9f // vld1.32 {d28[]}, [r4 :32] + .long 0xe2434010 // sub r4, r3, #16 + .long 0xf262a1b2 // vorr d26, d18, d18 + .long 0xf4e4ec9f // vld1.32 {d30[]}, [r4 :32] + .long 0xe243401c // sub r4, r3, #28 + .long 0xf352a13b // vbsl d26, d2, d27 + .long 0xe2833024 // add r3, r3, #36 + .long 0xf262b1b2 // vorr d27, d18, d18 + .long 0xf26291b2 // vorr d25, d18, d18 + .long 0xf351b13c // vbsl d27, d1, d28 + .long 0xf262c1b2 // vorr d28, d18, d18 + .long 0xf3539133 // vbsl d25, d3, d19 + .long 0xf350c1b4 // vbsl d28, d16, d20 + .long 0xf4e40c9f // vld1.32 {d16[]}, [r4 :32] + .long 0xf26241b2 // vorr d20, d18, d18 + .long 0xf26231b2 // vorr d19, d18, d18 + .long 0xf35841b5 // vbsl d20, d24, d21 + .long 0xf26251b2 // vorr d21, d18, d18 + .long 0xf35121b0 // vbsl d18, d17, d16 + .long 0xf35731be // vbsl d19, d23, d30 + .long 0xf35651bd // vbsl d21, d22, d29 + .long 0xf26211b2 // vorr d17, d18, d18 + .long 0xf22931b9 // vorr d3, d25, d25 + .long 0xf22a21ba // vorr d2, d26, d26 + .long 0xf22b11bb // vorr d1, d27, d27 + .long 0xf26c01bc // vorr d16, d28, d28 + .long 0xf26371b3 // vorr d23, d19, d19 + .long 0xf26481b4 // vorr d24, d20, d20 + .long 0xf26561b5 // vorr d22, d21, d21 + .long 0x1affffd3 // bne 25bc + .long 0xf26c01bc // vorr d16, d28, d28 + .long 0xf22b11bb // vorr d1, d27, d27 + .long 0xf22a21ba // vorr d2, d26, d26 + .long 0xf22931b9 // vorr d3, d25, d25 + .long 0xea000003 // b 2690 + .long 0xf2c05010 // vmov.i32 d21, #0 + .long 0xf2c04010 // vmov.i32 d20, #0 + .long 0xf2c03010 // vmov.i32 d19, #0 + .long 0xf2c02010 // vmov.i32 d18, #0 + .long 0xf2400c32 // vfma.f32 d16, d0, d18 + .long 0xe5913004 // ldr r3, [r1, #4] + .long 0xf2001c35 // vfma.f32 d1, d0, d21 + .long 0xe2811008 // add r1, r1, #8 + .long 0xf2002c34 // vfma.f32 d2, d0, d20 + .long 0xf2003c33 // vfma.f32 d3, d0, d19 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff13 // bx r3 + +HIDDEN _sk_linear_gradient_2stops_vfp4 +.globl _sk_linear_gradient_2stops_vfp4 +_sk_linear_gradient_2stops_vfp4: + .long 0xe92d4010 // push {r4, lr} + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xe283400c // add r4, r3, #12 + .long 0xe1a0e003 // mov lr, r3 + .long 0xf4e42c9f // vld1.32 {d18[]}, [r4 :32] + .long 0xe2834008 // add r4, r3, #8 + .long 0xf4e43c9f // vld1.32 {d19[]}, [r4 :32] + .long 0xe2834018 // add r4, r3, #24 + .long 0xf4a42c9f // vld1.32 {d2[]}, [r4 :32] + .long 0xe2834010 // add r4, r3, #16 + .long 0xf2002c33 // vfma.f32 d2, d0, d19 + .long 0xf4e40c9f // vld1.32 {d16[]}, [r4 :32] + .long 0xe283401c // add r4, r3, #28 + .long 0xe2833014 // add r3, r3, #20 + .long 0xf4ee1c9d // vld1.32 {d17[]}, [lr :32]! + .long 0xf2400c31 // vfma.f32 d16, d0, d17 + .long 0xf4a43c9f // vld1.32 {d3[]}, [r4 :32] + .long 0xf2003c32 // vfma.f32 d3, d0, d18 + .long 0xf4ee1c9f // vld1.32 {d17[]}, [lr :32] + .long 0xf4a31c9f // vld1.32 {d1[]}, [r3 :32] + .long 0xf2001c31 // vfma.f32 d1, d0, d17 + .long 0xf22001b0 // vorr d0, d16, d16 + .long 0xe8bd4010 // pop {r4, lr} + .long 0xe12fff1c // bx ip + +HIDDEN _sk_save_xy_vfp4 +.globl _sk_save_xy_vfp4 +_sk_save_xy_vfp4: + .long 0xf2c3061f // vmov.i32 d16, #1056964608 + .long 0xeddf7b17 // vldr d23, [pc, #92] + .long 0xf2c06010 // vmov.i32 d22, #0 + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2401d20 // vadd.f32 d17, d0, d16 + .long 0xf2410d20 // vadd.f32 d16, d1, d16 + .long 0xed830b00 // vstr d0, [r3] + .long 0xed831b08 // vstr d1, [r3, #32] + .long 0xf3fb2721 // vcvt.s32.f32 d18, d17 + .long 0xf3fb3720 // vcvt.s32.f32 d19, d16 + .long 0xf3fb2622 // vcvt.f32.s32 d18, d18 + .long 0xf3fb3623 // vcvt.f32.s32 d19, d19 + .long 0xf3624ea1 // vcgt.f32 d20, d18, d17 + .long 0xf3635ea0 // vcgt.f32 d21, d19, d16 + .long 0xf35741b6 // vbsl d20, d23, d22 + .long 0xf35751b6 // vbsl d21, d23, d22 + .long 0xf2622da4 // vsub.f32 d18, d18, d20 + .long 0xf2633da5 // vsub.f32 d19, d19, d21 + .long 0xf2611da2 // vsub.f32 d17, d17, d18 + .long 0xf2600da3 // vsub.f32 d16, d16, d19 + .long 0xedc31b10 // vstr d17, [r3, #64] + .long 0xedc30b18 // vstr d16, [r3, #96] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0x3f800000 // .word 0x3f800000 + .long 0x3f800000 // .word 0x3f800000 + +HIDDEN _sk_accumulate_vfp4 +.globl _sk_accumulate_vfp4 +_sk_accumulate_vfp4: + .long 0xe8911008 // ldm r1, {r3, ip} + .long 0xe2811008 // add r1, r1, #8 + .long 0xedd31b28 // vldr d17, [r3, #160] + .long 0xedd30b20 // vldr d16, [r3, #128] + .long 0xf3400db1 // vmul.f32 d16, d16, d17 + .long 0xf2004c90 // vfma.f32 d4, d16, d0 + .long 0xf2005c91 // vfma.f32 d5, d16, d1 + .long 0xf2006c92 // vfma.f32 d6, d16, d2 + .long 0xf2007c93 // vfma.f32 d7, d16, d3 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_bilinear_nx_vfp4 +.globl _sk_bilinear_nx_vfp4 +_sk_bilinear_nx_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xedd32b10 // vldr d18, [r3, #64] + .long 0xf2600da2 // vsub.f32 d16, d16, d18 + .long 0xedd31b00 // vldr d17, [r3] + .long 0xf3c3261f // vmov.i32 d18, #-1090519040 + .long 0xf2010da2 // vadd.f32 d0, d17, d18 + .long 0xedc30b20 // vstr d16, [r3, #128] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_bilinear_px_vfp4 +.globl _sk_bilinear_px_vfp4 +_sk_bilinear_px_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c3061f // vmov.i32 d16, #1056964608 + .long 0xedd31b00 // vldr d17, [r3] + .long 0xedd32b10 // vldr d18, [r3, #64] + .long 0xf2010da0 // vadd.f32 d0, d17, d16 + .long 0xedc32b20 // vstr d18, [r3, #128] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_bilinear_ny_vfp4 +.globl _sk_bilinear_ny_vfp4 +_sk_bilinear_ny_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xedd32b18 // vldr d18, [r3, #96] + .long 0xf2600da2 // vsub.f32 d16, d16, d18 + .long 0xedd31b08 // vldr d17, [r3, #32] + .long 0xf3c3261f // vmov.i32 d18, #-1090519040 + .long 0xf2011da2 // vadd.f32 d1, d17, d18 + .long 0xedc30b28 // vstr d16, [r3, #160] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_bilinear_py_vfp4 +.globl _sk_bilinear_py_vfp4 +_sk_bilinear_py_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c3061f // vmov.i32 d16, #1056964608 + .long 0xedd31b08 // vldr d17, [r3, #32] + .long 0xedd32b18 // vldr d18, [r3, #96] + .long 0xf2011da0 // vadd.f32 d1, d17, d16 + .long 0xedc32b28 // vstr d18, [r3, #160] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + +HIDDEN _sk_bicubic_n3x_vfp4 +.globl _sk_bicubic_n3x_vfp4 +_sk_bicubic_n3x_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xeddf3b10 // vldr d19, [pc, #64] + .long 0xedd32b10 // vldr d18, [r3, #64] + .long 0xf2600da2 // vsub.f32 d16, d16, d18 + .long 0xeddf2b0b // vldr d18, [pc, #44] + .long 0xedd31b00 // vldr d17, [r3] + .long 0xf2403cb2 // vfma.f32 d19, d16, d18 + .long 0xf3400db0 // vmul.f32 d16, d16, d16 + .long 0xf3c72f18 // vmov.f32 d18, #-1.5 + .long 0xf2010da2 // vadd.f32 d0, d17, d18 + .long 0xf3400db3 // vmul.f32 d16, d16, d19 + .long 0xedc30b20 // vstr d16, [r3, #128] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3ec71c72 // .word 0x3ec71c72 + .long 0x3ec71c72 // .word 0x3ec71c72 + .long 0xbeaaaaab // .word 0xbeaaaaab + .long 0xbeaaaaab // .word 0xbeaaaaab + +HIDDEN _sk_bicubic_n1x_vfp4 +.globl _sk_bicubic_n1x_vfp4 +_sk_bicubic_n1x_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xf2c73f18 // vmov.f32 d19, #1.5 + .long 0xedd32b10 // vldr d18, [r3, #64] + .long 0xf2600da2 // vsub.f32 d16, d16, d18 + .long 0xeddf2b0d // vldr d18, [pc, #52] + .long 0xedd31b00 // vldr d17, [r3] + .long 0xf2403cb2 // vfma.f32 d19, d16, d18 + .long 0xf2c3261f // vmov.i32 d18, #1056964608 + .long 0xf2402cb3 // vfma.f32 d18, d16, d19 + .long 0xeddf3b0a // vldr d19, [pc, #40] + .long 0xf2403cb2 // vfma.f32 d19, d16, d18 + .long 0xf3c3061f // vmov.i32 d16, #-1090519040 + .long 0xf2010da0 // vadd.f32 d0, d17, d16 + .long 0xedc33b20 // vstr d19, [r3, #128] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0xbf955555 // .word 0xbf955555 + .long 0xbf955555 // .word 0xbf955555 + .long 0x3d638e39 // .word 0x3d638e39 + .long 0x3d638e39 // .word 0x3d638e39 + +HIDDEN _sk_bicubic_p1x_vfp4 +.globl _sk_bicubic_p1x_vfp4 +_sk_bicubic_p1x_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c71f18 // vmov.f32 d17, #1.5 + .long 0xeddf0b0c // vldr d16, [pc, #48] + .long 0xedd33b10 // vldr d19, [r3, #64] + .long 0xf2431cb0 // vfma.f32 d17, d19, d16 + .long 0xedd32b00 // vldr d18, [r3] + .long 0xf2c3061f // vmov.i32 d16, #1056964608 + .long 0xf2020da0 // vadd.f32 d0, d18, d16 + .long 0xf2430cb1 // vfma.f32 d16, d19, d17 + .long 0xeddf1b07 // vldr d17, [pc, #28] + .long 0xf2431cb0 // vfma.f32 d17, d19, d16 + .long 0xedc31b20 // vstr d17, [r3, #128] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0xbf955555 // .word 0xbf955555 + .long 0xbf955555 // .word 0xbf955555 + .long 0x3d638e39 // .word 0x3d638e39 + .long 0x3d638e39 // .word 0x3d638e39 + +HIDDEN _sk_bicubic_p3x_vfp4 +.globl _sk_bicubic_p3x_vfp4 +_sk_bicubic_p3x_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xeddf0b0d // vldr d16, [pc, #52] + .long 0xeddf3b0e // vldr d19, [pc, #56] + .long 0xedd32b10 // vldr d18, [r3, #64] + .long 0xf2423cb0 // vfma.f32 d19, d18, d16 + .long 0xedd31b00 // vldr d17, [r3] + .long 0xf3420db2 // vmul.f32 d16, d18, d18 + .long 0xf2c72f18 // vmov.f32 d18, #1.5 + .long 0xf2010da2 // vadd.f32 d0, d17, d18 + .long 0xf3400db3 // vmul.f32 d16, d16, d19 + .long 0xedc30b20 // vstr d16, [r3, #128] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3ec71c72 // .word 0x3ec71c72 + .long 0x3ec71c72 // .word 0x3ec71c72 + .long 0xbeaaaaab // .word 0xbeaaaaab + .long 0xbeaaaaab // .word 0xbeaaaaab + +HIDDEN _sk_bicubic_n3y_vfp4 +.globl _sk_bicubic_n3y_vfp4 +_sk_bicubic_n3y_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xeddf3b10 // vldr d19, [pc, #64] + .long 0xedd32b18 // vldr d18, [r3, #96] + .long 0xf2600da2 // vsub.f32 d16, d16, d18 + .long 0xeddf2b0b // vldr d18, [pc, #44] + .long 0xedd31b08 // vldr d17, [r3, #32] + .long 0xf2403cb2 // vfma.f32 d19, d16, d18 + .long 0xf3400db0 // vmul.f32 d16, d16, d16 + .long 0xf3c72f18 // vmov.f32 d18, #-1.5 + .long 0xf2011da2 // vadd.f32 d1, d17, d18 + .long 0xf3400db3 // vmul.f32 d16, d16, d19 + .long 0xedc30b28 // vstr d16, [r3, #160] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3ec71c72 // .word 0x3ec71c72 + .long 0x3ec71c72 // .word 0x3ec71c72 + .long 0xbeaaaaab // .word 0xbeaaaaab + .long 0xbeaaaaab // .word 0xbeaaaaab + +HIDDEN _sk_bicubic_n1y_vfp4 +.globl _sk_bicubic_n1y_vfp4 +_sk_bicubic_n1y_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c70f10 // vmov.f32 d16, #1 + .long 0xf2c73f18 // vmov.f32 d19, #1.5 + .long 0xedd32b18 // vldr d18, [r3, #96] + .long 0xf2600da2 // vsub.f32 d16, d16, d18 + .long 0xeddf2b0d // vldr d18, [pc, #52] + .long 0xedd31b08 // vldr d17, [r3, #32] + .long 0xf2403cb2 // vfma.f32 d19, d16, d18 + .long 0xf2c3261f // vmov.i32 d18, #1056964608 + .long 0xf2402cb3 // vfma.f32 d18, d16, d19 + .long 0xeddf3b0a // vldr d19, [pc, #40] + .long 0xf2403cb2 // vfma.f32 d19, d16, d18 + .long 0xf3c3061f // vmov.i32 d16, #-1090519040 + .long 0xf2011da0 // vadd.f32 d1, d17, d16 + .long 0xedc33b28 // vstr d19, [r3, #160] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0xbf955555 // .word 0xbf955555 + .long 0xbf955555 // .word 0xbf955555 + .long 0x3d638e39 // .word 0x3d638e39 + .long 0x3d638e39 // .word 0x3d638e39 + +HIDDEN _sk_bicubic_p1y_vfp4 +.globl _sk_bicubic_p1y_vfp4 +_sk_bicubic_p1y_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xf2c71f18 // vmov.f32 d17, #1.5 + .long 0xeddf0b0c // vldr d16, [pc, #48] + .long 0xedd33b18 // vldr d19, [r3, #96] + .long 0xf2431cb0 // vfma.f32 d17, d19, d16 + .long 0xedd32b08 // vldr d18, [r3, #32] + .long 0xf2c3061f // vmov.i32 d16, #1056964608 + .long 0xf2021da0 // vadd.f32 d1, d18, d16 + .long 0xf2430cb1 // vfma.f32 d16, d19, d17 + .long 0xeddf1b07 // vldr d17, [pc, #28] + .long 0xf2431cb0 // vfma.f32 d17, d19, d16 + .long 0xedc31b28 // vstr d17, [r3, #160] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0xbf955555 // .word 0xbf955555 + .long 0xbf955555 // .word 0xbf955555 + .long 0x3d638e39 // .word 0x3d638e39 + .long 0x3d638e39 // .word 0x3d638e39 + +HIDDEN _sk_bicubic_p3y_vfp4 +.globl _sk_bicubic_p3y_vfp4 +_sk_bicubic_p3y_vfp4: + .long 0xe5913000 // ldr r3, [r1] + .long 0xeddf0b0d // vldr d16, [pc, #52] + .long 0xeddf3b0e // vldr d19, [pc, #56] + .long 0xedd32b18 // vldr d18, [r3, #96] + .long 0xf2423cb0 // vfma.f32 d19, d18, d16 + .long 0xedd31b08 // vldr d17, [r3, #32] + .long 0xf3420db2 // vmul.f32 d16, d18, d18 + .long 0xf2c72f18 // vmov.f32 d18, #1.5 + .long 0xf2011da2 // vadd.f32 d1, d17, d18 + .long 0xf3400db3 // vmul.f32 d16, d16, d19 + .long 0xedc30b28 // vstr d16, [r3, #160] + .long 0xe2813008 // add r3, r1, #8 + .long 0xe591c004 // ldr ip, [r1, #4] + .long 0xe1a01003 // mov r1, r3 + .long 0xe12fff1c // bx ip + .long 0xe320f000 // nop {0} + .long 0x3ec71c72 // .word 0x3ec71c72 + .long 0x3ec71c72 // .word 0x3ec71c72 + .long 0xbeaaaaab // .word 0xbeaaaaab + .long 0xbeaaaaab // .word 0xbeaaaaab +#elif defined(__x86_64__) + +HIDDEN _sk_start_pipeline_hsw +.globl _sk_start_pipeline_hsw +_sk_start_pipeline_hsw: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 73,137,205 // mov %rcx,%r13 + .byte 73,137,214 // mov %rdx,%r14 + .byte 72,137,251 // mov %rdi,%rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 73,137,199 // mov %rax,%r15 + .byte 73,137,244 // mov %rsi,%r12 + .byte 72,141,67,8 // lea 0x8(%rbx),%rax + .byte 76,57,232 // cmp %r13,%rax + .byte 118,5 // jbe 28 <_sk_start_pipeline_hsw+0x28> + .byte 72,137,223 // mov %rbx,%rdi + .byte 235,65 // jmp 69 <_sk_start_pipeline_hsw+0x69> + .byte 185,0,0,0,0 // mov $0x0,%ecx + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 197,228,87,219 // vxorps %ymm3,%ymm3,%ymm3 + .byte 197,220,87,228 // vxorps %ymm4,%ymm4,%ymm4 + .byte 197,212,87,237 // vxorps %ymm5,%ymm5,%ymm5 + .byte 197,204,87,246 // vxorps %ymm6,%ymm6,%ymm6 + .byte 197,196,87,255 // vxorps %ymm7,%ymm7,%ymm7 + .byte 72,137,223 // mov %rbx,%rdi + .byte 76,137,230 // mov %r12,%rsi + .byte 76,137,242 // mov %r14,%rdx + .byte 65,255,215 // callq *%r15 + .byte 72,141,123,8 // lea 0x8(%rbx),%rdi + .byte 72,131,195,16 // add $0x10,%rbx + .byte 76,57,235 // cmp %r13,%rbx + .byte 72,137,251 // mov %rdi,%rbx + .byte 118,191 // jbe 28 <_sk_start_pipeline_hsw+0x28> + .byte 76,137,233 // mov %r13,%rcx + .byte 72,41,249 // sub %rdi,%rcx + .byte 116,41 // je 9a <_sk_start_pipeline_hsw+0x9a> + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 197,228,87,219 // vxorps %ymm3,%ymm3,%ymm3 + .byte 197,220,87,228 // vxorps %ymm4,%ymm4,%ymm4 + .byte 197,212,87,237 // vxorps %ymm5,%ymm5,%ymm5 + .byte 197,204,87,246 // vxorps %ymm6,%ymm6,%ymm6 + .byte 197,196,87,255 // vxorps %ymm7,%ymm7,%ymm7 + .byte 76,137,230 // mov %r12,%rsi + .byte 76,137,242 // mov %r14,%rdx + .byte 65,255,215 // callq *%r15 + .byte 76,137,232 // mov %r13,%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 197,248,119 // vzeroupper + .byte 195 // retq + +HIDDEN _sk_just_return_hsw +.globl _sk_just_return_hsw +_sk_just_return_hsw: + .byte 195 // retq + +HIDDEN _sk_seed_shader_hsw +.globl _sk_seed_shader_hsw +_sk_seed_shader_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,249,110,199 // vmovd %edi,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,252,88,193 // vaddps %ymm1,%ymm0,%ymm0 + .byte 197,252,88,2 // vaddps (%rdx),%ymm0,%ymm0 + .byte 196,226,125,24,16 // vbroadcastss (%rax),%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 197,236,88,201 // vaddps %ymm1,%ymm2,%ymm1 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,226,125,88,210 // vpbroadcastd %xmm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,228,87,219 // vxorps %ymm3,%ymm3,%ymm3 + .byte 197,220,87,228 // vxorps %ymm4,%ymm4,%ymm4 + .byte 197,212,87,237 // vxorps %ymm5,%ymm5,%ymm5 + .byte 197,204,87,246 // vxorps %ymm6,%ymm6,%ymm6 + .byte 197,196,87,255 // vxorps %ymm7,%ymm7,%ymm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_constant_color_hsw +.globl _sk_constant_color_hsw +_sk_constant_color_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,226,125,24,0 // vbroadcastss (%rax),%ymm0 + .byte 196,226,125,24,72,4 // vbroadcastss 0x4(%rax),%ymm1 + .byte 196,226,125,24,80,8 // vbroadcastss 0x8(%rax),%ymm2 + .byte 196,226,125,24,88,12 // vbroadcastss 0xc(%rax),%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clear_hsw +.globl _sk_clear_hsw +_sk_clear_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 197,228,87,219 // vxorps %ymm3,%ymm3,%ymm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcatop_hsw +.globl _sk_srcatop_hsw +_sk_srcatop_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,204 // vmulps %ymm4,%ymm8,%ymm9 + .byte 196,194,69,168,193 // vfmadd213ps %ymm9,%ymm7,%ymm0 + .byte 197,60,89,205 // vmulps %ymm5,%ymm8,%ymm9 + .byte 196,194,69,168,201 // vfmadd213ps %ymm9,%ymm7,%ymm1 + .byte 197,60,89,206 // vmulps %ymm6,%ymm8,%ymm9 + .byte 196,194,69,168,209 // vfmadd213ps %ymm9,%ymm7,%ymm2 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 196,194,69,168,216 // vfmadd213ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstatop_hsw +.globl _sk_dstatop_hsw +_sk_dstatop_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,199 // vsubps %ymm7,%ymm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 196,226,101,184,196 // vfmadd231ps %ymm4,%ymm3,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 196,226,101,184,205 // vfmadd231ps %ymm5,%ymm3,%ymm1 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 196,226,101,184,214 // vfmadd231ps %ymm6,%ymm3,%ymm2 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 196,194,69,168,216 // vfmadd213ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcin_hsw +.globl _sk_srcin_hsw +_sk_srcin_hsw: + .byte 197,252,89,199 // vmulps %ymm7,%ymm0,%ymm0 + .byte 197,244,89,207 // vmulps %ymm7,%ymm1,%ymm1 + .byte 197,236,89,215 // vmulps %ymm7,%ymm2,%ymm2 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstin_hsw +.globl _sk_dstin_hsw +_sk_dstin_hsw: + .byte 197,228,89,196 // vmulps %ymm4,%ymm3,%ymm0 + .byte 197,228,89,205 // vmulps %ymm5,%ymm3,%ymm1 + .byte 197,228,89,214 // vmulps %ymm6,%ymm3,%ymm2 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcout_hsw +.globl _sk_srcout_hsw +_sk_srcout_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,199 // vsubps %ymm7,%ymm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstout_hsw +.globl _sk_dstout_hsw +_sk_dstout_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 197,252,92,219 // vsubps %ymm3,%ymm0,%ymm3 + .byte 197,228,89,196 // vmulps %ymm4,%ymm3,%ymm0 + .byte 197,228,89,205 // vmulps %ymm5,%ymm3,%ymm1 + .byte 197,228,89,214 // vmulps %ymm6,%ymm3,%ymm2 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcover_hsw +.globl _sk_srcover_hsw +_sk_srcover_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 196,194,93,184,192 // vfmadd231ps %ymm8,%ymm4,%ymm0 + .byte 196,194,85,184,200 // vfmadd231ps %ymm8,%ymm5,%ymm1 + .byte 196,194,77,184,208 // vfmadd231ps %ymm8,%ymm6,%ymm2 + .byte 196,194,69,184,216 // vfmadd231ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstover_hsw +.globl _sk_dstover_hsw +_sk_dstover_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,199 // vsubps %ymm7,%ymm8,%ymm8 + .byte 196,226,61,168,196 // vfmadd213ps %ymm4,%ymm8,%ymm0 + .byte 196,226,61,168,205 // vfmadd213ps %ymm5,%ymm8,%ymm1 + .byte 196,226,61,168,214 // vfmadd213ps %ymm6,%ymm8,%ymm2 + .byte 196,226,61,168,223 // vfmadd213ps %ymm7,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_modulate_hsw +.globl _sk_modulate_hsw +_sk_modulate_hsw: + .byte 197,252,89,196 // vmulps %ymm4,%ymm0,%ymm0 + .byte 197,244,89,205 // vmulps %ymm5,%ymm1,%ymm1 + .byte 197,236,89,214 // vmulps %ymm6,%ymm2,%ymm2 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_multiply_hsw +.globl _sk_multiply_hsw +_sk_multiply_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,207 // vsubps %ymm7,%ymm8,%ymm9 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,212 // vmulps %ymm4,%ymm8,%ymm10 + .byte 196,98,53,184,208 // vfmadd231ps %ymm0,%ymm9,%ymm10 + .byte 196,194,93,168,194 // vfmadd213ps %ymm10,%ymm4,%ymm0 + .byte 197,52,89,209 // vmulps %ymm1,%ymm9,%ymm10 + .byte 196,98,61,184,213 // vfmadd231ps %ymm5,%ymm8,%ymm10 + .byte 196,194,85,168,202 // vfmadd213ps %ymm10,%ymm5,%ymm1 + .byte 197,52,89,210 // vmulps %ymm2,%ymm9,%ymm10 + .byte 196,98,61,184,214 // vfmadd231ps %ymm6,%ymm8,%ymm10 + .byte 196,194,77,168,210 // vfmadd213ps %ymm10,%ymm6,%ymm2 + .byte 197,52,89,203 // vmulps %ymm3,%ymm9,%ymm9 + .byte 196,66,69,168,193 // vfmadd213ps %ymm9,%ymm7,%ymm8 + .byte 196,194,69,168,216 // vfmadd213ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_plus__hsw +.globl _sk_plus__hsw +_sk_plus__hsw: + .byte 197,252,88,196 // vaddps %ymm4,%ymm0,%ymm0 + .byte 197,244,88,205 // vaddps %ymm5,%ymm1,%ymm1 + .byte 197,236,88,214 // vaddps %ymm6,%ymm2,%ymm2 + .byte 197,228,88,223 // vaddps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_screen_hsw +.globl _sk_screen_hsw +_sk_screen_hsw: + .byte 197,124,88,196 // vaddps %ymm4,%ymm0,%ymm8 + .byte 196,194,93,172,192 // vfnmadd213ps %ymm8,%ymm4,%ymm0 + .byte 197,116,88,197 // vaddps %ymm5,%ymm1,%ymm8 + .byte 196,194,85,172,200 // vfnmadd213ps %ymm8,%ymm5,%ymm1 + .byte 197,108,88,198 // vaddps %ymm6,%ymm2,%ymm8 + .byte 196,194,77,172,208 // vfnmadd213ps %ymm8,%ymm6,%ymm2 + .byte 197,100,88,199 // vaddps %ymm7,%ymm3,%ymm8 + .byte 196,194,69,172,216 // vfnmadd213ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_xor__hsw +.globl _sk_xor__hsw +_sk_xor__hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,207 // vsubps %ymm7,%ymm8,%ymm9 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,212 // vmulps %ymm4,%ymm8,%ymm10 + .byte 196,194,53,168,194 // vfmadd213ps %ymm10,%ymm9,%ymm0 + .byte 197,180,89,201 // vmulps %ymm1,%ymm9,%ymm1 + .byte 196,226,61,184,205 // vfmadd231ps %ymm5,%ymm8,%ymm1 + .byte 197,180,89,210 // vmulps %ymm2,%ymm9,%ymm2 + .byte 196,226,61,184,214 // vfmadd231ps %ymm6,%ymm8,%ymm2 + .byte 197,180,89,219 // vmulps %ymm3,%ymm9,%ymm3 + .byte 196,98,69,168,195 // vfmadd213ps %ymm3,%ymm7,%ymm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,195 // vmovaps %ymm8,%ymm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_darken_hsw +.globl _sk_darken_hsw +_sk_darken_hsw: + .byte 197,124,88,196 // vaddps %ymm4,%ymm0,%ymm8 + .byte 197,252,89,199 // vmulps %ymm7,%ymm0,%ymm0 + .byte 197,100,89,204 // vmulps %ymm4,%ymm3,%ymm9 + .byte 196,193,124,95,193 // vmaxps %ymm9,%ymm0,%ymm0 + .byte 197,188,92,192 // vsubps %ymm0,%ymm8,%ymm0 + .byte 197,116,88,197 // vaddps %ymm5,%ymm1,%ymm8 + .byte 197,244,89,207 // vmulps %ymm7,%ymm1,%ymm1 + .byte 197,100,89,205 // vmulps %ymm5,%ymm3,%ymm9 + .byte 196,193,116,95,201 // vmaxps %ymm9,%ymm1,%ymm1 + .byte 197,188,92,201 // vsubps %ymm1,%ymm8,%ymm1 + .byte 197,108,88,198 // vaddps %ymm6,%ymm2,%ymm8 + .byte 197,236,89,215 // vmulps %ymm7,%ymm2,%ymm2 + .byte 197,100,89,206 // vmulps %ymm6,%ymm3,%ymm9 + .byte 196,193,108,95,209 // vmaxps %ymm9,%ymm2,%ymm2 + .byte 197,188,92,210 // vsubps %ymm2,%ymm8,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 196,194,69,184,216 // vfmadd231ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lighten_hsw +.globl _sk_lighten_hsw +_sk_lighten_hsw: + .byte 197,124,88,196 // vaddps %ymm4,%ymm0,%ymm8 + .byte 197,252,89,199 // vmulps %ymm7,%ymm0,%ymm0 + .byte 197,100,89,204 // vmulps %ymm4,%ymm3,%ymm9 + .byte 196,193,124,93,193 // vminps %ymm9,%ymm0,%ymm0 + .byte 197,188,92,192 // vsubps %ymm0,%ymm8,%ymm0 + .byte 197,116,88,197 // vaddps %ymm5,%ymm1,%ymm8 + .byte 197,244,89,207 // vmulps %ymm7,%ymm1,%ymm1 + .byte 197,100,89,205 // vmulps %ymm5,%ymm3,%ymm9 + .byte 196,193,116,93,201 // vminps %ymm9,%ymm1,%ymm1 + .byte 197,188,92,201 // vsubps %ymm1,%ymm8,%ymm1 + .byte 197,108,88,198 // vaddps %ymm6,%ymm2,%ymm8 + .byte 197,236,89,215 // vmulps %ymm7,%ymm2,%ymm2 + .byte 197,100,89,206 // vmulps %ymm6,%ymm3,%ymm9 + .byte 196,193,108,93,209 // vminps %ymm9,%ymm2,%ymm2 + .byte 197,188,92,210 // vsubps %ymm2,%ymm8,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 196,194,69,184,216 // vfmadd231ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_difference_hsw +.globl _sk_difference_hsw +_sk_difference_hsw: + .byte 197,124,88,196 // vaddps %ymm4,%ymm0,%ymm8 + .byte 197,252,89,199 // vmulps %ymm7,%ymm0,%ymm0 + .byte 197,100,89,204 // vmulps %ymm4,%ymm3,%ymm9 + .byte 196,193,124,93,193 // vminps %ymm9,%ymm0,%ymm0 + .byte 197,252,88,192 // vaddps %ymm0,%ymm0,%ymm0 + .byte 197,188,92,192 // vsubps %ymm0,%ymm8,%ymm0 + .byte 197,116,88,197 // vaddps %ymm5,%ymm1,%ymm8 + .byte 197,244,89,207 // vmulps %ymm7,%ymm1,%ymm1 + .byte 197,100,89,205 // vmulps %ymm5,%ymm3,%ymm9 + .byte 196,193,116,93,201 // vminps %ymm9,%ymm1,%ymm1 + .byte 197,244,88,201 // vaddps %ymm1,%ymm1,%ymm1 + .byte 197,188,92,201 // vsubps %ymm1,%ymm8,%ymm1 + .byte 197,108,88,198 // vaddps %ymm6,%ymm2,%ymm8 + .byte 197,236,89,215 // vmulps %ymm7,%ymm2,%ymm2 + .byte 197,100,89,206 // vmulps %ymm6,%ymm3,%ymm9 + .byte 196,193,108,93,209 // vminps %ymm9,%ymm2,%ymm2 + .byte 197,236,88,210 // vaddps %ymm2,%ymm2,%ymm2 + .byte 197,188,92,210 // vsubps %ymm2,%ymm8,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 196,194,69,184,216 // vfmadd231ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_exclusion_hsw +.globl _sk_exclusion_hsw +_sk_exclusion_hsw: + .byte 197,124,88,196 // vaddps %ymm4,%ymm0,%ymm8 + .byte 197,252,89,196 // vmulps %ymm4,%ymm0,%ymm0 + .byte 197,252,88,192 // vaddps %ymm0,%ymm0,%ymm0 + .byte 197,188,92,192 // vsubps %ymm0,%ymm8,%ymm0 + .byte 197,116,88,197 // vaddps %ymm5,%ymm1,%ymm8 + .byte 197,244,89,205 // vmulps %ymm5,%ymm1,%ymm1 + .byte 197,244,88,201 // vaddps %ymm1,%ymm1,%ymm1 + .byte 197,188,92,201 // vsubps %ymm1,%ymm8,%ymm1 + .byte 197,108,88,198 // vaddps %ymm6,%ymm2,%ymm8 + .byte 197,236,89,214 // vmulps %ymm6,%ymm2,%ymm2 + .byte 197,236,88,210 // vaddps %ymm2,%ymm2,%ymm2 + .byte 197,188,92,210 // vsubps %ymm2,%ymm8,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 196,194,69,184,216 // vfmadd231ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_colorburn_hsw +.globl _sk_colorburn_hsw +_sk_colorburn_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,207 // vsubps %ymm7,%ymm8,%ymm9 + .byte 197,52,89,216 // vmulps %ymm0,%ymm9,%ymm11 + .byte 196,65,44,87,210 // vxorps %ymm10,%ymm10,%ymm10 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,228 // vmulps %ymm4,%ymm8,%ymm12 + .byte 197,68,92,236 // vsubps %ymm4,%ymm7,%ymm13 + .byte 197,20,89,235 // vmulps %ymm3,%ymm13,%ymm13 + .byte 197,20,94,232 // vdivps %ymm0,%ymm13,%ymm13 + .byte 196,65,68,93,237 // vminps %ymm13,%ymm7,%ymm13 + .byte 196,65,68,92,237 // vsubps %ymm13,%ymm7,%ymm13 + .byte 196,66,101,168,235 // vfmadd213ps %ymm11,%ymm3,%ymm13 + .byte 196,65,28,88,237 // vaddps %ymm13,%ymm12,%ymm13 + .byte 197,28,88,224 // vaddps %ymm0,%ymm12,%ymm12 + .byte 196,193,124,194,194,0 // vcmpeqps %ymm10,%ymm0,%ymm0 + .byte 196,195,21,74,196,0 // vblendvps %ymm0,%ymm12,%ymm13,%ymm0 + .byte 197,92,194,231,0 // vcmpeqps %ymm7,%ymm4,%ymm12 + .byte 197,36,88,220 // vaddps %ymm4,%ymm11,%ymm11 + .byte 196,195,125,74,195,192 // vblendvps %ymm12,%ymm11,%ymm0,%ymm0 + .byte 197,52,89,217 // vmulps %ymm1,%ymm9,%ymm11 + .byte 197,60,89,229 // vmulps %ymm5,%ymm8,%ymm12 + .byte 197,68,92,237 // vsubps %ymm5,%ymm7,%ymm13 + .byte 197,20,89,235 // vmulps %ymm3,%ymm13,%ymm13 + .byte 197,20,94,233 // vdivps %ymm1,%ymm13,%ymm13 + .byte 196,65,68,93,237 // vminps %ymm13,%ymm7,%ymm13 + .byte 196,65,68,92,237 // vsubps %ymm13,%ymm7,%ymm13 + .byte 196,66,101,168,235 // vfmadd213ps %ymm11,%ymm3,%ymm13 + .byte 196,65,28,88,237 // vaddps %ymm13,%ymm12,%ymm13 + .byte 197,28,88,225 // vaddps %ymm1,%ymm12,%ymm12 + .byte 196,193,116,194,202,0 // vcmpeqps %ymm10,%ymm1,%ymm1 + .byte 196,195,21,74,204,16 // vblendvps %ymm1,%ymm12,%ymm13,%ymm1 + .byte 197,84,194,231,0 // vcmpeqps %ymm7,%ymm5,%ymm12 + .byte 197,36,88,221 // vaddps %ymm5,%ymm11,%ymm11 + .byte 196,195,117,74,203,192 // vblendvps %ymm12,%ymm11,%ymm1,%ymm1 + .byte 197,52,89,202 // vmulps %ymm2,%ymm9,%ymm9 + .byte 196,65,108,194,210,0 // vcmpeqps %ymm10,%ymm2,%ymm10 + .byte 197,60,89,222 // vmulps %ymm6,%ymm8,%ymm11 + .byte 197,68,92,230 // vsubps %ymm6,%ymm7,%ymm12 + .byte 197,28,89,227 // vmulps %ymm3,%ymm12,%ymm12 + .byte 197,28,94,226 // vdivps %ymm2,%ymm12,%ymm12 + .byte 197,164,88,210 // vaddps %ymm2,%ymm11,%ymm2 + .byte 196,65,68,93,228 // vminps %ymm12,%ymm7,%ymm12 + .byte 196,65,68,92,228 // vsubps %ymm12,%ymm7,%ymm12 + .byte 196,66,101,168,225 // vfmadd213ps %ymm9,%ymm3,%ymm12 + .byte 196,65,36,88,220 // vaddps %ymm12,%ymm11,%ymm11 + .byte 196,227,37,74,210,160 // vblendvps %ymm10,%ymm2,%ymm11,%ymm2 + .byte 197,76,194,215,0 // vcmpeqps %ymm7,%ymm6,%ymm10 + .byte 197,52,88,206 // vaddps %ymm6,%ymm9,%ymm9 + .byte 196,195,109,74,209,160 // vblendvps %ymm10,%ymm9,%ymm2,%ymm2 + .byte 196,194,69,184,216 // vfmadd231ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_colordodge_hsw +.globl _sk_colordodge_hsw +_sk_colordodge_hsw: + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 196,66,125,88,201 // vpbroadcastd %xmm9,%ymm9 + .byte 197,52,92,215 // vsubps %ymm7,%ymm9,%ymm10 + .byte 197,44,89,216 // vmulps %ymm0,%ymm10,%ymm11 + .byte 197,52,92,203 // vsubps %ymm3,%ymm9,%ymm9 + .byte 197,100,89,228 // vmulps %ymm4,%ymm3,%ymm12 + .byte 197,100,92,232 // vsubps %ymm0,%ymm3,%ymm13 + .byte 196,65,28,94,229 // vdivps %ymm13,%ymm12,%ymm12 + .byte 197,52,89,236 // vmulps %ymm4,%ymm9,%ymm13 + .byte 196,65,68,93,228 // vminps %ymm12,%ymm7,%ymm12 + .byte 196,66,101,168,227 // vfmadd213ps %ymm11,%ymm3,%ymm12 + .byte 196,65,20,88,228 // vaddps %ymm12,%ymm13,%ymm12 + .byte 197,20,88,232 // vaddps %ymm0,%ymm13,%ymm13 + .byte 197,252,194,195,0 // vcmpeqps %ymm3,%ymm0,%ymm0 + .byte 196,195,29,74,197,0 // vblendvps %ymm0,%ymm13,%ymm12,%ymm0 + .byte 196,65,92,194,224,0 // vcmpeqps %ymm8,%ymm4,%ymm12 + .byte 197,36,88,220 // vaddps %ymm4,%ymm11,%ymm11 + .byte 196,195,125,74,195,192 // vblendvps %ymm12,%ymm11,%ymm0,%ymm0 + .byte 197,44,89,217 // vmulps %ymm1,%ymm10,%ymm11 + .byte 197,100,89,229 // vmulps %ymm5,%ymm3,%ymm12 + .byte 197,100,92,233 // vsubps %ymm1,%ymm3,%ymm13 + .byte 196,65,28,94,229 // vdivps %ymm13,%ymm12,%ymm12 + .byte 197,52,89,237 // vmulps %ymm5,%ymm9,%ymm13 + .byte 196,65,68,93,228 // vminps %ymm12,%ymm7,%ymm12 + .byte 196,66,101,168,227 // vfmadd213ps %ymm11,%ymm3,%ymm12 + .byte 196,65,20,88,228 // vaddps %ymm12,%ymm13,%ymm12 + .byte 197,20,88,233 // vaddps %ymm1,%ymm13,%ymm13 + .byte 197,244,194,203,0 // vcmpeqps %ymm3,%ymm1,%ymm1 + .byte 196,195,29,74,205,16 // vblendvps %ymm1,%ymm13,%ymm12,%ymm1 + .byte 196,65,84,194,224,0 // vcmpeqps %ymm8,%ymm5,%ymm12 + .byte 197,36,88,221 // vaddps %ymm5,%ymm11,%ymm11 + .byte 196,195,117,74,203,192 // vblendvps %ymm12,%ymm11,%ymm1,%ymm1 + .byte 197,44,89,210 // vmulps %ymm2,%ymm10,%ymm10 + .byte 197,100,89,222 // vmulps %ymm6,%ymm3,%ymm11 + .byte 197,100,92,226 // vsubps %ymm2,%ymm3,%ymm12 + .byte 196,65,36,94,220 // vdivps %ymm12,%ymm11,%ymm11 + .byte 197,52,89,230 // vmulps %ymm6,%ymm9,%ymm12 + .byte 196,65,68,93,219 // vminps %ymm11,%ymm7,%ymm11 + .byte 196,66,101,168,218 // vfmadd213ps %ymm10,%ymm3,%ymm11 + .byte 196,65,28,88,219 // vaddps %ymm11,%ymm12,%ymm11 + .byte 197,28,88,226 // vaddps %ymm2,%ymm12,%ymm12 + .byte 197,236,194,211,0 // vcmpeqps %ymm3,%ymm2,%ymm2 + .byte 196,195,37,74,212,32 // vblendvps %ymm2,%ymm12,%ymm11,%ymm2 + .byte 196,65,76,194,192,0 // vcmpeqps %ymm8,%ymm6,%ymm8 + .byte 197,44,88,214 // vaddps %ymm6,%ymm10,%ymm10 + .byte 196,195,109,74,210,128 // vblendvps %ymm8,%ymm10,%ymm2,%ymm2 + .byte 196,194,69,184,217 // vfmadd231ps %ymm9,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_hardlight_hsw +.globl _sk_hardlight_hsw +_sk_hardlight_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,215 // vsubps %ymm7,%ymm8,%ymm10 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,220 // vmulps %ymm4,%ymm8,%ymm11 + .byte 196,98,45,184,216 // vfmadd231ps %ymm0,%ymm10,%ymm11 + .byte 197,124,88,200 // vaddps %ymm0,%ymm0,%ymm9 + .byte 197,52,194,227,2 // vcmpleps %ymm3,%ymm9,%ymm12 + .byte 197,124,89,204 // vmulps %ymm4,%ymm0,%ymm9 + .byte 196,65,52,88,233 // vaddps %ymm9,%ymm9,%ymm13 + .byte 197,100,89,207 // vmulps %ymm7,%ymm3,%ymm9 + .byte 197,68,92,244 // vsubps %ymm4,%ymm7,%ymm14 + .byte 197,228,92,192 // vsubps %ymm0,%ymm3,%ymm0 + .byte 196,193,124,89,198 // vmulps %ymm14,%ymm0,%ymm0 + .byte 197,252,88,192 // vaddps %ymm0,%ymm0,%ymm0 + .byte 197,180,92,192 // vsubps %ymm0,%ymm9,%ymm0 + .byte 196,195,125,74,197,192 // vblendvps %ymm12,%ymm13,%ymm0,%ymm0 + .byte 196,193,124,88,195 // vaddps %ymm11,%ymm0,%ymm0 + .byte 197,44,89,217 // vmulps %ymm1,%ymm10,%ymm11 + .byte 196,98,61,184,221 // vfmadd231ps %ymm5,%ymm8,%ymm11 + .byte 197,116,88,225 // vaddps %ymm1,%ymm1,%ymm12 + .byte 197,28,194,227,2 // vcmpleps %ymm3,%ymm12,%ymm12 + .byte 197,116,89,237 // vmulps %ymm5,%ymm1,%ymm13 + .byte 196,65,20,88,237 // vaddps %ymm13,%ymm13,%ymm13 + .byte 197,68,92,245 // vsubps %ymm5,%ymm7,%ymm14 + .byte 197,228,92,201 // vsubps %ymm1,%ymm3,%ymm1 + .byte 196,193,116,89,206 // vmulps %ymm14,%ymm1,%ymm1 + .byte 197,244,88,201 // vaddps %ymm1,%ymm1,%ymm1 + .byte 197,180,92,201 // vsubps %ymm1,%ymm9,%ymm1 + .byte 196,195,117,74,205,192 // vblendvps %ymm12,%ymm13,%ymm1,%ymm1 + .byte 196,193,116,88,203 // vaddps %ymm11,%ymm1,%ymm1 + .byte 197,44,89,210 // vmulps %ymm2,%ymm10,%ymm10 + .byte 196,98,61,184,214 // vfmadd231ps %ymm6,%ymm8,%ymm10 + .byte 197,108,88,218 // vaddps %ymm2,%ymm2,%ymm11 + .byte 197,36,194,219,2 // vcmpleps %ymm3,%ymm11,%ymm11 + .byte 197,108,89,230 // vmulps %ymm6,%ymm2,%ymm12 + .byte 196,65,28,88,228 // vaddps %ymm12,%ymm12,%ymm12 + .byte 197,68,92,238 // vsubps %ymm6,%ymm7,%ymm13 + .byte 197,228,92,210 // vsubps %ymm2,%ymm3,%ymm2 + .byte 196,193,108,89,213 // vmulps %ymm13,%ymm2,%ymm2 + .byte 197,236,88,210 // vaddps %ymm2,%ymm2,%ymm2 + .byte 197,180,92,210 // vsubps %ymm2,%ymm9,%ymm2 + .byte 196,195,109,74,212,176 // vblendvps %ymm11,%ymm12,%ymm2,%ymm2 + .byte 196,193,108,88,210 // vaddps %ymm10,%ymm2,%ymm2 + .byte 196,194,69,184,216 // vfmadd231ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_overlay_hsw +.globl _sk_overlay_hsw +_sk_overlay_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,215 // vsubps %ymm7,%ymm8,%ymm10 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,220 // vmulps %ymm4,%ymm8,%ymm11 + .byte 196,98,45,184,216 // vfmadd231ps %ymm0,%ymm10,%ymm11 + .byte 197,92,88,204 // vaddps %ymm4,%ymm4,%ymm9 + .byte 197,52,194,231,2 // vcmpleps %ymm7,%ymm9,%ymm12 + .byte 197,124,89,204 // vmulps %ymm4,%ymm0,%ymm9 + .byte 196,65,52,88,233 // vaddps %ymm9,%ymm9,%ymm13 + .byte 197,100,89,207 // vmulps %ymm7,%ymm3,%ymm9 + .byte 197,68,92,244 // vsubps %ymm4,%ymm7,%ymm14 + .byte 197,228,92,192 // vsubps %ymm0,%ymm3,%ymm0 + .byte 196,193,124,89,198 // vmulps %ymm14,%ymm0,%ymm0 + .byte 197,252,88,192 // vaddps %ymm0,%ymm0,%ymm0 + .byte 197,180,92,192 // vsubps %ymm0,%ymm9,%ymm0 + .byte 196,195,125,74,197,192 // vblendvps %ymm12,%ymm13,%ymm0,%ymm0 + .byte 196,193,124,88,195 // vaddps %ymm11,%ymm0,%ymm0 + .byte 197,44,89,217 // vmulps %ymm1,%ymm10,%ymm11 + .byte 196,98,61,184,221 // vfmadd231ps %ymm5,%ymm8,%ymm11 + .byte 197,84,88,229 // vaddps %ymm5,%ymm5,%ymm12 + .byte 197,28,194,231,2 // vcmpleps %ymm7,%ymm12,%ymm12 + .byte 197,116,89,237 // vmulps %ymm5,%ymm1,%ymm13 + .byte 196,65,20,88,237 // vaddps %ymm13,%ymm13,%ymm13 + .byte 197,68,92,245 // vsubps %ymm5,%ymm7,%ymm14 + .byte 197,228,92,201 // vsubps %ymm1,%ymm3,%ymm1 + .byte 196,193,116,89,206 // vmulps %ymm14,%ymm1,%ymm1 + .byte 197,244,88,201 // vaddps %ymm1,%ymm1,%ymm1 + .byte 197,180,92,201 // vsubps %ymm1,%ymm9,%ymm1 + .byte 196,195,117,74,205,192 // vblendvps %ymm12,%ymm13,%ymm1,%ymm1 + .byte 196,193,116,88,203 // vaddps %ymm11,%ymm1,%ymm1 + .byte 197,44,89,210 // vmulps %ymm2,%ymm10,%ymm10 + .byte 196,98,61,184,214 // vfmadd231ps %ymm6,%ymm8,%ymm10 + .byte 197,76,88,222 // vaddps %ymm6,%ymm6,%ymm11 + .byte 197,36,194,223,2 // vcmpleps %ymm7,%ymm11,%ymm11 + .byte 197,108,89,230 // vmulps %ymm6,%ymm2,%ymm12 + .byte 196,65,28,88,228 // vaddps %ymm12,%ymm12,%ymm12 + .byte 197,68,92,238 // vsubps %ymm6,%ymm7,%ymm13 + .byte 197,228,92,210 // vsubps %ymm2,%ymm3,%ymm2 + .byte 196,193,108,89,213 // vmulps %ymm13,%ymm2,%ymm2 + .byte 197,236,88,210 // vaddps %ymm2,%ymm2,%ymm2 + .byte 197,180,92,210 // vsubps %ymm2,%ymm9,%ymm2 + .byte 196,195,109,74,212,176 // vblendvps %ymm11,%ymm12,%ymm2,%ymm2 + .byte 196,193,108,88,210 // vaddps %ymm10,%ymm2,%ymm2 + .byte 196,194,69,184,216 // vfmadd231ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_softlight_hsw +.globl _sk_softlight_hsw +_sk_softlight_hsw: + .byte 197,252,17,84,36,200 // vmovups %ymm2,-0x38(%rsp) + .byte 196,65,44,87,210 // vxorps %ymm10,%ymm10,%ymm10 + .byte 197,44,194,223,1 // vcmpltps %ymm7,%ymm10,%ymm11 + .byte 197,92,94,199 // vdivps %ymm7,%ymm4,%ymm8 + .byte 196,67,45,74,224,176 // vblendvps %ymm11,%ymm8,%ymm10,%ymm12 + .byte 196,65,28,88,196 // vaddps %ymm12,%ymm12,%ymm8 + .byte 196,65,60,88,232 // vaddps %ymm8,%ymm8,%ymm13 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 196,66,21,168,237 // vfmadd213ps %ymm13,%ymm13,%ymm13 + .byte 196,65,28,92,240 // vsubps %ymm8,%ymm12,%ymm14 + .byte 184,0,0,224,64 // mov $0x40e00000,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 196,66,125,88,201 // vpbroadcastd %xmm9,%ymm9 + .byte 196,65,28,89,249 // vmulps %ymm9,%ymm12,%ymm15 + .byte 196,66,21,184,254 // vfmadd231ps %ymm14,%ymm13,%ymm15 + .byte 196,65,124,82,236 // vrsqrtps %ymm12,%ymm13 + .byte 196,65,124,83,237 // vrcpps %ymm13,%ymm13 + .byte 196,65,20,92,236 // vsubps %ymm12,%ymm13,%ymm13 + .byte 197,92,88,244 // vaddps %ymm4,%ymm4,%ymm14 + .byte 196,65,12,88,246 // vaddps %ymm14,%ymm14,%ymm14 + .byte 197,12,194,247,2 // vcmpleps %ymm7,%ymm14,%ymm14 + .byte 196,67,21,74,239,224 // vblendvps %ymm14,%ymm15,%ymm13,%ymm13 + .byte 197,124,88,240 // vaddps %ymm0,%ymm0,%ymm14 + .byte 197,12,92,251 // vsubps %ymm3,%ymm14,%ymm15 + .byte 196,65,60,92,228 // vsubps %ymm12,%ymm8,%ymm12 + .byte 196,98,5,168,227 // vfmadd213ps %ymm3,%ymm15,%ymm12 + .byte 197,28,89,228 // vmulps %ymm4,%ymm12,%ymm12 + .byte 197,4,89,255 // vmulps %ymm7,%ymm15,%ymm15 + .byte 196,65,4,89,237 // vmulps %ymm13,%ymm15,%ymm13 + .byte 196,98,101,184,236 // vfmadd231ps %ymm4,%ymm3,%ymm13 + .byte 197,12,194,243,2 // vcmpleps %ymm3,%ymm14,%ymm14 + .byte 196,195,21,74,212,224 // vblendvps %ymm14,%ymm12,%ymm13,%ymm2 + .byte 197,84,94,239 // vdivps %ymm7,%ymm5,%ymm13 + .byte 196,67,45,74,237,176 // vblendvps %ymm11,%ymm13,%ymm10,%ymm13 + .byte 196,65,20,88,245 // vaddps %ymm13,%ymm13,%ymm14 + .byte 196,65,12,88,246 // vaddps %ymm14,%ymm14,%ymm14 + .byte 196,66,13,168,246 // vfmadd213ps %ymm14,%ymm14,%ymm14 + .byte 196,65,20,92,248 // vsubps %ymm8,%ymm13,%ymm15 + .byte 196,65,4,89,246 // vmulps %ymm14,%ymm15,%ymm14 + .byte 196,66,53,184,245 // vfmadd231ps %ymm13,%ymm9,%ymm14 + .byte 196,65,124,82,253 // vrsqrtps %ymm13,%ymm15 + .byte 196,65,124,83,255 // vrcpps %ymm15,%ymm15 + .byte 196,65,4,92,253 // vsubps %ymm13,%ymm15,%ymm15 + .byte 197,84,88,229 // vaddps %ymm5,%ymm5,%ymm12 + .byte 196,65,28,88,228 // vaddps %ymm12,%ymm12,%ymm12 + .byte 197,28,194,231,2 // vcmpleps %ymm7,%ymm12,%ymm12 + .byte 196,67,5,74,230,192 // vblendvps %ymm12,%ymm14,%ymm15,%ymm12 + .byte 197,116,88,241 // vaddps %ymm1,%ymm1,%ymm14 + .byte 196,65,60,92,237 // vsubps %ymm13,%ymm8,%ymm13 + .byte 197,12,92,251 // vsubps %ymm3,%ymm14,%ymm15 + .byte 196,98,5,168,235 // vfmadd213ps %ymm3,%ymm15,%ymm13 + .byte 197,4,89,255 // vmulps %ymm7,%ymm15,%ymm15 + .byte 196,65,4,89,228 // vmulps %ymm12,%ymm15,%ymm12 + .byte 197,20,89,237 // vmulps %ymm5,%ymm13,%ymm13 + .byte 196,98,101,184,229 // vfmadd231ps %ymm5,%ymm3,%ymm12 + .byte 197,12,194,243,2 // vcmpleps %ymm3,%ymm14,%ymm14 + .byte 196,67,29,74,237,224 // vblendvps %ymm14,%ymm13,%ymm12,%ymm13 + .byte 197,76,94,231 // vdivps %ymm7,%ymm6,%ymm12 + .byte 196,67,45,74,212,176 // vblendvps %ymm11,%ymm12,%ymm10,%ymm10 + .byte 196,65,44,88,218 // vaddps %ymm10,%ymm10,%ymm11 + .byte 196,65,36,88,219 // vaddps %ymm11,%ymm11,%ymm11 + .byte 196,66,37,168,219 // vfmadd213ps %ymm11,%ymm11,%ymm11 + .byte 196,65,44,92,224 // vsubps %ymm8,%ymm10,%ymm12 + .byte 196,65,28,89,219 // vmulps %ymm11,%ymm12,%ymm11 + .byte 196,66,45,168,203 // vfmadd213ps %ymm11,%ymm10,%ymm9 + .byte 196,65,124,82,218 // vrsqrtps %ymm10,%ymm11 + .byte 196,65,124,83,219 // vrcpps %ymm11,%ymm11 + .byte 196,65,36,92,218 // vsubps %ymm10,%ymm11,%ymm11 + .byte 197,76,88,230 // vaddps %ymm6,%ymm6,%ymm12 + .byte 196,65,28,88,228 // vaddps %ymm12,%ymm12,%ymm12 + .byte 197,28,194,231,2 // vcmpleps %ymm7,%ymm12,%ymm12 + .byte 196,67,37,74,201,192 // vblendvps %ymm12,%ymm9,%ymm11,%ymm9 + .byte 197,124,16,116,36,200 // vmovups -0x38(%rsp),%ymm14 + .byte 196,65,12,88,222 // vaddps %ymm14,%ymm14,%ymm11 + .byte 197,36,92,227 // vsubps %ymm3,%ymm11,%ymm12 + .byte 196,65,60,92,210 // vsubps %ymm10,%ymm8,%ymm10 + .byte 196,98,29,168,211 // vfmadd213ps %ymm3,%ymm12,%ymm10 + .byte 197,28,89,231 // vmulps %ymm7,%ymm12,%ymm12 + .byte 196,65,28,89,201 // vmulps %ymm9,%ymm12,%ymm9 + .byte 197,44,89,214 // vmulps %ymm6,%ymm10,%ymm10 + .byte 196,98,101,184,206 // vfmadd231ps %ymm6,%ymm3,%ymm9 + .byte 197,36,194,219,2 // vcmpleps %ymm3,%ymm11,%ymm11 + .byte 196,67,53,74,202,176 // vblendvps %ymm11,%ymm10,%ymm9,%ymm9 + .byte 197,60,92,215 // vsubps %ymm7,%ymm8,%ymm10 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,220 // vmulps %ymm4,%ymm8,%ymm11 + .byte 196,98,45,184,216 // vfmadd231ps %ymm0,%ymm10,%ymm11 + .byte 196,193,108,88,195 // vaddps %ymm11,%ymm2,%ymm0 + .byte 197,172,89,201 // vmulps %ymm1,%ymm10,%ymm1 + .byte 196,226,61,184,205 // vfmadd231ps %ymm5,%ymm8,%ymm1 + .byte 196,193,116,88,205 // vaddps %ymm13,%ymm1,%ymm1 + .byte 196,193,44,89,214 // vmulps %ymm14,%ymm10,%ymm2 + .byte 196,226,61,184,214 // vfmadd231ps %ymm6,%ymm8,%ymm2 + .byte 196,193,108,88,209 // vaddps %ymm9,%ymm2,%ymm2 + .byte 196,194,69,184,216 // vfmadd231ps %ymm8,%ymm7,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_0_hsw +.globl _sk_clamp_0_hsw +_sk_clamp_0_hsw: + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 196,193,124,95,192 // vmaxps %ymm8,%ymm0,%ymm0 + .byte 196,193,116,95,200 // vmaxps %ymm8,%ymm1,%ymm1 + .byte 196,193,108,95,208 // vmaxps %ymm8,%ymm2,%ymm2 + .byte 196,193,100,95,216 // vmaxps %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_1_hsw +.globl _sk_clamp_1_hsw +_sk_clamp_1_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 196,193,124,93,192 // vminps %ymm8,%ymm0,%ymm0 + .byte 196,193,116,93,200 // vminps %ymm8,%ymm1,%ymm1 + .byte 196,193,108,93,208 // vminps %ymm8,%ymm2,%ymm2 + .byte 196,193,100,93,216 // vminps %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_a_hsw +.globl _sk_clamp_a_hsw +_sk_clamp_a_hsw: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 196,193,100,93,216 // vminps %ymm8,%ymm3,%ymm3 + .byte 197,252,93,195 // vminps %ymm3,%ymm0,%ymm0 + .byte 197,244,93,203 // vminps %ymm3,%ymm1,%ymm1 + .byte 197,236,93,211 // vminps %ymm3,%ymm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_set_rgb_hsw +.globl _sk_set_rgb_hsw +_sk_set_rgb_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,226,125,24,0 // vbroadcastss (%rax),%ymm0 + .byte 196,226,125,24,72,4 // vbroadcastss 0x4(%rax),%ymm1 + .byte 196,226,125,24,80,8 // vbroadcastss 0x8(%rax),%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_swap_rb_hsw +.globl _sk_swap_rb_hsw +_sk_swap_rb_hsw: + .byte 197,124,40,192 // vmovaps %ymm0,%ymm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,194 // vmovaps %ymm2,%ymm0 + .byte 197,124,41,194 // vmovaps %ymm8,%ymm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_swap_hsw +.globl _sk_swap_hsw +_sk_swap_hsw: + .byte 197,124,40,195 // vmovaps %ymm3,%ymm8 + .byte 197,124,40,202 // vmovaps %ymm2,%ymm9 + .byte 197,124,40,209 // vmovaps %ymm1,%ymm10 + .byte 197,124,40,216 // vmovaps %ymm0,%ymm11 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,196 // vmovaps %ymm4,%ymm0 + .byte 197,252,40,205 // vmovaps %ymm5,%ymm1 + .byte 197,252,40,214 // vmovaps %ymm6,%ymm2 + .byte 197,252,40,223 // vmovaps %ymm7,%ymm3 + .byte 197,124,41,220 // vmovaps %ymm11,%ymm4 + .byte 197,124,41,213 // vmovaps %ymm10,%ymm5 + .byte 197,124,41,206 // vmovaps %ymm9,%ymm6 + .byte 197,124,41,199 // vmovaps %ymm8,%ymm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_move_src_dst_hsw +.globl _sk_move_src_dst_hsw +_sk_move_src_dst_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,224 // vmovaps %ymm0,%ymm4 + .byte 197,252,40,233 // vmovaps %ymm1,%ymm5 + .byte 197,252,40,242 // vmovaps %ymm2,%ymm6 + .byte 197,252,40,251 // vmovaps %ymm3,%ymm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_move_dst_src_hsw +.globl _sk_move_dst_src_hsw +_sk_move_dst_src_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,196 // vmovaps %ymm4,%ymm0 + .byte 197,252,40,205 // vmovaps %ymm5,%ymm1 + .byte 197,252,40,214 // vmovaps %ymm6,%ymm2 + .byte 197,252,40,223 // vmovaps %ymm7,%ymm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_premul_hsw +.globl _sk_premul_hsw +_sk_premul_hsw: + .byte 197,252,89,195 // vmulps %ymm3,%ymm0,%ymm0 + .byte 197,244,89,203 // vmulps %ymm3,%ymm1,%ymm1 + .byte 197,236,89,211 // vmulps %ymm3,%ymm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_unpremul_hsw +.globl _sk_unpremul_hsw +_sk_unpremul_hsw: + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 196,65,100,194,200,0 // vcmpeqps %ymm8,%ymm3,%ymm9 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,208 // vmovd %eax,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 197,44,94,211 // vdivps %ymm3,%ymm10,%ymm10 + .byte 196,67,45,74,192,144 // vblendvps %ymm9,%ymm8,%ymm10,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_from_srgb_hsw +.globl _sk_from_srgb_hsw +_sk_from_srgb_hsw: + .byte 184,145,131,158,61 // mov $0x3d9e8391,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 197,124,89,208 // vmulps %ymm0,%ymm0,%ymm10 + .byte 184,154,153,153,62 // mov $0x3e99999a,%eax + .byte 197,121,110,216 // vmovd %eax,%xmm11 + .byte 196,66,125,88,219 // vpbroadcastd %xmm11,%ymm11 + .byte 184,92,143,50,63 // mov $0x3f328f5c,%eax + .byte 197,121,110,224 // vmovd %eax,%xmm12 + .byte 196,66,125,88,228 // vpbroadcastd %xmm12,%ymm12 + .byte 196,65,125,111,235 // vmovdqa %ymm11,%ymm13 + .byte 196,66,125,168,236 // vfmadd213ps %ymm12,%ymm0,%ymm13 + .byte 184,10,215,35,59 // mov $0x3b23d70a,%eax + .byte 197,121,110,240 // vmovd %eax,%xmm14 + .byte 196,66,125,88,246 // vpbroadcastd %xmm14,%ymm14 + .byte 196,66,45,168,238 // vfmadd213ps %ymm14,%ymm10,%ymm13 + .byte 184,174,71,97,61 // mov $0x3d6147ae,%eax + .byte 197,121,110,208 // vmovd %eax,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 196,193,124,194,194,1 // vcmpltps %ymm10,%ymm0,%ymm0 + .byte 196,195,21,74,193,0 // vblendvps %ymm0,%ymm9,%ymm13,%ymm0 + .byte 197,60,89,201 // vmulps %ymm1,%ymm8,%ymm9 + .byte 197,116,89,233 // vmulps %ymm1,%ymm1,%ymm13 + .byte 196,65,125,111,251 // vmovdqa %ymm11,%ymm15 + .byte 196,66,117,168,252 // vfmadd213ps %ymm12,%ymm1,%ymm15 + .byte 196,66,21,168,254 // vfmadd213ps %ymm14,%ymm13,%ymm15 + .byte 196,193,116,194,202,1 // vcmpltps %ymm10,%ymm1,%ymm1 + .byte 196,195,5,74,201,16 // vblendvps %ymm1,%ymm9,%ymm15,%ymm1 + .byte 197,60,89,194 // vmulps %ymm2,%ymm8,%ymm8 + .byte 197,108,89,202 // vmulps %ymm2,%ymm2,%ymm9 + .byte 196,66,109,168,220 // vfmadd213ps %ymm12,%ymm2,%ymm11 + .byte 196,66,53,168,222 // vfmadd213ps %ymm14,%ymm9,%ymm11 + .byte 196,193,108,194,210,1 // vcmpltps %ymm10,%ymm2,%ymm2 + .byte 196,195,37,74,208,32 // vblendvps %ymm2,%ymm8,%ymm11,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_to_srgb_hsw +.globl _sk_to_srgb_hsw +_sk_to_srgb_hsw: + .byte 197,124,82,192 // vrsqrtps %ymm0,%ymm8 + .byte 196,65,124,83,216 // vrcpps %ymm8,%ymm11 + .byte 196,65,124,82,224 // vrsqrtps %ymm8,%ymm12 + .byte 184,41,92,71,65 // mov $0x41475c29,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,89,232 // vmulps %ymm0,%ymm8,%ymm13 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 196,66,125,88,201 // vpbroadcastd %xmm9,%ymm9 + .byte 184,194,135,210,62 // mov $0x3ed287c2,%eax + .byte 197,121,110,208 // vmovd %eax,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 184,206,111,48,63 // mov $0x3f306fce,%eax + .byte 197,121,110,240 // vmovd %eax,%xmm14 + .byte 196,66,125,88,246 // vpbroadcastd %xmm14,%ymm14 + .byte 184,168,87,202,61 // mov $0x3dca57a8,%eax + .byte 53,0,0,0,128 // xor $0x80000000,%eax + .byte 197,121,110,248 // vmovd %eax,%xmm15 + .byte 196,66,125,88,255 // vpbroadcastd %xmm15,%ymm15 + .byte 196,66,13,168,223 // vfmadd213ps %ymm15,%ymm14,%ymm11 + .byte 196,66,45,184,220 // vfmadd231ps %ymm12,%ymm10,%ymm11 + .byte 196,65,52,93,219 // vminps %ymm11,%ymm9,%ymm11 + .byte 184,4,231,140,59 // mov $0x3b8ce704,%eax + .byte 197,121,110,224 // vmovd %eax,%xmm12 + .byte 196,66,125,88,228 // vpbroadcastd %xmm12,%ymm12 + .byte 196,193,124,194,196,1 // vcmpltps %ymm12,%ymm0,%ymm0 + .byte 196,195,37,74,197,0 // vblendvps %ymm0,%ymm13,%ymm11,%ymm0 + .byte 197,124,82,217 // vrsqrtps %ymm1,%ymm11 + .byte 196,65,124,83,235 // vrcpps %ymm11,%ymm13 + .byte 196,65,124,82,219 // vrsqrtps %ymm11,%ymm11 + .byte 196,66,13,168,239 // vfmadd213ps %ymm15,%ymm14,%ymm13 + .byte 196,66,45,184,235 // vfmadd231ps %ymm11,%ymm10,%ymm13 + .byte 197,60,89,217 // vmulps %ymm1,%ymm8,%ymm11 + .byte 196,65,52,93,237 // vminps %ymm13,%ymm9,%ymm13 + .byte 196,193,116,194,204,1 // vcmpltps %ymm12,%ymm1,%ymm1 + .byte 196,195,21,74,203,16 // vblendvps %ymm1,%ymm11,%ymm13,%ymm1 + .byte 197,124,82,218 // vrsqrtps %ymm2,%ymm11 + .byte 196,65,124,83,235 // vrcpps %ymm11,%ymm13 + .byte 196,66,13,168,239 // vfmadd213ps %ymm15,%ymm14,%ymm13 + .byte 196,65,124,82,219 // vrsqrtps %ymm11,%ymm11 + .byte 196,66,45,184,235 // vfmadd231ps %ymm11,%ymm10,%ymm13 + .byte 196,65,52,93,205 // vminps %ymm13,%ymm9,%ymm9 + .byte 197,60,89,194 // vmulps %ymm2,%ymm8,%ymm8 + .byte 196,193,108,194,212,1 // vcmpltps %ymm12,%ymm2,%ymm2 + .byte 196,195,53,74,208,32 // vblendvps %ymm2,%ymm8,%ymm9,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_from_2dot2_hsw +.globl _sk_from_2dot2_hsw +_sk_from_2dot2_hsw: + .byte 197,124,82,192 // vrsqrtps %ymm0,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,200 // vrsqrtps %ymm8,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 197,252,89,192 // vmulps %ymm0,%ymm0,%ymm0 + .byte 196,65,60,89,208 // vmulps %ymm8,%ymm8,%ymm10 + .byte 196,65,60,89,194 // vmulps %ymm10,%ymm8,%ymm8 + .byte 196,193,124,89,192 // vmulps %ymm8,%ymm0,%ymm0 + .byte 197,180,89,192 // vmulps %ymm0,%ymm9,%ymm0 + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 196,193,124,95,192 // vmaxps %ymm8,%ymm0,%ymm0 + .byte 197,124,82,201 // vrsqrtps %ymm1,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,209 // vrsqrtps %ymm9,%ymm10 + .byte 196,65,124,82,210 // vrsqrtps %ymm10,%ymm10 + .byte 197,244,89,201 // vmulps %ymm1,%ymm1,%ymm1 + .byte 196,65,52,89,217 // vmulps %ymm9,%ymm9,%ymm11 + .byte 196,65,52,89,203 // vmulps %ymm11,%ymm9,%ymm9 + .byte 196,193,116,89,201 // vmulps %ymm9,%ymm1,%ymm1 + .byte 197,172,89,201 // vmulps %ymm1,%ymm10,%ymm1 + .byte 196,193,116,95,200 // vmaxps %ymm8,%ymm1,%ymm1 + .byte 197,124,82,202 // vrsqrtps %ymm2,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,209 // vrsqrtps %ymm9,%ymm10 + .byte 196,65,124,82,210 // vrsqrtps %ymm10,%ymm10 + .byte 197,236,89,210 // vmulps %ymm2,%ymm2,%ymm2 + .byte 196,65,52,89,217 // vmulps %ymm9,%ymm9,%ymm11 + .byte 196,65,52,89,203 // vmulps %ymm11,%ymm9,%ymm9 + .byte 196,193,108,89,209 // vmulps %ymm9,%ymm2,%ymm2 + .byte 197,172,89,210 // vmulps %ymm2,%ymm10,%ymm2 + .byte 196,193,108,95,208 // vmaxps %ymm8,%ymm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_to_2dot2_hsw +.globl _sk_to_2dot2_hsw +_sk_to_2dot2_hsw: + .byte 197,252,82,192 // vrsqrtps %ymm0,%ymm0 + .byte 197,124,82,192 // vrsqrtps %ymm0,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,200 // vrsqrtps %ymm8,%ymm9 + .byte 197,252,83,192 // vrcpps %ymm0,%ymm0 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 196,65,124,83,193 // vrcpps %ymm9,%ymm8 + .byte 196,193,124,89,192 // vmulps %ymm8,%ymm0,%ymm0 + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 196,193,124,95,192 // vmaxps %ymm8,%ymm0,%ymm0 + .byte 197,252,82,201 // vrsqrtps %ymm1,%ymm1 + .byte 197,124,82,201 // vrsqrtps %ymm1,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,209 // vrsqrtps %ymm9,%ymm10 + .byte 197,252,83,201 // vrcpps %ymm1,%ymm1 + .byte 197,180,89,201 // vmulps %ymm1,%ymm9,%ymm1 + .byte 196,65,124,83,202 // vrcpps %ymm10,%ymm9 + .byte 196,193,116,89,201 // vmulps %ymm9,%ymm1,%ymm1 + .byte 196,193,116,95,200 // vmaxps %ymm8,%ymm1,%ymm1 + .byte 197,252,82,210 // vrsqrtps %ymm2,%ymm2 + .byte 197,124,82,202 // vrsqrtps %ymm2,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,209 // vrsqrtps %ymm9,%ymm10 + .byte 197,252,83,210 // vrcpps %ymm2,%ymm2 + .byte 197,180,89,210 // vmulps %ymm2,%ymm9,%ymm2 + .byte 196,65,124,83,202 // vrcpps %ymm10,%ymm9 + .byte 196,193,108,89,209 // vmulps %ymm9,%ymm2,%ymm2 + .byte 196,193,108,95,208 // vmaxps %ymm8,%ymm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_rgb_to_hsl_hsw +.globl _sk_rgb_to_hsl_hsw +_sk_rgb_to_hsl_hsw: + .byte 197,252,17,124,36,200 // vmovups %ymm7,-0x38(%rsp) + .byte 197,252,40,254 // vmovaps %ymm6,%ymm7 + .byte 197,252,40,245 // vmovaps %ymm5,%ymm6 + .byte 197,252,40,236 // vmovaps %ymm4,%ymm5 + .byte 197,252,40,227 // vmovaps %ymm3,%ymm4 + .byte 197,252,40,216 // vmovaps %ymm0,%ymm3 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 65,184,171,170,42,62 // mov $0x3e2aaaab,%r8d + .byte 184,0,0,192,64 // mov $0x40c00000,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 65,185,0,0,0,64 // mov $0x40000000,%r9d + .byte 184,0,0,128,64 // mov $0x40800000,%eax + .byte 197,121,110,208 // vmovd %eax,%xmm10 + .byte 197,100,95,217 // vmaxps %ymm1,%ymm3,%ymm11 + .byte 197,36,95,218 // vmaxps %ymm2,%ymm11,%ymm11 + .byte 197,100,93,225 // vminps %ymm1,%ymm3,%ymm12 + .byte 197,28,93,226 // vminps %ymm2,%ymm12,%ymm12 + .byte 196,65,36,92,236 // vsubps %ymm12,%ymm11,%ymm13 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 196,65,60,94,197 // vdivps %ymm13,%ymm8,%ymm8 + .byte 197,116,194,242,1 // vcmpltps %ymm2,%ymm1,%ymm14 + .byte 196,66,125,88,201 // vpbroadcastd %xmm9,%ymm9 + .byte 196,65,4,87,255 // vxorps %ymm15,%ymm15,%ymm15 + .byte 196,67,5,74,201,224 // vblendvps %ymm14,%ymm9,%ymm15,%ymm9 + .byte 197,116,92,242 // vsubps %ymm2,%ymm1,%ymm14 + .byte 196,66,61,168,241 // vfmadd213ps %ymm9,%ymm8,%ymm14 + .byte 197,236,92,195 // vsubps %ymm3,%ymm2,%ymm0 + .byte 197,100,92,201 // vsubps %ymm1,%ymm3,%ymm9 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 196,66,61,168,202 // vfmadd213ps %ymm10,%ymm8,%ymm9 + .byte 196,193,121,110,209 // vmovd %r9d,%xmm2 + .byte 196,98,125,88,210 // vpbroadcastd %xmm2,%ymm10 + .byte 196,194,61,168,194 // vfmadd213ps %ymm10,%ymm8,%ymm0 + .byte 197,164,194,201,0 // vcmpeqps %ymm1,%ymm11,%ymm1 + .byte 196,227,53,74,192,16 // vblendvps %ymm1,%ymm0,%ymm9,%ymm0 + .byte 184,0,0,0,63 // mov $0x3f000000,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 197,164,194,211,0 // vcmpeqps %ymm3,%ymm11,%ymm2 + .byte 196,195,125,74,198,32 // vblendvps %ymm2,%ymm14,%ymm0,%ymm0 + .byte 196,193,36,88,220 // vaddps %ymm12,%ymm11,%ymm3 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,228,89,209 // vmulps %ymm1,%ymm3,%ymm2 + .byte 197,244,194,202,1 // vcmpltps %ymm2,%ymm1,%ymm1 + .byte 196,65,44,92,195 // vsubps %ymm11,%ymm10,%ymm8 + .byte 196,65,60,92,196 // vsubps %ymm12,%ymm8,%ymm8 + .byte 196,195,101,74,200,16 // vblendvps %ymm1,%ymm8,%ymm3,%ymm1 + .byte 196,193,36,194,220,0 // vcmpeqps %ymm12,%ymm11,%ymm3 + .byte 197,148,94,201 // vdivps %ymm1,%ymm13,%ymm1 + .byte 196,195,125,74,199,48 // vblendvps %ymm3,%ymm15,%ymm0,%ymm0 + .byte 196,195,117,74,207,48 // vblendvps %ymm3,%ymm15,%ymm1,%ymm1 + .byte 196,193,121,110,216 // vmovd %r8d,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,228,89,192 // vmulps %ymm0,%ymm3,%ymm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,220 // vmovaps %ymm4,%ymm3 + .byte 197,252,40,229 // vmovaps %ymm5,%ymm4 + .byte 197,252,40,238 // vmovaps %ymm6,%ymm5 + .byte 197,252,40,247 // vmovaps %ymm7,%ymm6 + .byte 197,252,16,124,36,200 // vmovups -0x38(%rsp),%ymm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_hsl_to_rgb_hsw +.globl _sk_hsl_to_rgb_hsw +_sk_hsl_to_rgb_hsw: + .byte 72,131,236,56 // sub $0x38,%rsp + .byte 197,252,17,60,36 // vmovups %ymm7,(%rsp) + .byte 197,252,17,116,36,224 // vmovups %ymm6,-0x20(%rsp) + .byte 197,252,17,108,36,192 // vmovups %ymm5,-0x40(%rsp) + .byte 197,252,17,100,36,160 // vmovups %ymm4,-0x60(%rsp) + .byte 197,252,17,92,36,128 // vmovups %ymm3,-0x80(%rsp) + .byte 197,252,40,233 // vmovaps %ymm1,%ymm5 + .byte 184,0,0,0,63 // mov $0x3f000000,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,98,125,88,193 // vpbroadcastd %xmm1,%ymm8 + .byte 196,193,108,194,200,1 // vcmpltps %ymm8,%ymm2,%ymm1 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,224 // vmovd %eax,%xmm4 + .byte 196,98,125,88,212 // vpbroadcastd %xmm4,%ymm10 + .byte 197,172,88,229 // vaddps %ymm5,%ymm10,%ymm4 + .byte 197,220,89,226 // vmulps %ymm2,%ymm4,%ymm4 + .byte 197,84,88,202 // vaddps %ymm2,%ymm5,%ymm9 + .byte 196,98,85,188,202 // vfnmadd231ps %ymm2,%ymm5,%ymm9 + .byte 196,99,53,74,204,16 // vblendvps %ymm1,%ymm4,%ymm9,%ymm9 + .byte 65,184,0,0,0,64 // mov $0x40000000,%r8d + .byte 184,171,170,170,62 // mov $0x3eaaaaab,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,98,125,88,233 // vpbroadcastd %xmm1,%ymm13 + .byte 197,148,88,224 // vaddps %ymm0,%ymm13,%ymm4 + .byte 184,0,0,0,0 // mov $0x0,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,98,125,88,225 // vpbroadcastd %xmm1,%ymm12 + .byte 197,172,194,204,1 // vcmpltps %ymm4,%ymm10,%ymm1 + .byte 196,65,92,92,218 // vsubps %ymm10,%ymm4,%ymm11 + .byte 196,195,93,74,203,16 // vblendvps %ymm1,%ymm11,%ymm4,%ymm1 + .byte 196,65,92,194,220,1 // vcmpltps %ymm12,%ymm4,%ymm11 + .byte 197,44,88,244 // vaddps %ymm4,%ymm10,%ymm14 + .byte 196,195,117,74,206,176 // vblendvps %ymm11,%ymm14,%ymm1,%ymm1 + .byte 196,193,121,110,216 // vmovd %r8d,%xmm3 + .byte 196,98,125,88,219 // vpbroadcastd %xmm3,%ymm11 + .byte 196,66,109,170,217 // vfmsub213ps %ymm9,%ymm2,%ymm11 + .byte 65,184,171,170,42,62 // mov $0x3e2aaaab,%r8d + .byte 184,0,0,192,64 // mov $0x40c00000,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 196,65,52,92,243 // vsubps %ymm11,%ymm9,%ymm14 + .byte 197,12,89,243 // vmulps %ymm3,%ymm14,%ymm14 + .byte 184,171,170,42,63 // mov $0x3f2aaaab,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,98,125,88,251 // vpbroadcastd %xmm3,%ymm15 + .byte 197,132,92,217 // vsubps %ymm1,%ymm15,%ymm3 + .byte 196,194,13,168,219 // vfmadd213ps %ymm11,%ymm14,%ymm3 + .byte 196,193,116,194,255,1 // vcmpltps %ymm15,%ymm1,%ymm7 + .byte 196,227,37,74,219,112 // vblendvps %ymm7,%ymm3,%ymm11,%ymm3 + .byte 196,193,116,194,248,1 // vcmpltps %ymm8,%ymm1,%ymm7 + .byte 196,195,101,74,249,112 // vblendvps %ymm7,%ymm9,%ymm3,%ymm7 + .byte 196,193,121,110,216 // vmovd %r8d,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,244,194,203,1 // vcmpltps %ymm3,%ymm1,%ymm1 + .byte 196,194,13,168,227 // vfmadd213ps %ymm11,%ymm14,%ymm4 + .byte 196,227,69,74,228,16 // vblendvps %ymm1,%ymm4,%ymm7,%ymm4 + .byte 197,172,194,200,1 // vcmpltps %ymm0,%ymm10,%ymm1 + .byte 196,193,124,92,250 // vsubps %ymm10,%ymm0,%ymm7 + .byte 196,227,125,74,207,16 // vblendvps %ymm1,%ymm7,%ymm0,%ymm1 + .byte 196,193,124,194,252,1 // vcmpltps %ymm12,%ymm0,%ymm7 + .byte 197,172,88,240 // vaddps %ymm0,%ymm10,%ymm6 + .byte 196,227,117,74,206,112 // vblendvps %ymm7,%ymm6,%ymm1,%ymm1 + .byte 197,132,92,241 // vsubps %ymm1,%ymm15,%ymm6 + .byte 196,194,13,168,243 // vfmadd213ps %ymm11,%ymm14,%ymm6 + .byte 196,193,116,194,255,1 // vcmpltps %ymm15,%ymm1,%ymm7 + .byte 196,227,37,74,246,112 // vblendvps %ymm7,%ymm6,%ymm11,%ymm6 + .byte 196,193,116,194,248,1 // vcmpltps %ymm8,%ymm1,%ymm7 + .byte 196,195,77,74,241,112 // vblendvps %ymm7,%ymm9,%ymm6,%ymm6 + .byte 197,244,194,203,1 // vcmpltps %ymm3,%ymm1,%ymm1 + .byte 196,193,124,92,253 // vsubps %ymm13,%ymm0,%ymm7 + .byte 196,194,13,168,195 // vfmadd213ps %ymm11,%ymm14,%ymm0 + .byte 196,227,77,74,200,16 // vblendvps %ymm1,%ymm0,%ymm6,%ymm1 + .byte 197,172,194,199,1 // vcmpltps %ymm7,%ymm10,%ymm0 + .byte 196,193,68,92,242 // vsubps %ymm10,%ymm7,%ymm6 + .byte 196,227,69,74,198,0 // vblendvps %ymm0,%ymm6,%ymm7,%ymm0 + .byte 196,193,68,194,244,1 // vcmpltps %ymm12,%ymm7,%ymm6 + .byte 197,44,88,215 // vaddps %ymm7,%ymm10,%ymm10 + .byte 196,195,125,74,194,96 // vblendvps %ymm6,%ymm10,%ymm0,%ymm0 + .byte 196,194,13,168,251 // vfmadd213ps %ymm11,%ymm14,%ymm7 + .byte 197,132,92,240 // vsubps %ymm0,%ymm15,%ymm6 + .byte 196,194,13,168,243 // vfmadd213ps %ymm11,%ymm14,%ymm6 + .byte 196,65,124,194,215,1 // vcmpltps %ymm15,%ymm0,%ymm10 + .byte 196,227,37,74,246,160 // vblendvps %ymm10,%ymm6,%ymm11,%ymm6 + .byte 196,65,124,194,192,1 // vcmpltps %ymm8,%ymm0,%ymm8 + .byte 196,195,77,74,241,128 // vblendvps %ymm8,%ymm9,%ymm6,%ymm6 + .byte 197,252,194,195,1 // vcmpltps %ymm3,%ymm0,%ymm0 + .byte 196,227,77,74,223,0 // vblendvps %ymm0,%ymm7,%ymm6,%ymm3 + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,212,194,232,0 // vcmpeqps %ymm0,%ymm5,%ymm5 + .byte 196,227,93,74,194,80 // vblendvps %ymm5,%ymm2,%ymm4,%ymm0 + .byte 196,227,117,74,202,80 // vblendvps %ymm5,%ymm2,%ymm1,%ymm1 + .byte 196,227,101,74,210,80 // vblendvps %ymm5,%ymm2,%ymm3,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,16,92,36,128 // vmovups -0x80(%rsp),%ymm3 + .byte 197,252,16,100,36,160 // vmovups -0x60(%rsp),%ymm4 + .byte 197,252,16,108,36,192 // vmovups -0x40(%rsp),%ymm5 + .byte 197,252,16,116,36,224 // vmovups -0x20(%rsp),%ymm6 + .byte 197,252,16,60,36 // vmovups (%rsp),%ymm7 + .byte 72,131,196,56 // add $0x38,%rsp + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_scale_1_float_hsw +.globl _sk_scale_1_float_hsw +_sk_scale_1_float_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_scale_u8_hsw +.globl _sk_scale_u8_hsw +_sk_scale_u8_hsw: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,1,248 // add %rdi,%rax + .byte 77,133,192 // test %r8,%r8 + .byte 117,56 // jne 11bc <_sk_scale_u8_hsw+0x48> + .byte 197,122,126,0 // vmovq (%rax),%xmm8 + .byte 196,66,125,49,192 // vpmovzxbd %xmm8,%ymm8 + .byte 196,65,124,91,192 // vcvtdq2ps %ymm8,%ymm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 196,66,125,88,201 // vpbroadcastd %xmm9,%ymm9 + .byte 196,65,60,89,193 // vmulps %ymm9,%ymm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,137,193 // mov %r8,%rcx + .byte 255,224 // jmpq *%rax + .byte 49,201 // xor %ecx,%ecx + .byte 77,137,194 // mov %r8,%r10 + .byte 69,49,201 // xor %r9d,%r9d + .byte 68,15,182,24 // movzbl (%rax),%r11d + .byte 72,255,192 // inc %rax + .byte 73,211,227 // shl %cl,%r11 + .byte 77,9,217 // or %r11,%r9 + .byte 72,131,193,8 // add $0x8,%rcx + .byte 73,255,202 // dec %r10 + .byte 117,234 // jne 11c4 <_sk_scale_u8_hsw+0x50> + .byte 196,65,249,110,193 // vmovq %r9,%xmm8 + .byte 235,167 // jmp 1188 <_sk_scale_u8_hsw+0x14> + +HIDDEN _sk_lerp_1_float_hsw +.globl _sk_lerp_1_float_hsw +_sk_lerp_1_float_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 197,252,92,196 // vsubps %ymm4,%ymm0,%ymm0 + .byte 196,226,61,168,196 // vfmadd213ps %ymm4,%ymm8,%ymm0 + .byte 197,244,92,205 // vsubps %ymm5,%ymm1,%ymm1 + .byte 196,226,61,168,205 // vfmadd213ps %ymm5,%ymm8,%ymm1 + .byte 197,236,92,214 // vsubps %ymm6,%ymm2,%ymm2 + .byte 196,226,61,168,214 // vfmadd213ps %ymm6,%ymm8,%ymm2 + .byte 197,228,92,223 // vsubps %ymm7,%ymm3,%ymm3 + .byte 196,226,61,168,223 // vfmadd213ps %ymm7,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lerp_u8_hsw +.globl _sk_lerp_u8_hsw +_sk_lerp_u8_hsw: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,1,248 // add %rdi,%rax + .byte 77,133,192 // test %r8,%r8 + .byte 117,76 // jne 126c <_sk_lerp_u8_hsw+0x5c> + .byte 197,122,126,0 // vmovq (%rax),%xmm8 + .byte 196,66,125,49,192 // vpmovzxbd %xmm8,%ymm8 + .byte 196,65,124,91,192 // vcvtdq2ps %ymm8,%ymm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 196,66,125,88,201 // vpbroadcastd %xmm9,%ymm9 + .byte 196,65,60,89,193 // vmulps %ymm9,%ymm8,%ymm8 + .byte 197,252,92,196 // vsubps %ymm4,%ymm0,%ymm0 + .byte 196,226,61,168,196 // vfmadd213ps %ymm4,%ymm8,%ymm0 + .byte 197,244,92,205 // vsubps %ymm5,%ymm1,%ymm1 + .byte 196,226,61,168,205 // vfmadd213ps %ymm5,%ymm8,%ymm1 + .byte 197,236,92,214 // vsubps %ymm6,%ymm2,%ymm2 + .byte 196,226,61,168,214 // vfmadd213ps %ymm6,%ymm8,%ymm2 + .byte 197,228,92,223 // vsubps %ymm7,%ymm3,%ymm3 + .byte 196,226,61,168,223 // vfmadd213ps %ymm7,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,137,193 // mov %r8,%rcx + .byte 255,224 // jmpq *%rax + .byte 49,201 // xor %ecx,%ecx + .byte 77,137,194 // mov %r8,%r10 + .byte 69,49,201 // xor %r9d,%r9d + .byte 68,15,182,24 // movzbl (%rax),%r11d + .byte 72,255,192 // inc %rax + .byte 73,211,227 // shl %cl,%r11 + .byte 77,9,217 // or %r11,%r9 + .byte 72,131,193,8 // add $0x8,%rcx + .byte 73,255,202 // dec %r10 + .byte 117,234 // jne 1274 <_sk_lerp_u8_hsw+0x64> + .byte 196,65,249,110,193 // vmovq %r9,%xmm8 + .byte 235,147 // jmp 1224 <_sk_lerp_u8_hsw+0x14> + +HIDDEN _sk_lerp_565_hsw +.globl _sk_lerp_565_hsw +_sk_lerp_565_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,16 // mov (%rax),%r10 + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,179,0,0,0 // jne 1352 <_sk_lerp_565_hsw+0xc1> + .byte 196,193,122,111,28,122 // vmovdqu (%r10,%rdi,2),%xmm3 + .byte 196,98,125,51,195 // vpmovzxwd %xmm3,%ymm8 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 196,193,101,219,216 // vpand %ymm8,%ymm3,%ymm3 + .byte 197,124,91,203 // vcvtdq2ps %ymm3,%ymm9 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,52,89,203 // vmulps %ymm3,%ymm9,%ymm9 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 196,193,101,219,216 // vpand %ymm8,%ymm3,%ymm3 + .byte 197,124,91,211 // vcvtdq2ps %ymm3,%ymm10 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,44,89,211 // vmulps %ymm3,%ymm10,%ymm10 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 196,193,101,219,216 // vpand %ymm8,%ymm3,%ymm3 + .byte 197,124,91,195 // vcvtdq2ps %ymm3,%ymm8 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 197,252,92,196 // vsubps %ymm4,%ymm0,%ymm0 + .byte 196,226,53,168,196 // vfmadd213ps %ymm4,%ymm9,%ymm0 + .byte 197,244,92,205 // vsubps %ymm5,%ymm1,%ymm1 + .byte 196,226,45,168,205 // vfmadd213ps %ymm5,%ymm10,%ymm1 + .byte 197,236,92,214 // vsubps %ymm6,%ymm2,%ymm2 + .byte 196,226,101,168,214 // vfmadd213ps %ymm6,%ymm3,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 197,225,239,219 // vpxor %xmm3,%xmm3,%xmm3 + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 15,135,59,255,255,255 // ja 12a5 <_sk_lerp_565_hsw+0x14> + .byte 69,15,182,192 // movzbl %r8b,%r8d + .byte 76,141,13,75,0,0,0 // lea 0x4b(%rip),%r9 # 13c0 <_sk_lerp_565_hsw+0x12f> + .byte 75,99,4,129 // movslq (%r9,%r8,4),%rax + .byte 76,1,200 // add %r9,%rax + .byte 255,224 // jmpq *%rax + .byte 197,225,239,219 // vpxor %xmm3,%xmm3,%xmm3 + .byte 196,193,97,196,92,122,12,6 // vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm3,%xmm3 + .byte 196,193,97,196,92,122,10,5 // vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm3,%xmm3 + .byte 196,193,97,196,92,122,8,4 // vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm3,%xmm3 + .byte 196,193,97,196,92,122,6,3 // vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm3,%xmm3 + .byte 196,193,97,196,92,122,4,2 // vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm3,%xmm3 + .byte 196,193,97,196,92,122,2,1 // vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm3,%xmm3 + .byte 196,193,97,196,28,122,0 // vpinsrw $0x0,(%r10,%rdi,2),%xmm3,%xmm3 + .byte 233,231,254,255,255 // jmpq 12a5 <_sk_lerp_565_hsw+0x14> + .byte 102,144 // xchg %ax,%ax + .byte 242,255 // repnz (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 234 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,226 // jmpq *%rdx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 218,255 // (bad) + .byte 255 // (bad) + .byte 255,210 // callq *%rdx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,202 // dec %edx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 190 // .byte 0xbe + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_load_tables_hsw +.globl _sk_load_tables_hsw +_sk_load_tables_hsw: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,141,12,189,0,0,0,0 // lea 0x0(,%rdi,4),%r9 + .byte 76,3,8 // add (%rax),%r9 + .byte 77,133,192 // test %r8,%r8 + .byte 117,121 // jne 146a <_sk_load_tables_hsw+0x8e> + .byte 196,193,126,111,25 // vmovdqu (%r9),%ymm3 + .byte 185,255,0,0,0 // mov $0xff,%ecx + .byte 197,249,110,193 // vmovd %ecx,%xmm0 + .byte 196,226,125,88,208 // vpbroadcastd %xmm0,%ymm2 + .byte 197,237,219,203 // vpand %ymm3,%ymm2,%ymm1 + .byte 196,65,61,118,192 // vpcmpeqd %ymm8,%ymm8,%ymm8 + .byte 72,139,72,8 // mov 0x8(%rax),%rcx + .byte 76,139,72,16 // mov 0x10(%rax),%r9 + .byte 196,65,53,118,201 // vpcmpeqd %ymm9,%ymm9,%ymm9 + .byte 196,226,53,146,4,137 // vgatherdps %ymm9,(%rcx,%ymm1,4),%ymm0 + .byte 197,245,114,211,8 // vpsrld $0x8,%ymm3,%ymm1 + .byte 197,109,219,201 // vpand %ymm1,%ymm2,%ymm9 + .byte 196,65,45,118,210 // vpcmpeqd %ymm10,%ymm10,%ymm10 + .byte 196,130,45,146,12,137 // vgatherdps %ymm10,(%r9,%ymm9,4),%ymm1 + .byte 72,139,64,24 // mov 0x18(%rax),%rax + .byte 197,181,114,211,16 // vpsrld $0x10,%ymm3,%ymm9 + .byte 196,65,109,219,201 // vpand %ymm9,%ymm2,%ymm9 + .byte 196,162,61,146,20,136 // vgatherdps %ymm8,(%rax,%ymm9,4),%ymm2 + .byte 197,229,114,211,24 // vpsrld $0x18,%ymm3,%ymm3 + .byte 197,124,91,195 // vcvtdq2ps %ymm3,%ymm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,137,193 // mov %r8,%rcx + .byte 255,224 // jmpq *%rax + .byte 185,8,0,0,0 // mov $0x8,%ecx + .byte 68,41,193 // sub %r8d,%ecx + .byte 192,225,3 // shl $0x3,%cl + .byte 73,199,194,255,255,255,255 // mov $0xffffffffffffffff,%r10 + .byte 73,211,234 // shr %cl,%r10 + .byte 196,193,249,110,194 // vmovq %r10,%xmm0 + .byte 196,226,125,33,192 // vpmovsxbd %xmm0,%ymm0 + .byte 196,194,125,140,25 // vpmaskmovd (%r9),%ymm0,%ymm3 + .byte 233,99,255,255,255 // jmpq 13f6 <_sk_load_tables_hsw+0x1a> + +HIDDEN _sk_byte_tables_hsw +.globl _sk_byte_tables_hsw +_sk_byte_tables_hsw: + .byte 85 // push %rbp + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,127,67 // mov $0x437f0000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,253,91,192 // vcvtps2dq %ymm0,%ymm0 + .byte 196,195,249,22,192,1 // vpextrq $0x1,%xmm0,%r8 + .byte 68,137,197 // mov %r8d,%ebp + .byte 77,137,194 // mov %r8,%r10 + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,193,249,126,192 // vmovq %xmm0,%r8 + .byte 69,137,195 // mov %r8d,%r11d + .byte 77,137,199 // mov %r8,%r15 + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,227,125,57,192,1 // vextracti128 $0x1,%ymm0,%xmm0 + .byte 196,195,249,22,192,1 // vpextrq $0x1,%xmm0,%r8 + .byte 69,137,198 // mov %r8d,%r14d + .byte 77,137,196 // mov %r8,%r12 + .byte 73,193,236,32 // shr $0x20,%r12 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,221 // mov %ebx,%r13d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 76,139,8 // mov (%rax),%r9 + .byte 76,139,64,8 // mov 0x8(%rax),%r8 + .byte 196,131,121,32,4,25,0 // vpinsrb $0x0,(%r9,%r11,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,57,1 // vpinsrb $0x1,(%r9,%r15,1),%xmm0,%xmm0 + .byte 65,15,182,44,41 // movzbl (%r9,%rbp,1),%ebp + .byte 196,227,121,32,197,2 // vpinsrb $0x2,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,17 // movzbl (%r9,%r10,1),%ebp + .byte 196,227,121,32,197,3 // vpinsrb $0x3,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,41 // movzbl (%r9,%r13,1),%ebp + .byte 196,227,121,32,197,4 // vpinsrb $0x4,%ebp,%xmm0,%xmm0 + .byte 65,15,182,44,25 // movzbl (%r9,%rbx,1),%ebp + .byte 196,227,121,32,197,5 // vpinsrb $0x5,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,49 // movzbl (%r9,%r14,1),%ebp + .byte 196,227,121,32,197,6 // vpinsrb $0x6,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,33 // movzbl (%r9,%r12,1),%ebp + .byte 196,227,121,32,197,7 // vpinsrb $0x7,%ebp,%xmm0,%xmm0 + .byte 196,226,125,49,192 // vpmovzxbd %xmm0,%ymm0 + .byte 197,124,91,208 // vcvtdq2ps %ymm0,%ymm10 + .byte 189,129,128,128,59 // mov $0x3b808081,%ebp + .byte 197,249,110,197 // vmovd %ebp,%xmm0 + .byte 196,98,125,88,200 // vpbroadcastd %xmm0,%ymm9 + .byte 196,193,44,89,193 // vmulps %ymm9,%ymm10,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,253,91,201 // vcvtps2dq %ymm1,%ymm1 + .byte 196,227,249,22,205,1 // vpextrq $0x1,%xmm1,%rbp + .byte 65,137,233 // mov %ebp,%r9d + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,225,249,126,203 // vmovq %xmm1,%rbx + .byte 65,137,218 // mov %ebx,%r10d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,227,125,57,201,1 // vextracti128 $0x1,%ymm1,%xmm1 + .byte 196,195,249,22,203,1 // vpextrq $0x1,%xmm1,%r11 + .byte 69,137,222 // mov %r11d,%r14d + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 196,193,249,126,207 // vmovq %xmm1,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,131,121,32,12,16,0 // vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm1 + .byte 196,195,113,32,12,24,1 // vpinsrb $0x1,(%r8,%rbx,1),%xmm1,%xmm1 + .byte 67,15,182,28,8 // movzbl (%r8,%r9,1),%ebx + .byte 196,227,113,32,203,2 // vpinsrb $0x2,%ebx,%xmm1,%xmm1 + .byte 65,15,182,44,40 // movzbl (%r8,%rbp,1),%ebp + .byte 196,227,113,32,205,3 // vpinsrb $0x3,%ebp,%xmm1,%xmm1 + .byte 67,15,182,44,32 // movzbl (%r8,%r12,1),%ebp + .byte 196,227,113,32,205,4 // vpinsrb $0x4,%ebp,%xmm1,%xmm1 + .byte 67,15,182,44,56 // movzbl (%r8,%r15,1),%ebp + .byte 196,227,113,32,205,5 // vpinsrb $0x5,%ebp,%xmm1,%xmm1 + .byte 67,15,182,44,48 // movzbl (%r8,%r14,1),%ebp + .byte 196,227,113,32,205,6 // vpinsrb $0x6,%ebp,%xmm1,%xmm1 + .byte 67,15,182,44,24 // movzbl (%r8,%r11,1),%ebp + .byte 196,227,113,32,205,7 // vpinsrb $0x7,%ebp,%xmm1,%xmm1 + .byte 196,226,125,49,201 // vpmovzxbd %xmm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 197,180,89,201 // vmulps %ymm1,%ymm9,%ymm1 + .byte 76,139,64,16 // mov 0x10(%rax),%r8 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,253,91,210 // vcvtps2dq %ymm2,%ymm2 + .byte 196,227,249,22,213,1 // vpextrq $0x1,%xmm2,%rbp + .byte 65,137,233 // mov %ebp,%r9d + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,225,249,126,211 // vmovq %xmm2,%rbx + .byte 65,137,218 // mov %ebx,%r10d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,227,125,57,210,1 // vextracti128 $0x1,%ymm2,%xmm2 + .byte 196,195,249,22,211,1 // vpextrq $0x1,%xmm2,%r11 + .byte 69,137,222 // mov %r11d,%r14d + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 196,193,249,126,215 // vmovq %xmm2,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,131,121,32,20,16,0 // vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm2 + .byte 196,195,105,32,20,24,1 // vpinsrb $0x1,(%r8,%rbx,1),%xmm2,%xmm2 + .byte 67,15,182,28,8 // movzbl (%r8,%r9,1),%ebx + .byte 196,227,105,32,211,2 // vpinsrb $0x2,%ebx,%xmm2,%xmm2 + .byte 65,15,182,44,40 // movzbl (%r8,%rbp,1),%ebp + .byte 196,227,105,32,213,3 // vpinsrb $0x3,%ebp,%xmm2,%xmm2 + .byte 67,15,182,44,32 // movzbl (%r8,%r12,1),%ebp + .byte 196,227,105,32,213,4 // vpinsrb $0x4,%ebp,%xmm2,%xmm2 + .byte 67,15,182,44,56 // movzbl (%r8,%r15,1),%ebp + .byte 196,227,105,32,213,5 // vpinsrb $0x5,%ebp,%xmm2,%xmm2 + .byte 67,15,182,44,48 // movzbl (%r8,%r14,1),%ebp + .byte 196,227,105,32,213,6 // vpinsrb $0x6,%ebp,%xmm2,%xmm2 + .byte 67,15,182,44,24 // movzbl (%r8,%r11,1),%ebp + .byte 196,227,105,32,213,7 // vpinsrb $0x7,%ebp,%xmm2,%xmm2 + .byte 196,226,125,49,210 // vpmovzxbd %xmm2,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 197,180,89,210 // vmulps %ymm2,%ymm9,%ymm2 + .byte 72,139,64,24 // mov 0x18(%rax),%rax + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 197,253,91,219 // vcvtps2dq %ymm3,%ymm3 + .byte 196,227,249,22,221,1 // vpextrq $0x1,%xmm3,%rbp + .byte 65,137,232 // mov %ebp,%r8d + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,225,249,126,219 // vmovq %xmm3,%rbx + .byte 65,137,217 // mov %ebx,%r9d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,227,125,57,219,1 // vextracti128 $0x1,%ymm3,%xmm3 + .byte 196,195,249,22,218,1 // vpextrq $0x1,%xmm3,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,193,249,126,222 // vmovq %xmm3,%r14 + .byte 69,137,247 // mov %r14d,%r15d + .byte 73,193,238,32 // shr $0x20,%r14 + .byte 196,163,121,32,28,8,0 // vpinsrb $0x0,(%rax,%r9,1),%xmm0,%xmm3 + .byte 196,227,97,32,28,24,1 // vpinsrb $0x1,(%rax,%rbx,1),%xmm3,%xmm3 + .byte 66,15,182,28,0 // movzbl (%rax,%r8,1),%ebx + .byte 196,227,97,32,219,2 // vpinsrb $0x2,%ebx,%xmm3,%xmm3 + .byte 15,182,44,40 // movzbl (%rax,%rbp,1),%ebp + .byte 196,227,97,32,221,3 // vpinsrb $0x3,%ebp,%xmm3,%xmm3 + .byte 66,15,182,44,56 // movzbl (%rax,%r15,1),%ebp + .byte 196,227,97,32,221,4 // vpinsrb $0x4,%ebp,%xmm3,%xmm3 + .byte 66,15,182,44,48 // movzbl (%rax,%r14,1),%ebp + .byte 196,227,97,32,221,5 // vpinsrb $0x5,%ebp,%xmm3,%xmm3 + .byte 66,15,182,44,24 // movzbl (%rax,%r11,1),%ebp + .byte 196,227,97,32,221,6 // vpinsrb $0x6,%ebp,%xmm3,%xmm3 + .byte 66,15,182,4,16 // movzbl (%rax,%r10,1),%eax + .byte 196,227,97,32,216,7 // vpinsrb $0x7,%eax,%xmm3,%xmm3 + .byte 196,226,125,49,219 // vpmovzxbd %xmm3,%ymm3 + .byte 197,252,91,219 // vcvtdq2ps %ymm3,%ymm3 + .byte 197,180,89,219 // vmulps %ymm3,%ymm9,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 93 // pop %rbp + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_byte_tables_rgb_hsw +.globl _sk_byte_tables_rgb_hsw +_sk_byte_tables_rgb_hsw: + .byte 85 // push %rbp + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 68,139,64,24 // mov 0x18(%rax),%r8d + .byte 65,255,200 // dec %r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 196,65,124,91,192 // vcvtdq2ps %ymm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,253,91,192 // vcvtps2dq %ymm0,%ymm0 + .byte 196,195,249,22,192,1 // vpextrq $0x1,%xmm0,%r8 + .byte 68,137,197 // mov %r8d,%ebp + .byte 77,137,194 // mov %r8,%r10 + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,193,249,126,192 // vmovq %xmm0,%r8 + .byte 69,137,195 // mov %r8d,%r11d + .byte 77,137,199 // mov %r8,%r15 + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,227,125,57,192,1 // vextracti128 $0x1,%ymm0,%xmm0 + .byte 196,195,249,22,192,1 // vpextrq $0x1,%xmm0,%r8 + .byte 69,137,198 // mov %r8d,%r14d + .byte 77,137,196 // mov %r8,%r12 + .byte 73,193,236,32 // shr $0x20,%r12 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,221 // mov %ebx,%r13d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 76,139,8 // mov (%rax),%r9 + .byte 76,139,64,8 // mov 0x8(%rax),%r8 + .byte 196,131,121,32,4,25,0 // vpinsrb $0x0,(%r9,%r11,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,57,1 // vpinsrb $0x1,(%r9,%r15,1),%xmm0,%xmm0 + .byte 65,15,182,44,41 // movzbl (%r9,%rbp,1),%ebp + .byte 196,227,121,32,197,2 // vpinsrb $0x2,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,17 // movzbl (%r9,%r10,1),%ebp + .byte 196,227,121,32,197,3 // vpinsrb $0x3,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,41 // movzbl (%r9,%r13,1),%ebp + .byte 196,227,121,32,197,4 // vpinsrb $0x4,%ebp,%xmm0,%xmm0 + .byte 65,15,182,44,25 // movzbl (%r9,%rbx,1),%ebp + .byte 196,227,121,32,197,5 // vpinsrb $0x5,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,49 // movzbl (%r9,%r14,1),%ebp + .byte 196,227,121,32,197,6 // vpinsrb $0x6,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,33 // movzbl (%r9,%r12,1),%ebp + .byte 196,227,121,32,197,7 // vpinsrb $0x7,%ebp,%xmm0,%xmm0 + .byte 196,226,125,49,192 // vpmovzxbd %xmm0,%ymm0 + .byte 197,124,91,208 // vcvtdq2ps %ymm0,%ymm10 + .byte 189,129,128,128,59 // mov $0x3b808081,%ebp + .byte 197,249,110,197 // vmovd %ebp,%xmm0 + .byte 196,98,125,88,200 // vpbroadcastd %xmm0,%ymm9 + .byte 196,193,44,89,193 // vmulps %ymm9,%ymm10,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,253,91,201 // vcvtps2dq %ymm1,%ymm1 + .byte 196,227,249,22,205,1 // vpextrq $0x1,%xmm1,%rbp + .byte 65,137,233 // mov %ebp,%r9d + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,225,249,126,203 // vmovq %xmm1,%rbx + .byte 65,137,218 // mov %ebx,%r10d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,227,125,57,201,1 // vextracti128 $0x1,%ymm1,%xmm1 + .byte 196,195,249,22,203,1 // vpextrq $0x1,%xmm1,%r11 + .byte 69,137,222 // mov %r11d,%r14d + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 196,193,249,126,207 // vmovq %xmm1,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,131,121,32,12,16,0 // vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm1 + .byte 196,195,113,32,12,24,1 // vpinsrb $0x1,(%r8,%rbx,1),%xmm1,%xmm1 + .byte 67,15,182,28,8 // movzbl (%r8,%r9,1),%ebx + .byte 196,227,113,32,203,2 // vpinsrb $0x2,%ebx,%xmm1,%xmm1 + .byte 65,15,182,44,40 // movzbl (%r8,%rbp,1),%ebp + .byte 196,227,113,32,205,3 // vpinsrb $0x3,%ebp,%xmm1,%xmm1 + .byte 67,15,182,44,32 // movzbl (%r8,%r12,1),%ebp + .byte 196,227,113,32,205,4 // vpinsrb $0x4,%ebp,%xmm1,%xmm1 + .byte 67,15,182,44,56 // movzbl (%r8,%r15,1),%ebp + .byte 196,227,113,32,205,5 // vpinsrb $0x5,%ebp,%xmm1,%xmm1 + .byte 67,15,182,44,48 // movzbl (%r8,%r14,1),%ebp + .byte 196,227,113,32,205,6 // vpinsrb $0x6,%ebp,%xmm1,%xmm1 + .byte 67,15,182,44,24 // movzbl (%r8,%r11,1),%ebp + .byte 196,227,113,32,205,7 // vpinsrb $0x7,%ebp,%xmm1,%xmm1 + .byte 196,226,125,49,201 // vpmovzxbd %xmm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 197,180,89,201 // vmulps %ymm1,%ymm9,%ymm1 + .byte 72,139,64,16 // mov 0x10(%rax),%rax + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,253,91,210 // vcvtps2dq %ymm2,%ymm2 + .byte 196,227,249,22,213,1 // vpextrq $0x1,%xmm2,%rbp + .byte 65,137,232 // mov %ebp,%r8d + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,225,249,126,211 // vmovq %xmm2,%rbx + .byte 65,137,217 // mov %ebx,%r9d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,227,125,57,210,1 // vextracti128 $0x1,%ymm2,%xmm2 + .byte 196,195,249,22,210,1 // vpextrq $0x1,%xmm2,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,193,249,126,214 // vmovq %xmm2,%r14 + .byte 69,137,247 // mov %r14d,%r15d + .byte 73,193,238,32 // shr $0x20,%r14 + .byte 196,163,121,32,20,8,0 // vpinsrb $0x0,(%rax,%r9,1),%xmm0,%xmm2 + .byte 196,227,105,32,20,24,1 // vpinsrb $0x1,(%rax,%rbx,1),%xmm2,%xmm2 + .byte 66,15,182,28,0 // movzbl (%rax,%r8,1),%ebx + .byte 196,227,105,32,211,2 // vpinsrb $0x2,%ebx,%xmm2,%xmm2 + .byte 15,182,44,40 // movzbl (%rax,%rbp,1),%ebp + .byte 196,227,105,32,213,3 // vpinsrb $0x3,%ebp,%xmm2,%xmm2 + .byte 66,15,182,44,56 // movzbl (%rax,%r15,1),%ebp + .byte 196,227,105,32,213,4 // vpinsrb $0x4,%ebp,%xmm2,%xmm2 + .byte 66,15,182,44,48 // movzbl (%rax,%r14,1),%ebp + .byte 196,227,105,32,213,5 // vpinsrb $0x5,%ebp,%xmm2,%xmm2 + .byte 66,15,182,44,24 // movzbl (%rax,%r11,1),%ebp + .byte 196,227,105,32,213,6 // vpinsrb $0x6,%ebp,%xmm2,%xmm2 + .byte 66,15,182,4,16 // movzbl (%rax,%r10,1),%eax + .byte 196,227,105,32,208,7 // vpinsrb $0x7,%eax,%xmm2,%xmm2 + .byte 196,226,125,49,210 // vpmovzxbd %xmm2,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 197,180,89,210 // vmulps %ymm2,%ymm9,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 93 // pop %rbp + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_a8_hsw +.globl _sk_load_a8_hsw +_sk_load_a8_hsw: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,1,248 // add %rdi,%rax + .byte 77,133,192 // test %r8,%r8 + .byte 117,50 // jne 19c2 <_sk_load_a8_hsw+0x42> + .byte 197,250,126,0 // vmovq (%rax),%xmm0 + .byte 196,226,125,49,192 // vpmovzxbd %xmm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,252,89,217 // vmulps %ymm1,%ymm0,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 76,137,193 // mov %r8,%rcx + .byte 255,224 // jmpq *%rax + .byte 49,201 // xor %ecx,%ecx + .byte 77,137,194 // mov %r8,%r10 + .byte 69,49,201 // xor %r9d,%r9d + .byte 68,15,182,24 // movzbl (%rax),%r11d + .byte 72,255,192 // inc %rax + .byte 73,211,227 // shl %cl,%r11 + .byte 77,9,217 // or %r11,%r9 + .byte 72,131,193,8 // add $0x8,%rcx + .byte 73,255,202 // dec %r10 + .byte 117,234 // jne 19ca <_sk_load_a8_hsw+0x4a> + .byte 196,193,249,110,193 // vmovq %r9,%xmm0 + .byte 235,173 // jmp 1994 <_sk_load_a8_hsw+0x14> + +HIDDEN _sk_gather_a8_hsw +.globl _sk_gather_a8_hsw +_sk_gather_a8_hsw: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,201 // vcvttps2dq %ymm1,%ymm1 + .byte 196,226,125,88,80,16 // vpbroadcastd 0x10(%rax),%ymm2 + .byte 196,226,109,64,201 // vpmulld %ymm1,%ymm2,%ymm1 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 197,245,254,192 // vpaddd %ymm0,%ymm1,%ymm0 + .byte 196,227,249,22,192,1 // vpextrq $0x1,%xmm0,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,194 // vmovq %xmm0,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,227,125,57,192,1 // vextracti128 $0x1,%ymm0,%xmm0 + .byte 196,227,249,22,195,1 // vpextrq $0x1,%xmm0,%rbx + .byte 65,137,222 // mov %ebx,%r14d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,193,249,126,199 // vmovq %xmm0,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,131,121,32,4,24,0 // vpinsrb $0x0,(%r8,%r11,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,16,1 // vpinsrb $0x1,(%r8,%r10,1),%xmm0,%xmm0 + .byte 71,15,182,12,8 // movzbl (%r8,%r9,1),%r9d + .byte 196,195,121,32,193,2 // vpinsrb $0x2,%r9d,%xmm0,%xmm0 + .byte 65,15,182,4,0 // movzbl (%r8,%rax,1),%eax + .byte 196,227,121,32,192,3 // vpinsrb $0x3,%eax,%xmm0,%xmm0 + .byte 67,15,182,4,32 // movzbl (%r8,%r12,1),%eax + .byte 196,227,121,32,192,4 // vpinsrb $0x4,%eax,%xmm0,%xmm0 + .byte 67,15,182,4,56 // movzbl (%r8,%r15,1),%eax + .byte 196,227,121,32,192,5 // vpinsrb $0x5,%eax,%xmm0,%xmm0 + .byte 67,15,182,4,48 // movzbl (%r8,%r14,1),%eax + .byte 196,227,121,32,192,6 // vpinsrb $0x6,%eax,%xmm0,%xmm0 + .byte 65,15,182,4,24 // movzbl (%r8,%rbx,1),%eax + .byte 196,227,121,32,192,7 // vpinsrb $0x7,%eax,%xmm0,%xmm0 + .byte 196,226,125,49,192 // vpmovzxbd %xmm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,252,89,217 // vmulps %ymm1,%ymm0,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,237,239,210 // vpxor %ymm2,%ymm2,%ymm2 + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_a8_hsw +.globl _sk_store_a8_hsw +_sk_store_a8_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 184,0,0,127,67 // mov $0x437f0000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 196,65,125,91,192 // vcvtps2dq %ymm8,%ymm8 + .byte 196,67,125,25,193,1 // vextractf128 $0x1,%ymm8,%xmm9 + .byte 196,66,57,43,193 // vpackusdw %xmm9,%xmm8,%xmm8 + .byte 196,65,57,103,192 // vpackuswb %xmm8,%xmm8,%xmm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,10 // jne 1aff <_sk_store_a8_hsw+0x3b> + .byte 196,65,123,17,4,57 // vmovsd %xmm8,(%r9,%rdi,1) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 119,236 // ja 1afb <_sk_store_a8_hsw+0x37> + .byte 196,66,121,48,192 // vpmovzxbw %xmm8,%xmm8 + .byte 65,15,182,192 // movzbl %r8b,%eax + .byte 76,141,5,69,0,0,0 // lea 0x45(%rip),%r8 # 1b64 <_sk_store_a8_hsw+0xa0> + .byte 73,99,4,128 // movslq (%r8,%rax,4),%rax + .byte 76,1,192 // add %r8,%rax + .byte 255,224 // jmpq *%rax + .byte 196,67,121,20,68,57,6,12 // vpextrb $0xc,%xmm8,0x6(%r9,%rdi,1) + .byte 196,67,121,20,68,57,5,10 // vpextrb $0xa,%xmm8,0x5(%r9,%rdi,1) + .byte 196,67,121,20,68,57,4,8 // vpextrb $0x8,%xmm8,0x4(%r9,%rdi,1) + .byte 196,67,121,20,68,57,3,6 // vpextrb $0x6,%xmm8,0x3(%r9,%rdi,1) + .byte 196,67,121,20,68,57,2,4 // vpextrb $0x4,%xmm8,0x2(%r9,%rdi,1) + .byte 196,67,121,20,68,57,1,2 // vpextrb $0x2,%xmm8,0x1(%r9,%rdi,1) + .byte 196,67,121,20,4,57,0 // vpextrb $0x0,%xmm8,(%r9,%rdi,1) + .byte 235,154 // jmp 1afb <_sk_store_a8_hsw+0x37> + .byte 15,31,0 // nopl (%rax) + .byte 244 // hlt + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 236 // in (%dx),%al + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,228 // jmpq *%rsp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 220,255 // fdivr %st,%st(7) + .byte 255 // (bad) + .byte 255,212 // callq *%rsp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,204 // dec %esp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,196 // inc %esp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_load_g8_hsw +.globl _sk_load_g8_hsw +_sk_load_g8_hsw: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,1,248 // add %rdi,%rax + .byte 77,133,192 // test %r8,%r8 + .byte 117,60 // jne 1bcc <_sk_load_g8_hsw+0x4c> + .byte 197,250,126,0 // vmovq (%rax),%xmm0 + .byte 196,226,125,49,192 // vpmovzxbd %xmm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,217 // vpbroadcastd %xmm1,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,137,193 // mov %r8,%rcx + .byte 197,252,40,200 // vmovaps %ymm0,%ymm1 + .byte 197,252,40,208 // vmovaps %ymm0,%ymm2 + .byte 255,224 // jmpq *%rax + .byte 49,201 // xor %ecx,%ecx + .byte 77,137,194 // mov %r8,%r10 + .byte 69,49,201 // xor %r9d,%r9d + .byte 68,15,182,24 // movzbl (%rax),%r11d + .byte 72,255,192 // inc %rax + .byte 73,211,227 // shl %cl,%r11 + .byte 77,9,217 // or %r11,%r9 + .byte 72,131,193,8 // add $0x8,%rcx + .byte 73,255,202 // dec %r10 + .byte 117,234 // jne 1bd4 <_sk_load_g8_hsw+0x54> + .byte 196,193,249,110,193 // vmovq %r9,%xmm0 + .byte 235,163 // jmp 1b94 <_sk_load_g8_hsw+0x14> + +HIDDEN _sk_gather_g8_hsw +.globl _sk_gather_g8_hsw +_sk_gather_g8_hsw: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,201 // vcvttps2dq %ymm1,%ymm1 + .byte 196,226,125,88,80,16 // vpbroadcastd 0x10(%rax),%ymm2 + .byte 196,226,109,64,201 // vpmulld %ymm1,%ymm2,%ymm1 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 197,245,254,192 // vpaddd %ymm0,%ymm1,%ymm0 + .byte 196,227,249,22,192,1 // vpextrq $0x1,%xmm0,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,194 // vmovq %xmm0,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,227,125,57,192,1 // vextracti128 $0x1,%ymm0,%xmm0 + .byte 196,227,249,22,195,1 // vpextrq $0x1,%xmm0,%rbx + .byte 65,137,222 // mov %ebx,%r14d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,193,249,126,199 // vmovq %xmm0,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,131,121,32,4,24,0 // vpinsrb $0x0,(%r8,%r11,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,16,1 // vpinsrb $0x1,(%r8,%r10,1),%xmm0,%xmm0 + .byte 71,15,182,12,8 // movzbl (%r8,%r9,1),%r9d + .byte 196,195,121,32,193,2 // vpinsrb $0x2,%r9d,%xmm0,%xmm0 + .byte 65,15,182,4,0 // movzbl (%r8,%rax,1),%eax + .byte 196,227,121,32,192,3 // vpinsrb $0x3,%eax,%xmm0,%xmm0 + .byte 67,15,182,4,32 // movzbl (%r8,%r12,1),%eax + .byte 196,227,121,32,192,4 // vpinsrb $0x4,%eax,%xmm0,%xmm0 + .byte 67,15,182,4,56 // movzbl (%r8,%r15,1),%eax + .byte 196,227,121,32,192,5 // vpinsrb $0x5,%eax,%xmm0,%xmm0 + .byte 67,15,182,4,48 // movzbl (%r8,%r14,1),%eax + .byte 196,227,121,32,192,6 // vpinsrb $0x6,%eax,%xmm0,%xmm0 + .byte 65,15,182,4,24 // movzbl (%r8,%rbx,1),%eax + .byte 196,227,121,32,192,7 // vpinsrb $0x7,%eax,%xmm0,%xmm0 + .byte 196,226,125,49,192 // vpmovzxbd %xmm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,217 // vpbroadcastd %xmm1,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,200 // vmovaps %ymm0,%ymm1 + .byte 197,252,40,208 // vmovaps %ymm0,%ymm2 + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_i8_hsw +.globl _sk_gather_i8_hsw +_sk_gather_i8_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 73,137,192 // mov %rax,%r8 + .byte 77,133,192 // test %r8,%r8 + .byte 116,5 // je 1ce7 <_sk_gather_i8_hsw+0xf> + .byte 76,137,192 // mov %r8,%rax + .byte 235,2 // jmp 1ce9 <_sk_gather_i8_hsw+0x11> + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 76,139,8 // mov (%rax),%r9 + .byte 197,254,91,201 // vcvttps2dq %ymm1,%ymm1 + .byte 196,226,125,88,80,16 // vpbroadcastd 0x10(%rax),%ymm2 + .byte 196,226,109,64,201 // vpmulld %ymm1,%ymm2,%ymm1 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 197,245,254,192 // vpaddd %ymm0,%ymm1,%ymm0 + .byte 196,227,249,22,192,1 // vpextrq $0x1,%xmm0,%rax + .byte 65,137,194 // mov %eax,%r10d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,195 // vmovq %xmm0,%r11 + .byte 69,137,222 // mov %r11d,%r14d + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 196,227,125,57,192,1 // vextracti128 $0x1,%ymm0,%xmm0 + .byte 196,227,249,22,195,1 // vpextrq $0x1,%xmm0,%rbx + .byte 65,137,223 // mov %ebx,%r15d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,193,249,126,196 // vmovq %xmm0,%r12 + .byte 69,137,229 // mov %r12d,%r13d + .byte 73,193,236,32 // shr $0x20,%r12 + .byte 196,131,121,32,4,49,0 // vpinsrb $0x0,(%r9,%r14,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,25,1 // vpinsrb $0x1,(%r9,%r11,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,17,2 // vpinsrb $0x2,(%r9,%r10,1),%xmm0,%xmm0 + .byte 196,195,121,32,4,1,3 // vpinsrb $0x3,(%r9,%rax,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,41,4 // vpinsrb $0x4,(%r9,%r13,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,33,5 // vpinsrb $0x5,(%r9,%r12,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,57,6 // vpinsrb $0x6,(%r9,%r15,1),%xmm0,%xmm0 + .byte 196,195,121,32,4,25,7 // vpinsrb $0x7,(%r9,%rbx,1),%xmm0,%xmm0 + .byte 196,226,125,49,192 // vpmovzxbd %xmm0,%ymm0 + .byte 73,139,64,8 // mov 0x8(%r8),%rax + .byte 197,245,118,201 // vpcmpeqd %ymm1,%ymm1,%ymm1 + .byte 196,226,117,144,28,128 // vpgatherdd %ymm1,(%rax,%ymm0,4),%ymm3 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,226,125,88,208 // vpbroadcastd %xmm0,%ymm2 + .byte 197,237,219,195 // vpand %ymm3,%ymm2,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,98,125,88,193 // vpbroadcastd %xmm1,%ymm8 + .byte 196,193,124,89,192 // vmulps %ymm8,%ymm0,%ymm0 + .byte 197,245,114,211,8 // vpsrld $0x8,%ymm3,%ymm1 + .byte 197,237,219,201 // vpand %ymm1,%ymm2,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 196,193,116,89,200 // vmulps %ymm8,%ymm1,%ymm1 + .byte 197,181,114,211,16 // vpsrld $0x10,%ymm3,%ymm9 + .byte 196,193,109,219,209 // vpand %ymm9,%ymm2,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 196,193,108,89,208 // vmulps %ymm8,%ymm2,%ymm2 + .byte 197,229,114,211,24 // vpsrld $0x18,%ymm3,%ymm3 + .byte 197,252,91,219 // vcvtdq2ps %ymm3,%ymm3 + .byte 196,193,100,89,216 // vmulps %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_565_hsw +.globl _sk_load_565_hsw +_sk_load_565_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,16 // mov (%rax),%r10 + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,149,0,0,0 // jne 1e9b <_sk_load_565_hsw+0xa3> + .byte 196,193,122,111,4,122 // vmovdqu (%r10,%rdi,2),%xmm0 + .byte 196,226,125,51,208 // vpmovzxwd %xmm0,%ymm2 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 197,253,219,194 // vpand %ymm2,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,245,219,202 // vpand %ymm2,%ymm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,244,89,203 // vmulps %ymm3,%ymm1,%ymm1 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,229,219,210 // vpand %ymm2,%ymm3,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,236,89,211 // vmulps %ymm3,%ymm2,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 197,249,239,192 // vpxor %xmm0,%xmm0,%xmm0 + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 15,135,89,255,255,255 // ja 1e0c <_sk_load_565_hsw+0x14> + .byte 69,15,182,192 // movzbl %r8b,%r8d + .byte 76,141,13,74,0,0,0 // lea 0x4a(%rip),%r9 # 1f08 <_sk_load_565_hsw+0x110> + .byte 75,99,4,129 // movslq (%r9,%r8,4),%rax + .byte 76,1,200 // add %r9,%rax + .byte 255,224 // jmpq *%rax + .byte 197,249,239,192 // vpxor %xmm0,%xmm0,%xmm0 + .byte 196,193,121,196,68,122,12,6 // vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,10,5 // vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,8,4 // vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,6,3 // vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,4,2 // vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,2,1 // vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,4,122,0 // vpinsrw $0x0,(%r10,%rdi,2),%xmm0,%xmm0 + .byte 233,5,255,255,255 // jmpq 1e0c <_sk_load_565_hsw+0x14> + .byte 144 // nop + .byte 243,255 // repz (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 235,255 // jmp 1f0d <_sk_load_565_hsw+0x115> + .byte 255 // (bad) + .byte 255,227 // jmpq *%rbx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 219,255 // (bad) + .byte 255 // (bad) + .byte 255,211 // callq *%rbx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,203 // dec %ebx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 191 // .byte 0xbf + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_gather_565_hsw +.globl _sk_gather_565_hsw +_sk_gather_565_hsw: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,201 // vcvttps2dq %ymm1,%ymm1 + .byte 196,226,125,88,80,16 // vpbroadcastd 0x10(%rax),%ymm2 + .byte 196,226,109,64,201 // vpmulld %ymm1,%ymm2,%ymm1 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 197,245,254,192 // vpaddd %ymm0,%ymm1,%ymm0 + .byte 196,227,249,22,192,1 // vpextrq $0x1,%xmm0,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,194 // vmovq %xmm0,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,227,125,57,192,1 // vextracti128 $0x1,%ymm0,%xmm0 + .byte 196,227,249,22,195,1 // vpextrq $0x1,%xmm0,%rbx + .byte 65,137,222 // mov %ebx,%r14d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,193,249,126,199 // vmovq %xmm0,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 71,15,183,20,80 // movzwl (%r8,%r10,2),%r10d + .byte 71,15,183,28,88 // movzwl (%r8,%r11,2),%r11d + .byte 196,193,121,110,195 // vmovd %r11d,%xmm0 + .byte 196,193,121,196,194,1 // vpinsrw $0x1,%r10d,%xmm0,%xmm0 + .byte 71,15,183,12,72 // movzwl (%r8,%r9,2),%r9d + .byte 196,193,121,196,193,2 // vpinsrw $0x2,%r9d,%xmm0,%xmm0 + .byte 65,15,183,4,64 // movzwl (%r8,%rax,2),%eax + .byte 197,249,196,192,3 // vpinsrw $0x3,%eax,%xmm0,%xmm0 + .byte 67,15,183,4,96 // movzwl (%r8,%r12,2),%eax + .byte 197,249,196,192,4 // vpinsrw $0x4,%eax,%xmm0,%xmm0 + .byte 67,15,183,4,120 // movzwl (%r8,%r15,2),%eax + .byte 197,249,196,192,5 // vpinsrw $0x5,%eax,%xmm0,%xmm0 + .byte 67,15,183,4,112 // movzwl (%r8,%r14,2),%eax + .byte 197,249,196,192,6 // vpinsrw $0x6,%eax,%xmm0,%xmm0 + .byte 65,15,183,4,88 // movzwl (%r8,%rbx,2),%eax + .byte 197,249,196,192,7 // vpinsrw $0x7,%eax,%xmm0,%xmm0 + .byte 196,226,125,51,208 // vpmovzxwd %xmm0,%ymm2 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 197,253,219,194 // vpand %ymm2,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,245,219,202 // vpand %ymm2,%ymm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,244,89,203 // vmulps %ymm3,%ymm1,%ymm1 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,229,219,210 // vpand %ymm2,%ymm3,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,236,89,211 // vmulps %ymm3,%ymm2,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_565_hsw +.globl _sk_store_565_hsw +_sk_store_565_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 184,0,0,248,65 // mov $0x41f80000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 196,65,125,91,201 // vcvtps2dq %ymm9,%ymm9 + .byte 196,193,53,114,241,11 // vpslld $0xb,%ymm9,%ymm9 + .byte 184,0,0,124,66 // mov $0x427c0000,%eax + .byte 197,121,110,208 // vmovd %eax,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 197,44,89,209 // vmulps %ymm1,%ymm10,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,193,45,114,242,5 // vpslld $0x5,%ymm10,%ymm10 + .byte 196,65,45,235,201 // vpor %ymm9,%ymm10,%ymm9 + .byte 197,60,89,194 // vmulps %ymm2,%ymm8,%ymm8 + .byte 196,65,125,91,192 // vcvtps2dq %ymm8,%ymm8 + .byte 196,65,53,235,192 // vpor %ymm8,%ymm9,%ymm8 + .byte 196,67,125,57,193,1 // vextracti128 $0x1,%ymm8,%xmm9 + .byte 196,66,57,43,193 // vpackusdw %xmm9,%xmm8,%xmm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,10 // jne 20d3 <_sk_store_565_hsw+0x6c> + .byte 196,65,122,127,4,121 // vmovdqu %xmm8,(%r9,%rdi,2) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 119,236 // ja 20cf <_sk_store_565_hsw+0x68> + .byte 65,15,182,192 // movzbl %r8b,%eax + .byte 76,141,5,66,0,0,0 // lea 0x42(%rip),%r8 # 2130 <_sk_store_565_hsw+0xc9> + .byte 73,99,4,128 // movslq (%r8,%rax,4),%rax + .byte 76,1,192 // add %r8,%rax + .byte 255,224 // jmpq *%rax + .byte 196,67,121,21,68,121,12,6 // vpextrw $0x6,%xmm8,0xc(%r9,%rdi,2) + .byte 196,67,121,21,68,121,10,5 // vpextrw $0x5,%xmm8,0xa(%r9,%rdi,2) + .byte 196,67,121,21,68,121,8,4 // vpextrw $0x4,%xmm8,0x8(%r9,%rdi,2) + .byte 196,67,121,21,68,121,6,3 // vpextrw $0x3,%xmm8,0x6(%r9,%rdi,2) + .byte 196,67,121,21,68,121,4,2 // vpextrw $0x2,%xmm8,0x4(%r9,%rdi,2) + .byte 196,67,121,21,68,121,2,1 // vpextrw $0x1,%xmm8,0x2(%r9,%rdi,2) + .byte 196,67,121,21,4,121,0 // vpextrw $0x0,%xmm8,(%r9,%rdi,2) + .byte 235,159 // jmp 20cf <_sk_store_565_hsw+0x68> + .byte 247,255 // idiv %edi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 239 // out %eax,(%dx) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,231 // jmpq *%rdi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 223,255 // (bad) + .byte 255 // (bad) + .byte 255,215 // callq *%rdi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,207 // dec %edi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,199 // inc %edi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_load_4444_hsw +.globl _sk_load_4444_hsw +_sk_load_4444_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,16 // mov (%rax),%r10 + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,179,0,0,0 // jne 220d <_sk_load_4444_hsw+0xc1> + .byte 196,193,122,111,4,122 // vmovdqu (%r10,%rdi,2),%xmm0 + .byte 196,98,125,51,200 // vpmovzxwd %xmm0,%ymm9 + .byte 184,0,240,0,0 // mov $0xf000,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 196,193,125,219,193 // vpand %ymm9,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,137,136,136,55 // mov $0x37888889,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,0,15,0,0 // mov $0xf00,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 196,193,117,219,201 // vpand %ymm9,%ymm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 184,137,136,136,57 // mov $0x39888889,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,226,125,88,210 // vpbroadcastd %xmm2,%ymm2 + .byte 197,244,89,202 // vmulps %ymm2,%ymm1,%ymm1 + .byte 184,240,0,0,0 // mov $0xf0,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,226,125,88,210 // vpbroadcastd %xmm2,%ymm2 + .byte 196,193,109,219,209 // vpand %ymm9,%ymm2,%ymm2 + .byte 197,124,91,194 // vcvtdq2ps %ymm2,%ymm8 + .byte 184,137,136,136,59 // mov $0x3b888889,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,226,125,88,210 // vpbroadcastd %xmm2,%ymm2 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 184,15,0,0,0 // mov $0xf,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 196,193,101,219,217 // vpand %ymm9,%ymm3,%ymm3 + .byte 197,124,91,195 // vcvtdq2ps %ymm3,%ymm8 + .byte 184,137,136,136,61 // mov $0x3d888889,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 197,249,239,192 // vpxor %xmm0,%xmm0,%xmm0 + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 15,135,59,255,255,255 // ja 2160 <_sk_load_4444_hsw+0x14> + .byte 69,15,182,192 // movzbl %r8b,%r8d + .byte 76,141,13,76,0,0,0 // lea 0x4c(%rip),%r9 # 227c <_sk_load_4444_hsw+0x130> + .byte 75,99,4,129 // movslq (%r9,%r8,4),%rax + .byte 76,1,200 // add %r9,%rax + .byte 255,224 // jmpq *%rax + .byte 197,249,239,192 // vpxor %xmm0,%xmm0,%xmm0 + .byte 196,193,121,196,68,122,12,6 // vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,10,5 // vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,8,4 // vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,6,3 // vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,4,2 // vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,2,1 // vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,4,122,0 // vpinsrw $0x0,(%r10,%rdi,2),%xmm0,%xmm0 + .byte 233,231,254,255,255 // jmpq 2160 <_sk_load_4444_hsw+0x14> + .byte 15,31,0 // nopl (%rax) + .byte 241 // icebp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 233,255,255,255,225 // jmpq ffffffffe2002284 <_sk_bicubic_p3y_hsw+0xffffffffe1ffecd5> + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 217,255 // fcos + .byte 255 // (bad) + .byte 255,209 // callq *%rcx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,201 // dec %ecx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 189 // .byte 0xbd + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_gather_4444_hsw +.globl _sk_gather_4444_hsw +_sk_gather_4444_hsw: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,201 // vcvttps2dq %ymm1,%ymm1 + .byte 196,226,125,88,80,16 // vpbroadcastd 0x10(%rax),%ymm2 + .byte 196,226,109,64,201 // vpmulld %ymm1,%ymm2,%ymm1 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 197,245,254,192 // vpaddd %ymm0,%ymm1,%ymm0 + .byte 196,227,249,22,192,1 // vpextrq $0x1,%xmm0,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,194 // vmovq %xmm0,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,227,125,57,192,1 // vextracti128 $0x1,%ymm0,%xmm0 + .byte 196,227,249,22,195,1 // vpextrq $0x1,%xmm0,%rbx + .byte 65,137,222 // mov %ebx,%r14d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,193,249,126,199 // vmovq %xmm0,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 71,15,183,20,80 // movzwl (%r8,%r10,2),%r10d + .byte 71,15,183,28,88 // movzwl (%r8,%r11,2),%r11d + .byte 196,193,121,110,195 // vmovd %r11d,%xmm0 + .byte 196,193,121,196,194,1 // vpinsrw $0x1,%r10d,%xmm0,%xmm0 + .byte 71,15,183,12,72 // movzwl (%r8,%r9,2),%r9d + .byte 196,193,121,196,193,2 // vpinsrw $0x2,%r9d,%xmm0,%xmm0 + .byte 65,15,183,4,64 // movzwl (%r8,%rax,2),%eax + .byte 197,249,196,192,3 // vpinsrw $0x3,%eax,%xmm0,%xmm0 + .byte 67,15,183,4,96 // movzwl (%r8,%r12,2),%eax + .byte 197,249,196,192,4 // vpinsrw $0x4,%eax,%xmm0,%xmm0 + .byte 67,15,183,4,120 // movzwl (%r8,%r15,2),%eax + .byte 197,249,196,192,5 // vpinsrw $0x5,%eax,%xmm0,%xmm0 + .byte 67,15,183,4,112 // movzwl (%r8,%r14,2),%eax + .byte 197,249,196,192,6 // vpinsrw $0x6,%eax,%xmm0,%xmm0 + .byte 65,15,183,4,88 // movzwl (%r8,%rbx,2),%eax + .byte 197,249,196,192,7 // vpinsrw $0x7,%eax,%xmm0,%xmm0 + .byte 196,98,125,51,200 // vpmovzxwd %xmm0,%ymm9 + .byte 184,0,240,0,0 // mov $0xf000,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 196,193,125,219,193 // vpand %ymm9,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,137,136,136,55 // mov $0x37888889,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,0,15,0,0 // mov $0xf00,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 196,193,117,219,201 // vpand %ymm9,%ymm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 184,137,136,136,57 // mov $0x39888889,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,226,125,88,210 // vpbroadcastd %xmm2,%ymm2 + .byte 197,244,89,202 // vmulps %ymm2,%ymm1,%ymm1 + .byte 184,240,0,0,0 // mov $0xf0,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,226,125,88,210 // vpbroadcastd %xmm2,%ymm2 + .byte 196,193,109,219,209 // vpand %ymm9,%ymm2,%ymm2 + .byte 197,124,91,194 // vcvtdq2ps %ymm2,%ymm8 + .byte 184,137,136,136,59 // mov $0x3b888889,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,226,125,88,210 // vpbroadcastd %xmm2,%ymm2 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 184,15,0,0,0 // mov $0xf,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 196,193,101,219,217 // vpand %ymm9,%ymm3,%ymm3 + .byte 197,124,91,195 // vcvtdq2ps %ymm3,%ymm8 + .byte 184,137,136,136,61 // mov $0x3d888889,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_4444_hsw +.globl _sk_store_4444_hsw +_sk_store_4444_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 184,0,0,112,65 // mov $0x41700000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 196,65,125,91,201 // vcvtps2dq %ymm9,%ymm9 + .byte 196,193,53,114,241,12 // vpslld $0xc,%ymm9,%ymm9 + .byte 197,60,89,209 // vmulps %ymm1,%ymm8,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,193,45,114,242,8 // vpslld $0x8,%ymm10,%ymm10 + .byte 196,65,45,235,201 // vpor %ymm9,%ymm10,%ymm9 + .byte 197,60,89,210 // vmulps %ymm2,%ymm8,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,193,45,114,242,4 // vpslld $0x4,%ymm10,%ymm10 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 196,65,125,91,192 // vcvtps2dq %ymm8,%ymm8 + .byte 196,65,45,235,192 // vpor %ymm8,%ymm10,%ymm8 + .byte 196,65,53,235,192 // vpor %ymm8,%ymm9,%ymm8 + .byte 196,67,125,57,193,1 // vextracti128 $0x1,%ymm8,%xmm9 + .byte 196,66,57,43,193 // vpackusdw %xmm9,%xmm8,%xmm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,10 // jne 246b <_sk_store_4444_hsw+0x72> + .byte 196,65,122,127,4,121 // vmovdqu %xmm8,(%r9,%rdi,2) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 119,236 // ja 2467 <_sk_store_4444_hsw+0x6e> + .byte 65,15,182,192 // movzbl %r8b,%eax + .byte 76,141,5,66,0,0,0 // lea 0x42(%rip),%r8 # 24c8 <_sk_store_4444_hsw+0xcf> + .byte 73,99,4,128 // movslq (%r8,%rax,4),%rax + .byte 76,1,192 // add %r8,%rax + .byte 255,224 // jmpq *%rax + .byte 196,67,121,21,68,121,12,6 // vpextrw $0x6,%xmm8,0xc(%r9,%rdi,2) + .byte 196,67,121,21,68,121,10,5 // vpextrw $0x5,%xmm8,0xa(%r9,%rdi,2) + .byte 196,67,121,21,68,121,8,4 // vpextrw $0x4,%xmm8,0x8(%r9,%rdi,2) + .byte 196,67,121,21,68,121,6,3 // vpextrw $0x3,%xmm8,0x6(%r9,%rdi,2) + .byte 196,67,121,21,68,121,4,2 // vpextrw $0x2,%xmm8,0x4(%r9,%rdi,2) + .byte 196,67,121,21,68,121,2,1 // vpextrw $0x1,%xmm8,0x2(%r9,%rdi,2) + .byte 196,67,121,21,4,121,0 // vpextrw $0x0,%xmm8,(%r9,%rdi,2) + .byte 235,159 // jmp 2467 <_sk_store_4444_hsw+0x6e> + .byte 247,255 // idiv %edi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 239 // out %eax,(%dx) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,231 // jmpq *%rdi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 223,255 // (bad) + .byte 255 // (bad) + .byte 255,215 // callq *%rdi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,207 // dec %edi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,199 // inc %edi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_load_8888_hsw +.globl _sk_load_8888_hsw +_sk_load_8888_hsw: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,141,12,189,0,0,0,0 // lea 0x0(,%rdi,4),%r9 + .byte 76,3,8 // add (%rax),%r9 + .byte 77,133,192 // test %r8,%r8 + .byte 117,104 // jne 2561 <_sk_load_8888_hsw+0x7d> + .byte 196,193,126,111,25 // vmovdqu (%r9),%ymm3 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,226,125,88,208 // vpbroadcastd %xmm0,%ymm2 + .byte 197,237,219,195 // vpand %ymm3,%ymm2,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,98,125,88,193 // vpbroadcastd %xmm1,%ymm8 + .byte 196,193,124,89,192 // vmulps %ymm8,%ymm0,%ymm0 + .byte 197,245,114,211,8 // vpsrld $0x8,%ymm3,%ymm1 + .byte 197,237,219,201 // vpand %ymm1,%ymm2,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 196,193,116,89,200 // vmulps %ymm8,%ymm1,%ymm1 + .byte 197,181,114,211,16 // vpsrld $0x10,%ymm3,%ymm9 + .byte 196,193,109,219,209 // vpand %ymm9,%ymm2,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 196,193,108,89,208 // vmulps %ymm8,%ymm2,%ymm2 + .byte 197,229,114,211,24 // vpsrld $0x18,%ymm3,%ymm3 + .byte 197,252,91,219 // vcvtdq2ps %ymm3,%ymm3 + .byte 196,193,100,89,216 // vmulps %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,137,193 // mov %r8,%rcx + .byte 255,224 // jmpq *%rax + .byte 185,8,0,0,0 // mov $0x8,%ecx + .byte 68,41,193 // sub %r8d,%ecx + .byte 192,225,3 // shl $0x3,%cl + .byte 72,199,192,255,255,255,255 // mov $0xffffffffffffffff,%rax + .byte 72,211,232 // shr %cl,%rax + .byte 196,225,249,110,192 // vmovq %rax,%xmm0 + .byte 196,226,125,33,192 // vpmovsxbd %xmm0,%ymm0 + .byte 196,194,125,140,25 // vpmaskmovd (%r9),%ymm0,%ymm3 + .byte 233,116,255,255,255 // jmpq 24fe <_sk_load_8888_hsw+0x1a> + +HIDDEN _sk_gather_8888_hsw +.globl _sk_gather_8888_hsw +_sk_gather_8888_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,201 // vcvttps2dq %ymm1,%ymm1 + .byte 196,226,125,88,80,16 // vpbroadcastd 0x10(%rax),%ymm2 + .byte 196,226,109,64,201 // vpmulld %ymm1,%ymm2,%ymm1 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 197,245,254,192 // vpaddd %ymm0,%ymm1,%ymm0 + .byte 197,245,118,201 // vpcmpeqd %ymm1,%ymm1,%ymm1 + .byte 196,194,117,144,28,128 // vpgatherdd %ymm1,(%r8,%ymm0,4),%ymm3 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,226,125,88,208 // vpbroadcastd %xmm0,%ymm2 + .byte 197,237,219,195 // vpand %ymm3,%ymm2,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,98,125,88,193 // vpbroadcastd %xmm1,%ymm8 + .byte 196,193,124,89,192 // vmulps %ymm8,%ymm0,%ymm0 + .byte 197,245,114,211,8 // vpsrld $0x8,%ymm3,%ymm1 + .byte 197,237,219,201 // vpand %ymm1,%ymm2,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 196,193,116,89,200 // vmulps %ymm8,%ymm1,%ymm1 + .byte 197,181,114,211,16 // vpsrld $0x10,%ymm3,%ymm9 + .byte 196,193,109,219,209 // vpand %ymm9,%ymm2,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 196,193,108,89,208 // vmulps %ymm8,%ymm2,%ymm2 + .byte 197,229,114,211,24 // vpsrld $0x18,%ymm3,%ymm3 + .byte 197,252,91,219 // vcvtdq2ps %ymm3,%ymm3 + .byte 196,193,100,89,216 // vmulps %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_8888_hsw +.globl _sk_store_8888_hsw +_sk_store_8888_hsw: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,141,12,189,0,0,0,0 // lea 0x0(,%rdi,4),%r9 + .byte 76,3,8 // add (%rax),%r9 + .byte 184,0,0,127,67 // mov $0x437f0000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 196,65,125,91,201 // vcvtps2dq %ymm9,%ymm9 + .byte 197,60,89,209 // vmulps %ymm1,%ymm8,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,193,45,114,242,8 // vpslld $0x8,%ymm10,%ymm10 + .byte 196,65,45,235,201 // vpor %ymm9,%ymm10,%ymm9 + .byte 197,60,89,210 // vmulps %ymm2,%ymm8,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,193,45,114,242,16 // vpslld $0x10,%ymm10,%ymm10 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 196,65,125,91,192 // vcvtps2dq %ymm8,%ymm8 + .byte 196,193,61,114,240,24 // vpslld $0x18,%ymm8,%ymm8 + .byte 196,65,45,235,192 // vpor %ymm8,%ymm10,%ymm8 + .byte 196,65,53,235,192 // vpor %ymm8,%ymm9,%ymm8 + .byte 77,133,192 // test %r8,%r8 + .byte 117,12 // jne 2684 <_sk_store_8888_hsw+0x74> + .byte 196,65,126,127,1 // vmovdqu %ymm8,(%r9) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,137,193 // mov %r8,%rcx + .byte 255,224 // jmpq *%rax + .byte 185,8,0,0,0 // mov $0x8,%ecx + .byte 68,41,193 // sub %r8d,%ecx + .byte 192,225,3 // shl $0x3,%cl + .byte 72,199,192,255,255,255,255 // mov $0xffffffffffffffff,%rax + .byte 72,211,232 // shr %cl,%rax + .byte 196,97,249,110,200 // vmovq %rax,%xmm9 + .byte 196,66,125,33,201 // vpmovsxbd %xmm9,%ymm9 + .byte 196,66,53,142,1 // vpmaskmovd %ymm8,%ymm9,(%r9) + .byte 235,211 // jmp 267d <_sk_store_8888_hsw+0x6d> + +HIDDEN _sk_load_f16_hsw +.globl _sk_load_f16_hsw +_sk_load_f16_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,133,201 // test %rcx,%rcx + .byte 117,97 // jne 2715 <_sk_load_f16_hsw+0x6b> + .byte 197,121,16,4,248 // vmovupd (%rax,%rdi,8),%xmm8 + .byte 197,249,16,84,248,16 // vmovupd 0x10(%rax,%rdi,8),%xmm2 + .byte 197,249,16,92,248,32 // vmovupd 0x20(%rax,%rdi,8),%xmm3 + .byte 197,122,111,76,248,48 // vmovdqu 0x30(%rax,%rdi,8),%xmm9 + .byte 197,185,97,194 // vpunpcklwd %xmm2,%xmm8,%xmm0 + .byte 197,185,105,210 // vpunpckhwd %xmm2,%xmm8,%xmm2 + .byte 196,193,97,97,201 // vpunpcklwd %xmm9,%xmm3,%xmm1 + .byte 196,193,97,105,217 // vpunpckhwd %xmm9,%xmm3,%xmm3 + .byte 197,121,97,194 // vpunpcklwd %xmm2,%xmm0,%xmm8 + .byte 197,121,105,202 // vpunpckhwd %xmm2,%xmm0,%xmm9 + .byte 197,241,97,211 // vpunpcklwd %xmm3,%xmm1,%xmm2 + .byte 197,241,105,219 // vpunpckhwd %xmm3,%xmm1,%xmm3 + .byte 197,185,108,194 // vpunpcklqdq %xmm2,%xmm8,%xmm0 + .byte 196,226,125,19,192 // vcvtph2ps %xmm0,%ymm0 + .byte 197,185,109,202 // vpunpckhqdq %xmm2,%xmm8,%xmm1 + .byte 196,226,125,19,201 // vcvtph2ps %xmm1,%ymm1 + .byte 197,177,108,211 // vpunpcklqdq %xmm3,%xmm9,%xmm2 + .byte 196,226,125,19,210 // vcvtph2ps %xmm2,%ymm2 + .byte 197,177,109,219 // vpunpckhqdq %xmm3,%xmm9,%xmm3 + .byte 196,226,125,19,219 // vcvtph2ps %xmm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 197,123,16,4,248 // vmovsd (%rax,%rdi,8),%xmm8 + .byte 196,65,49,239,201 // vpxor %xmm9,%xmm9,%xmm9 + .byte 72,131,249,1 // cmp $0x1,%rcx + .byte 116,79 // je 2774 <_sk_load_f16_hsw+0xca> + .byte 197,57,22,68,248,8 // vmovhpd 0x8(%rax,%rdi,8),%xmm8,%xmm8 + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 114,67 // jb 2774 <_sk_load_f16_hsw+0xca> + .byte 197,251,16,84,248,16 // vmovsd 0x10(%rax,%rdi,8),%xmm2 + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 116,68 // je 2781 <_sk_load_f16_hsw+0xd7> + .byte 197,233,22,84,248,24 // vmovhpd 0x18(%rax,%rdi,8),%xmm2,%xmm2 + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 114,56 // jb 2781 <_sk_load_f16_hsw+0xd7> + .byte 197,251,16,92,248,32 // vmovsd 0x20(%rax,%rdi,8),%xmm3 + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 15,132,114,255,255,255 // je 26cb <_sk_load_f16_hsw+0x21> + .byte 197,225,22,92,248,40 // vmovhpd 0x28(%rax,%rdi,8),%xmm3,%xmm3 + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 15,130,98,255,255,255 // jb 26cb <_sk_load_f16_hsw+0x21> + .byte 197,122,126,76,248,48 // vmovq 0x30(%rax,%rdi,8),%xmm9 + .byte 233,87,255,255,255 // jmpq 26cb <_sk_load_f16_hsw+0x21> + .byte 197,225,87,219 // vxorpd %xmm3,%xmm3,%xmm3 + .byte 197,233,87,210 // vxorpd %xmm2,%xmm2,%xmm2 + .byte 233,74,255,255,255 // jmpq 26cb <_sk_load_f16_hsw+0x21> + .byte 197,225,87,219 // vxorpd %xmm3,%xmm3,%xmm3 + .byte 233,65,255,255,255 // jmpq 26cb <_sk_load_f16_hsw+0x21> + +HIDDEN _sk_gather_f16_hsw +.globl _sk_gather_f16_hsw +_sk_gather_f16_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,201 // vcvttps2dq %ymm1,%ymm1 + .byte 196,226,125,88,80,16 // vpbroadcastd 0x10(%rax),%ymm2 + .byte 196,226,109,64,201 // vpmulld %ymm1,%ymm2,%ymm1 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 197,245,254,192 // vpaddd %ymm0,%ymm1,%ymm0 + .byte 197,245,118,201 // vpcmpeqd %ymm1,%ymm1,%ymm1 + .byte 197,237,118,210 // vpcmpeqd %ymm2,%ymm2,%ymm2 + .byte 196,194,237,144,28,192 // vpgatherdq %ymm2,(%r8,%xmm0,8),%ymm3 + .byte 196,227,125,57,192,1 // vextracti128 $0x1,%ymm0,%xmm0 + .byte 196,194,245,144,20,192 // vpgatherdq %ymm1,(%r8,%xmm0,8),%ymm2 + .byte 196,227,125,57,216,1 // vextracti128 $0x1,%ymm3,%xmm0 + .byte 196,227,125,57,209,1 // vextracti128 $0x1,%ymm2,%xmm1 + .byte 197,97,97,192 // vpunpcklwd %xmm0,%xmm3,%xmm8 + .byte 197,225,105,192 // vpunpckhwd %xmm0,%xmm3,%xmm0 + .byte 197,233,97,217 // vpunpcklwd %xmm1,%xmm2,%xmm3 + .byte 197,233,105,201 // vpunpckhwd %xmm1,%xmm2,%xmm1 + .byte 197,57,97,200 // vpunpcklwd %xmm0,%xmm8,%xmm9 + .byte 197,57,105,192 // vpunpckhwd %xmm0,%xmm8,%xmm8 + .byte 197,225,97,209 // vpunpcklwd %xmm1,%xmm3,%xmm2 + .byte 197,225,105,217 // vpunpckhwd %xmm1,%xmm3,%xmm3 + .byte 197,177,108,194 // vpunpcklqdq %xmm2,%xmm9,%xmm0 + .byte 196,226,125,19,192 // vcvtph2ps %xmm0,%ymm0 + .byte 197,177,109,202 // vpunpckhqdq %xmm2,%xmm9,%xmm1 + .byte 196,226,125,19,201 // vcvtph2ps %xmm1,%ymm1 + .byte 197,185,108,211 // vpunpcklqdq %xmm3,%xmm8,%xmm2 + .byte 196,226,125,19,210 // vcvtph2ps %xmm2,%ymm2 + .byte 197,185,109,219 // vpunpckhqdq %xmm3,%xmm8,%xmm3 + .byte 196,226,125,19,219 // vcvtph2ps %xmm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_f16_hsw +.globl _sk_store_f16_hsw +_sk_store_f16_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 196,195,125,29,192,4 // vcvtps2ph $0x4,%ymm0,%xmm8 + .byte 196,195,125,29,201,4 // vcvtps2ph $0x4,%ymm1,%xmm9 + .byte 196,195,125,29,210,4 // vcvtps2ph $0x4,%ymm2,%xmm10 + .byte 196,195,125,29,219,4 // vcvtps2ph $0x4,%ymm3,%xmm11 + .byte 196,65,57,97,225 // vpunpcklwd %xmm9,%xmm8,%xmm12 + .byte 196,65,57,105,193 // vpunpckhwd %xmm9,%xmm8,%xmm8 + .byte 196,65,41,97,203 // vpunpcklwd %xmm11,%xmm10,%xmm9 + .byte 196,65,41,105,235 // vpunpckhwd %xmm11,%xmm10,%xmm13 + .byte 196,65,25,98,217 // vpunpckldq %xmm9,%xmm12,%xmm11 + .byte 196,65,25,106,209 // vpunpckhdq %xmm9,%xmm12,%xmm10 + .byte 196,65,57,98,205 // vpunpckldq %xmm13,%xmm8,%xmm9 + .byte 196,65,57,106,197 // vpunpckhdq %xmm13,%xmm8,%xmm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,27 // jne 2879 <_sk_store_f16_hsw+0x65> + .byte 197,120,17,28,248 // vmovups %xmm11,(%rax,%rdi,8) + .byte 197,120,17,84,248,16 // vmovups %xmm10,0x10(%rax,%rdi,8) + .byte 197,120,17,76,248,32 // vmovups %xmm9,0x20(%rax,%rdi,8) + .byte 197,122,127,68,248,48 // vmovdqu %xmm8,0x30(%rax,%rdi,8) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 197,121,214,28,248 // vmovq %xmm11,(%rax,%rdi,8) + .byte 72,131,249,1 // cmp $0x1,%rcx + .byte 116,241 // je 2875 <_sk_store_f16_hsw+0x61> + .byte 197,121,23,92,248,8 // vmovhpd %xmm11,0x8(%rax,%rdi,8) + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 114,229 // jb 2875 <_sk_store_f16_hsw+0x61> + .byte 197,121,214,84,248,16 // vmovq %xmm10,0x10(%rax,%rdi,8) + .byte 116,221 // je 2875 <_sk_store_f16_hsw+0x61> + .byte 197,121,23,84,248,24 // vmovhpd %xmm10,0x18(%rax,%rdi,8) + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 114,209 // jb 2875 <_sk_store_f16_hsw+0x61> + .byte 197,121,214,76,248,32 // vmovq %xmm9,0x20(%rax,%rdi,8) + .byte 116,201 // je 2875 <_sk_store_f16_hsw+0x61> + .byte 197,121,23,76,248,40 // vmovhpd %xmm9,0x28(%rax,%rdi,8) + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 114,189 // jb 2875 <_sk_store_f16_hsw+0x61> + .byte 197,121,214,68,248,48 // vmovq %xmm8,0x30(%rax,%rdi,8) + .byte 235,181 // jmp 2875 <_sk_store_f16_hsw+0x61> + +HIDDEN _sk_load_u16_be_hsw +.globl _sk_load_u16_be_hsw +_sk_load_u16_be_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,201,0,0,0 // jne 2997 <_sk_load_u16_be_hsw+0xd7> + .byte 197,121,16,4,248 // vmovupd (%rax,%rdi,8),%xmm8 + .byte 197,249,16,84,248,16 // vmovupd 0x10(%rax,%rdi,8),%xmm2 + .byte 197,249,16,92,248,32 // vmovupd 0x20(%rax,%rdi,8),%xmm3 + .byte 197,122,111,76,248,48 // vmovdqu 0x30(%rax,%rdi,8),%xmm9 + .byte 197,185,97,194 // vpunpcklwd %xmm2,%xmm8,%xmm0 + .byte 197,185,105,210 // vpunpckhwd %xmm2,%xmm8,%xmm2 + .byte 196,193,97,97,201 // vpunpcklwd %xmm9,%xmm3,%xmm1 + .byte 196,193,97,105,217 // vpunpckhwd %xmm9,%xmm3,%xmm3 + .byte 197,121,97,194 // vpunpcklwd %xmm2,%xmm0,%xmm8 + .byte 197,121,105,202 // vpunpckhwd %xmm2,%xmm0,%xmm9 + .byte 197,241,97,211 // vpunpcklwd %xmm3,%xmm1,%xmm2 + .byte 197,113,105,219 // vpunpckhwd %xmm3,%xmm1,%xmm11 + .byte 184,128,0,128,55 // mov $0x37800080,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,98,125,88,208 // vpbroadcastd %xmm0,%ymm10 + .byte 197,185,108,194 // vpunpcklqdq %xmm2,%xmm8,%xmm0 + .byte 197,241,113,240,8 // vpsllw $0x8,%xmm0,%xmm1 + .byte 197,249,113,208,8 // vpsrlw $0x8,%xmm0,%xmm0 + .byte 197,241,235,192 // vpor %xmm0,%xmm1,%xmm0 + .byte 196,226,125,51,192 // vpmovzxwd %xmm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 197,172,89,192 // vmulps %ymm0,%ymm10,%ymm0 + .byte 197,185,109,202 // vpunpckhqdq %xmm2,%xmm8,%xmm1 + .byte 197,233,113,241,8 // vpsllw $0x8,%xmm1,%xmm2 + .byte 197,241,113,209,8 // vpsrlw $0x8,%xmm1,%xmm1 + .byte 197,233,235,201 // vpor %xmm1,%xmm2,%xmm1 + .byte 196,226,125,51,201 // vpmovzxwd %xmm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 197,172,89,201 // vmulps %ymm1,%ymm10,%ymm1 + .byte 196,193,49,108,211 // vpunpcklqdq %xmm11,%xmm9,%xmm2 + .byte 197,225,113,242,8 // vpsllw $0x8,%xmm2,%xmm3 + .byte 197,233,113,210,8 // vpsrlw $0x8,%xmm2,%xmm2 + .byte 197,225,235,210 // vpor %xmm2,%xmm3,%xmm2 + .byte 196,226,125,51,210 // vpmovzxwd %xmm2,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 197,172,89,210 // vmulps %ymm2,%ymm10,%ymm2 + .byte 196,193,49,109,219 // vpunpckhqdq %xmm11,%xmm9,%xmm3 + .byte 197,185,113,243,8 // vpsllw $0x8,%xmm3,%xmm8 + .byte 197,225,113,211,8 // vpsrlw $0x8,%xmm3,%xmm3 + .byte 197,185,235,219 // vpor %xmm3,%xmm8,%xmm3 + .byte 196,226,125,51,219 // vpmovzxwd %xmm3,%ymm3 + .byte 197,252,91,219 // vcvtdq2ps %ymm3,%ymm3 + .byte 197,172,89,219 // vmulps %ymm3,%ymm10,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 197,123,16,4,248 // vmovsd (%rax,%rdi,8),%xmm8 + .byte 196,65,49,239,201 // vpxor %xmm9,%xmm9,%xmm9 + .byte 72,131,249,1 // cmp $0x1,%rcx + .byte 116,79 // je 29f6 <_sk_load_u16_be_hsw+0x136> + .byte 197,57,22,68,248,8 // vmovhpd 0x8(%rax,%rdi,8),%xmm8,%xmm8 + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 114,67 // jb 29f6 <_sk_load_u16_be_hsw+0x136> + .byte 197,251,16,84,248,16 // vmovsd 0x10(%rax,%rdi,8),%xmm2 + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 116,68 // je 2a03 <_sk_load_u16_be_hsw+0x143> + .byte 197,233,22,84,248,24 // vmovhpd 0x18(%rax,%rdi,8),%xmm2,%xmm2 + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 114,56 // jb 2a03 <_sk_load_u16_be_hsw+0x143> + .byte 197,251,16,92,248,32 // vmovsd 0x20(%rax,%rdi,8),%xmm3 + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 15,132,10,255,255,255 // je 28e5 <_sk_load_u16_be_hsw+0x25> + .byte 197,225,22,92,248,40 // vmovhpd 0x28(%rax,%rdi,8),%xmm3,%xmm3 + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 15,130,250,254,255,255 // jb 28e5 <_sk_load_u16_be_hsw+0x25> + .byte 197,122,126,76,248,48 // vmovq 0x30(%rax,%rdi,8),%xmm9 + .byte 233,239,254,255,255 // jmpq 28e5 <_sk_load_u16_be_hsw+0x25> + .byte 197,225,87,219 // vxorpd %xmm3,%xmm3,%xmm3 + .byte 197,233,87,210 // vxorpd %xmm2,%xmm2,%xmm2 + .byte 233,226,254,255,255 // jmpq 28e5 <_sk_load_u16_be_hsw+0x25> + .byte 197,225,87,219 // vxorpd %xmm3,%xmm3,%xmm3 + .byte 233,217,254,255,255 // jmpq 28e5 <_sk_load_u16_be_hsw+0x25> + +HIDDEN _sk_store_u16_be_hsw +.globl _sk_store_u16_be_hsw +_sk_store_u16_be_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 184,0,255,127,71 // mov $0x477fff00,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 196,65,125,91,201 // vcvtps2dq %ymm9,%ymm9 + .byte 196,67,125,25,202,1 // vextractf128 $0x1,%ymm9,%xmm10 + .byte 196,66,49,43,202 // vpackusdw %xmm10,%xmm9,%xmm9 + .byte 196,193,41,113,241,8 // vpsllw $0x8,%xmm9,%xmm10 + .byte 196,193,49,113,209,8 // vpsrlw $0x8,%xmm9,%xmm9 + .byte 196,65,41,235,201 // vpor %xmm9,%xmm10,%xmm9 + .byte 197,60,89,209 // vmulps %ymm1,%ymm8,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,67,125,25,211,1 // vextractf128 $0x1,%ymm10,%xmm11 + .byte 196,66,41,43,211 // vpackusdw %xmm11,%xmm10,%xmm10 + .byte 196,193,33,113,242,8 // vpsllw $0x8,%xmm10,%xmm11 + .byte 196,193,41,113,210,8 // vpsrlw $0x8,%xmm10,%xmm10 + .byte 196,65,33,235,210 // vpor %xmm10,%xmm11,%xmm10 + .byte 197,60,89,218 // vmulps %ymm2,%ymm8,%ymm11 + .byte 196,65,125,91,219 // vcvtps2dq %ymm11,%ymm11 + .byte 196,67,125,25,220,1 // vextractf128 $0x1,%ymm11,%xmm12 + .byte 196,66,33,43,220 // vpackusdw %xmm12,%xmm11,%xmm11 + .byte 196,193,25,113,243,8 // vpsllw $0x8,%xmm11,%xmm12 + .byte 196,193,33,113,211,8 // vpsrlw $0x8,%xmm11,%xmm11 + .byte 196,65,25,235,219 // vpor %xmm11,%xmm12,%xmm11 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 196,65,125,91,192 // vcvtps2dq %ymm8,%ymm8 + .byte 196,67,125,25,196,1 // vextractf128 $0x1,%ymm8,%xmm12 + .byte 196,66,57,43,196 // vpackusdw %xmm12,%xmm8,%xmm8 + .byte 196,193,25,113,240,8 // vpsllw $0x8,%xmm8,%xmm12 + .byte 196,193,57,113,208,8 // vpsrlw $0x8,%xmm8,%xmm8 + .byte 196,65,25,235,192 // vpor %xmm8,%xmm12,%xmm8 + .byte 196,65,49,97,226 // vpunpcklwd %xmm10,%xmm9,%xmm12 + .byte 196,65,49,105,234 // vpunpckhwd %xmm10,%xmm9,%xmm13 + .byte 196,65,33,97,200 // vpunpcklwd %xmm8,%xmm11,%xmm9 + .byte 196,65,33,105,192 // vpunpckhwd %xmm8,%xmm11,%xmm8 + .byte 196,65,25,98,217 // vpunpckldq %xmm9,%xmm12,%xmm11 + .byte 196,65,25,106,209 // vpunpckhdq %xmm9,%xmm12,%xmm10 + .byte 196,65,17,98,200 // vpunpckldq %xmm8,%xmm13,%xmm9 + .byte 196,65,17,106,192 // vpunpckhdq %xmm8,%xmm13,%xmm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,31 // jne 2aff <_sk_store_u16_be_hsw+0xf3> + .byte 196,65,120,17,28,248 // vmovups %xmm11,(%r8,%rdi,8) + .byte 196,65,120,17,84,248,16 // vmovups %xmm10,0x10(%r8,%rdi,8) + .byte 196,65,120,17,76,248,32 // vmovups %xmm9,0x20(%r8,%rdi,8) + .byte 196,65,122,127,68,248,48 // vmovdqu %xmm8,0x30(%r8,%rdi,8) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 196,65,121,214,28,248 // vmovq %xmm11,(%r8,%rdi,8) + .byte 72,131,249,1 // cmp $0x1,%rcx + .byte 116,240 // je 2afb <_sk_store_u16_be_hsw+0xef> + .byte 196,65,121,23,92,248,8 // vmovhpd %xmm11,0x8(%r8,%rdi,8) + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 114,227 // jb 2afb <_sk_store_u16_be_hsw+0xef> + .byte 196,65,121,214,84,248,16 // vmovq %xmm10,0x10(%r8,%rdi,8) + .byte 116,218 // je 2afb <_sk_store_u16_be_hsw+0xef> + .byte 196,65,121,23,84,248,24 // vmovhpd %xmm10,0x18(%r8,%rdi,8) + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 114,205 // jb 2afb <_sk_store_u16_be_hsw+0xef> + .byte 196,65,121,214,76,248,32 // vmovq %xmm9,0x20(%r8,%rdi,8) + .byte 116,196 // je 2afb <_sk_store_u16_be_hsw+0xef> + .byte 196,65,121,23,76,248,40 // vmovhpd %xmm9,0x28(%r8,%rdi,8) + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 114,183 // jb 2afb <_sk_store_u16_be_hsw+0xef> + .byte 196,65,121,214,68,248,48 // vmovq %xmm8,0x30(%r8,%rdi,8) + .byte 235,174 // jmp 2afb <_sk_store_u16_be_hsw+0xef> + +HIDDEN _sk_load_f32_hsw +.globl _sk_load_f32_hsw +_sk_load_f32_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 119,110 // ja 2bc3 <_sk_load_f32_hsw+0x76> + .byte 76,139,0 // mov (%rax),%r8 + .byte 76,141,12,189,0,0,0,0 // lea 0x0(,%rdi,4),%r9 + .byte 76,141,21,133,0,0,0 // lea 0x85(%rip),%r10 # 2bec <_sk_load_f32_hsw+0x9f> + .byte 73,99,4,138 // movslq (%r10,%rcx,4),%rax + .byte 76,1,208 // add %r10,%rax + .byte 255,224 // jmpq *%rax + .byte 196,3,125,24,68,136,112,1 // vinsertf128 $0x1,0x70(%r8,%r9,4),%ymm0,%ymm8 + .byte 196,131,125,24,92,136,96,1 // vinsertf128 $0x1,0x60(%r8,%r9,4),%ymm0,%ymm3 + .byte 196,131,125,24,76,136,80,1 // vinsertf128 $0x1,0x50(%r8,%r9,4),%ymm0,%ymm1 + .byte 196,131,125,24,84,136,64,1 // vinsertf128 $0x1,0x40(%r8,%r9,4),%ymm0,%ymm2 + .byte 196,129,121,16,68,136,48 // vmovupd 0x30(%r8,%r9,4),%xmm0 + .byte 196,195,125,13,192,12 // vblendpd $0xc,%ymm8,%ymm0,%ymm0 + .byte 196,1,121,16,68,136,32 // vmovupd 0x20(%r8,%r9,4),%xmm8 + .byte 196,99,61,13,203,12 // vblendpd $0xc,%ymm3,%ymm8,%ymm9 + .byte 196,129,121,16,92,136,16 // vmovupd 0x10(%r8,%r9,4),%xmm3 + .byte 196,99,101,13,209,12 // vblendpd $0xc,%ymm1,%ymm3,%ymm10 + .byte 196,129,121,16,12,136 // vmovupd (%r8,%r9,4),%xmm1 + .byte 196,227,117,13,202,12 // vblendpd $0xc,%ymm2,%ymm1,%ymm1 + .byte 196,193,116,20,210 // vunpcklps %ymm10,%ymm1,%ymm2 + .byte 196,193,116,21,218 // vunpckhps %ymm10,%ymm1,%ymm3 + .byte 197,180,20,200 // vunpcklps %ymm0,%ymm9,%ymm1 + .byte 197,52,21,192 // vunpckhps %ymm0,%ymm9,%ymm8 + .byte 197,237,20,193 // vunpcklpd %ymm1,%ymm2,%ymm0 + .byte 197,237,21,201 // vunpckhpd %ymm1,%ymm2,%ymm1 + .byte 196,193,101,20,208 // vunpcklpd %ymm8,%ymm3,%ymm2 + .byte 196,193,101,21,216 // vunpckhpd %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 144 // nop + .byte 132,255 // test %bh,%bh + .byte 255 // (bad) + .byte 255,203 // dec %ebx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 190,255,255,255,177 // mov $0xb1ffffff,%esi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,164,255,255,255,156,255 // jmpq *-0x630001(%rdi,%rdi,8) + .byte 255 // (bad) + .byte 255,148,255,255,255,140,255 // callq *-0x730001(%rdi,%rdi,8) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_store_f32_hsw +.globl _sk_store_f32_hsw +_sk_store_f32_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 72,141,4,189,0,0,0,0 // lea 0x0(,%rdi,4),%rax + .byte 197,124,20,193 // vunpcklps %ymm1,%ymm0,%ymm8 + .byte 197,124,21,217 // vunpckhps %ymm1,%ymm0,%ymm11 + .byte 197,108,20,203 // vunpcklps %ymm3,%ymm2,%ymm9 + .byte 197,108,21,227 // vunpckhps %ymm3,%ymm2,%ymm12 + .byte 196,65,61,20,209 // vunpcklpd %ymm9,%ymm8,%ymm10 + .byte 196,65,61,21,201 // vunpckhpd %ymm9,%ymm8,%ymm9 + .byte 196,65,37,20,196 // vunpcklpd %ymm12,%ymm11,%ymm8 + .byte 196,65,37,21,220 // vunpckhpd %ymm12,%ymm11,%ymm11 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,55 // jne 2c79 <_sk_store_f32_hsw+0x6d> + .byte 196,67,45,24,225,1 // vinsertf128 $0x1,%xmm9,%ymm10,%ymm12 + .byte 196,67,61,24,235,1 // vinsertf128 $0x1,%xmm11,%ymm8,%ymm13 + .byte 196,67,45,6,201,49 // vperm2f128 $0x31,%ymm9,%ymm10,%ymm9 + .byte 196,67,61,6,195,49 // vperm2f128 $0x31,%ymm11,%ymm8,%ymm8 + .byte 196,65,125,17,36,128 // vmovupd %ymm12,(%r8,%rax,4) + .byte 196,65,125,17,108,128,32 // vmovupd %ymm13,0x20(%r8,%rax,4) + .byte 196,65,125,17,76,128,64 // vmovupd %ymm9,0x40(%r8,%rax,4) + .byte 196,65,125,17,68,128,96 // vmovupd %ymm8,0x60(%r8,%rax,4) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 196,65,121,17,20,128 // vmovupd %xmm10,(%r8,%rax,4) + .byte 72,131,249,1 // cmp $0x1,%rcx + .byte 116,240 // je 2c75 <_sk_store_f32_hsw+0x69> + .byte 196,65,121,17,76,128,16 // vmovupd %xmm9,0x10(%r8,%rax,4) + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 114,227 // jb 2c75 <_sk_store_f32_hsw+0x69> + .byte 196,65,121,17,68,128,32 // vmovupd %xmm8,0x20(%r8,%rax,4) + .byte 116,218 // je 2c75 <_sk_store_f32_hsw+0x69> + .byte 196,65,121,17,92,128,48 // vmovupd %xmm11,0x30(%r8,%rax,4) + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 114,205 // jb 2c75 <_sk_store_f32_hsw+0x69> + .byte 196,67,125,25,84,128,64,1 // vextractf128 $0x1,%ymm10,0x40(%r8,%rax,4) + .byte 116,195 // je 2c75 <_sk_store_f32_hsw+0x69> + .byte 196,67,125,25,76,128,80,1 // vextractf128 $0x1,%ymm9,0x50(%r8,%rax,4) + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 114,181 // jb 2c75 <_sk_store_f32_hsw+0x69> + .byte 196,67,125,25,68,128,96,1 // vextractf128 $0x1,%ymm8,0x60(%r8,%rax,4) + .byte 235,171 // jmp 2c75 <_sk_store_f32_hsw+0x69> + +HIDDEN _sk_clamp_x_hsw +.globl _sk_clamp_x_hsw +_sk_clamp_x_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 197,188,95,192 // vmaxps %ymm0,%ymm8,%ymm0 + .byte 196,98,125,88,0 // vpbroadcastd (%rax),%ymm8 + .byte 196,65,53,118,201 // vpcmpeqd %ymm9,%ymm9,%ymm9 + .byte 196,65,61,254,193 // vpaddd %ymm9,%ymm8,%ymm8 + .byte 196,193,124,93,192 // vminps %ymm8,%ymm0,%ymm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_y_hsw +.globl _sk_clamp_y_hsw +_sk_clamp_y_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 197,188,95,201 // vmaxps %ymm1,%ymm8,%ymm1 + .byte 196,98,125,88,0 // vpbroadcastd (%rax),%ymm8 + .byte 196,65,53,118,201 // vpcmpeqd %ymm9,%ymm9,%ymm9 + .byte 196,65,61,254,193 // vpaddd %ymm9,%ymm8,%ymm8 + .byte 196,193,116,93,200 // vminps %ymm8,%ymm1,%ymm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_repeat_x_hsw +.globl _sk_repeat_x_hsw +_sk_repeat_x_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,65,124,94,200 // vdivps %ymm8,%ymm0,%ymm9 + .byte 196,67,125,8,201,1 // vroundps $0x1,%ymm9,%ymm9 + .byte 196,98,61,172,200 // vfnmadd213ps %ymm0,%ymm8,%ymm9 + .byte 197,253,118,192 // vpcmpeqd %ymm0,%ymm0,%ymm0 + .byte 197,189,254,192 // vpaddd %ymm0,%ymm8,%ymm0 + .byte 197,180,93,192 // vminps %ymm0,%ymm9,%ymm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_repeat_y_hsw +.globl _sk_repeat_y_hsw +_sk_repeat_y_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,65,116,94,200 // vdivps %ymm8,%ymm1,%ymm9 + .byte 196,67,125,8,201,1 // vroundps $0x1,%ymm9,%ymm9 + .byte 196,98,61,172,201 // vfnmadd213ps %ymm1,%ymm8,%ymm9 + .byte 197,245,118,201 // vpcmpeqd %ymm1,%ymm1,%ymm1 + .byte 197,189,254,201 // vpaddd %ymm1,%ymm8,%ymm1 + .byte 197,180,93,201 // vminps %ymm1,%ymm9,%ymm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_mirror_x_hsw +.globl _sk_mirror_x_hsw +_sk_mirror_x_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,122,16,0 // vmovss (%rax),%xmm8 + .byte 196,66,125,24,200 // vbroadcastss %xmm8,%ymm9 + .byte 196,65,124,92,209 // vsubps %ymm9,%ymm0,%ymm10 + .byte 196,193,58,88,192 // vaddss %xmm8,%xmm8,%xmm0 + .byte 196,226,125,24,192 // vbroadcastss %xmm0,%ymm0 + .byte 197,44,94,192 // vdivps %ymm0,%ymm10,%ymm8 + .byte 196,67,125,8,192,1 // vroundps $0x1,%ymm8,%ymm8 + .byte 196,66,125,172,194 // vfnmadd213ps %ymm10,%ymm0,%ymm8 + .byte 196,193,60,92,193 // vsubps %ymm9,%ymm8,%ymm0 + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 197,60,92,192 // vsubps %ymm0,%ymm8,%ymm8 + .byte 197,188,84,192 // vandps %ymm0,%ymm8,%ymm0 + .byte 196,65,61,118,192 // vpcmpeqd %ymm8,%ymm8,%ymm8 + .byte 196,65,53,254,192 // vpaddd %ymm8,%ymm9,%ymm8 + .byte 196,193,124,93,192 // vminps %ymm8,%ymm0,%ymm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_mirror_y_hsw +.globl _sk_mirror_y_hsw +_sk_mirror_y_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,122,16,0 // vmovss (%rax),%xmm8 + .byte 196,66,125,24,200 // vbroadcastss %xmm8,%ymm9 + .byte 196,65,116,92,209 // vsubps %ymm9,%ymm1,%ymm10 + .byte 196,193,58,88,200 // vaddss %xmm8,%xmm8,%xmm1 + .byte 196,226,125,24,201 // vbroadcastss %xmm1,%ymm1 + .byte 197,44,94,193 // vdivps %ymm1,%ymm10,%ymm8 + .byte 196,67,125,8,192,1 // vroundps $0x1,%ymm8,%ymm8 + .byte 196,66,117,172,194 // vfnmadd213ps %ymm10,%ymm1,%ymm8 + .byte 196,193,60,92,201 // vsubps %ymm9,%ymm8,%ymm1 + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 197,60,92,193 // vsubps %ymm1,%ymm8,%ymm8 + .byte 197,188,84,201 // vandps %ymm1,%ymm8,%ymm1 + .byte 196,65,61,118,192 // vpcmpeqd %ymm8,%ymm8,%ymm8 + .byte 196,65,53,254,192 // vpaddd %ymm8,%ymm9,%ymm8 + .byte 196,193,116,93,200 // vminps %ymm8,%ymm1,%ymm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_luminance_to_alpha_hsw +.globl _sk_luminance_to_alpha_hsw +_sk_luminance_to_alpha_hsw: + .byte 184,208,179,89,62 // mov $0x3e59b3d0,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,98,125,88,195 // vpbroadcastd %xmm3,%ymm8 + .byte 184,89,23,55,63 // mov $0x3f371759,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,226,125,88,219 // vpbroadcastd %xmm3,%ymm3 + .byte 197,228,89,201 // vmulps %ymm1,%ymm3,%ymm1 + .byte 196,98,125,168,193 // vfmadd213ps %ymm1,%ymm0,%ymm8 + .byte 184,152,221,147,61 // mov $0x3d93dd98,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,226,125,88,216 // vpbroadcastd %xmm0,%ymm3 + .byte 196,194,109,168,216 // vfmadd213ps %ymm8,%ymm2,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,253,239,192 // vpxor %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_2x3_hsw +.globl _sk_matrix_2x3_hsw +_sk_matrix_2x3_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,8 // vbroadcastss (%rax),%ymm9 + .byte 196,98,125,24,80,8 // vbroadcastss 0x8(%rax),%ymm10 + .byte 196,98,125,24,64,16 // vbroadcastss 0x10(%rax),%ymm8 + .byte 196,66,117,184,194 // vfmadd231ps %ymm10,%ymm1,%ymm8 + .byte 196,66,125,184,193 // vfmadd231ps %ymm9,%ymm0,%ymm8 + .byte 196,98,125,24,80,4 // vbroadcastss 0x4(%rax),%ymm10 + .byte 196,98,125,24,88,12 // vbroadcastss 0xc(%rax),%ymm11 + .byte 196,98,125,24,72,20 // vbroadcastss 0x14(%rax),%ymm9 + .byte 196,66,117,184,203 // vfmadd231ps %ymm11,%ymm1,%ymm9 + .byte 196,66,125,184,202 // vfmadd231ps %ymm10,%ymm0,%ymm9 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,192 // vmovaps %ymm8,%ymm0 + .byte 197,124,41,201 // vmovaps %ymm9,%ymm1 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_3x4_hsw +.globl _sk_matrix_3x4_hsw +_sk_matrix_3x4_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,8 // vbroadcastss (%rax),%ymm9 + .byte 196,98,125,24,80,12 // vbroadcastss 0xc(%rax),%ymm10 + .byte 196,98,125,24,88,24 // vbroadcastss 0x18(%rax),%ymm11 + .byte 196,98,125,24,64,36 // vbroadcastss 0x24(%rax),%ymm8 + .byte 196,66,109,184,195 // vfmadd231ps %ymm11,%ymm2,%ymm8 + .byte 196,66,117,184,194 // vfmadd231ps %ymm10,%ymm1,%ymm8 + .byte 196,66,125,184,193 // vfmadd231ps %ymm9,%ymm0,%ymm8 + .byte 196,98,125,24,80,4 // vbroadcastss 0x4(%rax),%ymm10 + .byte 196,98,125,24,88,16 // vbroadcastss 0x10(%rax),%ymm11 + .byte 196,98,125,24,96,28 // vbroadcastss 0x1c(%rax),%ymm12 + .byte 196,98,125,24,72,40 // vbroadcastss 0x28(%rax),%ymm9 + .byte 196,66,109,184,204 // vfmadd231ps %ymm12,%ymm2,%ymm9 + .byte 196,66,117,184,203 // vfmadd231ps %ymm11,%ymm1,%ymm9 + .byte 196,66,125,184,202 // vfmadd231ps %ymm10,%ymm0,%ymm9 + .byte 196,98,125,24,88,8 // vbroadcastss 0x8(%rax),%ymm11 + .byte 196,98,125,24,96,20 // vbroadcastss 0x14(%rax),%ymm12 + .byte 196,98,125,24,104,32 // vbroadcastss 0x20(%rax),%ymm13 + .byte 196,98,125,24,80,44 // vbroadcastss 0x2c(%rax),%ymm10 + .byte 196,66,109,184,213 // vfmadd231ps %ymm13,%ymm2,%ymm10 + .byte 196,66,117,184,212 // vfmadd231ps %ymm12,%ymm1,%ymm10 + .byte 196,66,125,184,211 // vfmadd231ps %ymm11,%ymm0,%ymm10 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,192 // vmovaps %ymm8,%ymm0 + .byte 197,124,41,201 // vmovaps %ymm9,%ymm1 + .byte 197,124,41,210 // vmovaps %ymm10,%ymm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_4x5_hsw +.globl _sk_matrix_4x5_hsw +_sk_matrix_4x5_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,8 // vbroadcastss (%rax),%ymm9 + .byte 196,98,125,24,80,16 // vbroadcastss 0x10(%rax),%ymm10 + .byte 196,98,125,24,88,32 // vbroadcastss 0x20(%rax),%ymm11 + .byte 196,98,125,24,96,48 // vbroadcastss 0x30(%rax),%ymm12 + .byte 196,98,125,24,64,64 // vbroadcastss 0x40(%rax),%ymm8 + .byte 196,66,101,184,196 // vfmadd231ps %ymm12,%ymm3,%ymm8 + .byte 196,66,109,184,195 // vfmadd231ps %ymm11,%ymm2,%ymm8 + .byte 196,66,117,184,194 // vfmadd231ps %ymm10,%ymm1,%ymm8 + .byte 196,66,125,184,193 // vfmadd231ps %ymm9,%ymm0,%ymm8 + .byte 196,98,125,24,80,4 // vbroadcastss 0x4(%rax),%ymm10 + .byte 196,98,125,24,88,20 // vbroadcastss 0x14(%rax),%ymm11 + .byte 196,98,125,24,96,36 // vbroadcastss 0x24(%rax),%ymm12 + .byte 196,98,125,24,104,52 // vbroadcastss 0x34(%rax),%ymm13 + .byte 196,98,125,24,72,68 // vbroadcastss 0x44(%rax),%ymm9 + .byte 196,66,101,184,205 // vfmadd231ps %ymm13,%ymm3,%ymm9 + .byte 196,66,109,184,204 // vfmadd231ps %ymm12,%ymm2,%ymm9 + .byte 196,66,117,184,203 // vfmadd231ps %ymm11,%ymm1,%ymm9 + .byte 196,66,125,184,202 // vfmadd231ps %ymm10,%ymm0,%ymm9 + .byte 196,98,125,24,88,8 // vbroadcastss 0x8(%rax),%ymm11 + .byte 196,98,125,24,96,24 // vbroadcastss 0x18(%rax),%ymm12 + .byte 196,98,125,24,104,40 // vbroadcastss 0x28(%rax),%ymm13 + .byte 196,98,125,24,112,56 // vbroadcastss 0x38(%rax),%ymm14 + .byte 196,98,125,24,80,72 // vbroadcastss 0x48(%rax),%ymm10 + .byte 196,66,101,184,214 // vfmadd231ps %ymm14,%ymm3,%ymm10 + .byte 196,66,109,184,213 // vfmadd231ps %ymm13,%ymm2,%ymm10 + .byte 196,66,117,184,212 // vfmadd231ps %ymm12,%ymm1,%ymm10 + .byte 196,66,125,184,211 // vfmadd231ps %ymm11,%ymm0,%ymm10 + .byte 196,98,125,24,96,12 // vbroadcastss 0xc(%rax),%ymm12 + .byte 196,98,125,24,104,28 // vbroadcastss 0x1c(%rax),%ymm13 + .byte 196,98,125,24,112,44 // vbroadcastss 0x2c(%rax),%ymm14 + .byte 196,98,125,24,120,60 // vbroadcastss 0x3c(%rax),%ymm15 + .byte 196,98,125,24,88,76 // vbroadcastss 0x4c(%rax),%ymm11 + .byte 196,66,101,184,223 // vfmadd231ps %ymm15,%ymm3,%ymm11 + .byte 196,66,109,184,222 // vfmadd231ps %ymm14,%ymm2,%ymm11 + .byte 196,66,117,184,221 // vfmadd231ps %ymm13,%ymm1,%ymm11 + .byte 196,66,125,184,220 // vfmadd231ps %ymm12,%ymm0,%ymm11 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,192 // vmovaps %ymm8,%ymm0 + .byte 197,124,41,201 // vmovaps %ymm9,%ymm1 + .byte 197,124,41,210 // vmovaps %ymm10,%ymm2 + .byte 197,124,41,219 // vmovaps %ymm11,%ymm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_perspective_hsw +.globl _sk_matrix_perspective_hsw +_sk_matrix_perspective_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,98,125,24,72,4 // vbroadcastss 0x4(%rax),%ymm9 + .byte 196,98,125,24,80,8 // vbroadcastss 0x8(%rax),%ymm10 + .byte 196,66,117,184,209 // vfmadd231ps %ymm9,%ymm1,%ymm10 + .byte 196,66,125,184,208 // vfmadd231ps %ymm8,%ymm0,%ymm10 + .byte 196,98,125,24,64,12 // vbroadcastss 0xc(%rax),%ymm8 + .byte 196,98,125,24,72,16 // vbroadcastss 0x10(%rax),%ymm9 + .byte 196,98,125,24,88,20 // vbroadcastss 0x14(%rax),%ymm11 + .byte 196,66,117,184,217 // vfmadd231ps %ymm9,%ymm1,%ymm11 + .byte 196,66,125,184,216 // vfmadd231ps %ymm8,%ymm0,%ymm11 + .byte 196,98,125,24,64,24 // vbroadcastss 0x18(%rax),%ymm8 + .byte 196,98,125,24,72,28 // vbroadcastss 0x1c(%rax),%ymm9 + .byte 196,98,125,24,96,32 // vbroadcastss 0x20(%rax),%ymm12 + .byte 196,66,117,184,225 // vfmadd231ps %ymm9,%ymm1,%ymm12 + .byte 196,66,125,184,224 // vfmadd231ps %ymm8,%ymm0,%ymm12 + .byte 196,193,124,83,204 // vrcpps %ymm12,%ymm1 + .byte 197,172,89,193 // vmulps %ymm1,%ymm10,%ymm0 + .byte 197,164,89,201 // vmulps %ymm1,%ymm11,%ymm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_linear_gradient_hsw +.globl _sk_linear_gradient_hsw +_sk_linear_gradient_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,64,16 // vbroadcastss 0x10(%rax),%ymm8 + .byte 196,98,125,24,88,20 // vbroadcastss 0x14(%rax),%ymm11 + .byte 196,98,125,24,80,24 // vbroadcastss 0x18(%rax),%ymm10 + .byte 196,98,125,24,72,28 // vbroadcastss 0x1c(%rax),%ymm9 + .byte 76,139,0 // mov (%rax),%r8 + .byte 77,133,192 // test %r8,%r8 + .byte 15,132,143,0,0,0 // je 3105 <_sk_linear_gradient_hsw+0xb5> + .byte 72,139,64,8 // mov 0x8(%rax),%rax + .byte 72,131,192,32 // add $0x20,%rax + .byte 196,65,28,87,228 // vxorps %ymm12,%ymm12,%ymm12 + .byte 197,228,87,219 // vxorps %ymm3,%ymm3,%ymm3 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 196,98,125,24,104,224 // vbroadcastss -0x20(%rax),%ymm13 + .byte 196,65,124,194,237,1 // vcmpltps %ymm13,%ymm0,%ymm13 + .byte 196,98,125,24,112,228 // vbroadcastss -0x1c(%rax),%ymm14 + .byte 196,67,13,74,228,208 // vblendvps %ymm13,%ymm12,%ymm14,%ymm12 + .byte 196,98,125,24,112,232 // vbroadcastss -0x18(%rax),%ymm14 + .byte 196,227,13,74,201,208 // vblendvps %ymm13,%ymm1,%ymm14,%ymm1 + .byte 196,98,125,24,112,236 // vbroadcastss -0x14(%rax),%ymm14 + .byte 196,227,13,74,210,208 // vblendvps %ymm13,%ymm2,%ymm14,%ymm2 + .byte 196,98,125,24,112,240 // vbroadcastss -0x10(%rax),%ymm14 + .byte 196,227,13,74,219,208 // vblendvps %ymm13,%ymm3,%ymm14,%ymm3 + .byte 196,98,125,24,112,244 // vbroadcastss -0xc(%rax),%ymm14 + .byte 196,67,13,74,192,208 // vblendvps %ymm13,%ymm8,%ymm14,%ymm8 + .byte 196,98,125,24,112,248 // vbroadcastss -0x8(%rax),%ymm14 + .byte 196,67,13,74,219,208 // vblendvps %ymm13,%ymm11,%ymm14,%ymm11 + .byte 196,98,125,24,112,252 // vbroadcastss -0x4(%rax),%ymm14 + .byte 196,67,13,74,210,208 // vblendvps %ymm13,%ymm10,%ymm14,%ymm10 + .byte 196,98,125,24,48 // vbroadcastss (%rax),%ymm14 + .byte 196,67,13,74,201,208 // vblendvps %ymm13,%ymm9,%ymm14,%ymm9 + .byte 72,131,192,36 // add $0x24,%rax + .byte 73,255,200 // dec %r8 + .byte 117,140 // jne 308f <_sk_linear_gradient_hsw+0x3f> + .byte 235,17 // jmp 3116 <_sk_linear_gradient_hsw+0xc6> + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 197,228,87,219 // vxorps %ymm3,%ymm3,%ymm3 + .byte 196,65,28,87,228 // vxorps %ymm12,%ymm12,%ymm12 + .byte 196,66,125,184,196 // vfmadd231ps %ymm12,%ymm0,%ymm8 + .byte 196,194,125,168,203 // vfmadd213ps %ymm11,%ymm0,%ymm1 + .byte 196,194,125,168,210 // vfmadd213ps %ymm10,%ymm0,%ymm2 + .byte 196,194,125,168,217 // vfmadd213ps %ymm9,%ymm0,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,192 // vmovaps %ymm8,%ymm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_linear_gradient_2stops_hsw +.globl _sk_linear_gradient_2stops_hsw +_sk_linear_gradient_2stops_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,226,125,24,8 // vbroadcastss (%rax),%ymm1 + .byte 196,98,125,24,64,16 // vbroadcastss 0x10(%rax),%ymm8 + .byte 196,98,125,184,193 // vfmadd231ps %ymm1,%ymm0,%ymm8 + .byte 196,226,125,24,80,4 // vbroadcastss 0x4(%rax),%ymm2 + .byte 196,226,125,24,72,20 // vbroadcastss 0x14(%rax),%ymm1 + .byte 196,226,125,184,202 // vfmadd231ps %ymm2,%ymm0,%ymm1 + .byte 196,226,125,24,88,8 // vbroadcastss 0x8(%rax),%ymm3 + .byte 196,226,125,24,80,24 // vbroadcastss 0x18(%rax),%ymm2 + .byte 196,226,125,184,211 // vfmadd231ps %ymm3,%ymm0,%ymm2 + .byte 196,98,125,24,72,12 // vbroadcastss 0xc(%rax),%ymm9 + .byte 196,226,125,24,88,28 // vbroadcastss 0x1c(%rax),%ymm3 + .byte 196,194,125,184,217 // vfmadd231ps %ymm9,%ymm0,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,192 // vmovaps %ymm8,%ymm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_save_xy_hsw +.globl _sk_save_xy_hsw +_sk_save_xy_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,88,200 // vaddps %ymm0,%ymm8,%ymm9 + .byte 196,67,125,8,209,1 // vroundps $0x1,%ymm9,%ymm10 + .byte 196,65,52,92,202 // vsubps %ymm10,%ymm9,%ymm9 + .byte 197,60,88,193 // vaddps %ymm1,%ymm8,%ymm8 + .byte 196,67,125,8,208,1 // vroundps $0x1,%ymm8,%ymm10 + .byte 196,65,60,92,194 // vsubps %ymm10,%ymm8,%ymm8 + .byte 197,252,17,0 // vmovups %ymm0,(%rax) + .byte 197,252,17,72,32 // vmovups %ymm1,0x20(%rax) + .byte 197,124,17,72,64 // vmovups %ymm9,0x40(%rax) + .byte 197,124,17,64,96 // vmovups %ymm8,0x60(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_accumulate_hsw +.globl _sk_accumulate_hsw +_sk_accumulate_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,16,128,128,0,0,0 // vmovups 0x80(%rax),%ymm8 + .byte 197,60,89,128,160,0,0,0 // vmulps 0xa0(%rax),%ymm8,%ymm8 + .byte 196,226,61,184,224 // vfmadd231ps %ymm0,%ymm8,%ymm4 + .byte 196,226,61,184,233 // vfmadd231ps %ymm1,%ymm8,%ymm5 + .byte 196,226,61,184,242 // vfmadd231ps %ymm2,%ymm8,%ymm6 + .byte 196,98,101,168,199 // vfmadd213ps %ymm7,%ymm3,%ymm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,199 // vmovaps %ymm8,%ymm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_nx_hsw +.globl _sk_bilinear_nx_hsw +_sk_bilinear_nx_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,191 // mov $0xbf000000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 197,252,88,0 // vaddps (%rax),%ymm0,%ymm0 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,64,64 // vsubps 0x40(%rax),%ymm8,%ymm8 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_px_hsw +.globl _sk_bilinear_px_hsw +_sk_bilinear_px_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 197,252,88,0 // vaddps (%rax),%ymm0,%ymm0 + .byte 197,124,16,64,64 // vmovups 0x40(%rax),%ymm8 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_ny_hsw +.globl _sk_bilinear_ny_hsw +_sk_bilinear_ny_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,191 // mov $0xbf000000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,244,88,72,32 // vaddps 0x20(%rax),%ymm1,%ymm1 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,64,96 // vsubps 0x60(%rax),%ymm8,%ymm8 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_py_hsw +.globl _sk_bilinear_py_hsw +_sk_bilinear_py_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,244,88,72,32 // vaddps 0x20(%rax),%ymm1,%ymm1 + .byte 197,124,16,64,96 // vmovups 0x60(%rax),%ymm8 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n3x_hsw +.globl _sk_bicubic_n3x_hsw +_sk_bicubic_n3x_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,192,191 // mov $0xbfc00000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 197,252,88,0 // vaddps (%rax),%ymm0,%ymm0 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,64,64 // vsubps 0x40(%rax),%ymm8,%ymm8 + .byte 196,65,60,89,200 // vmulps %ymm8,%ymm8,%ymm9 + .byte 65,184,114,28,199,62 // mov $0x3ec71c72,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 65,184,171,170,170,190 // mov $0xbeaaaaab,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,66,125,88,219 // vpbroadcastd %xmm11,%ymm11 + .byte 196,66,61,168,211 // vfmadd213ps %ymm11,%ymm8,%ymm10 + .byte 196,65,44,89,193 // vmulps %ymm9,%ymm10,%ymm8 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n1x_hsw +.globl _sk_bicubic_n1x_hsw +_sk_bicubic_n1x_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,191 // mov $0xbf000000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 197,252,88,0 // vaddps (%rax),%ymm0,%ymm0 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,64,64 // vsubps 0x40(%rax),%ymm8,%ymm8 + .byte 65,184,85,85,149,191 // mov $0xbf955555,%r8d + .byte 196,65,121,110,200 // vmovd %r8d,%xmm9 + .byte 196,66,125,88,201 // vpbroadcastd %xmm9,%ymm9 + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 196,66,61,168,202 // vfmadd213ps %ymm10,%ymm8,%ymm9 + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 196,66,61,184,209 // vfmadd231ps %ymm9,%ymm8,%ymm10 + .byte 65,184,57,142,99,61 // mov $0x3d638e39,%r8d + .byte 196,65,121,110,200 // vmovd %r8d,%xmm9 + .byte 196,66,125,88,201 // vpbroadcastd %xmm9,%ymm9 + .byte 196,66,61,184,202 // vfmadd231ps %ymm10,%ymm8,%ymm9 + .byte 197,124,17,136,128,0,0,0 // vmovups %ymm9,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p1x_hsw +.globl _sk_bicubic_p1x_hsw +_sk_bicubic_p1x_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,98,125,88,192 // vpbroadcastd %xmm0,%ymm8 + .byte 197,188,88,0 // vaddps (%rax),%ymm8,%ymm0 + .byte 197,124,16,72,64 // vmovups 0x40(%rax),%ymm9 + .byte 65,184,85,85,149,191 // mov $0xbf955555,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,66,125,88,219 // vpbroadcastd %xmm11,%ymm11 + .byte 196,66,53,168,211 // vfmadd213ps %ymm11,%ymm9,%ymm10 + .byte 196,66,53,168,208 // vfmadd213ps %ymm8,%ymm9,%ymm10 + .byte 65,184,57,142,99,61 // mov $0x3d638e39,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 196,66,53,184,194 // vfmadd231ps %ymm10,%ymm9,%ymm8 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p3x_hsw +.globl _sk_bicubic_p3x_hsw +_sk_bicubic_p3x_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,226,125,88,192 // vpbroadcastd %xmm0,%ymm0 + .byte 197,252,88,0 // vaddps (%rax),%ymm0,%ymm0 + .byte 197,124,16,64,64 // vmovups 0x40(%rax),%ymm8 + .byte 196,65,60,89,200 // vmulps %ymm8,%ymm8,%ymm9 + .byte 65,184,114,28,199,62 // mov $0x3ec71c72,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 65,184,171,170,170,190 // mov $0xbeaaaaab,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,66,125,88,219 // vpbroadcastd %xmm11,%ymm11 + .byte 196,66,61,168,211 // vfmadd213ps %ymm11,%ymm8,%ymm10 + .byte 196,65,52,89,194 // vmulps %ymm10,%ymm9,%ymm8 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n3y_hsw +.globl _sk_bicubic_n3y_hsw +_sk_bicubic_n3y_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,192,191 // mov $0xbfc00000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,244,88,72,32 // vaddps 0x20(%rax),%ymm1,%ymm1 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,64,96 // vsubps 0x60(%rax),%ymm8,%ymm8 + .byte 196,65,60,89,200 // vmulps %ymm8,%ymm8,%ymm9 + .byte 65,184,114,28,199,62 // mov $0x3ec71c72,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 65,184,171,170,170,190 // mov $0xbeaaaaab,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,66,125,88,219 // vpbroadcastd %xmm11,%ymm11 + .byte 196,66,61,168,211 // vfmadd213ps %ymm11,%ymm8,%ymm10 + .byte 196,65,44,89,193 // vmulps %ymm9,%ymm10,%ymm8 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n1y_hsw +.globl _sk_bicubic_n1y_hsw +_sk_bicubic_n1y_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,191 // mov $0xbf000000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,244,88,72,32 // vaddps 0x20(%rax),%ymm1,%ymm1 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 197,60,92,64,96 // vsubps 0x60(%rax),%ymm8,%ymm8 + .byte 65,184,85,85,149,191 // mov $0xbf955555,%r8d + .byte 196,65,121,110,200 // vmovd %r8d,%xmm9 + .byte 196,66,125,88,201 // vpbroadcastd %xmm9,%ymm9 + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 196,66,61,168,202 // vfmadd213ps %ymm10,%ymm8,%ymm9 + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 196,66,61,184,209 // vfmadd231ps %ymm9,%ymm8,%ymm10 + .byte 65,184,57,142,99,61 // mov $0x3d638e39,%r8d + .byte 196,65,121,110,200 // vmovd %r8d,%xmm9 + .byte 196,66,125,88,201 // vpbroadcastd %xmm9,%ymm9 + .byte 196,66,61,184,202 // vfmadd231ps %ymm10,%ymm8,%ymm9 + .byte 197,124,17,136,160,0,0,0 // vmovups %ymm9,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p1y_hsw +.globl _sk_bicubic_p1y_hsw +_sk_bicubic_p1y_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,98,125,88,193 // vpbroadcastd %xmm1,%ymm8 + .byte 197,188,88,72,32 // vaddps 0x20(%rax),%ymm8,%ymm1 + .byte 197,124,16,72,96 // vmovups 0x60(%rax),%ymm9 + .byte 65,184,85,85,149,191 // mov $0xbf955555,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,66,125,88,219 // vpbroadcastd %xmm11,%ymm11 + .byte 196,66,53,168,211 // vfmadd213ps %ymm11,%ymm9,%ymm10 + .byte 196,66,53,168,208 // vfmadd213ps %ymm8,%ymm9,%ymm10 + .byte 65,184,57,142,99,61 // mov $0x3d638e39,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,66,125,88,192 // vpbroadcastd %xmm8,%ymm8 + .byte 196,66,53,184,194 // vfmadd231ps %ymm10,%ymm9,%ymm8 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p3y_hsw +.globl _sk_bicubic_p3y_hsw +_sk_bicubic_p3y_hsw: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,226,125,88,201 // vpbroadcastd %xmm1,%ymm1 + .byte 197,244,88,72,32 // vaddps 0x20(%rax),%ymm1,%ymm1 + .byte 197,124,16,64,96 // vmovups 0x60(%rax),%ymm8 + .byte 196,65,60,89,200 // vmulps %ymm8,%ymm8,%ymm9 + .byte 65,184,114,28,199,62 // mov $0x3ec71c72,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,66,125,88,210 // vpbroadcastd %xmm10,%ymm10 + .byte 65,184,171,170,170,190 // mov $0xbeaaaaab,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,66,125,88,219 // vpbroadcastd %xmm11,%ymm11 + .byte 196,66,61,168,211 // vfmadd213ps %ymm11,%ymm8,%ymm10 + .byte 196,65,52,89,194 // vmulps %ymm10,%ymm9,%ymm8 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_start_pipeline_avx +.globl _sk_start_pipeline_avx +_sk_start_pipeline_avx: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 73,137,205 // mov %rcx,%r13 + .byte 73,137,214 // mov %rdx,%r14 + .byte 72,137,251 // mov %rdi,%rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 73,137,199 // mov %rax,%r15 + .byte 73,137,244 // mov %rsi,%r12 + .byte 72,141,67,8 // lea 0x8(%rbx),%rax + .byte 76,57,232 // cmp %r13,%rax + .byte 118,5 // jbe 28 <_sk_start_pipeline_avx+0x28> + .byte 72,137,223 // mov %rbx,%rdi + .byte 235,65 // jmp 69 <_sk_start_pipeline_avx+0x69> + .byte 185,0,0,0,0 // mov $0x0,%ecx + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 197,228,87,219 // vxorps %ymm3,%ymm3,%ymm3 + .byte 197,220,87,228 // vxorps %ymm4,%ymm4,%ymm4 + .byte 197,212,87,237 // vxorps %ymm5,%ymm5,%ymm5 + .byte 197,204,87,246 // vxorps %ymm6,%ymm6,%ymm6 + .byte 197,196,87,255 // vxorps %ymm7,%ymm7,%ymm7 + .byte 72,137,223 // mov %rbx,%rdi + .byte 76,137,230 // mov %r12,%rsi + .byte 76,137,242 // mov %r14,%rdx + .byte 65,255,215 // callq *%r15 + .byte 72,141,123,8 // lea 0x8(%rbx),%rdi + .byte 72,131,195,16 // add $0x10,%rbx + .byte 76,57,235 // cmp %r13,%rbx + .byte 72,137,251 // mov %rdi,%rbx + .byte 118,191 // jbe 28 <_sk_start_pipeline_avx+0x28> + .byte 76,137,233 // mov %r13,%rcx + .byte 72,41,249 // sub %rdi,%rcx + .byte 116,41 // je 9a <_sk_start_pipeline_avx+0x9a> + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 197,228,87,219 // vxorps %ymm3,%ymm3,%ymm3 + .byte 197,220,87,228 // vxorps %ymm4,%ymm4,%ymm4 + .byte 197,212,87,237 // vxorps %ymm5,%ymm5,%ymm5 + .byte 197,204,87,246 // vxorps %ymm6,%ymm6,%ymm6 + .byte 197,196,87,255 // vxorps %ymm7,%ymm7,%ymm7 + .byte 76,137,230 // mov %r12,%rsi + .byte 76,137,242 // mov %r14,%rdx + .byte 65,255,215 // callq *%r15 + .byte 76,137,232 // mov %r13,%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 197,248,119 // vzeroupper + .byte 195 // retq + +HIDDEN _sk_just_return_avx +.globl _sk_just_return_avx +_sk_just_return_avx: + .byte 195 // retq + +HIDDEN _sk_seed_shader_avx +.globl _sk_seed_shader_avx +_sk_seed_shader_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,249,110,199 // vmovd %edi,%xmm0 + .byte 197,249,112,192,0 // vpshufd $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,252,88,193 // vaddps %ymm1,%ymm0,%ymm0 + .byte 197,252,88,2 // vaddps (%rdx),%ymm0,%ymm0 + .byte 196,226,125,24,16 // vbroadcastss (%rax),%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 197,236,88,201 // vaddps %ymm1,%ymm2,%ymm1 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,227,121,4,210,0 // vpermilps $0x0,%xmm2,%xmm2 + .byte 196,227,109,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,228,87,219 // vxorps %ymm3,%ymm3,%ymm3 + .byte 197,220,87,228 // vxorps %ymm4,%ymm4,%ymm4 + .byte 197,212,87,237 // vxorps %ymm5,%ymm5,%ymm5 + .byte 197,204,87,246 // vxorps %ymm6,%ymm6,%ymm6 + .byte 197,196,87,255 // vxorps %ymm7,%ymm7,%ymm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_constant_color_avx +.globl _sk_constant_color_avx +_sk_constant_color_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,226,125,24,0 // vbroadcastss (%rax),%ymm0 + .byte 196,226,125,24,72,4 // vbroadcastss 0x4(%rax),%ymm1 + .byte 196,226,125,24,80,8 // vbroadcastss 0x8(%rax),%ymm2 + .byte 196,226,125,24,88,12 // vbroadcastss 0xc(%rax),%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clear_avx +.globl _sk_clear_avx +_sk_clear_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 197,228,87,219 // vxorps %ymm3,%ymm3,%ymm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcatop_avx +.globl _sk_srcatop_avx +_sk_srcatop_avx: + .byte 197,124,89,199 // vmulps %ymm7,%ymm0,%ymm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,124,92,203 // vsubps %ymm3,%ymm0,%ymm9 + .byte 197,180,89,196 // vmulps %ymm4,%ymm9,%ymm0 + .byte 197,188,88,192 // vaddps %ymm0,%ymm8,%ymm0 + .byte 197,244,89,207 // vmulps %ymm7,%ymm1,%ymm1 + .byte 197,52,89,197 // vmulps %ymm5,%ymm9,%ymm8 + .byte 196,193,116,88,200 // vaddps %ymm8,%ymm1,%ymm1 + .byte 197,236,89,215 // vmulps %ymm7,%ymm2,%ymm2 + .byte 197,52,89,198 // vmulps %ymm6,%ymm9,%ymm8 + .byte 196,193,108,88,208 // vaddps %ymm8,%ymm2,%ymm2 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 197,52,89,199 // vmulps %ymm7,%ymm9,%ymm8 + .byte 196,193,100,88,216 // vaddps %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstatop_avx +.globl _sk_dstatop_avx +_sk_dstatop_avx: + .byte 197,100,89,196 // vmulps %ymm4,%ymm3,%ymm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 196,67,121,4,201,0 // vpermilps $0x0,%xmm9,%xmm9 + .byte 196,67,53,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + .byte 197,52,92,207 // vsubps %ymm7,%ymm9,%ymm9 + .byte 197,180,89,192 // vmulps %ymm0,%ymm9,%ymm0 + .byte 197,188,88,192 // vaddps %ymm0,%ymm8,%ymm0 + .byte 197,100,89,197 // vmulps %ymm5,%ymm3,%ymm8 + .byte 197,180,89,201 // vmulps %ymm1,%ymm9,%ymm1 + .byte 197,188,88,201 // vaddps %ymm1,%ymm8,%ymm1 + .byte 197,100,89,198 // vmulps %ymm6,%ymm3,%ymm8 + .byte 197,180,89,210 // vmulps %ymm2,%ymm9,%ymm2 + .byte 197,188,88,210 // vaddps %ymm2,%ymm8,%ymm2 + .byte 197,100,89,199 // vmulps %ymm7,%ymm3,%ymm8 + .byte 197,180,89,219 // vmulps %ymm3,%ymm9,%ymm3 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcin_avx +.globl _sk_srcin_avx +_sk_srcin_avx: + .byte 197,252,89,199 // vmulps %ymm7,%ymm0,%ymm0 + .byte 197,244,89,207 // vmulps %ymm7,%ymm1,%ymm1 + .byte 197,236,89,215 // vmulps %ymm7,%ymm2,%ymm2 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstin_avx +.globl _sk_dstin_avx +_sk_dstin_avx: + .byte 197,228,89,196 // vmulps %ymm4,%ymm3,%ymm0 + .byte 197,228,89,205 // vmulps %ymm5,%ymm3,%ymm1 + .byte 197,228,89,214 // vmulps %ymm6,%ymm3,%ymm2 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcout_avx +.globl _sk_srcout_avx +_sk_srcout_avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,199 // vsubps %ymm7,%ymm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstout_avx +.globl _sk_dstout_avx +_sk_dstout_avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,252,92,219 // vsubps %ymm3,%ymm0,%ymm3 + .byte 197,228,89,196 // vmulps %ymm4,%ymm3,%ymm0 + .byte 197,228,89,205 // vmulps %ymm5,%ymm3,%ymm1 + .byte 197,228,89,214 // vmulps %ymm6,%ymm3,%ymm2 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcover_avx +.globl _sk_srcover_avx +_sk_srcover_avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,204 // vmulps %ymm4,%ymm8,%ymm9 + .byte 197,180,88,192 // vaddps %ymm0,%ymm9,%ymm0 + .byte 197,60,89,205 // vmulps %ymm5,%ymm8,%ymm9 + .byte 197,180,88,201 // vaddps %ymm1,%ymm9,%ymm1 + .byte 197,60,89,206 // vmulps %ymm6,%ymm8,%ymm9 + .byte 197,180,88,210 // vaddps %ymm2,%ymm9,%ymm2 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstover_avx +.globl _sk_dstover_avx +_sk_dstover_avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,199 // vsubps %ymm7,%ymm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,252,88,196 // vaddps %ymm4,%ymm0,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,244,88,205 // vaddps %ymm5,%ymm1,%ymm1 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,236,88,214 // vaddps %ymm6,%ymm2,%ymm2 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 197,228,88,223 // vaddps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_modulate_avx +.globl _sk_modulate_avx +_sk_modulate_avx: + .byte 197,252,89,196 // vmulps %ymm4,%ymm0,%ymm0 + .byte 197,244,89,205 // vmulps %ymm5,%ymm1,%ymm1 + .byte 197,236,89,214 // vmulps %ymm6,%ymm2,%ymm2 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_multiply_avx +.globl _sk_multiply_avx +_sk_multiply_avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,207 // vsubps %ymm7,%ymm8,%ymm9 + .byte 197,52,89,208 // vmulps %ymm0,%ymm9,%ymm10 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,220 // vmulps %ymm4,%ymm8,%ymm11 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 197,252,89,196 // vmulps %ymm4,%ymm0,%ymm0 + .byte 196,193,124,88,194 // vaddps %ymm10,%ymm0,%ymm0 + .byte 197,52,89,209 // vmulps %ymm1,%ymm9,%ymm10 + .byte 197,60,89,221 // vmulps %ymm5,%ymm8,%ymm11 + .byte 196,65,36,88,210 // vaddps %ymm10,%ymm11,%ymm10 + .byte 197,244,89,205 // vmulps %ymm5,%ymm1,%ymm1 + .byte 196,193,116,88,202 // vaddps %ymm10,%ymm1,%ymm1 + .byte 197,52,89,210 // vmulps %ymm2,%ymm9,%ymm10 + .byte 197,60,89,222 // vmulps %ymm6,%ymm8,%ymm11 + .byte 196,65,36,88,210 // vaddps %ymm10,%ymm11,%ymm10 + .byte 197,236,89,214 // vmulps %ymm6,%ymm2,%ymm2 + .byte 196,193,108,88,210 // vaddps %ymm10,%ymm2,%ymm2 + .byte 197,52,89,203 // vmulps %ymm3,%ymm9,%ymm9 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 196,65,60,88,193 // vaddps %ymm9,%ymm8,%ymm8 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 196,193,100,88,216 // vaddps %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_plus__avx +.globl _sk_plus__avx +_sk_plus__avx: + .byte 197,252,88,196 // vaddps %ymm4,%ymm0,%ymm0 + .byte 197,244,88,205 // vaddps %ymm5,%ymm1,%ymm1 + .byte 197,236,88,214 // vaddps %ymm6,%ymm2,%ymm2 + .byte 197,228,88,223 // vaddps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_screen_avx +.globl _sk_screen_avx +_sk_screen_avx: + .byte 197,124,88,196 // vaddps %ymm4,%ymm0,%ymm8 + .byte 197,252,89,196 // vmulps %ymm4,%ymm0,%ymm0 + .byte 197,188,92,192 // vsubps %ymm0,%ymm8,%ymm0 + .byte 197,116,88,197 // vaddps %ymm5,%ymm1,%ymm8 + .byte 197,244,89,205 // vmulps %ymm5,%ymm1,%ymm1 + .byte 197,188,92,201 // vsubps %ymm1,%ymm8,%ymm1 + .byte 197,108,88,198 // vaddps %ymm6,%ymm2,%ymm8 + .byte 197,236,89,214 // vmulps %ymm6,%ymm2,%ymm2 + .byte 197,188,92,210 // vsubps %ymm2,%ymm8,%ymm2 + .byte 197,100,88,199 // vaddps %ymm7,%ymm3,%ymm8 + .byte 197,228,89,223 // vmulps %ymm7,%ymm3,%ymm3 + .byte 197,188,92,219 // vsubps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_xor__avx +.globl _sk_xor__avx +_sk_xor__avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,207 // vsubps %ymm7,%ymm8,%ymm9 + .byte 197,180,89,192 // vmulps %ymm0,%ymm9,%ymm0 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,212 // vmulps %ymm4,%ymm8,%ymm10 + .byte 196,193,124,88,194 // vaddps %ymm10,%ymm0,%ymm0 + .byte 197,180,89,201 // vmulps %ymm1,%ymm9,%ymm1 + .byte 197,60,89,213 // vmulps %ymm5,%ymm8,%ymm10 + .byte 197,172,88,201 // vaddps %ymm1,%ymm10,%ymm1 + .byte 197,180,89,210 // vmulps %ymm2,%ymm9,%ymm2 + .byte 197,60,89,214 // vmulps %ymm6,%ymm8,%ymm10 + .byte 197,172,88,210 // vaddps %ymm2,%ymm10,%ymm2 + .byte 197,180,89,219 // vmulps %ymm3,%ymm9,%ymm3 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_darken_avx +.globl _sk_darken_avx +_sk_darken_avx: + .byte 197,124,88,196 // vaddps %ymm4,%ymm0,%ymm8 + .byte 197,252,89,199 // vmulps %ymm7,%ymm0,%ymm0 + .byte 197,100,89,204 // vmulps %ymm4,%ymm3,%ymm9 + .byte 196,193,124,95,193 // vmaxps %ymm9,%ymm0,%ymm0 + .byte 197,188,92,192 // vsubps %ymm0,%ymm8,%ymm0 + .byte 197,116,88,197 // vaddps %ymm5,%ymm1,%ymm8 + .byte 197,244,89,207 // vmulps %ymm7,%ymm1,%ymm1 + .byte 197,100,89,205 // vmulps %ymm5,%ymm3,%ymm9 + .byte 196,193,116,95,201 // vmaxps %ymm9,%ymm1,%ymm1 + .byte 197,188,92,201 // vsubps %ymm1,%ymm8,%ymm1 + .byte 197,108,88,198 // vaddps %ymm6,%ymm2,%ymm8 + .byte 197,236,89,215 // vmulps %ymm7,%ymm2,%ymm2 + .byte 197,100,89,206 // vmulps %ymm6,%ymm3,%ymm9 + .byte 196,193,108,95,209 // vmaxps %ymm9,%ymm2,%ymm2 + .byte 197,188,92,210 // vsubps %ymm2,%ymm8,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lighten_avx +.globl _sk_lighten_avx +_sk_lighten_avx: + .byte 197,124,88,196 // vaddps %ymm4,%ymm0,%ymm8 + .byte 197,252,89,199 // vmulps %ymm7,%ymm0,%ymm0 + .byte 197,100,89,204 // vmulps %ymm4,%ymm3,%ymm9 + .byte 196,193,124,93,193 // vminps %ymm9,%ymm0,%ymm0 + .byte 197,188,92,192 // vsubps %ymm0,%ymm8,%ymm0 + .byte 197,116,88,197 // vaddps %ymm5,%ymm1,%ymm8 + .byte 197,244,89,207 // vmulps %ymm7,%ymm1,%ymm1 + .byte 197,100,89,205 // vmulps %ymm5,%ymm3,%ymm9 + .byte 196,193,116,93,201 // vminps %ymm9,%ymm1,%ymm1 + .byte 197,188,92,201 // vsubps %ymm1,%ymm8,%ymm1 + .byte 197,108,88,198 // vaddps %ymm6,%ymm2,%ymm8 + .byte 197,236,89,215 // vmulps %ymm7,%ymm2,%ymm2 + .byte 197,100,89,206 // vmulps %ymm6,%ymm3,%ymm9 + .byte 196,193,108,93,209 // vminps %ymm9,%ymm2,%ymm2 + .byte 197,188,92,210 // vsubps %ymm2,%ymm8,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_difference_avx +.globl _sk_difference_avx +_sk_difference_avx: + .byte 197,124,88,196 // vaddps %ymm4,%ymm0,%ymm8 + .byte 197,252,89,199 // vmulps %ymm7,%ymm0,%ymm0 + .byte 197,100,89,204 // vmulps %ymm4,%ymm3,%ymm9 + .byte 196,193,124,93,193 // vminps %ymm9,%ymm0,%ymm0 + .byte 197,252,88,192 // vaddps %ymm0,%ymm0,%ymm0 + .byte 197,188,92,192 // vsubps %ymm0,%ymm8,%ymm0 + .byte 197,116,88,197 // vaddps %ymm5,%ymm1,%ymm8 + .byte 197,244,89,207 // vmulps %ymm7,%ymm1,%ymm1 + .byte 197,100,89,205 // vmulps %ymm5,%ymm3,%ymm9 + .byte 196,193,116,93,201 // vminps %ymm9,%ymm1,%ymm1 + .byte 197,244,88,201 // vaddps %ymm1,%ymm1,%ymm1 + .byte 197,188,92,201 // vsubps %ymm1,%ymm8,%ymm1 + .byte 197,108,88,198 // vaddps %ymm6,%ymm2,%ymm8 + .byte 197,236,89,215 // vmulps %ymm7,%ymm2,%ymm2 + .byte 197,100,89,206 // vmulps %ymm6,%ymm3,%ymm9 + .byte 196,193,108,93,209 // vminps %ymm9,%ymm2,%ymm2 + .byte 197,236,88,210 // vaddps %ymm2,%ymm2,%ymm2 + .byte 197,188,92,210 // vsubps %ymm2,%ymm8,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_exclusion_avx +.globl _sk_exclusion_avx +_sk_exclusion_avx: + .byte 197,124,88,196 // vaddps %ymm4,%ymm0,%ymm8 + .byte 197,252,89,196 // vmulps %ymm4,%ymm0,%ymm0 + .byte 197,252,88,192 // vaddps %ymm0,%ymm0,%ymm0 + .byte 197,188,92,192 // vsubps %ymm0,%ymm8,%ymm0 + .byte 197,116,88,197 // vaddps %ymm5,%ymm1,%ymm8 + .byte 197,244,89,205 // vmulps %ymm5,%ymm1,%ymm1 + .byte 197,244,88,201 // vaddps %ymm1,%ymm1,%ymm1 + .byte 197,188,92,201 // vsubps %ymm1,%ymm8,%ymm1 + .byte 197,108,88,198 // vaddps %ymm6,%ymm2,%ymm8 + .byte 197,236,89,214 // vmulps %ymm6,%ymm2,%ymm2 + .byte 197,236,88,210 // vaddps %ymm2,%ymm2,%ymm2 + .byte 197,188,92,210 // vsubps %ymm2,%ymm8,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_colorburn_avx +.globl _sk_colorburn_avx +_sk_colorburn_avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,207 // vsubps %ymm7,%ymm8,%ymm9 + .byte 197,52,89,216 // vmulps %ymm0,%ymm9,%ymm11 + .byte 196,65,44,87,210 // vxorps %ymm10,%ymm10,%ymm10 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,228 // vmulps %ymm4,%ymm8,%ymm12 + .byte 197,68,92,236 // vsubps %ymm4,%ymm7,%ymm13 + .byte 197,20,89,235 // vmulps %ymm3,%ymm13,%ymm13 + .byte 197,20,94,232 // vdivps %ymm0,%ymm13,%ymm13 + .byte 196,65,68,93,237 // vminps %ymm13,%ymm7,%ymm13 + .byte 196,65,68,92,237 // vsubps %ymm13,%ymm7,%ymm13 + .byte 197,20,89,235 // vmulps %ymm3,%ymm13,%ymm13 + .byte 196,65,20,88,235 // vaddps %ymm11,%ymm13,%ymm13 + .byte 196,65,28,88,237 // vaddps %ymm13,%ymm12,%ymm13 + .byte 197,28,88,224 // vaddps %ymm0,%ymm12,%ymm12 + .byte 196,193,124,194,194,0 // vcmpeqps %ymm10,%ymm0,%ymm0 + .byte 196,195,21,74,196,0 // vblendvps %ymm0,%ymm12,%ymm13,%ymm0 + .byte 197,92,194,231,0 // vcmpeqps %ymm7,%ymm4,%ymm12 + .byte 197,36,88,220 // vaddps %ymm4,%ymm11,%ymm11 + .byte 196,195,125,74,195,192 // vblendvps %ymm12,%ymm11,%ymm0,%ymm0 + .byte 197,52,89,217 // vmulps %ymm1,%ymm9,%ymm11 + .byte 197,60,89,229 // vmulps %ymm5,%ymm8,%ymm12 + .byte 197,68,92,237 // vsubps %ymm5,%ymm7,%ymm13 + .byte 197,20,89,235 // vmulps %ymm3,%ymm13,%ymm13 + .byte 197,20,94,233 // vdivps %ymm1,%ymm13,%ymm13 + .byte 196,65,68,93,237 // vminps %ymm13,%ymm7,%ymm13 + .byte 196,65,68,92,237 // vsubps %ymm13,%ymm7,%ymm13 + .byte 197,20,89,235 // vmulps %ymm3,%ymm13,%ymm13 + .byte 196,65,36,88,237 // vaddps %ymm13,%ymm11,%ymm13 + .byte 196,65,28,88,237 // vaddps %ymm13,%ymm12,%ymm13 + .byte 197,28,88,225 // vaddps %ymm1,%ymm12,%ymm12 + .byte 196,193,116,194,202,0 // vcmpeqps %ymm10,%ymm1,%ymm1 + .byte 196,195,21,74,204,16 // vblendvps %ymm1,%ymm12,%ymm13,%ymm1 + .byte 197,84,194,231,0 // vcmpeqps %ymm7,%ymm5,%ymm12 + .byte 197,36,88,221 // vaddps %ymm5,%ymm11,%ymm11 + .byte 196,195,117,74,203,192 // vblendvps %ymm12,%ymm11,%ymm1,%ymm1 + .byte 197,52,89,202 // vmulps %ymm2,%ymm9,%ymm9 + .byte 196,65,108,194,210,0 // vcmpeqps %ymm10,%ymm2,%ymm10 + .byte 197,60,89,222 // vmulps %ymm6,%ymm8,%ymm11 + .byte 197,68,92,230 // vsubps %ymm6,%ymm7,%ymm12 + .byte 197,28,89,227 // vmulps %ymm3,%ymm12,%ymm12 + .byte 197,28,94,226 // vdivps %ymm2,%ymm12,%ymm12 + .byte 197,164,88,210 // vaddps %ymm2,%ymm11,%ymm2 + .byte 196,65,68,93,228 // vminps %ymm12,%ymm7,%ymm12 + .byte 196,65,68,92,228 // vsubps %ymm12,%ymm7,%ymm12 + .byte 197,28,89,227 // vmulps %ymm3,%ymm12,%ymm12 + .byte 196,65,52,88,228 // vaddps %ymm12,%ymm9,%ymm12 + .byte 196,65,36,88,220 // vaddps %ymm12,%ymm11,%ymm11 + .byte 196,227,37,74,210,160 // vblendvps %ymm10,%ymm2,%ymm11,%ymm2 + .byte 197,76,194,215,0 // vcmpeqps %ymm7,%ymm6,%ymm10 + .byte 197,52,88,206 // vaddps %ymm6,%ymm9,%ymm9 + .byte 196,195,109,74,209,160 // vblendvps %ymm10,%ymm9,%ymm2,%ymm2 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_colordodge_avx +.globl _sk_colordodge_avx +_sk_colordodge_avx: + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 196,67,121,4,201,0 // vpermilps $0x0,%xmm9,%xmm9 + .byte 196,67,53,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + .byte 197,52,92,215 // vsubps %ymm7,%ymm9,%ymm10 + .byte 197,44,89,216 // vmulps %ymm0,%ymm10,%ymm11 + .byte 197,52,92,203 // vsubps %ymm3,%ymm9,%ymm9 + .byte 197,100,89,228 // vmulps %ymm4,%ymm3,%ymm12 + .byte 197,100,92,232 // vsubps %ymm0,%ymm3,%ymm13 + .byte 196,65,28,94,229 // vdivps %ymm13,%ymm12,%ymm12 + .byte 197,52,89,236 // vmulps %ymm4,%ymm9,%ymm13 + .byte 196,65,68,93,228 // vminps %ymm12,%ymm7,%ymm12 + .byte 197,28,89,227 // vmulps %ymm3,%ymm12,%ymm12 + .byte 196,65,28,88,227 // vaddps %ymm11,%ymm12,%ymm12 + .byte 196,65,20,88,228 // vaddps %ymm12,%ymm13,%ymm12 + .byte 197,20,88,232 // vaddps %ymm0,%ymm13,%ymm13 + .byte 197,252,194,195,0 // vcmpeqps %ymm3,%ymm0,%ymm0 + .byte 196,195,29,74,197,0 // vblendvps %ymm0,%ymm13,%ymm12,%ymm0 + .byte 196,65,92,194,224,0 // vcmpeqps %ymm8,%ymm4,%ymm12 + .byte 197,36,88,220 // vaddps %ymm4,%ymm11,%ymm11 + .byte 196,195,125,74,195,192 // vblendvps %ymm12,%ymm11,%ymm0,%ymm0 + .byte 197,44,89,217 // vmulps %ymm1,%ymm10,%ymm11 + .byte 197,100,89,229 // vmulps %ymm5,%ymm3,%ymm12 + .byte 197,100,92,233 // vsubps %ymm1,%ymm3,%ymm13 + .byte 196,65,28,94,229 // vdivps %ymm13,%ymm12,%ymm12 + .byte 197,52,89,237 // vmulps %ymm5,%ymm9,%ymm13 + .byte 196,65,68,93,228 // vminps %ymm12,%ymm7,%ymm12 + .byte 197,28,89,227 // vmulps %ymm3,%ymm12,%ymm12 + .byte 196,65,28,88,227 // vaddps %ymm11,%ymm12,%ymm12 + .byte 196,65,20,88,228 // vaddps %ymm12,%ymm13,%ymm12 + .byte 197,20,88,233 // vaddps %ymm1,%ymm13,%ymm13 + .byte 197,244,194,203,0 // vcmpeqps %ymm3,%ymm1,%ymm1 + .byte 196,195,29,74,205,16 // vblendvps %ymm1,%ymm13,%ymm12,%ymm1 + .byte 196,65,84,194,224,0 // vcmpeqps %ymm8,%ymm5,%ymm12 + .byte 197,36,88,221 // vaddps %ymm5,%ymm11,%ymm11 + .byte 196,195,117,74,203,192 // vblendvps %ymm12,%ymm11,%ymm1,%ymm1 + .byte 197,44,89,210 // vmulps %ymm2,%ymm10,%ymm10 + .byte 197,100,89,222 // vmulps %ymm6,%ymm3,%ymm11 + .byte 197,100,92,226 // vsubps %ymm2,%ymm3,%ymm12 + .byte 196,65,36,94,220 // vdivps %ymm12,%ymm11,%ymm11 + .byte 197,52,89,230 // vmulps %ymm6,%ymm9,%ymm12 + .byte 196,65,68,93,219 // vminps %ymm11,%ymm7,%ymm11 + .byte 197,36,89,219 // vmulps %ymm3,%ymm11,%ymm11 + .byte 196,65,44,88,219 // vaddps %ymm11,%ymm10,%ymm11 + .byte 196,65,28,88,219 // vaddps %ymm11,%ymm12,%ymm11 + .byte 197,28,88,226 // vaddps %ymm2,%ymm12,%ymm12 + .byte 197,236,194,211,0 // vcmpeqps %ymm3,%ymm2,%ymm2 + .byte 196,195,37,74,212,32 // vblendvps %ymm2,%ymm12,%ymm11,%ymm2 + .byte 196,65,76,194,192,0 // vcmpeqps %ymm8,%ymm6,%ymm8 + .byte 197,44,88,214 // vaddps %ymm6,%ymm10,%ymm10 + .byte 196,195,109,74,210,128 // vblendvps %ymm8,%ymm10,%ymm2,%ymm2 + .byte 197,52,89,199 // vmulps %ymm7,%ymm9,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_hardlight_avx +.globl _sk_hardlight_avx +_sk_hardlight_avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,215 // vsubps %ymm7,%ymm8,%ymm10 + .byte 197,44,89,200 // vmulps %ymm0,%ymm10,%ymm9 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,220 // vmulps %ymm4,%ymm8,%ymm11 + .byte 196,65,52,88,219 // vaddps %ymm11,%ymm9,%ymm11 + .byte 197,124,88,200 // vaddps %ymm0,%ymm0,%ymm9 + .byte 197,52,194,227,2 // vcmpleps %ymm3,%ymm9,%ymm12 + .byte 197,124,89,204 // vmulps %ymm4,%ymm0,%ymm9 + .byte 196,65,52,88,233 // vaddps %ymm9,%ymm9,%ymm13 + .byte 197,100,89,207 // vmulps %ymm7,%ymm3,%ymm9 + .byte 197,68,92,244 // vsubps %ymm4,%ymm7,%ymm14 + .byte 197,228,92,192 // vsubps %ymm0,%ymm3,%ymm0 + .byte 196,193,124,89,198 // vmulps %ymm14,%ymm0,%ymm0 + .byte 197,252,88,192 // vaddps %ymm0,%ymm0,%ymm0 + .byte 197,180,92,192 // vsubps %ymm0,%ymm9,%ymm0 + .byte 196,195,125,74,197,192 // vblendvps %ymm12,%ymm13,%ymm0,%ymm0 + .byte 196,193,124,88,195 // vaddps %ymm11,%ymm0,%ymm0 + .byte 197,44,89,217 // vmulps %ymm1,%ymm10,%ymm11 + .byte 197,60,89,229 // vmulps %ymm5,%ymm8,%ymm12 + .byte 196,65,28,88,219 // vaddps %ymm11,%ymm12,%ymm11 + .byte 197,116,88,225 // vaddps %ymm1,%ymm1,%ymm12 + .byte 197,28,194,227,2 // vcmpleps %ymm3,%ymm12,%ymm12 + .byte 197,116,89,237 // vmulps %ymm5,%ymm1,%ymm13 + .byte 196,65,20,88,237 // vaddps %ymm13,%ymm13,%ymm13 + .byte 197,68,92,245 // vsubps %ymm5,%ymm7,%ymm14 + .byte 197,228,92,201 // vsubps %ymm1,%ymm3,%ymm1 + .byte 196,193,116,89,206 // vmulps %ymm14,%ymm1,%ymm1 + .byte 197,244,88,201 // vaddps %ymm1,%ymm1,%ymm1 + .byte 197,180,92,201 // vsubps %ymm1,%ymm9,%ymm1 + .byte 196,195,117,74,205,192 // vblendvps %ymm12,%ymm13,%ymm1,%ymm1 + .byte 196,193,116,88,203 // vaddps %ymm11,%ymm1,%ymm1 + .byte 197,44,89,210 // vmulps %ymm2,%ymm10,%ymm10 + .byte 197,60,89,222 // vmulps %ymm6,%ymm8,%ymm11 + .byte 196,65,36,88,210 // vaddps %ymm10,%ymm11,%ymm10 + .byte 197,108,88,218 // vaddps %ymm2,%ymm2,%ymm11 + .byte 197,36,194,219,2 // vcmpleps %ymm3,%ymm11,%ymm11 + .byte 197,108,89,230 // vmulps %ymm6,%ymm2,%ymm12 + .byte 196,65,28,88,228 // vaddps %ymm12,%ymm12,%ymm12 + .byte 197,68,92,238 // vsubps %ymm6,%ymm7,%ymm13 + .byte 197,228,92,210 // vsubps %ymm2,%ymm3,%ymm2 + .byte 196,193,108,89,213 // vmulps %ymm13,%ymm2,%ymm2 + .byte 197,236,88,210 // vaddps %ymm2,%ymm2,%ymm2 + .byte 197,180,92,210 // vsubps %ymm2,%ymm9,%ymm2 + .byte 196,195,109,74,212,176 // vblendvps %ymm11,%ymm12,%ymm2,%ymm2 + .byte 196,193,108,88,210 // vaddps %ymm10,%ymm2,%ymm2 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_overlay_avx +.globl _sk_overlay_avx +_sk_overlay_avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,215 // vsubps %ymm7,%ymm8,%ymm10 + .byte 197,44,89,200 // vmulps %ymm0,%ymm10,%ymm9 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,220 // vmulps %ymm4,%ymm8,%ymm11 + .byte 196,65,52,88,219 // vaddps %ymm11,%ymm9,%ymm11 + .byte 197,92,88,204 // vaddps %ymm4,%ymm4,%ymm9 + .byte 197,52,194,231,2 // vcmpleps %ymm7,%ymm9,%ymm12 + .byte 197,124,89,204 // vmulps %ymm4,%ymm0,%ymm9 + .byte 196,65,52,88,233 // vaddps %ymm9,%ymm9,%ymm13 + .byte 197,100,89,207 // vmulps %ymm7,%ymm3,%ymm9 + .byte 197,68,92,244 // vsubps %ymm4,%ymm7,%ymm14 + .byte 197,228,92,192 // vsubps %ymm0,%ymm3,%ymm0 + .byte 196,193,124,89,198 // vmulps %ymm14,%ymm0,%ymm0 + .byte 197,252,88,192 // vaddps %ymm0,%ymm0,%ymm0 + .byte 197,180,92,192 // vsubps %ymm0,%ymm9,%ymm0 + .byte 196,195,125,74,197,192 // vblendvps %ymm12,%ymm13,%ymm0,%ymm0 + .byte 196,193,124,88,195 // vaddps %ymm11,%ymm0,%ymm0 + .byte 197,44,89,217 // vmulps %ymm1,%ymm10,%ymm11 + .byte 197,60,89,229 // vmulps %ymm5,%ymm8,%ymm12 + .byte 196,65,28,88,219 // vaddps %ymm11,%ymm12,%ymm11 + .byte 197,84,88,229 // vaddps %ymm5,%ymm5,%ymm12 + .byte 197,28,194,231,2 // vcmpleps %ymm7,%ymm12,%ymm12 + .byte 197,116,89,237 // vmulps %ymm5,%ymm1,%ymm13 + .byte 196,65,20,88,237 // vaddps %ymm13,%ymm13,%ymm13 + .byte 197,68,92,245 // vsubps %ymm5,%ymm7,%ymm14 + .byte 197,228,92,201 // vsubps %ymm1,%ymm3,%ymm1 + .byte 196,193,116,89,206 // vmulps %ymm14,%ymm1,%ymm1 + .byte 197,244,88,201 // vaddps %ymm1,%ymm1,%ymm1 + .byte 197,180,92,201 // vsubps %ymm1,%ymm9,%ymm1 + .byte 196,195,117,74,205,192 // vblendvps %ymm12,%ymm13,%ymm1,%ymm1 + .byte 196,193,116,88,203 // vaddps %ymm11,%ymm1,%ymm1 + .byte 197,44,89,210 // vmulps %ymm2,%ymm10,%ymm10 + .byte 197,60,89,222 // vmulps %ymm6,%ymm8,%ymm11 + .byte 196,65,36,88,210 // vaddps %ymm10,%ymm11,%ymm10 + .byte 197,76,88,222 // vaddps %ymm6,%ymm6,%ymm11 + .byte 197,36,194,223,2 // vcmpleps %ymm7,%ymm11,%ymm11 + .byte 197,108,89,230 // vmulps %ymm6,%ymm2,%ymm12 + .byte 196,65,28,88,228 // vaddps %ymm12,%ymm12,%ymm12 + .byte 197,68,92,238 // vsubps %ymm6,%ymm7,%ymm13 + .byte 197,228,92,210 // vsubps %ymm2,%ymm3,%ymm2 + .byte 196,193,108,89,213 // vmulps %ymm13,%ymm2,%ymm2 + .byte 197,236,88,210 // vaddps %ymm2,%ymm2,%ymm2 + .byte 197,180,92,210 // vsubps %ymm2,%ymm9,%ymm2 + .byte 196,195,109,74,212,176 // vblendvps %ymm11,%ymm12,%ymm2,%ymm2 + .byte 196,193,108,88,210 // vaddps %ymm10,%ymm2,%ymm2 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_softlight_avx +.globl _sk_softlight_avx +_sk_softlight_avx: + .byte 197,252,17,84,36,200 // vmovups %ymm2,-0x38(%rsp) + .byte 197,252,40,209 // vmovaps %ymm1,%ymm2 + .byte 196,65,52,87,201 // vxorps %ymm9,%ymm9,%ymm9 + .byte 197,52,194,215,1 // vcmpltps %ymm7,%ymm9,%ymm10 + .byte 197,92,94,199 // vdivps %ymm7,%ymm4,%ymm8 + .byte 196,67,53,74,216,160 // vblendvps %ymm10,%ymm8,%ymm9,%ymm11 + .byte 196,65,36,88,195 // vaddps %ymm11,%ymm11,%ymm8 + .byte 196,65,60,88,224 // vaddps %ymm8,%ymm8,%ymm12 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 196,65,28,89,236 // vmulps %ymm12,%ymm12,%ymm13 + .byte 196,65,28,88,229 // vaddps %ymm13,%ymm12,%ymm12 + .byte 196,65,36,92,232 // vsubps %ymm8,%ymm11,%ymm13 + .byte 196,65,28,89,237 // vmulps %ymm13,%ymm12,%ymm13 + .byte 184,0,0,224,64 // mov $0x40e00000,%eax + .byte 197,121,110,224 // vmovd %eax,%xmm12 + .byte 196,67,121,4,228,0 // vpermilps $0x0,%xmm12,%xmm12 + .byte 196,67,29,24,228,1 // vinsertf128 $0x1,%xmm12,%ymm12,%ymm12 + .byte 196,65,36,89,244 // vmulps %ymm12,%ymm11,%ymm14 + .byte 196,65,20,88,238 // vaddps %ymm14,%ymm13,%ymm13 + .byte 196,65,124,82,243 // vrsqrtps %ymm11,%ymm14 + .byte 196,65,124,83,246 // vrcpps %ymm14,%ymm14 + .byte 196,65,12,92,243 // vsubps %ymm11,%ymm14,%ymm14 + .byte 197,92,88,252 // vaddps %ymm4,%ymm4,%ymm15 + .byte 196,65,4,88,255 // vaddps %ymm15,%ymm15,%ymm15 + .byte 197,4,194,255,2 // vcmpleps %ymm7,%ymm15,%ymm15 + .byte 196,67,13,74,237,240 // vblendvps %ymm15,%ymm13,%ymm14,%ymm13 + .byte 197,124,88,240 // vaddps %ymm0,%ymm0,%ymm14 + .byte 197,12,92,251 // vsubps %ymm3,%ymm14,%ymm15 + .byte 196,65,60,92,219 // vsubps %ymm11,%ymm8,%ymm11 + .byte 196,65,4,89,219 // vmulps %ymm11,%ymm15,%ymm11 + .byte 197,36,88,219 // vaddps %ymm3,%ymm11,%ymm11 + .byte 197,36,89,220 // vmulps %ymm4,%ymm11,%ymm11 + .byte 197,4,89,255 // vmulps %ymm7,%ymm15,%ymm15 + .byte 196,65,4,89,237 // vmulps %ymm13,%ymm15,%ymm13 + .byte 197,100,89,252 // vmulps %ymm4,%ymm3,%ymm15 + .byte 196,65,4,88,237 // vaddps %ymm13,%ymm15,%ymm13 + .byte 197,12,194,243,2 // vcmpleps %ymm3,%ymm14,%ymm14 + .byte 196,195,21,74,203,224 // vblendvps %ymm14,%ymm11,%ymm13,%ymm1 + .byte 197,84,94,239 // vdivps %ymm7,%ymm5,%ymm13 + .byte 196,67,53,74,237,160 // vblendvps %ymm10,%ymm13,%ymm9,%ymm13 + .byte 196,65,20,88,245 // vaddps %ymm13,%ymm13,%ymm14 + .byte 196,65,12,88,246 // vaddps %ymm14,%ymm14,%ymm14 + .byte 196,65,12,89,254 // vmulps %ymm14,%ymm14,%ymm15 + .byte 196,65,12,88,247 // vaddps %ymm15,%ymm14,%ymm14 + .byte 196,65,20,92,248 // vsubps %ymm8,%ymm13,%ymm15 + .byte 196,65,4,89,246 // vmulps %ymm14,%ymm15,%ymm14 + .byte 196,65,28,89,253 // vmulps %ymm13,%ymm12,%ymm15 + .byte 196,65,4,88,246 // vaddps %ymm14,%ymm15,%ymm14 + .byte 196,65,124,82,253 // vrsqrtps %ymm13,%ymm15 + .byte 196,65,124,83,255 // vrcpps %ymm15,%ymm15 + .byte 196,65,4,92,253 // vsubps %ymm13,%ymm15,%ymm15 + .byte 197,84,88,221 // vaddps %ymm5,%ymm5,%ymm11 + .byte 196,65,36,88,219 // vaddps %ymm11,%ymm11,%ymm11 + .byte 197,36,194,223,2 // vcmpleps %ymm7,%ymm11,%ymm11 + .byte 196,67,5,74,222,176 // vblendvps %ymm11,%ymm14,%ymm15,%ymm11 + .byte 197,108,88,242 // vaddps %ymm2,%ymm2,%ymm14 + .byte 196,65,60,92,237 // vsubps %ymm13,%ymm8,%ymm13 + .byte 197,12,92,251 // vsubps %ymm3,%ymm14,%ymm15 + .byte 196,65,4,89,237 // vmulps %ymm13,%ymm15,%ymm13 + .byte 197,4,89,255 // vmulps %ymm7,%ymm15,%ymm15 + .byte 196,65,4,89,219 // vmulps %ymm11,%ymm15,%ymm11 + .byte 197,100,89,253 // vmulps %ymm5,%ymm3,%ymm15 + .byte 196,65,4,88,219 // vaddps %ymm11,%ymm15,%ymm11 + .byte 197,20,88,235 // vaddps %ymm3,%ymm13,%ymm13 + .byte 197,20,89,237 // vmulps %ymm5,%ymm13,%ymm13 + .byte 197,12,194,243,2 // vcmpleps %ymm3,%ymm14,%ymm14 + .byte 196,67,37,74,237,224 // vblendvps %ymm14,%ymm13,%ymm11,%ymm13 + .byte 197,76,94,223 // vdivps %ymm7,%ymm6,%ymm11 + .byte 196,67,53,74,203,160 // vblendvps %ymm10,%ymm11,%ymm9,%ymm9 + .byte 196,65,52,88,209 // vaddps %ymm9,%ymm9,%ymm10 + .byte 196,65,44,88,210 // vaddps %ymm10,%ymm10,%ymm10 + .byte 196,65,44,89,218 // vmulps %ymm10,%ymm10,%ymm11 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 196,65,52,92,216 // vsubps %ymm8,%ymm9,%ymm11 + .byte 196,65,36,89,210 // vmulps %ymm10,%ymm11,%ymm10 + .byte 196,65,28,89,217 // vmulps %ymm9,%ymm12,%ymm11 + .byte 196,65,36,88,210 // vaddps %ymm10,%ymm11,%ymm10 + .byte 196,65,124,82,217 // vrsqrtps %ymm9,%ymm11 + .byte 196,65,124,83,219 // vrcpps %ymm11,%ymm11 + .byte 196,65,36,92,217 // vsubps %ymm9,%ymm11,%ymm11 + .byte 197,76,88,230 // vaddps %ymm6,%ymm6,%ymm12 + .byte 196,65,28,88,228 // vaddps %ymm12,%ymm12,%ymm12 + .byte 197,28,194,231,2 // vcmpleps %ymm7,%ymm12,%ymm12 + .byte 196,67,37,74,210,192 // vblendvps %ymm12,%ymm10,%ymm11,%ymm10 + .byte 197,124,16,116,36,200 // vmovups -0x38(%rsp),%ymm14 + .byte 196,65,12,88,222 // vaddps %ymm14,%ymm14,%ymm11 + .byte 197,36,92,227 // vsubps %ymm3,%ymm11,%ymm12 + .byte 196,65,60,92,201 // vsubps %ymm9,%ymm8,%ymm9 + .byte 196,65,28,89,201 // vmulps %ymm9,%ymm12,%ymm9 + .byte 197,28,89,231 // vmulps %ymm7,%ymm12,%ymm12 + .byte 196,65,28,89,210 // vmulps %ymm10,%ymm12,%ymm10 + .byte 197,100,89,230 // vmulps %ymm6,%ymm3,%ymm12 + .byte 196,65,28,88,210 // vaddps %ymm10,%ymm12,%ymm10 + .byte 197,52,88,203 // vaddps %ymm3,%ymm9,%ymm9 + .byte 197,52,89,206 // vmulps %ymm6,%ymm9,%ymm9 + .byte 197,36,194,219,2 // vcmpleps %ymm3,%ymm11,%ymm11 + .byte 196,67,45,74,201,176 // vblendvps %ymm11,%ymm9,%ymm10,%ymm9 + .byte 197,60,92,215 // vsubps %ymm7,%ymm8,%ymm10 + .byte 197,172,89,192 // vmulps %ymm0,%ymm10,%ymm0 + .byte 197,60,92,195 // vsubps %ymm3,%ymm8,%ymm8 + .byte 197,60,89,220 // vmulps %ymm4,%ymm8,%ymm11 + .byte 196,193,124,88,195 // vaddps %ymm11,%ymm0,%ymm0 + .byte 197,244,88,192 // vaddps %ymm0,%ymm1,%ymm0 + .byte 197,172,89,202 // vmulps %ymm2,%ymm10,%ymm1 + .byte 197,188,89,213 // vmulps %ymm5,%ymm8,%ymm2 + .byte 197,236,88,201 // vaddps %ymm1,%ymm2,%ymm1 + .byte 196,193,116,88,205 // vaddps %ymm13,%ymm1,%ymm1 + .byte 196,193,44,89,214 // vmulps %ymm14,%ymm10,%ymm2 + .byte 197,60,89,214 // vmulps %ymm6,%ymm8,%ymm10 + .byte 197,172,88,210 // vaddps %ymm2,%ymm10,%ymm2 + .byte 196,193,108,88,209 // vaddps %ymm9,%ymm2,%ymm2 + .byte 197,60,89,199 // vmulps %ymm7,%ymm8,%ymm8 + .byte 197,188,88,219 // vaddps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_0_avx +.globl _sk_clamp_0_avx +_sk_clamp_0_avx: + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 196,193,124,95,192 // vmaxps %ymm8,%ymm0,%ymm0 + .byte 196,193,116,95,200 // vmaxps %ymm8,%ymm1,%ymm1 + .byte 196,193,108,95,208 // vmaxps %ymm8,%ymm2,%ymm2 + .byte 196,193,100,95,216 // vmaxps %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_1_avx +.globl _sk_clamp_1_avx +_sk_clamp_1_avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 196,193,124,93,192 // vminps %ymm8,%ymm0,%ymm0 + .byte 196,193,116,93,200 // vminps %ymm8,%ymm1,%ymm1 + .byte 196,193,108,93,208 // vminps %ymm8,%ymm2,%ymm2 + .byte 196,193,100,93,216 // vminps %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_a_avx +.globl _sk_clamp_a_avx +_sk_clamp_a_avx: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 196,193,100,93,216 // vminps %ymm8,%ymm3,%ymm3 + .byte 197,252,93,195 // vminps %ymm3,%ymm0,%ymm0 + .byte 197,244,93,203 // vminps %ymm3,%ymm1,%ymm1 + .byte 197,236,93,211 // vminps %ymm3,%ymm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_set_rgb_avx +.globl _sk_set_rgb_avx +_sk_set_rgb_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,226,125,24,0 // vbroadcastss (%rax),%ymm0 + .byte 196,226,125,24,72,4 // vbroadcastss 0x4(%rax),%ymm1 + .byte 196,226,125,24,80,8 // vbroadcastss 0x8(%rax),%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_swap_rb_avx +.globl _sk_swap_rb_avx +_sk_swap_rb_avx: + .byte 197,124,40,192 // vmovaps %ymm0,%ymm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,194 // vmovaps %ymm2,%ymm0 + .byte 197,124,41,194 // vmovaps %ymm8,%ymm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_swap_avx +.globl _sk_swap_avx +_sk_swap_avx: + .byte 197,124,40,195 // vmovaps %ymm3,%ymm8 + .byte 197,124,40,202 // vmovaps %ymm2,%ymm9 + .byte 197,124,40,209 // vmovaps %ymm1,%ymm10 + .byte 197,124,40,216 // vmovaps %ymm0,%ymm11 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,196 // vmovaps %ymm4,%ymm0 + .byte 197,252,40,205 // vmovaps %ymm5,%ymm1 + .byte 197,252,40,214 // vmovaps %ymm6,%ymm2 + .byte 197,252,40,223 // vmovaps %ymm7,%ymm3 + .byte 197,124,41,220 // vmovaps %ymm11,%ymm4 + .byte 197,124,41,213 // vmovaps %ymm10,%ymm5 + .byte 197,124,41,206 // vmovaps %ymm9,%ymm6 + .byte 197,124,41,199 // vmovaps %ymm8,%ymm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_move_src_dst_avx +.globl _sk_move_src_dst_avx +_sk_move_src_dst_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,224 // vmovaps %ymm0,%ymm4 + .byte 197,252,40,233 // vmovaps %ymm1,%ymm5 + .byte 197,252,40,242 // vmovaps %ymm2,%ymm6 + .byte 197,252,40,251 // vmovaps %ymm3,%ymm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_move_dst_src_avx +.globl _sk_move_dst_src_avx +_sk_move_dst_src_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,196 // vmovaps %ymm4,%ymm0 + .byte 197,252,40,205 // vmovaps %ymm5,%ymm1 + .byte 197,252,40,214 // vmovaps %ymm6,%ymm2 + .byte 197,252,40,223 // vmovaps %ymm7,%ymm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_premul_avx +.globl _sk_premul_avx +_sk_premul_avx: + .byte 197,252,89,195 // vmulps %ymm3,%ymm0,%ymm0 + .byte 197,244,89,203 // vmulps %ymm3,%ymm1,%ymm1 + .byte 197,236,89,211 // vmulps %ymm3,%ymm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_unpremul_avx +.globl _sk_unpremul_avx +_sk_unpremul_avx: + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 196,65,100,194,200,0 // vcmpeqps %ymm8,%ymm3,%ymm9 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,208 // vmovd %eax,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 197,44,94,211 // vdivps %ymm3,%ymm10,%ymm10 + .byte 196,67,45,74,192,144 // vblendvps %ymm9,%ymm8,%ymm10,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_from_srgb_avx +.globl _sk_from_srgb_avx +_sk_from_srgb_avx: + .byte 184,145,131,158,61 // mov $0x3d9e8391,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 197,124,89,208 // vmulps %ymm0,%ymm0,%ymm10 + .byte 184,154,153,153,62 // mov $0x3e99999a,%eax + .byte 197,121,110,216 // vmovd %eax,%xmm11 + .byte 196,67,121,4,219,0 // vpermilps $0x0,%xmm11,%xmm11 + .byte 196,67,37,24,219,1 // vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + .byte 184,92,143,50,63 // mov $0x3f328f5c,%eax + .byte 197,121,110,224 // vmovd %eax,%xmm12 + .byte 196,67,121,4,228,0 // vpermilps $0x0,%xmm12,%xmm12 + .byte 196,67,29,24,228,1 // vinsertf128 $0x1,%xmm12,%ymm12,%ymm12 + .byte 197,36,89,232 // vmulps %ymm0,%ymm11,%ymm13 + .byte 196,65,20,88,236 // vaddps %ymm12,%ymm13,%ymm13 + .byte 184,10,215,35,59 // mov $0x3b23d70a,%eax + .byte 197,121,110,240 // vmovd %eax,%xmm14 + .byte 196,67,121,4,246,0 // vpermilps $0x0,%xmm14,%xmm14 + .byte 196,67,13,24,246,1 // vinsertf128 $0x1,%xmm14,%ymm14,%ymm14 + .byte 196,65,44,89,213 // vmulps %ymm13,%ymm10,%ymm10 + .byte 196,65,12,88,210 // vaddps %ymm10,%ymm14,%ymm10 + .byte 184,174,71,97,61 // mov $0x3d6147ae,%eax + .byte 197,121,110,232 // vmovd %eax,%xmm13 + .byte 196,67,121,4,237,0 // vpermilps $0x0,%xmm13,%xmm13 + .byte 196,67,21,24,237,1 // vinsertf128 $0x1,%xmm13,%ymm13,%ymm13 + .byte 196,193,124,194,197,1 // vcmpltps %ymm13,%ymm0,%ymm0 + .byte 196,195,45,74,193,0 // vblendvps %ymm0,%ymm9,%ymm10,%ymm0 + .byte 197,60,89,201 // vmulps %ymm1,%ymm8,%ymm9 + .byte 197,116,89,209 // vmulps %ymm1,%ymm1,%ymm10 + .byte 197,36,89,249 // vmulps %ymm1,%ymm11,%ymm15 + .byte 196,65,28,88,255 // vaddps %ymm15,%ymm12,%ymm15 + .byte 196,65,44,89,215 // vmulps %ymm15,%ymm10,%ymm10 + .byte 196,65,12,88,210 // vaddps %ymm10,%ymm14,%ymm10 + .byte 196,193,116,194,205,1 // vcmpltps %ymm13,%ymm1,%ymm1 + .byte 196,195,45,74,201,16 // vblendvps %ymm1,%ymm9,%ymm10,%ymm1 + .byte 197,60,89,194 // vmulps %ymm2,%ymm8,%ymm8 + .byte 197,108,89,202 // vmulps %ymm2,%ymm2,%ymm9 + .byte 197,36,89,210 // vmulps %ymm2,%ymm11,%ymm10 + .byte 196,65,28,88,210 // vaddps %ymm10,%ymm12,%ymm10 + .byte 196,65,52,89,202 // vmulps %ymm10,%ymm9,%ymm9 + .byte 196,65,12,88,201 // vaddps %ymm9,%ymm14,%ymm9 + .byte 196,193,108,194,213,1 // vcmpltps %ymm13,%ymm2,%ymm2 + .byte 196,195,53,74,208,32 // vblendvps %ymm2,%ymm8,%ymm9,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_to_srgb_avx +.globl _sk_to_srgb_avx +_sk_to_srgb_avx: + .byte 197,124,82,192 // vrsqrtps %ymm0,%ymm8 + .byte 196,65,124,83,232 // vrcpps %ymm8,%ymm13 + .byte 196,65,124,82,240 // vrsqrtps %ymm8,%ymm14 + .byte 184,41,92,71,65 // mov $0x41475c29,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,89,224 // vmulps %ymm0,%ymm8,%ymm12 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 196,67,121,4,201,0 // vpermilps $0x0,%xmm9,%xmm9 + .byte 196,67,53,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + .byte 184,194,135,210,62 // mov $0x3ed287c2,%eax + .byte 197,121,110,208 // vmovd %eax,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 184,206,111,48,63 // mov $0x3f306fce,%eax + .byte 197,121,110,216 // vmovd %eax,%xmm11 + .byte 196,67,121,4,219,0 // vpermilps $0x0,%xmm11,%xmm11 + .byte 196,67,37,24,219,1 // vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + .byte 184,168,87,202,61 // mov $0x3dca57a8,%eax + .byte 53,0,0,0,128 // xor $0x80000000,%eax + .byte 197,121,110,248 // vmovd %eax,%xmm15 + .byte 196,67,121,4,255,0 // vpermilps $0x0,%xmm15,%xmm15 + .byte 196,67,5,24,255,1 // vinsertf128 $0x1,%xmm15,%ymm15,%ymm15 + .byte 196,65,20,89,235 // vmulps %ymm11,%ymm13,%ymm13 + .byte 196,65,20,88,239 // vaddps %ymm15,%ymm13,%ymm13 + .byte 196,65,12,89,242 // vmulps %ymm10,%ymm14,%ymm14 + .byte 196,65,12,88,237 // vaddps %ymm13,%ymm14,%ymm13 + .byte 196,65,52,93,237 // vminps %ymm13,%ymm9,%ymm13 + .byte 184,4,231,140,59 // mov $0x3b8ce704,%eax + .byte 197,121,110,240 // vmovd %eax,%xmm14 + .byte 196,67,121,4,246,0 // vpermilps $0x0,%xmm14,%xmm14 + .byte 196,67,13,24,246,1 // vinsertf128 $0x1,%xmm14,%ymm14,%ymm14 + .byte 196,193,124,194,198,1 // vcmpltps %ymm14,%ymm0,%ymm0 + .byte 196,195,21,74,196,0 // vblendvps %ymm0,%ymm12,%ymm13,%ymm0 + .byte 197,124,82,225 // vrsqrtps %ymm1,%ymm12 + .byte 196,65,124,83,236 // vrcpps %ymm12,%ymm13 + .byte 196,65,124,82,228 // vrsqrtps %ymm12,%ymm12 + .byte 196,65,36,89,237 // vmulps %ymm13,%ymm11,%ymm13 + .byte 196,65,4,88,237 // vaddps %ymm13,%ymm15,%ymm13 + .byte 196,65,44,89,228 // vmulps %ymm12,%ymm10,%ymm12 + .byte 196,65,28,88,229 // vaddps %ymm13,%ymm12,%ymm12 + .byte 197,60,89,233 // vmulps %ymm1,%ymm8,%ymm13 + .byte 196,65,52,93,228 // vminps %ymm12,%ymm9,%ymm12 + .byte 196,193,116,194,206,1 // vcmpltps %ymm14,%ymm1,%ymm1 + .byte 196,195,29,74,205,16 // vblendvps %ymm1,%ymm13,%ymm12,%ymm1 + .byte 197,124,82,226 // vrsqrtps %ymm2,%ymm12 + .byte 196,65,124,83,236 // vrcpps %ymm12,%ymm13 + .byte 196,65,36,89,221 // vmulps %ymm13,%ymm11,%ymm11 + .byte 196,65,4,88,219 // vaddps %ymm11,%ymm15,%ymm11 + .byte 196,65,124,82,228 // vrsqrtps %ymm12,%ymm12 + .byte 196,65,44,89,212 // vmulps %ymm12,%ymm10,%ymm10 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 196,65,52,93,202 // vminps %ymm10,%ymm9,%ymm9 + .byte 197,60,89,194 // vmulps %ymm2,%ymm8,%ymm8 + .byte 196,193,108,194,214,1 // vcmpltps %ymm14,%ymm2,%ymm2 + .byte 196,195,53,74,208,32 // vblendvps %ymm2,%ymm8,%ymm9,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_from_2dot2_avx +.globl _sk_from_2dot2_avx +_sk_from_2dot2_avx: + .byte 197,124,82,192 // vrsqrtps %ymm0,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,200 // vrsqrtps %ymm8,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 197,252,89,192 // vmulps %ymm0,%ymm0,%ymm0 + .byte 196,65,60,89,208 // vmulps %ymm8,%ymm8,%ymm10 + .byte 196,65,60,89,194 // vmulps %ymm10,%ymm8,%ymm8 + .byte 196,193,124,89,192 // vmulps %ymm8,%ymm0,%ymm0 + .byte 197,180,89,192 // vmulps %ymm0,%ymm9,%ymm0 + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 196,193,124,95,192 // vmaxps %ymm8,%ymm0,%ymm0 + .byte 197,124,82,201 // vrsqrtps %ymm1,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,209 // vrsqrtps %ymm9,%ymm10 + .byte 196,65,124,82,210 // vrsqrtps %ymm10,%ymm10 + .byte 197,244,89,201 // vmulps %ymm1,%ymm1,%ymm1 + .byte 196,65,52,89,217 // vmulps %ymm9,%ymm9,%ymm11 + .byte 196,65,52,89,203 // vmulps %ymm11,%ymm9,%ymm9 + .byte 196,193,116,89,201 // vmulps %ymm9,%ymm1,%ymm1 + .byte 197,172,89,201 // vmulps %ymm1,%ymm10,%ymm1 + .byte 196,193,116,95,200 // vmaxps %ymm8,%ymm1,%ymm1 + .byte 197,124,82,202 // vrsqrtps %ymm2,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,209 // vrsqrtps %ymm9,%ymm10 + .byte 196,65,124,82,210 // vrsqrtps %ymm10,%ymm10 + .byte 197,236,89,210 // vmulps %ymm2,%ymm2,%ymm2 + .byte 196,65,52,89,217 // vmulps %ymm9,%ymm9,%ymm11 + .byte 196,65,52,89,203 // vmulps %ymm11,%ymm9,%ymm9 + .byte 196,193,108,89,209 // vmulps %ymm9,%ymm2,%ymm2 + .byte 197,172,89,210 // vmulps %ymm2,%ymm10,%ymm2 + .byte 196,193,108,95,208 // vmaxps %ymm8,%ymm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_to_2dot2_avx +.globl _sk_to_2dot2_avx +_sk_to_2dot2_avx: + .byte 197,252,82,192 // vrsqrtps %ymm0,%ymm0 + .byte 197,124,82,192 // vrsqrtps %ymm0,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,192 // vrsqrtps %ymm8,%ymm8 + .byte 196,65,124,82,200 // vrsqrtps %ymm8,%ymm9 + .byte 197,252,83,192 // vrcpps %ymm0,%ymm0 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 196,65,124,83,193 // vrcpps %ymm9,%ymm8 + .byte 196,193,124,89,192 // vmulps %ymm8,%ymm0,%ymm0 + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 196,193,124,95,192 // vmaxps %ymm8,%ymm0,%ymm0 + .byte 197,252,82,201 // vrsqrtps %ymm1,%ymm1 + .byte 197,124,82,201 // vrsqrtps %ymm1,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,209 // vrsqrtps %ymm9,%ymm10 + .byte 197,252,83,201 // vrcpps %ymm1,%ymm1 + .byte 197,180,89,201 // vmulps %ymm1,%ymm9,%ymm1 + .byte 196,65,124,83,202 // vrcpps %ymm10,%ymm9 + .byte 196,193,116,89,201 // vmulps %ymm9,%ymm1,%ymm1 + .byte 196,193,116,95,200 // vmaxps %ymm8,%ymm1,%ymm1 + .byte 197,252,82,210 // vrsqrtps %ymm2,%ymm2 + .byte 197,124,82,202 // vrsqrtps %ymm2,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,201 // vrsqrtps %ymm9,%ymm9 + .byte 196,65,124,82,209 // vrsqrtps %ymm9,%ymm10 + .byte 197,252,83,210 // vrcpps %ymm2,%ymm2 + .byte 197,180,89,210 // vmulps %ymm2,%ymm9,%ymm2 + .byte 196,65,124,83,202 // vrcpps %ymm10,%ymm9 + .byte 196,193,108,89,209 // vmulps %ymm9,%ymm2,%ymm2 + .byte 196,193,108,95,208 // vmaxps %ymm8,%ymm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_rgb_to_hsl_avx +.globl _sk_rgb_to_hsl_avx +_sk_rgb_to_hsl_avx: + .byte 197,124,95,193 // vmaxps %ymm1,%ymm0,%ymm8 + .byte 197,60,95,194 // vmaxps %ymm2,%ymm8,%ymm8 + .byte 197,124,93,201 // vminps %ymm1,%ymm0,%ymm9 + .byte 197,52,93,202 // vminps %ymm2,%ymm9,%ymm9 + .byte 196,65,60,92,209 // vsubps %ymm9,%ymm8,%ymm10 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,121,110,216 // vmovd %eax,%xmm11 + .byte 196,67,121,4,219,0 // vpermilps $0x0,%xmm11,%xmm11 + .byte 196,67,37,24,219,1 // vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + .byte 196,65,36,94,218 // vdivps %ymm10,%ymm11,%ymm11 + .byte 65,184,171,170,42,62 // mov $0x3e2aaaab,%r8d + .byte 197,116,92,226 // vsubps %ymm2,%ymm1,%ymm12 + .byte 196,65,28,89,227 // vmulps %ymm11,%ymm12,%ymm12 + .byte 65,185,0,0,192,64 // mov $0x40c00000,%r9d + .byte 197,108,92,232 // vsubps %ymm0,%ymm2,%ymm13 + .byte 196,65,20,89,235 // vmulps %ymm11,%ymm13,%ymm13 + .byte 65,186,0,0,0,64 // mov $0x40000000,%r10d + .byte 197,124,92,241 // vsubps %ymm1,%ymm0,%ymm14 + .byte 196,65,12,89,219 // vmulps %ymm11,%ymm14,%ymm11 + .byte 184,0,0,128,64 // mov $0x40800000,%eax + .byte 197,121,110,240 // vmovd %eax,%xmm14 + .byte 196,67,121,4,246,0 // vpermilps $0x0,%xmm14,%xmm14 + .byte 196,67,13,24,246,1 // vinsertf128 $0x1,%xmm14,%ymm14,%ymm14 + .byte 196,65,36,88,222 // vaddps %ymm14,%ymm11,%ymm11 + .byte 196,65,121,110,242 // vmovd %r10d,%xmm14 + .byte 197,244,194,210,1 // vcmpltps %ymm2,%ymm1,%ymm2 + .byte 197,188,194,201,0 // vcmpeqps %ymm1,%ymm8,%ymm1 + .byte 196,67,121,4,246,0 // vpermilps $0x0,%xmm14,%xmm14 + .byte 196,67,13,24,246,1 // vinsertf128 $0x1,%xmm14,%ymm14,%ymm14 + .byte 196,65,20,88,238 // vaddps %ymm14,%ymm13,%ymm13 + .byte 196,67,37,74,221,16 // vblendvps %ymm1,%ymm13,%ymm11,%ymm11 + .byte 196,193,121,110,201 // vmovd %r9d,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 196,65,20,87,237 // vxorps %ymm13,%ymm13,%ymm13 + .byte 196,227,21,74,201,32 // vblendvps %ymm2,%ymm1,%ymm13,%ymm1 + .byte 196,193,116,88,204 // vaddps %ymm12,%ymm1,%ymm1 + .byte 184,0,0,0,63 // mov $0x3f000000,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 197,188,194,192,0 // vcmpeqps %ymm0,%ymm8,%ymm0 + .byte 196,227,37,74,193,0 // vblendvps %ymm0,%ymm1,%ymm11,%ymm0 + .byte 196,193,60,88,201 // vaddps %ymm9,%ymm8,%ymm1 + .byte 196,227,121,4,210,0 // vpermilps $0x0,%xmm2,%xmm2 + .byte 196,99,109,24,218,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm11 + .byte 196,193,116,89,211 // vmulps %ymm11,%ymm1,%ymm2 + .byte 197,36,194,218,1 // vcmpltps %ymm2,%ymm11,%ymm11 + .byte 196,65,12,92,224 // vsubps %ymm8,%ymm14,%ymm12 + .byte 196,65,28,92,225 // vsubps %ymm9,%ymm12,%ymm12 + .byte 196,195,117,74,204,176 // vblendvps %ymm11,%ymm12,%ymm1,%ymm1 + .byte 196,65,60,194,193,0 // vcmpeqps %ymm9,%ymm8,%ymm8 + .byte 197,172,94,201 // vdivps %ymm1,%ymm10,%ymm1 + .byte 196,67,125,74,205,128 // vblendvps %ymm8,%ymm13,%ymm0,%ymm9 + .byte 196,195,117,74,205,128 // vblendvps %ymm8,%ymm13,%ymm1,%ymm1 + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 196,193,124,89,193 // vmulps %ymm9,%ymm0,%ymm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_hsl_to_rgb_avx +.globl _sk_hsl_to_rgb_avx +_sk_hsl_to_rgb_avx: + .byte 72,131,236,56 // sub $0x38,%rsp + .byte 197,252,17,60,36 // vmovups %ymm7,(%rsp) + .byte 197,252,17,116,36,224 // vmovups %ymm6,-0x20(%rsp) + .byte 197,252,17,108,36,192 // vmovups %ymm5,-0x40(%rsp) + .byte 197,252,17,100,36,160 // vmovups %ymm4,-0x60(%rsp) + .byte 197,252,17,92,36,128 // vmovups %ymm3,-0x80(%rsp) + .byte 197,252,40,226 // vmovaps %ymm2,%ymm4 + .byte 197,252,40,233 // vmovaps %ymm1,%ymm5 + .byte 197,252,40,216 // vmovaps %ymm0,%ymm3 + .byte 184,0,0,0,63 // mov $0x3f000000,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,99,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm8 + .byte 196,193,92,194,192,1 // vcmpltps %ymm8,%ymm4,%ymm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,227,121,4,210,0 // vpermilps $0x0,%xmm2,%xmm2 + .byte 196,99,109,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm10 + .byte 197,172,88,213 // vaddps %ymm5,%ymm10,%ymm2 + .byte 197,236,89,212 // vmulps %ymm4,%ymm2,%ymm2 + .byte 197,84,88,204 // vaddps %ymm4,%ymm5,%ymm9 + .byte 197,84,89,220 // vmulps %ymm4,%ymm5,%ymm11 + .byte 196,65,52,92,203 // vsubps %ymm11,%ymm9,%ymm9 + .byte 196,99,53,74,202,0 // vblendvps %ymm0,%ymm2,%ymm9,%ymm9 + .byte 65,184,0,0,0,64 // mov $0x40000000,%r8d + .byte 184,171,170,170,62 // mov $0x3eaaaaab,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,99,125,24,224,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm12 + .byte 197,28,88,251 // vaddps %ymm3,%ymm12,%ymm15 + .byte 184,0,0,0,0 // mov $0x0,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,99,125,24,232,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm13 + .byte 196,193,44,194,199,1 // vcmpltps %ymm15,%ymm10,%ymm0 + .byte 196,193,4,92,210 // vsubps %ymm10,%ymm15,%ymm2 + .byte 196,227,5,74,194,0 // vblendvps %ymm0,%ymm2,%ymm15,%ymm0 + .byte 196,193,4,194,213,1 // vcmpltps %ymm13,%ymm15,%ymm2 + .byte 196,65,44,88,223 // vaddps %ymm15,%ymm10,%ymm11 + .byte 196,195,125,74,203,32 // vblendvps %ymm2,%ymm11,%ymm0,%ymm1 + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,252,89,196 // vmulps %ymm4,%ymm0,%ymm0 + .byte 196,65,124,92,217 // vsubps %ymm9,%ymm0,%ymm11 + .byte 65,184,171,170,42,62 // mov $0x3e2aaaab,%r8d + .byte 184,0,0,192,64 // mov $0x40c00000,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 196,193,52,92,211 // vsubps %ymm11,%ymm9,%ymm2 + .byte 197,108,89,240 // vmulps %ymm0,%ymm2,%ymm14 + .byte 184,171,170,42,63 // mov $0x3f2aaaab,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,252,92,209 // vsubps %ymm1,%ymm0,%ymm2 + .byte 197,140,89,210 // vmulps %ymm2,%ymm14,%ymm2 + .byte 197,164,88,210 // vaddps %ymm2,%ymm11,%ymm2 + .byte 197,244,194,248,1 // vcmpltps %ymm0,%ymm1,%ymm7 + .byte 196,227,37,74,210,112 // vblendvps %ymm7,%ymm2,%ymm11,%ymm2 + .byte 196,193,116,194,248,1 // vcmpltps %ymm8,%ymm1,%ymm7 + .byte 196,195,109,74,249,112 // vblendvps %ymm7,%ymm9,%ymm2,%ymm7 + .byte 196,193,121,110,208 // vmovd %r8d,%xmm2 + .byte 196,227,121,4,210,0 // vpermilps $0x0,%xmm2,%xmm2 + .byte 196,227,109,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + .byte 197,244,194,202,1 // vcmpltps %ymm2,%ymm1,%ymm1 + .byte 196,65,4,89,254 // vmulps %ymm14,%ymm15,%ymm15 + .byte 196,65,36,88,255 // vaddps %ymm15,%ymm11,%ymm15 + .byte 196,67,69,74,255,16 // vblendvps %ymm1,%ymm15,%ymm7,%ymm15 + .byte 197,172,194,203,1 // vcmpltps %ymm3,%ymm10,%ymm1 + .byte 196,193,100,92,250 // vsubps %ymm10,%ymm3,%ymm7 + .byte 196,227,101,74,207,16 // vblendvps %ymm1,%ymm7,%ymm3,%ymm1 + .byte 196,193,100,194,253,1 // vcmpltps %ymm13,%ymm3,%ymm7 + .byte 197,172,88,243 // vaddps %ymm3,%ymm10,%ymm6 + .byte 196,227,117,74,206,112 // vblendvps %ymm7,%ymm6,%ymm1,%ymm1 + .byte 197,252,92,241 // vsubps %ymm1,%ymm0,%ymm6 + .byte 197,140,89,246 // vmulps %ymm6,%ymm14,%ymm6 + .byte 197,164,88,246 // vaddps %ymm6,%ymm11,%ymm6 + .byte 197,244,194,248,1 // vcmpltps %ymm0,%ymm1,%ymm7 + .byte 196,227,37,74,246,112 // vblendvps %ymm7,%ymm6,%ymm11,%ymm6 + .byte 196,193,116,194,248,1 // vcmpltps %ymm8,%ymm1,%ymm7 + .byte 196,195,77,74,241,112 // vblendvps %ymm7,%ymm9,%ymm6,%ymm6 + .byte 197,244,194,202,1 // vcmpltps %ymm2,%ymm1,%ymm1 + .byte 197,140,89,251 // vmulps %ymm3,%ymm14,%ymm7 + .byte 197,164,88,255 // vaddps %ymm7,%ymm11,%ymm7 + .byte 196,227,77,74,207,16 // vblendvps %ymm1,%ymm7,%ymm6,%ymm1 + .byte 196,193,100,92,220 // vsubps %ymm12,%ymm3,%ymm3 + .byte 197,172,194,243,1 // vcmpltps %ymm3,%ymm10,%ymm6 + .byte 196,193,100,92,250 // vsubps %ymm10,%ymm3,%ymm7 + .byte 196,227,101,74,247,96 // vblendvps %ymm6,%ymm7,%ymm3,%ymm6 + .byte 196,193,100,194,253,1 // vcmpltps %ymm13,%ymm3,%ymm7 + .byte 197,44,88,211 // vaddps %ymm3,%ymm10,%ymm10 + .byte 196,195,77,74,242,112 // vblendvps %ymm7,%ymm10,%ymm6,%ymm6 + .byte 197,204,194,248,1 // vcmpltps %ymm0,%ymm6,%ymm7 + .byte 197,252,92,198 // vsubps %ymm6,%ymm0,%ymm0 + .byte 197,140,89,192 // vmulps %ymm0,%ymm14,%ymm0 + .byte 197,164,88,192 // vaddps %ymm0,%ymm11,%ymm0 + .byte 196,227,37,74,192,112 // vblendvps %ymm7,%ymm0,%ymm11,%ymm0 + .byte 196,193,76,194,248,1 // vcmpltps %ymm8,%ymm6,%ymm7 + .byte 196,195,125,74,193,112 // vblendvps %ymm7,%ymm9,%ymm0,%ymm0 + .byte 197,204,194,210,1 // vcmpltps %ymm2,%ymm6,%ymm2 + .byte 196,193,100,89,222 // vmulps %ymm14,%ymm3,%ymm3 + .byte 197,164,88,219 // vaddps %ymm3,%ymm11,%ymm3 + .byte 196,227,125,74,211,32 // vblendvps %ymm2,%ymm3,%ymm0,%ymm2 + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,212,194,216,0 // vcmpeqps %ymm0,%ymm5,%ymm3 + .byte 196,227,5,74,196,48 // vblendvps %ymm3,%ymm4,%ymm15,%ymm0 + .byte 196,227,117,74,204,48 // vblendvps %ymm3,%ymm4,%ymm1,%ymm1 + .byte 196,227,109,74,212,48 // vblendvps %ymm3,%ymm4,%ymm2,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,16,92,36,128 // vmovups -0x80(%rsp),%ymm3 + .byte 197,252,16,100,36,160 // vmovups -0x60(%rsp),%ymm4 + .byte 197,252,16,108,36,192 // vmovups -0x40(%rsp),%ymm5 + .byte 197,252,16,116,36,224 // vmovups -0x20(%rsp),%ymm6 + .byte 197,252,16,60,36 // vmovups (%rsp),%ymm7 + .byte 72,131,196,56 // add $0x38,%rsp + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_scale_1_float_avx +.globl _sk_scale_1_float_avx +_sk_scale_1_float_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_scale_u8_avx +.globl _sk_scale_u8_avx +_sk_scale_u8_avx: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,1,248 // add %rdi,%rax + .byte 77,133,192 // test %r8,%r8 + .byte 117,80 // jne 1456 <_sk_scale_u8_avx+0x60> + .byte 197,122,126,0 // vmovq (%rax),%xmm8 + .byte 196,66,121,49,200 // vpmovzxbd %xmm8,%xmm9 + .byte 196,67,121,4,192,229 // vpermilps $0xe5,%xmm8,%xmm8 + .byte 196,66,121,49,192 // vpmovzxbd %xmm8,%xmm8 + .byte 196,67,53,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm9,%ymm8 + .byte 196,65,124,91,192 // vcvtdq2ps %ymm8,%ymm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 196,67,121,4,201,0 // vpermilps $0x0,%xmm9,%xmm9 + .byte 196,67,53,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + .byte 196,65,60,89,193 // vmulps %ymm9,%ymm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,137,193 // mov %r8,%rcx + .byte 255,224 // jmpq *%rax + .byte 49,201 // xor %ecx,%ecx + .byte 77,137,194 // mov %r8,%r10 + .byte 69,49,201 // xor %r9d,%r9d + .byte 68,15,182,24 // movzbl (%rax),%r11d + .byte 72,255,192 // inc %rax + .byte 73,211,227 // shl %cl,%r11 + .byte 77,9,217 // or %r11,%r9 + .byte 72,131,193,8 // add $0x8,%rcx + .byte 73,255,202 // dec %r10 + .byte 117,234 // jne 145e <_sk_scale_u8_avx+0x68> + .byte 196,65,249,110,193 // vmovq %r9,%xmm8 + .byte 235,143 // jmp 140a <_sk_scale_u8_avx+0x14> + +HIDDEN _sk_lerp_1_float_avx +.globl _sk_lerp_1_float_avx +_sk_lerp_1_float_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 197,252,92,196 // vsubps %ymm4,%ymm0,%ymm0 + .byte 196,193,124,89,192 // vmulps %ymm8,%ymm0,%ymm0 + .byte 197,252,88,196 // vaddps %ymm4,%ymm0,%ymm0 + .byte 197,244,92,205 // vsubps %ymm5,%ymm1,%ymm1 + .byte 196,193,116,89,200 // vmulps %ymm8,%ymm1,%ymm1 + .byte 197,244,88,205 // vaddps %ymm5,%ymm1,%ymm1 + .byte 197,236,92,214 // vsubps %ymm6,%ymm2,%ymm2 + .byte 196,193,108,89,208 // vmulps %ymm8,%ymm2,%ymm2 + .byte 197,236,88,214 // vaddps %ymm6,%ymm2,%ymm2 + .byte 197,228,92,223 // vsubps %ymm7,%ymm3,%ymm3 + .byte 196,193,100,89,216 // vmulps %ymm8,%ymm3,%ymm3 + .byte 197,228,88,223 // vaddps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lerp_u8_avx +.globl _sk_lerp_u8_avx +_sk_lerp_u8_avx: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,1,248 // add %rdi,%rax + .byte 77,133,192 // test %r8,%r8 + .byte 117,116 // jne 153e <_sk_lerp_u8_avx+0x84> + .byte 197,122,126,0 // vmovq (%rax),%xmm8 + .byte 196,66,121,49,200 // vpmovzxbd %xmm8,%xmm9 + .byte 196,67,121,4,192,229 // vpermilps $0xe5,%xmm8,%xmm8 + .byte 196,66,121,49,192 // vpmovzxbd %xmm8,%xmm8 + .byte 196,67,53,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm9,%ymm8 + .byte 196,65,124,91,192 // vcvtdq2ps %ymm8,%ymm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,121,110,200 // vmovd %eax,%xmm9 + .byte 196,67,121,4,201,0 // vpermilps $0x0,%xmm9,%xmm9 + .byte 196,67,53,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + .byte 196,65,60,89,193 // vmulps %ymm9,%ymm8,%ymm8 + .byte 197,252,92,196 // vsubps %ymm4,%ymm0,%ymm0 + .byte 196,193,124,89,192 // vmulps %ymm8,%ymm0,%ymm0 + .byte 197,252,88,196 // vaddps %ymm4,%ymm0,%ymm0 + .byte 197,244,92,205 // vsubps %ymm5,%ymm1,%ymm1 + .byte 196,193,116,89,200 // vmulps %ymm8,%ymm1,%ymm1 + .byte 197,244,88,205 // vaddps %ymm5,%ymm1,%ymm1 + .byte 197,236,92,214 // vsubps %ymm6,%ymm2,%ymm2 + .byte 196,193,108,89,208 // vmulps %ymm8,%ymm2,%ymm2 + .byte 197,236,88,214 // vaddps %ymm6,%ymm2,%ymm2 + .byte 197,228,92,223 // vsubps %ymm7,%ymm3,%ymm3 + .byte 196,193,100,89,216 // vmulps %ymm8,%ymm3,%ymm3 + .byte 197,228,88,223 // vaddps %ymm7,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,137,193 // mov %r8,%rcx + .byte 255,224 // jmpq *%rax + .byte 49,201 // xor %ecx,%ecx + .byte 77,137,194 // mov %r8,%r10 + .byte 69,49,201 // xor %r9d,%r9d + .byte 68,15,182,24 // movzbl (%rax),%r11d + .byte 72,255,192 // inc %rax + .byte 73,211,227 // shl %cl,%r11 + .byte 77,9,217 // or %r11,%r9 + .byte 72,131,193,8 // add $0x8,%rcx + .byte 73,255,202 // dec %r10 + .byte 117,234 // jne 1546 <_sk_lerp_u8_avx+0x8c> + .byte 196,65,249,110,193 // vmovq %r9,%xmm8 + .byte 233,104,255,255,255 // jmpq 14ce <_sk_lerp_u8_avx+0x14> + +HIDDEN _sk_lerp_565_avx +.globl _sk_lerp_565_avx +_sk_lerp_565_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,16 // mov (%rax),%r10 + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,250,0,0,0 // jne 166e <_sk_lerp_565_avx+0x108> + .byte 196,65,122,111,4,122 // vmovdqu (%r10,%rdi,2),%xmm8 + .byte 197,225,239,219 // vpxor %xmm3,%xmm3,%xmm3 + .byte 197,185,105,219 // vpunpckhwd %xmm3,%xmm8,%xmm3 + .byte 196,66,121,51,192 // vpmovzxwd %xmm8,%xmm8 + .byte 196,99,61,24,195,1 // vinsertf128 $0x1,%xmm3,%ymm8,%ymm8 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 197,249,112,219,0 // vpshufd $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 196,193,100,84,216 // vandps %ymm8,%ymm3,%ymm3 + .byte 197,124,91,203 // vcvtdq2ps %ymm3,%ymm9 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,52,89,203 // vmulps %ymm3,%ymm9,%ymm9 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 197,249,112,219,0 // vpshufd $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 196,193,100,84,216 // vandps %ymm8,%ymm3,%ymm3 + .byte 197,124,91,211 // vcvtdq2ps %ymm3,%ymm10 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,44,89,211 // vmulps %ymm3,%ymm10,%ymm10 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 197,249,112,219,0 // vpshufd $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 196,193,100,84,216 // vandps %ymm8,%ymm3,%ymm3 + .byte 197,124,91,195 // vcvtdq2ps %ymm3,%ymm8 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 197,252,92,196 // vsubps %ymm4,%ymm0,%ymm0 + .byte 196,193,124,89,193 // vmulps %ymm9,%ymm0,%ymm0 + .byte 197,252,88,196 // vaddps %ymm4,%ymm0,%ymm0 + .byte 197,244,92,205 // vsubps %ymm5,%ymm1,%ymm1 + .byte 196,193,116,89,202 // vmulps %ymm10,%ymm1,%ymm1 + .byte 197,244,88,205 // vaddps %ymm5,%ymm1,%ymm1 + .byte 197,236,92,214 // vsubps %ymm6,%ymm2,%ymm2 + .byte 197,236,89,211 // vmulps %ymm3,%ymm2,%ymm2 + .byte 197,236,88,214 // vaddps %ymm6,%ymm2,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 196,65,57,239,192 // vpxor %xmm8,%xmm8,%xmm8 + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 15,135,243,254,255,255 // ja 157a <_sk_lerp_565_avx+0x14> + .byte 69,15,182,192 // movzbl %r8b,%r8d + .byte 76,141,13,74,0,0,0 // lea 0x4a(%rip),%r9 # 16dc <_sk_lerp_565_avx+0x176> + .byte 75,99,4,129 // movslq (%r9,%r8,4),%rax + .byte 76,1,200 // add %r9,%rax + .byte 255,224 // jmpq *%rax + .byte 197,225,239,219 // vpxor %xmm3,%xmm3,%xmm3 + .byte 196,65,97,196,68,122,12,6 // vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm3,%xmm8 + .byte 196,65,57,196,68,122,10,5 // vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm8,%xmm8 + .byte 196,65,57,196,68,122,8,4 // vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm8,%xmm8 + .byte 196,65,57,196,68,122,6,3 // vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm8,%xmm8 + .byte 196,65,57,196,68,122,4,2 // vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm8,%xmm8 + .byte 196,65,57,196,68,122,2,1 // vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm8,%xmm8 + .byte 196,65,57,196,4,122,0 // vpinsrw $0x0,(%r10,%rdi,2),%xmm8,%xmm8 + .byte 233,159,254,255,255 // jmpq 157a <_sk_lerp_565_avx+0x14> + .byte 144 // nop + .byte 243,255 // repz (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 235,255 // jmp 16e1 <_sk_lerp_565_avx+0x17b> + .byte 255 // (bad) + .byte 255,227 // jmpq *%rbx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 219,255 // (bad) + .byte 255 // (bad) + .byte 255,211 // callq *%rbx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,203 // dec %ebx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 191 // .byte 0xbf + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_load_tables_avx +.globl _sk_load_tables_avx +_sk_load_tables_avx: + .byte 85 // push %rbp + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,56,2,0,0 // jne 1948 <_sk_load_tables_avx+0x250> + .byte 196,65,124,16,4,184 // vmovups (%r8,%rdi,4),%ymm8 + .byte 187,255,0,0,0 // mov $0xff,%ebx + .byte 197,249,110,195 // vmovd %ebx,%xmm0 + .byte 197,249,112,192,0 // vpshufd $0x0,%xmm0,%xmm0 + .byte 196,99,125,24,200,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm9 + .byte 196,193,52,84,192 // vandps %ymm8,%ymm9,%ymm0 + .byte 196,193,249,126,193 // vmovq %xmm0,%r9 + .byte 69,137,203 // mov %r9d,%r11d + .byte 196,195,249,22,194,1 // vpextrq $0x1,%xmm0,%r10 + .byte 69,137,214 // mov %r10d,%r14d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 73,193,233,32 // shr $0x20,%r9 + .byte 196,227,125,25,192,1 // vextractf128 $0x1,%ymm0,%xmm0 + .byte 196,193,249,126,196 // vmovq %xmm0,%r12 + .byte 69,137,231 // mov %r12d,%r15d + .byte 196,227,249,22,195,1 // vpextrq $0x1,%xmm0,%rbx + .byte 65,137,221 // mov %ebx,%r13d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 73,193,236,32 // shr $0x20,%r12 + .byte 72,139,104,8 // mov 0x8(%rax),%rbp + .byte 76,139,64,16 // mov 0x10(%rax),%r8 + .byte 196,161,122,16,68,189,0 // vmovss 0x0(%rbp,%r15,4),%xmm0 + .byte 196,163,121,33,68,165,0,16 // vinsertps $0x10,0x0(%rbp,%r12,4),%xmm0,%xmm0 + .byte 196,161,122,16,76,173,0 // vmovss 0x0(%rbp,%r13,4),%xmm1 + .byte 196,227,121,33,193,32 // vinsertps $0x20,%xmm1,%xmm0,%xmm0 + .byte 197,250,16,76,157,0 // vmovss 0x0(%rbp,%rbx,4),%xmm1 + .byte 196,227,121,33,193,48 // vinsertps $0x30,%xmm1,%xmm0,%xmm0 + .byte 196,161,122,16,76,157,0 // vmovss 0x0(%rbp,%r11,4),%xmm1 + .byte 196,163,113,33,76,141,0,16 // vinsertps $0x10,0x0(%rbp,%r9,4),%xmm1,%xmm1 + .byte 196,161,122,16,92,181,0 // vmovss 0x0(%rbp,%r14,4),%xmm3 + .byte 196,227,113,33,203,32 // vinsertps $0x20,%xmm3,%xmm1,%xmm1 + .byte 196,161,122,16,92,149,0 // vmovss 0x0(%rbp,%r10,4),%xmm3 + .byte 196,227,113,33,203,48 // vinsertps $0x30,%xmm3,%xmm1,%xmm1 + .byte 196,227,117,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm1,%ymm0 + .byte 196,193,113,114,208,8 // vpsrld $0x8,%xmm8,%xmm1 + .byte 196,67,125,25,194,1 // vextractf128 $0x1,%ymm8,%xmm10 + .byte 196,193,105,114,210,8 // vpsrld $0x8,%xmm10,%xmm2 + .byte 196,227,117,24,202,1 // vinsertf128 $0x1,%xmm2,%ymm1,%ymm1 + .byte 197,180,84,201 // vandps %ymm1,%ymm9,%ymm1 + .byte 196,193,249,126,201 // vmovq %xmm1,%r9 + .byte 69,137,203 // mov %r9d,%r11d + .byte 196,195,249,22,202,1 // vpextrq $0x1,%xmm1,%r10 + .byte 69,137,214 // mov %r10d,%r14d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 73,193,233,32 // shr $0x20,%r9 + .byte 196,227,125,25,201,1 // vextractf128 $0x1,%ymm1,%xmm1 + .byte 196,225,249,126,205 // vmovq %xmm1,%rbp + .byte 65,137,239 // mov %ebp,%r15d + .byte 196,227,249,22,203,1 // vpextrq $0x1,%xmm1,%rbx + .byte 65,137,220 // mov %ebx,%r12d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,129,122,16,12,184 // vmovss (%r8,%r15,4),%xmm1 + .byte 196,195,113,33,12,168,16 // vinsertps $0x10,(%r8,%rbp,4),%xmm1,%xmm1 + .byte 196,129,122,16,20,160 // vmovss (%r8,%r12,4),%xmm2 + .byte 196,227,113,33,202,32 // vinsertps $0x20,%xmm2,%xmm1,%xmm1 + .byte 196,193,122,16,20,152 // vmovss (%r8,%rbx,4),%xmm2 + .byte 196,227,113,33,202,48 // vinsertps $0x30,%xmm2,%xmm1,%xmm1 + .byte 196,129,122,16,20,152 // vmovss (%r8,%r11,4),%xmm2 + .byte 196,131,105,33,20,136,16 // vinsertps $0x10,(%r8,%r9,4),%xmm2,%xmm2 + .byte 196,129,122,16,28,176 // vmovss (%r8,%r14,4),%xmm3 + .byte 196,227,105,33,211,32 // vinsertps $0x20,%xmm3,%xmm2,%xmm2 + .byte 196,129,122,16,28,144 // vmovss (%r8,%r10,4),%xmm3 + .byte 196,227,105,33,211,48 // vinsertps $0x30,%xmm3,%xmm2,%xmm2 + .byte 196,227,109,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm2,%ymm1 + .byte 72,139,64,24 // mov 0x18(%rax),%rax + .byte 196,193,105,114,208,16 // vpsrld $0x10,%xmm8,%xmm2 + .byte 196,193,97,114,210,16 // vpsrld $0x10,%xmm10,%xmm3 + .byte 196,227,109,24,211,1 // vinsertf128 $0x1,%xmm3,%ymm2,%ymm2 + .byte 197,180,84,210 // vandps %ymm2,%ymm9,%ymm2 + .byte 196,193,249,126,208 // vmovq %xmm2,%r8 + .byte 69,137,194 // mov %r8d,%r10d + .byte 196,195,249,22,209,1 // vpextrq $0x1,%xmm2,%r9 + .byte 69,137,203 // mov %r9d,%r11d + .byte 73,193,233,32 // shr $0x20,%r9 + .byte 73,193,232,32 // shr $0x20,%r8 + .byte 196,227,125,25,210,1 // vextractf128 $0x1,%ymm2,%xmm2 + .byte 196,225,249,126,213 // vmovq %xmm2,%rbp + .byte 65,137,238 // mov %ebp,%r14d + .byte 196,227,249,22,211,1 // vpextrq $0x1,%xmm2,%rbx + .byte 65,137,223 // mov %ebx,%r15d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,161,122,16,20,176 // vmovss (%rax,%r14,4),%xmm2 + .byte 196,227,105,33,20,168,16 // vinsertps $0x10,(%rax,%rbp,4),%xmm2,%xmm2 + .byte 196,161,122,16,28,184 // vmovss (%rax,%r15,4),%xmm3 + .byte 196,227,105,33,211,32 // vinsertps $0x20,%xmm3,%xmm2,%xmm2 + .byte 197,250,16,28,152 // vmovss (%rax,%rbx,4),%xmm3 + .byte 196,99,105,33,203,48 // vinsertps $0x30,%xmm3,%xmm2,%xmm9 + .byte 196,161,122,16,28,144 // vmovss (%rax,%r10,4),%xmm3 + .byte 196,163,97,33,28,128,16 // vinsertps $0x10,(%rax,%r8,4),%xmm3,%xmm3 + .byte 196,161,122,16,20,152 // vmovss (%rax,%r11,4),%xmm2 + .byte 196,227,97,33,210,32 // vinsertps $0x20,%xmm2,%xmm3,%xmm2 + .byte 196,161,122,16,28,136 // vmovss (%rax,%r9,4),%xmm3 + .byte 196,227,105,33,211,48 // vinsertps $0x30,%xmm3,%xmm2,%xmm2 + .byte 196,195,109,24,209,1 // vinsertf128 $0x1,%xmm9,%ymm2,%ymm2 + .byte 196,193,57,114,208,24 // vpsrld $0x18,%xmm8,%xmm8 + .byte 196,193,97,114,210,24 // vpsrld $0x18,%xmm10,%xmm3 + .byte 196,227,61,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + .byte 197,124,91,195 // vcvtdq2ps %ymm3,%ymm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 93 // pop %rbp + .byte 255,224 // jmpq *%rax + .byte 137,203 // mov %ecx,%ebx + .byte 128,227,7 // and $0x7,%bl + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 254,203 // dec %bl + .byte 128,251,6 // cmp $0x6,%bl + .byte 15,135,185,253,255,255 // ja 1716 <_sk_load_tables_avx+0x1e> + .byte 15,182,219 // movzbl %bl,%ebx + .byte 76,141,13,137,0,0,0 // lea 0x89(%rip),%r9 # 19f0 <_sk_load_tables_avx+0x2f8> + .byte 73,99,28,153 // movslq (%r9,%rbx,4),%rbx + .byte 76,1,203 // add %r9,%rbx + .byte 255,227 // jmpq *%rbx + .byte 196,193,121,110,68,184,24 // vmovd 0x18(%r8,%rdi,4),%xmm0 + .byte 197,249,112,192,68 // vpshufd $0x44,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 196,99,117,12,192,64 // vblendps $0x40,%ymm0,%ymm1,%ymm8 + .byte 196,99,125,25,192,1 // vextractf128 $0x1,%ymm8,%xmm0 + .byte 196,195,121,34,68,184,20,1 // vpinsrd $0x1,0x14(%r8,%rdi,4),%xmm0,%xmm0 + .byte 196,99,61,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm8,%ymm8 + .byte 196,99,125,25,192,1 // vextractf128 $0x1,%ymm8,%xmm0 + .byte 196,195,121,34,68,184,16,0 // vpinsrd $0x0,0x10(%r8,%rdi,4),%xmm0,%xmm0 + .byte 196,99,61,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm8,%ymm8 + .byte 196,195,57,34,68,184,12,3 // vpinsrd $0x3,0xc(%r8,%rdi,4),%xmm8,%xmm0 + .byte 196,99,61,12,192,15 // vblendps $0xf,%ymm0,%ymm8,%ymm8 + .byte 196,195,57,34,68,184,8,2 // vpinsrd $0x2,0x8(%r8,%rdi,4),%xmm8,%xmm0 + .byte 196,99,61,12,192,15 // vblendps $0xf,%ymm0,%ymm8,%ymm8 + .byte 196,195,57,34,68,184,4,1 // vpinsrd $0x1,0x4(%r8,%rdi,4),%xmm8,%xmm0 + .byte 196,99,61,12,192,15 // vblendps $0xf,%ymm0,%ymm8,%ymm8 + .byte 196,195,57,34,4,184,0 // vpinsrd $0x0,(%r8,%rdi,4),%xmm8,%xmm0 + .byte 196,99,61,12,192,15 // vblendps $0xf,%ymm0,%ymm8,%ymm8 + .byte 233,38,253,255,255 // jmpq 1716 <_sk_load_tables_avx+0x1e> + .byte 238 // out %al,(%dx) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,224 // jmpq *%rax + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,210 // callq *%rdx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,196 // inc %esp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,176,255,255,255,156 // pushq -0x63000001(%rax) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + .byte 128,255,255 // cmp $0xff,%bh + .byte 255 // .byte 0xff + +HIDDEN _sk_byte_tables_avx +.globl _sk_byte_tables_avx +_sk_byte_tables_avx: + .byte 85 // push %rbp + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,127,67 // mov $0x437f0000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,253,91,192 // vcvtps2dq %ymm0,%ymm0 + .byte 196,195,249,22,192,1 // vpextrq $0x1,%xmm0,%r8 + .byte 68,137,197 // mov %r8d,%ebp + .byte 77,137,194 // mov %r8,%r10 + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,193,249,126,192 // vmovq %xmm0,%r8 + .byte 69,137,195 // mov %r8d,%r11d + .byte 77,137,199 // mov %r8,%r15 + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,227,125,25,192,1 // vextractf128 $0x1,%ymm0,%xmm0 + .byte 196,195,249,22,192,1 // vpextrq $0x1,%xmm0,%r8 + .byte 69,137,198 // mov %r8d,%r14d + .byte 77,137,196 // mov %r8,%r12 + .byte 73,193,236,32 // shr $0x20,%r12 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,221 // mov %ebx,%r13d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 76,139,8 // mov (%rax),%r9 + .byte 76,139,64,8 // mov 0x8(%rax),%r8 + .byte 196,131,121,32,4,25,0 // vpinsrb $0x0,(%r9,%r11,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,57,1 // vpinsrb $0x1,(%r9,%r15,1),%xmm0,%xmm0 + .byte 65,15,182,44,41 // movzbl (%r9,%rbp,1),%ebp + .byte 196,227,121,32,197,2 // vpinsrb $0x2,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,17 // movzbl (%r9,%r10,1),%ebp + .byte 196,227,121,32,197,3 // vpinsrb $0x3,%ebp,%xmm0,%xmm0 + .byte 196,98,121,49,200 // vpmovzxbd %xmm0,%xmm9 + .byte 196,131,121,32,4,41,0 // vpinsrb $0x0,(%r9,%r13,1),%xmm0,%xmm0 + .byte 196,195,121,32,4,25,1 // vpinsrb $0x1,(%r9,%rbx,1),%xmm0,%xmm0 + .byte 67,15,182,44,49 // movzbl (%r9,%r14,1),%ebp + .byte 196,227,121,32,197,2 // vpinsrb $0x2,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,33 // movzbl (%r9,%r12,1),%ebp + .byte 196,227,121,32,197,3 // vpinsrb $0x3,%ebp,%xmm0,%xmm0 + .byte 196,226,121,49,192 // vpmovzxbd %xmm0,%xmm0 + .byte 196,227,53,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm9,%ymm0 + .byte 197,124,91,208 // vcvtdq2ps %ymm0,%ymm10 + .byte 189,129,128,128,59 // mov $0x3b808081,%ebp + .byte 197,249,110,197 // vmovd %ebp,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,99,125,24,200,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm9 + .byte 196,193,44,89,193 // vmulps %ymm9,%ymm10,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,253,91,201 // vcvtps2dq %ymm1,%ymm1 + .byte 196,227,249,22,205,1 // vpextrq $0x1,%xmm1,%rbp + .byte 65,137,233 // mov %ebp,%r9d + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,225,249,126,203 // vmovq %xmm1,%rbx + .byte 65,137,218 // mov %ebx,%r10d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,227,125,25,201,1 // vextractf128 $0x1,%ymm1,%xmm1 + .byte 196,195,249,22,203,1 // vpextrq $0x1,%xmm1,%r11 + .byte 69,137,222 // mov %r11d,%r14d + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 196,193,249,126,207 // vmovq %xmm1,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,131,121,32,12,16,0 // vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm1 + .byte 196,195,113,32,12,24,1 // vpinsrb $0x1,(%r8,%rbx,1),%xmm1,%xmm1 + .byte 67,15,182,28,8 // movzbl (%r8,%r9,1),%ebx + .byte 196,227,113,32,203,2 // vpinsrb $0x2,%ebx,%xmm1,%xmm1 + .byte 65,15,182,44,40 // movzbl (%r8,%rbp,1),%ebp + .byte 196,227,113,32,205,3 // vpinsrb $0x3,%ebp,%xmm1,%xmm1 + .byte 196,98,121,49,209 // vpmovzxbd %xmm1,%xmm10 + .byte 196,131,121,32,12,32,0 // vpinsrb $0x0,(%r8,%r12,1),%xmm0,%xmm1 + .byte 196,131,113,32,12,56,1 // vpinsrb $0x1,(%r8,%r15,1),%xmm1,%xmm1 + .byte 67,15,182,44,48 // movzbl (%r8,%r14,1),%ebp + .byte 196,227,113,32,205,2 // vpinsrb $0x2,%ebp,%xmm1,%xmm1 + .byte 67,15,182,44,24 // movzbl (%r8,%r11,1),%ebp + .byte 196,227,113,32,205,3 // vpinsrb $0x3,%ebp,%xmm1,%xmm1 + .byte 196,226,121,49,201 // vpmovzxbd %xmm1,%xmm1 + .byte 196,227,45,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm10,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 197,180,89,201 // vmulps %ymm1,%ymm9,%ymm1 + .byte 76,139,64,16 // mov 0x10(%rax),%r8 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,253,91,210 // vcvtps2dq %ymm2,%ymm2 + .byte 196,227,249,22,213,1 // vpextrq $0x1,%xmm2,%rbp + .byte 65,137,233 // mov %ebp,%r9d + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,225,249,126,211 // vmovq %xmm2,%rbx + .byte 65,137,218 // mov %ebx,%r10d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,227,125,25,210,1 // vextractf128 $0x1,%ymm2,%xmm2 + .byte 196,195,249,22,211,1 // vpextrq $0x1,%xmm2,%r11 + .byte 69,137,222 // mov %r11d,%r14d + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 196,193,249,126,215 // vmovq %xmm2,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,131,121,32,20,16,0 // vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm2 + .byte 196,195,105,32,20,24,1 // vpinsrb $0x1,(%r8,%rbx,1),%xmm2,%xmm2 + .byte 67,15,182,28,8 // movzbl (%r8,%r9,1),%ebx + .byte 196,227,105,32,211,2 // vpinsrb $0x2,%ebx,%xmm2,%xmm2 + .byte 65,15,182,44,40 // movzbl (%r8,%rbp,1),%ebp + .byte 196,227,105,32,213,3 // vpinsrb $0x3,%ebp,%xmm2,%xmm2 + .byte 196,98,121,49,210 // vpmovzxbd %xmm2,%xmm10 + .byte 196,131,121,32,20,32,0 // vpinsrb $0x0,(%r8,%r12,1),%xmm0,%xmm2 + .byte 196,131,105,32,20,56,1 // vpinsrb $0x1,(%r8,%r15,1),%xmm2,%xmm2 + .byte 67,15,182,44,48 // movzbl (%r8,%r14,1),%ebp + .byte 196,227,105,32,213,2 // vpinsrb $0x2,%ebp,%xmm2,%xmm2 + .byte 67,15,182,44,24 // movzbl (%r8,%r11,1),%ebp + .byte 196,227,105,32,213,3 // vpinsrb $0x3,%ebp,%xmm2,%xmm2 + .byte 196,226,121,49,210 // vpmovzxbd %xmm2,%xmm2 + .byte 196,227,45,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm10,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 197,180,89,210 // vmulps %ymm2,%ymm9,%ymm2 + .byte 72,139,64,24 // mov 0x18(%rax),%rax + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 197,253,91,219 // vcvtps2dq %ymm3,%ymm3 + .byte 196,227,249,22,221,1 // vpextrq $0x1,%xmm3,%rbp + .byte 65,137,232 // mov %ebp,%r8d + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,225,249,126,219 // vmovq %xmm3,%rbx + .byte 65,137,217 // mov %ebx,%r9d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,227,125,25,219,1 // vextractf128 $0x1,%ymm3,%xmm3 + .byte 196,195,249,22,218,1 // vpextrq $0x1,%xmm3,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,193,249,126,222 // vmovq %xmm3,%r14 + .byte 69,137,247 // mov %r14d,%r15d + .byte 73,193,238,32 // shr $0x20,%r14 + .byte 196,163,121,32,28,8,0 // vpinsrb $0x0,(%rax,%r9,1),%xmm0,%xmm3 + .byte 196,227,97,32,28,24,1 // vpinsrb $0x1,(%rax,%rbx,1),%xmm3,%xmm3 + .byte 66,15,182,28,0 // movzbl (%rax,%r8,1),%ebx + .byte 196,227,97,32,219,2 // vpinsrb $0x2,%ebx,%xmm3,%xmm3 + .byte 15,182,44,40 // movzbl (%rax,%rbp,1),%ebp + .byte 196,227,97,32,221,3 // vpinsrb $0x3,%ebp,%xmm3,%xmm3 + .byte 196,98,121,49,195 // vpmovzxbd %xmm3,%xmm8 + .byte 196,163,121,32,28,56,0 // vpinsrb $0x0,(%rax,%r15,1),%xmm0,%xmm3 + .byte 196,163,97,32,28,48,1 // vpinsrb $0x1,(%rax,%r14,1),%xmm3,%xmm3 + .byte 66,15,182,44,24 // movzbl (%rax,%r11,1),%ebp + .byte 196,227,97,32,221,2 // vpinsrb $0x2,%ebp,%xmm3,%xmm3 + .byte 66,15,182,4,16 // movzbl (%rax,%r10,1),%eax + .byte 196,227,97,32,216,3 // vpinsrb $0x3,%eax,%xmm3,%xmm3 + .byte 196,226,121,49,219 // vpmovzxbd %xmm3,%xmm3 + .byte 196,227,61,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + .byte 197,252,91,219 // vcvtdq2ps %ymm3,%ymm3 + .byte 197,180,89,219 // vmulps %ymm3,%ymm9,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 93 // pop %rbp + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_byte_tables_rgb_avx +.globl _sk_byte_tables_rgb_avx +_sk_byte_tables_rgb_avx: + .byte 85 // push %rbp + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 68,139,64,24 // mov 0x18(%rax),%r8d + .byte 65,255,200 // dec %r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,65,121,112,192,0 // vpshufd $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 196,65,124,91,192 // vcvtdq2ps %ymm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,253,91,192 // vcvtps2dq %ymm0,%ymm0 + .byte 196,195,249,22,192,1 // vpextrq $0x1,%xmm0,%r8 + .byte 68,137,197 // mov %r8d,%ebp + .byte 77,137,194 // mov %r8,%r10 + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,193,249,126,192 // vmovq %xmm0,%r8 + .byte 69,137,195 // mov %r8d,%r11d + .byte 77,137,199 // mov %r8,%r15 + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,227,125,25,192,1 // vextractf128 $0x1,%ymm0,%xmm0 + .byte 196,195,249,22,192,1 // vpextrq $0x1,%xmm0,%r8 + .byte 69,137,198 // mov %r8d,%r14d + .byte 77,137,196 // mov %r8,%r12 + .byte 73,193,236,32 // shr $0x20,%r12 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,221 // mov %ebx,%r13d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 76,139,8 // mov (%rax),%r9 + .byte 76,139,64,8 // mov 0x8(%rax),%r8 + .byte 196,131,121,32,4,25,0 // vpinsrb $0x0,(%r9,%r11,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,57,1 // vpinsrb $0x1,(%r9,%r15,1),%xmm0,%xmm0 + .byte 65,15,182,44,41 // movzbl (%r9,%rbp,1),%ebp + .byte 196,227,121,32,197,2 // vpinsrb $0x2,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,17 // movzbl (%r9,%r10,1),%ebp + .byte 196,227,121,32,197,3 // vpinsrb $0x3,%ebp,%xmm0,%xmm0 + .byte 196,98,121,49,200 // vpmovzxbd %xmm0,%xmm9 + .byte 196,131,121,32,4,41,0 // vpinsrb $0x0,(%r9,%r13,1),%xmm0,%xmm0 + .byte 196,195,121,32,4,25,1 // vpinsrb $0x1,(%r9,%rbx,1),%xmm0,%xmm0 + .byte 67,15,182,44,49 // movzbl (%r9,%r14,1),%ebp + .byte 196,227,121,32,197,2 // vpinsrb $0x2,%ebp,%xmm0,%xmm0 + .byte 67,15,182,44,33 // movzbl (%r9,%r12,1),%ebp + .byte 196,227,121,32,197,3 // vpinsrb $0x3,%ebp,%xmm0,%xmm0 + .byte 196,226,121,49,192 // vpmovzxbd %xmm0,%xmm0 + .byte 196,227,53,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm9,%ymm0 + .byte 197,124,91,208 // vcvtdq2ps %ymm0,%ymm10 + .byte 189,129,128,128,59 // mov $0x3b808081,%ebp + .byte 197,249,110,197 // vmovd %ebp,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,99,125,24,200,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm9 + .byte 196,193,44,89,193 // vmulps %ymm9,%ymm10,%ymm0 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,253,91,201 // vcvtps2dq %ymm1,%ymm1 + .byte 196,227,249,22,205,1 // vpextrq $0x1,%xmm1,%rbp + .byte 65,137,233 // mov %ebp,%r9d + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,225,249,126,203 // vmovq %xmm1,%rbx + .byte 65,137,218 // mov %ebx,%r10d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,227,125,25,201,1 // vextractf128 $0x1,%ymm1,%xmm1 + .byte 196,195,249,22,203,1 // vpextrq $0x1,%xmm1,%r11 + .byte 69,137,222 // mov %r11d,%r14d + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 196,193,249,126,207 // vmovq %xmm1,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,131,121,32,12,16,0 // vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm1 + .byte 196,195,113,32,12,24,1 // vpinsrb $0x1,(%r8,%rbx,1),%xmm1,%xmm1 + .byte 67,15,182,28,8 // movzbl (%r8,%r9,1),%ebx + .byte 196,227,113,32,203,2 // vpinsrb $0x2,%ebx,%xmm1,%xmm1 + .byte 65,15,182,44,40 // movzbl (%r8,%rbp,1),%ebp + .byte 196,227,113,32,205,3 // vpinsrb $0x3,%ebp,%xmm1,%xmm1 + .byte 196,98,121,49,209 // vpmovzxbd %xmm1,%xmm10 + .byte 196,131,121,32,12,32,0 // vpinsrb $0x0,(%r8,%r12,1),%xmm0,%xmm1 + .byte 196,131,113,32,12,56,1 // vpinsrb $0x1,(%r8,%r15,1),%xmm1,%xmm1 + .byte 67,15,182,44,48 // movzbl (%r8,%r14,1),%ebp + .byte 196,227,113,32,205,2 // vpinsrb $0x2,%ebp,%xmm1,%xmm1 + .byte 67,15,182,44,24 // movzbl (%r8,%r11,1),%ebp + .byte 196,227,113,32,205,3 // vpinsrb $0x3,%ebp,%xmm1,%xmm1 + .byte 196,226,121,49,201 // vpmovzxbd %xmm1,%xmm1 + .byte 196,227,45,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm10,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 197,180,89,201 // vmulps %ymm1,%ymm9,%ymm1 + .byte 72,139,64,16 // mov 0x10(%rax),%rax + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 197,253,91,210 // vcvtps2dq %ymm2,%ymm2 + .byte 196,227,249,22,213,1 // vpextrq $0x1,%xmm2,%rbp + .byte 65,137,232 // mov %ebp,%r8d + .byte 72,193,237,32 // shr $0x20,%rbp + .byte 196,225,249,126,211 // vmovq %xmm2,%rbx + .byte 65,137,217 // mov %ebx,%r9d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,227,125,25,210,1 // vextractf128 $0x1,%ymm2,%xmm2 + .byte 196,195,249,22,210,1 // vpextrq $0x1,%xmm2,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 196,193,249,126,214 // vmovq %xmm2,%r14 + .byte 69,137,247 // mov %r14d,%r15d + .byte 73,193,238,32 // shr $0x20,%r14 + .byte 196,163,121,32,20,8,0 // vpinsrb $0x0,(%rax,%r9,1),%xmm0,%xmm2 + .byte 196,227,105,32,20,24,1 // vpinsrb $0x1,(%rax,%rbx,1),%xmm2,%xmm2 + .byte 66,15,182,28,0 // movzbl (%rax,%r8,1),%ebx + .byte 196,227,105,32,211,2 // vpinsrb $0x2,%ebx,%xmm2,%xmm2 + .byte 15,182,44,40 // movzbl (%rax,%rbp,1),%ebp + .byte 196,227,105,32,213,3 // vpinsrb $0x3,%ebp,%xmm2,%xmm2 + .byte 196,98,121,49,194 // vpmovzxbd %xmm2,%xmm8 + .byte 196,163,121,32,20,56,0 // vpinsrb $0x0,(%rax,%r15,1),%xmm0,%xmm2 + .byte 196,163,105,32,20,48,1 // vpinsrb $0x1,(%rax,%r14,1),%xmm2,%xmm2 + .byte 66,15,182,44,24 // movzbl (%rax,%r11,1),%ebp + .byte 196,227,105,32,213,2 // vpinsrb $0x2,%ebp,%xmm2,%xmm2 + .byte 66,15,182,4,16 // movzbl (%rax,%r10,1),%eax + .byte 196,227,105,32,208,3 // vpinsrb $0x3,%eax,%xmm2,%xmm2 + .byte 196,226,121,49,210 // vpmovzxbd %xmm2,%xmm2 + .byte 196,227,61,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm8,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 197,180,89,210 // vmulps %ymm2,%ymm9,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 93 // pop %rbp + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_a8_avx +.globl _sk_load_a8_avx +_sk_load_a8_avx: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,1,248 // add %rdi,%rax + .byte 77,133,192 // test %r8,%r8 + .byte 117,74 // jne 1f84 <_sk_load_a8_avx+0x5a> + .byte 197,250,126,0 // vmovq (%rax),%xmm0 + .byte 196,226,121,49,200 // vpmovzxbd %xmm0,%xmm1 + .byte 196,227,121,4,192,229 // vpermilps $0xe5,%xmm0,%xmm0 + .byte 196,226,121,49,192 // vpmovzxbd %xmm0,%xmm0 + .byte 196,227,117,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm1,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,252,89,217 // vmulps %ymm1,%ymm0,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 76,137,193 // mov %r8,%rcx + .byte 255,224 // jmpq *%rax + .byte 49,201 // xor %ecx,%ecx + .byte 77,137,194 // mov %r8,%r10 + .byte 69,49,201 // xor %r9d,%r9d + .byte 68,15,182,24 // movzbl (%rax),%r11d + .byte 72,255,192 // inc %rax + .byte 73,211,227 // shl %cl,%r11 + .byte 77,9,217 // or %r11,%r9 + .byte 72,131,193,8 // add $0x8,%rcx + .byte 73,255,202 // dec %r10 + .byte 117,234 // jne 1f8c <_sk_load_a8_avx+0x62> + .byte 196,193,249,110,193 // vmovq %r9,%xmm0 + .byte 235,149 // jmp 1f3e <_sk_load_a8_avx+0x14> + +HIDDEN _sk_gather_a8_avx +.globl _sk_gather_a8_avx +_sk_gather_a8_avx: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,209 // vcvttps2dq %ymm1,%ymm2 + .byte 197,249,110,72,16 // vmovd 0x10(%rax),%xmm1 + .byte 197,249,112,217,0 // vpshufd $0x0,%xmm1,%xmm3 + .byte 196,226,97,64,202 // vpmulld %xmm2,%xmm3,%xmm1 + .byte 196,227,125,25,210,1 // vextractf128 $0x1,%ymm2,%xmm2 + .byte 196,226,97,64,210 // vpmulld %xmm2,%xmm3,%xmm2 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 196,227,125,25,195,1 // vextractf128 $0x1,%ymm0,%xmm3 + .byte 197,233,254,211 // vpaddd %xmm3,%xmm2,%xmm2 + .byte 196,227,249,22,208,1 // vpextrq $0x1,%xmm2,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,210 // vmovq %xmm2,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 197,241,254,192 // vpaddd %xmm0,%xmm1,%xmm0 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,222 // mov %ebx,%r14d + .byte 196,195,249,22,199,1 // vpextrq $0x1,%xmm0,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,131,121,32,4,48,0 // vpinsrb $0x0,(%r8,%r14,1),%xmm0,%xmm0 + .byte 196,195,121,32,4,24,1 // vpinsrb $0x1,(%r8,%rbx,1),%xmm0,%xmm0 + .byte 67,15,182,28,32 // movzbl (%r8,%r12,1),%ebx + .byte 196,227,121,32,195,2 // vpinsrb $0x2,%ebx,%xmm0,%xmm0 + .byte 67,15,182,28,56 // movzbl (%r8,%r15,1),%ebx + .byte 196,227,121,32,195,3 // vpinsrb $0x3,%ebx,%xmm0,%xmm0 + .byte 196,226,121,49,192 // vpmovzxbd %xmm0,%xmm0 + .byte 196,131,121,32,12,24,0 // vpinsrb $0x0,(%r8,%r11,1),%xmm0,%xmm1 + .byte 196,131,113,32,12,16,1 // vpinsrb $0x1,(%r8,%r10,1),%xmm1,%xmm1 + .byte 67,15,182,28,8 // movzbl (%r8,%r9,1),%ebx + .byte 196,227,113,32,203,2 // vpinsrb $0x2,%ebx,%xmm1,%xmm1 + .byte 65,15,182,4,0 // movzbl (%r8,%rax,1),%eax + .byte 196,227,113,32,200,3 // vpinsrb $0x3,%eax,%xmm1,%xmm1 + .byte 196,226,121,49,201 // vpmovzxbd %xmm1,%xmm1 + .byte 196,227,125,24,193,1 // vinsertf128 $0x1,%xmm1,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,252,89,217 // vmulps %ymm1,%ymm0,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_a8_avx +.globl _sk_store_a8_avx +_sk_store_a8_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 184,0,0,127,67 // mov $0x437f0000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 196,65,125,91,192 // vcvtps2dq %ymm8,%ymm8 + .byte 196,67,125,25,193,1 // vextractf128 $0x1,%ymm8,%xmm9 + .byte 196,66,57,43,193 // vpackusdw %xmm9,%xmm8,%xmm8 + .byte 196,65,57,103,192 // vpackuswb %xmm8,%xmm8,%xmm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,10 // jne 20e5 <_sk_store_a8_avx+0x42> + .byte 196,65,123,17,4,57 // vmovsd %xmm8,(%r9,%rdi,1) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 119,236 // ja 20e1 <_sk_store_a8_avx+0x3e> + .byte 196,66,121,48,192 // vpmovzxbw %xmm8,%xmm8 + .byte 65,15,182,192 // movzbl %r8b,%eax + .byte 76,141,5,67,0,0,0 // lea 0x43(%rip),%r8 # 2148 <_sk_store_a8_avx+0xa5> + .byte 73,99,4,128 // movslq (%r8,%rax,4),%rax + .byte 76,1,192 // add %r8,%rax + .byte 255,224 // jmpq *%rax + .byte 196,67,121,20,68,57,6,12 // vpextrb $0xc,%xmm8,0x6(%r9,%rdi,1) + .byte 196,67,121,20,68,57,5,10 // vpextrb $0xa,%xmm8,0x5(%r9,%rdi,1) + .byte 196,67,121,20,68,57,4,8 // vpextrb $0x8,%xmm8,0x4(%r9,%rdi,1) + .byte 196,67,121,20,68,57,3,6 // vpextrb $0x6,%xmm8,0x3(%r9,%rdi,1) + .byte 196,67,121,20,68,57,2,4 // vpextrb $0x4,%xmm8,0x2(%r9,%rdi,1) + .byte 196,67,121,20,68,57,1,2 // vpextrb $0x2,%xmm8,0x1(%r9,%rdi,1) + .byte 196,67,121,20,4,57,0 // vpextrb $0x0,%xmm8,(%r9,%rdi,1) + .byte 235,154 // jmp 20e1 <_sk_store_a8_avx+0x3e> + .byte 144 // nop + .byte 246,255 // idiv %bh + .byte 255 // (bad) + .byte 255 // (bad) + .byte 238 // out %al,(%dx) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,230 // jmpq *%rsi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 222,255 // fdivrp %st,%st(7) + .byte 255 // (bad) + .byte 255,214 // callq *%rsi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,206 // dec %esi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,198 // inc %esi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_load_g8_avx +.globl _sk_load_g8_avx +_sk_load_g8_avx: + .byte 73,137,200 // mov %rcx,%r8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,1,248 // add %rdi,%rax + .byte 77,133,192 // test %r8,%r8 + .byte 117,91 // jne 21cf <_sk_load_g8_avx+0x6b> + .byte 197,250,126,0 // vmovq (%rax),%xmm0 + .byte 196,226,121,49,200 // vpmovzxbd %xmm0,%xmm1 + .byte 196,227,121,4,192,229 // vpermilps $0xe5,%xmm0,%xmm0 + .byte 196,226,121,49,192 // vpmovzxbd %xmm0,%xmm0 + .byte 196,227,117,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm1,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,217,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,137,193 // mov %r8,%rcx + .byte 197,252,40,200 // vmovaps %ymm0,%ymm1 + .byte 197,252,40,208 // vmovaps %ymm0,%ymm2 + .byte 255,224 // jmpq *%rax + .byte 49,201 // xor %ecx,%ecx + .byte 77,137,194 // mov %r8,%r10 + .byte 69,49,201 // xor %r9d,%r9d + .byte 68,15,182,24 // movzbl (%rax),%r11d + .byte 72,255,192 // inc %rax + .byte 73,211,227 // shl %cl,%r11 + .byte 77,9,217 // or %r11,%r9 + .byte 72,131,193,8 // add $0x8,%rcx + .byte 73,255,202 // dec %r10 + .byte 117,234 // jne 21d7 <_sk_load_g8_avx+0x73> + .byte 196,193,249,110,193 // vmovq %r9,%xmm0 + .byte 235,132 // jmp 2178 <_sk_load_g8_avx+0x14> + +HIDDEN _sk_gather_g8_avx +.globl _sk_gather_g8_avx +_sk_gather_g8_avx: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,209 // vcvttps2dq %ymm1,%ymm2 + .byte 197,249,110,72,16 // vmovd 0x10(%rax),%xmm1 + .byte 197,249,112,217,0 // vpshufd $0x0,%xmm1,%xmm3 + .byte 196,226,97,64,202 // vpmulld %xmm2,%xmm3,%xmm1 + .byte 196,227,125,25,210,1 // vextractf128 $0x1,%ymm2,%xmm2 + .byte 196,226,97,64,210 // vpmulld %xmm2,%xmm3,%xmm2 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 196,227,125,25,195,1 // vextractf128 $0x1,%ymm0,%xmm3 + .byte 197,233,254,211 // vpaddd %xmm3,%xmm2,%xmm2 + .byte 196,227,249,22,208,1 // vpextrq $0x1,%xmm2,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,210 // vmovq %xmm2,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 197,241,254,192 // vpaddd %xmm0,%xmm1,%xmm0 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,222 // mov %ebx,%r14d + .byte 196,195,249,22,199,1 // vpextrq $0x1,%xmm0,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,131,121,32,4,48,0 // vpinsrb $0x0,(%r8,%r14,1),%xmm0,%xmm0 + .byte 196,195,121,32,4,24,1 // vpinsrb $0x1,(%r8,%rbx,1),%xmm0,%xmm0 + .byte 67,15,182,28,32 // movzbl (%r8,%r12,1),%ebx + .byte 196,227,121,32,195,2 // vpinsrb $0x2,%ebx,%xmm0,%xmm0 + .byte 67,15,182,28,56 // movzbl (%r8,%r15,1),%ebx + .byte 196,227,121,32,195,3 // vpinsrb $0x3,%ebx,%xmm0,%xmm0 + .byte 196,226,121,49,192 // vpmovzxbd %xmm0,%xmm0 + .byte 196,131,121,32,12,24,0 // vpinsrb $0x0,(%r8,%r11,1),%xmm0,%xmm1 + .byte 196,131,113,32,12,16,1 // vpinsrb $0x1,(%r8,%r10,1),%xmm1,%xmm1 + .byte 67,15,182,28,8 // movzbl (%r8,%r9,1),%ebx + .byte 196,227,113,32,203,2 // vpinsrb $0x2,%ebx,%xmm1,%xmm1 + .byte 65,15,182,4,0 // movzbl (%r8,%rax,1),%eax + .byte 196,227,113,32,200,3 // vpinsrb $0x3,%eax,%xmm1,%xmm1 + .byte 196,226,121,49,201 // vpmovzxbd %xmm1,%xmm1 + .byte 196,227,125,24,193,1 // vinsertf128 $0x1,%xmm1,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,217,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,40,200 // vmovaps %ymm0,%ymm1 + .byte 197,252,40,208 // vmovaps %ymm0,%ymm2 + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_i8_avx +.globl _sk_gather_i8_avx +_sk_gather_i8_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 73,137,192 // mov %rax,%r8 + .byte 77,133,192 // test %r8,%r8 + .byte 116,5 // je 230e <_sk_gather_i8_avx+0xf> + .byte 76,137,192 // mov %r8,%rax + .byte 235,2 // jmp 2310 <_sk_gather_i8_avx+0x11> + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 76,139,8 // mov (%rax),%r9 + .byte 197,254,91,209 // vcvttps2dq %ymm1,%ymm2 + .byte 197,249,110,72,16 // vmovd 0x10(%rax),%xmm1 + .byte 197,249,112,217,0 // vpshufd $0x0,%xmm1,%xmm3 + .byte 196,226,97,64,202 // vpmulld %xmm2,%xmm3,%xmm1 + .byte 196,227,125,25,210,1 // vextractf128 $0x1,%ymm2,%xmm2 + .byte 196,226,97,64,210 // vpmulld %xmm2,%xmm3,%xmm2 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 196,227,125,25,195,1 // vextractf128 $0x1,%ymm0,%xmm3 + .byte 197,233,254,211 // vpaddd %xmm3,%xmm2,%xmm2 + .byte 196,227,249,22,208,1 // vpextrq $0x1,%xmm2,%rax + .byte 65,137,194 // mov %eax,%r10d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,211 // vmovq %xmm2,%r11 + .byte 69,137,222 // mov %r11d,%r14d + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 197,241,254,192 // vpaddd %xmm0,%xmm1,%xmm0 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,223 // mov %ebx,%r15d + .byte 196,195,249,22,196,1 // vpextrq $0x1,%xmm0,%r12 + .byte 69,137,229 // mov %r12d,%r13d + .byte 73,193,236,32 // shr $0x20,%r12 + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,131,121,32,4,49,0 // vpinsrb $0x0,(%r9,%r14,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,25,1 // vpinsrb $0x1,(%r9,%r11,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,17,2 // vpinsrb $0x2,(%r9,%r10,1),%xmm0,%xmm0 + .byte 196,195,121,32,4,1,3 // vpinsrb $0x3,(%r9,%rax,1),%xmm0,%xmm0 + .byte 196,226,121,49,192 // vpmovzxbd %xmm0,%xmm0 + .byte 196,195,249,22,194,1 // vpextrq $0x1,%xmm0,%r10 + .byte 196,193,249,126,195 // vmovq %xmm0,%r11 + .byte 196,131,121,32,4,57,0 // vpinsrb $0x0,(%r9,%r15,1),%xmm0,%xmm0 + .byte 196,195,121,32,4,25,1 // vpinsrb $0x1,(%r9,%rbx,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,41,2 // vpinsrb $0x2,(%r9,%r13,1),%xmm0,%xmm0 + .byte 196,131,121,32,4,33,3 // vpinsrb $0x3,(%r9,%r12,1),%xmm0,%xmm0 + .byte 196,226,121,49,192 // vpmovzxbd %xmm0,%xmm0 + .byte 73,139,88,8 // mov 0x8(%r8),%rbx + .byte 196,193,249,126,193 // vmovq %xmm0,%r9 + .byte 69,137,200 // mov %r9d,%r8d + .byte 73,193,233,30 // shr $0x1e,%r9 + .byte 196,227,249,22,192,1 // vpextrq $0x1,%xmm0,%rax + .byte 65,137,198 // mov %eax,%r14d + .byte 72,193,232,30 // shr $0x1e,%rax + .byte 69,137,223 // mov %r11d,%r15d + .byte 73,193,235,30 // shr $0x1e,%r11 + .byte 69,137,212 // mov %r10d,%r12d + .byte 73,193,234,30 // shr $0x1e,%r10 + .byte 196,161,121,110,4,131 // vmovd (%rbx,%r8,4),%xmm0 + .byte 196,163,121,34,4,11,1 // vpinsrd $0x1,(%rbx,%r9,1),%xmm0,%xmm0 + .byte 196,163,121,34,4,179,2 // vpinsrd $0x2,(%rbx,%r14,4),%xmm0,%xmm0 + .byte 196,99,121,34,4,3,3 // vpinsrd $0x3,(%rbx,%rax,1),%xmm0,%xmm8 + .byte 196,161,121,110,4,187 // vmovd (%rbx,%r15,4),%xmm0 + .byte 196,163,121,34,4,27,1 // vpinsrd $0x1,(%rbx,%r11,1),%xmm0,%xmm0 + .byte 196,163,121,34,4,163,2 // vpinsrd $0x2,(%rbx,%r12,4),%xmm0,%xmm0 + .byte 196,163,121,34,28,19,3 // vpinsrd $0x3,(%rbx,%r10,1),%xmm0,%xmm3 + .byte 196,227,61,24,195,1 // vinsertf128 $0x1,%xmm3,%ymm8,%ymm0 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 197,249,112,201,0 // vpshufd $0x0,%xmm1,%xmm1 + .byte 196,99,117,24,217,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm11 + .byte 197,164,84,192 // vandps %ymm0,%ymm11,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,99,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm9 + .byte 196,193,124,89,193 // vmulps %ymm9,%ymm0,%ymm0 + .byte 196,193,41,114,208,8 // vpsrld $0x8,%xmm8,%xmm10 + .byte 197,241,114,211,8 // vpsrld $0x8,%xmm3,%xmm1 + .byte 196,227,45,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm10,%ymm1 + .byte 197,164,84,201 // vandps %ymm1,%ymm11,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 196,193,116,89,201 // vmulps %ymm9,%ymm1,%ymm1 + .byte 196,193,41,114,208,16 // vpsrld $0x10,%xmm8,%xmm10 + .byte 197,233,114,211,16 // vpsrld $0x10,%xmm3,%xmm2 + .byte 196,227,45,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm10,%ymm2 + .byte 197,164,84,210 // vandps %ymm2,%ymm11,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 196,193,108,89,209 // vmulps %ymm9,%ymm2,%ymm2 + .byte 196,193,57,114,208,24 // vpsrld $0x18,%xmm8,%xmm8 + .byte 197,225,114,211,24 // vpsrld $0x18,%xmm3,%xmm3 + .byte 196,227,61,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + .byte 197,252,91,219 // vcvtdq2ps %ymm3,%ymm3 + .byte 196,193,100,89,217 // vmulps %ymm9,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_565_avx +.globl _sk_load_565_avx +_sk_load_565_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,16 // mov (%rax),%r10 + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,209,0,0,0 // jne 25aa <_sk_load_565_avx+0xdf> + .byte 196,193,122,111,4,122 // vmovdqu (%r10,%rdi,2),%xmm0 + .byte 197,241,239,201 // vpxor %xmm1,%xmm1,%xmm1 + .byte 197,249,105,201 // vpunpckhwd %xmm1,%xmm0,%xmm1 + .byte 196,226,121,51,192 // vpmovzxwd %xmm0,%xmm0 + .byte 196,227,125,24,209,1 // vinsertf128 $0x1,%xmm1,%ymm0,%ymm2 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 197,249,112,192,0 // vpshufd $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,252,84,194 // vandps %ymm2,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 197,249,112,201,0 // vpshufd $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,244,84,202 // vandps %ymm2,%ymm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,244,89,203 // vmulps %ymm3,%ymm1,%ymm1 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 197,249,112,219,0 // vpshufd $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,228,84,210 // vandps %ymm2,%ymm3,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,236,89,211 // vmulps %ymm3,%ymm2,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 197,249,239,192 // vpxor %xmm0,%xmm0,%xmm0 + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 15,135,29,255,255,255 // ja 24df <_sk_load_565_avx+0x14> + .byte 69,15,182,192 // movzbl %r8b,%r8d + .byte 76,141,13,75,0,0,0 // lea 0x4b(%rip),%r9 # 2618 <_sk_load_565_avx+0x14d> + .byte 75,99,4,129 // movslq (%r9,%r8,4),%rax + .byte 76,1,200 // add %r9,%rax + .byte 255,224 // jmpq *%rax + .byte 197,249,239,192 // vpxor %xmm0,%xmm0,%xmm0 + .byte 196,193,121,196,68,122,12,6 // vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,10,5 // vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,8,4 // vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,6,3 // vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,4,2 // vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,2,1 // vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,4,122,0 // vpinsrw $0x0,(%r10,%rdi,2),%xmm0,%xmm0 + .byte 233,201,254,255,255 // jmpq 24df <_sk_load_565_avx+0x14> + .byte 102,144 // xchg %ax,%ax + .byte 242,255 // repnz (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 234 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,226 // jmpq *%rdx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 218,255 // (bad) + .byte 255 // (bad) + .byte 255,210 // callq *%rdx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,202 // dec %edx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 190 // .byte 0xbe + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_gather_565_avx +.globl _sk_gather_565_avx +_sk_gather_565_avx: + .byte 85 // push %rbp + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,209 // vcvttps2dq %ymm1,%ymm2 + .byte 197,249,110,72,16 // vmovd 0x10(%rax),%xmm1 + .byte 197,249,112,217,0 // vpshufd $0x0,%xmm1,%xmm3 + .byte 196,226,97,64,202 // vpmulld %xmm2,%xmm3,%xmm1 + .byte 196,227,125,25,210,1 // vextractf128 $0x1,%ymm2,%xmm2 + .byte 196,226,97,64,210 // vpmulld %xmm2,%xmm3,%xmm2 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 196,227,125,25,195,1 // vextractf128 $0x1,%ymm0,%xmm3 + .byte 197,233,254,211 // vpaddd %xmm3,%xmm2,%xmm2 + .byte 196,227,249,22,208,1 // vpextrq $0x1,%xmm2,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,210 // vmovq %xmm2,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 197,241,254,192 // vpaddd %xmm0,%xmm1,%xmm0 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,222 // mov %ebx,%r14d + .byte 196,195,249,22,199,1 // vpextrq $0x1,%xmm0,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 65,15,183,28,88 // movzwl (%r8,%rbx,2),%ebx + .byte 67,15,183,44,112 // movzwl (%r8,%r14,2),%ebp + .byte 197,249,110,197 // vmovd %ebp,%xmm0 + .byte 197,249,196,195,1 // vpinsrw $0x1,%ebx,%xmm0,%xmm0 + .byte 67,15,183,28,96 // movzwl (%r8,%r12,2),%ebx + .byte 197,249,196,195,2 // vpinsrw $0x2,%ebx,%xmm0,%xmm0 + .byte 67,15,183,28,120 // movzwl (%r8,%r15,2),%ebx + .byte 197,249,196,195,3 // vpinsrw $0x3,%ebx,%xmm0,%xmm0 + .byte 67,15,183,44,88 // movzwl (%r8,%r11,2),%ebp + .byte 197,249,196,197,4 // vpinsrw $0x4,%ebp,%xmm0,%xmm0 + .byte 67,15,183,44,80 // movzwl (%r8,%r10,2),%ebp + .byte 197,249,196,197,5 // vpinsrw $0x5,%ebp,%xmm0,%xmm0 + .byte 67,15,183,44,72 // movzwl (%r8,%r9,2),%ebp + .byte 197,249,196,197,6 // vpinsrw $0x6,%ebp,%xmm0,%xmm0 + .byte 65,15,183,4,64 // movzwl (%r8,%rax,2),%eax + .byte 197,249,196,192,7 // vpinsrw $0x7,%eax,%xmm0,%xmm0 + .byte 197,241,239,201 // vpxor %xmm1,%xmm1,%xmm1 + .byte 197,249,105,201 // vpunpckhwd %xmm1,%xmm0,%xmm1 + .byte 196,226,121,51,192 // vpmovzxwd %xmm0,%xmm0 + .byte 196,227,125,24,209,1 // vinsertf128 $0x1,%xmm1,%ymm0,%ymm2 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 197,249,112,192,0 // vpshufd $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,252,84,194 // vandps %ymm2,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 197,249,112,201,0 // vpshufd $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,244,84,202 // vandps %ymm2,%ymm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,244,89,203 // vmulps %ymm3,%ymm1,%ymm1 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 197,249,112,219,0 // vpshufd $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,228,84,210 // vandps %ymm2,%ymm3,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,236,89,211 // vmulps %ymm3,%ymm2,%ymm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 93 // pop %rbp + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_565_avx +.globl _sk_store_565_avx +_sk_store_565_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 184,0,0,248,65 // mov $0x41f80000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 196,65,125,91,201 // vcvtps2dq %ymm9,%ymm9 + .byte 196,193,41,114,241,11 // vpslld $0xb,%xmm9,%xmm10 + .byte 196,67,125,25,201,1 // vextractf128 $0x1,%ymm9,%xmm9 + .byte 196,193,49,114,241,11 // vpslld $0xb,%xmm9,%xmm9 + .byte 196,67,45,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm10,%ymm9 + .byte 184,0,0,124,66 // mov $0x427c0000,%eax + .byte 197,121,110,208 // vmovd %eax,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 197,44,89,209 // vmulps %ymm1,%ymm10,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,193,33,114,242,5 // vpslld $0x5,%xmm10,%xmm11 + .byte 196,67,125,25,210,1 // vextractf128 $0x1,%ymm10,%xmm10 + .byte 196,193,41,114,242,5 // vpslld $0x5,%xmm10,%xmm10 + .byte 196,67,37,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm11,%ymm10 + .byte 196,65,45,86,201 // vorpd %ymm9,%ymm10,%ymm9 + .byte 197,60,89,194 // vmulps %ymm2,%ymm8,%ymm8 + .byte 196,65,125,91,192 // vcvtps2dq %ymm8,%ymm8 + .byte 196,65,53,86,192 // vorpd %ymm8,%ymm9,%ymm8 + .byte 196,67,125,25,193,1 // vextractf128 $0x1,%ymm8,%xmm9 + .byte 196,66,57,43,193 // vpackusdw %xmm9,%xmm8,%xmm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,10 // jne 2863 <_sk_store_565_avx+0x9e> + .byte 196,65,122,127,4,121 // vmovdqu %xmm8,(%r9,%rdi,2) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 119,236 // ja 285f <_sk_store_565_avx+0x9a> + .byte 65,15,182,192 // movzbl %r8b,%eax + .byte 76,141,5,66,0,0,0 // lea 0x42(%rip),%r8 # 28c0 <_sk_store_565_avx+0xfb> + .byte 73,99,4,128 // movslq (%r8,%rax,4),%rax + .byte 76,1,192 // add %r8,%rax + .byte 255,224 // jmpq *%rax + .byte 196,67,121,21,68,121,12,6 // vpextrw $0x6,%xmm8,0xc(%r9,%rdi,2) + .byte 196,67,121,21,68,121,10,5 // vpextrw $0x5,%xmm8,0xa(%r9,%rdi,2) + .byte 196,67,121,21,68,121,8,4 // vpextrw $0x4,%xmm8,0x8(%r9,%rdi,2) + .byte 196,67,121,21,68,121,6,3 // vpextrw $0x3,%xmm8,0x6(%r9,%rdi,2) + .byte 196,67,121,21,68,121,4,2 // vpextrw $0x2,%xmm8,0x4(%r9,%rdi,2) + .byte 196,67,121,21,68,121,2,1 // vpextrw $0x1,%xmm8,0x2(%r9,%rdi,2) + .byte 196,67,121,21,4,121,0 // vpextrw $0x0,%xmm8,(%r9,%rdi,2) + .byte 235,159 // jmp 285f <_sk_store_565_avx+0x9a> + .byte 247,255 // idiv %edi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 239 // out %eax,(%dx) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,231 // jmpq *%rdi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 223,255 // (bad) + .byte 255 // (bad) + .byte 255,215 // callq *%rdi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,207 // dec %edi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,199 // inc %edi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_load_4444_avx +.globl _sk_load_4444_avx +_sk_load_4444_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,16 // mov (%rax),%r10 + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,245,0,0,0 // jne 29df <_sk_load_4444_avx+0x103> + .byte 196,193,122,111,4,122 // vmovdqu (%r10,%rdi,2),%xmm0 + .byte 197,241,239,201 // vpxor %xmm1,%xmm1,%xmm1 + .byte 197,249,105,201 // vpunpckhwd %xmm1,%xmm0,%xmm1 + .byte 196,226,121,51,192 // vpmovzxwd %xmm0,%xmm0 + .byte 196,99,125,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm0,%ymm9 + .byte 184,0,240,0,0 // mov $0xf000,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 197,249,112,192,0 // vpshufd $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 196,193,124,84,193 // vandps %ymm9,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,137,136,136,55 // mov $0x37888889,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,0,15,0,0 // mov $0xf00,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 197,249,112,201,0 // vpshufd $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 196,193,116,84,201 // vandps %ymm9,%ymm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 184,137,136,136,57 // mov $0x39888889,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,227,121,4,210,0 // vpermilps $0x0,%xmm2,%xmm2 + .byte 196,227,109,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + .byte 197,244,89,202 // vmulps %ymm2,%ymm1,%ymm1 + .byte 184,240,0,0,0 // mov $0xf0,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 197,249,112,210,0 // vpshufd $0x0,%xmm2,%xmm2 + .byte 196,227,109,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + .byte 196,193,108,84,209 // vandps %ymm9,%ymm2,%ymm2 + .byte 197,124,91,194 // vcvtdq2ps %ymm2,%ymm8 + .byte 184,137,136,136,59 // mov $0x3b888889,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,227,121,4,210,0 // vpermilps $0x0,%xmm2,%xmm2 + .byte 196,227,109,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 184,15,0,0,0 // mov $0xf,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 197,249,112,219,0 // vpshufd $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 196,193,100,84,217 // vandps %ymm9,%ymm3,%ymm3 + .byte 197,124,91,195 // vcvtdq2ps %ymm3,%ymm8 + .byte 184,137,136,136,61 // mov $0x3d888889,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 197,249,239,192 // vpxor %xmm0,%xmm0,%xmm0 + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 15,135,249,254,255,255 // ja 28f0 <_sk_load_4444_avx+0x14> + .byte 69,15,182,192 // movzbl %r8b,%r8d + .byte 76,141,13,74,0,0,0 // lea 0x4a(%rip),%r9 # 2a4c <_sk_load_4444_avx+0x170> + .byte 75,99,4,129 // movslq (%r9,%r8,4),%rax + .byte 76,1,200 // add %r9,%rax + .byte 255,224 // jmpq *%rax + .byte 197,249,239,192 // vpxor %xmm0,%xmm0,%xmm0 + .byte 196,193,121,196,68,122,12,6 // vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,10,5 // vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,8,4 // vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,6,3 // vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,4,2 // vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,68,122,2,1 // vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm0,%xmm0 + .byte 196,193,121,196,4,122,0 // vpinsrw $0x0,(%r10,%rdi,2),%xmm0,%xmm0 + .byte 233,165,254,255,255 // jmpq 28f0 <_sk_load_4444_avx+0x14> + .byte 144 // nop + .byte 243,255 // repz (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 235,255 // jmp 2a51 <_sk_load_4444_avx+0x175> + .byte 255 // (bad) + .byte 255,227 // jmpq *%rbx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 219,255 // (bad) + .byte 255 // (bad) + .byte 255,211 // callq *%rbx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,203 // dec %ebx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 191 // .byte 0xbf + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_gather_4444_avx +.globl _sk_gather_4444_avx +_sk_gather_4444_avx: + .byte 85 // push %rbp + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,209 // vcvttps2dq %ymm1,%ymm2 + .byte 197,249,110,72,16 // vmovd 0x10(%rax),%xmm1 + .byte 197,249,112,217,0 // vpshufd $0x0,%xmm1,%xmm3 + .byte 196,226,97,64,202 // vpmulld %xmm2,%xmm3,%xmm1 + .byte 196,227,125,25,210,1 // vextractf128 $0x1,%ymm2,%xmm2 + .byte 196,226,97,64,210 // vpmulld %xmm2,%xmm3,%xmm2 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 196,227,125,25,195,1 // vextractf128 $0x1,%ymm0,%xmm3 + .byte 197,233,254,211 // vpaddd %xmm3,%xmm2,%xmm2 + .byte 196,227,249,22,208,1 // vpextrq $0x1,%xmm2,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,210 // vmovq %xmm2,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 197,241,254,192 // vpaddd %xmm0,%xmm1,%xmm0 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,222 // mov %ebx,%r14d + .byte 196,195,249,22,199,1 // vpextrq $0x1,%xmm0,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 65,15,183,28,88 // movzwl (%r8,%rbx,2),%ebx + .byte 67,15,183,44,112 // movzwl (%r8,%r14,2),%ebp + .byte 197,249,110,197 // vmovd %ebp,%xmm0 + .byte 197,249,196,195,1 // vpinsrw $0x1,%ebx,%xmm0,%xmm0 + .byte 67,15,183,28,96 // movzwl (%r8,%r12,2),%ebx + .byte 197,249,196,195,2 // vpinsrw $0x2,%ebx,%xmm0,%xmm0 + .byte 67,15,183,28,120 // movzwl (%r8,%r15,2),%ebx + .byte 197,249,196,195,3 // vpinsrw $0x3,%ebx,%xmm0,%xmm0 + .byte 67,15,183,44,88 // movzwl (%r8,%r11,2),%ebp + .byte 197,249,196,197,4 // vpinsrw $0x4,%ebp,%xmm0,%xmm0 + .byte 67,15,183,44,80 // movzwl (%r8,%r10,2),%ebp + .byte 197,249,196,197,5 // vpinsrw $0x5,%ebp,%xmm0,%xmm0 + .byte 67,15,183,44,72 // movzwl (%r8,%r9,2),%ebp + .byte 197,249,196,197,6 // vpinsrw $0x6,%ebp,%xmm0,%xmm0 + .byte 65,15,183,4,64 // movzwl (%r8,%rax,2),%eax + .byte 197,249,196,192,7 // vpinsrw $0x7,%eax,%xmm0,%xmm0 + .byte 197,241,239,201 // vpxor %xmm1,%xmm1,%xmm1 + .byte 197,249,105,201 // vpunpckhwd %xmm1,%xmm0,%xmm1 + .byte 196,226,121,51,192 // vpmovzxwd %xmm0,%xmm0 + .byte 196,99,125,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm0,%ymm9 + .byte 184,0,240,0,0 // mov $0xf000,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 197,249,112,192,0 // vpshufd $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 196,193,124,84,193 // vandps %ymm9,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,137,136,136,55 // mov $0x37888889,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,252,89,193 // vmulps %ymm1,%ymm0,%ymm0 + .byte 184,0,15,0,0 // mov $0xf00,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 197,249,112,201,0 // vpshufd $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 196,193,116,84,201 // vandps %ymm9,%ymm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 184,137,136,136,57 // mov $0x39888889,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,227,121,4,210,0 // vpermilps $0x0,%xmm2,%xmm2 + .byte 196,227,109,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + .byte 197,244,89,202 // vmulps %ymm2,%ymm1,%ymm1 + .byte 184,240,0,0,0 // mov $0xf0,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 197,249,112,210,0 // vpshufd $0x0,%xmm2,%xmm2 + .byte 196,227,109,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + .byte 196,193,108,84,209 // vandps %ymm9,%ymm2,%ymm2 + .byte 197,124,91,194 // vcvtdq2ps %ymm2,%ymm8 + .byte 184,137,136,136,59 // mov $0x3b888889,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 196,227,121,4,210,0 // vpermilps $0x0,%xmm2,%xmm2 + .byte 196,227,109,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + .byte 197,188,89,210 // vmulps %ymm2,%ymm8,%ymm2 + .byte 184,15,0,0,0 // mov $0xf,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 197,249,112,219,0 // vpshufd $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 196,193,100,84,217 // vandps %ymm9,%ymm3,%ymm3 + .byte 197,124,91,195 // vcvtdq2ps %ymm3,%ymm8 + .byte 184,137,136,136,61 // mov $0x3d888889,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,188,89,219 // vmulps %ymm3,%ymm8,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 93 // pop %rbp + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_4444_avx +.globl _sk_store_4444_avx +_sk_store_4444_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 184,0,0,112,65 // mov $0x41700000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 196,65,125,91,201 // vcvtps2dq %ymm9,%ymm9 + .byte 196,193,41,114,241,12 // vpslld $0xc,%xmm9,%xmm10 + .byte 196,67,125,25,201,1 // vextractf128 $0x1,%ymm9,%xmm9 + .byte 196,193,49,114,241,12 // vpslld $0xc,%xmm9,%xmm9 + .byte 196,67,45,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm10,%ymm9 + .byte 197,60,89,209 // vmulps %ymm1,%ymm8,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,193,33,114,242,8 // vpslld $0x8,%xmm10,%xmm11 + .byte 196,67,125,25,210,1 // vextractf128 $0x1,%ymm10,%xmm10 + .byte 196,193,41,114,242,8 // vpslld $0x8,%xmm10,%xmm10 + .byte 196,67,37,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm11,%ymm10 + .byte 196,65,45,86,201 // vorpd %ymm9,%ymm10,%ymm9 + .byte 197,60,89,210 // vmulps %ymm2,%ymm8,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,193,33,114,242,4 // vpslld $0x4,%xmm10,%xmm11 + .byte 196,67,125,25,210,1 // vextractf128 $0x1,%ymm10,%xmm10 + .byte 196,193,41,114,242,4 // vpslld $0x4,%xmm10,%xmm10 + .byte 196,67,37,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm11,%ymm10 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 196,65,125,91,192 // vcvtps2dq %ymm8,%ymm8 + .byte 196,65,45,86,192 // vorpd %ymm8,%ymm10,%ymm8 + .byte 196,65,53,86,192 // vorpd %ymm8,%ymm9,%ymm8 + .byte 196,67,125,25,193,1 // vextractf128 $0x1,%ymm8,%xmm9 + .byte 196,66,57,43,193 // vpackusdw %xmm9,%xmm8,%xmm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,10 // jne 2ccc <_sk_store_4444_avx+0xaf> + .byte 196,65,122,127,4,121 // vmovdqu %xmm8,(%r9,%rdi,2) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 119,236 // ja 2cc8 <_sk_store_4444_avx+0xab> + .byte 65,15,182,192 // movzbl %r8b,%eax + .byte 76,141,5,69,0,0,0 // lea 0x45(%rip),%r8 # 2d2c <_sk_store_4444_avx+0x10f> + .byte 73,99,4,128 // movslq (%r8,%rax,4),%rax + .byte 76,1,192 // add %r8,%rax + .byte 255,224 // jmpq *%rax + .byte 196,67,121,21,68,121,12,6 // vpextrw $0x6,%xmm8,0xc(%r9,%rdi,2) + .byte 196,67,121,21,68,121,10,5 // vpextrw $0x5,%xmm8,0xa(%r9,%rdi,2) + .byte 196,67,121,21,68,121,8,4 // vpextrw $0x4,%xmm8,0x8(%r9,%rdi,2) + .byte 196,67,121,21,68,121,6,3 // vpextrw $0x3,%xmm8,0x6(%r9,%rdi,2) + .byte 196,67,121,21,68,121,4,2 // vpextrw $0x2,%xmm8,0x4(%r9,%rdi,2) + .byte 196,67,121,21,68,121,2,1 // vpextrw $0x1,%xmm8,0x2(%r9,%rdi,2) + .byte 196,67,121,21,4,121,0 // vpextrw $0x0,%xmm8,(%r9,%rdi,2) + .byte 235,159 // jmp 2cc8 <_sk_store_4444_avx+0xab> + .byte 15,31,0 // nopl (%rax) + .byte 244 // hlt + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 236 // in (%dx),%al + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,228 // jmpq *%rsp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 220,255 // fdivr %st,%st(7) + .byte 255 // (bad) + .byte 255,212 // callq *%rsp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,204 // dec %esp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,196 // inc %esp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_load_8888_avx +.globl _sk_load_8888_avx +_sk_load_8888_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,16 // mov (%rax),%r10 + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,157,0,0,0 // jne 2df3 <_sk_load_8888_avx+0xab> + .byte 196,65,124,16,12,186 // vmovups (%r10,%rdi,4),%ymm9 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 197,249,112,192,0 // vpshufd $0x0,%xmm0,%xmm0 + .byte 196,99,125,24,216,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm11 + .byte 196,193,36,84,193 // vandps %ymm9,%ymm11,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,99,117,24,193,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm8 + .byte 196,193,124,89,192 // vmulps %ymm8,%ymm0,%ymm0 + .byte 196,193,41,114,209,8 // vpsrld $0x8,%xmm9,%xmm10 + .byte 196,99,125,25,203,1 // vextractf128 $0x1,%ymm9,%xmm3 + .byte 197,241,114,211,8 // vpsrld $0x8,%xmm3,%xmm1 + .byte 196,227,45,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm10,%ymm1 + .byte 197,164,84,201 // vandps %ymm1,%ymm11,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 196,193,116,89,200 // vmulps %ymm8,%ymm1,%ymm1 + .byte 196,193,41,114,209,16 // vpsrld $0x10,%xmm9,%xmm10 + .byte 197,233,114,211,16 // vpsrld $0x10,%xmm3,%xmm2 + .byte 196,227,45,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm10,%ymm2 + .byte 197,164,84,210 // vandps %ymm2,%ymm11,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 196,193,108,89,208 // vmulps %ymm8,%ymm2,%ymm2 + .byte 196,193,49,114,209,24 // vpsrld $0x18,%xmm9,%xmm9 + .byte 197,225,114,211,24 // vpsrld $0x18,%xmm3,%xmm3 + .byte 196,227,53,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm9,%ymm3 + .byte 197,252,91,219 // vcvtdq2ps %ymm3,%ymm3 + .byte 196,193,100,89,216 // vmulps %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 196,65,52,87,201 // vxorps %ymm9,%ymm9,%ymm9 + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 15,135,80,255,255,255 // ja 2d5c <_sk_load_8888_avx+0x14> + .byte 69,15,182,192 // movzbl %r8b,%r8d + .byte 76,141,13,137,0,0,0 // lea 0x89(%rip),%r9 # 2ea0 <_sk_load_8888_avx+0x158> + .byte 75,99,4,129 // movslq (%r9,%r8,4),%rax + .byte 76,1,200 // add %r9,%rax + .byte 255,224 // jmpq *%rax + .byte 196,193,121,110,68,186,24 // vmovd 0x18(%r10,%rdi,4),%xmm0 + .byte 197,249,112,192,68 // vpshufd $0x44,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 196,99,117,12,200,64 // vblendps $0x40,%ymm0,%ymm1,%ymm9 + .byte 196,99,125,25,200,1 // vextractf128 $0x1,%ymm9,%xmm0 + .byte 196,195,121,34,68,186,20,1 // vpinsrd $0x1,0x14(%r10,%rdi,4),%xmm0,%xmm0 + .byte 196,99,53,24,200,1 // vinsertf128 $0x1,%xmm0,%ymm9,%ymm9 + .byte 196,99,125,25,200,1 // vextractf128 $0x1,%ymm9,%xmm0 + .byte 196,195,121,34,68,186,16,0 // vpinsrd $0x0,0x10(%r10,%rdi,4),%xmm0,%xmm0 + .byte 196,99,53,24,200,1 // vinsertf128 $0x1,%xmm0,%ymm9,%ymm9 + .byte 196,195,49,34,68,186,12,3 // vpinsrd $0x3,0xc(%r10,%rdi,4),%xmm9,%xmm0 + .byte 196,99,53,12,200,15 // vblendps $0xf,%ymm0,%ymm9,%ymm9 + .byte 196,195,49,34,68,186,8,2 // vpinsrd $0x2,0x8(%r10,%rdi,4),%xmm9,%xmm0 + .byte 196,99,53,12,200,15 // vblendps $0xf,%ymm0,%ymm9,%ymm9 + .byte 196,195,49,34,68,186,4,1 // vpinsrd $0x1,0x4(%r10,%rdi,4),%xmm9,%xmm0 + .byte 196,99,53,12,200,15 // vblendps $0xf,%ymm0,%ymm9,%ymm9 + .byte 196,195,49,34,4,186,0 // vpinsrd $0x0,(%r10,%rdi,4),%xmm9,%xmm0 + .byte 196,99,53,12,200,15 // vblendps $0xf,%ymm0,%ymm9,%ymm9 + .byte 233,188,254,255,255 // jmpq 2d5c <_sk_load_8888_avx+0x14> + .byte 238 // out %al,(%dx) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,224 // jmpq *%rax + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,210 // callq *%rdx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,196 // inc %esp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,176,255,255,255,156 // pushq -0x63000001(%rax) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + .byte 128,255,255 // cmp $0xff,%bh + .byte 255 // .byte 0xff + +HIDDEN _sk_gather_8888_avx +.globl _sk_gather_8888_avx +_sk_gather_8888_avx: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,201 // vcvttps2dq %ymm1,%ymm1 + .byte 197,249,110,80,16 // vmovd 0x10(%rax),%xmm2 + .byte 197,249,112,210,0 // vpshufd $0x0,%xmm2,%xmm2 + .byte 196,226,105,64,217 // vpmulld %xmm1,%xmm2,%xmm3 + .byte 196,227,125,25,201,1 // vextractf128 $0x1,%ymm1,%xmm1 + .byte 196,226,105,64,201 // vpmulld %xmm1,%xmm2,%xmm1 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 196,227,125,25,194,1 // vextractf128 $0x1,%ymm0,%xmm2 + .byte 197,241,254,202 // vpaddd %xmm2,%xmm1,%xmm1 + .byte 196,225,249,126,200 // vmovq %xmm1,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,195,249,22,202,1 // vpextrq $0x1,%xmm1,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 197,225,254,192 // vpaddd %xmm0,%xmm3,%xmm0 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,222 // mov %ebx,%r14d + .byte 196,195,249,22,199,1 // vpextrq $0x1,%xmm0,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 196,129,121,110,4,176 // vmovd (%r8,%r14,4),%xmm0 + .byte 196,195,121,34,4,152,1 // vpinsrd $0x1,(%r8,%rbx,4),%xmm0,%xmm0 + .byte 196,131,121,34,4,160,2 // vpinsrd $0x2,(%r8,%r12,4),%xmm0,%xmm0 + .byte 196,3,121,34,4,184,3 // vpinsrd $0x3,(%r8,%r15,4),%xmm0,%xmm8 + .byte 196,129,121,110,4,136 // vmovd (%r8,%r9,4),%xmm0 + .byte 196,195,121,34,4,128,1 // vpinsrd $0x1,(%r8,%rax,4),%xmm0,%xmm0 + .byte 196,131,121,34,4,152,2 // vpinsrd $0x2,(%r8,%r11,4),%xmm0,%xmm0 + .byte 196,131,121,34,28,144,3 // vpinsrd $0x3,(%r8,%r10,4),%xmm0,%xmm3 + .byte 196,227,61,24,195,1 // vinsertf128 $0x1,%xmm3,%ymm8,%ymm0 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 197,249,112,201,0 // vpshufd $0x0,%xmm1,%xmm1 + .byte 196,99,117,24,217,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm11 + .byte 197,164,84,192 // vandps %ymm0,%ymm11,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,99,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm9 + .byte 196,193,124,89,193 // vmulps %ymm9,%ymm0,%ymm0 + .byte 196,193,41,114,208,8 // vpsrld $0x8,%xmm8,%xmm10 + .byte 197,241,114,211,8 // vpsrld $0x8,%xmm3,%xmm1 + .byte 196,227,45,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm10,%ymm1 + .byte 197,164,84,201 // vandps %ymm1,%ymm11,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 196,193,116,89,201 // vmulps %ymm9,%ymm1,%ymm1 + .byte 196,193,41,114,208,16 // vpsrld $0x10,%xmm8,%xmm10 + .byte 197,233,114,211,16 // vpsrld $0x10,%xmm3,%xmm2 + .byte 196,227,45,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm10,%ymm2 + .byte 197,164,84,210 // vandps %ymm2,%ymm11,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 196,193,108,89,209 // vmulps %ymm9,%ymm2,%ymm2 + .byte 196,193,57,114,208,24 // vpsrld $0x18,%xmm8,%xmm8 + .byte 197,225,114,211,24 // vpsrld $0x18,%xmm3,%xmm3 + .byte 196,227,61,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + .byte 197,252,91,219 // vcvtdq2ps %ymm3,%ymm3 + .byte 196,193,100,89,217 // vmulps %ymm9,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_8888_avx +.globl _sk_store_8888_avx +_sk_store_8888_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 184,0,0,127,67 // mov $0x437f0000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 196,65,125,91,201 // vcvtps2dq %ymm9,%ymm9 + .byte 197,60,89,209 // vmulps %ymm1,%ymm8,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,193,33,114,242,8 // vpslld $0x8,%xmm10,%xmm11 + .byte 196,67,125,25,210,1 // vextractf128 $0x1,%ymm10,%xmm10 + .byte 196,193,41,114,242,8 // vpslld $0x8,%xmm10,%xmm10 + .byte 196,67,37,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm11,%ymm10 + .byte 196,65,45,86,201 // vorpd %ymm9,%ymm10,%ymm9 + .byte 197,60,89,210 // vmulps %ymm2,%ymm8,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,193,33,114,242,16 // vpslld $0x10,%xmm10,%xmm11 + .byte 196,67,125,25,210,1 // vextractf128 $0x1,%ymm10,%xmm10 + .byte 196,193,41,114,242,16 // vpslld $0x10,%xmm10,%xmm10 + .byte 196,67,37,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm11,%ymm10 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 196,65,125,91,192 // vcvtps2dq %ymm8,%ymm8 + .byte 196,193,33,114,240,24 // vpslld $0x18,%xmm8,%xmm11 + .byte 196,67,125,25,192,1 // vextractf128 $0x1,%ymm8,%xmm8 + .byte 196,193,57,114,240,24 // vpslld $0x18,%xmm8,%xmm8 + .byte 196,67,37,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm11,%ymm8 + .byte 196,65,45,86,192 // vorpd %ymm8,%ymm10,%ymm8 + .byte 196,65,53,86,192 // vorpd %ymm8,%ymm9,%ymm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,10 // jne 30a1 <_sk_store_8888_avx+0xa4> + .byte 196,65,124,17,4,185 // vmovups %ymm8,(%r9,%rdi,4) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 65,128,224,7 // and $0x7,%r8b + .byte 65,254,200 // dec %r8b + .byte 65,128,248,6 // cmp $0x6,%r8b + .byte 119,236 // ja 309d <_sk_store_8888_avx+0xa0> + .byte 65,15,182,192 // movzbl %r8b,%eax + .byte 76,141,5,84,0,0,0 // lea 0x54(%rip),%r8 # 3110 <_sk_store_8888_avx+0x113> + .byte 73,99,4,128 // movslq (%r8,%rax,4),%rax + .byte 76,1,192 // add %r8,%rax + .byte 255,224 // jmpq *%rax + .byte 196,67,125,25,193,1 // vextractf128 $0x1,%ymm8,%xmm9 + .byte 196,67,121,22,76,185,24,2 // vpextrd $0x2,%xmm9,0x18(%r9,%rdi,4) + .byte 196,67,125,25,193,1 // vextractf128 $0x1,%ymm8,%xmm9 + .byte 196,67,121,22,76,185,20,1 // vpextrd $0x1,%xmm9,0x14(%r9,%rdi,4) + .byte 196,67,125,25,193,1 // vextractf128 $0x1,%ymm8,%xmm9 + .byte 196,65,122,17,76,185,16 // vmovss %xmm9,0x10(%r9,%rdi,4) + .byte 196,67,121,22,68,185,12,3 // vpextrd $0x3,%xmm8,0xc(%r9,%rdi,4) + .byte 196,67,121,22,68,185,8,2 // vpextrd $0x2,%xmm8,0x8(%r9,%rdi,4) + .byte 196,67,121,22,68,185,4,1 // vpextrd $0x1,%xmm8,0x4(%r9,%rdi,4) + .byte 196,65,121,126,4,185 // vmovd %xmm8,(%r9,%rdi,4) + .byte 235,143 // jmp 309d <_sk_store_8888_avx+0xa0> + .byte 102,144 // xchg %ax,%ax + .byte 246,255 // idiv %bh + .byte 255 // (bad) + .byte 255 // (bad) + .byte 238 // out %al,(%dx) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,230 // jmpq *%rsi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 222,255 // fdivrp %st,%st(7) + .byte 255 // (bad) + .byte 255,209 // callq *%rcx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,195 // inc %ebx + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + .byte 181,255 // mov $0xff,%ch + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_load_f16_avx +.globl _sk_load_f16_avx +_sk_load_f16_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,17,1,0,0 // jne 324b <_sk_load_f16_avx+0x11f> + .byte 197,121,16,4,248 // vmovupd (%rax,%rdi,8),%xmm8 + .byte 197,249,16,84,248,16 // vmovupd 0x10(%rax,%rdi,8),%xmm2 + .byte 197,249,16,92,248,32 // vmovupd 0x20(%rax,%rdi,8),%xmm3 + .byte 197,122,111,76,248,48 // vmovdqu 0x30(%rax,%rdi,8),%xmm9 + .byte 197,185,97,194 // vpunpcklwd %xmm2,%xmm8,%xmm0 + .byte 197,185,105,210 // vpunpckhwd %xmm2,%xmm8,%xmm2 + .byte 196,193,97,97,201 // vpunpcklwd %xmm9,%xmm3,%xmm1 + .byte 196,193,97,105,217 // vpunpckhwd %xmm9,%xmm3,%xmm3 + .byte 197,121,97,218 // vpunpcklwd %xmm2,%xmm0,%xmm11 + .byte 197,121,105,194 // vpunpckhwd %xmm2,%xmm0,%xmm8 + .byte 197,241,97,211 // vpunpcklwd %xmm3,%xmm1,%xmm2 + .byte 197,113,105,203 // vpunpckhwd %xmm3,%xmm1,%xmm9 + .byte 197,161,108,194 // vpunpcklqdq %xmm2,%xmm11,%xmm0 + .byte 184,0,4,0,4 // mov $0x4000400,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 197,121,112,233,0 // vpshufd $0x0,%xmm1,%xmm13 + .byte 197,145,101,200 // vpcmpgtw %xmm0,%xmm13,%xmm1 + .byte 197,241,223,192 // vpandn %xmm0,%xmm1,%xmm0 + .byte 196,226,121,51,200 // vpmovzxwd %xmm0,%xmm1 + .byte 196,65,41,239,210 // vpxor %xmm10,%xmm10,%xmm10 + .byte 196,193,121,105,194 // vpunpckhwd %xmm10,%xmm0,%xmm0 + .byte 197,241,114,241,13 // vpslld $0xd,%xmm1,%xmm1 + .byte 197,249,114,240,13 // vpslld $0xd,%xmm0,%xmm0 + .byte 196,227,117,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm1,%ymm0 + .byte 184,0,0,128,119 // mov $0x77800000,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 197,249,112,201,0 // vpshufd $0x0,%xmm1,%xmm1 + .byte 196,99,117,24,225,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm12 + .byte 197,156,89,192 // vmulps %ymm0,%ymm12,%ymm0 + .byte 197,161,109,202 // vpunpckhqdq %xmm2,%xmm11,%xmm1 + .byte 197,145,101,209 // vpcmpgtw %xmm1,%xmm13,%xmm2 + .byte 197,233,223,201 // vpandn %xmm1,%xmm2,%xmm1 + .byte 196,226,121,51,209 // vpmovzxwd %xmm1,%xmm2 + .byte 196,193,113,105,202 // vpunpckhwd %xmm10,%xmm1,%xmm1 + .byte 197,233,114,242,13 // vpslld $0xd,%xmm2,%xmm2 + .byte 197,241,114,241,13 // vpslld $0xd,%xmm1,%xmm1 + .byte 196,227,109,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm2,%ymm1 + .byte 197,156,89,201 // vmulps %ymm1,%ymm12,%ymm1 + .byte 196,193,57,108,209 // vpunpcklqdq %xmm9,%xmm8,%xmm2 + .byte 197,145,101,218 // vpcmpgtw %xmm2,%xmm13,%xmm3 + .byte 197,225,223,210 // vpandn %xmm2,%xmm3,%xmm2 + .byte 196,226,121,51,218 // vpmovzxwd %xmm2,%xmm3 + .byte 196,193,105,105,210 // vpunpckhwd %xmm10,%xmm2,%xmm2 + .byte 197,225,114,243,13 // vpslld $0xd,%xmm3,%xmm3 + .byte 197,233,114,242,13 // vpslld $0xd,%xmm2,%xmm2 + .byte 196,227,101,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm3,%ymm2 + .byte 197,156,89,210 // vmulps %ymm2,%ymm12,%ymm2 + .byte 196,65,57,109,193 // vpunpckhqdq %xmm9,%xmm8,%xmm8 + .byte 196,193,17,101,216 // vpcmpgtw %xmm8,%xmm13,%xmm3 + .byte 196,193,97,223,216 // vpandn %xmm8,%xmm3,%xmm3 + .byte 196,98,121,51,195 // vpmovzxwd %xmm3,%xmm8 + .byte 196,193,97,105,218 // vpunpckhwd %xmm10,%xmm3,%xmm3 + .byte 196,193,57,114,240,13 // vpslld $0xd,%xmm8,%xmm8 + .byte 197,225,114,243,13 // vpslld $0xd,%xmm3,%xmm3 + .byte 196,227,61,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + .byte 197,156,89,219 // vmulps %ymm3,%ymm12,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 197,123,16,4,248 // vmovsd (%rax,%rdi,8),%xmm8 + .byte 196,65,49,239,201 // vpxor %xmm9,%xmm9,%xmm9 + .byte 72,131,249,1 // cmp $0x1,%rcx + .byte 116,79 // je 32aa <_sk_load_f16_avx+0x17e> + .byte 197,57,22,68,248,8 // vmovhpd 0x8(%rax,%rdi,8),%xmm8,%xmm8 + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 114,67 // jb 32aa <_sk_load_f16_avx+0x17e> + .byte 197,251,16,84,248,16 // vmovsd 0x10(%rax,%rdi,8),%xmm2 + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 116,68 // je 32b7 <_sk_load_f16_avx+0x18b> + .byte 197,233,22,84,248,24 // vmovhpd 0x18(%rax,%rdi,8),%xmm2,%xmm2 + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 114,56 // jb 32b7 <_sk_load_f16_avx+0x18b> + .byte 197,251,16,92,248,32 // vmovsd 0x20(%rax,%rdi,8),%xmm3 + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 15,132,194,254,255,255 // je 3151 <_sk_load_f16_avx+0x25> + .byte 197,225,22,92,248,40 // vmovhpd 0x28(%rax,%rdi,8),%xmm3,%xmm3 + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 15,130,178,254,255,255 // jb 3151 <_sk_load_f16_avx+0x25> + .byte 197,122,126,76,248,48 // vmovq 0x30(%rax,%rdi,8),%xmm9 + .byte 233,167,254,255,255 // jmpq 3151 <_sk_load_f16_avx+0x25> + .byte 197,225,87,219 // vxorpd %xmm3,%xmm3,%xmm3 + .byte 197,233,87,210 // vxorpd %xmm2,%xmm2,%xmm2 + .byte 233,154,254,255,255 // jmpq 3151 <_sk_load_f16_avx+0x25> + .byte 197,225,87,219 // vxorpd %xmm3,%xmm3,%xmm3 + .byte 233,145,254,255,255 // jmpq 3151 <_sk_load_f16_avx+0x25> + +HIDDEN _sk_gather_f16_avx +.globl _sk_gather_f16_avx +_sk_gather_f16_avx: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 197,254,91,209 // vcvttps2dq %ymm1,%ymm2 + .byte 197,249,110,72,16 // vmovd 0x10(%rax),%xmm1 + .byte 197,249,112,217,0 // vpshufd $0x0,%xmm1,%xmm3 + .byte 196,226,97,64,202 // vpmulld %xmm2,%xmm3,%xmm1 + .byte 196,227,125,25,210,1 // vextractf128 $0x1,%ymm2,%xmm2 + .byte 196,226,97,64,210 // vpmulld %xmm2,%xmm3,%xmm2 + .byte 197,254,91,192 // vcvttps2dq %ymm0,%ymm0 + .byte 196,227,125,25,195,1 // vextractf128 $0x1,%ymm0,%xmm3 + .byte 197,233,254,211 // vpaddd %xmm3,%xmm2,%xmm2 + .byte 196,227,249,22,208,1 // vpextrq $0x1,%xmm2,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 196,193,249,126,210 // vmovq %xmm2,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 197,241,254,192 // vpaddd %xmm0,%xmm1,%xmm0 + .byte 196,225,249,126,195 // vmovq %xmm0,%rbx + .byte 65,137,222 // mov %ebx,%r14d + .byte 196,195,249,22,199,1 // vpextrq $0x1,%xmm0,%r15 + .byte 69,137,252 // mov %r15d,%r12d + .byte 73,193,239,32 // shr $0x20,%r15 + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 196,193,122,126,4,216 // vmovq (%r8,%rbx,8),%xmm0 + .byte 196,129,122,126,12,240 // vmovq (%r8,%r14,8),%xmm1 + .byte 197,113,108,200 // vpunpcklqdq %xmm0,%xmm1,%xmm9 + .byte 196,129,122,126,12,248 // vmovq (%r8,%r15,8),%xmm1 + .byte 196,129,122,126,20,224 // vmovq (%r8,%r12,8),%xmm2 + .byte 197,233,108,201 // vpunpcklqdq %xmm1,%xmm2,%xmm1 + .byte 196,129,122,126,20,208 // vmovq (%r8,%r10,8),%xmm2 + .byte 196,129,122,126,28,216 // vmovq (%r8,%r11,8),%xmm3 + .byte 197,97,108,210 // vpunpcklqdq %xmm2,%xmm3,%xmm10 + .byte 196,65,122,126,4,192 // vmovq (%r8,%rax,8),%xmm8 + .byte 196,129,122,126,28,200 // vmovq (%r8,%r9,8),%xmm3 + .byte 196,193,97,108,216 // vpunpcklqdq %xmm8,%xmm3,%xmm3 + .byte 197,177,97,193 // vpunpcklwd %xmm1,%xmm9,%xmm0 + .byte 197,177,105,201 // vpunpckhwd %xmm1,%xmm9,%xmm1 + .byte 197,169,97,211 // vpunpcklwd %xmm3,%xmm10,%xmm2 + .byte 197,169,105,219 // vpunpckhwd %xmm3,%xmm10,%xmm3 + .byte 197,121,97,217 // vpunpcklwd %xmm1,%xmm0,%xmm11 + .byte 197,121,105,193 // vpunpckhwd %xmm1,%xmm0,%xmm8 + .byte 197,233,97,203 // vpunpcklwd %xmm3,%xmm2,%xmm1 + .byte 197,105,105,203 // vpunpckhwd %xmm3,%xmm2,%xmm9 + .byte 197,161,108,193 // vpunpcklqdq %xmm1,%xmm11,%xmm0 + .byte 184,0,4,0,4 // mov $0x4000400,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 197,121,112,234,0 // vpshufd $0x0,%xmm2,%xmm13 + .byte 197,145,101,208 // vpcmpgtw %xmm0,%xmm13,%xmm2 + .byte 197,233,223,192 // vpandn %xmm0,%xmm2,%xmm0 + .byte 196,226,121,51,208 // vpmovzxwd %xmm0,%xmm2 + .byte 196,65,41,239,210 // vpxor %xmm10,%xmm10,%xmm10 + .byte 196,193,121,105,194 // vpunpckhwd %xmm10,%xmm0,%xmm0 + .byte 197,233,114,242,13 // vpslld $0xd,%xmm2,%xmm2 + .byte 197,249,114,240,13 // vpslld $0xd,%xmm0,%xmm0 + .byte 196,227,109,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm2,%ymm0 + .byte 184,0,0,128,119 // mov $0x77800000,%eax + .byte 197,249,110,208 // vmovd %eax,%xmm2 + .byte 197,249,112,210,0 // vpshufd $0x0,%xmm2,%xmm2 + .byte 196,99,109,24,226,1 // vinsertf128 $0x1,%xmm2,%ymm2,%ymm12 + .byte 197,156,89,192 // vmulps %ymm0,%ymm12,%ymm0 + .byte 197,161,109,201 // vpunpckhqdq %xmm1,%xmm11,%xmm1 + .byte 197,145,101,209 // vpcmpgtw %xmm1,%xmm13,%xmm2 + .byte 197,233,223,201 // vpandn %xmm1,%xmm2,%xmm1 + .byte 196,226,121,51,209 // vpmovzxwd %xmm1,%xmm2 + .byte 196,193,113,105,202 // vpunpckhwd %xmm10,%xmm1,%xmm1 + .byte 197,233,114,242,13 // vpslld $0xd,%xmm2,%xmm2 + .byte 197,241,114,241,13 // vpslld $0xd,%xmm1,%xmm1 + .byte 196,227,109,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm2,%ymm1 + .byte 197,156,89,201 // vmulps %ymm1,%ymm12,%ymm1 + .byte 196,193,57,108,209 // vpunpcklqdq %xmm9,%xmm8,%xmm2 + .byte 197,145,101,218 // vpcmpgtw %xmm2,%xmm13,%xmm3 + .byte 197,225,223,210 // vpandn %xmm2,%xmm3,%xmm2 + .byte 196,226,121,51,218 // vpmovzxwd %xmm2,%xmm3 + .byte 196,193,105,105,210 // vpunpckhwd %xmm10,%xmm2,%xmm2 + .byte 197,225,114,243,13 // vpslld $0xd,%xmm3,%xmm3 + .byte 197,233,114,242,13 // vpslld $0xd,%xmm2,%xmm2 + .byte 196,227,101,24,210,1 // vinsertf128 $0x1,%xmm2,%ymm3,%ymm2 + .byte 197,156,89,210 // vmulps %ymm2,%ymm12,%ymm2 + .byte 196,65,57,109,193 // vpunpckhqdq %xmm9,%xmm8,%xmm8 + .byte 196,193,17,101,216 // vpcmpgtw %xmm8,%xmm13,%xmm3 + .byte 196,193,97,223,216 // vpandn %xmm8,%xmm3,%xmm3 + .byte 196,98,121,51,195 // vpmovzxwd %xmm3,%xmm8 + .byte 196,193,97,105,218 // vpunpckhwd %xmm10,%xmm3,%xmm3 + .byte 196,193,57,114,240,13 // vpslld $0xd,%xmm8,%xmm8 + .byte 197,225,114,243,13 // vpslld $0xd,%xmm3,%xmm3 + .byte 196,227,61,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + .byte 197,156,89,219 // vmulps %ymm3,%ymm12,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_f16_avx +.globl _sk_store_f16_avx +_sk_store_f16_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 184,0,0,128,7 // mov $0x7800000,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,65,121,112,192,0 // vpshufd $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 196,67,125,25,202,1 // vextractf128 $0x1,%ymm9,%xmm10 + .byte 196,193,41,114,210,13 // vpsrld $0xd,%xmm10,%xmm10 + .byte 196,193,49,114,209,13 // vpsrld $0xd,%xmm9,%xmm9 + .byte 196,66,49,43,202 // vpackusdw %xmm10,%xmm9,%xmm9 + .byte 197,60,89,209 // vmulps %ymm1,%ymm8,%ymm10 + .byte 196,67,125,25,211,1 // vextractf128 $0x1,%ymm10,%xmm11 + .byte 196,193,33,114,211,13 // vpsrld $0xd,%xmm11,%xmm11 + .byte 196,193,41,114,210,13 // vpsrld $0xd,%xmm10,%xmm10 + .byte 196,66,41,43,211 // vpackusdw %xmm11,%xmm10,%xmm10 + .byte 197,60,89,218 // vmulps %ymm2,%ymm8,%ymm11 + .byte 196,67,125,25,220,1 // vextractf128 $0x1,%ymm11,%xmm12 + .byte 196,193,25,114,212,13 // vpsrld $0xd,%xmm12,%xmm12 + .byte 196,193,33,114,211,13 // vpsrld $0xd,%xmm11,%xmm11 + .byte 196,66,33,43,220 // vpackusdw %xmm12,%xmm11,%xmm11 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 196,67,125,25,196,1 // vextractf128 $0x1,%ymm8,%xmm12 + .byte 196,193,25,114,212,13 // vpsrld $0xd,%xmm12,%xmm12 + .byte 196,193,57,114,208,13 // vpsrld $0xd,%xmm8,%xmm8 + .byte 196,66,57,43,196 // vpackusdw %xmm12,%xmm8,%xmm8 + .byte 196,65,49,97,226 // vpunpcklwd %xmm10,%xmm9,%xmm12 + .byte 196,65,49,105,234 // vpunpckhwd %xmm10,%xmm9,%xmm13 + .byte 196,65,33,97,200 // vpunpcklwd %xmm8,%xmm11,%xmm9 + .byte 196,65,33,105,192 // vpunpckhwd %xmm8,%xmm11,%xmm8 + .byte 196,65,25,98,217 // vpunpckldq %xmm9,%xmm12,%xmm11 + .byte 196,65,25,106,209 // vpunpckhdq %xmm9,%xmm12,%xmm10 + .byte 196,65,17,98,200 // vpunpckldq %xmm8,%xmm13,%xmm9 + .byte 196,65,17,106,192 // vpunpckhdq %xmm8,%xmm13,%xmm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,31 // jne 3540 <_sk_store_f16_avx+0xd2> + .byte 196,65,120,17,28,248 // vmovups %xmm11,(%r8,%rdi,8) + .byte 196,65,120,17,84,248,16 // vmovups %xmm10,0x10(%r8,%rdi,8) + .byte 196,65,120,17,76,248,32 // vmovups %xmm9,0x20(%r8,%rdi,8) + .byte 196,65,122,127,68,248,48 // vmovdqu %xmm8,0x30(%r8,%rdi,8) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 196,65,121,214,28,248 // vmovq %xmm11,(%r8,%rdi,8) + .byte 72,131,249,1 // cmp $0x1,%rcx + .byte 116,240 // je 353c <_sk_store_f16_avx+0xce> + .byte 196,65,121,23,92,248,8 // vmovhpd %xmm11,0x8(%r8,%rdi,8) + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 114,227 // jb 353c <_sk_store_f16_avx+0xce> + .byte 196,65,121,214,84,248,16 // vmovq %xmm10,0x10(%r8,%rdi,8) + .byte 116,218 // je 353c <_sk_store_f16_avx+0xce> + .byte 196,65,121,23,84,248,24 // vmovhpd %xmm10,0x18(%r8,%rdi,8) + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 114,205 // jb 353c <_sk_store_f16_avx+0xce> + .byte 196,65,121,214,76,248,32 // vmovq %xmm9,0x20(%r8,%rdi,8) + .byte 116,196 // je 353c <_sk_store_f16_avx+0xce> + .byte 196,65,121,23,76,248,40 // vmovhpd %xmm9,0x28(%r8,%rdi,8) + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 114,183 // jb 353c <_sk_store_f16_avx+0xce> + .byte 196,65,121,214,68,248,48 // vmovq %xmm8,0x30(%r8,%rdi,8) + .byte 235,174 // jmp 353c <_sk_store_f16_avx+0xce> + +HIDDEN _sk_load_u16_be_avx +.globl _sk_load_u16_be_avx +_sk_load_u16_be_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,133,201 // test %rcx,%rcx + .byte 15,133,1,1,0,0 // jne 369d <_sk_load_u16_be_avx+0x10f> + .byte 197,121,16,4,248 // vmovupd (%rax,%rdi,8),%xmm8 + .byte 197,249,16,84,248,16 // vmovupd 0x10(%rax,%rdi,8),%xmm2 + .byte 197,249,16,92,248,32 // vmovupd 0x20(%rax,%rdi,8),%xmm3 + .byte 197,122,111,76,248,48 // vmovdqu 0x30(%rax,%rdi,8),%xmm9 + .byte 197,185,97,194 // vpunpcklwd %xmm2,%xmm8,%xmm0 + .byte 197,185,105,210 // vpunpckhwd %xmm2,%xmm8,%xmm2 + .byte 196,193,97,97,201 // vpunpcklwd %xmm9,%xmm3,%xmm1 + .byte 196,193,97,105,217 // vpunpckhwd %xmm9,%xmm3,%xmm3 + .byte 197,121,97,210 // vpunpcklwd %xmm2,%xmm0,%xmm10 + .byte 197,121,105,194 // vpunpckhwd %xmm2,%xmm0,%xmm8 + .byte 197,241,97,211 // vpunpcklwd %xmm3,%xmm1,%xmm2 + .byte 197,113,105,203 // vpunpckhwd %xmm3,%xmm1,%xmm9 + .byte 184,128,0,128,55 // mov $0x37800080,%eax + .byte 197,249,110,192 // vmovd %eax,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,99,125,24,224,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm12 + .byte 197,169,108,194 // vpunpcklqdq %xmm2,%xmm10,%xmm0 + .byte 197,241,113,240,8 // vpsllw $0x8,%xmm0,%xmm1 + .byte 197,249,113,208,8 // vpsrlw $0x8,%xmm0,%xmm0 + .byte 197,241,235,192 // vpor %xmm0,%xmm1,%xmm0 + .byte 196,65,33,239,219 // vpxor %xmm11,%xmm11,%xmm11 + .byte 196,193,121,105,203 // vpunpckhwd %xmm11,%xmm0,%xmm1 + .byte 196,226,121,51,192 // vpmovzxwd %xmm0,%xmm0 + .byte 196,227,125,24,193,1 // vinsertf128 $0x1,%xmm1,%ymm0,%ymm0 + .byte 197,252,91,192 // vcvtdq2ps %ymm0,%ymm0 + .byte 197,156,89,192 // vmulps %ymm0,%ymm12,%ymm0 + .byte 197,169,109,202 // vpunpckhqdq %xmm2,%xmm10,%xmm1 + .byte 197,233,113,241,8 // vpsllw $0x8,%xmm1,%xmm2 + .byte 197,241,113,209,8 // vpsrlw $0x8,%xmm1,%xmm1 + .byte 197,233,235,201 // vpor %xmm1,%xmm2,%xmm1 + .byte 196,193,113,105,211 // vpunpckhwd %xmm11,%xmm1,%xmm2 + .byte 196,226,121,51,201 // vpmovzxwd %xmm1,%xmm1 + .byte 196,227,117,24,202,1 // vinsertf128 $0x1,%xmm2,%ymm1,%ymm1 + .byte 197,252,91,201 // vcvtdq2ps %ymm1,%ymm1 + .byte 197,156,89,201 // vmulps %ymm1,%ymm12,%ymm1 + .byte 196,193,57,108,209 // vpunpcklqdq %xmm9,%xmm8,%xmm2 + .byte 197,169,113,242,8 // vpsllw $0x8,%xmm2,%xmm10 + .byte 197,233,113,210,8 // vpsrlw $0x8,%xmm2,%xmm2 + .byte 197,169,235,210 // vpor %xmm2,%xmm10,%xmm2 + .byte 196,65,105,105,211 // vpunpckhwd %xmm11,%xmm2,%xmm10 + .byte 196,226,121,51,210 // vpmovzxwd %xmm2,%xmm2 + .byte 196,195,109,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm2,%ymm2 + .byte 197,252,91,210 // vcvtdq2ps %ymm2,%ymm2 + .byte 197,156,89,210 // vmulps %ymm2,%ymm12,%ymm2 + .byte 196,193,57,109,217 // vpunpckhqdq %xmm9,%xmm8,%xmm3 + .byte 197,185,113,243,8 // vpsllw $0x8,%xmm3,%xmm8 + .byte 197,225,113,211,8 // vpsrlw $0x8,%xmm3,%xmm3 + .byte 197,185,235,219 // vpor %xmm3,%xmm8,%xmm3 + .byte 196,65,97,105,195 // vpunpckhwd %xmm11,%xmm3,%xmm8 + .byte 196,226,121,51,219 // vpmovzxwd %xmm3,%xmm3 + .byte 196,195,101,24,216,1 // vinsertf128 $0x1,%xmm8,%ymm3,%ymm3 + .byte 197,252,91,219 // vcvtdq2ps %ymm3,%ymm3 + .byte 197,156,89,219 // vmulps %ymm3,%ymm12,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 197,123,16,4,248 // vmovsd (%rax,%rdi,8),%xmm8 + .byte 196,65,49,239,201 // vpxor %xmm9,%xmm9,%xmm9 + .byte 72,131,249,1 // cmp $0x1,%rcx + .byte 116,79 // je 36fc <_sk_load_u16_be_avx+0x16e> + .byte 197,57,22,68,248,8 // vmovhpd 0x8(%rax,%rdi,8),%xmm8,%xmm8 + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 114,67 // jb 36fc <_sk_load_u16_be_avx+0x16e> + .byte 197,251,16,84,248,16 // vmovsd 0x10(%rax,%rdi,8),%xmm2 + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 116,68 // je 3709 <_sk_load_u16_be_avx+0x17b> + .byte 197,233,22,84,248,24 // vmovhpd 0x18(%rax,%rdi,8),%xmm2,%xmm2 + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 114,56 // jb 3709 <_sk_load_u16_be_avx+0x17b> + .byte 197,251,16,92,248,32 // vmovsd 0x20(%rax,%rdi,8),%xmm3 + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 15,132,210,254,255,255 // je 35b3 <_sk_load_u16_be_avx+0x25> + .byte 197,225,22,92,248,40 // vmovhpd 0x28(%rax,%rdi,8),%xmm3,%xmm3 + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 15,130,194,254,255,255 // jb 35b3 <_sk_load_u16_be_avx+0x25> + .byte 197,122,126,76,248,48 // vmovq 0x30(%rax,%rdi,8),%xmm9 + .byte 233,183,254,255,255 // jmpq 35b3 <_sk_load_u16_be_avx+0x25> + .byte 197,225,87,219 // vxorpd %xmm3,%xmm3,%xmm3 + .byte 197,233,87,210 // vxorpd %xmm2,%xmm2,%xmm2 + .byte 233,170,254,255,255 // jmpq 35b3 <_sk_load_u16_be_avx+0x25> + .byte 197,225,87,219 // vxorpd %xmm3,%xmm3,%xmm3 + .byte 233,161,254,255,255 // jmpq 35b3 <_sk_load_u16_be_avx+0x25> + +HIDDEN _sk_store_u16_be_avx +.globl _sk_store_u16_be_avx +_sk_store_u16_be_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 184,0,255,127,71 // mov $0x477fff00,%eax + .byte 197,121,110,192 // vmovd %eax,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 196,65,125,91,201 // vcvtps2dq %ymm9,%ymm9 + .byte 196,67,125,25,202,1 // vextractf128 $0x1,%ymm9,%xmm10 + .byte 196,66,49,43,202 // vpackusdw %xmm10,%xmm9,%xmm9 + .byte 196,193,41,113,241,8 // vpsllw $0x8,%xmm9,%xmm10 + .byte 196,193,49,113,209,8 // vpsrlw $0x8,%xmm9,%xmm9 + .byte 196,65,41,235,201 // vpor %xmm9,%xmm10,%xmm9 + .byte 197,60,89,209 // vmulps %ymm1,%ymm8,%ymm10 + .byte 196,65,125,91,210 // vcvtps2dq %ymm10,%ymm10 + .byte 196,67,125,25,211,1 // vextractf128 $0x1,%ymm10,%xmm11 + .byte 196,66,41,43,211 // vpackusdw %xmm11,%xmm10,%xmm10 + .byte 196,193,33,113,242,8 // vpsllw $0x8,%xmm10,%xmm11 + .byte 196,193,41,113,210,8 // vpsrlw $0x8,%xmm10,%xmm10 + .byte 196,65,33,235,210 // vpor %xmm10,%xmm11,%xmm10 + .byte 197,60,89,218 // vmulps %ymm2,%ymm8,%ymm11 + .byte 196,65,125,91,219 // vcvtps2dq %ymm11,%ymm11 + .byte 196,67,125,25,220,1 // vextractf128 $0x1,%ymm11,%xmm12 + .byte 196,66,33,43,220 // vpackusdw %xmm12,%xmm11,%xmm11 + .byte 196,193,25,113,243,8 // vpsllw $0x8,%xmm11,%xmm12 + .byte 196,193,33,113,211,8 // vpsrlw $0x8,%xmm11,%xmm11 + .byte 196,65,25,235,219 // vpor %xmm11,%xmm12,%xmm11 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 196,65,125,91,192 // vcvtps2dq %ymm8,%ymm8 + .byte 196,67,125,25,196,1 // vextractf128 $0x1,%ymm8,%xmm12 + .byte 196,66,57,43,196 // vpackusdw %xmm12,%xmm8,%xmm8 + .byte 196,193,25,113,240,8 // vpsllw $0x8,%xmm8,%xmm12 + .byte 196,193,57,113,208,8 // vpsrlw $0x8,%xmm8,%xmm8 + .byte 196,65,25,235,192 // vpor %xmm8,%xmm12,%xmm8 + .byte 196,65,49,97,226 // vpunpcklwd %xmm10,%xmm9,%xmm12 + .byte 196,65,49,105,234 // vpunpckhwd %xmm10,%xmm9,%xmm13 + .byte 196,65,33,97,200 // vpunpcklwd %xmm8,%xmm11,%xmm9 + .byte 196,65,33,105,192 // vpunpckhwd %xmm8,%xmm11,%xmm8 + .byte 196,65,25,98,217 // vpunpckldq %xmm9,%xmm12,%xmm11 + .byte 196,65,25,106,209 // vpunpckhdq %xmm9,%xmm12,%xmm10 + .byte 196,65,17,98,200 // vpunpckldq %xmm8,%xmm13,%xmm9 + .byte 196,65,17,106,192 // vpunpckhdq %xmm8,%xmm13,%xmm8 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,31 // jne 380c <_sk_store_u16_be_avx+0xfa> + .byte 196,65,120,17,28,248 // vmovups %xmm11,(%r8,%rdi,8) + .byte 196,65,120,17,84,248,16 // vmovups %xmm10,0x10(%r8,%rdi,8) + .byte 196,65,120,17,76,248,32 // vmovups %xmm9,0x20(%r8,%rdi,8) + .byte 196,65,122,127,68,248,48 // vmovdqu %xmm8,0x30(%r8,%rdi,8) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 196,65,121,214,28,248 // vmovq %xmm11,(%r8,%rdi,8) + .byte 72,131,249,1 // cmp $0x1,%rcx + .byte 116,240 // je 3808 <_sk_store_u16_be_avx+0xf6> + .byte 196,65,121,23,92,248,8 // vmovhpd %xmm11,0x8(%r8,%rdi,8) + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 114,227 // jb 3808 <_sk_store_u16_be_avx+0xf6> + .byte 196,65,121,214,84,248,16 // vmovq %xmm10,0x10(%r8,%rdi,8) + .byte 116,218 // je 3808 <_sk_store_u16_be_avx+0xf6> + .byte 196,65,121,23,84,248,24 // vmovhpd %xmm10,0x18(%r8,%rdi,8) + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 114,205 // jb 3808 <_sk_store_u16_be_avx+0xf6> + .byte 196,65,121,214,76,248,32 // vmovq %xmm9,0x20(%r8,%rdi,8) + .byte 116,196 // je 3808 <_sk_store_u16_be_avx+0xf6> + .byte 196,65,121,23,76,248,40 // vmovhpd %xmm9,0x28(%r8,%rdi,8) + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 114,183 // jb 3808 <_sk_store_u16_be_avx+0xf6> + .byte 196,65,121,214,68,248,48 // vmovq %xmm8,0x30(%r8,%rdi,8) + .byte 235,174 // jmp 3808 <_sk_store_u16_be_avx+0xf6> + +HIDDEN _sk_load_f32_avx +.globl _sk_load_f32_avx +_sk_load_f32_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 119,110 // ja 38d0 <_sk_load_f32_avx+0x76> + .byte 76,139,0 // mov (%rax),%r8 + .byte 76,141,12,189,0,0,0,0 // lea 0x0(,%rdi,4),%r9 + .byte 76,141,21,132,0,0,0 // lea 0x84(%rip),%r10 # 38f8 <_sk_load_f32_avx+0x9e> + .byte 73,99,4,138 // movslq (%r10,%rcx,4),%rax + .byte 76,1,208 // add %r10,%rax + .byte 255,224 // jmpq *%rax + .byte 196,3,125,24,68,136,112,1 // vinsertf128 $0x1,0x70(%r8,%r9,4),%ymm0,%ymm8 + .byte 196,131,125,24,92,136,96,1 // vinsertf128 $0x1,0x60(%r8,%r9,4),%ymm0,%ymm3 + .byte 196,131,125,24,76,136,80,1 // vinsertf128 $0x1,0x50(%r8,%r9,4),%ymm0,%ymm1 + .byte 196,131,125,24,84,136,64,1 // vinsertf128 $0x1,0x40(%r8,%r9,4),%ymm0,%ymm2 + .byte 196,129,121,16,68,136,48 // vmovupd 0x30(%r8,%r9,4),%xmm0 + .byte 196,195,125,13,192,12 // vblendpd $0xc,%ymm8,%ymm0,%ymm0 + .byte 196,1,121,16,68,136,32 // vmovupd 0x20(%r8,%r9,4),%xmm8 + .byte 196,99,61,13,203,12 // vblendpd $0xc,%ymm3,%ymm8,%ymm9 + .byte 196,129,121,16,92,136,16 // vmovupd 0x10(%r8,%r9,4),%xmm3 + .byte 196,99,101,13,209,12 // vblendpd $0xc,%ymm1,%ymm3,%ymm10 + .byte 196,129,121,16,12,136 // vmovupd (%r8,%r9,4),%xmm1 + .byte 196,227,117,13,202,12 // vblendpd $0xc,%ymm2,%ymm1,%ymm1 + .byte 196,193,116,20,210 // vunpcklps %ymm10,%ymm1,%ymm2 + .byte 196,193,116,21,218 // vunpckhps %ymm10,%ymm1,%ymm3 + .byte 197,180,20,200 // vunpcklps %ymm0,%ymm9,%ymm1 + .byte 197,52,21,192 // vunpckhps %ymm0,%ymm9,%ymm8 + .byte 197,237,20,193 // vunpcklpd %ymm1,%ymm2,%ymm0 + .byte 197,237,21,201 // vunpckhpd %ymm1,%ymm2,%ymm1 + .byte 196,193,101,20,208 // vunpcklpd %ymm8,%ymm3,%ymm2 + .byte 196,193,101,21,216 // vunpckhpd %ymm8,%ymm3,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 133,255 // test %edi,%edi + .byte 255 // (bad) + .byte 255,204 // dec %esp + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 191,255,255,255,178 // mov $0xb2ffffff,%edi + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,165,255,255,255,157 // jmpq *-0x62000001(%rbp) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255,149,255,255,255,141 // callq *-0x72000001(%rbp) + .byte 255 // (bad) + .byte 255 // (bad) + .byte 255 // .byte 0xff + +HIDDEN _sk_store_f32_avx +.globl _sk_store_f32_avx +_sk_store_f32_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,0 // mov (%rax),%r8 + .byte 72,141,4,189,0,0,0,0 // lea 0x0(,%rdi,4),%rax + .byte 197,124,20,193 // vunpcklps %ymm1,%ymm0,%ymm8 + .byte 197,124,21,217 // vunpckhps %ymm1,%ymm0,%ymm11 + .byte 197,108,20,203 // vunpcklps %ymm3,%ymm2,%ymm9 + .byte 197,108,21,227 // vunpckhps %ymm3,%ymm2,%ymm12 + .byte 196,65,61,20,209 // vunpcklpd %ymm9,%ymm8,%ymm10 + .byte 196,65,61,21,201 // vunpckhpd %ymm9,%ymm8,%ymm9 + .byte 196,65,37,20,196 // vunpcklpd %ymm12,%ymm11,%ymm8 + .byte 196,65,37,21,220 // vunpckhpd %ymm12,%ymm11,%ymm11 + .byte 72,133,201 // test %rcx,%rcx + .byte 117,55 // jne 3985 <_sk_store_f32_avx+0x6d> + .byte 196,67,45,24,225,1 // vinsertf128 $0x1,%xmm9,%ymm10,%ymm12 + .byte 196,67,61,24,235,1 // vinsertf128 $0x1,%xmm11,%ymm8,%ymm13 + .byte 196,67,45,6,201,49 // vperm2f128 $0x31,%ymm9,%ymm10,%ymm9 + .byte 196,67,61,6,195,49 // vperm2f128 $0x31,%ymm11,%ymm8,%ymm8 + .byte 196,65,125,17,36,128 // vmovupd %ymm12,(%r8,%rax,4) + .byte 196,65,125,17,108,128,32 // vmovupd %ymm13,0x20(%r8,%rax,4) + .byte 196,65,125,17,76,128,64 // vmovupd %ymm9,0x40(%r8,%rax,4) + .byte 196,65,125,17,68,128,96 // vmovupd %ymm8,0x60(%r8,%rax,4) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + .byte 196,65,121,17,20,128 // vmovupd %xmm10,(%r8,%rax,4) + .byte 72,131,249,1 // cmp $0x1,%rcx + .byte 116,240 // je 3981 <_sk_store_f32_avx+0x69> + .byte 196,65,121,17,76,128,16 // vmovupd %xmm9,0x10(%r8,%rax,4) + .byte 72,131,249,3 // cmp $0x3,%rcx + .byte 114,227 // jb 3981 <_sk_store_f32_avx+0x69> + .byte 196,65,121,17,68,128,32 // vmovupd %xmm8,0x20(%r8,%rax,4) + .byte 116,218 // je 3981 <_sk_store_f32_avx+0x69> + .byte 196,65,121,17,92,128,48 // vmovupd %xmm11,0x30(%r8,%rax,4) + .byte 72,131,249,5 // cmp $0x5,%rcx + .byte 114,205 // jb 3981 <_sk_store_f32_avx+0x69> + .byte 196,67,125,25,84,128,64,1 // vextractf128 $0x1,%ymm10,0x40(%r8,%rax,4) + .byte 116,195 // je 3981 <_sk_store_f32_avx+0x69> + .byte 196,67,125,25,76,128,80,1 // vextractf128 $0x1,%ymm9,0x50(%r8,%rax,4) + .byte 72,131,249,7 // cmp $0x7,%rcx + .byte 114,181 // jb 3981 <_sk_store_f32_avx+0x69> + .byte 196,67,125,25,68,128,96,1 // vextractf128 $0x1,%ymm8,0x60(%r8,%rax,4) + .byte 235,171 // jmp 3981 <_sk_store_f32_avx+0x69> + +HIDDEN _sk_clamp_x_avx +.globl _sk_clamp_x_avx +_sk_clamp_x_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 197,60,95,200 // vmaxps %ymm0,%ymm8,%ymm9 + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,99,125,25,192,1 // vextractf128 $0x1,%ymm8,%xmm0 + .byte 196,65,41,118,210 // vpcmpeqd %xmm10,%xmm10,%xmm10 + .byte 196,193,121,254,194 // vpaddd %xmm10,%xmm0,%xmm0 + .byte 196,65,57,254,194 // vpaddd %xmm10,%xmm8,%xmm8 + .byte 196,227,61,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm8,%ymm0 + .byte 197,180,93,192 // vminps %ymm0,%ymm9,%ymm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_y_avx +.globl _sk_clamp_y_avx +_sk_clamp_y_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 197,60,95,201 // vmaxps %ymm1,%ymm8,%ymm9 + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,99,125,25,193,1 // vextractf128 $0x1,%ymm8,%xmm1 + .byte 196,65,41,118,210 // vpcmpeqd %xmm10,%xmm10,%xmm10 + .byte 196,193,113,254,202 // vpaddd %xmm10,%xmm1,%xmm1 + .byte 196,65,57,254,194 // vpaddd %xmm10,%xmm8,%xmm8 + .byte 196,227,61,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm8,%ymm1 + .byte 197,180,93,201 // vminps %ymm1,%ymm9,%ymm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_repeat_x_avx +.globl _sk_repeat_x_avx +_sk_repeat_x_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,65,124,94,200 // vdivps %ymm8,%ymm0,%ymm9 + .byte 196,67,125,8,201,1 // vroundps $0x1,%ymm9,%ymm9 + .byte 196,65,52,89,200 // vmulps %ymm8,%ymm9,%ymm9 + .byte 196,65,124,92,201 // vsubps %ymm9,%ymm0,%ymm9 + .byte 196,99,125,25,192,1 // vextractf128 $0x1,%ymm8,%xmm0 + .byte 196,65,41,118,210 // vpcmpeqd %xmm10,%xmm10,%xmm10 + .byte 196,193,121,254,194 // vpaddd %xmm10,%xmm0,%xmm0 + .byte 196,65,57,254,194 // vpaddd %xmm10,%xmm8,%xmm8 + .byte 196,227,61,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm8,%ymm0 + .byte 197,180,93,192 // vminps %ymm0,%ymm9,%ymm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_repeat_y_avx +.globl _sk_repeat_y_avx +_sk_repeat_y_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,65,116,94,200 // vdivps %ymm8,%ymm1,%ymm9 + .byte 196,67,125,8,201,1 // vroundps $0x1,%ymm9,%ymm9 + .byte 196,65,52,89,200 // vmulps %ymm8,%ymm9,%ymm9 + .byte 196,65,116,92,201 // vsubps %ymm9,%ymm1,%ymm9 + .byte 196,99,125,25,193,1 // vextractf128 $0x1,%ymm8,%xmm1 + .byte 196,65,41,118,210 // vpcmpeqd %xmm10,%xmm10,%xmm10 + .byte 196,193,113,254,202 // vpaddd %xmm10,%xmm1,%xmm1 + .byte 196,65,57,254,194 // vpaddd %xmm10,%xmm8,%xmm8 + .byte 196,227,61,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm8,%ymm1 + .byte 197,180,93,201 // vminps %ymm1,%ymm9,%ymm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_mirror_x_avx +.globl _sk_mirror_x_avx +_sk_mirror_x_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,121,110,0 // vmovd (%rax),%xmm8 + .byte 196,65,121,112,200,0 // vpshufd $0x0,%xmm8,%xmm9 + .byte 196,67,53,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + .byte 196,65,124,92,209 // vsubps %ymm9,%ymm0,%ymm10 + .byte 196,193,58,88,192 // vaddss %xmm8,%xmm8,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,44,94,192 // vdivps %ymm0,%ymm10,%ymm8 + .byte 196,67,125,8,192,1 // vroundps $0x1,%ymm8,%ymm8 + .byte 197,188,89,192 // vmulps %ymm0,%ymm8,%ymm0 + .byte 197,172,92,192 // vsubps %ymm0,%ymm10,%ymm0 + .byte 196,193,124,92,193 // vsubps %ymm9,%ymm0,%ymm0 + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 197,60,92,192 // vsubps %ymm0,%ymm8,%ymm8 + .byte 197,60,84,192 // vandps %ymm0,%ymm8,%ymm8 + .byte 196,99,125,25,200,1 // vextractf128 $0x1,%ymm9,%xmm0 + .byte 196,65,41,118,210 // vpcmpeqd %xmm10,%xmm10,%xmm10 + .byte 196,193,121,254,194 // vpaddd %xmm10,%xmm0,%xmm0 + .byte 196,65,49,254,202 // vpaddd %xmm10,%xmm9,%xmm9 + .byte 196,227,53,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm9,%ymm0 + .byte 197,188,93,192 // vminps %ymm0,%ymm8,%ymm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_mirror_y_avx +.globl _sk_mirror_y_avx +_sk_mirror_y_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,121,110,0 // vmovd (%rax),%xmm8 + .byte 196,65,121,112,200,0 // vpshufd $0x0,%xmm8,%xmm9 + .byte 196,67,53,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + .byte 196,65,116,92,209 // vsubps %ymm9,%ymm1,%ymm10 + .byte 196,193,58,88,200 // vaddss %xmm8,%xmm8,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,44,94,193 // vdivps %ymm1,%ymm10,%ymm8 + .byte 196,67,125,8,192,1 // vroundps $0x1,%ymm8,%ymm8 + .byte 197,188,89,201 // vmulps %ymm1,%ymm8,%ymm1 + .byte 197,172,92,201 // vsubps %ymm1,%ymm10,%ymm1 + .byte 196,193,116,92,201 // vsubps %ymm9,%ymm1,%ymm1 + .byte 196,65,60,87,192 // vxorps %ymm8,%ymm8,%ymm8 + .byte 197,60,92,193 // vsubps %ymm1,%ymm8,%ymm8 + .byte 197,60,84,193 // vandps %ymm1,%ymm8,%ymm8 + .byte 196,99,125,25,201,1 // vextractf128 $0x1,%ymm9,%xmm1 + .byte 196,65,41,118,210 // vpcmpeqd %xmm10,%xmm10,%xmm10 + .byte 196,193,113,254,202 // vpaddd %xmm10,%xmm1,%xmm1 + .byte 196,65,49,254,202 // vpaddd %xmm10,%xmm9,%xmm9 + .byte 196,227,53,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm9,%ymm1 + .byte 197,188,93,201 // vminps %ymm1,%ymm8,%ymm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_luminance_to_alpha_avx +.globl _sk_luminance_to_alpha_avx +_sk_luminance_to_alpha_avx: + .byte 184,208,179,89,62 // mov $0x3e59b3d0,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,228,89,192 // vmulps %ymm0,%ymm3,%ymm0 + .byte 184,89,23,55,63 // mov $0x3f371759,%eax + .byte 197,249,110,216 // vmovd %eax,%xmm3 + .byte 196,227,121,4,219,0 // vpermilps $0x0,%xmm3,%xmm3 + .byte 196,227,101,24,219,1 // vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + .byte 197,228,89,201 // vmulps %ymm1,%ymm3,%ymm1 + .byte 197,252,88,193 // vaddps %ymm1,%ymm0,%ymm0 + .byte 184,152,221,147,61 // mov $0x3d93dd98,%eax + .byte 197,249,110,200 // vmovd %eax,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,244,89,202 // vmulps %ymm2,%ymm1,%ymm1 + .byte 197,252,88,217 // vaddps %ymm1,%ymm0,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,252,87,192 // vxorps %ymm0,%ymm0,%ymm0 + .byte 197,244,87,201 // vxorps %ymm1,%ymm1,%ymm1 + .byte 197,236,87,210 // vxorps %ymm2,%ymm2,%ymm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_2x3_avx +.globl _sk_matrix_2x3_avx +_sk_matrix_2x3_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,98,125,24,72,8 // vbroadcastss 0x8(%rax),%ymm9 + .byte 196,98,125,24,80,16 // vbroadcastss 0x10(%rax),%ymm10 + .byte 197,52,89,201 // vmulps %ymm1,%ymm9,%ymm9 + .byte 196,65,52,88,202 // vaddps %ymm10,%ymm9,%ymm9 + .byte 197,60,89,192 // vmulps %ymm0,%ymm8,%ymm8 + .byte 196,65,60,88,193 // vaddps %ymm9,%ymm8,%ymm8 + .byte 196,98,125,24,72,4 // vbroadcastss 0x4(%rax),%ymm9 + .byte 196,98,125,24,80,12 // vbroadcastss 0xc(%rax),%ymm10 + .byte 196,98,125,24,88,20 // vbroadcastss 0x14(%rax),%ymm11 + .byte 197,172,89,201 // vmulps %ymm1,%ymm10,%ymm1 + .byte 196,193,116,88,203 // vaddps %ymm11,%ymm1,%ymm1 + .byte 197,180,89,192 // vmulps %ymm0,%ymm9,%ymm0 + .byte 197,252,88,201 // vaddps %ymm1,%ymm0,%ymm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,192 // vmovaps %ymm8,%ymm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_3x4_avx +.globl _sk_matrix_3x4_avx +_sk_matrix_3x4_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,98,125,24,72,12 // vbroadcastss 0xc(%rax),%ymm9 + .byte 196,98,125,24,80,24 // vbroadcastss 0x18(%rax),%ymm10 + .byte 196,98,125,24,88,36 // vbroadcastss 0x24(%rax),%ymm11 + .byte 197,44,89,210 // vmulps %ymm2,%ymm10,%ymm10 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 197,52,89,201 // vmulps %ymm1,%ymm9,%ymm9 + .byte 196,65,52,88,202 // vaddps %ymm10,%ymm9,%ymm9 + .byte 197,60,89,192 // vmulps %ymm0,%ymm8,%ymm8 + .byte 196,65,60,88,193 // vaddps %ymm9,%ymm8,%ymm8 + .byte 196,98,125,24,72,4 // vbroadcastss 0x4(%rax),%ymm9 + .byte 196,98,125,24,80,16 // vbroadcastss 0x10(%rax),%ymm10 + .byte 196,98,125,24,88,28 // vbroadcastss 0x1c(%rax),%ymm11 + .byte 196,98,125,24,96,40 // vbroadcastss 0x28(%rax),%ymm12 + .byte 197,36,89,218 // vmulps %ymm2,%ymm11,%ymm11 + .byte 196,65,36,88,220 // vaddps %ymm12,%ymm11,%ymm11 + .byte 197,44,89,209 // vmulps %ymm1,%ymm10,%ymm10 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 197,52,89,200 // vmulps %ymm0,%ymm9,%ymm9 + .byte 196,65,52,88,202 // vaddps %ymm10,%ymm9,%ymm9 + .byte 196,98,125,24,80,8 // vbroadcastss 0x8(%rax),%ymm10 + .byte 196,98,125,24,88,20 // vbroadcastss 0x14(%rax),%ymm11 + .byte 196,98,125,24,96,32 // vbroadcastss 0x20(%rax),%ymm12 + .byte 196,98,125,24,104,44 // vbroadcastss 0x2c(%rax),%ymm13 + .byte 197,156,89,210 // vmulps %ymm2,%ymm12,%ymm2 + .byte 196,193,108,88,213 // vaddps %ymm13,%ymm2,%ymm2 + .byte 197,164,89,201 // vmulps %ymm1,%ymm11,%ymm1 + .byte 197,244,88,202 // vaddps %ymm2,%ymm1,%ymm1 + .byte 197,172,89,192 // vmulps %ymm0,%ymm10,%ymm0 + .byte 197,252,88,209 // vaddps %ymm1,%ymm0,%ymm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,192 // vmovaps %ymm8,%ymm0 + .byte 197,124,41,201 // vmovaps %ymm9,%ymm1 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_4x5_avx +.globl _sk_matrix_4x5_avx +_sk_matrix_4x5_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,98,125,24,72,16 // vbroadcastss 0x10(%rax),%ymm9 + .byte 196,98,125,24,80,32 // vbroadcastss 0x20(%rax),%ymm10 + .byte 196,98,125,24,88,48 // vbroadcastss 0x30(%rax),%ymm11 + .byte 196,98,125,24,96,64 // vbroadcastss 0x40(%rax),%ymm12 + .byte 197,36,89,219 // vmulps %ymm3,%ymm11,%ymm11 + .byte 196,65,36,88,220 // vaddps %ymm12,%ymm11,%ymm11 + .byte 197,44,89,210 // vmulps %ymm2,%ymm10,%ymm10 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 197,52,89,201 // vmulps %ymm1,%ymm9,%ymm9 + .byte 196,65,52,88,202 // vaddps %ymm10,%ymm9,%ymm9 + .byte 197,60,89,192 // vmulps %ymm0,%ymm8,%ymm8 + .byte 196,65,60,88,193 // vaddps %ymm9,%ymm8,%ymm8 + .byte 196,98,125,24,72,4 // vbroadcastss 0x4(%rax),%ymm9 + .byte 196,98,125,24,80,20 // vbroadcastss 0x14(%rax),%ymm10 + .byte 196,98,125,24,88,36 // vbroadcastss 0x24(%rax),%ymm11 + .byte 196,98,125,24,96,52 // vbroadcastss 0x34(%rax),%ymm12 + .byte 196,98,125,24,104,68 // vbroadcastss 0x44(%rax),%ymm13 + .byte 197,28,89,227 // vmulps %ymm3,%ymm12,%ymm12 + .byte 196,65,28,88,229 // vaddps %ymm13,%ymm12,%ymm12 + .byte 197,36,89,218 // vmulps %ymm2,%ymm11,%ymm11 + .byte 196,65,36,88,220 // vaddps %ymm12,%ymm11,%ymm11 + .byte 197,44,89,209 // vmulps %ymm1,%ymm10,%ymm10 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 197,52,89,200 // vmulps %ymm0,%ymm9,%ymm9 + .byte 196,65,52,88,202 // vaddps %ymm10,%ymm9,%ymm9 + .byte 196,98,125,24,80,8 // vbroadcastss 0x8(%rax),%ymm10 + .byte 196,98,125,24,88,24 // vbroadcastss 0x18(%rax),%ymm11 + .byte 196,98,125,24,96,40 // vbroadcastss 0x28(%rax),%ymm12 + .byte 196,98,125,24,104,56 // vbroadcastss 0x38(%rax),%ymm13 + .byte 196,98,125,24,112,72 // vbroadcastss 0x48(%rax),%ymm14 + .byte 197,20,89,235 // vmulps %ymm3,%ymm13,%ymm13 + .byte 196,65,20,88,238 // vaddps %ymm14,%ymm13,%ymm13 + .byte 197,28,89,226 // vmulps %ymm2,%ymm12,%ymm12 + .byte 196,65,28,88,229 // vaddps %ymm13,%ymm12,%ymm12 + .byte 197,36,89,217 // vmulps %ymm1,%ymm11,%ymm11 + .byte 196,65,36,88,220 // vaddps %ymm12,%ymm11,%ymm11 + .byte 197,44,89,208 // vmulps %ymm0,%ymm10,%ymm10 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 196,98,125,24,88,12 // vbroadcastss 0xc(%rax),%ymm11 + .byte 196,98,125,24,96,28 // vbroadcastss 0x1c(%rax),%ymm12 + .byte 196,98,125,24,104,44 // vbroadcastss 0x2c(%rax),%ymm13 + .byte 196,98,125,24,112,60 // vbroadcastss 0x3c(%rax),%ymm14 + .byte 196,98,125,24,120,76 // vbroadcastss 0x4c(%rax),%ymm15 + .byte 197,140,89,219 // vmulps %ymm3,%ymm14,%ymm3 + .byte 196,193,100,88,223 // vaddps %ymm15,%ymm3,%ymm3 + .byte 197,148,89,210 // vmulps %ymm2,%ymm13,%ymm2 + .byte 197,236,88,211 // vaddps %ymm3,%ymm2,%ymm2 + .byte 197,156,89,201 // vmulps %ymm1,%ymm12,%ymm1 + .byte 197,244,88,202 // vaddps %ymm2,%ymm1,%ymm1 + .byte 197,164,89,192 // vmulps %ymm0,%ymm11,%ymm0 + .byte 197,252,88,217 // vaddps %ymm1,%ymm0,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,192 // vmovaps %ymm8,%ymm0 + .byte 197,124,41,201 // vmovaps %ymm9,%ymm1 + .byte 197,124,41,210 // vmovaps %ymm10,%ymm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_perspective_avx +.globl _sk_matrix_perspective_avx +_sk_matrix_perspective_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,0 // vbroadcastss (%rax),%ymm8 + .byte 196,98,125,24,72,4 // vbroadcastss 0x4(%rax),%ymm9 + .byte 196,98,125,24,80,8 // vbroadcastss 0x8(%rax),%ymm10 + .byte 197,52,89,201 // vmulps %ymm1,%ymm9,%ymm9 + .byte 196,65,52,88,202 // vaddps %ymm10,%ymm9,%ymm9 + .byte 197,60,89,192 // vmulps %ymm0,%ymm8,%ymm8 + .byte 196,65,60,88,193 // vaddps %ymm9,%ymm8,%ymm8 + .byte 196,98,125,24,72,12 // vbroadcastss 0xc(%rax),%ymm9 + .byte 196,98,125,24,80,16 // vbroadcastss 0x10(%rax),%ymm10 + .byte 196,98,125,24,88,20 // vbroadcastss 0x14(%rax),%ymm11 + .byte 197,44,89,209 // vmulps %ymm1,%ymm10,%ymm10 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 197,52,89,200 // vmulps %ymm0,%ymm9,%ymm9 + .byte 196,65,52,88,202 // vaddps %ymm10,%ymm9,%ymm9 + .byte 196,98,125,24,80,24 // vbroadcastss 0x18(%rax),%ymm10 + .byte 196,98,125,24,88,28 // vbroadcastss 0x1c(%rax),%ymm11 + .byte 196,98,125,24,96,32 // vbroadcastss 0x20(%rax),%ymm12 + .byte 197,164,89,201 // vmulps %ymm1,%ymm11,%ymm1 + .byte 196,193,116,88,204 // vaddps %ymm12,%ymm1,%ymm1 + .byte 197,172,89,192 // vmulps %ymm0,%ymm10,%ymm0 + .byte 197,252,88,193 // vaddps %ymm1,%ymm0,%ymm0 + .byte 197,252,83,200 // vrcpps %ymm0,%ymm1 + .byte 197,188,89,193 // vmulps %ymm1,%ymm8,%ymm0 + .byte 197,180,89,201 // vmulps %ymm1,%ymm9,%ymm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_linear_gradient_avx +.globl _sk_linear_gradient_avx +_sk_linear_gradient_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,98,125,24,64,16 // vbroadcastss 0x10(%rax),%ymm8 + .byte 196,226,125,24,72,20 // vbroadcastss 0x14(%rax),%ymm1 + .byte 196,226,125,24,80,24 // vbroadcastss 0x18(%rax),%ymm2 + .byte 196,226,125,24,88,28 // vbroadcastss 0x1c(%rax),%ymm3 + .byte 76,139,0 // mov (%rax),%r8 + .byte 77,133,192 // test %r8,%r8 + .byte 15,132,146,0,0,0 // je 3f39 <_sk_linear_gradient_avx+0xb8> + .byte 72,139,64,8 // mov 0x8(%rax),%rax + .byte 72,131,192,32 // add $0x20,%rax + .byte 196,65,28,87,228 // vxorps %ymm12,%ymm12,%ymm12 + .byte 196,65,52,87,201 // vxorps %ymm9,%ymm9,%ymm9 + .byte 196,65,44,87,210 // vxorps %ymm10,%ymm10,%ymm10 + .byte 196,65,36,87,219 // vxorps %ymm11,%ymm11,%ymm11 + .byte 196,98,125,24,104,224 // vbroadcastss -0x20(%rax),%ymm13 + .byte 196,65,124,194,237,1 // vcmpltps %ymm13,%ymm0,%ymm13 + .byte 196,98,125,24,112,228 // vbroadcastss -0x1c(%rax),%ymm14 + .byte 196,67,13,74,228,208 // vblendvps %ymm13,%ymm12,%ymm14,%ymm12 + .byte 196,98,125,24,112,232 // vbroadcastss -0x18(%rax),%ymm14 + .byte 196,67,13,74,219,208 // vblendvps %ymm13,%ymm11,%ymm14,%ymm11 + .byte 196,98,125,24,112,236 // vbroadcastss -0x14(%rax),%ymm14 + .byte 196,67,13,74,210,208 // vblendvps %ymm13,%ymm10,%ymm14,%ymm10 + .byte 196,98,125,24,112,240 // vbroadcastss -0x10(%rax),%ymm14 + .byte 196,67,13,74,201,208 // vblendvps %ymm13,%ymm9,%ymm14,%ymm9 + .byte 196,98,125,24,112,244 // vbroadcastss -0xc(%rax),%ymm14 + .byte 196,67,13,74,192,208 // vblendvps %ymm13,%ymm8,%ymm14,%ymm8 + .byte 196,98,125,24,112,248 // vbroadcastss -0x8(%rax),%ymm14 + .byte 196,227,13,74,201,208 // vblendvps %ymm13,%ymm1,%ymm14,%ymm1 + .byte 196,98,125,24,112,252 // vbroadcastss -0x4(%rax),%ymm14 + .byte 196,227,13,74,210,208 // vblendvps %ymm13,%ymm2,%ymm14,%ymm2 + .byte 196,98,125,24,48 // vbroadcastss (%rax),%ymm14 + .byte 196,227,13,74,219,208 // vblendvps %ymm13,%ymm3,%ymm14,%ymm3 + .byte 72,131,192,36 // add $0x24,%rax + .byte 73,255,200 // dec %r8 + .byte 117,140 // jne 3ec3 <_sk_linear_gradient_avx+0x42> + .byte 235,20 // jmp 3f4d <_sk_linear_gradient_avx+0xcc> + .byte 196,65,36,87,219 // vxorps %ymm11,%ymm11,%ymm11 + .byte 196,65,44,87,210 // vxorps %ymm10,%ymm10,%ymm10 + .byte 196,65,52,87,201 // vxorps %ymm9,%ymm9,%ymm9 + .byte 196,65,28,87,228 // vxorps %ymm12,%ymm12,%ymm12 + .byte 197,28,89,224 // vmulps %ymm0,%ymm12,%ymm12 + .byte 196,65,60,88,196 // vaddps %ymm12,%ymm8,%ymm8 + .byte 197,36,89,216 // vmulps %ymm0,%ymm11,%ymm11 + .byte 197,164,88,201 // vaddps %ymm1,%ymm11,%ymm1 + .byte 197,44,89,208 // vmulps %ymm0,%ymm10,%ymm10 + .byte 197,172,88,210 // vaddps %ymm2,%ymm10,%ymm2 + .byte 197,180,89,192 // vmulps %ymm0,%ymm9,%ymm0 + .byte 197,252,88,219 // vaddps %ymm3,%ymm0,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,192 // vmovaps %ymm8,%ymm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_linear_gradient_2stops_avx +.globl _sk_linear_gradient_2stops_avx +_sk_linear_gradient_2stops_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 196,226,125,24,8 // vbroadcastss (%rax),%ymm1 + .byte 196,226,125,24,80,16 // vbroadcastss 0x10(%rax),%ymm2 + .byte 197,244,89,200 // vmulps %ymm0,%ymm1,%ymm1 + .byte 197,116,88,194 // vaddps %ymm2,%ymm1,%ymm8 + .byte 196,226,125,24,72,4 // vbroadcastss 0x4(%rax),%ymm1 + .byte 196,226,125,24,80,20 // vbroadcastss 0x14(%rax),%ymm2 + .byte 197,244,89,200 // vmulps %ymm0,%ymm1,%ymm1 + .byte 197,244,88,202 // vaddps %ymm2,%ymm1,%ymm1 + .byte 196,226,125,24,80,8 // vbroadcastss 0x8(%rax),%ymm2 + .byte 196,226,125,24,88,24 // vbroadcastss 0x18(%rax),%ymm3 + .byte 197,236,89,208 // vmulps %ymm0,%ymm2,%ymm2 + .byte 197,236,88,211 // vaddps %ymm3,%ymm2,%ymm2 + .byte 196,226,125,24,88,12 // vbroadcastss 0xc(%rax),%ymm3 + .byte 196,98,125,24,72,28 // vbroadcastss 0x1c(%rax),%ymm9 + .byte 197,228,89,192 // vmulps %ymm0,%ymm3,%ymm0 + .byte 196,193,124,88,217 // vaddps %ymm9,%ymm0,%ymm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,41,192 // vmovaps %ymm8,%ymm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_save_xy_avx +.globl _sk_save_xy_avx +_sk_save_xy_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,88,200 // vaddps %ymm0,%ymm8,%ymm9 + .byte 196,67,125,8,209,1 // vroundps $0x1,%ymm9,%ymm10 + .byte 196,65,52,92,202 // vsubps %ymm10,%ymm9,%ymm9 + .byte 197,60,88,193 // vaddps %ymm1,%ymm8,%ymm8 + .byte 196,67,125,8,208,1 // vroundps $0x1,%ymm8,%ymm10 + .byte 196,65,60,92,194 // vsubps %ymm10,%ymm8,%ymm8 + .byte 197,252,17,0 // vmovups %ymm0,(%rax) + .byte 197,252,17,72,32 // vmovups %ymm1,0x20(%rax) + .byte 197,124,17,72,64 // vmovups %ymm9,0x40(%rax) + .byte 197,124,17,64,96 // vmovups %ymm8,0x60(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_accumulate_avx +.globl _sk_accumulate_avx +_sk_accumulate_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 197,124,16,128,128,0,0,0 // vmovups 0x80(%rax),%ymm8 + .byte 197,60,89,128,160,0,0,0 // vmulps 0xa0(%rax),%ymm8,%ymm8 + .byte 197,60,89,200 // vmulps %ymm0,%ymm8,%ymm9 + .byte 197,180,88,228 // vaddps %ymm4,%ymm9,%ymm4 + .byte 197,60,89,201 // vmulps %ymm1,%ymm8,%ymm9 + .byte 197,180,88,237 // vaddps %ymm5,%ymm9,%ymm5 + .byte 197,60,89,202 // vmulps %ymm2,%ymm8,%ymm9 + .byte 197,180,88,246 // vaddps %ymm6,%ymm9,%ymm6 + .byte 197,60,89,195 // vmulps %ymm3,%ymm8,%ymm8 + .byte 197,188,88,255 // vaddps %ymm7,%ymm8,%ymm7 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_nx_avx +.globl _sk_bilinear_nx_avx +_sk_bilinear_nx_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,191 // mov $0xbf000000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,252,88,0 // vaddps (%rax),%ymm0,%ymm0 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,64,64 // vsubps 0x40(%rax),%ymm8,%ymm8 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_px_avx +.globl _sk_bilinear_px_avx +_sk_bilinear_px_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,124,16,64,64 // vmovups 0x40(%rax),%ymm8 + .byte 197,252,88,0 // vaddps (%rax),%ymm0,%ymm0 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_ny_avx +.globl _sk_bilinear_ny_avx +_sk_bilinear_ny_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,191 // mov $0xbf000000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,244,88,72,32 // vaddps 0x20(%rax),%ymm1,%ymm1 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,64,96 // vsubps 0x60(%rax),%ymm8,%ymm8 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_py_avx +.globl _sk_bilinear_py_avx +_sk_bilinear_py_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,124,16,64,96 // vmovups 0x60(%rax),%ymm8 + .byte 197,244,88,72,32 // vaddps 0x20(%rax),%ymm1,%ymm1 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n3x_avx +.globl _sk_bicubic_n3x_avx +_sk_bicubic_n3x_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,192,191 // mov $0xbfc00000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,252,88,0 // vaddps (%rax),%ymm0,%ymm0 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,64,64 // vsubps 0x40(%rax),%ymm8,%ymm8 + .byte 196,65,60,89,200 // vmulps %ymm8,%ymm8,%ymm9 + .byte 65,184,114,28,199,62 // mov $0x3ec71c72,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 65,184,171,170,170,190 // mov $0xbeaaaaab,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,67,121,4,219,0 // vpermilps $0x0,%xmm11,%xmm11 + .byte 196,67,37,24,219,1 // vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + .byte 196,65,44,89,192 // vmulps %ymm8,%ymm10,%ymm8 + .byte 196,65,60,88,195 // vaddps %ymm11,%ymm8,%ymm8 + .byte 196,65,52,89,192 // vmulps %ymm8,%ymm9,%ymm8 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n1x_avx +.globl _sk_bicubic_n1x_avx +_sk_bicubic_n1x_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,191 // mov $0xbf000000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,252,88,0 // vaddps (%rax),%ymm0,%ymm0 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,64,64 // vsubps 0x40(%rax),%ymm8,%ymm8 + .byte 65,184,85,85,149,191 // mov $0xbf955555,%r8d + .byte 196,65,121,110,200 // vmovd %r8d,%xmm9 + .byte 196,67,121,4,201,0 // vpermilps $0x0,%xmm9,%xmm9 + .byte 196,67,53,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 196,65,52,89,200 // vmulps %ymm8,%ymm9,%ymm9 + .byte 196,65,52,88,202 // vaddps %ymm10,%ymm9,%ymm9 + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 196,65,60,89,201 // vmulps %ymm9,%ymm8,%ymm9 + .byte 196,65,44,88,201 // vaddps %ymm9,%ymm10,%ymm9 + .byte 65,184,57,142,99,61 // mov $0x3d638e39,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 196,65,60,89,193 // vmulps %ymm9,%ymm8,%ymm8 + .byte 196,65,44,88,192 // vaddps %ymm8,%ymm10,%ymm8 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p1x_avx +.globl _sk_bicubic_p1x_avx +_sk_bicubic_p1x_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,99,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm8 + .byte 197,188,88,0 // vaddps (%rax),%ymm8,%ymm0 + .byte 197,124,16,72,64 // vmovups 0x40(%rax),%ymm9 + .byte 65,184,85,85,149,191 // mov $0xbf955555,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,67,121,4,219,0 // vpermilps $0x0,%xmm11,%xmm11 + .byte 196,67,37,24,219,1 // vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + .byte 196,65,52,89,210 // vmulps %ymm10,%ymm9,%ymm10 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 196,65,52,89,210 // vmulps %ymm10,%ymm9,%ymm10 + .byte 196,65,60,88,194 // vaddps %ymm10,%ymm8,%ymm8 + .byte 65,184,57,142,99,61 // mov $0x3d638e39,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 196,65,52,89,192 // vmulps %ymm8,%ymm9,%ymm8 + .byte 196,65,44,88,192 // vaddps %ymm8,%ymm10,%ymm8 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p3x_avx +.globl _sk_bicubic_p3x_avx +_sk_bicubic_p3x_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,193,121,110,192 // vmovd %r8d,%xmm0 + .byte 196,227,121,4,192,0 // vpermilps $0x0,%xmm0,%xmm0 + .byte 196,227,125,24,192,1 // vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + .byte 197,252,88,0 // vaddps (%rax),%ymm0,%ymm0 + .byte 197,124,16,64,64 // vmovups 0x40(%rax),%ymm8 + .byte 196,65,60,89,200 // vmulps %ymm8,%ymm8,%ymm9 + .byte 65,184,114,28,199,62 // mov $0x3ec71c72,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 65,184,171,170,170,190 // mov $0xbeaaaaab,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,67,121,4,219,0 // vpermilps $0x0,%xmm11,%xmm11 + .byte 196,67,37,24,219,1 // vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + .byte 196,65,60,89,194 // vmulps %ymm10,%ymm8,%ymm8 + .byte 196,65,60,88,195 // vaddps %ymm11,%ymm8,%ymm8 + .byte 196,65,52,89,192 // vmulps %ymm8,%ymm9,%ymm8 + .byte 197,124,17,128,128,0,0,0 // vmovups %ymm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n3y_avx +.globl _sk_bicubic_n3y_avx +_sk_bicubic_n3y_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,192,191 // mov $0xbfc00000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,244,88,72,32 // vaddps 0x20(%rax),%ymm1,%ymm1 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,64,96 // vsubps 0x60(%rax),%ymm8,%ymm8 + .byte 196,65,60,89,200 // vmulps %ymm8,%ymm8,%ymm9 + .byte 65,184,114,28,199,62 // mov $0x3ec71c72,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 65,184,171,170,170,190 // mov $0xbeaaaaab,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,67,121,4,219,0 // vpermilps $0x0,%xmm11,%xmm11 + .byte 196,67,37,24,219,1 // vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + .byte 196,65,44,89,192 // vmulps %ymm8,%ymm10,%ymm8 + .byte 196,65,60,88,195 // vaddps %ymm11,%ymm8,%ymm8 + .byte 196,65,52,89,192 // vmulps %ymm8,%ymm9,%ymm8 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n1y_avx +.globl _sk_bicubic_n1y_avx +_sk_bicubic_n1y_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,191 // mov $0xbf000000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,244,88,72,32 // vaddps 0x20(%rax),%ymm1,%ymm1 + .byte 65,184,0,0,128,63 // mov $0x3f800000,%r8d + .byte 196,65,121,110,192 // vmovd %r8d,%xmm8 + .byte 196,67,121,4,192,0 // vpermilps $0x0,%xmm8,%xmm8 + .byte 196,67,61,24,192,1 // vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + .byte 197,60,92,64,96 // vsubps 0x60(%rax),%ymm8,%ymm8 + .byte 65,184,85,85,149,191 // mov $0xbf955555,%r8d + .byte 196,65,121,110,200 // vmovd %r8d,%xmm9 + .byte 196,67,121,4,201,0 // vpermilps $0x0,%xmm9,%xmm9 + .byte 196,67,53,24,201,1 // vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 196,65,52,89,200 // vmulps %ymm8,%ymm9,%ymm9 + .byte 196,65,52,88,202 // vaddps %ymm10,%ymm9,%ymm9 + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 196,65,60,89,201 // vmulps %ymm9,%ymm8,%ymm9 + .byte 196,65,44,88,201 // vaddps %ymm9,%ymm10,%ymm9 + .byte 65,184,57,142,99,61 // mov $0x3d638e39,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 196,65,60,89,193 // vmulps %ymm9,%ymm8,%ymm8 + .byte 196,65,44,88,192 // vaddps %ymm8,%ymm10,%ymm8 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p1y_avx +.globl _sk_bicubic_p1y_avx +_sk_bicubic_p1y_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,0,63 // mov $0x3f000000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,99,117,24,193,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm8 + .byte 197,188,88,72,32 // vaddps 0x20(%rax),%ymm8,%ymm1 + .byte 197,124,16,72,96 // vmovups 0x60(%rax),%ymm9 + .byte 65,184,85,85,149,191 // mov $0xbf955555,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,67,121,4,219,0 // vpermilps $0x0,%xmm11,%xmm11 + .byte 196,67,37,24,219,1 // vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + .byte 196,65,52,89,210 // vmulps %ymm10,%ymm9,%ymm10 + .byte 196,65,44,88,211 // vaddps %ymm11,%ymm10,%ymm10 + .byte 196,65,52,89,210 // vmulps %ymm10,%ymm9,%ymm10 + .byte 196,65,60,88,194 // vaddps %ymm10,%ymm8,%ymm8 + .byte 65,184,57,142,99,61 // mov $0x3d638e39,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 196,65,52,89,192 // vmulps %ymm8,%ymm9,%ymm8 + .byte 196,65,44,88,192 // vaddps %ymm8,%ymm10,%ymm8 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p3y_avx +.globl _sk_bicubic_p3y_avx +_sk_bicubic_p3y_avx: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,184,0,0,192,63 // mov $0x3fc00000,%r8d + .byte 196,193,121,110,200 // vmovd %r8d,%xmm1 + .byte 196,227,121,4,201,0 // vpermilps $0x0,%xmm1,%xmm1 + .byte 196,227,117,24,201,1 // vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + .byte 197,244,88,72,32 // vaddps 0x20(%rax),%ymm1,%ymm1 + .byte 197,124,16,64,96 // vmovups 0x60(%rax),%ymm8 + .byte 196,65,60,89,200 // vmulps %ymm8,%ymm8,%ymm9 + .byte 65,184,114,28,199,62 // mov $0x3ec71c72,%r8d + .byte 196,65,121,110,208 // vmovd %r8d,%xmm10 + .byte 196,67,121,4,210,0 // vpermilps $0x0,%xmm10,%xmm10 + .byte 196,67,45,24,210,1 // vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + .byte 65,184,171,170,170,190 // mov $0xbeaaaaab,%r8d + .byte 196,65,121,110,216 // vmovd %r8d,%xmm11 + .byte 196,67,121,4,219,0 // vpermilps $0x0,%xmm11,%xmm11 + .byte 196,67,37,24,219,1 // vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + .byte 196,65,60,89,194 // vmulps %ymm10,%ymm8,%ymm8 + .byte 196,65,60,88,195 // vaddps %ymm11,%ymm8,%ymm8 + .byte 196,65,52,89,192 // vmulps %ymm8,%ymm9,%ymm8 + .byte 197,124,17,128,160,0,0,0 // vmovups %ymm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_start_pipeline_sse41 +.globl _sk_start_pipeline_sse41 +_sk_start_pipeline_sse41: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 73,137,207 // mov %rcx,%r15 + .byte 73,137,214 // mov %rdx,%r14 + .byte 72,137,251 // mov %rdi,%rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 73,137,196 // mov %rax,%r12 + .byte 73,137,245 // mov %rsi,%r13 + .byte 72,141,67,4 // lea 0x4(%rbx),%rax + .byte 76,57,248 // cmp %r15,%rax + .byte 118,5 // jbe 28 <_sk_start_pipeline_sse41+0x28> + .byte 72,137,216 // mov %rbx,%rax + .byte 235,52 // jmp 5c <_sk_start_pipeline_sse41+0x5c> + .byte 15,87,192 // xorps %xmm0,%xmm0 + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 15,87,219 // xorps %xmm3,%xmm3 + .byte 15,87,228 // xorps %xmm4,%xmm4 + .byte 15,87,237 // xorps %xmm5,%xmm5 + .byte 15,87,246 // xorps %xmm6,%xmm6 + .byte 15,87,255 // xorps %xmm7,%xmm7 + .byte 72,137,223 // mov %rbx,%rdi + .byte 76,137,238 // mov %r13,%rsi + .byte 76,137,242 // mov %r14,%rdx + .byte 65,255,212 // callq *%r12 + .byte 72,141,67,4 // lea 0x4(%rbx),%rax + .byte 72,131,195,8 // add $0x8,%rbx + .byte 76,57,251 // cmp %r15,%rbx + .byte 72,137,195 // mov %rax,%rbx + .byte 118,204 // jbe 28 <_sk_start_pipeline_sse41+0x28> + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 195 // retq + +HIDDEN _sk_just_return_sse41 +.globl _sk_just_return_sse41 +_sk_just_return_sse41: + .byte 195 // retq + +HIDDEN _sk_seed_shader_sse41 +.globl _sk_seed_shader_sse41 +_sk_seed_shader_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 102,15,110,199 // movd %edi,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,15,110,209 // movd %ecx,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,88,202 // addps %xmm2,%xmm1 + .byte 15,16,2 // movups (%rdx),%xmm0 + .byte 15,88,193 // addps %xmm1,%xmm0 + .byte 102,15,110,8 // movd (%rax),%xmm1 + .byte 102,15,112,201,0 // pshufd $0x0,%xmm1,%xmm1 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 15,88,202 // addps %xmm2,%xmm1 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,87,219 // xorps %xmm3,%xmm3 + .byte 15,87,228 // xorps %xmm4,%xmm4 + .byte 15,87,237 // xorps %xmm5,%xmm5 + .byte 15,87,246 // xorps %xmm6,%xmm6 + .byte 15,87,255 // xorps %xmm7,%xmm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_constant_color_sse41 +.globl _sk_constant_color_sse41 +_sk_constant_color_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,15,16,80,8 // movss 0x8(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 243,15,16,88,12 // movss 0xc(%rax),%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clear_sse41 +.globl _sk_clear_sse41 +_sk_clear_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,87,192 // xorps %xmm0,%xmm0 + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 15,87,219 // xorps %xmm3,%xmm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcatop_sse41 +.globl _sk_srcatop_sse41 +_sk_srcatop_sse41: + .byte 15,89,199 // mulps %xmm7,%xmm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,92,195 // subps %xmm3,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,204 // mulps %xmm4,%xmm9 + .byte 65,15,88,193 // addps %xmm9,%xmm0 + .byte 15,89,207 // mulps %xmm7,%xmm1 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 65,15,88,201 // addps %xmm9,%xmm1 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 65,15,88,209 // addps %xmm9,%xmm2 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 65,15,88,216 // addps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstatop_sse41 +.globl _sk_dstatop_sse41 +_sk_dstatop_sse41: + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 68,15,89,196 // mulps %xmm4,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 68,15,92,207 // subps %xmm7,%xmm9 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 68,15,89,197 // mulps %xmm5,%xmm8 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 68,15,89,198 // mulps %xmm6,%xmm8 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 65,15,88,208 // addps %xmm8,%xmm2 + .byte 68,15,89,203 // mulps %xmm3,%xmm9 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 65,15,88,217 // addps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcin_sse41 +.globl _sk_srcin_sse41 +_sk_srcin_sse41: + .byte 15,89,199 // mulps %xmm7,%xmm0 + .byte 15,89,207 // mulps %xmm7,%xmm1 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstin_sse41 +.globl _sk_dstin_sse41 +_sk_dstin_sse41: + .byte 15,40,195 // movaps %xmm3,%xmm0 + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 15,40,211 // movaps %xmm3,%xmm2 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcout_sse41 +.globl _sk_srcout_sse41 +_sk_srcout_sse41: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,92,199 // subps %xmm7,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstout_sse41 +.globl _sk_dstout_sse41 +_sk_dstout_sse41: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,92,195 // subps %xmm3,%xmm8 + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,216 // movaps %xmm8,%xmm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcover_sse41 +.globl _sk_srcover_sse41 +_sk_srcover_sse41: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,92,195 // subps %xmm3,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,204 // mulps %xmm4,%xmm9 + .byte 65,15,88,193 // addps %xmm9,%xmm0 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 65,15,88,201 // addps %xmm9,%xmm1 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 65,15,88,209 // addps %xmm9,%xmm2 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 65,15,88,216 // addps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstover_sse41 +.globl _sk_dstover_sse41 +_sk_dstover_sse41: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,92,199 // subps %xmm7,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 15,88,223 // addps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_modulate_sse41 +.globl _sk_modulate_sse41 +_sk_modulate_sse41: + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_multiply_sse41 +.globl _sk_multiply_sse41 +_sk_multiply_sse41: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,92,207 // subps %xmm7,%xmm9 + .byte 69,15,40,209 // movaps %xmm9,%xmm10 + .byte 68,15,89,208 // mulps %xmm0,%xmm10 + .byte 68,15,92,195 // subps %xmm3,%xmm8 + .byte 69,15,40,216 // movaps %xmm8,%xmm11 + .byte 68,15,89,220 // mulps %xmm4,%xmm11 + .byte 69,15,88,218 // addps %xmm10,%xmm11 + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 65,15,88,195 // addps %xmm11,%xmm0 + .byte 69,15,40,209 // movaps %xmm9,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 69,15,40,216 // movaps %xmm8,%xmm11 + .byte 68,15,89,221 // mulps %xmm5,%xmm11 + .byte 69,15,88,218 // addps %xmm10,%xmm11 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 65,15,88,203 // addps %xmm11,%xmm1 + .byte 69,15,40,209 // movaps %xmm9,%xmm10 + .byte 68,15,89,210 // mulps %xmm2,%xmm10 + .byte 69,15,40,216 // movaps %xmm8,%xmm11 + .byte 68,15,89,222 // mulps %xmm6,%xmm11 + .byte 69,15,88,218 // addps %xmm10,%xmm11 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 65,15,88,211 // addps %xmm11,%xmm2 + .byte 68,15,89,203 // mulps %xmm3,%xmm9 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 69,15,88,193 // addps %xmm9,%xmm8 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 65,15,88,216 // addps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_plus__sse41 +.globl _sk_plus__sse41 +_sk_plus__sse41: + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 15,88,223 // addps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_screen_sse41 +.globl _sk_screen_sse41 +_sk_screen_sse41: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 68,15,88,196 // addps %xmm4,%xmm8 + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 68,15,92,192 // subps %xmm0,%xmm8 + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 68,15,88,205 // addps %xmm5,%xmm9 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 68,15,92,201 // subps %xmm1,%xmm9 + .byte 68,15,40,210 // movaps %xmm2,%xmm10 + .byte 68,15,88,214 // addps %xmm6,%xmm10 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 68,15,92,210 // subps %xmm2,%xmm10 + .byte 68,15,40,219 // movaps %xmm3,%xmm11 + .byte 68,15,88,223 // addps %xmm7,%xmm11 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 68,15,92,219 // subps %xmm3,%xmm11 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 65,15,40,201 // movaps %xmm9,%xmm1 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 65,15,40,219 // movaps %xmm11,%xmm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_xor__sse41 +.globl _sk_xor__sse41 +_sk_xor__sse41: + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,92,207 // subps %xmm7,%xmm9 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,92,216 // subps %xmm8,%xmm3 + .byte 68,15,40,211 // movaps %xmm3,%xmm10 + .byte 68,15,89,212 // mulps %xmm4,%xmm10 + .byte 65,15,88,194 // addps %xmm10,%xmm0 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 68,15,40,211 // movaps %xmm3,%xmm10 + .byte 68,15,89,213 // mulps %xmm5,%xmm10 + .byte 65,15,88,202 // addps %xmm10,%xmm1 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 68,15,40,211 // movaps %xmm3,%xmm10 + .byte 68,15,89,214 // mulps %xmm6,%xmm10 + .byte 65,15,88,210 // addps %xmm10,%xmm2 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 65,15,88,217 // addps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_darken_sse41 +.globl _sk_darken_sse41 +_sk_darken_sse41: + .byte 68,15,40,193 // movaps %xmm1,%xmm8 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 68,15,89,207 // mulps %xmm7,%xmm9 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 15,89,204 // mulps %xmm4,%xmm1 + .byte 68,15,95,201 // maxps %xmm1,%xmm9 + .byte 65,15,92,193 // subps %xmm9,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 69,15,95,193 // maxps %xmm9,%xmm8 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 68,15,40,194 // movaps %xmm2,%xmm8 + .byte 68,15,88,198 // addps %xmm6,%xmm8 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 65,15,95,209 // maxps %xmm9,%xmm2 + .byte 68,15,92,194 // subps %xmm2,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 15,88,218 // addps %xmm2,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lighten_sse41 +.globl _sk_lighten_sse41 +_sk_lighten_sse41: + .byte 68,15,40,193 // movaps %xmm1,%xmm8 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 68,15,89,207 // mulps %xmm7,%xmm9 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 15,89,204 // mulps %xmm4,%xmm1 + .byte 68,15,93,201 // minps %xmm1,%xmm9 + .byte 65,15,92,193 // subps %xmm9,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 69,15,93,193 // minps %xmm9,%xmm8 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 68,15,40,194 // movaps %xmm2,%xmm8 + .byte 68,15,88,198 // addps %xmm6,%xmm8 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 65,15,93,209 // minps %xmm9,%xmm2 + .byte 68,15,92,194 // subps %xmm2,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 15,88,218 // addps %xmm2,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_difference_sse41 +.globl _sk_difference_sse41 +_sk_difference_sse41: + .byte 68,15,40,193 // movaps %xmm1,%xmm8 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 68,15,89,207 // mulps %xmm7,%xmm9 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 15,89,204 // mulps %xmm4,%xmm1 + .byte 68,15,93,201 // minps %xmm1,%xmm9 + .byte 69,15,88,201 // addps %xmm9,%xmm9 + .byte 65,15,92,193 // subps %xmm9,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 69,15,93,193 // minps %xmm9,%xmm8 + .byte 69,15,88,192 // addps %xmm8,%xmm8 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 68,15,40,194 // movaps %xmm2,%xmm8 + .byte 68,15,88,198 // addps %xmm6,%xmm8 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 65,15,93,209 // minps %xmm9,%xmm2 + .byte 15,88,210 // addps %xmm2,%xmm2 + .byte 68,15,92,194 // subps %xmm2,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 15,88,218 // addps %xmm2,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_exclusion_sse41 +.globl _sk_exclusion_sse41 +_sk_exclusion_sse41: + .byte 68,15,40,193 // movaps %xmm1,%xmm8 + .byte 15,40,200 // movaps %xmm0,%xmm1 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 15,89,204 // mulps %xmm4,%xmm1 + .byte 15,88,201 // addps %xmm1,%xmm1 + .byte 15,92,193 // subps %xmm1,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 68,15,89,197 // mulps %xmm5,%xmm8 + .byte 69,15,88,192 // addps %xmm8,%xmm8 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 68,15,40,194 // movaps %xmm2,%xmm8 + .byte 68,15,88,198 // addps %xmm6,%xmm8 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 15,88,210 // addps %xmm2,%xmm2 + .byte 68,15,92,194 // subps %xmm2,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 15,88,218 // addps %xmm2,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_colorburn_sse41 +.globl _sk_colorburn_sse41 +_sk_colorburn_sse41: + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,40,218 // movaps %xmm10,%xmm11 + .byte 68,15,92,223 // subps %xmm7,%xmm11 + .byte 69,15,40,227 // movaps %xmm11,%xmm12 + .byte 69,15,89,225 // mulps %xmm9,%xmm12 + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 15,40,199 // movaps %xmm7,%xmm0 + .byte 15,92,196 // subps %xmm4,%xmm0 + .byte 15,89,195 // mulps %xmm3,%xmm0 + .byte 65,15,94,193 // divps %xmm9,%xmm0 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,93,232 // minps %xmm0,%xmm13 + .byte 68,15,40,247 // movaps %xmm7,%xmm14 + .byte 69,15,92,245 // subps %xmm13,%xmm14 + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 65,15,194,192,0 // cmpeqps %xmm8,%xmm0 + .byte 68,15,92,211 // subps %xmm3,%xmm10 + .byte 68,15,89,243 // mulps %xmm3,%xmm14 + .byte 69,15,88,244 // addps %xmm12,%xmm14 + .byte 102,69,15,56,20,241 // blendvps %xmm0,%xmm9,%xmm14 + .byte 69,15,40,202 // movaps %xmm10,%xmm9 + .byte 68,15,89,204 // mulps %xmm4,%xmm9 + .byte 68,15,88,228 // addps %xmm4,%xmm12 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 15,194,199,0 // cmpeqps %xmm7,%xmm0 + .byte 69,15,88,206 // addps %xmm14,%xmm9 + .byte 102,69,15,56,20,204 // blendvps %xmm0,%xmm12,%xmm9 + .byte 69,15,40,227 // movaps %xmm11,%xmm12 + .byte 68,15,89,225 // mulps %xmm1,%xmm12 + .byte 15,40,199 // movaps %xmm7,%xmm0 + .byte 15,92,197 // subps %xmm5,%xmm0 + .byte 15,89,195 // mulps %xmm3,%xmm0 + .byte 15,94,193 // divps %xmm1,%xmm0 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,93,232 // minps %xmm0,%xmm13 + .byte 68,15,40,247 // movaps %xmm7,%xmm14 + .byte 69,15,92,245 // subps %xmm13,%xmm14 + .byte 15,40,193 // movaps %xmm1,%xmm0 + .byte 65,15,194,192,0 // cmpeqps %xmm8,%xmm0 + .byte 68,15,89,243 // mulps %xmm3,%xmm14 + .byte 69,15,88,244 // addps %xmm12,%xmm14 + .byte 102,68,15,56,20,241 // blendvps %xmm0,%xmm1,%xmm14 + .byte 65,15,40,202 // movaps %xmm10,%xmm1 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 68,15,88,229 // addps %xmm5,%xmm12 + .byte 65,15,88,206 // addps %xmm14,%xmm1 + .byte 15,40,197 // movaps %xmm5,%xmm0 + .byte 15,194,199,0 // cmpeqps %xmm7,%xmm0 + .byte 102,65,15,56,20,204 // blendvps %xmm0,%xmm12,%xmm1 + .byte 15,40,199 // movaps %xmm7,%xmm0 + .byte 15,92,198 // subps %xmm6,%xmm0 + .byte 15,89,195 // mulps %xmm3,%xmm0 + .byte 15,94,194 // divps %xmm2,%xmm0 + .byte 68,15,40,231 // movaps %xmm7,%xmm12 + .byte 68,15,93,224 // minps %xmm0,%xmm12 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 69,15,92,236 // subps %xmm12,%xmm13 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 68,15,194,194,0 // cmpeqps %xmm2,%xmm8 + .byte 68,15,89,235 // mulps %xmm3,%xmm13 + .byte 69,15,88,235 // addps %xmm11,%xmm13 + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 102,68,15,56,20,234 // blendvps %xmm0,%xmm2,%xmm13 + .byte 68,15,88,222 // addps %xmm6,%xmm11 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 65,15,88,213 // addps %xmm13,%xmm2 + .byte 15,40,198 // movaps %xmm6,%xmm0 + .byte 15,194,199,0 // cmpeqps %xmm7,%xmm0 + .byte 102,65,15,56,20,211 // blendvps %xmm0,%xmm11,%xmm2 + .byte 68,15,89,215 // mulps %xmm7,%xmm10 + .byte 65,15,88,218 // addps %xmm10,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_colordodge_sse41 +.globl _sk_colordodge_sse41 +_sk_colordodge_sse41: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,40,218 // movaps %xmm10,%xmm11 + .byte 68,15,92,223 // subps %xmm7,%xmm11 + .byte 69,15,40,227 // movaps %xmm11,%xmm12 + .byte 69,15,89,224 // mulps %xmm8,%xmm12 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,204 // mulps %xmm4,%xmm9 + .byte 15,40,195 // movaps %xmm3,%xmm0 + .byte 65,15,92,192 // subps %xmm8,%xmm0 + .byte 68,15,94,200 // divps %xmm0,%xmm9 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,40,247 // movaps %xmm7,%xmm14 + .byte 69,15,93,241 // minps %xmm9,%xmm14 + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 15,194,195,0 // cmpeqps %xmm3,%xmm0 + .byte 68,15,89,243 // mulps %xmm3,%xmm14 + .byte 69,15,88,244 // addps %xmm12,%xmm14 + .byte 102,69,15,56,20,240 // blendvps %xmm0,%xmm8,%xmm14 + .byte 69,15,87,201 // xorps %xmm9,%xmm9 + .byte 68,15,92,211 // subps %xmm3,%xmm10 + .byte 69,15,40,194 // movaps %xmm10,%xmm8 + .byte 68,15,89,196 // mulps %xmm4,%xmm8 + .byte 68,15,88,228 // addps %xmm4,%xmm12 + .byte 69,15,88,198 // addps %xmm14,%xmm8 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 65,15,194,193,0 // cmpeqps %xmm9,%xmm0 + .byte 102,69,15,56,20,196 // blendvps %xmm0,%xmm12,%xmm8 + .byte 68,15,40,227 // movaps %xmm3,%xmm12 + .byte 68,15,89,229 // mulps %xmm5,%xmm12 + .byte 15,40,195 // movaps %xmm3,%xmm0 + .byte 15,92,193 // subps %xmm1,%xmm0 + .byte 68,15,94,224 // divps %xmm0,%xmm12 + .byte 69,15,40,243 // movaps %xmm11,%xmm14 + .byte 68,15,89,241 // mulps %xmm1,%xmm14 + .byte 69,15,93,236 // minps %xmm12,%xmm13 + .byte 15,40,193 // movaps %xmm1,%xmm0 + .byte 15,194,195,0 // cmpeqps %xmm3,%xmm0 + .byte 68,15,89,235 // mulps %xmm3,%xmm13 + .byte 69,15,88,238 // addps %xmm14,%xmm13 + .byte 102,68,15,56,20,233 // blendvps %xmm0,%xmm1,%xmm13 + .byte 65,15,40,202 // movaps %xmm10,%xmm1 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 68,15,88,245 // addps %xmm5,%xmm14 + .byte 65,15,88,205 // addps %xmm13,%xmm1 + .byte 15,40,197 // movaps %xmm5,%xmm0 + .byte 65,15,194,193,0 // cmpeqps %xmm9,%xmm0 + .byte 102,65,15,56,20,206 // blendvps %xmm0,%xmm14,%xmm1 + .byte 68,15,40,227 // movaps %xmm3,%xmm12 + .byte 68,15,89,230 // mulps %xmm6,%xmm12 + .byte 15,40,195 // movaps %xmm3,%xmm0 + .byte 15,92,194 // subps %xmm2,%xmm0 + .byte 68,15,94,224 // divps %xmm0,%xmm12 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,93,236 // minps %xmm12,%xmm13 + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 15,194,195,0 // cmpeqps %xmm3,%xmm0 + .byte 68,15,89,235 // mulps %xmm3,%xmm13 + .byte 69,15,88,235 // addps %xmm11,%xmm13 + .byte 102,68,15,56,20,234 // blendvps %xmm0,%xmm2,%xmm13 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 65,15,88,213 // addps %xmm13,%xmm2 + .byte 68,15,194,206,0 // cmpeqps %xmm6,%xmm9 + .byte 68,15,88,222 // addps %xmm6,%xmm11 + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 102,65,15,56,20,211 // blendvps %xmm0,%xmm11,%xmm2 + .byte 68,15,89,215 // mulps %xmm7,%xmm10 + .byte 65,15,88,218 // addps %xmm10,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_hardlight_sse41 +.globl _sk_hardlight_sse41 +_sk_hardlight_sse41: + .byte 15,41,116,36,232 // movaps %xmm6,-0x18(%rsp) + .byte 68,15,40,229 // movaps %xmm5,%xmm12 + .byte 15,40,244 // movaps %xmm4,%xmm6 + .byte 15,40,227 // movaps %xmm3,%xmm4 + .byte 15,40,234 // movaps %xmm2,%xmm5 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 15,92,215 // subps %xmm7,%xmm2 + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 68,15,92,212 // subps %xmm4,%xmm10 + .byte 69,15,40,194 // movaps %xmm10,%xmm8 + .byte 68,15,89,198 // mulps %xmm6,%xmm8 + .byte 68,15,88,192 // addps %xmm0,%xmm8 + .byte 68,15,40,252 // movaps %xmm4,%xmm15 + .byte 69,15,92,249 // subps %xmm9,%xmm15 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,40,247 // movaps %xmm7,%xmm14 + .byte 15,40,199 // movaps %xmm7,%xmm0 + .byte 15,92,198 // subps %xmm6,%xmm0 + .byte 65,15,89,199 // mulps %xmm15,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 68,15,40,251 // movaps %xmm3,%xmm15 + .byte 68,15,92,248 // subps %xmm0,%xmm15 + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,194,196,2 // cmpleps %xmm4,%xmm0 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 69,15,88,201 // addps %xmm9,%xmm9 + .byte 102,69,15,56,20,249 // blendvps %xmm0,%xmm9,%xmm15 + .byte 68,15,40,218 // movaps %xmm2,%xmm11 + .byte 68,15,89,217 // mulps %xmm1,%xmm11 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 15,92,193 // subps %xmm1,%xmm0 + .byte 69,15,40,204 // movaps %xmm12,%xmm9 + .byte 69,15,92,233 // subps %xmm9,%xmm13 + .byte 68,15,89,232 // mulps %xmm0,%xmm13 + .byte 69,15,88,237 // addps %xmm13,%xmm13 + .byte 68,15,40,227 // movaps %xmm3,%xmm12 + .byte 69,15,92,229 // subps %xmm13,%xmm12 + .byte 15,40,193 // movaps %xmm1,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,194,196,2 // cmpleps %xmm4,%xmm0 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 69,15,40,233 // movaps %xmm9,%xmm13 + .byte 15,88,201 // addps %xmm1,%xmm1 + .byte 102,68,15,56,20,225 // blendvps %xmm0,%xmm1,%xmm12 + .byte 65,15,40,202 // movaps %xmm10,%xmm1 + .byte 69,15,40,202 // movaps %xmm10,%xmm9 + .byte 68,15,89,215 // mulps %xmm7,%xmm10 + .byte 69,15,88,199 // addps %xmm15,%xmm8 + .byte 65,15,89,205 // mulps %xmm13,%xmm1 + .byte 65,15,88,203 // addps %xmm11,%xmm1 + .byte 65,15,88,204 // addps %xmm12,%xmm1 + .byte 15,89,213 // mulps %xmm5,%xmm2 + .byte 68,15,40,92,36,232 // movaps -0x18(%rsp),%xmm11 + .byte 69,15,89,203 // mulps %xmm11,%xmm9 + .byte 68,15,88,202 // addps %xmm2,%xmm9 + .byte 15,40,197 // movaps %xmm5,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,194,196,2 // cmpleps %xmm4,%xmm0 + .byte 15,40,212 // movaps %xmm4,%xmm2 + .byte 15,92,213 // subps %xmm5,%xmm2 + .byte 65,15,89,235 // mulps %xmm11,%xmm5 + .byte 15,88,237 // addps %xmm5,%xmm5 + .byte 69,15,92,243 // subps %xmm11,%xmm14 + .byte 68,15,89,242 // mulps %xmm2,%xmm14 + .byte 69,15,88,246 // addps %xmm14,%xmm14 + .byte 65,15,92,222 // subps %xmm14,%xmm3 + .byte 102,15,56,20,221 // blendvps %xmm0,%xmm5,%xmm3 + .byte 68,15,88,203 // addps %xmm3,%xmm9 + .byte 65,15,88,226 // addps %xmm10,%xmm4 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 65,15,40,209 // movaps %xmm9,%xmm2 + .byte 15,40,220 // movaps %xmm4,%xmm3 + .byte 15,40,230 // movaps %xmm6,%xmm4 + .byte 65,15,40,237 // movaps %xmm13,%xmm5 + .byte 65,15,40,243 // movaps %xmm11,%xmm6 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_overlay_sse41 +.globl _sk_overlay_sse41 +_sk_overlay_sse41: + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 68,15,40,240 // movaps %xmm0,%xmm14 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,40,218 // movaps %xmm10,%xmm11 + .byte 68,15,92,223 // subps %xmm7,%xmm11 + .byte 65,15,40,195 // movaps %xmm11,%xmm0 + .byte 65,15,89,198 // mulps %xmm14,%xmm0 + .byte 68,15,92,211 // subps %xmm3,%xmm10 + .byte 69,15,40,194 // movaps %xmm10,%xmm8 + .byte 68,15,89,196 // mulps %xmm4,%xmm8 + .byte 68,15,88,192 // addps %xmm0,%xmm8 + .byte 68,15,40,235 // movaps %xmm3,%xmm13 + .byte 69,15,92,238 // subps %xmm14,%xmm13 + .byte 68,15,89,244 // mulps %xmm4,%xmm14 + .byte 15,40,207 // movaps %xmm7,%xmm1 + .byte 15,92,204 // subps %xmm4,%xmm1 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,194,199,2 // cmpleps %xmm7,%xmm0 + .byte 69,15,88,246 // addps %xmm14,%xmm14 + .byte 68,15,40,227 // movaps %xmm3,%xmm12 + .byte 68,15,89,231 // mulps %xmm7,%xmm12 + .byte 65,15,89,205 // mulps %xmm13,%xmm1 + .byte 15,88,201 // addps %xmm1,%xmm1 + .byte 69,15,40,236 // movaps %xmm12,%xmm13 + .byte 68,15,92,233 // subps %xmm1,%xmm13 + .byte 102,69,15,56,20,238 // blendvps %xmm0,%xmm14,%xmm13 + .byte 69,15,88,197 // addps %xmm13,%xmm8 + .byte 65,15,40,195 // movaps %xmm11,%xmm0 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,40,202 // movaps %xmm10,%xmm1 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 15,88,200 // addps %xmm0,%xmm1 + .byte 68,15,40,235 // movaps %xmm3,%xmm13 + .byte 69,15,92,233 // subps %xmm9,%xmm13 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 68,15,40,247 // movaps %xmm7,%xmm14 + .byte 68,15,92,245 // subps %xmm5,%xmm14 + .byte 15,40,197 // movaps %xmm5,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,194,199,2 // cmpleps %xmm7,%xmm0 + .byte 69,15,88,201 // addps %xmm9,%xmm9 + .byte 69,15,89,245 // mulps %xmm13,%xmm14 + .byte 69,15,88,246 // addps %xmm14,%xmm14 + .byte 69,15,40,236 // movaps %xmm12,%xmm13 + .byte 69,15,92,238 // subps %xmm14,%xmm13 + .byte 102,69,15,56,20,233 // blendvps %xmm0,%xmm9,%xmm13 + .byte 65,15,88,205 // addps %xmm13,%xmm1 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,40,202 // movaps %xmm10,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 69,15,88,203 // addps %xmm11,%xmm9 + .byte 68,15,40,219 // movaps %xmm3,%xmm11 + .byte 68,15,92,218 // subps %xmm2,%xmm11 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,92,238 // subps %xmm6,%xmm13 + .byte 15,40,198 // movaps %xmm6,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,194,199,2 // cmpleps %xmm7,%xmm0 + .byte 15,88,210 // addps %xmm2,%xmm2 + .byte 69,15,89,235 // mulps %xmm11,%xmm13 + .byte 69,15,88,237 // addps %xmm13,%xmm13 + .byte 69,15,92,229 // subps %xmm13,%xmm12 + .byte 102,68,15,56,20,226 // blendvps %xmm0,%xmm2,%xmm12 + .byte 69,15,88,204 // addps %xmm12,%xmm9 + .byte 68,15,89,215 // mulps %xmm7,%xmm10 + .byte 65,15,88,218 // addps %xmm10,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 65,15,40,209 // movaps %xmm9,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_softlight_sse41 +.globl _sk_softlight_sse41 +_sk_softlight_sse41: + .byte 15,41,116,36,216 // movaps %xmm6,-0x28(%rsp) + .byte 15,40,244 // movaps %xmm4,%xmm6 + .byte 15,41,84,36,232 // movaps %xmm2,-0x18(%rsp) + .byte 68,15,40,225 // movaps %xmm1,%xmm12 + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 15,87,228 // xorps %xmm4,%xmm4 + .byte 15,194,231,1 // cmpltps %xmm7,%xmm4 + .byte 15,40,198 // movaps %xmm6,%xmm0 + .byte 15,94,199 // divps %xmm7,%xmm0 + .byte 15,84,196 // andps %xmm4,%xmm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 68,15,40,209 // movaps %xmm1,%xmm10 + .byte 68,15,92,208 // subps %xmm0,%xmm10 + .byte 68,15,40,240 // movaps %xmm0,%xmm14 + .byte 68,15,40,248 // movaps %xmm0,%xmm15 + .byte 15,82,208 // rsqrtps %xmm0,%xmm2 + .byte 68,15,83,218 // rcpps %xmm2,%xmm11 + .byte 68,15,92,216 // subps %xmm0,%xmm11 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,40,208 // movaps %xmm0,%xmm2 + .byte 15,89,210 // mulps %xmm2,%xmm2 + .byte 15,88,208 // addps %xmm0,%xmm2 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 69,15,88,201 // addps %xmm9,%xmm9 + .byte 68,15,92,241 // subps %xmm1,%xmm14 + .byte 68,15,89,242 // mulps %xmm2,%xmm14 + .byte 184,0,0,224,64 // mov $0x40e00000,%eax + .byte 102,68,15,110,232 // movd %eax,%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,89,253 // mulps %xmm13,%xmm15 + .byte 69,15,88,254 // addps %xmm14,%xmm15 + .byte 15,40,198 // movaps %xmm6,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,194,199,2 // cmpleps %xmm7,%xmm0 + .byte 102,69,15,56,20,223 // blendvps %xmm0,%xmm15,%xmm11 + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 15,92,195 // subps %xmm3,%xmm0 + .byte 68,15,89,208 // mulps %xmm0,%xmm10 + .byte 68,15,88,211 // addps %xmm3,%xmm10 + .byte 68,15,89,214 // mulps %xmm6,%xmm10 + .byte 15,40,211 // movaps %xmm3,%xmm2 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 15,89,199 // mulps %xmm7,%xmm0 + .byte 68,15,89,216 // mulps %xmm0,%xmm11 + .byte 68,15,88,218 // addps %xmm2,%xmm11 + .byte 68,15,194,203,2 // cmpleps %xmm3,%xmm9 + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 102,69,15,56,20,218 // blendvps %xmm0,%xmm10,%xmm11 + .byte 68,15,40,213 // movaps %xmm5,%xmm10 + .byte 68,15,94,215 // divps %xmm7,%xmm10 + .byte 68,15,84,212 // andps %xmm4,%xmm10 + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 69,15,92,202 // subps %xmm10,%xmm9 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 15,88,210 // addps %xmm2,%xmm2 + .byte 15,88,210 // addps %xmm2,%xmm2 + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 15,89,192 // mulps %xmm0,%xmm0 + .byte 15,88,194 // addps %xmm2,%xmm0 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 15,92,209 // subps %xmm1,%xmm2 + .byte 15,89,208 // mulps %xmm0,%xmm2 + .byte 65,15,82,194 // rsqrtps %xmm10,%xmm0 + .byte 68,15,83,240 // rcpps %xmm0,%xmm14 + .byte 69,15,92,242 // subps %xmm10,%xmm14 + .byte 69,15,89,213 // mulps %xmm13,%xmm10 + .byte 68,15,88,210 // addps %xmm2,%xmm10 + .byte 15,40,197 // movaps %xmm5,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,194,199,2 // cmpleps %xmm7,%xmm0 + .byte 102,69,15,56,20,242 // blendvps %xmm0,%xmm10,%xmm14 + .byte 65,15,40,196 // movaps %xmm12,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,40,208 // movaps %xmm0,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 68,15,88,203 // addps %xmm3,%xmm9 + .byte 15,41,108,36,200 // movaps %xmm5,-0x38(%rsp) + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 68,15,89,242 // mulps %xmm2,%xmm14 + .byte 15,40,211 // movaps %xmm3,%xmm2 + .byte 15,89,213 // mulps %xmm5,%xmm2 + .byte 68,15,88,242 // addps %xmm2,%xmm14 + .byte 68,15,40,249 // movaps %xmm1,%xmm15 + .byte 15,194,195,2 // cmpleps %xmm3,%xmm0 + .byte 102,69,15,56,20,241 // blendvps %xmm0,%xmm9,%xmm14 + .byte 68,15,40,209 // movaps %xmm1,%xmm10 + .byte 15,40,108,36,216 // movaps -0x28(%rsp),%xmm5 + .byte 15,40,197 // movaps %xmm5,%xmm0 + .byte 15,94,199 // divps %xmm7,%xmm0 + .byte 15,84,196 // andps %xmm4,%xmm0 + .byte 15,40,208 // movaps %xmm0,%xmm2 + .byte 15,92,209 // subps %xmm1,%xmm2 + .byte 15,92,200 // subps %xmm0,%xmm1 + .byte 68,15,89,232 // mulps %xmm0,%xmm13 + .byte 15,82,224 // rsqrtps %xmm0,%xmm4 + .byte 68,15,83,204 // rcpps %xmm4,%xmm9 + .byte 68,15,92,200 // subps %xmm0,%xmm9 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,40,224 // movaps %xmm0,%xmm4 + .byte 15,89,228 // mulps %xmm4,%xmm4 + .byte 15,88,224 // addps %xmm0,%xmm4 + .byte 15,89,226 // mulps %xmm2,%xmm4 + .byte 68,15,88,236 // addps %xmm4,%xmm13 + .byte 15,40,197 // movaps %xmm5,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,194,199,2 // cmpleps %xmm7,%xmm0 + .byte 102,69,15,56,20,205 // blendvps %xmm0,%xmm13,%xmm9 + .byte 68,15,40,108,36,232 // movaps -0x18(%rsp),%xmm13 + .byte 65,15,40,197 // movaps %xmm13,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 15,40,208 // movaps %xmm0,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 15,89,202 // mulps %xmm2,%xmm1 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 15,40,211 // movaps %xmm3,%xmm2 + .byte 15,89,213 // mulps %xmm5,%xmm2 + .byte 68,15,88,202 // addps %xmm2,%xmm9 + .byte 15,88,203 // addps %xmm3,%xmm1 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 15,40,213 // movaps %xmm5,%xmm2 + .byte 15,194,195,2 // cmpleps %xmm3,%xmm0 + .byte 102,68,15,56,20,201 // blendvps %xmm0,%xmm1,%xmm9 + .byte 68,15,92,255 // subps %xmm7,%xmm15 + .byte 69,15,89,199 // mulps %xmm15,%xmm8 + .byte 69,15,89,231 // mulps %xmm15,%xmm12 + .byte 69,15,89,253 // mulps %xmm13,%xmm15 + .byte 68,15,92,211 // subps %xmm3,%xmm10 + .byte 65,15,40,194 // movaps %xmm10,%xmm0 + .byte 15,89,198 // mulps %xmm6,%xmm0 + .byte 68,15,88,192 // addps %xmm0,%xmm8 + .byte 69,15,88,195 // addps %xmm11,%xmm8 + .byte 65,15,40,194 // movaps %xmm10,%xmm0 + .byte 15,40,108,36,200 // movaps -0x38(%rsp),%xmm5 + .byte 15,89,197 // mulps %xmm5,%xmm0 + .byte 68,15,88,224 // addps %xmm0,%xmm12 + .byte 69,15,88,230 // addps %xmm14,%xmm12 + .byte 65,15,40,194 // movaps %xmm10,%xmm0 + .byte 15,89,194 // mulps %xmm2,%xmm0 + .byte 65,15,88,199 // addps %xmm15,%xmm0 + .byte 68,15,88,200 // addps %xmm0,%xmm9 + .byte 68,15,89,215 // mulps %xmm7,%xmm10 + .byte 65,15,88,218 // addps %xmm10,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,230 // movaps %xmm6,%xmm4 + .byte 15,40,242 // movaps %xmm2,%xmm6 + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 65,15,40,204 // movaps %xmm12,%xmm1 + .byte 65,15,40,209 // movaps %xmm9,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_0_sse41 +.globl _sk_clamp_0_sse41 +_sk_clamp_0_sse41: + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 65,15,95,192 // maxps %xmm8,%xmm0 + .byte 65,15,95,200 // maxps %xmm8,%xmm1 + .byte 65,15,95,208 // maxps %xmm8,%xmm2 + .byte 65,15,95,216 // maxps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_1_sse41 +.globl _sk_clamp_1_sse41 +_sk_clamp_1_sse41: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,93,192 // minps %xmm8,%xmm0 + .byte 65,15,93,200 // minps %xmm8,%xmm1 + .byte 65,15,93,208 // minps %xmm8,%xmm2 + .byte 65,15,93,216 // minps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_a_sse41 +.globl _sk_clamp_a_sse41 +_sk_clamp_a_sse41: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,93,216 // minps %xmm8,%xmm3 + .byte 15,93,195 // minps %xmm3,%xmm0 + .byte 15,93,203 // minps %xmm3,%xmm1 + .byte 15,93,211 // minps %xmm3,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_set_rgb_sse41 +.globl _sk_set_rgb_sse41 +_sk_set_rgb_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,15,16,80,8 // movss 0x8(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_swap_rb_sse41 +.globl _sk_swap_rb_sse41 +_sk_swap_rb_sse41: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_swap_sse41 +.globl _sk_swap_sse41 +_sk_swap_sse41: + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 68,15,40,202 // movaps %xmm2,%xmm9 + .byte 68,15,40,209 // movaps %xmm1,%xmm10 + .byte 68,15,40,216 // movaps %xmm0,%xmm11 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 15,40,205 // movaps %xmm5,%xmm1 + .byte 15,40,214 // movaps %xmm6,%xmm2 + .byte 15,40,223 // movaps %xmm7,%xmm3 + .byte 65,15,40,227 // movaps %xmm11,%xmm4 + .byte 65,15,40,234 // movaps %xmm10,%xmm5 + .byte 65,15,40,241 // movaps %xmm9,%xmm6 + .byte 65,15,40,248 // movaps %xmm8,%xmm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_move_src_dst_sse41 +.globl _sk_move_src_dst_sse41 +_sk_move_src_dst_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,224 // movaps %xmm0,%xmm4 + .byte 15,40,233 // movaps %xmm1,%xmm5 + .byte 15,40,242 // movaps %xmm2,%xmm6 + .byte 15,40,251 // movaps %xmm3,%xmm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_move_dst_src_sse41 +.globl _sk_move_dst_src_sse41 +_sk_move_dst_src_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 15,40,205 // movaps %xmm5,%xmm1 + .byte 15,40,214 // movaps %xmm6,%xmm2 + .byte 15,40,223 // movaps %xmm7,%xmm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_premul_sse41 +.globl _sk_premul_sse41 +_sk_premul_sse41: + .byte 15,89,195 // mulps %xmm3,%xmm0 + .byte 15,89,203 // mulps %xmm3,%xmm1 + .byte 15,89,211 // mulps %xmm3,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_unpremul_sse41 +.globl _sk_unpremul_sse41 +_sk_unpremul_sse41: + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 68,15,94,203 // divps %xmm3,%xmm9 + .byte 68,15,194,195,4 // cmpneqps %xmm3,%xmm8 + .byte 69,15,84,193 // andps %xmm9,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_from_srgb_sse41 +.globl _sk_from_srgb_sse41 +_sk_from_srgb_sse41: + .byte 184,145,131,158,61 // mov $0x3d9e8391,%eax + .byte 102,68,15,110,216 // movd %eax,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,40,211 // movaps %xmm11,%xmm10 + .byte 68,15,89,208 // mulps %xmm0,%xmm10 + .byte 68,15,40,240 // movaps %xmm0,%xmm14 + .byte 69,15,89,246 // mulps %xmm14,%xmm14 + .byte 184,154,153,153,62 // mov $0x3e99999a,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 184,92,143,50,63 // mov $0x3f328f5c,%eax + .byte 102,68,15,110,224 // movd %eax,%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,200 // mulps %xmm0,%xmm9 + .byte 69,15,88,204 // addps %xmm12,%xmm9 + .byte 184,10,215,35,59 // mov $0x3b23d70a,%eax + .byte 102,68,15,110,232 // movd %eax,%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,89,206 // mulps %xmm14,%xmm9 + .byte 69,15,88,205 // addps %xmm13,%xmm9 + .byte 184,174,71,97,61 // mov $0x3d6147ae,%eax + .byte 102,68,15,110,240 // movd %eax,%xmm14 + .byte 69,15,198,246,0 // shufps $0x0,%xmm14,%xmm14 + .byte 65,15,194,198,1 // cmpltps %xmm14,%xmm0 + .byte 102,69,15,56,20,202 // blendvps %xmm0,%xmm10,%xmm9 + .byte 69,15,40,251 // movaps %xmm11,%xmm15 + .byte 68,15,89,249 // mulps %xmm1,%xmm15 + .byte 15,40,193 // movaps %xmm1,%xmm0 + .byte 15,89,192 // mulps %xmm0,%xmm0 + .byte 69,15,40,208 // movaps %xmm8,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 69,15,88,212 // addps %xmm12,%xmm10 + .byte 68,15,89,208 // mulps %xmm0,%xmm10 + .byte 69,15,88,213 // addps %xmm13,%xmm10 + .byte 65,15,194,206,1 // cmpltps %xmm14,%xmm1 + .byte 15,40,193 // movaps %xmm1,%xmm0 + .byte 102,69,15,56,20,215 // blendvps %xmm0,%xmm15,%xmm10 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 15,89,192 // mulps %xmm0,%xmm0 + .byte 68,15,89,194 // mulps %xmm2,%xmm8 + .byte 69,15,88,196 // addps %xmm12,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 69,15,88,197 // addps %xmm13,%xmm8 + .byte 65,15,194,214,1 // cmpltps %xmm14,%xmm2 + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 102,69,15,56,20,195 // blendvps %xmm0,%xmm11,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 65,15,40,202 // movaps %xmm10,%xmm1 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_to_srgb_sse41 +.globl _sk_to_srgb_sse41 +_sk_to_srgb_sse41: + .byte 15,41,124,36,232 // movaps %xmm7,-0x18(%rsp) + .byte 15,40,254 // movaps %xmm6,%xmm7 + .byte 15,40,245 // movaps %xmm5,%xmm6 + .byte 15,40,236 // movaps %xmm4,%xmm5 + .byte 15,40,227 // movaps %xmm3,%xmm4 + .byte 15,40,218 // movaps %xmm2,%xmm3 + .byte 15,40,209 // movaps %xmm1,%xmm2 + .byte 68,15,82,192 // rsqrtps %xmm0,%xmm8 + .byte 69,15,83,200 // rcpps %xmm8,%xmm9 + .byte 69,15,82,248 // rsqrtps %xmm8,%xmm15 + .byte 184,41,92,71,65 // mov $0x41475c29,%eax + .byte 102,68,15,110,216 // movd %eax,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,40,211 // movaps %xmm11,%xmm10 + .byte 68,15,89,208 // mulps %xmm0,%xmm10 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 184,194,135,210,62 // mov $0x3ed287c2,%eax + .byte 102,68,15,110,224 // movd %eax,%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 184,206,111,48,63 // mov $0x3f306fce,%eax + .byte 102,68,15,110,232 // movd %eax,%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 184,168,87,202,61 // mov $0x3dca57a8,%eax + .byte 53,0,0,0,128 // xor $0x80000000,%eax + .byte 102,68,15,110,240 // movd %eax,%xmm14 + .byte 69,15,198,246,0 // shufps $0x0,%xmm14,%xmm14 + .byte 69,15,89,205 // mulps %xmm13,%xmm9 + .byte 69,15,88,206 // addps %xmm14,%xmm9 + .byte 69,15,89,252 // mulps %xmm12,%xmm15 + .byte 69,15,88,249 // addps %xmm9,%xmm15 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 69,15,93,207 // minps %xmm15,%xmm9 + .byte 184,4,231,140,59 // mov $0x3b8ce704,%eax + .byte 102,68,15,110,248 // movd %eax,%xmm15 + .byte 69,15,198,255,0 // shufps $0x0,%xmm15,%xmm15 + .byte 65,15,194,199,1 // cmpltps %xmm15,%xmm0 + .byte 102,69,15,56,20,202 // blendvps %xmm0,%xmm10,%xmm9 + .byte 68,15,82,210 // rsqrtps %xmm2,%xmm10 + .byte 65,15,83,194 // rcpps %xmm10,%xmm0 + .byte 69,15,82,210 // rsqrtps %xmm10,%xmm10 + .byte 65,15,89,197 // mulps %xmm13,%xmm0 + .byte 65,15,88,198 // addps %xmm14,%xmm0 + .byte 69,15,89,212 // mulps %xmm12,%xmm10 + .byte 68,15,88,208 // addps %xmm0,%xmm10 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 65,15,93,202 // minps %xmm10,%xmm1 + .byte 69,15,40,211 // movaps %xmm11,%xmm10 + .byte 68,15,89,210 // mulps %xmm2,%xmm10 + .byte 65,15,194,215,1 // cmpltps %xmm15,%xmm2 + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 102,65,15,56,20,202 // blendvps %xmm0,%xmm10,%xmm1 + .byte 15,82,195 // rsqrtps %xmm3,%xmm0 + .byte 15,83,208 // rcpps %xmm0,%xmm2 + .byte 65,15,89,213 // mulps %xmm13,%xmm2 + .byte 65,15,88,214 // addps %xmm14,%xmm2 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 65,15,89,196 // mulps %xmm12,%xmm0 + .byte 15,88,194 // addps %xmm2,%xmm0 + .byte 68,15,93,192 // minps %xmm0,%xmm8 + .byte 68,15,89,219 // mulps %xmm3,%xmm11 + .byte 65,15,194,223,1 // cmpltps %xmm15,%xmm3 + .byte 15,40,195 // movaps %xmm3,%xmm0 + .byte 102,69,15,56,20,195 // blendvps %xmm0,%xmm11,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 15,40,220 // movaps %xmm4,%xmm3 + .byte 15,40,229 // movaps %xmm5,%xmm4 + .byte 15,40,238 // movaps %xmm6,%xmm5 + .byte 15,40,247 // movaps %xmm7,%xmm6 + .byte 15,40,124,36,232 // movaps -0x18(%rsp),%xmm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_from_2dot2_sse41 +.globl _sk_from_2dot2_sse41 +_sk_from_2dot2_sse41: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 65,15,82,192 // rsqrtps %xmm8,%xmm0 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 68,15,82,200 // rsqrtps %xmm0,%xmm9 + .byte 65,15,82,193 // rsqrtps %xmm9,%xmm0 + .byte 68,15,82,208 // rsqrtps %xmm0,%xmm10 + .byte 69,15,89,192 // mulps %xmm8,%xmm8 + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 15,89,192 // mulps %xmm0,%xmm0 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,89,194 // mulps %xmm10,%xmm0 + .byte 69,15,87,210 // xorps %xmm10,%xmm10 + .byte 65,15,95,194 // maxps %xmm10,%xmm0 + .byte 68,15,82,193 // rsqrtps %xmm1,%xmm8 + .byte 69,15,82,192 // rsqrtps %xmm8,%xmm8 + .byte 69,15,82,192 // rsqrtps %xmm8,%xmm8 + .byte 69,15,82,200 // rsqrtps %xmm8,%xmm9 + .byte 69,15,82,193 // rsqrtps %xmm9,%xmm8 + .byte 69,15,82,216 // rsqrtps %xmm8,%xmm11 + .byte 15,89,201 // mulps %xmm1,%xmm1 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 69,15,89,192 // mulps %xmm8,%xmm8 + .byte 69,15,89,193 // mulps %xmm9,%xmm8 + .byte 68,15,89,193 // mulps %xmm1,%xmm8 + .byte 69,15,89,195 // mulps %xmm11,%xmm8 + .byte 69,15,95,194 // maxps %xmm10,%xmm8 + .byte 15,82,202 // rsqrtps %xmm2,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 68,15,82,217 // rsqrtps %xmm1,%xmm11 + .byte 65,15,82,203 // rsqrtps %xmm11,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 15,89,210 // mulps %xmm2,%xmm2 + .byte 69,15,40,203 // movaps %xmm11,%xmm9 + .byte 69,15,89,201 // mulps %xmm9,%xmm9 + .byte 69,15,89,203 // mulps %xmm11,%xmm9 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 68,15,89,201 // mulps %xmm1,%xmm9 + .byte 69,15,95,202 // maxps %xmm10,%xmm9 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 65,15,40,209 // movaps %xmm9,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_to_2dot2_sse41 +.globl _sk_to_2dot2_sse41 +_sk_to_2dot2_sse41: + .byte 68,15,82,192 // rsqrtps %xmm0,%xmm8 + .byte 65,15,82,192 // rsqrtps %xmm8,%xmm0 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 68,15,82,200 // rsqrtps %xmm0,%xmm9 + .byte 69,15,83,192 // rcpps %xmm8,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 65,15,83,193 // rcpps %xmm9,%xmm0 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 65,15,95,192 // maxps %xmm8,%xmm0 + .byte 68,15,82,201 // rsqrtps %xmm1,%xmm9 + .byte 65,15,82,201 // rsqrtps %xmm9,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 68,15,82,209 // rsqrtps %xmm1,%xmm10 + .byte 69,15,83,201 // rcpps %xmm9,%xmm9 + .byte 68,15,89,201 // mulps %xmm1,%xmm9 + .byte 65,15,83,202 // rcpps %xmm10,%xmm1 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 65,15,95,200 // maxps %xmm8,%xmm1 + .byte 68,15,82,202 // rsqrtps %xmm2,%xmm9 + .byte 65,15,82,209 // rsqrtps %xmm9,%xmm2 + .byte 15,82,210 // rsqrtps %xmm2,%xmm2 + .byte 15,82,210 // rsqrtps %xmm2,%xmm2 + .byte 15,82,210 // rsqrtps %xmm2,%xmm2 + .byte 68,15,82,210 // rsqrtps %xmm2,%xmm10 + .byte 69,15,83,201 // rcpps %xmm9,%xmm9 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 65,15,83,210 // rcpps %xmm10,%xmm2 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 65,15,95,208 // maxps %xmm8,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_rgb_to_hsl_sse41 +.globl _sk_rgb_to_hsl_sse41 +_sk_rgb_to_hsl_sse41: + .byte 15,41,124,36,232 // movaps %xmm7,-0x18(%rsp) + .byte 15,40,254 // movaps %xmm6,%xmm7 + .byte 15,40,245 // movaps %xmm5,%xmm6 + .byte 15,40,236 // movaps %xmm4,%xmm5 + .byte 15,40,227 // movaps %xmm3,%xmm4 + .byte 15,40,218 // movaps %xmm2,%xmm3 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,216 // movd %eax,%xmm11 + .byte 65,184,171,170,42,62 // mov $0x3e2aaaab,%r8d + .byte 65,185,0,0,192,64 // mov $0x40c00000,%r9d + .byte 184,0,0,0,64 // mov $0x40000000,%eax + .byte 185,0,0,128,64 // mov $0x40800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 68,15,40,224 // movaps %xmm0,%xmm12 + .byte 68,15,95,225 // maxps %xmm1,%xmm12 + .byte 68,15,95,227 // maxps %xmm3,%xmm12 + .byte 68,15,40,232 // movaps %xmm0,%xmm13 + .byte 68,15,93,233 // minps %xmm1,%xmm13 + .byte 68,15,93,235 // minps %xmm3,%xmm13 + .byte 69,15,40,204 // movaps %xmm12,%xmm9 + .byte 68,15,194,200,0 // cmpeqps %xmm0,%xmm9 + .byte 68,15,40,241 // movaps %xmm1,%xmm14 + .byte 68,15,92,243 // subps %xmm3,%xmm14 + .byte 68,15,40,249 // movaps %xmm1,%xmm15 + .byte 68,15,194,251,1 // cmpltps %xmm3,%xmm15 + .byte 69,15,40,212 // movaps %xmm12,%xmm10 + .byte 68,15,194,209,0 // cmpeqps %xmm1,%xmm10 + .byte 15,92,216 // subps %xmm0,%xmm3 + .byte 15,92,193 // subps %xmm1,%xmm0 + .byte 65,15,40,212 // movaps %xmm12,%xmm2 + .byte 65,15,92,213 // subps %xmm13,%xmm2 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 68,15,94,218 // divps %xmm2,%xmm11 + .byte 65,15,89,195 // mulps %xmm11,%xmm0 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,88,192 // addps %xmm0,%xmm8 + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 65,15,89,219 // mulps %xmm11,%xmm3 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 15,88,217 // addps %xmm1,%xmm3 + .byte 65,15,40,194 // movaps %xmm10,%xmm0 + .byte 102,68,15,56,20,195 // blendvps %xmm0,%xmm3,%xmm8 + .byte 69,15,89,243 // mulps %xmm11,%xmm14 + .byte 102,65,15,110,217 // movd %r9d,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,84,223 // andps %xmm15,%xmm3 + .byte 65,15,88,222 // addps %xmm14,%xmm3 + .byte 184,0,0,0,63 // mov $0x3f000000,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 102,68,15,56,20,195 // blendvps %xmm0,%xmm3,%xmm8 + .byte 65,15,40,220 // movaps %xmm12,%xmm3 + .byte 65,15,92,204 // subps %xmm12,%xmm1 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,40,204 // movaps %xmm12,%xmm9 + .byte 69,15,89,202 // mulps %xmm10,%xmm9 + .byte 69,15,194,209,1 // cmpltps %xmm9,%xmm10 + .byte 65,15,92,205 // subps %xmm13,%xmm1 + .byte 65,15,40,194 // movaps %xmm10,%xmm0 + .byte 102,68,15,56,20,225 // blendvps %xmm0,%xmm1,%xmm12 + .byte 65,15,194,221,4 // cmpneqps %xmm13,%xmm3 + .byte 102,65,15,110,192 // movd %r8d,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 68,15,84,195 // andps %xmm3,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 65,15,94,212 // divps %xmm12,%xmm2 + .byte 15,84,211 // andps %xmm3,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 15,40,202 // movaps %xmm2,%xmm1 + .byte 65,15,40,209 // movaps %xmm9,%xmm2 + .byte 15,40,220 // movaps %xmm4,%xmm3 + .byte 15,40,229 // movaps %xmm5,%xmm4 + .byte 15,40,238 // movaps %xmm6,%xmm5 + .byte 15,40,247 // movaps %xmm7,%xmm6 + .byte 15,40,124,36,232 // movaps -0x18(%rsp),%xmm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_hsl_to_rgb_sse41 +.globl _sk_hsl_to_rgb_sse41 +_sk_hsl_to_rgb_sse41: + .byte 72,131,236,24 // sub $0x18,%rsp + .byte 15,41,60,36 // movaps %xmm7,(%rsp) + .byte 15,41,116,36,240 // movaps %xmm6,-0x10(%rsp) + .byte 15,41,108,36,224 // movaps %xmm5,-0x20(%rsp) + .byte 15,41,100,36,208 // movaps %xmm4,-0x30(%rsp) + .byte 15,41,92,36,192 // movaps %xmm3,-0x40(%rsp) + .byte 68,15,40,208 // movaps %xmm0,%xmm10 + .byte 184,0,0,0,63 // mov $0x3f000000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 15,41,92,36,128 // movaps %xmm3,-0x80(%rsp) + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 15,194,195,1 // cmpltps %xmm3,%xmm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,40,224 // movaps %xmm8,%xmm4 + .byte 15,88,225 // addps %xmm1,%xmm4 + .byte 15,89,226 // mulps %xmm2,%xmm4 + .byte 15,40,217 // movaps %xmm1,%xmm3 + .byte 15,40,249 // movaps %xmm1,%xmm7 + .byte 15,88,250 // addps %xmm2,%xmm7 + .byte 15,89,218 // mulps %xmm2,%xmm3 + .byte 15,40,234 // movaps %xmm2,%xmm5 + .byte 15,92,251 // subps %xmm3,%xmm7 + .byte 102,15,56,20,252 // blendvps %xmm0,%xmm4,%xmm7 + .byte 184,0,0,0,64 // mov $0x40000000,%eax + .byte 185,171,170,170,62 // mov $0x3eaaaaab,%ecx + .byte 102,15,110,209 // movd %ecx,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,41,84,36,176 // movaps %xmm2,-0x50(%rsp) + .byte 65,15,88,210 // addps %xmm10,%xmm2 + .byte 185,0,0,0,0 // mov $0x0,%ecx + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 15,194,194,1 // cmpltps %xmm2,%xmm0 + .byte 15,40,218 // movaps %xmm2,%xmm3 + .byte 65,15,92,216 // subps %xmm8,%xmm3 + .byte 68,15,40,226 // movaps %xmm2,%xmm12 + .byte 102,68,15,56,20,227 // blendvps %xmm0,%xmm3,%xmm12 + .byte 102,68,15,110,241 // movd %ecx,%xmm14 + .byte 69,15,198,246,0 // shufps $0x0,%xmm14,%xmm14 + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 65,15,194,198,1 // cmpltps %xmm14,%xmm0 + .byte 68,15,41,116,36,160 // movaps %xmm14,-0x60(%rsp) + .byte 65,15,40,216 // movaps %xmm8,%xmm3 + .byte 15,88,218 // addps %xmm2,%xmm3 + .byte 102,68,15,56,20,227 // blendvps %xmm0,%xmm3,%xmm12 + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 15,40,229 // movaps %xmm5,%xmm4 + .byte 15,41,100,36,144 // movaps %xmm4,-0x70(%rsp) + .byte 68,15,89,204 // mulps %xmm4,%xmm9 + .byte 68,15,92,207 // subps %xmm7,%xmm9 + .byte 184,171,170,42,62 // mov $0x3e2aaaab,%eax + .byte 15,40,199 // movaps %xmm7,%xmm0 + .byte 65,15,92,193 // subps %xmm9,%xmm0 + .byte 185,0,0,192,64 // mov $0x40c00000,%ecx + .byte 102,15,110,241 // movd %ecx,%xmm6 + .byte 15,198,246,0 // shufps $0x0,%xmm6,%xmm6 + .byte 15,89,240 // mulps %xmm0,%xmm6 + .byte 185,171,170,42,63 // mov $0x3f2aaaab,%ecx + .byte 102,15,110,217 // movd %ecx,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 15,40,235 // movaps %xmm3,%xmm5 + .byte 65,15,92,236 // subps %xmm12,%xmm5 + .byte 69,15,40,236 // movaps %xmm12,%xmm13 + .byte 69,15,40,252 // movaps %xmm12,%xmm15 + .byte 68,15,194,227,1 // cmpltps %xmm3,%xmm12 + .byte 15,89,238 // mulps %xmm6,%xmm5 + .byte 65,15,88,233 // addps %xmm9,%xmm5 + .byte 69,15,40,217 // movaps %xmm9,%xmm11 + .byte 65,15,40,196 // movaps %xmm12,%xmm0 + .byte 102,68,15,56,20,221 // blendvps %xmm0,%xmm5,%xmm11 + .byte 68,15,194,124,36,128,1 // cmpltps -0x80(%rsp),%xmm15 + .byte 65,15,40,199 // movaps %xmm15,%xmm0 + .byte 102,68,15,56,20,223 // blendvps %xmm0,%xmm7,%xmm11 + .byte 102,15,110,232 // movd %eax,%xmm5 + .byte 15,198,237,0 // shufps $0x0,%xmm5,%xmm5 + .byte 68,15,194,237,1 // cmpltps %xmm5,%xmm13 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 65,15,88,209 // addps %xmm9,%xmm2 + .byte 65,15,40,197 // movaps %xmm13,%xmm0 + .byte 102,68,15,56,20,218 // blendvps %xmm0,%xmm2,%xmm11 + .byte 69,15,87,228 // xorps %xmm12,%xmm12 + .byte 68,15,194,225,0 // cmpeqps %xmm1,%xmm12 + .byte 65,15,40,196 // movaps %xmm12,%xmm0 + .byte 102,68,15,56,20,220 // blendvps %xmm0,%xmm4,%xmm11 + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 65,15,194,194,1 // cmpltps %xmm10,%xmm0 + .byte 65,15,40,202 // movaps %xmm10,%xmm1 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 69,15,40,234 // movaps %xmm10,%xmm13 + .byte 102,68,15,56,20,233 // blendvps %xmm0,%xmm1,%xmm13 + .byte 65,15,40,194 // movaps %xmm10,%xmm0 + .byte 65,15,194,198,1 // cmpltps %xmm14,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 65,15,88,202 // addps %xmm10,%xmm1 + .byte 102,68,15,56,20,233 // blendvps %xmm0,%xmm1,%xmm13 + .byte 68,15,40,243 // movaps %xmm3,%xmm14 + .byte 69,15,92,245 // subps %xmm13,%xmm14 + .byte 65,15,40,229 // movaps %xmm13,%xmm4 + .byte 69,15,40,253 // movaps %xmm13,%xmm15 + .byte 68,15,194,235,1 // cmpltps %xmm3,%xmm13 + .byte 68,15,89,246 // mulps %xmm6,%xmm14 + .byte 69,15,88,241 // addps %xmm9,%xmm14 + .byte 65,15,40,201 // movaps %xmm9,%xmm1 + .byte 65,15,40,197 // movaps %xmm13,%xmm0 + .byte 102,65,15,56,20,206 // blendvps %xmm0,%xmm14,%xmm1 + .byte 68,15,40,116,36,128 // movaps -0x80(%rsp),%xmm14 + .byte 69,15,194,254,1 // cmpltps %xmm14,%xmm15 + .byte 65,15,40,199 // movaps %xmm15,%xmm0 + .byte 102,15,56,20,207 // blendvps %xmm0,%xmm7,%xmm1 + .byte 15,194,229,1 // cmpltps %xmm5,%xmm4 + .byte 15,40,214 // movaps %xmm6,%xmm2 + .byte 65,15,89,210 // mulps %xmm10,%xmm2 + .byte 65,15,88,209 // addps %xmm9,%xmm2 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 102,15,56,20,202 // blendvps %xmm0,%xmm2,%xmm1 + .byte 65,15,40,196 // movaps %xmm12,%xmm0 + .byte 68,15,40,124,36,144 // movaps -0x70(%rsp),%xmm15 + .byte 102,65,15,56,20,207 // blendvps %xmm0,%xmm15,%xmm1 + .byte 68,15,92,84,36,176 // subps -0x50(%rsp),%xmm10 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 65,15,92,208 // subps %xmm8,%xmm2 + .byte 69,15,40,232 // movaps %xmm8,%xmm13 + .byte 69,15,194,194,1 // cmpltps %xmm10,%xmm8 + .byte 65,15,40,226 // movaps %xmm10,%xmm4 + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 102,15,56,20,226 // blendvps %xmm0,%xmm2,%xmm4 + .byte 65,15,40,194 // movaps %xmm10,%xmm0 + .byte 15,194,68,36,160,1 // cmpltps -0x60(%rsp),%xmm0 + .byte 69,15,88,234 // addps %xmm10,%xmm13 + .byte 102,65,15,56,20,229 // blendvps %xmm0,%xmm13,%xmm4 + .byte 68,15,89,214 // mulps %xmm6,%xmm10 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 15,194,195,1 // cmpltps %xmm3,%xmm0 + .byte 15,92,220 // subps %xmm4,%xmm3 + .byte 15,89,222 // mulps %xmm6,%xmm3 + .byte 69,15,88,209 // addps %xmm9,%xmm10 + .byte 65,15,88,217 // addps %xmm9,%xmm3 + .byte 102,68,15,56,20,203 // blendvps %xmm0,%xmm3,%xmm9 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 65,15,194,198,1 // cmpltps %xmm14,%xmm0 + .byte 102,68,15,56,20,207 // blendvps %xmm0,%xmm7,%xmm9 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 15,194,197,1 // cmpltps %xmm5,%xmm0 + .byte 102,69,15,56,20,202 // blendvps %xmm0,%xmm10,%xmm9 + .byte 65,15,40,196 // movaps %xmm12,%xmm0 + .byte 102,69,15,56,20,207 // blendvps %xmm0,%xmm15,%xmm9 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,195 // movaps %xmm11,%xmm0 + .byte 65,15,40,209 // movaps %xmm9,%xmm2 + .byte 15,40,92,36,192 // movaps -0x40(%rsp),%xmm3 + .byte 15,40,100,36,208 // movaps -0x30(%rsp),%xmm4 + .byte 15,40,108,36,224 // movaps -0x20(%rsp),%xmm5 + .byte 15,40,116,36,240 // movaps -0x10(%rsp),%xmm6 + .byte 15,40,60,36 // movaps (%rsp),%xmm7 + .byte 72,131,196,24 // add $0x18,%rsp + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_scale_1_float_sse41 +.globl _sk_scale_1_float_sse41 +_sk_scale_1_float_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,0 // movss (%rax),%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_scale_u8_sse41 +.globl _sk_scale_u8_sse41 +_sk_scale_u8_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,68,15,56,49,4,56 // pmovzxbd (%rax,%rdi,1),%xmm8 + .byte 69,15,91,192 // cvtdq2ps %xmm8,%xmm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 65,15,89,217 // mulps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lerp_1_float_sse41 +.globl _sk_lerp_1_float_sse41 +_sk_lerp_1_float_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,0 // movss (%rax),%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,92,196 // subps %xmm4,%xmm0 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 15,92,205 // subps %xmm5,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 15,92,214 // subps %xmm6,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 15,92,223 // subps %xmm7,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 15,88,223 // addps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lerp_u8_sse41 +.globl _sk_lerp_u8_sse41 +_sk_lerp_u8_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,68,15,56,49,4,56 // pmovzxbd (%rax,%rdi,1),%xmm8 + .byte 69,15,91,192 // cvtdq2ps %xmm8,%xmm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 15,92,196 // subps %xmm4,%xmm0 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 15,92,205 // subps %xmm5,%xmm1 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 15,92,214 // subps %xmm6,%xmm2 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 15,92,223 // subps %xmm7,%xmm3 + .byte 65,15,89,217 // mulps %xmm9,%xmm3 + .byte 15,88,223 // addps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lerp_565_sse41 +.globl _sk_lerp_565_sse41 +_sk_lerp_565_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,68,15,56,51,4,120 // pmovzxwd (%rax,%rdi,2),%xmm8 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,65,15,219,216 // pand %xmm8,%xmm3 + .byte 68,15,91,203 // cvtdq2ps %xmm3,%xmm9 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,65,15,219,216 // pand %xmm8,%xmm3 + .byte 68,15,91,203 // cvtdq2ps %xmm3,%xmm9 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 102,68,15,110,216 // movd %eax,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,217 // mulps %xmm9,%xmm11 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,65,15,219,216 // pand %xmm8,%xmm3 + .byte 68,15,91,195 // cvtdq2ps %xmm3,%xmm8 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 15,92,196 // subps %xmm4,%xmm0 + .byte 65,15,89,194 // mulps %xmm10,%xmm0 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 15,92,205 // subps %xmm5,%xmm1 + .byte 65,15,89,203 // mulps %xmm11,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 15,92,214 // subps %xmm6,%xmm2 + .byte 15,89,211 // mulps %xmm3,%xmm2 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_tables_sse41 +.globl _sk_load_tables_sse41 +_sk_load_tables_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,8 // mov (%rax),%rcx + .byte 76,139,64,8 // mov 0x8(%rax),%r8 + .byte 243,68,15,111,4,185 // movdqu (%rcx,%rdi,4),%xmm8 + .byte 185,255,0,0,0 // mov $0xff,%ecx + .byte 102,15,110,193 // movd %ecx,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,65,15,111,200 // movdqa %xmm8,%xmm1 + .byte 102,15,114,209,8 // psrld $0x8,%xmm1 + .byte 102,15,219,200 // pand %xmm0,%xmm1 + .byte 102,65,15,111,208 // movdqa %xmm8,%xmm2 + .byte 102,15,114,210,16 // psrld $0x10,%xmm2 + .byte 102,15,219,208 // pand %xmm0,%xmm2 + .byte 102,65,15,219,192 // pand %xmm8,%xmm0 + .byte 102,72,15,58,22,193,1 // pextrq $0x1,%xmm0,%rcx + .byte 65,137,201 // mov %ecx,%r9d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,73,15,126,194 // movq %xmm0,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 243,67,15,16,4,152 // movss (%r8,%r11,4),%xmm0 + .byte 102,67,15,58,33,4,144,16 // insertps $0x10,(%r8,%r10,4),%xmm0 + .byte 102,67,15,58,33,4,136,32 // insertps $0x20,(%r8,%r9,4),%xmm0 + .byte 102,65,15,58,33,4,136,48 // insertps $0x30,(%r8,%rcx,4),%xmm0 + .byte 76,139,64,16 // mov 0x10(%rax),%r8 + .byte 102,73,15,58,22,202,1 // pextrq $0x1,%xmm1,%r10 + .byte 77,137,209 // mov %r10,%r9 + .byte 73,193,233,32 // shr $0x20,%r9 + .byte 102,72,15,126,201 // movq %xmm1,%rcx + .byte 65,137,203 // mov %ecx,%r11d + .byte 65,129,227,255,255,255,0 // and $0xffffff,%r11d + .byte 72,193,233,30 // shr $0x1e,%rcx + .byte 65,129,226,255,255,255,0 // and $0xffffff,%r10d + .byte 243,67,15,16,12,152 // movss (%r8,%r11,4),%xmm1 + .byte 102,65,15,58,33,12,8,16 // insertps $0x10,(%r8,%rcx,1),%xmm1 + .byte 243,67,15,16,28,144 // movss (%r8,%r10,4),%xmm3 + .byte 102,15,58,33,203,32 // insertps $0x20,%xmm3,%xmm1 + .byte 243,67,15,16,28,136 // movss (%r8,%r9,4),%xmm3 + .byte 102,15,58,33,203,48 // insertps $0x30,%xmm3,%xmm1 + .byte 76,139,72,24 // mov 0x18(%rax),%r9 + .byte 102,72,15,58,22,209,1 // pextrq $0x1,%xmm2,%rcx + .byte 68,15,183,193 // movzwl %cx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,72,15,126,208 // movq %xmm2,%rax + .byte 68,15,183,208 // movzwl %ax,%r10d + .byte 72,193,232,30 // shr $0x1e,%rax + .byte 243,67,15,16,20,145 // movss (%r9,%r10,4),%xmm2 + .byte 102,65,15,58,33,20,1,16 // insertps $0x10,(%r9,%rax,1),%xmm2 + .byte 243,67,15,16,28,129 // movss (%r9,%r8,4),%xmm3 + .byte 102,15,58,33,211,32 // insertps $0x20,%xmm3,%xmm2 + .byte 243,65,15,16,28,137 // movss (%r9,%rcx,4),%xmm3 + .byte 102,15,58,33,211,48 // insertps $0x30,%xmm3,%xmm2 + .byte 102,65,15,114,208,24 // psrld $0x18,%xmm8 + .byte 69,15,91,192 // cvtdq2ps %xmm8,%xmm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_byte_tables_sse41 +.globl _sk_byte_tables_sse41 +_sk_byte_tables_sse41: + .byte 65,86 // push %r14 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,127,67 // mov $0x437f0000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 102,15,91,192 // cvtps2dq %xmm0,%xmm0 + .byte 102,72,15,58,22,193,1 // pextrq $0x1,%xmm0,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,73,15,126,193 // movq %xmm0,%r9 + .byte 69,137,202 // mov %r9d,%r10d + .byte 77,137,203 // mov %r9,%r11 + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 76,139,48 // mov (%rax),%r14 + .byte 76,139,72,8 // mov 0x8(%rax),%r9 + .byte 102,67,15,58,32,4,22,0 // pinsrb $0x0,(%r14,%r10,1),%xmm0 + .byte 102,67,15,58,32,4,30,1 // pinsrb $0x1,(%r14,%r11,1),%xmm0 + .byte 67,15,182,28,6 // movzbl (%r14,%r8,1),%ebx + .byte 102,15,58,32,195,2 // pinsrb $0x2,%ebx,%xmm0 + .byte 65,15,182,12,14 // movzbl (%r14,%rcx,1),%ecx + .byte 102,15,58,32,193,3 // pinsrb $0x3,%ecx,%xmm0 + .byte 102,15,56,49,192 // pmovzxbd %xmm0,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 185,129,128,128,59 // mov $0x3b808081,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 102,15,91,201 // cvtps2dq %xmm1,%xmm1 + .byte 102,72,15,58,22,201,1 // pextrq $0x1,%xmm1,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,72,15,126,203 // movq %xmm1,%rbx + .byte 65,137,218 // mov %ebx,%r10d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 102,67,15,58,32,12,17,0 // pinsrb $0x0,(%r9,%r10,1),%xmm1 + .byte 102,65,15,58,32,12,25,1 // pinsrb $0x1,(%r9,%rbx,1),%xmm1 + .byte 67,15,182,28,1 // movzbl (%r9,%r8,1),%ebx + .byte 102,15,58,32,203,2 // pinsrb $0x2,%ebx,%xmm1 + .byte 65,15,182,12,9 // movzbl (%r9,%rcx,1),%ecx + .byte 102,15,58,32,201,3 // pinsrb $0x3,%ecx,%xmm1 + .byte 102,15,56,49,201 // pmovzxbd %xmm1,%xmm1 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 76,139,72,16 // mov 0x10(%rax),%r9 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,15,91,210 // cvtps2dq %xmm2,%xmm2 + .byte 102,72,15,58,22,211,1 // pextrq $0x1,%xmm2,%rbx + .byte 65,137,216 // mov %ebx,%r8d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 102,72,15,126,209 // movq %xmm2,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,67,15,58,32,20,17,0 // pinsrb $0x0,(%r9,%r10,1),%xmm2 + .byte 102,65,15,58,32,20,9,1 // pinsrb $0x1,(%r9,%rcx,1),%xmm2 + .byte 67,15,182,12,1 // movzbl (%r9,%r8,1),%ecx + .byte 102,15,58,32,209,2 // pinsrb $0x2,%ecx,%xmm2 + .byte 65,15,182,12,25 // movzbl (%r9,%rbx,1),%ecx + .byte 102,15,58,32,209,3 // pinsrb $0x3,%ecx,%xmm2 + .byte 102,15,56,49,210 // pmovzxbd %xmm2,%xmm2 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 72,139,64,24 // mov 0x18(%rax),%rax + .byte 68,15,89,195 // mulps %xmm3,%xmm8 + .byte 102,65,15,91,216 // cvtps2dq %xmm8,%xmm3 + .byte 102,72,15,58,22,217,1 // pextrq $0x1,%xmm3,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,72,15,126,219 // movq %xmm3,%rbx + .byte 65,137,217 // mov %ebx,%r9d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 102,66,15,58,32,28,8,0 // pinsrb $0x0,(%rax,%r9,1),%xmm3 + .byte 102,15,58,32,28,24,1 // pinsrb $0x1,(%rax,%rbx,1),%xmm3 + .byte 66,15,182,28,0 // movzbl (%rax,%r8,1),%ebx + .byte 102,15,58,32,219,2 // pinsrb $0x2,%ebx,%xmm3 + .byte 15,182,4,8 // movzbl (%rax,%rcx,1),%eax + .byte 102,15,58,32,216,3 // pinsrb $0x3,%eax,%xmm3 + .byte 102,15,56,49,219 // pmovzxbd %xmm3,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 65,15,89,217 // mulps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,94 // pop %r14 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_byte_tables_rgb_sse41 +.globl _sk_byte_tables_rgb_sse41 +_sk_byte_tables_rgb_sse41: + .byte 65,86 // push %r14 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 139,72,24 // mov 0x18(%rax),%ecx + .byte 255,201 // dec %ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 102,69,15,112,192,0 // pshufd $0x0,%xmm8,%xmm8 + .byte 69,15,91,192 // cvtdq2ps %xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 102,15,91,192 // cvtps2dq %xmm0,%xmm0 + .byte 102,72,15,58,22,193,1 // pextrq $0x1,%xmm0,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,73,15,126,193 // movq %xmm0,%r9 + .byte 69,137,202 // mov %r9d,%r10d + .byte 77,137,203 // mov %r9,%r11 + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 76,139,48 // mov (%rax),%r14 + .byte 76,139,72,8 // mov 0x8(%rax),%r9 + .byte 102,67,15,58,32,4,22,0 // pinsrb $0x0,(%r14,%r10,1),%xmm0 + .byte 102,67,15,58,32,4,30,1 // pinsrb $0x1,(%r14,%r11,1),%xmm0 + .byte 67,15,182,28,6 // movzbl (%r14,%r8,1),%ebx + .byte 102,15,58,32,195,2 // pinsrb $0x2,%ebx,%xmm0 + .byte 65,15,182,12,14 // movzbl (%r14,%rcx,1),%ecx + .byte 102,15,58,32,193,3 // pinsrb $0x3,%ecx,%xmm0 + .byte 102,15,56,49,192 // pmovzxbd %xmm0,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 185,129,128,128,59 // mov $0x3b808081,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 102,15,91,201 // cvtps2dq %xmm1,%xmm1 + .byte 102,72,15,58,22,201,1 // pextrq $0x1,%xmm1,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,72,15,126,203 // movq %xmm1,%rbx + .byte 65,137,218 // mov %ebx,%r10d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 102,67,15,58,32,12,17,0 // pinsrb $0x0,(%r9,%r10,1),%xmm1 + .byte 102,65,15,58,32,12,25,1 // pinsrb $0x1,(%r9,%rbx,1),%xmm1 + .byte 67,15,182,28,1 // movzbl (%r9,%r8,1),%ebx + .byte 102,15,58,32,203,2 // pinsrb $0x2,%ebx,%xmm1 + .byte 65,15,182,12,9 // movzbl (%r9,%rcx,1),%ecx + .byte 102,15,58,32,201,3 // pinsrb $0x3,%ecx,%xmm1 + .byte 102,15,56,49,201 // pmovzxbd %xmm1,%xmm1 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 72,139,64,16 // mov 0x10(%rax),%rax + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,15,91,210 // cvtps2dq %xmm2,%xmm2 + .byte 102,72,15,58,22,209,1 // pextrq $0x1,%xmm2,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,72,15,126,211 // movq %xmm2,%rbx + .byte 65,137,217 // mov %ebx,%r9d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 102,66,15,58,32,20,8,0 // pinsrb $0x0,(%rax,%r9,1),%xmm2 + .byte 102,15,58,32,20,24,1 // pinsrb $0x1,(%rax,%rbx,1),%xmm2 + .byte 66,15,182,28,0 // movzbl (%rax,%r8,1),%ebx + .byte 102,15,58,32,211,2 // pinsrb $0x2,%ebx,%xmm2 + .byte 15,182,4,8 // movzbl (%rax,%rcx,1),%eax + .byte 102,15,58,32,208,3 // pinsrb $0x3,%eax,%xmm2 + .byte 102,15,56,49,210 // pmovzxbd %xmm2,%xmm2 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,94 // pop %r14 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_a8_sse41 +.globl _sk_load_a8_sse41 +_sk_load_a8_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,15,56,49,4,56 // pmovzxbd (%rax,%rdi,1),%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 15,89,216 // mulps %xmm0,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,87,192 // xorps %xmm0,%xmm0 + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_a8_sse41 +.globl _sk_gather_a8_sse41 +_sk_gather_a8_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,56,64,209 // pmulld %xmm1,%xmm2 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,194 // paddd %xmm2,%xmm0 + .byte 102,72,15,58,22,192,1 // pextrq $0x1,%xmm0,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,67,15,58,32,4,17,0 // pinsrb $0x0,(%r9,%r10,1),%xmm0 + .byte 102,65,15,58,32,4,9,1 // pinsrb $0x1,(%r9,%rcx,1),%xmm0 + .byte 67,15,182,12,1 // movzbl (%r9,%r8,1),%ecx + .byte 102,15,58,32,193,2 // pinsrb $0x2,%ecx,%xmm0 + .byte 65,15,182,4,1 // movzbl (%r9,%rax,1),%eax + .byte 102,15,58,32,192,3 // pinsrb $0x3,%eax,%xmm0 + .byte 102,15,56,49,192 // pmovzxbd %xmm0,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 15,89,216 // mulps %xmm0,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,87,192 // xorps %xmm0,%xmm0 + .byte 102,15,239,201 // pxor %xmm1,%xmm1 + .byte 102,15,239,210 // pxor %xmm2,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_a8_sse41 +.globl _sk_store_a8_sse41 +_sk_store_a8_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,0,127,67 // mov $0x437f0000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,89,195 // mulps %xmm3,%xmm8 + .byte 102,69,15,91,192 // cvtps2dq %xmm8,%xmm8 + .byte 102,69,15,56,43,192 // packusdw %xmm8,%xmm8 + .byte 102,69,15,103,192 // packuswb %xmm8,%xmm8 + .byte 102,68,15,126,4,56 // movd %xmm8,(%rax,%rdi,1) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_g8_sse41 +.globl _sk_load_g8_sse41 +_sk_load_g8_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,15,56,49,4,56 // pmovzxbd (%rax,%rdi,1),%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,200 // movaps %xmm0,%xmm1 + .byte 15,40,208 // movaps %xmm0,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_g8_sse41 +.globl _sk_gather_g8_sse41 +_sk_gather_g8_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,56,64,209 // pmulld %xmm1,%xmm2 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,194 // paddd %xmm2,%xmm0 + .byte 102,72,15,58,22,192,1 // pextrq $0x1,%xmm0,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,67,15,58,32,4,17,0 // pinsrb $0x0,(%r9,%r10,1),%xmm0 + .byte 102,65,15,58,32,4,9,1 // pinsrb $0x1,(%r9,%rcx,1),%xmm0 + .byte 67,15,182,12,1 // movzbl (%r9,%r8,1),%ecx + .byte 102,15,58,32,193,2 // pinsrb $0x2,%ecx,%xmm0 + .byte 65,15,182,4,1 // movzbl (%r9,%rax,1),%eax + .byte 102,15,58,32,192,3 // pinsrb $0x3,%eax,%xmm0 + .byte 102,15,56,49,192 // pmovzxbd %xmm0,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,200 // movaps %xmm0,%xmm1 + .byte 15,40,208 // movaps %xmm0,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_i8_sse41 +.globl _sk_gather_i8_sse41 +_sk_gather_i8_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 73,137,192 // mov %rax,%r8 + .byte 77,133,192 // test %r8,%r8 + .byte 116,5 // je 1c27 <_sk_gather_i8_sse41+0xf> + .byte 76,137,192 // mov %r8,%rax + .byte 235,2 // jmp 1c29 <_sk_gather_i8_sse41+0x11> + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,16 // mov (%rax),%r10 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,56,64,209 // pmulld %xmm1,%xmm2 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,194 // paddd %xmm2,%xmm0 + .byte 102,72,15,58,22,192,1 // pextrq $0x1,%xmm0,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,203 // mov %ecx,%r11d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,67,15,58,32,4,26,0 // pinsrb $0x0,(%r10,%r11,1),%xmm0 + .byte 102,65,15,58,32,4,10,1 // pinsrb $0x1,(%r10,%rcx,1),%xmm0 + .byte 102,67,15,58,32,4,10,2 // pinsrb $0x2,(%r10,%r9,1),%xmm0 + .byte 102,65,15,58,32,4,2,3 // pinsrb $0x3,(%r10,%rax,1),%xmm0 + .byte 102,15,56,49,192 // pmovzxbd %xmm0,%xmm0 + .byte 102,73,15,58,22,193,1 // pextrq $0x1,%xmm0,%r9 + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 73,139,64,8 // mov 0x8(%r8),%rax + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,30 // shr $0x1e,%rcx + .byte 69,137,202 // mov %r9d,%r10d + .byte 73,193,233,30 // shr $0x1e,%r9 + .byte 102,66,15,110,28,128 // movd (%rax,%r8,4),%xmm3 + .byte 102,15,58,34,28,8,1 // pinsrd $0x1,(%rax,%rcx,1),%xmm3 + .byte 102,66,15,58,34,28,144,2 // pinsrd $0x2,(%rax,%r10,4),%xmm3 + .byte 102,66,15,58,34,28,8,3 // pinsrd $0x3,(%rax,%r9,1),%xmm3 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,15,111,203 // movdqa %xmm3,%xmm1 + .byte 102,15,114,209,8 // psrld $0x8,%xmm1 + .byte 102,15,219,200 // pand %xmm0,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,15,114,210,16 // psrld $0x10,%xmm2 + .byte 102,15,219,208 // pand %xmm0,%xmm2 + .byte 102,15,219,195 // pand %xmm3,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,15,114,211,24 // psrld $0x18,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_565_sse41 +.globl _sk_load_565_sse41 +_sk_load_565_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,15,56,51,20,120 // pmovzxwd (%rax,%rdi,2),%xmm2 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,15,219,194 // pand %xmm2,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 102,15,112,201,0 // pshufd $0x0,%xmm1,%xmm1 + .byte 102,15,219,202 // pand %xmm2,%xmm1 + .byte 15,91,217 // cvtdq2ps %xmm1,%xmm3 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 15,89,203 // mulps %xmm3,%xmm1 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,15,219,218 // pand %xmm2,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,89,211 // mulps %xmm3,%xmm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_565_sse41 +.globl _sk_gather_565_sse41 +_sk_gather_565_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,56,64,209 // pmulld %xmm1,%xmm2 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,194 // paddd %xmm2,%xmm0 + .byte 102,72,15,58,22,192,1 // pextrq $0x1,%xmm0,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,67,15,196,4,81,0 // pinsrw $0x0,(%r9,%r10,2),%xmm0 + .byte 102,65,15,196,4,73,1 // pinsrw $0x1,(%r9,%rcx,2),%xmm0 + .byte 67,15,183,12,65 // movzwl (%r9,%r8,2),%ecx + .byte 102,15,196,193,2 // pinsrw $0x2,%ecx,%xmm0 + .byte 65,15,183,4,65 // movzwl (%r9,%rax,2),%eax + .byte 102,15,196,192,3 // pinsrw $0x3,%eax,%xmm0 + .byte 102,15,56,51,208 // pmovzxwd %xmm0,%xmm2 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,15,219,194 // pand %xmm2,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 102,15,112,201,0 // pshufd $0x0,%xmm1,%xmm1 + .byte 102,15,219,202 // pand %xmm2,%xmm1 + .byte 15,91,217 // cvtdq2ps %xmm1,%xmm3 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 15,89,203 // mulps %xmm3,%xmm1 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,15,219,218 // pand %xmm2,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,89,211 // mulps %xmm3,%xmm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_565_sse41 +.globl _sk_store_565_sse41 +_sk_store_565_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,0,248,65 // mov $0x41f80000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,200 // mulps %xmm0,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 102,65,15,114,241,11 // pslld $0xb,%xmm9 + .byte 185,0,0,124,66 // mov $0x427c0000,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 102,69,15,91,210 // cvtps2dq %xmm10,%xmm10 + .byte 102,65,15,114,242,5 // pslld $0x5,%xmm10 + .byte 102,69,15,235,209 // por %xmm9,%xmm10 + .byte 68,15,89,194 // mulps %xmm2,%xmm8 + .byte 102,69,15,91,192 // cvtps2dq %xmm8,%xmm8 + .byte 102,69,15,86,194 // orpd %xmm10,%xmm8 + .byte 102,69,15,56,43,192 // packusdw %xmm8,%xmm8 + .byte 102,68,15,214,4,120 // movq %xmm8,(%rax,%rdi,2) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_4444_sse41 +.globl _sk_load_4444_sse41 +_sk_load_4444_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,68,15,56,51,12,120 // pmovzxwd (%rax,%rdi,2),%xmm9 + .byte 184,0,240,0,0 // mov $0xf000,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,65,15,219,193 // pand %xmm9,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,137,136,136,55 // mov $0x37888889,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,0,15,0,0 // mov $0xf00,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 102,15,112,201,0 // pshufd $0x0,%xmm1,%xmm1 + .byte 102,65,15,219,201 // pand %xmm9,%xmm1 + .byte 15,91,209 // cvtdq2ps %xmm1,%xmm2 + .byte 184,137,136,136,57 // mov $0x39888889,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 15,89,202 // mulps %xmm2,%xmm1 + .byte 184,240,0,0,0 // mov $0xf0,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,65,15,219,209 // pand %xmm9,%xmm2 + .byte 68,15,91,194 // cvtdq2ps %xmm2,%xmm8 + .byte 184,137,136,136,59 // mov $0x3b888889,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 184,15,0,0,0 // mov $0xf,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,65,15,219,217 // pand %xmm9,%xmm3 + .byte 68,15,91,195 // cvtdq2ps %xmm3,%xmm8 + .byte 184,137,136,136,61 // mov $0x3d888889,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_4444_sse41 +.globl _sk_gather_4444_sse41 +_sk_gather_4444_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,56,64,209 // pmulld %xmm1,%xmm2 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,194 // paddd %xmm2,%xmm0 + .byte 102,72,15,58,22,192,1 // pextrq $0x1,%xmm0,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,67,15,196,4,81,0 // pinsrw $0x0,(%r9,%r10,2),%xmm0 + .byte 102,65,15,196,4,73,1 // pinsrw $0x1,(%r9,%rcx,2),%xmm0 + .byte 67,15,183,12,65 // movzwl (%r9,%r8,2),%ecx + .byte 102,15,196,193,2 // pinsrw $0x2,%ecx,%xmm0 + .byte 65,15,183,4,65 // movzwl (%r9,%rax,2),%eax + .byte 102,15,196,192,3 // pinsrw $0x3,%eax,%xmm0 + .byte 102,68,15,56,51,200 // pmovzxwd %xmm0,%xmm9 + .byte 184,0,240,0,0 // mov $0xf000,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,65,15,219,193 // pand %xmm9,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,137,136,136,55 // mov $0x37888889,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,0,15,0,0 // mov $0xf00,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 102,15,112,201,0 // pshufd $0x0,%xmm1,%xmm1 + .byte 102,65,15,219,201 // pand %xmm9,%xmm1 + .byte 15,91,209 // cvtdq2ps %xmm1,%xmm2 + .byte 184,137,136,136,57 // mov $0x39888889,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 15,89,202 // mulps %xmm2,%xmm1 + .byte 184,240,0,0,0 // mov $0xf0,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,65,15,219,209 // pand %xmm9,%xmm2 + .byte 68,15,91,194 // cvtdq2ps %xmm2,%xmm8 + .byte 184,137,136,136,59 // mov $0x3b888889,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 184,15,0,0,0 // mov $0xf,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,65,15,219,217 // pand %xmm9,%xmm3 + .byte 68,15,91,195 // cvtdq2ps %xmm3,%xmm8 + .byte 184,137,136,136,61 // mov $0x3d888889,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_4444_sse41 +.globl _sk_store_4444_sse41 +_sk_store_4444_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,0,112,65 // mov $0x41700000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,200 // mulps %xmm0,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 102,65,15,114,241,12 // pslld $0xc,%xmm9 + .byte 69,15,40,208 // movaps %xmm8,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 102,69,15,91,210 // cvtps2dq %xmm10,%xmm10 + .byte 102,65,15,114,242,8 // pslld $0x8,%xmm10 + .byte 102,69,15,235,209 // por %xmm9,%xmm10 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 102,65,15,114,241,4 // pslld $0x4,%xmm9 + .byte 68,15,89,195 // mulps %xmm3,%xmm8 + .byte 102,69,15,91,192 // cvtps2dq %xmm8,%xmm8 + .byte 102,69,15,86,193 // orpd %xmm9,%xmm8 + .byte 102,69,15,86,194 // orpd %xmm10,%xmm8 + .byte 102,69,15,56,43,192 // packusdw %xmm8,%xmm8 + .byte 102,68,15,214,4,120 // movq %xmm8,(%rax,%rdi,2) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_8888_sse41 +.globl _sk_load_8888_sse41 +_sk_load_8888_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 243,15,111,28,184 // movdqu (%rax,%rdi,4),%xmm3 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,15,111,203 // movdqa %xmm3,%xmm1 + .byte 102,15,114,209,8 // psrld $0x8,%xmm1 + .byte 102,15,219,200 // pand %xmm0,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,15,114,210,16 // psrld $0x10,%xmm2 + .byte 102,15,219,208 // pand %xmm0,%xmm2 + .byte 102,15,219,195 // pand %xmm3,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,15,114,211,24 // psrld $0x18,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_8888_sse41 +.globl _sk_gather_8888_sse41 +_sk_gather_8888_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,56,64,209 // pmulld %xmm1,%xmm2 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,194 // paddd %xmm2,%xmm0 + .byte 102,72,15,126,192 // movq %xmm0,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,58,22,193,1 // pextrq $0x1,%xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,67,15,110,28,129 // movd (%r9,%r8,4),%xmm3 + .byte 102,65,15,58,34,28,129,1 // pinsrd $0x1,(%r9,%rax,4),%xmm3 + .byte 102,67,15,58,34,28,145,2 // pinsrd $0x2,(%r9,%r10,4),%xmm3 + .byte 102,65,15,58,34,28,137,3 // pinsrd $0x3,(%r9,%rcx,4),%xmm3 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,15,111,203 // movdqa %xmm3,%xmm1 + .byte 102,15,114,209,8 // psrld $0x8,%xmm1 + .byte 102,15,219,200 // pand %xmm0,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,15,114,210,16 // psrld $0x10,%xmm2 + .byte 102,15,219,208 // pand %xmm0,%xmm2 + .byte 102,15,219,195 // pand %xmm3,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,15,114,211,24 // psrld $0x18,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_8888_sse41 +.globl _sk_store_8888_sse41 +_sk_store_8888_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,0,127,67 // mov $0x437f0000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,200 // mulps %xmm0,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 69,15,40,208 // movaps %xmm8,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 102,69,15,91,210 // cvtps2dq %xmm10,%xmm10 + .byte 102,65,15,114,242,8 // pslld $0x8,%xmm10 + .byte 102,69,15,235,209 // por %xmm9,%xmm10 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 102,65,15,114,241,16 // pslld $0x10,%xmm9 + .byte 68,15,89,195 // mulps %xmm3,%xmm8 + .byte 102,69,15,91,192 // cvtps2dq %xmm8,%xmm8 + .byte 102,65,15,114,240,24 // pslld $0x18,%xmm8 + .byte 102,69,15,235,193 // por %xmm9,%xmm8 + .byte 102,69,15,235,194 // por %xmm10,%xmm8 + .byte 243,68,15,127,4,184 // movdqu %xmm8,(%rax,%rdi,4) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_f16_sse41 +.globl _sk_load_f16_sse41 +_sk_load_f16_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 243,15,111,4,248 // movdqu (%rax,%rdi,8),%xmm0 + .byte 243,15,111,76,248,16 // movdqu 0x10(%rax,%rdi,8),%xmm1 + .byte 102,68,15,111,192 // movdqa %xmm0,%xmm8 + .byte 102,68,15,97,193 // punpcklwd %xmm1,%xmm8 + .byte 102,15,105,193 // punpckhwd %xmm1,%xmm0 + .byte 102,65,15,111,200 // movdqa %xmm8,%xmm1 + .byte 102,15,97,200 // punpcklwd %xmm0,%xmm1 + .byte 102,68,15,105,192 // punpckhwd %xmm0,%xmm8 + .byte 184,0,4,0,4 // mov $0x4000400,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,216,0 // pshufd $0x0,%xmm0,%xmm3 + .byte 102,15,111,195 // movdqa %xmm3,%xmm0 + .byte 102,15,101,193 // pcmpgtw %xmm1,%xmm0 + .byte 102,15,223,193 // pandn %xmm1,%xmm0 + .byte 102,15,56,51,192 // pmovzxwd %xmm0,%xmm0 + .byte 102,15,114,240,13 // pslld $0xd,%xmm0 + .byte 184,0,0,128,119 // mov $0x77800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 102,68,15,112,202,0 // pshufd $0x0,%xmm2,%xmm9 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 102,15,112,201,78 // pshufd $0x4e,%xmm1,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,15,101,209 // pcmpgtw %xmm1,%xmm2 + .byte 102,15,223,209 // pandn %xmm1,%xmm2 + .byte 102,15,56,51,202 // pmovzxwd %xmm2,%xmm1 + .byte 102,15,114,241,13 // pslld $0xd,%xmm1 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,65,15,101,208 // pcmpgtw %xmm8,%xmm2 + .byte 102,65,15,223,208 // pandn %xmm8,%xmm2 + .byte 102,15,56,51,210 // pmovzxwd %xmm2,%xmm2 + .byte 102,15,114,242,13 // pslld $0xd,%xmm2 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 102,69,15,112,192,78 // pshufd $0x4e,%xmm8,%xmm8 + .byte 102,65,15,101,216 // pcmpgtw %xmm8,%xmm3 + .byte 102,65,15,223,216 // pandn %xmm8,%xmm3 + .byte 102,15,56,51,219 // pmovzxwd %xmm3,%xmm3 + .byte 102,15,114,243,13 // pslld $0xd,%xmm3 + .byte 65,15,89,217 // mulps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_f16_sse41 +.globl _sk_gather_f16_sse41 +_sk_gather_f16_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,56,64,209 // pmulld %xmm1,%xmm2 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,194 // paddd %xmm2,%xmm0 + .byte 102,72,15,126,192 // movq %xmm0,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,58,22,193,1 // pextrq $0x1,%xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 243,65,15,126,4,201 // movq (%r9,%rcx,8),%xmm0 + .byte 243,67,15,126,12,209 // movq (%r9,%r10,8),%xmm1 + .byte 102,15,108,200 // punpcklqdq %xmm0,%xmm1 + .byte 243,65,15,126,4,193 // movq (%r9,%rax,8),%xmm0 + .byte 243,67,15,126,20,193 // movq (%r9,%r8,8),%xmm2 + .byte 102,15,108,208 // punpcklqdq %xmm0,%xmm2 + .byte 102,68,15,111,194 // movdqa %xmm2,%xmm8 + .byte 102,68,15,97,193 // punpcklwd %xmm1,%xmm8 + .byte 102,15,105,209 // punpckhwd %xmm1,%xmm2 + .byte 102,65,15,111,200 // movdqa %xmm8,%xmm1 + .byte 102,15,97,202 // punpcklwd %xmm2,%xmm1 + .byte 102,68,15,105,194 // punpckhwd %xmm2,%xmm8 + .byte 184,0,4,0,4 // mov $0x4000400,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,216,0 // pshufd $0x0,%xmm0,%xmm3 + .byte 102,15,111,195 // movdqa %xmm3,%xmm0 + .byte 102,15,101,193 // pcmpgtw %xmm1,%xmm0 + .byte 102,15,223,193 // pandn %xmm1,%xmm0 + .byte 102,15,56,51,192 // pmovzxwd %xmm0,%xmm0 + .byte 102,15,114,240,13 // pslld $0xd,%xmm0 + .byte 184,0,0,128,119 // mov $0x77800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 102,68,15,112,202,0 // pshufd $0x0,%xmm2,%xmm9 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 102,15,112,201,78 // pshufd $0x4e,%xmm1,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,15,101,209 // pcmpgtw %xmm1,%xmm2 + .byte 102,15,223,209 // pandn %xmm1,%xmm2 + .byte 102,15,56,51,202 // pmovzxwd %xmm2,%xmm1 + .byte 102,15,114,241,13 // pslld $0xd,%xmm1 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,65,15,101,208 // pcmpgtw %xmm8,%xmm2 + .byte 102,65,15,223,208 // pandn %xmm8,%xmm2 + .byte 102,15,56,51,210 // pmovzxwd %xmm2,%xmm2 + .byte 102,15,114,242,13 // pslld $0xd,%xmm2 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 102,69,15,112,192,78 // pshufd $0x4e,%xmm8,%xmm8 + .byte 102,65,15,101,216 // pcmpgtw %xmm8,%xmm3 + .byte 102,65,15,223,216 // pandn %xmm8,%xmm3 + .byte 102,15,56,51,219 // pmovzxwd %xmm3,%xmm3 + .byte 102,15,114,243,13 // pslld $0xd,%xmm3 + .byte 65,15,89,217 // mulps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_f16_sse41 +.globl _sk_store_f16_sse41 +_sk_store_f16_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,0,128,7 // mov $0x7800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 102,69,15,112,200,0 // pshufd $0x0,%xmm8,%xmm9 + .byte 102,69,15,111,193 // movdqa %xmm9,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 102,65,15,114,208,13 // psrld $0xd,%xmm8 + .byte 102,69,15,56,43,192 // packusdw %xmm8,%xmm8 + .byte 102,69,15,111,209 // movdqa %xmm9,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 102,65,15,114,210,13 // psrld $0xd,%xmm10 + .byte 102,69,15,56,43,210 // packusdw %xmm10,%xmm10 + .byte 102,69,15,111,217 // movdqa %xmm9,%xmm11 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 102,65,15,114,211,13 // psrld $0xd,%xmm11 + .byte 102,69,15,56,43,219 // packusdw %xmm11,%xmm11 + .byte 68,15,89,203 // mulps %xmm3,%xmm9 + .byte 102,65,15,114,209,13 // psrld $0xd,%xmm9 + .byte 102,69,15,56,43,201 // packusdw %xmm9,%xmm9 + .byte 102,69,15,97,194 // punpcklwd %xmm10,%xmm8 + .byte 102,69,15,97,217 // punpcklwd %xmm9,%xmm11 + .byte 102,69,15,111,200 // movdqa %xmm8,%xmm9 + .byte 102,69,15,98,203 // punpckldq %xmm11,%xmm9 + .byte 243,68,15,127,12,248 // movdqu %xmm9,(%rax,%rdi,8) + .byte 102,69,15,106,195 // punpckhdq %xmm11,%xmm8 + .byte 243,68,15,127,68,248,16 // movdqu %xmm8,0x10(%rax,%rdi,8) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_u16_be_sse41 +.globl _sk_load_u16_be_sse41 +_sk_load_u16_be_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 243,15,111,4,248 // movdqu (%rax,%rdi,8),%xmm0 + .byte 243,15,111,76,248,16 // movdqu 0x10(%rax,%rdi,8),%xmm1 + .byte 102,15,111,208 // movdqa %xmm0,%xmm2 + .byte 102,15,97,209 // punpcklwd %xmm1,%xmm2 + .byte 102,15,105,193 // punpckhwd %xmm1,%xmm0 + .byte 102,15,111,202 // movdqa %xmm2,%xmm1 + .byte 102,15,97,200 // punpcklwd %xmm0,%xmm1 + .byte 102,15,105,208 // punpckhwd %xmm0,%xmm2 + .byte 184,128,0,128,55 // mov $0x37800080,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 102,15,111,193 // movdqa %xmm1,%xmm0 + .byte 102,15,113,240,8 // psllw $0x8,%xmm0 + .byte 102,15,112,217,78 // pshufd $0x4e,%xmm1,%xmm3 + .byte 102,15,113,209,8 // psrlw $0x8,%xmm1 + .byte 102,15,235,200 // por %xmm0,%xmm1 + .byte 102,15,56,51,193 // pmovzxwd %xmm1,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 102,15,111,203 // movdqa %xmm3,%xmm1 + .byte 102,15,113,241,8 // psllw $0x8,%xmm1 + .byte 102,15,113,211,8 // psrlw $0x8,%xmm3 + .byte 102,15,235,217 // por %xmm1,%xmm3 + .byte 102,15,56,51,203 // pmovzxwd %xmm3,%xmm1 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 102,68,15,111,202 // movdqa %xmm2,%xmm9 + .byte 102,65,15,113,241,8 // psllw $0x8,%xmm9 + .byte 102,15,112,218,78 // pshufd $0x4e,%xmm2,%xmm3 + .byte 102,15,113,210,8 // psrlw $0x8,%xmm2 + .byte 102,65,15,235,209 // por %xmm9,%xmm2 + .byte 102,15,56,51,210 // pmovzxwd %xmm2,%xmm2 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,68,15,111,203 // movdqa %xmm3,%xmm9 + .byte 102,65,15,113,241,8 // psllw $0x8,%xmm9 + .byte 102,15,113,211,8 // psrlw $0x8,%xmm3 + .byte 102,65,15,235,217 // por %xmm9,%xmm3 + .byte 102,15,56,51,219 // pmovzxwd %xmm3,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_u16_be_sse41 +.globl _sk_store_u16_be_sse41 +_sk_store_u16_be_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,255,127,71 // mov $0x477fff00,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 102,69,15,91,192 // cvtps2dq %xmm8,%xmm8 + .byte 102,69,15,56,43,192 // packusdw %xmm8,%xmm8 + .byte 102,69,15,111,208 // movdqa %xmm8,%xmm10 + .byte 102,65,15,113,242,8 // psllw $0x8,%xmm10 + .byte 102,65,15,113,208,8 // psrlw $0x8,%xmm8 + .byte 102,69,15,235,194 // por %xmm10,%xmm8 + .byte 69,15,40,209 // movaps %xmm9,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 102,69,15,91,210 // cvtps2dq %xmm10,%xmm10 + .byte 102,69,15,56,43,210 // packusdw %xmm10,%xmm10 + .byte 102,69,15,111,218 // movdqa %xmm10,%xmm11 + .byte 102,65,15,113,243,8 // psllw $0x8,%xmm11 + .byte 102,65,15,113,210,8 // psrlw $0x8,%xmm10 + .byte 102,69,15,235,211 // por %xmm11,%xmm10 + .byte 69,15,40,217 // movaps %xmm9,%xmm11 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 102,69,15,91,219 // cvtps2dq %xmm11,%xmm11 + .byte 102,69,15,56,43,219 // packusdw %xmm11,%xmm11 + .byte 102,69,15,111,227 // movdqa %xmm11,%xmm12 + .byte 102,65,15,113,244,8 // psllw $0x8,%xmm12 + .byte 102,65,15,113,211,8 // psrlw $0x8,%xmm11 + .byte 102,69,15,235,220 // por %xmm12,%xmm11 + .byte 68,15,89,203 // mulps %xmm3,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 102,69,15,56,43,201 // packusdw %xmm9,%xmm9 + .byte 102,69,15,111,225 // movdqa %xmm9,%xmm12 + .byte 102,65,15,113,244,8 // psllw $0x8,%xmm12 + .byte 102,65,15,113,209,8 // psrlw $0x8,%xmm9 + .byte 102,69,15,235,204 // por %xmm12,%xmm9 + .byte 102,69,15,97,194 // punpcklwd %xmm10,%xmm8 + .byte 102,69,15,97,217 // punpcklwd %xmm9,%xmm11 + .byte 102,69,15,111,200 // movdqa %xmm8,%xmm9 + .byte 102,69,15,98,203 // punpckldq %xmm11,%xmm9 + .byte 243,68,15,127,12,248 // movdqu %xmm9,(%rax,%rdi,8) + .byte 102,69,15,106,195 // punpckhdq %xmm11,%xmm8 + .byte 243,68,15,127,68,248,16 // movdqu %xmm8,0x10(%rax,%rdi,8) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_f32_sse41 +.globl _sk_load_f32_sse41 +_sk_load_f32_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,137,249 // mov %rdi,%rcx + .byte 72,193,225,4 // shl $0x4,%rcx + .byte 68,15,16,4,8 // movups (%rax,%rcx,1),%xmm8 + .byte 15,16,68,8,16 // movups 0x10(%rax,%rcx,1),%xmm0 + .byte 15,16,92,8,32 // movups 0x20(%rax,%rcx,1),%xmm3 + .byte 68,15,16,76,8,48 // movups 0x30(%rax,%rcx,1),%xmm9 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 15,20,208 // unpcklps %xmm0,%xmm2 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 65,15,20,201 // unpcklps %xmm9,%xmm1 + .byte 68,15,21,192 // unpckhps %xmm0,%xmm8 + .byte 65,15,21,217 // unpckhps %xmm9,%xmm3 + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 102,15,20,193 // unpcklpd %xmm1,%xmm0 + .byte 15,18,202 // movhlps %xmm2,%xmm1 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 102,15,20,211 // unpcklpd %xmm3,%xmm2 + .byte 65,15,18,216 // movhlps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_f32_sse41 +.globl _sk_store_f32_sse41 +_sk_store_f32_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,137,249 // mov %rdi,%rcx + .byte 72,193,225,4 // shl $0x4,%rcx + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 68,15,20,201 // unpcklps %xmm1,%xmm9 + .byte 68,15,40,210 // movaps %xmm2,%xmm10 + .byte 68,15,40,218 // movaps %xmm2,%xmm11 + .byte 68,15,20,219 // unpcklps %xmm3,%xmm11 + .byte 68,15,21,193 // unpckhps %xmm1,%xmm8 + .byte 68,15,21,211 // unpckhps %xmm3,%xmm10 + .byte 69,15,40,225 // movaps %xmm9,%xmm12 + .byte 102,69,15,20,227 // unpcklpd %xmm11,%xmm12 + .byte 69,15,18,217 // movhlps %xmm9,%xmm11 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 102,69,15,20,202 // unpcklpd %xmm10,%xmm9 + .byte 69,15,18,208 // movhlps %xmm8,%xmm10 + .byte 102,68,15,17,36,8 // movupd %xmm12,(%rax,%rcx,1) + .byte 68,15,17,92,8,16 // movups %xmm11,0x10(%rax,%rcx,1) + .byte 102,68,15,17,76,8,32 // movupd %xmm9,0x20(%rax,%rcx,1) + .byte 68,15,17,84,8,48 // movups %xmm10,0x30(%rax,%rcx,1) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_x_sse41 +.globl _sk_clamp_x_sse41 +_sk_clamp_x_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 68,15,95,192 // maxps %xmm0,%xmm8 + .byte 243,68,15,16,8 // movss (%rax),%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 102,15,118,192 // pcmpeqd %xmm0,%xmm0 + .byte 102,65,15,254,193 // paddd %xmm9,%xmm0 + .byte 68,15,93,192 // minps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_y_sse41 +.globl _sk_clamp_y_sse41 +_sk_clamp_y_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 68,15,95,193 // maxps %xmm1,%xmm8 + .byte 243,68,15,16,8 // movss (%rax),%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 102,15,118,201 // pcmpeqd %xmm1,%xmm1 + .byte 102,65,15,254,201 // paddd %xmm9,%xmm1 + .byte 68,15,93,193 // minps %xmm1,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_repeat_x_sse41 +.globl _sk_repeat_x_sse41 +_sk_repeat_x_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,0 // movss (%rax),%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 69,15,94,200 // divps %xmm8,%xmm9 + .byte 102,69,15,58,8,201,1 // roundps $0x1,%xmm9,%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 65,15,92,193 // subps %xmm9,%xmm0 + .byte 102,69,15,118,201 // pcmpeqd %xmm9,%xmm9 + .byte 102,69,15,254,200 // paddd %xmm8,%xmm9 + .byte 65,15,93,193 // minps %xmm9,%xmm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_repeat_y_sse41 +.globl _sk_repeat_y_sse41 +_sk_repeat_y_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,0 // movss (%rax),%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 69,15,94,200 // divps %xmm8,%xmm9 + .byte 102,69,15,58,8,201,1 // roundps $0x1,%xmm9,%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 65,15,92,201 // subps %xmm9,%xmm1 + .byte 102,69,15,118,201 // pcmpeqd %xmm9,%xmm9 + .byte 102,69,15,254,200 // paddd %xmm8,%xmm9 + .byte 65,15,93,201 // minps %xmm9,%xmm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_mirror_x_sse41 +.globl _sk_mirror_x_sse41 +_sk_mirror_x_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,0 // movss (%rax),%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 65,15,92,193 // subps %xmm9,%xmm0 + .byte 243,69,15,88,192 // addss %xmm8,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,40,208 // movaps %xmm0,%xmm10 + .byte 69,15,94,208 // divps %xmm8,%xmm10 + .byte 102,69,15,58,8,210,1 // roundps $0x1,%xmm10,%xmm10 + .byte 69,15,89,208 // mulps %xmm8,%xmm10 + .byte 65,15,92,194 // subps %xmm10,%xmm0 + .byte 65,15,92,193 // subps %xmm9,%xmm0 + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 68,15,92,192 // subps %xmm0,%xmm8 + .byte 65,15,84,192 // andps %xmm8,%xmm0 + .byte 102,69,15,118,192 // pcmpeqd %xmm8,%xmm8 + .byte 102,69,15,254,193 // paddd %xmm9,%xmm8 + .byte 65,15,93,192 // minps %xmm8,%xmm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_mirror_y_sse41 +.globl _sk_mirror_y_sse41 +_sk_mirror_y_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,0 // movss (%rax),%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 65,15,92,201 // subps %xmm9,%xmm1 + .byte 243,69,15,88,192 // addss %xmm8,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,40,209 // movaps %xmm1,%xmm10 + .byte 69,15,94,208 // divps %xmm8,%xmm10 + .byte 102,69,15,58,8,210,1 // roundps $0x1,%xmm10,%xmm10 + .byte 69,15,89,208 // mulps %xmm8,%xmm10 + .byte 65,15,92,202 // subps %xmm10,%xmm1 + .byte 65,15,92,201 // subps %xmm9,%xmm1 + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 68,15,92,193 // subps %xmm1,%xmm8 + .byte 65,15,84,200 // andps %xmm8,%xmm1 + .byte 102,69,15,118,192 // pcmpeqd %xmm8,%xmm8 + .byte 102,69,15,254,193 // paddd %xmm9,%xmm8 + .byte 65,15,93,200 // minps %xmm8,%xmm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_luminance_to_alpha_sse41 +.globl _sk_luminance_to_alpha_sse41 +_sk_luminance_to_alpha_sse41: + .byte 184,208,179,89,62 // mov $0x3e59b3d0,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 15,89,216 // mulps %xmm0,%xmm3 + .byte 184,89,23,55,63 // mov $0x3f371759,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 15,88,195 // addps %xmm3,%xmm0 + .byte 184,152,221,147,61 // mov $0x3d93dd98,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 15,89,218 // mulps %xmm2,%xmm3 + .byte 15,88,216 // addps %xmm0,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,87,192 // xorps %xmm0,%xmm0 + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_2x3_sse41 +.globl _sk_matrix_2x3_sse41 +_sk_matrix_2x3_sse41: + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 243,68,15,16,80,8 // movss 0x8(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,16 // movss 0x10(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,88,194 // addps %xmm10,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,68,15,16,80,12 // movss 0xc(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,20 // movss 0x14(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,88,202 // addps %xmm10,%xmm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_3x4_sse41 +.globl _sk_matrix_3x4_sse41 +_sk_matrix_3x4_sse41: + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 243,68,15,16,80,12 // movss 0xc(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,24 // movss 0x18(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,36 // movss 0x24(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,88,194 // addps %xmm10,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,68,15,16,80,16 // movss 0x10(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,28 // movss 0x1c(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,40 // movss 0x28(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,88,202 // addps %xmm10,%xmm1 + .byte 243,68,15,16,80,8 // movss 0x8(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,20 // movss 0x14(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,32 // movss 0x20(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,44 // movss 0x2c(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 68,15,89,226 // mulps %xmm2,%xmm12 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 69,15,89,217 // mulps %xmm9,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,208 // mulps %xmm8,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_4x5_sse41 +.globl _sk_matrix_4x5_sse41 +_sk_matrix_4x5_sse41: + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 243,68,15,16,80,16 // movss 0x10(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,32 // movss 0x20(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,48 // movss 0x30(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,64 // movss 0x40(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 68,15,89,227 // mulps %xmm3,%xmm12 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,88,194 // addps %xmm10,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,68,15,16,80,20 // movss 0x14(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,36 // movss 0x24(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,52 // movss 0x34(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,68 // movss 0x44(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 68,15,89,227 // mulps %xmm3,%xmm12 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,88,202 // addps %xmm10,%xmm1 + .byte 243,68,15,16,80,8 // movss 0x8(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,24 // movss 0x18(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,40 // movss 0x28(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,56 // movss 0x38(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 243,68,15,16,112,72 // movss 0x48(%rax),%xmm14 + .byte 69,15,198,246,0 // shufps $0x0,%xmm14,%xmm14 + .byte 68,15,89,235 // mulps %xmm3,%xmm13 + .byte 69,15,88,238 // addps %xmm14,%xmm13 + .byte 68,15,89,226 // mulps %xmm2,%xmm12 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 69,15,89,217 // mulps %xmm9,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,208 // mulps %xmm8,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 243,68,15,16,88,12 // movss 0xc(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,28 // movss 0x1c(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,44 // movss 0x2c(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 243,68,15,16,112,60 // movss 0x3c(%rax),%xmm14 + .byte 69,15,198,246,0 // shufps $0x0,%xmm14,%xmm14 + .byte 243,68,15,16,120,76 // movss 0x4c(%rax),%xmm15 + .byte 69,15,198,255,0 // shufps $0x0,%xmm15,%xmm15 + .byte 68,15,89,243 // mulps %xmm3,%xmm14 + .byte 69,15,88,247 // addps %xmm15,%xmm14 + .byte 68,15,89,234 // mulps %xmm2,%xmm13 + .byte 69,15,88,238 // addps %xmm14,%xmm13 + .byte 69,15,89,225 // mulps %xmm9,%xmm12 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 69,15,89,216 // mulps %xmm8,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 65,15,40,219 // movaps %xmm11,%xmm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_perspective_sse41 +.globl _sk_matrix_perspective_sse41 +_sk_matrix_perspective_sse41: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,68,15,16,72,4 // movss 0x4(%rax),%xmm9 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 243,68,15,16,80,8 // movss 0x8(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 68,15,89,201 // mulps %xmm1,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,88,193 // addps %xmm9,%xmm0 + .byte 243,68,15,16,72,12 // movss 0xc(%rax),%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 243,68,15,16,80,16 // movss 0x10(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,20 // movss 0x14(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 243,68,15,16,80,24 // movss 0x18(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,28 // movss 0x1c(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,32 // movss 0x20(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 68,15,89,217 // mulps %xmm1,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,208 // mulps %xmm8,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,83,202 // rcpps %xmm10,%xmm1 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 68,15,89,201 // mulps %xmm1,%xmm9 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,201 // movaps %xmm9,%xmm1 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_linear_gradient_sse41 +.globl _sk_linear_gradient_sse41 +_sk_linear_gradient_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,80,16 // movss 0x10(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,20 // movss 0x14(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,24 // movss 0x18(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,28 // movss 0x1c(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 72,139,8 // mov (%rax),%rcx + .byte 72,133,201 // test %rcx,%rcx + .byte 15,132,254,0,0,0 // je 2d95 <_sk_linear_gradient_sse41+0x138> + .byte 15,41,100,36,168 // movaps %xmm4,-0x58(%rsp) + .byte 15,41,108,36,184 // movaps %xmm5,-0x48(%rsp) + .byte 15,41,116,36,200 // movaps %xmm6,-0x38(%rsp) + .byte 15,41,124,36,216 // movaps %xmm7,-0x28(%rsp) + .byte 72,139,64,8 // mov 0x8(%rax),%rax + .byte 72,131,192,32 // add $0x20,%rax + .byte 69,15,87,201 // xorps %xmm9,%xmm9 + .byte 15,87,219 // xorps %xmm3,%xmm3 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 15,40,233 // movaps %xmm1,%xmm5 + .byte 15,40,242 // movaps %xmm2,%xmm6 + .byte 15,40,251 // movaps %xmm3,%xmm7 + .byte 69,15,40,194 // movaps %xmm10,%xmm8 + .byte 69,15,40,243 // movaps %xmm11,%xmm14 + .byte 69,15,40,252 // movaps %xmm12,%xmm15 + .byte 68,15,41,108,36,232 // movaps %xmm13,-0x18(%rsp) + .byte 65,15,40,201 // movaps %xmm9,%xmm1 + .byte 243,15,16,80,224 // movss -0x20(%rax),%xmm2 + .byte 243,68,15,16,72,228 // movss -0x1c(%rax),%xmm9 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,40,224 // movaps %xmm0,%xmm4 + .byte 15,194,194,1 // cmpltps %xmm2,%xmm0 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 102,68,15,56,20,201 // blendvps %xmm0,%xmm1,%xmm9 + .byte 243,15,16,72,232 // movss -0x18(%rax),%xmm1 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 102,15,56,20,205 // blendvps %xmm0,%xmm5,%xmm1 + .byte 243,15,16,80,236 // movss -0x14(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 102,15,56,20,214 // blendvps %xmm0,%xmm6,%xmm2 + .byte 243,15,16,88,240 // movss -0x10(%rax),%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 102,15,56,20,223 // blendvps %xmm0,%xmm7,%xmm3 + .byte 243,68,15,16,80,244 // movss -0xc(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 102,69,15,56,20,208 // blendvps %xmm0,%xmm8,%xmm10 + .byte 243,68,15,16,88,248 // movss -0x8(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 102,69,15,56,20,222 // blendvps %xmm0,%xmm14,%xmm11 + .byte 243,68,15,16,96,252 // movss -0x4(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 102,69,15,56,20,231 // blendvps %xmm0,%xmm15,%xmm12 + .byte 243,68,15,16,40 // movss (%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 102,68,15,56,20,108,36,232 // blendvps %xmm0,-0x18(%rsp),%xmm13 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 72,131,192,36 // add $0x24,%rax + .byte 72,255,201 // dec %rcx + .byte 15,133,65,255,255,255 // jne 2cc0 <_sk_linear_gradient_sse41+0x63> + .byte 15,40,124,36,216 // movaps -0x28(%rsp),%xmm7 + .byte 15,40,116,36,200 // movaps -0x38(%rsp),%xmm6 + .byte 15,40,108,36,184 // movaps -0x48(%rsp),%xmm5 + .byte 15,40,100,36,168 // movaps -0x58(%rsp),%xmm4 + .byte 235,13 // jmp 2da2 <_sk_linear_gradient_sse41+0x145> + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 15,87,219 // xorps %xmm3,%xmm3 + .byte 69,15,87,201 // xorps %xmm9,%xmm9 + .byte 68,15,89,200 // mulps %xmm0,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 15,89,200 // mulps %xmm0,%xmm1 + .byte 65,15,88,203 // addps %xmm11,%xmm1 + .byte 15,89,208 // mulps %xmm0,%xmm2 + .byte 65,15,88,212 // addps %xmm12,%xmm2 + .byte 15,89,216 // mulps %xmm0,%xmm3 + .byte 65,15,88,221 // addps %xmm13,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_linear_gradient_2stops_sse41 +.globl _sk_linear_gradient_2stops_sse41 +_sk_linear_gradient_2stops_sse41: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 243,15,16,80,16 // movss 0x10(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,88,194 // addps %xmm2,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,15,16,80,20 // movss 0x14(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,88,202 // addps %xmm2,%xmm1 + .byte 243,15,16,80,8 // movss 0x8(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 243,15,16,88,24 // movss 0x18(%rax),%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 15,88,211 // addps %xmm3,%xmm2 + .byte 243,15,16,88,12 // movss 0xc(%rax),%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 243,68,15,16,72,28 // movss 0x1c(%rax),%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 65,15,88,217 // addps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_save_xy_sse41 +.globl _sk_save_xy_sse41 +_sk_save_xy_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,88,200 // addps %xmm0,%xmm9 + .byte 102,69,15,58,8,209,1 // roundps $0x1,%xmm9,%xmm10 + .byte 69,15,92,202 // subps %xmm10,%xmm9 + .byte 68,15,88,193 // addps %xmm1,%xmm8 + .byte 102,69,15,58,8,208,1 // roundps $0x1,%xmm8,%xmm10 + .byte 69,15,92,194 // subps %xmm10,%xmm8 + .byte 15,17,0 // movups %xmm0,(%rax) + .byte 15,17,72,32 // movups %xmm1,0x20(%rax) + .byte 68,15,17,72,64 // movups %xmm9,0x40(%rax) + .byte 68,15,17,64,96 // movups %xmm8,0x60(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_accumulate_sse41 +.globl _sk_accumulate_sse41 +_sk_accumulate_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 68,15,16,128,128,0,0,0 // movups 0x80(%rax),%xmm8 + .byte 68,15,16,136,160,0,0,0 // movups 0xa0(%rax),%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 65,15,88,224 // addps %xmm8,%xmm4 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 68,15,89,193 // mulps %xmm1,%xmm8 + .byte 65,15,88,232 // addps %xmm8,%xmm5 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 68,15,89,194 // mulps %xmm2,%xmm8 + .byte 65,15,88,240 // addps %xmm8,%xmm6 + .byte 68,15,89,203 // mulps %xmm3,%xmm9 + .byte 65,15,88,249 // addps %xmm9,%xmm7 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_nx_sse41 +.globl _sk_bilinear_nx_sse41 +_sk_bilinear_nx_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,191 // mov $0xbf000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 68,15,17,128,128,0,0,0 // movups %xmm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_px_sse41 +.globl _sk_bilinear_px_sse41 +_sk_bilinear_px_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 68,15,17,136,128,0,0,0 // movups %xmm9,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_ny_sse41 +.globl _sk_bilinear_ny_sse41 +_sk_bilinear_ny_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,191 // mov $0xbf000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 68,15,17,128,160,0,0,0 // movups %xmm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_py_sse41 +.globl _sk_bilinear_py_sse41 +_sk_bilinear_py_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 68,15,17,136,160,0,0,0 // movups %xmm9,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n3x_sse41 +.globl _sk_bicubic_n3x_sse41 +_sk_bicubic_n3x_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,192,191 // mov $0xbfc00000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 185,114,28,199,62 // mov $0x3ec71c72,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 185,171,170,170,190 // mov $0xbeaaaaab,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,89,192 // mulps %xmm8,%xmm8 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 68,15,17,136,128,0,0,0 // movups %xmm9,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n1x_sse41 +.globl _sk_bicubic_n1x_sse41 +_sk_bicubic_n1x_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,191 // mov $0xbf000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 185,85,85,149,191 // mov $0xbf955555,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 185,57,142,99,61 // mov $0x3d638e39,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 68,15,17,136,128,0,0,0 // movups %xmm9,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p1x_sse41 +.globl _sk_bicubic_p1x_sse41 +_sk_bicubic_p1x_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 185,85,85,149,191 // mov $0xbf955555,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,217 // movd %ecx,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,208 // addps %xmm8,%xmm10 + .byte 185,57,142,99,61 // mov $0x3d638e39,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,208 // addps %xmm8,%xmm10 + .byte 68,15,17,144,128,0,0,0 // movups %xmm10,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p3x_sse41 +.globl _sk_bicubic_p3x_sse41 +_sk_bicubic_p3x_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 185,114,28,199,62 // mov $0x3ec71c72,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,89,193 // mulps %xmm9,%xmm8 + .byte 69,15,89,201 // mulps %xmm9,%xmm9 + .byte 185,171,170,170,190 // mov $0xbeaaaaab,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,88,194 // addps %xmm10,%xmm8 + .byte 69,15,89,193 // mulps %xmm9,%xmm8 + .byte 68,15,17,128,128,0,0,0 // movups %xmm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n3y_sse41 +.globl _sk_bicubic_n3y_sse41 +_sk_bicubic_n3y_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,192,191 // mov $0xbfc00000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 185,114,28,199,62 // mov $0x3ec71c72,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 185,171,170,170,190 // mov $0xbeaaaaab,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,89,192 // mulps %xmm8,%xmm8 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 68,15,17,136,160,0,0,0 // movups %xmm9,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n1y_sse41 +.globl _sk_bicubic_n1y_sse41 +_sk_bicubic_n1y_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,191 // mov $0xbf000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 185,85,85,149,191 // mov $0xbf955555,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 185,57,142,99,61 // mov $0x3d638e39,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 68,15,17,136,160,0,0,0 // movups %xmm9,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p1y_sse41 +.globl _sk_bicubic_p1y_sse41 +_sk_bicubic_p1y_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 185,85,85,149,191 // mov $0xbf955555,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,217 // movd %ecx,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,208 // addps %xmm8,%xmm10 + .byte 185,57,142,99,61 // mov $0x3d638e39,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,208 // addps %xmm8,%xmm10 + .byte 68,15,17,144,160,0,0,0 // movups %xmm10,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p3y_sse41 +.globl _sk_bicubic_p3y_sse41 +_sk_bicubic_p3y_sse41: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 185,114,28,199,62 // mov $0x3ec71c72,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,89,193 // mulps %xmm9,%xmm8 + .byte 69,15,89,201 // mulps %xmm9,%xmm9 + .byte 185,171,170,170,190 // mov $0xbeaaaaab,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,88,194 // addps %xmm10,%xmm8 + .byte 69,15,89,193 // mulps %xmm9,%xmm8 + .byte 68,15,17,128,160,0,0,0 // movups %xmm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_start_pipeline_sse2 +.globl _sk_start_pipeline_sse2 +_sk_start_pipeline_sse2: + .byte 65,87 // push %r15 + .byte 65,86 // push %r14 + .byte 65,85 // push %r13 + .byte 65,84 // push %r12 + .byte 83 // push %rbx + .byte 73,137,207 // mov %rcx,%r15 + .byte 73,137,214 // mov %rdx,%r14 + .byte 72,137,251 // mov %rdi,%rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 73,137,196 // mov %rax,%r12 + .byte 73,137,245 // mov %rsi,%r13 + .byte 72,141,67,4 // lea 0x4(%rbx),%rax + .byte 76,57,248 // cmp %r15,%rax + .byte 118,5 // jbe 28 <_sk_start_pipeline_sse2+0x28> + .byte 72,137,216 // mov %rbx,%rax + .byte 235,52 // jmp 5c <_sk_start_pipeline_sse2+0x5c> + .byte 15,87,192 // xorps %xmm0,%xmm0 + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 15,87,219 // xorps %xmm3,%xmm3 + .byte 15,87,228 // xorps %xmm4,%xmm4 + .byte 15,87,237 // xorps %xmm5,%xmm5 + .byte 15,87,246 // xorps %xmm6,%xmm6 + .byte 15,87,255 // xorps %xmm7,%xmm7 + .byte 72,137,223 // mov %rbx,%rdi + .byte 76,137,238 // mov %r13,%rsi + .byte 76,137,242 // mov %r14,%rdx + .byte 65,255,212 // callq *%r12 + .byte 72,141,67,4 // lea 0x4(%rbx),%rax + .byte 72,131,195,8 // add $0x8,%rbx + .byte 76,57,251 // cmp %r15,%rbx + .byte 72,137,195 // mov %rax,%rbx + .byte 118,204 // jbe 28 <_sk_start_pipeline_sse2+0x28> + .byte 91 // pop %rbx + .byte 65,92 // pop %r12 + .byte 65,93 // pop %r13 + .byte 65,94 // pop %r14 + .byte 65,95 // pop %r15 + .byte 195 // retq + +HIDDEN _sk_just_return_sse2 +.globl _sk_just_return_sse2 +_sk_just_return_sse2: + .byte 195 // retq + +HIDDEN _sk_seed_shader_sse2 +.globl _sk_seed_shader_sse2 +_sk_seed_shader_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 102,15,110,199 // movd %edi,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,15,110,209 // movd %ecx,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,88,202 // addps %xmm2,%xmm1 + .byte 15,16,2 // movups (%rdx),%xmm0 + .byte 15,88,193 // addps %xmm1,%xmm0 + .byte 102,15,110,8 // movd (%rax),%xmm1 + .byte 102,15,112,201,0 // pshufd $0x0,%xmm1,%xmm1 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 15,88,202 // addps %xmm2,%xmm1 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,87,219 // xorps %xmm3,%xmm3 + .byte 15,87,228 // xorps %xmm4,%xmm4 + .byte 15,87,237 // xorps %xmm5,%xmm5 + .byte 15,87,246 // xorps %xmm6,%xmm6 + .byte 15,87,255 // xorps %xmm7,%xmm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_constant_color_sse2 +.globl _sk_constant_color_sse2 +_sk_constant_color_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,15,16,80,8 // movss 0x8(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 243,15,16,88,12 // movss 0xc(%rax),%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clear_sse2 +.globl _sk_clear_sse2 +_sk_clear_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,87,192 // xorps %xmm0,%xmm0 + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 15,87,219 // xorps %xmm3,%xmm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcatop_sse2 +.globl _sk_srcatop_sse2 +_sk_srcatop_sse2: + .byte 15,89,199 // mulps %xmm7,%xmm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,92,195 // subps %xmm3,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,204 // mulps %xmm4,%xmm9 + .byte 65,15,88,193 // addps %xmm9,%xmm0 + .byte 15,89,207 // mulps %xmm7,%xmm1 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 65,15,88,201 // addps %xmm9,%xmm1 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 65,15,88,209 // addps %xmm9,%xmm2 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 65,15,88,216 // addps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstatop_sse2 +.globl _sk_dstatop_sse2 +_sk_dstatop_sse2: + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 68,15,89,196 // mulps %xmm4,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 68,15,92,207 // subps %xmm7,%xmm9 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 68,15,89,197 // mulps %xmm5,%xmm8 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 68,15,89,198 // mulps %xmm6,%xmm8 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 65,15,88,208 // addps %xmm8,%xmm2 + .byte 68,15,89,203 // mulps %xmm3,%xmm9 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 65,15,88,217 // addps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcin_sse2 +.globl _sk_srcin_sse2 +_sk_srcin_sse2: + .byte 15,89,199 // mulps %xmm7,%xmm0 + .byte 15,89,207 // mulps %xmm7,%xmm1 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstin_sse2 +.globl _sk_dstin_sse2 +_sk_dstin_sse2: + .byte 15,40,195 // movaps %xmm3,%xmm0 + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 15,40,211 // movaps %xmm3,%xmm2 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcout_sse2 +.globl _sk_srcout_sse2 +_sk_srcout_sse2: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,92,199 // subps %xmm7,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstout_sse2 +.globl _sk_dstout_sse2 +_sk_dstout_sse2: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,92,195 // subps %xmm3,%xmm8 + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,216 // movaps %xmm8,%xmm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_srcover_sse2 +.globl _sk_srcover_sse2 +_sk_srcover_sse2: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,92,195 // subps %xmm3,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,204 // mulps %xmm4,%xmm9 + .byte 65,15,88,193 // addps %xmm9,%xmm0 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 65,15,88,201 // addps %xmm9,%xmm1 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 65,15,88,209 // addps %xmm9,%xmm2 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 65,15,88,216 // addps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_dstover_sse2 +.globl _sk_dstover_sse2 +_sk_dstover_sse2: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,92,199 // subps %xmm7,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 15,88,223 // addps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_modulate_sse2 +.globl _sk_modulate_sse2 +_sk_modulate_sse2: + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_multiply_sse2 +.globl _sk_multiply_sse2 +_sk_multiply_sse2: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,92,207 // subps %xmm7,%xmm9 + .byte 69,15,40,209 // movaps %xmm9,%xmm10 + .byte 68,15,89,208 // mulps %xmm0,%xmm10 + .byte 68,15,92,195 // subps %xmm3,%xmm8 + .byte 69,15,40,216 // movaps %xmm8,%xmm11 + .byte 68,15,89,220 // mulps %xmm4,%xmm11 + .byte 69,15,88,218 // addps %xmm10,%xmm11 + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 65,15,88,195 // addps %xmm11,%xmm0 + .byte 69,15,40,209 // movaps %xmm9,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 69,15,40,216 // movaps %xmm8,%xmm11 + .byte 68,15,89,221 // mulps %xmm5,%xmm11 + .byte 69,15,88,218 // addps %xmm10,%xmm11 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 65,15,88,203 // addps %xmm11,%xmm1 + .byte 69,15,40,209 // movaps %xmm9,%xmm10 + .byte 68,15,89,210 // mulps %xmm2,%xmm10 + .byte 69,15,40,216 // movaps %xmm8,%xmm11 + .byte 68,15,89,222 // mulps %xmm6,%xmm11 + .byte 69,15,88,218 // addps %xmm10,%xmm11 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 65,15,88,211 // addps %xmm11,%xmm2 + .byte 68,15,89,203 // mulps %xmm3,%xmm9 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 69,15,88,193 // addps %xmm9,%xmm8 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 65,15,88,216 // addps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_plus__sse2 +.globl _sk_plus__sse2 +_sk_plus__sse2: + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 15,88,223 // addps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_screen_sse2 +.globl _sk_screen_sse2 +_sk_screen_sse2: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 68,15,88,196 // addps %xmm4,%xmm8 + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 68,15,92,192 // subps %xmm0,%xmm8 + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 68,15,88,205 // addps %xmm5,%xmm9 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 68,15,92,201 // subps %xmm1,%xmm9 + .byte 68,15,40,210 // movaps %xmm2,%xmm10 + .byte 68,15,88,214 // addps %xmm6,%xmm10 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 68,15,92,210 // subps %xmm2,%xmm10 + .byte 68,15,40,219 // movaps %xmm3,%xmm11 + .byte 68,15,88,223 // addps %xmm7,%xmm11 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 68,15,92,219 // subps %xmm3,%xmm11 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 65,15,40,201 // movaps %xmm9,%xmm1 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 65,15,40,219 // movaps %xmm11,%xmm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_xor__sse2 +.globl _sk_xor__sse2 +_sk_xor__sse2: + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,92,207 // subps %xmm7,%xmm9 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,92,216 // subps %xmm8,%xmm3 + .byte 68,15,40,211 // movaps %xmm3,%xmm10 + .byte 68,15,89,212 // mulps %xmm4,%xmm10 + .byte 65,15,88,194 // addps %xmm10,%xmm0 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 68,15,40,211 // movaps %xmm3,%xmm10 + .byte 68,15,89,213 // mulps %xmm5,%xmm10 + .byte 65,15,88,202 // addps %xmm10,%xmm1 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 68,15,40,211 // movaps %xmm3,%xmm10 + .byte 68,15,89,214 // mulps %xmm6,%xmm10 + .byte 65,15,88,210 // addps %xmm10,%xmm2 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 15,89,223 // mulps %xmm7,%xmm3 + .byte 65,15,88,217 // addps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_darken_sse2 +.globl _sk_darken_sse2 +_sk_darken_sse2: + .byte 68,15,40,193 // movaps %xmm1,%xmm8 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 68,15,89,207 // mulps %xmm7,%xmm9 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 15,89,204 // mulps %xmm4,%xmm1 + .byte 68,15,95,201 // maxps %xmm1,%xmm9 + .byte 65,15,92,193 // subps %xmm9,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 69,15,95,193 // maxps %xmm9,%xmm8 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 68,15,40,194 // movaps %xmm2,%xmm8 + .byte 68,15,88,198 // addps %xmm6,%xmm8 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 65,15,95,209 // maxps %xmm9,%xmm2 + .byte 68,15,92,194 // subps %xmm2,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 15,88,218 // addps %xmm2,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lighten_sse2 +.globl _sk_lighten_sse2 +_sk_lighten_sse2: + .byte 68,15,40,193 // movaps %xmm1,%xmm8 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 68,15,89,207 // mulps %xmm7,%xmm9 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 15,89,204 // mulps %xmm4,%xmm1 + .byte 68,15,93,201 // minps %xmm1,%xmm9 + .byte 65,15,92,193 // subps %xmm9,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 69,15,93,193 // minps %xmm9,%xmm8 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 68,15,40,194 // movaps %xmm2,%xmm8 + .byte 68,15,88,198 // addps %xmm6,%xmm8 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 65,15,93,209 // minps %xmm9,%xmm2 + .byte 68,15,92,194 // subps %xmm2,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 15,88,218 // addps %xmm2,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_difference_sse2 +.globl _sk_difference_sse2 +_sk_difference_sse2: + .byte 68,15,40,193 // movaps %xmm1,%xmm8 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 68,15,89,207 // mulps %xmm7,%xmm9 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 15,89,204 // mulps %xmm4,%xmm1 + .byte 68,15,93,201 // minps %xmm1,%xmm9 + .byte 69,15,88,201 // addps %xmm9,%xmm9 + .byte 65,15,92,193 // subps %xmm9,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 69,15,93,193 // minps %xmm9,%xmm8 + .byte 69,15,88,192 // addps %xmm8,%xmm8 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 68,15,40,194 // movaps %xmm2,%xmm8 + .byte 68,15,88,198 // addps %xmm6,%xmm8 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,89,206 // mulps %xmm6,%xmm9 + .byte 65,15,93,209 // minps %xmm9,%xmm2 + .byte 15,88,210 // addps %xmm2,%xmm2 + .byte 68,15,92,194 // subps %xmm2,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 15,88,218 // addps %xmm2,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_exclusion_sse2 +.globl _sk_exclusion_sse2 +_sk_exclusion_sse2: + .byte 68,15,40,193 // movaps %xmm1,%xmm8 + .byte 15,40,200 // movaps %xmm0,%xmm1 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 15,89,204 // mulps %xmm4,%xmm1 + .byte 15,88,201 // addps %xmm1,%xmm1 + .byte 15,92,193 // subps %xmm1,%xmm0 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 68,15,89,197 // mulps %xmm5,%xmm8 + .byte 69,15,88,192 // addps %xmm8,%xmm8 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 68,15,40,194 // movaps %xmm2,%xmm8 + .byte 68,15,88,198 // addps %xmm6,%xmm8 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 15,88,210 // addps %xmm2,%xmm2 + .byte 68,15,92,194 // subps %xmm2,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 15,89,215 // mulps %xmm7,%xmm2 + .byte 15,88,218 // addps %xmm2,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_colorburn_sse2 +.globl _sk_colorburn_sse2 +_sk_colorburn_sse2: + .byte 68,15,40,193 // movaps %xmm1,%xmm8 + .byte 68,15,40,224 // movaps %xmm0,%xmm12 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 69,15,40,217 // movaps %xmm9,%xmm11 + .byte 68,15,92,223 // subps %xmm7,%xmm11 + .byte 65,15,40,195 // movaps %xmm11,%xmm0 + .byte 65,15,89,196 // mulps %xmm12,%xmm0 + .byte 69,15,87,210 // xorps %xmm10,%xmm10 + .byte 15,40,207 // movaps %xmm7,%xmm1 + .byte 15,92,204 // subps %xmm4,%xmm1 + .byte 15,89,203 // mulps %xmm3,%xmm1 + .byte 65,15,94,204 // divps %xmm12,%xmm1 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,93,233 // minps %xmm1,%xmm13 + .byte 68,15,40,247 // movaps %xmm7,%xmm14 + .byte 69,15,92,245 // subps %xmm13,%xmm14 + .byte 65,15,40,204 // movaps %xmm12,%xmm1 + .byte 65,15,194,202,0 // cmpeqps %xmm10,%xmm1 + .byte 68,15,92,203 // subps %xmm3,%xmm9 + .byte 68,15,89,243 // mulps %xmm3,%xmm14 + .byte 68,15,88,240 // addps %xmm0,%xmm14 + .byte 68,15,84,225 // andps %xmm1,%xmm12 + .byte 65,15,85,206 // andnps %xmm14,%xmm1 + .byte 69,15,40,233 // movaps %xmm9,%xmm13 + .byte 68,15,89,236 // mulps %xmm4,%xmm13 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 65,15,86,204 // orps %xmm12,%xmm1 + .byte 68,15,40,228 // movaps %xmm4,%xmm12 + .byte 68,15,194,231,0 // cmpeqps %xmm7,%xmm12 + .byte 65,15,88,205 // addps %xmm13,%xmm1 + .byte 65,15,84,196 // andps %xmm12,%xmm0 + .byte 68,15,85,225 // andnps %xmm1,%xmm12 + .byte 65,15,86,196 // orps %xmm12,%xmm0 + .byte 65,15,40,203 // movaps %xmm11,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 68,15,40,231 // movaps %xmm7,%xmm12 + .byte 68,15,92,229 // subps %xmm5,%xmm12 + .byte 68,15,89,227 // mulps %xmm3,%xmm12 + .byte 69,15,94,224 // divps %xmm8,%xmm12 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 69,15,93,236 // minps %xmm12,%xmm13 + .byte 68,15,40,231 // movaps %xmm7,%xmm12 + .byte 69,15,92,229 // subps %xmm13,%xmm12 + .byte 69,15,40,232 // movaps %xmm8,%xmm13 + .byte 69,15,194,234,0 // cmpeqps %xmm10,%xmm13 + .byte 68,15,89,227 // mulps %xmm3,%xmm12 + .byte 68,15,88,225 // addps %xmm1,%xmm12 + .byte 69,15,84,197 // andps %xmm13,%xmm8 + .byte 69,15,85,236 // andnps %xmm12,%xmm13 + .byte 69,15,86,232 // orps %xmm8,%xmm13 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 68,15,89,197 // mulps %xmm5,%xmm8 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 69,15,88,232 // addps %xmm8,%xmm13 + .byte 68,15,40,197 // movaps %xmm5,%xmm8 + .byte 68,15,194,199,0 // cmpeqps %xmm7,%xmm8 + .byte 65,15,84,200 // andps %xmm8,%xmm1 + .byte 69,15,85,197 // andnps %xmm13,%xmm8 + .byte 65,15,86,200 // orps %xmm8,%xmm1 + .byte 68,15,40,199 // movaps %xmm7,%xmm8 + .byte 68,15,92,198 // subps %xmm6,%xmm8 + .byte 68,15,89,195 // mulps %xmm3,%xmm8 + .byte 68,15,94,194 // divps %xmm2,%xmm8 + .byte 68,15,40,231 // movaps %xmm7,%xmm12 + .byte 69,15,93,224 // minps %xmm8,%xmm12 + .byte 68,15,40,199 // movaps %xmm7,%xmm8 + .byte 69,15,92,196 // subps %xmm12,%xmm8 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 68,15,194,210,0 // cmpeqps %xmm2,%xmm10 + .byte 68,15,89,195 // mulps %xmm3,%xmm8 + .byte 69,15,88,195 // addps %xmm11,%xmm8 + .byte 65,15,84,210 // andps %xmm10,%xmm2 + .byte 69,15,85,208 // andnps %xmm8,%xmm10 + .byte 69,15,40,195 // movaps %xmm11,%xmm8 + .byte 68,15,88,198 // addps %xmm6,%xmm8 + .byte 68,15,86,210 // orps %xmm2,%xmm10 + .byte 65,15,40,209 // movaps %xmm9,%xmm2 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 68,15,88,210 // addps %xmm2,%xmm10 + .byte 15,40,214 // movaps %xmm6,%xmm2 + .byte 15,194,215,0 // cmpeqps %xmm7,%xmm2 + .byte 68,15,84,194 // andps %xmm2,%xmm8 + .byte 65,15,85,210 // andnps %xmm10,%xmm2 + .byte 68,15,86,194 // orps %xmm2,%xmm8 + .byte 68,15,89,207 // mulps %xmm7,%xmm9 + .byte 65,15,88,217 // addps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_colordodge_sse2 +.globl _sk_colordodge_sse2 +_sk_colordodge_sse2: + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,40,218 // movaps %xmm10,%xmm11 + .byte 68,15,92,223 // subps %xmm7,%xmm11 + .byte 65,15,40,195 // movaps %xmm11,%xmm0 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 68,15,89,196 // mulps %xmm4,%xmm8 + .byte 68,15,40,227 // movaps %xmm3,%xmm12 + .byte 69,15,92,225 // subps %xmm9,%xmm12 + .byte 69,15,94,196 // divps %xmm12,%xmm8 + .byte 68,15,40,231 // movaps %xmm7,%xmm12 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 69,15,93,232 // minps %xmm8,%xmm13 + .byte 69,15,40,241 // movaps %xmm9,%xmm14 + .byte 68,15,194,243,0 // cmpeqps %xmm3,%xmm14 + .byte 68,15,89,235 // mulps %xmm3,%xmm13 + .byte 68,15,88,232 // addps %xmm0,%xmm13 + .byte 69,15,84,206 // andps %xmm14,%xmm9 + .byte 69,15,85,245 // andnps %xmm13,%xmm14 + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 68,15,92,211 // subps %xmm3,%xmm10 + .byte 69,15,86,241 // orps %xmm9,%xmm14 + .byte 69,15,40,202 // movaps %xmm10,%xmm9 + .byte 68,15,89,204 // mulps %xmm4,%xmm9 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 69,15,88,241 // addps %xmm9,%xmm14 + .byte 68,15,40,204 // movaps %xmm4,%xmm9 + .byte 69,15,194,200,0 // cmpeqps %xmm8,%xmm9 + .byte 65,15,84,193 // andps %xmm9,%xmm0 + .byte 69,15,85,206 // andnps %xmm14,%xmm9 + .byte 65,15,86,193 // orps %xmm9,%xmm0 + .byte 68,15,40,235 // movaps %xmm3,%xmm13 + .byte 68,15,89,237 // mulps %xmm5,%xmm13 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,92,201 // subps %xmm1,%xmm9 + .byte 69,15,94,233 // divps %xmm9,%xmm13 + .byte 69,15,40,203 // movaps %xmm11,%xmm9 + .byte 68,15,89,201 // mulps %xmm1,%xmm9 + .byte 69,15,93,229 // minps %xmm13,%xmm12 + .byte 68,15,40,233 // movaps %xmm1,%xmm13 + .byte 68,15,194,235,0 // cmpeqps %xmm3,%xmm13 + .byte 68,15,89,227 // mulps %xmm3,%xmm12 + .byte 69,15,88,225 // addps %xmm9,%xmm12 + .byte 65,15,84,205 // andps %xmm13,%xmm1 + .byte 69,15,85,236 // andnps %xmm12,%xmm13 + .byte 68,15,86,233 // orps %xmm1,%xmm13 + .byte 65,15,40,202 // movaps %xmm10,%xmm1 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 68,15,88,205 // addps %xmm5,%xmm9 + .byte 68,15,88,233 // addps %xmm1,%xmm13 + .byte 15,40,205 // movaps %xmm5,%xmm1 + .byte 65,15,194,200,0 // cmpeqps %xmm8,%xmm1 + .byte 68,15,84,201 // andps %xmm1,%xmm9 + .byte 65,15,85,205 // andnps %xmm13,%xmm1 + .byte 68,15,86,201 // orps %xmm1,%xmm9 + .byte 68,15,40,227 // movaps %xmm3,%xmm12 + .byte 68,15,89,230 // mulps %xmm6,%xmm12 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 15,92,202 // subps %xmm2,%xmm1 + .byte 68,15,94,225 // divps %xmm1,%xmm12 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,93,236 // minps %xmm12,%xmm13 + .byte 15,40,202 // movaps %xmm2,%xmm1 + .byte 15,194,203,0 // cmpeqps %xmm3,%xmm1 + .byte 68,15,89,235 // mulps %xmm3,%xmm13 + .byte 69,15,88,235 // addps %xmm11,%xmm13 + .byte 15,84,209 // andps %xmm1,%xmm2 + .byte 65,15,85,205 // andnps %xmm13,%xmm1 + .byte 15,86,202 // orps %xmm2,%xmm1 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 15,88,202 // addps %xmm2,%xmm1 + .byte 68,15,194,198,0 // cmpeqps %xmm6,%xmm8 + .byte 68,15,88,222 // addps %xmm6,%xmm11 + .byte 69,15,84,216 // andps %xmm8,%xmm11 + .byte 68,15,85,193 // andnps %xmm1,%xmm8 + .byte 69,15,86,195 // orps %xmm11,%xmm8 + .byte 68,15,89,215 // mulps %xmm7,%xmm10 + .byte 65,15,88,218 // addps %xmm10,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,201 // movaps %xmm9,%xmm1 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_hardlight_sse2 +.globl _sk_hardlight_sse2 +_sk_hardlight_sse2: + .byte 15,41,116,36,232 // movaps %xmm6,-0x18(%rsp) + .byte 15,40,245 // movaps %xmm5,%xmm6 + .byte 15,40,236 // movaps %xmm4,%xmm5 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,216 // movd %eax,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,40,211 // movaps %xmm11,%xmm10 + .byte 68,15,92,215 // subps %xmm7,%xmm10 + .byte 69,15,40,194 // movaps %xmm10,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 68,15,92,219 // subps %xmm3,%xmm11 + .byte 69,15,40,203 // movaps %xmm11,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 69,15,88,200 // addps %xmm8,%xmm9 + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 68,15,92,192 // subps %xmm0,%xmm8 + .byte 15,40,227 // movaps %xmm3,%xmm4 + .byte 15,89,231 // mulps %xmm7,%xmm4 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,40,247 // movaps %xmm7,%xmm14 + .byte 68,15,40,255 // movaps %xmm7,%xmm15 + .byte 68,15,92,253 // subps %xmm5,%xmm15 + .byte 69,15,89,248 // mulps %xmm8,%xmm15 + .byte 69,15,88,255 // addps %xmm15,%xmm15 + .byte 68,15,40,228 // movaps %xmm4,%xmm12 + .byte 69,15,92,231 // subps %xmm15,%xmm12 + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 69,15,88,192 // addps %xmm8,%xmm8 + .byte 68,15,194,195,2 // cmpleps %xmm3,%xmm8 + .byte 15,89,197 // mulps %xmm5,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 65,15,84,192 // andps %xmm8,%xmm0 + .byte 69,15,85,196 // andnps %xmm12,%xmm8 + .byte 68,15,86,192 // orps %xmm0,%xmm8 + .byte 69,15,40,251 // movaps %xmm11,%xmm15 + .byte 69,15,40,227 // movaps %xmm11,%xmm12 + .byte 68,15,89,223 // mulps %xmm7,%xmm11 + .byte 69,15,88,193 // addps %xmm9,%xmm8 + .byte 65,15,40,194 // movaps %xmm10,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 68,15,89,254 // mulps %xmm6,%xmm15 + .byte 68,15,88,248 // addps %xmm0,%xmm15 + .byte 15,40,195 // movaps %xmm3,%xmm0 + .byte 15,92,193 // subps %xmm1,%xmm0 + .byte 68,15,92,238 // subps %xmm6,%xmm13 + .byte 68,15,89,232 // mulps %xmm0,%xmm13 + .byte 69,15,88,237 // addps %xmm13,%xmm13 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 65,15,92,197 // subps %xmm13,%xmm0 + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 69,15,88,201 // addps %xmm9,%xmm9 + .byte 68,15,194,203,2 // cmpleps %xmm3,%xmm9 + .byte 15,89,206 // mulps %xmm6,%xmm1 + .byte 15,88,201 // addps %xmm1,%xmm1 + .byte 65,15,84,201 // andps %xmm9,%xmm1 + .byte 68,15,85,200 // andnps %xmm0,%xmm9 + .byte 68,15,86,201 // orps %xmm1,%xmm9 + .byte 69,15,88,207 // addps %xmm15,%xmm9 + .byte 68,15,89,210 // mulps %xmm2,%xmm10 + .byte 68,15,40,108,36,232 // movaps -0x18(%rsp),%xmm13 + .byte 69,15,89,229 // mulps %xmm13,%xmm12 + .byte 69,15,88,226 // addps %xmm10,%xmm12 + .byte 68,15,40,210 // movaps %xmm2,%xmm10 + .byte 69,15,88,210 // addps %xmm10,%xmm10 + .byte 68,15,194,211,2 // cmpleps %xmm3,%xmm10 + .byte 15,40,195 // movaps %xmm3,%xmm0 + .byte 15,92,194 // subps %xmm2,%xmm0 + .byte 65,15,89,213 // mulps %xmm13,%xmm2 + .byte 15,88,210 // addps %xmm2,%xmm2 + .byte 69,15,92,245 // subps %xmm13,%xmm14 + .byte 68,15,89,240 // mulps %xmm0,%xmm14 + .byte 69,15,88,246 // addps %xmm14,%xmm14 + .byte 65,15,92,230 // subps %xmm14,%xmm4 + .byte 65,15,84,210 // andps %xmm10,%xmm2 + .byte 68,15,85,212 // andnps %xmm4,%xmm10 + .byte 68,15,86,210 // orps %xmm2,%xmm10 + .byte 69,15,88,212 // addps %xmm12,%xmm10 + .byte 65,15,88,219 // addps %xmm11,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 65,15,40,201 // movaps %xmm9,%xmm1 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 15,40,229 // movaps %xmm5,%xmm4 + .byte 15,40,238 // movaps %xmm6,%xmm5 + .byte 65,15,40,245 // movaps %xmm13,%xmm6 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_overlay_sse2 +.globl _sk_overlay_sse2 +_sk_overlay_sse2: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,92,207 // subps %xmm7,%xmm9 + .byte 69,15,40,209 // movaps %xmm9,%xmm10 + .byte 68,15,89,208 // mulps %xmm0,%xmm10 + .byte 68,15,92,195 // subps %xmm3,%xmm8 + .byte 69,15,40,216 // movaps %xmm8,%xmm11 + .byte 68,15,89,220 // mulps %xmm4,%xmm11 + .byte 69,15,88,218 // addps %xmm10,%xmm11 + .byte 68,15,40,227 // movaps %xmm3,%xmm12 + .byte 68,15,92,224 // subps %xmm0,%xmm12 + .byte 15,89,196 // mulps %xmm4,%xmm0 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,92,236 // subps %xmm4,%xmm13 + .byte 68,15,40,244 // movaps %xmm4,%xmm14 + .byte 69,15,88,246 // addps %xmm14,%xmm14 + .byte 68,15,194,247,2 // cmpleps %xmm7,%xmm14 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 68,15,40,211 // movaps %xmm3,%xmm10 + .byte 68,15,89,215 // mulps %xmm7,%xmm10 + .byte 69,15,89,236 // mulps %xmm12,%xmm13 + .byte 69,15,88,237 // addps %xmm13,%xmm13 + .byte 69,15,40,226 // movaps %xmm10,%xmm12 + .byte 69,15,92,229 // subps %xmm13,%xmm12 + .byte 65,15,84,198 // andps %xmm14,%xmm0 + .byte 69,15,85,244 // andnps %xmm12,%xmm14 + .byte 65,15,86,198 // orps %xmm14,%xmm0 + .byte 65,15,88,195 // addps %xmm11,%xmm0 + .byte 69,15,40,217 // movaps %xmm9,%xmm11 + .byte 68,15,89,217 // mulps %xmm1,%xmm11 + .byte 69,15,40,224 // movaps %xmm8,%xmm12 + .byte 68,15,89,229 // mulps %xmm5,%xmm12 + .byte 69,15,88,227 // addps %xmm11,%xmm12 + .byte 68,15,40,219 // movaps %xmm3,%xmm11 + .byte 68,15,92,217 // subps %xmm1,%xmm11 + .byte 15,89,205 // mulps %xmm5,%xmm1 + .byte 68,15,40,239 // movaps %xmm7,%xmm13 + .byte 68,15,92,237 // subps %xmm5,%xmm13 + .byte 68,15,40,245 // movaps %xmm5,%xmm14 + .byte 69,15,88,246 // addps %xmm14,%xmm14 + .byte 68,15,194,247,2 // cmpleps %xmm7,%xmm14 + .byte 15,88,201 // addps %xmm1,%xmm1 + .byte 69,15,89,235 // mulps %xmm11,%xmm13 + .byte 69,15,88,237 // addps %xmm13,%xmm13 + .byte 69,15,40,218 // movaps %xmm10,%xmm11 + .byte 69,15,92,221 // subps %xmm13,%xmm11 + .byte 65,15,84,206 // andps %xmm14,%xmm1 + .byte 69,15,85,243 // andnps %xmm11,%xmm14 + .byte 65,15,86,206 // orps %xmm14,%xmm1 + .byte 65,15,88,204 // addps %xmm12,%xmm1 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 69,15,40,216 // movaps %xmm8,%xmm11 + .byte 68,15,89,222 // mulps %xmm6,%xmm11 + .byte 69,15,88,217 // addps %xmm9,%xmm11 + .byte 68,15,40,203 // movaps %xmm3,%xmm9 + .byte 68,15,92,202 // subps %xmm2,%xmm9 + .byte 15,89,214 // mulps %xmm6,%xmm2 + .byte 68,15,40,231 // movaps %xmm7,%xmm12 + .byte 68,15,92,230 // subps %xmm6,%xmm12 + .byte 68,15,40,238 // movaps %xmm6,%xmm13 + .byte 69,15,88,237 // addps %xmm13,%xmm13 + .byte 68,15,194,239,2 // cmpleps %xmm7,%xmm13 + .byte 15,88,210 // addps %xmm2,%xmm2 + .byte 69,15,89,225 // mulps %xmm9,%xmm12 + .byte 69,15,88,228 // addps %xmm12,%xmm12 + .byte 69,15,92,212 // subps %xmm12,%xmm10 + .byte 65,15,84,213 // andps %xmm13,%xmm2 + .byte 69,15,85,234 // andnps %xmm10,%xmm13 + .byte 65,15,86,213 // orps %xmm13,%xmm2 + .byte 65,15,88,211 // addps %xmm11,%xmm2 + .byte 68,15,89,199 // mulps %xmm7,%xmm8 + .byte 65,15,88,216 // addps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_softlight_sse2 +.globl _sk_softlight_sse2 +_sk_softlight_sse2: + .byte 15,41,84,36,232 // movaps %xmm2,-0x18(%rsp) + .byte 15,40,209 // movaps %xmm1,%xmm2 + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 69,15,87,228 // xorps %xmm12,%xmm12 + .byte 68,15,194,231,1 // cmpltps %xmm7,%xmm12 + .byte 68,15,40,212 // movaps %xmm4,%xmm10 + .byte 68,15,94,215 // divps %xmm7,%xmm10 + .byte 69,15,84,212 // andps %xmm12,%xmm10 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 69,15,40,241 // movaps %xmm9,%xmm14 + .byte 69,15,92,242 // subps %xmm10,%xmm14 + .byte 69,15,40,218 // movaps %xmm10,%xmm11 + .byte 69,15,40,234 // movaps %xmm10,%xmm13 + .byte 65,15,82,194 // rsqrtps %xmm10,%xmm0 + .byte 68,15,83,248 // rcpps %xmm0,%xmm15 + .byte 69,15,92,250 // subps %xmm10,%xmm15 + .byte 69,15,88,210 // addps %xmm10,%xmm10 + .byte 69,15,88,210 // addps %xmm10,%xmm10 + .byte 65,15,40,194 // movaps %xmm10,%xmm0 + .byte 15,89,192 // mulps %xmm0,%xmm0 + .byte 65,15,88,194 // addps %xmm10,%xmm0 + .byte 69,15,92,217 // subps %xmm9,%xmm11 + .byte 68,15,89,216 // mulps %xmm0,%xmm11 + .byte 184,0,0,224,64 // mov $0x40e00000,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,234 // mulps %xmm10,%xmm13 + .byte 69,15,88,235 // addps %xmm11,%xmm13 + .byte 68,15,40,219 // movaps %xmm3,%xmm11 + .byte 15,40,204 // movaps %xmm4,%xmm1 + .byte 68,15,89,217 // mulps %xmm1,%xmm11 + .byte 15,88,228 // addps %xmm4,%xmm4 + .byte 15,88,228 // addps %xmm4,%xmm4 + .byte 15,194,231,2 // cmpleps %xmm7,%xmm4 + .byte 68,15,84,236 // andps %xmm4,%xmm13 + .byte 65,15,85,231 // andnps %xmm15,%xmm4 + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 15,88,192 // addps %xmm0,%xmm0 + .byte 65,15,86,229 // orps %xmm13,%xmm4 + .byte 68,15,40,232 // movaps %xmm0,%xmm13 + .byte 68,15,92,235 // subps %xmm3,%xmm13 + .byte 69,15,89,245 // mulps %xmm13,%xmm14 + .byte 68,15,89,239 // mulps %xmm7,%xmm13 + .byte 65,15,89,229 // mulps %xmm13,%xmm4 + .byte 65,15,88,227 // addps %xmm11,%xmm4 + .byte 69,15,40,217 // movaps %xmm9,%xmm11 + .byte 68,15,92,219 // subps %xmm3,%xmm11 + .byte 69,15,40,251 // movaps %xmm11,%xmm15 + .byte 15,41,76,36,216 // movaps %xmm1,-0x28(%rsp) + .byte 68,15,89,249 // mulps %xmm1,%xmm15 + .byte 69,15,40,233 // movaps %xmm9,%xmm13 + .byte 68,15,92,239 // subps %xmm7,%xmm13 + .byte 69,15,89,197 // mulps %xmm13,%xmm8 + .byte 69,15,88,199 // addps %xmm15,%xmm8 + .byte 68,15,88,243 // addps %xmm3,%xmm14 + .byte 68,15,89,241 // mulps %xmm1,%xmm14 + .byte 15,194,195,2 // cmpleps %xmm3,%xmm0 + .byte 68,15,84,240 // andps %xmm0,%xmm14 + .byte 15,85,196 // andnps %xmm4,%xmm0 + .byte 65,15,86,198 // orps %xmm14,%xmm0 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 15,41,108,36,200 // movaps %xmm5,-0x38(%rsp) + .byte 68,15,40,197 // movaps %xmm5,%xmm8 + .byte 68,15,94,199 // divps %xmm7,%xmm8 + .byte 69,15,84,196 // andps %xmm12,%xmm8 + .byte 69,15,40,240 // movaps %xmm8,%xmm14 + .byte 69,15,88,246 // addps %xmm14,%xmm14 + .byte 69,15,88,246 // addps %xmm14,%xmm14 + .byte 65,15,40,230 // movaps %xmm14,%xmm4 + .byte 15,89,228 // mulps %xmm4,%xmm4 + .byte 65,15,88,230 // addps %xmm14,%xmm4 + .byte 69,15,40,248 // movaps %xmm8,%xmm15 + .byte 69,15,92,249 // subps %xmm9,%xmm15 + .byte 68,15,89,252 // mulps %xmm4,%xmm15 + .byte 69,15,40,241 // movaps %xmm9,%xmm14 + .byte 69,15,92,240 // subps %xmm8,%xmm14 + .byte 65,15,82,224 // rsqrtps %xmm8,%xmm4 + .byte 15,83,228 // rcpps %xmm4,%xmm4 + .byte 65,15,92,224 // subps %xmm8,%xmm4 + .byte 69,15,89,194 // mulps %xmm10,%xmm8 + .byte 69,15,88,199 // addps %xmm15,%xmm8 + .byte 68,15,40,253 // movaps %xmm5,%xmm15 + .byte 69,15,88,255 // addps %xmm15,%xmm15 + .byte 69,15,88,255 // addps %xmm15,%xmm15 + .byte 68,15,194,255,2 // cmpleps %xmm7,%xmm15 + .byte 69,15,84,199 // andps %xmm15,%xmm8 + .byte 68,15,85,252 // andnps %xmm4,%xmm15 + .byte 69,15,86,248 // orps %xmm8,%xmm15 + .byte 68,15,40,194 // movaps %xmm2,%xmm8 + .byte 69,15,88,192 // addps %xmm8,%xmm8 + .byte 65,15,40,224 // movaps %xmm8,%xmm4 + .byte 15,92,227 // subps %xmm3,%xmm4 + .byte 68,15,89,244 // mulps %xmm4,%xmm14 + .byte 15,89,231 // mulps %xmm7,%xmm4 + .byte 68,15,89,252 // mulps %xmm4,%xmm15 + .byte 15,40,227 // movaps %xmm3,%xmm4 + .byte 15,89,229 // mulps %xmm5,%xmm4 + .byte 68,15,88,252 // addps %xmm4,%xmm15 + .byte 65,15,40,227 // movaps %xmm11,%xmm4 + .byte 15,89,229 // mulps %xmm5,%xmm4 + .byte 65,15,89,213 // mulps %xmm13,%xmm2 + .byte 15,88,212 // addps %xmm4,%xmm2 + .byte 68,15,88,243 // addps %xmm3,%xmm14 + .byte 68,15,89,245 // mulps %xmm5,%xmm14 + .byte 68,15,194,195,2 // cmpleps %xmm3,%xmm8 + .byte 69,15,84,240 // andps %xmm8,%xmm14 + .byte 69,15,85,199 // andnps %xmm15,%xmm8 + .byte 69,15,86,198 // orps %xmm14,%xmm8 + .byte 68,15,88,194 // addps %xmm2,%xmm8 + .byte 68,15,40,246 // movaps %xmm6,%xmm14 + .byte 65,15,40,206 // movaps %xmm14,%xmm1 + .byte 15,94,207 // divps %xmm7,%xmm1 + .byte 65,15,84,204 // andps %xmm12,%xmm1 + .byte 15,40,225 // movaps %xmm1,%xmm4 + .byte 65,15,92,225 // subps %xmm9,%xmm4 + .byte 68,15,92,201 // subps %xmm1,%xmm9 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 15,82,241 // rsqrtps %xmm1,%xmm6 + .byte 15,83,246 // rcpps %xmm6,%xmm6 + .byte 15,92,241 // subps %xmm1,%xmm6 + .byte 15,88,201 // addps %xmm1,%xmm1 + .byte 15,88,201 // addps %xmm1,%xmm1 + .byte 15,40,233 // movaps %xmm1,%xmm5 + .byte 15,89,237 // mulps %xmm5,%xmm5 + .byte 15,88,233 // addps %xmm1,%xmm5 + .byte 15,89,236 // mulps %xmm4,%xmm5 + .byte 68,15,88,213 // addps %xmm5,%xmm10 + .byte 65,15,40,238 // movaps %xmm14,%xmm5 + .byte 15,40,205 // movaps %xmm5,%xmm1 + .byte 15,88,201 // addps %xmm1,%xmm1 + .byte 15,88,201 // addps %xmm1,%xmm1 + .byte 15,194,207,2 // cmpleps %xmm7,%xmm1 + .byte 68,15,84,209 // andps %xmm1,%xmm10 + .byte 15,85,206 // andnps %xmm6,%xmm1 + .byte 15,40,84,36,232 // movaps -0x18(%rsp),%xmm2 + .byte 68,15,89,234 // mulps %xmm2,%xmm13 + .byte 15,88,210 // addps %xmm2,%xmm2 + .byte 65,15,86,202 // orps %xmm10,%xmm1 + .byte 15,40,226 // movaps %xmm2,%xmm4 + .byte 15,92,227 // subps %xmm3,%xmm4 + .byte 68,15,89,204 // mulps %xmm4,%xmm9 + .byte 15,89,231 // mulps %xmm7,%xmm4 + .byte 15,89,204 // mulps %xmm4,%xmm1 + .byte 15,40,227 // movaps %xmm3,%xmm4 + .byte 15,89,229 // mulps %xmm5,%xmm4 + .byte 15,88,204 // addps %xmm4,%xmm1 + .byte 65,15,40,227 // movaps %xmm11,%xmm4 + .byte 15,89,229 // mulps %xmm5,%xmm4 + .byte 65,15,88,229 // addps %xmm13,%xmm4 + .byte 68,15,88,203 // addps %xmm3,%xmm9 + .byte 68,15,89,205 // mulps %xmm5,%xmm9 + .byte 15,40,245 // movaps %xmm5,%xmm6 + .byte 15,194,211,2 // cmpleps %xmm3,%xmm2 + .byte 68,15,84,202 // andps %xmm2,%xmm9 + .byte 15,85,209 // andnps %xmm1,%xmm2 + .byte 65,15,86,209 // orps %xmm9,%xmm2 + .byte 15,88,212 // addps %xmm4,%xmm2 + .byte 68,15,89,223 // mulps %xmm7,%xmm11 + .byte 65,15,88,219 // addps %xmm11,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,100,36,216 // movaps -0x28(%rsp),%xmm4 + .byte 15,40,108,36,200 // movaps -0x38(%rsp),%xmm5 + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_0_sse2 +.globl _sk_clamp_0_sse2 +_sk_clamp_0_sse2: + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 65,15,95,192 // maxps %xmm8,%xmm0 + .byte 65,15,95,200 // maxps %xmm8,%xmm1 + .byte 65,15,95,208 // maxps %xmm8,%xmm2 + .byte 65,15,95,216 // maxps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_1_sse2 +.globl _sk_clamp_1_sse2 +_sk_clamp_1_sse2: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,93,192 // minps %xmm8,%xmm0 + .byte 65,15,93,200 // minps %xmm8,%xmm1 + .byte 65,15,93,208 // minps %xmm8,%xmm2 + .byte 65,15,93,216 // minps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_a_sse2 +.globl _sk_clamp_a_sse2 +_sk_clamp_a_sse2: + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,93,216 // minps %xmm8,%xmm3 + .byte 15,93,195 // minps %xmm3,%xmm0 + .byte 15,93,203 // minps %xmm3,%xmm1 + .byte 15,93,211 // minps %xmm3,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_set_rgb_sse2 +.globl _sk_set_rgb_sse2 +_sk_set_rgb_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,15,16,80,8 // movss 0x8(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_swap_rb_sse2 +.globl _sk_swap_rb_sse2 +_sk_swap_rb_sse2: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_swap_sse2 +.globl _sk_swap_sse2 +_sk_swap_sse2: + .byte 68,15,40,195 // movaps %xmm3,%xmm8 + .byte 68,15,40,202 // movaps %xmm2,%xmm9 + .byte 68,15,40,209 // movaps %xmm1,%xmm10 + .byte 68,15,40,216 // movaps %xmm0,%xmm11 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 15,40,205 // movaps %xmm5,%xmm1 + .byte 15,40,214 // movaps %xmm6,%xmm2 + .byte 15,40,223 // movaps %xmm7,%xmm3 + .byte 65,15,40,227 // movaps %xmm11,%xmm4 + .byte 65,15,40,234 // movaps %xmm10,%xmm5 + .byte 65,15,40,241 // movaps %xmm9,%xmm6 + .byte 65,15,40,248 // movaps %xmm8,%xmm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_move_src_dst_sse2 +.globl _sk_move_src_dst_sse2 +_sk_move_src_dst_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,224 // movaps %xmm0,%xmm4 + .byte 15,40,233 // movaps %xmm1,%xmm5 + .byte 15,40,242 // movaps %xmm2,%xmm6 + .byte 15,40,251 // movaps %xmm3,%xmm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_move_dst_src_sse2 +.globl _sk_move_dst_src_sse2 +_sk_move_dst_src_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 15,40,205 // movaps %xmm5,%xmm1 + .byte 15,40,214 // movaps %xmm6,%xmm2 + .byte 15,40,223 // movaps %xmm7,%xmm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_premul_sse2 +.globl _sk_premul_sse2 +_sk_premul_sse2: + .byte 15,89,195 // mulps %xmm3,%xmm0 + .byte 15,89,203 // mulps %xmm3,%xmm1 + .byte 15,89,211 // mulps %xmm3,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_unpremul_sse2 +.globl _sk_unpremul_sse2 +_sk_unpremul_sse2: + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 68,15,94,203 // divps %xmm3,%xmm9 + .byte 68,15,194,195,4 // cmpneqps %xmm3,%xmm8 + .byte 69,15,84,193 // andps %xmm9,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_from_srgb_sse2 +.globl _sk_from_srgb_sse2 +_sk_from_srgb_sse2: + .byte 184,145,131,158,61 // mov $0x3d9e8391,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,232 // movaps %xmm8,%xmm13 + .byte 68,15,89,232 // mulps %xmm0,%xmm13 + .byte 68,15,40,224 // movaps %xmm0,%xmm12 + .byte 69,15,89,228 // mulps %xmm12,%xmm12 + .byte 184,154,153,153,62 // mov $0x3e99999a,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 184,92,143,50,63 // mov $0x3f328f5c,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,40,241 // movaps %xmm9,%xmm14 + .byte 68,15,89,240 // mulps %xmm0,%xmm14 + .byte 69,15,88,242 // addps %xmm10,%xmm14 + .byte 184,10,215,35,59 // mov $0x3b23d70a,%eax + .byte 102,68,15,110,216 // movd %eax,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,244 // mulps %xmm12,%xmm14 + .byte 69,15,88,243 // addps %xmm11,%xmm14 + .byte 184,174,71,97,61 // mov $0x3d6147ae,%eax + .byte 102,68,15,110,224 // movd %eax,%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 65,15,194,196,1 // cmpltps %xmm12,%xmm0 + .byte 68,15,84,232 // andps %xmm0,%xmm13 + .byte 65,15,85,198 // andnps %xmm14,%xmm0 + .byte 65,15,86,197 // orps %xmm13,%xmm0 + .byte 69,15,40,232 // movaps %xmm8,%xmm13 + .byte 68,15,89,233 // mulps %xmm1,%xmm13 + .byte 68,15,40,241 // movaps %xmm1,%xmm14 + .byte 69,15,89,246 // mulps %xmm14,%xmm14 + .byte 69,15,40,249 // movaps %xmm9,%xmm15 + .byte 68,15,89,249 // mulps %xmm1,%xmm15 + .byte 69,15,88,250 // addps %xmm10,%xmm15 + .byte 69,15,89,254 // mulps %xmm14,%xmm15 + .byte 69,15,88,251 // addps %xmm11,%xmm15 + .byte 65,15,194,204,1 // cmpltps %xmm12,%xmm1 + .byte 68,15,84,233 // andps %xmm1,%xmm13 + .byte 65,15,85,207 // andnps %xmm15,%xmm1 + .byte 65,15,86,205 // orps %xmm13,%xmm1 + .byte 68,15,89,194 // mulps %xmm2,%xmm8 + .byte 68,15,40,234 // movaps %xmm2,%xmm13 + .byte 69,15,89,237 // mulps %xmm13,%xmm13 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 69,15,89,205 // mulps %xmm13,%xmm9 + .byte 69,15,88,203 // addps %xmm11,%xmm9 + .byte 65,15,194,212,1 // cmpltps %xmm12,%xmm2 + .byte 68,15,84,194 // andps %xmm2,%xmm8 + .byte 65,15,85,209 // andnps %xmm9,%xmm2 + .byte 65,15,86,208 // orps %xmm8,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_to_srgb_sse2 +.globl _sk_to_srgb_sse2 +_sk_to_srgb_sse2: + .byte 68,15,82,192 // rsqrtps %xmm0,%xmm8 + .byte 69,15,83,248 // rcpps %xmm8,%xmm15 + .byte 69,15,82,232 // rsqrtps %xmm8,%xmm13 + .byte 184,41,92,71,65 // mov $0x41475c29,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,240 // movaps %xmm8,%xmm14 + .byte 68,15,89,240 // mulps %xmm0,%xmm14 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 184,194,135,210,62 // mov $0x3ed287c2,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 184,206,111,48,63 // mov $0x3f306fce,%eax + .byte 102,68,15,110,216 // movd %eax,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 184,168,87,202,61 // mov $0x3dca57a8,%eax + .byte 53,0,0,0,128 // xor $0x80000000,%eax + .byte 102,68,15,110,224 // movd %eax,%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 69,15,89,251 // mulps %xmm11,%xmm15 + .byte 69,15,88,252 // addps %xmm12,%xmm15 + .byte 69,15,89,234 // mulps %xmm10,%xmm13 + .byte 69,15,88,239 // addps %xmm15,%xmm13 + .byte 69,15,40,249 // movaps %xmm9,%xmm15 + .byte 69,15,93,253 // minps %xmm13,%xmm15 + .byte 184,4,231,140,59 // mov $0x3b8ce704,%eax + .byte 102,68,15,110,232 // movd %eax,%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 65,15,194,197,1 // cmpltps %xmm13,%xmm0 + .byte 68,15,84,240 // andps %xmm0,%xmm14 + .byte 65,15,85,199 // andnps %xmm15,%xmm0 + .byte 65,15,86,198 // orps %xmm14,%xmm0 + .byte 68,15,82,241 // rsqrtps %xmm1,%xmm14 + .byte 69,15,83,254 // rcpps %xmm14,%xmm15 + .byte 69,15,82,246 // rsqrtps %xmm14,%xmm14 + .byte 69,15,89,251 // mulps %xmm11,%xmm15 + .byte 69,15,88,252 // addps %xmm12,%xmm15 + .byte 69,15,89,242 // mulps %xmm10,%xmm14 + .byte 69,15,88,247 // addps %xmm15,%xmm14 + .byte 69,15,40,249 // movaps %xmm9,%xmm15 + .byte 69,15,93,254 // minps %xmm14,%xmm15 + .byte 69,15,40,240 // movaps %xmm8,%xmm14 + .byte 68,15,89,241 // mulps %xmm1,%xmm14 + .byte 65,15,194,205,1 // cmpltps %xmm13,%xmm1 + .byte 68,15,84,241 // andps %xmm1,%xmm14 + .byte 65,15,85,207 // andnps %xmm15,%xmm1 + .byte 65,15,86,206 // orps %xmm14,%xmm1 + .byte 68,15,82,242 // rsqrtps %xmm2,%xmm14 + .byte 69,15,83,254 // rcpps %xmm14,%xmm15 + .byte 69,15,89,251 // mulps %xmm11,%xmm15 + .byte 69,15,88,252 // addps %xmm12,%xmm15 + .byte 69,15,82,222 // rsqrtps %xmm14,%xmm11 + .byte 69,15,89,218 // mulps %xmm10,%xmm11 + .byte 69,15,88,223 // addps %xmm15,%xmm11 + .byte 69,15,93,203 // minps %xmm11,%xmm9 + .byte 68,15,89,194 // mulps %xmm2,%xmm8 + .byte 65,15,194,213,1 // cmpltps %xmm13,%xmm2 + .byte 68,15,84,194 // andps %xmm2,%xmm8 + .byte 65,15,85,209 // andnps %xmm9,%xmm2 + .byte 65,15,86,208 // orps %xmm8,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_from_2dot2_sse2 +.globl _sk_from_2dot2_sse2 +_sk_from_2dot2_sse2: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 65,15,82,192 // rsqrtps %xmm8,%xmm0 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 68,15,82,200 // rsqrtps %xmm0,%xmm9 + .byte 65,15,82,193 // rsqrtps %xmm9,%xmm0 + .byte 68,15,82,208 // rsqrtps %xmm0,%xmm10 + .byte 69,15,89,192 // mulps %xmm8,%xmm8 + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 15,89,192 // mulps %xmm0,%xmm0 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,89,194 // mulps %xmm10,%xmm0 + .byte 69,15,87,210 // xorps %xmm10,%xmm10 + .byte 65,15,95,194 // maxps %xmm10,%xmm0 + .byte 68,15,82,193 // rsqrtps %xmm1,%xmm8 + .byte 69,15,82,192 // rsqrtps %xmm8,%xmm8 + .byte 69,15,82,192 // rsqrtps %xmm8,%xmm8 + .byte 69,15,82,200 // rsqrtps %xmm8,%xmm9 + .byte 69,15,82,193 // rsqrtps %xmm9,%xmm8 + .byte 69,15,82,216 // rsqrtps %xmm8,%xmm11 + .byte 15,89,201 // mulps %xmm1,%xmm1 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 69,15,89,192 // mulps %xmm8,%xmm8 + .byte 69,15,89,193 // mulps %xmm9,%xmm8 + .byte 68,15,89,193 // mulps %xmm1,%xmm8 + .byte 69,15,89,195 // mulps %xmm11,%xmm8 + .byte 69,15,95,194 // maxps %xmm10,%xmm8 + .byte 15,82,202 // rsqrtps %xmm2,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 68,15,82,217 // rsqrtps %xmm1,%xmm11 + .byte 65,15,82,203 // rsqrtps %xmm11,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 15,89,210 // mulps %xmm2,%xmm2 + .byte 69,15,40,203 // movaps %xmm11,%xmm9 + .byte 69,15,89,201 // mulps %xmm9,%xmm9 + .byte 69,15,89,203 // mulps %xmm11,%xmm9 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 68,15,89,201 // mulps %xmm1,%xmm9 + .byte 69,15,95,202 // maxps %xmm10,%xmm9 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 65,15,40,209 // movaps %xmm9,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_to_2dot2_sse2 +.globl _sk_to_2dot2_sse2 +_sk_to_2dot2_sse2: + .byte 68,15,82,192 // rsqrtps %xmm0,%xmm8 + .byte 65,15,82,192 // rsqrtps %xmm8,%xmm0 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 15,82,192 // rsqrtps %xmm0,%xmm0 + .byte 68,15,82,200 // rsqrtps %xmm0,%xmm9 + .byte 69,15,83,192 // rcpps %xmm8,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 65,15,83,193 // rcpps %xmm9,%xmm0 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 65,15,95,192 // maxps %xmm8,%xmm0 + .byte 68,15,82,201 // rsqrtps %xmm1,%xmm9 + .byte 65,15,82,201 // rsqrtps %xmm9,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 15,82,201 // rsqrtps %xmm1,%xmm1 + .byte 68,15,82,209 // rsqrtps %xmm1,%xmm10 + .byte 69,15,83,201 // rcpps %xmm9,%xmm9 + .byte 68,15,89,201 // mulps %xmm1,%xmm9 + .byte 65,15,83,202 // rcpps %xmm10,%xmm1 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 65,15,95,200 // maxps %xmm8,%xmm1 + .byte 68,15,82,202 // rsqrtps %xmm2,%xmm9 + .byte 65,15,82,209 // rsqrtps %xmm9,%xmm2 + .byte 15,82,210 // rsqrtps %xmm2,%xmm2 + .byte 15,82,210 // rsqrtps %xmm2,%xmm2 + .byte 15,82,210 // rsqrtps %xmm2,%xmm2 + .byte 68,15,82,210 // rsqrtps %xmm2,%xmm10 + .byte 69,15,83,201 // rcpps %xmm9,%xmm9 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 65,15,83,210 // rcpps %xmm10,%xmm2 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 65,15,95,208 // maxps %xmm8,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_rgb_to_hsl_sse2 +.globl _sk_rgb_to_hsl_sse2 +_sk_rgb_to_hsl_sse2: + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 69,15,40,208 // movaps %xmm8,%xmm10 + .byte 69,15,95,209 // maxps %xmm9,%xmm10 + .byte 68,15,95,210 // maxps %xmm2,%xmm10 + .byte 69,15,40,216 // movaps %xmm8,%xmm11 + .byte 69,15,93,217 // minps %xmm9,%xmm11 + .byte 68,15,93,218 // minps %xmm2,%xmm11 + .byte 65,15,40,202 // movaps %xmm10,%xmm1 + .byte 65,15,92,203 // subps %xmm11,%xmm1 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,224 // movd %eax,%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 68,15,94,225 // divps %xmm1,%xmm12 + .byte 65,184,171,170,42,62 // mov $0x3e2aaaab,%r8d + .byte 65,15,40,194 // movaps %xmm10,%xmm0 + .byte 65,15,194,192,0 // cmpeqps %xmm8,%xmm0 + .byte 69,15,40,241 // movaps %xmm9,%xmm14 + .byte 68,15,194,242,1 // cmpltps %xmm2,%xmm14 + .byte 185,0,0,192,64 // mov $0x40c00000,%ecx + .byte 102,68,15,110,233 // movd %ecx,%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,84,238 // andps %xmm14,%xmm13 + .byte 69,15,40,241 // movaps %xmm9,%xmm14 + .byte 68,15,92,242 // subps %xmm2,%xmm14 + .byte 69,15,89,244 // mulps %xmm12,%xmm14 + .byte 69,15,88,238 // addps %xmm14,%xmm13 + .byte 69,15,40,242 // movaps %xmm10,%xmm14 + .byte 69,15,194,241,0 // cmpeqps %xmm9,%xmm14 + .byte 65,15,92,208 // subps %xmm8,%xmm2 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 65,15,89,212 // mulps %xmm12,%xmm2 + .byte 185,0,0,0,64 // mov $0x40000000,%ecx + .byte 69,15,89,196 // mulps %xmm12,%xmm8 + .byte 184,0,0,128,64 // mov $0x40800000,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 69,15,88,200 // addps %xmm8,%xmm9 + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,88,208 // addps %xmm8,%xmm2 + .byte 65,15,84,214 // andps %xmm14,%xmm2 + .byte 69,15,85,241 // andnps %xmm9,%xmm14 + .byte 68,15,86,242 // orps %xmm2,%xmm14 + .byte 68,15,84,232 // andps %xmm0,%xmm13 + .byte 65,15,85,198 // andnps %xmm14,%xmm0 + .byte 102,65,15,110,208 // movd %r8d,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 65,15,86,197 // orps %xmm13,%xmm0 + .byte 69,15,40,202 // movaps %xmm10,%xmm9 + .byte 69,15,194,203,4 // cmpneqps %xmm11,%xmm9 + .byte 65,15,84,193 // andps %xmm9,%xmm0 + .byte 15,89,194 // mulps %xmm2,%xmm0 + .byte 69,15,92,194 // subps %xmm10,%xmm8 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 184,0,0,0,63 // mov $0x3f000000,%eax + .byte 102,68,15,110,224 // movd %eax,%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 69,15,92,195 // subps %xmm11,%xmm8 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 65,15,89,212 // mulps %xmm12,%xmm2 + .byte 68,15,194,226,1 // cmpltps %xmm2,%xmm12 + .byte 69,15,84,196 // andps %xmm12,%xmm8 + .byte 69,15,85,226 // andnps %xmm10,%xmm12 + .byte 69,15,86,224 // orps %xmm8,%xmm12 + .byte 65,15,94,204 // divps %xmm12,%xmm1 + .byte 65,15,84,201 // andps %xmm9,%xmm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_hsl_to_rgb_sse2 +.globl _sk_hsl_to_rgb_sse2 +_sk_hsl_to_rgb_sse2: + .byte 15,41,124,36,232 // movaps %xmm7,-0x18(%rsp) + .byte 15,41,116,36,216 // movaps %xmm6,-0x28(%rsp) + .byte 15,41,108,36,200 // movaps %xmm5,-0x38(%rsp) + .byte 15,41,100,36,184 // movaps %xmm4,-0x48(%rsp) + .byte 15,41,92,36,168 // movaps %xmm3,-0x58(%rsp) + .byte 68,15,40,210 // movaps %xmm2,%xmm10 + .byte 15,40,209 // movaps %xmm1,%xmm2 + .byte 15,40,240 // movaps %xmm0,%xmm6 + .byte 184,0,0,0,63 // mov $0x3f000000,%eax + .byte 102,68,15,110,240 // movd %eax,%xmm14 + .byte 69,15,198,246,0 // shufps $0x0,%xmm14,%xmm14 + .byte 69,15,40,202 // movaps %xmm10,%xmm9 + .byte 69,15,194,206,1 // cmpltps %xmm14,%xmm9 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,224 // movd %eax,%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 65,15,40,196 // movaps %xmm12,%xmm0 + .byte 15,88,194 // addps %xmm2,%xmm0 + .byte 65,15,89,194 // mulps %xmm10,%xmm0 + .byte 15,40,218 // movaps %xmm2,%xmm3 + .byte 69,15,87,219 // xorps %xmm11,%xmm11 + .byte 68,15,194,218,0 // cmpeqps %xmm2,%xmm11 + .byte 65,15,88,210 // addps %xmm10,%xmm2 + .byte 65,15,89,218 // mulps %xmm10,%xmm3 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 65,15,84,193 // andps %xmm9,%xmm0 + .byte 68,15,85,202 // andnps %xmm2,%xmm9 + .byte 68,15,86,200 // orps %xmm0,%xmm9 + .byte 184,0,0,0,64 // mov $0x40000000,%eax + .byte 185,171,170,170,62 // mov $0x3eaaaaab,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,41,68,36,152 // movaps %xmm8,-0x68(%rsp) + .byte 68,15,88,198 // addps %xmm6,%xmm8 + .byte 185,0,0,0,0 // mov $0x0,%ecx + .byte 102,15,110,233 // movd %ecx,%xmm5 + .byte 15,198,237,0 // shufps $0x0,%xmm5,%xmm5 + .byte 65,15,40,196 // movaps %xmm12,%xmm0 + .byte 65,15,194,192,1 // cmpltps %xmm8,%xmm0 + .byte 65,15,40,216 // movaps %xmm8,%xmm3 + .byte 65,15,92,220 // subps %xmm12,%xmm3 + .byte 15,84,216 // andps %xmm0,%xmm3 + .byte 65,15,85,192 // andnps %xmm8,%xmm0 + .byte 15,86,195 // orps %xmm3,%xmm0 + .byte 65,15,40,216 // movaps %xmm8,%xmm3 + .byte 15,194,221,1 // cmpltps %xmm5,%xmm3 + .byte 65,15,40,212 // movaps %xmm12,%xmm2 + .byte 65,15,88,208 // addps %xmm8,%xmm2 + .byte 15,84,211 // andps %xmm3,%xmm2 + .byte 15,85,216 // andnps %xmm0,%xmm3 + .byte 15,86,218 // orps %xmm2,%xmm3 + .byte 102,68,15,110,232 // movd %eax,%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,89,234 // mulps %xmm10,%xmm13 + .byte 69,15,92,233 // subps %xmm9,%xmm13 + .byte 184,171,170,42,62 // mov $0x3e2aaaab,%eax + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 65,15,92,197 // subps %xmm13,%xmm0 + .byte 185,0,0,192,64 // mov $0x40c00000,%ecx + .byte 102,68,15,110,249 // movd %ecx,%xmm15 + .byte 69,15,198,255,0 // shufps $0x0,%xmm15,%xmm15 + .byte 68,15,89,248 // mulps %xmm0,%xmm15 + .byte 185,171,170,42,63 // mov $0x3f2aaaab,%ecx + .byte 102,15,110,225 // movd %ecx,%xmm4 + .byte 15,198,228,0 // shufps $0x0,%xmm4,%xmm4 + .byte 15,40,212 // movaps %xmm4,%xmm2 + .byte 15,92,211 // subps %xmm3,%xmm2 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 15,40,195 // movaps %xmm3,%xmm0 + .byte 15,194,220,1 // cmpltps %xmm4,%xmm3 + .byte 65,15,89,215 // mulps %xmm15,%xmm2 + .byte 65,15,88,213 // addps %xmm13,%xmm2 + .byte 15,84,211 // andps %xmm3,%xmm2 + .byte 65,15,85,221 // andnps %xmm13,%xmm3 + .byte 15,86,218 // orps %xmm2,%xmm3 + .byte 65,15,194,198,1 // cmpltps %xmm14,%xmm0 + .byte 65,15,40,209 // movaps %xmm9,%xmm2 + .byte 15,84,208 // andps %xmm0,%xmm2 + .byte 15,85,195 // andnps %xmm3,%xmm0 + .byte 15,86,194 // orps %xmm2,%xmm0 + .byte 102,15,110,248 // movd %eax,%xmm7 + .byte 15,198,255,0 // shufps $0x0,%xmm7,%xmm7 + .byte 15,194,207,1 // cmpltps %xmm7,%xmm1 + .byte 69,15,89,199 // mulps %xmm15,%xmm8 + .byte 69,15,88,197 // addps %xmm13,%xmm8 + .byte 68,15,84,193 // andps %xmm1,%xmm8 + .byte 15,85,200 // andnps %xmm0,%xmm1 + .byte 65,15,86,200 // orps %xmm8,%xmm1 + .byte 69,15,40,195 // movaps %xmm11,%xmm8 + .byte 68,15,85,193 // andnps %xmm1,%xmm8 + .byte 65,15,40,196 // movaps %xmm12,%xmm0 + .byte 15,194,198,1 // cmpltps %xmm6,%xmm0 + .byte 15,40,206 // movaps %xmm6,%xmm1 + .byte 65,15,92,204 // subps %xmm12,%xmm1 + .byte 15,84,200 // andps %xmm0,%xmm1 + .byte 15,85,198 // andnps %xmm6,%xmm0 + .byte 15,86,193 // orps %xmm1,%xmm0 + .byte 15,40,206 // movaps %xmm6,%xmm1 + .byte 15,194,205,1 // cmpltps %xmm5,%xmm1 + .byte 65,15,40,212 // movaps %xmm12,%xmm2 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 15,84,209 // andps %xmm1,%xmm2 + .byte 15,85,200 // andnps %xmm0,%xmm1 + .byte 15,86,202 // orps %xmm2,%xmm1 + .byte 15,40,196 // movaps %xmm4,%xmm0 + .byte 15,92,193 // subps %xmm1,%xmm0 + .byte 15,40,217 // movaps %xmm1,%xmm3 + .byte 15,40,209 // movaps %xmm1,%xmm2 + .byte 15,194,204,1 // cmpltps %xmm4,%xmm1 + .byte 65,15,89,199 // mulps %xmm15,%xmm0 + .byte 65,15,88,197 // addps %xmm13,%xmm0 + .byte 15,84,193 // andps %xmm1,%xmm0 + .byte 65,15,85,205 // andnps %xmm13,%xmm1 + .byte 15,86,200 // orps %xmm0,%xmm1 + .byte 65,15,194,214,1 // cmpltps %xmm14,%xmm2 + .byte 65,15,40,193 // movaps %xmm9,%xmm0 + .byte 15,84,194 // andps %xmm2,%xmm0 + .byte 15,85,209 // andnps %xmm1,%xmm2 + .byte 15,86,208 // orps %xmm0,%xmm2 + .byte 15,194,223,1 // cmpltps %xmm7,%xmm3 + .byte 65,15,40,199 // movaps %xmm15,%xmm0 + .byte 15,89,198 // mulps %xmm6,%xmm0 + .byte 65,15,88,197 // addps %xmm13,%xmm0 + .byte 15,84,195 // andps %xmm3,%xmm0 + .byte 15,85,218 // andnps %xmm2,%xmm3 + .byte 15,86,216 // orps %xmm0,%xmm3 + .byte 65,15,40,203 // movaps %xmm11,%xmm1 + .byte 15,85,203 // andnps %xmm3,%xmm1 + .byte 15,92,116,36,152 // subps -0x68(%rsp),%xmm6 + .byte 15,40,198 // movaps %xmm6,%xmm0 + .byte 15,194,197,1 // cmpltps %xmm5,%xmm0 + .byte 15,40,214 // movaps %xmm6,%xmm2 + .byte 65,15,92,212 // subps %xmm12,%xmm2 + .byte 65,15,40,220 // movaps %xmm12,%xmm3 + .byte 68,15,194,230,1 // cmpltps %xmm6,%xmm12 + .byte 65,15,84,212 // andps %xmm12,%xmm2 + .byte 68,15,85,230 // andnps %xmm6,%xmm12 + .byte 68,15,86,226 // orps %xmm2,%xmm12 + .byte 15,88,222 // addps %xmm6,%xmm3 + .byte 15,84,216 // andps %xmm0,%xmm3 + .byte 65,15,85,196 // andnps %xmm12,%xmm0 + .byte 15,86,195 // orps %xmm3,%xmm0 + .byte 15,40,232 // movaps %xmm0,%xmm5 + .byte 15,194,239,1 // cmpltps %xmm7,%xmm5 + .byte 15,40,208 // movaps %xmm0,%xmm2 + .byte 15,194,212,1 // cmpltps %xmm4,%xmm2 + .byte 15,92,224 // subps %xmm0,%xmm4 + .byte 65,15,194,198,1 // cmpltps %xmm14,%xmm0 + .byte 65,15,89,247 // mulps %xmm15,%xmm6 + .byte 65,15,89,231 // mulps %xmm15,%xmm4 + .byte 65,15,88,245 // addps %xmm13,%xmm6 + .byte 65,15,88,229 // addps %xmm13,%xmm4 + .byte 15,84,226 // andps %xmm2,%xmm4 + .byte 65,15,85,213 // andnps %xmm13,%xmm2 + .byte 15,86,212 // orps %xmm4,%xmm2 + .byte 68,15,84,200 // andps %xmm0,%xmm9 + .byte 15,85,194 // andnps %xmm2,%xmm0 + .byte 65,15,86,193 // orps %xmm9,%xmm0 + .byte 15,84,245 // andps %xmm5,%xmm6 + .byte 15,85,232 // andnps %xmm0,%xmm5 + .byte 15,86,238 // orps %xmm6,%xmm5 + .byte 69,15,84,211 // andps %xmm11,%xmm10 + .byte 68,15,85,221 // andnps %xmm5,%xmm11 + .byte 69,15,86,194 // orps %xmm10,%xmm8 + .byte 65,15,86,202 // orps %xmm10,%xmm1 + .byte 69,15,86,211 // orps %xmm11,%xmm10 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 15,40,92,36,168 // movaps -0x58(%rsp),%xmm3 + .byte 15,40,100,36,184 // movaps -0x48(%rsp),%xmm4 + .byte 15,40,108,36,200 // movaps -0x38(%rsp),%xmm5 + .byte 15,40,116,36,216 // movaps -0x28(%rsp),%xmm6 + .byte 15,40,124,36,232 // movaps -0x18(%rsp),%xmm7 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_scale_1_float_sse2 +.globl _sk_scale_1_float_sse2 +_sk_scale_1_float_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,0 // movss (%rax),%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_scale_u8_sse2 +.globl _sk_scale_u8_sse2 +_sk_scale_u8_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,68,15,110,4,56 // movd (%rax,%rdi,1),%xmm8 + .byte 102,69,15,239,201 // pxor %xmm9,%xmm9 + .byte 102,69,15,96,193 // punpcklbw %xmm9,%xmm8 + .byte 102,69,15,97,193 // punpcklwd %xmm9,%xmm8 + .byte 69,15,91,192 // cvtdq2ps %xmm8,%xmm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 65,15,89,217 // mulps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lerp_1_float_sse2 +.globl _sk_lerp_1_float_sse2 +_sk_lerp_1_float_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,0 // movss (%rax),%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,92,196 // subps %xmm4,%xmm0 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 15,92,205 // subps %xmm5,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 15,92,214 // subps %xmm6,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 15,92,223 // subps %xmm7,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 15,88,223 // addps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lerp_u8_sse2 +.globl _sk_lerp_u8_sse2 +_sk_lerp_u8_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,68,15,110,4,56 // movd (%rax,%rdi,1),%xmm8 + .byte 102,69,15,239,201 // pxor %xmm9,%xmm9 + .byte 102,69,15,96,193 // punpcklbw %xmm9,%xmm8 + .byte 102,69,15,97,193 // punpcklwd %xmm9,%xmm8 + .byte 69,15,91,192 // cvtdq2ps %xmm8,%xmm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,68,15,110,200 // movd %eax,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 15,92,196 // subps %xmm4,%xmm0 + .byte 65,15,89,193 // mulps %xmm9,%xmm0 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 15,92,205 // subps %xmm5,%xmm1 + .byte 65,15,89,201 // mulps %xmm9,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 15,92,214 // subps %xmm6,%xmm2 + .byte 65,15,89,209 // mulps %xmm9,%xmm2 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 15,92,223 // subps %xmm7,%xmm3 + .byte 65,15,89,217 // mulps %xmm9,%xmm3 + .byte 15,88,223 // addps %xmm7,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_lerp_565_sse2 +.globl _sk_lerp_565_sse2 +_sk_lerp_565_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 243,68,15,126,4,120 // movq (%rax,%rdi,2),%xmm8 + .byte 102,15,239,219 // pxor %xmm3,%xmm3 + .byte 102,68,15,97,195 // punpcklwd %xmm3,%xmm8 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,65,15,219,216 // pand %xmm8,%xmm3 + .byte 68,15,91,203 // cvtdq2ps %xmm3,%xmm9 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 102,68,15,110,208 // movd %eax,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,65,15,219,216 // pand %xmm8,%xmm3 + .byte 68,15,91,203 // cvtdq2ps %xmm3,%xmm9 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 102,68,15,110,216 // movd %eax,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,217 // mulps %xmm9,%xmm11 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,65,15,219,216 // pand %xmm8,%xmm3 + .byte 68,15,91,195 // cvtdq2ps %xmm3,%xmm8 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 15,92,196 // subps %xmm4,%xmm0 + .byte 65,15,89,194 // mulps %xmm10,%xmm0 + .byte 15,88,196 // addps %xmm4,%xmm0 + .byte 15,92,205 // subps %xmm5,%xmm1 + .byte 65,15,89,203 // mulps %xmm11,%xmm1 + .byte 15,88,205 // addps %xmm5,%xmm1 + .byte 15,92,214 // subps %xmm6,%xmm2 + .byte 15,89,211 // mulps %xmm3,%xmm2 + .byte 15,88,214 // addps %xmm6,%xmm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_tables_sse2 +.globl _sk_load_tables_sse2 +_sk_load_tables_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,8 // mov (%rax),%rcx + .byte 76,139,64,8 // mov 0x8(%rax),%r8 + .byte 243,68,15,111,4,185 // movdqu (%rcx,%rdi,4),%xmm8 + .byte 185,255,0,0,0 // mov $0xff,%ecx + .byte 102,15,110,193 // movd %ecx,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,69,15,111,200 // movdqa %xmm8,%xmm9 + .byte 102,65,15,114,209,8 // psrld $0x8,%xmm9 + .byte 102,68,15,219,200 // pand %xmm0,%xmm9 + .byte 102,69,15,111,208 // movdqa %xmm8,%xmm10 + .byte 102,65,15,114,210,16 // psrld $0x10,%xmm10 + .byte 102,68,15,219,208 // pand %xmm0,%xmm10 + .byte 102,65,15,219,192 // pand %xmm8,%xmm0 + .byte 102,15,112,216,78 // pshufd $0x4e,%xmm0,%xmm3 + .byte 102,72,15,126,217 // movq %xmm3,%rcx + .byte 65,137,201 // mov %ecx,%r9d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,73,15,126,194 // movq %xmm0,%r10 + .byte 69,137,211 // mov %r10d,%r11d + .byte 73,193,234,32 // shr $0x20,%r10 + .byte 243,67,15,16,28,144 // movss (%r8,%r10,4),%xmm3 + .byte 243,65,15,16,4,136 // movss (%r8,%rcx,4),%xmm0 + .byte 15,20,216 // unpcklps %xmm0,%xmm3 + .byte 243,67,15,16,4,152 // movss (%r8,%r11,4),%xmm0 + .byte 243,67,15,16,12,136 // movss (%r8,%r9,4),%xmm1 + .byte 15,20,193 // unpcklps %xmm1,%xmm0 + .byte 15,20,195 // unpcklps %xmm3,%xmm0 + .byte 76,139,64,16 // mov 0x10(%rax),%r8 + .byte 102,65,15,112,201,78 // pshufd $0x4e,%xmm9,%xmm1 + .byte 102,73,15,126,202 // movq %xmm1,%r10 + .byte 77,137,209 // mov %r10,%r9 + .byte 73,193,233,32 // shr $0x20,%r9 + .byte 102,76,15,126,201 // movq %xmm9,%rcx + .byte 65,137,203 // mov %ecx,%r11d + .byte 65,129,227,255,255,255,0 // and $0xffffff,%r11d + .byte 72,193,233,30 // shr $0x1e,%rcx + .byte 65,129,226,255,255,255,0 // and $0xffffff,%r10d + .byte 243,65,15,16,28,8 // movss (%r8,%rcx,1),%xmm3 + .byte 243,67,15,16,12,136 // movss (%r8,%r9,4),%xmm1 + .byte 15,20,217 // unpcklps %xmm1,%xmm3 + .byte 243,67,15,16,12,152 // movss (%r8,%r11,4),%xmm1 + .byte 243,67,15,16,20,144 // movss (%r8,%r10,4),%xmm2 + .byte 15,20,202 // unpcklps %xmm2,%xmm1 + .byte 15,20,203 // unpcklps %xmm3,%xmm1 + .byte 76,139,72,24 // mov 0x18(%rax),%r9 + .byte 102,65,15,112,210,78 // pshufd $0x4e,%xmm10,%xmm2 + .byte 102,72,15,126,209 // movq %xmm2,%rcx + .byte 68,15,183,193 // movzwl %cx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,76,15,126,208 // movq %xmm10,%rax + .byte 68,15,183,208 // movzwl %ax,%r10d + .byte 72,193,232,30 // shr $0x1e,%rax + .byte 243,69,15,16,12,1 // movss (%r9,%rax,1),%xmm9 + .byte 243,65,15,16,20,137 // movss (%r9,%rcx,4),%xmm2 + .byte 68,15,20,202 // unpcklps %xmm2,%xmm9 + .byte 243,67,15,16,20,145 // movss (%r9,%r10,4),%xmm2 + .byte 243,67,15,16,28,129 // movss (%r9,%r8,4),%xmm3 + .byte 15,20,211 // unpcklps %xmm3,%xmm2 + .byte 65,15,20,209 // unpcklps %xmm9,%xmm2 + .byte 102,65,15,114,208,24 // psrld $0x18,%xmm8 + .byte 69,15,91,192 // cvtdq2ps %xmm8,%xmm8 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_byte_tables_sse2 +.globl _sk_byte_tables_sse2 +_sk_byte_tables_sse2: + .byte 65,86 // push %r14 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,127,67 // mov $0x437f0000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 102,15,91,192 // cvtps2dq %xmm0,%xmm0 + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,15,112,192,78 // pshufd $0x4e,%xmm0,%xmm0 + .byte 102,73,15,126,193 // movq %xmm0,%r9 + .byte 69,137,202 // mov %r9d,%r10d + .byte 77,137,203 // mov %r9,%r11 + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 76,139,48 // mov (%rax),%r14 + .byte 76,139,72,8 // mov 0x8(%rax),%r9 + .byte 71,15,182,20,22 // movzbl (%r14,%r10,1),%r10d + .byte 67,15,182,28,30 // movzbl (%r14,%r11,1),%ebx + .byte 193,227,8 // shl $0x8,%ebx + .byte 68,9,211 // or %r10d,%ebx + .byte 71,15,182,4,6 // movzbl (%r14,%r8,1),%r8d + .byte 65,15,182,12,14 // movzbl (%r14,%rcx,1),%ecx + .byte 193,225,8 // shl $0x8,%ecx + .byte 68,9,193 // or %r8d,%ecx + .byte 102,15,196,193,0 // pinsrw $0x0,%ecx,%xmm0 + .byte 102,15,196,195,1 // pinsrw $0x1,%ebx,%xmm0 + .byte 102,69,15,239,201 // pxor %xmm9,%xmm9 + .byte 102,65,15,96,193 // punpcklbw %xmm9,%xmm0 + .byte 102,65,15,97,193 // punpcklwd %xmm9,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 185,129,128,128,59 // mov $0x3b808081,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 65,15,89,194 // mulps %xmm10,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 102,15,91,201 // cvtps2dq %xmm1,%xmm1 + .byte 102,72,15,126,201 // movq %xmm1,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,15,112,201,78 // pshufd $0x4e,%xmm1,%xmm1 + .byte 102,72,15,126,203 // movq %xmm1,%rbx + .byte 65,137,218 // mov %ebx,%r10d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 71,15,182,20,17 // movzbl (%r9,%r10,1),%r10d + .byte 65,15,182,28,25 // movzbl (%r9,%rbx,1),%ebx + .byte 193,227,8 // shl $0x8,%ebx + .byte 68,9,211 // or %r10d,%ebx + .byte 71,15,182,4,1 // movzbl (%r9,%r8,1),%r8d + .byte 65,15,182,12,9 // movzbl (%r9,%rcx,1),%ecx + .byte 193,225,8 // shl $0x8,%ecx + .byte 68,9,193 // or %r8d,%ecx + .byte 102,15,196,201,0 // pinsrw $0x0,%ecx,%xmm1 + .byte 102,15,196,203,1 // pinsrw $0x1,%ebx,%xmm1 + .byte 102,65,15,96,201 // punpcklbw %xmm9,%xmm1 + .byte 102,65,15,97,201 // punpcklwd %xmm9,%xmm1 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,202 // mulps %xmm10,%xmm1 + .byte 76,139,72,16 // mov 0x10(%rax),%r9 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,15,91,210 // cvtps2dq %xmm2,%xmm2 + .byte 102,72,15,126,211 // movq %xmm2,%rbx + .byte 65,137,216 // mov %ebx,%r8d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 102,15,112,210,78 // pshufd $0x4e,%xmm2,%xmm2 + .byte 102,72,15,126,209 // movq %xmm2,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 71,15,182,20,17 // movzbl (%r9,%r10,1),%r10d + .byte 65,15,182,12,9 // movzbl (%r9,%rcx,1),%ecx + .byte 193,225,8 // shl $0x8,%ecx + .byte 68,9,209 // or %r10d,%ecx + .byte 71,15,182,4,1 // movzbl (%r9,%r8,1),%r8d + .byte 65,15,182,28,25 // movzbl (%r9,%rbx,1),%ebx + .byte 193,227,8 // shl $0x8,%ebx + .byte 68,9,195 // or %r8d,%ebx + .byte 102,15,196,211,0 // pinsrw $0x0,%ebx,%xmm2 + .byte 102,15,196,209,1 // pinsrw $0x1,%ecx,%xmm2 + .byte 102,65,15,96,209 // punpcklbw %xmm9,%xmm2 + .byte 102,65,15,97,209 // punpcklwd %xmm9,%xmm2 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,210 // mulps %xmm10,%xmm2 + .byte 72,139,64,24 // mov 0x18(%rax),%rax + .byte 68,15,89,195 // mulps %xmm3,%xmm8 + .byte 102,65,15,91,216 // cvtps2dq %xmm8,%xmm3 + .byte 102,72,15,126,217 // movq %xmm3,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,15,112,219,78 // pshufd $0x4e,%xmm3,%xmm3 + .byte 102,72,15,126,219 // movq %xmm3,%rbx + .byte 65,137,217 // mov %ebx,%r9d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 70,15,182,12,8 // movzbl (%rax,%r9,1),%r9d + .byte 15,182,28,24 // movzbl (%rax,%rbx,1),%ebx + .byte 193,227,8 // shl $0x8,%ebx + .byte 68,9,203 // or %r9d,%ebx + .byte 70,15,182,4,0 // movzbl (%rax,%r8,1),%r8d + .byte 15,182,4,8 // movzbl (%rax,%rcx,1),%eax + .byte 193,224,8 // shl $0x8,%eax + .byte 68,9,192 // or %r8d,%eax + .byte 102,15,196,216,0 // pinsrw $0x0,%eax,%xmm3 + .byte 102,15,196,219,1 // pinsrw $0x1,%ebx,%xmm3 + .byte 102,65,15,96,217 // punpcklbw %xmm9,%xmm3 + .byte 102,65,15,97,217 // punpcklwd %xmm9,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 65,15,89,218 // mulps %xmm10,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,94 // pop %r14 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_byte_tables_rgb_sse2 +.globl _sk_byte_tables_rgb_sse2 +_sk_byte_tables_rgb_sse2: + .byte 65,86 // push %r14 + .byte 83 // push %rbx + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 139,72,24 // mov 0x18(%rax),%ecx + .byte 255,201 // dec %ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 102,69,15,112,192,0 // pshufd $0x0,%xmm8,%xmm8 + .byte 69,15,91,192 // cvtdq2ps %xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 102,15,91,192 // cvtps2dq %xmm0,%xmm0 + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,15,112,192,78 // pshufd $0x4e,%xmm0,%xmm0 + .byte 102,73,15,126,193 // movq %xmm0,%r9 + .byte 69,137,202 // mov %r9d,%r10d + .byte 77,137,203 // mov %r9,%r11 + .byte 73,193,235,32 // shr $0x20,%r11 + .byte 76,139,48 // mov (%rax),%r14 + .byte 76,139,72,8 // mov 0x8(%rax),%r9 + .byte 71,15,182,20,22 // movzbl (%r14,%r10,1),%r10d + .byte 67,15,182,28,30 // movzbl (%r14,%r11,1),%ebx + .byte 193,227,8 // shl $0x8,%ebx + .byte 68,9,211 // or %r10d,%ebx + .byte 71,15,182,4,6 // movzbl (%r14,%r8,1),%r8d + .byte 65,15,182,12,14 // movzbl (%r14,%rcx,1),%ecx + .byte 193,225,8 // shl $0x8,%ecx + .byte 68,9,193 // or %r8d,%ecx + .byte 102,15,196,193,0 // pinsrw $0x0,%ecx,%xmm0 + .byte 102,15,196,195,1 // pinsrw $0x1,%ebx,%xmm0 + .byte 102,69,15,239,201 // pxor %xmm9,%xmm9 + .byte 102,65,15,96,193 // punpcklbw %xmm9,%xmm0 + .byte 102,65,15,97,193 // punpcklwd %xmm9,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 185,129,128,128,59 // mov $0x3b808081,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 65,15,89,194 // mulps %xmm10,%xmm0 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 102,15,91,201 // cvtps2dq %xmm1,%xmm1 + .byte 102,72,15,126,201 // movq %xmm1,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,15,112,201,78 // pshufd $0x4e,%xmm1,%xmm1 + .byte 102,72,15,126,203 // movq %xmm1,%rbx + .byte 65,137,218 // mov %ebx,%r10d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 71,15,182,20,17 // movzbl (%r9,%r10,1),%r10d + .byte 65,15,182,28,25 // movzbl (%r9,%rbx,1),%ebx + .byte 193,227,8 // shl $0x8,%ebx + .byte 68,9,211 // or %r10d,%ebx + .byte 71,15,182,4,1 // movzbl (%r9,%r8,1),%r8d + .byte 65,15,182,12,9 // movzbl (%r9,%rcx,1),%ecx + .byte 193,225,8 // shl $0x8,%ecx + .byte 68,9,193 // or %r8d,%ecx + .byte 102,15,196,201,0 // pinsrw $0x0,%ecx,%xmm1 + .byte 102,15,196,203,1 // pinsrw $0x1,%ebx,%xmm1 + .byte 102,65,15,96,201 // punpcklbw %xmm9,%xmm1 + .byte 102,65,15,97,201 // punpcklwd %xmm9,%xmm1 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,202 // mulps %xmm10,%xmm1 + .byte 72,139,64,16 // mov 0x10(%rax),%rax + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,15,91,210 // cvtps2dq %xmm2,%xmm2 + .byte 102,72,15,126,209 // movq %xmm2,%rcx + .byte 65,137,200 // mov %ecx,%r8d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,15,112,210,78 // pshufd $0x4e,%xmm2,%xmm2 + .byte 102,72,15,126,211 // movq %xmm2,%rbx + .byte 65,137,217 // mov %ebx,%r9d + .byte 72,193,235,32 // shr $0x20,%rbx + .byte 70,15,182,12,8 // movzbl (%rax,%r9,1),%r9d + .byte 15,182,28,24 // movzbl (%rax,%rbx,1),%ebx + .byte 193,227,8 // shl $0x8,%ebx + .byte 68,9,203 // or %r9d,%ebx + .byte 70,15,182,4,0 // movzbl (%rax,%r8,1),%r8d + .byte 15,182,4,8 // movzbl (%rax,%rcx,1),%eax + .byte 193,224,8 // shl $0x8,%eax + .byte 68,9,192 // or %r8d,%eax + .byte 102,15,196,208,0 // pinsrw $0x0,%eax,%xmm2 + .byte 102,15,196,211,1 // pinsrw $0x1,%ebx,%xmm2 + .byte 102,65,15,96,209 // punpcklbw %xmm9,%xmm2 + .byte 102,65,15,97,209 // punpcklwd %xmm9,%xmm2 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,210 // mulps %xmm10,%xmm2 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 91 // pop %rbx + .byte 65,94 // pop %r14 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_a8_sse2 +.globl _sk_load_a8_sse2 +_sk_load_a8_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,15,110,4,56 // movd (%rax,%rdi,1),%xmm0 + .byte 102,15,239,201 // pxor %xmm1,%xmm1 + .byte 102,15,96,193 // punpcklbw %xmm1,%xmm0 + .byte 102,15,97,193 // punpcklwd %xmm1,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 15,89,216 // mulps %xmm0,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,87,192 // xorps %xmm0,%xmm0 + .byte 102,15,239,201 // pxor %xmm1,%xmm1 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_a8_sse2 +.globl _sk_gather_a8_sse2 +_sk_gather_a8_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,112,217,245 // pshufd $0xf5,%xmm1,%xmm3 + .byte 102,15,244,218 // pmuludq %xmm2,%xmm3 + .byte 102,15,112,219,232 // pshufd $0xe8,%xmm3,%xmm3 + .byte 102,15,244,209 // pmuludq %xmm1,%xmm2 + .byte 102,15,112,202,232 // pshufd $0xe8,%xmm2,%xmm1 + .byte 102,15,98,203 // punpckldq %xmm3,%xmm1 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,193 // paddd %xmm1,%xmm0 + .byte 102,72,15,126,192 // movq %xmm0,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,15,112,192,78 // pshufd $0x4e,%xmm0,%xmm0 + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 71,15,182,20,17 // movzbl (%r9,%r10,1),%r10d + .byte 65,15,182,12,9 // movzbl (%r9,%rcx,1),%ecx + .byte 193,225,8 // shl $0x8,%ecx + .byte 68,9,209 // or %r10d,%ecx + .byte 71,15,182,4,1 // movzbl (%r9,%r8,1),%r8d + .byte 65,15,182,4,1 // movzbl (%r9,%rax,1),%eax + .byte 193,224,8 // shl $0x8,%eax + .byte 68,9,192 // or %r8d,%eax + .byte 102,15,196,192,0 // pinsrw $0x0,%eax,%xmm0 + .byte 102,15,196,193,1 // pinsrw $0x1,%ecx,%xmm0 + .byte 102,15,239,201 // pxor %xmm1,%xmm1 + .byte 102,15,96,193 // punpcklbw %xmm1,%xmm0 + .byte 102,15,97,193 // punpcklwd %xmm1,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 15,89,216 // mulps %xmm0,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,87,192 // xorps %xmm0,%xmm0 + .byte 102,15,239,201 // pxor %xmm1,%xmm1 + .byte 102,15,239,210 // pxor %xmm2,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_a8_sse2 +.globl _sk_store_a8_sse2 +_sk_store_a8_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,0,127,67 // mov $0x437f0000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,89,195 // mulps %xmm3,%xmm8 + .byte 102,69,15,91,192 // cvtps2dq %xmm8,%xmm8 + .byte 102,65,15,114,240,16 // pslld $0x10,%xmm8 + .byte 102,65,15,114,224,16 // psrad $0x10,%xmm8 + .byte 102,69,15,107,192 // packssdw %xmm8,%xmm8 + .byte 102,69,15,103,192 // packuswb %xmm8,%xmm8 + .byte 102,68,15,126,4,56 // movd %xmm8,(%rax,%rdi,1) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_g8_sse2 +.globl _sk_load_g8_sse2 +_sk_load_g8_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 102,15,110,4,56 // movd (%rax,%rdi,1),%xmm0 + .byte 102,15,239,201 // pxor %xmm1,%xmm1 + .byte 102,15,96,193 // punpcklbw %xmm1,%xmm0 + .byte 102,15,97,193 // punpcklwd %xmm1,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,200 // movaps %xmm0,%xmm1 + .byte 15,40,208 // movaps %xmm0,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_g8_sse2 +.globl _sk_gather_g8_sse2 +_sk_gather_g8_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,112,217,245 // pshufd $0xf5,%xmm1,%xmm3 + .byte 102,15,244,218 // pmuludq %xmm2,%xmm3 + .byte 102,15,112,219,232 // pshufd $0xe8,%xmm3,%xmm3 + .byte 102,15,244,209 // pmuludq %xmm1,%xmm2 + .byte 102,15,112,202,232 // pshufd $0xe8,%xmm2,%xmm1 + .byte 102,15,98,203 // punpckldq %xmm3,%xmm1 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,193 // paddd %xmm1,%xmm0 + .byte 102,72,15,126,192 // movq %xmm0,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,15,112,192,78 // pshufd $0x4e,%xmm0,%xmm0 + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 71,15,182,20,17 // movzbl (%r9,%r10,1),%r10d + .byte 65,15,182,12,9 // movzbl (%r9,%rcx,1),%ecx + .byte 193,225,8 // shl $0x8,%ecx + .byte 68,9,209 // or %r10d,%ecx + .byte 71,15,182,4,1 // movzbl (%r9,%r8,1),%r8d + .byte 65,15,182,4,1 // movzbl (%r9,%rax,1),%eax + .byte 193,224,8 // shl $0x8,%eax + .byte 68,9,192 // or %r8d,%eax + .byte 102,15,196,192,0 // pinsrw $0x0,%eax,%xmm0 + .byte 102,15,196,193,1 // pinsrw $0x1,%ecx,%xmm0 + .byte 102,15,239,201 // pxor %xmm1,%xmm1 + .byte 102,15,96,193 // punpcklbw %xmm1,%xmm0 + .byte 102,15,97,193 // punpcklwd %xmm1,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,40,200 // movaps %xmm0,%xmm1 + .byte 15,40,208 // movaps %xmm0,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_i8_sse2 +.globl _sk_gather_i8_sse2 +_sk_gather_i8_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 73,137,192 // mov %rax,%r8 + .byte 77,133,192 // test %r8,%r8 + .byte 116,5 // je 1d75 <_sk_gather_i8_sse2+0xf> + .byte 76,137,192 // mov %r8,%rax + .byte 235,2 // jmp 1d77 <_sk_gather_i8_sse2+0x11> + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,16 // mov (%rax),%r10 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,112,217,245 // pshufd $0xf5,%xmm1,%xmm3 + .byte 102,15,244,218 // pmuludq %xmm2,%xmm3 + .byte 102,15,112,219,232 // pshufd $0xe8,%xmm3,%xmm3 + .byte 102,15,244,209 // pmuludq %xmm1,%xmm2 + .byte 102,15,112,202,232 // pshufd $0xe8,%xmm2,%xmm1 + .byte 102,15,98,203 // punpckldq %xmm3,%xmm1 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,193 // paddd %xmm1,%xmm0 + .byte 102,72,15,126,192 // movq %xmm0,%rax + .byte 65,137,193 // mov %eax,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,15,112,192,78 // pshufd $0x4e,%xmm0,%xmm0 + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,203 // mov %ecx,%r11d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 71,15,182,28,26 // movzbl (%r10,%r11,1),%r11d + .byte 65,15,182,12,10 // movzbl (%r10,%rcx,1),%ecx + .byte 193,225,8 // shl $0x8,%ecx + .byte 68,9,217 // or %r11d,%ecx + .byte 71,15,182,12,10 // movzbl (%r10,%r9,1),%r9d + .byte 65,15,182,4,2 // movzbl (%r10,%rax,1),%eax + .byte 193,224,8 // shl $0x8,%eax + .byte 68,9,200 // or %r9d,%eax + .byte 102,15,196,192,0 // pinsrw $0x0,%eax,%xmm0 + .byte 102,15,196,193,1 // pinsrw $0x1,%ecx,%xmm0 + .byte 102,15,239,201 // pxor %xmm1,%xmm1 + .byte 102,15,96,193 // punpcklbw %xmm1,%xmm0 + .byte 102,15,97,193 // punpcklwd %xmm1,%xmm0 + .byte 102,15,112,200,78 // pshufd $0x4e,%xmm0,%xmm1 + .byte 102,72,15,126,200 // movq %xmm1,%rax + .byte 68,15,182,200 // movzbl %al,%r9d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 77,139,64,8 // mov 0x8(%r8),%r8 + .byte 68,15,182,209 // movzbl %cl,%r10d + .byte 72,193,233,30 // shr $0x1e,%rcx + .byte 102,65,15,110,4,8 // movd (%r8,%rcx,1),%xmm0 + .byte 102,65,15,110,12,128 // movd (%r8,%rax,4),%xmm1 + .byte 102,15,98,193 // punpckldq %xmm1,%xmm0 + .byte 102,67,15,110,28,144 // movd (%r8,%r10,4),%xmm3 + .byte 102,67,15,110,12,136 // movd (%r8,%r9,4),%xmm1 + .byte 102,15,98,217 // punpckldq %xmm1,%xmm3 + .byte 102,15,98,216 // punpckldq %xmm0,%xmm3 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,15,111,203 // movdqa %xmm3,%xmm1 + .byte 102,15,114,209,8 // psrld $0x8,%xmm1 + .byte 102,15,219,200 // pand %xmm0,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,15,114,210,16 // psrld $0x10,%xmm2 + .byte 102,15,219,208 // pand %xmm0,%xmm2 + .byte 102,15,219,195 // pand %xmm3,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,15,114,211,24 // psrld $0x18,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_565_sse2 +.globl _sk_load_565_sse2 +_sk_load_565_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 243,15,126,20,120 // movq (%rax,%rdi,2),%xmm2 + .byte 102,15,239,192 // pxor %xmm0,%xmm0 + .byte 102,15,97,208 // punpcklwd %xmm0,%xmm2 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,15,219,194 // pand %xmm2,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 102,15,112,201,0 // pshufd $0x0,%xmm1,%xmm1 + .byte 102,15,219,202 // pand %xmm2,%xmm1 + .byte 15,91,217 // cvtdq2ps %xmm1,%xmm3 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 15,89,203 // mulps %xmm3,%xmm1 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,15,219,218 // pand %xmm2,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,89,211 // mulps %xmm3,%xmm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_565_sse2 +.globl _sk_gather_565_sse2 +_sk_gather_565_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,112,217,245 // pshufd $0xf5,%xmm1,%xmm3 + .byte 102,15,244,218 // pmuludq %xmm2,%xmm3 + .byte 102,15,112,219,232 // pshufd $0xe8,%xmm3,%xmm3 + .byte 102,15,244,209 // pmuludq %xmm1,%xmm2 + .byte 102,15,112,202,232 // pshufd $0xe8,%xmm2,%xmm1 + .byte 102,15,98,203 // punpckldq %xmm3,%xmm1 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,193 // paddd %xmm1,%xmm0 + .byte 102,15,112,200,78 // pshufd $0x4e,%xmm0,%xmm1 + .byte 102,72,15,126,200 // movq %xmm1,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,67,15,196,20,81,0 // pinsrw $0x0,(%r9,%r10,2),%xmm2 + .byte 102,65,15,196,20,73,1 // pinsrw $0x1,(%r9,%rcx,2),%xmm2 + .byte 67,15,183,12,65 // movzwl (%r9,%r8,2),%ecx + .byte 102,15,196,209,2 // pinsrw $0x2,%ecx,%xmm2 + .byte 65,15,183,4,65 // movzwl (%r9,%rax,2),%eax + .byte 102,15,196,208,3 // pinsrw $0x3,%eax,%xmm2 + .byte 102,15,239,192 // pxor %xmm0,%xmm0 + .byte 102,15,97,208 // punpcklwd %xmm0,%xmm2 + .byte 184,0,248,0,0 // mov $0xf800,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,15,219,194 // pand %xmm2,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,8,33,132,55 // mov $0x37842108,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,224,7,0,0 // mov $0x7e0,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 102,15,112,201,0 // pshufd $0x0,%xmm1,%xmm1 + .byte 102,15,219,202 // pand %xmm2,%xmm1 + .byte 15,91,217 // cvtdq2ps %xmm1,%xmm3 + .byte 184,33,8,2,58 // mov $0x3a020821,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 15,89,203 // mulps %xmm3,%xmm1 + .byte 184,31,0,0,0 // mov $0x1f,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,15,219,218 // pand %xmm2,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 184,8,33,4,61 // mov $0x3d042108,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 15,89,211 // mulps %xmm3,%xmm2 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_565_sse2 +.globl _sk_store_565_sse2 +_sk_store_565_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,0,248,65 // mov $0x41f80000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,200 // mulps %xmm0,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 102,65,15,114,241,11 // pslld $0xb,%xmm9 + .byte 185,0,0,124,66 // mov $0x427c0000,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 102,69,15,91,210 // cvtps2dq %xmm10,%xmm10 + .byte 102,65,15,114,242,5 // pslld $0x5,%xmm10 + .byte 102,69,15,235,209 // por %xmm9,%xmm10 + .byte 68,15,89,194 // mulps %xmm2,%xmm8 + .byte 102,69,15,91,192 // cvtps2dq %xmm8,%xmm8 + .byte 102,69,15,86,194 // orpd %xmm10,%xmm8 + .byte 102,65,15,114,240,16 // pslld $0x10,%xmm8 + .byte 102,65,15,114,224,16 // psrad $0x10,%xmm8 + .byte 102,69,15,107,192 // packssdw %xmm8,%xmm8 + .byte 102,68,15,214,4,120 // movq %xmm8,(%rax,%rdi,2) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_4444_sse2 +.globl _sk_load_4444_sse2 +_sk_load_4444_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 243,68,15,126,12,120 // movq (%rax,%rdi,2),%xmm9 + .byte 102,15,239,192 // pxor %xmm0,%xmm0 + .byte 102,68,15,97,200 // punpcklwd %xmm0,%xmm9 + .byte 184,0,240,0,0 // mov $0xf000,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,65,15,219,193 // pand %xmm9,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,137,136,136,55 // mov $0x37888889,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,0,15,0,0 // mov $0xf00,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 102,15,112,201,0 // pshufd $0x0,%xmm1,%xmm1 + .byte 102,65,15,219,201 // pand %xmm9,%xmm1 + .byte 15,91,209 // cvtdq2ps %xmm1,%xmm2 + .byte 184,137,136,136,57 // mov $0x39888889,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 15,89,202 // mulps %xmm2,%xmm1 + .byte 184,240,0,0,0 // mov $0xf0,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,65,15,219,209 // pand %xmm9,%xmm2 + .byte 68,15,91,194 // cvtdq2ps %xmm2,%xmm8 + .byte 184,137,136,136,59 // mov $0x3b888889,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 184,15,0,0,0 // mov $0xf,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,65,15,219,217 // pand %xmm9,%xmm3 + .byte 68,15,91,195 // cvtdq2ps %xmm3,%xmm8 + .byte 184,137,136,136,61 // mov $0x3d888889,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_4444_sse2 +.globl _sk_gather_4444_sse2 +_sk_gather_4444_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,112,217,245 // pshufd $0xf5,%xmm1,%xmm3 + .byte 102,15,244,218 // pmuludq %xmm2,%xmm3 + .byte 102,15,112,219,232 // pshufd $0xe8,%xmm3,%xmm3 + .byte 102,15,244,209 // pmuludq %xmm1,%xmm2 + .byte 102,15,112,202,232 // pshufd $0xe8,%xmm2,%xmm1 + .byte 102,15,98,203 // punpckldq %xmm3,%xmm1 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,193 // paddd %xmm1,%xmm0 + .byte 102,15,112,200,78 // pshufd $0x4e,%xmm0,%xmm1 + .byte 102,72,15,126,200 // movq %xmm1,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,71,15,196,12,81,0 // pinsrw $0x0,(%r9,%r10,2),%xmm9 + .byte 102,69,15,196,12,73,1 // pinsrw $0x1,(%r9,%rcx,2),%xmm9 + .byte 67,15,183,12,65 // movzwl (%r9,%r8,2),%ecx + .byte 102,68,15,196,201,2 // pinsrw $0x2,%ecx,%xmm9 + .byte 65,15,183,4,65 // movzwl (%r9,%rax,2),%eax + .byte 102,68,15,196,200,3 // pinsrw $0x3,%eax,%xmm9 + .byte 102,15,239,192 // pxor %xmm0,%xmm0 + .byte 102,68,15,97,200 // punpcklwd %xmm0,%xmm9 + .byte 184,0,240,0,0 // mov $0xf000,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,65,15,219,193 // pand %xmm9,%xmm0 + .byte 15,91,200 // cvtdq2ps %xmm0,%xmm1 + .byte 184,137,136,136,55 // mov $0x37888889,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 184,0,15,0,0 // mov $0xf00,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 102,15,112,201,0 // pshufd $0x0,%xmm1,%xmm1 + .byte 102,65,15,219,201 // pand %xmm9,%xmm1 + .byte 15,91,209 // cvtdq2ps %xmm1,%xmm2 + .byte 184,137,136,136,57 // mov $0x39888889,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 15,89,202 // mulps %xmm2,%xmm1 + .byte 184,240,0,0,0 // mov $0xf0,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,65,15,219,209 // pand %xmm9,%xmm2 + .byte 68,15,91,194 // cvtdq2ps %xmm2,%xmm8 + .byte 184,137,136,136,59 // mov $0x3b888889,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 184,15,0,0,0 // mov $0xf,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 102,15,112,219,0 // pshufd $0x0,%xmm3,%xmm3 + .byte 102,65,15,219,217 // pand %xmm9,%xmm3 + .byte 68,15,91,195 // cvtdq2ps %xmm3,%xmm8 + .byte 184,137,136,136,61 // mov $0x3d888889,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_4444_sse2 +.globl _sk_store_4444_sse2 +_sk_store_4444_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,0,112,65 // mov $0x41700000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,200 // mulps %xmm0,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 102,65,15,114,241,12 // pslld $0xc,%xmm9 + .byte 69,15,40,208 // movaps %xmm8,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 102,69,15,91,210 // cvtps2dq %xmm10,%xmm10 + .byte 102,65,15,114,242,8 // pslld $0x8,%xmm10 + .byte 102,69,15,235,209 // por %xmm9,%xmm10 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 102,65,15,114,241,4 // pslld $0x4,%xmm9 + .byte 68,15,89,195 // mulps %xmm3,%xmm8 + .byte 102,69,15,91,192 // cvtps2dq %xmm8,%xmm8 + .byte 102,69,15,86,193 // orpd %xmm9,%xmm8 + .byte 102,69,15,86,194 // orpd %xmm10,%xmm8 + .byte 102,65,15,114,240,16 // pslld $0x10,%xmm8 + .byte 102,65,15,114,224,16 // psrad $0x10,%xmm8 + .byte 102,69,15,107,192 // packssdw %xmm8,%xmm8 + .byte 102,68,15,214,4,120 // movq %xmm8,(%rax,%rdi,2) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_8888_sse2 +.globl _sk_load_8888_sse2 +_sk_load_8888_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 243,15,111,28,184 // movdqu (%rax,%rdi,4),%xmm3 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,15,111,203 // movdqa %xmm3,%xmm1 + .byte 102,15,114,209,8 // psrld $0x8,%xmm1 + .byte 102,15,219,200 // pand %xmm0,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,15,114,210,16 // psrld $0x10,%xmm2 + .byte 102,15,219,208 // pand %xmm0,%xmm2 + .byte 102,15,219,195 // pand %xmm3,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,15,114,211,24 // psrld $0x18,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_8888_sse2 +.globl _sk_gather_8888_sse2 +_sk_gather_8888_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,112,217,245 // pshufd $0xf5,%xmm1,%xmm3 + .byte 102,15,244,218 // pmuludq %xmm2,%xmm3 + .byte 102,15,112,219,232 // pshufd $0xe8,%xmm3,%xmm3 + .byte 102,15,244,209 // pmuludq %xmm1,%xmm2 + .byte 102,15,112,202,232 // pshufd $0xe8,%xmm2,%xmm1 + .byte 102,15,98,203 // punpckldq %xmm3,%xmm1 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,193 // paddd %xmm1,%xmm0 + .byte 102,15,112,200,78 // pshufd $0x4e,%xmm0,%xmm1 + .byte 102,72,15,126,200 // movq %xmm1,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 102,65,15,110,4,137 // movd (%r9,%rcx,4),%xmm0 + .byte 102,65,15,110,12,129 // movd (%r9,%rax,4),%xmm1 + .byte 102,15,98,193 // punpckldq %xmm1,%xmm0 + .byte 102,67,15,110,28,145 // movd (%r9,%r10,4),%xmm3 + .byte 102,67,15,110,12,129 // movd (%r9,%r8,4),%xmm1 + .byte 102,15,98,217 // punpckldq %xmm1,%xmm3 + .byte 102,15,98,216 // punpckldq %xmm0,%xmm3 + .byte 184,255,0,0,0 // mov $0xff,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,192,0 // pshufd $0x0,%xmm0,%xmm0 + .byte 102,15,111,203 // movdqa %xmm3,%xmm1 + .byte 102,15,114,209,8 // psrld $0x8,%xmm1 + .byte 102,15,219,200 // pand %xmm0,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,15,114,210,16 // psrld $0x10,%xmm2 + .byte 102,15,219,208 // pand %xmm0,%xmm2 + .byte 102,15,219,195 // pand %xmm3,%xmm0 + .byte 15,91,192 // cvtdq2ps %xmm0,%xmm0 + .byte 184,129,128,128,59 // mov $0x3b808081,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,91,201 // cvtdq2ps %xmm1,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,15,114,211,24 // psrld $0x18,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_8888_sse2 +.globl _sk_store_8888_sse2 +_sk_store_8888_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,0,127,67 // mov $0x437f0000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,200 // mulps %xmm0,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 69,15,40,208 // movaps %xmm8,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 102,69,15,91,210 // cvtps2dq %xmm10,%xmm10 + .byte 102,65,15,114,242,8 // pslld $0x8,%xmm10 + .byte 102,69,15,235,209 // por %xmm9,%xmm10 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,89,202 // mulps %xmm2,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 102,65,15,114,241,16 // pslld $0x10,%xmm9 + .byte 68,15,89,195 // mulps %xmm3,%xmm8 + .byte 102,69,15,91,192 // cvtps2dq %xmm8,%xmm8 + .byte 102,65,15,114,240,24 // pslld $0x18,%xmm8 + .byte 102,69,15,235,193 // por %xmm9,%xmm8 + .byte 102,69,15,235,194 // por %xmm10,%xmm8 + .byte 243,68,15,127,4,184 // movdqu %xmm8,(%rax,%rdi,4) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_f16_sse2 +.globl _sk_load_f16_sse2 +_sk_load_f16_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 243,15,111,4,248 // movdqu (%rax,%rdi,8),%xmm0 + .byte 243,15,111,76,248,16 // movdqu 0x10(%rax,%rdi,8),%xmm1 + .byte 102,68,15,111,192 // movdqa %xmm0,%xmm8 + .byte 102,68,15,97,193 // punpcklwd %xmm1,%xmm8 + .byte 102,15,105,193 // punpckhwd %xmm1,%xmm0 + .byte 102,65,15,111,200 // movdqa %xmm8,%xmm1 + .byte 102,15,97,200 // punpcklwd %xmm0,%xmm1 + .byte 102,68,15,105,192 // punpckhwd %xmm0,%xmm8 + .byte 184,0,4,0,4 // mov $0x4000400,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,216,0 // pshufd $0x0,%xmm0,%xmm3 + .byte 102,15,111,195 // movdqa %xmm3,%xmm0 + .byte 102,15,101,193 // pcmpgtw %xmm1,%xmm0 + .byte 102,15,223,193 // pandn %xmm1,%xmm0 + .byte 102,69,15,239,201 // pxor %xmm9,%xmm9 + .byte 102,65,15,97,193 // punpcklwd %xmm9,%xmm0 + .byte 102,15,114,240,13 // pslld $0xd,%xmm0 + .byte 184,0,0,128,119 // mov $0x77800000,%eax + .byte 102,15,110,208 // movd %eax,%xmm2 + .byte 102,68,15,112,210,0 // pshufd $0x0,%xmm2,%xmm10 + .byte 65,15,89,194 // mulps %xmm10,%xmm0 + .byte 102,15,112,209,78 // pshufd $0x4e,%xmm1,%xmm2 + .byte 102,15,111,203 // movdqa %xmm3,%xmm1 + .byte 102,15,101,202 // pcmpgtw %xmm2,%xmm1 + .byte 102,15,223,202 // pandn %xmm2,%xmm1 + .byte 102,65,15,97,201 // punpcklwd %xmm9,%xmm1 + .byte 102,15,114,241,13 // pslld $0xd,%xmm1 + .byte 65,15,89,202 // mulps %xmm10,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,65,15,101,208 // pcmpgtw %xmm8,%xmm2 + .byte 102,65,15,223,208 // pandn %xmm8,%xmm2 + .byte 102,65,15,97,209 // punpcklwd %xmm9,%xmm2 + .byte 102,15,114,242,13 // pslld $0xd,%xmm2 + .byte 65,15,89,210 // mulps %xmm10,%xmm2 + .byte 102,69,15,112,192,78 // pshufd $0x4e,%xmm8,%xmm8 + .byte 102,65,15,101,216 // pcmpgtw %xmm8,%xmm3 + .byte 102,65,15,223,216 // pandn %xmm8,%xmm3 + .byte 102,65,15,97,217 // punpcklwd %xmm9,%xmm3 + .byte 102,15,114,243,13 // pslld $0xd,%xmm3 + .byte 65,15,89,218 // mulps %xmm10,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_gather_f16_sse2 +.globl _sk_gather_f16_sse2 +_sk_gather_f16_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 76,139,8 // mov (%rax),%r9 + .byte 243,15,91,201 // cvttps2dq %xmm1,%xmm1 + .byte 102,15,110,80,16 // movd 0x10(%rax),%xmm2 + .byte 102,15,112,210,0 // pshufd $0x0,%xmm2,%xmm2 + .byte 102,15,112,217,245 // pshufd $0xf5,%xmm1,%xmm3 + .byte 102,15,244,218 // pmuludq %xmm2,%xmm3 + .byte 102,15,112,219,232 // pshufd $0xe8,%xmm3,%xmm3 + .byte 102,15,244,209 // pmuludq %xmm1,%xmm2 + .byte 102,15,112,202,232 // pshufd $0xe8,%xmm2,%xmm1 + .byte 102,15,98,203 // punpckldq %xmm3,%xmm1 + .byte 243,15,91,192 // cvttps2dq %xmm0,%xmm0 + .byte 102,15,254,193 // paddd %xmm1,%xmm0 + .byte 102,15,112,200,78 // pshufd $0x4e,%xmm0,%xmm1 + .byte 102,72,15,126,200 // movq %xmm1,%rax + .byte 65,137,192 // mov %eax,%r8d + .byte 72,193,232,32 // shr $0x20,%rax + .byte 102,72,15,126,193 // movq %xmm0,%rcx + .byte 65,137,202 // mov %ecx,%r10d + .byte 72,193,233,32 // shr $0x20,%rcx + .byte 243,65,15,126,4,201 // movq (%r9,%rcx,8),%xmm0 + .byte 243,67,15,126,12,209 // movq (%r9,%r10,8),%xmm1 + .byte 102,15,108,200 // punpcklqdq %xmm0,%xmm1 + .byte 243,65,15,126,4,193 // movq (%r9,%rax,8),%xmm0 + .byte 243,67,15,126,20,193 // movq (%r9,%r8,8),%xmm2 + .byte 102,15,108,208 // punpcklqdq %xmm0,%xmm2 + .byte 102,68,15,111,193 // movdqa %xmm1,%xmm8 + .byte 102,68,15,97,194 // punpcklwd %xmm2,%xmm8 + .byte 102,15,105,202 // punpckhwd %xmm2,%xmm1 + .byte 102,65,15,111,208 // movdqa %xmm8,%xmm2 + .byte 102,15,97,209 // punpcklwd %xmm1,%xmm2 + .byte 102,68,15,105,193 // punpckhwd %xmm1,%xmm8 + .byte 184,0,4,0,4 // mov $0x4000400,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 102,15,112,216,0 // pshufd $0x0,%xmm0,%xmm3 + .byte 102,15,111,195 // movdqa %xmm3,%xmm0 + .byte 102,15,101,194 // pcmpgtw %xmm2,%xmm0 + .byte 102,15,223,194 // pandn %xmm2,%xmm0 + .byte 102,69,15,239,201 // pxor %xmm9,%xmm9 + .byte 102,65,15,97,193 // punpcklwd %xmm9,%xmm0 + .byte 102,15,114,240,13 // pslld $0xd,%xmm0 + .byte 184,0,0,128,119 // mov $0x77800000,%eax + .byte 102,15,110,200 // movd %eax,%xmm1 + .byte 102,68,15,112,209,0 // pshufd $0x0,%xmm1,%xmm10 + .byte 65,15,89,194 // mulps %xmm10,%xmm0 + .byte 102,15,112,210,78 // pshufd $0x4e,%xmm2,%xmm2 + .byte 102,15,111,203 // movdqa %xmm3,%xmm1 + .byte 102,15,101,202 // pcmpgtw %xmm2,%xmm1 + .byte 102,15,223,202 // pandn %xmm2,%xmm1 + .byte 102,65,15,97,201 // punpcklwd %xmm9,%xmm1 + .byte 102,15,114,241,13 // pslld $0xd,%xmm1 + .byte 65,15,89,202 // mulps %xmm10,%xmm1 + .byte 102,15,111,211 // movdqa %xmm3,%xmm2 + .byte 102,65,15,101,208 // pcmpgtw %xmm8,%xmm2 + .byte 102,65,15,223,208 // pandn %xmm8,%xmm2 + .byte 102,65,15,97,209 // punpcklwd %xmm9,%xmm2 + .byte 102,15,114,242,13 // pslld $0xd,%xmm2 + .byte 65,15,89,210 // mulps %xmm10,%xmm2 + .byte 102,69,15,112,192,78 // pshufd $0x4e,%xmm8,%xmm8 + .byte 102,65,15,101,216 // pcmpgtw %xmm8,%xmm3 + .byte 102,65,15,223,216 // pandn %xmm8,%xmm3 + .byte 102,65,15,97,217 // punpcklwd %xmm9,%xmm3 + .byte 102,15,114,243,13 // pslld $0xd,%xmm3 + .byte 65,15,89,218 // mulps %xmm10,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_f16_sse2 +.globl _sk_store_f16_sse2 +_sk_store_f16_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,0,128,7 // mov $0x7800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 102,69,15,112,200,0 // pshufd $0x0,%xmm8,%xmm9 + .byte 102,69,15,111,193 // movdqa %xmm9,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 102,65,15,114,208,13 // psrld $0xd,%xmm8 + .byte 102,65,15,114,240,16 // pslld $0x10,%xmm8 + .byte 102,65,15,114,224,16 // psrad $0x10,%xmm8 + .byte 102,69,15,107,192 // packssdw %xmm8,%xmm8 + .byte 102,69,15,111,209 // movdqa %xmm9,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 102,65,15,114,210,13 // psrld $0xd,%xmm10 + .byte 102,65,15,114,242,16 // pslld $0x10,%xmm10 + .byte 102,65,15,114,226,16 // psrad $0x10,%xmm10 + .byte 102,69,15,107,210 // packssdw %xmm10,%xmm10 + .byte 102,69,15,111,217 // movdqa %xmm9,%xmm11 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 102,65,15,114,211,13 // psrld $0xd,%xmm11 + .byte 102,65,15,114,243,16 // pslld $0x10,%xmm11 + .byte 102,65,15,114,227,16 // psrad $0x10,%xmm11 + .byte 102,69,15,107,219 // packssdw %xmm11,%xmm11 + .byte 68,15,89,203 // mulps %xmm3,%xmm9 + .byte 102,65,15,114,209,13 // psrld $0xd,%xmm9 + .byte 102,65,15,114,241,16 // pslld $0x10,%xmm9 + .byte 102,65,15,114,225,16 // psrad $0x10,%xmm9 + .byte 102,69,15,107,201 // packssdw %xmm9,%xmm9 + .byte 102,69,15,97,194 // punpcklwd %xmm10,%xmm8 + .byte 102,69,15,97,217 // punpcklwd %xmm9,%xmm11 + .byte 102,69,15,111,200 // movdqa %xmm8,%xmm9 + .byte 102,69,15,98,203 // punpckldq %xmm11,%xmm9 + .byte 243,68,15,127,12,248 // movdqu %xmm9,(%rax,%rdi,8) + .byte 102,69,15,106,195 // punpckhdq %xmm11,%xmm8 + .byte 243,68,15,127,68,248,16 // movdqu %xmm8,0x10(%rax,%rdi,8) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_u16_be_sse2 +.globl _sk_load_u16_be_sse2 +_sk_load_u16_be_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 243,15,111,4,248 // movdqu (%rax,%rdi,8),%xmm0 + .byte 243,15,111,76,248,16 // movdqu 0x10(%rax,%rdi,8),%xmm1 + .byte 102,15,111,208 // movdqa %xmm0,%xmm2 + .byte 102,15,97,209 // punpcklwd %xmm1,%xmm2 + .byte 102,15,105,193 // punpckhwd %xmm1,%xmm0 + .byte 102,15,111,202 // movdqa %xmm2,%xmm1 + .byte 102,15,97,200 // punpcklwd %xmm0,%xmm1 + .byte 102,15,105,208 // punpckhwd %xmm0,%xmm2 + .byte 184,128,0,128,55 // mov $0x37800080,%eax + .byte 102,68,15,110,192 // movd %eax,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 102,15,111,193 // movdqa %xmm1,%xmm0 + .byte 102,15,113,240,8 // psllw $0x8,%xmm0 + .byte 102,15,112,217,78 // pshufd $0x4e,%xmm1,%xmm3 + .byte 102,15,113,209,8 // psrlw $0x8,%xmm1 + .byte 102,15,235,200 // por %xmm0,%xmm1 + .byte 102,69,15,239,201 // pxor %xmm9,%xmm9 + .byte 102,65,15,97,201 // punpcklwd %xmm9,%xmm1 + .byte 15,91,193 // cvtdq2ps %xmm1,%xmm0 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 102,15,111,203 // movdqa %xmm3,%xmm1 + .byte 102,15,113,241,8 // psllw $0x8,%xmm1 + .byte 102,15,113,211,8 // psrlw $0x8,%xmm3 + .byte 102,15,235,217 // por %xmm1,%xmm3 + .byte 102,65,15,97,217 // punpcklwd %xmm9,%xmm3 + .byte 15,91,203 // cvtdq2ps %xmm3,%xmm1 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 102,68,15,111,210 // movdqa %xmm2,%xmm10 + .byte 102,65,15,113,242,8 // psllw $0x8,%xmm10 + .byte 102,15,112,218,78 // pshufd $0x4e,%xmm2,%xmm3 + .byte 102,15,113,210,8 // psrlw $0x8,%xmm2 + .byte 102,65,15,235,210 // por %xmm10,%xmm2 + .byte 102,65,15,97,209 // punpcklwd %xmm9,%xmm2 + .byte 15,91,210 // cvtdq2ps %xmm2,%xmm2 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 102,68,15,111,211 // movdqa %xmm3,%xmm10 + .byte 102,65,15,113,242,8 // psllw $0x8,%xmm10 + .byte 102,15,113,211,8 // psrlw $0x8,%xmm3 + .byte 102,65,15,235,218 // por %xmm10,%xmm3 + .byte 102,65,15,97,217 // punpcklwd %xmm9,%xmm3 + .byte 15,91,219 // cvtdq2ps %xmm3,%xmm3 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_u16_be_sse2 +.globl _sk_store_u16_be_sse2 +_sk_store_u16_be_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 185,0,255,127,71 // mov $0x477fff00,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 102,69,15,91,192 // cvtps2dq %xmm8,%xmm8 + .byte 102,65,15,114,240,16 // pslld $0x10,%xmm8 + .byte 102,65,15,114,224,16 // psrad $0x10,%xmm8 + .byte 102,69,15,107,192 // packssdw %xmm8,%xmm8 + .byte 102,69,15,111,208 // movdqa %xmm8,%xmm10 + .byte 102,65,15,113,242,8 // psllw $0x8,%xmm10 + .byte 102,65,15,113,208,8 // psrlw $0x8,%xmm8 + .byte 102,69,15,235,194 // por %xmm10,%xmm8 + .byte 69,15,40,209 // movaps %xmm9,%xmm10 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 102,69,15,91,210 // cvtps2dq %xmm10,%xmm10 + .byte 102,65,15,114,242,16 // pslld $0x10,%xmm10 + .byte 102,65,15,114,226,16 // psrad $0x10,%xmm10 + .byte 102,69,15,107,210 // packssdw %xmm10,%xmm10 + .byte 102,69,15,111,218 // movdqa %xmm10,%xmm11 + .byte 102,65,15,113,243,8 // psllw $0x8,%xmm11 + .byte 102,65,15,113,210,8 // psrlw $0x8,%xmm10 + .byte 102,69,15,235,211 // por %xmm11,%xmm10 + .byte 69,15,40,217 // movaps %xmm9,%xmm11 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 102,69,15,91,219 // cvtps2dq %xmm11,%xmm11 + .byte 102,65,15,114,243,16 // pslld $0x10,%xmm11 + .byte 102,65,15,114,227,16 // psrad $0x10,%xmm11 + .byte 102,69,15,107,219 // packssdw %xmm11,%xmm11 + .byte 102,69,15,111,227 // movdqa %xmm11,%xmm12 + .byte 102,65,15,113,244,8 // psllw $0x8,%xmm12 + .byte 102,65,15,113,211,8 // psrlw $0x8,%xmm11 + .byte 102,69,15,235,220 // por %xmm12,%xmm11 + .byte 68,15,89,203 // mulps %xmm3,%xmm9 + .byte 102,69,15,91,201 // cvtps2dq %xmm9,%xmm9 + .byte 102,65,15,114,241,16 // pslld $0x10,%xmm9 + .byte 102,65,15,114,225,16 // psrad $0x10,%xmm9 + .byte 102,69,15,107,201 // packssdw %xmm9,%xmm9 + .byte 102,69,15,111,225 // movdqa %xmm9,%xmm12 + .byte 102,65,15,113,244,8 // psllw $0x8,%xmm12 + .byte 102,65,15,113,209,8 // psrlw $0x8,%xmm9 + .byte 102,69,15,235,204 // por %xmm12,%xmm9 + .byte 102,69,15,97,194 // punpcklwd %xmm10,%xmm8 + .byte 102,69,15,97,217 // punpcklwd %xmm9,%xmm11 + .byte 102,69,15,111,200 // movdqa %xmm8,%xmm9 + .byte 102,69,15,98,203 // punpckldq %xmm11,%xmm9 + .byte 243,68,15,127,12,248 // movdqu %xmm9,(%rax,%rdi,8) + .byte 102,69,15,106,195 // punpckhdq %xmm11,%xmm8 + .byte 243,68,15,127,68,248,16 // movdqu %xmm8,0x10(%rax,%rdi,8) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_load_f32_sse2 +.globl _sk_load_f32_sse2 +_sk_load_f32_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,137,249 // mov %rdi,%rcx + .byte 72,193,225,4 // shl $0x4,%rcx + .byte 68,15,16,4,8 // movups (%rax,%rcx,1),%xmm8 + .byte 15,16,68,8,16 // movups 0x10(%rax,%rcx,1),%xmm0 + .byte 15,16,92,8,32 // movups 0x20(%rax,%rcx,1),%xmm3 + .byte 68,15,16,76,8,48 // movups 0x30(%rax,%rcx,1),%xmm9 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 15,20,208 // unpcklps %xmm0,%xmm2 + .byte 15,40,203 // movaps %xmm3,%xmm1 + .byte 65,15,20,201 // unpcklps %xmm9,%xmm1 + .byte 68,15,21,192 // unpckhps %xmm0,%xmm8 + .byte 65,15,21,217 // unpckhps %xmm9,%xmm3 + .byte 15,40,194 // movaps %xmm2,%xmm0 + .byte 102,15,20,193 // unpcklpd %xmm1,%xmm0 + .byte 15,18,202 // movhlps %xmm2,%xmm1 + .byte 65,15,40,208 // movaps %xmm8,%xmm2 + .byte 102,15,20,211 // unpcklpd %xmm3,%xmm2 + .byte 65,15,18,216 // movhlps %xmm8,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_store_f32_sse2 +.globl _sk_store_f32_sse2 +_sk_store_f32_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 72,139,0 // mov (%rax),%rax + .byte 72,137,249 // mov %rdi,%rcx + .byte 72,193,225,4 // shl $0x4,%rcx + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 68,15,20,201 // unpcklps %xmm1,%xmm9 + .byte 68,15,40,210 // movaps %xmm2,%xmm10 + .byte 68,15,40,218 // movaps %xmm2,%xmm11 + .byte 68,15,20,219 // unpcklps %xmm3,%xmm11 + .byte 68,15,21,193 // unpckhps %xmm1,%xmm8 + .byte 68,15,21,211 // unpckhps %xmm3,%xmm10 + .byte 69,15,40,225 // movaps %xmm9,%xmm12 + .byte 102,69,15,20,227 // unpcklpd %xmm11,%xmm12 + .byte 69,15,18,217 // movhlps %xmm9,%xmm11 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 102,69,15,20,202 // unpcklpd %xmm10,%xmm9 + .byte 69,15,18,208 // movhlps %xmm8,%xmm10 + .byte 102,68,15,17,36,8 // movupd %xmm12,(%rax,%rcx,1) + .byte 68,15,17,92,8,16 // movups %xmm11,0x10(%rax,%rcx,1) + .byte 102,68,15,17,76,8,32 // movupd %xmm9,0x20(%rax,%rcx,1) + .byte 68,15,17,84,8,48 // movups %xmm10,0x30(%rax,%rcx,1) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_x_sse2 +.globl _sk_clamp_x_sse2 +_sk_clamp_x_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 68,15,95,192 // maxps %xmm0,%xmm8 + .byte 243,68,15,16,8 // movss (%rax),%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 102,15,118,192 // pcmpeqd %xmm0,%xmm0 + .byte 102,65,15,254,193 // paddd %xmm9,%xmm0 + .byte 68,15,93,192 // minps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_clamp_y_sse2 +.globl _sk_clamp_y_sse2 +_sk_clamp_y_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 68,15,95,193 // maxps %xmm1,%xmm8 + .byte 243,68,15,16,8 // movss (%rax),%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 102,15,118,201 // pcmpeqd %xmm1,%xmm1 + .byte 102,65,15,254,201 // paddd %xmm9,%xmm1 + .byte 68,15,93,193 // minps %xmm1,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,200 // movaps %xmm8,%xmm1 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_repeat_x_sse2 +.globl _sk_repeat_x_sse2 +_sk_repeat_x_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,0 // movss (%rax),%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,40,200 // movaps %xmm0,%xmm9 + .byte 69,15,94,200 // divps %xmm8,%xmm9 + .byte 243,69,15,91,209 // cvttps2dq %xmm9,%xmm10 + .byte 69,15,91,210 // cvtdq2ps %xmm10,%xmm10 + .byte 69,15,194,202,1 // cmpltps %xmm10,%xmm9 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,216 // movd %eax,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,84,217 // andps %xmm9,%xmm11 + .byte 69,15,92,211 // subps %xmm11,%xmm10 + .byte 69,15,89,208 // mulps %xmm8,%xmm10 + .byte 65,15,92,194 // subps %xmm10,%xmm0 + .byte 102,69,15,118,201 // pcmpeqd %xmm9,%xmm9 + .byte 102,69,15,254,200 // paddd %xmm8,%xmm9 + .byte 65,15,93,193 // minps %xmm9,%xmm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_repeat_y_sse2 +.globl _sk_repeat_y_sse2 +_sk_repeat_y_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,0 // movss (%rax),%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 69,15,94,200 // divps %xmm8,%xmm9 + .byte 243,69,15,91,209 // cvttps2dq %xmm9,%xmm10 + .byte 69,15,91,210 // cvtdq2ps %xmm10,%xmm10 + .byte 69,15,194,202,1 // cmpltps %xmm10,%xmm9 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,216 // movd %eax,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,84,217 // andps %xmm9,%xmm11 + .byte 69,15,92,211 // subps %xmm11,%xmm10 + .byte 69,15,89,208 // mulps %xmm8,%xmm10 + .byte 65,15,92,202 // subps %xmm10,%xmm1 + .byte 102,69,15,118,201 // pcmpeqd %xmm9,%xmm9 + .byte 102,69,15,254,200 // paddd %xmm8,%xmm9 + .byte 65,15,93,201 // minps %xmm9,%xmm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_mirror_x_sse2 +.globl _sk_mirror_x_sse2 +_sk_mirror_x_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,8 // movss (%rax),%xmm9 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,92,192 // subps %xmm8,%xmm0 + .byte 243,69,15,88,201 // addss %xmm9,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 68,15,40,208 // movaps %xmm0,%xmm10 + .byte 69,15,94,209 // divps %xmm9,%xmm10 + .byte 243,69,15,91,218 // cvttps2dq %xmm10,%xmm11 + .byte 69,15,91,219 // cvtdq2ps %xmm11,%xmm11 + .byte 69,15,194,211,1 // cmpltps %xmm11,%xmm10 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,224 // movd %eax,%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 69,15,84,226 // andps %xmm10,%xmm12 + .byte 69,15,87,210 // xorps %xmm10,%xmm10 + .byte 69,15,92,220 // subps %xmm12,%xmm11 + .byte 69,15,89,217 // mulps %xmm9,%xmm11 + .byte 65,15,92,195 // subps %xmm11,%xmm0 + .byte 65,15,92,192 // subps %xmm8,%xmm0 + .byte 68,15,92,208 // subps %xmm0,%xmm10 + .byte 65,15,84,194 // andps %xmm10,%xmm0 + .byte 102,69,15,118,201 // pcmpeqd %xmm9,%xmm9 + .byte 102,69,15,254,200 // paddd %xmm8,%xmm9 + .byte 65,15,93,193 // minps %xmm9,%xmm0 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_mirror_y_sse2 +.globl _sk_mirror_y_sse2 +_sk_mirror_y_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,8 // movss (%rax),%xmm9 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 243,69,15,88,201 // addss %xmm9,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 68,15,40,209 // movaps %xmm1,%xmm10 + .byte 69,15,94,209 // divps %xmm9,%xmm10 + .byte 243,69,15,91,218 // cvttps2dq %xmm10,%xmm11 + .byte 69,15,91,219 // cvtdq2ps %xmm11,%xmm11 + .byte 69,15,194,211,1 // cmpltps %xmm11,%xmm10 + .byte 184,0,0,128,63 // mov $0x3f800000,%eax + .byte 102,68,15,110,224 // movd %eax,%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 69,15,84,226 // andps %xmm10,%xmm12 + .byte 69,15,87,210 // xorps %xmm10,%xmm10 + .byte 69,15,92,220 // subps %xmm12,%xmm11 + .byte 69,15,89,217 // mulps %xmm9,%xmm11 + .byte 65,15,92,203 // subps %xmm11,%xmm1 + .byte 65,15,92,200 // subps %xmm8,%xmm1 + .byte 68,15,92,209 // subps %xmm1,%xmm10 + .byte 65,15,84,202 // andps %xmm10,%xmm1 + .byte 102,69,15,118,201 // pcmpeqd %xmm9,%xmm9 + .byte 102,69,15,254,200 // paddd %xmm8,%xmm9 + .byte 65,15,93,201 // minps %xmm9,%xmm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_luminance_to_alpha_sse2 +.globl _sk_luminance_to_alpha_sse2 +_sk_luminance_to_alpha_sse2: + .byte 184,208,179,89,62 // mov $0x3e59b3d0,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 15,89,216 // mulps %xmm0,%xmm3 + .byte 184,89,23,55,63 // mov $0x3f371759,%eax + .byte 102,15,110,192 // movd %eax,%xmm0 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 15,88,195 // addps %xmm3,%xmm0 + .byte 184,152,221,147,61 // mov $0x3d93dd98,%eax + .byte 102,15,110,216 // movd %eax,%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 15,89,218 // mulps %xmm2,%xmm3 + .byte 15,88,216 // addps %xmm0,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 15,87,192 // xorps %xmm0,%xmm0 + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_2x3_sse2 +.globl _sk_matrix_2x3_sse2 +_sk_matrix_2x3_sse2: + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 243,68,15,16,80,8 // movss 0x8(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,16 // movss 0x10(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,88,194 // addps %xmm10,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,68,15,16,80,12 // movss 0xc(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,20 // movss 0x14(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,88,202 // addps %xmm10,%xmm1 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_3x4_sse2 +.globl _sk_matrix_3x4_sse2 +_sk_matrix_3x4_sse2: + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 243,68,15,16,80,12 // movss 0xc(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,24 // movss 0x18(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,36 // movss 0x24(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,88,194 // addps %xmm10,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,68,15,16,80,16 // movss 0x10(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,28 // movss 0x1c(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,40 // movss 0x28(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,88,202 // addps %xmm10,%xmm1 + .byte 243,68,15,16,80,8 // movss 0x8(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,20 // movss 0x14(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,32 // movss 0x20(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,44 // movss 0x2c(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 68,15,89,226 // mulps %xmm2,%xmm12 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 69,15,89,217 // mulps %xmm9,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,208 // mulps %xmm8,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_4x5_sse2 +.globl _sk_matrix_4x5_sse2 +_sk_matrix_4x5_sse2: + .byte 68,15,40,201 // movaps %xmm1,%xmm9 + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 243,68,15,16,80,16 // movss 0x10(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,32 // movss 0x20(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,48 // movss 0x30(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,64 // movss 0x40(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 68,15,89,227 // mulps %xmm3,%xmm12 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,88,194 // addps %xmm10,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,68,15,16,80,20 // movss 0x14(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,36 // movss 0x24(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,52 // movss 0x34(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,68 // movss 0x44(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 68,15,89,227 // mulps %xmm3,%xmm12 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 68,15,89,218 // mulps %xmm2,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 65,15,88,202 // addps %xmm10,%xmm1 + .byte 243,68,15,16,80,8 // movss 0x8(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,24 // movss 0x18(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,40 // movss 0x28(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,56 // movss 0x38(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 243,68,15,16,112,72 // movss 0x48(%rax),%xmm14 + .byte 69,15,198,246,0 // shufps $0x0,%xmm14,%xmm14 + .byte 68,15,89,235 // mulps %xmm3,%xmm13 + .byte 69,15,88,238 // addps %xmm14,%xmm13 + .byte 68,15,89,226 // mulps %xmm2,%xmm12 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 69,15,89,217 // mulps %xmm9,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,208 // mulps %xmm8,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 243,68,15,16,88,12 // movss 0xc(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,28 // movss 0x1c(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 243,68,15,16,104,44 // movss 0x2c(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 243,68,15,16,112,60 // movss 0x3c(%rax),%xmm14 + .byte 69,15,198,246,0 // shufps $0x0,%xmm14,%xmm14 + .byte 243,68,15,16,120,76 // movss 0x4c(%rax),%xmm15 + .byte 69,15,198,255,0 // shufps $0x0,%xmm15,%xmm15 + .byte 68,15,89,243 // mulps %xmm3,%xmm14 + .byte 69,15,88,247 // addps %xmm15,%xmm14 + .byte 68,15,89,234 // mulps %xmm2,%xmm13 + .byte 69,15,88,238 // addps %xmm14,%xmm13 + .byte 69,15,89,225 // mulps %xmm9,%xmm12 + .byte 69,15,88,229 // addps %xmm13,%xmm12 + .byte 69,15,89,216 // mulps %xmm8,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,210 // movaps %xmm10,%xmm2 + .byte 65,15,40,219 // movaps %xmm11,%xmm3 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_matrix_perspective_sse2 +.globl _sk_matrix_perspective_sse2 +_sk_matrix_perspective_sse2: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,68,15,16,72,4 // movss 0x4(%rax),%xmm9 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 243,68,15,16,80,8 // movss 0x8(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 68,15,89,201 // mulps %xmm1,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 65,15,88,193 // addps %xmm9,%xmm0 + .byte 243,68,15,16,72,12 // movss 0xc(%rax),%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 243,68,15,16,80,16 // movss 0x10(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,20 // movss 0x14(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 68,15,89,209 // mulps %xmm1,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 243,68,15,16,80,24 // movss 0x18(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,28 // movss 0x1c(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,32 // movss 0x20(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 68,15,89,217 // mulps %xmm1,%xmm11 + .byte 69,15,88,220 // addps %xmm12,%xmm11 + .byte 69,15,89,208 // mulps %xmm8,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 65,15,83,202 // rcpps %xmm10,%xmm1 + .byte 15,89,193 // mulps %xmm1,%xmm0 + .byte 68,15,89,201 // mulps %xmm1,%xmm9 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,201 // movaps %xmm9,%xmm1 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_linear_gradient_sse2 +.globl _sk_linear_gradient_sse2 +_sk_linear_gradient_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,68,15,16,72,16 // movss 0x10(%rax),%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 243,68,15,16,80,20 // movss 0x14(%rax),%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 243,68,15,16,88,24 // movss 0x18(%rax),%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 243,68,15,16,96,28 // movss 0x1c(%rax),%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 72,139,8 // mov (%rax),%rcx + .byte 72,133,201 // test %rcx,%rcx + .byte 15,132,15,1,0,0 // je 30a0 <_sk_linear_gradient_sse2+0x149> + .byte 72,139,64,8 // mov 0x8(%rax),%rax + .byte 72,131,192,32 // add $0x20,%rax + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 15,87,219 // xorps %xmm3,%xmm3 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 243,68,15,16,112,224 // movss -0x20(%rax),%xmm14 + .byte 243,68,15,16,104,228 // movss -0x1c(%rax),%xmm13 + .byte 69,15,198,246,0 // shufps $0x0,%xmm14,%xmm14 + .byte 69,15,40,252 // movaps %xmm12,%xmm15 + .byte 68,15,40,224 // movaps %xmm0,%xmm12 + .byte 69,15,194,230,1 // cmpltps %xmm14,%xmm12 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,40,244 // movaps %xmm12,%xmm14 + .byte 69,15,85,245 // andnps %xmm13,%xmm14 + .byte 69,15,84,196 // andps %xmm12,%xmm8 + .byte 69,15,86,198 // orps %xmm14,%xmm8 + .byte 243,68,15,16,104,232 // movss -0x18(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,40,244 // movaps %xmm12,%xmm14 + .byte 69,15,85,245 // andnps %xmm13,%xmm14 + .byte 65,15,84,204 // andps %xmm12,%xmm1 + .byte 65,15,86,206 // orps %xmm14,%xmm1 + .byte 243,68,15,16,104,236 // movss -0x14(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,40,244 // movaps %xmm12,%xmm14 + .byte 69,15,85,245 // andnps %xmm13,%xmm14 + .byte 65,15,84,212 // andps %xmm12,%xmm2 + .byte 65,15,86,214 // orps %xmm14,%xmm2 + .byte 243,68,15,16,104,240 // movss -0x10(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,40,244 // movaps %xmm12,%xmm14 + .byte 69,15,85,245 // andnps %xmm13,%xmm14 + .byte 65,15,84,220 // andps %xmm12,%xmm3 + .byte 65,15,86,222 // orps %xmm14,%xmm3 + .byte 243,68,15,16,104,244 // movss -0xc(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,40,244 // movaps %xmm12,%xmm14 + .byte 69,15,85,245 // andnps %xmm13,%xmm14 + .byte 69,15,84,204 // andps %xmm12,%xmm9 + .byte 69,15,86,206 // orps %xmm14,%xmm9 + .byte 243,68,15,16,104,248 // movss -0x8(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,40,244 // movaps %xmm12,%xmm14 + .byte 69,15,85,245 // andnps %xmm13,%xmm14 + .byte 69,15,84,212 // andps %xmm12,%xmm10 + .byte 69,15,86,214 // orps %xmm14,%xmm10 + .byte 243,68,15,16,104,252 // movss -0x4(%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,40,244 // movaps %xmm12,%xmm14 + .byte 69,15,85,245 // andnps %xmm13,%xmm14 + .byte 69,15,84,220 // andps %xmm12,%xmm11 + .byte 69,15,86,222 // orps %xmm14,%xmm11 + .byte 243,68,15,16,40 // movss (%rax),%xmm13 + .byte 69,15,198,237,0 // shufps $0x0,%xmm13,%xmm13 + .byte 69,15,84,252 // andps %xmm12,%xmm15 + .byte 69,15,85,229 // andnps %xmm13,%xmm12 + .byte 69,15,86,231 // orps %xmm15,%xmm12 + .byte 72,131,192,36 // add $0x24,%rax + .byte 72,255,201 // dec %rcx + .byte 15,133,8,255,255,255 // jne 2fa6 <_sk_linear_gradient_sse2+0x4f> + .byte 235,13 // jmp 30ad <_sk_linear_gradient_sse2+0x156> + .byte 15,87,201 // xorps %xmm1,%xmm1 + .byte 15,87,210 // xorps %xmm2,%xmm2 + .byte 15,87,219 // xorps %xmm3,%xmm3 + .byte 69,15,87,192 // xorps %xmm8,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 69,15,88,193 // addps %xmm9,%xmm8 + .byte 15,89,200 // mulps %xmm0,%xmm1 + .byte 65,15,88,202 // addps %xmm10,%xmm1 + .byte 15,89,208 // mulps %xmm0,%xmm2 + .byte 65,15,88,211 // addps %xmm11,%xmm2 + .byte 15,89,216 // mulps %xmm0,%xmm3 + .byte 65,15,88,220 // addps %xmm12,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 65,15,40,192 // movaps %xmm8,%xmm0 + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_linear_gradient_2stops_sse2 +.globl _sk_linear_gradient_2stops_sse2 +_sk_linear_gradient_2stops_sse2: + .byte 68,15,40,192 // movaps %xmm0,%xmm8 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 243,15,16,0 // movss (%rax),%xmm0 + .byte 243,15,16,72,4 // movss 0x4(%rax),%xmm1 + .byte 15,198,192,0 // shufps $0x0,%xmm0,%xmm0 + .byte 243,15,16,80,16 // movss 0x10(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 65,15,89,192 // mulps %xmm8,%xmm0 + .byte 15,88,194 // addps %xmm2,%xmm0 + .byte 15,198,201,0 // shufps $0x0,%xmm1,%xmm1 + .byte 243,15,16,80,20 // movss 0x14(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 65,15,89,200 // mulps %xmm8,%xmm1 + .byte 15,88,202 // addps %xmm2,%xmm1 + .byte 243,15,16,80,8 // movss 0x8(%rax),%xmm2 + .byte 15,198,210,0 // shufps $0x0,%xmm2,%xmm2 + .byte 243,15,16,88,24 // movss 0x18(%rax),%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 65,15,89,208 // mulps %xmm8,%xmm2 + .byte 15,88,211 // addps %xmm3,%xmm2 + .byte 243,15,16,88,12 // movss 0xc(%rax),%xmm3 + .byte 15,198,219,0 // shufps $0x0,%xmm3,%xmm3 + .byte 243,68,15,16,72,28 // movss 0x1c(%rax),%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 65,15,89,216 // mulps %xmm8,%xmm3 + .byte 65,15,88,217 // addps %xmm9,%xmm3 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_save_xy_sse2 +.globl _sk_save_xy_sse2 +_sk_save_xy_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,40,200 // movaps %xmm8,%xmm9 + .byte 68,15,88,200 // addps %xmm0,%xmm9 + .byte 243,69,15,91,209 // cvttps2dq %xmm9,%xmm10 + .byte 69,15,91,210 // cvtdq2ps %xmm10,%xmm10 + .byte 69,15,40,217 // movaps %xmm9,%xmm11 + .byte 69,15,194,218,1 // cmpltps %xmm10,%xmm11 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,225 // movd %ecx,%xmm12 + .byte 69,15,198,228,0 // shufps $0x0,%xmm12,%xmm12 + .byte 69,15,84,220 // andps %xmm12,%xmm11 + .byte 69,15,92,211 // subps %xmm11,%xmm10 + .byte 69,15,92,202 // subps %xmm10,%xmm9 + .byte 68,15,88,193 // addps %xmm1,%xmm8 + .byte 243,69,15,91,208 // cvttps2dq %xmm8,%xmm10 + .byte 69,15,91,210 // cvtdq2ps %xmm10,%xmm10 + .byte 69,15,40,216 // movaps %xmm8,%xmm11 + .byte 69,15,194,218,1 // cmpltps %xmm10,%xmm11 + .byte 69,15,84,220 // andps %xmm12,%xmm11 + .byte 69,15,92,211 // subps %xmm11,%xmm10 + .byte 69,15,92,194 // subps %xmm10,%xmm8 + .byte 15,17,0 // movups %xmm0,(%rax) + .byte 15,17,72,32 // movups %xmm1,0x20(%rax) + .byte 68,15,17,72,64 // movups %xmm9,0x40(%rax) + .byte 68,15,17,64,96 // movups %xmm8,0x60(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_accumulate_sse2 +.globl _sk_accumulate_sse2 +_sk_accumulate_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 68,15,16,128,128,0,0,0 // movups 0x80(%rax),%xmm8 + .byte 68,15,16,136,160,0,0,0 // movups 0xa0(%rax),%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 68,15,89,192 // mulps %xmm0,%xmm8 + .byte 65,15,88,224 // addps %xmm8,%xmm4 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 68,15,89,193 // mulps %xmm1,%xmm8 + .byte 65,15,88,232 // addps %xmm8,%xmm5 + .byte 69,15,40,193 // movaps %xmm9,%xmm8 + .byte 68,15,89,194 // mulps %xmm2,%xmm8 + .byte 65,15,88,240 // addps %xmm8,%xmm6 + .byte 68,15,89,203 // mulps %xmm3,%xmm9 + .byte 65,15,88,249 // addps %xmm9,%xmm7 + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_nx_sse2 +.globl _sk_bilinear_nx_sse2 +_sk_bilinear_nx_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,191 // mov $0xbf000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 68,15,17,128,128,0,0,0 // movups %xmm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_px_sse2 +.globl _sk_bilinear_px_sse2 +_sk_bilinear_px_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 68,15,17,136,128,0,0,0 // movups %xmm9,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_ny_sse2 +.globl _sk_bilinear_ny_sse2 +_sk_bilinear_ny_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,191 // mov $0xbf000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 68,15,17,128,160,0,0,0 // movups %xmm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bilinear_py_sse2 +.globl _sk_bilinear_py_sse2 +_sk_bilinear_py_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 68,15,17,136,160,0,0,0 // movups %xmm9,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n3x_sse2 +.globl _sk_bicubic_n3x_sse2 +_sk_bicubic_n3x_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,192,191 // mov $0xbfc00000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 185,114,28,199,62 // mov $0x3ec71c72,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 185,171,170,170,190 // mov $0xbeaaaaab,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,89,192 // mulps %xmm8,%xmm8 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 68,15,17,136,128,0,0,0 // movups %xmm9,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n1x_sse2 +.globl _sk_bicubic_n1x_sse2 +_sk_bicubic_n1x_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,191 // mov $0xbf000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 185,85,85,149,191 // mov $0xbf955555,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 185,57,142,99,61 // mov $0x3d638e39,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 68,15,17,136,128,0,0,0 // movups %xmm9,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p1x_sse2 +.globl _sk_bicubic_p1x_sse2 +_sk_bicubic_p1x_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 185,85,85,149,191 // mov $0xbf955555,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,217 // movd %ecx,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,208 // addps %xmm8,%xmm10 + .byte 185,57,142,99,61 // mov $0x3d638e39,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,208 // addps %xmm8,%xmm10 + .byte 68,15,17,144,128,0,0,0 // movups %xmm10,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p3x_sse2 +.globl _sk_bicubic_p3x_sse2 +_sk_bicubic_p3x_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,0 // movups (%rax),%xmm0 + .byte 68,15,16,72,64 // movups 0x40(%rax),%xmm9 + .byte 65,15,88,192 // addps %xmm8,%xmm0 + .byte 185,114,28,199,62 // mov $0x3ec71c72,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,89,193 // mulps %xmm9,%xmm8 + .byte 69,15,89,201 // mulps %xmm9,%xmm9 + .byte 185,171,170,170,190 // mov $0xbeaaaaab,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,88,194 // addps %xmm10,%xmm8 + .byte 69,15,89,193 // mulps %xmm9,%xmm8 + .byte 68,15,17,128,128,0,0,0 // movups %xmm8,0x80(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n3y_sse2 +.globl _sk_bicubic_n3y_sse2 +_sk_bicubic_n3y_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,192,191 // mov $0xbfc00000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 185,114,28,199,62 // mov $0x3ec71c72,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 185,171,170,170,190 // mov $0xbeaaaaab,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,89,192 // mulps %xmm8,%xmm8 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 68,15,17,136,160,0,0,0 // movups %xmm9,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_n1y_sse2 +.globl _sk_bicubic_n1y_sse2 +_sk_bicubic_n1y_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,191 // mov $0xbf000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 185,0,0,128,63 // mov $0x3f800000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,92,193 // subps %xmm9,%xmm8 + .byte 185,85,85,149,191 // mov $0xbf955555,%ecx + .byte 102,68,15,110,201 // movd %ecx,%xmm9 + .byte 69,15,198,201,0 // shufps $0x0,%xmm9,%xmm9 + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 185,57,142,99,61 // mov $0x3d638e39,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,89,200 // mulps %xmm8,%xmm9 + .byte 69,15,88,202 // addps %xmm10,%xmm9 + .byte 68,15,17,136,160,0,0,0 // movups %xmm9,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p1y_sse2 +.globl _sk_bicubic_p1y_sse2 +_sk_bicubic_p1y_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,0,63 // mov $0x3f000000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 185,85,85,149,191 // mov $0xbf955555,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,217 // movd %ecx,%xmm11 + .byte 69,15,198,219,0 // shufps $0x0,%xmm11,%xmm11 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,211 // addps %xmm11,%xmm10 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,208 // addps %xmm8,%xmm10 + .byte 185,57,142,99,61 // mov $0x3d638e39,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,89,209 // mulps %xmm9,%xmm10 + .byte 69,15,88,208 // addps %xmm8,%xmm10 + .byte 68,15,17,144,160,0,0,0 // movups %xmm10,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax + +HIDDEN _sk_bicubic_p3y_sse2 +.globl _sk_bicubic_p3y_sse2 +_sk_bicubic_p3y_sse2: + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 185,0,0,192,63 // mov $0x3fc00000,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 15,16,72,32 // movups 0x20(%rax),%xmm1 + .byte 68,15,16,72,96 // movups 0x60(%rax),%xmm9 + .byte 65,15,88,200 // addps %xmm8,%xmm1 + .byte 185,114,28,199,62 // mov $0x3ec71c72,%ecx + .byte 102,68,15,110,193 // movd %ecx,%xmm8 + .byte 69,15,198,192,0 // shufps $0x0,%xmm8,%xmm8 + .byte 69,15,89,193 // mulps %xmm9,%xmm8 + .byte 69,15,89,201 // mulps %xmm9,%xmm9 + .byte 185,171,170,170,190 // mov $0xbeaaaaab,%ecx + .byte 102,68,15,110,209 // movd %ecx,%xmm10 + .byte 69,15,198,210,0 // shufps $0x0,%xmm10,%xmm10 + .byte 69,15,88,194 // addps %xmm10,%xmm8 + .byte 69,15,89,193 // mulps %xmm9,%xmm8 + .byte 68,15,17,128,160,0,0,0 // movups %xmm8,0xa0(%rax) + .byte 72,173 // lods %ds:(%rsi),%rax + .byte 255,224 // jmpq *%rax +#endif diff --git a/gfx/skia/skia/src/jumper/SkJumper_generated_win.S b/gfx/skia/skia/src/jumper/SkJumper_generated_win.S new file mode 100644 index 000000000000..b305f2394379 --- /dev/null +++ b/gfx/skia/skia/src/jumper/SkJumper_generated_win.S @@ -0,0 +1,15230 @@ +; Copyright 2017 Google Inc. +; +; Use of this source code is governed by a BSD-style license that can be +; found in the LICENSE file. + +; This file is generated semi-automatically with this command: +; $ src/jumper/build_stages.py + +IFDEF RAX +_text SEGMENT + +PUBLIC _sk_start_pipeline_hsw +_sk_start_pipeline_hsw LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 86 ; push %rsi + DB 87 ; push %rdi + DB 83 ; push %rbx + DB 72,129,236,160,0,0,0 ; sub $0xa0,%rsp + DB 197,120,41,188,36,144,0,0,0 ; vmovaps %xmm15,0x90(%rsp) + DB 197,120,41,180,36,128,0,0,0 ; vmovaps %xmm14,0x80(%rsp) + DB 197,120,41,108,36,112 ; vmovaps %xmm13,0x70(%rsp) + DB 197,120,41,100,36,96 ; vmovaps %xmm12,0x60(%rsp) + DB 197,120,41,92,36,80 ; vmovaps %xmm11,0x50(%rsp) + DB 197,120,41,84,36,64 ; vmovaps %xmm10,0x40(%rsp) + DB 197,120,41,76,36,48 ; vmovaps %xmm9,0x30(%rsp) + DB 197,120,41,68,36,32 ; vmovaps %xmm8,0x20(%rsp) + DB 197,248,41,124,36,16 ; vmovaps %xmm7,0x10(%rsp) + DB 197,248,41,52,36 ; vmovaps %xmm6,(%rsp) + DB 77,137,205 ; mov %r9,%r13 + DB 77,137,198 ; mov %r8,%r14 + DB 72,137,203 ; mov %rcx,%rbx + DB 72,137,214 ; mov %rdx,%rsi + DB 72,173 ; lods %ds:(%rsi),%rax + DB 73,137,199 ; mov %rax,%r15 + DB 73,137,244 ; mov %rsi,%r12 + DB 72,141,67,8 ; lea 0x8(%rbx),%rax + DB 76,57,232 ; cmp %r13,%rax + DB 118,5 ; jbe 75 <_sk_start_pipeline_hsw+0x75> + DB 72,137,223 ; mov %rbx,%rdi + DB 235,65 ; jmp b6 <_sk_start_pipeline_hsw+0xb6> + DB 185,0,0,0,0 ; mov $0x0,%ecx + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 197,228,87,219 ; vxorps %ymm3,%ymm3,%ymm3 + DB 197,220,87,228 ; vxorps %ymm4,%ymm4,%ymm4 + DB 197,212,87,237 ; vxorps %ymm5,%ymm5,%ymm5 + DB 197,204,87,246 ; vxorps %ymm6,%ymm6,%ymm6 + DB 197,196,87,255 ; vxorps %ymm7,%ymm7,%ymm7 + DB 72,137,223 ; mov %rbx,%rdi + DB 76,137,230 ; mov %r12,%rsi + DB 76,137,242 ; mov %r14,%rdx + DB 65,255,215 ; callq *%r15 + DB 72,141,123,8 ; lea 0x8(%rbx),%rdi + DB 72,131,195,16 ; add $0x10,%rbx + DB 76,57,235 ; cmp %r13,%rbx + DB 72,137,251 ; mov %rdi,%rbx + DB 118,191 ; jbe 75 <_sk_start_pipeline_hsw+0x75> + DB 76,137,233 ; mov %r13,%rcx + DB 72,41,249 ; sub %rdi,%rcx + DB 116,41 ; je e7 <_sk_start_pipeline_hsw+0xe7> + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 197,228,87,219 ; vxorps %ymm3,%ymm3,%ymm3 + DB 197,220,87,228 ; vxorps %ymm4,%ymm4,%ymm4 + DB 197,212,87,237 ; vxorps %ymm5,%ymm5,%ymm5 + DB 197,204,87,246 ; vxorps %ymm6,%ymm6,%ymm6 + DB 197,196,87,255 ; vxorps %ymm7,%ymm7,%ymm7 + DB 76,137,230 ; mov %r12,%rsi + DB 76,137,242 ; mov %r14,%rdx + DB 65,255,215 ; callq *%r15 + DB 76,137,232 ; mov %r13,%rax + DB 197,248,40,52,36 ; vmovaps (%rsp),%xmm6 + DB 197,248,40,124,36,16 ; vmovaps 0x10(%rsp),%xmm7 + DB 197,120,40,68,36,32 ; vmovaps 0x20(%rsp),%xmm8 + DB 197,120,40,76,36,48 ; vmovaps 0x30(%rsp),%xmm9 + DB 197,120,40,84,36,64 ; vmovaps 0x40(%rsp),%xmm10 + DB 197,120,40,92,36,80 ; vmovaps 0x50(%rsp),%xmm11 + DB 197,120,40,100,36,96 ; vmovaps 0x60(%rsp),%xmm12 + DB 197,120,40,108,36,112 ; vmovaps 0x70(%rsp),%xmm13 + DB 197,120,40,180,36,128,0,0,0 ; vmovaps 0x80(%rsp),%xmm14 + DB 197,120,40,188,36,144,0,0,0 ; vmovaps 0x90(%rsp),%xmm15 + DB 72,129,196,160,0,0,0 ; add $0xa0,%rsp + DB 91 ; pop %rbx + DB 95 ; pop %rdi + DB 94 ; pop %rsi + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 197,248,119 ; vzeroupper + DB 195 ; retq + +PUBLIC _sk_just_return_hsw +_sk_just_return_hsw LABEL PROC + DB 195 ; retq + +PUBLIC _sk_seed_shader_hsw +_sk_seed_shader_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,249,110,199 ; vmovd %edi,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,252,88,193 ; vaddps %ymm1,%ymm0,%ymm0 + DB 197,252,88,2 ; vaddps (%rdx),%ymm0,%ymm0 + DB 196,226,125,24,16 ; vbroadcastss (%rax),%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 197,236,88,201 ; vaddps %ymm1,%ymm2,%ymm1 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,226,125,88,210 ; vpbroadcastd %xmm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,228,87,219 ; vxorps %ymm3,%ymm3,%ymm3 + DB 197,220,87,228 ; vxorps %ymm4,%ymm4,%ymm4 + DB 197,212,87,237 ; vxorps %ymm5,%ymm5,%ymm5 + DB 197,204,87,246 ; vxorps %ymm6,%ymm6,%ymm6 + DB 197,196,87,255 ; vxorps %ymm7,%ymm7,%ymm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_constant_color_hsw +_sk_constant_color_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,226,125,24,0 ; vbroadcastss (%rax),%ymm0 + DB 196,226,125,24,72,4 ; vbroadcastss 0x4(%rax),%ymm1 + DB 196,226,125,24,80,8 ; vbroadcastss 0x8(%rax),%ymm2 + DB 196,226,125,24,88,12 ; vbroadcastss 0xc(%rax),%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clear_hsw +_sk_clear_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 197,228,87,219 ; vxorps %ymm3,%ymm3,%ymm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcatop_hsw +_sk_srcatop_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,204 ; vmulps %ymm4,%ymm8,%ymm9 + DB 196,194,69,168,193 ; vfmadd213ps %ymm9,%ymm7,%ymm0 + DB 197,60,89,205 ; vmulps %ymm5,%ymm8,%ymm9 + DB 196,194,69,168,201 ; vfmadd213ps %ymm9,%ymm7,%ymm1 + DB 197,60,89,206 ; vmulps %ymm6,%ymm8,%ymm9 + DB 196,194,69,168,209 ; vfmadd213ps %ymm9,%ymm7,%ymm2 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 196,194,69,168,216 ; vfmadd213ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstatop_hsw +_sk_dstatop_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,199 ; vsubps %ymm7,%ymm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 196,226,101,184,196 ; vfmadd231ps %ymm4,%ymm3,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 196,226,101,184,205 ; vfmadd231ps %ymm5,%ymm3,%ymm1 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 196,226,101,184,214 ; vfmadd231ps %ymm6,%ymm3,%ymm2 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 196,194,69,168,216 ; vfmadd213ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcin_hsw +_sk_srcin_hsw LABEL PROC + DB 197,252,89,199 ; vmulps %ymm7,%ymm0,%ymm0 + DB 197,244,89,207 ; vmulps %ymm7,%ymm1,%ymm1 + DB 197,236,89,215 ; vmulps %ymm7,%ymm2,%ymm2 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstin_hsw +_sk_dstin_hsw LABEL PROC + DB 197,228,89,196 ; vmulps %ymm4,%ymm3,%ymm0 + DB 197,228,89,205 ; vmulps %ymm5,%ymm3,%ymm1 + DB 197,228,89,214 ; vmulps %ymm6,%ymm3,%ymm2 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcout_hsw +_sk_srcout_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,199 ; vsubps %ymm7,%ymm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstout_hsw +_sk_dstout_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 197,252,92,219 ; vsubps %ymm3,%ymm0,%ymm3 + DB 197,228,89,196 ; vmulps %ymm4,%ymm3,%ymm0 + DB 197,228,89,205 ; vmulps %ymm5,%ymm3,%ymm1 + DB 197,228,89,214 ; vmulps %ymm6,%ymm3,%ymm2 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcover_hsw +_sk_srcover_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 196,194,93,184,192 ; vfmadd231ps %ymm8,%ymm4,%ymm0 + DB 196,194,85,184,200 ; vfmadd231ps %ymm8,%ymm5,%ymm1 + DB 196,194,77,184,208 ; vfmadd231ps %ymm8,%ymm6,%ymm2 + DB 196,194,69,184,216 ; vfmadd231ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstover_hsw +_sk_dstover_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,199 ; vsubps %ymm7,%ymm8,%ymm8 + DB 196,226,61,168,196 ; vfmadd213ps %ymm4,%ymm8,%ymm0 + DB 196,226,61,168,205 ; vfmadd213ps %ymm5,%ymm8,%ymm1 + DB 196,226,61,168,214 ; vfmadd213ps %ymm6,%ymm8,%ymm2 + DB 196,226,61,168,223 ; vfmadd213ps %ymm7,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_modulate_hsw +_sk_modulate_hsw LABEL PROC + DB 197,252,89,196 ; vmulps %ymm4,%ymm0,%ymm0 + DB 197,244,89,205 ; vmulps %ymm5,%ymm1,%ymm1 + DB 197,236,89,214 ; vmulps %ymm6,%ymm2,%ymm2 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_multiply_hsw +_sk_multiply_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,207 ; vsubps %ymm7,%ymm8,%ymm9 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,212 ; vmulps %ymm4,%ymm8,%ymm10 + DB 196,98,53,184,208 ; vfmadd231ps %ymm0,%ymm9,%ymm10 + DB 196,194,93,168,194 ; vfmadd213ps %ymm10,%ymm4,%ymm0 + DB 197,52,89,209 ; vmulps %ymm1,%ymm9,%ymm10 + DB 196,98,61,184,213 ; vfmadd231ps %ymm5,%ymm8,%ymm10 + DB 196,194,85,168,202 ; vfmadd213ps %ymm10,%ymm5,%ymm1 + DB 197,52,89,210 ; vmulps %ymm2,%ymm9,%ymm10 + DB 196,98,61,184,214 ; vfmadd231ps %ymm6,%ymm8,%ymm10 + DB 196,194,77,168,210 ; vfmadd213ps %ymm10,%ymm6,%ymm2 + DB 197,52,89,203 ; vmulps %ymm3,%ymm9,%ymm9 + DB 196,66,69,168,193 ; vfmadd213ps %ymm9,%ymm7,%ymm8 + DB 196,194,69,168,216 ; vfmadd213ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_plus__hsw +_sk_plus__hsw LABEL PROC + DB 197,252,88,196 ; vaddps %ymm4,%ymm0,%ymm0 + DB 197,244,88,205 ; vaddps %ymm5,%ymm1,%ymm1 + DB 197,236,88,214 ; vaddps %ymm6,%ymm2,%ymm2 + DB 197,228,88,223 ; vaddps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_screen_hsw +_sk_screen_hsw LABEL PROC + DB 197,124,88,196 ; vaddps %ymm4,%ymm0,%ymm8 + DB 196,194,93,172,192 ; vfnmadd213ps %ymm8,%ymm4,%ymm0 + DB 197,116,88,197 ; vaddps %ymm5,%ymm1,%ymm8 + DB 196,194,85,172,200 ; vfnmadd213ps %ymm8,%ymm5,%ymm1 + DB 197,108,88,198 ; vaddps %ymm6,%ymm2,%ymm8 + DB 196,194,77,172,208 ; vfnmadd213ps %ymm8,%ymm6,%ymm2 + DB 197,100,88,199 ; vaddps %ymm7,%ymm3,%ymm8 + DB 196,194,69,172,216 ; vfnmadd213ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_xor__hsw +_sk_xor__hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,207 ; vsubps %ymm7,%ymm8,%ymm9 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,212 ; vmulps %ymm4,%ymm8,%ymm10 + DB 196,194,53,168,194 ; vfmadd213ps %ymm10,%ymm9,%ymm0 + DB 197,180,89,201 ; vmulps %ymm1,%ymm9,%ymm1 + DB 196,226,61,184,205 ; vfmadd231ps %ymm5,%ymm8,%ymm1 + DB 197,180,89,210 ; vmulps %ymm2,%ymm9,%ymm2 + DB 196,226,61,184,214 ; vfmadd231ps %ymm6,%ymm8,%ymm2 + DB 197,180,89,219 ; vmulps %ymm3,%ymm9,%ymm3 + DB 196,98,69,168,195 ; vfmadd213ps %ymm3,%ymm7,%ymm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,195 ; vmovaps %ymm8,%ymm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_darken_hsw +_sk_darken_hsw LABEL PROC + DB 197,124,88,196 ; vaddps %ymm4,%ymm0,%ymm8 + DB 197,252,89,199 ; vmulps %ymm7,%ymm0,%ymm0 + DB 197,100,89,204 ; vmulps %ymm4,%ymm3,%ymm9 + DB 196,193,124,95,193 ; vmaxps %ymm9,%ymm0,%ymm0 + DB 197,188,92,192 ; vsubps %ymm0,%ymm8,%ymm0 + DB 197,116,88,197 ; vaddps %ymm5,%ymm1,%ymm8 + DB 197,244,89,207 ; vmulps %ymm7,%ymm1,%ymm1 + DB 197,100,89,205 ; vmulps %ymm5,%ymm3,%ymm9 + DB 196,193,116,95,201 ; vmaxps %ymm9,%ymm1,%ymm1 + DB 197,188,92,201 ; vsubps %ymm1,%ymm8,%ymm1 + DB 197,108,88,198 ; vaddps %ymm6,%ymm2,%ymm8 + DB 197,236,89,215 ; vmulps %ymm7,%ymm2,%ymm2 + DB 197,100,89,206 ; vmulps %ymm6,%ymm3,%ymm9 + DB 196,193,108,95,209 ; vmaxps %ymm9,%ymm2,%ymm2 + DB 197,188,92,210 ; vsubps %ymm2,%ymm8,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 196,194,69,184,216 ; vfmadd231ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lighten_hsw +_sk_lighten_hsw LABEL PROC + DB 197,124,88,196 ; vaddps %ymm4,%ymm0,%ymm8 + DB 197,252,89,199 ; vmulps %ymm7,%ymm0,%ymm0 + DB 197,100,89,204 ; vmulps %ymm4,%ymm3,%ymm9 + DB 196,193,124,93,193 ; vminps %ymm9,%ymm0,%ymm0 + DB 197,188,92,192 ; vsubps %ymm0,%ymm8,%ymm0 + DB 197,116,88,197 ; vaddps %ymm5,%ymm1,%ymm8 + DB 197,244,89,207 ; vmulps %ymm7,%ymm1,%ymm1 + DB 197,100,89,205 ; vmulps %ymm5,%ymm3,%ymm9 + DB 196,193,116,93,201 ; vminps %ymm9,%ymm1,%ymm1 + DB 197,188,92,201 ; vsubps %ymm1,%ymm8,%ymm1 + DB 197,108,88,198 ; vaddps %ymm6,%ymm2,%ymm8 + DB 197,236,89,215 ; vmulps %ymm7,%ymm2,%ymm2 + DB 197,100,89,206 ; vmulps %ymm6,%ymm3,%ymm9 + DB 196,193,108,93,209 ; vminps %ymm9,%ymm2,%ymm2 + DB 197,188,92,210 ; vsubps %ymm2,%ymm8,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 196,194,69,184,216 ; vfmadd231ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_difference_hsw +_sk_difference_hsw LABEL PROC + DB 197,124,88,196 ; vaddps %ymm4,%ymm0,%ymm8 + DB 197,252,89,199 ; vmulps %ymm7,%ymm0,%ymm0 + DB 197,100,89,204 ; vmulps %ymm4,%ymm3,%ymm9 + DB 196,193,124,93,193 ; vminps %ymm9,%ymm0,%ymm0 + DB 197,252,88,192 ; vaddps %ymm0,%ymm0,%ymm0 + DB 197,188,92,192 ; vsubps %ymm0,%ymm8,%ymm0 + DB 197,116,88,197 ; vaddps %ymm5,%ymm1,%ymm8 + DB 197,244,89,207 ; vmulps %ymm7,%ymm1,%ymm1 + DB 197,100,89,205 ; vmulps %ymm5,%ymm3,%ymm9 + DB 196,193,116,93,201 ; vminps %ymm9,%ymm1,%ymm1 + DB 197,244,88,201 ; vaddps %ymm1,%ymm1,%ymm1 + DB 197,188,92,201 ; vsubps %ymm1,%ymm8,%ymm1 + DB 197,108,88,198 ; vaddps %ymm6,%ymm2,%ymm8 + DB 197,236,89,215 ; vmulps %ymm7,%ymm2,%ymm2 + DB 197,100,89,206 ; vmulps %ymm6,%ymm3,%ymm9 + DB 196,193,108,93,209 ; vminps %ymm9,%ymm2,%ymm2 + DB 197,236,88,210 ; vaddps %ymm2,%ymm2,%ymm2 + DB 197,188,92,210 ; vsubps %ymm2,%ymm8,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 196,194,69,184,216 ; vfmadd231ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_exclusion_hsw +_sk_exclusion_hsw LABEL PROC + DB 197,124,88,196 ; vaddps %ymm4,%ymm0,%ymm8 + DB 197,252,89,196 ; vmulps %ymm4,%ymm0,%ymm0 + DB 197,252,88,192 ; vaddps %ymm0,%ymm0,%ymm0 + DB 197,188,92,192 ; vsubps %ymm0,%ymm8,%ymm0 + DB 197,116,88,197 ; vaddps %ymm5,%ymm1,%ymm8 + DB 197,244,89,205 ; vmulps %ymm5,%ymm1,%ymm1 + DB 197,244,88,201 ; vaddps %ymm1,%ymm1,%ymm1 + DB 197,188,92,201 ; vsubps %ymm1,%ymm8,%ymm1 + DB 197,108,88,198 ; vaddps %ymm6,%ymm2,%ymm8 + DB 197,236,89,214 ; vmulps %ymm6,%ymm2,%ymm2 + DB 197,236,88,210 ; vaddps %ymm2,%ymm2,%ymm2 + DB 197,188,92,210 ; vsubps %ymm2,%ymm8,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 196,194,69,184,216 ; vfmadd231ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_colorburn_hsw +_sk_colorburn_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,207 ; vsubps %ymm7,%ymm8,%ymm9 + DB 197,52,89,216 ; vmulps %ymm0,%ymm9,%ymm11 + DB 196,65,44,87,210 ; vxorps %ymm10,%ymm10,%ymm10 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,228 ; vmulps %ymm4,%ymm8,%ymm12 + DB 197,68,92,236 ; vsubps %ymm4,%ymm7,%ymm13 + DB 197,20,89,235 ; vmulps %ymm3,%ymm13,%ymm13 + DB 197,20,94,232 ; vdivps %ymm0,%ymm13,%ymm13 + DB 196,65,68,93,237 ; vminps %ymm13,%ymm7,%ymm13 + DB 196,65,68,92,237 ; vsubps %ymm13,%ymm7,%ymm13 + DB 196,66,101,168,235 ; vfmadd213ps %ymm11,%ymm3,%ymm13 + DB 196,65,28,88,237 ; vaddps %ymm13,%ymm12,%ymm13 + DB 197,28,88,224 ; vaddps %ymm0,%ymm12,%ymm12 + DB 196,193,124,194,194,0 ; vcmpeqps %ymm10,%ymm0,%ymm0 + DB 196,195,21,74,196,0 ; vblendvps %ymm0,%ymm12,%ymm13,%ymm0 + DB 197,92,194,231,0 ; vcmpeqps %ymm7,%ymm4,%ymm12 + DB 197,36,88,220 ; vaddps %ymm4,%ymm11,%ymm11 + DB 196,195,125,74,195,192 ; vblendvps %ymm12,%ymm11,%ymm0,%ymm0 + DB 197,52,89,217 ; vmulps %ymm1,%ymm9,%ymm11 + DB 197,60,89,229 ; vmulps %ymm5,%ymm8,%ymm12 + DB 197,68,92,237 ; vsubps %ymm5,%ymm7,%ymm13 + DB 197,20,89,235 ; vmulps %ymm3,%ymm13,%ymm13 + DB 197,20,94,233 ; vdivps %ymm1,%ymm13,%ymm13 + DB 196,65,68,93,237 ; vminps %ymm13,%ymm7,%ymm13 + DB 196,65,68,92,237 ; vsubps %ymm13,%ymm7,%ymm13 + DB 196,66,101,168,235 ; vfmadd213ps %ymm11,%ymm3,%ymm13 + DB 196,65,28,88,237 ; vaddps %ymm13,%ymm12,%ymm13 + DB 197,28,88,225 ; vaddps %ymm1,%ymm12,%ymm12 + DB 196,193,116,194,202,0 ; vcmpeqps %ymm10,%ymm1,%ymm1 + DB 196,195,21,74,204,16 ; vblendvps %ymm1,%ymm12,%ymm13,%ymm1 + DB 197,84,194,231,0 ; vcmpeqps %ymm7,%ymm5,%ymm12 + DB 197,36,88,221 ; vaddps %ymm5,%ymm11,%ymm11 + DB 196,195,117,74,203,192 ; vblendvps %ymm12,%ymm11,%ymm1,%ymm1 + DB 197,52,89,202 ; vmulps %ymm2,%ymm9,%ymm9 + DB 196,65,108,194,210,0 ; vcmpeqps %ymm10,%ymm2,%ymm10 + DB 197,60,89,222 ; vmulps %ymm6,%ymm8,%ymm11 + DB 197,68,92,230 ; vsubps %ymm6,%ymm7,%ymm12 + DB 197,28,89,227 ; vmulps %ymm3,%ymm12,%ymm12 + DB 197,28,94,226 ; vdivps %ymm2,%ymm12,%ymm12 + DB 197,164,88,210 ; vaddps %ymm2,%ymm11,%ymm2 + DB 196,65,68,93,228 ; vminps %ymm12,%ymm7,%ymm12 + DB 196,65,68,92,228 ; vsubps %ymm12,%ymm7,%ymm12 + DB 196,66,101,168,225 ; vfmadd213ps %ymm9,%ymm3,%ymm12 + DB 196,65,36,88,220 ; vaddps %ymm12,%ymm11,%ymm11 + DB 196,227,37,74,210,160 ; vblendvps %ymm10,%ymm2,%ymm11,%ymm2 + DB 197,76,194,215,0 ; vcmpeqps %ymm7,%ymm6,%ymm10 + DB 197,52,88,206 ; vaddps %ymm6,%ymm9,%ymm9 + DB 196,195,109,74,209,160 ; vblendvps %ymm10,%ymm9,%ymm2,%ymm2 + DB 196,194,69,184,216 ; vfmadd231ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_colordodge_hsw +_sk_colordodge_hsw LABEL PROC + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 196,66,125,88,201 ; vpbroadcastd %xmm9,%ymm9 + DB 197,52,92,215 ; vsubps %ymm7,%ymm9,%ymm10 + DB 197,44,89,216 ; vmulps %ymm0,%ymm10,%ymm11 + DB 197,52,92,203 ; vsubps %ymm3,%ymm9,%ymm9 + DB 197,100,89,228 ; vmulps %ymm4,%ymm3,%ymm12 + DB 197,100,92,232 ; vsubps %ymm0,%ymm3,%ymm13 + DB 196,65,28,94,229 ; vdivps %ymm13,%ymm12,%ymm12 + DB 197,52,89,236 ; vmulps %ymm4,%ymm9,%ymm13 + DB 196,65,68,93,228 ; vminps %ymm12,%ymm7,%ymm12 + DB 196,66,101,168,227 ; vfmadd213ps %ymm11,%ymm3,%ymm12 + DB 196,65,20,88,228 ; vaddps %ymm12,%ymm13,%ymm12 + DB 197,20,88,232 ; vaddps %ymm0,%ymm13,%ymm13 + DB 197,252,194,195,0 ; vcmpeqps %ymm3,%ymm0,%ymm0 + DB 196,195,29,74,197,0 ; vblendvps %ymm0,%ymm13,%ymm12,%ymm0 + DB 196,65,92,194,224,0 ; vcmpeqps %ymm8,%ymm4,%ymm12 + DB 197,36,88,220 ; vaddps %ymm4,%ymm11,%ymm11 + DB 196,195,125,74,195,192 ; vblendvps %ymm12,%ymm11,%ymm0,%ymm0 + DB 197,44,89,217 ; vmulps %ymm1,%ymm10,%ymm11 + DB 197,100,89,229 ; vmulps %ymm5,%ymm3,%ymm12 + DB 197,100,92,233 ; vsubps %ymm1,%ymm3,%ymm13 + DB 196,65,28,94,229 ; vdivps %ymm13,%ymm12,%ymm12 + DB 197,52,89,237 ; vmulps %ymm5,%ymm9,%ymm13 + DB 196,65,68,93,228 ; vminps %ymm12,%ymm7,%ymm12 + DB 196,66,101,168,227 ; vfmadd213ps %ymm11,%ymm3,%ymm12 + DB 196,65,20,88,228 ; vaddps %ymm12,%ymm13,%ymm12 + DB 197,20,88,233 ; vaddps %ymm1,%ymm13,%ymm13 + DB 197,244,194,203,0 ; vcmpeqps %ymm3,%ymm1,%ymm1 + DB 196,195,29,74,205,16 ; vblendvps %ymm1,%ymm13,%ymm12,%ymm1 + DB 196,65,84,194,224,0 ; vcmpeqps %ymm8,%ymm5,%ymm12 + DB 197,36,88,221 ; vaddps %ymm5,%ymm11,%ymm11 + DB 196,195,117,74,203,192 ; vblendvps %ymm12,%ymm11,%ymm1,%ymm1 + DB 197,44,89,210 ; vmulps %ymm2,%ymm10,%ymm10 + DB 197,100,89,222 ; vmulps %ymm6,%ymm3,%ymm11 + DB 197,100,92,226 ; vsubps %ymm2,%ymm3,%ymm12 + DB 196,65,36,94,220 ; vdivps %ymm12,%ymm11,%ymm11 + DB 197,52,89,230 ; vmulps %ymm6,%ymm9,%ymm12 + DB 196,65,68,93,219 ; vminps %ymm11,%ymm7,%ymm11 + DB 196,66,101,168,218 ; vfmadd213ps %ymm10,%ymm3,%ymm11 + DB 196,65,28,88,219 ; vaddps %ymm11,%ymm12,%ymm11 + DB 197,28,88,226 ; vaddps %ymm2,%ymm12,%ymm12 + DB 197,236,194,211,0 ; vcmpeqps %ymm3,%ymm2,%ymm2 + DB 196,195,37,74,212,32 ; vblendvps %ymm2,%ymm12,%ymm11,%ymm2 + DB 196,65,76,194,192,0 ; vcmpeqps %ymm8,%ymm6,%ymm8 + DB 197,44,88,214 ; vaddps %ymm6,%ymm10,%ymm10 + DB 196,195,109,74,210,128 ; vblendvps %ymm8,%ymm10,%ymm2,%ymm2 + DB 196,194,69,184,217 ; vfmadd231ps %ymm9,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_hardlight_hsw +_sk_hardlight_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,215 ; vsubps %ymm7,%ymm8,%ymm10 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,220 ; vmulps %ymm4,%ymm8,%ymm11 + DB 196,98,45,184,216 ; vfmadd231ps %ymm0,%ymm10,%ymm11 + DB 197,124,88,200 ; vaddps %ymm0,%ymm0,%ymm9 + DB 197,52,194,227,2 ; vcmpleps %ymm3,%ymm9,%ymm12 + DB 197,124,89,204 ; vmulps %ymm4,%ymm0,%ymm9 + DB 196,65,52,88,233 ; vaddps %ymm9,%ymm9,%ymm13 + DB 197,100,89,207 ; vmulps %ymm7,%ymm3,%ymm9 + DB 197,68,92,244 ; vsubps %ymm4,%ymm7,%ymm14 + DB 197,228,92,192 ; vsubps %ymm0,%ymm3,%ymm0 + DB 196,193,124,89,198 ; vmulps %ymm14,%ymm0,%ymm0 + DB 197,252,88,192 ; vaddps %ymm0,%ymm0,%ymm0 + DB 197,180,92,192 ; vsubps %ymm0,%ymm9,%ymm0 + DB 196,195,125,74,197,192 ; vblendvps %ymm12,%ymm13,%ymm0,%ymm0 + DB 196,193,124,88,195 ; vaddps %ymm11,%ymm0,%ymm0 + DB 197,44,89,217 ; vmulps %ymm1,%ymm10,%ymm11 + DB 196,98,61,184,221 ; vfmadd231ps %ymm5,%ymm8,%ymm11 + DB 197,116,88,225 ; vaddps %ymm1,%ymm1,%ymm12 + DB 197,28,194,227,2 ; vcmpleps %ymm3,%ymm12,%ymm12 + DB 197,116,89,237 ; vmulps %ymm5,%ymm1,%ymm13 + DB 196,65,20,88,237 ; vaddps %ymm13,%ymm13,%ymm13 + DB 197,68,92,245 ; vsubps %ymm5,%ymm7,%ymm14 + DB 197,228,92,201 ; vsubps %ymm1,%ymm3,%ymm1 + DB 196,193,116,89,206 ; vmulps %ymm14,%ymm1,%ymm1 + DB 197,244,88,201 ; vaddps %ymm1,%ymm1,%ymm1 + DB 197,180,92,201 ; vsubps %ymm1,%ymm9,%ymm1 + DB 196,195,117,74,205,192 ; vblendvps %ymm12,%ymm13,%ymm1,%ymm1 + DB 196,193,116,88,203 ; vaddps %ymm11,%ymm1,%ymm1 + DB 197,44,89,210 ; vmulps %ymm2,%ymm10,%ymm10 + DB 196,98,61,184,214 ; vfmadd231ps %ymm6,%ymm8,%ymm10 + DB 197,108,88,218 ; vaddps %ymm2,%ymm2,%ymm11 + DB 197,36,194,219,2 ; vcmpleps %ymm3,%ymm11,%ymm11 + DB 197,108,89,230 ; vmulps %ymm6,%ymm2,%ymm12 + DB 196,65,28,88,228 ; vaddps %ymm12,%ymm12,%ymm12 + DB 197,68,92,238 ; vsubps %ymm6,%ymm7,%ymm13 + DB 197,228,92,210 ; vsubps %ymm2,%ymm3,%ymm2 + DB 196,193,108,89,213 ; vmulps %ymm13,%ymm2,%ymm2 + DB 197,236,88,210 ; vaddps %ymm2,%ymm2,%ymm2 + DB 197,180,92,210 ; vsubps %ymm2,%ymm9,%ymm2 + DB 196,195,109,74,212,176 ; vblendvps %ymm11,%ymm12,%ymm2,%ymm2 + DB 196,193,108,88,210 ; vaddps %ymm10,%ymm2,%ymm2 + DB 196,194,69,184,216 ; vfmadd231ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_overlay_hsw +_sk_overlay_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,215 ; vsubps %ymm7,%ymm8,%ymm10 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,220 ; vmulps %ymm4,%ymm8,%ymm11 + DB 196,98,45,184,216 ; vfmadd231ps %ymm0,%ymm10,%ymm11 + DB 197,92,88,204 ; vaddps %ymm4,%ymm4,%ymm9 + DB 197,52,194,231,2 ; vcmpleps %ymm7,%ymm9,%ymm12 + DB 197,124,89,204 ; vmulps %ymm4,%ymm0,%ymm9 + DB 196,65,52,88,233 ; vaddps %ymm9,%ymm9,%ymm13 + DB 197,100,89,207 ; vmulps %ymm7,%ymm3,%ymm9 + DB 197,68,92,244 ; vsubps %ymm4,%ymm7,%ymm14 + DB 197,228,92,192 ; vsubps %ymm0,%ymm3,%ymm0 + DB 196,193,124,89,198 ; vmulps %ymm14,%ymm0,%ymm0 + DB 197,252,88,192 ; vaddps %ymm0,%ymm0,%ymm0 + DB 197,180,92,192 ; vsubps %ymm0,%ymm9,%ymm0 + DB 196,195,125,74,197,192 ; vblendvps %ymm12,%ymm13,%ymm0,%ymm0 + DB 196,193,124,88,195 ; vaddps %ymm11,%ymm0,%ymm0 + DB 197,44,89,217 ; vmulps %ymm1,%ymm10,%ymm11 + DB 196,98,61,184,221 ; vfmadd231ps %ymm5,%ymm8,%ymm11 + DB 197,84,88,229 ; vaddps %ymm5,%ymm5,%ymm12 + DB 197,28,194,231,2 ; vcmpleps %ymm7,%ymm12,%ymm12 + DB 197,116,89,237 ; vmulps %ymm5,%ymm1,%ymm13 + DB 196,65,20,88,237 ; vaddps %ymm13,%ymm13,%ymm13 + DB 197,68,92,245 ; vsubps %ymm5,%ymm7,%ymm14 + DB 197,228,92,201 ; vsubps %ymm1,%ymm3,%ymm1 + DB 196,193,116,89,206 ; vmulps %ymm14,%ymm1,%ymm1 + DB 197,244,88,201 ; vaddps %ymm1,%ymm1,%ymm1 + DB 197,180,92,201 ; vsubps %ymm1,%ymm9,%ymm1 + DB 196,195,117,74,205,192 ; vblendvps %ymm12,%ymm13,%ymm1,%ymm1 + DB 196,193,116,88,203 ; vaddps %ymm11,%ymm1,%ymm1 + DB 197,44,89,210 ; vmulps %ymm2,%ymm10,%ymm10 + DB 196,98,61,184,214 ; vfmadd231ps %ymm6,%ymm8,%ymm10 + DB 197,76,88,222 ; vaddps %ymm6,%ymm6,%ymm11 + DB 197,36,194,223,2 ; vcmpleps %ymm7,%ymm11,%ymm11 + DB 197,108,89,230 ; vmulps %ymm6,%ymm2,%ymm12 + DB 196,65,28,88,228 ; vaddps %ymm12,%ymm12,%ymm12 + DB 197,68,92,238 ; vsubps %ymm6,%ymm7,%ymm13 + DB 197,228,92,210 ; vsubps %ymm2,%ymm3,%ymm2 + DB 196,193,108,89,213 ; vmulps %ymm13,%ymm2,%ymm2 + DB 197,236,88,210 ; vaddps %ymm2,%ymm2,%ymm2 + DB 197,180,92,210 ; vsubps %ymm2,%ymm9,%ymm2 + DB 196,195,109,74,212,176 ; vblendvps %ymm11,%ymm12,%ymm2,%ymm2 + DB 196,193,108,88,210 ; vaddps %ymm10,%ymm2,%ymm2 + DB 196,194,69,184,216 ; vfmadd231ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_softlight_hsw +_sk_softlight_hsw LABEL PROC + DB 72,131,236,56 ; sub $0x38,%rsp + DB 197,252,17,20,36 ; vmovups %ymm2,(%rsp) + DB 196,65,44,87,210 ; vxorps %ymm10,%ymm10,%ymm10 + DB 197,44,194,223,1 ; vcmpltps %ymm7,%ymm10,%ymm11 + DB 197,92,94,199 ; vdivps %ymm7,%ymm4,%ymm8 + DB 196,67,45,74,224,176 ; vblendvps %ymm11,%ymm8,%ymm10,%ymm12 + DB 196,65,28,88,196 ; vaddps %ymm12,%ymm12,%ymm8 + DB 196,65,60,88,232 ; vaddps %ymm8,%ymm8,%ymm13 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 196,66,21,168,237 ; vfmadd213ps %ymm13,%ymm13,%ymm13 + DB 196,65,28,92,240 ; vsubps %ymm8,%ymm12,%ymm14 + DB 184,0,0,224,64 ; mov $0x40e00000,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 196,66,125,88,201 ; vpbroadcastd %xmm9,%ymm9 + DB 196,65,28,89,249 ; vmulps %ymm9,%ymm12,%ymm15 + DB 196,66,21,184,254 ; vfmadd231ps %ymm14,%ymm13,%ymm15 + DB 196,65,124,82,236 ; vrsqrtps %ymm12,%ymm13 + DB 196,65,124,83,237 ; vrcpps %ymm13,%ymm13 + DB 196,65,20,92,236 ; vsubps %ymm12,%ymm13,%ymm13 + DB 197,92,88,244 ; vaddps %ymm4,%ymm4,%ymm14 + DB 196,65,12,88,246 ; vaddps %ymm14,%ymm14,%ymm14 + DB 197,12,194,247,2 ; vcmpleps %ymm7,%ymm14,%ymm14 + DB 196,67,21,74,239,224 ; vblendvps %ymm14,%ymm15,%ymm13,%ymm13 + DB 197,124,88,240 ; vaddps %ymm0,%ymm0,%ymm14 + DB 197,12,92,251 ; vsubps %ymm3,%ymm14,%ymm15 + DB 196,65,60,92,228 ; vsubps %ymm12,%ymm8,%ymm12 + DB 196,98,5,168,227 ; vfmadd213ps %ymm3,%ymm15,%ymm12 + DB 197,28,89,228 ; vmulps %ymm4,%ymm12,%ymm12 + DB 197,4,89,255 ; vmulps %ymm7,%ymm15,%ymm15 + DB 196,65,4,89,237 ; vmulps %ymm13,%ymm15,%ymm13 + DB 196,98,101,184,236 ; vfmadd231ps %ymm4,%ymm3,%ymm13 + DB 197,12,194,243,2 ; vcmpleps %ymm3,%ymm14,%ymm14 + DB 196,195,21,74,212,224 ; vblendvps %ymm14,%ymm12,%ymm13,%ymm2 + DB 197,84,94,239 ; vdivps %ymm7,%ymm5,%ymm13 + DB 196,67,45,74,237,176 ; vblendvps %ymm11,%ymm13,%ymm10,%ymm13 + DB 196,65,20,88,245 ; vaddps %ymm13,%ymm13,%ymm14 + DB 196,65,12,88,246 ; vaddps %ymm14,%ymm14,%ymm14 + DB 196,66,13,168,246 ; vfmadd213ps %ymm14,%ymm14,%ymm14 + DB 196,65,20,92,248 ; vsubps %ymm8,%ymm13,%ymm15 + DB 196,65,4,89,246 ; vmulps %ymm14,%ymm15,%ymm14 + DB 196,66,53,184,245 ; vfmadd231ps %ymm13,%ymm9,%ymm14 + DB 196,65,124,82,253 ; vrsqrtps %ymm13,%ymm15 + DB 196,65,124,83,255 ; vrcpps %ymm15,%ymm15 + DB 196,65,4,92,253 ; vsubps %ymm13,%ymm15,%ymm15 + DB 197,84,88,229 ; vaddps %ymm5,%ymm5,%ymm12 + DB 196,65,28,88,228 ; vaddps %ymm12,%ymm12,%ymm12 + DB 197,28,194,231,2 ; vcmpleps %ymm7,%ymm12,%ymm12 + DB 196,67,5,74,230,192 ; vblendvps %ymm12,%ymm14,%ymm15,%ymm12 + DB 197,116,88,241 ; vaddps %ymm1,%ymm1,%ymm14 + DB 196,65,60,92,237 ; vsubps %ymm13,%ymm8,%ymm13 + DB 197,12,92,251 ; vsubps %ymm3,%ymm14,%ymm15 + DB 196,98,5,168,235 ; vfmadd213ps %ymm3,%ymm15,%ymm13 + DB 197,4,89,255 ; vmulps %ymm7,%ymm15,%ymm15 + DB 196,65,4,89,228 ; vmulps %ymm12,%ymm15,%ymm12 + DB 197,20,89,237 ; vmulps %ymm5,%ymm13,%ymm13 + DB 196,98,101,184,229 ; vfmadd231ps %ymm5,%ymm3,%ymm12 + DB 197,12,194,243,2 ; vcmpleps %ymm3,%ymm14,%ymm14 + DB 196,67,29,74,237,224 ; vblendvps %ymm14,%ymm13,%ymm12,%ymm13 + DB 197,76,94,231 ; vdivps %ymm7,%ymm6,%ymm12 + DB 196,67,45,74,212,176 ; vblendvps %ymm11,%ymm12,%ymm10,%ymm10 + DB 196,65,44,88,218 ; vaddps %ymm10,%ymm10,%ymm11 + DB 196,65,36,88,219 ; vaddps %ymm11,%ymm11,%ymm11 + DB 196,66,37,168,219 ; vfmadd213ps %ymm11,%ymm11,%ymm11 + DB 196,65,44,92,224 ; vsubps %ymm8,%ymm10,%ymm12 + DB 196,65,28,89,219 ; vmulps %ymm11,%ymm12,%ymm11 + DB 196,66,45,168,203 ; vfmadd213ps %ymm11,%ymm10,%ymm9 + DB 196,65,124,82,218 ; vrsqrtps %ymm10,%ymm11 + DB 196,65,124,83,219 ; vrcpps %ymm11,%ymm11 + DB 196,65,36,92,218 ; vsubps %ymm10,%ymm11,%ymm11 + DB 197,76,88,230 ; vaddps %ymm6,%ymm6,%ymm12 + DB 196,65,28,88,228 ; vaddps %ymm12,%ymm12,%ymm12 + DB 197,28,194,231,2 ; vcmpleps %ymm7,%ymm12,%ymm12 + DB 196,67,37,74,201,192 ; vblendvps %ymm12,%ymm9,%ymm11,%ymm9 + DB 197,124,16,52,36 ; vmovups (%rsp),%ymm14 + DB 196,65,12,88,222 ; vaddps %ymm14,%ymm14,%ymm11 + DB 197,36,92,227 ; vsubps %ymm3,%ymm11,%ymm12 + DB 196,65,60,92,210 ; vsubps %ymm10,%ymm8,%ymm10 + DB 196,98,29,168,211 ; vfmadd213ps %ymm3,%ymm12,%ymm10 + DB 197,28,89,231 ; vmulps %ymm7,%ymm12,%ymm12 + DB 196,65,28,89,201 ; vmulps %ymm9,%ymm12,%ymm9 + DB 197,44,89,214 ; vmulps %ymm6,%ymm10,%ymm10 + DB 196,98,101,184,206 ; vfmadd231ps %ymm6,%ymm3,%ymm9 + DB 197,36,194,219,2 ; vcmpleps %ymm3,%ymm11,%ymm11 + DB 196,67,53,74,202,176 ; vblendvps %ymm11,%ymm10,%ymm9,%ymm9 + DB 197,60,92,215 ; vsubps %ymm7,%ymm8,%ymm10 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,220 ; vmulps %ymm4,%ymm8,%ymm11 + DB 196,98,45,184,216 ; vfmadd231ps %ymm0,%ymm10,%ymm11 + DB 196,193,108,88,195 ; vaddps %ymm11,%ymm2,%ymm0 + DB 197,172,89,201 ; vmulps %ymm1,%ymm10,%ymm1 + DB 196,226,61,184,205 ; vfmadd231ps %ymm5,%ymm8,%ymm1 + DB 196,193,116,88,205 ; vaddps %ymm13,%ymm1,%ymm1 + DB 196,193,44,89,214 ; vmulps %ymm14,%ymm10,%ymm2 + DB 196,226,61,184,214 ; vfmadd231ps %ymm6,%ymm8,%ymm2 + DB 196,193,108,88,209 ; vaddps %ymm9,%ymm2,%ymm2 + DB 196,194,69,184,216 ; vfmadd231ps %ymm8,%ymm7,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,131,196,56 ; add $0x38,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_0_hsw +_sk_clamp_0_hsw LABEL PROC + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 196,193,124,95,192 ; vmaxps %ymm8,%ymm0,%ymm0 + DB 196,193,116,95,200 ; vmaxps %ymm8,%ymm1,%ymm1 + DB 196,193,108,95,208 ; vmaxps %ymm8,%ymm2,%ymm2 + DB 196,193,100,95,216 ; vmaxps %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_1_hsw +_sk_clamp_1_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 196,193,124,93,192 ; vminps %ymm8,%ymm0,%ymm0 + DB 196,193,116,93,200 ; vminps %ymm8,%ymm1,%ymm1 + DB 196,193,108,93,208 ; vminps %ymm8,%ymm2,%ymm2 + DB 196,193,100,93,216 ; vminps %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_a_hsw +_sk_clamp_a_hsw LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 196,193,100,93,216 ; vminps %ymm8,%ymm3,%ymm3 + DB 197,252,93,195 ; vminps %ymm3,%ymm0,%ymm0 + DB 197,244,93,203 ; vminps %ymm3,%ymm1,%ymm1 + DB 197,236,93,211 ; vminps %ymm3,%ymm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_set_rgb_hsw +_sk_set_rgb_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,226,125,24,0 ; vbroadcastss (%rax),%ymm0 + DB 196,226,125,24,72,4 ; vbroadcastss 0x4(%rax),%ymm1 + DB 196,226,125,24,80,8 ; vbroadcastss 0x8(%rax),%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_swap_rb_hsw +_sk_swap_rb_hsw LABEL PROC + DB 197,124,40,192 ; vmovaps %ymm0,%ymm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,194 ; vmovaps %ymm2,%ymm0 + DB 197,124,41,194 ; vmovaps %ymm8,%ymm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_swap_hsw +_sk_swap_hsw LABEL PROC + DB 197,124,40,195 ; vmovaps %ymm3,%ymm8 + DB 197,124,40,202 ; vmovaps %ymm2,%ymm9 + DB 197,124,40,209 ; vmovaps %ymm1,%ymm10 + DB 197,124,40,216 ; vmovaps %ymm0,%ymm11 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,196 ; vmovaps %ymm4,%ymm0 + DB 197,252,40,205 ; vmovaps %ymm5,%ymm1 + DB 197,252,40,214 ; vmovaps %ymm6,%ymm2 + DB 197,252,40,223 ; vmovaps %ymm7,%ymm3 + DB 197,124,41,220 ; vmovaps %ymm11,%ymm4 + DB 197,124,41,213 ; vmovaps %ymm10,%ymm5 + DB 197,124,41,206 ; vmovaps %ymm9,%ymm6 + DB 197,124,41,199 ; vmovaps %ymm8,%ymm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_move_src_dst_hsw +_sk_move_src_dst_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,224 ; vmovaps %ymm0,%ymm4 + DB 197,252,40,233 ; vmovaps %ymm1,%ymm5 + DB 197,252,40,242 ; vmovaps %ymm2,%ymm6 + DB 197,252,40,251 ; vmovaps %ymm3,%ymm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_move_dst_src_hsw +_sk_move_dst_src_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,196 ; vmovaps %ymm4,%ymm0 + DB 197,252,40,205 ; vmovaps %ymm5,%ymm1 + DB 197,252,40,214 ; vmovaps %ymm6,%ymm2 + DB 197,252,40,223 ; vmovaps %ymm7,%ymm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_premul_hsw +_sk_premul_hsw LABEL PROC + DB 197,252,89,195 ; vmulps %ymm3,%ymm0,%ymm0 + DB 197,244,89,203 ; vmulps %ymm3,%ymm1,%ymm1 + DB 197,236,89,211 ; vmulps %ymm3,%ymm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_unpremul_hsw +_sk_unpremul_hsw LABEL PROC + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 196,65,100,194,200,0 ; vcmpeqps %ymm8,%ymm3,%ymm9 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,208 ; vmovd %eax,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 197,44,94,211 ; vdivps %ymm3,%ymm10,%ymm10 + DB 196,67,45,74,192,144 ; vblendvps %ymm9,%ymm8,%ymm10,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_from_srgb_hsw +_sk_from_srgb_hsw LABEL PROC + DB 184,145,131,158,61 ; mov $0x3d9e8391,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 197,124,89,208 ; vmulps %ymm0,%ymm0,%ymm10 + DB 184,154,153,153,62 ; mov $0x3e99999a,%eax + DB 197,121,110,216 ; vmovd %eax,%xmm11 + DB 196,66,125,88,219 ; vpbroadcastd %xmm11,%ymm11 + DB 184,92,143,50,63 ; mov $0x3f328f5c,%eax + DB 197,121,110,224 ; vmovd %eax,%xmm12 + DB 196,66,125,88,228 ; vpbroadcastd %xmm12,%ymm12 + DB 196,65,125,111,235 ; vmovdqa %ymm11,%ymm13 + DB 196,66,125,168,236 ; vfmadd213ps %ymm12,%ymm0,%ymm13 + DB 184,10,215,35,59 ; mov $0x3b23d70a,%eax + DB 197,121,110,240 ; vmovd %eax,%xmm14 + DB 196,66,125,88,246 ; vpbroadcastd %xmm14,%ymm14 + DB 196,66,45,168,238 ; vfmadd213ps %ymm14,%ymm10,%ymm13 + DB 184,174,71,97,61 ; mov $0x3d6147ae,%eax + DB 197,121,110,208 ; vmovd %eax,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 196,193,124,194,194,1 ; vcmpltps %ymm10,%ymm0,%ymm0 + DB 196,195,21,74,193,0 ; vblendvps %ymm0,%ymm9,%ymm13,%ymm0 + DB 197,60,89,201 ; vmulps %ymm1,%ymm8,%ymm9 + DB 197,116,89,233 ; vmulps %ymm1,%ymm1,%ymm13 + DB 196,65,125,111,251 ; vmovdqa %ymm11,%ymm15 + DB 196,66,117,168,252 ; vfmadd213ps %ymm12,%ymm1,%ymm15 + DB 196,66,21,168,254 ; vfmadd213ps %ymm14,%ymm13,%ymm15 + DB 196,193,116,194,202,1 ; vcmpltps %ymm10,%ymm1,%ymm1 + DB 196,195,5,74,201,16 ; vblendvps %ymm1,%ymm9,%ymm15,%ymm1 + DB 197,60,89,194 ; vmulps %ymm2,%ymm8,%ymm8 + DB 197,108,89,202 ; vmulps %ymm2,%ymm2,%ymm9 + DB 196,66,109,168,220 ; vfmadd213ps %ymm12,%ymm2,%ymm11 + DB 196,66,53,168,222 ; vfmadd213ps %ymm14,%ymm9,%ymm11 + DB 196,193,108,194,210,1 ; vcmpltps %ymm10,%ymm2,%ymm2 + DB 196,195,37,74,208,32 ; vblendvps %ymm2,%ymm8,%ymm11,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_to_srgb_hsw +_sk_to_srgb_hsw LABEL PROC + DB 197,124,82,192 ; vrsqrtps %ymm0,%ymm8 + DB 196,65,124,83,216 ; vrcpps %ymm8,%ymm11 + DB 196,65,124,82,224 ; vrsqrtps %ymm8,%ymm12 + DB 184,41,92,71,65 ; mov $0x41475c29,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,89,232 ; vmulps %ymm0,%ymm8,%ymm13 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 196,66,125,88,201 ; vpbroadcastd %xmm9,%ymm9 + DB 184,194,135,210,62 ; mov $0x3ed287c2,%eax + DB 197,121,110,208 ; vmovd %eax,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 184,206,111,48,63 ; mov $0x3f306fce,%eax + DB 197,121,110,240 ; vmovd %eax,%xmm14 + DB 196,66,125,88,246 ; vpbroadcastd %xmm14,%ymm14 + DB 184,168,87,202,61 ; mov $0x3dca57a8,%eax + DB 53,0,0,0,128 ; xor $0x80000000,%eax + DB 197,121,110,248 ; vmovd %eax,%xmm15 + DB 196,66,125,88,255 ; vpbroadcastd %xmm15,%ymm15 + DB 196,66,13,168,223 ; vfmadd213ps %ymm15,%ymm14,%ymm11 + DB 196,66,45,184,220 ; vfmadd231ps %ymm12,%ymm10,%ymm11 + DB 196,65,52,93,219 ; vminps %ymm11,%ymm9,%ymm11 + DB 184,4,231,140,59 ; mov $0x3b8ce704,%eax + DB 197,121,110,224 ; vmovd %eax,%xmm12 + DB 196,66,125,88,228 ; vpbroadcastd %xmm12,%ymm12 + DB 196,193,124,194,196,1 ; vcmpltps %ymm12,%ymm0,%ymm0 + DB 196,195,37,74,197,0 ; vblendvps %ymm0,%ymm13,%ymm11,%ymm0 + DB 197,124,82,217 ; vrsqrtps %ymm1,%ymm11 + DB 196,65,124,83,235 ; vrcpps %ymm11,%ymm13 + DB 196,65,124,82,219 ; vrsqrtps %ymm11,%ymm11 + DB 196,66,13,168,239 ; vfmadd213ps %ymm15,%ymm14,%ymm13 + DB 196,66,45,184,235 ; vfmadd231ps %ymm11,%ymm10,%ymm13 + DB 197,60,89,217 ; vmulps %ymm1,%ymm8,%ymm11 + DB 196,65,52,93,237 ; vminps %ymm13,%ymm9,%ymm13 + DB 196,193,116,194,204,1 ; vcmpltps %ymm12,%ymm1,%ymm1 + DB 196,195,21,74,203,16 ; vblendvps %ymm1,%ymm11,%ymm13,%ymm1 + DB 197,124,82,218 ; vrsqrtps %ymm2,%ymm11 + DB 196,65,124,83,235 ; vrcpps %ymm11,%ymm13 + DB 196,66,13,168,239 ; vfmadd213ps %ymm15,%ymm14,%ymm13 + DB 196,65,124,82,219 ; vrsqrtps %ymm11,%ymm11 + DB 196,66,45,184,235 ; vfmadd231ps %ymm11,%ymm10,%ymm13 + DB 196,65,52,93,205 ; vminps %ymm13,%ymm9,%ymm9 + DB 197,60,89,194 ; vmulps %ymm2,%ymm8,%ymm8 + DB 196,193,108,194,212,1 ; vcmpltps %ymm12,%ymm2,%ymm2 + DB 196,195,53,74,208,32 ; vblendvps %ymm2,%ymm8,%ymm9,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_from_2dot2_hsw +_sk_from_2dot2_hsw LABEL PROC + DB 197,124,82,192 ; vrsqrtps %ymm0,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,200 ; vrsqrtps %ymm8,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 197,252,89,192 ; vmulps %ymm0,%ymm0,%ymm0 + DB 196,65,60,89,208 ; vmulps %ymm8,%ymm8,%ymm10 + DB 196,65,60,89,194 ; vmulps %ymm10,%ymm8,%ymm8 + DB 196,193,124,89,192 ; vmulps %ymm8,%ymm0,%ymm0 + DB 197,180,89,192 ; vmulps %ymm0,%ymm9,%ymm0 + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 196,193,124,95,192 ; vmaxps %ymm8,%ymm0,%ymm0 + DB 197,124,82,201 ; vrsqrtps %ymm1,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,209 ; vrsqrtps %ymm9,%ymm10 + DB 196,65,124,82,210 ; vrsqrtps %ymm10,%ymm10 + DB 197,244,89,201 ; vmulps %ymm1,%ymm1,%ymm1 + DB 196,65,52,89,217 ; vmulps %ymm9,%ymm9,%ymm11 + DB 196,65,52,89,203 ; vmulps %ymm11,%ymm9,%ymm9 + DB 196,193,116,89,201 ; vmulps %ymm9,%ymm1,%ymm1 + DB 197,172,89,201 ; vmulps %ymm1,%ymm10,%ymm1 + DB 196,193,116,95,200 ; vmaxps %ymm8,%ymm1,%ymm1 + DB 197,124,82,202 ; vrsqrtps %ymm2,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,209 ; vrsqrtps %ymm9,%ymm10 + DB 196,65,124,82,210 ; vrsqrtps %ymm10,%ymm10 + DB 197,236,89,210 ; vmulps %ymm2,%ymm2,%ymm2 + DB 196,65,52,89,217 ; vmulps %ymm9,%ymm9,%ymm11 + DB 196,65,52,89,203 ; vmulps %ymm11,%ymm9,%ymm9 + DB 196,193,108,89,209 ; vmulps %ymm9,%ymm2,%ymm2 + DB 197,172,89,210 ; vmulps %ymm2,%ymm10,%ymm2 + DB 196,193,108,95,208 ; vmaxps %ymm8,%ymm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_to_2dot2_hsw +_sk_to_2dot2_hsw LABEL PROC + DB 197,252,82,192 ; vrsqrtps %ymm0,%ymm0 + DB 197,124,82,192 ; vrsqrtps %ymm0,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,200 ; vrsqrtps %ymm8,%ymm9 + DB 197,252,83,192 ; vrcpps %ymm0,%ymm0 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 196,65,124,83,193 ; vrcpps %ymm9,%ymm8 + DB 196,193,124,89,192 ; vmulps %ymm8,%ymm0,%ymm0 + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 196,193,124,95,192 ; vmaxps %ymm8,%ymm0,%ymm0 + DB 197,252,82,201 ; vrsqrtps %ymm1,%ymm1 + DB 197,124,82,201 ; vrsqrtps %ymm1,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,209 ; vrsqrtps %ymm9,%ymm10 + DB 197,252,83,201 ; vrcpps %ymm1,%ymm1 + DB 197,180,89,201 ; vmulps %ymm1,%ymm9,%ymm1 + DB 196,65,124,83,202 ; vrcpps %ymm10,%ymm9 + DB 196,193,116,89,201 ; vmulps %ymm9,%ymm1,%ymm1 + DB 196,193,116,95,200 ; vmaxps %ymm8,%ymm1,%ymm1 + DB 197,252,82,210 ; vrsqrtps %ymm2,%ymm2 + DB 197,124,82,202 ; vrsqrtps %ymm2,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,209 ; vrsqrtps %ymm9,%ymm10 + DB 197,252,83,210 ; vrcpps %ymm2,%ymm2 + DB 197,180,89,210 ; vmulps %ymm2,%ymm9,%ymm2 + DB 196,65,124,83,202 ; vrcpps %ymm10,%ymm9 + DB 196,193,108,89,209 ; vmulps %ymm9,%ymm2,%ymm2 + DB 196,193,108,95,208 ; vmaxps %ymm8,%ymm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_rgb_to_hsl_hsw +_sk_rgb_to_hsl_hsw LABEL PROC + DB 72,131,236,56 ; sub $0x38,%rsp + DB 197,252,17,60,36 ; vmovups %ymm7,(%rsp) + DB 197,252,40,254 ; vmovaps %ymm6,%ymm7 + DB 197,252,40,245 ; vmovaps %ymm5,%ymm6 + DB 197,252,40,236 ; vmovaps %ymm4,%ymm5 + DB 197,252,40,227 ; vmovaps %ymm3,%ymm4 + DB 197,252,40,216 ; vmovaps %ymm0,%ymm3 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 65,184,171,170,42,62 ; mov $0x3e2aaaab,%r8d + DB 184,0,0,192,64 ; mov $0x40c00000,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 65,185,0,0,0,64 ; mov $0x40000000,%r9d + DB 184,0,0,128,64 ; mov $0x40800000,%eax + DB 197,121,110,208 ; vmovd %eax,%xmm10 + DB 197,100,95,217 ; vmaxps %ymm1,%ymm3,%ymm11 + DB 197,36,95,218 ; vmaxps %ymm2,%ymm11,%ymm11 + DB 197,100,93,225 ; vminps %ymm1,%ymm3,%ymm12 + DB 197,28,93,226 ; vminps %ymm2,%ymm12,%ymm12 + DB 196,65,36,92,236 ; vsubps %ymm12,%ymm11,%ymm13 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 196,65,60,94,197 ; vdivps %ymm13,%ymm8,%ymm8 + DB 197,116,194,242,1 ; vcmpltps %ymm2,%ymm1,%ymm14 + DB 196,66,125,88,201 ; vpbroadcastd %xmm9,%ymm9 + DB 196,65,4,87,255 ; vxorps %ymm15,%ymm15,%ymm15 + DB 196,67,5,74,201,224 ; vblendvps %ymm14,%ymm9,%ymm15,%ymm9 + DB 197,116,92,242 ; vsubps %ymm2,%ymm1,%ymm14 + DB 196,66,61,168,241 ; vfmadd213ps %ymm9,%ymm8,%ymm14 + DB 197,236,92,195 ; vsubps %ymm3,%ymm2,%ymm0 + DB 197,100,92,201 ; vsubps %ymm1,%ymm3,%ymm9 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 196,66,61,168,202 ; vfmadd213ps %ymm10,%ymm8,%ymm9 + DB 196,193,121,110,209 ; vmovd %r9d,%xmm2 + DB 196,98,125,88,210 ; vpbroadcastd %xmm2,%ymm10 + DB 196,194,61,168,194 ; vfmadd213ps %ymm10,%ymm8,%ymm0 + DB 197,164,194,201,0 ; vcmpeqps %ymm1,%ymm11,%ymm1 + DB 196,227,53,74,192,16 ; vblendvps %ymm1,%ymm0,%ymm9,%ymm0 + DB 184,0,0,0,63 ; mov $0x3f000000,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 197,164,194,211,0 ; vcmpeqps %ymm3,%ymm11,%ymm2 + DB 196,195,125,74,198,32 ; vblendvps %ymm2,%ymm14,%ymm0,%ymm0 + DB 196,193,36,88,220 ; vaddps %ymm12,%ymm11,%ymm3 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,228,89,209 ; vmulps %ymm1,%ymm3,%ymm2 + DB 197,244,194,202,1 ; vcmpltps %ymm2,%ymm1,%ymm1 + DB 196,65,44,92,195 ; vsubps %ymm11,%ymm10,%ymm8 + DB 196,65,60,92,196 ; vsubps %ymm12,%ymm8,%ymm8 + DB 196,195,101,74,200,16 ; vblendvps %ymm1,%ymm8,%ymm3,%ymm1 + DB 196,193,36,194,220,0 ; vcmpeqps %ymm12,%ymm11,%ymm3 + DB 197,148,94,201 ; vdivps %ymm1,%ymm13,%ymm1 + DB 196,195,125,74,199,48 ; vblendvps %ymm3,%ymm15,%ymm0,%ymm0 + DB 196,195,117,74,207,48 ; vblendvps %ymm3,%ymm15,%ymm1,%ymm1 + DB 196,193,121,110,216 ; vmovd %r8d,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,228,89,192 ; vmulps %ymm0,%ymm3,%ymm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,220 ; vmovaps %ymm4,%ymm3 + DB 197,252,40,229 ; vmovaps %ymm5,%ymm4 + DB 197,252,40,238 ; vmovaps %ymm6,%ymm5 + DB 197,252,40,247 ; vmovaps %ymm7,%ymm6 + DB 197,252,16,60,36 ; vmovups (%rsp),%ymm7 + DB 72,131,196,56 ; add $0x38,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_hsl_to_rgb_hsw +_sk_hsl_to_rgb_hsw LABEL PROC + DB 72,129,236,184,0,0,0 ; sub $0xb8,%rsp + DB 197,252,17,188,36,128,0,0,0 ; vmovups %ymm7,0x80(%rsp) + DB 197,252,17,116,36,96 ; vmovups %ymm6,0x60(%rsp) + DB 197,252,17,108,36,64 ; vmovups %ymm5,0x40(%rsp) + DB 197,252,17,100,36,32 ; vmovups %ymm4,0x20(%rsp) + DB 197,252,17,28,36 ; vmovups %ymm3,(%rsp) + DB 197,252,40,233 ; vmovaps %ymm1,%ymm5 + DB 184,0,0,0,63 ; mov $0x3f000000,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,98,125,88,193 ; vpbroadcastd %xmm1,%ymm8 + DB 196,193,108,194,200,1 ; vcmpltps %ymm8,%ymm2,%ymm1 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,224 ; vmovd %eax,%xmm4 + DB 196,98,125,88,212 ; vpbroadcastd %xmm4,%ymm10 + DB 197,172,88,229 ; vaddps %ymm5,%ymm10,%ymm4 + DB 197,220,89,226 ; vmulps %ymm2,%ymm4,%ymm4 + DB 197,84,88,202 ; vaddps %ymm2,%ymm5,%ymm9 + DB 196,98,85,188,202 ; vfnmadd231ps %ymm2,%ymm5,%ymm9 + DB 196,99,53,74,204,16 ; vblendvps %ymm1,%ymm4,%ymm9,%ymm9 + DB 65,184,0,0,0,64 ; mov $0x40000000,%r8d + DB 184,171,170,170,62 ; mov $0x3eaaaaab,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,98,125,88,233 ; vpbroadcastd %xmm1,%ymm13 + DB 197,148,88,224 ; vaddps %ymm0,%ymm13,%ymm4 + DB 184,0,0,0,0 ; mov $0x0,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,98,125,88,225 ; vpbroadcastd %xmm1,%ymm12 + DB 197,172,194,204,1 ; vcmpltps %ymm4,%ymm10,%ymm1 + DB 196,65,92,92,218 ; vsubps %ymm10,%ymm4,%ymm11 + DB 196,195,93,74,203,16 ; vblendvps %ymm1,%ymm11,%ymm4,%ymm1 + DB 196,65,92,194,220,1 ; vcmpltps %ymm12,%ymm4,%ymm11 + DB 197,44,88,244 ; vaddps %ymm4,%ymm10,%ymm14 + DB 196,195,117,74,206,176 ; vblendvps %ymm11,%ymm14,%ymm1,%ymm1 + DB 196,193,121,110,216 ; vmovd %r8d,%xmm3 + DB 196,98,125,88,219 ; vpbroadcastd %xmm3,%ymm11 + DB 196,66,109,170,217 ; vfmsub213ps %ymm9,%ymm2,%ymm11 + DB 65,184,171,170,42,62 ; mov $0x3e2aaaab,%r8d + DB 184,0,0,192,64 ; mov $0x40c00000,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 196,65,52,92,243 ; vsubps %ymm11,%ymm9,%ymm14 + DB 197,12,89,243 ; vmulps %ymm3,%ymm14,%ymm14 + DB 184,171,170,42,63 ; mov $0x3f2aaaab,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,98,125,88,251 ; vpbroadcastd %xmm3,%ymm15 + DB 197,132,92,217 ; vsubps %ymm1,%ymm15,%ymm3 + DB 196,194,13,168,219 ; vfmadd213ps %ymm11,%ymm14,%ymm3 + DB 196,193,116,194,255,1 ; vcmpltps %ymm15,%ymm1,%ymm7 + DB 196,227,37,74,219,112 ; vblendvps %ymm7,%ymm3,%ymm11,%ymm3 + DB 196,193,116,194,248,1 ; vcmpltps %ymm8,%ymm1,%ymm7 + DB 196,195,101,74,249,112 ; vblendvps %ymm7,%ymm9,%ymm3,%ymm7 + DB 196,193,121,110,216 ; vmovd %r8d,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,244,194,203,1 ; vcmpltps %ymm3,%ymm1,%ymm1 + DB 196,194,13,168,227 ; vfmadd213ps %ymm11,%ymm14,%ymm4 + DB 196,227,69,74,228,16 ; vblendvps %ymm1,%ymm4,%ymm7,%ymm4 + DB 197,172,194,200,1 ; vcmpltps %ymm0,%ymm10,%ymm1 + DB 196,193,124,92,250 ; vsubps %ymm10,%ymm0,%ymm7 + DB 196,227,125,74,207,16 ; vblendvps %ymm1,%ymm7,%ymm0,%ymm1 + DB 196,193,124,194,252,1 ; vcmpltps %ymm12,%ymm0,%ymm7 + DB 197,172,88,240 ; vaddps %ymm0,%ymm10,%ymm6 + DB 196,227,117,74,206,112 ; vblendvps %ymm7,%ymm6,%ymm1,%ymm1 + DB 197,132,92,241 ; vsubps %ymm1,%ymm15,%ymm6 + DB 196,194,13,168,243 ; vfmadd213ps %ymm11,%ymm14,%ymm6 + DB 196,193,116,194,255,1 ; vcmpltps %ymm15,%ymm1,%ymm7 + DB 196,227,37,74,246,112 ; vblendvps %ymm7,%ymm6,%ymm11,%ymm6 + DB 196,193,116,194,248,1 ; vcmpltps %ymm8,%ymm1,%ymm7 + DB 196,195,77,74,241,112 ; vblendvps %ymm7,%ymm9,%ymm6,%ymm6 + DB 197,244,194,203,1 ; vcmpltps %ymm3,%ymm1,%ymm1 + DB 196,193,124,92,253 ; vsubps %ymm13,%ymm0,%ymm7 + DB 196,194,13,168,195 ; vfmadd213ps %ymm11,%ymm14,%ymm0 + DB 196,227,77,74,200,16 ; vblendvps %ymm1,%ymm0,%ymm6,%ymm1 + DB 197,172,194,199,1 ; vcmpltps %ymm7,%ymm10,%ymm0 + DB 196,193,68,92,242 ; vsubps %ymm10,%ymm7,%ymm6 + DB 196,227,69,74,198,0 ; vblendvps %ymm0,%ymm6,%ymm7,%ymm0 + DB 196,193,68,194,244,1 ; vcmpltps %ymm12,%ymm7,%ymm6 + DB 197,44,88,215 ; vaddps %ymm7,%ymm10,%ymm10 + DB 196,195,125,74,194,96 ; vblendvps %ymm6,%ymm10,%ymm0,%ymm0 + DB 196,194,13,168,251 ; vfmadd213ps %ymm11,%ymm14,%ymm7 + DB 197,132,92,240 ; vsubps %ymm0,%ymm15,%ymm6 + DB 196,194,13,168,243 ; vfmadd213ps %ymm11,%ymm14,%ymm6 + DB 196,65,124,194,215,1 ; vcmpltps %ymm15,%ymm0,%ymm10 + DB 196,227,37,74,246,160 ; vblendvps %ymm10,%ymm6,%ymm11,%ymm6 + DB 196,65,124,194,192,1 ; vcmpltps %ymm8,%ymm0,%ymm8 + DB 196,195,77,74,241,128 ; vblendvps %ymm8,%ymm9,%ymm6,%ymm6 + DB 197,252,194,195,1 ; vcmpltps %ymm3,%ymm0,%ymm0 + DB 196,227,77,74,223,0 ; vblendvps %ymm0,%ymm7,%ymm6,%ymm3 + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,212,194,232,0 ; vcmpeqps %ymm0,%ymm5,%ymm5 + DB 196,227,93,74,194,80 ; vblendvps %ymm5,%ymm2,%ymm4,%ymm0 + DB 196,227,117,74,202,80 ; vblendvps %ymm5,%ymm2,%ymm1,%ymm1 + DB 196,227,101,74,210,80 ; vblendvps %ymm5,%ymm2,%ymm3,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,16,28,36 ; vmovups (%rsp),%ymm3 + DB 197,252,16,100,36,32 ; vmovups 0x20(%rsp),%ymm4 + DB 197,252,16,108,36,64 ; vmovups 0x40(%rsp),%ymm5 + DB 197,252,16,116,36,96 ; vmovups 0x60(%rsp),%ymm6 + DB 197,252,16,188,36,128,0,0,0 ; vmovups 0x80(%rsp),%ymm7 + DB 72,129,196,184,0,0,0 ; add $0xb8,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_scale_1_float_hsw +_sk_scale_1_float_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_scale_u8_hsw +_sk_scale_u8_hsw LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,1,248 ; add %rdi,%rax + DB 77,133,192 ; test %r8,%r8 + DB 117,56 ; jne 126b <_sk_scale_u8_hsw+0x48> + DB 197,122,126,0 ; vmovq (%rax),%xmm8 + DB 196,66,125,49,192 ; vpmovzxbd %xmm8,%ymm8 + DB 196,65,124,91,192 ; vcvtdq2ps %ymm8,%ymm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 196,66,125,88,201 ; vpbroadcastd %xmm9,%ymm9 + DB 196,65,60,89,193 ; vmulps %ymm9,%ymm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,137,193 ; mov %r8,%rcx + DB 255,224 ; jmpq *%rax + DB 49,201 ; xor %ecx,%ecx + DB 77,137,194 ; mov %r8,%r10 + DB 69,49,201 ; xor %r9d,%r9d + DB 68,15,182,24 ; movzbl (%rax),%r11d + DB 72,255,192 ; inc %rax + DB 73,211,227 ; shl %cl,%r11 + DB 77,9,217 ; or %r11,%r9 + DB 72,131,193,8 ; add $0x8,%rcx + DB 73,255,202 ; dec %r10 + DB 117,234 ; jne 1273 <_sk_scale_u8_hsw+0x50> + DB 196,65,249,110,193 ; vmovq %r9,%xmm8 + DB 235,167 ; jmp 1237 <_sk_scale_u8_hsw+0x14> + +PUBLIC _sk_lerp_1_float_hsw +_sk_lerp_1_float_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 197,252,92,196 ; vsubps %ymm4,%ymm0,%ymm0 + DB 196,226,61,168,196 ; vfmadd213ps %ymm4,%ymm8,%ymm0 + DB 197,244,92,205 ; vsubps %ymm5,%ymm1,%ymm1 + DB 196,226,61,168,205 ; vfmadd213ps %ymm5,%ymm8,%ymm1 + DB 197,236,92,214 ; vsubps %ymm6,%ymm2,%ymm2 + DB 196,226,61,168,214 ; vfmadd213ps %ymm6,%ymm8,%ymm2 + DB 197,228,92,223 ; vsubps %ymm7,%ymm3,%ymm3 + DB 196,226,61,168,223 ; vfmadd213ps %ymm7,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lerp_u8_hsw +_sk_lerp_u8_hsw LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,1,248 ; add %rdi,%rax + DB 77,133,192 ; test %r8,%r8 + DB 117,76 ; jne 131b <_sk_lerp_u8_hsw+0x5c> + DB 197,122,126,0 ; vmovq (%rax),%xmm8 + DB 196,66,125,49,192 ; vpmovzxbd %xmm8,%ymm8 + DB 196,65,124,91,192 ; vcvtdq2ps %ymm8,%ymm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 196,66,125,88,201 ; vpbroadcastd %xmm9,%ymm9 + DB 196,65,60,89,193 ; vmulps %ymm9,%ymm8,%ymm8 + DB 197,252,92,196 ; vsubps %ymm4,%ymm0,%ymm0 + DB 196,226,61,168,196 ; vfmadd213ps %ymm4,%ymm8,%ymm0 + DB 197,244,92,205 ; vsubps %ymm5,%ymm1,%ymm1 + DB 196,226,61,168,205 ; vfmadd213ps %ymm5,%ymm8,%ymm1 + DB 197,236,92,214 ; vsubps %ymm6,%ymm2,%ymm2 + DB 196,226,61,168,214 ; vfmadd213ps %ymm6,%ymm8,%ymm2 + DB 197,228,92,223 ; vsubps %ymm7,%ymm3,%ymm3 + DB 196,226,61,168,223 ; vfmadd213ps %ymm7,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,137,193 ; mov %r8,%rcx + DB 255,224 ; jmpq *%rax + DB 49,201 ; xor %ecx,%ecx + DB 77,137,194 ; mov %r8,%r10 + DB 69,49,201 ; xor %r9d,%r9d + DB 68,15,182,24 ; movzbl (%rax),%r11d + DB 72,255,192 ; inc %rax + DB 73,211,227 ; shl %cl,%r11 + DB 77,9,217 ; or %r11,%r9 + DB 72,131,193,8 ; add $0x8,%rcx + DB 73,255,202 ; dec %r10 + DB 117,234 ; jne 1323 <_sk_lerp_u8_hsw+0x64> + DB 196,65,249,110,193 ; vmovq %r9,%xmm8 + DB 235,147 ; jmp 12d3 <_sk_lerp_u8_hsw+0x14> + +PUBLIC _sk_lerp_565_hsw +_sk_lerp_565_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,16 ; mov (%rax),%r10 + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,179,0,0,0 ; jne 1401 <_sk_lerp_565_hsw+0xc1> + DB 196,193,122,111,28,122 ; vmovdqu (%r10,%rdi,2),%xmm3 + DB 196,98,125,51,195 ; vpmovzxwd %xmm3,%ymm8 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 196,193,101,219,216 ; vpand %ymm8,%ymm3,%ymm3 + DB 197,124,91,203 ; vcvtdq2ps %ymm3,%ymm9 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,52,89,203 ; vmulps %ymm3,%ymm9,%ymm9 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 196,193,101,219,216 ; vpand %ymm8,%ymm3,%ymm3 + DB 197,124,91,211 ; vcvtdq2ps %ymm3,%ymm10 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,44,89,211 ; vmulps %ymm3,%ymm10,%ymm10 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 196,193,101,219,216 ; vpand %ymm8,%ymm3,%ymm3 + DB 197,124,91,195 ; vcvtdq2ps %ymm3,%ymm8 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 197,252,92,196 ; vsubps %ymm4,%ymm0,%ymm0 + DB 196,226,53,168,196 ; vfmadd213ps %ymm4,%ymm9,%ymm0 + DB 197,244,92,205 ; vsubps %ymm5,%ymm1,%ymm1 + DB 196,226,45,168,205 ; vfmadd213ps %ymm5,%ymm10,%ymm1 + DB 197,236,92,214 ; vsubps %ymm6,%ymm2,%ymm2 + DB 196,226,101,168,214 ; vfmadd213ps %ymm6,%ymm3,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 197,225,239,219 ; vpxor %xmm3,%xmm3,%xmm3 + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 15,135,59,255,255,255 ; ja 1354 <_sk_lerp_565_hsw+0x14> + DB 69,15,182,192 ; movzbl %r8b,%r8d + DB 76,141,13,76,0,0,0 ; lea 0x4c(%rip),%r9 # 1470 <_sk_lerp_565_hsw+0x130> + DB 75,99,4,129 ; movslq (%r9,%r8,4),%rax + DB 76,1,200 ; add %r9,%rax + DB 255,224 ; jmpq *%rax + DB 197,225,239,219 ; vpxor %xmm3,%xmm3,%xmm3 + DB 196,193,97,196,92,122,12,6 ; vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm3,%xmm3 + DB 196,193,97,196,92,122,10,5 ; vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm3,%xmm3 + DB 196,193,97,196,92,122,8,4 ; vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm3,%xmm3 + DB 196,193,97,196,92,122,6,3 ; vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm3,%xmm3 + DB 196,193,97,196,92,122,4,2 ; vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm3,%xmm3 + DB 196,193,97,196,92,122,2,1 ; vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm3,%xmm3 + DB 196,193,97,196,28,122,0 ; vpinsrw $0x0,(%r10,%rdi,2),%xmm3,%xmm3 + DB 233,231,254,255,255 ; jmpq 1354 <_sk_lerp_565_hsw+0x14> + DB 15,31,0 ; nopl (%rax) + DB 241 ; icebp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 233,255,255,255,225 ; jmpq ffffffffe2001478 <_sk_bicubic_p3y_hsw+0xffffffffe1ffde19> + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 217,255 ; fcos + DB 255 ; (bad) + DB 255,209 ; callq *%rcx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,201 ; dec %ecx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 189 ; .byte 0xbd + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_load_tables_hsw +_sk_load_tables_hsw LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,141,12,189,0,0,0,0 ; lea 0x0(,%rdi,4),%r9 + DB 76,3,8 ; add (%rax),%r9 + DB 77,133,192 ; test %r8,%r8 + DB 117,121 ; jne 151a <_sk_load_tables_hsw+0x8e> + DB 196,193,126,111,25 ; vmovdqu (%r9),%ymm3 + DB 185,255,0,0,0 ; mov $0xff,%ecx + DB 197,249,110,193 ; vmovd %ecx,%xmm0 + DB 196,226,125,88,208 ; vpbroadcastd %xmm0,%ymm2 + DB 197,237,219,203 ; vpand %ymm3,%ymm2,%ymm1 + DB 196,65,61,118,192 ; vpcmpeqd %ymm8,%ymm8,%ymm8 + DB 72,139,72,8 ; mov 0x8(%rax),%rcx + DB 76,139,72,16 ; mov 0x10(%rax),%r9 + DB 196,65,53,118,201 ; vpcmpeqd %ymm9,%ymm9,%ymm9 + DB 196,226,53,146,4,137 ; vgatherdps %ymm9,(%rcx,%ymm1,4),%ymm0 + DB 197,245,114,211,8 ; vpsrld $0x8,%ymm3,%ymm1 + DB 197,109,219,201 ; vpand %ymm1,%ymm2,%ymm9 + DB 196,65,45,118,210 ; vpcmpeqd %ymm10,%ymm10,%ymm10 + DB 196,130,45,146,12,137 ; vgatherdps %ymm10,(%r9,%ymm9,4),%ymm1 + DB 72,139,64,24 ; mov 0x18(%rax),%rax + DB 197,181,114,211,16 ; vpsrld $0x10,%ymm3,%ymm9 + DB 196,65,109,219,201 ; vpand %ymm9,%ymm2,%ymm9 + DB 196,162,61,146,20,136 ; vgatherdps %ymm8,(%rax,%ymm9,4),%ymm2 + DB 197,229,114,211,24 ; vpsrld $0x18,%ymm3,%ymm3 + DB 197,124,91,195 ; vcvtdq2ps %ymm3,%ymm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,137,193 ; mov %r8,%rcx + DB 255,224 ; jmpq *%rax + DB 185,8,0,0,0 ; mov $0x8,%ecx + DB 68,41,193 ; sub %r8d,%ecx + DB 192,225,3 ; shl $0x3,%cl + DB 73,199,194,255,255,255,255 ; mov $0xffffffffffffffff,%r10 + DB 73,211,234 ; shr %cl,%r10 + DB 196,193,249,110,194 ; vmovq %r10,%xmm0 + DB 196,226,125,33,192 ; vpmovsxbd %xmm0,%ymm0 + DB 196,194,125,140,25 ; vpmaskmovd (%r9),%ymm0,%ymm3 + DB 233,99,255,255,255 ; jmpq 14a6 <_sk_load_tables_hsw+0x1a> + +PUBLIC _sk_byte_tables_hsw +_sk_byte_tables_hsw LABEL PROC + DB 85 ; push %rbp + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,127,67 ; mov $0x437f0000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,253,91,192 ; vcvtps2dq %ymm0,%ymm0 + DB 196,195,249,22,192,1 ; vpextrq $0x1,%xmm0,%r8 + DB 68,137,197 ; mov %r8d,%ebp + DB 77,137,194 ; mov %r8,%r10 + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,193,249,126,192 ; vmovq %xmm0,%r8 + DB 69,137,195 ; mov %r8d,%r11d + DB 77,137,199 ; mov %r8,%r15 + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,227,125,57,192,1 ; vextracti128 $0x1,%ymm0,%xmm0 + DB 196,195,249,22,192,1 ; vpextrq $0x1,%xmm0,%r8 + DB 69,137,198 ; mov %r8d,%r14d + DB 77,137,196 ; mov %r8,%r12 + DB 73,193,236,32 ; shr $0x20,%r12 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,221 ; mov %ebx,%r13d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 76,139,8 ; mov (%rax),%r9 + DB 76,139,64,8 ; mov 0x8(%rax),%r8 + DB 196,131,121,32,4,25,0 ; vpinsrb $0x0,(%r9,%r11,1),%xmm0,%xmm0 + DB 196,131,121,32,4,57,1 ; vpinsrb $0x1,(%r9,%r15,1),%xmm0,%xmm0 + DB 65,15,182,44,41 ; movzbl (%r9,%rbp,1),%ebp + DB 196,227,121,32,197,2 ; vpinsrb $0x2,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,17 ; movzbl (%r9,%r10,1),%ebp + DB 196,227,121,32,197,3 ; vpinsrb $0x3,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,41 ; movzbl (%r9,%r13,1),%ebp + DB 196,227,121,32,197,4 ; vpinsrb $0x4,%ebp,%xmm0,%xmm0 + DB 65,15,182,44,25 ; movzbl (%r9,%rbx,1),%ebp + DB 196,227,121,32,197,5 ; vpinsrb $0x5,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,49 ; movzbl (%r9,%r14,1),%ebp + DB 196,227,121,32,197,6 ; vpinsrb $0x6,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,33 ; movzbl (%r9,%r12,1),%ebp + DB 196,227,121,32,197,7 ; vpinsrb $0x7,%ebp,%xmm0,%xmm0 + DB 196,226,125,49,192 ; vpmovzxbd %xmm0,%ymm0 + DB 197,124,91,208 ; vcvtdq2ps %ymm0,%ymm10 + DB 189,129,128,128,59 ; mov $0x3b808081,%ebp + DB 197,249,110,197 ; vmovd %ebp,%xmm0 + DB 196,98,125,88,200 ; vpbroadcastd %xmm0,%ymm9 + DB 196,193,44,89,193 ; vmulps %ymm9,%ymm10,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,253,91,201 ; vcvtps2dq %ymm1,%ymm1 + DB 196,227,249,22,205,1 ; vpextrq $0x1,%xmm1,%rbp + DB 65,137,233 ; mov %ebp,%r9d + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,225,249,126,203 ; vmovq %xmm1,%rbx + DB 65,137,218 ; mov %ebx,%r10d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,227,125,57,201,1 ; vextracti128 $0x1,%ymm1,%xmm1 + DB 196,195,249,22,203,1 ; vpextrq $0x1,%xmm1,%r11 + DB 69,137,222 ; mov %r11d,%r14d + DB 73,193,235,32 ; shr $0x20,%r11 + DB 196,193,249,126,207 ; vmovq %xmm1,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,131,121,32,12,16,0 ; vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm1 + DB 196,195,113,32,12,24,1 ; vpinsrb $0x1,(%r8,%rbx,1),%xmm1,%xmm1 + DB 67,15,182,28,8 ; movzbl (%r8,%r9,1),%ebx + DB 196,227,113,32,203,2 ; vpinsrb $0x2,%ebx,%xmm1,%xmm1 + DB 65,15,182,44,40 ; movzbl (%r8,%rbp,1),%ebp + DB 196,227,113,32,205,3 ; vpinsrb $0x3,%ebp,%xmm1,%xmm1 + DB 67,15,182,44,32 ; movzbl (%r8,%r12,1),%ebp + DB 196,227,113,32,205,4 ; vpinsrb $0x4,%ebp,%xmm1,%xmm1 + DB 67,15,182,44,56 ; movzbl (%r8,%r15,1),%ebp + DB 196,227,113,32,205,5 ; vpinsrb $0x5,%ebp,%xmm1,%xmm1 + DB 67,15,182,44,48 ; movzbl (%r8,%r14,1),%ebp + DB 196,227,113,32,205,6 ; vpinsrb $0x6,%ebp,%xmm1,%xmm1 + DB 67,15,182,44,24 ; movzbl (%r8,%r11,1),%ebp + DB 196,227,113,32,205,7 ; vpinsrb $0x7,%ebp,%xmm1,%xmm1 + DB 196,226,125,49,201 ; vpmovzxbd %xmm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 197,180,89,201 ; vmulps %ymm1,%ymm9,%ymm1 + DB 76,139,64,16 ; mov 0x10(%rax),%r8 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,253,91,210 ; vcvtps2dq %ymm2,%ymm2 + DB 196,227,249,22,213,1 ; vpextrq $0x1,%xmm2,%rbp + DB 65,137,233 ; mov %ebp,%r9d + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,225,249,126,211 ; vmovq %xmm2,%rbx + DB 65,137,218 ; mov %ebx,%r10d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,227,125,57,210,1 ; vextracti128 $0x1,%ymm2,%xmm2 + DB 196,195,249,22,211,1 ; vpextrq $0x1,%xmm2,%r11 + DB 69,137,222 ; mov %r11d,%r14d + DB 73,193,235,32 ; shr $0x20,%r11 + DB 196,193,249,126,215 ; vmovq %xmm2,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,131,121,32,20,16,0 ; vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm2 + DB 196,195,105,32,20,24,1 ; vpinsrb $0x1,(%r8,%rbx,1),%xmm2,%xmm2 + DB 67,15,182,28,8 ; movzbl (%r8,%r9,1),%ebx + DB 196,227,105,32,211,2 ; vpinsrb $0x2,%ebx,%xmm2,%xmm2 + DB 65,15,182,44,40 ; movzbl (%r8,%rbp,1),%ebp + DB 196,227,105,32,213,3 ; vpinsrb $0x3,%ebp,%xmm2,%xmm2 + DB 67,15,182,44,32 ; movzbl (%r8,%r12,1),%ebp + DB 196,227,105,32,213,4 ; vpinsrb $0x4,%ebp,%xmm2,%xmm2 + DB 67,15,182,44,56 ; movzbl (%r8,%r15,1),%ebp + DB 196,227,105,32,213,5 ; vpinsrb $0x5,%ebp,%xmm2,%xmm2 + DB 67,15,182,44,48 ; movzbl (%r8,%r14,1),%ebp + DB 196,227,105,32,213,6 ; vpinsrb $0x6,%ebp,%xmm2,%xmm2 + DB 67,15,182,44,24 ; movzbl (%r8,%r11,1),%ebp + DB 196,227,105,32,213,7 ; vpinsrb $0x7,%ebp,%xmm2,%xmm2 + DB 196,226,125,49,210 ; vpmovzxbd %xmm2,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 197,180,89,210 ; vmulps %ymm2,%ymm9,%ymm2 + DB 72,139,64,24 ; mov 0x18(%rax),%rax + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 197,253,91,219 ; vcvtps2dq %ymm3,%ymm3 + DB 196,227,249,22,221,1 ; vpextrq $0x1,%xmm3,%rbp + DB 65,137,232 ; mov %ebp,%r8d + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,225,249,126,219 ; vmovq %xmm3,%rbx + DB 65,137,217 ; mov %ebx,%r9d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,227,125,57,219,1 ; vextracti128 $0x1,%ymm3,%xmm3 + DB 196,195,249,22,218,1 ; vpextrq $0x1,%xmm3,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,193,249,126,222 ; vmovq %xmm3,%r14 + DB 69,137,247 ; mov %r14d,%r15d + DB 73,193,238,32 ; shr $0x20,%r14 + DB 196,163,121,32,28,8,0 ; vpinsrb $0x0,(%rax,%r9,1),%xmm0,%xmm3 + DB 196,227,97,32,28,24,1 ; vpinsrb $0x1,(%rax,%rbx,1),%xmm3,%xmm3 + DB 66,15,182,28,0 ; movzbl (%rax,%r8,1),%ebx + DB 196,227,97,32,219,2 ; vpinsrb $0x2,%ebx,%xmm3,%xmm3 + DB 15,182,44,40 ; movzbl (%rax,%rbp,1),%ebp + DB 196,227,97,32,221,3 ; vpinsrb $0x3,%ebp,%xmm3,%xmm3 + DB 66,15,182,44,56 ; movzbl (%rax,%r15,1),%ebp + DB 196,227,97,32,221,4 ; vpinsrb $0x4,%ebp,%xmm3,%xmm3 + DB 66,15,182,44,48 ; movzbl (%rax,%r14,1),%ebp + DB 196,227,97,32,221,5 ; vpinsrb $0x5,%ebp,%xmm3,%xmm3 + DB 66,15,182,44,24 ; movzbl (%rax,%r11,1),%ebp + DB 196,227,97,32,221,6 ; vpinsrb $0x6,%ebp,%xmm3,%xmm3 + DB 66,15,182,4,16 ; movzbl (%rax,%r10,1),%eax + DB 196,227,97,32,216,7 ; vpinsrb $0x7,%eax,%xmm3,%xmm3 + DB 196,226,125,49,219 ; vpmovzxbd %xmm3,%ymm3 + DB 197,252,91,219 ; vcvtdq2ps %ymm3,%ymm3 + DB 197,180,89,219 ; vmulps %ymm3,%ymm9,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 93 ; pop %rbp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_byte_tables_rgb_hsw +_sk_byte_tables_rgb_hsw LABEL PROC + DB 85 ; push %rbp + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 68,139,64,24 ; mov 0x18(%rax),%r8d + DB 65,255,200 ; dec %r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 196,65,124,91,192 ; vcvtdq2ps %ymm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,253,91,192 ; vcvtps2dq %ymm0,%ymm0 + DB 196,195,249,22,192,1 ; vpextrq $0x1,%xmm0,%r8 + DB 68,137,197 ; mov %r8d,%ebp + DB 77,137,194 ; mov %r8,%r10 + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,193,249,126,192 ; vmovq %xmm0,%r8 + DB 69,137,195 ; mov %r8d,%r11d + DB 77,137,199 ; mov %r8,%r15 + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,227,125,57,192,1 ; vextracti128 $0x1,%ymm0,%xmm0 + DB 196,195,249,22,192,1 ; vpextrq $0x1,%xmm0,%r8 + DB 69,137,198 ; mov %r8d,%r14d + DB 77,137,196 ; mov %r8,%r12 + DB 73,193,236,32 ; shr $0x20,%r12 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,221 ; mov %ebx,%r13d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 76,139,8 ; mov (%rax),%r9 + DB 76,139,64,8 ; mov 0x8(%rax),%r8 + DB 196,131,121,32,4,25,0 ; vpinsrb $0x0,(%r9,%r11,1),%xmm0,%xmm0 + DB 196,131,121,32,4,57,1 ; vpinsrb $0x1,(%r9,%r15,1),%xmm0,%xmm0 + DB 65,15,182,44,41 ; movzbl (%r9,%rbp,1),%ebp + DB 196,227,121,32,197,2 ; vpinsrb $0x2,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,17 ; movzbl (%r9,%r10,1),%ebp + DB 196,227,121,32,197,3 ; vpinsrb $0x3,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,41 ; movzbl (%r9,%r13,1),%ebp + DB 196,227,121,32,197,4 ; vpinsrb $0x4,%ebp,%xmm0,%xmm0 + DB 65,15,182,44,25 ; movzbl (%r9,%rbx,1),%ebp + DB 196,227,121,32,197,5 ; vpinsrb $0x5,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,49 ; movzbl (%r9,%r14,1),%ebp + DB 196,227,121,32,197,6 ; vpinsrb $0x6,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,33 ; movzbl (%r9,%r12,1),%ebp + DB 196,227,121,32,197,7 ; vpinsrb $0x7,%ebp,%xmm0,%xmm0 + DB 196,226,125,49,192 ; vpmovzxbd %xmm0,%ymm0 + DB 197,124,91,208 ; vcvtdq2ps %ymm0,%ymm10 + DB 189,129,128,128,59 ; mov $0x3b808081,%ebp + DB 197,249,110,197 ; vmovd %ebp,%xmm0 + DB 196,98,125,88,200 ; vpbroadcastd %xmm0,%ymm9 + DB 196,193,44,89,193 ; vmulps %ymm9,%ymm10,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,253,91,201 ; vcvtps2dq %ymm1,%ymm1 + DB 196,227,249,22,205,1 ; vpextrq $0x1,%xmm1,%rbp + DB 65,137,233 ; mov %ebp,%r9d + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,225,249,126,203 ; vmovq %xmm1,%rbx + DB 65,137,218 ; mov %ebx,%r10d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,227,125,57,201,1 ; vextracti128 $0x1,%ymm1,%xmm1 + DB 196,195,249,22,203,1 ; vpextrq $0x1,%xmm1,%r11 + DB 69,137,222 ; mov %r11d,%r14d + DB 73,193,235,32 ; shr $0x20,%r11 + DB 196,193,249,126,207 ; vmovq %xmm1,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,131,121,32,12,16,0 ; vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm1 + DB 196,195,113,32,12,24,1 ; vpinsrb $0x1,(%r8,%rbx,1),%xmm1,%xmm1 + DB 67,15,182,28,8 ; movzbl (%r8,%r9,1),%ebx + DB 196,227,113,32,203,2 ; vpinsrb $0x2,%ebx,%xmm1,%xmm1 + DB 65,15,182,44,40 ; movzbl (%r8,%rbp,1),%ebp + DB 196,227,113,32,205,3 ; vpinsrb $0x3,%ebp,%xmm1,%xmm1 + DB 67,15,182,44,32 ; movzbl (%r8,%r12,1),%ebp + DB 196,227,113,32,205,4 ; vpinsrb $0x4,%ebp,%xmm1,%xmm1 + DB 67,15,182,44,56 ; movzbl (%r8,%r15,1),%ebp + DB 196,227,113,32,205,5 ; vpinsrb $0x5,%ebp,%xmm1,%xmm1 + DB 67,15,182,44,48 ; movzbl (%r8,%r14,1),%ebp + DB 196,227,113,32,205,6 ; vpinsrb $0x6,%ebp,%xmm1,%xmm1 + DB 67,15,182,44,24 ; movzbl (%r8,%r11,1),%ebp + DB 196,227,113,32,205,7 ; vpinsrb $0x7,%ebp,%xmm1,%xmm1 + DB 196,226,125,49,201 ; vpmovzxbd %xmm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 197,180,89,201 ; vmulps %ymm1,%ymm9,%ymm1 + DB 72,139,64,16 ; mov 0x10(%rax),%rax + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,253,91,210 ; vcvtps2dq %ymm2,%ymm2 + DB 196,227,249,22,213,1 ; vpextrq $0x1,%xmm2,%rbp + DB 65,137,232 ; mov %ebp,%r8d + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,225,249,126,211 ; vmovq %xmm2,%rbx + DB 65,137,217 ; mov %ebx,%r9d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,227,125,57,210,1 ; vextracti128 $0x1,%ymm2,%xmm2 + DB 196,195,249,22,210,1 ; vpextrq $0x1,%xmm2,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,193,249,126,214 ; vmovq %xmm2,%r14 + DB 69,137,247 ; mov %r14d,%r15d + DB 73,193,238,32 ; shr $0x20,%r14 + DB 196,163,121,32,20,8,0 ; vpinsrb $0x0,(%rax,%r9,1),%xmm0,%xmm2 + DB 196,227,105,32,20,24,1 ; vpinsrb $0x1,(%rax,%rbx,1),%xmm2,%xmm2 + DB 66,15,182,28,0 ; movzbl (%rax,%r8,1),%ebx + DB 196,227,105,32,211,2 ; vpinsrb $0x2,%ebx,%xmm2,%xmm2 + DB 15,182,44,40 ; movzbl (%rax,%rbp,1),%ebp + DB 196,227,105,32,213,3 ; vpinsrb $0x3,%ebp,%xmm2,%xmm2 + DB 66,15,182,44,56 ; movzbl (%rax,%r15,1),%ebp + DB 196,227,105,32,213,4 ; vpinsrb $0x4,%ebp,%xmm2,%xmm2 + DB 66,15,182,44,48 ; movzbl (%rax,%r14,1),%ebp + DB 196,227,105,32,213,5 ; vpinsrb $0x5,%ebp,%xmm2,%xmm2 + DB 66,15,182,44,24 ; movzbl (%rax,%r11,1),%ebp + DB 196,227,105,32,213,6 ; vpinsrb $0x6,%ebp,%xmm2,%xmm2 + DB 66,15,182,4,16 ; movzbl (%rax,%r10,1),%eax + DB 196,227,105,32,208,7 ; vpinsrb $0x7,%eax,%xmm2,%xmm2 + DB 196,226,125,49,210 ; vpmovzxbd %xmm2,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 197,180,89,210 ; vmulps %ymm2,%ymm9,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 93 ; pop %rbp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_a8_hsw +_sk_load_a8_hsw LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,1,248 ; add %rdi,%rax + DB 77,133,192 ; test %r8,%r8 + DB 117,50 ; jne 1a72 <_sk_load_a8_hsw+0x42> + DB 197,250,126,0 ; vmovq (%rax),%xmm0 + DB 196,226,125,49,192 ; vpmovzxbd %xmm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,252,89,217 ; vmulps %ymm1,%ymm0,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 76,137,193 ; mov %r8,%rcx + DB 255,224 ; jmpq *%rax + DB 49,201 ; xor %ecx,%ecx + DB 77,137,194 ; mov %r8,%r10 + DB 69,49,201 ; xor %r9d,%r9d + DB 68,15,182,24 ; movzbl (%rax),%r11d + DB 72,255,192 ; inc %rax + DB 73,211,227 ; shl %cl,%r11 + DB 77,9,217 ; or %r11,%r9 + DB 72,131,193,8 ; add $0x8,%rcx + DB 73,255,202 ; dec %r10 + DB 117,234 ; jne 1a7a <_sk_load_a8_hsw+0x4a> + DB 196,193,249,110,193 ; vmovq %r9,%xmm0 + DB 235,173 ; jmp 1a44 <_sk_load_a8_hsw+0x14> + +PUBLIC _sk_gather_a8_hsw +_sk_gather_a8_hsw LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,201 ; vcvttps2dq %ymm1,%ymm1 + DB 196,226,125,88,80,16 ; vpbroadcastd 0x10(%rax),%ymm2 + DB 196,226,109,64,201 ; vpmulld %ymm1,%ymm2,%ymm1 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 197,245,254,192 ; vpaddd %ymm0,%ymm1,%ymm0 + DB 196,227,249,22,192,1 ; vpextrq $0x1,%xmm0,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,194 ; vmovq %xmm0,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,227,125,57,192,1 ; vextracti128 $0x1,%ymm0,%xmm0 + DB 196,227,249,22,195,1 ; vpextrq $0x1,%xmm0,%rbx + DB 65,137,222 ; mov %ebx,%r14d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,193,249,126,199 ; vmovq %xmm0,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,131,121,32,4,24,0 ; vpinsrb $0x0,(%r8,%r11,1),%xmm0,%xmm0 + DB 196,131,121,32,4,16,1 ; vpinsrb $0x1,(%r8,%r10,1),%xmm0,%xmm0 + DB 71,15,182,12,8 ; movzbl (%r8,%r9,1),%r9d + DB 196,195,121,32,193,2 ; vpinsrb $0x2,%r9d,%xmm0,%xmm0 + DB 65,15,182,4,0 ; movzbl (%r8,%rax,1),%eax + DB 196,227,121,32,192,3 ; vpinsrb $0x3,%eax,%xmm0,%xmm0 + DB 67,15,182,4,32 ; movzbl (%r8,%r12,1),%eax + DB 196,227,121,32,192,4 ; vpinsrb $0x4,%eax,%xmm0,%xmm0 + DB 67,15,182,4,56 ; movzbl (%r8,%r15,1),%eax + DB 196,227,121,32,192,5 ; vpinsrb $0x5,%eax,%xmm0,%xmm0 + DB 67,15,182,4,48 ; movzbl (%r8,%r14,1),%eax + DB 196,227,121,32,192,6 ; vpinsrb $0x6,%eax,%xmm0,%xmm0 + DB 65,15,182,4,24 ; movzbl (%r8,%rbx,1),%eax + DB 196,227,121,32,192,7 ; vpinsrb $0x7,%eax,%xmm0,%xmm0 + DB 196,226,125,49,192 ; vpmovzxbd %xmm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,252,89,217 ; vmulps %ymm1,%ymm0,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,237,239,210 ; vpxor %ymm2,%ymm2,%ymm2 + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_a8_hsw +_sk_store_a8_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 184,0,0,127,67 ; mov $0x437f0000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 196,65,125,91,192 ; vcvtps2dq %ymm8,%ymm8 + DB 196,67,125,25,193,1 ; vextractf128 $0x1,%ymm8,%xmm9 + DB 196,66,57,43,193 ; vpackusdw %xmm9,%xmm8,%xmm8 + DB 196,65,57,103,192 ; vpackuswb %xmm8,%xmm8,%xmm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,10 ; jne 1baf <_sk_store_a8_hsw+0x3b> + DB 196,65,123,17,4,57 ; vmovsd %xmm8,(%r9,%rdi,1) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 119,236 ; ja 1bab <_sk_store_a8_hsw+0x37> + DB 196,66,121,48,192 ; vpmovzxbw %xmm8,%xmm8 + DB 65,15,182,192 ; movzbl %r8b,%eax + DB 76,141,5,69,0,0,0 ; lea 0x45(%rip),%r8 # 1c14 <_sk_store_a8_hsw+0xa0> + DB 73,99,4,128 ; movslq (%r8,%rax,4),%rax + DB 76,1,192 ; add %r8,%rax + DB 255,224 ; jmpq *%rax + DB 196,67,121,20,68,57,6,12 ; vpextrb $0xc,%xmm8,0x6(%r9,%rdi,1) + DB 196,67,121,20,68,57,5,10 ; vpextrb $0xa,%xmm8,0x5(%r9,%rdi,1) + DB 196,67,121,20,68,57,4,8 ; vpextrb $0x8,%xmm8,0x4(%r9,%rdi,1) + DB 196,67,121,20,68,57,3,6 ; vpextrb $0x6,%xmm8,0x3(%r9,%rdi,1) + DB 196,67,121,20,68,57,2,4 ; vpextrb $0x4,%xmm8,0x2(%r9,%rdi,1) + DB 196,67,121,20,68,57,1,2 ; vpextrb $0x2,%xmm8,0x1(%r9,%rdi,1) + DB 196,67,121,20,4,57,0 ; vpextrb $0x0,%xmm8,(%r9,%rdi,1) + DB 235,154 ; jmp 1bab <_sk_store_a8_hsw+0x37> + DB 15,31,0 ; nopl (%rax) + DB 244 ; hlt + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 236 ; in (%dx),%al + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,228 ; jmpq *%rsp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 220,255 ; fdivr %st,%st(7) + DB 255 ; (bad) + DB 255,212 ; callq *%rsp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,204 ; dec %esp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,196 ; inc %esp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_load_g8_hsw +_sk_load_g8_hsw LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,1,248 ; add %rdi,%rax + DB 77,133,192 ; test %r8,%r8 + DB 117,60 ; jne 1c7c <_sk_load_g8_hsw+0x4c> + DB 197,250,126,0 ; vmovq (%rax),%xmm0 + DB 196,226,125,49,192 ; vpmovzxbd %xmm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,217 ; vpbroadcastd %xmm1,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,137,193 ; mov %r8,%rcx + DB 197,252,40,200 ; vmovaps %ymm0,%ymm1 + DB 197,252,40,208 ; vmovaps %ymm0,%ymm2 + DB 255,224 ; jmpq *%rax + DB 49,201 ; xor %ecx,%ecx + DB 77,137,194 ; mov %r8,%r10 + DB 69,49,201 ; xor %r9d,%r9d + DB 68,15,182,24 ; movzbl (%rax),%r11d + DB 72,255,192 ; inc %rax + DB 73,211,227 ; shl %cl,%r11 + DB 77,9,217 ; or %r11,%r9 + DB 72,131,193,8 ; add $0x8,%rcx + DB 73,255,202 ; dec %r10 + DB 117,234 ; jne 1c84 <_sk_load_g8_hsw+0x54> + DB 196,193,249,110,193 ; vmovq %r9,%xmm0 + DB 235,163 ; jmp 1c44 <_sk_load_g8_hsw+0x14> + +PUBLIC _sk_gather_g8_hsw +_sk_gather_g8_hsw LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,201 ; vcvttps2dq %ymm1,%ymm1 + DB 196,226,125,88,80,16 ; vpbroadcastd 0x10(%rax),%ymm2 + DB 196,226,109,64,201 ; vpmulld %ymm1,%ymm2,%ymm1 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 197,245,254,192 ; vpaddd %ymm0,%ymm1,%ymm0 + DB 196,227,249,22,192,1 ; vpextrq $0x1,%xmm0,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,194 ; vmovq %xmm0,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,227,125,57,192,1 ; vextracti128 $0x1,%ymm0,%xmm0 + DB 196,227,249,22,195,1 ; vpextrq $0x1,%xmm0,%rbx + DB 65,137,222 ; mov %ebx,%r14d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,193,249,126,199 ; vmovq %xmm0,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,131,121,32,4,24,0 ; vpinsrb $0x0,(%r8,%r11,1),%xmm0,%xmm0 + DB 196,131,121,32,4,16,1 ; vpinsrb $0x1,(%r8,%r10,1),%xmm0,%xmm0 + DB 71,15,182,12,8 ; movzbl (%r8,%r9,1),%r9d + DB 196,195,121,32,193,2 ; vpinsrb $0x2,%r9d,%xmm0,%xmm0 + DB 65,15,182,4,0 ; movzbl (%r8,%rax,1),%eax + DB 196,227,121,32,192,3 ; vpinsrb $0x3,%eax,%xmm0,%xmm0 + DB 67,15,182,4,32 ; movzbl (%r8,%r12,1),%eax + DB 196,227,121,32,192,4 ; vpinsrb $0x4,%eax,%xmm0,%xmm0 + DB 67,15,182,4,56 ; movzbl (%r8,%r15,1),%eax + DB 196,227,121,32,192,5 ; vpinsrb $0x5,%eax,%xmm0,%xmm0 + DB 67,15,182,4,48 ; movzbl (%r8,%r14,1),%eax + DB 196,227,121,32,192,6 ; vpinsrb $0x6,%eax,%xmm0,%xmm0 + DB 65,15,182,4,24 ; movzbl (%r8,%rbx,1),%eax + DB 196,227,121,32,192,7 ; vpinsrb $0x7,%eax,%xmm0,%xmm0 + DB 196,226,125,49,192 ; vpmovzxbd %xmm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,217 ; vpbroadcastd %xmm1,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,200 ; vmovaps %ymm0,%ymm1 + DB 197,252,40,208 ; vmovaps %ymm0,%ymm2 + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_i8_hsw +_sk_gather_i8_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 73,137,192 ; mov %rax,%r8 + DB 77,133,192 ; test %r8,%r8 + DB 116,5 ; je 1d97 <_sk_gather_i8_hsw+0xf> + DB 76,137,192 ; mov %r8,%rax + DB 235,2 ; jmp 1d99 <_sk_gather_i8_hsw+0x11> + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 76,139,8 ; mov (%rax),%r9 + DB 197,254,91,201 ; vcvttps2dq %ymm1,%ymm1 + DB 196,226,125,88,80,16 ; vpbroadcastd 0x10(%rax),%ymm2 + DB 196,226,109,64,201 ; vpmulld %ymm1,%ymm2,%ymm1 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 197,245,254,192 ; vpaddd %ymm0,%ymm1,%ymm0 + DB 196,227,249,22,192,1 ; vpextrq $0x1,%xmm0,%rax + DB 65,137,194 ; mov %eax,%r10d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,195 ; vmovq %xmm0,%r11 + DB 69,137,222 ; mov %r11d,%r14d + DB 73,193,235,32 ; shr $0x20,%r11 + DB 196,227,125,57,192,1 ; vextracti128 $0x1,%ymm0,%xmm0 + DB 196,227,249,22,195,1 ; vpextrq $0x1,%xmm0,%rbx + DB 65,137,223 ; mov %ebx,%r15d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,193,249,126,196 ; vmovq %xmm0,%r12 + DB 69,137,229 ; mov %r12d,%r13d + DB 73,193,236,32 ; shr $0x20,%r12 + DB 196,131,121,32,4,49,0 ; vpinsrb $0x0,(%r9,%r14,1),%xmm0,%xmm0 + DB 196,131,121,32,4,25,1 ; vpinsrb $0x1,(%r9,%r11,1),%xmm0,%xmm0 + DB 196,131,121,32,4,17,2 ; vpinsrb $0x2,(%r9,%r10,1),%xmm0,%xmm0 + DB 196,195,121,32,4,1,3 ; vpinsrb $0x3,(%r9,%rax,1),%xmm0,%xmm0 + DB 196,131,121,32,4,41,4 ; vpinsrb $0x4,(%r9,%r13,1),%xmm0,%xmm0 + DB 196,131,121,32,4,33,5 ; vpinsrb $0x5,(%r9,%r12,1),%xmm0,%xmm0 + DB 196,131,121,32,4,57,6 ; vpinsrb $0x6,(%r9,%r15,1),%xmm0,%xmm0 + DB 196,195,121,32,4,25,7 ; vpinsrb $0x7,(%r9,%rbx,1),%xmm0,%xmm0 + DB 196,226,125,49,192 ; vpmovzxbd %xmm0,%ymm0 + DB 73,139,64,8 ; mov 0x8(%r8),%rax + DB 197,245,118,201 ; vpcmpeqd %ymm1,%ymm1,%ymm1 + DB 196,226,117,144,28,128 ; vpgatherdd %ymm1,(%rax,%ymm0,4),%ymm3 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,226,125,88,208 ; vpbroadcastd %xmm0,%ymm2 + DB 197,237,219,195 ; vpand %ymm3,%ymm2,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,98,125,88,193 ; vpbroadcastd %xmm1,%ymm8 + DB 196,193,124,89,192 ; vmulps %ymm8,%ymm0,%ymm0 + DB 197,245,114,211,8 ; vpsrld $0x8,%ymm3,%ymm1 + DB 197,237,219,201 ; vpand %ymm1,%ymm2,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 196,193,116,89,200 ; vmulps %ymm8,%ymm1,%ymm1 + DB 197,181,114,211,16 ; vpsrld $0x10,%ymm3,%ymm9 + DB 196,193,109,219,209 ; vpand %ymm9,%ymm2,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 196,193,108,89,208 ; vmulps %ymm8,%ymm2,%ymm2 + DB 197,229,114,211,24 ; vpsrld $0x18,%ymm3,%ymm3 + DB 197,252,91,219 ; vcvtdq2ps %ymm3,%ymm3 + DB 196,193,100,89,216 ; vmulps %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_565_hsw +_sk_load_565_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,16 ; mov (%rax),%r10 + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,149,0,0,0 ; jne 1f4b <_sk_load_565_hsw+0xa3> + DB 196,193,122,111,4,122 ; vmovdqu (%r10,%rdi,2),%xmm0 + DB 196,226,125,51,208 ; vpmovzxwd %xmm0,%ymm2 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 197,253,219,194 ; vpand %ymm2,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,245,219,202 ; vpand %ymm2,%ymm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,244,89,203 ; vmulps %ymm3,%ymm1,%ymm1 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,229,219,210 ; vpand %ymm2,%ymm3,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,236,89,211 ; vmulps %ymm3,%ymm2,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 197,249,239,192 ; vpxor %xmm0,%xmm0,%xmm0 + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 15,135,89,255,255,255 ; ja 1ebc <_sk_load_565_hsw+0x14> + DB 69,15,182,192 ; movzbl %r8b,%r8d + DB 76,141,13,74,0,0,0 ; lea 0x4a(%rip),%r9 # 1fb8 <_sk_load_565_hsw+0x110> + DB 75,99,4,129 ; movslq (%r9,%r8,4),%rax + DB 76,1,200 ; add %r9,%rax + DB 255,224 ; jmpq *%rax + DB 197,249,239,192 ; vpxor %xmm0,%xmm0,%xmm0 + DB 196,193,121,196,68,122,12,6 ; vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,10,5 ; vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,8,4 ; vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,6,3 ; vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,4,2 ; vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,2,1 ; vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,4,122,0 ; vpinsrw $0x0,(%r10,%rdi,2),%xmm0,%xmm0 + DB 233,5,255,255,255 ; jmpq 1ebc <_sk_load_565_hsw+0x14> + DB 144 ; nop + DB 243,255 ; repz (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 235,255 ; jmp 1fbd <_sk_load_565_hsw+0x115> + DB 255 ; (bad) + DB 255,227 ; jmpq *%rbx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 219,255 ; (bad) + DB 255 ; (bad) + DB 255,211 ; callq *%rbx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,203 ; dec %ebx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 191 ; .byte 0xbf + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_gather_565_hsw +_sk_gather_565_hsw LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,201 ; vcvttps2dq %ymm1,%ymm1 + DB 196,226,125,88,80,16 ; vpbroadcastd 0x10(%rax),%ymm2 + DB 196,226,109,64,201 ; vpmulld %ymm1,%ymm2,%ymm1 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 197,245,254,192 ; vpaddd %ymm0,%ymm1,%ymm0 + DB 196,227,249,22,192,1 ; vpextrq $0x1,%xmm0,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,194 ; vmovq %xmm0,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,227,125,57,192,1 ; vextracti128 $0x1,%ymm0,%xmm0 + DB 196,227,249,22,195,1 ; vpextrq $0x1,%xmm0,%rbx + DB 65,137,222 ; mov %ebx,%r14d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,193,249,126,199 ; vmovq %xmm0,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 71,15,183,20,80 ; movzwl (%r8,%r10,2),%r10d + DB 71,15,183,28,88 ; movzwl (%r8,%r11,2),%r11d + DB 196,193,121,110,195 ; vmovd %r11d,%xmm0 + DB 196,193,121,196,194,1 ; vpinsrw $0x1,%r10d,%xmm0,%xmm0 + DB 71,15,183,12,72 ; movzwl (%r8,%r9,2),%r9d + DB 196,193,121,196,193,2 ; vpinsrw $0x2,%r9d,%xmm0,%xmm0 + DB 65,15,183,4,64 ; movzwl (%r8,%rax,2),%eax + DB 197,249,196,192,3 ; vpinsrw $0x3,%eax,%xmm0,%xmm0 + DB 67,15,183,4,96 ; movzwl (%r8,%r12,2),%eax + DB 197,249,196,192,4 ; vpinsrw $0x4,%eax,%xmm0,%xmm0 + DB 67,15,183,4,120 ; movzwl (%r8,%r15,2),%eax + DB 197,249,196,192,5 ; vpinsrw $0x5,%eax,%xmm0,%xmm0 + DB 67,15,183,4,112 ; movzwl (%r8,%r14,2),%eax + DB 197,249,196,192,6 ; vpinsrw $0x6,%eax,%xmm0,%xmm0 + DB 65,15,183,4,88 ; movzwl (%r8,%rbx,2),%eax + DB 197,249,196,192,7 ; vpinsrw $0x7,%eax,%xmm0,%xmm0 + DB 196,226,125,51,208 ; vpmovzxwd %xmm0,%ymm2 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 197,253,219,194 ; vpand %ymm2,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,245,219,202 ; vpand %ymm2,%ymm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,244,89,203 ; vmulps %ymm3,%ymm1,%ymm1 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,229,219,210 ; vpand %ymm2,%ymm3,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,236,89,211 ; vmulps %ymm3,%ymm2,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_565_hsw +_sk_store_565_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 184,0,0,248,65 ; mov $0x41f80000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 196,65,125,91,201 ; vcvtps2dq %ymm9,%ymm9 + DB 196,193,53,114,241,11 ; vpslld $0xb,%ymm9,%ymm9 + DB 184,0,0,124,66 ; mov $0x427c0000,%eax + DB 197,121,110,208 ; vmovd %eax,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 197,44,89,209 ; vmulps %ymm1,%ymm10,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,193,45,114,242,5 ; vpslld $0x5,%ymm10,%ymm10 + DB 196,65,45,235,201 ; vpor %ymm9,%ymm10,%ymm9 + DB 197,60,89,194 ; vmulps %ymm2,%ymm8,%ymm8 + DB 196,65,125,91,192 ; vcvtps2dq %ymm8,%ymm8 + DB 196,65,53,235,192 ; vpor %ymm8,%ymm9,%ymm8 + DB 196,67,125,57,193,1 ; vextracti128 $0x1,%ymm8,%xmm9 + DB 196,66,57,43,193 ; vpackusdw %xmm9,%xmm8,%xmm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,10 ; jne 2183 <_sk_store_565_hsw+0x6c> + DB 196,65,122,127,4,121 ; vmovdqu %xmm8,(%r9,%rdi,2) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 119,236 ; ja 217f <_sk_store_565_hsw+0x68> + DB 65,15,182,192 ; movzbl %r8b,%eax + DB 76,141,5,66,0,0,0 ; lea 0x42(%rip),%r8 # 21e0 <_sk_store_565_hsw+0xc9> + DB 73,99,4,128 ; movslq (%r8,%rax,4),%rax + DB 76,1,192 ; add %r8,%rax + DB 255,224 ; jmpq *%rax + DB 196,67,121,21,68,121,12,6 ; vpextrw $0x6,%xmm8,0xc(%r9,%rdi,2) + DB 196,67,121,21,68,121,10,5 ; vpextrw $0x5,%xmm8,0xa(%r9,%rdi,2) + DB 196,67,121,21,68,121,8,4 ; vpextrw $0x4,%xmm8,0x8(%r9,%rdi,2) + DB 196,67,121,21,68,121,6,3 ; vpextrw $0x3,%xmm8,0x6(%r9,%rdi,2) + DB 196,67,121,21,68,121,4,2 ; vpextrw $0x2,%xmm8,0x4(%r9,%rdi,2) + DB 196,67,121,21,68,121,2,1 ; vpextrw $0x1,%xmm8,0x2(%r9,%rdi,2) + DB 196,67,121,21,4,121,0 ; vpextrw $0x0,%xmm8,(%r9,%rdi,2) + DB 235,159 ; jmp 217f <_sk_store_565_hsw+0x68> + DB 247,255 ; idiv %edi + DB 255 ; (bad) + DB 255 ; (bad) + DB 239 ; out %eax,(%dx) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,231 ; jmpq *%rdi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 223,255 ; (bad) + DB 255 ; (bad) + DB 255,215 ; callq *%rdi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,207 ; dec %edi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,199 ; inc %edi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_load_4444_hsw +_sk_load_4444_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,16 ; mov (%rax),%r10 + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,179,0,0,0 ; jne 22bd <_sk_load_4444_hsw+0xc1> + DB 196,193,122,111,4,122 ; vmovdqu (%r10,%rdi,2),%xmm0 + DB 196,98,125,51,200 ; vpmovzxwd %xmm0,%ymm9 + DB 184,0,240,0,0 ; mov $0xf000,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 196,193,125,219,193 ; vpand %ymm9,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,137,136,136,55 ; mov $0x37888889,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,0,15,0,0 ; mov $0xf00,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 196,193,117,219,201 ; vpand %ymm9,%ymm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 184,137,136,136,57 ; mov $0x39888889,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,226,125,88,210 ; vpbroadcastd %xmm2,%ymm2 + DB 197,244,89,202 ; vmulps %ymm2,%ymm1,%ymm1 + DB 184,240,0,0,0 ; mov $0xf0,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,226,125,88,210 ; vpbroadcastd %xmm2,%ymm2 + DB 196,193,109,219,209 ; vpand %ymm9,%ymm2,%ymm2 + DB 197,124,91,194 ; vcvtdq2ps %ymm2,%ymm8 + DB 184,137,136,136,59 ; mov $0x3b888889,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,226,125,88,210 ; vpbroadcastd %xmm2,%ymm2 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 184,15,0,0,0 ; mov $0xf,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 196,193,101,219,217 ; vpand %ymm9,%ymm3,%ymm3 + DB 197,124,91,195 ; vcvtdq2ps %ymm3,%ymm8 + DB 184,137,136,136,61 ; mov $0x3d888889,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 197,249,239,192 ; vpxor %xmm0,%xmm0,%xmm0 + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 15,135,59,255,255,255 ; ja 2210 <_sk_load_4444_hsw+0x14> + DB 69,15,182,192 ; movzbl %r8b,%r8d + DB 76,141,13,76,0,0,0 ; lea 0x4c(%rip),%r9 # 232c <_sk_load_4444_hsw+0x130> + DB 75,99,4,129 ; movslq (%r9,%r8,4),%rax + DB 76,1,200 ; add %r9,%rax + DB 255,224 ; jmpq *%rax + DB 197,249,239,192 ; vpxor %xmm0,%xmm0,%xmm0 + DB 196,193,121,196,68,122,12,6 ; vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,10,5 ; vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,8,4 ; vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,6,3 ; vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,4,2 ; vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,2,1 ; vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,4,122,0 ; vpinsrw $0x0,(%r10,%rdi,2),%xmm0,%xmm0 + DB 233,231,254,255,255 ; jmpq 2210 <_sk_load_4444_hsw+0x14> + DB 15,31,0 ; nopl (%rax) + DB 241 ; icebp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 233,255,255,255,225 ; jmpq ffffffffe2002334 <_sk_bicubic_p3y_hsw+0xffffffffe1ffecd5> + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 217,255 ; fcos + DB 255 ; (bad) + DB 255,209 ; callq *%rcx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,201 ; dec %ecx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 189 ; .byte 0xbd + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_gather_4444_hsw +_sk_gather_4444_hsw LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,201 ; vcvttps2dq %ymm1,%ymm1 + DB 196,226,125,88,80,16 ; vpbroadcastd 0x10(%rax),%ymm2 + DB 196,226,109,64,201 ; vpmulld %ymm1,%ymm2,%ymm1 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 197,245,254,192 ; vpaddd %ymm0,%ymm1,%ymm0 + DB 196,227,249,22,192,1 ; vpextrq $0x1,%xmm0,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,194 ; vmovq %xmm0,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,227,125,57,192,1 ; vextracti128 $0x1,%ymm0,%xmm0 + DB 196,227,249,22,195,1 ; vpextrq $0x1,%xmm0,%rbx + DB 65,137,222 ; mov %ebx,%r14d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,193,249,126,199 ; vmovq %xmm0,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 71,15,183,20,80 ; movzwl (%r8,%r10,2),%r10d + DB 71,15,183,28,88 ; movzwl (%r8,%r11,2),%r11d + DB 196,193,121,110,195 ; vmovd %r11d,%xmm0 + DB 196,193,121,196,194,1 ; vpinsrw $0x1,%r10d,%xmm0,%xmm0 + DB 71,15,183,12,72 ; movzwl (%r8,%r9,2),%r9d + DB 196,193,121,196,193,2 ; vpinsrw $0x2,%r9d,%xmm0,%xmm0 + DB 65,15,183,4,64 ; movzwl (%r8,%rax,2),%eax + DB 197,249,196,192,3 ; vpinsrw $0x3,%eax,%xmm0,%xmm0 + DB 67,15,183,4,96 ; movzwl (%r8,%r12,2),%eax + DB 197,249,196,192,4 ; vpinsrw $0x4,%eax,%xmm0,%xmm0 + DB 67,15,183,4,120 ; movzwl (%r8,%r15,2),%eax + DB 197,249,196,192,5 ; vpinsrw $0x5,%eax,%xmm0,%xmm0 + DB 67,15,183,4,112 ; movzwl (%r8,%r14,2),%eax + DB 197,249,196,192,6 ; vpinsrw $0x6,%eax,%xmm0,%xmm0 + DB 65,15,183,4,88 ; movzwl (%r8,%rbx,2),%eax + DB 197,249,196,192,7 ; vpinsrw $0x7,%eax,%xmm0,%xmm0 + DB 196,98,125,51,200 ; vpmovzxwd %xmm0,%ymm9 + DB 184,0,240,0,0 ; mov $0xf000,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 196,193,125,219,193 ; vpand %ymm9,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,137,136,136,55 ; mov $0x37888889,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,0,15,0,0 ; mov $0xf00,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 196,193,117,219,201 ; vpand %ymm9,%ymm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 184,137,136,136,57 ; mov $0x39888889,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,226,125,88,210 ; vpbroadcastd %xmm2,%ymm2 + DB 197,244,89,202 ; vmulps %ymm2,%ymm1,%ymm1 + DB 184,240,0,0,0 ; mov $0xf0,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,226,125,88,210 ; vpbroadcastd %xmm2,%ymm2 + DB 196,193,109,219,209 ; vpand %ymm9,%ymm2,%ymm2 + DB 197,124,91,194 ; vcvtdq2ps %ymm2,%ymm8 + DB 184,137,136,136,59 ; mov $0x3b888889,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,226,125,88,210 ; vpbroadcastd %xmm2,%ymm2 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 184,15,0,0,0 ; mov $0xf,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 196,193,101,219,217 ; vpand %ymm9,%ymm3,%ymm3 + DB 197,124,91,195 ; vcvtdq2ps %ymm3,%ymm8 + DB 184,137,136,136,61 ; mov $0x3d888889,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_4444_hsw +_sk_store_4444_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 184,0,0,112,65 ; mov $0x41700000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 196,65,125,91,201 ; vcvtps2dq %ymm9,%ymm9 + DB 196,193,53,114,241,12 ; vpslld $0xc,%ymm9,%ymm9 + DB 197,60,89,209 ; vmulps %ymm1,%ymm8,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,193,45,114,242,8 ; vpslld $0x8,%ymm10,%ymm10 + DB 196,65,45,235,201 ; vpor %ymm9,%ymm10,%ymm9 + DB 197,60,89,210 ; vmulps %ymm2,%ymm8,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,193,45,114,242,4 ; vpslld $0x4,%ymm10,%ymm10 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 196,65,125,91,192 ; vcvtps2dq %ymm8,%ymm8 + DB 196,65,45,235,192 ; vpor %ymm8,%ymm10,%ymm8 + DB 196,65,53,235,192 ; vpor %ymm8,%ymm9,%ymm8 + DB 196,67,125,57,193,1 ; vextracti128 $0x1,%ymm8,%xmm9 + DB 196,66,57,43,193 ; vpackusdw %xmm9,%xmm8,%xmm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,10 ; jne 251b <_sk_store_4444_hsw+0x72> + DB 196,65,122,127,4,121 ; vmovdqu %xmm8,(%r9,%rdi,2) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 119,236 ; ja 2517 <_sk_store_4444_hsw+0x6e> + DB 65,15,182,192 ; movzbl %r8b,%eax + DB 76,141,5,66,0,0,0 ; lea 0x42(%rip),%r8 # 2578 <_sk_store_4444_hsw+0xcf> + DB 73,99,4,128 ; movslq (%r8,%rax,4),%rax + DB 76,1,192 ; add %r8,%rax + DB 255,224 ; jmpq *%rax + DB 196,67,121,21,68,121,12,6 ; vpextrw $0x6,%xmm8,0xc(%r9,%rdi,2) + DB 196,67,121,21,68,121,10,5 ; vpextrw $0x5,%xmm8,0xa(%r9,%rdi,2) + DB 196,67,121,21,68,121,8,4 ; vpextrw $0x4,%xmm8,0x8(%r9,%rdi,2) + DB 196,67,121,21,68,121,6,3 ; vpextrw $0x3,%xmm8,0x6(%r9,%rdi,2) + DB 196,67,121,21,68,121,4,2 ; vpextrw $0x2,%xmm8,0x4(%r9,%rdi,2) + DB 196,67,121,21,68,121,2,1 ; vpextrw $0x1,%xmm8,0x2(%r9,%rdi,2) + DB 196,67,121,21,4,121,0 ; vpextrw $0x0,%xmm8,(%r9,%rdi,2) + DB 235,159 ; jmp 2517 <_sk_store_4444_hsw+0x6e> + DB 247,255 ; idiv %edi + DB 255 ; (bad) + DB 255 ; (bad) + DB 239 ; out %eax,(%dx) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,231 ; jmpq *%rdi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 223,255 ; (bad) + DB 255 ; (bad) + DB 255,215 ; callq *%rdi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,207 ; dec %edi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,199 ; inc %edi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_load_8888_hsw +_sk_load_8888_hsw LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,141,12,189,0,0,0,0 ; lea 0x0(,%rdi,4),%r9 + DB 76,3,8 ; add (%rax),%r9 + DB 77,133,192 ; test %r8,%r8 + DB 117,104 ; jne 2611 <_sk_load_8888_hsw+0x7d> + DB 196,193,126,111,25 ; vmovdqu (%r9),%ymm3 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,226,125,88,208 ; vpbroadcastd %xmm0,%ymm2 + DB 197,237,219,195 ; vpand %ymm3,%ymm2,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,98,125,88,193 ; vpbroadcastd %xmm1,%ymm8 + DB 196,193,124,89,192 ; vmulps %ymm8,%ymm0,%ymm0 + DB 197,245,114,211,8 ; vpsrld $0x8,%ymm3,%ymm1 + DB 197,237,219,201 ; vpand %ymm1,%ymm2,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 196,193,116,89,200 ; vmulps %ymm8,%ymm1,%ymm1 + DB 197,181,114,211,16 ; vpsrld $0x10,%ymm3,%ymm9 + DB 196,193,109,219,209 ; vpand %ymm9,%ymm2,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 196,193,108,89,208 ; vmulps %ymm8,%ymm2,%ymm2 + DB 197,229,114,211,24 ; vpsrld $0x18,%ymm3,%ymm3 + DB 197,252,91,219 ; vcvtdq2ps %ymm3,%ymm3 + DB 196,193,100,89,216 ; vmulps %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,137,193 ; mov %r8,%rcx + DB 255,224 ; jmpq *%rax + DB 185,8,0,0,0 ; mov $0x8,%ecx + DB 68,41,193 ; sub %r8d,%ecx + DB 192,225,3 ; shl $0x3,%cl + DB 72,199,192,255,255,255,255 ; mov $0xffffffffffffffff,%rax + DB 72,211,232 ; shr %cl,%rax + DB 196,225,249,110,192 ; vmovq %rax,%xmm0 + DB 196,226,125,33,192 ; vpmovsxbd %xmm0,%ymm0 + DB 196,194,125,140,25 ; vpmaskmovd (%r9),%ymm0,%ymm3 + DB 233,116,255,255,255 ; jmpq 25ae <_sk_load_8888_hsw+0x1a> + +PUBLIC _sk_gather_8888_hsw +_sk_gather_8888_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,201 ; vcvttps2dq %ymm1,%ymm1 + DB 196,226,125,88,80,16 ; vpbroadcastd 0x10(%rax),%ymm2 + DB 196,226,109,64,201 ; vpmulld %ymm1,%ymm2,%ymm1 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 197,245,254,192 ; vpaddd %ymm0,%ymm1,%ymm0 + DB 197,245,118,201 ; vpcmpeqd %ymm1,%ymm1,%ymm1 + DB 196,194,117,144,28,128 ; vpgatherdd %ymm1,(%r8,%ymm0,4),%ymm3 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,226,125,88,208 ; vpbroadcastd %xmm0,%ymm2 + DB 197,237,219,195 ; vpand %ymm3,%ymm2,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,98,125,88,193 ; vpbroadcastd %xmm1,%ymm8 + DB 196,193,124,89,192 ; vmulps %ymm8,%ymm0,%ymm0 + DB 197,245,114,211,8 ; vpsrld $0x8,%ymm3,%ymm1 + DB 197,237,219,201 ; vpand %ymm1,%ymm2,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 196,193,116,89,200 ; vmulps %ymm8,%ymm1,%ymm1 + DB 197,181,114,211,16 ; vpsrld $0x10,%ymm3,%ymm9 + DB 196,193,109,219,209 ; vpand %ymm9,%ymm2,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 196,193,108,89,208 ; vmulps %ymm8,%ymm2,%ymm2 + DB 197,229,114,211,24 ; vpsrld $0x18,%ymm3,%ymm3 + DB 197,252,91,219 ; vcvtdq2ps %ymm3,%ymm3 + DB 196,193,100,89,216 ; vmulps %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_8888_hsw +_sk_store_8888_hsw LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,141,12,189,0,0,0,0 ; lea 0x0(,%rdi,4),%r9 + DB 76,3,8 ; add (%rax),%r9 + DB 184,0,0,127,67 ; mov $0x437f0000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 196,65,125,91,201 ; vcvtps2dq %ymm9,%ymm9 + DB 197,60,89,209 ; vmulps %ymm1,%ymm8,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,193,45,114,242,8 ; vpslld $0x8,%ymm10,%ymm10 + DB 196,65,45,235,201 ; vpor %ymm9,%ymm10,%ymm9 + DB 197,60,89,210 ; vmulps %ymm2,%ymm8,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,193,45,114,242,16 ; vpslld $0x10,%ymm10,%ymm10 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 196,65,125,91,192 ; vcvtps2dq %ymm8,%ymm8 + DB 196,193,61,114,240,24 ; vpslld $0x18,%ymm8,%ymm8 + DB 196,65,45,235,192 ; vpor %ymm8,%ymm10,%ymm8 + DB 196,65,53,235,192 ; vpor %ymm8,%ymm9,%ymm8 + DB 77,133,192 ; test %r8,%r8 + DB 117,12 ; jne 2734 <_sk_store_8888_hsw+0x74> + DB 196,65,126,127,1 ; vmovdqu %ymm8,(%r9) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,137,193 ; mov %r8,%rcx + DB 255,224 ; jmpq *%rax + DB 185,8,0,0,0 ; mov $0x8,%ecx + DB 68,41,193 ; sub %r8d,%ecx + DB 192,225,3 ; shl $0x3,%cl + DB 72,199,192,255,255,255,255 ; mov $0xffffffffffffffff,%rax + DB 72,211,232 ; shr %cl,%rax + DB 196,97,249,110,200 ; vmovq %rax,%xmm9 + DB 196,66,125,33,201 ; vpmovsxbd %xmm9,%ymm9 + DB 196,66,53,142,1 ; vpmaskmovd %ymm8,%ymm9,(%r9) + DB 235,211 ; jmp 272d <_sk_store_8888_hsw+0x6d> + +PUBLIC _sk_load_f16_hsw +_sk_load_f16_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,133,201 ; test %rcx,%rcx + DB 117,97 ; jne 27c5 <_sk_load_f16_hsw+0x6b> + DB 197,121,16,4,248 ; vmovupd (%rax,%rdi,8),%xmm8 + DB 197,249,16,84,248,16 ; vmovupd 0x10(%rax,%rdi,8),%xmm2 + DB 197,249,16,92,248,32 ; vmovupd 0x20(%rax,%rdi,8),%xmm3 + DB 197,122,111,76,248,48 ; vmovdqu 0x30(%rax,%rdi,8),%xmm9 + DB 197,185,97,194 ; vpunpcklwd %xmm2,%xmm8,%xmm0 + DB 197,185,105,210 ; vpunpckhwd %xmm2,%xmm8,%xmm2 + DB 196,193,97,97,201 ; vpunpcklwd %xmm9,%xmm3,%xmm1 + DB 196,193,97,105,217 ; vpunpckhwd %xmm9,%xmm3,%xmm3 + DB 197,121,97,194 ; vpunpcklwd %xmm2,%xmm0,%xmm8 + DB 197,121,105,202 ; vpunpckhwd %xmm2,%xmm0,%xmm9 + DB 197,241,97,211 ; vpunpcklwd %xmm3,%xmm1,%xmm2 + DB 197,241,105,219 ; vpunpckhwd %xmm3,%xmm1,%xmm3 + DB 197,185,108,194 ; vpunpcklqdq %xmm2,%xmm8,%xmm0 + DB 196,226,125,19,192 ; vcvtph2ps %xmm0,%ymm0 + DB 197,185,109,202 ; vpunpckhqdq %xmm2,%xmm8,%xmm1 + DB 196,226,125,19,201 ; vcvtph2ps %xmm1,%ymm1 + DB 197,177,108,211 ; vpunpcklqdq %xmm3,%xmm9,%xmm2 + DB 196,226,125,19,210 ; vcvtph2ps %xmm2,%ymm2 + DB 197,177,109,219 ; vpunpckhqdq %xmm3,%xmm9,%xmm3 + DB 196,226,125,19,219 ; vcvtph2ps %xmm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 197,123,16,4,248 ; vmovsd (%rax,%rdi,8),%xmm8 + DB 196,65,49,239,201 ; vpxor %xmm9,%xmm9,%xmm9 + DB 72,131,249,1 ; cmp $0x1,%rcx + DB 116,79 ; je 2824 <_sk_load_f16_hsw+0xca> + DB 197,57,22,68,248,8 ; vmovhpd 0x8(%rax,%rdi,8),%xmm8,%xmm8 + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 114,67 ; jb 2824 <_sk_load_f16_hsw+0xca> + DB 197,251,16,84,248,16 ; vmovsd 0x10(%rax,%rdi,8),%xmm2 + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 116,68 ; je 2831 <_sk_load_f16_hsw+0xd7> + DB 197,233,22,84,248,24 ; vmovhpd 0x18(%rax,%rdi,8),%xmm2,%xmm2 + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 114,56 ; jb 2831 <_sk_load_f16_hsw+0xd7> + DB 197,251,16,92,248,32 ; vmovsd 0x20(%rax,%rdi,8),%xmm3 + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 15,132,114,255,255,255 ; je 277b <_sk_load_f16_hsw+0x21> + DB 197,225,22,92,248,40 ; vmovhpd 0x28(%rax,%rdi,8),%xmm3,%xmm3 + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 15,130,98,255,255,255 ; jb 277b <_sk_load_f16_hsw+0x21> + DB 197,122,126,76,248,48 ; vmovq 0x30(%rax,%rdi,8),%xmm9 + DB 233,87,255,255,255 ; jmpq 277b <_sk_load_f16_hsw+0x21> + DB 197,225,87,219 ; vxorpd %xmm3,%xmm3,%xmm3 + DB 197,233,87,210 ; vxorpd %xmm2,%xmm2,%xmm2 + DB 233,74,255,255,255 ; jmpq 277b <_sk_load_f16_hsw+0x21> + DB 197,225,87,219 ; vxorpd %xmm3,%xmm3,%xmm3 + DB 233,65,255,255,255 ; jmpq 277b <_sk_load_f16_hsw+0x21> + +PUBLIC _sk_gather_f16_hsw +_sk_gather_f16_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,201 ; vcvttps2dq %ymm1,%ymm1 + DB 196,226,125,88,80,16 ; vpbroadcastd 0x10(%rax),%ymm2 + DB 196,226,109,64,201 ; vpmulld %ymm1,%ymm2,%ymm1 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 197,245,254,192 ; vpaddd %ymm0,%ymm1,%ymm0 + DB 197,245,118,201 ; vpcmpeqd %ymm1,%ymm1,%ymm1 + DB 197,237,118,210 ; vpcmpeqd %ymm2,%ymm2,%ymm2 + DB 196,194,237,144,28,192 ; vpgatherdq %ymm2,(%r8,%xmm0,8),%ymm3 + DB 196,227,125,57,192,1 ; vextracti128 $0x1,%ymm0,%xmm0 + DB 196,194,245,144,20,192 ; vpgatherdq %ymm1,(%r8,%xmm0,8),%ymm2 + DB 196,227,125,57,216,1 ; vextracti128 $0x1,%ymm3,%xmm0 + DB 196,227,125,57,209,1 ; vextracti128 $0x1,%ymm2,%xmm1 + DB 197,97,97,192 ; vpunpcklwd %xmm0,%xmm3,%xmm8 + DB 197,225,105,192 ; vpunpckhwd %xmm0,%xmm3,%xmm0 + DB 197,233,97,217 ; vpunpcklwd %xmm1,%xmm2,%xmm3 + DB 197,233,105,201 ; vpunpckhwd %xmm1,%xmm2,%xmm1 + DB 197,57,97,200 ; vpunpcklwd %xmm0,%xmm8,%xmm9 + DB 197,57,105,192 ; vpunpckhwd %xmm0,%xmm8,%xmm8 + DB 197,225,97,209 ; vpunpcklwd %xmm1,%xmm3,%xmm2 + DB 197,225,105,217 ; vpunpckhwd %xmm1,%xmm3,%xmm3 + DB 197,177,108,194 ; vpunpcklqdq %xmm2,%xmm9,%xmm0 + DB 196,226,125,19,192 ; vcvtph2ps %xmm0,%ymm0 + DB 197,177,109,202 ; vpunpckhqdq %xmm2,%xmm9,%xmm1 + DB 196,226,125,19,201 ; vcvtph2ps %xmm1,%ymm1 + DB 197,185,108,211 ; vpunpcklqdq %xmm3,%xmm8,%xmm2 + DB 196,226,125,19,210 ; vcvtph2ps %xmm2,%ymm2 + DB 197,185,109,219 ; vpunpckhqdq %xmm3,%xmm8,%xmm3 + DB 196,226,125,19,219 ; vcvtph2ps %xmm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_f16_hsw +_sk_store_f16_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 196,195,125,29,192,4 ; vcvtps2ph $0x4,%ymm0,%xmm8 + DB 196,195,125,29,201,4 ; vcvtps2ph $0x4,%ymm1,%xmm9 + DB 196,195,125,29,210,4 ; vcvtps2ph $0x4,%ymm2,%xmm10 + DB 196,195,125,29,219,4 ; vcvtps2ph $0x4,%ymm3,%xmm11 + DB 196,65,57,97,225 ; vpunpcklwd %xmm9,%xmm8,%xmm12 + DB 196,65,57,105,193 ; vpunpckhwd %xmm9,%xmm8,%xmm8 + DB 196,65,41,97,203 ; vpunpcklwd %xmm11,%xmm10,%xmm9 + DB 196,65,41,105,235 ; vpunpckhwd %xmm11,%xmm10,%xmm13 + DB 196,65,25,98,217 ; vpunpckldq %xmm9,%xmm12,%xmm11 + DB 196,65,25,106,209 ; vpunpckhdq %xmm9,%xmm12,%xmm10 + DB 196,65,57,98,205 ; vpunpckldq %xmm13,%xmm8,%xmm9 + DB 196,65,57,106,197 ; vpunpckhdq %xmm13,%xmm8,%xmm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,27 ; jne 2929 <_sk_store_f16_hsw+0x65> + DB 197,120,17,28,248 ; vmovups %xmm11,(%rax,%rdi,8) + DB 197,120,17,84,248,16 ; vmovups %xmm10,0x10(%rax,%rdi,8) + DB 197,120,17,76,248,32 ; vmovups %xmm9,0x20(%rax,%rdi,8) + DB 197,122,127,68,248,48 ; vmovdqu %xmm8,0x30(%rax,%rdi,8) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 197,121,214,28,248 ; vmovq %xmm11,(%rax,%rdi,8) + DB 72,131,249,1 ; cmp $0x1,%rcx + DB 116,241 ; je 2925 <_sk_store_f16_hsw+0x61> + DB 197,121,23,92,248,8 ; vmovhpd %xmm11,0x8(%rax,%rdi,8) + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 114,229 ; jb 2925 <_sk_store_f16_hsw+0x61> + DB 197,121,214,84,248,16 ; vmovq %xmm10,0x10(%rax,%rdi,8) + DB 116,221 ; je 2925 <_sk_store_f16_hsw+0x61> + DB 197,121,23,84,248,24 ; vmovhpd %xmm10,0x18(%rax,%rdi,8) + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 114,209 ; jb 2925 <_sk_store_f16_hsw+0x61> + DB 197,121,214,76,248,32 ; vmovq %xmm9,0x20(%rax,%rdi,8) + DB 116,201 ; je 2925 <_sk_store_f16_hsw+0x61> + DB 197,121,23,76,248,40 ; vmovhpd %xmm9,0x28(%rax,%rdi,8) + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 114,189 ; jb 2925 <_sk_store_f16_hsw+0x61> + DB 197,121,214,68,248,48 ; vmovq %xmm8,0x30(%rax,%rdi,8) + DB 235,181 ; jmp 2925 <_sk_store_f16_hsw+0x61> + +PUBLIC _sk_load_u16_be_hsw +_sk_load_u16_be_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,201,0,0,0 ; jne 2a47 <_sk_load_u16_be_hsw+0xd7> + DB 197,121,16,4,248 ; vmovupd (%rax,%rdi,8),%xmm8 + DB 197,249,16,84,248,16 ; vmovupd 0x10(%rax,%rdi,8),%xmm2 + DB 197,249,16,92,248,32 ; vmovupd 0x20(%rax,%rdi,8),%xmm3 + DB 197,122,111,76,248,48 ; vmovdqu 0x30(%rax,%rdi,8),%xmm9 + DB 197,185,97,194 ; vpunpcklwd %xmm2,%xmm8,%xmm0 + DB 197,185,105,210 ; vpunpckhwd %xmm2,%xmm8,%xmm2 + DB 196,193,97,97,201 ; vpunpcklwd %xmm9,%xmm3,%xmm1 + DB 196,193,97,105,217 ; vpunpckhwd %xmm9,%xmm3,%xmm3 + DB 197,121,97,194 ; vpunpcklwd %xmm2,%xmm0,%xmm8 + DB 197,121,105,202 ; vpunpckhwd %xmm2,%xmm0,%xmm9 + DB 197,241,97,211 ; vpunpcklwd %xmm3,%xmm1,%xmm2 + DB 197,113,105,219 ; vpunpckhwd %xmm3,%xmm1,%xmm11 + DB 184,128,0,128,55 ; mov $0x37800080,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,98,125,88,208 ; vpbroadcastd %xmm0,%ymm10 + DB 197,185,108,194 ; vpunpcklqdq %xmm2,%xmm8,%xmm0 + DB 197,241,113,240,8 ; vpsllw $0x8,%xmm0,%xmm1 + DB 197,249,113,208,8 ; vpsrlw $0x8,%xmm0,%xmm0 + DB 197,241,235,192 ; vpor %xmm0,%xmm1,%xmm0 + DB 196,226,125,51,192 ; vpmovzxwd %xmm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 197,172,89,192 ; vmulps %ymm0,%ymm10,%ymm0 + DB 197,185,109,202 ; vpunpckhqdq %xmm2,%xmm8,%xmm1 + DB 197,233,113,241,8 ; vpsllw $0x8,%xmm1,%xmm2 + DB 197,241,113,209,8 ; vpsrlw $0x8,%xmm1,%xmm1 + DB 197,233,235,201 ; vpor %xmm1,%xmm2,%xmm1 + DB 196,226,125,51,201 ; vpmovzxwd %xmm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 197,172,89,201 ; vmulps %ymm1,%ymm10,%ymm1 + DB 196,193,49,108,211 ; vpunpcklqdq %xmm11,%xmm9,%xmm2 + DB 197,225,113,242,8 ; vpsllw $0x8,%xmm2,%xmm3 + DB 197,233,113,210,8 ; vpsrlw $0x8,%xmm2,%xmm2 + DB 197,225,235,210 ; vpor %xmm2,%xmm3,%xmm2 + DB 196,226,125,51,210 ; vpmovzxwd %xmm2,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 197,172,89,210 ; vmulps %ymm2,%ymm10,%ymm2 + DB 196,193,49,109,219 ; vpunpckhqdq %xmm11,%xmm9,%xmm3 + DB 197,185,113,243,8 ; vpsllw $0x8,%xmm3,%xmm8 + DB 197,225,113,211,8 ; vpsrlw $0x8,%xmm3,%xmm3 + DB 197,185,235,219 ; vpor %xmm3,%xmm8,%xmm3 + DB 196,226,125,51,219 ; vpmovzxwd %xmm3,%ymm3 + DB 197,252,91,219 ; vcvtdq2ps %ymm3,%ymm3 + DB 197,172,89,219 ; vmulps %ymm3,%ymm10,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 197,123,16,4,248 ; vmovsd (%rax,%rdi,8),%xmm8 + DB 196,65,49,239,201 ; vpxor %xmm9,%xmm9,%xmm9 + DB 72,131,249,1 ; cmp $0x1,%rcx + DB 116,79 ; je 2aa6 <_sk_load_u16_be_hsw+0x136> + DB 197,57,22,68,248,8 ; vmovhpd 0x8(%rax,%rdi,8),%xmm8,%xmm8 + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 114,67 ; jb 2aa6 <_sk_load_u16_be_hsw+0x136> + DB 197,251,16,84,248,16 ; vmovsd 0x10(%rax,%rdi,8),%xmm2 + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 116,68 ; je 2ab3 <_sk_load_u16_be_hsw+0x143> + DB 197,233,22,84,248,24 ; vmovhpd 0x18(%rax,%rdi,8),%xmm2,%xmm2 + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 114,56 ; jb 2ab3 <_sk_load_u16_be_hsw+0x143> + DB 197,251,16,92,248,32 ; vmovsd 0x20(%rax,%rdi,8),%xmm3 + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 15,132,10,255,255,255 ; je 2995 <_sk_load_u16_be_hsw+0x25> + DB 197,225,22,92,248,40 ; vmovhpd 0x28(%rax,%rdi,8),%xmm3,%xmm3 + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 15,130,250,254,255,255 ; jb 2995 <_sk_load_u16_be_hsw+0x25> + DB 197,122,126,76,248,48 ; vmovq 0x30(%rax,%rdi,8),%xmm9 + DB 233,239,254,255,255 ; jmpq 2995 <_sk_load_u16_be_hsw+0x25> + DB 197,225,87,219 ; vxorpd %xmm3,%xmm3,%xmm3 + DB 197,233,87,210 ; vxorpd %xmm2,%xmm2,%xmm2 + DB 233,226,254,255,255 ; jmpq 2995 <_sk_load_u16_be_hsw+0x25> + DB 197,225,87,219 ; vxorpd %xmm3,%xmm3,%xmm3 + DB 233,217,254,255,255 ; jmpq 2995 <_sk_load_u16_be_hsw+0x25> + +PUBLIC _sk_store_u16_be_hsw +_sk_store_u16_be_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 184,0,255,127,71 ; mov $0x477fff00,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 196,65,125,91,201 ; vcvtps2dq %ymm9,%ymm9 + DB 196,67,125,25,202,1 ; vextractf128 $0x1,%ymm9,%xmm10 + DB 196,66,49,43,202 ; vpackusdw %xmm10,%xmm9,%xmm9 + DB 196,193,41,113,241,8 ; vpsllw $0x8,%xmm9,%xmm10 + DB 196,193,49,113,209,8 ; vpsrlw $0x8,%xmm9,%xmm9 + DB 196,65,41,235,201 ; vpor %xmm9,%xmm10,%xmm9 + DB 197,60,89,209 ; vmulps %ymm1,%ymm8,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,67,125,25,211,1 ; vextractf128 $0x1,%ymm10,%xmm11 + DB 196,66,41,43,211 ; vpackusdw %xmm11,%xmm10,%xmm10 + DB 196,193,33,113,242,8 ; vpsllw $0x8,%xmm10,%xmm11 + DB 196,193,41,113,210,8 ; vpsrlw $0x8,%xmm10,%xmm10 + DB 196,65,33,235,210 ; vpor %xmm10,%xmm11,%xmm10 + DB 197,60,89,218 ; vmulps %ymm2,%ymm8,%ymm11 + DB 196,65,125,91,219 ; vcvtps2dq %ymm11,%ymm11 + DB 196,67,125,25,220,1 ; vextractf128 $0x1,%ymm11,%xmm12 + DB 196,66,33,43,220 ; vpackusdw %xmm12,%xmm11,%xmm11 + DB 196,193,25,113,243,8 ; vpsllw $0x8,%xmm11,%xmm12 + DB 196,193,33,113,211,8 ; vpsrlw $0x8,%xmm11,%xmm11 + DB 196,65,25,235,219 ; vpor %xmm11,%xmm12,%xmm11 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 196,65,125,91,192 ; vcvtps2dq %ymm8,%ymm8 + DB 196,67,125,25,196,1 ; vextractf128 $0x1,%ymm8,%xmm12 + DB 196,66,57,43,196 ; vpackusdw %xmm12,%xmm8,%xmm8 + DB 196,193,25,113,240,8 ; vpsllw $0x8,%xmm8,%xmm12 + DB 196,193,57,113,208,8 ; vpsrlw $0x8,%xmm8,%xmm8 + DB 196,65,25,235,192 ; vpor %xmm8,%xmm12,%xmm8 + DB 196,65,49,97,226 ; vpunpcklwd %xmm10,%xmm9,%xmm12 + DB 196,65,49,105,234 ; vpunpckhwd %xmm10,%xmm9,%xmm13 + DB 196,65,33,97,200 ; vpunpcklwd %xmm8,%xmm11,%xmm9 + DB 196,65,33,105,192 ; vpunpckhwd %xmm8,%xmm11,%xmm8 + DB 196,65,25,98,217 ; vpunpckldq %xmm9,%xmm12,%xmm11 + DB 196,65,25,106,209 ; vpunpckhdq %xmm9,%xmm12,%xmm10 + DB 196,65,17,98,200 ; vpunpckldq %xmm8,%xmm13,%xmm9 + DB 196,65,17,106,192 ; vpunpckhdq %xmm8,%xmm13,%xmm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,31 ; jne 2baf <_sk_store_u16_be_hsw+0xf3> + DB 196,65,120,17,28,248 ; vmovups %xmm11,(%r8,%rdi,8) + DB 196,65,120,17,84,248,16 ; vmovups %xmm10,0x10(%r8,%rdi,8) + DB 196,65,120,17,76,248,32 ; vmovups %xmm9,0x20(%r8,%rdi,8) + DB 196,65,122,127,68,248,48 ; vmovdqu %xmm8,0x30(%r8,%rdi,8) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 196,65,121,214,28,248 ; vmovq %xmm11,(%r8,%rdi,8) + DB 72,131,249,1 ; cmp $0x1,%rcx + DB 116,240 ; je 2bab <_sk_store_u16_be_hsw+0xef> + DB 196,65,121,23,92,248,8 ; vmovhpd %xmm11,0x8(%r8,%rdi,8) + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 114,227 ; jb 2bab <_sk_store_u16_be_hsw+0xef> + DB 196,65,121,214,84,248,16 ; vmovq %xmm10,0x10(%r8,%rdi,8) + DB 116,218 ; je 2bab <_sk_store_u16_be_hsw+0xef> + DB 196,65,121,23,84,248,24 ; vmovhpd %xmm10,0x18(%r8,%rdi,8) + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 114,205 ; jb 2bab <_sk_store_u16_be_hsw+0xef> + DB 196,65,121,214,76,248,32 ; vmovq %xmm9,0x20(%r8,%rdi,8) + DB 116,196 ; je 2bab <_sk_store_u16_be_hsw+0xef> + DB 196,65,121,23,76,248,40 ; vmovhpd %xmm9,0x28(%r8,%rdi,8) + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 114,183 ; jb 2bab <_sk_store_u16_be_hsw+0xef> + DB 196,65,121,214,68,248,48 ; vmovq %xmm8,0x30(%r8,%rdi,8) + DB 235,174 ; jmp 2bab <_sk_store_u16_be_hsw+0xef> + +PUBLIC _sk_load_f32_hsw +_sk_load_f32_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 119,110 ; ja 2c73 <_sk_load_f32_hsw+0x76> + DB 76,139,0 ; mov (%rax),%r8 + DB 76,141,12,189,0,0,0,0 ; lea 0x0(,%rdi,4),%r9 + DB 76,141,21,133,0,0,0 ; lea 0x85(%rip),%r10 # 2c9c <_sk_load_f32_hsw+0x9f> + DB 73,99,4,138 ; movslq (%r10,%rcx,4),%rax + DB 76,1,208 ; add %r10,%rax + DB 255,224 ; jmpq *%rax + DB 196,3,125,24,68,136,112,1 ; vinsertf128 $0x1,0x70(%r8,%r9,4),%ymm0,%ymm8 + DB 196,131,125,24,92,136,96,1 ; vinsertf128 $0x1,0x60(%r8,%r9,4),%ymm0,%ymm3 + DB 196,131,125,24,76,136,80,1 ; vinsertf128 $0x1,0x50(%r8,%r9,4),%ymm0,%ymm1 + DB 196,131,125,24,84,136,64,1 ; vinsertf128 $0x1,0x40(%r8,%r9,4),%ymm0,%ymm2 + DB 196,129,121,16,68,136,48 ; vmovupd 0x30(%r8,%r9,4),%xmm0 + DB 196,195,125,13,192,12 ; vblendpd $0xc,%ymm8,%ymm0,%ymm0 + DB 196,1,121,16,68,136,32 ; vmovupd 0x20(%r8,%r9,4),%xmm8 + DB 196,99,61,13,203,12 ; vblendpd $0xc,%ymm3,%ymm8,%ymm9 + DB 196,129,121,16,92,136,16 ; vmovupd 0x10(%r8,%r9,4),%xmm3 + DB 196,99,101,13,209,12 ; vblendpd $0xc,%ymm1,%ymm3,%ymm10 + DB 196,129,121,16,12,136 ; vmovupd (%r8,%r9,4),%xmm1 + DB 196,227,117,13,202,12 ; vblendpd $0xc,%ymm2,%ymm1,%ymm1 + DB 196,193,116,20,210 ; vunpcklps %ymm10,%ymm1,%ymm2 + DB 196,193,116,21,218 ; vunpckhps %ymm10,%ymm1,%ymm3 + DB 197,180,20,200 ; vunpcklps %ymm0,%ymm9,%ymm1 + DB 197,52,21,192 ; vunpckhps %ymm0,%ymm9,%ymm8 + DB 197,237,20,193 ; vunpcklpd %ymm1,%ymm2,%ymm0 + DB 197,237,21,201 ; vunpckhpd %ymm1,%ymm2,%ymm1 + DB 196,193,101,20,208 ; vunpcklpd %ymm8,%ymm3,%ymm2 + DB 196,193,101,21,216 ; vunpckhpd %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 144 ; nop + DB 132,255 ; test %bh,%bh + DB 255 ; (bad) + DB 255,203 ; dec %ebx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 190,255,255,255,177 ; mov $0xb1ffffff,%esi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,164,255,255,255,156,255 ; jmpq *-0x630001(%rdi,%rdi,8) + DB 255 ; (bad) + DB 255,148,255,255,255,140,255 ; callq *-0x730001(%rdi,%rdi,8) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_store_f32_hsw +_sk_store_f32_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 72,141,4,189,0,0,0,0 ; lea 0x0(,%rdi,4),%rax + DB 197,124,20,193 ; vunpcklps %ymm1,%ymm0,%ymm8 + DB 197,124,21,217 ; vunpckhps %ymm1,%ymm0,%ymm11 + DB 197,108,20,203 ; vunpcklps %ymm3,%ymm2,%ymm9 + DB 197,108,21,227 ; vunpckhps %ymm3,%ymm2,%ymm12 + DB 196,65,61,20,209 ; vunpcklpd %ymm9,%ymm8,%ymm10 + DB 196,65,61,21,201 ; vunpckhpd %ymm9,%ymm8,%ymm9 + DB 196,65,37,20,196 ; vunpcklpd %ymm12,%ymm11,%ymm8 + DB 196,65,37,21,220 ; vunpckhpd %ymm12,%ymm11,%ymm11 + DB 72,133,201 ; test %rcx,%rcx + DB 117,55 ; jne 2d29 <_sk_store_f32_hsw+0x6d> + DB 196,67,45,24,225,1 ; vinsertf128 $0x1,%xmm9,%ymm10,%ymm12 + DB 196,67,61,24,235,1 ; vinsertf128 $0x1,%xmm11,%ymm8,%ymm13 + DB 196,67,45,6,201,49 ; vperm2f128 $0x31,%ymm9,%ymm10,%ymm9 + DB 196,67,61,6,195,49 ; vperm2f128 $0x31,%ymm11,%ymm8,%ymm8 + DB 196,65,125,17,36,128 ; vmovupd %ymm12,(%r8,%rax,4) + DB 196,65,125,17,108,128,32 ; vmovupd %ymm13,0x20(%r8,%rax,4) + DB 196,65,125,17,76,128,64 ; vmovupd %ymm9,0x40(%r8,%rax,4) + DB 196,65,125,17,68,128,96 ; vmovupd %ymm8,0x60(%r8,%rax,4) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 196,65,121,17,20,128 ; vmovupd %xmm10,(%r8,%rax,4) + DB 72,131,249,1 ; cmp $0x1,%rcx + DB 116,240 ; je 2d25 <_sk_store_f32_hsw+0x69> + DB 196,65,121,17,76,128,16 ; vmovupd %xmm9,0x10(%r8,%rax,4) + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 114,227 ; jb 2d25 <_sk_store_f32_hsw+0x69> + DB 196,65,121,17,68,128,32 ; vmovupd %xmm8,0x20(%r8,%rax,4) + DB 116,218 ; je 2d25 <_sk_store_f32_hsw+0x69> + DB 196,65,121,17,92,128,48 ; vmovupd %xmm11,0x30(%r8,%rax,4) + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 114,205 ; jb 2d25 <_sk_store_f32_hsw+0x69> + DB 196,67,125,25,84,128,64,1 ; vextractf128 $0x1,%ymm10,0x40(%r8,%rax,4) + DB 116,195 ; je 2d25 <_sk_store_f32_hsw+0x69> + DB 196,67,125,25,76,128,80,1 ; vextractf128 $0x1,%ymm9,0x50(%r8,%rax,4) + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 114,181 ; jb 2d25 <_sk_store_f32_hsw+0x69> + DB 196,67,125,25,68,128,96,1 ; vextractf128 $0x1,%ymm8,0x60(%r8,%rax,4) + DB 235,171 ; jmp 2d25 <_sk_store_f32_hsw+0x69> + +PUBLIC _sk_clamp_x_hsw +_sk_clamp_x_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 197,188,95,192 ; vmaxps %ymm0,%ymm8,%ymm0 + DB 196,98,125,88,0 ; vpbroadcastd (%rax),%ymm8 + DB 196,65,53,118,201 ; vpcmpeqd %ymm9,%ymm9,%ymm9 + DB 196,65,61,254,193 ; vpaddd %ymm9,%ymm8,%ymm8 + DB 196,193,124,93,192 ; vminps %ymm8,%ymm0,%ymm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_y_hsw +_sk_clamp_y_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 197,188,95,201 ; vmaxps %ymm1,%ymm8,%ymm1 + DB 196,98,125,88,0 ; vpbroadcastd (%rax),%ymm8 + DB 196,65,53,118,201 ; vpcmpeqd %ymm9,%ymm9,%ymm9 + DB 196,65,61,254,193 ; vpaddd %ymm9,%ymm8,%ymm8 + DB 196,193,116,93,200 ; vminps %ymm8,%ymm1,%ymm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_repeat_x_hsw +_sk_repeat_x_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,65,124,94,200 ; vdivps %ymm8,%ymm0,%ymm9 + DB 196,67,125,8,201,1 ; vroundps $0x1,%ymm9,%ymm9 + DB 196,98,61,172,200 ; vfnmadd213ps %ymm0,%ymm8,%ymm9 + DB 197,253,118,192 ; vpcmpeqd %ymm0,%ymm0,%ymm0 + DB 197,189,254,192 ; vpaddd %ymm0,%ymm8,%ymm0 + DB 197,180,93,192 ; vminps %ymm0,%ymm9,%ymm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_repeat_y_hsw +_sk_repeat_y_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,65,116,94,200 ; vdivps %ymm8,%ymm1,%ymm9 + DB 196,67,125,8,201,1 ; vroundps $0x1,%ymm9,%ymm9 + DB 196,98,61,172,201 ; vfnmadd213ps %ymm1,%ymm8,%ymm9 + DB 197,245,118,201 ; vpcmpeqd %ymm1,%ymm1,%ymm1 + DB 197,189,254,201 ; vpaddd %ymm1,%ymm8,%ymm1 + DB 197,180,93,201 ; vminps %ymm1,%ymm9,%ymm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_mirror_x_hsw +_sk_mirror_x_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,122,16,0 ; vmovss (%rax),%xmm8 + DB 196,66,125,24,200 ; vbroadcastss %xmm8,%ymm9 + DB 196,65,124,92,209 ; vsubps %ymm9,%ymm0,%ymm10 + DB 196,193,58,88,192 ; vaddss %xmm8,%xmm8,%xmm0 + DB 196,226,125,24,192 ; vbroadcastss %xmm0,%ymm0 + DB 197,44,94,192 ; vdivps %ymm0,%ymm10,%ymm8 + DB 196,67,125,8,192,1 ; vroundps $0x1,%ymm8,%ymm8 + DB 196,66,125,172,194 ; vfnmadd213ps %ymm10,%ymm0,%ymm8 + DB 196,193,60,92,193 ; vsubps %ymm9,%ymm8,%ymm0 + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 197,60,92,192 ; vsubps %ymm0,%ymm8,%ymm8 + DB 197,188,84,192 ; vandps %ymm0,%ymm8,%ymm0 + DB 196,65,61,118,192 ; vpcmpeqd %ymm8,%ymm8,%ymm8 + DB 196,65,53,254,192 ; vpaddd %ymm8,%ymm9,%ymm8 + DB 196,193,124,93,192 ; vminps %ymm8,%ymm0,%ymm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_mirror_y_hsw +_sk_mirror_y_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,122,16,0 ; vmovss (%rax),%xmm8 + DB 196,66,125,24,200 ; vbroadcastss %xmm8,%ymm9 + DB 196,65,116,92,209 ; vsubps %ymm9,%ymm1,%ymm10 + DB 196,193,58,88,200 ; vaddss %xmm8,%xmm8,%xmm1 + DB 196,226,125,24,201 ; vbroadcastss %xmm1,%ymm1 + DB 197,44,94,193 ; vdivps %ymm1,%ymm10,%ymm8 + DB 196,67,125,8,192,1 ; vroundps $0x1,%ymm8,%ymm8 + DB 196,66,117,172,194 ; vfnmadd213ps %ymm10,%ymm1,%ymm8 + DB 196,193,60,92,201 ; vsubps %ymm9,%ymm8,%ymm1 + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 197,60,92,193 ; vsubps %ymm1,%ymm8,%ymm8 + DB 197,188,84,201 ; vandps %ymm1,%ymm8,%ymm1 + DB 196,65,61,118,192 ; vpcmpeqd %ymm8,%ymm8,%ymm8 + DB 196,65,53,254,192 ; vpaddd %ymm8,%ymm9,%ymm8 + DB 196,193,116,93,200 ; vminps %ymm8,%ymm1,%ymm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_luminance_to_alpha_hsw +_sk_luminance_to_alpha_hsw LABEL PROC + DB 184,208,179,89,62 ; mov $0x3e59b3d0,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,98,125,88,195 ; vpbroadcastd %xmm3,%ymm8 + DB 184,89,23,55,63 ; mov $0x3f371759,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,226,125,88,219 ; vpbroadcastd %xmm3,%ymm3 + DB 197,228,89,201 ; vmulps %ymm1,%ymm3,%ymm1 + DB 196,98,125,168,193 ; vfmadd213ps %ymm1,%ymm0,%ymm8 + DB 184,152,221,147,61 ; mov $0x3d93dd98,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,226,125,88,216 ; vpbroadcastd %xmm0,%ymm3 + DB 196,194,109,168,216 ; vfmadd213ps %ymm8,%ymm2,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,253,239,192 ; vpxor %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_2x3_hsw +_sk_matrix_2x3_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,8 ; vbroadcastss (%rax),%ymm9 + DB 196,98,125,24,80,8 ; vbroadcastss 0x8(%rax),%ymm10 + DB 196,98,125,24,64,16 ; vbroadcastss 0x10(%rax),%ymm8 + DB 196,66,117,184,194 ; vfmadd231ps %ymm10,%ymm1,%ymm8 + DB 196,66,125,184,193 ; vfmadd231ps %ymm9,%ymm0,%ymm8 + DB 196,98,125,24,80,4 ; vbroadcastss 0x4(%rax),%ymm10 + DB 196,98,125,24,88,12 ; vbroadcastss 0xc(%rax),%ymm11 + DB 196,98,125,24,72,20 ; vbroadcastss 0x14(%rax),%ymm9 + DB 196,66,117,184,203 ; vfmadd231ps %ymm11,%ymm1,%ymm9 + DB 196,66,125,184,202 ; vfmadd231ps %ymm10,%ymm0,%ymm9 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,192 ; vmovaps %ymm8,%ymm0 + DB 197,124,41,201 ; vmovaps %ymm9,%ymm1 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_3x4_hsw +_sk_matrix_3x4_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,8 ; vbroadcastss (%rax),%ymm9 + DB 196,98,125,24,80,12 ; vbroadcastss 0xc(%rax),%ymm10 + DB 196,98,125,24,88,24 ; vbroadcastss 0x18(%rax),%ymm11 + DB 196,98,125,24,64,36 ; vbroadcastss 0x24(%rax),%ymm8 + DB 196,66,109,184,195 ; vfmadd231ps %ymm11,%ymm2,%ymm8 + DB 196,66,117,184,194 ; vfmadd231ps %ymm10,%ymm1,%ymm8 + DB 196,66,125,184,193 ; vfmadd231ps %ymm9,%ymm0,%ymm8 + DB 196,98,125,24,80,4 ; vbroadcastss 0x4(%rax),%ymm10 + DB 196,98,125,24,88,16 ; vbroadcastss 0x10(%rax),%ymm11 + DB 196,98,125,24,96,28 ; vbroadcastss 0x1c(%rax),%ymm12 + DB 196,98,125,24,72,40 ; vbroadcastss 0x28(%rax),%ymm9 + DB 196,66,109,184,204 ; vfmadd231ps %ymm12,%ymm2,%ymm9 + DB 196,66,117,184,203 ; vfmadd231ps %ymm11,%ymm1,%ymm9 + DB 196,66,125,184,202 ; vfmadd231ps %ymm10,%ymm0,%ymm9 + DB 196,98,125,24,88,8 ; vbroadcastss 0x8(%rax),%ymm11 + DB 196,98,125,24,96,20 ; vbroadcastss 0x14(%rax),%ymm12 + DB 196,98,125,24,104,32 ; vbroadcastss 0x20(%rax),%ymm13 + DB 196,98,125,24,80,44 ; vbroadcastss 0x2c(%rax),%ymm10 + DB 196,66,109,184,213 ; vfmadd231ps %ymm13,%ymm2,%ymm10 + DB 196,66,117,184,212 ; vfmadd231ps %ymm12,%ymm1,%ymm10 + DB 196,66,125,184,211 ; vfmadd231ps %ymm11,%ymm0,%ymm10 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,192 ; vmovaps %ymm8,%ymm0 + DB 197,124,41,201 ; vmovaps %ymm9,%ymm1 + DB 197,124,41,210 ; vmovaps %ymm10,%ymm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_4x5_hsw +_sk_matrix_4x5_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,8 ; vbroadcastss (%rax),%ymm9 + DB 196,98,125,24,80,16 ; vbroadcastss 0x10(%rax),%ymm10 + DB 196,98,125,24,88,32 ; vbroadcastss 0x20(%rax),%ymm11 + DB 196,98,125,24,96,48 ; vbroadcastss 0x30(%rax),%ymm12 + DB 196,98,125,24,64,64 ; vbroadcastss 0x40(%rax),%ymm8 + DB 196,66,101,184,196 ; vfmadd231ps %ymm12,%ymm3,%ymm8 + DB 196,66,109,184,195 ; vfmadd231ps %ymm11,%ymm2,%ymm8 + DB 196,66,117,184,194 ; vfmadd231ps %ymm10,%ymm1,%ymm8 + DB 196,66,125,184,193 ; vfmadd231ps %ymm9,%ymm0,%ymm8 + DB 196,98,125,24,80,4 ; vbroadcastss 0x4(%rax),%ymm10 + DB 196,98,125,24,88,20 ; vbroadcastss 0x14(%rax),%ymm11 + DB 196,98,125,24,96,36 ; vbroadcastss 0x24(%rax),%ymm12 + DB 196,98,125,24,104,52 ; vbroadcastss 0x34(%rax),%ymm13 + DB 196,98,125,24,72,68 ; vbroadcastss 0x44(%rax),%ymm9 + DB 196,66,101,184,205 ; vfmadd231ps %ymm13,%ymm3,%ymm9 + DB 196,66,109,184,204 ; vfmadd231ps %ymm12,%ymm2,%ymm9 + DB 196,66,117,184,203 ; vfmadd231ps %ymm11,%ymm1,%ymm9 + DB 196,66,125,184,202 ; vfmadd231ps %ymm10,%ymm0,%ymm9 + DB 196,98,125,24,88,8 ; vbroadcastss 0x8(%rax),%ymm11 + DB 196,98,125,24,96,24 ; vbroadcastss 0x18(%rax),%ymm12 + DB 196,98,125,24,104,40 ; vbroadcastss 0x28(%rax),%ymm13 + DB 196,98,125,24,112,56 ; vbroadcastss 0x38(%rax),%ymm14 + DB 196,98,125,24,80,72 ; vbroadcastss 0x48(%rax),%ymm10 + DB 196,66,101,184,214 ; vfmadd231ps %ymm14,%ymm3,%ymm10 + DB 196,66,109,184,213 ; vfmadd231ps %ymm13,%ymm2,%ymm10 + DB 196,66,117,184,212 ; vfmadd231ps %ymm12,%ymm1,%ymm10 + DB 196,66,125,184,211 ; vfmadd231ps %ymm11,%ymm0,%ymm10 + DB 196,98,125,24,96,12 ; vbroadcastss 0xc(%rax),%ymm12 + DB 196,98,125,24,104,28 ; vbroadcastss 0x1c(%rax),%ymm13 + DB 196,98,125,24,112,44 ; vbroadcastss 0x2c(%rax),%ymm14 + DB 196,98,125,24,120,60 ; vbroadcastss 0x3c(%rax),%ymm15 + DB 196,98,125,24,88,76 ; vbroadcastss 0x4c(%rax),%ymm11 + DB 196,66,101,184,223 ; vfmadd231ps %ymm15,%ymm3,%ymm11 + DB 196,66,109,184,222 ; vfmadd231ps %ymm14,%ymm2,%ymm11 + DB 196,66,117,184,221 ; vfmadd231ps %ymm13,%ymm1,%ymm11 + DB 196,66,125,184,220 ; vfmadd231ps %ymm12,%ymm0,%ymm11 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,192 ; vmovaps %ymm8,%ymm0 + DB 197,124,41,201 ; vmovaps %ymm9,%ymm1 + DB 197,124,41,210 ; vmovaps %ymm10,%ymm2 + DB 197,124,41,219 ; vmovaps %ymm11,%ymm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_perspective_hsw +_sk_matrix_perspective_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,98,125,24,72,4 ; vbroadcastss 0x4(%rax),%ymm9 + DB 196,98,125,24,80,8 ; vbroadcastss 0x8(%rax),%ymm10 + DB 196,66,117,184,209 ; vfmadd231ps %ymm9,%ymm1,%ymm10 + DB 196,66,125,184,208 ; vfmadd231ps %ymm8,%ymm0,%ymm10 + DB 196,98,125,24,64,12 ; vbroadcastss 0xc(%rax),%ymm8 + DB 196,98,125,24,72,16 ; vbroadcastss 0x10(%rax),%ymm9 + DB 196,98,125,24,88,20 ; vbroadcastss 0x14(%rax),%ymm11 + DB 196,66,117,184,217 ; vfmadd231ps %ymm9,%ymm1,%ymm11 + DB 196,66,125,184,216 ; vfmadd231ps %ymm8,%ymm0,%ymm11 + DB 196,98,125,24,64,24 ; vbroadcastss 0x18(%rax),%ymm8 + DB 196,98,125,24,72,28 ; vbroadcastss 0x1c(%rax),%ymm9 + DB 196,98,125,24,96,32 ; vbroadcastss 0x20(%rax),%ymm12 + DB 196,66,117,184,225 ; vfmadd231ps %ymm9,%ymm1,%ymm12 + DB 196,66,125,184,224 ; vfmadd231ps %ymm8,%ymm0,%ymm12 + DB 196,193,124,83,204 ; vrcpps %ymm12,%ymm1 + DB 197,172,89,193 ; vmulps %ymm1,%ymm10,%ymm0 + DB 197,164,89,201 ; vmulps %ymm1,%ymm11,%ymm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_linear_gradient_hsw +_sk_linear_gradient_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,64,16 ; vbroadcastss 0x10(%rax),%ymm8 + DB 196,98,125,24,88,20 ; vbroadcastss 0x14(%rax),%ymm11 + DB 196,98,125,24,80,24 ; vbroadcastss 0x18(%rax),%ymm10 + DB 196,98,125,24,72,28 ; vbroadcastss 0x1c(%rax),%ymm9 + DB 76,139,0 ; mov (%rax),%r8 + DB 77,133,192 ; test %r8,%r8 + DB 15,132,143,0,0,0 ; je 31b5 <_sk_linear_gradient_hsw+0xb5> + DB 72,139,64,8 ; mov 0x8(%rax),%rax + DB 72,131,192,32 ; add $0x20,%rax + DB 196,65,28,87,228 ; vxorps %ymm12,%ymm12,%ymm12 + DB 197,228,87,219 ; vxorps %ymm3,%ymm3,%ymm3 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 196,98,125,24,104,224 ; vbroadcastss -0x20(%rax),%ymm13 + DB 196,65,124,194,237,1 ; vcmpltps %ymm13,%ymm0,%ymm13 + DB 196,98,125,24,112,228 ; vbroadcastss -0x1c(%rax),%ymm14 + DB 196,67,13,74,228,208 ; vblendvps %ymm13,%ymm12,%ymm14,%ymm12 + DB 196,98,125,24,112,232 ; vbroadcastss -0x18(%rax),%ymm14 + DB 196,227,13,74,201,208 ; vblendvps %ymm13,%ymm1,%ymm14,%ymm1 + DB 196,98,125,24,112,236 ; vbroadcastss -0x14(%rax),%ymm14 + DB 196,227,13,74,210,208 ; vblendvps %ymm13,%ymm2,%ymm14,%ymm2 + DB 196,98,125,24,112,240 ; vbroadcastss -0x10(%rax),%ymm14 + DB 196,227,13,74,219,208 ; vblendvps %ymm13,%ymm3,%ymm14,%ymm3 + DB 196,98,125,24,112,244 ; vbroadcastss -0xc(%rax),%ymm14 + DB 196,67,13,74,192,208 ; vblendvps %ymm13,%ymm8,%ymm14,%ymm8 + DB 196,98,125,24,112,248 ; vbroadcastss -0x8(%rax),%ymm14 + DB 196,67,13,74,219,208 ; vblendvps %ymm13,%ymm11,%ymm14,%ymm11 + DB 196,98,125,24,112,252 ; vbroadcastss -0x4(%rax),%ymm14 + DB 196,67,13,74,210,208 ; vblendvps %ymm13,%ymm10,%ymm14,%ymm10 + DB 196,98,125,24,48 ; vbroadcastss (%rax),%ymm14 + DB 196,67,13,74,201,208 ; vblendvps %ymm13,%ymm9,%ymm14,%ymm9 + DB 72,131,192,36 ; add $0x24,%rax + DB 73,255,200 ; dec %r8 + DB 117,140 ; jne 313f <_sk_linear_gradient_hsw+0x3f> + DB 235,17 ; jmp 31c6 <_sk_linear_gradient_hsw+0xc6> + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 197,228,87,219 ; vxorps %ymm3,%ymm3,%ymm3 + DB 196,65,28,87,228 ; vxorps %ymm12,%ymm12,%ymm12 + DB 196,66,125,184,196 ; vfmadd231ps %ymm12,%ymm0,%ymm8 + DB 196,194,125,168,203 ; vfmadd213ps %ymm11,%ymm0,%ymm1 + DB 196,194,125,168,210 ; vfmadd213ps %ymm10,%ymm0,%ymm2 + DB 196,194,125,168,217 ; vfmadd213ps %ymm9,%ymm0,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,192 ; vmovaps %ymm8,%ymm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_linear_gradient_2stops_hsw +_sk_linear_gradient_2stops_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,226,125,24,8 ; vbroadcastss (%rax),%ymm1 + DB 196,98,125,24,64,16 ; vbroadcastss 0x10(%rax),%ymm8 + DB 196,98,125,184,193 ; vfmadd231ps %ymm1,%ymm0,%ymm8 + DB 196,226,125,24,80,4 ; vbroadcastss 0x4(%rax),%ymm2 + DB 196,226,125,24,72,20 ; vbroadcastss 0x14(%rax),%ymm1 + DB 196,226,125,184,202 ; vfmadd231ps %ymm2,%ymm0,%ymm1 + DB 196,226,125,24,88,8 ; vbroadcastss 0x8(%rax),%ymm3 + DB 196,226,125,24,80,24 ; vbroadcastss 0x18(%rax),%ymm2 + DB 196,226,125,184,211 ; vfmadd231ps %ymm3,%ymm0,%ymm2 + DB 196,98,125,24,72,12 ; vbroadcastss 0xc(%rax),%ymm9 + DB 196,226,125,24,88,28 ; vbroadcastss 0x1c(%rax),%ymm3 + DB 196,194,125,184,217 ; vfmadd231ps %ymm9,%ymm0,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,192 ; vmovaps %ymm8,%ymm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_save_xy_hsw +_sk_save_xy_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,88,200 ; vaddps %ymm0,%ymm8,%ymm9 + DB 196,67,125,8,209,1 ; vroundps $0x1,%ymm9,%ymm10 + DB 196,65,52,92,202 ; vsubps %ymm10,%ymm9,%ymm9 + DB 197,60,88,193 ; vaddps %ymm1,%ymm8,%ymm8 + DB 196,67,125,8,208,1 ; vroundps $0x1,%ymm8,%ymm10 + DB 196,65,60,92,194 ; vsubps %ymm10,%ymm8,%ymm8 + DB 197,252,17,0 ; vmovups %ymm0,(%rax) + DB 197,252,17,72,32 ; vmovups %ymm1,0x20(%rax) + DB 197,124,17,72,64 ; vmovups %ymm9,0x40(%rax) + DB 197,124,17,64,96 ; vmovups %ymm8,0x60(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_accumulate_hsw +_sk_accumulate_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,16,128,128,0,0,0 ; vmovups 0x80(%rax),%ymm8 + DB 197,60,89,128,160,0,0,0 ; vmulps 0xa0(%rax),%ymm8,%ymm8 + DB 196,226,61,184,224 ; vfmadd231ps %ymm0,%ymm8,%ymm4 + DB 196,226,61,184,233 ; vfmadd231ps %ymm1,%ymm8,%ymm5 + DB 196,226,61,184,242 ; vfmadd231ps %ymm2,%ymm8,%ymm6 + DB 196,98,101,168,199 ; vfmadd213ps %ymm7,%ymm3,%ymm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,199 ; vmovaps %ymm8,%ymm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_nx_hsw +_sk_bilinear_nx_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,191 ; mov $0xbf000000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 197,252,88,0 ; vaddps (%rax),%ymm0,%ymm0 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,64,64 ; vsubps 0x40(%rax),%ymm8,%ymm8 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_px_hsw +_sk_bilinear_px_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 197,252,88,0 ; vaddps (%rax),%ymm0,%ymm0 + DB 197,124,16,64,64 ; vmovups 0x40(%rax),%ymm8 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_ny_hsw +_sk_bilinear_ny_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,191 ; mov $0xbf000000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,244,88,72,32 ; vaddps 0x20(%rax),%ymm1,%ymm1 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,64,96 ; vsubps 0x60(%rax),%ymm8,%ymm8 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_py_hsw +_sk_bilinear_py_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,244,88,72,32 ; vaddps 0x20(%rax),%ymm1,%ymm1 + DB 197,124,16,64,96 ; vmovups 0x60(%rax),%ymm8 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n3x_hsw +_sk_bicubic_n3x_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,192,191 ; mov $0xbfc00000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 197,252,88,0 ; vaddps (%rax),%ymm0,%ymm0 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,64,64 ; vsubps 0x40(%rax),%ymm8,%ymm8 + DB 196,65,60,89,200 ; vmulps %ymm8,%ymm8,%ymm9 + DB 65,184,114,28,199,62 ; mov $0x3ec71c72,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 65,184,171,170,170,190 ; mov $0xbeaaaaab,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,66,125,88,219 ; vpbroadcastd %xmm11,%ymm11 + DB 196,66,61,168,211 ; vfmadd213ps %ymm11,%ymm8,%ymm10 + DB 196,65,44,89,193 ; vmulps %ymm9,%ymm10,%ymm8 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n1x_hsw +_sk_bicubic_n1x_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,191 ; mov $0xbf000000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 197,252,88,0 ; vaddps (%rax),%ymm0,%ymm0 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,64,64 ; vsubps 0x40(%rax),%ymm8,%ymm8 + DB 65,184,85,85,149,191 ; mov $0xbf955555,%r8d + DB 196,65,121,110,200 ; vmovd %r8d,%xmm9 + DB 196,66,125,88,201 ; vpbroadcastd %xmm9,%ymm9 + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 196,66,61,168,202 ; vfmadd213ps %ymm10,%ymm8,%ymm9 + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 196,66,61,184,209 ; vfmadd231ps %ymm9,%ymm8,%ymm10 + DB 65,184,57,142,99,61 ; mov $0x3d638e39,%r8d + DB 196,65,121,110,200 ; vmovd %r8d,%xmm9 + DB 196,66,125,88,201 ; vpbroadcastd %xmm9,%ymm9 + DB 196,66,61,184,202 ; vfmadd231ps %ymm10,%ymm8,%ymm9 + DB 197,124,17,136,128,0,0,0 ; vmovups %ymm9,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p1x_hsw +_sk_bicubic_p1x_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,98,125,88,192 ; vpbroadcastd %xmm0,%ymm8 + DB 197,188,88,0 ; vaddps (%rax),%ymm8,%ymm0 + DB 197,124,16,72,64 ; vmovups 0x40(%rax),%ymm9 + DB 65,184,85,85,149,191 ; mov $0xbf955555,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,66,125,88,219 ; vpbroadcastd %xmm11,%ymm11 + DB 196,66,53,168,211 ; vfmadd213ps %ymm11,%ymm9,%ymm10 + DB 196,66,53,168,208 ; vfmadd213ps %ymm8,%ymm9,%ymm10 + DB 65,184,57,142,99,61 ; mov $0x3d638e39,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 196,66,53,184,194 ; vfmadd231ps %ymm10,%ymm9,%ymm8 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p3x_hsw +_sk_bicubic_p3x_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,226,125,88,192 ; vpbroadcastd %xmm0,%ymm0 + DB 197,252,88,0 ; vaddps (%rax),%ymm0,%ymm0 + DB 197,124,16,64,64 ; vmovups 0x40(%rax),%ymm8 + DB 196,65,60,89,200 ; vmulps %ymm8,%ymm8,%ymm9 + DB 65,184,114,28,199,62 ; mov $0x3ec71c72,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 65,184,171,170,170,190 ; mov $0xbeaaaaab,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,66,125,88,219 ; vpbroadcastd %xmm11,%ymm11 + DB 196,66,61,168,211 ; vfmadd213ps %ymm11,%ymm8,%ymm10 + DB 196,65,52,89,194 ; vmulps %ymm10,%ymm9,%ymm8 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n3y_hsw +_sk_bicubic_n3y_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,192,191 ; mov $0xbfc00000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,244,88,72,32 ; vaddps 0x20(%rax),%ymm1,%ymm1 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,64,96 ; vsubps 0x60(%rax),%ymm8,%ymm8 + DB 196,65,60,89,200 ; vmulps %ymm8,%ymm8,%ymm9 + DB 65,184,114,28,199,62 ; mov $0x3ec71c72,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 65,184,171,170,170,190 ; mov $0xbeaaaaab,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,66,125,88,219 ; vpbroadcastd %xmm11,%ymm11 + DB 196,66,61,168,211 ; vfmadd213ps %ymm11,%ymm8,%ymm10 + DB 196,65,44,89,193 ; vmulps %ymm9,%ymm10,%ymm8 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n1y_hsw +_sk_bicubic_n1y_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,191 ; mov $0xbf000000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,244,88,72,32 ; vaddps 0x20(%rax),%ymm1,%ymm1 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 197,60,92,64,96 ; vsubps 0x60(%rax),%ymm8,%ymm8 + DB 65,184,85,85,149,191 ; mov $0xbf955555,%r8d + DB 196,65,121,110,200 ; vmovd %r8d,%xmm9 + DB 196,66,125,88,201 ; vpbroadcastd %xmm9,%ymm9 + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 196,66,61,168,202 ; vfmadd213ps %ymm10,%ymm8,%ymm9 + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 196,66,61,184,209 ; vfmadd231ps %ymm9,%ymm8,%ymm10 + DB 65,184,57,142,99,61 ; mov $0x3d638e39,%r8d + DB 196,65,121,110,200 ; vmovd %r8d,%xmm9 + DB 196,66,125,88,201 ; vpbroadcastd %xmm9,%ymm9 + DB 196,66,61,184,202 ; vfmadd231ps %ymm10,%ymm8,%ymm9 + DB 197,124,17,136,160,0,0,0 ; vmovups %ymm9,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p1y_hsw +_sk_bicubic_p1y_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,98,125,88,193 ; vpbroadcastd %xmm1,%ymm8 + DB 197,188,88,72,32 ; vaddps 0x20(%rax),%ymm8,%ymm1 + DB 197,124,16,72,96 ; vmovups 0x60(%rax),%ymm9 + DB 65,184,85,85,149,191 ; mov $0xbf955555,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,66,125,88,219 ; vpbroadcastd %xmm11,%ymm11 + DB 196,66,53,168,211 ; vfmadd213ps %ymm11,%ymm9,%ymm10 + DB 196,66,53,168,208 ; vfmadd213ps %ymm8,%ymm9,%ymm10 + DB 65,184,57,142,99,61 ; mov $0x3d638e39,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,66,125,88,192 ; vpbroadcastd %xmm8,%ymm8 + DB 196,66,53,184,194 ; vfmadd231ps %ymm10,%ymm9,%ymm8 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p3y_hsw +_sk_bicubic_p3y_hsw LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,226,125,88,201 ; vpbroadcastd %xmm1,%ymm1 + DB 197,244,88,72,32 ; vaddps 0x20(%rax),%ymm1,%ymm1 + DB 197,124,16,64,96 ; vmovups 0x60(%rax),%ymm8 + DB 196,65,60,89,200 ; vmulps %ymm8,%ymm8,%ymm9 + DB 65,184,114,28,199,62 ; mov $0x3ec71c72,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,66,125,88,210 ; vpbroadcastd %xmm10,%ymm10 + DB 65,184,171,170,170,190 ; mov $0xbeaaaaab,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,66,125,88,219 ; vpbroadcastd %xmm11,%ymm11 + DB 196,66,61,168,211 ; vfmadd213ps %ymm11,%ymm8,%ymm10 + DB 196,65,52,89,194 ; vmulps %ymm10,%ymm9,%ymm8 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_start_pipeline_avx +_sk_start_pipeline_avx LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 86 ; push %rsi + DB 87 ; push %rdi + DB 83 ; push %rbx + DB 72,129,236,160,0,0,0 ; sub $0xa0,%rsp + DB 197,120,41,188,36,144,0,0,0 ; vmovaps %xmm15,0x90(%rsp) + DB 197,120,41,180,36,128,0,0,0 ; vmovaps %xmm14,0x80(%rsp) + DB 197,120,41,108,36,112 ; vmovaps %xmm13,0x70(%rsp) + DB 197,120,41,100,36,96 ; vmovaps %xmm12,0x60(%rsp) + DB 197,120,41,92,36,80 ; vmovaps %xmm11,0x50(%rsp) + DB 197,120,41,84,36,64 ; vmovaps %xmm10,0x40(%rsp) + DB 197,120,41,76,36,48 ; vmovaps %xmm9,0x30(%rsp) + DB 197,120,41,68,36,32 ; vmovaps %xmm8,0x20(%rsp) + DB 197,248,41,124,36,16 ; vmovaps %xmm7,0x10(%rsp) + DB 197,248,41,52,36 ; vmovaps %xmm6,(%rsp) + DB 77,137,205 ; mov %r9,%r13 + DB 77,137,198 ; mov %r8,%r14 + DB 72,137,203 ; mov %rcx,%rbx + DB 72,137,214 ; mov %rdx,%rsi + DB 72,173 ; lods %ds:(%rsi),%rax + DB 73,137,199 ; mov %rax,%r15 + DB 73,137,244 ; mov %rsi,%r12 + DB 72,141,67,8 ; lea 0x8(%rbx),%rax + DB 76,57,232 ; cmp %r13,%rax + DB 118,5 ; jbe 75 <_sk_start_pipeline_avx+0x75> + DB 72,137,223 ; mov %rbx,%rdi + DB 235,65 ; jmp b6 <_sk_start_pipeline_avx+0xb6> + DB 185,0,0,0,0 ; mov $0x0,%ecx + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 197,228,87,219 ; vxorps %ymm3,%ymm3,%ymm3 + DB 197,220,87,228 ; vxorps %ymm4,%ymm4,%ymm4 + DB 197,212,87,237 ; vxorps %ymm5,%ymm5,%ymm5 + DB 197,204,87,246 ; vxorps %ymm6,%ymm6,%ymm6 + DB 197,196,87,255 ; vxorps %ymm7,%ymm7,%ymm7 + DB 72,137,223 ; mov %rbx,%rdi + DB 76,137,230 ; mov %r12,%rsi + DB 76,137,242 ; mov %r14,%rdx + DB 65,255,215 ; callq *%r15 + DB 72,141,123,8 ; lea 0x8(%rbx),%rdi + DB 72,131,195,16 ; add $0x10,%rbx + DB 76,57,235 ; cmp %r13,%rbx + DB 72,137,251 ; mov %rdi,%rbx + DB 118,191 ; jbe 75 <_sk_start_pipeline_avx+0x75> + DB 76,137,233 ; mov %r13,%rcx + DB 72,41,249 ; sub %rdi,%rcx + DB 116,41 ; je e7 <_sk_start_pipeline_avx+0xe7> + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 197,228,87,219 ; vxorps %ymm3,%ymm3,%ymm3 + DB 197,220,87,228 ; vxorps %ymm4,%ymm4,%ymm4 + DB 197,212,87,237 ; vxorps %ymm5,%ymm5,%ymm5 + DB 197,204,87,246 ; vxorps %ymm6,%ymm6,%ymm6 + DB 197,196,87,255 ; vxorps %ymm7,%ymm7,%ymm7 + DB 76,137,230 ; mov %r12,%rsi + DB 76,137,242 ; mov %r14,%rdx + DB 65,255,215 ; callq *%r15 + DB 76,137,232 ; mov %r13,%rax + DB 197,248,40,52,36 ; vmovaps (%rsp),%xmm6 + DB 197,248,40,124,36,16 ; vmovaps 0x10(%rsp),%xmm7 + DB 197,120,40,68,36,32 ; vmovaps 0x20(%rsp),%xmm8 + DB 197,120,40,76,36,48 ; vmovaps 0x30(%rsp),%xmm9 + DB 197,120,40,84,36,64 ; vmovaps 0x40(%rsp),%xmm10 + DB 197,120,40,92,36,80 ; vmovaps 0x50(%rsp),%xmm11 + DB 197,120,40,100,36,96 ; vmovaps 0x60(%rsp),%xmm12 + DB 197,120,40,108,36,112 ; vmovaps 0x70(%rsp),%xmm13 + DB 197,120,40,180,36,128,0,0,0 ; vmovaps 0x80(%rsp),%xmm14 + DB 197,120,40,188,36,144,0,0,0 ; vmovaps 0x90(%rsp),%xmm15 + DB 72,129,196,160,0,0,0 ; add $0xa0,%rsp + DB 91 ; pop %rbx + DB 95 ; pop %rdi + DB 94 ; pop %rsi + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 197,248,119 ; vzeroupper + DB 195 ; retq + +PUBLIC _sk_just_return_avx +_sk_just_return_avx LABEL PROC + DB 195 ; retq + +PUBLIC _sk_seed_shader_avx +_sk_seed_shader_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,249,110,199 ; vmovd %edi,%xmm0 + DB 197,249,112,192,0 ; vpshufd $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,252,88,193 ; vaddps %ymm1,%ymm0,%ymm0 + DB 197,252,88,2 ; vaddps (%rdx),%ymm0,%ymm0 + DB 196,226,125,24,16 ; vbroadcastss (%rax),%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 197,236,88,201 ; vaddps %ymm1,%ymm2,%ymm1 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,227,121,4,210,0 ; vpermilps $0x0,%xmm2,%xmm2 + DB 196,227,109,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,228,87,219 ; vxorps %ymm3,%ymm3,%ymm3 + DB 197,220,87,228 ; vxorps %ymm4,%ymm4,%ymm4 + DB 197,212,87,237 ; vxorps %ymm5,%ymm5,%ymm5 + DB 197,204,87,246 ; vxorps %ymm6,%ymm6,%ymm6 + DB 197,196,87,255 ; vxorps %ymm7,%ymm7,%ymm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_constant_color_avx +_sk_constant_color_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,226,125,24,0 ; vbroadcastss (%rax),%ymm0 + DB 196,226,125,24,72,4 ; vbroadcastss 0x4(%rax),%ymm1 + DB 196,226,125,24,80,8 ; vbroadcastss 0x8(%rax),%ymm2 + DB 196,226,125,24,88,12 ; vbroadcastss 0xc(%rax),%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clear_avx +_sk_clear_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 197,228,87,219 ; vxorps %ymm3,%ymm3,%ymm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcatop_avx +_sk_srcatop_avx LABEL PROC + DB 197,124,89,199 ; vmulps %ymm7,%ymm0,%ymm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,124,92,203 ; vsubps %ymm3,%ymm0,%ymm9 + DB 197,180,89,196 ; vmulps %ymm4,%ymm9,%ymm0 + DB 197,188,88,192 ; vaddps %ymm0,%ymm8,%ymm0 + DB 197,244,89,207 ; vmulps %ymm7,%ymm1,%ymm1 + DB 197,52,89,197 ; vmulps %ymm5,%ymm9,%ymm8 + DB 196,193,116,88,200 ; vaddps %ymm8,%ymm1,%ymm1 + DB 197,236,89,215 ; vmulps %ymm7,%ymm2,%ymm2 + DB 197,52,89,198 ; vmulps %ymm6,%ymm9,%ymm8 + DB 196,193,108,88,208 ; vaddps %ymm8,%ymm2,%ymm2 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 197,52,89,199 ; vmulps %ymm7,%ymm9,%ymm8 + DB 196,193,100,88,216 ; vaddps %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstatop_avx +_sk_dstatop_avx LABEL PROC + DB 197,100,89,196 ; vmulps %ymm4,%ymm3,%ymm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 196,67,121,4,201,0 ; vpermilps $0x0,%xmm9,%xmm9 + DB 196,67,53,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + DB 197,52,92,207 ; vsubps %ymm7,%ymm9,%ymm9 + DB 197,180,89,192 ; vmulps %ymm0,%ymm9,%ymm0 + DB 197,188,88,192 ; vaddps %ymm0,%ymm8,%ymm0 + DB 197,100,89,197 ; vmulps %ymm5,%ymm3,%ymm8 + DB 197,180,89,201 ; vmulps %ymm1,%ymm9,%ymm1 + DB 197,188,88,201 ; vaddps %ymm1,%ymm8,%ymm1 + DB 197,100,89,198 ; vmulps %ymm6,%ymm3,%ymm8 + DB 197,180,89,210 ; vmulps %ymm2,%ymm9,%ymm2 + DB 197,188,88,210 ; vaddps %ymm2,%ymm8,%ymm2 + DB 197,100,89,199 ; vmulps %ymm7,%ymm3,%ymm8 + DB 197,180,89,219 ; vmulps %ymm3,%ymm9,%ymm3 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcin_avx +_sk_srcin_avx LABEL PROC + DB 197,252,89,199 ; vmulps %ymm7,%ymm0,%ymm0 + DB 197,244,89,207 ; vmulps %ymm7,%ymm1,%ymm1 + DB 197,236,89,215 ; vmulps %ymm7,%ymm2,%ymm2 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstin_avx +_sk_dstin_avx LABEL PROC + DB 197,228,89,196 ; vmulps %ymm4,%ymm3,%ymm0 + DB 197,228,89,205 ; vmulps %ymm5,%ymm3,%ymm1 + DB 197,228,89,214 ; vmulps %ymm6,%ymm3,%ymm2 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcout_avx +_sk_srcout_avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,199 ; vsubps %ymm7,%ymm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstout_avx +_sk_dstout_avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,252,92,219 ; vsubps %ymm3,%ymm0,%ymm3 + DB 197,228,89,196 ; vmulps %ymm4,%ymm3,%ymm0 + DB 197,228,89,205 ; vmulps %ymm5,%ymm3,%ymm1 + DB 197,228,89,214 ; vmulps %ymm6,%ymm3,%ymm2 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcover_avx +_sk_srcover_avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,204 ; vmulps %ymm4,%ymm8,%ymm9 + DB 197,180,88,192 ; vaddps %ymm0,%ymm9,%ymm0 + DB 197,60,89,205 ; vmulps %ymm5,%ymm8,%ymm9 + DB 197,180,88,201 ; vaddps %ymm1,%ymm9,%ymm1 + DB 197,60,89,206 ; vmulps %ymm6,%ymm8,%ymm9 + DB 197,180,88,210 ; vaddps %ymm2,%ymm9,%ymm2 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstover_avx +_sk_dstover_avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,199 ; vsubps %ymm7,%ymm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,252,88,196 ; vaddps %ymm4,%ymm0,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,244,88,205 ; vaddps %ymm5,%ymm1,%ymm1 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,236,88,214 ; vaddps %ymm6,%ymm2,%ymm2 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 197,228,88,223 ; vaddps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_modulate_avx +_sk_modulate_avx LABEL PROC + DB 197,252,89,196 ; vmulps %ymm4,%ymm0,%ymm0 + DB 197,244,89,205 ; vmulps %ymm5,%ymm1,%ymm1 + DB 197,236,89,214 ; vmulps %ymm6,%ymm2,%ymm2 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_multiply_avx +_sk_multiply_avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,207 ; vsubps %ymm7,%ymm8,%ymm9 + DB 197,52,89,208 ; vmulps %ymm0,%ymm9,%ymm10 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,220 ; vmulps %ymm4,%ymm8,%ymm11 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 197,252,89,196 ; vmulps %ymm4,%ymm0,%ymm0 + DB 196,193,124,88,194 ; vaddps %ymm10,%ymm0,%ymm0 + DB 197,52,89,209 ; vmulps %ymm1,%ymm9,%ymm10 + DB 197,60,89,221 ; vmulps %ymm5,%ymm8,%ymm11 + DB 196,65,36,88,210 ; vaddps %ymm10,%ymm11,%ymm10 + DB 197,244,89,205 ; vmulps %ymm5,%ymm1,%ymm1 + DB 196,193,116,88,202 ; vaddps %ymm10,%ymm1,%ymm1 + DB 197,52,89,210 ; vmulps %ymm2,%ymm9,%ymm10 + DB 197,60,89,222 ; vmulps %ymm6,%ymm8,%ymm11 + DB 196,65,36,88,210 ; vaddps %ymm10,%ymm11,%ymm10 + DB 197,236,89,214 ; vmulps %ymm6,%ymm2,%ymm2 + DB 196,193,108,88,210 ; vaddps %ymm10,%ymm2,%ymm2 + DB 197,52,89,203 ; vmulps %ymm3,%ymm9,%ymm9 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 196,65,60,88,193 ; vaddps %ymm9,%ymm8,%ymm8 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 196,193,100,88,216 ; vaddps %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_plus__avx +_sk_plus__avx LABEL PROC + DB 197,252,88,196 ; vaddps %ymm4,%ymm0,%ymm0 + DB 197,244,88,205 ; vaddps %ymm5,%ymm1,%ymm1 + DB 197,236,88,214 ; vaddps %ymm6,%ymm2,%ymm2 + DB 197,228,88,223 ; vaddps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_screen_avx +_sk_screen_avx LABEL PROC + DB 197,124,88,196 ; vaddps %ymm4,%ymm0,%ymm8 + DB 197,252,89,196 ; vmulps %ymm4,%ymm0,%ymm0 + DB 197,188,92,192 ; vsubps %ymm0,%ymm8,%ymm0 + DB 197,116,88,197 ; vaddps %ymm5,%ymm1,%ymm8 + DB 197,244,89,205 ; vmulps %ymm5,%ymm1,%ymm1 + DB 197,188,92,201 ; vsubps %ymm1,%ymm8,%ymm1 + DB 197,108,88,198 ; vaddps %ymm6,%ymm2,%ymm8 + DB 197,236,89,214 ; vmulps %ymm6,%ymm2,%ymm2 + DB 197,188,92,210 ; vsubps %ymm2,%ymm8,%ymm2 + DB 197,100,88,199 ; vaddps %ymm7,%ymm3,%ymm8 + DB 197,228,89,223 ; vmulps %ymm7,%ymm3,%ymm3 + DB 197,188,92,219 ; vsubps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_xor__avx +_sk_xor__avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,207 ; vsubps %ymm7,%ymm8,%ymm9 + DB 197,180,89,192 ; vmulps %ymm0,%ymm9,%ymm0 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,212 ; vmulps %ymm4,%ymm8,%ymm10 + DB 196,193,124,88,194 ; vaddps %ymm10,%ymm0,%ymm0 + DB 197,180,89,201 ; vmulps %ymm1,%ymm9,%ymm1 + DB 197,60,89,213 ; vmulps %ymm5,%ymm8,%ymm10 + DB 197,172,88,201 ; vaddps %ymm1,%ymm10,%ymm1 + DB 197,180,89,210 ; vmulps %ymm2,%ymm9,%ymm2 + DB 197,60,89,214 ; vmulps %ymm6,%ymm8,%ymm10 + DB 197,172,88,210 ; vaddps %ymm2,%ymm10,%ymm2 + DB 197,180,89,219 ; vmulps %ymm3,%ymm9,%ymm3 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_darken_avx +_sk_darken_avx LABEL PROC + DB 197,124,88,196 ; vaddps %ymm4,%ymm0,%ymm8 + DB 197,252,89,199 ; vmulps %ymm7,%ymm0,%ymm0 + DB 197,100,89,204 ; vmulps %ymm4,%ymm3,%ymm9 + DB 196,193,124,95,193 ; vmaxps %ymm9,%ymm0,%ymm0 + DB 197,188,92,192 ; vsubps %ymm0,%ymm8,%ymm0 + DB 197,116,88,197 ; vaddps %ymm5,%ymm1,%ymm8 + DB 197,244,89,207 ; vmulps %ymm7,%ymm1,%ymm1 + DB 197,100,89,205 ; vmulps %ymm5,%ymm3,%ymm9 + DB 196,193,116,95,201 ; vmaxps %ymm9,%ymm1,%ymm1 + DB 197,188,92,201 ; vsubps %ymm1,%ymm8,%ymm1 + DB 197,108,88,198 ; vaddps %ymm6,%ymm2,%ymm8 + DB 197,236,89,215 ; vmulps %ymm7,%ymm2,%ymm2 + DB 197,100,89,206 ; vmulps %ymm6,%ymm3,%ymm9 + DB 196,193,108,95,209 ; vmaxps %ymm9,%ymm2,%ymm2 + DB 197,188,92,210 ; vsubps %ymm2,%ymm8,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lighten_avx +_sk_lighten_avx LABEL PROC + DB 197,124,88,196 ; vaddps %ymm4,%ymm0,%ymm8 + DB 197,252,89,199 ; vmulps %ymm7,%ymm0,%ymm0 + DB 197,100,89,204 ; vmulps %ymm4,%ymm3,%ymm9 + DB 196,193,124,93,193 ; vminps %ymm9,%ymm0,%ymm0 + DB 197,188,92,192 ; vsubps %ymm0,%ymm8,%ymm0 + DB 197,116,88,197 ; vaddps %ymm5,%ymm1,%ymm8 + DB 197,244,89,207 ; vmulps %ymm7,%ymm1,%ymm1 + DB 197,100,89,205 ; vmulps %ymm5,%ymm3,%ymm9 + DB 196,193,116,93,201 ; vminps %ymm9,%ymm1,%ymm1 + DB 197,188,92,201 ; vsubps %ymm1,%ymm8,%ymm1 + DB 197,108,88,198 ; vaddps %ymm6,%ymm2,%ymm8 + DB 197,236,89,215 ; vmulps %ymm7,%ymm2,%ymm2 + DB 197,100,89,206 ; vmulps %ymm6,%ymm3,%ymm9 + DB 196,193,108,93,209 ; vminps %ymm9,%ymm2,%ymm2 + DB 197,188,92,210 ; vsubps %ymm2,%ymm8,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_difference_avx +_sk_difference_avx LABEL PROC + DB 197,124,88,196 ; vaddps %ymm4,%ymm0,%ymm8 + DB 197,252,89,199 ; vmulps %ymm7,%ymm0,%ymm0 + DB 197,100,89,204 ; vmulps %ymm4,%ymm3,%ymm9 + DB 196,193,124,93,193 ; vminps %ymm9,%ymm0,%ymm0 + DB 197,252,88,192 ; vaddps %ymm0,%ymm0,%ymm0 + DB 197,188,92,192 ; vsubps %ymm0,%ymm8,%ymm0 + DB 197,116,88,197 ; vaddps %ymm5,%ymm1,%ymm8 + DB 197,244,89,207 ; vmulps %ymm7,%ymm1,%ymm1 + DB 197,100,89,205 ; vmulps %ymm5,%ymm3,%ymm9 + DB 196,193,116,93,201 ; vminps %ymm9,%ymm1,%ymm1 + DB 197,244,88,201 ; vaddps %ymm1,%ymm1,%ymm1 + DB 197,188,92,201 ; vsubps %ymm1,%ymm8,%ymm1 + DB 197,108,88,198 ; vaddps %ymm6,%ymm2,%ymm8 + DB 197,236,89,215 ; vmulps %ymm7,%ymm2,%ymm2 + DB 197,100,89,206 ; vmulps %ymm6,%ymm3,%ymm9 + DB 196,193,108,93,209 ; vminps %ymm9,%ymm2,%ymm2 + DB 197,236,88,210 ; vaddps %ymm2,%ymm2,%ymm2 + DB 197,188,92,210 ; vsubps %ymm2,%ymm8,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_exclusion_avx +_sk_exclusion_avx LABEL PROC + DB 197,124,88,196 ; vaddps %ymm4,%ymm0,%ymm8 + DB 197,252,89,196 ; vmulps %ymm4,%ymm0,%ymm0 + DB 197,252,88,192 ; vaddps %ymm0,%ymm0,%ymm0 + DB 197,188,92,192 ; vsubps %ymm0,%ymm8,%ymm0 + DB 197,116,88,197 ; vaddps %ymm5,%ymm1,%ymm8 + DB 197,244,89,205 ; vmulps %ymm5,%ymm1,%ymm1 + DB 197,244,88,201 ; vaddps %ymm1,%ymm1,%ymm1 + DB 197,188,92,201 ; vsubps %ymm1,%ymm8,%ymm1 + DB 197,108,88,198 ; vaddps %ymm6,%ymm2,%ymm8 + DB 197,236,89,214 ; vmulps %ymm6,%ymm2,%ymm2 + DB 197,236,88,210 ; vaddps %ymm2,%ymm2,%ymm2 + DB 197,188,92,210 ; vsubps %ymm2,%ymm8,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_colorburn_avx +_sk_colorburn_avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,207 ; vsubps %ymm7,%ymm8,%ymm9 + DB 197,52,89,216 ; vmulps %ymm0,%ymm9,%ymm11 + DB 196,65,44,87,210 ; vxorps %ymm10,%ymm10,%ymm10 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,228 ; vmulps %ymm4,%ymm8,%ymm12 + DB 197,68,92,236 ; vsubps %ymm4,%ymm7,%ymm13 + DB 197,20,89,235 ; vmulps %ymm3,%ymm13,%ymm13 + DB 197,20,94,232 ; vdivps %ymm0,%ymm13,%ymm13 + DB 196,65,68,93,237 ; vminps %ymm13,%ymm7,%ymm13 + DB 196,65,68,92,237 ; vsubps %ymm13,%ymm7,%ymm13 + DB 197,20,89,235 ; vmulps %ymm3,%ymm13,%ymm13 + DB 196,65,20,88,235 ; vaddps %ymm11,%ymm13,%ymm13 + DB 196,65,28,88,237 ; vaddps %ymm13,%ymm12,%ymm13 + DB 197,28,88,224 ; vaddps %ymm0,%ymm12,%ymm12 + DB 196,193,124,194,194,0 ; vcmpeqps %ymm10,%ymm0,%ymm0 + DB 196,195,21,74,196,0 ; vblendvps %ymm0,%ymm12,%ymm13,%ymm0 + DB 197,92,194,231,0 ; vcmpeqps %ymm7,%ymm4,%ymm12 + DB 197,36,88,220 ; vaddps %ymm4,%ymm11,%ymm11 + DB 196,195,125,74,195,192 ; vblendvps %ymm12,%ymm11,%ymm0,%ymm0 + DB 197,52,89,217 ; vmulps %ymm1,%ymm9,%ymm11 + DB 197,60,89,229 ; vmulps %ymm5,%ymm8,%ymm12 + DB 197,68,92,237 ; vsubps %ymm5,%ymm7,%ymm13 + DB 197,20,89,235 ; vmulps %ymm3,%ymm13,%ymm13 + DB 197,20,94,233 ; vdivps %ymm1,%ymm13,%ymm13 + DB 196,65,68,93,237 ; vminps %ymm13,%ymm7,%ymm13 + DB 196,65,68,92,237 ; vsubps %ymm13,%ymm7,%ymm13 + DB 197,20,89,235 ; vmulps %ymm3,%ymm13,%ymm13 + DB 196,65,36,88,237 ; vaddps %ymm13,%ymm11,%ymm13 + DB 196,65,28,88,237 ; vaddps %ymm13,%ymm12,%ymm13 + DB 197,28,88,225 ; vaddps %ymm1,%ymm12,%ymm12 + DB 196,193,116,194,202,0 ; vcmpeqps %ymm10,%ymm1,%ymm1 + DB 196,195,21,74,204,16 ; vblendvps %ymm1,%ymm12,%ymm13,%ymm1 + DB 197,84,194,231,0 ; vcmpeqps %ymm7,%ymm5,%ymm12 + DB 197,36,88,221 ; vaddps %ymm5,%ymm11,%ymm11 + DB 196,195,117,74,203,192 ; vblendvps %ymm12,%ymm11,%ymm1,%ymm1 + DB 197,52,89,202 ; vmulps %ymm2,%ymm9,%ymm9 + DB 196,65,108,194,210,0 ; vcmpeqps %ymm10,%ymm2,%ymm10 + DB 197,60,89,222 ; vmulps %ymm6,%ymm8,%ymm11 + DB 197,68,92,230 ; vsubps %ymm6,%ymm7,%ymm12 + DB 197,28,89,227 ; vmulps %ymm3,%ymm12,%ymm12 + DB 197,28,94,226 ; vdivps %ymm2,%ymm12,%ymm12 + DB 197,164,88,210 ; vaddps %ymm2,%ymm11,%ymm2 + DB 196,65,68,93,228 ; vminps %ymm12,%ymm7,%ymm12 + DB 196,65,68,92,228 ; vsubps %ymm12,%ymm7,%ymm12 + DB 197,28,89,227 ; vmulps %ymm3,%ymm12,%ymm12 + DB 196,65,52,88,228 ; vaddps %ymm12,%ymm9,%ymm12 + DB 196,65,36,88,220 ; vaddps %ymm12,%ymm11,%ymm11 + DB 196,227,37,74,210,160 ; vblendvps %ymm10,%ymm2,%ymm11,%ymm2 + DB 197,76,194,215,0 ; vcmpeqps %ymm7,%ymm6,%ymm10 + DB 197,52,88,206 ; vaddps %ymm6,%ymm9,%ymm9 + DB 196,195,109,74,209,160 ; vblendvps %ymm10,%ymm9,%ymm2,%ymm2 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_colordodge_avx +_sk_colordodge_avx LABEL PROC + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 196,67,121,4,201,0 ; vpermilps $0x0,%xmm9,%xmm9 + DB 196,67,53,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + DB 197,52,92,215 ; vsubps %ymm7,%ymm9,%ymm10 + DB 197,44,89,216 ; vmulps %ymm0,%ymm10,%ymm11 + DB 197,52,92,203 ; vsubps %ymm3,%ymm9,%ymm9 + DB 197,100,89,228 ; vmulps %ymm4,%ymm3,%ymm12 + DB 197,100,92,232 ; vsubps %ymm0,%ymm3,%ymm13 + DB 196,65,28,94,229 ; vdivps %ymm13,%ymm12,%ymm12 + DB 197,52,89,236 ; vmulps %ymm4,%ymm9,%ymm13 + DB 196,65,68,93,228 ; vminps %ymm12,%ymm7,%ymm12 + DB 197,28,89,227 ; vmulps %ymm3,%ymm12,%ymm12 + DB 196,65,28,88,227 ; vaddps %ymm11,%ymm12,%ymm12 + DB 196,65,20,88,228 ; vaddps %ymm12,%ymm13,%ymm12 + DB 197,20,88,232 ; vaddps %ymm0,%ymm13,%ymm13 + DB 197,252,194,195,0 ; vcmpeqps %ymm3,%ymm0,%ymm0 + DB 196,195,29,74,197,0 ; vblendvps %ymm0,%ymm13,%ymm12,%ymm0 + DB 196,65,92,194,224,0 ; vcmpeqps %ymm8,%ymm4,%ymm12 + DB 197,36,88,220 ; vaddps %ymm4,%ymm11,%ymm11 + DB 196,195,125,74,195,192 ; vblendvps %ymm12,%ymm11,%ymm0,%ymm0 + DB 197,44,89,217 ; vmulps %ymm1,%ymm10,%ymm11 + DB 197,100,89,229 ; vmulps %ymm5,%ymm3,%ymm12 + DB 197,100,92,233 ; vsubps %ymm1,%ymm3,%ymm13 + DB 196,65,28,94,229 ; vdivps %ymm13,%ymm12,%ymm12 + DB 197,52,89,237 ; vmulps %ymm5,%ymm9,%ymm13 + DB 196,65,68,93,228 ; vminps %ymm12,%ymm7,%ymm12 + DB 197,28,89,227 ; vmulps %ymm3,%ymm12,%ymm12 + DB 196,65,28,88,227 ; vaddps %ymm11,%ymm12,%ymm12 + DB 196,65,20,88,228 ; vaddps %ymm12,%ymm13,%ymm12 + DB 197,20,88,233 ; vaddps %ymm1,%ymm13,%ymm13 + DB 197,244,194,203,0 ; vcmpeqps %ymm3,%ymm1,%ymm1 + DB 196,195,29,74,205,16 ; vblendvps %ymm1,%ymm13,%ymm12,%ymm1 + DB 196,65,84,194,224,0 ; vcmpeqps %ymm8,%ymm5,%ymm12 + DB 197,36,88,221 ; vaddps %ymm5,%ymm11,%ymm11 + DB 196,195,117,74,203,192 ; vblendvps %ymm12,%ymm11,%ymm1,%ymm1 + DB 197,44,89,210 ; vmulps %ymm2,%ymm10,%ymm10 + DB 197,100,89,222 ; vmulps %ymm6,%ymm3,%ymm11 + DB 197,100,92,226 ; vsubps %ymm2,%ymm3,%ymm12 + DB 196,65,36,94,220 ; vdivps %ymm12,%ymm11,%ymm11 + DB 197,52,89,230 ; vmulps %ymm6,%ymm9,%ymm12 + DB 196,65,68,93,219 ; vminps %ymm11,%ymm7,%ymm11 + DB 197,36,89,219 ; vmulps %ymm3,%ymm11,%ymm11 + DB 196,65,44,88,219 ; vaddps %ymm11,%ymm10,%ymm11 + DB 196,65,28,88,219 ; vaddps %ymm11,%ymm12,%ymm11 + DB 197,28,88,226 ; vaddps %ymm2,%ymm12,%ymm12 + DB 197,236,194,211,0 ; vcmpeqps %ymm3,%ymm2,%ymm2 + DB 196,195,37,74,212,32 ; vblendvps %ymm2,%ymm12,%ymm11,%ymm2 + DB 196,65,76,194,192,0 ; vcmpeqps %ymm8,%ymm6,%ymm8 + DB 197,44,88,214 ; vaddps %ymm6,%ymm10,%ymm10 + DB 196,195,109,74,210,128 ; vblendvps %ymm8,%ymm10,%ymm2,%ymm2 + DB 197,52,89,199 ; vmulps %ymm7,%ymm9,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_hardlight_avx +_sk_hardlight_avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,215 ; vsubps %ymm7,%ymm8,%ymm10 + DB 197,44,89,200 ; vmulps %ymm0,%ymm10,%ymm9 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,220 ; vmulps %ymm4,%ymm8,%ymm11 + DB 196,65,52,88,219 ; vaddps %ymm11,%ymm9,%ymm11 + DB 197,124,88,200 ; vaddps %ymm0,%ymm0,%ymm9 + DB 197,52,194,227,2 ; vcmpleps %ymm3,%ymm9,%ymm12 + DB 197,124,89,204 ; vmulps %ymm4,%ymm0,%ymm9 + DB 196,65,52,88,233 ; vaddps %ymm9,%ymm9,%ymm13 + DB 197,100,89,207 ; vmulps %ymm7,%ymm3,%ymm9 + DB 197,68,92,244 ; vsubps %ymm4,%ymm7,%ymm14 + DB 197,228,92,192 ; vsubps %ymm0,%ymm3,%ymm0 + DB 196,193,124,89,198 ; vmulps %ymm14,%ymm0,%ymm0 + DB 197,252,88,192 ; vaddps %ymm0,%ymm0,%ymm0 + DB 197,180,92,192 ; vsubps %ymm0,%ymm9,%ymm0 + DB 196,195,125,74,197,192 ; vblendvps %ymm12,%ymm13,%ymm0,%ymm0 + DB 196,193,124,88,195 ; vaddps %ymm11,%ymm0,%ymm0 + DB 197,44,89,217 ; vmulps %ymm1,%ymm10,%ymm11 + DB 197,60,89,229 ; vmulps %ymm5,%ymm8,%ymm12 + DB 196,65,28,88,219 ; vaddps %ymm11,%ymm12,%ymm11 + DB 197,116,88,225 ; vaddps %ymm1,%ymm1,%ymm12 + DB 197,28,194,227,2 ; vcmpleps %ymm3,%ymm12,%ymm12 + DB 197,116,89,237 ; vmulps %ymm5,%ymm1,%ymm13 + DB 196,65,20,88,237 ; vaddps %ymm13,%ymm13,%ymm13 + DB 197,68,92,245 ; vsubps %ymm5,%ymm7,%ymm14 + DB 197,228,92,201 ; vsubps %ymm1,%ymm3,%ymm1 + DB 196,193,116,89,206 ; vmulps %ymm14,%ymm1,%ymm1 + DB 197,244,88,201 ; vaddps %ymm1,%ymm1,%ymm1 + DB 197,180,92,201 ; vsubps %ymm1,%ymm9,%ymm1 + DB 196,195,117,74,205,192 ; vblendvps %ymm12,%ymm13,%ymm1,%ymm1 + DB 196,193,116,88,203 ; vaddps %ymm11,%ymm1,%ymm1 + DB 197,44,89,210 ; vmulps %ymm2,%ymm10,%ymm10 + DB 197,60,89,222 ; vmulps %ymm6,%ymm8,%ymm11 + DB 196,65,36,88,210 ; vaddps %ymm10,%ymm11,%ymm10 + DB 197,108,88,218 ; vaddps %ymm2,%ymm2,%ymm11 + DB 197,36,194,219,2 ; vcmpleps %ymm3,%ymm11,%ymm11 + DB 197,108,89,230 ; vmulps %ymm6,%ymm2,%ymm12 + DB 196,65,28,88,228 ; vaddps %ymm12,%ymm12,%ymm12 + DB 197,68,92,238 ; vsubps %ymm6,%ymm7,%ymm13 + DB 197,228,92,210 ; vsubps %ymm2,%ymm3,%ymm2 + DB 196,193,108,89,213 ; vmulps %ymm13,%ymm2,%ymm2 + DB 197,236,88,210 ; vaddps %ymm2,%ymm2,%ymm2 + DB 197,180,92,210 ; vsubps %ymm2,%ymm9,%ymm2 + DB 196,195,109,74,212,176 ; vblendvps %ymm11,%ymm12,%ymm2,%ymm2 + DB 196,193,108,88,210 ; vaddps %ymm10,%ymm2,%ymm2 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_overlay_avx +_sk_overlay_avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,215 ; vsubps %ymm7,%ymm8,%ymm10 + DB 197,44,89,200 ; vmulps %ymm0,%ymm10,%ymm9 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,220 ; vmulps %ymm4,%ymm8,%ymm11 + DB 196,65,52,88,219 ; vaddps %ymm11,%ymm9,%ymm11 + DB 197,92,88,204 ; vaddps %ymm4,%ymm4,%ymm9 + DB 197,52,194,231,2 ; vcmpleps %ymm7,%ymm9,%ymm12 + DB 197,124,89,204 ; vmulps %ymm4,%ymm0,%ymm9 + DB 196,65,52,88,233 ; vaddps %ymm9,%ymm9,%ymm13 + DB 197,100,89,207 ; vmulps %ymm7,%ymm3,%ymm9 + DB 197,68,92,244 ; vsubps %ymm4,%ymm7,%ymm14 + DB 197,228,92,192 ; vsubps %ymm0,%ymm3,%ymm0 + DB 196,193,124,89,198 ; vmulps %ymm14,%ymm0,%ymm0 + DB 197,252,88,192 ; vaddps %ymm0,%ymm0,%ymm0 + DB 197,180,92,192 ; vsubps %ymm0,%ymm9,%ymm0 + DB 196,195,125,74,197,192 ; vblendvps %ymm12,%ymm13,%ymm0,%ymm0 + DB 196,193,124,88,195 ; vaddps %ymm11,%ymm0,%ymm0 + DB 197,44,89,217 ; vmulps %ymm1,%ymm10,%ymm11 + DB 197,60,89,229 ; vmulps %ymm5,%ymm8,%ymm12 + DB 196,65,28,88,219 ; vaddps %ymm11,%ymm12,%ymm11 + DB 197,84,88,229 ; vaddps %ymm5,%ymm5,%ymm12 + DB 197,28,194,231,2 ; vcmpleps %ymm7,%ymm12,%ymm12 + DB 197,116,89,237 ; vmulps %ymm5,%ymm1,%ymm13 + DB 196,65,20,88,237 ; vaddps %ymm13,%ymm13,%ymm13 + DB 197,68,92,245 ; vsubps %ymm5,%ymm7,%ymm14 + DB 197,228,92,201 ; vsubps %ymm1,%ymm3,%ymm1 + DB 196,193,116,89,206 ; vmulps %ymm14,%ymm1,%ymm1 + DB 197,244,88,201 ; vaddps %ymm1,%ymm1,%ymm1 + DB 197,180,92,201 ; vsubps %ymm1,%ymm9,%ymm1 + DB 196,195,117,74,205,192 ; vblendvps %ymm12,%ymm13,%ymm1,%ymm1 + DB 196,193,116,88,203 ; vaddps %ymm11,%ymm1,%ymm1 + DB 197,44,89,210 ; vmulps %ymm2,%ymm10,%ymm10 + DB 197,60,89,222 ; vmulps %ymm6,%ymm8,%ymm11 + DB 196,65,36,88,210 ; vaddps %ymm10,%ymm11,%ymm10 + DB 197,76,88,222 ; vaddps %ymm6,%ymm6,%ymm11 + DB 197,36,194,223,2 ; vcmpleps %ymm7,%ymm11,%ymm11 + DB 197,108,89,230 ; vmulps %ymm6,%ymm2,%ymm12 + DB 196,65,28,88,228 ; vaddps %ymm12,%ymm12,%ymm12 + DB 197,68,92,238 ; vsubps %ymm6,%ymm7,%ymm13 + DB 197,228,92,210 ; vsubps %ymm2,%ymm3,%ymm2 + DB 196,193,108,89,213 ; vmulps %ymm13,%ymm2,%ymm2 + DB 197,236,88,210 ; vaddps %ymm2,%ymm2,%ymm2 + DB 197,180,92,210 ; vsubps %ymm2,%ymm9,%ymm2 + DB 196,195,109,74,212,176 ; vblendvps %ymm11,%ymm12,%ymm2,%ymm2 + DB 196,193,108,88,210 ; vaddps %ymm10,%ymm2,%ymm2 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_softlight_avx +_sk_softlight_avx LABEL PROC + DB 72,131,236,56 ; sub $0x38,%rsp + DB 197,252,17,20,36 ; vmovups %ymm2,(%rsp) + DB 197,252,40,209 ; vmovaps %ymm1,%ymm2 + DB 196,65,52,87,201 ; vxorps %ymm9,%ymm9,%ymm9 + DB 197,52,194,215,1 ; vcmpltps %ymm7,%ymm9,%ymm10 + DB 197,92,94,199 ; vdivps %ymm7,%ymm4,%ymm8 + DB 196,67,53,74,216,160 ; vblendvps %ymm10,%ymm8,%ymm9,%ymm11 + DB 196,65,36,88,195 ; vaddps %ymm11,%ymm11,%ymm8 + DB 196,65,60,88,224 ; vaddps %ymm8,%ymm8,%ymm12 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 196,65,28,89,236 ; vmulps %ymm12,%ymm12,%ymm13 + DB 196,65,28,88,229 ; vaddps %ymm13,%ymm12,%ymm12 + DB 196,65,36,92,232 ; vsubps %ymm8,%ymm11,%ymm13 + DB 196,65,28,89,237 ; vmulps %ymm13,%ymm12,%ymm13 + DB 184,0,0,224,64 ; mov $0x40e00000,%eax + DB 197,121,110,224 ; vmovd %eax,%xmm12 + DB 196,67,121,4,228,0 ; vpermilps $0x0,%xmm12,%xmm12 + DB 196,67,29,24,228,1 ; vinsertf128 $0x1,%xmm12,%ymm12,%ymm12 + DB 196,65,36,89,244 ; vmulps %ymm12,%ymm11,%ymm14 + DB 196,65,20,88,238 ; vaddps %ymm14,%ymm13,%ymm13 + DB 196,65,124,82,243 ; vrsqrtps %ymm11,%ymm14 + DB 196,65,124,83,246 ; vrcpps %ymm14,%ymm14 + DB 196,65,12,92,243 ; vsubps %ymm11,%ymm14,%ymm14 + DB 197,92,88,252 ; vaddps %ymm4,%ymm4,%ymm15 + DB 196,65,4,88,255 ; vaddps %ymm15,%ymm15,%ymm15 + DB 197,4,194,255,2 ; vcmpleps %ymm7,%ymm15,%ymm15 + DB 196,67,13,74,237,240 ; vblendvps %ymm15,%ymm13,%ymm14,%ymm13 + DB 197,124,88,240 ; vaddps %ymm0,%ymm0,%ymm14 + DB 197,12,92,251 ; vsubps %ymm3,%ymm14,%ymm15 + DB 196,65,60,92,219 ; vsubps %ymm11,%ymm8,%ymm11 + DB 196,65,4,89,219 ; vmulps %ymm11,%ymm15,%ymm11 + DB 197,36,88,219 ; vaddps %ymm3,%ymm11,%ymm11 + DB 197,36,89,220 ; vmulps %ymm4,%ymm11,%ymm11 + DB 197,4,89,255 ; vmulps %ymm7,%ymm15,%ymm15 + DB 196,65,4,89,237 ; vmulps %ymm13,%ymm15,%ymm13 + DB 197,100,89,252 ; vmulps %ymm4,%ymm3,%ymm15 + DB 196,65,4,88,237 ; vaddps %ymm13,%ymm15,%ymm13 + DB 197,12,194,243,2 ; vcmpleps %ymm3,%ymm14,%ymm14 + DB 196,195,21,74,203,224 ; vblendvps %ymm14,%ymm11,%ymm13,%ymm1 + DB 197,84,94,239 ; vdivps %ymm7,%ymm5,%ymm13 + DB 196,67,53,74,237,160 ; vblendvps %ymm10,%ymm13,%ymm9,%ymm13 + DB 196,65,20,88,245 ; vaddps %ymm13,%ymm13,%ymm14 + DB 196,65,12,88,246 ; vaddps %ymm14,%ymm14,%ymm14 + DB 196,65,12,89,254 ; vmulps %ymm14,%ymm14,%ymm15 + DB 196,65,12,88,247 ; vaddps %ymm15,%ymm14,%ymm14 + DB 196,65,20,92,248 ; vsubps %ymm8,%ymm13,%ymm15 + DB 196,65,4,89,246 ; vmulps %ymm14,%ymm15,%ymm14 + DB 196,65,28,89,253 ; vmulps %ymm13,%ymm12,%ymm15 + DB 196,65,4,88,246 ; vaddps %ymm14,%ymm15,%ymm14 + DB 196,65,124,82,253 ; vrsqrtps %ymm13,%ymm15 + DB 196,65,124,83,255 ; vrcpps %ymm15,%ymm15 + DB 196,65,4,92,253 ; vsubps %ymm13,%ymm15,%ymm15 + DB 197,84,88,221 ; vaddps %ymm5,%ymm5,%ymm11 + DB 196,65,36,88,219 ; vaddps %ymm11,%ymm11,%ymm11 + DB 197,36,194,223,2 ; vcmpleps %ymm7,%ymm11,%ymm11 + DB 196,67,5,74,222,176 ; vblendvps %ymm11,%ymm14,%ymm15,%ymm11 + DB 197,108,88,242 ; vaddps %ymm2,%ymm2,%ymm14 + DB 196,65,60,92,237 ; vsubps %ymm13,%ymm8,%ymm13 + DB 197,12,92,251 ; vsubps %ymm3,%ymm14,%ymm15 + DB 196,65,4,89,237 ; vmulps %ymm13,%ymm15,%ymm13 + DB 197,4,89,255 ; vmulps %ymm7,%ymm15,%ymm15 + DB 196,65,4,89,219 ; vmulps %ymm11,%ymm15,%ymm11 + DB 197,100,89,253 ; vmulps %ymm5,%ymm3,%ymm15 + DB 196,65,4,88,219 ; vaddps %ymm11,%ymm15,%ymm11 + DB 197,20,88,235 ; vaddps %ymm3,%ymm13,%ymm13 + DB 197,20,89,237 ; vmulps %ymm5,%ymm13,%ymm13 + DB 197,12,194,243,2 ; vcmpleps %ymm3,%ymm14,%ymm14 + DB 196,67,37,74,237,224 ; vblendvps %ymm14,%ymm13,%ymm11,%ymm13 + DB 197,76,94,223 ; vdivps %ymm7,%ymm6,%ymm11 + DB 196,67,53,74,203,160 ; vblendvps %ymm10,%ymm11,%ymm9,%ymm9 + DB 196,65,52,88,209 ; vaddps %ymm9,%ymm9,%ymm10 + DB 196,65,44,88,210 ; vaddps %ymm10,%ymm10,%ymm10 + DB 196,65,44,89,218 ; vmulps %ymm10,%ymm10,%ymm11 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 196,65,52,92,216 ; vsubps %ymm8,%ymm9,%ymm11 + DB 196,65,36,89,210 ; vmulps %ymm10,%ymm11,%ymm10 + DB 196,65,28,89,217 ; vmulps %ymm9,%ymm12,%ymm11 + DB 196,65,36,88,210 ; vaddps %ymm10,%ymm11,%ymm10 + DB 196,65,124,82,217 ; vrsqrtps %ymm9,%ymm11 + DB 196,65,124,83,219 ; vrcpps %ymm11,%ymm11 + DB 196,65,36,92,217 ; vsubps %ymm9,%ymm11,%ymm11 + DB 197,76,88,230 ; vaddps %ymm6,%ymm6,%ymm12 + DB 196,65,28,88,228 ; vaddps %ymm12,%ymm12,%ymm12 + DB 197,28,194,231,2 ; vcmpleps %ymm7,%ymm12,%ymm12 + DB 196,67,37,74,210,192 ; vblendvps %ymm12,%ymm10,%ymm11,%ymm10 + DB 197,124,16,52,36 ; vmovups (%rsp),%ymm14 + DB 196,65,12,88,222 ; vaddps %ymm14,%ymm14,%ymm11 + DB 197,36,92,227 ; vsubps %ymm3,%ymm11,%ymm12 + DB 196,65,60,92,201 ; vsubps %ymm9,%ymm8,%ymm9 + DB 196,65,28,89,201 ; vmulps %ymm9,%ymm12,%ymm9 + DB 197,28,89,231 ; vmulps %ymm7,%ymm12,%ymm12 + DB 196,65,28,89,210 ; vmulps %ymm10,%ymm12,%ymm10 + DB 197,100,89,230 ; vmulps %ymm6,%ymm3,%ymm12 + DB 196,65,28,88,210 ; vaddps %ymm10,%ymm12,%ymm10 + DB 197,52,88,203 ; vaddps %ymm3,%ymm9,%ymm9 + DB 197,52,89,206 ; vmulps %ymm6,%ymm9,%ymm9 + DB 197,36,194,219,2 ; vcmpleps %ymm3,%ymm11,%ymm11 + DB 196,67,45,74,201,176 ; vblendvps %ymm11,%ymm9,%ymm10,%ymm9 + DB 197,60,92,215 ; vsubps %ymm7,%ymm8,%ymm10 + DB 197,172,89,192 ; vmulps %ymm0,%ymm10,%ymm0 + DB 197,60,92,195 ; vsubps %ymm3,%ymm8,%ymm8 + DB 197,60,89,220 ; vmulps %ymm4,%ymm8,%ymm11 + DB 196,193,124,88,195 ; vaddps %ymm11,%ymm0,%ymm0 + DB 197,244,88,192 ; vaddps %ymm0,%ymm1,%ymm0 + DB 197,172,89,202 ; vmulps %ymm2,%ymm10,%ymm1 + DB 197,188,89,213 ; vmulps %ymm5,%ymm8,%ymm2 + DB 197,236,88,201 ; vaddps %ymm1,%ymm2,%ymm1 + DB 196,193,116,88,205 ; vaddps %ymm13,%ymm1,%ymm1 + DB 196,193,44,89,214 ; vmulps %ymm14,%ymm10,%ymm2 + DB 197,60,89,214 ; vmulps %ymm6,%ymm8,%ymm10 + DB 197,172,88,210 ; vaddps %ymm2,%ymm10,%ymm2 + DB 196,193,108,88,209 ; vaddps %ymm9,%ymm2,%ymm2 + DB 197,60,89,199 ; vmulps %ymm7,%ymm8,%ymm8 + DB 197,188,88,219 ; vaddps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,131,196,56 ; add $0x38,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_0_avx +_sk_clamp_0_avx LABEL PROC + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 196,193,124,95,192 ; vmaxps %ymm8,%ymm0,%ymm0 + DB 196,193,116,95,200 ; vmaxps %ymm8,%ymm1,%ymm1 + DB 196,193,108,95,208 ; vmaxps %ymm8,%ymm2,%ymm2 + DB 196,193,100,95,216 ; vmaxps %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_1_avx +_sk_clamp_1_avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 196,193,124,93,192 ; vminps %ymm8,%ymm0,%ymm0 + DB 196,193,116,93,200 ; vminps %ymm8,%ymm1,%ymm1 + DB 196,193,108,93,208 ; vminps %ymm8,%ymm2,%ymm2 + DB 196,193,100,93,216 ; vminps %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_a_avx +_sk_clamp_a_avx LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 196,193,100,93,216 ; vminps %ymm8,%ymm3,%ymm3 + DB 197,252,93,195 ; vminps %ymm3,%ymm0,%ymm0 + DB 197,244,93,203 ; vminps %ymm3,%ymm1,%ymm1 + DB 197,236,93,211 ; vminps %ymm3,%ymm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_set_rgb_avx +_sk_set_rgb_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,226,125,24,0 ; vbroadcastss (%rax),%ymm0 + DB 196,226,125,24,72,4 ; vbroadcastss 0x4(%rax),%ymm1 + DB 196,226,125,24,80,8 ; vbroadcastss 0x8(%rax),%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_swap_rb_avx +_sk_swap_rb_avx LABEL PROC + DB 197,124,40,192 ; vmovaps %ymm0,%ymm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,194 ; vmovaps %ymm2,%ymm0 + DB 197,124,41,194 ; vmovaps %ymm8,%ymm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_swap_avx +_sk_swap_avx LABEL PROC + DB 197,124,40,195 ; vmovaps %ymm3,%ymm8 + DB 197,124,40,202 ; vmovaps %ymm2,%ymm9 + DB 197,124,40,209 ; vmovaps %ymm1,%ymm10 + DB 197,124,40,216 ; vmovaps %ymm0,%ymm11 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,196 ; vmovaps %ymm4,%ymm0 + DB 197,252,40,205 ; vmovaps %ymm5,%ymm1 + DB 197,252,40,214 ; vmovaps %ymm6,%ymm2 + DB 197,252,40,223 ; vmovaps %ymm7,%ymm3 + DB 197,124,41,220 ; vmovaps %ymm11,%ymm4 + DB 197,124,41,213 ; vmovaps %ymm10,%ymm5 + DB 197,124,41,206 ; vmovaps %ymm9,%ymm6 + DB 197,124,41,199 ; vmovaps %ymm8,%ymm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_move_src_dst_avx +_sk_move_src_dst_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,224 ; vmovaps %ymm0,%ymm4 + DB 197,252,40,233 ; vmovaps %ymm1,%ymm5 + DB 197,252,40,242 ; vmovaps %ymm2,%ymm6 + DB 197,252,40,251 ; vmovaps %ymm3,%ymm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_move_dst_src_avx +_sk_move_dst_src_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,196 ; vmovaps %ymm4,%ymm0 + DB 197,252,40,205 ; vmovaps %ymm5,%ymm1 + DB 197,252,40,214 ; vmovaps %ymm6,%ymm2 + DB 197,252,40,223 ; vmovaps %ymm7,%ymm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_premul_avx +_sk_premul_avx LABEL PROC + DB 197,252,89,195 ; vmulps %ymm3,%ymm0,%ymm0 + DB 197,244,89,203 ; vmulps %ymm3,%ymm1,%ymm1 + DB 197,236,89,211 ; vmulps %ymm3,%ymm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_unpremul_avx +_sk_unpremul_avx LABEL PROC + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 196,65,100,194,200,0 ; vcmpeqps %ymm8,%ymm3,%ymm9 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,208 ; vmovd %eax,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 197,44,94,211 ; vdivps %ymm3,%ymm10,%ymm10 + DB 196,67,45,74,192,144 ; vblendvps %ymm9,%ymm8,%ymm10,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_from_srgb_avx +_sk_from_srgb_avx LABEL PROC + DB 184,145,131,158,61 ; mov $0x3d9e8391,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 197,124,89,208 ; vmulps %ymm0,%ymm0,%ymm10 + DB 184,154,153,153,62 ; mov $0x3e99999a,%eax + DB 197,121,110,216 ; vmovd %eax,%xmm11 + DB 196,67,121,4,219,0 ; vpermilps $0x0,%xmm11,%xmm11 + DB 196,67,37,24,219,1 ; vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + DB 184,92,143,50,63 ; mov $0x3f328f5c,%eax + DB 197,121,110,224 ; vmovd %eax,%xmm12 + DB 196,67,121,4,228,0 ; vpermilps $0x0,%xmm12,%xmm12 + DB 196,67,29,24,228,1 ; vinsertf128 $0x1,%xmm12,%ymm12,%ymm12 + DB 197,36,89,232 ; vmulps %ymm0,%ymm11,%ymm13 + DB 196,65,20,88,236 ; vaddps %ymm12,%ymm13,%ymm13 + DB 184,10,215,35,59 ; mov $0x3b23d70a,%eax + DB 197,121,110,240 ; vmovd %eax,%xmm14 + DB 196,67,121,4,246,0 ; vpermilps $0x0,%xmm14,%xmm14 + DB 196,67,13,24,246,1 ; vinsertf128 $0x1,%xmm14,%ymm14,%ymm14 + DB 196,65,44,89,213 ; vmulps %ymm13,%ymm10,%ymm10 + DB 196,65,12,88,210 ; vaddps %ymm10,%ymm14,%ymm10 + DB 184,174,71,97,61 ; mov $0x3d6147ae,%eax + DB 197,121,110,232 ; vmovd %eax,%xmm13 + DB 196,67,121,4,237,0 ; vpermilps $0x0,%xmm13,%xmm13 + DB 196,67,21,24,237,1 ; vinsertf128 $0x1,%xmm13,%ymm13,%ymm13 + DB 196,193,124,194,197,1 ; vcmpltps %ymm13,%ymm0,%ymm0 + DB 196,195,45,74,193,0 ; vblendvps %ymm0,%ymm9,%ymm10,%ymm0 + DB 197,60,89,201 ; vmulps %ymm1,%ymm8,%ymm9 + DB 197,116,89,209 ; vmulps %ymm1,%ymm1,%ymm10 + DB 197,36,89,249 ; vmulps %ymm1,%ymm11,%ymm15 + DB 196,65,28,88,255 ; vaddps %ymm15,%ymm12,%ymm15 + DB 196,65,44,89,215 ; vmulps %ymm15,%ymm10,%ymm10 + DB 196,65,12,88,210 ; vaddps %ymm10,%ymm14,%ymm10 + DB 196,193,116,194,205,1 ; vcmpltps %ymm13,%ymm1,%ymm1 + DB 196,195,45,74,201,16 ; vblendvps %ymm1,%ymm9,%ymm10,%ymm1 + DB 197,60,89,194 ; vmulps %ymm2,%ymm8,%ymm8 + DB 197,108,89,202 ; vmulps %ymm2,%ymm2,%ymm9 + DB 197,36,89,210 ; vmulps %ymm2,%ymm11,%ymm10 + DB 196,65,28,88,210 ; vaddps %ymm10,%ymm12,%ymm10 + DB 196,65,52,89,202 ; vmulps %ymm10,%ymm9,%ymm9 + DB 196,65,12,88,201 ; vaddps %ymm9,%ymm14,%ymm9 + DB 196,193,108,194,213,1 ; vcmpltps %ymm13,%ymm2,%ymm2 + DB 196,195,53,74,208,32 ; vblendvps %ymm2,%ymm8,%ymm9,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_to_srgb_avx +_sk_to_srgb_avx LABEL PROC + DB 197,124,82,192 ; vrsqrtps %ymm0,%ymm8 + DB 196,65,124,83,232 ; vrcpps %ymm8,%ymm13 + DB 196,65,124,82,240 ; vrsqrtps %ymm8,%ymm14 + DB 184,41,92,71,65 ; mov $0x41475c29,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,89,224 ; vmulps %ymm0,%ymm8,%ymm12 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 196,67,121,4,201,0 ; vpermilps $0x0,%xmm9,%xmm9 + DB 196,67,53,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + DB 184,194,135,210,62 ; mov $0x3ed287c2,%eax + DB 197,121,110,208 ; vmovd %eax,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 184,206,111,48,63 ; mov $0x3f306fce,%eax + DB 197,121,110,216 ; vmovd %eax,%xmm11 + DB 196,67,121,4,219,0 ; vpermilps $0x0,%xmm11,%xmm11 + DB 196,67,37,24,219,1 ; vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + DB 184,168,87,202,61 ; mov $0x3dca57a8,%eax + DB 53,0,0,0,128 ; xor $0x80000000,%eax + DB 197,121,110,248 ; vmovd %eax,%xmm15 + DB 196,67,121,4,255,0 ; vpermilps $0x0,%xmm15,%xmm15 + DB 196,67,5,24,255,1 ; vinsertf128 $0x1,%xmm15,%ymm15,%ymm15 + DB 196,65,20,89,235 ; vmulps %ymm11,%ymm13,%ymm13 + DB 196,65,20,88,239 ; vaddps %ymm15,%ymm13,%ymm13 + DB 196,65,12,89,242 ; vmulps %ymm10,%ymm14,%ymm14 + DB 196,65,12,88,237 ; vaddps %ymm13,%ymm14,%ymm13 + DB 196,65,52,93,237 ; vminps %ymm13,%ymm9,%ymm13 + DB 184,4,231,140,59 ; mov $0x3b8ce704,%eax + DB 197,121,110,240 ; vmovd %eax,%xmm14 + DB 196,67,121,4,246,0 ; vpermilps $0x0,%xmm14,%xmm14 + DB 196,67,13,24,246,1 ; vinsertf128 $0x1,%xmm14,%ymm14,%ymm14 + DB 196,193,124,194,198,1 ; vcmpltps %ymm14,%ymm0,%ymm0 + DB 196,195,21,74,196,0 ; vblendvps %ymm0,%ymm12,%ymm13,%ymm0 + DB 197,124,82,225 ; vrsqrtps %ymm1,%ymm12 + DB 196,65,124,83,236 ; vrcpps %ymm12,%ymm13 + DB 196,65,124,82,228 ; vrsqrtps %ymm12,%ymm12 + DB 196,65,36,89,237 ; vmulps %ymm13,%ymm11,%ymm13 + DB 196,65,4,88,237 ; vaddps %ymm13,%ymm15,%ymm13 + DB 196,65,44,89,228 ; vmulps %ymm12,%ymm10,%ymm12 + DB 196,65,28,88,229 ; vaddps %ymm13,%ymm12,%ymm12 + DB 197,60,89,233 ; vmulps %ymm1,%ymm8,%ymm13 + DB 196,65,52,93,228 ; vminps %ymm12,%ymm9,%ymm12 + DB 196,193,116,194,206,1 ; vcmpltps %ymm14,%ymm1,%ymm1 + DB 196,195,29,74,205,16 ; vblendvps %ymm1,%ymm13,%ymm12,%ymm1 + DB 197,124,82,226 ; vrsqrtps %ymm2,%ymm12 + DB 196,65,124,83,236 ; vrcpps %ymm12,%ymm13 + DB 196,65,36,89,221 ; vmulps %ymm13,%ymm11,%ymm11 + DB 196,65,4,88,219 ; vaddps %ymm11,%ymm15,%ymm11 + DB 196,65,124,82,228 ; vrsqrtps %ymm12,%ymm12 + DB 196,65,44,89,212 ; vmulps %ymm12,%ymm10,%ymm10 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 196,65,52,93,202 ; vminps %ymm10,%ymm9,%ymm9 + DB 197,60,89,194 ; vmulps %ymm2,%ymm8,%ymm8 + DB 196,193,108,194,214,1 ; vcmpltps %ymm14,%ymm2,%ymm2 + DB 196,195,53,74,208,32 ; vblendvps %ymm2,%ymm8,%ymm9,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_from_2dot2_avx +_sk_from_2dot2_avx LABEL PROC + DB 197,124,82,192 ; vrsqrtps %ymm0,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,200 ; vrsqrtps %ymm8,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 197,252,89,192 ; vmulps %ymm0,%ymm0,%ymm0 + DB 196,65,60,89,208 ; vmulps %ymm8,%ymm8,%ymm10 + DB 196,65,60,89,194 ; vmulps %ymm10,%ymm8,%ymm8 + DB 196,193,124,89,192 ; vmulps %ymm8,%ymm0,%ymm0 + DB 197,180,89,192 ; vmulps %ymm0,%ymm9,%ymm0 + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 196,193,124,95,192 ; vmaxps %ymm8,%ymm0,%ymm0 + DB 197,124,82,201 ; vrsqrtps %ymm1,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,209 ; vrsqrtps %ymm9,%ymm10 + DB 196,65,124,82,210 ; vrsqrtps %ymm10,%ymm10 + DB 197,244,89,201 ; vmulps %ymm1,%ymm1,%ymm1 + DB 196,65,52,89,217 ; vmulps %ymm9,%ymm9,%ymm11 + DB 196,65,52,89,203 ; vmulps %ymm11,%ymm9,%ymm9 + DB 196,193,116,89,201 ; vmulps %ymm9,%ymm1,%ymm1 + DB 197,172,89,201 ; vmulps %ymm1,%ymm10,%ymm1 + DB 196,193,116,95,200 ; vmaxps %ymm8,%ymm1,%ymm1 + DB 197,124,82,202 ; vrsqrtps %ymm2,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,209 ; vrsqrtps %ymm9,%ymm10 + DB 196,65,124,82,210 ; vrsqrtps %ymm10,%ymm10 + DB 197,236,89,210 ; vmulps %ymm2,%ymm2,%ymm2 + DB 196,65,52,89,217 ; vmulps %ymm9,%ymm9,%ymm11 + DB 196,65,52,89,203 ; vmulps %ymm11,%ymm9,%ymm9 + DB 196,193,108,89,209 ; vmulps %ymm9,%ymm2,%ymm2 + DB 197,172,89,210 ; vmulps %ymm2,%ymm10,%ymm2 + DB 196,193,108,95,208 ; vmaxps %ymm8,%ymm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_to_2dot2_avx +_sk_to_2dot2_avx LABEL PROC + DB 197,252,82,192 ; vrsqrtps %ymm0,%ymm0 + DB 197,124,82,192 ; vrsqrtps %ymm0,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,192 ; vrsqrtps %ymm8,%ymm8 + DB 196,65,124,82,200 ; vrsqrtps %ymm8,%ymm9 + DB 197,252,83,192 ; vrcpps %ymm0,%ymm0 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 196,65,124,83,193 ; vrcpps %ymm9,%ymm8 + DB 196,193,124,89,192 ; vmulps %ymm8,%ymm0,%ymm0 + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 196,193,124,95,192 ; vmaxps %ymm8,%ymm0,%ymm0 + DB 197,252,82,201 ; vrsqrtps %ymm1,%ymm1 + DB 197,124,82,201 ; vrsqrtps %ymm1,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,209 ; vrsqrtps %ymm9,%ymm10 + DB 197,252,83,201 ; vrcpps %ymm1,%ymm1 + DB 197,180,89,201 ; vmulps %ymm1,%ymm9,%ymm1 + DB 196,65,124,83,202 ; vrcpps %ymm10,%ymm9 + DB 196,193,116,89,201 ; vmulps %ymm9,%ymm1,%ymm1 + DB 196,193,116,95,200 ; vmaxps %ymm8,%ymm1,%ymm1 + DB 197,252,82,210 ; vrsqrtps %ymm2,%ymm2 + DB 197,124,82,202 ; vrsqrtps %ymm2,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,201 ; vrsqrtps %ymm9,%ymm9 + DB 196,65,124,82,209 ; vrsqrtps %ymm9,%ymm10 + DB 197,252,83,210 ; vrcpps %ymm2,%ymm2 + DB 197,180,89,210 ; vmulps %ymm2,%ymm9,%ymm2 + DB 196,65,124,83,202 ; vrcpps %ymm10,%ymm9 + DB 196,193,108,89,209 ; vmulps %ymm9,%ymm2,%ymm2 + DB 196,193,108,95,208 ; vmaxps %ymm8,%ymm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_rgb_to_hsl_avx +_sk_rgb_to_hsl_avx LABEL PROC + DB 197,124,95,193 ; vmaxps %ymm1,%ymm0,%ymm8 + DB 197,60,95,194 ; vmaxps %ymm2,%ymm8,%ymm8 + DB 197,124,93,201 ; vminps %ymm1,%ymm0,%ymm9 + DB 197,52,93,202 ; vminps %ymm2,%ymm9,%ymm9 + DB 196,65,60,92,209 ; vsubps %ymm9,%ymm8,%ymm10 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,121,110,216 ; vmovd %eax,%xmm11 + DB 196,67,121,4,219,0 ; vpermilps $0x0,%xmm11,%xmm11 + DB 196,67,37,24,219,1 ; vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + DB 196,65,36,94,218 ; vdivps %ymm10,%ymm11,%ymm11 + DB 65,184,171,170,42,62 ; mov $0x3e2aaaab,%r8d + DB 197,116,92,226 ; vsubps %ymm2,%ymm1,%ymm12 + DB 196,65,28,89,227 ; vmulps %ymm11,%ymm12,%ymm12 + DB 65,185,0,0,192,64 ; mov $0x40c00000,%r9d + DB 197,108,92,232 ; vsubps %ymm0,%ymm2,%ymm13 + DB 196,65,20,89,235 ; vmulps %ymm11,%ymm13,%ymm13 + DB 65,186,0,0,0,64 ; mov $0x40000000,%r10d + DB 197,124,92,241 ; vsubps %ymm1,%ymm0,%ymm14 + DB 196,65,12,89,219 ; vmulps %ymm11,%ymm14,%ymm11 + DB 184,0,0,128,64 ; mov $0x40800000,%eax + DB 197,121,110,240 ; vmovd %eax,%xmm14 + DB 196,67,121,4,246,0 ; vpermilps $0x0,%xmm14,%xmm14 + DB 196,67,13,24,246,1 ; vinsertf128 $0x1,%xmm14,%ymm14,%ymm14 + DB 196,65,36,88,222 ; vaddps %ymm14,%ymm11,%ymm11 + DB 196,65,121,110,242 ; vmovd %r10d,%xmm14 + DB 197,244,194,210,1 ; vcmpltps %ymm2,%ymm1,%ymm2 + DB 197,188,194,201,0 ; vcmpeqps %ymm1,%ymm8,%ymm1 + DB 196,67,121,4,246,0 ; vpermilps $0x0,%xmm14,%xmm14 + DB 196,67,13,24,246,1 ; vinsertf128 $0x1,%xmm14,%ymm14,%ymm14 + DB 196,65,20,88,238 ; vaddps %ymm14,%ymm13,%ymm13 + DB 196,67,37,74,221,16 ; vblendvps %ymm1,%ymm13,%ymm11,%ymm11 + DB 196,193,121,110,201 ; vmovd %r9d,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 196,65,20,87,237 ; vxorps %ymm13,%ymm13,%ymm13 + DB 196,227,21,74,201,32 ; vblendvps %ymm2,%ymm1,%ymm13,%ymm1 + DB 196,193,116,88,204 ; vaddps %ymm12,%ymm1,%ymm1 + DB 184,0,0,0,63 ; mov $0x3f000000,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 197,188,194,192,0 ; vcmpeqps %ymm0,%ymm8,%ymm0 + DB 196,227,37,74,193,0 ; vblendvps %ymm0,%ymm1,%ymm11,%ymm0 + DB 196,193,60,88,201 ; vaddps %ymm9,%ymm8,%ymm1 + DB 196,227,121,4,210,0 ; vpermilps $0x0,%xmm2,%xmm2 + DB 196,99,109,24,218,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm11 + DB 196,193,116,89,211 ; vmulps %ymm11,%ymm1,%ymm2 + DB 197,36,194,218,1 ; vcmpltps %ymm2,%ymm11,%ymm11 + DB 196,65,12,92,224 ; vsubps %ymm8,%ymm14,%ymm12 + DB 196,65,28,92,225 ; vsubps %ymm9,%ymm12,%ymm12 + DB 196,195,117,74,204,176 ; vblendvps %ymm11,%ymm12,%ymm1,%ymm1 + DB 196,65,60,194,193,0 ; vcmpeqps %ymm9,%ymm8,%ymm8 + DB 197,172,94,201 ; vdivps %ymm1,%ymm10,%ymm1 + DB 196,67,125,74,205,128 ; vblendvps %ymm8,%ymm13,%ymm0,%ymm9 + DB 196,195,117,74,205,128 ; vblendvps %ymm8,%ymm13,%ymm1,%ymm1 + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 196,193,124,89,193 ; vmulps %ymm9,%ymm0,%ymm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_hsl_to_rgb_avx +_sk_hsl_to_rgb_avx LABEL PROC + DB 72,129,236,184,0,0,0 ; sub $0xb8,%rsp + DB 197,252,17,188,36,128,0,0,0 ; vmovups %ymm7,0x80(%rsp) + DB 197,252,17,116,36,96 ; vmovups %ymm6,0x60(%rsp) + DB 197,252,17,108,36,64 ; vmovups %ymm5,0x40(%rsp) + DB 197,252,17,100,36,32 ; vmovups %ymm4,0x20(%rsp) + DB 197,252,17,28,36 ; vmovups %ymm3,(%rsp) + DB 197,252,40,226 ; vmovaps %ymm2,%ymm4 + DB 197,252,40,233 ; vmovaps %ymm1,%ymm5 + DB 197,252,40,216 ; vmovaps %ymm0,%ymm3 + DB 184,0,0,0,63 ; mov $0x3f000000,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,99,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm8 + DB 196,193,92,194,192,1 ; vcmpltps %ymm8,%ymm4,%ymm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,227,121,4,210,0 ; vpermilps $0x0,%xmm2,%xmm2 + DB 196,99,109,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm10 + DB 197,172,88,213 ; vaddps %ymm5,%ymm10,%ymm2 + DB 197,236,89,212 ; vmulps %ymm4,%ymm2,%ymm2 + DB 197,84,88,204 ; vaddps %ymm4,%ymm5,%ymm9 + DB 197,84,89,220 ; vmulps %ymm4,%ymm5,%ymm11 + DB 196,65,52,92,203 ; vsubps %ymm11,%ymm9,%ymm9 + DB 196,99,53,74,202,0 ; vblendvps %ymm0,%ymm2,%ymm9,%ymm9 + DB 65,184,0,0,0,64 ; mov $0x40000000,%r8d + DB 184,171,170,170,62 ; mov $0x3eaaaaab,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,99,125,24,224,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm12 + DB 197,28,88,251 ; vaddps %ymm3,%ymm12,%ymm15 + DB 184,0,0,0,0 ; mov $0x0,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,99,125,24,232,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm13 + DB 196,193,44,194,199,1 ; vcmpltps %ymm15,%ymm10,%ymm0 + DB 196,193,4,92,210 ; vsubps %ymm10,%ymm15,%ymm2 + DB 196,227,5,74,194,0 ; vblendvps %ymm0,%ymm2,%ymm15,%ymm0 + DB 196,193,4,194,213,1 ; vcmpltps %ymm13,%ymm15,%ymm2 + DB 196,65,44,88,223 ; vaddps %ymm15,%ymm10,%ymm11 + DB 196,195,125,74,203,32 ; vblendvps %ymm2,%ymm11,%ymm0,%ymm1 + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,252,89,196 ; vmulps %ymm4,%ymm0,%ymm0 + DB 196,65,124,92,217 ; vsubps %ymm9,%ymm0,%ymm11 + DB 65,184,171,170,42,62 ; mov $0x3e2aaaab,%r8d + DB 184,0,0,192,64 ; mov $0x40c00000,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 196,193,52,92,211 ; vsubps %ymm11,%ymm9,%ymm2 + DB 197,108,89,240 ; vmulps %ymm0,%ymm2,%ymm14 + DB 184,171,170,42,63 ; mov $0x3f2aaaab,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,252,92,209 ; vsubps %ymm1,%ymm0,%ymm2 + DB 197,140,89,210 ; vmulps %ymm2,%ymm14,%ymm2 + DB 197,164,88,210 ; vaddps %ymm2,%ymm11,%ymm2 + DB 197,244,194,248,1 ; vcmpltps %ymm0,%ymm1,%ymm7 + DB 196,227,37,74,210,112 ; vblendvps %ymm7,%ymm2,%ymm11,%ymm2 + DB 196,193,116,194,248,1 ; vcmpltps %ymm8,%ymm1,%ymm7 + DB 196,195,109,74,249,112 ; vblendvps %ymm7,%ymm9,%ymm2,%ymm7 + DB 196,193,121,110,208 ; vmovd %r8d,%xmm2 + DB 196,227,121,4,210,0 ; vpermilps $0x0,%xmm2,%xmm2 + DB 196,227,109,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + DB 197,244,194,202,1 ; vcmpltps %ymm2,%ymm1,%ymm1 + DB 196,65,4,89,254 ; vmulps %ymm14,%ymm15,%ymm15 + DB 196,65,36,88,255 ; vaddps %ymm15,%ymm11,%ymm15 + DB 196,67,69,74,255,16 ; vblendvps %ymm1,%ymm15,%ymm7,%ymm15 + DB 197,172,194,203,1 ; vcmpltps %ymm3,%ymm10,%ymm1 + DB 196,193,100,92,250 ; vsubps %ymm10,%ymm3,%ymm7 + DB 196,227,101,74,207,16 ; vblendvps %ymm1,%ymm7,%ymm3,%ymm1 + DB 196,193,100,194,253,1 ; vcmpltps %ymm13,%ymm3,%ymm7 + DB 197,172,88,243 ; vaddps %ymm3,%ymm10,%ymm6 + DB 196,227,117,74,206,112 ; vblendvps %ymm7,%ymm6,%ymm1,%ymm1 + DB 197,252,92,241 ; vsubps %ymm1,%ymm0,%ymm6 + DB 197,140,89,246 ; vmulps %ymm6,%ymm14,%ymm6 + DB 197,164,88,246 ; vaddps %ymm6,%ymm11,%ymm6 + DB 197,244,194,248,1 ; vcmpltps %ymm0,%ymm1,%ymm7 + DB 196,227,37,74,246,112 ; vblendvps %ymm7,%ymm6,%ymm11,%ymm6 + DB 196,193,116,194,248,1 ; vcmpltps %ymm8,%ymm1,%ymm7 + DB 196,195,77,74,241,112 ; vblendvps %ymm7,%ymm9,%ymm6,%ymm6 + DB 197,244,194,202,1 ; vcmpltps %ymm2,%ymm1,%ymm1 + DB 197,140,89,251 ; vmulps %ymm3,%ymm14,%ymm7 + DB 197,164,88,255 ; vaddps %ymm7,%ymm11,%ymm7 + DB 196,227,77,74,207,16 ; vblendvps %ymm1,%ymm7,%ymm6,%ymm1 + DB 196,193,100,92,220 ; vsubps %ymm12,%ymm3,%ymm3 + DB 197,172,194,243,1 ; vcmpltps %ymm3,%ymm10,%ymm6 + DB 196,193,100,92,250 ; vsubps %ymm10,%ymm3,%ymm7 + DB 196,227,101,74,247,96 ; vblendvps %ymm6,%ymm7,%ymm3,%ymm6 + DB 196,193,100,194,253,1 ; vcmpltps %ymm13,%ymm3,%ymm7 + DB 197,44,88,211 ; vaddps %ymm3,%ymm10,%ymm10 + DB 196,195,77,74,242,112 ; vblendvps %ymm7,%ymm10,%ymm6,%ymm6 + DB 197,204,194,248,1 ; vcmpltps %ymm0,%ymm6,%ymm7 + DB 197,252,92,198 ; vsubps %ymm6,%ymm0,%ymm0 + DB 197,140,89,192 ; vmulps %ymm0,%ymm14,%ymm0 + DB 197,164,88,192 ; vaddps %ymm0,%ymm11,%ymm0 + DB 196,227,37,74,192,112 ; vblendvps %ymm7,%ymm0,%ymm11,%ymm0 + DB 196,193,76,194,248,1 ; vcmpltps %ymm8,%ymm6,%ymm7 + DB 196,195,125,74,193,112 ; vblendvps %ymm7,%ymm9,%ymm0,%ymm0 + DB 197,204,194,210,1 ; vcmpltps %ymm2,%ymm6,%ymm2 + DB 196,193,100,89,222 ; vmulps %ymm14,%ymm3,%ymm3 + DB 197,164,88,219 ; vaddps %ymm3,%ymm11,%ymm3 + DB 196,227,125,74,211,32 ; vblendvps %ymm2,%ymm3,%ymm0,%ymm2 + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,212,194,216,0 ; vcmpeqps %ymm0,%ymm5,%ymm3 + DB 196,227,5,74,196,48 ; vblendvps %ymm3,%ymm4,%ymm15,%ymm0 + DB 196,227,117,74,204,48 ; vblendvps %ymm3,%ymm4,%ymm1,%ymm1 + DB 196,227,109,74,212,48 ; vblendvps %ymm3,%ymm4,%ymm2,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,16,28,36 ; vmovups (%rsp),%ymm3 + DB 197,252,16,100,36,32 ; vmovups 0x20(%rsp),%ymm4 + DB 197,252,16,108,36,64 ; vmovups 0x40(%rsp),%ymm5 + DB 197,252,16,116,36,96 ; vmovups 0x60(%rsp),%ymm6 + DB 197,252,16,188,36,128,0,0,0 ; vmovups 0x80(%rsp),%ymm7 + DB 72,129,196,184,0,0,0 ; add $0xb8,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_scale_1_float_avx +_sk_scale_1_float_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_scale_u8_avx +_sk_scale_u8_avx LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,1,248 ; add %rdi,%rax + DB 77,133,192 ; test %r8,%r8 + DB 117,80 ; jne 14ff <_sk_scale_u8_avx+0x60> + DB 197,122,126,0 ; vmovq (%rax),%xmm8 + DB 196,66,121,49,200 ; vpmovzxbd %xmm8,%xmm9 + DB 196,67,121,4,192,229 ; vpermilps $0xe5,%xmm8,%xmm8 + DB 196,66,121,49,192 ; vpmovzxbd %xmm8,%xmm8 + DB 196,67,53,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm9,%ymm8 + DB 196,65,124,91,192 ; vcvtdq2ps %ymm8,%ymm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 196,67,121,4,201,0 ; vpermilps $0x0,%xmm9,%xmm9 + DB 196,67,53,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + DB 196,65,60,89,193 ; vmulps %ymm9,%ymm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,137,193 ; mov %r8,%rcx + DB 255,224 ; jmpq *%rax + DB 49,201 ; xor %ecx,%ecx + DB 77,137,194 ; mov %r8,%r10 + DB 69,49,201 ; xor %r9d,%r9d + DB 68,15,182,24 ; movzbl (%rax),%r11d + DB 72,255,192 ; inc %rax + DB 73,211,227 ; shl %cl,%r11 + DB 77,9,217 ; or %r11,%r9 + DB 72,131,193,8 ; add $0x8,%rcx + DB 73,255,202 ; dec %r10 + DB 117,234 ; jne 1507 <_sk_scale_u8_avx+0x68> + DB 196,65,249,110,193 ; vmovq %r9,%xmm8 + DB 235,143 ; jmp 14b3 <_sk_scale_u8_avx+0x14> + +PUBLIC _sk_lerp_1_float_avx +_sk_lerp_1_float_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 197,252,92,196 ; vsubps %ymm4,%ymm0,%ymm0 + DB 196,193,124,89,192 ; vmulps %ymm8,%ymm0,%ymm0 + DB 197,252,88,196 ; vaddps %ymm4,%ymm0,%ymm0 + DB 197,244,92,205 ; vsubps %ymm5,%ymm1,%ymm1 + DB 196,193,116,89,200 ; vmulps %ymm8,%ymm1,%ymm1 + DB 197,244,88,205 ; vaddps %ymm5,%ymm1,%ymm1 + DB 197,236,92,214 ; vsubps %ymm6,%ymm2,%ymm2 + DB 196,193,108,89,208 ; vmulps %ymm8,%ymm2,%ymm2 + DB 197,236,88,214 ; vaddps %ymm6,%ymm2,%ymm2 + DB 197,228,92,223 ; vsubps %ymm7,%ymm3,%ymm3 + DB 196,193,100,89,216 ; vmulps %ymm8,%ymm3,%ymm3 + DB 197,228,88,223 ; vaddps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lerp_u8_avx +_sk_lerp_u8_avx LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,1,248 ; add %rdi,%rax + DB 77,133,192 ; test %r8,%r8 + DB 117,116 ; jne 15e7 <_sk_lerp_u8_avx+0x84> + DB 197,122,126,0 ; vmovq (%rax),%xmm8 + DB 196,66,121,49,200 ; vpmovzxbd %xmm8,%xmm9 + DB 196,67,121,4,192,229 ; vpermilps $0xe5,%xmm8,%xmm8 + DB 196,66,121,49,192 ; vpmovzxbd %xmm8,%xmm8 + DB 196,67,53,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm9,%ymm8 + DB 196,65,124,91,192 ; vcvtdq2ps %ymm8,%ymm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,121,110,200 ; vmovd %eax,%xmm9 + DB 196,67,121,4,201,0 ; vpermilps $0x0,%xmm9,%xmm9 + DB 196,67,53,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + DB 196,65,60,89,193 ; vmulps %ymm9,%ymm8,%ymm8 + DB 197,252,92,196 ; vsubps %ymm4,%ymm0,%ymm0 + DB 196,193,124,89,192 ; vmulps %ymm8,%ymm0,%ymm0 + DB 197,252,88,196 ; vaddps %ymm4,%ymm0,%ymm0 + DB 197,244,92,205 ; vsubps %ymm5,%ymm1,%ymm1 + DB 196,193,116,89,200 ; vmulps %ymm8,%ymm1,%ymm1 + DB 197,244,88,205 ; vaddps %ymm5,%ymm1,%ymm1 + DB 197,236,92,214 ; vsubps %ymm6,%ymm2,%ymm2 + DB 196,193,108,89,208 ; vmulps %ymm8,%ymm2,%ymm2 + DB 197,236,88,214 ; vaddps %ymm6,%ymm2,%ymm2 + DB 197,228,92,223 ; vsubps %ymm7,%ymm3,%ymm3 + DB 196,193,100,89,216 ; vmulps %ymm8,%ymm3,%ymm3 + DB 197,228,88,223 ; vaddps %ymm7,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,137,193 ; mov %r8,%rcx + DB 255,224 ; jmpq *%rax + DB 49,201 ; xor %ecx,%ecx + DB 77,137,194 ; mov %r8,%r10 + DB 69,49,201 ; xor %r9d,%r9d + DB 68,15,182,24 ; movzbl (%rax),%r11d + DB 72,255,192 ; inc %rax + DB 73,211,227 ; shl %cl,%r11 + DB 77,9,217 ; or %r11,%r9 + DB 72,131,193,8 ; add $0x8,%rcx + DB 73,255,202 ; dec %r10 + DB 117,234 ; jne 15ef <_sk_lerp_u8_avx+0x8c> + DB 196,65,249,110,193 ; vmovq %r9,%xmm8 + DB 233,104,255,255,255 ; jmpq 1577 <_sk_lerp_u8_avx+0x14> + +PUBLIC _sk_lerp_565_avx +_sk_lerp_565_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,16 ; mov (%rax),%r10 + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,250,0,0,0 ; jne 1717 <_sk_lerp_565_avx+0x108> + DB 196,65,122,111,4,122 ; vmovdqu (%r10,%rdi,2),%xmm8 + DB 197,225,239,219 ; vpxor %xmm3,%xmm3,%xmm3 + DB 197,185,105,219 ; vpunpckhwd %xmm3,%xmm8,%xmm3 + DB 196,66,121,51,192 ; vpmovzxwd %xmm8,%xmm8 + DB 196,99,61,24,195,1 ; vinsertf128 $0x1,%xmm3,%ymm8,%ymm8 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 197,249,112,219,0 ; vpshufd $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 196,193,100,84,216 ; vandps %ymm8,%ymm3,%ymm3 + DB 197,124,91,203 ; vcvtdq2ps %ymm3,%ymm9 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,52,89,203 ; vmulps %ymm3,%ymm9,%ymm9 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 197,249,112,219,0 ; vpshufd $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 196,193,100,84,216 ; vandps %ymm8,%ymm3,%ymm3 + DB 197,124,91,211 ; vcvtdq2ps %ymm3,%ymm10 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,44,89,211 ; vmulps %ymm3,%ymm10,%ymm10 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 197,249,112,219,0 ; vpshufd $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 196,193,100,84,216 ; vandps %ymm8,%ymm3,%ymm3 + DB 197,124,91,195 ; vcvtdq2ps %ymm3,%ymm8 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 197,252,92,196 ; vsubps %ymm4,%ymm0,%ymm0 + DB 196,193,124,89,193 ; vmulps %ymm9,%ymm0,%ymm0 + DB 197,252,88,196 ; vaddps %ymm4,%ymm0,%ymm0 + DB 197,244,92,205 ; vsubps %ymm5,%ymm1,%ymm1 + DB 196,193,116,89,202 ; vmulps %ymm10,%ymm1,%ymm1 + DB 197,244,88,205 ; vaddps %ymm5,%ymm1,%ymm1 + DB 197,236,92,214 ; vsubps %ymm6,%ymm2,%ymm2 + DB 197,236,89,211 ; vmulps %ymm3,%ymm2,%ymm2 + DB 197,236,88,214 ; vaddps %ymm6,%ymm2,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 196,65,57,239,192 ; vpxor %xmm8,%xmm8,%xmm8 + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 15,135,243,254,255,255 ; ja 1623 <_sk_lerp_565_avx+0x14> + DB 69,15,182,192 ; movzbl %r8b,%r8d + DB 76,141,13,73,0,0,0 ; lea 0x49(%rip),%r9 # 1784 <_sk_lerp_565_avx+0x175> + DB 75,99,4,129 ; movslq (%r9,%r8,4),%rax + DB 76,1,200 ; add %r9,%rax + DB 255,224 ; jmpq *%rax + DB 197,225,239,219 ; vpxor %xmm3,%xmm3,%xmm3 + DB 196,65,97,196,68,122,12,6 ; vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm3,%xmm8 + DB 196,65,57,196,68,122,10,5 ; vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm8,%xmm8 + DB 196,65,57,196,68,122,8,4 ; vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm8,%xmm8 + DB 196,65,57,196,68,122,6,3 ; vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm8,%xmm8 + DB 196,65,57,196,68,122,4,2 ; vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm8,%xmm8 + DB 196,65,57,196,68,122,2,1 ; vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm8,%xmm8 + DB 196,65,57,196,4,122,0 ; vpinsrw $0x0,(%r10,%rdi,2),%xmm8,%xmm8 + DB 233,159,254,255,255 ; jmpq 1623 <_sk_lerp_565_avx+0x14> + DB 244 ; hlt + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 236 ; in (%dx),%al + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,228 ; jmpq *%rsp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 220,255 ; fdivr %st,%st(7) + DB 255 ; (bad) + DB 255,212 ; callq *%rsp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,204 ; dec %esp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,192 ; inc %eax + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_load_tables_avx +_sk_load_tables_avx LABEL PROC + DB 85 ; push %rbp + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,56,2,0,0 ; jne 19f0 <_sk_load_tables_avx+0x250> + DB 196,65,124,16,4,184 ; vmovups (%r8,%rdi,4),%ymm8 + DB 187,255,0,0,0 ; mov $0xff,%ebx + DB 197,249,110,195 ; vmovd %ebx,%xmm0 + DB 197,249,112,192,0 ; vpshufd $0x0,%xmm0,%xmm0 + DB 196,99,125,24,200,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm9 + DB 196,193,52,84,192 ; vandps %ymm8,%ymm9,%ymm0 + DB 196,193,249,126,193 ; vmovq %xmm0,%r9 + DB 69,137,203 ; mov %r9d,%r11d + DB 196,195,249,22,194,1 ; vpextrq $0x1,%xmm0,%r10 + DB 69,137,214 ; mov %r10d,%r14d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 73,193,233,32 ; shr $0x20,%r9 + DB 196,227,125,25,192,1 ; vextractf128 $0x1,%ymm0,%xmm0 + DB 196,193,249,126,196 ; vmovq %xmm0,%r12 + DB 69,137,231 ; mov %r12d,%r15d + DB 196,227,249,22,195,1 ; vpextrq $0x1,%xmm0,%rbx + DB 65,137,221 ; mov %ebx,%r13d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 73,193,236,32 ; shr $0x20,%r12 + DB 72,139,104,8 ; mov 0x8(%rax),%rbp + DB 76,139,64,16 ; mov 0x10(%rax),%r8 + DB 196,161,122,16,68,189,0 ; vmovss 0x0(%rbp,%r15,4),%xmm0 + DB 196,163,121,33,68,165,0,16 ; vinsertps $0x10,0x0(%rbp,%r12,4),%xmm0,%xmm0 + DB 196,161,122,16,76,173,0 ; vmovss 0x0(%rbp,%r13,4),%xmm1 + DB 196,227,121,33,193,32 ; vinsertps $0x20,%xmm1,%xmm0,%xmm0 + DB 197,250,16,76,157,0 ; vmovss 0x0(%rbp,%rbx,4),%xmm1 + DB 196,227,121,33,193,48 ; vinsertps $0x30,%xmm1,%xmm0,%xmm0 + DB 196,161,122,16,76,157,0 ; vmovss 0x0(%rbp,%r11,4),%xmm1 + DB 196,163,113,33,76,141,0,16 ; vinsertps $0x10,0x0(%rbp,%r9,4),%xmm1,%xmm1 + DB 196,161,122,16,92,181,0 ; vmovss 0x0(%rbp,%r14,4),%xmm3 + DB 196,227,113,33,203,32 ; vinsertps $0x20,%xmm3,%xmm1,%xmm1 + DB 196,161,122,16,92,149,0 ; vmovss 0x0(%rbp,%r10,4),%xmm3 + DB 196,227,113,33,203,48 ; vinsertps $0x30,%xmm3,%xmm1,%xmm1 + DB 196,227,117,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm1,%ymm0 + DB 196,193,113,114,208,8 ; vpsrld $0x8,%xmm8,%xmm1 + DB 196,67,125,25,194,1 ; vextractf128 $0x1,%ymm8,%xmm10 + DB 196,193,105,114,210,8 ; vpsrld $0x8,%xmm10,%xmm2 + DB 196,227,117,24,202,1 ; vinsertf128 $0x1,%xmm2,%ymm1,%ymm1 + DB 197,180,84,201 ; vandps %ymm1,%ymm9,%ymm1 + DB 196,193,249,126,201 ; vmovq %xmm1,%r9 + DB 69,137,203 ; mov %r9d,%r11d + DB 196,195,249,22,202,1 ; vpextrq $0x1,%xmm1,%r10 + DB 69,137,214 ; mov %r10d,%r14d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 73,193,233,32 ; shr $0x20,%r9 + DB 196,227,125,25,201,1 ; vextractf128 $0x1,%ymm1,%xmm1 + DB 196,225,249,126,205 ; vmovq %xmm1,%rbp + DB 65,137,239 ; mov %ebp,%r15d + DB 196,227,249,22,203,1 ; vpextrq $0x1,%xmm1,%rbx + DB 65,137,220 ; mov %ebx,%r12d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,129,122,16,12,184 ; vmovss (%r8,%r15,4),%xmm1 + DB 196,195,113,33,12,168,16 ; vinsertps $0x10,(%r8,%rbp,4),%xmm1,%xmm1 + DB 196,129,122,16,20,160 ; vmovss (%r8,%r12,4),%xmm2 + DB 196,227,113,33,202,32 ; vinsertps $0x20,%xmm2,%xmm1,%xmm1 + DB 196,193,122,16,20,152 ; vmovss (%r8,%rbx,4),%xmm2 + DB 196,227,113,33,202,48 ; vinsertps $0x30,%xmm2,%xmm1,%xmm1 + DB 196,129,122,16,20,152 ; vmovss (%r8,%r11,4),%xmm2 + DB 196,131,105,33,20,136,16 ; vinsertps $0x10,(%r8,%r9,4),%xmm2,%xmm2 + DB 196,129,122,16,28,176 ; vmovss (%r8,%r14,4),%xmm3 + DB 196,227,105,33,211,32 ; vinsertps $0x20,%xmm3,%xmm2,%xmm2 + DB 196,129,122,16,28,144 ; vmovss (%r8,%r10,4),%xmm3 + DB 196,227,105,33,211,48 ; vinsertps $0x30,%xmm3,%xmm2,%xmm2 + DB 196,227,109,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm2,%ymm1 + DB 72,139,64,24 ; mov 0x18(%rax),%rax + DB 196,193,105,114,208,16 ; vpsrld $0x10,%xmm8,%xmm2 + DB 196,193,97,114,210,16 ; vpsrld $0x10,%xmm10,%xmm3 + DB 196,227,109,24,211,1 ; vinsertf128 $0x1,%xmm3,%ymm2,%ymm2 + DB 197,180,84,210 ; vandps %ymm2,%ymm9,%ymm2 + DB 196,193,249,126,208 ; vmovq %xmm2,%r8 + DB 69,137,194 ; mov %r8d,%r10d + DB 196,195,249,22,209,1 ; vpextrq $0x1,%xmm2,%r9 + DB 69,137,203 ; mov %r9d,%r11d + DB 73,193,233,32 ; shr $0x20,%r9 + DB 73,193,232,32 ; shr $0x20,%r8 + DB 196,227,125,25,210,1 ; vextractf128 $0x1,%ymm2,%xmm2 + DB 196,225,249,126,213 ; vmovq %xmm2,%rbp + DB 65,137,238 ; mov %ebp,%r14d + DB 196,227,249,22,211,1 ; vpextrq $0x1,%xmm2,%rbx + DB 65,137,223 ; mov %ebx,%r15d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,161,122,16,20,176 ; vmovss (%rax,%r14,4),%xmm2 + DB 196,227,105,33,20,168,16 ; vinsertps $0x10,(%rax,%rbp,4),%xmm2,%xmm2 + DB 196,161,122,16,28,184 ; vmovss (%rax,%r15,4),%xmm3 + DB 196,227,105,33,211,32 ; vinsertps $0x20,%xmm3,%xmm2,%xmm2 + DB 197,250,16,28,152 ; vmovss (%rax,%rbx,4),%xmm3 + DB 196,99,105,33,203,48 ; vinsertps $0x30,%xmm3,%xmm2,%xmm9 + DB 196,161,122,16,28,144 ; vmovss (%rax,%r10,4),%xmm3 + DB 196,163,97,33,28,128,16 ; vinsertps $0x10,(%rax,%r8,4),%xmm3,%xmm3 + DB 196,161,122,16,20,152 ; vmovss (%rax,%r11,4),%xmm2 + DB 196,227,97,33,210,32 ; vinsertps $0x20,%xmm2,%xmm3,%xmm2 + DB 196,161,122,16,28,136 ; vmovss (%rax,%r9,4),%xmm3 + DB 196,227,105,33,211,48 ; vinsertps $0x30,%xmm3,%xmm2,%xmm2 + DB 196,195,109,24,209,1 ; vinsertf128 $0x1,%xmm9,%ymm2,%ymm2 + DB 196,193,57,114,208,24 ; vpsrld $0x18,%xmm8,%xmm8 + DB 196,193,97,114,210,24 ; vpsrld $0x18,%xmm10,%xmm3 + DB 196,227,61,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + DB 197,124,91,195 ; vcvtdq2ps %ymm3,%ymm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 93 ; pop %rbp + DB 255,224 ; jmpq *%rax + DB 137,203 ; mov %ecx,%ebx + DB 128,227,7 ; and $0x7,%bl + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 254,203 ; dec %bl + DB 128,251,6 ; cmp $0x6,%bl + DB 15,135,185,253,255,255 ; ja 17be <_sk_load_tables_avx+0x1e> + DB 15,182,219 ; movzbl %bl,%ebx + DB 76,141,13,137,0,0,0 ; lea 0x89(%rip),%r9 # 1a98 <_sk_load_tables_avx+0x2f8> + DB 73,99,28,153 ; movslq (%r9,%rbx,4),%rbx + DB 76,1,203 ; add %r9,%rbx + DB 255,227 ; jmpq *%rbx + DB 196,193,121,110,68,184,24 ; vmovd 0x18(%r8,%rdi,4),%xmm0 + DB 197,249,112,192,68 ; vpshufd $0x44,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 196,99,117,12,192,64 ; vblendps $0x40,%ymm0,%ymm1,%ymm8 + DB 196,99,125,25,192,1 ; vextractf128 $0x1,%ymm8,%xmm0 + DB 196,195,121,34,68,184,20,1 ; vpinsrd $0x1,0x14(%r8,%rdi,4),%xmm0,%xmm0 + DB 196,99,61,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm8,%ymm8 + DB 196,99,125,25,192,1 ; vextractf128 $0x1,%ymm8,%xmm0 + DB 196,195,121,34,68,184,16,0 ; vpinsrd $0x0,0x10(%r8,%rdi,4),%xmm0,%xmm0 + DB 196,99,61,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm8,%ymm8 + DB 196,195,57,34,68,184,12,3 ; vpinsrd $0x3,0xc(%r8,%rdi,4),%xmm8,%xmm0 + DB 196,99,61,12,192,15 ; vblendps $0xf,%ymm0,%ymm8,%ymm8 + DB 196,195,57,34,68,184,8,2 ; vpinsrd $0x2,0x8(%r8,%rdi,4),%xmm8,%xmm0 + DB 196,99,61,12,192,15 ; vblendps $0xf,%ymm0,%ymm8,%ymm8 + DB 196,195,57,34,68,184,4,1 ; vpinsrd $0x1,0x4(%r8,%rdi,4),%xmm8,%xmm0 + DB 196,99,61,12,192,15 ; vblendps $0xf,%ymm0,%ymm8,%ymm8 + DB 196,195,57,34,4,184,0 ; vpinsrd $0x0,(%r8,%rdi,4),%xmm8,%xmm0 + DB 196,99,61,12,192,15 ; vblendps $0xf,%ymm0,%ymm8,%ymm8 + DB 233,38,253,255,255 ; jmpq 17be <_sk_load_tables_avx+0x1e> + DB 238 ; out %al,(%dx) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,224 ; jmpq *%rax + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,210 ; callq *%rdx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,196 ; inc %esp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,176,255,255,255,156 ; pushq -0x63000001(%rax) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + DB 128,255,255 ; cmp $0xff,%bh + DB 255 ; .byte 0xff + +PUBLIC _sk_byte_tables_avx +_sk_byte_tables_avx LABEL PROC + DB 85 ; push %rbp + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,127,67 ; mov $0x437f0000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,253,91,192 ; vcvtps2dq %ymm0,%ymm0 + DB 196,195,249,22,192,1 ; vpextrq $0x1,%xmm0,%r8 + DB 68,137,197 ; mov %r8d,%ebp + DB 77,137,194 ; mov %r8,%r10 + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,193,249,126,192 ; vmovq %xmm0,%r8 + DB 69,137,195 ; mov %r8d,%r11d + DB 77,137,199 ; mov %r8,%r15 + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,227,125,25,192,1 ; vextractf128 $0x1,%ymm0,%xmm0 + DB 196,195,249,22,192,1 ; vpextrq $0x1,%xmm0,%r8 + DB 69,137,198 ; mov %r8d,%r14d + DB 77,137,196 ; mov %r8,%r12 + DB 73,193,236,32 ; shr $0x20,%r12 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,221 ; mov %ebx,%r13d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 76,139,8 ; mov (%rax),%r9 + DB 76,139,64,8 ; mov 0x8(%rax),%r8 + DB 196,131,121,32,4,25,0 ; vpinsrb $0x0,(%r9,%r11,1),%xmm0,%xmm0 + DB 196,131,121,32,4,57,1 ; vpinsrb $0x1,(%r9,%r15,1),%xmm0,%xmm0 + DB 65,15,182,44,41 ; movzbl (%r9,%rbp,1),%ebp + DB 196,227,121,32,197,2 ; vpinsrb $0x2,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,17 ; movzbl (%r9,%r10,1),%ebp + DB 196,227,121,32,197,3 ; vpinsrb $0x3,%ebp,%xmm0,%xmm0 + DB 196,98,121,49,200 ; vpmovzxbd %xmm0,%xmm9 + DB 196,131,121,32,4,41,0 ; vpinsrb $0x0,(%r9,%r13,1),%xmm0,%xmm0 + DB 196,195,121,32,4,25,1 ; vpinsrb $0x1,(%r9,%rbx,1),%xmm0,%xmm0 + DB 67,15,182,44,49 ; movzbl (%r9,%r14,1),%ebp + DB 196,227,121,32,197,2 ; vpinsrb $0x2,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,33 ; movzbl (%r9,%r12,1),%ebp + DB 196,227,121,32,197,3 ; vpinsrb $0x3,%ebp,%xmm0,%xmm0 + DB 196,226,121,49,192 ; vpmovzxbd %xmm0,%xmm0 + DB 196,227,53,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm9,%ymm0 + DB 197,124,91,208 ; vcvtdq2ps %ymm0,%ymm10 + DB 189,129,128,128,59 ; mov $0x3b808081,%ebp + DB 197,249,110,197 ; vmovd %ebp,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,99,125,24,200,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm9 + DB 196,193,44,89,193 ; vmulps %ymm9,%ymm10,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,253,91,201 ; vcvtps2dq %ymm1,%ymm1 + DB 196,227,249,22,205,1 ; vpextrq $0x1,%xmm1,%rbp + DB 65,137,233 ; mov %ebp,%r9d + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,225,249,126,203 ; vmovq %xmm1,%rbx + DB 65,137,218 ; mov %ebx,%r10d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,227,125,25,201,1 ; vextractf128 $0x1,%ymm1,%xmm1 + DB 196,195,249,22,203,1 ; vpextrq $0x1,%xmm1,%r11 + DB 69,137,222 ; mov %r11d,%r14d + DB 73,193,235,32 ; shr $0x20,%r11 + DB 196,193,249,126,207 ; vmovq %xmm1,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,131,121,32,12,16,0 ; vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm1 + DB 196,195,113,32,12,24,1 ; vpinsrb $0x1,(%r8,%rbx,1),%xmm1,%xmm1 + DB 67,15,182,28,8 ; movzbl (%r8,%r9,1),%ebx + DB 196,227,113,32,203,2 ; vpinsrb $0x2,%ebx,%xmm1,%xmm1 + DB 65,15,182,44,40 ; movzbl (%r8,%rbp,1),%ebp + DB 196,227,113,32,205,3 ; vpinsrb $0x3,%ebp,%xmm1,%xmm1 + DB 196,98,121,49,209 ; vpmovzxbd %xmm1,%xmm10 + DB 196,131,121,32,12,32,0 ; vpinsrb $0x0,(%r8,%r12,1),%xmm0,%xmm1 + DB 196,131,113,32,12,56,1 ; vpinsrb $0x1,(%r8,%r15,1),%xmm1,%xmm1 + DB 67,15,182,44,48 ; movzbl (%r8,%r14,1),%ebp + DB 196,227,113,32,205,2 ; vpinsrb $0x2,%ebp,%xmm1,%xmm1 + DB 67,15,182,44,24 ; movzbl (%r8,%r11,1),%ebp + DB 196,227,113,32,205,3 ; vpinsrb $0x3,%ebp,%xmm1,%xmm1 + DB 196,226,121,49,201 ; vpmovzxbd %xmm1,%xmm1 + DB 196,227,45,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm10,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 197,180,89,201 ; vmulps %ymm1,%ymm9,%ymm1 + DB 76,139,64,16 ; mov 0x10(%rax),%r8 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,253,91,210 ; vcvtps2dq %ymm2,%ymm2 + DB 196,227,249,22,213,1 ; vpextrq $0x1,%xmm2,%rbp + DB 65,137,233 ; mov %ebp,%r9d + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,225,249,126,211 ; vmovq %xmm2,%rbx + DB 65,137,218 ; mov %ebx,%r10d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,227,125,25,210,1 ; vextractf128 $0x1,%ymm2,%xmm2 + DB 196,195,249,22,211,1 ; vpextrq $0x1,%xmm2,%r11 + DB 69,137,222 ; mov %r11d,%r14d + DB 73,193,235,32 ; shr $0x20,%r11 + DB 196,193,249,126,215 ; vmovq %xmm2,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,131,121,32,20,16,0 ; vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm2 + DB 196,195,105,32,20,24,1 ; vpinsrb $0x1,(%r8,%rbx,1),%xmm2,%xmm2 + DB 67,15,182,28,8 ; movzbl (%r8,%r9,1),%ebx + DB 196,227,105,32,211,2 ; vpinsrb $0x2,%ebx,%xmm2,%xmm2 + DB 65,15,182,44,40 ; movzbl (%r8,%rbp,1),%ebp + DB 196,227,105,32,213,3 ; vpinsrb $0x3,%ebp,%xmm2,%xmm2 + DB 196,98,121,49,210 ; vpmovzxbd %xmm2,%xmm10 + DB 196,131,121,32,20,32,0 ; vpinsrb $0x0,(%r8,%r12,1),%xmm0,%xmm2 + DB 196,131,105,32,20,56,1 ; vpinsrb $0x1,(%r8,%r15,1),%xmm2,%xmm2 + DB 67,15,182,44,48 ; movzbl (%r8,%r14,1),%ebp + DB 196,227,105,32,213,2 ; vpinsrb $0x2,%ebp,%xmm2,%xmm2 + DB 67,15,182,44,24 ; movzbl (%r8,%r11,1),%ebp + DB 196,227,105,32,213,3 ; vpinsrb $0x3,%ebp,%xmm2,%xmm2 + DB 196,226,121,49,210 ; vpmovzxbd %xmm2,%xmm2 + DB 196,227,45,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm10,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 197,180,89,210 ; vmulps %ymm2,%ymm9,%ymm2 + DB 72,139,64,24 ; mov 0x18(%rax),%rax + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 197,253,91,219 ; vcvtps2dq %ymm3,%ymm3 + DB 196,227,249,22,221,1 ; vpextrq $0x1,%xmm3,%rbp + DB 65,137,232 ; mov %ebp,%r8d + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,225,249,126,219 ; vmovq %xmm3,%rbx + DB 65,137,217 ; mov %ebx,%r9d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,227,125,25,219,1 ; vextractf128 $0x1,%ymm3,%xmm3 + DB 196,195,249,22,218,1 ; vpextrq $0x1,%xmm3,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,193,249,126,222 ; vmovq %xmm3,%r14 + DB 69,137,247 ; mov %r14d,%r15d + DB 73,193,238,32 ; shr $0x20,%r14 + DB 196,163,121,32,28,8,0 ; vpinsrb $0x0,(%rax,%r9,1),%xmm0,%xmm3 + DB 196,227,97,32,28,24,1 ; vpinsrb $0x1,(%rax,%rbx,1),%xmm3,%xmm3 + DB 66,15,182,28,0 ; movzbl (%rax,%r8,1),%ebx + DB 196,227,97,32,219,2 ; vpinsrb $0x2,%ebx,%xmm3,%xmm3 + DB 15,182,44,40 ; movzbl (%rax,%rbp,1),%ebp + DB 196,227,97,32,221,3 ; vpinsrb $0x3,%ebp,%xmm3,%xmm3 + DB 196,98,121,49,195 ; vpmovzxbd %xmm3,%xmm8 + DB 196,163,121,32,28,56,0 ; vpinsrb $0x0,(%rax,%r15,1),%xmm0,%xmm3 + DB 196,163,97,32,28,48,1 ; vpinsrb $0x1,(%rax,%r14,1),%xmm3,%xmm3 + DB 66,15,182,44,24 ; movzbl (%rax,%r11,1),%ebp + DB 196,227,97,32,221,2 ; vpinsrb $0x2,%ebp,%xmm3,%xmm3 + DB 66,15,182,4,16 ; movzbl (%rax,%r10,1),%eax + DB 196,227,97,32,216,3 ; vpinsrb $0x3,%eax,%xmm3,%xmm3 + DB 196,226,121,49,219 ; vpmovzxbd %xmm3,%xmm3 + DB 196,227,61,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + DB 197,252,91,219 ; vcvtdq2ps %ymm3,%ymm3 + DB 197,180,89,219 ; vmulps %ymm3,%ymm9,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 93 ; pop %rbp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_byte_tables_rgb_avx +_sk_byte_tables_rgb_avx LABEL PROC + DB 85 ; push %rbp + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 68,139,64,24 ; mov 0x18(%rax),%r8d + DB 65,255,200 ; dec %r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,65,121,112,192,0 ; vpshufd $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 196,65,124,91,192 ; vcvtdq2ps %ymm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,253,91,192 ; vcvtps2dq %ymm0,%ymm0 + DB 196,195,249,22,192,1 ; vpextrq $0x1,%xmm0,%r8 + DB 68,137,197 ; mov %r8d,%ebp + DB 77,137,194 ; mov %r8,%r10 + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,193,249,126,192 ; vmovq %xmm0,%r8 + DB 69,137,195 ; mov %r8d,%r11d + DB 77,137,199 ; mov %r8,%r15 + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,227,125,25,192,1 ; vextractf128 $0x1,%ymm0,%xmm0 + DB 196,195,249,22,192,1 ; vpextrq $0x1,%xmm0,%r8 + DB 69,137,198 ; mov %r8d,%r14d + DB 77,137,196 ; mov %r8,%r12 + DB 73,193,236,32 ; shr $0x20,%r12 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,221 ; mov %ebx,%r13d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 76,139,8 ; mov (%rax),%r9 + DB 76,139,64,8 ; mov 0x8(%rax),%r8 + DB 196,131,121,32,4,25,0 ; vpinsrb $0x0,(%r9,%r11,1),%xmm0,%xmm0 + DB 196,131,121,32,4,57,1 ; vpinsrb $0x1,(%r9,%r15,1),%xmm0,%xmm0 + DB 65,15,182,44,41 ; movzbl (%r9,%rbp,1),%ebp + DB 196,227,121,32,197,2 ; vpinsrb $0x2,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,17 ; movzbl (%r9,%r10,1),%ebp + DB 196,227,121,32,197,3 ; vpinsrb $0x3,%ebp,%xmm0,%xmm0 + DB 196,98,121,49,200 ; vpmovzxbd %xmm0,%xmm9 + DB 196,131,121,32,4,41,0 ; vpinsrb $0x0,(%r9,%r13,1),%xmm0,%xmm0 + DB 196,195,121,32,4,25,1 ; vpinsrb $0x1,(%r9,%rbx,1),%xmm0,%xmm0 + DB 67,15,182,44,49 ; movzbl (%r9,%r14,1),%ebp + DB 196,227,121,32,197,2 ; vpinsrb $0x2,%ebp,%xmm0,%xmm0 + DB 67,15,182,44,33 ; movzbl (%r9,%r12,1),%ebp + DB 196,227,121,32,197,3 ; vpinsrb $0x3,%ebp,%xmm0,%xmm0 + DB 196,226,121,49,192 ; vpmovzxbd %xmm0,%xmm0 + DB 196,227,53,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm9,%ymm0 + DB 197,124,91,208 ; vcvtdq2ps %ymm0,%ymm10 + DB 189,129,128,128,59 ; mov $0x3b808081,%ebp + DB 197,249,110,197 ; vmovd %ebp,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,99,125,24,200,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm9 + DB 196,193,44,89,193 ; vmulps %ymm9,%ymm10,%ymm0 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,253,91,201 ; vcvtps2dq %ymm1,%ymm1 + DB 196,227,249,22,205,1 ; vpextrq $0x1,%xmm1,%rbp + DB 65,137,233 ; mov %ebp,%r9d + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,225,249,126,203 ; vmovq %xmm1,%rbx + DB 65,137,218 ; mov %ebx,%r10d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,227,125,25,201,1 ; vextractf128 $0x1,%ymm1,%xmm1 + DB 196,195,249,22,203,1 ; vpextrq $0x1,%xmm1,%r11 + DB 69,137,222 ; mov %r11d,%r14d + DB 73,193,235,32 ; shr $0x20,%r11 + DB 196,193,249,126,207 ; vmovq %xmm1,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,131,121,32,12,16,0 ; vpinsrb $0x0,(%r8,%r10,1),%xmm0,%xmm1 + DB 196,195,113,32,12,24,1 ; vpinsrb $0x1,(%r8,%rbx,1),%xmm1,%xmm1 + DB 67,15,182,28,8 ; movzbl (%r8,%r9,1),%ebx + DB 196,227,113,32,203,2 ; vpinsrb $0x2,%ebx,%xmm1,%xmm1 + DB 65,15,182,44,40 ; movzbl (%r8,%rbp,1),%ebp + DB 196,227,113,32,205,3 ; vpinsrb $0x3,%ebp,%xmm1,%xmm1 + DB 196,98,121,49,209 ; vpmovzxbd %xmm1,%xmm10 + DB 196,131,121,32,12,32,0 ; vpinsrb $0x0,(%r8,%r12,1),%xmm0,%xmm1 + DB 196,131,113,32,12,56,1 ; vpinsrb $0x1,(%r8,%r15,1),%xmm1,%xmm1 + DB 67,15,182,44,48 ; movzbl (%r8,%r14,1),%ebp + DB 196,227,113,32,205,2 ; vpinsrb $0x2,%ebp,%xmm1,%xmm1 + DB 67,15,182,44,24 ; movzbl (%r8,%r11,1),%ebp + DB 196,227,113,32,205,3 ; vpinsrb $0x3,%ebp,%xmm1,%xmm1 + DB 196,226,121,49,201 ; vpmovzxbd %xmm1,%xmm1 + DB 196,227,45,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm10,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 197,180,89,201 ; vmulps %ymm1,%ymm9,%ymm1 + DB 72,139,64,16 ; mov 0x10(%rax),%rax + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 197,253,91,210 ; vcvtps2dq %ymm2,%ymm2 + DB 196,227,249,22,213,1 ; vpextrq $0x1,%xmm2,%rbp + DB 65,137,232 ; mov %ebp,%r8d + DB 72,193,237,32 ; shr $0x20,%rbp + DB 196,225,249,126,211 ; vmovq %xmm2,%rbx + DB 65,137,217 ; mov %ebx,%r9d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,227,125,25,210,1 ; vextractf128 $0x1,%ymm2,%xmm2 + DB 196,195,249,22,210,1 ; vpextrq $0x1,%xmm2,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 196,193,249,126,214 ; vmovq %xmm2,%r14 + DB 69,137,247 ; mov %r14d,%r15d + DB 73,193,238,32 ; shr $0x20,%r14 + DB 196,163,121,32,20,8,0 ; vpinsrb $0x0,(%rax,%r9,1),%xmm0,%xmm2 + DB 196,227,105,32,20,24,1 ; vpinsrb $0x1,(%rax,%rbx,1),%xmm2,%xmm2 + DB 66,15,182,28,0 ; movzbl (%rax,%r8,1),%ebx + DB 196,227,105,32,211,2 ; vpinsrb $0x2,%ebx,%xmm2,%xmm2 + DB 15,182,44,40 ; movzbl (%rax,%rbp,1),%ebp + DB 196,227,105,32,213,3 ; vpinsrb $0x3,%ebp,%xmm2,%xmm2 + DB 196,98,121,49,194 ; vpmovzxbd %xmm2,%xmm8 + DB 196,163,121,32,20,56,0 ; vpinsrb $0x0,(%rax,%r15,1),%xmm0,%xmm2 + DB 196,163,105,32,20,48,1 ; vpinsrb $0x1,(%rax,%r14,1),%xmm2,%xmm2 + DB 66,15,182,44,24 ; movzbl (%rax,%r11,1),%ebp + DB 196,227,105,32,213,2 ; vpinsrb $0x2,%ebp,%xmm2,%xmm2 + DB 66,15,182,4,16 ; movzbl (%rax,%r10,1),%eax + DB 196,227,105,32,208,3 ; vpinsrb $0x3,%eax,%xmm2,%xmm2 + DB 196,226,121,49,210 ; vpmovzxbd %xmm2,%xmm2 + DB 196,227,61,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm8,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 197,180,89,210 ; vmulps %ymm2,%ymm9,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 93 ; pop %rbp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_a8_avx +_sk_load_a8_avx LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,1,248 ; add %rdi,%rax + DB 77,133,192 ; test %r8,%r8 + DB 117,74 ; jne 202c <_sk_load_a8_avx+0x5a> + DB 197,250,126,0 ; vmovq (%rax),%xmm0 + DB 196,226,121,49,200 ; vpmovzxbd %xmm0,%xmm1 + DB 196,227,121,4,192,229 ; vpermilps $0xe5,%xmm0,%xmm0 + DB 196,226,121,49,192 ; vpmovzxbd %xmm0,%xmm0 + DB 196,227,117,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm1,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,252,89,217 ; vmulps %ymm1,%ymm0,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 76,137,193 ; mov %r8,%rcx + DB 255,224 ; jmpq *%rax + DB 49,201 ; xor %ecx,%ecx + DB 77,137,194 ; mov %r8,%r10 + DB 69,49,201 ; xor %r9d,%r9d + DB 68,15,182,24 ; movzbl (%rax),%r11d + DB 72,255,192 ; inc %rax + DB 73,211,227 ; shl %cl,%r11 + DB 77,9,217 ; or %r11,%r9 + DB 72,131,193,8 ; add $0x8,%rcx + DB 73,255,202 ; dec %r10 + DB 117,234 ; jne 2034 <_sk_load_a8_avx+0x62> + DB 196,193,249,110,193 ; vmovq %r9,%xmm0 + DB 235,149 ; jmp 1fe6 <_sk_load_a8_avx+0x14> + +PUBLIC _sk_gather_a8_avx +_sk_gather_a8_avx LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,209 ; vcvttps2dq %ymm1,%ymm2 + DB 197,249,110,72,16 ; vmovd 0x10(%rax),%xmm1 + DB 197,249,112,217,0 ; vpshufd $0x0,%xmm1,%xmm3 + DB 196,226,97,64,202 ; vpmulld %xmm2,%xmm3,%xmm1 + DB 196,227,125,25,210,1 ; vextractf128 $0x1,%ymm2,%xmm2 + DB 196,226,97,64,210 ; vpmulld %xmm2,%xmm3,%xmm2 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 196,227,125,25,195,1 ; vextractf128 $0x1,%ymm0,%xmm3 + DB 197,233,254,211 ; vpaddd %xmm3,%xmm2,%xmm2 + DB 196,227,249,22,208,1 ; vpextrq $0x1,%xmm2,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,210 ; vmovq %xmm2,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 197,241,254,192 ; vpaddd %xmm0,%xmm1,%xmm0 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,222 ; mov %ebx,%r14d + DB 196,195,249,22,199,1 ; vpextrq $0x1,%xmm0,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,131,121,32,4,48,0 ; vpinsrb $0x0,(%r8,%r14,1),%xmm0,%xmm0 + DB 196,195,121,32,4,24,1 ; vpinsrb $0x1,(%r8,%rbx,1),%xmm0,%xmm0 + DB 67,15,182,28,32 ; movzbl (%r8,%r12,1),%ebx + DB 196,227,121,32,195,2 ; vpinsrb $0x2,%ebx,%xmm0,%xmm0 + DB 67,15,182,28,56 ; movzbl (%r8,%r15,1),%ebx + DB 196,227,121,32,195,3 ; vpinsrb $0x3,%ebx,%xmm0,%xmm0 + DB 196,226,121,49,192 ; vpmovzxbd %xmm0,%xmm0 + DB 196,131,121,32,12,24,0 ; vpinsrb $0x0,(%r8,%r11,1),%xmm0,%xmm1 + DB 196,131,113,32,12,16,1 ; vpinsrb $0x1,(%r8,%r10,1),%xmm1,%xmm1 + DB 67,15,182,28,8 ; movzbl (%r8,%r9,1),%ebx + DB 196,227,113,32,203,2 ; vpinsrb $0x2,%ebx,%xmm1,%xmm1 + DB 65,15,182,4,0 ; movzbl (%r8,%rax,1),%eax + DB 196,227,113,32,200,3 ; vpinsrb $0x3,%eax,%xmm1,%xmm1 + DB 196,226,121,49,201 ; vpmovzxbd %xmm1,%xmm1 + DB 196,227,125,24,193,1 ; vinsertf128 $0x1,%xmm1,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,252,89,217 ; vmulps %ymm1,%ymm0,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_a8_avx +_sk_store_a8_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 184,0,0,127,67 ; mov $0x437f0000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 196,65,125,91,192 ; vcvtps2dq %ymm8,%ymm8 + DB 196,67,125,25,193,1 ; vextractf128 $0x1,%ymm8,%xmm9 + DB 196,66,57,43,193 ; vpackusdw %xmm9,%xmm8,%xmm8 + DB 196,65,57,103,192 ; vpackuswb %xmm8,%xmm8,%xmm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,10 ; jne 218d <_sk_store_a8_avx+0x42> + DB 196,65,123,17,4,57 ; vmovsd %xmm8,(%r9,%rdi,1) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 119,236 ; ja 2189 <_sk_store_a8_avx+0x3e> + DB 196,66,121,48,192 ; vpmovzxbw %xmm8,%xmm8 + DB 65,15,182,192 ; movzbl %r8b,%eax + DB 76,141,5,67,0,0,0 ; lea 0x43(%rip),%r8 # 21f0 <_sk_store_a8_avx+0xa5> + DB 73,99,4,128 ; movslq (%r8,%rax,4),%rax + DB 76,1,192 ; add %r8,%rax + DB 255,224 ; jmpq *%rax + DB 196,67,121,20,68,57,6,12 ; vpextrb $0xc,%xmm8,0x6(%r9,%rdi,1) + DB 196,67,121,20,68,57,5,10 ; vpextrb $0xa,%xmm8,0x5(%r9,%rdi,1) + DB 196,67,121,20,68,57,4,8 ; vpextrb $0x8,%xmm8,0x4(%r9,%rdi,1) + DB 196,67,121,20,68,57,3,6 ; vpextrb $0x6,%xmm8,0x3(%r9,%rdi,1) + DB 196,67,121,20,68,57,2,4 ; vpextrb $0x4,%xmm8,0x2(%r9,%rdi,1) + DB 196,67,121,20,68,57,1,2 ; vpextrb $0x2,%xmm8,0x1(%r9,%rdi,1) + DB 196,67,121,20,4,57,0 ; vpextrb $0x0,%xmm8,(%r9,%rdi,1) + DB 235,154 ; jmp 2189 <_sk_store_a8_avx+0x3e> + DB 144 ; nop + DB 246,255 ; idiv %bh + DB 255 ; (bad) + DB 255 ; (bad) + DB 238 ; out %al,(%dx) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,230 ; jmpq *%rsi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 222,255 ; fdivrp %st,%st(7) + DB 255 ; (bad) + DB 255,214 ; callq *%rsi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,206 ; dec %esi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,198 ; inc %esi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_load_g8_avx +_sk_load_g8_avx LABEL PROC + DB 73,137,200 ; mov %rcx,%r8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,1,248 ; add %rdi,%rax + DB 77,133,192 ; test %r8,%r8 + DB 117,91 ; jne 2277 <_sk_load_g8_avx+0x6b> + DB 197,250,126,0 ; vmovq (%rax),%xmm0 + DB 196,226,121,49,200 ; vpmovzxbd %xmm0,%xmm1 + DB 196,227,121,4,192,229 ; vpermilps $0xe5,%xmm0,%xmm0 + DB 196,226,121,49,192 ; vpmovzxbd %xmm0,%xmm0 + DB 196,227,117,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm1,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,217,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,137,193 ; mov %r8,%rcx + DB 197,252,40,200 ; vmovaps %ymm0,%ymm1 + DB 197,252,40,208 ; vmovaps %ymm0,%ymm2 + DB 255,224 ; jmpq *%rax + DB 49,201 ; xor %ecx,%ecx + DB 77,137,194 ; mov %r8,%r10 + DB 69,49,201 ; xor %r9d,%r9d + DB 68,15,182,24 ; movzbl (%rax),%r11d + DB 72,255,192 ; inc %rax + DB 73,211,227 ; shl %cl,%r11 + DB 77,9,217 ; or %r11,%r9 + DB 72,131,193,8 ; add $0x8,%rcx + DB 73,255,202 ; dec %r10 + DB 117,234 ; jne 227f <_sk_load_g8_avx+0x73> + DB 196,193,249,110,193 ; vmovq %r9,%xmm0 + DB 235,132 ; jmp 2220 <_sk_load_g8_avx+0x14> + +PUBLIC _sk_gather_g8_avx +_sk_gather_g8_avx LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,209 ; vcvttps2dq %ymm1,%ymm2 + DB 197,249,110,72,16 ; vmovd 0x10(%rax),%xmm1 + DB 197,249,112,217,0 ; vpshufd $0x0,%xmm1,%xmm3 + DB 196,226,97,64,202 ; vpmulld %xmm2,%xmm3,%xmm1 + DB 196,227,125,25,210,1 ; vextractf128 $0x1,%ymm2,%xmm2 + DB 196,226,97,64,210 ; vpmulld %xmm2,%xmm3,%xmm2 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 196,227,125,25,195,1 ; vextractf128 $0x1,%ymm0,%xmm3 + DB 197,233,254,211 ; vpaddd %xmm3,%xmm2,%xmm2 + DB 196,227,249,22,208,1 ; vpextrq $0x1,%xmm2,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,210 ; vmovq %xmm2,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 197,241,254,192 ; vpaddd %xmm0,%xmm1,%xmm0 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,222 ; mov %ebx,%r14d + DB 196,195,249,22,199,1 ; vpextrq $0x1,%xmm0,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,131,121,32,4,48,0 ; vpinsrb $0x0,(%r8,%r14,1),%xmm0,%xmm0 + DB 196,195,121,32,4,24,1 ; vpinsrb $0x1,(%r8,%rbx,1),%xmm0,%xmm0 + DB 67,15,182,28,32 ; movzbl (%r8,%r12,1),%ebx + DB 196,227,121,32,195,2 ; vpinsrb $0x2,%ebx,%xmm0,%xmm0 + DB 67,15,182,28,56 ; movzbl (%r8,%r15,1),%ebx + DB 196,227,121,32,195,3 ; vpinsrb $0x3,%ebx,%xmm0,%xmm0 + DB 196,226,121,49,192 ; vpmovzxbd %xmm0,%xmm0 + DB 196,131,121,32,12,24,0 ; vpinsrb $0x0,(%r8,%r11,1),%xmm0,%xmm1 + DB 196,131,113,32,12,16,1 ; vpinsrb $0x1,(%r8,%r10,1),%xmm1,%xmm1 + DB 67,15,182,28,8 ; movzbl (%r8,%r9,1),%ebx + DB 196,227,113,32,203,2 ; vpinsrb $0x2,%ebx,%xmm1,%xmm1 + DB 65,15,182,4,0 ; movzbl (%r8,%rax,1),%eax + DB 196,227,113,32,200,3 ; vpinsrb $0x3,%eax,%xmm1,%xmm1 + DB 196,226,121,49,201 ; vpmovzxbd %xmm1,%xmm1 + DB 196,227,125,24,193,1 ; vinsertf128 $0x1,%xmm1,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,217,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,40,200 ; vmovaps %ymm0,%ymm1 + DB 197,252,40,208 ; vmovaps %ymm0,%ymm2 + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_i8_avx +_sk_gather_i8_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 73,137,192 ; mov %rax,%r8 + DB 77,133,192 ; test %r8,%r8 + DB 116,5 ; je 23b6 <_sk_gather_i8_avx+0xf> + DB 76,137,192 ; mov %r8,%rax + DB 235,2 ; jmp 23b8 <_sk_gather_i8_avx+0x11> + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 76,139,8 ; mov (%rax),%r9 + DB 197,254,91,209 ; vcvttps2dq %ymm1,%ymm2 + DB 197,249,110,72,16 ; vmovd 0x10(%rax),%xmm1 + DB 197,249,112,217,0 ; vpshufd $0x0,%xmm1,%xmm3 + DB 196,226,97,64,202 ; vpmulld %xmm2,%xmm3,%xmm1 + DB 196,227,125,25,210,1 ; vextractf128 $0x1,%ymm2,%xmm2 + DB 196,226,97,64,210 ; vpmulld %xmm2,%xmm3,%xmm2 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 196,227,125,25,195,1 ; vextractf128 $0x1,%ymm0,%xmm3 + DB 197,233,254,211 ; vpaddd %xmm3,%xmm2,%xmm2 + DB 196,227,249,22,208,1 ; vpextrq $0x1,%xmm2,%rax + DB 65,137,194 ; mov %eax,%r10d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,211 ; vmovq %xmm2,%r11 + DB 69,137,222 ; mov %r11d,%r14d + DB 73,193,235,32 ; shr $0x20,%r11 + DB 197,241,254,192 ; vpaddd %xmm0,%xmm1,%xmm0 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,223 ; mov %ebx,%r15d + DB 196,195,249,22,196,1 ; vpextrq $0x1,%xmm0,%r12 + DB 69,137,229 ; mov %r12d,%r13d + DB 73,193,236,32 ; shr $0x20,%r12 + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,131,121,32,4,49,0 ; vpinsrb $0x0,(%r9,%r14,1),%xmm0,%xmm0 + DB 196,131,121,32,4,25,1 ; vpinsrb $0x1,(%r9,%r11,1),%xmm0,%xmm0 + DB 196,131,121,32,4,17,2 ; vpinsrb $0x2,(%r9,%r10,1),%xmm0,%xmm0 + DB 196,195,121,32,4,1,3 ; vpinsrb $0x3,(%r9,%rax,1),%xmm0,%xmm0 + DB 196,226,121,49,192 ; vpmovzxbd %xmm0,%xmm0 + DB 196,195,249,22,194,1 ; vpextrq $0x1,%xmm0,%r10 + DB 196,193,249,126,195 ; vmovq %xmm0,%r11 + DB 196,131,121,32,4,57,0 ; vpinsrb $0x0,(%r9,%r15,1),%xmm0,%xmm0 + DB 196,195,121,32,4,25,1 ; vpinsrb $0x1,(%r9,%rbx,1),%xmm0,%xmm0 + DB 196,131,121,32,4,41,2 ; vpinsrb $0x2,(%r9,%r13,1),%xmm0,%xmm0 + DB 196,131,121,32,4,33,3 ; vpinsrb $0x3,(%r9,%r12,1),%xmm0,%xmm0 + DB 196,226,121,49,192 ; vpmovzxbd %xmm0,%xmm0 + DB 73,139,88,8 ; mov 0x8(%r8),%rbx + DB 196,193,249,126,193 ; vmovq %xmm0,%r9 + DB 69,137,200 ; mov %r9d,%r8d + DB 73,193,233,30 ; shr $0x1e,%r9 + DB 196,227,249,22,192,1 ; vpextrq $0x1,%xmm0,%rax + DB 65,137,198 ; mov %eax,%r14d + DB 72,193,232,30 ; shr $0x1e,%rax + DB 69,137,223 ; mov %r11d,%r15d + DB 73,193,235,30 ; shr $0x1e,%r11 + DB 69,137,212 ; mov %r10d,%r12d + DB 73,193,234,30 ; shr $0x1e,%r10 + DB 196,161,121,110,4,131 ; vmovd (%rbx,%r8,4),%xmm0 + DB 196,163,121,34,4,11,1 ; vpinsrd $0x1,(%rbx,%r9,1),%xmm0,%xmm0 + DB 196,163,121,34,4,179,2 ; vpinsrd $0x2,(%rbx,%r14,4),%xmm0,%xmm0 + DB 196,99,121,34,4,3,3 ; vpinsrd $0x3,(%rbx,%rax,1),%xmm0,%xmm8 + DB 196,161,121,110,4,187 ; vmovd (%rbx,%r15,4),%xmm0 + DB 196,163,121,34,4,27,1 ; vpinsrd $0x1,(%rbx,%r11,1),%xmm0,%xmm0 + DB 196,163,121,34,4,163,2 ; vpinsrd $0x2,(%rbx,%r12,4),%xmm0,%xmm0 + DB 196,163,121,34,28,19,3 ; vpinsrd $0x3,(%rbx,%r10,1),%xmm0,%xmm3 + DB 196,227,61,24,195,1 ; vinsertf128 $0x1,%xmm3,%ymm8,%ymm0 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 197,249,112,201,0 ; vpshufd $0x0,%xmm1,%xmm1 + DB 196,99,117,24,217,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm11 + DB 197,164,84,192 ; vandps %ymm0,%ymm11,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,99,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm9 + DB 196,193,124,89,193 ; vmulps %ymm9,%ymm0,%ymm0 + DB 196,193,41,114,208,8 ; vpsrld $0x8,%xmm8,%xmm10 + DB 197,241,114,211,8 ; vpsrld $0x8,%xmm3,%xmm1 + DB 196,227,45,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm10,%ymm1 + DB 197,164,84,201 ; vandps %ymm1,%ymm11,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 196,193,116,89,201 ; vmulps %ymm9,%ymm1,%ymm1 + DB 196,193,41,114,208,16 ; vpsrld $0x10,%xmm8,%xmm10 + DB 197,233,114,211,16 ; vpsrld $0x10,%xmm3,%xmm2 + DB 196,227,45,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm10,%ymm2 + DB 197,164,84,210 ; vandps %ymm2,%ymm11,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 196,193,108,89,209 ; vmulps %ymm9,%ymm2,%ymm2 + DB 196,193,57,114,208,24 ; vpsrld $0x18,%xmm8,%xmm8 + DB 197,225,114,211,24 ; vpsrld $0x18,%xmm3,%xmm3 + DB 196,227,61,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + DB 197,252,91,219 ; vcvtdq2ps %ymm3,%ymm3 + DB 196,193,100,89,217 ; vmulps %ymm9,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_565_avx +_sk_load_565_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,16 ; mov (%rax),%r10 + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,209,0,0,0 ; jne 2652 <_sk_load_565_avx+0xdf> + DB 196,193,122,111,4,122 ; vmovdqu (%r10,%rdi,2),%xmm0 + DB 197,241,239,201 ; vpxor %xmm1,%xmm1,%xmm1 + DB 197,249,105,201 ; vpunpckhwd %xmm1,%xmm0,%xmm1 + DB 196,226,121,51,192 ; vpmovzxwd %xmm0,%xmm0 + DB 196,227,125,24,209,1 ; vinsertf128 $0x1,%xmm1,%ymm0,%ymm2 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 197,249,112,192,0 ; vpshufd $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,252,84,194 ; vandps %ymm2,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 197,249,112,201,0 ; vpshufd $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,244,84,202 ; vandps %ymm2,%ymm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,244,89,203 ; vmulps %ymm3,%ymm1,%ymm1 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 197,249,112,219,0 ; vpshufd $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,228,84,210 ; vandps %ymm2,%ymm3,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,236,89,211 ; vmulps %ymm3,%ymm2,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 197,249,239,192 ; vpxor %xmm0,%xmm0,%xmm0 + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 15,135,29,255,255,255 ; ja 2587 <_sk_load_565_avx+0x14> + DB 69,15,182,192 ; movzbl %r8b,%r8d + DB 76,141,13,75,0,0,0 ; lea 0x4b(%rip),%r9 # 26c0 <_sk_load_565_avx+0x14d> + DB 75,99,4,129 ; movslq (%r9,%r8,4),%rax + DB 76,1,200 ; add %r9,%rax + DB 255,224 ; jmpq *%rax + DB 197,249,239,192 ; vpxor %xmm0,%xmm0,%xmm0 + DB 196,193,121,196,68,122,12,6 ; vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,10,5 ; vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,8,4 ; vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,6,3 ; vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,4,2 ; vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,2,1 ; vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,4,122,0 ; vpinsrw $0x0,(%r10,%rdi,2),%xmm0,%xmm0 + DB 233,201,254,255,255 ; jmpq 2587 <_sk_load_565_avx+0x14> + DB 102,144 ; xchg %ax,%ax + DB 242,255 ; repnz (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 234 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,226 ; jmpq *%rdx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 218,255 ; (bad) + DB 255 ; (bad) + DB 255,210 ; callq *%rdx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,202 ; dec %edx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 190 ; .byte 0xbe + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_gather_565_avx +_sk_gather_565_avx LABEL PROC + DB 85 ; push %rbp + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,209 ; vcvttps2dq %ymm1,%ymm2 + DB 197,249,110,72,16 ; vmovd 0x10(%rax),%xmm1 + DB 197,249,112,217,0 ; vpshufd $0x0,%xmm1,%xmm3 + DB 196,226,97,64,202 ; vpmulld %xmm2,%xmm3,%xmm1 + DB 196,227,125,25,210,1 ; vextractf128 $0x1,%ymm2,%xmm2 + DB 196,226,97,64,210 ; vpmulld %xmm2,%xmm3,%xmm2 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 196,227,125,25,195,1 ; vextractf128 $0x1,%ymm0,%xmm3 + DB 197,233,254,211 ; vpaddd %xmm3,%xmm2,%xmm2 + DB 196,227,249,22,208,1 ; vpextrq $0x1,%xmm2,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,210 ; vmovq %xmm2,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 197,241,254,192 ; vpaddd %xmm0,%xmm1,%xmm0 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,222 ; mov %ebx,%r14d + DB 196,195,249,22,199,1 ; vpextrq $0x1,%xmm0,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 72,193,235,32 ; shr $0x20,%rbx + DB 65,15,183,28,88 ; movzwl (%r8,%rbx,2),%ebx + DB 67,15,183,44,112 ; movzwl (%r8,%r14,2),%ebp + DB 197,249,110,197 ; vmovd %ebp,%xmm0 + DB 197,249,196,195,1 ; vpinsrw $0x1,%ebx,%xmm0,%xmm0 + DB 67,15,183,28,96 ; movzwl (%r8,%r12,2),%ebx + DB 197,249,196,195,2 ; vpinsrw $0x2,%ebx,%xmm0,%xmm0 + DB 67,15,183,28,120 ; movzwl (%r8,%r15,2),%ebx + DB 197,249,196,195,3 ; vpinsrw $0x3,%ebx,%xmm0,%xmm0 + DB 67,15,183,44,88 ; movzwl (%r8,%r11,2),%ebp + DB 197,249,196,197,4 ; vpinsrw $0x4,%ebp,%xmm0,%xmm0 + DB 67,15,183,44,80 ; movzwl (%r8,%r10,2),%ebp + DB 197,249,196,197,5 ; vpinsrw $0x5,%ebp,%xmm0,%xmm0 + DB 67,15,183,44,72 ; movzwl (%r8,%r9,2),%ebp + DB 197,249,196,197,6 ; vpinsrw $0x6,%ebp,%xmm0,%xmm0 + DB 65,15,183,4,64 ; movzwl (%r8,%rax,2),%eax + DB 197,249,196,192,7 ; vpinsrw $0x7,%eax,%xmm0,%xmm0 + DB 197,241,239,201 ; vpxor %xmm1,%xmm1,%xmm1 + DB 197,249,105,201 ; vpunpckhwd %xmm1,%xmm0,%xmm1 + DB 196,226,121,51,192 ; vpmovzxwd %xmm0,%xmm0 + DB 196,227,125,24,209,1 ; vinsertf128 $0x1,%xmm1,%ymm0,%ymm2 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 197,249,112,192,0 ; vpshufd $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,252,84,194 ; vandps %ymm2,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 197,249,112,201,0 ; vpshufd $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,244,84,202 ; vandps %ymm2,%ymm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,244,89,203 ; vmulps %ymm3,%ymm1,%ymm1 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 197,249,112,219,0 ; vpshufd $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,228,84,210 ; vandps %ymm2,%ymm3,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,236,89,211 ; vmulps %ymm3,%ymm2,%ymm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 93 ; pop %rbp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_565_avx +_sk_store_565_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 184,0,0,248,65 ; mov $0x41f80000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 196,65,125,91,201 ; vcvtps2dq %ymm9,%ymm9 + DB 196,193,41,114,241,11 ; vpslld $0xb,%xmm9,%xmm10 + DB 196,67,125,25,201,1 ; vextractf128 $0x1,%ymm9,%xmm9 + DB 196,193,49,114,241,11 ; vpslld $0xb,%xmm9,%xmm9 + DB 196,67,45,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm10,%ymm9 + DB 184,0,0,124,66 ; mov $0x427c0000,%eax + DB 197,121,110,208 ; vmovd %eax,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 197,44,89,209 ; vmulps %ymm1,%ymm10,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,193,33,114,242,5 ; vpslld $0x5,%xmm10,%xmm11 + DB 196,67,125,25,210,1 ; vextractf128 $0x1,%ymm10,%xmm10 + DB 196,193,41,114,242,5 ; vpslld $0x5,%xmm10,%xmm10 + DB 196,67,37,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm11,%ymm10 + DB 196,65,45,86,201 ; vorpd %ymm9,%ymm10,%ymm9 + DB 197,60,89,194 ; vmulps %ymm2,%ymm8,%ymm8 + DB 196,65,125,91,192 ; vcvtps2dq %ymm8,%ymm8 + DB 196,65,53,86,192 ; vorpd %ymm8,%ymm9,%ymm8 + DB 196,67,125,25,193,1 ; vextractf128 $0x1,%ymm8,%xmm9 + DB 196,66,57,43,193 ; vpackusdw %xmm9,%xmm8,%xmm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,10 ; jne 290b <_sk_store_565_avx+0x9e> + DB 196,65,122,127,4,121 ; vmovdqu %xmm8,(%r9,%rdi,2) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 119,236 ; ja 2907 <_sk_store_565_avx+0x9a> + DB 65,15,182,192 ; movzbl %r8b,%eax + DB 76,141,5,66,0,0,0 ; lea 0x42(%rip),%r8 # 2968 <_sk_store_565_avx+0xfb> + DB 73,99,4,128 ; movslq (%r8,%rax,4),%rax + DB 76,1,192 ; add %r8,%rax + DB 255,224 ; jmpq *%rax + DB 196,67,121,21,68,121,12,6 ; vpextrw $0x6,%xmm8,0xc(%r9,%rdi,2) + DB 196,67,121,21,68,121,10,5 ; vpextrw $0x5,%xmm8,0xa(%r9,%rdi,2) + DB 196,67,121,21,68,121,8,4 ; vpextrw $0x4,%xmm8,0x8(%r9,%rdi,2) + DB 196,67,121,21,68,121,6,3 ; vpextrw $0x3,%xmm8,0x6(%r9,%rdi,2) + DB 196,67,121,21,68,121,4,2 ; vpextrw $0x2,%xmm8,0x4(%r9,%rdi,2) + DB 196,67,121,21,68,121,2,1 ; vpextrw $0x1,%xmm8,0x2(%r9,%rdi,2) + DB 196,67,121,21,4,121,0 ; vpextrw $0x0,%xmm8,(%r9,%rdi,2) + DB 235,159 ; jmp 2907 <_sk_store_565_avx+0x9a> + DB 247,255 ; idiv %edi + DB 255 ; (bad) + DB 255 ; (bad) + DB 239 ; out %eax,(%dx) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,231 ; jmpq *%rdi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 223,255 ; (bad) + DB 255 ; (bad) + DB 255,215 ; callq *%rdi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,207 ; dec %edi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,199 ; inc %edi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_load_4444_avx +_sk_load_4444_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,16 ; mov (%rax),%r10 + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,245,0,0,0 ; jne 2a87 <_sk_load_4444_avx+0x103> + DB 196,193,122,111,4,122 ; vmovdqu (%r10,%rdi,2),%xmm0 + DB 197,241,239,201 ; vpxor %xmm1,%xmm1,%xmm1 + DB 197,249,105,201 ; vpunpckhwd %xmm1,%xmm0,%xmm1 + DB 196,226,121,51,192 ; vpmovzxwd %xmm0,%xmm0 + DB 196,99,125,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm0,%ymm9 + DB 184,0,240,0,0 ; mov $0xf000,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 197,249,112,192,0 ; vpshufd $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 196,193,124,84,193 ; vandps %ymm9,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,137,136,136,55 ; mov $0x37888889,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,0,15,0,0 ; mov $0xf00,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 197,249,112,201,0 ; vpshufd $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 196,193,116,84,201 ; vandps %ymm9,%ymm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 184,137,136,136,57 ; mov $0x39888889,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,227,121,4,210,0 ; vpermilps $0x0,%xmm2,%xmm2 + DB 196,227,109,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + DB 197,244,89,202 ; vmulps %ymm2,%ymm1,%ymm1 + DB 184,240,0,0,0 ; mov $0xf0,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 197,249,112,210,0 ; vpshufd $0x0,%xmm2,%xmm2 + DB 196,227,109,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + DB 196,193,108,84,209 ; vandps %ymm9,%ymm2,%ymm2 + DB 197,124,91,194 ; vcvtdq2ps %ymm2,%ymm8 + DB 184,137,136,136,59 ; mov $0x3b888889,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,227,121,4,210,0 ; vpermilps $0x0,%xmm2,%xmm2 + DB 196,227,109,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 184,15,0,0,0 ; mov $0xf,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 197,249,112,219,0 ; vpshufd $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 196,193,100,84,217 ; vandps %ymm9,%ymm3,%ymm3 + DB 197,124,91,195 ; vcvtdq2ps %ymm3,%ymm8 + DB 184,137,136,136,61 ; mov $0x3d888889,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 197,249,239,192 ; vpxor %xmm0,%xmm0,%xmm0 + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 15,135,249,254,255,255 ; ja 2998 <_sk_load_4444_avx+0x14> + DB 69,15,182,192 ; movzbl %r8b,%r8d + DB 76,141,13,74,0,0,0 ; lea 0x4a(%rip),%r9 # 2af4 <_sk_load_4444_avx+0x170> + DB 75,99,4,129 ; movslq (%r9,%r8,4),%rax + DB 76,1,200 ; add %r9,%rax + DB 255,224 ; jmpq *%rax + DB 197,249,239,192 ; vpxor %xmm0,%xmm0,%xmm0 + DB 196,193,121,196,68,122,12,6 ; vpinsrw $0x6,0xc(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,10,5 ; vpinsrw $0x5,0xa(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,8,4 ; vpinsrw $0x4,0x8(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,6,3 ; vpinsrw $0x3,0x6(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,4,2 ; vpinsrw $0x2,0x4(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,68,122,2,1 ; vpinsrw $0x1,0x2(%r10,%rdi,2),%xmm0,%xmm0 + DB 196,193,121,196,4,122,0 ; vpinsrw $0x0,(%r10,%rdi,2),%xmm0,%xmm0 + DB 233,165,254,255,255 ; jmpq 2998 <_sk_load_4444_avx+0x14> + DB 144 ; nop + DB 243,255 ; repz (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 235,255 ; jmp 2af9 <_sk_load_4444_avx+0x175> + DB 255 ; (bad) + DB 255,227 ; jmpq *%rbx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 219,255 ; (bad) + DB 255 ; (bad) + DB 255,211 ; callq *%rbx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,203 ; dec %ebx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 191 ; .byte 0xbf + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_gather_4444_avx +_sk_gather_4444_avx LABEL PROC + DB 85 ; push %rbp + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,209 ; vcvttps2dq %ymm1,%ymm2 + DB 197,249,110,72,16 ; vmovd 0x10(%rax),%xmm1 + DB 197,249,112,217,0 ; vpshufd $0x0,%xmm1,%xmm3 + DB 196,226,97,64,202 ; vpmulld %xmm2,%xmm3,%xmm1 + DB 196,227,125,25,210,1 ; vextractf128 $0x1,%ymm2,%xmm2 + DB 196,226,97,64,210 ; vpmulld %xmm2,%xmm3,%xmm2 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 196,227,125,25,195,1 ; vextractf128 $0x1,%ymm0,%xmm3 + DB 197,233,254,211 ; vpaddd %xmm3,%xmm2,%xmm2 + DB 196,227,249,22,208,1 ; vpextrq $0x1,%xmm2,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,210 ; vmovq %xmm2,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 197,241,254,192 ; vpaddd %xmm0,%xmm1,%xmm0 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,222 ; mov %ebx,%r14d + DB 196,195,249,22,199,1 ; vpextrq $0x1,%xmm0,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 72,193,235,32 ; shr $0x20,%rbx + DB 65,15,183,28,88 ; movzwl (%r8,%rbx,2),%ebx + DB 67,15,183,44,112 ; movzwl (%r8,%r14,2),%ebp + DB 197,249,110,197 ; vmovd %ebp,%xmm0 + DB 197,249,196,195,1 ; vpinsrw $0x1,%ebx,%xmm0,%xmm0 + DB 67,15,183,28,96 ; movzwl (%r8,%r12,2),%ebx + DB 197,249,196,195,2 ; vpinsrw $0x2,%ebx,%xmm0,%xmm0 + DB 67,15,183,28,120 ; movzwl (%r8,%r15,2),%ebx + DB 197,249,196,195,3 ; vpinsrw $0x3,%ebx,%xmm0,%xmm0 + DB 67,15,183,44,88 ; movzwl (%r8,%r11,2),%ebp + DB 197,249,196,197,4 ; vpinsrw $0x4,%ebp,%xmm0,%xmm0 + DB 67,15,183,44,80 ; movzwl (%r8,%r10,2),%ebp + DB 197,249,196,197,5 ; vpinsrw $0x5,%ebp,%xmm0,%xmm0 + DB 67,15,183,44,72 ; movzwl (%r8,%r9,2),%ebp + DB 197,249,196,197,6 ; vpinsrw $0x6,%ebp,%xmm0,%xmm0 + DB 65,15,183,4,64 ; movzwl (%r8,%rax,2),%eax + DB 197,249,196,192,7 ; vpinsrw $0x7,%eax,%xmm0,%xmm0 + DB 197,241,239,201 ; vpxor %xmm1,%xmm1,%xmm1 + DB 197,249,105,201 ; vpunpckhwd %xmm1,%xmm0,%xmm1 + DB 196,226,121,51,192 ; vpmovzxwd %xmm0,%xmm0 + DB 196,99,125,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm0,%ymm9 + DB 184,0,240,0,0 ; mov $0xf000,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 197,249,112,192,0 ; vpshufd $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 196,193,124,84,193 ; vandps %ymm9,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,137,136,136,55 ; mov $0x37888889,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,252,89,193 ; vmulps %ymm1,%ymm0,%ymm0 + DB 184,0,15,0,0 ; mov $0xf00,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 197,249,112,201,0 ; vpshufd $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 196,193,116,84,201 ; vandps %ymm9,%ymm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 184,137,136,136,57 ; mov $0x39888889,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,227,121,4,210,0 ; vpermilps $0x0,%xmm2,%xmm2 + DB 196,227,109,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + DB 197,244,89,202 ; vmulps %ymm2,%ymm1,%ymm1 + DB 184,240,0,0,0 ; mov $0xf0,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 197,249,112,210,0 ; vpshufd $0x0,%xmm2,%xmm2 + DB 196,227,109,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + DB 196,193,108,84,209 ; vandps %ymm9,%ymm2,%ymm2 + DB 197,124,91,194 ; vcvtdq2ps %ymm2,%ymm8 + DB 184,137,136,136,59 ; mov $0x3b888889,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 196,227,121,4,210,0 ; vpermilps $0x0,%xmm2,%xmm2 + DB 196,227,109,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm2 + DB 197,188,89,210 ; vmulps %ymm2,%ymm8,%ymm2 + DB 184,15,0,0,0 ; mov $0xf,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 197,249,112,219,0 ; vpshufd $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 196,193,100,84,217 ; vandps %ymm9,%ymm3,%ymm3 + DB 197,124,91,195 ; vcvtdq2ps %ymm3,%ymm8 + DB 184,137,136,136,61 ; mov $0x3d888889,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,188,89,219 ; vmulps %ymm3,%ymm8,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 93 ; pop %rbp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_4444_avx +_sk_store_4444_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 184,0,0,112,65 ; mov $0x41700000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 196,65,125,91,201 ; vcvtps2dq %ymm9,%ymm9 + DB 196,193,41,114,241,12 ; vpslld $0xc,%xmm9,%xmm10 + DB 196,67,125,25,201,1 ; vextractf128 $0x1,%ymm9,%xmm9 + DB 196,193,49,114,241,12 ; vpslld $0xc,%xmm9,%xmm9 + DB 196,67,45,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm10,%ymm9 + DB 197,60,89,209 ; vmulps %ymm1,%ymm8,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,193,33,114,242,8 ; vpslld $0x8,%xmm10,%xmm11 + DB 196,67,125,25,210,1 ; vextractf128 $0x1,%ymm10,%xmm10 + DB 196,193,41,114,242,8 ; vpslld $0x8,%xmm10,%xmm10 + DB 196,67,37,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm11,%ymm10 + DB 196,65,45,86,201 ; vorpd %ymm9,%ymm10,%ymm9 + DB 197,60,89,210 ; vmulps %ymm2,%ymm8,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,193,33,114,242,4 ; vpslld $0x4,%xmm10,%xmm11 + DB 196,67,125,25,210,1 ; vextractf128 $0x1,%ymm10,%xmm10 + DB 196,193,41,114,242,4 ; vpslld $0x4,%xmm10,%xmm10 + DB 196,67,37,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm11,%ymm10 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 196,65,125,91,192 ; vcvtps2dq %ymm8,%ymm8 + DB 196,65,45,86,192 ; vorpd %ymm8,%ymm10,%ymm8 + DB 196,65,53,86,192 ; vorpd %ymm8,%ymm9,%ymm8 + DB 196,67,125,25,193,1 ; vextractf128 $0x1,%ymm8,%xmm9 + DB 196,66,57,43,193 ; vpackusdw %xmm9,%xmm8,%xmm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,10 ; jne 2d74 <_sk_store_4444_avx+0xaf> + DB 196,65,122,127,4,121 ; vmovdqu %xmm8,(%r9,%rdi,2) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 119,236 ; ja 2d70 <_sk_store_4444_avx+0xab> + DB 65,15,182,192 ; movzbl %r8b,%eax + DB 76,141,5,69,0,0,0 ; lea 0x45(%rip),%r8 # 2dd4 <_sk_store_4444_avx+0x10f> + DB 73,99,4,128 ; movslq (%r8,%rax,4),%rax + DB 76,1,192 ; add %r8,%rax + DB 255,224 ; jmpq *%rax + DB 196,67,121,21,68,121,12,6 ; vpextrw $0x6,%xmm8,0xc(%r9,%rdi,2) + DB 196,67,121,21,68,121,10,5 ; vpextrw $0x5,%xmm8,0xa(%r9,%rdi,2) + DB 196,67,121,21,68,121,8,4 ; vpextrw $0x4,%xmm8,0x8(%r9,%rdi,2) + DB 196,67,121,21,68,121,6,3 ; vpextrw $0x3,%xmm8,0x6(%r9,%rdi,2) + DB 196,67,121,21,68,121,4,2 ; vpextrw $0x2,%xmm8,0x4(%r9,%rdi,2) + DB 196,67,121,21,68,121,2,1 ; vpextrw $0x1,%xmm8,0x2(%r9,%rdi,2) + DB 196,67,121,21,4,121,0 ; vpextrw $0x0,%xmm8,(%r9,%rdi,2) + DB 235,159 ; jmp 2d70 <_sk_store_4444_avx+0xab> + DB 15,31,0 ; nopl (%rax) + DB 244 ; hlt + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 236 ; in (%dx),%al + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,228 ; jmpq *%rsp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 220,255 ; fdivr %st,%st(7) + DB 255 ; (bad) + DB 255,212 ; callq *%rsp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,204 ; dec %esp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,196 ; inc %esp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_load_8888_avx +_sk_load_8888_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,16 ; mov (%rax),%r10 + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,157,0,0,0 ; jne 2e9b <_sk_load_8888_avx+0xab> + DB 196,65,124,16,12,186 ; vmovups (%r10,%rdi,4),%ymm9 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 197,249,112,192,0 ; vpshufd $0x0,%xmm0,%xmm0 + DB 196,99,125,24,216,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm11 + DB 196,193,36,84,193 ; vandps %ymm9,%ymm11,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,99,117,24,193,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm8 + DB 196,193,124,89,192 ; vmulps %ymm8,%ymm0,%ymm0 + DB 196,193,41,114,209,8 ; vpsrld $0x8,%xmm9,%xmm10 + DB 196,99,125,25,203,1 ; vextractf128 $0x1,%ymm9,%xmm3 + DB 197,241,114,211,8 ; vpsrld $0x8,%xmm3,%xmm1 + DB 196,227,45,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm10,%ymm1 + DB 197,164,84,201 ; vandps %ymm1,%ymm11,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 196,193,116,89,200 ; vmulps %ymm8,%ymm1,%ymm1 + DB 196,193,41,114,209,16 ; vpsrld $0x10,%xmm9,%xmm10 + DB 197,233,114,211,16 ; vpsrld $0x10,%xmm3,%xmm2 + DB 196,227,45,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm10,%ymm2 + DB 197,164,84,210 ; vandps %ymm2,%ymm11,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 196,193,108,89,208 ; vmulps %ymm8,%ymm2,%ymm2 + DB 196,193,49,114,209,24 ; vpsrld $0x18,%xmm9,%xmm9 + DB 197,225,114,211,24 ; vpsrld $0x18,%xmm3,%xmm3 + DB 196,227,53,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm9,%ymm3 + DB 197,252,91,219 ; vcvtdq2ps %ymm3,%ymm3 + DB 196,193,100,89,216 ; vmulps %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 196,65,52,87,201 ; vxorps %ymm9,%ymm9,%ymm9 + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 15,135,80,255,255,255 ; ja 2e04 <_sk_load_8888_avx+0x14> + DB 69,15,182,192 ; movzbl %r8b,%r8d + DB 76,141,13,137,0,0,0 ; lea 0x89(%rip),%r9 # 2f48 <_sk_load_8888_avx+0x158> + DB 75,99,4,129 ; movslq (%r9,%r8,4),%rax + DB 76,1,200 ; add %r9,%rax + DB 255,224 ; jmpq *%rax + DB 196,193,121,110,68,186,24 ; vmovd 0x18(%r10,%rdi,4),%xmm0 + DB 197,249,112,192,68 ; vpshufd $0x44,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 196,99,117,12,200,64 ; vblendps $0x40,%ymm0,%ymm1,%ymm9 + DB 196,99,125,25,200,1 ; vextractf128 $0x1,%ymm9,%xmm0 + DB 196,195,121,34,68,186,20,1 ; vpinsrd $0x1,0x14(%r10,%rdi,4),%xmm0,%xmm0 + DB 196,99,53,24,200,1 ; vinsertf128 $0x1,%xmm0,%ymm9,%ymm9 + DB 196,99,125,25,200,1 ; vextractf128 $0x1,%ymm9,%xmm0 + DB 196,195,121,34,68,186,16,0 ; vpinsrd $0x0,0x10(%r10,%rdi,4),%xmm0,%xmm0 + DB 196,99,53,24,200,1 ; vinsertf128 $0x1,%xmm0,%ymm9,%ymm9 + DB 196,195,49,34,68,186,12,3 ; vpinsrd $0x3,0xc(%r10,%rdi,4),%xmm9,%xmm0 + DB 196,99,53,12,200,15 ; vblendps $0xf,%ymm0,%ymm9,%ymm9 + DB 196,195,49,34,68,186,8,2 ; vpinsrd $0x2,0x8(%r10,%rdi,4),%xmm9,%xmm0 + DB 196,99,53,12,200,15 ; vblendps $0xf,%ymm0,%ymm9,%ymm9 + DB 196,195,49,34,68,186,4,1 ; vpinsrd $0x1,0x4(%r10,%rdi,4),%xmm9,%xmm0 + DB 196,99,53,12,200,15 ; vblendps $0xf,%ymm0,%ymm9,%ymm9 + DB 196,195,49,34,4,186,0 ; vpinsrd $0x0,(%r10,%rdi,4),%xmm9,%xmm0 + DB 196,99,53,12,200,15 ; vblendps $0xf,%ymm0,%ymm9,%ymm9 + DB 233,188,254,255,255 ; jmpq 2e04 <_sk_load_8888_avx+0x14> + DB 238 ; out %al,(%dx) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,224 ; jmpq *%rax + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,210 ; callq *%rdx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,196 ; inc %esp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,176,255,255,255,156 ; pushq -0x63000001(%rax) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + DB 128,255,255 ; cmp $0xff,%bh + DB 255 ; .byte 0xff + +PUBLIC _sk_gather_8888_avx +_sk_gather_8888_avx LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,201 ; vcvttps2dq %ymm1,%ymm1 + DB 197,249,110,80,16 ; vmovd 0x10(%rax),%xmm2 + DB 197,249,112,210,0 ; vpshufd $0x0,%xmm2,%xmm2 + DB 196,226,105,64,217 ; vpmulld %xmm1,%xmm2,%xmm3 + DB 196,227,125,25,201,1 ; vextractf128 $0x1,%ymm1,%xmm1 + DB 196,226,105,64,201 ; vpmulld %xmm1,%xmm2,%xmm1 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 196,227,125,25,194,1 ; vextractf128 $0x1,%ymm0,%xmm2 + DB 197,241,254,202 ; vpaddd %xmm2,%xmm1,%xmm1 + DB 196,225,249,126,200 ; vmovq %xmm1,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,195,249,22,202,1 ; vpextrq $0x1,%xmm1,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 197,225,254,192 ; vpaddd %xmm0,%xmm3,%xmm0 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,222 ; mov %ebx,%r14d + DB 196,195,249,22,199,1 ; vpextrq $0x1,%xmm0,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 73,193,239,32 ; shr $0x20,%r15 + DB 196,129,121,110,4,176 ; vmovd (%r8,%r14,4),%xmm0 + DB 196,195,121,34,4,152,1 ; vpinsrd $0x1,(%r8,%rbx,4),%xmm0,%xmm0 + DB 196,131,121,34,4,160,2 ; vpinsrd $0x2,(%r8,%r12,4),%xmm0,%xmm0 + DB 196,3,121,34,4,184,3 ; vpinsrd $0x3,(%r8,%r15,4),%xmm0,%xmm8 + DB 196,129,121,110,4,136 ; vmovd (%r8,%r9,4),%xmm0 + DB 196,195,121,34,4,128,1 ; vpinsrd $0x1,(%r8,%rax,4),%xmm0,%xmm0 + DB 196,131,121,34,4,152,2 ; vpinsrd $0x2,(%r8,%r11,4),%xmm0,%xmm0 + DB 196,131,121,34,28,144,3 ; vpinsrd $0x3,(%r8,%r10,4),%xmm0,%xmm3 + DB 196,227,61,24,195,1 ; vinsertf128 $0x1,%xmm3,%ymm8,%ymm0 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 197,249,112,201,0 ; vpshufd $0x0,%xmm1,%xmm1 + DB 196,99,117,24,217,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm11 + DB 197,164,84,192 ; vandps %ymm0,%ymm11,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,99,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm9 + DB 196,193,124,89,193 ; vmulps %ymm9,%ymm0,%ymm0 + DB 196,193,41,114,208,8 ; vpsrld $0x8,%xmm8,%xmm10 + DB 197,241,114,211,8 ; vpsrld $0x8,%xmm3,%xmm1 + DB 196,227,45,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm10,%ymm1 + DB 197,164,84,201 ; vandps %ymm1,%ymm11,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 196,193,116,89,201 ; vmulps %ymm9,%ymm1,%ymm1 + DB 196,193,41,114,208,16 ; vpsrld $0x10,%xmm8,%xmm10 + DB 197,233,114,211,16 ; vpsrld $0x10,%xmm3,%xmm2 + DB 196,227,45,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm10,%ymm2 + DB 197,164,84,210 ; vandps %ymm2,%ymm11,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 196,193,108,89,209 ; vmulps %ymm9,%ymm2,%ymm2 + DB 196,193,57,114,208,24 ; vpsrld $0x18,%xmm8,%xmm8 + DB 197,225,114,211,24 ; vpsrld $0x18,%xmm3,%xmm3 + DB 196,227,61,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + DB 197,252,91,219 ; vcvtdq2ps %ymm3,%ymm3 + DB 196,193,100,89,217 ; vmulps %ymm9,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_8888_avx +_sk_store_8888_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 184,0,0,127,67 ; mov $0x437f0000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 196,65,125,91,201 ; vcvtps2dq %ymm9,%ymm9 + DB 197,60,89,209 ; vmulps %ymm1,%ymm8,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,193,33,114,242,8 ; vpslld $0x8,%xmm10,%xmm11 + DB 196,67,125,25,210,1 ; vextractf128 $0x1,%ymm10,%xmm10 + DB 196,193,41,114,242,8 ; vpslld $0x8,%xmm10,%xmm10 + DB 196,67,37,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm11,%ymm10 + DB 196,65,45,86,201 ; vorpd %ymm9,%ymm10,%ymm9 + DB 197,60,89,210 ; vmulps %ymm2,%ymm8,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,193,33,114,242,16 ; vpslld $0x10,%xmm10,%xmm11 + DB 196,67,125,25,210,1 ; vextractf128 $0x1,%ymm10,%xmm10 + DB 196,193,41,114,242,16 ; vpslld $0x10,%xmm10,%xmm10 + DB 196,67,37,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm11,%ymm10 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 196,65,125,91,192 ; vcvtps2dq %ymm8,%ymm8 + DB 196,193,33,114,240,24 ; vpslld $0x18,%xmm8,%xmm11 + DB 196,67,125,25,192,1 ; vextractf128 $0x1,%ymm8,%xmm8 + DB 196,193,57,114,240,24 ; vpslld $0x18,%xmm8,%xmm8 + DB 196,67,37,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm11,%ymm8 + DB 196,65,45,86,192 ; vorpd %ymm8,%ymm10,%ymm8 + DB 196,65,53,86,192 ; vorpd %ymm8,%ymm9,%ymm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,10 ; jne 3149 <_sk_store_8888_avx+0xa4> + DB 196,65,124,17,4,185 ; vmovups %ymm8,(%r9,%rdi,4) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 65,128,224,7 ; and $0x7,%r8b + DB 65,254,200 ; dec %r8b + DB 65,128,248,6 ; cmp $0x6,%r8b + DB 119,236 ; ja 3145 <_sk_store_8888_avx+0xa0> + DB 65,15,182,192 ; movzbl %r8b,%eax + DB 76,141,5,84,0,0,0 ; lea 0x54(%rip),%r8 # 31b8 <_sk_store_8888_avx+0x113> + DB 73,99,4,128 ; movslq (%r8,%rax,4),%rax + DB 76,1,192 ; add %r8,%rax + DB 255,224 ; jmpq *%rax + DB 196,67,125,25,193,1 ; vextractf128 $0x1,%ymm8,%xmm9 + DB 196,67,121,22,76,185,24,2 ; vpextrd $0x2,%xmm9,0x18(%r9,%rdi,4) + DB 196,67,125,25,193,1 ; vextractf128 $0x1,%ymm8,%xmm9 + DB 196,67,121,22,76,185,20,1 ; vpextrd $0x1,%xmm9,0x14(%r9,%rdi,4) + DB 196,67,125,25,193,1 ; vextractf128 $0x1,%ymm8,%xmm9 + DB 196,65,122,17,76,185,16 ; vmovss %xmm9,0x10(%r9,%rdi,4) + DB 196,67,121,22,68,185,12,3 ; vpextrd $0x3,%xmm8,0xc(%r9,%rdi,4) + DB 196,67,121,22,68,185,8,2 ; vpextrd $0x2,%xmm8,0x8(%r9,%rdi,4) + DB 196,67,121,22,68,185,4,1 ; vpextrd $0x1,%xmm8,0x4(%r9,%rdi,4) + DB 196,65,121,126,4,185 ; vmovd %xmm8,(%r9,%rdi,4) + DB 235,143 ; jmp 3145 <_sk_store_8888_avx+0xa0> + DB 102,144 ; xchg %ax,%ax + DB 246,255 ; idiv %bh + DB 255 ; (bad) + DB 255 ; (bad) + DB 238 ; out %al,(%dx) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,230 ; jmpq *%rsi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 222,255 ; fdivrp %st,%st(7) + DB 255 ; (bad) + DB 255,209 ; callq *%rcx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,195 ; inc %ebx + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + DB 181,255 ; mov $0xff,%ch + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_load_f16_avx +_sk_load_f16_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,17,1,0,0 ; jne 32f3 <_sk_load_f16_avx+0x11f> + DB 197,121,16,4,248 ; vmovupd (%rax,%rdi,8),%xmm8 + DB 197,249,16,84,248,16 ; vmovupd 0x10(%rax,%rdi,8),%xmm2 + DB 197,249,16,92,248,32 ; vmovupd 0x20(%rax,%rdi,8),%xmm3 + DB 197,122,111,76,248,48 ; vmovdqu 0x30(%rax,%rdi,8),%xmm9 + DB 197,185,97,194 ; vpunpcklwd %xmm2,%xmm8,%xmm0 + DB 197,185,105,210 ; vpunpckhwd %xmm2,%xmm8,%xmm2 + DB 196,193,97,97,201 ; vpunpcklwd %xmm9,%xmm3,%xmm1 + DB 196,193,97,105,217 ; vpunpckhwd %xmm9,%xmm3,%xmm3 + DB 197,121,97,218 ; vpunpcklwd %xmm2,%xmm0,%xmm11 + DB 197,121,105,194 ; vpunpckhwd %xmm2,%xmm0,%xmm8 + DB 197,241,97,211 ; vpunpcklwd %xmm3,%xmm1,%xmm2 + DB 197,113,105,203 ; vpunpckhwd %xmm3,%xmm1,%xmm9 + DB 197,161,108,194 ; vpunpcklqdq %xmm2,%xmm11,%xmm0 + DB 184,0,4,0,4 ; mov $0x4000400,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 197,121,112,233,0 ; vpshufd $0x0,%xmm1,%xmm13 + DB 197,145,101,200 ; vpcmpgtw %xmm0,%xmm13,%xmm1 + DB 197,241,223,192 ; vpandn %xmm0,%xmm1,%xmm0 + DB 196,226,121,51,200 ; vpmovzxwd %xmm0,%xmm1 + DB 196,65,41,239,210 ; vpxor %xmm10,%xmm10,%xmm10 + DB 196,193,121,105,194 ; vpunpckhwd %xmm10,%xmm0,%xmm0 + DB 197,241,114,241,13 ; vpslld $0xd,%xmm1,%xmm1 + DB 197,249,114,240,13 ; vpslld $0xd,%xmm0,%xmm0 + DB 196,227,117,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm1,%ymm0 + DB 184,0,0,128,119 ; mov $0x77800000,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 197,249,112,201,0 ; vpshufd $0x0,%xmm1,%xmm1 + DB 196,99,117,24,225,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm12 + DB 197,156,89,192 ; vmulps %ymm0,%ymm12,%ymm0 + DB 197,161,109,202 ; vpunpckhqdq %xmm2,%xmm11,%xmm1 + DB 197,145,101,209 ; vpcmpgtw %xmm1,%xmm13,%xmm2 + DB 197,233,223,201 ; vpandn %xmm1,%xmm2,%xmm1 + DB 196,226,121,51,209 ; vpmovzxwd %xmm1,%xmm2 + DB 196,193,113,105,202 ; vpunpckhwd %xmm10,%xmm1,%xmm1 + DB 197,233,114,242,13 ; vpslld $0xd,%xmm2,%xmm2 + DB 197,241,114,241,13 ; vpslld $0xd,%xmm1,%xmm1 + DB 196,227,109,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm2,%ymm1 + DB 197,156,89,201 ; vmulps %ymm1,%ymm12,%ymm1 + DB 196,193,57,108,209 ; vpunpcklqdq %xmm9,%xmm8,%xmm2 + DB 197,145,101,218 ; vpcmpgtw %xmm2,%xmm13,%xmm3 + DB 197,225,223,210 ; vpandn %xmm2,%xmm3,%xmm2 + DB 196,226,121,51,218 ; vpmovzxwd %xmm2,%xmm3 + DB 196,193,105,105,210 ; vpunpckhwd %xmm10,%xmm2,%xmm2 + DB 197,225,114,243,13 ; vpslld $0xd,%xmm3,%xmm3 + DB 197,233,114,242,13 ; vpslld $0xd,%xmm2,%xmm2 + DB 196,227,101,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm3,%ymm2 + DB 197,156,89,210 ; vmulps %ymm2,%ymm12,%ymm2 + DB 196,65,57,109,193 ; vpunpckhqdq %xmm9,%xmm8,%xmm8 + DB 196,193,17,101,216 ; vpcmpgtw %xmm8,%xmm13,%xmm3 + DB 196,193,97,223,216 ; vpandn %xmm8,%xmm3,%xmm3 + DB 196,98,121,51,195 ; vpmovzxwd %xmm3,%xmm8 + DB 196,193,97,105,218 ; vpunpckhwd %xmm10,%xmm3,%xmm3 + DB 196,193,57,114,240,13 ; vpslld $0xd,%xmm8,%xmm8 + DB 197,225,114,243,13 ; vpslld $0xd,%xmm3,%xmm3 + DB 196,227,61,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + DB 197,156,89,219 ; vmulps %ymm3,%ymm12,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 197,123,16,4,248 ; vmovsd (%rax,%rdi,8),%xmm8 + DB 196,65,49,239,201 ; vpxor %xmm9,%xmm9,%xmm9 + DB 72,131,249,1 ; cmp $0x1,%rcx + DB 116,79 ; je 3352 <_sk_load_f16_avx+0x17e> + DB 197,57,22,68,248,8 ; vmovhpd 0x8(%rax,%rdi,8),%xmm8,%xmm8 + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 114,67 ; jb 3352 <_sk_load_f16_avx+0x17e> + DB 197,251,16,84,248,16 ; vmovsd 0x10(%rax,%rdi,8),%xmm2 + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 116,68 ; je 335f <_sk_load_f16_avx+0x18b> + DB 197,233,22,84,248,24 ; vmovhpd 0x18(%rax,%rdi,8),%xmm2,%xmm2 + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 114,56 ; jb 335f <_sk_load_f16_avx+0x18b> + DB 197,251,16,92,248,32 ; vmovsd 0x20(%rax,%rdi,8),%xmm3 + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 15,132,194,254,255,255 ; je 31f9 <_sk_load_f16_avx+0x25> + DB 197,225,22,92,248,40 ; vmovhpd 0x28(%rax,%rdi,8),%xmm3,%xmm3 + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 15,130,178,254,255,255 ; jb 31f9 <_sk_load_f16_avx+0x25> + DB 197,122,126,76,248,48 ; vmovq 0x30(%rax,%rdi,8),%xmm9 + DB 233,167,254,255,255 ; jmpq 31f9 <_sk_load_f16_avx+0x25> + DB 197,225,87,219 ; vxorpd %xmm3,%xmm3,%xmm3 + DB 197,233,87,210 ; vxorpd %xmm2,%xmm2,%xmm2 + DB 233,154,254,255,255 ; jmpq 31f9 <_sk_load_f16_avx+0x25> + DB 197,225,87,219 ; vxorpd %xmm3,%xmm3,%xmm3 + DB 233,145,254,255,255 ; jmpq 31f9 <_sk_load_f16_avx+0x25> + +PUBLIC _sk_gather_f16_avx +_sk_gather_f16_avx LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,84 ; push %r12 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 197,254,91,209 ; vcvttps2dq %ymm1,%ymm2 + DB 197,249,110,72,16 ; vmovd 0x10(%rax),%xmm1 + DB 197,249,112,217,0 ; vpshufd $0x0,%xmm1,%xmm3 + DB 196,226,97,64,202 ; vpmulld %xmm2,%xmm3,%xmm1 + DB 196,227,125,25,210,1 ; vextractf128 $0x1,%ymm2,%xmm2 + DB 196,226,97,64,210 ; vpmulld %xmm2,%xmm3,%xmm2 + DB 197,254,91,192 ; vcvttps2dq %ymm0,%ymm0 + DB 196,227,125,25,195,1 ; vextractf128 $0x1,%ymm0,%xmm3 + DB 197,233,254,211 ; vpaddd %xmm3,%xmm2,%xmm2 + DB 196,227,249,22,208,1 ; vpextrq $0x1,%xmm2,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 196,193,249,126,210 ; vmovq %xmm2,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 197,241,254,192 ; vpaddd %xmm0,%xmm1,%xmm0 + DB 196,225,249,126,195 ; vmovq %xmm0,%rbx + DB 65,137,222 ; mov %ebx,%r14d + DB 196,195,249,22,199,1 ; vpextrq $0x1,%xmm0,%r15 + DB 69,137,252 ; mov %r15d,%r12d + DB 73,193,239,32 ; shr $0x20,%r15 + DB 72,193,235,32 ; shr $0x20,%rbx + DB 196,193,122,126,4,216 ; vmovq (%r8,%rbx,8),%xmm0 + DB 196,129,122,126,12,240 ; vmovq (%r8,%r14,8),%xmm1 + DB 197,113,108,200 ; vpunpcklqdq %xmm0,%xmm1,%xmm9 + DB 196,129,122,126,12,248 ; vmovq (%r8,%r15,8),%xmm1 + DB 196,129,122,126,20,224 ; vmovq (%r8,%r12,8),%xmm2 + DB 197,233,108,201 ; vpunpcklqdq %xmm1,%xmm2,%xmm1 + DB 196,129,122,126,20,208 ; vmovq (%r8,%r10,8),%xmm2 + DB 196,129,122,126,28,216 ; vmovq (%r8,%r11,8),%xmm3 + DB 197,97,108,210 ; vpunpcklqdq %xmm2,%xmm3,%xmm10 + DB 196,65,122,126,4,192 ; vmovq (%r8,%rax,8),%xmm8 + DB 196,129,122,126,28,200 ; vmovq (%r8,%r9,8),%xmm3 + DB 196,193,97,108,216 ; vpunpcklqdq %xmm8,%xmm3,%xmm3 + DB 197,177,97,193 ; vpunpcklwd %xmm1,%xmm9,%xmm0 + DB 197,177,105,201 ; vpunpckhwd %xmm1,%xmm9,%xmm1 + DB 197,169,97,211 ; vpunpcklwd %xmm3,%xmm10,%xmm2 + DB 197,169,105,219 ; vpunpckhwd %xmm3,%xmm10,%xmm3 + DB 197,121,97,217 ; vpunpcklwd %xmm1,%xmm0,%xmm11 + DB 197,121,105,193 ; vpunpckhwd %xmm1,%xmm0,%xmm8 + DB 197,233,97,203 ; vpunpcklwd %xmm3,%xmm2,%xmm1 + DB 197,105,105,203 ; vpunpckhwd %xmm3,%xmm2,%xmm9 + DB 197,161,108,193 ; vpunpcklqdq %xmm1,%xmm11,%xmm0 + DB 184,0,4,0,4 ; mov $0x4000400,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 197,121,112,234,0 ; vpshufd $0x0,%xmm2,%xmm13 + DB 197,145,101,208 ; vpcmpgtw %xmm0,%xmm13,%xmm2 + DB 197,233,223,192 ; vpandn %xmm0,%xmm2,%xmm0 + DB 196,226,121,51,208 ; vpmovzxwd %xmm0,%xmm2 + DB 196,65,41,239,210 ; vpxor %xmm10,%xmm10,%xmm10 + DB 196,193,121,105,194 ; vpunpckhwd %xmm10,%xmm0,%xmm0 + DB 197,233,114,242,13 ; vpslld $0xd,%xmm2,%xmm2 + DB 197,249,114,240,13 ; vpslld $0xd,%xmm0,%xmm0 + DB 196,227,109,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm2,%ymm0 + DB 184,0,0,128,119 ; mov $0x77800000,%eax + DB 197,249,110,208 ; vmovd %eax,%xmm2 + DB 197,249,112,210,0 ; vpshufd $0x0,%xmm2,%xmm2 + DB 196,99,109,24,226,1 ; vinsertf128 $0x1,%xmm2,%ymm2,%ymm12 + DB 197,156,89,192 ; vmulps %ymm0,%ymm12,%ymm0 + DB 197,161,109,201 ; vpunpckhqdq %xmm1,%xmm11,%xmm1 + DB 197,145,101,209 ; vpcmpgtw %xmm1,%xmm13,%xmm2 + DB 197,233,223,201 ; vpandn %xmm1,%xmm2,%xmm1 + DB 196,226,121,51,209 ; vpmovzxwd %xmm1,%xmm2 + DB 196,193,113,105,202 ; vpunpckhwd %xmm10,%xmm1,%xmm1 + DB 197,233,114,242,13 ; vpslld $0xd,%xmm2,%xmm2 + DB 197,241,114,241,13 ; vpslld $0xd,%xmm1,%xmm1 + DB 196,227,109,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm2,%ymm1 + DB 197,156,89,201 ; vmulps %ymm1,%ymm12,%ymm1 + DB 196,193,57,108,209 ; vpunpcklqdq %xmm9,%xmm8,%xmm2 + DB 197,145,101,218 ; vpcmpgtw %xmm2,%xmm13,%xmm3 + DB 197,225,223,210 ; vpandn %xmm2,%xmm3,%xmm2 + DB 196,226,121,51,218 ; vpmovzxwd %xmm2,%xmm3 + DB 196,193,105,105,210 ; vpunpckhwd %xmm10,%xmm2,%xmm2 + DB 197,225,114,243,13 ; vpslld $0xd,%xmm3,%xmm3 + DB 197,233,114,242,13 ; vpslld $0xd,%xmm2,%xmm2 + DB 196,227,101,24,210,1 ; vinsertf128 $0x1,%xmm2,%ymm3,%ymm2 + DB 197,156,89,210 ; vmulps %ymm2,%ymm12,%ymm2 + DB 196,65,57,109,193 ; vpunpckhqdq %xmm9,%xmm8,%xmm8 + DB 196,193,17,101,216 ; vpcmpgtw %xmm8,%xmm13,%xmm3 + DB 196,193,97,223,216 ; vpandn %xmm8,%xmm3,%xmm3 + DB 196,98,121,51,195 ; vpmovzxwd %xmm3,%xmm8 + DB 196,193,97,105,218 ; vpunpckhwd %xmm10,%xmm3,%xmm3 + DB 196,193,57,114,240,13 ; vpslld $0xd,%xmm8,%xmm8 + DB 197,225,114,243,13 ; vpslld $0xd,%xmm3,%xmm3 + DB 196,227,61,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm8,%ymm3 + DB 197,156,89,219 ; vmulps %ymm3,%ymm12,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,92 ; pop %r12 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_f16_avx +_sk_store_f16_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 184,0,0,128,7 ; mov $0x7800000,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,65,121,112,192,0 ; vpshufd $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 196,67,125,25,202,1 ; vextractf128 $0x1,%ymm9,%xmm10 + DB 196,193,41,114,210,13 ; vpsrld $0xd,%xmm10,%xmm10 + DB 196,193,49,114,209,13 ; vpsrld $0xd,%xmm9,%xmm9 + DB 196,66,49,43,202 ; vpackusdw %xmm10,%xmm9,%xmm9 + DB 197,60,89,209 ; vmulps %ymm1,%ymm8,%ymm10 + DB 196,67,125,25,211,1 ; vextractf128 $0x1,%ymm10,%xmm11 + DB 196,193,33,114,211,13 ; vpsrld $0xd,%xmm11,%xmm11 + DB 196,193,41,114,210,13 ; vpsrld $0xd,%xmm10,%xmm10 + DB 196,66,41,43,211 ; vpackusdw %xmm11,%xmm10,%xmm10 + DB 197,60,89,218 ; vmulps %ymm2,%ymm8,%ymm11 + DB 196,67,125,25,220,1 ; vextractf128 $0x1,%ymm11,%xmm12 + DB 196,193,25,114,212,13 ; vpsrld $0xd,%xmm12,%xmm12 + DB 196,193,33,114,211,13 ; vpsrld $0xd,%xmm11,%xmm11 + DB 196,66,33,43,220 ; vpackusdw %xmm12,%xmm11,%xmm11 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 196,67,125,25,196,1 ; vextractf128 $0x1,%ymm8,%xmm12 + DB 196,193,25,114,212,13 ; vpsrld $0xd,%xmm12,%xmm12 + DB 196,193,57,114,208,13 ; vpsrld $0xd,%xmm8,%xmm8 + DB 196,66,57,43,196 ; vpackusdw %xmm12,%xmm8,%xmm8 + DB 196,65,49,97,226 ; vpunpcklwd %xmm10,%xmm9,%xmm12 + DB 196,65,49,105,234 ; vpunpckhwd %xmm10,%xmm9,%xmm13 + DB 196,65,33,97,200 ; vpunpcklwd %xmm8,%xmm11,%xmm9 + DB 196,65,33,105,192 ; vpunpckhwd %xmm8,%xmm11,%xmm8 + DB 196,65,25,98,217 ; vpunpckldq %xmm9,%xmm12,%xmm11 + DB 196,65,25,106,209 ; vpunpckhdq %xmm9,%xmm12,%xmm10 + DB 196,65,17,98,200 ; vpunpckldq %xmm8,%xmm13,%xmm9 + DB 196,65,17,106,192 ; vpunpckhdq %xmm8,%xmm13,%xmm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,31 ; jne 35e8 <_sk_store_f16_avx+0xd2> + DB 196,65,120,17,28,248 ; vmovups %xmm11,(%r8,%rdi,8) + DB 196,65,120,17,84,248,16 ; vmovups %xmm10,0x10(%r8,%rdi,8) + DB 196,65,120,17,76,248,32 ; vmovups %xmm9,0x20(%r8,%rdi,8) + DB 196,65,122,127,68,248,48 ; vmovdqu %xmm8,0x30(%r8,%rdi,8) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 196,65,121,214,28,248 ; vmovq %xmm11,(%r8,%rdi,8) + DB 72,131,249,1 ; cmp $0x1,%rcx + DB 116,240 ; je 35e4 <_sk_store_f16_avx+0xce> + DB 196,65,121,23,92,248,8 ; vmovhpd %xmm11,0x8(%r8,%rdi,8) + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 114,227 ; jb 35e4 <_sk_store_f16_avx+0xce> + DB 196,65,121,214,84,248,16 ; vmovq %xmm10,0x10(%r8,%rdi,8) + DB 116,218 ; je 35e4 <_sk_store_f16_avx+0xce> + DB 196,65,121,23,84,248,24 ; vmovhpd %xmm10,0x18(%r8,%rdi,8) + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 114,205 ; jb 35e4 <_sk_store_f16_avx+0xce> + DB 196,65,121,214,76,248,32 ; vmovq %xmm9,0x20(%r8,%rdi,8) + DB 116,196 ; je 35e4 <_sk_store_f16_avx+0xce> + DB 196,65,121,23,76,248,40 ; vmovhpd %xmm9,0x28(%r8,%rdi,8) + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 114,183 ; jb 35e4 <_sk_store_f16_avx+0xce> + DB 196,65,121,214,68,248,48 ; vmovq %xmm8,0x30(%r8,%rdi,8) + DB 235,174 ; jmp 35e4 <_sk_store_f16_avx+0xce> + +PUBLIC _sk_load_u16_be_avx +_sk_load_u16_be_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,133,201 ; test %rcx,%rcx + DB 15,133,1,1,0,0 ; jne 3745 <_sk_load_u16_be_avx+0x10f> + DB 197,121,16,4,248 ; vmovupd (%rax,%rdi,8),%xmm8 + DB 197,249,16,84,248,16 ; vmovupd 0x10(%rax,%rdi,8),%xmm2 + DB 197,249,16,92,248,32 ; vmovupd 0x20(%rax,%rdi,8),%xmm3 + DB 197,122,111,76,248,48 ; vmovdqu 0x30(%rax,%rdi,8),%xmm9 + DB 197,185,97,194 ; vpunpcklwd %xmm2,%xmm8,%xmm0 + DB 197,185,105,210 ; vpunpckhwd %xmm2,%xmm8,%xmm2 + DB 196,193,97,97,201 ; vpunpcklwd %xmm9,%xmm3,%xmm1 + DB 196,193,97,105,217 ; vpunpckhwd %xmm9,%xmm3,%xmm3 + DB 197,121,97,210 ; vpunpcklwd %xmm2,%xmm0,%xmm10 + DB 197,121,105,194 ; vpunpckhwd %xmm2,%xmm0,%xmm8 + DB 197,241,97,211 ; vpunpcklwd %xmm3,%xmm1,%xmm2 + DB 197,113,105,203 ; vpunpckhwd %xmm3,%xmm1,%xmm9 + DB 184,128,0,128,55 ; mov $0x37800080,%eax + DB 197,249,110,192 ; vmovd %eax,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,99,125,24,224,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm12 + DB 197,169,108,194 ; vpunpcklqdq %xmm2,%xmm10,%xmm0 + DB 197,241,113,240,8 ; vpsllw $0x8,%xmm0,%xmm1 + DB 197,249,113,208,8 ; vpsrlw $0x8,%xmm0,%xmm0 + DB 197,241,235,192 ; vpor %xmm0,%xmm1,%xmm0 + DB 196,65,33,239,219 ; vpxor %xmm11,%xmm11,%xmm11 + DB 196,193,121,105,203 ; vpunpckhwd %xmm11,%xmm0,%xmm1 + DB 196,226,121,51,192 ; vpmovzxwd %xmm0,%xmm0 + DB 196,227,125,24,193,1 ; vinsertf128 $0x1,%xmm1,%ymm0,%ymm0 + DB 197,252,91,192 ; vcvtdq2ps %ymm0,%ymm0 + DB 197,156,89,192 ; vmulps %ymm0,%ymm12,%ymm0 + DB 197,169,109,202 ; vpunpckhqdq %xmm2,%xmm10,%xmm1 + DB 197,233,113,241,8 ; vpsllw $0x8,%xmm1,%xmm2 + DB 197,241,113,209,8 ; vpsrlw $0x8,%xmm1,%xmm1 + DB 197,233,235,201 ; vpor %xmm1,%xmm2,%xmm1 + DB 196,193,113,105,211 ; vpunpckhwd %xmm11,%xmm1,%xmm2 + DB 196,226,121,51,201 ; vpmovzxwd %xmm1,%xmm1 + DB 196,227,117,24,202,1 ; vinsertf128 $0x1,%xmm2,%ymm1,%ymm1 + DB 197,252,91,201 ; vcvtdq2ps %ymm1,%ymm1 + DB 197,156,89,201 ; vmulps %ymm1,%ymm12,%ymm1 + DB 196,193,57,108,209 ; vpunpcklqdq %xmm9,%xmm8,%xmm2 + DB 197,169,113,242,8 ; vpsllw $0x8,%xmm2,%xmm10 + DB 197,233,113,210,8 ; vpsrlw $0x8,%xmm2,%xmm2 + DB 197,169,235,210 ; vpor %xmm2,%xmm10,%xmm2 + DB 196,65,105,105,211 ; vpunpckhwd %xmm11,%xmm2,%xmm10 + DB 196,226,121,51,210 ; vpmovzxwd %xmm2,%xmm2 + DB 196,195,109,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm2,%ymm2 + DB 197,252,91,210 ; vcvtdq2ps %ymm2,%ymm2 + DB 197,156,89,210 ; vmulps %ymm2,%ymm12,%ymm2 + DB 196,193,57,109,217 ; vpunpckhqdq %xmm9,%xmm8,%xmm3 + DB 197,185,113,243,8 ; vpsllw $0x8,%xmm3,%xmm8 + DB 197,225,113,211,8 ; vpsrlw $0x8,%xmm3,%xmm3 + DB 197,185,235,219 ; vpor %xmm3,%xmm8,%xmm3 + DB 196,65,97,105,195 ; vpunpckhwd %xmm11,%xmm3,%xmm8 + DB 196,226,121,51,219 ; vpmovzxwd %xmm3,%xmm3 + DB 196,195,101,24,216,1 ; vinsertf128 $0x1,%xmm8,%ymm3,%ymm3 + DB 197,252,91,219 ; vcvtdq2ps %ymm3,%ymm3 + DB 197,156,89,219 ; vmulps %ymm3,%ymm12,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 197,123,16,4,248 ; vmovsd (%rax,%rdi,8),%xmm8 + DB 196,65,49,239,201 ; vpxor %xmm9,%xmm9,%xmm9 + DB 72,131,249,1 ; cmp $0x1,%rcx + DB 116,79 ; je 37a4 <_sk_load_u16_be_avx+0x16e> + DB 197,57,22,68,248,8 ; vmovhpd 0x8(%rax,%rdi,8),%xmm8,%xmm8 + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 114,67 ; jb 37a4 <_sk_load_u16_be_avx+0x16e> + DB 197,251,16,84,248,16 ; vmovsd 0x10(%rax,%rdi,8),%xmm2 + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 116,68 ; je 37b1 <_sk_load_u16_be_avx+0x17b> + DB 197,233,22,84,248,24 ; vmovhpd 0x18(%rax,%rdi,8),%xmm2,%xmm2 + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 114,56 ; jb 37b1 <_sk_load_u16_be_avx+0x17b> + DB 197,251,16,92,248,32 ; vmovsd 0x20(%rax,%rdi,8),%xmm3 + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 15,132,210,254,255,255 ; je 365b <_sk_load_u16_be_avx+0x25> + DB 197,225,22,92,248,40 ; vmovhpd 0x28(%rax,%rdi,8),%xmm3,%xmm3 + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 15,130,194,254,255,255 ; jb 365b <_sk_load_u16_be_avx+0x25> + DB 197,122,126,76,248,48 ; vmovq 0x30(%rax,%rdi,8),%xmm9 + DB 233,183,254,255,255 ; jmpq 365b <_sk_load_u16_be_avx+0x25> + DB 197,225,87,219 ; vxorpd %xmm3,%xmm3,%xmm3 + DB 197,233,87,210 ; vxorpd %xmm2,%xmm2,%xmm2 + DB 233,170,254,255,255 ; jmpq 365b <_sk_load_u16_be_avx+0x25> + DB 197,225,87,219 ; vxorpd %xmm3,%xmm3,%xmm3 + DB 233,161,254,255,255 ; jmpq 365b <_sk_load_u16_be_avx+0x25> + +PUBLIC _sk_store_u16_be_avx +_sk_store_u16_be_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 184,0,255,127,71 ; mov $0x477fff00,%eax + DB 197,121,110,192 ; vmovd %eax,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 196,65,125,91,201 ; vcvtps2dq %ymm9,%ymm9 + DB 196,67,125,25,202,1 ; vextractf128 $0x1,%ymm9,%xmm10 + DB 196,66,49,43,202 ; vpackusdw %xmm10,%xmm9,%xmm9 + DB 196,193,41,113,241,8 ; vpsllw $0x8,%xmm9,%xmm10 + DB 196,193,49,113,209,8 ; vpsrlw $0x8,%xmm9,%xmm9 + DB 196,65,41,235,201 ; vpor %xmm9,%xmm10,%xmm9 + DB 197,60,89,209 ; vmulps %ymm1,%ymm8,%ymm10 + DB 196,65,125,91,210 ; vcvtps2dq %ymm10,%ymm10 + DB 196,67,125,25,211,1 ; vextractf128 $0x1,%ymm10,%xmm11 + DB 196,66,41,43,211 ; vpackusdw %xmm11,%xmm10,%xmm10 + DB 196,193,33,113,242,8 ; vpsllw $0x8,%xmm10,%xmm11 + DB 196,193,41,113,210,8 ; vpsrlw $0x8,%xmm10,%xmm10 + DB 196,65,33,235,210 ; vpor %xmm10,%xmm11,%xmm10 + DB 197,60,89,218 ; vmulps %ymm2,%ymm8,%ymm11 + DB 196,65,125,91,219 ; vcvtps2dq %ymm11,%ymm11 + DB 196,67,125,25,220,1 ; vextractf128 $0x1,%ymm11,%xmm12 + DB 196,66,33,43,220 ; vpackusdw %xmm12,%xmm11,%xmm11 + DB 196,193,25,113,243,8 ; vpsllw $0x8,%xmm11,%xmm12 + DB 196,193,33,113,211,8 ; vpsrlw $0x8,%xmm11,%xmm11 + DB 196,65,25,235,219 ; vpor %xmm11,%xmm12,%xmm11 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 196,65,125,91,192 ; vcvtps2dq %ymm8,%ymm8 + DB 196,67,125,25,196,1 ; vextractf128 $0x1,%ymm8,%xmm12 + DB 196,66,57,43,196 ; vpackusdw %xmm12,%xmm8,%xmm8 + DB 196,193,25,113,240,8 ; vpsllw $0x8,%xmm8,%xmm12 + DB 196,193,57,113,208,8 ; vpsrlw $0x8,%xmm8,%xmm8 + DB 196,65,25,235,192 ; vpor %xmm8,%xmm12,%xmm8 + DB 196,65,49,97,226 ; vpunpcklwd %xmm10,%xmm9,%xmm12 + DB 196,65,49,105,234 ; vpunpckhwd %xmm10,%xmm9,%xmm13 + DB 196,65,33,97,200 ; vpunpcklwd %xmm8,%xmm11,%xmm9 + DB 196,65,33,105,192 ; vpunpckhwd %xmm8,%xmm11,%xmm8 + DB 196,65,25,98,217 ; vpunpckldq %xmm9,%xmm12,%xmm11 + DB 196,65,25,106,209 ; vpunpckhdq %xmm9,%xmm12,%xmm10 + DB 196,65,17,98,200 ; vpunpckldq %xmm8,%xmm13,%xmm9 + DB 196,65,17,106,192 ; vpunpckhdq %xmm8,%xmm13,%xmm8 + DB 72,133,201 ; test %rcx,%rcx + DB 117,31 ; jne 38b4 <_sk_store_u16_be_avx+0xfa> + DB 196,65,120,17,28,248 ; vmovups %xmm11,(%r8,%rdi,8) + DB 196,65,120,17,84,248,16 ; vmovups %xmm10,0x10(%r8,%rdi,8) + DB 196,65,120,17,76,248,32 ; vmovups %xmm9,0x20(%r8,%rdi,8) + DB 196,65,122,127,68,248,48 ; vmovdqu %xmm8,0x30(%r8,%rdi,8) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 196,65,121,214,28,248 ; vmovq %xmm11,(%r8,%rdi,8) + DB 72,131,249,1 ; cmp $0x1,%rcx + DB 116,240 ; je 38b0 <_sk_store_u16_be_avx+0xf6> + DB 196,65,121,23,92,248,8 ; vmovhpd %xmm11,0x8(%r8,%rdi,8) + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 114,227 ; jb 38b0 <_sk_store_u16_be_avx+0xf6> + DB 196,65,121,214,84,248,16 ; vmovq %xmm10,0x10(%r8,%rdi,8) + DB 116,218 ; je 38b0 <_sk_store_u16_be_avx+0xf6> + DB 196,65,121,23,84,248,24 ; vmovhpd %xmm10,0x18(%r8,%rdi,8) + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 114,205 ; jb 38b0 <_sk_store_u16_be_avx+0xf6> + DB 196,65,121,214,76,248,32 ; vmovq %xmm9,0x20(%r8,%rdi,8) + DB 116,196 ; je 38b0 <_sk_store_u16_be_avx+0xf6> + DB 196,65,121,23,76,248,40 ; vmovhpd %xmm9,0x28(%r8,%rdi,8) + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 114,183 ; jb 38b0 <_sk_store_u16_be_avx+0xf6> + DB 196,65,121,214,68,248,48 ; vmovq %xmm8,0x30(%r8,%rdi,8) + DB 235,174 ; jmp 38b0 <_sk_store_u16_be_avx+0xf6> + +PUBLIC _sk_load_f32_avx +_sk_load_f32_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 119,110 ; ja 3978 <_sk_load_f32_avx+0x76> + DB 76,139,0 ; mov (%rax),%r8 + DB 76,141,12,189,0,0,0,0 ; lea 0x0(,%rdi,4),%r9 + DB 76,141,21,132,0,0,0 ; lea 0x84(%rip),%r10 # 39a0 <_sk_load_f32_avx+0x9e> + DB 73,99,4,138 ; movslq (%r10,%rcx,4),%rax + DB 76,1,208 ; add %r10,%rax + DB 255,224 ; jmpq *%rax + DB 196,3,125,24,68,136,112,1 ; vinsertf128 $0x1,0x70(%r8,%r9,4),%ymm0,%ymm8 + DB 196,131,125,24,92,136,96,1 ; vinsertf128 $0x1,0x60(%r8,%r9,4),%ymm0,%ymm3 + DB 196,131,125,24,76,136,80,1 ; vinsertf128 $0x1,0x50(%r8,%r9,4),%ymm0,%ymm1 + DB 196,131,125,24,84,136,64,1 ; vinsertf128 $0x1,0x40(%r8,%r9,4),%ymm0,%ymm2 + DB 196,129,121,16,68,136,48 ; vmovupd 0x30(%r8,%r9,4),%xmm0 + DB 196,195,125,13,192,12 ; vblendpd $0xc,%ymm8,%ymm0,%ymm0 + DB 196,1,121,16,68,136,32 ; vmovupd 0x20(%r8,%r9,4),%xmm8 + DB 196,99,61,13,203,12 ; vblendpd $0xc,%ymm3,%ymm8,%ymm9 + DB 196,129,121,16,92,136,16 ; vmovupd 0x10(%r8,%r9,4),%xmm3 + DB 196,99,101,13,209,12 ; vblendpd $0xc,%ymm1,%ymm3,%ymm10 + DB 196,129,121,16,12,136 ; vmovupd (%r8,%r9,4),%xmm1 + DB 196,227,117,13,202,12 ; vblendpd $0xc,%ymm2,%ymm1,%ymm1 + DB 196,193,116,20,210 ; vunpcklps %ymm10,%ymm1,%ymm2 + DB 196,193,116,21,218 ; vunpckhps %ymm10,%ymm1,%ymm3 + DB 197,180,20,200 ; vunpcklps %ymm0,%ymm9,%ymm1 + DB 197,52,21,192 ; vunpckhps %ymm0,%ymm9,%ymm8 + DB 197,237,20,193 ; vunpcklpd %ymm1,%ymm2,%ymm0 + DB 197,237,21,201 ; vunpckhpd %ymm1,%ymm2,%ymm1 + DB 196,193,101,20,208 ; vunpcklpd %ymm8,%ymm3,%ymm2 + DB 196,193,101,21,216 ; vunpckhpd %ymm8,%ymm3,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 133,255 ; test %edi,%edi + DB 255 ; (bad) + DB 255,204 ; dec %esp + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; (bad) + DB 191,255,255,255,178 ; mov $0xb2ffffff,%edi + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,165,255,255,255,157 ; jmpq *-0x62000001(%rbp) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255,149,255,255,255,141 ; callq *-0x72000001(%rbp) + DB 255 ; (bad) + DB 255 ; (bad) + DB 255 ; .byte 0xff + +PUBLIC _sk_store_f32_avx +_sk_store_f32_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,0 ; mov (%rax),%r8 + DB 72,141,4,189,0,0,0,0 ; lea 0x0(,%rdi,4),%rax + DB 197,124,20,193 ; vunpcklps %ymm1,%ymm0,%ymm8 + DB 197,124,21,217 ; vunpckhps %ymm1,%ymm0,%ymm11 + DB 197,108,20,203 ; vunpcklps %ymm3,%ymm2,%ymm9 + DB 197,108,21,227 ; vunpckhps %ymm3,%ymm2,%ymm12 + DB 196,65,61,20,209 ; vunpcklpd %ymm9,%ymm8,%ymm10 + DB 196,65,61,21,201 ; vunpckhpd %ymm9,%ymm8,%ymm9 + DB 196,65,37,20,196 ; vunpcklpd %ymm12,%ymm11,%ymm8 + DB 196,65,37,21,220 ; vunpckhpd %ymm12,%ymm11,%ymm11 + DB 72,133,201 ; test %rcx,%rcx + DB 117,55 ; jne 3a2d <_sk_store_f32_avx+0x6d> + DB 196,67,45,24,225,1 ; vinsertf128 $0x1,%xmm9,%ymm10,%ymm12 + DB 196,67,61,24,235,1 ; vinsertf128 $0x1,%xmm11,%ymm8,%ymm13 + DB 196,67,45,6,201,49 ; vperm2f128 $0x31,%ymm9,%ymm10,%ymm9 + DB 196,67,61,6,195,49 ; vperm2f128 $0x31,%ymm11,%ymm8,%ymm8 + DB 196,65,125,17,36,128 ; vmovupd %ymm12,(%r8,%rax,4) + DB 196,65,125,17,108,128,32 ; vmovupd %ymm13,0x20(%r8,%rax,4) + DB 196,65,125,17,76,128,64 ; vmovupd %ymm9,0x40(%r8,%rax,4) + DB 196,65,125,17,68,128,96 ; vmovupd %ymm8,0x60(%r8,%rax,4) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + DB 196,65,121,17,20,128 ; vmovupd %xmm10,(%r8,%rax,4) + DB 72,131,249,1 ; cmp $0x1,%rcx + DB 116,240 ; je 3a29 <_sk_store_f32_avx+0x69> + DB 196,65,121,17,76,128,16 ; vmovupd %xmm9,0x10(%r8,%rax,4) + DB 72,131,249,3 ; cmp $0x3,%rcx + DB 114,227 ; jb 3a29 <_sk_store_f32_avx+0x69> + DB 196,65,121,17,68,128,32 ; vmovupd %xmm8,0x20(%r8,%rax,4) + DB 116,218 ; je 3a29 <_sk_store_f32_avx+0x69> + DB 196,65,121,17,92,128,48 ; vmovupd %xmm11,0x30(%r8,%rax,4) + DB 72,131,249,5 ; cmp $0x5,%rcx + DB 114,205 ; jb 3a29 <_sk_store_f32_avx+0x69> + DB 196,67,125,25,84,128,64,1 ; vextractf128 $0x1,%ymm10,0x40(%r8,%rax,4) + DB 116,195 ; je 3a29 <_sk_store_f32_avx+0x69> + DB 196,67,125,25,76,128,80,1 ; vextractf128 $0x1,%ymm9,0x50(%r8,%rax,4) + DB 72,131,249,7 ; cmp $0x7,%rcx + DB 114,181 ; jb 3a29 <_sk_store_f32_avx+0x69> + DB 196,67,125,25,68,128,96,1 ; vextractf128 $0x1,%ymm8,0x60(%r8,%rax,4) + DB 235,171 ; jmp 3a29 <_sk_store_f32_avx+0x69> + +PUBLIC _sk_clamp_x_avx +_sk_clamp_x_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 197,60,95,200 ; vmaxps %ymm0,%ymm8,%ymm9 + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,99,125,25,192,1 ; vextractf128 $0x1,%ymm8,%xmm0 + DB 196,65,41,118,210 ; vpcmpeqd %xmm10,%xmm10,%xmm10 + DB 196,193,121,254,194 ; vpaddd %xmm10,%xmm0,%xmm0 + DB 196,65,57,254,194 ; vpaddd %xmm10,%xmm8,%xmm8 + DB 196,227,61,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm8,%ymm0 + DB 197,180,93,192 ; vminps %ymm0,%ymm9,%ymm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_y_avx +_sk_clamp_y_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 197,60,95,201 ; vmaxps %ymm1,%ymm8,%ymm9 + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,99,125,25,193,1 ; vextractf128 $0x1,%ymm8,%xmm1 + DB 196,65,41,118,210 ; vpcmpeqd %xmm10,%xmm10,%xmm10 + DB 196,193,113,254,202 ; vpaddd %xmm10,%xmm1,%xmm1 + DB 196,65,57,254,194 ; vpaddd %xmm10,%xmm8,%xmm8 + DB 196,227,61,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm8,%ymm1 + DB 197,180,93,201 ; vminps %ymm1,%ymm9,%ymm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_repeat_x_avx +_sk_repeat_x_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,65,124,94,200 ; vdivps %ymm8,%ymm0,%ymm9 + DB 196,67,125,8,201,1 ; vroundps $0x1,%ymm9,%ymm9 + DB 196,65,52,89,200 ; vmulps %ymm8,%ymm9,%ymm9 + DB 196,65,124,92,201 ; vsubps %ymm9,%ymm0,%ymm9 + DB 196,99,125,25,192,1 ; vextractf128 $0x1,%ymm8,%xmm0 + DB 196,65,41,118,210 ; vpcmpeqd %xmm10,%xmm10,%xmm10 + DB 196,193,121,254,194 ; vpaddd %xmm10,%xmm0,%xmm0 + DB 196,65,57,254,194 ; vpaddd %xmm10,%xmm8,%xmm8 + DB 196,227,61,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm8,%ymm0 + DB 197,180,93,192 ; vminps %ymm0,%ymm9,%ymm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_repeat_y_avx +_sk_repeat_y_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,65,116,94,200 ; vdivps %ymm8,%ymm1,%ymm9 + DB 196,67,125,8,201,1 ; vroundps $0x1,%ymm9,%ymm9 + DB 196,65,52,89,200 ; vmulps %ymm8,%ymm9,%ymm9 + DB 196,65,116,92,201 ; vsubps %ymm9,%ymm1,%ymm9 + DB 196,99,125,25,193,1 ; vextractf128 $0x1,%ymm8,%xmm1 + DB 196,65,41,118,210 ; vpcmpeqd %xmm10,%xmm10,%xmm10 + DB 196,193,113,254,202 ; vpaddd %xmm10,%xmm1,%xmm1 + DB 196,65,57,254,194 ; vpaddd %xmm10,%xmm8,%xmm8 + DB 196,227,61,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm8,%ymm1 + DB 197,180,93,201 ; vminps %ymm1,%ymm9,%ymm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_mirror_x_avx +_sk_mirror_x_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,121,110,0 ; vmovd (%rax),%xmm8 + DB 196,65,121,112,200,0 ; vpshufd $0x0,%xmm8,%xmm9 + DB 196,67,53,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + DB 196,65,124,92,209 ; vsubps %ymm9,%ymm0,%ymm10 + DB 196,193,58,88,192 ; vaddss %xmm8,%xmm8,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,44,94,192 ; vdivps %ymm0,%ymm10,%ymm8 + DB 196,67,125,8,192,1 ; vroundps $0x1,%ymm8,%ymm8 + DB 197,188,89,192 ; vmulps %ymm0,%ymm8,%ymm0 + DB 197,172,92,192 ; vsubps %ymm0,%ymm10,%ymm0 + DB 196,193,124,92,193 ; vsubps %ymm9,%ymm0,%ymm0 + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 197,60,92,192 ; vsubps %ymm0,%ymm8,%ymm8 + DB 197,60,84,192 ; vandps %ymm0,%ymm8,%ymm8 + DB 196,99,125,25,200,1 ; vextractf128 $0x1,%ymm9,%xmm0 + DB 196,65,41,118,210 ; vpcmpeqd %xmm10,%xmm10,%xmm10 + DB 196,193,121,254,194 ; vpaddd %xmm10,%xmm0,%xmm0 + DB 196,65,49,254,202 ; vpaddd %xmm10,%xmm9,%xmm9 + DB 196,227,53,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm9,%ymm0 + DB 197,188,93,192 ; vminps %ymm0,%ymm8,%ymm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_mirror_y_avx +_sk_mirror_y_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,121,110,0 ; vmovd (%rax),%xmm8 + DB 196,65,121,112,200,0 ; vpshufd $0x0,%xmm8,%xmm9 + DB 196,67,53,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + DB 196,65,116,92,209 ; vsubps %ymm9,%ymm1,%ymm10 + DB 196,193,58,88,200 ; vaddss %xmm8,%xmm8,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,44,94,193 ; vdivps %ymm1,%ymm10,%ymm8 + DB 196,67,125,8,192,1 ; vroundps $0x1,%ymm8,%ymm8 + DB 197,188,89,201 ; vmulps %ymm1,%ymm8,%ymm1 + DB 197,172,92,201 ; vsubps %ymm1,%ymm10,%ymm1 + DB 196,193,116,92,201 ; vsubps %ymm9,%ymm1,%ymm1 + DB 196,65,60,87,192 ; vxorps %ymm8,%ymm8,%ymm8 + DB 197,60,92,193 ; vsubps %ymm1,%ymm8,%ymm8 + DB 197,60,84,193 ; vandps %ymm1,%ymm8,%ymm8 + DB 196,99,125,25,201,1 ; vextractf128 $0x1,%ymm9,%xmm1 + DB 196,65,41,118,210 ; vpcmpeqd %xmm10,%xmm10,%xmm10 + DB 196,193,113,254,202 ; vpaddd %xmm10,%xmm1,%xmm1 + DB 196,65,49,254,202 ; vpaddd %xmm10,%xmm9,%xmm9 + DB 196,227,53,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm9,%ymm1 + DB 197,188,93,201 ; vminps %ymm1,%ymm8,%ymm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_luminance_to_alpha_avx +_sk_luminance_to_alpha_avx LABEL PROC + DB 184,208,179,89,62 ; mov $0x3e59b3d0,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,228,89,192 ; vmulps %ymm0,%ymm3,%ymm0 + DB 184,89,23,55,63 ; mov $0x3f371759,%eax + DB 197,249,110,216 ; vmovd %eax,%xmm3 + DB 196,227,121,4,219,0 ; vpermilps $0x0,%xmm3,%xmm3 + DB 196,227,101,24,219,1 ; vinsertf128 $0x1,%xmm3,%ymm3,%ymm3 + DB 197,228,89,201 ; vmulps %ymm1,%ymm3,%ymm1 + DB 197,252,88,193 ; vaddps %ymm1,%ymm0,%ymm0 + DB 184,152,221,147,61 ; mov $0x3d93dd98,%eax + DB 197,249,110,200 ; vmovd %eax,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,244,89,202 ; vmulps %ymm2,%ymm1,%ymm1 + DB 197,252,88,217 ; vaddps %ymm1,%ymm0,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,252,87,192 ; vxorps %ymm0,%ymm0,%ymm0 + DB 197,244,87,201 ; vxorps %ymm1,%ymm1,%ymm1 + DB 197,236,87,210 ; vxorps %ymm2,%ymm2,%ymm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_2x3_avx +_sk_matrix_2x3_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,98,125,24,72,8 ; vbroadcastss 0x8(%rax),%ymm9 + DB 196,98,125,24,80,16 ; vbroadcastss 0x10(%rax),%ymm10 + DB 197,52,89,201 ; vmulps %ymm1,%ymm9,%ymm9 + DB 196,65,52,88,202 ; vaddps %ymm10,%ymm9,%ymm9 + DB 197,60,89,192 ; vmulps %ymm0,%ymm8,%ymm8 + DB 196,65,60,88,193 ; vaddps %ymm9,%ymm8,%ymm8 + DB 196,98,125,24,72,4 ; vbroadcastss 0x4(%rax),%ymm9 + DB 196,98,125,24,80,12 ; vbroadcastss 0xc(%rax),%ymm10 + DB 196,98,125,24,88,20 ; vbroadcastss 0x14(%rax),%ymm11 + DB 197,172,89,201 ; vmulps %ymm1,%ymm10,%ymm1 + DB 196,193,116,88,203 ; vaddps %ymm11,%ymm1,%ymm1 + DB 197,180,89,192 ; vmulps %ymm0,%ymm9,%ymm0 + DB 197,252,88,201 ; vaddps %ymm1,%ymm0,%ymm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,192 ; vmovaps %ymm8,%ymm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_3x4_avx +_sk_matrix_3x4_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,98,125,24,72,12 ; vbroadcastss 0xc(%rax),%ymm9 + DB 196,98,125,24,80,24 ; vbroadcastss 0x18(%rax),%ymm10 + DB 196,98,125,24,88,36 ; vbroadcastss 0x24(%rax),%ymm11 + DB 197,44,89,210 ; vmulps %ymm2,%ymm10,%ymm10 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 197,52,89,201 ; vmulps %ymm1,%ymm9,%ymm9 + DB 196,65,52,88,202 ; vaddps %ymm10,%ymm9,%ymm9 + DB 197,60,89,192 ; vmulps %ymm0,%ymm8,%ymm8 + DB 196,65,60,88,193 ; vaddps %ymm9,%ymm8,%ymm8 + DB 196,98,125,24,72,4 ; vbroadcastss 0x4(%rax),%ymm9 + DB 196,98,125,24,80,16 ; vbroadcastss 0x10(%rax),%ymm10 + DB 196,98,125,24,88,28 ; vbroadcastss 0x1c(%rax),%ymm11 + DB 196,98,125,24,96,40 ; vbroadcastss 0x28(%rax),%ymm12 + DB 197,36,89,218 ; vmulps %ymm2,%ymm11,%ymm11 + DB 196,65,36,88,220 ; vaddps %ymm12,%ymm11,%ymm11 + DB 197,44,89,209 ; vmulps %ymm1,%ymm10,%ymm10 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 197,52,89,200 ; vmulps %ymm0,%ymm9,%ymm9 + DB 196,65,52,88,202 ; vaddps %ymm10,%ymm9,%ymm9 + DB 196,98,125,24,80,8 ; vbroadcastss 0x8(%rax),%ymm10 + DB 196,98,125,24,88,20 ; vbroadcastss 0x14(%rax),%ymm11 + DB 196,98,125,24,96,32 ; vbroadcastss 0x20(%rax),%ymm12 + DB 196,98,125,24,104,44 ; vbroadcastss 0x2c(%rax),%ymm13 + DB 197,156,89,210 ; vmulps %ymm2,%ymm12,%ymm2 + DB 196,193,108,88,213 ; vaddps %ymm13,%ymm2,%ymm2 + DB 197,164,89,201 ; vmulps %ymm1,%ymm11,%ymm1 + DB 197,244,88,202 ; vaddps %ymm2,%ymm1,%ymm1 + DB 197,172,89,192 ; vmulps %ymm0,%ymm10,%ymm0 + DB 197,252,88,209 ; vaddps %ymm1,%ymm0,%ymm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,192 ; vmovaps %ymm8,%ymm0 + DB 197,124,41,201 ; vmovaps %ymm9,%ymm1 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_4x5_avx +_sk_matrix_4x5_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,98,125,24,72,16 ; vbroadcastss 0x10(%rax),%ymm9 + DB 196,98,125,24,80,32 ; vbroadcastss 0x20(%rax),%ymm10 + DB 196,98,125,24,88,48 ; vbroadcastss 0x30(%rax),%ymm11 + DB 196,98,125,24,96,64 ; vbroadcastss 0x40(%rax),%ymm12 + DB 197,36,89,219 ; vmulps %ymm3,%ymm11,%ymm11 + DB 196,65,36,88,220 ; vaddps %ymm12,%ymm11,%ymm11 + DB 197,44,89,210 ; vmulps %ymm2,%ymm10,%ymm10 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 197,52,89,201 ; vmulps %ymm1,%ymm9,%ymm9 + DB 196,65,52,88,202 ; vaddps %ymm10,%ymm9,%ymm9 + DB 197,60,89,192 ; vmulps %ymm0,%ymm8,%ymm8 + DB 196,65,60,88,193 ; vaddps %ymm9,%ymm8,%ymm8 + DB 196,98,125,24,72,4 ; vbroadcastss 0x4(%rax),%ymm9 + DB 196,98,125,24,80,20 ; vbroadcastss 0x14(%rax),%ymm10 + DB 196,98,125,24,88,36 ; vbroadcastss 0x24(%rax),%ymm11 + DB 196,98,125,24,96,52 ; vbroadcastss 0x34(%rax),%ymm12 + DB 196,98,125,24,104,68 ; vbroadcastss 0x44(%rax),%ymm13 + DB 197,28,89,227 ; vmulps %ymm3,%ymm12,%ymm12 + DB 196,65,28,88,229 ; vaddps %ymm13,%ymm12,%ymm12 + DB 197,36,89,218 ; vmulps %ymm2,%ymm11,%ymm11 + DB 196,65,36,88,220 ; vaddps %ymm12,%ymm11,%ymm11 + DB 197,44,89,209 ; vmulps %ymm1,%ymm10,%ymm10 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 197,52,89,200 ; vmulps %ymm0,%ymm9,%ymm9 + DB 196,65,52,88,202 ; vaddps %ymm10,%ymm9,%ymm9 + DB 196,98,125,24,80,8 ; vbroadcastss 0x8(%rax),%ymm10 + DB 196,98,125,24,88,24 ; vbroadcastss 0x18(%rax),%ymm11 + DB 196,98,125,24,96,40 ; vbroadcastss 0x28(%rax),%ymm12 + DB 196,98,125,24,104,56 ; vbroadcastss 0x38(%rax),%ymm13 + DB 196,98,125,24,112,72 ; vbroadcastss 0x48(%rax),%ymm14 + DB 197,20,89,235 ; vmulps %ymm3,%ymm13,%ymm13 + DB 196,65,20,88,238 ; vaddps %ymm14,%ymm13,%ymm13 + DB 197,28,89,226 ; vmulps %ymm2,%ymm12,%ymm12 + DB 196,65,28,88,229 ; vaddps %ymm13,%ymm12,%ymm12 + DB 197,36,89,217 ; vmulps %ymm1,%ymm11,%ymm11 + DB 196,65,36,88,220 ; vaddps %ymm12,%ymm11,%ymm11 + DB 197,44,89,208 ; vmulps %ymm0,%ymm10,%ymm10 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 196,98,125,24,88,12 ; vbroadcastss 0xc(%rax),%ymm11 + DB 196,98,125,24,96,28 ; vbroadcastss 0x1c(%rax),%ymm12 + DB 196,98,125,24,104,44 ; vbroadcastss 0x2c(%rax),%ymm13 + DB 196,98,125,24,112,60 ; vbroadcastss 0x3c(%rax),%ymm14 + DB 196,98,125,24,120,76 ; vbroadcastss 0x4c(%rax),%ymm15 + DB 197,140,89,219 ; vmulps %ymm3,%ymm14,%ymm3 + DB 196,193,100,88,223 ; vaddps %ymm15,%ymm3,%ymm3 + DB 197,148,89,210 ; vmulps %ymm2,%ymm13,%ymm2 + DB 197,236,88,211 ; vaddps %ymm3,%ymm2,%ymm2 + DB 197,156,89,201 ; vmulps %ymm1,%ymm12,%ymm1 + DB 197,244,88,202 ; vaddps %ymm2,%ymm1,%ymm1 + DB 197,164,89,192 ; vmulps %ymm0,%ymm11,%ymm0 + DB 197,252,88,217 ; vaddps %ymm1,%ymm0,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,192 ; vmovaps %ymm8,%ymm0 + DB 197,124,41,201 ; vmovaps %ymm9,%ymm1 + DB 197,124,41,210 ; vmovaps %ymm10,%ymm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_perspective_avx +_sk_matrix_perspective_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,0 ; vbroadcastss (%rax),%ymm8 + DB 196,98,125,24,72,4 ; vbroadcastss 0x4(%rax),%ymm9 + DB 196,98,125,24,80,8 ; vbroadcastss 0x8(%rax),%ymm10 + DB 197,52,89,201 ; vmulps %ymm1,%ymm9,%ymm9 + DB 196,65,52,88,202 ; vaddps %ymm10,%ymm9,%ymm9 + DB 197,60,89,192 ; vmulps %ymm0,%ymm8,%ymm8 + DB 196,65,60,88,193 ; vaddps %ymm9,%ymm8,%ymm8 + DB 196,98,125,24,72,12 ; vbroadcastss 0xc(%rax),%ymm9 + DB 196,98,125,24,80,16 ; vbroadcastss 0x10(%rax),%ymm10 + DB 196,98,125,24,88,20 ; vbroadcastss 0x14(%rax),%ymm11 + DB 197,44,89,209 ; vmulps %ymm1,%ymm10,%ymm10 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 197,52,89,200 ; vmulps %ymm0,%ymm9,%ymm9 + DB 196,65,52,88,202 ; vaddps %ymm10,%ymm9,%ymm9 + DB 196,98,125,24,80,24 ; vbroadcastss 0x18(%rax),%ymm10 + DB 196,98,125,24,88,28 ; vbroadcastss 0x1c(%rax),%ymm11 + DB 196,98,125,24,96,32 ; vbroadcastss 0x20(%rax),%ymm12 + DB 197,164,89,201 ; vmulps %ymm1,%ymm11,%ymm1 + DB 196,193,116,88,204 ; vaddps %ymm12,%ymm1,%ymm1 + DB 197,172,89,192 ; vmulps %ymm0,%ymm10,%ymm0 + DB 197,252,88,193 ; vaddps %ymm1,%ymm0,%ymm0 + DB 197,252,83,200 ; vrcpps %ymm0,%ymm1 + DB 197,188,89,193 ; vmulps %ymm1,%ymm8,%ymm0 + DB 197,180,89,201 ; vmulps %ymm1,%ymm9,%ymm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_linear_gradient_avx +_sk_linear_gradient_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,98,125,24,64,16 ; vbroadcastss 0x10(%rax),%ymm8 + DB 196,226,125,24,72,20 ; vbroadcastss 0x14(%rax),%ymm1 + DB 196,226,125,24,80,24 ; vbroadcastss 0x18(%rax),%ymm2 + DB 196,226,125,24,88,28 ; vbroadcastss 0x1c(%rax),%ymm3 + DB 76,139,0 ; mov (%rax),%r8 + DB 77,133,192 ; test %r8,%r8 + DB 15,132,146,0,0,0 ; je 3fe1 <_sk_linear_gradient_avx+0xb8> + DB 72,139,64,8 ; mov 0x8(%rax),%rax + DB 72,131,192,32 ; add $0x20,%rax + DB 196,65,28,87,228 ; vxorps %ymm12,%ymm12,%ymm12 + DB 196,65,52,87,201 ; vxorps %ymm9,%ymm9,%ymm9 + DB 196,65,44,87,210 ; vxorps %ymm10,%ymm10,%ymm10 + DB 196,65,36,87,219 ; vxorps %ymm11,%ymm11,%ymm11 + DB 196,98,125,24,104,224 ; vbroadcastss -0x20(%rax),%ymm13 + DB 196,65,124,194,237,1 ; vcmpltps %ymm13,%ymm0,%ymm13 + DB 196,98,125,24,112,228 ; vbroadcastss -0x1c(%rax),%ymm14 + DB 196,67,13,74,228,208 ; vblendvps %ymm13,%ymm12,%ymm14,%ymm12 + DB 196,98,125,24,112,232 ; vbroadcastss -0x18(%rax),%ymm14 + DB 196,67,13,74,219,208 ; vblendvps %ymm13,%ymm11,%ymm14,%ymm11 + DB 196,98,125,24,112,236 ; vbroadcastss -0x14(%rax),%ymm14 + DB 196,67,13,74,210,208 ; vblendvps %ymm13,%ymm10,%ymm14,%ymm10 + DB 196,98,125,24,112,240 ; vbroadcastss -0x10(%rax),%ymm14 + DB 196,67,13,74,201,208 ; vblendvps %ymm13,%ymm9,%ymm14,%ymm9 + DB 196,98,125,24,112,244 ; vbroadcastss -0xc(%rax),%ymm14 + DB 196,67,13,74,192,208 ; vblendvps %ymm13,%ymm8,%ymm14,%ymm8 + DB 196,98,125,24,112,248 ; vbroadcastss -0x8(%rax),%ymm14 + DB 196,227,13,74,201,208 ; vblendvps %ymm13,%ymm1,%ymm14,%ymm1 + DB 196,98,125,24,112,252 ; vbroadcastss -0x4(%rax),%ymm14 + DB 196,227,13,74,210,208 ; vblendvps %ymm13,%ymm2,%ymm14,%ymm2 + DB 196,98,125,24,48 ; vbroadcastss (%rax),%ymm14 + DB 196,227,13,74,219,208 ; vblendvps %ymm13,%ymm3,%ymm14,%ymm3 + DB 72,131,192,36 ; add $0x24,%rax + DB 73,255,200 ; dec %r8 + DB 117,140 ; jne 3f6b <_sk_linear_gradient_avx+0x42> + DB 235,20 ; jmp 3ff5 <_sk_linear_gradient_avx+0xcc> + DB 196,65,36,87,219 ; vxorps %ymm11,%ymm11,%ymm11 + DB 196,65,44,87,210 ; vxorps %ymm10,%ymm10,%ymm10 + DB 196,65,52,87,201 ; vxorps %ymm9,%ymm9,%ymm9 + DB 196,65,28,87,228 ; vxorps %ymm12,%ymm12,%ymm12 + DB 197,28,89,224 ; vmulps %ymm0,%ymm12,%ymm12 + DB 196,65,60,88,196 ; vaddps %ymm12,%ymm8,%ymm8 + DB 197,36,89,216 ; vmulps %ymm0,%ymm11,%ymm11 + DB 197,164,88,201 ; vaddps %ymm1,%ymm11,%ymm1 + DB 197,44,89,208 ; vmulps %ymm0,%ymm10,%ymm10 + DB 197,172,88,210 ; vaddps %ymm2,%ymm10,%ymm2 + DB 197,180,89,192 ; vmulps %ymm0,%ymm9,%ymm0 + DB 197,252,88,219 ; vaddps %ymm3,%ymm0,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,192 ; vmovaps %ymm8,%ymm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_linear_gradient_2stops_avx +_sk_linear_gradient_2stops_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 196,226,125,24,8 ; vbroadcastss (%rax),%ymm1 + DB 196,226,125,24,80,16 ; vbroadcastss 0x10(%rax),%ymm2 + DB 197,244,89,200 ; vmulps %ymm0,%ymm1,%ymm1 + DB 197,116,88,194 ; vaddps %ymm2,%ymm1,%ymm8 + DB 196,226,125,24,72,4 ; vbroadcastss 0x4(%rax),%ymm1 + DB 196,226,125,24,80,20 ; vbroadcastss 0x14(%rax),%ymm2 + DB 197,244,89,200 ; vmulps %ymm0,%ymm1,%ymm1 + DB 197,244,88,202 ; vaddps %ymm2,%ymm1,%ymm1 + DB 196,226,125,24,80,8 ; vbroadcastss 0x8(%rax),%ymm2 + DB 196,226,125,24,88,24 ; vbroadcastss 0x18(%rax),%ymm3 + DB 197,236,89,208 ; vmulps %ymm0,%ymm2,%ymm2 + DB 197,236,88,211 ; vaddps %ymm3,%ymm2,%ymm2 + DB 196,226,125,24,88,12 ; vbroadcastss 0xc(%rax),%ymm3 + DB 196,98,125,24,72,28 ; vbroadcastss 0x1c(%rax),%ymm9 + DB 197,228,89,192 ; vmulps %ymm0,%ymm3,%ymm0 + DB 196,193,124,88,217 ; vaddps %ymm9,%ymm0,%ymm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,41,192 ; vmovaps %ymm8,%ymm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_save_xy_avx +_sk_save_xy_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,88,200 ; vaddps %ymm0,%ymm8,%ymm9 + DB 196,67,125,8,209,1 ; vroundps $0x1,%ymm9,%ymm10 + DB 196,65,52,92,202 ; vsubps %ymm10,%ymm9,%ymm9 + DB 197,60,88,193 ; vaddps %ymm1,%ymm8,%ymm8 + DB 196,67,125,8,208,1 ; vroundps $0x1,%ymm8,%ymm10 + DB 196,65,60,92,194 ; vsubps %ymm10,%ymm8,%ymm8 + DB 197,252,17,0 ; vmovups %ymm0,(%rax) + DB 197,252,17,72,32 ; vmovups %ymm1,0x20(%rax) + DB 197,124,17,72,64 ; vmovups %ymm9,0x40(%rax) + DB 197,124,17,64,96 ; vmovups %ymm8,0x60(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_accumulate_avx +_sk_accumulate_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 197,124,16,128,128,0,0,0 ; vmovups 0x80(%rax),%ymm8 + DB 197,60,89,128,160,0,0,0 ; vmulps 0xa0(%rax),%ymm8,%ymm8 + DB 197,60,89,200 ; vmulps %ymm0,%ymm8,%ymm9 + DB 197,180,88,228 ; vaddps %ymm4,%ymm9,%ymm4 + DB 197,60,89,201 ; vmulps %ymm1,%ymm8,%ymm9 + DB 197,180,88,237 ; vaddps %ymm5,%ymm9,%ymm5 + DB 197,60,89,202 ; vmulps %ymm2,%ymm8,%ymm9 + DB 197,180,88,246 ; vaddps %ymm6,%ymm9,%ymm6 + DB 197,60,89,195 ; vmulps %ymm3,%ymm8,%ymm8 + DB 197,188,88,255 ; vaddps %ymm7,%ymm8,%ymm7 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_nx_avx +_sk_bilinear_nx_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,191 ; mov $0xbf000000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,252,88,0 ; vaddps (%rax),%ymm0,%ymm0 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,64,64 ; vsubps 0x40(%rax),%ymm8,%ymm8 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_px_avx +_sk_bilinear_px_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,124,16,64,64 ; vmovups 0x40(%rax),%ymm8 + DB 197,252,88,0 ; vaddps (%rax),%ymm0,%ymm0 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_ny_avx +_sk_bilinear_ny_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,191 ; mov $0xbf000000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,244,88,72,32 ; vaddps 0x20(%rax),%ymm1,%ymm1 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,64,96 ; vsubps 0x60(%rax),%ymm8,%ymm8 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_py_avx +_sk_bilinear_py_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,124,16,64,96 ; vmovups 0x60(%rax),%ymm8 + DB 197,244,88,72,32 ; vaddps 0x20(%rax),%ymm1,%ymm1 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n3x_avx +_sk_bicubic_n3x_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,192,191 ; mov $0xbfc00000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,252,88,0 ; vaddps (%rax),%ymm0,%ymm0 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,64,64 ; vsubps 0x40(%rax),%ymm8,%ymm8 + DB 196,65,60,89,200 ; vmulps %ymm8,%ymm8,%ymm9 + DB 65,184,114,28,199,62 ; mov $0x3ec71c72,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 65,184,171,170,170,190 ; mov $0xbeaaaaab,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,67,121,4,219,0 ; vpermilps $0x0,%xmm11,%xmm11 + DB 196,67,37,24,219,1 ; vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + DB 196,65,44,89,192 ; vmulps %ymm8,%ymm10,%ymm8 + DB 196,65,60,88,195 ; vaddps %ymm11,%ymm8,%ymm8 + DB 196,65,52,89,192 ; vmulps %ymm8,%ymm9,%ymm8 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n1x_avx +_sk_bicubic_n1x_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,191 ; mov $0xbf000000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,252,88,0 ; vaddps (%rax),%ymm0,%ymm0 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,64,64 ; vsubps 0x40(%rax),%ymm8,%ymm8 + DB 65,184,85,85,149,191 ; mov $0xbf955555,%r8d + DB 196,65,121,110,200 ; vmovd %r8d,%xmm9 + DB 196,67,121,4,201,0 ; vpermilps $0x0,%xmm9,%xmm9 + DB 196,67,53,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 196,65,52,89,200 ; vmulps %ymm8,%ymm9,%ymm9 + DB 196,65,52,88,202 ; vaddps %ymm10,%ymm9,%ymm9 + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 196,65,60,89,201 ; vmulps %ymm9,%ymm8,%ymm9 + DB 196,65,44,88,201 ; vaddps %ymm9,%ymm10,%ymm9 + DB 65,184,57,142,99,61 ; mov $0x3d638e39,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 196,65,60,89,193 ; vmulps %ymm9,%ymm8,%ymm8 + DB 196,65,44,88,192 ; vaddps %ymm8,%ymm10,%ymm8 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p1x_avx +_sk_bicubic_p1x_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,99,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm8 + DB 197,188,88,0 ; vaddps (%rax),%ymm8,%ymm0 + DB 197,124,16,72,64 ; vmovups 0x40(%rax),%ymm9 + DB 65,184,85,85,149,191 ; mov $0xbf955555,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,67,121,4,219,0 ; vpermilps $0x0,%xmm11,%xmm11 + DB 196,67,37,24,219,1 ; vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + DB 196,65,52,89,210 ; vmulps %ymm10,%ymm9,%ymm10 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 196,65,52,89,210 ; vmulps %ymm10,%ymm9,%ymm10 + DB 196,65,60,88,194 ; vaddps %ymm10,%ymm8,%ymm8 + DB 65,184,57,142,99,61 ; mov $0x3d638e39,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 196,65,52,89,192 ; vmulps %ymm8,%ymm9,%ymm8 + DB 196,65,44,88,192 ; vaddps %ymm8,%ymm10,%ymm8 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p3x_avx +_sk_bicubic_p3x_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,193,121,110,192 ; vmovd %r8d,%xmm0 + DB 196,227,121,4,192,0 ; vpermilps $0x0,%xmm0,%xmm0 + DB 196,227,125,24,192,1 ; vinsertf128 $0x1,%xmm0,%ymm0,%ymm0 + DB 197,252,88,0 ; vaddps (%rax),%ymm0,%ymm0 + DB 197,124,16,64,64 ; vmovups 0x40(%rax),%ymm8 + DB 196,65,60,89,200 ; vmulps %ymm8,%ymm8,%ymm9 + DB 65,184,114,28,199,62 ; mov $0x3ec71c72,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 65,184,171,170,170,190 ; mov $0xbeaaaaab,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,67,121,4,219,0 ; vpermilps $0x0,%xmm11,%xmm11 + DB 196,67,37,24,219,1 ; vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + DB 196,65,60,89,194 ; vmulps %ymm10,%ymm8,%ymm8 + DB 196,65,60,88,195 ; vaddps %ymm11,%ymm8,%ymm8 + DB 196,65,52,89,192 ; vmulps %ymm8,%ymm9,%ymm8 + DB 197,124,17,128,128,0,0,0 ; vmovups %ymm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n3y_avx +_sk_bicubic_n3y_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,192,191 ; mov $0xbfc00000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,244,88,72,32 ; vaddps 0x20(%rax),%ymm1,%ymm1 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,64,96 ; vsubps 0x60(%rax),%ymm8,%ymm8 + DB 196,65,60,89,200 ; vmulps %ymm8,%ymm8,%ymm9 + DB 65,184,114,28,199,62 ; mov $0x3ec71c72,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 65,184,171,170,170,190 ; mov $0xbeaaaaab,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,67,121,4,219,0 ; vpermilps $0x0,%xmm11,%xmm11 + DB 196,67,37,24,219,1 ; vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + DB 196,65,44,89,192 ; vmulps %ymm8,%ymm10,%ymm8 + DB 196,65,60,88,195 ; vaddps %ymm11,%ymm8,%ymm8 + DB 196,65,52,89,192 ; vmulps %ymm8,%ymm9,%ymm8 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n1y_avx +_sk_bicubic_n1y_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,191 ; mov $0xbf000000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,244,88,72,32 ; vaddps 0x20(%rax),%ymm1,%ymm1 + DB 65,184,0,0,128,63 ; mov $0x3f800000,%r8d + DB 196,65,121,110,192 ; vmovd %r8d,%xmm8 + DB 196,67,121,4,192,0 ; vpermilps $0x0,%xmm8,%xmm8 + DB 196,67,61,24,192,1 ; vinsertf128 $0x1,%xmm8,%ymm8,%ymm8 + DB 197,60,92,64,96 ; vsubps 0x60(%rax),%ymm8,%ymm8 + DB 65,184,85,85,149,191 ; mov $0xbf955555,%r8d + DB 196,65,121,110,200 ; vmovd %r8d,%xmm9 + DB 196,67,121,4,201,0 ; vpermilps $0x0,%xmm9,%xmm9 + DB 196,67,53,24,201,1 ; vinsertf128 $0x1,%xmm9,%ymm9,%ymm9 + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 196,65,52,89,200 ; vmulps %ymm8,%ymm9,%ymm9 + DB 196,65,52,88,202 ; vaddps %ymm10,%ymm9,%ymm9 + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 196,65,60,89,201 ; vmulps %ymm9,%ymm8,%ymm9 + DB 196,65,44,88,201 ; vaddps %ymm9,%ymm10,%ymm9 + DB 65,184,57,142,99,61 ; mov $0x3d638e39,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 196,65,60,89,193 ; vmulps %ymm9,%ymm8,%ymm8 + DB 196,65,44,88,192 ; vaddps %ymm8,%ymm10,%ymm8 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p1y_avx +_sk_bicubic_p1y_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,0,63 ; mov $0x3f000000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,99,117,24,193,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm8 + DB 197,188,88,72,32 ; vaddps 0x20(%rax),%ymm8,%ymm1 + DB 197,124,16,72,96 ; vmovups 0x60(%rax),%ymm9 + DB 65,184,85,85,149,191 ; mov $0xbf955555,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,67,121,4,219,0 ; vpermilps $0x0,%xmm11,%xmm11 + DB 196,67,37,24,219,1 ; vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + DB 196,65,52,89,210 ; vmulps %ymm10,%ymm9,%ymm10 + DB 196,65,44,88,211 ; vaddps %ymm11,%ymm10,%ymm10 + DB 196,65,52,89,210 ; vmulps %ymm10,%ymm9,%ymm10 + DB 196,65,60,88,194 ; vaddps %ymm10,%ymm8,%ymm8 + DB 65,184,57,142,99,61 ; mov $0x3d638e39,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 196,65,52,89,192 ; vmulps %ymm8,%ymm9,%ymm8 + DB 196,65,44,88,192 ; vaddps %ymm8,%ymm10,%ymm8 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p3y_avx +_sk_bicubic_p3y_avx LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,184,0,0,192,63 ; mov $0x3fc00000,%r8d + DB 196,193,121,110,200 ; vmovd %r8d,%xmm1 + DB 196,227,121,4,201,0 ; vpermilps $0x0,%xmm1,%xmm1 + DB 196,227,117,24,201,1 ; vinsertf128 $0x1,%xmm1,%ymm1,%ymm1 + DB 197,244,88,72,32 ; vaddps 0x20(%rax),%ymm1,%ymm1 + DB 197,124,16,64,96 ; vmovups 0x60(%rax),%ymm8 + DB 196,65,60,89,200 ; vmulps %ymm8,%ymm8,%ymm9 + DB 65,184,114,28,199,62 ; mov $0x3ec71c72,%r8d + DB 196,65,121,110,208 ; vmovd %r8d,%xmm10 + DB 196,67,121,4,210,0 ; vpermilps $0x0,%xmm10,%xmm10 + DB 196,67,45,24,210,1 ; vinsertf128 $0x1,%xmm10,%ymm10,%ymm10 + DB 65,184,171,170,170,190 ; mov $0xbeaaaaab,%r8d + DB 196,65,121,110,216 ; vmovd %r8d,%xmm11 + DB 196,67,121,4,219,0 ; vpermilps $0x0,%xmm11,%xmm11 + DB 196,67,37,24,219,1 ; vinsertf128 $0x1,%xmm11,%ymm11,%ymm11 + DB 196,65,60,89,194 ; vmulps %ymm10,%ymm8,%ymm8 + DB 196,65,60,88,195 ; vaddps %ymm11,%ymm8,%ymm8 + DB 196,65,52,89,192 ; vmulps %ymm8,%ymm9,%ymm8 + DB 197,124,17,128,160,0,0,0 ; vmovups %ymm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_start_pipeline_sse41 +_sk_start_pipeline_sse41 LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 86 ; push %rsi + DB 87 ; push %rdi + DB 83 ; push %rbx + DB 72,129,236,160,0,0,0 ; sub $0xa0,%rsp + DB 68,15,41,188,36,144,0,0,0 ; movaps %xmm15,0x90(%rsp) + DB 68,15,41,180,36,128,0,0,0 ; movaps %xmm14,0x80(%rsp) + DB 68,15,41,108,36,112 ; movaps %xmm13,0x70(%rsp) + DB 68,15,41,100,36,96 ; movaps %xmm12,0x60(%rsp) + DB 68,15,41,92,36,80 ; movaps %xmm11,0x50(%rsp) + DB 68,15,41,84,36,64 ; movaps %xmm10,0x40(%rsp) + DB 68,15,41,76,36,48 ; movaps %xmm9,0x30(%rsp) + DB 68,15,41,68,36,32 ; movaps %xmm8,0x20(%rsp) + DB 15,41,124,36,16 ; movaps %xmm7,0x10(%rsp) + DB 15,41,52,36 ; movaps %xmm6,(%rsp) + DB 77,137,207 ; mov %r9,%r15 + DB 77,137,198 ; mov %r8,%r14 + DB 72,137,203 ; mov %rcx,%rbx + DB 72,137,214 ; mov %rdx,%rsi + DB 72,173 ; lods %ds:(%rsi),%rax + DB 73,137,196 ; mov %rax,%r12 + DB 73,137,245 ; mov %rsi,%r13 + DB 72,141,67,4 ; lea 0x4(%rbx),%rax + DB 76,57,248 ; cmp %r15,%rax + DB 118,5 ; jbe 73 <_sk_start_pipeline_sse41+0x73> + DB 72,137,216 ; mov %rbx,%rax + DB 235,52 ; jmp a7 <_sk_start_pipeline_sse41+0xa7> + DB 15,87,192 ; xorps %xmm0,%xmm0 + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 15,87,219 ; xorps %xmm3,%xmm3 + DB 15,87,228 ; xorps %xmm4,%xmm4 + DB 15,87,237 ; xorps %xmm5,%xmm5 + DB 15,87,246 ; xorps %xmm6,%xmm6 + DB 15,87,255 ; xorps %xmm7,%xmm7 + DB 72,137,223 ; mov %rbx,%rdi + DB 76,137,238 ; mov %r13,%rsi + DB 76,137,242 ; mov %r14,%rdx + DB 65,255,212 ; callq *%r12 + DB 72,141,67,4 ; lea 0x4(%rbx),%rax + DB 72,131,195,8 ; add $0x8,%rbx + DB 76,57,251 ; cmp %r15,%rbx + DB 72,137,195 ; mov %rax,%rbx + DB 118,204 ; jbe 73 <_sk_start_pipeline_sse41+0x73> + DB 15,40,52,36 ; movaps (%rsp),%xmm6 + DB 15,40,124,36,16 ; movaps 0x10(%rsp),%xmm7 + DB 68,15,40,68,36,32 ; movaps 0x20(%rsp),%xmm8 + DB 68,15,40,76,36,48 ; movaps 0x30(%rsp),%xmm9 + DB 68,15,40,84,36,64 ; movaps 0x40(%rsp),%xmm10 + DB 68,15,40,92,36,80 ; movaps 0x50(%rsp),%xmm11 + DB 68,15,40,100,36,96 ; movaps 0x60(%rsp),%xmm12 + DB 68,15,40,108,36,112 ; movaps 0x70(%rsp),%xmm13 + DB 68,15,40,180,36,128,0,0,0 ; movaps 0x80(%rsp),%xmm14 + DB 68,15,40,188,36,144,0,0,0 ; movaps 0x90(%rsp),%xmm15 + DB 72,129,196,160,0,0,0 ; add $0xa0,%rsp + DB 91 ; pop %rbx + DB 95 ; pop %rdi + DB 94 ; pop %rsi + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 195 ; retq + +PUBLIC _sk_just_return_sse41 +_sk_just_return_sse41 LABEL PROC + DB 195 ; retq + +PUBLIC _sk_seed_shader_sse41 +_sk_seed_shader_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 102,15,110,199 ; movd %edi,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,15,110,209 ; movd %ecx,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,88,202 ; addps %xmm2,%xmm1 + DB 15,16,2 ; movups (%rdx),%xmm0 + DB 15,88,193 ; addps %xmm1,%xmm0 + DB 102,15,110,8 ; movd (%rax),%xmm1 + DB 102,15,112,201,0 ; pshufd $0x0,%xmm1,%xmm1 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 15,88,202 ; addps %xmm2,%xmm1 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,87,219 ; xorps %xmm3,%xmm3 + DB 15,87,228 ; xorps %xmm4,%xmm4 + DB 15,87,237 ; xorps %xmm5,%xmm5 + DB 15,87,246 ; xorps %xmm6,%xmm6 + DB 15,87,255 ; xorps %xmm7,%xmm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_constant_color_sse41 +_sk_constant_color_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,15,16,80,8 ; movss 0x8(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 243,15,16,88,12 ; movss 0xc(%rax),%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clear_sse41 +_sk_clear_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,87,192 ; xorps %xmm0,%xmm0 + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 15,87,219 ; xorps %xmm3,%xmm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcatop_sse41 +_sk_srcatop_sse41 LABEL PROC + DB 15,89,199 ; mulps %xmm7,%xmm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,92,195 ; subps %xmm3,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,204 ; mulps %xmm4,%xmm9 + DB 65,15,88,193 ; addps %xmm9,%xmm0 + DB 15,89,207 ; mulps %xmm7,%xmm1 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 65,15,88,201 ; addps %xmm9,%xmm1 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 65,15,88,209 ; addps %xmm9,%xmm2 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 65,15,88,216 ; addps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstatop_sse41 +_sk_dstatop_sse41 LABEL PROC + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 68,15,89,196 ; mulps %xmm4,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 68,15,92,207 ; subps %xmm7,%xmm9 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 68,15,89,197 ; mulps %xmm5,%xmm8 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 68,15,89,198 ; mulps %xmm6,%xmm8 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 65,15,88,208 ; addps %xmm8,%xmm2 + DB 68,15,89,203 ; mulps %xmm3,%xmm9 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 65,15,88,217 ; addps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcin_sse41 +_sk_srcin_sse41 LABEL PROC + DB 15,89,199 ; mulps %xmm7,%xmm0 + DB 15,89,207 ; mulps %xmm7,%xmm1 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstin_sse41 +_sk_dstin_sse41 LABEL PROC + DB 15,40,195 ; movaps %xmm3,%xmm0 + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 15,40,211 ; movaps %xmm3,%xmm2 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcout_sse41 +_sk_srcout_sse41 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,92,199 ; subps %xmm7,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstout_sse41 +_sk_dstout_sse41 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,92,195 ; subps %xmm3,%xmm8 + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,216 ; movaps %xmm8,%xmm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcover_sse41 +_sk_srcover_sse41 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,92,195 ; subps %xmm3,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,204 ; mulps %xmm4,%xmm9 + DB 65,15,88,193 ; addps %xmm9,%xmm0 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 65,15,88,201 ; addps %xmm9,%xmm1 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 65,15,88,209 ; addps %xmm9,%xmm2 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 65,15,88,216 ; addps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstover_sse41 +_sk_dstover_sse41 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,92,199 ; subps %xmm7,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 15,88,223 ; addps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_modulate_sse41 +_sk_modulate_sse41 LABEL PROC + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_multiply_sse41 +_sk_multiply_sse41 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,92,207 ; subps %xmm7,%xmm9 + DB 69,15,40,209 ; movaps %xmm9,%xmm10 + DB 68,15,89,208 ; mulps %xmm0,%xmm10 + DB 68,15,92,195 ; subps %xmm3,%xmm8 + DB 69,15,40,216 ; movaps %xmm8,%xmm11 + DB 68,15,89,220 ; mulps %xmm4,%xmm11 + DB 69,15,88,218 ; addps %xmm10,%xmm11 + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 65,15,88,195 ; addps %xmm11,%xmm0 + DB 69,15,40,209 ; movaps %xmm9,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 69,15,40,216 ; movaps %xmm8,%xmm11 + DB 68,15,89,221 ; mulps %xmm5,%xmm11 + DB 69,15,88,218 ; addps %xmm10,%xmm11 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 65,15,88,203 ; addps %xmm11,%xmm1 + DB 69,15,40,209 ; movaps %xmm9,%xmm10 + DB 68,15,89,210 ; mulps %xmm2,%xmm10 + DB 69,15,40,216 ; movaps %xmm8,%xmm11 + DB 68,15,89,222 ; mulps %xmm6,%xmm11 + DB 69,15,88,218 ; addps %xmm10,%xmm11 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 65,15,88,211 ; addps %xmm11,%xmm2 + DB 68,15,89,203 ; mulps %xmm3,%xmm9 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 69,15,88,193 ; addps %xmm9,%xmm8 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 65,15,88,216 ; addps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_plus__sse41 +_sk_plus__sse41 LABEL PROC + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 15,88,223 ; addps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_screen_sse41 +_sk_screen_sse41 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 68,15,88,196 ; addps %xmm4,%xmm8 + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 68,15,92,192 ; subps %xmm0,%xmm8 + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 68,15,88,205 ; addps %xmm5,%xmm9 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 68,15,92,201 ; subps %xmm1,%xmm9 + DB 68,15,40,210 ; movaps %xmm2,%xmm10 + DB 68,15,88,214 ; addps %xmm6,%xmm10 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 68,15,92,210 ; subps %xmm2,%xmm10 + DB 68,15,40,219 ; movaps %xmm3,%xmm11 + DB 68,15,88,223 ; addps %xmm7,%xmm11 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 68,15,92,219 ; subps %xmm3,%xmm11 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 65,15,40,201 ; movaps %xmm9,%xmm1 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 65,15,40,219 ; movaps %xmm11,%xmm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_xor__sse41 +_sk_xor__sse41 LABEL PROC + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,92,207 ; subps %xmm7,%xmm9 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,92,216 ; subps %xmm8,%xmm3 + DB 68,15,40,211 ; movaps %xmm3,%xmm10 + DB 68,15,89,212 ; mulps %xmm4,%xmm10 + DB 65,15,88,194 ; addps %xmm10,%xmm0 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 68,15,40,211 ; movaps %xmm3,%xmm10 + DB 68,15,89,213 ; mulps %xmm5,%xmm10 + DB 65,15,88,202 ; addps %xmm10,%xmm1 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 68,15,40,211 ; movaps %xmm3,%xmm10 + DB 68,15,89,214 ; mulps %xmm6,%xmm10 + DB 65,15,88,210 ; addps %xmm10,%xmm2 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 65,15,88,217 ; addps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_darken_sse41 +_sk_darken_sse41 LABEL PROC + DB 68,15,40,193 ; movaps %xmm1,%xmm8 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 68,15,89,207 ; mulps %xmm7,%xmm9 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 15,89,204 ; mulps %xmm4,%xmm1 + DB 68,15,95,201 ; maxps %xmm1,%xmm9 + DB 65,15,92,193 ; subps %xmm9,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 69,15,95,193 ; maxps %xmm9,%xmm8 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 68,15,40,194 ; movaps %xmm2,%xmm8 + DB 68,15,88,198 ; addps %xmm6,%xmm8 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 65,15,95,209 ; maxps %xmm9,%xmm2 + DB 68,15,92,194 ; subps %xmm2,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 15,88,218 ; addps %xmm2,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lighten_sse41 +_sk_lighten_sse41 LABEL PROC + DB 68,15,40,193 ; movaps %xmm1,%xmm8 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 68,15,89,207 ; mulps %xmm7,%xmm9 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 15,89,204 ; mulps %xmm4,%xmm1 + DB 68,15,93,201 ; minps %xmm1,%xmm9 + DB 65,15,92,193 ; subps %xmm9,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 69,15,93,193 ; minps %xmm9,%xmm8 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 68,15,40,194 ; movaps %xmm2,%xmm8 + DB 68,15,88,198 ; addps %xmm6,%xmm8 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 65,15,93,209 ; minps %xmm9,%xmm2 + DB 68,15,92,194 ; subps %xmm2,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 15,88,218 ; addps %xmm2,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_difference_sse41 +_sk_difference_sse41 LABEL PROC + DB 68,15,40,193 ; movaps %xmm1,%xmm8 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 68,15,89,207 ; mulps %xmm7,%xmm9 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 15,89,204 ; mulps %xmm4,%xmm1 + DB 68,15,93,201 ; minps %xmm1,%xmm9 + DB 69,15,88,201 ; addps %xmm9,%xmm9 + DB 65,15,92,193 ; subps %xmm9,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 69,15,93,193 ; minps %xmm9,%xmm8 + DB 69,15,88,192 ; addps %xmm8,%xmm8 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 68,15,40,194 ; movaps %xmm2,%xmm8 + DB 68,15,88,198 ; addps %xmm6,%xmm8 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 65,15,93,209 ; minps %xmm9,%xmm2 + DB 15,88,210 ; addps %xmm2,%xmm2 + DB 68,15,92,194 ; subps %xmm2,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 15,88,218 ; addps %xmm2,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_exclusion_sse41 +_sk_exclusion_sse41 LABEL PROC + DB 68,15,40,193 ; movaps %xmm1,%xmm8 + DB 15,40,200 ; movaps %xmm0,%xmm1 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 15,89,204 ; mulps %xmm4,%xmm1 + DB 15,88,201 ; addps %xmm1,%xmm1 + DB 15,92,193 ; subps %xmm1,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 68,15,89,197 ; mulps %xmm5,%xmm8 + DB 69,15,88,192 ; addps %xmm8,%xmm8 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 68,15,40,194 ; movaps %xmm2,%xmm8 + DB 68,15,88,198 ; addps %xmm6,%xmm8 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 15,88,210 ; addps %xmm2,%xmm2 + DB 68,15,92,194 ; subps %xmm2,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 15,88,218 ; addps %xmm2,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_colorburn_sse41 +_sk_colorburn_sse41 LABEL PROC + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,40,218 ; movaps %xmm10,%xmm11 + DB 68,15,92,223 ; subps %xmm7,%xmm11 + DB 69,15,40,227 ; movaps %xmm11,%xmm12 + DB 69,15,89,225 ; mulps %xmm9,%xmm12 + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 15,40,199 ; movaps %xmm7,%xmm0 + DB 15,92,196 ; subps %xmm4,%xmm0 + DB 15,89,195 ; mulps %xmm3,%xmm0 + DB 65,15,94,193 ; divps %xmm9,%xmm0 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,93,232 ; minps %xmm0,%xmm13 + DB 68,15,40,247 ; movaps %xmm7,%xmm14 + DB 69,15,92,245 ; subps %xmm13,%xmm14 + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 65,15,194,192,0 ; cmpeqps %xmm8,%xmm0 + DB 68,15,92,211 ; subps %xmm3,%xmm10 + DB 68,15,89,243 ; mulps %xmm3,%xmm14 + DB 69,15,88,244 ; addps %xmm12,%xmm14 + DB 102,69,15,56,20,241 ; blendvps %xmm0,%xmm9,%xmm14 + DB 69,15,40,202 ; movaps %xmm10,%xmm9 + DB 68,15,89,204 ; mulps %xmm4,%xmm9 + DB 68,15,88,228 ; addps %xmm4,%xmm12 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 15,194,199,0 ; cmpeqps %xmm7,%xmm0 + DB 69,15,88,206 ; addps %xmm14,%xmm9 + DB 102,69,15,56,20,204 ; blendvps %xmm0,%xmm12,%xmm9 + DB 69,15,40,227 ; movaps %xmm11,%xmm12 + DB 68,15,89,225 ; mulps %xmm1,%xmm12 + DB 15,40,199 ; movaps %xmm7,%xmm0 + DB 15,92,197 ; subps %xmm5,%xmm0 + DB 15,89,195 ; mulps %xmm3,%xmm0 + DB 15,94,193 ; divps %xmm1,%xmm0 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,93,232 ; minps %xmm0,%xmm13 + DB 68,15,40,247 ; movaps %xmm7,%xmm14 + DB 69,15,92,245 ; subps %xmm13,%xmm14 + DB 15,40,193 ; movaps %xmm1,%xmm0 + DB 65,15,194,192,0 ; cmpeqps %xmm8,%xmm0 + DB 68,15,89,243 ; mulps %xmm3,%xmm14 + DB 69,15,88,244 ; addps %xmm12,%xmm14 + DB 102,68,15,56,20,241 ; blendvps %xmm0,%xmm1,%xmm14 + DB 65,15,40,202 ; movaps %xmm10,%xmm1 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 68,15,88,229 ; addps %xmm5,%xmm12 + DB 65,15,88,206 ; addps %xmm14,%xmm1 + DB 15,40,197 ; movaps %xmm5,%xmm0 + DB 15,194,199,0 ; cmpeqps %xmm7,%xmm0 + DB 102,65,15,56,20,204 ; blendvps %xmm0,%xmm12,%xmm1 + DB 15,40,199 ; movaps %xmm7,%xmm0 + DB 15,92,198 ; subps %xmm6,%xmm0 + DB 15,89,195 ; mulps %xmm3,%xmm0 + DB 15,94,194 ; divps %xmm2,%xmm0 + DB 68,15,40,231 ; movaps %xmm7,%xmm12 + DB 68,15,93,224 ; minps %xmm0,%xmm12 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 69,15,92,236 ; subps %xmm12,%xmm13 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 68,15,194,194,0 ; cmpeqps %xmm2,%xmm8 + DB 68,15,89,235 ; mulps %xmm3,%xmm13 + DB 69,15,88,235 ; addps %xmm11,%xmm13 + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 102,68,15,56,20,234 ; blendvps %xmm0,%xmm2,%xmm13 + DB 68,15,88,222 ; addps %xmm6,%xmm11 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 65,15,88,213 ; addps %xmm13,%xmm2 + DB 15,40,198 ; movaps %xmm6,%xmm0 + DB 15,194,199,0 ; cmpeqps %xmm7,%xmm0 + DB 102,65,15,56,20,211 ; blendvps %xmm0,%xmm11,%xmm2 + DB 68,15,89,215 ; mulps %xmm7,%xmm10 + DB 65,15,88,218 ; addps %xmm10,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_colordodge_sse41 +_sk_colordodge_sse41 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,40,218 ; movaps %xmm10,%xmm11 + DB 68,15,92,223 ; subps %xmm7,%xmm11 + DB 69,15,40,227 ; movaps %xmm11,%xmm12 + DB 69,15,89,224 ; mulps %xmm8,%xmm12 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,204 ; mulps %xmm4,%xmm9 + DB 15,40,195 ; movaps %xmm3,%xmm0 + DB 65,15,92,192 ; subps %xmm8,%xmm0 + DB 68,15,94,200 ; divps %xmm0,%xmm9 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,40,247 ; movaps %xmm7,%xmm14 + DB 69,15,93,241 ; minps %xmm9,%xmm14 + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 15,194,195,0 ; cmpeqps %xmm3,%xmm0 + DB 68,15,89,243 ; mulps %xmm3,%xmm14 + DB 69,15,88,244 ; addps %xmm12,%xmm14 + DB 102,69,15,56,20,240 ; blendvps %xmm0,%xmm8,%xmm14 + DB 69,15,87,201 ; xorps %xmm9,%xmm9 + DB 68,15,92,211 ; subps %xmm3,%xmm10 + DB 69,15,40,194 ; movaps %xmm10,%xmm8 + DB 68,15,89,196 ; mulps %xmm4,%xmm8 + DB 68,15,88,228 ; addps %xmm4,%xmm12 + DB 69,15,88,198 ; addps %xmm14,%xmm8 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 65,15,194,193,0 ; cmpeqps %xmm9,%xmm0 + DB 102,69,15,56,20,196 ; blendvps %xmm0,%xmm12,%xmm8 + DB 68,15,40,227 ; movaps %xmm3,%xmm12 + DB 68,15,89,229 ; mulps %xmm5,%xmm12 + DB 15,40,195 ; movaps %xmm3,%xmm0 + DB 15,92,193 ; subps %xmm1,%xmm0 + DB 68,15,94,224 ; divps %xmm0,%xmm12 + DB 69,15,40,243 ; movaps %xmm11,%xmm14 + DB 68,15,89,241 ; mulps %xmm1,%xmm14 + DB 69,15,93,236 ; minps %xmm12,%xmm13 + DB 15,40,193 ; movaps %xmm1,%xmm0 + DB 15,194,195,0 ; cmpeqps %xmm3,%xmm0 + DB 68,15,89,235 ; mulps %xmm3,%xmm13 + DB 69,15,88,238 ; addps %xmm14,%xmm13 + DB 102,68,15,56,20,233 ; blendvps %xmm0,%xmm1,%xmm13 + DB 65,15,40,202 ; movaps %xmm10,%xmm1 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 68,15,88,245 ; addps %xmm5,%xmm14 + DB 65,15,88,205 ; addps %xmm13,%xmm1 + DB 15,40,197 ; movaps %xmm5,%xmm0 + DB 65,15,194,193,0 ; cmpeqps %xmm9,%xmm0 + DB 102,65,15,56,20,206 ; blendvps %xmm0,%xmm14,%xmm1 + DB 68,15,40,227 ; movaps %xmm3,%xmm12 + DB 68,15,89,230 ; mulps %xmm6,%xmm12 + DB 15,40,195 ; movaps %xmm3,%xmm0 + DB 15,92,194 ; subps %xmm2,%xmm0 + DB 68,15,94,224 ; divps %xmm0,%xmm12 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,93,236 ; minps %xmm12,%xmm13 + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 15,194,195,0 ; cmpeqps %xmm3,%xmm0 + DB 68,15,89,235 ; mulps %xmm3,%xmm13 + DB 69,15,88,235 ; addps %xmm11,%xmm13 + DB 102,68,15,56,20,234 ; blendvps %xmm0,%xmm2,%xmm13 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 65,15,88,213 ; addps %xmm13,%xmm2 + DB 68,15,194,206,0 ; cmpeqps %xmm6,%xmm9 + DB 68,15,88,222 ; addps %xmm6,%xmm11 + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 102,65,15,56,20,211 ; blendvps %xmm0,%xmm11,%xmm2 + DB 68,15,89,215 ; mulps %xmm7,%xmm10 + DB 65,15,88,218 ; addps %xmm10,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_hardlight_sse41 +_sk_hardlight_sse41 LABEL PROC + DB 72,131,236,24 ; sub $0x18,%rsp + DB 15,41,52,36 ; movaps %xmm6,(%rsp) + DB 68,15,40,229 ; movaps %xmm5,%xmm12 + DB 15,40,244 ; movaps %xmm4,%xmm6 + DB 15,40,227 ; movaps %xmm3,%xmm4 + DB 15,40,234 ; movaps %xmm2,%xmm5 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 15,92,215 ; subps %xmm7,%xmm2 + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 68,15,92,212 ; subps %xmm4,%xmm10 + DB 69,15,40,194 ; movaps %xmm10,%xmm8 + DB 68,15,89,198 ; mulps %xmm6,%xmm8 + DB 68,15,88,192 ; addps %xmm0,%xmm8 + DB 68,15,40,252 ; movaps %xmm4,%xmm15 + DB 69,15,92,249 ; subps %xmm9,%xmm15 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,40,247 ; movaps %xmm7,%xmm14 + DB 15,40,199 ; movaps %xmm7,%xmm0 + DB 15,92,198 ; subps %xmm6,%xmm0 + DB 65,15,89,199 ; mulps %xmm15,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 68,15,40,251 ; movaps %xmm3,%xmm15 + DB 68,15,92,248 ; subps %xmm0,%xmm15 + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,194,196,2 ; cmpleps %xmm4,%xmm0 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 69,15,88,201 ; addps %xmm9,%xmm9 + DB 102,69,15,56,20,249 ; blendvps %xmm0,%xmm9,%xmm15 + DB 68,15,40,218 ; movaps %xmm2,%xmm11 + DB 68,15,89,217 ; mulps %xmm1,%xmm11 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 15,92,193 ; subps %xmm1,%xmm0 + DB 69,15,40,204 ; movaps %xmm12,%xmm9 + DB 69,15,92,233 ; subps %xmm9,%xmm13 + DB 68,15,89,232 ; mulps %xmm0,%xmm13 + DB 69,15,88,237 ; addps %xmm13,%xmm13 + DB 68,15,40,227 ; movaps %xmm3,%xmm12 + DB 69,15,92,229 ; subps %xmm13,%xmm12 + DB 15,40,193 ; movaps %xmm1,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,194,196,2 ; cmpleps %xmm4,%xmm0 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 69,15,40,233 ; movaps %xmm9,%xmm13 + DB 15,88,201 ; addps %xmm1,%xmm1 + DB 102,68,15,56,20,225 ; blendvps %xmm0,%xmm1,%xmm12 + DB 65,15,40,202 ; movaps %xmm10,%xmm1 + DB 69,15,40,202 ; movaps %xmm10,%xmm9 + DB 68,15,89,215 ; mulps %xmm7,%xmm10 + DB 69,15,88,199 ; addps %xmm15,%xmm8 + DB 65,15,89,205 ; mulps %xmm13,%xmm1 + DB 65,15,88,203 ; addps %xmm11,%xmm1 + DB 65,15,88,204 ; addps %xmm12,%xmm1 + DB 15,89,213 ; mulps %xmm5,%xmm2 + DB 68,15,40,28,36 ; movaps (%rsp),%xmm11 + DB 69,15,89,203 ; mulps %xmm11,%xmm9 + DB 68,15,88,202 ; addps %xmm2,%xmm9 + DB 15,40,197 ; movaps %xmm5,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,194,196,2 ; cmpleps %xmm4,%xmm0 + DB 15,40,212 ; movaps %xmm4,%xmm2 + DB 15,92,213 ; subps %xmm5,%xmm2 + DB 65,15,89,235 ; mulps %xmm11,%xmm5 + DB 15,88,237 ; addps %xmm5,%xmm5 + DB 69,15,92,243 ; subps %xmm11,%xmm14 + DB 68,15,89,242 ; mulps %xmm2,%xmm14 + DB 69,15,88,246 ; addps %xmm14,%xmm14 + DB 65,15,92,222 ; subps %xmm14,%xmm3 + DB 102,15,56,20,221 ; blendvps %xmm0,%xmm5,%xmm3 + DB 68,15,88,203 ; addps %xmm3,%xmm9 + DB 65,15,88,226 ; addps %xmm10,%xmm4 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 65,15,40,209 ; movaps %xmm9,%xmm2 + DB 15,40,220 ; movaps %xmm4,%xmm3 + DB 15,40,230 ; movaps %xmm6,%xmm4 + DB 65,15,40,237 ; movaps %xmm13,%xmm5 + DB 65,15,40,243 ; movaps %xmm11,%xmm6 + DB 72,131,196,24 ; add $0x18,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_overlay_sse41 +_sk_overlay_sse41 LABEL PROC + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 68,15,40,240 ; movaps %xmm0,%xmm14 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,40,218 ; movaps %xmm10,%xmm11 + DB 68,15,92,223 ; subps %xmm7,%xmm11 + DB 65,15,40,195 ; movaps %xmm11,%xmm0 + DB 65,15,89,198 ; mulps %xmm14,%xmm0 + DB 68,15,92,211 ; subps %xmm3,%xmm10 + DB 69,15,40,194 ; movaps %xmm10,%xmm8 + DB 68,15,89,196 ; mulps %xmm4,%xmm8 + DB 68,15,88,192 ; addps %xmm0,%xmm8 + DB 68,15,40,235 ; movaps %xmm3,%xmm13 + DB 69,15,92,238 ; subps %xmm14,%xmm13 + DB 68,15,89,244 ; mulps %xmm4,%xmm14 + DB 15,40,207 ; movaps %xmm7,%xmm1 + DB 15,92,204 ; subps %xmm4,%xmm1 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,194,199,2 ; cmpleps %xmm7,%xmm0 + DB 69,15,88,246 ; addps %xmm14,%xmm14 + DB 68,15,40,227 ; movaps %xmm3,%xmm12 + DB 68,15,89,231 ; mulps %xmm7,%xmm12 + DB 65,15,89,205 ; mulps %xmm13,%xmm1 + DB 15,88,201 ; addps %xmm1,%xmm1 + DB 69,15,40,236 ; movaps %xmm12,%xmm13 + DB 68,15,92,233 ; subps %xmm1,%xmm13 + DB 102,69,15,56,20,238 ; blendvps %xmm0,%xmm14,%xmm13 + DB 69,15,88,197 ; addps %xmm13,%xmm8 + DB 65,15,40,195 ; movaps %xmm11,%xmm0 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,40,202 ; movaps %xmm10,%xmm1 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 15,88,200 ; addps %xmm0,%xmm1 + DB 68,15,40,235 ; movaps %xmm3,%xmm13 + DB 69,15,92,233 ; subps %xmm9,%xmm13 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 68,15,40,247 ; movaps %xmm7,%xmm14 + DB 68,15,92,245 ; subps %xmm5,%xmm14 + DB 15,40,197 ; movaps %xmm5,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,194,199,2 ; cmpleps %xmm7,%xmm0 + DB 69,15,88,201 ; addps %xmm9,%xmm9 + DB 69,15,89,245 ; mulps %xmm13,%xmm14 + DB 69,15,88,246 ; addps %xmm14,%xmm14 + DB 69,15,40,236 ; movaps %xmm12,%xmm13 + DB 69,15,92,238 ; subps %xmm14,%xmm13 + DB 102,69,15,56,20,233 ; blendvps %xmm0,%xmm9,%xmm13 + DB 65,15,88,205 ; addps %xmm13,%xmm1 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,40,202 ; movaps %xmm10,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 69,15,88,203 ; addps %xmm11,%xmm9 + DB 68,15,40,219 ; movaps %xmm3,%xmm11 + DB 68,15,92,218 ; subps %xmm2,%xmm11 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,92,238 ; subps %xmm6,%xmm13 + DB 15,40,198 ; movaps %xmm6,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,194,199,2 ; cmpleps %xmm7,%xmm0 + DB 15,88,210 ; addps %xmm2,%xmm2 + DB 69,15,89,235 ; mulps %xmm11,%xmm13 + DB 69,15,88,237 ; addps %xmm13,%xmm13 + DB 69,15,92,229 ; subps %xmm13,%xmm12 + DB 102,68,15,56,20,226 ; blendvps %xmm0,%xmm2,%xmm12 + DB 69,15,88,204 ; addps %xmm12,%xmm9 + DB 68,15,89,215 ; mulps %xmm7,%xmm10 + DB 65,15,88,218 ; addps %xmm10,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 65,15,40,209 ; movaps %xmm9,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_softlight_sse41 +_sk_softlight_sse41 LABEL PROC + DB 72,131,236,56 ; sub $0x38,%rsp + DB 15,41,116,36,16 ; movaps %xmm6,0x10(%rsp) + DB 15,40,244 ; movaps %xmm4,%xmm6 + DB 15,41,84,36,32 ; movaps %xmm2,0x20(%rsp) + DB 68,15,40,225 ; movaps %xmm1,%xmm12 + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 15,87,228 ; xorps %xmm4,%xmm4 + DB 15,194,231,1 ; cmpltps %xmm7,%xmm4 + DB 15,40,198 ; movaps %xmm6,%xmm0 + DB 15,94,199 ; divps %xmm7,%xmm0 + DB 15,84,196 ; andps %xmm4,%xmm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 68,15,40,209 ; movaps %xmm1,%xmm10 + DB 68,15,92,208 ; subps %xmm0,%xmm10 + DB 68,15,40,240 ; movaps %xmm0,%xmm14 + DB 68,15,40,248 ; movaps %xmm0,%xmm15 + DB 15,82,208 ; rsqrtps %xmm0,%xmm2 + DB 68,15,83,218 ; rcpps %xmm2,%xmm11 + DB 68,15,92,216 ; subps %xmm0,%xmm11 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,40,208 ; movaps %xmm0,%xmm2 + DB 15,89,210 ; mulps %xmm2,%xmm2 + DB 15,88,208 ; addps %xmm0,%xmm2 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 69,15,88,201 ; addps %xmm9,%xmm9 + DB 68,15,92,241 ; subps %xmm1,%xmm14 + DB 68,15,89,242 ; mulps %xmm2,%xmm14 + DB 184,0,0,224,64 ; mov $0x40e00000,%eax + DB 102,68,15,110,232 ; movd %eax,%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,89,253 ; mulps %xmm13,%xmm15 + DB 69,15,88,254 ; addps %xmm14,%xmm15 + DB 15,40,198 ; movaps %xmm6,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,194,199,2 ; cmpleps %xmm7,%xmm0 + DB 102,69,15,56,20,223 ; blendvps %xmm0,%xmm15,%xmm11 + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 15,92,195 ; subps %xmm3,%xmm0 + DB 68,15,89,208 ; mulps %xmm0,%xmm10 + DB 68,15,88,211 ; addps %xmm3,%xmm10 + DB 68,15,89,214 ; mulps %xmm6,%xmm10 + DB 15,40,211 ; movaps %xmm3,%xmm2 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 15,89,199 ; mulps %xmm7,%xmm0 + DB 68,15,89,216 ; mulps %xmm0,%xmm11 + DB 68,15,88,218 ; addps %xmm2,%xmm11 + DB 68,15,194,203,2 ; cmpleps %xmm3,%xmm9 + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 102,69,15,56,20,218 ; blendvps %xmm0,%xmm10,%xmm11 + DB 68,15,40,213 ; movaps %xmm5,%xmm10 + DB 68,15,94,215 ; divps %xmm7,%xmm10 + DB 68,15,84,212 ; andps %xmm4,%xmm10 + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 69,15,92,202 ; subps %xmm10,%xmm9 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 15,88,210 ; addps %xmm2,%xmm2 + DB 15,88,210 ; addps %xmm2,%xmm2 + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 15,89,192 ; mulps %xmm0,%xmm0 + DB 15,88,194 ; addps %xmm2,%xmm0 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 15,92,209 ; subps %xmm1,%xmm2 + DB 15,89,208 ; mulps %xmm0,%xmm2 + DB 65,15,82,194 ; rsqrtps %xmm10,%xmm0 + DB 68,15,83,240 ; rcpps %xmm0,%xmm14 + DB 69,15,92,242 ; subps %xmm10,%xmm14 + DB 69,15,89,213 ; mulps %xmm13,%xmm10 + DB 68,15,88,210 ; addps %xmm2,%xmm10 + DB 15,40,197 ; movaps %xmm5,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,194,199,2 ; cmpleps %xmm7,%xmm0 + DB 102,69,15,56,20,242 ; blendvps %xmm0,%xmm10,%xmm14 + DB 65,15,40,196 ; movaps %xmm12,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,40,208 ; movaps %xmm0,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 68,15,88,203 ; addps %xmm3,%xmm9 + DB 15,41,44,36 ; movaps %xmm5,(%rsp) + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 68,15,89,242 ; mulps %xmm2,%xmm14 + DB 15,40,211 ; movaps %xmm3,%xmm2 + DB 15,89,213 ; mulps %xmm5,%xmm2 + DB 68,15,88,242 ; addps %xmm2,%xmm14 + DB 68,15,40,249 ; movaps %xmm1,%xmm15 + DB 15,194,195,2 ; cmpleps %xmm3,%xmm0 + DB 102,69,15,56,20,241 ; blendvps %xmm0,%xmm9,%xmm14 + DB 68,15,40,209 ; movaps %xmm1,%xmm10 + DB 15,40,108,36,16 ; movaps 0x10(%rsp),%xmm5 + DB 15,40,197 ; movaps %xmm5,%xmm0 + DB 15,94,199 ; divps %xmm7,%xmm0 + DB 15,84,196 ; andps %xmm4,%xmm0 + DB 15,40,208 ; movaps %xmm0,%xmm2 + DB 15,92,209 ; subps %xmm1,%xmm2 + DB 15,92,200 ; subps %xmm0,%xmm1 + DB 68,15,89,232 ; mulps %xmm0,%xmm13 + DB 15,82,224 ; rsqrtps %xmm0,%xmm4 + DB 68,15,83,204 ; rcpps %xmm4,%xmm9 + DB 68,15,92,200 ; subps %xmm0,%xmm9 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,40,224 ; movaps %xmm0,%xmm4 + DB 15,89,228 ; mulps %xmm4,%xmm4 + DB 15,88,224 ; addps %xmm0,%xmm4 + DB 15,89,226 ; mulps %xmm2,%xmm4 + DB 68,15,88,236 ; addps %xmm4,%xmm13 + DB 15,40,197 ; movaps %xmm5,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,194,199,2 ; cmpleps %xmm7,%xmm0 + DB 102,69,15,56,20,205 ; blendvps %xmm0,%xmm13,%xmm9 + DB 68,15,40,108,36,32 ; movaps 0x20(%rsp),%xmm13 + DB 65,15,40,197 ; movaps %xmm13,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 15,40,208 ; movaps %xmm0,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 15,89,202 ; mulps %xmm2,%xmm1 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 15,40,211 ; movaps %xmm3,%xmm2 + DB 15,89,213 ; mulps %xmm5,%xmm2 + DB 68,15,88,202 ; addps %xmm2,%xmm9 + DB 15,88,203 ; addps %xmm3,%xmm1 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 15,40,213 ; movaps %xmm5,%xmm2 + DB 15,194,195,2 ; cmpleps %xmm3,%xmm0 + DB 102,68,15,56,20,201 ; blendvps %xmm0,%xmm1,%xmm9 + DB 68,15,92,255 ; subps %xmm7,%xmm15 + DB 69,15,89,199 ; mulps %xmm15,%xmm8 + DB 69,15,89,231 ; mulps %xmm15,%xmm12 + DB 69,15,89,253 ; mulps %xmm13,%xmm15 + DB 68,15,92,211 ; subps %xmm3,%xmm10 + DB 65,15,40,194 ; movaps %xmm10,%xmm0 + DB 15,89,198 ; mulps %xmm6,%xmm0 + DB 68,15,88,192 ; addps %xmm0,%xmm8 + DB 69,15,88,195 ; addps %xmm11,%xmm8 + DB 65,15,40,194 ; movaps %xmm10,%xmm0 + DB 15,40,44,36 ; movaps (%rsp),%xmm5 + DB 15,89,197 ; mulps %xmm5,%xmm0 + DB 68,15,88,224 ; addps %xmm0,%xmm12 + DB 69,15,88,230 ; addps %xmm14,%xmm12 + DB 65,15,40,194 ; movaps %xmm10,%xmm0 + DB 15,89,194 ; mulps %xmm2,%xmm0 + DB 65,15,88,199 ; addps %xmm15,%xmm0 + DB 68,15,88,200 ; addps %xmm0,%xmm9 + DB 68,15,89,215 ; mulps %xmm7,%xmm10 + DB 65,15,88,218 ; addps %xmm10,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,230 ; movaps %xmm6,%xmm4 + DB 15,40,242 ; movaps %xmm2,%xmm6 + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 65,15,40,204 ; movaps %xmm12,%xmm1 + DB 65,15,40,209 ; movaps %xmm9,%xmm2 + DB 72,131,196,56 ; add $0x38,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_0_sse41 +_sk_clamp_0_sse41 LABEL PROC + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 65,15,95,192 ; maxps %xmm8,%xmm0 + DB 65,15,95,200 ; maxps %xmm8,%xmm1 + DB 65,15,95,208 ; maxps %xmm8,%xmm2 + DB 65,15,95,216 ; maxps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_1_sse41 +_sk_clamp_1_sse41 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,93,192 ; minps %xmm8,%xmm0 + DB 65,15,93,200 ; minps %xmm8,%xmm1 + DB 65,15,93,208 ; minps %xmm8,%xmm2 + DB 65,15,93,216 ; minps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_a_sse41 +_sk_clamp_a_sse41 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,93,216 ; minps %xmm8,%xmm3 + DB 15,93,195 ; minps %xmm3,%xmm0 + DB 15,93,203 ; minps %xmm3,%xmm1 + DB 15,93,211 ; minps %xmm3,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_set_rgb_sse41 +_sk_set_rgb_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,15,16,80,8 ; movss 0x8(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_swap_rb_sse41 +_sk_swap_rb_sse41 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_swap_sse41 +_sk_swap_sse41 LABEL PROC + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 68,15,40,202 ; movaps %xmm2,%xmm9 + DB 68,15,40,209 ; movaps %xmm1,%xmm10 + DB 68,15,40,216 ; movaps %xmm0,%xmm11 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 15,40,205 ; movaps %xmm5,%xmm1 + DB 15,40,214 ; movaps %xmm6,%xmm2 + DB 15,40,223 ; movaps %xmm7,%xmm3 + DB 65,15,40,227 ; movaps %xmm11,%xmm4 + DB 65,15,40,234 ; movaps %xmm10,%xmm5 + DB 65,15,40,241 ; movaps %xmm9,%xmm6 + DB 65,15,40,248 ; movaps %xmm8,%xmm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_move_src_dst_sse41 +_sk_move_src_dst_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,224 ; movaps %xmm0,%xmm4 + DB 15,40,233 ; movaps %xmm1,%xmm5 + DB 15,40,242 ; movaps %xmm2,%xmm6 + DB 15,40,251 ; movaps %xmm3,%xmm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_move_dst_src_sse41 +_sk_move_dst_src_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 15,40,205 ; movaps %xmm5,%xmm1 + DB 15,40,214 ; movaps %xmm6,%xmm2 + DB 15,40,223 ; movaps %xmm7,%xmm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_premul_sse41 +_sk_premul_sse41 LABEL PROC + DB 15,89,195 ; mulps %xmm3,%xmm0 + DB 15,89,203 ; mulps %xmm3,%xmm1 + DB 15,89,211 ; mulps %xmm3,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_unpremul_sse41 +_sk_unpremul_sse41 LABEL PROC + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 68,15,94,203 ; divps %xmm3,%xmm9 + DB 68,15,194,195,4 ; cmpneqps %xmm3,%xmm8 + DB 69,15,84,193 ; andps %xmm9,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_from_srgb_sse41 +_sk_from_srgb_sse41 LABEL PROC + DB 184,145,131,158,61 ; mov $0x3d9e8391,%eax + DB 102,68,15,110,216 ; movd %eax,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,40,211 ; movaps %xmm11,%xmm10 + DB 68,15,89,208 ; mulps %xmm0,%xmm10 + DB 68,15,40,240 ; movaps %xmm0,%xmm14 + DB 69,15,89,246 ; mulps %xmm14,%xmm14 + DB 184,154,153,153,62 ; mov $0x3e99999a,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 184,92,143,50,63 ; mov $0x3f328f5c,%eax + DB 102,68,15,110,224 ; movd %eax,%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,200 ; mulps %xmm0,%xmm9 + DB 69,15,88,204 ; addps %xmm12,%xmm9 + DB 184,10,215,35,59 ; mov $0x3b23d70a,%eax + DB 102,68,15,110,232 ; movd %eax,%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,89,206 ; mulps %xmm14,%xmm9 + DB 69,15,88,205 ; addps %xmm13,%xmm9 + DB 184,174,71,97,61 ; mov $0x3d6147ae,%eax + DB 102,68,15,110,240 ; movd %eax,%xmm14 + DB 69,15,198,246,0 ; shufps $0x0,%xmm14,%xmm14 + DB 65,15,194,198,1 ; cmpltps %xmm14,%xmm0 + DB 102,69,15,56,20,202 ; blendvps %xmm0,%xmm10,%xmm9 + DB 69,15,40,251 ; movaps %xmm11,%xmm15 + DB 68,15,89,249 ; mulps %xmm1,%xmm15 + DB 15,40,193 ; movaps %xmm1,%xmm0 + DB 15,89,192 ; mulps %xmm0,%xmm0 + DB 69,15,40,208 ; movaps %xmm8,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 69,15,88,212 ; addps %xmm12,%xmm10 + DB 68,15,89,208 ; mulps %xmm0,%xmm10 + DB 69,15,88,213 ; addps %xmm13,%xmm10 + DB 65,15,194,206,1 ; cmpltps %xmm14,%xmm1 + DB 15,40,193 ; movaps %xmm1,%xmm0 + DB 102,69,15,56,20,215 ; blendvps %xmm0,%xmm15,%xmm10 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 15,89,192 ; mulps %xmm0,%xmm0 + DB 68,15,89,194 ; mulps %xmm2,%xmm8 + DB 69,15,88,196 ; addps %xmm12,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 69,15,88,197 ; addps %xmm13,%xmm8 + DB 65,15,194,214,1 ; cmpltps %xmm14,%xmm2 + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 102,69,15,56,20,195 ; blendvps %xmm0,%xmm11,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 65,15,40,202 ; movaps %xmm10,%xmm1 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_to_srgb_sse41 +_sk_to_srgb_sse41 LABEL PROC + DB 72,131,236,24 ; sub $0x18,%rsp + DB 15,41,60,36 ; movaps %xmm7,(%rsp) + DB 15,40,254 ; movaps %xmm6,%xmm7 + DB 15,40,245 ; movaps %xmm5,%xmm6 + DB 15,40,236 ; movaps %xmm4,%xmm5 + DB 15,40,227 ; movaps %xmm3,%xmm4 + DB 15,40,218 ; movaps %xmm2,%xmm3 + DB 15,40,209 ; movaps %xmm1,%xmm2 + DB 68,15,82,192 ; rsqrtps %xmm0,%xmm8 + DB 69,15,83,200 ; rcpps %xmm8,%xmm9 + DB 69,15,82,248 ; rsqrtps %xmm8,%xmm15 + DB 184,41,92,71,65 ; mov $0x41475c29,%eax + DB 102,68,15,110,216 ; movd %eax,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,40,211 ; movaps %xmm11,%xmm10 + DB 68,15,89,208 ; mulps %xmm0,%xmm10 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 184,194,135,210,62 ; mov $0x3ed287c2,%eax + DB 102,68,15,110,224 ; movd %eax,%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 184,206,111,48,63 ; mov $0x3f306fce,%eax + DB 102,68,15,110,232 ; movd %eax,%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 184,168,87,202,61 ; mov $0x3dca57a8,%eax + DB 53,0,0,0,128 ; xor $0x80000000,%eax + DB 102,68,15,110,240 ; movd %eax,%xmm14 + DB 69,15,198,246,0 ; shufps $0x0,%xmm14,%xmm14 + DB 69,15,89,205 ; mulps %xmm13,%xmm9 + DB 69,15,88,206 ; addps %xmm14,%xmm9 + DB 69,15,89,252 ; mulps %xmm12,%xmm15 + DB 69,15,88,249 ; addps %xmm9,%xmm15 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 69,15,93,207 ; minps %xmm15,%xmm9 + DB 184,4,231,140,59 ; mov $0x3b8ce704,%eax + DB 102,68,15,110,248 ; movd %eax,%xmm15 + DB 69,15,198,255,0 ; shufps $0x0,%xmm15,%xmm15 + DB 65,15,194,199,1 ; cmpltps %xmm15,%xmm0 + DB 102,69,15,56,20,202 ; blendvps %xmm0,%xmm10,%xmm9 + DB 68,15,82,210 ; rsqrtps %xmm2,%xmm10 + DB 65,15,83,194 ; rcpps %xmm10,%xmm0 + DB 69,15,82,210 ; rsqrtps %xmm10,%xmm10 + DB 65,15,89,197 ; mulps %xmm13,%xmm0 + DB 65,15,88,198 ; addps %xmm14,%xmm0 + DB 69,15,89,212 ; mulps %xmm12,%xmm10 + DB 68,15,88,208 ; addps %xmm0,%xmm10 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 65,15,93,202 ; minps %xmm10,%xmm1 + DB 69,15,40,211 ; movaps %xmm11,%xmm10 + DB 68,15,89,210 ; mulps %xmm2,%xmm10 + DB 65,15,194,215,1 ; cmpltps %xmm15,%xmm2 + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 102,65,15,56,20,202 ; blendvps %xmm0,%xmm10,%xmm1 + DB 15,82,195 ; rsqrtps %xmm3,%xmm0 + DB 15,83,208 ; rcpps %xmm0,%xmm2 + DB 65,15,89,213 ; mulps %xmm13,%xmm2 + DB 65,15,88,214 ; addps %xmm14,%xmm2 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 65,15,89,196 ; mulps %xmm12,%xmm0 + DB 15,88,194 ; addps %xmm2,%xmm0 + DB 68,15,93,192 ; minps %xmm0,%xmm8 + DB 68,15,89,219 ; mulps %xmm3,%xmm11 + DB 65,15,194,223,1 ; cmpltps %xmm15,%xmm3 + DB 15,40,195 ; movaps %xmm3,%xmm0 + DB 102,69,15,56,20,195 ; blendvps %xmm0,%xmm11,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 15,40,220 ; movaps %xmm4,%xmm3 + DB 15,40,229 ; movaps %xmm5,%xmm4 + DB 15,40,238 ; movaps %xmm6,%xmm5 + DB 15,40,247 ; movaps %xmm7,%xmm6 + DB 15,40,60,36 ; movaps (%rsp),%xmm7 + DB 72,131,196,24 ; add $0x18,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_from_2dot2_sse41 +_sk_from_2dot2_sse41 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 65,15,82,192 ; rsqrtps %xmm8,%xmm0 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 68,15,82,200 ; rsqrtps %xmm0,%xmm9 + DB 65,15,82,193 ; rsqrtps %xmm9,%xmm0 + DB 68,15,82,208 ; rsqrtps %xmm0,%xmm10 + DB 69,15,89,192 ; mulps %xmm8,%xmm8 + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 15,89,192 ; mulps %xmm0,%xmm0 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,89,194 ; mulps %xmm10,%xmm0 + DB 69,15,87,210 ; xorps %xmm10,%xmm10 + DB 65,15,95,194 ; maxps %xmm10,%xmm0 + DB 68,15,82,193 ; rsqrtps %xmm1,%xmm8 + DB 69,15,82,192 ; rsqrtps %xmm8,%xmm8 + DB 69,15,82,192 ; rsqrtps %xmm8,%xmm8 + DB 69,15,82,200 ; rsqrtps %xmm8,%xmm9 + DB 69,15,82,193 ; rsqrtps %xmm9,%xmm8 + DB 69,15,82,216 ; rsqrtps %xmm8,%xmm11 + DB 15,89,201 ; mulps %xmm1,%xmm1 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 69,15,89,192 ; mulps %xmm8,%xmm8 + DB 69,15,89,193 ; mulps %xmm9,%xmm8 + DB 68,15,89,193 ; mulps %xmm1,%xmm8 + DB 69,15,89,195 ; mulps %xmm11,%xmm8 + DB 69,15,95,194 ; maxps %xmm10,%xmm8 + DB 15,82,202 ; rsqrtps %xmm2,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 68,15,82,217 ; rsqrtps %xmm1,%xmm11 + DB 65,15,82,203 ; rsqrtps %xmm11,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 15,89,210 ; mulps %xmm2,%xmm2 + DB 69,15,40,203 ; movaps %xmm11,%xmm9 + DB 69,15,89,201 ; mulps %xmm9,%xmm9 + DB 69,15,89,203 ; mulps %xmm11,%xmm9 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 68,15,89,201 ; mulps %xmm1,%xmm9 + DB 69,15,95,202 ; maxps %xmm10,%xmm9 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 65,15,40,209 ; movaps %xmm9,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_to_2dot2_sse41 +_sk_to_2dot2_sse41 LABEL PROC + DB 68,15,82,192 ; rsqrtps %xmm0,%xmm8 + DB 65,15,82,192 ; rsqrtps %xmm8,%xmm0 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 68,15,82,200 ; rsqrtps %xmm0,%xmm9 + DB 69,15,83,192 ; rcpps %xmm8,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 65,15,83,193 ; rcpps %xmm9,%xmm0 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 65,15,95,192 ; maxps %xmm8,%xmm0 + DB 68,15,82,201 ; rsqrtps %xmm1,%xmm9 + DB 65,15,82,201 ; rsqrtps %xmm9,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 68,15,82,209 ; rsqrtps %xmm1,%xmm10 + DB 69,15,83,201 ; rcpps %xmm9,%xmm9 + DB 68,15,89,201 ; mulps %xmm1,%xmm9 + DB 65,15,83,202 ; rcpps %xmm10,%xmm1 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 65,15,95,200 ; maxps %xmm8,%xmm1 + DB 68,15,82,202 ; rsqrtps %xmm2,%xmm9 + DB 65,15,82,209 ; rsqrtps %xmm9,%xmm2 + DB 15,82,210 ; rsqrtps %xmm2,%xmm2 + DB 15,82,210 ; rsqrtps %xmm2,%xmm2 + DB 15,82,210 ; rsqrtps %xmm2,%xmm2 + DB 68,15,82,210 ; rsqrtps %xmm2,%xmm10 + DB 69,15,83,201 ; rcpps %xmm9,%xmm9 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 65,15,83,210 ; rcpps %xmm10,%xmm2 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 65,15,95,208 ; maxps %xmm8,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_rgb_to_hsl_sse41 +_sk_rgb_to_hsl_sse41 LABEL PROC + DB 72,131,236,24 ; sub $0x18,%rsp + DB 15,41,60,36 ; movaps %xmm7,(%rsp) + DB 15,40,254 ; movaps %xmm6,%xmm7 + DB 15,40,245 ; movaps %xmm5,%xmm6 + DB 15,40,236 ; movaps %xmm4,%xmm5 + DB 15,40,227 ; movaps %xmm3,%xmm4 + DB 15,40,218 ; movaps %xmm2,%xmm3 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,216 ; movd %eax,%xmm11 + DB 65,184,171,170,42,62 ; mov $0x3e2aaaab,%r8d + DB 65,185,0,0,192,64 ; mov $0x40c00000,%r9d + DB 184,0,0,0,64 ; mov $0x40000000,%eax + DB 185,0,0,128,64 ; mov $0x40800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 68,15,40,224 ; movaps %xmm0,%xmm12 + DB 68,15,95,225 ; maxps %xmm1,%xmm12 + DB 68,15,95,227 ; maxps %xmm3,%xmm12 + DB 68,15,40,232 ; movaps %xmm0,%xmm13 + DB 68,15,93,233 ; minps %xmm1,%xmm13 + DB 68,15,93,235 ; minps %xmm3,%xmm13 + DB 69,15,40,204 ; movaps %xmm12,%xmm9 + DB 68,15,194,200,0 ; cmpeqps %xmm0,%xmm9 + DB 68,15,40,241 ; movaps %xmm1,%xmm14 + DB 68,15,92,243 ; subps %xmm3,%xmm14 + DB 68,15,40,249 ; movaps %xmm1,%xmm15 + DB 68,15,194,251,1 ; cmpltps %xmm3,%xmm15 + DB 69,15,40,212 ; movaps %xmm12,%xmm10 + DB 68,15,194,209,0 ; cmpeqps %xmm1,%xmm10 + DB 15,92,216 ; subps %xmm0,%xmm3 + DB 15,92,193 ; subps %xmm1,%xmm0 + DB 65,15,40,212 ; movaps %xmm12,%xmm2 + DB 65,15,92,213 ; subps %xmm13,%xmm2 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 68,15,94,218 ; divps %xmm2,%xmm11 + DB 65,15,89,195 ; mulps %xmm11,%xmm0 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,88,192 ; addps %xmm0,%xmm8 + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 65,15,89,219 ; mulps %xmm11,%xmm3 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 15,88,217 ; addps %xmm1,%xmm3 + DB 65,15,40,194 ; movaps %xmm10,%xmm0 + DB 102,68,15,56,20,195 ; blendvps %xmm0,%xmm3,%xmm8 + DB 69,15,89,243 ; mulps %xmm11,%xmm14 + DB 102,65,15,110,217 ; movd %r9d,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,84,223 ; andps %xmm15,%xmm3 + DB 65,15,88,222 ; addps %xmm14,%xmm3 + DB 184,0,0,0,63 ; mov $0x3f000000,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 102,68,15,56,20,195 ; blendvps %xmm0,%xmm3,%xmm8 + DB 65,15,40,220 ; movaps %xmm12,%xmm3 + DB 65,15,92,204 ; subps %xmm12,%xmm1 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,40,204 ; movaps %xmm12,%xmm9 + DB 69,15,89,202 ; mulps %xmm10,%xmm9 + DB 69,15,194,209,1 ; cmpltps %xmm9,%xmm10 + DB 65,15,92,205 ; subps %xmm13,%xmm1 + DB 65,15,40,194 ; movaps %xmm10,%xmm0 + DB 102,68,15,56,20,225 ; blendvps %xmm0,%xmm1,%xmm12 + DB 65,15,194,221,4 ; cmpneqps %xmm13,%xmm3 + DB 102,65,15,110,192 ; movd %r8d,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 68,15,84,195 ; andps %xmm3,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 65,15,94,212 ; divps %xmm12,%xmm2 + DB 15,84,211 ; andps %xmm3,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 15,40,202 ; movaps %xmm2,%xmm1 + DB 65,15,40,209 ; movaps %xmm9,%xmm2 + DB 15,40,220 ; movaps %xmm4,%xmm3 + DB 15,40,229 ; movaps %xmm5,%xmm4 + DB 15,40,238 ; movaps %xmm6,%xmm5 + DB 15,40,247 ; movaps %xmm7,%xmm6 + DB 15,40,60,36 ; movaps (%rsp),%xmm7 + DB 72,131,196,24 ; add $0x18,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_hsl_to_rgb_sse41 +_sk_hsl_to_rgb_sse41 LABEL PROC + DB 72,129,236,152,0,0,0 ; sub $0x98,%rsp + DB 15,41,188,36,128,0,0,0 ; movaps %xmm7,0x80(%rsp) + DB 15,41,116,36,112 ; movaps %xmm6,0x70(%rsp) + DB 15,41,108,36,96 ; movaps %xmm5,0x60(%rsp) + DB 15,41,100,36,80 ; movaps %xmm4,0x50(%rsp) + DB 15,41,92,36,64 ; movaps %xmm3,0x40(%rsp) + DB 68,15,40,208 ; movaps %xmm0,%xmm10 + DB 184,0,0,0,63 ; mov $0x3f000000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 15,41,28,36 ; movaps %xmm3,(%rsp) + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 15,194,195,1 ; cmpltps %xmm3,%xmm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,40,224 ; movaps %xmm8,%xmm4 + DB 15,88,225 ; addps %xmm1,%xmm4 + DB 15,89,226 ; mulps %xmm2,%xmm4 + DB 15,40,217 ; movaps %xmm1,%xmm3 + DB 15,40,249 ; movaps %xmm1,%xmm7 + DB 15,88,250 ; addps %xmm2,%xmm7 + DB 15,89,218 ; mulps %xmm2,%xmm3 + DB 15,40,234 ; movaps %xmm2,%xmm5 + DB 15,92,251 ; subps %xmm3,%xmm7 + DB 102,15,56,20,252 ; blendvps %xmm0,%xmm4,%xmm7 + DB 184,0,0,0,64 ; mov $0x40000000,%eax + DB 185,171,170,170,62 ; mov $0x3eaaaaab,%ecx + DB 102,15,110,209 ; movd %ecx,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,41,84,36,48 ; movaps %xmm2,0x30(%rsp) + DB 65,15,88,210 ; addps %xmm10,%xmm2 + DB 185,0,0,0,0 ; mov $0x0,%ecx + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 15,194,194,1 ; cmpltps %xmm2,%xmm0 + DB 15,40,218 ; movaps %xmm2,%xmm3 + DB 65,15,92,216 ; subps %xmm8,%xmm3 + DB 68,15,40,226 ; movaps %xmm2,%xmm12 + DB 102,68,15,56,20,227 ; blendvps %xmm0,%xmm3,%xmm12 + DB 102,68,15,110,241 ; movd %ecx,%xmm14 + DB 69,15,198,246,0 ; shufps $0x0,%xmm14,%xmm14 + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 65,15,194,198,1 ; cmpltps %xmm14,%xmm0 + DB 68,15,41,116,36,32 ; movaps %xmm14,0x20(%rsp) + DB 65,15,40,216 ; movaps %xmm8,%xmm3 + DB 15,88,218 ; addps %xmm2,%xmm3 + DB 102,68,15,56,20,227 ; blendvps %xmm0,%xmm3,%xmm12 + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 15,40,229 ; movaps %xmm5,%xmm4 + DB 15,41,100,36,16 ; movaps %xmm4,0x10(%rsp) + DB 68,15,89,204 ; mulps %xmm4,%xmm9 + DB 68,15,92,207 ; subps %xmm7,%xmm9 + DB 184,171,170,42,62 ; mov $0x3e2aaaab,%eax + DB 15,40,199 ; movaps %xmm7,%xmm0 + DB 65,15,92,193 ; subps %xmm9,%xmm0 + DB 185,0,0,192,64 ; mov $0x40c00000,%ecx + DB 102,15,110,241 ; movd %ecx,%xmm6 + DB 15,198,246,0 ; shufps $0x0,%xmm6,%xmm6 + DB 15,89,240 ; mulps %xmm0,%xmm6 + DB 185,171,170,42,63 ; mov $0x3f2aaaab,%ecx + DB 102,15,110,217 ; movd %ecx,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 15,40,235 ; movaps %xmm3,%xmm5 + DB 65,15,92,236 ; subps %xmm12,%xmm5 + DB 69,15,40,236 ; movaps %xmm12,%xmm13 + DB 69,15,40,252 ; movaps %xmm12,%xmm15 + DB 68,15,194,227,1 ; cmpltps %xmm3,%xmm12 + DB 15,89,238 ; mulps %xmm6,%xmm5 + DB 65,15,88,233 ; addps %xmm9,%xmm5 + DB 69,15,40,217 ; movaps %xmm9,%xmm11 + DB 65,15,40,196 ; movaps %xmm12,%xmm0 + DB 102,68,15,56,20,221 ; blendvps %xmm0,%xmm5,%xmm11 + DB 68,15,194,60,36,1 ; cmpltps (%rsp),%xmm15 + DB 65,15,40,199 ; movaps %xmm15,%xmm0 + DB 102,68,15,56,20,223 ; blendvps %xmm0,%xmm7,%xmm11 + DB 102,15,110,232 ; movd %eax,%xmm5 + DB 15,198,237,0 ; shufps $0x0,%xmm5,%xmm5 + DB 68,15,194,237,1 ; cmpltps %xmm5,%xmm13 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 65,15,88,209 ; addps %xmm9,%xmm2 + DB 65,15,40,197 ; movaps %xmm13,%xmm0 + DB 102,68,15,56,20,218 ; blendvps %xmm0,%xmm2,%xmm11 + DB 69,15,87,228 ; xorps %xmm12,%xmm12 + DB 68,15,194,225,0 ; cmpeqps %xmm1,%xmm12 + DB 65,15,40,196 ; movaps %xmm12,%xmm0 + DB 102,68,15,56,20,220 ; blendvps %xmm0,%xmm4,%xmm11 + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 65,15,194,194,1 ; cmpltps %xmm10,%xmm0 + DB 65,15,40,202 ; movaps %xmm10,%xmm1 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 69,15,40,234 ; movaps %xmm10,%xmm13 + DB 102,68,15,56,20,233 ; blendvps %xmm0,%xmm1,%xmm13 + DB 65,15,40,194 ; movaps %xmm10,%xmm0 + DB 65,15,194,198,1 ; cmpltps %xmm14,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 65,15,88,202 ; addps %xmm10,%xmm1 + DB 102,68,15,56,20,233 ; blendvps %xmm0,%xmm1,%xmm13 + DB 68,15,40,243 ; movaps %xmm3,%xmm14 + DB 69,15,92,245 ; subps %xmm13,%xmm14 + DB 65,15,40,229 ; movaps %xmm13,%xmm4 + DB 69,15,40,253 ; movaps %xmm13,%xmm15 + DB 68,15,194,235,1 ; cmpltps %xmm3,%xmm13 + DB 68,15,89,246 ; mulps %xmm6,%xmm14 + DB 69,15,88,241 ; addps %xmm9,%xmm14 + DB 65,15,40,201 ; movaps %xmm9,%xmm1 + DB 65,15,40,197 ; movaps %xmm13,%xmm0 + DB 102,65,15,56,20,206 ; blendvps %xmm0,%xmm14,%xmm1 + DB 68,15,40,52,36 ; movaps (%rsp),%xmm14 + DB 69,15,194,254,1 ; cmpltps %xmm14,%xmm15 + DB 65,15,40,199 ; movaps %xmm15,%xmm0 + DB 102,15,56,20,207 ; blendvps %xmm0,%xmm7,%xmm1 + DB 15,194,229,1 ; cmpltps %xmm5,%xmm4 + DB 15,40,214 ; movaps %xmm6,%xmm2 + DB 65,15,89,210 ; mulps %xmm10,%xmm2 + DB 65,15,88,209 ; addps %xmm9,%xmm2 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 102,15,56,20,202 ; blendvps %xmm0,%xmm2,%xmm1 + DB 65,15,40,196 ; movaps %xmm12,%xmm0 + DB 68,15,40,124,36,16 ; movaps 0x10(%rsp),%xmm15 + DB 102,65,15,56,20,207 ; blendvps %xmm0,%xmm15,%xmm1 + DB 68,15,92,84,36,48 ; subps 0x30(%rsp),%xmm10 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 65,15,92,208 ; subps %xmm8,%xmm2 + DB 69,15,40,232 ; movaps %xmm8,%xmm13 + DB 69,15,194,194,1 ; cmpltps %xmm10,%xmm8 + DB 65,15,40,226 ; movaps %xmm10,%xmm4 + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 102,15,56,20,226 ; blendvps %xmm0,%xmm2,%xmm4 + DB 65,15,40,194 ; movaps %xmm10,%xmm0 + DB 15,194,68,36,32,1 ; cmpltps 0x20(%rsp),%xmm0 + DB 69,15,88,234 ; addps %xmm10,%xmm13 + DB 102,65,15,56,20,229 ; blendvps %xmm0,%xmm13,%xmm4 + DB 68,15,89,214 ; mulps %xmm6,%xmm10 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 15,194,195,1 ; cmpltps %xmm3,%xmm0 + DB 15,92,220 ; subps %xmm4,%xmm3 + DB 15,89,222 ; mulps %xmm6,%xmm3 + DB 69,15,88,209 ; addps %xmm9,%xmm10 + DB 65,15,88,217 ; addps %xmm9,%xmm3 + DB 102,68,15,56,20,203 ; blendvps %xmm0,%xmm3,%xmm9 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 65,15,194,198,1 ; cmpltps %xmm14,%xmm0 + DB 102,68,15,56,20,207 ; blendvps %xmm0,%xmm7,%xmm9 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 15,194,197,1 ; cmpltps %xmm5,%xmm0 + DB 102,69,15,56,20,202 ; blendvps %xmm0,%xmm10,%xmm9 + DB 65,15,40,196 ; movaps %xmm12,%xmm0 + DB 102,69,15,56,20,207 ; blendvps %xmm0,%xmm15,%xmm9 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,195 ; movaps %xmm11,%xmm0 + DB 65,15,40,209 ; movaps %xmm9,%xmm2 + DB 15,40,92,36,64 ; movaps 0x40(%rsp),%xmm3 + DB 15,40,100,36,80 ; movaps 0x50(%rsp),%xmm4 + DB 15,40,108,36,96 ; movaps 0x60(%rsp),%xmm5 + DB 15,40,116,36,112 ; movaps 0x70(%rsp),%xmm6 + DB 15,40,188,36,128,0,0,0 ; movaps 0x80(%rsp),%xmm7 + DB 72,129,196,152,0,0,0 ; add $0x98,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_scale_1_float_sse41 +_sk_scale_1_float_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,0 ; movss (%rax),%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_scale_u8_sse41 +_sk_scale_u8_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,68,15,56,49,4,56 ; pmovzxbd (%rax,%rdi,1),%xmm8 + DB 69,15,91,192 ; cvtdq2ps %xmm8,%xmm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 65,15,89,217 ; mulps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lerp_1_float_sse41 +_sk_lerp_1_float_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,0 ; movss (%rax),%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,92,196 ; subps %xmm4,%xmm0 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 15,92,205 ; subps %xmm5,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 15,92,214 ; subps %xmm6,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 15,92,223 ; subps %xmm7,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 15,88,223 ; addps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lerp_u8_sse41 +_sk_lerp_u8_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,68,15,56,49,4,56 ; pmovzxbd (%rax,%rdi,1),%xmm8 + DB 69,15,91,192 ; cvtdq2ps %xmm8,%xmm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 15,92,196 ; subps %xmm4,%xmm0 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 15,92,205 ; subps %xmm5,%xmm1 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 15,92,214 ; subps %xmm6,%xmm2 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 15,92,223 ; subps %xmm7,%xmm3 + DB 65,15,89,217 ; mulps %xmm9,%xmm3 + DB 15,88,223 ; addps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lerp_565_sse41 +_sk_lerp_565_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,68,15,56,51,4,120 ; pmovzxwd (%rax,%rdi,2),%xmm8 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,65,15,219,216 ; pand %xmm8,%xmm3 + DB 68,15,91,203 ; cvtdq2ps %xmm3,%xmm9 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,65,15,219,216 ; pand %xmm8,%xmm3 + DB 68,15,91,203 ; cvtdq2ps %xmm3,%xmm9 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 102,68,15,110,216 ; movd %eax,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,217 ; mulps %xmm9,%xmm11 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,65,15,219,216 ; pand %xmm8,%xmm3 + DB 68,15,91,195 ; cvtdq2ps %xmm3,%xmm8 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 15,92,196 ; subps %xmm4,%xmm0 + DB 65,15,89,194 ; mulps %xmm10,%xmm0 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 15,92,205 ; subps %xmm5,%xmm1 + DB 65,15,89,203 ; mulps %xmm11,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 15,92,214 ; subps %xmm6,%xmm2 + DB 15,89,211 ; mulps %xmm3,%xmm2 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_tables_sse41 +_sk_load_tables_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,8 ; mov (%rax),%rcx + DB 76,139,64,8 ; mov 0x8(%rax),%r8 + DB 243,68,15,111,4,185 ; movdqu (%rcx,%rdi,4),%xmm8 + DB 185,255,0,0,0 ; mov $0xff,%ecx + DB 102,15,110,193 ; movd %ecx,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,65,15,111,200 ; movdqa %xmm8,%xmm1 + DB 102,15,114,209,8 ; psrld $0x8,%xmm1 + DB 102,15,219,200 ; pand %xmm0,%xmm1 + DB 102,65,15,111,208 ; movdqa %xmm8,%xmm2 + DB 102,15,114,210,16 ; psrld $0x10,%xmm2 + DB 102,15,219,208 ; pand %xmm0,%xmm2 + DB 102,65,15,219,192 ; pand %xmm8,%xmm0 + DB 102,72,15,58,22,193,1 ; pextrq $0x1,%xmm0,%rcx + DB 65,137,201 ; mov %ecx,%r9d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,73,15,126,194 ; movq %xmm0,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 243,67,15,16,4,152 ; movss (%r8,%r11,4),%xmm0 + DB 102,67,15,58,33,4,144,16 ; insertps $0x10,(%r8,%r10,4),%xmm0 + DB 102,67,15,58,33,4,136,32 ; insertps $0x20,(%r8,%r9,4),%xmm0 + DB 102,65,15,58,33,4,136,48 ; insertps $0x30,(%r8,%rcx,4),%xmm0 + DB 76,139,64,16 ; mov 0x10(%rax),%r8 + DB 102,73,15,58,22,202,1 ; pextrq $0x1,%xmm1,%r10 + DB 77,137,209 ; mov %r10,%r9 + DB 73,193,233,32 ; shr $0x20,%r9 + DB 102,72,15,126,201 ; movq %xmm1,%rcx + DB 65,137,203 ; mov %ecx,%r11d + DB 65,129,227,255,255,255,0 ; and $0xffffff,%r11d + DB 72,193,233,30 ; shr $0x1e,%rcx + DB 65,129,226,255,255,255,0 ; and $0xffffff,%r10d + DB 243,67,15,16,12,152 ; movss (%r8,%r11,4),%xmm1 + DB 102,65,15,58,33,12,8,16 ; insertps $0x10,(%r8,%rcx,1),%xmm1 + DB 243,67,15,16,28,144 ; movss (%r8,%r10,4),%xmm3 + DB 102,15,58,33,203,32 ; insertps $0x20,%xmm3,%xmm1 + DB 243,67,15,16,28,136 ; movss (%r8,%r9,4),%xmm3 + DB 102,15,58,33,203,48 ; insertps $0x30,%xmm3,%xmm1 + DB 76,139,72,24 ; mov 0x18(%rax),%r9 + DB 102,72,15,58,22,209,1 ; pextrq $0x1,%xmm2,%rcx + DB 68,15,183,193 ; movzwl %cx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,72,15,126,208 ; movq %xmm2,%rax + DB 68,15,183,208 ; movzwl %ax,%r10d + DB 72,193,232,30 ; shr $0x1e,%rax + DB 243,67,15,16,20,145 ; movss (%r9,%r10,4),%xmm2 + DB 102,65,15,58,33,20,1,16 ; insertps $0x10,(%r9,%rax,1),%xmm2 + DB 243,67,15,16,28,129 ; movss (%r9,%r8,4),%xmm3 + DB 102,15,58,33,211,32 ; insertps $0x20,%xmm3,%xmm2 + DB 243,65,15,16,28,137 ; movss (%r9,%rcx,4),%xmm3 + DB 102,15,58,33,211,48 ; insertps $0x30,%xmm3,%xmm2 + DB 102,65,15,114,208,24 ; psrld $0x18,%xmm8 + DB 69,15,91,192 ; cvtdq2ps %xmm8,%xmm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_byte_tables_sse41 +_sk_byte_tables_sse41 LABEL PROC + DB 65,86 ; push %r14 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,127,67 ; mov $0x437f0000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 102,15,91,192 ; cvtps2dq %xmm0,%xmm0 + DB 102,72,15,58,22,193,1 ; pextrq $0x1,%xmm0,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,73,15,126,193 ; movq %xmm0,%r9 + DB 69,137,202 ; mov %r9d,%r10d + DB 77,137,203 ; mov %r9,%r11 + DB 73,193,235,32 ; shr $0x20,%r11 + DB 76,139,48 ; mov (%rax),%r14 + DB 76,139,72,8 ; mov 0x8(%rax),%r9 + DB 102,67,15,58,32,4,22,0 ; pinsrb $0x0,(%r14,%r10,1),%xmm0 + DB 102,67,15,58,32,4,30,1 ; pinsrb $0x1,(%r14,%r11,1),%xmm0 + DB 67,15,182,28,6 ; movzbl (%r14,%r8,1),%ebx + DB 102,15,58,32,195,2 ; pinsrb $0x2,%ebx,%xmm0 + DB 65,15,182,12,14 ; movzbl (%r14,%rcx,1),%ecx + DB 102,15,58,32,193,3 ; pinsrb $0x3,%ecx,%xmm0 + DB 102,15,56,49,192 ; pmovzxbd %xmm0,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 185,129,128,128,59 ; mov $0x3b808081,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 102,15,91,201 ; cvtps2dq %xmm1,%xmm1 + DB 102,72,15,58,22,201,1 ; pextrq $0x1,%xmm1,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,72,15,126,203 ; movq %xmm1,%rbx + DB 65,137,218 ; mov %ebx,%r10d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 102,67,15,58,32,12,17,0 ; pinsrb $0x0,(%r9,%r10,1),%xmm1 + DB 102,65,15,58,32,12,25,1 ; pinsrb $0x1,(%r9,%rbx,1),%xmm1 + DB 67,15,182,28,1 ; movzbl (%r9,%r8,1),%ebx + DB 102,15,58,32,203,2 ; pinsrb $0x2,%ebx,%xmm1 + DB 65,15,182,12,9 ; movzbl (%r9,%rcx,1),%ecx + DB 102,15,58,32,201,3 ; pinsrb $0x3,%ecx,%xmm1 + DB 102,15,56,49,201 ; pmovzxbd %xmm1,%xmm1 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 76,139,72,16 ; mov 0x10(%rax),%r9 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,15,91,210 ; cvtps2dq %xmm2,%xmm2 + DB 102,72,15,58,22,211,1 ; pextrq $0x1,%xmm2,%rbx + DB 65,137,216 ; mov %ebx,%r8d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 102,72,15,126,209 ; movq %xmm2,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,67,15,58,32,20,17,0 ; pinsrb $0x0,(%r9,%r10,1),%xmm2 + DB 102,65,15,58,32,20,9,1 ; pinsrb $0x1,(%r9,%rcx,1),%xmm2 + DB 67,15,182,12,1 ; movzbl (%r9,%r8,1),%ecx + DB 102,15,58,32,209,2 ; pinsrb $0x2,%ecx,%xmm2 + DB 65,15,182,12,25 ; movzbl (%r9,%rbx,1),%ecx + DB 102,15,58,32,209,3 ; pinsrb $0x3,%ecx,%xmm2 + DB 102,15,56,49,210 ; pmovzxbd %xmm2,%xmm2 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 72,139,64,24 ; mov 0x18(%rax),%rax + DB 68,15,89,195 ; mulps %xmm3,%xmm8 + DB 102,65,15,91,216 ; cvtps2dq %xmm8,%xmm3 + DB 102,72,15,58,22,217,1 ; pextrq $0x1,%xmm3,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,72,15,126,219 ; movq %xmm3,%rbx + DB 65,137,217 ; mov %ebx,%r9d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 102,66,15,58,32,28,8,0 ; pinsrb $0x0,(%rax,%r9,1),%xmm3 + DB 102,15,58,32,28,24,1 ; pinsrb $0x1,(%rax,%rbx,1),%xmm3 + DB 66,15,182,28,0 ; movzbl (%rax,%r8,1),%ebx + DB 102,15,58,32,219,2 ; pinsrb $0x2,%ebx,%xmm3 + DB 15,182,4,8 ; movzbl (%rax,%rcx,1),%eax + DB 102,15,58,32,216,3 ; pinsrb $0x3,%eax,%xmm3 + DB 102,15,56,49,219 ; pmovzxbd %xmm3,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 65,15,89,217 ; mulps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,94 ; pop %r14 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_byte_tables_rgb_sse41 +_sk_byte_tables_rgb_sse41 LABEL PROC + DB 65,86 ; push %r14 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 139,72,24 ; mov 0x18(%rax),%ecx + DB 255,201 ; dec %ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 102,69,15,112,192,0 ; pshufd $0x0,%xmm8,%xmm8 + DB 69,15,91,192 ; cvtdq2ps %xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 102,15,91,192 ; cvtps2dq %xmm0,%xmm0 + DB 102,72,15,58,22,193,1 ; pextrq $0x1,%xmm0,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,73,15,126,193 ; movq %xmm0,%r9 + DB 69,137,202 ; mov %r9d,%r10d + DB 77,137,203 ; mov %r9,%r11 + DB 73,193,235,32 ; shr $0x20,%r11 + DB 76,139,48 ; mov (%rax),%r14 + DB 76,139,72,8 ; mov 0x8(%rax),%r9 + DB 102,67,15,58,32,4,22,0 ; pinsrb $0x0,(%r14,%r10,1),%xmm0 + DB 102,67,15,58,32,4,30,1 ; pinsrb $0x1,(%r14,%r11,1),%xmm0 + DB 67,15,182,28,6 ; movzbl (%r14,%r8,1),%ebx + DB 102,15,58,32,195,2 ; pinsrb $0x2,%ebx,%xmm0 + DB 65,15,182,12,14 ; movzbl (%r14,%rcx,1),%ecx + DB 102,15,58,32,193,3 ; pinsrb $0x3,%ecx,%xmm0 + DB 102,15,56,49,192 ; pmovzxbd %xmm0,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 185,129,128,128,59 ; mov $0x3b808081,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 102,15,91,201 ; cvtps2dq %xmm1,%xmm1 + DB 102,72,15,58,22,201,1 ; pextrq $0x1,%xmm1,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,72,15,126,203 ; movq %xmm1,%rbx + DB 65,137,218 ; mov %ebx,%r10d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 102,67,15,58,32,12,17,0 ; pinsrb $0x0,(%r9,%r10,1),%xmm1 + DB 102,65,15,58,32,12,25,1 ; pinsrb $0x1,(%r9,%rbx,1),%xmm1 + DB 67,15,182,28,1 ; movzbl (%r9,%r8,1),%ebx + DB 102,15,58,32,203,2 ; pinsrb $0x2,%ebx,%xmm1 + DB 65,15,182,12,9 ; movzbl (%r9,%rcx,1),%ecx + DB 102,15,58,32,201,3 ; pinsrb $0x3,%ecx,%xmm1 + DB 102,15,56,49,201 ; pmovzxbd %xmm1,%xmm1 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 72,139,64,16 ; mov 0x10(%rax),%rax + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,15,91,210 ; cvtps2dq %xmm2,%xmm2 + DB 102,72,15,58,22,209,1 ; pextrq $0x1,%xmm2,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,72,15,126,211 ; movq %xmm2,%rbx + DB 65,137,217 ; mov %ebx,%r9d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 102,66,15,58,32,20,8,0 ; pinsrb $0x0,(%rax,%r9,1),%xmm2 + DB 102,15,58,32,20,24,1 ; pinsrb $0x1,(%rax,%rbx,1),%xmm2 + DB 66,15,182,28,0 ; movzbl (%rax,%r8,1),%ebx + DB 102,15,58,32,211,2 ; pinsrb $0x2,%ebx,%xmm2 + DB 15,182,4,8 ; movzbl (%rax,%rcx,1),%eax + DB 102,15,58,32,208,3 ; pinsrb $0x3,%eax,%xmm2 + DB 102,15,56,49,210 ; pmovzxbd %xmm2,%xmm2 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,94 ; pop %r14 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_a8_sse41 +_sk_load_a8_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,15,56,49,4,56 ; pmovzxbd (%rax,%rdi,1),%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 15,89,216 ; mulps %xmm0,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,87,192 ; xorps %xmm0,%xmm0 + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_a8_sse41 +_sk_gather_a8_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,56,64,209 ; pmulld %xmm1,%xmm2 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,194 ; paddd %xmm2,%xmm0 + DB 102,72,15,58,22,192,1 ; pextrq $0x1,%xmm0,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,67,15,58,32,4,17,0 ; pinsrb $0x0,(%r9,%r10,1),%xmm0 + DB 102,65,15,58,32,4,9,1 ; pinsrb $0x1,(%r9,%rcx,1),%xmm0 + DB 67,15,182,12,1 ; movzbl (%r9,%r8,1),%ecx + DB 102,15,58,32,193,2 ; pinsrb $0x2,%ecx,%xmm0 + DB 65,15,182,4,1 ; movzbl (%r9,%rax,1),%eax + DB 102,15,58,32,192,3 ; pinsrb $0x3,%eax,%xmm0 + DB 102,15,56,49,192 ; pmovzxbd %xmm0,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 15,89,216 ; mulps %xmm0,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,87,192 ; xorps %xmm0,%xmm0 + DB 102,15,239,201 ; pxor %xmm1,%xmm1 + DB 102,15,239,210 ; pxor %xmm2,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_a8_sse41 +_sk_store_a8_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,0,127,67 ; mov $0x437f0000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,89,195 ; mulps %xmm3,%xmm8 + DB 102,69,15,91,192 ; cvtps2dq %xmm8,%xmm8 + DB 102,69,15,56,43,192 ; packusdw %xmm8,%xmm8 + DB 102,69,15,103,192 ; packuswb %xmm8,%xmm8 + DB 102,68,15,126,4,56 ; movd %xmm8,(%rax,%rdi,1) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_g8_sse41 +_sk_load_g8_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,15,56,49,4,56 ; pmovzxbd (%rax,%rdi,1),%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,200 ; movaps %xmm0,%xmm1 + DB 15,40,208 ; movaps %xmm0,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_g8_sse41 +_sk_gather_g8_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,56,64,209 ; pmulld %xmm1,%xmm2 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,194 ; paddd %xmm2,%xmm0 + DB 102,72,15,58,22,192,1 ; pextrq $0x1,%xmm0,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,67,15,58,32,4,17,0 ; pinsrb $0x0,(%r9,%r10,1),%xmm0 + DB 102,65,15,58,32,4,9,1 ; pinsrb $0x1,(%r9,%rcx,1),%xmm0 + DB 67,15,182,12,1 ; movzbl (%r9,%r8,1),%ecx + DB 102,15,58,32,193,2 ; pinsrb $0x2,%ecx,%xmm0 + DB 65,15,182,4,1 ; movzbl (%r9,%rax,1),%eax + DB 102,15,58,32,192,3 ; pinsrb $0x3,%eax,%xmm0 + DB 102,15,56,49,192 ; pmovzxbd %xmm0,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,200 ; movaps %xmm0,%xmm1 + DB 15,40,208 ; movaps %xmm0,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_i8_sse41 +_sk_gather_i8_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 73,137,192 ; mov %rax,%r8 + DB 77,133,192 ; test %r8,%r8 + DB 116,5 ; je 1cdd <_sk_gather_i8_sse41+0xf> + DB 76,137,192 ; mov %r8,%rax + DB 235,2 ; jmp 1cdf <_sk_gather_i8_sse41+0x11> + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,16 ; mov (%rax),%r10 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,56,64,209 ; pmulld %xmm1,%xmm2 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,194 ; paddd %xmm2,%xmm0 + DB 102,72,15,58,22,192,1 ; pextrq $0x1,%xmm0,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,203 ; mov %ecx,%r11d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,67,15,58,32,4,26,0 ; pinsrb $0x0,(%r10,%r11,1),%xmm0 + DB 102,65,15,58,32,4,10,1 ; pinsrb $0x1,(%r10,%rcx,1),%xmm0 + DB 102,67,15,58,32,4,10,2 ; pinsrb $0x2,(%r10,%r9,1),%xmm0 + DB 102,65,15,58,32,4,2,3 ; pinsrb $0x3,(%r10,%rax,1),%xmm0 + DB 102,15,56,49,192 ; pmovzxbd %xmm0,%xmm0 + DB 102,73,15,58,22,193,1 ; pextrq $0x1,%xmm0,%r9 + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 73,139,64,8 ; mov 0x8(%r8),%rax + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,30 ; shr $0x1e,%rcx + DB 69,137,202 ; mov %r9d,%r10d + DB 73,193,233,30 ; shr $0x1e,%r9 + DB 102,66,15,110,28,128 ; movd (%rax,%r8,4),%xmm3 + DB 102,15,58,34,28,8,1 ; pinsrd $0x1,(%rax,%rcx,1),%xmm3 + DB 102,66,15,58,34,28,144,2 ; pinsrd $0x2,(%rax,%r10,4),%xmm3 + DB 102,66,15,58,34,28,8,3 ; pinsrd $0x3,(%rax,%r9,1),%xmm3 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,15,111,203 ; movdqa %xmm3,%xmm1 + DB 102,15,114,209,8 ; psrld $0x8,%xmm1 + DB 102,15,219,200 ; pand %xmm0,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,15,114,210,16 ; psrld $0x10,%xmm2 + DB 102,15,219,208 ; pand %xmm0,%xmm2 + DB 102,15,219,195 ; pand %xmm3,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,15,114,211,24 ; psrld $0x18,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_565_sse41 +_sk_load_565_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,15,56,51,20,120 ; pmovzxwd (%rax,%rdi,2),%xmm2 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,15,219,194 ; pand %xmm2,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 102,15,112,201,0 ; pshufd $0x0,%xmm1,%xmm1 + DB 102,15,219,202 ; pand %xmm2,%xmm1 + DB 15,91,217 ; cvtdq2ps %xmm1,%xmm3 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 15,89,203 ; mulps %xmm3,%xmm1 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,15,219,218 ; pand %xmm2,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,89,211 ; mulps %xmm3,%xmm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_565_sse41 +_sk_gather_565_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,56,64,209 ; pmulld %xmm1,%xmm2 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,194 ; paddd %xmm2,%xmm0 + DB 102,72,15,58,22,192,1 ; pextrq $0x1,%xmm0,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,67,15,196,4,81,0 ; pinsrw $0x0,(%r9,%r10,2),%xmm0 + DB 102,65,15,196,4,73,1 ; pinsrw $0x1,(%r9,%rcx,2),%xmm0 + DB 67,15,183,12,65 ; movzwl (%r9,%r8,2),%ecx + DB 102,15,196,193,2 ; pinsrw $0x2,%ecx,%xmm0 + DB 65,15,183,4,65 ; movzwl (%r9,%rax,2),%eax + DB 102,15,196,192,3 ; pinsrw $0x3,%eax,%xmm0 + DB 102,15,56,51,208 ; pmovzxwd %xmm0,%xmm2 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,15,219,194 ; pand %xmm2,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 102,15,112,201,0 ; pshufd $0x0,%xmm1,%xmm1 + DB 102,15,219,202 ; pand %xmm2,%xmm1 + DB 15,91,217 ; cvtdq2ps %xmm1,%xmm3 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 15,89,203 ; mulps %xmm3,%xmm1 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,15,219,218 ; pand %xmm2,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,89,211 ; mulps %xmm3,%xmm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_565_sse41 +_sk_store_565_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,0,248,65 ; mov $0x41f80000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,200 ; mulps %xmm0,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 102,65,15,114,241,11 ; pslld $0xb,%xmm9 + DB 185,0,0,124,66 ; mov $0x427c0000,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 102,69,15,91,210 ; cvtps2dq %xmm10,%xmm10 + DB 102,65,15,114,242,5 ; pslld $0x5,%xmm10 + DB 102,69,15,235,209 ; por %xmm9,%xmm10 + DB 68,15,89,194 ; mulps %xmm2,%xmm8 + DB 102,69,15,91,192 ; cvtps2dq %xmm8,%xmm8 + DB 102,69,15,86,194 ; orpd %xmm10,%xmm8 + DB 102,69,15,56,43,192 ; packusdw %xmm8,%xmm8 + DB 102,68,15,214,4,120 ; movq %xmm8,(%rax,%rdi,2) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_4444_sse41 +_sk_load_4444_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,68,15,56,51,12,120 ; pmovzxwd (%rax,%rdi,2),%xmm9 + DB 184,0,240,0,0 ; mov $0xf000,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,65,15,219,193 ; pand %xmm9,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,137,136,136,55 ; mov $0x37888889,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,0,15,0,0 ; mov $0xf00,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 102,15,112,201,0 ; pshufd $0x0,%xmm1,%xmm1 + DB 102,65,15,219,201 ; pand %xmm9,%xmm1 + DB 15,91,209 ; cvtdq2ps %xmm1,%xmm2 + DB 184,137,136,136,57 ; mov $0x39888889,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 15,89,202 ; mulps %xmm2,%xmm1 + DB 184,240,0,0,0 ; mov $0xf0,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,65,15,219,209 ; pand %xmm9,%xmm2 + DB 68,15,91,194 ; cvtdq2ps %xmm2,%xmm8 + DB 184,137,136,136,59 ; mov $0x3b888889,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 184,15,0,0,0 ; mov $0xf,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,65,15,219,217 ; pand %xmm9,%xmm3 + DB 68,15,91,195 ; cvtdq2ps %xmm3,%xmm8 + DB 184,137,136,136,61 ; mov $0x3d888889,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_4444_sse41 +_sk_gather_4444_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,56,64,209 ; pmulld %xmm1,%xmm2 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,194 ; paddd %xmm2,%xmm0 + DB 102,72,15,58,22,192,1 ; pextrq $0x1,%xmm0,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,67,15,196,4,81,0 ; pinsrw $0x0,(%r9,%r10,2),%xmm0 + DB 102,65,15,196,4,73,1 ; pinsrw $0x1,(%r9,%rcx,2),%xmm0 + DB 67,15,183,12,65 ; movzwl (%r9,%r8,2),%ecx + DB 102,15,196,193,2 ; pinsrw $0x2,%ecx,%xmm0 + DB 65,15,183,4,65 ; movzwl (%r9,%rax,2),%eax + DB 102,15,196,192,3 ; pinsrw $0x3,%eax,%xmm0 + DB 102,68,15,56,51,200 ; pmovzxwd %xmm0,%xmm9 + DB 184,0,240,0,0 ; mov $0xf000,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,65,15,219,193 ; pand %xmm9,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,137,136,136,55 ; mov $0x37888889,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,0,15,0,0 ; mov $0xf00,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 102,15,112,201,0 ; pshufd $0x0,%xmm1,%xmm1 + DB 102,65,15,219,201 ; pand %xmm9,%xmm1 + DB 15,91,209 ; cvtdq2ps %xmm1,%xmm2 + DB 184,137,136,136,57 ; mov $0x39888889,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 15,89,202 ; mulps %xmm2,%xmm1 + DB 184,240,0,0,0 ; mov $0xf0,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,65,15,219,209 ; pand %xmm9,%xmm2 + DB 68,15,91,194 ; cvtdq2ps %xmm2,%xmm8 + DB 184,137,136,136,59 ; mov $0x3b888889,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 184,15,0,0,0 ; mov $0xf,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,65,15,219,217 ; pand %xmm9,%xmm3 + DB 68,15,91,195 ; cvtdq2ps %xmm3,%xmm8 + DB 184,137,136,136,61 ; mov $0x3d888889,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_4444_sse41 +_sk_store_4444_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,0,112,65 ; mov $0x41700000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,200 ; mulps %xmm0,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 102,65,15,114,241,12 ; pslld $0xc,%xmm9 + DB 69,15,40,208 ; movaps %xmm8,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 102,69,15,91,210 ; cvtps2dq %xmm10,%xmm10 + DB 102,65,15,114,242,8 ; pslld $0x8,%xmm10 + DB 102,69,15,235,209 ; por %xmm9,%xmm10 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 102,65,15,114,241,4 ; pslld $0x4,%xmm9 + DB 68,15,89,195 ; mulps %xmm3,%xmm8 + DB 102,69,15,91,192 ; cvtps2dq %xmm8,%xmm8 + DB 102,69,15,86,193 ; orpd %xmm9,%xmm8 + DB 102,69,15,86,194 ; orpd %xmm10,%xmm8 + DB 102,69,15,56,43,192 ; packusdw %xmm8,%xmm8 + DB 102,68,15,214,4,120 ; movq %xmm8,(%rax,%rdi,2) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_8888_sse41 +_sk_load_8888_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 243,15,111,28,184 ; movdqu (%rax,%rdi,4),%xmm3 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,15,111,203 ; movdqa %xmm3,%xmm1 + DB 102,15,114,209,8 ; psrld $0x8,%xmm1 + DB 102,15,219,200 ; pand %xmm0,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,15,114,210,16 ; psrld $0x10,%xmm2 + DB 102,15,219,208 ; pand %xmm0,%xmm2 + DB 102,15,219,195 ; pand %xmm3,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,15,114,211,24 ; psrld $0x18,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_8888_sse41 +_sk_gather_8888_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,56,64,209 ; pmulld %xmm1,%xmm2 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,194 ; paddd %xmm2,%xmm0 + DB 102,72,15,126,192 ; movq %xmm0,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,58,22,193,1 ; pextrq $0x1,%xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,67,15,110,28,129 ; movd (%r9,%r8,4),%xmm3 + DB 102,65,15,58,34,28,129,1 ; pinsrd $0x1,(%r9,%rax,4),%xmm3 + DB 102,67,15,58,34,28,145,2 ; pinsrd $0x2,(%r9,%r10,4),%xmm3 + DB 102,65,15,58,34,28,137,3 ; pinsrd $0x3,(%r9,%rcx,4),%xmm3 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,15,111,203 ; movdqa %xmm3,%xmm1 + DB 102,15,114,209,8 ; psrld $0x8,%xmm1 + DB 102,15,219,200 ; pand %xmm0,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,15,114,210,16 ; psrld $0x10,%xmm2 + DB 102,15,219,208 ; pand %xmm0,%xmm2 + DB 102,15,219,195 ; pand %xmm3,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,15,114,211,24 ; psrld $0x18,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_8888_sse41 +_sk_store_8888_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,0,127,67 ; mov $0x437f0000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,200 ; mulps %xmm0,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 69,15,40,208 ; movaps %xmm8,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 102,69,15,91,210 ; cvtps2dq %xmm10,%xmm10 + DB 102,65,15,114,242,8 ; pslld $0x8,%xmm10 + DB 102,69,15,235,209 ; por %xmm9,%xmm10 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 102,65,15,114,241,16 ; pslld $0x10,%xmm9 + DB 68,15,89,195 ; mulps %xmm3,%xmm8 + DB 102,69,15,91,192 ; cvtps2dq %xmm8,%xmm8 + DB 102,65,15,114,240,24 ; pslld $0x18,%xmm8 + DB 102,69,15,235,193 ; por %xmm9,%xmm8 + DB 102,69,15,235,194 ; por %xmm10,%xmm8 + DB 243,68,15,127,4,184 ; movdqu %xmm8,(%rax,%rdi,4) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_f16_sse41 +_sk_load_f16_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 243,15,111,4,248 ; movdqu (%rax,%rdi,8),%xmm0 + DB 243,15,111,76,248,16 ; movdqu 0x10(%rax,%rdi,8),%xmm1 + DB 102,68,15,111,192 ; movdqa %xmm0,%xmm8 + DB 102,68,15,97,193 ; punpcklwd %xmm1,%xmm8 + DB 102,15,105,193 ; punpckhwd %xmm1,%xmm0 + DB 102,65,15,111,200 ; movdqa %xmm8,%xmm1 + DB 102,15,97,200 ; punpcklwd %xmm0,%xmm1 + DB 102,68,15,105,192 ; punpckhwd %xmm0,%xmm8 + DB 184,0,4,0,4 ; mov $0x4000400,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,216,0 ; pshufd $0x0,%xmm0,%xmm3 + DB 102,15,111,195 ; movdqa %xmm3,%xmm0 + DB 102,15,101,193 ; pcmpgtw %xmm1,%xmm0 + DB 102,15,223,193 ; pandn %xmm1,%xmm0 + DB 102,15,56,51,192 ; pmovzxwd %xmm0,%xmm0 + DB 102,15,114,240,13 ; pslld $0xd,%xmm0 + DB 184,0,0,128,119 ; mov $0x77800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 102,68,15,112,202,0 ; pshufd $0x0,%xmm2,%xmm9 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 102,15,112,201,78 ; pshufd $0x4e,%xmm1,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,15,101,209 ; pcmpgtw %xmm1,%xmm2 + DB 102,15,223,209 ; pandn %xmm1,%xmm2 + DB 102,15,56,51,202 ; pmovzxwd %xmm2,%xmm1 + DB 102,15,114,241,13 ; pslld $0xd,%xmm1 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,65,15,101,208 ; pcmpgtw %xmm8,%xmm2 + DB 102,65,15,223,208 ; pandn %xmm8,%xmm2 + DB 102,15,56,51,210 ; pmovzxwd %xmm2,%xmm2 + DB 102,15,114,242,13 ; pslld $0xd,%xmm2 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 102,69,15,112,192,78 ; pshufd $0x4e,%xmm8,%xmm8 + DB 102,65,15,101,216 ; pcmpgtw %xmm8,%xmm3 + DB 102,65,15,223,216 ; pandn %xmm8,%xmm3 + DB 102,15,56,51,219 ; pmovzxwd %xmm3,%xmm3 + DB 102,15,114,243,13 ; pslld $0xd,%xmm3 + DB 65,15,89,217 ; mulps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_f16_sse41 +_sk_gather_f16_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,56,64,209 ; pmulld %xmm1,%xmm2 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,194 ; paddd %xmm2,%xmm0 + DB 102,72,15,126,192 ; movq %xmm0,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,58,22,193,1 ; pextrq $0x1,%xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 243,65,15,126,4,201 ; movq (%r9,%rcx,8),%xmm0 + DB 243,67,15,126,12,209 ; movq (%r9,%r10,8),%xmm1 + DB 102,15,108,200 ; punpcklqdq %xmm0,%xmm1 + DB 243,65,15,126,4,193 ; movq (%r9,%rax,8),%xmm0 + DB 243,67,15,126,20,193 ; movq (%r9,%r8,8),%xmm2 + DB 102,15,108,208 ; punpcklqdq %xmm0,%xmm2 + DB 102,68,15,111,194 ; movdqa %xmm2,%xmm8 + DB 102,68,15,97,193 ; punpcklwd %xmm1,%xmm8 + DB 102,15,105,209 ; punpckhwd %xmm1,%xmm2 + DB 102,65,15,111,200 ; movdqa %xmm8,%xmm1 + DB 102,15,97,202 ; punpcklwd %xmm2,%xmm1 + DB 102,68,15,105,194 ; punpckhwd %xmm2,%xmm8 + DB 184,0,4,0,4 ; mov $0x4000400,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,216,0 ; pshufd $0x0,%xmm0,%xmm3 + DB 102,15,111,195 ; movdqa %xmm3,%xmm0 + DB 102,15,101,193 ; pcmpgtw %xmm1,%xmm0 + DB 102,15,223,193 ; pandn %xmm1,%xmm0 + DB 102,15,56,51,192 ; pmovzxwd %xmm0,%xmm0 + DB 102,15,114,240,13 ; pslld $0xd,%xmm0 + DB 184,0,0,128,119 ; mov $0x77800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 102,68,15,112,202,0 ; pshufd $0x0,%xmm2,%xmm9 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 102,15,112,201,78 ; pshufd $0x4e,%xmm1,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,15,101,209 ; pcmpgtw %xmm1,%xmm2 + DB 102,15,223,209 ; pandn %xmm1,%xmm2 + DB 102,15,56,51,202 ; pmovzxwd %xmm2,%xmm1 + DB 102,15,114,241,13 ; pslld $0xd,%xmm1 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,65,15,101,208 ; pcmpgtw %xmm8,%xmm2 + DB 102,65,15,223,208 ; pandn %xmm8,%xmm2 + DB 102,15,56,51,210 ; pmovzxwd %xmm2,%xmm2 + DB 102,15,114,242,13 ; pslld $0xd,%xmm2 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 102,69,15,112,192,78 ; pshufd $0x4e,%xmm8,%xmm8 + DB 102,65,15,101,216 ; pcmpgtw %xmm8,%xmm3 + DB 102,65,15,223,216 ; pandn %xmm8,%xmm3 + DB 102,15,56,51,219 ; pmovzxwd %xmm3,%xmm3 + DB 102,15,114,243,13 ; pslld $0xd,%xmm3 + DB 65,15,89,217 ; mulps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_f16_sse41 +_sk_store_f16_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,0,128,7 ; mov $0x7800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 102,69,15,112,200,0 ; pshufd $0x0,%xmm8,%xmm9 + DB 102,69,15,111,193 ; movdqa %xmm9,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 102,65,15,114,208,13 ; psrld $0xd,%xmm8 + DB 102,69,15,56,43,192 ; packusdw %xmm8,%xmm8 + DB 102,69,15,111,209 ; movdqa %xmm9,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 102,65,15,114,210,13 ; psrld $0xd,%xmm10 + DB 102,69,15,56,43,210 ; packusdw %xmm10,%xmm10 + DB 102,69,15,111,217 ; movdqa %xmm9,%xmm11 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 102,65,15,114,211,13 ; psrld $0xd,%xmm11 + DB 102,69,15,56,43,219 ; packusdw %xmm11,%xmm11 + DB 68,15,89,203 ; mulps %xmm3,%xmm9 + DB 102,65,15,114,209,13 ; psrld $0xd,%xmm9 + DB 102,69,15,56,43,201 ; packusdw %xmm9,%xmm9 + DB 102,69,15,97,194 ; punpcklwd %xmm10,%xmm8 + DB 102,69,15,97,217 ; punpcklwd %xmm9,%xmm11 + DB 102,69,15,111,200 ; movdqa %xmm8,%xmm9 + DB 102,69,15,98,203 ; punpckldq %xmm11,%xmm9 + DB 243,68,15,127,12,248 ; movdqu %xmm9,(%rax,%rdi,8) + DB 102,69,15,106,195 ; punpckhdq %xmm11,%xmm8 + DB 243,68,15,127,68,248,16 ; movdqu %xmm8,0x10(%rax,%rdi,8) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_u16_be_sse41 +_sk_load_u16_be_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 243,15,111,4,248 ; movdqu (%rax,%rdi,8),%xmm0 + DB 243,15,111,76,248,16 ; movdqu 0x10(%rax,%rdi,8),%xmm1 + DB 102,15,111,208 ; movdqa %xmm0,%xmm2 + DB 102,15,97,209 ; punpcklwd %xmm1,%xmm2 + DB 102,15,105,193 ; punpckhwd %xmm1,%xmm0 + DB 102,15,111,202 ; movdqa %xmm2,%xmm1 + DB 102,15,97,200 ; punpcklwd %xmm0,%xmm1 + DB 102,15,105,208 ; punpckhwd %xmm0,%xmm2 + DB 184,128,0,128,55 ; mov $0x37800080,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 102,15,111,193 ; movdqa %xmm1,%xmm0 + DB 102,15,113,240,8 ; psllw $0x8,%xmm0 + DB 102,15,112,217,78 ; pshufd $0x4e,%xmm1,%xmm3 + DB 102,15,113,209,8 ; psrlw $0x8,%xmm1 + DB 102,15,235,200 ; por %xmm0,%xmm1 + DB 102,15,56,51,193 ; pmovzxwd %xmm1,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 102,15,111,203 ; movdqa %xmm3,%xmm1 + DB 102,15,113,241,8 ; psllw $0x8,%xmm1 + DB 102,15,113,211,8 ; psrlw $0x8,%xmm3 + DB 102,15,235,217 ; por %xmm1,%xmm3 + DB 102,15,56,51,203 ; pmovzxwd %xmm3,%xmm1 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 102,68,15,111,202 ; movdqa %xmm2,%xmm9 + DB 102,65,15,113,241,8 ; psllw $0x8,%xmm9 + DB 102,15,112,218,78 ; pshufd $0x4e,%xmm2,%xmm3 + DB 102,15,113,210,8 ; psrlw $0x8,%xmm2 + DB 102,65,15,235,209 ; por %xmm9,%xmm2 + DB 102,15,56,51,210 ; pmovzxwd %xmm2,%xmm2 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,68,15,111,203 ; movdqa %xmm3,%xmm9 + DB 102,65,15,113,241,8 ; psllw $0x8,%xmm9 + DB 102,15,113,211,8 ; psrlw $0x8,%xmm3 + DB 102,65,15,235,217 ; por %xmm9,%xmm3 + DB 102,15,56,51,219 ; pmovzxwd %xmm3,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_u16_be_sse41 +_sk_store_u16_be_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,255,127,71 ; mov $0x477fff00,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 102,69,15,91,192 ; cvtps2dq %xmm8,%xmm8 + DB 102,69,15,56,43,192 ; packusdw %xmm8,%xmm8 + DB 102,69,15,111,208 ; movdqa %xmm8,%xmm10 + DB 102,65,15,113,242,8 ; psllw $0x8,%xmm10 + DB 102,65,15,113,208,8 ; psrlw $0x8,%xmm8 + DB 102,69,15,235,194 ; por %xmm10,%xmm8 + DB 69,15,40,209 ; movaps %xmm9,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 102,69,15,91,210 ; cvtps2dq %xmm10,%xmm10 + DB 102,69,15,56,43,210 ; packusdw %xmm10,%xmm10 + DB 102,69,15,111,218 ; movdqa %xmm10,%xmm11 + DB 102,65,15,113,243,8 ; psllw $0x8,%xmm11 + DB 102,65,15,113,210,8 ; psrlw $0x8,%xmm10 + DB 102,69,15,235,211 ; por %xmm11,%xmm10 + DB 69,15,40,217 ; movaps %xmm9,%xmm11 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 102,69,15,91,219 ; cvtps2dq %xmm11,%xmm11 + DB 102,69,15,56,43,219 ; packusdw %xmm11,%xmm11 + DB 102,69,15,111,227 ; movdqa %xmm11,%xmm12 + DB 102,65,15,113,244,8 ; psllw $0x8,%xmm12 + DB 102,65,15,113,211,8 ; psrlw $0x8,%xmm11 + DB 102,69,15,235,220 ; por %xmm12,%xmm11 + DB 68,15,89,203 ; mulps %xmm3,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 102,69,15,56,43,201 ; packusdw %xmm9,%xmm9 + DB 102,69,15,111,225 ; movdqa %xmm9,%xmm12 + DB 102,65,15,113,244,8 ; psllw $0x8,%xmm12 + DB 102,65,15,113,209,8 ; psrlw $0x8,%xmm9 + DB 102,69,15,235,204 ; por %xmm12,%xmm9 + DB 102,69,15,97,194 ; punpcklwd %xmm10,%xmm8 + DB 102,69,15,97,217 ; punpcklwd %xmm9,%xmm11 + DB 102,69,15,111,200 ; movdqa %xmm8,%xmm9 + DB 102,69,15,98,203 ; punpckldq %xmm11,%xmm9 + DB 243,68,15,127,12,248 ; movdqu %xmm9,(%rax,%rdi,8) + DB 102,69,15,106,195 ; punpckhdq %xmm11,%xmm8 + DB 243,68,15,127,68,248,16 ; movdqu %xmm8,0x10(%rax,%rdi,8) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_f32_sse41 +_sk_load_f32_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,137,249 ; mov %rdi,%rcx + DB 72,193,225,4 ; shl $0x4,%rcx + DB 68,15,16,4,8 ; movups (%rax,%rcx,1),%xmm8 + DB 15,16,68,8,16 ; movups 0x10(%rax,%rcx,1),%xmm0 + DB 15,16,92,8,32 ; movups 0x20(%rax,%rcx,1),%xmm3 + DB 68,15,16,76,8,48 ; movups 0x30(%rax,%rcx,1),%xmm9 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 15,20,208 ; unpcklps %xmm0,%xmm2 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 65,15,20,201 ; unpcklps %xmm9,%xmm1 + DB 68,15,21,192 ; unpckhps %xmm0,%xmm8 + DB 65,15,21,217 ; unpckhps %xmm9,%xmm3 + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 102,15,20,193 ; unpcklpd %xmm1,%xmm0 + DB 15,18,202 ; movhlps %xmm2,%xmm1 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 102,15,20,211 ; unpcklpd %xmm3,%xmm2 + DB 65,15,18,216 ; movhlps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_f32_sse41 +_sk_store_f32_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,137,249 ; mov %rdi,%rcx + DB 72,193,225,4 ; shl $0x4,%rcx + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 68,15,20,201 ; unpcklps %xmm1,%xmm9 + DB 68,15,40,210 ; movaps %xmm2,%xmm10 + DB 68,15,40,218 ; movaps %xmm2,%xmm11 + DB 68,15,20,219 ; unpcklps %xmm3,%xmm11 + DB 68,15,21,193 ; unpckhps %xmm1,%xmm8 + DB 68,15,21,211 ; unpckhps %xmm3,%xmm10 + DB 69,15,40,225 ; movaps %xmm9,%xmm12 + DB 102,69,15,20,227 ; unpcklpd %xmm11,%xmm12 + DB 69,15,18,217 ; movhlps %xmm9,%xmm11 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 102,69,15,20,202 ; unpcklpd %xmm10,%xmm9 + DB 69,15,18,208 ; movhlps %xmm8,%xmm10 + DB 102,68,15,17,36,8 ; movupd %xmm12,(%rax,%rcx,1) + DB 68,15,17,92,8,16 ; movups %xmm11,0x10(%rax,%rcx,1) + DB 102,68,15,17,76,8,32 ; movupd %xmm9,0x20(%rax,%rcx,1) + DB 68,15,17,84,8,48 ; movups %xmm10,0x30(%rax,%rcx,1) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_x_sse41 +_sk_clamp_x_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 68,15,95,192 ; maxps %xmm0,%xmm8 + DB 243,68,15,16,8 ; movss (%rax),%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 102,15,118,192 ; pcmpeqd %xmm0,%xmm0 + DB 102,65,15,254,193 ; paddd %xmm9,%xmm0 + DB 68,15,93,192 ; minps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_y_sse41 +_sk_clamp_y_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 68,15,95,193 ; maxps %xmm1,%xmm8 + DB 243,68,15,16,8 ; movss (%rax),%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 102,15,118,201 ; pcmpeqd %xmm1,%xmm1 + DB 102,65,15,254,201 ; paddd %xmm9,%xmm1 + DB 68,15,93,193 ; minps %xmm1,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_repeat_x_sse41 +_sk_repeat_x_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,0 ; movss (%rax),%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 69,15,94,200 ; divps %xmm8,%xmm9 + DB 102,69,15,58,8,201,1 ; roundps $0x1,%xmm9,%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 65,15,92,193 ; subps %xmm9,%xmm0 + DB 102,69,15,118,201 ; pcmpeqd %xmm9,%xmm9 + DB 102,69,15,254,200 ; paddd %xmm8,%xmm9 + DB 65,15,93,193 ; minps %xmm9,%xmm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_repeat_y_sse41 +_sk_repeat_y_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,0 ; movss (%rax),%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 69,15,94,200 ; divps %xmm8,%xmm9 + DB 102,69,15,58,8,201,1 ; roundps $0x1,%xmm9,%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 65,15,92,201 ; subps %xmm9,%xmm1 + DB 102,69,15,118,201 ; pcmpeqd %xmm9,%xmm9 + DB 102,69,15,254,200 ; paddd %xmm8,%xmm9 + DB 65,15,93,201 ; minps %xmm9,%xmm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_mirror_x_sse41 +_sk_mirror_x_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,0 ; movss (%rax),%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 65,15,92,193 ; subps %xmm9,%xmm0 + DB 243,69,15,88,192 ; addss %xmm8,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,40,208 ; movaps %xmm0,%xmm10 + DB 69,15,94,208 ; divps %xmm8,%xmm10 + DB 102,69,15,58,8,210,1 ; roundps $0x1,%xmm10,%xmm10 + DB 69,15,89,208 ; mulps %xmm8,%xmm10 + DB 65,15,92,194 ; subps %xmm10,%xmm0 + DB 65,15,92,193 ; subps %xmm9,%xmm0 + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 68,15,92,192 ; subps %xmm0,%xmm8 + DB 65,15,84,192 ; andps %xmm8,%xmm0 + DB 102,69,15,118,192 ; pcmpeqd %xmm8,%xmm8 + DB 102,69,15,254,193 ; paddd %xmm9,%xmm8 + DB 65,15,93,192 ; minps %xmm8,%xmm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_mirror_y_sse41 +_sk_mirror_y_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,0 ; movss (%rax),%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 65,15,92,201 ; subps %xmm9,%xmm1 + DB 243,69,15,88,192 ; addss %xmm8,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,40,209 ; movaps %xmm1,%xmm10 + DB 69,15,94,208 ; divps %xmm8,%xmm10 + DB 102,69,15,58,8,210,1 ; roundps $0x1,%xmm10,%xmm10 + DB 69,15,89,208 ; mulps %xmm8,%xmm10 + DB 65,15,92,202 ; subps %xmm10,%xmm1 + DB 65,15,92,201 ; subps %xmm9,%xmm1 + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 68,15,92,193 ; subps %xmm1,%xmm8 + DB 65,15,84,200 ; andps %xmm8,%xmm1 + DB 102,69,15,118,192 ; pcmpeqd %xmm8,%xmm8 + DB 102,69,15,254,193 ; paddd %xmm9,%xmm8 + DB 65,15,93,200 ; minps %xmm8,%xmm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_luminance_to_alpha_sse41 +_sk_luminance_to_alpha_sse41 LABEL PROC + DB 184,208,179,89,62 ; mov $0x3e59b3d0,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 15,89,216 ; mulps %xmm0,%xmm3 + DB 184,89,23,55,63 ; mov $0x3f371759,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 15,88,195 ; addps %xmm3,%xmm0 + DB 184,152,221,147,61 ; mov $0x3d93dd98,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 15,89,218 ; mulps %xmm2,%xmm3 + DB 15,88,216 ; addps %xmm0,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,87,192 ; xorps %xmm0,%xmm0 + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_2x3_sse41 +_sk_matrix_2x3_sse41 LABEL PROC + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 243,68,15,16,80,8 ; movss 0x8(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,16 ; movss 0x10(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,88,194 ; addps %xmm10,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,68,15,16,80,12 ; movss 0xc(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,20 ; movss 0x14(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,88,202 ; addps %xmm10,%xmm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_3x4_sse41 +_sk_matrix_3x4_sse41 LABEL PROC + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 243,68,15,16,80,12 ; movss 0xc(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,24 ; movss 0x18(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,36 ; movss 0x24(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,88,194 ; addps %xmm10,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,68,15,16,80,16 ; movss 0x10(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,28 ; movss 0x1c(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,40 ; movss 0x28(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,88,202 ; addps %xmm10,%xmm1 + DB 243,68,15,16,80,8 ; movss 0x8(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,20 ; movss 0x14(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,32 ; movss 0x20(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,44 ; movss 0x2c(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 68,15,89,226 ; mulps %xmm2,%xmm12 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 69,15,89,217 ; mulps %xmm9,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,208 ; mulps %xmm8,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_4x5_sse41 +_sk_matrix_4x5_sse41 LABEL PROC + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 243,68,15,16,80,16 ; movss 0x10(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,32 ; movss 0x20(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,48 ; movss 0x30(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,64 ; movss 0x40(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 68,15,89,227 ; mulps %xmm3,%xmm12 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,88,194 ; addps %xmm10,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,68,15,16,80,20 ; movss 0x14(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,36 ; movss 0x24(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,52 ; movss 0x34(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,68 ; movss 0x44(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 68,15,89,227 ; mulps %xmm3,%xmm12 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,88,202 ; addps %xmm10,%xmm1 + DB 243,68,15,16,80,8 ; movss 0x8(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,24 ; movss 0x18(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,40 ; movss 0x28(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,56 ; movss 0x38(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 243,68,15,16,112,72 ; movss 0x48(%rax),%xmm14 + DB 69,15,198,246,0 ; shufps $0x0,%xmm14,%xmm14 + DB 68,15,89,235 ; mulps %xmm3,%xmm13 + DB 69,15,88,238 ; addps %xmm14,%xmm13 + DB 68,15,89,226 ; mulps %xmm2,%xmm12 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 69,15,89,217 ; mulps %xmm9,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,208 ; mulps %xmm8,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 243,68,15,16,88,12 ; movss 0xc(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,28 ; movss 0x1c(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,44 ; movss 0x2c(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 243,68,15,16,112,60 ; movss 0x3c(%rax),%xmm14 + DB 69,15,198,246,0 ; shufps $0x0,%xmm14,%xmm14 + DB 243,68,15,16,120,76 ; movss 0x4c(%rax),%xmm15 + DB 69,15,198,255,0 ; shufps $0x0,%xmm15,%xmm15 + DB 68,15,89,243 ; mulps %xmm3,%xmm14 + DB 69,15,88,247 ; addps %xmm15,%xmm14 + DB 68,15,89,234 ; mulps %xmm2,%xmm13 + DB 69,15,88,238 ; addps %xmm14,%xmm13 + DB 69,15,89,225 ; mulps %xmm9,%xmm12 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 69,15,89,216 ; mulps %xmm8,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 65,15,40,219 ; movaps %xmm11,%xmm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_perspective_sse41 +_sk_matrix_perspective_sse41 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,68,15,16,72,4 ; movss 0x4(%rax),%xmm9 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 243,68,15,16,80,8 ; movss 0x8(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 68,15,89,201 ; mulps %xmm1,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,88,193 ; addps %xmm9,%xmm0 + DB 243,68,15,16,72,12 ; movss 0xc(%rax),%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 243,68,15,16,80,16 ; movss 0x10(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,20 ; movss 0x14(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 243,68,15,16,80,24 ; movss 0x18(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,28 ; movss 0x1c(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,32 ; movss 0x20(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 68,15,89,217 ; mulps %xmm1,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,208 ; mulps %xmm8,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,83,202 ; rcpps %xmm10,%xmm1 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 68,15,89,201 ; mulps %xmm1,%xmm9 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,201 ; movaps %xmm9,%xmm1 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_linear_gradient_sse41 +_sk_linear_gradient_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,80,16 ; movss 0x10(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,20 ; movss 0x14(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,24 ; movss 0x18(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,28 ; movss 0x1c(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 72,139,8 ; mov (%rax),%rcx + DB 72,133,201 ; test %rcx,%rcx + DB 15,132,4,1,0,0 ; je 2e51 <_sk_linear_gradient_sse41+0x13e> + DB 72,131,236,88 ; sub $0x58,%rsp + DB 15,41,36,36 ; movaps %xmm4,(%rsp) + DB 15,41,108,36,16 ; movaps %xmm5,0x10(%rsp) + DB 15,41,116,36,32 ; movaps %xmm6,0x20(%rsp) + DB 15,41,124,36,48 ; movaps %xmm7,0x30(%rsp) + DB 72,139,64,8 ; mov 0x8(%rax),%rax + DB 72,131,192,32 ; add $0x20,%rax + DB 69,15,87,201 ; xorps %xmm9,%xmm9 + DB 15,87,219 ; xorps %xmm3,%xmm3 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 15,40,233 ; movaps %xmm1,%xmm5 + DB 15,40,242 ; movaps %xmm2,%xmm6 + DB 15,40,251 ; movaps %xmm3,%xmm7 + DB 69,15,40,194 ; movaps %xmm10,%xmm8 + DB 69,15,40,243 ; movaps %xmm11,%xmm14 + DB 69,15,40,252 ; movaps %xmm12,%xmm15 + DB 68,15,41,108,36,64 ; movaps %xmm13,0x40(%rsp) + DB 65,15,40,201 ; movaps %xmm9,%xmm1 + DB 243,15,16,80,224 ; movss -0x20(%rax),%xmm2 + DB 243,68,15,16,72,228 ; movss -0x1c(%rax),%xmm9 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,40,224 ; movaps %xmm0,%xmm4 + DB 15,194,194,1 ; cmpltps %xmm2,%xmm0 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 102,68,15,56,20,201 ; blendvps %xmm0,%xmm1,%xmm9 + DB 243,15,16,72,232 ; movss -0x18(%rax),%xmm1 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 102,15,56,20,205 ; blendvps %xmm0,%xmm5,%xmm1 + DB 243,15,16,80,236 ; movss -0x14(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 102,15,56,20,214 ; blendvps %xmm0,%xmm6,%xmm2 + DB 243,15,16,88,240 ; movss -0x10(%rax),%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 102,15,56,20,223 ; blendvps %xmm0,%xmm7,%xmm3 + DB 243,68,15,16,80,244 ; movss -0xc(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 102,69,15,56,20,208 ; blendvps %xmm0,%xmm8,%xmm10 + DB 243,68,15,16,88,248 ; movss -0x8(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 102,69,15,56,20,222 ; blendvps %xmm0,%xmm14,%xmm11 + DB 243,68,15,16,96,252 ; movss -0x4(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 102,69,15,56,20,231 ; blendvps %xmm0,%xmm15,%xmm12 + DB 243,68,15,16,40 ; movss (%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 102,68,15,56,20,108,36,64 ; blendvps %xmm0,0x40(%rsp),%xmm13 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 72,131,192,36 ; add $0x24,%rax + DB 72,255,201 ; dec %rcx + DB 15,133,65,255,255,255 ; jne 2d79 <_sk_linear_gradient_sse41+0x66> + DB 15,40,124,36,48 ; movaps 0x30(%rsp),%xmm7 + DB 15,40,116,36,32 ; movaps 0x20(%rsp),%xmm6 + DB 15,40,108,36,16 ; movaps 0x10(%rsp),%xmm5 + DB 15,40,36,36 ; movaps (%rsp),%xmm4 + DB 72,131,196,88 ; add $0x58,%rsp + DB 235,13 ; jmp 2e5e <_sk_linear_gradient_sse41+0x14b> + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 15,87,219 ; xorps %xmm3,%xmm3 + DB 69,15,87,201 ; xorps %xmm9,%xmm9 + DB 68,15,89,200 ; mulps %xmm0,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 15,89,200 ; mulps %xmm0,%xmm1 + DB 65,15,88,203 ; addps %xmm11,%xmm1 + DB 15,89,208 ; mulps %xmm0,%xmm2 + DB 65,15,88,212 ; addps %xmm12,%xmm2 + DB 15,89,216 ; mulps %xmm0,%xmm3 + DB 65,15,88,221 ; addps %xmm13,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_linear_gradient_2stops_sse41 +_sk_linear_gradient_2stops_sse41 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 243,15,16,80,16 ; movss 0x10(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,88,194 ; addps %xmm2,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,15,16,80,20 ; movss 0x14(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,88,202 ; addps %xmm2,%xmm1 + DB 243,15,16,80,8 ; movss 0x8(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 243,15,16,88,24 ; movss 0x18(%rax),%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 15,88,211 ; addps %xmm3,%xmm2 + DB 243,15,16,88,12 ; movss 0xc(%rax),%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 243,68,15,16,72,28 ; movss 0x1c(%rax),%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 65,15,88,217 ; addps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_save_xy_sse41 +_sk_save_xy_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,88,200 ; addps %xmm0,%xmm9 + DB 102,69,15,58,8,209,1 ; roundps $0x1,%xmm9,%xmm10 + DB 69,15,92,202 ; subps %xmm10,%xmm9 + DB 68,15,88,193 ; addps %xmm1,%xmm8 + DB 102,69,15,58,8,208,1 ; roundps $0x1,%xmm8,%xmm10 + DB 69,15,92,194 ; subps %xmm10,%xmm8 + DB 15,17,0 ; movups %xmm0,(%rax) + DB 15,17,72,32 ; movups %xmm1,0x20(%rax) + DB 68,15,17,72,64 ; movups %xmm9,0x40(%rax) + DB 68,15,17,64,96 ; movups %xmm8,0x60(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_accumulate_sse41 +_sk_accumulate_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 68,15,16,128,128,0,0,0 ; movups 0x80(%rax),%xmm8 + DB 68,15,16,136,160,0,0,0 ; movups 0xa0(%rax),%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 65,15,88,224 ; addps %xmm8,%xmm4 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 68,15,89,193 ; mulps %xmm1,%xmm8 + DB 65,15,88,232 ; addps %xmm8,%xmm5 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 68,15,89,194 ; mulps %xmm2,%xmm8 + DB 65,15,88,240 ; addps %xmm8,%xmm6 + DB 68,15,89,203 ; mulps %xmm3,%xmm9 + DB 65,15,88,249 ; addps %xmm9,%xmm7 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_nx_sse41 +_sk_bilinear_nx_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,191 ; mov $0xbf000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 68,15,17,128,128,0,0,0 ; movups %xmm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_px_sse41 +_sk_bilinear_px_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 68,15,17,136,128,0,0,0 ; movups %xmm9,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_ny_sse41 +_sk_bilinear_ny_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,191 ; mov $0xbf000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 68,15,17,128,160,0,0,0 ; movups %xmm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_py_sse41 +_sk_bilinear_py_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 68,15,17,136,160,0,0,0 ; movups %xmm9,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n3x_sse41 +_sk_bicubic_n3x_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,192,191 ; mov $0xbfc00000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 185,114,28,199,62 ; mov $0x3ec71c72,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 185,171,170,170,190 ; mov $0xbeaaaaab,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,89,192 ; mulps %xmm8,%xmm8 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 68,15,17,136,128,0,0,0 ; movups %xmm9,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n1x_sse41 +_sk_bicubic_n1x_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,191 ; mov $0xbf000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 185,85,85,149,191 ; mov $0xbf955555,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 185,57,142,99,61 ; mov $0x3d638e39,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 68,15,17,136,128,0,0,0 ; movups %xmm9,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p1x_sse41 +_sk_bicubic_p1x_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 185,85,85,149,191 ; mov $0xbf955555,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,217 ; movd %ecx,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,208 ; addps %xmm8,%xmm10 + DB 185,57,142,99,61 ; mov $0x3d638e39,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,208 ; addps %xmm8,%xmm10 + DB 68,15,17,144,128,0,0,0 ; movups %xmm10,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p3x_sse41 +_sk_bicubic_p3x_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 185,114,28,199,62 ; mov $0x3ec71c72,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,89,193 ; mulps %xmm9,%xmm8 + DB 69,15,89,201 ; mulps %xmm9,%xmm9 + DB 185,171,170,170,190 ; mov $0xbeaaaaab,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,88,194 ; addps %xmm10,%xmm8 + DB 69,15,89,193 ; mulps %xmm9,%xmm8 + DB 68,15,17,128,128,0,0,0 ; movups %xmm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n3y_sse41 +_sk_bicubic_n3y_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,192,191 ; mov $0xbfc00000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 185,114,28,199,62 ; mov $0x3ec71c72,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 185,171,170,170,190 ; mov $0xbeaaaaab,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,89,192 ; mulps %xmm8,%xmm8 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 68,15,17,136,160,0,0,0 ; movups %xmm9,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n1y_sse41 +_sk_bicubic_n1y_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,191 ; mov $0xbf000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 185,85,85,149,191 ; mov $0xbf955555,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 185,57,142,99,61 ; mov $0x3d638e39,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 68,15,17,136,160,0,0,0 ; movups %xmm9,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p1y_sse41 +_sk_bicubic_p1y_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 185,85,85,149,191 ; mov $0xbf955555,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,217 ; movd %ecx,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,208 ; addps %xmm8,%xmm10 + DB 185,57,142,99,61 ; mov $0x3d638e39,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,208 ; addps %xmm8,%xmm10 + DB 68,15,17,144,160,0,0,0 ; movups %xmm10,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p3y_sse41 +_sk_bicubic_p3y_sse41 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 185,114,28,199,62 ; mov $0x3ec71c72,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,89,193 ; mulps %xmm9,%xmm8 + DB 69,15,89,201 ; mulps %xmm9,%xmm9 + DB 185,171,170,170,190 ; mov $0xbeaaaaab,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,88,194 ; addps %xmm10,%xmm8 + DB 69,15,89,193 ; mulps %xmm9,%xmm8 + DB 68,15,17,128,160,0,0,0 ; movups %xmm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_start_pipeline_sse2 +_sk_start_pipeline_sse2 LABEL PROC + DB 65,87 ; push %r15 + DB 65,86 ; push %r14 + DB 65,85 ; push %r13 + DB 65,84 ; push %r12 + DB 86 ; push %rsi + DB 87 ; push %rdi + DB 83 ; push %rbx + DB 72,129,236,160,0,0,0 ; sub $0xa0,%rsp + DB 68,15,41,188,36,144,0,0,0 ; movaps %xmm15,0x90(%rsp) + DB 68,15,41,180,36,128,0,0,0 ; movaps %xmm14,0x80(%rsp) + DB 68,15,41,108,36,112 ; movaps %xmm13,0x70(%rsp) + DB 68,15,41,100,36,96 ; movaps %xmm12,0x60(%rsp) + DB 68,15,41,92,36,80 ; movaps %xmm11,0x50(%rsp) + DB 68,15,41,84,36,64 ; movaps %xmm10,0x40(%rsp) + DB 68,15,41,76,36,48 ; movaps %xmm9,0x30(%rsp) + DB 68,15,41,68,36,32 ; movaps %xmm8,0x20(%rsp) + DB 15,41,124,36,16 ; movaps %xmm7,0x10(%rsp) + DB 15,41,52,36 ; movaps %xmm6,(%rsp) + DB 77,137,207 ; mov %r9,%r15 + DB 77,137,198 ; mov %r8,%r14 + DB 72,137,203 ; mov %rcx,%rbx + DB 72,137,214 ; mov %rdx,%rsi + DB 72,173 ; lods %ds:(%rsi),%rax + DB 73,137,196 ; mov %rax,%r12 + DB 73,137,245 ; mov %rsi,%r13 + DB 72,141,67,4 ; lea 0x4(%rbx),%rax + DB 76,57,248 ; cmp %r15,%rax + DB 118,5 ; jbe 73 <_sk_start_pipeline_sse2+0x73> + DB 72,137,216 ; mov %rbx,%rax + DB 235,52 ; jmp a7 <_sk_start_pipeline_sse2+0xa7> + DB 15,87,192 ; xorps %xmm0,%xmm0 + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 15,87,219 ; xorps %xmm3,%xmm3 + DB 15,87,228 ; xorps %xmm4,%xmm4 + DB 15,87,237 ; xorps %xmm5,%xmm5 + DB 15,87,246 ; xorps %xmm6,%xmm6 + DB 15,87,255 ; xorps %xmm7,%xmm7 + DB 72,137,223 ; mov %rbx,%rdi + DB 76,137,238 ; mov %r13,%rsi + DB 76,137,242 ; mov %r14,%rdx + DB 65,255,212 ; callq *%r12 + DB 72,141,67,4 ; lea 0x4(%rbx),%rax + DB 72,131,195,8 ; add $0x8,%rbx + DB 76,57,251 ; cmp %r15,%rbx + DB 72,137,195 ; mov %rax,%rbx + DB 118,204 ; jbe 73 <_sk_start_pipeline_sse2+0x73> + DB 15,40,52,36 ; movaps (%rsp),%xmm6 + DB 15,40,124,36,16 ; movaps 0x10(%rsp),%xmm7 + DB 68,15,40,68,36,32 ; movaps 0x20(%rsp),%xmm8 + DB 68,15,40,76,36,48 ; movaps 0x30(%rsp),%xmm9 + DB 68,15,40,84,36,64 ; movaps 0x40(%rsp),%xmm10 + DB 68,15,40,92,36,80 ; movaps 0x50(%rsp),%xmm11 + DB 68,15,40,100,36,96 ; movaps 0x60(%rsp),%xmm12 + DB 68,15,40,108,36,112 ; movaps 0x70(%rsp),%xmm13 + DB 68,15,40,180,36,128,0,0,0 ; movaps 0x80(%rsp),%xmm14 + DB 68,15,40,188,36,144,0,0,0 ; movaps 0x90(%rsp),%xmm15 + DB 72,129,196,160,0,0,0 ; add $0xa0,%rsp + DB 91 ; pop %rbx + DB 95 ; pop %rdi + DB 94 ; pop %rsi + DB 65,92 ; pop %r12 + DB 65,93 ; pop %r13 + DB 65,94 ; pop %r14 + DB 65,95 ; pop %r15 + DB 195 ; retq + +PUBLIC _sk_just_return_sse2 +_sk_just_return_sse2 LABEL PROC + DB 195 ; retq + +PUBLIC _sk_seed_shader_sse2 +_sk_seed_shader_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 102,15,110,199 ; movd %edi,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,15,110,209 ; movd %ecx,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,88,202 ; addps %xmm2,%xmm1 + DB 15,16,2 ; movups (%rdx),%xmm0 + DB 15,88,193 ; addps %xmm1,%xmm0 + DB 102,15,110,8 ; movd (%rax),%xmm1 + DB 102,15,112,201,0 ; pshufd $0x0,%xmm1,%xmm1 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 15,88,202 ; addps %xmm2,%xmm1 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,87,219 ; xorps %xmm3,%xmm3 + DB 15,87,228 ; xorps %xmm4,%xmm4 + DB 15,87,237 ; xorps %xmm5,%xmm5 + DB 15,87,246 ; xorps %xmm6,%xmm6 + DB 15,87,255 ; xorps %xmm7,%xmm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_constant_color_sse2 +_sk_constant_color_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,15,16,80,8 ; movss 0x8(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 243,15,16,88,12 ; movss 0xc(%rax),%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clear_sse2 +_sk_clear_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,87,192 ; xorps %xmm0,%xmm0 + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 15,87,219 ; xorps %xmm3,%xmm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcatop_sse2 +_sk_srcatop_sse2 LABEL PROC + DB 15,89,199 ; mulps %xmm7,%xmm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,92,195 ; subps %xmm3,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,204 ; mulps %xmm4,%xmm9 + DB 65,15,88,193 ; addps %xmm9,%xmm0 + DB 15,89,207 ; mulps %xmm7,%xmm1 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 65,15,88,201 ; addps %xmm9,%xmm1 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 65,15,88,209 ; addps %xmm9,%xmm2 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 65,15,88,216 ; addps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstatop_sse2 +_sk_dstatop_sse2 LABEL PROC + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 68,15,89,196 ; mulps %xmm4,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 68,15,92,207 ; subps %xmm7,%xmm9 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 68,15,89,197 ; mulps %xmm5,%xmm8 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 68,15,89,198 ; mulps %xmm6,%xmm8 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 65,15,88,208 ; addps %xmm8,%xmm2 + DB 68,15,89,203 ; mulps %xmm3,%xmm9 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 65,15,88,217 ; addps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcin_sse2 +_sk_srcin_sse2 LABEL PROC + DB 15,89,199 ; mulps %xmm7,%xmm0 + DB 15,89,207 ; mulps %xmm7,%xmm1 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstin_sse2 +_sk_dstin_sse2 LABEL PROC + DB 15,40,195 ; movaps %xmm3,%xmm0 + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 15,40,211 ; movaps %xmm3,%xmm2 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcout_sse2 +_sk_srcout_sse2 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,92,199 ; subps %xmm7,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstout_sse2 +_sk_dstout_sse2 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,92,195 ; subps %xmm3,%xmm8 + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,216 ; movaps %xmm8,%xmm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_srcover_sse2 +_sk_srcover_sse2 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,92,195 ; subps %xmm3,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,204 ; mulps %xmm4,%xmm9 + DB 65,15,88,193 ; addps %xmm9,%xmm0 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 65,15,88,201 ; addps %xmm9,%xmm1 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 65,15,88,209 ; addps %xmm9,%xmm2 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 65,15,88,216 ; addps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_dstover_sse2 +_sk_dstover_sse2 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,92,199 ; subps %xmm7,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 15,88,223 ; addps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_modulate_sse2 +_sk_modulate_sse2 LABEL PROC + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_multiply_sse2 +_sk_multiply_sse2 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,92,207 ; subps %xmm7,%xmm9 + DB 69,15,40,209 ; movaps %xmm9,%xmm10 + DB 68,15,89,208 ; mulps %xmm0,%xmm10 + DB 68,15,92,195 ; subps %xmm3,%xmm8 + DB 69,15,40,216 ; movaps %xmm8,%xmm11 + DB 68,15,89,220 ; mulps %xmm4,%xmm11 + DB 69,15,88,218 ; addps %xmm10,%xmm11 + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 65,15,88,195 ; addps %xmm11,%xmm0 + DB 69,15,40,209 ; movaps %xmm9,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 69,15,40,216 ; movaps %xmm8,%xmm11 + DB 68,15,89,221 ; mulps %xmm5,%xmm11 + DB 69,15,88,218 ; addps %xmm10,%xmm11 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 65,15,88,203 ; addps %xmm11,%xmm1 + DB 69,15,40,209 ; movaps %xmm9,%xmm10 + DB 68,15,89,210 ; mulps %xmm2,%xmm10 + DB 69,15,40,216 ; movaps %xmm8,%xmm11 + DB 68,15,89,222 ; mulps %xmm6,%xmm11 + DB 69,15,88,218 ; addps %xmm10,%xmm11 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 65,15,88,211 ; addps %xmm11,%xmm2 + DB 68,15,89,203 ; mulps %xmm3,%xmm9 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 69,15,88,193 ; addps %xmm9,%xmm8 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 65,15,88,216 ; addps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_plus__sse2 +_sk_plus__sse2 LABEL PROC + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 15,88,223 ; addps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_screen_sse2 +_sk_screen_sse2 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 68,15,88,196 ; addps %xmm4,%xmm8 + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 68,15,92,192 ; subps %xmm0,%xmm8 + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 68,15,88,205 ; addps %xmm5,%xmm9 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 68,15,92,201 ; subps %xmm1,%xmm9 + DB 68,15,40,210 ; movaps %xmm2,%xmm10 + DB 68,15,88,214 ; addps %xmm6,%xmm10 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 68,15,92,210 ; subps %xmm2,%xmm10 + DB 68,15,40,219 ; movaps %xmm3,%xmm11 + DB 68,15,88,223 ; addps %xmm7,%xmm11 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 68,15,92,219 ; subps %xmm3,%xmm11 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 65,15,40,201 ; movaps %xmm9,%xmm1 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 65,15,40,219 ; movaps %xmm11,%xmm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_xor__sse2 +_sk_xor__sse2 LABEL PROC + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,92,207 ; subps %xmm7,%xmm9 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,92,216 ; subps %xmm8,%xmm3 + DB 68,15,40,211 ; movaps %xmm3,%xmm10 + DB 68,15,89,212 ; mulps %xmm4,%xmm10 + DB 65,15,88,194 ; addps %xmm10,%xmm0 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 68,15,40,211 ; movaps %xmm3,%xmm10 + DB 68,15,89,213 ; mulps %xmm5,%xmm10 + DB 65,15,88,202 ; addps %xmm10,%xmm1 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 68,15,40,211 ; movaps %xmm3,%xmm10 + DB 68,15,89,214 ; mulps %xmm6,%xmm10 + DB 65,15,88,210 ; addps %xmm10,%xmm2 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 15,89,223 ; mulps %xmm7,%xmm3 + DB 65,15,88,217 ; addps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_darken_sse2 +_sk_darken_sse2 LABEL PROC + DB 68,15,40,193 ; movaps %xmm1,%xmm8 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 68,15,89,207 ; mulps %xmm7,%xmm9 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 15,89,204 ; mulps %xmm4,%xmm1 + DB 68,15,95,201 ; maxps %xmm1,%xmm9 + DB 65,15,92,193 ; subps %xmm9,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 69,15,95,193 ; maxps %xmm9,%xmm8 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 68,15,40,194 ; movaps %xmm2,%xmm8 + DB 68,15,88,198 ; addps %xmm6,%xmm8 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 65,15,95,209 ; maxps %xmm9,%xmm2 + DB 68,15,92,194 ; subps %xmm2,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 15,88,218 ; addps %xmm2,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lighten_sse2 +_sk_lighten_sse2 LABEL PROC + DB 68,15,40,193 ; movaps %xmm1,%xmm8 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 68,15,89,207 ; mulps %xmm7,%xmm9 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 15,89,204 ; mulps %xmm4,%xmm1 + DB 68,15,93,201 ; minps %xmm1,%xmm9 + DB 65,15,92,193 ; subps %xmm9,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 69,15,93,193 ; minps %xmm9,%xmm8 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 68,15,40,194 ; movaps %xmm2,%xmm8 + DB 68,15,88,198 ; addps %xmm6,%xmm8 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 65,15,93,209 ; minps %xmm9,%xmm2 + DB 68,15,92,194 ; subps %xmm2,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 15,88,218 ; addps %xmm2,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_difference_sse2 +_sk_difference_sse2 LABEL PROC + DB 68,15,40,193 ; movaps %xmm1,%xmm8 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 68,15,89,207 ; mulps %xmm7,%xmm9 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 15,89,204 ; mulps %xmm4,%xmm1 + DB 68,15,93,201 ; minps %xmm1,%xmm9 + DB 69,15,88,201 ; addps %xmm9,%xmm9 + DB 65,15,92,193 ; subps %xmm9,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 69,15,93,193 ; minps %xmm9,%xmm8 + DB 69,15,88,192 ; addps %xmm8,%xmm8 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 68,15,40,194 ; movaps %xmm2,%xmm8 + DB 68,15,88,198 ; addps %xmm6,%xmm8 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,89,206 ; mulps %xmm6,%xmm9 + DB 65,15,93,209 ; minps %xmm9,%xmm2 + DB 15,88,210 ; addps %xmm2,%xmm2 + DB 68,15,92,194 ; subps %xmm2,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 15,88,218 ; addps %xmm2,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_exclusion_sse2 +_sk_exclusion_sse2 LABEL PROC + DB 68,15,40,193 ; movaps %xmm1,%xmm8 + DB 15,40,200 ; movaps %xmm0,%xmm1 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 15,89,204 ; mulps %xmm4,%xmm1 + DB 15,88,201 ; addps %xmm1,%xmm1 + DB 15,92,193 ; subps %xmm1,%xmm0 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 68,15,89,197 ; mulps %xmm5,%xmm8 + DB 69,15,88,192 ; addps %xmm8,%xmm8 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 68,15,40,194 ; movaps %xmm2,%xmm8 + DB 68,15,88,198 ; addps %xmm6,%xmm8 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 15,88,210 ; addps %xmm2,%xmm2 + DB 68,15,92,194 ; subps %xmm2,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 15,89,215 ; mulps %xmm7,%xmm2 + DB 15,88,218 ; addps %xmm2,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_colorburn_sse2 +_sk_colorburn_sse2 LABEL PROC + DB 68,15,40,193 ; movaps %xmm1,%xmm8 + DB 68,15,40,224 ; movaps %xmm0,%xmm12 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 69,15,40,217 ; movaps %xmm9,%xmm11 + DB 68,15,92,223 ; subps %xmm7,%xmm11 + DB 65,15,40,195 ; movaps %xmm11,%xmm0 + DB 65,15,89,196 ; mulps %xmm12,%xmm0 + DB 69,15,87,210 ; xorps %xmm10,%xmm10 + DB 15,40,207 ; movaps %xmm7,%xmm1 + DB 15,92,204 ; subps %xmm4,%xmm1 + DB 15,89,203 ; mulps %xmm3,%xmm1 + DB 65,15,94,204 ; divps %xmm12,%xmm1 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,93,233 ; minps %xmm1,%xmm13 + DB 68,15,40,247 ; movaps %xmm7,%xmm14 + DB 69,15,92,245 ; subps %xmm13,%xmm14 + DB 65,15,40,204 ; movaps %xmm12,%xmm1 + DB 65,15,194,202,0 ; cmpeqps %xmm10,%xmm1 + DB 68,15,92,203 ; subps %xmm3,%xmm9 + DB 68,15,89,243 ; mulps %xmm3,%xmm14 + DB 68,15,88,240 ; addps %xmm0,%xmm14 + DB 68,15,84,225 ; andps %xmm1,%xmm12 + DB 65,15,85,206 ; andnps %xmm14,%xmm1 + DB 69,15,40,233 ; movaps %xmm9,%xmm13 + DB 68,15,89,236 ; mulps %xmm4,%xmm13 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 65,15,86,204 ; orps %xmm12,%xmm1 + DB 68,15,40,228 ; movaps %xmm4,%xmm12 + DB 68,15,194,231,0 ; cmpeqps %xmm7,%xmm12 + DB 65,15,88,205 ; addps %xmm13,%xmm1 + DB 65,15,84,196 ; andps %xmm12,%xmm0 + DB 68,15,85,225 ; andnps %xmm1,%xmm12 + DB 65,15,86,196 ; orps %xmm12,%xmm0 + DB 65,15,40,203 ; movaps %xmm11,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 68,15,40,231 ; movaps %xmm7,%xmm12 + DB 68,15,92,229 ; subps %xmm5,%xmm12 + DB 68,15,89,227 ; mulps %xmm3,%xmm12 + DB 69,15,94,224 ; divps %xmm8,%xmm12 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 69,15,93,236 ; minps %xmm12,%xmm13 + DB 68,15,40,231 ; movaps %xmm7,%xmm12 + DB 69,15,92,229 ; subps %xmm13,%xmm12 + DB 69,15,40,232 ; movaps %xmm8,%xmm13 + DB 69,15,194,234,0 ; cmpeqps %xmm10,%xmm13 + DB 68,15,89,227 ; mulps %xmm3,%xmm12 + DB 68,15,88,225 ; addps %xmm1,%xmm12 + DB 69,15,84,197 ; andps %xmm13,%xmm8 + DB 69,15,85,236 ; andnps %xmm12,%xmm13 + DB 69,15,86,232 ; orps %xmm8,%xmm13 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 68,15,89,197 ; mulps %xmm5,%xmm8 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 69,15,88,232 ; addps %xmm8,%xmm13 + DB 68,15,40,197 ; movaps %xmm5,%xmm8 + DB 68,15,194,199,0 ; cmpeqps %xmm7,%xmm8 + DB 65,15,84,200 ; andps %xmm8,%xmm1 + DB 69,15,85,197 ; andnps %xmm13,%xmm8 + DB 65,15,86,200 ; orps %xmm8,%xmm1 + DB 68,15,40,199 ; movaps %xmm7,%xmm8 + DB 68,15,92,198 ; subps %xmm6,%xmm8 + DB 68,15,89,195 ; mulps %xmm3,%xmm8 + DB 68,15,94,194 ; divps %xmm2,%xmm8 + DB 68,15,40,231 ; movaps %xmm7,%xmm12 + DB 69,15,93,224 ; minps %xmm8,%xmm12 + DB 68,15,40,199 ; movaps %xmm7,%xmm8 + DB 69,15,92,196 ; subps %xmm12,%xmm8 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 68,15,194,210,0 ; cmpeqps %xmm2,%xmm10 + DB 68,15,89,195 ; mulps %xmm3,%xmm8 + DB 69,15,88,195 ; addps %xmm11,%xmm8 + DB 65,15,84,210 ; andps %xmm10,%xmm2 + DB 69,15,85,208 ; andnps %xmm8,%xmm10 + DB 69,15,40,195 ; movaps %xmm11,%xmm8 + DB 68,15,88,198 ; addps %xmm6,%xmm8 + DB 68,15,86,210 ; orps %xmm2,%xmm10 + DB 65,15,40,209 ; movaps %xmm9,%xmm2 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 68,15,88,210 ; addps %xmm2,%xmm10 + DB 15,40,214 ; movaps %xmm6,%xmm2 + DB 15,194,215,0 ; cmpeqps %xmm7,%xmm2 + DB 68,15,84,194 ; andps %xmm2,%xmm8 + DB 65,15,85,210 ; andnps %xmm10,%xmm2 + DB 68,15,86,194 ; orps %xmm2,%xmm8 + DB 68,15,89,207 ; mulps %xmm7,%xmm9 + DB 65,15,88,217 ; addps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_colordodge_sse2 +_sk_colordodge_sse2 LABEL PROC + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,40,218 ; movaps %xmm10,%xmm11 + DB 68,15,92,223 ; subps %xmm7,%xmm11 + DB 65,15,40,195 ; movaps %xmm11,%xmm0 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 68,15,89,196 ; mulps %xmm4,%xmm8 + DB 68,15,40,227 ; movaps %xmm3,%xmm12 + DB 69,15,92,225 ; subps %xmm9,%xmm12 + DB 69,15,94,196 ; divps %xmm12,%xmm8 + DB 68,15,40,231 ; movaps %xmm7,%xmm12 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 69,15,93,232 ; minps %xmm8,%xmm13 + DB 69,15,40,241 ; movaps %xmm9,%xmm14 + DB 68,15,194,243,0 ; cmpeqps %xmm3,%xmm14 + DB 68,15,89,235 ; mulps %xmm3,%xmm13 + DB 68,15,88,232 ; addps %xmm0,%xmm13 + DB 69,15,84,206 ; andps %xmm14,%xmm9 + DB 69,15,85,245 ; andnps %xmm13,%xmm14 + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 68,15,92,211 ; subps %xmm3,%xmm10 + DB 69,15,86,241 ; orps %xmm9,%xmm14 + DB 69,15,40,202 ; movaps %xmm10,%xmm9 + DB 68,15,89,204 ; mulps %xmm4,%xmm9 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 69,15,88,241 ; addps %xmm9,%xmm14 + DB 68,15,40,204 ; movaps %xmm4,%xmm9 + DB 69,15,194,200,0 ; cmpeqps %xmm8,%xmm9 + DB 65,15,84,193 ; andps %xmm9,%xmm0 + DB 69,15,85,206 ; andnps %xmm14,%xmm9 + DB 65,15,86,193 ; orps %xmm9,%xmm0 + DB 68,15,40,235 ; movaps %xmm3,%xmm13 + DB 68,15,89,237 ; mulps %xmm5,%xmm13 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,92,201 ; subps %xmm1,%xmm9 + DB 69,15,94,233 ; divps %xmm9,%xmm13 + DB 69,15,40,203 ; movaps %xmm11,%xmm9 + DB 68,15,89,201 ; mulps %xmm1,%xmm9 + DB 69,15,93,229 ; minps %xmm13,%xmm12 + DB 68,15,40,233 ; movaps %xmm1,%xmm13 + DB 68,15,194,235,0 ; cmpeqps %xmm3,%xmm13 + DB 68,15,89,227 ; mulps %xmm3,%xmm12 + DB 69,15,88,225 ; addps %xmm9,%xmm12 + DB 65,15,84,205 ; andps %xmm13,%xmm1 + DB 69,15,85,236 ; andnps %xmm12,%xmm13 + DB 68,15,86,233 ; orps %xmm1,%xmm13 + DB 65,15,40,202 ; movaps %xmm10,%xmm1 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 68,15,88,205 ; addps %xmm5,%xmm9 + DB 68,15,88,233 ; addps %xmm1,%xmm13 + DB 15,40,205 ; movaps %xmm5,%xmm1 + DB 65,15,194,200,0 ; cmpeqps %xmm8,%xmm1 + DB 68,15,84,201 ; andps %xmm1,%xmm9 + DB 65,15,85,205 ; andnps %xmm13,%xmm1 + DB 68,15,86,201 ; orps %xmm1,%xmm9 + DB 68,15,40,227 ; movaps %xmm3,%xmm12 + DB 68,15,89,230 ; mulps %xmm6,%xmm12 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 15,92,202 ; subps %xmm2,%xmm1 + DB 68,15,94,225 ; divps %xmm1,%xmm12 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,93,236 ; minps %xmm12,%xmm13 + DB 15,40,202 ; movaps %xmm2,%xmm1 + DB 15,194,203,0 ; cmpeqps %xmm3,%xmm1 + DB 68,15,89,235 ; mulps %xmm3,%xmm13 + DB 69,15,88,235 ; addps %xmm11,%xmm13 + DB 15,84,209 ; andps %xmm1,%xmm2 + DB 65,15,85,205 ; andnps %xmm13,%xmm1 + DB 15,86,202 ; orps %xmm2,%xmm1 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 15,88,202 ; addps %xmm2,%xmm1 + DB 68,15,194,198,0 ; cmpeqps %xmm6,%xmm8 + DB 68,15,88,222 ; addps %xmm6,%xmm11 + DB 69,15,84,216 ; andps %xmm8,%xmm11 + DB 68,15,85,193 ; andnps %xmm1,%xmm8 + DB 69,15,86,195 ; orps %xmm11,%xmm8 + DB 68,15,89,215 ; mulps %xmm7,%xmm10 + DB 65,15,88,218 ; addps %xmm10,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,201 ; movaps %xmm9,%xmm1 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_hardlight_sse2 +_sk_hardlight_sse2 LABEL PROC + DB 72,131,236,24 ; sub $0x18,%rsp + DB 15,41,52,36 ; movaps %xmm6,(%rsp) + DB 15,40,245 ; movaps %xmm5,%xmm6 + DB 15,40,236 ; movaps %xmm4,%xmm5 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,216 ; movd %eax,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,40,211 ; movaps %xmm11,%xmm10 + DB 68,15,92,215 ; subps %xmm7,%xmm10 + DB 69,15,40,194 ; movaps %xmm10,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 68,15,92,219 ; subps %xmm3,%xmm11 + DB 69,15,40,203 ; movaps %xmm11,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 69,15,88,200 ; addps %xmm8,%xmm9 + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 68,15,92,192 ; subps %xmm0,%xmm8 + DB 15,40,227 ; movaps %xmm3,%xmm4 + DB 15,89,231 ; mulps %xmm7,%xmm4 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,40,247 ; movaps %xmm7,%xmm14 + DB 68,15,40,255 ; movaps %xmm7,%xmm15 + DB 68,15,92,253 ; subps %xmm5,%xmm15 + DB 69,15,89,248 ; mulps %xmm8,%xmm15 + DB 69,15,88,255 ; addps %xmm15,%xmm15 + DB 68,15,40,228 ; movaps %xmm4,%xmm12 + DB 69,15,92,231 ; subps %xmm15,%xmm12 + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 69,15,88,192 ; addps %xmm8,%xmm8 + DB 68,15,194,195,2 ; cmpleps %xmm3,%xmm8 + DB 15,89,197 ; mulps %xmm5,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 65,15,84,192 ; andps %xmm8,%xmm0 + DB 69,15,85,196 ; andnps %xmm12,%xmm8 + DB 68,15,86,192 ; orps %xmm0,%xmm8 + DB 69,15,40,251 ; movaps %xmm11,%xmm15 + DB 69,15,40,227 ; movaps %xmm11,%xmm12 + DB 68,15,89,223 ; mulps %xmm7,%xmm11 + DB 69,15,88,193 ; addps %xmm9,%xmm8 + DB 65,15,40,194 ; movaps %xmm10,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 68,15,89,254 ; mulps %xmm6,%xmm15 + DB 68,15,88,248 ; addps %xmm0,%xmm15 + DB 15,40,195 ; movaps %xmm3,%xmm0 + DB 15,92,193 ; subps %xmm1,%xmm0 + DB 68,15,92,238 ; subps %xmm6,%xmm13 + DB 68,15,89,232 ; mulps %xmm0,%xmm13 + DB 69,15,88,237 ; addps %xmm13,%xmm13 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 65,15,92,197 ; subps %xmm13,%xmm0 + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 69,15,88,201 ; addps %xmm9,%xmm9 + DB 68,15,194,203,2 ; cmpleps %xmm3,%xmm9 + DB 15,89,206 ; mulps %xmm6,%xmm1 + DB 15,88,201 ; addps %xmm1,%xmm1 + DB 65,15,84,201 ; andps %xmm9,%xmm1 + DB 68,15,85,200 ; andnps %xmm0,%xmm9 + DB 68,15,86,201 ; orps %xmm1,%xmm9 + DB 69,15,88,207 ; addps %xmm15,%xmm9 + DB 68,15,89,210 ; mulps %xmm2,%xmm10 + DB 68,15,40,44,36 ; movaps (%rsp),%xmm13 + DB 69,15,89,229 ; mulps %xmm13,%xmm12 + DB 69,15,88,226 ; addps %xmm10,%xmm12 + DB 68,15,40,210 ; movaps %xmm2,%xmm10 + DB 69,15,88,210 ; addps %xmm10,%xmm10 + DB 68,15,194,211,2 ; cmpleps %xmm3,%xmm10 + DB 15,40,195 ; movaps %xmm3,%xmm0 + DB 15,92,194 ; subps %xmm2,%xmm0 + DB 65,15,89,213 ; mulps %xmm13,%xmm2 + DB 15,88,210 ; addps %xmm2,%xmm2 + DB 69,15,92,245 ; subps %xmm13,%xmm14 + DB 68,15,89,240 ; mulps %xmm0,%xmm14 + DB 69,15,88,246 ; addps %xmm14,%xmm14 + DB 65,15,92,230 ; subps %xmm14,%xmm4 + DB 65,15,84,210 ; andps %xmm10,%xmm2 + DB 68,15,85,212 ; andnps %xmm4,%xmm10 + DB 68,15,86,210 ; orps %xmm2,%xmm10 + DB 69,15,88,212 ; addps %xmm12,%xmm10 + DB 65,15,88,219 ; addps %xmm11,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 65,15,40,201 ; movaps %xmm9,%xmm1 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 15,40,229 ; movaps %xmm5,%xmm4 + DB 15,40,238 ; movaps %xmm6,%xmm5 + DB 65,15,40,245 ; movaps %xmm13,%xmm6 + DB 72,131,196,24 ; add $0x18,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_overlay_sse2 +_sk_overlay_sse2 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,92,207 ; subps %xmm7,%xmm9 + DB 69,15,40,209 ; movaps %xmm9,%xmm10 + DB 68,15,89,208 ; mulps %xmm0,%xmm10 + DB 68,15,92,195 ; subps %xmm3,%xmm8 + DB 69,15,40,216 ; movaps %xmm8,%xmm11 + DB 68,15,89,220 ; mulps %xmm4,%xmm11 + DB 69,15,88,218 ; addps %xmm10,%xmm11 + DB 68,15,40,227 ; movaps %xmm3,%xmm12 + DB 68,15,92,224 ; subps %xmm0,%xmm12 + DB 15,89,196 ; mulps %xmm4,%xmm0 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,92,236 ; subps %xmm4,%xmm13 + DB 68,15,40,244 ; movaps %xmm4,%xmm14 + DB 69,15,88,246 ; addps %xmm14,%xmm14 + DB 68,15,194,247,2 ; cmpleps %xmm7,%xmm14 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 68,15,40,211 ; movaps %xmm3,%xmm10 + DB 68,15,89,215 ; mulps %xmm7,%xmm10 + DB 69,15,89,236 ; mulps %xmm12,%xmm13 + DB 69,15,88,237 ; addps %xmm13,%xmm13 + DB 69,15,40,226 ; movaps %xmm10,%xmm12 + DB 69,15,92,229 ; subps %xmm13,%xmm12 + DB 65,15,84,198 ; andps %xmm14,%xmm0 + DB 69,15,85,244 ; andnps %xmm12,%xmm14 + DB 65,15,86,198 ; orps %xmm14,%xmm0 + DB 65,15,88,195 ; addps %xmm11,%xmm0 + DB 69,15,40,217 ; movaps %xmm9,%xmm11 + DB 68,15,89,217 ; mulps %xmm1,%xmm11 + DB 69,15,40,224 ; movaps %xmm8,%xmm12 + DB 68,15,89,229 ; mulps %xmm5,%xmm12 + DB 69,15,88,227 ; addps %xmm11,%xmm12 + DB 68,15,40,219 ; movaps %xmm3,%xmm11 + DB 68,15,92,217 ; subps %xmm1,%xmm11 + DB 15,89,205 ; mulps %xmm5,%xmm1 + DB 68,15,40,239 ; movaps %xmm7,%xmm13 + DB 68,15,92,237 ; subps %xmm5,%xmm13 + DB 68,15,40,245 ; movaps %xmm5,%xmm14 + DB 69,15,88,246 ; addps %xmm14,%xmm14 + DB 68,15,194,247,2 ; cmpleps %xmm7,%xmm14 + DB 15,88,201 ; addps %xmm1,%xmm1 + DB 69,15,89,235 ; mulps %xmm11,%xmm13 + DB 69,15,88,237 ; addps %xmm13,%xmm13 + DB 69,15,40,218 ; movaps %xmm10,%xmm11 + DB 69,15,92,221 ; subps %xmm13,%xmm11 + DB 65,15,84,206 ; andps %xmm14,%xmm1 + DB 69,15,85,243 ; andnps %xmm11,%xmm14 + DB 65,15,86,206 ; orps %xmm14,%xmm1 + DB 65,15,88,204 ; addps %xmm12,%xmm1 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 69,15,40,216 ; movaps %xmm8,%xmm11 + DB 68,15,89,222 ; mulps %xmm6,%xmm11 + DB 69,15,88,217 ; addps %xmm9,%xmm11 + DB 68,15,40,203 ; movaps %xmm3,%xmm9 + DB 68,15,92,202 ; subps %xmm2,%xmm9 + DB 15,89,214 ; mulps %xmm6,%xmm2 + DB 68,15,40,231 ; movaps %xmm7,%xmm12 + DB 68,15,92,230 ; subps %xmm6,%xmm12 + DB 68,15,40,238 ; movaps %xmm6,%xmm13 + DB 69,15,88,237 ; addps %xmm13,%xmm13 + DB 68,15,194,239,2 ; cmpleps %xmm7,%xmm13 + DB 15,88,210 ; addps %xmm2,%xmm2 + DB 69,15,89,225 ; mulps %xmm9,%xmm12 + DB 69,15,88,228 ; addps %xmm12,%xmm12 + DB 69,15,92,212 ; subps %xmm12,%xmm10 + DB 65,15,84,213 ; andps %xmm13,%xmm2 + DB 69,15,85,234 ; andnps %xmm10,%xmm13 + DB 65,15,86,213 ; orps %xmm13,%xmm2 + DB 65,15,88,211 ; addps %xmm11,%xmm2 + DB 68,15,89,199 ; mulps %xmm7,%xmm8 + DB 65,15,88,216 ; addps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_softlight_sse2 +_sk_softlight_sse2 LABEL PROC + DB 72,131,236,56 ; sub $0x38,%rsp + DB 15,41,84,36,32 ; movaps %xmm2,0x20(%rsp) + DB 15,40,209 ; movaps %xmm1,%xmm2 + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 69,15,87,228 ; xorps %xmm12,%xmm12 + DB 68,15,194,231,1 ; cmpltps %xmm7,%xmm12 + DB 68,15,40,212 ; movaps %xmm4,%xmm10 + DB 68,15,94,215 ; divps %xmm7,%xmm10 + DB 69,15,84,212 ; andps %xmm12,%xmm10 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 69,15,40,241 ; movaps %xmm9,%xmm14 + DB 69,15,92,242 ; subps %xmm10,%xmm14 + DB 69,15,40,218 ; movaps %xmm10,%xmm11 + DB 69,15,40,234 ; movaps %xmm10,%xmm13 + DB 65,15,82,194 ; rsqrtps %xmm10,%xmm0 + DB 68,15,83,248 ; rcpps %xmm0,%xmm15 + DB 69,15,92,250 ; subps %xmm10,%xmm15 + DB 69,15,88,210 ; addps %xmm10,%xmm10 + DB 69,15,88,210 ; addps %xmm10,%xmm10 + DB 65,15,40,194 ; movaps %xmm10,%xmm0 + DB 15,89,192 ; mulps %xmm0,%xmm0 + DB 65,15,88,194 ; addps %xmm10,%xmm0 + DB 69,15,92,217 ; subps %xmm9,%xmm11 + DB 68,15,89,216 ; mulps %xmm0,%xmm11 + DB 184,0,0,224,64 ; mov $0x40e00000,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,234 ; mulps %xmm10,%xmm13 + DB 69,15,88,235 ; addps %xmm11,%xmm13 + DB 68,15,40,219 ; movaps %xmm3,%xmm11 + DB 15,40,204 ; movaps %xmm4,%xmm1 + DB 68,15,89,217 ; mulps %xmm1,%xmm11 + DB 15,88,228 ; addps %xmm4,%xmm4 + DB 15,88,228 ; addps %xmm4,%xmm4 + DB 15,194,231,2 ; cmpleps %xmm7,%xmm4 + DB 68,15,84,236 ; andps %xmm4,%xmm13 + DB 65,15,85,231 ; andnps %xmm15,%xmm4 + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 15,88,192 ; addps %xmm0,%xmm0 + DB 65,15,86,229 ; orps %xmm13,%xmm4 + DB 68,15,40,232 ; movaps %xmm0,%xmm13 + DB 68,15,92,235 ; subps %xmm3,%xmm13 + DB 69,15,89,245 ; mulps %xmm13,%xmm14 + DB 68,15,89,239 ; mulps %xmm7,%xmm13 + DB 65,15,89,229 ; mulps %xmm13,%xmm4 + DB 65,15,88,227 ; addps %xmm11,%xmm4 + DB 69,15,40,217 ; movaps %xmm9,%xmm11 + DB 68,15,92,219 ; subps %xmm3,%xmm11 + DB 69,15,40,251 ; movaps %xmm11,%xmm15 + DB 15,41,76,36,16 ; movaps %xmm1,0x10(%rsp) + DB 68,15,89,249 ; mulps %xmm1,%xmm15 + DB 69,15,40,233 ; movaps %xmm9,%xmm13 + DB 68,15,92,239 ; subps %xmm7,%xmm13 + DB 69,15,89,197 ; mulps %xmm13,%xmm8 + DB 69,15,88,199 ; addps %xmm15,%xmm8 + DB 68,15,88,243 ; addps %xmm3,%xmm14 + DB 68,15,89,241 ; mulps %xmm1,%xmm14 + DB 15,194,195,2 ; cmpleps %xmm3,%xmm0 + DB 68,15,84,240 ; andps %xmm0,%xmm14 + DB 15,85,196 ; andnps %xmm4,%xmm0 + DB 65,15,86,198 ; orps %xmm14,%xmm0 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 15,41,44,36 ; movaps %xmm5,(%rsp) + DB 68,15,40,197 ; movaps %xmm5,%xmm8 + DB 68,15,94,199 ; divps %xmm7,%xmm8 + DB 69,15,84,196 ; andps %xmm12,%xmm8 + DB 69,15,40,240 ; movaps %xmm8,%xmm14 + DB 69,15,88,246 ; addps %xmm14,%xmm14 + DB 69,15,88,246 ; addps %xmm14,%xmm14 + DB 65,15,40,230 ; movaps %xmm14,%xmm4 + DB 15,89,228 ; mulps %xmm4,%xmm4 + DB 65,15,88,230 ; addps %xmm14,%xmm4 + DB 69,15,40,248 ; movaps %xmm8,%xmm15 + DB 69,15,92,249 ; subps %xmm9,%xmm15 + DB 68,15,89,252 ; mulps %xmm4,%xmm15 + DB 69,15,40,241 ; movaps %xmm9,%xmm14 + DB 69,15,92,240 ; subps %xmm8,%xmm14 + DB 65,15,82,224 ; rsqrtps %xmm8,%xmm4 + DB 15,83,228 ; rcpps %xmm4,%xmm4 + DB 65,15,92,224 ; subps %xmm8,%xmm4 + DB 69,15,89,194 ; mulps %xmm10,%xmm8 + DB 69,15,88,199 ; addps %xmm15,%xmm8 + DB 68,15,40,253 ; movaps %xmm5,%xmm15 + DB 69,15,88,255 ; addps %xmm15,%xmm15 + DB 69,15,88,255 ; addps %xmm15,%xmm15 + DB 68,15,194,255,2 ; cmpleps %xmm7,%xmm15 + DB 69,15,84,199 ; andps %xmm15,%xmm8 + DB 68,15,85,252 ; andnps %xmm4,%xmm15 + DB 69,15,86,248 ; orps %xmm8,%xmm15 + DB 68,15,40,194 ; movaps %xmm2,%xmm8 + DB 69,15,88,192 ; addps %xmm8,%xmm8 + DB 65,15,40,224 ; movaps %xmm8,%xmm4 + DB 15,92,227 ; subps %xmm3,%xmm4 + DB 68,15,89,244 ; mulps %xmm4,%xmm14 + DB 15,89,231 ; mulps %xmm7,%xmm4 + DB 68,15,89,252 ; mulps %xmm4,%xmm15 + DB 15,40,227 ; movaps %xmm3,%xmm4 + DB 15,89,229 ; mulps %xmm5,%xmm4 + DB 68,15,88,252 ; addps %xmm4,%xmm15 + DB 65,15,40,227 ; movaps %xmm11,%xmm4 + DB 15,89,229 ; mulps %xmm5,%xmm4 + DB 65,15,89,213 ; mulps %xmm13,%xmm2 + DB 15,88,212 ; addps %xmm4,%xmm2 + DB 68,15,88,243 ; addps %xmm3,%xmm14 + DB 68,15,89,245 ; mulps %xmm5,%xmm14 + DB 68,15,194,195,2 ; cmpleps %xmm3,%xmm8 + DB 69,15,84,240 ; andps %xmm8,%xmm14 + DB 69,15,85,199 ; andnps %xmm15,%xmm8 + DB 69,15,86,198 ; orps %xmm14,%xmm8 + DB 68,15,88,194 ; addps %xmm2,%xmm8 + DB 68,15,40,246 ; movaps %xmm6,%xmm14 + DB 65,15,40,206 ; movaps %xmm14,%xmm1 + DB 15,94,207 ; divps %xmm7,%xmm1 + DB 65,15,84,204 ; andps %xmm12,%xmm1 + DB 15,40,225 ; movaps %xmm1,%xmm4 + DB 65,15,92,225 ; subps %xmm9,%xmm4 + DB 68,15,92,201 ; subps %xmm1,%xmm9 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 15,82,241 ; rsqrtps %xmm1,%xmm6 + DB 15,83,246 ; rcpps %xmm6,%xmm6 + DB 15,92,241 ; subps %xmm1,%xmm6 + DB 15,88,201 ; addps %xmm1,%xmm1 + DB 15,88,201 ; addps %xmm1,%xmm1 + DB 15,40,233 ; movaps %xmm1,%xmm5 + DB 15,89,237 ; mulps %xmm5,%xmm5 + DB 15,88,233 ; addps %xmm1,%xmm5 + DB 15,89,236 ; mulps %xmm4,%xmm5 + DB 68,15,88,213 ; addps %xmm5,%xmm10 + DB 65,15,40,238 ; movaps %xmm14,%xmm5 + DB 15,40,205 ; movaps %xmm5,%xmm1 + DB 15,88,201 ; addps %xmm1,%xmm1 + DB 15,88,201 ; addps %xmm1,%xmm1 + DB 15,194,207,2 ; cmpleps %xmm7,%xmm1 + DB 68,15,84,209 ; andps %xmm1,%xmm10 + DB 15,85,206 ; andnps %xmm6,%xmm1 + DB 15,40,84,36,32 ; movaps 0x20(%rsp),%xmm2 + DB 68,15,89,234 ; mulps %xmm2,%xmm13 + DB 15,88,210 ; addps %xmm2,%xmm2 + DB 65,15,86,202 ; orps %xmm10,%xmm1 + DB 15,40,226 ; movaps %xmm2,%xmm4 + DB 15,92,227 ; subps %xmm3,%xmm4 + DB 68,15,89,204 ; mulps %xmm4,%xmm9 + DB 15,89,231 ; mulps %xmm7,%xmm4 + DB 15,89,204 ; mulps %xmm4,%xmm1 + DB 15,40,227 ; movaps %xmm3,%xmm4 + DB 15,89,229 ; mulps %xmm5,%xmm4 + DB 15,88,204 ; addps %xmm4,%xmm1 + DB 65,15,40,227 ; movaps %xmm11,%xmm4 + DB 15,89,229 ; mulps %xmm5,%xmm4 + DB 65,15,88,229 ; addps %xmm13,%xmm4 + DB 68,15,88,203 ; addps %xmm3,%xmm9 + DB 68,15,89,205 ; mulps %xmm5,%xmm9 + DB 15,40,245 ; movaps %xmm5,%xmm6 + DB 15,194,211,2 ; cmpleps %xmm3,%xmm2 + DB 68,15,84,202 ; andps %xmm2,%xmm9 + DB 15,85,209 ; andnps %xmm1,%xmm2 + DB 65,15,86,209 ; orps %xmm9,%xmm2 + DB 15,88,212 ; addps %xmm4,%xmm2 + DB 68,15,89,223 ; mulps %xmm7,%xmm11 + DB 65,15,88,219 ; addps %xmm11,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,100,36,16 ; movaps 0x10(%rsp),%xmm4 + DB 15,40,44,36 ; movaps (%rsp),%xmm5 + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 72,131,196,56 ; add $0x38,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_0_sse2 +_sk_clamp_0_sse2 LABEL PROC + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 65,15,95,192 ; maxps %xmm8,%xmm0 + DB 65,15,95,200 ; maxps %xmm8,%xmm1 + DB 65,15,95,208 ; maxps %xmm8,%xmm2 + DB 65,15,95,216 ; maxps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_1_sse2 +_sk_clamp_1_sse2 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,93,192 ; minps %xmm8,%xmm0 + DB 65,15,93,200 ; minps %xmm8,%xmm1 + DB 65,15,93,208 ; minps %xmm8,%xmm2 + DB 65,15,93,216 ; minps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_a_sse2 +_sk_clamp_a_sse2 LABEL PROC + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,93,216 ; minps %xmm8,%xmm3 + DB 15,93,195 ; minps %xmm3,%xmm0 + DB 15,93,203 ; minps %xmm3,%xmm1 + DB 15,93,211 ; minps %xmm3,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_set_rgb_sse2 +_sk_set_rgb_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,15,16,80,8 ; movss 0x8(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_swap_rb_sse2 +_sk_swap_rb_sse2 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_swap_sse2 +_sk_swap_sse2 LABEL PROC + DB 68,15,40,195 ; movaps %xmm3,%xmm8 + DB 68,15,40,202 ; movaps %xmm2,%xmm9 + DB 68,15,40,209 ; movaps %xmm1,%xmm10 + DB 68,15,40,216 ; movaps %xmm0,%xmm11 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 15,40,205 ; movaps %xmm5,%xmm1 + DB 15,40,214 ; movaps %xmm6,%xmm2 + DB 15,40,223 ; movaps %xmm7,%xmm3 + DB 65,15,40,227 ; movaps %xmm11,%xmm4 + DB 65,15,40,234 ; movaps %xmm10,%xmm5 + DB 65,15,40,241 ; movaps %xmm9,%xmm6 + DB 65,15,40,248 ; movaps %xmm8,%xmm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_move_src_dst_sse2 +_sk_move_src_dst_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,224 ; movaps %xmm0,%xmm4 + DB 15,40,233 ; movaps %xmm1,%xmm5 + DB 15,40,242 ; movaps %xmm2,%xmm6 + DB 15,40,251 ; movaps %xmm3,%xmm7 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_move_dst_src_sse2 +_sk_move_dst_src_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 15,40,205 ; movaps %xmm5,%xmm1 + DB 15,40,214 ; movaps %xmm6,%xmm2 + DB 15,40,223 ; movaps %xmm7,%xmm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_premul_sse2 +_sk_premul_sse2 LABEL PROC + DB 15,89,195 ; mulps %xmm3,%xmm0 + DB 15,89,203 ; mulps %xmm3,%xmm1 + DB 15,89,211 ; mulps %xmm3,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_unpremul_sse2 +_sk_unpremul_sse2 LABEL PROC + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 68,15,94,203 ; divps %xmm3,%xmm9 + DB 68,15,194,195,4 ; cmpneqps %xmm3,%xmm8 + DB 69,15,84,193 ; andps %xmm9,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_from_srgb_sse2 +_sk_from_srgb_sse2 LABEL PROC + DB 184,145,131,158,61 ; mov $0x3d9e8391,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,232 ; movaps %xmm8,%xmm13 + DB 68,15,89,232 ; mulps %xmm0,%xmm13 + DB 68,15,40,224 ; movaps %xmm0,%xmm12 + DB 69,15,89,228 ; mulps %xmm12,%xmm12 + DB 184,154,153,153,62 ; mov $0x3e99999a,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 184,92,143,50,63 ; mov $0x3f328f5c,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,40,241 ; movaps %xmm9,%xmm14 + DB 68,15,89,240 ; mulps %xmm0,%xmm14 + DB 69,15,88,242 ; addps %xmm10,%xmm14 + DB 184,10,215,35,59 ; mov $0x3b23d70a,%eax + DB 102,68,15,110,216 ; movd %eax,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,244 ; mulps %xmm12,%xmm14 + DB 69,15,88,243 ; addps %xmm11,%xmm14 + DB 184,174,71,97,61 ; mov $0x3d6147ae,%eax + DB 102,68,15,110,224 ; movd %eax,%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 65,15,194,196,1 ; cmpltps %xmm12,%xmm0 + DB 68,15,84,232 ; andps %xmm0,%xmm13 + DB 65,15,85,198 ; andnps %xmm14,%xmm0 + DB 65,15,86,197 ; orps %xmm13,%xmm0 + DB 69,15,40,232 ; movaps %xmm8,%xmm13 + DB 68,15,89,233 ; mulps %xmm1,%xmm13 + DB 68,15,40,241 ; movaps %xmm1,%xmm14 + DB 69,15,89,246 ; mulps %xmm14,%xmm14 + DB 69,15,40,249 ; movaps %xmm9,%xmm15 + DB 68,15,89,249 ; mulps %xmm1,%xmm15 + DB 69,15,88,250 ; addps %xmm10,%xmm15 + DB 69,15,89,254 ; mulps %xmm14,%xmm15 + DB 69,15,88,251 ; addps %xmm11,%xmm15 + DB 65,15,194,204,1 ; cmpltps %xmm12,%xmm1 + DB 68,15,84,233 ; andps %xmm1,%xmm13 + DB 65,15,85,207 ; andnps %xmm15,%xmm1 + DB 65,15,86,205 ; orps %xmm13,%xmm1 + DB 68,15,89,194 ; mulps %xmm2,%xmm8 + DB 68,15,40,234 ; movaps %xmm2,%xmm13 + DB 69,15,89,237 ; mulps %xmm13,%xmm13 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 69,15,89,205 ; mulps %xmm13,%xmm9 + DB 69,15,88,203 ; addps %xmm11,%xmm9 + DB 65,15,194,212,1 ; cmpltps %xmm12,%xmm2 + DB 68,15,84,194 ; andps %xmm2,%xmm8 + DB 65,15,85,209 ; andnps %xmm9,%xmm2 + DB 65,15,86,208 ; orps %xmm8,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_to_srgb_sse2 +_sk_to_srgb_sse2 LABEL PROC + DB 68,15,82,192 ; rsqrtps %xmm0,%xmm8 + DB 69,15,83,248 ; rcpps %xmm8,%xmm15 + DB 69,15,82,232 ; rsqrtps %xmm8,%xmm13 + DB 184,41,92,71,65 ; mov $0x41475c29,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,240 ; movaps %xmm8,%xmm14 + DB 68,15,89,240 ; mulps %xmm0,%xmm14 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 184,194,135,210,62 ; mov $0x3ed287c2,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 184,206,111,48,63 ; mov $0x3f306fce,%eax + DB 102,68,15,110,216 ; movd %eax,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 184,168,87,202,61 ; mov $0x3dca57a8,%eax + DB 53,0,0,0,128 ; xor $0x80000000,%eax + DB 102,68,15,110,224 ; movd %eax,%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 69,15,89,251 ; mulps %xmm11,%xmm15 + DB 69,15,88,252 ; addps %xmm12,%xmm15 + DB 69,15,89,234 ; mulps %xmm10,%xmm13 + DB 69,15,88,239 ; addps %xmm15,%xmm13 + DB 69,15,40,249 ; movaps %xmm9,%xmm15 + DB 69,15,93,253 ; minps %xmm13,%xmm15 + DB 184,4,231,140,59 ; mov $0x3b8ce704,%eax + DB 102,68,15,110,232 ; movd %eax,%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 65,15,194,197,1 ; cmpltps %xmm13,%xmm0 + DB 68,15,84,240 ; andps %xmm0,%xmm14 + DB 65,15,85,199 ; andnps %xmm15,%xmm0 + DB 65,15,86,198 ; orps %xmm14,%xmm0 + DB 68,15,82,241 ; rsqrtps %xmm1,%xmm14 + DB 69,15,83,254 ; rcpps %xmm14,%xmm15 + DB 69,15,82,246 ; rsqrtps %xmm14,%xmm14 + DB 69,15,89,251 ; mulps %xmm11,%xmm15 + DB 69,15,88,252 ; addps %xmm12,%xmm15 + DB 69,15,89,242 ; mulps %xmm10,%xmm14 + DB 69,15,88,247 ; addps %xmm15,%xmm14 + DB 69,15,40,249 ; movaps %xmm9,%xmm15 + DB 69,15,93,254 ; minps %xmm14,%xmm15 + DB 69,15,40,240 ; movaps %xmm8,%xmm14 + DB 68,15,89,241 ; mulps %xmm1,%xmm14 + DB 65,15,194,205,1 ; cmpltps %xmm13,%xmm1 + DB 68,15,84,241 ; andps %xmm1,%xmm14 + DB 65,15,85,207 ; andnps %xmm15,%xmm1 + DB 65,15,86,206 ; orps %xmm14,%xmm1 + DB 68,15,82,242 ; rsqrtps %xmm2,%xmm14 + DB 69,15,83,254 ; rcpps %xmm14,%xmm15 + DB 69,15,89,251 ; mulps %xmm11,%xmm15 + DB 69,15,88,252 ; addps %xmm12,%xmm15 + DB 69,15,82,222 ; rsqrtps %xmm14,%xmm11 + DB 69,15,89,218 ; mulps %xmm10,%xmm11 + DB 69,15,88,223 ; addps %xmm15,%xmm11 + DB 69,15,93,203 ; minps %xmm11,%xmm9 + DB 68,15,89,194 ; mulps %xmm2,%xmm8 + DB 65,15,194,213,1 ; cmpltps %xmm13,%xmm2 + DB 68,15,84,194 ; andps %xmm2,%xmm8 + DB 65,15,85,209 ; andnps %xmm9,%xmm2 + DB 65,15,86,208 ; orps %xmm8,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_from_2dot2_sse2 +_sk_from_2dot2_sse2 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 65,15,82,192 ; rsqrtps %xmm8,%xmm0 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 68,15,82,200 ; rsqrtps %xmm0,%xmm9 + DB 65,15,82,193 ; rsqrtps %xmm9,%xmm0 + DB 68,15,82,208 ; rsqrtps %xmm0,%xmm10 + DB 69,15,89,192 ; mulps %xmm8,%xmm8 + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 15,89,192 ; mulps %xmm0,%xmm0 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,89,194 ; mulps %xmm10,%xmm0 + DB 69,15,87,210 ; xorps %xmm10,%xmm10 + DB 65,15,95,194 ; maxps %xmm10,%xmm0 + DB 68,15,82,193 ; rsqrtps %xmm1,%xmm8 + DB 69,15,82,192 ; rsqrtps %xmm8,%xmm8 + DB 69,15,82,192 ; rsqrtps %xmm8,%xmm8 + DB 69,15,82,200 ; rsqrtps %xmm8,%xmm9 + DB 69,15,82,193 ; rsqrtps %xmm9,%xmm8 + DB 69,15,82,216 ; rsqrtps %xmm8,%xmm11 + DB 15,89,201 ; mulps %xmm1,%xmm1 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 69,15,89,192 ; mulps %xmm8,%xmm8 + DB 69,15,89,193 ; mulps %xmm9,%xmm8 + DB 68,15,89,193 ; mulps %xmm1,%xmm8 + DB 69,15,89,195 ; mulps %xmm11,%xmm8 + DB 69,15,95,194 ; maxps %xmm10,%xmm8 + DB 15,82,202 ; rsqrtps %xmm2,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 68,15,82,217 ; rsqrtps %xmm1,%xmm11 + DB 65,15,82,203 ; rsqrtps %xmm11,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 15,89,210 ; mulps %xmm2,%xmm2 + DB 69,15,40,203 ; movaps %xmm11,%xmm9 + DB 69,15,89,201 ; mulps %xmm9,%xmm9 + DB 69,15,89,203 ; mulps %xmm11,%xmm9 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 68,15,89,201 ; mulps %xmm1,%xmm9 + DB 69,15,95,202 ; maxps %xmm10,%xmm9 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 65,15,40,209 ; movaps %xmm9,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_to_2dot2_sse2 +_sk_to_2dot2_sse2 LABEL PROC + DB 68,15,82,192 ; rsqrtps %xmm0,%xmm8 + DB 65,15,82,192 ; rsqrtps %xmm8,%xmm0 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 15,82,192 ; rsqrtps %xmm0,%xmm0 + DB 68,15,82,200 ; rsqrtps %xmm0,%xmm9 + DB 69,15,83,192 ; rcpps %xmm8,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 65,15,83,193 ; rcpps %xmm9,%xmm0 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 65,15,95,192 ; maxps %xmm8,%xmm0 + DB 68,15,82,201 ; rsqrtps %xmm1,%xmm9 + DB 65,15,82,201 ; rsqrtps %xmm9,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 15,82,201 ; rsqrtps %xmm1,%xmm1 + DB 68,15,82,209 ; rsqrtps %xmm1,%xmm10 + DB 69,15,83,201 ; rcpps %xmm9,%xmm9 + DB 68,15,89,201 ; mulps %xmm1,%xmm9 + DB 65,15,83,202 ; rcpps %xmm10,%xmm1 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 65,15,95,200 ; maxps %xmm8,%xmm1 + DB 68,15,82,202 ; rsqrtps %xmm2,%xmm9 + DB 65,15,82,209 ; rsqrtps %xmm9,%xmm2 + DB 15,82,210 ; rsqrtps %xmm2,%xmm2 + DB 15,82,210 ; rsqrtps %xmm2,%xmm2 + DB 15,82,210 ; rsqrtps %xmm2,%xmm2 + DB 68,15,82,210 ; rsqrtps %xmm2,%xmm10 + DB 69,15,83,201 ; rcpps %xmm9,%xmm9 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 65,15,83,210 ; rcpps %xmm10,%xmm2 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 65,15,95,208 ; maxps %xmm8,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_rgb_to_hsl_sse2 +_sk_rgb_to_hsl_sse2 LABEL PROC + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 69,15,40,208 ; movaps %xmm8,%xmm10 + DB 69,15,95,209 ; maxps %xmm9,%xmm10 + DB 68,15,95,210 ; maxps %xmm2,%xmm10 + DB 69,15,40,216 ; movaps %xmm8,%xmm11 + DB 69,15,93,217 ; minps %xmm9,%xmm11 + DB 68,15,93,218 ; minps %xmm2,%xmm11 + DB 65,15,40,202 ; movaps %xmm10,%xmm1 + DB 65,15,92,203 ; subps %xmm11,%xmm1 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,224 ; movd %eax,%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 68,15,94,225 ; divps %xmm1,%xmm12 + DB 65,184,171,170,42,62 ; mov $0x3e2aaaab,%r8d + DB 65,15,40,194 ; movaps %xmm10,%xmm0 + DB 65,15,194,192,0 ; cmpeqps %xmm8,%xmm0 + DB 69,15,40,241 ; movaps %xmm9,%xmm14 + DB 68,15,194,242,1 ; cmpltps %xmm2,%xmm14 + DB 185,0,0,192,64 ; mov $0x40c00000,%ecx + DB 102,68,15,110,233 ; movd %ecx,%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,84,238 ; andps %xmm14,%xmm13 + DB 69,15,40,241 ; movaps %xmm9,%xmm14 + DB 68,15,92,242 ; subps %xmm2,%xmm14 + DB 69,15,89,244 ; mulps %xmm12,%xmm14 + DB 69,15,88,238 ; addps %xmm14,%xmm13 + DB 69,15,40,242 ; movaps %xmm10,%xmm14 + DB 69,15,194,241,0 ; cmpeqps %xmm9,%xmm14 + DB 65,15,92,208 ; subps %xmm8,%xmm2 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 65,15,89,212 ; mulps %xmm12,%xmm2 + DB 185,0,0,0,64 ; mov $0x40000000,%ecx + DB 69,15,89,196 ; mulps %xmm12,%xmm8 + DB 184,0,0,128,64 ; mov $0x40800000,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 69,15,88,200 ; addps %xmm8,%xmm9 + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,88,208 ; addps %xmm8,%xmm2 + DB 65,15,84,214 ; andps %xmm14,%xmm2 + DB 69,15,85,241 ; andnps %xmm9,%xmm14 + DB 68,15,86,242 ; orps %xmm2,%xmm14 + DB 68,15,84,232 ; andps %xmm0,%xmm13 + DB 65,15,85,198 ; andnps %xmm14,%xmm0 + DB 102,65,15,110,208 ; movd %r8d,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 65,15,86,197 ; orps %xmm13,%xmm0 + DB 69,15,40,202 ; movaps %xmm10,%xmm9 + DB 69,15,194,203,4 ; cmpneqps %xmm11,%xmm9 + DB 65,15,84,193 ; andps %xmm9,%xmm0 + DB 15,89,194 ; mulps %xmm2,%xmm0 + DB 69,15,92,194 ; subps %xmm10,%xmm8 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 184,0,0,0,63 ; mov $0x3f000000,%eax + DB 102,68,15,110,224 ; movd %eax,%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 69,15,92,195 ; subps %xmm11,%xmm8 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 65,15,89,212 ; mulps %xmm12,%xmm2 + DB 68,15,194,226,1 ; cmpltps %xmm2,%xmm12 + DB 69,15,84,196 ; andps %xmm12,%xmm8 + DB 69,15,85,226 ; andnps %xmm10,%xmm12 + DB 69,15,86,224 ; orps %xmm8,%xmm12 + DB 65,15,94,204 ; divps %xmm12,%xmm1 + DB 65,15,84,201 ; andps %xmm9,%xmm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_hsl_to_rgb_sse2 +_sk_hsl_to_rgb_sse2 LABEL PROC + DB 72,131,236,104 ; sub $0x68,%rsp + DB 15,41,124,36,80 ; movaps %xmm7,0x50(%rsp) + DB 15,41,116,36,64 ; movaps %xmm6,0x40(%rsp) + DB 15,41,108,36,48 ; movaps %xmm5,0x30(%rsp) + DB 15,41,100,36,32 ; movaps %xmm4,0x20(%rsp) + DB 15,41,92,36,16 ; movaps %xmm3,0x10(%rsp) + DB 68,15,40,210 ; movaps %xmm2,%xmm10 + DB 15,40,209 ; movaps %xmm1,%xmm2 + DB 15,40,240 ; movaps %xmm0,%xmm6 + DB 184,0,0,0,63 ; mov $0x3f000000,%eax + DB 102,68,15,110,240 ; movd %eax,%xmm14 + DB 69,15,198,246,0 ; shufps $0x0,%xmm14,%xmm14 + DB 69,15,40,202 ; movaps %xmm10,%xmm9 + DB 69,15,194,206,1 ; cmpltps %xmm14,%xmm9 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,224 ; movd %eax,%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 65,15,40,196 ; movaps %xmm12,%xmm0 + DB 15,88,194 ; addps %xmm2,%xmm0 + DB 65,15,89,194 ; mulps %xmm10,%xmm0 + DB 15,40,218 ; movaps %xmm2,%xmm3 + DB 69,15,87,219 ; xorps %xmm11,%xmm11 + DB 68,15,194,218,0 ; cmpeqps %xmm2,%xmm11 + DB 65,15,88,210 ; addps %xmm10,%xmm2 + DB 65,15,89,218 ; mulps %xmm10,%xmm3 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 65,15,84,193 ; andps %xmm9,%xmm0 + DB 68,15,85,202 ; andnps %xmm2,%xmm9 + DB 68,15,86,200 ; orps %xmm0,%xmm9 + DB 184,0,0,0,64 ; mov $0x40000000,%eax + DB 185,171,170,170,62 ; mov $0x3eaaaaab,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,41,4,36 ; movaps %xmm8,(%rsp) + DB 68,15,88,198 ; addps %xmm6,%xmm8 + DB 185,0,0,0,0 ; mov $0x0,%ecx + DB 102,15,110,233 ; movd %ecx,%xmm5 + DB 15,198,237,0 ; shufps $0x0,%xmm5,%xmm5 + DB 65,15,40,196 ; movaps %xmm12,%xmm0 + DB 65,15,194,192,1 ; cmpltps %xmm8,%xmm0 + DB 65,15,40,216 ; movaps %xmm8,%xmm3 + DB 65,15,92,220 ; subps %xmm12,%xmm3 + DB 15,84,216 ; andps %xmm0,%xmm3 + DB 65,15,85,192 ; andnps %xmm8,%xmm0 + DB 15,86,195 ; orps %xmm3,%xmm0 + DB 65,15,40,216 ; movaps %xmm8,%xmm3 + DB 15,194,221,1 ; cmpltps %xmm5,%xmm3 + DB 65,15,40,212 ; movaps %xmm12,%xmm2 + DB 65,15,88,208 ; addps %xmm8,%xmm2 + DB 15,84,211 ; andps %xmm3,%xmm2 + DB 15,85,216 ; andnps %xmm0,%xmm3 + DB 15,86,218 ; orps %xmm2,%xmm3 + DB 102,68,15,110,232 ; movd %eax,%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,89,234 ; mulps %xmm10,%xmm13 + DB 69,15,92,233 ; subps %xmm9,%xmm13 + DB 184,171,170,42,62 ; mov $0x3e2aaaab,%eax + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 65,15,92,197 ; subps %xmm13,%xmm0 + DB 185,0,0,192,64 ; mov $0x40c00000,%ecx + DB 102,68,15,110,249 ; movd %ecx,%xmm15 + DB 69,15,198,255,0 ; shufps $0x0,%xmm15,%xmm15 + DB 68,15,89,248 ; mulps %xmm0,%xmm15 + DB 185,171,170,42,63 ; mov $0x3f2aaaab,%ecx + DB 102,15,110,225 ; movd %ecx,%xmm4 + DB 15,198,228,0 ; shufps $0x0,%xmm4,%xmm4 + DB 15,40,212 ; movaps %xmm4,%xmm2 + DB 15,92,211 ; subps %xmm3,%xmm2 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 15,40,195 ; movaps %xmm3,%xmm0 + DB 15,194,220,1 ; cmpltps %xmm4,%xmm3 + DB 65,15,89,215 ; mulps %xmm15,%xmm2 + DB 65,15,88,213 ; addps %xmm13,%xmm2 + DB 15,84,211 ; andps %xmm3,%xmm2 + DB 65,15,85,221 ; andnps %xmm13,%xmm3 + DB 15,86,218 ; orps %xmm2,%xmm3 + DB 65,15,194,198,1 ; cmpltps %xmm14,%xmm0 + DB 65,15,40,209 ; movaps %xmm9,%xmm2 + DB 15,84,208 ; andps %xmm0,%xmm2 + DB 15,85,195 ; andnps %xmm3,%xmm0 + DB 15,86,194 ; orps %xmm2,%xmm0 + DB 102,15,110,248 ; movd %eax,%xmm7 + DB 15,198,255,0 ; shufps $0x0,%xmm7,%xmm7 + DB 15,194,207,1 ; cmpltps %xmm7,%xmm1 + DB 69,15,89,199 ; mulps %xmm15,%xmm8 + DB 69,15,88,197 ; addps %xmm13,%xmm8 + DB 68,15,84,193 ; andps %xmm1,%xmm8 + DB 15,85,200 ; andnps %xmm0,%xmm1 + DB 65,15,86,200 ; orps %xmm8,%xmm1 + DB 69,15,40,195 ; movaps %xmm11,%xmm8 + DB 68,15,85,193 ; andnps %xmm1,%xmm8 + DB 65,15,40,196 ; movaps %xmm12,%xmm0 + DB 15,194,198,1 ; cmpltps %xmm6,%xmm0 + DB 15,40,206 ; movaps %xmm6,%xmm1 + DB 65,15,92,204 ; subps %xmm12,%xmm1 + DB 15,84,200 ; andps %xmm0,%xmm1 + DB 15,85,198 ; andnps %xmm6,%xmm0 + DB 15,86,193 ; orps %xmm1,%xmm0 + DB 15,40,206 ; movaps %xmm6,%xmm1 + DB 15,194,205,1 ; cmpltps %xmm5,%xmm1 + DB 65,15,40,212 ; movaps %xmm12,%xmm2 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 15,84,209 ; andps %xmm1,%xmm2 + DB 15,85,200 ; andnps %xmm0,%xmm1 + DB 15,86,202 ; orps %xmm2,%xmm1 + DB 15,40,196 ; movaps %xmm4,%xmm0 + DB 15,92,193 ; subps %xmm1,%xmm0 + DB 15,40,217 ; movaps %xmm1,%xmm3 + DB 15,40,209 ; movaps %xmm1,%xmm2 + DB 15,194,204,1 ; cmpltps %xmm4,%xmm1 + DB 65,15,89,199 ; mulps %xmm15,%xmm0 + DB 65,15,88,197 ; addps %xmm13,%xmm0 + DB 15,84,193 ; andps %xmm1,%xmm0 + DB 65,15,85,205 ; andnps %xmm13,%xmm1 + DB 15,86,200 ; orps %xmm0,%xmm1 + DB 65,15,194,214,1 ; cmpltps %xmm14,%xmm2 + DB 65,15,40,193 ; movaps %xmm9,%xmm0 + DB 15,84,194 ; andps %xmm2,%xmm0 + DB 15,85,209 ; andnps %xmm1,%xmm2 + DB 15,86,208 ; orps %xmm0,%xmm2 + DB 15,194,223,1 ; cmpltps %xmm7,%xmm3 + DB 65,15,40,199 ; movaps %xmm15,%xmm0 + DB 15,89,198 ; mulps %xmm6,%xmm0 + DB 65,15,88,197 ; addps %xmm13,%xmm0 + DB 15,84,195 ; andps %xmm3,%xmm0 + DB 15,85,218 ; andnps %xmm2,%xmm3 + DB 15,86,216 ; orps %xmm0,%xmm3 + DB 65,15,40,203 ; movaps %xmm11,%xmm1 + DB 15,85,203 ; andnps %xmm3,%xmm1 + DB 15,92,52,36 ; subps (%rsp),%xmm6 + DB 15,40,198 ; movaps %xmm6,%xmm0 + DB 15,194,197,1 ; cmpltps %xmm5,%xmm0 + DB 15,40,214 ; movaps %xmm6,%xmm2 + DB 65,15,92,212 ; subps %xmm12,%xmm2 + DB 65,15,40,220 ; movaps %xmm12,%xmm3 + DB 68,15,194,230,1 ; cmpltps %xmm6,%xmm12 + DB 65,15,84,212 ; andps %xmm12,%xmm2 + DB 68,15,85,230 ; andnps %xmm6,%xmm12 + DB 68,15,86,226 ; orps %xmm2,%xmm12 + DB 15,88,222 ; addps %xmm6,%xmm3 + DB 15,84,216 ; andps %xmm0,%xmm3 + DB 65,15,85,196 ; andnps %xmm12,%xmm0 + DB 15,86,195 ; orps %xmm3,%xmm0 + DB 15,40,232 ; movaps %xmm0,%xmm5 + DB 15,194,239,1 ; cmpltps %xmm7,%xmm5 + DB 15,40,208 ; movaps %xmm0,%xmm2 + DB 15,194,212,1 ; cmpltps %xmm4,%xmm2 + DB 15,92,224 ; subps %xmm0,%xmm4 + DB 65,15,194,198,1 ; cmpltps %xmm14,%xmm0 + DB 65,15,89,247 ; mulps %xmm15,%xmm6 + DB 65,15,89,231 ; mulps %xmm15,%xmm4 + DB 65,15,88,245 ; addps %xmm13,%xmm6 + DB 65,15,88,229 ; addps %xmm13,%xmm4 + DB 15,84,226 ; andps %xmm2,%xmm4 + DB 65,15,85,213 ; andnps %xmm13,%xmm2 + DB 15,86,212 ; orps %xmm4,%xmm2 + DB 68,15,84,200 ; andps %xmm0,%xmm9 + DB 15,85,194 ; andnps %xmm2,%xmm0 + DB 65,15,86,193 ; orps %xmm9,%xmm0 + DB 15,84,245 ; andps %xmm5,%xmm6 + DB 15,85,232 ; andnps %xmm0,%xmm5 + DB 15,86,238 ; orps %xmm6,%xmm5 + DB 69,15,84,211 ; andps %xmm11,%xmm10 + DB 68,15,85,221 ; andnps %xmm5,%xmm11 + DB 69,15,86,194 ; orps %xmm10,%xmm8 + DB 65,15,86,202 ; orps %xmm10,%xmm1 + DB 69,15,86,211 ; orps %xmm11,%xmm10 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 15,40,92,36,16 ; movaps 0x10(%rsp),%xmm3 + DB 15,40,100,36,32 ; movaps 0x20(%rsp),%xmm4 + DB 15,40,108,36,48 ; movaps 0x30(%rsp),%xmm5 + DB 15,40,116,36,64 ; movaps 0x40(%rsp),%xmm6 + DB 15,40,124,36,80 ; movaps 0x50(%rsp),%xmm7 + DB 72,131,196,104 ; add $0x68,%rsp + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_scale_1_float_sse2 +_sk_scale_1_float_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,0 ; movss (%rax),%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_scale_u8_sse2 +_sk_scale_u8_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,68,15,110,4,56 ; movd (%rax,%rdi,1),%xmm8 + DB 102,69,15,239,201 ; pxor %xmm9,%xmm9 + DB 102,69,15,96,193 ; punpcklbw %xmm9,%xmm8 + DB 102,69,15,97,193 ; punpcklwd %xmm9,%xmm8 + DB 69,15,91,192 ; cvtdq2ps %xmm8,%xmm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 65,15,89,217 ; mulps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lerp_1_float_sse2 +_sk_lerp_1_float_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,0 ; movss (%rax),%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,92,196 ; subps %xmm4,%xmm0 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 15,92,205 ; subps %xmm5,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 15,92,214 ; subps %xmm6,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 15,92,223 ; subps %xmm7,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 15,88,223 ; addps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lerp_u8_sse2 +_sk_lerp_u8_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,68,15,110,4,56 ; movd (%rax,%rdi,1),%xmm8 + DB 102,69,15,239,201 ; pxor %xmm9,%xmm9 + DB 102,69,15,96,193 ; punpcklbw %xmm9,%xmm8 + DB 102,69,15,97,193 ; punpcklwd %xmm9,%xmm8 + DB 69,15,91,192 ; cvtdq2ps %xmm8,%xmm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,68,15,110,200 ; movd %eax,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 15,92,196 ; subps %xmm4,%xmm0 + DB 65,15,89,193 ; mulps %xmm9,%xmm0 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 15,92,205 ; subps %xmm5,%xmm1 + DB 65,15,89,201 ; mulps %xmm9,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 15,92,214 ; subps %xmm6,%xmm2 + DB 65,15,89,209 ; mulps %xmm9,%xmm2 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 15,92,223 ; subps %xmm7,%xmm3 + DB 65,15,89,217 ; mulps %xmm9,%xmm3 + DB 15,88,223 ; addps %xmm7,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_lerp_565_sse2 +_sk_lerp_565_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 243,68,15,126,4,120 ; movq (%rax,%rdi,2),%xmm8 + DB 102,15,239,219 ; pxor %xmm3,%xmm3 + DB 102,68,15,97,195 ; punpcklwd %xmm3,%xmm8 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,65,15,219,216 ; pand %xmm8,%xmm3 + DB 68,15,91,203 ; cvtdq2ps %xmm3,%xmm9 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 102,68,15,110,208 ; movd %eax,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,65,15,219,216 ; pand %xmm8,%xmm3 + DB 68,15,91,203 ; cvtdq2ps %xmm3,%xmm9 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 102,68,15,110,216 ; movd %eax,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,217 ; mulps %xmm9,%xmm11 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,65,15,219,216 ; pand %xmm8,%xmm3 + DB 68,15,91,195 ; cvtdq2ps %xmm3,%xmm8 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 15,92,196 ; subps %xmm4,%xmm0 + DB 65,15,89,194 ; mulps %xmm10,%xmm0 + DB 15,88,196 ; addps %xmm4,%xmm0 + DB 15,92,205 ; subps %xmm5,%xmm1 + DB 65,15,89,203 ; mulps %xmm11,%xmm1 + DB 15,88,205 ; addps %xmm5,%xmm1 + DB 15,92,214 ; subps %xmm6,%xmm2 + DB 15,89,211 ; mulps %xmm3,%xmm2 + DB 15,88,214 ; addps %xmm6,%xmm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_tables_sse2 +_sk_load_tables_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,8 ; mov (%rax),%rcx + DB 76,139,64,8 ; mov 0x8(%rax),%r8 + DB 243,68,15,111,4,185 ; movdqu (%rcx,%rdi,4),%xmm8 + DB 185,255,0,0,0 ; mov $0xff,%ecx + DB 102,15,110,193 ; movd %ecx,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,69,15,111,200 ; movdqa %xmm8,%xmm9 + DB 102,65,15,114,209,8 ; psrld $0x8,%xmm9 + DB 102,68,15,219,200 ; pand %xmm0,%xmm9 + DB 102,69,15,111,208 ; movdqa %xmm8,%xmm10 + DB 102,65,15,114,210,16 ; psrld $0x10,%xmm10 + DB 102,68,15,219,208 ; pand %xmm0,%xmm10 + DB 102,65,15,219,192 ; pand %xmm8,%xmm0 + DB 102,15,112,216,78 ; pshufd $0x4e,%xmm0,%xmm3 + DB 102,72,15,126,217 ; movq %xmm3,%rcx + DB 65,137,201 ; mov %ecx,%r9d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,73,15,126,194 ; movq %xmm0,%r10 + DB 69,137,211 ; mov %r10d,%r11d + DB 73,193,234,32 ; shr $0x20,%r10 + DB 243,67,15,16,28,144 ; movss (%r8,%r10,4),%xmm3 + DB 243,65,15,16,4,136 ; movss (%r8,%rcx,4),%xmm0 + DB 15,20,216 ; unpcklps %xmm0,%xmm3 + DB 243,67,15,16,4,152 ; movss (%r8,%r11,4),%xmm0 + DB 243,67,15,16,12,136 ; movss (%r8,%r9,4),%xmm1 + DB 15,20,193 ; unpcklps %xmm1,%xmm0 + DB 15,20,195 ; unpcklps %xmm3,%xmm0 + DB 76,139,64,16 ; mov 0x10(%rax),%r8 + DB 102,65,15,112,201,78 ; pshufd $0x4e,%xmm9,%xmm1 + DB 102,73,15,126,202 ; movq %xmm1,%r10 + DB 77,137,209 ; mov %r10,%r9 + DB 73,193,233,32 ; shr $0x20,%r9 + DB 102,76,15,126,201 ; movq %xmm9,%rcx + DB 65,137,203 ; mov %ecx,%r11d + DB 65,129,227,255,255,255,0 ; and $0xffffff,%r11d + DB 72,193,233,30 ; shr $0x1e,%rcx + DB 65,129,226,255,255,255,0 ; and $0xffffff,%r10d + DB 243,65,15,16,28,8 ; movss (%r8,%rcx,1),%xmm3 + DB 243,67,15,16,12,136 ; movss (%r8,%r9,4),%xmm1 + DB 15,20,217 ; unpcklps %xmm1,%xmm3 + DB 243,67,15,16,12,152 ; movss (%r8,%r11,4),%xmm1 + DB 243,67,15,16,20,144 ; movss (%r8,%r10,4),%xmm2 + DB 15,20,202 ; unpcklps %xmm2,%xmm1 + DB 15,20,203 ; unpcklps %xmm3,%xmm1 + DB 76,139,72,24 ; mov 0x18(%rax),%r9 + DB 102,65,15,112,210,78 ; pshufd $0x4e,%xmm10,%xmm2 + DB 102,72,15,126,209 ; movq %xmm2,%rcx + DB 68,15,183,193 ; movzwl %cx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,76,15,126,208 ; movq %xmm10,%rax + DB 68,15,183,208 ; movzwl %ax,%r10d + DB 72,193,232,30 ; shr $0x1e,%rax + DB 243,69,15,16,12,1 ; movss (%r9,%rax,1),%xmm9 + DB 243,65,15,16,20,137 ; movss (%r9,%rcx,4),%xmm2 + DB 68,15,20,202 ; unpcklps %xmm2,%xmm9 + DB 243,67,15,16,20,145 ; movss (%r9,%r10,4),%xmm2 + DB 243,67,15,16,28,129 ; movss (%r9,%r8,4),%xmm3 + DB 15,20,211 ; unpcklps %xmm3,%xmm2 + DB 65,15,20,209 ; unpcklps %xmm9,%xmm2 + DB 102,65,15,114,208,24 ; psrld $0x18,%xmm8 + DB 69,15,91,192 ; cvtdq2ps %xmm8,%xmm8 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_byte_tables_sse2 +_sk_byte_tables_sse2 LABEL PROC + DB 65,86 ; push %r14 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,127,67 ; mov $0x437f0000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 102,15,91,192 ; cvtps2dq %xmm0,%xmm0 + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,15,112,192,78 ; pshufd $0x4e,%xmm0,%xmm0 + DB 102,73,15,126,193 ; movq %xmm0,%r9 + DB 69,137,202 ; mov %r9d,%r10d + DB 77,137,203 ; mov %r9,%r11 + DB 73,193,235,32 ; shr $0x20,%r11 + DB 76,139,48 ; mov (%rax),%r14 + DB 76,139,72,8 ; mov 0x8(%rax),%r9 + DB 71,15,182,20,22 ; movzbl (%r14,%r10,1),%r10d + DB 67,15,182,28,30 ; movzbl (%r14,%r11,1),%ebx + DB 193,227,8 ; shl $0x8,%ebx + DB 68,9,211 ; or %r10d,%ebx + DB 71,15,182,4,6 ; movzbl (%r14,%r8,1),%r8d + DB 65,15,182,12,14 ; movzbl (%r14,%rcx,1),%ecx + DB 193,225,8 ; shl $0x8,%ecx + DB 68,9,193 ; or %r8d,%ecx + DB 102,15,196,193,0 ; pinsrw $0x0,%ecx,%xmm0 + DB 102,15,196,195,1 ; pinsrw $0x1,%ebx,%xmm0 + DB 102,69,15,239,201 ; pxor %xmm9,%xmm9 + DB 102,65,15,96,193 ; punpcklbw %xmm9,%xmm0 + DB 102,65,15,97,193 ; punpcklwd %xmm9,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 185,129,128,128,59 ; mov $0x3b808081,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 65,15,89,194 ; mulps %xmm10,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 102,15,91,201 ; cvtps2dq %xmm1,%xmm1 + DB 102,72,15,126,201 ; movq %xmm1,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,15,112,201,78 ; pshufd $0x4e,%xmm1,%xmm1 + DB 102,72,15,126,203 ; movq %xmm1,%rbx + DB 65,137,218 ; mov %ebx,%r10d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 71,15,182,20,17 ; movzbl (%r9,%r10,1),%r10d + DB 65,15,182,28,25 ; movzbl (%r9,%rbx,1),%ebx + DB 193,227,8 ; shl $0x8,%ebx + DB 68,9,211 ; or %r10d,%ebx + DB 71,15,182,4,1 ; movzbl (%r9,%r8,1),%r8d + DB 65,15,182,12,9 ; movzbl (%r9,%rcx,1),%ecx + DB 193,225,8 ; shl $0x8,%ecx + DB 68,9,193 ; or %r8d,%ecx + DB 102,15,196,201,0 ; pinsrw $0x0,%ecx,%xmm1 + DB 102,15,196,203,1 ; pinsrw $0x1,%ebx,%xmm1 + DB 102,65,15,96,201 ; punpcklbw %xmm9,%xmm1 + DB 102,65,15,97,201 ; punpcklwd %xmm9,%xmm1 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,202 ; mulps %xmm10,%xmm1 + DB 76,139,72,16 ; mov 0x10(%rax),%r9 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,15,91,210 ; cvtps2dq %xmm2,%xmm2 + DB 102,72,15,126,211 ; movq %xmm2,%rbx + DB 65,137,216 ; mov %ebx,%r8d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 102,15,112,210,78 ; pshufd $0x4e,%xmm2,%xmm2 + DB 102,72,15,126,209 ; movq %xmm2,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 71,15,182,20,17 ; movzbl (%r9,%r10,1),%r10d + DB 65,15,182,12,9 ; movzbl (%r9,%rcx,1),%ecx + DB 193,225,8 ; shl $0x8,%ecx + DB 68,9,209 ; or %r10d,%ecx + DB 71,15,182,4,1 ; movzbl (%r9,%r8,1),%r8d + DB 65,15,182,28,25 ; movzbl (%r9,%rbx,1),%ebx + DB 193,227,8 ; shl $0x8,%ebx + DB 68,9,195 ; or %r8d,%ebx + DB 102,15,196,211,0 ; pinsrw $0x0,%ebx,%xmm2 + DB 102,15,196,209,1 ; pinsrw $0x1,%ecx,%xmm2 + DB 102,65,15,96,209 ; punpcklbw %xmm9,%xmm2 + DB 102,65,15,97,209 ; punpcklwd %xmm9,%xmm2 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,210 ; mulps %xmm10,%xmm2 + DB 72,139,64,24 ; mov 0x18(%rax),%rax + DB 68,15,89,195 ; mulps %xmm3,%xmm8 + DB 102,65,15,91,216 ; cvtps2dq %xmm8,%xmm3 + DB 102,72,15,126,217 ; movq %xmm3,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,15,112,219,78 ; pshufd $0x4e,%xmm3,%xmm3 + DB 102,72,15,126,219 ; movq %xmm3,%rbx + DB 65,137,217 ; mov %ebx,%r9d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 70,15,182,12,8 ; movzbl (%rax,%r9,1),%r9d + DB 15,182,28,24 ; movzbl (%rax,%rbx,1),%ebx + DB 193,227,8 ; shl $0x8,%ebx + DB 68,9,203 ; or %r9d,%ebx + DB 70,15,182,4,0 ; movzbl (%rax,%r8,1),%r8d + DB 15,182,4,8 ; movzbl (%rax,%rcx,1),%eax + DB 193,224,8 ; shl $0x8,%eax + DB 68,9,192 ; or %r8d,%eax + DB 102,15,196,216,0 ; pinsrw $0x0,%eax,%xmm3 + DB 102,15,196,219,1 ; pinsrw $0x1,%ebx,%xmm3 + DB 102,65,15,96,217 ; punpcklbw %xmm9,%xmm3 + DB 102,65,15,97,217 ; punpcklwd %xmm9,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 65,15,89,218 ; mulps %xmm10,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,94 ; pop %r14 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_byte_tables_rgb_sse2 +_sk_byte_tables_rgb_sse2 LABEL PROC + DB 65,86 ; push %r14 + DB 83 ; push %rbx + DB 72,173 ; lods %ds:(%rsi),%rax + DB 139,72,24 ; mov 0x18(%rax),%ecx + DB 255,201 ; dec %ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 102,69,15,112,192,0 ; pshufd $0x0,%xmm8,%xmm8 + DB 69,15,91,192 ; cvtdq2ps %xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 102,15,91,192 ; cvtps2dq %xmm0,%xmm0 + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,15,112,192,78 ; pshufd $0x4e,%xmm0,%xmm0 + DB 102,73,15,126,193 ; movq %xmm0,%r9 + DB 69,137,202 ; mov %r9d,%r10d + DB 77,137,203 ; mov %r9,%r11 + DB 73,193,235,32 ; shr $0x20,%r11 + DB 76,139,48 ; mov (%rax),%r14 + DB 76,139,72,8 ; mov 0x8(%rax),%r9 + DB 71,15,182,20,22 ; movzbl (%r14,%r10,1),%r10d + DB 67,15,182,28,30 ; movzbl (%r14,%r11,1),%ebx + DB 193,227,8 ; shl $0x8,%ebx + DB 68,9,211 ; or %r10d,%ebx + DB 71,15,182,4,6 ; movzbl (%r14,%r8,1),%r8d + DB 65,15,182,12,14 ; movzbl (%r14,%rcx,1),%ecx + DB 193,225,8 ; shl $0x8,%ecx + DB 68,9,193 ; or %r8d,%ecx + DB 102,15,196,193,0 ; pinsrw $0x0,%ecx,%xmm0 + DB 102,15,196,195,1 ; pinsrw $0x1,%ebx,%xmm0 + DB 102,69,15,239,201 ; pxor %xmm9,%xmm9 + DB 102,65,15,96,193 ; punpcklbw %xmm9,%xmm0 + DB 102,65,15,97,193 ; punpcklwd %xmm9,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 185,129,128,128,59 ; mov $0x3b808081,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 65,15,89,194 ; mulps %xmm10,%xmm0 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 102,15,91,201 ; cvtps2dq %xmm1,%xmm1 + DB 102,72,15,126,201 ; movq %xmm1,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,15,112,201,78 ; pshufd $0x4e,%xmm1,%xmm1 + DB 102,72,15,126,203 ; movq %xmm1,%rbx + DB 65,137,218 ; mov %ebx,%r10d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 71,15,182,20,17 ; movzbl (%r9,%r10,1),%r10d + DB 65,15,182,28,25 ; movzbl (%r9,%rbx,1),%ebx + DB 193,227,8 ; shl $0x8,%ebx + DB 68,9,211 ; or %r10d,%ebx + DB 71,15,182,4,1 ; movzbl (%r9,%r8,1),%r8d + DB 65,15,182,12,9 ; movzbl (%r9,%rcx,1),%ecx + DB 193,225,8 ; shl $0x8,%ecx + DB 68,9,193 ; or %r8d,%ecx + DB 102,15,196,201,0 ; pinsrw $0x0,%ecx,%xmm1 + DB 102,15,196,203,1 ; pinsrw $0x1,%ebx,%xmm1 + DB 102,65,15,96,201 ; punpcklbw %xmm9,%xmm1 + DB 102,65,15,97,201 ; punpcklwd %xmm9,%xmm1 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,202 ; mulps %xmm10,%xmm1 + DB 72,139,64,16 ; mov 0x10(%rax),%rax + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,15,91,210 ; cvtps2dq %xmm2,%xmm2 + DB 102,72,15,126,209 ; movq %xmm2,%rcx + DB 65,137,200 ; mov %ecx,%r8d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,15,112,210,78 ; pshufd $0x4e,%xmm2,%xmm2 + DB 102,72,15,126,211 ; movq %xmm2,%rbx + DB 65,137,217 ; mov %ebx,%r9d + DB 72,193,235,32 ; shr $0x20,%rbx + DB 70,15,182,12,8 ; movzbl (%rax,%r9,1),%r9d + DB 15,182,28,24 ; movzbl (%rax,%rbx,1),%ebx + DB 193,227,8 ; shl $0x8,%ebx + DB 68,9,203 ; or %r9d,%ebx + DB 70,15,182,4,0 ; movzbl (%rax,%r8,1),%r8d + DB 15,182,4,8 ; movzbl (%rax,%rcx,1),%eax + DB 193,224,8 ; shl $0x8,%eax + DB 68,9,192 ; or %r8d,%eax + DB 102,15,196,208,0 ; pinsrw $0x0,%eax,%xmm2 + DB 102,15,196,211,1 ; pinsrw $0x1,%ebx,%xmm2 + DB 102,65,15,96,209 ; punpcklbw %xmm9,%xmm2 + DB 102,65,15,97,209 ; punpcklwd %xmm9,%xmm2 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,210 ; mulps %xmm10,%xmm2 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 91 ; pop %rbx + DB 65,94 ; pop %r14 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_a8_sse2 +_sk_load_a8_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,15,110,4,56 ; movd (%rax,%rdi,1),%xmm0 + DB 102,15,239,201 ; pxor %xmm1,%xmm1 + DB 102,15,96,193 ; punpcklbw %xmm1,%xmm0 + DB 102,15,97,193 ; punpcklwd %xmm1,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 15,89,216 ; mulps %xmm0,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,87,192 ; xorps %xmm0,%xmm0 + DB 102,15,239,201 ; pxor %xmm1,%xmm1 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_a8_sse2 +_sk_gather_a8_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,112,217,245 ; pshufd $0xf5,%xmm1,%xmm3 + DB 102,15,244,218 ; pmuludq %xmm2,%xmm3 + DB 102,15,112,219,232 ; pshufd $0xe8,%xmm3,%xmm3 + DB 102,15,244,209 ; pmuludq %xmm1,%xmm2 + DB 102,15,112,202,232 ; pshufd $0xe8,%xmm2,%xmm1 + DB 102,15,98,203 ; punpckldq %xmm3,%xmm1 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,193 ; paddd %xmm1,%xmm0 + DB 102,72,15,126,192 ; movq %xmm0,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,15,112,192,78 ; pshufd $0x4e,%xmm0,%xmm0 + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 71,15,182,20,17 ; movzbl (%r9,%r10,1),%r10d + DB 65,15,182,12,9 ; movzbl (%r9,%rcx,1),%ecx + DB 193,225,8 ; shl $0x8,%ecx + DB 68,9,209 ; or %r10d,%ecx + DB 71,15,182,4,1 ; movzbl (%r9,%r8,1),%r8d + DB 65,15,182,4,1 ; movzbl (%r9,%rax,1),%eax + DB 193,224,8 ; shl $0x8,%eax + DB 68,9,192 ; or %r8d,%eax + DB 102,15,196,192,0 ; pinsrw $0x0,%eax,%xmm0 + DB 102,15,196,193,1 ; pinsrw $0x1,%ecx,%xmm0 + DB 102,15,239,201 ; pxor %xmm1,%xmm1 + DB 102,15,96,193 ; punpcklbw %xmm1,%xmm0 + DB 102,15,97,193 ; punpcklwd %xmm1,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 15,89,216 ; mulps %xmm0,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,87,192 ; xorps %xmm0,%xmm0 + DB 102,15,239,201 ; pxor %xmm1,%xmm1 + DB 102,15,239,210 ; pxor %xmm2,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_a8_sse2 +_sk_store_a8_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,0,127,67 ; mov $0x437f0000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,89,195 ; mulps %xmm3,%xmm8 + DB 102,69,15,91,192 ; cvtps2dq %xmm8,%xmm8 + DB 102,65,15,114,240,16 ; pslld $0x10,%xmm8 + DB 102,65,15,114,224,16 ; psrad $0x10,%xmm8 + DB 102,69,15,107,192 ; packssdw %xmm8,%xmm8 + DB 102,69,15,103,192 ; packuswb %xmm8,%xmm8 + DB 102,68,15,126,4,56 ; movd %xmm8,(%rax,%rdi,1) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_g8_sse2 +_sk_load_g8_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 102,15,110,4,56 ; movd (%rax,%rdi,1),%xmm0 + DB 102,15,239,201 ; pxor %xmm1,%xmm1 + DB 102,15,96,193 ; punpcklbw %xmm1,%xmm0 + DB 102,15,97,193 ; punpcklwd %xmm1,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,200 ; movaps %xmm0,%xmm1 + DB 15,40,208 ; movaps %xmm0,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_g8_sse2 +_sk_gather_g8_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,112,217,245 ; pshufd $0xf5,%xmm1,%xmm3 + DB 102,15,244,218 ; pmuludq %xmm2,%xmm3 + DB 102,15,112,219,232 ; pshufd $0xe8,%xmm3,%xmm3 + DB 102,15,244,209 ; pmuludq %xmm1,%xmm2 + DB 102,15,112,202,232 ; pshufd $0xe8,%xmm2,%xmm1 + DB 102,15,98,203 ; punpckldq %xmm3,%xmm1 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,193 ; paddd %xmm1,%xmm0 + DB 102,72,15,126,192 ; movq %xmm0,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,15,112,192,78 ; pshufd $0x4e,%xmm0,%xmm0 + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 71,15,182,20,17 ; movzbl (%r9,%r10,1),%r10d + DB 65,15,182,12,9 ; movzbl (%r9,%rcx,1),%ecx + DB 193,225,8 ; shl $0x8,%ecx + DB 68,9,209 ; or %r10d,%ecx + DB 71,15,182,4,1 ; movzbl (%r9,%r8,1),%r8d + DB 65,15,182,4,1 ; movzbl (%r9,%rax,1),%eax + DB 193,224,8 ; shl $0x8,%eax + DB 68,9,192 ; or %r8d,%eax + DB 102,15,196,192,0 ; pinsrw $0x0,%eax,%xmm0 + DB 102,15,196,193,1 ; pinsrw $0x1,%ecx,%xmm0 + DB 102,15,239,201 ; pxor %xmm1,%xmm1 + DB 102,15,96,193 ; punpcklbw %xmm1,%xmm0 + DB 102,15,97,193 ; punpcklwd %xmm1,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,40,200 ; movaps %xmm0,%xmm1 + DB 15,40,208 ; movaps %xmm0,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_i8_sse2 +_sk_gather_i8_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 73,137,192 ; mov %rax,%r8 + DB 77,133,192 ; test %r8,%r8 + DB 116,5 ; je 1e1a <_sk_gather_i8_sse2+0xf> + DB 76,137,192 ; mov %r8,%rax + DB 235,2 ; jmp 1e1c <_sk_gather_i8_sse2+0x11> + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,16 ; mov (%rax),%r10 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,112,217,245 ; pshufd $0xf5,%xmm1,%xmm3 + DB 102,15,244,218 ; pmuludq %xmm2,%xmm3 + DB 102,15,112,219,232 ; pshufd $0xe8,%xmm3,%xmm3 + DB 102,15,244,209 ; pmuludq %xmm1,%xmm2 + DB 102,15,112,202,232 ; pshufd $0xe8,%xmm2,%xmm1 + DB 102,15,98,203 ; punpckldq %xmm3,%xmm1 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,193 ; paddd %xmm1,%xmm0 + DB 102,72,15,126,192 ; movq %xmm0,%rax + DB 65,137,193 ; mov %eax,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,15,112,192,78 ; pshufd $0x4e,%xmm0,%xmm0 + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,203 ; mov %ecx,%r11d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 71,15,182,28,26 ; movzbl (%r10,%r11,1),%r11d + DB 65,15,182,12,10 ; movzbl (%r10,%rcx,1),%ecx + DB 193,225,8 ; shl $0x8,%ecx + DB 68,9,217 ; or %r11d,%ecx + DB 71,15,182,12,10 ; movzbl (%r10,%r9,1),%r9d + DB 65,15,182,4,2 ; movzbl (%r10,%rax,1),%eax + DB 193,224,8 ; shl $0x8,%eax + DB 68,9,200 ; or %r9d,%eax + DB 102,15,196,192,0 ; pinsrw $0x0,%eax,%xmm0 + DB 102,15,196,193,1 ; pinsrw $0x1,%ecx,%xmm0 + DB 102,15,239,201 ; pxor %xmm1,%xmm1 + DB 102,15,96,193 ; punpcklbw %xmm1,%xmm0 + DB 102,15,97,193 ; punpcklwd %xmm1,%xmm0 + DB 102,15,112,200,78 ; pshufd $0x4e,%xmm0,%xmm1 + DB 102,72,15,126,200 ; movq %xmm1,%rax + DB 68,15,182,200 ; movzbl %al,%r9d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 77,139,64,8 ; mov 0x8(%r8),%r8 + DB 68,15,182,209 ; movzbl %cl,%r10d + DB 72,193,233,30 ; shr $0x1e,%rcx + DB 102,65,15,110,4,8 ; movd (%r8,%rcx,1),%xmm0 + DB 102,65,15,110,12,128 ; movd (%r8,%rax,4),%xmm1 + DB 102,15,98,193 ; punpckldq %xmm1,%xmm0 + DB 102,67,15,110,28,144 ; movd (%r8,%r10,4),%xmm3 + DB 102,67,15,110,12,136 ; movd (%r8,%r9,4),%xmm1 + DB 102,15,98,217 ; punpckldq %xmm1,%xmm3 + DB 102,15,98,216 ; punpckldq %xmm0,%xmm3 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,15,111,203 ; movdqa %xmm3,%xmm1 + DB 102,15,114,209,8 ; psrld $0x8,%xmm1 + DB 102,15,219,200 ; pand %xmm0,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,15,114,210,16 ; psrld $0x10,%xmm2 + DB 102,15,219,208 ; pand %xmm0,%xmm2 + DB 102,15,219,195 ; pand %xmm3,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,15,114,211,24 ; psrld $0x18,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_565_sse2 +_sk_load_565_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 243,15,126,20,120 ; movq (%rax,%rdi,2),%xmm2 + DB 102,15,239,192 ; pxor %xmm0,%xmm0 + DB 102,15,97,208 ; punpcklwd %xmm0,%xmm2 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,15,219,194 ; pand %xmm2,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 102,15,112,201,0 ; pshufd $0x0,%xmm1,%xmm1 + DB 102,15,219,202 ; pand %xmm2,%xmm1 + DB 15,91,217 ; cvtdq2ps %xmm1,%xmm3 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 15,89,203 ; mulps %xmm3,%xmm1 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,15,219,218 ; pand %xmm2,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,89,211 ; mulps %xmm3,%xmm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_565_sse2 +_sk_gather_565_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,112,217,245 ; pshufd $0xf5,%xmm1,%xmm3 + DB 102,15,244,218 ; pmuludq %xmm2,%xmm3 + DB 102,15,112,219,232 ; pshufd $0xe8,%xmm3,%xmm3 + DB 102,15,244,209 ; pmuludq %xmm1,%xmm2 + DB 102,15,112,202,232 ; pshufd $0xe8,%xmm2,%xmm1 + DB 102,15,98,203 ; punpckldq %xmm3,%xmm1 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,193 ; paddd %xmm1,%xmm0 + DB 102,15,112,200,78 ; pshufd $0x4e,%xmm0,%xmm1 + DB 102,72,15,126,200 ; movq %xmm1,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,67,15,196,20,81,0 ; pinsrw $0x0,(%r9,%r10,2),%xmm2 + DB 102,65,15,196,20,73,1 ; pinsrw $0x1,(%r9,%rcx,2),%xmm2 + DB 67,15,183,12,65 ; movzwl (%r9,%r8,2),%ecx + DB 102,15,196,209,2 ; pinsrw $0x2,%ecx,%xmm2 + DB 65,15,183,4,65 ; movzwl (%r9,%rax,2),%eax + DB 102,15,196,208,3 ; pinsrw $0x3,%eax,%xmm2 + DB 102,15,239,192 ; pxor %xmm0,%xmm0 + DB 102,15,97,208 ; punpcklwd %xmm0,%xmm2 + DB 184,0,248,0,0 ; mov $0xf800,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,15,219,194 ; pand %xmm2,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,8,33,132,55 ; mov $0x37842108,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,224,7,0,0 ; mov $0x7e0,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 102,15,112,201,0 ; pshufd $0x0,%xmm1,%xmm1 + DB 102,15,219,202 ; pand %xmm2,%xmm1 + DB 15,91,217 ; cvtdq2ps %xmm1,%xmm3 + DB 184,33,8,2,58 ; mov $0x3a020821,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 15,89,203 ; mulps %xmm3,%xmm1 + DB 184,31,0,0,0 ; mov $0x1f,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,15,219,218 ; pand %xmm2,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 184,8,33,4,61 ; mov $0x3d042108,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 15,89,211 ; mulps %xmm3,%xmm2 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_565_sse2 +_sk_store_565_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,0,248,65 ; mov $0x41f80000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,200 ; mulps %xmm0,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 102,65,15,114,241,11 ; pslld $0xb,%xmm9 + DB 185,0,0,124,66 ; mov $0x427c0000,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 102,69,15,91,210 ; cvtps2dq %xmm10,%xmm10 + DB 102,65,15,114,242,5 ; pslld $0x5,%xmm10 + DB 102,69,15,235,209 ; por %xmm9,%xmm10 + DB 68,15,89,194 ; mulps %xmm2,%xmm8 + DB 102,69,15,91,192 ; cvtps2dq %xmm8,%xmm8 + DB 102,69,15,86,194 ; orpd %xmm10,%xmm8 + DB 102,65,15,114,240,16 ; pslld $0x10,%xmm8 + DB 102,65,15,114,224,16 ; psrad $0x10,%xmm8 + DB 102,69,15,107,192 ; packssdw %xmm8,%xmm8 + DB 102,68,15,214,4,120 ; movq %xmm8,(%rax,%rdi,2) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_4444_sse2 +_sk_load_4444_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 243,68,15,126,12,120 ; movq (%rax,%rdi,2),%xmm9 + DB 102,15,239,192 ; pxor %xmm0,%xmm0 + DB 102,68,15,97,200 ; punpcklwd %xmm0,%xmm9 + DB 184,0,240,0,0 ; mov $0xf000,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,65,15,219,193 ; pand %xmm9,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,137,136,136,55 ; mov $0x37888889,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,0,15,0,0 ; mov $0xf00,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 102,15,112,201,0 ; pshufd $0x0,%xmm1,%xmm1 + DB 102,65,15,219,201 ; pand %xmm9,%xmm1 + DB 15,91,209 ; cvtdq2ps %xmm1,%xmm2 + DB 184,137,136,136,57 ; mov $0x39888889,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 15,89,202 ; mulps %xmm2,%xmm1 + DB 184,240,0,0,0 ; mov $0xf0,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,65,15,219,209 ; pand %xmm9,%xmm2 + DB 68,15,91,194 ; cvtdq2ps %xmm2,%xmm8 + DB 184,137,136,136,59 ; mov $0x3b888889,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 184,15,0,0,0 ; mov $0xf,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,65,15,219,217 ; pand %xmm9,%xmm3 + DB 68,15,91,195 ; cvtdq2ps %xmm3,%xmm8 + DB 184,137,136,136,61 ; mov $0x3d888889,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_4444_sse2 +_sk_gather_4444_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,112,217,245 ; pshufd $0xf5,%xmm1,%xmm3 + DB 102,15,244,218 ; pmuludq %xmm2,%xmm3 + DB 102,15,112,219,232 ; pshufd $0xe8,%xmm3,%xmm3 + DB 102,15,244,209 ; pmuludq %xmm1,%xmm2 + DB 102,15,112,202,232 ; pshufd $0xe8,%xmm2,%xmm1 + DB 102,15,98,203 ; punpckldq %xmm3,%xmm1 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,193 ; paddd %xmm1,%xmm0 + DB 102,15,112,200,78 ; pshufd $0x4e,%xmm0,%xmm1 + DB 102,72,15,126,200 ; movq %xmm1,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,71,15,196,12,81,0 ; pinsrw $0x0,(%r9,%r10,2),%xmm9 + DB 102,69,15,196,12,73,1 ; pinsrw $0x1,(%r9,%rcx,2),%xmm9 + DB 67,15,183,12,65 ; movzwl (%r9,%r8,2),%ecx + DB 102,68,15,196,201,2 ; pinsrw $0x2,%ecx,%xmm9 + DB 65,15,183,4,65 ; movzwl (%r9,%rax,2),%eax + DB 102,68,15,196,200,3 ; pinsrw $0x3,%eax,%xmm9 + DB 102,15,239,192 ; pxor %xmm0,%xmm0 + DB 102,68,15,97,200 ; punpcklwd %xmm0,%xmm9 + DB 184,0,240,0,0 ; mov $0xf000,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,65,15,219,193 ; pand %xmm9,%xmm0 + DB 15,91,200 ; cvtdq2ps %xmm0,%xmm1 + DB 184,137,136,136,55 ; mov $0x37888889,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 184,0,15,0,0 ; mov $0xf00,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 102,15,112,201,0 ; pshufd $0x0,%xmm1,%xmm1 + DB 102,65,15,219,201 ; pand %xmm9,%xmm1 + DB 15,91,209 ; cvtdq2ps %xmm1,%xmm2 + DB 184,137,136,136,57 ; mov $0x39888889,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 15,89,202 ; mulps %xmm2,%xmm1 + DB 184,240,0,0,0 ; mov $0xf0,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,65,15,219,209 ; pand %xmm9,%xmm2 + DB 68,15,91,194 ; cvtdq2ps %xmm2,%xmm8 + DB 184,137,136,136,59 ; mov $0x3b888889,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 184,15,0,0,0 ; mov $0xf,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 102,15,112,219,0 ; pshufd $0x0,%xmm3,%xmm3 + DB 102,65,15,219,217 ; pand %xmm9,%xmm3 + DB 68,15,91,195 ; cvtdq2ps %xmm3,%xmm8 + DB 184,137,136,136,61 ; mov $0x3d888889,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_4444_sse2 +_sk_store_4444_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,0,112,65 ; mov $0x41700000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,200 ; mulps %xmm0,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 102,65,15,114,241,12 ; pslld $0xc,%xmm9 + DB 69,15,40,208 ; movaps %xmm8,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 102,69,15,91,210 ; cvtps2dq %xmm10,%xmm10 + DB 102,65,15,114,242,8 ; pslld $0x8,%xmm10 + DB 102,69,15,235,209 ; por %xmm9,%xmm10 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 102,65,15,114,241,4 ; pslld $0x4,%xmm9 + DB 68,15,89,195 ; mulps %xmm3,%xmm8 + DB 102,69,15,91,192 ; cvtps2dq %xmm8,%xmm8 + DB 102,69,15,86,193 ; orpd %xmm9,%xmm8 + DB 102,69,15,86,194 ; orpd %xmm10,%xmm8 + DB 102,65,15,114,240,16 ; pslld $0x10,%xmm8 + DB 102,65,15,114,224,16 ; psrad $0x10,%xmm8 + DB 102,69,15,107,192 ; packssdw %xmm8,%xmm8 + DB 102,68,15,214,4,120 ; movq %xmm8,(%rax,%rdi,2) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_8888_sse2 +_sk_load_8888_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 243,15,111,28,184 ; movdqu (%rax,%rdi,4),%xmm3 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,15,111,203 ; movdqa %xmm3,%xmm1 + DB 102,15,114,209,8 ; psrld $0x8,%xmm1 + DB 102,15,219,200 ; pand %xmm0,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,15,114,210,16 ; psrld $0x10,%xmm2 + DB 102,15,219,208 ; pand %xmm0,%xmm2 + DB 102,15,219,195 ; pand %xmm3,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,15,114,211,24 ; psrld $0x18,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_8888_sse2 +_sk_gather_8888_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,112,217,245 ; pshufd $0xf5,%xmm1,%xmm3 + DB 102,15,244,218 ; pmuludq %xmm2,%xmm3 + DB 102,15,112,219,232 ; pshufd $0xe8,%xmm3,%xmm3 + DB 102,15,244,209 ; pmuludq %xmm1,%xmm2 + DB 102,15,112,202,232 ; pshufd $0xe8,%xmm2,%xmm1 + DB 102,15,98,203 ; punpckldq %xmm3,%xmm1 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,193 ; paddd %xmm1,%xmm0 + DB 102,15,112,200,78 ; pshufd $0x4e,%xmm0,%xmm1 + DB 102,72,15,126,200 ; movq %xmm1,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 102,65,15,110,4,137 ; movd (%r9,%rcx,4),%xmm0 + DB 102,65,15,110,12,129 ; movd (%r9,%rax,4),%xmm1 + DB 102,15,98,193 ; punpckldq %xmm1,%xmm0 + DB 102,67,15,110,28,145 ; movd (%r9,%r10,4),%xmm3 + DB 102,67,15,110,12,129 ; movd (%r9,%r8,4),%xmm1 + DB 102,15,98,217 ; punpckldq %xmm1,%xmm3 + DB 102,15,98,216 ; punpckldq %xmm0,%xmm3 + DB 184,255,0,0,0 ; mov $0xff,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,192,0 ; pshufd $0x0,%xmm0,%xmm0 + DB 102,15,111,203 ; movdqa %xmm3,%xmm1 + DB 102,15,114,209,8 ; psrld $0x8,%xmm1 + DB 102,15,219,200 ; pand %xmm0,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,15,114,210,16 ; psrld $0x10,%xmm2 + DB 102,15,219,208 ; pand %xmm0,%xmm2 + DB 102,15,219,195 ; pand %xmm3,%xmm0 + DB 15,91,192 ; cvtdq2ps %xmm0,%xmm0 + DB 184,129,128,128,59 ; mov $0x3b808081,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,91,201 ; cvtdq2ps %xmm1,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,15,114,211,24 ; psrld $0x18,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_8888_sse2 +_sk_store_8888_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,0,127,67 ; mov $0x437f0000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,200 ; mulps %xmm0,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 69,15,40,208 ; movaps %xmm8,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 102,69,15,91,210 ; cvtps2dq %xmm10,%xmm10 + DB 102,65,15,114,242,8 ; pslld $0x8,%xmm10 + DB 102,69,15,235,209 ; por %xmm9,%xmm10 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,89,202 ; mulps %xmm2,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 102,65,15,114,241,16 ; pslld $0x10,%xmm9 + DB 68,15,89,195 ; mulps %xmm3,%xmm8 + DB 102,69,15,91,192 ; cvtps2dq %xmm8,%xmm8 + DB 102,65,15,114,240,24 ; pslld $0x18,%xmm8 + DB 102,69,15,235,193 ; por %xmm9,%xmm8 + DB 102,69,15,235,194 ; por %xmm10,%xmm8 + DB 243,68,15,127,4,184 ; movdqu %xmm8,(%rax,%rdi,4) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_f16_sse2 +_sk_load_f16_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 243,15,111,4,248 ; movdqu (%rax,%rdi,8),%xmm0 + DB 243,15,111,76,248,16 ; movdqu 0x10(%rax,%rdi,8),%xmm1 + DB 102,68,15,111,192 ; movdqa %xmm0,%xmm8 + DB 102,68,15,97,193 ; punpcklwd %xmm1,%xmm8 + DB 102,15,105,193 ; punpckhwd %xmm1,%xmm0 + DB 102,65,15,111,200 ; movdqa %xmm8,%xmm1 + DB 102,15,97,200 ; punpcklwd %xmm0,%xmm1 + DB 102,68,15,105,192 ; punpckhwd %xmm0,%xmm8 + DB 184,0,4,0,4 ; mov $0x4000400,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,216,0 ; pshufd $0x0,%xmm0,%xmm3 + DB 102,15,111,195 ; movdqa %xmm3,%xmm0 + DB 102,15,101,193 ; pcmpgtw %xmm1,%xmm0 + DB 102,15,223,193 ; pandn %xmm1,%xmm0 + DB 102,69,15,239,201 ; pxor %xmm9,%xmm9 + DB 102,65,15,97,193 ; punpcklwd %xmm9,%xmm0 + DB 102,15,114,240,13 ; pslld $0xd,%xmm0 + DB 184,0,0,128,119 ; mov $0x77800000,%eax + DB 102,15,110,208 ; movd %eax,%xmm2 + DB 102,68,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm10 + DB 65,15,89,194 ; mulps %xmm10,%xmm0 + DB 102,15,112,209,78 ; pshufd $0x4e,%xmm1,%xmm2 + DB 102,15,111,203 ; movdqa %xmm3,%xmm1 + DB 102,15,101,202 ; pcmpgtw %xmm2,%xmm1 + DB 102,15,223,202 ; pandn %xmm2,%xmm1 + DB 102,65,15,97,201 ; punpcklwd %xmm9,%xmm1 + DB 102,15,114,241,13 ; pslld $0xd,%xmm1 + DB 65,15,89,202 ; mulps %xmm10,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,65,15,101,208 ; pcmpgtw %xmm8,%xmm2 + DB 102,65,15,223,208 ; pandn %xmm8,%xmm2 + DB 102,65,15,97,209 ; punpcklwd %xmm9,%xmm2 + DB 102,15,114,242,13 ; pslld $0xd,%xmm2 + DB 65,15,89,210 ; mulps %xmm10,%xmm2 + DB 102,69,15,112,192,78 ; pshufd $0x4e,%xmm8,%xmm8 + DB 102,65,15,101,216 ; pcmpgtw %xmm8,%xmm3 + DB 102,65,15,223,216 ; pandn %xmm8,%xmm3 + DB 102,65,15,97,217 ; punpcklwd %xmm9,%xmm3 + DB 102,15,114,243,13 ; pslld $0xd,%xmm3 + DB 65,15,89,218 ; mulps %xmm10,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_gather_f16_sse2 +_sk_gather_f16_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 76,139,8 ; mov (%rax),%r9 + DB 243,15,91,201 ; cvttps2dq %xmm1,%xmm1 + DB 102,15,110,80,16 ; movd 0x10(%rax),%xmm2 + DB 102,15,112,210,0 ; pshufd $0x0,%xmm2,%xmm2 + DB 102,15,112,217,245 ; pshufd $0xf5,%xmm1,%xmm3 + DB 102,15,244,218 ; pmuludq %xmm2,%xmm3 + DB 102,15,112,219,232 ; pshufd $0xe8,%xmm3,%xmm3 + DB 102,15,244,209 ; pmuludq %xmm1,%xmm2 + DB 102,15,112,202,232 ; pshufd $0xe8,%xmm2,%xmm1 + DB 102,15,98,203 ; punpckldq %xmm3,%xmm1 + DB 243,15,91,192 ; cvttps2dq %xmm0,%xmm0 + DB 102,15,254,193 ; paddd %xmm1,%xmm0 + DB 102,15,112,200,78 ; pshufd $0x4e,%xmm0,%xmm1 + DB 102,72,15,126,200 ; movq %xmm1,%rax + DB 65,137,192 ; mov %eax,%r8d + DB 72,193,232,32 ; shr $0x20,%rax + DB 102,72,15,126,193 ; movq %xmm0,%rcx + DB 65,137,202 ; mov %ecx,%r10d + DB 72,193,233,32 ; shr $0x20,%rcx + DB 243,65,15,126,4,201 ; movq (%r9,%rcx,8),%xmm0 + DB 243,67,15,126,12,209 ; movq (%r9,%r10,8),%xmm1 + DB 102,15,108,200 ; punpcklqdq %xmm0,%xmm1 + DB 243,65,15,126,4,193 ; movq (%r9,%rax,8),%xmm0 + DB 243,67,15,126,20,193 ; movq (%r9,%r8,8),%xmm2 + DB 102,15,108,208 ; punpcklqdq %xmm0,%xmm2 + DB 102,68,15,111,193 ; movdqa %xmm1,%xmm8 + DB 102,68,15,97,194 ; punpcklwd %xmm2,%xmm8 + DB 102,15,105,202 ; punpckhwd %xmm2,%xmm1 + DB 102,65,15,111,208 ; movdqa %xmm8,%xmm2 + DB 102,15,97,209 ; punpcklwd %xmm1,%xmm2 + DB 102,68,15,105,193 ; punpckhwd %xmm1,%xmm8 + DB 184,0,4,0,4 ; mov $0x4000400,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 102,15,112,216,0 ; pshufd $0x0,%xmm0,%xmm3 + DB 102,15,111,195 ; movdqa %xmm3,%xmm0 + DB 102,15,101,194 ; pcmpgtw %xmm2,%xmm0 + DB 102,15,223,194 ; pandn %xmm2,%xmm0 + DB 102,69,15,239,201 ; pxor %xmm9,%xmm9 + DB 102,65,15,97,193 ; punpcklwd %xmm9,%xmm0 + DB 102,15,114,240,13 ; pslld $0xd,%xmm0 + DB 184,0,0,128,119 ; mov $0x77800000,%eax + DB 102,15,110,200 ; movd %eax,%xmm1 + DB 102,68,15,112,209,0 ; pshufd $0x0,%xmm1,%xmm10 + DB 65,15,89,194 ; mulps %xmm10,%xmm0 + DB 102,15,112,210,78 ; pshufd $0x4e,%xmm2,%xmm2 + DB 102,15,111,203 ; movdqa %xmm3,%xmm1 + DB 102,15,101,202 ; pcmpgtw %xmm2,%xmm1 + DB 102,15,223,202 ; pandn %xmm2,%xmm1 + DB 102,65,15,97,201 ; punpcklwd %xmm9,%xmm1 + DB 102,15,114,241,13 ; pslld $0xd,%xmm1 + DB 65,15,89,202 ; mulps %xmm10,%xmm1 + DB 102,15,111,211 ; movdqa %xmm3,%xmm2 + DB 102,65,15,101,208 ; pcmpgtw %xmm8,%xmm2 + DB 102,65,15,223,208 ; pandn %xmm8,%xmm2 + DB 102,65,15,97,209 ; punpcklwd %xmm9,%xmm2 + DB 102,15,114,242,13 ; pslld $0xd,%xmm2 + DB 65,15,89,210 ; mulps %xmm10,%xmm2 + DB 102,69,15,112,192,78 ; pshufd $0x4e,%xmm8,%xmm8 + DB 102,65,15,101,216 ; pcmpgtw %xmm8,%xmm3 + DB 102,65,15,223,216 ; pandn %xmm8,%xmm3 + DB 102,65,15,97,217 ; punpcklwd %xmm9,%xmm3 + DB 102,15,114,243,13 ; pslld $0xd,%xmm3 + DB 65,15,89,218 ; mulps %xmm10,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_f16_sse2 +_sk_store_f16_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,0,128,7 ; mov $0x7800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 102,69,15,112,200,0 ; pshufd $0x0,%xmm8,%xmm9 + DB 102,69,15,111,193 ; movdqa %xmm9,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 102,65,15,114,208,13 ; psrld $0xd,%xmm8 + DB 102,65,15,114,240,16 ; pslld $0x10,%xmm8 + DB 102,65,15,114,224,16 ; psrad $0x10,%xmm8 + DB 102,69,15,107,192 ; packssdw %xmm8,%xmm8 + DB 102,69,15,111,209 ; movdqa %xmm9,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 102,65,15,114,210,13 ; psrld $0xd,%xmm10 + DB 102,65,15,114,242,16 ; pslld $0x10,%xmm10 + DB 102,65,15,114,226,16 ; psrad $0x10,%xmm10 + DB 102,69,15,107,210 ; packssdw %xmm10,%xmm10 + DB 102,69,15,111,217 ; movdqa %xmm9,%xmm11 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 102,65,15,114,211,13 ; psrld $0xd,%xmm11 + DB 102,65,15,114,243,16 ; pslld $0x10,%xmm11 + DB 102,65,15,114,227,16 ; psrad $0x10,%xmm11 + DB 102,69,15,107,219 ; packssdw %xmm11,%xmm11 + DB 68,15,89,203 ; mulps %xmm3,%xmm9 + DB 102,65,15,114,209,13 ; psrld $0xd,%xmm9 + DB 102,65,15,114,241,16 ; pslld $0x10,%xmm9 + DB 102,65,15,114,225,16 ; psrad $0x10,%xmm9 + DB 102,69,15,107,201 ; packssdw %xmm9,%xmm9 + DB 102,69,15,97,194 ; punpcklwd %xmm10,%xmm8 + DB 102,69,15,97,217 ; punpcklwd %xmm9,%xmm11 + DB 102,69,15,111,200 ; movdqa %xmm8,%xmm9 + DB 102,69,15,98,203 ; punpckldq %xmm11,%xmm9 + DB 243,68,15,127,12,248 ; movdqu %xmm9,(%rax,%rdi,8) + DB 102,69,15,106,195 ; punpckhdq %xmm11,%xmm8 + DB 243,68,15,127,68,248,16 ; movdqu %xmm8,0x10(%rax,%rdi,8) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_u16_be_sse2 +_sk_load_u16_be_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 243,15,111,4,248 ; movdqu (%rax,%rdi,8),%xmm0 + DB 243,15,111,76,248,16 ; movdqu 0x10(%rax,%rdi,8),%xmm1 + DB 102,15,111,208 ; movdqa %xmm0,%xmm2 + DB 102,15,97,209 ; punpcklwd %xmm1,%xmm2 + DB 102,15,105,193 ; punpckhwd %xmm1,%xmm0 + DB 102,15,111,202 ; movdqa %xmm2,%xmm1 + DB 102,15,97,200 ; punpcklwd %xmm0,%xmm1 + DB 102,15,105,208 ; punpckhwd %xmm0,%xmm2 + DB 184,128,0,128,55 ; mov $0x37800080,%eax + DB 102,68,15,110,192 ; movd %eax,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 102,15,111,193 ; movdqa %xmm1,%xmm0 + DB 102,15,113,240,8 ; psllw $0x8,%xmm0 + DB 102,15,112,217,78 ; pshufd $0x4e,%xmm1,%xmm3 + DB 102,15,113,209,8 ; psrlw $0x8,%xmm1 + DB 102,15,235,200 ; por %xmm0,%xmm1 + DB 102,69,15,239,201 ; pxor %xmm9,%xmm9 + DB 102,65,15,97,201 ; punpcklwd %xmm9,%xmm1 + DB 15,91,193 ; cvtdq2ps %xmm1,%xmm0 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 102,15,111,203 ; movdqa %xmm3,%xmm1 + DB 102,15,113,241,8 ; psllw $0x8,%xmm1 + DB 102,15,113,211,8 ; psrlw $0x8,%xmm3 + DB 102,15,235,217 ; por %xmm1,%xmm3 + DB 102,65,15,97,217 ; punpcklwd %xmm9,%xmm3 + DB 15,91,203 ; cvtdq2ps %xmm3,%xmm1 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 102,68,15,111,210 ; movdqa %xmm2,%xmm10 + DB 102,65,15,113,242,8 ; psllw $0x8,%xmm10 + DB 102,15,112,218,78 ; pshufd $0x4e,%xmm2,%xmm3 + DB 102,15,113,210,8 ; psrlw $0x8,%xmm2 + DB 102,65,15,235,210 ; por %xmm10,%xmm2 + DB 102,65,15,97,209 ; punpcklwd %xmm9,%xmm2 + DB 15,91,210 ; cvtdq2ps %xmm2,%xmm2 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 102,68,15,111,211 ; movdqa %xmm3,%xmm10 + DB 102,65,15,113,242,8 ; psllw $0x8,%xmm10 + DB 102,15,113,211,8 ; psrlw $0x8,%xmm3 + DB 102,65,15,235,218 ; por %xmm10,%xmm3 + DB 102,65,15,97,217 ; punpcklwd %xmm9,%xmm3 + DB 15,91,219 ; cvtdq2ps %xmm3,%xmm3 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_u16_be_sse2 +_sk_store_u16_be_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 185,0,255,127,71 ; mov $0x477fff00,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 102,69,15,91,192 ; cvtps2dq %xmm8,%xmm8 + DB 102,65,15,114,240,16 ; pslld $0x10,%xmm8 + DB 102,65,15,114,224,16 ; psrad $0x10,%xmm8 + DB 102,69,15,107,192 ; packssdw %xmm8,%xmm8 + DB 102,69,15,111,208 ; movdqa %xmm8,%xmm10 + DB 102,65,15,113,242,8 ; psllw $0x8,%xmm10 + DB 102,65,15,113,208,8 ; psrlw $0x8,%xmm8 + DB 102,69,15,235,194 ; por %xmm10,%xmm8 + DB 69,15,40,209 ; movaps %xmm9,%xmm10 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 102,69,15,91,210 ; cvtps2dq %xmm10,%xmm10 + DB 102,65,15,114,242,16 ; pslld $0x10,%xmm10 + DB 102,65,15,114,226,16 ; psrad $0x10,%xmm10 + DB 102,69,15,107,210 ; packssdw %xmm10,%xmm10 + DB 102,69,15,111,218 ; movdqa %xmm10,%xmm11 + DB 102,65,15,113,243,8 ; psllw $0x8,%xmm11 + DB 102,65,15,113,210,8 ; psrlw $0x8,%xmm10 + DB 102,69,15,235,211 ; por %xmm11,%xmm10 + DB 69,15,40,217 ; movaps %xmm9,%xmm11 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 102,69,15,91,219 ; cvtps2dq %xmm11,%xmm11 + DB 102,65,15,114,243,16 ; pslld $0x10,%xmm11 + DB 102,65,15,114,227,16 ; psrad $0x10,%xmm11 + DB 102,69,15,107,219 ; packssdw %xmm11,%xmm11 + DB 102,69,15,111,227 ; movdqa %xmm11,%xmm12 + DB 102,65,15,113,244,8 ; psllw $0x8,%xmm12 + DB 102,65,15,113,211,8 ; psrlw $0x8,%xmm11 + DB 102,69,15,235,220 ; por %xmm12,%xmm11 + DB 68,15,89,203 ; mulps %xmm3,%xmm9 + DB 102,69,15,91,201 ; cvtps2dq %xmm9,%xmm9 + DB 102,65,15,114,241,16 ; pslld $0x10,%xmm9 + DB 102,65,15,114,225,16 ; psrad $0x10,%xmm9 + DB 102,69,15,107,201 ; packssdw %xmm9,%xmm9 + DB 102,69,15,111,225 ; movdqa %xmm9,%xmm12 + DB 102,65,15,113,244,8 ; psllw $0x8,%xmm12 + DB 102,65,15,113,209,8 ; psrlw $0x8,%xmm9 + DB 102,69,15,235,204 ; por %xmm12,%xmm9 + DB 102,69,15,97,194 ; punpcklwd %xmm10,%xmm8 + DB 102,69,15,97,217 ; punpcklwd %xmm9,%xmm11 + DB 102,69,15,111,200 ; movdqa %xmm8,%xmm9 + DB 102,69,15,98,203 ; punpckldq %xmm11,%xmm9 + DB 243,68,15,127,12,248 ; movdqu %xmm9,(%rax,%rdi,8) + DB 102,69,15,106,195 ; punpckhdq %xmm11,%xmm8 + DB 243,68,15,127,68,248,16 ; movdqu %xmm8,0x10(%rax,%rdi,8) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_load_f32_sse2 +_sk_load_f32_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,137,249 ; mov %rdi,%rcx + DB 72,193,225,4 ; shl $0x4,%rcx + DB 68,15,16,4,8 ; movups (%rax,%rcx,1),%xmm8 + DB 15,16,68,8,16 ; movups 0x10(%rax,%rcx,1),%xmm0 + DB 15,16,92,8,32 ; movups 0x20(%rax,%rcx,1),%xmm3 + DB 68,15,16,76,8,48 ; movups 0x30(%rax,%rcx,1),%xmm9 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 15,20,208 ; unpcklps %xmm0,%xmm2 + DB 15,40,203 ; movaps %xmm3,%xmm1 + DB 65,15,20,201 ; unpcklps %xmm9,%xmm1 + DB 68,15,21,192 ; unpckhps %xmm0,%xmm8 + DB 65,15,21,217 ; unpckhps %xmm9,%xmm3 + DB 15,40,194 ; movaps %xmm2,%xmm0 + DB 102,15,20,193 ; unpcklpd %xmm1,%xmm0 + DB 15,18,202 ; movhlps %xmm2,%xmm1 + DB 65,15,40,208 ; movaps %xmm8,%xmm2 + DB 102,15,20,211 ; unpcklpd %xmm3,%xmm2 + DB 65,15,18,216 ; movhlps %xmm8,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_store_f32_sse2 +_sk_store_f32_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 72,139,0 ; mov (%rax),%rax + DB 72,137,249 ; mov %rdi,%rcx + DB 72,193,225,4 ; shl $0x4,%rcx + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 68,15,20,201 ; unpcklps %xmm1,%xmm9 + DB 68,15,40,210 ; movaps %xmm2,%xmm10 + DB 68,15,40,218 ; movaps %xmm2,%xmm11 + DB 68,15,20,219 ; unpcklps %xmm3,%xmm11 + DB 68,15,21,193 ; unpckhps %xmm1,%xmm8 + DB 68,15,21,211 ; unpckhps %xmm3,%xmm10 + DB 69,15,40,225 ; movaps %xmm9,%xmm12 + DB 102,69,15,20,227 ; unpcklpd %xmm11,%xmm12 + DB 69,15,18,217 ; movhlps %xmm9,%xmm11 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 102,69,15,20,202 ; unpcklpd %xmm10,%xmm9 + DB 69,15,18,208 ; movhlps %xmm8,%xmm10 + DB 102,68,15,17,36,8 ; movupd %xmm12,(%rax,%rcx,1) + DB 68,15,17,92,8,16 ; movups %xmm11,0x10(%rax,%rcx,1) + DB 102,68,15,17,76,8,32 ; movupd %xmm9,0x20(%rax,%rcx,1) + DB 68,15,17,84,8,48 ; movups %xmm10,0x30(%rax,%rcx,1) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_x_sse2 +_sk_clamp_x_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 68,15,95,192 ; maxps %xmm0,%xmm8 + DB 243,68,15,16,8 ; movss (%rax),%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 102,15,118,192 ; pcmpeqd %xmm0,%xmm0 + DB 102,65,15,254,193 ; paddd %xmm9,%xmm0 + DB 68,15,93,192 ; minps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_clamp_y_sse2 +_sk_clamp_y_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 68,15,95,193 ; maxps %xmm1,%xmm8 + DB 243,68,15,16,8 ; movss (%rax),%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 102,15,118,201 ; pcmpeqd %xmm1,%xmm1 + DB 102,65,15,254,201 ; paddd %xmm9,%xmm1 + DB 68,15,93,193 ; minps %xmm1,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,200 ; movaps %xmm8,%xmm1 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_repeat_x_sse2 +_sk_repeat_x_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,0 ; movss (%rax),%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,40,200 ; movaps %xmm0,%xmm9 + DB 69,15,94,200 ; divps %xmm8,%xmm9 + DB 243,69,15,91,209 ; cvttps2dq %xmm9,%xmm10 + DB 69,15,91,210 ; cvtdq2ps %xmm10,%xmm10 + DB 69,15,194,202,1 ; cmpltps %xmm10,%xmm9 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,216 ; movd %eax,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,84,217 ; andps %xmm9,%xmm11 + DB 69,15,92,211 ; subps %xmm11,%xmm10 + DB 69,15,89,208 ; mulps %xmm8,%xmm10 + DB 65,15,92,194 ; subps %xmm10,%xmm0 + DB 102,69,15,118,201 ; pcmpeqd %xmm9,%xmm9 + DB 102,69,15,254,200 ; paddd %xmm8,%xmm9 + DB 65,15,93,193 ; minps %xmm9,%xmm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_repeat_y_sse2 +_sk_repeat_y_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,0 ; movss (%rax),%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 69,15,94,200 ; divps %xmm8,%xmm9 + DB 243,69,15,91,209 ; cvttps2dq %xmm9,%xmm10 + DB 69,15,91,210 ; cvtdq2ps %xmm10,%xmm10 + DB 69,15,194,202,1 ; cmpltps %xmm10,%xmm9 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,216 ; movd %eax,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,84,217 ; andps %xmm9,%xmm11 + DB 69,15,92,211 ; subps %xmm11,%xmm10 + DB 69,15,89,208 ; mulps %xmm8,%xmm10 + DB 65,15,92,202 ; subps %xmm10,%xmm1 + DB 102,69,15,118,201 ; pcmpeqd %xmm9,%xmm9 + DB 102,69,15,254,200 ; paddd %xmm8,%xmm9 + DB 65,15,93,201 ; minps %xmm9,%xmm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_mirror_x_sse2 +_sk_mirror_x_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,8 ; movss (%rax),%xmm9 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,92,192 ; subps %xmm8,%xmm0 + DB 243,69,15,88,201 ; addss %xmm9,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 68,15,40,208 ; movaps %xmm0,%xmm10 + DB 69,15,94,209 ; divps %xmm9,%xmm10 + DB 243,69,15,91,218 ; cvttps2dq %xmm10,%xmm11 + DB 69,15,91,219 ; cvtdq2ps %xmm11,%xmm11 + DB 69,15,194,211,1 ; cmpltps %xmm11,%xmm10 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,224 ; movd %eax,%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 69,15,84,226 ; andps %xmm10,%xmm12 + DB 69,15,87,210 ; xorps %xmm10,%xmm10 + DB 69,15,92,220 ; subps %xmm12,%xmm11 + DB 69,15,89,217 ; mulps %xmm9,%xmm11 + DB 65,15,92,195 ; subps %xmm11,%xmm0 + DB 65,15,92,192 ; subps %xmm8,%xmm0 + DB 68,15,92,208 ; subps %xmm0,%xmm10 + DB 65,15,84,194 ; andps %xmm10,%xmm0 + DB 102,69,15,118,201 ; pcmpeqd %xmm9,%xmm9 + DB 102,69,15,254,200 ; paddd %xmm8,%xmm9 + DB 65,15,93,193 ; minps %xmm9,%xmm0 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_mirror_y_sse2 +_sk_mirror_y_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,8 ; movss (%rax),%xmm9 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 243,69,15,88,201 ; addss %xmm9,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 68,15,40,209 ; movaps %xmm1,%xmm10 + DB 69,15,94,209 ; divps %xmm9,%xmm10 + DB 243,69,15,91,218 ; cvttps2dq %xmm10,%xmm11 + DB 69,15,91,219 ; cvtdq2ps %xmm11,%xmm11 + DB 69,15,194,211,1 ; cmpltps %xmm11,%xmm10 + DB 184,0,0,128,63 ; mov $0x3f800000,%eax + DB 102,68,15,110,224 ; movd %eax,%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 69,15,84,226 ; andps %xmm10,%xmm12 + DB 69,15,87,210 ; xorps %xmm10,%xmm10 + DB 69,15,92,220 ; subps %xmm12,%xmm11 + DB 69,15,89,217 ; mulps %xmm9,%xmm11 + DB 65,15,92,203 ; subps %xmm11,%xmm1 + DB 65,15,92,200 ; subps %xmm8,%xmm1 + DB 68,15,92,209 ; subps %xmm1,%xmm10 + DB 65,15,84,202 ; andps %xmm10,%xmm1 + DB 102,69,15,118,201 ; pcmpeqd %xmm9,%xmm9 + DB 102,69,15,254,200 ; paddd %xmm8,%xmm9 + DB 65,15,93,201 ; minps %xmm9,%xmm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_luminance_to_alpha_sse2 +_sk_luminance_to_alpha_sse2 LABEL PROC + DB 184,208,179,89,62 ; mov $0x3e59b3d0,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 15,89,216 ; mulps %xmm0,%xmm3 + DB 184,89,23,55,63 ; mov $0x3f371759,%eax + DB 102,15,110,192 ; movd %eax,%xmm0 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 15,88,195 ; addps %xmm3,%xmm0 + DB 184,152,221,147,61 ; mov $0x3d93dd98,%eax + DB 102,15,110,216 ; movd %eax,%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 15,89,218 ; mulps %xmm2,%xmm3 + DB 15,88,216 ; addps %xmm0,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 15,87,192 ; xorps %xmm0,%xmm0 + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_2x3_sse2 +_sk_matrix_2x3_sse2 LABEL PROC + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 243,68,15,16,80,8 ; movss 0x8(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,16 ; movss 0x10(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,88,194 ; addps %xmm10,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,68,15,16,80,12 ; movss 0xc(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,20 ; movss 0x14(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,88,202 ; addps %xmm10,%xmm1 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_3x4_sse2 +_sk_matrix_3x4_sse2 LABEL PROC + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 243,68,15,16,80,12 ; movss 0xc(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,24 ; movss 0x18(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,36 ; movss 0x24(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,88,194 ; addps %xmm10,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,68,15,16,80,16 ; movss 0x10(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,28 ; movss 0x1c(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,40 ; movss 0x28(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,88,202 ; addps %xmm10,%xmm1 + DB 243,68,15,16,80,8 ; movss 0x8(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,20 ; movss 0x14(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,32 ; movss 0x20(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,44 ; movss 0x2c(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 68,15,89,226 ; mulps %xmm2,%xmm12 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 69,15,89,217 ; mulps %xmm9,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,208 ; mulps %xmm8,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_4x5_sse2 +_sk_matrix_4x5_sse2 LABEL PROC + DB 68,15,40,201 ; movaps %xmm1,%xmm9 + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 243,68,15,16,80,16 ; movss 0x10(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,32 ; movss 0x20(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,48 ; movss 0x30(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,64 ; movss 0x40(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 68,15,89,227 ; mulps %xmm3,%xmm12 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,88,194 ; addps %xmm10,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,68,15,16,80,20 ; movss 0x14(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,36 ; movss 0x24(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,52 ; movss 0x34(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,68 ; movss 0x44(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 68,15,89,227 ; mulps %xmm3,%xmm12 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 68,15,89,218 ; mulps %xmm2,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 65,15,88,202 ; addps %xmm10,%xmm1 + DB 243,68,15,16,80,8 ; movss 0x8(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,24 ; movss 0x18(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,40 ; movss 0x28(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,56 ; movss 0x38(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 243,68,15,16,112,72 ; movss 0x48(%rax),%xmm14 + DB 69,15,198,246,0 ; shufps $0x0,%xmm14,%xmm14 + DB 68,15,89,235 ; mulps %xmm3,%xmm13 + DB 69,15,88,238 ; addps %xmm14,%xmm13 + DB 68,15,89,226 ; mulps %xmm2,%xmm12 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 69,15,89,217 ; mulps %xmm9,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,208 ; mulps %xmm8,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 243,68,15,16,88,12 ; movss 0xc(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,28 ; movss 0x1c(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 243,68,15,16,104,44 ; movss 0x2c(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 243,68,15,16,112,60 ; movss 0x3c(%rax),%xmm14 + DB 69,15,198,246,0 ; shufps $0x0,%xmm14,%xmm14 + DB 243,68,15,16,120,76 ; movss 0x4c(%rax),%xmm15 + DB 69,15,198,255,0 ; shufps $0x0,%xmm15,%xmm15 + DB 68,15,89,243 ; mulps %xmm3,%xmm14 + DB 69,15,88,247 ; addps %xmm15,%xmm14 + DB 68,15,89,234 ; mulps %xmm2,%xmm13 + DB 69,15,88,238 ; addps %xmm14,%xmm13 + DB 69,15,89,225 ; mulps %xmm9,%xmm12 + DB 69,15,88,229 ; addps %xmm13,%xmm12 + DB 69,15,89,216 ; mulps %xmm8,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,210 ; movaps %xmm10,%xmm2 + DB 65,15,40,219 ; movaps %xmm11,%xmm3 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_matrix_perspective_sse2 +_sk_matrix_perspective_sse2 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,68,15,16,72,4 ; movss 0x4(%rax),%xmm9 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 243,68,15,16,80,8 ; movss 0x8(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 68,15,89,201 ; mulps %xmm1,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 65,15,88,193 ; addps %xmm9,%xmm0 + DB 243,68,15,16,72,12 ; movss 0xc(%rax),%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 243,68,15,16,80,16 ; movss 0x10(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,20 ; movss 0x14(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 68,15,89,209 ; mulps %xmm1,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 243,68,15,16,80,24 ; movss 0x18(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,28 ; movss 0x1c(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,32 ; movss 0x20(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 68,15,89,217 ; mulps %xmm1,%xmm11 + DB 69,15,88,220 ; addps %xmm12,%xmm11 + DB 69,15,89,208 ; mulps %xmm8,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 65,15,83,202 ; rcpps %xmm10,%xmm1 + DB 15,89,193 ; mulps %xmm1,%xmm0 + DB 68,15,89,201 ; mulps %xmm1,%xmm9 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,201 ; movaps %xmm9,%xmm1 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_linear_gradient_sse2 +_sk_linear_gradient_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,68,15,16,72,16 ; movss 0x10(%rax),%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 243,68,15,16,80,20 ; movss 0x14(%rax),%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 243,68,15,16,88,24 ; movss 0x18(%rax),%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 243,68,15,16,96,28 ; movss 0x1c(%rax),%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 72,139,8 ; mov (%rax),%rcx + DB 72,133,201 ; test %rcx,%rcx + DB 15,132,15,1,0,0 ; je 3145 <_sk_linear_gradient_sse2+0x149> + DB 72,139,64,8 ; mov 0x8(%rax),%rax + DB 72,131,192,32 ; add $0x20,%rax + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 15,87,219 ; xorps %xmm3,%xmm3 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 243,68,15,16,112,224 ; movss -0x20(%rax),%xmm14 + DB 243,68,15,16,104,228 ; movss -0x1c(%rax),%xmm13 + DB 69,15,198,246,0 ; shufps $0x0,%xmm14,%xmm14 + DB 69,15,40,252 ; movaps %xmm12,%xmm15 + DB 68,15,40,224 ; movaps %xmm0,%xmm12 + DB 69,15,194,230,1 ; cmpltps %xmm14,%xmm12 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,40,244 ; movaps %xmm12,%xmm14 + DB 69,15,85,245 ; andnps %xmm13,%xmm14 + DB 69,15,84,196 ; andps %xmm12,%xmm8 + DB 69,15,86,198 ; orps %xmm14,%xmm8 + DB 243,68,15,16,104,232 ; movss -0x18(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,40,244 ; movaps %xmm12,%xmm14 + DB 69,15,85,245 ; andnps %xmm13,%xmm14 + DB 65,15,84,204 ; andps %xmm12,%xmm1 + DB 65,15,86,206 ; orps %xmm14,%xmm1 + DB 243,68,15,16,104,236 ; movss -0x14(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,40,244 ; movaps %xmm12,%xmm14 + DB 69,15,85,245 ; andnps %xmm13,%xmm14 + DB 65,15,84,212 ; andps %xmm12,%xmm2 + DB 65,15,86,214 ; orps %xmm14,%xmm2 + DB 243,68,15,16,104,240 ; movss -0x10(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,40,244 ; movaps %xmm12,%xmm14 + DB 69,15,85,245 ; andnps %xmm13,%xmm14 + DB 65,15,84,220 ; andps %xmm12,%xmm3 + DB 65,15,86,222 ; orps %xmm14,%xmm3 + DB 243,68,15,16,104,244 ; movss -0xc(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,40,244 ; movaps %xmm12,%xmm14 + DB 69,15,85,245 ; andnps %xmm13,%xmm14 + DB 69,15,84,204 ; andps %xmm12,%xmm9 + DB 69,15,86,206 ; orps %xmm14,%xmm9 + DB 243,68,15,16,104,248 ; movss -0x8(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,40,244 ; movaps %xmm12,%xmm14 + DB 69,15,85,245 ; andnps %xmm13,%xmm14 + DB 69,15,84,212 ; andps %xmm12,%xmm10 + DB 69,15,86,214 ; orps %xmm14,%xmm10 + DB 243,68,15,16,104,252 ; movss -0x4(%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,40,244 ; movaps %xmm12,%xmm14 + DB 69,15,85,245 ; andnps %xmm13,%xmm14 + DB 69,15,84,220 ; andps %xmm12,%xmm11 + DB 69,15,86,222 ; orps %xmm14,%xmm11 + DB 243,68,15,16,40 ; movss (%rax),%xmm13 + DB 69,15,198,237,0 ; shufps $0x0,%xmm13,%xmm13 + DB 69,15,84,252 ; andps %xmm12,%xmm15 + DB 69,15,85,229 ; andnps %xmm13,%xmm12 + DB 69,15,86,231 ; orps %xmm15,%xmm12 + DB 72,131,192,36 ; add $0x24,%rax + DB 72,255,201 ; dec %rcx + DB 15,133,8,255,255,255 ; jne 304b <_sk_linear_gradient_sse2+0x4f> + DB 235,13 ; jmp 3152 <_sk_linear_gradient_sse2+0x156> + DB 15,87,201 ; xorps %xmm1,%xmm1 + DB 15,87,210 ; xorps %xmm2,%xmm2 + DB 15,87,219 ; xorps %xmm3,%xmm3 + DB 69,15,87,192 ; xorps %xmm8,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 69,15,88,193 ; addps %xmm9,%xmm8 + DB 15,89,200 ; mulps %xmm0,%xmm1 + DB 65,15,88,202 ; addps %xmm10,%xmm1 + DB 15,89,208 ; mulps %xmm0,%xmm2 + DB 65,15,88,211 ; addps %xmm11,%xmm2 + DB 15,89,216 ; mulps %xmm0,%xmm3 + DB 65,15,88,220 ; addps %xmm12,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 65,15,40,192 ; movaps %xmm8,%xmm0 + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_linear_gradient_2stops_sse2 +_sk_linear_gradient_2stops_sse2 LABEL PROC + DB 68,15,40,192 ; movaps %xmm0,%xmm8 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 243,15,16,0 ; movss (%rax),%xmm0 + DB 243,15,16,72,4 ; movss 0x4(%rax),%xmm1 + DB 15,198,192,0 ; shufps $0x0,%xmm0,%xmm0 + DB 243,15,16,80,16 ; movss 0x10(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 65,15,89,192 ; mulps %xmm8,%xmm0 + DB 15,88,194 ; addps %xmm2,%xmm0 + DB 15,198,201,0 ; shufps $0x0,%xmm1,%xmm1 + DB 243,15,16,80,20 ; movss 0x14(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 65,15,89,200 ; mulps %xmm8,%xmm1 + DB 15,88,202 ; addps %xmm2,%xmm1 + DB 243,15,16,80,8 ; movss 0x8(%rax),%xmm2 + DB 15,198,210,0 ; shufps $0x0,%xmm2,%xmm2 + DB 243,15,16,88,24 ; movss 0x18(%rax),%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 65,15,89,208 ; mulps %xmm8,%xmm2 + DB 15,88,211 ; addps %xmm3,%xmm2 + DB 243,15,16,88,12 ; movss 0xc(%rax),%xmm3 + DB 15,198,219,0 ; shufps $0x0,%xmm3,%xmm3 + DB 243,68,15,16,72,28 ; movss 0x1c(%rax),%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 65,15,89,216 ; mulps %xmm8,%xmm3 + DB 65,15,88,217 ; addps %xmm9,%xmm3 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_save_xy_sse2 +_sk_save_xy_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,40,200 ; movaps %xmm8,%xmm9 + DB 68,15,88,200 ; addps %xmm0,%xmm9 + DB 243,69,15,91,209 ; cvttps2dq %xmm9,%xmm10 + DB 69,15,91,210 ; cvtdq2ps %xmm10,%xmm10 + DB 69,15,40,217 ; movaps %xmm9,%xmm11 + DB 69,15,194,218,1 ; cmpltps %xmm10,%xmm11 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,225 ; movd %ecx,%xmm12 + DB 69,15,198,228,0 ; shufps $0x0,%xmm12,%xmm12 + DB 69,15,84,220 ; andps %xmm12,%xmm11 + DB 69,15,92,211 ; subps %xmm11,%xmm10 + DB 69,15,92,202 ; subps %xmm10,%xmm9 + DB 68,15,88,193 ; addps %xmm1,%xmm8 + DB 243,69,15,91,208 ; cvttps2dq %xmm8,%xmm10 + DB 69,15,91,210 ; cvtdq2ps %xmm10,%xmm10 + DB 69,15,40,216 ; movaps %xmm8,%xmm11 + DB 69,15,194,218,1 ; cmpltps %xmm10,%xmm11 + DB 69,15,84,220 ; andps %xmm12,%xmm11 + DB 69,15,92,211 ; subps %xmm11,%xmm10 + DB 69,15,92,194 ; subps %xmm10,%xmm8 + DB 15,17,0 ; movups %xmm0,(%rax) + DB 15,17,72,32 ; movups %xmm1,0x20(%rax) + DB 68,15,17,72,64 ; movups %xmm9,0x40(%rax) + DB 68,15,17,64,96 ; movups %xmm8,0x60(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_accumulate_sse2 +_sk_accumulate_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 68,15,16,128,128,0,0,0 ; movups 0x80(%rax),%xmm8 + DB 68,15,16,136,160,0,0,0 ; movups 0xa0(%rax),%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 68,15,89,192 ; mulps %xmm0,%xmm8 + DB 65,15,88,224 ; addps %xmm8,%xmm4 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 68,15,89,193 ; mulps %xmm1,%xmm8 + DB 65,15,88,232 ; addps %xmm8,%xmm5 + DB 69,15,40,193 ; movaps %xmm9,%xmm8 + DB 68,15,89,194 ; mulps %xmm2,%xmm8 + DB 65,15,88,240 ; addps %xmm8,%xmm6 + DB 68,15,89,203 ; mulps %xmm3,%xmm9 + DB 65,15,88,249 ; addps %xmm9,%xmm7 + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_nx_sse2 +_sk_bilinear_nx_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,191 ; mov $0xbf000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 68,15,17,128,128,0,0,0 ; movups %xmm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_px_sse2 +_sk_bilinear_px_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 68,15,17,136,128,0,0,0 ; movups %xmm9,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_ny_sse2 +_sk_bilinear_ny_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,191 ; mov $0xbf000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 68,15,17,128,160,0,0,0 ; movups %xmm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bilinear_py_sse2 +_sk_bilinear_py_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 68,15,17,136,160,0,0,0 ; movups %xmm9,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n3x_sse2 +_sk_bicubic_n3x_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,192,191 ; mov $0xbfc00000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 185,114,28,199,62 ; mov $0x3ec71c72,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 185,171,170,170,190 ; mov $0xbeaaaaab,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,89,192 ; mulps %xmm8,%xmm8 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 68,15,17,136,128,0,0,0 ; movups %xmm9,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n1x_sse2 +_sk_bicubic_n1x_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,191 ; mov $0xbf000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 185,85,85,149,191 ; mov $0xbf955555,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 185,57,142,99,61 ; mov $0x3d638e39,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 68,15,17,136,128,0,0,0 ; movups %xmm9,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p1x_sse2 +_sk_bicubic_p1x_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 185,85,85,149,191 ; mov $0xbf955555,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,217 ; movd %ecx,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,208 ; addps %xmm8,%xmm10 + DB 185,57,142,99,61 ; mov $0x3d638e39,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,208 ; addps %xmm8,%xmm10 + DB 68,15,17,144,128,0,0,0 ; movups %xmm10,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p3x_sse2 +_sk_bicubic_p3x_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,0 ; movups (%rax),%xmm0 + DB 68,15,16,72,64 ; movups 0x40(%rax),%xmm9 + DB 65,15,88,192 ; addps %xmm8,%xmm0 + DB 185,114,28,199,62 ; mov $0x3ec71c72,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,89,193 ; mulps %xmm9,%xmm8 + DB 69,15,89,201 ; mulps %xmm9,%xmm9 + DB 185,171,170,170,190 ; mov $0xbeaaaaab,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,88,194 ; addps %xmm10,%xmm8 + DB 69,15,89,193 ; mulps %xmm9,%xmm8 + DB 68,15,17,128,128,0,0,0 ; movups %xmm8,0x80(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n3y_sse2 +_sk_bicubic_n3y_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,192,191 ; mov $0xbfc00000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 185,114,28,199,62 ; mov $0x3ec71c72,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 185,171,170,170,190 ; mov $0xbeaaaaab,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,89,192 ; mulps %xmm8,%xmm8 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 68,15,17,136,160,0,0,0 ; movups %xmm9,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_n1y_sse2 +_sk_bicubic_n1y_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,191 ; mov $0xbf000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 185,0,0,128,63 ; mov $0x3f800000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,92,193 ; subps %xmm9,%xmm8 + DB 185,85,85,149,191 ; mov $0xbf955555,%ecx + DB 102,68,15,110,201 ; movd %ecx,%xmm9 + DB 69,15,198,201,0 ; shufps $0x0,%xmm9,%xmm9 + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 185,57,142,99,61 ; mov $0x3d638e39,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,89,200 ; mulps %xmm8,%xmm9 + DB 69,15,88,202 ; addps %xmm10,%xmm9 + DB 68,15,17,136,160,0,0,0 ; movups %xmm9,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p1y_sse2 +_sk_bicubic_p1y_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,0,63 ; mov $0x3f000000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 185,85,85,149,191 ; mov $0xbf955555,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,217 ; movd %ecx,%xmm11 + DB 69,15,198,219,0 ; shufps $0x0,%xmm11,%xmm11 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,211 ; addps %xmm11,%xmm10 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,208 ; addps %xmm8,%xmm10 + DB 185,57,142,99,61 ; mov $0x3d638e39,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,89,209 ; mulps %xmm9,%xmm10 + DB 69,15,88,208 ; addps %xmm8,%xmm10 + DB 68,15,17,144,160,0,0,0 ; movups %xmm10,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax + +PUBLIC _sk_bicubic_p3y_sse2 +_sk_bicubic_p3y_sse2 LABEL PROC + DB 72,173 ; lods %ds:(%rsi),%rax + DB 185,0,0,192,63 ; mov $0x3fc00000,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 15,16,72,32 ; movups 0x20(%rax),%xmm1 + DB 68,15,16,72,96 ; movups 0x60(%rax),%xmm9 + DB 65,15,88,200 ; addps %xmm8,%xmm1 + DB 185,114,28,199,62 ; mov $0x3ec71c72,%ecx + DB 102,68,15,110,193 ; movd %ecx,%xmm8 + DB 69,15,198,192,0 ; shufps $0x0,%xmm8,%xmm8 + DB 69,15,89,193 ; mulps %xmm9,%xmm8 + DB 69,15,89,201 ; mulps %xmm9,%xmm9 + DB 185,171,170,170,190 ; mov $0xbeaaaaab,%ecx + DB 102,68,15,110,209 ; movd %ecx,%xmm10 + DB 69,15,198,210,0 ; shufps $0x0,%xmm10,%xmm10 + DB 69,15,88,194 ; addps %xmm10,%xmm8 + DB 69,15,89,193 ; mulps %xmm9,%xmm8 + DB 68,15,17,128,160,0,0,0 ; movups %xmm8,0xa0(%rax) + DB 72,173 ; lods %ds:(%rsi),%rax + DB 255,224 ; jmpq *%rax +ENDIF +END diff --git a/gfx/skia/skia/src/jumper/SkJumper_misc.h b/gfx/skia/skia/src/jumper/SkJumper_misc.h new file mode 100644 index 000000000000..54e957ad6e05 --- /dev/null +++ b/gfx/skia/skia/src/jumper/SkJumper_misc.h @@ -0,0 +1,57 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkJumper_misc_DEFINED +#define SkJumper_misc_DEFINED + +#include "SkJumper.h" // for memcpy() + +// Miscellany used by SkJumper_stages.cpp and SkJumper_vectors.h. + +// Every function in this file should be marked static and inline using SI. +#define SI static inline + +template +SI T unaligned_load(const P* p) { // const void* would work too, but const P* helps ARMv7 codegen. + T v; + memcpy(&v, p, sizeof(v)); + return v; +} + +template +SI Dst bit_cast(const Src& src) { + static_assert(sizeof(Dst) == sizeof(Src), ""); + return unaligned_load(&src); +} + +template +SI Dst widen_cast(const Src& src) { + static_assert(sizeof(Dst) > sizeof(Src), ""); + Dst dst; + memcpy(&dst, &src, sizeof(Src)); + return dst; +} + +// A couple functions for embedding constants directly into code, +// so that no .const or .literal4 section is created. +SI int C(int x) { +#if defined(JUMPER) && defined(__x86_64__) + // Move x-the-compile-time-constant as a literal into x-the-register. + asm("mov %1, %0" : "=r"(x) : "i"(x)); +#endif + return x; +} +SI float C(float f) { + int x = C(unaligned_load(&f)); + return unaligned_load(&x); +} + +// Syntax sugar to make C() easy to use for constant literals. +SI int operator "" _i(unsigned long long int i) { return C( (int)i); } +SI float operator "" _f( long double f) { return C((float)f); } + +#endif//SkJumper_misc_DEFINED diff --git a/gfx/skia/skia/src/jumper/SkJumper_stages.cpp b/gfx/skia/skia/src/jumper/SkJumper_stages.cpp new file mode 100644 index 000000000000..2e6746c338ec --- /dev/null +++ b/gfx/skia/skia/src/jumper/SkJumper_stages.cpp @@ -0,0 +1,1024 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkJumper.h" +#include "SkJumper_misc.h" // SI, unaligned_load(), bit_cast(), C(), operator"" _i and _f. +#include "SkJumper_vectors.h" // F, I32, U32, U16, U8, cast(), expand() + +// Our fundamental vector depth is our pixel stride. +static const size_t kStride = sizeof(F) / sizeof(float); + +// A reminder: +// Code guarded by defined(JUMPER) can assume that it will be compiled by Clang +// and that F, I32, etc. are kStride-deep ext_vector_types of the appropriate type. +// Otherwise, F, I32, etc. just alias the basic scalar types (and so kStride == 1). + +// Another reminder: +// You can't generally use constants in this file except via C() or operator"" _i/_f. +// Not all constants can be generated using C() or _i/_f. Stages read the rest from this struct. +using K = const SkJumper_constants; + + +// Let's start first with the mechanisms we use to build Stages. + +// Our program is an array of void*, either +// - 1 void* per stage with no context pointer, the next stage; +// - 2 void* per stage with a context pointer, first the context pointer, then the next stage. + +// load_and_inc() steps the program forward by 1 void*, returning that pointer. +SI void* load_and_inc(void**& program) { +#if defined(__GNUC__) && defined(__x86_64__) + // If program is in %rsi (we try to make this likely) then this is a single instruction. + void* rax; + asm("lodsq" : "=a"(rax), "+S"(program)); // Write-only %rax, read-write %rsi. + return rax; +#else + // On ARM *program++ compiles into pretty ideal code without any handholding. + return *program++; +#endif +} + +// LazyCtx doesn't do anything unless you call operator T*(), encapsulating the logic +// from above that stages without a context pointer are represented by just 1 void*. +struct LazyCtx { + void* ptr; + void**& program; + + explicit LazyCtx(void**& p) : ptr(nullptr), program(p) {} + + template + operator T*() { + if (!ptr) { ptr = load_and_inc(program); } + return (T*)ptr; + } +}; + +// A little wrapper macro to name Stages differently depending on the instruction set. +// That lets us link together several options. +#if !defined(JUMPER) + #define WRAP(name) sk_##name +#elif defined(__aarch64__) + #define WRAP(name) sk_##name##_aarch64 +#elif defined(__arm__) + #define WRAP(name) sk_##name##_vfp4 +#elif defined(__AVX2__) + #define WRAP(name) sk_##name##_hsw +#elif defined(__AVX__) + #define WRAP(name) sk_##name##_avx +#elif defined(__SSE4_1__) + #define WRAP(name) sk_##name##_sse41 +#elif defined(__SSE2__) + #define WRAP(name) sk_##name##_sse2 +#endif + +// We're finally going to get to what a Stage function looks like! +// It's best to jump down to the #else case first, then to come back up here for AVX. + +#if defined(JUMPER) && defined(__AVX__) + // There's a big cost to switch between SSE and AVX, so we do a little + // extra work to handle even the jagged work on a full kStride pixels + // tail != 0 ~~> work on only the first tail pixels + // tail is always < kStride. + using Stage = void(size_t x, void** program, K* k, size_t tail, F,F,F,F, F,F,F,F); + + #if defined(JUMPER) && defined(WIN) + __attribute__((ms_abi)) + #endif + extern "C" size_t WRAP(start_pipeline)(size_t x, void** program, K* k, size_t limit) { + F v{}; + auto start = (Stage*)load_and_inc(program); + while (x + kStride <= limit) { + start(x,program,k,0, v,v,v,v, v,v,v,v); + x += kStride; + } + if (size_t tail = limit - x) { + start(x,program,k,tail, v,v,v,v, v,v,v,v); + } + return limit; + } + + #define STAGE(name) \ + SI void name##_k(size_t x, LazyCtx ctx, K* k, size_t tail, \ + F& r, F& g, F& b, F& a, F& dr, F& dg, F& db, F& da); \ + extern "C" void WRAP(name)(size_t x, void** program, K* k, size_t tail, \ + F r, F g, F b, F a, F dr, F dg, F db, F da) { \ + LazyCtx ctx(program); \ + name##_k(x,ctx,k,tail, r,g,b,a, dr,dg,db,da); \ + auto next = (Stage*)load_and_inc(program); \ + next(x,program,k,tail, r,g,b,a, dr,dg,db,da); \ + } \ + SI void name##_k(size_t x, LazyCtx ctx, K* k, size_t tail, \ + F& r, F& g, F& b, F& a, F& dr, F& dg, F& db, F& da) + +#else + // Other instruction sets (SSE, NEON, portable) can fall back on narrower + // pipelines cheaply, which frees us to always assume tail==0. + + // Stages tail call between each other by following program as described above. + // x is our induction variable, stepping forward kStride at a time. + using Stage = void(size_t x, void** program, K* k, F,F,F,F, F,F,F,F); + + // On Windows, start_pipeline() has a normal Windows ABI, and then the rest is System V. + #if defined(JUMPER) && defined(WIN) + __attribute__((ms_abi)) + #endif + extern "C" size_t WRAP(start_pipeline)(size_t x, void** program, K* k, size_t limit) { + F v{}; + auto start = (Stage*)load_and_inc(program); + while (x + kStride <= limit) { + start(x,program,k, v,v,v,v, v,v,v,v); + x += kStride; + } + return x; + } + + // This STAGE macro makes it easier to write stages, handling all the Stage chaining for you. + #define STAGE(name) \ + SI void name##_k(size_t x, LazyCtx ctx, K* k, size_t tail, \ + F& r, F& g, F& b, F& a, F& dr, F& dg, F& db, F& da); \ + extern "C" void WRAP(name)(size_t x, void** program, K* k, \ + F r, F g, F b, F a, F dr, F dg, F db, F da) { \ + LazyCtx ctx(program); \ + name##_k(x,ctx,k,0, r,g,b,a, dr,dg,db,da); \ + auto next = (Stage*)load_and_inc(program); \ + next(x,program,k, r,g,b,a, dr,dg,db,da); \ + } \ + SI void name##_k(size_t x, LazyCtx ctx, K* k, size_t tail, \ + F& r, F& g, F& b, F& a, F& dr, F& dg, F& db, F& da) +#endif + +// just_return() is a simple no-op stage that only exists to end the chain, +// returning back up to start_pipeline(), and from there to the caller. +extern "C" void WRAP(just_return)(size_t, void**, K*, F,F,F,F, F,F,F,F) {} + + +// We could start defining normal Stages now. But first, some helper functions. + +// These load() and store() methods are tail-aware, +// but focus mainly on keeping the at-stride tail==0 case fast. + +template +SI V load(const T* src, size_t tail) { +#if defined(JUMPER) + __builtin_assume(tail < kStride); + if (__builtin_expect(tail, 0)) { + V v{}; // Any inactive lanes are zeroed. + switch (tail-1) { + case 6: v[6] = src[6]; + case 5: v[5] = src[5]; + case 4: v[4] = src[4]; + case 3: v[3] = src[3]; + case 2: v[2] = src[2]; + case 1: v[1] = src[1]; + case 0: v[0] = src[0]; + } + return v; + } +#endif + return unaligned_load(src); +} + +template +SI void store(T* dst, V v, size_t tail) { +#if defined(JUMPER) + __builtin_assume(tail < kStride); + if (__builtin_expect(tail, 0)) { + switch (tail-1) { + case 6: dst[6] = v[6]; + case 5: dst[5] = v[5]; + case 4: dst[4] = v[4]; + case 3: dst[3] = v[3]; + case 2: dst[2] = v[2]; + case 1: dst[1] = v[1]; + case 0: dst[0] = v[0]; + } + return; + } +#endif + memcpy(dst, &v, sizeof(v)); +} + +// This doesn't look strictly necessary, but without it Clang would generate load() using +// compiler-generated constants that we can't support. This version doesn't need constants. +#if defined(JUMPER) && defined(__AVX__) + template <> + inline U8 load(const uint8_t* src, size_t tail) { + if (__builtin_expect(tail, 0)) { + uint64_t v = 0; + size_t shift = 0; + #pragma nounroll + while (tail --> 0) { + v |= (uint64_t)*src++ << shift; + shift += 8; + } + return unaligned_load(&v); + } + return unaligned_load(src); + } +#endif + +// AVX2 adds some mask loads and stores that make for shorter, faster code. +#if defined(JUMPER) && defined(__AVX2__) + SI U32 mask(size_t tail) { + // We go a little out of our way to avoid needing large constant values here. + + // It's easiest to build the mask as 8 8-bit values, either 0x00 or 0xff. + // Start fully on, then shift away lanes from the top until we've got our mask. + uint64_t mask = 0xffffffffffffffff >> 8*(kStride-tail); + + // Sign-extend each mask lane to its full width, 0x00000000 or 0xffffffff. + return _mm256_cvtepi8_epi32(_mm_cvtsi64_si128((int64_t)mask)); + } + + template <> + inline U32 load(const uint32_t* src, size_t tail) { + __builtin_assume(tail < kStride); + if (__builtin_expect(tail, 0)) { + return _mm256_maskload_epi32((const int*)src, mask(tail)); + } + return unaligned_load(src); + } + + template <> + inline void store(uint32_t* dst, U32 v, size_t tail) { + __builtin_assume(tail < kStride); + if (__builtin_expect(tail, 0)) { + return _mm256_maskstore_epi32((int*)dst, mask(tail), v); + } + memcpy(dst, &v, sizeof(v)); + } +#endif + +SI F from_byte(U8 b) { + return cast(expand(b)) * C(1/255.0f); +} +SI void from_565(U16 _565, F* r, F* g, F* b) { + U32 wide = expand(_565); + *r = cast(wide & C(31<<11)) * C(1.0f / (31<<11)); + *g = cast(wide & C(63<< 5)) * C(1.0f / (63<< 5)); + *b = cast(wide & C(31<< 0)) * C(1.0f / (31<< 0)); +} +SI void from_4444(U16 _4444, F* r, F* g, F* b, F* a) { + U32 wide = expand(_4444); + *r = cast(wide & C(15<<12)) * C(1.0f / (15<<12)); + *g = cast(wide & C(15<< 8)) * C(1.0f / (15<< 8)); + *b = cast(wide & C(15<< 4)) * C(1.0f / (15<< 4)); + *a = cast(wide & C(15<< 0)) * C(1.0f / (15<< 0)); +} +SI void from_8888(U32 _8888, F* r, F* g, F* b, F* a) { + *r = cast((_8888 ) & 0xff_i) * C(1/255.0f); + *g = cast((_8888 >> 8) & 0xff_i) * C(1/255.0f); + *b = cast((_8888 >> 16) & 0xff_i) * C(1/255.0f); + *a = cast((_8888 >> 24) ) * C(1/255.0f); +} + +template +SI U32 ix_and_ptr(T** ptr, const SkJumper_GatherCtx* ctx, F x, F y) { + *ptr = (const T*)ctx->pixels; + return trunc_(y)*ctx->stride + trunc_(x); +} + +// Now finally, normal Stages! + +STAGE(seed_shader) { + auto y = *(const int*)ctx; + + // It's important for speed to explicitly cast(x) and cast(y), + // which has the effect of splatting them to vectors before converting to floats. + // On Intel this breaks a data dependency on previous loop iterations' registers. + r = cast(x) + 0.5_f + unaligned_load(k->iota); + g = cast(y) + 0.5_f; + b = 1.0_f; + a = 0; + dr = dg = db = da = 0; +} + +STAGE(constant_color) { + auto rgba = (const float*)ctx; + r = rgba[0]; + g = rgba[1]; + b = rgba[2]; + a = rgba[3]; +} + +// Most blend modes apply the same logic to each channel. +#define BLEND_MODE(name) \ + SI F name##_channel(F s, F d, F sa, F da); \ + STAGE(name) { \ + r = name##_channel(r,dr,a,da); \ + g = name##_channel(g,dg,a,da); \ + b = name##_channel(b,db,a,da); \ + a = name##_channel(a,da,a,da); \ + } \ + SI F name##_channel(F s, F d, F sa, F da) + +SI F inv(F x) { return 1.0_f - x; } +SI F two(F x) { return x + x; } + +BLEND_MODE(clear) { return 0; } +BLEND_MODE(srcatop) { return s*da + d*inv(sa); } +BLEND_MODE(dstatop) { return d*sa + s*inv(da); } +BLEND_MODE(srcin) { return s * da; } +BLEND_MODE(dstin) { return d * sa; } +BLEND_MODE(srcout) { return s * inv(da); } +BLEND_MODE(dstout) { return d * inv(sa); } +BLEND_MODE(srcover) { return mad(d, inv(sa), s); } +BLEND_MODE(dstover) { return mad(s, inv(da), d); } + +BLEND_MODE(modulate) { return s*d; } +BLEND_MODE(multiply) { return s*inv(da) + d*inv(sa) + s*d; } +BLEND_MODE(plus_) { return s + d; } +BLEND_MODE(screen) { return s + d - s*d; } +BLEND_MODE(xor_) { return s*inv(da) + d*inv(sa); } +#undef BLEND_MODE + +// Most other blend modes apply the same logic to colors, and srcover to alpha. +#define BLEND_MODE(name) \ + SI F name##_channel(F s, F d, F sa, F da); \ + STAGE(name) { \ + r = name##_channel(r,dr,a,da); \ + g = name##_channel(g,dg,a,da); \ + b = name##_channel(b,db,a,da); \ + a = mad(da, inv(a), a); \ + } \ + SI F name##_channel(F s, F d, F sa, F da) + +BLEND_MODE(darken) { return s + d - max(s*da, d*sa) ; } +BLEND_MODE(lighten) { return s + d - min(s*da, d*sa) ; } +BLEND_MODE(difference) { return s + d - two(min(s*da, d*sa)); } +BLEND_MODE(exclusion) { return s + d - two(s*d); } + +BLEND_MODE(colorburn) { + return if_then_else(d == da, d + s*inv(da), + if_then_else(s == 0, s + d*inv(sa), + sa*(da - min(da, (da-d)*sa/s)) + s*inv(da) + d*inv(sa))); +} +BLEND_MODE(colordodge) { + return if_then_else(d == 0, d + s*inv(da), + if_then_else(s == sa, s + d*inv(sa), + sa*min(da, (d*sa)/(sa - s)) + s*inv(da) + d*inv(sa))); +} +BLEND_MODE(hardlight) { + return s*inv(da) + d*inv(sa) + + if_then_else(two(s) <= sa, two(s*d), sa*da - two((da-d)*(sa-s))); +} +BLEND_MODE(overlay) { + return s*inv(da) + d*inv(sa) + + if_then_else(two(d) <= da, two(s*d), sa*da - two((da-d)*(sa-s))); +} + +BLEND_MODE(softlight) { + F m = if_then_else(da > 0, d / da, 0), + s2 = two(s), + m4 = two(two(m)); + + // The logic forks three ways: + // 1. dark src? + // 2. light src, dark dst? + // 3. light src, light dst? + F darkSrc = d*(sa + (s2 - sa)*(1.0_f - m)), // Used in case 1. + darkDst = (m4*m4 + m4)*(m - 1.0_f) + 7.0_f*m, // Used in case 2. + liteDst = rcp(rsqrt(m)) - m, // Used in case 3. + liteSrc = d*sa + da*(s2 - sa) * if_then_else(two(two(d)) <= da, darkDst, liteDst); // 2 or 3? + return s*inv(da) + d*inv(sa) + if_then_else(s2 <= sa, darkSrc, liteSrc); // 1 or (2 or 3)? +} +#undef BLEND_MODE + +STAGE(clamp_0) { + r = max(r, 0); + g = max(g, 0); + b = max(b, 0); + a = max(a, 0); +} + +STAGE(clamp_1) { + r = min(r, 1.0_f); + g = min(g, 1.0_f); + b = min(b, 1.0_f); + a = min(a, 1.0_f); +} + +STAGE(clamp_a) { + a = min(a, 1.0_f); + r = min(r, a); + g = min(g, a); + b = min(b, a); +} + +STAGE(set_rgb) { + auto rgb = (const float*)ctx; + r = rgb[0]; + g = rgb[1]; + b = rgb[2]; +} +STAGE(swap_rb) { + auto tmp = r; + r = b; + b = tmp; +} + +STAGE(swap) { + auto swap = [](F& v, F& dv) { + auto tmp = v; + v = dv; + dv = tmp; + }; + swap(r, dr); + swap(g, dg); + swap(b, db); + swap(a, da); +} +STAGE(move_src_dst) { + dr = r; + dg = g; + db = b; + da = a; +} +STAGE(move_dst_src) { + r = dr; + g = dg; + b = db; + a = da; +} + +STAGE(premul) { + r = r * a; + g = g * a; + b = b * a; +} +STAGE(unpremul) { + auto scale = if_then_else(a == 0, 0, 1.0_f / a); + r = r * scale; + g = g * scale; + b = b * scale; +} + +STAGE(from_srgb) { + auto fn = [&](F s) { + auto lo = s * C(1/12.92f); + auto hi = mad(s*s, mad(s, 0.3000_f, 0.6975_f), 0.0025_f); + return if_then_else(s < 0.055_f, lo, hi); + }; + r = fn(r); + g = fn(g); + b = fn(b); +} +STAGE(to_srgb) { + auto fn = [&](F l) { + F sqrt = rcp (rsqrt(l)), + ftrt = rsqrt(rsqrt(l)); + auto lo = l * 12.46_f; + auto hi = min(1.0_f, mad(0.411192_f, ftrt, + mad(0.689206_f, sqrt, -0.0988_f))); + return if_then_else(l < 0.0043_f, lo, hi); + }; + r = fn(r); + g = fn(g); + b = fn(b); +} + +STAGE(from_2dot2) { + auto fn = [](F x) { + // x^(141/64) = x^(2.20312) is a great approximation of the true value, x^(2.2). + // (note: x^(35/16) = x^(2.1875) is an okay one as well and would be quicker) + F x16 = rsqrt(rsqrt(rsqrt(rsqrt(x)))), // x^(1/16) = x^(4/64); + x64 = rsqrt(rsqrt(x16)); // x^(1/64) + + // 141/64 = 128/64 + 12/64 + 1/64 + return max((x*x) * (x16*x16*x16) * x64, 0); + }; + r = fn(r); + g = fn(g); + b = fn(b); +} +STAGE(to_2dot2) { + auto fn = [](F x) { + // x^(29/64) is a very good approximation of the true value, x^(1/2.2). + F x2 = rsqrt(x), // x^(-1/2) + x32 = rsqrt(rsqrt(rsqrt(rsqrt(x2)))), // x^(-1/32) + x64 = rsqrt(x32); // x^(+1/64) + + // 29/64 = 32/64 - 2/64 - 1/64 + return max(rcp(x2) * x32 * rcp(x64), 0); + }; + r = fn(r); + g = fn(g); + b = fn(b); +} + +STAGE(rgb_to_hsl) { + F mx = max(max(r,g), b), + mn = min(min(r,g), b), + d = mx - mn, + d_rcp = 1.0_f / d; + + F h = C(1/6.0f) * + if_then_else(mx == mn, 0, + if_then_else(mx == r, (g-b)*d_rcp + if_then_else(g < b, 6.0_f, 0), + if_then_else(mx == g, (b-r)*d_rcp + 2.0_f, + (r-g)*d_rcp + 4.0_f))); + + F l = (mx + mn) * 0.5_f; + F s = if_then_else(mx == mn, 0, + d / if_then_else(l > 0.5_f, 2.0_f-mx-mn, mx+mn)); + + r = h; + g = s; + b = l; +} +STAGE(hsl_to_rgb) { + F h = r, + s = g, + l = b; + + F q = if_then_else(l < 0.5_f, l*(1.0_f + s), l + s - l*s), + p = 2.0_f*l - q; + + auto hue_to_rgb = [&](F t) { + F t2 = if_then_else(t < 0.0_f, t + 1.0_f, + if_then_else(t > 1.0_f, t - 1.0_f, + t)); + + return if_then_else(t2 < C(1/6.0f), p + (q-p)*6.0_f*t, + if_then_else(t2 < C(3/6.0f), q, + if_then_else(t2 < C(4/6.0f), p + (q-p)*6.0_f*(C(4/6.0f) - t2), + p))); + }; + + r = if_then_else(s == 0, l, hue_to_rgb(h + C(1/3.0f))); + g = if_then_else(s == 0, l, hue_to_rgb(h )); + b = if_then_else(s == 0, l, hue_to_rgb(h - C(1/3.0f))); +} + +STAGE(scale_1_float) { + auto c = *(const float*)ctx; + + r = r * c; + g = g * c; + b = b * c; + a = a * c; +} +STAGE(scale_u8) { + auto ptr = *(const uint8_t**)ctx + x; + + auto scales = load(ptr, tail); + auto c = from_byte(scales); + + r = r * c; + g = g * c; + b = b * c; + a = a * c; +} + +SI F lerp(F from, F to, F t) { + return mad(to-from, t, from); +} + +STAGE(lerp_1_float) { + auto c = *(const float*)ctx; + + r = lerp(dr, r, c); + g = lerp(dg, g, c); + b = lerp(db, b, c); + a = lerp(da, a, c); +} +STAGE(lerp_u8) { + auto ptr = *(const uint8_t**)ctx + x; + + auto scales = load(ptr, tail); + auto c = from_byte(scales); + + r = lerp(dr, r, c); + g = lerp(dg, g, c); + b = lerp(db, b, c); + a = lerp(da, a, c); +} +STAGE(lerp_565) { + auto ptr = *(const uint16_t**)ctx + x; + + F cr,cg,cb; + from_565(load(ptr, tail), &cr, &cg, &cb); + + r = lerp(dr, r, cr); + g = lerp(dg, g, cg); + b = lerp(db, b, cb); + a = 1.0_f; +} + +STAGE(load_tables) { + struct Ctx { + const uint32_t* src; + const float *r, *g, *b; + }; + auto c = (const Ctx*)ctx; + + auto px = load(c->src + x, tail); + r = gather(c->r, (px ) & 0xff_i); + g = gather(c->g, (px >> 8) & 0xff_i); + b = gather(c->b, (px >> 16) & 0xff_i); + a = cast( (px >> 24)) * C(1/255.0f); +} + +STAGE(byte_tables) { + struct Tables { const uint8_t *r, *g, *b, *a; }; + auto tables = (const Tables*)ctx; + + r = from_byte(gather(tables->r, round(r, 255.0_f))); + g = from_byte(gather(tables->g, round(g, 255.0_f))); + b = from_byte(gather(tables->b, round(b, 255.0_f))); + a = from_byte(gather(tables->a, round(a, 255.0_f))); +} + +STAGE(byte_tables_rgb) { + struct Tables { const uint8_t *r, *g, *b; int n; }; + auto tables = (const Tables*)ctx; + + F scale = tables->n - 1; + r = from_byte(gather(tables->r, round(r, scale))); + g = from_byte(gather(tables->g, round(g, scale))); + b = from_byte(gather(tables->b, round(b, scale))); +} + +STAGE(load_a8) { + auto ptr = *(const uint8_t**)ctx + x; + + r = g = b = 0.0f; + a = from_byte(load(ptr, tail)); +} +STAGE(gather_a8) { + const uint8_t* ptr; + U32 ix = ix_and_ptr(&ptr, ctx, r,g); + r = g = b = 0.0f; + a = from_byte(gather(ptr, ix)); +} +STAGE(store_a8) { + auto ptr = *(uint8_t**)ctx + x; + + U8 packed = pack(pack(round(a, 255.0_f))); + store(ptr, packed, tail); +} + +STAGE(load_g8) { + auto ptr = *(const uint8_t**)ctx + x; + + r = g = b = from_byte(load(ptr, tail)); + a = 1.0_f; +} +STAGE(gather_g8) { + const uint8_t* ptr; + U32 ix = ix_and_ptr(&ptr, ctx, r,g); + r = g = b = from_byte(gather(ptr, ix)); + a = 1.0_f; +} + +STAGE(gather_i8) { + auto c = (const SkJumper_GatherCtx*)ctx; + const uint8_t* ptr; + U32 ix = ix_and_ptr(&ptr, ctx, r,g); + ix = expand(gather(ptr, ix)); + from_8888(gather(c->ctable, ix), &r,&g,&b,&a); +} + +STAGE(load_565) { + auto ptr = *(const uint16_t**)ctx + x; + + from_565(load(ptr, tail), &r,&g,&b); + a = 1.0_f; +} +STAGE(gather_565) { + const uint16_t* ptr; + U32 ix = ix_and_ptr(&ptr, ctx, r,g); + from_565(gather(ptr, ix), &r,&g,&b); + a = 1.0_f; +} +STAGE(store_565) { + auto ptr = *(uint16_t**)ctx + x; + + U16 px = pack( round(r, 31.0_f) << 11 + | round(g, 63.0_f) << 5 + | round(b, 31.0_f) ); + store(ptr, px, tail); +} + +STAGE(load_4444) { + auto ptr = *(const uint16_t**)ctx + x; + from_4444(load(ptr, tail), &r,&g,&b,&a); +} +STAGE(gather_4444) { + const uint16_t* ptr; + U32 ix = ix_and_ptr(&ptr, ctx, r,g); + from_4444(gather(ptr, ix), &r,&g,&b,&a); +} +STAGE(store_4444) { + auto ptr = *(uint16_t**)ctx + x; + U16 px = pack( round(r, 15.0_f) << 12 + | round(g, 15.0_f) << 8 + | round(b, 15.0_f) << 4 + | round(a, 15.0_f) ); + store(ptr, px, tail); +} + +STAGE(load_8888) { + auto ptr = *(const uint32_t**)ctx + x; + from_8888(load(ptr, tail), &r,&g,&b,&a); +} +STAGE(gather_8888) { + const uint32_t* ptr; + U32 ix = ix_and_ptr(&ptr, ctx, r,g); + from_8888(gather(ptr, ix), &r,&g,&b,&a); +} +STAGE(store_8888) { + auto ptr = *(uint32_t**)ctx + x; + + U32 px = round(r, 255.0_f) + | round(g, 255.0_f) << 8 + | round(b, 255.0_f) << 16 + | round(a, 255.0_f) << 24; + store(ptr, px, tail); +} + +STAGE(load_f16) { + auto ptr = *(const uint64_t**)ctx + x; + + U16 R,G,B,A; + load4((const uint16_t*)ptr,tail, &R,&G,&B,&A); + r = from_half(R); + g = from_half(G); + b = from_half(B); + a = from_half(A); +} +STAGE(gather_f16) { + const uint64_t* ptr; + U32 ix = ix_and_ptr(&ptr, ctx, r,g); + auto px = gather(ptr, ix); + + U16 R,G,B,A; + load4((const uint16_t*)&px,0, &R,&G,&B,&A); + r = from_half(R); + g = from_half(G); + b = from_half(B); + a = from_half(A); +} +STAGE(store_f16) { + auto ptr = *(uint64_t**)ctx + x; + store4((uint16_t*)ptr,tail, to_half(r) + , to_half(g) + , to_half(b) + , to_half(a)); +} + +STAGE(load_u16_be) { + auto ptr = *(const uint64_t**)ctx + x; + + U16 R,G,B,A; + load4((const uint16_t*)ptr,tail, &R,&G,&B,&A); + + r = C(1/65535.0f) * cast(expand(bswap(R))); + g = C(1/65535.0f) * cast(expand(bswap(G))); + b = C(1/65535.0f) * cast(expand(bswap(B))); + a = C(1/65535.0f) * cast(expand(bswap(A))); +} +STAGE(store_u16_be) { + auto ptr = *(uint64_t**)ctx + x; + + U16 R = bswap(pack(round(r, 65535.0_f))), + G = bswap(pack(round(g, 65535.0_f))), + B = bswap(pack(round(b, 65535.0_f))), + A = bswap(pack(round(a, 65535.0_f))); + + store4((uint16_t*)ptr,tail, R,G,B,A); +} + +STAGE(load_f32) { + auto ptr = *(const float**)ctx + 4*x; + load4(ptr,tail, &r,&g,&b,&a); +} +STAGE(store_f32) { + auto ptr = *(float**)ctx + 4*x; + store4(ptr,tail, r,g,b,a); +} + +SI F ulp_before(F v) { + return bit_cast(bit_cast(v) + U32(0xffffffff)); +} +SI F clamp(F v, float limit) { + v = max(0, v); + return min(v, ulp_before(limit)); +} +SI F repeat(F v, float limit) { + v = v - floor_(v/limit)*limit; + return min(v, ulp_before(limit)); +} +SI F mirror(F v, float limit) { + v = abs_( (v-limit) - (limit+limit)*floor_((v-limit)/(limit+limit)) - limit ); + return min(v, ulp_before(limit)); +} +STAGE(clamp_x) { r = clamp (r, *(const float*)ctx); } +STAGE(clamp_y) { g = clamp (g, *(const float*)ctx); } +STAGE(repeat_x) { r = repeat(r, *(const float*)ctx); } +STAGE(repeat_y) { g = repeat(g, *(const float*)ctx); } +STAGE(mirror_x) { r = mirror(r, *(const float*)ctx); } +STAGE(mirror_y) { g = mirror(g, *(const float*)ctx); } + +STAGE(luminance_to_alpha) { + a = r*0.2126_f + g*0.7152_f + b*0.0722_f; + r = g = b = 0; +} + +STAGE(matrix_2x3) { + auto m = (const float*)ctx; + + auto R = mad(r,m[0], mad(g,m[2], m[4])), + G = mad(r,m[1], mad(g,m[3], m[5])); + r = R; + g = G; +} +STAGE(matrix_3x4) { + auto m = (const float*)ctx; + + auto R = mad(r,m[0], mad(g,m[3], mad(b,m[6], m[ 9]))), + G = mad(r,m[1], mad(g,m[4], mad(b,m[7], m[10]))), + B = mad(r,m[2], mad(g,m[5], mad(b,m[8], m[11]))); + r = R; + g = G; + b = B; +} +STAGE(matrix_4x5) { + auto m = (const float*)ctx; + + auto R = mad(r,m[0], mad(g,m[4], mad(b,m[ 8], mad(a,m[12], m[16])))), + G = mad(r,m[1], mad(g,m[5], mad(b,m[ 9], mad(a,m[13], m[17])))), + B = mad(r,m[2], mad(g,m[6], mad(b,m[10], mad(a,m[14], m[18])))), + A = mad(r,m[3], mad(g,m[7], mad(b,m[11], mad(a,m[15], m[19])))); + r = R; + g = G; + b = B; + a = A; +} +STAGE(matrix_perspective) { + // N.B. Unlike the other matrix_ stages, this matrix is row-major. + auto m = (const float*)ctx; + + auto R = mad(r,m[0], mad(g,m[1], m[2])), + G = mad(r,m[3], mad(g,m[4], m[5])), + Z = mad(r,m[6], mad(g,m[7], m[8])); + r = R * rcp(Z); + g = G * rcp(Z); +} + +STAGE(linear_gradient) { + struct Stop { float pos; float f[4], b[4]; }; + struct Ctx { size_t n; Stop *stops; float start[4]; }; + + auto c = (const Ctx*)ctx; + F fr = 0, fg = 0, fb = 0, fa = 0; + F br = c->start[0], + bg = c->start[1], + bb = c->start[2], + ba = c->start[3]; + auto t = r; + for (size_t i = 0; i < c->n; i++) { + fr = if_then_else(t < c->stops[i].pos, fr, c->stops[i].f[0]); + fg = if_then_else(t < c->stops[i].pos, fg, c->stops[i].f[1]); + fb = if_then_else(t < c->stops[i].pos, fb, c->stops[i].f[2]); + fa = if_then_else(t < c->stops[i].pos, fa, c->stops[i].f[3]); + br = if_then_else(t < c->stops[i].pos, br, c->stops[i].b[0]); + bg = if_then_else(t < c->stops[i].pos, bg, c->stops[i].b[1]); + bb = if_then_else(t < c->stops[i].pos, bb, c->stops[i].b[2]); + ba = if_then_else(t < c->stops[i].pos, ba, c->stops[i].b[3]); + } + + r = mad(t, fr, br); + g = mad(t, fg, bg); + b = mad(t, fb, bb); + a = mad(t, fa, ba); +} + +STAGE(linear_gradient_2stops) { + struct Ctx { float f[4], b[4]; }; + auto c = (const Ctx*)ctx; + + auto t = r; + r = mad(t, c->f[0], c->b[0]); + g = mad(t, c->f[1], c->b[1]); + b = mad(t, c->f[2], c->b[2]); + a = mad(t, c->f[3], c->b[3]); +} + +STAGE(save_xy) { + auto c = (SkJumper_SamplerCtx*)ctx; + + // Whether bilinear or bicubic, all sample points are at the same fractional offset (fx,fy). + // They're either the 4 corners of a logical 1x1 pixel or the 16 corners of a 3x3 grid + // surrounding (x,y) at (0.5,0.5) off-center. + auto fract = [](F v) { return v - floor_(v); }; + F fx = fract(r + 0.5_f), + fy = fract(g + 0.5_f); + + // Samplers will need to load x and fx, or y and fy. + memcpy(c->x, &r, sizeof(F)); + memcpy(c->y, &g, sizeof(F)); + memcpy(c->fx, &fx, sizeof(F)); + memcpy(c->fy, &fy, sizeof(F)); +} + +STAGE(accumulate) { + auto c = (const SkJumper_SamplerCtx*)ctx; + + // Bilinear and bicubic filters are both separable, so we produce independent contributions + // from x and y, multiplying them together here to get each pixel's total scale factor. + auto scale = unaligned_load(c->scalex) + * unaligned_load(c->scaley); + dr = mad(scale, r, dr); + dg = mad(scale, g, dg); + db = mad(scale, b, db); + da = mad(scale, a, da); +} + +// In bilinear interpolation, the 4 pixels at +/- 0.5 offsets from the sample pixel center +// are combined in direct proportion to their area overlapping that logical query pixel. +// At positive offsets, the x-axis contribution to that rectangle is fx, or (1-fx) at negative x. +// The y-axis is symmetric. + +template +SI void bilinear_x(SkJumper_SamplerCtx* ctx, F* x) { + *x = unaligned_load(ctx->x) + C(kScale * 0.5f); + F fx = unaligned_load(ctx->fx); + + F scalex; + if (kScale == -1) { scalex = 1.0_f - fx; } + if (kScale == +1) { scalex = fx; } + memcpy(ctx->scalex, &scalex, sizeof(F)); +} +template +SI void bilinear_y(SkJumper_SamplerCtx* ctx, F* y) { + *y = unaligned_load(ctx->y) + C(kScale * 0.5f); + F fy = unaligned_load(ctx->fy); + + F scaley; + if (kScale == -1) { scaley = 1.0_f - fy; } + if (kScale == +1) { scaley = fy; } + memcpy(ctx->scaley, &scaley, sizeof(F)); +} + +STAGE(bilinear_nx) { bilinear_x<-1>(ctx, &r); } +STAGE(bilinear_px) { bilinear_x<+1>(ctx, &r); } +STAGE(bilinear_ny) { bilinear_y<-1>(ctx, &g); } +STAGE(bilinear_py) { bilinear_y<+1>(ctx, &g); } + + +// In bicubic interpolation, the 16 pixels and +/- 0.5 and +/- 1.5 offsets from the sample +// pixel center are combined with a non-uniform cubic filter, with higher values near the center. +// +// We break this function into two parts, one for near 0.5 offsets and one for far 1.5 offsets. +// See GrCubicEffect for details of this particular filter. + +SI F bicubic_near(F t) { + // 1/18 + 9/18t + 27/18t^2 - 21/18t^3 == t ( t ( -21/18t + 27/18) + 9/18) + 1/18 + return mad(t, mad(t, mad(C(-21/18.0f), t, C(27/18.0f)), C(9/18.0f)), C(1/18.0f)); +} +SI F bicubic_far(F t) { + // 0/18 + 0/18*t - 6/18t^2 + 7/18t^3 == t^2 (7/18t - 6/18) + return (t*t)*mad(C(7/18.0f), t, C(-6/18.0f)); +} + +template +SI void bicubic_x(SkJumper_SamplerCtx* ctx, F* x) { + *x = unaligned_load(ctx->x) + C(kScale * 0.5f); + F fx = unaligned_load(ctx->fx); + + F scalex; + if (kScale == -3) { scalex = bicubic_far (1.0_f - fx); } + if (kScale == -1) { scalex = bicubic_near(1.0_f - fx); } + if (kScale == +1) { scalex = bicubic_near( fx); } + if (kScale == +3) { scalex = bicubic_far ( fx); } + memcpy(ctx->scalex, &scalex, sizeof(F)); +} +template +SI void bicubic_y(SkJumper_SamplerCtx* ctx, F* y) { + *y = unaligned_load(ctx->y) + C(kScale * 0.5f); + F fy = unaligned_load(ctx->fy); + + F scaley; + if (kScale == -3) { scaley = bicubic_far (1.0_f - fy); } + if (kScale == -1) { scaley = bicubic_near(1.0_f - fy); } + if (kScale == +1) { scaley = bicubic_near( fy); } + if (kScale == +3) { scaley = bicubic_far ( fy); } + memcpy(ctx->scaley, &scaley, sizeof(F)); +} + +STAGE(bicubic_n3x) { bicubic_x<-3>(ctx, &r); } +STAGE(bicubic_n1x) { bicubic_x<-1>(ctx, &r); } +STAGE(bicubic_p1x) { bicubic_x<+1>(ctx, &r); } +STAGE(bicubic_p3x) { bicubic_x<+3>(ctx, &r); } + +STAGE(bicubic_n3y) { bicubic_y<-3>(ctx, &g); } +STAGE(bicubic_n1y) { bicubic_y<-1>(ctx, &g); } +STAGE(bicubic_p1y) { bicubic_y<+1>(ctx, &g); } +STAGE(bicubic_p3y) { bicubic_y<+3>(ctx, &g); } diff --git a/gfx/skia/skia/src/jumper/SkJumper_vectors.h b/gfx/skia/skia/src/jumper/SkJumper_vectors.h new file mode 100644 index 000000000000..e8d7f6c7545f --- /dev/null +++ b/gfx/skia/skia/src/jumper/SkJumper_vectors.h @@ -0,0 +1,549 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkJumper_vectors_DEFINED +#define SkJumper_vectors_DEFINED + +#include "SkJumper.h" +#include "SkJumper_misc.h" + +// This file contains vector types that SkJumper_stages.cpp uses to define stages. + +// Every function in this file should be marked static and inline using SI (see SkJumper_misc.h). + +#if !defined(JUMPER) + // This path should lead to portable code that can be compiled directly into Skia. + // (All other paths are compiled offline by Clang into SkJumper_generated.S.) + #include + + using F = float ; + using I32 = int32_t; + using U64 = uint64_t; + using U32 = uint32_t; + using U16 = uint16_t; + using U8 = uint8_t ; + + SI F mad(F f, F m, F a) { return f*m+a; } + SI F min(F a, F b) { return fminf(a,b); } + SI F max(F a, F b) { return fmaxf(a,b); } + SI F abs_ (F v) { return fabsf(v); } + SI F floor_(F v) { return floorf(v); } + SI F rcp (F v) { return 1.0f / v; } + SI F rsqrt (F v) { return 1.0f / sqrtf(v); } + SI U32 round (F v, F scale) { return (uint32_t)lrintf(v*scale); } + SI U16 pack(U32 v) { return (U16)v; } + SI U8 pack(U16 v) { return (U8)v; } + + SI F if_then_else(I32 c, F t, F e) { return c ? t : e; } + + template + SI T gather(const T* p, U32 ix) { return p[ix]; } + + SI void load4(const uint16_t* ptr, size_t tail, U16* r, U16* g, U16* b, U16* a) { + *r = ptr[0]; + *g = ptr[1]; + *b = ptr[2]; + *a = ptr[3]; + } + SI void store4(uint16_t* ptr, size_t tail, U16 r, U16 g, U16 b, U16 a) { + ptr[0] = r; + ptr[1] = g; + ptr[2] = b; + ptr[3] = a; + } + + SI void load4(const float* ptr, size_t tail, F* r, F* g, F* b, F* a) { + *r = ptr[0]; + *g = ptr[1]; + *b = ptr[2]; + *a = ptr[3]; + } + SI void store4(float* ptr, size_t tail, F r, F g, F b, F a) { + ptr[0] = r; + ptr[1] = g; + ptr[2] = b; + ptr[3] = a; + } + + SI F from_half(U16 h) { + if ((int16_t)h < 0x0400) { h = 0; } // Flush denorm and negative to zero. + return bit_cast(h << 13) // Line up the mantissa, + * bit_cast(U32(0x77800000)); // then fix up the exponent. + } + SI U16 to_half(F f) { + return bit_cast(f * bit_cast(U32(0x07800000_i))) // Fix up the exponent, + >> 13; // then line up the mantissa. + } + +#elif defined(__aarch64__) + #include + + // Since we know we're using Clang, we can use its vector extensions. + template using V = T __attribute__((ext_vector_type(4))); + using F = V; + using I32 = V< int32_t>; + using U64 = V; + using U32 = V; + using U16 = V; + using U8 = V; + + // We polyfill a few routines that Clang doesn't build into ext_vector_types. + SI F mad(F f, F m, F a) { return vfmaq_f32(a,f,m); } + SI F min(F a, F b) { return vminq_f32(a,b); } + SI F max(F a, F b) { return vmaxq_f32(a,b); } + SI F abs_ (F v) { return vabsq_f32(v); } + SI F floor_(F v) { return vrndmq_f32(v); } + SI F rcp (F v) { auto e = vrecpeq_f32 (v); return vrecpsq_f32 (v,e ) * e; } + SI F rsqrt (F v) { auto e = vrsqrteq_f32(v); return vrsqrtsq_f32(v,e*e) * e; } + SI U32 round (F v, F scale) { return vcvtnq_u32_f32(v*scale); } + SI U16 pack(U32 v) { return __builtin_convertvector(v, U16); } + SI U8 pack(U16 v) { return __builtin_convertvector(v, U8); } + + SI F if_then_else(I32 c, F t, F e) { return vbslq_f32((U32)c,t,e); } + + template + SI V gather(const T* p, U32 ix) { + return {p[ix[0]], p[ix[1]], p[ix[2]], p[ix[3]]}; + } + + SI void load4(const uint16_t* ptr, size_t tail, U16* r, U16* g, U16* b, U16* a) { + uint16x4x4_t rgba = vld4_u16(ptr); + *r = rgba.val[0]; + *g = rgba.val[1]; + *b = rgba.val[2]; + *a = rgba.val[3]; + } + SI void store4(uint16_t* ptr, size_t tail, U16 r, U16 g, U16 b, U16 a) { + vst4_u16(ptr, (uint16x4x4_t{{r,g,b,a}})); + } + + SI void load4(const float* ptr, size_t tail, F* r, F* g, F* b, F* a) { + float32x4x4_t rgba = vld4q_f32(ptr); + *r = rgba.val[0]; + *g = rgba.val[1]; + *b = rgba.val[2]; + *a = rgba.val[3]; + } + SI void store4(float* ptr, size_t tail, F r, F g, F b, F a) { + vst4q_f32(ptr, (float32x4x4_t{{r,g,b,a}})); + } + + SI F from_half(U16 h) { return vcvt_f32_f16(h); } + SI U16 to_half(F f) { return vcvt_f16_f32(f); } + +#elif defined(__arm__) + #if defined(__thumb2__) || !defined(__ARM_ARCH_7A__) || !defined(__ARM_VFPV4__) + #error On ARMv7, compile with -march=armv7-a -mfpu=neon-vfp4, without -mthumb. + #endif + #include + + // We can pass {s0-s15} as arguments under AAPCS-VFP. We'll slice that as 8 d-registers. + template using V = T __attribute__((ext_vector_type(2))); + using F = V; + using I32 = V< int32_t>; + using U64 = V; + using U32 = V; + using U16 = V; + using U8 = V; + + SI F mad(F f, F m, F a) { return vfma_f32(a,f,m); } + SI F min(F a, F b) { return vmin_f32(a,b); } + SI F max(F a, F b) { return vmax_f32(a,b); } + SI F abs_ (F v) { return vabs_f32(v); } + SI F rcp (F v) { auto e = vrecpe_f32 (v); return vrecps_f32 (v,e ) * e; } + SI F rsqrt(F v) { auto e = vrsqrte_f32(v); return vrsqrts_f32(v,e*e) * e; } + SI U32 round(F v, F scale) { return vcvt_u32_f32(mad(v,scale,0.5f)); } + SI U16 pack(U32 v) { return __builtin_convertvector(v, U16); } + SI U8 pack(U16 v) { return __builtin_convertvector(v, U8); } + + SI F if_then_else(I32 c, F t, F e) { return vbsl_f32((U32)c,t,e); } + + SI F floor_(F v) { + F roundtrip = vcvt_f32_s32(vcvt_s32_f32(v)); + return roundtrip - if_then_else(roundtrip > v, 1.0_f, 0); + } + + template + SI V gather(const T* p, U32 ix) { + return {p[ix[0]], p[ix[1]]}; + } + + SI void load4(const uint16_t* ptr, size_t tail, U16* r, U16* g, U16* b, U16* a) { + uint16x4x4_t rgba; + rgba = vld4_lane_u16(ptr + 0, rgba, 0); + rgba = vld4_lane_u16(ptr + 4, rgba, 1); + *r = unaligned_load(rgba.val+0); + *g = unaligned_load(rgba.val+1); + *b = unaligned_load(rgba.val+2); + *a = unaligned_load(rgba.val+3); + } + SI void store4(uint16_t* ptr, size_t tail, U16 r, U16 g, U16 b, U16 a) { + uint16x4x4_t rgba = {{ + widen_cast(r), + widen_cast(g), + widen_cast(b), + widen_cast(a), + }}; + vst4_lane_u16(ptr + 0, rgba, 0); + vst4_lane_u16(ptr + 4, rgba, 1); + } + + SI void load4(const float* ptr, size_t tail, F* r, F* g, F* b, F* a) { + float32x2x4_t rgba = vld4_f32(ptr); + *r = rgba.val[0]; + *g = rgba.val[1]; + *b = rgba.val[2]; + *a = rgba.val[3]; + } + SI void store4(float* ptr, size_t tail, F r, F g, F b, F a) { + vst4_f32(ptr, (float32x2x4_t{{r,g,b,a}})); + } + + SI F from_half(U16 h) { + auto v = widen_cast(h); + return vget_low_f32(vcvt_f32_f16(v)); + } + SI U16 to_half(F f) { + auto v = widen_cast(f); + uint16x4_t h = vcvt_f16_f32(v); + return unaligned_load(&h); + } + +#elif defined(__AVX__) + #include + + // These are __m256 and __m256i, but friendlier and strongly-typed. + template using V = T __attribute__((ext_vector_type(8))); + using F = V; + using I32 = V< int32_t>; + using U64 = V; + using U32 = V; + using U16 = V; + using U8 = V; + + SI F mad(F f, F m, F a) { + #if defined(__FMA__) + return _mm256_fmadd_ps(f,m,a); + #else + return f*m+a; + #endif + } + + SI F min(F a, F b) { return _mm256_min_ps(a,b); } + SI F max(F a, F b) { return _mm256_max_ps(a,b); } + SI F abs_ (F v) { return _mm256_and_ps(v, 0-v); } + SI F floor_(F v) { return _mm256_floor_ps(v); } + SI F rcp (F v) { return _mm256_rcp_ps (v); } + SI F rsqrt (F v) { return _mm256_rsqrt_ps(v); } + SI U32 round (F v, F scale) { return _mm256_cvtps_epi32(v*scale); } + + SI U16 pack(U32 v) { + return _mm_packus_epi32(_mm256_extractf128_si256(v, 0), + _mm256_extractf128_si256(v, 1)); + } + SI U8 pack(U16 v) { + auto r = _mm_packus_epi16(v,v); + return unaligned_load(&r); + } + + SI F if_then_else(I32 c, F t, F e) { return _mm256_blendv_ps(e,t,c); } + + template + SI V gather(const T* p, U32 ix) { + return { p[ix[0]], p[ix[1]], p[ix[2]], p[ix[3]], + p[ix[4]], p[ix[5]], p[ix[6]], p[ix[7]], }; + } + #if defined(__AVX2__) + SI F gather(const float* p, U32 ix) { return _mm256_i32gather_ps (p, ix, 4); } + SI U32 gather(const uint32_t* p, U32 ix) { return _mm256_i32gather_epi32(p, ix, 4); } + SI U64 gather(const uint64_t* p, U32 ix) { + __m256i parts[] = { + _mm256_i32gather_epi64(p, _mm256_extracti128_si256(ix,0), 8), + _mm256_i32gather_epi64(p, _mm256_extracti128_si256(ix,1), 8), + }; + return bit_cast(parts); + } + #endif + + SI void load4(const uint16_t* ptr, size_t tail, U16* r, U16* g, U16* b, U16* a) { + __m128i _01, _23, _45, _67; + if (__builtin_expect(tail,0)) { + auto src = (const double*)ptr; + _01 = _23 = _45 = _67 = _mm_setzero_si128(); + if (tail > 0) { _01 = _mm_loadl_pd(_01, src+0); } + if (tail > 1) { _01 = _mm_loadh_pd(_01, src+1); } + if (tail > 2) { _23 = _mm_loadl_pd(_23, src+2); } + if (tail > 3) { _23 = _mm_loadh_pd(_23, src+3); } + if (tail > 4) { _45 = _mm_loadl_pd(_45, src+4); } + if (tail > 5) { _45 = _mm_loadh_pd(_45, src+5); } + if (tail > 6) { _67 = _mm_loadl_pd(_67, src+6); } + } else { + _01 = _mm_loadu_si128(((__m128i*)ptr) + 0); + _23 = _mm_loadu_si128(((__m128i*)ptr) + 1); + _45 = _mm_loadu_si128(((__m128i*)ptr) + 2); + _67 = _mm_loadu_si128(((__m128i*)ptr) + 3); + } + + auto _02 = _mm_unpacklo_epi16(_01, _23), // r0 r2 g0 g2 b0 b2 a0 a2 + _13 = _mm_unpackhi_epi16(_01, _23), // r1 r3 g1 g3 b1 b3 a1 a3 + _46 = _mm_unpacklo_epi16(_45, _67), + _57 = _mm_unpackhi_epi16(_45, _67); + + auto rg0123 = _mm_unpacklo_epi16(_02, _13), // r0 r1 r2 r3 g0 g1 g2 g3 + ba0123 = _mm_unpackhi_epi16(_02, _13), // b0 b1 b2 b3 a0 a1 a2 a3 + rg4567 = _mm_unpacklo_epi16(_46, _57), + ba4567 = _mm_unpackhi_epi16(_46, _57); + + *r = _mm_unpacklo_epi64(rg0123, rg4567); + *g = _mm_unpackhi_epi64(rg0123, rg4567); + *b = _mm_unpacklo_epi64(ba0123, ba4567); + *a = _mm_unpackhi_epi64(ba0123, ba4567); + } + SI void store4(uint16_t* ptr, size_t tail, U16 r, U16 g, U16 b, U16 a) { + auto rg0123 = _mm_unpacklo_epi16(r, g), // r0 g0 r1 g1 r2 g2 r3 g3 + rg4567 = _mm_unpackhi_epi16(r, g), // r4 g4 r5 g5 r6 g6 r7 g7 + ba0123 = _mm_unpacklo_epi16(b, a), + ba4567 = _mm_unpackhi_epi16(b, a); + + auto _01 = _mm_unpacklo_epi32(rg0123, ba0123), + _23 = _mm_unpackhi_epi32(rg0123, ba0123), + _45 = _mm_unpacklo_epi32(rg4567, ba4567), + _67 = _mm_unpackhi_epi32(rg4567, ba4567); + + if (__builtin_expect(tail,0)) { + auto dst = (double*)ptr; + if (tail > 0) { _mm_storel_pd(dst+0, _01); } + if (tail > 1) { _mm_storeh_pd(dst+1, _01); } + if (tail > 2) { _mm_storel_pd(dst+2, _23); } + if (tail > 3) { _mm_storeh_pd(dst+3, _23); } + if (tail > 4) { _mm_storel_pd(dst+4, _45); } + if (tail > 5) { _mm_storeh_pd(dst+5, _45); } + if (tail > 6) { _mm_storel_pd(dst+6, _67); } + } else { + _mm_storeu_si128((__m128i*)ptr + 0, _01); + _mm_storeu_si128((__m128i*)ptr + 1, _23); + _mm_storeu_si128((__m128i*)ptr + 2, _45); + _mm_storeu_si128((__m128i*)ptr + 3, _67); + } + } + + SI void load4(const float* ptr, size_t tail, F* r, F* g, F* b, F* a) { + F _04, _15, _26, _37; + + switch (tail) { + case 0: _37 = _mm256_insertf128_ps(_37, _mm_loadu_ps(ptr+28), 1); + case 7: _26 = _mm256_insertf128_ps(_26, _mm_loadu_ps(ptr+24), 1); + case 6: _15 = _mm256_insertf128_ps(_15, _mm_loadu_ps(ptr+20), 1); + case 5: _04 = _mm256_insertf128_ps(_04, _mm_loadu_ps(ptr+16), 1); + case 4: _37 = _mm256_insertf128_ps(_37, _mm_loadu_ps(ptr+12), 0); + case 3: _26 = _mm256_insertf128_ps(_26, _mm_loadu_ps(ptr+ 8), 0); + case 2: _15 = _mm256_insertf128_ps(_15, _mm_loadu_ps(ptr+ 4), 0); + case 1: _04 = _mm256_insertf128_ps(_04, _mm_loadu_ps(ptr+ 0), 0); + } + + F rg0145 = _mm256_unpacklo_ps(_04,_15), // r0 r1 g0 g1 | r4 r5 g4 g5 + ba0145 = _mm256_unpackhi_ps(_04,_15), + rg2367 = _mm256_unpacklo_ps(_26,_37), + ba2367 = _mm256_unpackhi_ps(_26,_37); + + *r = _mm256_unpacklo_pd(rg0145, rg2367); + *g = _mm256_unpackhi_pd(rg0145, rg2367); + *b = _mm256_unpacklo_pd(ba0145, ba2367); + *a = _mm256_unpackhi_pd(ba0145, ba2367); + } + SI void store4(float* ptr, size_t tail, F r, F g, F b, F a) { + F rg0145 = _mm256_unpacklo_ps(r, g), // r0 g0 r1 g1 | r4 g4 r5 g5 + rg2367 = _mm256_unpackhi_ps(r, g), // r2 ... | r6 ... + ba0145 = _mm256_unpacklo_ps(b, a), // b0 a0 b1 a1 | b4 a4 b5 a5 + ba2367 = _mm256_unpackhi_ps(b, a); // b2 ... | b6 ... + + F _04 = _mm256_unpacklo_pd(rg0145, ba0145), // r0 g0 b0 a0 | r4 g4 b4 a4 + _15 = _mm256_unpackhi_pd(rg0145, ba0145), // r1 ... | r5 ... + _26 = _mm256_unpacklo_pd(rg2367, ba2367), // r2 ... | r6 ... + _37 = _mm256_unpackhi_pd(rg2367, ba2367); // r3 ... | r7 ... + + if (__builtin_expect(tail, 0)) { + if (tail > 0) { _mm_storeu_ps(ptr+ 0, _mm256_extractf128_ps(_04, 0)); } + if (tail > 1) { _mm_storeu_ps(ptr+ 4, _mm256_extractf128_ps(_15, 0)); } + if (tail > 2) { _mm_storeu_ps(ptr+ 8, _mm256_extractf128_ps(_26, 0)); } + if (tail > 3) { _mm_storeu_ps(ptr+12, _mm256_extractf128_ps(_37, 0)); } + if (tail > 4) { _mm_storeu_ps(ptr+16, _mm256_extractf128_ps(_04, 1)); } + if (tail > 5) { _mm_storeu_ps(ptr+20, _mm256_extractf128_ps(_15, 1)); } + if (tail > 6) { _mm_storeu_ps(ptr+24, _mm256_extractf128_ps(_26, 1)); } + } else { + F _01 = _mm256_permute2f128_ps(_04, _15, 32), // 32 == 0010 0000 == lo, lo + _23 = _mm256_permute2f128_ps(_26, _37, 32), + _45 = _mm256_permute2f128_ps(_04, _15, 49), // 49 == 0011 0001 == hi, hi + _67 = _mm256_permute2f128_ps(_26, _37, 49); + _mm256_storeu_ps(ptr+ 0, _01); + _mm256_storeu_ps(ptr+ 8, _23); + _mm256_storeu_ps(ptr+16, _45); + _mm256_storeu_ps(ptr+24, _67); + } + } + + SI F from_half(U16 h) { + #if defined(__AVX2__) + return _mm256_cvtph_ps(h); + #else + // This technique would slow down ~10x for denorm inputs, so we flush them to zero. + // With a signed comparison this conveniently also flushes negative half floats to zero. + h = _mm_andnot_si128(_mm_cmplt_epi16(h, _mm_set1_epi32(0x04000400_i)), h); + + U32 w = _mm256_setr_m128i(_mm_unpacklo_epi16(h, _mm_setzero_si128()), + _mm_unpackhi_epi16(h, _mm_setzero_si128())); + return bit_cast(w << 13) // Line up the mantissa, + * bit_cast(U32(0x77800000_i)); // then fix up the exponent. + #endif + } + SI U16 to_half(F f) { + #if defined(__AVX2__) + return _mm256_cvtps_ph(f, _MM_FROUND_CUR_DIRECTION); + #else + return pack(bit_cast(f * bit_cast(U32(0x07800000_i))) // Fix up the exponent, + >> 13); // then line up the mantissa. + #endif + } + +#elif defined(__SSE2__) + #include + + template using V = T __attribute__((ext_vector_type(4))); + using F = V; + using I32 = V< int32_t>; + using U64 = V; + using U32 = V; + using U16 = V; + using U8 = V; + + SI F mad(F f, F m, F a) { return f*m+a; } + SI F min(F a, F b) { return _mm_min_ps(a,b); } + SI F max(F a, F b) { return _mm_max_ps(a,b); } + SI F abs_(F v) { return _mm_and_ps(v, 0-v); } + SI F rcp (F v) { return _mm_rcp_ps (v); } + SI F rsqrt(F v) { return _mm_rsqrt_ps(v); } + SI U32 round(F v, F scale) { return _mm_cvtps_epi32(v*scale); } + + SI U16 pack(U32 v) { + #if defined(__SSE4_1__) + auto p = _mm_packus_epi32(v,v); + #else + // Sign extend so that _mm_packs_epi32() does the pack we want. + auto p = _mm_srai_epi32(_mm_slli_epi32(v, 16), 16); + p = _mm_packs_epi32(p,p); + #endif + return unaligned_load(&p); // We have two copies. Return (the lower) one. + } + SI U8 pack(U16 v) { + auto r = widen_cast<__m128i>(v); + r = _mm_packus_epi16(r,r); + return unaligned_load(&r); + } + + SI F if_then_else(I32 c, F t, F e) { + return _mm_or_ps(_mm_and_ps(c, t), _mm_andnot_ps(c, e)); + } + + SI F floor_(F v) { + #if defined(__SSE4_1__) + return _mm_floor_ps(v); + #else + F roundtrip = _mm_cvtepi32_ps(_mm_cvttps_epi32(v)); + return roundtrip - if_then_else(roundtrip > v, 1.0_f, 0); + #endif + } + + template + SI V gather(const T* p, U32 ix) { + return {p[ix[0]], p[ix[1]], p[ix[2]], p[ix[3]]}; + } + + SI void load4(const uint16_t* ptr, size_t tail, U16* r, U16* g, U16* b, U16* a) { + auto _01 = _mm_loadu_si128(((__m128i*)ptr) + 0), + _23 = _mm_loadu_si128(((__m128i*)ptr) + 1); + + auto _02 = _mm_unpacklo_epi16(_01, _23), // r0 r2 g0 g2 b0 b2 a0 a2 + _13 = _mm_unpackhi_epi16(_01, _23); // r1 r3 g1 g3 b1 b3 a1 a3 + + auto rg = _mm_unpacklo_epi16(_02, _13), // r0 r1 r2 r3 g0 g1 g2 g3 + ba = _mm_unpackhi_epi16(_02, _13); // b0 b1 b2 b3 a0 a1 a2 a3 + + *r = unaligned_load((uint16_t*)&rg + 0); + *g = unaligned_load((uint16_t*)&rg + 4); + *b = unaligned_load((uint16_t*)&ba + 0); + *a = unaligned_load((uint16_t*)&ba + 4); + } + SI void store4(uint16_t* ptr, size_t tail, U16 r, U16 g, U16 b, U16 a) { + auto rg = _mm_unpacklo_epi16(widen_cast<__m128i>(r), widen_cast<__m128i>(g)), + ba = _mm_unpacklo_epi16(widen_cast<__m128i>(b), widen_cast<__m128i>(a)); + _mm_storeu_si128((__m128i*)ptr + 0, _mm_unpacklo_epi32(rg, ba)); + _mm_storeu_si128((__m128i*)ptr + 1, _mm_unpackhi_epi32(rg, ba)); + } + + SI void load4(const float* ptr, size_t tail, F* r, F* g, F* b, F* a) { + auto _0 = _mm_loadu_ps(ptr+ 0), + _1 = _mm_loadu_ps(ptr+ 4), + _2 = _mm_loadu_ps(ptr+ 8), + _3 = _mm_loadu_ps(ptr+12); + _MM_TRANSPOSE4_PS(_0,_1,_2,_3); + *r = _0; + *g = _1; + *b = _2; + *a = _3; + } + SI void store4(float* ptr, size_t tail, F r, F g, F b, F a) { + _MM_TRANSPOSE4_PS(r,g,b,a); + _mm_storeu_ps(ptr+ 0, r); + _mm_storeu_ps(ptr+ 4, g); + _mm_storeu_ps(ptr+ 8, b); + _mm_storeu_ps(ptr+12, a); + } + + SI F from_half(U16 h) { + auto v = widen_cast<__m128i>(h); + + // Same deal as AVX: flush denorms and negatives to zero. + v = _mm_andnot_si128(_mm_cmplt_epi16(v, _mm_set1_epi32(0x04000400_i)), v); + + U32 w = _mm_unpacklo_epi16(v, _mm_setzero_si128()); + return bit_cast(w << 13) // Line up the mantissa, + * bit_cast(U32(0x77800000_i)); // then fix up the exponent. + } + SI U16 to_half(F f) { + return pack(bit_cast(f * bit_cast(U32(0x07800000_i))) // Fix up the exponent, + >> 13); // then line up the mantissa. + } +#endif + +// We need to be a careful with casts. +// (F)x means cast x to float in the portable path, but bit_cast x to float in the others. +// These named casts and bit_cast() are always what they seem to be. +#if defined(JUMPER) + SI F cast (U32 v) { return __builtin_convertvector((I32)v, F); } + SI U32 trunc_(F v) { return (U32)__builtin_convertvector( v, I32); } + SI U32 expand(U16 v) { return __builtin_convertvector( v, U32); } + SI U32 expand(U8 v) { return __builtin_convertvector( v, U32); } +#else + SI F cast (U32 v) { return (F)v; } + SI U32 trunc_(F v) { return (U32)v; } + SI U32 expand(U16 v) { return (U32)v; } + SI U32 expand(U8 v) { return (U32)v; } +#endif + +SI U16 bswap(U16 x) { +#if defined(JUMPER) && defined(__SSE2__) && !defined(__AVX__) + // Somewhat inexplicably Clang decides to do (x<<8) | (x>>8) in 32-bit lanes + // when generating code for SSE2 and SSE4.1. We'll do it manually... + auto v = widen_cast<__m128i>(x); + v = _mm_slli_epi16(v,8) | _mm_srli_epi16(v,8); + return unaligned_load(&v); +#else + return (x<<8) | (x>>8); +#endif +} + +#endif//SkJumper_vectors_DEFINED diff --git a/gfx/skia/skia/src/jumper/build_stages.py b/gfx/skia/skia/src/jumper/build_stages.py new file mode 100755 index 000000000000..81f8697bd947 --- /dev/null +++ b/gfx/skia/skia/src/jumper/build_stages.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python2.7 +# +# Copyright 2017 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import re +import subprocess +import sys + +clang = sys.argv[1] if len(sys.argv) > 1 else 'clang-4.0' +objdump = sys.argv[2] if len(sys.argv) > 2 else 'gobjdump' + +clang = ['ccache', clang, '-x', 'c++'] + + +cflags = ['-std=c++11', '-Os', '-DJUMPER', + '-fomit-frame-pointer', '-ffp-contract=fast', + '-fno-exceptions', '-fno-rtti', '-fno-unwind-tables'] + +win = ['-DWIN', '-mno-red-zone'] +sse2 = ['-msse2', '-mno-sse3', '-mno-ssse3', '-mno-sse4.1'] +subprocess.check_call(clang + cflags + sse2 + + ['-c', 'src/jumper/SkJumper_stages.cpp'] + + ['-o', 'sse2.o']) +subprocess.check_call(clang + cflags + sse2 + win + + ['-c', 'src/jumper/SkJumper_stages.cpp'] + + ['-o', 'win_sse2.o']) + +sse41 = ['-msse4.1'] +subprocess.check_call(clang + cflags + sse41 + + ['-c', 'src/jumper/SkJumper_stages.cpp'] + + ['-o', 'sse41.o']) +subprocess.check_call(clang + cflags + sse41 + win + + ['-c', 'src/jumper/SkJumper_stages.cpp'] + + ['-o', 'win_sse41.o']) + +avx = ['-mavx'] +subprocess.check_call(clang + cflags + avx + + ['-c', 'src/jumper/SkJumper_stages.cpp'] + + ['-o', 'avx.o']) +subprocess.check_call(clang + cflags + avx + win + + ['-c', 'src/jumper/SkJumper_stages.cpp'] + + ['-o', 'win_avx.o']) + +hsw = ['-mavx2', '-mfma', '-mf16c'] +subprocess.check_call(clang + cflags + hsw + + ['-c', 'src/jumper/SkJumper_stages.cpp'] + + ['-o', 'hsw.o']) +subprocess.check_call(clang + cflags + hsw + win + + ['-c', 'src/jumper/SkJumper_stages.cpp'] + + ['-o', 'win_hsw.o']) + +aarch64 = [ '--target=aarch64' ] +subprocess.check_call(clang + cflags + aarch64 + + ['-c', 'src/jumper/SkJumper_stages.cpp'] + + ['-o', 'aarch64.o']) + +vfp4 = [ + '--target=armv7a-linux-gnueabihf', + '-mfpu=neon-vfpv4', +] +subprocess.check_call(clang + cflags + vfp4 + + ['-c', 'src/jumper/SkJumper_stages.cpp'] + + ['-o', 'vfp4.o']) + +def parse_object_file(dot_o, directive, target=None): + globl, hidden, label, comment = '.globl', 'HIDDEN', ':', '// ' + if 'win' in dot_o: + globl, hidden, label, comment = 'PUBLIC', '', ' LABEL PROC', '; ' + + dehex = lambda h: '0x'+h + if directive != '.long': + dehex = lambda h: str(int(h,16)) + + cmd = [objdump] + if target: + cmd += ['--target', target] + + # Look for sections we know we can't handle. + section_headers = subprocess.check_output(cmd + ['-h', dot_o]) + for snippet in ['.literal', '.const', '.rodata']: + if snippet in section_headers: + print >>sys.stderr, 'Found %s in section.' % snippet + assert snippet not in section_headers + + # Ok. Let's disassemble. + disassemble = ['-d', '--insn-width=10', dot_o] + for line in subprocess.check_output(cmd + disassemble).split('\n'): + line = line.strip() + + if not line or line.startswith(dot_o) or line.startswith('Disassembly'): + continue + + # E.g. 00000000000003a4 <_load_f16>: + m = re.match('''[0-9a-f]+ <_?(.*)>:''', line) + if m: + print + if hidden: + print hidden + ' _' + m.group(1) + print globl + ' _' + m.group(1) + print '_' + m.group(1) + label + continue + + columns = line.split('\t') + code = columns[1] + if len(columns) >= 4: + inst = columns[2] + args = columns[3] + else: + inst, args = columns[2], '' + if ' ' in columns[2]: + inst, args = columns[2].split(' ', 1) + code, inst, args = code.strip(), inst.strip(), args.strip() + + hexed = ','.join(dehex(x) for x in code.split(' ')) + print ' ' + directive + ' ' + hexed + ' '*(36-len(hexed)) + \ + comment + inst + (' '*(14-len(inst)) + args if args else '') + +sys.stdout = open('src/jumper/SkJumper_generated.S', 'w') + +print '''# Copyright 2017 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file is generated semi-automatically with this command: +# $ src/jumper/build_stages.py +''' +print '#if defined(__MACH__)' +print ' #define HIDDEN .private_extern' +print '#else' +print ' #define HIDDEN .hidden' +print ' .section .note.GNU-stack,"",%progbits' +print '#endif' + +print '.text' +print '#if defined(__aarch64__)' +print '.balign 4' +parse_object_file('aarch64.o', '.long') + +print '#elif defined(__arm__)' +print '.balign 4' +parse_object_file('vfp4.o', '.long', target='elf32-littlearm') + +print '#elif defined(__x86_64__)' +parse_object_file('hsw.o', '.byte') +parse_object_file('avx.o', '.byte') +parse_object_file('sse41.o', '.byte') +parse_object_file('sse2.o', '.byte') + +print '#endif' + +sys.stdout = open('src/jumper/SkJumper_generated_win.S', 'w') +print '''; Copyright 2017 Google Inc. +; +; Use of this source code is governed by a BSD-style license that can be +; found in the LICENSE file. + +; This file is generated semi-automatically with this command: +; $ src/jumper/build_stages.py +''' + +print 'IFDEF RAX' +print '_text SEGMENT' +parse_object_file('win_hsw.o', 'DB') +parse_object_file('win_avx.o', 'DB') +parse_object_file('win_sse41.o', 'DB') +parse_object_file('win_sse2.o', 'DB') +print 'ENDIF' +print 'END' diff --git a/gfx/skia/skia/src/lazy/SkDiscardableMemoryPool.cpp b/gfx/skia/skia/src/lazy/SkDiscardableMemoryPool.cpp index 6ced5bfc027d..8a6cb526b395 100644 --- a/gfx/skia/skia/src/lazy/SkDiscardableMemoryPool.cpp +++ b/gfx/skia/skia/src/lazy/SkDiscardableMemoryPool.cpp @@ -8,6 +8,7 @@ #include "SkDiscardableMemory.h" #include "SkDiscardableMemoryPool.h" #include "SkImageGenerator.h" +#include "SkMalloc.h" #include "SkMutex.h" #include "SkOnce.h" #include "SkTInternalLList.h" @@ -30,7 +31,7 @@ public: * Without mutex, will be not be thread safe. */ DiscardableMemoryPool(size_t budget, SkBaseMutex* mutex = nullptr); - virtual ~DiscardableMemoryPool(); + ~DiscardableMemoryPool() override; SkDiscardableMemory* create(size_t bytes) override; @@ -79,7 +80,7 @@ class PoolDiscardableMemory : public SkDiscardableMemory { public: PoolDiscardableMemory(DiscardableMemoryPool* pool, void* pointer, size_t bytes); - virtual ~PoolDiscardableMemory(); + ~PoolDiscardableMemory() override; bool lock() override; void* data() override; void unlock() override; diff --git a/gfx/skia/skia/src/lazy/SkDiscardablePixelRef.cpp b/gfx/skia/skia/src/lazy/SkDiscardablePixelRef.cpp deleted file mode 100644 index ba4a50ff823a..000000000000 --- a/gfx/skia/skia/src/lazy/SkDiscardablePixelRef.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkDiscardablePixelRef.h" -#include "SkDiscardableMemory.h" -#include "SkImageGenerator.h" - -SkDiscardablePixelRef::SkDiscardablePixelRef(const SkImageInfo& info, - SkImageGenerator* generator, - size_t rowBytes, - SkDiscardableMemory::Factory* fact) - : INHERITED(info) - , fGenerator(generator) - , fDMFactory(fact) - , fRowBytes(rowBytes) - , fDiscardableMemory(nullptr) - , fDiscardableMemoryIsLocked(false) -{ - SkASSERT(fGenerator != nullptr); - SkASSERT(fRowBytes > 0); - // The SkImageGenerator contract requires fGenerator to always - // decode the same image on each call to getPixels(). - this->setImmutable(); - SkSafeRef(fDMFactory); -} - -SkDiscardablePixelRef::~SkDiscardablePixelRef() { - if (fDiscardableMemoryIsLocked) { - fDiscardableMemory->unlock(); - fDiscardableMemoryIsLocked = false; - } - delete fDiscardableMemory; - SkSafeUnref(fDMFactory); - delete fGenerator; -} - -bool SkDiscardablePixelRef::onNewLockPixels(LockRec* rec) { - if (fDiscardableMemory != nullptr) { - if (fDiscardableMemory->lock()) { - fDiscardableMemoryIsLocked = true; - rec->fPixels = fDiscardableMemory->data(); - rec->fColorTable = fCTable.get(); - rec->fRowBytes = fRowBytes; - return true; - } - delete fDiscardableMemory; - fDiscardableMemory = nullptr; - fDiscardableMemoryIsLocked = false; - } - - const size_t size = this->info().getSafeSize(fRowBytes); - - if (fDMFactory != nullptr) { - fDiscardableMemory = fDMFactory->create(size); - fDiscardableMemoryIsLocked = true; - } else { - fDiscardableMemory = SkDiscardableMemory::Create(size); - fDiscardableMemoryIsLocked = true; - } - if (nullptr == fDiscardableMemory) { - fDiscardableMemoryIsLocked = false; - return false; // Memory allocation failed. - } - - void* pixels = fDiscardableMemory->data(); - const SkImageInfo& info = this->info(); - SkPMColor colors[256]; - int colorCount = 0; - - if (!fGenerator->getPixels(info, pixels, fRowBytes, colors, &colorCount)) { - fDiscardableMemory->unlock(); - fDiscardableMemoryIsLocked = false; - delete fDiscardableMemory; - fDiscardableMemory = nullptr; - return false; - } - - // Note: our ctable is not purgeable, as it is not stored in the discardablememory block. - // This is because SkColorTable is refcntable, and therefore our caller could hold onto it - // beyond the scope of a lock/unlock. If we change the API/lifecycle for SkColorTable, we - // could move it into the block, but then again perhaps it is small enough that this doesn't - // really matter. - if (colorCount > 0) { - fCTable.reset(new SkColorTable(colors, colorCount)); - } else { - fCTable.reset(nullptr); - } - - rec->fPixels = pixels; - rec->fColorTable = fCTable.get(); - rec->fRowBytes = fRowBytes; - return true; -} - -void SkDiscardablePixelRef::onUnlockPixels() { - fDiscardableMemory->unlock(); - fDiscardableMemoryIsLocked = false; -} - -bool SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator* generator, const SkIRect* subset, - SkBitmap* dst, SkDiscardableMemory::Factory* factory) { - SkAutoTDelete autoGenerator(generator); - if (nullptr == autoGenerator.get()) { - return false; - } - - SkImageInfo prInfo = autoGenerator->getInfo(); - if (prInfo.isEmpty()) { - return false; - } - - SkIPoint origin = SkIPoint::Make(0, 0); - SkImageInfo bmInfo = prInfo; - if (subset) { - const SkIRect prBounds = SkIRect::MakeWH(prInfo.width(), prInfo.height()); - if (subset->isEmpty() || !prBounds.contains(*subset)) { - return false; - } - bmInfo = prInfo.makeWH(subset->width(), subset->height()); - origin.set(subset->x(), subset->y()); - } - - // must compute our desired rowBytes w.r.t. the pixelRef's dimensions, not ours, which may be - // smaller. - if (!dst->setInfo(bmInfo, prInfo.minRowBytes())) { - return false; - } - - // Since dst->setInfo() may have changed/fixed-up info, we check from the bitmap - SkASSERT(dst->info().colorType() != kUnknown_SkColorType); - - if (dst->empty()) { // Use a normal pixelref. - return dst->tryAllocPixels(); - } - SkAutoTUnref ref( - new SkDiscardablePixelRef(prInfo, autoGenerator.release(), dst->rowBytes(), factory)); - dst->setPixelRef(ref, origin.x(), origin.y()); - return true; -} - -// These are the public API - -bool SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) { - return SkDEPRECATED_InstallDiscardablePixelRef(generator, nullptr, dst, nullptr); -} - -bool SkDEPRECATED_InstallDiscardablePixelRef(SkData* encoded, SkBitmap* dst) { - SkImageGenerator* generator = SkImageGenerator::NewFromEncoded(encoded); - return generator ? - SkDEPRECATED_InstallDiscardablePixelRef(generator, nullptr, dst, nullptr) : false; -} diff --git a/gfx/skia/skia/src/lazy/SkDiscardablePixelRef.h b/gfx/skia/skia/src/lazy/SkDiscardablePixelRef.h deleted file mode 100644 index 73a2b082501b..000000000000 --- a/gfx/skia/skia/src/lazy/SkDiscardablePixelRef.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkDiscardablePixelRef_DEFINED -#define SkDiscardablePixelRef_DEFINED - -#include "SkDiscardableMemory.h" -#include "SkImageGeneratorPriv.h" -#include "SkImageInfo.h" -#include "SkPixelRef.h" - -/** - * A PixelRef backed by SkDiscardableMemory, with the ability to - * re-generate the pixels (via a SkImageGenerator) if the DM is - * purged. - */ -class SkDiscardablePixelRef : public SkPixelRef { -public: - - SkDiscardableMemory* diagnostic_only_getDiscardable() const override { - return fDiscardableMemory; - } - -protected: - ~SkDiscardablePixelRef(); - - bool onNewLockPixels(LockRec*) override; - void onUnlockPixels() override; - bool onLockPixelsAreWritable() const override { return false; } - - SkData* onRefEncodedData() override { - return fGenerator->refEncodedData(); - } - - bool onIsLazyGenerated() const override { return true; } - -private: - SkImageGenerator* const fGenerator; - SkDiscardableMemory::Factory* const fDMFactory; - const size_t fRowBytes; - // These const members should not change over the life of the - // PixelRef, since the SkBitmap doesn't expect them to change. - - SkDiscardableMemory* fDiscardableMemory; - bool fDiscardableMemoryIsLocked; - SkAutoTUnref fCTable; - - /* Takes ownership of SkImageGenerator. */ - SkDiscardablePixelRef(const SkImageInfo&, SkImageGenerator*, - size_t rowBytes, - SkDiscardableMemory::Factory* factory); - - bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override { - // If the image was already decoded with lockPixels(), favor not - // re-decoding to YUV8 planes. - if (fDiscardableMemory) { - return false; - } - return fGenerator->queryYUV8(sizeInfo, colorSpace); - } - - bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override { - // If the image was already decoded with lockPixels(), favor not - // re-decoding to YUV8 planes. - if (fDiscardableMemory) { - return false; - } - return fGenerator->getYUV8Planes(sizeInfo, planes); - } - - friend bool SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator*, const SkIRect*, SkBitmap*, - SkDiscardableMemory::Factory*); - - typedef SkPixelRef INHERITED; -}; - -#endif // SkDiscardablePixelRef_DEFINED diff --git a/gfx/skia/skia/src/opts/SkBitmapFilter_opts.h b/gfx/skia/skia/src/opts/SkBitmapFilter_opts.h new file mode 100644 index 000000000000..4f21c579fb34 --- /dev/null +++ b/gfx/skia/skia/src/opts/SkBitmapFilter_opts.h @@ -0,0 +1,940 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBitmapFilter_opts_DEFINED +#define SkBitmapFilter_opts_DEFINED + +#include "SkConvolver.h" + +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + #include +#elif defined(SK_ARM_HAS_NEON) + #include +#endif + +namespace SK_OPTS_NS { + +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + + static SK_ALWAYS_INLINE void AccumRemainder(const unsigned char* pixelsLeft, + const SkConvolutionFilter1D::ConvolutionFixed* filterValues, __m128i& accum, int r) { + int remainder[4] = {0}; + for (int i = 0; i < r; i++) { + SkConvolutionFilter1D::ConvolutionFixed coeff = filterValues[i]; + remainder[0] += coeff * pixelsLeft[i * 4 + 0]; + remainder[1] += coeff * pixelsLeft[i * 4 + 1]; + remainder[2] += coeff * pixelsLeft[i * 4 + 2]; + remainder[3] += coeff * pixelsLeft[i * 4 + 3]; + } + __m128i t = _mm_setr_epi32(remainder[0], remainder[1], remainder[2], remainder[3]); + accum = _mm_add_epi32(accum, t); + } + + // Convolves horizontally along a single row. The row data is given in + // |srcData| and continues for the numValues() of the filter. + void convolve_horizontally(const unsigned char* srcData, + const SkConvolutionFilter1D& filter, + unsigned char* outRow, + bool /*hasAlpha*/) { + // Output one pixel each iteration, calculating all channels (RGBA) together. + int numValues = filter.numValues(); + for (int outX = 0; outX < numValues; outX++) { + // Get the filter that determines the current output pixel. + int filterOffset, filterLength; + const SkConvolutionFilter1D::ConvolutionFixed* filterValues = + filter.FilterForValue(outX, &filterOffset, &filterLength); + + // Compute the first pixel in this row that the filter affects. It will + // touch |filterLength| pixels (4 bytes each) after this. + const unsigned char* rowToFilter = &srcData[filterOffset * 4]; + + __m128i zero = _mm_setzero_si128(); + __m128i accum = _mm_setzero_si128(); + + // We will load and accumulate with four coefficients per iteration. + for (int filterX = 0; filterX < filterLength >> 2; filterX++) { + // Load 4 coefficients => duplicate 1st and 2nd of them for all channels. + __m128i coeff, coeff16; + // [16] xx xx xx xx c3 c2 c1 c0 + coeff = _mm_loadl_epi64(reinterpret_cast(filterValues)); + // [16] xx xx xx xx c1 c1 c0 c0 + coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); + // [16] c1 c1 c1 c1 c0 c0 c0 c0 + coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); + + // Load four pixels => unpack the first two pixels to 16 bits => + // multiply with coefficients => accumulate the convolution result. + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + __m128i src8 = _mm_loadu_si128(reinterpret_cast(rowToFilter)); + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + __m128i src16 = _mm_unpacklo_epi8(src8, zero); + __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); + __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a0*c0 b0*c0 g0*c0 r0*c0 + __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + // [32] a1*c1 b1*c1 g1*c1 r1*c1 + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + + // Duplicate 3rd and 4th coefficients for all channels => + // unpack the 3rd and 4th pixels to 16 bits => multiply with coefficients + // => accumulate the convolution results. + // [16] xx xx xx xx c3 c3 c2 c2 + coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); + // [16] c3 c3 c3 c3 c2 c2 c2 c2 + coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); + // [16] a3 g3 b3 r3 a2 g2 b2 r2 + src16 = _mm_unpackhi_epi8(src8, zero); + mul_hi = _mm_mulhi_epi16(src16, coeff16); + mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a2*c2 b2*c2 g2*c2 r2*c2 + t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + // [32] a3*c3 b3*c3 g3*c3 r3*c3 + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + + // Advance the pixel and coefficients pointers. + rowToFilter += 16; + filterValues += 4; + } + + // When |filterLength| is not divisible by 4, we accumulate the last 1 - 3 + // coefficients one at a time. + int r = filterLength & 3; + if (r) { + int remainderOffset = (filterOffset + filterLength - r) * 4; + AccumRemainder(srcData + remainderOffset, filterValues, accum, r); + } + + // Shift right for fixed point implementation. + accum = _mm_srai_epi32(accum, SkConvolutionFilter1D::kShiftBits); + + // Packing 32 bits |accum| to 16 bits per channel (signed saturation). + accum = _mm_packs_epi32(accum, zero); + // Packing 16 bits |accum| to 8 bits per channel (unsigned saturation). + accum = _mm_packus_epi16(accum, zero); + + // Store the pixel value of 32 bits. + *(reinterpret_cast(outRow)) = _mm_cvtsi128_si32(accum); + outRow += 4; + } + } + + // Convolves horizontally along four rows. The row data is given in + // |srcData| and continues for the numValues() of the filter. + // The algorithm is almost same as |convolve_horizontally|. Please + // refer to that function for detailed comments. + void convolve_4_rows_horizontally(const unsigned char* srcData[4], + const SkConvolutionFilter1D& filter, + unsigned char* outRow[4], + size_t outRowBytes) { + SkDEBUGCODE(const unsigned char* out_row_0_start = outRow[0];) + + // Output one pixel each iteration, calculating all channels (RGBA) together. + int numValues = filter.numValues(); + for (int outX = 0; outX < numValues; outX++) { + int filterOffset, filterLength; + const SkConvolutionFilter1D::ConvolutionFixed* filterValues = + filter.FilterForValue(outX, &filterOffset, &filterLength); + + __m128i zero = _mm_setzero_si128(); + + // four pixels in a column per iteration. + __m128i accum0 = _mm_setzero_si128(); + __m128i accum1 = _mm_setzero_si128(); + __m128i accum2 = _mm_setzero_si128(); + __m128i accum3 = _mm_setzero_si128(); + + int start = filterOffset * 4; + // We will load and accumulate with four coefficients per iteration. + for (int filterX = 0; filterX < (filterLength >> 2); filterX++) { + __m128i coeff, coeff16lo, coeff16hi; + // [16] xx xx xx xx c3 c2 c1 c0 + coeff = _mm_loadl_epi64(reinterpret_cast(filterValues)); + // [16] xx xx xx xx c1 c1 c0 c0 + coeff16lo = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); + // [16] c1 c1 c1 c1 c0 c0 c0 c0 + coeff16lo = _mm_unpacklo_epi16(coeff16lo, coeff16lo); + // [16] xx xx xx xx c3 c3 c2 c2 + coeff16hi = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); + // [16] c3 c3 c3 c3 c2 c2 c2 c2 + coeff16hi = _mm_unpacklo_epi16(coeff16hi, coeff16hi); + + __m128i src8, src16, mul_hi, mul_lo, t; + +#define ITERATION(src, accum) \ + src8 = _mm_loadu_si128(reinterpret_cast(src)); \ + src16 = _mm_unpacklo_epi8(src8, zero); \ + mul_hi = _mm_mulhi_epi16(src16, coeff16lo); \ + mul_lo = _mm_mullo_epi16(src16, coeff16lo); \ + t = _mm_unpacklo_epi16(mul_lo, mul_hi); \ + accum = _mm_add_epi32(accum, t); \ + t = _mm_unpackhi_epi16(mul_lo, mul_hi); \ + accum = _mm_add_epi32(accum, t); \ + src16 = _mm_unpackhi_epi8(src8, zero); \ + mul_hi = _mm_mulhi_epi16(src16, coeff16hi); \ + mul_lo = _mm_mullo_epi16(src16, coeff16hi); \ + t = _mm_unpacklo_epi16(mul_lo, mul_hi); \ + accum = _mm_add_epi32(accum, t); \ + t = _mm_unpackhi_epi16(mul_lo, mul_hi); \ + accum = _mm_add_epi32(accum, t) + + ITERATION(srcData[0] + start, accum0); + ITERATION(srcData[1] + start, accum1); + ITERATION(srcData[2] + start, accum2); + ITERATION(srcData[3] + start, accum3); + + start += 16; + filterValues += 4; + } + + int r = filterLength & 3; + if (r) { + int remainderOffset = (filterOffset + filterLength - r) * 4; + AccumRemainder(srcData[0] + remainderOffset, filterValues, accum0, r); + AccumRemainder(srcData[1] + remainderOffset, filterValues, accum1, r); + AccumRemainder(srcData[2] + remainderOffset, filterValues, accum2, r); + AccumRemainder(srcData[3] + remainderOffset, filterValues, accum3, r); + } + + accum0 = _mm_srai_epi32(accum0, SkConvolutionFilter1D::kShiftBits); + accum0 = _mm_packs_epi32(accum0, zero); + accum0 = _mm_packus_epi16(accum0, zero); + accum1 = _mm_srai_epi32(accum1, SkConvolutionFilter1D::kShiftBits); + accum1 = _mm_packs_epi32(accum1, zero); + accum1 = _mm_packus_epi16(accum1, zero); + accum2 = _mm_srai_epi32(accum2, SkConvolutionFilter1D::kShiftBits); + accum2 = _mm_packs_epi32(accum2, zero); + accum2 = _mm_packus_epi16(accum2, zero); + accum3 = _mm_srai_epi32(accum3, SkConvolutionFilter1D::kShiftBits); + accum3 = _mm_packs_epi32(accum3, zero); + accum3 = _mm_packus_epi16(accum3, zero); + + // We seem to be running off the edge here (chromium:491660). + SkASSERT(((size_t)outRow[0] - (size_t)out_row_0_start) < outRowBytes); + + *(reinterpret_cast(outRow[0])) = _mm_cvtsi128_si32(accum0); + *(reinterpret_cast(outRow[1])) = _mm_cvtsi128_si32(accum1); + *(reinterpret_cast(outRow[2])) = _mm_cvtsi128_si32(accum2); + *(reinterpret_cast(outRow[3])) = _mm_cvtsi128_si32(accum3); + + outRow[0] += 4; + outRow[1] += 4; + outRow[2] += 4; + outRow[3] += 4; + } + } + + // Does vertical convolution to produce one output row. The filter values and + // length are given in the first two parameters. These are applied to each + // of the rows pointed to in the |sourceDataRows| array, with each row + // being |pixelWidth| wide. + // + // The output must have room for |pixelWidth * 4| bytes. + template + void ConvolveVertically(const SkConvolutionFilter1D::ConvolutionFixed* filterValues, + int filterLength, + unsigned char* const* sourceDataRows, + int pixelWidth, + unsigned char* outRow) { + // Output four pixels per iteration (16 bytes). + int width = pixelWidth & ~3; + __m128i zero = _mm_setzero_si128(); + for (int outX = 0; outX < width; outX += 4) { + // Accumulated result for each pixel. 32 bits per RGBA channel. + __m128i accum0 = _mm_setzero_si128(); + __m128i accum1 = _mm_setzero_si128(); + __m128i accum2 = _mm_setzero_si128(); + __m128i accum3 = _mm_setzero_si128(); + + // Convolve with one filter coefficient per iteration. + for (int filterY = 0; filterY < filterLength; filterY++) { + + // Duplicate the filter coefficient 8 times. + // [16] cj cj cj cj cj cj cj cj + __m128i coeff16 = _mm_set1_epi16(filterValues[filterY]); + + // Load four pixels (16 bytes) together. + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + const __m128i* src = reinterpret_cast( + &sourceDataRows[filterY][outX << 2]); + __m128i src8 = _mm_loadu_si128(src); + + // Unpack 1st and 2nd pixels from 8 bits to 16 bits for each channels => + // multiply with current coefficient => accumulate the result. + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + __m128i src16 = _mm_unpacklo_epi8(src8, zero); + __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); + __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a0 b0 g0 r0 + __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum0 = _mm_add_epi32(accum0, t); + // [32] a1 b1 g1 r1 + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum1 = _mm_add_epi32(accum1, t); + + // Unpack 3rd and 4th pixels from 8 bits to 16 bits for each channels => + // multiply with current coefficient => accumulate the result. + // [16] a3 b3 g3 r3 a2 b2 g2 r2 + src16 = _mm_unpackhi_epi8(src8, zero); + mul_hi = _mm_mulhi_epi16(src16, coeff16); + mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a2 b2 g2 r2 + t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum2 = _mm_add_epi32(accum2, t); + // [32] a3 b3 g3 r3 + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum3 = _mm_add_epi32(accum3, t); + } + + // Shift right for fixed point implementation. + accum0 = _mm_srai_epi32(accum0, SkConvolutionFilter1D::kShiftBits); + accum1 = _mm_srai_epi32(accum1, SkConvolutionFilter1D::kShiftBits); + accum2 = _mm_srai_epi32(accum2, SkConvolutionFilter1D::kShiftBits); + accum3 = _mm_srai_epi32(accum3, SkConvolutionFilter1D::kShiftBits); + + // Packing 32 bits |accum| to 16 bits per channel (signed saturation). + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + accum0 = _mm_packs_epi32(accum0, accum1); + // [16] a3 b3 g3 r3 a2 b2 g2 r2 + accum2 = _mm_packs_epi32(accum2, accum3); + + // Packing 16 bits |accum| to 8 bits per channel (unsigned saturation). + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + accum0 = _mm_packus_epi16(accum0, accum2); + + if (hasAlpha) { + // Compute the max(ri, gi, bi) for each pixel. + // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 + __m128i a = _mm_srli_epi32(accum0, 8); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + __m128i b = _mm_max_epu8(a, accum0); // Max of r and g. + // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 + a = _mm_srli_epi32(accum0, 16); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + b = _mm_max_epu8(a, b); // Max of r and g and b. + // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 + b = _mm_slli_epi32(b, 24); + + // Make sure the value of alpha channel is always larger than maximum + // value of color channels. + accum0 = _mm_max_epu8(b, accum0); + } else { + // Set value of alpha channels to 0xFF. + __m128i mask = _mm_set1_epi32(0xff000000); + accum0 = _mm_or_si128(accum0, mask); + } + + // Store the convolution result (16 bytes) and advance the pixel pointers. + _mm_storeu_si128(reinterpret_cast<__m128i*>(outRow), accum0); + outRow += 16; + } + + // When the width of the output is not divisible by 4, We need to save one + // pixel (4 bytes) each time. And also the fourth pixel is always absent. + int r = pixelWidth & 3; + if (r) { + __m128i accum0 = _mm_setzero_si128(); + __m128i accum1 = _mm_setzero_si128(); + __m128i accum2 = _mm_setzero_si128(); + for (int filterY = 0; filterY < filterLength; ++filterY) { + __m128i coeff16 = _mm_set1_epi16(filterValues[filterY]); + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + const __m128i* src = reinterpret_cast( + &sourceDataRows[filterY][width << 2]); + __m128i src8 = _mm_loadu_si128(src); + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + __m128i src16 = _mm_unpacklo_epi8(src8, zero); + __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); + __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a0 b0 g0 r0 + __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum0 = _mm_add_epi32(accum0, t); + // [32] a1 b1 g1 r1 + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum1 = _mm_add_epi32(accum1, t); + // [16] a3 b3 g3 r3 a2 b2 g2 r2 + src16 = _mm_unpackhi_epi8(src8, zero); + mul_hi = _mm_mulhi_epi16(src16, coeff16); + mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a2 b2 g2 r2 + t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum2 = _mm_add_epi32(accum2, t); + } + + accum0 = _mm_srai_epi32(accum0, SkConvolutionFilter1D::kShiftBits); + accum1 = _mm_srai_epi32(accum1, SkConvolutionFilter1D::kShiftBits); + accum2 = _mm_srai_epi32(accum2, SkConvolutionFilter1D::kShiftBits); + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + accum0 = _mm_packs_epi32(accum0, accum1); + // [16] a3 b3 g3 r3 a2 b2 g2 r2 + accum2 = _mm_packs_epi32(accum2, zero); + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + accum0 = _mm_packus_epi16(accum0, accum2); + if (hasAlpha) { + // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 + __m128i a = _mm_srli_epi32(accum0, 8); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + __m128i b = _mm_max_epu8(a, accum0); // Max of r and g. + // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 + a = _mm_srli_epi32(accum0, 16); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + b = _mm_max_epu8(a, b); // Max of r and g and b. + // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 + b = _mm_slli_epi32(b, 24); + accum0 = _mm_max_epu8(b, accum0); + } else { + __m128i mask = _mm_set1_epi32(0xff000000); + accum0 = _mm_or_si128(accum0, mask); + } + + for (int i = 0; i < r; i++) { + *(reinterpret_cast(outRow)) = _mm_cvtsi128_si32(accum0); + accum0 = _mm_srli_si128(accum0, 4); + outRow += 4; + } + } + } + +#elif defined(SK_ARM_HAS_NEON) + + static SK_ALWAYS_INLINE void AccumRemainder(const unsigned char* pixelsLeft, + const SkConvolutionFilter1D::ConvolutionFixed* filterValues, int32x4_t& accum, int r) { + int remainder[4] = {0}; + for (int i = 0; i < r; i++) { + SkConvolutionFilter1D::ConvolutionFixed coeff = filterValues[i]; + remainder[0] += coeff * pixelsLeft[i * 4 + 0]; + remainder[1] += coeff * pixelsLeft[i * 4 + 1]; + remainder[2] += coeff * pixelsLeft[i * 4 + 2]; + remainder[3] += coeff * pixelsLeft[i * 4 + 3]; + } + int32x4_t t = {remainder[0], remainder[1], remainder[2], remainder[3]}; + accum += t; + } + + // Convolves horizontally along a single row. The row data is given in + // |srcData| and continues for the numValues() of the filter. + void convolve_horizontally(const unsigned char* srcData, + const SkConvolutionFilter1D& filter, + unsigned char* outRow, + bool /*hasAlpha*/) { + // Loop over each pixel on this row in the output image. + int numValues = filter.numValues(); + for (int outX = 0; outX < numValues; outX++) { + uint8x8_t coeff_mask0 = vcreate_u8(0x0100010001000100); + uint8x8_t coeff_mask1 = vcreate_u8(0x0302030203020302); + uint8x8_t coeff_mask2 = vcreate_u8(0x0504050405040504); + uint8x8_t coeff_mask3 = vcreate_u8(0x0706070607060706); + // Get the filter that determines the current output pixel. + int filterOffset, filterLength; + const SkConvolutionFilter1D::ConvolutionFixed* filterValues = + filter.FilterForValue(outX, &filterOffset, &filterLength); + + // Compute the first pixel in this row that the filter affects. It will + // touch |filterLength| pixels (4 bytes each) after this. + const unsigned char* rowToFilter = &srcData[filterOffset * 4]; + + // Apply the filter to the row to get the destination pixel in |accum|. + int32x4_t accum = vdupq_n_s32(0); + for (int filterX = 0; filterX < filterLength >> 2; filterX++) { + // Load 4 coefficients + int16x4_t coeffs, coeff0, coeff1, coeff2, coeff3; + coeffs = vld1_s16(filterValues); + coeff0 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask0)); + coeff1 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask1)); + coeff2 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask2)); + coeff3 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask3)); + + // Load pixels and calc + uint8x16_t pixels = vld1q_u8(rowToFilter); + int16x8_t p01_16 = vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(pixels))); + int16x8_t p23_16 = vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(pixels))); + + int16x4_t p0_src = vget_low_s16(p01_16); + int16x4_t p1_src = vget_high_s16(p01_16); + int16x4_t p2_src = vget_low_s16(p23_16); + int16x4_t p3_src = vget_high_s16(p23_16); + + int32x4_t p0 = vmull_s16(p0_src, coeff0); + int32x4_t p1 = vmull_s16(p1_src, coeff1); + int32x4_t p2 = vmull_s16(p2_src, coeff2); + int32x4_t p3 = vmull_s16(p3_src, coeff3); + + accum += p0; + accum += p1; + accum += p2; + accum += p3; + + // Advance the pointers + rowToFilter += 16; + filterValues += 4; + } + + int r = filterLength & 3; + if (r) { + int remainder_offset = (filterOffset + filterLength - r) * 4; + AccumRemainder(srcData + remainder_offset, filterValues, accum, r); + } + + // Bring this value back in range. All of the filter scaling factors + // are in fixed point with kShiftBits bits of fractional part. + accum = vshrq_n_s32(accum, SkConvolutionFilter1D::kShiftBits); + + // Pack and store the new pixel. + int16x4_t accum16 = vqmovn_s32(accum); + uint8x8_t accum8 = vqmovun_s16(vcombine_s16(accum16, accum16)); + vst1_lane_u32(reinterpret_cast(outRow), vreinterpret_u32_u8(accum8), 0); + outRow += 4; + } + } + + // Convolves horizontally along four rows. The row data is given in + // |srcData| and continues for the numValues() of the filter. + // The algorithm is almost same as |convolve_horizontally|. Please + // refer to that function for detailed comments. + void convolve_4_rows_horizontally(const unsigned char* srcData[4], + const SkConvolutionFilter1D& filter, + unsigned char* outRow[4], + size_t outRowBytes) { + // Output one pixel each iteration, calculating all channels (RGBA) together. + int numValues = filter.numValues(); + for (int outX = 0; outX < numValues; outX++) { + + int filterOffset, filterLength; + const SkConvolutionFilter1D::ConvolutionFixed* filterValues = + filter.FilterForValue(outX, &filterOffset, &filterLength); + + // four pixels in a column per iteration. + int32x4_t accum0 = vdupq_n_s32(0); + int32x4_t accum1 = vdupq_n_s32(0); + int32x4_t accum2 = vdupq_n_s32(0); + int32x4_t accum3 = vdupq_n_s32(0); + + uint8x8_t coeff_mask0 = vcreate_u8(0x0100010001000100); + uint8x8_t coeff_mask1 = vcreate_u8(0x0302030203020302); + uint8x8_t coeff_mask2 = vcreate_u8(0x0504050405040504); + uint8x8_t coeff_mask3 = vcreate_u8(0x0706070607060706); + + int start = filterOffset * 4; + + // We will load and accumulate with four coefficients per iteration. + for (int filterX = 0; filterX < (filterLength >> 2); filterX++) { + int16x4_t coeffs, coeff0, coeff1, coeff2, coeff3; + + coeffs = vld1_s16(filterValues); + coeff0 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask0)); + coeff1 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask1)); + coeff2 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask2)); + coeff3 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask3)); + + uint8x16_t pixels; + int16x8_t p01_16, p23_16; + int32x4_t p0, p1, p2, p3; + +#define ITERATION(src, accum) \ + pixels = vld1q_u8(src); \ + p01_16 = vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(pixels))); \ + p23_16 = vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(pixels))); \ + p0 = vmull_s16(vget_low_s16(p01_16), coeff0); \ + p1 = vmull_s16(vget_high_s16(p01_16), coeff1); \ + p2 = vmull_s16(vget_low_s16(p23_16), coeff2); \ + p3 = vmull_s16(vget_high_s16(p23_16), coeff3); \ + accum += p0; \ + accum += p1; \ + accum += p2; \ + accum += p3 + + ITERATION(srcData[0] + start, accum0); + ITERATION(srcData[1] + start, accum1); + ITERATION(srcData[2] + start, accum2); + ITERATION(srcData[3] + start, accum3); + + start += 16; + filterValues += 4; + } + + int r = filterLength & 3; + if (r) { + int remainder_offset = (filterOffset + filterLength - r) * 4; + AccumRemainder(srcData[0] + remainder_offset, filterValues, accum0, r); + AccumRemainder(srcData[1] + remainder_offset, filterValues, accum1, r); + AccumRemainder(srcData[2] + remainder_offset, filterValues, accum2, r); + AccumRemainder(srcData[3] + remainder_offset, filterValues, accum3, r); + } + + int16x4_t accum16; + uint8x8_t res0, res1, res2, res3; + +#define PACK_RESULT(accum, res) \ + accum = vshrq_n_s32(accum, SkConvolutionFilter1D::kShiftBits); \ + accum16 = vqmovn_s32(accum); \ + res = vqmovun_s16(vcombine_s16(accum16, accum16)); + + PACK_RESULT(accum0, res0); + PACK_RESULT(accum1, res1); + PACK_RESULT(accum2, res2); + PACK_RESULT(accum3, res3); + + vst1_lane_u32(reinterpret_cast(outRow[0]), vreinterpret_u32_u8(res0), 0); + vst1_lane_u32(reinterpret_cast(outRow[1]), vreinterpret_u32_u8(res1), 0); + vst1_lane_u32(reinterpret_cast(outRow[2]), vreinterpret_u32_u8(res2), 0); + vst1_lane_u32(reinterpret_cast(outRow[3]), vreinterpret_u32_u8(res3), 0); + outRow[0] += 4; + outRow[1] += 4; + outRow[2] += 4; + outRow[3] += 4; + } + } + + + // Does vertical convolution to produce one output row. The filter values and + // length are given in the first two parameters. These are applied to each + // of the rows pointed to in the |sourceDataRows| array, with each row + // being |pixelWidth| wide. + // + // The output must have room for |pixelWidth * 4| bytes. + template + void ConvolveVertically(const SkConvolutionFilter1D::ConvolutionFixed* filterValues, + int filterLength, + unsigned char* const* sourceDataRows, + int pixelWidth, + unsigned char* outRow) { + int width = pixelWidth & ~3; + + // Output four pixels per iteration (16 bytes). + for (int outX = 0; outX < width; outX += 4) { + + // Accumulated result for each pixel. 32 bits per RGBA channel. + int32x4_t accum0 = vdupq_n_s32(0); + int32x4_t accum1 = vdupq_n_s32(0); + int32x4_t accum2 = vdupq_n_s32(0); + int32x4_t accum3 = vdupq_n_s32(0); + + // Convolve with one filter coefficient per iteration. + for (int filterY = 0; filterY < filterLength; filterY++) { + + // Duplicate the filter coefficient 4 times. + // [16] cj cj cj cj + int16x4_t coeff16 = vdup_n_s16(filterValues[filterY]); + + // Load four pixels (16 bytes) together. + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + uint8x16_t src8 = vld1q_u8(&sourceDataRows[filterY][outX << 2]); + + int16x8_t src16_01 = vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(src8))); + int16x8_t src16_23 = vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(src8))); + int16x4_t src16_0 = vget_low_s16(src16_01); + int16x4_t src16_1 = vget_high_s16(src16_01); + int16x4_t src16_2 = vget_low_s16(src16_23); + int16x4_t src16_3 = vget_high_s16(src16_23); + + accum0 += vmull_s16(src16_0, coeff16); + accum1 += vmull_s16(src16_1, coeff16); + accum2 += vmull_s16(src16_2, coeff16); + accum3 += vmull_s16(src16_3, coeff16); + } + + // Shift right for fixed point implementation. + accum0 = vshrq_n_s32(accum0, SkConvolutionFilter1D::kShiftBits); + accum1 = vshrq_n_s32(accum1, SkConvolutionFilter1D::kShiftBits); + accum2 = vshrq_n_s32(accum2, SkConvolutionFilter1D::kShiftBits); + accum3 = vshrq_n_s32(accum3, SkConvolutionFilter1D::kShiftBits); + + // Packing 32 bits |accum| to 16 bits per channel (signed saturation). + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + int16x8_t accum16_0 = vcombine_s16(vqmovn_s32(accum0), vqmovn_s32(accum1)); + // [16] a3 b3 g3 r3 a2 b2 g2 r2 + int16x8_t accum16_1 = vcombine_s16(vqmovn_s32(accum2), vqmovn_s32(accum3)); + + // Packing 16 bits |accum| to 8 bits per channel (unsigned saturation). + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + uint8x16_t accum8 = vcombine_u8(vqmovun_s16(accum16_0), vqmovun_s16(accum16_1)); + + if (hasAlpha) { + // Compute the max(ri, gi, bi) for each pixel. + // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 + uint8x16_t a = vreinterpretq_u8_u32(vshrq_n_u32(vreinterpretq_u32_u8(accum8), 8)); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + uint8x16_t b = vmaxq_u8(a, accum8); // Max of r and g + // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 + a = vreinterpretq_u8_u32(vshrq_n_u32(vreinterpretq_u32_u8(accum8), 16)); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + b = vmaxq_u8(a, b); // Max of r and g and b. + // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 + b = vreinterpretq_u8_u32(vshlq_n_u32(vreinterpretq_u32_u8(b), 24)); + + // Make sure the value of alpha channel is always larger than maximum + // value of color channels. + accum8 = vmaxq_u8(b, accum8); + } else { + // Set value of alpha channels to 0xFF. + accum8 = vreinterpretq_u8_u32(vreinterpretq_u32_u8(accum8) | vdupq_n_u32(0xFF000000)); + } + + // Store the convolution result (16 bytes) and advance the pixel pointers. + vst1q_u8(outRow, accum8); + outRow += 16; + } + + // Process the leftovers when the width of the output is not divisible + // by 4, that is at most 3 pixels. + int r = pixelWidth & 3; + if (r) { + + int32x4_t accum0 = vdupq_n_s32(0); + int32x4_t accum1 = vdupq_n_s32(0); + int32x4_t accum2 = vdupq_n_s32(0); + + for (int filterY = 0; filterY < filterLength; ++filterY) { + int16x4_t coeff16 = vdup_n_s16(filterValues[filterY]); + + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + uint8x16_t src8 = vld1q_u8(&sourceDataRows[filterY][width << 2]); + + int16x8_t src16_01 = vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(src8))); + int16x8_t src16_23 = vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(src8))); + int16x4_t src16_0 = vget_low_s16(src16_01); + int16x4_t src16_1 = vget_high_s16(src16_01); + int16x4_t src16_2 = vget_low_s16(src16_23); + + accum0 += vmull_s16(src16_0, coeff16); + accum1 += vmull_s16(src16_1, coeff16); + accum2 += vmull_s16(src16_2, coeff16); + } + + accum0 = vshrq_n_s32(accum0, SkConvolutionFilter1D::kShiftBits); + accum1 = vshrq_n_s32(accum1, SkConvolutionFilter1D::kShiftBits); + accum2 = vshrq_n_s32(accum2, SkConvolutionFilter1D::kShiftBits); + + int16x8_t accum16_0 = vcombine_s16(vqmovn_s32(accum0), vqmovn_s32(accum1)); + int16x8_t accum16_1 = vcombine_s16(vqmovn_s32(accum2), vqmovn_s32(accum2)); + + uint8x16_t accum8 = vcombine_u8(vqmovun_s16(accum16_0), vqmovun_s16(accum16_1)); + + if (hasAlpha) { + // Compute the max(ri, gi, bi) for each pixel. + // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 + uint8x16_t a = vreinterpretq_u8_u32(vshrq_n_u32(vreinterpretq_u32_u8(accum8), 8)); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + uint8x16_t b = vmaxq_u8(a, accum8); // Max of r and g + // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 + a = vreinterpretq_u8_u32(vshrq_n_u32(vreinterpretq_u32_u8(accum8), 16)); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + b = vmaxq_u8(a, b); // Max of r and g and b. + // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 + b = vreinterpretq_u8_u32(vshlq_n_u32(vreinterpretq_u32_u8(b), 24)); + + // Make sure the value of alpha channel is always larger than maximum + // value of color channels. + accum8 = vmaxq_u8(b, accum8); + } else { + // Set value of alpha channels to 0xFF. + accum8 = vreinterpretq_u8_u32(vreinterpretq_u32_u8(accum8) | vdupq_n_u32(0xFF000000)); + } + + switch(r) { + case 1: + vst1q_lane_u32(reinterpret_cast(outRow), vreinterpretq_u32_u8(accum8), 0); + break; + case 2: + vst1_u32(reinterpret_cast(outRow), + vreinterpret_u32_u8(vget_low_u8(accum8))); + break; + case 3: + vst1_u32(reinterpret_cast(outRow), + vreinterpret_u32_u8(vget_low_u8(accum8))); + vst1q_lane_u32(reinterpret_cast(outRow+8), vreinterpretq_u32_u8(accum8), 2); + break; + } + } + } + +#else + + // Converts the argument to an 8-bit unsigned value by clamping to the range + // 0-255. + inline unsigned char ClampTo8(int a) { + if (static_cast(a) < 256) { + return a; // Avoid the extra check in the common case. + } + if (a < 0) { + return 0; + } + return 255; + } + + // Convolves horizontally along a single row. The row data is given in + // |srcData| and continues for the numValues() of the filter. + template + void ConvolveHorizontally(const unsigned char* srcData, + const SkConvolutionFilter1D& filter, + unsigned char* outRow) { + // Loop over each pixel on this row in the output image. + int numValues = filter.numValues(); + for (int outX = 0; outX < numValues; outX++) { + // Get the filter that determines the current output pixel. + int filterOffset, filterLength; + const SkConvolutionFilter1D::ConvolutionFixed* filterValues = + filter.FilterForValue(outX, &filterOffset, &filterLength); + + // Compute the first pixel in this row that the filter affects. It will + // touch |filterLength| pixels (4 bytes each) after this. + const unsigned char* rowToFilter = &srcData[filterOffset * 4]; + + // Apply the filter to the row to get the destination pixel in |accum|. + int accum[4] = {0}; + for (int filterX = 0; filterX < filterLength; filterX++) { + SkConvolutionFilter1D::ConvolutionFixed curFilter = filterValues[filterX]; + accum[0] += curFilter * rowToFilter[filterX * 4 + 0]; + accum[1] += curFilter * rowToFilter[filterX * 4 + 1]; + accum[2] += curFilter * rowToFilter[filterX * 4 + 2]; + if (hasAlpha) { + accum[3] += curFilter * rowToFilter[filterX * 4 + 3]; + } + } + + // Bring this value back in range. All of the filter scaling factors + // are in fixed point with kShiftBits bits of fractional part. + accum[0] >>= SkConvolutionFilter1D::kShiftBits; + accum[1] >>= SkConvolutionFilter1D::kShiftBits; + accum[2] >>= SkConvolutionFilter1D::kShiftBits; + if (hasAlpha) { + accum[3] >>= SkConvolutionFilter1D::kShiftBits; + } + + // Store the new pixel. + outRow[outX * 4 + 0] = ClampTo8(accum[0]); + outRow[outX * 4 + 1] = ClampTo8(accum[1]); + outRow[outX * 4 + 2] = ClampTo8(accum[2]); + if (hasAlpha) { + outRow[outX * 4 + 3] = ClampTo8(accum[3]); + } + } + } + + // Does vertical convolution to produce one output row. The filter values and + // length are given in the first two parameters. These are applied to each + // of the rows pointed to in the |sourceDataRows| array, with each row + // being |pixelWidth| wide. + // + // The output must have room for |pixelWidth * 4| bytes. + template + void ConvolveVertically(const SkConvolutionFilter1D::ConvolutionFixed* filterValues, + int filterLength, + unsigned char* const* sourceDataRows, + int pixelWidth, + unsigned char* outRow) { + // We go through each column in the output and do a vertical convolution, + // generating one output pixel each time. + for (int outX = 0; outX < pixelWidth; outX++) { + // Compute the number of bytes over in each row that the current column + // we're convolving starts at. The pixel will cover the next 4 bytes. + int byteOffset = outX * 4; + + // Apply the filter to one column of pixels. + int accum[4] = {0}; + for (int filterY = 0; filterY < filterLength; filterY++) { + SkConvolutionFilter1D::ConvolutionFixed curFilter = filterValues[filterY]; + accum[0] += curFilter * sourceDataRows[filterY][byteOffset + 0]; + accum[1] += curFilter * sourceDataRows[filterY][byteOffset + 1]; + accum[2] += curFilter * sourceDataRows[filterY][byteOffset + 2]; + if (hasAlpha) { + accum[3] += curFilter * sourceDataRows[filterY][byteOffset + 3]; + } + } + + // Bring this value back in range. All of the filter scaling factors + // are in fixed point with kShiftBits bits of precision. + accum[0] >>= SkConvolutionFilter1D::kShiftBits; + accum[1] >>= SkConvolutionFilter1D::kShiftBits; + accum[2] >>= SkConvolutionFilter1D::kShiftBits; + if (hasAlpha) { + accum[3] >>= SkConvolutionFilter1D::kShiftBits; + } + + // Store the new pixel. + outRow[byteOffset + 0] = ClampTo8(accum[0]); + outRow[byteOffset + 1] = ClampTo8(accum[1]); + outRow[byteOffset + 2] = ClampTo8(accum[2]); + if (hasAlpha) { + unsigned char alpha = ClampTo8(accum[3]); + + // Make sure the alpha channel doesn't come out smaller than any of the + // color channels. We use premultipled alpha channels, so this should + // never happen, but rounding errors will cause this from time to time. + // These "impossible" colors will cause overflows (and hence random pixel + // values) when the resulting bitmap is drawn to the screen. + // + // We only need to do this when generating the final output row (here). + int maxColorChannel = SkTMax(outRow[byteOffset + 0], + SkTMax(outRow[byteOffset + 1], + outRow[byteOffset + 2])); + if (alpha < maxColorChannel) { + outRow[byteOffset + 3] = maxColorChannel; + } else { + outRow[byteOffset + 3] = alpha; + } + } else { + // No alpha channel, the image is opaque. + outRow[byteOffset + 3] = 0xff; + } + } + } + + // There's a bug somewhere here with GCC autovectorization (-ftree-vectorize). We originally + // thought this was 32 bit only, but subsequent tests show that some 64 bit gcc compiles + // suffer here too. + // + // Dropping to -O2 disables -ftree-vectorize. GCC 4.6 needs noinline. https://bug.skia.org/2575 +#if SK_HAS_ATTRIBUTE(optimize) && defined(SK_RELEASE) + #define SK_MAYBE_DISABLE_VECTORIZATION __attribute__((optimize("O2"), noinline)) +#else + #define SK_MAYBE_DISABLE_VECTORIZATION +#endif + + SK_MAYBE_DISABLE_VECTORIZATION + void convolve_horizontally(const unsigned char* srcData, + const SkConvolutionFilter1D& filter, + unsigned char* outRow, + bool hasAlpha) { + if (hasAlpha) { + ConvolveHorizontally(srcData, filter, outRow); + } else { + ConvolveHorizontally(srcData, filter, outRow); + } + } +#undef SK_MAYBE_DISABLE_VECTORIZATION + + void (*convolve_4_rows_horizontally)(const unsigned char* srcData[4], + const SkConvolutionFilter1D& filter, + unsigned char* outRow[4], + size_t outRowBytes) + = nullptr; + + +#endif + + void convolve_vertically(const SkConvolutionFilter1D::ConvolutionFixed* filterValues, + int filterLength, + unsigned char* const* sourceDataRows, + int pixelWidth, + unsigned char* outRow, + bool hasAlpha) { + if (hasAlpha) { + ConvolveVertically(filterValues, filterLength, sourceDataRows, + pixelWidth, outRow); + } else { + ConvolveVertically(filterValues, filterLength, sourceDataRows, + pixelWidth, outRow); + } + } + +} // namespace SK_OPTS_NS + +#endif//SkBitmapFilter_opts_DEFINED diff --git a/gfx/skia/skia/src/opts/SkBitmapFilter_opts_SSE2.cpp b/gfx/skia/skia/src/opts/SkBitmapFilter_opts_SSE2.cpp deleted file mode 100644 index ecaad23d76f1..000000000000 --- a/gfx/skia/skia/src/opts/SkBitmapFilter_opts_SSE2.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include -#include "SkBitmap.h" -#include "SkBitmapFilter_opts_SSE2.h" -#include "SkBitmapProcState.h" -#include "SkColor.h" -#include "SkColorPriv.h" -#include "SkConvolver.h" -#include "SkShader.h" -#include "SkUnPreMultiply.h" - -#if 0 -static inline void print128i(__m128i value) { - int *v = (int*) &value; - printf("% .11d % .11d % .11d % .11d\n", v[0], v[1], v[2], v[3]); -} - -static inline void print128i_16(__m128i value) { - short *v = (short*) &value; - printf("% .5d % .5d % .5d % .5d % .5d % .5d % .5d % .5d\n", v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); -} - -static inline void print128i_8(__m128i value) { - unsigned char *v = (unsigned char*) &value; - printf("%.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u\n", - v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], - v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15] - ); -} - -static inline void print128f(__m128 value) { - float *f = (float*) &value; - printf("%3.4f %3.4f %3.4f %3.4f\n", f[0], f[1], f[2], f[3]); -} -#endif - -// Convolves horizontally along a single row. The row data is given in -// |src_data| and continues for the num_values() of the filter. -void convolveHorizontally_SSE2(const unsigned char* src_data, - const SkConvolutionFilter1D& filter, - unsigned char* out_row, - bool /*has_alpha*/) { - int num_values = filter.numValues(); - - int filter_offset, filter_length; - __m128i zero = _mm_setzero_si128(); - __m128i mask[4]; - // |mask| will be used to decimate all extra filter coefficients that are - // loaded by SIMD when |filter_length| is not divisible by 4. - // mask[0] is not used in following algorithm. - mask[1] = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, -1); - mask[2] = _mm_set_epi16(0, 0, 0, 0, 0, 0, -1, -1); - mask[3] = _mm_set_epi16(0, 0, 0, 0, 0, -1, -1, -1); - - // Output one pixel each iteration, calculating all channels (RGBA) together. - for (int out_x = 0; out_x < num_values; out_x++) { - const SkConvolutionFilter1D::ConvolutionFixed* filter_values = - filter.FilterForValue(out_x, &filter_offset, &filter_length); - - __m128i accum = _mm_setzero_si128(); - - // Compute the first pixel in this row that the filter affects. It will - // touch |filter_length| pixels (4 bytes each) after this. - const __m128i* row_to_filter = - reinterpret_cast(&src_data[filter_offset << 2]); - - // We will load and accumulate with four coefficients per iteration. - for (int filter_x = 0; filter_x < filter_length >> 2; filter_x++) { - - // Load 4 coefficients => duplicate 1st and 2nd of them for all channels. - __m128i coeff, coeff16; - // [16] xx xx xx xx c3 c2 c1 c0 - coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); - // [16] xx xx xx xx c1 c1 c0 c0 - coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); - // [16] c1 c1 c1 c1 c0 c0 c0 c0 - coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); - - // Load four pixels => unpack the first two pixels to 16 bits => - // multiply with coefficients => accumulate the convolution result. - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - __m128i src8 = _mm_loadu_si128(row_to_filter); - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - __m128i src16 = _mm_unpacklo_epi8(src8, zero); - __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); - __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a0*c0 b0*c0 g0*c0 r0*c0 - __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - // [32] a1*c1 b1*c1 g1*c1 r1*c1 - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - - // Duplicate 3rd and 4th coefficients for all channels => - // unpack the 3rd and 4th pixels to 16 bits => multiply with coefficients - // => accumulate the convolution results. - // [16] xx xx xx xx c3 c3 c2 c2 - coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); - // [16] c3 c3 c3 c3 c2 c2 c2 c2 - coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); - // [16] a3 g3 b3 r3 a2 g2 b2 r2 - src16 = _mm_unpackhi_epi8(src8, zero); - mul_hi = _mm_mulhi_epi16(src16, coeff16); - mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a2*c2 b2*c2 g2*c2 r2*c2 - t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - // [32] a3*c3 b3*c3 g3*c3 r3*c3 - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - - // Advance the pixel and coefficients pointers. - row_to_filter += 1; - filter_values += 4; - } - - // When |filter_length| is not divisible by 4, we need to decimate some of - // the filter coefficient that was loaded incorrectly to zero; Other than - // that the algorithm is same with above, exceot that the 4th pixel will be - // always absent. - int r = filter_length&3; - if (r) { - // Note: filter_values must be padded to align_up(filter_offset, 8). - __m128i coeff, coeff16; - coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); - // Mask out extra filter taps. - coeff = _mm_and_si128(coeff, mask[r]); - coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); - coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); - - // Note: line buffer must be padded to align_up(filter_offset, 16). - // We resolve this by use C-version for the last horizontal line. - __m128i src8 = _mm_loadu_si128(row_to_filter); - __m128i src16 = _mm_unpacklo_epi8(src8, zero); - __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); - __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); - __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - - src16 = _mm_unpackhi_epi8(src8, zero); - coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); - coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); - mul_hi = _mm_mulhi_epi16(src16, coeff16); - mul_lo = _mm_mullo_epi16(src16, coeff16); - t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - } - - // Shift right for fixed point implementation. - accum = _mm_srai_epi32(accum, SkConvolutionFilter1D::kShiftBits); - - // Packing 32 bits |accum| to 16 bits per channel (signed saturation). - accum = _mm_packs_epi32(accum, zero); - // Packing 16 bits |accum| to 8 bits per channel (unsigned saturation). - accum = _mm_packus_epi16(accum, zero); - - // Store the pixel value of 32 bits. - *(reinterpret_cast(out_row)) = _mm_cvtsi128_si32(accum); - out_row += 4; - } -} - -// Convolves horizontally along four rows. The row data is given in -// |src_data| and continues for the num_values() of the filter. -// The algorithm is almost same as |ConvolveHorizontally_SSE2|. Please -// refer to that function for detailed comments. -void convolve4RowsHorizontally_SSE2(const unsigned char* src_data[4], - const SkConvolutionFilter1D& filter, - unsigned char* out_row[4], - size_t outRowBytes) { - SkDEBUGCODE(const unsigned char* out_row_0_start = out_row[0];) - - int num_values = filter.numValues(); - - int filter_offset, filter_length; - __m128i zero = _mm_setzero_si128(); - __m128i mask[4]; - // |mask| will be used to decimate all extra filter coefficients that are - // loaded by SIMD when |filter_length| is not divisible by 4. - // mask[0] is not used in following algorithm. - mask[1] = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, -1); - mask[2] = _mm_set_epi16(0, 0, 0, 0, 0, 0, -1, -1); - mask[3] = _mm_set_epi16(0, 0, 0, 0, 0, -1, -1, -1); - - // Output one pixel each iteration, calculating all channels (RGBA) together. - for (int out_x = 0; out_x < num_values; out_x++) { - const SkConvolutionFilter1D::ConvolutionFixed* filter_values = - filter.FilterForValue(out_x, &filter_offset, &filter_length); - - // four pixels in a column per iteration. - __m128i accum0 = _mm_setzero_si128(); - __m128i accum1 = _mm_setzero_si128(); - __m128i accum2 = _mm_setzero_si128(); - __m128i accum3 = _mm_setzero_si128(); - int start = (filter_offset<<2); - // We will load and accumulate with four coefficients per iteration. - for (int filter_x = 0; filter_x < (filter_length >> 2); filter_x++) { - __m128i coeff, coeff16lo, coeff16hi; - // [16] xx xx xx xx c3 c2 c1 c0 - coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); - // [16] xx xx xx xx c1 c1 c0 c0 - coeff16lo = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); - // [16] c1 c1 c1 c1 c0 c0 c0 c0 - coeff16lo = _mm_unpacklo_epi16(coeff16lo, coeff16lo); - // [16] xx xx xx xx c3 c3 c2 c2 - coeff16hi = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); - // [16] c3 c3 c3 c3 c2 c2 c2 c2 - coeff16hi = _mm_unpacklo_epi16(coeff16hi, coeff16hi); - - __m128i src8, src16, mul_hi, mul_lo, t; - -#define ITERATION(src, accum) \ - src8 = _mm_loadu_si128(reinterpret_cast(src)); \ - src16 = _mm_unpacklo_epi8(src8, zero); \ - mul_hi = _mm_mulhi_epi16(src16, coeff16lo); \ - mul_lo = _mm_mullo_epi16(src16, coeff16lo); \ - t = _mm_unpacklo_epi16(mul_lo, mul_hi); \ - accum = _mm_add_epi32(accum, t); \ - t = _mm_unpackhi_epi16(mul_lo, mul_hi); \ - accum = _mm_add_epi32(accum, t); \ - src16 = _mm_unpackhi_epi8(src8, zero); \ - mul_hi = _mm_mulhi_epi16(src16, coeff16hi); \ - mul_lo = _mm_mullo_epi16(src16, coeff16hi); \ - t = _mm_unpacklo_epi16(mul_lo, mul_hi); \ - accum = _mm_add_epi32(accum, t); \ - t = _mm_unpackhi_epi16(mul_lo, mul_hi); \ - accum = _mm_add_epi32(accum, t) - - ITERATION(src_data[0] + start, accum0); - ITERATION(src_data[1] + start, accum1); - ITERATION(src_data[2] + start, accum2); - ITERATION(src_data[3] + start, accum3); - - start += 16; - filter_values += 4; - } - - int r = filter_length & 3; - if (r) { - // Note: filter_values must be padded to align_up(filter_offset, 8); - __m128i coeff; - coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); - // Mask out extra filter taps. - coeff = _mm_and_si128(coeff, mask[r]); - - __m128i coeff16lo = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); - /* c1 c1 c1 c1 c0 c0 c0 c0 */ - coeff16lo = _mm_unpacklo_epi16(coeff16lo, coeff16lo); - __m128i coeff16hi = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); - coeff16hi = _mm_unpacklo_epi16(coeff16hi, coeff16hi); - - __m128i src8, src16, mul_hi, mul_lo, t; - - ITERATION(src_data[0] + start, accum0); - ITERATION(src_data[1] + start, accum1); - ITERATION(src_data[2] + start, accum2); - ITERATION(src_data[3] + start, accum3); - } - - accum0 = _mm_srai_epi32(accum0, SkConvolutionFilter1D::kShiftBits); - accum0 = _mm_packs_epi32(accum0, zero); - accum0 = _mm_packus_epi16(accum0, zero); - accum1 = _mm_srai_epi32(accum1, SkConvolutionFilter1D::kShiftBits); - accum1 = _mm_packs_epi32(accum1, zero); - accum1 = _mm_packus_epi16(accum1, zero); - accum2 = _mm_srai_epi32(accum2, SkConvolutionFilter1D::kShiftBits); - accum2 = _mm_packs_epi32(accum2, zero); - accum2 = _mm_packus_epi16(accum2, zero); - accum3 = _mm_srai_epi32(accum3, SkConvolutionFilter1D::kShiftBits); - accum3 = _mm_packs_epi32(accum3, zero); - accum3 = _mm_packus_epi16(accum3, zero); - - // We seem to be running off the edge here (chromium:491660). - SkASSERT(((size_t)out_row[0] - (size_t)out_row_0_start) < outRowBytes); - - *(reinterpret_cast(out_row[0])) = _mm_cvtsi128_si32(accum0); - *(reinterpret_cast(out_row[1])) = _mm_cvtsi128_si32(accum1); - *(reinterpret_cast(out_row[2])) = _mm_cvtsi128_si32(accum2); - *(reinterpret_cast(out_row[3])) = _mm_cvtsi128_si32(accum3); - - out_row[0] += 4; - out_row[1] += 4; - out_row[2] += 4; - out_row[3] += 4; - } -} - -// Does vertical convolution to produce one output row. The filter values and -// length are given in the first two parameters. These are applied to each -// of the rows pointed to in the |source_data_rows| array, with each row -// being |pixel_width| wide. -// -// The output must have room for |pixel_width * 4| bytes. -template -void convolveVertically_SSE2(const SkConvolutionFilter1D::ConvolutionFixed* filter_values, - int filter_length, - unsigned char* const* source_data_rows, - int pixel_width, - unsigned char* out_row) { - int width = pixel_width & ~3; - - __m128i zero = _mm_setzero_si128(); - __m128i accum0, accum1, accum2, accum3, coeff16; - const __m128i* src; - // Output four pixels per iteration (16 bytes). - for (int out_x = 0; out_x < width; out_x += 4) { - - // Accumulated result for each pixel. 32 bits per RGBA channel. - accum0 = _mm_setzero_si128(); - accum1 = _mm_setzero_si128(); - accum2 = _mm_setzero_si128(); - accum3 = _mm_setzero_si128(); - - // Convolve with one filter coefficient per iteration. - for (int filter_y = 0; filter_y < filter_length; filter_y++) { - - // Duplicate the filter coefficient 8 times. - // [16] cj cj cj cj cj cj cj cj - coeff16 = _mm_set1_epi16(filter_values[filter_y]); - - // Load four pixels (16 bytes) together. - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - src = reinterpret_cast( - &source_data_rows[filter_y][out_x << 2]); - __m128i src8 = _mm_loadu_si128(src); - - // Unpack 1st and 2nd pixels from 8 bits to 16 bits for each channels => - // multiply with current coefficient => accumulate the result. - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - __m128i src16 = _mm_unpacklo_epi8(src8, zero); - __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); - __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a0 b0 g0 r0 - __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum0 = _mm_add_epi32(accum0, t); - // [32] a1 b1 g1 r1 - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum1 = _mm_add_epi32(accum1, t); - - // Unpack 3rd and 4th pixels from 8 bits to 16 bits for each channels => - // multiply with current coefficient => accumulate the result. - // [16] a3 b3 g3 r3 a2 b2 g2 r2 - src16 = _mm_unpackhi_epi8(src8, zero); - mul_hi = _mm_mulhi_epi16(src16, coeff16); - mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a2 b2 g2 r2 - t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum2 = _mm_add_epi32(accum2, t); - // [32] a3 b3 g3 r3 - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum3 = _mm_add_epi32(accum3, t); - } - - // Shift right for fixed point implementation. - accum0 = _mm_srai_epi32(accum0, SkConvolutionFilter1D::kShiftBits); - accum1 = _mm_srai_epi32(accum1, SkConvolutionFilter1D::kShiftBits); - accum2 = _mm_srai_epi32(accum2, SkConvolutionFilter1D::kShiftBits); - accum3 = _mm_srai_epi32(accum3, SkConvolutionFilter1D::kShiftBits); - - // Packing 32 bits |accum| to 16 bits per channel (signed saturation). - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - accum0 = _mm_packs_epi32(accum0, accum1); - // [16] a3 b3 g3 r3 a2 b2 g2 r2 - accum2 = _mm_packs_epi32(accum2, accum3); - - // Packing 16 bits |accum| to 8 bits per channel (unsigned saturation). - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - accum0 = _mm_packus_epi16(accum0, accum2); - - if (has_alpha) { - // Compute the max(ri, gi, bi) for each pixel. - // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 - __m128i a = _mm_srli_epi32(accum0, 8); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - __m128i b = _mm_max_epu8(a, accum0); // Max of r and g. - // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 - a = _mm_srli_epi32(accum0, 16); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - b = _mm_max_epu8(a, b); // Max of r and g and b. - // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 - b = _mm_slli_epi32(b, 24); - - // Make sure the value of alpha channel is always larger than maximum - // value of color channels. - accum0 = _mm_max_epu8(b, accum0); - } else { - // Set value of alpha channels to 0xFF. - __m128i mask = _mm_set1_epi32(0xff000000); - accum0 = _mm_or_si128(accum0, mask); - } - - // Store the convolution result (16 bytes) and advance the pixel pointers. - _mm_storeu_si128(reinterpret_cast<__m128i*>(out_row), accum0); - out_row += 16; - } - - // When the width of the output is not divisible by 4, We need to save one - // pixel (4 bytes) each time. And also the fourth pixel is always absent. - if (pixel_width & 3) { - accum0 = _mm_setzero_si128(); - accum1 = _mm_setzero_si128(); - accum2 = _mm_setzero_si128(); - for (int filter_y = 0; filter_y < filter_length; ++filter_y) { - coeff16 = _mm_set1_epi16(filter_values[filter_y]); - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - src = reinterpret_cast( - &source_data_rows[filter_y][width<<2]); - __m128i src8 = _mm_loadu_si128(src); - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - __m128i src16 = _mm_unpacklo_epi8(src8, zero); - __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); - __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a0 b0 g0 r0 - __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum0 = _mm_add_epi32(accum0, t); - // [32] a1 b1 g1 r1 - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum1 = _mm_add_epi32(accum1, t); - // [16] a3 b3 g3 r3 a2 b2 g2 r2 - src16 = _mm_unpackhi_epi8(src8, zero); - mul_hi = _mm_mulhi_epi16(src16, coeff16); - mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a2 b2 g2 r2 - t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum2 = _mm_add_epi32(accum2, t); - } - - accum0 = _mm_srai_epi32(accum0, SkConvolutionFilter1D::kShiftBits); - accum1 = _mm_srai_epi32(accum1, SkConvolutionFilter1D::kShiftBits); - accum2 = _mm_srai_epi32(accum2, SkConvolutionFilter1D::kShiftBits); - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - accum0 = _mm_packs_epi32(accum0, accum1); - // [16] a3 b3 g3 r3 a2 b2 g2 r2 - accum2 = _mm_packs_epi32(accum2, zero); - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - accum0 = _mm_packus_epi16(accum0, accum2); - if (has_alpha) { - // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 - __m128i a = _mm_srli_epi32(accum0, 8); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - __m128i b = _mm_max_epu8(a, accum0); // Max of r and g. - // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 - a = _mm_srli_epi32(accum0, 16); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - b = _mm_max_epu8(a, b); // Max of r and g and b. - // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 - b = _mm_slli_epi32(b, 24); - accum0 = _mm_max_epu8(b, accum0); - } else { - __m128i mask = _mm_set1_epi32(0xff000000); - accum0 = _mm_or_si128(accum0, mask); - } - - for (int out_x = width; out_x < pixel_width; out_x++) { - *(reinterpret_cast(out_row)) = _mm_cvtsi128_si32(accum0); - accum0 = _mm_srli_si128(accum0, 4); - out_row += 4; - } - } -} - -void convolveVertically_SSE2(const SkConvolutionFilter1D::ConvolutionFixed* filter_values, - int filter_length, - unsigned char* const* source_data_rows, - int pixel_width, - unsigned char* out_row, - bool has_alpha) { - if (has_alpha) { - convolveVertically_SSE2(filter_values, - filter_length, - source_data_rows, - pixel_width, - out_row); - } else { - convolveVertically_SSE2(filter_values, - filter_length, - source_data_rows, - pixel_width, - out_row); - } -} - -void applySIMDPadding_SSE2(SkConvolutionFilter1D *filter) { - // Padding |paddingCount| of more dummy coefficients after the coefficients - // of last filter to prevent SIMD instructions which load 8 or 16 bytes - // together to access invalid memory areas. We are not trying to align the - // coefficients right now due to the opaqueness of implementation. - // This has to be done after all |AddFilter| calls. - for (int i = 0; i < 8; ++i) { - filter->addFilterValue(static_cast(0)); - } -} diff --git a/gfx/skia/skia/src/opts/SkBitmapFilter_opts_SSE2.h b/gfx/skia/skia/src/opts/SkBitmapFilter_opts_SSE2.h deleted file mode 100644 index 46ab5c8ae716..000000000000 --- a/gfx/skia/skia/src/opts/SkBitmapFilter_opts_SSE2.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkBitmapFilter_opts_sse2_DEFINED -#define SkBitmapFilter_opts_sse2_DEFINED - -#include "SkBitmapProcState.h" -#include "SkConvolver.h" - -void convolveVertically_SSE2(const SkConvolutionFilter1D::ConvolutionFixed* filter_values, - int filter_length, - unsigned char* const* source_data_rows, - int pixel_width, - unsigned char* out_row, - bool has_alpha); -void convolve4RowsHorizontally_SSE2(const unsigned char* src_data[4], - const SkConvolutionFilter1D& filter, - unsigned char* out_row[4], - size_t outRowBytes); -void convolveHorizontally_SSE2(const unsigned char* src_data, - const SkConvolutionFilter1D& filter, - unsigned char* out_row, - bool has_alpha); -void applySIMDPadding_SSE2(SkConvolutionFilter1D* filter); - -#endif diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_arm_neon.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_arm_neon.cpp index ce2656da6549..2f442514dd44 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_arm_neon.cpp +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_arm_neon.cpp @@ -77,423 +77,3 @@ const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[] = { SG8_alpha_D32_filter_DX_neon, SG8_alpha_D32_filter_DX_neon, }; - -/////////////////////////////////////////////////////////////////////////////// - -#include -#include "SkConvolver.h" - -// Convolves horizontally along a single row. The row data is given in -// |srcData| and continues for the numValues() of the filter. -void convolveHorizontally_neon(const unsigned char* srcData, - const SkConvolutionFilter1D& filter, - unsigned char* outRow, - bool hasAlpha) { - // Loop over each pixel on this row in the output image. - int numValues = filter.numValues(); - for (int outX = 0; outX < numValues; outX++) { - uint8x8_t coeff_mask0 = vcreate_u8(0x0100010001000100); - uint8x8_t coeff_mask1 = vcreate_u8(0x0302030203020302); - uint8x8_t coeff_mask2 = vcreate_u8(0x0504050405040504); - uint8x8_t coeff_mask3 = vcreate_u8(0x0706070607060706); - // Get the filter that determines the current output pixel. - int filterOffset, filterLength; - const SkConvolutionFilter1D::ConvolutionFixed* filterValues = - filter.FilterForValue(outX, &filterOffset, &filterLength); - - // Compute the first pixel in this row that the filter affects. It will - // touch |filterLength| pixels (4 bytes each) after this. - const unsigned char* rowToFilter = &srcData[filterOffset * 4]; - - // Apply the filter to the row to get the destination pixel in |accum|. - int32x4_t accum = vdupq_n_s32(0); - for (int filterX = 0; filterX < filterLength >> 2; filterX++) { - // Load 4 coefficients - int16x4_t coeffs, coeff0, coeff1, coeff2, coeff3; - coeffs = vld1_s16(filterValues); - coeff0 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask0)); - coeff1 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask1)); - coeff2 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask2)); - coeff3 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask3)); - - // Load pixels and calc - uint8x16_t pixels = vld1q_u8(rowToFilter); - int16x8_t p01_16 = vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(pixels))); - int16x8_t p23_16 = vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(pixels))); - - int16x4_t p0_src = vget_low_s16(p01_16); - int16x4_t p1_src = vget_high_s16(p01_16); - int16x4_t p2_src = vget_low_s16(p23_16); - int16x4_t p3_src = vget_high_s16(p23_16); - - int32x4_t p0 = vmull_s16(p0_src, coeff0); - int32x4_t p1 = vmull_s16(p1_src, coeff1); - int32x4_t p2 = vmull_s16(p2_src, coeff2); - int32x4_t p3 = vmull_s16(p3_src, coeff3); - - accum += p0; - accum += p1; - accum += p2; - accum += p3; - - // Advance the pointers - rowToFilter += 16; - filterValues += 4; - } - int r = filterLength & 3; - if (r) { - const uint16_t mask[4][4] = { - {0, 0, 0, 0}, - {0xFFFF, 0, 0, 0}, - {0xFFFF, 0xFFFF, 0, 0}, - {0xFFFF, 0xFFFF, 0xFFFF, 0} - }; - uint16x4_t coeffs; - int16x4_t coeff0, coeff1, coeff2; - coeffs = vld1_u16(reinterpret_cast(filterValues)); - coeffs &= vld1_u16(&mask[r][0]); - coeff0 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_u16(coeffs), coeff_mask0)); - coeff1 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_u16(coeffs), coeff_mask1)); - coeff2 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_u16(coeffs), coeff_mask2)); - - // Load pixels and calc - uint8x16_t pixels = vld1q_u8(rowToFilter); - int16x8_t p01_16 = vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(pixels))); - int16x8_t p23_16 = vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(pixels))); - int32x4_t p0 = vmull_s16(vget_low_s16(p01_16), coeff0); - int32x4_t p1 = vmull_s16(vget_high_s16(p01_16), coeff1); - int32x4_t p2 = vmull_s16(vget_low_s16(p23_16), coeff2); - - accum += p0; - accum += p1; - accum += p2; - } - - // Bring this value back in range. All of the filter scaling factors - // are in fixed point with kShiftBits bits of fractional part. - accum = vshrq_n_s32(accum, SkConvolutionFilter1D::kShiftBits); - - // Pack and store the new pixel. - int16x4_t accum16 = vqmovn_s32(accum); - uint8x8_t accum8 = vqmovun_s16(vcombine_s16(accum16, accum16)); - vst1_lane_u32(reinterpret_cast(outRow), vreinterpret_u32_u8(accum8), 0); - outRow += 4; - } -} - -// Does vertical convolution to produce one output row. The filter values and -// length are given in the first two parameters. These are applied to each -// of the rows pointed to in the |sourceDataRows| array, with each row -// being |pixelWidth| wide. -// -// The output must have room for |pixelWidth * 4| bytes. -template -void convolveVertically_neon(const SkConvolutionFilter1D::ConvolutionFixed* filterValues, - int filterLength, - unsigned char* const* sourceDataRows, - int pixelWidth, - unsigned char* outRow) { - int width = pixelWidth & ~3; - - int32x4_t accum0, accum1, accum2, accum3; - int16x4_t coeff16; - - // Output four pixels per iteration (16 bytes). - for (int outX = 0; outX < width; outX += 4) { - - // Accumulated result for each pixel. 32 bits per RGBA channel. - accum0 = accum1 = accum2 = accum3 = vdupq_n_s32(0); - - // Convolve with one filter coefficient per iteration. - for (int filterY = 0; filterY < filterLength; filterY++) { - - // Duplicate the filter coefficient 4 times. - // [16] cj cj cj cj - coeff16 = vdup_n_s16(filterValues[filterY]); - - // Load four pixels (16 bytes) together. - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - uint8x16_t src8 = vld1q_u8(&sourceDataRows[filterY][outX << 2]); - - int16x8_t src16_01 = vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(src8))); - int16x8_t src16_23 = vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(src8))); - int16x4_t src16_0 = vget_low_s16(src16_01); - int16x4_t src16_1 = vget_high_s16(src16_01); - int16x4_t src16_2 = vget_low_s16(src16_23); - int16x4_t src16_3 = vget_high_s16(src16_23); - - accum0 += vmull_s16(src16_0, coeff16); - accum1 += vmull_s16(src16_1, coeff16); - accum2 += vmull_s16(src16_2, coeff16); - accum3 += vmull_s16(src16_3, coeff16); - } - - // Shift right for fixed point implementation. - accum0 = vshrq_n_s32(accum0, SkConvolutionFilter1D::kShiftBits); - accum1 = vshrq_n_s32(accum1, SkConvolutionFilter1D::kShiftBits); - accum2 = vshrq_n_s32(accum2, SkConvolutionFilter1D::kShiftBits); - accum3 = vshrq_n_s32(accum3, SkConvolutionFilter1D::kShiftBits); - - // Packing 32 bits |accum| to 16 bits per channel (signed saturation). - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - int16x8_t accum16_0 = vcombine_s16(vqmovn_s32(accum0), vqmovn_s32(accum1)); - // [16] a3 b3 g3 r3 a2 b2 g2 r2 - int16x8_t accum16_1 = vcombine_s16(vqmovn_s32(accum2), vqmovn_s32(accum3)); - - // Packing 16 bits |accum| to 8 bits per channel (unsigned saturation). - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - uint8x16_t accum8 = vcombine_u8(vqmovun_s16(accum16_0), vqmovun_s16(accum16_1)); - - if (hasAlpha) { - // Compute the max(ri, gi, bi) for each pixel. - // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 - uint8x16_t a = vreinterpretq_u8_u32(vshrq_n_u32(vreinterpretq_u32_u8(accum8), 8)); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - uint8x16_t b = vmaxq_u8(a, accum8); // Max of r and g - // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 - a = vreinterpretq_u8_u32(vshrq_n_u32(vreinterpretq_u32_u8(accum8), 16)); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - b = vmaxq_u8(a, b); // Max of r and g and b. - // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 - b = vreinterpretq_u8_u32(vshlq_n_u32(vreinterpretq_u32_u8(b), 24)); - - // Make sure the value of alpha channel is always larger than maximum - // value of color channels. - accum8 = vmaxq_u8(b, accum8); - } else { - // Set value of alpha channels to 0xFF. - accum8 = vreinterpretq_u8_u32(vreinterpretq_u32_u8(accum8) | vdupq_n_u32(0xFF000000)); - } - - // Store the convolution result (16 bytes) and advance the pixel pointers. - vst1q_u8(outRow, accum8); - outRow += 16; - } - - // Process the leftovers when the width of the output is not divisible - // by 4, that is at most 3 pixels. - int r = pixelWidth & 3; - if (r) { - - accum0 = accum1 = accum2 = vdupq_n_s32(0); - - for (int filterY = 0; filterY < filterLength; ++filterY) { - coeff16 = vdup_n_s16(filterValues[filterY]); - - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - uint8x16_t src8 = vld1q_u8(&sourceDataRows[filterY][width << 2]); - - int16x8_t src16_01 = vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(src8))); - int16x8_t src16_23 = vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(src8))); - int16x4_t src16_0 = vget_low_s16(src16_01); - int16x4_t src16_1 = vget_high_s16(src16_01); - int16x4_t src16_2 = vget_low_s16(src16_23); - - accum0 += vmull_s16(src16_0, coeff16); - accum1 += vmull_s16(src16_1, coeff16); - accum2 += vmull_s16(src16_2, coeff16); - } - - accum0 = vshrq_n_s32(accum0, SkConvolutionFilter1D::kShiftBits); - accum1 = vshrq_n_s32(accum1, SkConvolutionFilter1D::kShiftBits); - accum2 = vshrq_n_s32(accum2, SkConvolutionFilter1D::kShiftBits); - - int16x8_t accum16_0 = vcombine_s16(vqmovn_s32(accum0), vqmovn_s32(accum1)); - int16x8_t accum16_1 = vcombine_s16(vqmovn_s32(accum2), vqmovn_s32(accum2)); - - uint8x16_t accum8 = vcombine_u8(vqmovun_s16(accum16_0), vqmovun_s16(accum16_1)); - - if (hasAlpha) { - // Compute the max(ri, gi, bi) for each pixel. - // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 - uint8x16_t a = vreinterpretq_u8_u32(vshrq_n_u32(vreinterpretq_u32_u8(accum8), 8)); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - uint8x16_t b = vmaxq_u8(a, accum8); // Max of r and g - // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 - a = vreinterpretq_u8_u32(vshrq_n_u32(vreinterpretq_u32_u8(accum8), 16)); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - b = vmaxq_u8(a, b); // Max of r and g and b. - // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 - b = vreinterpretq_u8_u32(vshlq_n_u32(vreinterpretq_u32_u8(b), 24)); - - // Make sure the value of alpha channel is always larger than maximum - // value of color channels. - accum8 = vmaxq_u8(b, accum8); - } else { - // Set value of alpha channels to 0xFF. - accum8 = vreinterpretq_u8_u32(vreinterpretq_u32_u8(accum8) | vdupq_n_u32(0xFF000000)); - } - - switch(r) { - case 1: - vst1q_lane_u32(reinterpret_cast(outRow), vreinterpretq_u32_u8(accum8), 0); - break; - case 2: - vst1_u32(reinterpret_cast(outRow), - vreinterpret_u32_u8(vget_low_u8(accum8))); - break; - case 3: - vst1_u32(reinterpret_cast(outRow), - vreinterpret_u32_u8(vget_low_u8(accum8))); - vst1q_lane_u32(reinterpret_cast(outRow+8), vreinterpretq_u32_u8(accum8), 2); - break; - } - } -} - -void convolveVertically_neon(const SkConvolutionFilter1D::ConvolutionFixed* filterValues, - int filterLength, - unsigned char* const* sourceDataRows, - int pixelWidth, - unsigned char* outRow, - bool sourceHasAlpha) { - if (sourceHasAlpha) { - convolveVertically_neon(filterValues, filterLength, - sourceDataRows, pixelWidth, - outRow); - } else { - convolveVertically_neon(filterValues, filterLength, - sourceDataRows, pixelWidth, - outRow); - } -} - -// Convolves horizontally along four rows. The row data is given in -// |src_data| and continues for the num_values() of the filter. -// The algorithm is almost same as |ConvolveHorizontally_SSE2|. Please -// refer to that function for detailed comments. -void convolve4RowsHorizontally_neon(const unsigned char* srcData[4], - const SkConvolutionFilter1D& filter, - unsigned char* outRow[4], - size_t outRowBytes) { - - uint8x8_t coeff_mask0 = vcreate_u8(0x0100010001000100); - uint8x8_t coeff_mask1 = vcreate_u8(0x0302030203020302); - uint8x8_t coeff_mask2 = vcreate_u8(0x0504050405040504); - uint8x8_t coeff_mask3 = vcreate_u8(0x0706070607060706); - int num_values = filter.numValues(); - - int filterOffset, filterLength; - // |mask| will be used to decimate all extra filter coefficients that are - // loaded by SIMD when |filter_length| is not divisible by 4. - // mask[0] is not used in following algorithm. - const uint16_t mask[4][4] = { - {0, 0, 0, 0}, - {0xFFFF, 0, 0, 0}, - {0xFFFF, 0xFFFF, 0, 0}, - {0xFFFF, 0xFFFF, 0xFFFF, 0} - }; - - // Output one pixel each iteration, calculating all channels (RGBA) together. - for (int outX = 0; outX < num_values; outX++) { - - const SkConvolutionFilter1D::ConvolutionFixed* filterValues = - filter.FilterForValue(outX, &filterOffset, &filterLength); - - // four pixels in a column per iteration. - int32x4_t accum0 = vdupq_n_s32(0); - int32x4_t accum1 = vdupq_n_s32(0); - int32x4_t accum2 = vdupq_n_s32(0); - int32x4_t accum3 = vdupq_n_s32(0); - - int start = (filterOffset<<2); - - // We will load and accumulate with four coefficients per iteration. - for (int filter_x = 0; filter_x < (filterLength >> 2); filter_x++) { - int16x4_t coeffs, coeff0, coeff1, coeff2, coeff3; - - coeffs = vld1_s16(filterValues); - coeff0 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask0)); - coeff1 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask1)); - coeff2 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask2)); - coeff3 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask3)); - - uint8x16_t pixels; - int16x8_t p01_16, p23_16; - int32x4_t p0, p1, p2, p3; - - -#define ITERATION(src, accum) \ - pixels = vld1q_u8(src); \ - p01_16 = vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(pixels))); \ - p23_16 = vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(pixels))); \ - p0 = vmull_s16(vget_low_s16(p01_16), coeff0); \ - p1 = vmull_s16(vget_high_s16(p01_16), coeff1); \ - p2 = vmull_s16(vget_low_s16(p23_16), coeff2); \ - p3 = vmull_s16(vget_high_s16(p23_16), coeff3); \ - accum += p0; \ - accum += p1; \ - accum += p2; \ - accum += p3 - - ITERATION(srcData[0] + start, accum0); - ITERATION(srcData[1] + start, accum1); - ITERATION(srcData[2] + start, accum2); - ITERATION(srcData[3] + start, accum3); - - start += 16; - filterValues += 4; - } - - int r = filterLength & 3; - if (r) { - int16x4_t coeffs, coeff0, coeff1, coeff2, coeff3; - coeffs = vld1_s16(filterValues); - coeffs &= vreinterpret_s16_u16(vld1_u16(&mask[r][0])); - coeff0 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask0)); - coeff1 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask1)); - coeff2 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask2)); - coeff3 = vreinterpret_s16_u8(vtbl1_u8(vreinterpret_u8_s16(coeffs), coeff_mask3)); - - uint8x16_t pixels; - int16x8_t p01_16, p23_16; - int32x4_t p0, p1, p2, p3; - - ITERATION(srcData[0] + start, accum0); - ITERATION(srcData[1] + start, accum1); - ITERATION(srcData[2] + start, accum2); - ITERATION(srcData[3] + start, accum3); - } - - int16x4_t accum16; - uint8x8_t res0, res1, res2, res3; - -#define PACK_RESULT(accum, res) \ - accum = vshrq_n_s32(accum, SkConvolutionFilter1D::kShiftBits); \ - accum16 = vqmovn_s32(accum); \ - res = vqmovun_s16(vcombine_s16(accum16, accum16)); - - PACK_RESULT(accum0, res0); - PACK_RESULT(accum1, res1); - PACK_RESULT(accum2, res2); - PACK_RESULT(accum3, res3); - - vst1_lane_u32(reinterpret_cast(outRow[0]), vreinterpret_u32_u8(res0), 0); - vst1_lane_u32(reinterpret_cast(outRow[1]), vreinterpret_u32_u8(res1), 0); - vst1_lane_u32(reinterpret_cast(outRow[2]), vreinterpret_u32_u8(res2), 0); - vst1_lane_u32(reinterpret_cast(outRow[3]), vreinterpret_u32_u8(res3), 0); - outRow[0] += 4; - outRow[1] += 4; - outRow[2] += 4; - outRow[3] += 4; - } -} - -void applySIMDPadding_neon(SkConvolutionFilter1D *filter) { - // Padding |paddingCount| of more dummy coefficients after the coefficients - // of last filter to prevent SIMD instructions which load 8 or 16 bytes - // together to access invalid memory areas. We are not trying to align the - // coefficients right now due to the opaqueness of implementation. - // This has to be done after all |AddFilter| calls. - for (int i = 0; i < 8; ++i) { - filter->addFilterValue(static_cast(0)); - } -} - -void platformConvolutionProcs_arm_neon(SkConvolutionProcs* procs) { - procs->fExtraHorizontalReads = 3; - procs->fConvolveVertically = &convolveVertically_neon; - procs->fConvolve4RowsHorizontally = &convolve4RowsHorizontally_neon; - procs->fConvolveHorizontally = &convolveHorizontally_neon; - procs->fApplySIMDPadding = &applySIMDPadding_neon; -} diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp index 7789031c0285..612ef0472051 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp @@ -1,4 +1,4 @@ -/* NEON optimized code (C) COPYRIGHT 2009 Motorola +/* Copyright 2009 Motorola * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. @@ -46,7 +46,7 @@ static inline int32x4_t sbpsm_clamp_tile4(int32x4_t f, unsigned max) { return res; } -// TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF) +// EXTRACT_LOW_BITS(fy, max) (((fy) >> 12) & 0xF) static inline int32x4_t sbpsm_clamp_tile4_low_bits(int32x4_t fx) { int32x4_t ret; @@ -95,7 +95,7 @@ static inline int32x4_t sbpsm_repeat_tile4(int32x4_t f, unsigned max) { return vreinterpretq_s32_u32(tmp); } -// TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) +// EXTRACT_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) static inline int32x4_t sbpsm_repeat_tile4_low_bits(int32x4_t fx, unsigned max) { uint16x4_t res; uint32x4_t tmp; @@ -125,10 +125,8 @@ static inline int32x4_t sbpsm_repeat_tile4_low_bits(int32x4_t fx, unsigned max) #define TILEY_PROCF_NEON8(l, h, max) sbpsm_clamp_tile8(l, h, max) #define TILEX_PROCF_NEON4(fx, max) sbpsm_clamp_tile4(fx, max) #define TILEY_PROCF_NEON4(fy, max) sbpsm_clamp_tile4(fy, max) -#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF) -#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF) -#define TILEX_LOW_BITS_NEON4(fx, max) sbpsm_clamp_tile4_low_bits(fx) -#define TILEY_LOW_BITS_NEON4(fy, max) sbpsm_clamp_tile4_low_bits(fy) +#define EXTRACT_LOW_BITS(v, max) (((v) >> 12) & 0xF) +#define EXTRACT_LOW_BITS_NEON4(v, max) sbpsm_clamp_tile4_low_bits(v) #define CHECK_FOR_DECAL #include "SkBitmapProcState_matrix_neon.h" @@ -139,10 +137,8 @@ static inline int32x4_t sbpsm_repeat_tile4_low_bits(int32x4_t fx, unsigned max) #define TILEY_PROCF_NEON8(l, h, max) sbpsm_repeat_tile8(l, h, max) #define TILEX_PROCF_NEON4(fx, max) sbpsm_repeat_tile4(fx, max) #define TILEY_PROCF_NEON4(fy, max) sbpsm_repeat_tile4(fy, max) -#define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) -#define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) -#define TILEX_LOW_BITS_NEON4(fx, max) sbpsm_repeat_tile4_low_bits(fx, max) -#define TILEY_LOW_BITS_NEON4(fy, max) sbpsm_repeat_tile4_low_bits(fy, max) +#define EXTRACT_LOW_BITS(v, max) ((((v) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) +#define EXTRACT_LOW_BITS_NEON4(v, max) sbpsm_repeat_tile4_low_bits(v, max) #include "SkBitmapProcState_matrix_neon.h" diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_matrix_neon.h b/gfx/skia/skia/src/opts/SkBitmapProcState_matrix_neon.h index 45691b90ce2b..fb9154757140 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_matrix_neon.h +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_matrix_neon.h @@ -54,9 +54,10 @@ static void SCALE_NOFILTER_NAME(const SkBitmapProcState& s, #ifdef CHECK_FOR_DECAL // test if we don't need to apply the tile proc - if (can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) { - decal_nofilter_scale_neon(xy, SkFractionalIntToFixed(fx), - SkFractionalIntToFixed(dx), count); + const SkFixed fixedFx = SkFractionalIntToFixed(fx); + const SkFixed fixedDx = SkFractionalIntToFixed(dx); + if (can_truncate_to_fixed_for_decal(fixedFx, fixedDx, count, maxX)) { + decal_nofilter_scale_neon(xy, fixedFx, fixedDx, count); return; } #endif @@ -231,14 +232,14 @@ static void PERSP_NOFILTER_NAME(const SkBitmapProcState& s, static inline uint32_t PACK_FILTER_Y_NAME(SkFixed f, unsigned max, SkFixed one PREAMBLE_PARAM_Y) { unsigned i = TILEY_PROCF(f, max); - i = (i << 4) | TILEY_LOW_BITS(f, max); + i = (i << 4) | EXTRACT_LOW_BITS(f, max); return (i << 14) | (TILEY_PROCF((f + one), max)); } static inline uint32_t PACK_FILTER_X_NAME(SkFixed f, unsigned max, SkFixed one PREAMBLE_PARAM_X) { unsigned i = TILEX_PROCF(f, max); - i = (i << 4) | TILEX_LOW_BITS(f, max); + i = (i << 4) | EXTRACT_LOW_BITS(f, max); return (i << 14) | (TILEX_PROCF((f + one), max)); } @@ -253,7 +254,7 @@ static inline int32x4_t PACK_FILTER_X4_NAME(int32x4_t f, unsigned max, res = TILEX_PROCF_NEON4(f, max); // Step 2 - ret = TILEX_LOW_BITS_NEON4(f, max); + ret = EXTRACT_LOW_BITS_NEON4(f, max); ret = vsliq_n_s32(ret, res, 4); // Step 3 @@ -274,7 +275,7 @@ static inline int32x4_t PACK_FILTER_Y4_NAME(int32x4_t f, unsigned max, res = TILEY_PROCF_NEON4(f, max); // Step 2 - ret = TILEY_LOW_BITS_NEON4(f, max); + ret = EXTRACT_LOW_BITS_NEON4(f, max); ret = vsliq_n_s32(ret, res, 4); // Step 3 @@ -309,9 +310,10 @@ static void SCALE_FILTER_NAME(const SkBitmapProcState& s, #ifdef CHECK_FOR_DECAL // test if we don't need to apply the tile proc - if (can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) { - decal_filter_scale_neon(xy, SkFractionalIntToFixed(fx), - SkFractionalIntToFixed(dx), count); + const SkFixed fixedFx = SkFractionalIntToFixed(fx); + const SkFixed fixedDx = SkFractionalIntToFixed(dx); + if (can_truncate_to_fixed_for_decal(fixedFx, fixedDx, count, maxX)) { + decal_filter_scale_neon(xy, fixedFx, fixedDx, count); return; } #endif @@ -473,8 +475,7 @@ const SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = { #undef TILEY_PROCF_NEON8 #undef TILEX_PROCF_NEON4 #undef TILEY_PROCF_NEON4 -#undef TILEX_LOW_BITS_NEON4 -#undef TILEY_LOW_BITS_NEON4 +#undef EXTRACT_LOW_BITS_NEON4 #undef MAKENAME #undef TILEX_PROCF @@ -496,5 +497,4 @@ const SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = { #undef PREAMBLE_ARG_X #undef PREAMBLE_ARG_Y -#undef TILEX_LOW_BITS -#undef TILEY_LOW_BITS +#undef EXTRACT_LOW_BITS diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.cpp index 7a3bef0ddd3d..fa1e04227f62 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.cpp +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.cpp @@ -7,6 +7,7 @@ #include #include "SkBitmapProcState_opts_SSE2.h" +#include "SkBitmapProcState_utils.h" #include "SkColorPriv.h" #include "SkPaint.h" #include "SkUtils.h" @@ -262,8 +263,7 @@ void ClampX_ClampY_filter_scale_SSE2(const SkBitmapProcState& s, uint32_t xy[], SkFixed fx = mapper.fixedX(); // test if we don't need to apply the tile proc - if (dx > 0 && (unsigned)(fx >> 16) <= maxX && - (unsigned)((fx + dx * (count - 1)) >> 16) < maxX) { + if (can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) { if (count >= 4) { // SSE version of decal_filter_scale while ((size_t(xy) & 0x0F) != 0) { @@ -328,7 +328,7 @@ void ClampX_ClampY_filter_scale_SSE2(const SkBitmapProcState& s, uint32_t xy[], _mm_setzero_si128()); wide_i = _mm_min_epi16(wide_i, wide_maxX); - // i<<4 | TILEX_LOW_BITS(fx) + // i<<4 | EXTRACT_LOW_BITS(fx) wide_lo = _mm_srli_epi32(wide_fx, 12); wide_lo = _mm_and_si128(wide_lo, wide_mask); wide_i = _mm_slli_epi32(wide_i, 4); @@ -509,7 +509,7 @@ void ClampX_ClampY_filter_affine_SSE2(const SkBitmapProcState& s, _mm_setzero_si128()); wide_i = _mm_min_epi16(wide_i, wide_max); - // i<<4 | TILEX_LOW_BITS(f) + // i<<4 | EXTRACT_LOW_BITS(f) __m128i wide_lo = _mm_srli_epi32(wide_f, 12); wide_lo = _mm_and_si128(wide_lo, wide_mask); wide_i = _mm_slli_epi32(wide_i, 4); diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp index 17d7da931a74..7890e8a4c6a2 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp @@ -10,12 +10,6 @@ #include "SkPaint.h" #include "SkUtils.h" -/* With the exception of the compilers that don't support it, we always build the - * SSSE3 functions and enable the caller to determine SSSE3 support. However for - * compilers that do not support SSSE3 we provide a stub implementation. - */ -#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 - #include // SSSE3 // adding anonymous namespace seemed to force gcc to inline directly the @@ -731,31 +725,3 @@ void S32_alpha_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s, int count, uint32_t* colors) { S32_generic_D32_filter_DXDY_SSSE3(s, xy, count, colors); } - -#else // SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 - -void S32_opaque_D32_filter_DX_SSSE3(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint32_t* colors) { - sk_throw(); -} - -void S32_alpha_D32_filter_DX_SSSE3(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint32_t* colors) { - sk_throw(); -} - -void S32_opaque_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint32_t* colors) { - sk_throw(); -} - -void S32_alpha_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint32_t* colors) { - sk_throw(); -} - -#endif diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_arm.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_arm.cpp deleted file mode 100644 index e3726e727477..000000000000 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_arm.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2009 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkBitmapScaler.h" -#include "SkBitmapProcState.h" -#include "SkColorPriv.h" -#include "SkPaint.h" -#include "SkTypes.h" -#include "SkUtils.h" -#include "SkUtilsArm.h" - -#include "SkConvolver.h" - -void SkBitmapProcState::platformProcs() { } - -/////////////////////////////////////////////////////////////////////////////// - -extern void platformConvolutionProcs_arm_neon(SkConvolutionProcs* procs); - -void platformConvolutionProcs_arm(SkConvolutionProcs* procs) { -} - -void SkBitmapScaler::PlatformConvolutionProcs(SkConvolutionProcs* procs) { - SK_ARM_NEON_WRAP(platformConvolutionProcs_arm)(procs); -} diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_mips_dsp.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_mips_dsp.cpp deleted file mode 100644 index 10f80c2a41f7..000000000000 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_mips_dsp.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkBitmapProcState.h" -#include "SkBitmapScaler.h" -#include "SkColorPriv.h" -#include "SkPaint.h" -#include "SkUtils.h" - -static void SI8_opaque_D32_nofilter_DX_mips_dsp(const SkBitmapProcState& s, - const uint32_t* SK_RESTRICT xy, - int count, SkPMColor* SK_RESTRICT colors) { - SkASSERT(count > 0 && colors != nullptr); - SkASSERT(s.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)); - SkASSERT(kNone_SkFilterQuality == s.fFilterQuality); - const SkPMColor* SK_RESTRICT table = s.fPixmap.ctable()->readColors(); - const uint8_t* SK_RESTRICT srcAddr = (const uint8_t*)s.fPixmap.addr(); - srcAddr = (const uint8_t*)((const char*)srcAddr + xy[0] * s.fPixmap.rowBytes()); - - if (1 == s.fPixmap.width()) { - uint8_t src = srcAddr[0]; - SkPMColor dstValue = table[src]; - sk_memset32(colors, dstValue, count); - } else { - const uint16_t* xx = (const uint16_t*)(xy + 1); - int s0, s1, s2, s3, s4, s5, s6, s7; - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - ".set noat \n\t" - "srl $t8, %[count], 4 \n\t" - "beqz $t8, 3f \n\t" - " nop \n\t" - "1: \n\t" - "addiu $t8, $t8, -1 \n\t" - "beqz $t8, 2f \n\t" - " addiu %[count], %[count], -16 \n\t" - "pref 0, 32(%[xx]) \n\t" - "lhu $t0, 0(%[xx]) \n\t" - "lhu $t1, 2(%[xx]) \n\t" - "lhu $t2, 4(%[xx]) \n\t" - "lhu $t3, 6(%[xx]) \n\t" - "lhu $t4, 8(%[xx]) \n\t" - "lhu $t5, 10(%[xx]) \n\t" - "lhu $t6, 12(%[xx]) \n\t" - "lhu $t7, 14(%[xx]) \n\t" - "lhu %[s0], 16(%[xx]) \n\t" - "lhu %[s1], 18(%[xx]) \n\t" - "lhu %[s2], 20(%[xx]) \n\t" - "lhu %[s3], 22(%[xx]) \n\t" - "lhu %[s4], 24(%[xx]) \n\t" - "lhu %[s5], 26(%[xx]) \n\t" - "lhu %[s6], 28(%[xx]) \n\t" - "lhu %[s7], 30(%[xx]) \n\t" - "lbux $t0, $t0(%[srcAddr]) \n\t" - "lbux $t1, $t1(%[srcAddr]) \n\t" - "lbux $t2, $t2(%[srcAddr]) \n\t" - "lbux $t3, $t3(%[srcAddr]) \n\t" - "lbux $t4, $t4(%[srcAddr]) \n\t" - "lbux $t5, $t5(%[srcAddr]) \n\t" - "lbux $t6, $t6(%[srcAddr]) \n\t" - "lbux $t7, $t7(%[srcAddr]) \n\t" - "lbux %[s0], %[s0](%[srcAddr]) \n\t" - "lbux %[s1], %[s1](%[srcAddr]) \n\t" - "lbux %[s2], %[s2](%[srcAddr]) \n\t" - "lbux %[s3], %[s3](%[srcAddr]) \n\t" - "lbux %[s4], %[s4](%[srcAddr]) \n\t" - "lbux %[s5], %[s5](%[srcAddr]) \n\t" - "lbux %[s6], %[s6](%[srcAddr]) \n\t" - "lbux %[s7], %[s7](%[srcAddr]) \n\t" - "sll $t0, $t0, 2 \n\t" - "sll $t1, $t1, 2 \n\t" - "sll $t2, $t2, 2 \n\t" - "sll $t3, $t3, 2 \n\t" - "sll $t4, $t4, 2 \n\t" - "sll $t5, $t5, 2 \n\t" - "sll $t6, $t6, 2 \n\t" - "sll $t7, $t7, 2 \n\t" - "sll %[s0], %[s0], 2 \n\t" - "sll %[s1], %[s1], 2 \n\t" - "sll %[s2], %[s2], 2 \n\t" - "sll %[s3], %[s3], 2 \n\t" - "sll %[s4], %[s4], 2 \n\t" - "sll %[s5], %[s5], 2 \n\t" - "sll %[s6], %[s6], 2 \n\t" - "sll %[s7], %[s7], 2 \n\t" - "pref 0, 64(%[table]) \n\t" - "lwx $t0, $t0(%[table]) \n\t" - "lwx $t1, $t1(%[table]) \n\t" - "lwx $t2, $t2(%[table]) \n\t" - "lwx $t3, $t3(%[table]) \n\t" - "lwx $t4, $t4(%[table]) \n\t" - "lwx $t5, $t5(%[table]) \n\t" - "lwx $t6, $t6(%[table]) \n\t" - "lwx $t7, $t7(%[table]) \n\t" - "lwx %[s0], %[s0](%[table]) \n\t" - "lwx %[s1], %[s1](%[table]) \n\t" - "lwx %[s2], %[s2](%[table]) \n\t" - "lwx %[s3], %[s3](%[table]) \n\t" - "lwx %[s4], %[s4](%[table]) \n\t" - "lwx %[s5], %[s5](%[table]) \n\t" - "lwx %[s6], %[s6](%[table]) \n\t" - "lwx %[s7], %[s7](%[table]) \n\t" - "pref 30, 64(%[colors]) \n\t" - "sw $t0, 0(%[colors]) \n\t" - "sw $t1, 4(%[colors]) \n\t" - "sw $t2, 8(%[colors]) \n\t" - "sw $t3, 12(%[colors]) \n\t" - "sw $t4, 16(%[colors]) \n\t" - "sw $t5, 20(%[colors]) \n\t" - "sw $t6, 24(%[colors]) \n\t" - "sw $t7, 28(%[colors]) \n\t" - "sw %[s0], 32(%[colors]) \n\t" - "sw %[s1], 36(%[colors]) \n\t" - "sw %[s2], 40(%[colors]) \n\t" - "sw %[s3], 44(%[colors]) \n\t" - "sw %[s4], 48(%[colors]) \n\t" - "sw %[s5], 52(%[colors]) \n\t" - "sw %[s6], 56(%[colors]) \n\t" - "sw %[s7], 60(%[colors]) \n\t" - "addiu %[xx], %[xx], 32 \n\t" - "b 1b \n\t" - " addiu %[colors], %[colors], 64 \n\t" - "2: \n\t" - "lhu $t0, 0(%[xx]) \n\t" - "lhu $t1, 2(%[xx]) \n\t" - "lhu $t2, 4(%[xx]) \n\t" - "lhu $t3, 6(%[xx]) \n\t" - "lhu $t4, 8(%[xx]) \n\t" - "lhu $t5, 10(%[xx]) \n\t" - "lhu $t6, 12(%[xx]) \n\t" - "lhu $t7, 14(%[xx]) \n\t" - "lhu %[s0], 16(%[xx]) \n\t" - "lhu %[s1], 18(%[xx]) \n\t" - "lhu %[s2], 20(%[xx]) \n\t" - "lhu %[s3], 22(%[xx]) \n\t" - "lhu %[s4], 24(%[xx]) \n\t" - "lhu %[s5], 26(%[xx]) \n\t" - "lhu %[s6], 28(%[xx]) \n\t" - "lhu %[s7], 30(%[xx]) \n\t" - "lbux $t0, $t0(%[srcAddr]) \n\t" - "lbux $t1, $t1(%[srcAddr]) \n\t" - "lbux $t2, $t2(%[srcAddr]) \n\t" - "lbux $t3, $t3(%[srcAddr]) \n\t" - "lbux $t4, $t4(%[srcAddr]) \n\t" - "lbux $t5, $t5(%[srcAddr]) \n\t" - "lbux $t6, $t6(%[srcAddr]) \n\t" - "lbux $t7, $t7(%[srcAddr]) \n\t" - "lbux %[s0], %[s0](%[srcAddr]) \n\t" - "lbux %[s1], %[s1](%[srcAddr]) \n\t" - "lbux %[s2], %[s2](%[srcAddr]) \n\t" - "lbux %[s3], %[s3](%[srcAddr]) \n\t" - "lbux %[s4], %[s4](%[srcAddr]) \n\t" - "lbux %[s5], %[s5](%[srcAddr]) \n\t" - "lbux %[s6], %[s6](%[srcAddr]) \n\t" - "lbux %[s7], %[s7](%[srcAddr]) \n\t" - "sll $t0, $t0, 2 \n\t" - "sll $t1, $t1, 2 \n\t" - "sll $t2, $t2, 2 \n\t" - "sll $t3, $t3, 2 \n\t" - "sll $t4, $t4, 2 \n\t" - "sll $t5, $t5, 2 \n\t" - "sll $t6, $t6, 2 \n\t" - "sll $t7, $t7, 2 \n\t" - "sll %[s0], %[s0], 2 \n\t" - "sll %[s1], %[s1], 2 \n\t" - "sll %[s2], %[s2], 2 \n\t" - "sll %[s3], %[s3], 2 \n\t" - "sll %[s4], %[s4], 2 \n\t" - "sll %[s5], %[s5], 2 \n\t" - "sll %[s6], %[s6], 2 \n\t" - "sll %[s7], %[s7], 2 \n\t" - "lwx $t0, $t0(%[table]) \n\t" - "lwx $t1, $t1(%[table]) \n\t" - "lwx $t2, $t2(%[table]) \n\t" - "lwx $t3, $t3(%[table]) \n\t" - "lwx $t4, $t4(%[table]) \n\t" - "lwx $t5, $t5(%[table]) \n\t" - "lwx $t6, $t6(%[table]) \n\t" - "lwx $t7, $t7(%[table]) \n\t" - "lwx %[s0], %[s0](%[table]) \n\t" - "lwx %[s1], %[s1](%[table]) \n\t" - "lwx %[s2], %[s2](%[table]) \n\t" - "lwx %[s3], %[s3](%[table]) \n\t" - "lwx %[s4], %[s4](%[table]) \n\t" - "lwx %[s5], %[s5](%[table]) \n\t" - "lwx %[s6], %[s6](%[table]) \n\t" - "lwx %[s7], %[s7](%[table]) \n\t" - "sw $t0, 0(%[colors]) \n\t" - "sw $t1, 4(%[colors]) \n\t" - "sw $t2, 8(%[colors]) \n\t" - "sw $t3, 12(%[colors]) \n\t" - "sw $t4, 16(%[colors]) \n\t" - "sw $t5, 20(%[colors]) \n\t" - "sw $t6, 24(%[colors]) \n\t" - "sw $t7, 28(%[colors]) \n\t" - "sw %[s0], 32(%[colors]) \n\t" - "sw %[s1], 36(%[colors]) \n\t" - "sw %[s2], 40(%[colors]) \n\t" - "sw %[s3], 44(%[colors]) \n\t" - "sw %[s4], 48(%[colors]) \n\t" - "sw %[s5], 52(%[colors]) \n\t" - "sw %[s6], 56(%[colors]) \n\t" - "sw %[s7], 60(%[colors]) \n\t" - "addiu %[xx], %[xx], 32 \n\t" - "beqz %[count], 4f \n\t" - " addiu %[colors], %[colors], 64 \n\t" - "3: \n\t" - "addiu %[count], %[count], -1 \n\t" - "lhu $t0, 0(%[xx]) \n\t" - "lbux $t1, $t0(%[srcAddr]) \n\t" - "sll $t1, $t1, 2 \n\t" - "lwx $t2, $t1(%[table]) \n\t" - "sw $t2, 0(%[colors]) \n\t" - "addiu %[xx], %[xx], 2 \n\t" - "bnez %[count], 3b \n\t" - " addiu %[colors], %[colors], 4 \n\t" - "4: \n\t" - ".set pop \n\t" - : [xx]"+r"(xx), [count]"+r"(count), [colors]"+r"(colors), - [s0]"=&r"(s0), [s1]"=&r"(s1), [s2]"=&r"(s2), [s3]"=&r"(s3), - [s4]"=&r"(s4), [s5]"=&r"(s5), [s6]"=&r"(s6), [s7]"=&r"(s7) - : [table]"r"(table), [srcAddr]"r"(srcAddr) - : "memory", "t0", "t1", "t2", "t3", - "t4", "t5", "t6", "t7", "t8" - ); - } -} - -/* If we replace a sampleproc, then we null-out the associated shaderproc, - otherwise the shader won't even look at the matrix/sampler - */ - -void SkBitmapProcState::platformProcs() { - bool isOpaque = 256 == fAlphaScale; - bool justDx = false; - - if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { - justDx = true; - } - - switch (fPixmap.colorType()) { - case kIndex_8_SkColorType: - if (justDx && kNone_SkFilterQuality == fFilterQuality) { - if (isOpaque) { - fSampleProc32 = SI8_opaque_D32_nofilter_DX_mips_dsp; - fShaderProc32 = nullptr; - } - } - break; - default: - break; - } -} - -void SkBitmapScaler::PlatformConvolutionProcs(SkConvolutionProcs*) {} diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_none.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_none.cpp index f2217f3503fc..0d96e171336b 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_none.cpp +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_none.cpp @@ -22,6 +22,3 @@ // empty implementation just uses default supplied function pointers void SkBitmapProcState::platformProcs() {} - -// empty implementation just uses default supplied function pointers -void SkBitmapScaler::PlatformConvolutionProcs(SkConvolutionProcs*) {} diff --git a/gfx/skia/skia/src/opts/SkBlitRow_opts_arm_neon.cpp b/gfx/skia/skia/src/opts/SkBlitRow_opts_arm_neon.cpp index 7998a8951771..623d08be23b5 100644 --- a/gfx/skia/skia/src/opts/SkBlitRow_opts_arm_neon.cpp +++ b/gfx/skia/skia/src/opts/SkBlitRow_opts_arm_neon.cpp @@ -909,12 +909,8 @@ void S32_Blend_BlitRow32_neon(SkPMColor* SK_RESTRICT dst, vdst_wide = vmull_u8(vdst, vdup_n_u8(dst_scale)); // Combine -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - vres = vshrn_n_u16(vdst_wide, 8) + vshrn_n_u16(vsrc_wide, 8); -#else vdst_wide += vsrc_wide; vres = vshrn_n_u16(vdst_wide, 8); -#endif // Store vst1_u32(dst, vreinterpret_u32_u8(vres)); @@ -936,12 +932,8 @@ void S32_Blend_BlitRow32_neon(SkPMColor* SK_RESTRICT dst, vsrc_wide = vmovl_u8(vsrc); vsrc_wide = vmulq_u16(vsrc_wide, vdupq_n_u16(src_scale)); vdst_wide = vmull_u8(vdst, vdup_n_u8(dst_scale)); -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - vres = vshrn_n_u16(vdst_wide, 8) + vshrn_n_u16(vsrc_wide, 8); -#else vdst_wide += vsrc_wide; vres = vshrn_n_u16(vdst_wide, 8); -#endif // Store vst1_lane_u32(dst, vreinterpret_u32_u8(vres), 0); @@ -984,12 +976,8 @@ void S32A_Blend_BlitRow32_neon(SkPMColor* SK_RESTRICT dst, vdst_wide = vmulq_n_u16(vdst_wide, dst_scale); // Combine -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - vres = vshrn_n_u16(vdst_wide, 8) + vshrn_n_u16(vsrc_wide, 8); -#else vdst_wide += vsrc_wide; vres = vshrn_n_u16(vdst_wide, 8); -#endif vst1_lane_u32(dst, vreinterpret_u32_u8(vres), 0); dst++; @@ -1020,11 +1008,6 @@ void S32A_Blend_BlitRow32_neon(SkPMColor* SK_RESTRICT dst, // Calc dst_scale vsrc_alphas = vtbl1_u8(vsrc, alpha_mask); vdst_scale = vmovl_u8(vsrc_alphas); -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - vdst_scale *= vsrc_scale; - vdst_scale = vshrq_n_u16(vdst_scale, 8); - vdst_scale = vsubq_u16(vdupq_n_u16(256), vdst_scale); -#else // Calculate SkAlphaMulInv256(vdst_scale, vsrc_scale). // A 16-bit lane would overflow if we used 0xFFFF here, // so use an approximation with 0xFF00 that is off by 1, @@ -1033,7 +1016,6 @@ void S32A_Blend_BlitRow32_neon(SkPMColor* SK_RESTRICT dst, vdst_scale = vmlsq_u16(vdupq_n_u16(0xFF00), vdst_scale, vsrc_scale); vdst_scale = vsraq_n_u16(vdst_scale, vdst_scale, 8); vdst_scale = vsraq_n_u16(vdupq_n_u16(1), vdst_scale, 8); -#endif // Process src vsrc_wide = vmovl_u8(vsrc); @@ -1044,12 +1026,8 @@ void S32A_Blend_BlitRow32_neon(SkPMColor* SK_RESTRICT dst, vdst_wide *= vdst_scale; // Combine -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - vres = vshrn_n_u16(vdst_wide, 8) + vshrn_n_u16(vsrc_wide, 8); -#else vdst_wide += vsrc_wide; vres = vshrn_n_u16(vdst_wide, 8); -#endif vst1_u32(dst, vreinterpret_u32_u8(vres)); diff --git a/gfx/skia/skia/src/opts/SkBlitRow_opts_mips_dsp.cpp b/gfx/skia/skia/src/opts/SkBlitRow_opts_mips_dsp.cpp deleted file mode 100644 index 38922b2ead35..000000000000 --- a/gfx/skia/skia/src/opts/SkBlitRow_opts_mips_dsp.cpp +++ /dev/null @@ -1,958 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBlitRow.h" -#include "SkBlitMask.h" -#include "SkColorPriv.h" -#include "SkDither.h" -#include "SkMathPriv.h" - -static void S32_D565_Blend_mips_dsp(uint16_t* SK_RESTRICT dst, - const SkPMColor* SK_RESTRICT src, int count, - U8CPU alpha, int /*x*/, int /*y*/) { - uint32_t t0, t1, t2, t3, t4, t5, t6; - uint32_t s0, s1, s2, s4, s5, s6; - - alpha += 1; - if (count >= 2) { - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "sll %[s4], %[alpha], 8 \n\t" - "or %[s4], %[s4], %[alpha] \n\t" - "repl.ph %[s5], 0x1f \n\t" - "repl.ph %[s6], 0x3f \n\t" - "1: \n\t" - "lw %[s2], 0(%[src]) \n\t" - "lw %[s1], 4(%[src]) \n\t" - "lwr %[s0], 0(%[dst]) \n\t" - "lwl %[s0], 3(%[dst]) \n\t" - "and %[t1], %[s0], %[s5] \n\t" - "shra.ph %[t0], %[s0], 5 \n\t" - "and %[t2], %[t0], %[s6] \n\t" -#ifdef __mips_dspr2 - "shrl.ph %[t3], %[s0], 11 \n\t" -#else - "shra.ph %[t0], %[s0], 11 \n\t" - "and %[t3], %[t0], %[s5] \n\t" -#endif - "precrq.ph.w %[t0], %[s1], %[s2] \n\t" - "shrl.qb %[t5], %[t0], 3 \n\t" - "and %[t4], %[t5], %[s5] \n\t" - "ins %[s2], %[s1], 16, 16 \n\t" - "preceu.ph.qbra %[t0], %[s2] \n\t" - "shrl.qb %[t6], %[t0], 3 \n\t" -#ifdef __mips_dspr2 - "shrl.ph %[t5], %[s2], 10 \n\t" -#else - "shra.ph %[t0], %[s2], 10 \n\t" - "and %[t5], %[t0], %[s6] \n\t" -#endif - "subu.qb %[t4], %[t4], %[t1] \n\t" - "subu.qb %[t5], %[t5], %[t2] \n\t" - "subu.qb %[t6], %[t6], %[t3] \n\t" - "muleu_s.ph.qbr %[t4], %[s4], %[t4] \n\t" - "muleu_s.ph.qbr %[t5], %[s4], %[t5] \n\t" - "muleu_s.ph.qbr %[t6], %[s4], %[t6] \n\t" - "addiu %[count], %[count], -2 \n\t" - "addiu %[src], %[src], 8 \n\t" - "shra.ph %[t4], %[t4], 8 \n\t" - "shra.ph %[t5], %[t5], 8 \n\t" - "shra.ph %[t6], %[t6], 8 \n\t" - "addu.qb %[t4], %[t4], %[t1] \n\t" - "addu.qb %[t5], %[t5], %[t2] \n\t" - "addu.qb %[t6], %[t6], %[t3] \n\t" - "andi %[s0], %[t4], 0xffff \n\t" - "andi %[t0], %[t5], 0xffff \n\t" - "sll %[t0], %[t0], 0x5 \n\t" - "or %[s0], %[s0], %[t0] \n\t" - "sll %[t0], %[t6], 0xb \n\t" - "or %[t0], %[t0], %[s0] \n\t" - "sh %[t0], 0(%[dst]) \n\t" - "srl %[s1], %[t4], 16 \n\t" - "srl %[t0], %[t5], 16 \n\t" - "sll %[t5], %[t0], 5 \n\t" - "or %[t0], %[t5], %[s1] \n\t" - "srl %[s0], %[t6], 16 \n\t" - "sll %[s2], %[s0], 0xb \n\t" - "or %[s1], %[s2], %[t0] \n\t" - "sh %[s1], 2(%[dst]) \n\t" - "bge %[count], 2, 1b \n\t" - " addiu %[dst], %[dst], 4 \n\t" - ".set pop \n\t" - : [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3), - [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), [s0]"=&r"(s0), - [s1]"=&r"(s1), [s2]"=&r"(s2), [s4]"=&r"(s4), [s5]"=&r"(s5), - [s6]"=&r"(s6), [count]"+r"(count), [dst]"+r"(dst), - [src]"+r"(src) - : [alpha]"r"(alpha) - : "memory", "hi", "lo" - ); - } - - if (count == 1) { - SkPMColor c = *src++; - SkPMColorAssert(c); - SkASSERT(SkGetPackedA32(c) == 255); - uint16_t d = *dst; - *dst++ = SkPackRGB16(SkAlphaBlend(SkPacked32ToR16(c), SkGetPackedR16(d), alpha), - SkAlphaBlend(SkPacked32ToG16(c), SkGetPackedG16(d), alpha), - SkAlphaBlend(SkPacked32ToB16(c), SkGetPackedB16(d), alpha)); - } -} - -static void S32A_D565_Opaque_Dither_mips_dsp(uint16_t* __restrict__ dst, - const SkPMColor* __restrict__ src, - int count, U8CPU alpha, int x, int y) { - __asm__ volatile ( - "pref 0, 0(%[src]) \n\t" - "pref 1, 0(%[dst]) \n\t" - "pref 0, 32(%[src]) \n\t" - "pref 1, 32(%[dst]) \n\t" - : - : [src]"r"(src), [dst]"r"(dst) - : "memory" - ); - - int32_t t0, t1, t2, t3, t4, t5, t6; - int32_t t7, t8, t9, s0, s1, s2, s3; - const uint16_t dither_scan = gDitherMatrix_3Bit_16[(y) & 3]; - - if (count >= 2) { - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "li %[s1], 0x01010101 \n\t" - "li %[s2], -2017 \n\t" - "1: \n\t" - "bnez %[s3], 4f \n\t" - " li %[s3], 2 \n\t" - "pref 0, 64(%[src]) \n\t" - "pref 1, 64(%[dst]) \n\t" - "4: \n\t" - "addiu %[s3], %[s3], -1 \n\t" - "lw %[t1], 0(%[src]) \n\t" - "andi %[t3], %[x], 0x3 \n\t" - "addiu %[x], %[x], 1 \n\t" - "sll %[t4], %[t3], 2 \n\t" - "srav %[t5], %[dither_scan], %[t4] \n\t" - "andi %[t3], %[t5], 0xf \n\t" - "lw %[t2], 4(%[src]) \n\t" - "andi %[t4], %[x], 0x3 \n\t" - "sll %[t5], %[t4], 2 \n\t" - "srav %[t6], %[dither_scan], %[t5] \n\t" - "addiu %[x], %[x], 1 \n\t" - "ins %[t3], %[t6], 8, 4 \n\t" - "srl %[t4], %[t1], 24 \n\t" - "addiu %[t0], %[t4], 1 \n\t" - "srl %[t4], %[t2], 24 \n\t" - "addiu %[t5], %[t4], 1 \n\t" - "ins %[t0], %[t5], 16, 16 \n\t" - "muleu_s.ph.qbr %[t4], %[t3], %[t0] \n\t" - "preceu.ph.qbla %[t3], %[t4] \n\t" - "andi %[t4], %[t1], 0xff \n\t" - "ins %[t4], %[t2], 16, 8 \n\t" - "shrl.qb %[t5], %[t4], 5 \n\t" - "subu.qb %[t6], %[t3], %[t5] \n\t" - "addq.ph %[t5], %[t6], %[t4] \n\t" - "ext %[t4], %[t1], 8, 8 \n\t" - "srl %[t6], %[t2], 8 \n\t" - "ins %[t4], %[t6], 16, 8 \n\t" - "shrl.qb %[t6], %[t4], 6 \n\t" - "shrl.qb %[t7], %[t3], 1 \n\t" - "subu.qb %[t8], %[t7], %[t6] \n\t" - "addq.ph %[t6], %[t8], %[t4] \n\t" - "ext %[t4], %[t1], 16, 8 \n\t" - "srl %[t7], %[t2], 16 \n\t" - "ins %[t4], %[t7], 16, 8 \n\t" - "shrl.qb %[t7], %[t4], 5 \n\t" - "subu.qb %[t8], %[t3], %[t7] \n\t" - "addq.ph %[t7], %[t8], %[t4] \n\t" - "shll.ph %[t4], %[t7], 2 \n\t" - "andi %[t9], %[t4], 0xffff \n\t" - "srl %[s0], %[t4], 16 \n\t" - "andi %[t3], %[t6], 0xffff \n\t" - "srl %[t4], %[t6], 16 \n\t" - "andi %[t6], %[t5], 0xffff \n\t" - "srl %[t7], %[t5], 16 \n\t" - "subq.ph %[t5], %[s1], %[t0] \n\t" - "srl %[t0], %[t5], 3 \n\t" - "beqz %[t1], 3f \n\t" - " lhu %[t5], 0(%[dst]) \n\t" - "sll %[t1], %[t6], 13 \n\t" - "or %[t8], %[t9], %[t1] \n\t" - "sll %[t1], %[t3], 24 \n\t" - "or %[t9], %[t1], %[t8] \n\t" - "andi %[t3], %[t5], 0x7e0 \n\t" - "sll %[t6], %[t3], 0x10 \n\t" - "and %[t8], %[s2], %[t5] \n\t" - "or %[t5], %[t6], %[t8] \n\t" - "andi %[t6], %[t0], 0xff \n\t" - "mul %[t1], %[t6], %[t5] \n\t" - "addu %[t5], %[t1], %[t9] \n\t" - "srl %[t6], %[t5], 5 \n\t" - "and %[t5], %[s2], %[t6] \n\t" - "srl %[t8], %[t6], 16 \n\t" - "andi %[t6], %[t8], 0x7e0 \n\t" - "or %[t1], %[t5], %[t6] \n\t" - "sh %[t1], 0(%[dst]) \n\t" - "3: \n\t" - "beqz %[t2], 2f \n\t" - " lhu %[t5], 2(%[dst]) \n\t" - "sll %[t1], %[t7], 13 \n\t" - "or %[t8], %[s0], %[t1] \n\t" - "sll %[t1], %[t4], 24 \n\t" - "or %[t9], %[t1], %[t8] \n\t" - "andi %[t3], %[t5], 0x7e0 \n\t" - "sll %[t6], %[t3], 0x10 \n\t" - "and %[t8], %[s2], %[t5] \n\t" - "or %[t5], %[t6], %[t8] \n\t" - "srl %[t6], %[t0], 16 \n\t" - "mul %[t1], %[t6], %[t5] \n\t" - "addu %[t5], %[t1], %[t9] \n\t" - "srl %[t6], %[t5], 5 \n\t" - "and %[t5], %[s2], %[t6] \n\t" - "srl %[t8], %[t6], 16 \n\t" - "andi %[t6], %[t8], 0x7e0 \n\t" - "or %[t1], %[t5], %[t6] \n\t" - "sh %[t1], 2(%[dst]) \n\t" - "2: \n\t" - "addiu %[count], %[count], -2 \n\t" - "addiu %[src], %[src], 8 \n\t" - "addiu %[t1], %[count], -1 \n\t" - "bgtz %[t1], 1b \n\t" - " addiu %[dst], %[dst], 4 \n\t" - ".set pop \n\t" - : [src]"+r"(src), [count]"+r"(count), [dst]"+r"(dst), [x]"+r"(x), - [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3), - [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), [t7]"=&r"(t7), - [t8]"=&r"(t8), [t9]"=&r"(t9), [s0]"=&r"(s0), [s1]"=&r"(s1), - [s2]"=&r"(s2), [s3]"=&r"(s3) - : [dither_scan]"r"(dither_scan) - : "memory", "hi", "lo" - ); - } - - if (count == 1) { - SkPMColor c = *src++; - SkPMColorAssert(c); - if (c) { - unsigned a = SkGetPackedA32(c); - int d = SkAlphaMul(DITHER_VALUE(x), SkAlpha255To256(a)); - - unsigned sr = SkGetPackedR32(c); - unsigned sg = SkGetPackedG32(c); - unsigned sb = SkGetPackedB32(c); - sr = SkDITHER_R32_FOR_565(sr, d); - sg = SkDITHER_G32_FOR_565(sg, d); - sb = SkDITHER_B32_FOR_565(sb, d); - - uint32_t src_expanded = (sg << 24) | (sr << 13) | (sb << 2); - uint32_t dst_expanded = SkExpand_rgb_16(*dst); - dst_expanded = dst_expanded * (SkAlpha255To256(255 - a) >> 3); - // now src and dst expanded are in g:11 r:10 x:1 b:10 - *dst = SkCompact_rgb_16((src_expanded + dst_expanded) >> 5); - } - dst += 1; - DITHER_INC_X(x); - } -} - -static void S32_D565_Opaque_Dither_mips_dsp(uint16_t* __restrict__ dst, - const SkPMColor* __restrict__ src, - int count, U8CPU alpha, int x, int y) { - uint16_t dither_scan = gDitherMatrix_3Bit_16[(y) & 3]; - uint32_t t0, t1, t2, t3, t4, t5; - uint32_t t6, t7, t8, t9, s0; - int dither[4]; - int i; - - for (i = 0; i < 4; i++, x++) { - dither[i] = (dither_scan >> ((x & 3) << 2)) & 0xF; - } - - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "li %[s0], 1 \n\t" - "2: \n\t" - "beqz %[count], 1f \n\t" - " nop \n\t" - "addiu %[t0], %[count], -1 \n\t" - "beqz %[t0], 1f \n\t" - " nop \n\t" - "beqz %[s0], 3f \n\t" - " nop \n\t" - "lw %[t0], 0(%[dither]) \n\t" - "lw %[t1], 4(%[dither]) \n\t" - "li %[s0], 0 \n\t" - "b 4f \n\t" - " nop \n\t" - "3: \n\t" - "lw %[t0], 8(%[dither]) \n\t" - "lw %[t1], 12(%[dither]) \n\t" - "li %[s0], 1 \n\t" - "4: \n\t" - "sll %[t2], %[t0], 16 \n\t" - "or %[t1], %[t2], %[t1] \n\t" - "lw %[t0], 0(%[src]) \n\t" - "lw %[t2], 4(%[src]) \n\t" - "precrq.ph.w %[t3], %[t0], %[t2] \n\t" - "preceu.ph.qbra %[t9], %[t3] \n\t" -#ifdef __mips_dspr2 - "append %[t0], %[t2], 16 \n\t" - "preceu.ph.qbra %[t4], %[t0] \n\t" - "preceu.ph.qbla %[t5], %[t0] \n\t" -#else - "sll %[t6], %[t0], 16 \n\t" - "sll %[t7], %[t2], 16 \n\t" - "precrq.ph.w %[t8], %[t6], %[t7] \n\t" - "preceu.ph.qbra %[t4], %[t8] \n\t" - "preceu.ph.qbla %[t5], %[t8] \n\t" -#endif - "addu.qb %[t0], %[t4], %[t1] \n\t" - "shra.ph %[t2], %[t4], 5 \n\t" - "subu.qb %[t3], %[t0], %[t2] \n\t" - "shra.ph %[t6], %[t3], 3 \n\t" - "addu.qb %[t0], %[t9], %[t1] \n\t" - "shra.ph %[t2], %[t9], 5 \n\t" - "subu.qb %[t3], %[t0], %[t2] \n\t" - "shra.ph %[t7], %[t3], 3 \n\t" - "shra.ph %[t0], %[t1], 1 \n\t" - "shra.ph %[t2], %[t5], 6 \n\t" - "addu.qb %[t3], %[t5], %[t0] \n\t" - "subu.qb %[t4], %[t3], %[t2] \n\t" - "shra.ph %[t8], %[t4], 2 \n\t" - "precrq.ph.w %[t0], %[t6], %[t7] \n\t" -#ifdef __mips_dspr2 - "append %[t6], %[t7], 16 \n\t" -#else - "sll %[t6], %[t6], 16 \n\t" - "sll %[t2], %[t7], 16 \n\t" - "precrq.ph.w %[t6], %[t6], %[t2] \n\t" -#endif - "sra %[t4], %[t8], 16 \n\t" - "andi %[t5], %[t8], 0xFF \n\t" - "sll %[t7], %[t4], 5 \n\t" - "sra %[t8], %[t0], 5 \n\t" - "or %[t9], %[t7], %[t8] \n\t" - "or %[t3], %[t9], %[t0] \n\t" - "andi %[t4], %[t3], 0xFFFF \n\t" - "sll %[t7], %[t5], 5 \n\t" - "sra %[t8], %[t6], 5 \n\t" - "or %[t9], %[t7], %[t8] \n\t" - "or %[t3], %[t9], %[t6] \n\t" - "and %[t7], %[t3], 0xFFFF \n\t" - "sh %[t4], 0(%[dst]) \n\t" - "sh %[t7], 2(%[dst]) \n\t" - "addiu %[count], %[count], -2 \n\t" - "addiu %[src], %[src], 8 \n\t" - "b 2b \n\t" - " addiu %[dst], %[dst], 4 \n\t" - "1: \n\t" - ".set pop \n\t" - : [dst]"+r"(dst), [src]"+r"(src), [count]"+r"(count), - [x]"+r"(x), [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), - [t3]"=&r"(t3), [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), - [t7]"=&r"(t7), [t8]"=&r"(t8), [t9]"=&r"(t9), [s0]"=&r"(s0) - : [dither] "r" (dither) - : "memory" - ); - - if (count == 1) { - SkPMColor c = *src++; - SkPMColorAssert(c); // only if DEBUG is turned on - SkASSERT(SkGetPackedA32(c) == 255); - unsigned dither = DITHER_VALUE(x); - *dst++ = SkDitherRGB32To565(c, dither); - } -} - -static void S32_D565_Blend_Dither_mips_dsp(uint16_t* dst, - const SkPMColor* src, - int count, U8CPU alpha, int x, int y) { - int32_t t0, t1, t2, t3, t4, t5, t6; - int32_t s0, s1, s2, s3; - int x1 = 0; - uint32_t sc_mul; - uint32_t sc_add; -#ifdef ENABLE_DITHER_MATRIX_4X4 - const uint8_t* dither_scan = gDitherMatrix_3Bit_4X4[(y) & 3]; -#else // ENABLE_DITHER_MATRIX_4X4 - const uint16_t dither_scan = gDitherMatrix_3Bit_16[(y) & 3]; -#endif // ENABLE_DITHER_MATRIX_4X4 - int dither[4]; - - for (int i = 0; i < 4; i++) { - dither[i] = (dither_scan >> ((x & 3) << 2)) & 0xF; - x += 1; - } - alpha += 1; - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "li %[t0], 0x100 \n\t" - "subu %[t0], %[t0], %[alpha] \n\t" - "replv.ph %[sc_mul], %[alpha] \n\t" - "beqz %[alpha], 1f \n\t" - " nop \n\t" - "replv.qb %[sc_add], %[t0] \n\t" - "b 2f \n\t" - " nop \n\t" - "1: \n\t" - "replv.qb %[sc_add], %[alpha] \n\t" - "2: \n\t" - "addiu %[t2], %[count], -1 \n\t" - "blez %[t2], 3f \n\t" - " nop \n\t" - "lw %[s0], 0(%[src]) \n\t" - "lw %[s1], 4(%[src]) \n\t" - "bnez %[x1], 4f \n\t" - " nop \n\t" - "lw %[t0], 0(%[dither]) \n\t" - "lw %[t1], 4(%[dither]) \n\t" - "li %[x1], 1 \n\t" - "b 5f \n\t" - " nop \n\t" - "4: \n\t" - "lw %[t0], 8(%[dither]) \n\t" - "lw %[t1], 12(%[dither]) \n\t" - "li %[x1], 0 \n\t" - "5: \n\t" - "sll %[t3], %[t0], 7 \n\t" - "sll %[t4], %[t1], 7 \n\t" -#ifdef __mips_dspr2 - "append %[t0], %[t1], 16 \n\t" -#else - "sll %[t0], %[t0], 8 \n\t" - "sll %[t2], %[t1], 8 \n\t" - "precrq.qb.ph %[t0], %[t0], %[t2] \n\t" -#endif - "precrq.qb.ph %[t1], %[t3], %[t4] \n\t" - "sll %[t5], %[s0], 8 \n\t" - "sll %[t6], %[s1], 8 \n\t" - "precrq.qb.ph %[t4], %[t5], %[t6] \n\t" - "precrq.qb.ph %[t6], %[s0], %[s1] \n\t" - "preceu.ph.qbla %[t5], %[t4] \n\t" - "preceu.ph.qbra %[t4], %[t4] \n\t" - "preceu.ph.qbra %[t6], %[t6] \n\t" - "lh %[t2], 0(%[dst]) \n\t" - "lh %[s1], 2(%[dst]) \n\t" -#ifdef __mips_dspr2 - "append %[t2], %[s1], 16 \n\t" -#else - "sll %[s1], %[s1], 16 \n\t" - "packrl.ph %[t2], %[t2], %[s1] \n\t" -#endif - "shra.ph %[s1], %[t2], 11 \n\t" - "and %[s1], %[s1], 0x1F001F \n\t" - "shra.ph %[s2], %[t2], 5 \n\t" - "and %[s2], %[s2], 0x3F003F \n\t" - "and %[s3], %[t2], 0x1F001F \n\t" - "shrl.qb %[t3], %[t4], 5 \n\t" - "addu.qb %[t4], %[t4], %[t0] \n\t" - "subu.qb %[t4], %[t4], %[t3] \n\t" - "shrl.qb %[t4], %[t4], 3 \n\t" - "shrl.qb %[t3], %[t5], 5 \n\t" - "addu.qb %[t5], %[t5], %[t0] \n\t" - "subu.qb %[t5], %[t5], %[t3] \n\t" - "shrl.qb %[t5], %[t5], 3 \n\t" - "shrl.qb %[t3], %[t6], 6 \n\t" - "addu.qb %[t6], %[t6], %[t1] \n\t" - "subu.qb %[t6], %[t6], %[t3] \n\t" - "shrl.qb %[t6], %[t6], 2 \n\t" - "cmpu.lt.qb %[t4], %[s1] \n\t" - "pick.qb %[s0], %[sc_add], $0 \n\t" - "addu.qb %[s0], %[s0], %[s1] \n\t" - "subu.qb %[t4], %[t4], %[s1] \n\t" - "muleu_s.ph.qbl %[t0], %[t4], %[sc_mul] \n\t" - "muleu_s.ph.qbr %[t1], %[t4], %[sc_mul] \n\t" - "precrq.qb.ph %[t4], %[t0], %[t1] \n\t" - "addu.qb %[t4], %[t4], %[s0] \n\t" - "cmpu.lt.qb %[t5], %[s3] \n\t" - "pick.qb %[s0], %[sc_add], $0 \n\t" - "addu.qb %[s0], %[s0], %[s3] \n\t" - "subu.qb %[t5], %[t5], %[s3] \n\t" - "muleu_s.ph.qbl %[t0], %[t5], %[sc_mul] \n\t" - "muleu_s.ph.qbr %[t1], %[t5], %[sc_mul] \n\t" - "precrq.qb.ph %[t5], %[t0], %[t1] \n\t" - "addu.qb %[t5], %[t5], %[s0] \n\t" - "cmpu.lt.qb %[t6], %[s2] \n\t" - "pick.qb %[s0], %[sc_add], $0 \n\t" - "addu.qb %[s0], %[s0], %[s2] \n\t" - "subu.qb %[t6], %[t6], %[s2] \n\t" - "muleu_s.ph.qbl %[t0], %[t6], %[sc_mul] \n\t" - "muleu_s.ph.qbr %[t1], %[t6], %[sc_mul] \n\t" - "precrq.qb.ph %[t6], %[t0], %[t1] \n\t" - "addu.qb %[t6], %[t6], %[s0] \n\t" - "shll.ph %[s1], %[t4], 11 \n\t" - "shll.ph %[t0], %[t6], 5 \n\t" - "or %[s0], %[s1], %[t0] \n\t" - "or %[s1], %[s0], %[t5] \n\t" - "srl %[t2], %[s1], 16 \n\t" - "and %[t3], %[s1], 0xFFFF \n\t" - "sh %[t2], 0(%[dst]) \n\t" - "sh %[t3], 2(%[dst]) \n\t" - "addiu %[src], %[src], 8 \n\t" - "addi %[count], %[count], -2 \n\t" - "b 2b \n\t" - " addu %[dst], %[dst], 4 \n\t" - "3: \n\t" - ".set pop \n\t" - : [src]"+r"(src), [dst]"+r"(dst), [count]"+r"(count), - [x1]"+r"(x1), [sc_mul]"=&r"(sc_mul), [sc_add]"=&r"(sc_add), - [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3), - [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), [s0]"=&r"(s0), - [s1]"=&r"(s1), [s2]"=&r"(s2), [s3]"=&r"(s3) - : [dither]"r"(dither), [alpha]"r"(alpha) - : "memory", "hi", "lo" - ); - - if(count == 1) { - SkPMColor c = *src++; - SkPMColorAssert(c); - SkASSERT(SkGetPackedA32(c) == 255); - DITHER_565_SCAN(y); - int dither = DITHER_VALUE(x); - int sr = SkGetPackedR32(c); - int sg = SkGetPackedG32(c); - int sb = SkGetPackedB32(c); - sr = SkDITHER_R32To565(sr, dither); - sg = SkDITHER_G32To565(sg, dither); - sb = SkDITHER_B32To565(sb, dither); - - uint16_t d = *dst; - *dst++ = SkPackRGB16(SkAlphaBlend(sr, SkGetPackedR16(d), alpha), - SkAlphaBlend(sg, SkGetPackedG16(d), alpha), - SkAlphaBlend(sb, SkGetPackedB16(d), alpha)); - DITHER_INC_X(x); - } -} - -static void S32A_D565_Opaque_mips_dsp(uint16_t* __restrict__ dst, - const SkPMColor* __restrict__ src, - int count, U8CPU alpha, int x, int y) { - - __asm__ volatile ( - "pref 0, 0(%[src]) \n\t" - "pref 1, 0(%[dst]) \n\t" - "pref 0, 32(%[src]) \n\t" - "pref 1, 32(%[dst]) \n\t" - : - : [src]"r"(src), [dst]"r"(dst) - : "memory" - ); - - uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8; - uint32_t t16; - uint32_t add_x10 = 0x100010; - uint32_t add_x20 = 0x200020; - uint32_t sa = 0xff00ff; - - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "blez %[count], 1f \n\t" - " nop \n\t" - "2: \n\t" - "beqz %[count], 1f \n\t" - " nop \n\t" - "addiu %[t0], %[count], -1 \n\t" - "beqz %[t0], 1f \n\t" - " nop \n\t" - "bnez %[t16], 3f \n\t" - " nop \n\t" - "li %[t16], 2 \n\t" - "pref 0, 64(%[src]) \n\t" - "pref 1, 64(%[dst]) \n\t" - "3: \n\t" - "addiu %[t16], %[t16], -1 \n\t" - "lw %[t0], 0(%[src]) \n\t" - "lw %[t1], 4(%[src]) \n\t" - "precrq.ph.w %[t2], %[t0], %[t1] \n\t" - "preceu.ph.qbra %[t8], %[t2] \n\t" -#ifdef __mips_dspr2 - "append %[t0], %[t1], 16 \n\t" -#else - "sll %[t0], %[t0], 16 \n\t" - "sll %[t6], %[t1], 16 \n\t" - "precrq.ph.w %[t0], %[t0], %[t6] \n\t" -#endif - "preceu.ph.qbra %[t3], %[t0] \n\t" - "preceu.ph.qbla %[t4], %[t0] \n\t" - "preceu.ph.qbla %[t0], %[t2] \n\t" - "subq.ph %[t1], %[sa], %[t0] \n\t" - "sra %[t2], %[t1], 8 \n\t" - "or %[t5], %[t2], %[t1] \n\t" - "replv.ph %[t2], %[t5] \n\t" - "lh %[t0], 0(%[dst]) \n\t" - "lh %[t1], 2(%[dst]) \n\t" - "and %[t1], %[t1], 0xffff \n\t" -#ifdef __mips_dspr2 - "append %[t0], %[t1], 16 \n\t" -#else - "sll %[t5], %[t0], 16 \n\t" - "or %[t0], %[t5], %[t1] \n\t" -#endif - "and %[t1], %[t0], 0x1f001f \n\t" - "shra.ph %[t6], %[t0], 11 \n\t" - "and %[t6], %[t6], 0x1f001f \n\t" - "and %[t7], %[t0], 0x7e007e0 \n\t" - "shra.ph %[t5], %[t7], 5 \n\t" - "muleu_s.ph.qbl %[t0], %[t2], %[t6] \n\t" - "addq.ph %[t7], %[t0], %[add_x10] \n\t" - "shra.ph %[t6], %[t7], 5 \n\t" - "addq.ph %[t6], %[t7], %[t6] \n\t" - "shra.ph %[t0], %[t6], 5 \n\t" - "addq.ph %[t7], %[t0], %[t3] \n\t" - "shra.ph %[t6], %[t7], 3 \n\t" - "muleu_s.ph.qbl %[t0], %[t2], %[t1] \n\t" - "addq.ph %[t7], %[t0], %[add_x10] \n\t" - "shra.ph %[t0], %[t7], 5 \n\t" - "addq.ph %[t7], %[t7], %[t0] \n\t" - "shra.ph %[t0], %[t7], 5 \n\t" - "addq.ph %[t7], %[t0], %[t8] \n\t" - "shra.ph %[t3], %[t7], 3 \n\t" - "muleu_s.ph.qbl %[t0], %[t2], %[t5] \n\t" - "addq.ph %[t7], %[t0], %[add_x20] \n\t" - "shra.ph %[t0], %[t7], 6 \n\t" - "addq.ph %[t8], %[t7], %[t0] \n\t" - "shra.ph %[t0], %[t8], 6 \n\t" - "addq.ph %[t7], %[t0], %[t4] \n\t" - "shra.ph %[t8], %[t7], 2 \n\t" - "shll.ph %[t0], %[t8], 5 \n\t" - "shll.ph %[t1], %[t6], 11 \n\t" - "or %[t2], %[t0], %[t1] \n\t" - "or %[t3], %[t2], %[t3] \n\t" - "sra %[t4], %[t3], 16 \n\t" - "sh %[t4], 0(%[dst]) \n\t" - "sh %[t3], 2(%[dst]) \n\t" - "addiu %[count], %[count], -2 \n\t" - "addiu %[src], %[src], 8 \n\t" - "b 2b \n\t" - " addiu %[dst], %[dst], 4 \n\t" - "1: \n\t" - ".set pop \n\t" - : [dst]"+r"(dst), [src]"+r"(src), [count]"+r"(count), - [t16]"=&r"(t16), [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), - [t3]"=&r"(t3), [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), - [t7]"=&r"(t7), [t8]"=&r"(t8) - : [add_x10]"r"(add_x10), [add_x20]"r"(add_x20), [sa]"r"(sa) - : "memory", "hi", "lo" - ); - - if (count == 1) { - SkPMColor c = *src++; - SkPMColorAssert(c); - if (c) { - *dst = SkSrcOver32To16(c, *dst); - } - dst += 1; - } -} - -static void S32A_D565_Blend_mips_dsp(uint16_t* SK_RESTRICT dst, - const SkPMColor* SK_RESTRICT src, int count, - U8CPU alpha, int /*x*/, int /*y*/) { - uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; - uint32_t s0, s1, s2, s3; - unsigned dst_scale = 0; - - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "replv.qb %[t0], %[alpha] \n\t" - "repl.ph %[t6], 0x80 \n\t" - "repl.ph %[t7], 0xFF \n\t" - "1: \n\t" - "addiu %[t8], %[count], -1 \n\t" - "blez %[t8], 2f \n\t" - " nop \n\t" - "lw %[t8], 0(%[src]) \n\t" - "lw %[t9], 4(%[src]) \n\t" - "lh %[t4], 0(%[dst]) \n\t" - "lh %[t5], 2(%[dst]) \n\t" - "sll %[t5], %[t5], 16 \n\t" - "sll %[t2], %[t8], 8 \n\t" - "sll %[t3], %[t9], 8 \n\t" - "precrq.qb.ph %[t1], %[t2], %[t3] \n\t" - "precrq.qb.ph %[t3], %[t8], %[t9] \n\t" - "preceu.ph.qbla %[t8], %[t3] \n\t" - "muleu_s.ph.qbr %[s3], %[t0], %[t8] \n\t" - "preceu.ph.qbla %[t2], %[t1] \n\t" - "preceu.ph.qbra %[t1], %[t1] \n\t" - "preceu.ph.qbra %[t3], %[t3] \n\t" - "packrl.ph %[t9], %[t4], %[t5] \n\t" - "shra.ph %[s0], %[t9], 11 \n\t" - "and %[s0], %[s0], 0x1F001F \n\t" - "shra.ph %[s1], %[t9], 5 \n\t" - "and %[s1], %[s1], 0x3F003F \n\t" - "and %[s2], %[t9], 0x1F001F \n\t" - "addq.ph %[s3], %[s3], %[t6] \n\t" - "shra.ph %[t5], %[s3], 8 \n\t" - "and %[t5], %[t5], 0xFF00FF \n\t" - "addq.ph %[dst_scale], %[s3], %[t5] \n\t" - "shra.ph %[dst_scale], %[dst_scale], 8 \n\t" - "subq_s.ph %[dst_scale], %[t7], %[dst_scale] \n\t" - "sll %[dst_scale], %[dst_scale], 8 \n\t" - "precrq.qb.ph %[dst_scale], %[dst_scale], %[dst_scale] \n\t" - "shrl.qb %[t1], %[t1], 3 \n\t" - "shrl.qb %[t2], %[t2], 3 \n\t" - "shrl.qb %[t3], %[t3], 2 \n\t" - "muleu_s.ph.qbl %[t1], %[t0], %[t1] \n\t" - "muleu_s.ph.qbl %[t2], %[t0], %[t2] \n\t" - "muleu_s.ph.qbl %[t3], %[t0], %[t3] \n\t" - "muleu_s.ph.qbl %[t8], %[dst_scale], %[s0] \n\t" - "muleu_s.ph.qbl %[t9], %[dst_scale], %[s2] \n\t" - "muleu_s.ph.qbl %[t4], %[dst_scale], %[s1] \n\t" - "addq.ph %[t1], %[t1], %[t8] \n\t" - "addq.ph %[t2], %[t2], %[t9] \n\t" - "addq.ph %[t3], %[t3], %[t4] \n\t" - "addq.ph %[t8], %[t1], %[t6] \n\t" - "addq.ph %[t9], %[t2], %[t6] \n\t" - "addq.ph %[t4], %[t3], %[t6] \n\t" - "shra.ph %[t1], %[t8], 8 \n\t" - "addq.ph %[t1], %[t1], %[t8] \n\t" - "preceu.ph.qbla %[t1], %[t1] \n\t" - "shra.ph %[t2], %[t9], 8 \n\t" - "addq.ph %[t2], %[t2], %[t9] \n\t" - "preceu.ph.qbla %[t2], %[t2] \n\t" - "shra.ph %[t3], %[t4], 8 \n\t" - "addq.ph %[t3], %[t3], %[t4] \n\t" - "preceu.ph.qbla %[t3], %[t3] \n\t" - "shll.ph %[t8], %[t1], 11 \n\t" - "shll.ph %[t9], %[t3], 5 \n\t" - "or %[t8], %[t8], %[t9] \n\t" - "or %[s0], %[t8], %[t2] \n\t" - "srl %[t8], %[s0], 16 \n\t" - "and %[t9], %[s0], 0xFFFF \n\t" - "sh %[t8], 0(%[dst]) \n\t" - "sh %[t9], 2(%[dst]) \n\t" - "addiu %[src], %[src], 8 \n\t" - "addiu %[count], %[count], -2 \n\t" - "b 1b \n\t" - " addiu %[dst], %[dst], 4 \n\t" - "2: \n\t" - ".set pop \n\t" - : [src]"+r"(src), [dst]"+r"(dst), [count]"+r"(count), - [dst_scale]"+r"(dst_scale), [s0]"=&r"(s0), [s1]"=&r"(s1), - [s2]"=&r"(s2), [s3]"=&r"(s3), [t0]"=&r"(t0), [t1]"=&r"(t1), - [t2]"=&r"(t2), [t3]"=&r"(t3), [t4]"=&r"(t4), [t5]"=&r"(t5), - [t6]"=&r"(t6), [t7]"=&r"(t7), [t8]"=&r"(t8), [t9]"=&r"(t9) - : [alpha]"r"(alpha) - : "memory", "hi", "lo" - ); - - if (count == 1) { - SkPMColor sc = *src++; - SkPMColorAssert(sc); - if (sc) { - uint16_t dc = *dst; - unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha); - unsigned dr = (SkPacked32ToR16(sc) * alpha) + (SkGetPackedR16(dc) * dst_scale); - unsigned dg = (SkPacked32ToG16(sc) * alpha) + (SkGetPackedG16(dc) * dst_scale); - unsigned db = (SkPacked32ToB16(sc) * alpha) + (SkGetPackedB16(dc) * dst_scale); - *dst = SkPackRGB16(SkDiv255Round(dr), SkDiv255Round(dg), SkDiv255Round(db)); - } - dst += 1; - } -} - -static void S32_Blend_BlitRow32_mips_dsp(SkPMColor* SK_RESTRICT dst, - const SkPMColor* SK_RESTRICT src, - int count, U8CPU alpha) { - int32_t t0, t1, t2, t3, t4, t5, t6, t7; - - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "li %[t2], 0x100 \n\t" - "addiu %[t0], %[alpha], 1 \n\t" - "subu %[t1], %[t2], %[t0] \n\t" - "replv.qb %[t7], %[t0] \n\t" - "replv.qb %[t6], %[t1] \n\t" - "1: \n\t" - "blez %[count], 2f \n\t" - "lw %[t0], 0(%[src]) \n\t" - "lw %[t1], 0(%[dst]) \n\t" - "preceu.ph.qbr %[t2], %[t0] \n\t" - "preceu.ph.qbl %[t3], %[t0] \n\t" - "preceu.ph.qbr %[t4], %[t1] \n\t" - "preceu.ph.qbl %[t5], %[t1] \n\t" - "muleu_s.ph.qbr %[t2], %[t7], %[t2] \n\t" - "muleu_s.ph.qbr %[t3], %[t7], %[t3] \n\t" - "muleu_s.ph.qbr %[t4], %[t6], %[t4] \n\t" - "muleu_s.ph.qbr %[t5], %[t6], %[t5] \n\t" - "addiu %[src], %[src], 4 \n\t" - "addiu %[count], %[count], -1 \n\t" -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - "precrq.qb.ph %[t0], %[t3], %[t2] \n\t" - "precrq.qb.ph %[t2], %[t5], %[t4] \n\t" - "addu %[t1], %[t0], %[t2] \n\t" -#else - "addu %[t0], %[t3], %[t5] \n\t" - "addu %[t2], %[t2], %[t4] \n\t" - "precrq.qb.ph %[t1], %[t0], %[t2] \n\t" -#endif - "sw %[t1], 0(%[dst]) \n\t" - "b 1b \n\t" - " addi %[dst], %[dst], 4 \n\t" - "2: \n\t" - ".set pop \n\t" - : [src]"+r"(src), [dst]"+r"(dst), [count]"+r"(count), - [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3), - [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), [t7]"=&r"(t7) - : [alpha]"r"(alpha) - : "memory", "hi", "lo" - ); -} - -void blitmask_d565_opaque_mips(int width, int height, uint16_t* device, - unsigned deviceRB, const uint8_t* alpha, - uint32_t expanded32, unsigned maskRB) { - uint32_t s0, s1, s2, s3; - - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - ".set noat \n\t" - "li $t9, 0x7E0F81F \n\t" - "1: \n\t" - "move $t8, %[width] \n\t" - "addiu %[height], %[height], -1 \n\t" - "2: \n\t" - "beqz $t8, 4f \n\t" - " addiu $t0, $t8, -4 \n\t" - "bltz $t0, 3f \n\t" - " nop \n\t" - "addiu $t8, $t8, -4 \n\t" - "lhu $t0, 0(%[device]) \n\t" - "lhu $t1, 2(%[device]) \n\t" - "lhu $t2, 4(%[device]) \n\t" - "lhu $t3, 6(%[device]) \n\t" - "lbu $t4, 0(%[alpha]) \n\t" - "lbu $t5, 1(%[alpha]) \n\t" - "lbu $t6, 2(%[alpha]) \n\t" - "lbu $t7, 3(%[alpha]) \n\t" - "replv.ph $t0, $t0 \n\t" - "replv.ph $t1, $t1 \n\t" - "replv.ph $t2, $t2 \n\t" - "replv.ph $t3, $t3 \n\t" - "addiu %[s0], $t4, 1 \n\t" - "addiu %[s1], $t5, 1 \n\t" - "addiu %[s2], $t6, 1 \n\t" - "addiu %[s3], $t7, 1 \n\t" - "srl %[s0], %[s0], 3 \n\t" - "srl %[s1], %[s1], 3 \n\t" - "srl %[s2], %[s2], 3 \n\t" - "srl %[s3], %[s3], 3 \n\t" - "and $t0, $t0, $t9 \n\t" - "and $t1, $t1, $t9 \n\t" - "and $t2, $t2, $t9 \n\t" - "and $t3, $t3, $t9 \n\t" - "subu $t4, %[expanded32], $t0 \n\t" - "subu $t5, %[expanded32], $t1 \n\t" - "subu $t6, %[expanded32], $t2 \n\t" - "subu $t7, %[expanded32], $t3 \n\t" - "mul $t4, $t4, %[s0] \n\t" - "mul $t5, $t5, %[s1] \n\t" - "mul $t6, $t6, %[s2] \n\t" - "mul $t7, $t7, %[s3] \n\t" - "addiu %[alpha], %[alpha], 4 \n\t" - "srl $t4, $t4, 5 \n\t" - "srl $t5, $t5, 5 \n\t" - "srl $t6, $t6, 5 \n\t" - "srl $t7, $t7, 5 \n\t" - "addu $t4, $t0, $t4 \n\t" - "addu $t5, $t1, $t5 \n\t" - "addu $t6, $t2, $t6 \n\t" - "addu $t7, $t3, $t7 \n\t" - "and $t4, $t4, $t9 \n\t" - "and $t5, $t5, $t9 \n\t" - "and $t6, $t6, $t9 \n\t" - "and $t7, $t7, $t9 \n\t" - "srl $t0, $t4, 16 \n\t" - "srl $t1, $t5, 16 \n\t" - "srl $t2, $t6, 16 \n\t" - "srl $t3, $t7, 16 \n\t" - "or %[s0], $t0, $t4 \n\t" - "or %[s1], $t1, $t5 \n\t" - "or %[s2], $t2, $t6 \n\t" - "or %[s3], $t3, $t7 \n\t" - "sh %[s0], 0(%[device]) \n\t" - "sh %[s1], 2(%[device]) \n\t" - "sh %[s2], 4(%[device]) \n\t" - "sh %[s3], 6(%[device]) \n\t" - "b 2b \n\t" - " addiu %[device], %[device], 8 \n\t" - "3: \n\t" - "lhu $t0, 0(%[device]) \n\t" - "lbu $t1, 0(%[alpha]) \n\t" - "addiu $t8, $t8, -1 \n\t" - "replv.ph $t2, $t0 \n\t" - "and $t2, $t2, $t9 \n\t" - "addiu $t0, $t1, 1 \n\t" - "srl $t0, $t0, 3 \n\t" - "subu $t3, %[expanded32], $t2 \n\t" - "mul $t3, $t3, $t0 \n\t" - "addiu %[alpha], %[alpha], 1 \n\t" - "srl $t3, $t3, 5 \n\t" - "addu $t3, $t2, $t3 \n\t" - "and $t3, $t3, $t9 \n\t" - "srl $t4, $t3, 16 \n\t" - "or %[s0], $t4, $t3 \n\t" - "sh %[s0], 0(%[device]) \n\t" - "bnez $t8, 3b \n\t" - "addiu %[device], %[device], 2 \n\t" - "4: \n\t" - "addu %[device], %[device], %[deviceRB] \n\t" - "bgtz %[height], 1b \n\t" - " addu %[alpha], %[alpha], %[maskRB] \n\t" - ".set pop \n\t" - : [height]"+r"(height), [alpha]"+r"(alpha), [device]"+r"(device), - [deviceRB]"+r"(deviceRB), [maskRB]"+r"(maskRB), [s0]"=&r"(s0), - [s1]"=&r"(s1), [s2]"=&r"(s2), [s3]"=&r"(s3) - : [expanded32] "r" (expanded32), [width] "r" (width) - : "memory", "hi", "lo", "t0", "t1", "t2", "t3", - "t4", "t5", "t6", "t7", "t8", "t9" - ); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -const SkBlitRow::Proc16 platform_565_procs_mips_dsp[] = { - // no dither - nullptr, - S32_D565_Blend_mips_dsp, - S32A_D565_Opaque_mips_dsp, - S32A_D565_Blend_mips_dsp, - - // dither - S32_D565_Opaque_Dither_mips_dsp, - S32_D565_Blend_Dither_mips_dsp, - S32A_D565_Opaque_Dither_mips_dsp, - nullptr, -}; - -static const SkBlitRow::Proc32 platform_32_procs_mips_dsp[] = { - nullptr, // S32_Opaque, - S32_Blend_BlitRow32_mips_dsp, // S32_Blend, - nullptr, // S32A_Opaque, - nullptr, // S32A_Blend, -}; - -SkBlitRow::Proc16 SkBlitRow::PlatformFactory565(unsigned flags) { - return platform_565_procs_mips_dsp[flags]; -} - -SkBlitRow::ColorProc16 SkBlitRow::PlatformColorFactory565(unsigned flags) { - return nullptr; -} - -SkBlitRow::Proc32 SkBlitRow::PlatformProcs32(unsigned flags) { - return platform_32_procs_mips_dsp[flags]; -} diff --git a/gfx/skia/skia/src/opts/SkBlurImageFilter_opts.h b/gfx/skia/skia/src/opts/SkBlurImageFilter_opts.h index 497bcde33f1d..f953a2e7e8ce 100644 --- a/gfx/skia/skia/src/opts/SkBlurImageFilter_opts.h +++ b/gfx/skia/skia/src/opts/SkBlurImageFilter_opts.h @@ -9,7 +9,7 @@ #define SkBlurImageFilter_opts_DEFINED #include "SkColorPriv.h" -#include "SkTypes.h" +#include "SkRect.h" #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 #include diff --git a/gfx/skia/skia/src/opts/SkColorCubeFilter_opts.h b/gfx/skia/skia/src/opts/SkColorCubeFilter_opts.h deleted file mode 100644 index 12acd7803915..000000000000 --- a/gfx/skia/skia/src/opts/SkColorCubeFilter_opts.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SkColorCubeFilter_opts_DEFINED -#define SkColorCubeFilter_opts_DEFINED - -#include "SkColor.h" -#include "SkNx.h" -#include "SkUnPreMultiply.h" - -namespace SK_OPTS_NS { - -static void color_cube_filter_span(const SkPMColor src[], - int count, - SkPMColor dst[], - const int* colorToIndex[2], - const SkScalar* colorToFactors[2], - int dim, - const SkColor* colorCube) { - uint8_t r, g, b, a; - - for (int i = 0; i < count; ++i) { - const SkPMColor input = src[i]; - a = input >> SK_A32_SHIFT; - - if (a != 255) { - const SkColor source = SkUnPreMultiply::PMColorToColor(input); - r = SkColorGetR(source); - g = SkColorGetG(source); - b = SkColorGetB(source); - } else { - r = SkGetPackedR32(input); - g = SkGetPackedG32(input); - b = SkGetPackedB32(input); - } - - const SkScalar g0 = colorToFactors[0][g], - g1 = colorToFactors[1][g], - b0 = colorToFactors[0][b], - b1 = colorToFactors[1][b]; - - const Sk4f g0b0(g0*b0), - g0b1(g0*b1), - g1b0(g1*b0), - g1b1(g1*b1); - - const int i00 = (colorToIndex[0][g] + colorToIndex[0][b] * dim) * dim; - const int i01 = (colorToIndex[0][g] + colorToIndex[1][b] * dim) * dim; - const int i10 = (colorToIndex[1][g] + colorToIndex[0][b] * dim) * dim; - const int i11 = (colorToIndex[1][g] + colorToIndex[1][b] * dim) * dim; - - Sk4f color(0.5f); // Starting from 0.5f gets us rounding for free. - for (int x = 0; x < 2; ++x) { - const int ix = colorToIndex[x][r]; - - const SkColor lutColor00 = colorCube[ix + i00]; - const SkColor lutColor01 = colorCube[ix + i01]; - const SkColor lutColor10 = colorCube[ix + i10]; - const SkColor lutColor11 = colorCube[ix + i11]; - - Sk4f sum = SkNx_cast(Sk4b::Load(&lutColor00)) * g0b0; - sum = sum + SkNx_cast(Sk4b::Load(&lutColor01)) * g0b1; - sum = sum + SkNx_cast(Sk4b::Load(&lutColor10)) * g1b0; - sum = sum + SkNx_cast(Sk4b::Load(&lutColor11)) * g1b1; - color = color + sum * Sk4f((float)colorToFactors[x][r]); - } - if (a != 255) { - color = color * Sk4f(a * (1.0f/255)); - } - - // color is BGRA (SkColor order), dst is SkPMColor order, so may need to swap R+B. - #if defined(SK_PMCOLOR_IS_RGBA) - color = SkNx_shuffle<2,1,0,3>(color); - #endif - uint8_t* dstBytes = (uint8_t*)(dst+i); - SkNx_cast(color).store(dstBytes); - dstBytes[SK_A32_SHIFT/8] = a; - } -} - -} // namespace SK_OPTS NS - -#endif // SkColorCubeFilter_opts_DEFINED diff --git a/gfx/skia/skia/src/opts/SkColor_opts_SSE2.h b/gfx/skia/skia/src/opts/SkColor_opts_SSE2.h index a3db8805981b..5453f20d4bef 100644 --- a/gfx/skia/skia/src/opts/SkColor_opts_SSE2.h +++ b/gfx/skia/skia/src/opts/SkColor_opts_SSE2.h @@ -109,11 +109,7 @@ static inline __m128i SkFastFourByteInterp256_SSE2(const __m128i& src, const __m // Portable version SkPMLerp is in SkColorPriv.h static inline __m128i SkPMLerp_SSE2(const __m128i& src, const __m128i& dst, const unsigned scale) { -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - return _mm_add_epi8(SkAlphaMulQ_SSE2(src, scale), SkAlphaMulQ_SSE2(dst, 256 - scale)); -#else return SkFastFourByteInterp256_SSE2(src, dst, scale); -#endif } static inline __m128i SkGetPackedA32_SSE2(const __m128i& src) { @@ -253,17 +249,6 @@ static inline __m128i SkPMSrcOver_SSE2(const __m128i& src, const __m128i& dst) { static inline __m128i SkBlendARGB32_SSE2(const __m128i& src, const __m128i& dst, const unsigned aa) { unsigned alpha = SkAlpha255To256(aa); -#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP - __m128i src_scale = _mm_set1_epi32(alpha); - // SkAlpha255To256(255 - SkAlphaMul(SkGetPackedA32(src), src_scale)) - __m128i dst_scale = SkGetPackedA32_SSE2(src); - dst_scale = _mm_mullo_epi16(dst_scale, src_scale); - dst_scale = _mm_srli_epi16(dst_scale, 8); - dst_scale = _mm_sub_epi32(_mm_set1_epi32(256), dst_scale); - - __m128i result = SkAlphaMulQ_SSE2(src, alpha); - return _mm_add_epi8(result, SkAlphaMulQ_SSE2(dst, dst_scale)); -#else __m128i src_scale = _mm_set1_epi16(alpha); // SkAlphaMulInv256(SkGetPackedA32(src), src_scale) __m128i dst_scale = SkGetPackedA32_SSE2(src); @@ -298,7 +283,6 @@ static inline __m128i SkBlendARGB32_SSE2(const __m128i& src, const __m128i& dst, dst_rb = _mm_srli_epi16(dst_rb, 8); dst_ag = _mm_andnot_si128(mask, dst_ag); return _mm_or_si128(dst_rb, dst_ag); -#endif } #undef ASSERT_EQ diff --git a/gfx/skia/skia/src/opts/SkMorphologyImageFilter_opts.h b/gfx/skia/skia/src/opts/SkMorphologyImageFilter_opts.h index e30a9e49736f..0c29ff1af29b 100644 --- a/gfx/skia/skia/src/opts/SkMorphologyImageFilter_opts.h +++ b/gfx/skia/skia/src/opts/SkMorphologyImageFilter_opts.h @@ -8,6 +8,8 @@ #ifndef SkMorphologyImageFilter_opts_DEFINED #define SkMorphologyImageFilter_opts_DEFINED +#include "SkColor.h" + namespace SK_OPTS_NS { enum MorphType { kDilate, kErode }; diff --git a/gfx/skia/skia/src/opts/SkNx_neon.h b/gfx/skia/skia/src/opts/SkNx_neon.h index f5a0b09785a7..5671f7131573 100644 --- a/gfx/skia/skia/src/opts/SkNx_neon.h +++ b/gfx/skia/skia/src/opts/SkNx_neon.h @@ -10,13 +10,13 @@ #include -#define SKNX_IS_FAST +namespace { // ARMv8 has vrndmq_f32 to floor 4 floats. Here we emulate it: // - roundtrip through integers via truncation // - subtract 1 if that's too big (possible for negative values). // This restricts the domain of our inputs to a maximum somehwere around 2^31. Seems plenty big. -static inline float32x4_t armv7_vrndmq_f32(float32x4_t v) { +AI static float32x4_t armv7_vrndmq_f32(float32x4_t v) { auto roundtrip = vcvtq_f32_s32(vcvtq_s32_f32(v)); auto too_big = vcgtq_f32(roundtrip, v); return vsubq_f32(roundtrip, (float32x4_t)vandq_u32(too_big, (uint32x4_t)vdupq_n_f32(1))); @@ -25,25 +25,25 @@ static inline float32x4_t armv7_vrndmq_f32(float32x4_t v) { template <> class SkNx<2, float> { public: - SkNx(float32x2_t vec) : fVec(vec) {} + AI SkNx(float32x2_t vec) : fVec(vec) {} - SkNx() {} - SkNx(float val) : fVec(vdup_n_f32(val)) {} - static SkNx Load(const void* ptr) { return vld1_f32((const float*)ptr); } - SkNx(float a, float b) { fVec = (float32x2_t) { a, b }; } + AI SkNx() {} + AI SkNx(float val) : fVec(vdup_n_f32(val)) {} + AI SkNx(float a, float b) { fVec = (float32x2_t) { a, b }; } - void store(void* ptr) const { vst1_f32((float*)ptr, fVec); } + AI static SkNx Load(const void* ptr) { return vld1_f32((const float*)ptr); } + AI void store(void* ptr) const { vst1_f32((float*)ptr, fVec); } - SkNx invert() const { + AI SkNx invert() const { float32x2_t est0 = vrecpe_f32(fVec), est1 = vmul_f32(vrecps_f32(est0, fVec), est0); return est1; } - SkNx operator + (const SkNx& o) const { return vadd_f32(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsub_f32(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmul_f32(fVec, o.fVec); } - SkNx operator / (const SkNx& o) const { + AI SkNx operator + (const SkNx& o) const { return vadd_f32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsub_f32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmul_f32(fVec, o.fVec); } + AI SkNx operator / (const SkNx& o) const { #if defined(SK_CPU_ARM64) return vdiv_f32(fVec, o.fVec); #else @@ -54,24 +54,24 @@ public: #endif } - SkNx operator == (const SkNx& o) const { return vreinterpret_f32_u32(vceq_f32(fVec, o.fVec)); } - SkNx operator < (const SkNx& o) const { return vreinterpret_f32_u32(vclt_f32(fVec, o.fVec)); } - SkNx operator > (const SkNx& o) const { return vreinterpret_f32_u32(vcgt_f32(fVec, o.fVec)); } - SkNx operator <= (const SkNx& o) const { return vreinterpret_f32_u32(vcle_f32(fVec, o.fVec)); } - SkNx operator >= (const SkNx& o) const { return vreinterpret_f32_u32(vcge_f32(fVec, o.fVec)); } - SkNx operator != (const SkNx& o) const { + AI SkNx operator==(const SkNx& o) const { return vreinterpret_f32_u32(vceq_f32(fVec, o.fVec)); } + AI SkNx operator <(const SkNx& o) const { return vreinterpret_f32_u32(vclt_f32(fVec, o.fVec)); } + AI SkNx operator >(const SkNx& o) const { return vreinterpret_f32_u32(vcgt_f32(fVec, o.fVec)); } + AI SkNx operator<=(const SkNx& o) const { return vreinterpret_f32_u32(vcle_f32(fVec, o.fVec)); } + AI SkNx operator>=(const SkNx& o) const { return vreinterpret_f32_u32(vcge_f32(fVec, o.fVec)); } + AI SkNx operator!=(const SkNx& o) const { return vreinterpret_f32_u32(vmvn_u32(vceq_f32(fVec, o.fVec))); } - static SkNx Min(const SkNx& l, const SkNx& r) { return vmin_f32(l.fVec, r.fVec); } - static SkNx Max(const SkNx& l, const SkNx& r) { return vmax_f32(l.fVec, r.fVec); } + AI static SkNx Min(const SkNx& l, const SkNx& r) { return vmin_f32(l.fVec, r.fVec); } + AI static SkNx Max(const SkNx& l, const SkNx& r) { return vmax_f32(l.fVec, r.fVec); } - SkNx rsqrt() const { + AI SkNx rsqrt() const { float32x2_t est0 = vrsqrte_f32(fVec); return vmul_f32(vrsqrts_f32(fVec, vmul_f32(est0, est0)), est0); } - SkNx sqrt() const { + AI SkNx sqrt() const { #if defined(SK_CPU_ARM64) return vsqrt_f32(fVec); #else @@ -82,17 +82,17 @@ public: #endif } - float operator[](int k) const { + AI float operator[](int k) const { SkASSERT(0 <= k && k < 2); union { float32x2_t v; float fs[2]; } pun = {fVec}; return pun.fs[k&1]; } - bool allTrue() const { + AI bool allTrue() const { auto v = vreinterpret_u32_f32(fVec); return vget_lane_u32(v,0) && vget_lane_u32(v,1); } - bool anyTrue() const { + AI bool anyTrue() const { auto v = vreinterpret_u32_f32(fVec); return vget_lane_u32(v,0) || vget_lane_u32(v,1); } @@ -103,24 +103,42 @@ public: template <> class SkNx<4, float> { public: - SkNx(float32x4_t vec) : fVec(vec) {} + AI SkNx(float32x4_t vec) : fVec(vec) {} - SkNx() {} - SkNx(float val) : fVec(vdupq_n_f32(val)) {} - static SkNx Load(const void* ptr) { return vld1q_f32((const float*)ptr); } - SkNx(float a, float b, float c, float d) { fVec = (float32x4_t) { a, b, c, d }; } + AI SkNx() {} + AI SkNx(float val) : fVec(vdupq_n_f32(val)) {} + AI SkNx(float a, float b, float c, float d) { fVec = (float32x4_t) { a, b, c, d }; } - void store(void* ptr) const { vst1q_f32((float*)ptr, fVec); } - SkNx invert() const { + AI static SkNx Load(const void* ptr) { return vld1q_f32((const float*)ptr); } + AI void store(void* ptr) const { vst1q_f32((float*)ptr, fVec); } + + AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) { + float32x4x4_t rgba = vld4q_f32((const float*) ptr); + *r = rgba.val[0]; + *g = rgba.val[1]; + *b = rgba.val[2]; + *a = rgba.val[3]; + } + AI static void Store4(void* dst, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) { + float32x4x4_t rgba = {{ + r.fVec, + g.fVec, + b.fVec, + a.fVec, + }}; + vst4q_f32((float*) dst, rgba); + } + + AI SkNx invert() const { float32x4_t est0 = vrecpeq_f32(fVec), est1 = vmulq_f32(vrecpsq_f32(est0, fVec), est0); return est1; } - SkNx operator + (const SkNx& o) const { return vaddq_f32(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsubq_f32(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmulq_f32(fVec, o.fVec); } - SkNx operator / (const SkNx& o) const { + AI SkNx operator + (const SkNx& o) const { return vaddq_f32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsubq_f32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmulq_f32(fVec, o.fVec); } + AI SkNx operator / (const SkNx& o) const { #if defined(SK_CPU_ARM64) return vdivq_f32(fVec, o.fVec); #else @@ -131,20 +149,20 @@ public: #endif } - SkNx operator==(const SkNx& o) const { return vreinterpretq_f32_u32(vceqq_f32(fVec, o.fVec)); } - SkNx operator <(const SkNx& o) const { return vreinterpretq_f32_u32(vcltq_f32(fVec, o.fVec)); } - SkNx operator >(const SkNx& o) const { return vreinterpretq_f32_u32(vcgtq_f32(fVec, o.fVec)); } - SkNx operator<=(const SkNx& o) const { return vreinterpretq_f32_u32(vcleq_f32(fVec, o.fVec)); } - SkNx operator>=(const SkNx& o) const { return vreinterpretq_f32_u32(vcgeq_f32(fVec, o.fVec)); } - SkNx operator!=(const SkNx& o) const { + AI SkNx operator==(const SkNx& o) const {return vreinterpretq_f32_u32(vceqq_f32(fVec, o.fVec));} + AI SkNx operator <(const SkNx& o) const {return vreinterpretq_f32_u32(vcltq_f32(fVec, o.fVec));} + AI SkNx operator >(const SkNx& o) const {return vreinterpretq_f32_u32(vcgtq_f32(fVec, o.fVec));} + AI SkNx operator<=(const SkNx& o) const {return vreinterpretq_f32_u32(vcleq_f32(fVec, o.fVec));} + AI SkNx operator>=(const SkNx& o) const {return vreinterpretq_f32_u32(vcgeq_f32(fVec, o.fVec));} + AI SkNx operator!=(const SkNx& o) const { return vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(fVec, o.fVec))); } - static SkNx Min(const SkNx& l, const SkNx& r) { return vminq_f32(l.fVec, r.fVec); } - static SkNx Max(const SkNx& l, const SkNx& r) { return vmaxq_f32(l.fVec, r.fVec); } + AI static SkNx Min(const SkNx& l, const SkNx& r) { return vminq_f32(l.fVec, r.fVec); } + AI static SkNx Max(const SkNx& l, const SkNx& r) { return vmaxq_f32(l.fVec, r.fVec); } - SkNx abs() const { return vabsq_f32(fVec); } - SkNx floor() const { + AI SkNx abs() const { return vabsq_f32(fVec); } + AI SkNx floor() const { #if defined(SK_CPU_ARM64) return vrndmq_f32(fVec); #else @@ -153,12 +171,12 @@ public: } - SkNx rsqrt() const { + AI SkNx rsqrt() const { float32x4_t est0 = vrsqrteq_f32(fVec); return vmulq_f32(vrsqrtsq_f32(fVec, vmulq_f32(est0, est0)), est0); } - SkNx sqrt() const { + AI SkNx sqrt() const { #if defined(SK_CPU_ARM64) return vsqrtq_f32(fVec); #else @@ -169,64 +187,94 @@ public: #endif } - float operator[](int k) const { + AI float operator[](int k) const { SkASSERT(0 <= k && k < 4); union { float32x4_t v; float fs[4]; } pun = {fVec}; return pun.fs[k&3]; } - bool allTrue() const { + AI bool allTrue() const { auto v = vreinterpretq_u32_f32(fVec); return vgetq_lane_u32(v,0) && vgetq_lane_u32(v,1) && vgetq_lane_u32(v,2) && vgetq_lane_u32(v,3); } - bool anyTrue() const { + AI bool anyTrue() const { auto v = vreinterpretq_u32_f32(fVec); return vgetq_lane_u32(v,0) || vgetq_lane_u32(v,1) || vgetq_lane_u32(v,2) || vgetq_lane_u32(v,3); } - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbslq_f32(vreinterpretq_u32_f32(fVec), t.fVec, e.fVec); } float32x4_t fVec; }; +#if defined(SK_CPU_ARM64) + AI static Sk4f SkNx_fma(const Sk4f& f, const Sk4f& m, const Sk4f& a) { + return vfmaq_f32(a.fVec, f.fVec, m.fVec); + } +#endif + // It's possible that for our current use cases, representing this as // half a uint16x8_t might be better than representing it as a uint16x4_t. // It'd make conversion to Sk4b one step simpler. template <> class SkNx<4, uint16_t> { public: - SkNx(const uint16x4_t& vec) : fVec(vec) {} + AI SkNx(const uint16x4_t& vec) : fVec(vec) {} - SkNx() {} - SkNx(uint16_t val) : fVec(vdup_n_u16(val)) {} - static SkNx Load(const void* ptr) { return vld1_u16((const uint16_t*)ptr); } - - SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d) { + AI SkNx() {} + AI SkNx(uint16_t val) : fVec(vdup_n_u16(val)) {} + AI SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d) { fVec = (uint16x4_t) { a,b,c,d }; } - void store(void* ptr) const { vst1_u16((uint16_t*)ptr, fVec); } + AI static SkNx Load(const void* ptr) { return vld1_u16((const uint16_t*)ptr); } + AI void store(void* ptr) const { vst1_u16((uint16_t*)ptr, fVec); } - SkNx operator + (const SkNx& o) const { return vadd_u16(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsub_u16(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmul_u16(fVec, o.fVec); } + AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) { + uint16x4x4_t rgba = vld4_u16((const uint16_t*)ptr); + *r = rgba.val[0]; + *g = rgba.val[1]; + *b = rgba.val[2]; + *a = rgba.val[3]; + } + AI static void Load3(const void* ptr, SkNx* r, SkNx* g, SkNx* b) { + uint16x4x3_t rgba = vld3_u16((const uint16_t*)ptr); + *r = rgba.val[0]; + *g = rgba.val[1]; + *b = rgba.val[2]; + } + AI static void Store4(void* dst, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) { + uint16x4x4_t rgba = {{ + r.fVec, + g.fVec, + b.fVec, + a.fVec, + }}; + vst4_u16((uint16_t*) dst, rgba); + } - SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } - SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } + AI SkNx operator + (const SkNx& o) const { return vadd_u16(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsub_u16(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmul_u16(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return vand_u16(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return vorr_u16(fVec, o.fVec); } - static SkNx Min(const SkNx& a, const SkNx& b) { return vmin_u16(a.fVec, b.fVec); } + AI SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } + AI SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } - uint16_t operator[](int k) const { + AI static SkNx Min(const SkNx& a, const SkNx& b) { return vmin_u16(a.fVec, b.fVec); } + + AI uint16_t operator[](int k) const { SkASSERT(0 <= k && k < 4); union { uint16x4_t v; uint16_t us[4]; } pun = {fVec}; return pun.us[k&3]; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbsl_u16(fVec, t.fVec, e.fVec); } @@ -236,35 +284,37 @@ public: template <> class SkNx<8, uint16_t> { public: - SkNx(const uint16x8_t& vec) : fVec(vec) {} + AI SkNx(const uint16x8_t& vec) : fVec(vec) {} - SkNx() {} - SkNx(uint16_t val) : fVec(vdupq_n_u16(val)) {} - static SkNx Load(const void* ptr) { return vld1q_u16((const uint16_t*)ptr); } + AI SkNx() {} + AI SkNx(uint16_t val) : fVec(vdupq_n_u16(val)) {} + AI static SkNx Load(const void* ptr) { return vld1q_u16((const uint16_t*)ptr); } - SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d, - uint16_t e, uint16_t f, uint16_t g, uint16_t h) { + AI SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d, + uint16_t e, uint16_t f, uint16_t g, uint16_t h) { fVec = (uint16x8_t) { a,b,c,d, e,f,g,h }; } - void store(void* ptr) const { vst1q_u16((uint16_t*)ptr, fVec); } + AI void store(void* ptr) const { vst1q_u16((uint16_t*)ptr, fVec); } - SkNx operator + (const SkNx& o) const { return vaddq_u16(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsubq_u16(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmulq_u16(fVec, o.fVec); } + AI SkNx operator + (const SkNx& o) const { return vaddq_u16(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsubq_u16(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmulq_u16(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return vandq_u16(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return vorrq_u16(fVec, o.fVec); } - SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } - SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } + AI SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } + AI SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } - static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u16(a.fVec, b.fVec); } + AI static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u16(a.fVec, b.fVec); } - uint16_t operator[](int k) const { + AI uint16_t operator[](int k) const { SkASSERT(0 <= k && k < 8); union { uint16x8_t v; uint16_t us[8]; } pun = {fVec}; return pun.us[k&7]; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbslq_u16(fVec, t.fVec, e.fVec); } @@ -276,19 +326,19 @@ class SkNx<4, uint8_t> { public: typedef uint32_t __attribute__((aligned(1))) unaligned_uint32_t; - SkNx(const uint8x8_t& vec) : fVec(vec) {} + AI SkNx(const uint8x8_t& vec) : fVec(vec) {} - SkNx() {} - SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { + AI SkNx() {} + AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { fVec = (uint8x8_t){a,b,c,d, 0,0,0,0}; } - static SkNx Load(const void* ptr) { + AI static SkNx Load(const void* ptr) { return (uint8x8_t)vld1_dup_u32((const unaligned_uint32_t*)ptr); } - void store(void* ptr) const { + AI void store(void* ptr) const { return vst1_lane_u32((unaligned_uint32_t*)ptr, (uint32x2_t)fVec, 0); } - uint8_t operator[](int k) const { + AI uint8_t operator[](int k) const { SkASSERT(0 <= k && k < 4); union { uint8x8_t v; uint8_t us[8]; } pun = {fVec}; return pun.us[k&3]; @@ -302,36 +352,35 @@ public: template <> class SkNx<16, uint8_t> { public: - SkNx(const uint8x16_t& vec) : fVec(vec) {} + AI SkNx(const uint8x16_t& vec) : fVec(vec) {} - SkNx() {} - SkNx(uint8_t val) : fVec(vdupq_n_u8(val)) {} - static SkNx Load(const void* ptr) { return vld1q_u8((const uint8_t*)ptr); } - - SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d, - uint8_t e, uint8_t f, uint8_t g, uint8_t h, - uint8_t i, uint8_t j, uint8_t k, uint8_t l, - uint8_t m, uint8_t n, uint8_t o, uint8_t p) { + AI SkNx() {} + AI SkNx(uint8_t val) : fVec(vdupq_n_u8(val)) {} + AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d, + uint8_t e, uint8_t f, uint8_t g, uint8_t h, + uint8_t i, uint8_t j, uint8_t k, uint8_t l, + uint8_t m, uint8_t n, uint8_t o, uint8_t p) { fVec = (uint8x16_t) { a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p }; } - void store(void* ptr) const { vst1q_u8((uint8_t*)ptr, fVec); } + AI static SkNx Load(const void* ptr) { return vld1q_u8((const uint8_t*)ptr); } + AI void store(void* ptr) const { vst1q_u8((uint8_t*)ptr, fVec); } - SkNx saturatedAdd(const SkNx& o) const { return vqaddq_u8(fVec, o.fVec); } + AI SkNx saturatedAdd(const SkNx& o) const { return vqaddq_u8(fVec, o.fVec); } - SkNx operator + (const SkNx& o) const { return vaddq_u8(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsubq_u8(fVec, o.fVec); } + AI SkNx operator + (const SkNx& o) const { return vaddq_u8(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsubq_u8(fVec, o.fVec); } - static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u8(a.fVec, b.fVec); } - SkNx operator < (const SkNx& o) const { return vcltq_u8(fVec, o.fVec); } + AI static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u8(a.fVec, b.fVec); } + AI SkNx operator < (const SkNx& o) const { return vcltq_u8(fVec, o.fVec); } - uint8_t operator[](int k) const { + AI uint8_t operator[](int k) const { SkASSERT(0 <= k && k < 16); union { uint8x16_t v; uint8_t us[16]; } pun = {fVec}; return pun.us[k&15]; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbslq_u8(fVec, t.fVec, e.fVec); } @@ -341,52 +390,52 @@ public: template <> class SkNx<4, int32_t> { public: - SkNx(const int32x4_t& vec) : fVec(vec) {} + AI SkNx(const int32x4_t& vec) : fVec(vec) {} - SkNx() {} - SkNx(int32_t v) { + AI SkNx() {} + AI SkNx(int32_t v) { fVec = vdupq_n_s32(v); } - SkNx(int32_t a, int32_t b, int32_t c, int32_t d) { + AI SkNx(int32_t a, int32_t b, int32_t c, int32_t d) { fVec = (int32x4_t){a,b,c,d}; } - static SkNx Load(const void* ptr) { + AI static SkNx Load(const void* ptr) { return vld1q_s32((const int32_t*)ptr); } - void store(void* ptr) const { + AI void store(void* ptr) const { return vst1q_s32((int32_t*)ptr, fVec); } - int32_t operator[](int k) const { + AI int32_t operator[](int k) const { SkASSERT(0 <= k && k < 4); union { int32x4_t v; int32_t is[4]; } pun = {fVec}; return pun.is[k&3]; } - SkNx operator + (const SkNx& o) const { return vaddq_s32(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsubq_s32(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmulq_s32(fVec, o.fVec); } + AI SkNx operator + (const SkNx& o) const { return vaddq_s32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsubq_s32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmulq_s32(fVec, o.fVec); } - SkNx operator & (const SkNx& o) const { return vandq_s32(fVec, o.fVec); } - SkNx operator | (const SkNx& o) const { return vorrq_s32(fVec, o.fVec); } - SkNx operator ^ (const SkNx& o) const { return veorq_s32(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return vandq_s32(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return vorrq_s32(fVec, o.fVec); } + AI SkNx operator ^ (const SkNx& o) const { return veorq_s32(fVec, o.fVec); } - SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } - SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } + AI SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } + AI SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } - SkNx operator == (const SkNx& o) const { + AI SkNx operator == (const SkNx& o) const { return vreinterpretq_s32_u32(vceqq_s32(fVec, o.fVec)); } - SkNx operator < (const SkNx& o) const { + AI SkNx operator < (const SkNx& o) const { return vreinterpretq_s32_u32(vcltq_s32(fVec, o.fVec)); } - SkNx operator > (const SkNx& o) const { + AI SkNx operator > (const SkNx& o) const { return vreinterpretq_s32_u32(vcgtq_s32(fVec, o.fVec)); } - static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_s32(a.fVec, b.fVec); } + AI static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_s32(a.fVec, b.fVec); } // TODO as needed - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbslq_s32(vreinterpretq_u32_s32(fVec), t.fVec, e.fVec); } @@ -396,84 +445,87 @@ public: template <> class SkNx<4, uint32_t> { public: - SkNx(const uint32x4_t& vec) : fVec(vec) {} + AI SkNx(const uint32x4_t& vec) : fVec(vec) {} - SkNx() {} - SkNx(uint32_t v) { + AI SkNx() {} + AI SkNx(uint32_t v) { fVec = vdupq_n_u32(v); } - SkNx(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + AI SkNx(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { fVec = (uint32x4_t){a,b,c,d}; } - static SkNx Load(const void* ptr) { + AI static SkNx Load(const void* ptr) { return vld1q_u32((const uint32_t*)ptr); } - void store(void* ptr) const { + AI void store(void* ptr) const { return vst1q_u32((uint32_t*)ptr, fVec); } - uint32_t operator[](int k) const { + AI uint32_t operator[](int k) const { SkASSERT(0 <= k && k < 4); union { uint32x4_t v; uint32_t us[4]; } pun = {fVec}; return pun.us[k&3]; } - SkNx operator + (const SkNx& o) const { return vaddq_u32(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsubq_u32(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmulq_u32(fVec, o.fVec); } + AI SkNx operator + (const SkNx& o) const { return vaddq_u32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsubq_u32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmulq_u32(fVec, o.fVec); } - SkNx operator & (const SkNx& o) const { return vandq_u32(fVec, o.fVec); } - SkNx operator | (const SkNx& o) const { return vorrq_u32(fVec, o.fVec); } - SkNx operator ^ (const SkNx& o) const { return veorq_u32(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return vandq_u32(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return vorrq_u32(fVec, o.fVec); } + AI SkNx operator ^ (const SkNx& o) const { return veorq_u32(fVec, o.fVec); } - SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } - SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } + AI SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } + AI SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } - SkNx operator == (const SkNx& o) const { return vceqq_u32(fVec, o.fVec); } - SkNx operator < (const SkNx& o) const { return vcltq_u32(fVec, o.fVec); } - SkNx operator > (const SkNx& o) const { return vcgtq_u32(fVec, o.fVec); } + AI SkNx operator == (const SkNx& o) const { return vceqq_u32(fVec, o.fVec); } + AI SkNx operator < (const SkNx& o) const { return vcltq_u32(fVec, o.fVec); } + AI SkNx operator > (const SkNx& o) const { return vcgtq_u32(fVec, o.fVec); } - static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u32(a.fVec, b.fVec); } + AI static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u32(a.fVec, b.fVec); } // TODO as needed - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbslq_u32(fVec, t.fVec, e.fVec); } uint32x4_t fVec; }; -template<> inline Sk4i SkNx_cast(const Sk4f& src) { +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4f& src) { return vcvtq_s32_f32(src.fVec); } -template<> inline Sk4f SkNx_cast(const Sk4i& src) { +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4i& src) { return vcvtq_f32_s32(src.fVec); } -template<> inline Sk4f SkNx_cast(const Sk4u& src) { +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4u& src) { return SkNx_cast(Sk4i::Load(&src)); } -template<> inline Sk4h SkNx_cast(const Sk4f& src) { +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4f& src) { return vqmovn_u32(vcvtq_u32_f32(src.fVec)); } -template<> inline Sk4f SkNx_cast(const Sk4h& src) { +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4h& src) { return vcvtq_f32_u32(vmovl_u16(src.fVec)); } -template<> inline Sk4b SkNx_cast(const Sk4f& src) { +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4f& src) { uint32x4_t _32 = vcvtq_u32_f32(src.fVec); uint16x4_t _16 = vqmovn_u32(_32); return vqmovn_u16(vcombine_u16(_16, _16)); } -template<> inline Sk4f SkNx_cast(const Sk4b& src) { - uint16x8_t _16 = vmovl_u8 (src.fVec) ; - uint32x4_t _32 = vmovl_u16(vget_low_u16(_16)); - return vcvtq_f32_u32(_32); +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4b& src) { + uint16x8_t _16 = vmovl_u8(src.fVec); + return vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(_16))); } -template<> inline Sk16b SkNx_cast(const Sk16f& src) { +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4b& src) { + return vcvtq_f32_s32(SkNx_cast(src).fVec); +} + +template<> AI /*static*/ Sk16b SkNx_cast(const Sk16f& src) { Sk8f ab, cd; SkNx_split(src, &ab, &cd); @@ -486,71 +538,35 @@ template<> inline Sk16b SkNx_cast(const Sk16f& src) { (uint8x16_t)vcvtq_u32_f32(d.fVec)).val[0]).val[0]; } -template<> inline Sk4h SkNx_cast(const Sk4b& src) { +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4b& src) { return vget_low_u16(vmovl_u8(src.fVec)); } -template<> inline Sk4b SkNx_cast(const Sk4h& src) { +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4h& src) { return vmovn_u16(vcombine_u16(src.fVec, src.fVec)); } -template<> inline Sk4b SkNx_cast(const Sk4i& src) { +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4i& src) { uint16x4_t _16 = vqmovun_s32(src.fVec); return vqmovn_u16(vcombine_u16(_16, _16)); } -template<> inline Sk4i SkNx_cast(const Sk4h& src) { +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4h& src) { return vreinterpretq_s32_u32(vmovl_u16(src.fVec)); } -template<> inline Sk4h SkNx_cast(const Sk4i& src) { +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4i& src) { return vmovn_u32(vreinterpretq_u32_s32(src.fVec)); } -template<> /*static*/ inline Sk4i SkNx_cast(const Sk4u& src) { +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4u& src) { return vreinterpretq_s32_u32(src.fVec); } -static inline Sk4i Sk4f_round(const Sk4f& x) { +AI static Sk4i Sk4f_round(const Sk4f& x) { return vcvtq_s32_f32((x + 0.5f).fVec); } -static inline void Sk4h_load4(const void* ptr, Sk4h* r, Sk4h* g, Sk4h* b, Sk4h* a) { - uint16x4x4_t rgba = vld4_u16((const uint16_t*)ptr); - *r = rgba.val[0]; - *g = rgba.val[1]; - *b = rgba.val[2]; - *a = rgba.val[3]; -} - -static inline void Sk4h_store4(void* dst, const Sk4h& r, const Sk4h& g, const Sk4h& b, - const Sk4h& a) { - uint16x4x4_t rgba = {{ - r.fVec, - g.fVec, - b.fVec, - a.fVec, - }}; - vst4_u16((uint16_t*) dst, rgba); -} - -static inline void Sk4f_load4(const void* ptr, Sk4f* r, Sk4f* g, Sk4f* b, Sk4f* a) { - float32x4x4_t rgba = vld4q_f32((const float*) ptr); - *r = rgba.val[0]; - *g = rgba.val[1]; - *b = rgba.val[2]; - *a = rgba.val[3]; -} - -static inline void Sk4f_store4(void* dst, const Sk4f& r, const Sk4f& g, const Sk4f& b, - const Sk4f& a) { - float32x4x4_t rgba = {{ - r.fVec, - g.fVec, - b.fVec, - a.fVec, - }}; - vst4q_f32((float*) dst, rgba); -} +} // namespace #endif//SkNx_neon_DEFINED diff --git a/gfx/skia/skia/src/opts/SkNx_sse.h b/gfx/skia/skia/src/opts/SkNx_sse.h index 25a5cd8f8423..3e59a9d0e81e 100644 --- a/gfx/skia/skia/src/opts/SkNx_sse.h +++ b/gfx/skia/skia/src/opts/SkNx_sse.h @@ -13,49 +13,49 @@ // This file may assume <= SSE2, but must check SK_CPU_SSE_LEVEL for anything more recent. // If you do, make sure this is in a static inline function... anywhere else risks violating ODR. -#define SKNX_IS_FAST +namespace { template <> class SkNx<2, float> { public: - SkNx(const __m128& vec) : fVec(vec) {} + AI SkNx(const __m128& vec) : fVec(vec) {} - SkNx() {} - SkNx(float val) : fVec(_mm_set1_ps(val)) {} - static SkNx Load(const void* ptr) { + AI SkNx() {} + AI SkNx(float val) : fVec(_mm_set1_ps(val)) {} + AI static SkNx Load(const void* ptr) { return _mm_castsi128_ps(_mm_loadl_epi64((const __m128i*)ptr)); } - SkNx(float a, float b) : fVec(_mm_setr_ps(a,b,0,0)) {} + AI SkNx(float a, float b) : fVec(_mm_setr_ps(a,b,0,0)) {} - void store(void* ptr) const { _mm_storel_pi((__m64*)ptr, fVec); } + AI void store(void* ptr) const { _mm_storel_pi((__m64*)ptr, fVec); } - SkNx operator + (const SkNx& o) const { return _mm_add_ps(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return _mm_sub_ps(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return _mm_mul_ps(fVec, o.fVec); } - SkNx operator / (const SkNx& o) const { return _mm_div_ps(fVec, o.fVec); } + AI SkNx operator + (const SkNx& o) const { return _mm_add_ps(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_ps(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return _mm_mul_ps(fVec, o.fVec); } + AI SkNx operator / (const SkNx& o) const { return _mm_div_ps(fVec, o.fVec); } - SkNx operator == (const SkNx& o) const { return _mm_cmpeq_ps (fVec, o.fVec); } - SkNx operator != (const SkNx& o) const { return _mm_cmpneq_ps(fVec, o.fVec); } - SkNx operator < (const SkNx& o) const { return _mm_cmplt_ps (fVec, o.fVec); } - SkNx operator > (const SkNx& o) const { return _mm_cmpgt_ps (fVec, o.fVec); } - SkNx operator <= (const SkNx& o) const { return _mm_cmple_ps (fVec, o.fVec); } - SkNx operator >= (const SkNx& o) const { return _mm_cmpge_ps (fVec, o.fVec); } + AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_ps (fVec, o.fVec); } + AI SkNx operator != (const SkNx& o) const { return _mm_cmpneq_ps(fVec, o.fVec); } + AI SkNx operator < (const SkNx& o) const { return _mm_cmplt_ps (fVec, o.fVec); } + AI SkNx operator > (const SkNx& o) const { return _mm_cmpgt_ps (fVec, o.fVec); } + AI SkNx operator <= (const SkNx& o) const { return _mm_cmple_ps (fVec, o.fVec); } + AI SkNx operator >= (const SkNx& o) const { return _mm_cmpge_ps (fVec, o.fVec); } - static SkNx Min(const SkNx& l, const SkNx& r) { return _mm_min_ps(l.fVec, r.fVec); } - static SkNx Max(const SkNx& l, const SkNx& r) { return _mm_max_ps(l.fVec, r.fVec); } + AI static SkNx Min(const SkNx& l, const SkNx& r) { return _mm_min_ps(l.fVec, r.fVec); } + AI static SkNx Max(const SkNx& l, const SkNx& r) { return _mm_max_ps(l.fVec, r.fVec); } - SkNx sqrt() const { return _mm_sqrt_ps (fVec); } - SkNx rsqrt() const { return _mm_rsqrt_ps(fVec); } - SkNx invert() const { return _mm_rcp_ps(fVec); } + AI SkNx sqrt() const { return _mm_sqrt_ps (fVec); } + AI SkNx rsqrt() const { return _mm_rsqrt_ps(fVec); } + AI SkNx invert() const { return _mm_rcp_ps(fVec); } - float operator[](int k) const { + AI float operator[](int k) const { SkASSERT(0 <= k && k < 2); union { __m128 v; float fs[4]; } pun = {fVec}; return pun.fs[k&1]; } - bool allTrue() const { return 0xff == (_mm_movemask_epi8(_mm_castps_si128(fVec)) & 0xff); } - bool anyTrue() const { return 0x00 != (_mm_movemask_epi8(_mm_castps_si128(fVec)) & 0xff); } + AI bool allTrue() const { return 0xff == (_mm_movemask_epi8(_mm_castps_si128(fVec)) & 0xff); } + AI bool anyTrue() const { return 0x00 != (_mm_movemask_epi8(_mm_castps_si128(fVec)) & 0xff); } __m128 fVec; }; @@ -63,33 +63,55 @@ public: template <> class SkNx<4, float> { public: - SkNx(const __m128& vec) : fVec(vec) {} + AI SkNx(const __m128& vec) : fVec(vec) {} - SkNx() {} - SkNx(float val) : fVec( _mm_set1_ps(val) ) {} - static SkNx Load(const void* ptr) { return _mm_loadu_ps((const float*)ptr); } + AI SkNx() {} + AI SkNx(float val) : fVec( _mm_set1_ps(val) ) {} + AI SkNx(float a, float b, float c, float d) : fVec(_mm_setr_ps(a,b,c,d)) {} - SkNx(float a, float b, float c, float d) : fVec(_mm_setr_ps(a,b,c,d)) {} + AI static SkNx Load(const void* ptr) { return _mm_loadu_ps((const float*)ptr); } + AI void store(void* ptr) const { _mm_storeu_ps((float*)ptr, fVec); } - void store(void* ptr) const { _mm_storeu_ps((float*)ptr, fVec); } + AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) { + __m128 v0 = _mm_loadu_ps(((float*)ptr) + 0), + v1 = _mm_loadu_ps(((float*)ptr) + 4), + v2 = _mm_loadu_ps(((float*)ptr) + 8), + v3 = _mm_loadu_ps(((float*)ptr) + 12); + _MM_TRANSPOSE4_PS(v0, v1, v2, v3); + *r = v0; + *g = v1; + *b = v2; + *a = v3; + } + AI static void Store4(void* dst, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) { + __m128 v0 = r.fVec, + v1 = g.fVec, + v2 = b.fVec, + v3 = a.fVec; + _MM_TRANSPOSE4_PS(v0, v1, v2, v3); + _mm_storeu_ps(((float*) dst) + 0, v0); + _mm_storeu_ps(((float*) dst) + 4, v1); + _mm_storeu_ps(((float*) dst) + 8, v2); + _mm_storeu_ps(((float*) dst) + 12, v3); + } - SkNx operator + (const SkNx& o) const { return _mm_add_ps(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return _mm_sub_ps(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return _mm_mul_ps(fVec, o.fVec); } - SkNx operator / (const SkNx& o) const { return _mm_div_ps(fVec, o.fVec); } + AI SkNx operator + (const SkNx& o) const { return _mm_add_ps(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_ps(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return _mm_mul_ps(fVec, o.fVec); } + AI SkNx operator / (const SkNx& o) const { return _mm_div_ps(fVec, o.fVec); } - SkNx operator == (const SkNx& o) const { return _mm_cmpeq_ps (fVec, o.fVec); } - SkNx operator != (const SkNx& o) const { return _mm_cmpneq_ps(fVec, o.fVec); } - SkNx operator < (const SkNx& o) const { return _mm_cmplt_ps (fVec, o.fVec); } - SkNx operator > (const SkNx& o) const { return _mm_cmpgt_ps (fVec, o.fVec); } - SkNx operator <= (const SkNx& o) const { return _mm_cmple_ps (fVec, o.fVec); } - SkNx operator >= (const SkNx& o) const { return _mm_cmpge_ps (fVec, o.fVec); } + AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_ps (fVec, o.fVec); } + AI SkNx operator != (const SkNx& o) const { return _mm_cmpneq_ps(fVec, o.fVec); } + AI SkNx operator < (const SkNx& o) const { return _mm_cmplt_ps (fVec, o.fVec); } + AI SkNx operator > (const SkNx& o) const { return _mm_cmpgt_ps (fVec, o.fVec); } + AI SkNx operator <= (const SkNx& o) const { return _mm_cmple_ps (fVec, o.fVec); } + AI SkNx operator >= (const SkNx& o) const { return _mm_cmpge_ps (fVec, o.fVec); } - static SkNx Min(const SkNx& l, const SkNx& r) { return _mm_min_ps(l.fVec, r.fVec); } - static SkNx Max(const SkNx& l, const SkNx& r) { return _mm_max_ps(l.fVec, r.fVec); } + AI static SkNx Min(const SkNx& l, const SkNx& r) { return _mm_min_ps(l.fVec, r.fVec); } + AI static SkNx Max(const SkNx& l, const SkNx& r) { return _mm_max_ps(l.fVec, r.fVec); } - SkNx abs() const { return _mm_andnot_ps(_mm_set1_ps(-0.0f), fVec); } - SkNx floor() const { + AI SkNx abs() const { return _mm_andnot_ps(_mm_set1_ps(-0.0f), fVec); } + AI SkNx floor() const { #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 return _mm_floor_ps(fVec); #else @@ -104,20 +126,20 @@ public: #endif } - SkNx sqrt() const { return _mm_sqrt_ps (fVec); } - SkNx rsqrt() const { return _mm_rsqrt_ps(fVec); } - SkNx invert() const { return _mm_rcp_ps(fVec); } + AI SkNx sqrt() const { return _mm_sqrt_ps (fVec); } + AI SkNx rsqrt() const { return _mm_rsqrt_ps(fVec); } + AI SkNx invert() const { return _mm_rcp_ps(fVec); } - float operator[](int k) const { + AI float operator[](int k) const { SkASSERT(0 <= k && k < 4); union { __m128 v; float fs[4]; } pun = {fVec}; return pun.fs[k&3]; } - bool allTrue() const { return 0xffff == _mm_movemask_epi8(_mm_castps_si128(fVec)); } - bool anyTrue() const { return 0x0000 != _mm_movemask_epi8(_mm_castps_si128(fVec)); } + AI bool allTrue() const { return 0xffff == _mm_movemask_epi8(_mm_castps_si128(fVec)); } + AI bool anyTrue() const { return 0x0000 != _mm_movemask_epi8(_mm_castps_si128(fVec)); } - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 return _mm_blendv_ps(e.fVec, t.fVec, fVec); #else @@ -132,42 +154,42 @@ public: template <> class SkNx<4, int32_t> { public: - SkNx(const __m128i& vec) : fVec(vec) {} + AI SkNx(const __m128i& vec) : fVec(vec) {} - SkNx() {} - SkNx(int32_t val) : fVec(_mm_set1_epi32(val)) {} - static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } - SkNx(int32_t a, int32_t b, int32_t c, int32_t d) : fVec(_mm_setr_epi32(a,b,c,d)) {} + AI SkNx() {} + AI SkNx(int32_t val) : fVec(_mm_set1_epi32(val)) {} + AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + AI SkNx(int32_t a, int32_t b, int32_t c, int32_t d) : fVec(_mm_setr_epi32(a,b,c,d)) {} - void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } + AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } - SkNx operator + (const SkNx& o) const { return _mm_add_epi32(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return _mm_sub_epi32(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { __m128i mul20 = _mm_mul_epu32(fVec, o.fVec), mul31 = _mm_mul_epu32(_mm_srli_si128(fVec, 4), _mm_srli_si128(o.fVec, 4)); return _mm_unpacklo_epi32(_mm_shuffle_epi32(mul20, _MM_SHUFFLE(0,0,2,0)), _mm_shuffle_epi32(mul31, _MM_SHUFFLE(0,0,2,0))); } - SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } - SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } - SkNx operator ^ (const SkNx& o) const { return _mm_xor_si128(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } + AI SkNx operator ^ (const SkNx& o) const { return _mm_xor_si128(fVec, o.fVec); } - SkNx operator << (int bits) const { return _mm_slli_epi32(fVec, bits); } - SkNx operator >> (int bits) const { return _mm_srai_epi32(fVec, bits); } + AI SkNx operator << (int bits) const { return _mm_slli_epi32(fVec, bits); } + AI SkNx operator >> (int bits) const { return _mm_srai_epi32(fVec, bits); } - SkNx operator == (const SkNx& o) const { return _mm_cmpeq_epi32 (fVec, o.fVec); } - SkNx operator < (const SkNx& o) const { return _mm_cmplt_epi32 (fVec, o.fVec); } - SkNx operator > (const SkNx& o) const { return _mm_cmpgt_epi32 (fVec, o.fVec); } + AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_epi32 (fVec, o.fVec); } + AI SkNx operator < (const SkNx& o) const { return _mm_cmplt_epi32 (fVec, o.fVec); } + AI SkNx operator > (const SkNx& o) const { return _mm_cmpgt_epi32 (fVec, o.fVec); } - int32_t operator[](int k) const { + AI int32_t operator[](int k) const { SkASSERT(0 <= k && k < 4); union { __m128i v; int32_t is[4]; } pun = {fVec}; return pun.is[k&3]; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 return _mm_blendv_epi8(e.fVec, t.fVec, fVec); #else @@ -182,36 +204,36 @@ public: template <> class SkNx<4, uint32_t> { public: - SkNx(const __m128i& vec) : fVec(vec) {} + AI SkNx(const __m128i& vec) : fVec(vec) {} - SkNx() {} - SkNx(uint32_t val) : fVec(_mm_set1_epi32(val)) {} - static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } - SkNx(uint32_t a, uint32_t b, uint32_t c, uint32_t d) : fVec(_mm_setr_epi32(a,b,c,d)) {} + AI SkNx() {} + AI SkNx(uint32_t val) : fVec(_mm_set1_epi32(val)) {} + AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + AI SkNx(uint32_t a, uint32_t b, uint32_t c, uint32_t d) : fVec(_mm_setr_epi32(a,b,c,d)) {} - void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } + AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } - SkNx operator + (const SkNx& o) const { return _mm_add_epi32(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return _mm_sub_epi32(fVec, o.fVec); } + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi32(fVec, o.fVec); } // Not quite sure how to best do operator * in SSE2. We probably don't use it. - SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } - SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } - SkNx operator ^ (const SkNx& o) const { return _mm_xor_si128(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } + AI SkNx operator ^ (const SkNx& o) const { return _mm_xor_si128(fVec, o.fVec); } - SkNx operator << (int bits) const { return _mm_slli_epi32(fVec, bits); } - SkNx operator >> (int bits) const { return _mm_srli_epi32(fVec, bits); } + AI SkNx operator << (int bits) const { return _mm_slli_epi32(fVec, bits); } + AI SkNx operator >> (int bits) const { return _mm_srli_epi32(fVec, bits); } - SkNx operator == (const SkNx& o) const { return _mm_cmpeq_epi32 (fVec, o.fVec); } + AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_epi32 (fVec, o.fVec); } // operator < and > take a little extra fiddling to make work for unsigned ints. - uint32_t operator[](int k) const { + AI uint32_t operator[](int k) const { SkASSERT(0 <= k && k < 4); union { __m128i v; uint32_t us[4]; } pun = {fVec}; return pun.us[k&3]; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 return _mm_blendv_epi8(e.fVec, t.fVec, fVec); #else @@ -227,23 +249,63 @@ public: template <> class SkNx<4, uint16_t> { public: - SkNx(const __m128i& vec) : fVec(vec) {} + AI SkNx(const __m128i& vec) : fVec(vec) {} - SkNx() {} - SkNx(uint16_t val) : fVec(_mm_set1_epi16(val)) {} - static SkNx Load(const void* ptr) { return _mm_loadl_epi64((const __m128i*)ptr); } - SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d) : fVec(_mm_setr_epi16(a,b,c,d,0,0,0,0)) {} + AI SkNx() {} + AI SkNx(uint16_t val) : fVec(_mm_set1_epi16(val)) {} + AI SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d) + : fVec(_mm_setr_epi16(a,b,c,d,0,0,0,0)) {} - void store(void* ptr) const { _mm_storel_epi64((__m128i*)ptr, fVec); } + AI static SkNx Load(const void* ptr) { return _mm_loadl_epi64((const __m128i*)ptr); } + AI void store(void* ptr) const { _mm_storel_epi64((__m128i*)ptr, fVec); } - SkNx operator + (const SkNx& o) const { return _mm_add_epi16(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return _mm_sub_epi16(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return _mm_mullo_epi16(fVec, o.fVec); } + AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) { + __m128i lo = _mm_loadu_si128(((__m128i*)ptr) + 0), + hi = _mm_loadu_si128(((__m128i*)ptr) + 1); + __m128i even = _mm_unpacklo_epi16(lo, hi), // r0 r2 g0 g2 b0 b2 a0 a2 + odd = _mm_unpackhi_epi16(lo, hi); // r1 r3 ... + __m128i rg = _mm_unpacklo_epi16(even, odd), // r0 r1 r2 r3 g0 g1 g2 g3 + ba = _mm_unpackhi_epi16(even, odd); // b0 b1 ... a0 a1 ... + *r = rg; + *g = _mm_srli_si128(rg, 8); + *b = ba; + *a = _mm_srli_si128(ba, 8); + } + AI static void Load3(const void* ptr, SkNx* r, SkNx* g, SkNx* b) { + // The idea here is to get 4 vectors that are R G B _ _ _ _ _. + // The second load is at a funny location to make sure we don't read past + // the bounds of memory. This is fine, we just need to shift it a little bit. + const uint8_t* ptr8 = (const uint8_t*) ptr; + __m128i rgb0 = _mm_loadu_si128((const __m128i*) (ptr8 + 0)); + __m128i rgb1 = _mm_srli_si128(rgb0, 3*2); + __m128i rgb2 = _mm_srli_si128(_mm_loadu_si128((const __m128i*) (ptr8 + 4*2)), 2*2); + __m128i rgb3 = _mm_srli_si128(rgb2, 3*2); - SkNx operator << (int bits) const { return _mm_slli_epi16(fVec, bits); } - SkNx operator >> (int bits) const { return _mm_srli_epi16(fVec, bits); } + __m128i rrggbb01 = _mm_unpacklo_epi16(rgb0, rgb1); + __m128i rrggbb23 = _mm_unpacklo_epi16(rgb2, rgb3); + *r = _mm_unpacklo_epi32(rrggbb01, rrggbb23); + *g = _mm_srli_si128(r->fVec, 4*2); + *b = _mm_unpackhi_epi32(rrggbb01, rrggbb23); + } + AI static void Store4(void* dst, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) { + __m128i rg = _mm_unpacklo_epi16(r.fVec, g.fVec); + __m128i ba = _mm_unpacklo_epi16(b.fVec, a.fVec); + __m128i lo = _mm_unpacklo_epi32(rg, ba); + __m128i hi = _mm_unpackhi_epi32(rg, ba); + _mm_storeu_si128(((__m128i*) dst) + 0, lo); + _mm_storeu_si128(((__m128i*) dst) + 1, hi); + } - uint16_t operator[](int k) const { + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi16(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi16(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return _mm_mullo_epi16(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return _mm_slli_epi16(fVec, bits); } + AI SkNx operator >> (int bits) const { return _mm_srli_epi16(fVec, bits); } + + AI uint16_t operator[](int k) const { SkASSERT(0 <= k && k < 4); union { __m128i v; uint16_t us[8]; } pun = {fVec}; return pun.us[k&3]; @@ -255,24 +317,85 @@ public: template <> class SkNx<8, uint16_t> { public: - SkNx(const __m128i& vec) : fVec(vec) {} + AI SkNx(const __m128i& vec) : fVec(vec) {} - SkNx() {} - SkNx(uint16_t val) : fVec(_mm_set1_epi16(val)) {} - static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } - SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d, - uint16_t e, uint16_t f, uint16_t g, uint16_t h) : fVec(_mm_setr_epi16(a,b,c,d,e,f,g,h)) {} + AI SkNx() {} + AI SkNx(uint16_t val) : fVec(_mm_set1_epi16(val)) {} + AI SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d, + uint16_t e, uint16_t f, uint16_t g, uint16_t h) + : fVec(_mm_setr_epi16(a,b,c,d,e,f,g,h)) {} - void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } + AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } - SkNx operator + (const SkNx& o) const { return _mm_add_epi16(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return _mm_sub_epi16(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return _mm_mullo_epi16(fVec, o.fVec); } + AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) { + __m128i _01 = _mm_loadu_si128(((__m128i*)ptr) + 0), + _23 = _mm_loadu_si128(((__m128i*)ptr) + 1), + _45 = _mm_loadu_si128(((__m128i*)ptr) + 2), + _67 = _mm_loadu_si128(((__m128i*)ptr) + 3); - SkNx operator << (int bits) const { return _mm_slli_epi16(fVec, bits); } - SkNx operator >> (int bits) const { return _mm_srli_epi16(fVec, bits); } + __m128i _02 = _mm_unpacklo_epi16(_01, _23), // r0 r2 g0 g2 b0 b2 a0 a2 + _13 = _mm_unpackhi_epi16(_01, _23), // r1 r3 g1 g3 b1 b3 a1 a3 + _46 = _mm_unpacklo_epi16(_45, _67), + _57 = _mm_unpackhi_epi16(_45, _67); - static SkNx Min(const SkNx& a, const SkNx& b) { + __m128i rg0123 = _mm_unpacklo_epi16(_02, _13), // r0 r1 r2 r3 g0 g1 g2 g3 + ba0123 = _mm_unpackhi_epi16(_02, _13), // b0 b1 b2 b3 a0 a1 a2 a3 + rg4567 = _mm_unpacklo_epi16(_46, _57), + ba4567 = _mm_unpackhi_epi16(_46, _57); + + *r = _mm_unpacklo_epi64(rg0123, rg4567); + *g = _mm_unpackhi_epi64(rg0123, rg4567); + *b = _mm_unpacklo_epi64(ba0123, ba4567); + *a = _mm_unpackhi_epi64(ba0123, ba4567); + } + AI static void Load3(const void* ptr, SkNx* r, SkNx* g, SkNx* b) { + const uint8_t* ptr8 = (const uint8_t*) ptr; + __m128i rgb0 = _mm_loadu_si128((const __m128i*) (ptr8 + 0*2)); + __m128i rgb1 = _mm_srli_si128(rgb0, 3*2); + __m128i rgb2 = _mm_loadu_si128((const __m128i*) (ptr8 + 6*2)); + __m128i rgb3 = _mm_srli_si128(rgb2, 3*2); + __m128i rgb4 = _mm_loadu_si128((const __m128i*) (ptr8 + 12*2)); + __m128i rgb5 = _mm_srli_si128(rgb4, 3*2); + __m128i rgb6 = _mm_srli_si128(_mm_loadu_si128((const __m128i*) (ptr8 + 16*2)), 2*2); + __m128i rgb7 = _mm_srli_si128(rgb6, 3*2); + + __m128i rgb01 = _mm_unpacklo_epi16(rgb0, rgb1); + __m128i rgb23 = _mm_unpacklo_epi16(rgb2, rgb3); + __m128i rgb45 = _mm_unpacklo_epi16(rgb4, rgb5); + __m128i rgb67 = _mm_unpacklo_epi16(rgb6, rgb7); + + __m128i rg03 = _mm_unpacklo_epi32(rgb01, rgb23); + __m128i bx03 = _mm_unpackhi_epi32(rgb01, rgb23); + __m128i rg47 = _mm_unpacklo_epi32(rgb45, rgb67); + __m128i bx47 = _mm_unpackhi_epi32(rgb45, rgb67); + + *r = _mm_unpacklo_epi64(rg03, rg47); + *g = _mm_unpackhi_epi64(rg03, rg47); + *b = _mm_unpacklo_epi64(bx03, bx47); + } + AI static void Store4(void* ptr, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) { + __m128i rg0123 = _mm_unpacklo_epi16(r.fVec, g.fVec), // r0 g0 r1 g1 r2 g2 r3 g3 + rg4567 = _mm_unpackhi_epi16(r.fVec, g.fVec), // r4 g4 r5 g5 r6 g6 r7 g7 + ba0123 = _mm_unpacklo_epi16(b.fVec, a.fVec), + ba4567 = _mm_unpackhi_epi16(b.fVec, a.fVec); + + _mm_storeu_si128((__m128i*)ptr + 0, _mm_unpacklo_epi32(rg0123, ba0123)); + _mm_storeu_si128((__m128i*)ptr + 1, _mm_unpackhi_epi32(rg0123, ba0123)); + _mm_storeu_si128((__m128i*)ptr + 2, _mm_unpacklo_epi32(rg4567, ba4567)); + _mm_storeu_si128((__m128i*)ptr + 3, _mm_unpackhi_epi32(rg4567, ba4567)); + } + + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi16(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi16(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return _mm_mullo_epi16(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return _mm_slli_epi16(fVec, bits); } + AI SkNx operator >> (int bits) const { return _mm_srli_epi16(fVec, bits); } + + AI static SkNx Min(const SkNx& a, const SkNx& b) { // No unsigned _mm_min_epu16, so we'll shift into a space where we can use the // signed version, _mm_min_epi16, then shift back. const uint16_t top = 0x8000; // Keep this separate from _mm_set1_epi16 or MSVC will whine. @@ -281,12 +404,12 @@ public: _mm_sub_epi8(b.fVec, top_8x))); } - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return _mm_or_si128(_mm_and_si128 (fVec, t.fVec), _mm_andnot_si128(fVec, e.fVec)); } - uint16_t operator[](int k) const { + AI uint16_t operator[](int k) const { SkASSERT(0 <= k && k < 8); union { __m128i v; uint16_t us[8]; } pun = {fVec}; return pun.us[k&7]; @@ -298,16 +421,16 @@ public: template <> class SkNx<4, uint8_t> { public: - SkNx() {} - SkNx(const __m128i& vec) : fVec(vec) {} - SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d) + AI SkNx() {} + AI SkNx(const __m128i& vec) : fVec(vec) {} + AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d) : fVec(_mm_setr_epi8(a,b,c,d, 0,0,0,0, 0,0,0,0, 0,0,0,0)) {} - static SkNx Load(const void* ptr) { return _mm_cvtsi32_si128(*(const int*)ptr); } - void store(void* ptr) const { *(int*)ptr = _mm_cvtsi128_si32(fVec); } + AI static SkNx Load(const void* ptr) { return _mm_cvtsi32_si128(*(const int*)ptr); } + AI void store(void* ptr) const { *(int*)ptr = _mm_cvtsi128_si32(fVec); } - uint8_t operator[](int k) const { + AI uint8_t operator[](int k) const { SkASSERT(0 <= k && k < 4); union { __m128i v; uint8_t us[16]; } pun = {fVec}; return pun.us[k&3]; @@ -321,38 +444,38 @@ public: template <> class SkNx<16, uint8_t> { public: - SkNx(const __m128i& vec) : fVec(vec) {} + AI SkNx(const __m128i& vec) : fVec(vec) {} - SkNx() {} - SkNx(uint8_t val) : fVec(_mm_set1_epi8(val)) {} - static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } - SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d, - uint8_t e, uint8_t f, uint8_t g, uint8_t h, - uint8_t i, uint8_t j, uint8_t k, uint8_t l, - uint8_t m, uint8_t n, uint8_t o, uint8_t p) + AI SkNx() {} + AI SkNx(uint8_t val) : fVec(_mm_set1_epi8(val)) {} + AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d, + uint8_t e, uint8_t f, uint8_t g, uint8_t h, + uint8_t i, uint8_t j, uint8_t k, uint8_t l, + uint8_t m, uint8_t n, uint8_t o, uint8_t p) : fVec(_mm_setr_epi8(a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p)) {} - void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } + AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } - SkNx saturatedAdd(const SkNx& o) const { return _mm_adds_epu8(fVec, o.fVec); } + AI SkNx saturatedAdd(const SkNx& o) const { return _mm_adds_epu8(fVec, o.fVec); } - SkNx operator + (const SkNx& o) const { return _mm_add_epi8(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return _mm_sub_epi8(fVec, o.fVec); } + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi8(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi8(fVec, o.fVec); } - static SkNx Min(const SkNx& a, const SkNx& b) { return _mm_min_epu8(a.fVec, b.fVec); } - SkNx operator < (const SkNx& o) const { + AI static SkNx Min(const SkNx& a, const SkNx& b) { return _mm_min_epu8(a.fVec, b.fVec); } + AI SkNx operator < (const SkNx& o) const { // There's no unsigned _mm_cmplt_epu8, so we flip the sign bits then use a signed compare. auto flip = _mm_set1_epi8(char(0x80)); return _mm_cmplt_epi8(_mm_xor_si128(flip, fVec), _mm_xor_si128(flip, o.fVec)); } - uint8_t operator[](int k) const { + AI uint8_t operator[](int k) const { SkASSERT(0 <= k && k < 16); union { __m128i v; uint8_t us[16]; } pun = {fVec}; return pun.us[k&15]; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return _mm_or_si128(_mm_and_si128 (fVec, t.fVec), _mm_andnot_si128(fVec, e.fVec)); } @@ -360,18 +483,18 @@ public: __m128i fVec; }; -template<> /*static*/ inline Sk4f SkNx_cast(const Sk4i& src) { +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4i& src) { return _mm_cvtepi32_ps(src.fVec); } -template<> /*static*/ inline Sk4f SkNx_cast(const Sk4u& src) { +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4u& src) { return SkNx_cast(Sk4i::Load(&src)); } -template <> /*static*/ inline Sk4i SkNx_cast(const Sk4f& src) { +template <> AI /*static*/ Sk4i SkNx_cast(const Sk4f& src) { return _mm_cvttps_epi32(src.fVec); } -template<> /*static*/ inline Sk4h SkNx_cast(const Sk4i& src) { +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4i& src) { #if 0 && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 // TODO: This seems to be causing code generation problems. Investigate? return _mm_packus_epi32(src.fVec); @@ -386,11 +509,11 @@ template<> /*static*/ inline Sk4h SkNx_cast(const Sk4i& src) #endif } -template<> /*static*/ inline Sk4h SkNx_cast(const Sk4f& src) { +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4f& src) { return SkNx_cast(SkNx_cast(src)); } -template<> /*static*/ inline Sk4b SkNx_cast(const Sk4f& src) { +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4f& src) { auto _32 = _mm_cvttps_epi32(src.fVec); #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 const int _ = ~0; @@ -401,23 +524,26 @@ template<> /*static*/ inline Sk4b SkNx_cast(const Sk4f& src) { #endif } -template<> /*static*/ inline Sk4f SkNx_cast(const Sk4b& src) { +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4b& src) { #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 const int _ = ~0; - auto _32 = _mm_shuffle_epi8(src.fVec, _mm_setr_epi8(0,_,_,_, 1,_,_,_, 2,_,_,_, 3,_,_,_)); + return _mm_shuffle_epi8(src.fVec, _mm_setr_epi8(0,_,_,_, 1,_,_,_, 2,_,_,_, 3,_,_,_)); #else - auto _16 = _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128()), - _32 = _mm_unpacklo_epi16(_16, _mm_setzero_si128()); + auto _16 = _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128()); + return _mm_unpacklo_epi16(_16, _mm_setzero_si128()); #endif - return _mm_cvtepi32_ps(_32); } -template<> /*static*/ inline Sk4f SkNx_cast(const Sk4h& src) { +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4b& src) { + return _mm_cvtepi32_ps(SkNx_cast(src).fVec); +} + +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4h& src) { auto _32 = _mm_unpacklo_epi16(src.fVec, _mm_setzero_si128()); return _mm_cvtepi32_ps(_32); } -template<> /*static*/ inline Sk16b SkNx_cast(const Sk16f& src) { +template<> AI /*static*/ Sk16b SkNx_cast(const Sk16f& src) { Sk8f ab, cd; SkNx_split(src, &ab, &cd); @@ -431,76 +557,30 @@ template<> /*static*/ inline Sk16b SkNx_cast(const Sk16f& src) { _mm_cvttps_epi32(d.fVec))); } -template<> /*static*/ inline Sk4h SkNx_cast(const Sk4b& src) { +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4b& src) { return _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128()); } -template<> /*static*/ inline Sk4b SkNx_cast(const Sk4h& src) { +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4h& src) { return _mm_packus_epi16(src.fVec, src.fVec); } -template<> /*static*/ inline Sk4i SkNx_cast(const Sk4h& src) { +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4h& src) { return _mm_unpacklo_epi16(src.fVec, _mm_setzero_si128()); } -template<> /*static*/ inline Sk4b SkNx_cast(const Sk4i& src) { +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4i& src) { return _mm_packus_epi16(_mm_packus_epi16(src.fVec, src.fVec), src.fVec); } -template<> /*static*/ inline Sk4i SkNx_cast(const Sk4u& src) { +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4u& src) { return src.fVec; } -static inline Sk4i Sk4f_round(const Sk4f& x) { +AI static Sk4i Sk4f_round(const Sk4f& x) { return _mm_cvtps_epi32(x.fVec); } -static inline void Sk4h_load4(const void* ptr, Sk4h* r, Sk4h* g, Sk4h* b, Sk4h* a) { - __m128i lo = _mm_loadu_si128(((__m128i*)ptr) + 0), - hi = _mm_loadu_si128(((__m128i*)ptr) + 1); - __m128i even = _mm_unpacklo_epi16(lo, hi), // r0 r2 g0 g2 b0 b2 a0 a2 - odd = _mm_unpackhi_epi16(lo, hi); // r1 r3 ... - __m128i rg = _mm_unpacklo_epi16(even, odd), // r0 r1 r2 r3 g0 g1 g2 g3 - ba = _mm_unpackhi_epi16(even, odd); // b0 b1 ... a0 a1 ... - *r = rg; - *g = _mm_srli_si128(rg, 8); - *b = ba; - *a = _mm_srli_si128(ba, 8); -} - -static inline void Sk4h_store4(void* dst, const Sk4h& r, const Sk4h& g, const Sk4h& b, - const Sk4h& a) { - __m128i rg = _mm_unpacklo_epi16(r.fVec, g.fVec); - __m128i ba = _mm_unpacklo_epi16(b.fVec, a.fVec); - __m128i lo = _mm_unpacklo_epi32(rg, ba); - __m128i hi = _mm_unpackhi_epi32(rg, ba); - _mm_storeu_si128(((__m128i*) dst) + 0, lo); - _mm_storeu_si128(((__m128i*) dst) + 1, hi); -} - -static inline void Sk4f_load4(const void* ptr, Sk4f* r, Sk4f* g, Sk4f* b, Sk4f* a) { - __m128 v0 = _mm_loadu_ps(((float*)ptr) + 0), - v1 = _mm_loadu_ps(((float*)ptr) + 4), - v2 = _mm_loadu_ps(((float*)ptr) + 8), - v3 = _mm_loadu_ps(((float*)ptr) + 12); - _MM_TRANSPOSE4_PS(v0, v1, v2, v3); - *r = v0; - *g = v1; - *b = v2; - *a = v3; -} - -static inline void Sk4f_store4(void* dst, const Sk4f& r, const Sk4f& g, const Sk4f& b, - const Sk4f& a) { - __m128 v0 = r.fVec, - v1 = g.fVec, - v2 = b.fVec, - v3 = a.fVec; - _MM_TRANSPOSE4_PS(v0, v1, v2, v3); - _mm_storeu_ps(((float*) dst) + 0, v0); - _mm_storeu_ps(((float*) dst) + 4, v1); - _mm_storeu_ps(((float*) dst) + 8, v2); - _mm_storeu_ps(((float*) dst) + 12, v3); -} +} // namespace #endif//SkNx_sse_DEFINED diff --git a/gfx/skia/skia/src/opts/SkOpts_avx.cpp b/gfx/skia/skia/src/opts/SkOpts_avx.cpp index b5df2b69f0ce..06e46d950263 100644 --- a/gfx/skia/skia/src/opts/SkOpts_avx.cpp +++ b/gfx/skia/skia/src/opts/SkOpts_avx.cpp @@ -5,10 +5,15 @@ * found in the LICENSE file. */ +#include "SkSafe_math.h" // Keep this first. #include "SkOpts.h" #define SK_OPTS_NS avx +#if defined(_INC_MATH) && !defined(INC_MATH_IS_SAFE_NOW) + #error We have included ucrt\math.h without protecting it against ODR violation. +#endif + namespace SkOpts { void Init_avx() { } } diff --git a/gfx/skia/skia/src/opts/SkOpts_hsw.cpp b/gfx/skia/skia/src/opts/SkOpts_hsw.cpp index 53e2e5acdd91..dded64776a49 100644 --- a/gfx/skia/skia/src/opts/SkOpts_hsw.cpp +++ b/gfx/skia/skia/src/opts/SkOpts_hsw.cpp @@ -5,11 +5,114 @@ * found in the LICENSE file. */ -#include "SkOpts.h" +// It is not safe to #include any header file here unless it has been vetted for ODR safety: +// all symbols used must be file-scoped static or in an anonymous namespace. This applies +// to _all_ header files: C standard library, C++ standard library, Skia... everything. -#define SK_OPTS_NS hsw +#include // ODR safe +#include // ODR safe + +#if defined(__AVX2__) + +namespace hsw { + + void convolve_vertically(const int16_t* filter, int filterLen, + uint8_t* const* srcRows, int width, + uint8_t* out, bool hasAlpha) { + // It's simpler to work with the output array in terms of 4-byte pixels. + auto dst = (int*)out; + + // Output up to eight pixels per iteration. + for (int x = 0; x < width; x += 8) { + // Accumulated result for 4 (non-adjacent) pairs of pixels, + // with each channel in signed 17.14 fixed point. + auto accum04 = _mm256_setzero_si256(), + accum15 = _mm256_setzero_si256(), + accum26 = _mm256_setzero_si256(), + accum37 = _mm256_setzero_si256(); + + // Convolve with the filter. (This inner loop is where we spend ~all our time.) + // While we can, we consume 2 filter coefficients and 2 rows of 8 pixels each at a time. + auto convolve_16_pixels = [&](__m256i interlaced_coeffs, + __m256i pixels_01234567, __m256i pixels_89ABCDEF) { + // Interlaced R0R8 G0G8 B0B8 A0A8 R1R9 G1G9... 32 8-bit values each. + auto _08194C5D = _mm256_unpacklo_epi8(pixels_01234567, pixels_89ABCDEF), + _2A3B6E7F = _mm256_unpackhi_epi8(pixels_01234567, pixels_89ABCDEF); + + // Still interlaced R0R8 G0G8... as above, each channel expanded to 16-bit lanes. + auto _084C = _mm256_unpacklo_epi8(_08194C5D, _mm256_setzero_si256()), + _195D = _mm256_unpackhi_epi8(_08194C5D, _mm256_setzero_si256()), + _2A6E = _mm256_unpacklo_epi8(_2A3B6E7F, _mm256_setzero_si256()), + _3B7F = _mm256_unpackhi_epi8(_2A3B6E7F, _mm256_setzero_si256()); + + // accum0_R += R0*coeff0 + R8*coeff1, etc. + accum04 = _mm256_add_epi32(accum04, _mm256_madd_epi16(_084C, interlaced_coeffs)); + accum15 = _mm256_add_epi32(accum15, _mm256_madd_epi16(_195D, interlaced_coeffs)); + accum26 = _mm256_add_epi32(accum26, _mm256_madd_epi16(_2A6E, interlaced_coeffs)); + accum37 = _mm256_add_epi32(accum37, _mm256_madd_epi16(_3B7F, interlaced_coeffs)); + }; + + int i = 0; + for (; i < filterLen/2*2; i += 2) { + convolve_16_pixels(_mm256_set1_epi32(*(const int32_t*)(filter+i)), + _mm256_loadu_si256((const __m256i*)(srcRows[i+0] + x*4)), + _mm256_loadu_si256((const __m256i*)(srcRows[i+1] + x*4))); + } + if (i < filterLen) { + convolve_16_pixels(_mm256_set1_epi32(*(const int16_t*)(filter+i)), + _mm256_loadu_si256((const __m256i*)(srcRows[i] + x*4)), + _mm256_setzero_si256()); + } + + // Trim the fractional parts off the accumulators. + accum04 = _mm256_srai_epi32(accum04, 14); + accum15 = _mm256_srai_epi32(accum15, 14); + accum26 = _mm256_srai_epi32(accum26, 14); + accum37 = _mm256_srai_epi32(accum37, 14); + + // Pack back down to 8-bit channels. + auto pixels = _mm256_packus_epi16(_mm256_packs_epi32(accum04, accum15), + _mm256_packs_epi32(accum26, accum37)); + + if (hasAlpha) { + // Clamp alpha to the max of r,g,b to make sure we stay premultiplied. + __m256i max_rg = _mm256_max_epu8(pixels, _mm256_srli_epi32(pixels, 8)), + max_rgb = _mm256_max_epu8(max_rg, _mm256_srli_epi32(pixels, 16)); + pixels = _mm256_max_epu8(pixels, _mm256_slli_epi32(max_rgb, 24)); + } else { + // Force opaque. + pixels = _mm256_or_si256(pixels, _mm256_set1_epi32(0xff000000)); + } + + // Normal path to store 8 pixels. + if (x + 8 <= width) { + _mm256_storeu_si256((__m256i*)dst, pixels); + dst += 8; + continue; + } + + // Store one pixel at a time on the last iteration. + for (int i = x; i < width; i++) { + *dst++ = _mm_cvtsi128_si32(_mm256_castsi256_si128(pixels)); + pixels = _mm256_permutevar8x32_epi32(pixels, _mm256_setr_epi32(1,2,3,4,5,6,7,0)); + } + } + } -namespace SkOpts { - void Init_hsw() { } } +namespace SkOpts { + // See SkOpts.h, writing SkConvolutionFilter1D::ConvolutionFixed as the underlying type. + extern void (*convolve_vertically)(const int16_t* filter, int filterLen, + uint8_t* const* srcRows, int width, + uint8_t* out, bool hasAlpha); + void Init_hsw() { + convolve_vertically = hsw::convolve_vertically; + } +} + +#else // defined(__AVX2__) is not true... + +namespace SkOpts { void Init_hsw() {} } + +#endif diff --git a/gfx/skia/skia/src/opts/SkOpts_neon.cpp b/gfx/skia/skia/src/opts/SkOpts_neon.cpp deleted file mode 100644 index 751bea2513f7..000000000000 --- a/gfx/skia/skia/src/opts/SkOpts_neon.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkOpts.h" - -#define SK_OPTS_NS sk_neon -#include "SkBlitMask_opts.h" -#include "SkBlitRow_opts.h" -#include "SkBlurImageFilter_opts.h" -#include "SkColorCubeFilter_opts.h" -#include "SkMorphologyImageFilter_opts.h" -#include "SkSwizzler_opts.h" -#include "SkTextureCompressor_opts.h" -#include "SkXfermode_opts.h" - -namespace SkOpts { - void Init_neon() { - create_xfermode = sk_neon::create_xfermode; - - box_blur_xx = sk_neon::box_blur_xx; - box_blur_xy = sk_neon::box_blur_xy; - box_blur_yx = sk_neon::box_blur_yx; - - dilate_x = sk_neon::dilate_x; - dilate_y = sk_neon::dilate_y; - erode_x = sk_neon::erode_x; - erode_y = sk_neon::erode_y; - - texture_compressor = sk_neon::texture_compressor; - fill_block_dimensions = sk_neon::fill_block_dimensions; - - blit_mask_d32_a8 = sk_neon::blit_mask_d32_a8; - - blit_row_color32 = sk_neon::blit_row_color32; - blit_row_s32a_opaque = sk_neon::blit_row_s32a_opaque; - - color_cube_filter_span = sk_neon::color_cube_filter_span; - - RGBA_to_BGRA = sk_neon::RGBA_to_BGRA; - RGBA_to_rgbA = sk_neon::RGBA_to_rgbA; - RGBA_to_bgrA = sk_neon::RGBA_to_bgrA; - RGB_to_RGB1 = sk_neon::RGB_to_RGB1; - RGB_to_BGR1 = sk_neon::RGB_to_BGR1; - gray_to_RGB1 = sk_neon::gray_to_RGB1; - grayA_to_RGBA = sk_neon::grayA_to_RGBA; - grayA_to_rgbA = sk_neon::grayA_to_rgbA; - inverted_CMYK_to_RGB1 = sk_neon::inverted_CMYK_to_RGB1; - inverted_CMYK_to_BGR1 = sk_neon::inverted_CMYK_to_BGR1; - } -} diff --git a/gfx/skia/skia/src/opts/SkOpts_sse41.cpp b/gfx/skia/skia/src/opts/SkOpts_sse41.cpp index 3a37834c725f..7a90f7683e6d 100644 --- a/gfx/skia/skia/src/opts/SkOpts_sse41.cpp +++ b/gfx/skia/skia/src/opts/SkOpts_sse41.cpp @@ -20,62 +20,6 @@ namespace SkOpts { box_blur_yx = sse41::box_blur_yx; srcover_srgb_srgb = sse41::srcover_srgb_srgb; blit_row_s32a_opaque = sse41::blit_row_s32a_opaque; - - #define STAGE(stage, kCallNext) \ - stages_4 [SkRasterPipeline::stage] = stage_4 ; \ - stages_1_3[SkRasterPipeline::stage] = stage_1_3 - - STAGE(store_565 , false); - STAGE(store_srgb, false); - STAGE(store_f16 , false); - - STAGE(load_s_565 , true); - STAGE(load_s_srgb, true); - STAGE(load_s_f16 , true); - - STAGE(load_d_565 , true); - STAGE(load_d_srgb, true); - STAGE(load_d_f16 , true); - - STAGE(scale_u8, true); - - STAGE(lerp_u8 , true); - STAGE(lerp_565 , true); - STAGE(lerp_constant_float, true); - - STAGE(constant_color, true); - - #undef STAGE - - #define STAGE(stage) \ - stages_4 [SkRasterPipeline::stage] = SK_OPTS_NS::stage; \ - stages_1_3[SkRasterPipeline::stage] = SK_OPTS_NS::stage - - STAGE(dst); - STAGE(dstatop); - STAGE(dstin); - STAGE(dstout); - STAGE(dstover); - STAGE(srcatop); - STAGE(srcin); - STAGE(srcout); - STAGE(srcover); - STAGE(clear); - STAGE(modulate); - STAGE(multiply); - STAGE(plus_); - STAGE(screen); - STAGE(xor_); - STAGE(colorburn); - STAGE(colordodge); - STAGE(darken); - STAGE(difference); - STAGE(exclusion); - STAGE(hardlight); - STAGE(lighten); - STAGE(overlay); - STAGE(softlight); - #undef STAGE - + run_pipeline = sse41::run_pipeline; } } diff --git a/gfx/skia/skia/src/opts/SkOpts_ssse3.cpp b/gfx/skia/skia/src/opts/SkOpts_ssse3.cpp index ec968339a076..0d2fcf42acf9 100644 --- a/gfx/skia/skia/src/opts/SkOpts_ssse3.cpp +++ b/gfx/skia/skia/src/opts/SkOpts_ssse3.cpp @@ -8,7 +8,6 @@ #include "SkOpts.h" #define SK_OPTS_NS ssse3 #include "SkBlitMask_opts.h" -#include "SkColorCubeFilter_opts.h" #include "SkSwizzler_opts.h" #include "SkXfermode_opts.h" @@ -16,7 +15,6 @@ namespace SkOpts { void Init_ssse3() { create_xfermode = ssse3::create_xfermode; blit_mask_d32_a8 = ssse3::blit_mask_d32_a8; - color_cube_filter_span = ssse3::color_cube_filter_span; RGBA_to_BGRA = ssse3::RGBA_to_BGRA; RGBA_to_rgbA = ssse3::RGBA_to_rgbA; diff --git a/gfx/skia/skia/src/opts/SkRasterPipeline_opts.h b/gfx/skia/skia/src/opts/SkRasterPipeline_opts.h index fdb15b421ee2..1146b3d7fb54 100644 --- a/gfx/skia/skia/src/opts/SkRasterPipeline_opts.h +++ b/gfx/skia/skia/src/opts/SkRasterPipeline_opts.h @@ -8,351 +8,1184 @@ #ifndef SkRasterPipeline_opts_DEFINED #define SkRasterPipeline_opts_DEFINED +#include "SkColorPriv.h" +#include "SkColorLookUpTable.h" +#include "SkColorSpaceXform_A2B.h" +#include "SkColorSpaceXformPriv.h" #include "SkHalf.h" +#include "SkMSAN.h" #include "SkPM4f.h" +#include "SkPM4fPriv.h" #include "SkRasterPipeline.h" +#include "SkShader.h" #include "SkSRGB.h" +#include "../jumper/SkJumper.h" -using Kernel_Sk4f = void(void*, size_t, size_t, Sk4f&, Sk4f&, Sk4f&, Sk4f&, - Sk4f&, Sk4f&, Sk4f&, Sk4f&); +namespace { -// These are always static, and we _really_ want them to inline. -// If you find yourself wanting a non-inline stage, write a SkRasterPipeline::Fn directly. -#define KERNEL_Sk4f(name) \ - static SK_ALWAYS_INLINE void name(void* ctx, size_t x, size_t tail, \ - Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, \ - Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) + static constexpr int N = 4; + using SkNf = SkNx; + using SkNi = SkNx; + using SkNu = SkNx; + using SkNh = SkNx; + using SkNb = SkNx; -template -static inline void SK_VECTORCALL stage_4(SkRasterPipeline::Stage* st, size_t x, size_t tail, - Sk4f r, Sk4f g, Sk4f b, Sk4f a, - Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { - // Passing 0 lets the optimizer completely drop any "if (tail) {...}" code in kernel. - kernel(st->ctx(), x,0, r,g,b,a, dr,dg,db,da); - if (kCallNext) { - st->next(x,tail, r,g,b,a, dr,dg,db,da); // It's faster to pass t here than 0. - } -} + using Fn = void(SK_VECTORCALL *)(size_t x_tail, void** p, SkNf,SkNf,SkNf,SkNf, + SkNf,SkNf,SkNf,SkNf); + // x_tail encodes two values x and tail as x*N+tail, where 0 <= tail < N. + // x is the induction variable we're walking along, incrementing by N each step. + // tail == 0 means work with a full N pixels; otherwise use only the low tail pixels. + // + // p is our program, a sequence of Fn to call interlaced with any void* context pointers. E.g. + // &load_8888 + // (src ptr) + // &from_srgb + // &move_src_dst + // &load_f16 + // (dst ptr) + // &swap + // &srcover + // &store_f16 + // (dst ptr) + // &just_return -template -static inline void SK_VECTORCALL stage_1_3(SkRasterPipeline::Stage* st, size_t x, size_t tail, - Sk4f r, Sk4f g, Sk4f b, Sk4f a, - Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { -#if defined(__clang__) - __builtin_assume(tail > 0); // This flourish lets Clang compile away any tail==0 code. +} // namespace + +#define SI static inline + +// Basically, return *(*ptr)++, maybe faster than the compiler can do it. +SI void* load_and_increment(void*** ptr) { + // We do this often enough that it's worth hyper-optimizing. + // x86 can do this in one instruction if ptr is in rsi. + // (This is why p is the second argument to Fn: it's passed in rsi.) +#if defined(__GNUC__) && defined(__x86_64__) + void* rax; + __asm__("lodsq" : "=a"(rax), "+S"(*ptr)); + return rax; +#else + return *(*ptr)++; #endif - kernel(st->ctx(), x,tail, r,g,b,a, dr,dg,db,da); - if (kCallNext) { - st->next(x,tail, r,g,b,a, dr,dg,db,da); - } } +// Stages are logically a pipeline, and physically are contiguous in an array. +// To get to the next stage, we just increment our pointer to the next array element. +SI void SK_VECTORCALL next(size_t x_tail, void** p, SkNf r, SkNf g, SkNf b, SkNf a, + SkNf dr, SkNf dg, SkNf db, SkNf da) { + auto next = (Fn)load_and_increment(&p); + next(x_tail,p, r,g,b,a, dr,dg,db,da); +} + +// Stages defined below always call next. +// This is always the last stage, a backstop that actually returns to the caller when done. +SI void SK_VECTORCALL just_return(size_t, void**, SkNf, SkNf, SkNf, SkNf, + SkNf, SkNf, SkNf, SkNf) {} + +#define STAGE(name) \ + static SK_ALWAYS_INLINE void name##_kernel(size_t x, size_t tail, \ + SkNf& r, SkNf& g, SkNf& b, SkNf& a, \ + SkNf& dr, SkNf& dg, SkNf& db, SkNf& da); \ + SI void SK_VECTORCALL name(size_t x_tail, void** p, \ + SkNf r, SkNf g, SkNf b, SkNf a, \ + SkNf dr, SkNf dg, SkNf db, SkNf da) { \ + name##_kernel(x_tail/N, x_tail%N, r,g,b,a, dr,dg,db,da); \ + next(x_tail,p, r,g,b,a, dr,dg,db,da); \ + } \ + static SK_ALWAYS_INLINE void name##_kernel(size_t x, size_t tail, \ + SkNf& r, SkNf& g, SkNf& b, SkNf& a, \ + SkNf& dr, SkNf& dg, SkNf& db, SkNf& da) + +#define STAGE_CTX(name, Ctx) \ + static SK_ALWAYS_INLINE void name##_kernel(Ctx ctx, size_t x, size_t tail, \ + SkNf& r, SkNf& g, SkNf& b, SkNf& a, \ + SkNf& dr, SkNf& dg, SkNf& db, SkNf& da); \ + SI void SK_VECTORCALL name(size_t x_tail, void** p, \ + SkNf r, SkNf g, SkNf b, SkNf a, \ + SkNf dr, SkNf dg, SkNf db, SkNf da) { \ + auto ctx = (Ctx)load_and_increment(&p); \ + name##_kernel(ctx, x_tail/N, x_tail%N, r,g,b,a, dr,dg,db,da); \ + next(x_tail,p, r,g,b,a, dr,dg,db,da); \ + } \ + static SK_ALWAYS_INLINE void name##_kernel(Ctx ctx, size_t x, size_t tail, \ + SkNf& r, SkNf& g, SkNf& b, SkNf& a, \ + SkNf& dr, SkNf& dg, SkNf& db, SkNf& da) + // Many xfermodes apply the same logic to each channel. -#define RGBA_XFERMODE_Sk4f(name) \ - static SK_ALWAYS_INLINE Sk4f name##_kernel(const Sk4f& s, const Sk4f& sa, \ - const Sk4f& d, const Sk4f& da); \ - static void SK_VECTORCALL name(SkRasterPipeline::Stage* st, size_t x, size_t tail, \ - Sk4f r, Sk4f g, Sk4f b, Sk4f a, \ - Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { \ - r = name##_kernel(r,a,dr,da); \ - g = name##_kernel(g,a,dg,da); \ - b = name##_kernel(b,a,db,da); \ - a = name##_kernel(a,a,da,da); \ - st->next(x,tail, r,g,b,a, dr,dg,db,da); \ - } \ - static SK_ALWAYS_INLINE Sk4f name##_kernel(const Sk4f& s, const Sk4f& sa, \ - const Sk4f& d, const Sk4f& da) +#define RGBA_XFERMODE(name) \ + static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa, \ + const SkNf& d, const SkNf& da); \ + SI void SK_VECTORCALL name(size_t x_tail, void** p, \ + SkNf r, SkNf g, SkNf b, SkNf a, \ + SkNf dr, SkNf dg, SkNf db, SkNf da) { \ + r = name##_kernel(r,a,dr,da); \ + g = name##_kernel(g,a,dg,da); \ + b = name##_kernel(b,a,db,da); \ + a = name##_kernel(a,a,da,da); \ + next(x_tail,p, r,g,b,a, dr,dg,db,da); \ + } \ + static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa, \ + const SkNf& d, const SkNf& da) // Most of the rest apply the same logic to color channels and use srcover's alpha logic. -#define RGB_XFERMODE_Sk4f(name) \ - static SK_ALWAYS_INLINE Sk4f name##_kernel(const Sk4f& s, const Sk4f& sa, \ - const Sk4f& d, const Sk4f& da); \ - static void SK_VECTORCALL name(SkRasterPipeline::Stage* st, size_t x, size_t tail, \ - Sk4f r, Sk4f g, Sk4f b, Sk4f a, \ - Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { \ - r = name##_kernel(r,a,dr,da); \ - g = name##_kernel(g,a,dg,da); \ - b = name##_kernel(b,a,db,da); \ - a = a + (da * (1.0f-a)); \ - st->next(x,tail, r,g,b,a, dr,dg,db,da); \ - } \ - static SK_ALWAYS_INLINE Sk4f name##_kernel(const Sk4f& s, const Sk4f& sa, \ - const Sk4f& d, const Sk4f& da) +#define RGB_XFERMODE(name) \ + static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa, \ + const SkNf& d, const SkNf& da); \ + SI void SK_VECTORCALL name(size_t x_tail, void** p, \ + SkNf r, SkNf g, SkNf b, SkNf a, \ + SkNf dr, SkNf dg, SkNf db, SkNf da) { \ + r = name##_kernel(r,a,dr,da); \ + g = name##_kernel(g,a,dg,da); \ + b = name##_kernel(b,a,db,da); \ + a = a + (da * (1.0f-a)); \ + next(x_tail,p, r,g,b,a, dr,dg,db,da); \ + } \ + static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa, \ + const SkNf& d, const SkNf& da) + +template +SI SkNx load(size_t tail, const T* src) { + if (tail) { + T buf[8]; + memset(buf, 0, 8*sizeof(T)); + switch (tail & (N-1)) { + case 7: buf[6] = src[6]; + case 6: buf[5] = src[5]; + case 5: buf[4] = src[4]; + case 4: buf[3] = src[3]; + case 3: buf[2] = src[2]; + case 2: buf[1] = src[1]; + } + buf[0] = src[0]; + return SkNx::Load(buf); + } + return SkNx::Load(src); +} +template +SI SkNx gather(size_t tail, const T* src, const SkNi& offset) { + if (tail) { + T buf[8] = {0}; + switch (tail & (N-1)) { + case 7: buf[6] = src[offset[6]]; + case 6: buf[5] = src[offset[5]]; + case 5: buf[4] = src[offset[4]]; + case 4: buf[3] = src[offset[3]]; + case 3: buf[2] = src[offset[2]]; + case 2: buf[1] = src[offset[1]]; + } + buf[0] = src[offset[0]]; + return SkNx::Load(buf); + } + T buf[8]; + for (size_t i = 0; i < N; i++) { + buf[i] = src[offset[i]]; + } + return SkNx::Load(buf); +} +template +SI void store(size_t tail, const SkNx& v, T* dst) { + if (tail) { + switch (tail & (N-1)) { + case 7: dst[6] = v[6]; + case 6: dst[5] = v[5]; + case 5: dst[4] = v[4]; + case 4: dst[3] = v[3]; + case 3: dst[2] = v[2]; + case 2: dst[1] = v[1]; + } + dst[0] = v[0]; + return; + } + v.store(dst); +} + +SI SkNf SkNf_fma(const SkNf& f, const SkNf& m, const SkNf& a) { return SkNx_fma(f,m,a); } + +SI SkNi SkNf_round(const SkNf& x, const SkNf& scale) { + // Every time I try, _mm_cvtps_epi32 benches as slower than using FMA and _mm_cvttps_epi32. :/ + return SkNx_cast(SkNf_fma(x,scale, 0.5f)); +} + +SI SkNf SkNf_from_byte(const SkNi& x) { + // Same trick as in store_8888: 0x470000BB == 32768.0f + BB/256.0f for all bytes BB. + auto v = 0x47000000 | x; + // Read this as (pun_float(v) - 32768.0f) * (256/255.0f), redistributed to be an FMA. + return SkNf_fma(SkNf::Load(&v), 256/255.0f, -32768*256/255.0f); +} +SI SkNf SkNf_from_byte(const SkNu& x) { return SkNf_from_byte(SkNi::Load(&x)); } +SI SkNf SkNf_from_byte(const SkNb& x) { return SkNf_from_byte(SkNx_cast(x)); } + +SI void from_8888(const SkNu& _8888, SkNf* r, SkNf* g, SkNf* b, SkNf* a) { + *r = SkNf_from_byte((_8888 ) & 0xff); + *g = SkNf_from_byte((_8888 >> 8) & 0xff); + *b = SkNf_from_byte((_8888 >> 16) & 0xff); + *a = SkNf_from_byte((_8888 >> 24) ); +} +SI void from_4444(const SkNh& _4444, SkNf* r, SkNf* g, SkNf* b, SkNf* a) { + auto _32_bit = SkNx_cast(_4444); + + *r = SkNx_cast(_32_bit & (0xF << SK_R4444_SHIFT)) * (1.0f / (0xF << SK_R4444_SHIFT)); + *g = SkNx_cast(_32_bit & (0xF << SK_G4444_SHIFT)) * (1.0f / (0xF << SK_G4444_SHIFT)); + *b = SkNx_cast(_32_bit & (0xF << SK_B4444_SHIFT)) * (1.0f / (0xF << SK_B4444_SHIFT)); + *a = SkNx_cast(_32_bit & (0xF << SK_A4444_SHIFT)) * (1.0f / (0xF << SK_A4444_SHIFT)); +} +SI void from_565(const SkNh& _565, SkNf* r, SkNf* g, SkNf* b) { + auto _32_bit = SkNx_cast(_565); + + *r = SkNx_cast(_32_bit & SK_R16_MASK_IN_PLACE) * (1.0f / SK_R16_MASK_IN_PLACE); + *g = SkNx_cast(_32_bit & SK_G16_MASK_IN_PLACE) * (1.0f / SK_G16_MASK_IN_PLACE); + *b = SkNx_cast(_32_bit & SK_B16_MASK_IN_PLACE) * (1.0f / SK_B16_MASK_IN_PLACE); +} +SI void from_f16(const void* px, SkNf* r, SkNf* g, SkNf* b, SkNf* a) { + SkNh rh, gh, bh, ah; + SkNh::Load4(px, &rh, &gh, &bh, &ah); + + *r = SkHalfToFloat_finite_ftz(rh); + *g = SkHalfToFloat_finite_ftz(gh); + *b = SkHalfToFloat_finite_ftz(bh); + *a = SkHalfToFloat_finite_ftz(ah); +} + +STAGE(clamp_0) { + a = SkNf::Max(a, 0.0f); + r = SkNf::Max(r, 0.0f); + g = SkNf::Max(g, 0.0f); + b = SkNf::Max(b, 0.0f); +} +STAGE(clamp_1) { + a = SkNf::Min(a, 1.0f); + r = SkNf::Min(r, 1.0f); + g = SkNf::Min(g, 1.0f); + b = SkNf::Min(b, 1.0f); +} +STAGE(clamp_a) { + a = SkNf::Min(a, 1.0f); + r = SkNf::Min(r, a); + g = SkNf::Min(g, a); + b = SkNf::Min(b, a); +} + +STAGE(unpremul) { + auto scale = (a == 0.0f).thenElse(0.0f, 1.0f/a); + r *= scale; + g *= scale; + b *= scale; +} +STAGE(premul) { + r *= a; + g *= a; + b *= a; +} + +STAGE_CTX(set_rgb, const float*) { + r = ctx[0]; + g = ctx[1]; + b = ctx[2]; +} +STAGE(swap_rb) { SkTSwap(r,b); } + +STAGE(move_src_dst) { + dr = r; + dg = g; + db = b; + da = a; +} +STAGE(move_dst_src) { + r = dr; + g = dg; + b = db; + a = da; +} +STAGE(swap) { + SkTSwap(r,dr); + SkTSwap(g,dg); + SkTSwap(b,db); + SkTSwap(a,da); +} + +STAGE(from_srgb) { + r = sk_linear_from_srgb_math(r); + g = sk_linear_from_srgb_math(g); + b = sk_linear_from_srgb_math(b); +} +STAGE(to_srgb) { + r = sk_linear_to_srgb_needs_round(r); + g = sk_linear_to_srgb_needs_round(g); + b = sk_linear_to_srgb_needs_round(b); +} + +STAGE(from_2dot2) { + auto from_2dot2 = [](const SkNf& x) { + // x^(141/64) = x^(2.20312) is a great approximation of the true value, x^(2.2). + // (note: x^(35/16) = x^(2.1875) is an okay one as well and would be quicker) + auto x16 = x.rsqrt().rsqrt().rsqrt().rsqrt(); // x^(1/16) = x^(4/64); + auto x64 = x16.rsqrt().rsqrt(); // x^(1/64) + + // x^(141/64) = x^(128/64) * x^(12/64) * x^(1/64) + return SkNf::Max((x*x) * (x16*x16*x16) * (x64), 0.0f); + }; + + r = from_2dot2(r); + g = from_2dot2(g); + b = from_2dot2(b); +} +STAGE(to_2dot2) { + auto to_2dot2 = [](const SkNf& x) { + // x^(29/64) is a very good approximation of the true value, x^(1/2.2). + auto x2 = x.rsqrt(), // x^(-1/2) + x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(), // x^(-1/32) + x64 = x32.rsqrt(); // x^(+1/64) + + // 29 = 32 - 2 - 1 + return SkNf::Max(x2.invert() * x32 * x64.invert(), 0.0f); // Watch out for NaN. + }; + + r = to_2dot2(r); + g = to_2dot2(g); + b = to_2dot2(b); +} + +// The default shader produces a constant color (from the SkPaint). +STAGE_CTX(constant_color, const SkPM4f*) { + r = ctx->r(); + g = ctx->g(); + b = ctx->b(); + a = ctx->a(); +} + +// Set up registers with values relevant to shaders. +STAGE_CTX(seed_shader, const int*) { + int y = *ctx; + + static const float dx[] = { 0,1,2,3,4,5,6,7 }; + r = x + 0.5f + SkNf::Load(dx); // dst pixel center x coordinates + g = y + 0.5f; // dst pixel center y coordinate(s) + b = 1.0f; + a = 0.0f; + dr = dg = db = da = 0.0f; +} + +// s' = sc for a scalar c. +STAGE_CTX(scale_1_float, const float*) { + SkNf c = *ctx; + + r *= c; + g *= c; + b *= c; + a *= c; +} +// s' = sc for 8-bit c. +STAGE_CTX(scale_u8, const uint8_t**) { + auto ptr = *ctx + x; + SkNf c = SkNf_from_byte(load(tail, ptr)); + + r = r*c; + g = g*c; + b = b*c; + a = a*c; +} + +SI SkNf lerp(const SkNf& from, const SkNf& to, const SkNf& cov) { + return SkNf_fma(to-from, cov, from); +} + +// s' = d(1-c) + sc, for a scalar c. +STAGE_CTX(lerp_1_float, const float*) { + SkNf c = *ctx; + + r = lerp(dr, r, c); + g = lerp(dg, g, c); + b = lerp(db, b, c); + a = lerp(da, a, c); +} + +// s' = d(1-c) + sc for 8-bit c. +STAGE_CTX(lerp_u8, const uint8_t**) { + auto ptr = *ctx + x; + SkNf c = SkNf_from_byte(load(tail, ptr)); + + r = lerp(dr, r, c); + g = lerp(dg, g, c); + b = lerp(db, b, c); + a = lerp(da, a, c); +} + +// s' = d(1-c) + sc for 565 c. +STAGE_CTX(lerp_565, const uint16_t**) { + auto ptr = *ctx + x; + SkNf cr, cg, cb; + from_565(load(tail, ptr), &cr, &cg, &cb); + + r = lerp(dr, r, cr); + g = lerp(dg, g, cg); + b = lerp(db, b, cb); + a = 1.0f; +} + +STAGE_CTX(load_a8, const uint8_t**) { + auto ptr = *ctx + x; + r = g = b = 0.0f; + a = SkNf_from_byte(load(tail, ptr)); +} +STAGE_CTX(store_a8, uint8_t**) { + auto ptr = *ctx + x; + store(tail, SkNx_cast(SkNf_round(255.0f, a)), ptr); +} + +STAGE_CTX(load_g8, const uint8_t**) { + auto ptr = *ctx + x; + r = g = b = SkNf_from_byte(load(tail, ptr)); + a = 1.0f; +} + +STAGE_CTX(load_565, const uint16_t**) { + auto ptr = *ctx + x; + from_565(load(tail, ptr), &r,&g,&b); + a = 1.0f; +} +STAGE_CTX(store_565, uint16_t**) { + auto ptr = *ctx + x; + store(tail, SkNx_cast( SkNf_round(r, SK_R16_MASK) << SK_R16_SHIFT + | SkNf_round(g, SK_G16_MASK) << SK_G16_SHIFT + | SkNf_round(b, SK_B16_MASK) << SK_B16_SHIFT), ptr); +} + +STAGE_CTX(load_4444, const uint16_t**) { + auto ptr = *ctx + x; + from_4444(load(tail, ptr), &r,&g,&b,&a); +} +STAGE_CTX(store_4444, uint16_t**) { + auto ptr = *ctx + x; + store(tail, SkNx_cast( SkNf_round(r, 0xF) << SK_R4444_SHIFT + | SkNf_round(g, 0xF) << SK_G4444_SHIFT + | SkNf_round(b, 0xF) << SK_B4444_SHIFT + | SkNf_round(a, 0xF) << SK_A4444_SHIFT), ptr); +} + +STAGE_CTX(load_f16, const uint64_t**) { + auto ptr = *ctx + x; + + const void* src = ptr; + SkNx px; + if (tail) { + px = load(tail, ptr); + src = &px; + } + from_f16(src, &r, &g, &b, &a); +} +STAGE_CTX(store_f16, uint64_t**) { + auto ptr = *ctx + x; + + SkNx px; + SkNh::Store4(tail ? (void*)&px : (void*)ptr, SkFloatToHalf_finite_ftz(r), + SkFloatToHalf_finite_ftz(g), + SkFloatToHalf_finite_ftz(b), + SkFloatToHalf_finite_ftz(a)); + if (tail) { + store(tail, px, ptr); + } +} + +STAGE_CTX(load_f32, const SkPM4f**) { + auto ptr = *ctx + x; + + const void* src = ptr; + SkNx px; + if (tail) { + px = load(tail, ptr); + src = &px; + } + SkNf::Load4(src, &r, &g, &b, &a); +} +STAGE_CTX(store_f32, SkPM4f**) { + auto ptr = *ctx + x; + + SkNx px; + SkNf::Store4(tail ? (void*)&px : (void*)ptr, r,g,b,a); + if (tail) { + store(tail, px, ptr); + } +} + + +STAGE_CTX(load_8888, const uint32_t**) { + auto ptr = *ctx + x; + from_8888(load(tail, ptr), &r, &g, &b, &a); +} +STAGE_CTX(store_8888, uint32_t**) { + auto byte = [](const SkNf& x, int ix) { + // Here's a neat trick: 0x47000000 == 32768.0f, and 0x470000ff == 32768.0f + (255/256.0f). + auto v = SkNf_fma(255/256.0f, x, 32768.0f); + switch (ix) { + case 0: return SkNi::Load(&v) & 0xff; // R + case 3: return SkNi::Load(&v) << 24; // A + } + return (SkNi::Load(&v) & 0xff) << (8*ix); // B or G + }; + + auto ptr = *ctx + x; + store(tail, byte(r,0)|byte(g,1)|byte(b,2)|byte(a,3), (int*)ptr); +} + +STAGE_CTX(load_u16_be, const uint64_t**) { + auto ptr = *ctx + x; + const void* src = ptr; + SkNx px; + if (tail) { + px = load(tail, ptr); + src = &px; + } + + SkNh rh, gh, bh, ah; + SkNh::Load4(src, &rh, &gh, &bh, &ah); + r = (1.0f / 65535.0f) * SkNx_cast((rh << 8) | (rh >> 8)); + g = (1.0f / 65535.0f) * SkNx_cast((gh << 8) | (gh >> 8)); + b = (1.0f / 65535.0f) * SkNx_cast((bh << 8) | (bh >> 8)); + a = (1.0f / 65535.0f) * SkNx_cast((ah << 8) | (ah >> 8)); +} + +STAGE_CTX(load_rgb_u16_be, const uint16_t**) { + auto ptr = *ctx + 3*x; + const void* src = ptr; + uint16_t buf[N*3] = {0}; + if (tail) { + memcpy(buf, src, tail*3*sizeof(uint16_t)); + src = buf; + } + + SkNh rh, gh, bh; + SkNh::Load3(src, &rh, &gh, &bh); + r = (1.0f / 65535.0f) * SkNx_cast((rh << 8) | (rh >> 8)); + g = (1.0f / 65535.0f) * SkNx_cast((gh << 8) | (gh >> 8)); + b = (1.0f / 65535.0f) * SkNx_cast((bh << 8) | (bh >> 8)); + a = 1.0f; +} + +STAGE_CTX(store_u16_be, uint64_t**) { + auto to_u16_be = [](const SkNf& x) { + SkNh x16 = SkNx_cast(65535.0f * x); + return (x16 << 8) | (x16 >> 8); + }; + + auto ptr = *ctx + x; + SkNx px; + SkNh::Store4(tail ? (void*)&px : (void*)ptr, to_u16_be(r), + to_u16_be(g), + to_u16_be(b), + to_u16_be(a)); + if (tail) { + store(tail, px, ptr); + } +} + +STAGE_CTX(load_tables, const LoadTablesContext*) { + auto ptr = (const uint32_t*)ctx->fSrc + x; + + SkNu rgba = load(tail, ptr); + auto to_int = [](const SkNu& v) { return SkNi::Load(&v); }; + r = gather(tail, ctx->fR, to_int((rgba >> 0) & 0xff)); + g = gather(tail, ctx->fG, to_int((rgba >> 8) & 0xff)); + b = gather(tail, ctx->fB, to_int((rgba >> 16) & 0xff)); + a = SkNf_from_byte(rgba >> 24); +} + +STAGE_CTX(load_tables_u16_be, const LoadTablesContext*) { + auto ptr = (const uint64_t*)ctx->fSrc + x; + const void* src = ptr; + SkNx px; + if (tail) { + px = load(tail, ptr); + src = &px; + } + + SkNh rh, gh, bh, ah; + SkNh::Load4(src, &rh, &gh, &bh, &ah); + + // ctx->fSrc is big-endian, so "& 0xff" grabs the 8 most significant bits of each component. + r = gather(tail, ctx->fR, SkNx_cast(rh & 0xff)); + g = gather(tail, ctx->fG, SkNx_cast(gh & 0xff)); + b = gather(tail, ctx->fB, SkNx_cast(bh & 0xff)); + a = (1.0f / 65535.0f) * SkNx_cast((ah << 8) | (ah >> 8)); +} + +STAGE_CTX(load_tables_rgb_u16_be, const LoadTablesContext*) { + auto ptr = (const uint16_t*)ctx->fSrc + 3*x; + const void* src = ptr; + uint16_t buf[N*3] = {0}; + if (tail) { + memcpy(buf, src, tail*3*sizeof(uint16_t)); + src = buf; + } + + SkNh rh, gh, bh; + SkNh::Load3(src, &rh, &gh, &bh); + + // ctx->fSrc is big-endian, so "& 0xff" grabs the 8 most significant bits of each component. + r = gather(tail, ctx->fR, SkNx_cast(rh & 0xff)); + g = gather(tail, ctx->fG, SkNx_cast(gh & 0xff)); + b = gather(tail, ctx->fB, SkNx_cast(bh & 0xff)); + a = 1.0f; +} + +SI SkNf inv(const SkNf& x) { return 1.0f - x; } + +RGBA_XFERMODE(clear) { return 0.0f; } +RGBA_XFERMODE(srcatop) { return s*da + d*inv(sa); } +RGBA_XFERMODE(srcin) { return s * da; } +RGBA_XFERMODE(srcout) { return s * inv(da); } +RGBA_XFERMODE(srcover) { return SkNf_fma(d, inv(sa), s); } +RGBA_XFERMODE(dstatop) { return srcatop_kernel(d,da,s,sa); } +RGBA_XFERMODE(dstin) { return srcin_kernel (d,da,s,sa); } +RGBA_XFERMODE(dstout) { return srcout_kernel (d,da,s,sa); } +RGBA_XFERMODE(dstover) { return srcover_kernel(d,da,s,sa); } + +RGBA_XFERMODE(modulate) { return s*d; } +RGBA_XFERMODE(multiply) { return s*inv(da) + d*inv(sa) + s*d; } +RGBA_XFERMODE(plus_) { return s + d; } +RGBA_XFERMODE(screen) { return s + d - s*d; } +RGBA_XFERMODE(xor_) { return s*inv(da) + d*inv(sa); } + +RGB_XFERMODE(colorburn) { + return (d == da ).thenElse(d + s*inv(da), + (s == 0.0f).thenElse(s + d*inv(sa), + sa*(da - SkNf::Min(da, (da-d)*sa/s)) + s*inv(da) + d*inv(sa))); +} +RGB_XFERMODE(colordodge) { + return (d == 0.0f).thenElse(d + s*inv(da), + (s == sa ).thenElse(s + d*inv(sa), + sa*SkNf::Min(da, (d*sa)/(sa - s)) + s*inv(da) + d*inv(sa))); +} +RGB_XFERMODE(darken) { return s + d - SkNf::Max(s*da, d*sa); } +RGB_XFERMODE(difference) { return s + d - 2.0f*SkNf::Min(s*da,d*sa); } +RGB_XFERMODE(exclusion) { return s + d - 2.0f*s*d; } +RGB_XFERMODE(hardlight) { + return s*inv(da) + d*inv(sa) + + (2.0f*s <= sa).thenElse(2.0f*s*d, sa*da - 2.0f*(da-d)*(sa-s)); +} +RGB_XFERMODE(lighten) { return s + d - SkNf::Min(s*da, d*sa); } +RGB_XFERMODE(overlay) { return hardlight_kernel(d,da,s,sa); } +RGB_XFERMODE(softlight) { + SkNf m = (da > 0.0f).thenElse(d / da, 0.0f), + s2 = 2.0f*s, + m4 = 4.0f*m; + + // The logic forks three ways: + // 1. dark src? + // 2. light src, dark dst? + // 3. light src, light dst? + SkNf darkSrc = d*(sa + (s2 - sa)*(1.0f - m)), // Used in case 1. + darkDst = (m4*m4 + m4)*(m - 1.0f) + 7.0f*m, // Used in case 2. + liteDst = m.rsqrt().invert() - m, // Used in case 3. + liteSrc = d*sa + da*(s2 - sa) * (4.0f*d <= da).thenElse(darkDst, liteDst); // 2 or 3? + return s*inv(da) + d*inv(sa) + (s2 <= sa).thenElse(darkSrc, liteSrc); // 1 or (2 or 3)? +} + +STAGE(luminance_to_alpha) { + a = SK_LUM_COEFF_R*r + SK_LUM_COEFF_G*g + SK_LUM_COEFF_B*b; + r = g = b = 0; +} + +STAGE(rgb_to_hsl) { + auto max = SkNf::Max(SkNf::Max(r, g), b); + auto min = SkNf::Min(SkNf::Min(r, g), b); + auto l = 0.5f * (max + min); + + auto d = max - min; + auto d_inv = 1.0f/d; + auto s = (max == min).thenElse(0.0f, + d/(l > 0.5f).thenElse(2.0f - max - min, max + min)); + SkNf h = (max != r).thenElse(0.0f, + (g - b)*d_inv + (g < b).thenElse(6.0f, 0.0f)); + h = (max == g).thenElse((b - r)*d_inv + 2.0f, h); + h = (max == b).thenElse((r - g)*d_inv + 4.0f, h); + h *= (1/6.0f); + + h = (max == min).thenElse(0.0f, h); + + r = h; + g = s; + b = l; +} + +STAGE(hsl_to_rgb) { + auto h = r; + auto s = g; + auto l = b; + auto q = (l < 0.5f).thenElse(l*(1.0f + s), l + s - l*s); + auto p = 2.0f*l - q; + + auto hue_to_rgb = [](const SkNf& p, const SkNf& q, const SkNf& t) { + auto t2 = (t < 0.0f).thenElse(t + 1.0f, (t > 1.0f).thenElse(t - 1.0f, t)); + return (t2 < (1/6.0f)).thenElse( + p + (q - p)*6.0f*t, (t2 < (3/6.0f)).thenElse( + q, (t2 < (4/6.0f)).thenElse( + p + (q - p)*((4/6.0f) - t2)*6.0f, p))); + }; + + r = (s == 0.f).thenElse(l, hue_to_rgb(p, q, h + (1/3.0f))); + g = (s == 0.f).thenElse(l, hue_to_rgb(p, q, h)); + b = (s == 0.f).thenElse(l, hue_to_rgb(p, q, h - (1/3.0f))); +} + +STAGE_CTX(matrix_2x3, const float*) { + auto m = ctx; + + auto R = SkNf_fma(r,m[0], SkNf_fma(g,m[2], m[4])), + G = SkNf_fma(r,m[1], SkNf_fma(g,m[3], m[5])); + r = R; + g = G; +} +STAGE_CTX(matrix_3x4, const float*) { + auto m = ctx; + + auto R = SkNf_fma(r,m[0], SkNf_fma(g,m[3], SkNf_fma(b,m[6], m[ 9]))), + G = SkNf_fma(r,m[1], SkNf_fma(g,m[4], SkNf_fma(b,m[7], m[10]))), + B = SkNf_fma(r,m[2], SkNf_fma(g,m[5], SkNf_fma(b,m[8], m[11]))); + r = R; + g = G; + b = B; +} +STAGE_CTX(matrix_4x5, const float*) { + auto m = ctx; + + auto R = SkNf_fma(r,m[0], SkNf_fma(g,m[4], SkNf_fma(b,m[ 8], SkNf_fma(a,m[12], m[16])))), + G = SkNf_fma(r,m[1], SkNf_fma(g,m[5], SkNf_fma(b,m[ 9], SkNf_fma(a,m[13], m[17])))), + B = SkNf_fma(r,m[2], SkNf_fma(g,m[6], SkNf_fma(b,m[10], SkNf_fma(a,m[14], m[18])))), + A = SkNf_fma(r,m[3], SkNf_fma(g,m[7], SkNf_fma(b,m[11], SkNf_fma(a,m[15], m[19])))); + r = R; + g = G; + b = B; + a = A; +} +STAGE_CTX(matrix_perspective, const float*) { + // N.B. unlike the matrix_NxM stages, this takes a row-major matrix. + auto m = ctx; + + auto R = SkNf_fma(r,m[0], SkNf_fma(g,m[1], m[2])), + G = SkNf_fma(r,m[3], SkNf_fma(g,m[4], m[5])), + Z = SkNf_fma(r,m[6], SkNf_fma(g,m[7], m[8])); + r = R * Z.invert(); + g = G * Z.invert(); +} + +SI SkNf parametric(const SkNf& v, const SkColorSpaceTransferFn& p) { + float result[N]; // Unconstrained powf() doesn't vectorize well... + for (int i = 0; i < N; i++) { + float s = v[i]; + result[i] = (s <= p.fD) ? p.fC * s + p.fF + : powf(s * p.fA + p.fB, p.fG) + p.fE; + } + // Clamp the output to [0, 1]. + // Max(NaN, 0) = 0, but Max(0, NaN) = NaN, so we want this exact order to ensure NaN => 0 + return SkNf::Min(SkNf::Max(SkNf::Load(result), 0.0f), 1.0f); +} +STAGE_CTX(parametric_r, const SkColorSpaceTransferFn*) { r = parametric(r, *ctx); } +STAGE_CTX(parametric_g, const SkColorSpaceTransferFn*) { g = parametric(g, *ctx); } +STAGE_CTX(parametric_b, const SkColorSpaceTransferFn*) { b = parametric(b, *ctx); } +STAGE_CTX(parametric_a, const SkColorSpaceTransferFn*) { a = parametric(a, *ctx); } + +SI SkNf table(const SkNf& v, const SkTableTransferFn& table) { + float result[N]; + for (int i = 0; i < N; i++) { + result[i] = interp_lut(v[i], table.fData, table.fSize); + } + // no need to clamp - tables are by-design [0,1] -> [0,1] + return SkNf::Load(result); +} +STAGE_CTX(table_r, const SkTableTransferFn*) { r = table(r, *ctx); } +STAGE_CTX(table_g, const SkTableTransferFn*) { g = table(g, *ctx); } +STAGE_CTX(table_b, const SkTableTransferFn*) { b = table(b, *ctx); } +STAGE_CTX(table_a, const SkTableTransferFn*) { a = table(a, *ctx); } + +STAGE_CTX(color_lookup_table, const SkColorLookUpTable*) { + const SkColorLookUpTable* colorLUT = ctx; + SkASSERT(3 == colorLUT->inputChannels() || 4 == colorLUT->inputChannels()); + SkASSERT(3 == colorLUT->outputChannels()); + float result[3][N]; + for (int i = 0; i < N; ++i) { + const float in[4] = { r[i], g[i], b[i], a[i] }; + float out[3]; + colorLUT->interp(out, in); + for (int j = 0; j < colorLUT->outputChannels(); ++j) { + result[j][i] = out[j]; + } + } + r = SkNf::Load(result[0]); + g = SkNf::Load(result[1]); + b = SkNf::Load(result[2]); + if (4 == colorLUT->inputChannels()) { + // we must set the pixel to opaque, as the alpha channel was used + // as input before this. + a = 1.f; + } +} + +STAGE(lab_to_xyz) { + const auto lab_l = r * 100.0f; + const auto lab_a = g * 255.0f - 128.0f; + const auto lab_b = b * 255.0f - 128.0f; + auto Y = (lab_l + 16.0f) * (1/116.0f); + auto X = lab_a * (1/500.0f) + Y; + auto Z = Y - (lab_b * (1/200.0f)); + + const auto X3 = X*X*X; + X = (X3 > 0.008856f).thenElse(X3, (X - (16/116.0f)) * (1/7.787f)); + const auto Y3 = Y*Y*Y; + Y = (Y3 > 0.008856f).thenElse(Y3, (Y - (16/116.0f)) * (1/7.787f)); + const auto Z3 = Z*Z*Z; + Z = (Z3 > 0.008856f).thenElse(Z3, (Z - (16/116.0f)) * (1/7.787f)); + + // adjust to D50 illuminant + X *= 0.96422f; + Y *= 1.00000f; + Z *= 0.82521f; + + r = X; + g = Y; + b = Z; +} + +SI SkNf assert_in_tile(const SkNf& v, float limit) { + for (int i = 0; i < N; i++) { + SkASSERT(0 <= v[i] && v[i] < limit); + } + return v; +} + +SI SkNf ulp_before(float v) { + SkASSERT(v > 0); + SkNf vs(v); + SkNu uvs = SkNu::Load(&vs) - 1; + return SkNf::Load(&uvs); +} + +SI SkNf clamp(const SkNf& v, float limit) { + SkNf result = SkNf::Max(0, SkNf::Min(v, ulp_before(limit))); + return assert_in_tile(result, limit); +} +SI SkNf repeat(const SkNf& v, float limit) { + SkNf result = v - (v/limit).floor()*limit; + // For small negative v, (v/limit).floor()*limit can dominate v in the subtraction, + // which leaves result == limit. We want result < limit, so clamp it one ULP. + result = SkNf::Min(result, ulp_before(limit)); + return assert_in_tile(result, limit); +} +SI SkNf mirror(const SkNf& v, float l/*imit*/) { + SkNf result = ((v - l) - ((v - l) / (2*l)).floor()*(2*l) - l).abs(); + // Same deal as repeat. + result = SkNf::Min(result, ulp_before(l)); + return assert_in_tile(result, l); +} +STAGE_CTX( clamp_x, const float*) { r = clamp (r, *ctx); } +STAGE_CTX(repeat_x, const float*) { r = repeat(r, *ctx); } +STAGE_CTX(mirror_x, const float*) { r = mirror(r, *ctx); } +STAGE_CTX( clamp_y, const float*) { g = clamp (g, *ctx); } +STAGE_CTX(repeat_y, const float*) { g = repeat(g, *ctx); } +STAGE_CTX(mirror_y, const float*) { g = mirror(g, *ctx); } + +STAGE_CTX(save_xy, SkJumper_SamplerCtx*) { + r.store(ctx->x); + g.store(ctx->y); + + // Whether bilinear or bicubic, all sample points have the same fractional offset (fx,fy). + // They're either the 4 corners of a logical 1x1 pixel or the 16 corners of a 3x3 grid + // surrounding (x,y), all (0.5,0.5) off-center. + auto fract = [](const SkNf& v) { return v - v.floor(); }; + fract(r + 0.5f).store(ctx->fx); + fract(g + 0.5f).store(ctx->fy); +} + +STAGE_CTX(accumulate, const SkJumper_SamplerCtx*) { + // Bilinear and bicubic filtering are both separable, so we'll end up with independent + // scale contributions in x and y that we multiply together to get each pixel's scale factor. + auto scale = SkNf::Load(ctx->scalex) * SkNf::Load(ctx->scaley); + dr = SkNf_fma(scale, r, dr); + dg = SkNf_fma(scale, g, dg); + db = SkNf_fma(scale, b, db); + da = SkNf_fma(scale, a, da); +} + +// In bilinear interpolation, the 4 pixels at +/- 0.5 offsets from the sample pixel center +// are combined in direct proportion to their area overlapping that logical query pixel. +// At positive offsets, the x-axis contribution to that rectangular area is fx; (1-fx) +// at negative x offsets. The y-axis is treated symmetrically. +template +SI void bilinear_x(SkJumper_SamplerCtx* ctx, SkNf* x) { + *x = SkNf::Load(ctx->x) + Scale*0.5f; + auto fx = SkNf::Load(ctx->fx); + (Scale > 0 ? fx : (1.0f - fx)).store(ctx->scalex); +} +template +SI void bilinear_y(SkJumper_SamplerCtx* ctx, SkNf* y) { + *y = SkNf::Load(ctx->y) + Scale*0.5f; + auto fy = SkNf::Load(ctx->fy); + (Scale > 0 ? fy : (1.0f - fy)).store(ctx->scaley); +} +STAGE_CTX(bilinear_nx, SkJumper_SamplerCtx*) { bilinear_x<-1>(ctx, &r); } +STAGE_CTX(bilinear_px, SkJumper_SamplerCtx*) { bilinear_x<+1>(ctx, &r); } +STAGE_CTX(bilinear_ny, SkJumper_SamplerCtx*) { bilinear_y<-1>(ctx, &g); } +STAGE_CTX(bilinear_py, SkJumper_SamplerCtx*) { bilinear_y<+1>(ctx, &g); } + + +// In bilinear interpolation, the 16 pixels at +/- 0.5 and +/- 1.5 offsets from the sample +// pixel center are combined with a non-uniform cubic filter, with high filter values near +// the center and lower values farther away. +// +// We break this filter function into two parts, one for near +/- 0.5 offsets, +// and one for far +/- 1.5 offsets. +// +// See GrBicubicEffect for details about this particular Mitchell-Netravali filter. +SI SkNf bicubic_near(const SkNf& t) { + // 1/18 + 9/18t + 27/18t^2 - 21/18t^3 == t ( t ( -21/18t + 27/18) + 9/18) + 1/18 + return SkNf_fma(t, SkNf_fma(t, SkNf_fma(-21/18.0f, t, 27/18.0f), 9/18.0f), 1/18.0f); +} +SI SkNf bicubic_far(const SkNf& t) { + // 0/18 + 0/18*t - 6/18t^2 + 7/18t^3 == t^2 (7/18t - 6/18) + return (t*t)*SkNf_fma(7/18.0f, t, -6/18.0f); +} + +template +SI void bicubic_x(SkJumper_SamplerCtx* ctx, SkNf* x) { + *x = SkNf::Load(ctx->x) + Scale*0.5f; + auto fx = SkNf::Load(ctx->fx); + if (Scale == -3) { return bicubic_far (1.0f - fx).store(ctx->scalex); } + if (Scale == -1) { return bicubic_near(1.0f - fx).store(ctx->scalex); } + if (Scale == +1) { return bicubic_near( fx).store(ctx->scalex); } + if (Scale == +3) { return bicubic_far ( fx).store(ctx->scalex); } + SkDEBUGFAIL("unreachable"); +} +template +SI void bicubic_y(SkJumper_SamplerCtx* ctx, SkNf* y) { + *y = SkNf::Load(ctx->y) + Scale*0.5f; + auto fy = SkNf::Load(ctx->fy); + if (Scale == -3) { return bicubic_far (1.0f - fy).store(ctx->scaley); } + if (Scale == -1) { return bicubic_near(1.0f - fy).store(ctx->scaley); } + if (Scale == +1) { return bicubic_near( fy).store(ctx->scaley); } + if (Scale == +3) { return bicubic_far ( fy).store(ctx->scaley); } + SkDEBUGFAIL("unreachable"); +} +STAGE_CTX(bicubic_n3x, SkJumper_SamplerCtx*) { bicubic_x<-3>(ctx, &r); } +STAGE_CTX(bicubic_n1x, SkJumper_SamplerCtx*) { bicubic_x<-1>(ctx, &r); } +STAGE_CTX(bicubic_p1x, SkJumper_SamplerCtx*) { bicubic_x<+1>(ctx, &r); } +STAGE_CTX(bicubic_p3x, SkJumper_SamplerCtx*) { bicubic_x<+3>(ctx, &r); } + +STAGE_CTX(bicubic_n3y, SkJumper_SamplerCtx*) { bicubic_y<-3>(ctx, &g); } +STAGE_CTX(bicubic_n1y, SkJumper_SamplerCtx*) { bicubic_y<-1>(ctx, &g); } +STAGE_CTX(bicubic_p1y, SkJumper_SamplerCtx*) { bicubic_y<+1>(ctx, &g); } +STAGE_CTX(bicubic_p3y, SkJumper_SamplerCtx*) { bicubic_y<+3>(ctx, &g); } + + +template +SI SkNi offset_and_ptr(T** ptr, const SkJumper_GatherCtx* ctx, const SkNf& x, const SkNf& y) { + SkNi ix = SkNx_cast(x), + iy = SkNx_cast(y); + SkNi offset = iy*ctx->stride + ix; + + *ptr = (const T*)ctx->pixels; + return offset; +} + +STAGE_CTX(gather_a8, const SkJumper_GatherCtx*) { + const uint8_t* p; + SkNi offset = offset_and_ptr(&p, ctx, r, g); + + r = g = b = 0.0f; + a = SkNf_from_byte(gather(tail, p, offset)); +} +STAGE_CTX(gather_i8, const SkJumper_GatherCtx*) { + const uint8_t* p; + SkNi offset = offset_and_ptr(&p, ctx, r, g); + + SkNi ix = SkNx_cast(gather(tail, p, offset)); + from_8888(gather(tail, ctx->ctable, ix), &r, &g, &b, &a); +} +STAGE_CTX(gather_g8, const SkJumper_GatherCtx*) { + const uint8_t* p; + SkNi offset = offset_and_ptr(&p, ctx, r, g); + + r = g = b = SkNf_from_byte(gather(tail, p, offset)); + a = 1.0f; +} +STAGE_CTX(gather_565, const SkJumper_GatherCtx*) { + const uint16_t* p; + SkNi offset = offset_and_ptr(&p, ctx, r, g); + + from_565(gather(tail, p, offset), &r, &g, &b); + a = 1.0f; +} +STAGE_CTX(gather_4444, const SkJumper_GatherCtx*) { + const uint16_t* p; + SkNi offset = offset_and_ptr(&p, ctx, r, g); + + from_4444(gather(tail, p, offset), &r, &g, &b, &a); +} +STAGE_CTX(gather_8888, const SkJumper_GatherCtx*) { + const uint32_t* p; + SkNi offset = offset_and_ptr(&p, ctx, r, g); + + from_8888(gather(tail, p, offset), &r, &g, &b, &a); +} +STAGE_CTX(gather_f16, const SkJumper_GatherCtx*) { + const uint64_t* p; + SkNi offset = offset_and_ptr(&p, ctx, r, g); + + auto px = gather(tail, p, offset); + from_f16(&px, &r, &g, &b, &a); +} + +STAGE_CTX(linear_gradient, const SkPM4f*) { + struct Stop { float pos; float f[4], b[4]; }; + struct Ctx { size_t n; Stop *stops; float start[4]; }; + + auto c = (const Ctx*)ctx; + SkNf fr = 0, fg = 0, fb = 0, fa = 0; + SkNf br = c->start[0], + bg = c->start[1], + bb = c->start[2], + ba = c->start[3]; + auto t = r; + for (size_t i = 0; i < c->n; i++) { + fr = (t < c->stops[i].pos).thenElse(fr, c->stops[i].f[0]); + fg = (t < c->stops[i].pos).thenElse(fg, c->stops[i].f[1]); + fb = (t < c->stops[i].pos).thenElse(fb, c->stops[i].f[2]); + fa = (t < c->stops[i].pos).thenElse(fa, c->stops[i].f[3]); + br = (t < c->stops[i].pos).thenElse(br, c->stops[i].b[0]); + bg = (t < c->stops[i].pos).thenElse(bg, c->stops[i].b[1]); + bb = (t < c->stops[i].pos).thenElse(bb, c->stops[i].b[2]); + ba = (t < c->stops[i].pos).thenElse(ba, c->stops[i].b[3]); + } + + r = SkNf_fma(t, fr, br); + g = SkNf_fma(t, fg, bg); + b = SkNf_fma(t, fb, bb); + a = SkNf_fma(t, fa, ba); +} + +STAGE_CTX(linear_gradient_2stops, const SkPM4f*) { + auto t = r; + SkPM4f c0 = ctx[0], + dc = ctx[1]; + + r = SkNf_fma(t, dc.r(), c0.r()); + g = SkNf_fma(t, dc.g(), c0.g()); + b = SkNf_fma(t, dc.b(), c0.b()); + a = SkNf_fma(t, dc.a(), c0.a()); +} + +STAGE_CTX(byte_tables, const void*) { + struct Tables { const uint8_t *r, *g, *b, *a; }; + auto tables = (const Tables*)ctx; + + r = SkNf_from_byte(gather(tail, tables->r, SkNf_round(255.0f, r))); + g = SkNf_from_byte(gather(tail, tables->g, SkNf_round(255.0f, g))); + b = SkNf_from_byte(gather(tail, tables->b, SkNf_round(255.0f, b))); + a = SkNf_from_byte(gather(tail, tables->a, SkNf_round(255.0f, a))); +} + +STAGE_CTX(byte_tables_rgb, const void*) { + struct Tables { const uint8_t *r, *g, *b; int n; }; + auto tables = (const Tables*)ctx; + + float scale = tables->n - 1; + r = SkNf_from_byte(gather(tail, tables->r, SkNf_round(scale, r))); + g = SkNf_from_byte(gather(tail, tables->g, SkNf_round(scale, g))); + b = SkNf_from_byte(gather(tail, tables->b, SkNf_round(scale, b))); +} + +STAGE_CTX(shader_adapter, SkShader::Context*) { + SkPM4f buf[N]; + static_assert(sizeof(buf) == sizeof(r) + sizeof(g) + sizeof(b) + sizeof(a), ""); + ctx->shadeSpan4f(x, (int)g[0], buf, N); + SkNf::Load4(buf, &r, &g, &b, &a); +} + +SI Fn enum_to_Fn(SkRasterPipeline::StockStage st) { + switch (st) { + #define M(stage) case SkRasterPipeline::stage: return stage; + SK_RASTER_PIPELINE_STAGES(M) + #undef M + } + SkASSERT(false); + return just_return; +} + +namespace { + + static void build_program(void** program, const SkRasterPipeline::Stage* stages, int nstages) { + for (int i = 0; i < nstages; i++) { + *program++ = (void*)enum_to_Fn(stages[i].stage); + if (stages[i].ctx) { + *program++ = stages[i].ctx; + } + } + *program++ = (void*)just_return; + } + + static void run_program(void** program, size_t x, size_t n) { + SkNf u; // fastest to start uninitialized. + + auto start = (Fn)load_and_increment(&program); + while (n >= N) { + start(x*N, program, u,u,u,u, u,u,u,u); + x += N; + n -= N; + } + if (n) { + start(x*N+n, program, u,u,u,u, u,u,u,u); + } + } + + // Compiled manages its memory manually because it's not safe to use + // std::vector, SkTDArray, etc without setting us up for big ODR violations. + struct Compiled { + Compiled(const SkRasterPipeline::Stage* stages, int nstages) { + int slots = nstages + 1; // One extra for just_return. + for (int i = 0; i < nstages; i++) { + if (stages[i].ctx) { + slots++; + } + } + fProgram = (void**)sk_malloc_throw(slots * sizeof(void*)); + build_program(fProgram, stages, nstages); + } + ~Compiled() { sk_free(fProgram); } + + Compiled(const Compiled& o) { + int slots = 0; + while (o.fProgram[slots++] != (void*)just_return); + + fProgram = (void**)sk_malloc_throw(slots * sizeof(void*)); + memcpy(fProgram, o.fProgram, slots * sizeof(void*)); + } + + void operator()(size_t x, size_t n) { + run_program(fProgram, x, n); + } + + void** fProgram; + }; +} namespace SK_OPTS_NS { - // Clamp colors into [0,1] premul (e.g. just before storing back to memory). - static void clamp_01_premul(Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a) { - a = Sk4f::Max(a, 0.0f); - r = Sk4f::Max(r, 0.0f); - g = Sk4f::Max(g, 0.0f); - b = Sk4f::Max(b, 0.0f); - - a = Sk4f::Min(a, 1.0f); - r = Sk4f::Min(r, a); - g = Sk4f::Min(g, a); - b = Sk4f::Min(b, a); - } - - static Sk4f inv(const Sk4f& x) { return 1.0f - x; } - - static Sk4f lerp(const Sk4f& from, const Sk4f& to, const Sk4f& cov) { - return from + (to-from)*cov; - } - - template - static SkNx<4,T> load_tail(size_t tail, const T* src) { - if (tail) { - return SkNx<4,T>(src[0], (tail>1 ? src[1] : 0), (tail>2 ? src[2] : 0), 0); - } - return SkNx<4,T>::Load(src); - } - - template - static void store_tail(size_t tail, const SkNx<4,T>& v, T* dst) { - switch(tail) { - case 0: return v.store(dst); - case 3: dst[2] = v[2]; - case 2: dst[1] = v[1]; - case 1: dst[0] = v[0]; + SI void run_pipeline(size_t x, size_t n, + const SkRasterPipeline::Stage* stages, int nstages) { + static const int kStackMax = 256; + // Worst case is nstages stages with nstages context pointers, and just_return. + if (2*nstages+1 <= kStackMax) { + void* program[kStackMax]; + build_program(program, stages, nstages); + run_program(program, x,n); + } else { + Compiled{stages,nstages}(x,n); } } - static void from_565(const Sk4h& _565, Sk4f* r, Sk4f* g, Sk4f* b) { - Sk4i _32_bit = SkNx_cast(_565); +} // namespace SK_OPTS_NS - *r = SkNx_cast(_32_bit & SK_R16_MASK_IN_PLACE) * (1.0f / SK_R16_MASK_IN_PLACE); - *g = SkNx_cast(_32_bit & SK_G16_MASK_IN_PLACE) * (1.0f / SK_G16_MASK_IN_PLACE); - *b = SkNx_cast(_32_bit & SK_B16_MASK_IN_PLACE) * (1.0f / SK_B16_MASK_IN_PLACE); - } - - static Sk4h to_565(const Sk4f& r, const Sk4f& g, const Sk4f& b) { - return SkNx_cast( Sk4f_round(r * SK_R16_MASK) << SK_R16_SHIFT - | Sk4f_round(g * SK_G16_MASK) << SK_G16_SHIFT - | Sk4f_round(b * SK_B16_MASK) << SK_B16_SHIFT); - } - - - // The default shader produces a constant color (from the SkPaint). - KERNEL_Sk4f(constant_color) { - auto color = (const SkPM4f*)ctx; - r = color->r(); - g = color->g(); - b = color->b(); - a = color->a(); - } - - // s' = d(1-c) + sc, for a constant c. - KERNEL_Sk4f(lerp_constant_float) { - Sk4f c = *(const float*)ctx; - - r = lerp(dr, r, c); - g = lerp(dg, g, c); - b = lerp(db, b, c); - a = lerp(da, a, c); - } - - // s' = sc for 8-bit c. - KERNEL_Sk4f(scale_u8) { - auto ptr = (const uint8_t*)ctx + x; - - Sk4f c = SkNx_cast(load_tail(tail, ptr)) * (1/255.0f); - r = r*c; - g = g*c; - b = b*c; - a = a*c; - } - - // s' = d(1-c) + sc for 8-bit c. - KERNEL_Sk4f(lerp_u8) { - auto ptr = (const uint8_t*)ctx + x; - - Sk4f c = SkNx_cast(load_tail(tail, ptr)) * (1/255.0f); - r = lerp(dr, r, c); - g = lerp(dg, g, c); - b = lerp(db, b, c); - a = lerp(da, a, c); - } - - // s' = d(1-c) + sc for 565 c. - KERNEL_Sk4f(lerp_565) { - auto ptr = (const uint16_t*)ctx + x; - Sk4f cr, cg, cb; - from_565(load_tail(tail, ptr), &cr, &cg, &cb); - - r = lerp(dr, r, cr); - g = lerp(dg, g, cg); - b = lerp(db, b, cb); - a = 1.0f; - } - - KERNEL_Sk4f(load_d_565) { - auto ptr = (const uint16_t*)ctx + x; - from_565(load_tail(tail, ptr), &dr,&dg,&db); - da = 1.0f; - } - - KERNEL_Sk4f(load_s_565) { - auto ptr = (const uint16_t*)ctx + x; - from_565(load_tail(tail, ptr), &r,&g,&b); - a = 1.0f; - } - - KERNEL_Sk4f(store_565) { - clamp_01_premul(r,g,b,a); - auto ptr = (uint16_t*)ctx + x; - store_tail(tail, to_565(r,g,b), ptr); - } - - KERNEL_Sk4f(load_d_f16) { - auto ptr = (const uint64_t*)ctx + x; - - if (tail) { - auto p0 = SkHalfToFloat_finite_ftz(ptr[0]) , - p1 = tail>1 ? SkHalfToFloat_finite_ftz(ptr[1]) : Sk4f{0}, - p2 = tail>2 ? SkHalfToFloat_finite_ftz(ptr[2]) : Sk4f{0}; - dr = { p0[0],p1[0],p2[0],0 }; - dg = { p0[1],p1[1],p2[1],0 }; - db = { p0[2],p1[2],p2[2],0 }; - da = { p0[3],p1[3],p2[3],0 }; - return; - } - - Sk4h rh, gh, bh, ah; - Sk4h_load4(ptr, &rh, &gh, &bh, &ah); - dr = SkHalfToFloat_finite_ftz(rh); - dg = SkHalfToFloat_finite_ftz(gh); - db = SkHalfToFloat_finite_ftz(bh); - da = SkHalfToFloat_finite_ftz(ah); - } - - KERNEL_Sk4f(load_s_f16) { - auto ptr = (const uint64_t*)ctx + x; - - if (tail) { - auto p0 = SkHalfToFloat_finite_ftz(ptr[0]) , - p1 = tail>1 ? SkHalfToFloat_finite_ftz(ptr[1]) : Sk4f{0}, - p2 = tail>2 ? SkHalfToFloat_finite_ftz(ptr[2]) : Sk4f{0}; - r = { p0[0],p1[0],p2[0],0 }; - g = { p0[1],p1[1],p2[1],0 }; - b = { p0[2],p1[2],p2[2],0 }; - a = { p0[3],p1[3],p2[3],0 }; - return; - } - - Sk4h rh, gh, bh, ah; - Sk4h_load4(ptr, &rh, &gh, &bh, &ah); - r = SkHalfToFloat_finite_ftz(rh); - g = SkHalfToFloat_finite_ftz(gh); - b = SkHalfToFloat_finite_ftz(bh); - a = SkHalfToFloat_finite_ftz(ah); - } - - KERNEL_Sk4f(store_f16) { - clamp_01_premul(r,g,b,a); - auto ptr = (uint64_t*)ctx + x; - - switch (tail) { - case 0: return Sk4h_store4(ptr, SkFloatToHalf_finite_ftz(r), - SkFloatToHalf_finite_ftz(g), - SkFloatToHalf_finite_ftz(b), - SkFloatToHalf_finite_ftz(a)); - - case 3: SkFloatToHalf_finite_ftz({r[2], g[2], b[2], a[2]}).store(ptr+2); - case 2: SkFloatToHalf_finite_ftz({r[1], g[1], b[1], a[1]}).store(ptr+1); - case 1: SkFloatToHalf_finite_ftz({r[0], g[0], b[0], a[0]}).store(ptr+0); - } - } - - - // Load 8-bit SkPMColor-order sRGB. - KERNEL_Sk4f(load_d_srgb) { - auto ptr = (const uint32_t*)ctx + x; - - auto px = load_tail(tail, (const int*)ptr); - dr = sk_linear_from_srgb_math((px >> SK_R32_SHIFT) & 0xff); - dg = sk_linear_from_srgb_math((px >> SK_G32_SHIFT) & 0xff); - db = sk_linear_from_srgb_math((px >> SK_B32_SHIFT) & 0xff); - da = (1/255.0f)*SkNx_cast((px >> SK_A32_SHIFT) & 0xff); - } - - KERNEL_Sk4f(load_s_srgb) { - auto ptr = (const uint32_t*)ctx + x; - - auto px = load_tail(tail, (const int*)ptr); - r = sk_linear_from_srgb_math((px >> SK_R32_SHIFT) & 0xff); - g = sk_linear_from_srgb_math((px >> SK_G32_SHIFT) & 0xff); - b = sk_linear_from_srgb_math((px >> SK_B32_SHIFT) & 0xff); - a = (1/255.0f)*SkNx_cast((px >> SK_A32_SHIFT) & 0xff); - } - - KERNEL_Sk4f(store_srgb) { - clamp_01_premul(r,g,b,a); - auto ptr = (uint32_t*)ctx + x; - store_tail(tail, ( sk_linear_to_srgb_noclamp(r) << SK_R32_SHIFT - | sk_linear_to_srgb_noclamp(g) << SK_G32_SHIFT - | sk_linear_to_srgb_noclamp(b) << SK_B32_SHIFT - | Sk4f_round(255.0f * a) << SK_A32_SHIFT), (int*)ptr); - } - - RGBA_XFERMODE_Sk4f(clear) { return 0.0f; } - //RGBA_XFERMODE_Sk4f(src) { return s; } // This would be a no-op stage, so we just omit it. - RGBA_XFERMODE_Sk4f(dst) { return d; } - - RGBA_XFERMODE_Sk4f(srcatop) { return s*da + d*inv(sa); } - RGBA_XFERMODE_Sk4f(srcin) { return s * da; } - RGBA_XFERMODE_Sk4f(srcout) { return s * inv(da); } - RGBA_XFERMODE_Sk4f(srcover) { return s + inv(sa)*d; } - RGBA_XFERMODE_Sk4f(dstatop) { return srcatop_kernel(d,da,s,sa); } - RGBA_XFERMODE_Sk4f(dstin) { return srcin_kernel (d,da,s,sa); } - RGBA_XFERMODE_Sk4f(dstout) { return srcout_kernel (d,da,s,sa); } - RGBA_XFERMODE_Sk4f(dstover) { return srcover_kernel(d,da,s,sa); } - - RGBA_XFERMODE_Sk4f(modulate) { return s*d; } - RGBA_XFERMODE_Sk4f(multiply) { return s*inv(da) + d*inv(sa) + s*d; } - RGBA_XFERMODE_Sk4f(plus_) { return s + d; } - RGBA_XFERMODE_Sk4f(screen) { return s + d - s*d; } - RGBA_XFERMODE_Sk4f(xor_) { return s*inv(da) + d*inv(sa); } - - RGB_XFERMODE_Sk4f(colorburn) { - return (d == da ).thenElse(d + s*inv(da), - (s == 0.0f).thenElse(s + d*inv(sa), - sa*(da - Sk4f::Min(da, (da-d)*sa/s)) + s*inv(da) + d*inv(sa))); - } - RGB_XFERMODE_Sk4f(colordodge) { - return (d == 0.0f).thenElse(d + s*inv(da), - (s == sa ).thenElse(s + d*inv(sa), - sa*Sk4f::Min(da, (d*sa)/(sa - s)) + s*inv(da) + d*inv(sa))); - } - RGB_XFERMODE_Sk4f(darken) { return s + d - Sk4f::Max(s*da, d*sa); } - RGB_XFERMODE_Sk4f(difference) { return s + d - 2.0f*Sk4f::Min(s*da,d*sa); } - RGB_XFERMODE_Sk4f(exclusion) { return s + d - 2.0f*s*d; } - RGB_XFERMODE_Sk4f(hardlight) { - return s*inv(da) + d*inv(sa) - + (2.0f*s <= sa).thenElse(2.0f*s*d, sa*da - 2.0f*(da-d)*(sa-s)); - } - RGB_XFERMODE_Sk4f(lighten) { return s + d - Sk4f::Min(s*da, d*sa); } - RGB_XFERMODE_Sk4f(overlay) { return hardlight_kernel(d,da,s,sa); } - RGB_XFERMODE_Sk4f(softlight) { - Sk4f m = (da > 0.0f).thenElse(d / da, 0.0f), - s2 = 2.0f*s, - m4 = 4.0f*m; - - // The logic forks three ways: - // 1. dark src? - // 2. light src, dark dst? - // 3. light src, light dst? - Sk4f darkSrc = d*(sa + (s2 - sa)*(1.0f - m)), // Used in case 1. - darkDst = (m4*m4 + m4)*(m - 1.0f) + 7.0f*m, // Used in case 2. - liteDst = m.rsqrt().invert() - m, // Used in case 3. - liteSrc = d*sa + da*(s2 - sa) * (4.0f*d <= da).thenElse(darkDst, liteDst); // 2 or 3? - return s*inv(da) + d*inv(sa) + (s2 <= sa).thenElse(darkSrc, liteSrc); // 1 or (2 or 3)? - } -} - -#undef KERNEL_Sk4f -#undef RGB_XFERMODE_Sk4f -#undef RGB_XFERMODE_Sk4f +#undef SI +#undef STAGE +#undef STAGE_CTX +#undef RGBA_XFERMODE +#undef RGB_XFERMODE #endif//SkRasterPipeline_opts_DEFINED diff --git a/gfx/skia/skia/src/opts/SkTextureCompressor_opts.h b/gfx/skia/skia/src/opts/SkTextureCompressor_opts.h deleted file mode 100644 index 06ced38bdf0c..000000000000 --- a/gfx/skia/skia/src/opts/SkTextureCompressor_opts.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkTextureCompressor_opts_DEFINED -#define SkTextureCompressor_opts_DEFINED - -#include "SkOpts.h" - -namespace SK_OPTS_NS { - -#if defined(SK_ARM_HAS_NEON) - // Converts indices in each of the four bits of the register from - // 0, 1, 2, 3, 4, 5, 6, 7 - // to - // 3, 2, 1, 0, 4, 5, 6, 7 - // - // A more detailed explanation can be found in SkTextureCompressor::convert_indices - static inline uint8x16_t convert_indices(const uint8x16_t &x) { - static const int8x16_t kThree = { - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - }; - - static const int8x16_t kZero = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - - // Take top three bits - int8x16_t sx = vreinterpretq_s8_u8(x); - - // Negate ... - sx = vnegq_s8(sx); - - // Add three... - sx = vaddq_s8(sx, kThree); - - // Generate negatives mask - const int8x16_t mask = vreinterpretq_s8_u8(vcltq_s8(sx, kZero)); - - // Absolute value - sx = vabsq_s8(sx); - - // Add three to the values that were negative... - return vreinterpretq_u8_s8(vaddq_s8(sx, vandq_s8(mask, kThree))); - } - - template - static inline uint64x2_t shift_swap(const uint64x2_t &x, const uint64x2_t &mask) { - uint64x2_t t = vandq_u64(mask, veorq_u64(x, vshrq_n_u64(x, shift))); - return veorq_u64(x, veorq_u64(t, vshlq_n_u64(t, shift))); - } - - static inline uint64x2_t pack_indices(const uint64x2_t &x) { - // x: 00 a e 00 b f 00 c g 00 d h 00 i m 00 j n 00 k o 00 l p - - static const uint64x2_t kMask1 = { 0x3FC0003FC00000ULL, 0x3FC0003FC00000ULL }; - uint64x2_t ret = shift_swap<10>(x, kMask1); - - // x: b f 00 00 00 a e c g i m 00 00 00 d h j n 00 k o 00 l p - static const uint64x2_t kMask2 = { (0x3FULL << 52), (0x3FULL << 52) }; - static const uint64x2_t kMask3 = { (0x3FULL << 28), (0x3FULL << 28) }; - const uint64x2_t x1 = vandq_u64(vshlq_n_u64(ret, 52), kMask2); - const uint64x2_t x2 = vandq_u64(vshlq_n_u64(ret, 20), kMask3); - ret = vshrq_n_u64(vorrq_u64(ret, vorrq_u64(x1, x2)), 16); - - // x: 00 00 00 00 00 00 00 00 b f l p a e c g i m k o d h j n - - static const uint64x2_t kMask4 = { 0xFC0000ULL, 0xFC0000ULL }; - ret = shift_swap<6>(ret, kMask4); - - #if defined (SK_CPU_BENDIAN) - // x: 00 00 00 00 00 00 00 00 b f l p a e i m c g k o d h j n - - static const uint64x2_t kMask5 = { 0x3FULL, 0x3FULL }; - ret = shift_swap<36>(ret, kMask5); - - // x: 00 00 00 00 00 00 00 00 b f j n a e i m c g k o d h l p - - static const uint64x2_t kMask6 = { 0xFFF000000ULL, 0xFFF000000ULL }; - ret = shift_swap<12>(ret, kMask6); - #else - // x: 00 00 00 00 00 00 00 00 c g i m d h l p b f j n a e k o - - static const uint64x2_t kMask5 = { 0xFC0ULL, 0xFC0ULL }; - ret = shift_swap<36>(ret, kMask5); - - // x: 00 00 00 00 00 00 00 00 a e i m d h l p b f j n c g k o - - static const uint64x2_t kMask6 = { (0xFFFULL << 36), (0xFFFULL << 36) }; - static const uint64x2_t kMask7 = { 0xFFFFFFULL, 0xFFFFFFULL }; - static const uint64x2_t kMask8 = { 0xFFFULL, 0xFFFULL }; - const uint64x2_t y1 = vandq_u64(ret, kMask6); - const uint64x2_t y2 = vshlq_n_u64(vandq_u64(ret, kMask7), 12); - const uint64x2_t y3 = vandq_u64(vshrq_n_u64(ret, 24), kMask8); - ret = vorrq_u64(y1, vorrq_u64(y2, y3)); - #endif - - // x: 00 00 00 00 00 00 00 00 a e i m b f j n c g k o d h l p - - // Set the header - static const uint64x2_t kHeader = { 0x8490000000000000ULL, 0x8490000000000000ULL }; - return vorrq_u64(kHeader, ret); - } - - // Takes a row of alpha values and places the most significant three bits of each byte into - // the least significant bits of the same byte - static inline uint8x16_t make_index_row(const uint8x16_t &x) { - static const uint8x16_t kTopThreeMask = { - 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, - 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, - }; - return vshrq_n_u8(vandq_u8(x, kTopThreeMask), 5); - } - - // Returns true if all of the bits in x are 0. - static inline bool is_zero(uint8x16_t x) { - // First experiments say that this is way slower than just examining the lanes - // but it might need a little more investigation. - #if 0 - // This code path tests the system register for overflow. We trigger - // overflow by adding x to a register with all of its bits set. The - // first instruction sets the bits. - int reg; - asm ("VTST.8 %%q0, %q1, %q1\n" - "VQADD.u8 %q1, %%q0\n" - "VMRS %0, FPSCR\n" - : "=r"(reg) : "w"(vreinterpretq_f32_u8(x)) : "q0", "q1"); - - // Bit 21 corresponds to the overflow flag. - return reg & (0x1 << 21); - #else - const uint64x2_t cvt = vreinterpretq_u64_u8(x); - const uint64_t l1 = vgetq_lane_u64(cvt, 0); - return (l1 == 0) && (l1 == vgetq_lane_u64(cvt, 1)); - #endif - } - - #if defined (SK_CPU_BENDIAN) - static inline uint64x2_t fix_endianness(uint64x2_t x) { - return x; - } - #else - static inline uint64x2_t fix_endianness(uint64x2_t x) { - return vreinterpretq_u64_u8(vrev64q_u8(vreinterpretq_u8_u64(x))); - } - #endif - - static void compress_r11eac_blocks(uint8_t* dst, const uint8_t* src, size_t rowBytes) { - // Try to avoid switching between vector and non-vector ops... - const uint8_t *const src1 = src; - const uint8_t *const src2 = src + rowBytes; - const uint8_t *const src3 = src + 2*rowBytes; - const uint8_t *const src4 = src + 3*rowBytes; - uint8_t *const dst1 = dst; - uint8_t *const dst2 = dst + 16; - - const uint8x16_t alphaRow1 = vld1q_u8(src1); - const uint8x16_t alphaRow2 = vld1q_u8(src2); - const uint8x16_t alphaRow3 = vld1q_u8(src3); - const uint8x16_t alphaRow4 = vld1q_u8(src4); - - const uint8x16_t cmp12 = vceqq_u8(alphaRow1, alphaRow2); - const uint8x16_t cmp34 = vceqq_u8(alphaRow3, alphaRow4); - const uint8x16_t cmp13 = vceqq_u8(alphaRow1, alphaRow3); - - const uint8x16_t cmp = vandq_u8(vandq_u8(cmp12, cmp34), cmp13); - const uint8x16_t ncmp = vmvnq_u8(cmp); - const uint8x16_t nAlphaRow1 = vmvnq_u8(alphaRow1); - if (is_zero(ncmp)) { - if (is_zero(alphaRow1)) { - static const uint64x2_t kTransparent = { 0x0020000000002000ULL, - 0x0020000000002000ULL }; - vst1q_u8(dst1, vreinterpretq_u8_u64(kTransparent)); - vst1q_u8(dst2, vreinterpretq_u8_u64(kTransparent)); - return; - } else if (is_zero(nAlphaRow1)) { - vst1q_u8(dst1, cmp); - vst1q_u8(dst2, cmp); - return; - } - } - - const uint8x16_t indexRow1 = convert_indices(make_index_row(alphaRow1)); - const uint8x16_t indexRow2 = convert_indices(make_index_row(alphaRow2)); - const uint8x16_t indexRow3 = convert_indices(make_index_row(alphaRow3)); - const uint8x16_t indexRow4 = convert_indices(make_index_row(alphaRow4)); - - const uint64x2_t indexRow12 = vreinterpretq_u64_u8( - vorrq_u8(vshlq_n_u8(indexRow1, 3), indexRow2)); - const uint64x2_t indexRow34 = vreinterpretq_u64_u8( - vorrq_u8(vshlq_n_u8(indexRow3, 3), indexRow4)); - - const uint32x4x2_t blockIndices = vtrnq_u32(vreinterpretq_u32_u64(indexRow12), - vreinterpretq_u32_u64(indexRow34)); - const uint64x2_t blockIndicesLeft = vreinterpretq_u64_u32(vrev64q_u32(blockIndices.val[0])); - const uint64x2_t blockIndicesRight = vreinterpretq_u64_u32(vrev64q_u32(blockIndices.val[1])); - - const uint64x2_t indicesLeft = fix_endianness(pack_indices(blockIndicesLeft)); - const uint64x2_t indicesRight = fix_endianness(pack_indices(blockIndicesRight)); - - const uint64x2_t d1 = vcombine_u64(vget_low_u64(indicesLeft), vget_low_u64(indicesRight)); - const uint64x2_t d2 = vcombine_u64(vget_high_u64(indicesLeft), vget_high_u64(indicesRight)); - vst1q_u8(dst1, vreinterpretq_u8_u64(d1)); - vst1q_u8(dst2, vreinterpretq_u8_u64(d2)); - } - - static bool compress_a8_r11eac(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes) { - - // Since we're going to operate on 4 blocks at a time, the src width - // must be a multiple of 16. However, the height only needs to be a - // multiple of 4 - if (0 == width || 0 == height || (width % 16) != 0 || (height % 4) != 0) { - return false; - } - - const int blocksX = width >> 2; - const int blocksY = height >> 2; - - SkASSERT((blocksX % 4) == 0); - - for (int y = 0; y < blocksY; ++y) { - for (int x = 0; x < blocksX; x+=4) { - // Compress it - compress_r11eac_blocks(dst, src + 4*x, rowBytes); - dst += 32; - } - src += 4 * rowBytes; - } - return true; - } - - static SkOpts::TextureCompressor texture_compressor(SkColorType ct, - SkTextureCompressor::Format fmt) { - if (ct == kAlpha_8_SkColorType && fmt == SkTextureCompressor::kR11_EAC_Format) { - return compress_a8_r11eac; - } - return nullptr; - } - static bool fill_block_dimensions(SkTextureCompressor::Format fmt, int* x, int* y) { - if (fmt == SkTextureCompressor::kR11_EAC_Format) { - *x = 16; - *y = 4; - return true; - } - return false; - } - -#else - static SkOpts::TextureCompressor texture_compressor(SkColorType, SkTextureCompressor::Format) { - return nullptr; - } - static bool fill_block_dimensions(SkTextureCompressor::Format, int*, int*) { - return false; - } - -#endif - -} // namespace SK_OPTS_NS - -#endif//SkTextureCompressor_opts_DEFINED diff --git a/gfx/skia/skia/src/opts/SkXfermode_opts.h b/gfx/skia/skia/src/opts/SkXfermode_opts.h index 54f906e4f6c6..81e5bb9f30b2 100644 --- a/gfx/skia/skia/src/opts/SkXfermode_opts.h +++ b/gfx/skia/skia/src/opts/SkXfermode_opts.h @@ -217,7 +217,7 @@ template <> void mark_dst_initialized_if_safe(void* dst, void* end) { template class Sk4pxXfermode : public SkProcCoeffXfermode { public: - Sk4pxXfermode(const ProcCoeff& rec, SkXfermode::Mode mode) + Sk4pxXfermode(const ProcCoeff& rec, SkBlendMode mode) : INHERITED(rec, mode) {} void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override { @@ -269,7 +269,7 @@ private: template class Sk4fXfermode : public SkProcCoeffXfermode { public: - Sk4fXfermode(const ProcCoeff& rec, SkXfermode::Mode mode) + Sk4fXfermode(const ProcCoeff& rec, SkBlendMode mode) : INHERITED(rec, mode) {} void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override { @@ -315,10 +315,10 @@ private: namespace SK_OPTS_NS { -static SkXfermode* create_xfermode(const ProcCoeff& rec, SkXfermode::Mode mode) { +static SkXfermode* create_xfermode(const ProcCoeff& rec, SkBlendMode mode) { switch (mode) { #define CASE(Xfermode) \ - case SkXfermode::k##Xfermode##_Mode: return new Sk4pxXfermode(rec, mode) + case SkBlendMode::k##Xfermode: return new Sk4pxXfermode(rec, mode) CASE(Clear); CASE(Src); CASE(Dst); @@ -344,7 +344,7 @@ static SkXfermode* create_xfermode(const ProcCoeff& rec, SkXfermode::Mode mode) #undef CASE #define CASE(Xfermode) \ - case SkXfermode::k##Xfermode##_Mode: return new Sk4fXfermode(rec, mode) + case SkBlendMode::k##Xfermode: return new Sk4fXfermode(rec, mode) CASE(ColorDodge); CASE(ColorBurn); CASE(SoftLight); diff --git a/gfx/skia/skia/src/opts/opts_check_x86.cpp b/gfx/skia/skia/src/opts/opts_check_x86.cpp index a8003a3b0e38..4b8c8a118bc8 100644 --- a/gfx/skia/skia/src/opts/opts_check_x86.cpp +++ b/gfx/skia/skia/src/opts/opts_check_x86.cpp @@ -5,7 +5,6 @@ * found in the LICENSE file. */ -#include "SkBitmapFilter_opts_SSE2.h" #include "SkBitmapProcState_opts_SSE2.h" #include "SkBitmapProcState_opts_SSSE3.h" #include "SkBitmapScaler.h" @@ -35,18 +34,6 @@ //////////////////////////////////////////////////////////////////////////////// -void SkBitmapScaler::PlatformConvolutionProcs(SkConvolutionProcs* procs) { - if (SkCpu::Supports(SkCpu::SSE2)) { - procs->fExtraHorizontalReads = 3; - procs->fConvolveVertically = &convolveVertically_SSE2; - procs->fConvolve4RowsHorizontally = &convolve4RowsHorizontally_SSE2; - procs->fConvolveHorizontally = &convolveHorizontally_SSE2; - procs->fApplySIMDPadding = &applySIMDPadding_SSE2; - } -} - -//////////////////////////////////////////////////////////////////////////////// - void SkBitmapProcState::platformProcs() { /* Every optimization in the function requires at least SSE2 */ if (!SkCpu::Supports(SkCpu::SSE2)) { diff --git a/gfx/skia/skia/src/pathops/SkAddIntersections.cpp b/gfx/skia/skia/src/pathops/SkAddIntersections.cpp index b3a82cdeca83..b47e7df5993c 100644 --- a/gfx/skia/skia/src/pathops/SkAddIntersections.cpp +++ b/gfx/skia/skia/src/pathops/SkAddIntersections.cpp @@ -450,8 +450,10 @@ bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coinc } case SkIntersectionHelper::kCubic_Segment: { swap = true; - pts = ts.intersect(cubic2.set(wn.pts()), - conic1.set(wt.pts(), wt.weight())); + pts = ts.intersect(cubic2.set(wn.pts() + SkDEBUGPARAMS(ts.globalState())), + conic1.set(wt.pts(), wt.weight() + SkDEBUGPARAMS(ts.globalState()))); debugShowCubicConicIntersection(pts, wn, wt, ts); break; } @@ -479,8 +481,10 @@ bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coinc break; } case SkIntersectionHelper::kConic_Segment: { - pts = ts.intersect(cubic1.set(wt.pts()), - conic2.set(wn.pts(), wn.weight())); + pts = ts.intersect(cubic1.set(wt.pts() + SkDEBUGPARAMS(ts.globalState())), + conic2.set(wn.pts(), wn.weight() + SkDEBUGPARAMS(ts.globalState()))); debugShowCubicConicIntersection(pts, wt, wn, ts); break; } @@ -557,7 +561,7 @@ bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coinc wn.segment()->debugValidate(); coinIndex = -1; } - SkASSERT(coinIndex < 0); // expect coincidence to be paired + SkOPOBJASSERT(coincidence, coinIndex < 0); // expect coincidence to be paired } while (wn.advance()); } while (wt.advance()); return true; diff --git a/gfx/skia/skia/src/pathops/SkDConicLineIntersection.cpp b/gfx/skia/skia/src/pathops/SkDConicLineIntersection.cpp index eb32068d0e61..102a4c3c9031 100644 --- a/gfx/skia/skia/src/pathops/SkDConicLineIntersection.cpp +++ b/gfx/skia/skia/src/pathops/SkDConicLineIntersection.cpp @@ -105,8 +105,8 @@ public: double conicT = rootVals[index]; double lineT = this->findLineT(conicT); #ifdef SK_DEBUG - if (!fIntersections->debugGlobalState() - || !fIntersections->debugGlobalState()->debugSkipAssert()) { + if (!fIntersections->globalState() + || !fIntersections->globalState()->debugSkipAssert()) { SkDEBUGCODE(SkDPoint conicPt = fConic.ptAtT(conicT)); SkDEBUGCODE(SkDPoint linePt = fLine->ptAtT(lineT)); SkASSERT(conicPt.approximatelyDEqual(linePt)); diff --git a/gfx/skia/skia/src/pathops/SkDCubicLineIntersection.cpp b/gfx/skia/skia/src/pathops/SkDCubicLineIntersection.cpp index fd060de6468f..ceedce18e938 100644 --- a/gfx/skia/skia/src/pathops/SkDCubicLineIntersection.cpp +++ b/gfx/skia/skia/src/pathops/SkDCubicLineIntersection.cpp @@ -122,6 +122,7 @@ public: double adj = fLine[1].fX - fLine[0].fX; double opp = fLine[1].fY - fLine[0].fY; SkDCubic c; + SkDEBUGCODE(c.fDebugGlobalState = fIntersections->globalState()); for (int n = 0; n < 4; ++n) { c[n].fX = (fCubic[n].fY - fLine[0].fY) * adj - (fCubic[n].fX - fLine[0].fX) * opp; } diff --git a/gfx/skia/skia/src/pathops/SkDLineIntersection.cpp b/gfx/skia/skia/src/pathops/SkDLineIntersection.cpp index 71e2a064d5c9..082e2987b9b7 100644 --- a/gfx/skia/skia/src/pathops/SkDLineIntersection.cpp +++ b/gfx/skia/skia/src/pathops/SkDLineIntersection.cpp @@ -152,7 +152,7 @@ int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) { continue; } SkASSERT(a[iA] != b[nearer]); - SkASSERT(iA == (bNearA[nearer] > 0.5)); + SkOPASSERT(iA == (bNearA[nearer] > 0.5)); insertNear(iA, nearer, a[iA], b[nearer]); aNearB[iA] = -1; bNearA[nearer] = -1; diff --git a/gfx/skia/skia/src/pathops/SkIntersections.cpp b/gfx/skia/skia/src/pathops/SkIntersections.cpp index 9683796a5b52..f17e5dbc3840 100644 --- a/gfx/skia/skia/src/pathops/SkIntersections.cpp +++ b/gfx/skia/skia/src/pathops/SkIntersections.cpp @@ -67,7 +67,7 @@ int SkIntersections::insert(double one, double two, const SkDPoint& pt) { } } if (fUsed >= fMax) { - SkASSERT(0); // FIXME : this error, if it is to be handled at runtime in release, must + SkOPASSERT(0); // FIXME : this error, if it is to be handled at runtime in release, must // be propagated all the way back down to the caller, and return failure. fUsed = 0; return 0; @@ -82,8 +82,12 @@ int SkIntersections::insert(double one, double two, const SkDPoint& pt) { fIsCoincident[1] += fIsCoincident[1] & clearMask; } fPt[index] = pt; - SkASSERT(one >= 0 && one <= 1); - SkASSERT(two >= 0 && two <= 1); + if (one < 0 || one > 1) { + return -1; + } + if (two < 0 || two > 1) { + return -1; + } fT[0][index] = one; fT[1][index] = two; ++fUsed; diff --git a/gfx/skia/skia/src/pathops/SkIntersections.h b/gfx/skia/skia/src/pathops/SkIntersections.h index abc10e19dd4b..d5d217cc8017 100644 --- a/gfx/skia/skia/src/pathops/SkIntersections.h +++ b/gfx/skia/skia/src/pathops/SkIntersections.h @@ -104,7 +104,7 @@ public: } #ifdef SK_DEBUG - SkOpGlobalState* debugGlobalState() { return fDebugGlobalState; } + SkOpGlobalState* globalState() const { return fDebugGlobalState; } #endif bool hasT(double t) const { @@ -308,9 +308,9 @@ private: void cleanUpParallelLines(bool parallel); void computePoints(const SkDLine& line, int used); - SkDPoint fPt[12]; // FIXME: since scans store points as SkPoint, this should also + SkDPoint fPt[13]; // FIXME: since scans store points as SkPoint, this should also SkDPoint fPt2[2]; // used by nearly same to store alternate intersection point - double fT[2][12]; + double fT[2][13]; uint16_t fIsCoincident[2]; // bit set for each curve's coincident T bool fNearlySame[2]; // true if end points nearly match unsigned char fUsed; diff --git a/gfx/skia/skia/src/pathops/SkOpAngle.cpp b/gfx/skia/skia/src/pathops/SkOpAngle.cpp index 820b5dceeef8..c07e8cc73f05 100644 --- a/gfx/skia/skia/src/pathops/SkOpAngle.cpp +++ b/gfx/skia/skia/src/pathops/SkOpAngle.cpp @@ -140,6 +140,8 @@ bool SkOpAngle::after(SkOpAngle* test) { int trGap = (rh->fSectorStart - fSectorStart + 32) & 0x1f; trOrder = trGap > 20 ? 0 : trGap > 11 ? -1 : 1; } + this->alignmentSameSide(lh, <Order); + this->alignmentSameSide(rh, &trOrder); if (lrOrder >= 0 && ltOrder >= 0 && trOrder >= 0) { return COMPARE_RESULT(7, lrOrder ? (ltOrder & trOrder) : (ltOrder | trOrder)); } @@ -152,7 +154,7 @@ bool SkOpAngle::after(SkOpAngle* test) { // FIXME : once this is verified to work, remove one opposite angle call SkDEBUGCODE(bool lrOpposite = lh->oppositePlanes(rh)); bool ltOpposite = lh->oppositePlanes(this); - SkASSERT(lrOpposite != ltOpposite); + SkOPASSERT(lrOpposite != ltOpposite); return COMPARE_RESULT(8, ltOpposite); } else if (ltOrder == 1 && trOrder == 0) { SkASSERT(lrOrder < 0); @@ -160,9 +162,9 @@ bool SkOpAngle::after(SkOpAngle* test) { return COMPARE_RESULT(9, trOpposite); } else if (lrOrder == 1 && trOrder == 1) { SkASSERT(ltOrder < 0); - SkDEBUGCODE(bool trOpposite = oppositePlanes(rh)); +// SkDEBUGCODE(bool trOpposite = oppositePlanes(rh)); bool lrOpposite = lh->oppositePlanes(rh); - SkASSERT(lrOpposite != trOpposite); +// SkASSERT(lrOpposite != trOpposite); return COMPARE_RESULT(10, lrOpposite); } if (lrOrder < 0) { @@ -212,6 +214,40 @@ int SkOpAngle::allOnOneSide(const SkOpAngle* test) { return -1; } +// To sort the angles, all curves are translated to have the same starting point. +// If the curve's control point in its original position is on one side of a compared line, +// and translated is on the opposite side, reverse the previously computed order. +void SkOpAngle::alignmentSameSide(const SkOpAngle* test, int* order) const { + if (*order < 0) { + return; + } + if (fPart.isCurve()) { + // This should support all curve types, but only bug that requires this has lines + // Turning on for curves causes existing tests to fail + return; + } + if (test->fPart.isCurve()) { + return; + } + const SkDPoint& xOrigin = test->fPart.fCurve.fLine[0]; + const SkDPoint& oOrigin = test->fOriginalCurvePart.fLine[0]; + if (xOrigin == oOrigin) { + return; + } + int iMax = SkPathOpsVerbToPoints(this->segment()->verb()); + SkDVector xLine = test->fPart.fCurve.fLine[1] - xOrigin; + SkDVector oLine = test->fOriginalCurvePart.fLine[1] - oOrigin; + for (int index = 1; index <= iMax; ++index) { + const SkDPoint& testPt = fPart.fCurve[index]; + double xCross = oLine.crossCheck(testPt - xOrigin); + double oCross = xLine.crossCheck(testPt - oOrigin); + if (oCross * xCross < 0) { + *order ^= 1; + break; + } + } +} + bool SkOpAngle::checkCrossesZero() const { int start = SkTMin(fSectorStart, fSectorEnd); int end = SkTMax(fSectorStart, fSectorEnd); @@ -320,7 +356,7 @@ recomputeSector: return !fUnorderable; } -int SkOpAngle::convexHullOverlaps(const SkOpAngle* rh) const { +int SkOpAngle::convexHullOverlaps(const SkOpAngle* rh) { const SkDVector* sweep = this->fPart.fSweep; const SkDVector* tweep = rh->fPart.fSweep; double s0xs1 = sweep[0].crossCheck(sweep[1]); @@ -593,20 +629,20 @@ SkOpGlobalState* SkOpAngle::globalState() const { // OPTIMIZE: if this loops to only one other angle, after first compare fails, insert on other side // OPTIMIZE: return where insertion succeeded. Then, start next insertion on opposite side -void SkOpAngle::insert(SkOpAngle* angle) { +bool SkOpAngle::insert(SkOpAngle* angle) { if (angle->fNext) { if (loopCount() >= angle->loopCount()) { if (!merge(angle)) { - return; + return true; } } else if (fNext) { if (!angle->merge(this)) { - return; + return true; } } else { angle->insert(this); } - return; + return true; } bool singleton = nullptr == fNext; if (singleton) { @@ -622,20 +658,27 @@ void SkOpAngle::insert(SkOpAngle* angle) { angle->fNext = this; } debugValidateNext(); - return; + return true; } SkOpAngle* last = this; + bool flipAmbiguity = false; do { SkASSERT(last->fNext == next); - if (angle->after(last)) { + if (angle->after(last) ^ (angle->tangentsAmbiguous() & flipAmbiguity)) { last->fNext = angle; angle->fNext = next; debugValidateNext(); - return; + return true; } last = next; + if (last == this) { + FAIL_IF(flipAmbiguity); + // We're in a loop. If a sort was ambiguous, flip it to end the loop. + flipAmbiguity = true; + } next = next->fNext; } while (true); + return true; } SkOpSpanBase* SkOpAngle::lastMarked() const { @@ -815,7 +858,7 @@ void SkOpAngle::set(SkOpSpanBase* start, SkOpSpanBase* end) { fComputedEnd = fEnd = end; SkASSERT(start != end); fNext = nullptr; - fComputeSector = fComputedSector = fCheckCoincidence = false; + fComputeSector = fComputedSector = fCheckCoincidence = fTangentsAmbiguous = false; setSpans(); setSector(); SkDEBUGCODE(fID = start ? start->globalState()->nextAngleID() : -1); @@ -966,7 +1009,7 @@ SkOpSpan* SkOpAngle::starter() { return fStart->starter(fEnd); } -bool SkOpAngle::tangentsDiverge(const SkOpAngle* rh, double s0xt0) const { +bool SkOpAngle::tangentsDiverge(const SkOpAngle* rh, double s0xt0) { if (s0xt0 == 0) { return false; } @@ -991,5 +1034,6 @@ bool SkOpAngle::tangentsDiverge(const SkOpAngle* rh, double s0xt0) const { double tDist = tweep[0].length() * m; bool useS = fabs(sDist) < fabs(tDist); double mFactor = fabs(useS ? this->distEndRatio(sDist) : rh->distEndRatio(tDist)); + fTangentsAmbiguous = mFactor >= 50 && mFactor < 200; return mFactor < 50; // empirically found limit } diff --git a/gfx/skia/skia/src/pathops/SkOpAngle.h b/gfx/skia/skia/src/pathops/SkOpAngle.h index cbdadf10398c..d8615c322944 100644 --- a/gfx/skia/skia/src/pathops/SkOpAngle.h +++ b/gfx/skia/skia/src/pathops/SkOpAngle.h @@ -64,7 +64,7 @@ public: return fEnd; } - void insert(SkOpAngle* ); + bool insert(SkOpAngle* ); SkOpSpanBase* lastMarked() const; bool loopContains(const SkOpAngle* ) const; int loopCount() const; @@ -87,17 +87,22 @@ public: SkOpSpan* starter(); + bool tangentsAmbiguous() const { + return fTangentsAmbiguous; + } + bool unorderable() const { return fUnorderable; } private: bool after(SkOpAngle* test); + void alignmentSameSide(const SkOpAngle* test, int* order) const; int allOnOneSide(const SkOpAngle* test); bool checkCrossesZero() const; bool checkParallel(SkOpAngle* ); bool computeSector(); - int convexHullOverlaps(const SkOpAngle* ) const; + int convexHullOverlaps(const SkOpAngle* ); bool endToSide(const SkOpAngle* rh, bool* inside) const; bool endsIntersect(SkOpAngle* ); int findSector(SkPath::Verb verb, double x, double y) const; @@ -109,7 +114,7 @@ private: bool orderable(SkOpAngle* rh); // false == this < rh ; true == this > rh void setSector(); void setSpans(); - bool tangentsDiverge(const SkOpAngle* rh, double s0xt0) const; + bool tangentsDiverge(const SkOpAngle* rh, double s0xt0); SkDCurve fOriginalCurvePart; // the curve from start to end SkDCurveSweep fPart; // the curve from start to end offset as needed @@ -127,6 +132,7 @@ private: bool fComputeSector; bool fComputedSector; bool fCheckCoincidence; + bool fTangentsAmbiguous; SkDEBUGCODE(int fID); friend class PathOpsAngleTester; diff --git a/gfx/skia/skia/src/pathops/SkOpBuilder.cpp b/gfx/skia/skia/src/pathops/SkOpBuilder.cpp index 011d6a6aba0f..c4eb0a91b589 100644 --- a/gfx/skia/skia/src/pathops/SkOpBuilder.cpp +++ b/gfx/skia/skia/src/pathops/SkOpBuilder.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkMatrix.h" #include "SkOpEdgeBuilder.h" #include "SkPathPriv.h" @@ -12,10 +13,10 @@ #include "SkPathOpsCommon.h" static bool one_contour(const SkPath& path) { - SkChunkAlloc allocator(256); + char storage[256]; + SkArenaAlloc allocator(storage); int verbCount = path.countVerbs(); - uint8_t* verbs = (uint8_t*) allocator.alloc(sizeof(uint8_t) * verbCount, - SkChunkAlloc::kThrow_AllocFailType); + uint8_t* verbs = (uint8_t*) allocator.makeArrayDefault(verbCount); (void) path.getVerbs(verbs, verbCount); for (int index = 1; index < verbCount; ++index) { if (verbs[index] == SkPath::kMove_Verb) { @@ -25,7 +26,17 @@ static bool one_contour(const SkPath& path) { return true; } -bool FixWinding(SkPath* path) { +void SkOpBuilder::ReversePath(SkPath* path) { + SkPath temp; + SkPoint lastPt; + SkAssertResult(path->getLastPt(&lastPt)); + temp.moveTo(lastPt); + temp.reversePathTo(*path); + temp.close(); + *path = temp; +} + +bool SkOpBuilder::FixWinding(SkPath* path) { SkPath::FillType fillType = path->getFillType(); if (fillType == SkPath::kInverseEvenOdd_FillType) { fillType = SkPath::kInverseWinding_FillType; @@ -35,14 +46,13 @@ bool FixWinding(SkPath* path) { SkPathPriv::FirstDirection dir; if (one_contour(*path) && SkPathPriv::CheapComputeFirstDirection(*path, &dir)) { if (dir != SkPathPriv::kCCW_FirstDirection) { - SkPath temp; - temp.reverseAddPath(*path); - *path = temp; + ReversePath(path); } path->setFillType(fillType); return true; } - SkChunkAlloc allocator(4096); + char storage[4096]; + SkArenaAlloc allocator(storage); SkOpContourHead contourHead; SkOpGlobalState globalState(&contourHead, &allocator SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr)); @@ -84,6 +94,9 @@ bool FixWinding(SkPath* path) { SkPathWriter woundPath(empty); SkOpContour* test = &contourHead; do { + if (!test->count()) { + continue; + } if (test->reversed()) { test->toReversePath(&woundPath); } else { @@ -133,9 +146,7 @@ bool SkOpBuilder::resolve(SkPath* result) { if (firstDir == SkPathPriv::kUnknown_FirstDirection) { firstDir = dir; } else if (firstDir != dir) { - SkPath temp; - temp.reverseAddPath(*test); - *test = temp; + ReversePath(test); } continue; } diff --git a/gfx/skia/skia/src/pathops/SkOpCoincidence.cpp b/gfx/skia/skia/src/pathops/SkOpCoincidence.cpp index f0481ab242a6..93a6d66faddb 100644 --- a/gfx/skia/skia/src/pathops/SkOpCoincidence.cpp +++ b/gfx/skia/skia/src/pathops/SkOpCoincidence.cpp @@ -16,6 +16,16 @@ bool SkCoincidentSpans::collapsed(const SkOpPtT* test) const { || (fOppPtTEnd == test && fOppPtTStart->contains(test)); } +// out of line since this function is referenced by address +const SkOpPtT* SkCoincidentSpans::coinPtTEnd() const { + return fCoinPtTEnd; +} + +// out of line since this function is referenced by address +const SkOpPtT* SkCoincidentSpans::coinPtTStart() const { + return fCoinPtTStart; +} + // sets the span's end to the ptT referenced by the previous-next void SkCoincidentSpans::correctOneEnd( const SkOpPtT* (SkCoincidentSpans::* getEnd)() const, @@ -125,14 +135,25 @@ bool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const { } } +// out of line since this function is referenced by address +const SkOpPtT* SkCoincidentSpans::oppPtTStart() const { + return fOppPtTStart; +} + +// out of line since this function is referenced by address +const SkOpPtT* SkCoincidentSpans::oppPtTEnd() const { + return fOppPtTEnd; +} + // A coincident span is unordered if the pairs of points in the main and opposite curves' // t values do not ascend or descend. For instance, if a tightly arced quadratic is // coincident with another curve, it may intersect it out of order. -bool SkCoincidentSpans::ordered() const { +bool SkCoincidentSpans::ordered(bool* result) const { const SkOpSpanBase* start = this->coinPtTStart()->span(); const SkOpSpanBase* end = this->coinPtTEnd()->span(); const SkOpSpanBase* next = start->upCast()->next(); if (next == end) { + *result = true; return true; } bool flipped = this->flipped(); @@ -141,21 +162,24 @@ bool SkCoincidentSpans::ordered() const { do { const SkOpPtT* opp = next->contains(oppSeg); if (!opp) { - SkASSERT(0); // may assert if coincident span isn't fully processed - continue; +// SkOPOBJASSERT(start, 0); // may assert if coincident span isn't fully processed + return false; } if ((oppLastT > opp->fT) != flipped) { - return false; + *result = false; + return true; } oppLastT = opp->fT; if (next == end) { break; } if (!next->upCastable()) { - return false; + *result = false; + return true; } next = next->upCast()->next(); } while (true); + *result = true; return true; } @@ -234,8 +258,8 @@ void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* o coinPtTEnd = coinPtTEnd->span()->ptT(); oppPtTStart = oppPtTStart->span()->ptT(); oppPtTEnd = oppPtTEnd->span()->ptT(); - SkASSERT(coinPtTStart->fT < coinPtTEnd->fT); - SkASSERT(oppPtTStart->fT != oppPtTEnd->fT); + SkOPASSERT(coinPtTStart->fT < coinPtTEnd->fT); + SkOPASSERT(oppPtTStart->fT != oppPtTEnd->fT); SkOPASSERT(!coinPtTStart->deleted()); SkOPASSERT(!coinPtTEnd->deleted()); SkOPASSERT(!oppPtTStart->deleted()); @@ -254,7 +278,11 @@ bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* const SkOpPtT* testPtT = testSpan->ptT(); const SkOpPtT* stopPtT = testPtT; const SkOpSegment* baseSeg = base->segment(); + int escapeHatch = 100000; // this is 100 times larger than the debugLoopLimit test while ((testPtT = testPtT->next()) != stopPtT) { + if (--escapeHatch <= 0) { + return false; // if triggered (likely by a fuzz-generated test) too complex to succeed + } const SkOpSegment* testSeg = testPtT->segment(); if (testPtT->deleted()) { continue; @@ -272,7 +300,7 @@ bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* SkDVector dxdy = baseSeg->dSlopeAtT(base->t()); const SkPoint& pt = base->pt(); SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}}; - SkIntersections i; + SkIntersections i SkDEBUGCODE((this->globalState())); (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i); for (int index = 0; index < i.used(); ++index) { double t = i[0][index]; @@ -477,7 +505,12 @@ bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { } if (oTest != oEnd) { oPriorT = oTest->t(); - oTest = coin->flipped() ? oTest->prev() : oTest->upCast()->next(); + if (coin->flipped()) { + oTest = oTest->prev(); + } else { + FAIL_IF(!oTest->upCastable()); + oTest = oTest->upCast()->next(); + } FAIL_IF(!oTest); } @@ -754,7 +787,7 @@ bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) { // save head so that walker can iterate over old data unperturbed // addifmissing adds to head freely then add saved head in the end const SkOpPtT* ocs = outer->coinPtTStart(); - SkASSERT(!ocs->deleted()); + FAIL_IF(ocs->deleted()); const SkOpSegment* outerCoin = ocs->segment(); SkASSERT(!outerCoin->done()); // if it's done, should have already been removed from list const SkOpPtT* oos = outer->oppPtTStart(); @@ -762,7 +795,7 @@ bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) { return true; } const SkOpSegment* outerOpp = oos->segment(); - SkASSERT(!outerOpp->done()); + SkOPASSERT(!outerOpp->done()); SkOpSegment* outerCoinWritable = const_cast(outerCoin); SkOpSegment* outerOppWritable = const_cast(outerOpp); SkCoincidentSpans* inner = outer; @@ -770,13 +803,13 @@ bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) { this->debugValidate(); double overS, overE; const SkOpPtT* ics = inner->coinPtTStart(); - SkASSERT(!ics->deleted()); + FAIL_IF(ics->deleted()); const SkOpSegment* innerCoin = ics->segment(); - SkASSERT(!innerCoin->done()); + FAIL_IF(innerCoin->done()); const SkOpPtT* ios = inner->oppPtTStart(); - SkASSERT(!ios->deleted()); + FAIL_IF(ios->deleted()); const SkOpSegment* innerOpp = ios->segment(); - SkASSERT(!innerOpp->done()); + SkOPASSERT(!innerOpp->done()); SkOpSegment* innerCoinWritable = const_cast(innerCoin); SkOpSegment* innerOppWritable = const_cast(innerOpp); if (outerCoin == innerCoin) { @@ -785,7 +818,7 @@ bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) { return true; } const SkOpPtT* ice = inner->coinPtTEnd(); - SkASSERT(!ice->deleted()); + FAIL_IF(ice->deleted()); if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) { (void) this->addIfMissing(ocs->starter(oce), ics->starter(ice), overS, overE, outerOppWritable, innerOppWritable, added @@ -842,18 +875,26 @@ bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg const SkOpPtT* overS, const SkOpPtT* overE) { const SkOpPtT* s1 = overS->find(seg1); const SkOpPtT* e1 = overE->find(seg1); + FAIL_IF(!s1); + FAIL_IF(!e1); if (!s1->starter(e1)->span()->upCast()->windValue()) { s1 = overS->find(seg1o); e1 = overE->find(seg1o); + FAIL_IF(!s1); + FAIL_IF(!e1); if (!s1->starter(e1)->span()->upCast()->windValue()) { return true; } } const SkOpPtT* s2 = overS->find(seg2); const SkOpPtT* e2 = overE->find(seg2); + FAIL_IF(!s2); + FAIL_IF(!e2); if (!s2->starter(e2)->span()->upCast()->windValue()) { s2 = overS->find(seg2o); e2 = overE->find(seg2o); + FAIL_IF(!s2); + FAIL_IF(!e2); if (!s2->starter(e2)->span()->upCast()->windValue()) { return true; } @@ -952,22 +993,26 @@ void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { } // walk span sets in parallel, moving winding from one to the other -void SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { +bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { DEBUG_SET_PHASE(); SkCoincidentSpans* coin = fHead; if (!coin) { - return; + return true; } do { - SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast(); + SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span(); + FAIL_IF(!startSpan->upCastable()); + SkOpSpan* start = startSpan->upCast(); if (start->deleted()) { continue; } const SkOpSpanBase* end = coin->coinPtTEnd()->span(); SkASSERT(start == start->starter(end)); bool flipped = coin->flipped(); - SkOpSpan* oStart = (flipped ? coin->oppPtTEndWritable() - : coin->oppPtTStartWritable())->span()->upCast(); + SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable() + : coin->oppPtTStartWritable())->span(); + FAIL_IF(!oStartBase->upCastable()); + SkOpSpan* oStart = oStartBase->upCast(); if (oStart->deleted()) { continue; } @@ -985,6 +1030,7 @@ void SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { if (oNext == oEnd) { break; } + FAIL_IF(!oNext->upCastable()); oStart = oNext->upCast(); } while (true); } @@ -1051,6 +1097,7 @@ void SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { #endif start->setWindValue(windValue); start->setOppValue(oppValue); + FAIL_IF(oWindValue == -1); oStart->setWindValue(oWindValue); oStart->setOppValue(oOppValue); if (!windValue && !oppValue) { @@ -1064,6 +1111,7 @@ void SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { if (next == end) { break; } + FAIL_IF(!next->upCastable()); start = next->upCast(); // if the opposite ran out too soon, just reuse the last span if (!oNext || !oNext->upCastable()) { @@ -1072,6 +1120,7 @@ void SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { oStart = oNext->upCast(); } while (true); } while ((coin = coin->next())); + return true; } // Please keep this in sync with debugRelease() @@ -1176,7 +1225,7 @@ bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { return expanded; } -void SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const { +bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const { DEBUG_SET_PHASE(); overlaps->fHead = overlaps->fTop = nullptr; SkCoincidentSpans* outer = fHead; @@ -1201,12 +1250,15 @@ void SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(), outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(), &overlapS, &overlapE))) { - SkAssertResult(overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp, - overlapS, overlapE)); + if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp, + overlapS, overlapE)) { + return false; + } } } outer = outer->next(); } + return true; } void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) { @@ -1255,19 +1307,21 @@ void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkO // Please keep this in sync with debugMark() /* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */ -void SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { +bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { DEBUG_SET_PHASE(); SkCoincidentSpans* coin = fHead; if (!coin) { - return; + return true; } do { - SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast(); - SkASSERT(!start->deleted()); + SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span(); + FAIL_IF(!startBase->upCastable()); + SkOpSpan* start = startBase->upCast(); + FAIL_IF(start->deleted()); SkOpSpanBase* end = coin->coinPtTEndWritable()->span(); - SkASSERT(!end->deleted()); + SkOPASSERT(!end->deleted()); SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span(); - SkASSERT(!oStart->deleted()); + SkOPASSERT(!oStart->deleted()); SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span(); SkASSERT(!oEnd->deleted()); bool flipped = coin->flipped(); @@ -1276,20 +1330,25 @@ void SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { } /* coin and opp spans may not match up. Mark the ends, and then let the interior get marked as many times as the spans allow */ + FAIL_IF(!oStart->upCastable()); start->insertCoincidence(oStart->upCast()); end->insertCoinEnd(oEnd); const SkOpSegment* segment = start->segment(); const SkOpSegment* oSegment = oStart->segment(); SkOpSpanBase* next = start; SkOpSpanBase* oNext = oStart; - bool ordered = coin->ordered(); + bool ordered; + FAIL_IF(!coin->ordered(&ordered)); while ((next = next->upCast()->next()) != end) { - SkAssertResult(next->upCast()->insertCoincidence(oSegment, flipped, ordered)); + FAIL_IF(!next->upCastable()); + FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered)); } while ((oNext = oNext->upCast()->next()) != oEnd) { - SkAssertResult(oNext->upCast()->insertCoincidence(segment, flipped, ordered)); + FAIL_IF(!oNext->upCastable()); + FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered)); } } while ((coin = coin->next())); + return true; } // Please keep in sync with debugMarkCollapsed() diff --git a/gfx/skia/skia/src/pathops/SkOpCoincidence.h b/gfx/skia/skia/src/pathops/SkOpCoincidence.h index 24403532304a..92076b12c716 100644 --- a/gfx/skia/skia/src/pathops/SkOpCoincidence.h +++ b/gfx/skia/skia/src/pathops/SkOpCoincidence.h @@ -17,8 +17,8 @@ class SkOpSpanBase; class SkCoincidentSpans { public: - const SkOpPtT* coinPtTEnd() const { return fCoinPtTEnd; } - const SkOpPtT* coinPtTStart() const { return fCoinPtTStart; } + const SkOpPtT* coinPtTEnd() const; + const SkOpPtT* coinPtTStart() const; // These return non-const pointers so that, as copies, they can be added // to a new span pair @@ -67,27 +67,27 @@ public: SkCoincidentSpans* next() { return fNext; } const SkCoincidentSpans* next() const { return fNext; } SkCoincidentSpans** nextPtr() { return &fNext; } - const SkOpPtT* oppPtTStart() const { return fOppPtTStart; } - const SkOpPtT* oppPtTEnd() const { return fOppPtTEnd; } + const SkOpPtT* oppPtTStart() const; + const SkOpPtT* oppPtTEnd() const; // These return non-const pointers so that, as copies, they can be added // to a new span pair SkOpPtT* oppPtTStartWritable() const { return const_cast(fOppPtTStart); } SkOpPtT* oppPtTEndWritable() const { return const_cast(fOppPtTEnd); } - bool ordered() const; + bool ordered(bool* result) const; void set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd); void setCoinPtTEnd(const SkOpPtT* ptT) { SkOPASSERT(ptT == ptT->span()->ptT()); - SkASSERT(!fCoinPtTStart || ptT->fT != fCoinPtTStart->fT); + SkOPASSERT(!fCoinPtTStart || ptT->fT != fCoinPtTStart->fT); SkASSERT(!fCoinPtTStart || fCoinPtTStart->segment() == ptT->segment()); fCoinPtTEnd = ptT; ptT->setCoincident(); } void setCoinPtTStart(const SkOpPtT* ptT) { - SkASSERT(ptT == ptT->span()->ptT()); + SkOPASSERT(ptT == ptT->span()->ptT()); SkOPASSERT(!fCoinPtTEnd || ptT->fT != fCoinPtTEnd->fT); SkASSERT(!fCoinPtTEnd || fCoinPtTEnd->segment() == ptT->segment()); fCoinPtTStart = ptT; @@ -108,8 +108,8 @@ public: } void setOppPtTStart(const SkOpPtT* ptT) { - SkASSERT(ptT == ptT->span()->ptT()); - SkASSERT(!fOppPtTEnd || ptT->fT != fOppPtTEnd->fT); + SkOPASSERT(ptT == ptT->span()->ptT()); + SkOPASSERT(!fOppPtTEnd || ptT->fT != fOppPtTEnd->fT); SkASSERT(!fOppPtTEnd || fOppPtTEnd->segment() == ptT->segment()); fOppPtTStart = ptT; ptT->setCoincident(); @@ -150,7 +150,7 @@ public: bool addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()); - void apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()); + bool apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const; void correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()); @@ -212,7 +212,7 @@ public: bool expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd); - void findOverlaps(SkOpCoincidence* DEBUG_COIN_DECLARE_PARAMS()) const; + bool findOverlaps(SkOpCoincidence* DEBUG_COIN_DECLARE_PARAMS()) const; void fixUp(SkOpPtT* deleted, const SkOpPtT* kept); SkOpGlobalState* globalState() { @@ -227,7 +227,7 @@ public: return !fHead && !fTop; } - void mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()); + bool mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()); void markCollapsed(SkOpPtT* ); static bool Ordered(const SkOpPtT* coinPtTStart, const SkOpPtT* oppPtTStart) { diff --git a/gfx/skia/skia/src/pathops/SkOpContour.cpp b/gfx/skia/skia/src/pathops/SkOpContour.cpp index 981bd29573cc..ea1659ee2bc7 100644 --- a/gfx/skia/skia/src/pathops/SkOpContour.cpp +++ b/gfx/skia/skia/src/pathops/SkOpContour.cpp @@ -10,36 +10,10 @@ #include "SkReduceOrder.h" #include "SkTSort.h" -SkOpSegment* SkOpContour::addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight) { - SkChunkAlloc* allocator = this->globalState()->allocator(); - switch (verb) { - case SkPath::kLine_Verb: { - SkPoint* ptStorage = SkOpTAllocator::AllocateArray(allocator, 2); - memcpy(ptStorage, pts, sizeof(SkPoint) * 2); - return appendSegment().addLine(ptStorage, this); - } break; - case SkPath::kQuad_Verb: { - SkPoint* ptStorage = SkOpTAllocator::AllocateArray(allocator, 3); - memcpy(ptStorage, pts, sizeof(SkPoint) * 3); - return appendSegment().addQuad(ptStorage, this); - } break; - case SkPath::kConic_Verb: { - SkPoint* ptStorage = SkOpTAllocator::AllocateArray(allocator, 3); - memcpy(ptStorage, pts, sizeof(SkPoint) * 3); - return appendSegment().addConic(ptStorage, weight, this); - } break; - case SkPath::kCubic_Verb: { - SkPoint* ptStorage = SkOpTAllocator::AllocateArray(allocator, 4); - memcpy(ptStorage, pts, sizeof(SkPoint) * 4); - return appendSegment().addCubic(ptStorage, this); - } break; - default: - SkASSERT(0); - } - return nullptr; -} - void SkOpContour::toPath(SkPathWriter* path) const { + if (!this->count()) { + return; + } const SkOpSegment* segment = &fHead; do { SkAssertResult(segment->addCurveTo(segment->head(), segment->tail(), path)); @@ -57,14 +31,84 @@ void SkOpContour::toReversePath(SkPathWriter* path) const { path->assemble(); } -SkOpSegment* SkOpContour::undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr) { - SkOpSegment* segment = &fHead; +SkOpSpan* SkOpContour::undoneSpan() { + SkOpSegment* testSegment = &fHead; + bool allDone = true; do { - if (segment->done()) { + if (testSegment->done()) { continue; } - segment->undoneSpan(startPtr, endPtr); - return segment; - } while ((segment = segment->next())); + allDone = false; + return testSegment->undoneSpan(); + } while ((testSegment = testSegment->next())); + if (allDone) { + fDone = true; + } return nullptr; } + +void SkOpContourBuilder::addConic(SkPoint pts[3], SkScalar weight) { + this->flush(); + fContour->addConic(pts, weight); +} + +void SkOpContourBuilder::addCubic(SkPoint pts[4]) { + this->flush(); + fContour->addCubic(pts); +} + +void SkOpContourBuilder::addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight) { + if (SkPath::kLine_Verb == verb) { + this->addLine(pts); + return; + } + SkArenaAlloc* allocator = fContour->globalState()->allocator(); + switch (verb) { + case SkPath::kQuad_Verb: { + SkPoint* ptStorage = SkOpTAllocator::AllocateArray(allocator, 3); + memcpy(ptStorage, pts, sizeof(SkPoint) * 3); + this->addQuad(ptStorage); + } break; + case SkPath::kConic_Verb: { + SkPoint* ptStorage = SkOpTAllocator::AllocateArray(allocator, 3); + memcpy(ptStorage, pts, sizeof(SkPoint) * 3); + this->addConic(ptStorage, weight); + } break; + case SkPath::kCubic_Verb: { + SkPoint* ptStorage = SkOpTAllocator::AllocateArray(allocator, 4); + memcpy(ptStorage, pts, sizeof(SkPoint) * 4); + this->addCubic(ptStorage); + } break; + default: + SkASSERT(0); + } +} + +void SkOpContourBuilder::addLine(const SkPoint pts[2]) { + // if the previous line added is the exact opposite, eliminate both + if (fLastIsLine) { + if (fLastLine[0] == pts[1] && fLastLine[1] == pts[0]) { + fLastIsLine = false; + return; + } else { + flush(); + } + } + memcpy(fLastLine, pts, sizeof(fLastLine)); + fLastIsLine = true; +} + +void SkOpContourBuilder::addQuad(SkPoint pts[3]) { + this->flush(); + fContour->addQuad(pts); +} + +void SkOpContourBuilder::flush() { + if (!fLastIsLine) + return; + SkArenaAlloc* allocator = fContour->globalState()->allocator(); + SkPoint* ptStorage = SkOpTAllocator::AllocateArray(allocator, 2); + memcpy(ptStorage, fLastLine, sizeof(fLastLine)); + (void) fContour->addLine(ptStorage); + fLastIsLine = false; +} diff --git a/gfx/skia/skia/src/pathops/SkOpContour.h b/gfx/skia/skia/src/pathops/SkOpContour.h index dc07c530451b..c28322659037 100644 --- a/gfx/skia/skia/src/pathops/SkOpContour.h +++ b/gfx/skia/skia/src/pathops/SkOpContour.h @@ -21,12 +21,6 @@ public: reset(); } - ~SkOpContour() { - if (fNext) { - fNext->~SkOpContour(); - } - } - bool operator<(const SkOpContour& rh) const { return fBounds.fTop == rh.fBounds.fTop ? fBounds.fLeft < rh.fBounds.fLeft @@ -41,8 +35,6 @@ public: appendSegment().addCubic(pts, this); } - SkOpSegment* addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight = 1); - SkOpSegment* addLine(SkPoint pts[2]) { SkASSERT(pts[0] != pts[1]); return appendSegment().addLine(pts, this); @@ -123,10 +115,10 @@ public: } #if DEBUG_ACTIVE_SPANS - void debugShowActiveSpans() { + void debugShowActiveSpans(SkString* str) { SkOpSegment* segment = &fHead; do { - segment->debugShowActiveSpans(); + segment->debugShowActiveSpans(str); } while ((segment = segment->next())); } #endif @@ -251,12 +243,15 @@ public: return true; } - void moveNearby() { + bool moveNearby() { SkASSERT(fCount > 0); SkOpSegment* segment = &fHead; do { - segment->moveNearby(); + if (!segment->moveNearby()) { + return false; + } } while ((segment = segment->next())); + return true; } SkOpContour* next() { @@ -279,7 +274,7 @@ public: SkDEBUGCODE(fDebugIndent -= 2); } - void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkChunkAlloc* ); + void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkArenaAlloc*); void reset() { fTail = nullptr; @@ -294,6 +289,9 @@ public: void resetReverse() { SkOpContour* next = this; do { + if (!next->count()) { + continue; + } next->fCcw = -1; next->fReverse = false; } while ((next = next->next())); @@ -341,12 +339,13 @@ public: fXor = isXor; } - void sortAngles() { + bool sortAngles() { SkASSERT(fCount > 0); SkOpSegment* segment = &fHead; do { - segment->sortAngles(); + FAIL_IF(!segment->sortAngles()); } while ((segment = segment->next())); + return true; } const SkPoint& start() const { @@ -369,9 +368,9 @@ public: void toReversePath(SkPathWriter* path) const; void toPath(SkPathWriter* path) const; - SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr); + SkOpSpan* undoneSpan(); -private: +protected: SkOpGlobalState* fState; SkOpSegment fHead; SkOpSegment* fTail; @@ -406,6 +405,9 @@ public: void joinAllSegments() { SkOpContour* next = this; do { + if (!next->count()) { + continue; + } next->joinSegments(); } while ((next = next->next())); } @@ -428,4 +430,25 @@ public: }; +class SkOpContourBuilder { +public: + SkOpContourBuilder(SkOpContour* contour) + : fContour(contour) + , fLastIsLine(false) { + } + + void addConic(SkPoint pts[3], SkScalar weight); + void addCubic(SkPoint pts[4]); + void addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight = 1); + void addLine(const SkPoint pts[2]); + void addQuad(SkPoint pts[3]); + void flush(); + SkOpContour* contour() { return fContour; } + void setContour(SkOpContour* contour) { flush(); fContour = contour; } +protected: + SkOpContour* fContour; + SkPoint fLastLine[2]; + bool fLastIsLine; +}; + #endif diff --git a/gfx/skia/skia/src/pathops/SkOpEdgeBuilder.cpp b/gfx/skia/skia/src/pathops/SkOpEdgeBuilder.cpp index ab2aca0a7682..120a50322750 100644 --- a/gfx/skia/skia/src/pathops/SkOpEdgeBuilder.cpp +++ b/gfx/skia/skia/src/pathops/SkOpEdgeBuilder.cpp @@ -9,7 +9,6 @@ #include "SkReduceOrder.h" void SkOpEdgeBuilder::init() { - fCurrentContour = fContoursHead; fOperand = false; fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask : kWinding_PathOpsMask; @@ -52,8 +51,9 @@ bool SkOpEdgeBuilder::finish() { return false; } complete(); - if (fCurrentContour && !fCurrentContour->count()) { - fContoursHead->remove(fCurrentContour); + SkOpContour* contour = fContourBuilder.contour(); + if (contour && !contour->count()) { + fContoursHead->remove(contour); } return true; } @@ -105,7 +105,7 @@ int SkOpEdgeBuilder::preFetch() { if (SkDPoint::ApproximatelyEqual(curve[0], pts[1])) { uint8_t lastVerb = fPathVerbs.top(); if (lastVerb != SkPath::kLine_Verb && lastVerb != SkPath::kMove_Verb) { - fPathPts.top() = pts[1]; + fPathPts.top() = curve[0] = pts[1]; } continue; // skip degenerate points } @@ -178,6 +178,7 @@ bool SkOpEdgeBuilder::walk() { SkPoint* pointsPtr = fPathPts.begin() - 1; SkScalar* weightPtr = fWeights.begin(); SkPath::Verb verb; + SkOpContour* contour = fContourBuilder.contour(); while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) { if (verbPtr == endOfFirstHalf) { fOperand = true; @@ -185,22 +186,22 @@ bool SkOpEdgeBuilder::walk() { verbPtr++; switch (verb) { case SkPath::kMove_Verb: - if (fCurrentContour && fCurrentContour->count()) { + if (contour && contour->count()) { if (fAllowOpenContours) { complete(); } else if (!close()) { return false; } } - if (!fCurrentContour) { - fCurrentContour = fContoursHead->appendContour(); + if (!contour) { + fContourBuilder.setContour(contour = fContoursHead->appendContour()); } - fCurrentContour->init(fGlobalState, fOperand, + contour->init(fGlobalState, fOperand, fXorMask[fOperand] == kEvenOdd_PathOpsMask); pointsPtr += 1; continue; case SkPath::kLine_Verb: - fCurrentContour->addLine(pointsPtr); + fContourBuilder.addLine(pointsPtr); break; case SkPath::kQuad_Verb: { @@ -220,14 +221,14 @@ bool SkOpEdgeBuilder::walk() { SkPoint* curve1 = v1 != SkPath::kLine_Verb ? &pair[0] : cStorage[0]; SkPoint* curve2 = v2 != SkPath::kLine_Verb ? &pair[2] : cStorage[1]; if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) { - fCurrentContour->addCurve(v1, curve1); - fCurrentContour->addCurve(v2, curve2); + fContourBuilder.addCurve(v1, curve1); + fContourBuilder.addCurve(v2, curve2); break; } } } addOneQuad: - fCurrentContour->addQuad(pointsPtr); + fContourBuilder.addQuad(pointsPtr); break; case SkPath::kConic_Verb: { SkVector v1 = pointsPtr[1] - pointsPtr[0]; @@ -241,7 +242,7 @@ bool SkOpEdgeBuilder::walk() { SkConic pair[2]; if (!conic.chopAt(maxCurvature, pair)) { // if result can't be computed, use original - fCurrentContour->addConic(pointsPtr, weight); + fContourBuilder.addConic(pointsPtr, weight); break; } SkPoint cStorage[2][3]; @@ -250,56 +251,106 @@ bool SkOpEdgeBuilder::walk() { SkPoint* curve1 = v1 != SkPath::kLine_Verb ? pair[0].fPts : cStorage[0]; SkPoint* curve2 = v2 != SkPath::kLine_Verb ? pair[1].fPts : cStorage[1]; if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) { - fCurrentContour->addCurve(v1, curve1, pair[0].fW); - fCurrentContour->addCurve(v2, curve2, pair[1].fW); + fContourBuilder.addCurve(v1, curve1, pair[0].fW); + fContourBuilder.addCurve(v2, curve2, pair[1].fW); break; } } } - fCurrentContour->addConic(pointsPtr, weight); + fContourBuilder.addConic(pointsPtr, weight); } break; case SkPath::kCubic_Verb: { // Split complex cubics (such as self-intersecting curves or // ones with difficult curvature) in two before proceeding. // This can be required for intersection to succeed. - SkScalar splitT; - if (SkDCubic::ComplexBreak(pointsPtr, &splitT)) { - SkPoint pair[7]; - SkChopCubicAt(pointsPtr, pair, splitT); - if (!SkScalarsAreFinite(&pair[0].fX, SK_ARRAY_COUNT(pair) * 2)) { + SkScalar splitT[3]; + int breaks = SkDCubic::ComplexBreak(pointsPtr, splitT); + if (!breaks) { + fContourBuilder.addCubic(pointsPtr); + break; + } + SkASSERT(breaks <= (int) SK_ARRAY_COUNT(splitT)); + struct Splitsville { + double fT[2]; + SkPoint fPts[4]; + SkPoint fReduced[4]; + SkPath::Verb fVerb; + bool fCanAdd; + } splits[4]; + SkASSERT(SK_ARRAY_COUNT(splits) == SK_ARRAY_COUNT(splitT) + 1); + SkTQSort(splitT, &splitT[breaks - 1]); + for (int index = 0; index <= breaks; ++index) { + Splitsville* split = &splits[index]; + split->fT[0] = index ? splitT[index - 1] : 0; + split->fT[1] = index < breaks ? splitT[index] : 1; + SkDCubic part = SkDCubic::SubDivide(pointsPtr, split->fT[0], split->fT[1]); + if (!part.toFloatPoints(split->fPts)) { return false; } - SkPoint cStorage[2][4]; - SkPath::Verb v1 = SkReduceOrder::Cubic(&pair[0], cStorage[0]); - SkPath::Verb v2 = SkReduceOrder::Cubic(&pair[3], cStorage[1]); - SkPoint* curve1 = v1 == SkPath::kCubic_Verb ? &pair[0] : cStorage[0]; - SkPoint* curve2 = v2 == SkPath::kCubic_Verb ? &pair[3] : cStorage[1]; - if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) { - fCurrentContour->addCurve(v1, curve1); - fCurrentContour->addCurve(v2, curve2); - break; - } + split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced); + SkPoint* curve = SkPath::kCubic_Verb == verb + ? split->fPts : split->fReduced; + split->fCanAdd = can_add_curve(split->fVerb, curve); + } + for (int index = 0; index <= breaks; ++index) { + Splitsville* split = &splits[index]; + if (!split->fCanAdd) { + continue; + } + int prior = index; + while (prior > 0 && !splits[prior - 1].fCanAdd) { + --prior; + } + if (prior < index) { + split->fT[0] = splits[prior].fT[0]; + } + int next = index; + while (next < breaks && !splits[next + 1].fCanAdd) { + ++next; + } + if (next > index) { + split->fT[1] = splits[next].fT[1]; + } + if (prior < index || next > index) { + if (0 == split->fT[0] && 1 == split->fT[1]) { + fContourBuilder.addCubic(pointsPtr); + break; + } + SkDCubic part = SkDCubic::SubDivide(pointsPtr, split->fT[0], + split->fT[1]); + if (!part.toFloatPoints(split->fPts)) { + return false; + } + split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced); + } + SkPoint* curve = SkPath::kCubic_Verb == split->fVerb + ? split->fPts : split->fReduced; + SkAssertResult(can_add_curve(split->fVerb, curve)); + fContourBuilder.addCurve(split->fVerb, curve); } } - fCurrentContour->addCubic(pointsPtr); break; case SkPath::kClose_Verb: - SkASSERT(fCurrentContour); + SkASSERT(contour); if (!close()) { return false; } + contour = nullptr; continue; default: SkDEBUGFAIL("bad verb"); return false; } - SkASSERT(fCurrentContour); - fCurrentContour->debugValidate(); + SkASSERT(contour); + if (contour->count()) { + contour->debugValidate(); + } pointsPtr += SkPathOpsVerbToPoints(verb); } - if (fCurrentContour && fCurrentContour->count() &&!fAllowOpenContours && !close()) { - return false; - } - return true; + fContourBuilder.flush(); + if (contour && contour->count() &&!fAllowOpenContours && !close()) { + return false; + } + return true; } diff --git a/gfx/skia/skia/src/pathops/SkOpEdgeBuilder.h b/gfx/skia/skia/src/pathops/SkOpEdgeBuilder.h index c6fc7dcb0784..a71001f440f9 100644 --- a/gfx/skia/skia/src/pathops/SkOpEdgeBuilder.h +++ b/gfx/skia/skia/src/pathops/SkOpEdgeBuilder.h @@ -16,6 +16,7 @@ public: SkOpGlobalState* globalState) : fGlobalState(globalState) , fPath(path.nativePath()) + , fContourBuilder(contours2) , fContoursHead(contours2) , fAllowOpenContours(true) { init(); @@ -24,6 +25,7 @@ public: SkOpEdgeBuilder(const SkPath& path, SkOpContourHead* contours2, SkOpGlobalState* globalState) : fGlobalState(globalState) , fPath(&path) + , fContourBuilder(contours2) , fContoursHead(contours2) , fAllowOpenContours(false) { init(); @@ -32,9 +34,11 @@ public: void addOperand(const SkPath& path); void complete() { - if (fCurrentContour && fCurrentContour->count()) { - fCurrentContour->complete(); - fCurrentContour = nullptr; + fContourBuilder.flush(); + SkOpContour* contour = fContourBuilder.contour(); + if (contour && contour->count()) { + contour->complete(); + fContourBuilder.setContour(nullptr); } } @@ -59,7 +63,7 @@ private: SkTDArray fPathPts; SkTDArray fWeights; SkTDArray fPathVerbs; - SkOpContour* fCurrentContour; + SkOpContourBuilder fContourBuilder; SkOpContourHead* fContoursHead; SkPathOpsMask fXorMask[2]; int fSecondHalf; diff --git a/gfx/skia/skia/src/pathops/SkOpSegment.cpp b/gfx/skia/skia/src/pathops/SkOpSegment.cpp index 2246f36ff217..5502688615f8 100644 --- a/gfx/skia/skia/src/pathops/SkOpSegment.cpp +++ b/gfx/skia/skia/src/pathops/SkOpSegment.cpp @@ -169,18 +169,18 @@ bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, path->deferredMove(start->ptT()); switch (verb) { case SkPath::kLine_Verb: - path->deferredLine(end->ptT()); + FAIL_IF(!path->deferredLine(end->ptT())); break; case SkPath::kQuad_Verb: - path->quadTo(curvePart.fCurve.fQuad.fPts[1].asSkPoint(), end->ptT()); + path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT()); break; case SkPath::kConic_Verb: - path->conicTo(curvePart.fCurve.fConic.fPts[1].asSkPoint(), end->ptT(), + path->conicTo(curvePart.fCurve.fConic[1].asSkPoint(), end->ptT(), curvePart.fCurve.fConic.fWeight); break; case SkPath::kCubic_Verb: - path->cubicTo(curvePart.fCurve.fCubic.fPts[1].asSkPoint(), - curvePart.fCurve.fCubic.fPts[2].asSkPoint(), end->ptT()); + path->cubicTo(curvePart.fCurve.fCubic[1].asSkPoint(), + curvePart.fCurve.fCubic[2].asSkPoint(), end->ptT()); break; default: SkASSERT(0); @@ -225,6 +225,7 @@ bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* start return true; } this->globalState()->resetAllocatedOpSpan(); + FAIL_IF(!between(0, newT, 1)); SkOpPtT* newPtT = this->addT(newT); *startOver |= this->globalState()->allocatedOpSpan(); if (!newPtT) { @@ -836,12 +837,19 @@ SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* e markDone(minSpan); SkOpSpanBase* last = nullptr; SkOpSegment* other = this; + SkOpSpan* priorDone = nullptr; + SkOpSpan* lastDone = nullptr; while ((other = other->nextChase(&start, &step, &minSpan, &last))) { if (other->done()) { SkASSERT(!last); break; } + if (lastDone == minSpan || priorDone == minSpan) { + return nullptr; + } other->markDone(minSpan); + priorDone = lastDone; + lastDone = minSpan; } return last; } @@ -855,7 +863,7 @@ bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, in SkOpSegment* other = this; while ((other = other->nextChase(&start, &step, &spanStart, &last))) { if (spanStart->windSum() != SK_MinS32) { - SkASSERT(spanStart->windSum() == winding); +// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive? SkASSERT(!last); break; } @@ -1057,9 +1065,6 @@ SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS return set_last(last, endSpan); } SkASSERT(*startPtr); - if (!otherEnd) { - return nullptr; - } // SkASSERT(otherEnd >= 0); SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast(); SkOpSpan* foundMin = foundSpan->starter(otherEnd); @@ -1206,8 +1211,8 @@ bool SkOpSegment::moveMultiples() { SkOpSpanBase* test = &fHead; do { int addCount = test->spanAddsCount(); - FAIL_IF(addCount < 1); - if (addCount == 1) { +// FAIL_IF(addCount < 1); + if (addCount <= 1) { continue; } SkOpPtT* startPtT = test->ptT(); @@ -1296,7 +1301,8 @@ checkNextSpan: } // adjacent spans may have points close by -bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan) const { +bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan, + bool* found) const { const SkOpPtT* refHead = refSpan->ptT(); const SkOpPtT* checkHead = checkSpan->ptT(); // if the first pt pair from adjacent spans are far apart, assume that all are far enough apart @@ -1313,7 +1319,8 @@ bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* c dBugRef = dBugRef->next(); } while (dBugRef != refHead); #endif - return false; + *found = false; + return true; } // check only unique points SkScalar distSqBest = SK_ScalarMax; @@ -1332,6 +1339,7 @@ bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* c } const SkOpPtT* check = checkHead; const SkOpSegment* refSeg = ref->segment(); + int escapeHatch = 100000; // defend against infinite loops do { if (check->deleted()) { continue; @@ -1349,18 +1357,22 @@ bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* c refBest = ref; checkBest = check; } + if (--escapeHatch <= 0) { + return false; + } } while ((check = check->next()) != checkHead); -nextRef: + nextRef: ; } while ((ref = ref->next()) != refHead); doneCheckingDistance: - return checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT, + *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT, checkBest->fPt); + return true; } // Please keep this function in sync with debugMoveNearby() // Move nearby t values and pts so they all hang off the same span. Alignment happens later. -void SkOpSegment::moveNearby() { +bool SkOpSegment::moveNearby() { debugValidate(); // release undeleted spans pointing to this seg that are linked to the primary span SkOpSpanBase* spanBase = &fHead; @@ -1374,7 +1386,7 @@ void SkOpSegment::moveNearby() { if (test->final()) { if (spanBase == &fHead) { this->clearAll(); - return; + return true; } spanBase->upCast()->release(ptT); } else if (test->prev()) { @@ -1390,13 +1402,17 @@ void SkOpSegment::moveNearby() { spanBase = &fHead; do { // iterate through all spans associated with start SkOpSpanBase* test = spanBase->upCast()->next(); - if (this->spansNearby(spanBase, test)) { + bool found; + if (!this->spansNearby(spanBase, test, &found)) { + return false; + } + if (found) { if (test->final()) { if (spanBase->prev()) { test->merge(spanBase->upCast()); } else { this->clearAll(); - return; + return true; } } else { spanBase->merge(test->upCast()); @@ -1405,6 +1421,7 @@ void SkOpSegment::moveNearby() { spanBase = test; } while (!spanBase->final()); debugValidate(); + return true; } bool SkOpSegment::operand() const { @@ -1459,7 +1476,7 @@ void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sum SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM); } -void SkOpSegment::sortAngles() { +bool SkOpSegment::sortAngles() { SkOpSpanBase* span = &this->fHead; do { SkOpAngle* fromAngle = span->fromAngle(); @@ -1477,7 +1494,7 @@ void SkOpSegment::sortAngles() { span->debugID()); wroteAfterHeader = true; #endif - fromAngle->insert(toAngle); + FAIL_IF(!fromAngle->insert(toAngle)); } else if (!fromAngle) { baseAngle = toAngle; } @@ -1527,6 +1544,7 @@ void SkOpSegment::sortAngles() { SkASSERT(!baseAngle || baseAngle->loopCount() > 1); #endif } while (!span->final() && (span = span->upCast()->next())); + return true; } bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, @@ -1613,16 +1631,16 @@ bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT return coincident; } -void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { - SkOpSpan* span = this->head(); +SkOpSpan* SkOpSegment::undoneSpan() { + SkOpSpan* span = &fHead; + SkOpSpanBase* next; do { + next = span->next(); if (!span->done()) { - break; + return span; } - } while ((span = span->next()->upCastable())); - SkASSERT(span); - *start = span; - *end = span->next(); + } while (!next->final() && (span = next->upCast())); + return nullptr; } int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const { diff --git a/gfx/skia/skia/src/pathops/SkOpSegment.h b/gfx/skia/skia/src/pathops/SkOpSegment.h index b6e7714018b7..20b095658021 100644 --- a/gfx/skia/skia/src/pathops/SkOpSegment.h +++ b/gfx/skia/skia/src/pathops/SkOpSegment.h @@ -158,7 +158,7 @@ public: const SkOpSegment* debugSegment(int id) const; #if DEBUG_ACTIVE_SPANS - void debugShowActiveSpans() const; + void debugShowActiveSpans(SkString* str) const; #endif #if DEBUG_MARK_DONE void debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding); @@ -169,8 +169,8 @@ public: void debugValidate() const; #if DEBUG_COINCIDENCE_ORDER - void debugResetCoinT() const; - void debugSetCoinT(int, SkScalar ) const; + void debugResetCoinT() const; + void debugSetCoinT(int, SkScalar ) const; #endif #if DEBUG_COIN @@ -291,7 +291,7 @@ public: bool match(const SkOpPtT* span, const SkOpSegment* parent, double t, const SkPoint& pt) const; bool missingCoincidence(); bool moveMultiples(); - void moveNearby(); + bool moveNearby(); SkOpSegment* next() const { return fNext; @@ -333,7 +333,7 @@ public: bool ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const; - void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkChunkAlloc*); + void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkArenaAlloc*); void release(const SkOpSpan* ); #if DEBUG_COIN @@ -371,8 +371,8 @@ public: int* maxWinding, int* sumWinding); void setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding, int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding); - void sortAngles(); - bool spansNearby(const SkOpSpanBase* ref, const SkOpSpanBase* check) const; + bool sortAngles(); + bool spansNearby(const SkOpSpanBase* ref, const SkOpSpanBase* check, bool* found) const; static int SpanSign(const SkOpSpanBase* start, const SkOpSpanBase* end) { int result = start->t() < end->t() ? -start->upCast()->windValue() @@ -398,7 +398,7 @@ public: bool testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT, const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const; - void undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end); + SkOpSpan* undoneSpan(); int updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const; int updateOppWinding(const SkOpAngle* angle) const; int updateOppWindingReverse(const SkOpAngle* angle) const; diff --git a/gfx/skia/skia/src/pathops/SkOpSpan.cpp b/gfx/skia/skia/src/pathops/SkOpSpan.cpp index 2abc44e24849..40d6383c7482 100644 --- a/gfx/skia/skia/src/pathops/SkOpSpan.cpp +++ b/gfx/skia/skia/src/pathops/SkOpSpan.cpp @@ -407,7 +407,9 @@ bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped, bool SkOpSpan* span; SkOpSpanBase* base = next->span(); if (!ordered) { - const SkOpSpanBase* spanEnd = fNext->contains(segment)->span(); + const SkOpPtT* spanEndPtT = fNext->contains(segment); + FAIL_IF(!spanEndPtT); + const SkOpSpanBase* spanEnd = spanEndPtT->span(); const SkOpPtT* start = base->ptT()->starter(spanEnd->ptT()); FAIL_IF(!start->span()->upCastable()); span = const_cast(start->span()->upCast()); diff --git a/gfx/skia/skia/src/pathops/SkOpSpan.h b/gfx/skia/skia/src/pathops/SkOpSpan.h index 023e7acfbe92..fea33095982b 100644 --- a/gfx/skia/skia/src/pathops/SkOpSpan.h +++ b/gfx/skia/skia/src/pathops/SkOpSpan.h @@ -11,7 +11,7 @@ #include "SkPathOpsTypes.h" #include "SkPoint.h" -class SkChunkAlloc; +class SkArenaAlloc; class SkOpAngle; class SkOpContour; class SkOpGlobalState; @@ -518,7 +518,7 @@ public: void setOppValue(int oppValue) { SkASSERT(!final()); SkASSERT(fOppSum == SK_MinS32); - SkASSERT(!oppValue || !fDone); + SkOPASSERT(!oppValue || !fDone); fOppValue = oppValue; } diff --git a/gfx/skia/skia/src/pathops/SkOpTAllocator.h b/gfx/skia/skia/src/pathops/SkOpTAllocator.h index e8835f02e6cb..599c445f12a5 100644 --- a/gfx/skia/skia/src/pathops/SkOpTAllocator.h +++ b/gfx/skia/skia/src/pathops/SkOpTAllocator.h @@ -7,26 +7,22 @@ #ifndef SkOpTAllocator_DEFINED #define SkOpTAllocator_DEFINED -#include "SkChunkAlloc.h" +#include "SkArenaAlloc.h" // T is SkOpAngle2, SkOpSpan2, or SkOpSegment2 template class SkOpTAllocator { public: - static T* Allocate(SkChunkAlloc* allocator) { - void* ptr = allocator->allocThrow(sizeof(T)); - T* record = (T*) ptr; - return record; + static T* Allocate(SkArenaAlloc* allocator) { + return allocator->make(); } - static T* AllocateArray(SkChunkAlloc* allocator, int count) { - void* ptr = allocator->allocThrow(sizeof(T) * count); - T* record = (T*) ptr; - return record; + static T* AllocateArray(SkArenaAlloc* allocator, int count) { + return allocator->makeArrayDefault(count); } - static T* New(SkChunkAlloc* allocator) { - return new (Allocate(allocator)) T(); + static T* New(SkArenaAlloc* allocator) { + return allocator->make(); } }; diff --git a/gfx/skia/skia/src/pathops/SkPathOpsCommon.cpp b/gfx/skia/skia/src/pathops/SkPathOpsCommon.cpp index 3d6ba4dda523..9cdf8124a8e1 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsCommon.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsCommon.cpp @@ -85,12 +85,13 @@ const SkOpAngle* AngleWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* windi return angle; } -SkOpSegment* FindUndone(SkOpContourHead* contourList, SkOpSpanBase** startPtr, - SkOpSpanBase** endPtr) { - SkOpSegment* result; - SkOpContour* contour = contourList; +SkOpSpan* FindUndone(SkOpContourHead* contourHead) { + SkOpContour* contour = contourHead; do { - result = contour->undoneSegment(startPtr, endPtr); + if (contour->done()) { + continue; + } + SkOpSpan* result = contour->undoneSpan(); if (result) { return result; } @@ -227,19 +228,25 @@ static bool move_multiples(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARA return true; } -static void move_nearby(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS()) { +static bool move_nearby(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS()) { DEBUG_STATIC_SET_PHASE(contourList); SkOpContour* contour = contourList; do { - contour->moveNearby(); + if (!contour->moveNearby()) { + return false; + } } while ((contour = contour->next())); + return true; } -static void sort_angles(SkOpContourHead* contourList) { +static bool sort_angles(SkOpContourHead* contourList) { SkOpContour* contour = contourList; do { - contour->sortAngles(); + if (!contour->sortAngles()) { + return false; + } } while ((contour = contour->next())); + return true; } bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence) { @@ -253,7 +260,9 @@ bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc return false; } // move t values and points together to eliminate small/tiny gaps - move_nearby(contourList DEBUG_COIN_PARAMS()); + if (!move_nearby(contourList DEBUG_COIN_PARAMS())) { + return false; + } // add coincidence formed by pairing on curve points and endpoints coincidence->correctEnds(DEBUG_PHASE_ONLY_PARAMS(kIntersecting)); if (!coincidence->addEndMovedSpans(DEBUG_COIN_ONLY_PARAMS())) { @@ -302,7 +311,9 @@ bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) { return false; } - coincidence->mark(DEBUG_PHASE_ONLY_PARAMS(kWalking)); + if (!coincidence->mark(DEBUG_PHASE_ONLY_PARAMS(kWalking))) { + return false; + } } else { (void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS()); } @@ -313,17 +324,23 @@ bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc do { SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps; // adjust the winding value to account for coincident edges - pairs->apply(DEBUG_ITER_ONLY_PARAMS(SAFETY_COUNT - safetyHatch)); + if (!pairs->apply(DEBUG_ITER_ONLY_PARAMS(SAFETY_COUNT - safetyHatch))) { + return false; + } // For each coincident pair that overlaps another, when the receivers (the 1st of the pair) // are different, construct a new pair to resolve their mutual span - pairs->findOverlaps(&overlaps DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch)); + if (!pairs->findOverlaps(&overlaps DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) { + return false; + } if (!--safetyHatch) { SkASSERT(globalState->debugSkipAssert()); return false; } } while (!overlaps.isEmpty()); calc_angles(contourList DEBUG_COIN_PARAMS()); - sort_angles(contourList); + if (!sort_angles(contourList)) { + return false; + } #if DEBUG_COINCIDENCE_VERBOSE coincidence->debugShowCoincidence(); #endif diff --git a/gfx/skia/skia/src/pathops/SkPathOpsCommon.h b/gfx/skia/skia/src/pathops/SkPathOpsCommon.h index beffb8522cd1..679a4869307f 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsCommon.h +++ b/gfx/skia/skia/src/pathops/SkPathOpsCommon.h @@ -19,8 +19,7 @@ const SkOpAngle* AngleWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* windi SkOpSegment* FindChase(SkTDArray* chase, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr); SkOpSpan* FindSortableTop(SkOpContourHead* ); -SkOpSegment* FindUndone(SkOpContourHead* , SkOpSpanBase** startPtr, - SkOpSpanBase** endPtr); +SkOpSpan* FindUndone(SkOpContourHead* ); bool FixWinding(SkPath* path); bool SortContourList(SkOpContourHead** , bool evenOdd, bool oppEvenOdd); bool HandleCoincidence(SkOpContourHead* , SkOpCoincidence* ); diff --git a/gfx/skia/skia/src/pathops/SkPathOpsConic.cpp b/gfx/skia/skia/src/pathops/SkPathOpsConic.cpp index dd523211de17..82f3a7b0ccfe 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsConic.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsConic.cpp @@ -156,7 +156,8 @@ SkDConic SkDConic::subDivide(double t1, double t2) const { double bx = 2 * dx - (ax + cx) / 2; double by = 2 * dy - (ay + cy) / 2; double bz = 2 * dz - (az + cz) / 2; - SkDConic dst = {{{{ax / az, ay / az}, {bx / bz, by / bz}, {cx / cz, cy / cz}}}, + SkDConic dst = {{{{ax / az, ay / az}, {bx / bz, by / bz}, {cx / cz, cy / cz}} + SkDEBUGPARAMS(fPts.fDebugGlobalState) }, SkDoubleToScalar(bz / sqrt(az * cz)) }; return dst; } diff --git a/gfx/skia/skia/src/pathops/SkPathOpsConic.h b/gfx/skia/skia/src/pathops/SkPathOpsConic.h index 4cbe147b49e4..42362797a22c 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsConic.h +++ b/gfx/skia/skia/src/pathops/SkPathOpsConic.h @@ -31,15 +31,23 @@ struct SkDConic { fPts.debugInit(); } + void debugSet(const SkDPoint* pts, SkScalar weight); + SkDConic flip() const { - SkDConic result = {{{fPts[2], fPts[1], fPts[0]}}, fWeight}; + SkDConic result = {{{fPts[2], fPts[1], fPts[0]} + SkDEBUGPARAMS(fPts.fDebugGlobalState) }, fWeight}; return result; } +#ifdef SK_DEBUG + SkOpGlobalState* globalState() const { return fPts.globalState(); } +#endif + static bool IsConic() { return true; } - const SkDConic& set(const SkPoint pts[kPointCount], SkScalar weight) { - fPts.set(pts); + const SkDConic& set(const SkPoint pts[kPointCount], SkScalar weight + SkDEBUGPARAMS(SkOpGlobalState* state = nullptr)) { + fPts.set(pts SkDEBUGPARAMS(state)); fWeight = weight; return *this; } @@ -117,6 +125,7 @@ struct SkDConic { void dump() const; void dumpID(int id) const; void dumpInner() const; + }; diff --git a/gfx/skia/skia/src/pathops/SkPathOpsCubic.cpp b/gfx/skia/skia/src/pathops/SkPathOpsCubic.cpp index bdae492de07b..d842e2cc0c7f 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsCubic.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsCubic.cpp @@ -36,7 +36,7 @@ double SkDCubic::binarySearch(double min, double max, double axisIntercept, double calcDist = calcPos - axisIntercept; do { double priorT = t - step; - SkASSERT(priorT >= min); + SkOPASSERT(priorT >= min); SkDPoint lessPt = ptAtT(priorT); if (approximately_equal_half(lessPt.fX, cubicAtT.fX) && approximately_equal_half(lessPt.fY, cubicAtT.fY)) { @@ -75,16 +75,13 @@ double SkDCubic::binarySearch(double min, double max, double axisIntercept, return t; } -// FIXME: cache keep the bounds and/or precision with the caller? +// get the rough scale of the cubic; used to determine if curvature is extreme double SkDCubic::calcPrecision() const { - SkDRect dRect; - dRect.setBounds(*this); // OPTIMIZATION: just use setRawBounds ? - double width = dRect.fRight - dRect.fLeft; - double height = dRect.fBottom - dRect.fTop; - return (width > height ? width : height) / gPrecisionUnit; + return ((fPts[1] - fPts[0]).length() + + (fPts[2] - fPts[1]).length() + + (fPts[3] - fPts[2]).length()) / gPrecisionUnit; } - /* classic one t subdivision */ static void interp_cubic_coords(const double* src, double* dst, double t) { double ab = SkDInterp(src[0], src[2], t); @@ -232,34 +229,53 @@ bool SkDCubic::isLinear(int startIndex, int endIndex) const { return approximately_zero_when_compared_to(distance, largest); } -bool SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t) { +// from http://www.cs.sunysb.edu/~qin/courses/geometry/4.pdf +// c(t) = a(1-t)^3 + 3bt(1-t)^2 + 3c(1-t)t^2 + dt^3 +// c'(t) = -3a(1-t)^2 + 3b((1-t)^2 - 2t(1-t)) + 3c(2t(1-t) - t^2) + 3dt^2 +// = 3(b-a)(1-t)^2 + 6(c-b)t(1-t) + 3(d-c)t^2 +static double derivative_at_t(const double* src, double t) { + double one_t = 1 - t; + double a = src[0]; + double b = src[2]; + double c = src[4]; + double d = src[6]; + return 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t); +} + +int SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t) { + SkDCubic cubic; + cubic.set(pointsPtr); + if (cubic.monotonicInX() && cubic.monotonicInY()) { + return 0; + } SkScalar d[3]; SkCubicType cubicType = SkClassifyCubic(pointsPtr, d); - if (cubicType == kLoop_SkCubicType) { - // crib code from gpu path utils that finds t values where loop self-intersects - // use it to find mid of t values which should be a friendly place to chop - SkScalar tempSqrt = SkScalarSqrt(4.f * d[0] * d[2] - 3.f * d[1] * d[1]); - SkScalar ls = d[1] - tempSqrt; - SkScalar lt = 2.f * d[0]; - SkScalar ms = d[1] + tempSqrt; - SkScalar mt = 2.f * d[0]; - if (roughly_between(0, ls, lt) && roughly_between(0, ms, mt)) { - ls = ls / lt; - ms = ms / mt; - SkASSERT(roughly_between(0, ls, 1) && roughly_between(0, ms, 1)); - *t = (ls + ms) / 2; - SkASSERT(roughly_between(0, *t, 1)); - return *t > 0 && *t < 1; + switch (cubicType) { + case kLoop_SkCubicType: { + // crib code from gpu path utils that finds t values where loop self-intersects + // use it to find mid of t values which should be a friendly place to chop + SkScalar tempSqrt = SkScalarSqrt(4.f * d[0] * d[2] - 3.f * d[1] * d[1]); + SkScalar ls = d[1] - tempSqrt; + SkScalar lt = 2.f * d[0]; + SkScalar ms = d[1] + tempSqrt; + SkScalar mt = 2.f * d[0]; + if (roughly_between(0, ls, lt) && roughly_between(0, ms, mt)) { + ls = ls / lt; + ms = ms / mt; + SkASSERT(roughly_between(0, ls, 1) && roughly_between(0, ms, 1)); + t[0] = (ls + ms) / 2; + SkASSERT(roughly_between(0, *t, 1)); + return (int) (t[0] > 0 && t[0] < 1); + } } - } else if (kSerpentine_SkCubicType == cubicType || kCusp_SkCubicType == cubicType) { - SkDCubic cubic; - cubic.set(pointsPtr); - double inflectionTs[2]; - int infTCount = cubic.findInflections(inflectionTs); - if (infTCount == 2) { + // fall through if no t value found + case kSerpentine_SkCubicType: + case kCusp_SkCubicType: { + double inflectionTs[2]; + int infTCount = cubic.findInflections(inflectionTs); double maxCurvature[3]; int roots = cubic.findMaxCurvature(maxCurvature); -#if DEBUG_CUBIC_SPLIT + #if DEBUG_CUBIC_SPLIT SkDebugf("%s\n", __FUNCTION__); cubic.dump(); for (int index = 0; index < infTCount; ++index) { @@ -276,19 +292,42 @@ bool SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t) { SkDLine perp = {{pt - dPt, pt + dPt}}; perp.dump(); } -#endif - for (int index = 0; index < roots; ++index) { - if (between(inflectionTs[0], maxCurvature[index], inflectionTs[1])) { - *t = maxCurvature[index]; - return *t > 0 && *t < 1; + #endif + if (infTCount == 2) { + for (int index = 0; index < roots; ++index) { + if (between(inflectionTs[0], maxCurvature[index], inflectionTs[1])) { + t[0] = maxCurvature[index]; + return (int) (t[0] > 0 && t[0] < 1); + } } + } else { + int resultCount = 0; + // FIXME: constant found through experimentation -- maybe there's a better way.... + double precision = cubic.calcPrecision() * 2; + for (int index = 0; index < roots; ++index) { + double testT = maxCurvature[index]; + if (0 >= testT || testT >= 1) { + continue; + } + // don't call dxdyAtT since we want (0,0) results + SkDVector dPt = { derivative_at_t(&cubic.fPts[0].fX, testT), + derivative_at_t(&cubic.fPts[0].fY, testT) }; + double dPtLen = dPt.length(); + if (dPtLen < precision) { + t[resultCount++] = testT; + } + } + if (!resultCount && infTCount == 1) { + t[0] = inflectionTs[0]; + resultCount = (int) (t[0] > 0 && t[0] < 1); + } + return resultCount; } - } else if (infTCount == 1) { - *t = inflectionTs[0]; - return *t > 0 && *t < 1; } + default: + ; } - return false; + return 0; } bool SkDCubic::monotonicInX() const { @@ -463,19 +502,6 @@ int SkDCubic::RootsReal(double A, double B, double C, double D, double s[3]) { return static_cast(roots - s); } -// from http://www.cs.sunysb.edu/~qin/courses/geometry/4.pdf -// c(t) = a(1-t)^3 + 3bt(1-t)^2 + 3c(1-t)t^2 + dt^3 -// c'(t) = -3a(1-t)^2 + 3b((1-t)^2 - 2t(1-t)) + 3c(2t(1-t) - t^2) + 3dt^2 -// = 3(b-a)(1-t)^2 + 6(c-b)t(1-t) + 3(d-c)t^2 -static double derivative_at_t(const double* src, double t) { - double one_t = 1 - t; - double a = src[0]; - double b = src[2]; - double c = src[4]; - double d = src[6]; - return 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t); -} - // OPTIMIZE? compute t^2, t(1-t), and (1-t)^2 and pass them to another version of derivative at t? SkDVector SkDCubic::dxdyAtT(double t) const { SkDVector result = { derivative_at_t(&fPts[0].fX, t), derivative_at_t(&fPts[0].fY, t) }; @@ -690,6 +716,15 @@ void SkDCubic::subDivide(const SkDPoint& a, const SkDPoint& d, } } +bool SkDCubic::toFloatPoints(SkPoint* pts) const { + const double* dCubic = &fPts[0].fX; + SkScalar* cubic = &pts[0].fX; + for (int index = 0; index < kPointCount * 2; ++index) { + *cubic++ = SkDoubleToScalar(*dCubic++); + } + return SkScalarsAreFinite(&pts->fX, kPointCount * 2); +} + double SkDCubic::top(const SkDCubic& dCurve, double startT, double endT, SkDPoint*topPt) const { double extremeTs[2]; double topT = -1; diff --git a/gfx/skia/skia/src/pathops/SkPathOpsCubic.h b/gfx/skia/skia/src/pathops/SkPathOpsCubic.h index 16bca7953319..2e8a5db3f762 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsCubic.h +++ b/gfx/skia/skia/src/pathops/SkPathOpsCubic.h @@ -11,11 +11,7 @@ #include "SkPath.h" #include "SkPathOpsPoint.h" -struct SkDCubicPair { - const SkDCubic& first() const { return (const SkDCubic&) pts[0]; } - const SkDCubic& second() const { return (const SkDCubic&) pts[3]; } - SkDPoint pts[7]; -}; +struct SkDCubicPair; struct SkDCubic { static const int kPointCount = 4; @@ -51,13 +47,15 @@ struct SkDCubic { double calcPrecision() const; SkDCubicPair chopAt(double t) const; static void Coefficients(const double* cubic, double* A, double* B, double* C, double* D); - static bool ComplexBreak(const SkPoint pts[4], SkScalar* t); + static int ComplexBreak(const SkPoint pts[4], SkScalar* t); int convexHull(char order[kPointCount]) const; void debugInit() { sk_bzero(fPts, sizeof(fPts)); } + void debugSet(const SkDPoint* pts); + void dump() const; // callable from the debugger when the implementation code is linked in void dumpID(int id) const; void dumpInner() const; @@ -72,6 +70,11 @@ struct SkDCubic { } int findMaxCurvature(double tValues[]) const; + +#ifdef SK_DEBUG + SkOpGlobalState* globalState() const { return fDebugGlobalState; } +#endif + bool hullIntersects(const SkDCubic& c2, bool* isLinear) const; bool hullIntersects(const SkDConic& c, bool* isLinear) const; bool hullIntersects(const SkDQuad& c2, bool* isLinear) const; @@ -87,6 +90,7 @@ struct SkDCubic { int searchRoots(double extremes[6], int extrema, double axisIntercept, SearchAxis xAxis, double* validRoots) const; + bool toFloatPoints(SkPoint* ) const; /** * Return the number of valid roots (0 < root < 1) for this cubic intersecting the * specified horizontal line. @@ -98,11 +102,14 @@ struct SkDCubic { */ int verticalIntersect(double xIntercept, double roots[3]) const; - const SkDCubic& set(const SkPoint pts[kPointCount]) { +// add debug only global pointer so asserts can be skipped by fuzzers + const SkDCubic& set(const SkPoint pts[kPointCount] + SkDEBUGPARAMS(SkOpGlobalState* state = nullptr)) { fPts[0] = pts[0]; fPts[1] = pts[1]; fPts[2] = pts[2]; fPts[3] = pts[3]; + SkDEBUGCODE(fDebugGlobalState = state); return *this; } @@ -125,8 +132,8 @@ struct SkDCubic { SkDQuad toQuad() const; static const int gPrecisionUnit; - SkDPoint fPts[kPointCount]; + SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); }; /* Given the set [0, 1, 2, 3], and two of the four members, compute an XOR mask @@ -147,4 +154,26 @@ inline int other_two(int one, int two) { return 1 >> (3 - (one ^ two)) ^ 3; } +struct SkDCubicPair { + const SkDCubic first() const { +#ifdef SK_DEBUG + SkDCubic result; + result.debugSet(&pts[0]); + return result; +#else + return (const SkDCubic&) pts[0]; +#endif + } + const SkDCubic second() const { +#ifdef SK_DEBUG + SkDCubic result; + result.debugSet(&pts[3]); + return result; +#else + return (const SkDCubic&) pts[3]; +#endif + } + SkDPoint pts[7]; +}; + #endif diff --git a/gfx/skia/skia/src/pathops/SkPathOpsDebug.cpp b/gfx/skia/skia/src/pathops/SkPathOpsDebug.cpp index e744c75658ec..45a11384882d 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsDebug.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsDebug.cpp @@ -8,10 +8,19 @@ #include "SkMutex.h" #include "SkOpCoincidence.h" #include "SkOpContour.h" +#include "SkOSFile.h" #include "SkPath.h" #include "SkPathOpsDebug.h" #include "SkString.h" +#if DEBUG_DUMP_VERIFY +bool SkPathOpsDebug::gDumpOp; // set to true to write op to file before a crash +bool SkPathOpsDebug::gVerifyOp; // set to true to compare result against regions +#endif + +bool SkPathOpsDebug::gRunFail; // set to true to check for success on tests known to fail +bool SkPathOpsDebug::gVeryVerbose; // set to true to run extensive checking tests + #undef FAIL_IF #define FAIL_IF(cond, coin) \ do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, coin); } while (false) @@ -27,10 +36,6 @@ class SkCoincidentSpans; -#if DEBUG_VALIDATE -extern bool FLAGS_runFail; -#endif - #if DEBUG_SORT int SkPathOpsDebug::gSortCountDefault = SK_MaxS32; int SkPathOpsDebug::gSortCount; @@ -58,6 +63,10 @@ bool SkPathOpsDebug::ChaseContains(const SkTDArray& chaseArray, return false; } #endif + +#if DEBUG_ACTIVE_SPANS +SkString SkPathOpsDebug::gActiveSpans; +#endif #if DEBUG_COIN @@ -277,7 +286,7 @@ static void move_nearby(SkPathOpsDebug::GlitchLog* glitches, const SkOpContourHe void SkOpGlobalState::debugAddToCoinChangedDict() { #if DEBUG_COINCIDENCE - CheckHealth(contourList); + SkPathOpsDebug::CheckHealth(fContourHead); #endif // see if next coincident operation makes a change; if so, record it SkPathOpsDebug::GlitchLog glitches; @@ -319,10 +328,20 @@ void SkOpGlobalState::debugAddToCoinChangedDict() { void SkPathOpsDebug::ShowActiveSpans(SkOpContourHead* contourList) { #if DEBUG_ACTIVE_SPANS + SkString str; SkOpContour* contour = contourList; do { - contour->debugShowActiveSpans(); + contour->debugShowActiveSpans(&str); } while ((contour = contour->next())); + if (!gActiveSpans.equals(str)) { + const char* s = str.c_str(); + const char* end; + while ((end = strchr(s, '\n'))) { + SkDebugf("%.*s", end - s + 1, s); + s = end + 1; + } + gActiveSpans.set(str); + } #endif } @@ -353,6 +372,7 @@ void SkPathOpsDebug::CheckHealth(SkOpContourHead* contourList) { for (int index = 0; index < kGlitchType_Count; ++index) { SkDebugf(mask & (1 << index) ? "x" : "-"); } + SkDebugf(" %s\n", contourList->globalState()->debugCoinDictEntry().fFunctionName); for (int index = 0; index < glitches.fGlitches.count(); ++index) { const SpanGlitch& glitch = glitches.fGlitches[index]; SkDebugf("%02d: ", index); @@ -477,14 +497,6 @@ void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) { } } -#if DEBUG_VALIDATE -void SkPathOpsDebug::SetPhase(SkOpContourHead* contourList, CoinID next, - int lineNumber, SkOpPhase phase) { - AddedCoin(contourList, next, 0, lineNumber); - contourList->globalState()->setPhase(phase); -} -#endif - bool SkPathOpsDebug::ValidWind(int wind) { return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF; } @@ -655,15 +667,9 @@ void SkOpGlobalState::debugResetLoopCounts() { } #endif -#ifdef SK_DEBUG -bool SkOpGlobalState::debugRunFail() const { -#if DEBUG_VALIDATE - return FLAGS_runFail; -#else - return false; -#endif +bool SkOpGlobalState::DebugRunFail() { + return SkPathOpsDebug::gRunFail; } -#endif // this is const so it can be called by const methods that overwise don't alter state #if DEBUG_VALIDATE || DEBUG_COIN @@ -699,8 +705,8 @@ void SkIntersections::debugResetLoopCount() { } #endif +#include "SkPathOpsConic.h" #include "SkPathOpsCubic.h" -#include "SkPathOpsQuad.h" SkDCubic SkDQuad::debugToCubic() const { SkDCubic cubic; @@ -714,6 +720,21 @@ SkDCubic SkDQuad::debugToCubic() const { return cubic; } +void SkDQuad::debugSet(const SkDPoint* pts) { + memcpy(fPts, pts, sizeof(fPts)); + SkDEBUGCODE(fDebugGlobalState = nullptr); +} + +void SkDCubic::debugSet(const SkDPoint* pts) { + memcpy(fPts, pts, sizeof(fPts)); + SkDEBUGCODE(fDebugGlobalState = nullptr); +} + +void SkDConic::debugSet(const SkDPoint* pts, SkScalar weight) { + fPts.debugSet(pts); + fWeight = weight; +} + void SkDRect::debugInit() { fLeft = fTop = fRight = fBottom = SK_ScalarNaN; } @@ -947,8 +968,8 @@ void SkOpSegment::debugMoveMultiples(SkPathOpsDebug::GlitchLog* glitches) const const SkOpSpanBase* test = &fHead; do { int addCount = test->spanAddsCount(); - SkASSERT(addCount >= 1); - if (addCount == 1) { +// SkASSERT(addCount >= 1); + if (addCount <= 1) { continue; } const SkOpPtT* startPtT = test->ptT(); @@ -1111,7 +1132,7 @@ void SkOpSegment::debugSetCoinT(int index, SkScalar t) const { #endif #if DEBUG_ACTIVE_SPANS -void SkOpSegment::debugShowActiveSpans() const { +void SkOpSegment::debugShowActiveSpans(SkString* str) const { debugValidate(); if (done()) { return; @@ -1128,34 +1149,34 @@ void SkOpSegment::debugShowActiveSpans() const { } lastId = this->debugID(); lastT = span->t(); - SkDebugf("%s id=%d", __FUNCTION__, this->debugID()); + str->appendf("%s id=%d", __FUNCTION__, this->debugID()); // since endpoints may have be adjusted, show actual computed curves SkDCurve curvePart; this->subDivide(span, span->next(), &curvePart); const SkDPoint* pts = curvePart.fCubic.fPts; - SkDebugf(" (%1.9g,%1.9g", pts[0].fX, pts[0].fY); + str->appendf(" (%1.9g,%1.9g", pts[0].fX, pts[0].fY); for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { - SkDebugf(" %1.9g,%1.9g", pts[vIndex].fX, pts[vIndex].fY); + str->appendf(" %1.9g,%1.9g", pts[vIndex].fX, pts[vIndex].fY); } if (SkPath::kConic_Verb == fVerb) { - SkDebugf(" %1.9gf", curvePart.fConic.fWeight); + str->appendf(" %1.9gf", curvePart.fConic.fWeight); } - SkDebugf(") t=%1.9g tEnd=%1.9g", span->t(), span->next()->t()); + str->appendf(") t=%1.9g tEnd=%1.9g", span->t(), span->next()->t()); if (span->windSum() == SK_MinS32) { - SkDebugf(" windSum=?"); + str->appendf(" windSum=?"); } else { - SkDebugf(" windSum=%d", span->windSum()); + str->appendf(" windSum=%d", span->windSum()); } if (span->oppValue() && span->oppSum() == SK_MinS32) { - SkDebugf(" oppSum=?"); + str->appendf(" oppSum=?"); } else if (span->oppValue() || span->oppSum() != SK_MinS32) { - SkDebugf(" oppSum=%d", span->oppSum()); + str->appendf(" oppSum=%d", span->oppSum()); } - SkDebugf(" windValue=%d", span->windValue()); + str->appendf(" windValue=%d", span->windValue()); if (span->oppValue() || span->oppSum() != SK_MinS32) { - SkDebugf(" oppValue=%d", span->oppValue()); + str->appendf(" oppValue=%d", span->oppValue()); } - SkDebugf("\n"); + str->appendf("\n"); } while ((span = span->next()->upCastable())); } #endif @@ -1355,8 +1376,8 @@ void SkOpAngle::debugValidate() const { } next = next->fNext; } while (next && next != first); - SkASSERT(wind == 0 || !FLAGS_runFail); - SkASSERT(opp == 0 || !FLAGS_runFail); + SkASSERT(wind == 0 || !SkPathOpsDebug::gRunFail); + SkASSERT(opp == 0 || !SkPathOpsDebug::gRunFail); #endif } @@ -1383,8 +1404,8 @@ void SkOpAngle::debugValidateNext() const { #ifdef SK_DEBUG void SkCoincidentSpans::debugStartCheck(const SkOpSpanBase* outer, const SkOpSpanBase* over, const SkOpGlobalState* debugState) const { - SkASSERT(coinPtTEnd()->span() == over || !debugState->debugRunFail()); - SkASSERT(oppPtTEnd()->span() == outer || !debugState->debugRunFail()); + SkASSERT(coinPtTEnd()->span() == over || !SkOpGlobalState::DebugRunFail()); + SkASSERT(oppPtTEnd()->span() == outer || !SkOpGlobalState::DebugRunFail()); } #endif @@ -1603,6 +1624,7 @@ void SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log) cons // for each coincident pair, match the spans // if the spans don't match, add the mssing pt to the segment and loop it in the opposite span void SkOpCoincidence::debugAddExpanded(SkPathOpsDebug::GlitchLog* log) const { +// DEBUG_SET_PHASE(); const SkCoincidentSpans* coin = this->fHead; if (!coin) { return; @@ -1612,7 +1634,7 @@ void SkOpCoincidence::debugAddExpanded(SkPathOpsDebug::GlitchLog* log) const { const SkOpPtT* oStartPtT = coin->oppPtTStart(); double priorT = startPtT->fT; double oPriorT = oStartPtT->fT; - FAIL_IF(startPtT->contains(oStartPtT), coin); + FAIL_IF(!startPtT->contains(oStartPtT), coin); SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd())); const SkOpSpanBase* start = startPtT->span(); const SkOpSpanBase* oStart = oStartPtT->span(); @@ -1647,14 +1669,15 @@ void SkOpCoincidence::debugAddExpanded(SkPathOpsDebug::GlitchLog* log) const { walk = walk->upCast()->next(); } while (!(walkOpp = walk->ptT()->contains(oSeg)) && walk != coin->coinPtTEnd()->span()); + FAIL_IF(!walkOpp, coin); nextT = walk->t(); oNextT = walkOpp->fT; } // use t ranges to guess which one is missing - double startRange = coin->coinPtTEnd()->fT - startPtT->fT; + double startRange = nextT - priorT; FAIL_IF(!startRange, coin); - double startPart = (test->t() - startPtT->fT) / startRange; - double oStartRange = coin->oppPtTEnd()->fT - oStartPtT->fT; + double startPart = (test->t() - priorT) / startRange; + double oStartRange = oNextT - oPriorT; FAIL_IF(!oStartRange, coin); double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange; FAIL_IF(startPart == oStartPart, coin); @@ -1688,21 +1711,6 @@ void SkOpCoincidence::debugAddExpanded(SkPathOpsDebug::GlitchLog* log) const { return; } -/* Commented-out lines keep this in sync with addIfMissing() */ -void SkOpCoincidence::debugAddIfMissing(SkPathOpsDebug::GlitchLog* log, const SkCoincidentSpans* outer, const SkOpPtT* over1s, - const SkOpPtT* over1e) const { -// SkASSERT(fTop); - if (fTop && alreadyAdded(fTop, outer, over1s, over1e)) { // in debug, fTop may be null - return; - } - if (fHead && alreadyAdded(fHead, outer, over1s, over1e)) { - return; - } - log->record(SkPathOpsDebug::kAddIfMissingCoin_Glitch, outer->coinPtTStart(), outer->coinPtTEnd(), over1s, over1e); - this->debugValidate(); - return; -} - /* Commented-out lines keep this in sync addIfMissing() */ // note that over1s, over1e, over2s, over2e are ordered void SkOpCoincidence::debugAddIfMissing(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* over1s, const SkOpPtT* over2s, @@ -2052,7 +2060,8 @@ void SkOpCoincidence::debugMark(SkPathOpsDebug::GlitchLog* log) const { const SkOpSegment* oSegment = oStart->segment(); const SkOpSpanBase* next = start; const SkOpSpanBase* oNext = oStart; - bool ordered = coin->ordered(); + bool ordered; + FAIL_IF(!coin->ordered(&ordered), coin); while ((next = next->upCast()->next()) != end) { FAIL_IF(!next->upCastable(), coin); if (next->upCast()->debugInsertCoincidence(log, oSegment, flipped, ordered), false) { @@ -2911,3 +2920,203 @@ void SkPathOpsDebug::ShowOnePath(const SkPath& path, const char* name, bool incl iter.setPath(path); showPathContours(iter, name); } + +#if DEBUG_DUMP_VERIFY +#include "SkData.h" +#include "SkStream.h" + +static void dump_path(FILE* file, const SkPath& path, bool force, bool dumpAsHex) { + SkDynamicMemoryWStream wStream; + path.dump(&wStream, force, dumpAsHex); + sk_sp data(wStream.detachAsData()); + fprintf(file, "%.*s\n", (int) data->size(), (char*) data->data()); +} + +static int dumpID = 0; + +void SkPathOpsDebug::DumpOp(const SkPath& one, const SkPath& two, SkPathOp op, + const char* testName) { + FILE* file = sk_fopen("op_dump.txt", kWrite_SkFILE_Flag); + DumpOp(file, one, two, op, testName); +} + +void SkPathOpsDebug::DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op, + const char* testName) { + const char* name = testName ? testName : "op"; + fprintf(file, + "\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n", + name, ++dumpID); + fprintf(file, " SkPath path;\n"); + fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", one.getFillType()); + dump_path(file, one, false, true); + fprintf(file, " SkPath path1(path);\n"); + fprintf(file, " path.reset();\n"); + fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", two.getFillType()); + dump_path(file, two, false, true); + fprintf(file, " SkPath path2(path);\n"); + fprintf(file, " testPathOp(reporter, path1, path2, (SkPathOp) %d, filename);\n", op); + fprintf(file, "}\n\n"); + fclose(file); +} + +void SkPathOpsDebug::DumpSimplify(const SkPath& path, const char* testName) { + FILE* file = sk_fopen("simplify_dump.txt", kWrite_SkFILE_Flag); + DumpSimplify(file, path, testName); +} + +void SkPathOpsDebug::DumpSimplify(FILE* file, const SkPath& path, const char* testName) { + const char* name = testName ? testName : "simplify"; + fprintf(file, + "\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n", + name, ++dumpID); + fprintf(file, " SkPath path;\n"); + fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", path.getFillType()); + dump_path(file, path, false, true); + fprintf(file, " testSimplify(reporter, path, filename);\n"); + fprintf(file, "}\n\n"); + fclose(file); +} + +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkPaint.h" + +const int bitWidth = 64; +const int bitHeight = 64; + +static void debug_scale_matrix(const SkPath& one, const SkPath* two, SkMatrix& scale) { + SkRect larger = one.getBounds(); + if (two) { + larger.join(two->getBounds()); + } + SkScalar largerWidth = larger.width(); + if (largerWidth < 4) { + largerWidth = 4; + } + SkScalar largerHeight = larger.height(); + if (largerHeight < 4) { + largerHeight = 4; + } + SkScalar hScale = (bitWidth - 2) / largerWidth; + SkScalar vScale = (bitHeight - 2) / largerHeight; + scale.reset(); + scale.preScale(hScale, vScale); + larger.fLeft *= hScale; + larger.fRight *= hScale; + larger.fTop *= vScale; + larger.fBottom *= vScale; + SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft + : 16000 < larger.fRight ? 16000 - larger.fRight : 0; + SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop + : 16000 < larger.fBottom ? 16000 - larger.fBottom : 0; + scale.preTranslate(dx, dy); +} + +static int debug_paths_draw_the_same(const SkPath& one, const SkPath& two, SkBitmap& bits) { + if (bits.width() == 0) { + bits.allocN32Pixels(bitWidth * 2, bitHeight); + } + SkCanvas canvas(bits); + canvas.drawColor(SK_ColorWHITE); + SkPaint paint; + canvas.save(); + const SkRect& bounds1 = one.getBounds(); + canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); + canvas.drawPath(one, paint); + canvas.restore(); + canvas.save(); + canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); + canvas.drawPath(two, paint); + canvas.restore(); + int errors = 0; + for (int y = 0; y < bitHeight - 1; ++y) { + uint32_t* addr1 = bits.getAddr32(0, y); + uint32_t* addr2 = bits.getAddr32(0, y + 1); + uint32_t* addr3 = bits.getAddr32(bitWidth, y); + uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1); + for (int x = 0; x < bitWidth - 1; ++x) { + // count 2x2 blocks + bool err = addr1[x] != addr3[x]; + if (err) { + errors += addr1[x + 1] != addr3[x + 1] + && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1]; + } + } + } + return errors; +} + +void SkPathOpsDebug::ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op) { + SkDebugf("// Op did not expect failure\n"); + DumpOp(stderr, one, two, op, "opTest"); + fflush(stderr); +} + +void SkPathOpsDebug::VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op, + const SkPath& result) { + SkPath pathOut, scaledPathOut; + SkRegion rgnA, rgnB, openClip, rgnOut; + openClip.setRect(-16000, -16000, 16000, 16000); + rgnA.setPath(one, openClip); + rgnB.setPath(two, openClip); + rgnOut.op(rgnA, rgnB, (SkRegion::Op) op); + rgnOut.getBoundaryPath(&pathOut); + SkMatrix scale; + debug_scale_matrix(one, &two, scale); + SkRegion scaledRgnA, scaledRgnB, scaledRgnOut; + SkPath scaledA, scaledB; + scaledA.addPath(one, scale); + scaledA.setFillType(one.getFillType()); + scaledB.addPath(two, scale); + scaledB.setFillType(two.getFillType()); + scaledRgnA.setPath(scaledA, openClip); + scaledRgnB.setPath(scaledB, openClip); + scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) op); + scaledRgnOut.getBoundaryPath(&scaledPathOut); + SkBitmap bitmap; + SkPath scaledOut; + scaledOut.addPath(result, scale); + scaledOut.setFillType(result.getFillType()); + int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap); + const int MAX_ERRORS = 9; + if (errors > MAX_ERRORS) { + fprintf(stderr, "// Op did not expect errors=%d\n", errors); + DumpOp(stderr, one, two, op, "opTest"); + fflush(stderr); + } +} + +void SkPathOpsDebug::ReportSimplifyFail(const SkPath& path) { + SkDebugf("// Simplify did not expect failure\n"); + DumpSimplify(stderr, path, "simplifyTest"); + fflush(stderr); +} + +void SkPathOpsDebug::VerifySimplify(const SkPath& path, const SkPath& result) { + SkPath pathOut, scaledPathOut; + SkRegion rgnA, openClip, rgnOut; + openClip.setRect(-16000, -16000, 16000, 16000); + rgnA.setPath(path, openClip); + rgnOut.getBoundaryPath(&pathOut); + SkMatrix scale; + debug_scale_matrix(path, nullptr, scale); + SkRegion scaledRgnA; + SkPath scaledA; + scaledA.addPath(path, scale); + scaledA.setFillType(path.getFillType()); + scaledRgnA.setPath(scaledA, openClip); + scaledRgnA.getBoundaryPath(&scaledPathOut); + SkBitmap bitmap; + SkPath scaledOut; + scaledOut.addPath(result, scale); + scaledOut.setFillType(result.getFillType()); + int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap); + const int MAX_ERRORS = 9; + if (errors > MAX_ERRORS) { + fprintf(stderr, "// Simplify did not expect errors=%d\n", errors); + DumpSimplify(stderr, path, "simplifyTest"); + fflush(stderr); + } +} + +#endif diff --git a/gfx/skia/skia/src/pathops/SkPathOpsDebug.h b/gfx/skia/skia/src/pathops/SkPathOpsDebug.h index f07d7d0524f1..97fa534a2a71 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsDebug.h +++ b/gfx/skia/skia/src/pathops/SkPathOpsDebug.h @@ -22,7 +22,7 @@ class SkOpContourHead; #define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging #endif -#define DEBUG_UNDER_DEVELOPMENT 1 +#define DEBUG_UNDER_DEVELOPMENT 0 #define ONE_OFF_DEBUG 0 #define ONE_OFF_DEBUG_MATHEMATICA 0 @@ -58,6 +58,7 @@ class SkOpContourHead; #define DEBUG_CUBIC_BINARY_SEARCH 0 #define DEBUG_CUBIC_SPLIT 0 #define DEBUG_DUMP_SEGMENTS 0 +#define DEBUG_DUMP_VERIFY 0 #define DEBUG_FLOW 0 #define DEBUG_LIMIT_WIND_SUM 0 #define DEBUG_MARK_DONE 0 @@ -81,12 +82,13 @@ class SkOpContourHead; #define DEBUG_ALIGNMENT 0 #define DEBUG_ANGLE 1 #define DEBUG_ASSEMBLE 1 -#define DEBUG_COINCIDENCE 01 +#define DEBUG_COINCIDENCE 1 #define DEBUG_COINCIDENCE_DUMP 0 #define DEBUG_COINCIDENCE_ORDER 0 // tight arc quads may generate out-of-order coincdence spans -#define DEBUG_COINCIDENCE_VERBOSE 01 +#define DEBUG_COINCIDENCE_VERBOSE 1 #define DEBUG_CUBIC_BINARY_SEARCH 0 #define DEBUG_CUBIC_SPLIT 1 +#define DEBUG_DUMP_VERIFY 0 #define DEBUG_DUMP_SEGMENTS 1 #define DEBUG_FLOW 1 #define DEBUG_LIMIT_WIND_SUM 15 @@ -371,6 +373,31 @@ public: static void DumpCoinDict(); static void DumpGlitchType(GlitchType ); #endif + + static bool gRunFail; + static bool gVeryVerbose; + +#if DEBUG_DUMP_VERIFY + static bool gDumpOp; + static bool gVerifyOp; + + static void DumpOp(const SkPath& one, const SkPath& two, SkPathOp op, + const char* testName); + static void DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op, + const char* testName); + static void DumpSimplify(const SkPath& path, const char* testName); + static void DumpSimplify(FILE* file, const SkPath& path, const char* testName); + static void ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op); + static void ReportSimplifyFail(const SkPath& path); + static void VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op, + const SkPath& result); + static void VerifySimplify(const SkPath& path, const SkPath& result); +#endif + +#if DEBUG_ACTIVE_SPANS + static SkString gActiveSpans; +#endif + }; struct SkDQuad; diff --git a/gfx/skia/skia/src/pathops/SkPathOpsOp.cpp b/gfx/skia/skia/src/pathops/SkPathOpsOp.cpp index e622451a9253..fd08aaaad140 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsOp.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsOp.cpp @@ -198,44 +198,6 @@ static const bool gOutInverse[kReverseDifference_SkPathOp + 1][2][2] = { {{ false, true }, { false, false }}, // rev diff }; -#define DEBUGGING_PATHOPS_FROM_HOST 0 // enable to debug svg in chrome -- note path hardcoded below -#if DEBUGGING_PATHOPS_FROM_HOST -#include "SkData.h" -#include "SkStream.h" - -static void dump_path(FILE* file, const SkPath& path, bool force, bool dumpAsHex) { - SkDynamicMemoryWStream wStream; - path.dump(&wStream, force, dumpAsHex); - sk_sp data(wStream.detachAsData()); - fprintf(file, "%.*s\n", (int) data->size(), (char*) data->data()); -} - -static int dumpID = 0; - -static void dump_op(const SkPath& one, const SkPath& two, SkPathOp op) { -#if SK_BUILD_FOR_MAC - FILE* file = fopen("/Users/caryclark/Documents/svgop.txt", "w"); -#else - FILE* file = fopen("/usr/local/google/home/caryclark/Documents/svgop.txt", "w"); -#endif - fprintf(file, - "\nstatic void fuzz763_%d(skiatest::Reporter* reporter, const char* filename) {\n", - ++dumpID); - fprintf(file, " SkPath path;\n"); - fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", one.getFillType()); - dump_path(file, one, false, true); - fprintf(file, " SkPath path1(path);\n"); - fprintf(file, " path.reset();\n"); - fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", two.getFillType()); - dump_path(file, two, false, true); - fprintf(file, " SkPath path2(path);\n"); - fprintf(file, " testPathOp(reporter, path1, path2, (SkPathOp) %d, filename);\n", op); - fprintf(file, "}\n"); - fclose(file); -} -#endif - - #if DEBUG_T_SECT_LOOP_COUNT #include "SkMutex.h" @@ -255,14 +217,20 @@ extern void (*gVerboseFinalize)(); bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char* testName)) { - SkChunkAlloc allocator(4096); // FIXME: add a constant expression here, tune + char storage[4096]; + SkArenaAlloc allocator(storage); // FIXME: add a constant expression here, tune SkOpContour contour; SkOpContourHead* contourList = static_cast(&contour); SkOpGlobalState globalState(contourList, &allocator SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName)); SkOpCoincidence coincidence(&globalState); -#if DEBUGGING_PATHOPS_FROM_HOST - dump_op(one, two, op); +#if DEBUG_DUMP_VERIFY +#ifndef SK_DEBUG + const char* testName = "release"; +#endif + if (SkPathOpsDebug::gDumpOp) { + SkPathOpsDebug::DumpOp(one, two, op, testName); + } #endif op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()]; SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isInverseFillType()] @@ -351,122 +319,16 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result return true; } -#define DEBUG_VERIFY 0 - -#if DEBUG_VERIFY -#include "SkBitmap.h" -#include "SkCanvas.h" -#include "SkPaint.h" - -const int bitWidth = 64; -const int bitHeight = 64; - -static void debug_scale_matrix(const SkPath& one, const SkPath& two, SkMatrix& scale) { - SkRect larger = one.getBounds(); - larger.join(two.getBounds()); - SkScalar largerWidth = larger.width(); - if (largerWidth < 4) { - largerWidth = 4; - } - SkScalar largerHeight = larger.height(); - if (largerHeight < 4) { - largerHeight = 4; - } - SkScalar hScale = (bitWidth - 2) / largerWidth; - SkScalar vScale = (bitHeight - 2) / largerHeight; - scale.reset(); - scale.preScale(hScale, vScale); - larger.fLeft *= hScale; - larger.fRight *= hScale; - larger.fTop *= vScale; - larger.fBottom *= vScale; - SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft - : 16000 < larger.fRight ? 16000 - larger.fRight : 0; - SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop - : 16000 < larger.fBottom ? 16000 - larger.fBottom : 0; - scale.preTranslate(dx, dy); -} - -static int debug_paths_draw_the_same(const SkPath& one, const SkPath& two, SkBitmap& bits) { - if (bits.width() == 0) { - bits.allocN32Pixels(bitWidth * 2, bitHeight); - } - SkCanvas canvas(bits); - canvas.drawColor(SK_ColorWHITE); - SkPaint paint; - canvas.save(); - const SkRect& bounds1 = one.getBounds(); - canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); - canvas.drawPath(one, paint); - canvas.restore(); - canvas.save(); - canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); - canvas.drawPath(two, paint); - canvas.restore(); - int errors = 0; - for (int y = 0; y < bitHeight - 1; ++y) { - uint32_t* addr1 = bits.getAddr32(0, y); - uint32_t* addr2 = bits.getAddr32(0, y + 1); - uint32_t* addr3 = bits.getAddr32(bitWidth, y); - uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1); - for (int x = 0; x < bitWidth - 1; ++x) { - // count 2x2 blocks - bool err = addr1[x] != addr3[x]; - if (err) { - errors += addr1[x + 1] != addr3[x + 1] - && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1]; - } - } - } - return errors; -} - -#endif - bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { -#if DEBUG_VERIFY - if (!OpDebug(one, two, op, result SkDEBUGPARAMS(nullptr))) { - SkDebugf("%s did not expect failure\none: fill=%d\n", __FUNCTION__, one.getFillType()); - one.dumpHex(); - SkDebugf("two: fill=%d\n", two.getFillType()); - two.dumpHex(); - SkASSERT(0); - return false; +#if DEBUG_DUMP_VERIFY + if (SkPathOpsDebug::gVerifyOp) { + if (!OpDebug(one, two, op, result SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr))) { + SkPathOpsDebug::ReportOpFail(one, two, op); + return false; + } + SkPathOpsDebug::VerifyOp(one, two, op, *result); + return true; } - SkPath pathOut, scaledPathOut; - SkRegion rgnA, rgnB, openClip, rgnOut; - openClip.setRect(-16000, -16000, 16000, 16000); - rgnA.setPath(one, openClip); - rgnB.setPath(two, openClip); - rgnOut.op(rgnA, rgnB, (SkRegion::Op) op); - rgnOut.getBoundaryPath(&pathOut); - SkMatrix scale; - debug_scale_matrix(one, two, scale); - SkRegion scaledRgnA, scaledRgnB, scaledRgnOut; - SkPath scaledA, scaledB; - scaledA.addPath(one, scale); - scaledA.setFillType(one.getFillType()); - scaledB.addPath(two, scale); - scaledB.setFillType(two.getFillType()); - scaledRgnA.setPath(scaledA, openClip); - scaledRgnB.setPath(scaledB, openClip); - scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) op); - scaledRgnOut.getBoundaryPath(&scaledPathOut); - SkBitmap bitmap; - SkPath scaledOut; - scaledOut.addPath(*result, scale); - scaledOut.setFillType(result->getFillType()); - int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap); - const int MAX_ERRORS = 9; - if (errors > MAX_ERRORS) { - SkDebugf("%s did not expect failure\none: fill=%d\n", __FUNCTION__, one.getFillType()); - one.dumpHex(); - SkDebugf("two: fill=%d\n", two.getFillType()); - two.dumpHex(); - SkASSERT(0); - } - return true; -#else - return OpDebug(one, two, op, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr)); #endif + return OpDebug(one, two, op, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr)); } diff --git a/gfx/skia/skia/src/pathops/SkPathOpsQuad.h b/gfx/skia/skia/src/pathops/SkPathOpsQuad.h index 32cfe58ecf81..34740d6b1dee 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsQuad.h +++ b/gfx/skia/skia/src/pathops/SkPathOpsQuad.h @@ -40,17 +40,21 @@ struct SkDQuad { sk_bzero(fPts, sizeof(fPts)); } + void debugSet(const SkDPoint* pts); + SkDQuad flip() const { - SkDQuad result = {{fPts[2], fPts[1], fPts[0]}}; + SkDQuad result = {{fPts[2], fPts[1], fPts[0]} SkDEBUGPARAMS(fDebugGlobalState) }; return result; } static bool IsConic() { return false; } - const SkDQuad& set(const SkPoint pts[kPointCount]) { + const SkDQuad& set(const SkPoint pts[kPointCount] + SkDEBUGPARAMS(SkOpGlobalState* state = nullptr)) { fPts[0] = pts[0]; fPts[1] = pts[1]; fPts[2] = pts[2]; + SkDEBUGCODE(fDebugGlobalState = state); return *this; } @@ -63,6 +67,10 @@ struct SkDQuad { SkDVector dxdyAtT(double t) const; static int FindExtrema(const double src[], double tValue[1]); +#ifdef SK_DEBUG + SkOpGlobalState* globalState() const { return fDebugGlobalState; } +#endif + /** * Return the number of valid roots (0 < root < 1) for this cubic intersecting the * specified horizontal line. @@ -106,8 +114,7 @@ struct SkDQuad { void dumpID(int id) const; void dumpInner() const; -private: -// static double Tangent(const double* quadratic, double t); // uncalled + SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); }; #endif diff --git a/gfx/skia/skia/src/pathops/SkPathOpsRect.h b/gfx/skia/skia/src/pathops/SkPathOpsRect.h index d4e5f5489a4f..1efbb8c6ea64 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsRect.h +++ b/gfx/skia/skia/src/pathops/SkPathOpsRect.h @@ -64,6 +64,10 @@ struct SkDRect { } void setBounds(const SkDQuad& curve, const SkDQuad& sub, double tStart, double tEnd); + + bool valid() const { + return fLeft <= fRight && fTop <= fBottom; + } }; #endif diff --git a/gfx/skia/skia/src/pathops/SkPathOpsSimplify.cpp b/gfx/skia/skia/src/pathops/SkPathOpsSimplify.cpp index f9f8f5c71ea6..e671ab81a9d0 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsSimplify.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsSimplify.cpp @@ -84,30 +84,25 @@ static bool bridgeWinding(SkOpContourHead* contourList, SkPathWriter* simple) { // returns true if all edges were processed static bool bridgeXor(SkOpContourHead* contourList, SkPathWriter* simple) { - SkOpSegment* current; - SkOpSpanBase* start; - SkOpSpanBase* end; bool unsortable = false; - while ((current = FindUndone(contourList, &start, &end))) { + do { + SkOpSpan* span = FindUndone(contourList); + if (!span) { + break; + } + SkOpSegment* current = span->segment(); + SkOpSpanBase* start = span->next(); + SkOpSpanBase* end = span; do { if (!unsortable && current->done()) { - SkPathOpsDebug::ShowActiveSpans(contourList); + break; } SkASSERT(unsortable || !current->done()); SkOpSpanBase* nextStart = start; SkOpSpanBase* nextEnd = end; - SkOpSegment* next = current->findNextXor(&nextStart, &nextEnd, &unsortable); + SkOpSegment* next = current->findNextXor(&nextStart, &nextEnd, + &unsortable); if (!next) { - if (!unsortable && simple->hasMove() - && current->verb() != SkPath::kLine_Verb - && !simple->isClosed()) { - if (!current->addCurveTo(start, end, simple)) { - return false; - } - if (!simple->isClosed()) { - SkPathOpsDebug::ShowActiveSpans(contourList); - } - } break; } #if DEBUG_FLOW @@ -123,7 +118,6 @@ static bool bridgeXor(SkOpContourHead* contourList, SkPathWriter* simple) { end = nextEnd; } while (!simple->isClosed() && (!unsortable || !start->starter(end)->done())); if (!simple->isClosed()) { - SkASSERT(unsortable); SkOpSpan* spanStart = start->starter(end); if (!spanStart->done()) { if (!current->addCurveTo(start, end, simple)) { @@ -134,7 +128,7 @@ static bool bridgeXor(SkOpContourHead* contourList, SkPathWriter* simple) { } simple->finishContour(); SkPathOpsDebug::ShowActiveSpans(contourList); - } + } while (true); return true; } @@ -152,12 +146,21 @@ bool SimplifyDebug(const SkPath& path, SkPath* result return true; } // turn path into list of segments - SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune + char storage[4096]; + SkArenaAlloc allocator(storage); // FIXME: constant-ize, tune SkOpContour contour; SkOpContourHead* contourList = static_cast(&contour); SkOpGlobalState globalState(contourList, &allocator SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName)); SkOpCoincidence coincidence(&globalState); +#if DEBUG_DUMP_VERIFY +#ifndef SK_DEBUG + const char* testName = "release"; +#endif + if (SkPathOpsDebug::gDumpOp) { + SkPathOpsDebug::DumpSimplify(path, testName); + } +#endif SkScalar scaleFactor = ScaleFactor(path); SkPath scaledPath; const SkPath* workingPath; @@ -218,5 +221,15 @@ bool SimplifyDebug(const SkPath& path, SkPath* result } bool Simplify(const SkPath& path, SkPath* result) { +#if DEBUG_DUMP_VERIFY + if (SkPathOpsDebug::gVerifyOp) { + if (!SimplifyDebug(path, result SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr))) { + SkPathOpsDebug::ReportSimplifyFail(path); + return false; + } + SkPathOpsDebug::VerifySimplify(path, *result); + return true; + } +#endif return SimplifyDebug(path, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr)); } diff --git a/gfx/skia/skia/src/pathops/SkPathOpsTSect.cpp b/gfx/skia/skia/src/pathops/SkPathOpsTSect.cpp index 3e7817ca9e91..9bff5af4f0a7 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsTSect.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsTSect.cpp @@ -9,54 +9,54 @@ int SkIntersections::intersect(const SkDQuad& quad1, const SkDQuad& quad2) { SkTSect sect1(quad1 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect sect2(quad2 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect::BinarySearch(§1, §2, this); return used(); } int SkIntersections::intersect(const SkDConic& conic, const SkDQuad& quad) { SkTSect sect1(conic - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect sect2(quad - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect::BinarySearch(§1, §2, this); return used(); } int SkIntersections::intersect(const SkDConic& conic1, const SkDConic& conic2) { SkTSect sect1(conic1 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect sect2(conic2 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect::BinarySearch(§1, §2, this); return used(); } int SkIntersections::intersect(const SkDCubic& cubic, const SkDQuad& quad) { SkTSect sect1(cubic - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect sect2(quad - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect::BinarySearch(§1, §2, this); return used(); } int SkIntersections::intersect(const SkDCubic& cubic, const SkDConic& conic) { SkTSect sect1(cubic - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect sect2(conic - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect::BinarySearch(§1, §2, this); return used(); } int SkIntersections::intersect(const SkDCubic& cubic1, const SkDCubic& cubic2) { SkTSect sect1(cubic1 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect sect2(cubic2 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect::BinarySearch(§1, §2, this); return used(); } diff --git a/gfx/skia/skia/src/pathops/SkPathOpsTSect.h b/gfx/skia/skia/src/pathops/SkPathOpsTSect.h index a04a4e442fc8..ef0799de4f35 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsTSect.h +++ b/gfx/skia/skia/src/pathops/SkPathOpsTSect.h @@ -7,7 +7,7 @@ #ifndef SkPathOpsTSect_DEFINED #define SkPathOpsTSect_DEFINED -#include "SkChunkAlloc.h" +#include "SkArenaAlloc.h" #include "SkPathOpsBounds.h" #include "SkPathOpsRect.h" #include "SkIntersections.h" @@ -85,7 +85,7 @@ struct SkTSpanBounded { template class SkTSpan { public: - void addBounded(SkTSpan* , SkChunkAlloc* ); + void addBounded(SkTSpan* , SkArenaAlloc* ); double closestBoundedT(const SkDPoint& pt) const; bool contains(double t) const; @@ -137,7 +137,7 @@ public: int hullsIntersect(SkTSpan* span, bool* start, bool* oppStart); void init(const TCurve& ); - void initBounds(const TCurve& ); + bool initBounds(const TCurve& ); bool isBounded() const { return fBounded != nullptr; @@ -174,11 +174,11 @@ public: initBounds(curve); } - bool split(SkTSpan* work, SkChunkAlloc* heap) { + bool split(SkTSpan* work, SkArenaAlloc* heap) { return splitAt(work, (work->fStartT + work->fEndT) * 0.5, heap); } - bool splitAt(SkTSpan* work, double t, SkChunkAlloc* heap); + bool splitAt(SkTSpan* work, double t, SkArenaAlloc* heap); double startT() const { return fStartT; @@ -315,9 +315,15 @@ private: bool removeSpan(SkTSpan* span); void removeSpanRange(SkTSpan* first, SkTSpan* last); void removeSpans(SkTSpan* span, SkTSect* opp); + void removedEndCheck(SkTSpan* span); + + void resetRemovedEnds() { + fRemovedStartT = fRemovedEndT = false; + } + SkTSpan* spanAtT(double t, SkTSpan** priorSpan); SkTSpan* tail(); - void trim(SkTSpan* span, SkTSect* opp); + bool trim(SkTSpan* span, SkTSect* opp); void unlinkSpan(SkTSpan* span); bool updateBounded(SkTSpan* first, SkTSpan* last, SkTSpan* oppFirst); @@ -325,7 +331,7 @@ private: void validateBounded() const; const TCurve& fCurve; - SkChunkAlloc fHeap; + SkArenaAlloc fHeap; SkTSpan* fHead; SkTSpan* fCoincident; SkTSpan* fDeleted; @@ -351,7 +357,7 @@ void SkTCoincident::setPerp(const TCurve& c1, double t, const SkDPoint& cPt, const OppCurve& c2) { SkDVector dxdy = c1.dxdyAtT(t); SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; - SkIntersections i; + SkIntersections i SkDEBUGCODE((c1.globalState())); int used = i.intersectRay(c2, perp); // only keep closest if (used == 0 || used == 3) { @@ -383,9 +389,8 @@ void SkTCoincident::setPerp(const TCurve& c1, double t, } template -void SkTSpan::addBounded(SkTSpan* span, SkChunkAlloc* heap) { - SkTSpanBounded* bounded = new (heap->allocThrow( - sizeof(SkTSpanBounded)))(SkTSpanBounded); +void SkTSpan::addBounded(SkTSpan* span, SkArenaAlloc* heap) { + SkTSpanBounded* bounded = heap->make>(); bounded->fBounded = span; bounded->fNext = fBounded; fBounded = bounded; @@ -565,7 +570,7 @@ void SkTSpan::init(const TCurve& c) { } template -void SkTSpan::initBounds(const TCurve& c) { +bool SkTSpan::initBounds(const TCurve& c) { fPart = c.subDivide(fStartT, fEndT); fBounds.setBounds(fPart); fCoinStart.init(); @@ -579,6 +584,7 @@ void SkTSpan::initBounds(const TCurve& c) { SkDebugf(""); // for convenient breakpoints } #endif + return fBounds.valid(); } template @@ -749,7 +755,7 @@ bool SkTSpan::removeBounded(const SkTSpan* o } template -bool SkTSpan::splitAt(SkTSpan* work, double t, SkChunkAlloc* heap) { +bool SkTSpan::splitAt(SkTSpan* work, double t, SkArenaAlloc* heap) { fStartT = t; fEndT = work->fEndT; if (fStartT == fEndT) { @@ -851,7 +857,7 @@ void SkTSpan::validatePerpPt(double t, const SkDPoint& pt) con template -SkTSect::SkTSect(const TCurve& c +SkTSect::SkTSect(const TCurve& c SkDEBUGPARAMS(SkOpGlobalState* debugGlobalState) PATH_OPS_DEBUG_T_SECT_PARAMS(int id)) : fCurve(c) @@ -864,7 +870,8 @@ SkTSect::SkTSect(const TCurve& c PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugCount(0)) PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugAllocatedCount(0)) { - fHead = addOne(); + this->resetRemovedEnds(); + fHead = this->addOne(); SkDEBUGCODE(fHead->debugSetGlobalState(debugGlobalState)); fHead->init(c); } @@ -876,8 +883,7 @@ SkTSpan* SkTSect::addOne() { result = fDeleted; fDeleted = result->fNext; } else { - result = new (fHeap.allocThrow(sizeof(SkTSpan)))( - SkTSpan); + result = fHeap.make>(); #if DEBUG_T_SECT ++fDebugAllocatedCount; #endif @@ -984,6 +990,9 @@ SkTSpan* SkTSect::boundsMax() const { template bool SkTSect::coincidentCheck(SkTSect* sect2) { SkTSpan* first = fHead; + if (!first) { + return false; + } SkTSpan* last, * next; do { int consecutive = this->countConsecutiveSpans(first, &last); @@ -1151,6 +1160,7 @@ template bool SkTSect::deleteEmptySpans() { SkTSpan* test; SkTSpan* next = fHead; + int safetyHatch = 1000; while ((test = next)) { next = test->fNext; if (!test->fBounded) { @@ -1158,6 +1168,9 @@ bool SkTSect::deleteEmptySpans() { return false; } } + if (--safetyHatch < 0) { + return false; + } } return true; } @@ -1206,6 +1219,7 @@ bool SkTSect::extractCoincident( } } else { SkDEBUGCODE(coinStart = first->fStartT); + FAIL_IF(!oppFirst); SkDEBUGCODE(oppStartT = oppMatched ? oppFirst->fStartT : oppFirst->fEndT); } // FIXME: incomplete : if we're not at the end, find end of coin @@ -1286,7 +1300,7 @@ SkTSpan* SkTSect::findCoincidentRun( work->validatePerpT(work->fCoinStart.perpT()); work->validatePerpPt(work->fCoinStart.perpT(), work->fCoinStart.perpPt()); #endif - SkASSERT(work->hasOppT(work->fCoinStart.perpT())); + SkOPASSERT(work->hasOppT(work->fCoinStart.perpT())); if (!work->fCoinEnd.isMatch()) { break; } @@ -1358,7 +1372,9 @@ int SkTSect::intersects(SkTSpan* span, if (!sects) { return -1; } + this->removedEndCheck(span); span->fStartT = span->fEndT = i[0][0]; + opp->removedEndCheck(oppSpan); oppSpan->fStartT = oppSpan->fEndT = i[1][0]; return *oppResult = 2; } @@ -1400,7 +1416,8 @@ template int SkTSect::linesIntersect(SkTSpan* span, SkTSect* opp, SkTSpan* oppSpan, SkIntersections* i) { - SkIntersections thisRayI, oppRayI; + SkIntersections thisRayI SkDEBUGCODE((span->fDebugGlobalState)); + SkIntersections oppRayI SkDEBUGCODE((span->fDebugGlobalState)); SkDLine thisLine = {{ span->fPart[0], span->fPart[TCurve::kPointLast] }}; SkDLine oppLine = {{ oppSpan->fPart[0], oppSpan->fPart[OppCurve::kPointLast] }}; int loopCount = 0; @@ -1594,6 +1611,9 @@ void SkTSect::mergeCoincidence(SkTSect* sect SkTSpan* smaller = nullptr; SkTSpan* test = fCoincident; do { + if (!test) { + return; + } if (test->fStartT < smallLimit) { continue; } @@ -1615,7 +1635,7 @@ void SkTSect::mergeCoincidence(SkTSect* sect if (test->fStartT < smaller->fEndT) { continue; } - SkASSERT(test->fStartT != smaller->fEndT); + SkOPASSERT(test->fStartT != smaller->fEndT); if (larger && larger->fStartT < test->fStartT) { continue; } @@ -1729,13 +1749,18 @@ void SkTSect::removeCoincident(SkTSpan* span } template -bool SkTSect::removeSpan(SkTSpan* span) { +void SkTSect::removedEndCheck(SkTSpan* span) { if (!span->fStartT) { fRemovedStartT = true; } if (1 == span->fEndT) { fRemovedEndT = true; } +} + +template +bool SkTSect::removeSpan(SkTSpan* span) {\ + this->removedEndCheck(span); this->unlinkSpan(span); return this->markSpanGone(span); } @@ -1807,9 +1832,9 @@ SkTSpan* SkTSect::tail() { /* Each span has a range of opposite spans it intersects. After the span is split in two, adjust the range to its new size */ template -void SkTSect::trim(SkTSpan* span, +bool SkTSect::trim(SkTSpan* span, SkTSect* opp) { - span->initBounds(fCurve); + FAIL_IF(!span->initBounds(fCurve)); const SkTSpanBounded* testBounded = span->fBounded; while (testBounded) { SkTSpan* test = testBounded->fBounded; @@ -1823,7 +1848,7 @@ void SkTSect::trim(SkTSpan* span, if (sects == 2) { span->initBounds(fCurve); this->removeAllBut(test, span, opp); - return; + return true; } } else { if (span->removeBounded(test)) { @@ -1835,6 +1860,7 @@ void SkTSect::trim(SkTSpan* span, } testBounded = next; } + return true; } template @@ -2003,7 +2029,7 @@ struct SkClosestRecord { } bool matesWith(const SkClosestRecord& mate SkDEBUGPARAMS(SkIntersections* i)) const { - SkASSERT(fC1Span == mate.fC1Span || fC1Span->endT() <= mate.fC1Span->startT() + SkOPOBJASSERT(i, fC1Span == mate.fC1Span || fC1Span->endT() <= mate.fC1Span->startT() || mate.fC1Span->endT() <= fC1Span->startT()); SkOPOBJASSERT(i, fC2Span == mate.fC2Span || fC2Span->endT() <= mate.fC2Span->startT() || mate.fC2Span->endT() <= fC2Span->startT()); @@ -2109,7 +2135,7 @@ void SkTSect::BinarySearch(SkTSect* sect1, SkDEBUGCODE(sect1->fOppSect = sect2); SkDEBUGCODE(sect2->fOppSect = sect1); intersections->reset(); - intersections->setMax(TCurve::kMaxIntersections + 3); // give extra for slop + intersections->setMax(TCurve::kMaxIntersections + 4); // give extra for slop SkTSpan* span1 = sect1->fHead; SkTSpan* span2 = sect2->fHead; int oppSect, sect = sect1->intersects(span1, sect2, span2, &oppSect); @@ -2134,34 +2160,48 @@ void SkTSect::BinarySearch(SkTSect* sect1, break; } SkTSpan* largest2 = sect2->boundsMax(); - sect1->fRemovedStartT = sect1->fRemovedEndT = false; - sect2->fRemovedStartT = sect2->fRemovedEndT = false; // split it if (!largest2 || (largest1 && (largest1->fBoundsMax > largest2->fBoundsMax || (!largest1->fCollapsed && largest2->fCollapsed)))) { if (largest1->fCollapsed) { break; } + sect1->resetRemovedEnds(); + sect2->resetRemovedEnds(); // trim parts that don't intersect the opposite SkTSpan* half1 = sect1->addOne(); SkDEBUGCODE(half1->debugSetGlobalState(sect1->globalState())); if (!half1->split(largest1, §1->fHeap)) { break; } - sect1->trim(largest1, sect2); - sect1->trim(half1, sect2); + if (!sect1->trim(largest1, sect2)) { + SkOPOBJASSERT(intersections, 0); + return; + } + if (!sect1->trim(half1, sect2)) { + SkOPOBJASSERT(intersections, 0); + return; + } } else { if (largest2->fCollapsed) { break; } + sect1->resetRemovedEnds(); + sect2->resetRemovedEnds(); // trim parts that don't intersect the opposite SkTSpan* half2 = sect2->addOne(); SkDEBUGCODE(half2->debugSetGlobalState(sect2->globalState())); if (!half2->split(largest2, §2->fHeap)) { break; } - sect2->trim(largest2, sect1); - sect2->trim(half2, sect1); + if (!sect2->trim(largest2, sect1)) { + SkOPOBJASSERT(intersections, 0); + return; + } + if (!sect2->trim(half2, sect1)) { + SkOPOBJASSERT(intersections, 0); + return; + } } sect1->validate(); sect2->validate(); @@ -2196,7 +2236,13 @@ void SkTSect::BinarySearch(SkTSect* sect1, } if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { + if (!sect1->fHead) { + return; + } sect1->computePerpendiculars(sect2, sect1->fHead, sect1->tail()); + if (!sect2->fHead) { + return; + } sect2->computePerpendiculars(sect1, sect2->fHead, sect2->tail()); sect1->removeByPerpendicular(sect2); sect1->validate(); @@ -2224,14 +2270,21 @@ void SkTSect::BinarySearch(SkTSect* sect1, } SkASSERT(sect2->fCoincident); // courtesy check : coincidence only looks at sect 1 do { + if (!coincident) { + return; + } if (!coincident->fCoinStart.isMatch()) { continue; } if (!coincident->fCoinEnd.isMatch()) { continue; } + double perpT = coincident->fCoinStart.perpT(); + if (perpT < 0) { + return; + } int index = intersections->insertCoincident(coincident->fStartT, - coincident->fCoinStart.perpT(), coincident->fPart[0]); + perpT, coincident->fPart[0]); if ((intersections->insertCoincident(coincident->fEndT, coincident->fCoinEnd.perpT(), coincident->fPart[TCurve::kPointLast]) < 0) && index >= 0) { @@ -2240,36 +2293,38 @@ void SkTSect::BinarySearch(SkTSect* sect1, } while ((coincident = coincident->fNext)); } int zeroOneSet = EndsEqual(sect1, sect2, intersections); - if (!sect1->fHead || !sect2->fHead) { +// if (!sect1->fHead || !sect2->fHead) { // if the final iteration contains an end (0 or 1), if (sect1->fRemovedStartT && !(zeroOneSet & kZeroS1Set)) { SkTCoincident perp; // intersect perpendicular with opposite curve - perp.setPerp(sect1->fCurve, 0, sect1->fCurve.fPts[0], sect2->fCurve); + perp.setPerp(sect1->fCurve, 0, sect1->fCurve[0], sect2->fCurve); if (perp.isMatch()) { intersections->insert(0, perp.perpT(), perp.perpPt()); } } if (sect1->fRemovedEndT && !(zeroOneSet & kOneS1Set)) { SkTCoincident perp; - perp.setPerp(sect1->fCurve, 1, sect1->fCurve.fPts[TCurve::kPointLast], sect2->fCurve); + perp.setPerp(sect1->fCurve, 1, sect1->fCurve[TCurve::kPointLast], sect2->fCurve); if (perp.isMatch()) { intersections->insert(1, perp.perpT(), perp.perpPt()); } } if (sect2->fRemovedStartT && !(zeroOneSet & kZeroS2Set)) { SkTCoincident perp; - perp.setPerp(sect2->fCurve, 0, sect2->fCurve.fPts[0], sect1->fCurve); + perp.setPerp(sect2->fCurve, 0, sect2->fCurve[0], sect1->fCurve); if (perp.isMatch()) { intersections->insert(perp.perpT(), 0, perp.perpPt()); } } if (sect2->fRemovedEndT && !(zeroOneSet & kOneS2Set)) { SkTCoincident perp; - perp.setPerp(sect2->fCurve, 1, sect2->fCurve.fPts[OppCurve::kPointLast], sect1->fCurve); + perp.setPerp(sect2->fCurve, 1, sect2->fCurve[OppCurve::kPointLast], sect1->fCurve); if (perp.isMatch()) { intersections->insert(perp.perpT(), 1, perp.perpPt()); } } +// } + if (!sect1->fHead || !sect2->fHead) { return; } sect1->recoverCollapsed(); @@ -2359,7 +2414,7 @@ void SkTSect::BinarySearch(SkTSect* sect1, } intersections->setCoincident(index); } - SkASSERT(intersections->used() <= TCurve::kMaxIntersections); + SkOPOBJASSERT(intersections, intersections->used() <= TCurve::kMaxIntersections); } #endif diff --git a/gfx/skia/skia/src/pathops/SkPathOpsTightBounds.cpp b/gfx/skia/skia/src/pathops/SkPathOpsTightBounds.cpp index d748ff538afa..4236d2d545d1 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsTightBounds.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsTightBounds.cpp @@ -47,7 +47,8 @@ bool TightBounds(const SkPath& path, SkRect* result) { *result = path.getBounds(); return true; } - SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune + char storage[4096]; + SkArenaAlloc allocator(storage); // FIXME: constant-ize, tune SkOpContour contour; SkOpContourHead* contourList = static_cast(&contour); SkOpGlobalState globalState(contourList, &allocator SkDEBUGPARAMS(false) @@ -75,6 +76,10 @@ bool TightBounds(const SkPath& path, SkRect* result) { while ((current = current->next())) { bounds.add(current->bounds()); } + if (scaleFactor > SK_Scalar1) { + bounds.set(bounds.left() * scaleFactor, bounds.top() * scaleFactor, + bounds.right() * scaleFactor, bounds.bottom() * scaleFactor); + } *result = bounds; if (!moveBounds.isEmpty()) { result->join(moveBounds); diff --git a/gfx/skia/skia/src/pathops/SkPathOpsTypes.cpp b/gfx/skia/skia/src/pathops/SkPathOpsTypes.cpp index 5f87076c249a..bddfd7e50893 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsTypes.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsTypes.cpp @@ -4,6 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#include "SkArenaAlloc.h" #include "SkFloatBits.h" #include "SkOpCoincidence.h" #include "SkPathOpsTypes.h" @@ -225,7 +226,7 @@ double SkDCubeRoot(double x) { } SkOpGlobalState::SkOpGlobalState(SkOpContourHead* head, - SkChunkAlloc* allocator + SkArenaAlloc* allocator SkDEBUGPARAMS(bool debugSkipAssert) SkDEBUGPARAMS(const char* testName)) : fAllocator(allocator) diff --git a/gfx/skia/skia/src/pathops/SkPathOpsTypes.h b/gfx/skia/skia/src/pathops/SkPathOpsTypes.h index 786eb2288e52..2fef8266c277 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsTypes.h +++ b/gfx/skia/skia/src/pathops/SkPathOpsTypes.h @@ -8,12 +8,12 @@ #define SkPathOpsTypes_DEFINED #include // for FLT_EPSILON -#include // for fabs, sqrt #include "SkFloatingPoint.h" #include "SkPath.h" #include "SkPathOps.h" #include "SkPathOpsDebug.h" +#include "SkSafe_math.h" // for fabs, sqrt #include "SkScalar.h" enum SkPathOpsMask { @@ -22,7 +22,7 @@ enum SkPathOpsMask { kEvenOdd_PathOpsMask = 1 }; -class SkChunkAlloc; +class SkArenaAlloc; class SkOpCoincidence; class SkOpContour; class SkOpContourHead; @@ -39,7 +39,7 @@ enum class SkOpPhase : char { class SkOpGlobalState { public: SkOpGlobalState(SkOpContourHead* head, - SkChunkAlloc* allocator SkDEBUGPARAMS(bool debugSkipAssert) + SkArenaAlloc* allocator SkDEBUGPARAMS(bool debugSkipAssert) SkDEBUGPARAMS(const char* testName)); enum { @@ -50,7 +50,7 @@ public: return fAllocatedOpSpan; } - SkChunkAlloc* allocator() { + SkArenaAlloc* allocator() { return fAllocator; } @@ -75,7 +75,11 @@ public: const SkOpCoincidence* debugCoincidence() const; SkOpContour* debugContour(int id) const; const class SkOpPtT* debugPtT(int id) const; - bool debugRunFail() const; +#endif + + static bool DebugRunFail(); + +#ifdef SK_DEBUG const class SkOpSegment* debugSegment(int id) const; bool debugSkipAssert() const { return fDebugSkipAssert; } const class SkOpSpanBase* debugSpan(int id) const; @@ -142,7 +146,7 @@ public: SkOpPhase phase() const { return fPhase; } - + void resetAllocatedOpSpan() { fAllocatedOpSpan = false; } @@ -154,7 +158,7 @@ public: void setCoincidence(SkOpCoincidence* coincidence) { fCoincidence = coincidence; } - + void setContourHead(SkOpContourHead* contourHead) { fContourHead = contourHead; } @@ -177,7 +181,7 @@ public: } private: - SkChunkAlloc* fAllocator; + SkArenaAlloc* fAllocator; SkOpCoincidence* fCoincidence; SkOpContourHead* fContourHead; int fNested; @@ -221,8 +225,8 @@ private: #define SkOPASSERT(cond) SkASSERT((this->globalState() && \ this->globalState()->debugSkipAssert()) || (cond)) #endif -#define SkOPOBJASSERT(obj, cond) SkASSERT((obj->debugGlobalState() && \ - obj->debugGlobalState()->debugSkipAssert()) || (cond)) +#define SkOPOBJASSERT(obj, cond) SkASSERT((obj->globalState() && \ + obj->globalState()->debugSkipAssert()) || (cond)) #else #define SkOPASSERT(cond) #define SkOPOBJASSERT(obj, cond) @@ -306,7 +310,9 @@ const double FLT_EPSILON_HALF = FLT_EPSILON / 2; const double FLT_EPSILON_DOUBLE = FLT_EPSILON * 2; const double FLT_EPSILON_ORDERABLE_ERR = FLT_EPSILON * 16; const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON; -const double FLT_EPSILON_SQRT = sqrt(FLT_EPSILON); +// Use a compile-time constant for FLT_EPSILON_SQRT to avoid initializers. +// A 17 digit constant guarantees exact results. +const double FLT_EPSILON_SQRT = 0.00034526697709225118; // sqrt(FLT_EPSILON); const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON; const double DBL_EPSILON_ERR = DBL_EPSILON * 4; // FIXME: tune -- allow a few bits of error const double DBL_EPSILON_SUBDIVIDE_ERR = DBL_EPSILON * 16; diff --git a/gfx/skia/skia/src/pathops/SkPathOpsWinding.cpp b/gfx/skia/skia/src/pathops/SkPathOpsWinding.cpp index 35cabcf62e42..724e6f47bc5e 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsWinding.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsWinding.cpp @@ -101,7 +101,7 @@ struct SkOpRayHit { }; void SkOpContour::rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, - SkChunkAlloc* allocator) { + SkArenaAlloc* allocator) { // if the bounds extreme is outside the best, we're done SkScalar baseXY = pt_xy(base.fPt, dir); SkScalar boundsXY = rect_side(fBounds, dir); @@ -116,7 +116,7 @@ void SkOpContour::rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** } void SkOpSegment::rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, - SkChunkAlloc* allocator) { + SkArenaAlloc* allocator) { if (!sideways_overlap(fBounds, base.fPt, dir)) { return; } @@ -233,7 +233,8 @@ static double get_t_guess(int tTry, int* dirOffset) { } bool SkOpSpan::sortableTop(SkOpContour* contourHead) { - SkChunkAlloc allocator(1024); + char storage[1024]; + SkArenaAlloc allocator(storage); int dirOffset; double t = get_t_guess(fTopTTry++, &dirOffset); SkOpRayHit hitBase; @@ -249,6 +250,9 @@ bool SkOpSpan::sortableTop(SkOpContour* contourHead) { } SkOpContour* contour = contourHead; do { + if (!contour->count()) { + continue; + } contour->rayCheck(hitBase, dir, &hitHead, &allocator); } while ((contour = contour->next())); // sort hits @@ -381,18 +385,20 @@ SkOpSpan* SkOpSegment::findSortableTop(SkOpContour* contourHead) { } SkOpSpan* SkOpContour::findSortableTop(SkOpContour* contourHead) { - SkOpSegment* testSegment = &fHead; bool allDone = true; - do { - if (testSegment->done()) { - continue; - } - allDone = false; - SkOpSpan* result = testSegment->findSortableTop(contourHead); - if (result) { - return result; - } - } while ((testSegment = testSegment->next())); + if (fCount) { + SkOpSegment* testSegment = &fHead; + do { + if (testSegment->done()) { + continue; + } + allDone = false; + SkOpSpan* result = testSegment->findSortableTop(contourHead); + if (result) { + return result; + } + } while ((testSegment = testSegment->next())); + } if (allDone) { fDone = true; } diff --git a/gfx/skia/skia/src/pathops/SkPathWriter.cpp b/gfx/skia/skia/src/pathops/SkPathWriter.cpp index 1f6dddd137f0..9893a502caab 100644 --- a/gfx/skia/skia/src/pathops/SkPathWriter.cpp +++ b/gfx/skia/skia/src/pathops/SkPathWriter.cpp @@ -48,23 +48,26 @@ void SkPathWriter::cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkOpPtT fCurrent.cubicTo(pt1, pt2, pt3->fPt); } -void SkPathWriter::deferredLine(const SkOpPtT* pt) { +bool SkPathWriter::deferredLine(const SkOpPtT* pt) { SkASSERT(fFirstPtT); SkASSERT(fDefer[0]); if (fDefer[0] == pt) { // FIXME: why we're adding a degenerate line? Caller should have preflighted this. - return; + return true; } if (pt->contains(fDefer[0])) { // FIXME: why we're adding a degenerate line? - return; + return true; + } + if (this->matchedLast(pt)) { + return false; } - SkASSERT(!this->matchedLast(pt)); if (fDefer[1] && this->changedSlopes(pt)) { this->lineTo(); fDefer[0] = fDefer[1]; } fDefer[1] = pt; + return true; } void SkPathWriter::deferredMove(const SkOpPtT* pt) { @@ -303,7 +306,7 @@ void SkPathWriter::assemble() { first ? SkPath::kAppend_AddPathMode : SkPath::kExtend_AddPathMode); } else { SkASSERT(!first); - fPathPtr->reverseAddPath(contour); + fPathPtr->reversePathTo(contour); } if (first) { first = false; diff --git a/gfx/skia/skia/src/pathops/SkPathWriter.h b/gfx/skia/skia/src/pathops/SkPathWriter.h index bd13c718a90f..5dd1bf6f60a5 100644 --- a/gfx/skia/skia/src/pathops/SkPathWriter.h +++ b/gfx/skia/skia/src/pathops/SkPathWriter.h @@ -23,7 +23,7 @@ public: void assemble(); void conicTo(const SkPoint& pt1, const SkOpPtT* pt2, SkScalar weight); void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkOpPtT* pt3); - void deferredLine(const SkOpPtT* pt); + bool deferredLine(const SkOpPtT* pt); void deferredMove(const SkOpPtT* pt); void finishContour(); bool hasMove() const { return !fFirstPtT; } diff --git a/gfx/skia/skia/src/pdf/SkDeflate.cpp b/gfx/skia/skia/src/pdf/SkDeflate.cpp index c2b85fccb326..81c26c9196a8 100644 --- a/gfx/skia/skia/src/pdf/SkDeflate.cpp +++ b/gfx/skia/skia/src/pdf/SkDeflate.cpp @@ -9,6 +9,7 @@ #include "SkData.h" #include "SkDeflate.h" #include "SkMakeUnique.h" +#include "SkMalloc.h" #include "zlib.h" diff --git a/gfx/skia/skia/src/pdf/SkDeflate.h b/gfx/skia/skia/src/pdf/SkDeflate.h index 387de40a15f1..be76a1d53e6e 100644 --- a/gfx/skia/skia/src/pdf/SkDeflate.h +++ b/gfx/skia/skia/src/pdf/SkDeflate.h @@ -35,7 +35,7 @@ public: bool gzip = false); /** The destructor calls finalize(). */ - ~SkDeflateWStream(); + ~SkDeflateWStream() override; /** Write the end of the compressed stream. All subsequent calls to write() will fail. Subsequent calls to finalize() do nothing. */ diff --git a/gfx/skia/skia/src/pdf/SkPDFBitmap.cpp b/gfx/skia/skia/src/pdf/SkPDFBitmap.cpp index 2d789d04d8dc..511fca837072 100644 --- a/gfx/skia/skia/src/pdf/SkPDFBitmap.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFBitmap.cpp @@ -17,7 +17,8 @@ #include "SkUnPreMultiply.h" void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) { - if(as_IB(image)->getROPixels(dst) + SkColorSpace* legacyColorSpace = nullptr; + if(as_IB(image)->getROPixels(dst, legacyColorSpace) && dst->dimensions() == image->dimensions()) { if (dst->colorType() != kIndex_8_SkColorType) { return; @@ -502,7 +503,9 @@ sk_sp SkPDFCreateBitmapObject(sk_sp image, if (pixelSerializer) { SkBitmap bm; SkAutoPixmapUnlock apu; - if (as_IB(image.get())->getROPixels(&bm) && bm.requestLock(&apu)) { + SkColorSpace* legacyColorSpace = nullptr; + if (as_IB(image.get())->getROPixels(&bm, legacyColorSpace) && + bm.requestLock(&apu)) { data.reset(pixelSerializer->encode(apu.pixmap())); if (data && SkIsJFIF(data.get(), &info)) { bool yuv = info.fType == SkJFIFInfo::kYCbCr; diff --git a/gfx/skia/skia/src/pdf/SkPDFCanvas.cpp b/gfx/skia/skia/src/pdf/SkPDFCanvas.cpp index c7e39259ce5d..d946f48197d5 100644 --- a/gfx/skia/skia/src/pdf/SkPDFCanvas.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFCanvas.cpp @@ -19,15 +19,15 @@ SkPDFCanvas::~SkPDFCanvas() {} * we intercept all clip calls to ensure that the clip stays BW (i.e. never antialiased), since * an antialiased clip won't build a SkRegion (it builds SkAAClip). */ -void SkPDFCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkPDFCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { this->INHERITED::onClipRect(rect, op, kHard_ClipEdgeStyle); } -void SkPDFCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkPDFCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { this->INHERITED::onClipRRect(rrect, op, kHard_ClipEdgeStyle); } -void SkPDFCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkPDFCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { this->INHERITED::onClipPath(path, op, kHard_ClipEdgeStyle); } diff --git a/gfx/skia/skia/src/pdf/SkPDFCanvas.h b/gfx/skia/skia/src/pdf/SkPDFCanvas.h index ead13c34a555..93c055a26ae7 100644 --- a/gfx/skia/skia/src/pdf/SkPDFCanvas.h +++ b/gfx/skia/skia/src/pdf/SkPDFCanvas.h @@ -14,12 +14,12 @@ class SkPDFDevice; class SkPDFCanvas : public SkCanvas { public: SkPDFCanvas(const sk_sp&); - ~SkPDFCanvas(); + ~SkPDFCanvas() override; protected: - void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; - void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect&, const SkPaint*) override; diff --git a/gfx/skia/skia/src/pdf/SkPDFConvertType1FontStream.cpp b/gfx/skia/skia/src/pdf/SkPDFConvertType1FontStream.cpp index d75da5c78712..387f0efacf79 100644 --- a/gfx/skia/skia/src/pdf/SkPDFConvertType1FontStream.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFConvertType1FontStream.cpp @@ -6,6 +6,7 @@ */ #include "SkPDFConvertType1FontStream.h" +#include "SkTemplates.h" #include diff --git a/gfx/skia/skia/src/pdf/SkPDFDevice.cpp b/gfx/skia/skia/src/pdf/SkPDFDevice.cpp index 217dd3f2b674..992508db240c 100644 --- a/gfx/skia/skia/src/pdf/SkPDFDevice.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFDevice.cpp @@ -42,11 +42,29 @@ #include "SkTextFormatParams.h" #include "SkUtils.h" #include "SkXfermodeInterpretation.h" +#include "SkClipOpPriv.h" #define DPI_FOR_RASTER_SCALE_ONE 72 // Utility functions +static void draw_points(SkCanvas::PointMode mode, + size_t count, + const SkPoint* points, + const SkPaint& paint, + const SkIRect& bounds, + const SkMatrix& ctm, + SkBaseDevice* device) { + SkRasterClip rc(bounds); + SkDraw draw; + draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(bounds.right(), bounds.bottom()), nullptr, 0); + draw.fMatrix = &ctm; + draw.fRC = &rc; + draw.drawPoints(mode, count, points, paint, device); +} + +static SkIRect size(const SkBaseDevice& dev) { return {0, 0, dev.width(), dev.height()}; } + // If the paint will definitely draw opaquely, replace kSrc with // kSrcOver. http://crbug.com/473572 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { @@ -72,7 +90,7 @@ static SkPaint calculate_text_paint(const SkPaint& paint) { kStdFakeBoldInterpKeys, kStdFakeBoldInterpValues, kStdFakeBoldInterpLength); - SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale); + SkScalar width = result.getTextSize() * fakeBoldScale; if (result.getStyle() == SkPaint::kFill_Style) { result.setStyle(SkPaint::kStrokeAndFill_Style); } else { @@ -90,7 +108,7 @@ static SkImageSubset make_image_subset(const SkBitmap& bitmap) { SkASSERT(bitmap.pixelRef()); SkBitmap tmp; tmp.setInfo(bitmap.pixelRef()->info(), bitmap.rowBytes()); - tmp.setPixelRef(bitmap.pixelRef()); + tmp.setPixelRef(sk_ref_sp(bitmap.pixelRef()), 0, 0); tmp.lockPixels(); auto img = SkImage::MakeFromBitmap(tmp); if (img) { @@ -127,16 +145,14 @@ bool SkPDFDevice::GraphicStateEntry::compareInitialState( class GraphicStackState { public: GraphicStackState(const SkClipStack& existingClipStack, - const SkRegion& existingClipRegion, SkWStream* contentStream) : fStackDepth(0), fContentStream(contentStream) { fEntries[0].fClipStack = existingClipStack; - fEntries[0].fClipRegion = existingClipRegion; } - void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion, - const SkPoint& translation); + void updateClip(const SkClipStack& clipStack, + const SkPoint& translation, const SkRect& bounds); void updateMatrix(const SkMatrix& matrix); void updateDrawingState(const SkPDFDevice::GraphicStateEntry& state); @@ -187,21 +203,24 @@ static bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath, return Op(clipPath, invPath, kIntersect_SkPathOp, outPath); } -// Sanity check the numerical values of the SkRegion ops and PathOps ops -// enums so region_op_to_pathops_op can do a straight passthrough cast. -// If these are failing, it may be necessary to make region_op_to_pathops_op -// do more. -static_assert(SkRegion::kDifference_Op == (int)kDifference_SkPathOp, "region_pathop_mismatch"); -static_assert(SkRegion::kIntersect_Op == (int)kIntersect_SkPathOp, "region_pathop_mismatch"); -static_assert(SkRegion::kUnion_Op == (int)kUnion_SkPathOp, "region_pathop_mismatch"); -static_assert(SkRegion::kXOR_Op == (int)kXOR_SkPathOp, "region_pathop_mismatch"); -static_assert(SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkPathOp, - "region_pathop_mismatch"); - -static SkPathOp region_op_to_pathops_op(SkCanvas::ClipOp op) { - SkASSERT(op >= 0); - SkASSERT(op <= SkCanvas::kReverseDifference_Op); - return (SkPathOp)op; +bool apply_clip(SkClipOp op, const SkPath& u, const SkPath& v, SkPath* r) { + switch (op) { + case SkClipOp::kDifference: + return Op(u, v, kDifference_SkPathOp, r); + case SkClipOp::kIntersect: + return Op(u, v, kIntersect_SkPathOp, r); + case SkClipOp::kUnion_deprecated: + return Op(u, v, kUnion_SkPathOp, r); + case SkClipOp::kXOR_deprecated: + return Op(u, v, kXOR_SkPathOp, r); + case SkClipOp::kReverseDifference_deprecated: + return Op(u, v, kReverseDifference_SkPathOp, r); + case SkClipOp::kReplace_deprecated: + *r = v; + return true; + default: + return false; + } } /* Uses Path Ops to calculate a vector SkPath clip from a clip stack. @@ -212,7 +231,7 @@ static SkPathOp region_op_to_pathops_op(SkCanvas::ClipOp op) { */ static bool get_clip_stack_path(const SkMatrix& transform, const SkClipStack& clipStack, - const SkRegion& clipRegion, + const SkRect& bounds, SkPath* outClipPath) { outClipPath->reset(); outClipPath->setFillType(SkPath::kInverseWinding_FillType); @@ -230,14 +249,8 @@ static bool get_clip_stack_path(const SkMatrix& transform, clipEntry->asPath(&entryPath); } entryPath.transform(transform); - - if (SkCanvas::kReplace_Op == clipEntry->getOp()) { - *outClipPath = entryPath; - } else { - SkPathOp op = region_op_to_pathops_op(clipEntry->getOp()); - if (!Op(*outClipPath, entryPath, op, outClipPath)) { - return false; - } + if (!apply_clip(clipEntry->getOp(), *outClipPath, entryPath, outClipPath)) { + return false; } } @@ -245,7 +258,7 @@ static bool get_clip_stack_path(const SkMatrix& transform, // The bounds are slightly outset to ensure this is correct in the // face of floating-point accuracy and possible SkRegion bitmap // approximations. - SkRect clipBounds = SkRect::Make(clipRegion.getBounds()); + SkRect clipBounds = bounds; clipBounds.outset(SK_Scalar1, SK_Scalar1); if (!calculate_inverse_path(clipBounds, *outClipPath, outClipPath)) { return false; @@ -258,8 +271,8 @@ static bool get_clip_stack_path(const SkMatrix& transform, // graphic state stack, and the fact that we can know all the clips used // on the page to optimize this. void GraphicStackState::updateClip(const SkClipStack& clipStack, - const SkRegion& clipRegion, - const SkPoint& translation) { + const SkPoint& translation, + const SkRect& bounds) { if (clipStack == currentEntry()->fClipStack) { return; } @@ -273,13 +286,12 @@ void GraphicStackState::updateClip(const SkClipStack& clipStack, push(); currentEntry()->fClipStack = clipStack; - currentEntry()->fClipRegion = clipRegion; SkMatrix transform; transform.setTranslate(translation.fX, translation.fY); SkPath clipPath; - if (get_clip_stack_path(transform, clipStack, clipRegion, &clipPath)) { + if (get_clip_stack_path(transform, clipStack, bounds, &clipPath)) { SkPDFUtils::EmitPath(clipPath, SkPaint::kFill_Style, fContentStream); SkPath::FillType clipFill = clipPath.getFillType(); NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false); @@ -342,8 +354,7 @@ void GraphicStackState::updateDrawingState(const SkPDFDevice::GraphicStateEntry& if (state.fTextScaleX) { if (state.fTextScaleX != currentEntry()->fTextScaleX) { - SkScalar pdfScale = SkScalarMul(state.fTextScaleX, - SkIntToScalar(100)); + SkScalar pdfScale = state.fTextScaleX * 1000; SkPDFUtils::AppendScalar(pdfScale, fContentStream); fContentStream->writeText(" Tz\n"); currentEntry()->fTextScaleX = state.fTextScaleX; @@ -387,23 +398,26 @@ SkPDFCanon* SkPDFDevice::getCanon() const { return fDocument->canon(); } // drawing method and maintain the state needed between set up and finish. class ScopedContentEntry { public: - ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw, - const SkPaint& paint, bool hasText = false) - : fDevice(device), - fContentEntry(nullptr), - fBlendMode(SkBlendMode::kSrcOver), - fDstFormXObject(nullptr) { - init(draw.fClipStack, draw.fRC->bwRgn(), *draw.fMatrix, paint, hasText); - } - ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack, - const SkRegion& clipRegion, const SkMatrix& matrix, - const SkPaint& paint, bool hasText = false) - : fDevice(device), - fContentEntry(nullptr), - fBlendMode(SkBlendMode::kSrcOver), - fDstFormXObject(nullptr) { - init(clipStack, clipRegion, matrix, paint, hasText); + ScopedContentEntry(SkPDFDevice* device, + const SkClipStack& clipStack, + const SkMatrix& matrix, + const SkPaint& paint, + bool hasText = false) + : fDevice(device) + , fContentEntry(nullptr) + , fBlendMode(SkBlendMode::kSrcOver) + , fDstFormXObject(nullptr) + { + if (matrix.hasPerspective()) { + NOT_IMPLEMENTED(!matrix.hasPerspective(), false); + return; + } + fBlendMode = paint.getBlendMode(); + fContentEntry = + fDevice->setUpContentEntry(clipStack, matrix, paint, hasText, &fDstFormXObject); } + ScopedContentEntry(SkPDFDevice* dev, const SkPaint& paint, bool hasText = false) + : ScopedContentEntry(dev, dev->cs(), dev->ctm(), paint, hasText) {} ~ScopedContentEntry() { if (fContentEntry) { @@ -457,19 +471,6 @@ private: SkBlendMode fBlendMode; sk_sp fDstFormXObject; SkPath fShape; - - void init(const SkClipStack* clipStack, const SkRegion& clipRegion, - const SkMatrix& matrix, const SkPaint& paint, bool hasText) { - // Shape has to be flatten before we get here. - if (matrix.hasPerspective()) { - NOT_IMPLEMENTED(!matrix.hasPerspective(), false); - return; - } - fBlendMode = paint.getBlendMode(); - fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion, - matrix, paint, hasText, - &fDstFormXObject); - } }; //////////////////////////////////////////////////////////////////////////////// @@ -478,7 +479,6 @@ SkPDFDevice::SkPDFDevice(SkISize pageSize, SkScalar rasterDpi, SkPDFDocument* do : INHERITED(SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height()), SkSurfaceProps(0, kUnknown_SkPixelGeometry)) , fPageSize(pageSize) - , fExistingClipRegion(SkIRect::MakeSize(pageSize)) , fRasterDpi(rasterDpi) , fDocument(doc) { SkASSERT(pageSize.width() > 0); @@ -511,24 +511,44 @@ void SkPDFDevice::cleanUp() { fShaderResources.unrefAll(); } -void SkPDFDevice::drawAnnotation(const SkDraw& d, const SkRect& rect, const char key[], - SkData* value) { - if (0 == rect.width() && 0 == rect.height()) { - handlePointAnnotation({ rect.x(), rect.y() }, *d.fMatrix, key, value); - } else { - SkPath path; - path.addRect(rect); - handlePathAnnotation(path, d, key, value); +void SkPDFDevice::drawAnnotation(const SkRect& rect, const char key[], SkData* value) { + if (!value) { + return; + } + if (rect.isEmpty()) { + if (!strcmp(SkAnnotationKeys::Define_Named_Dest_Key(), key)) { + SkPoint transformedPoint; + this->ctm().mapXY(rect.x(), rect.y(), &transformedPoint); + fNamedDestinations.emplace_back(value, transformedPoint); + } + return; + } + // Convert to path to handle non-90-degree rotations. + SkPath path; + path.addRect(rect); + path.transform(this->ctm(), &path); + SkPath clip; + (void)this->cs().asPath(&clip); + Op(clip, path, kIntersect_SkPathOp, &path); + // PDF wants a rectangle only. + SkRect transformedRect = path.getBounds(); + if (transformedRect.isEmpty()) { + return; + } + if (!strcmp(SkAnnotationKeys::URL_Key(), key)) { + fLinkToURLs.emplace_back(transformedRect, value); + } else if (!strcmp(SkAnnotationKeys::Link_Named_Dest_Key(), key)) { + fLinkToDestinations.emplace_back(transformedRect, value); } } -void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) { +void SkPDFDevice::drawPaint(const SkPaint& paint) { SkPaint newPaint = paint; replace_srcmode_on_opaque_paint(&newPaint); newPaint.setStyle(SkPaint::kFill_Style); - ScopedContentEntry content(this, d, newPaint); - internalDrawPaint(newPaint, content.entry()); + ScopedContentEntry content(this, newPaint); + this->internalDrawPaint(newPaint, content.entry()); } void SkPDFDevice::internalDrawPaint(const SkPaint& paint, @@ -549,8 +569,7 @@ void SkPDFDevice::internalDrawPaint(const SkPaint& paint, &contentEntry->fContent); } -void SkPDFDevice::drawPoints(const SkDraw& d, - SkCanvas::PointMode mode, +void SkPDFDevice::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint* points, const SkPaint& srcPaint) { @@ -565,12 +584,11 @@ void SkPDFDevice::drawPoints(const SkDraw& d, // We only use this when there's a path effect because of the overhead // of multiple calls to setUpContentEntry it causes. if (passedPaint.getPathEffect()) { - if (d.fRC->isEmpty()) { + if (this->cs().isEmpty(size(*this))) { return; } - SkDraw pointDraw(d); - pointDraw.fDevice = this; - pointDraw.drawPoints(mode, count, points, passedPaint, true); + draw_points(mode, count, points, passedPaint, + this->devClipBounds(), this->ctm(), this); return; } @@ -590,7 +608,7 @@ void SkPDFDevice::drawPoints(const SkDraw& d, for (size_t i = 0; i < count; i++) { SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0); r.inset(-halfStroke, -halfStroke); - drawRect(d, r, modifiedPaint); + this->drawRect(r, modifiedPaint); } return; } else { @@ -598,7 +616,7 @@ void SkPDFDevice::drawPoints(const SkDraw& d, } } - ScopedContentEntry content(this, d, *paint); + ScopedContentEntry content(this, *paint); if (!content.entry()) { return; } @@ -680,8 +698,7 @@ static sk_sp create_link_named_dest(const SkData* nameData, return annotation; } -void SkPDFDevice::drawRect(const SkDraw& d, - const SkRect& rect, +void SkPDFDevice::drawRect(const SkRect& rect, const SkPaint& srcPaint) { SkPaint paint = srcPaint; replace_srcmode_on_opaque_paint(&paint); @@ -689,16 +706,16 @@ void SkPDFDevice::drawRect(const SkDraw& d, r.sort(); if (paint.getPathEffect()) { - if (d.fRC->isEmpty()) { + if (this->cs().isEmpty(size(*this))) { return; } SkPath path; path.addRect(r); - drawPath(d, path, paint, nullptr, true); + this->drawPath(path, paint, nullptr, true); return; } - ScopedContentEntry content(this, d, paint); + ScopedContentEntry content(this, paint); if (!content.entry()) { return; } @@ -707,37 +724,44 @@ void SkPDFDevice::drawRect(const SkDraw& d, &content.entry()->fContent); } -void SkPDFDevice::drawRRect(const SkDraw& draw, - const SkRRect& rrect, +void SkPDFDevice::drawRRect(const SkRRect& rrect, const SkPaint& srcPaint) { SkPaint paint = srcPaint; replace_srcmode_on_opaque_paint(&paint); SkPath path; path.addRRect(rrect); - this->drawPath(draw, path, paint, nullptr, true); + this->drawPath(path, paint, nullptr, true); } -void SkPDFDevice::drawOval(const SkDraw& draw, - const SkRect& oval, +void SkPDFDevice::drawOval(const SkRect& oval, const SkPaint& srcPaint) { SkPaint paint = srcPaint; replace_srcmode_on_opaque_paint(&paint); SkPath path; path.addOval(oval); - this->drawPath(draw, path, paint, nullptr, true); + this->drawPath(path, paint, nullptr, true); } -void SkPDFDevice::drawPath(const SkDraw& d, - const SkPath& origPath, +void SkPDFDevice::drawPath(const SkPath& origPath, const SkPaint& srcPaint, const SkMatrix* prePathMatrix, bool pathIsMutable) { + this->internalDrawPath( + this->cs(), this->ctm(), origPath, srcPaint, prePathMatrix, pathIsMutable); +} + +void SkPDFDevice::internalDrawPath(const SkClipStack& clipStack, + const SkMatrix& ctm, + const SkPath& origPath, + const SkPaint& srcPaint, + const SkMatrix* prePathMatrix, + bool pathIsMutable) { SkPaint paint = srcPaint; replace_srcmode_on_opaque_paint(&paint); SkPath modifiedPath; SkPath* pathPtr = const_cast(&origPath); - SkMatrix matrix = *d.fMatrix; + SkMatrix matrix = ctm; if (prePathMatrix) { if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { if (!pathIsMutable) { @@ -751,7 +775,7 @@ void SkPDFDevice::drawPath(const SkDraw& d, } if (paint.getPathEffect()) { - if (d.fRC->isEmpty()) { + if (clipStack.isEmpty(size(*this))) { return; } if (!pathIsMutable) { @@ -768,32 +792,34 @@ void SkPDFDevice::drawPath(const SkDraw& d, noEffectPaint.setStyle(SkPaint::kStroke_Style); noEffectPaint.setStrokeWidth(0); } - drawPath(d, *pathPtr, noEffectPaint, nullptr, true); + this->internalDrawPath(clipStack, ctm, *pathPtr, noEffectPaint, nullptr, true); return; } - if (handleInversePath(d, origPath, paint, pathIsMutable, prePathMatrix)) { + if (this->handleInversePath(origPath, paint, pathIsMutable, prePathMatrix)) { return; } - ScopedContentEntry content(this, d.fClipStack, d.fRC->bwRgn(), matrix, paint); + ScopedContentEntry content(this, clipStack, matrix, paint); if (!content.entry()) { return; } + SkScalar matrixScale = matrix.mapRadius(1.0f); + SkScalar tolerance = matrixScale > 0.0f ? 0.25f / matrixScale : 0.25f; bool consumeDegeratePathSegments = paint.getStyle() == SkPaint::kFill_Style || (paint.getStrokeCap() != SkPaint::kRound_Cap && paint.getStrokeCap() != SkPaint::kSquare_Cap); SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), consumeDegeratePathSegments, - &content.entry()->fContent); + &content.entry()->fContent, + tolerance); SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), &content.entry()->fContent); } -void SkPDFDevice::drawImageRect(const SkDraw& d, - const SkImage* image, +void SkPDFDevice::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint& srcPaint, @@ -821,17 +847,15 @@ void SkPDFDevice::drawImageRect(const SkDraw& d, if (!imageSubset.isValid()) { return; } - transform.postConcat(*d.fMatrix); - this->internalDrawImage(transform, d.fClipStack, d.fRC->bwRgn(), - std::move(imageSubset), paint); + transform.postConcat(this->ctm()); + this->internalDrawImage(transform, this->cs(), std::move(imageSubset), paint); } -void SkPDFDevice::drawBitmapRect(const SkDraw& d, - const SkBitmap& bitmap, +void SkPDFDevice::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, - const SkPaint& srcPaint, - SkCanvas::SrcRectConstraint) { + const SkPaint& srcPaint, + SkCanvas::SrcRectConstraint) { if (bitmap.drawsNothing()) { return; } @@ -859,16 +883,14 @@ void SkPDFDevice::drawBitmapRect(const SkDraw& d, if (!imageSubset.isValid()) { return; } - transform.postConcat(*d.fMatrix); - this->internalDrawImage(transform, d.fClipStack, d.fRC->bwRgn(), - std::move(imageSubset), paint); + transform.postConcat(this->ctm()); + this->internalDrawImage(transform, this->cs(), std::move(imageSubset), paint); } -void SkPDFDevice::drawBitmap(const SkDraw& d, - const SkBitmap& bitmap, +void SkPDFDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint& srcPaint) { - if (bitmap.drawsNothing() || d.fRC->isEmpty()) { + if (bitmap.drawsNothing() || this->cs().isEmpty(size(*this))) { return; } SkPaint paint = srcPaint; @@ -880,17 +902,15 @@ void SkPDFDevice::drawBitmap(const SkDraw& d, return; } SkMatrix transform = matrix; - transform.postConcat(*d.fMatrix); - this->internalDrawImage( - transform, d.fClipStack, d.fRC->bwRgn(), std::move(imageSubset), paint); + transform.postConcat(this->ctm()); + this->internalDrawImage(transform, this->cs(), std::move(imageSubset), paint); } -void SkPDFDevice::drawSprite(const SkDraw& d, - const SkBitmap& bitmap, +void SkPDFDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& srcPaint) { - if (bitmap.drawsNothing() || d.fRC->isEmpty()) { + if (bitmap.drawsNothing() || this->cs().isEmpty(size(*this))) { return; } SkPaint paint = srcPaint; @@ -902,12 +922,10 @@ void SkPDFDevice::drawSprite(const SkDraw& d, return; } SkMatrix transform = SkMatrix::MakeTrans(SkIntToScalar(x), SkIntToScalar(y)); - this->internalDrawImage( - transform, d.fClipStack, d.fRC->bwRgn(), std::move(imageSubset), paint); + this->internalDrawImage(transform, this->cs(), std::move(imageSubset), paint); } -void SkPDFDevice::drawImage(const SkDraw& draw, - const SkImage* image, +void SkPDFDevice::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint& srcPaint) { @@ -918,17 +936,13 @@ void SkPDFDevice::drawImage(const SkDraw& draw, if (image->isOpaque()) { replace_srcmode_on_opaque_paint(&paint); } - if (draw.fRC->isEmpty()) { - return; - } SkImageSubset imageSubset(sk_ref_sp(const_cast(image))); if (!imageSubset.isValid()) { return; } SkMatrix transform = SkMatrix::MakeTrans(x, y); - transform.postConcat(*draw.fMatrix); - this->internalDrawImage( - transform, draw.fClipStack, draw.fRC->bwRgn(), std::move(imageSubset), paint); + transform.postConcat(this->ctm()); + this->internalDrawImage(transform, this->cs(), std::move(imageSubset), paint); } namespace { @@ -968,9 +982,14 @@ public: fCurrentMatrixOrigin.set(0.0f, 0.0f); fInitialized = true; } +#ifdef SK_BUILD_FOR_WIN + const bool kAlwaysPosition = true; +#else + const bool kAlwaysPosition = false; +#endif if (!fDefaultPositioning) { SkPoint position = xy - fCurrentMatrixOrigin; - if (position != SkPoint{fXAdvance, 0}) { + if (kAlwaysPosition || position != SkPoint{fXAdvance, 0}) { this->flush(); SkPDFUtils::AppendScalar(position.x(), fContent); fContent->writeText(" "); @@ -1217,7 +1236,7 @@ static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) { } void SkPDFDevice::internalDrawText( - const SkDraw& d, const void* sourceText, size_t sourceByteCount, + const void* sourceText, size_t sourceByteCount, const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, uint32_t textByteLength, const char* utf8Text) { @@ -1288,7 +1307,12 @@ void SkPDFDevice::internalDrawText( } bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); paint.setHinting(SkPaint::kNo_Hinting); - SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); + + int emSize; + SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(typeface, &emSize); + + SkScalar textSize = paint.getTextSize(); + SkScalar advanceScale = textSize * paint.getTextScaleX() / emSize; SkPaint::Align alignment = paint.getTextAlign(); float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : @@ -1297,22 +1321,22 @@ void SkPDFDevice::internalDrawText( if (defaultPositioning && alignment != SkPaint::kLeft_Align) { SkScalar advance = 0; for (int i = 0; i < glyphCount; ++i) { - advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; + advance += advanceScale * glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; } offset.offset(alignmentFactor * advance, 0); } - ScopedContentEntry content(this, d, paint, true); + ScopedContentEntry content(this, paint, true); if (!content.entry()) { return; } SkDynamicMemoryWStream* out = &content.entry()->fContent; - SkScalar textSize = paint.getTextSize(); const SkTDArray& glyphToUnicode = metrics->fGlyphToUnicode; out->writeText("BT\n"); SK_AT_SCOPE_EXIT(out->writeText("ET\n")); - const SkGlyphID maxGlyphID = metrics->fLastGlyphID; + const SkGlyphID maxGlyphID = SkToU16(typeface->countGlyphs() - 1); + bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics)); if (clusterator.reversedChars()) { out->writeText("/ReversedChars BMC\n"); @@ -1334,9 +1358,11 @@ void SkPDFDevice::internalDrawText( if (c.fUtf8Text) { // real cluster // Check if `/ActualText` needed. const char* textPtr = c.fUtf8Text; - // TODO(halcanary): validate utf8 input. - SkUnichar unichar = SkUTF8_NextUnichar(&textPtr); const char* textEnd = c.fUtf8Text + c.fTextByteLength; + SkUnichar unichar = SkUTF8_NextUnicharWithError(&textPtr, textEnd); + if (unichar < 0) { + return; + } if (textPtr < textEnd || // more characters left glyphLimit > index + 1 || // toUnicode wouldn't work unichar != map_glyph(glyphToUnicode, glyphs[index])) // test single Unichar map @@ -1347,7 +1373,10 @@ void SkPDFDevice::internalDrawText( // the BOM marks this text as UTF-16BE, not PDFDocEncoding. SkPDFUtils::WriteUTF16beHex(out, unichar); // first char while (textPtr < textEnd) { - unichar = SkUTF8_NextUnichar(&textPtr); + unichar = SkUTF8_NextUnicharWithError(&textPtr, textEnd); + if (unichar < 0) { + break; + } SkPDFUtils::WriteUTF16beHex(out, unichar); } out->writeText("> >> BDC\n"); // begin marked-content sequence @@ -1380,7 +1409,7 @@ void SkPDFDevice::internalDrawText( SkPoint xy{0, 0}; SkScalar advance{0}; if (!defaultPositioning) { - advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX; + advance = advanceScale * glyphCache->getGlyphIDAdvance(gid).fAdvanceX; xy = SkTextBlob::kFull_Positioning == positioning ? SkPoint{pos[2 * index], pos[2 * index + 1]} : SkPoint{pos[index], 0}; @@ -1395,20 +1424,20 @@ void SkPDFDevice::internalDrawText( } } -void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, +void SkPDFDevice::drawText(const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint& paint) { - this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioning, + this->internalDrawText(text, len, nullptr, SkTextBlob::kDefault_Positioning, SkPoint{x, y}, paint, nullptr, 0, nullptr); } -void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, +void SkPDFDevice::drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { - this->internalDrawText(d, text, len, pos, (SkTextBlob::GlyphPositioning)scalarsPerPos, + this->internalDrawText(text, len, pos, (SkTextBlob::GlyphPositioning)scalarsPerPos, offset, paint, nullptr, 0, nullptr); } -void SkPDFDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y, +void SkPDFDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint &paint, SkDrawFilter* drawFilter) { for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) { SkPaint runPaint(paint); @@ -1418,25 +1447,20 @@ void SkPDFDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkSca } runPaint.setFlags(this->filterTextFlags(runPaint)); SkPoint offset = it.offset() + SkPoint{x, y}; - this->internalDrawText(draw, it.glyphs(), sizeof(SkGlyphID) * it.glyphCount(), + this->internalDrawText(it.glyphs(), sizeof(SkGlyphID) * it.glyphCount(), it.pos(), it.positioning(), offset, runPaint, it.clusters(), it.textSize(), it.text()); } } -void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, - int vertexCount, const SkPoint verts[], - const SkPoint texs[], const SkColor colors[], - SkXfermode* xmode, const uint16_t indices[], - int indexCount, const SkPaint& paint) { - if (d.fRC->isEmpty()) { +void SkPDFDevice::drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) { + if (this->cs().isEmpty(size(*this))) { return; } // TODO: implement drawVertices } -void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device, - int x, int y, const SkPaint& paint) { +void SkPDFDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) { SkASSERT(!paint.getImageFilter()); // Check if the source device is really a bitmapdevice (because that's what we returned @@ -1445,7 +1469,7 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device, if (device->peekPixels(&pmap)) { SkBitmap bitmap; bitmap.installPixels(pmap); - this->drawSprite(d, bitmap, x, y, paint); + this->drawSprite(bitmap, x, y, paint); return; } @@ -1471,9 +1495,8 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device, return; } - SkMatrix matrix; - matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); - ScopedContentEntry content(this, d.fClipStack, d.fRC->bwRgn(), matrix, paint); + SkMatrix matrix = SkMatrix::MakeTrans(SkIntToScalar(x), SkIntToScalar(y)); + ScopedContentEntry content(this, this->cs(), matrix, paint); if (!content.entry()) { return; } @@ -1527,13 +1550,10 @@ std::unique_ptr SkPDFDevice::content() const { SkPDFUtils::AppendTransform(fInitialTransform, &buffer); } - GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, &buffer); + GraphicStackState gsState(fExistingClipStack, &buffer); for (const auto& entry : fContentEntries) { - SkPoint translation; - translation.iset(this->getOrigin()); - translation.negate(); - gsState.updateClip(entry.fState.fClipStack, entry.fState.fClipRegion, - translation); + gsState.updateClip(entry.fState.fClipStack, + {0, 0}, SkRect::Make(size(*this))); gsState.updateMatrix(entry.fState.fMatrix); gsState.updateDrawingState(entry.fState); @@ -1554,14 +1574,14 @@ std::unique_ptr SkPDFDevice::content() const { * either as a (incorrect) fallback or because the path was not inverse * in the first place. */ -bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath, +bool SkPDFDevice::handleInversePath(const SkPath& origPath, const SkPaint& paint, bool pathIsMutable, const SkMatrix* prePathMatrix) { if (!origPath.isInverseFillType()) { return false; } - if (d.fRC->isEmpty()) { + if (this->cs().isEmpty(size(*this))) { return false; } @@ -1581,23 +1601,22 @@ bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath, // To be consistent with the raster output, hairline strokes // are rendered as non-inverted. modifiedPath.toggleInverseFillType(); - drawPath(d, modifiedPath, paint, nullptr, true); + this->drawPath(modifiedPath, paint, nullptr, true); return true; } } // Get bounds of clip in current transform space // (clip bounds are given in device space). - SkRect bounds; SkMatrix transformInverse; - SkMatrix totalMatrix = *d.fMatrix; + SkMatrix totalMatrix = this->ctm(); if (prePathMatrix) { totalMatrix.preConcat(*prePathMatrix); } if (!totalMatrix.invert(&transformInverse)) { return false; } - bounds.set(d.fRC->getBounds()); + SkRect bounds = this->cs().bounds(size(*this)); transformInverse.mapRect(&bounds); // Extend the bounds by the line width (plus some padding) @@ -1609,48 +1628,10 @@ bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath, return false; } - drawPath(d, modifiedPath, noInversePaint, prePathMatrix, true); + this->drawPath(modifiedPath, noInversePaint, prePathMatrix, true); return true; } -void SkPDFDevice::handlePointAnnotation(const SkPoint& point, - const SkMatrix& matrix, - const char key[], SkData* value) { - if (!value) { - return; - } - - if (!strcmp(SkAnnotationKeys::Define_Named_Dest_Key(), key)) { - SkPoint transformedPoint; - matrix.mapXY(point.x(), point.y(), &transformedPoint); - fNamedDestinations.emplace_back(value, transformedPoint); - } -} - -void SkPDFDevice::handlePathAnnotation(const SkPath& path, - const SkDraw& d, - const char key[], SkData* value) { - if (!value) { - return; - } - - SkRasterClip clip = *d.fRC; - clip.op(path, *d.fMatrix, SkIRect::MakeWH(width(), height()), - SkRegion::kIntersect_Op, - false); - SkRect transformedRect = SkRect::Make(clip.getBounds()); - - if (!strcmp(SkAnnotationKeys::URL_Key(), key)) { - if (!transformedRect.isEmpty()) { - fLinkToURLs.emplace_back(transformedRect, value); - } - } else if (!strcmp(SkAnnotationKeys::Link_Named_Dest_Key(), key)) { - if (!transformedRect.isEmpty()) { - fLinkToDestinations.emplace_back(transformedRect, value); - } - } -} - void SkPDFDevice::appendAnnotations(SkPDFArray* array) const { array->reserve(fLinkToURLs.count() + fLinkToDestinations.count()); for (const RectWithData& rectWithURL : fLinkToURLs) { @@ -1702,11 +1683,10 @@ sk_sp SkPDFDevice::makeFormXObjectFromDevice() { void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, sk_sp mask, - const SkClipStack* clipStack, - const SkRegion& clipRegion, + const SkClipStack& clipStack, SkBlendMode mode, bool invertClip) { - if (clipRegion.isEmpty() && !invertClip) { + if (!invertClip && clipStack.isEmpty(size(*this))) { return; } @@ -1714,11 +1694,9 @@ void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, std::move(mask), invertClip, SkPDFGraphicState::kAlpha_SMaskMode, fDocument->canon()); - SkMatrix identity; - identity.reset(); SkPaint paint; paint.setBlendMode(mode); - ScopedContentEntry content(this, clipStack, clipRegion, identity, paint); + ScopedContentEntry content(this, clipStack, SkMatrix::I(), paint); if (!content.entry()) { return; } @@ -1734,34 +1712,12 @@ void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, &content.entry()->fContent); } -SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack, - const SkRegion& clipRegion, - const SkMatrix& matrix, - const SkPaint& paint, - bool hasText, - sk_sp* dst) { +SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack& clipStack, + const SkMatrix& matrix, + const SkPaint& paint, + bool hasText, + sk_sp* dst) { *dst = nullptr; - if (clipRegion.isEmpty()) { - return nullptr; - } - - // The clip stack can come from an SkDraw where it is technically optional. - SkClipStack synthesizedClipStack; - if (clipStack == nullptr) { - if (clipRegion == fExistingClipRegion) { - clipStack = &fExistingClipStack; - } else { - // GraphicStackState::updateClip expects the clip stack to have - // fExistingClip as a prefix, so start there, then set the clip - // to the passed region. - synthesizedClipStack = fExistingClipStack; - SkPath clipPath; - clipRegion.getBoundaryPath(&clipPath); - synthesizedClipStack.clipPath(clipPath, SkMatrix::I(), SkCanvas::kReplace_Op, false); - clipStack = &synthesizedClipStack; - } - } - SkBlendMode blendMode = paint.getBlendMode(); // For the following modes, we want to handle source and destination @@ -1794,15 +1750,14 @@ SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* cli } SkPDFDevice::ContentEntry* entry; - if (fContentEntries.back() && fContentEntries.back()->fContent.getOffset() == 0) { + if (fContentEntries.back() && fContentEntries.back()->fContent.bytesWritten() == 0) { entry = fContentEntries.back(); } else if (blendMode != SkBlendMode::kDstOver) { entry = fContentEntries.emplace_back(); } else { entry = fContentEntries.emplace_front(); } - populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, - hasText, &entry->fState); + populateGraphicStateEntryFromPaint(matrix, clipStack, paint, hasText, &entry->fState); return entry; } @@ -1824,7 +1779,7 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, } if (blendMode == SkBlendMode::kDstOver) { SkASSERT(!dst); - if (fContentEntries.front()->fContent.getOffset() == 0) { + if (fContentEntries.front()->fContent.bytesWritten() == 0) { // For DstOver, an empty content entry was inserted before the rest // of the content entries. If nothing was drawn, it needs to be // removed. @@ -1846,10 +1801,7 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, // saved. SkClipStack clipStack = fContentEntries.front()->fState.fClipStack; - SkRegion clipRegion = fContentEntries.front()->fState.fClipRegion; - SkMatrix identity; - identity.reset(); SkPaint stockPaint; sk_sp srcFormXObject; @@ -1861,9 +1813,7 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, // reduces to Dst. if (shape == nullptr || blendMode == SkBlendMode::kDstOut || blendMode == SkBlendMode::kSrcATop) { - ScopedContentEntry content(this, &fExistingClipStack, - fExistingClipRegion, identity, - stockPaint); + ScopedContentEntry content(this, fExistingClipStack, SkMatrix::I(), stockPaint); // TODO: addXObjectResource take sk_sp SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst.get()), &content.entry()->fContent); @@ -1884,29 +1834,23 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, // the non-transparent parts of the device and the outlines (shape) of // all images and devices drawn. drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst, - &fExistingClipStack, fExistingClipRegion, - SkBlendMode::kSrcOver, true); + fExistingClipStack, SkBlendMode::kSrcOver, true); } else { if (shape != nullptr) { // Draw shape into a form-xobject. - SkRasterClip rc(clipRegion); - SkDraw d; - d.fMatrix = &identity; - d.fRC = &rc; - d.fClipStack = &clipStack; SkPaint filledPaint; filledPaint.setColor(SK_ColorBLACK); filledPaint.setStyle(SkPaint::kFill_Style); - this->drawPath(d, *shape, filledPaint, nullptr, true); - drawFormXObjectWithMask(addXObjectResource(dst.get()), - this->makeFormXObjectFromDevice(), - &fExistingClipStack, fExistingClipRegion, - SkBlendMode::kSrcOver, true); - + this->internalDrawPath(clipStack, SkMatrix::I(), *shape, filledPaint, nullptr, true); + this->drawFormXObjectWithMask(this->addXObjectResource(dst.get()), + this->makeFormXObjectFromDevice(), + fExistingClipStack, + SkBlendMode::kSrcOver, true); } else { - drawFormXObjectWithMask(addXObjectResource(dst.get()), srcFormXObject, - &fExistingClipStack, fExistingClipRegion, - SkBlendMode::kSrcOver, true); + this->drawFormXObjectWithMask(this->addXObjectResource(dst.get()), + srcFormXObject, + fExistingClipStack, + SkBlendMode::kSrcOver, true); } } @@ -1914,8 +1858,7 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, return; } else if (blendMode == SkBlendMode::kSrc || blendMode == SkBlendMode::kDstATop) { - ScopedContentEntry content(this, &fExistingClipStack, - fExistingClipRegion, identity, stockPaint); + ScopedContentEntry content(this, fExistingClipStack, SkMatrix::I(), stockPaint); if (content.entry()) { SkPDFUtils::DrawFormXObject( this->addXObjectResource(srcFormXObject.get()), @@ -1925,8 +1868,8 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, return; } } else if (blendMode == SkBlendMode::kSrcATop) { - ScopedContentEntry content(this, &fExistingClipStack, - fExistingClipRegion, identity, stockPaint); + ScopedContentEntry content(this, fExistingClipStack, + SkMatrix::I(), stockPaint); if (content.entry()) { SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst.get()), &content.entry()->fContent); @@ -1946,7 +1889,7 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, blendMode == SkBlendMode::kSrcATop) { drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), std::move(dst), - &fExistingClipStack, fExistingClipRegion, + fExistingClipStack, SkBlendMode::kSrcOver, blendMode == SkBlendMode::kSrcOut); return; @@ -1955,20 +1898,19 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, int resourceID = addXObjectResource(dst.get()); if (blendMode == SkBlendMode::kModulate) { drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), - std::move(dst), &fExistingClipStack, - fExistingClipRegion, + std::move(dst), fExistingClipStack, SkBlendMode::kSrcOver, false); mode = SkBlendMode::kMultiply; } drawFormXObjectWithMask(resourceID, std::move(srcFormXObject), - &fExistingClipStack, fExistingClipRegion, mode, + fExistingClipStack, mode, blendMode == SkBlendMode::kDstOut); return; } } bool SkPDFDevice::isContentEmpty() { - if (!fContentEntries.front() || fContentEntries.front()->fContent.getOffset() == 0) { + if (!fContentEntries.front() || fContentEntries.front()->fContent.bytesWritten() == 0) { SkASSERT(fContentEntries.count() <= 1); return true; } @@ -1978,7 +1920,6 @@ bool SkPDFDevice::isContentEmpty() { void SkPDFDevice::populateGraphicStateEntryFromPaint( const SkMatrix& matrix, const SkClipStack& clipStack, - const SkRegion& clipRegion, const SkPaint& paint, bool hasText, SkPDFDevice::GraphicStateEntry* entry) { @@ -1988,7 +1929,6 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint( entry->fMatrix = matrix; entry->fClipStack = clipStack; - entry->fClipRegion = clipRegion; entry->fColor = SkColorSetA(paint.getColor(), 0xFF); entry->fShaderIndex = -1; @@ -1997,49 +1937,47 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint( SkShader* shader = paint.getShader(); SkColor color = paint.getColor(); if (shader) { - // PDF positions patterns relative to the initial transform, so - // we need to apply the current transform to the shader parameters. - SkMatrix transform = matrix; - transform.postConcat(fInitialTransform); - - // PDF doesn't support kClamp_TileMode, so we simulate it by making - // a pattern the size of the current clip. - SkIRect bounds = clipRegion.getBounds(); - - // We need to apply the initial transform to bounds in order to get - // bounds in a consistent coordinate system. - SkRect boundsTemp; - boundsTemp.set(bounds); - fInitialTransform.mapRect(&boundsTemp); - boundsTemp.roundOut(&bounds); - - SkScalar rasterScale = - SkIntToScalar(fRasterDpi) / DPI_FOR_RASTER_SCALE_ONE; - pdfShader = SkPDFShader::GetPDFShader( - fDocument, fRasterDpi, shader, transform, bounds, rasterScale); - - if (pdfShader.get()) { - // pdfShader has been canonicalized so we can directly compare - // pointers. - int resourceIndex = fShaderResources.find(pdfShader.get()); - if (resourceIndex < 0) { - resourceIndex = fShaderResources.count(); - fShaderResources.push(pdfShader.get()); - pdfShader.get()->ref(); - } - entry->fShaderIndex = resourceIndex; - } else { - // A color shader is treated as an invalid shader so we don't have - // to set a shader just for a color. + if (SkShader::kColor_GradientType == shader->asAGradient(nullptr)) { + // We don't have to set a shader just for a color. SkShader::GradientInfo gradientInfo; - SkColor gradientColor; + SkColor gradientColor = SK_ColorBLACK; gradientInfo.fColors = &gradientColor; gradientInfo.fColorOffsets = nullptr; gradientInfo.fColorCount = 1; - if (shader->asAGradient(&gradientInfo) == - SkShader::kColor_GradientType) { - entry->fColor = SkColorSetA(gradientColor, 0xFF); - color = gradientColor; + SkAssertResult(shader->asAGradient(&gradientInfo) == SkShader::kColor_GradientType); + entry->fColor = SkColorSetA(gradientColor, 0xFF); + color = gradientColor; + } else { + // PDF positions patterns relative to the initial transform, so + // we need to apply the current transform to the shader parameters. + SkMatrix transform = matrix; + transform.postConcat(fInitialTransform); + + // PDF doesn't support kClamp_TileMode, so we simulate it by making + // a pattern the size of the current clip. + SkRect clipStackBounds = clipStack.bounds(size(*this)); + + // We need to apply the initial transform to bounds in order to get + // bounds in a consistent coordinate system. + fInitialTransform.mapRect(&clipStackBounds); + SkIRect bounds; + clipStackBounds.roundOut(&bounds); + + SkScalar rasterScale = + SkIntToScalar(fRasterDpi) / DPI_FOR_RASTER_SCALE_ONE; + pdfShader = SkPDFShader::GetPDFShader( + fDocument, fRasterDpi, shader, transform, bounds, rasterScale); + + if (pdfShader.get()) { + // pdfShader has been canonicalized so we can directly compare + // pointers. + int resourceIndex = fShaderResources.find(pdfShader.get()); + if (resourceIndex < 0) { + resourceIndex = fShaderResources.count(); + fShaderResources.push(pdfShader.get()); + pdfShader.get()->ref(); + } + entry->fShaderIndex = resourceIndex; } } } @@ -2104,9 +2042,7 @@ int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { return resourceIndex; } -static SkSize rect_to_size(const SkRect& r) { - return SkSize::Make(r.width(), r.height()); -} +static SkSize rect_to_size(const SkRect& r) { return {r.width(), r.height()}; } static sk_sp color_filter(const SkImageSubset& imageSubset, SkColorFilter* colorFilter) { @@ -2124,8 +2060,7 @@ static sk_sp color_filter(const SkImageSubset& imageSubset, //////////////////////////////////////////////////////////////////////////////// void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix, - const SkClipStack* clipStack, - const SkRegion& origClipRegion, + const SkClipStack& clipStack, SkImageSubset imageSubset, const SkPaint& paint) { if (imageSubset.dimensions().isZero()) { @@ -2135,8 +2070,6 @@ void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix, gDrawImageCalls.fetch_add(1); #endif SkMatrix matrix = origMatrix; - SkRegion perspectiveBounds; - const SkRegion* clipRegion = &origClipRegion; // Rasterize the bitmap using perspective in a new bitmap. if (origMatrix.hasPerspective()) { @@ -2206,9 +2139,6 @@ void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix, matrix.setScale(1 / scaleX, 1 / scaleY); matrix.postTranslate(deltaX, deltaY); - perspectiveBounds.setRect(bounds.roundOut()); - clipRegion = &perspectiveBounds; - imageSubset = SkImageSubset(surface->makeImageSnapshot()); } @@ -2221,7 +2151,7 @@ void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix, scaled.postScale(SkIntToScalar(imageSubset.dimensions().width()), SkIntToScalar(imageSubset.dimensions().height())); scaled.postConcat(matrix); - ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint); + ScopedContentEntry content(this, clipStack, scaled, paint); if (!content.entry()) { return; } @@ -2272,8 +2202,8 @@ void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix, #include "SkSpecialImage.h" #include "SkImageFilter.h" -void SkPDFDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, int y, - const SkPaint& paint) { +void SkPDFDevice::drawSpecial(SkSpecialImage* srcImg, int x, int y, + const SkPaint& paint) { SkASSERT(!srcImg->isTextureBacked()); SkBitmap resultBM; @@ -2281,10 +2211,11 @@ void SkPDFDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, SkImageFilter* filter = paint.getImageFilter(); if (filter) { SkIPoint offset = SkIPoint::Make(0, 0); - SkMatrix matrix = *draw.fMatrix; + SkMatrix matrix = this->ctm(); matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); - const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y); - SkAutoTUnref cache(this->getImageFilterCache()); + const SkIRect clipBounds = + this->cs().bounds(this->imageInfo().bounds()).roundOut().makeOffset(-x, -y); + sk_sp cache(this->getImageFilterCache()); // TODO: Should PDF be operating in a specified color space? For now, run the filter // in the same color space as the source (this is different from all other backends). SkImageFilter::OutputProperties outputProperties(srcImg->getColorSpace()); @@ -2295,12 +2226,12 @@ void SkPDFDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, SkPaint tmpUnfiltered(paint); tmpUnfiltered.setImageFilter(nullptr); if (resultImg->getROPixels(&resultBM)) { - this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); + this->drawSprite(resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); } } } else { if (srcImg->getROPixels(&resultBM)) { - this->drawSprite(draw, resultBM, x, y, paint); + this->drawSprite(resultBM, x, y, paint); } } } @@ -2310,8 +2241,12 @@ sk_sp SkPDFDevice::makeSpecial(const SkBitmap& bitmap) { } sk_sp SkPDFDevice::makeSpecial(const SkImage* image) { + // TODO: See comment above in drawSpecial. The color mode we use for decode should be driven + // by the destination where we're going to draw thing thing (ie this device). But we don't have + // a color space, so we always decode in legacy mode for now. + SkColorSpace* legacyColorSpace = nullptr; return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()), - image->makeNonTextureImage()); + image->makeNonTextureImage(), legacyColorSpace); } sk_sp SkPDFDevice::snapSpecial() { diff --git a/gfx/skia/skia/src/pdf/SkPDFDevice.h b/gfx/skia/skia/src/pdf/SkPDFDevice.h index 7d207e7cf944..93eb78dc50a8 100644 --- a/gfx/skia/skia/src/pdf/SkPDFDevice.h +++ b/gfx/skia/skia/src/pdf/SkPDFDevice.h @@ -11,8 +11,8 @@ #include "SkBitmap.h" #include "SkCanvas.h" #include "SkClipStack.h" +#include "SkClipStackDevice.h" #include "SkData.h" -#include "SkDevice.h" #include "SkPaint.h" #include "SkRect.h" #include "SkRefCnt.h" @@ -37,7 +37,7 @@ class SkRRect; The drawing context for the PDF backend. */ -class SkPDFDevice final : public SkBaseDevice { +class SkPDFDevice final : public SkClipStackDevice { public: /** Create a PDF drawing context. SkPDFDevice applies a * scale-and-translate transform to move the origin from the @@ -72,53 +72,47 @@ public: return new SkPDFDevice(pageSize, rasterDpi, doc, false); } - virtual ~SkPDFDevice(); + ~SkPDFDevice() override; /** These are called inside the per-device-layer loop for each draw call. When these are called, we have already applied any saveLayer operations, and are handling any looping from the paint, and any effects from the DrawFilter. */ - void drawPaint(const SkDraw&, const SkPaint& paint) override; - void drawPoints(const SkDraw&, SkCanvas::PointMode mode, + void drawPaint(const SkPaint& paint) override; + void drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint[], const SkPaint& paint) override; - void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) override; - void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) override; - void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) override; - void drawPath(const SkDraw&, const SkPath& origpath, + void drawRect(const SkRect& r, const SkPaint& paint) override; + void drawOval(const SkRect& oval, const SkPaint& paint) override; + void drawRRect(const SkRRect& rr, const SkPaint& paint) override; + void drawPath(const SkPath& origpath, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) override; - void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src, + void drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override; - void drawBitmap(const SkDraw&, const SkBitmap& bitmap, + void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint&) override; - void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, + void drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) override; - void drawImage(const SkDraw&, - const SkImage*, + void drawImage(const SkImage*, SkScalar x, SkScalar y, const SkPaint&) override; - void drawImageRect(const SkDraw&, - const SkImage*, + void drawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override; - void drawText(const SkDraw&, const void* text, size_t len, + void drawText(const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint&) override; - void drawPosText(const SkDraw&, const void* text, size_t len, + void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint&) override; - void drawTextBlob(const SkDraw&, const SkTextBlob*, SkScalar x, SkScalar y, + void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y, const SkPaint &, SkDrawFilter*) override; - void drawVertices(const SkDraw&, SkCanvas::VertexMode, - int vertexCount, const SkPoint verts[], - const SkPoint texs[], const SkColor colors[], - SkXfermode* xmode, const uint16_t indices[], - int indexCount, const SkPaint& paint) override; - void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, + void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override; + void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; // PDF specific methods. @@ -161,7 +155,6 @@ public: // we have to fall back to the region. Treat fClipStack as authoritative. // See https://bugs.skia.org/221 SkClipStack fClipStack; - SkRegion fClipRegion; // When emitting the content entry, we will ensure the graphic state // is set to these values first. @@ -175,9 +168,9 @@ public: protected: sk_sp makeSurface(const SkImageInfo&, const SkSurfaceProps&) override; - void drawAnnotation(const SkDraw&, const SkRect&, const char key[], SkData* value) override; + void drawAnnotation(const SkRect&, const char key[], SkData* value) override; - void drawSpecial(const SkDraw&, SkSpecialImage*, int x, int y, const SkPaint&) override; + void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&) override; sk_sp makeSpecial(const SkBitmap&) override; sk_sp makeSpecial(const SkImage*) override; sk_sp snapSpecial() override; @@ -209,7 +202,6 @@ private: SkISize fPageSize; SkMatrix fInitialTransform; SkClipStack fExistingClipStack; - SkRegion fExistingClipRegion; SkTArray fLinkToURLs; SkTArray fLinkToDestinations; @@ -244,8 +236,7 @@ private: void drawFormXObjectWithMask(int xObjectIndex, sk_sp mask, - const SkClipStack* clipStack, - const SkRegion& clipRegion, + const SkClipStack& clipStack, SkBlendMode, bool invertClip); @@ -253,8 +244,7 @@ private: // returns nullptr and does not create a content entry. // setUpContentEntry and finishContentEntry can be used directly, but // the preferred method is to use the ScopedContentEntry helper class. - ContentEntry* setUpContentEntry(const SkClipStack* clipStack, - const SkRegion& clipRegion, + ContentEntry* setUpContentEntry(const SkClipStack& clipStack, const SkMatrix& matrix, const SkPaint& paint, bool hasText, @@ -264,7 +254,6 @@ private: void populateGraphicStateEntryFromPaint(const SkMatrix& matrix, const SkClipStack& clipStack, - const SkRegion& clipRegion, const SkPaint& paint, bool hasText, GraphicStateEntry* entry); @@ -274,25 +263,29 @@ private: int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID); - void internalDrawText(const SkDraw&, const void*, size_t, const SkScalar pos[], + void internalDrawText( const void*, size_t, const SkScalar pos[], SkTextBlob::GlyphPositioning, SkPoint, const SkPaint&, const uint32_t*, uint32_t, const char*); void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry); void internalDrawImage(const SkMatrix& origMatrix, - const SkClipStack* clipStack, - const SkRegion& origClipRegion, + const SkClipStack& clipStack, SkImageSubset imageSubset, const SkPaint& paint); - bool handleInversePath(const SkDraw& d, const SkPath& origPath, + void internalDrawPath(const SkClipStack&, + const SkMatrix&, + const SkPath&, + const SkPaint&, + const SkMatrix* prePathMatrix, + bool pathIsMutable); + + bool handleInversePath(const SkPath& origPath, const SkPaint& paint, bool pathIsMutable, const SkMatrix* prePathMatrix = nullptr); - void handlePointAnnotation(const SkPoint&, const SkMatrix&, const char key[], SkData* value); - void handlePathAnnotation(const SkPath&, const SkDraw& d, const char key[], SkData* value); - typedef SkBaseDevice INHERITED; + typedef SkClipStackDevice INHERITED; // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create // an SkPDFDevice diff --git a/gfx/skia/skia/src/pdf/SkPDFDocument.cpp b/gfx/skia/skia/src/pdf/SkPDFDocument.cpp index ab5f465971be..92e82fc01832 100644 --- a/gfx/skia/skia/src/pdf/SkPDFDocument.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFDocument.cpp @@ -217,7 +217,7 @@ SkCanvas* SkPDFDocument::onBeginPage(SkScalar width, SkScalar height, SkScalarRoundToInt(width), SkScalarRoundToInt(height)); fPageDevice.reset( SkPDFDevice::Create(pageSize, fRasterDpi, this)); - fCanvas = sk_make_sp(fPageDevice); + fCanvas.reset(new SkPDFCanvas(fPageDevice)); fCanvas->clipRect(trimBox); fCanvas->translate(trimBox.x(), trimBox.y()); return fCanvas.get(); diff --git a/gfx/skia/skia/src/pdf/SkPDFDocument.h b/gfx/skia/skia/src/pdf/SkPDFDocument.h index b62a7a59a298..aa6dcb286fd3 100644 --- a/gfx/skia/skia/src/pdf/SkPDFDocument.h +++ b/gfx/skia/skia/src/pdf/SkPDFDocument.h @@ -50,7 +50,7 @@ public: const SkDocument::PDFMetadata&, sk_sp, bool); - virtual ~SkPDFDocument(); + ~SkPDFDocument() override; SkCanvas* onBeginPage(SkScalar, SkScalar, const SkRect&) override; void onEndPage() override; void onClose(SkWStream*) override; @@ -76,7 +76,7 @@ private: SkTHashSet fFonts; sk_sp fDests; sk_sp fPageDevice; - sk_sp fCanvas; + std::unique_ptr fCanvas; sk_sp fID; sk_sp fXMP; SkScalar fRasterDpi; diff --git a/gfx/skia/skia/src/pdf/SkPDFFont.cpp b/gfx/skia/skia/src/pdf/SkPDFFont.cpp index 284e1bfcd5d0..09d133ece762 100644 --- a/gfx/skia/skia/src/pdf/SkPDFFont.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFFont.cpp @@ -25,6 +25,24 @@ #include "sample/chromium/font_subsetter.h" #endif +SkAutoGlyphCache SkPDFFont::MakeVectorCache(SkTypeface* face, int* size) { + SkPaint tmpPaint; + tmpPaint.setHinting(SkPaint::kNo_Hinting); + tmpPaint.setTypeface(sk_ref_sp(face)); + int unitsPerEm = face->getUnitsPerEm(); + if (unitsPerEm <= 0) { + unitsPerEm = 1024; + } + if (size) { + *size = unitsPerEm; + } + tmpPaint.setTextSize((SkScalar)unitsPerEm); + const SkSurfaceProps props(0, kUnknown_SkPixelGeometry); + SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr); + SkASSERT(glyphCache.get()); + return glyphCache; +} + namespace { // PDF's notion of symbolic vs non-symbolic is related to the character set, not // symbols vs. characters. Rarely is a font the right character set to call it @@ -33,7 +51,7 @@ static const int32_t kPdfSymbolic = 4; struct SkPDFType0Font final : public SkPDFFont { SkPDFType0Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&); - virtual ~SkPDFType0Font(); + ~SkPDFType0Font() override; void getFontSubset(SkPDFCanon*) override; #ifdef SK_DEBUG void emitObject(SkWStream*, const SkPDFObjNumMap&) const override; @@ -44,13 +62,13 @@ struct SkPDFType0Font final : public SkPDFFont { struct SkPDFType1Font final : public SkPDFFont { SkPDFType1Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&, SkPDFCanon*); - virtual ~SkPDFType1Font() {} + ~SkPDFType1Font() override {} void getFontSubset(SkPDFCanon*) override {} // TODO(halcanary): implement }; struct SkPDFType3Font final : public SkPDFFont { SkPDFType3Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&); - virtual ~SkPDFType3Font() {} + ~SkPDFType3Font() override {} void getFontSubset(SkPDFCanon*) override; }; @@ -58,28 +76,12 @@ struct SkPDFType3Font final : public SkPDFFont { // File-Local Functions /////////////////////////////////////////////////////////////////////////////// -static SkAutoGlyphCache vector_cache(SkTypeface* face, SkScalar size = 0) { - SkPaint tmpPaint; - tmpPaint.setHinting(SkPaint::kNo_Hinting); - tmpPaint.setTypeface(sk_ref_sp(face)); - if (0 == size) { - SkASSERT(face); - tmpPaint.setTextSize((SkScalar)face->getUnitsPerEm()); - } else { - tmpPaint.setTextSize(size); - } - const SkSurfaceProps props(0, kUnknown_SkPixelGeometry); - SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr); - SkASSERT(glyphCache.get()); - return glyphCache; -} - // scale from em-units to base-1000, returning as a SkScalar SkScalar from_font_units(SkScalar scaled, uint16_t emSize) { if (emSize == 1000) { return scaled; } else { - return SkScalarMulDiv(scaled, 1000, emSize); + return scaled * 1000 / emSize; } } @@ -155,9 +157,7 @@ const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface, nullptr, 0)); if (!metrics) { metrics = sk_make_sp(); - metrics->fLastGlyphID = SkToU16(count - 1); } - SkASSERT(metrics->fLastGlyphID == SkToU16(count - 1)); return *canon->fTypefaceMetrics.set(id, metrics.release()); } @@ -197,8 +197,7 @@ SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon, sk_sp typeface(sk_ref_sp(face)); SkASSERT(typeface); - SkGlyphID lastGlyph = metrics.fLastGlyphID; - SkASSERT(typeface->countGlyphs() == SkToInt(1 + metrics.fLastGlyphID)); + SkGlyphID lastGlyph = SkToU16(typeface->countGlyphs() - 1); // should be caught by SkPDFDevice::internalDrawText SkASSERT(glyphID <= lastGlyph); @@ -244,8 +243,8 @@ SkPDFFont::SkPDFFont(SkPDFFont::Info info) static void add_common_font_descriptor_entries(SkPDFDict* descriptor, const SkAdvancedTypefaceMetrics& metrics, + uint16_t emSize, int16_t defaultWidth) { - const uint16_t emSize = metrics.fEmSize; descriptor->insertName("FontName", metrics.fFontName); descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic)); descriptor->insertScalar("Ascent", @@ -258,7 +257,7 @@ static void add_common_font_descriptor_entries(SkPDFDict* descriptor, scaleFromFontUnits(metrics.fCapHeight, emSize)); descriptor->insertInt("ItalicAngle", metrics.fItalicAngle); descriptor->insertObject( - "FontBBox", makeFontBBox(metrics.fBBox, metrics.fEmSize)); + "FontBBox", makeFontBBox(metrics.fBBox, emSize)); if (defaultWidth > 0) { descriptor->insertScalar("MissingWidth", scaleFromFontUnits(defaultWidth, emSize)); @@ -317,8 +316,8 @@ static sk_sp get_subset_font_stream( unsigned char* subsetFont{nullptr}; sk_sp fontData(stream_to_data(std::move(fontAsset))); -#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) || defined(GOOGLE3) - // TODO(halcanary): update Android Framework to newest version of Sfntly. +#if defined(GOOGLE3) + // TODO(halcanary): update GOOGLE3 to newest version of Sfntly. (void)ttcIndex; int subsetFontSize = SfntlyWrapper::SubsetFont(fontName, fontData->bytes(), @@ -364,7 +363,8 @@ void SkPDFType0Font::getFontSubset(SkPDFCanon* canon) { SkASSERT(face); auto descriptor = sk_make_sp("FontDescriptor"); - add_common_font_descriptor_entries(descriptor.get(), metrics, 0); + uint16_t emSize = SkToU16(this->typeface()->getUnitsPerEm()); + add_common_font_descriptor_entries(descriptor.get(), metrics, emSize , 0); int ttcIndex; std::unique_ptr fontAsset(face->openStream(&ttcIndex)); @@ -430,17 +430,17 @@ void SkPDFType0Font::getFontSubset(SkPDFCanon* canon) { sysInfo->insertInt("Supplement", 0); newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo)); - uint16_t emSize = metrics.fEmSize; int16_t defaultWidth = 0; { - SkAutoGlyphCache glyphCache = vector_cache(face); + int emSize; + SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(face, &emSize); sk_sp widths = SkPDFMakeCIDGlyphWidthsArray( - glyphCache.get(), &this->glyphUsage(), emSize, &defaultWidth); + glyphCache.get(), &this->glyphUsage(), SkToS16(emSize), &defaultWidth); if (widths && widths->size() > 0) { newCIDFont->insertObject("W", std::move(widths)); } newCIDFont->insertScalar( - "DW", scaleFromFontUnits(defaultWidth, emSize)); + "DW", scaleFromFontUnits(defaultWidth, SkToS16(emSize))); } //////////////////////////////////////////////////////////////////////////// @@ -472,7 +472,8 @@ static sk_sp make_type1_font_descriptor( SkTypeface* typeface, const SkAdvancedTypefaceMetrics& info) { auto descriptor = sk_make_sp("FontDescriptor"); - add_common_font_descriptor_entries(descriptor.get(), info, 0); + uint16_t emSize = SkToU16(typeface->getUnitsPerEm()); + add_common_font_descriptor_entries(descriptor.get(), info, emSize, 0); if (!can_embed(info)) { return descriptor; } @@ -507,14 +508,14 @@ static void populate_type_1_font(SkPDFDict* font, font->insertInt("FirstChar", (size_t)0); font->insertInt("LastChar", (size_t)glyphCount); { - SkAutoGlyphCache glyphCache = vector_cache(typeface); + int emSize; + SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(typeface, &emSize); auto widths = sk_make_sp(); SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX; - const uint16_t emSize = info.fEmSize; - widths->appendScalar(from_font_units(advance, emSize)); + widths->appendScalar(from_font_units(advance, SkToU16(emSize))); for (unsigned gID = firstGlyphID; gID <= lastGlyphID; gID++) { advance = glyphCache->getGlyphIDAdvance(gID).fAdvanceX; - widths->appendScalar(from_font_units(advance, emSize)); + widths->appendScalar(from_font_units(advance, SkToU16(emSize))); } font->insertObject("Widths", std::move(widths)); } @@ -592,7 +593,6 @@ private: static void add_type3_font_info(SkPDFCanon* canon, SkPDFDict* font, SkTypeface* typeface, - SkScalar emSize, const SkBitSet& subset, SkGlyphID firstGlyphID, SkGlyphID lastGlyphID) { @@ -603,8 +603,9 @@ static void add_type3_font_info(SkPDFCanon* canon, while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) { --lastGlyphID; } - SkASSERT(emSize > 0.0f); - SkAutoGlyphCache cache = vector_cache(typeface, emSize); + int unitsPerEm; + SkAutoGlyphCache cache = SkPDFFont::MakeVectorCache(typeface, &unitsPerEm); + SkScalar emSize = (SkScalar)unitsPerEm; font->insertName("Subtype", "Type3"); // Flip about the x-axis and scale by 1/emSize. SkMatrix fontMatrix; @@ -712,12 +713,7 @@ SkPDFType3Font::SkPDFType3Font(SkPDFFont::Info info, : SkPDFFont(std::move(info)) {} void SkPDFType3Font::getFontSubset(SkPDFCanon* canon) { - const SkAdvancedTypefaceMetrics* info = - SkPDFFont::GetMetrics(this->typeface(), canon); - SkASSERT(info); - uint16_t emSize = info->fEmSize > 0 ? info->fEmSize : 1000; - add_type3_font_info(canon, this, this->typeface(), (SkScalar)emSize, - this->glyphUsage(), + add_type3_font_info(canon, this, this->typeface(), this->glyphUsage(), this->firstGlyphID(), this->lastGlyphID()); } diff --git a/gfx/skia/skia/src/pdf/SkPDFFont.h b/gfx/skia/skia/src/pdf/SkPDFFont.h index a14ae63572a5..67786f33fc87 100644 --- a/gfx/skia/skia/src/pdf/SkPDFFont.h +++ b/gfx/skia/skia/src/pdf/SkPDFFont.h @@ -15,6 +15,7 @@ #include "SkTDArray.h" #include "SkTypeface.h" +class SkAutoGlyphCache; class SkPDFCanon; class SkPDFFont; @@ -28,7 +29,7 @@ class SkPDFFont; class SkPDFFont : public SkPDFDict { public: - virtual ~SkPDFFont(); + ~SkPDFFont() override; /** Returns the typeface represented by this class. Returns nullptr for the * default typeface. @@ -47,6 +48,8 @@ public: type == SkAdvancedTypefaceMetrics::kTrueType_Font; } + static SkAutoGlyphCache MakeVectorCache(SkTypeface*, int* sizeOut); + /** Returns true if this font encoding supports glyph IDs above 255. */ bool multiByteGlyphs() const { return SkPDFFont::IsMultiByte(this->getType()); } diff --git a/gfx/skia/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp b/gfx/skia/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp index 988961e64b14..4d5471d9b331 100644 --- a/gfx/skia/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp @@ -43,7 +43,7 @@ static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) { if (emSize == 1000) { return scaled; } else { - return SkScalarMulDiv(scaled, 1000, emSize); + return scaled * 1000 / emSize; } } diff --git a/gfx/skia/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h b/gfx/skia/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h index d7a53a9b1633..4fc0072846b9 100644 --- a/gfx/skia/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h +++ b/gfx/skia/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h @@ -12,7 +12,7 @@ class SkBitSet; class SkGlyphCache; -/* PDF 32000-1:2008, page 270: "The array’s elements have a variable +/* PDF 32000-1:2008, page 270: "The array's elements have a variable format that can specify individual widths for consecutive CIDs or one width for a range of CIDs". */ sk_sp SkPDFMakeCIDGlyphWidthsArray(SkGlyphCache* cache, diff --git a/gfx/skia/skia/src/pdf/SkPDFMetadata.cpp b/gfx/skia/skia/src/pdf/SkPDFMetadata.cpp index 42068843bf43..ee5c19bba4bb 100644 --- a/gfx/skia/skia/src/pdf/SkPDFMetadata.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFMetadata.cpp @@ -164,7 +164,7 @@ public: stream->write(streamBegin, strlen(streamBegin)); // Do not compress this. The standard requires that a // program that does not understand PDF can grep for - // "write(fXML.c_str(), fXML.size()); static const char streamEnd[] = "\nendstream"; stream->write(streamEnd, strlen(streamEnd)); diff --git a/gfx/skia/skia/src/pdf/SkPDFShader.cpp b/gfx/skia/skia/src/pdf/SkPDFShader.cpp index 82b5b3475ea8..6a511855b9d5 100644 --- a/gfx/skia/skia/src/pdf/SkPDFShader.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFShader.cpp @@ -403,8 +403,7 @@ static void twoPointConicalCode(const SkShader::GradientInfo& info, SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY; SkScalar r0 = info.fRadius[0]; SkScalar dr = info.fRadius[1] - info.fRadius[0]; - SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - - SkScalarMul(dr, dr); + SkScalar a = dx * dx + dy * dy - dr * dr; // First compute t, if the pixel falls outside the cone, then we'll end // with 'false' on the stack, otherwise we'll push 'true' with t below it @@ -422,12 +421,12 @@ static void twoPointConicalCode(const SkShader::GradientInfo& info, function->writeText(" mul exch "); SkPDFUtils::AppendScalar(dx, function); function->writeText(" mul add "); - SkPDFUtils::AppendScalar(SkScalarMul(r0, dr), function); + SkPDFUtils::AppendScalar(r0 * dr, function); function->writeText(" add -2 mul dup dup mul\n"); // c = x^2 + y^2 + radius0^2 function->writeText("4 2 roll dup mul exch dup mul add "); - SkPDFUtils::AppendScalar(SkScalarMul(r0, r0), function); + SkPDFUtils::AppendScalar(r0 * r0, function); function->writeText(" sub dup 4 1 roll\n"); // Contents of the stack at this point: c, b, b^2, c @@ -453,7 +452,7 @@ static void twoPointConicalCode(const SkShader::GradientInfo& info, // root t for which radius(t) > 0 // compute the discriminant (b^2 - 4ac) - SkPDFUtils::AppendScalar(SkScalarMul(SkIntToScalar(4), a), function); + SkPDFUtils::AppendScalar(a * 4, function); function->writeText(" mul sub dup\n"); // if d >= 0, proceed @@ -578,6 +577,9 @@ sk_sp SkPDFShader::GetPDFShader(SkPDFDocument* doc, const SkMatrix& matrix, const SkIRect& surfaceBBox, SkScalar rasterScale) { + if (surfaceBBox.isEmpty()) { + return nullptr; + } SkBitmap image; State state(shader, matrix, surfaceBBox, rasterScale, &image); return get_pdf_shader_by_state( @@ -1214,8 +1216,15 @@ bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const { SkPDFShader::State::State(SkShader* shader, const SkMatrix& canvasTransform, const SkIRect& bbox, SkScalar rasterScale, SkBitmap* imageDst) - : fCanvasTransform(canvasTransform), - fBBox(bbox) { + : fType(SkShader::kNone_GradientType) + , fInfo{0, nullptr, nullptr, {{0.0f, 0.0f}, {0.0f, 0.0f}}, + {0.0f, 0.0f}, SkShader::kClamp_TileMode, 0} + , fCanvasTransform(canvasTransform) + , fShaderTransform{SkMatrix::I()} + , fBBox(bbox) + , fBitmapKey{{0, 0, 0, 0}, 0} + , fImageTileModes{SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode} { SkASSERT(imageDst); fInfo.fColorCount = 0; fInfo.fColors = nullptr; @@ -1260,10 +1269,10 @@ SkPDFShader::State::State(SkShader* shader, const SkMatrix& canvasTransform, rasterScale *= SkScalarSqrt(kMaxBitmapArea / bitmapArea); } - SkISize size = SkISize::Make(SkScalarRoundToInt(rasterScale * bbox.width()), - SkScalarRoundToInt(rasterScale * bbox.height())); - SkSize scale = SkSize::Make(SkIntToScalar(size.width()) / shaderRect.width(), - SkIntToScalar(size.height()) / shaderRect.height()); + SkISize size = {SkScalarRoundToInt(rasterScale * bbox.width()), + SkScalarRoundToInt(rasterScale * bbox.height())}; + SkSize scale = {SkIntToScalar(size.width()) / shaderRect.width(), + SkIntToScalar(size.height()) / shaderRect.height()}; imageDst->allocN32Pixels(size.width(), size.height()); imageDst->eraseColor(SK_ColorTRANSPARENT); diff --git a/gfx/skia/skia/src/pdf/SkPDFTypes.cpp b/gfx/skia/skia/src/pdf/SkPDFTypes.cpp index 7a1e0a48f5e8..42b4ed49539e 100644 --- a/gfx/skia/skia/src/pdf/SkPDFTypes.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFTypes.cpp @@ -568,7 +568,7 @@ void SkPDFStream::setData(std::unique_ptr stream) { fDict.insertInt("Length", originalLength); return; } - fCompressedData.reset(compressedData.detachAsStream()); + fCompressedData = compressedData.detachAsStream(); fDict.insertName("Filter", "FlateDecode"); fDict.insertInt("Length", compressedLength); #endif diff --git a/gfx/skia/skia/src/pdf/SkPDFTypes.h b/gfx/skia/skia/src/pdf/SkPDFTypes.h index 201d62b2efe0..0be20f13a1d7 100644 --- a/gfx/skia/skia/src/pdf/SkPDFTypes.h +++ b/gfx/skia/skia/src/pdf/SkPDFTypes.h @@ -187,7 +187,7 @@ public: /** Create a PDF array. Maximum length is 8191. */ SkPDFArray(); - virtual ~SkPDFArray(); + ~SkPDFArray() override; // The SkPDFObject interface. void emitObject(SkWStream* stream, @@ -235,7 +235,7 @@ public: */ explicit SkPDFDict(const char type[] = nullptr); - virtual ~SkPDFDict(); + ~SkPDFDict() override; // The SkPDFObject interface. void emitObject(SkWStream* stream, @@ -298,7 +298,7 @@ private: class SkPDFSharedStream final : public SkPDFObject { public: SkPDFSharedStream(std::unique_ptr data); - ~SkPDFSharedStream(); + ~SkPDFSharedStream() override; SkPDFDict* dict() { return &fDict; } void emitObject(SkWStream*, const SkPDFObjNumMap&) const override; @@ -327,7 +327,7 @@ public: * @param stream The data part of the stream. */ explicit SkPDFStream(sk_sp data); explicit SkPDFStream(std::unique_ptr stream); - virtual ~SkPDFStream(); + ~SkPDFStream() override; SkPDFDict* dict() { return &fDict; } diff --git a/gfx/skia/skia/src/pdf/SkPDFUtils.cpp b/gfx/skia/skia/src/pdf/SkPDFUtils.cpp index 0fe6fb59a9df..2487043bb926 100644 --- a/gfx/skia/skia/src/pdf/SkPDFUtils.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFUtils.cpp @@ -117,11 +117,23 @@ void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) { // static void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle, - bool doConsumeDegerates, SkWStream* content) { + bool doConsumeDegerates, SkWStream* content, + SkScalar tolerance) { // Filling a path with no area results in a drawing in PDF renderers but // Chrome expects to be able to draw some such entities with no visible // result, so we detect those cases and discard the drawing for them. // Specifically: moveTo(X), lineTo(Y) and moveTo(X), lineTo(X), lineTo(Y). + + SkRect rect; + bool isClosed; // Both closure and direction need to be checked. + SkPath::Direction direction; + if (path.isRect(&rect, &isClosed, &direction) && + isClosed && SkPath::kCW_Direction == direction) + { + SkPDFUtils::AppendRectangle(rect, content); + return; + } + enum SkipFillState { kEmpty_SkipFillState, kSingleLine_SkipFillState, @@ -158,9 +170,8 @@ void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle, fillState = kNonSingleLine_SkipFillState; break; case SkPath::kConic_Verb: { - const SkScalar tol = SK_Scalar1 / 4; SkAutoConicToQuads converter; - const SkPoint* quads = converter.computeQuads(args, iter.conicWeight(), tol); + const SkPoint* quads = converter.computeQuads(args, iter.conicWeight(), tolerance); for (int i = 0; i < converter.countQuads(); ++i) { append_quad(&quads[i * 2], ¤tSegment); } @@ -172,9 +183,7 @@ void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle, fillState = kNonSingleLine_SkipFillState; break; case SkPath::kClose_Verb: - - ClosePath(¤tSegment); - + ClosePath(¤tSegment); currentSegment.writeToStream(content); currentSegment.reset(); break; diff --git a/gfx/skia/skia/src/pdf/SkPDFUtils.h b/gfx/skia/skia/src/pdf/SkPDFUtils.h index 964689f4f277..5c9e46b38166 100644 --- a/gfx/skia/skia/src/pdf/SkPDFUtils.h +++ b/gfx/skia/skia/src/pdf/SkPDFUtils.h @@ -45,10 +45,10 @@ void AppendCubic(SkScalar ctl1X, SkScalar ctl1Y, SkScalar dstX, SkScalar dstY, SkWStream* content); void AppendRectangle(const SkRect& rect, SkWStream* content); void EmitPath(const SkPath& path, SkPaint::Style paintStyle, - bool doConsumeDegerates, SkWStream* content); + bool doConsumeDegerates, SkWStream* content, SkScalar tolerance = 0.25f); inline void EmitPath(const SkPath& path, SkPaint::Style paintStyle, - SkWStream* content) { - SkPDFUtils::EmitPath(path, paintStyle, true, content); + SkWStream* content, SkScalar tolerance = 0.25f) { + SkPDFUtils::EmitPath(path, paintStyle, true, content, tolerance); } void ClosePath(SkWStream* content); void PaintPath(SkPaint::Style style, SkPath::FillType fill, diff --git a/gfx/skia/skia/src/pipe/SkPipeCanvas.cpp b/gfx/skia/skia/src/pipe/SkPipeCanvas.cpp index 3b636a23c057..1473b843f6ad 100644 --- a/gfx/skia/skia/src/pipe/SkPipeCanvas.cpp +++ b/gfx/skia/skia/src/pipe/SkPipeCanvas.cpp @@ -5,15 +5,16 @@ * found in the LICENSE file. */ -#include "SkPathEffect.h" +#include "SkAutoMalloc.h" #include "SkColorFilter.h" #include "SkDrawLooper.h" #include "SkImageFilter.h" #include "SkMaskFilter.h" +#include "SkPathEffect.h" #include "SkPipeCanvas.h" #include "SkPipeFormat.h" -#include "SkRasterizer.h" #include "SkRSXform.h" +#include "SkRasterizer.h" #include "SkShader.h" #include "SkStream.h" #include "SkTextBlob.h" @@ -208,7 +209,7 @@ public: /////////////////////////////////////////////////////////////////////////////////////////////////// SkPipeCanvas::SkPipeCanvas(const SkRect& cull, SkPipeDeduper* deduper, SkWStream* stream) - : INHERITED(SkScalarCeilToInt(cull.width()), SkScalarCeilToInt(cull.height())) + : INHERITED(cull.roundOut()) , fDeduper(deduper) , fStream(stream) {} @@ -239,7 +240,7 @@ SkCanvas::SaveLayerStrategy SkPipeCanvas::getSaveLayerStrategy(const SaveLayerRe if (rec.fBackdrop) { extra |= kHasBackdrop_SaveLayerMask; } - + writer.write32(pack_verb(SkPipeVerb::kSaveLayer, extra)); if (rec.fBounds) { writer.writeRect(*rec.fBounds); @@ -309,21 +310,21 @@ void SkPipeCanvas::didSetMatrix(const SkMatrix& matrix) { this->INHERITED::didSetMatrix(matrix); } -void SkPipeCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkPipeCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { fStream->write32(pack_verb(SkPipeVerb::kClipRect, ((unsigned)op << 1) | edgeStyle)); fStream->write(&rect, 4 * sizeof(SkScalar)); this->INHERITED::onClipRect(rect, op, edgeStyle); } -void SkPipeCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkPipeCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { fStream->write32(pack_verb(SkPipeVerb::kClipRRect, ((unsigned)op << 1) | edgeStyle)); write_rrect(fStream, rrect); this->INHERITED::onClipRRect(rrect, op, edgeStyle); } -void SkPipeCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkPipeCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { SkPipeWriter writer(this); writer.write32(pack_verb(SkPipeVerb::kClipPath, ((unsigned)op << 1) | edgeStyle)); writer.writePath(path); @@ -331,7 +332,7 @@ void SkPipeCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeS this->INHERITED::onClipPath(path, op, edgeStyle); } -void SkPipeCanvas::onClipRegion(const SkRegion& deviceRgn, ClipOp op) { +void SkPipeCanvas::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { SkPipeWriter writer(this); writer.write32(pack_verb(SkPipeVerb::kClipRegion, (unsigned)op << 1)); writer.writeRegion(deviceRgn); @@ -352,7 +353,7 @@ void SkPipeCanvas::onDrawArc(const SkRect& bounds, SkScalar startAngle, SkScalar } void SkPipeCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[], const SkRect rect[], - const SkColor colors[], int count, SkXfermode::Mode mode, + const SkColor colors[], int count, SkBlendMode mode, const SkRect* cull, const SkPaint* paint) { unsigned extra = (unsigned)mode; SkASSERT(0 == (extra & ~kMode_DrawAtlasMask)); @@ -479,7 +480,7 @@ void SkPipeCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& la } /////////////////////////////////////////////////////////////////////////////////////////////////// - + void SkPipeCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint) { unsigned extra = 0; @@ -603,9 +604,9 @@ void SkPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, S void SkPipeCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) { SkASSERT(byteLength); - + bool compact = fits_in(byteLength, 24); - + SkPipeWriter writer(this); writer.write32(pack_verb(SkPipeVerb::kDrawPosText, compact ? (unsigned)byteLength : 0)); if (!compact) { @@ -619,9 +620,9 @@ void SkPipeCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPo void SkPipeCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { SkASSERT(byteLength); - + bool compact = fits_in(byteLength, 24); - + SkPipeWriter writer(this); writer.write32(pack_verb(SkPipeVerb::kDrawPosTextH, compact ? (unsigned)byteLength : 0)); if (!compact) { @@ -660,13 +661,13 @@ void SkPipeCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const S void SkPipeCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], const SkRect* cull, const SkPaint& paint) { SkASSERT(byteLength); - + bool compact = fits_in(byteLength, 23); unsigned extra = compact ? (byteLength << 1) : 0; if (cull) { extra |= 1; } - + SkPipeWriter writer(this); writer.write32(pack_verb(SkPipeVerb::kDrawTextRSXform, extra)); if (!compact) { @@ -730,71 +731,24 @@ void SkPipeCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { write_paint(writer, paint, kGeometry_PaintUsage); } -void SkPipeCanvas::onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { - SkASSERT(vertexCount > 0); - - unsigned extra = 0; - if (vertexCount <= kVCount_DrawVerticesMask) { - extra |= vertexCount; - } - extra |= (unsigned)vmode << kVMode_DrawVerticesShift; - - SkXfermode::Mode mode = SkXfermode::kModulate_Mode; - if (xmode && !SkXfermode::AsMode(xmode, &mode)) { - mode = (SkXfermode::Mode)0xFF; // sentinel for read the xfer later - } - extra |= (unsigned)mode << kXMode_DrawVerticesShift; - - if (texs) { - extra |= kHasTex_DrawVerticesMask; - } - if (colors) { - extra |= kHasColors_DrawVerticesMask; - } - if (indexCount > 0) { - extra |= kHasIndices_DrawVerticesMask; - } +void SkPipeCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode, + const SkPaint& paint) { + unsigned extra = static_cast(bmode); SkPipeWriter writer(this); writer.write32(pack_verb(SkPipeVerb::kDrawVertices, extra)); - if (vertexCount > kVCount_DrawVerticesMask) { - writer.write32(vertexCount); - } - if (mode == (SkXfermode::Mode)0xFF) { - writer.writeFlattenable(xmode); - } - writer.write(vertices, vertexCount * sizeof(SkPoint)); - if (texs) { - writer.write(texs, vertexCount * sizeof(SkPoint)); - } - if (colors) { - writer.write(colors, vertexCount * sizeof(SkColor)); - } - if (indexCount > 0) { - writer.write32(indexCount); - SkASSERT(SkIsAlign2(indexCount)); - writer.write(indices, indexCount * sizeof(uint16_t)); - } + // TODO: dedup vertices? + writer.writeDataAsByteArray(vertices->encode().get()); write_paint(writer, paint, kVertices_PaintUsage); } void SkPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xfer, + const SkPoint texCoords[4], SkBlendMode bmode, const SkPaint& paint) { SkPipeWriter writer(this); unsigned extra = 0; - SkXfermode::Mode mode = SkXfermode::kModulate_Mode; - if (xfer && !xfer->asMode(&mode)) { - mode = (SkXfermode::Mode)kExplicitXfer_DrawPatchExtraValue; - } else { - xfer = nullptr; // signal that we're using the mode enum - } - SkASSERT(0 == (mode & ~kModeEnum_DrawPatchExtraMask)); - extra = (unsigned)mode; + SkASSERT(0 == ((int)bmode & ~kModeEnum_DrawPatchExtraMask)); + extra = (unsigned)bmode; if (colors) { extra |= kHasColors_DrawPatchExtraMask; } @@ -809,9 +763,6 @@ void SkPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4] if (texCoords) { writer.write(texCoords, sizeof(SkPoint) * 4); } - if (xfer) { - xfer->flatten(writer); - } write_paint(writer, paint, kGeometry_PaintUsage); } @@ -862,6 +813,15 @@ protected: } }; +static sk_sp default_image_serializer(SkImage* image) { + A8Serializer serial; + sk_sp data(image->encode(&serial)); + if (!data) { + data.reset(image->encode()); + } + return data; +} + static bool show_deduper_traffic = false; int SkPipeDeduper::findOrDefineImage(SkImage* image) { @@ -874,11 +834,8 @@ int SkPipeDeduper::findOrDefineImage(SkImage* image) { return index; } - A8Serializer serial; - sk_sp data(image->encode(&serial)); - if (!data) { - data.reset(image->encode()); - } + sk_sp data = fIMSerializer ? fIMSerializer->serialize(image) + : default_image_serializer(image); if (data) { index = fImages.add(image->uniqueID()); SkASSERT(index > 0); @@ -921,8 +878,10 @@ int SkPipeDeduper::findOrDefinePicture(SkPicture* picture) { ASSERT_FITS_IN(index, kObjectDefinitionBits); fStream->write32(pack_verb(SkPipeVerb::kEndPicture, index)); - SkDebugf(" definePicture(%d) %d\n", - index - 1, SkToU32(fStream->bytesWritten() - prevWritten)); + if (show_deduper_traffic) { + SkDebugf(" definePicture(%d) %d\n", + index - 1, SkToU32(fStream->bytesWritten() - prevWritten)); + } return index; } @@ -1017,6 +976,10 @@ void SkPipeSerializer::setTypefaceSerializer(SkTypefaceSerializer* tfs) { fImpl->fDeduper.setTypefaceSerializer(tfs); } +void SkPipeSerializer::setImageSerializer(SkImageSerializer* ims) { + fImpl->fDeduper.setImageSerializer(ims); +} + void SkPipeSerializer::resetCache() { fImpl->fDeduper.resetCaches(); } diff --git a/gfx/skia/skia/src/pipe/SkPipeCanvas.h b/gfx/skia/skia/src/pipe/SkPipeCanvas.h index 50d76edfd29f..5604ba787a28 100644 --- a/gfx/skia/skia/src/pipe/SkPipeCanvas.h +++ b/gfx/skia/skia/src/pipe/SkPipeCanvas.h @@ -8,9 +8,9 @@ #ifndef SkPipeCanvas_DEFINED #define SkPipeCanvas_DEFINED -#include "SkCanvas.h" #include "SkDeduper.h" #include "SkImage.h" +#include "SkNoDrawCanvas.h" #include "SkPipe.h" #include "SkTypeface.h" #include "SkWriteBuffer.h" @@ -63,6 +63,7 @@ public: void setCanvas(SkPipeCanvas* canvas) { fPipeCanvas = canvas; } void setStream(SkWStream* stream) { fStream = stream; } void setTypefaceSerializer(SkTypefaceSerializer* tfs) { fTFSerializer = tfs; } + void setImageSerializer(SkImageSerializer* ims) { fIMSerializer = ims; } // returns 0 if not found int findImage(SkImage* image) const { return fImages.find(image->uniqueID()); } @@ -78,6 +79,7 @@ private: SkWStream* fStream = nullptr; SkTypefaceSerializer* fTFSerializer = nullptr; + SkImageSerializer* fIMSerializer = nullptr; // All our keys (at the moment) are 32bit uniqueIDs SkTIndexSet fImages; @@ -87,7 +89,7 @@ private: }; -class SkPipeCanvas : public SkCanvas { +class SkPipeCanvas : public SkNoDrawCanvas { public: SkPipeCanvas(const SkRect& cull, SkPipeDeduper*, SkWStream*); ~SkPipeCanvas() override; @@ -103,7 +105,7 @@ protected: void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint&) override; void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], - int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) override; + int count, SkBlendMode, const SkRect* cull, const SkPaint*) override; void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint&) override; @@ -117,7 +119,7 @@ protected: void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], const SkRect* cull, const SkPaint& paint) override; void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], - SkXfermode*, const SkPaint&) override; + SkBlendMode, const SkPaint&) override; void onDrawPaint(const SkPaint&) override; void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; @@ -134,16 +136,12 @@ protected: const SkPaint*) override; void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst, const SkPaint*) override; - void onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; - void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; - void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, ClipOp) override; + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; void onDrawAnnotation(const SkRect&, const char[], SkData*) override; @@ -163,7 +161,7 @@ private: friend class SkPipeWriter; - typedef SkCanvas INHERITED; + typedef SkNoDrawCanvas INHERITED; }; diff --git a/gfx/skia/skia/src/pipe/SkPipeReader.cpp b/gfx/skia/skia/src/pipe/SkPipeReader.cpp index 47d4072d0661..974e6b005d21 100644 --- a/gfx/skia/skia/src/pipe/SkPipeReader.cpp +++ b/gfx/skia/skia/src/pipe/SkPipeReader.cpp @@ -7,6 +7,7 @@ #include "SkCanvas.h" #include "SkDeduper.h" +#include "SkImageDeserializer.h" #include "SkPicture.h" #include "SkPictureRecorder.h" #include "SkPipe.h" @@ -16,6 +17,7 @@ #include "SkRSXform.h" #include "SkTextBlob.h" #include "SkTypeface.h" +#include "SkVertices.h" class SkPipeReader; @@ -27,12 +29,13 @@ class SkPipeInflator : public SkInflator { public: SkPipeInflator(SkRefSet* images, SkRefSet* pictures, SkRefSet* typefaces, SkTDArray* factories, - SkTypefaceDeserializer* tfd) + SkTypefaceDeserializer* tfd, SkImageDeserializer* imd) : fImages(images) , fPictures(pictures) , fTypefaces(typefaces) , fFactories(factories) , fTFDeserializer(tfd) + , fIMDeserializer(imd) {} SkImage* getImage(int index) override { @@ -76,8 +79,13 @@ public: void setTypefaceDeserializer(SkTypefaceDeserializer* tfd) { fTFDeserializer = tfd; } - + + void setImageDeserializer(SkImageDeserializer* imd) { + fIMDeserializer = imd; + } + sk_sp makeTypeface(const void* data, size_t size); + sk_sp makeImage(const sk_sp&); private: SkRefSet* fImages; @@ -86,6 +94,7 @@ private: SkTDArray* fFactories; SkTypefaceDeserializer* fTFDeserializer; + SkImageDeserializer* fIMDeserializer; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -263,21 +272,21 @@ static void concat_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* static void clipRect_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { SkASSERT(SkPipeVerb::kClipRect == unpack_verb(packedVerb)); - SkCanvas::ClipOp op = (SkCanvas::ClipOp)(unpack_verb_extra(packedVerb) >> 1); + SkClipOp op = (SkClipOp)(unpack_verb_extra(packedVerb) >> 1); bool isAA = unpack_verb_extra(packedVerb) & 1; canvas->clipRect(*skip(reader), op, isAA); } static void clipRRect_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { SkASSERT(SkPipeVerb::kClipRRect == unpack_verb(packedVerb)); - SkCanvas::ClipOp op = (SkCanvas::ClipOp)(unpack_verb_extra(packedVerb) >> 1); + SkClipOp op = (SkClipOp)(unpack_verb_extra(packedVerb) >> 1); bool isAA = unpack_verb_extra(packedVerb) & 1; canvas->clipRRect(read_rrect(reader), op, isAA); } static void clipPath_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { SkASSERT(SkPipeVerb::kClipPath == unpack_verb(packedVerb)); - SkCanvas::ClipOp op = (SkCanvas::ClipOp)(unpack_verb_extra(packedVerb) >> 1); + SkClipOp op = (SkClipOp)(unpack_verb_extra(packedVerb) >> 1); bool isAA = unpack_verb_extra(packedVerb) & 1; SkPath path; reader.readPath(&path); @@ -286,7 +295,7 @@ static void clipPath_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas static void clipRegion_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { SkASSERT(SkPipeVerb::kClipRegion == unpack_verb(packedVerb)); - SkCanvas::ClipOp op = (SkCanvas::ClipOp)(unpack_verb_extra(packedVerb) >> 1); + SkClipOp op = (SkClipOp)(unpack_verb_extra(packedVerb) >> 1); SkRegion region; reader.readRegion(®ion); canvas->clipRegion(region, op); @@ -302,7 +311,7 @@ static void drawArc_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* static void drawAtlas_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { SkASSERT(SkPipeVerb::kDrawAtlas == unpack_verb(packedVerb)); - SkXfermode::Mode mode = (SkXfermode::Mode)(packedVerb & kMode_DrawAtlasMask); + SkBlendMode mode = (SkBlendMode)(packedVerb & kMode_DrawAtlasMask); sk_sp image(reader.readImage()); int count = reader.read32(); const SkRSXform* xform = skip(reader, count); @@ -425,16 +434,8 @@ static void drawPatch_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanva if (packedVerb & kHasTexture_DrawPatchExtraMask) { tex = skip(reader, 4); } - sk_sp xfer; - unsigned mode = packedVerb & kModeEnum_DrawPatchExtraMask; - if (kExplicitXfer_DrawPatchExtraValue == mode) { - xfer = reader.readXfermode(); - } else { - if (mode != SkXfermode::kSrcOver_Mode) { - xfer = SkXfermode::Make((SkXfermode::Mode)mode); - } - } - canvas->drawPatch(cubics, colors, tex, xfer.get(), read_paint(reader)); + SkBlendMode mode = (SkBlendMode)(packedVerb & kModeEnum_DrawPatchExtraMask); + canvas->drawPatch(cubics, colors, tex, mode, read_paint(reader)); } static void drawPaint_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { @@ -567,37 +568,9 @@ static void drawImageLattice_handler(SkPipeReader& reader, uint32_t packedVerb, static void drawVertices_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { SkASSERT(SkPipeVerb::kDrawVertices == unpack_verb(packedVerb)); - SkCanvas::VertexMode vmode = (SkCanvas::VertexMode) - ((packedVerb & kVMode_DrawVerticesMask) >> kVMode_DrawVerticesShift); - int vertexCount = packedVerb & kVCount_DrawVerticesMask; - if (0 == vertexCount) { - vertexCount = reader.read32(); - } - sk_sp xfer; - unsigned xmode = (packedVerb & kXMode_DrawVerticesMask) >> kXMode_DrawVerticesShift; - if (0xFF == xmode) { - xfer = reader.readXfermode(); - } else { - xfer = SkXfermode::Make((SkXfermode::Mode)xmode); - } - const SkPoint* vertices = skip(reader, vertexCount); - const SkPoint* texs = nullptr; - if (packedVerb & kHasTex_DrawVerticesMask) { - texs = skip(reader, vertexCount); - } - const SkColor* colors = nullptr; - if (packedVerb & kHasColors_DrawVerticesMask) { - colors = skip(reader, vertexCount); - } - int indexCount = 0; - const uint16_t* indices = nullptr; - if (packedVerb & kHasIndices_DrawVerticesMask) { - indexCount = reader.read32(); - indices = skip(reader, indexCount); - } - - canvas->drawVertices(vmode, vertexCount, vertices, texs, colors, xfer.get(), - indices, indexCount, read_paint(reader)); + SkBlendMode bmode = (SkBlendMode)unpack_verb_extra(packedVerb); + sk_sp data = reader.readByteArrayAsData(); + canvas->drawVertices(SkVertices::Decode(data->data(), data->size()), bmode, read_paint(reader)); } static void drawPicture_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { @@ -677,7 +650,10 @@ static sk_sp make_from_skiaimageformat(const void* encoded, size_t enco return SkImage::MakeRasterData(info, pixels, width); } -static sk_sp make_from_encoded(const sk_sp& data) { +sk_sp SkPipeInflator::makeImage(const sk_sp& data) { + if (fIMDeserializer) { + return fIMDeserializer->makeFromData(data.get(), nullptr); + } sk_sp image = make_from_skiaimageformat(data->data(), data->size()); if (!image) { image = SkImage::MakeFromEncoded(data); @@ -685,6 +661,7 @@ static sk_sp make_from_encoded(const sk_sp& data) { return image; } + static void defineImage_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas*) { SkASSERT(SkPipeVerb::kDefineImage == unpack_verb(packedVerb)); SkPipeInflator* inflator = (SkPipeInflator*)reader.getInflator(); @@ -697,7 +674,7 @@ static void defineImage_handler(SkPipeReader& reader, uint32_t packedVerb, SkCan } else { // we are defining a new image sk_sp data = reader.readByteArrayAsData(); - sk_sp image = make_from_encoded(data); + sk_sp image = inflator->makeImage(data); if (!image) { SkDebugf("-- failed to decode\n"); } @@ -833,6 +810,7 @@ public: SkTDArray fFactories; SkTypefaceDeserializer* fTFDeserializer = nullptr; + SkImageDeserializer* fIMDeserializer = nullptr; }; SkPipeDeserializer::SkPipeDeserializer() : fImpl(new Impl) {} @@ -842,6 +820,10 @@ void SkPipeDeserializer::setTypefaceDeserializer(SkTypefaceDeserializer* tfd) { fImpl->fTFDeserializer = tfd; } +void SkPipeDeserializer::setImageDeserializer(SkImageDeserializer* imd) { + fImpl->fIMDeserializer = imd; +} + sk_sp SkPipeDeserializer::readImage(const void* data, size_t size) { if (size < sizeof(uint32_t)) { SkDebugf("-------- data length too short for readImage %d\n", size); @@ -855,7 +837,7 @@ sk_sp SkPipeDeserializer::readImage(const void* data, size_t size) { if (SkPipeVerb::kDefineImage == unpack_verb(packedVerb)) { SkPipeInflator inflator(&fImpl->fImages, &fImpl->fPictures, &fImpl->fTypefaces, &fImpl->fFactories, - fImpl->fTFDeserializer); + fImpl->fTFDeserializer, fImpl->fIMDeserializer); SkPipeReader reader(this, ptr, size); reader.setInflator(&inflator); defineImage_handler(reader, packedVerb, nullptr); @@ -885,7 +867,7 @@ sk_sp SkPipeDeserializer::readPicture(const void* data, size_t size) if (SkPipeVerb::kDefinePicture == unpack_verb(packedVerb)) { SkPipeInflator inflator(&fImpl->fImages, &fImpl->fPictures, &fImpl->fTypefaces, &fImpl->fFactories, - fImpl->fTFDeserializer); + fImpl->fTFDeserializer, fImpl->fIMDeserializer); SkPipeReader reader(this, ptr, size); reader.setInflator(&inflator); definePicture_handler(reader, packedVerb, nullptr); @@ -954,7 +936,7 @@ static bool do_playback(SkPipeReader& reader, SkCanvas* canvas, int* endPictureI bool SkPipeDeserializer::playback(const void* data, size_t size, SkCanvas* canvas) { SkPipeInflator inflator(&fImpl->fImages, &fImpl->fPictures, &fImpl->fTypefaces, &fImpl->fFactories, - fImpl->fTFDeserializer); + fImpl->fTFDeserializer, fImpl->fIMDeserializer); SkPipeReader reader(this, data, size); reader.setInflator(&inflator); return do_playback(reader, canvas); diff --git a/gfx/skia/skia/src/ports/SkDebug_android.cpp b/gfx/skia/skia/src/ports/SkDebug_android.cpp index 0a1b59a2cd0a..6821834dcf5f 100644 --- a/gfx/skia/skia/src/ports/SkDebug_android.cpp +++ b/gfx/skia/skia/src/ports/SkDebug_android.cpp @@ -14,8 +14,7 @@ #include // Print debug output to stdout as well. This is useful for command line -// applications (e.g. skia_launcher). To enable, include android_output as a -// gyp dependency. +// applications (e.g. skia_launcher). bool gSkDebugToStdOut = false; void SkDebugf(const char format[], ...) { diff --git a/gfx/skia/skia/src/ports/SkFontConfigInterface_direct.cpp b/gfx/skia/skia/src/ports/SkFontConfigInterface_direct.cpp index df68fae0a830..d552befb5ab7 100644 --- a/gfx/skia/skia/src/ports/SkFontConfigInterface_direct.cpp +++ b/gfx/skia/skia/src/ports/SkFontConfigInterface_direct.cpp @@ -7,8 +7,8 @@ /* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */ +#include "SkAutoMalloc.h" #include "SkBuffer.h" -#include "SkDataTable.h" #include "SkFixed.h" #include "SkFontConfigInterface_direct.h" #include "SkFontStyle.h" @@ -19,7 +19,6 @@ #include "SkTDArray.h" #include "SkTemplates.h" #include "SkTypeface.h" -#include "SkTypes.h" #include #include @@ -685,51 +684,3 @@ bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[], SkStreamAsset* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) { return SkStream::MakeFromFile(identity.fString.c_str()).release(); } - -/////////////////////////////////////////////////////////////////////////////// - -static bool find_name(const SkTDArray& list, const char* str) { - int count = list.count(); - for (int i = 0; i < count; ++i) { - if (!strcmp(list[i], str)) { - return true; - } - } - return false; -} - -sk_sp SkFontConfigInterfaceDirect::getFamilyNames() { - FCLocker lock; - - FcPattern* pat = FcPatternCreate(); - SkAutoTCallVProc autoDestroyPat(pat); - if (nullptr == pat) { - return nullptr; - } - - FcObjectSet* os = FcObjectSetBuild(FC_FAMILY, (char *)0); - SkAutoTCallVProc autoDestroyOs(os); - if (nullptr == os) { - return nullptr; - } - - FcFontSet* fs = FcFontList(nullptr, pat, os); - SkAutoTCallVProc autoDestroyFs(fs); - if (nullptr == fs) { - return nullptr; - } - - SkTDArray names; - SkTDArray sizes; - for (int i = 0; i < fs->nfont; ++i) { - FcPattern* match = fs->fonts[i]; - const char* famName = get_string(match, FC_FAMILY); - if (famName && !find_name(names, famName)) { - *names.append() = famName; - *sizes.append() = strlen(famName) + 1; - } - } - - return SkDataTable::MakeCopyArrays((const void*const*)names.begin(), - sizes.begin(), names.count()); -} diff --git a/gfx/skia/skia/src/ports/SkFontConfigInterface_direct.h b/gfx/skia/skia/src/ports/SkFontConfigInterface_direct.h index 6cd0a8f9ba5c..829f87092dc3 100644 --- a/gfx/skia/skia/src/ports/SkFontConfigInterface_direct.h +++ b/gfx/skia/skia/src/ports/SkFontConfigInterface_direct.h @@ -24,9 +24,6 @@ public: SkStreamAsset* openStream(const FontIdentity&) override; - // new APIs - sk_sp getFamilyNames() override; - protected: virtual bool isAccessible(const char* filename); diff --git a/gfx/skia/skia/src/ports/SkFontConfigTypeface.h b/gfx/skia/skia/src/ports/SkFontConfigTypeface.h index 0da78aed87bc..e27fbb3d8514 100644 --- a/gfx/skia/skia/src/ports/SkFontConfigTypeface.h +++ b/gfx/skia/skia/src/ports/SkFontConfigTypeface.h @@ -22,16 +22,16 @@ class SkTypeface_FCI : public SkTypeface_FreeType { public: static SkTypeface_FCI* Create(sk_sp fci, const SkFontConfigInterface::FontIdentity& fi, - const SkString& familyName, + SkString familyName, const SkFontStyle& style) { - return new SkTypeface_FCI(std::move(fci), fi, familyName, style); + return new SkTypeface_FCI(std::move(fci), fi, std::move(familyName), style); } static SkTypeface_FCI* Create(std::unique_ptr data, - SkFontStyle style, bool isFixedPitch) + SkString familyName, SkFontStyle style, bool isFixedPitch) { - return new SkTypeface_FCI(std::move(data), style, isFixedPitch); + return new SkTypeface_FCI(std::move(data), std::move(familyName), style, isFixedPitch); } const SkFontConfigInterface::FontIdentity& getIdentity() const { @@ -41,16 +41,18 @@ public: protected: SkTypeface_FCI(sk_sp fci, const SkFontConfigInterface::FontIdentity& fi, - const SkString& familyName, + SkString familyName, const SkFontStyle& style) : INHERITED(style, false) , fFCI(std::move(fci)) , fIdentity(fi) - , fFamilyName(familyName) + , fFamilyName(std::move(familyName)) , fFontData(nullptr) {} - SkTypeface_FCI(std::unique_ptr data, SkFontStyle style, bool isFixedPitch) + SkTypeface_FCI(std::unique_ptr data, + SkString familyName, SkFontStyle style, bool isFixedPitch) : INHERITED(style, isFixedPitch) + , fFamilyName(std::move(familyName)) , fFontData(std::move(data)) { SkASSERT(fFontData); diff --git a/gfx/skia/skia/src/ports/SkFontHost_FreeType.cpp b/gfx/skia/skia/src/ports/SkFontHost_FreeType.cpp index 71ce865f080c..91801cdbd0be 100644 --- a/gfx/skia/skia/src/ports/SkFontHost_FreeType.cpp +++ b/gfx/skia/skia/src/ports/SkFontHost_FreeType.cpp @@ -14,9 +14,11 @@ #include "SkFontDescriptor.h" #include "SkFontHost_FreeType_common.h" #include "SkGlyph.h" +#include "SkMakeUnique.h" #include "SkMask.h" #include "SkMaskGamma.h" #include "SkMatrix22.h" +#include "SkMalloc.h" #include "SkMutex.h" #include "SkOTUtils.h" #include "SkPath.h" @@ -24,12 +26,8 @@ #include "SkStream.h" #include "SkString.h" #include "SkTemplates.h" -#include "SkTypes.h" #include -#if defined(SK_CAN_USE_DLOPEN) -#include -#endif #include #include FT_ADVANCES_H #include FT_BITMAP_H @@ -44,6 +42,20 @@ #include FT_TYPE1_TABLES_H #include FT_XFREE86_H +// SK_FREETYPE_MINIMUM_RUNTIME_VERSION 0x +// Flag SK_FREETYPE_DLOPEN: also try dlopen to get newer features. +#define SK_FREETYPE_DLOPEN (0x1) +#ifndef SK_FREETYPE_MINIMUM_RUNTIME_VERSION +# if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) || defined (GOOGLE3) +# define SK_FREETYPE_MINIMUM_RUNTIME_VERSION (((FREETYPE_MAJOR) << 24) | ((FREETYPE_MINOR) << 16) | ((FREETYPE_PATCH) << 8)) +# else +# define SK_FREETYPE_MINIMUM_RUNTIME_VERSION ((2 << 24) | (3 << 16) | (11 << 8) | (SK_FREETYPE_DLOPEN)) +# endif +#endif +#if SK_FREETYPE_MINIMUM_RUNTIME_VERSION & SK_FREETYPE_DLOPEN +# include +#endif + // FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA // were introduced in FreeType 2.5.0. // The following may be removed once FreeType 2.5.0 is required to build. @@ -52,9 +64,14 @@ # define FT_PIXEL_MODE_BGRA 7 #endif +// FT_LOAD_BITMAP_METRICS_ONLY was introduced in FreeType 2.7.1 +// The following may be removed once FreeType 2.7.1 is required to build. +#ifndef FT_LOAD_BITMAP_METRICS_ONLY +# define FT_LOAD_BITMAP_METRICS_ONLY ( 1L << 22 ) +#endif + //#define ENABLE_GLYPH_SPEW // for tracing calls //#define DUMP_STRIKE_CREATION -//#define SK_FONTHOST_FREETYPE_USE_NORMAL_LCD_FILTER //#define SK_FONTHOST_FREETYPE_RUNTIME_VERSION //#define SK_GAMMA_APPLY_TO_A8 @@ -79,41 +96,62 @@ FT_MemoryRec_ gFTMemory = { nullptr, sk_ft_alloc, sk_ft_free, sk_ft_realloc }; class FreeTypeLibrary : SkNoncopyable { public: - FreeTypeLibrary() : fLibrary(nullptr), fIsLCDSupported(false), fLCDExtra(0) { + FreeTypeLibrary() + : fGetVarDesignCoordinates(nullptr) + , fLibrary(nullptr) + , fIsLCDSupported(false) + , fLCDExtra(0) + { if (FT_New_Library(&gFTMemory, &fLibrary)) { return; } FT_Add_Default_Modules(fLibrary); - // Setup LCD filtering. This reduces color fringes for LCD smoothed glyphs. - // Default { 0x10, 0x40, 0x70, 0x40, 0x10 } adds up to 0x110, simulating ink spread. - // SetLcdFilter must be called before SetLcdFilterWeights. - if (FT_Library_SetLcdFilter(fLibrary, FT_LCD_FILTER_DEFAULT) == 0) { - fIsLCDSupported = true; - fLCDExtra = 2; //Using a filter adds one full pixel to each side. + // When using dlsym + // *(void**)(&procPtr) = dlsym(self, "proc"); + // is non-standard, but safe for POSIX. Cannot write + // *reinterpret_cast(&procPtr) = dlsym(self, "proc"); + // because clang has not implemented DR573. See http://clang.llvm.org/cxx_dr_status.html . -#ifdef SK_FONTHOST_FREETYPE_USE_NORMAL_LCD_FILTER - // Adds to 0x110 simulating ink spread, but provides better results than default. - static unsigned char gGaussianLikeHeavyWeights[] = { 0x1A, 0x43, 0x56, 0x43, 0x1A, }; + FT_Int major, minor, patch; + FT_Library_Version(fLibrary, &major, &minor, &patch); -# if SK_FONTHOST_FREETYPE_RUNTIME_VERSION > 0x020400 - FT_Library_SetLcdFilterWeights(fLibrary, gGaussianLikeHeavyWeights); -# elif SK_CAN_USE_DLOPEN == 1 +#if SK_FREETYPE_MINIMUM_RUNTIME_VERSION >= 0x02070100 + fGetVarDesignCoordinates = FT_Get_Var_Design_Coordinates; +#elif SK_FREETYPE_MINIMUM_RUNTIME_VERSION & SK_FREETYPE_DLOPEN + if (major > 2 || ((major == 2 && minor > 7) || (major == 2 && minor == 7 && patch >= 0))) { //The FreeType library is already loaded, so symbols are available in process. void* self = dlopen(nullptr, RTLD_LAZY); if (self) { - FT_Library_SetLcdFilterWeightsProc setLcdFilterWeights; - //The following cast is non-standard, but safe for POSIX. - *reinterpret_cast(&setLcdFilterWeights) = - dlsym(self, "FT_Library_SetLcdFilterWeights"); + *(void**)(&fGetVarDesignCoordinates) = dlsym(self, "FT_Get_Var_Design_Coordinates"); + dlclose(self); + } + } +#endif + +#if SK_FREETYPE_MINIMUM_RUNTIME_VERSION >= 0x02070200 + FT_Set_Default_Properties(fLibrary); +#elif SK_FREETYPE_MINIMUM_RUNTIME_VERSION & SK_FREETYPE_DLOPEN + if (major > 2 || ((major == 2 && minor > 7) || (major == 2 && minor == 7 && patch >= 1))) { + //The FreeType library is already loaded, so symbols are available in process. + void* self = dlopen(nullptr, RTLD_LAZY); + if (self) { + FT_Set_Default_PropertiesProc setDefaultProperties; + *(void**)(&setDefaultProperties) = dlsym(self, "FT_Set_Default_Properties"); dlclose(self); - if (setLcdFilterWeights) { - setLcdFilterWeights(fLibrary, gGaussianLikeHeavyWeights); + if (setDefaultProperties) { + setDefaultProperties(fLibrary); } } -# endif + } #endif + + // Setup LCD filtering. This reduces color fringes for LCD smoothed glyphs. + // The default has changed over time, so this doesn't mean the same thing to all users. + if (FT_Library_SetLcdFilter(fLibrary, FT_LCD_FILTER_DEFAULT) == 0) { + fIsLCDSupported = true; + fLCDExtra = 2; //Using a filter adds one full pixel to each side. } } ~FreeTypeLibrary() { @@ -126,6 +164,13 @@ public: bool isLCDSupported() { return fIsLCDSupported; } int lcdExtra() { return fLCDExtra; } + // FT_Get_{MM,Var}_{Blend,Design}_Coordinates were added in FreeType 2.7.1. + // Prior to this there was no way to get the coordinates out of the FT_Face. + // This wasn't too bad because you needed to specify them anyway, and the clamp was provided. + // However, this doesn't work when face_index specifies named variations as introduced in 2.6.1. + using FT_Get_Var_Blend_CoordinatesProc = FT_Error (*)(FT_Face, FT_UInt, FT_Fixed*); + FT_Get_Var_Blend_CoordinatesProc fGetVarDesignCoordinates; + private: FT_Library fLibrary; bool fIsLCDSupported; @@ -138,7 +183,12 @@ private: // OpenSuse >= 11.4 (previous deprecated January 2012 / Nov 2013 for Evergreen 11.2) // Fedora >= 14 (good) // Android >= Gingerbread (good) - typedef FT_Error (*FT_Library_SetLcdFilterWeightsProc)(FT_Library, unsigned char*); + // RHEL >= 7 (6 has 2.3.11, EOL Nov 2020, Phase 3 May 2017) + using FT_Library_SetLcdFilterWeightsProc = FT_Error (*)(FT_Library, unsigned char*); + + // FreeType added the ability to read global properties in 2.7.0. After 2.7.1 a means for users + // of FT_New_Library to request these global properties to be read was added. + using FT_Set_Default_PropertiesProc = void (*)(FT_Library); }; struct SkFaceRec; @@ -177,10 +227,230 @@ static void unref_ft_library() { } } +/////////////////////////////////////////////////////////////////////////// + +struct SkFaceRec { + SkFaceRec* fNext; + std::unique_ptr> fFace; + FT_StreamRec fFTStream; + std::unique_ptr fSkStream; + uint32_t fRefCnt; + uint32_t fFontID; + + // FreeType prior to 2.7.1 does not implement retreiving variation design metrics. + // Cache the variation design metrics used to create the font if the user specifies them. + SkAutoSTMalloc<4, SkFixed> fAxes; + int fAxesCount; + + // FreeType from 2.6.1 (14d6b5d7) until 2.7.0 (ee3f36f6b38) uses font_index for both font index + // and named variation index on input, but masks the named variation index part on output. + // Manually keep track of when a named variation is requested for 2.6.1 until 2.7.1. + bool fNamedVariationSpecified; + + SkFaceRec(std::unique_ptr stream, uint32_t fontID); +}; + +extern "C" { + static unsigned long sk_ft_stream_io(FT_Stream ftStream, + unsigned long offset, + unsigned char* buffer, + unsigned long count) + { + SkStreamAsset* stream = static_cast(ftStream->descriptor.pointer); + + if (count) { + if (!stream->seek(offset)) { + return 0; + } + count = stream->read(buffer, count); + } + return count; + } + + static void sk_ft_stream_close(FT_Stream) {} +} + +SkFaceRec::SkFaceRec(std::unique_ptr stream, uint32_t fontID) + : fNext(nullptr), fSkStream(std::move(stream)), fRefCnt(1), fFontID(fontID) + , fAxesCount(0), fNamedVariationSpecified(false) +{ + sk_bzero(&fFTStream, sizeof(fFTStream)); + fFTStream.size = fSkStream->getLength(); + fFTStream.descriptor.pointer = fSkStream.get(); + fFTStream.read = sk_ft_stream_io; + fFTStream.close = sk_ft_stream_close; +} + +static void ft_face_setup_axes(SkFaceRec* rec, const SkFontData& data) { + if (!(rec->fFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) { + return; + } + + // If a named variation is requested, don't overwrite the named variation's position. + if (data.getIndex() > 0xFFFF) { + rec->fNamedVariationSpecified = true; + return; + } + + SkDEBUGCODE( + FT_MM_Var* variations = nullptr; + if (FT_Get_MM_Var(rec->fFace.get(), &variations)) { + SkDEBUGF(("INFO: font %s claims variations, but none found.\n", + rec->fFace->family_name)); + return; + } + SkAutoFree autoFreeVariations(variations); + + if (static_cast(data.getAxisCount()) != variations->num_axis) { + SkDEBUGF(("INFO: font %s has %d variations, but %d were specified.\n", + rec->fFace->family_name, variations->num_axis, data.getAxisCount())); + return; + } + ) + + SkAutoSTMalloc<4, FT_Fixed> coords(data.getAxisCount()); + for (int i = 0; i < data.getAxisCount(); ++i) { + coords[i] = data.getAxis()[i]; + } + if (FT_Set_Var_Design_Coordinates(rec->fFace.get(), data.getAxisCount(), coords.get())) { + SkDEBUGF(("INFO: font %s has variations, but specified variations could not be set.\n", + rec->fFace->family_name)); + return; + } + + rec->fAxesCount = data.getAxisCount(); + rec->fAxes.reset(rec->fAxesCount); + for (int i = 0; i < rec->fAxesCount; ++i) { + rec->fAxes[i] = data.getAxis()[i]; + } +} + +// Will return nullptr on failure +// Caller must lock gFTMutex before calling this function. +static SkFaceRec* ref_ft_face(const SkTypeface* typeface) { + gFTMutex.assertHeld(); + + const SkFontID fontID = typeface->uniqueID(); + SkFaceRec* cachedRec = gFaceRecHead; + while (cachedRec) { + if (cachedRec->fFontID == fontID) { + SkASSERT(cachedRec->fFace); + cachedRec->fRefCnt += 1; + return cachedRec; + } + cachedRec = cachedRec->fNext; + } + + std::unique_ptr data = typeface->makeFontData(); + if (nullptr == data || !data->hasStream()) { + return nullptr; + } + + std::unique_ptr rec(new SkFaceRec(data->detachStream(), fontID)); + + FT_Open_Args args; + memset(&args, 0, sizeof(args)); + const void* memoryBase = rec->fSkStream->getMemoryBase(); + if (memoryBase) { + args.flags = FT_OPEN_MEMORY; + args.memory_base = (const FT_Byte*)memoryBase; + args.memory_size = rec->fSkStream->getLength(); + } else { + args.flags = FT_OPEN_STREAM; + args.stream = &rec->fFTStream; + } + + { + FT_Face rawFace; + FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, data->getIndex(), &rawFace); + if (err) { + SkDEBUGF(("ERROR: unable to open font '%x'\n", fontID)); + return nullptr; + } + rec->fFace.reset(rawFace); + } + SkASSERT(rec->fFace); + + ft_face_setup_axes(rec.get(), *data); + + // FreeType will set the charmap to the "most unicode" cmap if it exists. + // If there are no unicode cmaps, the charmap is set to nullptr. + // However, "symbol" cmaps should also be considered "fallback unicode" cmaps + // because they are effectively private use area only (even if they aren't). + // This is the last on the fallback list at + // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html + if (!rec->fFace->charmap) { + FT_Select_Charmap(rec->fFace.get(), FT_ENCODING_MS_SYMBOL); + } + + rec->fNext = gFaceRecHead; + gFaceRecHead = rec.get(); + return rec.release(); +} + +// Caller must lock gFTMutex before calling this function. +// Marked extern because vc++ does not support internal linkage template parameters. +extern /*static*/ void unref_ft_face(SkFaceRec* faceRec) { + gFTMutex.assertHeld(); + + SkFaceRec* rec = gFaceRecHead; + SkFaceRec* prev = nullptr; + while (rec) { + SkFaceRec* next = rec->fNext; + if (rec->fFace == faceRec->fFace) { + if (--rec->fRefCnt == 0) { + if (prev) { + prev->fNext = next; + } else { + gFaceRecHead = next; + } + delete rec; + } + return; + } + prev = rec; + rec = next; + } + SkDEBUGFAIL("shouldn't get here, face not in list"); +} + +class AutoFTAccess { +public: + AutoFTAccess(const SkTypeface* tf) : fFaceRec(nullptr) { + gFTMutex.acquire(); + if (!ref_ft_library()) { + sk_throw(); + } + fFaceRec = ref_ft_face(tf); + } + + ~AutoFTAccess() { + if (fFaceRec) { + unref_ft_face(fFaceRec); + } + unref_ft_library(); + gFTMutex.release(); + } + + FT_Face face() { return fFaceRec ? fFaceRec->fFace.get() : nullptr; } + int getAxesCount() { return fFaceRec ? fFaceRec->fAxesCount : 0; } + SkFixed* getAxes() { return fFaceRec ? fFaceRec->fAxes.get() : nullptr; } + bool isNamedVariationSpecified() { + return fFaceRec ? fFaceRec->fNamedVariationSpecified : false; + } + +private: + SkFaceRec* fFaceRec; +}; + +/////////////////////////////////////////////////////////////////////////// + class SkScalerContext_FreeType : public SkScalerContext_FreeType_Base { public: - SkScalerContext_FreeType(SkTypeface*, const SkScalerContextEffects&, const SkDescriptor* desc); - virtual ~SkScalerContext_FreeType(); + SkScalerContext_FreeType(sk_sp, + const SkScalerContextEffects&, + const SkDescriptor* desc); + ~SkScalerContext_FreeType() override; bool success() const { return fFTSize != nullptr && fFace != nullptr; @@ -192,12 +462,15 @@ protected: void generateAdvance(SkGlyph* glyph) override; void generateMetrics(SkGlyph* glyph) override; void generateImage(const SkGlyph& glyph) override; - void generatePath(const SkGlyph& glyph, SkPath* path) override; + void generatePath(SkGlyphID glyphID, SkPath* path) override; void generateFontMetrics(SkPaint::FontMetrics*) override; SkUnichar generateGlyphToChar(uint16_t glyph) override; private: - FT_Face fFace; // Shared face from gFaceRecHead. + using UnrefFTFace = SkFunctionWrapper; + std::unique_ptr fFaceRec; + + FT_Face fFace; // Borrowed face from gFaceRecHead. FT_Size fFTSize; // The size on the fFace for this scaler. FT_Int fStrikeIndex; @@ -227,192 +500,6 @@ private: bool shouldSubpixelBitmap(const SkGlyph&, const SkMatrix&); }; -/////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////// - -struct SkFaceRec { - SkFaceRec* fNext; - FT_Face fFace; - FT_StreamRec fFTStream; - std::unique_ptr fSkStream; - uint32_t fRefCnt; - uint32_t fFontID; - - SkFaceRec(std::unique_ptr stream, uint32_t fontID); -}; - -extern "C" { - static unsigned long sk_ft_stream_io(FT_Stream ftStream, - unsigned long offset, - unsigned char* buffer, - unsigned long count) - { - SkStreamAsset* stream = static_cast(ftStream->descriptor.pointer); - - if (count) { - if (!stream->seek(offset)) { - return 0; - } - count = stream->read(buffer, count); - } - return count; - } - - static void sk_ft_stream_close(FT_Stream) {} -} - -SkFaceRec::SkFaceRec(std::unique_ptr stream, uint32_t fontID) - : fNext(nullptr), fSkStream(std::move(stream)), fRefCnt(1), fFontID(fontID) -{ - sk_bzero(&fFTStream, sizeof(fFTStream)); - fFTStream.size = fSkStream->getLength(); - fFTStream.descriptor.pointer = fSkStream.get(); - fFTStream.read = sk_ft_stream_io; - fFTStream.close = sk_ft_stream_close; -} - -static void ft_face_setup_axes(FT_Face face, const SkFontData& data) { - if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) { - return; - } - - SkDEBUGCODE( - FT_MM_Var* variations = nullptr; - if (FT_Get_MM_Var(face, &variations)) { - SkDEBUGF(("INFO: font %s claims variations, but none found.\n", face->family_name)); - return; - } - SkAutoFree autoFreeVariations(variations); - - if (static_cast(data.getAxisCount()) != variations->num_axis) { - SkDEBUGF(("INFO: font %s has %d variations, but %d were specified.\n", - face->family_name, variations->num_axis, data.getAxisCount())); - return; - } - ) - - SkAutoSTMalloc<4, FT_Fixed> coords(data.getAxisCount()); - for (int i = 0; i < data.getAxisCount(); ++i) { - coords[i] = data.getAxis()[i]; - } - if (FT_Set_Var_Design_Coordinates(face, data.getAxisCount(), coords.get())) { - SkDEBUGF(("INFO: font %s has variations, but specified variations could not be set.\n", - face->family_name)); - return; - } -} - -// Will return 0 on failure -// Caller must lock gFTMutex before calling this function. -static FT_Face ref_ft_face(const SkTypeface* typeface) { - gFTMutex.assertHeld(); - - const SkFontID fontID = typeface->uniqueID(); - SkFaceRec* rec = gFaceRecHead; - while (rec) { - if (rec->fFontID == fontID) { - SkASSERT(rec->fFace); - rec->fRefCnt += 1; - return rec->fFace; - } - rec = rec->fNext; - } - - std::unique_ptr data = typeface->makeFontData(); - if (nullptr == data || !data->hasStream()) { - return nullptr; - } - - rec = new SkFaceRec(data->detachStream(), fontID); - - FT_Open_Args args; - memset(&args, 0, sizeof(args)); - const void* memoryBase = rec->fSkStream->getMemoryBase(); - if (memoryBase) { - args.flags = FT_OPEN_MEMORY; - args.memory_base = (const FT_Byte*)memoryBase; - args.memory_size = rec->fSkStream->getLength(); - } else { - args.flags = FT_OPEN_STREAM; - args.stream = &rec->fFTStream; - } - - FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, data->getIndex(), &rec->fFace); - if (err) { - SkDEBUGF(("ERROR: unable to open font '%x'\n", fontID)); - delete rec; - return nullptr; - } - SkASSERT(rec->fFace); - - ft_face_setup_axes(rec->fFace, *data); - - // FreeType will set the charmap to the "most unicode" cmap if it exists. - // If there are no unicode cmaps, the charmap is set to nullptr. - // However, "symbol" cmaps should also be considered "fallback unicode" cmaps - // because they are effectively private use area only (even if they aren't). - // This is the last on the fallback list at - // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html - if (!rec->fFace->charmap) { - FT_Select_Charmap(rec->fFace, FT_ENCODING_MS_SYMBOL); - } - - rec->fNext = gFaceRecHead; - gFaceRecHead = rec; - return rec->fFace; -} - -// Caller must lock gFTMutex before calling this function. -extern void unref_ft_face(FT_Face face); -void unref_ft_face(FT_Face face) { - gFTMutex.assertHeld(); - - SkFaceRec* rec = gFaceRecHead; - SkFaceRec* prev = nullptr; - while (rec) { - SkFaceRec* next = rec->fNext; - if (rec->fFace == face) { - if (--rec->fRefCnt == 0) { - if (prev) { - prev->fNext = next; - } else { - gFaceRecHead = next; - } - FT_Done_Face(face); - delete rec; - } - return; - } - prev = rec; - rec = next; - } - SkDEBUGFAIL("shouldn't get here, face not in list"); -} - -class AutoFTAccess { -public: - AutoFTAccess(const SkTypeface* tf) : fFace(nullptr) { - gFTMutex.acquire(); - if (!ref_ft_library()) { - sk_throw(); - } - fFace = ref_ft_face(tf); - } - - ~AutoFTAccess() { - if (fFace) { - unref_ft_face(fFace); - } - unref_ft_library(); - gFTMutex.release(); - } - - FT_Face face() { return fFace; } - -private: - FT_Face fFace; -}; - /////////////////////////////////////////////////////////////////////////// static bool canEmbed(FT_Face face) { @@ -475,8 +562,6 @@ SkAdvancedTypefaceMetrics* SkTypeface_FreeType::onGetAdvancedTypefaceMetrics( if (!canSubset(face)) { info->fFlags |= SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag; } - info->fLastGlyphID = face->num_glyphs - 1; - info->fEmSize = 1000; const char* fontType = FT_Get_X11_Font_Format(face); if (strcmp(fontType, "Type 1") == 0) { @@ -487,10 +572,6 @@ SkAdvancedTypefaceMetrics* SkTypeface_FreeType::onGetAdvancedTypefaceMetrics( info->fType = SkAdvancedTypefaceMetrics::kCFF_Font; } else if (strcmp(fontType, "TrueType") == 0) { info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; - TT_Header* ttHeader; - if ((ttHeader = (TT_Header*)FT_Get_Sfnt_Table(face, ft_sfnt_head)) != nullptr) { - info->fEmSize = ttHeader->Units_Per_EM; - } } else { info->fType = SkAdvancedTypefaceMetrics::kOther_Font; } @@ -612,13 +693,12 @@ static bool isAxisAligned(const SkScalerContext::Rec& rec) { SkScalerContext* SkTypeface_FreeType::onCreateScalerContext(const SkScalerContextEffects& effects, const SkDescriptor* desc) const { - SkScalerContext_FreeType* c = - new SkScalerContext_FreeType(const_cast(this), effects, desc); + auto c = skstd::make_unique( + sk_ref_sp(const_cast(this)), effects, desc); if (!c->success()) { - delete c; - c = nullptr; + return nullptr; } - return c; + return c.release(); } void SkTypeface_FreeType::onFilterRec(SkScalerContextRec* rec) const { @@ -725,10 +805,10 @@ static FT_Int chooseBitmapStrike(FT_Face face, FT_F26Dot6 scaleY) { return chosenStrikeIndex; } -SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, +SkScalerContext_FreeType::SkScalerContext_FreeType(sk_sp typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc) - : SkScalerContext_FreeType_Base(typeface, effects, desc) + : SkScalerContext_FreeType_Base(std::move(typeface), effects, desc) , fFace(nullptr) , fFTSize(nullptr) , fStrikeIndex(-1) @@ -739,10 +819,10 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, sk_throw(); } + fFaceRec.reset(ref_ft_face(this->getTypeface())); + // load the font file - using UnrefFTFace = SkFunctionWrapper, unref_ft_face>; - std::unique_ptr, UnrefFTFace> ftFace(ref_ft_face(typeface)); - if (nullptr == ftFace) { + if (nullptr == fFaceRec) { SkDEBUGF(("Could not create FT_Face.\n")); return; } @@ -828,11 +908,11 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, } using DoneFTSize = SkFunctionWrapper, FT_Done_Size>; - std::unique_ptr, DoneFTSize> ftSize([&ftFace]() -> FT_Size { + std::unique_ptr, DoneFTSize> ftSize([this]() -> FT_Size { FT_Size size; - FT_Error err = FT_New_Size(ftFace.get(), &size); + FT_Error err = FT_New_Size(fFaceRec->fFace.get(), &size); if (err != 0) { - SkDEBUGF(("FT_New_Size(%s) returned 0x%x.\n", ftFace->family_name, err)); + SkDEBUGF(("FT_New_Size(%s) returned 0x%x.\n", fFaceRec->fFace->family_name, err)); return nullptr; } return size; @@ -844,36 +924,37 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, FT_Error err = FT_Activate_Size(ftSize.get()); if (err != 0) { - SkDEBUGF(("FT_Activate_Size(%s) returned 0x%x.\n", ftFace->family_name, err)); + SkDEBUGF(("FT_Activate_Size(%s) returned 0x%x.\n", fFaceRec->fFace->family_name, err)); return; } - if (FT_IS_SCALABLE(ftFace)) { - err = FT_Set_Char_Size(ftFace.get(), scaleX, scaleY, 72, 72); + if (FT_IS_SCALABLE(fFaceRec->fFace)) { + err = FT_Set_Char_Size(fFaceRec->fFace.get(), scaleX, scaleY, 72, 72); if (err != 0) { SkDEBUGF(("FT_Set_CharSize(%s, %f, %f) returned 0x%x.\n", - ftFace->family_name, fScale.fX, fScale.fY, err)); + fFaceRec->fFace->family_name, fScale.fX, fScale.fY, err)); return; } - } else if (FT_HAS_FIXED_SIZES(ftFace)) { - fStrikeIndex = chooseBitmapStrike(ftFace.get(), scaleY); + } else if (FT_HAS_FIXED_SIZES(fFaceRec->fFace)) { + fStrikeIndex = chooseBitmapStrike(fFaceRec->fFace.get(), scaleY); if (fStrikeIndex == -1) { - SkDEBUGF(("No glyphs for font \"%s\" size %f.\n", ftFace->family_name, fScale.fY)); + SkDEBUGF(("No glyphs for font \"%s\" size %f.\n", + fFaceRec->fFace->family_name, fScale.fY)); return; } - err = FT_Select_Size(ftFace.get(), fStrikeIndex); + err = FT_Select_Size(fFaceRec->fFace.get(), fStrikeIndex); if (err != 0) { SkDEBUGF(("FT_Select_Size(%s, %d) returned 0x%x.\n", - ftFace->family_name, fStrikeIndex, err)); + fFaceRec->fFace->family_name, fStrikeIndex, err)); fStrikeIndex = -1; return; } // A non-ideal size was picked, so recompute the matrix. // This adjusts for the difference between FT_Set_Char_Size and FT_Select_Size. - fMatrix22Scalar.preScale(fScale.x() / ftFace->size->metrics.x_ppem, - fScale.y() / ftFace->size->metrics.y_ppem); + fMatrix22Scalar.preScale(fScale.x() / fFaceRec->fFace->size->metrics.x_ppem, + fScale.y() / fFaceRec->fFace->size->metrics.y_ppem); fMatrix22.xx = SkScalarToFixed(fMatrix22Scalar.getScaleX()); fMatrix22.xy = SkScalarToFixed(-fMatrix22Scalar.getSkewX()); fMatrix22.yx = SkScalarToFixed(-fMatrix22Scalar.getSkewY()); @@ -890,12 +971,12 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, // Force this flag off for bitmap only fonts. fLoadGlyphFlags &= ~FT_LOAD_NO_BITMAP; } else { - SkDEBUGF(("Unknown kind of font \"%s\" size %f.\n", fFace->family_name, fScale.fY)); + SkDEBUGF(("Unknown kind of font \"%s\" size %f.\n", fFaceRec->fFace->family_name, fScale.fY)); return; } fFTSize = ftSize.release(); - fFace = ftFace.release(); + fFace = fFaceRec->fFace.get(); fDoLinearMetrics = linearMetrics; } @@ -906,9 +987,7 @@ SkScalerContext_FreeType::~SkScalerContext_FreeType() { FT_Done_Size(fFTSize); } - if (fFace != nullptr) { - unref_ft_face(fFace); - } + fFaceRec = nullptr; unref_ft_library(); } @@ -1081,7 +1160,8 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { return; } - err = FT_Load_Glyph( fFace, glyph->getGlyphID(), fLoadGlyphFlags ); + err = FT_Load_Glyph( fFace, glyph->getGlyphID(), + fLoadGlyphFlags | FT_LOAD_BITMAP_METRICS_ONLY ); if (err != 0) { glyph->zeroMetrics(); return; @@ -1209,7 +1289,7 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) { } -void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, SkPath* path) { +void SkScalerContext_FreeType::generatePath(SkGlyphID glyphID, SkPath* path) { SkAutoMutexAcquire ac(gFTMutex); SkASSERT(path); @@ -1223,11 +1303,11 @@ void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, SkPath* path) flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline) - FT_Error err = FT_Load_Glyph( fFace, glyph.getGlyphID(), flags); + FT_Error err = FT_Load_Glyph(fFace, glyphID, flags); if (err != 0) { SkDEBUGF(("SkScalerContext_FreeType::generatePath: FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n", - glyph.getGlyphID(), flags, err)); + glyphID, flags, err)); path->reset(); return; } @@ -1308,7 +1388,7 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* metrics underlinePosition = -SkIntToScalar(face->underline_position + face->underline_thickness / 2) / upem; - metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; + metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag; metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; // we may be able to synthesize x_height and cap_height from outline @@ -1337,7 +1417,7 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* metrics underlineThickness = 0; underlinePosition = 0; - metrics->fFlags &= ~SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; + metrics->fFlags &= ~SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag; metrics->fFlags &= ~SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; } else { sk_bzero(metrics, sizeof(*metrics)); @@ -1491,6 +1571,51 @@ SkTypeface::LocalizedStrings* SkTypeface_FreeType::onCreateFamilyNameIterator() return nameIter; } +int SkTypeface_FreeType::onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const +{ + AutoFTAccess fta(this); + FT_Face face = fta.face(); + + if (!face || !(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) { + return 0; + } + + FT_MM_Var* variations = nullptr; + if (FT_Get_MM_Var(face, &variations)) { + return 0; + } + SkAutoFree autoFreeVariations(variations); + + if (!coordinates || coordinateCount < SkToInt(variations->num_axis)) { + return variations->num_axis; + } + + SkAutoSTMalloc<4, FT_Fixed> coords(variations->num_axis); + // FT_Get_{MM,Var}_{Blend,Design}_Coordinates were added in FreeType 2.7.1. + if (gFTLibrary->fGetVarDesignCoordinates && + !gFTLibrary->fGetVarDesignCoordinates(face, variations->num_axis, coords.get())) + { + for (FT_UInt i = 0; i < variations->num_axis; ++i) { + coordinates[i].axis = variations->axis[i].tag; + coordinates[i].value = SkFixedToScalar(coords[i]); + } + } else if (static_cast(fta.getAxesCount()) == variations->num_axis) { + for (FT_UInt i = 0; i < variations->num_axis; ++i) { + coordinates[i].axis = variations->axis[i].tag; + coordinates[i].value = SkFixedToScalar(fta.getAxes()[i]); + } + } else if (fta.isNamedVariationSpecified()) { + // The font has axes, they cannot be retrieved, and some named axis was specified. + return -1; + } else { + // The font has axes, they cannot be retrieved, but no named instance was specified. + return 0; + } + + return variations->num_axis; +} + int SkTypeface_FreeType::onGetTableTags(SkFontTableTag tags[]) const { AutoFTAccess fta(this); FT_Face face = fta.face(); @@ -1721,7 +1846,7 @@ bool SkTypeface_FreeType::Scanner::scanFont( /*static*/ void SkTypeface_FreeType::Scanner::computeAxisValues( AxisDefinitions axisDefinitions, - const SkFontMgr::FontParameters::Axis* requestedAxes, int requestedAxisCount, + const SkFontArguments::VariationPosition position, SkFixed* axisValues, const SkString& name) { @@ -1730,11 +1855,13 @@ bool SkTypeface_FreeType::Scanner::scanFont( const SkScalar axisMin = SkFixedToScalar(axisDefinition.fMinimum); const SkScalar axisMax = SkFixedToScalar(axisDefinition.fMaximum); axisValues[i] = axisDefinition.fDefault; - for (int j = 0; j < requestedAxisCount; ++j) { - const SkFontMgr::FontParameters::Axis& axisSpecified = requestedAxes[j]; - if (axisDefinition.fTag == axisSpecified.fTag) { - const SkScalar axisValue = SkTPin(axisSpecified.fStyleValue, axisMin, axisMax); - if (axisSpecified.fStyleValue != axisValue) { + // The position may be over specified. If there are multiple values for a given axis, + // use the last one since that's what css-fonts-4 requires. + for (int j = position.coordinateCount; j --> 0;) { + const auto& coordinate = position.coordinates[j]; + if (axisDefinition.fTag == coordinate.axis) { + const SkScalar axisValue = SkTPin(coordinate.value, axisMin, axisMax); + if (coordinate.value != axisValue) { SkDEBUGF(("Requested font axis value out of range: " "%s '%c%c%c%c' %f; pinned to %f.\n", name.c_str(), @@ -1742,7 +1869,7 @@ bool SkTypeface_FreeType::Scanner::scanFont( (axisDefinition.fTag >> 16) & 0xFF, (axisDefinition.fTag >> 8) & 0xFF, (axisDefinition.fTag ) & 0xFF, - SkScalarToDouble(axisSpecified.fStyleValue), + SkScalarToDouble(coordinate.value), SkScalarToDouble(axisValue))); } axisValues[i] = SkScalarToFixed(axisValue); @@ -1754,8 +1881,8 @@ bool SkTypeface_FreeType::Scanner::scanFont( SkDEBUGCODE( // Check for axis specified, but not matched in font. - for (int i = 0; i < requestedAxisCount; ++i) { - SkFourByteTag skTag = requestedAxes[i].fTag; + for (int i = 0; i < position.coordinateCount; ++i) { + SkFourByteTag skTag = position.coordinates[i].axis; bool found = false; for (int j = 0; j < axisDefinitions.count(); ++j) { if (skTag == axisDefinitions[j].fTag) { diff --git a/gfx/skia/skia/src/ports/SkFontHost_FreeType_common.cpp b/gfx/skia/skia/src/ports/SkFontHost_FreeType_common.cpp index 26e02fd1b9a4..9df7268bb4e0 100644 --- a/gfx/skia/skia/src/ports/SkFontHost_FreeType_common.cpp +++ b/gfx/skia/skia/src/ports/SkFontHost_FreeType_common.cpp @@ -32,7 +32,9 @@ //#define SK_SHOW_TEXT_BLIT_COVERAGE -static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) { +namespace { + +FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) { switch (format) { case SkMask::kBW_Format: return FT_PIXEL_MODE_MONO; @@ -44,7 +46,7 @@ static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) { /////////////////////////////////////////////////////////////////////////////// -static uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) { +uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) { #ifdef SK_SHOW_TEXT_BLIT_COVERAGE r = SkTMax(r, (U8CPU)0x40); g = SkTMax(g, (U8CPU)0x40); @@ -53,14 +55,14 @@ static uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) { return SkPack888ToRGB16(r, g, b); } -static uint16_t grayToRGB16(U8CPU gray) { +uint16_t grayToRGB16(U8CPU gray) { #ifdef SK_SHOW_TEXT_BLIT_COVERAGE gray = SkTMax(gray, (U8CPU)0x40); #endif return SkPack888ToRGB16(gray, gray, gray); } -static int bittst(const uint8_t data[], int bitOffset) { +int bittst(const uint8_t data[], int bitOffset) { SkASSERT(bitOffset >= 0); int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7); return lowBit & 1; @@ -75,8 +77,8 @@ static int bittst(const uint8_t data[], int bitOffset) { * FT_PIXEL_MODE_LCD_V */ template -static void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR, - const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) +void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR, + const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { SkASSERT(SkMask::kLCD16_Format == mask.fFormat); if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) { @@ -176,7 +178,7 @@ static void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsB * * TODO: All of these N need to be Y or otherwise ruled out. */ -static void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) { +void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) { SkASSERTF(dstMask.fBounds.width() == static_cast(srcFTBitmap.width), "dstMask.fBounds.width() = %d\n" "static_cast(srcFTBitmap.width) = %d", @@ -259,13 +261,13 @@ static void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) { } } -static inline int convert_8_to_1(unsigned byte) { +inline int convert_8_to_1(unsigned byte) { SkASSERT(byte <= 0xFF); // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better. return (byte >> 6) != 0; } -static uint8_t pack_8_to_1(const uint8_t alpha[8]) { +uint8_t pack_8_to_1(const uint8_t alpha[8]) { unsigned bits = 0; for (int i = 0; i < 8; ++i) { bits <<= 1; @@ -274,7 +276,7 @@ static uint8_t pack_8_to_1(const uint8_t alpha[8]) { return SkToU8(bits); } -static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) { +void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) { const int height = mask.fBounds.height(); const int width = mask.fBounds.width(); const int octs = width >> 3; @@ -344,6 +346,44 @@ inline SkColorType SkColorType_for_SkMaskFormat(SkMask::Format format) { } } +#ifdef SK_DEBUG + +# define SK_STRING(X) SK_STRING_IMPL(X) +# define SK_STRING_IMPL(X) #X + +# undef __FTERRORS_H__ +# define FT_ERROR_START_LIST +# define FT_ERRORDEF(e, v, s) { SK_STRING(e), s }, +# define FT_ERROR_END_LIST + +const struct { + const char* err_code; + const char* err_msg; +} sk_ft_errors[] = { +# include FT_ERRORS_H +}; + +void SkTraceFTR(const char* file, unsigned long line, FT_Error err, const char* msg) { + SkString s; + s.printf("%s:%lu:1: error: 0x%x ", file, line, err); + if (0 <= err && (unsigned)err < SK_ARRAY_COUNT(sk_ft_errors)) { + s.appendf("%s '%s' ", sk_ft_errors[err].err_code, sk_ft_errors[err].err_msg); + } else { + s.appendf(" "); + } + if (msg) { + s.appendf("%s", msg); + } + SkDebugf("%s\n", s.c_str()); +} + +# define SK_TRACEFTR(_err, _msg) SkTraceFTR(__FILE__, __LINE__, _err, _msg) +#else +# define SK_TRACEFTR(_err, _msg) sk_ignore_unused_variable(_err) +#endif + +} // namespace + void SkScalerContext_FreeType_Base::generateGlyphImage( FT_Face face, const SkGlyph& glyph, @@ -378,7 +418,13 @@ void SkScalerContext_FreeType_Base::generateGlyphImage( dy - ((bbox.yMin + dy) & ~63)); if (SkMask::kLCD16_Format == glyph.fMaskFormat) { - FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD); + FT_Error err = FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : + FT_RENDER_MODE_LCD); + if (err) { + SK_TRACEFTR(err, "Could not render glyph."); + sk_bzero(glyph.fImage, glyph.computeImageSize()); + return; + } SkMask mask; glyph.toMask(&mask); if (fPreBlend.isApplicable()) { @@ -522,20 +568,22 @@ void SkScalerContext_FreeType_Base::generateGlyphImage( /////////////////////////////////////////////////////////////////////////////// -static int move_proc(const FT_Vector* pt, void* ctx) { +namespace { + +int move_proc(const FT_Vector* pt, void* ctx) { SkPath* path = (SkPath*)ctx; path->close(); // to close the previous contour (if any) path->moveTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y)); return 0; } -static int line_proc(const FT_Vector* pt, void* ctx) { +int line_proc(const FT_Vector* pt, void* ctx) { SkPath* path = (SkPath*)ctx; path->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y)); return 0; } -static int quad_proc(const FT_Vector* pt0, const FT_Vector* pt1, +int quad_proc(const FT_Vector* pt0, const FT_Vector* pt1, void* ctx) { SkPath* path = (SkPath*)ctx; path->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y), @@ -543,7 +591,7 @@ static int quad_proc(const FT_Vector* pt0, const FT_Vector* pt1, return 0; } -static int cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1, +int cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* pt2, void* ctx) { SkPath* path = (SkPath*)ctx; path->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y), @@ -552,9 +600,9 @@ static int cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1, return 0; } -void SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, - SkPath* path) -{ +} // namespace + +void SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, SkPath* path) { FT_Outline_Funcs funcs; funcs.move_to = move_proc; diff --git a/gfx/skia/skia/src/ports/SkFontHost_FreeType_common.h b/gfx/skia/skia/src/ports/SkFontHost_FreeType_common.h index 21e774866282..b9e8b13d7f6e 100644 --- a/gfx/skia/skia/src/ports/SkFontHost_FreeType_common.h +++ b/gfx/skia/skia/src/ports/SkFontHost_FreeType_common.h @@ -17,8 +17,11 @@ #include "SkFontMgr.h" -#include -#include FT_FREETYPE_H +// These are forward declared to avoid pimpl but also hide the FreeType implementation. +typedef struct FT_LibraryRec_* FT_Library; +typedef struct FT_FaceRec_* FT_Face; +typedef struct FT_StreamRec_* FT_Stream; +typedef signed long FT_Pos; class SkScalerContext_FreeType_Base : public SkScalerContext { protected: @@ -26,9 +29,9 @@ protected: // This value was chosen by eyeballing the result in Firefox and trying to match it. static const FT_Pos kBitmapEmboldenStrength = 1 << 6; - SkScalerContext_FreeType_Base(SkTypeface* typeface, const SkScalerContextEffects& effects, + SkScalerContext_FreeType_Base(sk_sp typeface, const SkScalerContextEffects& effects, const SkDescriptor *desc) - : INHERITED(typeface, effects, desc) + : INHERITED(std::move(typeface), effects, desc) {} void generateGlyphImage(FT_Face face, const SkGlyph& glyph, const SkMatrix& bitmapTransform); @@ -59,7 +62,7 @@ public: AxisDefinitions* axes) const; static void computeAxisValues( AxisDefinitions axisDefinitions, - const SkFontMgr::FontParameters::Axis* requestedAxis, int requestedAxisCount, + const SkFontArguments::VariationPosition position, SkFixed* axisValues, const SkString& name); @@ -80,17 +83,19 @@ protected: SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( PerGlyphInfo, const uint32_t*, uint32_t) const override; int onGetUPEM() const override; - virtual bool onGetKerningPairAdjustments(const uint16_t glyphs[], int count, - int32_t adjustments[]) const override; - virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[], - int glyphCount) const override; + bool onGetKerningPairAdjustments(const uint16_t glyphs[], int count, + int32_t adjustments[]) const override; + int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[], + int glyphCount) const override; int onCountGlyphs() const override; LocalizedStrings* onCreateFamilyNameIterator() const override; + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override; int onGetTableTags(SkFontTableTag tags[]) const override; - virtual size_t onGetTableData(SkFontTableTag, size_t offset, - size_t length, void* data) const override; + size_t onGetTableData(SkFontTableTag, size_t offset, + size_t length, void* data) const override; private: typedef SkTypeface INHERITED; diff --git a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp index cf56299a1112..53efa544ef89 100644 --- a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp +++ b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp @@ -86,19 +86,9 @@ void SkInitCairoFT(bool fontHintingEnabled) typedef struct _FcPattern FcPattern; #endif -template<> struct SkTUnref { - void operator()(FcPattern* pattern) { -#ifdef CAIRO_HAS_FC_FONT - if (pattern) { - FcPatternDestroy(pattern); - } -#endif - } -}; - class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base { public: - SkScalerContext_CairoFT(SkTypeface* typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc, + SkScalerContext_CairoFT(sk_sp typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc, cairo_font_face_t* fontFace, FcPattern* pattern); virtual ~SkScalerContext_CairoFT(); @@ -112,7 +102,7 @@ protected: virtual void generateAdvance(SkGlyph* glyph) override; virtual void generateMetrics(SkGlyph* glyph) override; virtual void generateImage(const SkGlyph& glyph) override; - virtual void generatePath(const SkGlyph& glyph, SkPath* path) override; + virtual void generatePath(const SkGlyphID glyphID, SkPath* path) override; virtual void generateFontMetrics(SkPaint::FontMetrics* metrics) override; virtual SkUnichar generateGlyphToChar(uint16_t glyph) override; @@ -123,7 +113,6 @@ private: #ifdef CAIRO_HAS_FC_FONT void parsePattern(FcPattern* pattern); - void resolvePattern(FcPattern* pattern); #endif cairo_scaled_font_t* fScaledFont; @@ -205,8 +194,8 @@ public: virtual SkScalerContext* onCreateScalerContext(const SkScalerContextEffects& effects, const SkDescriptor* desc) const override { SkScalerContext_CairoFT* ctx = - new SkScalerContext_CairoFT(const_cast(this), effects, desc, - fFontFace, fPattern); + new SkScalerContext_CairoFT(sk_ref_sp(const_cast(this)), + effects, desc, fFontFace, fPattern); if (!ctx->isValid()) { delete ctx; return nullptr; @@ -230,6 +219,13 @@ public: rec->ignorePreBlend(); } + virtual int onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override + { + return -1; + } + virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const override { SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetFontDescriptor unimplemented\n")); @@ -291,10 +287,15 @@ private: { cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, nullptr, nullptr); cairo_font_face_destroy(fFontFace); +#ifdef CAIRO_HAS_FC_FONT + if (fPattern) { + FcPatternDestroy(fPattern); + } +#endif } cairo_font_face_t* fFontFace; - SkAutoTUnref fPattern; + FcPattern* fPattern; }; SkTypeface* SkCreateTypefaceFromCairoFTFontWithFontconfig(cairo_scaled_font_t* scaledFont, FcPattern* pattern) @@ -321,9 +322,9 @@ SkTypeface* SkCreateTypefaceFromCairoFTFont(cairo_scaled_font_t* scaledFont) return SkCreateTypefaceFromCairoFTFontWithFontconfig(scaledFont, nullptr); } -SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc, +SkScalerContext_CairoFT::SkScalerContext_CairoFT(sk_sp typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc, cairo_font_face_t* fontFace, FcPattern* pattern) - : SkScalerContext_FreeType_Base(typeface, effects, desc) + : SkScalerContext_FreeType_Base(std::move(typeface), effects, desc) , fLcdFilter(FT_LCD_FILTER_NONE) { SkMatrix matrix; @@ -342,7 +343,9 @@ SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkS fRec.fFlags |= SkScalerContext::kEmbeddedBitmapText_Flag; #ifdef CAIRO_HAS_FC_FONT - resolvePattern(pattern); + if (pattern) { + parsePattern(pattern); + } #endif FT_Int32 loadFlags = FT_LOAD_DEFAULT; @@ -513,29 +516,6 @@ void SkScalerContext_CairoFT::parsePattern(FcPattern* pattern) } } } - -void SkScalerContext_CairoFT::resolvePattern(FcPattern* pattern) -{ - if (!pattern) { - return; - } - FcValue value; - if (FcPatternGet(pattern, FC_PIXEL_SIZE, 0, &value) == FcResultNoMatch) { - SkAutoTUnref scalePattern(FcPatternDuplicate(pattern)); - if (scalePattern && - FcPatternAddDouble(scalePattern, FC_PIXEL_SIZE, fScaleY) && - FcConfigSubstitute(nullptr, scalePattern, FcMatchPattern)) { - FcDefaultSubstitute(scalePattern); - FcResult result; - SkAutoTUnref resolved(FcFontMatch(nullptr, scalePattern, &result)); - if (resolved) { - parsePattern(resolved); - return; - } - } - } - parsePattern(pattern); -} #endif bool SkScalerContext_CairoFT::computeShapeMatrix(const SkMatrix& m) @@ -781,7 +761,7 @@ void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph) } } -void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path) +void SkScalerContext_CairoFT::generatePath(const SkGlyphID glyphID, SkPath* path) { SkASSERT(fScaledFont != nullptr); CairoLockedFTFace faceLock(fScaledFont); @@ -793,7 +773,7 @@ void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path) flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline) - FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), flags); + FT_Error err = FT_Load_Glyph(face, glyphID, flags); if (err != 0) { path->reset(); @@ -834,7 +814,7 @@ SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph) #include "SkFontMgr.h" -SkFontMgr* SkFontMgr::Factory() { +sk_sp SkFontMgr::Factory() { // todo return nullptr; } diff --git a/gfx/skia/skia/src/ports/SkFontHost_mac.cpp b/gfx/skia/skia/src/ports/SkFontHost_mac.cpp index 34be57a79a04..9ecc4011033a 100644 --- a/gfx/skia/skia/src/ports/SkFontHost_mac.cpp +++ b/gfx/skia/skia/src/ports/SkFontHost_mac.cpp @@ -20,6 +20,7 @@ #endif #include "SkAdvancedTypefaceMetrics.h" +#include "SkAutoMalloc.h" #include "SkCGUtils.h" #include "SkColorPriv.h" #include "SkDescriptor.h" @@ -32,10 +33,7 @@ #include "SkMaskGamma.h" #include "SkMathPriv.h" #include "SkMutex.h" -#include "SkOTTable_glyf.h" -#include "SkOTTable_head.h" -#include "SkOTTable_hhea.h" -#include "SkOTTable_loca.h" +#include "SkOTTable_OS_2.h" #include "SkOTUtils.h" #include "SkOnce.h" #include "SkPaint.h" @@ -47,10 +45,14 @@ #include "SkTypefaceCache.h" #include "SkTypeface_mac.h" #include "SkUtils.h" -#include "SkUtils.h" #include +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 +#define kCTFontOrientationHorizontal kCTFontHorizontalOrientation +#define kCTFontOrientationVertical kCTFontVerticalOrientation +#endif + // Experimental code to use a global lock whenever we access CG, to see if this reduces // crashes in Chrome #define USE_GLOBAL_MUTEX_FOR_CG_ACCESS @@ -67,80 +69,20 @@ class SkScalerContext_Mac; -// CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we -// provide a wrapper here that will return an empty array if need be. -static CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() { -#ifdef SK_BUILD_FOR_IOS - return CFArrayCreate(nullptr, nullptr, 0, nullptr); -#else - return CTFontManagerCopyAvailableFontFamilyNames(); -#endif -} - - -// Being templated and taking const T* prevents calling -// CFSafeRelease(autoCFRelease) through implicit conversion. -template static void CFSafeRelease(/*CFTypeRef*/const T* cfTypeRef) { - if (cfTypeRef) { - CFRelease(cfTypeRef); +struct CFSafeRelease { + void operator()(CFTypeRef cfTypeRef) { + if (cfTypeRef) { + CFRelease(cfTypeRef); + } } -} - -// Being templated and taking const T* prevents calling -// CFSafeRetain(autoCFRelease) through implicit conversion. -template static void CFSafeRetain(/*CFTypeRef*/const T* cfTypeRef) { - if (cfTypeRef) { - CFRetain(cfTypeRef); - } -} - -/** Acts like a CFRef, but calls CFSafeRelease when it goes out of scope. */ -template class AutoCFRelease : private SkNoncopyable { -public: - explicit AutoCFRelease(CFRef cfRef = nullptr) : fCFRef(cfRef) { } - ~AutoCFRelease() { CFSafeRelease(fCFRef); } - - void reset(CFRef that = nullptr) { - if (that != fCFRef) { - CFSafeRelease(fCFRef); - fCFRef = that; - } - } - - CFRef release() { - CFRef self = fCFRef; - fCFRef = nullptr; - return self; - } - - operator CFRef() const { return fCFRef; } - CFRef get() const { return fCFRef; } - - CFRef* operator&() { SkASSERT(fCFRef == nullptr); return &fCFRef; } -private: - CFRef fCFRef; }; +template using UniqueCFRef = + std::unique_ptr, CFSafeRelease>; -static CFStringRef make_CFString(const char str[]) { - return CFStringCreateWithCString(nullptr, str, kCFStringEncodingUTF8); +static UniqueCFRef make_CFString(const char str[]) { + return UniqueCFRef(CFStringCreateWithCString(nullptr, str, kCFStringEncodingUTF8)); } -template class AutoCGTable : SkNoncopyable { -public: - AutoCGTable(CGFontRef font) - //Undocumented: the tag parameter in this call is expected in machine order and not BE order. - : fCFData(CGFontCopyTableForTag(font, SkSetFourByteTag(T::TAG0, T::TAG1, T::TAG2, T::TAG3))) - , fData(fCFData ? reinterpret_cast(CFDataGetBytePtr(fCFData)) : nullptr) - { } - - const T* operator->() const { return fData; } - -private: - AutoCFRelease fCFData; -public: - const T* fData; -}; - // inline versions of these rect helpers static bool CGRectIsEmpty_inline(const CGRect& rect) { @@ -213,60 +155,12 @@ static void sk_memset_rect32(uint32_t* ptr, uint32_t value, } } -#include - typedef uint32_t CGRGBPixel; static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) { return pixel & 0xFF; } -static const char FONT_DEFAULT_NAME[] = "Lucida Sans"; - -// See Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal for original source. -static int readVersion() { - struct utsname info; - if (uname(&info) != 0) { - SkDebugf("uname failed\n"); - return 0; - } - if (strcmp(info.sysname, "Darwin") != 0) { - SkDebugf("unexpected uname sysname %s\n", info.sysname); - return 0; - } - char* dot = strchr(info.release, '.'); - if (!dot) { - SkDebugf("expected dot in uname release %s\n", info.release); - return 0; - } - int version = atoi(info.release); - if (version == 0) { - SkDebugf("could not parse uname release %s\n", info.release); - } - return version; -} - -static int darwinVersion() { - static int darwin_version = readVersion(); - return darwin_version; -} - -static bool isSnowLeopard() { - return darwinVersion() == 10; -} - -static bool isLion() { - return darwinVersion() == 11; -} - -static bool isMountainLion() { - return darwinVersion() == 12; -} - -static bool isLCDFormat(unsigned format) { - return SkMask::kLCD16_Format == format; -} - static CGFloat ScalarToCG(SkScalar scalar) { if (sizeof(CGFloat) == sizeof(float)) { return SkScalarToFloat(scalar); @@ -294,15 +188,13 @@ static float CGToFloat(CGFloat cgFloat) { } } -static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix, - SkScalar sx = SK_Scalar1, - SkScalar sy = SK_Scalar1) { - return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx), - -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy), - -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx), - ScalarToCG(matrix[SkMatrix::kMScaleY] * sy), - ScalarToCG(matrix[SkMatrix::kMTransX] * sx), - ScalarToCG(matrix[SkMatrix::kMTransY] * sy)); +static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix) { + return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX]), + -ScalarToCG(matrix[SkMatrix::kMSkewY] ), + -ScalarToCG(matrix[SkMatrix::kMSkewX] ), + ScalarToCG(matrix[SkMatrix::kMScaleY]), + ScalarToCG(matrix[SkMatrix::kMTransX]), + ScalarToCG(matrix[SkMatrix::kMTransY])); } /////////////////////////////////////////////////////////////////////////////// @@ -320,19 +212,19 @@ static bool supports_LCD() { return (bool) gSupportsLCD; } uint32_t rgb = 0; - AutoCFRelease colorspace(CGColorSpaceCreateDeviceRGB()); - AutoCFRelease cgContext(CGBitmapContextCreate(&rgb, 1, 1, 8, 4, - colorspace, BITMAP_INFO_RGB)); - AutoCFRelease ctFont(CTFontCreateWithName(CFSTR("Helvetica"), 16, nullptr)); - CGContextSetShouldSmoothFonts(cgContext, true); - CGContextSetShouldAntialias(cgContext, true); - CGContextSetTextDrawingMode(cgContext, kCGTextFill); - CGContextSetGrayFillColor(cgContext, 1, 1); + UniqueCFRef colorspace(CGColorSpaceCreateDeviceRGB()); + UniqueCFRef cgContext( + CGBitmapContextCreate(&rgb, 1, 1, 8, 4, colorspace.get(), BITMAP_INFO_RGB)); + UniqueCFRef ctFont(CTFontCreateWithName(CFSTR("Helvetica"), 16, nullptr)); + CGContextSetShouldSmoothFonts(cgContext.get(), true); + CGContextSetShouldAntialias(cgContext.get(), true); + CGContextSetTextDrawingMode(cgContext.get(), kCGTextFill); + CGContextSetGrayFillColor(cgContext.get(), 1, 1); CGPoint point = CGPointMake(-1, 0); static const UniChar pipeChar = '|'; CGGlyph pipeGlyph; - CTFontGetGlyphsForCharacters(ctFont, &pipeChar, &pipeGlyph, 1); - CTFontDrawGlyphs(ctFont, &pipeGlyph, &point, 1, cgContext); + CTFontGetGlyphsForCharacters(ctFont.get(), &pipeChar, &pipeGlyph, 1); + CTFontDrawGlyphs(ctFont.get(), &pipeGlyph, &point, 1, cgContext.get()); uint32_t r = (rgb >> 16) & 0xFF; uint32_t g = (rgb >> 8) & 0xFF; @@ -353,18 +245,17 @@ public: } CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, - CGGlyph glyphID, size_t* rowBytesPtr, - bool generateA8FromLCD); + CGGlyph glyphID, size_t* rowBytesPtr, bool generateA8FromLCD); private: enum { kSize = 32 * 32 * sizeof(CGRGBPixel) }; SkAutoSMalloc fImageStorage; - AutoCFRelease fRGBSpace; + UniqueCFRef fRGBSpace; // cached state - AutoCFRelease fCG; + UniqueCFRef fCG; SkISize fSize; bool fDoAA; bool fDoLCD; @@ -379,8 +270,8 @@ private: static bool find_dict_CGFloat(CFDictionaryRef dict, CFStringRef name, CGFloat* value) { CFNumberRef num; return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num) - && CFNumberIsFloatType(num) - && CFNumberGetValue(num, kCFNumberCGFloatType, value); + && CFNumberIsFloatType(num) + && CFNumberGetValue(num, kCFNumberCGFloatType, value); } template struct LinearInterpolater { @@ -397,7 +288,7 @@ template struct LinearInterpolater { return C()(dst_min + (((value - src_min) * (dst_max - dst_min)) / (src_max - src_min))); } - int map(S val) const { + D map(S val) const { // -Inf to [0] if (val < fMapping[0].src_val) { return fMapping[0].dst_val; @@ -423,16 +314,103 @@ template struct LinearInterpolater { struct RoundCGFloatToInt { int operator()(CGFloat s) { return s + 0.5; } }; +struct CGFloatIdentity { + CGFloat operator()(CGFloat s) { return s; } +}; -static int ct_weight_to_fontstyle(CGFloat cgWeight) { - using Interpolator = LinearInterpolater; +/** Returns the [-1, 1] CTFontDescriptor weights for the + * <0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000> CSS weights. + * + * It is assumed that the values will be interpolated linearly between these points. + * NSFontWeightXXX were added in 10.11, appear in 10.10, but do not appear in 10.9. + * The actual values appear to be stable, but they may change in the future without notice. + */ +static CGFloat(&get_NSFontWeight_mapping())[11] { - // Values determined by creating font data with every weight, creating a CTFont, - // and asking the CTFont for its weight. See TypefaceStyle test for basics. + // Declarations in on macOS, on iOS +#ifdef SK_BUILD_FOR_MAC +# define SK_KIT_FONT_WEIGHT_PREFIX "NS" +#endif +#ifdef SK_BUILD_FOR_IOS +# define SK_KIT_FONT_WEIGHT_PREFIX "UI" +#endif + static constexpr struct { + CGFloat defaultValue; + const char* name; + } nsFontWeightLoaderInfos[] = { + { -0.80f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightUltraLight" }, + { -0.60f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightThin" }, + { -0.40f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightLight" }, + { 0.00f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightRegular" }, + { 0.23f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightMedium" }, + { 0.30f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightSemibold" }, + { 0.40f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightBold" }, + { 0.56f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightHeavy" }, + { 0.62f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightBlack" }, + }; + + static_assert(SK_ARRAY_COUNT(nsFontWeightLoaderInfos) == 9, ""); + static CGFloat nsFontWeights[11]; + static SkOnce once; + once([&] { + size_t i = 0; + nsFontWeights[i++] = -1.00; + for (const auto& nsFontWeightLoaderInfo : nsFontWeightLoaderInfos) { + void* nsFontWeightValuePtr = dlsym(RTLD_DEFAULT, nsFontWeightLoaderInfo.name); + if (nsFontWeightValuePtr) { + nsFontWeights[i++] = *(static_cast(nsFontWeightValuePtr)); + } else { + nsFontWeights[i++] = nsFontWeightLoaderInfo.defaultValue; + } + } + nsFontWeights[i++] = 1.00; + }); + return nsFontWeights; +} + +/** Convert the [0, 1000] CSS weight to [-1, 1] CTFontDescriptor weight (for system fonts). + * + * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the + * CTFont is native or created from a CGDataProvider. + */ +static CGFloat fontstyle_to_ct_weight(int fontstyleWeight) { + using Interpolator = LinearInterpolater; // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100. - // However, on this end we can't tell. - static constexpr Interpolator::Mapping weightMappings[] = { + // However, on this end we can't tell, so this is ignored. + + static Interpolator::Mapping nativeWeightMappings[11]; + static SkOnce once; + once([&] { + CGFloat(&nsFontWeights)[11] = get_NSFontWeight_mapping(); + for (int i = 0; i < 11; ++i) { + nativeWeightMappings[i].src_val = i * 100; + nativeWeightMappings[i].dst_val = nsFontWeights[i]; + } + }); + static constexpr Interpolator nativeInterpolator( + nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings)); + + return nativeInterpolator.map(fontstyleWeight); +} + + +/** Convert the [-1, 1] CTFontDescriptor weight to [0, 1000] CSS weight. + * + * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the + * CTFont is native or created from a CGDataProvider. + */ +static int ct_weight_to_fontstyle(CGFloat cgWeight, bool fromDataProvider) { + using Interpolator = LinearInterpolater; + + // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100. + // However, on this end we can't tell, so this is ignored. + + /** This mapping for CGDataProvider created fonts is determined by creating font data with every + * weight, creating a CTFont, and asking the CTFont for its weight. See the TypefaceStyle test + * in tests/TypefaceTest.cpp for the code used to determine these values. + */ + static constexpr Interpolator::Mapping dataProviderWeightMappings[] = { { -1.00, 0 }, { -0.70, 100 }, { -0.50, 200 }, @@ -445,10 +423,40 @@ static int ct_weight_to_fontstyle(CGFloat cgWeight) { { 0.80, 900 }, { 1.00, 1000 }, }; - static constexpr Interpolator interpolater(weightMappings, SK_ARRAY_COUNT(weightMappings)); - return interpolater.map(cgWeight); + static constexpr Interpolator dataProviderInterpolator( + dataProviderWeightMappings, SK_ARRAY_COUNT(dataProviderWeightMappings)); + + static Interpolator::Mapping nativeWeightMappings[11]; + static SkOnce once; + once([&] { + CGFloat(&nsFontWeights)[11] = get_NSFontWeight_mapping(); + for (int i = 0; i < 11; ++i) { + nativeWeightMappings[i].src_val = nsFontWeights[i]; + nativeWeightMappings[i].dst_val = i * 100; + } + }); + static constexpr Interpolator nativeInterpolator( + nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings)); + + return fromDataProvider ? dataProviderInterpolator.map(cgWeight) + : nativeInterpolator.map(cgWeight); } +/** Convert the [0, 10] CSS weight to [-1, 1] CTFontDescriptor width. */ +static int fontstyle_to_ct_width(int fontstyleWidth) { + using Interpolator = LinearInterpolater; + + // Values determined by creating font data with every width, creating a CTFont, + // and asking the CTFont for its width. See TypefaceStyle test for basics. + static constexpr Interpolator::Mapping widthMappings[] = { + { 0, -0.5 }, + { 10, 0.5 }, + }; + static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings)); + return interpolator.map(fontstyleWidth); +} + +/** Convert the [-1, 1] CTFontDescriptor width to [0, 10] CSS weight. */ static int ct_width_to_fontstyle(CGFloat cgWidth) { using Interpolator = LinearInterpolater; @@ -458,60 +466,51 @@ static int ct_width_to_fontstyle(CGFloat cgWidth) { { -0.5, 0 }, { 0.5, 10 }, }; - static constexpr Interpolator interpolater(widthMappings, SK_ARRAY_COUNT(widthMappings)); - return interpolater.map(cgWidth); + static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings)); + return interpolator.map(cgWidth); } -static SkFontStyle fontstyle_from_descriptor(CTFontDescriptorRef desc) { - AutoCFRelease dict( - (CFDictionaryRef)CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute)); - if (nullptr == dict.get()) { +static SkFontStyle fontstyle_from_descriptor(CTFontDescriptorRef desc, bool fromDataProvider) { + UniqueCFRef fontTraits(CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute)); + if (!fontTraits || CFDictionaryGetTypeID() != CFGetTypeID(fontTraits.get())) { return SkFontStyle(); } + UniqueCFRef fontTraitsDict(static_cast(fontTraits.release())); CGFloat weight, width, slant; - if (!find_dict_CGFloat(dict, kCTFontWeightTrait, &weight)) { + if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWeightTrait, &weight)) { weight = 0; } - if (!find_dict_CGFloat(dict, kCTFontWidthTrait, &width)) { + if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWidthTrait, &width)) { width = 0; } - if (!find_dict_CGFloat(dict, kCTFontSlantTrait, &slant)) { + if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontSlantTrait, &slant)) { slant = 0; } - return SkFontStyle(ct_weight_to_fontstyle(weight), + return SkFontStyle(ct_weight_to_fontstyle(weight, fromDataProvider), ct_width_to_fontstyle(width), slant ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant); } -#define WEIGHT_THRESHOLD ((SkFontStyle::kNormal_Weight + SkFontStyle::kBold_Weight)/2) - -// kCTFontColorGlyphsTrait was added in the Mac 10.7 and iPhone 4.3 SDKs. -// Being an enum value it is not guarded by version macros, but old SDKs must still be supported. -#if defined(__MAC_10_7) || defined(__IPHONE_4_3) -static const uint32_t SkCTFontColorGlyphsTrait = kCTFontColorGlyphsTrait; -#else -static const uint32_t SkCTFontColorGlyphsTrait = (1 << 13); -#endif - class SkTypeface_Mac : public SkTypeface { public: - SkTypeface_Mac(CTFontRef fontRef, CFTypeRef resourceRef, + SkTypeface_Mac(UniqueCFRef fontRef, UniqueCFRef resourceRef, const SkFontStyle& fs, bool isFixedPitch, bool isLocalStream) : SkTypeface(fs, isFixedPitch) - , fFontRef(fontRef) // caller has already called CFRetain for us - , fOriginatingCFTypeRef(resourceRef) // caller has already called CFRetain for us - , fHasColorGlyphs(SkToBool(CTFontGetSymbolicTraits(fFontRef) & SkCTFontColorGlyphsTrait)) + , fFontRef(std::move(fontRef)) + , fOriginatingCFTypeRef(std::move(resourceRef)) + , fHasColorGlyphs( + SkToBool(CTFontGetSymbolicTraits(fFontRef.get()) & kCTFontColorGlyphsTrait)) , fIsLocalStream(isLocalStream) { - SkASSERT(fontRef); + SkASSERT(fFontRef); } - AutoCFRelease fFontRef; - AutoCFRelease fOriginatingCFTypeRef; + UniqueCFRef fFontRef; + UniqueCFRef fOriginatingCFTypeRef; const bool fHasColorGlyphs; bool hasColorGlyphs() const override { return fHasColorGlyphs; } @@ -519,20 +518,20 @@ protected: int onGetUPEM() const override; SkStreamAsset* onOpenStream(int* ttcIndex) const override; std::unique_ptr onMakeFontData() const override; + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override; void onGetFamilyName(SkString* familyName) const override; SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; int onGetTableTags(SkFontTableTag tags[]) const override; - virtual size_t onGetTableData(SkFontTableTag, size_t offset, - size_t length, void* data) const override; + size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override; SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, const SkDescriptor*) const override; void onFilterRec(SkScalerContextRec*) const override; void onGetFontDescriptor(SkFontDescriptor*, bool*) const override; - virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( - PerGlyphInfo, - const uint32_t*, uint32_t) const override; - virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[], - int glyphCount) const override; + SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( + PerGlyphInfo, const uint32_t* glyphIDs, uint32_t glyphIDsCount) const override; + int onCharsToGlyphs(const void* chars, Encoding, + uint16_t glyphs[], int glyphCount) const override; int onCountGlyphs() const override; private: @@ -543,18 +542,16 @@ private: static bool find_by_CTFontRef(SkTypeface* cached, void* context) { CTFontRef self = (CTFontRef)context; - CTFontRef other = ((SkTypeface_Mac*)cached)->fFontRef; + CTFontRef other = ((SkTypeface_Mac*)cached)->fFontRef.get(); return CFEqual(self, other); } -/** Creates a typeface, searching the cache if isLocalStream is false. - * Takes ownership of the CTFontRef and CFTypeRef. - */ -static SkTypeface* create_from_CTFontRef(CTFontRef f, CFTypeRef r, bool isLocalStream) { - SkASSERT(f); - AutoCFRelease font(f); - AutoCFRelease resource(r); +/** Creates a typeface, searching the cache if isLocalStream is false. */ +static SkTypeface* create_from_CTFontRef(UniqueCFRef font, + UniqueCFRef resource, + bool isLocalStream) { + SkASSERT(font); if (!isLocalStream) { SkTypeface* face = SkTypefaceCache::FindByProcAndRef(find_by_CTFontRef, (void*)font.get()); @@ -563,12 +560,12 @@ static SkTypeface* create_from_CTFontRef(CTFontRef f, CFTypeRef r, bool isLocalS } } - AutoCFRelease desc(CTFontCopyFontDescriptor(font)); - SkFontStyle style = fontstyle_from_descriptor(desc); - CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font); + UniqueCFRef desc(CTFontCopyFontDescriptor(font.get())); + SkFontStyle style = fontstyle_from_descriptor(desc.get(), isLocalStream); + CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font.get()); bool isFixedPitch = SkToBool(traits & kCTFontMonoSpaceTrait); - SkTypeface* face = new SkTypeface_Mac(font.release(), resource.release(), + SkTypeface* face = new SkTypeface_Mac(std::move(font), std::move(resource), style, isFixedPitch, isLocalStream); if (!isLocalStream) { SkTypefaceCache::Add(face); @@ -578,15 +575,31 @@ static SkTypeface* create_from_CTFontRef(CTFontRef f, CFTypeRef r, bool isLocalS /** Creates a typeface from a descriptor, searching the cache. */ static SkTypeface* create_from_desc(CTFontDescriptorRef desc) { - AutoCFRelease ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr)); + UniqueCFRef ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr)); if (!ctFont) { return nullptr; } - return create_from_CTFontRef(ctFont.release(), nullptr, false); + return create_from_CTFontRef(std::move(ctFont), nullptr, false); } -static CTFontDescriptorRef create_descriptor(const char familyName[], const SkFontStyle& style) { +static UniqueCFRef create_descriptor(const char familyName[], + const SkFontStyle& style) { + UniqueCFRef cfAttributes( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + UniqueCFRef cfTraits( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + if (!cfAttributes || !cfTraits) { + return nullptr; + } + + // CTFontTraits (symbolic) CTFontSymbolicTraits ctFontTraits = 0; if (style.weight() >= SkFontStyle::kBold_Weight) { ctFontTraits |= kCTFontBoldTrait; @@ -594,56 +607,54 @@ static CTFontDescriptorRef create_descriptor(const char familyName[], const SkFo if (style.slant() != SkFontStyle::kUpright_Slant) { ctFontTraits |= kCTFontItalicTrait; } - - //TODO: add weight width slant - - // Create the font info - AutoCFRelease cfFontName(make_CFString(familyName)); - - AutoCFRelease cfFontTraits( + UniqueCFRef cfFontTraits( CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits)); + if (cfFontTraits) { + CFDictionaryAddValue(cfTraits.get(), kCTFontSymbolicTrait, cfFontTraits.get()); + } + // CTFontTraits (weight) + CGFloat ctWeight = fontstyle_to_ct_weight(style.weight()); + UniqueCFRef cfFontWeight( + CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWeight)); + if (cfFontWeight) { + CFDictionaryAddValue(cfTraits.get(), kCTFontWeightTrait, cfFontWeight.get()); + } + // CTFontTraits (width) + CGFloat ctWidth = fontstyle_to_ct_width(style.weight()); + UniqueCFRef cfFontWidth( + CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWidth)); + if (cfFontWidth) { + CFDictionaryAddValue(cfTraits.get(), kCTFontWidthTrait, cfFontWidth.get()); + } + // CTFontTraits (slant) + CGFloat ctSlant = style.slant() == SkFontStyle::kUpright_Slant ? 0 : 1; + UniqueCFRef cfFontSlant( + CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctSlant)); + if (cfFontSlant) { + CFDictionaryAddValue(cfTraits.get(), kCTFontSlantTrait, cfFontSlant.get()); + } + // CTFontTraits + CFDictionaryAddValue(cfAttributes.get(), kCTFontTraitsAttribute, cfTraits.get()); - AutoCFRelease cfAttributes( - CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - AutoCFRelease cfTraits( - CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - if (!cfFontName || !cfFontTraits || !cfAttributes || !cfTraits) { - return nullptr; + // CTFontFamilyName + if (familyName) { + UniqueCFRef cfFontName = make_CFString(familyName); + if (cfFontName) { + CFDictionaryAddValue(cfAttributes.get(), kCTFontFamilyNameAttribute, cfFontName.get()); + } } - CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits); - - CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName); - CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits); - - return CTFontDescriptorCreateWithAttributes(cfAttributes); + return UniqueCFRef( + CTFontDescriptorCreateWithAttributes(cfAttributes.get())); } /** Creates a typeface from a name, searching the cache. */ static SkTypeface* create_from_name(const char familyName[], const SkFontStyle& style) { - AutoCFRelease desc(create_descriptor(familyName, style)); + UniqueCFRef desc = create_descriptor(familyName, style); if (!desc) { return nullptr; } - return create_from_desc(desc); -} - -SK_DECLARE_STATIC_MUTEX(gGetDefaultFaceMutex); -static SkTypeface* GetDefaultFace() { - SkAutoMutexAcquire ma(gGetDefaultFaceMutex); - - static SkTypeface* gDefaultFace; - - if (nullptr == gDefaultFace) { - gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()); - } - return gDefaultFace; + return create_from_desc(desc.get()); } /////////////////////////////////////////////////////////////////////////////// @@ -657,12 +668,14 @@ CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) { /* This function is visible on the outside. It first searches the cache, and if * not found, returns a new entry (after adding it to the cache). */ -SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef, CFTypeRef resourceRef) { - CFRetain(fontRef); - if (resourceRef) { - CFRetain(resourceRef); +SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef font, CFTypeRef resource) { + CFRetain(font); + if (resource) { + CFRetain(resource); } - return create_from_CTFontRef(fontRef, resourceRef, false); + return create_from_CTFontRef(UniqueCFRef(font), + UniqueCFRef(resource), + false); } static const char* map_css_names(const char* name) { @@ -685,17 +698,9 @@ static const char* map_css_names(const char* name) { /////////////////////////////////////////////////////////////////////////////// -/** GlyphRect is in FUnits (em space, y up). */ -struct GlyphRect { - int16_t fMinX; - int16_t fMinY; - int16_t fMaxX; - int16_t fMaxY; -}; - class SkScalerContext_Mac : public SkScalerContext { public: - SkScalerContext_Mac(SkTypeface_Mac*, const SkScalerContextEffects&, const SkDescriptor*); + SkScalerContext_Mac(sk_sp, const SkScalerContextEffects&, const SkDescriptor*); protected: unsigned generateGlyphCount(void) override; @@ -703,7 +708,7 @@ protected: void generateAdvance(SkGlyph* glyph) override; void generateMetrics(SkGlyph* glyph) override; void generateImage(const SkGlyph& glyph) override; - void generatePath(const SkGlyph& glyph, SkPath* path) override; + void generatePath(SkGlyphID glyph, SkPath* path) override; void generateFontMetrics(SkPaint::FontMetrics*) override; private: @@ -712,37 +717,6 @@ private: /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */ void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const; - /** Initializes and returns the value of fFBoundingBoxesGlyphOffset. - * - * For use with (and must be called before) generateBBoxes. - */ - uint16_t getFBoundingBoxesGlyphOffset(); - - /** Initializes fFBoundingBoxes and returns true on success. - * - * On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to - * return a bad value in bounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is - * less than its maxp::numGlyphs. When this is the case we try to read the bounds from the - * font directly. - * - * This routine initializes fFBoundingBoxes to an array of - * fGlyphCount - fFBoundingBoxesGlyphOffset GlyphRects which contain the bounds in FUnits - * (em space, y up) of glyphs with ids in the range [fFBoundingBoxesGlyphOffset, fGlyphCount). - * - * Returns true if fFBoundingBoxes is properly initialized. The table can only be properly - * initialized for a TrueType font with 'head', 'loca', and 'glyf' tables. - * - * TODO: A future optimization will compute fFBoundingBoxes once per fCTFont. - */ - bool generateBBoxes(); - - /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down). - * - * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs. - * Used on Lion to correct CTFontGetBoundingRectsForGlyphs. - */ - SkMatrix fFUnitMatrix; - Offscreen fOffscreen; /** Unrotated variant of fCTFont. @@ -752,9 +726,9 @@ private: * unrotated glyph, and then the rotation is applied separately. * * CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise. - * This makes kCTFontDefaultOrientation dangerous, because the metrics from - * kCTFontHorizontalOrientation are in a different space from kCTFontVerticalOrientation. - * With kCTFontVerticalOrientation the advances must be unrotated. + * This makes kCTFontOrientationDefault dangerous, because the metrics from + * kCTFontOrientationHorizontal are in a different space from kCTFontOrientationVertical. + * With kCTFontOrientationVertical the advances must be unrotated. * * Sometimes, creating a copy of a CTFont with the same size but different trasform will select * different underlying font data. As a result, avoid ever creating more than one CTFont per @@ -763,17 +737,14 @@ private: * As a result of the above (and other constraints) this font contains the size, but not the * transform. The transform must always be applied separately. */ - AutoCFRelease fCTFont; + UniqueCFRef fCTFont; /** The transform without the font size. */ CGAffineTransform fTransform; CGAffineTransform fInvTransform; - AutoCFRelease fCGFont; - SkAutoTMalloc fFBoundingBoxes; - uint16_t fFBoundingBoxesGlyphOffset; + UniqueCFRef fCGFont; uint16_t fGlyphCount; - bool fGeneratedFBoundingBoxes; const bool fDoSubPosition; const bool fVertical; @@ -787,10 +758,13 @@ private: // It is not possible to use descriptors with CTFontCreateWithFontDescriptor, since that does not // work with non-system fonts. As a result, create the strike specific CTFonts from the underlying // CGFont. -static CTFontRef ctfont_create_exact_copy(CTFontRef baseFont, CGFloat textSize, - const CGAffineTransform* transform) +#ifdef MOZ_SKIA +extern "C" bool Gecko_OnSierraOrLater(); +#endif +static UniqueCFRef ctfont_create_exact_copy(CTFontRef baseFont, CGFloat textSize, + const CGAffineTransform* transform) { - AutoCFRelease baseCGFont(CTFontCopyGraphicsFont(baseFont, nullptr)); + UniqueCFRef baseCGFont(CTFontCopyGraphicsFont(baseFont, nullptr)); // The last parameter (CTFontDescriptorRef attributes) *must* be nullptr. // If non-nullptr then with fonts with variation axes, the copy will fail in @@ -801,13 +775,16 @@ static CTFontRef ctfont_create_exact_copy(CTFontRef baseFont, CGFloat textSize, // as other uses of CTFontCreateWithGraphicsFont which is that such CTFonts should not escape // the scaler context, since they aren't 'normal'. +#ifdef MOZ_SKIA // Avoid calling potentially buggy variation APIs on pre-Sierra macOS // versions (see bug 1331683) - if (darwinVersion() >= 16) { - // Not AutoCFRelease<> because CGFontCopyVariations can return null! - CFDictionaryRef variations = CGFontCopyVariations(baseCGFont); + if (Gecko_OnSierraOrLater()) +#endif + { + // Not UniqueCFRef<> because CGFontCopyVariations can return null! + CFDictionaryRef variations = CGFontCopyVariations(baseCGFont.get()); if (variations) { - AutoCFRelease + UniqueCFRef varAttr(CFDictionaryCreate(nullptr, (const void**)&kCTFontVariationAttribute, (const void**)&variations, @@ -816,30 +793,29 @@ static CTFontRef ctfont_create_exact_copy(CTFontRef baseFont, CGFloat textSize, &kCFTypeDictionaryValueCallBacks)); CFRelease(variations); - AutoCFRelease - varDesc(CTFontDescriptorCreateWithAttributes(varAttr)); + UniqueCFRef + varDesc(CTFontDescriptorCreateWithAttributes(varAttr.get())); - return CTFontCreateWithGraphicsFont(baseCGFont, textSize, transform, varDesc); + return UniqueCFRef( + CTFontCreateWithGraphicsFont(baseCGFont.get(), textSize, transform, varDesc.get())); } } - return CTFontCreateWithGraphicsFont(baseCGFont, textSize, transform, nullptr); + return UniqueCFRef( + CTFontCreateWithGraphicsFont(baseCGFont.get(), textSize, transform, nullptr)); } -SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, +SkScalerContext_Mac::SkScalerContext_Mac(sk_sp typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc) - : INHERITED(typeface, effects, desc) - , fFBoundingBoxes() - , fFBoundingBoxesGlyphOffset(0) - , fGeneratedFBoundingBoxes(false) + : INHERITED(std::move(typeface), effects, desc) , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) , fVertical(SkToBool(fRec.fFlags & kVertical_Flag)) { AUTO_CG_LOCK(); - CTFontRef ctFont = typeface->fFontRef.get(); + CTFontRef ctFont = static_cast(this->getTypeface())->fFontRef.get(); CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); fGlyphCount = SkToU16(numGlyphs); @@ -849,7 +825,7 @@ SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, SkVector scale; SkMatrix skTransform; bool invertible = fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, - &scale, &skTransform, nullptr, nullptr, &fFUnitMatrix); + &scale, &skTransform, nullptr, nullptr, nullptr); fTransform = MatrixToCGAffineTransform(skTransform); // CGAffineTransformInvert documents that if the transform is non-invertible it will return the // passed transform unchanged. It does so, but then also prints a message to stdout. Avoid this. @@ -862,12 +838,8 @@ SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, // The transform contains everything except the requested text size. // Some properties, like 'trak', are based on the text size (before applying the matrix). CGFloat textSize = ScalarToCG(scale.y()); - fCTFont.reset(ctfont_create_exact_copy(ctFont, textSize, nullptr)); - fCGFont.reset(CTFontCopyGraphicsFont(fCTFont, nullptr)); - - // The fUnitMatrix includes the text size (and em) as it is used to scale the raw font data. - SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont))); - fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit); + fCTFont = ctfont_create_exact_copy(ctFont, textSize, nullptr); + fCGFont.reset(CTFontCopyGraphicsFont(fCTFont.get(), nullptr)); } CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, @@ -918,37 +890,37 @@ CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& : kCGImageAlphaNoneSkipFirst; const CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | alpha; fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, - rowBytes, fRGBSpace, bitmapInfo)); + rowBytes, fRGBSpace.get(), bitmapInfo)); // Skia handles quantization and subpixel positioning, // so disable quantization and enabe subpixel positioning in CG. - CGContextSetAllowsFontSubpixelQuantization(fCG, false); - CGContextSetShouldSubpixelQuantizeFonts(fCG, false); + CGContextSetAllowsFontSubpixelQuantization(fCG.get(), false); + CGContextSetShouldSubpixelQuantizeFonts(fCG.get(), false); // Because CG always draws from the horizontal baseline, // if there is a non-integral translation from the horizontal origin to the vertical origin, // then CG cannot draw the glyph in the correct location without subpixel positioning. - CGContextSetAllowsFontSubpixelPositioning(fCG, true); - CGContextSetShouldSubpixelPositionFonts(fCG, true); + CGContextSetAllowsFontSubpixelPositioning(fCG.get(), true); + CGContextSetShouldSubpixelPositionFonts(fCG.get(), true); - CGContextSetTextDrawingMode(fCG, kCGTextFill); + CGContextSetTextDrawingMode(fCG.get(), kCGTextFill); // Draw black on white to create mask. (Special path exists to speed this up in CG.) - CGContextSetGrayFillColor(fCG, 0.0f, 1.0f); + CGContextSetGrayFillColor(fCG.get(), 0.0f, 1.0f); // force our checks below to happen fDoAA = !doAA; fDoLCD = !doLCD; - CGContextSetTextMatrix(fCG, context.fTransform); + CGContextSetTextMatrix(fCG.get(), context.fTransform); } if (fDoAA != doAA) { - CGContextSetShouldAntialias(fCG, doAA); + CGContextSetShouldAntialias(fCG.get(), doAA); fDoAA = doAA; } if (fDoLCD != doLCD) { - CGContextSetShouldSmoothFonts(fCG, doLCD); + CGContextSetShouldSmoothFonts(fCG.get(), doLCD); fDoLCD = doLCD; } @@ -979,13 +951,13 @@ CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& // Prior to 10.10, CTFontDrawGlyphs acted like CGContextShowGlyphsAtPositions and took // 'positions' which are in text space. The glyph location (in device space) must be // mapped into text space, so that CG can convert it back into device space. - // In 10.10.1, this is handled directly in CTFontDrawGlyphs. + // In 10.10.1, this is handled directly in CTFontDrawGlyphs. // // However, in 10.10.2 color glyphs no longer rotate based on the font transform. // So always make the font transform identity and place the transform on the context. point = CGPointApplyAffineTransform(point, context.fInvTransform); - CTFontDrawGlyphs(context.fCTFont, &glyphID, &point, 1, fCG); + CTFontDrawGlyphs(context.fCTFont.get(), &glyphID, &point, 1, fCG.get()); SkASSERT(rowBytesPtr); *rowBytesPtr = rowBytes; @@ -993,17 +965,9 @@ CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& } void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const { - // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up). - // Lion and Leopard return cgVertOffset in CG units (pixels, y up). + // CTFontGetVerticalTranslationsForGlyphs produces cgVertOffset in CG units (pixels, y up). CGSize cgVertOffset; - CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1); - if (isSnowLeopard()) { - SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) }; - // From FUnits (em space, y up) to SkGlyph units (pixels, y down). - fFUnitMatrix.mapPoints(&skVertOffset, 1); - *offset = skVertOffset; - return; - } + CTFontGetVerticalTranslationsForGlyphs(fCTFont.get(), &glyphID, &cgVertOffset, 1); cgVertOffset = CGSizeApplyAffineTransform(cgVertOffset, fTransform); SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) }; // From CG units (pixels, y up) to SkGlyph units (pixels, y down). @@ -1011,57 +975,6 @@ void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) co *offset = skVertOffset; } -uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() { - if (fFBoundingBoxesGlyphOffset) { - return fFBoundingBoxesGlyphOffset; - } - fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts - AutoCGTable hheaTable(fCGFont); - if (hheaTable.fData) { - fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetrics); - } - return fFBoundingBoxesGlyphOffset; -} - -bool SkScalerContext_Mac::generateBBoxes() { - if (fGeneratedFBoundingBoxes) { - return SkToBool(fFBoundingBoxes.get()); - } - fGeneratedFBoundingBoxes = true; - - AutoCGTable headTable(fCGFont); - if (!headTable.fData) { - return false; - } - - AutoCGTable locaTable(fCGFont); - if (!locaTable.fData) { - return false; - } - - AutoCGTable glyfTable(fCGFont); - if (!glyfTable.fData) { - return false; - } - - uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset; - fFBoundingBoxes.reset(entries); - - SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat; - SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, locaFormat); - glyphDataIter.advance(fFBoundingBoxesGlyphOffset); - for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundingBoxesIndex) { - const SkOTTableGlyphData* glyphData = glyphDataIter.next(); - GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex]; - rect.fMinX = SkEndian_SwapBE16(glyphData->xMin); - rect.fMinY = SkEndian_SwapBE16(glyphData->yMin); - rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax); - rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax); - } - - return true; -} - unsigned SkScalerContext_Mac::generateGlyphCount(void) { return fGlyphCount; } @@ -1079,7 +992,7 @@ uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points: // When a surrogate pair is detected, the glyph index used is the index of the high surrogate. // It is documented that if a mapping is unavailable, the glyph will be set to 0. - CTFontGetGlyphsForCharacters(fCTFont, theChar, cgGlyph, numUniChar); + CTFontGetGlyphsForCharacters(fCTFont.get(), theChar, cgGlyph, numUniChar); return cgGlyph[0]; } @@ -1096,13 +1009,13 @@ void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { // The following block produces cgAdvance in CG units (pixels, y up). CGSize cgAdvance; if (fVertical) { - CTFontGetAdvancesForGlyphs(fCTFont, kCTFontVerticalOrientation, + CTFontGetAdvancesForGlyphs(fCTFont.get(), kCTFontOrientationVertical, &cgGlyph, &cgAdvance, 1); // Vertical advances are returned as widths instead of heights. SkTSwap(cgAdvance.height, cgAdvance.width); cgAdvance.height = -cgAdvance.height; } else { - CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation, + CTFontGetAdvancesForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal, &cgGlyph, &cgAdvance, 1); } cgAdvance = CGSizeApplyAffineTransform(cgAdvance, fTransform); @@ -1113,42 +1026,15 @@ void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { // or returns early if skBounds would be empty. SkRect skBounds; - // On Mountain Lion, CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation and - // CTFontGetVerticalTranslationsForGlyphs do not agree when using OTF CFF fonts. - // For TTF fonts these two do agree and we can use CTFontGetBoundingRectsForGlyphs to get - // the bounding box and CTFontGetVerticalTranslationsForGlyphs to then draw the glyph - // inside that bounding box. However, with OTF CFF fonts this does not work. It appears that - // CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation on OTF CFF fonts tries - // to center the glyph along the vertical baseline and also perform some mysterious shift - // along the baseline. CTFontGetVerticalTranslationsForGlyphs does not appear to perform - // these steps. - // - // It is not known which is correct (or if either is correct). However, we must always draw - // from the horizontal origin and must use CTFontGetVerticalTranslationsForGlyphs to draw. - // As a result, we do not call CTFontGetBoundingRectsForGlyphs for vertical glyphs. - - // On Snow Leopard, CTFontGetBoundingRectsForGlyphs ignores kCTFontVerticalOrientation and - // returns horizontal bounds. - - // On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to - // return a bad value in cgBounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is - // less than its maxp::numGlyphs. When this is the case we try to read the bounds from the - // font directly. - if ((isLion() || isMountainLion()) && - (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes())) + // Glyphs are always drawn from the horizontal origin. The caller must manually use the result + // of CTFontGetVerticalTranslationsForGlyphs to calculate where to draw the glyph for vertical + // glyphs. As a result, always get the horizontal bounds of a glyph and translate it if the + // glyph is vertical. This avoids any diagreement between the various means of retrieving + // vertical metrics. { - const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset]; - if (gRect.fMinX >= gRect.fMaxX || gRect.fMinY >= gRect.fMaxY) { - return; - } - skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY); - // From FUnits (em space, y up) to SkGlyph units (pixels, y down). - fFUnitMatrix.mapRect(&skBounds); - - } else { // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up). CGRect cgBounds; - CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation, + CTFontGetBoundingRectsForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal, &cgGlyph, &cgBounds, 1); cgBounds = CGRectApplyAffineTransform(cgBounds, fTransform); @@ -1158,8 +1044,8 @@ void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance // is rare, so we won't incur a big performance cost for this extra check. if (0 == cgAdvance.width && 0 == cgAdvance.height) { - AutoCFRelease path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, nullptr)); - if (nullptr == path || CGPathIsEmpty(path)) { + UniqueCFRef path(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph, nullptr)); + if (!path || CGPathIsEmpty(path.get())) { return; } } @@ -1174,10 +1060,10 @@ void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { } if (fVertical) { - // Due to all of the vertical bounds bugs, skBounds is always the horizontal bounds. + // Due to possible vertical bounds bugs and simplicity, skBounds is the horizontal bounds. // Convert these horizontal bounds into vertical bounds. SkPoint offset; - getVerticalOffset(cgGlyph, &offset); + this->getVerticalOffset(cgGlyph, &offset); skBounds.offset(offset); } @@ -1263,8 +1149,8 @@ static void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, for (int i = 0; i < width; ++i) { dst[i] = rgb_to_a8(cgPixels[i], table8); } - cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); - dst += dstRB; + cgPixels = SkTAddOffset(cgPixels, cgRowBytes); + dst = SkTAddOffset(dst, dstRB); } } @@ -1293,8 +1179,8 @@ static void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowByt for (int i = 0; i < width; i++) { dst[i] = rgb_to_lcd16(cgPixels[i], tableR, tableG, tableB); } - cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); - dst = (uint16_t*)((char*)dst + dstRB); + cgPixels = SkTAddOffset(cgPixels, cgRowBytes); + dst = SkTAddOffset(dst, dstRB); } } @@ -1310,7 +1196,7 @@ static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) { } void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { - CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(); + CGGlyph cgGlyph = SkTo(glyph.getGlyphID()); // FIXME: lcd smoothed un-hinted rasterization unsupported. bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting; @@ -1323,8 +1209,9 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { } // Fix the glyph - const bool isLCD = isLCDFormat(glyph.fMaskFormat); - if (isLCD || (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) { + if ((glyph.fMaskFormat == SkMask::kLCD16_Format) || + (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) + { const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing(); //Note that the following cannot really be integrated into the @@ -1368,8 +1255,8 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { uint8_t* dst = (uint8_t*)glyph.fImage; for (int y = 0; y < glyph.fHeight; y++) { cgpixels_to_bits(dst, cgPixels, width); - cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); - dst += dstRB; + cgPixels = SkTAddOffset(cgPixels, cgRowBytes); + dst = SkTAddOffset(dst, dstRB); } } break; case SkMask::kARGB32_Format: { @@ -1380,8 +1267,8 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { for (int x = 0; x < width; ++x) { dst[x] = cgpixels_to_pmcolor(cgPixels[x]); } - cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); - dst = (SkPMColor*)((char*)dst + dstRB); + cgPixels = SkTAddOffset(cgPixels, cgRowBytes); + dst = SkTAddOffset(dst, dstRB); } } break; default: @@ -1397,7 +1284,7 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { */ #define kScaleForSubPixelPositionHinting (4.0f) -void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) { +void SkScalerContext_Mac::generatePath(SkGlyphID glyph, SkPath* path) { AUTO_CG_LOCK(); SkScalar scaleX = SK_Scalar1; @@ -1432,12 +1319,12 @@ void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) { xform = CGAffineTransformConcat(fTransform, scale); } - CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(); - AutoCFRelease cgPath(CTFontCreatePathForGlyph(fCTFont, cgGlyph, &xform)); + CGGlyph cgGlyph = SkTo(glyph); + UniqueCFRef cgPath(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph, &xform)); path->reset(); if (cgPath != nullptr) { - CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement); + CGPathApply(cgPath.get(), path, SkScalerContext_Mac::CTPathElement); } if (fDoSubPosition) { @@ -1459,24 +1346,51 @@ void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* metrics) { AUTO_CG_LOCK(); - CGRect theBounds = CTFontGetBoundingBox(fCTFont); + CGRect theBounds = CTFontGetBoundingBox(fCTFont.get()); metrics->fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds)); - metrics->fAscent = CGToScalar(-CTFontGetAscent(fCTFont)); - metrics->fDescent = CGToScalar( CTFontGetDescent(fCTFont)); + metrics->fAscent = CGToScalar(-CTFontGetAscent(fCTFont.get())); + metrics->fDescent = CGToScalar( CTFontGetDescent(fCTFont.get())); metrics->fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds)); - metrics->fLeading = CGToScalar( CTFontGetLeading(fCTFont)); + metrics->fLeading = CGToScalar( CTFontGetLeading(fCTFont.get())); metrics->fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds)); metrics->fXMin = CGToScalar( CGRectGetMinX_inline(theBounds)); metrics->fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds)); metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; - metrics->fXHeight = CGToScalar( CTFontGetXHeight(fCTFont)); - metrics->fCapHeight = CGToScalar( CTFontGetCapHeight(fCTFont)); - metrics->fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont)); - metrics->fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont)); + metrics->fXHeight = CGToScalar( CTFontGetXHeight(fCTFont.get())); + metrics->fCapHeight = CGToScalar( CTFontGetCapHeight(fCTFont.get())); + metrics->fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont.get())); + metrics->fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont.get())); - metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; + metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag; metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; + + // See https://bugs.chromium.org/p/skia/issues/detail?id=6203 + // At least on 10.12.3 with memory based fonts the x-height is always 0.6666 of the ascent and + // the cap-height is always 0.8888 of the ascent. It appears that the values from the 'OS/2' + // table are read, but then overwritten if the font is not a system font. As a result, if there + // is a valid 'OS/2' table available use the values from the table if they aren't too strange. + struct OS2HeightMetrics { + SK_OT_SHORT sxHeight; + SK_OT_SHORT sCapHeight; + } heights; + size_t bytesRead = this->getTypeface()->getTableData( + SkTEndian_SwapBE32(SkOTTableOS2::TAG), offsetof(SkOTTableOS2, version.v2.sxHeight), + sizeof(heights), &heights); + if (bytesRead == sizeof(heights)) { + // 'fontSize' is correct because the entire resolved size is set by the constructor. + CGFloat fontSize = CTFontGetSize(this->fCTFont.get()); + unsigned upem = CTFontGetUnitsPerEm(this->fCTFont.get()); + unsigned maxSaneHeight = upem * 2; + uint16_t xHeight = SkEndian_SwapBE16(heights.sxHeight); + if (xHeight && xHeight < maxSaneHeight) { + metrics->fXHeight = CGToScalar(xHeight * fontSize / upem); + } + uint16_t capHeight = SkEndian_SwapBE16(heights.sCapHeight); + if (capHeight && capHeight < maxSaneHeight) { + metrics->fCapHeight = CGToScalar(capHeight * fontSize / upem); + } + } } void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) { @@ -1518,16 +1432,22 @@ void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element // Returns nullptr on failure // Call must still manage its ownership of provider -static SkTypeface* create_from_dataProvider(CGDataProviderRef provider) { - AutoCFRelease cg(CGFontCreateWithDataProvider(provider)); - if (nullptr == cg) { +static SkTypeface* create_from_dataProvider(UniqueCFRef provider, int ttcIndex) { + if (ttcIndex != 0) { return nullptr; } - CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr); - return ct ? create_from_CTFontRef(ct, nullptr, true) : nullptr; + UniqueCFRef cg(CGFontCreateWithDataProvider(provider.get())); + if (!cg) { + return nullptr; + } + UniqueCFRef ct(CTFontCreateWithGraphicsFont(cg.get(), 0, nullptr, nullptr)); + if (!ct) { + return nullptr; + } + return create_from_CTFontRef(std::move(ct), nullptr, true); } -// Web fonts added to the the CTFont registry do not return their character set. +// Web fonts added to the CTFont registry do not return their character set. // Iterate through the font in this case. The existing caller caches the result, // so the performance impact isn't too bad. static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount, @@ -1539,8 +1459,10 @@ static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount, while (glyphCount > 0) { CGGlyph glyph; if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) { - out[glyph] = unichar; - --glyphCount; + if (out[glyph] != 0) { + out[glyph] = unichar; + --glyphCount; + } } if (++unichar == 0) { break; @@ -1553,18 +1475,17 @@ static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount, // supported. static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount, SkTDArray* glyphToUnicode) { - AutoCFRelease charSet(CTFontCopyCharacterSet(ctFont)); + UniqueCFRef charSet(CTFontCopyCharacterSet(ctFont)); if (!charSet) { populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode); return; } - AutoCFRelease bitmap(CFCharacterSetCreateBitmapRepresentation(kCFAllocatorDefault, - charSet)); + UniqueCFRef bitmap(CFCharacterSetCreateBitmapRepresentation(nullptr, charSet.get())); if (!bitmap) { return; } - CFIndex length = CFDataGetLength(bitmap); + CFIndex length = CFDataGetLength(bitmap.get()); if (!length) { return; } @@ -1575,7 +1496,7 @@ static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount, // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html length = 8192; } - const UInt8* bits = CFDataGetBytePtr(bitmap); + const UInt8* bits = CFDataGetBytePtr(bitmap.get()); glyphToUnicode->setCount(SkToInt(glyphCount)); SkUnichar* out = glyphToUnicode->begin(); sk_bzero(out, glyphCount * sizeof(SkUnichar)); @@ -1613,25 +1534,34 @@ SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics( AUTO_CG_LOCK(); - CTFontRef originalCTFont = fFontRef.get(); - AutoCFRelease ctFont(ctfont_create_exact_copy( - originalCTFont, CTFontGetUnitsPerEm(originalCTFont), nullptr)); + UniqueCFRef ctFont = + ctfont_create_exact_copy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), nullptr); SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics; { - AutoCFRelease fontName(CTFontCopyPostScriptName(ctFont)); + UniqueCFRef fontName(CTFontCopyPostScriptName(ctFont.get())); if (fontName.get()) { - CFStringToSkString(fontName, &info->fFontName); + CFStringToSkString(fontName.get(), &info->fFontName); } } - CFIndex glyphCount = CTFontGetGlyphCount(ctFont); - info->fLastGlyphID = SkToU16(glyphCount - 1); - info->fEmSize = CTFontGetUnitsPerEm(ctFont); + // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when + // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always + // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and + // CGFontCopyVariations here until support for 10.10 and earlier is removed. + UniqueCFRef cgFont(CTFontCopyGraphicsFont(ctFont.get(), nullptr)); + if (cgFont) { + UniqueCFRef cgAxes(CGFontCopyVariationAxes(cgFont.get())); + if (cgAxes && CFArrayGetCount(cgAxes.get()) > 0) { + info->fFlags |= SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag; + } + } + + CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get()); if (perGlyphInfo & kToUnicode_PerGlyphInfo) { - populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode); + populate_glyph_to_unicode(ctFont.get(), glyphCount, &info->fGlyphToUnicode); } // If it's not a truetype font, mark it as 'other'. Assume that TrueType @@ -1643,7 +1573,7 @@ SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics( } info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; - CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont); + CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get()); if (symbolicTraits & kCTFontMonoSpaceTrait) { info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; } @@ -1656,11 +1586,11 @@ SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics( } else if (stylisticClass & kCTFontScriptsClass) { info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; } - info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont); - info->fAscent = (int16_t) CTFontGetAscent(ctFont); - info->fDescent = (int16_t) CTFontGetDescent(ctFont); - info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont); - CGRect bbox = CTFontGetBoundingBox(ctFont); + info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get()); + info->fAscent = (int16_t) CTFontGetAscent(ctFont.get()); + info->fDescent = (int16_t) CTFontGetDescent(ctFont.get()); + info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get()); + CGRect bbox = CTFontGetBoundingBox(ctFont.get()); SkRect r; r.set( CGToScalar(CGRectGetMinX_inline(bbox)), // Left @@ -1678,8 +1608,8 @@ SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics( const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]); CGGlyph glyphs[count]; CGRect boundingRects[count]; - if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) { - CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation, + if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars, glyphs, count)) { + CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal, glyphs, boundingRects, count); for (size_t i = 0; i < count; i++) { int16_t width = (int16_t) boundingRects[i].size.width; @@ -1696,14 +1626,14 @@ SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics( static SK_SFNT_ULONG get_font_type_tag(const SkTypeface_Mac* typeface) { CTFontRef ctFont = typeface->fFontRef.get(); - AutoCFRelease fontFormatRef( + UniqueCFRef fontFormatRef( static_cast(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute))); if (!fontFormatRef) { return 0; } SInt32 fontFormatValue; - if (!CFNumberGetValue(fontFormatRef, kCFNumberSInt32Type, &fontFormatValue)) { + if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) { return 0; } @@ -1838,28 +1768,35 @@ static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context) } self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble); } -static bool get_variations(CTFontRef fFontRef, CFIndex* cgAxisCount, +static bool get_variations(CTFontRef ctFont, CFIndex* cgAxisCount, SkAutoSTMalloc<4, SkFixed>* axisValues) { - // CTFontCopyVariationAxes and CTFontCopyVariation do not work when applied to fonts which - // started life with CGFontCreateWithDataProvider (they simply always return nullptr). - // As a result, we are limited to CGFontCopyVariationAxes and CGFontCopyVariations. - AutoCFRelease cgFont(CTFontCopyGraphicsFont(fFontRef, nullptr)); - - AutoCFRelease cgVariations(CGFontCopyVariations(cgFont)); - // If a font has no variations CGFontCopyVariations returns nullptr (instead of an empty dict). - if (!cgVariations.get()) { + // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when + // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always + // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and + // CGFontCopyVariations here until support for 10.10 and earlier is removed. + UniqueCFRef cgFont(CTFontCopyGraphicsFont(ctFont, nullptr)); + if (!cgFont) { return false; } - AutoCFRelease cgAxes(CGFontCopyVariationAxes(cgFont)); - *cgAxisCount = CFArrayGetCount(cgAxes); + UniqueCFRef cgVariations(CGFontCopyVariations(cgFont.get())); + // If a font has no variations CGFontCopyVariations returns nullptr (instead of an empty dict). + if (!cgVariations) { + return false; + } + + UniqueCFRef cgAxes(CGFontCopyVariationAxes(cgFont.get())); + if (!cgAxes) { + return false; + } + *cgAxisCount = CFArrayGetCount(cgAxes.get()); axisValues->reset(*cgAxisCount); // Set all of the axes to their default values. // Fail if any default value cannot be determined. for (CFIndex i = 0; i < *cgAxisCount; ++i) { - CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes, i); + CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes.get(), i); if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) { return false; } @@ -1886,7 +1823,7 @@ static bool get_variations(CTFontRef fFontRef, CFIndex* cgAxisCount, // Override the default values with the given font's stated axis values. NonDefaultAxesContext c = { axisValues->get(), cgAxes.get() }; - CFDictionaryApplyFunction(cgVariations, set_non_default_axes, &c); + CFDictionaryApplyFunction(cgVariations.get(), set_non_default_axes, &c); return true; } @@ -1896,37 +1833,158 @@ std::unique_ptr SkTypeface_Mac::onMakeFontData() const { CFIndex cgAxisCount; SkAutoSTMalloc<4, SkFixed> axisValues; - if (get_variations(fFontRef, &cgAxisCount, &axisValues)) { + if (get_variations(fFontRef.get(), &cgAxisCount, &axisValues)) { return skstd::make_unique(std::move(stream), index, axisValues.get(), cgAxisCount); } return skstd::make_unique(std::move(stream), index, nullptr, 0); } +/** Creates a CT variation dictionary {tag, value} from a CG variation dictionary {name, value}. */ +static UniqueCFRef ct_variation_from_cg_variation(CFDictionaryRef cgVariations, + CFArrayRef ctAxes) { + + UniqueCFRef ctVariations( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + CFIndex axisCount = CFArrayGetCount(ctAxes); + for (CFIndex i = 0; i < axisCount; ++i) { + CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes, i); + if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { + return nullptr; + } + CFDictionaryRef axisInfoDict = static_cast(axisInfo); + + // The assumption is that values produced by kCTFontVariationAxisNameKey and + // kCGFontVariationAxisName will always be equal. + CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey); + if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) { + return nullptr; + } + + CFTypeRef axisValue = CFDictionaryGetValue(cgVariations, axisName); + if (!axisValue || CFGetTypeID(axisValue) != CFNumberGetTypeID()) { + return nullptr; + } + + CFTypeRef axisTag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); + if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) { + return nullptr; + } + + CFDictionaryAddValue(ctVariations.get(), axisTag, axisValue); + } + return std::move(ctVariations); +} + +int SkTypeface_Mac::onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const +{ + // The CGFont variation data does not contain the tag. + + // This call always returns nullptr on 10.10 and under for CGFontCreateWithDataProvider fonts. + // When this happens, there is no API to provide the tag. + UniqueCFRef ctAxes(CTFontCopyVariationAxes(fFontRef.get())); + if (!ctAxes) { + return -1; + } + CFIndex axisCount = CFArrayGetCount(ctAxes.get()); + if (!coordinates || coordinateCount < axisCount) { + return axisCount; + } + + // This call always returns nullptr on 10.11 and under for CGFontCreateWithDataProvider fonts. + // When this happens, try converting the CG variation to a CT variation. + // On 10.12 and later, this only returns non-default variations. + UniqueCFRef ctVariations(CTFontCopyVariation(fFontRef.get())); + if (!ctVariations) { + // When 10.11 and earlier are no longer supported, the following code can be replaced with + // return -1 and ct_variation_from_cg_variation can be removed. + UniqueCFRef cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr)); + if (!cgFont) { + return -1; + } + UniqueCFRef cgVariations(CGFontCopyVariations(cgFont.get())); + if (!cgVariations) { + return -1; + } + ctVariations = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get()); + if (!ctVariations) { + return -1; + } + } + + for (int i = 0; i < axisCount; ++i) { + CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); + if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { + return -1; + } + CFDictionaryRef axisInfoDict = static_cast(axisInfo); + + CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); + if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { + return -1; + } + CFNumberRef tagNumber = static_cast(tag); + int64_t tagLong; + if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { + return -1; + } + coordinates[i].axis = tagLong; + + CGFloat variationCGFloat; + CFTypeRef variationValue = CFDictionaryGetValue(ctVariations.get(), tagNumber); + if (variationValue) { + if (CFGetTypeID(variationValue) != CFNumberGetTypeID()) { + return -1; + } + CFNumberRef variationNumber = static_cast(variationValue); + if (!CFNumberGetValue(variationNumber, kCFNumberCGFloatType, &variationCGFloat)) { + return -1; + } + } else { + CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey); + if (!def || CFGetTypeID(def) != CFNumberGetTypeID()) { + return -1; + } + CFNumberRef defNumber = static_cast(def); + if (!CFNumberGetValue(defNumber, kCFNumberCGFloatType, &variationCGFloat)) { + return -1; + } + } + coordinates[i].value = CGToScalar(variationCGFloat); + + } + return axisCount; +} + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// int SkTypeface_Mac::onGetUPEM() const { - AutoCFRelease cgFont(CTFontCopyGraphicsFont(fFontRef, nullptr)); - return CGFontGetUnitsPerEm(cgFont); + UniqueCFRef cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr)); + return CGFontGetUnitsPerEm(cgFont.get()); } SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const { SkTypeface::LocalizedStrings* nameIter = - SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this); + SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this); if (nullptr == nameIter) { - AutoCFRelease cfLanguage; - AutoCFRelease cfFamilyName( - CTFontCopyLocalizedName(fFontRef, kCTFontFamilyNameKey, &cfLanguage)); + CFStringRef cfLanguageRaw; + UniqueCFRef cfFamilyName( + CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw)); + UniqueCFRef cfLanguage(cfLanguageRaw); SkString skLanguage; SkString skFamilyName; - if (cfLanguage.get()) { + if (cfLanguage) { CFStringToSkString(cfLanguage.get(), &skLanguage); } else { skLanguage = "und"; //undetermined } - if (cfFamilyName.get()) { + if (cfFamilyName) { CFStringToSkString(cfFamilyName.get(), &skFamilyName); } @@ -1935,43 +1993,44 @@ SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const return nameIter; } -// If, as is the case with web fonts, the CTFont data isn't available, -// the CGFont data may work. While the CGFont may always provide the -// right result, leave the CTFont code path to minimize disruption. -static CFDataRef copyTableFromFont(CTFontRef ctFont, SkFontTableTag tag) { - CFDataRef data = CTFontCopyTable(ctFont, (CTFontTableTag) tag, - kCTFontTableOptionNoOptions); - if (nullptr == data) { - AutoCFRelease cgFont(CTFontCopyGraphicsFont(ctFont, nullptr)); - data = CGFontCopyTableForTag(cgFont, tag); - } - return data; -} - int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const { - AutoCFRelease cfArray(CTFontCopyAvailableTables(fFontRef, - kCTFontTableOptionNoOptions)); - if (nullptr == cfArray) { + UniqueCFRef cfArray( + CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions)); + if (!cfArray) { return 0; } - int count = SkToInt(CFArrayGetCount(cfArray)); + int count = SkToInt(CFArrayGetCount(cfArray.get())); if (tags) { for (int i = 0; i < count; ++i) { - uintptr_t fontTag = reinterpret_cast(CFArrayGetValueAtIndex(cfArray, i)); + uintptr_t fontTag = reinterpret_cast( + CFArrayGetValueAtIndex(cfArray.get(), i)); tags[i] = static_cast(fontTag); } } return count; } +// If, as is the case with web fonts, the CTFont data isn't available, +// the CGFont data may work. While the CGFont may always provide the +// right result, leave the CTFont code path to minimize disruption. +static UniqueCFRef copy_table_from_font(CTFontRef ctFont, SkFontTableTag tag) { + UniqueCFRef data(CTFontCopyTable(ctFont, (CTFontTableTag) tag, + kCTFontTableOptionNoOptions)); + if (!data) { + UniqueCFRef cgFont(CTFontCopyGraphicsFont(ctFont, nullptr)); + data.reset(CGFontCopyTableForTag(cgFont.get(), tag)); + } + return data; +} + size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset, size_t length, void* dstData) const { - AutoCFRelease srcData(copyTableFromFont(fFontRef, tag)); - if (nullptr == srcData) { + UniqueCFRef srcData = copy_table_from_font(fFontRef.get(), tag); + if (!srcData) { return 0; } - size_t srcSize = CFDataGetLength(srcData); + size_t srcSize = CFDataGetLength(srcData.get()); if (offset >= srcSize) { return 0; } @@ -1979,14 +2038,14 @@ size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset, length = srcSize - offset; } if (dstData) { - memcpy(dstData, CFDataGetBytePtr(srcData) + offset, length); + memcpy(dstData, CFDataGetBytePtr(srcData.get()) + offset, length); } return length; } SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkScalerContextEffects& effects, const SkDescriptor* desc) const { - return new SkScalerContext_Mac(const_cast(this), effects, desc); + return new SkScalerContext_Mac(sk_ref_sp(const_cast(this)), effects, desc); } void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const { @@ -2041,7 +2100,7 @@ void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const { // Currenly side with LCD, effectively ignoring the hinting setting. // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output. - if (isLCDFormat(rec->fMaskFormat)) { + if (rec->fMaskFormat == SkMask::kLCD16_Format) { if (lcdSupport) { //CoreGraphics creates 555 masks for smoothed text anyway. rec->fMaskFormat = SkMask::kLCD16_Format; @@ -2071,27 +2130,27 @@ void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const { } } -// we take ownership of the ref +/** Takes ownership of the CFStringRef. */ static const char* get_str(CFStringRef ref, SkString* str) { if (nullptr == ref) { return nullptr; } CFStringToSkString(ref, str); - CFSafeRelease(ref); + CFRelease(ref); return str->c_str(); } void SkTypeface_Mac::onGetFamilyName(SkString* familyName) const { - get_str(CTFontCopyFamilyName(fFontRef), familyName); + get_str(CTFontCopyFamilyName(fFontRef.get()), familyName); } void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocalStream) const { SkString tmpStr; - desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef), &tmpStr)); - desc->setFullName(get_str(CTFontCopyFullName(fFontRef), &tmpStr)); - desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef), &tmpStr)); + desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr)); + desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr)); + desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr)); desc->setStyle(this->fontStyle()); *isLocalStream = fIsLocalStream; } @@ -2149,7 +2208,7 @@ int SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding, macGlyphs = glyphStorage.reset(srcCount); } - bool allEncoded = CTFontGetGlyphsForCharacters(fFontRef, src, macGlyphs, srcCount); + bool allEncoded = CTFontGetGlyphsForCharacters(fFontRef.get(), src, macGlyphs, srcCount); // If there were any non-bmp, then copy and compact. // If 'glyphs' is nullptr, then compact glyphStorage in-place. @@ -2184,18 +2243,18 @@ int SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding, } int SkTypeface_Mac::onCountGlyphs() const { - return SkToInt(CTFontGetGlyphCount(fFontRef)); + return SkToInt(CTFontGetGlyphCount(fFontRef.get())); } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) { - AutoCFRelease ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name)); - if (nullptr == ref.get()) { + UniqueCFRef ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name)); + if (!ref) { return false; } - CFStringToSkString(ref, value); + CFStringToSkString(ref.get(), value); return true; } @@ -2217,15 +2276,12 @@ class SkFontStyleSet_Mac : public SkFontStyleSet { public: SkFontStyleSet_Mac(CTFontDescriptorRef desc) : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, nullptr)) - , fCount(0) { - if (nullptr == fArray) { - fArray = CFArrayCreate(nullptr, nullptr, 0, nullptr); + , fCount(0) + { + if (!fArray) { + fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr)); } - fCount = SkToInt(CFArrayGetCount(fArray)); - } - - virtual ~SkFontStyleSet_Mac() { - CFRelease(fArray); + fCount = SkToInt(CFArrayGetCount(fArray.get())); } int count() override { @@ -2234,9 +2290,9 @@ public: void getStyle(int index, SkFontStyle* style, SkString* name) override { SkASSERT((unsigned)index < (unsigned)fCount); - CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index); + CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index); if (style) { - *style = fontstyle_from_descriptor(desc); + *style = fontstyle_from_descriptor(desc, false); } if (name) { if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) { @@ -2246,8 +2302,8 @@ public: } SkTypeface* createTypeface(int index) override { - SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray)); - CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index); + SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get())); + CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index); return create_from_desc(desc); } @@ -2260,16 +2316,16 @@ public: } private: - CFArrayRef fArray; - int fCount; + UniqueCFRef fArray; + int fCount; CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const { int bestMetric = SK_MaxS32; CTFontDescriptorRef bestDesc = nullptr; for (int i = 0; i < fCount; ++i) { - CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, i); - int metric = compute_metric(pattern, fontstyle_from_descriptor(desc)); + CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i); + int metric = compute_metric(pattern, fontstyle_from_descriptor(desc, false)); if (0 == metric) { return desc; } @@ -2284,35 +2340,42 @@ private: }; class SkFontMgr_Mac : public SkFontMgr { - CFArrayRef fNames; - int fCount; + UniqueCFRef fNames; + int fCount; - CFStringRef stringAt(int index) const { + CFStringRef getFamilyNameAt(int index) const { SkASSERT((unsigned)index < (unsigned)fCount); - return (CFStringRef)CFArrayGetValueAtIndex(fNames, index); + return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index); } static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) { - AutoCFRelease cfAttr( + UniqueCFRef cfAttr( CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); - CFDictionaryAddValue(cfAttr, kCTFontFamilyNameAttribute, cfFamilyName); + CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName); - AutoCFRelease desc( - CTFontDescriptorCreateWithAttributes(cfAttr)); - return new SkFontStyleSet_Mac(desc); + UniqueCFRef desc( + CTFontDescriptorCreateWithAttributes(cfAttr.get())); + return new SkFontStyleSet_Mac(desc.get()); + } + + /** CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we + * provide a wrapper here that will return an empty array if need be. + */ + static UniqueCFRef CopyAvailableFontFamilyNames() { +#ifdef SK_BUILD_FOR_IOS + return UniqueCFRef(CFArrayCreate(nullptr, nullptr, 0, nullptr)); +#else + return UniqueCFRef(CTFontManagerCopyAvailableFontFamilyNames()); +#endif } public: SkFontMgr_Mac() - : fNames(SkCTFontManagerCopyAvailableFontFamilyNames()) - , fCount(fNames ? SkToInt(CFArrayGetCount(fNames)) : 0) {} - - virtual ~SkFontMgr_Mac() { - CFSafeRelease(fNames); - } + : fNames(CopyAvailableFontFamilyNames()) + , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0) {} protected: int onCountFamilies() const override { @@ -2321,7 +2384,7 @@ protected: void onGetFamilyName(int index, SkString* familyName) const override { if ((unsigned)index < (unsigned)fCount) { - CFStringToSkString(this->stringAt(index), familyName); + CFStringToSkString(this->getFamilyNameAt(index), familyName); } else { familyName->reset(); } @@ -2331,26 +2394,26 @@ protected: if ((unsigned)index >= (unsigned)fCount) { return nullptr; } - return CreateSet(this->stringAt(index)); + return CreateSet(this->getFamilyNameAt(index)); } SkFontStyleSet* onMatchFamily(const char familyName[]) const override { - AutoCFRelease cfName(make_CFString(familyName)); - return CreateSet(cfName); + UniqueCFRef cfName = make_CFString(familyName); + return CreateSet(cfName.get()); } - virtual SkTypeface* onMatchFamilyStyle(const char familyName[], - const SkFontStyle& fontStyle) const override { - SkAutoTUnref sset(this->matchFamily(familyName)); + SkTypeface* onMatchFamilyStyle(const char familyName[], + const SkFontStyle& fontStyle) const override { + sk_sp sset(this->matchFamily(familyName)); return sset->matchStyle(fontStyle); } - virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], - const SkFontStyle& style, - const char* bcp47[], int bcp47Count, - SkUnichar character) const override { - AutoCFRelease desc(create_descriptor(familyName, style)); - AutoCFRelease currentFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr)); + SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], + const SkFontStyle& style, + const char* bcp47[], int bcp47Count, + SkUnichar character) const override { + UniqueCFRef desc = create_descriptor(familyName, style); + UniqueCFRef currentFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr)); // kCFStringEncodingUTF32 is BE unless there is a BOM. // Since there is no machine endian option, explicitly state machine endian. @@ -2359,104 +2422,80 @@ protected: #else constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE; #endif - AutoCFRelease string(CFStringCreateWithBytes( + UniqueCFRef string(CFStringCreateWithBytes( kCFAllocatorDefault, reinterpret_cast(&character), sizeof(character), encoding, false)); - CFRange range = CFRangeMake(0, CFStringGetLength(string)); // in UniChar units. - AutoCFRelease fallbackFont(CTFontCreateForString(currentFont, string, range)); - return create_from_CTFontRef(fallbackFont.release(), nullptr, false); + CFRange range = CFRangeMake(0, CFStringGetLength(string.get())); // in UniChar units. + UniqueCFRef fallbackFont( + CTFontCreateForString(currentFont.get(), string.get(), range)); + return create_from_CTFontRef(std::move(fallbackFont), nullptr, false); } - virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, - const SkFontStyle&) const override { + SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, + const SkFontStyle&) const override { return nullptr; } SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override { - AutoCFRelease pr(SkCreateDataProviderFromData(sk_ref_sp(data))); - if (nullptr == pr) { + UniqueCFRef pr(SkCreateDataProviderFromData(sk_ref_sp(data))); + if (!pr) { return nullptr; } - return create_from_dataProvider(pr); + return create_from_dataProvider(std::move(pr), ttcIndex); } SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override { std::unique_ptr stream(bareStream); - AutoCFRelease pr(SkCreateDataProviderFromStream(std::move(stream))); - if (nullptr == pr) { + UniqueCFRef pr(SkCreateDataProviderFromStream(std::move(stream))); + if (!pr) { return nullptr; } - return create_from_dataProvider(pr); + return create_from_dataProvider(std::move(pr), ttcIndex); } - static CFNumberRef get_tag_for_name(CFStringRef name, CFArrayRef ctAxes) { - CFIndex ctAxisCount = CFArrayGetCount(ctAxes); - for (int i = 0; i < ctAxisCount; ++i) { - CFTypeRef ctAxisInfo = CFArrayGetValueAtIndex(ctAxes, i); - if (CFDictionaryGetTypeID() != CFGetTypeID(ctAxisInfo)) { - return nullptr; - } - CFDictionaryRef ctAxisInfoDict = static_cast(ctAxisInfo); - - CFTypeRef ctAxisName = CFDictionaryGetValue(ctAxisInfoDict, - kCTFontVariationAxisNameKey); - if (!ctAxisName || CFGetTypeID(ctAxisName) != CFStringGetTypeID()) { - return nullptr; - } - - if (CFEqual(name, ctAxisName)) { - CFTypeRef tag = CFDictionaryGetValue(ctAxisInfoDict, - kCTFontVariationAxisIdentifierKey); - if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { - return nullptr; - } - return static_cast(tag); - } - } - return nullptr; - } - static CFDictionaryRef get_axes(CGFontRef cg, const FontParameters& params) { - AutoCFRelease cgAxes(CGFontCopyVariationAxes(cg)); - if (!cgAxes) { - return nullptr; - } - CFIndex axisCount = CFArrayGetCount(cgAxes); - - // The CGFont variation data is keyed by name, and lacks the tag. + /** Creates a dictionary suitable for setting the axes on a CGFont. */ + static UniqueCFRef copy_axes(CGFontRef cg, const SkFontArguments& args) { + // The CGFont variation data is keyed by name, but lacks the tag. // The CTFont variation data is keyed by tag, and also has the name. - // We would like to work with CTFont variaitons, but creating a CTFont font with + // We would like to work with CTFont variations, but creating a CTFont font with // CTFont variation dictionary runs into bugs. So use the CTFont variation data // to match names to tags to create the appropriate CGFont. - AutoCFRelease ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr)); - AutoCFRelease ctAxes(CTFontCopyVariationAxes(ct)); - if (!ctAxes || CFArrayGetCount(ctAxes) != axisCount) { + UniqueCFRef ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr)); + // This call always returns nullptr on 10.10 and under. + // When this happens, there is no API to provide the tag. + UniqueCFRef ctAxes(CTFontCopyVariationAxes(ct.get())); + if (!ctAxes) { return nullptr; } + CFIndex axisCount = CFArrayGetCount(ctAxes.get()); - int paramAxisCount; - const FontParameters::Axis* paramAxes = params.getAxes(¶mAxisCount); + const SkFontArguments::VariationPosition position = args.getVariationDesignPosition(); + + UniqueCFRef dict( + CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); - CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); for (int i = 0; i < axisCount; ++i) { - CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes, i); + CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { return nullptr; } CFDictionaryRef axisInfoDict = static_cast(axisInfo); - CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisName); + // The assumption is that values produced by kCTFontVariationAxisNameKey and + // kCGFontVariationAxisName will always be equal. + // If they are ever not, seach the project history for "get_tag_for_name". + CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey); if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) { return nullptr; } - CFNumberRef tagNumber = get_tag_for_name(static_cast(axisName), ctAxes); - if (!tagNumber) { - // Could not find a tag to go with the name of this index. - // This would be a bug in CG/CT. - continue; + CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); + if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { + return nullptr; } + CFNumberRef tagNumber = static_cast(tag); int64_t tagLong; if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { return nullptr; @@ -2464,9 +2503,9 @@ protected: // The variation axes can be set to any value, but cg will effectively pin them. // Pin them here to normalize. - CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMinValue); - CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMaxValue); - CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisDefaultValue); + CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey); + CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey); + CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey); if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || !max || CFGetTypeID(max) != CFNumberGetTypeID() || !def || CFGetTypeID(def) != CFNumberGetTypeID()) @@ -2487,64 +2526,73 @@ protected: } double value = defDouble; - for (int j = 0; j < paramAxisCount; ++j) { - if (paramAxes[j].fTag == tagLong) { - value = SkTPin(SkScalarToDouble(paramAxes[j].fStyleValue),minDouble,maxDouble); + // The position may be over specified. If there are multiple values for a given axis, + // use the last one since that's what css-fonts-4 requires. + for (int j = position.coordinateCount; j --> 0;) { + if (position.coordinates[j].axis == tagLong) { + value = SkTPin(SkScalarToDouble(position.coordinates[j].value), + minDouble, maxDouble); break; } } - CFNumberRef valueNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, - &value); - CFDictionaryAddValue(dict, axisName, valueNumber); - CFRelease(valueNumber); + UniqueCFRef valueNumber( + CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value)); + CFDictionaryAddValue(dict.get(), axisName, valueNumber.get()); } - return dict; + return std::move(dict); } - SkTypeface* onCreateFromStream(SkStreamAsset* bs, const FontParameters& params) const override { + SkTypeface* onCreateFromStream(SkStreamAsset* bs, const SkFontArguments& args) const override { std::unique_ptr s(bs); - AutoCFRelease provider(SkCreateDataProviderFromStream(std::move(s))); - if (nullptr == provider) { + if (args.getCollectionIndex() != 0) { return nullptr; } - AutoCFRelease cg(CGFontCreateWithDataProvider(provider)); - if (nullptr == cg) { + UniqueCFRef provider(SkCreateDataProviderFromStream(std::move(s))); + if (!provider) { + return nullptr; + } + UniqueCFRef cg(CGFontCreateWithDataProvider(provider.get())); + if (!cg) { return nullptr; } - AutoCFRelease cgVariations(get_axes(cg, params)); + UniqueCFRef cgVariations = copy_axes(cg.get(), args); // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was // created from a data provider does not appear to have any ownership of the underlying // data. The original CGFontRef must be kept alive until the copy will no longer be used. - AutoCFRelease cgVariant; + UniqueCFRef cgVariant; if (cgVariations) { - cgVariant.reset(CGFontCreateCopyWithVariations(cg, cgVariations)); + cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.get())); } else { cgVariant.reset(cg.release()); } - AutoCFRelease ct(CTFontCreateWithGraphicsFont(cgVariant, 0, nullptr, nullptr)); + UniqueCFRef ct( + CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, nullptr)); if (!ct) { return nullptr; } - return create_from_CTFontRef(ct.release(), cg.release(), true); + return create_from_CTFontRef(std::move(ct), std::move(cg), true); } - static CFDictionaryRef get_axes(CGFontRef cg, SkFontData* fontData) { - AutoCFRelease cgAxes(CGFontCopyVariationAxes(cg)); + /** Creates a dictionary suitable for setting the axes on a CGFont. */ + static UniqueCFRef copy_axes(CGFontRef cg, SkFontData* fontData) { + UniqueCFRef cgAxes(CGFontCopyVariationAxes(cg)); if (!cgAxes) { return nullptr; } - CFIndex axisCount = CFArrayGetCount(cgAxes); + CFIndex axisCount = CFArrayGetCount(cgAxes.get()); if (0 == axisCount || axisCount != fontData->getAxisCount()) { return nullptr; } - CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + UniqueCFRef dict( + CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + for (int i = 0; i < fontData->getAxisCount(); ++i) { - CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes, i); + CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes.get(), i); if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { return nullptr; } @@ -2574,49 +2622,51 @@ protected: return nullptr; } double value = SkTPin(SkFixedToDouble(fontData->getAxis()[i]), minDouble, maxDouble); - CFNumberRef valueNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, - &value); - - CFDictionaryAddValue(dict, axisName, valueNumber); - CFRelease(valueNumber); + UniqueCFRef valueNumber( + CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value)); + CFDictionaryAddValue(dict.get(), axisName, valueNumber.get()); } - return dict; + return std::move(dict); } SkTypeface* onCreateFromFontData(std::unique_ptr fontData) const override { - AutoCFRelease provider( - SkCreateDataProviderFromStream(fontData->detachStream())); - if (nullptr == provider) { + if (fontData->getIndex() != 0) { return nullptr; } - AutoCFRelease cg(CGFontCreateWithDataProvider(provider)); - if (nullptr == cg) { + UniqueCFRef provider( + SkCreateDataProviderFromStream(fontData->detachStream())); + if (!provider) { + return nullptr; + } + UniqueCFRef cg(CGFontCreateWithDataProvider(provider.get())); + if (!cg) { return nullptr; } - AutoCFRelease cgVariations(get_axes(cg, fontData.get())); + UniqueCFRef cgVariations = copy_axes(cg.get(), fontData.get()); // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was // created from a data provider does not appear to have any ownership of the underlying // data. The original CGFontRef must be kept alive until the copy will no longer be used. - AutoCFRelease cgVariant; + UniqueCFRef cgVariant; if (cgVariations) { - cgVariant.reset(CGFontCreateCopyWithVariations(cg, cgVariations)); + cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.get())); } else { cgVariant.reset(cg.release()); } - AutoCFRelease ct(CTFontCreateWithGraphicsFont(cgVariant, 0, nullptr, nullptr)); + UniqueCFRef ct( + CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, nullptr)); if (!ct) { return nullptr; } - return create_from_CTFontRef(ct.release(), cg.release(), true); + return create_from_CTFontRef(std::move(ct), std::move(cg), true); } SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { - AutoCFRelease pr(CGDataProviderCreateWithFilename(path)); - if (nullptr == pr) { + UniqueCFRef pr(CGDataProviderCreateWithFilename(path)); + if (!pr) { return nullptr; } - return create_from_dataProvider(pr); + return create_from_dataProvider(std::move(pr), ttcIndex); } SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override { @@ -2624,21 +2674,23 @@ protected: familyName = map_css_names(familyName); } - if (!familyName || !*familyName) { - familyName = FONT_DEFAULT_NAME; - } - SkTypeface* face = create_from_name(familyName, style); if (face) { return face; } - return SkSafeRef(GetDefaultFace()); + static SkTypeface* gDefaultFace; + static SkOnce lookupDefault; + static const char FONT_DEFAULT_NAME[] = "Lucida Sans"; + lookupDefault([]{ + gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()); + }); + return SkSafeRef(gDefaultFace); } }; /////////////////////////////////////////////////////////////////////////////// -SkFontMgr* SkFontMgr::Factory() { return new SkFontMgr_Mac; } +sk_sp SkFontMgr::Factory() { return sk_make_sp(); } #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) diff --git a/gfx/skia/skia/src/ports/SkFontHost_win.cpp b/gfx/skia/skia/src/ports/SkFontHost_win.cpp index c1013d767e0e..b9148027ab7f 100644 --- a/gfx/skia/skia/src/ports/SkFontHost_win.cpp +++ b/gfx/skia/skia/src/ports/SkFontHost_win.cpp @@ -16,6 +16,7 @@ #include "SkFontDescriptor.h" #include "SkGlyph.h" #include "SkHRESULT.h" +#include "SkMakeUnique.h" #include "SkMaskGamma.h" #include "SkMatrix22.h" #include "SkOTTable_maxp.h" @@ -262,15 +263,19 @@ protected: SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( PerGlyphInfo, const uint32_t*, uint32_t) const override; void onGetFontDescriptor(SkFontDescriptor*, bool*) const override; - virtual int onCharsToGlyphs(const void* chars, Encoding encoding, - uint16_t glyphs[], int glyphCount) const override; + int onCharsToGlyphs(const void* chars, Encoding encoding, + uint16_t glyphs[], int glyphCount) const override; int onCountGlyphs() const override; int onGetUPEM() const override; void onGetFamilyName(SkString* familyName) const override; SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override + { + return -1; + } int onGetTableTags(SkFontTableTag tags[]) const override; - virtual size_t onGetTableData(SkFontTableTag, size_t offset, - size_t length, void* data) const override; + size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override; }; class FontMemResourceTypeface : public LogFontTypeface { @@ -375,7 +380,7 @@ static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount, return; } - SkAutoTDeleteArray glyphSetBuffer(new BYTE[glyphSetBufferSize]); + std::unique_ptr glyphSetBuffer(new BYTE[glyphSetBufferSize]); GLYPHSET* glyphSet = reinterpret_cast(glyphSetBuffer.get()); if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) { @@ -543,7 +548,9 @@ const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, class SkScalerContext_GDI : public SkScalerContext { public: - SkScalerContext_GDI(SkTypeface*, const SkScalerContextEffects&, const SkDescriptor* desc); + SkScalerContext_GDI(sk_sp, + const SkScalerContextEffects&, + const SkDescriptor* desc); virtual ~SkScalerContext_GDI(); // Returns true if the constructor was able to complete all of its @@ -556,11 +563,11 @@ protected: void generateAdvance(SkGlyph* glyph) override; void generateMetrics(SkGlyph* glyph) override; void generateImage(const SkGlyph& glyph) override; - void generatePath(const SkGlyph& glyph, SkPath* path) override; + void generatePath(SkGlyphID glyph, SkPath* path) override; void generateFontMetrics(SkPaint::FontMetrics*) override; private: - DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags, + DWORD getGDIGlyphPath(SkGlyphID glyph, UINT flags, SkAutoSTMalloc* glyphbuf); HDCOffscreen fOffscreen; @@ -613,17 +620,17 @@ static BYTE compute_quality(const SkScalerContext::Rec& rec) { } } -SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface, +SkScalerContext_GDI::SkScalerContext_GDI(sk_sp rawTypeface, const SkScalerContextEffects& effects, const SkDescriptor* desc) - : SkScalerContext(rawTypeface, effects, desc) + : SkScalerContext(std::move(rawTypeface), effects, desc) , fDDC(0) , fSavefont(0) , fFont(0) , fSC(0) , fGlyphCount(-1) { - LogFontTypeface* typeface = reinterpret_cast(rawTypeface); + LogFontTypeface* typeface = static_cast(this->getTypeface()); fDDC = ::CreateCompatibleDC(nullptr); if (!fDDC) { @@ -1015,7 +1022,7 @@ void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* metrics) { metrics->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize); metrics->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition); - metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; + metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag; metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; metrics->fXHeight = SkIntToScalar(otm.otmsXHeight); @@ -1599,22 +1606,22 @@ static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD return true; } -DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags, - SkAutoSTMalloc* glyphbuf) +DWORD SkScalerContext_GDI::getGDIGlyphPath(SkGlyphID glyph, UINT flags, + SkAutoSTMalloc* glyphbuf) { GLYPHMETRICS gm; - DWORD total_size = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22); + DWORD total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22); // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0. // It has been verified that this does not involve a buffer overrun. if (GDI_ERROR == total_size || total_size > BUFFERSIZE) { // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible. // When the data is not accessable GetGlyphOutlineW fails rather quickly, // so just try to get the size. If that fails then ensure the data is accessible. - total_size = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, 0, nullptr, &fMat22); + total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, 0, nullptr, &fMat22); if (GDI_ERROR == total_size) { LogFontTypeface::EnsureAccessible(this->getTypeface()); - total_size = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, 0, nullptr, &fMat22); + total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, 0, nullptr, &fMat22); if (GDI_ERROR == total_size) { // GetGlyphOutlineW is known to fail for some characters, such as spaces. // In these cases, just return that the glyph does not have a shape. @@ -1624,10 +1631,10 @@ DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags, glyphbuf->reset(total_size); - DWORD ret = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, total_size, glyphbuf->get(), &fMat22); + DWORD ret = GetGlyphOutlineW(fDDC, glyph, flags, &gm, total_size, glyphbuf->get(), &fMat22); if (GDI_ERROR == ret) { LogFontTypeface::EnsureAccessible(this->getTypeface()); - ret = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, total_size, glyphbuf->get(), &fMat22); + ret = GetGlyphOutlineW(fDDC, glyph, flags, &gm, total_size, glyphbuf->get(), &fMat22); if (GDI_ERROR == ret) { SkASSERT(false); return 0; @@ -1637,7 +1644,7 @@ DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags, return total_size; } -void SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path) { +void SkScalerContext_GDI::generatePath(SkGlyphID glyph, SkPath* path) { SkASSERT(path); SkASSERT(fDDC); @@ -1767,8 +1774,6 @@ SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics( glyphCount = calculateGlyphCount(hdc, fLogFont); info = new SkAdvancedTypefaceMetrics; - info->fEmSize = otm.otmEMSquare; - info->fLastGlyphID = SkToU16(glyphCount - 1); tchar_to_skstring(lf.lfFaceName, &info->fFontName); // If bit 1 is set, the font may not be embedded in a document. // If bit 1 is clear, the font can be embedded. @@ -2267,13 +2272,12 @@ size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset, SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkScalerContextEffects& effects, const SkDescriptor* desc) const { - SkScalerContext_GDI* ctx = new SkScalerContext_GDI(const_cast(this), - effects, desc); + auto ctx = skstd::make_unique( + sk_ref_sp(const_cast(this)), effects, desc); if (!ctx->isValid()) { - delete ctx; - ctx = nullptr; + return nullptr; } - return ctx; + return ctx.release(); } void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const { @@ -2446,7 +2450,7 @@ protected: virtual SkTypeface* onMatchFamilyStyle(const char familyName[], const SkFontStyle& fontstyle) const override { // could be in base impl - SkAutoTUnref sset(this->matchFamily(familyName)); + sk_sp sset(this->matchFamily(familyName)); return sset->matchStyle(fontstyle); } @@ -2465,18 +2469,21 @@ protected: } SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override { - SkAutoTDelete stream(bareStream); - return create_from_stream(stream); + std::unique_ptr stream(bareStream); + if (ttcIndex != 0) { + return nullptr; + } + return create_from_stream(stream.get()); } SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override { // could be in base impl - return this->createFromStream(new SkMemoryStream(sk_ref_sp(data))); + return this->createFromStream(new SkMemoryStream(sk_ref_sp(data)), ttcIndex); } SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { // could be in base impl - return this->createFromStream(SkStream::MakeFromFile(path).release()); + return this->createFromStream(SkStream::MakeFromFile(path).release(), ttcIndex); } SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override { @@ -2498,6 +2505,6 @@ private: /////////////////////////////////////////////////////////////////////////////// -SkFontMgr* SkFontMgr_New_GDI() { return new SkFontMgrGDI; } +sk_sp SkFontMgr_New_GDI() { return sk_make_sp(); } #endif//defined(SK_BUILD_FOR_WIN32) diff --git a/gfx/skia/skia/src/ports/SkFontMgr_FontConfigInterface.cpp b/gfx/skia/skia/src/ports/SkFontMgr_FontConfigInterface.cpp index d4c7569009e4..626471000839 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_FontConfigInterface.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_FontConfigInterface.cpp @@ -113,8 +113,8 @@ private: const char* getCategory() const override { return "request_cache"; } SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; } - SkAutoTDelete fRequest; - SkAutoTUnref fFace; + std::unique_ptr fRequest; + sk_sp fFace; }; SkResourceCache fCachedResults; @@ -133,7 +133,7 @@ public: const Result& result = static_cast(rec); SkTypeface** face = static_cast(context); - *face = result.fFace; + *face = result.fFace.get(); return true; }, &face); return SkSafeRef(face); @@ -154,7 +154,6 @@ static bool find_by_FontIdentity(SkTypeface* cachedTypeface, void* ctx) { class SkFontMgr_FCI : public SkFontMgr { sk_sp fFCI; - sk_sp fFamilyNames; SkTypeface_FreeType::Scanner fScanner; mutable SkMutex fMutex; @@ -168,21 +167,21 @@ class SkFontMgr_FCI : public SkFontMgr { public: SkFontMgr_FCI(sk_sp fci) : fFCI(std::move(fci)) - , fFamilyNames(fFCI->getFamilyNames()) , fCache(kMaxSize) {} protected: int onCountFamilies() const override { - return fFamilyNames->count(); + return 0; } void onGetFamilyName(int index, SkString* familyName) const override { - familyName->set(fFamilyNames->atStr(index)); + SkFAIL("Not implemented."); } SkFontStyleSet* onCreateStyleSet(int index) const override { - return this->onMatchFamily(fFamilyNames->atStr(index)); + SkFAIL("Not implemented."); + return nullptr; } SkFontStyleSet* onMatchFamily(const char familyName[]) const override { @@ -212,17 +211,18 @@ protected: } // TODO should the caller give us the style or should we get it from freetype? + SkString name; SkFontStyle style; bool isFixedPitch = false; - if (!fScanner.scanFont(stream.get(), 0, nullptr, &style, &isFixedPitch, nullptr)) { + if (!fScanner.scanFont(stream.get(), 0, &name, &style, &isFixedPitch, nullptr)) { return nullptr; } auto fontData = skstd::make_unique(std::move(stream), ttcIndex, nullptr, 0); - return SkTypeface_FCI::Create(std::move(fontData), style, isFixedPitch); + return SkTypeface_FCI::Create(std::move(fontData), std::move(name), style, isFixedPitch); } - SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override { + SkTypeface* onCreateFromStream(SkStreamAsset* s, const SkFontArguments& args) const override { using Scanner = SkTypeface_FreeType::Scanner; std::unique_ptr stream(s); const size_t length = stream->getLength(); @@ -237,22 +237,21 @@ protected: SkFontStyle style; SkString name; Scanner::AxisDefinitions axisDefinitions; - if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(), + if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(), &name, &style, &isFixedPitch, &axisDefinitions)) { return nullptr; } - int paramAxisCount; - const FontParameters::Axis* paramAxes = params.getAxes(¶mAxisCount); SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); - Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name); + Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(), + axisValues, name); auto fontData = skstd::make_unique(std::move(stream), - params.getCollectionIndex(), + args.getCollectionIndex(), axisValues.get(), axisDefinitions.count()); - return SkTypeface_FCI::Create(std::move(fontData), style, isFixedPitch); + return SkTypeface_FCI::Create(std::move(fontData), std::move(name), style, isFixedPitch); } SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { @@ -267,8 +266,8 @@ protected: // Check if this request is already in the request cache. using Request = SkFontRequestCache::Request; - SkAutoTDelete request(Request::Create(requestedFamilyName, requestedStyle)); - SkTypeface* face = fCache.findAndRef(request); + std::unique_ptr request(Request::Create(requestedFamilyName, requestedStyle)); + SkTypeface* face = fCache.findAndRef(request.get()); if (face) { return face; } @@ -285,7 +284,7 @@ protected: // Check if a typeface with this FontIdentity is already in the FontIdentity cache. face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); if (!face) { - face = SkTypeface_FCI::Create(fFCI, identity, outFamilyName, outStyle); + face = SkTypeface_FCI::Create(fFCI, identity, std::move(outFamilyName), outStyle); // Add this FontIdentity to the FontIdentity cache. fTFCache.add(face); } @@ -296,7 +295,7 @@ protected: } }; -SK_API SkFontMgr* SkFontMgr_New_FCI(sk_sp fci) { +SK_API sk_sp SkFontMgr_New_FCI(sk_sp fci) { SkASSERT(fci); - return new SkFontMgr_FCI(std::move(fci)); + return sk_make_sp(std::move(fci)); } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_FontConfigInterface_factory.cpp b/gfx/skia/skia/src/ports/SkFontMgr_FontConfigInterface_factory.cpp index b2bb74ee1d62..a4ee13841a5d 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_FontConfigInterface_factory.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_FontConfigInterface_factory.cpp @@ -9,7 +9,7 @@ #include "SkFontMgr.h" #include "SkFontMgr_FontConfigInterface.h" -SkFontMgr* SkFontMgr::Factory() { +sk_sp SkFontMgr::Factory() { sk_sp fci(SkFontConfigInterface::RefGlobal()); if (!fci) { return nullptr; diff --git a/gfx/skia/skia/src/ports/SkFontMgr_android.cpp b/gfx/skia/skia/src/ports/SkFontMgr_android.cpp index 3a84ecad8b18..a180215e8848 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_android.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_android.cpp @@ -201,8 +201,11 @@ public: } SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); - Scanner::computeAxisValues(axisDefinitions, - fontFile.fAxes.begin(), fontFile.fAxes.count(), + SkFontArguments::VariationPosition position = { + fontFile.fVariationDesignPosition.begin(), + fontFile.fVariationDesignPosition.count() + }; + Scanner::computeAxisValues(axisDefinitions, position, axisValues, familyName); fStyles.push_back().reset(new SkTypeface_AndroidSystem( @@ -237,7 +240,7 @@ public: } private: - SkTArray, true> fStyles; + SkTArray, true> fStyles; friend struct NameToFamily; friend class SkFontMgr_Android; @@ -323,7 +326,7 @@ protected: virtual SkTypeface* onMatchFamilyStyle(const char familyName[], const SkFontStyle& style) const override { - SkAutoTUnref sset(this->matchFamily(familyName)); + sk_sp sset(this->matchFamily(familyName)); return sset->matchStyle(style); } @@ -331,7 +334,7 @@ protected: const SkFontStyle& style) const override { for (int i = 0; i < fStyleSets.count(); ++i) { for (int j = 0; j < fStyleSets[i]->fStyles.count(); ++j) { - if (fStyleSets[i]->fStyles[j] == typeface) { + if (fStyleSets[i]->fStyles[j].get() == typeface) { return fStyleSets[i]->matchStyle(style); } } @@ -428,25 +431,24 @@ protected: return new SkTypeface_AndroidStream(std::move(data), style, isFixedPitch, name); } - SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override { + SkTypeface* onCreateFromStream(SkStreamAsset* s, const SkFontArguments& args) const override { using Scanner = SkTypeface_FreeType::Scanner; std::unique_ptr stream(s); bool isFixedPitch; SkFontStyle style; SkString name; Scanner::AxisDefinitions axisDefinitions; - if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(), + if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(), &name, &style, &isFixedPitch, &axisDefinitions)) { return nullptr; } - int paramAxisCount; - const FontParameters::Axis* paramAxes = params.getAxes(¶mAxisCount); SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); - Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name); + Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(), + axisValues, name); - auto data = skstd::make_unique(std::move(stream), params.getCollectionIndex(), + auto data = skstd::make_unique(std::move(stream), args.getCollectionIndex(), axisValues.get(), axisDefinitions.count()); return new SkTypeface_AndroidStream(std::move(data), style, isFixedPitch, name); } @@ -535,7 +537,8 @@ static char const * const gSystemFontUseStrings[] = { "OnlyCustom", "PreferCustom", "PreferSystem" }; #endif -SkFontMgr* SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom) { + +sk_sp SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom) { if (custom) { SkASSERT(0 <= custom->fSystemFontUse); SkASSERT(custom->fSystemFontUse < SK_ARRAY_COUNT(gSystemFontUseStrings)); @@ -545,6 +548,5 @@ SkFontMgr* SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom) { custom->fFontsXml, custom->fFallbackFontsXml)); } - - return new SkFontMgr_Android(custom); + return sk_make_sp(custom); } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_android_factory.cpp b/gfx/skia/skia/src/ports/SkFontMgr_android_factory.cpp index ce39b2cf97df..88e055840b57 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_android_factory.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_android_factory.cpp @@ -10,38 +10,7 @@ #include "SkFontMgr.h" #include "SkFontMgr_android.h" -// For test only. -static const char* gTestFontsXml = nullptr; -static const char* gTestFallbackFontsXml = nullptr; -static const char* gTestBasePath = nullptr; - -void SkUseTestFontConfigFile(const char* fontsXml, const char* fallbackFontsXml, - const char* basePath) -{ - gTestFontsXml = fontsXml; - gTestFallbackFontsXml = fallbackFontsXml; - gTestBasePath = basePath; - SkASSERT(gTestFontsXml); - SkASSERT(gTestFallbackFontsXml); - SkASSERT(gTestBasePath); - SkDEBUGF(("Test BasePath: %s Fonts: %s FallbackFonts: %s\n", - gTestBasePath, gTestFontsXml, gTestFallbackFontsXml)); -} - -SkFontMgr* SkFontMgr::Factory() { - // These globals exist so that Chromium can override the environment. - // TODO: these globals need to be removed, and Chromium use SkFontMgr_New_Android instead. - if ((gTestFontsXml || gTestFallbackFontsXml) && gTestBasePath) { - SkFontMgr_Android_CustomFonts custom = { - SkFontMgr_Android_CustomFonts::kOnlyCustom, - gTestBasePath, - gTestFontsXml, - gTestFallbackFontsXml, - false /* fIsolated */ - }; - return SkFontMgr_New_Android(&custom); - } - +sk_sp SkFontMgr::Factory() { return SkFontMgr_New_Android(nullptr); } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_android_parser.cpp b/gfx/skia/skia/src/ports/SkFontMgr_android_parser.cpp index 306c6ffdb73a..a68f7913877c 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_android_parser.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_android_parser.cpp @@ -10,6 +10,7 @@ #include "SkFixed.h" #include "SkFontMgr.h" #include "SkFontMgr_android_parser.h" +#include "SkMalloc.h" #include "SkOSFile.h" #include "SkStream.h" #include "SkTDArray.h" @@ -100,18 +101,18 @@ struct FamilyData { , fHandler(&topLevelHandler, 1) { } - XML_Parser fParser; // The expat parser doing the work, owned by caller - SkTDArray& fFamilies; // The array to append families, owned by caller - SkAutoTDelete fCurrentFamily; // The family being created, owned by this - FontFileInfo* fCurrentFontInfo; // The fontInfo being created, owned by fCurrentFamily - int fVersion; // The version of the file parsed. - const SkString& fBasePath; // The current base path. - const bool fIsFallback; // Indicates the file being parsed is a fallback file - const char* fFilename; // The name of the file currently being parsed. + XML_Parser fParser; // The expat parser doing the work, owned by caller + SkTDArray& fFamilies; // The array to append families, owned by caller + std::unique_ptr fCurrentFamily; // The family being created, owned by this + FontFileInfo* fCurrentFontInfo; // The info being created, owned by fCurrentFamily + int fVersion; // The version of the file parsed. + const SkString& fBasePath; // The current base path. + const bool fIsFallback; // The file being parsed is a fallback file + const char* fFilename; // The name of the file currently being parsed. - int fDepth; // The current element depth of the parse. - int fSkip; // The depth to stop skipping, 0 if not skipping. - SkTDArray fHandler; // The stack of current tag handlers. + int fDepth; // The current element depth of the parse. + int fSkip; // The depth to stop skipping, 0 if not skipping. + SkTDArray fHandler; // The stack of current tag handlers. }; static bool memeq(const char* s1, const char* s2, size_t n1, size_t n2) { @@ -167,8 +168,8 @@ static const TagHandler axisHandler = { if (valueLen == 4) { axisTag = SkSetFourByteTag(value[0], value[1], value[2], value[3]); axisTagIsValid = true; - for (int j = 0; j < file.fAxes.count() - 1; ++j) { - if (file.fAxes[j].fTag == axisTag) { + for (int j = 0; j < file.fVariationDesignPosition.count() - 1; ++j) { + if (file.fVariationDesignPosition[j].axis == axisTag) { axisTagIsValid = false; SK_FONTCONFIGPARSER_WARNING("'%c%c%c%c' axis specified more than once", (axisTag >> 24) & 0xFF, @@ -189,9 +190,9 @@ static const TagHandler axisHandler = { } } if (axisTagIsValid && axisStyleValueIsValid) { - SkFontMgr::FontParameters::Axis& axis = file.fAxes.push_back(); - axis.fTag = axisTag; - axis.fStyleValue = SkFixedToScalar(axisStyleValue); + auto& coordinate = file.fVariationDesignPosition.push_back(); + coordinate.axis = axisTag; + coordinate.value = SkFixedToScalar(axisStyleValue); } }, /*end*/nullptr, diff --git a/gfx/skia/skia/src/ports/SkFontMgr_android_parser.h b/gfx/skia/skia/src/ports/SkFontMgr_android_parser.h index efd8144f1463..75b31c300ee6 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_android_parser.h +++ b/gfx/skia/skia/src/ports/SkFontMgr_android_parser.h @@ -73,7 +73,7 @@ struct FontFileInfo { int fIndex; int fWeight; enum class Style { kAuto, kNormal, kItalic } fStyle; - SkTArray fAxes; + SkTArray fVariationDesignPosition; }; /** diff --git a/gfx/skia/skia/src/ports/SkFontMgr_custom.cpp b/gfx/skia/skia/src/ports/SkFontMgr_custom.cpp index 9a8aa4946fcb..91a590827c0d 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_custom.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_custom.cpp @@ -5,20 +5,19 @@ * found in the LICENSE file. */ +#include "SkFontArguments.h" #include "SkFontDescriptor.h" #include "SkFontHost_FreeType_common.h" #include "SkFontMgr.h" #include "SkFontMgr_custom.h" #include "SkFontStyle.h" #include "SkMakeUnique.h" -#include "SkOSFile.h" #include "SkRefCnt.h" #include "SkStream.h" #include "SkString.h" #include "SkTArray.h" #include "SkTemplates.h" #include "SkTypeface.h" -#include "SkTypefaceCache.h" #include "SkTypes.h" #include @@ -26,497 +25,234 @@ class SkData; -/** The base SkTypeface implementation for the custom font manager. */ -class SkTypeface_Custom : public SkTypeface_FreeType { -public: - SkTypeface_Custom(const SkFontStyle& style, bool isFixedPitch, - bool sysFont, const SkString familyName, int index) - : INHERITED(style, isFixedPitch) - , fIsSysFont(sysFont), fFamilyName(familyName), fIndex(index) - { } +SkTypeface_Custom::SkTypeface_Custom(const SkFontStyle& style, bool isFixedPitch, + bool sysFont, const SkString familyName, int index) + : INHERITED(style, isFixedPitch) + , fIsSysFont(sysFont), fFamilyName(familyName), fIndex(index) +{ } - bool isSysFont() const { return fIsSysFont; } +bool SkTypeface_Custom::isSysFont() const { return fIsSysFont; } -protected: - void onGetFamilyName(SkString* familyName) const override { - *familyName = fFamilyName; - } +void SkTypeface_Custom::onGetFamilyName(SkString* familyName) const { + *familyName = fFamilyName; +} - void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override { - desc->setFamilyName(fFamilyName.c_str()); - desc->setStyle(this->fontStyle()); - *isLocal = !this->isSysFont(); - } +void SkTypeface_Custom::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { + desc->setFamilyName(fFamilyName.c_str()); + desc->setStyle(this->fontStyle()); + *isLocal = !this->isSysFont(); +} - int getIndex() const { return fIndex; } +int SkTypeface_Custom::getIndex() const { return fIndex; } -private: - const bool fIsSysFont; - const SkString fFamilyName; - const int fIndex; - typedef SkTypeface_FreeType INHERITED; -}; +SkTypeface_Empty::SkTypeface_Empty() : INHERITED(SkFontStyle(), false, true, SkString(), 0) {} -/** The empty SkTypeface implementation for the custom font manager. - * Used as the last resort fallback typeface. - */ -class SkTypeface_Empty : public SkTypeface_Custom { -public: - SkTypeface_Empty() : INHERITED(SkFontStyle(), false, true, SkString(), 0) {} +SkStreamAsset* SkTypeface_Empty::onOpenStream(int*) const { return nullptr; } -protected: - SkStreamAsset* onOpenStream(int*) const override { return nullptr; } -private: - typedef SkTypeface_Custom INHERITED; -}; +SkTypeface_Stream::SkTypeface_Stream(std::unique_ptr fontData, + const SkFontStyle& style, bool isFixedPitch, bool sysFont, + const SkString familyName) + : INHERITED(style, isFixedPitch, sysFont, familyName, fontData->getIndex()) + , fData(std::move(fontData)) +{ } -/** The stream SkTypeface implementation for the custom font manager. */ -class SkTypeface_Stream : public SkTypeface_Custom { -public: - SkTypeface_Stream(std::unique_ptr fontData, - const SkFontStyle& style, bool isFixedPitch, bool sysFont, - const SkString familyName) - : INHERITED(style, isFixedPitch, sysFont, familyName, fontData->getIndex()) - , fData(std::move(fontData)) - { } +SkStreamAsset* SkTypeface_Stream::onOpenStream(int* ttcIndex) const { + *ttcIndex = fData->getIndex(); + return fData->getStream()->duplicate(); +} -protected: - SkStreamAsset* onOpenStream(int* ttcIndex) const override { - *ttcIndex = fData->getIndex(); - return fData->getStream()->duplicate(); - } +std::unique_ptr SkTypeface_Stream::onMakeFontData() const { + return skstd::make_unique(*fData); +} - std::unique_ptr onMakeFontData() const override { - return skstd::make_unique(*fData); - } -private: - const std::unique_ptr fData; +SkTypeface_File::SkTypeface_File(const SkFontStyle& style, bool isFixedPitch, bool sysFont, + const SkString familyName, const char path[], int index) + : INHERITED(style, isFixedPitch, sysFont, familyName, index) + , fPath(path) +{ } - typedef SkTypeface_Custom INHERITED; -}; - -/** The file SkTypeface implementation for the custom font manager. */ -class SkTypeface_File : public SkTypeface_Custom { -public: - SkTypeface_File(const SkFontStyle& style, bool isFixedPitch, bool sysFont, - const SkString familyName, const char path[], int index) - : INHERITED(style, isFixedPitch, sysFont, familyName, index) - , fPath(path) - { } - -protected: - SkStreamAsset* onOpenStream(int* ttcIndex) const override { - *ttcIndex = this->getIndex(); - return SkStream::MakeFromFile(fPath.c_str()).release(); - } - -private: - SkString fPath; - - typedef SkTypeface_Custom INHERITED; -}; +SkStreamAsset* SkTypeface_File::onOpenStream(int* ttcIndex) const { + *ttcIndex = this->getIndex(); + return SkStream::MakeFromFile(fPath.c_str()).release(); +} /////////////////////////////////////////////////////////////////////////////// -/** - * SkFontStyleSet_Custom - * - * This class is used by SkFontMgr_Custom to hold SkTypeface_Custom families. - */ -class SkFontStyleSet_Custom : public SkFontStyleSet { -public: - explicit SkFontStyleSet_Custom(const SkString familyName) : fFamilyName(familyName) { } +SkFontStyleSet_Custom::SkFontStyleSet_Custom(const SkString familyName) : fFamilyName(familyName) {} - /** Should only be called during the inital build phase. */ - void appendTypeface(sk_sp typeface) { - fStyles.emplace_back(std::move(typeface)); +void SkFontStyleSet_Custom::appendTypeface(sk_sp typeface) { + fStyles.emplace_back(std::move(typeface)); +} + +int SkFontStyleSet_Custom::count() { + return fStyles.count(); +} + +void SkFontStyleSet_Custom::getStyle(int index, SkFontStyle* style, SkString* name) { + SkASSERT(index < fStyles.count()); + if (style) { + *style = fStyles[index]->fontStyle(); } - - int count() override { - return fStyles.count(); + if (name) { + name->reset(); } +} - void getStyle(int index, SkFontStyle* style, SkString* name) override { - SkASSERT(index < fStyles.count()); - if (style) { - *style = fStyles[index]->fontStyle(); - } - if (name) { - name->reset(); - } - } +SkTypeface* SkFontStyleSet_Custom::createTypeface(int index) { + SkASSERT(index < fStyles.count()); + return SkRef(fStyles[index].get()); +} - SkTypeface* createTypeface(int index) override { - SkASSERT(index < fStyles.count()); - return SkRef(fStyles[index].get()); - } +SkTypeface* SkFontStyleSet_Custom::matchStyle(const SkFontStyle& pattern) { + return this->matchStyleCSS3(pattern); +} - SkTypeface* matchStyle(const SkFontStyle& pattern) override { - return this->matchStyleCSS3(pattern); - } +SkString SkFontStyleSet_Custom::getFamilyName() { return fFamilyName; } - SkString getFamilyName() { return fFamilyName; } -private: - SkTArray> fStyles; - SkString fFamilyName; +SkFontMgr_Custom::SkFontMgr_Custom(const SystemFontLoader& loader) : fDefaultFamily(nullptr) { + loader.loadSystemFonts(fScanner, &fFamilies); - friend class SkFontMgr_Custom; -}; - -/** - * SkFontMgr_Custom - * - * This class is essentially a collection of SkFontStyleSet_Custom, - * one SkFontStyleSet_Custom for each family. This class may be modified - * to load fonts from any source by changing the initialization. - */ -class SkFontMgr_Custom : public SkFontMgr { -public: - typedef SkTArray> Families; - class SystemFontLoader { - public: - virtual ~SystemFontLoader() { } - virtual void loadSystemFonts(const SkTypeface_FreeType::Scanner&, Families*) const = 0; + // Try to pick a default font. + static const char* defaultNames[] = { + "Arial", "Verdana", "Times New Roman", "Droid Sans", nullptr }; - explicit SkFontMgr_Custom(const SystemFontLoader& loader) : fDefaultFamily(nullptr) { - loader.loadSystemFonts(fScanner, &fFamilies); - - // Try to pick a default font. - static const char* defaultNames[] = { - "Arial", "Verdana", "Times New Roman", "Droid Sans", nullptr - }; - for (size_t i = 0; i < SK_ARRAY_COUNT(defaultNames); ++i) { - sk_sp set(this->onMatchFamily(defaultNames[i])); - if (nullptr == set) { - continue; - } - - sk_sp tf(set->matchStyle(SkFontStyle(SkFontStyle::kNormal_Weight, - SkFontStyle::kNormal_Width, - SkFontStyle::kUpright_Slant))); - if (nullptr == tf) { - continue; - } - - fDefaultFamily = set.get(); - break; - } - if (nullptr == fDefaultFamily) { - fDefaultFamily = fFamilies[0].get(); - } - } - -protected: - int onCountFamilies() const override { - return fFamilies.count(); - } - - void onGetFamilyName(int index, SkString* familyName) const override { - SkASSERT(index < fFamilies.count()); - familyName->set(fFamilies[index]->getFamilyName()); - } - - SkFontStyleSet_Custom* onCreateStyleSet(int index) const override { - SkASSERT(index < fFamilies.count()); - return SkRef(fFamilies[index].get()); - } - - SkFontStyleSet_Custom* onMatchFamily(const char familyName[]) const override { - for (int i = 0; i < fFamilies.count(); ++i) { - if (fFamilies[i]->getFamilyName().equals(familyName)) { - return SkRef(fFamilies[i].get()); - } - } - return nullptr; - } - - SkTypeface* onMatchFamilyStyle(const char familyName[], - const SkFontStyle& fontStyle) const override - { - SkAutoTUnref sset(this->matchFamily(familyName)); - return sset->matchStyle(fontStyle); - } - - SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&, - const char* bcp47[], int bcp47Count, - SkUnichar character) const override - { - return nullptr; - } - - SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, - const SkFontStyle& fontStyle) const override - { - for (int i = 0; i < fFamilies.count(); ++i) { - for (int j = 0; j < fFamilies[i]->fStyles.count(); ++j) { - if (fFamilies[i]->fStyles[j].get() == familyMember) { - return fFamilies[i]->matchStyle(fontStyle); - } - } - } - return nullptr; - } - - SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override { - return this->createFromStream(new SkMemoryStream(sk_ref_sp(data)), ttcIndex); - } - - SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override { - return this->createFromStream(bareStream, FontParameters().setCollectionIndex(ttcIndex)); - } - - SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override { - using Scanner = SkTypeface_FreeType::Scanner; - std::unique_ptr stream(s); - bool isFixedPitch; - SkFontStyle style; - SkString name; - Scanner::AxisDefinitions axisDefinitions; - if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(), - &name, &style, &isFixedPitch, &axisDefinitions)) - { - return nullptr; - } - - int paramAxisCount; - const FontParameters::Axis* paramAxes = params.getAxes(¶mAxisCount); - SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); - Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name); - - auto data = skstd::make_unique(std::move(stream), params.getCollectionIndex(), - axisValues.get(), axisDefinitions.count()); - return new SkTypeface_Stream(std::move(data), style, isFixedPitch, false, name); - } - - SkTypeface* onCreateFromFontData(std::unique_ptr data) const override { - bool isFixedPitch; - SkFontStyle style; - SkString name; - if (!fScanner.scanFont(data->getStream(), data->getIndex(), - &name, &style, &isFixedPitch, nullptr)) - { - return nullptr; - } - return new SkTypeface_Stream(std::move(data), style, isFixedPitch, false, name); - } - - SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { - std::unique_ptr stream = SkStream::MakeFromFile(path); - return stream.get() ? this->createFromStream(stream.release(), ttcIndex) : nullptr; - } - - SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override { - SkTypeface* tf = nullptr; - - if (familyName) { - tf = this->onMatchFamilyStyle(familyName, style); + for (size_t i = 0; i < SK_ARRAY_COUNT(defaultNames); ++i) { + sk_sp set(this->onMatchFamily(defaultNames[i])); + if (nullptr == set) { + continue; } + sk_sp tf(set->matchStyle(SkFontStyle(SkFontStyle::kNormal_Weight, + SkFontStyle::kNormal_Width, + SkFontStyle::kUpright_Slant))); if (nullptr == tf) { - tf = fDefaultFamily->matchStyle(style); + continue; } - return tf; + fDefaultFamily = set.get(); + break; } + if (nullptr == fDefaultFamily) { + fDefaultFamily = fFamilies[0].get(); + } +} -private: - Families fFamilies; - SkFontStyleSet_Custom* fDefaultFamily; - SkTypeface_FreeType::Scanner fScanner; -}; +int SkFontMgr_Custom::onCountFamilies() const { + return fFamilies.count(); +} -/////////////////////////////////////////////////////////////////////////////// +void SkFontMgr_Custom::onGetFamilyName(int index, SkString* familyName) const { + SkASSERT(index < fFamilies.count()); + familyName->set(fFamilies[index]->getFamilyName()); +} -class DirectorySystemFontLoader : public SkFontMgr_Custom::SystemFontLoader { -public: - DirectorySystemFontLoader(const char* dir) : fBaseDirectory(dir) { } +SkFontStyleSet_Custom* SkFontMgr_Custom::onCreateStyleSet(int index) const { + SkASSERT(index < fFamilies.count()); + return SkRef(fFamilies[index].get()); +} - void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner, - SkFontMgr_Custom::Families* families) const override - { - load_directory_fonts(scanner, fBaseDirectory, ".ttf", families); - load_directory_fonts(scanner, fBaseDirectory, ".ttc", families); - load_directory_fonts(scanner, fBaseDirectory, ".otf", families); - load_directory_fonts(scanner, fBaseDirectory, ".pfb", families); - - if (families->empty()) { - SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString()); - families->push_back().reset(family); - family->appendTypeface(sk_make_sp()); +SkFontStyleSet_Custom* SkFontMgr_Custom::onMatchFamily(const char familyName[]) const { + for (int i = 0; i < fFamilies.count(); ++i) { + if (fFamilies[i]->getFamilyName().equals(familyName)) { + return SkRef(fFamilies[i].get()); } } + return nullptr; +} -private: - static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families, - const char familyName[]) - { - for (int i = 0; i < families.count(); ++i) { - if (families[i]->getFamilyName().equals(familyName)) { - return families[i].get(); +SkTypeface* SkFontMgr_Custom::onMatchFamilyStyle(const char familyName[], + const SkFontStyle& fontStyle) const +{ + sk_sp sset(this->matchFamily(familyName)); + return sset->matchStyle(fontStyle); +} + +SkTypeface* SkFontMgr_Custom::onMatchFamilyStyleCharacter(const char familyName[], + const SkFontStyle&, + const char* bcp47[], int bcp47Count, + SkUnichar character) const +{ + return nullptr; +} + +SkTypeface* SkFontMgr_Custom::onMatchFaceStyle(const SkTypeface* familyMember, + const SkFontStyle& fontStyle) const +{ + for (int i = 0; i < fFamilies.count(); ++i) { + for (int j = 0; j < fFamilies[i]->fStyles.count(); ++j) { + if (fFamilies[i]->fStyles[j].get() == familyMember) { + return fFamilies[i]->matchStyle(fontStyle); } } + } + return nullptr; +} + +SkTypeface* SkFontMgr_Custom::onCreateFromData(SkData* data, int ttcIndex) const { + return this->createFromStream(new SkMemoryStream(sk_ref_sp(data)), ttcIndex); +} + +SkTypeface* SkFontMgr_Custom::onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const { + return this->createFromStream(bareStream, FontParameters().setCollectionIndex(ttcIndex)); +} + +SkTypeface* SkFontMgr_Custom::onCreateFromStream(SkStreamAsset* s, + const SkFontArguments& args) const +{ + using Scanner = SkTypeface_FreeType::Scanner; + std::unique_ptr stream(s); + bool isFixedPitch; + SkFontStyle style; + SkString name; + Scanner::AxisDefinitions axisDefinitions; + if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(), + &name, &style, &isFixedPitch, &axisDefinitions)) + { return nullptr; } - static void load_directory_fonts(const SkTypeface_FreeType::Scanner& scanner, - const SkString& directory, const char* suffix, - SkFontMgr_Custom::Families* families) - { - SkOSFile::Iter iter(directory.c_str(), suffix); - SkString name; + const SkFontArguments::VariationPosition position = args.getVariationDesignPosition(); + SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); + Scanner::computeAxisValues(axisDefinitions, position, axisValues, name); - while (iter.next(&name, false)) { - SkString filename(SkOSPath::Join(directory.c_str(), name.c_str())); - std::unique_ptr stream = SkStream::MakeFromFile(filename.c_str()); - if (!stream) { - SkDebugf("---- failed to open <%s>\n", filename.c_str()); - continue; - } - - int numFaces; - if (!scanner.recognizedFont(stream.get(), &numFaces)) { - SkDebugf("---- failed to open <%s> as a font\n", filename.c_str()); - continue; - } - - for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { - bool isFixedPitch; - SkString realname; - SkFontStyle style = SkFontStyle(); // avoid uninitialized warning - if (!scanner.scanFont(stream.get(), faceIndex, - &realname, &style, &isFixedPitch, nullptr)) - { - SkDebugf("---- failed to open <%s> <%d> as a font\n", - filename.c_str(), faceIndex); - continue; - } - - SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str()); - if (nullptr == addTo) { - addTo = new SkFontStyleSet_Custom(realname); - families->push_back().reset(addTo); - } - addTo->appendTypeface(sk_make_sp(style, isFixedPitch, true, - realname, filename.c_str(), - faceIndex)); - } - } - - SkOSFile::Iter dirIter(directory.c_str()); - while (dirIter.next(&name, true)) { - if (name.startsWith(".")) { - continue; - } - SkString dirname(SkOSPath::Join(directory.c_str(), name.c_str())); - load_directory_fonts(scanner, dirname, suffix, families); - } - } - - SkString fBaseDirectory; -}; - -SK_API SkFontMgr* SkFontMgr_New_Custom_Directory(const char* dir) { - return new SkFontMgr_Custom(DirectorySystemFontLoader(dir)); + auto data = skstd::make_unique(std::move(stream), args.getCollectionIndex(), + axisValues.get(), axisDefinitions.count()); + return new SkTypeface_Stream(std::move(data), style, isFixedPitch, false, name); } -/////////////////////////////////////////////////////////////////////////////// - -struct SkEmbeddedResource { const uint8_t* data; size_t size; }; -struct SkEmbeddedResourceHeader { const SkEmbeddedResource* entries; int count; }; - -class EmbeddedSystemFontLoader : public SkFontMgr_Custom::SystemFontLoader { -public: - EmbeddedSystemFontLoader(const SkEmbeddedResourceHeader* header) : fHeader(header) { } - - void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner, - SkFontMgr_Custom::Families* families) const override +SkTypeface* SkFontMgr_Custom::onCreateFromFontData(std::unique_ptr data) const { + bool isFixedPitch; + SkFontStyle style; + SkString name; + if (!fScanner.scanFont(data->getStream(), data->getIndex(), + &name, &style, &isFixedPitch, nullptr)) { - for (int i = 0; i < fHeader->count; ++i) { - const SkEmbeddedResource& fontEntry = fHeader->entries[i]; - load_embedded_font(scanner, fontEntry.data, fontEntry.size, i, families); - } - - if (families->empty()) { - SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString()); - families->push_back().reset(family); - family->appendTypeface(sk_make_sp()); - } - } - -private: - static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families, - const char familyName[]) - { - for (int i = 0; i < families.count(); ++i) { - if (families[i]->getFamilyName().equals(familyName)) { - return families[i].get(); - } - } return nullptr; } - - static void load_embedded_font(const SkTypeface_FreeType::Scanner& scanner, - const uint8_t* data, size_t size, int index, - SkFontMgr_Custom::Families* families) - { - auto stream = skstd::make_unique(data, size, false); - - int numFaces; - if (!scanner.recognizedFont(stream.get(), &numFaces)) { - SkDebugf("---- failed to open <%d> as a font\n", index); - return; - } - - for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { - bool isFixedPitch; - SkString realname; - SkFontStyle style = SkFontStyle(); // avoid uninitialized warning - if (!scanner.scanFont(stream.get(), faceIndex, - &realname, &style, &isFixedPitch, nullptr)) - { - SkDebugf("---- failed to open <%d> <%d> as a font\n", index, faceIndex); - return; - } - - SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str()); - if (nullptr == addTo) { - addTo = new SkFontStyleSet_Custom(realname); - families->push_back().reset(addTo); - } - auto data = skstd::make_unique(std::move(stream), faceIndex, nullptr, 0); - addTo->appendTypeface(sk_make_sp(std::move(data), - style, isFixedPitch, - true, realname)); - } - } - - const SkEmbeddedResourceHeader* fHeader; -}; - -SkFontMgr* SkFontMgr_New_Custom_Embedded(const SkEmbeddedResourceHeader* header) { - return new SkFontMgr_Custom(EmbeddedSystemFontLoader(header)); + return new SkTypeface_Stream(std::move(data), style, isFixedPitch, false, name); } -/////////////////////////////////////////////////////////////////////////////// +SkTypeface* SkFontMgr_Custom::onCreateFromFile(const char path[], int ttcIndex) const { + std::unique_ptr stream = SkStream::MakeFromFile(path); + return stream.get() ? this->createFromStream(stream.release(), ttcIndex) : nullptr; +} -class EmptyFontLoader : public SkFontMgr_Custom::SystemFontLoader { -public: - EmptyFontLoader() { } +SkTypeface* SkFontMgr_Custom::onLegacyCreateTypeface(const char familyName[], + SkFontStyle style) const +{ + SkTypeface* tf = nullptr; - void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner, - SkFontMgr_Custom::Families* families) const override - { - SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString()); - families->push_back().reset(family); - family->appendTypeface(sk_make_sp()); + if (familyName) { + tf = this->onMatchFamilyStyle(familyName, style); } -}; + if (nullptr == tf) { + tf = fDefaultFamily->matchStyle(style); + } -SK_API SkFontMgr* SkFontMgr_New_Custom_Empty() { - return new SkFontMgr_Custom(EmptyFontLoader()); + return tf; } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_custom.h b/gfx/skia/skia/src/ports/SkFontMgr_custom.h new file mode 100644 index 000000000000..f8d083c0491a --- /dev/null +++ b/gfx/skia/skia/src/ports/SkFontMgr_custom.h @@ -0,0 +1,158 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_custom_DEFINED +#define SkFontMgr_custom_DEFINED + +#include "SkFontHost_FreeType_common.h" +#include "SkFontMgr.h" +#include "SkFontStyle.h" +#include "SkRefCnt.h" +#include "SkString.h" +#include "SkTArray.h" +#include "SkTypes.h" + +class SkData; +class SkFontDescriptor; +class SkStreamAsset; +class SkTypeface; + +/** The base SkTypeface implementation for the custom font manager. */ +class SkTypeface_Custom : public SkTypeface_FreeType { +public: + SkTypeface_Custom(const SkFontStyle& style, bool isFixedPitch, + bool sysFont, const SkString familyName, int index); + bool isSysFont() const; + +protected: + void onGetFamilyName(SkString* familyName) const override; + void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override; + int getIndex() const; + +private: + const bool fIsSysFont; + const SkString fFamilyName; + const int fIndex; + + typedef SkTypeface_FreeType INHERITED; +}; + +/** The empty SkTypeface implementation for the custom font manager. + * Used as the last resort fallback typeface. + */ +class SkTypeface_Empty : public SkTypeface_Custom { +public: + SkTypeface_Empty() ; + +protected: + SkStreamAsset* onOpenStream(int*) const override; + +private: + typedef SkTypeface_Custom INHERITED; +}; + +/** The stream SkTypeface implementation for the custom font manager. */ +class SkTypeface_Stream : public SkTypeface_Custom { +public: + SkTypeface_Stream(std::unique_ptr fontData, + const SkFontStyle& style, bool isFixedPitch, bool sysFont, + const SkString familyName); + +protected: + SkStreamAsset* onOpenStream(int* ttcIndex) const override; + std::unique_ptr onMakeFontData() const override; + +private: + const std::unique_ptr fData; + + typedef SkTypeface_Custom INHERITED; +}; + +/** The file SkTypeface implementation for the custom font manager. */ +class SkTypeface_File : public SkTypeface_Custom { +public: + SkTypeface_File(const SkFontStyle& style, bool isFixedPitch, bool sysFont, + const SkString familyName, const char path[], int index); + +protected: + SkStreamAsset* onOpenStream(int* ttcIndex) const override; + +private: + SkString fPath; + + typedef SkTypeface_Custom INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * SkFontStyleSet_Custom + * + * This class is used by SkFontMgr_Custom to hold SkTypeface_Custom families. + */ +class SkFontStyleSet_Custom : public SkFontStyleSet { +public: + explicit SkFontStyleSet_Custom(const SkString familyName); + + /** Should only be called during the inital build phase. */ + void appendTypeface(sk_sp typeface); + int count() override; + void getStyle(int index, SkFontStyle* style, SkString* name) override; + SkTypeface* createTypeface(int index) override; + SkTypeface* matchStyle(const SkFontStyle& pattern) override; + SkString getFamilyName(); + +private: + SkTArray> fStyles; + SkString fFamilyName; + + friend class SkFontMgr_Custom; +}; + +/** + * SkFontMgr_Custom + * + * This class is essentially a collection of SkFontStyleSet_Custom, + * one SkFontStyleSet_Custom for each family. This class may be modified + * to load fonts from any source by changing the initialization. + */ +class SkFontMgr_Custom : public SkFontMgr { +public: + typedef SkTArray> Families; + class SystemFontLoader { + public: + virtual ~SystemFontLoader() { } + virtual void loadSystemFonts(const SkTypeface_FreeType::Scanner&, Families*) const = 0; + }; + explicit SkFontMgr_Custom(const SystemFontLoader& loader); + +protected: + int onCountFamilies() const override; + void onGetFamilyName(int index, SkString* familyName) const override; + SkFontStyleSet_Custom* onCreateStyleSet(int index) const override; + SkFontStyleSet_Custom* onMatchFamily(const char familyName[]) const override; + SkTypeface* onMatchFamilyStyle(const char familyName[], + const SkFontStyle& fontStyle) const override; + SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&, + const char* bcp47[], int bcp47Count, + SkUnichar character) const override; + SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, + const SkFontStyle& fontStyle) const override; + SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override; + SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override; + SkTypeface* onCreateFromStream(SkStreamAsset* s, const SkFontArguments& args) const override; + SkTypeface* onCreateFromFontData(std::unique_ptr data) const override; + SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override; + SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override; + +private: + Families fFamilies; + SkFontStyleSet_Custom* fDefaultFamily; + SkTypeface_FreeType::Scanner fScanner; +}; + +#endif diff --git a/gfx/skia/skia/src/ports/SkFontMgr_custom_directory.cpp b/gfx/skia/skia/src/ports/SkFontMgr_custom_directory.cpp new file mode 100644 index 000000000000..af322875f396 --- /dev/null +++ b/gfx/skia/skia/src/ports/SkFontMgr_custom_directory.cpp @@ -0,0 +1,104 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkFontMgr_custom.h" +#include "SkFontMgr_directory.h" +#include "SkOSFile.h" +#include "SkOSPath.h" +#include "SkStream.h" + +class DirectorySystemFontLoader : public SkFontMgr_Custom::SystemFontLoader { +public: + DirectorySystemFontLoader(const char* dir) : fBaseDirectory(dir) { } + + void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner, + SkFontMgr_Custom::Families* families) const override + { + load_directory_fonts(scanner, fBaseDirectory, ".ttf", families); + load_directory_fonts(scanner, fBaseDirectory, ".ttc", families); + load_directory_fonts(scanner, fBaseDirectory, ".otf", families); + load_directory_fonts(scanner, fBaseDirectory, ".pfb", families); + + if (families->empty()) { + SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString()); + families->push_back().reset(family); + family->appendTypeface(sk_make_sp()); + } + } + +private: + static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families, + const char familyName[]) + { + for (int i = 0; i < families.count(); ++i) { + if (families[i]->getFamilyName().equals(familyName)) { + return families[i].get(); + } + } + return nullptr; + } + + static void load_directory_fonts(const SkTypeface_FreeType::Scanner& scanner, + const SkString& directory, const char* suffix, + SkFontMgr_Custom::Families* families) + { + SkOSFile::Iter iter(directory.c_str(), suffix); + SkString name; + + while (iter.next(&name, false)) { + SkString filename(SkOSPath::Join(directory.c_str(), name.c_str())); + std::unique_ptr stream = SkStream::MakeFromFile(filename.c_str()); + if (!stream) { + SkDebugf("---- failed to open <%s>\n", filename.c_str()); + continue; + } + + int numFaces; + if (!scanner.recognizedFont(stream.get(), &numFaces)) { + SkDebugf("---- failed to open <%s> as a font\n", filename.c_str()); + continue; + } + + for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { + bool isFixedPitch; + SkString realname; + SkFontStyle style = SkFontStyle(); // avoid uninitialized warning + if (!scanner.scanFont(stream.get(), faceIndex, + &realname, &style, &isFixedPitch, nullptr)) + { + SkDebugf("---- failed to open <%s> <%d> as a font\n", + filename.c_str(), faceIndex); + continue; + } + + SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str()); + if (nullptr == addTo) { + addTo = new SkFontStyleSet_Custom(realname); + families->push_back().reset(addTo); + } + addTo->appendTypeface(sk_make_sp(style, isFixedPitch, true, + realname, filename.c_str(), + faceIndex)); + } + } + + SkOSFile::Iter dirIter(directory.c_str()); + while (dirIter.next(&name, true)) { + if (name.startsWith(".")) { + continue; + } + SkString dirname(SkOSPath::Join(directory.c_str(), name.c_str())); + load_directory_fonts(scanner, dirname, suffix, families); + } + } + + SkString fBaseDirectory; +}; + +SK_API sk_sp SkFontMgr_New_Custom_Directory(const char* dir) { + return sk_make_sp(DirectorySystemFontLoader(dir)); +} diff --git a/gfx/skia/skia/src/ports/SkFontMgr_custom_directory_factory.cpp b/gfx/skia/skia/src/ports/SkFontMgr_custom_directory_factory.cpp index 0ca6f4b3b4b6..e8d4bb3f3e50 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_custom_directory_factory.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_custom_directory_factory.cpp @@ -6,12 +6,12 @@ */ #include "SkFontMgr.h" -#include "SkFontMgr_custom.h" +#include "SkFontMgr_directory.h" #ifndef SK_FONT_FILE_PREFIX # define SK_FONT_FILE_PREFIX "/usr/share/fonts/" #endif -SkFontMgr* SkFontMgr::Factory() { +sk_sp SkFontMgr::Factory() { return SkFontMgr_New_Custom_Directory(SK_FONT_FILE_PREFIX); } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_custom_embedded.cpp b/gfx/skia/skia/src/ports/SkFontMgr_custom_embedded.cpp new file mode 100644 index 000000000000..bb8d9f20b725 --- /dev/null +++ b/gfx/skia/skia/src/ports/SkFontMgr_custom_embedded.cpp @@ -0,0 +1,87 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkFontDescriptor.h" +#include "SkFontMgr_custom.h" +#include "SkMakeUnique.h" +#include "SkStream.h" + +struct SkEmbeddedResource { const uint8_t* data; size_t size; }; +struct SkEmbeddedResourceHeader { const SkEmbeddedResource* entries; int count; }; + +class EmbeddedSystemFontLoader : public SkFontMgr_Custom::SystemFontLoader { +public: + EmbeddedSystemFontLoader(const SkEmbeddedResourceHeader* header) : fHeader(header) { } + + void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner, + SkFontMgr_Custom::Families* families) const override + { + for (int i = 0; i < fHeader->count; ++i) { + const SkEmbeddedResource& fontEntry = fHeader->entries[i]; + load_embedded_font(scanner, fontEntry.data, fontEntry.size, i, families); + } + + if (families->empty()) { + SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString()); + families->push_back().reset(family); + family->appendTypeface(sk_make_sp()); + } + } + +private: + static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families, + const char familyName[]) + { + for (int i = 0; i < families.count(); ++i) { + if (families[i]->getFamilyName().equals(familyName)) { + return families[i].get(); + } + } + return nullptr; + } + + static void load_embedded_font(const SkTypeface_FreeType::Scanner& scanner, + const uint8_t* data, size_t size, int index, + SkFontMgr_Custom::Families* families) + { + auto stream = skstd::make_unique(data, size, false); + + int numFaces; + if (!scanner.recognizedFont(stream.get(), &numFaces)) { + SkDebugf("---- failed to open <%d> as a font\n", index); + return; + } + + for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { + bool isFixedPitch; + SkString realname; + SkFontStyle style = SkFontStyle(); // avoid uninitialized warning + if (!scanner.scanFont(stream.get(), faceIndex, + &realname, &style, &isFixedPitch, nullptr)) + { + SkDebugf("---- failed to open <%d> <%d> as a font\n", index, faceIndex); + return; + } + + SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str()); + if (nullptr == addTo) { + addTo = new SkFontStyleSet_Custom(realname); + families->push_back().reset(addTo); + } + auto data = skstd::make_unique(std::move(stream), faceIndex, nullptr, 0); + addTo->appendTypeface(sk_make_sp(std::move(data), + style, isFixedPitch, + true, realname)); + } + } + + const SkEmbeddedResourceHeader* fHeader; +}; + +sk_sp SkFontMgr_New_Custom_Embedded(const SkEmbeddedResourceHeader* header) { + return sk_make_sp(EmbeddedSystemFontLoader(header)); +} diff --git a/gfx/skia/skia/src/ports/SkFontMgr_custom_embedded_factory.cpp b/gfx/skia/skia/src/ports/SkFontMgr_custom_embedded_factory.cpp index 6ea6a2d2af22..7a6df43b73bf 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_custom_embedded_factory.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_custom_embedded_factory.cpp @@ -9,9 +9,9 @@ struct SkEmbeddedResource { const uint8_t* data; size_t size; }; struct SkEmbeddedResourceHeader { const SkEmbeddedResource* entries; int count; }; -SkFontMgr* SkFontMgr_New_Custom_Embedded(const SkEmbeddedResourceHeader* header); +sk_sp SkFontMgr_New_Custom_Embedded(const SkEmbeddedResourceHeader* header); extern "C" const SkEmbeddedResourceHeader SK_EMBEDDED_FONTS; -SkFontMgr* SkFontMgr::Factory() { +sk_sp SkFontMgr::Factory() { return SkFontMgr_New_Custom_Embedded(&SK_EMBEDDED_FONTS); } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_custom_empty.cpp b/gfx/skia/skia/src/ports/SkFontMgr_custom_empty.cpp new file mode 100644 index 000000000000..8732bc32b4d5 --- /dev/null +++ b/gfx/skia/skia/src/ports/SkFontMgr_custom_empty.cpp @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkFontMgr_custom.h" +#include "SkFontMgr_empty.h" + +class EmptyFontLoader : public SkFontMgr_Custom::SystemFontLoader { +public: + EmptyFontLoader() { } + + void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner, + SkFontMgr_Custom::Families* families) const override + { + SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString()); + families->push_back().reset(family); + family->appendTypeface(sk_make_sp()); + } + +}; + +SK_API sk_sp SkFontMgr_New_Custom_Empty() { + return sk_make_sp(EmptyFontLoader()); +} diff --git a/gfx/skia/skia/src/ports/SkFontMgr_custom_empty_factory.cpp b/gfx/skia/skia/src/ports/SkFontMgr_custom_empty_factory.cpp index c9487cdcc717..da3650076ac9 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_custom_empty_factory.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_custom_empty_factory.cpp @@ -6,8 +6,8 @@ */ #include "SkFontMgr.h" -#include "SkFontMgr_custom.h" +#include "SkFontMgr_empty.h" -SkFontMgr* SkFontMgr::Factory() { +sk_sp SkFontMgr::Factory() { return SkFontMgr_New_Custom_Empty(); } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_empty_factory.cpp b/gfx/skia/skia/src/ports/SkFontMgr_empty_factory.cpp index b4232cde1270..9ca9e65fdd5b 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_empty_factory.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_empty_factory.cpp @@ -7,7 +7,7 @@ #include "SkFontMgr.h" -SkFontMgr* SkFontMgr::Factory() { +sk_sp SkFontMgr::Factory() { // Always return nullptr, an empty SkFontMgr will be used. return nullptr; } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_fontconfig.cpp b/gfx/skia/skia/src/ports/SkFontMgr_fontconfig.cpp index 1f0055870930..bceb4de3bd91 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_fontconfig.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_fontconfig.cpp @@ -406,13 +406,15 @@ static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) { class SkTypeface_stream : public SkTypeface_FreeType { public: /** @param data takes ownership of the font data.*/ - SkTypeface_stream(std::unique_ptr data, const SkFontStyle& style, bool fixedWidth) + SkTypeface_stream(std::unique_ptr data, + SkString familyName, const SkFontStyle& style, bool fixedWidth) : INHERITED(style, fixedWidth) + , fFamilyName(std::move(familyName)) , fData(std::move(data)) { } void onGetFamilyName(SkString* familyName) const override { - familyName->reset(); + *familyName = fFamilyName; } void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override { @@ -429,6 +431,7 @@ public: } private: + SkString fFamilyName; const std::unique_ptr fData; typedef SkTypeface_FreeType INHERITED; @@ -500,7 +503,7 @@ public: return info; } - virtual ~SkTypeface_fontconfig() { + ~SkTypeface_fontconfig() override { // Hold the lock while unrefing the pattern. FCLocker lock; fPattern.reset(); @@ -531,7 +534,7 @@ class SkFontMgr_fontconfig : public SkFontMgr { : fFontMgr(SkRef(parent)), fFontSet(fontSet) { } - virtual ~StyleSet() { + ~StyleSet() override { // Hold the lock while unrefing the font set. FCLocker lock; fFontSet.reset(); @@ -581,7 +584,7 @@ class SkFontMgr_fontconfig : public SkFontMgr { } private: - SkAutoTUnref fFontMgr; + sk_sp fFontMgr; SkAutoFcFontSet fFontSet; }; @@ -664,7 +667,7 @@ public: : fFC(config ? config : FcInitLoadConfigAndFonts()) , fFamilyNames(GetFamilyNames(fFC)) { } - virtual ~SkFontMgr_fontconfig() { + ~SkFontMgr_fontconfig() override { // Hold the lock while unrefing the config. FCLocker lock; fFC.reset(); @@ -885,37 +888,37 @@ protected: return nullptr; } + SkString name; SkFontStyle style; bool isFixedWidth = false; - if (!fScanner.scanFont(stream.get(), ttcIndex, nullptr, &style, &isFixedWidth, nullptr)) { + if (!fScanner.scanFont(stream.get(), ttcIndex, &name, &style, &isFixedWidth, nullptr)) { return nullptr; } auto data = skstd::make_unique(std::move(stream), ttcIndex, nullptr, 0); - return new SkTypeface_stream(std::move(data), style, isFixedWidth); + return new SkTypeface_stream(std::move(data), std::move(name), style, isFixedWidth); } - SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override { + SkTypeface* onCreateFromStream(SkStreamAsset* s, const SkFontArguments& args) const override { using Scanner = SkTypeface_FreeType::Scanner; std::unique_ptr stream(s); bool isFixedPitch; SkFontStyle style; SkString name; Scanner::AxisDefinitions axisDefinitions; - if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(), + if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(), &name, &style, &isFixedPitch, &axisDefinitions)) { return nullptr; } - int paramAxisCount; - const FontParameters::Axis* paramAxes = params.getAxes(¶mAxisCount); SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); - Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name); + Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(), + axisValues, name); - auto data = skstd::make_unique(std::move(stream), params.getCollectionIndex(), + auto data = skstd::make_unique(std::move(stream), args.getCollectionIndex(), axisValues.get(), axisDefinitions.count()); - return new SkTypeface_stream(std::move(data), style, isFixedPitch); + return new SkTypeface_stream(std::move(data), std::move(name), style, isFixedPitch); } SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override { @@ -934,17 +937,18 @@ protected: } const int ttcIndex = fontData->getIndex(); + SkString name; SkFontStyle style; bool isFixedWidth = false; - if (!fScanner.scanFont(stream, ttcIndex, nullptr, &style, &isFixedWidth, nullptr)) { + if (!fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedWidth, nullptr)) { return nullptr; } - return new SkTypeface_stream(std::move(fontData), style, isFixedWidth); + return new SkTypeface_stream(std::move(fontData), std::move(name), style, isFixedWidth); } SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override { - SkAutoTUnref typeface(this->matchFamilyStyle(familyName, style)); + sk_sp typeface(this->matchFamilyStyle(familyName, style)); if (typeface.get()) { return typeface.release(); } @@ -953,6 +957,6 @@ protected: } }; -SK_API SkFontMgr* SkFontMgr_New_FontConfig(FcConfig* fc) { - return new SkFontMgr_fontconfig(fc); +SK_API sk_sp SkFontMgr_New_FontConfig(FcConfig* fc) { + return sk_make_sp(fc); } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_fontconfig_factory.cpp b/gfx/skia/skia/src/ports/SkFontMgr_fontconfig_factory.cpp index cdf055608d54..2f5ffb41ac0e 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_fontconfig_factory.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_fontconfig_factory.cpp @@ -9,6 +9,6 @@ #include "SkFontMgr_fontconfig.h" #include "SkTypes.h" -SkFontMgr* SkFontMgr::Factory() { +sk_sp SkFontMgr::Factory() { return SkFontMgr_New_FontConfig(nullptr); } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_win_dw.cpp b/gfx/skia/skia/src/ports/SkFontMgr_win_dw.cpp index 7201dc10b03b..f985c4f24551 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_win_dw.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_win_dw.cpp @@ -22,10 +22,7 @@ #include "SkUtils.h" #include - -#if SK_HAS_DWRITE_2_H #include -#endif //////////////////////////////////////////////////////////////////////////////// @@ -51,7 +48,7 @@ public: return S_OK; } - SkAutoTDelete fStream; + std::unique_ptr fStream; private: StreamFontFileLoader(SkStreamAsset* stream) : fStream(stream), fRefCount(1) { } @@ -266,23 +263,19 @@ public: SkFontMgr_DirectWrite(IDWriteFactory* factory, IDWriteFontCollection* fontCollection, IDWriteFontFallback* fallback, WCHAR* localeName, int localeNameLength) : fFactory(SkRefComPtr(factory)) -#if SK_HAS_DWRITE_2_H , fFontFallback(SkSafeRefComPtr(fallback)) -#endif , fFontCollection(SkRefComPtr(fontCollection)) , fLocaleName(localeNameLength) { -#if SK_HAS_DWRITE_2_H if (!SUCCEEDED(fFactory->QueryInterface(&fFactory2))) { // IUnknown::QueryInterface states that if it fails, punk will be set to nullptr. // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx SkASSERT_RELEASE(nullptr == fFactory2.get()); } if (fFontFallback.get()) { - // factory must be provied if fallback is non-null, else the fallback will not be used. + // factory must be provided if fallback is non-null, else the fallback will not be used. SkASSERT(fFactory2.get()); } -#endif memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR)); } @@ -313,10 +306,8 @@ private: IDWriteFontFamily* fontFamily) const; SkTScopedComPtr fFactory; -#if SK_HAS_DWRITE_2_H SkTScopedComPtr fFactory2; SkTScopedComPtr fFontFallback; -#endif SkTScopedComPtr fFontCollection; SkSMallocWCHAR fLocaleName; mutable SkMutex fTFCacheMutex; @@ -340,7 +331,7 @@ public: SkTypeface* matchStyle(const SkFontStyle& pattern) override; private: - SkAutoTUnref fFontMgr; + sk_sp fFontMgr; SkTScopedComPtr fFontFamily; }; @@ -509,7 +500,7 @@ SkFontStyleSet* SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) co SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[], const SkFontStyle& fontstyle) const { - SkAutoTUnref sset(this->matchFamily(familyName)); + sk_sp sset(this->matchFamily(familyName)); return sset->matchStyle(fontstyle); } @@ -634,7 +625,7 @@ public: protected: ULONG fRefCount; - SkAutoTUnref fOuter; + sk_sp fOuter; UINT32 fCharacter; SkTypeface* fResolvedTypeface; }; @@ -768,7 +759,6 @@ SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyleCharacter(const char family dwBcp47 = &dwBcp47Local; } -#if SK_HAS_DWRITE_2_H if (fFactory2.get()) { SkTScopedComPtr systemFontFallback; IDWriteFontFallback* fontFallback = fFontFallback.get(); @@ -811,9 +801,6 @@ SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyleCharacter(const char family HRNM(font->GetFontFamily(&fontFamily), "Could not get family from font."); return this->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get()); } -#else -# pragma message("No dwrite_2.h is available, font fallback may be affected.") -#endif SkTScopedComPtr fallbackFormat; HRNM(fFactory->CreateTextFormat(dwFamilyName ? dwFamilyName : L"", @@ -951,10 +938,7 @@ HRESULT SkFontMgr_DirectWrite::getByFamilyName(const WCHAR wideFamilyName[], HRESULT SkFontMgr_DirectWrite::getDefaultFontFamily(IDWriteFontFamily** fontFamily) const { NONCLIENTMETRICSW metrics; metrics.cbSize = sizeof(metrics); - if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, - sizeof(metrics), - &metrics, - 0)) { + if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0)) { return E_UNEXPECTED; } HRM(this->getByFamilyName(metrics.lfMessageFont.lfFaceName, fontFamily), @@ -974,7 +958,7 @@ SkTypeface* SkFontMgr_DirectWrite::onLegacyCreateTypeface(const char familyName[ if (nullptr == fontFamily.get()) { // No family with given name, try default. - HRNM(this->getDefaultFontFamily(&fontFamily), "Could not get default font family."); + this->getDefaultFontFamily(&fontFamily); } if (nullptr == fontFamily.get()) { @@ -1043,14 +1027,14 @@ SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) { //////////////////////////////////////////////////////////////////////////////// #include "SkTypeface_win.h" -SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory, - IDWriteFontCollection* collection) { +SK_API sk_sp SkFontMgr_New_DirectWrite(IDWriteFactory* factory, + IDWriteFontCollection* collection) { return SkFontMgr_New_DirectWrite(factory, collection, nullptr); } -SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory, - IDWriteFontCollection* collection, - IDWriteFontFallback* fallback) { +SK_API sk_sp SkFontMgr_New_DirectWrite(IDWriteFactory* factory, + IDWriteFontCollection* collection, + IDWriteFontFallback* fallback) { if (nullptr == factory) { factory = sk_get_dwrite_factory(); if (nullptr == factory) { @@ -1081,15 +1065,16 @@ SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory, }; } - return new SkFontMgr_DirectWrite(factory, collection, fallback, localeName, localeNameLen); + return sk_make_sp(factory, collection, fallback, + localeName, localeNameLen); } #include "SkFontMgr_indirect.h" -SK_API SkFontMgr* SkFontMgr_New_DirectWriteRenderer(SkRemotableFontMgr* proxy) { - SkAutoTUnref impl(SkFontMgr_New_DirectWrite()); - if (impl.get() == nullptr) { +SK_API sk_sp SkFontMgr_New_DirectWriteRenderer(sk_sp proxy) { + sk_sp impl(SkFontMgr_New_DirectWrite()); + if (!impl) { return nullptr; } - return new SkFontMgr_Indirect(impl.get(), proxy); + return sk_make_sp(std::move(impl), std::move(proxy)); } #endif//defined(SK_BUILD_FOR_WIN32) diff --git a/gfx/skia/skia/src/ports/SkFontMgr_win_dw_factory.cpp b/gfx/skia/skia/src/ports/SkFontMgr_win_dw_factory.cpp index 52e22aec5268..464a05b43fbf 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_win_dw_factory.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_win_dw_factory.cpp @@ -11,7 +11,7 @@ #include "SkFontMgr.h" #include "SkTypeface_win.h" -SkFontMgr* SkFontMgr::Factory() { +sk_sp SkFontMgr::Factory() { return SkFontMgr_New_DirectWrite(); } diff --git a/gfx/skia/skia/src/ports/SkFontMgr_win_gdi_factory.cpp b/gfx/skia/skia/src/ports/SkFontMgr_win_gdi_factory.cpp index c1ca822c28f6..6015794bbcca 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_win_gdi_factory.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_win_gdi_factory.cpp @@ -11,7 +11,7 @@ #include "SkFontMgr.h" #include "SkTypeface_win.h" -SkFontMgr* SkFontMgr::Factory() { +sk_sp SkFontMgr::Factory() { return SkFontMgr_New_GDI(); } diff --git a/gfx/skia/skia/src/ports/SkGlobalInitialization_none.cpp b/gfx/skia/skia/src/ports/SkGlobalInitialization_none.cpp new file mode 100644 index 000000000000..07d1825c6f8f --- /dev/null +++ b/gfx/skia/skia/src/ports/SkGlobalInitialization_none.cpp @@ -0,0 +1,10 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkFlattenable.h" + +void SkFlattenable::PrivateInitializer::InitEffects() {} diff --git a/gfx/skia/skia/src/ports/SkImageEncoder_CG.cpp b/gfx/skia/skia/src/ports/SkImageEncoder_CG.cpp index 789285626c05..b3fd24332464 100644 --- a/gfx/skia/skia/src/ports/SkImageEncoder_CG.cpp +++ b/gfx/skia/skia/src/ports/SkImageEncoder_CG.cpp @@ -5,14 +5,14 @@ * found in the LICENSE file. */ -#include "SkTypes.h" +#include "SkImageEncoderPriv.h" + #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) #include "SkBitmap.h" #include "SkCGUtils.h" #include "SkColorPriv.h" #include "SkData.h" -#include "SkImageEncoder.h" #include "SkStream.h" #include "SkStreamPriv.h" #include "SkTemplates.h" @@ -57,50 +57,41 @@ static CGImageDestinationRef SkStreamToImageDestination(SkWStream* stream, return CGImageDestinationCreateWithDataConsumer(consumer, type, 1, nullptr); } -class SkImageEncoder_CG : public SkImageEncoder { -public: - SkImageEncoder_CG(Type t) : fType(t) {} - -protected: - virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); - -private: - Type fType; -}; - /* Encode bitmaps via CGImageDestination. We setup a DataConsumer which writes to our SkWStream. Since we don't reference/own the SkWStream, our consumer must only live for the duration of the onEncode() method. */ -bool SkImageEncoder_CG::onEncode(SkWStream* stream, const SkBitmap& bm, - int quality) { - // Used for converting a bitmap to 8888. - const SkBitmap* bmPtr = &bm; - SkBitmap bitmap8888; +bool SkEncodeImageWithCG(SkWStream* stream, const SkPixmap& pixmap, SkEncodedImageFormat format) { + SkBitmap bm; + if (!bm.installPixels(pixmap)) { + return false; + } + bm.setImmutable(); CFStringRef type; - switch (fType) { - case kICO_Type: + switch (format) { + case SkEncodedImageFormat::kICO: type = kUTTypeICO; break; - case kBMP_Type: + case SkEncodedImageFormat::kBMP: type = kUTTypeBMP; break; - case kGIF_Type: + case SkEncodedImageFormat::kGIF: type = kUTTypeGIF; break; - case kJPEG_Type: + case SkEncodedImageFormat::kJPEG: type = kUTTypeJPEG; break; - case kPNG_Type: + case SkEncodedImageFormat::kPNG: // PNG encoding an ARGB_4444 bitmap gives the following errors in GM: // : CGImageDestinationAddImage image could not be converted to destination // format. // : CGImageDestinationFinalize image destination does not have enough images // So instead we copy to 8888. if (bm.colorType() == kARGB_4444_SkColorType) { + SkBitmap bitmap8888; bm.copyTo(&bitmap8888, kN32_SkColorType); - bmPtr = &bitmap8888; + bm.swap(bitmap8888); } type = kUTTypePNG; break; @@ -114,7 +105,7 @@ bool SkImageEncoder_CG::onEncode(SkWStream* stream, const SkBitmap& bm, } SkAutoTCallVProc ardst(dst); - CGImageRef image = SkCreateCGImageRef(*bmPtr); + CGImageRef image = SkCreateCGImageRef(bm); if (nullptr == image) { return false; } @@ -124,28 +115,4 @@ bool SkImageEncoder_CG::onEncode(SkWStream* stream, const SkBitmap& bm, return CGImageDestinationFinalize(dst); } -/////////////////////////////////////////////////////////////////////////////// - -#ifdef SK_USE_CG_ENCODER -static SkImageEncoder* sk_imageencoder_cg_factory(SkImageEncoder::Type t) { - switch (t) { - case SkImageEncoder::kICO_Type: - case SkImageEncoder::kBMP_Type: - case SkImageEncoder::kGIF_Type: - case SkImageEncoder::kJPEG_Type: - case SkImageEncoder::kPNG_Type: - break; - default: - return nullptr; - } - return new SkImageEncoder_CG(t); -} - -static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_cg_factory); -#endif - -SkImageEncoder* CreateImageEncoder_CG(SkImageEncoder::Type type) { - return new SkImageEncoder_CG(type); -} - #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) diff --git a/gfx/skia/skia/src/ports/SkImageEncoder_WIC.cpp b/gfx/skia/skia/src/ports/SkImageEncoder_WIC.cpp index 6524526bdbda..6d355c1d47c6 100644 --- a/gfx/skia/skia/src/ports/SkImageEncoder_WIC.cpp +++ b/gfx/skia/skia/src/ports/SkImageEncoder_WIC.cpp @@ -28,14 +28,17 @@ #undef INT64_MAX #undef UINT64_MAX -#include #include "SkAutoCoInitialize.h" +#include "SkAutoMalloc.h" #include "SkBitmap.h" -#include "SkImageEncoder.h" +#include "SkImageEncoderPriv.h" #include "SkIStream.h" +#include "SkImageEncoder.h" #include "SkStream.h" #include "SkTScopedComPtr.h" +#include "SkTemplates.h" #include "SkUnPreMultiply.h" +#include //All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol. //In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported @@ -46,32 +49,24 @@ #undef CLSID_WICImagingFactory #endif -class SkImageEncoder_WIC : public SkImageEncoder { -public: - SkImageEncoder_WIC(Type t) : fType(t) {} - -protected: - virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); - -private: - Type fType; -}; - -bool SkImageEncoder_WIC::onEncode(SkWStream* stream - , const SkBitmap& bitmapOrig - , int quality) -{ +bool SkEncodeImageWithWIC(SkWStream* stream, const SkPixmap& pixmap, + SkEncodedImageFormat format, int quality) { GUID type; - switch (fType) { - case kJPEG_Type: + switch (format) { + case SkEncodedImageFormat::kJPEG: type = GUID_ContainerFormatJpeg; break; - case kPNG_Type: + case SkEncodedImageFormat::kPNG: type = GUID_ContainerFormatPng; break; default: return false; } + SkBitmap bitmapOrig; + if (!bitmapOrig.installPixels(pixmap)) { + return false; + } + bitmapOrig.setImmutable(); // First convert to BGRA if necessary. SkBitmap bitmap; @@ -97,7 +92,7 @@ bool SkImageEncoder_WIC::onEncode(SkWStream* stream size_t rowBytes = bitmap.rowBytes(); SkAutoMalloc pixelStorage; WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA; - if (kJPEG_Type == fType) { + if (SkEncodedImageFormat::kJPEG == format) { formatDesired = GUID_WICPixelFormat24bppBGR; rowBytes = SkAlign4(bitmap.width() * 3); pixelStorage.reset(rowBytes * bitmap.height()); @@ -216,25 +211,4 @@ bool SkImageEncoder_WIC::onEncode(SkWStream* stream return SUCCEEDED(hr); } -/////////////////////////////////////////////////////////////////////////////// - -#ifdef SK_USE_WIC_ENCODER -static SkImageEncoder* sk_imageencoder_wic_factory(SkImageEncoder::Type t) { - switch (t) { - case SkImageEncoder::kPNG_Type: - case SkImageEncoder::kJPEG_Type: - break; - default: - return nullptr; - } - return new SkImageEncoder_WIC(t); -} - -static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory); -#endif - -SkImageEncoder* CreateImageEncoder_WIC(SkImageEncoder::Type type) { - return new SkImageEncoder_WIC(type); -} - #endif // defined(SK_BUILD_FOR_WIN32) diff --git a/gfx/skia/skia/src/ports/SkImageEncoder_none.cpp b/gfx/skia/skia/src/ports/SkImageEncoder_none.cpp index c7d4b92425be..a26698beeb4c 100644 --- a/gfx/skia/skia/src/ports/SkImageEncoder_none.cpp +++ b/gfx/skia/skia/src/ports/SkImageEncoder_none.cpp @@ -5,72 +5,9 @@ * found in the LICENSE file. */ -#include "SkBitmap.h" -#include "SkImage.h" #include "SkImageEncoder.h" -#include "SkMovie.h" -#include "SkPixelSerializer.h" -#include "SkStream.h" -///////////////////////////////////////////////////////////////////////// - -// Empty implementation for SkMovie. - -SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) { - return nullptr; -} - -///////////////////////////////////////////////////////////////////////// - -// Empty implementations for SkImageEncoder. - -SkImageEncoder* SkImageEncoder::Create(Type t) { - return nullptr; -} - -bool SkImageEncoder::EncodeFile(const char file[], const SkBitmap&, Type, int quality) { +bool SkEncodeImage(SkWStream*, const SkPixmap&, SkEncodedImageFormat, int) { return false; } -bool SkImageEncoder::EncodeStream(SkWStream*, const SkBitmap&, SkImageEncoder::Type, int) { - return false; -} - -SkData* SkImageEncoder::EncodeData(const SkBitmap&, Type, int quality) { - return nullptr; -} - -SkData* SkImageEncoder::EncodeData(const SkImageInfo&, const void* pixels, size_t rowBytes, - Type, int quality) { - return nullptr; -} - -SkData* SkImageEncoder::EncodeData(const SkPixmap&, Type, int) { - return nullptr; -} - -bool SkImageEncoder::encodeStream(SkWStream*, const SkBitmap&, int) { - return false; -} - -SkData* SkImageEncoder::encodeData(const SkBitmap&, int) { - return nullptr; -} - -bool SkImageEncoder::encodeFile(const char file[], const SkBitmap& bm, int quality) { - return false; -} - -namespace { -class ImageEncoderPixelSerializer final : public SkPixelSerializer { -protected: - bool onUseEncodedData(const void*, size_t) override { return true; } - SkData* onEncode(const SkPixmap&) override { return nullptr; } -}; -} // namespace - -SkPixelSerializer* SkImageEncoder::CreatePixelSerializer() { - return new ImageEncoderPixelSerializer; -} - -///////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/ports/SkImageGeneratorCG.cpp b/gfx/skia/skia/src/ports/SkImageGeneratorCG.cpp index c54eebf9c7b2..d2e64369169a 100644 --- a/gfx/skia/skia/src/ports/SkImageGeneratorCG.cpp +++ b/gfx/skia/skia/src/ports/SkImageGeneratorCG.cpp @@ -60,7 +60,7 @@ SkImageGenerator* SkImageGeneratorCG::NewFromEncodedCG(SkData* data) { } SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType; - SkImageInfo info = SkImageInfo::Make(width, height, kN32_SkColorType, alphaType); + SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType); // FIXME: We have the opportunity to extract color space information here, // though I think it makes sense to wait until we understand how @@ -75,7 +75,7 @@ SkImageGeneratorCG::SkImageGeneratorCG(const SkImageInfo& info, const void* imag , fData(SkRef(data)) {} -SkData* SkImageGeneratorCG::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { +SkData* SkImageGeneratorCG::onRefEncodedData(GrContext* ctx) { return SkRef(fData.get()); } diff --git a/gfx/skia/skia/src/ports/SkImageGeneratorCG.h b/gfx/skia/skia/src/ports/SkImageGeneratorCG.h index baf3669ffce4..9ecfe1b1fe29 100644 --- a/gfx/skia/skia/src/ports/SkImageGeneratorCG.h +++ b/gfx/skia/skia/src/ports/SkImageGeneratorCG.h @@ -22,7 +22,7 @@ public: static SkImageGenerator* NewFromEncodedCG(SkData* data); protected: - SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) override; + SkData* onRefEncodedData(GrContext* ctx) override; bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) override; diff --git a/gfx/skia/skia/src/ports/SkImageGeneratorWIC.cpp b/gfx/skia/skia/src/ports/SkImageGeneratorWIC.cpp index 52d1377f20cc..7a367851ae2b 100644 --- a/gfx/skia/skia/src/ports/SkImageGeneratorWIC.cpp +++ b/gfx/skia/skia/src/ports/SkImageGeneratorWIC.cpp @@ -120,7 +120,7 @@ SkImageGenerator* SkImageGeneratorWIC::NewFromEncodedWIC(SkData* data) { // FIXME: If we change the implementation to handle swizzling ourselves, // we can support more output formats. - SkImageInfo info = SkImageInfo::MakeN32(width, height, alphaType); + SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType); return new SkImageGeneratorWIC(info, imagingFactory.release(), imageSource.release(), data); } @@ -132,7 +132,7 @@ SkImageGeneratorWIC::SkImageGeneratorWIC(const SkImageInfo& info, , fData(SkRef(data)) {} -SkData* SkImageGeneratorWIC::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { +SkData* SkImageGeneratorWIC::onRefEncodedData(GrContext* ctx) { return SkRef(fData.get()); } diff --git a/gfx/skia/skia/src/ports/SkImageGeneratorWIC.h b/gfx/skia/skia/src/ports/SkImageGeneratorWIC.h index 76cb6df1a36f..eb65e0b6780c 100644 --- a/gfx/skia/skia/src/ports/SkImageGeneratorWIC.h +++ b/gfx/skia/skia/src/ports/SkImageGeneratorWIC.h @@ -39,7 +39,7 @@ public: static SkImageGenerator* NewFromEncodedWIC(SkData* data); protected: - SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) override; + SkData* onRefEncodedData(GrContext* ctx) override; bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) override; diff --git a/gfx/skia/skia/src/ports/SkImageGenerator_none.cpp b/gfx/skia/skia/src/ports/SkImageGenerator_none.cpp index 2dce1c2dc4ce..5aeb5cb64abc 100644 --- a/gfx/skia/skia/src/ports/SkImageGenerator_none.cpp +++ b/gfx/skia/skia/src/ports/SkImageGenerator_none.cpp @@ -7,6 +7,6 @@ #include "SkImageGenerator.h" -SkImageGenerator* SkImageGenerator::NewFromEncodedImpl(SkData*) { +std::unique_ptr SkImageGenerator::MakeFromEncodedImpl(sk_sp) { return nullptr; } diff --git a/gfx/skia/skia/src/ports/SkImageGenerator_skia.cpp b/gfx/skia/skia/src/ports/SkImageGenerator_skia.cpp index b6ddee935ad7..e310b7fe2305 100644 --- a/gfx/skia/skia/src/ports/SkImageGenerator_skia.cpp +++ b/gfx/skia/skia/src/ports/SkImageGenerator_skia.cpp @@ -8,6 +8,6 @@ #include "SkData.h" #include "SkCodecImageGenerator.h" -SkImageGenerator* SkImageGenerator::NewFromEncodedImpl(SkData* data) { - return SkCodecImageGenerator::NewFromEncodedCodec(data); +std::unique_ptr SkImageGenerator::MakeFromEncodedImpl(sk_sp data) { + return SkCodecImageGenerator::MakeFromEncodedCodec(std::move(data)); } diff --git a/gfx/skia/skia/src/ports/SkMemory_malloc.cpp b/gfx/skia/skia/src/ports/SkMemory_malloc.cpp index f06dc35ea6a1..6c21decc8074 100644 --- a/gfx/skia/skia/src/ports/SkMemory_malloc.cpp +++ b/gfx/skia/skia/src/ports/SkMemory_malloc.cpp @@ -4,10 +4,11 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#include "SkMalloc.h" #include "SkTypes.h" -#include +#include #define SK_DEBUGFAILF(fmt, ...) \ SkASSERT((SkDebugf(fmt"\n", __VA_ARGS__), false)) @@ -15,7 +16,11 @@ static inline void sk_out_of_memory(size_t size) { SK_DEBUGFAILF("sk_out_of_memory (asked for " SK_SIZE_T_SPECIFIER " bytes)", size); +#if defined(IS_FUZZING) + exit(1); +#else abort(); +#endif } static inline void* throw_on_failure(size_t size, void* p) { @@ -33,6 +38,9 @@ void sk_abort_no_print() { #endif #if defined(SK_DEBUG) && defined(SK_BUILD_FOR_WIN) __debugbreak(); +#endif +#if defined(IS_FUZZING) + exit(1); #else abort(); #endif @@ -40,7 +48,11 @@ void sk_abort_no_print() { void sk_out_of_memory(void) { SkDEBUGFAIL("sk_out_of_memory"); +#if defined(IS_FUZZING) + exit(1); +#else abort(); +#endif } void* sk_malloc_throw(size_t size) { diff --git a/gfx/skia/skia/src/ports/SkMemory_mozalloc.cpp b/gfx/skia/skia/src/ports/SkMemory_mozalloc.cpp index f29881d96b0c..6d5d36be420b 100644 --- a/gfx/skia/skia/src/ports/SkMemory_mozalloc.cpp +++ b/gfx/skia/skia/src/ports/SkMemory_mozalloc.cpp @@ -6,8 +6,9 @@ * found in the LICENSE file. */ -#include "SkTypes.h" +#include "SkMalloc.h" +#include "SkTypes.h" #include "mozilla/mozalloc.h" #include "mozilla/mozalloc_abort.h" #include "mozilla/mozalloc_oom.h" diff --git a/gfx/skia/skia/src/ports/SkOSFile_posix.cpp b/gfx/skia/skia/src/ports/SkOSFile_posix.cpp index 396de68bbe8e..40028246ff70 100644 --- a/gfx/skia/skia/src/ports/SkOSFile_posix.cpp +++ b/gfx/skia/skia/src/ports/SkOSFile_posix.cpp @@ -19,6 +19,25 @@ #include #include +size_t sk_fgetsize(FILE* f) { + int fd = fileno(f); + if (fd < 0) { + return 0; + } + + struct stat status; + if (0 != fstat(fd, &status)) { + return 0; + } + if (!S_ISREG(status.st_mode)) { + return 0; + } + if (!SkTFitsIn(status.st_size)) { + return 0; + } + return static_cast(status.st_size); +} + bool sk_exists(const char *path, SkFILE_Flags flags) { int mode = F_OK; if (flags & kRead_SkFILE_Flag) { @@ -95,6 +114,18 @@ void* sk_fmmap(FILE* f, size_t* size) { return sk_fdmmap(fd, size); } +size_t sk_qread(FILE* file, void* buffer, size_t count, size_t offset) { + int fd = sk_fileno(file); + if (fd < 0) { + return SIZE_MAX; + } + ssize_t bytesRead = pread(fd, buffer, count, offset); + if (bytesRead < 0) { + return SIZE_MAX; + } + return bytesRead; +} + //////////////////////////////////////////////////////////////////////////// struct SkOSFileIterData { diff --git a/gfx/skia/skia/src/ports/SkOSFile_stdio.cpp b/gfx/skia/skia/src/ports/SkOSFile_stdio.cpp index 1c4bd4babdb3..e79d87fc895e 100644 --- a/gfx/skia/skia/src/ports/SkOSFile_stdio.cpp +++ b/gfx/skia/skia/src/ports/SkOSFile_stdio.cpp @@ -87,59 +87,6 @@ FILE* sk_fopen(const char path[], SkFILE_Flags flags) { return file; } -char* sk_fgets(char* str, int size, FILE* f) { - return fgets(str, size, (FILE *)f); -} - -int sk_feof(FILE *f) { - // no :: namespace qualifier because it breaks android - return feof((FILE *)f); -} - -size_t sk_fgetsize(FILE* f) { - SkASSERT(f); - - long curr = ftell(f); // remember where we are - if (curr < 0) { - return 0; - } - - fseek(f, 0, SEEK_END); // go to the end - long size = ftell(f); // record the size - if (size < 0) { - size = 0; - } - - fseek(f, curr, SEEK_SET); // go back to our prev location - return size; -} - -bool sk_frewind(FILE* f) { - SkASSERT(f); - ::rewind(f); - return true; -} - -size_t sk_fread(void* buffer, size_t byteCount, FILE* f) { - SkASSERT(f); - if (buffer == nullptr) { - size_t curr = ftell(f); - if ((long)curr == -1) { - SkDEBUGF(("sk_fread: ftell(%p) returned -1 feof:%d ferror:%d\n", f, feof(f), ferror(f))); - return 0; - } - int err = fseek(f, (long)byteCount, SEEK_CUR); - if (err != 0) { - SkDEBUGF(("sk_fread: fseek(%d) tell:%d failed with feof:%d ferror:%d returned:%d\n", - byteCount, curr, feof(f), ferror(f), err)); - return 0; - } - return byteCount; - } - else - return fread(buffer, 1, byteCount, f); -} - size_t sk_fwrite(const void* buffer, size_t byteCount, FILE* f) { SkASSERT(f); return fwrite(buffer, 1, byteCount, f); @@ -158,16 +105,6 @@ void sk_fsync(FILE* f) { #endif } -bool sk_fseek(FILE* f, size_t byteCount) { - int err = fseek(f, (long)byteCount, SEEK_SET); - return err == 0; -} - -bool sk_fmove(FILE* f, long byteCount) { - int err = fseek(f, byteCount, SEEK_CUR); - return err == 0; -} - size_t sk_ftell(FILE* f) { long curr = ftell(f); if (curr < 0) { @@ -177,8 +114,9 @@ size_t sk_ftell(FILE* f) { } void sk_fclose(FILE* f) { - SkASSERT(f); - fclose(f); + if (f) { + fclose(f); + } } bool sk_isdir(const char *path) { diff --git a/gfx/skia/skia/src/ports/SkOSFile_win.cpp b/gfx/skia/skia/src/ports/SkOSFile_win.cpp index cf46cea98525..e66bcb89c0d2 100644 --- a/gfx/skia/skia/src/ports/SkOSFile_win.cpp +++ b/gfx/skia/skia/src/ports/SkOSFile_win.cpp @@ -9,6 +9,7 @@ #if defined(SK_BUILD_FOR_WIN32) #include "SkLeanWindows.h" +#include "SkMalloc.h" #include "SkOSFile.h" #include "SkTFitsIn.h" @@ -16,6 +17,27 @@ #include #include +size_t sk_fgetsize(FILE* f) { + int fileno = sk_fileno(f); + if (fileno < 0) { + return 0; + } + + HANDLE file = (HANDLE)_get_osfhandle(fileno); + if (INVALID_HANDLE_VALUE == file) { + return 0; + } + + LARGE_INTEGER fileSize; + if (0 == GetFileSizeEx(file, &fileSize)) { + return 0; + } + if (!SkTFitsIn(fileSize.QuadPart)) { + return 0; + } + return static_cast(fileSize.QuadPart); +} + bool sk_exists(const char *path, SkFILE_Flags flags) { int mode = 0; // existence if (flags & kRead_SkFILE_Flag) { @@ -124,6 +146,33 @@ void* sk_fmmap(FILE* f, size_t* length) { return sk_fdmmap(fileno, length); } +size_t sk_qread(FILE* file, void* buffer, size_t count, size_t offset) { + int fileno = sk_fileno(file); + HANDLE fileHandle = (HANDLE)_get_osfhandle(fileno); + if (INVALID_HANDLE_VALUE == file) { + return SIZE_MAX; + } + + OVERLAPPED overlapped = {0}; + ULARGE_INTEGER winOffset; + winOffset.QuadPart = offset; + overlapped.Offset = winOffset.LowPart; + overlapped.OffsetHigh = winOffset.HighPart; + + if (!SkTFitsIn(count)) { + count = std::numeric_limits::max(); + } + + DWORD bytesRead; + if (ReadFile(fileHandle, buffer, static_cast(count), &bytesRead, &overlapped)) { + return bytesRead; + } + if (GetLastError() == ERROR_HANDLE_EOF) { + return 0; + } + return SIZE_MAX; +} + //////////////////////////////////////////////////////////////////////////// struct SkOSFileIterData { diff --git a/gfx/skia/skia/src/ports/SkOSLibrary_posix.cpp b/gfx/skia/skia/src/ports/SkOSLibrary_posix.cpp index 6372a8122a18..901ee22f3c94 100644 --- a/gfx/skia/skia/src/ports/SkOSLibrary_posix.cpp +++ b/gfx/skia/skia/src/ports/SkOSLibrary_posix.cpp @@ -12,11 +12,7 @@ #include void* DynamicLoadLibrary(const char* libraryName) { - void* result = dlopen(libraryName, RTLD_LAZY); - if (!result) { - SkDebugf("Error loading %s {\n %s\n}\n", libraryName, dlerror()); - } - return result; + return dlopen(libraryName, RTLD_LAZY); } void* GetProcedureAddress(void* library, const char* functionName) { diff --git a/gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp b/gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp index a4c895ad0d24..fd38c4f73fed 100644 --- a/gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp +++ b/gfx/skia/skia/src/ports/SkRemotableFontMgr_win_dw.cpp @@ -9,7 +9,6 @@ #include "SkDWrite.h" #include "SkDWriteFontFileStream.h" -#include "SkDataTable.h" #include "SkHRESULT.h" #include "SkMutex.h" #include "SkRemotableFontMgr.h" @@ -90,26 +89,6 @@ public: memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR)); } - sk_sp getFamilyNames() const override { - int count = fFontCollection->GetFontFamilyCount(); - - SkDataTableBuilder names(1024); - for (int index = 0; index < count; ++index) { - SkTScopedComPtr fontFamily; - HRNM(fFontCollection->GetFontFamily(index, &fontFamily), - "Could not get requested family."); - - SkTScopedComPtr familyNames; - HRNM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names."); - - SkString familyName; - sk_get_locale_string(familyNames.get(), fLocaleName.get(), &familyName); - - names.appendString(familyName); - } - return names.detachDataTable(); - } - HRESULT FontToIdentity(IDWriteFont* font, SkFontIdentity* fontId) const { SkTScopedComPtr fontFace; HRM(font->CreateFontFace(&fontFace), "Could not create font face."); @@ -148,7 +127,7 @@ public: int count = fontFamily->GetFontCount(); SkFontIdentity* fontIds; - SkAutoTUnref fontIdSet( + sk_sp fontIdSet( new SkRemotableFontIdentitySet(count, &fontIds)); for (int fontIndex = 0; fontIndex < count; ++fontIndex) { SkTScopedComPtr font; @@ -365,7 +344,7 @@ public: protected: ULONG fRefCount; - SkAutoTUnref fOuter; + sk_sp fOuter; UINT32 fCharacter; SkFontIdentity fIdentity; }; diff --git a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp index d050cb06966b..f76095ab1cef 100644 --- a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp +++ b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp @@ -32,9 +32,7 @@ #include "SkTypeface_win_dw.h" #include -#if SK_HAS_DWRITE_1_H -# include -#endif +#include /* Note: * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe. @@ -48,7 +46,7 @@ static bool isLCD(const SkScalerContext::Rec& rec) { return SkMask::kLCD16_Format == rec.fMaskFormat; } -static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) { +static bool is_hinted(DWriteFontTypeface* typeface) { SkAutoExclusive l(DWriteFactoryMutex); AutoTDWriteTable maxp(typeface->fDWriteFontFace.get()); if (!maxp.fExists) { @@ -60,45 +58,40 @@ static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) { if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) { return false; } - - if (0 == maxp->version.tt.maxSizeOfInstructions) { - // No hints. - return false; - } - - AutoTDWriteTable gasp(typeface->fDWriteFontFace.get()); - return !gasp.fExists; + return (0 != maxp->version.tt.maxSizeOfInstructions); } -/** A PPEMRange is inclusive, [min, max]. */ -struct PPEMRange { - int min; - int max; +/** A GaspRange is inclusive, [min, max]. */ +struct GaspRange { + using Behavior = SkOTTableGridAndScanProcedure::GaspRange::behavior; + GaspRange(int min, int max, int version, Behavior flags) + : fMin(min), fMax(max), fVersion(version), fFlags(flags) { } + int fMin; + int fMax; + int fVersion; + Behavior fFlags; }; -/** If the rendering mode for the specified 'size' is gridfit, then place - * the gridfit range into 'range'. Otherwise, leave 'range' alone. - */ -static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) { +bool get_gasp_range(DWriteFontTypeface* typeface, int size, GaspRange* range) { AutoTDWriteTable gasp(typeface->fDWriteFontFace.get()); if (!gasp.fExists) { - return; + return false; } if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) { - return; + return false; } if (gasp->version != SkOTTableGridAndScanProcedure::version0 && gasp->version != SkOTTableGridAndScanProcedure::version1) { - return; + return false; } uint16_t numRanges = SkEndianSwap16(gasp->numRanges); if (numRanges > 1024 || gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) + - sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges) + sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges) { - return; + return false; } const SkOTTableGridAndScanProcedure::GaspRange* rangeTable = @@ -106,19 +99,25 @@ static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, int minPPEM = -1; for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) { int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM); - // Test that the size is in range and the range is gridfit only. - if (minPPEM < size && size <= maxPPEM && - rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask) - { - range->min = minPPEM + 1; - range->max = maxPPEM; - return; + if (minPPEM < size && size <= maxPPEM) { + range->fMin = minPPEM + 1; + range->fMax = maxPPEM; + range->fVersion = SkEndian_SwapBE16(gasp->version); + range->fFlags = rangeTable->flags; + return true; } minPPEM = maxPPEM; } + return false; +} +/** If the rendering mode for the specified 'size' is gridfit, then place + * the gridfit range into 'range'. Otherwise, leave 'range' alone. + */ +static bool is_gridfit_only(GaspRange::Behavior flags) { + return flags.raw.value == GaspRange::Behavior::Raw::GridfitMask; } -static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) { +static bool has_bitmap_strike(DWriteFontTypeface* typeface, GaspRange range) { SkAutoExclusive l(DWriteFactoryMutex); { AutoTDWriteTable eblc(typeface->fDWriteFontFace.get()); @@ -144,7 +143,7 @@ static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) { SkTAfter(eblc.get()); for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { if (sizeTable->ppemX == sizeTable->ppemY && - range.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max) + range.fMin <= sizeTable->ppemX && sizeTable->ppemX <= range.fMax) { // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable // to determine the actual number of glyphs with bitmaps. @@ -183,7 +182,7 @@ static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) { SkTAfter(ebsc.get()); for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { if (scaleTable->ppemX == scaleTable->ppemY && - range.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max) { + range.fMin <= scaleTable->ppemX && scaleTable->ppemX <= range.fMax) { // EBSC tables are normally only found in bitmap only fonts. return true; } @@ -204,26 +203,16 @@ static bool is_axis_aligned(const SkScalerContext::Rec& rec) { both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); } -SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, +SkScalerContext_DW::SkScalerContext_DW(sk_sp typefaceRef, const SkScalerContextEffects& effects, const SkDescriptor* desc) - : SkScalerContext(typeface, effects, desc) - , fTypeface(SkRef(typeface)) + : SkScalerContext(std::move(typefaceRef), effects, desc) , fGlyphCount(-1) { -#if SK_HAS_DWRITE_2_H - fTypeface->fFactory->QueryInterface(&fFactory2); - - SkTScopedComPtr fontFace2; - fTypeface->fDWriteFontFace->QueryInterface(&fontFace2); - fIsColorFont = fFactory2.get() && fontFace2.get() && fontFace2->IsColorFont(); -#endif - - IDWriteFactory* factory = sk_get_dwrite_factory(); - if (factory != nullptr) { - HRVM(factory->CreateRenderingParams(&fDefaultRenderingParams), - "Could not create default rendering params"); - } + DWriteFontTypeface* typeface = this->getDWriteTypeface(); + fIsColorFont = typeface->fFactory2 && + typeface->fDWriteFontFace2 && + typeface->fDWriteFontFace2->IsColorFont(); // In general, all glyphs should DWriteFontFace::GetRecommendedRenderingMode // except when bi-level rendering is requested or there are embedded @@ -277,13 +266,19 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, // When embedded bitmaps are requested, treat the entire range like // a bitmap strike if the range is gridfit only and contains a bitmap. int bitmapPPEM = SkScalarTruncToInt(gdiTextSize); - PPEMRange range = { bitmapPPEM, bitmapPPEM }; - expand_range_if_gridfit_only(typeface, bitmapPPEM, &range); + GaspRange range(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior()); + if (get_gasp_range(typeface, bitmapPPEM, &range)) { + if (!is_gridfit_only(range.fFlags)) { + range = GaspRange(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior()); + } + } treatLikeBitmap = has_bitmap_strike(typeface, range); axisAlignedBitmap = is_axis_aligned(fRec); } + GaspRange range(0, 0xFFFF, 0, GaspRange::Behavior()); + // If the user requested aliased, do so with aliased compatible metrics. if (SkMask::kBW_Format == fRec.fMaskFormat) { fTextSizeRender = gdiTextSize; @@ -296,7 +291,7 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, // This will not always provide a bitmap, but matches expected behavior. } else if ((treatLikeBitmap && axisAlignedBitmap) || typeface->ForceGDI()) { fTextSizeRender = gdiTextSize; - fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; + fRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC; fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; fTextSizeMeasure = gdiTextSize; fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; @@ -305,30 +300,29 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, // render high quality rotated glyphs but measure using bitmap metrics. } else if (treatLikeBitmap) { fTextSizeRender = gdiTextSize; - fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; + fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; fTextSizeMeasure = gdiTextSize; fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; - // Fonts that have hints but no gasp table get non-symmetric rendering. - // Usually such fonts have low quality hints which were never tested - // with anything but GDI ClearType classic. Such fonts often rely on - // drop out control in the y direction in order to be legible. - } else if (is_hinted_without_gasp(typeface)) { - fTextSizeRender = gdiTextSize; - fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL; - fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; - fTextSizeMeasure = realTextSize; - fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; - - // The normal case is to use the recommended rendering mode - } else { + // If the font has a gasp table version 1, use it to determine symmetric rendering. + } else if ((get_gasp_range(typeface, SkScalarRoundToInt(gdiTextSize), &range) && + range.fVersion >= 1) || + // If the requested size is above 20px or there are no bytecode hints, use symmetric rendering. + realTextSize > SkIntToScalar(20) || !is_hinted(typeface)) { fTextSizeRender = realTextSize; fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; fTextSizeMeasure = realTextSize; fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; - if (!SUCCEEDED(fTypeface->fDWriteFontFace->GetRecommendedRenderingMode( + IDWriteFactory* factory = sk_get_dwrite_factory(); + if (factory != nullptr) { + HRVM(factory->CreateRenderingParams(&fDefaultRenderingParams), + "Could not create default rendering params"); + } + + DWriteFontTypeface* typeface = static_cast(getTypeface()); + if (!SUCCEEDED(typeface->fDWriteFontFace->GetRecommendedRenderingMode( fTextSizeRender, 1.0f, fMeasuringMode, @@ -341,6 +335,42 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, if (fRenderingMode == DWRITE_RENDERING_MODE_OUTLINE) { fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; } + + // Fonts with hints, no gasp or gasp version 0, and below 20px get non-symmetric rendering. + // Often such fonts have hints which were only tested with GDI ClearType classic. + // Some of these fonts rely on drop out control in the y direction in order to be legible. + // Tenor Sans + // https://fonts.google.com/specimen/Tenor+Sans + // Gill Sans W04 + // https://cdn.leagueoflegends.com/lolkit/1.1.9/resources/fonts/gill-sans-w04-book.woff + // https://na.leagueoflegends.com/en/news/game-updates/patch/patch-410-notes + // See https://crbug.com/385897 + } else { + fTextSizeRender = gdiTextSize; + fRenderingMode = DWRITE_RENDERING_MODE_NATURAL; + fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; + fTextSizeMeasure = realTextSize; + fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; + } + + // DirectWrite2 allows for grayscale hinting. + fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE; + if (typeface->fFactory2 && typeface->fDWriteFontFace2 && + SkMask::kA8_Format == fRec.fMaskFormat && + !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) + { + // DWRITE_TEXTURE_ALIASED_1x1 is now misnamed, it must also be used with grayscale. + fTextureType = DWRITE_TEXTURE_ALIASED_1x1; + fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE; + } + + // DirectWrite2 allows hinting to be disabled. + fGridFitMode = DWRITE_GRID_FIT_MODE_ENABLED; + if (fRec.getHinting() == SkPaint::kNo_Hinting) { + fGridFitMode = DWRITE_GRID_FIT_MODE_DISABLED; + if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) { + fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; + } } if (this->isSubpixel()) { @@ -354,14 +384,15 @@ SkScalerContext_DW::~SkScalerContext_DW() { unsigned SkScalerContext_DW::generateGlyphCount() { if (fGlyphCount < 0) { - fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount(); + fGlyphCount = this->getDWriteTypeface()->fDWriteFontFace->GetGlyphCount(); } return fGlyphCount; } uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) { uint16_t index = 0; - fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast(&uni), 1, &index); + UINT32* uniPtr = reinterpret_cast(&uni); + this->getDWriteTypeface()->fDWriteFontFace->GetGlyphIndices(uniPtr, 1, &index); return index; } @@ -382,7 +413,7 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) { SkAutoExclusive l(DWriteFactoryMutex); - HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( + HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( fTextSizeMeasure, 1.0f, // pixelsPerDip &fGsA, @@ -392,18 +423,16 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { "Could not get gdi compatible glyph metrics."); } else { SkAutoExclusive l(DWriteFactoryMutex); - HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), + HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), "Could not get design metrics."); } DWRITE_FONT_METRICS dwfm; { Shared l(DWriteFactoryMutex); - fTypeface->fDWriteFontFace->GetMetrics(&dwfm); + this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm); } - SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure, - SkIntToScalar(gm.advanceWidth), - SkIntToScalar(dwfm.designUnitsPerEm)); + SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm; SkVector vecs[1] = { { advanceX, 0 } }; if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || @@ -441,7 +470,7 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph, DWRITE_GLYPH_RUN run; run.glyphCount = 1; run.glyphAdvances = &advance; - run.fontFace = fTypeface->fDWriteFontFace.get(); + run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get(); run.fontEmSize = SkScalarToFloat(fTextSizeRender); run.bidiLevel = 0; run.glyphIndices = &glyphId; @@ -451,16 +480,33 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph, SkTScopedComPtr glyphRunAnalysis; { SkAutoExclusive l(DWriteFactoryMutex); - HRM(fTypeface->fFactory->CreateGlyphRunAnalysis( - &run, - 1.0f, // pixelsPerDip, - &fXform, - renderingMode, - fMeasuringMode, - 0.0f, // baselineOriginX, - 0.0f, // baselineOriginY, - &glyphRunAnalysis), - "Could not create glyph run analysis."); + // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs. + if (this->getDWriteTypeface()->fFactory2 && + (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED || + fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)) + { + HRM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis( + &run, + &fXform, + renderingMode, + fMeasuringMode, + fGridFitMode, + fAntiAliasMode, + 0.0f, // baselineOriginX, + 0.0f, // baselineOriginY, + &glyphRunAnalysis), + "Could not create DW2 glyph run analysis."); + } else { + HRM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run, + 1.0f, // pixelsPerDip, + &fXform, + renderingMode, + fMeasuringMode, + 0.0f, // baselineOriginX, + 0.0f, // baselineOriginY, + &glyphRunAnalysis), + "Could not create glyph run analysis."); + } } { Shared l(DWriteFactoryMutex); @@ -487,16 +533,10 @@ static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) { } bool SkScalerContext_DW::isColorGlyph(const SkGlyph& glyph) { -#if SK_HAS_DWRITE_2_H SkTScopedComPtr colorLayer; - if (getColorGlyphRun(glyph, &colorLayer)) { - return true; - } -#endif - return false; + return getColorGlyphRun(glyph, &colorLayer); } -#if SK_HAS_DWRITE_2_H bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph, IDWriteColorGlyphRunEnumerator** colorGlyph) { @@ -510,14 +550,14 @@ bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph, DWRITE_GLYPH_RUN run; run.glyphCount = 1; run.glyphAdvances = &advance; - run.fontFace = fTypeface->fDWriteFontFace.get(); + run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get(); run.fontEmSize = SkScalarToFloat(fTextSizeRender); run.bidiLevel = 0; run.glyphIndices = &glyphId; run.isSideways = FALSE; run.glyphOffsets = &offset; - HRESULT hr = fFactory2->TranslateColorGlyphRun( + HRESULT hr = this->getDWriteTypeface()->fFactory2->TranslateColorGlyphRun( 0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph); if (hr == DWRITE_E_NOCOLOR) { return false; @@ -525,7 +565,6 @@ bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph, HRBM(hr, "Failed to translate color glyph run"); return true; } -#endif void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { glyph->fWidth = 0; @@ -535,11 +574,9 @@ void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { this->generateAdvance(glyph); -#if SK_HAS_DWRITE_2_H if (fIsColorFont && isColorGlyph(*glyph)) { glyph->fMaskFormat = SkMask::kARGB32_Format; } -#endif RECT bbox; HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), @@ -577,13 +614,13 @@ void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) { if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) { - fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics( + this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleMetrics( fTextSizeRender, 1.0f, // pixelsPerDip &fXform, &dwfm); } else { - fTypeface->fDWriteFontFace->GetMetrics(&dwfm); + this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm); } SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); @@ -592,16 +629,16 @@ void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) { metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; + metrics->fCapHeight = fTextSizeRender * SkIntToScalar(dwfm.capHeight) / upem; metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem; metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem); - metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; + metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag; metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; -#if SK_HAS_DWRITE_1_H - if (fTypeface->fDWriteFontFace1.get()) { + if (this->getDWriteTypeface()->fDWriteFontFace1.get()) { DWRITE_FONT_METRICS1 dwfm1; - fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1); + this->getDWriteTypeface()->fDWriteFontFace1->GetMetrics(&dwfm1); metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem; metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem; metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem; @@ -610,11 +647,8 @@ void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) { metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; return; } -#else -# pragma message("No dwrite_1.h is available, font metrics may be affected.") -#endif - AutoTDWriteTable head(fTypeface->fDWriteFontFace.get()); + AutoTDWriteTable head(this->getDWriteTypeface()->fDWriteFontFace.get()); if (head.fExists && head.fSize >= sizeof(SkOTTableHead) && head->version == SkOTTableHead::version1) @@ -674,6 +708,22 @@ static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) } } +template +static void grayscale_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, + const uint8_t* table8) { + const size_t dstRB = glyph.rowBytes(); + const U16CPU width = glyph.fWidth; + uint8_t* SK_RESTRICT dst = static_cast(glyph.fImage); + + for (U16CPU y = 0; y < glyph.fHeight; y++) { + for (U16CPU i = 0; i < width; i++) { + U8CPU a = *(src++); + dst[i] = sk_apply_lut_if(a, table8); + } + dst = SkTAddOffset(dst, dstRB); + } +} + template static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) { const size_t dstRB = glyph.rowBytes(); @@ -690,7 +740,7 @@ static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, cons // to just get a grayscale AA alpha texture from a glyph run. dst[i] = sk_apply_lut_if(g, table8); } - dst = (uint8_t*)((char*)dst + dstRB); + dst = SkTAddOffset(dst, dstRB); } } @@ -715,7 +765,7 @@ static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, } dst[i] = SkPack888ToRGB16(r, g, b); } - dst = (uint16_t*)((char*)dst + dstRB); + dst = SkTAddOffset(dst, dstRB); } } @@ -724,7 +774,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, DWRITE_TEXTURE_TYPE textureType) { int sizeNeeded = glyph.fWidth * glyph.fHeight; - if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) { + if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) { sizeNeeded *= 3; } if (sizeNeeded > fBits.count()) { @@ -748,26 +798,42 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, DWRITE_GLYPH_RUN run; run.glyphCount = 1; run.glyphAdvances = &advance; - run.fontFace = fTypeface->fDWriteFontFace.get(); + run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get(); run.fontEmSize = SkScalarToFloat(fTextSizeRender); run.bidiLevel = 0; run.glyphIndices = &index; run.isSideways = FALSE; run.glyphOffsets = &offset; { - SkTScopedComPtr glyphRunAnalysis; { SkAutoExclusive l(DWriteFactoryMutex); - HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, - 1.0f, // pixelsPerDip, - &fXform, - renderingMode, - fMeasuringMode, - 0.0f, // baselineOriginX, - 0.0f, // baselineOriginY, - &glyphRunAnalysis), - "Could not create glyph run analysis."); + // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs. + if (this->getDWriteTypeface()->fFactory2 && + (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED || + fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)) + { + HRNM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(&run, + &fXform, + renderingMode, + fMeasuringMode, + fGridFitMode, + fAntiAliasMode, + 0.0f, // baselineOriginX, + 0.0f, // baselineOriginY, + &glyphRunAnalysis), + "Could not create DW2 glyph run analysis."); + } else { + HRNM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run, + 1.0f, // pixelsPerDip, + &fXform, + renderingMode, + fMeasuringMode, + 0.0f, // baselineOriginX, + 0.0f, // baselineOriginY, + &glyphRunAnalysis), + "Could not create glyph run analysis."); + } } //NOTE: this assumes that the glyph has already been measured //with an exact same glyph run analysis. @@ -779,16 +845,15 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, { Shared l(DWriteFactoryMutex); HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, - &bbox, - fBits.begin(), - sizeNeeded), + &bbox, + fBits.begin(), + sizeNeeded), "Could not draw mask."); } } return fBits.begin(); } -#if SK_HAS_DWRITE_2_H void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) { SkASSERT(isColorGlyph(glyph)); SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format); @@ -855,7 +920,6 @@ void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) { draw.drawPath(path, paint, nullptr, true /* pathIsMutable */); } } -#endif void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { //Create the mask. @@ -866,12 +930,10 @@ void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { textureType = DWRITE_TEXTURE_ALIASED_1x1; } -#if SK_HAS_DWRITE_2_H if (SkMask::kARGB32_Format == glyph.fMaskFormat) { generateColorGlyphImage(glyph); return; } -#endif const void* bits = this->drawDWMask(glyph, renderingMode, textureType); if (!bits) { @@ -885,10 +947,18 @@ void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { bilevel_to_bw(src, glyph); const_cast(glyph).fMaskFormat = SkMask::kBW_Format; } else if (!isLCD(fRec)) { - if (fPreBlend.isApplicable()) { - rgb_to_a8(src, glyph, fPreBlend.fG); + if (textureType == DWRITE_TEXTURE_ALIASED_1x1) { + if (fPreBlend.isApplicable()) { + grayscale_to_a8(src, glyph, fPreBlend.fG); + } else { + grayscale_to_a8(src, glyph, fPreBlend.fG); + } } else { - rgb_to_a8(src, glyph, fPreBlend.fG); + if (fPreBlend.isApplicable()) { + rgb_to_a8(src, glyph, fPreBlend.fG); + } else { + rgb_to_a8(src, glyph, fPreBlend.fG); + } } } else { SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat); @@ -908,7 +978,7 @@ void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { } } -void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { +void SkScalerContext_DW::generatePath(SkGlyphID glyph, SkPath* path) { SkASSERT(path); path->reset(); @@ -916,20 +986,21 @@ void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { SkTScopedComPtr geometryToPath; HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), "Could not create geometry to path converter."); - uint16_t glyphId = glyph.getGlyphID(); + UINT16 glyphId = SkTo(glyph); { SkAutoExclusive l(DWriteFactoryMutex); //TODO: convert to<->from DIUs? This would make a difference if hinting. //It may not be needed, it appears that DirectWrite only hints at em size. - HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender), - &glyphId, - nullptr, //advances - nullptr, //offsets - 1, //num glyphs - FALSE, //sideways - FALSE, //rtl - geometryToPath.get()), - "Could not create glyph outline."); + HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline( + SkScalarToFloat(fTextSizeRender), + &glyphId, + nullptr, //advances + nullptr, //offsets + 1, //num glyphs + FALSE, //sideways + FALSE, //rtl + geometryToPath.get()), + "Could not create glyph outline."); } path->transform(fSkXform); diff --git a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h index f2a7e255bab0..fcd423f4c8d9 100644 --- a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h +++ b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h @@ -14,16 +14,16 @@ #include "SkTypes.h" #include -#if SK_HAS_DWRITE_2_H #include -#endif class SkGlyph; class SkDescriptor; class SkScalerContext_DW : public SkScalerContext { public: - SkScalerContext_DW(DWriteFontTypeface*, const SkScalerContextEffects&, const SkDescriptor*); + SkScalerContext_DW(sk_sp, + const SkScalerContextEffects&, + const SkDescriptor*); virtual ~SkScalerContext_DW(); protected: @@ -32,7 +32,7 @@ protected: void generateAdvance(SkGlyph* glyph) override; void generateMetrics(SkGlyph* glyph) override; void generateImage(const SkGlyph& glyph) override; - void generatePath(const SkGlyph& glyph, SkPath* path) override; + void generatePath(SkGlyphID glyph, SkPath* path) override; void generateFontMetrics(SkPaint::FontMetrics*) override; private: @@ -47,11 +47,13 @@ private: bool isColorGlyph(const SkGlyph& glyph); -#if SK_HAS_DWRITE_2_H + DWriteFontTypeface* getDWriteTypeface() { + return static_cast(this->getTypeface()); + } + bool getColorGlyphRun(const SkGlyph& glyph, IDWriteColorGlyphRunEnumerator** colorGlyph); void generateColorGlyphImage(const SkGlyph& glyph); -#endif SkTDArray fBits; /** The total matrix without the text height scale. */ @@ -70,16 +72,14 @@ private: SkScalar fTextSizeRender; /** The text size to measure with. */ SkScalar fTextSizeMeasure; - SkAutoTUnref fTypeface; int fGlyphCount; DWRITE_RENDERING_MODE fRenderingMode; DWRITE_TEXTURE_TYPE fTextureType; DWRITE_MEASURING_MODE fMeasuringMode; + DWRITE_TEXT_ANTIALIAS_MODE fAntiAliasMode; + DWRITE_GRID_FIT_MODE fGridFitMode; SkTScopedComPtr fDefaultRenderingParams; -#if SK_HAS_DWRITE_2_H - SkTScopedComPtr fFactory2; bool fIsColorFont; -#endif }; #endif diff --git a/gfx/skia/skia/src/ports/SkTypeface_win_dw.cpp b/gfx/skia/skia/src/ports/SkTypeface_win_dw.cpp index 96a728f600a2..8bab841b4949 100644 --- a/gfx/skia/skia/src/ports/SkTypeface_win_dw.cpp +++ b/gfx/skia/skia/src/ports/SkTypeface_win_dw.cpp @@ -18,6 +18,7 @@ #include "SkDWriteFontFileStream.h" #include "SkFontDescriptor.h" #include "SkFontStream.h" +#include "SkOTTable_fvar.h" #include "SkOTTable_head.h" #include "SkOTTable_hhea.h" #include "SkOTTable_OS_2.h" @@ -193,8 +194,8 @@ int DWriteFontTypeface::onGetTableTags(SkFontTableTag tags[]) const { } int ttcIndex; - SkAutoTDelete stream(this->openStream(&ttcIndex)); - return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0; + std::unique_ptr stream(this->openStream(&ttcIndex)); + return stream.get() ? SkFontStream::GetTableTags(stream.get(), ttcIndex, tags) : 0; } size_t DWriteFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset, @@ -247,7 +248,7 @@ SkStreamAsset* DWriteFontTypeface::onOpenStream(int* ttcIndex) const { SkScalerContext* DWriteFontTypeface::onCreateScalerContext(const SkScalerContextEffects& effects, const SkDescriptor* desc) const { - return new SkScalerContext_DW(const_cast(this), effects, desc); + return new SkScalerContext_DW(sk_ref_sp(const_cast(this)), effects, desc); } #ifdef MOZ_SKIA @@ -257,6 +258,7 @@ IDWriteRenderingParams* GetDwriteRenderingParams(bool aGDI); void DWriteFontTypeface::onFilterRec(SkScalerContext::Rec* rec) const { if (rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) { rec->fMaskFormat = SkMask::kA8_Format; + rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag; } unsigned flagsWeDontSupport = SkScalerContext::kVertical_Flag | @@ -267,8 +269,10 @@ void DWriteFontTypeface::onFilterRec(SkScalerContext::Rec* rec) const { rec->fFlags &= ~flagsWeDontSupport; SkPaint::Hinting h = rec->getHinting(); - // DirectWrite does not provide for hinting hints. - h = SkPaint::kSlight_Hinting; + // DirectWrite2 allows for hinting to be turned off. Force everything else to normal. + if (h != SkPaint::kNo_Hinting || !fFactory2 || !fDWriteFontFace2) { + h = SkPaint::kNormal_Hinting; + } rec->setHinting(h); #if defined(SK_FONT_HOST_USE_SYSTEM_SETTINGS) @@ -308,9 +312,11 @@ static void populate_glyph_to_unicode(IDWriteFontFace* fontFace, const unsigned glyphCount, SkTDArray* glyphToUnicode) { //Do this like free type instead - SkAutoTMalloc glyphToUni(glyphCount); + SkAutoTMalloc glyphToUni( + (SkUnichar*)sk_calloc_throw(sizeof(SkUnichar) * glyphCount)); int maxGlyph = -1; - for (UINT32 c = 0; c < 0x10FFFF; ++c) { + unsigned remainingGlyphCount = glyphCount; + for (UINT32 c = 0; c < 0x10FFFF && remainingGlyphCount != 0; ++c) { UINT16 glyph = 0; HRVM(fontFace->GetGlyphIndices(&c, 1, &glyph), "Failed to get glyph index."); @@ -318,12 +324,12 @@ static void populate_glyph_to_unicode(IDWriteFontFace* fontFace, if (glyph >= glyphCount) { return; } - if (0 < glyph) { + if (0 < glyph && glyphToUni[glyph] == 0) { maxGlyph = SkTMax(static_cast(glyph), maxGlyph); - glyphToUni[glyph] = c; + glyphToUni[glyph] = c; // Always use lowest-index unichar. + --remainingGlyphCount; } } - SkTDArray(glyphToUni, maxGlyph + 1).swap(*glyphToUnicode); } @@ -342,8 +348,6 @@ SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics( fDWriteFontFace->GetMetrics(&dwfm); info = new SkAdvancedTypefaceMetrics; - info->fEmSize = dwfm.designUnitsPerEm; - info->fLastGlyphID = SkToU16(glyphCount - 1); info->fAscent = SkToS16(dwfm.ascent); info->fDescent = SkToS16(dwfm.descent); @@ -387,6 +391,13 @@ SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics( return info; } + // There are versions of DirectWrite which support named instances for system variation fonts, + // but no means to indicate that such a typeface is a variation. + AutoTDWriteTable fvarTable(fDWriteFontFace.get()); + if (fvarTable.fExists) { + info->fFlags |= SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag; + } + //There exist CJK fonts which set the IsFixedPitch and Monospace bits, //but have full width, latin half-width, and half-width kana. bool fixedWidth = (postTable->isFixedPitch && diff --git a/gfx/skia/skia/src/ports/SkTypeface_win_dw.h b/gfx/skia/skia/src/ports/SkTypeface_win_dw.h index fbf9821931ef..035d133be772 100644 --- a/gfx/skia/skia/src/ports/SkTypeface_win_dw.h +++ b/gfx/skia/skia/src/ports/SkTypeface_win_dw.h @@ -17,9 +17,8 @@ #include "SkTypefaceCache.h" #include -#if SK_HAS_DWRITE_1_H -# include -#endif +#include +#include class SkFontDescriptor; struct SkScalerContextRec; @@ -55,25 +54,29 @@ private: , fDWriteFontFace(SkRefComPtr(fontFace)) , fForceGDI(false) { -#if SK_HAS_DWRITE_1_H if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace1))) { // IUnknown::QueryInterface states that if it fails, punk will be set to nullptr. // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx SkASSERT_RELEASE(nullptr == fDWriteFontFace1.get()); } -#endif + if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace2))) { + SkASSERT_RELEASE(nullptr == fDWriteFontFace2.get()); + } + if (!SUCCEEDED(fFactory->QueryInterface(&fFactory2))) { + SkASSERT_RELEASE(nullptr == fFactory2.get()); + } } public: SkTScopedComPtr fFactory; + SkTScopedComPtr fFactory2; SkTScopedComPtr fDWriteFontCollectionLoader; SkTScopedComPtr fDWriteFontFileLoader; SkTScopedComPtr fDWriteFontFamily; SkTScopedComPtr fDWriteFont; SkTScopedComPtr fDWriteFontFace; -#if SK_HAS_DWRITE_1_H SkTScopedComPtr fDWriteFontFace1; -#endif + SkTScopedComPtr fDWriteFontFace2; static DWriteFontTypeface* Create(IDWriteFactory* factory, IDWriteFontFace* fontFace, @@ -119,15 +122,19 @@ protected: SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( PerGlyphInfo, const uint32_t*, uint32_t) const override; void onGetFontDescriptor(SkFontDescriptor*, bool*) const override; - virtual int onCharsToGlyphs(const void* chars, Encoding encoding, - uint16_t glyphs[], int glyphCount) const override; + int onCharsToGlyphs(const void* chars, Encoding encoding, + uint16_t glyphs[], int glyphCount) const override; int onCountGlyphs() const override; int onGetUPEM() const override; void onGetFamilyName(SkString* familyName) const override; SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override + { + return -1; + } int onGetTableTags(SkFontTableTag tags[]) const override; - virtual size_t onGetTableData(SkFontTableTag, size_t offset, - size_t length, void* data) const override; + size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override; private: typedef SkTypeface INHERITED; diff --git a/gfx/skia/skia/src/sfnt/SkOTTable_fvar.h b/gfx/skia/skia/src/sfnt/SkOTTable_fvar.h new file mode 100644 index 000000000000..5d6ffbe4ccfa --- /dev/null +++ b/gfx/skia/skia/src/sfnt/SkOTTable_fvar.h @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOTTable_fvar_DEFINED +#define SkOTTable_fvar_DEFINED + +#include "SkEndian.h" +#include "SkOTTableTypes.h" + +#pragma pack(push, 1) + +struct SkOTTableFontVariations { + static const SK_OT_CHAR TAG0 = 'f'; + static const SK_OT_CHAR TAG1 = 'v'; + static const SK_OT_CHAR TAG2 = 'a'; + static const SK_OT_CHAR TAG3 = 'r'; + static const SK_OT_ULONG TAG = SkOTTableTAG::value; + + SK_OT_USHORT majorVersion; + SK_OT_USHORT minorVersion; + SK_OT_USHORT offsetToAxesArray; + SK_OT_USHORT reserved; + SK_OT_USHORT axisCount; + SK_OT_USHORT axisSize; // Must be 0x0014 in v1.0 + SK_OT_USHORT instanceCount; + SK_OT_USHORT instanceSize; // Must be axisCount * sizeof(Fixed) + (4 | 6) + + struct VariationAxisRecord { + SK_OT_ULONG axisTag; + SK_OT_Fixed minValue; + SK_OT_Fixed defaultValue; + SK_OT_Fixed maxValue; + SK_OT_USHORT flags; // Must be 0 + SK_OT_USHORT axisNameID; + }; // axes[axisCount]; + + template struct InstanceRecord { + SK_OT_USHORT subfamilyNameID; + SK_OT_USHORT flags; // Must be 0 + SK_OT_Fixed coordinates[AxisCount]; + SK_OT_USHORT postScriptNameID; + }; // instances[instanceCount]; +}; + +#pragma pack(pop) + + +#include +static_assert(offsetof(SkOTTableFontVariations, instanceSize) == 14, "SkOTTableFontVariations_instanceSize_not_at_14"); +static_assert(sizeof(SkOTTableFontVariations) == 16, "sizeof_SkOTTableFontVariations_not_16"); + +#endif diff --git a/gfx/skia/skia/src/sfnt/SkOTTable_name.cpp b/gfx/skia/skia/src/sfnt/SkOTTable_name.cpp index 476e0ce36816..9670b6f91eb7 100644 --- a/gfx/skia/skia/src/sfnt/SkOTTable_name.cpp +++ b/gfx/skia/skia/src/sfnt/SkOTTable_name.cpp @@ -46,7 +46,7 @@ static void SkStringFromUTF16BE(const uint16_t* utf16be, size_t length, SkString * In MacRoman the first 128 code points match ASCII code points. * This maps the second 128 MacRoman code points to unicode code points. */ -static uint16_t UnicodeFromMacRoman[0x80] = { +static const uint16_t UnicodeFromMacRoman[0x80] = { 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, @@ -73,7 +73,7 @@ static void SkStringFromMacRoman(const uint8_t* macRoman, size_t length, SkStrin } } -static struct BCP47FromLanguageId { +static const struct BCP47FromLanguageId { uint16_t languageID; const char* bcp47; } diff --git a/gfx/skia/skia/src/sfnt/SkOTUtils.cpp b/gfx/skia/skia/src/sfnt/SkOTUtils.cpp index cb533ff3f254..4d8c023ea455 100644 --- a/gfx/skia/skia/src/sfnt/SkOTUtils.cpp +++ b/gfx/skia/skia/src/sfnt/SkOTUtils.cpp @@ -168,7 +168,7 @@ SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(const SkTypeface& ty if (0 == nameTableSize) { return nullptr; } - SkAutoTDeleteArray nameTableData(new uint8_t[nameTableSize]); + std::unique_ptr nameTableData(new uint8_t[nameTableSize]); size_t copied = typeface.getTableData(nameTag, 0, nameTableSize, nameTableData.get()); if (copied != nameTableSize) { return nullptr; diff --git a/gfx/skia/skia/src/sfnt/SkOTUtils.h b/gfx/skia/skia/src/sfnt/SkOTUtils.h index 1773e69ab6c3..4708a7bb789c 100644 --- a/gfx/skia/skia/src/sfnt/SkOTUtils.h +++ b/gfx/skia/skia/src/sfnt/SkOTUtils.h @@ -61,7 +61,7 @@ struct SkOTUtils { SkOTTableName::Record::NameID::Predefined::Value* fTypes; int fTypesCount; int fTypesIndex; - SkAutoTDeleteArray fNameTableData; + std::unique_ptr fNameTableData; SkOTTableName::Iterator fFamilyNameIter; }; diff --git a/gfx/skia/skia/src/sfnt/SkTTCFHeader.h b/gfx/skia/skia/src/sfnt/SkTTCFHeader.h index 2dc77eea57fe..71c6661e102b 100644 --- a/gfx/skia/skia/src/sfnt/SkTTCFHeader.h +++ b/gfx/skia/skia/src/sfnt/SkTTCFHeader.h @@ -9,6 +9,7 @@ #define SkTTCFHeader_DEFINED #include "SkOTTableTypes.h" +#include "SkSFNTHeader.h" #pragma pack(push, 1) diff --git a/gfx/skia/skia/src/sksl/README b/gfx/skia/skia/src/sksl/README new file mode 100644 index 000000000000..5e8e21b92f33 --- /dev/null +++ b/gfx/skia/skia/src/sksl/README @@ -0,0 +1,55 @@ +Overview +======== + +SkSL ("Skia Shading Language") is a variant of GLSL which is used as Skia's +internal shading language. SkSL is, at its heart, a single standardized version +of GLSL which avoids all of the various version and dialect differences found +in GLSL "in the wild", but it does bring a few of its own changes to the table. + +Skia uses the SkSL compiler to convert SkSL code to GLSL, GLSL ES, or SPIR-V +before handing it over to the graphics driver. + +Differences from GLSL +===================== + +SkSL is based on GLSL 4.5. For the most part, write SkSL exactly as you would +desktop GLSL, and the SkSL compiler will take care of version and dialect +differences (for instance, you always use "in" and "out", and skslc will handle +translating them to "varying" and "attribute" as appropriate). Be aware of the +following differences between SkSL and GLSL: + +* GLSL caps can be referenced via the syntax 'sk_Caps.', e.g. + sk_Caps.sampleVariablesSupport. The value will be a constant boolean or int, + as appropriate. As SkSL supports constant folding and branch elimination, this + means that an 'if' statement which statically queries a cap will collapse down + to the chosen branch, meaning that: + + if (sk_Caps.externalTextureSupport) + do_something(); + else + do_something_else(); + + will compile as if you had written either 'do_something();' or + 'do_something_else();', depending on whether that cap is enabled or not. +* no #version statement is required, and will be ignored if present +* the output color is sk_FragColor (do not declare it) +* use sk_VertexID instead of gl_VertexID +* the fragment coordinate is sk_FragCoord, and is always relative to the upper + left. +* lowp, mediump, and highp are always permitted (but will only be respected if + you run on a device which supports them) +* you do not need to include ".0" to make a number a float (meaning that + "vec2(x, y) * 4" is perfectly legal in SkSL, unlike GLSL where it would often + have to be expressed "vec2(x, y) * 4.0". There is no performance penalty for + this, as the number is converted to a float at compile time) +* type suffixes on numbers (1.0f, 0xFFu) are both unnecessary and unsupported +* creating a smaller vector from a larger vector (e.g. vec2(vec3(1))) is + intentionally disallowed, as it is just a wordier way of performing a swizzle. + Use swizzles instead. +* Use texture() instead of textureProj(), e.g. texture(sampler2D, vec3) is + equivalent to GLSL's textureProj(sampler2D, vec3) +* some built-in functions and one or two rarely-used language features are not + yet supported (sorry!) + +SkSL is still under development, and is expected to diverge further from GLSL +over time. diff --git a/gfx/skia/skia/src/sksl/SkSLCFGGenerator.cpp b/gfx/skia/skia/src/sksl/SkSLCFGGenerator.cpp new file mode 100644 index 000000000000..e2c038075b0a --- /dev/null +++ b/gfx/skia/skia/src/sksl/SkSLCFGGenerator.cpp @@ -0,0 +1,397 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSLCFGGenerator.h" + +#include "ir/SkSLConstructor.h" +#include "ir/SkSLBinaryExpression.h" +#include "ir/SkSLDoStatement.h" +#include "ir/SkSLExpressionStatement.h" +#include "ir/SkSLFieldAccess.h" +#include "ir/SkSLForStatement.h" +#include "ir/SkSLFunctionCall.h" +#include "ir/SkSLIfStatement.h" +#include "ir/SkSLIndexExpression.h" +#include "ir/SkSLPostfixExpression.h" +#include "ir/SkSLPrefixExpression.h" +#include "ir/SkSLReturnStatement.h" +#include "ir/SkSLSwizzle.h" +#include "ir/SkSLSwitchStatement.h" +#include "ir/SkSLTernaryExpression.h" +#include "ir/SkSLVarDeclarationsStatement.h" +#include "ir/SkSLWhileStatement.h" + +namespace SkSL { + +BlockId CFG::newBlock() { + BlockId result = fBlocks.size(); + fBlocks.emplace_back(); + if (fBlocks.size() > 1) { + this->addExit(fCurrent, result); + } + fCurrent = result; + return result; +} + +BlockId CFG::newIsolatedBlock() { + BlockId result = fBlocks.size(); + fBlocks.emplace_back(); + return result; +} + +void CFG::addExit(BlockId from, BlockId to) { + if (from == 0 || fBlocks[from].fEntrances.size()) { + fBlocks[from].fExits.insert(to); + fBlocks[to].fEntrances.insert(from); + } +} + +void CFG::dump() { + for (size_t i = 0; i < fBlocks.size(); i++) { + printf("Block %d\n-------\nBefore: ", (int) i); + const char* separator = ""; + for (auto iter = fBlocks[i].fBefore.begin(); iter != fBlocks[i].fBefore.end(); iter++) { + printf("%s%s = %s", separator, iter->first->description().c_str(), + *iter->second ? (*iter->second)->description().c_str() : ""); + separator = ", "; + } + printf("\nEntrances: "); + separator = ""; + for (BlockId b : fBlocks[i].fEntrances) { + printf("%s%d", separator, (int) b); + separator = ", "; + } + printf("\n"); + for (size_t j = 0; j < fBlocks[i].fNodes.size(); j++) { + BasicBlock::Node& n = fBlocks[i].fNodes[j]; + printf("Node %d: %s\n", (int) j, n.fKind == BasicBlock::Node::kExpression_Kind + ? (*n.fExpression)->description().c_str() + : n.fStatement->description().c_str()); + } + printf("Exits: "); + separator = ""; + for (BlockId b : fBlocks[i].fExits) { + printf("%s%d", separator, (int) b); + separator = ", "; + } + printf("\n\n"); + } +} + +void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr* e, bool constantPropagate) { + ASSERT(e); + switch ((*e)->fKind) { + case Expression::kBinary_Kind: { + BinaryExpression* b = (BinaryExpression*) e->get(); + switch (b->fOperator) { + case Token::LOGICALAND: // fall through + case Token::LOGICALOR: { + // this isn't as precise as it could be -- we don't bother to track that if we + // early exit from a logical and/or, we know which branch of an 'if' we're going + // to hit -- but it won't make much difference in practice. + this->addExpression(cfg, &b->fLeft, constantPropagate); + BlockId start = cfg.fCurrent; + cfg.newBlock(); + this->addExpression(cfg, &b->fRight, constantPropagate); + cfg.newBlock(); + cfg.addExit(start, cfg.fCurrent); + break; + } + case Token::EQ: { + this->addExpression(cfg, &b->fRight, constantPropagate); + this->addLValue(cfg, &b->fLeft); + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ + BasicBlock::Node::kExpression_Kind, + constantPropagate, + e, + nullptr + }); + break; + } + default: + this->addExpression(cfg, &b->fLeft, !Token::IsAssignment(b->fOperator)); + this->addExpression(cfg, &b->fRight, constantPropagate); + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ + BasicBlock::Node::kExpression_Kind, + constantPropagate, + e, + nullptr + }); + } + break; + } + case Expression::kConstructor_Kind: { + Constructor* c = (Constructor*) e->get(); + for (auto& arg : c->fArguments) { + this->addExpression(cfg, &arg, constantPropagate); + } + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, + constantPropagate, e, nullptr }); + break; + } + case Expression::kFunctionCall_Kind: { + FunctionCall* c = (FunctionCall*) e->get(); + for (auto& arg : c->fArguments) { + this->addExpression(cfg, &arg, constantPropagate); + } + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, + constantPropagate, e, nullptr }); + break; + } + case Expression::kFieldAccess_Kind: + this->addExpression(cfg, &((FieldAccess*) e->get())->fBase, constantPropagate); + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, + constantPropagate, e, nullptr }); + break; + case Expression::kIndex_Kind: + this->addExpression(cfg, &((IndexExpression*) e->get())->fBase, constantPropagate); + this->addExpression(cfg, &((IndexExpression*) e->get())->fIndex, constantPropagate); + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, + constantPropagate, e, nullptr }); + break; + case Expression::kPrefix_Kind: { + PrefixExpression* p = (PrefixExpression*) e->get(); + this->addExpression(cfg, &p->fOperand, constantPropagate && + p->fOperator != Token::PLUSPLUS && + p->fOperator != Token::MINUSMINUS); + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, + constantPropagate, e, nullptr }); + break; + } + case Expression::kPostfix_Kind: + this->addExpression(cfg, &((PostfixExpression*) e->get())->fOperand, false); + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, + constantPropagate, e, nullptr }); + break; + case Expression::kSwizzle_Kind: + this->addExpression(cfg, &((Swizzle*) e->get())->fBase, constantPropagate); + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, + constantPropagate, e, nullptr }); + break; + case Expression::kBoolLiteral_Kind: // fall through + case Expression::kFloatLiteral_Kind: // fall through + case Expression::kIntLiteral_Kind: // fall through + case Expression::kVariableReference_Kind: + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, + constantPropagate, e, nullptr }); + break; + case Expression::kTernary_Kind: { + TernaryExpression* t = (TernaryExpression*) e->get(); + this->addExpression(cfg, &t->fTest, constantPropagate); + BlockId start = cfg.fCurrent; + cfg.newBlock(); + this->addExpression(cfg, &t->fIfTrue, constantPropagate); + BlockId next = cfg.newBlock(); + cfg.fCurrent = start; + cfg.newBlock(); + this->addExpression(cfg, &t->fIfFalse, constantPropagate); + cfg.addExit(cfg.fCurrent, next); + cfg.fCurrent = next; + break; + } + case Expression::kFunctionReference_Kind: // fall through + case Expression::kTypeReference_Kind: // fall through + case Expression::kDefined_Kind: + ASSERT(false); + break; + } +} + +// adds expressions that are evaluated as part of resolving an lvalue +void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr* e) { + switch ((*e)->fKind) { + case Expression::kFieldAccess_Kind: + this->addLValue(cfg, &((FieldAccess&) **e).fBase); + break; + case Expression::kIndex_Kind: + this->addLValue(cfg, &((IndexExpression&) **e).fBase); + this->addExpression(cfg, &((IndexExpression&) **e).fIndex, true); + break; + case Expression::kSwizzle_Kind: + this->addLValue(cfg, &((Swizzle&) **e).fBase); + break; + case Expression::kVariableReference_Kind: + break; + default: + // not an lvalue, can't happen + ASSERT(false); + break; + } +} + +void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { + switch (s->fKind) { + case Statement::kBlock_Kind: + for (const auto& child : ((const Block*) s)->fStatements) { + addStatement(cfg, child.get()); + } + break; + case Statement::kIf_Kind: { + IfStatement* ifs = (IfStatement*) s; + this->addExpression(cfg, &ifs->fTest, true); + BlockId start = cfg.fCurrent; + cfg.newBlock(); + this->addStatement(cfg, ifs->fIfTrue.get()); + BlockId next = cfg.newBlock(); + if (ifs->fIfFalse) { + cfg.fCurrent = start; + cfg.newBlock(); + this->addStatement(cfg, ifs->fIfFalse.get()); + cfg.addExit(cfg.fCurrent, next); + cfg.fCurrent = next; + } else { + cfg.addExit(start, next); + } + break; + } + case Statement::kExpression_Kind: { + this->addExpression(cfg, &((ExpressionStatement&) *s).fExpression, true); + break; + } + case Statement::kVarDeclarations_Kind: { + VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) *s); + for (auto& vd : decls.fDeclaration->fVars) { + if (vd.fValue) { + this->addExpression(cfg, &vd.fValue, true); + } + } + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false, + nullptr, s }); + break; + } + case Statement::kDiscard_Kind: + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false, + nullptr, s }); + cfg.fCurrent = cfg.newIsolatedBlock(); + break; + case Statement::kReturn_Kind: { + ReturnStatement& r = ((ReturnStatement&) *s); + if (r.fExpression) { + this->addExpression(cfg, &r.fExpression, true); + } + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false, + nullptr, s }); + cfg.fCurrent = cfg.newIsolatedBlock(); + break; + } + case Statement::kBreak_Kind: + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false, + nullptr, s }); + cfg.addExit(cfg.fCurrent, fLoopExits.top()); + cfg.fCurrent = cfg.newIsolatedBlock(); + break; + case Statement::kContinue_Kind: + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false, + nullptr, s }); + cfg.addExit(cfg.fCurrent, fLoopContinues.top()); + cfg.fCurrent = cfg.newIsolatedBlock(); + break; + case Statement::kWhile_Kind: { + WhileStatement* w = (WhileStatement*) s; + BlockId loopStart = cfg.newBlock(); + fLoopContinues.push(loopStart); + BlockId loopExit = cfg.newIsolatedBlock(); + fLoopExits.push(loopExit); + this->addExpression(cfg, &w->fTest, true); + BlockId test = cfg.fCurrent; + cfg.addExit(test, loopExit); + cfg.newBlock(); + this->addStatement(cfg, w->fStatement.get()); + cfg.addExit(cfg.fCurrent, loopStart); + fLoopContinues.pop(); + fLoopExits.pop(); + cfg.fCurrent = loopExit; + break; + } + case Statement::kDo_Kind: { + DoStatement* d = (DoStatement*) s; + BlockId loopStart = cfg.newBlock(); + fLoopContinues.push(loopStart); + BlockId loopExit = cfg.newIsolatedBlock(); + fLoopExits.push(loopExit); + this->addStatement(cfg, d->fStatement.get()); + this->addExpression(cfg, &d->fTest, true); + cfg.addExit(cfg.fCurrent, loopExit); + cfg.addExit(cfg.fCurrent, loopStart); + fLoopContinues.pop(); + fLoopExits.pop(); + cfg.fCurrent = loopExit; + break; + } + case Statement::kFor_Kind: { + ForStatement* f = (ForStatement*) s; + if (f->fInitializer) { + this->addStatement(cfg, f->fInitializer.get()); + } + BlockId loopStart = cfg.newBlock(); + BlockId next = cfg.newIsolatedBlock(); + fLoopContinues.push(next); + BlockId loopExit = cfg.newIsolatedBlock(); + fLoopExits.push(loopExit); + if (f->fTest) { + this->addExpression(cfg, &f->fTest, true); + BlockId test = cfg.fCurrent; + cfg.addExit(test, loopExit); + } + cfg.newBlock(); + this->addStatement(cfg, f->fStatement.get()); + cfg.addExit(cfg.fCurrent, next); + cfg.fCurrent = next; + if (f->fNext) { + this->addExpression(cfg, &f->fNext, true); + } + cfg.addExit(cfg.fCurrent, loopStart); + fLoopContinues.pop(); + fLoopExits.pop(); + cfg.fCurrent = loopExit; + break; + } + case Statement::kSwitch_Kind: { + SwitchStatement* ss = (SwitchStatement*) s; + this->addExpression(cfg, &ss->fValue, true); + BlockId start = cfg.fCurrent; + BlockId switchExit = cfg.newIsolatedBlock(); + fLoopExits.push(switchExit); + for (const auto& c : ss->fCases) { + cfg.newBlock(); + cfg.addExit(start, cfg.fCurrent); + if (c->fValue) { + // technically this should go in the start block, but it doesn't actually matter + // because it must be constant. Not worth running two loops for. + this->addExpression(cfg, &c->fValue, true); + } + for (const auto& caseStatement : c->fStatements) { + this->addStatement(cfg, caseStatement.get()); + } + } + cfg.addExit(cfg.fCurrent, switchExit); + // note that unlike GLSL, our grammar requires the default case to be last + if (0 == ss->fCases.size() || ss->fCases[ss->fCases.size() - 1]->fValue) { + // switch does not have a default clause, mark that it can skip straight to the end + cfg.addExit(start, switchExit); + } + fLoopExits.pop(); + cfg.fCurrent = switchExit; + break; + } + default: + printf("statement: %s\n", s->description().c_str()); + ABORT("unsupported statement kind"); + } +} + +CFG CFGGenerator::getCFG(const FunctionDefinition& f) { + CFG result; + result.fStart = result.newBlock(); + result.fCurrent = result.fStart; + this->addStatement(result, f.fBody.get()); + result.newBlock(); + result.fExit = result.fCurrent; + return result; +} + +} // namespace diff --git a/gfx/skia/skia/src/sksl/SkSLCFGGenerator.h b/gfx/skia/skia/src/sksl/SkSLCFGGenerator.h new file mode 100644 index 000000000000..0a03d69fc625 --- /dev/null +++ b/gfx/skia/skia/src/sksl/SkSLCFGGenerator.h @@ -0,0 +1,99 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_CFGGENERATOR +#define SKSL_CFGGENERATOR + +#include "ir/SkSLExpression.h" +#include "ir/SkSLFunctionDefinition.h" + +#include +#include + +namespace SkSL { + +// index of a block within CFG.fBlocks +typedef size_t BlockId; + +struct BasicBlock { + struct Node { + enum Kind { + kStatement_Kind, + kExpression_Kind + }; + + Kind fKind; + // if false, this node should not be subject to constant propagation. This happens with + // compound assignment (i.e. x *= 2), in which the value x is used as an rvalue for + // multiplication by 2 and then as an lvalue for assignment purposes. Since there is only + // one "x" node, replacing it with a constant would break the assignment and we suppress + // it. Down the road, we should handle this more elegantly by substituting a regular + // assignment if the target is constant (i.e. x = 1; x *= 2; should become x = 1; x = 1 * 2; + // and then collapse down to a simple x = 2;). + bool fConstantPropagation; + std::unique_ptr* fExpression; + const Statement* fStatement; + }; + + std::vector fNodes; + std::set fEntrances; + std::set fExits; + // variable definitions upon entering this basic block (null expression = undefined) + DefinitionMap fBefore; +}; + +struct CFG { + BlockId fStart; + BlockId fExit; + std::vector fBlocks; + + void dump(); + +private: + BlockId fCurrent; + + // Adds a new block, adds an exit* from the current block to the new block, then marks the new + // block as the current block + // *see note in addExit() + BlockId newBlock(); + + // Adds a new block, but does not mark it current or add an exit from the current block + BlockId newIsolatedBlock(); + + // Adds an exit from the 'from' block to the 'to' block + // Note that we skip adding the exit if the 'from' block is itself unreachable; this means that + // we don't actually have to trace the tree to see if a particular block is unreachable, we can + // just check to see if it has any entrances. This does require a bit of care in the order in + // which we set the CFG up. + void addExit(BlockId from, BlockId to); + + friend class CFGGenerator; +}; + +/** + * Converts functions into control flow graphs. + */ +class CFGGenerator { +public: + CFGGenerator() {} + + CFG getCFG(const FunctionDefinition& f); + +private: + void addStatement(CFG& cfg, const Statement* s); + + void addExpression(CFG& cfg, std::unique_ptr* e, bool constantPropagate); + + void addLValue(CFG& cfg, std::unique_ptr* e); + + std::stack fLoopContinues; + std::stack fLoopExits; +}; + +} + +#endif diff --git a/gfx/skia/skia/src/sksl/SkSLCodeGenerator.h b/gfx/skia/skia/src/sksl/SkSLCodeGenerator.h index 7fa8c1931a9f..f6f990503cff 100644 --- a/gfx/skia/skia/src/sksl/SkSLCodeGenerator.h +++ b/gfx/skia/skia/src/sksl/SkSLCodeGenerator.h @@ -4,13 +4,11 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_CODEGENERATOR #define SKSL_CODEGENERATOR #include "ir/SkSLProgram.h" -#include -#include namespace SkSL { @@ -20,9 +18,20 @@ namespace SkSL { */ class CodeGenerator { public: + CodeGenerator(const Program* program, ErrorReporter* errors, OutputStream* out) + : fProgram(*program) + , fErrors(*errors) + , fOut(out) {} + virtual ~CodeGenerator() {} - - virtual void generateCode(const Program& program, std::ostream& out) = 0; + + virtual bool generateCode() = 0; + +protected: + + const Program& fProgram; + ErrorReporter& fErrors; + OutputStream* fOut; }; } // namespace diff --git a/gfx/skia/skia/src/sksl/SkSLCompiler.cpp b/gfx/skia/skia/src/sksl/SkSLCompiler.cpp index d2ad81223e8c..ea87e999385a 100644 --- a/gfx/skia/skia/src/sksl/SkSLCompiler.cpp +++ b/gfx/skia/skia/src/sksl/SkSLCompiler.cpp @@ -4,43 +4,52 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #include "SkSLCompiler.h" -#include -#include - +#include "ast/SkSLASTPrecision.h" +#include "SkSLCFGGenerator.h" +#include "SkSLGLSLCodeGenerator.h" #include "SkSLIRGenerator.h" #include "SkSLParser.h" #include "SkSLSPIRVCodeGenerator.h" #include "ir/SkSLExpression.h" #include "ir/SkSLIntLiteral.h" +#include "ir/SkSLModifiersDeclaration.h" #include "ir/SkSLSymbolTable.h" -#include "ir/SkSLVarDeclaration.h" -#include "SkMutex.h" +#include "ir/SkSLUnresolvedFunction.h" +#include "ir/SkSLVarDeclarations.h" + +#ifdef SK_ENABLE_SPIRV_VALIDATION +#include "spirv-tools/libspirv.hpp" +#endif #define STRINGIFY(x) #x // include the built-in shader symbols as static strings -static std::string SKSL_INCLUDE = +static const char* SKSL_INCLUDE = #include "sksl.include" ; -static std::string SKSL_VERT_INCLUDE = +static const char* SKSL_VERT_INCLUDE = #include "sksl_vert.include" ; -static std::string SKSL_FRAG_INCLUDE = +static const char* SKSL_FRAG_INCLUDE = #include "sksl_frag.include" ; +static const char* SKSL_GEOM_INCLUDE = +#include "sksl_geom.include" +; + namespace SkSL { -Compiler::Compiler() +Compiler::Compiler() : fErrorCount(0) { - auto types = std::shared_ptr(new SymbolTable(*this)); - auto symbols = std::shared_ptr(new SymbolTable(types, *this)); + auto types = std::shared_ptr(new SymbolTable(this)); + auto symbols = std::shared_ptr(new SymbolTable(types, this)); fIRGenerator = new IRGenerator(&fContext, symbols, *this); fTypes = types; #define ADD_TYPE(t) types->addWithoutOwnership(fContext.f ## t ## _Type->fName, \ @@ -67,17 +76,17 @@ Compiler::Compiler() ADD_TYPE(BVec3); ADD_TYPE(BVec4); ADD_TYPE(Mat2x2); - types->addWithoutOwnership("mat2x2", fContext.fMat2x2_Type.get()); + types->addWithoutOwnership(String("mat2x2"), fContext.fMat2x2_Type.get()); ADD_TYPE(Mat2x3); ADD_TYPE(Mat2x4); ADD_TYPE(Mat3x2); ADD_TYPE(Mat3x3); - types->addWithoutOwnership("mat3x3", fContext.fMat3x3_Type.get()); + types->addWithoutOwnership(String("mat3x3"), fContext.fMat3x3_Type.get()); ADD_TYPE(Mat3x4); ADD_TYPE(Mat4x2); ADD_TYPE(Mat4x3); ADD_TYPE(Mat4x4); - types->addWithoutOwnership("mat4x4", fContext.fMat4x4_Type.get()); + types->addWithoutOwnership(String("mat4x4"), fContext.fMat4x4_Type.get()); ADD_TYPE(GenType); ADD_TYPE(GenDType); ADD_TYPE(GenIType); @@ -97,6 +106,7 @@ Compiler::Compiler() ADD_TYPE(Sampler1D); ADD_TYPE(Sampler2D); ADD_TYPE(Sampler3D); + ADD_TYPE(SamplerExternalOES); ADD_TYPE(SamplerCube); ADD_TYPE(Sampler2DRect); ADD_TYPE(Sampler1DArray); @@ -106,6 +116,14 @@ Compiler::Compiler() ADD_TYPE(Sampler2DMS); ADD_TYPE(Sampler2DMSArray); + ADD_TYPE(ISampler2D); + + ADD_TYPE(Image2D); + ADD_TYPE(IImage2D); + + ADD_TYPE(SubpassInput); + ADD_TYPE(SubpassInputMS); + ADD_TYPE(GSampler1D); ADD_TYPE(GSampler2D); ADD_TYPE(GSampler3D); @@ -128,8 +146,15 @@ Compiler::Compiler() ADD_TYPE(GSampler2DArrayShadow); ADD_TYPE(GSamplerCubeArrayShadow); - std::vector> ignored; - this->internalConvertProgram(SKSL_INCLUDE, &ignored); + String skCapsName("sk_Caps"); + Variable* skCaps = new Variable(Position(), Modifiers(), skCapsName, + *fContext.fSkCaps_Type, Variable::kGlobal_Storage); + fIRGenerator->fSymbolTable->add(skCapsName, std::unique_ptr(skCaps)); + + Modifiers::Flag ignored1; + std::vector> ignored2; + this->internalConvertProgram(String(SKSL_INCLUDE), &ignored1, &ignored2); + fIRGenerator->fSymbolTable->markAllFunctionsBuiltin(); ASSERT(!fErrorCount); } @@ -137,19 +162,252 @@ Compiler::~Compiler() { delete fIRGenerator; } -void Compiler::internalConvertProgram(std::string text, +// add the definition created by assigning to the lvalue to the definition set +void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr* expr, + DefinitionMap* definitions) { + switch (lvalue->fKind) { + case Expression::kVariableReference_Kind: { + const Variable& var = ((VariableReference*) lvalue)->fVariable; + if (var.fStorage == Variable::kLocal_Storage) { + (*definitions)[&var] = expr; + } + break; + } + case Expression::kSwizzle_Kind: + // We consider the variable written to as long as at least some of its components have + // been written to. This will lead to some false negatives (we won't catch it if you + // write to foo.x and then read foo.y), but being stricter could lead to false positives + // (we write to foo.x, and then pass foo to a function which happens to only read foo.x, + // but since we pass foo as a whole it is flagged as an error) unless we perform a much + // more complicated whole-program analysis. This is probably good enough. + this->addDefinition(((Swizzle*) lvalue)->fBase.get(), + (std::unique_ptr*) &fContext.fDefined_Expression, + definitions); + break; + case Expression::kIndex_Kind: + // see comments in Swizzle + this->addDefinition(((IndexExpression*) lvalue)->fBase.get(), + (std::unique_ptr*) &fContext.fDefined_Expression, + definitions); + break; + case Expression::kFieldAccess_Kind: + // see comments in Swizzle + this->addDefinition(((FieldAccess*) lvalue)->fBase.get(), + (std::unique_ptr*) &fContext.fDefined_Expression, + definitions); + break; + default: + // not an lvalue, can't happen + ASSERT(false); + } +} + +// add local variables defined by this node to the set +void Compiler::addDefinitions(const BasicBlock::Node& node, + DefinitionMap* definitions) { + switch (node.fKind) { + case BasicBlock::Node::kExpression_Kind: { + ASSERT(node.fExpression); + const Expression* expr = (Expression*) node.fExpression->get(); + switch (expr->fKind) { + case Expression::kBinary_Kind: { + BinaryExpression* b = (BinaryExpression*) expr; + if (b->fOperator == Token::EQ) { + this->addDefinition(b->fLeft.get(), &b->fRight, definitions); + } else if (Token::IsAssignment(b->fOperator)) { + this->addDefinition( + b->fLeft.get(), + (std::unique_ptr*) &fContext.fDefined_Expression, + definitions); + + } + break; + } + case Expression::kPrefix_Kind: { + const PrefixExpression* p = (PrefixExpression*) expr; + if (p->fOperator == Token::MINUSMINUS || p->fOperator == Token::PLUSPLUS) { + this->addDefinition( + p->fOperand.get(), + (std::unique_ptr*) &fContext.fDefined_Expression, + definitions); + } + break; + } + case Expression::kPostfix_Kind: { + const PostfixExpression* p = (PostfixExpression*) expr; + if (p->fOperator == Token::MINUSMINUS || p->fOperator == Token::PLUSPLUS) { + this->addDefinition( + p->fOperand.get(), + (std::unique_ptr*) &fContext.fDefined_Expression, + definitions); + + } + break; + } + default: + break; + } + break; + } + case BasicBlock::Node::kStatement_Kind: { + const Statement* stmt = (Statement*) node.fStatement; + if (stmt->fKind == Statement::kVarDeclarations_Kind) { + VarDeclarationsStatement* vd = (VarDeclarationsStatement*) stmt; + for (VarDeclaration& decl : vd->fDeclaration->fVars) { + if (decl.fValue) { + (*definitions)[decl.fVar] = &decl.fValue; + } + } + } + break; + } + } +} + +void Compiler::scanCFG(CFG* cfg, BlockId blockId, std::set* workList) { + BasicBlock& block = cfg->fBlocks[blockId]; + + // compute definitions after this block + DefinitionMap after = block.fBefore; + for (const BasicBlock::Node& n : block.fNodes) { + this->addDefinitions(n, &after); + } + + // propagate definitions to exits + for (BlockId exitId : block.fExits) { + BasicBlock& exit = cfg->fBlocks[exitId]; + for (const auto& pair : after) { + std::unique_ptr* e1 = pair.second; + auto found = exit.fBefore.find(pair.first); + if (found == exit.fBefore.end()) { + // exit has no definition for it, just copy it + workList->insert(exitId); + exit.fBefore[pair.first] = e1; + } else { + // exit has a (possibly different) value already defined + std::unique_ptr* e2 = exit.fBefore[pair.first]; + if (e1 != e2) { + // definition has changed, merge and add exit block to worklist + workList->insert(exitId); + if (e1 && e2) { + exit.fBefore[pair.first] = + (std::unique_ptr*) &fContext.fDefined_Expression; + } else { + exit.fBefore[pair.first] = nullptr; + } + } + } + } + } +} + +// returns a map which maps all local variables in the function to null, indicating that their value +// is initially unknown +static DefinitionMap compute_start_state(const CFG& cfg) { + DefinitionMap result; + for (const auto& block : cfg.fBlocks) { + for (const auto& node : block.fNodes) { + if (node.fKind == BasicBlock::Node::kStatement_Kind) { + ASSERT(node.fStatement); + const Statement* s = node.fStatement; + if (s->fKind == Statement::kVarDeclarations_Kind) { + const VarDeclarationsStatement* vd = (const VarDeclarationsStatement*) s; + for (const VarDeclaration& decl : vd->fDeclaration->fVars) { + result[decl.fVar] = nullptr; + } + } + } + } + } + return result; +} + +void Compiler::scanCFG(const FunctionDefinition& f) { + CFG cfg = CFGGenerator().getCFG(f); + + // compute the data flow + cfg.fBlocks[cfg.fStart].fBefore = compute_start_state(cfg); + std::set workList; + for (BlockId i = 0; i < cfg.fBlocks.size(); i++) { + workList.insert(i); + } + while (workList.size()) { + BlockId next = *workList.begin(); + workList.erase(workList.begin()); + this->scanCFG(&cfg, next, &workList); + } + + // check for unreachable code + for (size_t i = 0; i < cfg.fBlocks.size(); i++) { + if (i != cfg.fStart && !cfg.fBlocks[i].fEntrances.size() && + cfg.fBlocks[i].fNodes.size()) { + Position p; + switch (cfg.fBlocks[i].fNodes[0].fKind) { + case BasicBlock::Node::kStatement_Kind: + p = cfg.fBlocks[i].fNodes[0].fStatement->fPosition; + break; + case BasicBlock::Node::kExpression_Kind: + p = (*cfg.fBlocks[i].fNodes[0].fExpression)->fPosition; + break; + } + this->error(p, String("unreachable")); + } + } + if (fErrorCount) { + return; + } + + // check for undefined variables, perform constant propagation + for (BasicBlock& b : cfg.fBlocks) { + DefinitionMap definitions = b.fBefore; + for (BasicBlock::Node& n : b.fNodes) { + if (n.fKind == BasicBlock::Node::kExpression_Kind) { + ASSERT(n.fExpression); + Expression* expr = n.fExpression->get(); + if (n.fConstantPropagation) { + std::unique_ptr optimized = expr->constantPropagate(*fIRGenerator, + definitions); + if (optimized) { + n.fExpression->reset(optimized.release()); + expr = n.fExpression->get(); + } + } + if (expr->fKind == Expression::kVariableReference_Kind) { + const Variable& var = ((VariableReference*) expr)->fVariable; + if (var.fStorage == Variable::kLocal_Storage && + !definitions[&var]) { + this->error(expr->fPosition, + "'" + var.fName + "' has not been assigned"); + } + } + } + this->addDefinitions(n, &definitions); + } + } + + // check for missing return + if (f.fDeclaration.fReturnType != *fContext.fVoid_Type) { + if (cfg.fBlocks[cfg.fExit].fEntrances.size()) { + this->error(f.fPosition, String("function can exit without returning a value")); + } + } +} + +void Compiler::internalConvertProgram(String text, + Modifiers::Flag* defaultPrecision, std::vector>* result) { Parser parser(text, *fTypes, *this); std::vector> parsed = parser.file(); if (fErrorCount) { return; } + *defaultPrecision = Modifiers::kHighp_Flag; for (size_t i = 0; i < parsed.size(); i++) { ASTDeclaration& decl = *parsed[i]; switch (decl.fKind) { case ASTDeclaration::kVar_Kind: { std::unique_ptr s = fIRGenerator->convertVarDeclarations( - (ASTVarDeclarations&) decl, + (ASTVarDeclarations&) decl, Variable::kGlobal_Storage); if (s) { result->push_back(std::move(s)); @@ -159,6 +417,15 @@ void Compiler::internalConvertProgram(std::string text, case ASTDeclaration::kFunction_Kind: { std::unique_ptr f = fIRGenerator->convertFunction( (ASTFunction&) decl); + if (!fErrorCount && f) { + this->scanCFG(*f); + result->push_back(std::move(f)); + } + break; + } + case ASTDeclaration::kModifiers_Kind: { + std::unique_ptr f = fIRGenerator->convertModifiersDeclaration( + (ASTModifiersDeclaration&) decl); if (f) { result->push_back(std::move(f)); } @@ -179,40 +446,107 @@ void Compiler::internalConvertProgram(std::string text, } break; } + case ASTDeclaration::kPrecision_Kind: { + *defaultPrecision = ((ASTPrecision&) decl).fPrecision; + break; + } default: ABORT("unsupported declaration: %s\n", decl.description().c_str()); } } } -std::unique_ptr Compiler::convertProgram(Program::Kind kind, std::string text) { +std::unique_ptr Compiler::convertProgram(Program::Kind kind, String text, + const Program::Settings& settings) { fErrorText = ""; fErrorCount = 0; - fIRGenerator->pushSymbolTable(); + fIRGenerator->start(&settings); std::vector> elements; + Modifiers::Flag ignored; switch (kind) { case Program::kVertex_Kind: - this->internalConvertProgram(SKSL_VERT_INCLUDE, &elements); + this->internalConvertProgram(String(SKSL_VERT_INCLUDE), &ignored, &elements); break; case Program::kFragment_Kind: - this->internalConvertProgram(SKSL_FRAG_INCLUDE, &elements); + this->internalConvertProgram(String(SKSL_FRAG_INCLUDE), &ignored, &elements); + break; + case Program::kGeometry_Kind: + this->internalConvertProgram(String(SKSL_GEOM_INCLUDE), &ignored, &elements); break; } - this->internalConvertProgram(text, &elements); - auto result = std::unique_ptr(new Program(kind, std::move(elements), - fIRGenerator->fSymbolTable));; - fIRGenerator->popSymbolTable(); + fIRGenerator->fSymbolTable->markAllFunctionsBuiltin(); + Modifiers::Flag defaultPrecision; + this->internalConvertProgram(text, &defaultPrecision, &elements); + auto result = std::unique_ptr(new Program(kind, settings, defaultPrecision, &fContext, + std::move(elements), + fIRGenerator->fSymbolTable, + fIRGenerator->fInputs)); + fIRGenerator->finish(); + this->writeErrorCount(); + if (fErrorCount) { + return nullptr; + } + return result; +} + +bool Compiler::toSPIRV(const Program& program, OutputStream& out) { +#ifdef SK_ENABLE_SPIRV_VALIDATION + StringStream buffer; + SPIRVCodeGenerator cg(&fContext, &program, this, &buffer); + bool result = cg.generateCode(); + if (result) { + spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0); + ASSERT(0 == buffer.size() % 4); + auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) { + SkDebugf("SPIR-V validation error: %s\n", m); + }; + tools.SetMessageConsumer(dumpmsg); + // Verify that the SPIR-V we produced is valid. If this assert fails, check the logs prior + // to the failure to see the validation errors. + ASSERT_RESULT(tools.Validate((const uint32_t*) buffer.data(), buffer.size() / 4)); + out.write(buffer.data(), buffer.size()); + } +#else + SPIRVCodeGenerator cg(&fContext, &program, this, &out); + bool result = cg.generateCode(); +#endif this->writeErrorCount(); return result; } -void Compiler::error(Position position, std::string msg) { +bool Compiler::toSPIRV(const Program& program, String* out) { + StringStream buffer; + bool result = this->toSPIRV(program, buffer); + if (result) { + *out = String(buffer.data(), buffer.size()); + } + return result; +} + +bool Compiler::toGLSL(const Program& program, OutputStream& out) { + GLSLCodeGenerator cg(&fContext, &program, this, &out); + bool result = cg.generateCode(); + this->writeErrorCount(); + return result; +} + +bool Compiler::toGLSL(const Program& program, String* out) { + StringStream buffer; + bool result = this->toGLSL(program, buffer); + if (result) { + *out = String(buffer.data(), buffer.size()); + } + return result; +} + + +void Compiler::error(Position position, String msg) { fErrorCount++; fErrorText += "error: " + position.description() + ": " + msg.c_str() + "\n"; } -std::string Compiler::errorText() { - std::string result = fErrorText; +String Compiler::errorText() { + String result = fErrorText; return result; } @@ -226,44 +560,4 @@ void Compiler::writeErrorCount() { } } -bool Compiler::toSPIRV(Program::Kind kind, const std::string& text, std::ostream& out) { - auto program = this->convertProgram(kind, text); - if (fErrorCount == 0) { - SkSL::SPIRVCodeGenerator cg(&fContext); - cg.generateCode(*program.get(), out); - ASSERT(!out.rdstate()); - } - return fErrorCount == 0; -} - -bool Compiler::toSPIRV(Program::Kind kind, const std::string& text, std::string* out) { - std::stringstream buffer; - bool result = this->toSPIRV(kind, text, buffer); - if (result) { - *out = buffer.str(); - } - return result; -} - -bool Compiler::toGLSL(Program::Kind kind, const std::string& text, GLCaps caps, - std::ostream& out) { - auto program = this->convertProgram(kind, text); - if (fErrorCount == 0) { - SkSL::GLSLCodeGenerator cg(&fContext, caps); - cg.generateCode(*program.get(), out); - ASSERT(!out.rdstate()); - } - return fErrorCount == 0; -} - -bool Compiler::toGLSL(Program::Kind kind, const std::string& text, GLCaps caps, - std::string* out) { - std::stringstream buffer; - bool result = this->toGLSL(kind, text, caps, buffer); - if (result) { - *out = buffer.str(); - } - return result; -} - } // namespace diff --git a/gfx/skia/skia/src/sksl/SkSLCompiler.h b/gfx/skia/skia/src/sksl/SkSLCompiler.h index 9cd1eac3f94f..7e3c83edffdc 100644 --- a/gfx/skia/skia/src/sksl/SkSLCompiler.h +++ b/gfx/skia/skia/src/sksl/SkSLCompiler.h @@ -4,16 +4,25 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_COMPILER #define SKSL_COMPILER +#include #include #include "ir/SkSLProgram.h" #include "ir/SkSLSymbolTable.h" +#include "SkSLCFGGenerator.h" #include "SkSLContext.h" #include "SkSLErrorReporter.h" -#include "SkSLGLSLCodeGenerator.h" +#include "SkSLIRGenerator.h" + +#define SK_FRAGCOLOR_BUILTIN 10001 +#define SK_IN_BUILTIN 10002 +#define SK_FRAGCOORD_BUILTIN 15 +#define SK_VERTEXID_BUILTIN 5 +#define SK_CLIPDISTANCE_BUILTIN 3 +#define SK_INVOCATIONID_BUILTIN 8 namespace SkSL { @@ -21,44 +30,60 @@ class IRGenerator; /** * Main compiler entry point. This is a traditional compiler design which first parses the .sksl - * file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to + * file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to * produce a Program (a tree of IRNodes), then feeds the Program into a CodeGenerator to produce * compiled output. + * + * See the README for information about SkSL. */ class Compiler : public ErrorReporter { public: Compiler(); - ~Compiler(); + ~Compiler() override; - std::unique_ptr convertProgram(Program::Kind kind, std::string text); + std::unique_ptr convertProgram(Program::Kind kind, String text, + const Program::Settings& settings); - bool toSPIRV(Program::Kind kind, const std::string& text, std::ostream& out); - - bool toSPIRV(Program::Kind kind, const std::string& text, std::string* out); + bool toSPIRV(const Program& program, OutputStream& out); - bool toGLSL(Program::Kind kind, const std::string& text, GLCaps caps, std::ostream& out); - - bool toGLSL(Program::Kind kind, const std::string& text, GLCaps caps, std::string* out); + bool toSPIRV(const Program& program, String* out); - void error(Position position, std::string msg) override; + bool toGLSL(const Program& program, OutputStream& out); - std::string errorText(); + bool toGLSL(const Program& program, String* out); + + void error(Position position, String msg) override; + + String errorText(); void writeErrorCount(); -private: + int errorCount() override { + return fErrorCount; + } - void internalConvertProgram(std::string text, +private: + void addDefinition(const Expression* lvalue, std::unique_ptr* expr, + DefinitionMap* definitions); + + void addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions); + + void scanCFG(CFG* cfg, BlockId block, std::set* workList); + + void scanCFG(const FunctionDefinition& f); + + void internalConvertProgram(String text, + Modifiers::Flag* defaultPrecision, std::vector>* result); std::shared_ptr fTypes; IRGenerator* fIRGenerator; - std::string fSkiaVertText; // FIXME store parsed version instead + String fSkiaVertText; // FIXME store parsed version instead Context fContext; int fErrorCount; - std::string fErrorText; + String fErrorText; }; } // namespace diff --git a/gfx/skia/skia/src/sksl/SkSLContext.h b/gfx/skia/skia/src/sksl/SkSLContext.h index 1f124d05eb03..450baa5d77d2 100644 --- a/gfx/skia/skia/src/sksl/SkSLContext.h +++ b/gfx/skia/skia/src/sksl/SkSLContext.h @@ -4,11 +4,12 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_CONTEXT #define SKSL_CONTEXT #include "ir/SkSLType.h" +#include "ir/SkSLExpression.h" namespace SkSL { @@ -18,107 +19,144 @@ namespace SkSL { class Context { public: Context() - : fVoid_Type(new Type("void")) - , fDouble_Type(new Type("double", true)) - , fDVec2_Type(new Type("dvec2", *fDouble_Type, 2)) - , fDVec3_Type(new Type("dvec3", *fDouble_Type, 3)) - , fDVec4_Type(new Type("dvec4", *fDouble_Type, 4)) - , fFloat_Type(new Type("float", true, { fDouble_Type.get() })) - , fVec2_Type(new Type("vec2", *fFloat_Type, 2)) - , fVec3_Type(new Type("vec3", *fFloat_Type, 3)) - , fVec4_Type(new Type("vec4", *fFloat_Type, 4)) - , fUInt_Type(new Type("uint", true, { fFloat_Type.get(), fDouble_Type.get() })) - , fUVec2_Type(new Type("uvec2", *fUInt_Type, 2)) - , fUVec3_Type(new Type("uvec3", *fUInt_Type, 3)) - , fUVec4_Type(new Type("uvec4", *fUInt_Type, 4)) - , fInt_Type(new Type("int", true, { fUInt_Type.get(), fFloat_Type.get(), fDouble_Type.get() })) - , fIVec2_Type(new Type("ivec2", *fInt_Type, 2)) - , fIVec3_Type(new Type("ivec3", *fInt_Type, 3)) - , fIVec4_Type(new Type("ivec4", *fInt_Type, 4)) - , fBool_Type(new Type("bool", false)) - , fBVec2_Type(new Type("bvec2", *fBool_Type, 2)) - , fBVec3_Type(new Type("bvec3", *fBool_Type, 3)) - , fBVec4_Type(new Type("bvec4", *fBool_Type, 4)) - , fMat2x2_Type(new Type("mat2", *fFloat_Type, 2, 2)) - , fMat2x3_Type(new Type("mat2x3", *fFloat_Type, 2, 3)) - , fMat2x4_Type(new Type("mat2x4", *fFloat_Type, 2, 4)) - , fMat3x2_Type(new Type("mat3x2", *fFloat_Type, 3, 2)) - , fMat3x3_Type(new Type("mat3", *fFloat_Type, 3, 3)) - , fMat3x4_Type(new Type("mat3x4", *fFloat_Type, 3, 4)) - , fMat4x2_Type(new Type("mat4x2", *fFloat_Type, 4, 2)) - , fMat4x3_Type(new Type("mat4x3", *fFloat_Type, 4, 3)) - , fMat4x4_Type(new Type("mat4", *fFloat_Type, 4, 4)) - , fDMat2x2_Type(new Type("dmat2", *fFloat_Type, 2, 2)) - , fDMat2x3_Type(new Type("dmat2x3", *fFloat_Type, 2, 3)) - , fDMat2x4_Type(new Type("dmat2x4", *fFloat_Type, 2, 4)) - , fDMat3x2_Type(new Type("dmat3x2", *fFloat_Type, 3, 2)) - , fDMat3x3_Type(new Type("dmat3", *fFloat_Type, 3, 3)) - , fDMat3x4_Type(new Type("dmat3x4", *fFloat_Type, 3, 4)) - , fDMat4x2_Type(new Type("dmat4x2", *fFloat_Type, 4, 2)) - , fDMat4x3_Type(new Type("dmat4x3", *fFloat_Type, 4, 3)) - , fDMat4x4_Type(new Type("dmat4", *fFloat_Type, 4, 4)) - , fSampler1D_Type(new Type("sampler1D", SpvDim1D, false, false, false, true)) - , fSampler2D_Type(new Type("sampler2D", SpvDim2D, false, false, false, true)) - , fSampler3D_Type(new Type("sampler3D", SpvDim3D, false, false, false, true)) - , fSamplerCube_Type(new Type("samplerCube")) - , fSampler2DRect_Type(new Type("sampler2DRect")) - , fSampler1DArray_Type(new Type("sampler1DArray")) - , fSampler2DArray_Type(new Type("sampler2DArray")) - , fSamplerCubeArray_Type(new Type("samplerCubeArray")) - , fSamplerBuffer_Type(new Type("samplerBuffer")) - , fSampler2DMS_Type(new Type("sampler2DMS")) - , fSampler2DMSArray_Type(new Type("sampler2DMSArray")) - , fSampler1DShadow_Type(new Type("sampler1DShadow")) - , fSampler2DShadow_Type(new Type("sampler2DShadow")) - , fSamplerCubeShadow_Type(new Type("samplerCubeShadow")) - , fSampler2DRectShadow_Type(new Type("sampler2DRectShadow")) - , fSampler1DArrayShadow_Type(new Type("sampler1DArrayShadow")) - , fSampler2DArrayShadow_Type(new Type("sampler2DArrayShadow")) - , fSamplerCubeArrayShadow_Type(new Type("samplerCubeArrayShadow")) + : fInvalid_Type(new Type(String(""))) + , fVoid_Type(new Type(String("void"))) + , fDouble_Type(new Type(String("double"), true)) + , fDVec2_Type(new Type(String("dvec2"), *fDouble_Type, 2)) + , fDVec3_Type(new Type(String("dvec3"), *fDouble_Type, 3)) + , fDVec4_Type(new Type(String("dvec4"), *fDouble_Type, 4)) + , fFloat_Type(new Type(String("float"), true, { fDouble_Type.get() })) + , fVec2_Type(new Type(String("vec2"), *fFloat_Type, 2)) + , fVec3_Type(new Type(String("vec3"), *fFloat_Type, 3)) + , fVec4_Type(new Type(String("vec4"), *fFloat_Type, 4)) + , fUInt_Type(new Type(String("uint"), true, { fFloat_Type.get(), fDouble_Type.get() })) + , fUVec2_Type(new Type(String("uvec2"), *fUInt_Type, 2)) + , fUVec3_Type(new Type(String("uvec3"), *fUInt_Type, 3)) + , fUVec4_Type(new Type(String("uvec4"), *fUInt_Type, 4)) + , fInt_Type(new Type(String("int"), true, { fUInt_Type.get(), fFloat_Type.get(), + fDouble_Type.get() })) + , fIVec2_Type(new Type(String("ivec2"), *fInt_Type, 2)) + , fIVec3_Type(new Type(String("ivec3"), *fInt_Type, 3)) + , fIVec4_Type(new Type(String("ivec4"), *fInt_Type, 4)) + , fBool_Type(new Type(String("bool"), false)) + , fBVec2_Type(new Type(String("bvec2"), *fBool_Type, 2)) + , fBVec3_Type(new Type(String("bvec3"), *fBool_Type, 3)) + , fBVec4_Type(new Type(String("bvec4"), *fBool_Type, 4)) + , fMat2x2_Type(new Type(String("mat2"), *fFloat_Type, 2, 2)) + , fMat2x3_Type(new Type(String("mat2x3"), *fFloat_Type, 2, 3)) + , fMat2x4_Type(new Type(String("mat2x4"), *fFloat_Type, 2, 4)) + , fMat3x2_Type(new Type(String("mat3x2"), *fFloat_Type, 3, 2)) + , fMat3x3_Type(new Type(String("mat3"), *fFloat_Type, 3, 3)) + , fMat3x4_Type(new Type(String("mat3x4"), *fFloat_Type, 3, 4)) + , fMat4x2_Type(new Type(String("mat4x2"), *fFloat_Type, 4, 2)) + , fMat4x3_Type(new Type(String("mat4x3"), *fFloat_Type, 4, 3)) + , fMat4x4_Type(new Type(String("mat4"), *fFloat_Type, 4, 4)) + , fDMat2x2_Type(new Type(String("dmat2"), *fFloat_Type, 2, 2)) + , fDMat2x3_Type(new Type(String("dmat2x3"), *fFloat_Type, 2, 3)) + , fDMat2x4_Type(new Type(String("dmat2x4"), *fFloat_Type, 2, 4)) + , fDMat3x2_Type(new Type(String("dmat3x2"), *fFloat_Type, 3, 2)) + , fDMat3x3_Type(new Type(String("dmat3"), *fFloat_Type, 3, 3)) + , fDMat3x4_Type(new Type(String("dmat3x4"), *fFloat_Type, 3, 4)) + , fDMat4x2_Type(new Type(String("dmat4x2"), *fFloat_Type, 4, 2)) + , fDMat4x3_Type(new Type(String("dmat4x3"), *fFloat_Type, 4, 3)) + , fDMat4x4_Type(new Type(String("dmat4"), *fFloat_Type, 4, 4)) + , fSampler1D_Type(new Type(String("sampler1D"), SpvDim1D, false, false, false, true)) + , fSampler2D_Type(new Type(String("sampler2D"), SpvDim2D, false, false, false, true)) + , fSampler3D_Type(new Type(String("sampler3D"), SpvDim3D, false, false, false, true)) + , fSamplerExternalOES_Type(new Type(String("samplerExternalOES"), SpvDim2D, false, false, + false, true)) + , fSamplerCube_Type(new Type(String("samplerCube"), SpvDimCube, false, false, false, true)) + , fSampler2DRect_Type(new Type(String("sampler2DRect"), SpvDimRect, false, false, false, + true)) + , fSampler1DArray_Type(new Type(String("sampler1DArray"))) + , fSampler2DArray_Type(new Type(String("sampler2DArray"))) + , fSamplerCubeArray_Type(new Type(String("samplerCubeArray"))) + , fSamplerBuffer_Type(new Type(String("samplerBuffer"))) + , fSampler2DMS_Type(new Type(String("sampler2DMS"))) + , fSampler2DMSArray_Type(new Type(String("sampler2DMSArray"))) + , fSampler1DShadow_Type(new Type(String("sampler1DShadow"))) + , fSampler2DShadow_Type(new Type(String("sampler2DShadow"))) + , fSamplerCubeShadow_Type(new Type(String("samplerCubeShadow"))) + , fSampler2DRectShadow_Type(new Type(String("sampler2DRectShadow"))) + , fSampler1DArrayShadow_Type(new Type(String("sampler1DArrayShadow"))) + , fSampler2DArrayShadow_Type(new Type(String("sampler2DArrayShadow"))) + , fSamplerCubeArrayShadow_Type(new Type(String("samplerCubeArrayShadow"))) + + // Related to below FIXME, gsampler*s don't currently expand to cover integer case. + , fISampler2D_Type(new Type(String("isampler2D"), SpvDim2D, false, false, false, true)) + + // FIXME express these as "gimage2D" that expand to image2D, iimage2D, and uimage2D. + , fImage2D_Type(new Type(String("image2D"), SpvDim2D, false, false, false, true)) + , fIImage2D_Type(new Type(String("iimage2D"), SpvDim2D, false, false, false, true)) + + // FIXME express these as "gsubpassInput" that expand to subpassInput, isubpassInput, + // and usubpassInput. + , fSubpassInput_Type(new Type(String("subpassInput"), SpvDimSubpassData, false, false, + false, false)) + , fSubpassInputMS_Type(new Type(String("subpassInputMS"), SpvDimSubpassData, false, false, + true, false)) + // FIXME figure out what we're supposed to do with the gsampler et al. types) - , fGSampler1D_Type(new Type("$gsampler1D", static_type(*fSampler1D_Type))) - , fGSampler2D_Type(new Type("$gsampler2D", static_type(*fSampler2D_Type))) - , fGSampler3D_Type(new Type("$gsampler3D", static_type(*fSampler3D_Type))) - , fGSamplerCube_Type(new Type("$gsamplerCube", static_type(*fSamplerCube_Type))) - , fGSampler2DRect_Type(new Type("$gsampler2DRect", static_type(*fSampler2DRect_Type))) - , fGSampler1DArray_Type(new Type("$gsampler1DArray", static_type(*fSampler1DArray_Type))) - , fGSampler2DArray_Type(new Type("$gsampler2DArray", static_type(*fSampler2DArray_Type))) - , fGSamplerCubeArray_Type(new Type("$gsamplerCubeArray", static_type(*fSamplerCubeArray_Type))) - , fGSamplerBuffer_Type(new Type("$gsamplerBuffer", static_type(*fSamplerBuffer_Type))) - , fGSampler2DMS_Type(new Type("$gsampler2DMS", static_type(*fSampler2DMS_Type))) - , fGSampler2DMSArray_Type(new Type("$gsampler2DMSArray", static_type(*fSampler2DMSArray_Type))) - , fGSampler2DArrayShadow_Type(new Type("$gsampler2DArrayShadow", + , fGSampler1D_Type(new Type(String("$gsampler1D"), static_type(*fSampler1D_Type))) + , fGSampler2D_Type(new Type(String("$gsampler2D"), static_type(*fSampler2D_Type))) + , fGSampler3D_Type(new Type(String("$gsampler3D"), static_type(*fSampler3D_Type))) + , fGSamplerCube_Type(new Type(String("$gsamplerCube"), static_type(*fSamplerCube_Type))) + , fGSampler2DRect_Type(new Type(String("$gsampler2DRect"), static_type(*fSampler2DRect_Type))) + , fGSampler1DArray_Type(new Type(String("$gsampler1DArray"), + static_type(*fSampler1DArray_Type))) + , fGSampler2DArray_Type(new Type(String("$gsampler2DArray"), + static_type(*fSampler2DArray_Type))) + , fGSamplerCubeArray_Type(new Type(String("$gsamplerCubeArray"), + static_type(*fSamplerCubeArray_Type))) + , fGSamplerBuffer_Type(new Type(String("$gsamplerBuffer"), static_type(*fSamplerBuffer_Type))) + , fGSampler2DMS_Type(new Type(String("$gsampler2DMS"), static_type(*fSampler2DMS_Type))) + , fGSampler2DMSArray_Type(new Type(String("$gsampler2DMSArray"), + static_type(*fSampler2DMSArray_Type))) + , fGSampler2DArrayShadow_Type(new Type(String("$gsampler2DArrayShadow"), static_type(*fSampler2DArrayShadow_Type))) - , fGSamplerCubeArrayShadow_Type(new Type("$gsamplerCubeArrayShadow", + , fGSamplerCubeArrayShadow_Type(new Type(String("$gsamplerCubeArrayShadow"), static_type(*fSamplerCubeArrayShadow_Type))) - , fGenType_Type(new Type("$genType", { fFloat_Type.get(), fVec2_Type.get(), fVec3_Type.get(), - fVec4_Type.get() })) - , fGenDType_Type(new Type("$genDType", { fDouble_Type.get(), fDVec2_Type.get(), - fDVec3_Type.get(), fDVec4_Type.get() })) - , fGenIType_Type(new Type("$genIType", { fInt_Type.get(), fIVec2_Type.get(), fIVec3_Type.get(), - fIVec4_Type.get() })) - , fGenUType_Type(new Type("$genUType", { fUInt_Type.get(), fUVec2_Type.get(), fUVec3_Type.get(), - fUVec4_Type.get() })) - , fGenBType_Type(new Type("$genBType", { fBool_Type.get(), fBVec2_Type.get(), fBVec3_Type.get(), - fBVec4_Type.get() })) - , fMat_Type(new Type("$mat")) - , fVec_Type(new Type("$vec", { fVec2_Type.get(), fVec2_Type.get(), fVec3_Type.get(), - fVec4_Type.get() })) - , fGVec_Type(new Type("$gvec")) - , fGVec2_Type(new Type("$gvec2")) - , fGVec3_Type(new Type("$gvec3")) - , fGVec4_Type(new Type("$gvec4", static_type(*fVec4_Type))) - , fDVec_Type(new Type("$dvec")) - , fIVec_Type(new Type("$ivec")) - , fUVec_Type(new Type("$uvec")) - , fBVec_Type(new Type("$bvec", { fBVec2_Type.get(), fBVec2_Type.get(), fBVec3_Type.get(), - fBVec4_Type.get() })) - , fInvalid_Type(new Type("")) {} + , fGenType_Type(new Type(String("$genType"), { fFloat_Type.get(), fVec2_Type.get(), + fVec3_Type.get(), fVec4_Type.get() })) + , fGenDType_Type(new Type(String("$genDType"), { fDouble_Type.get(), fDVec2_Type.get(), + fDVec3_Type.get(), fDVec4_Type.get() })) + , fGenIType_Type(new Type(String("$genIType"), { fInt_Type.get(), fIVec2_Type.get(), + fIVec3_Type.get(), fIVec4_Type.get() })) + , fGenUType_Type(new Type(String("$genUType"), { fUInt_Type.get(), fUVec2_Type.get(), + fUVec3_Type.get(), fUVec4_Type.get() })) + , fGenBType_Type(new Type(String("$genBType"), { fBool_Type.get(), fBVec2_Type.get(), + fBVec3_Type.get(), fBVec4_Type.get() })) + , fMat_Type(new Type(String("$mat"), { fMat2x2_Type.get(), fMat2x3_Type.get(), + fMat2x4_Type.get(), fMat3x2_Type.get(), + fMat3x3_Type.get(), fMat3x4_Type.get(), + fMat4x2_Type.get(), fMat4x3_Type.get(), + fMat4x4_Type.get(), fDMat2x2_Type.get(), + fDMat2x3_Type.get(), fDMat2x4_Type.get(), + fDMat3x2_Type.get(), fDMat3x3_Type.get(), + fDMat3x4_Type.get(), fDMat4x2_Type.get(), + fDMat4x3_Type.get(), fDMat4x4_Type.get() })) + , fVec_Type(new Type(String("$vec"), { fInvalid_Type.get(), fVec2_Type.get(), + fVec3_Type.get(), fVec4_Type.get() })) + , fGVec_Type(new Type(String("$gvec"))) + , fGVec2_Type(new Type(String("$gvec2"))) + , fGVec3_Type(new Type(String("$gvec3"))) + , fGVec4_Type(new Type(String("$gvec4"), static_type(*fVec4_Type))) + , fDVec_Type(new Type(String("$dvec"), { fInvalid_Type.get(), fDVec2_Type.get(), + fDVec3_Type.get(), fDVec4_Type.get() })) + , fIVec_Type(new Type(String("$ivec"), { fInvalid_Type.get(), fIVec2_Type.get(), + fIVec3_Type.get(), fIVec4_Type.get() })) + , fUVec_Type(new Type(String("$uvec"), { fInvalid_Type.get(), fUVec2_Type.get(), + fUVec3_Type.get(), fUVec4_Type.get() })) + , fBVec_Type(new Type(String("$bvec"), { fInvalid_Type.get(), fBVec2_Type.get(), + fBVec3_Type.get(), fBVec4_Type.get() })) + , fSkCaps_Type(new Type(String("$sk_Caps"))) + , fDefined_Expression(new Defined(*fInvalid_Type)) {} static std::vector static_type(const Type& t) { - return { &t, &t, &t, &t }; + return { &t, &t, &t, &t }; } + const std::unique_ptr fInvalid_Type; const std::unique_ptr fVoid_Type; const std::unique_ptr fDouble_Type; @@ -169,6 +207,7 @@ public: const std::unique_ptr fSampler1D_Type; const std::unique_ptr fSampler2D_Type; const std::unique_ptr fSampler3D_Type; + const std::unique_ptr fSamplerExternalOES_Type; const std::unique_ptr fSamplerCube_Type; const std::unique_ptr fSampler2DRect_Type; const std::unique_ptr fSampler1DArray_Type; @@ -185,6 +224,15 @@ public: const std::unique_ptr fSampler2DArrayShadow_Type; const std::unique_ptr fSamplerCubeArrayShadow_Type; + + const std::unique_ptr fISampler2D_Type; + + const std::unique_ptr fImage2D_Type; + const std::unique_ptr fIImage2D_Type; + + const std::unique_ptr fSubpassInput_Type; + const std::unique_ptr fSubpassInputMS_Type; + const std::unique_ptr fGSampler1D_Type; const std::unique_ptr fGSampler2D_Type; const std::unique_ptr fGSampler3D_Type; @@ -219,7 +267,25 @@ public: const std::unique_ptr fBVec_Type; - const std::unique_ptr fInvalid_Type; + const std::unique_ptr fSkCaps_Type; + + // dummy expression used to mark that a variable has a value during dataflow analysis (when it + // could have several different values, or the analyzer is otherwise unable to assign it a + // specific expression) + const std::unique_ptr fDefined_Expression; + +private: + class Defined : public Expression { + public: + Defined(const Type& type) + : INHERITED(Position(), kDefined_Kind, type) {} + + virtual String description() const override { + return String(""); + } + + typedef Expression INHERITED; + }; }; } // namespace diff --git a/gfx/skia/skia/src/sksl/SkSLErrorReporter.h b/gfx/skia/skia/src/sksl/SkSLErrorReporter.h index 26b44711c306..172e4888d8b1 100644 --- a/gfx/skia/skia/src/sksl/SkSLErrorReporter.h +++ b/gfx/skia/skia/src/sksl/SkSLErrorReporter.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ERRORREPORTER #define SKSL_ERRORREPORTER @@ -19,7 +19,13 @@ class ErrorReporter { public: virtual ~ErrorReporter() {} - virtual void error(Position position, std::string msg) = 0; + void error(Position position, const char* msg) { + this->error(position, String(msg)); + } + + virtual void error(Position position, String msg) = 0; + + virtual int errorCount() = 0; }; } // namespace diff --git a/gfx/skia/skia/src/sksl/SkSLFileOutputStream.h b/gfx/skia/skia/src/sksl/SkSLFileOutputStream.h new file mode 100644 index 000000000000..f4739306c9d0 --- /dev/null +++ b/gfx/skia/skia/src/sksl/SkSLFileOutputStream.h @@ -0,0 +1,75 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_FILEOUTPUTSTREAM +#define SKSL_FILEOUTPUTSTREAM + +#include "SkSLOutputStream.h" +#include + +namespace SkSL { + +class FileOutputStream : public OutputStream { +public: + FileOutputStream(const char* name) { + fFile = fopen(name, "w"); + } + + ~FileOutputStream() { + ASSERT(!fOpen); + } + + bool isValid() const override { + return nullptr != fFile; + } + + void write8(uint8_t b) override { + ASSERT(fOpen); + if (isValid()) { + if (EOF == fputc(b, fFile)) { + fFile = nullptr; + } + } + } + + void writeText(const char* s) override { + ASSERT(fOpen); + if (isValid()) { + if (EOF == fputs(s, fFile)) { + fFile = nullptr; + } + } + } + + void write(const void* s, size_t size) override { + if (isValid()) { + size_t written = fwrite(s, 1, size, fFile); + if (written != size) { + fFile = nullptr; + } + } + } + + bool close() { + fOpen = false; + if (isValid() && fclose(fFile)) { + fFile = nullptr; + return false; + } + return true; + } + +private: + bool fOpen = true; + FILE *fFile; + + typedef OutputStream INHERITED; +}; + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/SkSLGLSLCodeGenerator.cpp b/gfx/skia/skia/src/sksl/SkSLGLSLCodeGenerator.cpp index da0bcb903cf3..ab64e66f7cc5 100644 --- a/gfx/skia/skia/src/sksl/SkSLGLSLCodeGenerator.cpp +++ b/gfx/skia/skia/src/sksl/SkSLGLSLCodeGenerator.cpp @@ -4,16 +4,16 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - -#include "SkSLGLSLCodeGenerator.h" -#include "string.h" +#include "SkSLGLSLCodeGenerator.h" #include "GLSL.std.450.h" +#include "SkSLCompiler.h" #include "ir/SkSLExpressionStatement.h" #include "ir/SkSLExtension.h" #include "ir/SkSLIndexExpression.h" +#include "ir/SkSLModifiersDeclaration.h" #include "ir/SkSLVariableReference.h" namespace SkSL { @@ -24,24 +24,24 @@ void GLSLCodeGenerator::write(const char* s) { } if (fAtLineStart) { for (int i = 0; i < fIndentation; i++) { - *fOut << " "; + fOut->writeText(" "); } } - *fOut << s; + fOut->writeText(s); fAtLineStart = false; } void GLSLCodeGenerator::writeLine(const char* s) { this->write(s); - *fOut << "\n"; + fOut->write8('\n'); fAtLineStart = true; } -void GLSLCodeGenerator::write(const std::string& s) { +void GLSLCodeGenerator::write(const String& s) { this->write(s.c_str()); } -void GLSLCodeGenerator::writeLine(const std::string& s) { +void GLSLCodeGenerator::writeLine(const String& s) { this->writeLine(s.c_str()); } @@ -66,13 +66,13 @@ void GLSLCodeGenerator::writeType(const Type& type) { this->writeLine("struct " + type.name() + " {"); fIndentation++; for (const auto& f : type.fields()) { - this->writeModifiers(f.fModifiers); + this->writeModifiers(f.fModifiers, false); // sizes (which must be static in structs) are part of the type name here this->writeType(*f.fType); this->writeLine(" " + f.fName + ";"); } fIndentation--; - this->writeLine("}"); + this->write("}"); } else { this->write(type.name()); } @@ -124,8 +124,127 @@ void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence paren } } +static bool is_abs(Expression& expr) { + if (expr.fKind != Expression::kFunctionCall_Kind) { + return false; + } + return ((FunctionCall&) expr).fFunction.fName == "abs"; +} + +// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a +// Tegra3 compiler bug. +void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) { + ASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether()); + String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++); + String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++); + this->fFunctionHeader += " " + absExpr.fType.name() + " " + tmpVar1 + ";\n"; + this->fFunctionHeader += " " + otherExpr.fType.name() + " " + tmpVar2 + ";\n"; + this->write("((" + tmpVar1 + " = "); + this->writeExpression(absExpr, kTopLevel_Precedence); + this->write(") < (" + tmpVar2 + " = "); + this->writeExpression(otherExpr, kAssignment_Precedence); + this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")"); +} + void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) { - this->write(c.fFunction.fName + "("); + if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether() && c.fFunction.fName == "min" && + c.fFunction.fBuiltin) { + ASSERT(c.fArguments.size() == 2); + if (is_abs(*c.fArguments[0])) { + this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]); + return; + } + if (is_abs(*c.fArguments[1])) { + // note that this violates the GLSL left-to-right evaluation semantics. I doubt it will + // ever end up mattering, but it's worth calling out. + this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]); + return; + } + } + if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() && + c.fFunction.fName == "atan" && + c.fFunction.fBuiltin && c.fArguments.size() == 2 && + c.fArguments[1]->fKind == Expression::kPrefix_Kind) { + const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1]; + if (p.fOperator == Token::MINUS) { + this->write("atan("); + this->writeExpression(*c.fArguments[0], kSequence_Precedence); + this->write(", -1.0 * "); + this->writeExpression(*p.fOperand, kMultiplicative_Precedence); + this->write(")"); + return; + } + } + if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") && + c.fFunction.fBuiltin && fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) { + ASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport()); + fHeader.writeText("#extension "); + fHeader.writeText(fProgram.fSettings.fCaps->shaderDerivativeExtensionString()); + fHeader.writeText(" : require\n"); + fFoundDerivatives = true; + } + if (c.fFunction.fName == "texture" && c.fFunction.fBuiltin) { + const char* dim = ""; + bool proj = false; + switch (c.fArguments[0]->fType.dimensions()) { + case SpvDim1D: + dim = "1D"; + if (c.fArguments[1]->fType == *fContext.fFloat_Type) { + proj = false; + } else { + ASSERT(c.fArguments[1]->fType == *fContext.fVec2_Type); + proj = true; + } + break; + case SpvDim2D: + dim = "2D"; + if (c.fArguments[1]->fType == *fContext.fVec2_Type) { + proj = false; + } else { + ASSERT(c.fArguments[1]->fType == *fContext.fVec3_Type); + proj = true; + } + break; + case SpvDim3D: + dim = "3D"; + if (c.fArguments[1]->fType == *fContext.fVec3_Type) { + proj = false; + } else { + ASSERT(c.fArguments[1]->fType == *fContext.fVec4_Type); + proj = true; + } + break; + case SpvDimCube: + dim = "Cube"; + proj = false; + break; + case SpvDimRect: + dim = "Rect"; + proj = false; + break; + case SpvDimBuffer: + ASSERT(false); // doesn't exist + dim = "Buffer"; + proj = false; + break; + case SpvDimSubpassData: + ASSERT(false); // doesn't exist + dim = "SubpassData"; + proj = false; + break; + } + this->write("texture"); + if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) { + this->write(dim); + } + if (proj) { + this->write("Proj"); + } + + } else { + this->write(c.fFunction.fName); + } + this->write("("); const char* separator = ""; for (const auto& arg : c.fArguments) { this->write(separator); @@ -146,8 +265,80 @@ void GLSLCodeGenerator::writeConstructor(const Constructor& c) { this->write(")"); } +void GLSLCodeGenerator::writeFragCoord() { + // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers + // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the + // declaration varies in earlier GLSL specs. So it is simpler to omit it. + if (!fProgram.fSettings.fFlipY) { + this->write("gl_FragCoord"); + } else if (const char* extension = + fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) { + if (!fSetupFragPositionGlobal) { + if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) { + fHeader.writeText("#extension "); + fHeader.writeText(extension); + fHeader.writeText(" : require\n"); + } + fHeader.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n"); + fSetupFragPositionGlobal = true; + } + this->write("gl_FragCoord"); + } else { + if (!fSetupFragPositionGlobal) { + // The Adreno compiler seems to be very touchy about access to "gl_FragCoord". + // Accessing glFragCoord.zw can cause a program to fail to link. Additionally, + // depending on the surrounding code, accessing .xy with a uniform involved can + // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand + // (and only accessing .xy) seems to "fix" things. + const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp " + : ""; + fHeader.writeText("uniform "); + fHeader.writeText(precision); + fHeader.writeText("float " SKSL_RTHEIGHT_NAME ";\n"); + fSetupFragPositionGlobal = true; + } + if (!fSetupFragPositionLocal) { + const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp " + : ""; + fFunctionHeader += precision; + fFunctionHeader += " vec2 _sktmpCoord = gl_FragCoord.xy;\n"; + fFunctionHeader += precision; + fFunctionHeader += " vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME + " - _sktmpCoord.y, 1.0, 1.0);\n"; + fSetupFragPositionLocal = true; + } + this->write("sk_FragCoord"); + } +} + + void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) { - this->write(ref.fVariable.fName); + switch (ref.fVariable.fModifiers.fLayout.fBuiltin) { + case SK_FRAGCOLOR_BUILTIN: + if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) { + this->write("sk_FragColor"); + } else { + this->write("gl_FragColor"); + } + break; + case SK_FRAGCOORD_BUILTIN: + this->writeFragCoord(); + break; + case SK_VERTEXID_BUILTIN: + this->write("gl_VertexID"); + break; + case SK_CLIPDISTANCE_BUILTIN: + this->write("gl_ClipDistance"); + break; + case SK_IN_BUILTIN: + this->write("gl_in"); + break; + case SK_INVOCATIONID_BUILTIN: + this->write("gl_InvocationID"); + break; + default: + this->write(ref.fVariable.fName); + } } void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) { @@ -162,7 +353,13 @@ void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) { this->writeExpression(*f.fBase, kPostfix_Precedence); this->write("."); } - this->write(f.fBase->fType.fields()[f.fFieldIndex].fName); + switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) { + case SK_CLIPDISTANCE_BUILTIN: + this->write("gl_ClipDistance"); + break; + default: + this->write(f.fBase->fType.fields()[f.fFieldIndex].fName); + } } void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) { @@ -212,7 +409,7 @@ static GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) { } } -void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b, +void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence) { Precedence precedence = get_binary_precedence(b.fOperator); if (precedence >= parentPrecedence) { @@ -226,7 +423,7 @@ void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b, } } -void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t, +void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence) { if (kTernary_Precedence >= parentPrecedence) { this->write("("); @@ -241,7 +438,7 @@ void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t, } } -void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p, +void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence) { if (kPrefix_Precedence >= parentPrecedence) { this->write("("); @@ -253,7 +450,7 @@ void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p, } } -void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p, +void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p, Precedence parentPrecedence) { if (kPostfix_Precedence >= parentPrecedence) { this->write("("); @@ -270,7 +467,11 @@ void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) { } void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) { - this->write(to_string(i.fValue)); + if (i.fType == *fContext.fUInt_Type) { + this->write(to_string(i.fValue & 0xffffffff) + "u"); + } else { + this->write(to_string((int32_t) i.fValue)); + } } void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) { @@ -284,54 +485,168 @@ void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) { for (const auto& param : f.fDeclaration.fParameters) { this->write(separator); separator = ", "; - this->writeModifiers(param->fModifiers); - this->writeType(param->fType); + this->writeModifiers(param->fModifiers, false); + std::vector sizes; + const Type* type = ¶m->fType; + while (type->kind() == Type::kArray_Kind) { + sizes.push_back(type->columns()); + type = &type->componentType(); + } + this->writeType(*type); this->write(" " + param->fName); + for (int s : sizes) { + if (s <= 0) { + this->write("[]"); + } else { + this->write("[" + to_string(s) + "]"); + } + } } - this->write(") "); - this->writeBlock(*f.fBody); - this->writeLine(); + this->writeLine(") {"); + + fFunctionHeader = ""; + OutputStream* oldOut = fOut; + StringStream buffer; + fOut = &buffer; + fIndentation++; + for (const auto& s : f.fBody->fStatements) { + this->writeStatement(*s); + this->writeLine(); + } + fIndentation--; + this->writeLine("}"); + + fOut = oldOut; + this->write(fFunctionHeader); + this->write(String(buffer.data(), buffer.size())); } -void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers) { - this->write(modifiers.description()); +void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers, + bool globalContext) { + if (modifiers.fFlags & Modifiers::kFlat_Flag) { + this->write("flat "); + } + if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) { + this->write("noperspective "); + } + String layout = modifiers.fLayout.description(); + if (layout.size()) { + this->write(layout + " "); + } + if (modifiers.fFlags & Modifiers::kReadOnly_Flag) { + this->write("readonly "); + } + if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) { + this->write("writeonly "); + } + if (modifiers.fFlags & Modifiers::kCoherent_Flag) { + this->write("coherent "); + } + if (modifiers.fFlags & Modifiers::kVolatile_Flag) { + this->write("volatile "); + } + if (modifiers.fFlags & Modifiers::kRestrict_Flag) { + this->write("restrict "); + } + if ((modifiers.fFlags & Modifiers::kIn_Flag) && + (modifiers.fFlags & Modifiers::kOut_Flag)) { + this->write("inout "); + } else if (modifiers.fFlags & Modifiers::kIn_Flag) { + if (globalContext && + fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) { + this->write(fProgramKind == Program::kVertex_Kind ? "attribute " + : "varying "); + } else { + this->write("in "); + } + } else if (modifiers.fFlags & Modifiers::kOut_Flag) { + if (globalContext && + fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) { + this->write("varying "); + } else { + this->write("out "); + } + } + if (modifiers.fFlags & Modifiers::kUniform_Flag) { + this->write("uniform "); + } + if (modifiers.fFlags & Modifiers::kConst_Flag) { + this->write("const "); + } + if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) { + if (modifiers.fFlags & Modifiers::kLowp_Flag) { + this->write("lowp "); + } + if (modifiers.fFlags & Modifiers::kMediump_Flag) { + this->write("mediump "); + } + if (modifiers.fFlags & Modifiers::kHighp_Flag) { + this->write("highp "); + } + } } void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { - if (intf.fVariable.fName == "gl_PerVertex") { + if (intf.fTypeName == "sk_PerVertex") { return; } - this->writeModifiers(intf.fVariable.fModifiers); - this->writeLine(intf.fVariable.fType.name() + " {"); + this->writeModifiers(intf.fVariable.fModifiers, true); + this->writeLine(intf.fTypeName + " {"); fIndentation++; - for (const auto& f : intf.fVariable.fType.fields()) { - this->writeModifiers(f.fModifiers); + const Type* structType = &intf.fVariable.fType; + while (structType->kind() == Type::kArray_Kind) { + structType = &structType->componentType(); + } + for (const auto& f : structType->fields()) { + this->writeModifiers(f.fModifiers, false); this->writeType(*f.fType); this->writeLine(" " + f.fName + ";"); } fIndentation--; - this->writeLine("};"); + this->write("}"); + if (intf.fInstanceName.size()) { + this->write(" "); + this->write(intf.fInstanceName); + for (const auto& size : intf.fSizes) { + this->write("["); + if (size) { + this->writeExpression(*size, kTopLevel_Precedence); + } + this->write("]"); + } + } + this->writeLine(";"); } -void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl) { +void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) { ASSERT(decl.fVars.size() > 0); - this->writeModifiers(decl.fVars[0].fVar->fModifiers); + this->writeModifiers(decl.fVars[0].fVar->fModifiers, global); this->writeType(decl.fBaseType); - std::string separator = " "; + String separator(" "); for (const auto& var : decl.fVars) { ASSERT(var.fVar->fModifiers == decl.fVars[0].fVar->fModifiers); this->write(separator); - separator = ", "; + separator = String(", "); this->write(var.fVar->fName); for (const auto& size : var.fSizes) { this->write("["); - this->writeExpression(*size, kTopLevel_Precedence); + if (size) { + this->writeExpression(*size, kTopLevel_Precedence); + } this->write("]"); } if (var.fValue) { this->write(" = "); this->writeExpression(*var.fValue, kTopLevel_Precedence); } + if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) { + if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) { + fHeader.writeText("#extension "); + fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString()); + fHeader.writeText(" : require\n"); + } + fFoundImageDecl = true; + } } this->write(";"); } @@ -345,11 +660,11 @@ void GLSLCodeGenerator::writeStatement(const Statement& s) { this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence); this->write(";"); break; - case Statement::kReturn_Kind: + case Statement::kReturn_Kind: this->writeReturnStatement((ReturnStatement&) s); break; case Statement::kVarDeclarations_Kind: - this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration); + this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false); break; case Statement::kIf_Kind: this->writeIfStatement((IfStatement&) s); @@ -363,6 +678,9 @@ void GLSLCodeGenerator::writeStatement(const Statement& s) { case Statement::kDo_Kind: this->writeDoStatement((DoStatement&) s); break; + case Statement::kSwitch_Kind: + this->writeSwitchStatement((SwitchStatement&) s); + break; case Statement::kBreak_Kind: this->write("break;"); break; @@ -432,6 +750,30 @@ void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) { this->write(");"); } +void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) { + this->write("switch ("); + this->writeExpression(*s.fValue, kTopLevel_Precedence); + this->writeLine(") {"); + fIndentation++; + for (const auto& c : s.fCases) { + if (c->fValue) { + this->write("case "); + this->writeExpression(*c->fValue, kTopLevel_Precedence); + this->writeLine(":"); + } else { + this->writeLine("default:"); + } + fIndentation++; + for (const auto& stmt : c->fStatements) { + this->writeStatement(*stmt); + this->writeLine(); + } + fIndentation--; + } + fIndentation--; + this->write("}"); +} + void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) { this->write("return"); if (r.fExpression) { @@ -441,25 +783,57 @@ void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) { this->write(";"); } -void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out) { - ASSERT(fOut == nullptr); - fOut = &out; - this->write("#version " + to_string(fCaps.fVersion)); - if (fCaps.fStandard == GLCaps::kGLES_Standard) { - this->write(" es"); - } +bool GLSLCodeGenerator::generateCode() { + OutputStream* rawOut = fOut; + fOut = &fHeader; + fProgramKind = fProgram.fKind; + this->write(fProgram.fSettings.fCaps->versionDeclString()); this->writeLine(); - for (const auto& e : program.fElements) { + for (const auto& e : fProgram.fElements) { + if (e->fKind == ProgramElement::kExtension_Kind) { + this->writeExtension((Extension&) *e); + } + } + StringStream body; + fOut = &body; + if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) { + this->write("precision "); + switch (fProgram.fDefaultPrecision) { + case Modifiers::kLowp_Flag: + this->write("lowp"); + break; + case Modifiers::kMediump_Flag: + this->write("mediump"); + break; + case Modifiers::kHighp_Flag: + this->write("highp"); + break; + default: + ASSERT(false); + this->write(""); + } + this->writeLine(" float;"); + } + for (const auto& e : fProgram.fElements) { switch (e->fKind) { case ProgramElement::kExtension_Kind: - this->writeExtension((Extension&) *e); break; case ProgramElement::kVar_Kind: { VarDeclarations& decl = (VarDeclarations&) *e; - if (decl.fVars.size() > 0 && - decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin == -1) { - this->writeVarDeclarations(decl); - this->writeLine(); + if (decl.fVars.size() > 0) { + int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin; + if (builtin == -1) { + // normal var + this->writeVarDeclarations(decl, true); + this->writeLine(); + } else if (builtin == SK_FRAGCOLOR_BUILTIN && + fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) { + this->write("out "); + if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) { + this->write("mediump "); + } + this->writeLine("vec4 sk_FragColor;"); + } } break; } @@ -469,12 +843,20 @@ void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out) case ProgramElement::kFunction_Kind: this->writeFunction((FunctionDefinition&) *e); break; + case ProgramElement::kModifiers_Kind: + this->writeModifiers(((ModifiersDeclaration&) *e).fModifiers, true); + this->writeLine(";"); + break; default: printf("%s\n", e->description().c_str()); ABORT("unsupported program element"); } } fOut = nullptr; + + write_stringstream(fHeader, *rawOut); + write_stringstream(body, *rawOut); + return true; } } diff --git a/gfx/skia/skia/src/sksl/SkSLGLSLCodeGenerator.h b/gfx/skia/skia/src/sksl/SkSLGLSLCodeGenerator.h index 3534affccca2..ab88d50881fa 100644 --- a/gfx/skia/skia/src/sksl/SkSLGLSLCodeGenerator.h +++ b/gfx/skia/skia/src/sksl/SkSLGLSLCodeGenerator.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_GLSLCODEGENERATOR #define SKSL_GLSLCODEGENERATOR @@ -33,10 +33,11 @@ #include "ir/SkSLProgramElement.h" #include "ir/SkSLReturnStatement.h" #include "ir/SkSLStatement.h" +#include "ir/SkSLSwitchStatement.h" #include "ir/SkSLSwizzle.h" #include "ir/SkSLTernaryExpression.h" -#include "ir/SkSLVarDeclaration.h" -#include "ir/SkSLVarDeclarationStatement.h" +#include "ir/SkSLVarDeclarations.h" +#include "ir/SkSLVarDeclarationsStatement.h" #include "ir/SkSLVariableReference.h" #include "ir/SkSLWhileStatement.h" @@ -44,14 +45,6 @@ namespace SkSL { #define kLast_Capability SpvCapabilityMultiViewport -struct GLCaps { - int fVersion; - enum { - kGL_Standard, - kGLES_Standard - } fStandard; -}; - /** * Converts a Program into GLSL code. */ @@ -78,13 +71,12 @@ public: kTopLevel_Precedence = 18 }; - GLSLCodeGenerator(const Context* context, GLCaps caps) - : fContext(*context) - , fCaps(caps) - , fIndentation(0) - , fAtLineStart(true) {} + GLSLCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors, + OutputStream* out) + : INHERITED(program, errors, out) + , fContext(*context) {} - void generateCode(const Program& program, std::ostream& out) override; + virtual bool generateCode() override; private: void write(const char* s); @@ -93,9 +85,9 @@ private: void writeLine(const char* s); - void write(const std::string& s); + void write(const String& s); - void writeLine(const std::string& s); + void writeLine(const String& s); void writeType(const Type& type); @@ -104,25 +96,29 @@ private: void writeInterfaceBlock(const InterfaceBlock& intf); void writeFunctionStart(const FunctionDeclaration& f); - + void writeFunctionDeclaration(const FunctionDeclaration& f); void writeFunction(const FunctionDefinition& f); void writeLayout(const Layout& layout); - void writeModifiers(const Modifiers& modifiers); - + void writeModifiers(const Modifiers& modifiers, bool globalContext); + void writeGlobalVars(const VarDeclaration& vs); - void writeVarDeclarations(const VarDeclarations& decl); + void writeVarDeclarations(const VarDeclarations& decl, bool global); + + void writeFragCoord(); void writeVariableReference(const VariableReference& ref); void writeExpression(const Expression& expr, Precedence parentPrecedence); - + void writeIntrinsicCall(const FunctionCall& c); + void writeMinAbsHack(Expression& absExpr, Expression& otherExpr); + void writeFunctionCall(const FunctionCall& c); void writeConstructor(const Constructor& c); @@ -159,17 +155,28 @@ private: void writeDoStatement(const DoStatement& d); + void writeSwitchStatement(const SwitchStatement& s); + void writeReturnStatement(const ReturnStatement& r); const Context& fContext; - const GLCaps fCaps; - std::ostream* fOut; - int fIndentation; - bool fAtLineStart; - // Keeps track of which struct types we have written. Given that we are unlikely to ever write - // more than one or two structs per shader, a simple linear search will be faster than anything + StringStream fHeader; + String fFunctionHeader; + Program::Kind fProgramKind; + int fVarCount = 0; + int fIndentation = 0; + bool fAtLineStart = false; + // Keeps track of which struct types we have written. Given that we are unlikely to ever write + // more than one or two structs per shader, a simple linear search will be faster than anything // fancier. std::vector fWrittenStructs; + // true if we have run into usages of dFdx / dFdy + bool fFoundDerivatives = false; + bool fFoundImageDecl = false; + bool fSetupFragPositionGlobal = false; + bool fSetupFragPositionLocal = false; + + typedef CodeGenerator INHERITED; }; } diff --git a/gfx/skia/skia/src/sksl/SkSLIRGenerator.cpp b/gfx/skia/skia/src/sksl/SkSLIRGenerator.cpp index c30cac17d76d..9910513fbbdb 100644 --- a/gfx/skia/skia/src/sksl/SkSLIRGenerator.cpp +++ b/gfx/skia/skia/src/sksl/SkSLIRGenerator.cpp @@ -4,11 +4,13 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #include "SkSLIRGenerator.h" #include "limits.h" +#include +#include "SkSLCompiler.h" #include "ast/SkSLASTBoolLiteral.h" #include "ast/SkSLASTFieldSuffix.h" #include "ast/SkSLASTFloatLiteral.h" @@ -38,12 +40,14 @@ #include "ir/SkSLPostfixExpression.h" #include "ir/SkSLPrefixExpression.h" #include "ir/SkSLReturnStatement.h" +#include "ir/SkSLSwitchCase.h" +#include "ir/SkSLSwitchStatement.h" #include "ir/SkSLSwizzle.h" #include "ir/SkSLTernaryExpression.h" #include "ir/SkSLUnresolvedFunction.h" #include "ir/SkSLVariable.h" -#include "ir/SkSLVarDeclaration.h" -#include "ir/SkSLVarDeclarationStatement.h" +#include "ir/SkSLVarDeclarations.h" +#include "ir/SkSLVarDeclarationsStatement.h" #include "ir/SkSLVariableReference.h" #include "ir/SkSLWhileStatement.h" @@ -51,7 +55,7 @@ namespace SkSL { class AutoSymbolTable { public: - AutoSymbolTable(IRGenerator* ir) + AutoSymbolTable(IRGenerator* ir) : fIR(ir) , fPrevious(fIR->fSymbolTable) { fIR->pushSymbolTable(); @@ -66,21 +70,87 @@ public: std::shared_ptr fPrevious; }; -IRGenerator::IRGenerator(const Context* context, std::shared_ptr symbolTable, +class AutoLoopLevel { +public: + AutoLoopLevel(IRGenerator* ir) + : fIR(ir) { + fIR->fLoopLevel++; + } + + ~AutoLoopLevel() { + fIR->fLoopLevel--; + } + + IRGenerator* fIR; +}; + +class AutoSwitchLevel { +public: + AutoSwitchLevel(IRGenerator* ir) + : fIR(ir) { + fIR->fSwitchLevel++; + } + + ~AutoSwitchLevel() { + fIR->fSwitchLevel--; + } + + IRGenerator* fIR; +}; + +IRGenerator::IRGenerator(const Context* context, std::shared_ptr symbolTable, ErrorReporter& errorReporter) : fContext(*context) , fCurrentFunction(nullptr) , fSymbolTable(std::move(symbolTable)) +, fLoopLevel(0) +, fSwitchLevel(0) , fErrors(errorReporter) {} void IRGenerator::pushSymbolTable() { - fSymbolTable.reset(new SymbolTable(std::move(fSymbolTable), fErrors)); + fSymbolTable.reset(new SymbolTable(std::move(fSymbolTable), &fErrors)); } void IRGenerator::popSymbolTable() { fSymbolTable = fSymbolTable->fParent; } +static void fill_caps(const SKSL_CAPS_CLASS& caps, std::unordered_map* capsMap) { +#define CAP(name) capsMap->insert(std::make_pair(String(#name), CapValue(caps.name()))); + CAP(fbFetchSupport); + CAP(fbFetchNeedsCustomOutput); + CAP(bindlessTextureSupport); + CAP(dropsTileOnZeroDivide); + CAP(flatInterpolationSupport); + CAP(noperspectiveInterpolationSupport); + CAP(multisampleInterpolationSupport); + CAP(sampleVariablesSupport); + CAP(sampleMaskOverrideCoverageSupport); + CAP(externalTextureSupport); + CAP(texelFetchSupport); + CAP(imageLoadStoreSupport); + CAP(mustEnableAdvBlendEqs); + CAP(mustEnableSpecificAdvBlendEqs); + CAP(mustDeclareFragmentShaderOutput); + CAP(canUseAnyFunctionInShader); +#undef CAP +} + +void IRGenerator::start(const Program::Settings* settings) { + fSettings = settings; + fCapsMap.clear(); + if (settings->fCaps) { + fill_caps(*settings->fCaps, &fCapsMap); + } + this->pushSymbolTable(); + fInputs.reset(); +} + +void IRGenerator::finish() { + this->popSymbolTable(); + fSettings = nullptr; +} + std::unique_ptr IRGenerator::convertExtension(const ASTExtension& extension) { return std::unique_ptr(new Extension(extension.fPosition, extension.fName)); } @@ -101,6 +171,8 @@ std::unique_ptr IRGenerator::convertStatement(const ASTStatement& sta return this->convertWhile((ASTWhileStatement&) statement); case ASTStatement::kDo_Kind: return this->convertDo((ASTDoStatement&) statement); + case ASTStatement::kSwitch_Kind: + return this->convertSwitch((ASTSwitchStatement&) statement); case ASTStatement::kReturn_Kind: return this->convertReturn((ASTReturnStatement&) statement); case ASTStatement::kBreak_Kind: @@ -136,10 +208,6 @@ std::unique_ptr IRGenerator::convertVarDeclarationStatement( return std::unique_ptr(new VarDeclarationsStatement(std::move(decl))); } -Modifiers IRGenerator::convertModifiers(const ASTModifiers& modifiers) { - return Modifiers(modifiers); -} - std::unique_ptr IRGenerator::convertVarDeclarations(const ASTVarDeclarations& decl, Variable::Storage storage) { std::vector variables; @@ -148,9 +216,7 @@ std::unique_ptr IRGenerator::convertVarDeclarations(const ASTVa return nullptr; } for (const auto& varDecl : decl.fVars) { - Modifiers modifiers = this->convertModifiers(decl.fModifiers); const Type* type = baseType; - ASSERT(type->kind() != Type::kArray_Kind); std::vector> sizes; for (const auto& rawSize : varDecl.fSizes) { if (rawSize) { @@ -158,8 +224,8 @@ std::unique_ptr IRGenerator::convertVarDeclarations(const ASTVa if (!size) { return nullptr; } - std::string name = type->fName; - uint64_t count; + String name = type->fName; + int64_t count; if (size->fKind == Expression::kIntLiteral_Kind) { count = ((IntLiteral&) *size).fValue; if (count <= 0) { @@ -179,8 +245,8 @@ std::unique_ptr IRGenerator::convertVarDeclarations(const ASTVa sizes.push_back(nullptr); } } - auto var = std::unique_ptr(new Variable(decl.fPosition, modifiers, varDecl.fName, - *type, storage)); + auto var = std::unique_ptr(new Variable(decl.fPosition, decl.fModifiers, + varDecl.fName, *type, storage)); std::unique_ptr value; if (varDecl.fValue) { value = this->convertExpression(*varDecl.fValue); @@ -189,7 +255,12 @@ std::unique_ptr IRGenerator::convertVarDeclarations(const ASTVa } value = this->coerce(std::move(value), *type); } - if ("gl_FragCoord" == varDecl.fName && (*fSymbolTable)[varDecl.fName]) { + if (storage == Variable::kGlobal_Storage && varDecl.fName == String("sk_FragColor") && + (*fSymbolTable)[varDecl.fName]) { + // already defined, ignore + } else if (storage == Variable::kGlobal_Storage && (*fSymbolTable)[varDecl.fName] && + (*fSymbolTable)[varDecl.fName]->fKind == Symbol::kVariable_Kind && + ((Variable*) (*fSymbolTable)[varDecl.fName])->fModifiers.fLayout.fBuiltin >= 0) { // already defined, just update the modifiers Variable* old = (Variable*) (*fSymbolTable)[varDecl.fName]; old->fModifiers = var->fModifiers; @@ -198,13 +269,18 @@ std::unique_ptr IRGenerator::convertVarDeclarations(const ASTVa fSymbolTable->add(varDecl.fName, std::move(var)); } } - return std::unique_ptr(new VarDeclarations(decl.fPosition, + return std::unique_ptr(new VarDeclarations(decl.fPosition, baseType, std::move(variables))); } +std::unique_ptr IRGenerator::convertModifiersDeclaration( + const ASTModifiersDeclaration& m) { + return std::unique_ptr(new ModifiersDeclaration(m.fModifiers)); +} + std::unique_ptr IRGenerator::convertIf(const ASTIfStatement& s) { - std::unique_ptr test = this->coerce(this->convertExpression(*s.fTest), + std::unique_ptr test = this->coerce(this->convertExpression(*s.fTest), *fContext.fBool_Type); if (!test) { return nullptr; @@ -220,37 +296,60 @@ std::unique_ptr IRGenerator::convertIf(const ASTIfStatement& s) { return nullptr; } } - return std::unique_ptr(new IfStatement(s.fPosition, std::move(test), + if (test->fKind == Expression::kBoolLiteral_Kind) { + // static boolean value, fold down to a single branch + if (((BoolLiteral&) *test).fValue) { + return ifTrue; + } else if (s.fIfFalse) { + return ifFalse; + } else { + // False & no else clause. Not an error, so don't return null! + std::vector> empty; + return std::unique_ptr(new Block(s.fPosition, std::move(empty), + fSymbolTable)); + } + } + return std::unique_ptr(new IfStatement(s.fPosition, std::move(test), std::move(ifTrue), std::move(ifFalse))); } std::unique_ptr IRGenerator::convertFor(const ASTForStatement& f) { + AutoLoopLevel level(this); AutoSymbolTable table(this); - std::unique_ptr initializer = this->convertStatement(*f.fInitializer); - if (!initializer) { - return nullptr; + std::unique_ptr initializer; + if (f.fInitializer) { + initializer = this->convertStatement(*f.fInitializer); + if (!initializer) { + return nullptr; + } } - std::unique_ptr test = this->coerce(this->convertExpression(*f.fTest), - *fContext.fBool_Type); - if (!test) { - return nullptr; + std::unique_ptr test; + if (f.fTest) { + test = this->coerce(this->convertExpression(*f.fTest), *fContext.fBool_Type); + if (!test) { + return nullptr; + } } - std::unique_ptr next = this->convertExpression(*f.fNext); - if (!next) { - return nullptr; + std::unique_ptr next; + if (f.fNext) { + next = this->convertExpression(*f.fNext); + if (!next) { + return nullptr; + } + this->checkValid(*next); } - this->checkValid(*next); std::unique_ptr statement = this->convertStatement(*f.fStatement); if (!statement) { return nullptr; } - return std::unique_ptr(new ForStatement(f.fPosition, std::move(initializer), + return std::unique_ptr(new ForStatement(f.fPosition, std::move(initializer), std::move(test), std::move(next), std::move(statement), fSymbolTable)); } std::unique_ptr IRGenerator::convertWhile(const ASTWhileStatement& w) { - std::unique_ptr test = this->coerce(this->convertExpression(*w.fTest), + AutoLoopLevel level(this); + std::unique_ptr test = this->coerce(this->convertExpression(*w.fTest), *fContext.fBool_Type); if (!test) { return nullptr; @@ -264,6 +363,7 @@ std::unique_ptr IRGenerator::convertWhile(const ASTWhileStatement& w) } std::unique_ptr IRGenerator::convertDo(const ASTDoStatement& d) { + AutoLoopLevel level(this); std::unique_ptr test = this->coerce(this->convertExpression(*d.fTest), *fContext.fBool_Type); if (!test) { @@ -273,10 +373,64 @@ std::unique_ptr IRGenerator::convertDo(const ASTDoStatement& d) { if (!statement) { return nullptr; } - return std::unique_ptr(new DoStatement(d.fPosition, std::move(statement), + return std::unique_ptr(new DoStatement(d.fPosition, std::move(statement), std::move(test))); } +std::unique_ptr IRGenerator::convertSwitch(const ASTSwitchStatement& s) { + AutoSwitchLevel level(this); + std::unique_ptr value = this->convertExpression(*s.fValue); + if (!value) { + return nullptr; + } + if (value->fType != *fContext.fUInt_Type) { + value = this->coerce(std::move(value), *fContext.fInt_Type); + if (!value) { + return nullptr; + } + } + AutoSymbolTable table(this); + std::unordered_set caseValues; + std::vector> cases; + for (const auto& c : s.fCases) { + std::unique_ptr caseValue; + if (c->fValue) { + caseValue = this->convertExpression(*c->fValue); + if (!caseValue) { + return nullptr; + } + if (caseValue->fType != *fContext.fUInt_Type) { + caseValue = this->coerce(std::move(caseValue), *fContext.fInt_Type); + if (!caseValue) { + return nullptr; + } + } + if (!caseValue->isConstant()) { + fErrors.error(caseValue->fPosition, "case value must be a constant"); + return nullptr; + } + ASSERT(caseValue->fKind == Expression::kIntLiteral_Kind); + int64_t v = ((IntLiteral&) *caseValue).fValue; + if (caseValues.find(v) != caseValues.end()) { + fErrors.error(caseValue->fPosition, "duplicate case value"); + } + caseValues.insert(v); + } + std::vector> statements; + for (const auto& s : c->fStatements) { + std::unique_ptr converted = this->convertStatement(*s); + if (!converted) { + return nullptr; + } + statements.push_back(std::move(converted)); + } + cases.emplace_back(new SwitchCase(c->fPosition, std::move(caseValue), + std::move(statements))); + } + return std::unique_ptr(new SwitchStatement(s.fPosition, std::move(value), + std::move(cases))); +} + std::unique_ptr IRGenerator::convertExpressionStatement( const ASTExpressionStatement& s) { std::unique_ptr e = this->convertExpression(*s.fExpression); @@ -313,51 +467,32 @@ std::unique_ptr IRGenerator::convertReturn(const ASTReturnStatement& } std::unique_ptr IRGenerator::convertBreak(const ASTBreakStatement& b) { - return std::unique_ptr(new BreakStatement(b.fPosition)); + if (fLoopLevel > 0 || fSwitchLevel > 0) { + return std::unique_ptr(new BreakStatement(b.fPosition)); + } else { + fErrors.error(b.fPosition, "break statement must be inside a loop or switch"); + return nullptr; + } } std::unique_ptr IRGenerator::convertContinue(const ASTContinueStatement& c) { - return std::unique_ptr(new ContinueStatement(c.fPosition)); + if (fLoopLevel > 0) { + return std::unique_ptr(new ContinueStatement(c.fPosition)); + } else { + fErrors.error(c.fPosition, "continue statement must be inside a loop"); + return nullptr; + } } std::unique_ptr IRGenerator::convertDiscard(const ASTDiscardStatement& d) { return std::unique_ptr(new DiscardStatement(d.fPosition)); } -static const Type& expand_generics(const Type& type, int i) { - if (type.kind() == Type::kGeneric_Kind) { - return *type.coercibleTypes()[i]; - } - return type; -} - -static void expand_generics(const FunctionDeclaration& decl, - std::shared_ptr symbolTable) { - for (int i = 0; i < 4; i++) { - const Type& returnType = expand_generics(decl.fReturnType, i); - std::vector parameters; - for (const auto& p : decl.fParameters) { - Variable* var = new Variable(p->fPosition, Modifiers(p->fModifiers), p->fName, - expand_generics(p->fType, i), - Variable::kParameter_Storage); - symbolTable->takeOwnership(var); - parameters.push_back(var); - } - symbolTable->add(decl.fName, std::unique_ptr(new FunctionDeclaration( - decl.fPosition, - decl.fName, - std::move(parameters), - std::move(returnType)))); - } -} - std::unique_ptr IRGenerator::convertFunction(const ASTFunction& f) { - bool isGeneric; const Type* returnType = this->convertType(*f.fReturnType); if (!returnType) { return nullptr; } - isGeneric = returnType->kind() == Type::kGeneric_Kind; std::vector parameters; for (const auto& param : f.fParameters) { const Type* type = this->convertType(*param->fType); @@ -366,19 +501,17 @@ std::unique_ptr IRGenerator::convertFunction(const ASTFuncti } for (int j = (int) param->fSizes.size() - 1; j >= 0; j--) { int size = param->fSizes[j]; - std::string name = type->name() + "[" + to_string(size) + "]"; + String name = type->name() + "[" + to_string(size) + "]"; Type* newType = new Type(std::move(name), Type::kArray_Kind, *type, size); fSymbolTable->takeOwnership(newType); type = newType; } - std::string name = param->fName; - Modifiers modifiers = this->convertModifiers(param->fModifiers); + String name = param->fName; Position pos = param->fPosition; - Variable* var = new Variable(pos, modifiers, std::move(name), *type, + Variable* var = new Variable(pos, param->fModifiers, std::move(name), *type, Variable::kParameter_Storage); fSymbolTable->takeOwnership(var); parameters.push_back(var); - isGeneric |= type->kind() == Type::kGeneric_Kind; } // find existing declaration @@ -411,21 +544,22 @@ std::unique_ptr IRGenerator::convertFunction(const ASTFuncti if (*returnType != other->fReturnType) { FunctionDeclaration newDecl(f.fPosition, f.fName, parameters, *returnType); fErrors.error(f.fPosition, "functions '" + newDecl.description() + - "' and '" + other->description() + + "' and '" + other->description() + "' differ only in return type"); return nullptr; } decl = other; for (size_t i = 0; i < parameters.size(); i++) { if (parameters[i]->fModifiers != other->fParameters[i]->fModifiers) { - fErrors.error(f.fPosition, "modifiers on parameter " + - to_string(i + 1) + " differ between " + - "declaration and definition"); + fErrors.error(f.fPosition, "modifiers on parameter " + + to_string((uint64_t) i + 1) + + " differ between declaration and " + "definition"); return nullptr; } } if (other->fDefined) { - fErrors.error(f.fPosition, "duplicate definition of " + + fErrors.error(f.fPosition, "duplicate definition of " + other->description()); } break; @@ -435,19 +569,12 @@ std::unique_ptr IRGenerator::convertFunction(const ASTFuncti } if (!decl) { // couldn't find an existing declaration - if (isGeneric) { - ASSERT(!f.fBody); - expand_generics(FunctionDeclaration(f.fPosition, f.fName, parameters, *returnType), - fSymbolTable); - } else { - auto newDecl = std::unique_ptr(new FunctionDeclaration( - f.fPosition, - f.fName, - parameters, - *returnType)); - decl = newDecl.get(); - fSymbolTable->add(decl->fName, std::move(newDecl)); - } + auto newDecl = std::unique_ptr(new FunctionDeclaration(f.fPosition, + f.fName, + parameters, + *returnType)); + decl = newDecl.get(); + fSymbolTable->add(decl->fName, std::move(newDecl)); } if (f.fBody) { ASSERT(!fCurrentFunction); @@ -463,7 +590,7 @@ std::unique_ptr IRGenerator::convertFunction(const ASTFuncti if (!body) { return nullptr; } - return std::unique_ptr(new FunctionDefinition(f.fPosition, *decl, + return std::unique_ptr(new FunctionDefinition(f.fPosition, *decl, std::move(body))); } return nullptr; @@ -472,17 +599,19 @@ std::unique_ptr IRGenerator::convertFunction(const ASTFuncti std::unique_ptr IRGenerator::convertInterfaceBlock(const ASTInterfaceBlock& intf) { std::shared_ptr old = fSymbolTable; AutoSymbolTable table(this); - Modifiers mods = this->convertModifiers(intf.fModifiers); std::vector fields; for (size_t i = 0; i < intf.fDeclarations.size(); i++) { std::unique_ptr decl = this->convertVarDeclarations( - *intf.fDeclarations[i], + *intf.fDeclarations[i], Variable::kGlobal_Storage); + if (!decl) { + return nullptr; + } for (const auto& var : decl->fVars) { - fields.push_back(Type::Field(var.fVar->fModifiers, var.fVar->fName, + fields.push_back(Type::Field(var.fVar->fModifiers, var.fVar->fName, &var.fVar->fType)); if (var.fValue) { - fErrors.error(decl->fPosition, + fErrors.error(decl->fPosition, "initializers are not permitted on interface block fields"); } if (var.fVar->fModifiers.fFlags & (Modifiers::kIn_Flag | @@ -492,27 +621,70 @@ std::unique_ptr IRGenerator::convertInterfaceBlock(const ASTInte fErrors.error(decl->fPosition, "interface block fields may not have storage qualifiers"); } - } + } } - Type* type = new Type(intf.fInterfaceName, fields); - fSymbolTable->takeOwnership(type); - std::string name = intf.fValueName.length() > 0 ? intf.fValueName : intf.fInterfaceName; - Variable* var = new Variable(intf.fPosition, mods, name, *type, Variable::kGlobal_Storage); - fSymbolTable->takeOwnership(var); - if (intf.fValueName.length()) { - old->addWithoutOwnership(intf.fValueName, var); + Type* type = new Type(intf.fPosition, intf.fTypeName, fields); + old->takeOwnership(type); + std::vector> sizes; + for (const auto& size : intf.fSizes) { + if (size) { + std::unique_ptr converted = this->convertExpression(*size); + if (!converted) { + return nullptr; + } + String name = type->fName; + int64_t count; + if (converted->fKind == Expression::kIntLiteral_Kind) { + count = ((IntLiteral&) *converted).fValue; + if (count <= 0) { + fErrors.error(converted->fPosition, "array size must be positive"); + } + name += "[" + to_string(count) + "]"; + } else { + count = -1; + name += "[]"; + } + type = new Type(name, Type::kArray_Kind, *type, (int) count); + fSymbolTable->takeOwnership((Type*) type); + sizes.push_back(std::move(converted)); + } else { + type = new Type(type->fName + "[]", Type::kArray_Kind, *type, -1); + fSymbolTable->takeOwnership((Type*) type); + sizes.push_back(nullptr); + } + } + Variable* var = new Variable(intf.fPosition, intf.fModifiers, + intf.fInstanceName.size() ? intf.fInstanceName : intf.fTypeName, + *type, Variable::kGlobal_Storage); + old->takeOwnership(var); + if (intf.fInstanceName.size()) { + old->addWithoutOwnership(intf.fInstanceName, var); } else { for (size_t i = 0; i < fields.size(); i++) { - old->add(fields[i].fName, std::unique_ptr(new Field(intf.fPosition, *var, + old->add(fields[i].fName, std::unique_ptr(new Field(intf.fPosition, *var, (int) i))); } } - return std::unique_ptr(new InterfaceBlock(intf.fPosition, *var, fSymbolTable)); + return std::unique_ptr(new InterfaceBlock(intf.fPosition, + var, + intf.fTypeName, + intf.fInstanceName, + std::move(sizes), + fSymbolTable)); } const Type* IRGenerator::convertType(const ASTType& type) { const Symbol* result = (*fSymbolTable)[type.fName]; if (result && result->fKind == Symbol::kType_Kind) { + for (int size : type.fSizes) { + String name = result->fName + "["; + if (size != -1) { + name += to_string(size); + } + name += "]"; + result = new Type(name, Type::kArray_Kind, (const Type&) *result, size); + fSymbolTable->takeOwnership((Type*) result); + } return (const Type*) result; } fErrors.error(type.fPosition, "unknown type '" + type.fName + "'"); @@ -568,13 +740,24 @@ std::unique_ptr IRGenerator::convertIdentifier(const ASTIdentifier& } case Symbol::kVariable_Kind: { const Variable* var = (const Variable*) result; - this->markReadFrom(*var); - return std::unique_ptr(new VariableReference(identifier.fPosition, - *var)); + if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) { + fInputs.fFlipY = true; + if (fSettings->fFlipY && + (!fSettings->fCaps || + !fSettings->fCaps->fragCoordConventionsExtensionString())) { + fInputs.fRTHeight = true; + } + } + // default to kRead_RefKind; this will be corrected later if the variable is written to + return std::unique_ptr(new VariableReference( + identifier.fPosition, + *var, + VariableReference::kRead_RefKind)); } case Symbol::kField_Kind: { const Field* field = (const Field*) result; - VariableReference* base = new VariableReference(identifier.fPosition, field->fOwner); + VariableReference* base = new VariableReference(identifier.fPosition, field->fOwner, + VariableReference::kRead_RefKind); return std::unique_ptr(new FieldAccess( std::unique_ptr(base), field->fFieldIndex, @@ -582,7 +765,7 @@ std::unique_ptr IRGenerator::convertIdentifier(const ASTIdentifier& } case Symbol::kType_Kind: { const Type* t = (const Type*) result; - return std::unique_ptr(new TypeReference(fContext, identifier.fPosition, + return std::unique_ptr(new TypeReference(fContext, identifier.fPosition, *t)); } default: @@ -591,7 +774,7 @@ std::unique_ptr IRGenerator::convertIdentifier(const ASTIdentifier& } -std::unique_ptr IRGenerator::coerce(std::unique_ptr expr, +std::unique_ptr IRGenerator::coerce(std::unique_ptr expr, const Type& type) { if (!expr) { return nullptr; @@ -604,7 +787,7 @@ std::unique_ptr IRGenerator::coerce(std::unique_ptr expr return nullptr; } if (!expr->fType.canCoerceTo(type)) { - fErrors.error(expr->fPosition, "expected '" + type.description() + "', but found '" + + fErrors.error(expr->fPosition, "expected '" + type.description() + "', but found '" + expr->fType.description() + "'"); return nullptr; } @@ -616,8 +799,9 @@ std::unique_ptr IRGenerator::coerce(std::unique_ptr expr ASSERT(ctor); return this->call(Position(), std::move(ctor), std::move(args)); } - ABORT("cannot coerce %s to %s", expr->fType.description().c_str(), - type.description().c_str()); + std::vector> args; + args.push_back(std::move(expr)); + return std::unique_ptr(new Constructor(Position(), type, std::move(args))); } static bool is_matrix_multiply(const Type& left, const Type& right) { @@ -626,27 +810,38 @@ static bool is_matrix_multiply(const Type& left, const Type& right) { } return left.kind() == Type::kVector_Kind && right.kind() == Type::kMatrix_Kind; } + /** * Determines the operand and result types of a binary expression. Returns true if the expression is * legal, false otherwise. If false, the values of the out parameters are undefined. */ -static bool determine_binary_type(const Context& context, - Token::Kind op, - const Type& left, - const Type& right, +static bool determine_binary_type(const Context& context, + Token::Kind op, + const Type& left, + const Type& right, const Type** outLeftType, const Type** outRightType, const Type** outResultType, bool tryFlipped) { bool isLogical; + bool validMatrixOrVectorOp; switch (op) { + case Token::EQ: + *outLeftType = &left; + *outRightType = &left; + *outResultType = &left; + return right.canCoerceTo(left); case Token::EQEQ: // fall through - case Token::NEQ: // fall through + case Token::NEQ: + isLogical = true; + validMatrixOrVectorOp = true; + break; case Token::LT: // fall through case Token::GT: // fall through case Token::LTEQ: // fall through case Token::GTEQ: isLogical = true; + validMatrixOrVectorOp = false; break; case Token::LOGICALOR: // fall through case Token::LOGICALAND: // fall through @@ -657,18 +852,18 @@ static bool determine_binary_type(const Context& context, *outLeftType = context.fBool_Type.get(); *outRightType = context.fBool_Type.get(); *outResultType = context.fBool_Type.get(); - return left.canCoerceTo(*context.fBool_Type) && + return left.canCoerceTo(*context.fBool_Type) && right.canCoerceTo(*context.fBool_Type); case Token::STAR: // fall through - case Token::STAREQ: + case Token::STAREQ: if (is_matrix_multiply(left, right)) { // determine final component type if (determine_binary_type(context, Token::STAR, left.componentType(), right.componentType(), outLeftType, outRightType, outResultType, false)) { - *outLeftType = &(*outResultType)->toCompound(context, left.columns(), + *outLeftType = &(*outResultType)->toCompound(context, left.columns(), left.rows());; - *outRightType = &(*outResultType)->toCompound(context, right.columns(), + *outRightType = &(*outResultType)->toCompound(context, right.columns(), right.rows());; int leftColumns = left.columns(); int leftRows = left.rows(); @@ -697,13 +892,26 @@ static bool determine_binary_type(const Context& context, return false; } } - // fall through + isLogical = false; + validMatrixOrVectorOp = true; + break; + case Token::PLUS: // fall through + case Token::PLUSEQ: // fall through + case Token::MINUS: // fall through + case Token::MINUSEQ: // fall through + case Token::SLASH: // fall through + case Token::SLASHEQ: + isLogical = false; + validMatrixOrVectorOp = true; + break; default: isLogical = false; + validMatrixOrVectorOp = false; } - // FIXME: need to disallow illegal operations like vec3 > vec3. Also do not currently have - // full support for numbers other than float. - if (left == right) { + bool isVectorOrMatrix = left.kind() == Type::kVector_Kind || left.kind() == Type::kMatrix_Kind; + // FIXME: incorrect for shift + if (right.canCoerceTo(left) && (left.kind() == Type::kScalar_Kind || + (isVectorOrMatrix && validMatrixOrVectorOp))) { *outLeftType = &left; *outRightType = &left; if (isLogical) { @@ -713,24 +921,13 @@ static bool determine_binary_type(const Context& context, } return true; } - // FIXME: incorrect for shift operations - if (left.canCoerceTo(right)) { - *outLeftType = &right; - *outRightType = &right; - if (isLogical) { - *outResultType = context.fBool_Type.get(); - } else { - *outResultType = &right; - } - return true; - } - if ((left.kind() == Type::kVector_Kind || left.kind() == Type::kMatrix_Kind) && + if ((left.kind() == Type::kVector_Kind || left.kind() == Type::kMatrix_Kind) && (right.kind() == Type::kScalar_Kind)) { - if (determine_binary_type(context, op, left.componentType(), right, outLeftType, + if (determine_binary_type(context, op, left.componentType(), right, outLeftType, outRightType, outResultType, false)) { *outLeftType = &(*outLeftType)->toCompound(context, left.columns(), left.rows()); if (!isLogical) { - *outResultType = &(*outResultType)->toCompound(context, left.columns(), + *outResultType = &(*outResultType)->toCompound(context, left.columns(), left.rows()); } return true; @@ -738,12 +935,94 @@ static bool determine_binary_type(const Context& context, return false; } if (tryFlipped) { - return determine_binary_type(context, op, right, left, outRightType, outLeftType, + return determine_binary_type(context, op, right, left, outRightType, outLeftType, outResultType, false); } return false; } +std::unique_ptr IRGenerator::constantFold(const Expression& left, + Token::Kind op, + const Expression& right) const { + // Note that we expressly do not worry about precision and overflow here -- we use the maximum + // precision to calculate the results and hope the result makes sense. The plan is to move the + // Skia caps into SkSL, so we have access to all of them including the precisions of the various + // types, which will let us be more intelligent about this. + if (left.fKind == Expression::kBoolLiteral_Kind && + right.fKind == Expression::kBoolLiteral_Kind) { + bool leftVal = ((BoolLiteral&) left).fValue; + bool rightVal = ((BoolLiteral&) right).fValue; + bool result; + switch (op) { + case Token::LOGICALAND: result = leftVal && rightVal; break; + case Token::LOGICALOR: result = leftVal || rightVal; break; + case Token::LOGICALXOR: result = leftVal ^ rightVal; break; + default: return nullptr; + } + return std::unique_ptr(new BoolLiteral(fContext, left.fPosition, result)); + } + #define RESULT(t, op) std::unique_ptr(new t ## Literal(fContext, left.fPosition, \ + leftVal op rightVal)) + if (left.fKind == Expression::kIntLiteral_Kind && right.fKind == Expression::kIntLiteral_Kind) { + int64_t leftVal = ((IntLiteral&) left).fValue; + int64_t rightVal = ((IntLiteral&) right).fValue; + switch (op) { + case Token::PLUS: return RESULT(Int, +); + case Token::MINUS: return RESULT(Int, -); + case Token::STAR: return RESULT(Int, *); + case Token::SLASH: + if (rightVal) { + return RESULT(Int, /); + } + fErrors.error(right.fPosition, "division by zero"); + return nullptr; + case Token::PERCENT: + if (rightVal) { + return RESULT(Int, %); + } + fErrors.error(right.fPosition, "division by zero"); + return nullptr; + case Token::BITWISEAND: return RESULT(Int, &); + case Token::BITWISEOR: return RESULT(Int, |); + case Token::BITWISEXOR: return RESULT(Int, ^); + case Token::SHL: return RESULT(Int, <<); + case Token::SHR: return RESULT(Int, >>); + case Token::EQEQ: return RESULT(Bool, ==); + case Token::NEQ: return RESULT(Bool, !=); + case Token::GT: return RESULT(Bool, >); + case Token::GTEQ: return RESULT(Bool, >=); + case Token::LT: return RESULT(Bool, <); + case Token::LTEQ: return RESULT(Bool, <=); + default: return nullptr; + } + } + if (left.fKind == Expression::kFloatLiteral_Kind && + right.fKind == Expression::kFloatLiteral_Kind) { + double leftVal = ((FloatLiteral&) left).fValue; + double rightVal = ((FloatLiteral&) right).fValue; + switch (op) { + case Token::PLUS: return RESULT(Float, +); + case Token::MINUS: return RESULT(Float, -); + case Token::STAR: return RESULT(Float, *); + case Token::SLASH: + if (rightVal) { + return RESULT(Float, /); + } + fErrors.error(right.fPosition, "division by zero"); + return nullptr; + case Token::EQEQ: return RESULT(Bool, ==); + case Token::NEQ: return RESULT(Bool, !=); + case Token::GT: return RESULT(Bool, >); + case Token::GTEQ: return RESULT(Bool, >=); + case Token::LT: return RESULT(Bool, <); + case Token::LTEQ: return RESULT(Bool, <=); + default: return nullptr; + } + } + #undef RESULT + return nullptr; +} + std::unique_ptr IRGenerator::convertBinaryExpression( const ASTBinaryExpression& expression) { std::unique_ptr left = this->convertExpression(*expression.fLeft); @@ -758,44 +1037,37 @@ std::unique_ptr IRGenerator::convertBinaryExpression( const Type* rightType; const Type* resultType; if (!determine_binary_type(fContext, expression.fOperator, left->fType, right->fType, &leftType, - &rightType, &resultType, true)) { - fErrors.error(expression.fPosition, "type mismatch: '" + - Token::OperatorName(expression.fOperator) + - "' cannot operate on '" + left->fType.fName + + &rightType, &resultType, + !Token::IsAssignment(expression.fOperator))) { + fErrors.error(expression.fPosition, "type mismatch: '" + + Token::OperatorName(expression.fOperator) + + "' cannot operate on '" + left->fType.fName + "', '" + right->fType.fName + "'"); return nullptr; } - switch (expression.fOperator) { - case Token::EQ: // fall through - case Token::PLUSEQ: // fall through - case Token::MINUSEQ: // fall through - case Token::STAREQ: // fall through - case Token::SLASHEQ: // fall through - case Token::PERCENTEQ: // fall through - case Token::SHLEQ: // fall through - case Token::SHREQ: // fall through - case Token::BITWISEOREQ: // fall through - case Token::BITWISEXOREQ: // fall through - case Token::BITWISEANDEQ: // fall through - case Token::LOGICALOREQ: // fall through - case Token::LOGICALXOREQ: // fall through - case Token::LOGICALANDEQ: - this->markWrittenTo(*left); - default: - break; + if (Token::IsAssignment(expression.fOperator)) { + this->markWrittenTo(*left, expression.fOperator != Token::EQ); } - return std::unique_ptr(new BinaryExpression(expression.fPosition, - this->coerce(std::move(left), - *leftType), - expression.fOperator, - this->coerce(std::move(right), - *rightType), - *resultType)); + left = this->coerce(std::move(left), *leftType); + right = this->coerce(std::move(right), *rightType); + if (!left || !right) { + return nullptr; + } + std::unique_ptr result = this->constantFold(*left.get(), expression.fOperator, + *right.get()); + if (!result) { + result = std::unique_ptr(new BinaryExpression(expression.fPosition, + std::move(left), + expression.fOperator, + std::move(right), + *resultType)); + } + return result; } -std::unique_ptr IRGenerator::convertTernaryExpression( +std::unique_ptr IRGenerator::convertTernaryExpression( const ASTTernaryExpression& expression) { - std::unique_ptr test = this->coerce(this->convertExpression(*expression.fTest), + std::unique_ptr test = this->coerce(this->convertExpression(*expression.fTest), *fContext.fBool_Type); if (!test) { return nullptr; @@ -812,60 +1084,95 @@ std::unique_ptr IRGenerator::convertTernaryExpression( const Type* falseType; const Type* resultType; if (!determine_binary_type(fContext, Token::EQEQ, ifTrue->fType, ifFalse->fType, &trueType, - &falseType, &resultType, true)) { - fErrors.error(expression.fPosition, "ternary operator result mismatch: '" + - ifTrue->fType.fName + "', '" + + &falseType, &resultType, true) || trueType != falseType) { + fErrors.error(expression.fPosition, "ternary operator result mismatch: '" + + ifTrue->fType.fName + "', '" + ifFalse->fType.fName + "'"); return nullptr; } - ASSERT(trueType == falseType); ifTrue = this->coerce(std::move(ifTrue), *trueType); + if (!ifTrue) { + return nullptr; + } ifFalse = this->coerce(std::move(ifFalse), *falseType); - return std::unique_ptr(new TernaryExpression(expression.fPosition, + if (!ifFalse) { + return nullptr; + } + if (test->fKind == Expression::kBoolLiteral_Kind) { + // static boolean test, just return one of the branches + if (((BoolLiteral&) *test).fValue) { + return ifTrue; + } else { + return ifFalse; + } + } + return std::unique_ptr(new TernaryExpression(expression.fPosition, std::move(test), - std::move(ifTrue), + std::move(ifTrue), std::move(ifFalse))); } -std::unique_ptr IRGenerator::call(Position position, - const FunctionDeclaration& function, +std::unique_ptr IRGenerator::call(Position position, + const FunctionDeclaration& function, std::vector> arguments) { if (function.fParameters.size() != arguments.size()) { - std::string msg = "call to '" + function.fName + "' expected " + - to_string(function.fParameters.size()) + + String msg = "call to '" + function.fName + "' expected " + + to_string((uint64_t) function.fParameters.size()) + " argument"; if (function.fParameters.size() != 1) { msg += "s"; } - msg += ", but found " + to_string(arguments.size()); + msg += ", but found " + to_string((uint64_t) arguments.size()); + fErrors.error(position, msg); + return nullptr; + } + std::vector types; + const Type* returnType; + if (!function.determineFinalTypes(arguments, &types, &returnType)) { + String msg = "no match for " + function.fName + "("; + String separator; + for (size_t i = 0; i < arguments.size(); i++) { + msg += separator; + separator = ", "; + msg += arguments[i]->fType.description(); + } + msg += ")"; fErrors.error(position, msg); return nullptr; } for (size_t i = 0; i < arguments.size(); i++) { - arguments[i] = this->coerce(std::move(arguments[i]), function.fParameters[i]->fType); + arguments[i] = this->coerce(std::move(arguments[i]), *types[i]); + if (!arguments[i]) { + return nullptr; + } if (arguments[i] && (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag)) { - this->markWrittenTo(*arguments[i]); + this->markWrittenTo(*arguments[i], true); } } - return std::unique_ptr(new FunctionCall(position, function, + return std::unique_ptr(new FunctionCall(position, *returnType, function, std::move(arguments))); } /** - * Determines the cost of coercing the arguments of a function to the required types. Returns true - * if the cost could be computed, false if the call is not valid. Cost has no particular meaning + * Determines the cost of coercing the arguments of a function to the required types. Returns true + * if the cost could be computed, false if the call is not valid. Cost has no particular meaning * other than "lower costs are preferred". */ -bool IRGenerator::determineCallCost(const FunctionDeclaration& function, +bool IRGenerator::determineCallCost(const FunctionDeclaration& function, const std::vector>& arguments, int* outCost) { if (function.fParameters.size() != arguments.size()) { return false; } int total = 0; + std::vector types; + const Type* ignored; + if (!function.determineFinalTypes(arguments, &types, &ignored)) { + return false; + } for (size_t i = 0; i < arguments.size(); i++) { int cost; - if (arguments[i]->fType.determineCoercionCost(function.fParameters[i]->fType, &cost)) { + if (arguments[i]->fType.determineCoercionCost(*types[i], &cost)) { total += cost; } else { return false; @@ -875,12 +1182,12 @@ bool IRGenerator::determineCallCost(const FunctionDeclaration& function, return true; } -std::unique_ptr IRGenerator::call(Position position, - std::unique_ptr functionValue, +std::unique_ptr IRGenerator::call(Position position, + std::unique_ptr functionValue, std::vector> arguments) { if (functionValue->fKind == Expression::kTypeReference_Kind) { - return this->convertConstructor(position, - ((TypeReference&) *functionValue).fValue, + return this->convertConstructor(position, + ((TypeReference&) *functionValue).fValue, std::move(arguments)); } if (functionValue->fKind != Expression::kFunctionReference_Kind) { @@ -901,8 +1208,8 @@ std::unique_ptr IRGenerator::call(Position position, if (best) { return this->call(position, *best, std::move(arguments)); } - std::string msg = "no match for " + ref->fFunctions[0]->fName + "("; - std::string separator = ""; + String msg = "no match for " + ref->fFunctions[0]->fName + "("; + String separator; for (size_t i = 0; i < arguments.size(); i++) { msg += separator; separator = ", "; @@ -915,59 +1222,90 @@ std::unique_ptr IRGenerator::call(Position position, return this->call(position, *ref->fFunctions[0], std::move(arguments)); } -std::unique_ptr IRGenerator::convertConstructor( - Position position, - const Type& type, +std::unique_ptr IRGenerator::convertNumberConstructor( + Position position, + const Type& type, std::vector> args) { - // FIXME: add support for structs and arrays - Type::Kind kind = type.kind(); - if (!type.isNumber() && kind != Type::kVector_Kind && kind != Type::kMatrix_Kind) { - fErrors.error(position, "cannot construct '" + type.description() + "'"); + ASSERT(type.isNumber()); + if (args.size() != 1) { + fErrors.error(position, "invalid arguments to '" + type.description() + + "' constructor, (expected exactly 1 argument, but found " + + to_string((uint64_t) args.size()) + ")"); return nullptr; } - if (type == *fContext.fFloat_Type && args.size() == 1 && + if (type == *fContext.fFloat_Type && args.size() == 1 && args[0]->fKind == Expression::kIntLiteral_Kind) { int64_t value = ((IntLiteral&) *args[0]).fValue; return std::unique_ptr(new FloatLiteral(fContext, position, (double) value)); } - if (args.size() == 1 && args[0]->fType == type) { - // argument is already the right type, just return it - return std::move(args[0]); + if (args[0]->fKind == Expression::kIntLiteral_Kind && (type == *fContext.fInt_Type || + type == *fContext.fUInt_Type)) { + return std::unique_ptr(new IntLiteral(fContext, + position, + ((IntLiteral&) *args[0]).fValue, + &type)); } - if (type.isNumber()) { - if (args.size() != 1) { - fErrors.error(position, "invalid arguments to '" + type.description() + - "' constructor, (expected exactly 1 argument, but found " + - to_string(args.size()) + ")"); - } - if (args[0]->fType == *fContext.fBool_Type) { - std::unique_ptr zero(new IntLiteral(fContext, position, 0)); - std::unique_ptr one(new IntLiteral(fContext, position, 1)); - return std::unique_ptr( - new TernaryExpression(position, std::move(args[0]), - this->coerce(std::move(one), type), - this->coerce(std::move(zero), - type))); - } else if (!args[0]->fType.isNumber()) { - fErrors.error(position, "invalid argument to '" + type.description() + - "' constructor (expected a number or bool, but found '" + - args[0]->fType.description() + "')"); - } - } else { - ASSERT(kind == Type::kVector_Kind || kind == Type::kMatrix_Kind); - int actual = 0; + if (args[0]->fType == *fContext.fBool_Type) { + std::unique_ptr zero(new IntLiteral(fContext, position, 0)); + std::unique_ptr one(new IntLiteral(fContext, position, 1)); + return std::unique_ptr( + new TernaryExpression(position, std::move(args[0]), + this->coerce(std::move(one), type), + this->coerce(std::move(zero), + type))); + } + if (!args[0]->fType.isNumber()) { + fErrors.error(position, "invalid argument to '" + type.description() + + "' constructor (expected a number or bool, but found '" + + args[0]->fType.description() + "')"); + return nullptr; + } + return std::unique_ptr(new Constructor(position, std::move(type), std::move(args))); +} + +int component_count(const Type& type) { + switch (type.kind()) { + case Type::kVector_Kind: + return type.columns(); + case Type::kMatrix_Kind: + return type.columns() * type.rows(); + default: + return 1; + } +} + +std::unique_ptr IRGenerator::convertCompoundConstructor( + Position position, + const Type& type, + std::vector> args) { + ASSERT(type.kind() == Type::kVector_Kind || type.kind() == Type::kMatrix_Kind); + if (type.kind() == Type::kMatrix_Kind && args.size() == 1 && + args[0]->fType.kind() == Type::kMatrix_Kind) { + // matrix from matrix is always legal + return std::unique_ptr(new Constructor(position, std::move(type), + std::move(args))); + } + int actual = 0; + int expected = type.rows() * type.columns(); + if (args.size() != 1 || expected != component_count(args[0]->fType) || + type.componentType().isNumber() != args[0]->fType.componentType().isNumber()) { for (size_t i = 0; i < args.size(); i++) { - if (args[i]->fType.kind() == Type::kVector_Kind || - args[i]->fType.kind() == Type::kMatrix_Kind) { - int columns = args[i]->fType.columns(); - int rows = args[i]->fType.rows(); - args[i] = this->coerce(std::move(args[i]), - type.componentType().toCompound(fContext, columns, rows)); - actual += args[i]->fType.rows() * args[i]->fType.columns(); + if (args[i]->fType.kind() == Type::kVector_Kind) { + if (type.componentType().isNumber() != + args[i]->fType.componentType().isNumber()) { + fErrors.error(position, "'" + args[i]->fType.description() + "' is not a valid " + "parameter to '" + type.description() + + "' constructor"); + return nullptr; + } + actual += args[i]->fType.columns(); } else if (args[i]->fType.kind() == Type::kScalar_Kind) { actual += 1; if (type.kind() != Type::kScalar_Kind) { args[i] = this->coerce(std::move(args[i]), type.componentType()); + if (!args[i]) { + return nullptr; + } } } else { fErrors.error(position, "'" + args[i]->fType.description() + "' is not a valid " @@ -975,20 +1313,46 @@ std::unique_ptr IRGenerator::convertConstructor( return nullptr; } } - int min = type.rows() * type.columns(); - int max = type.columns() > 1 ? INT_MAX : min; - if ((actual < min || actual > max) && - !((kind == Type::kVector_Kind || kind == Type::kMatrix_Kind) && (actual == 1))) { - fErrors.error(position, "invalid arguments to '" + type.description() + - "' constructor (expected " + to_string(min) + " scalar" + - (min == 1 ? "" : "s") + ", but found " + to_string(actual) + - ")"); + if (actual != 1 && actual != expected) { + fErrors.error(position, "invalid arguments to '" + type.description() + + "' constructor (expected " + to_string(expected) + + " scalars, but found " + to_string(actual) + ")"); return nullptr; } } return std::unique_ptr(new Constructor(position, std::move(type), std::move(args))); } +std::unique_ptr IRGenerator::convertConstructor( + Position position, + const Type& type, + std::vector> args) { + // FIXME: add support for structs + Type::Kind kind = type.kind(); + if (args.size() == 1 && args[0]->fType == type) { + // argument is already the right type, just return it + return std::move(args[0]); + } + if (type.isNumber()) { + return this->convertNumberConstructor(position, type, std::move(args)); + } else if (kind == Type::kArray_Kind) { + const Type& base = type.componentType(); + for (size_t i = 0; i < args.size(); i++) { + args[i] = this->coerce(std::move(args[i]), base); + if (!args[i]) { + return nullptr; + } + } + return std::unique_ptr(new Constructor(position, std::move(type), + std::move(args))); + } else if (kind == Type::kVector_Kind || kind == Type::kMatrix_Kind) { + return this->convertCompoundConstructor(position, type, std::move(args)); + } else { + fErrors.error(position, "cannot construct '" + type.description() + "'"); + return nullptr; + } +} + std::unique_ptr IRGenerator::convertPrefixExpression( const ASTPrefixExpression& expression) { std::unique_ptr base = this->convertExpression(*expression.fOperand); @@ -998,14 +1362,14 @@ std::unique_ptr IRGenerator::convertPrefixExpression( switch (expression.fOperator) { case Token::PLUS: if (!base->fType.isNumber() && base->fType.kind() != Type::kVector_Kind) { - fErrors.error(expression.fPosition, + fErrors.error(expression.fPosition, "'+' cannot operate on '" + base->fType.description() + "'"); return nullptr; } return base; case Token::MINUS: if (!base->fType.isNumber() && base->fType.kind() != Type::kVector_Kind) { - fErrors.error(expression.fPosition, + fErrors.error(expression.fPosition, "'-' cannot operate on '" + base->fType.description() + "'"); return nullptr; } @@ -1015,47 +1379,75 @@ std::unique_ptr IRGenerator::convertPrefixExpression( } if (base->fKind == Expression::kFloatLiteral_Kind) { double value = -((FloatLiteral&) *base).fValue; - return std::unique_ptr(new FloatLiteral(fContext, base->fPosition, + return std::unique_ptr(new FloatLiteral(fContext, base->fPosition, value)); } return std::unique_ptr(new PrefixExpression(Token::MINUS, std::move(base))); case Token::PLUSPLUS: if (!base->fType.isNumber()) { - fErrors.error(expression.fPosition, - "'" + Token::OperatorName(expression.fOperator) + + fErrors.error(expression.fPosition, + "'" + Token::OperatorName(expression.fOperator) + "' cannot operate on '" + base->fType.description() + "'"); return nullptr; } - this->markWrittenTo(*base); + this->markWrittenTo(*base, true); break; - case Token::MINUSMINUS: + case Token::MINUSMINUS: if (!base->fType.isNumber()) { - fErrors.error(expression.fPosition, - "'" + Token::OperatorName(expression.fOperator) + + fErrors.error(expression.fPosition, + "'" + Token::OperatorName(expression.fOperator) + "' cannot operate on '" + base->fType.description() + "'"); return nullptr; } - this->markWrittenTo(*base); + this->markWrittenTo(*base, true); break; - case Token::NOT: + case Token::LOGICALNOT: if (base->fType != *fContext.fBool_Type) { - fErrors.error(expression.fPosition, - "'" + Token::OperatorName(expression.fOperator) + + fErrors.error(expression.fPosition, + "'" + Token::OperatorName(expression.fOperator) + + "' cannot operate on '" + base->fType.description() + "'"); + return nullptr; + } + if (base->fKind == Expression::kBoolLiteral_Kind) { + return std::unique_ptr(new BoolLiteral(fContext, base->fPosition, + !((BoolLiteral&) *base).fValue)); + } + break; + case Token::BITWISENOT: + if (base->fType != *fContext.fInt_Type) { + fErrors.error(expression.fPosition, + "'" + Token::OperatorName(expression.fOperator) + "' cannot operate on '" + base->fType.description() + "'"); return nullptr; } break; - default: + default: ABORT("unsupported prefix operator\n"); } - return std::unique_ptr(new PrefixExpression(expression.fOperator, + return std::unique_ptr(new PrefixExpression(expression.fOperator, std::move(base))); } std::unique_ptr IRGenerator::convertIndex(std::unique_ptr base, const ASTExpression& index) { - if (base->fType.kind() != Type::kArray_Kind && base->fType.kind() != Type::kMatrix_Kind) { - fErrors.error(base->fPosition, "expected array, but found '" + base->fType.description() + + if (base->fKind == Expression::kTypeReference_Kind) { + if (index.fKind == ASTExpression::kInt_Kind) { + const Type& oldType = ((TypeReference&) *base).fValue; + int64_t size = ((const ASTIntLiteral&) index).fValue; + Type* newType = new Type(oldType.name() + "[" + to_string(size) + "]", + Type::kArray_Kind, oldType, size); + fSymbolTable->takeOwnership(newType); + return std::unique_ptr(new TypeReference(fContext, base->fPosition, + *newType)); + + } else { + fErrors.error(base->fPosition, "array size must be a constant"); + return nullptr; + } + } + if (base->fType.kind() != Type::kArray_Kind && base->fType.kind() != Type::kMatrix_Kind && + base->fType.kind() != Type::kVector_Kind) { + fErrors.error(base->fPosition, "expected array, but found '" + base->fType.description() + "'"); return nullptr; } @@ -1063,16 +1455,18 @@ std::unique_ptr IRGenerator::convertIndex(std::unique_ptrcoerce(std::move(converted), *fContext.fInt_Type); - if (!converted) { - return nullptr; + if (converted->fType != *fContext.fUInt_Type) { + converted = this->coerce(std::move(converted), *fContext.fInt_Type); + if (!converted) { + return nullptr; + } } - return std::unique_ptr(new IndexExpression(fContext, std::move(base), + return std::unique_ptr(new IndexExpression(fContext, std::move(base), std::move(converted))); } std::unique_ptr IRGenerator::convertField(std::unique_ptr base, - const std::string& field) { + const String& field) { auto fields = base->fType.fields(); for (size_t i = 0; i < fields.size(); i++) { if (fields[i].fName == field) { @@ -1085,17 +1479,17 @@ std::unique_ptr IRGenerator::convertField(std::unique_ptr IRGenerator::convertSwizzle(std::unique_ptr base, - const std::string& fields) { + const String& fields) { if (base->fType.kind() != Type::kVector_Kind) { fErrors.error(base->fPosition, "cannot swizzle type '" + base->fType.description() + "'"); return nullptr; } std::vector swizzleComponents; - for (char c : fields) { - switch (c) { + for (size_t i = 0; i < fields.size(); i++) { + switch (fields[i]) { case 'x': // fall through case 'r': // fall through - case 's': + case 's': swizzleComponents.push_back(0); break; case 'y': // fall through @@ -1108,7 +1502,7 @@ std::unique_ptr IRGenerator::convertSwizzle(std::unique_ptrfType.columns() >= 3) { swizzleComponents.push_back(2); break; @@ -1123,8 +1517,8 @@ std::unique_ptr IRGenerator::convertSwizzle(std::unique_ptrfPosition, "invalid swizzle component '" + std::string(1, c) + - "'"); + fErrors.error(base->fPosition, String::printf("invalid swizzle component '%c'", + fields[i])); return nullptr; } } @@ -1136,6 +1530,24 @@ std::unique_ptr IRGenerator::convertSwizzle(std::unique_ptr(new Swizzle(fContext, std::move(base), swizzleComponents)); } +std::unique_ptr IRGenerator::getCap(Position position, String name) { + auto found = fCapsMap.find(name); + if (found == fCapsMap.end()) { + fErrors.error(position, "unknown capability flag '" + name + "'"); + return nullptr; + } + switch (found->second.fKind) { + case CapValue::kBool_Kind: + return std::unique_ptr(new BoolLiteral(fContext, position, + (bool) found->second.fValue)); + case CapValue::kInt_Kind: + return std::unique_ptr(new IntLiteral(fContext, position, + found->second.fValue)); + } + ASSERT(false); + return nullptr; +} + std::unique_ptr IRGenerator::convertSuffixExpression( const ASTSuffixExpression& expression) { std::unique_ptr base = this->convertExpression(*expression.fBase); @@ -1143,14 +1555,27 @@ std::unique_ptr IRGenerator::convertSuffixExpression( return nullptr; } switch (expression.fSuffix->fKind) { - case ASTSuffix::kIndex_Kind: - return this->convertIndex(std::move(base), - *((ASTIndexSuffix&) *expression.fSuffix).fExpression); + case ASTSuffix::kIndex_Kind: { + const ASTExpression* expr = ((ASTIndexSuffix&) *expression.fSuffix).fExpression.get(); + if (expr) { + return this->convertIndex(std::move(base), *expr); + } else if (base->fKind == Expression::kTypeReference_Kind) { + const Type& oldType = ((TypeReference&) *base).fValue; + Type* newType = new Type(oldType.name() + "[]", Type::kArray_Kind, oldType, + -1); + fSymbolTable->takeOwnership(newType); + return std::unique_ptr(new TypeReference(fContext, base->fPosition, + *newType)); + } else { + fErrors.error(expression.fPosition, "'[]' must follow a type name"); + return nullptr; + } + } case ASTSuffix::kCall_Kind: { auto rawArguments = &((ASTCallSuffix&) *expression.fSuffix).fArguments; std::vector> arguments; for (size_t i = 0; i < rawArguments->size(); i++) { - std::unique_ptr converted = + std::unique_ptr converted = this->convertExpression(*(*rawArguments)[i]); if (!converted) { return nullptr; @@ -1160,36 +1585,40 @@ std::unique_ptr IRGenerator::convertSuffixExpression( return this->call(expression.fPosition, std::move(base), std::move(arguments)); } case ASTSuffix::kField_Kind: { + if (base->fType == *fContext.fSkCaps_Type) { + return this->getCap(expression.fPosition, + ((ASTFieldSuffix&) *expression.fSuffix).fField); + } switch (base->fType.kind()) { case Type::kVector_Kind: - return this->convertSwizzle(std::move(base), + return this->convertSwizzle(std::move(base), ((ASTFieldSuffix&) *expression.fSuffix).fField); case Type::kStruct_Kind: return this->convertField(std::move(base), ((ASTFieldSuffix&) *expression.fSuffix).fField); default: - fErrors.error(base->fPosition, "cannot swizzle value of type '" + + fErrors.error(base->fPosition, "cannot swizzle value of type '" + base->fType.description() + "'"); return nullptr; } } case ASTSuffix::kPostIncrement_Kind: if (!base->fType.isNumber()) { - fErrors.error(expression.fPosition, + fErrors.error(expression.fPosition, "'++' cannot operate on '" + base->fType.description() + "'"); return nullptr; } - this->markWrittenTo(*base); - return std::unique_ptr(new PostfixExpression(std::move(base), + this->markWrittenTo(*base, true); + return std::unique_ptr(new PostfixExpression(std::move(base), Token::PLUSPLUS)); case ASTSuffix::kPostDecrement_Kind: if (!base->fType.isNumber()) { - fErrors.error(expression.fPosition, + fErrors.error(expression.fPosition, "'--' cannot operate on '" + base->fType.description() + "'"); return nullptr; } - this->markWrittenTo(*base); - return std::unique_ptr(new PostfixExpression(std::move(base), + this->markWrittenTo(*base, true); + return std::unique_ptr(new PostfixExpression(std::move(base), Token::MINUSMINUS)); default: ABORT("unsupported suffix operator"); @@ -1205,15 +1634,12 @@ void IRGenerator::checkValid(const Expression& expr) { fErrors.error(expr.fPosition, "expected '(' to begin constructor invocation"); break; default: - ASSERT(expr.fType != *fContext.fInvalid_Type); - break; + if (expr.fType == *fContext.fInvalid_Type) { + fErrors.error(expr.fPosition, "invalid expression"); + } } } -void IRGenerator::markReadFrom(const Variable& var) { - var.fIsReadFrom = true; -} - static bool has_duplicates(const Swizzle& swizzle) { int bits = 0; for (int idx : swizzle.fComponents) { @@ -1227,29 +1653,30 @@ static bool has_duplicates(const Swizzle& swizzle) { return false; } -void IRGenerator::markWrittenTo(const Expression& expr) { +void IRGenerator::markWrittenTo(const Expression& expr, bool readWrite) { switch (expr.fKind) { case Expression::kVariableReference_Kind: { const Variable& var = ((VariableReference&) expr).fVariable; if (var.fModifiers.fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) { - fErrors.error(expr.fPosition, + fErrors.error(expr.fPosition, "cannot modify immutable variable '" + var.fName + "'"); } - var.fIsWrittenTo = true; + ((VariableReference&) expr).setRefKind(readWrite ? VariableReference::kReadWrite_RefKind + : VariableReference::kWrite_RefKind); break; } case Expression::kFieldAccess_Kind: - this->markWrittenTo(*((FieldAccess&) expr).fBase); + this->markWrittenTo(*((FieldAccess&) expr).fBase, readWrite); break; case Expression::kSwizzle_Kind: if (has_duplicates((Swizzle&) expr)) { - fErrors.error(expr.fPosition, + fErrors.error(expr.fPosition, "cannot write to the same swizzle field more than once"); } - this->markWrittenTo(*((Swizzle&) expr).fBase); + this->markWrittenTo(*((Swizzle&) expr).fBase, readWrite); break; case Expression::kIndex_Kind: - this->markWrittenTo(*((IndexExpression&) expr).fBase); + this->markWrittenTo(*((IndexExpression&) expr).fBase, readWrite); break; default: fErrors.error(expr.fPosition, "cannot assign to '" + expr.description() + "'"); diff --git a/gfx/skia/skia/src/sksl/SkSLIRGenerator.h b/gfx/skia/skia/src/sksl/SkSLIRGenerator.h index a3ff210b4597..b0a449aceac2 100644 --- a/gfx/skia/skia/src/sksl/SkSLIRGenerator.h +++ b/gfx/skia/skia/src/sksl/SkSLIRGenerator.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_IRGENERATOR #define SKSL_IRGENERATOR @@ -24,11 +24,12 @@ #include "ast/SkSLASTIdentifier.h" #include "ast/SkSLASTIfStatement.h" #include "ast/SkSLASTInterfaceBlock.h" -#include "ast/SkSLASTModifiers.h" +#include "ast/SkSLASTModifiersDeclaration.h" #include "ast/SkSLASTPrefixExpression.h" #include "ast/SkSLASTReturnStatement.h" #include "ast/SkSLASTStatement.h" #include "ast/SkSLASTSuffixExpression.h" +#include "ast/SkSLASTSwitchStatement.h" #include "ast/SkSLASTTernaryExpression.h" #include "ast/SkSLASTVarDeclaration.h" #include "ast/SkSLASTVarDeclarationStatement.h" @@ -39,51 +40,108 @@ #include "ir/SkSLFunctionDefinition.h" #include "ir/SkSLInterfaceBlock.h" #include "ir/SkSLModifiers.h" +#include "ir/SkSLModifiersDeclaration.h" +#include "ir/SkSLProgram.h" #include "ir/SkSLSymbolTable.h" #include "ir/SkSLStatement.h" #include "ir/SkSLType.h" #include "ir/SkSLTypeReference.h" -#include "ir/SkSLVarDeclaration.h" +#include "ir/SkSLVarDeclarations.h" namespace SkSL { +struct CapValue { + CapValue() + : fKind(kInt_Kind) + , fValue(-1) { + ASSERT(false); + } + + CapValue(bool b) + : fKind(kBool_Kind) + , fValue(b) {} + + CapValue(int i) + : fKind(kInt_Kind) + , fValue(i) {} + + enum { + kBool_Kind, + kInt_Kind, + } fKind; + int fValue; +}; + /** - * Performs semantic analysis on an abstract syntax tree (AST) and produces the corresponding + * Performs semantic analysis on an abstract syntax tree (AST) and produces the corresponding * (unoptimized) intermediate representation (IR). */ class IRGenerator { public: - IRGenerator(const Context* context, std::shared_ptr root, + IRGenerator(const Context* context, std::shared_ptr root, ErrorReporter& errorReporter); - std::unique_ptr convertVarDeclarations(const ASTVarDeclarations& decl, + std::unique_ptr convertVarDeclarations(const ASTVarDeclarations& decl, Variable::Storage storage); std::unique_ptr convertFunction(const ASTFunction& f); std::unique_ptr convertStatement(const ASTStatement& statement); std::unique_ptr convertExpression(const ASTExpression& expression); + std::unique_ptr convertModifiersDeclaration( + const ASTModifiersDeclaration& m); + + /** + * If both operands are compile-time constants and can be folded, returns an expression + * representing the folded value. Otherwise, returns null. Note that unlike most other functions + * here, null does not represent a compilation error. + */ + std::unique_ptr constantFold(const Expression& left, + Token::Kind op, + const Expression& right) const; + Program::Inputs fInputs; + const Context& fContext; private: + /** + * Prepare to compile a program. Resets state, pushes a new symbol table, and installs the + * settings. + */ + void start(const Program::Settings* settings); + + /** + * Performs cleanup after compilation is complete. + */ + void finish(); + void pushSymbolTable(); void popSymbolTable(); const Type* convertType(const ASTType& type); - std::unique_ptr call(Position position, - const FunctionDeclaration& function, + std::unique_ptr call(Position position, + const FunctionDeclaration& function, std::vector> arguments); - bool determineCallCost(const FunctionDeclaration& function, + bool determineCallCost(const FunctionDeclaration& function, const std::vector>& arguments, int* outCost); - std::unique_ptr call(Position position, std::unique_ptr function, + std::unique_ptr call(Position position, std::unique_ptr function, std::vector> arguments); std::unique_ptr coerce(std::unique_ptr expr, const Type& type); std::unique_ptr convertBlock(const ASTBlock& block); std::unique_ptr convertBreak(const ASTBreakStatement& b); - std::unique_ptr convertConstructor(Position position, - const Type& type, + std::unique_ptr convertNumberConstructor( + Position position, + const Type& type, + std::vector> params); + std::unique_ptr convertCompoundConstructor( + Position position, + const Type& type, + std::vector> params); + std::unique_ptr convertConstructor(Position position, + const Type& type, std::vector> params); std::unique_ptr convertContinue(const ASTContinueStatement& c); std::unique_ptr convertDiscard(const ASTDiscardStatement& d); std::unique_ptr convertDo(const ASTDoStatement& d); + std::unique_ptr convertSwitch(const ASTSwitchStatement& s); std::unique_ptr convertBinaryExpression(const ASTBinaryExpression& expression); std::unique_ptr convertExtension(const ASTExtension& e); std::unique_ptr convertExpressionStatement(const ASTExpressionStatement& s); @@ -93,28 +151,33 @@ private: std::unique_ptr convertIndex(std::unique_ptr base, const ASTExpression& index); std::unique_ptr convertInterfaceBlock(const ASTInterfaceBlock& s); - Modifiers convertModifiers(const ASTModifiers& m); + Modifiers convertModifiers(const Modifiers& m); std::unique_ptr convertPrefixExpression(const ASTPrefixExpression& expression); std::unique_ptr convertReturn(const ASTReturnStatement& r); + std::unique_ptr getCap(Position position, String name); std::unique_ptr convertSuffixExpression(const ASTSuffixExpression& expression); - std::unique_ptr convertField(std::unique_ptr base, - const std::string& field); + std::unique_ptr convertField(std::unique_ptr base, + const String& field); std::unique_ptr convertSwizzle(std::unique_ptr base, - const std::string& fields); + const String& fields); std::unique_ptr convertTernaryExpression(const ASTTernaryExpression& expression); std::unique_ptr convertVarDeclarationStatement(const ASTVarDeclarationStatement& s); std::unique_ptr convertWhile(const ASTWhileStatement& w); void checkValid(const Expression& expr); - void markReadFrom(const Variable& var); - void markWrittenTo(const Expression& expr); + void markWrittenTo(const Expression& expr, bool readWrite); - const Context& fContext; const FunctionDeclaration* fCurrentFunction; + const Program::Settings* fSettings; + std::unordered_map fCapsMap; std::shared_ptr fSymbolTable; + int fLoopLevel; + int fSwitchLevel; ErrorReporter& fErrors; friend class AutoSymbolTable; + friend class AutoLoopLevel; + friend class AutoSwitchLevel; friend class Compiler; }; diff --git a/gfx/skia/skia/src/sksl/SkSLMain.cpp b/gfx/skia/skia/src/sksl/SkSLMain.cpp index 24fbb6c260fa..1461bf9aae21 100644 --- a/gfx/skia/skia/src/sksl/SkSLMain.cpp +++ b/gfx/skia/skia/src/sksl/SkSLMain.cpp @@ -8,6 +8,7 @@ #include "stdio.h" #include #include "SkSLCompiler.h" +#include "SkSLFileOutputStream.h" /** * Very simple standalone executable to facilitate testing. @@ -23,26 +24,56 @@ int main(int argc, const char** argv) { kind = SkSL::Program::kVertex_Kind; } else if (len > 5 && !strcmp(argv[1] + strlen(argv[1]) - 5, ".frag")) { kind = SkSL::Program::kFragment_Kind; + } else if (len > 5 && !strcmp(argv[1] + strlen(argv[1]) - 5, ".geom")) { + kind = SkSL::Program::kGeometry_Kind; } else { - printf("input filename must end in '.vert' or '.frag'\n"); + printf("input filename must end in '.vert', '.frag', or '.geom'\n"); exit(1); } std::ifstream in(argv[1]); - std::string text((std::istreambuf_iterator(in)), - std::istreambuf_iterator()); + std::string stdText((std::istreambuf_iterator(in)), + std::istreambuf_iterator()); + SkSL::String text(stdText.c_str()); if (in.rdstate()) { printf("error reading '%s'\n", argv[1]); exit(2); } - std::ofstream out(argv[2], std::ofstream::binary); - SkSL::Compiler compiler; - if (!compiler.toSPIRV(kind, text, out)) { - printf("%s", compiler.errorText().c_str()); - exit(3); - } - if (out.rdstate()) { - printf("error writing '%s'\n", argv[2]); - exit(4); + SkSL::Program::Settings settings; + SkSL::String name(argv[2]); + if (name.endsWith(".spirv")) { + SkSL::FileOutputStream out(argv[2]); + SkSL::Compiler compiler; + if (!out.isValid()) { + printf("error writing '%s'\n", argv[2]); + exit(4); + } + std::unique_ptr program = compiler.convertProgram(kind, text, settings); + if (!program || !compiler.toSPIRV(*program, out)) { + printf("%s", compiler.errorText().c_str()); + exit(3); + } + if (!out.close()) { + printf("error writing '%s'\n", argv[2]); + exit(4); + } + } else if (name.endsWith(".glsl")) { + SkSL::FileOutputStream out(argv[2]); + SkSL::Compiler compiler; + if (!out.isValid()) { + printf("error writing '%s'\n", argv[2]); + exit(4); + } + std::unique_ptr program = compiler.convertProgram(kind, text, settings); + if (!program || !compiler.toGLSL(*program, out)) { + printf("%s", compiler.errorText().c_str()); + exit(3); + } + if (!out.close()) { + printf("error writing '%s'\n", argv[2]); + exit(4); + } + } else { + printf("expected output filename to end with '.spirv' or '.glsl'"); } } diff --git a/gfx/skia/skia/src/sksl/SkSLMemoryLayout.h b/gfx/skia/skia/src/sksl/SkSLMemoryLayout.h new file mode 100644 index 000000000000..61712eccffb0 --- /dev/null +++ b/gfx/skia/skia/src/sksl/SkSLMemoryLayout.h @@ -0,0 +1,128 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKIASL_MEMORYLAYOUT +#define SKIASL_MEMORYLAYOUT + +#include "ir/SkSLType.h" + +namespace SkSL { + +class MemoryLayout { +public: + enum Standard { + k140_Standard, + k430_Standard + }; + + MemoryLayout(Standard std) + : fStd(std) {} + + static size_t vector_alignment(size_t componentSize, int columns) { + return componentSize * (columns + columns % 2); + } + + /** + * Rounds up to the nearest multiple of 16 if in std140, otherwise returns the parameter + * unchanged (std140 requires various things to be rounded up to the nearest multiple of 16, + * std430 does not). + */ + size_t roundUpIfNeeded(size_t raw) const { + switch (fStd) { + case k140_Standard: return (raw + 15) & ~15; + case k430_Standard: return raw; + } + ABORT("unreachable"); + } + + /** + * Returns a type's required alignment when used as a standalone variable. + */ + size_t alignment(const Type& type) const { + // See OpenGL Spec 7.6.2.2 Standard Uniform Block Layout + switch (type.kind()) { + case Type::kScalar_Kind: + return this->size(type); + case Type::kVector_Kind: + return vector_alignment(this->size(type.componentType()), type.columns()); + case Type::kMatrix_Kind: + return this->roundUpIfNeeded(vector_alignment(this->size(type.componentType()), + type.rows())); + case Type::kArray_Kind: + return this->roundUpIfNeeded(this->alignment(type.componentType())); + case Type::kStruct_Kind: { + size_t result = 0; + for (const auto& f : type.fields()) { + size_t alignment = this->alignment(*f.fType); + if (alignment > result) { + result = alignment; + } + } + return this->roundUpIfNeeded(result); + } + default: + ABORT("cannot determine size of type %s", type.name().c_str()); + } + } + + /** + * For matrices and arrays, returns the number of bytes from the start of one entry (row, in + * the case of matrices) to the start of the next. + */ + size_t stride(const Type& type) const { + switch (type.kind()) { + case Type::kMatrix_Kind: // fall through + case Type::kArray_Kind: + return this->alignment(type); + default: + ABORT("type does not have a stride"); + } + } + + /** + * Returns the size of a type in bytes. + */ + size_t size(const Type& type) const { + switch (type.kind()) { + case Type::kScalar_Kind: + if (type.name() == "bool") { + return 1; + } + // FIXME need to take precision into account, once we figure out how we want to + // handle it... + return 4; + case Type::kVector_Kind: + return type.columns() * this->size(type.componentType()); + case Type::kMatrix_Kind: // fall through + case Type::kArray_Kind: + return type.columns() * this->stride(type); + case Type::kStruct_Kind: { + size_t total = 0; + for (const auto& f : type.fields()) { + size_t alignment = this->alignment(*f.fType); + if (total % alignment != 0) { + total += alignment - total % alignment; + } + ASSERT(total % alignment == 0); + total += this->size(*f.fType); + } + size_t alignment = this->alignment(type); + ASSERT(!type.fields().size() || + (0 == alignment % this->alignment(*type.fields()[0].fType))); + return (total + alignment - 1) & ~(alignment - 1); + } + default: + ABORT("cannot determine size of type %s", type.name().c_str()); + } + } + + const Standard fStd; +}; + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/SkSLOutputStream.h b/gfx/skia/skia/src/sksl/SkSLOutputStream.h new file mode 100644 index 000000000000..62be61e75326 --- /dev/null +++ b/gfx/skia/skia/src/sksl/SkSLOutputStream.h @@ -0,0 +1,36 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_OUTPUTSTREAM +#define SKSL_OUTPUTSTREAM + +#include "SkSLString.h" + +namespace SkSL { + +class OutputStream { +public: + virtual bool isValid() const { + return true; + } + + virtual void write8(uint8_t b) = 0; + + virtual void writeText(const char* s) = 0; + + virtual void write(const void* s, size_t size) = 0; + + void writeString(String s) { + this->write(s.c_str(), s.size()); + } + + virtual ~OutputStream() {} +}; + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/SkSLParser.cpp b/gfx/skia/skia/src/sksl/SkSLParser.cpp index b240e4501e98..0f2b943a9dc5 100644 --- a/gfx/skia/skia/src/sksl/SkSLParser.cpp +++ b/gfx/skia/skia/src/sksl/SkSLParser.cpp @@ -4,27 +4,18 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #include "stdio.h" #include "SkSLParser.h" #include "SkSLToken.h" #define register -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunneeded-internal-declaration" -#pragma clang diagnostic ignored "-Wnull-conversion" -#pragma clang diagnostic ignored "-Wsign-compare" -#endif -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-compare" -#endif -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4018) -#endif +#include "disable_flex_warnings.h" #include "lex.sksl.c" +static_assert(YY_FLEX_MAJOR_VERSION * 100 + YY_FLEX_MINOR_VERSION * 10 + + YY_FLEX_SUBMINOR_VERSION >= 261, + "we require Flex 2.6.1 or better for security reasons"); +#undef register #ifdef __clang__ #pragma clang diagnostic pop #endif @@ -34,8 +25,8 @@ #ifdef _MSC_VER #pragma warning(pop) #endif -#undef register +#include "lex.layout.h" #include "ast/SkSLASTBinaryExpression.h" #include "ast/SkSLASTBlock.h" #include "ast/SkSLASTBoolLiteral.h" @@ -56,26 +47,57 @@ #include "ast/SkSLASTIndexSuffix.h" #include "ast/SkSLASTInterfaceBlock.h" #include "ast/SkSLASTIntLiteral.h" +#include "ast/SkSLASTModifiersDeclaration.h" #include "ast/SkSLASTParameter.h" +#include "ast/SkSLASTPrecision.h" #include "ast/SkSLASTPrefixExpression.h" #include "ast/SkSLASTReturnStatement.h" #include "ast/SkSLASTStatement.h" #include "ast/SkSLASTSuffixExpression.h" +#include "ast/SkSLASTSwitchCase.h" +#include "ast/SkSLASTSwitchStatement.h" #include "ast/SkSLASTTernaryExpression.h" #include "ast/SkSLASTType.h" #include "ast/SkSLASTVarDeclaration.h" #include "ast/SkSLASTVarDeclarationStatement.h" #include "ast/SkSLASTWhileStatement.h" #include "ir/SkSLSymbolTable.h" +#include "ir/SkSLModifiers.h" #include "ir/SkSLType.h" namespace SkSL { -Parser::Parser(std::string text, SymbolTable& types, ErrorReporter& errors) -: fPushback(Position(-1, -1), Token::INVALID_TOKEN, "") +#define MAX_PARSE_DEPTH 50 + +class AutoDepth { +public: + AutoDepth(Parser* p) + : fParser(p) { + fParser->fDepth++; + } + + ~AutoDepth() { + fParser->fDepth--; + } + + bool checkValid() { + if (fParser->fDepth > MAX_PARSE_DEPTH) { + fParser->error(fParser->peek().fPosition, String("exceeded max parse depth")); + return false; + } + return true; + } + +private: + Parser* fParser; +}; + +Parser::Parser(String text, SymbolTable& types, ErrorReporter& errors) +: fPushback(Position(-1, -1), Token::INVALID_TOKEN, String()) , fTypes(types) , fErrors(errors) { sksllex_init(&fScanner); + layoutlex_init(&fLayoutScanner); fBuffer = sksl_scan_string(text.c_str(), fScanner); skslset_lineno(1, fScanner); @@ -88,6 +110,7 @@ Parser::Parser(std::string text, SymbolTable& types, ErrorReporter& errors) Parser::~Parser() { sksl_delete_buffer(fBuffer, fScanner); sksllex_destroy(fScanner); + layoutlex_destroy(fLayoutScanner); } /* (precision | directive | declaration)* END_OF_FILE */ @@ -97,9 +120,13 @@ std::vector> Parser::file() { switch (this->peek().fKind) { case Token::END_OF_FILE: return result; - case Token::PRECISION: - this->precision(); + case Token::PRECISION: { + std::unique_ptr precision = this->precision(); + if (precision) { + result.push_back(std::move(precision)); + } break; + } case Token::DIRECTIVE: { std::unique_ptr decl = this->directive(); if (decl) { @@ -126,9 +153,21 @@ Token Parser::nextToken() { return result; } int token = sksllex(fScanner); - return Token(Position(skslget_lineno(fScanner), -1), (Token::Kind) token, - token == Token::END_OF_FILE ? "" : - std::string(skslget_text(fScanner))); + String text; + switch ((Token::Kind) token) { + case Token::IDENTIFIER: // fall through + case Token::INT_LITERAL: // fall through + case Token::FLOAT_LITERAL: // fall through + case Token::DIRECTIVE: + text = String(skslget_text(fScanner)); + break; + default: +#ifdef SK_DEBUG + text = String(skslget_text(fScanner)); +#endif + break; + } + return Token(Position(skslget_lineno(fScanner), -1), (Token::Kind) token, text); } void Parser::pushback(Token t) { @@ -141,7 +180,12 @@ Token Parser::peek() { return fPushback; } -bool Parser::expect(Token::Kind kind, std::string expected, Token* result) { + +bool Parser::expect(Token::Kind kind, const char* expected, Token* result) { + return this->expect(kind, String(expected), result); +} + +bool Parser::expect(Token::Kind kind, String expected, Token* result) { Token next = this->nextToken(); if (next.fKind == kind) { if (result) { @@ -149,43 +193,60 @@ bool Parser::expect(Token::Kind kind, std::string expected, Token* result) { } return true; } else { - this->error(next.fPosition, "expected " + expected + ", but found '" + next.fText + "'"); + if (next.fText.size()) { + this->error(next.fPosition, "expected " + expected + ", but found '" + next.fText + + "'"); + } else { + this->error(next.fPosition, "parse error, recompile in debug mode for details"); + } return false; } } -void Parser::error(Position p, std::string msg) { +void Parser::error(Position p, const char* msg) { + this->error(p, String(msg)); +} + +void Parser::error(Position p, String msg) { fErrors.error(p, msg); } -bool Parser::isType(std::string name) { +bool Parser::isType(String name) { return nullptr != fTypes[name]; } /* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */ -void Parser::precision() { +std::unique_ptr Parser::precision() { if (!this->expect(Token::PRECISION, "'precision'")) { - return; + return nullptr; } + Modifiers::Flag result; Token p = this->nextToken(); switch (p.fKind) { - case Token::LOWP: // fall through - case Token::MEDIUMP: // fall through + case Token::LOWP: + result = Modifiers::kLowp_Flag; + break; + case Token::MEDIUMP: + result = Modifiers::kMediump_Flag; + break; case Token::HIGHP: - // ignored for now + result = Modifiers::kHighp_Flag; break; default: - this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" + + this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" + p.fText + "'"); - return; + return nullptr; } + // FIXME handle the type if (!this->type()) { - return; + return nullptr; } this->expect(Token::SEMICOLON, "';'"); + return std::unique_ptr(new ASTPrecision(p.fPosition, result)); } -/* DIRECTIVE(#version) INT_LITERAL | DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */ +/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? | + DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */ std::unique_ptr Parser::directive() { Token start; if (!this->expect(Token::DIRECTIVE, "a directive", &start)) { @@ -193,7 +254,12 @@ std::unique_ptr Parser::directive() { } if (start.fText == "#version") { this->expect(Token::INT_LITERAL, "a version number"); - // ignored for now + Token next = this->peek(); + if (next.fText == "es" || next.fText == "compatibility") { + this->nextToken(); + } + // version is ignored for now; it will eventually become an error when we stop pretending + // to be GLSL return nullptr; } else if (start.fText == "#extension") { Token name; @@ -207,7 +273,7 @@ std::unique_ptr Parser::directive() { if (!this->expect(Token::IDENTIFIER, "an identifier")) { return nullptr; } - return std::unique_ptr(new ASTExtension(start.fPosition, + return std::unique_ptr(new ASTExtension(start.fPosition, std::move(name.fText))); } else { this->error(start.fPosition, "unsupported directive '" + start.fText + "'"); @@ -215,10 +281,10 @@ std::unique_ptr Parser::directive() { } } -/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter +/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */ std::unique_ptr Parser::declaration() { - ASTModifiers modifiers = this->modifiers(); + Modifiers modifiers = this->modifiers(); Token lookahead = this->peek(); if (lookahead.fKind == Token::IDENTIFIER && !this->isType(lookahead.fText)) { // we have an identifier that's not a type, could be the start of an interface block @@ -227,6 +293,10 @@ std::unique_ptr Parser::declaration() { if (lookahead.fKind == Token::STRUCT) { return this->structVarDeclaration(modifiers); } + if (lookahead.fKind == Token::SEMICOLON) { + this->nextToken(); + return std::unique_ptr(new ASTModifiersDeclaration(modifiers)); + } std::unique_ptr type(this->type()); if (!type) { return nullptr; @@ -264,9 +334,9 @@ std::unique_ptr Parser::declaration() { return nullptr; } } - return std::unique_ptr(new ASTFunction(name.fPosition, std::move(type), - std::move(name.fText), - std::move(parameters), + return std::unique_ptr(new ASTFunction(name.fPosition, std::move(type), + std::move(name.fText), + std::move(parameters), std::move(body))); } else { return this->varDeclarationEnd(modifiers, std::move(type), name.fText); @@ -275,7 +345,7 @@ std::unique_ptr Parser::declaration() { /* modifiers type IDENTIFIER varDeclarationEnd */ std::unique_ptr Parser::varDeclarations() { - ASTModifiers modifiers = this->modifiers(); + Modifiers modifiers = this->modifiers(); std::unique_ptr type(this->type()); if (!type) { return nullptr; @@ -308,11 +378,12 @@ std::unique_ptr Parser::structDeclaration() { for (const auto& var : decl->fVars) { auto type = (const Type*) fTypes[decl->fType->fName]; for (int i = (int) var.fSizes.size() - 1; i >= 0; i--) { - if (var.fSizes[i]->fKind != ASTExpression::kInt_Kind) { + if (!var.fSizes[i] || var.fSizes[i]->fKind != ASTExpression::kInt_Kind) { this->error(decl->fPosition, "array size in struct field must be a constant"); + return nullptr; } uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue; - std::string name = type->name() + "[" + to_string(columns) + "]"; + String name = type->name() + "[" + to_string(columns) + "]"; type = new Type(name, Type::kArray_Kind, *type, (int) columns); fTypes.takeOwnership((Type*) type); } @@ -325,26 +396,26 @@ std::unique_ptr Parser::structDeclaration() { if (!this->expect(Token::RBRACE, "'}'")) { return nullptr; } - fTypes.add(name.fText, std::unique_ptr(new Type(name.fText, fields))); - return std::unique_ptr(new ASTType(name.fPosition, name.fText, - ASTType::kStruct_Kind)); + fTypes.add(name.fText, std::unique_ptr(new Type(name.fPosition, name.fText, fields))); + return std::unique_ptr(new ASTType(name.fPosition, name.fText, + ASTType::kStruct_Kind, std::vector())); } /* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */ -std::unique_ptr Parser::structVarDeclaration(ASTModifiers modifiers) { +std::unique_ptr Parser::structVarDeclaration(Modifiers modifiers) { std::unique_ptr type = this->structDeclaration(); if (!type) { return nullptr; } if (peek().fKind == Token::IDENTIFIER) { Token name = this->nextToken(); - std::unique_ptr result = this->varDeclarationEnd(modifiers, - std::move(type), + std::unique_ptr result = this->varDeclarationEnd(modifiers, + std::move(type), std::move(name.fText)); if (result) { for (const auto& var : result->fVars) { if (var.fValue) { - this->error(var.fValue->fPosition, + this->error(var.fValue->fPosition, "struct variables cannot be initialized"); } } @@ -355,11 +426,11 @@ std::unique_ptr Parser::structVarDeclaration(ASTModifiers mo return nullptr; } -/* (LBRACKET expression? RBRACKET)* (EQ expression)? (COMMA IDENTIFER +/* (LBRACKET expression? RBRACKET)* (EQ expression)? (COMMA IDENTIFER (LBRACKET expression? RBRACKET)* (EQ expression)?)* SEMICOLON */ -std::unique_ptr Parser::varDeclarationEnd(ASTModifiers mods, +std::unique_ptr Parser::varDeclarationEnd(Modifiers mods, std::unique_ptr type, - std::string name) { + String name) { std::vector vars; std::vector> currentVarSizes; while (this->peek().fKind == Token::LBRACKET) { @@ -430,7 +501,7 @@ std::unique_ptr Parser::varDeclarationEnd(ASTModifiers mods, /* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */ std::unique_ptr Parser::parameter() { - ASTModifiers modifiers = this->modifiersWithDefaults(ASTModifiers::kIn_Flag); + Modifiers modifiers = this->modifiersWithDefaults(0); std::unique_ptr type = this->type(); if (!type) { return nullptr; @@ -451,8 +522,8 @@ std::unique_ptr Parser::parameter() { return nullptr; } } - return std::unique_ptr(new ASTParameter(name.fPosition, modifiers, - std::move(type), name.fText, + return std::unique_ptr(new ASTParameter(name.fPosition, modifiers, + std::move(type), name.fText, std::move(sizes))); } @@ -468,36 +539,103 @@ int Parser::layoutInt() { return -1; } -/* LAYOUT LPAREN IDENTIFIER EQ INT_LITERAL (COMMA IDENTIFIER EQ INT_LITERAL)* - RPAREN */ -ASTLayout Parser::layout() { +/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */ +Layout Parser::layout() { int location = -1; + int offset = -1; int binding = -1; int index = -1; int set = -1; int builtin = -1; + int inputAttachmentIndex = -1; bool originUpperLeft = false; + bool overrideCoverage = false; + bool blendSupportAllEquations = false; + Layout::Format format = Layout::Format::kUnspecified; + bool pushConstant = false; + Layout::Primitive primitive = Layout::kUnspecified_Primitive; + int maxVertices = -1; + int invocations = -1; if (this->peek().fKind == Token::LAYOUT) { this->nextToken(); if (!this->expect(Token::LPAREN, "'('")) { - return ASTLayout(location, binding, index, set, builtin, originUpperLeft); + return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex, + originUpperLeft, overrideCoverage, blendSupportAllEquations, format, + pushConstant, primitive, maxVertices, invocations); } for (;;) { Token t = this->nextToken(); - if (t.fText == "location") { - location = this->layoutInt(); - } else if (t.fText == "binding") { - binding = this->layoutInt(); - } else if (t.fText == "index") { - index = this->layoutInt(); - } else if (t.fText == "set") { - set = this->layoutInt(); - } else if (t.fText == "builtin") { - builtin = this->layoutInt(); - } else if (t.fText == "origin_upper_left") { - originUpperLeft = true; + YY_BUFFER_STATE buffer; + buffer = layout_scan_string(t.fText.c_str(), fLayoutScanner); + int token = layoutlex(fLayoutScanner); + layout_delete_buffer(buffer, fLayoutScanner); + if (token != Token::INVALID_TOKEN) { + switch (token) { + case Token::LOCATION: + location = this->layoutInt(); + break; + case Token::OFFSET: + offset = this->layoutInt(); + break; + case Token::BINDING: + binding = this->layoutInt(); + break; + case Token::INDEX: + index = this->layoutInt(); + break; + case Token::SET: + set = this->layoutInt(); + break; + case Token::BUILTIN: + builtin = this->layoutInt(); + break; + case Token::INPUT_ATTACHMENT_INDEX: + inputAttachmentIndex = this->layoutInt(); + break; + case Token::ORIGIN_UPPER_LEFT: + originUpperLeft = true; + break; + case Token::OVERRIDE_COVERAGE: + overrideCoverage = true; + break; + case Token::BLEND_SUPPORT_ALL_EQUATIONS: + blendSupportAllEquations = true; + break; + case Token::PUSH_CONSTANT: + pushConstant = true; + break; + case Token::POINTS: + primitive = Layout::kPoints_Primitive; + break; + case Token::LINES: + primitive = Layout::kLines_Primitive; + break; + case Token::LINE_STRIP: + primitive = Layout::kLineStrip_Primitive; + break; + case Token::LINES_ADJACENCY: + primitive = Layout::kLinesAdjacency_Primitive; + break; + case Token::TRIANGLES: + primitive = Layout::kTriangles_Primitive; + break; + case Token::TRIANGLE_STRIP: + primitive = Layout::kTriangleStrip_Primitive; + break; + case Token::TRIANGLES_ADJACENCY: + primitive = Layout::kTrianglesAdjacency_Primitive; + break; + case Token::MAX_VERTICES: + maxVertices = this->layoutInt(); + break; + case Token::INVOCATIONS: + invocations = this->layoutInt(); + break; + } + } else if (Layout::ReadFormat(t.fText, &format)) { + // AST::ReadFormat stored the result in 'format'. } else { - this->error(t.fPosition, ("'" + t.fText + + this->error(t.fPosition, ("'" + t.fText + "' is not a valid layout qualifier").c_str()); } if (this->peek().fKind == Token::RPAREN) { @@ -509,67 +647,90 @@ ASTLayout Parser::layout() { } } } - return ASTLayout(location, binding, index, set, builtin, originUpperLeft); + return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex, + originUpperLeft, overrideCoverage, blendSupportAllEquations, format, + pushConstant, primitive, maxVertices, invocations); } -/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE)* */ -ASTModifiers Parser::modifiers() { - ASTLayout layout = this->layout(); +/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE | + READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT)* */ +Modifiers Parser::modifiers() { + Layout layout = this->layout(); int flags = 0; for (;;) { // TODO: handle duplicate / incompatible flags switch (peek().fKind) { case Token::UNIFORM: this->nextToken(); - flags |= ASTModifiers::kUniform_Flag; + flags |= Modifiers::kUniform_Flag; break; case Token::CONST: this->nextToken(); - flags |= ASTModifiers::kConst_Flag; + flags |= Modifiers::kConst_Flag; break; case Token::IN: this->nextToken(); - flags |= ASTModifiers::kIn_Flag; + flags |= Modifiers::kIn_Flag; break; case Token::OUT: this->nextToken(); - flags |= ASTModifiers::kOut_Flag; + flags |= Modifiers::kOut_Flag; break; case Token::INOUT: this->nextToken(); - flags |= ASTModifiers::kIn_Flag; - flags |= ASTModifiers::kOut_Flag; + flags |= Modifiers::kIn_Flag; + flags |= Modifiers::kOut_Flag; break; case Token::LOWP: this->nextToken(); - flags |= ASTModifiers::kLowp_Flag; + flags |= Modifiers::kLowp_Flag; break; case Token::MEDIUMP: this->nextToken(); - flags |= ASTModifiers::kMediump_Flag; + flags |= Modifiers::kMediump_Flag; break; case Token::HIGHP: this->nextToken(); - flags |= ASTModifiers::kHighp_Flag; + flags |= Modifiers::kHighp_Flag; break; case Token::FLAT: this->nextToken(); - flags |= ASTModifiers::kFlat_Flag; + flags |= Modifiers::kFlat_Flag; break; case Token::NOPERSPECTIVE: this->nextToken(); - flags |= ASTModifiers::kNoPerspective_Flag; + flags |= Modifiers::kNoPerspective_Flag; + break; + case Token::READONLY: + this->nextToken(); + flags |= Modifiers::kReadOnly_Flag; + break; + case Token::WRITEONLY: + this->nextToken(); + flags |= Modifiers::kWriteOnly_Flag; + break; + case Token::COHERENT: + this->nextToken(); + flags |= Modifiers::kCoherent_Flag; + break; + case Token::VOLATILE: + this->nextToken(); + flags |= Modifiers::kVolatile_Flag; + break; + case Token::RESTRICT: + this->nextToken(); + flags |= Modifiers::kRestrict_Flag; break; default: - return ASTModifiers(layout, flags); + return Modifiers(layout, flags); } } } -ASTModifiers Parser::modifiersWithDefaults(int defaultFlags) { - ASTModifiers result = this->modifiers(); +Modifiers Parser::modifiersWithDefaults(int defaultFlags) { + Modifiers result = this->modifiers(); if (!result.fFlags) { - return ASTModifiers(result.fLayout, defaultFlags); + return Modifiers(result.fLayout, defaultFlags); } return result; } @@ -586,6 +747,8 @@ std::unique_ptr Parser::statement() { return this->doStatement(); case Token::WHILE: return this->whileStatement(); + case Token::SWITCH: + return this->switchStatement(); case Token::RETURN: return this->returnStatement(); case Token::BREAK: @@ -597,8 +760,8 @@ std::unique_ptr Parser::statement() { case Token::LBRACE: return this->block(); case Token::SEMICOLON: - this->nextToken(); - return std::unique_ptr(new ASTBlock(start.fPosition, + this->nextToken(); + return std::unique_ptr(new ASTBlock(start.fPosition, std::vector>())); case Token::CONST: // fall through case Token::HIGHP: // fall through @@ -622,10 +785,10 @@ std::unique_ptr Parser::statement() { // fall through default: return this->expressionStatement(); - } + } } -/* IDENTIFIER(type) */ +/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* */ std::unique_ptr Parser::type() { Token type; if (!this->expect(Token::IDENTIFIER, "a type", &type)) { @@ -635,25 +798,40 @@ std::unique_ptr Parser::type() { this->error(type.fPosition, ("no type named '" + type.fText + "'").c_str()); return nullptr; } - return std::unique_ptr(new ASTType(type.fPosition, std::move(type.fText), - ASTType::kIdentifier_Kind)); + std::vector sizes; + while (this->peek().fKind == Token::LBRACKET) { + this->expect(Token::LBRACKET, "'['"); + if (this->peek().fKind != Token::RBRACKET) { + int64_t i; + if (this->intLiteral(&i)) { + sizes.push_back(i); + } else { + return nullptr; + } + } else { + sizes.push_back(-1); + } + this->expect(Token::RBRACKET, "']'"); + } + return std::unique_ptr(new ASTType(type.fPosition, std::move(type.fText), + ASTType::kIdentifier_Kind, sizes)); } -/* IDENTIFIER LBRACE varDeclaration* RBRACE */ -std::unique_ptr Parser::interfaceBlock(ASTModifiers mods) { +/* IDENTIFIER LBRACE varDeclaration* RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? */ +std::unique_ptr Parser::interfaceBlock(Modifiers mods) { Token name; if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) { return nullptr; } if (peek().fKind != Token::LBRACE) { // we only get into interfaceBlock if we found a top-level identifier which was not a type. - // 99% of the time, the user was not actually intending to create an interface block, so + // 99% of the time, the user was not actually intending to create an interface block, so // it's better to report it as an unknown type this->error(name.fPosition, "no type named '" + name.fText + "'"); return nullptr; } this->nextToken(); - std::vector> decls; + std::vector> decls; while (this->peek().fKind != Token::RBRACE) { std::unique_ptr decl = this->varDeclarations(); if (!decl) { @@ -662,14 +840,29 @@ std::unique_ptr Parser::interfaceBlock(ASTModifiers mods) { decls.push_back(std::move(decl)); } this->nextToken(); - std::string valueName; + String instanceName; + std::vector> sizes; if (this->peek().fKind == Token::IDENTIFIER) { - valueName = this->nextToken().fText; + instanceName = this->nextToken().fText; + while (this->peek().fKind == Token::LBRACKET) { + this->expect(Token::LBRACKET, "'['"); + if (this->peek().fKind != Token::RBRACKET) { + std::unique_ptr size = this->expression(); + if (!size) { + return nullptr; + } + sizes.push_back(std::move(size)); + } else { + sizes.push_back(nullptr); + } + this->expect(Token::RBRACKET, "']'"); + } } this->expect(Token::SEMICOLON, "';'"); - return std::unique_ptr(new ASTInterfaceBlock(name.fPosition, mods, - name.fText, std::move(valueName), - std::move(decls))); + return std::unique_ptr(new ASTInterfaceBlock(name.fPosition, mods, + name.fText, std::move(decls), + std::move(instanceName), + std::move(sizes))); } /* IF LPAREN expression RPAREN statement (ELSE statement)? */ @@ -700,8 +893,8 @@ std::unique_ptr Parser::ifStatement() { return nullptr; } } - return std::unique_ptr(new ASTIfStatement(start.fPosition, std::move(test), - std::move(ifTrue), + return std::unique_ptr(new ASTIfStatement(start.fPosition, std::move(test), + std::move(ifTrue), std::move(ifFalse))); } @@ -731,7 +924,7 @@ std::unique_ptr Parser::doStatement() { if (!this->expect(Token::SEMICOLON, "';'")) { return nullptr; } - return std::unique_ptr(new ASTDoStatement(start.fPosition, + return std::unique_ptr(new ASTDoStatement(start.fPosition, std::move(statement), std::move(test))); } @@ -756,12 +949,92 @@ std::unique_ptr Parser::whileStatement() { if (!statement) { return nullptr; } - return std::unique_ptr(new ASTWhileStatement(start.fPosition, - std::move(test), + return std::unique_ptr(new ASTWhileStatement(start.fPosition, + std::move(test), std::move(statement))); } -/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN +/* CASE expression COLON statement* */ +std::unique_ptr Parser::switchCase() { + Token start; + if (!this->expect(Token::CASE, "'case'", &start)) { + return nullptr; + } + std::unique_ptr value = this->expression(); + if (!value) { + return nullptr; + } + if (!this->expect(Token::COLON, "':'")) { + return nullptr; + } + std::vector> statements; + while (this->peek().fKind != Token::RBRACE && this->peek().fKind != Token::CASE && + this->peek().fKind != Token::DEFAULT) { + std::unique_ptr s = this->statement(); + if (!s) { + return nullptr; + } + statements.push_back(std::move(s)); + } + return std::unique_ptr(new ASTSwitchCase(start.fPosition, std::move(value), + std::move(statements))); +} + +/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */ +std::unique_ptr Parser::switchStatement() { + Token start; + if (!this->expect(Token::SWITCH, "'switch'", &start)) { + return nullptr; + } + if (!this->expect(Token::LPAREN, "'('")) { + return nullptr; + } + std::unique_ptr value(this->expression()); + if (!value) { + return nullptr; + } + if (!this->expect(Token::RPAREN, "')'")) { + return nullptr; + } + if (!this->expect(Token::LBRACE, "'{'")) { + return nullptr; + } + std::vector> cases; + while (this->peek().fKind == Token::CASE) { + std::unique_ptr c = this->switchCase(); + if (!c) { + return nullptr; + } + cases.push_back(std::move(c)); + } + // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other + // parts of the compiler may rely upon this assumption. + if (this->peek().fKind == Token::DEFAULT) { + Token defaultStart; + ASSERT_RESULT(this->expect(Token::DEFAULT, "'default'", &defaultStart)); + if (!this->expect(Token::COLON, "':'")) { + return nullptr; + } + std::vector> statements; + while (this->peek().fKind != Token::RBRACE) { + std::unique_ptr s = this->statement(); + if (!s) { + return nullptr; + } + statements.push_back(std::move(s)); + } + cases.emplace_back(new ASTSwitchCase(defaultStart.fPosition, nullptr, + std::move(statements))); + } + if (!this->expect(Token::RBRACE, "'}'")) { + return nullptr; + } + return std::unique_ptr(new ASTSwitchStatement(start.fPosition, + std::move(value), + std::move(cases))); +} + +/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN STATEMENT */ std::unique_ptr Parser::forStatement() { Token start; @@ -774,19 +1047,29 @@ std::unique_ptr Parser::forStatement() { std::unique_ptr initializer; Token nextToken = this->peek(); switch (nextToken.fKind) { - case Token::SEMICOLON: + case Token::SEMICOLON: + this->nextToken(); break; - case Token::CONST: + case Token::CONST: { + std::unique_ptr vd = this->varDeclarations(); + if (!vd) { + return nullptr; + } initializer = std::unique_ptr(new ASTVarDeclarationStatement( - this->varDeclarations())); + std::move(vd))); break; - case Token::IDENTIFIER: + } + case Token::IDENTIFIER: { if (this->isType(nextToken.fText)) { + std::unique_ptr vd = this->varDeclarations(); + if (!vd) { + return nullptr; + } initializer = std::unique_ptr(new ASTVarDeclarationStatement( - this->varDeclarations())); + std::move(vd))); break; } - // fall through + } // fall through default: initializer = this->expressionStatement(); } @@ -801,7 +1084,7 @@ std::unique_ptr Parser::forStatement() { return nullptr; } std::unique_ptr next; - if (this->peek().fKind != Token::SEMICOLON) { + if (this->peek().fKind != Token::RPAREN) { next = this->expression(); if (!next) { return nullptr; @@ -814,7 +1097,7 @@ std::unique_ptr Parser::forStatement() { if (!statement) { return nullptr; } - return std::unique_ptr(new ASTForStatement(start.fPosition, + return std::unique_ptr(new ASTForStatement(start.fPosition, std::move(initializer), std::move(test), std::move(next), std::move(statement))); @@ -836,7 +1119,7 @@ std::unique_ptr Parser::returnStatement() { if (!this->expect(Token::SEMICOLON, "';'")) { return nullptr; } - return std::unique_ptr(new ASTReturnStatement(start.fPosition, + return std::unique_ptr(new ASTReturnStatement(start.fPosition, std::move(expression))); } @@ -878,6 +1161,10 @@ std::unique_ptr Parser::discardStatement() { /* LBRACE statement* RBRACE */ std::unique_ptr Parser::block() { + AutoDepth depth(this); + if (!depth.checkValid()) { + return nullptr; + } Token start; if (!this->expect(Token::LBRACE, "'{'", &start)) { return nullptr; @@ -885,11 +1172,11 @@ std::unique_ptr Parser::block() { std::vector> statements; for (;;) { switch (this->peek().fKind) { - case Token::RBRACE: + case Token::RBRACE: this->nextToken(); - return std::unique_ptr(new ASTBlock(start.fPosition, + return std::unique_ptr(new ASTBlock(start.fPosition, std::move(statements))); - case Token::END_OF_FILE: + case Token::END_OF_FILE: this->error(this->peek().fPosition, "expected '}', but found end of file"); return nullptr; default: { @@ -917,6 +1204,10 @@ std::unique_ptr Parser::expressionStatement() { /* assignmentExpression */ std::unique_ptr Parser::expression() { + AutoDepth depth(this); + if (!depth.checkValid()) { + return nullptr; + } return this->assignmentExpression(); } @@ -950,8 +1241,8 @@ std::unique_ptr Parser::assignmentExpression() { if (!right) { return nullptr; } - result = std::unique_ptr(new ASTBinaryExpression(std::move(result), - t, + result = std::unique_ptr(new ASTBinaryExpression(std::move(result), + t, std::move(right))); } default: @@ -974,8 +1265,8 @@ std::unique_ptr Parser::ternaryExpression() { } if (this->expect(Token::COLON, "':'")) { std::unique_ptr falseExpr = this->assignmentExpression(); - return std::unique_ptr(new ASTTernaryExpression(std::move(result), - std::move(trueExpr), + return std::unique_ptr(new ASTTernaryExpression(std::move(result), + std::move(trueExpr), std::move(falseExpr))); } return nullptr; @@ -1211,10 +1502,11 @@ std::unique_ptr Parser::multiplicativeExpression() { /* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */ std::unique_ptr Parser::unaryExpression() { switch (this->peek().fKind) { - case Token::PLUS: // fall through - case Token::MINUS: // fall through - case Token::NOT: // fall through - case Token::PLUSPLUS: // fall through + case Token::PLUS: // fall through + case Token::MINUS: // fall through + case Token::LOGICALNOT: // fall through + case Token::BITWISENOT: // fall through + case Token::PLUSPLUS: // fall through case Token::MINUSMINUS: { Token t = this->nextToken(); std::unique_ptr expr = this->unaryExpression(); @@ -1254,12 +1546,16 @@ std::unique_ptr Parser::postfixExpression() { } } -/* LBRACKET expression RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN | +/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN | PLUSPLUS | MINUSMINUS */ std::unique_ptr Parser::suffix() { Token next = this->nextToken(); switch (next.fKind) { case Token::LBRACKET: { + if (this->peek().fKind == Token::RBRACKET) { + this->nextToken(); + return std::unique_ptr(new ASTIndexSuffix(next.fPosition)); + } std::unique_ptr e = this->expression(); if (!e) { return nullptr; @@ -1269,7 +1565,7 @@ std::unique_ptr Parser::suffix() { } case Token::DOT: { Position pos = this->peek().fPosition; - std::string text; + String text; if (this->identifier(&text)) { return std::unique_ptr(new ASTFieldSuffix(pos, std::move(text))); } @@ -1291,17 +1587,17 @@ std::unique_ptr Parser::suffix() { } } this->expect(Token::RPAREN, "')' to complete function parameters"); - return std::unique_ptr(new ASTCallSuffix(next.fPosition, + return std::unique_ptr(new ASTCallSuffix(next.fPosition, std::move(parameters))); } case Token::PLUSPLUS: - return std::unique_ptr(new ASTSuffix(next.fPosition, + return std::unique_ptr(new ASTSuffix(next.fPosition, ASTSuffix::kPostIncrement_Kind)); case Token::MINUSMINUS: return std::unique_ptr(new ASTSuffix(next.fPosition, ASTSuffix::kPostDecrement_Kind)); default: { - this->error(next.fPosition, "expected expression suffix, but found '" + next.fText + + this->error(next.fPosition, "expected expression suffix, but found '" + next.fText + "'\n"); return nullptr; } @@ -1314,7 +1610,7 @@ std::unique_ptr Parser::term() { Token t = this->peek(); switch (t.fKind) { case Token::IDENTIFIER: { - std::string text; + String text; if (this->identifier(&text)) { result.reset(new ASTIdentifier(t.fPosition, std::move(text))); } @@ -1395,10 +1691,10 @@ bool Parser::boolLiteral(bool* dest) { } /* IDENTIFIER */ -bool Parser::identifier(std::string* dest) { +bool Parser::identifier(String* dest) { Token t; if (this->expect(Token::IDENTIFIER, "identifier", &t)) { - *dest = t.fText; + *dest = t.fText; return true; } return false; diff --git a/gfx/skia/skia/src/sksl/SkSLParser.h b/gfx/skia/skia/src/sksl/SkSLParser.h index 75f304bc8c5c..0fa00cb8826e 100644 --- a/gfx/skia/skia/src/sksl/SkSLParser.h +++ b/gfx/skia/skia/src/sksl/SkSLParser.h @@ -4,13 +4,13 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_PARSER #define SKSL_PARSER -#include #include #include +#include #include #include "SkSLErrorReporter.h" #include "SkSLToken.h" @@ -32,15 +32,18 @@ struct ASTExpressionStatement; struct ASTForStatement; struct ASTIfStatement; struct ASTInterfaceBlock; -struct ASTLayout; -struct ASTModifiers; struct ASTParameter; +struct ASTPrecision; struct ASTReturnStatement; struct ASTStatement; struct ASTSuffix; +struct ASTSwitchCase; +struct ASTSwitchStatement; struct ASTType; struct ASTWhileStatement; struct ASTVarDeclarations; +struct Layout; +struct Modifiers; class SymbolTable; /** @@ -48,7 +51,7 @@ class SymbolTable; */ class Parser { public: - Parser(std::string text, SymbolTable& types, ErrorReporter& errors); + Parser(String text, SymbolTable& types, ErrorReporter& errors); ~Parser(); @@ -73,7 +76,7 @@ private: void pushback(Token t); /** - * Returns the next token without consuming it from the stream. + * Returns the next token without consuming it from the stream. */ Token peek(); @@ -86,21 +89,23 @@ private: * If 'result' is non-null, it is set to point to the token that was read. * Returns true if the read token was as expected, false otherwise. */ - bool expect(Token::Kind kind, std::string expected, Token* result = nullptr); + bool expect(Token::Kind kind, const char* expected, Token* result = nullptr); + bool expect(Token::Kind kind, String expected, Token* result = nullptr); + + void error(Position p, const char* msg); + void error(Position p, String msg); - void error(Position p, std::string msg); - /** * Returns true if the 'name' identifier refers to a type name. For instance, isType("int") will * always return true. */ - bool isType(std::string name); + bool isType(String name); // these functions parse individual grammar rules from the current parse position; you probably // don't need to call any of these outside of the parser. The function declarations in the .cpp // file have comments describing the grammar rules. - void precision(); + std::unique_ptr precision(); std::unique_ptr directive(); @@ -110,27 +115,27 @@ private: std::unique_ptr structDeclaration(); - std::unique_ptr structVarDeclaration(ASTModifiers modifiers); + std::unique_ptr structVarDeclaration(Modifiers modifiers); - std::unique_ptr varDeclarationEnd(ASTModifiers modifiers, - std::unique_ptr type, - std::string name); + std::unique_ptr varDeclarationEnd(Modifiers modifiers, + std::unique_ptr type, + String name); std::unique_ptr parameter(); int layoutInt(); - - ASTLayout layout(); - ASTModifiers modifiers(); + Layout layout(); - ASTModifiers modifiersWithDefaults(int defaultFlags); + Modifiers modifiers(); + + Modifiers modifiersWithDefaults(int defaultFlags); std::unique_ptr statement(); std::unique_ptr type(); - std::unique_ptr interfaceBlock(ASTModifiers mods); + std::unique_ptr interfaceBlock(Modifiers mods); std::unique_ptr ifStatement(); @@ -140,6 +145,10 @@ private: std::unique_ptr forStatement(); + std::unique_ptr switchCase(); + + std::unique_ptr switchStatement(); + std::unique_ptr returnStatement(); std::unique_ptr breakStatement(); @@ -155,7 +164,7 @@ private: std::unique_ptr expression(); std::unique_ptr assignmentExpression(); - + std::unique_ptr ternaryExpression(); std::unique_ptr logicalOrExpression(); @@ -194,14 +203,19 @@ private: bool boolLiteral(bool* dest); - bool identifier(std::string* dest); - + bool identifier(String* dest); void* fScanner; + void* fLayoutScanner; YY_BUFFER_STATE fBuffer; + // current parse depth, used to enforce a recursion limit to try to keep us from overflowing the + // stack on pathological inputs + int fDepth = 0; Token fPushback; SymbolTable& fTypes; ErrorReporter& fErrors; + + friend class AutoDepth; }; } // namespace diff --git a/gfx/skia/skia/src/sksl/SkSLPosition.h b/gfx/skia/skia/src/sksl/SkSLPosition.h index 979f630ae7b0..83cfe825420c 100644 --- a/gfx/skia/skia/src/sksl/SkSLPosition.h +++ b/gfx/skia/skia/src/sksl/SkSLPosition.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_POSITION #define SKSL_POSITION @@ -17,15 +17,15 @@ namespace SkSL { * ignored. */ struct Position { - Position() + Position() : fLine(-1) , fColumn(-1) {} - + Position(int line, int column) : fLine(line) , fColumn(column) {} - std::string description() const { + String description() const { return to_string(fLine); } diff --git a/gfx/skia/skia/src/sksl/SkSLSPIRVCodeGenerator.cpp b/gfx/skia/skia/src/sksl/SkSLSPIRVCodeGenerator.cpp index d17e3c42a2d4..d713d6fddd69 100644 --- a/gfx/skia/skia/src/sksl/SkSLSPIRVCodeGenerator.cpp +++ b/gfx/skia/skia/src/sksl/SkSLSPIRVCodeGenerator.cpp @@ -4,10 +4,8 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - -#include "SkSLSPIRVCodeGenerator.h" -#include "string.h" +#include "SkSLSPIRVCodeGenerator.h" #include "GLSL.std.450.h" @@ -15,6 +13,7 @@ #include "ir/SkSLExtension.h" #include "ir/SkSLIndexExpression.h" #include "ir/SkSLVariableReference.h" +#include "SkSLCompiler.h" namespace SkSL { @@ -33,107 +32,111 @@ void SPIRVCodeGenerator::setupIntrinsics() { #define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \ k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \ k ## x ## _SpecialIntrinsic) - fIntrinsicMap["round"] = ALL_GLSL(Round); - fIntrinsicMap["roundEven"] = ALL_GLSL(RoundEven); - fIntrinsicMap["trunc"] = ALL_GLSL(Trunc); - fIntrinsicMap["abs"] = BY_TYPE_GLSL(FAbs, SAbs, SAbs); - fIntrinsicMap["sign"] = BY_TYPE_GLSL(FSign, SSign, SSign); - fIntrinsicMap["floor"] = ALL_GLSL(Floor); - fIntrinsicMap["ceil"] = ALL_GLSL(Ceil); - fIntrinsicMap["fract"] = ALL_GLSL(Fract); - fIntrinsicMap["radians"] = ALL_GLSL(Radians); - fIntrinsicMap["degrees"] = ALL_GLSL(Degrees); - fIntrinsicMap["sin"] = ALL_GLSL(Sin); - fIntrinsicMap["cos"] = ALL_GLSL(Cos); - fIntrinsicMap["tan"] = ALL_GLSL(Tan); - fIntrinsicMap["asin"] = ALL_GLSL(Asin); - fIntrinsicMap["acos"] = ALL_GLSL(Acos); - fIntrinsicMap["atan"] = SPECIAL(Atan); - fIntrinsicMap["sinh"] = ALL_GLSL(Sinh); - fIntrinsicMap["cosh"] = ALL_GLSL(Cosh); - fIntrinsicMap["tanh"] = ALL_GLSL(Tanh); - fIntrinsicMap["asinh"] = ALL_GLSL(Asinh); - fIntrinsicMap["acosh"] = ALL_GLSL(Acosh); - fIntrinsicMap["atanh"] = ALL_GLSL(Atanh); - fIntrinsicMap["pow"] = ALL_GLSL(Pow); - fIntrinsicMap["exp"] = ALL_GLSL(Exp); - fIntrinsicMap["log"] = ALL_GLSL(Log); - fIntrinsicMap["exp2"] = ALL_GLSL(Exp2); - fIntrinsicMap["log2"] = ALL_GLSL(Log2); - fIntrinsicMap["sqrt"] = ALL_GLSL(Sqrt); - fIntrinsicMap["inversesqrt"] = ALL_GLSL(InverseSqrt); - fIntrinsicMap["determinant"] = ALL_GLSL(Determinant); - fIntrinsicMap["matrixInverse"] = ALL_GLSL(MatrixInverse); - fIntrinsicMap["mod"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFMod, SpvOpSMod, - SpvOpUMod, SpvOpUndef); - fIntrinsicMap["min"] = BY_TYPE_GLSL(FMin, SMin, UMin); - fIntrinsicMap["max"] = BY_TYPE_GLSL(FMax, SMax, UMax); - fIntrinsicMap["clamp"] = BY_TYPE_GLSL(FClamp, SClamp, UClamp); - fIntrinsicMap["dot"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot, SpvOpUndef, - SpvOpUndef, SpvOpUndef); - fIntrinsicMap["mix"] = ALL_GLSL(FMix); - fIntrinsicMap["step"] = ALL_GLSL(Step); - fIntrinsicMap["smoothstep"] = ALL_GLSL(SmoothStep); - fIntrinsicMap["fma"] = ALL_GLSL(Fma); - fIntrinsicMap["frexp"] = ALL_GLSL(Frexp); - fIntrinsicMap["ldexp"] = ALL_GLSL(Ldexp); + fIntrinsicMap[String("round")] = ALL_GLSL(Round); + fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven); + fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc); + fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs); + fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign); + fIntrinsicMap[String("floor")] = ALL_GLSL(Floor); + fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil); + fIntrinsicMap[String("fract")] = ALL_GLSL(Fract); + fIntrinsicMap[String("radians")] = ALL_GLSL(Radians); + fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees); + fIntrinsicMap[String("sin")] = ALL_GLSL(Sin); + fIntrinsicMap[String("cos")] = ALL_GLSL(Cos); + fIntrinsicMap[String("tan")] = ALL_GLSL(Tan); + fIntrinsicMap[String("asin")] = ALL_GLSL(Asin); + fIntrinsicMap[String("acos")] = ALL_GLSL(Acos); + fIntrinsicMap[String("atan")] = SPECIAL(Atan); + fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh); + fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh); + fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh); + fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh); + fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh); + fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh); + fIntrinsicMap[String("pow")] = ALL_GLSL(Pow); + fIntrinsicMap[String("exp")] = ALL_GLSL(Exp); + fIntrinsicMap[String("log")] = ALL_GLSL(Log); + fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2); + fIntrinsicMap[String("log2")] = ALL_GLSL(Log2); + fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt); + fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt); + fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant); + fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse); + fIntrinsicMap[String("mod")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFMod, + SpvOpSMod, SpvOpUMod, SpvOpUndef); + fIntrinsicMap[String("min")] = BY_TYPE_GLSL(FMin, SMin, UMin); + fIntrinsicMap[String("max")] = BY_TYPE_GLSL(FMax, SMax, UMax); + fIntrinsicMap[String("clamp")] = BY_TYPE_GLSL(FClamp, SClamp, UClamp); + fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot, + SpvOpUndef, SpvOpUndef, SpvOpUndef); + fIntrinsicMap[String("mix")] = ALL_GLSL(FMix); + fIntrinsicMap[String("step")] = ALL_GLSL(Step); + fIntrinsicMap[String("smoothstep")] = ALL_GLSL(SmoothStep); + fIntrinsicMap[String("fma")] = ALL_GLSL(Fma); + fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp); + fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp); -#define PACK(type) fIntrinsicMap["pack" #type] = ALL_GLSL(Pack ## type); \ - fIntrinsicMap["unpack" #type] = ALL_GLSL(Unpack ## type) +#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \ + fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type) PACK(Snorm4x8); PACK(Unorm4x8); PACK(Snorm2x16); PACK(Unorm2x16); PACK(Half2x16); PACK(Double2x32); - fIntrinsicMap["length"] = ALL_GLSL(Length); - fIntrinsicMap["distance"] = ALL_GLSL(Distance); - fIntrinsicMap["cross"] = ALL_GLSL(Cross); - fIntrinsicMap["normalize"] = ALL_GLSL(Normalize); - fIntrinsicMap["faceForward"] = ALL_GLSL(FaceForward); - fIntrinsicMap["reflect"] = ALL_GLSL(Reflect); - fIntrinsicMap["refract"] = ALL_GLSL(Refract); - fIntrinsicMap["findLSB"] = ALL_GLSL(FindILsb); - fIntrinsicMap["findMSB"] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb); - fIntrinsicMap["dFdx"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx, SpvOpUndef, - SpvOpUndef, SpvOpUndef); - fIntrinsicMap["dFdy"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy, SpvOpUndef, - SpvOpUndef, SpvOpUndef); - fIntrinsicMap["dFdy"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy, SpvOpUndef, - SpvOpUndef, SpvOpUndef); - fIntrinsicMap["texture"] = SPECIAL(Texture); - fIntrinsicMap["texture2D"] = SPECIAL(Texture2D); - fIntrinsicMap["textureProj"] = SPECIAL(TextureProj); + fIntrinsicMap[String("length")] = ALL_GLSL(Length); + fIntrinsicMap[String("distance")] = ALL_GLSL(Distance); + fIntrinsicMap[String("cross")] = ALL_GLSL(Cross); + fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize); + fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward); + fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect); + fIntrinsicMap[String("refract")] = ALL_GLSL(Refract); + fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb); + fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb); + fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx, + SpvOpUndef, SpvOpUndef, SpvOpUndef); + fIntrinsicMap[String("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy, + SpvOpUndef, SpvOpUndef, SpvOpUndef); + fIntrinsicMap[String("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy, + SpvOpUndef, SpvOpUndef, SpvOpUndef); + fIntrinsicMap[String("texture")] = SPECIAL(Texture); - fIntrinsicMap["any"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef, - SpvOpUndef, SpvOpUndef, SpvOpAny); - fIntrinsicMap["all"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef, - SpvOpUndef, SpvOpUndef, SpvOpAll); - fIntrinsicMap["equal"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFOrdEqual, - SpvOpIEqual, SpvOpIEqual, - SpvOpLogicalEqual); - fIntrinsicMap["notEqual"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFOrdNotEqual, - SpvOpINotEqual, SpvOpINotEqual, - SpvOpLogicalNotEqual); - fIntrinsicMap["lessThan"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpSLessThan, - SpvOpULessThan, SpvOpFOrdLessThan, - SpvOpUndef); - fIntrinsicMap["lessThanEqual"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpSLessThanEqual, - SpvOpULessThanEqual, SpvOpFOrdLessThanEqual, - SpvOpUndef); - fIntrinsicMap["greaterThan"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpSGreaterThan, - SpvOpUGreaterThan, SpvOpFOrdGreaterThan, - SpvOpUndef); - fIntrinsicMap["greaterThanEqual"] = std::make_tuple(kSPIRV_IntrinsicKind, - SpvOpSGreaterThanEqual, - SpvOpUGreaterThanEqual, - SpvOpFOrdGreaterThanEqual, - SpvOpUndef); + fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad); + fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef, + SpvOpUndef, SpvOpUndef, SpvOpAny); + fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef, + SpvOpUndef, SpvOpUndef, SpvOpAll); + fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind, + SpvOpFOrdEqual, SpvOpIEqual, + SpvOpIEqual, SpvOpLogicalEqual); + fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind, + SpvOpFOrdNotEqual, SpvOpINotEqual, + SpvOpINotEqual, + SpvOpLogicalNotEqual); + fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind, + SpvOpSLessThan, SpvOpULessThan, + SpvOpFOrdLessThan, SpvOpUndef); + fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind, + SpvOpSLessThanEqual, + SpvOpULessThanEqual, + SpvOpFOrdLessThanEqual, + SpvOpUndef); + fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind, + SpvOpSGreaterThan, + SpvOpUGreaterThan, + SpvOpFOrdGreaterThan, + SpvOpUndef); + fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind, + SpvOpSGreaterThanEqual, + SpvOpUGreaterThanEqual, + SpvOpFOrdGreaterThanEqual, + SpvOpUndef); // interpolateAt* not yet supported... } -void SPIRVCodeGenerator::writeWord(int32_t word, std::ostream& out) { +void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) { #if SPIRV_DEBUG out << "(" << word << ") "; #else @@ -174,603 +177,603 @@ static bool is_out(const Variable& var) { } #if SPIRV_DEBUG -static std::string opcode_text(SpvOp_ opCode) { +static String opcode_text(SpvOp_ opCode) { switch (opCode) { case SpvOpNop: - return "Nop"; + return String("Nop"); case SpvOpUndef: - return "Undef"; + return String("Undef"); case SpvOpSourceContinued: - return "SourceContinued"; + return String("SourceContinued"); case SpvOpSource: - return "Source"; + return String("Source"); case SpvOpSourceExtension: - return "SourceExtension"; + return String("SourceExtension"); case SpvOpName: - return "Name"; + return String("Name"); case SpvOpMemberName: - return "MemberName"; + return String("MemberName"); case SpvOpString: - return "String"; + return String("String"); case SpvOpLine: - return "Line"; + return String("Line"); case SpvOpExtension: - return "Extension"; + return String("Extension"); case SpvOpExtInstImport: - return "ExtInstImport"; + return String("ExtInstImport"); case SpvOpExtInst: - return "ExtInst"; + return String("ExtInst"); case SpvOpMemoryModel: - return "MemoryModel"; + return String("MemoryModel"); case SpvOpEntryPoint: - return "EntryPoint"; + return String("EntryPoint"); case SpvOpExecutionMode: - return "ExecutionMode"; + return String("ExecutionMode"); case SpvOpCapability: - return "Capability"; + return String("Capability"); case SpvOpTypeVoid: - return "TypeVoid"; + return String("TypeVoid"); case SpvOpTypeBool: - return "TypeBool"; + return String("TypeBool"); case SpvOpTypeInt: - return "TypeInt"; + return String("TypeInt"); case SpvOpTypeFloat: - return "TypeFloat"; + return String("TypeFloat"); case SpvOpTypeVector: - return "TypeVector"; + return String("TypeVector"); case SpvOpTypeMatrix: - return "TypeMatrix"; + return String("TypeMatrix"); case SpvOpTypeImage: - return "TypeImage"; + return String("TypeImage"); case SpvOpTypeSampler: - return "TypeSampler"; + return String("TypeSampler"); case SpvOpTypeSampledImage: - return "TypeSampledImage"; + return String("TypeSampledImage"); case SpvOpTypeArray: - return "TypeArray"; + return String("TypeArray"); case SpvOpTypeRuntimeArray: - return "TypeRuntimeArray"; + return String("TypeRuntimeArray"); case SpvOpTypeStruct: - return "TypeStruct"; + return String("TypeStruct"); case SpvOpTypeOpaque: - return "TypeOpaque"; + return String("TypeOpaque"); case SpvOpTypePointer: - return "TypePointer"; + return String("TypePointer"); case SpvOpTypeFunction: - return "TypeFunction"; + return String("TypeFunction"); case SpvOpTypeEvent: - return "TypeEvent"; + return String("TypeEvent"); case SpvOpTypeDeviceEvent: - return "TypeDeviceEvent"; + return String("TypeDeviceEvent"); case SpvOpTypeReserveId: - return "TypeReserveId"; + return String("TypeReserveId"); case SpvOpTypeQueue: - return "TypeQueue"; + return String("TypeQueue"); case SpvOpTypePipe: - return "TypePipe"; + return String("TypePipe"); case SpvOpTypeForwardPointer: - return "TypeForwardPointer"; + return String("TypeForwardPointer"); case SpvOpConstantTrue: - return "ConstantTrue"; + return String("ConstantTrue"); case SpvOpConstantFalse: - return "ConstantFalse"; + return String("ConstantFalse"); case SpvOpConstant: - return "Constant"; + return String("Constant"); case SpvOpConstantComposite: - return "ConstantComposite"; + return String("ConstantComposite"); case SpvOpConstantSampler: - return "ConstantSampler"; + return String("ConstantSampler"); case SpvOpConstantNull: - return "ConstantNull"; + return String("ConstantNull"); case SpvOpSpecConstantTrue: - return "SpecConstantTrue"; + return String("SpecConstantTrue"); case SpvOpSpecConstantFalse: - return "SpecConstantFalse"; + return String("SpecConstantFalse"); case SpvOpSpecConstant: - return "SpecConstant"; + return String("SpecConstant"); case SpvOpSpecConstantComposite: - return "SpecConstantComposite"; + return String("SpecConstantComposite"); case SpvOpSpecConstantOp: - return "SpecConstantOp"; + return String("SpecConstantOp"); case SpvOpFunction: - return "Function"; + return String("Function"); case SpvOpFunctionParameter: - return "FunctionParameter"; + return String("FunctionParameter"); case SpvOpFunctionEnd: - return "FunctionEnd"; + return String("FunctionEnd"); case SpvOpFunctionCall: - return "FunctionCall"; + return String("FunctionCall"); case SpvOpVariable: - return "Variable"; + return String("Variable"); case SpvOpImageTexelPointer: - return "ImageTexelPointer"; + return String("ImageTexelPointer"); case SpvOpLoad: - return "Load"; + return String("Load"); case SpvOpStore: - return "Store"; + return String("Store"); case SpvOpCopyMemory: - return "CopyMemory"; + return String("CopyMemory"); case SpvOpCopyMemorySized: - return "CopyMemorySized"; + return String("CopyMemorySized"); case SpvOpAccessChain: - return "AccessChain"; + return String("AccessChain"); case SpvOpInBoundsAccessChain: - return "InBoundsAccessChain"; + return String("InBoundsAccessChain"); case SpvOpPtrAccessChain: - return "PtrAccessChain"; + return String("PtrAccessChain"); case SpvOpArrayLength: - return "ArrayLength"; + return String("ArrayLength"); case SpvOpGenericPtrMemSemantics: - return "GenericPtrMemSemantics"; + return String("GenericPtrMemSemantics"); case SpvOpInBoundsPtrAccessChain: - return "InBoundsPtrAccessChain"; + return String("InBoundsPtrAccessChain"); case SpvOpDecorate: - return "Decorate"; + return String("Decorate"); case SpvOpMemberDecorate: - return "MemberDecorate"; + return String("MemberDecorate"); case SpvOpDecorationGroup: - return "DecorationGroup"; + return String("DecorationGroup"); case SpvOpGroupDecorate: - return "GroupDecorate"; + return String("GroupDecorate"); case SpvOpGroupMemberDecorate: - return "GroupMemberDecorate"; + return String("GroupMemberDecorate"); case SpvOpVectorExtractDynamic: - return "VectorExtractDynamic"; + return String("VectorExtractDynamic"); case SpvOpVectorInsertDynamic: - return "VectorInsertDynamic"; + return String("VectorInsertDynamic"); case SpvOpVectorShuffle: - return "VectorShuffle"; + return String("VectorShuffle"); case SpvOpCompositeConstruct: - return "CompositeConstruct"; + return String("CompositeConstruct"); case SpvOpCompositeExtract: - return "CompositeExtract"; + return String("CompositeExtract"); case SpvOpCompositeInsert: - return "CompositeInsert"; + return String("CompositeInsert"); case SpvOpCopyObject: - return "CopyObject"; + return String("CopyObject"); case SpvOpTranspose: - return "Transpose"; + return String("Transpose"); case SpvOpSampledImage: - return "SampledImage"; + return String("SampledImage"); case SpvOpImageSampleImplicitLod: - return "ImageSampleImplicitLod"; + return String("ImageSampleImplicitLod"); case SpvOpImageSampleExplicitLod: - return "ImageSampleExplicitLod"; + return String("ImageSampleExplicitLod"); case SpvOpImageSampleDrefImplicitLod: - return "ImageSampleDrefImplicitLod"; + return String("ImageSampleDrefImplicitLod"); case SpvOpImageSampleDrefExplicitLod: - return "ImageSampleDrefExplicitLod"; + return String("ImageSampleDrefExplicitLod"); case SpvOpImageSampleProjImplicitLod: - return "ImageSampleProjImplicitLod"; + return String("ImageSampleProjImplicitLod"); case SpvOpImageSampleProjExplicitLod: - return "ImageSampleProjExplicitLod"; + return String("ImageSampleProjExplicitLod"); case SpvOpImageSampleProjDrefImplicitLod: - return "ImageSampleProjDrefImplicitLod"; + return String("ImageSampleProjDrefImplicitLod"); case SpvOpImageSampleProjDrefExplicitLod: - return "ImageSampleProjDrefExplicitLod"; + return String("ImageSampleProjDrefExplicitLod"); case SpvOpImageFetch: - return "ImageFetch"; + return String("ImageFetch"); case SpvOpImageGather: - return "ImageGather"; + return String("ImageGather"); case SpvOpImageDrefGather: - return "ImageDrefGather"; + return String("ImageDrefGather"); case SpvOpImageRead: - return "ImageRead"; + return String("ImageRead"); case SpvOpImageWrite: - return "ImageWrite"; + return String("ImageWrite"); case SpvOpImage: - return "Image"; + return String("Image"); case SpvOpImageQueryFormat: - return "ImageQueryFormat"; + return String("ImageQueryFormat"); case SpvOpImageQueryOrder: - return "ImageQueryOrder"; + return String("ImageQueryOrder"); case SpvOpImageQuerySizeLod: - return "ImageQuerySizeLod"; + return String("ImageQuerySizeLod"); case SpvOpImageQuerySize: - return "ImageQuerySize"; + return String("ImageQuerySize"); case SpvOpImageQueryLod: - return "ImageQueryLod"; + return String("ImageQueryLod"); case SpvOpImageQueryLevels: - return "ImageQueryLevels"; + return String("ImageQueryLevels"); case SpvOpImageQuerySamples: - return "ImageQuerySamples"; + return String("ImageQuerySamples"); case SpvOpConvertFToU: - return "ConvertFToU"; + return String("ConvertFToU"); case SpvOpConvertFToS: - return "ConvertFToS"; + return String("ConvertFToS"); case SpvOpConvertSToF: - return "ConvertSToF"; + return String("ConvertSToF"); case SpvOpConvertUToF: - return "ConvertUToF"; + return String("ConvertUToF"); case SpvOpUConvert: - return "UConvert"; + return String("UConvert"); case SpvOpSConvert: - return "SConvert"; + return String("SConvert"); case SpvOpFConvert: - return "FConvert"; + return String("FConvert"); case SpvOpQuantizeToF16: - return "QuantizeToF16"; + return String("QuantizeToF16"); case SpvOpConvertPtrToU: - return "ConvertPtrToU"; + return String("ConvertPtrToU"); case SpvOpSatConvertSToU: - return "SatConvertSToU"; + return String("SatConvertSToU"); case SpvOpSatConvertUToS: - return "SatConvertUToS"; + return String("SatConvertUToS"); case SpvOpConvertUToPtr: - return "ConvertUToPtr"; + return String("ConvertUToPtr"); case SpvOpPtrCastToGeneric: - return "PtrCastToGeneric"; + return String("PtrCastToGeneric"); case SpvOpGenericCastToPtr: - return "GenericCastToPtr"; + return String("GenericCastToPtr"); case SpvOpGenericCastToPtrExplicit: - return "GenericCastToPtrExplicit"; + return String("GenericCastToPtrExplicit"); case SpvOpBitcast: - return "Bitcast"; + return String("Bitcast"); case SpvOpSNegate: - return "SNegate"; + return String("SNegate"); case SpvOpFNegate: - return "FNegate"; + return String("FNegate"); case SpvOpIAdd: - return "IAdd"; + return String("IAdd"); case SpvOpFAdd: - return "FAdd"; + return String("FAdd"); case SpvOpISub: - return "ISub"; + return String("ISub"); case SpvOpFSub: - return "FSub"; + return String("FSub"); case SpvOpIMul: - return "IMul"; + return String("IMul"); case SpvOpFMul: - return "FMul"; + return String("FMul"); case SpvOpUDiv: - return "UDiv"; + return String("UDiv"); case SpvOpSDiv: - return "SDiv"; + return String("SDiv"); case SpvOpFDiv: - return "FDiv"; + return String("FDiv"); case SpvOpUMod: - return "UMod"; + return String("UMod"); case SpvOpSRem: - return "SRem"; + return String("SRem"); case SpvOpSMod: - return "SMod"; + return String("SMod"); case SpvOpFRem: - return "FRem"; + return String("FRem"); case SpvOpFMod: - return "FMod"; + return String("FMod"); case SpvOpVectorTimesScalar: - return "VectorTimesScalar"; + return String("VectorTimesScalar"); case SpvOpMatrixTimesScalar: - return "MatrixTimesScalar"; + return String("MatrixTimesScalar"); case SpvOpVectorTimesMatrix: - return "VectorTimesMatrix"; + return String("VectorTimesMatrix"); case SpvOpMatrixTimesVector: - return "MatrixTimesVector"; + return String("MatrixTimesVector"); case SpvOpMatrixTimesMatrix: - return "MatrixTimesMatrix"; + return String("MatrixTimesMatrix"); case SpvOpOuterProduct: - return "OuterProduct"; + return String("OuterProduct"); case SpvOpDot: - return "Dot"; + return String("Dot"); case SpvOpIAddCarry: - return "IAddCarry"; + return String("IAddCarry"); case SpvOpISubBorrow: - return "ISubBorrow"; + return String("ISubBorrow"); case SpvOpUMulExtended: - return "UMulExtended"; + return String("UMulExtended"); case SpvOpSMulExtended: - return "SMulExtended"; + return String("SMulExtended"); case SpvOpAny: - return "Any"; + return String("Any"); case SpvOpAll: - return "All"; + return String("All"); case SpvOpIsNan: - return "IsNan"; + return String("IsNan"); case SpvOpIsInf: - return "IsInf"; + return String("IsInf"); case SpvOpIsFinite: - return "IsFinite"; + return String("IsFinite"); case SpvOpIsNormal: - return "IsNormal"; + return String("IsNormal"); case SpvOpSignBitSet: - return "SignBitSet"; + return String("SignBitSet"); case SpvOpLessOrGreater: - return "LessOrGreater"; + return String("LessOrGreater"); case SpvOpOrdered: - return "Ordered"; + return String("Ordered"); case SpvOpUnordered: - return "Unordered"; + return String("Unordered"); case SpvOpLogicalEqual: - return "LogicalEqual"; + return String("LogicalEqual"); case SpvOpLogicalNotEqual: - return "LogicalNotEqual"; + return String("LogicalNotEqual"); case SpvOpLogicalOr: - return "LogicalOr"; + return String("LogicalOr"); case SpvOpLogicalAnd: - return "LogicalAnd"; + return String("LogicalAnd"); case SpvOpLogicalNot: - return "LogicalNot"; + return String("LogicalNot"); case SpvOpSelect: - return "Select"; + return String("Select"); case SpvOpIEqual: - return "IEqual"; + return String("IEqual"); case SpvOpINotEqual: - return "INotEqual"; + return String("INotEqual"); case SpvOpUGreaterThan: - return "UGreaterThan"; + return String("UGreaterThan"); case SpvOpSGreaterThan: - return "SGreaterThan"; + return String("SGreaterThan"); case SpvOpUGreaterThanEqual: - return "UGreaterThanEqual"; + return String("UGreaterThanEqual"); case SpvOpSGreaterThanEqual: - return "SGreaterThanEqual"; + return String("SGreaterThanEqual"); case SpvOpULessThan: - return "ULessThan"; + return String("ULessThan"); case SpvOpSLessThan: - return "SLessThan"; + return String("SLessThan"); case SpvOpULessThanEqual: - return "ULessThanEqual"; + return String("ULessThanEqual"); case SpvOpSLessThanEqual: - return "SLessThanEqual"; + return String("SLessThanEqual"); case SpvOpFOrdEqual: - return "FOrdEqual"; + return String("FOrdEqual"); case SpvOpFUnordEqual: - return "FUnordEqual"; + return String("FUnordEqual"); case SpvOpFOrdNotEqual: - return "FOrdNotEqual"; + return String("FOrdNotEqual"); case SpvOpFUnordNotEqual: - return "FUnordNotEqual"; + return String("FUnordNotEqual"); case SpvOpFOrdLessThan: - return "FOrdLessThan"; + return String("FOrdLessThan"); case SpvOpFUnordLessThan: - return "FUnordLessThan"; + return String("FUnordLessThan"); case SpvOpFOrdGreaterThan: - return "FOrdGreaterThan"; + return String("FOrdGreaterThan"); case SpvOpFUnordGreaterThan: - return "FUnordGreaterThan"; + return String("FUnordGreaterThan"); case SpvOpFOrdLessThanEqual: - return "FOrdLessThanEqual"; + return String("FOrdLessThanEqual"); case SpvOpFUnordLessThanEqual: - return "FUnordLessThanEqual"; + return String("FUnordLessThanEqual"); case SpvOpFOrdGreaterThanEqual: - return "FOrdGreaterThanEqual"; + return String("FOrdGreaterThanEqual"); case SpvOpFUnordGreaterThanEqual: - return "FUnordGreaterThanEqual"; + return String("FUnordGreaterThanEqual"); case SpvOpShiftRightLogical: - return "ShiftRightLogical"; + return String("ShiftRightLogical"); case SpvOpShiftRightArithmetic: - return "ShiftRightArithmetic"; + return String("ShiftRightArithmetic"); case SpvOpShiftLeftLogical: - return "ShiftLeftLogical"; + return String("ShiftLeftLogical"); case SpvOpBitwiseOr: - return "BitwiseOr"; + return String("BitwiseOr"); case SpvOpBitwiseXor: - return "BitwiseXor"; + return String("BitwiseXor"); case SpvOpBitwiseAnd: - return "BitwiseAnd"; + return String("BitwiseAnd"); case SpvOpNot: - return "Not"; + return String("Not"); case SpvOpBitFieldInsert: - return "BitFieldInsert"; + return String("BitFieldInsert"); case SpvOpBitFieldSExtract: - return "BitFieldSExtract"; + return String("BitFieldSExtract"); case SpvOpBitFieldUExtract: - return "BitFieldUExtract"; + return String("BitFieldUExtract"); case SpvOpBitReverse: - return "BitReverse"; + return String("BitReverse"); case SpvOpBitCount: - return "BitCount"; + return String("BitCount"); case SpvOpDPdx: - return "DPdx"; + return String("DPdx"); case SpvOpDPdy: - return "DPdy"; + return String("DPdy"); case SpvOpFwidth: - return "Fwidth"; + return String("Fwidth"); case SpvOpDPdxFine: - return "DPdxFine"; + return String("DPdxFine"); case SpvOpDPdyFine: - return "DPdyFine"; + return String("DPdyFine"); case SpvOpFwidthFine: - return "FwidthFine"; + return String("FwidthFine"); case SpvOpDPdxCoarse: - return "DPdxCoarse"; + return String("DPdxCoarse"); case SpvOpDPdyCoarse: - return "DPdyCoarse"; + return String("DPdyCoarse"); case SpvOpFwidthCoarse: - return "FwidthCoarse"; + return String("FwidthCoarse"); case SpvOpEmitVertex: - return "EmitVertex"; + return String("EmitVertex"); case SpvOpEndPrimitive: - return "EndPrimitive"; + return String("EndPrimitive"); case SpvOpEmitStreamVertex: - return "EmitStreamVertex"; + return String("EmitStreamVertex"); case SpvOpEndStreamPrimitive: - return "EndStreamPrimitive"; + return String("EndStreamPrimitive"); case SpvOpControlBarrier: - return "ControlBarrier"; + return String("ControlBarrier"); case SpvOpMemoryBarrier: - return "MemoryBarrier"; + return String("MemoryBarrier"); case SpvOpAtomicLoad: - return "AtomicLoad"; + return String("AtomicLoad"); case SpvOpAtomicStore: - return "AtomicStore"; + return String("AtomicStore"); case SpvOpAtomicExchange: - return "AtomicExchange"; + return String("AtomicExchange"); case SpvOpAtomicCompareExchange: - return "AtomicCompareExchange"; + return String("AtomicCompareExchange"); case SpvOpAtomicCompareExchangeWeak: - return "AtomicCompareExchangeWeak"; + return String("AtomicCompareExchangeWeak"); case SpvOpAtomicIIncrement: - return "AtomicIIncrement"; + return String("AtomicIIncrement"); case SpvOpAtomicIDecrement: - return "AtomicIDecrement"; + return String("AtomicIDecrement"); case SpvOpAtomicIAdd: - return "AtomicIAdd"; + return String("AtomicIAdd"); case SpvOpAtomicISub: - return "AtomicISub"; + return String("AtomicISub"); case SpvOpAtomicSMin: - return "AtomicSMin"; + return String("AtomicSMin"); case SpvOpAtomicUMin: - return "AtomicUMin"; + return String("AtomicUMin"); case SpvOpAtomicSMax: - return "AtomicSMax"; + return String("AtomicSMax"); case SpvOpAtomicUMax: - return "AtomicUMax"; + return String("AtomicUMax"); case SpvOpAtomicAnd: - return "AtomicAnd"; + return String("AtomicAnd"); case SpvOpAtomicOr: - return "AtomicOr"; + return String("AtomicOr"); case SpvOpAtomicXor: - return "AtomicXor"; + return String("AtomicXor"); case SpvOpPhi: - return "Phi"; + return String("Phi"); case SpvOpLoopMerge: - return "LoopMerge"; + return String("LoopMerge"); case SpvOpSelectionMerge: - return "SelectionMerge"; + return String("SelectionMerge"); case SpvOpLabel: - return "Label"; + return String("Label"); case SpvOpBranch: - return "Branch"; + return String("Branch"); case SpvOpBranchConditional: - return "BranchConditional"; + return String("BranchConditional"); case SpvOpSwitch: - return "Switch"; + return String("Switch"); case SpvOpKill: - return "Kill"; + return String("Kill"); case SpvOpReturn: - return "Return"; + return String("Return"); case SpvOpReturnValue: - return "ReturnValue"; + return String("ReturnValue"); case SpvOpUnreachable: - return "Unreachable"; + return String("Unreachable"); case SpvOpLifetimeStart: - return "LifetimeStart"; + return String("LifetimeStart"); case SpvOpLifetimeStop: - return "LifetimeStop"; + return String("LifetimeStop"); case SpvOpGroupAsyncCopy: - return "GroupAsyncCopy"; + return String("GroupAsyncCopy"); case SpvOpGroupWaitEvents: - return "GroupWaitEvents"; + return String("GroupWaitEvents"); case SpvOpGroupAll: - return "GroupAll"; + return String("GroupAll"); case SpvOpGroupAny: - return "GroupAny"; + return String("GroupAny"); case SpvOpGroupBroadcast: - return "GroupBroadcast"; + return String("GroupBroadcast"); case SpvOpGroupIAdd: - return "GroupIAdd"; + return String("GroupIAdd"); case SpvOpGroupFAdd: - return "GroupFAdd"; + return String("GroupFAdd"); case SpvOpGroupFMin: - return "GroupFMin"; + return String("GroupFMin"); case SpvOpGroupUMin: - return "GroupUMin"; + return String("GroupUMin"); case SpvOpGroupSMin: - return "GroupSMin"; + return String("GroupSMin"); case SpvOpGroupFMax: - return "GroupFMax"; + return String("GroupFMax"); case SpvOpGroupUMax: - return "GroupUMax"; + return String("GroupUMax"); case SpvOpGroupSMax: - return "GroupSMax"; + return String("GroupSMax"); case SpvOpReadPipe: - return "ReadPipe"; + return String("ReadPipe"); case SpvOpWritePipe: - return "WritePipe"; + return String("WritePipe"); case SpvOpReservedReadPipe: - return "ReservedReadPipe"; + return String("ReservedReadPipe"); case SpvOpReservedWritePipe: - return "ReservedWritePipe"; + return String("ReservedWritePipe"); case SpvOpReserveReadPipePackets: - return "ReserveReadPipePackets"; + return String("ReserveReadPipePackets"); case SpvOpReserveWritePipePackets: - return "ReserveWritePipePackets"; + return String("ReserveWritePipePackets"); case SpvOpCommitReadPipe: - return "CommitReadPipe"; + return String("CommitReadPipe"); case SpvOpCommitWritePipe: - return "CommitWritePipe"; + return String("CommitWritePipe"); case SpvOpIsValidReserveId: - return "IsValidReserveId"; + return String("IsValidReserveId"); case SpvOpGetNumPipePackets: - return "GetNumPipePackets"; + return String("GetNumPipePackets"); case SpvOpGetMaxPipePackets: - return "GetMaxPipePackets"; + return String("GetMaxPipePackets"); case SpvOpGroupReserveReadPipePackets: - return "GroupReserveReadPipePackets"; + return String("GroupReserveReadPipePackets"); case SpvOpGroupReserveWritePipePackets: - return "GroupReserveWritePipePackets"; + return String("GroupReserveWritePipePackets"); case SpvOpGroupCommitReadPipe: - return "GroupCommitReadPipe"; + return String("GroupCommitReadPipe"); case SpvOpGroupCommitWritePipe: - return "GroupCommitWritePipe"; + return String("GroupCommitWritePipe"); case SpvOpEnqueueMarker: - return "EnqueueMarker"; + return String("EnqueueMarker"); case SpvOpEnqueueKernel: - return "EnqueueKernel"; + return String("EnqueueKernel"); case SpvOpGetKernelNDrangeSubGroupCount: - return "GetKernelNDrangeSubGroupCount"; + return String("GetKernelNDrangeSubGroupCount"); case SpvOpGetKernelNDrangeMaxSubGroupSize: - return "GetKernelNDrangeMaxSubGroupSize"; + return String("GetKernelNDrangeMaxSubGroupSize"); case SpvOpGetKernelWorkGroupSize: - return "GetKernelWorkGroupSize"; + return String("GetKernelWorkGroupSize"); case SpvOpGetKernelPreferredWorkGroupSizeMultiple: - return "GetKernelPreferredWorkGroupSizeMultiple"; + return String("GetKernelPreferredWorkGroupSizeMultiple"); case SpvOpRetainEvent: - return "RetainEvent"; + return String("RetainEvent"); case SpvOpReleaseEvent: - return "ReleaseEvent"; + return String("ReleaseEvent"); case SpvOpCreateUserEvent: - return "CreateUserEvent"; + return String("CreateUserEvent"); case SpvOpIsValidEvent: - return "IsValidEvent"; + return String("IsValidEvent"); case SpvOpSetUserEventStatus: - return "SetUserEventStatus"; + return String("SetUserEventStatus"); case SpvOpCaptureEventProfilingInfo: - return "CaptureEventProfilingInfo"; + return String("CaptureEventProfilingInfo"); case SpvOpGetDefaultQueue: - return "GetDefaultQueue"; + return String("GetDefaultQueue"); case SpvOpBuildNDRange: - return "BuildNDRange"; + return String("BuildNDRange"); case SpvOpImageSparseSampleImplicitLod: - return "ImageSparseSampleImplicitLod"; + return String("ImageSparseSampleImplicitLod"); case SpvOpImageSparseSampleExplicitLod: - return "ImageSparseSampleExplicitLod"; + return String("ImageSparseSampleExplicitLod"); case SpvOpImageSparseSampleDrefImplicitLod: - return "ImageSparseSampleDrefImplicitLod"; + return String("ImageSparseSampleDrefImplicitLod"); case SpvOpImageSparseSampleDrefExplicitLod: - return "ImageSparseSampleDrefExplicitLod"; + return String("ImageSparseSampleDrefExplicitLod"); case SpvOpImageSparseSampleProjImplicitLod: - return "ImageSparseSampleProjImplicitLod"; + return String("ImageSparseSampleProjImplicitLod"); case SpvOpImageSparseSampleProjExplicitLod: - return "ImageSparseSampleProjExplicitLod"; + return String("ImageSparseSampleProjExplicitLod"); case SpvOpImageSparseSampleProjDrefImplicitLod: - return "ImageSparseSampleProjDrefImplicitLod"; + return String("ImageSparseSampleProjDrefImplicitLod"); case SpvOpImageSparseSampleProjDrefExplicitLod: - return "ImageSparseSampleProjDrefExplicitLod"; + return String("ImageSparseSampleProjDrefExplicitLod"); case SpvOpImageSparseFetch: - return "ImageSparseFetch"; + return String("ImageSparseFetch"); case SpvOpImageSparseGather: - return "ImageSparseGather"; + return String("ImageSparseGather"); case SpvOpImageSparseDrefGather: - return "ImageSparseDrefGather"; + return String("ImageSparseDrefGather"); case SpvOpImageSparseTexelsResident: - return "ImageSparseTexelsResident"; + return String("ImageSparseTexelsResident"); case SpvOpNoLine: - return "NoLine"; + return String("NoLine"); case SpvOpAtomicFlagTestAndSet: - return "AtomicFlagTestAndSet"; + return String("AtomicFlagTestAndSet"); case SpvOpAtomicFlagClear: - return "AtomicFlagClear"; + return String("AtomicFlagClear"); case SpvOpImageSparseRead: - return "ImageSparseRead"; + return String("ImageSparseRead"); default: - ABORT("unsupported SPIR-V op"); + ABORT("unsupported SPIR-V op"); } } #endif -void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, std::ostream& out) { +void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) { ASSERT(opCode != SpvOpUndef); switch (opCode) { case SpvOpReturn: // fall through @@ -824,55 +827,55 @@ void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, std::ostream& ou #endif } -void SPIRVCodeGenerator::writeLabel(SpvId label, std::ostream& out) { +void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) { fCurrentBlock = label; this->writeInstruction(SpvOpLabel, label, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, std::ostream& out) { +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) { this->writeOpCode(opCode, 1, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, std::ostream& out) { +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) { this->writeOpCode(opCode, 2, out); this->writeWord(word1, out); } -void SPIRVCodeGenerator::writeString(const char* string, std::ostream& out) { +void SPIRVCodeGenerator::writeString(const char* string, OutputStream& out) { size_t length = strlen(string); - out << string; + out.write(string, length); switch (length % 4) { case 1: - out << (char) 0; + out.write8(0); // fall through case 2: - out << (char) 0; + out.write8(0); // fall through case 3: - out << (char) 0; + out.write8(0); break; default: this->writeWord(0, out); } } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, const char* string, std::ostream& out) { +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, const char* string, OutputStream& out) { int32_t length = (int32_t) strlen(string); this->writeOpCode(opCode, 1 + (length + 4) / 4, out); this->writeString(string, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, const char* string, - std::ostream& out) { +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, const char* string, + OutputStream& out) { int32_t length = (int32_t) strlen(string); this->writeOpCode(opCode, 2 + (length + 4) / 4, out); this->writeWord(word1, out); this->writeString(string, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, - const char* string, std::ostream& out) { +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, + const char* string, OutputStream& out) { int32_t length = (int32_t) strlen(string); this->writeOpCode(opCode, 3 + (length + 4) / 4, out); this->writeWord(word1, out); @@ -880,23 +883,23 @@ void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t this->writeString(string, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, - std::ostream& out) { +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, + OutputStream& out) { this->writeOpCode(opCode, 3, out); this->writeWord(word1, out); this->writeWord(word2, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, - int32_t word3, std::ostream& out) { +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, + int32_t word3, OutputStream& out) { this->writeOpCode(opCode, 4, out); this->writeWord(word1, out); this->writeWord(word2, out); this->writeWord(word3, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, - int32_t word3, int32_t word4, std::ostream& out) { +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, + int32_t word3, int32_t word4, OutputStream& out) { this->writeOpCode(opCode, 5, out); this->writeWord(word1, out); this->writeWord(word2, out); @@ -904,9 +907,9 @@ void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t this->writeWord(word4, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, - int32_t word3, int32_t word4, int32_t word5, - std::ostream& out) { +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, + int32_t word3, int32_t word4, int32_t word5, + OutputStream& out) { this->writeOpCode(opCode, 6, out); this->writeWord(word1, out); this->writeWord(word2, out); @@ -915,9 +918,9 @@ void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t this->writeWord(word5, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4, int32_t word5, - int32_t word6, std::ostream& out) { + int32_t word6, OutputStream& out) { this->writeOpCode(opCode, 7, out); this->writeWord(word1, out); this->writeWord(word2, out); @@ -927,9 +930,9 @@ void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t this->writeWord(word6, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4, int32_t word5, - int32_t word6, int32_t word7, std::ostream& out) { + int32_t word6, int32_t word7, OutputStream& out) { this->writeOpCode(opCode, 8, out); this->writeWord(word1, out); this->writeWord(word2, out); @@ -940,10 +943,10 @@ void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t this->writeWord(word7, out); } -void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, +void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4, int32_t word5, int32_t word6, int32_t word7, int32_t word8, - std::ostream& out) { + OutputStream& out) { this->writeOpCode(opCode, 9, out); this->writeWord(word1, out); this->writeWord(word2, out); @@ -955,7 +958,7 @@ void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t this->writeWord(word8, out); } -void SPIRVCodeGenerator::writeCapabilities(std::ostream& out) { +void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) { for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) { if (fCapabilities & bit) { this->writeInstruction(SpvOpCapability, (SpvId) i, out); @@ -967,13 +970,14 @@ SpvId SPIRVCodeGenerator::nextId() { return fIdCount++; } -void SPIRVCodeGenerator::writeStruct(const Type& type, SpvId resultId) { +void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout, + SpvId resultId) { this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer); // go ahead and write all of the field types, so we don't inadvertently write them while we're // in the middle of writing the struct instruction std::vector types; for (const auto& f : type.fields()) { - types.push_back(this->getType(*f.fType)); + types.push_back(this->getType(*f.fType, memoryLayout)); } this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer); this->writeWord(resultId, fConstantBuffer); @@ -982,36 +986,56 @@ void SPIRVCodeGenerator::writeStruct(const Type& type, SpvId resultId) { } size_t offset = 0; for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) { - size_t size = type.fields()[i].fType->size(); - size_t alignment = type.fields()[i].fType->alignment(); - size_t mod = offset % alignment; - if (mod != 0) { - offset += alignment - mod; + size_t size = memoryLayout.size(*type.fields()[i].fType); + size_t alignment = memoryLayout.alignment(*type.fields()[i].fType); + const Layout& fieldLayout = type.fields()[i].fModifiers.fLayout; + if (fieldLayout.fOffset >= 0) { + if (fieldLayout.fOffset < (int) offset) { + fErrors.error(type.fPosition, + "offset of field '" + type.fields()[i].fName + "' must be at " + "least " + to_string((int) offset)); + } + if (fieldLayout.fOffset % alignment) { + fErrors.error(type.fPosition, + "offset of field '" + type.fields()[i].fName + "' must be a multiple" + " of " + to_string((int) alignment)); + } + offset = fieldLayout.fOffset; + } else { + size_t mod = offset % alignment; + if (mod) { + offset += alignment - mod; + } } this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName.c_str(), fNameBuffer); - this->writeLayout(type.fields()[i].fModifiers.fLayout, resultId, i); + this->writeLayout(fieldLayout, resultId, i); if (type.fields()[i].fModifiers.fLayout.fBuiltin < 0) { - this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset, + this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset, (SpvId) offset, fDecorationBuffer); } if (type.fields()[i].fType->kind() == Type::kMatrix_Kind) { - this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor, + this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor, + fDecorationBuffer); + this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride, + (SpvId) memoryLayout.stride(*type.fields()[i].fType), fDecorationBuffer); - this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride, - (SpvId) type.fields()[i].fType->stride(), fDecorationBuffer); } offset += size; Type::Kind kind = type.fields()[i].fType->kind(); if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) { offset += alignment - offset % alignment; } - ASSERT(offset % alignment == 0); } } SpvId SPIRVCodeGenerator::getType(const Type& type) { - auto entry = fTypeMap.find(type.name()); + return this->getType(type, fDefaultLayout); +} + +SpvId SPIRVCodeGenerator::getType(const Type& type, const MemoryLayout& layout) { + String key = type.name() + to_string((int) layout.fStd); + auto entry = fTypeMap.find(key); if (entry == fTypeMap.end()) { SpvId result = this->nextId(); switch (type.kind()) { @@ -1031,40 +1055,48 @@ SpvId SPIRVCodeGenerator::getType(const Type& type) { } break; case Type::kVector_Kind: - this->writeInstruction(SpvOpTypeVector, result, - this->getType(type.componentType()), + this->writeInstruction(SpvOpTypeVector, result, + this->getType(type.componentType(), layout), type.columns(), fConstantBuffer); break; case Type::kMatrix_Kind: - this->writeInstruction(SpvOpTypeMatrix, result, - this->getType(index_type(fContext, type)), + this->writeInstruction(SpvOpTypeMatrix, result, + this->getType(index_type(fContext, type), layout), type.columns(), fConstantBuffer); break; case Type::kStruct_Kind: - this->writeStruct(type, result); + this->writeStruct(type, layout, result); break; case Type::kArray_Kind: { if (type.columns() > 0) { IntLiteral count(fContext, Position(), type.columns()); - this->writeInstruction(SpvOpTypeArray, result, - this->getType(type.componentType()), + this->writeInstruction(SpvOpTypeArray, result, + this->getType(type.componentType(), layout), this->writeIntLiteral(count), fConstantBuffer); - this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride, - (int32_t) type.stride(), fDecorationBuffer); + this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride, + (int32_t) layout.stride(type), + fDecorationBuffer); } else { ABORT("runtime-sized arrays are not yet supported"); - this->writeInstruction(SpvOpTypeRuntimeArray, result, - this->getType(type.componentType()), fConstantBuffer); + this->writeInstruction(SpvOpTypeRuntimeArray, result, + this->getType(type.componentType(), layout), + fConstantBuffer); } break; } case Type::kSampler_Kind: { - SpvId image = this->nextId(); - this->writeInstruction(SpvOpTypeImage, image, this->getType(*fContext.fFloat_Type), + SpvId image = result; + if (SpvDimSubpassData != type.dimensions()) { + image = this->nextId(); + } + this->writeInstruction(SpvOpTypeImage, image, + this->getType(*fContext.fFloat_Type, layout), type.dimensions(), type.isDepth(), type.isArrayed(), - type.isMultisampled(), type.isSampled(), + type.isMultisampled(), type.isSampled() ? 1 : 2, SpvImageFormatUnknown, fConstantBuffer); - this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer); + if (SpvDimSubpassData != type.dimensions()) { + this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer); + } break; } default: @@ -1074,15 +1106,15 @@ SpvId SPIRVCodeGenerator::getType(const Type& type) { ABORT("invalid type: %s", type.description().c_str()); } } - fTypeMap[type.name()] = result; + fTypeMap[key] = result; return result; } return entry->second; } SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) { - std::string key = function.fReturnType.description() + "("; - std::string separator = ""; + String key = function.fReturnType.description() + "("; + String separator; for (size_t i = 0; i < function.fParameters.size(); i++) { key += separator; separator = ", "; @@ -1096,26 +1128,26 @@ SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) { SpvId returnType = this->getType(function.fReturnType); std::vector parameterTypes; for (size_t i = 0; i < function.fParameters.size(); i++) { - // glslang seems to treat all function arguments as pointers whether they need to be or - // not. I was initially puzzled by this until I ran bizarre failures with certain - // patterns of function calls and control constructs, as exemplified by this minimal + // glslang seems to treat all function arguments as pointers whether they need to be or + // not. I was initially puzzled by this until I ran bizarre failures with certain + // patterns of function calls and control constructs, as exemplified by this minimal // failure case: // // void sphere(float x) { // } - // + // // void map() { // sphere(1.0); // } - // + // // void main() { // for (int i = 0; i < 1; i++) { // map(); // } // } // - // As of this writing, compiling this in the "obvious" way (with sphere taking a float) - // crashes. Making it take a float* and storing the argument in a temporary variable, + // As of this writing, compiling this in the "obvious" way (with sphere taking a float) + // crashes. Making it take a float* and storing the argument in a temporary variable, // as glslang does, fixes it. It's entirely possible I simply missed whichever part of // the spec makes this make sense. // if (is_out(function->fParameters[i])) { @@ -1137,13 +1169,17 @@ SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) { return entry->second; } -SpvId SPIRVCodeGenerator::getPointerType(const Type& type, +SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) { + return this->getPointerType(type, fDefaultLayout, storageClass); +} + +SpvId SPIRVCodeGenerator::getPointerType(const Type& type, const MemoryLayout& layout, SpvStorageClass_ storageClass) { - std::string key = type.description() + "*" + to_string(storageClass); + String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass); auto entry = fTypeMap.find(key); if (entry == fTypeMap.end()) { SpvId result = this->nextId(); - this->writeInstruction(SpvOpTypePointer, result, storageClass, + this->writeInstruction(SpvOpTypePointer, result, storageClass, this->getType(type), fConstantBuffer); fTypeMap[key] = result; return result; @@ -1151,7 +1187,7 @@ SpvId SPIRVCodeGenerator::getPointerType(const Type& type, return entry->second; } -SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) { switch (expr.fKind) { case Expression::kBinary_Kind: return this->writeBinaryExpression((BinaryExpression&) expr, out); @@ -1185,7 +1221,7 @@ SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, std::ostream& return -1; } -SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) { auto intrinsic = fIntrinsicMap.find(c.fFunction.fName); ASSERT(intrinsic != fIntrinsicMap.end()); const Type& type = c.fArguments[0]->fType; @@ -1240,8 +1276,8 @@ SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, std::ostream } } -SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, - std::ostream& out) { +SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, + OutputStream& out) { SpvId result = this->nextId(); switch (kind) { case kAtan_SpecialIntrinsic: { @@ -1257,55 +1293,86 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn for (SpvId id : arguments) { this->writeWord(id, out); } - return result; + return result; } case kTexture_SpecialIntrinsic: { + SpvOp_ op = SpvOpImageSampleImplicitLod; + switch (c.fArguments[0]->fType.dimensions()) { + case SpvDim1D: + if (c.fArguments[1]->fType == *fContext.fVec2_Type) { + op = SpvOpImageSampleProjImplicitLod; + } else { + ASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type); + } + break; + case SpvDim2D: + if (c.fArguments[1]->fType == *fContext.fVec3_Type) { + op = SpvOpImageSampleProjImplicitLod; + } else { + ASSERT(c.fArguments[1]->fType == *fContext.fVec2_Type); + } + break; + case SpvDim3D: + if (c.fArguments[1]->fType == *fContext.fVec4_Type) { + op = SpvOpImageSampleProjImplicitLod; + } else { + ASSERT(c.fArguments[1]->fType == *fContext.fVec3_Type); + } + break; + case SpvDimCube: // fall through + case SpvDimRect: // fall through + case SpvDimBuffer: // fall through + case SpvDimSubpassData: + break; + } SpvId type = this->getType(c.fType); SpvId sampler = this->writeExpression(*c.fArguments[0], out); SpvId uv = this->writeExpression(*c.fArguments[1], out); if (c.fArguments.size() == 3) { - this->writeInstruction(SpvOpImageSampleImplicitLod, type, result, sampler, uv, + this->writeInstruction(op, type, result, sampler, uv, SpvImageOperandsBiasMask, this->writeExpression(*c.fArguments[2], out), out); } else { ASSERT(c.fArguments.size() == 2); - this->writeInstruction(SpvOpImageSampleImplicitLod, type, result, sampler, uv, out); - } - break; - } - case kTextureProj_SpecialIntrinsic: { - SpvId type = this->getType(c.fType); - SpvId sampler = this->writeExpression(*c.fArguments[0], out); - SpvId uv = this->writeExpression(*c.fArguments[1], out); - if (c.fArguments.size() == 3) { - this->writeInstruction(SpvOpImageSampleProjImplicitLod, type, result, sampler, uv, - SpvImageOperandsBiasMask, - this->writeExpression(*c.fArguments[2], out), - out); - } else { - ASSERT(c.fArguments.size() == 2); - this->writeInstruction(SpvOpImageSampleProjImplicitLod, type, result, sampler, uv, + this->writeInstruction(op, type, result, sampler, uv, out); } break; } - case kTexture2D_SpecialIntrinsic: { + case kSubpassLoad_SpecialIntrinsic: { SpvId img = this->writeExpression(*c.fArguments[0], out); - SpvId coords = this->writeExpression(*c.fArguments[1], out); - this->writeInstruction(SpvOpImageSampleImplicitLod, - this->getType(c.fType), - result, - img, - coords, - out); + std::vector> args; + args.emplace_back(new FloatLiteral(fContext, Position(), 0.0)); + args.emplace_back(new FloatLiteral(fContext, Position(), 0.0)); + Constructor ctor(Position(), *fContext.fVec2_Type, std::move(args)); + SpvId coords = this->writeConstantVector(ctor); + if (1 == c.fArguments.size()) { + this->writeInstruction(SpvOpImageRead, + this->getType(c.fType), + result, + img, + coords, + out); + } else { + ASSERT(2 == c.fArguments.size()); + SpvId sample = this->writeExpression(*c.fArguments[1], out); + this->writeInstruction(SpvOpImageRead, + this->getType(c.fType), + result, + img, + coords, + SpvImageOperandsSampleMask, + sample, + out); + } break; } } return result; } -SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) { const auto& entry = fFunctionMap.find(&c.fFunction); if (entry == fFunctionMap.end()) { return this->writeIntrinsicCall(c, out); @@ -1314,7 +1381,7 @@ SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, std::ostream& std::vector>> lvalues; std::vector arguments; for (size_t i = 0; i < c.fArguments.size(); i++) { - // id of temporary variable that we will use to hold this argument, or 0 if it is being + // id of temporary variable that we will use to hold this argument, or 0 if it is being // passed directly SpvId tmpVar; // if we need a temporary var to store this argument, this is the value to store in the var @@ -1339,10 +1406,10 @@ SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, std::ostream& tmpValueId = this->writeExpression(*c.fArguments[i], out); tmpVar = this->nextId(); } - this->writeInstruction(SpvOpVariable, - this->getPointerType(c.fArguments[i]->fType, + this->writeInstruction(SpvOpVariable, + this->getPointerType(c.fArguments[i]->fType, SpvStorageClassFunction), - tmpVar, + tmpVar, SpvStorageClassFunction, fVariableBuffer); this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out); @@ -1383,7 +1450,7 @@ SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) { this->writeWord(arguments[0], fConstantBuffer); } } else { - this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(), + this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(), fConstantBuffer); this->writeWord(type, fConstantBuffer); this->writeWord(result, fConstantBuffer); @@ -1394,17 +1461,17 @@ SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) { return result; } -SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) { ASSERT(c.fType == *fContext.fFloat_Type); ASSERT(c.fArguments.size() == 1); ASSERT(c.fArguments[0]->fType.isNumber()); SpvId result = this->nextId(); SpvId parameter = this->writeExpression(*c.fArguments[0], out); if (c.fArguments[0]->fType == *fContext.fInt_Type) { - this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter, + this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter, out); } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) { - this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter, + this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter, out); } else if (c.fArguments[0]->fType == *fContext.fFloat_Type) { return parameter; @@ -1412,17 +1479,17 @@ SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, std::ostre return result; } -SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) { ASSERT(c.fType == *fContext.fInt_Type); ASSERT(c.fArguments.size() == 1); ASSERT(c.fArguments[0]->fType.isNumber()); SpvId result = this->nextId(); SpvId parameter = this->writeExpression(*c.fArguments[0], out); if (c.fArguments[0]->fType == *fContext.fFloat_Type) { - this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter, + this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter, out); } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) { - this->writeInstruction(SpvOpSatConvertUToS, this->getType(c.fType), result, parameter, + this->writeInstruction(SpvOpSatConvertUToS, this->getType(c.fType), result, parameter, out); } else if (c.fArguments[0]->fType == *fContext.fInt_Type) { return parameter; @@ -1430,7 +1497,38 @@ SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, std::ostream return result; } -SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, std::ostream& out) { +void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type, + OutputStream& out) { + FloatLiteral zero(fContext, Position(), 0); + SpvId zeroId = this->writeFloatLiteral(zero); + std::vector columnIds; + for (int column = 0; column < type.columns(); column++) { + this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(), + out); + this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)), + out); + SpvId columnId = this->nextId(); + this->writeWord(columnId, out); + columnIds.push_back(columnId); + for (int row = 0; row < type.columns(); row++) { + this->writeWord(row == column ? diagonal : zeroId, out); + } + } + this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), + out); + this->writeWord(this->getType(type), out); + this->writeWord(id, out); + for (SpvId id : columnIds) { + this->writeWord(id, out); + } +} + +void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType, + const Type& dstType, OutputStream& out) { + ABORT("unimplemented"); +} + +SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) { ASSERT(c.fType.kind() == Type::kMatrix_Kind); // go ahead and write the arguments so we don't try to write new instructions in the middle of // an instruction @@ -1441,33 +1539,10 @@ SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, std::ostr SpvId result = this->nextId(); int rows = c.fType.rows(); int columns = c.fType.columns(); - // FIXME this won't work to create a matrix from another matrix - if (arguments.size() == 1) { - // with a single argument, a matrix will have all of its diagonal entries equal to the - // argument and its other values equal to zero - // FIXME this won't work for int matrices - FloatLiteral zero(fContext, Position(), 0); - SpvId zeroId = this->writeFloatLiteral(zero); - std::vector columnIds; - for (int column = 0; column < columns; column++) { - this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(), - out); - this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows, 1)), - out); - SpvId columnId = this->nextId(); - this->writeWord(columnId, out); - columnIds.push_back(columnId); - for (int row = 0; row < c.fType.columns(); row++) { - this->writeWord(row == column ? arguments[0] : zeroId, out); - } - } - this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, - out); - this->writeWord(this->getType(c.fType), out); - this->writeWord(result, out); - for (SpvId id : columnIds) { - this->writeWord(id, out); - } + if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) { + this->writeUniformScaleMatrix(result, arguments[0], c.fType, out); + } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) { + this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out); } else { std::vector columnIds; int currentCount = 0; @@ -1480,8 +1555,8 @@ SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, std::ostr ASSERT(c.fArguments[i]->fType.kind() == Type::kScalar_Kind); if (currentCount == 0) { this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(), out); - this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows, - 1)), + this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows, + 1)), out); SpvId id = this->nextId(); this->writeWord(id, out); @@ -1502,7 +1577,7 @@ SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, std::ostr return result; } -SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) { ASSERT(c.fType.kind() == Type::kVector_Kind); if (c.isConstant()) { return this->writeConstantVector(c); @@ -1532,7 +1607,7 @@ SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, std::ostr return result; } -SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) { if (c.fType == *fContext.fFloat_Type) { return this->writeFloatConstructor(c, out); } else if (c.fType == *fContext.fInt_Type) { @@ -1550,10 +1625,15 @@ SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, std::ostream& o SpvStorageClass_ get_storage_class(const Modifiers& modifiers) { if (modifiers.fFlags & Modifiers::kIn_Flag) { + ASSERT(!modifiers.fLayout.fPushConstant); return SpvStorageClassInput; } else if (modifiers.fFlags & Modifiers::kOut_Flag) { + ASSERT(!modifiers.fLayout.fPushConstant); return SpvStorageClassOutput; } else if (modifiers.fFlags & Modifiers::kUniform_Flag) { + if (modifiers.fLayout.fPushConstant) { + return SpvStorageClassPushConstant; + } return SpvStorageClassUniform; } else { return SpvStorageClassFunction; @@ -1562,8 +1642,13 @@ SpvStorageClass_ get_storage_class(const Modifiers& modifiers) { SpvStorageClass_ get_storage_class(const Expression& expr) { switch (expr.fKind) { - case Expression::kVariableReference_Kind: - return get_storage_class(((VariableReference&) expr).fVariable.fModifiers); + case Expression::kVariableReference_Kind: { + const Variable& var = ((VariableReference&) expr).fVariable; + if (var.fStorage != Variable::kGlobal_Storage) { + return SpvStorageClassFunction; + } + return get_storage_class(var.fModifiers); + } case Expression::kFieldAccess_Kind: return get_storage_class(*((FieldAccess&) expr).fBase); case Expression::kIndex_Kind: @@ -1573,7 +1658,7 @@ SpvStorageClass_ get_storage_class(const Expression& expr) { } } -std::vector SPIRVCodeGenerator::getAccessChain(const Expression& expr, std::ostream& out) { +std::vector SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) { std::vector chain; switch (expr.fKind) { case Expression::kIndex_Kind: { @@ -1597,7 +1682,7 @@ std::vector SPIRVCodeGenerator::getAccessChain(const Expression& expr, st class PointerLValue : public SPIRVCodeGenerator::LValue { public: - PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type) + PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type) : fGen(gen) , fPointer(pointer) , fType(type) {} @@ -1606,13 +1691,13 @@ public: return fPointer; } - virtual SpvId load(std::ostream& out) override { + virtual SpvId load(OutputStream& out) override { SpvId result = fGen.nextId(); fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out); return result; } - virtual void store(SpvId value, std::ostream& out) override { + virtual void store(SpvId value, OutputStream& out) override { fGen.writeInstruction(SpvOpStore, fPointer, value, out); } @@ -1624,7 +1709,7 @@ private: class SwizzleLValue : public SPIRVCodeGenerator::LValue { public: - SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector& components, + SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector& components, const Type& baseType, const Type& swizzleType) : fGen(gen) , fVecPointer(vecPointer) @@ -1636,7 +1721,7 @@ public: return 0; } - virtual SpvId load(std::ostream& out) override { + virtual SpvId load(OutputStream& out) override { SpvId base = fGen.nextId(); fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out); SpvId result = fGen.nextId(); @@ -1651,15 +1736,15 @@ public: return result; } - virtual void store(SpvId value, std::ostream& out) override { + virtual void store(SpvId value, OutputStream& out) override { // use OpVectorShuffle to mix and match the vector components. We effectively create // a virtual vector out of the concatenation of the left and right vectors, and then - // select components from this virtual vector to make the result vector. For + // select components from this virtual vector to make the result vector. For // instance, given: // vec3 L = ...; // vec3 R = ...; // L.xz = R.xy; - // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want + // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want // our result vector to look like (R.x, L.y, R.y), so we need to select indices // (3, 1, 4). SpvId base = fGen.nextId(); @@ -1677,7 +1762,7 @@ public: // check to see if we are writing this component for (size_t j = 0; j < fComponents.size(); j++) { if (fComponents[j] == i) { - // we're writing to this component, so adjust the offset to pull from + // we're writing to this component, so adjust the offset to pull from // the correct component of the right side instead of preserving the // value from the left offset = (int) (j + fBaseType.columns()); @@ -1697,8 +1782,8 @@ private: const Type& fSwizzleType; }; -std::unique_ptr SPIRVCodeGenerator::getLValue(const Expression& expr, - std::ostream& out) { +std::unique_ptr SPIRVCodeGenerator::getLValue(const Expression& expr, + OutputStream& out) { switch (expr.fKind) { case Expression::kVariableReference_Kind: { const Variable& var = ((VariableReference&) expr).fVariable; @@ -1706,7 +1791,7 @@ std::unique_ptr SPIRVCodeGenerator::getLValue(const ASSERT(entry != fVariableMap.end()); return std::unique_ptr(new PointerLValue( *this, - entry->second, + entry->second, this->getType(expr.fType))); } case Expression::kIndex_Kind: // fall through @@ -1714,14 +1799,14 @@ std::unique_ptr SPIRVCodeGenerator::getLValue(const std::vector chain = this->getAccessChain(expr, out); SpvId member = this->nextId(); this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out); - this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out); + this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out); this->writeWord(member, out); for (SpvId idx : chain) { this->writeWord(idx, out); } return std::unique_ptr(new PointerLValue( *this, - member, + member, this->getType(expr.fType))); } @@ -1734,21 +1819,21 @@ std::unique_ptr SPIRVCodeGenerator::getLValue(const IntLiteral index(fContext, Position(), swizzle.fComponents[0]); SpvId member = this->nextId(); this->writeInstruction(SpvOpAccessChain, - this->getPointerType(swizzle.fType, - get_storage_class(*swizzle.fBase)), - member, - base, - this->writeIntLiteral(index), + this->getPointerType(swizzle.fType, + get_storage_class(*swizzle.fBase)), + member, + base, + this->writeIntLiteral(index), out); return std::unique_ptr(new PointerLValue( *this, - member, + member, this->getType(expr.fType))); } else { return std::unique_ptr(new SwizzleLValue( - *this, - base, - swizzle.fComponents, + *this, + base, + swizzle.fComponents, swizzle.fBase->fType, expr.fType)); } @@ -1756,7 +1841,7 @@ std::unique_ptr SPIRVCodeGenerator::getLValue(const default: // expr isn't actually an lvalue, create a dummy variable for it. This case happens due - // to the need to store values in temporary variables during function calls (see + // to the need to store values in temporary variables during function calls (see // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been // caught by IRGenerator SpvId result = this->nextId(); @@ -1766,35 +1851,97 @@ std::unique_ptr SPIRVCodeGenerator::getLValue(const this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out); return std::unique_ptr(new PointerLValue( *this, - result, + result, this->getType(expr.fType))); } } -SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) { + SpvId result = this->nextId(); auto entry = fVariableMap.find(&ref.fVariable); ASSERT(entry != fVariableMap.end()); SpvId var = entry->second; - SpvId result = this->nextId(); this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out); + if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN && + fProgram.fSettings.fFlipY) { + // need to remap to a top-left coordinate system + if (fRTHeightStructId == (SpvId) -1) { + // height variable hasn't been written yet + std::shared_ptr st(new SymbolTable(&fErrors)); + ASSERT(fRTHeightFieldIndex == (SpvId) -1); + std::vector fields; + fields.emplace_back(Modifiers(), String(SKSL_RTHEIGHT_NAME), + fContext.fFloat_Type.get()); + String name("sksl_synthetic_uniforms"); + Type intfStruct(Position(), name, fields); + Layout layout(-1, -1, 1, -1, -1, -1, -1, false, false, false, + Layout::Format::kUnspecified, false, Layout::kUnspecified_Primitive, -1, + -1); + Variable* intfVar = new Variable(Position(), + Modifiers(layout, Modifiers::kUniform_Flag), + name, + intfStruct, + Variable::kGlobal_Storage); + fSynthetics.takeOwnership(intfVar); + InterfaceBlock intf(Position(), intfVar, name, String(""), + std::vector>(), st); + fRTHeightStructId = this->writeInterfaceBlock(intf); + fRTHeightFieldIndex = 0; + } + ASSERT(fRTHeightFieldIndex != (SpvId) -1); + // write vec4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, 1.0) + SpvId xId = this->nextId(); + this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId, + result, 0, out); + IntLiteral fieldIndex(fContext, Position(), fRTHeightFieldIndex); + SpvId fieldIndexId = this->writeIntLiteral(fieldIndex); + SpvId heightPtr = this->nextId(); + this->writeOpCode(SpvOpAccessChain, 5, out); + this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out); + this->writeWord(heightPtr, out); + this->writeWord(fRTHeightStructId, out); + this->writeWord(fieldIndexId, out); + SpvId heightRead = this->nextId(); + this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead, + heightPtr, out); + SpvId rawYId = this->nextId(); + this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId, + result, 1, out); + SpvId flippedYId = this->nextId(); + this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId, + heightRead, rawYId, out); + FloatLiteral zero(fContext, Position(), 0.0); + SpvId zeroId = writeFloatLiteral(zero); + FloatLiteral one(fContext, Position(), 1.0); + SpvId oneId = writeFloatLiteral(one); + SpvId flipped = this->nextId(); + this->writeOpCode(SpvOpCompositeConstruct, 7, out); + this->writeWord(this->getType(*fContext.fVec4_Type), out); + this->writeWord(flipped, out); + this->writeWord(xId, out); + this->writeWord(flippedYId, out); + this->writeWord(zeroId, out); + this->writeWord(oneId, out); + return flipped; + } return result; } -SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) { return getLValue(expr, out)->load(out); } -SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) { return getLValue(f, out)->load(out); } -SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) { SpvId base = this->writeExpression(*swizzle.fBase, out); SpvId result = this->nextId(); size_t count = swizzle.fComponents.size(); if (count == 1) { - this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base, - swizzle.fComponents[0], out); + this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base, + swizzle.fComponents[0], out); } else { this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out); this->writeWord(this->getType(swizzle.fType), out); @@ -1808,10 +1955,10 @@ SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, std::ostream& out return result; } -SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType, - const Type& operandType, SpvId lhs, - SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, - SpvOp_ ifUInt, SpvOp_ ifBool, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType, + const Type& operandType, SpvId lhs, + SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, + SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) { SpvId result = this->nextId(); if (is_float(fContext, operandType)) { this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out); @@ -1849,7 +1996,16 @@ bool is_assignment(Token::Kind op) { } } -SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std::ostream& out) { +SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, OutputStream& out) { + if (operandType.kind() == Type::kVector_Kind) { + SpvId result = this->nextId(); + this->writeInstruction(SpvOpAll, this->getType(*fContext.fBool_Type), result, id, out); + return result; + } + return id; +} + +SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) { // handle cases where we don't necessarily evaluate both LHS and RHS switch (b.fOperator) { case Token::EQ: { @@ -1882,7 +2038,7 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std:: // IR allows mismatched types in expressions (e.g. vec2 * float), but they need special handling // in SPIR-V if (b.fLeft->fType != b.fRight->fType) { - if (b.fLeft->fType.kind() == Type::kVector_Kind && + if (b.fLeft->fType.kind() == Type::kVector_Kind && b.fRight->fType.isNumber()) { // promote number to vector SpvId vec = this->nextId(); @@ -1894,7 +2050,7 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std:: } rhs = vec; operandType = &b.fRight->fType; - } else if (b.fRight->fType.kind() == Type::kVector_Kind && + } else if (b.fRight->fType.kind() == Type::kVector_Kind && b.fLeft->fType.isNumber()) { // promote number to vector SpvId vec = this->nextId(); @@ -1928,11 +2084,11 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std:: } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) { SpvId result = this->nextId(); if (b.fLeft->fType.kind() == Type::kVector_Kind) { - this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result, + this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result, lhs, rhs, out); } else { ASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind); - this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs, + this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs, lhs, out); } if (b.fOperator == Token::STAREQ) { @@ -1949,42 +2105,47 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std:: ASSERT(*operandType == b.fRight->fType); } switch (b.fOperator) { - case Token::EQEQ: + case Token::EQEQ: { ASSERT(resultType == *fContext.fBool_Type); - return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdEqual, - SpvOpIEqual, SpvOpIEqual, SpvOpLogicalEqual, out); + return this->foldToBool(this->writeBinaryOperation(resultType, *operandType, lhs, rhs, + SpvOpFOrdEqual, SpvOpIEqual, + SpvOpIEqual, SpvOpLogicalEqual, out), + *operandType, out); + } case Token::NEQ: ASSERT(resultType == *fContext.fBool_Type); - return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdNotEqual, - SpvOpINotEqual, SpvOpINotEqual, SpvOpLogicalNotEqual, - out); + return this->foldToBool(this->writeBinaryOperation(resultType, *operandType, lhs, rhs, + SpvOpFOrdNotEqual, SpvOpINotEqual, + SpvOpINotEqual, SpvOpLogicalNotEqual, + out), + *operandType, out); case Token::GT: ASSERT(resultType == *fContext.fBool_Type); - return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, - SpvOpFOrdGreaterThan, SpvOpSGreaterThan, + return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, + SpvOpFOrdGreaterThan, SpvOpSGreaterThan, SpvOpUGreaterThan, SpvOpUndef, out); case Token::LT: ASSERT(resultType == *fContext.fBool_Type); - return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan, + return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan, SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out); case Token::GTEQ: ASSERT(resultType == *fContext.fBool_Type); - return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, - SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual, + return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, + SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual, SpvOpUGreaterThanEqual, SpvOpUndef, out); case Token::LTEQ: ASSERT(resultType == *fContext.fBool_Type); - return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, - SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual, + return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, + SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual, SpvOpULessThanEqual, SpvOpUndef, out); case Token::PLUS: - return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd, + return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out); case Token::MINUS: - return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub, + return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef, out); case Token::STAR: - if (b.fLeft->fType.kind() == Type::kMatrix_Kind && + if (b.fLeft->fType.kind() == Type::kMatrix_Kind && b.fRight->fType.kind() == Type::kMatrix_Kind) { // matrix multiply SpvId result = this->nextId(); @@ -1992,27 +2153,27 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std:: lhs, rhs, out); return result; } - return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul, + return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul, SpvOpIMul, SpvOpIMul, SpvOpUndef, out); case Token::SLASH: - return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv, + return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv, SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out); case Token::PLUSEQ: { - SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd, + SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out); ASSERT(lvalue); lvalue->store(result, out); return result; } case Token::MINUSEQ: { - SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub, + SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef, out); ASSERT(lvalue); lvalue->store(result, out); return result; } case Token::STAREQ: { - if (b.fLeft->fType.kind() == Type::kMatrix_Kind && + if (b.fLeft->fType.kind() == Type::kMatrix_Kind && b.fRight->fType.kind() == Type::kMatrix_Kind) { // matrix multiply SpvId result = this->nextId(); @@ -2022,14 +2183,14 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std:: lvalue->store(result, out); return result; } - SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul, + SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul, SpvOpIMul, SpvOpIMul, SpvOpUndef, out); ASSERT(lvalue); lvalue->store(result, out); return result; } case Token::SLASHEQ: { - SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv, + SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv, SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out); ASSERT(lvalue); lvalue->store(result, out); @@ -2041,7 +2202,7 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std:: } } -SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) { ASSERT(a.fOperator == Token::LOGICALAND); BoolLiteral falseLiteral(fContext, Position(), false); SpvId falseConstant = this->writeBoolLiteral(falseLiteral); @@ -2057,12 +2218,12 @@ SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, std::ostrea this->writeInstruction(SpvOpBranch, end, out); this->writeLabel(end, out); SpvId result = this->nextId(); - this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant, + this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant, lhsBlock, rhs, rhsBlock, out); return result; } -SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) { ASSERT(o.fOperator == Token::LOGICALOR); BoolLiteral trueLiteral(fContext, Position(), true); SpvId trueConstant = this->writeBoolLiteral(trueLiteral); @@ -2078,26 +2239,26 @@ SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, std::ostream this->writeInstruction(SpvOpBranch, end, out); this->writeLabel(end, out); SpvId result = this->nextId(); - this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant, + this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant, lhsBlock, rhs, rhsBlock, out); return result; } -SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) { SpvId test = this->writeExpression(*t.fTest, out); if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) { // both true and false are constants, can just use OpSelect SpvId result = this->nextId(); SpvId trueId = this->writeExpression(*t.fIfTrue, out); SpvId falseId = this->writeExpression(*t.fIfFalse, out); - this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId, + this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId, out); return result; } - // was originally using OpPhi to choose the result, but for some reason that is crashing on + // was originally using OpPhi to choose the result, but for some reason that is crashing on // Adreno. Switched to storing the result in a temp variable as glslang does. SpvId var = this->nextId(); - this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction), + this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction), var, SpvStorageClassFunction, fVariableBuffer); SpvId trueLabel = this->nextId(); SpvId falseLabel = this->nextId(); @@ -2123,11 +2284,11 @@ std::unique_ptr create_literal_1(const Context& context, const Type& else if (type == *context.fFloat_Type) { return std::unique_ptr(new FloatLiteral(context, Position(), 1.0)); } else { - ABORT("math is unsupported on type '%s'") + ABORT("math is unsupported on type '%s'", type.name().c_str()); } } -SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, std::ostream& out) { +SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) { if (p.fOperator == Token::MINUS) { SpvId result = this->nextId(); SpvId typeId = this->getType(p.fType); @@ -2147,8 +2308,8 @@ SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, std:: case Token::PLUSPLUS: { std::unique_ptr lv = this->getLValue(*p.fOperand, out); SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out); - SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one, - SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef, + SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one, + SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out); lv->store(result, out); return result; @@ -2156,37 +2317,43 @@ SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, std:: case Token::MINUSMINUS: { std::unique_ptr lv = this->getLValue(*p.fOperand, out); SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out); - SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one, - SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef, + SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one, + SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef, out); lv->store(result, out); return result; } - case Token::NOT: { + case Token::LOGICALNOT: { ASSERT(p.fOperand->fType == *fContext.fBool_Type); SpvId result = this->nextId(); this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result, this->writeExpression(*p.fOperand, out), out); return result; } + case Token::BITWISENOT: { + SpvId result = this->nextId(); + this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result, + this->writeExpression(*p.fOperand, out), out); + return result; + } default: ABORT("unsupported prefix expression: %s", p.description().c_str()); } } -SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, std::ostream& out) { +SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) { std::unique_ptr lv = this->getLValue(*p.fOperand, out); SpvId result = lv->load(out); SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out); switch (p.fOperator) { case Token::PLUSPLUS: { - SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd, + SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out); lv->store(temp, out); return result; } case Token::MINUSMINUS: { - SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub, + SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef, out); lv->store(temp, out); return result; @@ -2200,14 +2367,14 @@ SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) { if (b.fValue) { if (fBoolTrue == 0) { fBoolTrue = this->nextId(); - this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue, + this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue, fConstantBuffer); } return fBoolTrue; } else { if (fBoolFalse == 0) { fBoolFalse = this->nextId(); - this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse, + this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse, fConstantBuffer); } return fBoolFalse; @@ -2219,7 +2386,7 @@ SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) { auto entry = fIntConstants.find(i.fValue); if (entry == fIntConstants.end()) { SpvId result = this->nextId(); - this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue, + this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue, fConstantBuffer); fIntConstants[i.fValue] = result; return result; @@ -2230,7 +2397,7 @@ SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) { auto entry = fUIntConstants.find(i.fValue); if (entry == fUIntConstants.end()) { SpvId result = this->nextId(); - this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue, + this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue, fConstantBuffer); fUIntConstants[i.fValue] = result; return result; @@ -2248,7 +2415,7 @@ SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) { uint32_t bits; ASSERT(sizeof(bits) == sizeof(value)); memcpy(&bits, &value, sizeof(bits)); - this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits, + this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits, fConstantBuffer); fFloatConstants[value] = result; return result; @@ -2262,7 +2429,7 @@ SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) { uint64_t bits; ASSERT(sizeof(bits) == sizeof(f.fValue)); memcpy(&bits, &f.fValue, sizeof(bits)); - this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, + this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits & 0xffffffff, bits >> 32, fConstantBuffer); fDoubleConstants[f.fValue] = result; return result; @@ -2271,9 +2438,9 @@ SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) { } } -SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) { SpvId result = fFunctionMap[&f]; - this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result, + this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result, SpvFunctionControlMaskNone, this->getFunctionType(f), out); this->writeInstruction(SpvOpName, result, f.fName.c_str(), fNameBuffer); for (size_t i = 0; i < f.fParameters.size(); i++) { @@ -2286,17 +2453,17 @@ SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, std:: return result; } -SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, std::ostream& out) { +SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) { + fVariableBuffer.reset(); SpvId result = this->writeFunctionStart(f.fDeclaration, out); this->writeLabel(this->nextId(), out); if (f.fDeclaration.fName == "main") { - out << fGlobalInitializersBuffer.str(); + write_stringstream(fGlobalInitializersBuffer, out); } - std::stringstream bodyBuffer; + StringStream bodyBuffer; this->writeBlock(*f.fBody, bodyBuffer); - out << fVariableBuffer.str(); - fVariableBuffer.str(""); - out << bodyBuffer.str(); + write_stringstream(fVariableBuffer, out); + write_stringstream(bodyBuffer, out); if (fCurrentBlock) { this->writeInstruction(SpvOpReturn, out); } @@ -2306,68 +2473,108 @@ SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, std::ostrea void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) { if (layout.fLocation >= 0) { - this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation, + this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation, fDecorationBuffer); } if (layout.fBinding >= 0) { - this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding, + this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding, fDecorationBuffer); } if (layout.fIndex >= 0) { - this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex, + this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex, fDecorationBuffer); } if (layout.fSet >= 0) { - this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet, + this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet, fDecorationBuffer); } - if (layout.fBuiltin >= 0) { - this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin, + if (layout.fInputAttachmentIndex >= 0) { + this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex, + layout.fInputAttachmentIndex, fDecorationBuffer); + } + if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN) { + this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin, fDecorationBuffer); } } void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) { if (layout.fLocation >= 0) { - this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation, + this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation, layout.fLocation, fDecorationBuffer); } if (layout.fBinding >= 0) { - this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding, + this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding, layout.fBinding, fDecorationBuffer); } if (layout.fIndex >= 0) { - this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex, + this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex, layout.fIndex, fDecorationBuffer); } if (layout.fSet >= 0) { - this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet, + this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet, layout.fSet, fDecorationBuffer); } + if (layout.fInputAttachmentIndex >= 0) { + this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex, + layout.fInputAttachmentIndex, fDecorationBuffer); + } if (layout.fBuiltin >= 0) { - this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn, + this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn, layout.fBuiltin, fDecorationBuffer); } } SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { - SpvId type = this->getType(intf.fVariable.fType); + MemoryLayout layout = intf.fVariable.fModifiers.fLayout.fPushConstant ? + MemoryLayout(MemoryLayout::k430_Standard) : + fDefaultLayout; SpvId result = this->nextId(); - this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer); + const Type* type = &intf.fVariable.fType; + if (fProgram.fInputs.fRTHeight) { + ASSERT(fRTHeightStructId == (SpvId) -1); + ASSERT(fRTHeightFieldIndex == (SpvId) -1); + std::vector fields = type->fields(); + fRTHeightStructId = result; + fRTHeightFieldIndex = fields.size(); + fields.emplace_back(Modifiers(), String(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get()); + type = new Type(type->fPosition, type->name(), fields); + } + SpvId typeId = this->getType(*type, layout); + this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer); SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers); SpvId ptrType = this->nextId(); - this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, type, fConstantBuffer); + this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer); this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer); this->writeLayout(intf.fVariable.fModifiers.fLayout, result); fVariableMap[&intf.fVariable] = result; + if (fProgram.fInputs.fRTHeight) { + delete type; + } return result; } -void SPIRVCodeGenerator::writeGlobalVars(const VarDeclarations& decl, std::ostream& out) { +#define BUILTIN_IGNORE 9999 +void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl, + OutputStream& out) { for (size_t i = 0; i < decl.fVars.size(); i++) { const VarDeclaration& varDecl = decl.fVars[i]; const Variable* var = varDecl.fVar; - if (!var->fIsReadFrom && !var->fIsWrittenTo && + // These haven't been implemented in our SPIR-V generator yet and we only currently use them + // in the OpenGL backend. + ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag | + Modifiers::kWriteOnly_Flag | + Modifiers::kCoherent_Flag | + Modifiers::kVolatile_Flag | + Modifiers::kRestrict_Flag))); + if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) { + continue; + } + if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN && + kind != Program::kFragment_Kind) { + continue; + } + if (!var->fReadCount && !var->fWriteCount && !(var->fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag))) { @@ -2395,10 +2602,10 @@ void SPIRVCodeGenerator::writeGlobalVars(const VarDeclarations& decl, std::ostre this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer); this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer); if (var->fType.kind() == Type::kMatrix_Kind) { - this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationColMajor, + this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationColMajor, fDecorationBuffer); - this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationMatrixStride, - (SpvId) var->fType.stride(), fDecorationBuffer); + this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationMatrixStride, + (SpvId) fDefaultLayout.stride(var->fType), fDecorationBuffer); } if (varDecl.fValue) { ASSERT(!fCurrentBlock); @@ -2411,9 +2618,16 @@ void SPIRVCodeGenerator::writeGlobalVars(const VarDeclarations& decl, std::ostre } } -void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, std::ostream& out) { +void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) { for (const auto& varDecl : decl.fVars) { const Variable* var = varDecl.fVar; + // These haven't been implemented in our SPIR-V generator yet and we only currently use them + // in the OpenGL backend. + ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag | + Modifiers::kWriteOnly_Flag | + Modifiers::kCoherent_Flag | + Modifiers::kVolatile_Flag | + Modifiers::kRestrict_Flag))); SpvId id = this->nextId(); fVariableMap[var] = id; SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction); @@ -2426,7 +2640,7 @@ void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, std:: } } -void SPIRVCodeGenerator::writeStatement(const Statement& s, std::ostream& out) { +void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) { switch (s.fKind) { case Statement::kBlock_Kind: this->writeBlock((Block&) s, out); @@ -2434,7 +2648,7 @@ void SPIRVCodeGenerator::writeStatement(const Statement& s, std::ostream& out) { case Statement::kExpression_Kind: this->writeExpression(*((ExpressionStatement&) s).fExpression, out); break; - case Statement::kReturn_Kind: + case Statement::kReturn_Kind: this->writeReturnStatement((ReturnStatement&) s, out); break; case Statement::kVarDeclarations_Kind: @@ -2446,6 +2660,12 @@ void SPIRVCodeGenerator::writeStatement(const Statement& s, std::ostream& out) { case Statement::kFor_Kind: this->writeForStatement((ForStatement&) s, out); break; + case Statement::kWhile_Kind: + this->writeWhileStatement((WhileStatement&) s, out); + break; + case Statement::kDo_Kind: + this->writeDoStatement((DoStatement&) s, out); + break; case Statement::kBreak_Kind: this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out); break; @@ -2460,13 +2680,13 @@ void SPIRVCodeGenerator::writeStatement(const Statement& s, std::ostream& out) { } } -void SPIRVCodeGenerator::writeBlock(const Block& b, std::ostream& out) { +void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) { for (size_t i = 0; i < b.fStatements.size(); i++) { this->writeStatement(*b.fStatements[i], out); } } -void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, std::ostream& out) { +void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) { SpvId test = this->writeExpression(*stmt.fTest, out); SpvId ifTrue = this->nextId(); SpvId ifFalse = this->nextId(); @@ -2497,7 +2717,7 @@ void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, std::ostream& } } -void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, std::ostream& out) { +void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) { if (f.fInitializer) { this->writeStatement(*f.fInitializer, out); } @@ -2513,8 +2733,10 @@ void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, std::ostream& this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out); this->writeInstruction(SpvOpBranch, start, out); this->writeLabel(start, out); - SpvId test = this->writeExpression(*f.fTest, out); - this->writeInstruction(SpvOpBranchConditional, test, body, end, out); + if (f.fTest) { + SpvId test = this->writeExpression(*f.fTest, out); + this->writeInstruction(SpvOpBranchConditional, test, body, end, out); + } this->writeLabel(body, out); this->writeStatement(*f.fStatement, out); if (fCurrentBlock) { @@ -2530,19 +2752,83 @@ void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, std::ostream& fContinueTarget.pop(); } -void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, std::ostream& out) { +void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) { + // We believe the while loop code below will work, but Skia doesn't actually use them and + // adequately testing this code in the absence of Skia exercising it isn't straightforward. For + // the time being, we just fail with an error due to the lack of testing. If you encounter this + // message, simply remove the error call below to see whether our while loop support actually + // works. + fErrors.error(w.fPosition, "internal error: while loop support has been disabled in SPIR-V, " + "see SkSLSPIRVCodeGenerator.cpp for details"); + + SpvId header = this->nextId(); + SpvId start = this->nextId(); + SpvId body = this->nextId(); + fContinueTarget.push(start); + SpvId end = this->nextId(); + fBreakTarget.push(end); + this->writeInstruction(SpvOpBranch, header, out); + this->writeLabel(header, out); + this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out); + this->writeInstruction(SpvOpBranch, start, out); + this->writeLabel(start, out); + SpvId test = this->writeExpression(*w.fTest, out); + this->writeInstruction(SpvOpBranchConditional, test, body, end, out); + this->writeLabel(body, out); + this->writeStatement(*w.fStatement, out); + if (fCurrentBlock) { + this->writeInstruction(SpvOpBranch, start, out); + } + this->writeLabel(end, out); + fBreakTarget.pop(); + fContinueTarget.pop(); +} + +void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) { + // We believe the do loop code below will work, but Skia doesn't actually use them and + // adequately testing this code in the absence of Skia exercising it isn't straightforward. For + // the time being, we just fail with an error due to the lack of testing. If you encounter this + // message, simply remove the error call below to see whether our do loop support actually + // works. + fErrors.error(d.fPosition, "internal error: do loop support has been disabled in SPIR-V, see " + "SkSLSPIRVCodeGenerator.cpp for details"); + + SpvId header = this->nextId(); + SpvId start = this->nextId(); + SpvId next = this->nextId(); + fContinueTarget.push(next); + SpvId end = this->nextId(); + fBreakTarget.push(end); + this->writeInstruction(SpvOpBranch, header, out); + this->writeLabel(header, out); + this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out); + this->writeInstruction(SpvOpBranch, start, out); + this->writeLabel(start, out); + this->writeStatement(*d.fStatement, out); + if (fCurrentBlock) { + this->writeInstruction(SpvOpBranch, next, out); + } + this->writeLabel(next, out); + SpvId test = this->writeExpression(*d.fTest, out); + this->writeInstruction(SpvOpBranchConditional, test, start, end, out); + this->writeLabel(end, out); + fBreakTarget.pop(); + fContinueTarget.pop(); +} + +void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) { if (r.fExpression) { - this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out), + this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out), out); } else { this->writeInstruction(SpvOpReturn, out); } } -void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream& out) { +void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) { fGLSLExtendedInstructions = this->nextId(); - std::stringstream body; - std::vector interfaceVars; + StringStream body; + std::set interfaceVars; // assign IDs to functions for (size_t i = 0; i < program.fElements.size(); i++) { if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) { @@ -2556,13 +2842,14 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream& SpvId id = this->writeInterfaceBlock(intf); if ((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) || (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) { - interfaceVars.push_back(id); + interfaceVars.insert(id); } } } for (size_t i = 0; i < program.fElements.size(); i++) { if (program.fElements[i]->fKind == ProgramElement::kVar_Kind) { - this->writeGlobalVars(((VarDeclarations&) *program.fElements[i]), body); + this->writeGlobalVars(program.fKind, ((VarDeclarations&) *program.fElements[i]), + body); } } for (size_t i = 0; i < program.fElements.size(); i++) { @@ -2579,16 +2866,16 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream& ASSERT(main); for (auto entry : fVariableMap) { const Variable* var = entry.first; - if (var->fStorage == Variable::kGlobal_Storage && + if (var->fStorage == Variable::kGlobal_Storage && ((var->fModifiers.fFlags & Modifiers::kIn_Flag) || (var->fModifiers.fFlags & Modifiers::kOut_Flag))) { - interfaceVars.push_back(entry.second); + interfaceVars.insert(entry.second); } } this->writeCapabilities(out); this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out); this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out); - this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (strlen(main->fName.c_str()) + 4) / 4) + + this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (strlen(main->fName.c_str()) + 4) / 4) + (int32_t) interfaceVars.size(), out); switch (program.fKind) { case Program::kVertex_Kind: @@ -2597,6 +2884,9 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream& case Program::kFragment_Kind: this->writeWord(SpvExecutionModelFragment, out); break; + case Program::kGeometry_Kind: + this->writeWord(SpvExecutionModelGeometry, out); + break; } this->writeWord(fFunctionMap[main], out); this->writeString(main->fName.c_str(), out); @@ -2604,35 +2894,38 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream& this->writeWord(var, out); } if (program.fKind == Program::kFragment_Kind) { - this->writeInstruction(SpvOpExecutionMode, - fFunctionMap[main], + this->writeInstruction(SpvOpExecutionMode, + fFunctionMap[main], SpvExecutionModeOriginUpperLeft, out); } for (size_t i = 0; i < program.fElements.size(); i++) { if (program.fElements[i]->fKind == ProgramElement::kExtension_Kind) { - this->writeInstruction(SpvOpSourceExtension, - ((Extension&) *program.fElements[i]).fName.c_str(), + this->writeInstruction(SpvOpSourceExtension, + ((Extension&) *program.fElements[i]).fName.c_str(), out); } } - - out << fNameBuffer.str(); - out << fDecorationBuffer.str(); - out << fConstantBuffer.str(); - out << fExternalFunctionsBuffer.str(); - out << body.str(); + + write_stringstream(fExtraGlobalsBuffer, out); + write_stringstream(fNameBuffer, out); + write_stringstream(fDecorationBuffer, out); + write_stringstream(fConstantBuffer, out); + write_stringstream(fExternalFunctionsBuffer, out); + write_stringstream(body, out); } -void SPIRVCodeGenerator::generateCode(const Program& program, std::ostream& out) { - this->writeWord(SpvMagicNumber, out); - this->writeWord(SpvVersion, out); - this->writeWord(SKSL_MAGIC, out); - std::stringstream buffer; - this->writeInstructions(program, buffer); - this->writeWord(fIdCount, out); - this->writeWord(0, out); // reserved, always zero - out << buffer.str(); +bool SPIRVCodeGenerator::generateCode() { + ASSERT(!fErrors.errorCount()); + this->writeWord(SpvMagicNumber, *fOut); + this->writeWord(SpvVersion, *fOut); + this->writeWord(SKSL_MAGIC, *fOut); + StringStream buffer; + this->writeInstructions(fProgram, buffer); + this->writeWord(fIdCount, *fOut); + this->writeWord(0, *fOut); // reserved, always zero + write_stringstream(buffer, *fOut); + return 0 == fErrors.errorCount(); } } diff --git a/gfx/skia/skia/src/sksl/SkSLSPIRVCodeGenerator.h b/gfx/skia/skia/src/sksl/SkSLSPIRVCodeGenerator.h index e7b2b30232ad..84a4c1ff6a99 100644 --- a/gfx/skia/skia/src/sksl/SkSLSPIRVCodeGenerator.h +++ b/gfx/skia/skia/src/sksl/SkSLSPIRVCodeGenerator.h @@ -4,19 +4,20 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_SPIRVCODEGENERATOR #define SKSL_SPIRVCODEGENERATOR -#include #include #include #include #include "SkSLCodeGenerator.h" +#include "SkSLMemoryLayout.h" #include "ir/SkSLBinaryExpression.h" #include "ir/SkSLBoolLiteral.h" #include "ir/SkSLConstructor.h" +#include "ir/SkSLDoStatement.h" #include "ir/SkSLFloatLiteral.h" #include "ir/SkSLIfStatement.h" #include "ir/SkSLIndexExpression.h" @@ -34,9 +35,10 @@ #include "ir/SkSLStatement.h" #include "ir/SkSLSwizzle.h" #include "ir/SkSLTernaryExpression.h" -#include "ir/SkSLVarDeclaration.h" -#include "ir/SkSLVarDeclarationStatement.h" +#include "ir/SkSLVarDeclarations.h" +#include "ir/SkSLVarDeclarationsStatement.h" #include "ir/SkSLVariableReference.h" +#include "ir/SkSLWhileStatement.h" #include "spirv.h" namespace SkSL { @@ -51,27 +53,32 @@ public: class LValue { public: virtual ~LValue() {} - + // returns a pointer to the lvalue, if possible. If the lvalue cannot be directly referenced // by a pointer (e.g. vector swizzles), returns 0. virtual SpvId getPointer() = 0; - virtual SpvId load(std::ostream& out) = 0; + virtual SpvId load(OutputStream& out) = 0; - virtual void store(SpvId value, std::ostream& out) = 0; + virtual void store(SpvId value, OutputStream& out) = 0; }; - SPIRVCodeGenerator(const Context* context) - : fContext(*context) + SPIRVCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors, + OutputStream* out) + : INHERITED(program, errors, out) + , fContext(*context) + , fDefaultLayout(MemoryLayout::k140_Standard) , fCapabilities(1 << SpvCapabilityShader) , fIdCount(1) , fBoolTrue(0) , fBoolFalse(0) - , fCurrentBlock(0) { + , fSetupFragPosition(false) + , fCurrentBlock(0) + , fSynthetics(nullptr, errors) { this->setupIntrinsics(); } - void generateCode(const Program& program, std::ostream& out) override; + bool generateCode() override; private: enum IntrinsicKind { @@ -83,8 +90,7 @@ private: enum SpecialIntrinsic { kAtan_SpecialIntrinsic, kTexture_SpecialIntrinsic, - kTexture2D_SpecialIntrinsic, - kTextureProj_SpecialIntrinsic + kSubpassLoad_SpecialIntrinsic, }; void setupIntrinsics(); @@ -93,80 +99,107 @@ private: SpvId getType(const Type& type); + SpvId getType(const Type& type, const MemoryLayout& layout); + SpvId getFunctionType(const FunctionDeclaration& function); SpvId getPointerType(const Type& type, SpvStorageClass_ storageClass); - std::vector getAccessChain(const Expression& expr, std::ostream& out); + SpvId getPointerType(const Type& type, const MemoryLayout& layout, + SpvStorageClass_ storageClass); + + std::vector getAccessChain(const Expression& expr, OutputStream& out); void writeLayout(const Layout& layout, SpvId target); void writeLayout(const Layout& layout, SpvId target, int member); - void writeStruct(const Type& type, SpvId resultId); + void writeStruct(const Type& type, const MemoryLayout& layout, SpvId resultId); - void writeProgramElement(const ProgramElement& pe, std::ostream& out); + void writeProgramElement(const ProgramElement& pe, OutputStream& out); SpvId writeInterfaceBlock(const InterfaceBlock& intf); - SpvId writeFunctionStart(const FunctionDeclaration& f, std::ostream& out); - - SpvId writeFunctionDeclaration(const FunctionDeclaration& f, std::ostream& out); + SpvId writeFunctionStart(const FunctionDeclaration& f, OutputStream& out); - SpvId writeFunction(const FunctionDefinition& f, std::ostream& out); + SpvId writeFunctionDeclaration(const FunctionDeclaration& f, OutputStream& out); - void writeGlobalVars(const VarDeclarations& v, std::ostream& out); + SpvId writeFunction(const FunctionDefinition& f, OutputStream& out); - void writeVarDeclarations(const VarDeclarations& decl, std::ostream& out); + void writeGlobalVars(Program::Kind kind, const VarDeclarations& v, OutputStream& out); - SpvId writeVariableReference(const VariableReference& ref, std::ostream& out); + void writeVarDeclarations(const VarDeclarations& decl, OutputStream& out); - std::unique_ptr getLValue(const Expression& value, std::ostream& out); + SpvId writeVariableReference(const VariableReference& ref, OutputStream& out); - SpvId writeExpression(const Expression& expr, std::ostream& out); - - SpvId writeIntrinsicCall(const FunctionCall& c, std::ostream& out); + std::unique_ptr getLValue(const Expression& value, OutputStream& out); - SpvId writeFunctionCall(const FunctionCall& c, std::ostream& out); + SpvId writeExpression(const Expression& expr, OutputStream& out); - SpvId writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, std::ostream& out); + SpvId writeIntrinsicCall(const FunctionCall& c, OutputStream& out); + + SpvId writeFunctionCall(const FunctionCall& c, OutputStream& out); + + SpvId writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, OutputStream& out); SpvId writeConstantVector(const Constructor& c); - SpvId writeFloatConstructor(const Constructor& c, std::ostream& out); + SpvId writeFloatConstructor(const Constructor& c, OutputStream& out); - SpvId writeIntConstructor(const Constructor& c, std::ostream& out); - - SpvId writeMatrixConstructor(const Constructor& c, std::ostream& out); + SpvId writeIntConstructor(const Constructor& c, OutputStream& out); - SpvId writeVectorConstructor(const Constructor& c, std::ostream& out); + /** + * Writes a matrix with the diagonal entries all equal to the provided expression, and all other + * entries equal to zero. + */ + void writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type, OutputStream& out); - SpvId writeConstructor(const Constructor& c, std::ostream& out); + /** + * Writes a potentially-different-sized copy of a matrix. Entries which do not exist in the + * source matrix are filled with zero; entries which do not exist in the destination matrix are + * ignored. + */ + void writeMatrixCopy(SpvId id, SpvId src, const Type& srcType, const Type& dstType, + OutputStream& out); - SpvId writeFieldAccess(const FieldAccess& f, std::ostream& out); + SpvId writeMatrixConstructor(const Constructor& c, OutputStream& out); - SpvId writeSwizzle(const Swizzle& swizzle, std::ostream& out); + SpvId writeVectorConstructor(const Constructor& c, OutputStream& out); - SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs, - SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt, - SpvOp_ ifBool, std::ostream& out); + SpvId writeConstructor(const Constructor& c, OutputStream& out); - SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt, - SpvOp_ ifUInt, std::ostream& out); + SpvId writeFieldAccess(const FieldAccess& f, OutputStream& out); - SpvId writeBinaryExpression(const BinaryExpression& b, std::ostream& out); + SpvId writeSwizzle(const Swizzle& swizzle, OutputStream& out); - SpvId writeTernaryExpression(const TernaryExpression& t, std::ostream& out); + /** + * Folds the potentially-vector result of a logical operation down to a single bool. If + * operandType is a vector type, assumes that the intermediate result in id is a bvec of the + * same dimensions, and applys all() to it to fold it down to a single bool value. Otherwise, + * returns the original id value. + */ + SpvId foldToBool(SpvId id, const Type& operandType, OutputStream& out); - SpvId writeIndexExpression(const IndexExpression& expr, std::ostream& out); + SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs, + SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt, + SpvOp_ ifBool, OutputStream& out); - SpvId writeLogicalAnd(const BinaryExpression& b, std::ostream& out); + SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt, + SpvOp_ ifUInt, OutputStream& out); - SpvId writeLogicalOr(const BinaryExpression& o, std::ostream& out); + SpvId writeBinaryExpression(const BinaryExpression& b, OutputStream& out); - SpvId writePrefixExpression(const PrefixExpression& p, std::ostream& out); + SpvId writeTernaryExpression(const TernaryExpression& t, OutputStream& out); - SpvId writePostfixExpression(const PostfixExpression& p, std::ostream& out); + SpvId writeIndexExpression(const IndexExpression& expr, OutputStream& out); + + SpvId writeLogicalAnd(const BinaryExpression& b, OutputStream& out); + + SpvId writeLogicalOr(const BinaryExpression& o, OutputStream& out); + + SpvId writePrefixExpression(const PrefixExpression& p, OutputStream& out); + + SpvId writePostfixExpression(const PostfixExpression& p, OutputStream& out); SpvId writeBoolLiteral(const BoolLiteral& b); @@ -174,78 +207,84 @@ private: SpvId writeFloatLiteral(const FloatLiteral& f); - void writeStatement(const Statement& s, std::ostream& out); + void writeStatement(const Statement& s, OutputStream& out); - void writeBlock(const Block& b, std::ostream& out); + void writeBlock(const Block& b, OutputStream& out); - void writeIfStatement(const IfStatement& stmt, std::ostream& out); + void writeIfStatement(const IfStatement& stmt, OutputStream& out); - void writeForStatement(const ForStatement& f, std::ostream& out); + void writeForStatement(const ForStatement& f, OutputStream& out); - void writeReturnStatement(const ReturnStatement& r, std::ostream& out); + void writeWhileStatement(const WhileStatement& w, OutputStream& out); - void writeCapabilities(std::ostream& out); + void writeDoStatement(const DoStatement& d, OutputStream& out); - void writeInstructions(const Program& program, std::ostream& out); + void writeReturnStatement(const ReturnStatement& r, OutputStream& out); - void writeOpCode(SpvOp_ opCode, int length, std::ostream& out); + void writeCapabilities(OutputStream& out); - void writeWord(int32_t word, std::ostream& out); + void writeInstructions(const Program& program, OutputStream& out); - void writeString(const char* string, std::ostream& out); + void writeOpCode(SpvOp_ opCode, int length, OutputStream& out); - void writeLabel(SpvId id, std::ostream& out); + void writeWord(int32_t word, OutputStream& out); - void writeInstruction(SpvOp_ opCode, std::ostream& out); + void writeString(const char* string, OutputStream& out); - void writeInstruction(SpvOp_ opCode, const char* string, std::ostream& out); + void writeLabel(SpvId id, OutputStream& out); - void writeInstruction(SpvOp_ opCode, int32_t word1, std::ostream& out); + void writeInstruction(SpvOp_ opCode, OutputStream& out); - void writeInstruction(SpvOp_ opCode, int32_t word1, const char* string, std::ostream& out); + void writeInstruction(SpvOp_ opCode, const char* string, OutputStream& out); + + void writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out); + + void writeInstruction(SpvOp_ opCode, int32_t word1, const char* string, OutputStream& out); void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, const char* string, - std::ostream& out); + OutputStream& out); - void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, std::ostream& out); + void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, OutputStream& out); - void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, - std::ostream& out); + void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, + OutputStream& out); void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4, - std::ostream& out); + OutputStream& out); void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4, - int32_t word5, std::ostream& out); + int32_t word5, OutputStream& out); void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4, - int32_t word5, int32_t word6, std::ostream& out); + int32_t word5, int32_t word6, OutputStream& out); void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4, - int32_t word5, int32_t word6, int32_t word7, std::ostream& out); + int32_t word5, int32_t word6, int32_t word7, OutputStream& out); void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4, - int32_t word5, int32_t word6, int32_t word7, int32_t word8, - std::ostream& out); + int32_t word5, int32_t word6, int32_t word7, int32_t word8, + OutputStream& out); const Context& fContext; + const MemoryLayout fDefaultLayout; uint64_t fCapabilities; SpvId fIdCount; SpvId fGLSLExtendedInstructions; typedef std::tuple Intrinsic; - std::unordered_map fIntrinsicMap; + std::unordered_map fIntrinsicMap; std::unordered_map fFunctionMap; std::unordered_map fVariableMap; std::unordered_map fInterfaceBlockMap; - std::unordered_map fTypeMap; - std::stringstream fCapabilitiesBuffer; - std::stringstream fGlobalInitializersBuffer; - std::stringstream fConstantBuffer; - std::stringstream fExternalFunctionsBuffer; - std::stringstream fVariableBuffer; - std::stringstream fNameBuffer; - std::stringstream fDecorationBuffer; + std::unordered_map fTypeMap; + StringStream fCapabilitiesBuffer; + StringStream fGlobalInitializersBuffer; + StringStream fConstantBuffer; + StringStream fExtraGlobalsBuffer; + StringStream fExternalFunctionsBuffer; + StringStream fVariableBuffer; + StringStream fNameBuffer; + StringStream fDecorationBuffer; SpvId fBoolTrue; SpvId fBoolFalse; @@ -253,13 +292,20 @@ private: std::unordered_map fUIntConstants; std::unordered_map fFloatConstants; std::unordered_map fDoubleConstants; + bool fSetupFragPosition; // label of the current block, or 0 if we are not in a block SpvId fCurrentBlock; std::stack fBreakTarget; std::stack fContinueTarget; + SpvId fRTHeightStructId = (SpvId) -1; + SpvId fRTHeightFieldIndex = (SpvId) -1; + // holds variables synthesized during output, for lifetime purposes + SymbolTable fSynthetics; friend class PointerLValue; friend class SwizzleLValue; + + typedef CodeGenerator INHERITED; }; } diff --git a/gfx/skia/skia/src/sksl/SkSLString.cpp b/gfx/skia/skia/src/sksl/SkSLString.cpp new file mode 100644 index 000000000000..8e531ae0fb6c --- /dev/null +++ b/gfx/skia/skia/src/sksl/SkSLString.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSLString.h" + +#include "SkSLUtil.h" +#include +#include +#include +#include +#include + +namespace SkSL { + +String String::printf(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + String result; + result.vappendf(fmt, args); + return result; +} + +#ifdef SKSL_STANDALONE +void String::appendf(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + this->vappendf(fmt, args); +} +#endif + +void String::vappendf(const char* fmt, va_list args) { +#ifdef SKSL_BUILD_FOR_WIN + #define VSNPRINTF _vsnprintf +#else + #define VSNPRINTF vsnprintf +#endif + #define BUFFER_SIZE 256 + char buffer[BUFFER_SIZE]; + size_t size = VSNPRINTF(buffer, BUFFER_SIZE, fmt, args); + if (BUFFER_SIZE >= size) { + this->append(buffer, size); + } else { + auto newBuffer = std::unique_ptr(new char[size]); + VSNPRINTF(newBuffer.get(), size, fmt, args); + this->append(newBuffer.get(), size); + } + va_end(args); +} + + +bool String::startsWith(const char* s) const { + return strncmp(c_str(), s, strlen(s)); +} + +bool String::endsWith(const char* s) const { + size_t len = strlen(s); + if (size() < len) { + return false; + } + return strncmp(c_str() + size() - len, s, len); +} + +String String::operator+(const char* s) const { + String result(*this); + result.append(s); + return result; +} + +String String::operator+(const String& s) const { + String result(*this); + result.append(s); + return result; +} + +bool String::operator==(const String& s) const { + return this->size() == s.size() && !memcmp(c_str(), s.c_str(), this->size()); +} + +bool String::operator!=(const String& s) const { + return !(*this == s); +} + +bool String::operator==(const char* s) const { + return this->size() == strlen(s) && !memcmp(c_str(), s, this->size()); +} + +bool String::operator!=(const char* s) const { + return !(*this == s); +} + +String operator+(const char* s1, const String& s2) { + String result(s1); + result.append(s2); + return result; +} + +bool operator==(const char* s1, const String& s2) { + return s2 == s1; +} + +bool operator!=(const char* s1, const String& s2) { + return s2 != s1; +} + +String to_string(int32_t value) { + return SkSL::String::printf("%d", value); +} + +String to_string(uint32_t value) { + return SkSL::String::printf("%u", value); +} + +String to_string(int64_t value) { + std::stringstream buffer; + buffer << value; + return String(buffer.str().c_str()); +} + +String to_string(uint64_t value) { + std::stringstream buffer; + buffer << value; + return String(buffer.str().c_str()); +} + +String to_string(double value) { +#ifdef SKSL_BUILD_FOR_WIN + #define SNPRINTF _snprintf +#else + #define SNPRINTF snprintf +#endif +#define MAX_DOUBLE_CHARS 25 + char buffer[MAX_DOUBLE_CHARS]; + SKSL_DEBUGCODE(int len = )SNPRINTF(buffer, sizeof(buffer), "%.17g", value); + ASSERT(len < MAX_DOUBLE_CHARS); + String result(buffer); + if (!strchr(buffer, '.') && !strchr(buffer, 'e')) { + result += ".0"; + } + return result; +#undef SNPRINTF +#undef MAX_DOUBLE_CHARS +} + +int stoi(String s) { + char* p; + SKSL_DEBUGCODE(errno = 0;) + long result = strtoul(s.c_str(), &p, 0); + ASSERT(*p == 0); + ASSERT(!errno); + return (int) result; +} + +double stod(String s) { + double result; + std::string str(s.c_str(), s.size()); + std::stringstream buffer(str); + buffer.imbue(std::locale::classic()); + buffer >> result; + ASSERT(!buffer.fail()); + return result; +} + +long stol(String s) { + char* p; + SKSL_DEBUGCODE(errno = 0;) + long result = strtoul(s.c_str(), &p, 0); + ASSERT(*p == 0); + ASSERT(!errno); + return result; +} + +} // namespace diff --git a/gfx/skia/skia/src/sksl/SkSLString.h b/gfx/skia/skia/src/sksl/SkSLString.h new file mode 100644 index 000000000000..73ba74643ecd --- /dev/null +++ b/gfx/skia/skia/src/sksl/SkSLString.h @@ -0,0 +1,105 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_STRING +#define SKSL_STRING + + +#ifdef SKSL_STANDALONE + #define SKSL_STRING_BASE std::string + #include +#else + #define SKSL_STRING_BASE SkString + #include "SkString.h" +#endif + +namespace SkSL { + +class String : public SKSL_STRING_BASE { +public: + String() = default; + String(const String&) = default; + String(String&&) = default; + String& operator=(const String&) = default; + String& operator=(String&&) = default; + +#ifndef SKSL_STANDALONE + String(const SkString& s) + : INHERITED(s) {} +#endif + + String(const char* s) + : INHERITED(s) {} + + String(const char* s, size_t size) + : INHERITED(s, size) {} + + static String printf(const char* fmt, ...); + +#ifdef SKSL_STANDALONE + void appendf(const char* fmt, ...); +#endif + void vappendf(const char* fmt, va_list va); + + bool startsWith(const char* s) const; + bool endsWith(const char* s) const; + + String operator+(const char* s) const; + String operator+(const String& s) const; + bool operator==(const char* s) const; + bool operator!=(const char* s) const; + bool operator==(const String& s) const; + bool operator!=(const String& s) const; + friend String operator+(const char* s1, const String& s2); + friend bool operator==(const char* s1, const String& s2); + friend bool operator!=(const char* s1, const String& s2); + +private: + typedef SKSL_STRING_BASE INHERITED; +}; + +String operator+(const char* s1, const String& s2); +bool operator!=(const char* s1, const String& s2); + +String to_string(double value); + +String to_string(int32_t value); + +String to_string(uint32_t value); + +String to_string(int64_t value); + +String to_string(uint64_t value); + +int stoi(String s); + +double stod(String s); + +long stol(String s); + +} // namespace + +#ifdef SKSL_STANDALONE +namespace std { + template<> struct hash { + size_t operator()(const SkSL::String& s) const { + return hash{}(s); + } + }; +} // namespace +#else +#include "SkOpts.h" +namespace std { + template<> struct hash { + size_t operator()(const SkSL::String& s) const { + return SkOpts::hash_fn(s.c_str(), s.size(), 0); + } + }; +} // namespace +#endif // SKIA_STANDALONE + +#endif diff --git a/gfx/skia/skia/src/sksl/SkSLStringStream.h b/gfx/skia/skia/src/sksl/SkSLStringStream.h new file mode 100644 index 000000000000..9061432018d8 --- /dev/null +++ b/gfx/skia/skia/src/sksl/SkSLStringStream.h @@ -0,0 +1,99 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_STRINGSTREAM +#define SKSL_STRINGSTREAM + +#include "SkSLOutputStream.h" + +#ifdef SKSL_STANDALONE + +namespace SkSL { + +class StringStream : public OutputStream { +public: + void write8(uint8_t b) override { + fBuffer += (char) b; + } + + void writeText(const char* s) override { + fBuffer += s; + } + + void write(const void* s, size_t size) override { + fBuffer.append((const char*) s, size); + } + + const char* data() const { + return fBuffer.c_str(); + } + + size_t size() const { + return fBuffer.size(); + } + + void reset() { + fBuffer = ""; + } + +private: + String fBuffer; +}; + +#else + +#include "SkData.h" +#include "SkStream.h" + +namespace SkSL { + +class StringStream : public OutputStream { +public: + void write8(uint8_t b) override { + SkASSERT(!fData); + fStream.write8(b); + } + + void writeText(const char* s) override { + SkASSERT(!fData); + fStream.writeText(s); + } + + void write(const void* s, size_t size) override { + SkASSERT(!fData); + fStream.write(s, size); + } + + const char* data() const { + if (!fData) { + fData = fStream.detachAsData(); + } + return (const char*) fData->data(); + } + + size_t size() const { + if (!fData) { + fData = fStream.detachAsData(); + } + return fData->size(); + } + + void reset() { + fStream.reset(); + fData = nullptr; + } + +private: + mutable SkDynamicMemoryWStream fStream; + mutable sk_sp fData; +}; + +#endif // SKSL_STANDALONE + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/SkSLToken.h b/gfx/skia/skia/src/sksl/SkSLToken.h index 29fa81e2e06a..8732e80c6044 100644 --- a/gfx/skia/skia/src/sksl/SkSLToken.h +++ b/gfx/skia/skia/src/sksl/SkSLToken.h @@ -4,13 +4,13 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_TOKEN #define SKSL_TOKEN #include "SkSLPosition.h" #include "SkSLUtil.h" - + namespace SkSL { #undef IN @@ -49,10 +49,11 @@ struct Token { BITWISEOR, BITWISEXOR, BITWISEAND, + BITWISENOT, LOGICALOR, LOGICALXOR, LOGICALAND, - NOT, + LOGICALNOT, QUESTION, COLON, EQ, @@ -81,6 +82,9 @@ struct Token { FOR, WHILE, DO, + SWITCH, + CASE, + DEFAULT, RETURN, BREAK, CONTINUE, @@ -95,67 +99,117 @@ struct Token { UNIFORM, FLAT, NOPERSPECTIVE, + READONLY, + WRITEONLY, + COHERENT, + VOLATILE, + RESTRICT, STRUCT, LAYOUT, DIRECTIVE, PRECISION, + LOCATION, + OFFSET, + BINDING, + INDEX, + SET, + BUILTIN, + INPUT_ATTACHMENT_INDEX, + ORIGIN_UPPER_LEFT, + OVERRIDE_COVERAGE, + BLEND_SUPPORT_ALL_EQUATIONS, + PUSH_CONSTANT, + POINTS, + LINES, + LINE_STRIP, + LINES_ADJACENCY, + TRIANGLES, + TRIANGLE_STRIP, + TRIANGLES_ADJACENCY, + MAX_VERTICES, + INVOCATIONS, INVALID_TOKEN }; - static std::string OperatorName(Kind kind) { + static String OperatorName(Kind kind) { switch (kind) { - case Token::PLUS: return "+"; - case Token::MINUS: return "-"; - case Token::STAR: return "*"; - case Token::SLASH: return "/"; - case Token::PERCENT: return "%"; - case Token::SHL: return "<<"; - case Token::SHR: return ">>"; - case Token::LOGICALAND: return "&&"; - case Token::LOGICALOR: return "||"; - case Token::LOGICALXOR: return "^^"; - case Token::BITWISEAND: return "&"; - case Token::BITWISEOR: return "|"; - case Token::BITWISEXOR: return "^"; - case Token::EQ: return "="; - case Token::EQEQ: return "=="; - case Token::NEQ: return "!="; - case Token::LT: return "<"; - case Token::GT: return ">"; - case Token::LTEQ: return "<="; - case Token::GTEQ: return ">="; - case Token::PLUSEQ: return "+="; - case Token::MINUSEQ: return "-="; - case Token::STAREQ: return "*="; - case Token::SLASHEQ: return "/="; - case Token::PERCENTEQ: return "%="; - case Token::SHLEQ: return "<<="; - case Token::SHREQ: return ">>="; - case Token::LOGICALANDEQ: return "&&="; - case Token::LOGICALOREQ: return "||="; - case Token::LOGICALXOREQ: return "^^="; - case Token::BITWISEANDEQ: return "&="; - case Token::BITWISEOREQ: return "|="; - case Token::BITWISEXOREQ: return "^="; - case Token::PLUSPLUS: return "++"; - case Token::MINUSMINUS: return "--"; - case Token::NOT: return "!"; + case Token::PLUS: return String("+"); + case Token::MINUS: return String("-"); + case Token::STAR: return String("*"); + case Token::SLASH: return String("/"); + case Token::PERCENT: return String("%"); + case Token::SHL: return String("<<"); + case Token::SHR: return String(">>"); + case Token::LOGICALNOT: return String("!"); + case Token::LOGICALAND: return String("&&"); + case Token::LOGICALOR: return String("||"); + case Token::LOGICALXOR: return String("^^"); + case Token::BITWISENOT: return String("~"); + case Token::BITWISEAND: return String("&"); + case Token::BITWISEOR: return String("|"); + case Token::BITWISEXOR: return String("^"); + case Token::EQ: return String("="); + case Token::EQEQ: return String("=="); + case Token::NEQ: return String("!="); + case Token::LT: return String("<"); + case Token::GT: return String(">"); + case Token::LTEQ: return String("<="); + case Token::GTEQ: return String(">="); + case Token::PLUSEQ: return String("+="); + case Token::MINUSEQ: return String("-="); + case Token::STAREQ: return String("*="); + case Token::SLASHEQ: return String("/="); + case Token::PERCENTEQ: return String("%="); + case Token::SHLEQ: return String("<<="); + case Token::SHREQ: return String(">>="); + case Token::LOGICALANDEQ: return String("&&="); + case Token::LOGICALOREQ: return String("||="); + case Token::LOGICALXOREQ: return String("^^="); + case Token::BITWISEANDEQ: return String("&="); + case Token::BITWISEOREQ: return String("|="); + case Token::BITWISEXOREQ: return String("^="); + case Token::PLUSPLUS: return String("++"); + case Token::MINUSMINUS: return String("--"); default: - ABORT("unsupported operator: %d\n", kind); - } + ABORT("unsupported operator: %d\n", kind); + } } Token() { } - Token(Position position, Kind kind, std::string text) + Token(Position position, Kind kind, String text) : fPosition(position) , fKind(kind) , fText(std::move(text)) {} + static bool IsAssignment(Token::Kind op) { + switch (op) { + case Token::EQ: // fall through + case Token::PLUSEQ: // fall through + case Token::MINUSEQ: // fall through + case Token::STAREQ: // fall through + case Token::SLASHEQ: // fall through + case Token::PERCENTEQ: // fall through + case Token::SHLEQ: // fall through + case Token::SHREQ: // fall through + case Token::BITWISEOREQ: // fall through + case Token::BITWISEXOREQ: // fall through + case Token::BITWISEANDEQ: // fall through + case Token::LOGICALOREQ: // fall through + case Token::LOGICALXOREQ: // fall through + case Token::LOGICALANDEQ: + return true; + default: + return false; + } + } + Position fPosition; Kind fKind; - std::string fText; + // will be the empty string unless the token has variable text content (identifiers, numeric + // literals, and directives) + String fText; }; } // namespace diff --git a/gfx/skia/skia/src/sksl/SkSLUtil.cpp b/gfx/skia/skia/src/sksl/SkSLUtil.cpp index 327bffe4f191..c715cf1d09eb 100644 --- a/gfx/skia/skia/src/sksl/SkSLUtil.cpp +++ b/gfx/skia/skia/src/sksl/SkSLUtil.cpp @@ -7,27 +7,27 @@ #include "SkSLUtil.h" +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + namespace SkSL { -int stoi(std::string s) { - return atoi(s.c_str()); -} - -double stod(std::string s) { - return atof(s.c_str()); -} - -long stol(std::string s) { - return atol(s.c_str()); -} +#ifdef SKSL_STANDALONE +StandaloneShaderCaps standaloneCaps; +#endif void sksl_abort() { -#ifdef SKIA +#ifdef SKSL_STANDALONE + abort(); +#else sk_abort_no_print(); exit(1); -#else - abort(); #endif } +void write_stringstream(const StringStream& s, OutputStream& out) { + out.write(s.data(), s.size()); +} + } // namespace diff --git a/gfx/skia/skia/src/sksl/SkSLUtil.h b/gfx/skia/skia/src/sksl/SkSLUtil.h index 33611cde0238..d1af9bb3c77c 100644 --- a/gfx/skia/skia/src/sksl/SkSLUtil.h +++ b/gfx/skia/skia/src/sksl/SkSLUtil.h @@ -4,54 +4,269 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_UTIL #define SKSL_UTIL -#include -#include -#include +#include +#include #include "stdlib.h" +#include "string.h" #include "assert.h" -#include "SkTypes.h" +#include "SkSLString.h" +#include "SkSLStringStream.h" + +#ifndef SKSL_STANDALONE +#include "GrContextOptions.h" +#include "GrShaderCaps.h" +#endif + +#ifdef SKSL_STANDALONE +#if defined(_WIN32) || defined(__SYMBIAN32__) +#define SKSL_BUILD_FOR_WIN +#endif +#else +#ifdef SK_BUILD_FOR_WIN +#define SKSL_BUILD_FOR_WIN +#endif // SK_BUILD_FOR_WIN +#endif // SKSL_STANDALONE namespace SkSL { -// our own definitions of certain std:: functions, because they are not always present on Android +#ifdef SKSL_STANDALONE -template std::string to_string(T value) { - std::stringstream buffer; - buffer << std::setprecision(std::numeric_limits::digits10) << value; - return buffer.str(); -} +// we're being compiled standalone, so we don't have access to caps... +enum GrGLSLGeneration { + k110_GrGLSLGeneration, + k130_GrGLSLGeneration, + k140_GrGLSLGeneration, + k150_GrGLSLGeneration, + k330_GrGLSLGeneration, + k400_GrGLSLGeneration, + k420_GrGLSLGeneration, + k310es_GrGLSLGeneration, + k320es_GrGLSLGeneration, +}; + +#define SKSL_CAPS_CLASS StandaloneShaderCaps +class StandaloneShaderCaps { +public: + GrGLSLGeneration generation() const { + return k400_GrGLSLGeneration; + } + + bool canUseMinAndAbsTogether() const { + return true; + } + + bool mustForceNegatedAtanParamToFloat() const { + return false; + } + + bool shaderDerivativeSupport() const { + return true; + } + + bool usesPrecisionModifiers() const { + return true; + } + + bool mustDeclareFragmentShaderOutput() const { + return true; + } + + bool fbFetchSupport() const { + return true; + } + + bool fbFetchNeedsCustomOutput() const { + return false; + } + + bool bindlessTextureSupport() const { + return false; + } + + bool dropsTileOnZeroDivide() const { + return false; + } + + bool flatInterpolationSupport() const { + return true; + } + + bool noperspectiveInterpolationSupport() const { + return true; + } + + bool multisampleInterpolationSupport() const { + return true; + } + + bool sampleVariablesSupport() const { + return true; + } + + bool sampleMaskOverrideCoverageSupport() const { + return true; + } + + bool externalTextureSupport() const { + return true; + } + + bool texelFetchSupport() const { + return true; + } + + bool imageLoadStoreSupport() const { + return true; + } + + bool mustEnableAdvBlendEqs() const { + return false; + } + + bool mustEnableSpecificAdvBlendEqs() const { + return false; + } + + bool canUseAnyFunctionInShader() const { + return false; + } + + const char* shaderDerivativeExtensionString() const { + return nullptr; + } + + const char* fragCoordConventionsExtensionString() const { + return nullptr; + } + + const char* imageLoadStoreExtensionString() const { + return nullptr; + } + + const char* versionDeclString() const { + return ""; + } +}; + +extern StandaloneShaderCaps standaloneCaps; + +#else + +#define SKSL_CAPS_CLASS GrShaderCaps +// Various sets of caps for use in tests +class ShaderCapsFactory { +public: + static sk_sp Default() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 400"; + result->fShaderDerivativeSupport = true; + return result; + } + + static sk_sp Version450Core() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 450 core"; + return result; + } + + static sk_sp Version110() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 110"; + result->fGLSLGeneration = GrGLSLGeneration::k110_GrGLSLGeneration; + return result; + } + + static sk_sp UsesPrecisionModifiers() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 400"; + result->fUsesPrecisionModifiers = true; + return result; + } + + static sk_sp CannotUseMinAndAbsTogether() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 400"; + result->fCanUseMinAndAbsTogether = false; + return result; + } + + static sk_sp MustForceNegatedAtanParamToFloat() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 400"; + result->fMustForceNegatedAtanParamToFloat = true; + return result; + } + + static sk_sp ShaderDerivativeExtensionString() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 400"; + result->fShaderDerivativeSupport = true; + result->fShaderDerivativeExtensionString = "GL_OES_standard_derivatives"; + return result; + } + + static sk_sp FragCoordsOld() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 110"; + result->fGLSLGeneration = GrGLSLGeneration::k110_GrGLSLGeneration; + result->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions"; + return result; + } + + static sk_sp FragCoordsNew() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 400"; + result->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions"; + return result; + } + + static sk_sp VariousCaps() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 400"; + result->fExternalTextureSupport = true; + result->fFBFetchSupport = false; + result->fDropsTileOnZeroDivide = true; + result->fTexelFetchSupport = true; + result->fCanUseAnyFunctionInShader = false; + return result; + } +}; +#endif + +void write_stringstream(const StringStream& d, OutputStream& out); #if _MSC_VER #define NORETURN __declspec(noreturn) #else #define NORETURN __attribute__((__noreturn__)) #endif -int stoi(std::string s); - -double stod(std::string s); - -long stol(std::string s); NORETURN void sksl_abort(); } // namespace -#ifdef DEBUG -#define ASSERT(x) assert(x) -#define ASSERT_RESULT(x) ASSERT(x); +#ifdef SKSL_STANDALONE +#define ASSERT(x) (void)((x) || (ABORT("failed assert(%s): %s:%d\n", #x, __FILE__, __LINE__), 0)) +#define ASSERT_RESULT(x) ASSERT(x) +#define SKSL_DEBUGCODE(x) x #else -#define ASSERT(x) -#define ASSERT_RESULT(x) x +#define ASSERT SkASSERT +#define ASSERT_RESULT(x) SkAssertResult(x) +#define SKSL_DEBUGCODE(x) SkDEBUGCODE(x) #endif -#ifdef SKIA -#define ABORT(...) { SkDebugf(__VA_ARGS__); sksl_abort(); } +#define SKSL_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) + +#if defined(__clang__) || defined(__GNUC__) +#define SKSL_PRINTF_LIKE(A, B) __attribute__((format(printf, (A), (B)))) #else -#define ABORT(...) { sksl_abort(); } +#define SKSL_PRINTF_LIKE(A, B) #endif +#define ABORT(...) (printf(__VA_ARGS__), sksl_abort()) + #endif diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTBinaryExpression.h b/gfx/skia/skia/src/sksl/ast/SkSLASTBinaryExpression.h index 88feba66a76c..9a2497026223 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTBinaryExpression.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTBinaryExpression.h @@ -10,12 +10,11 @@ #include "SkSLASTExpression.h" #include "../SkSLToken.h" -#include namespace SkSL { /** - * Represents a binary operation, with the operator represented by the token's type. + * Represents a binary operation, with the operator represented by the token's type. */ struct ASTBinaryExpression : public ASTExpression { ASTBinaryExpression(std::unique_ptr left, Token op, @@ -25,7 +24,7 @@ struct ASTBinaryExpression : public ASTExpression { , fOperator(op.fKind) , fRight(std::move(right)) {} - std::string description() const override { + String description() const override { return "(" + fLeft->description() + " " + Token::OperatorName(fOperator) + " " + fRight->description() + ")"; } diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTBlock.h b/gfx/skia/skia/src/sksl/ast/SkSLASTBlock.h index 09450a3db8d3..37c0e81a95ce 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTBlock.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTBlock.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTBLOCK #define SKSL_ASTBLOCK @@ -13,21 +13,21 @@ namespace SkSL { /** - * Represents a curly-braced block of statements. + * Represents a curly-braced block of statements. */ struct ASTBlock : public ASTStatement { ASTBlock(Position position, std::vector> statements) : INHERITED(position, kBlock_Kind) , fStatements(std::move(statements)) {} - std::string description() const override { - std::string result("{"); + String description() const override { + String result("{"); for (size_t i = 0; i < fStatements.size(); i++) { result += "\n"; result += fStatements[i]->description(); } result += "\n}\n"; - return result; + return result; } const std::vector> fStatements; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTBoolLiteral.h b/gfx/skia/skia/src/sksl/ast/SkSLASTBoolLiteral.h index ff58822952c1..48e916eed5b1 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTBoolLiteral.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTBoolLiteral.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTBOOLLITERAL #define SKSL_ASTBOOLLITERAL @@ -13,15 +13,15 @@ namespace SkSL { /** - * Represents "true" or "false". + * Represents "true" or "false". */ struct ASTBoolLiteral : public ASTExpression { ASTBoolLiteral(Position position, bool value) : INHERITED(position, kBool_Kind) , fValue(value) {} - std::string description() const override { - return fValue ? "true" : "false"; + String description() const override { + return String(fValue ? "true" : "false"); } const bool fValue; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTBreakStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTBreakStatement.h index ede548cc246c..079ee76d20a8 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTBreakStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTBreakStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTBREAKSTATEMENT #define SKSL_ASTBREAKSTATEMENT @@ -13,14 +13,14 @@ namespace SkSL { /** - * A 'break' statement. + * A 'break' statement. */ struct ASTBreakStatement : public ASTStatement { ASTBreakStatement(Position position) : INHERITED(position, kBreak_Kind) {} - std::string description() const override { - return "break;"; + String description() const override { + return String("break;"); } typedef ASTStatement INHERITED; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTCallSuffix.h b/gfx/skia/skia/src/sksl/ast/SkSLASTCallSuffix.h index 5cff6f6c93b8..3ba3f0e60f43 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTCallSuffix.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTCallSuffix.h @@ -4,27 +4,26 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTCALLSUFFIX #define SKSL_ASTCALLSUFFIX -#include #include #include "SkSLASTSuffix.h" namespace SkSL { /** - * A parenthesized list of arguments following an expression, indicating a function call. + * A parenthesized list of arguments following an expression, indicating a function call. */ struct ASTCallSuffix : public ASTSuffix { - ASTCallSuffix(Position position, std::vector> arguments) + ASTCallSuffix(Position position, std::vector> arguments) : INHERITED(position, ASTSuffix::kCall_Kind) , fArguments(std::move(arguments)) {} - std::string description() const override { - std::string result("("); - std::string separator = ""; + String description() const override { + String result("("); + String separator; for (size_t i = 0; i < fArguments.size(); ++i) { result += separator; separator = ", "; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTContinueStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTContinueStatement.h index d5ab7a5c7479..fdfce8598d6b 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTContinueStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTContinueStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTCONTINUESTATEMENT #define SKSL_ASTCONTINUESTATEMENT @@ -13,14 +13,14 @@ namespace SkSL { /** - * A 'continue' statement. + * A 'continue' statement. */ struct ASTContinueStatement : public ASTStatement { ASTContinueStatement(Position position) : INHERITED(position, kContinue_Kind) {} - std::string description() const override { - return "continue;"; + String description() const override { + return String("continue;"); } typedef ASTStatement INHERITED; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTDeclaration.h b/gfx/skia/skia/src/sksl/ast/SkSLASTDeclaration.h index 8b55ecf832ec..0395ef91b48d 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTDeclaration.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTDeclaration.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTDECLARATION #define SKSL_ASTDECLARATION @@ -13,14 +13,16 @@ namespace SkSL { /** - * Abstract supertype of declarations such as variables and functions. + * Abstract supertype of declarations such as variables and functions. */ struct ASTDeclaration : public ASTPositionNode { enum Kind { kVar_Kind, kFunction_Kind, kInterfaceBlock_Kind, - kExtension_Kind + kExtension_Kind, + kPrecision_Kind, + kModifiers_Kind }; ASTDeclaration(Position position, Kind kind) diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTDiscardStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTDiscardStatement.h index 4eaeec9ea471..dcf6b15e64a8 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTDiscardStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTDiscardStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTDISCARDSTATEMENT #define SKSL_ASTDISCARDSTATEMENT @@ -13,14 +13,14 @@ namespace SkSL { /** - * A 'discard' statement. + * A 'discard' statement. */ struct ASTDiscardStatement : public ASTStatement { ASTDiscardStatement(Position position) : INHERITED(position, kDiscard_Kind) {} - std::string description() const override { - return "discard;"; + String description() const override { + return String("discard;"); } typedef ASTStatement INHERITED; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTDoStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTDoStatement.h index a952d62eb506..fc97d9e142bf 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTDoStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTDoStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTDOSTATEMENT #define SKSL_ASTDOSTATEMENT @@ -13,7 +13,7 @@ namespace SkSL { /** - * A 'do' loop. + * A 'do' loop. */ struct ASTDoStatement : public ASTStatement { ASTDoStatement(Position position, std::unique_ptr statement, @@ -22,7 +22,7 @@ struct ASTDoStatement : public ASTStatement { , fStatement(std::move(statement)) , fTest(std::move(test)) {} - std::string description() const override { + String description() const override { return "do " + fStatement->description() + " while (" + fTest->description() + ");"; } diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTExpression.h b/gfx/skia/skia/src/sksl/ast/SkSLASTExpression.h index 8a48271042a8..11815aef8453 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTExpression.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTExpression.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTEXPRESSION #define SKSL_ASTEXPRESSION @@ -13,7 +13,7 @@ namespace SkSL { /** - * Abstract supertype of all expressions. + * Abstract supertype of all expressions. */ struct ASTExpression : public ASTPositionNode { enum Kind { diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTExpressionStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTExpressionStatement.h index 450cca29fc9a..398a16a23a00 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTExpressionStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTExpressionStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTEXPRESSIONSTATEMENT #define SKSL_ASTEXPRESSIONSTATEMENT @@ -13,14 +13,14 @@ namespace SkSL { /** - * A lone expression being used as a statement. + * A lone expression being used as a statement. */ struct ASTExpressionStatement : public ASTStatement { ASTExpressionStatement(std::unique_ptr expression) : INHERITED(expression->fPosition, kExpression_Kind) , fExpression(std::move(expression)) {} - std::string description() const override { + String description() const override { return fExpression->description() + ";"; } diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTExtension.h b/gfx/skia/skia/src/sksl/ast/SkSLASTExtension.h index 896ac46c583d..a6fde0694cbf 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTExtension.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTExtension.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTEXTENSION #define SKSL_ASTEXTENSION @@ -12,19 +12,19 @@ namespace SkSL { -/** - * An extension declaration. +/** + * An extension declaration. */ struct ASTExtension : public ASTDeclaration { - ASTExtension(Position position, std::string name) + ASTExtension(Position position, String name) : INHERITED(position, kExtension_Kind) , fName(std::move(name)) {} - std::string description() const override { + String description() const override { return "#extension " + fName + " : enable"; } - const std::string fName; + const String fName; typedef ASTDeclaration INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTFieldSuffix.h b/gfx/skia/skia/src/sksl/ast/SkSLASTFieldSuffix.h index cf141d822f01..bde1e4aec562 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTFieldSuffix.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTFieldSuffix.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTFIELDSUFFIX #define SKSL_ASTFIELDSUFFIX @@ -17,15 +17,15 @@ namespace SkSL { * actually vector swizzle (which looks the same to the parser). */ struct ASTFieldSuffix : public ASTSuffix { - ASTFieldSuffix(Position position, std::string field) + ASTFieldSuffix(Position position, String field) : INHERITED(position, ASTSuffix::kField_Kind) , fField(std::move(field)) {} - std::string description() const override { + String description() const override { return "." + fField; } - std::string fField; + String fField; typedef ASTSuffix INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTFloatLiteral.h b/gfx/skia/skia/src/sksl/ast/SkSLASTFloatLiteral.h index 89d43cc003bb..15fe8360495f 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTFloatLiteral.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTFloatLiteral.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTFLOATLITERAL #define SKSL_ASTFLOATLITERAL @@ -13,14 +13,14 @@ namespace SkSL { /** - * A literal floating point number. + * A literal floating point number. */ struct ASTFloatLiteral : public ASTExpression { ASTFloatLiteral(Position position, double value) : INHERITED(position, kFloat_Kind) , fValue(value) {} - std::string description() const override { + String description() const override { return to_string(fValue); } diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTForStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTForStatement.h index f4f68c8f40d1..326713eb6268 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTForStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTForStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTFORSTATEMENT #define SKSL_ASTFORSTATEMENT @@ -13,10 +13,10 @@ namespace SkSL { /** - * A 'for' loop. + * A 'for' loop. */ struct ASTForStatement : public ASTStatement { - ASTForStatement(Position position, std::unique_ptr initializer, + ASTForStatement(Position position, std::unique_ptr initializer, std::unique_ptr test, std::unique_ptr next, std::unique_ptr statement) : INHERITED(position, kFor_Kind) @@ -25,8 +25,8 @@ struct ASTForStatement : public ASTStatement { , fNext(std::move(next)) , fStatement(std::move(statement)) {} - std::string description() const override { - std::string result = "for ("; + String description() const override { + String result("for ("); if (fInitializer) { result.append(fInitializer->description()); } diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTFunction.h b/gfx/skia/skia/src/sksl/ast/SkSLASTFunction.h index c5c3b9ad83a1..d9f3067baad2 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTFunction.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTFunction.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTFUNCTION #define SKSL_ASTFUNCTION @@ -16,11 +16,11 @@ namespace SkSL { /** - * A function declaration or definition. The fBody field will be null for declarations. + * A function declaration or definition. The fBody field will be null for declarations. */ struct ASTFunction : public ASTDeclaration { - ASTFunction(Position position, std::unique_ptr returnType, std::string name, - std::vector> parameters, + ASTFunction(Position position, std::unique_ptr returnType, String name, + std::vector> parameters, std::unique_ptr body) : INHERITED(position, kFunction_Kind) , fReturnType(std::move(returnType)) @@ -28,8 +28,8 @@ struct ASTFunction : public ASTDeclaration { , fParameters(std::move(parameters)) , fBody(std::move(body)) {} - std::string description() const override { - std::string result = fReturnType->description() + " " + fName + "("; + String description() const override { + String result = fReturnType->description() + " " + fName + "("; for (size_t i = 0; i < fParameters.size(); i++) { if (i > 0) { result += ", "; @@ -41,11 +41,11 @@ struct ASTFunction : public ASTDeclaration { } else { result += ");"; } - return result; + return result; } const std::unique_ptr fReturnType; - const std::string fName; + const String fName; const std::vector> fParameters; const std::unique_ptr fBody; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTIdentifier.h b/gfx/skia/skia/src/sksl/ast/SkSLASTIdentifier.h index d67f64d39b6c..016123cf8c27 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTIdentifier.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTIdentifier.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTIDENTIFIER #define SKSL_ASTIDENTIFIER @@ -13,18 +13,18 @@ namespace SkSL { /** - * An identifier in an expression context. + * An identifier in an expression context. */ struct ASTIdentifier : public ASTExpression { - ASTIdentifier(Position position, std::string text) + ASTIdentifier(Position position, String text) : INHERITED(position, kIdentifier_Kind) , fText(std::move(text)) {} - std::string description() const override { + String description() const override { return fText; } - const std::string fText; + const String fText; typedef ASTExpression INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTIfStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTIfStatement.h index 06f663d5fb3e..684bea00d99e 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTIfStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTIfStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTIFSTATEMENT #define SKSL_ASTIFSTATEMENT @@ -13,18 +13,18 @@ namespace SkSL { /** - * An 'if' statement. + * An 'if' statement. */ struct ASTIfStatement : public ASTStatement { - ASTIfStatement(Position position, std::unique_ptr test, + ASTIfStatement(Position position, std::unique_ptr test, std::unique_ptr ifTrue, std::unique_ptr ifFalse) : INHERITED(position, kIf_Kind) , fTest(std::move(test)) , fIfTrue(std::move(ifTrue)) , fIfFalse(std::move(ifFalse)) {} - std::string description() const override { - std::string result("if ("); + String description() const override { + String result("if ("); result += fTest->description(); result += ") "; result += fIfTrue->description(); @@ -32,7 +32,7 @@ struct ASTIfStatement : public ASTStatement { result += " else "; result += fIfFalse->description(); } - return result; + return result; } const std::unique_ptr fTest; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTIndexSuffix.h b/gfx/skia/skia/src/sksl/ast/SkSLASTIndexSuffix.h index 44d91fa4c4c1..31142e368562 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTIndexSuffix.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTIndexSuffix.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTINDEXSUFFIX #define SKSL_ASTINDEXSUFFIX @@ -14,17 +14,27 @@ namespace SkSL { /** - * A bracketed expression, as in '[0]', indicating an array access. + * A bracketed expression, as in '[0]', indicating an array access. Empty brackets (as occur in + * 'float[](5, 6)' are represented with a null fExpression. */ struct ASTIndexSuffix : public ASTSuffix { - ASTIndexSuffix(std::unique_ptr expression) - : INHERITED(expression->fPosition, ASTSuffix::kIndex_Kind) + ASTIndexSuffix(Position position) + : INHERITED(position, ASTSuffix::kIndex_Kind) + , fExpression(nullptr) {} + + ASTIndexSuffix(std::unique_ptr expression) + : INHERITED(expression ? expression->fPosition : Position(), ASTSuffix::kIndex_Kind) , fExpression(std::move(expression)) {} - std::string description() const override { - return "[" + fExpression->description() + "]"; + String description() const override { + if (fExpression) { + return "[" + fExpression->description() + "]"; + } else { + return String("[]"); + } } + // may be null std::unique_ptr fExpression; typedef ASTSuffix INHERITED; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTIntLiteral.h b/gfx/skia/skia/src/sksl/ast/SkSLASTIntLiteral.h index 25988475349f..fe04347fd8c5 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTIntLiteral.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTIntLiteral.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTINTLITERAL #define SKSL_ASTINTLITERAL @@ -21,7 +21,7 @@ struct ASTIntLiteral : public ASTExpression { : INHERITED(position, kInt_Kind) , fValue(value) {} - std::string description() const override { + String description() const override { return to_string(fValue); } diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTInterfaceBlock.h b/gfx/skia/skia/src/sksl/ast/SkSLASTInterfaceBlock.h index c27136207177..e727ae9aad08 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTInterfaceBlock.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTInterfaceBlock.h @@ -4,11 +4,12 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTINTERFACEBLOCK #define SKSL_ASTINTERFACEBLOCK #include "SkSLASTVarDeclaration.h" +#include "../ir/SkSLModifiers.h" namespace SkSL { @@ -23,32 +24,42 @@ namespace SkSL { struct ASTInterfaceBlock : public ASTDeclaration { // valueName is empty when it was not present in the source ASTInterfaceBlock(Position position, - ASTModifiers modifiers, - std::string interfaceName, - std::string valueName, - std::vector> declarations) + Modifiers modifiers, + String typeName, + std::vector> declarations, + String instanceName, + std::vector> sizes) : INHERITED(position, kInterfaceBlock_Kind) , fModifiers(modifiers) - , fInterfaceName(std::move(interfaceName)) - , fValueName(std::move(valueName)) - , fDeclarations(std::move(declarations)) {} + , fTypeName(std::move(typeName)) + , fDeclarations(std::move(declarations)) + , fInstanceName(std::move(instanceName)) + , fSizes(std::move(sizes)) {} - std::string description() const override { - std::string result = fModifiers.description() + fInterfaceName + " {\n"; + String description() const override { + String result = fModifiers.description() + fTypeName + " {\n"; for (size_t i = 0; i < fDeclarations.size(); i++) { result += fDeclarations[i]->description() + "\n"; } result += "}"; - if (fValueName.length()) { - result += " " + fValueName; + if (fInstanceName.size()) { + result += " " + fInstanceName; + for (const auto& size : fSizes) { + result += "["; + if (size) { + result += size->description(); + } + result += "]"; + } } return result + ";"; } - const ASTModifiers fModifiers; - const std::string fInterfaceName; - const std::string fValueName; + const Modifiers fModifiers; + const String fTypeName; const std::vector> fDeclarations; + const String fInstanceName; + const std::vector> fSizes; typedef ASTDeclaration INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTLayout.h b/gfx/skia/skia/src/sksl/ast/SkSLASTLayout.h deleted file mode 100644 index 08d67531c3cf..000000000000 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTLayout.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SKSL_ASTLAYOUT -#define SKSL_ASTLAYOUT - -#include "SkSLASTNode.h" -#include "SkSLUtil.h" - -namespace SkSL { - -/** - * Represents a layout block appearing before a variable declaration, as in: - * - * layout (location = 0) int x; - */ -struct ASTLayout : public ASTNode { - // For all parameters, a -1 means no value - ASTLayout(int location, int binding, int index, int set, int builtin, bool originUpperLeft) - : fLocation(location) - , fBinding(binding) - , fIndex(index) - , fSet(set) - , fBuiltin(builtin) - , fOriginUpperLeft(originUpperLeft) {} - - std::string description() const { - std::string result; - std::string separator; - if (fLocation >= 0) { - result += separator + "location = " + to_string(fLocation); - separator = ", "; - } - if (fBinding >= 0) { - result += separator + "binding = " + to_string(fBinding); - separator = ", "; - } - if (fIndex >= 0) { - result += separator + "index = " + to_string(fIndex); - separator = ", "; - } - if (fSet >= 0) { - result += separator + "set = " + to_string(fSet); - separator = ", "; - } - if (fBuiltin >= 0) { - result += separator + "builtin = " + to_string(fBuiltin); - separator = ", "; - } - if (fOriginUpperLeft) { - result += separator + "origin_upper_left"; - separator = ", "; - } - if (result.length() > 0) { - result = "layout (" + result + ")"; - } - return result; - } - - const int fLocation; - const int fBinding; - const int fIndex; - const int fSet; - const int fBuiltin; - const bool fOriginUpperLeft; -}; - -} // namespace - -#endif diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTModifiers.h b/gfx/skia/skia/src/sksl/ast/SkSLASTModifiers.h deleted file mode 100644 index 61d2e9f25d53..000000000000 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTModifiers.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SKSL_ASTMODIFIERS -#define SKSL_ASTMODIFIERS - -#include "SkSLASTLayout.h" -#include "SkSLASTNode.h" - -namespace SkSL { - -/** - * A set of modifier keywords (in, out, uniform, etc.) appearing before a declaration. - */ -struct ASTModifiers : public ASTNode { - enum Flag { - kNo_Flag = 0, - kConst_Flag = 1, - kIn_Flag = 2, - kOut_Flag = 4, - kLowp_Flag = 8, - kMediump_Flag = 16, - kHighp_Flag = 32, - kUniform_Flag = 64, - kFlat_Flag = 128, - kNoPerspective_Flag = 256 - }; - - ASTModifiers(ASTLayout layout, int flags) - : fLayout(layout) - , fFlags(flags) {} - - std::string description() const override { - std::string result = fLayout.description(); - if (fFlags & kUniform_Flag) { - result += "uniform "; - } - if (fFlags & kConst_Flag) { - result += "const "; - } - if (fFlags & kLowp_Flag) { - result += "lowp "; - } - if (fFlags & kMediump_Flag) { - result += "mediump "; - } - if (fFlags & kHighp_Flag) { - result += "highp "; - } - if (fFlags & kFlat_Flag) { - result += "flat "; - } - if (fFlags & kNoPerspective_Flag) { - result += "noperspective "; - } - - if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) { - result += "inout "; - } else if (fFlags & kIn_Flag) { - result += "in "; - } else if (fFlags & kOut_Flag) { - result += "out "; - } - - return result; - } - - const ASTLayout fLayout; - const int fFlags; -}; - -} // namespace - -#endif diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTModifiersDeclaration.h b/gfx/skia/skia/src/sksl/ast/SkSLASTModifiersDeclaration.h new file mode 100644 index 000000000000..ba07f168b233 --- /dev/null +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTModifiersDeclaration.h @@ -0,0 +1,37 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_ASTMODIFIERDECLARATION +#define SKSL_ASTMODIFIERDECLARATION + +#include "SkSLASTDeclaration.h" +#include "../ir/SkSLModifiers.h" + +namespace SkSL { + +/** + * A declaration that consists only of modifiers, e.g.: + * + * layout(blend_support_all_equations) out; + */ +struct ASTModifiersDeclaration : public ASTDeclaration { + ASTModifiersDeclaration(Modifiers modifiers) + : INHERITED(Position(), kModifiers_Kind) + , fModifiers(modifiers) {} + + String description() const { + return fModifiers.description() + ";"; + } + + Modifiers fModifiers; + + typedef ASTDeclaration INHERITED; +}; + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTNode.h b/gfx/skia/skia/src/sksl/ast/SkSLASTNode.h index 4305011fa5cd..b08bc2a9320d 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTNode.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTNode.h @@ -4,12 +4,11 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTNODE #define SKSL_ASTNODE -#include -#include +#include "SkSLString.h" namespace SkSL { @@ -19,8 +18,8 @@ namespace SkSL { */ struct ASTNode { virtual ~ASTNode() {} - - virtual std::string description() const = 0; + + virtual String description() const = 0; }; } // namespace diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTParameter.h b/gfx/skia/skia/src/sksl/ast/SkSLASTParameter.h index 8f1b4535f2be..01227c637e21 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTParameter.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTParameter.h @@ -4,12 +4,13 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTPARAMETER #define SKSL_ASTPARAMETER -#include "SkSLASTModifiers.h" +#include "SkSLASTPositionNode.h" #include "SkSLASTType.h" +#include "../ir/SkSLModifiers.h" namespace SkSL { @@ -17,27 +18,27 @@ namespace SkSL { * A declaration of a parameter, as part of a function declaration. */ struct ASTParameter : public ASTPositionNode { - // 'sizes' is a list of the array sizes appearing on a parameter, in source order. + // 'sizes' is a list of the array sizes appearing on a parameter, in source order. // e.g. int x[3][1] would have sizes [3, 1]. - ASTParameter(Position position, ASTModifiers modifiers, std::unique_ptr type, - std::string name, std::vector sizes) + ASTParameter(Position position, Modifiers modifiers, std::unique_ptr type, + String name, std::vector sizes) : INHERITED(position) , fModifiers(modifiers) , fType(std::move(type)) , fName(std::move(name)) , fSizes(std::move(sizes)) {} - std::string description() const override { - std::string result = fModifiers.description() + fType->description() + " " + fName; + String description() const override { + String result = fModifiers.description() + fType->description() + " " + fName; for (int size : fSizes) { result += "[" + to_string(size) + "]"; } return result; } - const ASTModifiers fModifiers; + const Modifiers fModifiers; const std::unique_ptr fType; - const std::string fName; + const String fName; const std::vector fSizes; typedef ASTPositionNode INHERITED; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTPositionNode.h b/gfx/skia/skia/src/sksl/ast/SkSLASTPositionNode.h index 226b4ae4b06e..cc435c486c64 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTPositionNode.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTPositionNode.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTPOSITIONNODE #define SKSL_ASTPOSITIONNODE diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTPrecision.h b/gfx/skia/skia/src/sksl/ast/SkSLASTPrecision.h new file mode 100644 index 000000000000..4b50ed3979cb --- /dev/null +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTPrecision.h @@ -0,0 +1,45 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_ASTPRECISION +#define SKSL_ASTPRECISION + +#include "SkSLASTDeclaration.h" +#include "../ir/SkSLModifiers.h" + +namespace SkSL { + +/** + * Represents a precision declaration (e.g. 'precision mediump float;'). + */ +struct ASTPrecision : public ASTDeclaration { + // FIXME handle the type + ASTPrecision(Position position, Modifiers::Flag precision) + : INHERITED(position, kPrecision_Kind) + , fPrecision(precision) {} + + String description() const { + switch (fPrecision) { + case Modifiers::kLowp_Flag: return String("precision lowp float;"); + case Modifiers::kMediump_Flag: return String("precision mediump float;"); + case Modifiers::kHighp_Flag: return String("precision highp float;"); + default: + ASSERT(false); + return String(""); + } + ASSERT(false); + return String(""); + } + + const Modifiers::Flag fPrecision; + + typedef ASTDeclaration INHERITED; +}; + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTPrefixExpression.h b/gfx/skia/skia/src/sksl/ast/SkSLASTPrefixExpression.h index 0d326e2aab80..08e50f7bf196 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTPrefixExpression.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTPrefixExpression.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTPREFIXEXPRESSION #define SKSL_ASTPREFIXEXPRESSION @@ -22,7 +22,7 @@ struct ASTPrefixExpression : public ASTExpression { , fOperator(op.fKind) , fOperand(std::move(operand)) {} - std::string description() const override { + String description() const override { return Token::OperatorName(fOperator) + fOperand->description(); } diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTReturnStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTReturnStatement.h index 3aac783a8c64..6762eb3f90fa 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTReturnStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTReturnStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTRETURNSTATEMENT #define SKSL_ASTRETURNSTATEMENT @@ -21,12 +21,12 @@ struct ASTReturnStatement : public ASTStatement { : INHERITED(position, kReturn_Kind) , fExpression(std::move(expression)) {} - std::string description() const override { - std::string result("return"); + String description() const override { + String result("return"); if (fExpression) { result += " " + fExpression->description(); } - return result + ";"; + return result + ";"; } const std::unique_ptr fExpression; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTStatement.h index 9ddde063ea3e..1989a1fce65c 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTSTATEMENT #define SKSL_ASTSTATEMENT @@ -26,6 +26,7 @@ struct ASTStatement : public ASTPositionNode { kFor_Kind, kWhile_Kind, kDo_Kind, + kSwitch_Kind, kReturn_Kind, kBreak_Kind, kContinue_Kind, diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTSuffix.h b/gfx/skia/skia/src/sksl/ast/SkSLASTSuffix.h index 18f79f01ea54..f06c6fd362b7 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTSuffix.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTSuffix.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTSUFFIX #define SKSL_ASTSUFFIX @@ -30,15 +30,15 @@ struct ASTSuffix : public ASTPositionNode { : INHERITED(position) , fKind(kind) {} - std::string description() const override { + String description() const override { switch (fKind) { case kPostIncrement_Kind: - return "++"; + return String("++"); case kPostDecrement_Kind: - return "--"; + return String("--"); default: ABORT("unsupported suffix operator"); - } + } } Kind fKind; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTSuffixExpression.h b/gfx/skia/skia/src/sksl/ast/SkSLASTSuffixExpression.h index c0fda294b977..2cff9a865fcd 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTSuffixExpression.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTSuffixExpression.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTSUFFIXEXPRESSION #define SKSL_ASTSUFFIXEXPRESSION @@ -22,7 +22,7 @@ struct ASTSuffixExpression : public ASTExpression { , fBase(std::move(base)) , fSuffix(std::move(suffix)) {} - std::string description() const override { + String description() const override { return fBase->description() + fSuffix->description(); } diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTSwitchCase.h b/gfx/skia/skia/src/sksl/ast/SkSLASTSwitchCase.h new file mode 100644 index 000000000000..405013a6a7f2 --- /dev/null +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTSwitchCase.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_ASTSWITCHCASE +#define SKSL_ASTSWITCHCASE + +#include "SkSLASTStatement.h" + +namespace SkSL { + +/** + * A single case of a 'switch' statement. + */ +struct ASTSwitchCase : public ASTStatement { + // a null value means "default:" + ASTSwitchCase(Position position, std::unique_ptr value, + std::vector> statements) + : INHERITED(position, kSwitch_Kind) + , fValue(std::move(value)) + , fStatements(std::move(statements)) {} + + String description() const override { + String result; + if (fValue) { + result.appendf("case %s:\n", fValue->description().c_str()); + } else { + result += "default:\n"; + } + for (const auto& s : fStatements) { + result += s->description() + "\n"; + } + return result; + } + + // null value implies "default" case + const std::unique_ptr fValue; + const std::vector> fStatements; + + typedef ASTStatement INHERITED; +}; + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTSwitchStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTSwitchStatement.h new file mode 100644 index 000000000000..4a963ebc7a9d --- /dev/null +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTSwitchStatement.h @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_ASTSWITCHSTATEMENT +#define SKSL_ASTSWITCHSTATEMENT + +#include "SkSLASTStatement.h" +#include "SkSLASTSwitchCase.h" + +namespace SkSL { + +/** + * A 'switch' statement. + */ +struct ASTSwitchStatement : public ASTStatement { + ASTSwitchStatement(Position position, std::unique_ptr value, + std::vector> cases) + : INHERITED(position, kSwitch_Kind) + , fValue(std::move(value)) + , fCases(std::move(cases)) {} + + String description() const override { + String result = String::printf("switch (%s) {\n", + fValue->description().c_str()); + for (const auto& c : fCases) { + result += c->description(); + } + result += "}"; + return result; + } + + const std::unique_ptr fValue; + const std::vector> fCases; + + typedef ASTStatement INHERITED; +}; + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTTernaryExpression.h b/gfx/skia/skia/src/sksl/ast/SkSLASTTernaryExpression.h index 20b827a049cc..07c92975e0ff 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTTernaryExpression.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTTernaryExpression.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTTERNARYEXPRESSION #define SKSL_ASTTERNARYEXPRESSION @@ -24,9 +24,9 @@ struct ASTTernaryExpression : public ASTExpression { , fIfTrue(std::move(ifTrue)) , fIfFalse(std::move(ifFalse)) {} - std::string description() const override { + String description() const override { return "(" + fTest->description() + " ? " + fIfTrue->description() + " : " + - fIfFalse->description() + ")"; + fIfFalse->description() + ")"; } const std::unique_ptr fTest; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTType.h b/gfx/skia/skia/src/sksl/ast/SkSLASTType.h index b8fdedb2149f..57a8025b7b7e 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTType.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTType.h @@ -4,10 +4,12 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTTYPE #define SKSL_ASTTYPE +#include "SkSLASTPositionNode.h" + namespace SkSL { /** @@ -19,19 +21,23 @@ struct ASTType : public ASTPositionNode { kStruct_Kind }; - ASTType(Position position, std::string name, Kind kind) + ASTType(Position position, String name, Kind kind, std::vector sizes) : INHERITED(position) , fName(std::move(name)) - , fKind(kind) {} + , fKind(kind) + , fSizes(std::move(sizes)) {} - std::string description() const override { + String description() const override { return fName; } - const std::string fName; + const String fName; const Kind fKind; + // array sizes, -1 meaning unspecified + const std::vector fSizes; + typedef ASTPositionNode INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTVarDeclaration.h b/gfx/skia/skia/src/sksl/ast/SkSLASTVarDeclaration.h index 066922fb852b..2dcb9787ead9 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTVarDeclaration.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTVarDeclaration.h @@ -4,33 +4,33 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTVARDECLARATIONS #define SKSL_ASTVARDECLARATIONS #include "SkSLASTDeclaration.h" -#include "SkSLASTModifiers.h" #include "SkSLASTStatement.h" #include "SkSLASTType.h" #include "../SkSLUtil.h" +#include "../ir/SkSLModifiers.h" namespace SkSL { /** * A single variable declaration within a var declaration statement. For instance, the statement - * 'int x = 2, y[3];' is an ASTVarDeclarations statement containing two individual ASTVarDeclaration + * 'int x = 2, y[3];' is an ASTVarDeclarations statement containing two individual ASTVarDeclaration * instances. */ struct ASTVarDeclaration { - ASTVarDeclaration(const std::string name, + ASTVarDeclaration(const String name, std::vector> sizes, std::unique_ptr value) : fName(name) , fSizes(std::move(sizes)) , fValue(std::move(value)) {} - std::string description() const { - std::string result = fName; + String description() const { + String result = fName; for (const auto& size : fSizes) { if (size) { result += "[" + size->description() + "]"; @@ -41,10 +41,10 @@ struct ASTVarDeclaration { if (fValue) { result += " = " + fValue->description(); } - return result; + return result; } - std::string fName; + String fName; // array sizes, if any. e.g. 'foo[3][]' has sizes [3, null] std::vector> fSizes; @@ -57,17 +57,17 @@ struct ASTVarDeclaration { * A variable declaration statement, which may consist of one or more individual variables. */ struct ASTVarDeclarations : public ASTDeclaration { - ASTVarDeclarations(ASTModifiers modifiers, - std::unique_ptr type, + ASTVarDeclarations(Modifiers modifiers, + std::unique_ptr type, std::vector vars) : INHERITED(type->fPosition, kVar_Kind) , fModifiers(modifiers) , fType(std::move(type)) , fVars(std::move(vars)) {} - std::string description() const override { - std::string result = fModifiers.description() + fType->description() + " "; - std::string separator = ""; + String description() const override { + String result = fModifiers.description() + fType->description() + " "; + String separator; for (const auto& var : fVars) { result += separator; separator = ", "; @@ -76,7 +76,7 @@ struct ASTVarDeclarations : public ASTDeclaration { return result; } - const ASTModifiers fModifiers; + const Modifiers fModifiers; const std::unique_ptr fType; const std::vector fVars; diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTVarDeclarationStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTVarDeclarationStatement.h index 8bae389146c1..c3a4069ba0f0 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTVarDeclarationStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTVarDeclarationStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTVARDECLARATIONSTATEMENT #define SKSL_ASTVARDECLARATIONSTATEMENT @@ -21,7 +21,7 @@ struct ASTVarDeclarationStatement : public ASTStatement { : INHERITED(decl->fPosition, kVarDeclaration_Kind) , fDeclarations(std::move(decl)) {} - std::string description() const override { + String description() const override { return fDeclarations->description() + ";"; } diff --git a/gfx/skia/skia/src/sksl/ast/SkSLASTWhileStatement.h b/gfx/skia/skia/src/sksl/ast/SkSLASTWhileStatement.h index e29aa23e4a52..e63c50293a48 100644 --- a/gfx/skia/skia/src/sksl/ast/SkSLASTWhileStatement.h +++ b/gfx/skia/skia/src/sksl/ast/SkSLASTWhileStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_ASTWHILESTATEMENT #define SKSL_ASTWHILESTATEMENT @@ -16,13 +16,13 @@ namespace SkSL { * A 'while' statement. */ struct ASTWhileStatement : public ASTStatement { - ASTWhileStatement(Position position, std::unique_ptr test, + ASTWhileStatement(Position position, std::unique_ptr test, std::unique_ptr statement) : INHERITED(position, kWhile_Kind) , fTest(std::move(test)) , fStatement(std::move(statement)) {} - std::string description() const override { + String description() const override { return "while (" + fTest->description() + ") " + fStatement->description(); } diff --git a/gfx/skia/skia/src/sksl/disable_flex_warnings.h b/gfx/skia/skia/src/sksl/disable_flex_warnings.h new file mode 100644 index 000000000000..fa11eda24ca4 --- /dev/null +++ b/gfx/skia/skia/src/sksl/disable_flex_warnings.h @@ -0,0 +1,26 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// useless include to avoid "#if before #include" complaint from Skia presubmit +#include "SkSLUtil.h" +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunneeded-internal-declaration" +#pragma clang diagnostic ignored "-Wnull-conversion" +#pragma clang diagnostic ignored "-Wsign-compare" +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wdeprecated-register" +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4018) +#endif diff --git a/gfx/skia/skia/src/sksl/ir/SkSLBinaryExpression.h b/gfx/skia/skia/src/sksl/ir/SkSLBinaryExpression.h index 9ecdbc717c88..73b1829ef294 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLBinaryExpression.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLBinaryExpression.h @@ -4,17 +4,19 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_BINARYEXPRESSION #define SKSL_BINARYEXPRESSION #include "SkSLExpression.h" +#include "SkSLExpression.h" +#include "../SkSLIRGenerator.h" #include "../SkSLToken.h" namespace SkSL { /** - * A binary operation. + * A binary operation. */ struct BinaryExpression : public Expression { BinaryExpression(Position position, std::unique_ptr left, Token::Kind op, @@ -24,14 +26,22 @@ struct BinaryExpression : public Expression { , fOperator(op) , fRight(std::move(right)) {} - virtual std::string description() const override { + virtual std::unique_ptr constantPropagate( + const IRGenerator& irGenerator, + const DefinitionMap& definitions) override { + return irGenerator.constantFold(*fLeft, + fOperator, + *fRight); + } + + virtual String description() const override { return "(" + fLeft->description() + " " + Token::OperatorName(fOperator) + " " + fRight->description() + ")"; } - const std::unique_ptr fLeft; + std::unique_ptr fLeft; const Token::Kind fOperator; - const std::unique_ptr fRight; + std::unique_ptr fRight; typedef Expression INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLBlock.h b/gfx/skia/skia/src/sksl/ir/SkSLBlock.h index a53d13d16909..fe58d4413519 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLBlock.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLBlock.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_BLOCK #define SKSL_BLOCK @@ -20,21 +20,23 @@ struct Block : public Statement { Block(Position position, std::vector> statements, const std::shared_ptr symbols) : INHERITED(position, kBlock_Kind) - , fStatements(std::move(statements)) - , fSymbols(std::move(symbols)) {} + , fSymbols(std::move(symbols)) + , fStatements(std::move(statements)) {} - std::string description() const override { - std::string result = "{"; + String description() const override { + String result("{"); for (size_t i = 0; i < fStatements.size(); i++) { result += "\n"; result += fStatements[i]->description(); } result += "\n}\n"; - return result; + return result; } - const std::vector> fStatements; + // it's important to keep fStatements defined after (and thus destroyed before) fSymbols, + // because destroying statements can modify reference counts in symbols const std::shared_ptr fSymbols; + const std::vector> fStatements; typedef Statement INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLBoolLiteral.h b/gfx/skia/skia/src/sksl/ir/SkSLBoolLiteral.h index ba054e4181e6..4e1e05077811 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLBoolLiteral.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLBoolLiteral.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_BOOLLITERAL #define SKSL_BOOLLITERAL @@ -21,8 +21,8 @@ struct BoolLiteral : public Expression { : INHERITED(position, kBoolLiteral_Kind, *context.fBool_Type) , fValue(value) {} - std::string description() const override { - return fValue ? "true" : "false"; + String description() const override { + return String(fValue ? "true" : "false"); } bool isConstant() const override { diff --git a/gfx/skia/skia/src/sksl/ir/SkSLBreakStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLBreakStatement.h index 8aa17b096b49..f6edc558e5cf 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLBreakStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLBreakStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_BREAKSTATEMENT #define SKSL_BREAKSTATEMENT @@ -14,14 +14,14 @@ namespace SkSL { /** - * A 'break' statement. + * A 'break' statement. */ struct BreakStatement : public Statement { BreakStatement(Position position) : INHERITED(position, kBreak_Kind) {} - std::string description() const override { - return "break;"; + String description() const override { + return String("break;"); } typedef Statement INHERITED; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLConstructor.h b/gfx/skia/skia/src/sksl/ir/SkSLConstructor.h index 0501b651ead8..5c647c7cab12 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLConstructor.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLConstructor.h @@ -4,26 +4,49 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_CONSTRUCTOR #define SKSL_CONSTRUCTOR #include "SkSLExpression.h" +#include "SkSLFloatLiteral.h" +#include "SkSLIntLiteral.h" +#include "SkSLIRGenerator.h" namespace SkSL { /** * Represents the construction of a compound type, such as "vec2(x, y)". + * + * Vector constructors will always consist of either exactly 1 scalar, or a collection of vectors + * and scalars totalling exactly the right number of scalar components. + * + * Matrix constructors will always consist of either exactly 1 scalar, exactly 1 matrix, or a + * collection of vectors and scalars totalling exactly the right number of scalar components. */ struct Constructor : public Expression { - Constructor(Position position, const Type& type, + Constructor(Position position, const Type& type, std::vector> arguments) : INHERITED(position, kConstructor_Kind, type) , fArguments(std::move(arguments)) {} - std::string description() const override { - std::string result = fType.description() + "("; - std::string separator = ""; + virtual std::unique_ptr constantPropagate( + const IRGenerator& irGenerator, + const DefinitionMap& definitions) override { + if (fArguments.size() == 1 && fArguments[0]->fKind == Expression::kIntLiteral_Kind && + // promote float(1) to 1.0 + fType == *irGenerator.fContext.fFloat_Type) { + int64_t intValue = ((IntLiteral&) *fArguments[0]).fValue; + return std::unique_ptr(new FloatLiteral(irGenerator.fContext, + fPosition, + intValue)); + } + return nullptr; + } + + String description() const override { + String result = fType.description() + "("; + String separator; for (size_t i = 0; i < fArguments.size(); i++) { result += separator; result += fArguments[i]->description(); @@ -42,7 +65,7 @@ struct Constructor : public Expression { return true; } - const std::vector> fArguments; + std::vector> fArguments; typedef Expression INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLContinueStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLContinueStatement.h index 1951bd990a4c..3f5bc1d4bbba 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLContinueStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLContinueStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_CONTINUESTATEMENT #define SKSL_CONTINUESTATEMENT @@ -14,14 +14,14 @@ namespace SkSL { /** - * A 'continue' statement. + * A 'continue' statement. */ struct ContinueStatement : public Statement { ContinueStatement(Position position) : INHERITED(position, kContinue_Kind) {} - std::string description() const override { - return "continue;"; + String description() const override { + return String("continue;"); } typedef Statement INHERITED; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLDiscardStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLDiscardStatement.h index b39712ebd11a..62124668ee0d 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLDiscardStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLDiscardStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_DISCARDSTATEMENT #define SKSL_DISCARDSTATEMENT @@ -14,14 +14,14 @@ namespace SkSL { /** - * A 'discard' statement. + * A 'discard' statement. */ struct DiscardStatement : public Statement { DiscardStatement(Position position) : INHERITED(position, kDiscard_Kind) {} - std::string description() const override { - return "discard;"; + String description() const override { + return String("discard;"); } typedef Statement INHERITED; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLDoStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLDoStatement.h index 601245327709..4d3d34864db4 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLDoStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLDoStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_DOSTATEMENT #define SKSL_DOSTATEMENT @@ -23,12 +23,12 @@ struct DoStatement : public Statement { , fStatement(std::move(statement)) , fTest(std::move(test)) {} - std::string description() const override { + String description() const override { return "do " + fStatement->description() + " while (" + fTest->description() + ");"; } const std::unique_ptr fStatement; - const std::unique_ptr fTest; + std::unique_ptr fTest; typedef Statement INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLExpression.h b/gfx/skia/skia/src/sksl/ir/SkSLExpression.h index 92cb37de776b..f87d810fc043 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLExpression.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLExpression.h @@ -4,17 +4,24 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_EXPRESSION #define SKSL_EXPRESSION -#include "SkSLIRNode.h" #include "SkSLType.h" +#include "SkSLVariable.h" + +#include namespace SkSL { +struct Expression; +class IRGenerator; + +typedef std::unordered_map*> DefinitionMap; + /** - * Abstract supertype of all expressions. + * Abstract supertype of all expressions. */ struct Expression : public IRNode { enum Kind { @@ -33,6 +40,7 @@ struct Expression : public IRNode { kVariableReference_Kind, kTernary_Kind, kTypeReference_Kind, + kDefined_Kind }; Expression(Position position, Kind kind, const Type& type) @@ -44,6 +52,18 @@ struct Expression : public IRNode { return false; } + /** + * Given a map of known constant variable values, substitute them in for references to those + * variables occurring in this expression and its subexpressions. Similar simplifications, such + * as folding a constant binary expression down to a single value, may also be performed. + * Returns a new expression which replaces this expression, or null if no replacements were + * made. If a new expression is returned, this expression is no longer valid. + */ + virtual std::unique_ptr constantPropagate(const IRGenerator& irGenerator, + const DefinitionMap& definitions) { + return nullptr; + } + const Kind fKind; const Type& fType; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLExpressionStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLExpressionStatement.h index e975ccf2ac6a..d1ab8e9ed960 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLExpressionStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLExpressionStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_EXPRESSIONSTATEMENT #define SKSL_EXPRESSIONSTATEMENT @@ -14,18 +14,18 @@ namespace SkSL { /** - * A lone expression being used as a statement. + * A lone expression being used as a statement. */ struct ExpressionStatement : public Statement { ExpressionStatement(std::unique_ptr expression) : INHERITED(expression->fPosition, kExpression_Kind) , fExpression(std::move(expression)) {} - std::string description() const override { + String description() const override { return fExpression->description() + ";"; } - const std::unique_ptr fExpression; + std::unique_ptr fExpression; typedef Statement INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLExtension.h b/gfx/skia/skia/src/sksl/ir/SkSLExtension.h index d7f83fad8a90..70dc6b3eaf4e 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLExtension.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLExtension.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_EXTENSION #define SKSL_EXTENSION @@ -12,19 +12,19 @@ namespace SkSL { -/** - * An extension declaration. +/** + * An extension declaration. */ struct Extension : public ProgramElement { - Extension(Position position, std::string name) - : INHERITED(position, kExtension_Kind) + Extension(Position position, String name) + : INHERITED(position, kExtension_Kind) , fName(std::move(name)) {} - std::string description() const override { + String description() const override { return "#extension " + fName + " : enable"; } - const std::string fName; + const String fName; typedef ProgramElement INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLField.h b/gfx/skia/skia/src/sksl/ir/SkSLField.h index a01df2943d0d..abea730da147 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLField.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLField.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_FIELD #define SKSL_FIELD @@ -12,12 +12,13 @@ #include "SkSLPosition.h" #include "SkSLSymbol.h" #include "SkSLType.h" +#include "SkSLVariable.h" namespace SkSL { -/** - * A symbol which should be interpreted as a field access. Fields are added to the symboltable - * whenever a bare reference to an identifier should refer to a struct field; in GLSL, this is the +/** + * A symbol which should be interpreted as a field access. Fields are added to the symboltable + * whenever a bare reference to an identifier should refer to a struct field; in GLSL, this is the * result of declaring anonymous interface blocks. */ struct Field : public Symbol { @@ -26,7 +27,7 @@ struct Field : public Symbol { , fOwner(owner) , fFieldIndex(fieldIndex) {} - virtual std::string description() const override { + virtual String description() const override { return fOwner.description() + "." + fOwner.fType.fields()[fFieldIndex].fName; } diff --git a/gfx/skia/skia/src/sksl/ir/SkSLFieldAccess.h b/gfx/skia/skia/src/sksl/ir/SkSLFieldAccess.h index 4be4e9e84c13..eead41c71f10 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLFieldAccess.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLFieldAccess.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_FIELDACCESS #define SKSL_FIELDACCESS @@ -24,18 +24,18 @@ struct FieldAccess : public Expression { kAnonymousInterfaceBlock_OwnerKind }; - FieldAccess(std::unique_ptr base, int fieldIndex, + FieldAccess(std::unique_ptr base, int fieldIndex, OwnerKind ownerKind = kDefault_OwnerKind) : INHERITED(base->fPosition, kFieldAccess_Kind, *base->fType.fields()[fieldIndex].fType) , fBase(std::move(base)) , fFieldIndex(fieldIndex) , fOwnerKind(ownerKind) {} - virtual std::string description() const override { + virtual String description() const override { return fBase->description() + "." + fBase->fType.fields()[fFieldIndex].fName; } - const std::unique_ptr fBase; + std::unique_ptr fBase; const int fFieldIndex; const OwnerKind fOwnerKind; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLFloatLiteral.h b/gfx/skia/skia/src/sksl/ir/SkSLFloatLiteral.h index a8fcfcf644e7..5ed123575b73 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLFloatLiteral.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLFloatLiteral.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_FLOATLITERAL #define SKSL_FLOATLITERAL @@ -21,7 +21,7 @@ struct FloatLiteral : public Expression { : INHERITED(position, kFloatLiteral_Kind, *context.fFloat_Type) , fValue(value) {} - virtual std::string description() const override { + virtual String description() const override { return to_string(fValue); } diff --git a/gfx/skia/skia/src/sksl/ir/SkSLForStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLForStatement.h index 642d15125e5c..b72c26b17963 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLForStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLForStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_FORSTATEMENT #define SKSL_FORSTATEMENT @@ -18,25 +18,25 @@ namespace SkSL { * A 'for' statement. */ struct ForStatement : public Statement { - ForStatement(Position position, std::unique_ptr initializer, - std::unique_ptr test, std::unique_ptr next, + ForStatement(Position position, std::unique_ptr initializer, + std::unique_ptr test, std::unique_ptr next, std::unique_ptr statement, std::shared_ptr symbols) : INHERITED(position, kFor_Kind) + , fSymbols(symbols) , fInitializer(std::move(initializer)) , fTest(std::move(test)) , fNext(std::move(next)) - , fStatement(std::move(statement)) - , fSymbols(symbols) {} + , fStatement(std::move(statement)) {} - std::string description() const override { - std::string result = "for ("; + String description() const override { + String result("for ("); if (fInitializer) { result += fInitializer->description(); - } + } result += " "; if (fTest) { result += fTest->description(); - } + } result += "; "; if (fNext) { result += fNext->description(); @@ -45,11 +45,13 @@ struct ForStatement : public Statement { return result; } - const std::unique_ptr fInitializer; - const std::unique_ptr fTest; - const std::unique_ptr fNext; - const std::unique_ptr fStatement; + // it's important to keep fSymbols defined first (and thus destroyed last) because destroying + // the other fields can update symbol reference counts const std::shared_ptr fSymbols; + const std::unique_ptr fInitializer; + std::unique_ptr fTest; + std::unique_ptr fNext; + const std::unique_ptr fStatement; typedef Statement INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLFunctionCall.h b/gfx/skia/skia/src/sksl/ir/SkSLFunctionCall.h index 85dba40f2ae8..1a5c6fd693ca 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLFunctionCall.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLFunctionCall.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_FUNCTIONCALL #define SKSL_FUNCTIONCALL @@ -17,15 +17,15 @@ namespace SkSL { * A function invocation. */ struct FunctionCall : public Expression { - FunctionCall(Position position, const FunctionDeclaration& function, + FunctionCall(Position position, const Type& type, const FunctionDeclaration& function, std::vector> arguments) - : INHERITED(position, kFunctionCall_Kind, function.fReturnType) + : INHERITED(position, kFunctionCall_Kind, type) , fFunction(std::move(function)) , fArguments(std::move(arguments)) {} - std::string description() const override { - std::string result = fFunction.fName + "("; - std::string separator = ""; + String description() const override { + String result = fFunction.fName + "("; + String separator; for (size_t i = 0; i < fArguments.size(); i++) { result += separator; result += fArguments[i]->description(); @@ -36,7 +36,7 @@ struct FunctionCall : public Expression { } const FunctionDeclaration& fFunction; - const std::vector> fArguments; + std::vector> fArguments; typedef Expression INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLFunctionDeclaration.h b/gfx/skia/skia/src/sksl/ir/SkSLFunctionDeclaration.h index 16a184a6d798..05ba03addb58 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLFunctionDeclaration.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLFunctionDeclaration.h @@ -4,10 +4,11 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_FUNCTIONDECLARATION #define SKSL_FUNCTIONDECLARATION +#include "SkSLExpression.h" #include "SkSLModifiers.h" #include "SkSLSymbol.h" #include "SkSLSymbolTable.h" @@ -20,16 +21,17 @@ namespace SkSL { * A function declaration (not a definition -- does not contain a body). */ struct FunctionDeclaration : public Symbol { - FunctionDeclaration(Position position, std::string name, + FunctionDeclaration(Position position, String name, std::vector parameters, const Type& returnType) : INHERITED(position, kFunctionDeclaration_Kind, std::move(name)) , fDefined(false) + , fBuiltin(false) , fParameters(std::move(parameters)) , fReturnType(returnType) {} - std::string description() const override { - std::string result = fReturnType.description() + " " + fName + "("; - std::string separator = ""; + String description() const override { + String result = fReturnType.description() + " " + fName + "("; + String separator; for (auto p : fParameters) { result += separator; separator = ", "; @@ -54,7 +56,52 @@ struct FunctionDeclaration : public Symbol { return true; } + /** + * Determine the effective types of this function's parameters and return value when called with + * the given arguments. This is relevant for functions with generic parameter types, where this + * will collapse the generic types down into specific concrete types. + * + * Returns true if it was able to select a concrete set of types for the generic function, false + * if there is no possible way this can match the argument types. Note that even a true return + * does not guarantee that the function can be successfully called with those arguments, merely + * indicates that an attempt should be made. If false is returned, the state of + * outParameterTypes and outReturnType are undefined. + */ + bool determineFinalTypes(const std::vector>& arguments, + std::vector* outParameterTypes, + const Type** outReturnType) const { + assert(arguments.size() == fParameters.size()); + int genericIndex = -1; + for (size_t i = 0; i < arguments.size(); i++) { + if (fParameters[i]->fType.kind() == Type::kGeneric_Kind) { + std::vector types = fParameters[i]->fType.coercibleTypes(); + if (genericIndex == -1) { + for (size_t j = 0; j < types.size(); j++) { + if (arguments[i]->fType.canCoerceTo(*types[j])) { + genericIndex = j; + break; + } + } + if (genericIndex == -1) { + return false; + } + } + outParameterTypes->push_back(types[genericIndex]); + } else { + outParameterTypes->push_back(&fParameters[i]->fType); + } + } + if (fReturnType.kind() == Type::kGeneric_Kind) { + assert(genericIndex != -1); + *outReturnType = fReturnType.coercibleTypes()[genericIndex]; + } else { + *outReturnType = &fReturnType; + } + return true; + } + mutable bool fDefined; + bool fBuiltin; const std::vector fParameters; const Type& fReturnType; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLFunctionDefinition.h b/gfx/skia/skia/src/sksl/ir/SkSLFunctionDefinition.h index ace27a3ed8e2..e87ee63e7aef 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLFunctionDefinition.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLFunctionDefinition.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_FUNCTIONDEFINITION #define SKSL_FUNCTIONDEFINITION @@ -18,13 +18,13 @@ namespace SkSL { * A function definition (a declaration plus an associated block of code). */ struct FunctionDefinition : public ProgramElement { - FunctionDefinition(Position position, const FunctionDeclaration& declaration, + FunctionDefinition(Position position, const FunctionDeclaration& declaration, std::unique_ptr body) : INHERITED(position, kFunction_Kind) , fDeclaration(declaration) , fBody(std::move(body)) {} - std::string description() const override { + String description() const override { return fDeclaration.description() + " " + fBody->description(); } diff --git a/gfx/skia/skia/src/sksl/ir/SkSLFunctionReference.h b/gfx/skia/skia/src/sksl/ir/SkSLFunctionReference.h index f3f8fb71daf5..49ddf839f920 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLFunctionReference.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLFunctionReference.h @@ -4,28 +4,29 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_FUNCTIONREFERENCE #define SKSL_FUNCTIONREFERENCE #include "SkSLContext.h" #include "SkSLExpression.h" +#include "SkSLFunctionDeclaration.h" namespace SkSL { /** - * An identifier referring to a function name. This is an intermediate value: FunctionReferences are + * An identifier referring to a function name. This is an intermediate value: FunctionReferences are * always eventually replaced by FunctionCalls in valid programs. */ struct FunctionReference : public Expression { - FunctionReference(const Context& context, Position position, + FunctionReference(const Context& context, Position position, std::vector function) : INHERITED(position, kFunctionReference_Kind, *context.fInvalid_Type) , fFunctions(function) {} - virtual std::string description() const override { + virtual String description() const override { ASSERT(false); - return ""; + return String(""); } const std::vector fFunctions; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLIRNode.h b/gfx/skia/skia/src/sksl/ir/SkSLIRNode.h index 8c433cfc6b49..139be32f44c3 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLIRNode.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLIRNode.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_IRNODE #define SKSL_IRNODE @@ -13,7 +13,7 @@ namespace SkSL { /** - * Represents a node in the intermediate representation (IR) tree. The IR is a fully-resolved + * Represents a node in the intermediate representation (IR) tree. The IR is a fully-resolved * version of the program (all types determined, everything validated), ready for code generation. */ struct IRNode { @@ -22,7 +22,7 @@ struct IRNode { virtual ~IRNode() {} - virtual std::string description() const = 0; + virtual String description() const = 0; const Position fPosition; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLIfStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLIfStatement.h index 8ab5c00fd78c..a7e0aad00e68 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLIfStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLIfStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_IFSTATEMENT #define SKSL_IFSTATEMENT @@ -17,22 +17,22 @@ namespace SkSL { * An 'if' statement. */ struct IfStatement : public Statement { - IfStatement(Position position, std::unique_ptr test, + IfStatement(Position position, std::unique_ptr test, std::unique_ptr ifTrue, std::unique_ptr ifFalse) : INHERITED(position, kIf_Kind) , fTest(std::move(test)) , fIfTrue(std::move(ifTrue)) , fIfFalse(std::move(ifFalse)) {} - std::string description() const override { - std::string result = "if (" + fTest->description() + ") " + fIfTrue->description(); + String description() const override { + String result = "if (" + fTest->description() + ") " + fIfTrue->description(); if (fIfFalse) { result += " else " + fIfFalse->description(); } return result; } - const std::unique_ptr fTest; + std::unique_ptr fTest; const std::unique_ptr fIfTrue; const std::unique_ptr fIfFalse; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLIndexExpression.h b/gfx/skia/skia/src/sksl/ir/SkSLIndexExpression.h index f5b0d09c2cbf..68823bf18424 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLIndexExpression.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLIndexExpression.h @@ -4,10 +4,11 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_INDEX #define SKSL_INDEX +#include "SkSLContext.h" #include "SkSLExpression.h" #include "SkSLUtil.h" @@ -19,7 +20,7 @@ namespace SkSL { static const Type& index_type(const Context& context, const Type& type) { if (type.kind() == Type::kMatrix_Kind) { if (type.componentType() == *context.fFloat_Type) { - switch (type.columns()) { + switch (type.rows()) { case 2: return *context.fVec2_Type; case 3: return *context.fVec3_Type; case 4: return *context.fVec4_Type; @@ -27,7 +28,7 @@ static const Type& index_type(const Context& context, const Type& type) { } } else { ASSERT(type.componentType() == *context.fDouble_Type); - switch (type.columns()) { + switch (type.rows()) { case 2: return *context.fDVec2_Type; case 3: return *context.fDVec3_Type; case 4: return *context.fDVec4_Type; @@ -42,20 +43,20 @@ static const Type& index_type(const Context& context, const Type& type) { * An expression which extracts a value from an array or matrix, as in 'm[2]'. */ struct IndexExpression : public Expression { - IndexExpression(const Context& context, std::unique_ptr base, + IndexExpression(const Context& context, std::unique_ptr base, std::unique_ptr index) : INHERITED(base->fPosition, kIndex_Kind, index_type(context, base->fType)) , fBase(std::move(base)) , fIndex(std::move(index)) { - ASSERT(fIndex->fType == *context.fInt_Type); + ASSERT(fIndex->fType == *context.fInt_Type || fIndex->fType == *context.fUInt_Type); } - std::string description() const override { + String description() const override { return fBase->description() + "[" + fIndex->description() + "]"; } - const std::unique_ptr fBase; - const std::unique_ptr fIndex; + std::unique_ptr fBase; + std::unique_ptr fIndex; typedef Expression INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLIntLiteral.h b/gfx/skia/skia/src/sksl/ir/SkSLIntLiteral.h index 2bc565712e41..2322a3d40a5a 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLIntLiteral.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLIntLiteral.h @@ -4,10 +4,11 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_INTLITERAL #define SKSL_INTLITERAL +#include "SkSLContext.h" #include "SkSLExpression.h" namespace SkSL { @@ -18,11 +19,11 @@ namespace SkSL { struct IntLiteral : public Expression { // FIXME: we will need to revisit this if/when we add full support for both signed and unsigned // 64-bit integers, but for right now an int64_t will hold every value we care about - IntLiteral(const Context& context, Position position, int64_t value) - : INHERITED(position, kIntLiteral_Kind, *context.fInt_Type) + IntLiteral(const Context& context, Position position, int64_t value, const Type* type = nullptr) + : INHERITED(position, kIntLiteral_Kind, type ? *type : *context.fInt_Type) , fValue(value) {} - virtual std::string description() const override { + virtual String description() const override { return to_string(fValue); } diff --git a/gfx/skia/skia/src/sksl/ir/SkSLInterfaceBlock.h b/gfx/skia/skia/src/sksl/ir/SkSLInterfaceBlock.h index f1121ed70768..fc6ccecc8d67 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLInterfaceBlock.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLInterfaceBlock.h @@ -4,12 +4,13 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_INTERFACEBLOCK #define SKSL_INTERFACEBLOCK #include "SkSLProgramElement.h" -#include "SkSLVarDeclaration.h" +#include "SkSLSymbolTable.h" +#include "SkSLVarDeclarations.h" namespace SkSL { @@ -24,23 +25,43 @@ namespace SkSL { * At the IR level, this is represented by a single variable of struct type. */ struct InterfaceBlock : public ProgramElement { - InterfaceBlock(Position position, const Variable& var, std::shared_ptr typeOwner) - : INHERITED(position, kInterfaceBlock_Kind) - , fVariable(std::move(var)) - , fTypeOwner(typeOwner) { - ASSERT(fVariable.fType.kind() == Type::kStruct_Kind); - } + InterfaceBlock(Position position, const Variable* var, String typeName, String instanceName, + std::vector> sizes, + std::shared_ptr typeOwner) + : INHERITED(position, kInterfaceBlock_Kind) + , fVariable(*var) + , fTypeName(std::move(typeName)) + , fInstanceName(std::move(instanceName)) + , fSizes(std::move(sizes)) + , fTypeOwner(typeOwner) {} - std::string description() const override { - std::string result = fVariable.fModifiers.description() + fVariable.fName + " {\n"; - for (size_t i = 0; i < fVariable.fType.fields().size(); i++) { - result += fVariable.fType.fields()[i].description() + "\n"; + String description() const override { + String result = fVariable.fModifiers.description() + fTypeName + " {\n"; + const Type* structType = &fVariable.fType; + while (structType->kind() == Type::kArray_Kind) { + structType = &structType->componentType(); } - result += "};"; - return result; + for (const auto& f : structType->fields()) { + result += f.description() + "\n"; + } + result += "}"; + if (fInstanceName.size()) { + result += " " + fInstanceName; + for (const auto& size : fSizes) { + result += "["; + if (size) { + result += size->description(); + } + result += "]"; + } + } + return result + ";"; } const Variable& fVariable; + const String fTypeName; + const String fInstanceName; + const std::vector> fSizes; const std::shared_ptr fTypeOwner; typedef ProgramElement INHERITED; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLLayout.h b/gfx/skia/skia/src/sksl/ir/SkSLLayout.h index d8dc98096fa7..3a8416ac4eb8 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLLayout.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLLayout.h @@ -4,10 +4,12 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_LAYOUT #define SKSL_LAYOUT +#include "SkSLUtil.h" + namespace SkSL { /** @@ -16,29 +18,123 @@ namespace SkSL { * layout (location = 0) int x; */ struct Layout { - Layout(const ASTLayout& layout) - : fLocation(layout.fLocation) - , fBinding(layout.fBinding) - , fIndex(layout.fIndex) - , fSet(layout.fSet) - , fBuiltin(layout.fBuiltin) - , fOriginUpperLeft(layout.fOriginUpperLeft) {} + enum Primitive { + kUnspecified_Primitive = -1, + kPoints_Primitive, + kLines_Primitive, + kLineStrip_Primitive, + kLinesAdjacency_Primitive, + kTriangles_Primitive, + kTriangleStrip_Primitive, + kTrianglesAdjacency_Primitive + }; - Layout(int location, int binding, int index, int set, int builtin, bool originUpperLeft) + // These are used by images in GLSL. We only support a subset of what GL supports. + enum class Format { + kUnspecified = -1, + kRGBA32F, + kR32F, + kRGBA16F, + kR16F, + kRGBA8, + kR8, + kRGBA8I, + kR8I, + }; + + static const char* FormatToStr(Format format) { + switch (format) { + case Format::kUnspecified: return ""; + case Format::kRGBA32F: return "rgba32f"; + case Format::kR32F: return "r32f"; + case Format::kRGBA16F: return "rgba16f"; + case Format::kR16F: return "r16f"; + case Format::kRGBA8: return "rgba8"; + case Format::kR8: return "r8"; + case Format::kRGBA8I: return "rgba8i"; + case Format::kR8I: return "r8i"; + } + ABORT("Unexpected format"); + return ""; + } + + static bool ReadFormat(String str, Format* format) { + if (str == "rgba32f") { + *format = Format::kRGBA32F; + return true; + } else if (str == "r32f") { + *format = Format::kR32F; + return true; + } else if (str == "rgba16f") { + *format = Format::kRGBA16F; + return true; + } else if (str == "r16f") { + *format = Format::kR16F; + return true; + } else if (str == "rgba8") { + *format = Format::kRGBA8; + return true; + } else if (str == "r8") { + *format = Format::kR8; + return true; + } else if (str == "rgba8i") { + *format = Format::kRGBA8I; + return true; + } else if (str == "r8i") { + *format = Format::kR8I; + return true; + } + return false; + } + + Layout(int location, int offset, int binding, int index, int set, int builtin, + int inputAttachmentIndex, bool originUpperLeft, bool overrideCoverage, + bool blendSupportAllEquations, Format format, bool pushconstant, Primitive primitive, + int maxVertices, int invocations) : fLocation(location) + , fOffset(offset) , fBinding(binding) , fIndex(index) , fSet(set) , fBuiltin(builtin) - , fOriginUpperLeft(originUpperLeft) {} + , fInputAttachmentIndex(inputAttachmentIndex) + , fOriginUpperLeft(originUpperLeft) + , fOverrideCoverage(overrideCoverage) + , fBlendSupportAllEquations(blendSupportAllEquations) + , fFormat(format) + , fPushConstant(pushconstant) + , fPrimitive(primitive) + , fMaxVertices(maxVertices) + , fInvocations(invocations) {} - std::string description() const { - std::string result; - std::string separator; + Layout() + : fLocation(-1) + , fOffset(-1) + , fBinding(-1) + , fIndex(-1) + , fSet(-1) + , fBuiltin(-1) + , fInputAttachmentIndex(-1) + , fOriginUpperLeft(false) + , fOverrideCoverage(false) + , fBlendSupportAllEquations(false) + , fFormat(Format::kUnspecified) + , fPushConstant(false) + , fPrimitive(kUnspecified_Primitive) + , fMaxVertices(-1) + , fInvocations(-1) {} + + String description() const { + String result; + String separator; if (fLocation >= 0) { result += separator + "location = " + to_string(fLocation); separator = ", "; } + if (fOffset >= 0) { + result += separator + "offset = " + to_string(fOffset); + separator = ", "; + } if (fBinding >= 0) { result += separator + "binding = " + to_string(fBinding); separator = ", "; @@ -55,36 +151,116 @@ struct Layout { result += separator + "builtin = " + to_string(fBuiltin); separator = ", "; } + if (fInputAttachmentIndex >= 0) { + result += separator + "input_attachment_index = " + to_string(fBuiltin); + separator = ", "; + } if (fOriginUpperLeft) { result += separator + "origin_upper_left"; separator = ", "; } - if (result.length() > 0) { + if (fOverrideCoverage) { + result += separator + "override_coverage"; + separator = ", "; + } + if (fBlendSupportAllEquations) { + result += separator + "blend_support_all_equations"; + separator = ", "; + } + if (Format::kUnspecified != fFormat) { + result += separator + FormatToStr(fFormat); + separator = ", "; + } + if (fPushConstant) { + result += separator + "push_constant"; + separator = ", "; + } + switch (fPrimitive) { + case kPoints_Primitive: + result += separator + "points"; + separator = ", "; + break; + case kLines_Primitive: + result += separator + "lines"; + separator = ", "; + break; + case kLineStrip_Primitive: + result += separator + "line_strip"; + separator = ", "; + break; + case kLinesAdjacency_Primitive: + result += separator + "lines_adjacency"; + separator = ", "; + break; + case kTriangles_Primitive: + result += separator + "triangles"; + separator = ", "; + break; + case kTriangleStrip_Primitive: + result += separator + "triangle_strip"; + separator = ", "; + break; + case kTrianglesAdjacency_Primitive: + result += separator + "triangles_adjacency"; + separator = ", "; + break; + case kUnspecified_Primitive: + break; + } + if (fMaxVertices >= 0) { + result += separator + "max_vertices = " + to_string(fMaxVertices); + separator = ", "; + } + if (fInvocations >= 0) { + result += separator + "invocations = " + to_string(fInvocations); + separator = ", "; + } + if (result.size() > 0) { result = "layout (" + result + ")"; } return result; } bool operator==(const Layout& other) const { - return fLocation == other.fLocation && - fBinding == other.fBinding && - fIndex == other.fIndex && - fSet == other.fSet && - fBuiltin == other.fBuiltin; + return fLocation == other.fLocation && + fOffset == other.fOffset && + fBinding == other.fBinding && + fIndex == other.fIndex && + fSet == other.fSet && + fBuiltin == other.fBuiltin && + fInputAttachmentIndex == other.fInputAttachmentIndex && + fOriginUpperLeft == other.fOriginUpperLeft && + fOverrideCoverage == other.fOverrideCoverage && + fBlendSupportAllEquations == other.fBlendSupportAllEquations && + fFormat == other.fFormat && + fPrimitive == other.fPrimitive && + fMaxVertices == other.fMaxVertices && + fInvocations == other.fInvocations; } bool operator!=(const Layout& other) const { return !(*this == other); } - // everything but builtin is in the GLSL spec; builtin comes from SPIR-V and identifies which - // particular builtin value this object represents. int fLocation; + int fOffset; int fBinding; int fIndex; int fSet; + // builtin comes from SPIR-V and identifies which particular builtin value this object + // represents. int fBuiltin; + // input_attachment_index comes from Vulkan/SPIR-V to connect a shader variable to the a + // corresponding attachment on the subpass in which the shader is being used. + int fInputAttachmentIndex; bool fOriginUpperLeft; + bool fOverrideCoverage; + bool fBlendSupportAllEquations; + Format fFormat; + bool fPushConstant; + Primitive fPrimitive; + int fMaxVertices; + int fInvocations; }; } // namespace diff --git a/gfx/skia/skia/src/sksl/ir/SkSLModifiers.h b/gfx/skia/skia/src/sksl/ir/SkSLModifiers.h index f39e92959f99..9fae5b098c11 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLModifiers.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLModifiers.h @@ -4,42 +4,46 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_MODIFIERS #define SKSL_MODIFIERS -#include "../ast/SkSLASTModifiers.h" #include "SkSLLayout.h" namespace SkSL { /** - * A set of modifier keywords (in, out, uniform, etc.) appearing before a declaration. + * A set of modifier keywords (in, out, uniform, etc.) appearing before a declaration. */ struct Modifiers { enum Flag { - kNo_Flag = ASTModifiers::kNo_Flag, - kConst_Flag = ASTModifiers::kConst_Flag, - kIn_Flag = ASTModifiers::kIn_Flag, - kOut_Flag = ASTModifiers::kOut_Flag, - kLowp_Flag = ASTModifiers::kLowp_Flag, - kMediump_Flag = ASTModifiers::kMediump_Flag, - kHighp_Flag = ASTModifiers::kHighp_Flag, - kUniform_Flag = ASTModifiers::kUniform_Flag, - kFlat_Flag = ASTModifiers::kFlat_Flag, - kNoPerspective_Flag = ASTModifiers::kNoPerspective_Flag + kNo_Flag = 0, + kConst_Flag = 1, + kIn_Flag = 2, + kOut_Flag = 4, + kLowp_Flag = 8, + kMediump_Flag = 16, + kHighp_Flag = 32, + kUniform_Flag = 64, + kFlat_Flag = 128, + kNoPerspective_Flag = 256, + kReadOnly_Flag = 512, + kWriteOnly_Flag = 1024, + kCoherent_Flag = 2048, + kVolatile_Flag = 4096, + kRestrict_Flag = 8192 }; - Modifiers(const ASTModifiers& modifiers) - : fLayout(modifiers.fLayout) - , fFlags(modifiers.fFlags) {} + Modifiers() + : fLayout(Layout()) + , fFlags(0) {} Modifiers(Layout& layout, int flags) : fLayout(layout) , fFlags(flags) {} - std::string description() const { - std::string result = fLayout.description(); + String description() const { + String result = fLayout.description(); if (fFlags & kUniform_Flag) { result += "uniform "; } @@ -61,6 +65,21 @@ struct Modifiers { if (fFlags & kNoPerspective_Flag) { result += "noperspective "; } + if (fFlags & kReadOnly_Flag) { + result += "readonly "; + } + if (fFlags & kWriteOnly_Flag) { + result += "writeonly "; + } + if (fFlags & kCoherent_Flag) { + result += "coherent "; + } + if (fFlags & kVolatile_Flag) { + result += "volatile "; + } + if (fFlags & kRestrict_Flag) { + result += "restrict "; + } if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) { result += "inout "; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLModifiersDeclaration.h b/gfx/skia/skia/src/sksl/ir/SkSLModifiersDeclaration.h new file mode 100644 index 000000000000..a0ce74852dca --- /dev/null +++ b/gfx/skia/skia/src/sksl/ir/SkSLModifiersDeclaration.h @@ -0,0 +1,37 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_MODIFIERDECLARATION +#define SKSL_MODIFIERDECLARATION + +#include "SkSLProgramElement.h" +#include "SkSLModifiers.h" + +namespace SkSL { + +/** + * A declaration that consists only of modifiers, e.g.: + * + * layout(blend_support_all_equations) out; + */ +struct ModifiersDeclaration : public ProgramElement { + ModifiersDeclaration(Modifiers modifiers) + : INHERITED(Position(), kModifiers_Kind) + , fModifiers(modifiers) {} + + String description() const { + return fModifiers.description() + ";"; + } + + Modifiers fModifiers; + + typedef ProgramElement INHERITED; +}; + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/ir/SkSLPostfixExpression.h b/gfx/skia/skia/src/sksl/ir/SkSLPostfixExpression.h index de146ac43c90..2c84af72fdb6 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLPostfixExpression.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLPostfixExpression.h @@ -4,11 +4,12 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_POSTFIXEXPRESSION #define SKSL_POSTFIXEXPRESSION #include "SkSLExpression.h" +#include "SkSLToken.h" namespace SkSL { @@ -21,11 +22,11 @@ struct PostfixExpression : public Expression { , fOperand(std::move(operand)) , fOperator(op) {} - virtual std::string description() const override { + virtual String description() const override { return fOperand->description() + Token::OperatorName(fOperator); } - const std::unique_ptr fOperand; + std::unique_ptr fOperand; const Token::Kind fOperator; typedef Expression INHERITED; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.h b/gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.h index 53c3849b38f1..4fa54ca32dbb 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.h @@ -4,11 +4,12 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_PREFIXEXPRESSION #define SKSL_PREFIXEXPRESSION #include "SkSLExpression.h" +#include "SkSLToken.h" namespace SkSL { @@ -21,11 +22,11 @@ struct PrefixExpression : public Expression { , fOperand(std::move(operand)) , fOperator(op) {} - virtual std::string description() const override { + virtual String description() const override { return Token::OperatorName(fOperator) + fOperand->description(); } - const std::unique_ptr fOperand; + std::unique_ptr fOperand; const Token::Kind fOperator; typedef Expression INHERITED; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLProgram.h b/gfx/skia/skia/src/sksl/ir/SkSLProgram.h index 205db6e93209..96bd5c4fbdd2 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLProgram.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLProgram.h @@ -4,37 +4,87 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_PROGRAM #define SKSL_PROGRAM #include #include +#include "SkSLContext.h" +#include "SkSLModifiers.h" #include "SkSLProgramElement.h" #include "SkSLSymbolTable.h" +// name of the render target height uniform +#define SKSL_RTHEIGHT_NAME "u_skRTHeight" + namespace SkSL { /** * Represents a fully-digested program, ready for code generation. */ struct Program { - enum Kind { - kFragment_Kind, - kVertex_Kind + struct Settings { +#ifdef SKSL_STANDALONE + const StandaloneShaderCaps* fCaps = &standaloneCaps; +#else + const GrShaderCaps* fCaps = nullptr; +#endif + // if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the y coordinate + // must be flipped. + bool fFlipY = false; }; - Program(Kind kind, std::vector> elements, - std::shared_ptr symbols) - : fKind(kind) + struct Inputs { + // if true, this program requires the render target height uniform to be defined + bool fRTHeight; + + // if true, this program must be recompiled if the flipY setting changes. If false, the + // program will compile to the same code regardless of the flipY setting. + bool fFlipY; + + void reset() { + fRTHeight = false; + fFlipY = false; + } + + bool isEmpty() { + return !fRTHeight && !fFlipY; + } + }; + + enum Kind { + kFragment_Kind, + kVertex_Kind, + kGeometry_Kind + }; + + Program(Kind kind, + Settings settings, + Modifiers::Flag defaultPrecision, + Context* context, + std::vector> elements, + std::shared_ptr symbols, + Inputs inputs) + : fKind(kind) + , fSettings(settings) + , fDefaultPrecision(defaultPrecision) + , fContext(context) + , fSymbols(symbols) , fElements(std::move(elements)) - , fSymbols(symbols) {} + , fInputs(inputs) {} Kind fKind; - - std::vector> fElements; + Settings fSettings; + // FIXME handle different types; currently it assumes this is for floats + Modifiers::Flag fDefaultPrecision; + Context* fContext; + // it's important to keep fElements defined after (and thus destroyed before) fSymbols, + // because destroying elements can modify reference counts in symbols std::shared_ptr fSymbols; + std::vector> fElements; + Inputs fInputs; }; } // namespace diff --git a/gfx/skia/skia/src/sksl/ir/SkSLProgramElement.h b/gfx/skia/skia/src/sksl/ir/SkSLProgramElement.h index 44fc34066763..ebb4e9a84dc6 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLProgramElement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLProgramElement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_PROGRAMELEMENT #define SKSL_PROGRAMELEMENT @@ -20,7 +20,8 @@ struct ProgramElement : public IRNode { kVar_Kind, kFunction_Kind, kInterfaceBlock_Kind, - kExtension_Kind + kExtension_Kind, + kModifiers_Kind }; ProgramElement(Position position, Kind kind) diff --git a/gfx/skia/skia/src/sksl/ir/SkSLReturnStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLReturnStatement.h index ec2226cc5615..841db9466920 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLReturnStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLReturnStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_RETURNSTATEMENT #define SKSL_RETURNSTATEMENT @@ -21,18 +21,18 @@ struct ReturnStatement : public Statement { : INHERITED(position, kReturn_Kind) {} ReturnStatement(std::unique_ptr expression) - : INHERITED(expression->fPosition, kReturn_Kind) + : INHERITED(expression->fPosition, kReturn_Kind) , fExpression(std::move(expression)) {} - std::string description() const override { + String description() const override { if (fExpression) { return "return " + fExpression->description() + ";"; } else { - return "return;"; + return String("return;"); } } - const std::unique_ptr fExpression; + std::unique_ptr fExpression; typedef Statement INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLStatement.h index 012311fdd3c1..ba1a08772ed8 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_STATEMENT #define SKSL_STATEMENT @@ -27,6 +27,7 @@ struct Statement : public IRNode { kFor_Kind, kIf_Kind, kReturn_Kind, + kSwitch_Kind, kVarDeclarations_Kind, kWhile_Kind }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLSwitchCase.h b/gfx/skia/skia/src/sksl/ir/SkSLSwitchCase.h new file mode 100644 index 000000000000..8043f2e787d9 --- /dev/null +++ b/gfx/skia/skia/src/sksl/ir/SkSLSwitchCase.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_SWITCHCASE +#define SKSL_SWITCHCASE + +#include "SkSLExpression.h" +#include "SkSLStatement.h" + +namespace SkSL { + +/** + * A single case of a 'switch' statement. + */ +struct SwitchCase : public Statement { + SwitchCase(Position position, std::unique_ptr value, + std::vector> statements) + : INHERITED(position, kSwitch_Kind) + , fValue(std::move(value)) + , fStatements(std::move(statements)) {} + + String description() const override { + String result; + if (fValue) { + result.appendf("case %s:\n", fValue->description().c_str()); + } else { + result += "default:\n"; + } + for (const auto& s : fStatements) { + result += s->description() + "\n"; + } + return result; + } + + // null value implies "default" case + std::unique_ptr fValue; + std::vector> fStatements; + + typedef Statement INHERITED; +}; + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/ir/SkSLSwitchStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLSwitchStatement.h new file mode 100644 index 000000000000..88e1e70019f8 --- /dev/null +++ b/gfx/skia/skia/src/sksl/ir/SkSLSwitchStatement.h @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_SWITCHSTATEMENT +#define SKSL_SWITCHSTATEMENT + +#include "SkSLStatement.h" +#include "SkSLSwitchCase.h" + +namespace SkSL { + +/** + * A 'switch' statement. + */ +struct SwitchStatement : public Statement { + SwitchStatement(Position position, std::unique_ptr value, + std::vector> cases) + : INHERITED(position, kSwitch_Kind) + , fValue(std::move(value)) + , fCases(std::move(cases)) {} + + String description() const override { + String result = String::printf("switch (%s) {\n", + fValue->description().c_str()); + for (const auto& c : fCases) { + result += c->description(); + } + result += "}"; + return result; + } + + std::unique_ptr fValue; + std::vector> fCases; + + typedef Statement INHERITED; +}; + +} // namespace + +#endif diff --git a/gfx/skia/skia/src/sksl/ir/SkSLSwizzle.h b/gfx/skia/skia/src/sksl/ir/SkSLSwizzle.h index 0eb4a00dcab1..1725ec2b5a16 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLSwizzle.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLSwizzle.h @@ -4,17 +4,18 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_SWIZZLE #define SKSL_SWIZZLE +#include "SkSLContext.h" #include "SkSLExpression.h" #include "SkSLUtil.h" namespace SkSL { /** - * Given a type and a swizzle component count, returns the type that will result from swizzling. For + * Given a type and a swizzle component count, returns the type that will result from swizzling. For * instance, swizzling a vec3 with two components will result in a vec2. It is possible to swizzle * with more components than the source vector, as in 'vec2(1).xxxx'. */ @@ -68,15 +69,15 @@ struct Swizzle : public Expression { ASSERT(fComponents.size() >= 1 && fComponents.size() <= 4); } - std::string description() const override { - std::string result = fBase->description() + "."; + String description() const override { + String result = fBase->description() + "."; for (int x : fComponents) { result += "xyzw"[x]; } return result; } - const std::unique_ptr fBase; + std::unique_ptr fBase; const std::vector fComponents; typedef Expression INHERITED; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLSymbol.h b/gfx/skia/skia/src/sksl/ir/SkSLSymbol.h index d736516bc463..e883ea7555e5 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLSymbol.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLSymbol.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_SYMBOL #define SKSL_SYMBOL @@ -24,13 +24,13 @@ struct Symbol : public IRNode { kField_Kind }; - Symbol(Position position, Kind kind, std::string name) + Symbol(Position position, Kind kind, String name) : INHERITED(position) , fKind(kind) , fName(std::move(name)) {} const Kind fKind; - const std::string fName; + const String fName; typedef IRNode INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.cpp b/gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.cpp index 9d8c0063c555..4d39e8bc9dc0 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.cpp +++ b/gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.cpp @@ -21,7 +21,7 @@ std::vector SymbolTable::GetFunctions(const Symbol& } } -const Symbol* SymbolTable::operator[](const std::string& name) { +const Symbol* SymbolTable::operator[](const String& name) { const auto& entry = fSymbols.find(name); if (entry == fSymbols.end()) { if (fParent) { @@ -64,12 +64,12 @@ Symbol* SymbolTable::takeOwnership(Symbol* s) { return s; } -void SymbolTable::add(const std::string& name, std::unique_ptr symbol) { +void SymbolTable::add(const String& name, std::unique_ptr symbol) { this->addWithoutOwnership(name, symbol.get()); fOwnedPointers.push_back(std::move(symbol)); } -void SymbolTable::addWithoutOwnership(const std::string& name, const Symbol* symbol) { +void SymbolTable::addWithoutOwnership(const String& name, const Symbol* symbol) { const auto& existing = fSymbols.find(name); if (existing == fSymbols.end()) { fSymbols[name] = symbol; @@ -97,4 +97,22 @@ void SymbolTable::addWithoutOwnership(const std::string& name, const Symbol* sym } } + +void SymbolTable::markAllFunctionsBuiltin() { + for (const auto& pair : fSymbols) { + switch (pair.second->fKind) { + case Symbol::kFunctionDeclaration_Kind: + ((FunctionDeclaration&) *pair.second).fBuiltin = true; + break; + case Symbol::kUnresolvedFunction_Kind: + for (auto& f : ((UnresolvedFunction&) *pair.second).fFunctions) { + ((FunctionDeclaration*) f)->fBuiltin = true; + } + break; + default: + break; + } + } +} + } // namespace diff --git a/gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.h b/gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.h index d732023ff091..6bafef259df5 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_SYMBOLTABLE #define SKSL_SYMBOLTABLE @@ -24,21 +24,23 @@ struct FunctionDeclaration; */ class SymbolTable { public: - SymbolTable(ErrorReporter& errorReporter) - : fErrorReporter(errorReporter) {} + SymbolTable(ErrorReporter* errorReporter) + : fErrorReporter(*errorReporter) {} - SymbolTable(std::shared_ptr parent, ErrorReporter& errorReporter) + SymbolTable(std::shared_ptr parent, ErrorReporter* errorReporter) : fParent(parent) - , fErrorReporter(errorReporter) {} + , fErrorReporter(*errorReporter) {} - const Symbol* operator[](const std::string& name); + const Symbol* operator[](const String& name); - void add(const std::string& name, std::unique_ptr symbol); + void add(const String& name, std::unique_ptr symbol); - void addWithoutOwnership(const std::string& name, const Symbol* symbol); + void addWithoutOwnership(const String& name, const Symbol* symbol); Symbol* takeOwnership(Symbol* s); + void markAllFunctionsBuiltin(); + const std::shared_ptr fParent; private: @@ -46,7 +48,7 @@ private: std::vector> fOwnedPointers; - std::unordered_map fSymbols; + std::unordered_map fSymbols; ErrorReporter& fErrorReporter; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLTernaryExpression.h b/gfx/skia/skia/src/sksl/ir/SkSLTernaryExpression.h index bfaf304e55d9..9fbac19c25a3 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLTernaryExpression.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLTernaryExpression.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_TERNARYEXPRESSION #define SKSL_TERNARYEXPRESSION @@ -26,14 +26,14 @@ struct TernaryExpression : public Expression { ASSERT(fIfTrue->fType == fIfFalse->fType); } - std::string description() const override { - return "(" + fTest->description() + " ? " + fIfTrue->description() + " : " + + String description() const override { + return "(" + fTest->description() + " ? " + fIfTrue->description() + " : " + fIfFalse->description() + ")"; } - const std::unique_ptr fTest; - const std::unique_ptr fIfTrue; - const std::unique_ptr fIfFalse; + std::unique_ptr fTest; + std::unique_ptr fIfTrue; + std::unique_ptr fIfFalse; typedef Expression INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLType.cpp b/gfx/skia/skia/src/sksl/ir/SkSLType.cpp index d28c4f0666a7..c919cbc8ae07 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLType.cpp +++ b/gfx/skia/skia/src/sksl/ir/SkSLType.cpp @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #include "SkSLType.h" #include "SkSLContext.h" @@ -22,7 +22,7 @@ bool Type::determineCoercionCost(const Type& other, int* outCost) const { return false; } if (this->kind() == kMatrix_Kind) { - if (this->columns() == other.columns() && + if (this->columns() == other.columns() && this->rows() == other.rows()) { return this->componentType().determineCoercionCost(other.componentType(), outCost); } diff --git a/gfx/skia/skia/src/sksl/ir/SkSLType.h b/gfx/skia/skia/src/sksl/ir/SkSLType.h index ad2185b4ee18..44bc26272b8a 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLType.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLType.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKIASL_TYPE #define SKIASL_TYPE @@ -26,17 +26,17 @@ class Context; class Type : public Symbol { public: struct Field { - Field(Modifiers modifiers, std::string name, const Type* type) + Field(Modifiers modifiers, String name, const Type* type) : fModifiers(modifiers) , fName(std::move(name)) , fType(std::move(type)) {} - const std::string description() const { + const String description() const { return fType->description() + " " + fName + ";"; } Modifiers fModifiers; - std::string fName; + String fName; const Type* fType; }; @@ -51,28 +51,26 @@ public: kOther_Kind }; - // Create an "other" (special) type with the given name. These types cannot be directly + // Create an "other" (special) type with the given name. These types cannot be directly // referenced from user code. - Type(std::string name) + Type(String name) : INHERITED(Position(), kType_Kind, std::move(name)) , fTypeKind(kOther_Kind) {} // Create a generic type which maps to the listed types. - Type(std::string name, std::vector types) + Type(String name, std::vector types) : INHERITED(Position(), kType_Kind, std::move(name)) , fTypeKind(kGeneric_Kind) - , fCoercibleTypes(std::move(types)) { - ASSERT(fCoercibleTypes.size() == 4); - } + , fCoercibleTypes(std::move(types)) {} // Create a struct type with the given fields. - Type(std::string name, std::vector fields) - : INHERITED(Position(), kType_Kind, std::move(name)) + Type(Position position, String name, std::vector fields) + : INHERITED(position, kType_Kind, std::move(name)) , fTypeKind(kStruct_Kind) , fFields(std::move(fields)) {} // Create a scalar type. - Type(std::string name, bool isNumber) + Type(String name, bool isNumber) : INHERITED(Position(), kType_Kind, std::move(name)) , fTypeKind(kScalar_Kind) , fIsNumber(isNumber) @@ -80,7 +78,7 @@ public: , fRows(1) {} // Create a scalar type which can be coerced to the listed types. - Type(std::string name, bool isNumber, std::vector coercibleTypes) + Type(String name, bool isNumber, std::vector coercibleTypes) : INHERITED(Position(), kType_Kind, std::move(name)) , fTypeKind(kScalar_Kind) , fIsNumber(isNumber) @@ -89,30 +87,30 @@ public: , fRows(1) {} // Create a vector type. - Type(std::string name, const Type& componentType, int columns) + Type(String name, const Type& componentType, int columns) : Type(name, kVector_Kind, componentType, columns) {} // Create a vector or array type. - Type(std::string name, Kind kind, const Type& componentType, int columns) + Type(String name, Kind kind, const Type& componentType, int columns) : INHERITED(Position(), kType_Kind, std::move(name)) , fTypeKind(kind) , fComponentType(&componentType) , fColumns(columns) - , fRows(1) + , fRows(1) , fDimensions(SpvDim1D) {} // Create a matrix type. - Type(std::string name, const Type& componentType, int columns, int rows) + Type(String name, const Type& componentType, int columns, int rows) : INHERITED(Position(), kType_Kind, std::move(name)) , fTypeKind(kMatrix_Kind) , fComponentType(&componentType) , fColumns(columns) - , fRows(rows) + , fRows(rows) , fDimensions(SpvDim1D) {} // Create a sampler type. - Type(std::string name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled, - bool isSampled) + Type(String name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled, + bool isSampled) : INHERITED(Position(), kType_Kind, std::move(name)) , fTypeKind(kSampler_Kind) , fDimensions(dimensions) @@ -121,11 +119,11 @@ public: , fIsMultisampled(isMultisampled) , fIsSampled(isSampled) {} - std::string name() const { + String name() const { return fName; } - std::string description() const override { + String description() const override { return fName; } @@ -152,7 +150,7 @@ public: } /** - * Returns true if an instance of this type can be freely coerced (implicitly converted) to + * Returns true if an instance of this type can be freely coerced (implicitly converted) to * another type. */ bool canCoerceTo(const Type& other) const { @@ -162,8 +160,8 @@ public: /** * Determines the "cost" of coercing (implicitly converting) this type to another type. The cost - * is a number with no particular meaning other than that lower costs are preferable to higher - * costs. Returns true if a conversion is possible, false otherwise. The value of the out + * is a number with no particular meaning other than that lower costs are preferable to higher + * costs. Returns true if a conversion is possible, false otherwise. The value of the out * parameter is undefined if false is returned. */ bool determineCoercionCost(const Type& other, int* outCost) const; @@ -179,11 +177,11 @@ public: /** * For matrices and vectors, returns the number of columns (e.g. both mat3 and vec3 return 3). - * For scalars, returns 1. For arrays, returns either the size of the array (if known) or -1. + * For scalars, returns 1. For arrays, returns either the size of the array (if known) or -1. * For all other types, causes an assertion failure. */ int columns() const { - ASSERT(fTypeKind == kScalar_Kind || fTypeKind == kVector_Kind || + ASSERT(fTypeKind == kScalar_Kind || fTypeKind == kVector_Kind || fTypeKind == kMatrix_Kind || fTypeKind == kArray_Kind); return fColumns; } @@ -211,114 +209,33 @@ public: return fCoercibleTypes; } - int dimensions() const { - ASSERT(fTypeKind == kSampler_Kind); + SpvDim_ dimensions() const { + ASSERT(kSampler_Kind == fTypeKind); return fDimensions; } bool isDepth() const { - ASSERT(fTypeKind == kSampler_Kind); + ASSERT(kSampler_Kind == fTypeKind); return fIsDepth; } bool isArrayed() const { - ASSERT(fTypeKind == kSampler_Kind); + ASSERT(kSampler_Kind == fTypeKind); return fIsArrayed; } bool isMultisampled() const { - ASSERT(fTypeKind == kSampler_Kind); + ASSERT(kSampler_Kind == fTypeKind); return fIsMultisampled; } bool isSampled() const { - ASSERT(fTypeKind == kSampler_Kind); + ASSERT(kSampler_Kind == fTypeKind); return fIsSampled; } - static size_t vector_alignment(size_t componentSize, int columns) { - return componentSize * (columns + columns % 2); - } - /** - * Returns the type's required alignment (when putting this type into a struct, the offset must - * be a multiple of the alignment). - */ - size_t alignment() const { - // See OpenGL Spec 7.6.2.2 Standard Uniform Block Layout - switch (fTypeKind) { - case kScalar_Kind: - return this->size(); - case kVector_Kind: - return vector_alignment(fComponentType->size(), fColumns); - case kMatrix_Kind: - return (vector_alignment(fComponentType->size(), fRows) + 15) & ~15; - case kArray_Kind: - // round up to next multiple of 16 - return (fComponentType->alignment() + 15) & ~15; - case kStruct_Kind: { - size_t result = 16; - for (size_t i = 0; i < fFields.size(); i++) { - size_t alignment = fFields[i].fType->alignment(); - if (alignment > result) { - result = alignment; - } - } - } - default: - ABORT(("cannot determine size of type " + fName).c_str()); - } - } - - /** - * For matrices and arrays, returns the number of bytes from the start of one entry (row, in - * the case of matrices) to the start of the next. - */ - size_t stride() const { - switch (fTypeKind) { - case kMatrix_Kind: // fall through - case kArray_Kind: - return this->alignment(); - default: - ABORT("type does not have a stride"); - } - } - - /** - * Returns the size of this type in bytes. - */ - size_t size() const { - switch (fTypeKind) { - case kScalar_Kind: - // FIXME need to take precision into account, once we figure out how we want to - // handle it... - return 4; - case kVector_Kind: - return fColumns * fComponentType->size(); - case kMatrix_Kind: - return vector_alignment(fComponentType->size(), fRows) * fColumns; - case kArray_Kind: - return fColumns * this->stride(); - case kStruct_Kind: { - size_t total = 0; - for (size_t i = 0; i < fFields.size(); i++) { - size_t alignment = fFields[i].fType->alignment(); - if (total % alignment != 0) { - total += alignment - total % alignment; - } - ASSERT(false); - ASSERT(total % alignment == 0); - total += fFields[i].fType->size(); - } - return total; - } - default: - ABORT(("cannot determine size of type " + fName).c_str()); - } - } - - /** - * Returns the corresponding vector or matrix type with the specified number of columns and + * Returns the corresponding vector or matrix type with the specified number of columns and * rows. */ const Type& toCompound(const Context& context, int columns, int rows) const; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLTypeReference.h b/gfx/skia/skia/src/sksl/ir/SkSLTypeReference.h index 10f36aa24856..b12c185ce205 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLTypeReference.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLTypeReference.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_TYPEREFERENCE #define SKSL_TYPEREFERENCE @@ -14,7 +14,7 @@ namespace SkSL { /** - * Represents an identifier referring to a type. This is an intermediate value: TypeReferences are + * Represents an identifier referring to a type. This is an intermediate value: TypeReferences are * always eventually replaced by Constructors in valid programs. */ struct TypeReference : public Expression { @@ -22,9 +22,8 @@ struct TypeReference : public Expression { : INHERITED(position, kTypeReference_Kind, *context.fInvalid_Type) , fValue(type) {} - std::string description() const override { - ASSERT(false); - return ""; + String description() const override { + return fValue.name(); } const Type& fValue; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLUnresolvedFunction.h b/gfx/skia/skia/src/sksl/ir/SkSLUnresolvedFunction.h index 7e8a3601e86f..c5fdbd073402 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLUnresolvedFunction.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLUnresolvedFunction.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_UNRESOLVEDFUNCTION #define SKSL_UNRESOLVEDFUNCTION @@ -26,7 +26,7 @@ struct UnresolvedFunction : public Symbol { #endif } - virtual std::string description() const override { + virtual String description() const override { return fName; } diff --git a/gfx/skia/skia/src/sksl/ir/SkSLVarDeclaration.h b/gfx/skia/skia/src/sksl/ir/SkSLVarDeclarations.h similarity index 78% rename from gfx/skia/skia/src/sksl/ir/SkSLVarDeclaration.h rename to gfx/skia/skia/src/sksl/ir/SkSLVarDeclarations.h index e64a874d69df..5a006bd133d2 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLVarDeclaration.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLVarDeclarations.h @@ -4,11 +4,12 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_VARDECLARATIONS #define SKSL_VARDECLARATIONS #include "SkSLExpression.h" +#include "SkSLProgramElement.h" #include "SkSLStatement.h" #include "SkSLVariable.h" @@ -16,7 +17,7 @@ namespace SkSL { /** * A single variable declaration within a var declaration statement. For instance, the statement - * 'int x = 2, y[3];' is a VarDeclarations statement containing two individual VarDeclaration + * 'int x = 2, y[3];' is a VarDeclarations statement containing two individual VarDeclaration * instances. */ struct VarDeclaration { @@ -27,8 +28,8 @@ struct VarDeclaration { , fSizes(std::move(sizes)) , fValue(std::move(value)) {} - std::string description() const { - std::string result = fVar->fName; + String description() const { + String result = fVar->fName; for (const auto& size : fSizes) { if (size) { result += "[" + size->description() + "]"; @@ -39,7 +40,7 @@ struct VarDeclaration { if (fValue) { result += " = " + fValue->description(); } - return result; + return result; } const Variable* fVar; @@ -51,19 +52,18 @@ struct VarDeclaration { * A variable declaration statement, which may consist of one or more individual variables. */ struct VarDeclarations : public ProgramElement { - VarDeclarations(Position position, const Type* baseType, + VarDeclarations(Position position, const Type* baseType, std::vector vars) : INHERITED(position, kVar_Kind) , fBaseType(*baseType) , fVars(std::move(vars)) {} - std::string description() const override { + String description() const override { if (!fVars.size()) { - return ""; + return String(); } - std::string result = fVars[0].fVar->fModifiers.description() + fBaseType.description() + - " "; - std::string separator = ""; + String result = fVars[0].fVar->fModifiers.description() + fBaseType.description() + " "; + String separator; for (const auto& var : fVars) { result += separator; separator = ", "; @@ -73,7 +73,7 @@ struct VarDeclarations : public ProgramElement { } const Type& fBaseType; - const std::vector fVars; + std::vector fVars; typedef ProgramElement INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLVarDeclarationStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLVarDeclarationsStatement.h similarity index 67% rename from gfx/skia/skia/src/sksl/ir/SkSLVarDeclarationStatement.h rename to gfx/skia/skia/src/sksl/ir/SkSLVarDeclarationsStatement.h index 59d37ab91589..50365decc16e 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLVarDeclarationStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLVarDeclarationsStatement.h @@ -4,12 +4,12 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - -#ifndef SKSL_VARDECLARATIONSTATEMENT -#define SKSL_VARDECLARATIONSTATEMENT + +#ifndef SKSL_VARDECLARATIONSSTATEMENT +#define SKSL_VARDECLARATIONSSTATEMENT #include "SkSLStatement.h" -#include "SkSLVarDeclaration.h" +#include "SkSLVarDeclarations.h" namespace SkSL { @@ -18,14 +18,14 @@ namespace SkSL { */ struct VarDeclarationsStatement : public Statement { VarDeclarationsStatement(std::unique_ptr decl) - : INHERITED(decl->fPosition, kVarDeclarations_Kind) + : INHERITED(decl->fPosition, kVarDeclarations_Kind) , fDeclaration(std::move(decl)) {} - std::string description() const override { + String description() const override { return fDeclaration->description(); } - const std::shared_ptr fDeclaration; + std::shared_ptr fDeclaration; typedef Statement INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLVariable.h b/gfx/skia/skia/src/sksl/ir/SkSLVariable.h index 217b1006b6ce..21f17bad8e4d 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLVariable.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLVariable.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_VARIABLE #define SKSL_VARIABLE @@ -27,16 +27,16 @@ struct Variable : public Symbol { kParameter_Storage }; - Variable(Position position, Modifiers modifiers, std::string name, const Type& type, + Variable(Position position, Modifiers modifiers, String name, const Type& type, Storage storage) : INHERITED(position, kVariable_Kind, std::move(name)) , fModifiers(modifiers) , fType(type) , fStorage(storage) - , fIsReadFrom(false) - , fIsWrittenTo(false) {} + , fReadCount(0) + , fWriteCount(0) {} - virtual std::string description() const override { + virtual String description() const override { return fModifiers.description() + fType.fName + " " + fName; } @@ -44,8 +44,12 @@ struct Variable : public Symbol { const Type& fType; const Storage fStorage; - mutable bool fIsReadFrom; - mutable bool fIsWrittenTo; + // Tracks how many sites read from the variable. If this is zero for a non-out variable (or + // becomes zero during optimization), the variable is dead and may be eliminated. + mutable int fReadCount; + // Tracks how many sites write to the variable. If this is zero, the variable is dead and may be + // eliminated. + mutable int fWriteCount; typedef Symbol INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLVariableReference.h b/gfx/skia/skia/src/sksl/ir/SkSLVariableReference.h index b443da1f2286..af181f84fd7a 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLVariableReference.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLVariableReference.h @@ -4,11 +4,14 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_VARIABLEREFERENCE #define SKSL_VARIABLEREFERENCE #include "SkSLExpression.h" +#include "SkSLFloatLiteral.h" +#include "SkSLIRGenerator.h" +#include "SkSLIntLiteral.h" namespace SkSL { @@ -20,16 +23,83 @@ namespace SkSL { * there is only one Variable 'x', but two VariableReferences to it. */ struct VariableReference : public Expression { - VariableReference(Position position, const Variable& variable) - : INHERITED(position, kVariableReference_Kind, variable.fType) - , fVariable(variable) {} + enum RefKind { + kRead_RefKind, + kWrite_RefKind, + kReadWrite_RefKind + }; - std::string description() const override { + VariableReference(Position position, const Variable& variable, RefKind refKind = kRead_RefKind) + : INHERITED(position, kVariableReference_Kind, variable.fType) + , fVariable(variable) + , fRefKind(refKind) { + if (refKind != kRead_RefKind) { + fVariable.fWriteCount++; + } + if (refKind != kWrite_RefKind) { + fVariable.fReadCount++; + } + } + + virtual ~VariableReference() override { + if (fRefKind != kWrite_RefKind) { + fVariable.fReadCount--; + } + } + + RefKind refKind() { + return fRefKind; + } + + void setRefKind(RefKind refKind) { + if (fRefKind != kRead_RefKind) { + fVariable.fWriteCount--; + } + if (fRefKind != kWrite_RefKind) { + fVariable.fReadCount--; + } + if (refKind != kRead_RefKind) { + fVariable.fWriteCount++; + } + if (refKind != kWrite_RefKind) { + fVariable.fReadCount++; + } + fRefKind = refKind; + } + + String description() const override { return fVariable.fName; } + virtual std::unique_ptr constantPropagate( + const IRGenerator& irGenerator, + const DefinitionMap& definitions) override { + auto exprIter = definitions.find(&fVariable); + if (exprIter != definitions.end() && exprIter->second) { + const Expression* expr = exprIter->second->get(); + switch (expr->fKind) { + case Expression::kIntLiteral_Kind: + return std::unique_ptr(new IntLiteral( + irGenerator.fContext, + Position(), + ((IntLiteral*) expr)->fValue)); + case Expression::kFloatLiteral_Kind: + return std::unique_ptr(new FloatLiteral( + irGenerator.fContext, + Position(), + ((FloatLiteral*) expr)->fValue)); + default: + break; + } + } + return nullptr; + } + const Variable& fVariable; +private: + RefKind fRefKind; + typedef Expression INHERITED; }; diff --git a/gfx/skia/skia/src/sksl/ir/SkSLWhileStatement.h b/gfx/skia/skia/src/sksl/ir/SkSLWhileStatement.h index 1acb572583b1..c35d6df9e4d3 100644 --- a/gfx/skia/skia/src/sksl/ir/SkSLWhileStatement.h +++ b/gfx/skia/skia/src/sksl/ir/SkSLWhileStatement.h @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #ifndef SKSL_WHILESTATEMENT #define SKSL_WHILESTATEMENT @@ -17,17 +17,17 @@ namespace SkSL { * A 'while' loop. */ struct WhileStatement : public Statement { - WhileStatement(Position position, std::unique_ptr test, + WhileStatement(Position position, std::unique_ptr test, std::unique_ptr statement) : INHERITED(position, kWhile_Kind) , fTest(std::move(test)) , fStatement(std::move(statement)) {} - std::string description() const override { + String description() const override { return "while (" + fTest->description() + ") " + fStatement->description(); } - const std::unique_ptr fTest; + std::unique_ptr fTest; const std::unique_ptr fStatement; typedef Statement INHERITED; diff --git a/gfx/skia/skia/src/sksl/layout.flex b/gfx/skia/skia/src/sksl/layout.flex new file mode 100644 index 000000000000..412bd4707b62 --- /dev/null +++ b/gfx/skia/skia/src/sksl/layout.flex @@ -0,0 +1,61 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + + This file is IGNORED during the build process! + + As this file is updated so infrequently and flex is not universally present on build machines, + the lex.layout.c file must be manually regenerated if you make any changes to this file. Just + run: + + flex layout.flex + + You will have to manually add a copyright notice to the top of lex.layout.c. + +*/ + +%option prefix="layout" +%option reentrant +%option yylineno +%option never-interactive +%option nounistd + +%{ +#include "SkSLToken.h" +%} + +%% + +"location" { return SkSL::Token::LOCATION; } +"offset" { return SkSL::Token::OFFSET; } +"binding" { return SkSL::Token::BINDING; } +"index" { return SkSL::Token::INDEX; } +"set" { return SkSL::Token::SET; } +"builtin" { return SkSL::Token::BUILTIN; } +"input_attachment_index" { return SkSL::Token::INPUT_ATTACHMENT_INDEX; } +"origin_upper_left" { return SkSL::Token::ORIGIN_UPPER_LEFT; } +"override_coverage" { return SkSL::Token::OVERRIDE_COVERAGE; } +"blend_support_all_equations" { return SkSL::Token::BLEND_SUPPORT_ALL_EQUATIONS; } +"push_constant" { return SkSL::Token::PUSH_CONSTANT; } +"points" { return SkSL::Token::POINTS; } +"lines" { return SkSL::Token::LINES; } +"line_strip" { return SkSL::Token::LINE_STRIP; } +"lines_adjacency" { return SkSL::Token::LINES_ADJACENCY; } +"triangles" { return SkSL::Token::TRIANGLES; } +"triangle_strip" { return SkSL::Token::TRIANGLE_STRIP; } +"triangles_adjacency" { return SkSL::Token::TRIANGLES_ADJACENCY; } +"max_vertices" { return SkSL::Token::MAX_VERTICES; } +"invocations" { return SkSL::Token::INVOCATIONS; } + +. { return SkSL::Token::INVALID_TOKEN; } + +%% + +int layoutwrap(yyscan_t scanner) { + return 1; // terminate +} diff --git a/gfx/skia/skia/src/sksl/lex.layout.c b/gfx/skia/skia/src/sksl/lex.layout.c new file mode 100644 index 000000000000..42db0fe5ef8f --- /dev/null +++ b/gfx/skia/skia/src/sksl/lex.layout.c @@ -0,0 +1,2276 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#line 2 "lex.layout.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 3 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + + #define yy_create_buffer layout_create_buffer + + #define yy_delete_buffer layout_delete_buffer + + #define yy_scan_buffer layout_scan_buffer + + #define yy_scan_string layout_scan_string + + #define yy_scan_bytes layout_scan_bytes + + #define yy_init_buffer layout_init_buffer + + #define yy_flush_buffer layout_flush_buffer + + #define yy_load_buffer_state layout_load_buffer_state + + #define yy_switch_to_buffer layout_switch_to_buffer + + #define yypush_buffer_state layoutpush_buffer_state + + #define yypop_buffer_state layoutpop_buffer_state + + #define yyensure_buffer_stack layoutensure_buffer_stack + + #define yylex layoutlex + + #define yyrestart layoutrestart + + #define yylex_init layoutlex_init + + #define yylex_init_extra layoutlex_init_extra + + #define yylex_destroy layoutlex_destroy + + #define yyget_debug layoutget_debug + + #define yyset_debug layoutset_debug + + #define yyget_extra layoutget_extra + + #define yyset_extra layoutset_extra + + #define yyget_in layoutget_in + + #define yyset_in layoutset_in + + #define yyget_out layoutget_out + + #define yyset_out layoutset_out + + #define yyget_leng layoutget_leng + + #define yyget_text layoutget_text + + #define yyget_lineno layoutget_lineno + + #define yyset_lineno layoutset_lineno + + #define yyget_column layoutget_column + + #define yyset_column layoutset_column + + #define yywrap layoutwrap + + #define yyalloc layoutalloc + + #define yyrealloc layoutrealloc + + #define yyfree layoutfree + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE layoutrestart(yyin ,yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE layoutlex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via layoutrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void layoutrestart ( FILE *input_file , yyscan_t yyscanner ); +void layout_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE layout_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void layout_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void layout_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void layoutpush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void layoutpop_buffer_state ( yyscan_t yyscanner ); + +static void layoutensure_buffer_stack ( yyscan_t yyscanner ); +static void layout_load_buffer_state ( yyscan_t yyscanner ); +static void layout_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER layout_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE layout_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE layout_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE layout_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *layoutalloc ( yy_size_t , yyscan_t yyscanner ); +void *layoutrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void layoutfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer layout_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + layoutensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + layout_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + layoutensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + layout_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 22 +#define YY_END_OF_BUFFER 23 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[204] = + { 0, + 0, 0, 23, 21, 22, 21, 21, 21, 21, 21, + 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4, 0, 0, 0, 13, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 12, 0, 0, 3, + 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 16, 0, 0, 0, 14, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, + 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, + 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 7, 0, 0, 0, + + 0, 10, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 1, 4, 5, 6, 7, + + 8, 9, 10, 11, 12, 13, 1, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 1, 25, + 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[27] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1 + } ; + +static const flex_int16_t yy_base[205] = + { 0, + 0, 21, 218, 219, 219, 17, 201, 7, 212, 21, + 11, 207, 194, 197, 204, 199, 30, 194, 203, 183, + 198, 194, 197, 192, 182, 180, 189, 193, 183, 184, + 189, 173, 178, 186, 189, 189, 170, 180, 169, 172, + 176, 219, 182, 173, 177, 161, 157, 159, 174, 4, + 157, 154, 169, 164, 155, 152, 170, 156, 155, 167, + 157, 219, 165, 163, 145, 162, 152, 155, 140, 145, + 148, 138, 152, 147, 146, 134, 138, 149, 130, 129, + 146, 132, 128, 219, 144, 139, 219, 128, 130, 219, + 120, 219, 120, 129, 120, 132, 122, 115, 113, 127, + + 118, 125, 114, 109, 113, 117, 115, 219, 115, 108, + 122, 103, 6, 105, 118, 105, 102, 115, 112, 99, + 110, 93, 93, 110, 95, 105, 89, 219, 103, 100, + 99, 89, 101, 82, 99, 82, 90, 219, 92, 78, + 78, 73, 80, 75, 87, 71, 77, 75, 219, 87, + 81, 66, 75, 73, 82, 76, 77, 68, 61, 219, + 62, 75, 74, 61, 50, 67, 70, 219, 67, 58, + 49, 219, 61, 59, 60, 53, 63, 43, 56, 47, + 59, 49, 219, 219, 54, 51, 42, 31, 37, 48, + 219, 30, 44, 47, 25, 27, 219, 35, 29, 28, + + 11, 219, 219, 0 + } ; + +static const flex_int16_t yy_def[205] = + { 0, + 204, 204, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + + 203, 203, 0, 203 + } ; + +static const flex_int16_t yy_nxt[246] = + { 0, + 4, 5, 203, 203, 6, 203, 65, 203, 123, 203, + 203, 7, 203, 8, 9, 203, 10, 11, 18, 203, + 12, 13, 5, 19, 66, 6, 124, 24, 14, 21, + 15, 202, 7, 25, 8, 9, 31, 10, 11, 16, + 22, 12, 13, 201, 23, 200, 199, 32, 198, 197, + 196, 195, 194, 33, 193, 192, 191, 190, 189, 188, + 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, + 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, + 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, + 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, + + 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, + 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, + 127, 126, 125, 122, 121, 120, 119, 118, 117, 116, + 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, + 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, + 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, + 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, + 75, 74, 73, 72, 71, 70, 69, 68, 67, 64, + 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, + 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, + + 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, + 30, 29, 28, 27, 26, 20, 17, 203, 3, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203 + } ; + +static const flex_int16_t yy_chk[246] = + { 0, + 204, 1, 0, 0, 1, 0, 50, 0, 113, 0, + 0, 1, 0, 1, 1, 0, 1, 1, 8, 0, + 1, 1, 2, 8, 50, 2, 113, 11, 6, 10, + 6, 201, 2, 11, 2, 2, 17, 2, 2, 6, + 10, 2, 2, 200, 10, 199, 198, 17, 196, 195, + 194, 193, 192, 17, 190, 189, 188, 187, 186, 185, + 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, + 171, 170, 169, 167, 166, 165, 164, 163, 162, 161, + 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, + 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, + + 137, 136, 135, 134, 133, 132, 131, 130, 129, 127, + 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, + 116, 115, 114, 112, 111, 110, 109, 107, 106, 105, + 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, + 94, 93, 91, 89, 88, 86, 85, 83, 82, 81, + 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, + 70, 69, 68, 67, 66, 65, 64, 63, 61, 60, + 59, 58, 57, 56, 55, 54, 53, 52, 51, 49, + 48, 47, 46, 45, 44, 43, 41, 40, 39, 38, + 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, + + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, + 16, 15, 14, 13, 12, 9, 7, 3, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203 + } ; + +/* Table of booleans, true if rule could match eol. */ +static const flex_int32_t yy_rule_can_match_eol[23] = + { 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "layout.flex" +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +/* + + This file is IGNORED during the build process! + + As this file is updated so infrequently and flex is not universally present on build machines, + the lex.layout.c file must be manually regenerated if you make any changes to this file. Just + run: + + flex layout.flex + + You will have to manually add a copyright notice to the top of lex.layout.c. + +*/ +#define YY_NO_UNISTD_H 1 +#line 29 "layout.flex" +#include "SkSLToken.h" +#line 648 "lex.layout.c" +#line 649 "lex.layout.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + +int layoutlex_init (yyscan_t* scanner); + +int layoutlex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int layoutlex_destroy ( yyscan_t yyscanner ); + +int layoutget_debug ( yyscan_t yyscanner ); + +void layoutset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE layoutget_extra ( yyscan_t yyscanner ); + +void layoutset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *layoutget_in ( yyscan_t yyscanner ); + +void layoutset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *layoutget_out ( yyscan_t yyscanner ); + +void layoutset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int layoutget_leng ( yyscan_t yyscanner ); + +char *layoutget_text ( yyscan_t yyscanner ); + +int layoutget_lineno ( yyscan_t yyscanner ); + +void layoutset_lineno ( int _line_number , yyscan_t yyscanner ); + +int layoutget_column ( yyscan_t yyscanner ); + +void layoutset_column ( int _column_no , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int layoutwrap ( yyscan_t yyscanner ); +#else +extern int layoutwrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + + static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner); + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int layoutlex (yyscan_t yyscanner); + +#define YY_DECL int layoutlex (yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + layoutensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + layout_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + layout_load_buffer_state(yyscanner ); + } + + { +#line 32 "layout.flex" + + +#line 912 "lex.layout.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 204 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 203 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 34 "layout.flex" +{ return SkSL::Token::LOCATION; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 35 "layout.flex" +{ return SkSL::Token::OFFSET; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 36 "layout.flex" +{ return SkSL::Token::BINDING; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 37 "layout.flex" +{ return SkSL::Token::INDEX; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 38 "layout.flex" +{ return SkSL::Token::SET; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 39 "layout.flex" +{ return SkSL::Token::BUILTIN; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 40 "layout.flex" +{ return SkSL::Token::INPUT_ATTACHMENT_INDEX; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 41 "layout.flex" +{ return SkSL::Token::ORIGIN_UPPER_LEFT; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 42 "layout.flex" +{ return SkSL::Token::OVERRIDE_COVERAGE; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 43 "layout.flex" +{ return SkSL::Token::BLEND_SUPPORT_ALL_EQUATIONS; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 44 "layout.flex" +{ return SkSL::Token::PUSH_CONSTANT; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 45 "layout.flex" +{ return SkSL::Token::POINTS; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 46 "layout.flex" +{ return SkSL::Token::LINES; } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 47 "layout.flex" +{ return SkSL::Token::LINE_STRIP; } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 48 "layout.flex" +{ return SkSL::Token::LINES_ADJACENCY; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 49 "layout.flex" +{ return SkSL::Token::TRIANGLES; } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 50 "layout.flex" +{ return SkSL::Token::TRIANGLE_STRIP; } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 51 "layout.flex" +{ return SkSL::Token::TRIANGLES_ADJACENCY; } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 52 "layout.flex" +{ return SkSL::Token::MAX_VERTICES; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 53 "layout.flex" +{ return SkSL::Token::INVOCATIONS; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 55 "layout.flex" +{ return SkSL::Token::INVALID_TOKEN; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 57 "layout.flex" +ECHO; + YY_BREAK +#line 1087 "lex.layout.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * layoutlex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( layoutwrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of layoutlex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + layoutrealloc((void *) b->yy_ch_buf,(yy_size_t) (b->yy_buf_size + 2) ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + layoutrestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) layoutrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,(yy_size_t) new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 204 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 204 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 203); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp , yyscan_t yyscanner) +{ + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_cp = yyg->yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yyg->yy_hold_char; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + int number_to_move = yyg->yy_n_chars + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + if ( c == '\n' ){ + --yylineno; + } + + yyg->yytext_ptr = yy_bp; + yyg->yy_hold_char = *yy_cp; + yyg->yy_c_buf_p = yy_cp; +} + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + layoutrestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( layoutwrap(yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void layoutrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + layoutensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + layout_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + layout_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + layout_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void layout_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * layoutpop_buffer_state(); + * layoutpush_buffer_state(new_buffer); + */ + layoutensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + layout_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (layoutwrap()) processing, but the only time this flag + * is looked at is after layoutwrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void layout_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE layout_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) layoutalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in layout_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) layoutalloc((yy_size_t) (b->yy_buf_size + 2) ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in layout_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + layout_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with layout_create_buffer() + * @param yyscanner The scanner object. + */ + void layout_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + layoutfree((void *) b->yy_ch_buf ,yyscanner ); + + layoutfree((void *) b ,yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a layoutrestart() or at EOF. + */ + static void layout_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + layout_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then layout_init_buffer was _probably_ + * called from layoutrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void layout_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + layout_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void layoutpush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + layoutensure_buffer_stack(yyscanner); + + /* This block is copied from layout_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from layout_switch_to_buffer. */ + layout_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void layoutpop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + layout_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + layout_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void layoutensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)layoutalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in layoutensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)layoutrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in layoutensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE layout_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) layoutalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in layout_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + layout_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to layoutlex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * layout_scan_bytes() instead. + */ +YY_BUFFER_STATE layout_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return layout_scan_bytes(yystr,(int) strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to layoutlex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE layout_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) layoutalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in layout_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = layout_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in layout_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE layoutget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int layoutget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int layoutget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *layoutget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *layoutget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int layoutget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *layoutget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void layoutset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void layoutset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "layoutset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void layoutset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "layoutset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see layout_switch_to_buffer + */ +void layoutset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void layoutset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int layoutget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void layoutset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +/* User-visible API */ + +/* layoutlex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int layoutlex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) layoutalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* layoutlex_init_extra has the same functionality as layoutlex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to layoutalloc in + * the yyextra field. + */ +int layoutlex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + layoutset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) layoutalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + layoutset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from layoutlex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * layoutlex_init() + */ + return 0; +} + +/* layoutlex_destroy is for both reentrant and non-reentrant scanners. */ +int layoutlex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + layout_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + layoutpop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + layoutfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + layoutfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * layoutlex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + layoutfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *layoutalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *layoutrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void layoutfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see layoutrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 57 "layout.flex" + + +int layoutwrap(yyscan_t scanner) { + return 1; // terminate +} + diff --git a/gfx/skia/skia/src/sksl/lex.layout.cpp b/gfx/skia/skia/src/sksl/lex.layout.cpp new file mode 100644 index 000000000000..4289b110d9bf --- /dev/null +++ b/gfx/skia/skia/src/sksl/lex.layout.cpp @@ -0,0 +1,12 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "disable_flex_warnings.h" +#include "lex.layout.c" +static_assert(YY_FLEX_MAJOR_VERSION * 100 + YY_FLEX_MINOR_VERSION * 10 + + YY_FLEX_SUBMINOR_VERSION >= 261, + "we require Flex 2.6.1 or better for security reasons"); diff --git a/gfx/skia/skia/src/sksl/lex.layout.h b/gfx/skia/skia/src/sksl/lex.layout.h new file mode 100644 index 000000000000..345b3362535f --- /dev/null +++ b/gfx/skia/skia/src/sksl/lex.layout.h @@ -0,0 +1,12 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +int layoutlex_init(yyscan_t* ptr_yy_globals); +int layoutlex_destroy(void* scanner); +YY_BUFFER_STATE layout_scan_string(const char* s, void* scanner); +int layoutlex(void* yyscanner); +void layout_delete_buffer(YY_BUFFER_STATE b, void* yyscanner); diff --git a/gfx/skia/skia/src/sksl/lex.sksl.c b/gfx/skia/skia/src/sksl/lex.sksl.c index 4993fac3a5a2..ad08251eb9c7 100644 --- a/gfx/skia/skia/src/sksl/lex.sksl.c +++ b/gfx/skia/skia/src/sksl/lex.sksl.c @@ -1,11 +1,11 @@ /* - * Copyright 2016 Google Inc. + * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#line 3 "lex.sksl.c" +#line 2 "lex.sksl.c" #define YY_INT_ALIGNED short int @@ -13,12 +13,82 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 37 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 3 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif + #define yy_create_buffer sksl_create_buffer + + #define yy_delete_buffer sksl_delete_buffer + + #define yy_scan_buffer sksl_scan_buffer + + #define yy_scan_string sksl_scan_string + + #define yy_scan_bytes sksl_scan_bytes + + #define yy_init_buffer sksl_init_buffer + + #define yy_flush_buffer sksl_flush_buffer + + #define yy_load_buffer_state sksl_load_buffer_state + + #define yy_switch_to_buffer sksl_switch_to_buffer + + #define yypush_buffer_state skslpush_buffer_state + + #define yypop_buffer_state skslpop_buffer_state + + #define yyensure_buffer_stack skslensure_buffer_stack + + #define yylex sksllex + + #define yyrestart skslrestart + + #define yylex_init sksllex_init + + #define yylex_init_extra sksllex_init_extra + + #define yylex_destroy sksllex_destroy + + #define yyget_debug skslget_debug + + #define yyset_debug skslset_debug + + #define yyget_extra skslget_extra + + #define yyset_extra skslset_extra + + #define yyget_in skslget_in + + #define yyset_in skslset_in + + #define yyget_out skslget_out + + #define yyset_out skslset_out + + #define yyget_leng skslget_leng + + #define yyget_text skslget_text + + #define yyget_lineno skslget_lineno + + #define yyset_lineno skslset_lineno + + #define yyget_column skslget_column + + #define yyset_column skslset_column + + #define yywrap skslwrap + + #define yyalloc skslalloc + + #define yyrealloc skslrealloc + + #define yyfree skslfree + /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ @@ -93,36 +163,22 @@ typedef unsigned int flex_uint32_t; #endif /* ! FLEXINT_H */ -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST +/* TODO: this is always defined, so inline it */ #define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) #else -#define yyconst +#define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T @@ -146,25 +202,29 @@ typedef void* yyscan_t; * definition of BEGIN. */ #define BEGIN yyg->yy_start = 1 + 2 * - /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yyg->yy_start - 1) / 2) #define YYSTATE YY_START - /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE skslrestart(yyin ,yyscanner ) - #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else #define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. @@ -184,10 +244,10 @@ typedef size_t yy_size_t; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 - + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires * access to the local variable yy_act. Since yyless() is a macro, it would break - * existing scanners that call yyless() from OUTSIDE sksllex. + * existing scanners that call yyless() from OUTSIDE sksllex. * One obvious solution it to make yy_act a global. I tried that, and saw * a 5% performance hit in a non-yylineno scanner, because yy_act is * normally declared as a register variable-- so it is not worth it. @@ -199,6 +259,13 @@ typedef size_t yy_size_t; if ( yytext[yyl] == '\n' )\ --yylineno;\ }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ @@ -213,7 +280,6 @@ typedef size_t yy_size_t; YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) - #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) #ifndef YY_STRUCT_YY_BUFFER_STATE @@ -228,12 +294,12 @@ struct yy_buffer_state /* Size of input buffer in bytes, not including room for EOB * characters. */ - yy_size_t yy_buf_size; + int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ - yy_size_t yy_n_chars; + int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to @@ -256,7 +322,7 @@ struct yy_buffer_state int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ - + /* Whether to try to fill the input buffer when we reach the * end of it. */ @@ -290,36 +356,33 @@ struct yy_buffer_state #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ : NULL) - /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] -void skslrestart (FILE *input_file ,yyscan_t yyscanner ); -void sksl_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -YY_BUFFER_STATE sksl_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); -void sksl_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void sksl_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void skslpush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -void skslpop_buffer_state (yyscan_t yyscanner ); - -static void skslensure_buffer_stack (yyscan_t yyscanner ); -static void sksl_load_buffer_state (yyscan_t yyscanner ); -static void sksl_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); +void skslrestart ( FILE *input_file , yyscan_t yyscanner ); +void sksl_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE sksl_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void sksl_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void sksl_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void skslpush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void skslpop_buffer_state ( yyscan_t yyscanner ); +static void skslensure_buffer_stack ( yyscan_t yyscanner ); +static void sksl_load_buffer_state ( yyscan_t yyscanner ); +static void sksl_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); #define YY_FLUSH_BUFFER sksl_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) -YY_BUFFER_STATE sksl_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); -YY_BUFFER_STATE sksl_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); -YY_BUFFER_STATE sksl_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner ); +YY_BUFFER_STATE sksl_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE sksl_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE sksl_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); -void *skslalloc (yy_size_t ,yyscan_t yyscanner ); -void *skslrealloc (void *,yy_size_t ,yyscan_t yyscanner ); -void skslfree (void * ,yyscan_t yyscanner ); +void *skslalloc ( yy_size_t , yyscan_t yyscanner ); +void *skslrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void skslfree ( void * , yyscan_t yyscanner ); #define yy_new_buffer sksl_create_buffer - #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ @@ -329,7 +392,6 @@ void skslfree (void * ,yyscan_t yyscanner ); } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } - #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ @@ -339,34 +401,31 @@ void skslfree (void * ,yyscan_t yyscanner ); } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } - #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ - -typedef unsigned char YY_CHAR; +typedef flex_uint8_t YY_CHAR; typedef int yy_state_type; #define yytext_ptr yytext_r -static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); -static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); -static int yy_get_next_buffer (yyscan_t yyscanner ); -static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ - yyleng = (size_t) (yy_cp - yy_bp); \ + yyleng = (int) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 82 -#define YY_END_OF_BUFFER 83 +#define YY_NUM_RULES 92 +#define YY_END_OF_BUFFER 93 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -374,48 +433,54 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[201] = +static const flex_int16_t yy_accept[253] = { 0, - 0, 0, 83, 81, 80, 80, 54, 81, 29, 45, - 50, 31, 32, 43, 41, 38, 42, 37, 44, 4, - 56, 77, 61, 57, 60, 55, 35, 36, 49, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 33, 48, 34, 80, - 59, 30, 29, 68, 53, 73, 66, 39, 64, 40, - 65, 1, 0, 78, 67, 2, 4, 0, 46, 63, - 58, 62, 47, 72, 52, 29, 29, 29, 11, 29, - 29, 29, 29, 29, 7, 16, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 71, 51, 30, + 0, 0, 93, 91, 90, 90, 64, 91, 38, 54, + 59, 40, 41, 52, 50, 47, 51, 46, 53, 4, + 4, 66, 87, 71, 67, 70, 65, 44, 45, 58, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 42, 57, + 43, 60, 90, 69, 39, 38, 78, 63, 83, 76, + 48, 74, 49, 75, 1, 0, 88, 77, 2, 4, + 0, 0, 55, 73, 68, 72, 56, 82, 62, 38, + 38, 38, 38, 38, 12, 38, 38, 38, 38, 38, + 8, 20, 38, 38, 38, 38, 38, 38, 38, 38, - 76, 0, 0, 0, 78, 1, 0, 0, 3, 69, - 70, 75, 29, 29, 29, 29, 29, 29, 9, 29, - 29, 29, 29, 29, 29, 17, 29, 29, 29, 29, - 29, 29, 74, 0, 1, 79, 0, 0, 2, 29, - 29, 29, 29, 8, 29, 24, 29, 29, 29, 21, - 29, 29, 29, 29, 29, 5, 29, 29, 0, 1, - 12, 20, 29, 29, 6, 23, 18, 29, 29, 29, - 29, 29, 29, 29, 10, 29, 29, 27, 29, 29, - 29, 15, 26, 29, 29, 14, 22, 29, 29, 19, - 13, 29, 29, 29, 28, 29, 29, 29, 25, 0 + 38, 38, 38, 38, 38, 38, 81, 61, 39, 86, + 0, 0, 0, 88, 1, 0, 0, 3, 5, 79, + 80, 85, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 10, 38, 38, 38, 38, 38, 38, 21, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 84, 0, 1, 89, 0, 0, 2, 38, 14, 38, + 38, 38, 38, 38, 9, 38, 28, 38, 38, 38, + 25, 38, 38, 38, 38, 38, 38, 38, 38, 6, + 38, 38, 38, 38, 0, 1, 16, 38, 24, 38, + 38, 38, 7, 27, 22, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 11, 38, 38, 38, + 38, 38, 36, 38, 38, 38, 38, 38, 19, 35, + 13, 38, 38, 38, 38, 38, 15, 18, 26, 38, + 38, 38, 38, 23, 38, 38, 32, 17, 38, 38, + 30, 34, 33, 38, 38, 37, 31, 38, 38, 38, + 29, 0 } ; -static yyconst flex_int32_t yy_ec[256] = +static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 1, 5, 6, 7, 8, 1, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 18, 19, 20, - 21, 22, 23, 1, 6, 6, 6, 6, 24, 6, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, + 22, 23, 24, 1, 25, 25, 25, 25, 26, 25, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 25, 1, 26, 27, 6, 1, 28, 29, 30, 31, + 27, 1, 28, 29, 6, 1, 30, 31, 32, 33, - 32, 33, 34, 35, 36, 6, 37, 38, 39, 40, - 41, 42, 6, 43, 44, 45, 46, 47, 48, 6, - 49, 6, 50, 51, 52, 1, 1, 1, 1, 1, + 34, 35, 36, 37, 38, 6, 39, 40, 41, 42, + 43, 44, 6, 45, 46, 47, 48, 49, 50, 51, + 52, 6, 53, 54, 55, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -432,152 +497,178 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[53] = +static const YY_CHAR yy_meta[57] = { 0, 1, 1, 2, 1, 1, 3, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, - 1, 1, 1, 3, 1, 1, 1, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, + 1, 1, 1, 1, 5, 5, 1, 1, 1, 5, + 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, - 1, 1 + 3, 3, 1, 1, 1, 1 } ; -static yyconst flex_int16_t yy_base[206] = +static const flex_int16_t yy_base[259] = { 0, - 0, 0, 238, 239, 51, 53, 216, 0, 0, 215, - 49, 239, 239, 214, 46, 239, 45, 217, 52, 45, - 239, 239, 44, 212, 50, 239, 239, 239, 53, 189, - 190, 40, 192, 47, 193, 46, 50, 196, 186, 180, - 182, 192, 178, 179, 181, 185, 239, 61, 239, 81, - 239, 0, 0, 239, 198, 239, 239, 239, 239, 239, - 239, 70, 207, 0, 239, 72, 75, 81, 196, 239, - 239, 239, 195, 239, 194, 182, 173, 168, 0, 167, - 172, 181, 165, 173, 0, 165, 156, 156, 172, 160, - 156, 168, 154, 155, 151, 160, 159, 239, 173, 0, + 0, 0, 320, 321, 55, 57, 297, 0, 0, 296, + 53, 321, 321, 295, 50, 321, 49, 47, 57, 52, + 59, 321, 321, 59, 294, 60, 321, 321, 321, 62, + 270, 57, 54, 274, 59, 275, 59, 65, 278, 268, + 262, 264, 274, 57, 262, 264, 262, 53, 321, 74, + 321, 321, 103, 321, 0, 0, 321, 282, 321, 321, + 321, 321, 321, 321, 92, 292, 0, 321, 95, 99, + 118, 0, 280, 321, 321, 321, 279, 321, 278, 265, + 252, 78, 262, 250, 0, 249, 254, 263, 247, 255, + 0, 247, 237, 238, 254, 242, 238, 250, 92, 238, - 239, 89, 182, 176, 0, 91, 97, 174, 173, 239, - 239, 239, 161, 72, 158, 155, 142, 140, 0, 149, - 137, 141, 139, 144, 147, 0, 148, 131, 130, 143, - 141, 135, 239, 155, 154, 239, 107, 153, 152, 131, - 122, 130, 137, 0, 132, 0, 121, 117, 115, 0, - 114, 116, 122, 114, 126, 0, 114, 122, 136, 135, - 0, 0, 111, 107, 0, 0, 0, 104, 109, 103, - 102, 105, 99, 100, 0, 96, 110, 0, 98, 97, - 102, 0, 0, 98, 102, 0, 0, 90, 79, 0, - 0, 88, 73, 65, 0, 69, 53, 65, 0, 239, + 244, 233, 242, 239, 240, 239, 321, 254, 0, 321, + 128, 264, 258, 0, 126, 136, 106, 138, 0, 321, + 321, 321, 243, 238, 237, 111, 240, 237, 234, 221, + 219, 0, 228, 216, 220, 218, 223, 226, 0, 227, + 225, 210, 208, 207, 207, 219, 217, 221, 210, 202, + 321, 144, 146, 321, 153, 151, 155, 209, 0, 202, + 199, 207, 196, 213, 0, 208, 0, 197, 193, 191, + 0, 190, 192, 198, 192, 189, 188, 200, 199, 0, + 187, 182, 194, 193, 157, 159, 0, 192, 0, 183, + 184, 178, 0, 0, 0, 175, 180, 174, 173, 176, - 58, 122, 124, 128, 132 + 179, 174, 168, 177, 168, 174, 0, 168, 168, 161, + 161, 174, 0, 162, 161, 166, 163, 170, 0, 0, + 0, 160, 160, 157, 146, 145, 0, 0, 0, 132, + 116, 99, 102, 0, 113, 101, 0, 0, 105, 92, + 0, 0, 0, 79, 80, 0, 0, 81, 62, 32, + 0, 321, 175, 178, 181, 186, 191, 193 } ; -static yyconst flex_int16_t yy_def[206] = +static const flex_int16_t yy_def[259] = { 0, - 200, 1, 200, 200, 200, 200, 200, 201, 202, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 200, 200, 200, 200, - 200, 203, 202, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 204, 205, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 200, 200, 203, + 252, 1, 252, 252, 252, 252, 252, 253, 254, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 252, 252, + 252, 252, 252, 252, 255, 254, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 256, 257, 252, 252, 252, + 252, 258, 252, 252, 252, 252, 252, 252, 252, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 200, 200, 204, 204, 205, 200, 200, 200, 200, 200, - 200, 200, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 200, 200, 200, 200, 200, 200, 200, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 200, 200, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 0, + 254, 254, 254, 254, 254, 254, 252, 252, 255, 252, + 252, 256, 256, 257, 252, 252, 252, 252, 258, 252, + 252, 252, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 252, 252, 252, 252, 252, 252, 252, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 252, 252, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 200, 200, 200, 200, 200 + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 0, 252, 252, 252, 252, 252, 252 } ; -static yyconst flex_int16_t yy_nxt[292] = +static const flex_int16_t yy_nxt[378] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 9, 27, 28, 29, 9, 30, 31, - 32, 33, 34, 9, 35, 36, 9, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 9, 46, 9, 47, - 48, 49, 50, 50, 50, 50, 55, 58, 60, 66, - 52, 67, 63, 69, 70, 61, 59, 64, 68, 56, - 72, 73, 65, 74, 81, 78, 68, 87, 85, 75, - 79, 98, 50, 50, 82, 86, 62, 83, 106, 66, - 88, 67, 108, 102, 108, 107, 199, 109, 68, 198, + 24, 25, 26, 27, 9, 9, 28, 29, 30, 9, + 31, 32, 33, 34, 35, 9, 36, 37, 9, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 9, 9, 49, 50, 51, 52, 53, 53, 53, 53, + 58, 61, 63, 65, 65, 251, 69, 66, 70, 70, + 64, 62, 67, 69, 59, 70, 70, 71, 68, 73, + 74, 76, 77, 78, 71, 71, 81, 83, 87, 105, + 79, 84, 71, 91, 93, 107, 85, 106, 88, 82, - 134, 102, 134, 107, 197, 135, 68, 106, 138, 196, - 138, 99, 195, 139, 137, 141, 142, 194, 159, 193, - 159, 192, 137, 160, 53, 53, 100, 100, 103, 103, - 103, 103, 105, 191, 105, 105, 190, 189, 188, 187, - 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, - 176, 160, 160, 175, 174, 173, 172, 171, 170, 169, - 168, 167, 166, 165, 164, 163, 162, 161, 139, 139, - 135, 135, 158, 157, 156, 155, 154, 153, 152, 151, - 150, 149, 148, 147, 146, 145, 144, 143, 140, 109, - 109, 136, 104, 133, 132, 131, 130, 129, 128, 127, + 92, 89, 72, 100, 53, 53, 101, 94, 65, 65, + 250, 115, 115, 69, 125, 70, 70, 111, 249, 126, + 116, 141, 118, 118, 71, 111, 248, 108, 116, 117, + 247, 117, 71, 246, 118, 118, 245, 142, 143, 152, + 244, 152, 115, 115, 153, 153, 243, 156, 242, 156, + 241, 155, 157, 157, 118, 118, 161, 162, 240, 155, + 153, 153, 153, 153, 185, 239, 185, 157, 157, 186, + 186, 157, 157, 186, 186, 186, 186, 55, 238, 55, + 56, 56, 56, 109, 109, 109, 112, 112, 112, 112, + 112, 114, 237, 114, 114, 114, 119, 119, 236, 235, - 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, - 116, 115, 114, 113, 112, 111, 110, 104, 101, 97, - 96, 95, 94, 93, 92, 91, 90, 89, 84, 80, - 77, 76, 71, 62, 57, 54, 51, 200, 3, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200 + 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, + 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, + 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, + 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, + 194, 193, 192, 191, 190, 189, 188, 187, 184, 183, + 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, + 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, + 160, 159, 158, 154, 113, 151, 150, 149, 148, 147, + 146, 145, 144, 140, 139, 138, 137, 136, 135, 134, + 133, 132, 131, 130, 129, 128, 127, 124, 123, 122, + 121, 120, 113, 110, 104, 103, 102, 99, 98, 97, + 96, 95, 90, 86, 80, 75, 60, 57, 54, 252, + 3, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252 } ; -static yyconst flex_int16_t yy_chk[292] = +static const flex_int16_t yy_chk[378] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 5, 5, 6, 6, 11, 15, 17, 20, - 201, 20, 19, 23, 23, 17, 15, 19, 20, 11, - 25, 25, 19, 29, 34, 32, 20, 37, 36, 29, - 32, 48, 50, 50, 34, 36, 62, 34, 66, 67, - 37, 67, 68, 62, 68, 66, 198, 68, 67, 197, + 1, 1, 1, 1, 1, 1, 5, 5, 6, 6, + 11, 15, 17, 18, 18, 250, 20, 19, 20, 20, + 17, 15, 19, 21, 11, 21, 21, 20, 19, 24, + 24, 26, 26, 30, 21, 20, 32, 33, 35, 48, + 30, 33, 21, 37, 38, 50, 33, 48, 35, 32, - 102, 62, 102, 66, 196, 102, 67, 106, 107, 194, - 107, 48, 193, 107, 106, 114, 114, 192, 137, 189, - 137, 188, 106, 137, 202, 202, 203, 203, 204, 204, - 204, 204, 205, 185, 205, 205, 184, 181, 180, 179, - 177, 176, 174, 173, 172, 171, 170, 169, 168, 164, - 163, 160, 159, 158, 157, 155, 154, 153, 152, 151, - 149, 148, 147, 145, 143, 142, 141, 140, 139, 138, - 135, 134, 132, 131, 130, 129, 128, 127, 125, 124, - 123, 122, 121, 120, 118, 117, 116, 115, 113, 109, - 108, 104, 103, 99, 97, 96, 95, 94, 93, 92, + 37, 35, 20, 44, 53, 53, 44, 38, 65, 65, + 249, 69, 69, 70, 82, 70, 70, 65, 248, 82, + 69, 99, 117, 117, 70, 65, 245, 50, 69, 71, + 244, 71, 70, 240, 71, 71, 239, 99, 99, 111, + 236, 111, 115, 115, 111, 111, 235, 116, 233, 116, + 232, 115, 116, 116, 118, 118, 126, 126, 231, 115, + 152, 152, 153, 153, 155, 230, 155, 156, 156, 155, + 155, 157, 157, 185, 185, 186, 186, 253, 226, 253, + 254, 254, 254, 255, 255, 255, 256, 256, 256, 256, + 256, 257, 225, 257, 257, 257, 258, 258, 224, 223, - 91, 90, 89, 88, 87, 86, 84, 83, 82, 81, - 80, 78, 77, 76, 75, 73, 69, 63, 55, 46, - 45, 44, 43, 42, 41, 40, 39, 38, 35, 33, - 31, 30, 24, 18, 14, 10, 7, 3, 200, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200 + 222, 218, 217, 216, 215, 214, 212, 211, 210, 209, + 208, 206, 205, 204, 203, 202, 201, 200, 199, 198, + 197, 196, 192, 191, 190, 188, 184, 183, 182, 181, + 179, 178, 177, 176, 175, 174, 173, 172, 170, 169, + 168, 166, 164, 163, 162, 161, 160, 158, 150, 149, + 148, 147, 146, 145, 144, 143, 142, 141, 140, 138, + 137, 136, 135, 134, 133, 131, 130, 129, 128, 127, + 125, 124, 123, 113, 112, 108, 106, 105, 104, 103, + 102, 101, 100, 98, 97, 96, 95, 94, 93, 92, + 90, 89, 88, 87, 86, 84, 83, 81, 80, 79, + 77, 73, 66, 58, 47, 46, 45, 43, 42, 41, + 40, 39, 36, 34, 31, 25, 14, 10, 7, 3, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252 } ; /* Table of booleans, true if rule could match eol. */ -static yyconst flex_int32_t yy_rule_can_match_eol[83] = +static const flex_int32_t yy_rule_can_match_eol[93] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 1, 0, 0, }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, }; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. @@ -587,20 +678,26 @@ static yyconst flex_int32_t yy_rule_can_match_eol[83] = #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET #line 1 "sksl.flex" +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ /* - This file is IGNORED during the build process! + This file is IGNORED during the build process! - As this file is updated so infrequently and flex is not universally present on build machines, - the lex.sksl.c file must be manually regenerated if you make any changes to this file. Just run: + As this file is updated so infrequently and flex is not universally present on build machines, + the lex.sksl.c file must be manually regenerated if you make any changes to this file. Just run: - flex sksl.flex + flex sksl.flex You will have to manually add a copyright notice to the top of lex.sksl.c. - + */ #define YY_NO_UNISTD_H 1 -#line 598 "lex.sksl.c" +#line 694 "lex.sksl.c" #define INITIAL 0 @@ -629,8 +726,8 @@ struct yyguts_t size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; - yy_size_t yy_n_chars; - yy_size_t yyleng_r; + int yy_n_chars; + int yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; @@ -650,44 +747,44 @@ struct yyguts_t }; /* end struct yyguts_t */ -static int yy_init_globals (yyscan_t yyscanner ); +static int yy_init_globals ( yyscan_t yyscanner ); int sksllex_init (yyscan_t* scanner); -int sksllex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); +int sksllex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ -int sksllex_destroy (yyscan_t yyscanner ); +int sksllex_destroy ( yyscan_t yyscanner ); -int skslget_debug (yyscan_t yyscanner ); +int skslget_debug ( yyscan_t yyscanner ); -void skslset_debug (int debug_flag ,yyscan_t yyscanner ); +void skslset_debug ( int debug_flag , yyscan_t yyscanner ); -YY_EXTRA_TYPE skslget_extra (yyscan_t yyscanner ); +YY_EXTRA_TYPE skslget_extra ( yyscan_t yyscanner ); -void skslset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); +void skslset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); -FILE *skslget_in (yyscan_t yyscanner ); +FILE *skslget_in ( yyscan_t yyscanner ); -void skslset_in (FILE * in_str ,yyscan_t yyscanner ); +void skslset_in ( FILE * _in_str , yyscan_t yyscanner ); -FILE *skslget_out (yyscan_t yyscanner ); +FILE *skslget_out ( yyscan_t yyscanner ); -void skslset_out (FILE * out_str ,yyscan_t yyscanner ); +void skslset_out ( FILE * _out_str , yyscan_t yyscanner ); -yy_size_t skslget_leng (yyscan_t yyscanner ); + int skslget_leng ( yyscan_t yyscanner ); -char *skslget_text (yyscan_t yyscanner ); +char *skslget_text ( yyscan_t yyscanner ); -int skslget_lineno (yyscan_t yyscanner ); +int skslget_lineno ( yyscan_t yyscanner ); -void skslset_lineno (int line_number ,yyscan_t yyscanner ); +void skslset_lineno ( int _line_number , yyscan_t yyscanner ); -int skslget_column (yyscan_t yyscanner ); +int skslget_column ( yyscan_t yyscanner ); -void skslset_column (int column_no ,yyscan_t yyscanner ); +void skslset_column ( int _column_no , yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. @@ -695,35 +792,43 @@ void skslset_column (int column_no ,yyscan_t yyscanner ); #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus -extern "C" int skslwrap (yyscan_t yyscanner ); +extern "C" int skslwrap ( yyscan_t yyscanner ); #else -extern int skslwrap (yyscan_t yyscanner ); +extern int skslwrap ( yyscan_t yyscanner ); #endif #endif - static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); +#ifndef YY_NO_UNPUT + static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner); + +#endif + #ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT - #ifdef __cplusplus -static int yyinput (yyscan_t yyscanner ); +static int yyinput ( yyscan_t yyscanner ); #else -static int input (yyscan_t yyscanner ); +static int input ( yyscan_t yyscanner ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else #define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ @@ -731,7 +836,7 @@ static int input (yyscan_t yyscanner ); /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -742,7 +847,7 @@ static int input (yyscan_t yyscanner ); if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ - size_t n; \ + int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ @@ -755,7 +860,7 @@ static int input (yyscan_t yyscanner ); else \ { \ errno=0; \ - while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ @@ -810,7 +915,7 @@ extern int sksllex (yyscan_t yyscanner); /* Code executed at the end of each rule. */ #ifndef YY_BREAK -#define YY_BREAK break; +#define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ @@ -820,16 +925,11 @@ extern int sksllex (yyscan_t yyscanner); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; -#line 23 "sksl.flex" - - -#line 826 "lex.sksl.c" - if ( !yyg->yy_init ) { yyg->yy_init = 1; @@ -856,7 +956,13 @@ YY_DECL sksl_load_buffer_state(yyscanner ); } - while ( 1 ) /* loops until end-of-file is reached */ + { +#line 30 "sksl.flex" + + +#line 957 "lex.sksl.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = yyg->yy_c_buf_p; @@ -872,7 +978,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -881,13 +987,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 201 ) - yy_c = yy_meta[(unsigned int) yy_c]; + if ( yy_current_state >= 253 ) + yy_c = yy_meta[yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_current_state != 200 ); + while ( yy_current_state != 252 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; @@ -901,7 +1007,7 @@ yy_find_action: int yyl; for ( yyl = 0; yyl < yyleng; ++yyl ) if ( yytext[yyl] == '\n' ) - + do{ yylineno++; yycolumn=0; }while(0) @@ -921,417 +1027,467 @@ do_action: /* This label is used only to access EOF actions. */ case 1: YY_RULE_SETUP -#line 25 "sksl.flex" +#line 32 "sksl.flex" { return SkSL::Token::FLOAT_LITERAL; } YY_BREAK case 2: YY_RULE_SETUP -#line 27 "sksl.flex" +#line 34 "sksl.flex" { return SkSL::Token::FLOAT_LITERAL; } YY_BREAK case 3: YY_RULE_SETUP -#line 29 "sksl.flex" +#line 36 "sksl.flex" { return SkSL::Token::FLOAT_LITERAL; } YY_BREAK case 4: YY_RULE_SETUP -#line 31 "sksl.flex" +#line 38 "sksl.flex" { return SkSL::Token::INT_LITERAL; } YY_BREAK case 5: YY_RULE_SETUP -#line 33 "sksl.flex" -{ return SkSL::Token::TRUE_LITERAL; } +#line 40 "sksl.flex" +{ return SkSL::Token::INT_LITERAL; } YY_BREAK case 6: YY_RULE_SETUP -#line 35 "sksl.flex" -{ return SkSL::Token::FALSE_LITERAL; } +#line 42 "sksl.flex" +{ return SkSL::Token::TRUE_LITERAL; } YY_BREAK case 7: YY_RULE_SETUP -#line 37 "sksl.flex" -{ return SkSL::Token::IF; } +#line 44 "sksl.flex" +{ return SkSL::Token::FALSE_LITERAL; } YY_BREAK case 8: YY_RULE_SETUP -#line 39 "sksl.flex" -{ return SkSL::Token::ELSE; } +#line 46 "sksl.flex" +{ return SkSL::Token::IF; } YY_BREAK case 9: YY_RULE_SETUP -#line 41 "sksl.flex" -{ return SkSL::Token::FOR; } +#line 48 "sksl.flex" +{ return SkSL::Token::ELSE; } YY_BREAK case 10: YY_RULE_SETUP -#line 43 "sksl.flex" -{ return SkSL::Token::WHILE; } +#line 50 "sksl.flex" +{ return SkSL::Token::FOR; } YY_BREAK case 11: YY_RULE_SETUP -#line 45 "sksl.flex" -{ return SkSL::Token::DO; } +#line 52 "sksl.flex" +{ return SkSL::Token::WHILE; } YY_BREAK case 12: YY_RULE_SETUP -#line 47 "sksl.flex" -{ return SkSL::Token::BREAK; } +#line 54 "sksl.flex" +{ return SkSL::Token::DO; } YY_BREAK case 13: YY_RULE_SETUP -#line 49 "sksl.flex" -{ return SkSL::Token::CONTINUE; } +#line 56 "sksl.flex" +{ return SkSL::Token::SWITCH; } YY_BREAK case 14: YY_RULE_SETUP -#line 51 "sksl.flex" -{ return SkSL::Token::DISCARD; } +#line 58 "sksl.flex" +{ return SkSL::Token::CASE; } YY_BREAK case 15: YY_RULE_SETUP -#line 53 "sksl.flex" -{ return SkSL::Token::RETURN; } +#line 60 "sksl.flex" +{ return SkSL::Token::DEFAULT; } YY_BREAK case 16: YY_RULE_SETUP -#line 55 "sksl.flex" -{ return SkSL::Token::IN; } +#line 62 "sksl.flex" +{ return SkSL::Token::BREAK; } YY_BREAK case 17: YY_RULE_SETUP -#line 57 "sksl.flex" -{ return SkSL::Token::OUT; } +#line 64 "sksl.flex" +{ return SkSL::Token::CONTINUE; } YY_BREAK case 18: YY_RULE_SETUP -#line 59 "sksl.flex" -{ return SkSL::Token::INOUT; } +#line 66 "sksl.flex" +{ return SkSL::Token::DISCARD; } YY_BREAK case 19: YY_RULE_SETUP -#line 61 "sksl.flex" -{ return SkSL::Token::UNIFORM; } +#line 68 "sksl.flex" +{ return SkSL::Token::RETURN; } YY_BREAK case 20: YY_RULE_SETUP -#line 63 "sksl.flex" -{ return SkSL::Token::CONST; } +#line 70 "sksl.flex" +{ return SkSL::Token::IN; } YY_BREAK case 21: YY_RULE_SETUP -#line 65 "sksl.flex" -{ return SkSL::Token::LOWP; } +#line 72 "sksl.flex" +{ return SkSL::Token::OUT; } YY_BREAK case 22: YY_RULE_SETUP -#line 67 "sksl.flex" -{ return SkSL::Token::MEDIUMP; } +#line 74 "sksl.flex" +{ return SkSL::Token::INOUT; } YY_BREAK case 23: YY_RULE_SETUP -#line 69 "sksl.flex" -{ return SkSL::Token::HIGHP; } +#line 76 "sksl.flex" +{ return SkSL::Token::UNIFORM; } YY_BREAK case 24: YY_RULE_SETUP -#line 71 "sksl.flex" -{ return SkSL::Token::FLAT; } +#line 78 "sksl.flex" +{ return SkSL::Token::CONST; } YY_BREAK case 25: YY_RULE_SETUP -#line 73 "sksl.flex" -{ return SkSL::Token::NOPERSPECTIVE; } +#line 80 "sksl.flex" +{ return SkSL::Token::LOWP; } YY_BREAK case 26: YY_RULE_SETUP -#line 75 "sksl.flex" -{ return SkSL::Token::STRUCT; } +#line 82 "sksl.flex" +{ return SkSL::Token::MEDIUMP; } YY_BREAK case 27: YY_RULE_SETUP -#line 77 "sksl.flex" -{ return SkSL::Token::LAYOUT; } +#line 84 "sksl.flex" +{ return SkSL::Token::HIGHP; } YY_BREAK case 28: YY_RULE_SETUP -#line 79 "sksl.flex" -{ return SkSL::Token::PRECISION; } +#line 86 "sksl.flex" +{ return SkSL::Token::FLAT; } YY_BREAK case 29: YY_RULE_SETUP -#line 81 "sksl.flex" -{ return SkSL::Token::IDENTIFIER; } +#line 88 "sksl.flex" +{ return SkSL::Token::NOPERSPECTIVE; } YY_BREAK case 30: YY_RULE_SETUP -#line 83 "sksl.flex" -{ return SkSL::Token::DIRECTIVE; } +#line 90 "sksl.flex" +{ return SkSL::Token::READONLY; } YY_BREAK case 31: YY_RULE_SETUP -#line 85 "sksl.flex" -{ return SkSL::Token::LPAREN; } +#line 92 "sksl.flex" +{ return SkSL::Token::WRITEONLY; } YY_BREAK case 32: YY_RULE_SETUP -#line 87 "sksl.flex" -{ return SkSL::Token::RPAREN; } +#line 94 "sksl.flex" +{ return SkSL::Token::COHERENT; } YY_BREAK case 33: YY_RULE_SETUP -#line 89 "sksl.flex" -{ return SkSL::Token::LBRACE; } +#line 96 "sksl.flex" +{ return SkSL::Token::VOLATILE; } YY_BREAK case 34: YY_RULE_SETUP -#line 91 "sksl.flex" -{ return SkSL::Token::RBRACE; } +#line 98 "sksl.flex" +{ return SkSL::Token::RESTRICT; } YY_BREAK case 35: YY_RULE_SETUP -#line 93 "sksl.flex" -{ return SkSL::Token::LBRACKET; } +#line 100 "sksl.flex" +{ return SkSL::Token::STRUCT; } YY_BREAK case 36: YY_RULE_SETUP -#line 95 "sksl.flex" -{ return SkSL::Token::RBRACKET; } +#line 102 "sksl.flex" +{ return SkSL::Token::LAYOUT; } YY_BREAK case 37: YY_RULE_SETUP -#line 97 "sksl.flex" -{ return SkSL::Token::DOT; } +#line 104 "sksl.flex" +{ return SkSL::Token::PRECISION; } YY_BREAK case 38: YY_RULE_SETUP -#line 99 "sksl.flex" -{ return SkSL::Token::COMMA; } +#line 106 "sksl.flex" +{ return SkSL::Token::IDENTIFIER; } YY_BREAK case 39: YY_RULE_SETUP -#line 101 "sksl.flex" -{ return SkSL::Token::PLUSPLUS; } +#line 108 "sksl.flex" +{ return SkSL::Token::DIRECTIVE; } YY_BREAK case 40: YY_RULE_SETUP -#line 103 "sksl.flex" -{ return SkSL::Token::MINUSMINUS; } +#line 110 "sksl.flex" +{ return SkSL::Token::LPAREN; } YY_BREAK case 41: YY_RULE_SETUP -#line 105 "sksl.flex" -{ return SkSL::Token::PLUS; } +#line 112 "sksl.flex" +{ return SkSL::Token::RPAREN; } YY_BREAK case 42: YY_RULE_SETUP -#line 107 "sksl.flex" -{ return SkSL::Token::MINUS; } +#line 114 "sksl.flex" +{ return SkSL::Token::LBRACE; } YY_BREAK case 43: YY_RULE_SETUP -#line 109 "sksl.flex" -{ return SkSL::Token::STAR; } +#line 116 "sksl.flex" +{ return SkSL::Token::RBRACE; } YY_BREAK case 44: YY_RULE_SETUP -#line 111 "sksl.flex" -{ return SkSL::Token::SLASH; } +#line 118 "sksl.flex" +{ return SkSL::Token::LBRACKET; } YY_BREAK case 45: YY_RULE_SETUP -#line 113 "sksl.flex" -{ return SkSL::Token::PERCENT; } +#line 120 "sksl.flex" +{ return SkSL::Token::RBRACKET; } YY_BREAK case 46: YY_RULE_SETUP -#line 115 "sksl.flex" -{ return SkSL::Token::SHL; } +#line 122 "sksl.flex" +{ return SkSL::Token::DOT; } YY_BREAK case 47: YY_RULE_SETUP -#line 117 "sksl.flex" -{ return SkSL::Token::SHR; } +#line 124 "sksl.flex" +{ return SkSL::Token::COMMA; } YY_BREAK case 48: YY_RULE_SETUP -#line 119 "sksl.flex" -{ return SkSL::Token::BITWISEOR; } +#line 126 "sksl.flex" +{ return SkSL::Token::PLUSPLUS; } YY_BREAK case 49: YY_RULE_SETUP -#line 121 "sksl.flex" -{ return SkSL::Token::BITWISEXOR; } +#line 128 "sksl.flex" +{ return SkSL::Token::MINUSMINUS; } YY_BREAK case 50: YY_RULE_SETUP -#line 123 "sksl.flex" -{ return SkSL::Token::BITWISEAND; } +#line 130 "sksl.flex" +{ return SkSL::Token::PLUS; } YY_BREAK case 51: YY_RULE_SETUP -#line 125 "sksl.flex" -{ return SkSL::Token::LOGICALOR; } +#line 132 "sksl.flex" +{ return SkSL::Token::MINUS; } YY_BREAK case 52: YY_RULE_SETUP -#line 127 "sksl.flex" -{ return SkSL::Token::LOGICALXOR; } +#line 134 "sksl.flex" +{ return SkSL::Token::STAR; } YY_BREAK case 53: YY_RULE_SETUP -#line 129 "sksl.flex" -{ return SkSL::Token::LOGICALAND; } +#line 136 "sksl.flex" +{ return SkSL::Token::SLASH; } YY_BREAK case 54: YY_RULE_SETUP -#line 131 "sksl.flex" -{ return SkSL::Token::NOT; } +#line 138 "sksl.flex" +{ return SkSL::Token::PERCENT; } YY_BREAK case 55: YY_RULE_SETUP -#line 133 "sksl.flex" -{ return SkSL::Token::QUESTION; } +#line 140 "sksl.flex" +{ return SkSL::Token::SHL; } YY_BREAK case 56: YY_RULE_SETUP -#line 135 "sksl.flex" -{ return SkSL::Token::COLON; } +#line 142 "sksl.flex" +{ return SkSL::Token::SHR; } YY_BREAK case 57: YY_RULE_SETUP -#line 137 "sksl.flex" -{ return SkSL::Token::EQ; } +#line 144 "sksl.flex" +{ return SkSL::Token::BITWISEOR; } YY_BREAK case 58: YY_RULE_SETUP -#line 139 "sksl.flex" -{ return SkSL::Token::EQEQ; } +#line 146 "sksl.flex" +{ return SkSL::Token::BITWISEXOR; } YY_BREAK case 59: YY_RULE_SETUP -#line 141 "sksl.flex" -{ return SkSL::Token::NEQ; } +#line 148 "sksl.flex" +{ return SkSL::Token::BITWISEAND; } YY_BREAK case 60: YY_RULE_SETUP -#line 143 "sksl.flex" -{ return SkSL::Token::GT; } +#line 150 "sksl.flex" +{ return SkSL::Token::BITWISENOT; } YY_BREAK case 61: YY_RULE_SETUP -#line 145 "sksl.flex" -{ return SkSL::Token::LT; } +#line 152 "sksl.flex" +{ return SkSL::Token::LOGICALOR; } YY_BREAK case 62: YY_RULE_SETUP -#line 147 "sksl.flex" -{ return SkSL::Token::GTEQ; } +#line 154 "sksl.flex" +{ return SkSL::Token::LOGICALXOR; } YY_BREAK case 63: YY_RULE_SETUP -#line 149 "sksl.flex" -{ return SkSL::Token::LTEQ; } +#line 156 "sksl.flex" +{ return SkSL::Token::LOGICALAND; } YY_BREAK case 64: YY_RULE_SETUP -#line 151 "sksl.flex" -{ return SkSL::Token::PLUSEQ; } +#line 158 "sksl.flex" +{ return SkSL::Token::LOGICALNOT; } YY_BREAK case 65: YY_RULE_SETUP -#line 153 "sksl.flex" -{ return SkSL::Token::MINUSEQ; } +#line 160 "sksl.flex" +{ return SkSL::Token::QUESTION; } YY_BREAK case 66: YY_RULE_SETUP -#line 155 "sksl.flex" -{ return SkSL::Token::STAREQ; } +#line 162 "sksl.flex" +{ return SkSL::Token::COLON; } YY_BREAK case 67: YY_RULE_SETUP -#line 157 "sksl.flex" -{ return SkSL::Token::SLASHEQ; } +#line 164 "sksl.flex" +{ return SkSL::Token::EQ; } YY_BREAK case 68: YY_RULE_SETUP -#line 159 "sksl.flex" -{ return SkSL::Token::PERCENTEQ; } +#line 166 "sksl.flex" +{ return SkSL::Token::EQEQ; } YY_BREAK case 69: YY_RULE_SETUP -#line 161 "sksl.flex" -{ return SkSL::Token::SHLEQ; } +#line 168 "sksl.flex" +{ return SkSL::Token::NEQ; } YY_BREAK case 70: YY_RULE_SETUP -#line 163 "sksl.flex" -{ return SkSL::Token::SHREQ; } +#line 170 "sksl.flex" +{ return SkSL::Token::GT; } YY_BREAK case 71: YY_RULE_SETUP -#line 165 "sksl.flex" -{ return SkSL::Token::BITWISEOREQ; } +#line 172 "sksl.flex" +{ return SkSL::Token::LT; } YY_BREAK case 72: YY_RULE_SETUP -#line 167 "sksl.flex" -{ return SkSL::Token::BITWISEXOREQ; } +#line 174 "sksl.flex" +{ return SkSL::Token::GTEQ; } YY_BREAK case 73: YY_RULE_SETUP -#line 169 "sksl.flex" -{ return SkSL::Token::BITWISEANDEQ; } +#line 176 "sksl.flex" +{ return SkSL::Token::LTEQ; } YY_BREAK case 74: YY_RULE_SETUP -#line 171 "sksl.flex" -{ return SkSL::Token::LOGICALOREQ; } +#line 178 "sksl.flex" +{ return SkSL::Token::PLUSEQ; } YY_BREAK case 75: YY_RULE_SETUP -#line 173 "sksl.flex" -{ return SkSL::Token::LOGICALXOREQ; } +#line 180 "sksl.flex" +{ return SkSL::Token::MINUSEQ; } YY_BREAK case 76: YY_RULE_SETUP -#line 175 "sksl.flex" -{ return SkSL::Token::LOGICALANDEQ; } +#line 182 "sksl.flex" +{ return SkSL::Token::STAREQ; } YY_BREAK case 77: YY_RULE_SETUP -#line 177 "sksl.flex" -{ return SkSL::Token::SEMICOLON; } +#line 184 "sksl.flex" +{ return SkSL::Token::SLASHEQ; } YY_BREAK case 78: YY_RULE_SETUP -#line 179 "sksl.flex" -/* line comment */ +#line 186 "sksl.flex" +{ return SkSL::Token::PERCENTEQ; } YY_BREAK case 79: -/* rule 79 can match eol */ YY_RULE_SETUP -#line 181 "sksl.flex" -/* block comment */ +#line 188 "sksl.flex" +{ return SkSL::Token::SHLEQ; } YY_BREAK case 80: -/* rule 80 can match eol */ YY_RULE_SETUP -#line 183 "sksl.flex" -/* whitespace */ +#line 190 "sksl.flex" +{ return SkSL::Token::SHREQ; } YY_BREAK case 81: YY_RULE_SETUP -#line 185 "sksl.flex" -{ return SkSL::Token::INVALID_TOKEN; } +#line 192 "sksl.flex" +{ return SkSL::Token::BITWISEOREQ; } YY_BREAK case 82: YY_RULE_SETUP -#line 187 "sksl.flex" +#line 194 "sksl.flex" +{ return SkSL::Token::BITWISEXOREQ; } + YY_BREAK +case 83: +YY_RULE_SETUP +#line 196 "sksl.flex" +{ return SkSL::Token::BITWISEANDEQ; } + YY_BREAK +case 84: +YY_RULE_SETUP +#line 198 "sksl.flex" +{ return SkSL::Token::LOGICALOREQ; } + YY_BREAK +case 85: +YY_RULE_SETUP +#line 200 "sksl.flex" +{ return SkSL::Token::LOGICALXOREQ; } + YY_BREAK +case 86: +YY_RULE_SETUP +#line 202 "sksl.flex" +{ return SkSL::Token::LOGICALANDEQ; } + YY_BREAK +case 87: +YY_RULE_SETUP +#line 204 "sksl.flex" +{ return SkSL::Token::SEMICOLON; } + YY_BREAK +case 88: +YY_RULE_SETUP +#line 206 "sksl.flex" +/* line comment */ + YY_BREAK +case 89: +/* rule 89 can match eol */ +YY_RULE_SETUP +#line 208 "sksl.flex" +/* block comment */ + YY_BREAK +case 90: +/* rule 90 can match eol */ +YY_RULE_SETUP +#line 210 "sksl.flex" +/* whitespace */ + YY_BREAK +case 91: +YY_RULE_SETUP +#line 212 "sksl.flex" +{ return SkSL::Token::INVALID_TOKEN; } + YY_BREAK +case 92: +YY_RULE_SETUP +#line 214 "sksl.flex" ECHO; YY_BREAK -#line 1329 "lex.sksl.c" +#line 1484 "lex.sksl.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1463,6 +1619,7 @@ case YY_STATE_EOF(INITIAL): "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ + } /* end of user's declarations */ } /* end of sksllex */ /* yy_get_next_buffer - try to read in a new buffer @@ -1475,9 +1632,9 @@ case YY_STATE_EOF(INITIAL): static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) @@ -1506,7 +1663,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); @@ -1519,7 +1676,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) else { - yy_size_t num_to_read = + int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) @@ -1533,7 +1690,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) if ( b->yy_is_our_buffer ) { - yy_size_t new_size = b->yy_buf_size * 2; + int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; @@ -1542,11 +1699,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ - skslrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + skslrealloc((void *) b->yy_ch_buf,(yy_size_t) (b->yy_buf_size + 2) ,yyscanner ); } else /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; + b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( @@ -1588,10 +1745,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner) else ret_val = EOB_ACT_CONTINUE_SCAN; - if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) skslrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) skslrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,(yy_size_t) new_size ,yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } @@ -1609,15 +1766,15 @@ static int yy_get_next_buffer (yyscan_t yyscanner) static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1626,10 +1783,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 201 ) - yy_c = yy_meta[(unsigned int) yy_c]; + if ( yy_current_state >= 253 ) + yy_c = yy_meta[yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; @@ -1642,11 +1799,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { - register int yy_is_jam; + int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ - register char *yy_cp = yyg->yy_c_buf_p; + char *yy_cp = yyg->yy_c_buf_p; - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1655,19 +1812,21 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 201 ) - yy_c = yy_meta[(unsigned int) yy_c]; + if ( yy_current_state >= 253 ) + yy_c = yy_meta[yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 200); + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 252); (void)yyg; return yy_is_jam ? 0 : yy_current_state; } - static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp , yyscan_t yyscanner) { - register char *yy_cp; + char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_cp = yyg->yy_c_buf_p; @@ -1678,10 +1837,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner) if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ - register yy_size_t number_to_move = yyg->yy_n_chars + 2; - register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + int number_to_move = yyg->yy_n_chars + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; - register char *source = + char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) @@ -1690,7 +1849,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); @@ -1707,6 +1866,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner) yyg->yy_c_buf_p = yy_cp; } +#endif + #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner) @@ -1732,7 +1893,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) else { /* need more input */ - yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) @@ -1756,7 +1917,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) case EOB_ACT_END_OF_FILE: { if ( skslwrap(yyscanner ) ) - return EOF; + return 0; if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; @@ -1779,7 +1940,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) yyg->yy_hold_char = *++yyg->yy_c_buf_p; if ( c == '\n' ) - + do{ yylineno++; yycolumn=0; }while(0) @@ -1872,7 +2033,7 @@ static void sksl_load_buffer_state (yyscan_t yyscanner) /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ - b->yy_ch_buf = (char *) skslalloc(b->yy_buf_size + 2 ,yyscanner ); + b->yy_ch_buf = (char *) skslalloc((yy_size_t) (b->yy_buf_size + 2) ,yyscanner ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in sksl_create_buffer()" ); @@ -2028,15 +2189,15 @@ static void skslensure_buffer_stack (yyscan_t yyscanner) * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ - num_to_alloc = 1; + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ yyg->yy_buffer_stack = (struct yy_buffer_state**)skslalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in skslensure_buffer_stack()" ); - + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - + yyg->yy_buffer_stack_max = num_to_alloc; yyg->yy_buffer_stack_top = 0; return; @@ -2045,7 +2206,7 @@ static void skslensure_buffer_stack (yyscan_t yyscanner) if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; + yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = yyg->yy_buffer_stack_max + grow_size; yyg->yy_buffer_stack = (struct yy_buffer_state**)skslrealloc @@ -2065,7 +2226,7 @@ static void skslensure_buffer_stack (yyscan_t yyscanner) * @param base the character buffer * @param size the size in bytes of the character buffer * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. + * @return the newly allocated buffer state object. */ YY_BUFFER_STATE sksl_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { @@ -2075,16 +2236,16 @@ YY_BUFFER_STATE sksl_scan_buffer (char * base, yy_size_t size , yyscan_t yysca base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ - return 0; + return NULL; b = (YY_BUFFER_STATE) skslalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in sksl_scan_buffer()" ); - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; - b->yy_input_file = 0; + b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; @@ -2104,10 +2265,10 @@ YY_BUFFER_STATE sksl_scan_buffer (char * base, yy_size_t size , yyscan_t yysca * @note If you want to scan bytes that may contain NUL values, then use * sksl_scan_bytes() instead. */ -YY_BUFFER_STATE sksl_scan_string (yyconst char * yystr , yyscan_t yyscanner) +YY_BUFFER_STATE sksl_scan_string (const char * yystr , yyscan_t yyscanner) { - return sksl_scan_bytes(yystr,strlen(yystr) ,yyscanner); + return sksl_scan_bytes(yystr,(int) strlen(yystr) ,yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to sksllex() will @@ -2117,7 +2278,7 @@ YY_BUFFER_STATE sksl_scan_string (yyconst char * yystr , yyscan_t yyscanner) * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ -YY_BUFFER_STATE sksl_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner) +YY_BUFFER_STATE sksl_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; @@ -2125,7 +2286,7 @@ YY_BUFFER_STATE sksl_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_le int i; /* Get memory for full buffer, including space for trailing EOB's. */ - n = _yybytes_len + 2; + n = (yy_size_t) (_yybytes_len + 2); buf = (char *) skslalloc(n ,yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in sksl_scan_bytes()" ); @@ -2151,9 +2312,11 @@ YY_BUFFER_STATE sksl_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_le #define YY_EXIT_FAILURE 2 #endif -static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) { - (void) fprintf( stderr, "%s\n", msg ); + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } @@ -2191,7 +2354,7 @@ YY_EXTRA_TYPE skslget_extra (yyscan_t yyscanner) int skslget_lineno (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - + if (! YY_CURRENT_BUFFER) return 0; @@ -2204,7 +2367,7 @@ int skslget_lineno (yyscan_t yyscanner) int skslget_column (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - + if (! YY_CURRENT_BUFFER) return 0; @@ -2232,7 +2395,7 @@ FILE *skslget_out (yyscan_t yyscanner) /** Get the length of the current token. * @param yyscanner The scanner object. */ -yy_size_t skslget_leng (yyscan_t yyscanner) +int skslget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; @@ -2259,10 +2422,10 @@ void skslset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) } /** Set the current line number. - * @param line_number + * @param _line_number line number * @param yyscanner The scanner object. */ -void skslset_lineno (int line_number , yyscan_t yyscanner) +void skslset_lineno (int _line_number , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; @@ -2270,14 +2433,14 @@ void skslset_lineno (int line_number , yyscan_t yyscanner) if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "skslset_lineno called with no buffer" ); - yylineno = line_number; + yylineno = _line_number; } /** Set the current column. - * @param line_number + * @param _column_no column number * @param yyscanner The scanner object. */ -void skslset_column (int column_no , yyscan_t yyscanner) +void skslset_column (int _column_no , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; @@ -2285,25 +2448,25 @@ void skslset_column (int column_no , yyscan_t yyscanner) if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "skslset_column called with no buffer" ); - yycolumn = column_no; + yycolumn = _column_no; } /** Set the input stream. This does not discard the current * input buffer. - * @param in_str A readable stream. + * @param _in_str A readable stream. * @param yyscanner The scanner object. * @see sksl_switch_to_buffer */ -void skslset_in (FILE * in_str , yyscan_t yyscanner) +void skslset_in (FILE * _in_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyin = in_str ; + yyin = _in_str ; } -void skslset_out (FILE * out_str , yyscan_t yyscanner) +void skslset_out (FILE * _out_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyout = out_str ; + yyout = _out_str ; } int skslget_debug (yyscan_t yyscanner) @@ -2312,10 +2475,10 @@ int skslget_debug (yyscan_t yyscanner) return yy_flex_debug; } -void skslset_debug (int bdebug , yyscan_t yyscanner) +void skslset_debug (int _bdebug , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yy_flex_debug = bdebug ; + yy_flex_debug = _bdebug ; } /* Accessor methods for yylval and yylloc */ @@ -2326,9 +2489,7 @@ void skslset_debug (int bdebug , yyscan_t yyscanner) * the ONLY reentrant function that doesn't take the scanner as the last argument. * That's why we explicitly handle the declaration, instead of using our macros. */ - int sksllex_init(yyscan_t* ptr_yy_globals) - { if (ptr_yy_globals == NULL){ errno = EINVAL; @@ -2355,9 +2516,7 @@ int sksllex_init(yyscan_t* ptr_yy_globals) * The user defined value in the first argument will be available to skslalloc in * the yyextra field. */ - int sksllex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) - { struct yyguts_t dummy_yyguts; @@ -2367,20 +2526,20 @@ int sksllex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) errno = EINVAL; return 1; } - + *ptr_yy_globals = (yyscan_t) skslalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); - + if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } - + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - + skslset_extra (yy_user_defined, *ptr_yy_globals); - + return yy_init_globals ( *ptr_yy_globals ); } @@ -2391,10 +2550,10 @@ static int yy_init_globals (yyscan_t yyscanner) * This function is called from sksllex_destroy(), so don't allocate here. */ - yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack = NULL; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; - yyg->yy_c_buf_p = (char *) 0; + yyg->yy_c_buf_p = NULL; yyg->yy_init = 0; yyg->yy_start = 0; @@ -2407,8 +2566,8 @@ static int yy_init_globals (yyscan_t yyscanner) yyin = stdin; yyout = stdout; #else - yyin = (FILE *) 0; - yyout = (FILE *) 0; + yyin = NULL; + yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by @@ -2452,18 +2611,21 @@ int sksllex_destroy (yyscan_t yyscanner) */ #ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) { - register int i; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) { - register int n; + int n; for ( n = 0; s[n]; ++n ) ; @@ -2473,11 +2635,16 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) void *skslalloc (yy_size_t size , yyscan_t yyscanner) { - return (void *) malloc( size ); + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); } void *skslrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) { + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter @@ -2485,18 +2652,19 @@ void *skslrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ - return (void *) realloc( (char *) ptr, size ); + return realloc(ptr, size); } void skslfree (void * ptr , yyscan_t yyscanner) { + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; free( (char *) ptr ); /* see skslrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" -#line 187 "sksl.flex" - +#line 214 "sksl.flex" int skslwrap(yyscan_t scanner) { diff --git a/gfx/skia/skia/src/sksl/sksl.flex b/gfx/skia/skia/src/sksl/sksl.flex index 67b48e9cb92f..bbb106c2288e 100644 --- a/gfx/skia/skia/src/sksl/sksl.flex +++ b/gfx/skia/skia/src/sksl/sksl.flex @@ -1,14 +1,21 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + /* - This file is IGNORED during the build process! + This file is IGNORED during the build process! - As this file is updated so infrequently and flex is not universally present on build machines, - the lex.sksl.c file must be manually regenerated if you make any changes to this file. Just run: + As this file is updated so infrequently and flex is not universally present on build machines, + the lex.sksl.c file must be manually regenerated if you make any changes to this file. Just run: - flex sksl.flex + flex sksl.flex You will have to manually add a copyright notice to the top of lex.sksl.c. - + */ %option prefix="sksl" @@ -30,6 +37,8 @@ LETTER [a-zA-Z_$] {DIGIT}+ { return SkSL::Token::INT_LITERAL; } +"0x"[0-9a-fA-F]+ { return SkSL::Token::INT_LITERAL; } + true { return SkSL::Token::TRUE_LITERAL; } false { return SkSL::Token::FALSE_LITERAL; } @@ -44,6 +53,12 @@ while { return SkSL::Token::WHILE; } do { return SkSL::Token::DO; } +switch { return SkSL::Token::SWITCH; } + +case { return SkSL::Token::CASE; } + +default { return SkSL::Token::DEFAULT; } + break { return SkSL::Token::BREAK; } continue { return SkSL::Token::CONTINUE; } @@ -72,6 +87,16 @@ flat { return SkSL::Token::FLAT; } noperspective { return SkSL::Token::NOPERSPECTIVE; } +readonly { return SkSL::Token::READONLY; } + +writeonly { return SkSL::Token::WRITEONLY; } + +coherent { return SkSL::Token::COHERENT; } + +volatile { return SkSL::Token::VOLATILE; } + +restrict { return SkSL::Token::RESTRICT; } + struct { return SkSL::Token::STRUCT; } layout { return SkSL::Token::LAYOUT; } @@ -122,13 +147,15 @@ precision { return SkSL::Token::PRECISION; } "&" { return SkSL::Token::BITWISEAND; } +"~" { return SkSL::Token::BITWISENOT; } + "||" { return SkSL::Token::LOGICALOR; } "^^" { return SkSL::Token::LOGICALXOR; } "&&" { return SkSL::Token::LOGICALAND; } -"!" { return SkSL::Token::NOT; } +"!" { return SkSL::Token::LOGICALNOT; } "?" { return SkSL::Token::QUESTION; } diff --git a/gfx/skia/skia/src/sksl/sksl.include b/gfx/skia/skia/src/sksl/sksl.include index 4fd5511ee3f6..11e37105565f 100644 --- a/gfx/skia/skia/src/sksl/sksl.include +++ b/gfx/skia/skia/src/sksl/sksl.include @@ -22,88 +22,88 @@ $genType log($genType x); $genType exp2($genType x); $genType log2($genType x); $genType sqrt($genType x); -$genDType sqrt($genDType x); +//$genDType sqrt($genDType x); $genType inversesqrt($genType x); -$genDType inversesqrt($genDType x); +//$genDType inversesqrt($genDType x); $genType abs($genType x); $genIType abs($genIType x); -$genDType abs($genDType x); +//$genDType abs($genDType x); $genType sign($genType x); $genIType sign($genIType x); -$genDType sign($genDType x); +//$genDType sign($genDType x); $genType floor($genType x); -$genDType floor($genDType x); +//$genDType floor($genDType x); $genType trunc($genType x); -$genDType trunc($genDType x); +//$genDType trunc($genDType x); $genType round($genType x); -$genDType round($genDType x); +//$genDType round($genDType x); $genType roundEven($genType x); -$genDType roundEven($genDType x); +//$genDType roundEven($genDType x); $genType ceil($genType x); -$genDType ceil($genDType x); +//$genDType ceil($genDType x); $genType fract($genType x); -$genDType fract($genDType x); +//$genDType fract($genDType x); $genType mod($genType x, float y); $genType mod($genType x, $genType y); -$genDType mod($genDType x, double y); -$genDType mod($genDType x, $genDType y); +//$genDType mod($genDType x, double y); +//$genDType mod($genDType x, $genDType y); $genType modf($genType x, out $genType i); -$genDType modf($genDType x, out $genDType i); +//$genDType modf($genDType x, out $genDType i); $genType min($genType x, $genType y); $genType min($genType x, float y); -$genDType min($genDType x, $genDType y); -$genDType min($genDType x, double y); +//$genDType min($genDType x, $genDType y); +//$genDType min($genDType x, double y); $genIType min($genIType x, $genIType y); $genIType min($genIType x, int y); -$genUType min($genUType x, $genUType y); -$genUType min($genUType x, uint y); +//$genUType min($genUType x, $genUType y); +//$genUType min($genUType x, uint y); $genType max($genType x, $genType y); $genType max($genType x, float y); -$genDType max($genDType x, $genDType y); -$genDType max($genDType x, double y); +//$genDType max($genDType x, $genDType y); +//$genDType max($genDType x, double y); $genIType max($genIType x, $genIType y); $genIType max($genIType x, int y); -$genUType max($genUType x, $genUType y); -$genUType max($genUType x, uint y); +//$genUType max($genUType x, $genUType y); +//$genUType max($genUType x, uint y); $genType clamp($genType x, $genType minVal, $genType maxVal); $genType clamp($genType x, float minVal, float maxVal); -$genDType clamp($genDType x, $genDType minVal, $genDType maxVal); -$genDType clamp($genDType x, double minVal, double maxVal); +//$genDType clamp($genDType x, $genDType minVal, $genDType maxVal); +//$genDType clamp($genDType x, double minVal, double maxVal); $genIType clamp($genIType x, $genIType minVal, $genIType maxVal); $genIType clamp($genIType x, int minVal, int maxVal); -$genUType clamp($genUType x, $genUType minVal, $genUType maxVal); -$genUType clamp($genUType x, uint minVal, uint maxVal); +//$genUType clamp($genUType x, $genUType minVal, $genUType maxVal); +//$genUType clamp($genUType x, uint minVal, uint maxVal); $genType mix($genType x, $genType y, $genType a); $genType mix($genType x, $genType y, float a); -$genDType mix($genDType x, $genDType y, $genDType a); -$genDType mix($genDType x, $genDType y, double a); +//$genDType mix($genDType x, $genDType y, $genDType a); +//$genDType mix($genDType x, $genDType y, double a); $genType mix($genType x, $genType y, $genBType a); -$genDType mix($genDType x, $genDType y, $genBType a); +//$genDType mix($genDType x, $genDType y, $genBType a); $genIType mix($genIType x, $genIType y, $genBType a); -$genUType mix($genUType x, $genUType y, $genBType a); +//$genUType mix($genUType x, $genUType y, $genBType a); $genBType mix($genBType x, $genBType y, $genBType a); $genType step($genType edge, $genType x); $genType step(float edge, $genType x); -$genDType step($genDType edge, $genDType x); -$genDType step(double edge, $genDType x); +//$genDType step($genDType edge, $genDType x); +//$genDType step(double edge, $genDType x); $genType smoothstep($genType edge0, $genType edge1, $genType x); $genType smoothstep(float edge0, float edge1, $genType x); -$genDType smoothstep($genDType edge0, $genDType edge1, $genDType x); -$genDType smoothstep(double edge0, double edge1, $genDType x); +//$genDType smoothstep($genDType edge0, $genDType edge1, $genDType x); +//$genDType smoothstep(double edge0, double edge1, $genDType x); $genBType isnan($genType x); $genBType isnan($genDType x); $genBType isinf($genType x); $genBType isinf($genDType x); $genIType floatBitsToInt($genType value); -$genUType floatBitsToUint($genType value); +//$genUType floatBitsToUint($genType value); $genType intBitsToFloat($genIType value); $genType uintBitsToFloat($genUType value); $genType fma($genType a, $genType b, $genType c); -$genDType fma($genDType a, $genDType b, $genDType c); +//$genDType fma($genDType a, $genDType b, $genDType c); $genType frexp($genType x, out $genIType exp); -$genDType frexp($genDType x, out $genIType exp); +//$genDType frexp($genDType x, out $genIType exp); $genType ldexp($genType x, in $genIType exp); -$genDType ldexp($genDType x, in $genIType exp); +//$genDType ldexp($genDType x, in $genIType exp); uint packUnorm2x16(vec2 v); uint packSnorm2x16(vec2 v); uint packUnorm4x8(vec4 v); @@ -112,27 +112,27 @@ vec2 unpackUnorm2x16(uint p); vec2 unpackSnorm2x16(uint p); vec4 unpackUnorm4x8(uint p); vec4 unpackSnorm4x8(uint p); -double packDouble2x32(uvec2 v); +//double packDouble2x32(uvec2 v); uvec2 unpackDouble2x32(double v); uint packHalf2x16(vec2 v); vec2 unpackHalf2x16(uint v); float length($genType x); -double length($genDType x); +//double length($genDType x); float distance($genType p0, $genType p1); -double distance($genDType p0, $genDType p1); +//double distance($genDType p0, $genDType p1); float dot($genType x, $genType y); -double dot($genDType x, $genDType y); +//double dot($genDType x, $genDType y); vec3 cross(vec3 x, vec3 y); -dvec3 cross(dvec3 x, dvec3 y); +//dvec3 cross(dvec3 x, dvec3 y); $genType normalize($genType x); -$genDType normalize($genDType x); +//$genDType normalize($genDType x); vec4 ftransform(); $genType faceforward($genType N, $genType I, $genType Nref); -$genDType faceforward($genDType N, $genDType I, $genDType Nref); +//$genDType faceforward($genDType N, $genDType I, $genDType Nref); $genType reflect($genType I, $genType N); -$genDType reflect($genDType I, $genDType N); +//$genDType reflect($genDType I, $genDType N); $genType refract($genType I, $genType N, float eta); -$genDType refract($genDType I, $genDType N, float eta); +//$genDType refract($genDType I, $genDType N, float eta); $mat matrixCompMult($mat x, $mat y); mat2 outerProduct(vec2 c, vec2 r); mat3 outerProduct(vec3 c, vec3 r); @@ -181,22 +181,25 @@ $bvec notEqual($bvec x, $bvec y); bool any($bvec x); bool all($bvec x); $bvec not($bvec x); -$genUType uaddCarry($genUType x, $genUType y, out $genUType carry); -$genUType usubBorrow($genUType x, $genUType y, out $genUType borrow); -void umulExtended($genUType x, $genUType y, out $genUType msb, out $genUType lsb); -void imulExtended($genIType x, $genIType y, out $genIType msb, out $genIType lsb); -$genIType bitfieldExtract($genIType value, int offset, int bits); -$genUType bitfieldExtract($genUType value, int offset, int bits); -$genIType bitfieldInsert($genIType base, $genIType insert, int offset, int bits); -$genUType bitfieldInsert($genUType base, $genUType insert, int offset, int bits); -$genIType bitfieldReverse($genIType value); -$genUType bitfieldReverse($genUType value); + $genIType bitCount($genIType value); $genIType bitCount($genUType value); $genIType findLSB($genIType value); $genIType findLSB($genUType value); $genIType findMSB($genIType value); $genIType findMSB($genUType value); + +/* +//$genUType uaddCarry($genUType x, $genUType y, out $genUType carry); +//$genUType usubBorrow($genUType x, $genUType y, out $genUType borrow); +void umulExtended($genUType x, $genUType y, out $genUType msb, out $genUType lsb); +void imulExtended($genIType x, $genIType y, out $genIType msb, out $genIType lsb); +$genIType bitfieldExtract($genIType value, int offset, int bits); +//$genUType bitfieldExtract($genUType value, int offset, int bits); +$genIType bitfieldInsert($genIType base, $genIType insert, int offset, int bits); +//$genUType bitfieldInsert($genUType base, $genUType insert, int offset, int bits); +$genIType bitfieldReverse($genIType value); +//$genUType bitfieldReverse($genUType value); int textureSize($gsampler1D sampler, int lod); ivec2 textureSize($gsampler2D sampler, int lod); ivec3 textureSize($gsampler3D sampler, int lod); @@ -206,7 +209,9 @@ ivec2 textureSize(sampler2DShadow sampler, int lod); ivec2 textureSize(samplerCubeShadow sampler, int lod); ivec3 textureSize($gsamplerCubeArray sampler, int lod); ivec3 textureSize(samplerCubeArrayShadow sampler, int lod); +*/ ivec2 textureSize($gsampler2DRect sampler); +/* ivec2 textureSize(sampler2DRectShadow sampler); ivec2 textureSize($gsampler1DArray sampler, int lod); ivec3 textureSize($gsampler2DArray sampler, int lod); @@ -241,9 +246,18 @@ int textureQueryLevels(samplerCubeShadow sampler); int textureQueryLevels(sampler1DArrayShadow sampler); int textureQueryLevels(sampler2DArrayShadow sampler); int textureQueryLevels(samplerCubeArrayShadow sampler); +*/ + $gvec4 texture($gsampler1D sampler, float P); $gvec4 texture($gsampler1D sampler, float P, float bias); $gvec4 texture($gsampler2D sampler, vec2 P); +// The above currently only expand to handle the float/fixed case. So we also declare this integer +// version of texture(). +ivec4 texture(isampler2D sampler, vec2 P); +vec4 texture(samplerExternalOES sampler, vec2 P, float bias); +vec4 texture(samplerExternalOES sampler, vec2 P); + +/* $gvec4 texture($gsampler2D sampler, vec2 P, float bias); $gvec4 texture($gsampler3D sampler, vec3 P); $gvec4 texture($gsampler3D sampler, vec3 P, float bias); @@ -264,24 +278,34 @@ $gvec4 texture($gsamplerCubeArray sampler, vec4 P, float bias); float texture(sampler1DArrayShadow sampler, vec3 P); float texture(sampler1DArrayShadow sampler, vec3 P, float bias); float texture(sampler2DArrayShadow sampler, vec4 P); +*/ + $gvec4 texture($gsampler2DRect sampler, vec2 P); + +/* float texture(sampler2DRectShadow sampler, vec3 P); float texture($gsamplerCubeArrayShadow sampler, vec4 P, float compare); +*/ +// Currently we do not support the generic types of loading subpassInput so we have some explicit +// versions that we currently use +vec4 subpassLoad(subpassInput subpass); +vec4 subpassLoad(subpassInputMS subpass, int sample); +/* +$gvec4 subpassLoad(gsubpassInput subpass); +$gvec4 subpassLoad(gsubpassInputMS subpass, int sample); +*/ ) // split into multiple chunks, as MSVC++ complains if a single string is too long STRINGIFY( -$gvec4 textureProj($gsampler1D sampler, vec2 P); -$gvec4 textureProj($gsampler1D sampler, vec2 P, float bias); -$gvec4 textureProj($gsampler1D sampler, vec4 P); -$gvec4 textureProj($gsampler1D sampler, vec4 P, float bias); -$gvec4 textureProj($gsampler2D sampler, vec3 P); -$gvec4 textureProj($gsampler2D sampler, vec3 P, float bias); -$gvec4 textureProj($gsampler2D sampler, vec4 P); -$gvec4 textureProj($gsampler2D sampler, vec4 P, float bias); +$gvec4 texture($gsampler1D sampler, vec2 P); +$gvec4 texture($gsampler1D sampler, vec2 P, float bias); +$gvec4 texture($gsampler2D sampler, vec3 P); +$gvec4 texture($gsampler2D sampler, vec3 P, float bias); +/* $gvec4 textureProj($gsampler3D sampler, vec4 P); $gvec4 textureProj($gsampler3D sampler, vec4 P, float bias); float textureProj(sampler1DShadow sampler, vec4 P); @@ -320,13 +344,15 @@ $gvec4 textureOffset($gsampler2DArray sampler, vec3 P, ivec2 offset, float bias) float textureOffset(sampler1DArrayShadow sampler, vec3 P, int offset); float textureOffset(sampler1DArrayShadow sampler, vec3 P, int offset, float bias); float textureOffset(sampler2DArrayShadow sampler, vec4 P, ivec2 offset); +*/ $gvec4 texelFetch($gsampler1D sampler, int P, int lod); $gvec4 texelFetch($gsampler2D sampler, ivec2 P, int lod); -$gvec4 texelFetch($gsampler3D sampler, ivec3 P, int lod); +$gvec4 texelFetch($gsamplerBuffer sampler, int P); $gvec4 texelFetch($gsampler2DRect sampler, ivec2 P); +/* +$gvec4 texelFetch($gsampler3D sampler, ivec3 P, int lod); $gvec4 texelFetch($gsampler1DArray sampler, ivec2 P, int lod); $gvec4 texelFetch($gsampler2DArray sampler, ivec3 P, int lod); -$gvec4 texelFetch($gsamplerBuffer sampler, int P); $gvec4 texelFetch($gsampler2DMS sampler, ivec2 P, int sample); $gvec4 texelFetch($gsampler2DMSArray sampler, ivec3 P, int sample); $gvec4 texelFetchOffset($gsampler1D sampler, int P, int lod, int offset); @@ -443,7 +469,6 @@ $gvec4 textureGatherOffset($gsampler2DRect sampler, vec2 P, ivec2 offset, int co vec4 textureGatherOffset(sampler2DShadow sampler, vec2 P, float refZ, ivec2 offset); vec4 textureGatherOffset(sampler2DArrayShadow sampler, vec3 P, float refZ, ivec2 offset); vec4 textureGatherOffset(sampler2DRectShadow sampler, vec2 P, float refZ, ivec2 offset); -/* $gvec4 textureGatherOffsets($gsampler2D sampler, vec2 P, ivec2 offsets[4]); $gvec4 textureGatherOffsets($gsampler2D sampler, vec2 P, ivec2 offsets[4], int comp); $gvec4 textureGatherOffsets($gsampler2DArray sampler, vec3 P, ivec2 offsets[4]); @@ -453,47 +478,6 @@ $gvec4 textureGatherOffsets($gsampler2DRect sampler, vec2 P, ivec2 offsets[4], i vec4 textureGatherOffsets(sampler2DShadow sampler, vec2 P, float refZ, ivec2 offsets[4]); vec4 textureGatherOffsets(sampler2DArrayShadow sampler, vec3 P, float refZ, ivec2 offsets[4]); vec4 textureGatherOffsets(sampler2DRectShadow sampler, vec2 P, float refZ, ivec2 offsets[4]); -*/ -vec4 texture1D(sampler1D sampler, float coord); -vec4 texture1D(sampler1D sampler, float coord, float bias); -vec4 texture1DProj(sampler1D sampler, vec2 coord); -vec4 texture1DProj(sampler1D sampler, vec2 coord, float bias); -vec4 texture1DProj(sampler1D sampler, vec4 coord); -vec4 texture1DProj(sampler1D sampler, vec4 coord, float bias); -vec4 texture1DLod(sampler1D sampler, float coord, float lod); -vec4 texture1DProjLod(sampler1D sampler, vec2 coord, float lod); -vec4 texture1DProjLod(sampler1D sampler, vec4 coord, float lod); -vec4 texture2D(sampler2D sampler, vec2 coord); -vec4 texture2D(sampler2D sampler, vec2 coord, float bias); -vec4 texture2DProj(sampler2D sampler, vec3 coord); -vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias); -vec4 texture2DProj(sampler2D sampler, vec4 coord); -vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias); -vec4 texture2DLod(sampler2D sampler, vec2 coord, float lod); -vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod); -vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod); -vec4 texture3D(sampler3D sampler, vec3 coord); -vec4 texture3D(sampler3D sampler, vec3 coord, float bias); -vec4 texture3DProj(sampler3D sampler, vec4 coord); -vec4 texture3DProj(sampler3D sampler, vec4 coord, float bias); -vec4 texture3DLod(sampler3D sampler, vec3 coord, float lod); -vec4 texture3DProjLod(sampler3D sampler, vec4 coord, float lod); -vec4 textureCube(samplerCube sampler, vec3 coord); -vec4 textureCube(samplerCube sampler, vec3 coord, float bias); -vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod); -vec4 shadow1D(sampler1DShadow sampler, vec3 coord); -vec4 shadow1D(sampler1DShadow sampler, vec3 coord, float bias); -vec4 shadow2D(sampler2DShadow sampler, vec3 coord); -vec4 shadow2D(sampler2DShadow sampler, vec3 coord, float bias); -vec4 shadow1DProj(sampler1DShadow sampler, vec4 coord); -vec4 shadow1DProj(sampler1DShadow sampler, vec4 coord, float bias); -vec4 shadow2DProj(sampler2DShadow sampler, vec4 coord); -vec4 shadow2DProj(sampler2DShadow sampler, vec4 coord, float bias); -vec4 shadow1DLod(sampler1DShadow sampler, vec3 coord, float lod); -vec4 shadow2DLod(sampler2DShadow sampler, vec3 coord, float lod); -vec4 shadow1DProjLod(sampler1DShadow sampler, vec4 coord, float lod); -vec4 shadow2DProjLod(sampler2DShadow sampler, vec4 coord, float lod); -/* uint atomicCounterIncrement(atomic_uint c); uint atomicCounter(atomic_uint c); uint atomicAdd(inout uint mem, uint data); @@ -513,13 +497,12 @@ int atomicExchange(inout int mem, int data); uint atomicCompSwap(inout uint mem, uint compare, uint data); int atomicCompSwap(inout int mem, int compare, int data); */ -// section 8.12 Image Functions will go here if and when we add support for them - +// section 8.12 Additional Image Functions will go here if and when we add +// support for them +vec4 imageLoad(image2D image, ivec2 P); +ivec4 imageLoad(iimage2D image, ivec2 P); $genType dFdx($genType p); $genType dFdy($genType p); -$genType fwidth($genType p); -$genType fwidthCoarse($genType p); -$genType fwidthFine($genType p); float interpolateAtSample(float interpolant, int sample); vec2 interpolateAtSample(vec2 interpolant, int sample); vec3 interpolateAtSample(vec3 interpolant, int sample); @@ -528,10 +511,11 @@ float interpolateAtOffset(float interpolant, vec2 offset); vec2 interpolateAtOffset(vec2 interpolant, vec2 offset); vec3 interpolateAtOffset(vec3 interpolant, vec2 offset); vec4 interpolateAtOffset(vec4 interpolant, vec2 offset); -void EmitStreamVertex(int stream); -void EndStreamPrimitive(int stream); -void EmitVertex(); -void EndPrimitive(); + +/* +$genType fwidth($genType p); +$genType fwidthCoarse($genType p); +$genType fwidthFine($genType p); void barrier(); void memoryBarrier(); void memoryBarrierAtomicCounter(); @@ -539,6 +523,7 @@ void memoryBarrierBuffer(); void memoryBarrierShared(); void memoryBarrierImage(); void groupMemoryBarrier(); +*/ ) diff --git a/gfx/skia/skia/src/sksl/sksl_frag.include b/gfx/skia/skia/src/sksl/sksl_frag.include index 123c3393a20c..d65545da66e4 100644 --- a/gfx/skia/skia/src/sksl/sksl_frag.include +++ b/gfx/skia/skia/src/sksl/sksl_frag.include @@ -2,7 +2,20 @@ STRINGIFY( // defines built-in interfaces supported by SkiaSL fragment shaders -layout(builtin=15) in vec4 gl_FragCoord; +layout(builtin=15) in vec4 sk_FragCoord; +layout(builtin=3) float sk_ClipDistance[1]; + +// 9999 is a temporary value that causes us to ignore these declarations beyond +// adding them to the symbol table. This works fine in GLSL (where they do not +// require any further handling) but will fail in SPIR-V. We'll have a better +// solution for this soon. +layout(builtin=9999) vec4 gl_LastFragData[1]; +layout(builtin=9999) vec4 gl_LastFragColor; +layout(builtin=9999) vec4 gl_LastFragColorARM; +layout(builtin=9999) int gl_SampleMaskIn[1]; +layout(builtin=9999) out int gl_SampleMask[1]; +layout(builtin=9999) vec4 gl_SecondaryFragColorEXT; + +layout(location=0,index=0,builtin=10001) out vec4 sk_FragColor; ) - diff --git a/gfx/skia/skia/src/sksl/sksl_geom.include b/gfx/skia/skia/src/sksl/sksl_geom.include new file mode 100644 index 000000000000..18e779f330f3 --- /dev/null +++ b/gfx/skia/skia/src/sksl/sksl_geom.include @@ -0,0 +1,24 @@ +STRINGIFY( + +// defines built-in interfaces supported by SkiaSL geometry shaders + +layout(builtin=10002) in sk_PerVertex { + layout(builtin=0) vec4 gl_Position; + layout(builtin=1) float gl_PointSize; + layout(builtin=3) float sk_ClipDistance[]; +} sk_in[]; + +out sk_PerVertex { + layout(builtin=0) vec4 gl_Position; + layout(builtin=1) float gl_PointSize; + layout(builtin=3) float sk_ClipDistance[]; +}; + +layout(builtin=8) int sk_InvocationID; + +void EmitStreamVertex(int stream); +void EndStreamPrimitive(int stream); +void EmitVertex(); +void EndPrimitive(); + +) diff --git a/gfx/skia/skia/src/sksl/sksl_vert.include b/gfx/skia/skia/src/sksl/sksl_vert.include index 85b53850a08e..e7e9d59ea8bf 100644 --- a/gfx/skia/skia/src/sksl/sksl_vert.include +++ b/gfx/skia/skia/src/sksl/sksl_vert.include @@ -2,10 +2,13 @@ STRINGIFY( // defines built-in interfaces supported by SkiaSL vertex shaders -out gl_PerVertex { - layout(builtin=0) vec4 gl_Position; - layout(builtin=1) float gl_PointSize; +out sk_PerVertex { + layout(builtin=0) vec4 gl_Position; + layout(builtin=1) float gl_PointSize; + layout(builtin=3) float sk_ClipDistance[1]; }; +layout(builtin=5) int sk_VertexID; + ) diff --git a/gfx/skia/skia/src/svg/SkSVGCanvas.cpp b/gfx/skia/skia/src/svg/SkSVGCanvas.cpp index b6634b8a1db5..95a4625417d5 100644 --- a/gfx/skia/skia/src/svg/SkSVGCanvas.cpp +++ b/gfx/skia/skia/src/svg/SkSVGCanvas.cpp @@ -7,11 +7,12 @@ #include "SkSVGCanvas.h" #include "SkSVGDevice.h" +#include "SkMakeUnique.h" -SkCanvas* SkSVGCanvas::Create(const SkRect& bounds, SkXMLWriter* writer) { +std::unique_ptr SkSVGCanvas::Make(const SkRect& bounds, SkXMLWriter* writer) { // TODO: pass full bounds to the device SkISize size = bounds.roundOut().size(); - SkAutoTUnref device(SkSVGDevice::Create(size, writer)); + sk_sp device(SkSVGDevice::Create(size, writer)); - return new SkCanvas(device); + return skstd::make_unique(device.get()); } diff --git a/gfx/skia/skia/src/svg/SkSVGDevice.cpp b/gfx/skia/skia/src/svg/SkSVGDevice.cpp index 16e2b3f7b5f4..4c0898689303 100644 --- a/gfx/skia/skia/src/svg/SkSVGDevice.cpp +++ b/gfx/skia/skia/src/svg/SkSVGDevice.cpp @@ -22,6 +22,7 @@ #include "SkTypeface.h" #include "SkUtils.h" #include "SkXMLWriter.h" +#include "SkClipOpPriv.h" namespace { @@ -273,6 +274,14 @@ private: uint32_t fImageCount; }; +struct SkSVGDevice::MxCp { + const SkMatrix* fMatrix; + const SkClipStack* fClipStack; + + MxCp(const SkMatrix* mx, const SkClipStack* cs) : fMatrix(mx), fClipStack(cs) {} + MxCp(SkSVGDevice* device) : fMatrix(&device->ctm()), fClipStack(&device->cs()) {} +}; + class SkSVGDevice::AutoElement : ::SkNoncopyable { public: AutoElement(const char name[], SkXMLWriter* writer) @@ -282,11 +291,11 @@ public: } AutoElement(const char name[], SkXMLWriter* writer, ResourceBucket* bucket, - const SkDraw& draw, const SkPaint& paint) + const MxCp& mc, const SkPaint& paint) : fWriter(writer) , fResourceBucket(bucket) { - Resources res = this->addResources(draw, paint); + Resources res = this->addResources(mc, paint); if (!res.fClip.isEmpty()) { // The clip is in device space. Apply it via a wrapper to avoid local transform // interference. @@ -298,8 +307,8 @@ public: this->addPaint(paint, res); - if (!draw.fMatrix->isIdentity()) { - this->addAttribute("transform", svg_transform(*draw.fMatrix)); + if (!mc.fMatrix->isIdentity()) { + this->addAttribute("transform", svg_transform(*mc.fMatrix)); } } @@ -332,8 +341,8 @@ public: void addTextAttributes(const SkPaint&); private: - Resources addResources(const SkDraw& draw, const SkPaint& paint); - void addClipResources(const SkDraw& draw, Resources* resources); + Resources addResources(const MxCp&, const SkPaint& paint); + void addClipResources(const MxCp&, Resources* resources); void addShaderResources(const SkPaint& paint, Resources* resources); void addPaint(const SkPaint& paint, const Resources& resources); @@ -342,7 +351,7 @@ private: SkXMLWriter* fWriter; ResourceBucket* fResourceBucket; - SkAutoTDelete fClipGroup; + std::unique_ptr fClipGroup; }; void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& resources) { @@ -390,18 +399,18 @@ void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& r } } -Resources SkSVGDevice::AutoElement::addResources(const SkDraw& draw, const SkPaint& paint) { +Resources SkSVGDevice::AutoElement::addResources(const MxCp& mc, const SkPaint& paint) { Resources resources(paint); // FIXME: this is a weak heuristic and we end up with LOTS of redundant clips. - bool hasClip = !draw.fClipStack->isWideOpen(); + bool hasClip = !mc.fClipStack->isWideOpen(); bool hasShader = SkToBool(paint.getShader()); if (hasClip || hasShader) { AutoElement defs("defs", fWriter); if (hasClip) { - this->addClipResources(draw, &resources); + this->addClipResources(mc, &resources); } if (hasShader) { @@ -437,11 +446,11 @@ void SkSVGDevice::AutoElement::addShaderResources(const SkPaint& paint, Resource resources->fPaintServer.printf("url(#%s)", addLinearGradientDef(grInfo, shader).c_str()); } -void SkSVGDevice::AutoElement::addClipResources(const SkDraw& draw, Resources* resources) { - SkASSERT(!draw.fClipStack->isWideOpen()); +void SkSVGDevice::AutoElement::addClipResources(const MxCp& mc, Resources* resources) { + SkASSERT(!mc.fClipStack->isWideOpen()); SkPath clipPath; - (void) draw.fClipStack->asPath(&clipPath); + (void) mc.fClipStack->asPath(&clipPath); SkString clipID = fResourceBucket->addClip(); const char* clipRule = clipPath.getFillType() == SkPath::kEvenOdd_FillType ? @@ -534,8 +543,7 @@ void SkSVGDevice::AutoElement::addTextAttributes(const SkPaint& paint) { SkString familyName; SkTHashSet familySet; - sk_sp tface(paint.getTypeface() ? - sk_ref_sp(paint.getTypeface()) : SkTypeface::MakeDefault()); + sk_sp tface(paint.getTypeface() ? paint.refTypeface() : SkTypeface::MakeDefault()); SkASSERT(tface); SkTypeface::Style style = tface->style(); @@ -546,16 +554,17 @@ void SkSVGDevice::AutoElement::addTextAttributes(const SkPaint& paint) { this->addAttribute("font-weight", "bold"); } - SkAutoTUnref familyNameIter(tface->createFamilyNameIterator()); + sk_sp familyNameIter(tface->createFamilyNameIterator()); SkTypeface::LocalizedString familyString; - while (familyNameIter->next(&familyString)) { - if (familySet.contains(familyString.fString)) { - continue; + if (familyNameIter) { + while (familyNameIter->next(&familyString)) { + if (familySet.contains(familyString.fString)) { + continue; + } + familySet.add(familyString.fString); + familyName.appendf((familyName.isEmpty() ? "%s" : ", %s"), familyString.fString.c_str()); } - familySet.add(familyString.fString); - familyName.appendf((familyName.isEmpty() ? "%s" : ", %s"), familyString.fString.c_str()); } - if (!familyName.isEmpty()) { this->addAttribute("font-family", familyName); } @@ -591,13 +600,13 @@ SkSVGDevice::SkSVGDevice(const SkISize& size, SkXMLWriter* writer) SkSVGDevice::~SkSVGDevice() { } -void SkSVGDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { - AutoElement rect("rect", fWriter, fResourceBucket, draw, paint); +void SkSVGDevice::drawPaint(const SkPaint& paint) { + AutoElement rect("rect", fWriter, fResourceBucket.get(), MxCp(this), paint); rect.addRectAttributes(SkRect::MakeWH(SkIntToScalar(this->width()), SkIntToScalar(this->height()))); } -void SkSVGDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, +void SkSVGDevice::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { SkPath path; @@ -612,7 +621,7 @@ void SkSVGDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_ path.rewind(); path.moveTo(pts[i]); path.lineTo(pts[i+1]); - AutoElement elem("path", fWriter, fResourceBucket, draw, paint); + AutoElement elem("path", fWriter, fResourceBucket.get(), MxCp(this), paint); elem.addPathAttributes(path); } break; @@ -620,37 +629,37 @@ void SkSVGDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_ if (count > 1) { path.addPoly(pts, SkToInt(count), false); path.moveTo(pts[0]); - AutoElement elem("path", fWriter, fResourceBucket, draw, paint); + AutoElement elem("path", fWriter, fResourceBucket.get(), MxCp(this), paint); elem.addPathAttributes(path); } break; } } -void SkSVGDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { - AutoElement rect("rect", fWriter, fResourceBucket, draw, paint); +void SkSVGDevice::drawRect(const SkRect& r, const SkPaint& paint) { + AutoElement rect("rect", fWriter, fResourceBucket.get(), MxCp(this), paint); rect.addRectAttributes(r); } -void SkSVGDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { - AutoElement ellipse("ellipse", fWriter, fResourceBucket, draw, paint); +void SkSVGDevice::drawOval(const SkRect& oval, const SkPaint& paint) { + AutoElement ellipse("ellipse", fWriter, fResourceBucket.get(), MxCp(this), paint); ellipse.addAttribute("cx", oval.centerX()); ellipse.addAttribute("cy", oval.centerY()); ellipse.addAttribute("rx", oval.width() / 2); ellipse.addAttribute("ry", oval.height() / 2); } -void SkSVGDevice::drawRRect(const SkDraw& draw, const SkRRect& rr, const SkPaint& paint) { +void SkSVGDevice::drawRRect(const SkRRect& rr, const SkPaint& paint) { SkPath path; path.addRRect(rr); - AutoElement elem("path", fWriter, fResourceBucket, draw, paint); + AutoElement elem("path", fWriter, fResourceBucket.get(), MxCp(this), paint); elem.addPathAttributes(path); } -void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint& paint, +void SkSVGDevice::drawPath(const SkPath& path, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) { - AutoElement elem("path", fWriter, fResourceBucket, draw, paint); + AutoElement elem("path", fWriter, fResourceBucket.get(), MxCp(this), paint); elem.addPathAttributes(path); // TODO: inverse fill types? @@ -659,10 +668,13 @@ void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint } } -void SkSVGDevice::drawBitmapCommon(const SkDraw& draw, const SkBitmap& bm, - const SkPaint& paint) { - SkAutoTUnref pngData( - SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality)); +static sk_sp encode(const SkBitmap& src) { + SkDynamicMemoryWStream buf; + return SkEncodeImage(&buf, src, SkEncodedImageFormat::kPNG, 80) ? buf.detachAsData() : nullptr; +} + +void SkSVGDevice::drawBitmapCommon(const MxCp& mc, const SkBitmap& bm, const SkPaint& paint) { + sk_sp pngData = encode(bm); if (!pngData) { return; } @@ -687,57 +699,53 @@ void SkSVGDevice::drawBitmapCommon(const SkDraw& draw, const SkBitmap& bm, } { - AutoElement imageUse("use", fWriter, fResourceBucket, draw, paint); + AutoElement imageUse("use", fWriter, fResourceBucket.get(), mc, paint); imageUse.addAttribute("xlink:href", SkStringPrintf("#%s", imageID.c_str())); } } -void SkSVGDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, +void SkSVGDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint& paint) { - SkMatrix adjustedMatrix = *draw.fMatrix; + MxCp mc(this); + SkMatrix adjustedMatrix = *mc.fMatrix; adjustedMatrix.preConcat(matrix); - SkDraw adjustedDraw(draw); - adjustedDraw.fMatrix = &adjustedMatrix; + mc.fMatrix = &adjustedMatrix; - drawBitmapCommon(adjustedDraw, bitmap, paint); + drawBitmapCommon(mc, bitmap, paint); } -void SkSVGDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, +void SkSVGDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) { - SkMatrix adjustedMatrix = *draw.fMatrix; + MxCp mc(this); + SkMatrix adjustedMatrix = *mc.fMatrix; adjustedMatrix.preTranslate(SkIntToScalar(x), SkIntToScalar(y)); - SkDraw adjustedDraw(draw); - adjustedDraw.fMatrix = &adjustedMatrix; + mc.fMatrix = &adjustedMatrix; - drawBitmapCommon(adjustedDraw, bitmap, paint); + drawBitmapCommon(mc, bitmap, paint); } -void SkSVGDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bm, const SkRect* srcOrNull, +void SkSVGDevice::drawBitmapRect(const SkBitmap& bm, const SkRect* srcOrNull, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint) { + SkClipStack* cs = &this->cs(); + SkClipStack::AutoRestore ar(cs, false); + if (srcOrNull && *srcOrNull != SkRect::Make(bm.bounds())) { + cs->save(); + cs->clipRect(dst, this->ctm(), kIntersect_SkClipOp, paint.isAntiAlias()); + } + SkMatrix adjustedMatrix; adjustedMatrix.setRectToRect(srcOrNull ? *srcOrNull : SkRect::Make(bm.bounds()), dst, SkMatrix::kFill_ScaleToFit); - adjustedMatrix.postConcat(*draw.fMatrix); + adjustedMatrix.postConcat(this->ctm()); - SkDraw adjustedDraw(draw); - adjustedDraw.fMatrix = &adjustedMatrix; - - SkClipStack adjustedClipStack; - if (srcOrNull && *srcOrNull != SkRect::Make(bm.bounds())) { - adjustedClipStack = *draw.fClipStack; - adjustedClipStack.clipRect(dst, *draw.fMatrix, SkCanvas::kIntersect_Op, - paint.isAntiAlias()); - adjustedDraw.fClipStack = &adjustedClipStack; - } - - drawBitmapCommon(adjustedDraw, bm, paint); + drawBitmapCommon(MxCp(&adjustedMatrix, cs), bm, paint); } -void SkSVGDevice::drawText(const SkDraw& draw, const void* text, size_t len, +void SkSVGDevice::drawText(const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint& paint) { - AutoElement elem("text", fWriter, fResourceBucket, draw, paint); + AutoElement elem("text", fWriter, fResourceBucket.get(), MxCp(this), paint); elem.addTextAttributes(paint); SVGTextBuilder builder(text, len, paint, SkPoint::Make(x, y), 0); @@ -746,12 +754,12 @@ void SkSVGDevice::drawText(const SkDraw& draw, const void* text, size_t len, elem.addText(builder.text()); } -void SkSVGDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, +void SkSVGDevice::drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2); - AutoElement elem("text", fWriter, fResourceBucket, draw, paint); + AutoElement elem("text", fWriter, fResourceBucket.get(), MxCp(this), paint); elem.addTextAttributes(paint); SVGTextBuilder builder(text, len, paint, offset, scalarsPerPos, pos); @@ -760,7 +768,7 @@ void SkSVGDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, elem.addText(builder.text()); } -void SkSVGDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, const SkPath& path, +void SkSVGDevice::drawTextOnPath(const void* text, size_t len, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { SkString pathID = fResourceBucket->addPath(); @@ -797,16 +805,12 @@ void SkSVGDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, co } } -void SkSVGDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, - const SkPoint verts[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { +void SkSVGDevice::drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) { // todo SkDebugf("unsupported operation: drawVertices()\n"); } -void SkSVGDevice::drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, +void SkSVGDevice::drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) { // todo SkDebugf("unsupported operation: drawDevice()\n"); diff --git a/gfx/skia/skia/src/svg/SkSVGDevice.h b/gfx/skia/skia/src/svg/SkSVGDevice.h index cb13ffdc8c03..e05dc9283ea9 100644 --- a/gfx/skia/skia/src/svg/SkSVGDevice.h +++ b/gfx/skia/skia/src/svg/SkSVGDevice.h @@ -8,66 +8,63 @@ #ifndef SkSVGDevice_DEFINED #define SkSVGDevice_DEFINED -#include "SkDevice.h" +#include "SkClipStackDevice.h" #include "SkTemplates.h" class SkXMLWriter; -class SkSVGDevice : public SkBaseDevice { +class SkSVGDevice : public SkClipStackDevice { public: static SkBaseDevice* Create(const SkISize& size, SkXMLWriter* writer); protected: - void drawPaint(const SkDraw&, const SkPaint& paint) override; - void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, + void drawPaint(const SkPaint& paint) override; + void drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint[], const SkPaint& paint) override; - void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) override; - void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) override; - void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) override; - void drawPath(const SkDraw&, const SkPath& path, + void drawRect(const SkRect& r, const SkPaint& paint) override; + void drawOval(const SkRect& oval, const SkPaint& paint) override; + void drawRRect(const SkRRect& rr, const SkPaint& paint) override; + void drawPath(const SkPath& path, const SkPaint& paint, const SkMatrix* prePathMatrix = nullptr, bool pathIsMutable = false) override; - void drawBitmap(const SkDraw&, const SkBitmap& bitmap, + void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint& paint) override; - void drawSprite(const SkDraw&, const SkBitmap& bitmap, + void drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) override; - void drawBitmapRect(const SkDraw&, const SkBitmap&, + void drawBitmapRect(const SkBitmap&, const SkRect* srcOrNull, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint) override; - void drawText(const SkDraw&, const void* text, size_t len, + void drawText(const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint& paint) override; - void drawPosText(const SkDraw&, const void* text, size_t len, + void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override; - void drawTextOnPath(const SkDraw&, const void* text, size_t len, + void drawTextOnPath(const void* text, size_t len, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) override; - void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, - const SkPoint verts[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) override; + void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) override; - void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, + void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; private: SkSVGDevice(const SkISize& size, SkXMLWriter* writer); - virtual ~SkSVGDevice(); + ~SkSVGDevice() override; - void drawBitmapCommon(const SkDraw& draw, const SkBitmap& bm, const SkPaint& paint); + struct MxCp; + void drawBitmapCommon(const MxCp&, const SkBitmap& bm, const SkPaint& paint); class AutoElement; class ResourceBucket; - SkXMLWriter* fWriter; - SkAutoTDelete fRootElement; - SkAutoTDelete fResourceBucket; + SkXMLWriter* fWriter; + std::unique_ptr fRootElement; + std::unique_ptr fResourceBucket; - typedef SkBaseDevice INHERITED; + typedef SkClipStackDevice INHERITED; }; #endif // SkSVGDevice_DEFINED diff --git a/gfx/skia/skia/src/utils/SkBoundaryPatch.cpp b/gfx/skia/skia/src/utils/SkBoundaryPatch.cpp deleted file mode 100644 index 0cfb09c2c712..000000000000 --- a/gfx/skia/skia/src/utils/SkBoundaryPatch.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkBoundaryPatch.h" - -SkBoundaryPatch::SkBoundaryPatch() : fBoundary(nullptr) {} - -SkBoundaryPatch::~SkBoundaryPatch() { - SkSafeUnref(fBoundary); -} - -SkBoundary* SkBoundaryPatch::setBoundary(SkBoundary* b) { - SkRefCnt_SafeAssign(fBoundary, b); - return b; -} - -static SkPoint SkMakePoint(SkScalar x, SkScalar y) { - SkPoint pt; - pt.set(x, y); - return pt; -} - -static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) { - return SkMakePoint(SkScalarInterp(a.fX, b.fX, t), - SkScalarInterp(a.fY, b.fY, t)); -} - -SkPoint SkBoundaryPatch::eval(SkScalar unitU, SkScalar unitV) { - SkBoundary* b = fBoundary; - SkPoint u = SkPointInterp(b->eval(SkBoundary::kLeft, SK_Scalar1 - unitV), - b->eval(SkBoundary::kRight, unitV), - unitU); - SkPoint v = SkPointInterp(b->eval(SkBoundary::kTop, unitU), - b->eval(SkBoundary::kBottom, SK_Scalar1 - unitU), - unitV); - return SkMakePoint(SkScalarAve(u.fX, v.fX), - SkScalarAve(u.fY, v.fY)); -} - -bool SkBoundaryPatch::evalPatch(SkPoint verts[], int rows, int cols) { - if (rows < 2 || cols < 2) { - return false; - } - - const SkScalar invR = SkScalarInvert(SkIntToScalar(rows - 1)); - const SkScalar invC = SkScalarInvert(SkIntToScalar(cols - 1)); - - for (int y = 0; y < cols; y++) { - SkScalar yy = y * invC; - for (int x = 0; x < rows; x++) { - *verts++ = this->eval(x * invR, yy); - } - } - return true; -} - -//////////////////////////////////////////////////////////////////////// - -#include "SkGeometry.h" - -SkPoint SkLineBoundary::eval(Edge e, SkScalar t) { - SkASSERT((unsigned)e < 4); - return SkPointInterp(fPts[e], fPts[(e + 1) & 3], t); -} - -SkPoint SkCubicBoundary::eval(Edge e, SkScalar t) { - SkASSERT((unsigned)e < 4); - - // ensure our 4th cubic wraps to the start of the first - fPts[12] = fPts[0]; - - SkPoint loc; - SkEvalCubicAt(&fPts[e * 3], t, &loc, nullptr, nullptr); - return loc; -} diff --git a/gfx/skia/skia/src/utils/SkCamera.cpp b/gfx/skia/skia/src/utils/SkCamera.cpp index c8c462a5f71a..cb364a504e2c 100644 --- a/gfx/skia/skia/src/utils/SkCamera.cpp +++ b/gfx/skia/skia/src/utils/SkCamera.cpp @@ -83,11 +83,11 @@ void SkPatch3D::transform(const SkMatrix3D& m, SkPatch3D* dst) const { } SkScalar SkPatch3D::dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const { - SkScalar cx = SkScalarMul(fU.fY, fV.fZ) - SkScalarMul(fU.fZ, fV.fY); - SkScalar cy = SkScalarMul(fU.fZ, fV.fX) - SkScalarMul(fU.fX, fV.fY); - SkScalar cz = SkScalarMul(fU.fX, fV.fY) - SkScalarMul(fU.fY, fV.fX); + SkScalar cx = fU.fY * fV.fZ - fU.fZ * fV.fY; + SkScalar cy = fU.fZ * fV.fX - fU.fX * fV.fY; + SkScalar cz = fU.fX * fV.fY - fU.fY * fV.fX; - return SkScalarMul(cx, dx) + SkScalarMul(cy, dy) + SkScalarMul(cz, dz); + return cx * dx + cy * dy + cz * dz; } /////////////////////////////////////////////////////////////////////////////// @@ -214,6 +214,7 @@ void SkCamera3D::update() { void SkCamera3D::doUpdate() const { SkUnit3D axis, zenith, cross; + // construct a orthonormal basis of cross (x), zenith (y), and axis (z) fAxis.normalize(&axis); { @@ -234,6 +235,20 @@ void SkCamera3D::doUpdate() const { SkScalar y = fObserver.fY; SkScalar z = fObserver.fZ; + // Looking along the view axis we have: + // + // /|\ zenith + // | + // | + // | * observer (projected on XY plane) + // | + // |____________\ cross + // / + // + // So this does a z-shear along the view axis based on the observer's x and y values, + // and scales in x and y relative to the negative of the observer's z value + // (the observer is in the negative z direction). + orien->set(SkMatrix::kMScaleX, x * axis.fX - z * cross.fX); orien->set(SkMatrix::kMSkewX, x * axis.fY - z * cross.fY); orien->set(SkMatrix::kMTransX, x * axis.fZ - z * cross.fZ); @@ -264,6 +279,15 @@ void SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const { dot = SkUnit3D::Dot(*SkTCast(&diff), *SkTCast(SkTCast(&fOrientation) + 6)); + // This multiplies fOrientation by the matrix [quilt.fU quilt.fV diff] -- U, V, and diff are + // column vectors in the matrix -- then divides by the length of the projection of diff onto + // the view axis (which is 'dot'). This transforms the patch (which transforms from local path + // space to world space) into view space (since fOrientation transforms from world space to + // view space). + // + // The divide by 'dot' isn't strictly necessary as the homogeneous divide would do much the + // same thing (it's just scaling the entire matrix by 1/dot). It looks like it's normalizing + // the matrix into some canonical space. patchPtr = (const SkScalar*)&quilt; matrix->set(SkMatrix::kMScaleX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot)); matrix->set(SkMatrix::kMSkewY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot)); diff --git a/gfx/skia/skia/src/utils/SkCanvasStack.cpp b/gfx/skia/skia/src/utils/SkCanvasStack.cpp index 58607d7d2934..38cd21013e37 100644 --- a/gfx/skia/skia/src/utils/SkCanvasStack.cpp +++ b/gfx/skia/skia/src/utils/SkCanvasStack.cpp @@ -13,18 +13,19 @@ SkCanvasStack::~SkCanvasStack() { this->removeAll(); } -void SkCanvasStack::pushCanvas(SkCanvas* canvas, const SkIPoint& origin) { +void SkCanvasStack::pushCanvas(std::unique_ptr canvas, const SkIPoint& origin) { if (canvas) { // compute the bounds of this canvas - const SkIRect canvasBounds = SkIRect::MakeSize(canvas->getDeviceSize()); + const SkIRect canvasBounds = SkIRect::MakeSize(canvas->getBaseLayerSize()); // push the canvas onto the stack - this->INHERITED::addCanvas(canvas); + this->INHERITED::addCanvas(canvas.get()); // push the canvas data onto the stack CanvasData* data = &fCanvasData.push_back(); data->origin = origin; data->requiredClip.setRect(canvasBounds); + data->ownedCanvas = std::move(canvas); // subtract this region from the canvas objects already on the stack. // This ensures they do not draw into the space occupied by the layers @@ -41,8 +42,8 @@ void SkCanvasStack::pushCanvas(SkCanvas* canvas, const SkIPoint& origin) { } void SkCanvasStack::removeAll() { + this->INHERITED::removeAll(); // call the baseclass *before* we actually delete the canvases fCanvasData.reset(); - this->INHERITED::removeAll(); } /** @@ -76,22 +77,22 @@ void SkCanvasStack::didSetMatrix(const SkMatrix& matrix) { this->SkCanvas::didSetMatrix(matrix); } -void SkCanvasStack::onClipRect(const SkRect& r, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkCanvasStack::onClipRect(const SkRect& r, SkClipOp op, ClipEdgeStyle edgeStyle) { this->INHERITED::onClipRect(r, op, edgeStyle); this->clipToZOrderedBounds(); } -void SkCanvasStack::onClipRRect(const SkRRect& rr, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkCanvasStack::onClipRRect(const SkRRect& rr, SkClipOp op, ClipEdgeStyle edgeStyle) { this->INHERITED::onClipRRect(rr, op, edgeStyle); this->clipToZOrderedBounds(); } -void SkCanvasStack::onClipPath(const SkPath& p, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkCanvasStack::onClipPath(const SkPath& p, SkClipOp op, ClipEdgeStyle edgeStyle) { this->INHERITED::onClipPath(p, op, edgeStyle); this->clipToZOrderedBounds(); } -void SkCanvasStack::onClipRegion(const SkRegion& deviceRgn, ClipOp op) { +void SkCanvasStack::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { SkASSERT(fList.count() == fCanvasData.count()); for (int i = 0; i < fList.count(); ++i) { SkRegion tempRegion; diff --git a/gfx/skia/skia/src/utils/SkCanvasStack.h b/gfx/skia/skia/src/utils/SkCanvasStack.h index 762ab9f76f3c..22cfc3e53847 100644 --- a/gfx/skia/skia/src/utils/SkCanvasStack.h +++ b/gfx/skia/skia/src/utils/SkCanvasStack.h @@ -9,14 +9,21 @@ #define SkCanvasStack_DEFINED #include "SkNWayCanvas.h" +#include "SkRegion.h" #include "SkTArray.h" +/** + * Like NWayCanvas, in that it forwards all canvas methods to each sub-canvas that is "pushed". + * + * Unlike NWayCanvas, this takes ownership of each subcanvas, and deletes them when this canvas + * is deleted. + */ class SkCanvasStack : public SkNWayCanvas { public: SkCanvasStack(int width, int height); - virtual ~SkCanvasStack(); + ~SkCanvasStack() override; - void pushCanvas(SkCanvas* canvas, const SkIPoint& origin); + void pushCanvas(std::unique_ptr, const SkIPoint& origin); void removeAll() override; /* @@ -31,10 +38,10 @@ public: protected: void didSetMatrix(const SkMatrix&) override; - void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; - void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, ClipOp) override; + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; private: void clipToZOrderedBounds(); @@ -42,6 +49,7 @@ private: struct CanvasData { SkIPoint origin; SkRegion requiredClip; + std::unique_ptr ownedCanvas; }; SkTArray fCanvasData; diff --git a/gfx/skia/skia/src/utils/SkCanvasStateUtils.cpp b/gfx/skia/skia/src/utils/SkCanvasStateUtils.cpp index cc8ea43d43a9..0c50bad0f6e5 100644 --- a/gfx/skia/skia/src/utils/SkCanvasStateUtils.cpp +++ b/gfx/skia/skia/src/utils/SkCanvasStateUtils.cpp @@ -10,9 +10,9 @@ #include "SkCanvas.h" #include "SkCanvasStack.h" #include "SkDevice.h" -#include "SkErrorInternals.h" #include "SkRasterClip.h" #include "SkWriter32.h" +#include "SkClipOpPriv.h" /* * WARNING: The structs below are part of a stable ABI and as such we explicitly @@ -101,14 +101,12 @@ class SkCanvasState_v1 : public SkCanvasState { public: static const int32_t kVersion = 1; - SkCanvasState_v1(SkCanvas* canvas) - : INHERITED(kVersion, canvas) - { + SkCanvasState_v1(SkCanvas* canvas) : INHERITED(kVersion, canvas) { layerCount = 0; layers = nullptr; mcState.clipRectCount = 0; mcState.clipRects = nullptr; - originalCanvas = SkRef(canvas); + originalCanvas = canvas; } ~SkCanvasState_v1() { @@ -119,10 +117,6 @@ public: sk_free(mcState.clipRects); sk_free(layers); - - // it is now safe to free the canvas since there should be no remaining - // references to the content that is referenced by this canvas (e.g. pixels) - originalCanvas->unref(); } SkMCState mcState; @@ -136,28 +130,6 @@ private: //////////////////////////////////////////////////////////////////////////////// -class ClipValidator : public SkCanvas::ClipVisitor { -public: - ClipValidator() : fFailed(false) {} - bool failed() { return fFailed; } - - // ClipVisitor - void clipRect(const SkRect& rect, SkCanvas::ClipOp op, bool antialias) override { - fFailed |= antialias; - } - - void clipRRect(const SkRRect& rrect, SkCanvas::ClipOp op, bool antialias) override { - fFailed |= antialias; - } - - void clipPath(const SkPath&, SkCanvas::ClipOp, bool antialias) override { - fFailed |= antialias; - } - -private: - bool fFailed; -}; - static void setup_MC_state(SkMCState* state, const SkMatrix& matrix, const SkRegion& clip) { // initialize the struct state->clipRectCount = 0; @@ -199,19 +171,18 @@ SkCanvasState* SkCanvasStateUtils::CaptureCanvasState(SkCanvas* canvas) { SkASSERT(canvas); // Check the clip can be decomposed into rectangles (i.e. no soft clips). - ClipValidator validator; - canvas->replayClips(&validator); - if (validator.failed()) { - SkErrorInternals::SetError(kInvalidOperation_SkError, - "CaptureCanvasState does not support canvases with antialiased clips.\n"); + if (canvas->androidFramework_isClipAA()) { return nullptr; } - SkAutoTDelete canvasState(new SkCanvasState_v1(canvas)); + std::unique_ptr canvasState(new SkCanvasState_v1(canvas)); // decompose the total matrix and clip - setup_MC_state(&canvasState->mcState, canvas->getTotalMatrix(), - canvas->internal_private_getTotalClip()); + { + SkRegion rgn; + canvas->temporary_internal_getRgnClip(&rgn); + setup_MC_state(&canvasState->mcState, canvas->getTotalMatrix(), rgn); + } /* * decompose the layers @@ -251,7 +222,9 @@ SkCanvasState* SkCanvasStateUtils::CaptureCanvasState(SkCanvas* canvas) { layerState->raster.rowBytes = pmap.rowBytes(); layerState->raster.pixels = pmap.writable_addr(); - setup_MC_state(&layerState->mcState, layer.matrix(), layer.clip().bwRgn()); + SkRegion rgn; + layer.clip(&rgn); + setup_MC_state(&layerState->mcState, layer.matrix(), rgn); layerCount++; } @@ -284,10 +257,11 @@ static void setup_canvas_from_MC_state(const SkMCState& state, SkCanvas* canvas) } canvas->setMatrix(matrix); - canvas->clipRegion(clip, SkCanvas::kReplace_Op); + canvas->clipRegion(clip, kReplace_SkClipOp); } -static SkCanvas* create_canvas_from_canvas_layer(const SkCanvasLayerState& layerState) { +static std::unique_ptr +make_canvas_from_canvas_layer(const SkCanvasLayerState& layerState) { SkASSERT(kRaster_CanvasBackend == layerState.type); SkBitmap bitmap; @@ -307,15 +281,15 @@ static SkCanvas* create_canvas_from_canvas_layer(const SkCanvasLayerState& layer SkASSERT(!bitmap.empty()); SkASSERT(!bitmap.isNull()); - SkAutoTUnref canvas(new SkCanvas(bitmap)); + std::unique_ptr canvas(new SkCanvas(bitmap)); // setup the matrix and clip setup_canvas_from_MC_state(layerState.mcState, canvas.get()); - return canvas.release(); + return canvas; } -SkCanvas* SkCanvasStateUtils::CreateFromCanvasState(const SkCanvasState* state) { +std::unique_ptr SkCanvasStateUtils::MakeFromCanvasState(const SkCanvasState* state) { SkASSERT(state); // Currently there is only one possible version. SkASSERT(SkCanvasState_v1::kVersion == state->version); @@ -326,22 +300,22 @@ SkCanvas* SkCanvasStateUtils::CreateFromCanvasState(const SkCanvasState* state) return nullptr; } - SkAutoTUnref canvas(new SkCanvasStack(state->width, state->height)); + std::unique_ptr canvas(new SkCanvasStack(state->width, state->height)); // setup the matrix and clip on the n-way canvas - setup_canvas_from_MC_state(state_v1->mcState, canvas); + setup_canvas_from_MC_state(state_v1->mcState, canvas.get()); // Iterate over the layers and add them to the n-way canvas for (int i = state_v1->layerCount - 1; i >= 0; --i) { - SkAutoTUnref canvasLayer(create_canvas_from_canvas_layer(state_v1->layers[i])); + std::unique_ptr canvasLayer = make_canvas_from_canvas_layer(state_v1->layers[i]); if (!canvasLayer.get()) { return nullptr; } - canvas->pushCanvas(canvasLayer.get(), SkIPoint::Make(state_v1->layers[i].x, - state_v1->layers[i].y)); + canvas->pushCanvas(std::move(canvasLayer), SkIPoint::Make(state_v1->layers[i].x, + state_v1->layers[i].y)); } - return canvas.release(); + return std::move(canvas); } //////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/utils/SkCurveMeasure.cpp b/gfx/skia/skia/src/utils/SkCurveMeasure.cpp index a82008e67e25..140228dbfae8 100644 --- a/gfx/skia/skia/src/utils/SkCurveMeasure.cpp +++ b/gfx/skia/skia/src/utils/SkCurveMeasure.cpp @@ -67,19 +67,28 @@ static inline SkVector evaluateDerivative(const SkPoint pts[4], } /// Used in ArcLengthIntegrator::computeLength static inline Sk8f evaluateDerivativeLength(const Sk8f& ts, - const Sk8f (&xCoeff)[3], - const Sk8f (&yCoeff)[3], + const float (&xCoeff)[3][8], + const float (&yCoeff)[3][8], const SkSegType segType) { Sk8f x; Sk8f y; + + Sk8f x0 = Sk8f::Load(&xCoeff[0]), + x1 = Sk8f::Load(&xCoeff[1]), + x2 = Sk8f::Load(&xCoeff[2]); + + Sk8f y0 = Sk8f::Load(&yCoeff[0]), + y1 = Sk8f::Load(&yCoeff[1]), + y2 = Sk8f::Load(&yCoeff[2]); + switch (segType) { case kQuad_SegType: - x = xCoeff[0]*ts + xCoeff[1]; - y = yCoeff[0]*ts + yCoeff[1]; + x = x0*ts + x1; + y = y0*ts + y1; break; case kCubic_SegType: - x = (xCoeff[0]*ts + xCoeff[1])*ts + xCoeff[2]; - y = (yCoeff[0]*ts + yCoeff[1])*ts + yCoeff[2]; + x = (x0*ts + x1)*ts + x2; + y = (y0*ts + y1)*ts + y2; break; case kConic_SegType: UNIMPLEMENTED; @@ -106,11 +115,11 @@ ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) float Cy = pts[2].y(); // precompute coefficients for derivative - xCoeff[0] = Sk8f(2*(Ax - 2*Bx + Cx)); - xCoeff[1] = Sk8f(2*(Bx - Ax)); + Sk8f(2*(Ax - 2*Bx + Cx)).store(&xCoeff[0]); + Sk8f(2*(Bx - Ax)).store(&xCoeff[1]); - yCoeff[0] = Sk8f(2*(Ay - 2*By + Cy)); - yCoeff[1] = Sk8f(2*(By - Ay)); + Sk8f(2*(Ay - 2*By + Cy)).store(&yCoeff[0]); + Sk8f(2*(By - Ay)).store(&yCoeff[1]); } break; case kCubic_SegType: @@ -125,13 +134,13 @@ ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) float Dy = pts[3].y(); // precompute coefficients for derivative - xCoeff[0] = Sk8f(3*(-Ax + 3*(Bx - Cx) + Dx)); - xCoeff[1] = Sk8f(6*(Ax - 2*Bx + Cx)); - xCoeff[2] = Sk8f(3*(-Ax + Bx)); + Sk8f(3*(-Ax + 3*(Bx - Cx) + Dx)).store(&xCoeff[0]); + Sk8f(6*(Ax - 2*Bx + Cx)).store(&xCoeff[1]); + Sk8f(3*(-Ax + Bx)).store(&xCoeff[2]); - yCoeff[0] = Sk8f(3*(-Ay + 3*(By - Cy) + Dy)); - yCoeff[1] = Sk8f(6*(Ay - 2*By + Cy)); - yCoeff[2] = Sk8f(3*(-Ay + By)); + Sk8f(3*(-Ay + 3*(By - Cy) + Dy)).store(&yCoeff[0]); + Sk8f(6*(Ay - 2*By + Cy)).store(&yCoeff[1]); + Sk8f(3*(-Ay + By)).store(&yCoeff[2]); } break; case kConic_SegType: diff --git a/gfx/skia/skia/src/utils/SkCurveMeasure.h b/gfx/skia/skia/src/utils/SkCurveMeasure.h index 5807211236ef..3d1c415598ce 100644 --- a/gfx/skia/skia/src/utils/SkCurveMeasure.h +++ b/gfx/skia/skia/src/utils/SkCurveMeasure.h @@ -37,8 +37,8 @@ private: SkSegType fSegType; // precomputed coefficients for derivatives in Horner form - Sk8f xCoeff[3]; - Sk8f yCoeff[3]; + float xCoeff[3][8]; + float yCoeff[3][8]; }; class SkCurveMeasure { diff --git a/gfx/skia/skia/src/utils/SkDashPath.cpp b/gfx/skia/skia/src/utils/SkDashPath.cpp index c0cdcc195d20..4b5e58ef4f31 100644 --- a/gfx/skia/skia/src/utils/SkDashPath.cpp +++ b/gfx/skia/skia/src/utils/SkDashPath.cpp @@ -77,7 +77,7 @@ static void outset_for_stroke(SkRect* rect, const SkStrokeRec& rec) { radius = SK_Scalar1; // hairlines } if (SkPaint::kMiter_Join == rec.getJoin()) { - radius = SkScalarMul(radius, rec.getMiter()); + radius *= rec.getMiter(); } rect->outset(radius, radius); } @@ -173,9 +173,7 @@ public: // resulting segments = pathLen * intervalCount / intervalLen // resulting points = 4 * segments - SkScalar ptCount = SkScalarMulDiv(pathLength, - SkIntToScalar(intervalCount), - intervalLength); + SkScalar ptCount = pathLength * intervalCount / (float)intervalLength; ptCount = SkTMin(ptCount, SkDashPath::kMaxDashCount); int n = SkScalarCeilToInt(ptCount) << 2; dst->incReserve(n); @@ -192,10 +190,10 @@ public: d1 = fPathLength; } - SkScalar x0 = fPts[0].fX + SkScalarMul(fTangent.fX, d0); - SkScalar x1 = fPts[0].fX + SkScalarMul(fTangent.fX, d1); - SkScalar y0 = fPts[0].fY + SkScalarMul(fTangent.fY, d0); - SkScalar y1 = fPts[0].fY + SkScalarMul(fTangent.fY, d1); + SkScalar x0 = fPts[0].fX + fTangent.fX * d0; + SkScalar x1 = fPts[0].fX + fTangent.fX * d1; + SkScalar y0 = fPts[0].fY + fTangent.fY * d0; + SkScalar y1 = fPts[0].fY + fTangent.fY * d1; SkPoint pts[4]; pts[0].set(x0 + fNormal.fX, y0 + fNormal.fY); // moveTo diff --git a/gfx/skia/skia/src/utils/SkDeferredCanvas.cpp b/gfx/skia/skia/src/utils/SkDeferredCanvas.cpp index 75cd5dbd497a..975f496d3b0e 100644 --- a/gfx/skia/skia/src/utils/SkDeferredCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkDeferredCanvas.cpp @@ -8,9 +8,11 @@ #include "SkDeferredCanvas.h" #include "SkDrawable.h" #include "SkPath.h" +#include "SkRSXform.h" #include "SkRRect.h" #include "SkSurface.h" #include "SkTextBlob.h" +#include "SkClipOpPriv.h" bool SkDeferredCanvas::Rec::isConcat(SkMatrix* m) const { switch (fType) { @@ -31,7 +33,7 @@ bool SkDeferredCanvas::Rec::isConcat(SkMatrix* m) const { void SkDeferredCanvas::Rec::setConcat(const SkMatrix& m) { SkASSERT(m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)); - + if (m.getType() <= SkMatrix::kTranslate_Mask) { fType = kTrans_Type; fData.fTranslate.set(m.getTranslateX(), m.getTranslateY()); @@ -44,13 +46,28 @@ void SkDeferredCanvas::Rec::setConcat(const SkMatrix& m) { /////////////////////////////////////////////////////////////////////////////////////////////////// -SkDeferredCanvas::SkDeferredCanvas(SkCanvas* canvas) +SkDeferredCanvas::SkDeferredCanvas(SkCanvas* canvas, EvalType evalType) : INHERITED(canvas->getBaseLayerSize().width(), canvas->getBaseLayerSize().height()) - , fCanvas(canvas) -{} + , fCanvas(nullptr) // must be here for reset to work. + , fEvalType(evalType) +{ + this->reset(canvas); +} SkDeferredCanvas::~SkDeferredCanvas() {} +void SkDeferredCanvas::reset(SkCanvas* canvas) { + if (fCanvas) { + this->flush(); + fCanvas = nullptr; + } + fRecs.reset(); + if (canvas) { + this->resetForNextPicture(SkIRect::MakeSize(canvas->getBaseLayerSize())); + fCanvas = canvas; + } +} + void SkDeferredCanvas::push_save() { Rec* r = fRecs.append(); r->fType = kSave_Type; @@ -99,7 +116,7 @@ void SkDeferredCanvas::emit(const Rec& rec) { case kClipRect_Type: fCanvas->clipRect(rec.fData.fBounds); this->INHERITED::onClipRect(rec.fData.fBounds, - kIntersect_Op, kHard_ClipEdgeStyle); + kIntersect_SkClipOp, kHard_ClipEdgeStyle); break; case kTrans_Type: case kScaleTrans_Type: { @@ -272,8 +289,8 @@ void SkDeferredCanvas::didSetMatrix(const SkMatrix& matrix) { this->INHERITED::didSetMatrix(matrix); } -void SkDeferredCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) { - if (kIntersect_Op == op) { +void SkDeferredCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { + if (kIntersect_SkClipOp == op) { this->push_cliprect(rect); } else { this->flush_all(); @@ -282,19 +299,19 @@ void SkDeferredCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle e } } -void SkDeferredCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkDeferredCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { this->flush_all(); fCanvas->clipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle); this->INHERITED::onClipRRect(rrect, op, edgeStyle); } -void SkDeferredCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkDeferredCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { this->flush_all(); fCanvas->clipPath(path, op, kSoft_ClipEdgeStyle == edgeStyle); this->INHERITED::onClipPath(path, op, edgeStyle); } -void SkDeferredCanvas::onClipRegion(const SkRegion& deviceRgn, ClipOp op) { +void SkDeferredCanvas::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { this->flush_all(); fCanvas->clipRegion(deviceRgn, op); this->INHERITED::onClipRegion(deviceRgn, op); @@ -434,7 +451,7 @@ void SkDeferredCanvas::onDrawImageLattice(const SkImage* image, const Lattice& l } void SkDeferredCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, - const SkPaint& paint) { + const SkPaint& paint) { this->flush_translate(&x, &y, paint); fCanvas->drawText(text, byteLength, x, y, paint); } @@ -480,52 +497,50 @@ void SkDeferredCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScal #include "SkCanvasPriv.h" void SkDeferredCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { -#if 1 - SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); - picture->playback(this); -#else - this->flush_before_saves(); - fCanvas->drawPicture(picture, matrix, paint); -#endif + if (kEager == fEvalType) { + SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); + picture->playback(this); + } else { + this->flush_before_saves(); + fCanvas->drawPicture(picture, matrix, paint); + } } void SkDeferredCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { - // TODO: investigate culling and applying concat to the matrix -#if 1 - drawable->draw(this, matrix); -#else - this->flush_before_saves(); - fCanvas->drawDrawable(drawable, matrix); -#endif + if (kEager == fEvalType) { + // TODO: investigate culling and applying concat to the matrix + drawable->draw(this, matrix); + } else { + this->flush_before_saves(); + fCanvas->drawDrawable(drawable, matrix); + } } void SkDeferredCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[], const SkRect rects[], const SkColor colors[], - int count, SkXfermode::Mode mode, + int count, SkBlendMode bmode, const SkRect* cull, const SkPaint* paint) { this->flush_before_saves(); - fCanvas->drawAtlas(image, xform, rects, colors, count, mode, cull, paint); + fCanvas->drawAtlas(image, xform, rects, colors, count, bmode, cull, paint); } -void SkDeferredCanvas::onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { +void SkDeferredCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode, + const SkPaint& paint) { this->flush_before_saves(); - fCanvas->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode, - indices, indexCount, paint); + fCanvas->drawVertices(vertices, bmode, paint); } void SkDeferredCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, + const SkPoint texCoords[4], SkBlendMode bmode, const SkPaint& paint) { this->flush_before_saves(); - fCanvas->drawPatch(cubics, colors, texCoords, xmode, paint); + fCanvas->drawPatch(cubics, colors, texCoords, bmode, paint); } void SkDeferredCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* data) { - fCanvas->drawAnnotation(rect, key, data); + SkRect modRect = rect; + this->flush_check(&modRect, nullptr, kNoClip_Flag); + fCanvas->drawAnnotation(modRect, key, data); } #ifdef SK_SUPPORT_LEGACY_DRAWFILTER @@ -542,11 +557,11 @@ sk_sp SkDeferredCanvas::onNewSurface(const SkImageInfo& info, return fCanvas->makeSurface(info, &props); } SkISize SkDeferredCanvas::getBaseLayerSize() const { return fCanvas->getBaseLayerSize(); } -bool SkDeferredCanvas::getClipBounds(SkRect* bounds) const { - return fCanvas->getClipBounds(bounds); +SkRect SkDeferredCanvas::onGetLocalClipBounds() const { + return fCanvas->getLocalClipBounds(); } -bool SkDeferredCanvas::getClipDeviceBounds(SkIRect* bounds) const { - return fCanvas->getClipDeviceBounds(bounds); +SkIRect SkDeferredCanvas::onGetDeviceClipBounds() const { + return fCanvas->getDeviceClipBounds(); } bool SkDeferredCanvas::isClipEmpty() const { return fCanvas->isClipEmpty(); } bool SkDeferredCanvas::isClipRect() const { return fCanvas->isClipRect(); } diff --git a/gfx/skia/skia/src/utils/SkDeferredCanvas.h b/gfx/skia/skia/src/utils/SkDeferredCanvas.h index 312c22d26ead..eb07965799f2 100644 --- a/gfx/skia/skia/src/utils/SkDeferredCanvas.h +++ b/gfx/skia/skia/src/utils/SkDeferredCanvas.h @@ -1,4 +1,3 @@ - /* * Copyright 2016 Google Inc. * @@ -10,13 +9,23 @@ #define SkDeferredCanvas_DEFINED #include "../private/SkTDArray.h" -#include "SkCanvas.h" +#include "SkNoDrawCanvas.h" -class SK_API SkDeferredCanvas : public SkCanvas { +class SK_API SkDeferredCanvas : public SkNoDrawCanvas { public: - SkDeferredCanvas(SkCanvas*); + enum EvalType {kEager, kLazy}; + // There are two strategies for evaluating of sub-drawings (pictures and drawables). + // * kEager - a sub-drawing is expanded using the using the SkDeferredCanvas. This has + // the advantage of optimizing the sub drawing, and is used when the underlying + // SkCanvas is drawing and not recording. + // * kLazy - a sub-drawing is not expanded, but passed directly to the underlying SkCanvas. + // This has the advantage of not expanding the sub drawing and then immediately + // re-encoding it, and is used for recording canvases. + SkDeferredCanvas(SkCanvas*, EvalType); ~SkDeferredCanvas() override; + void reset(SkCanvas*); + #ifdef SK_SUPPORT_LEGACY_DRAWFILTER SkDrawFilter* setDrawFilter(SkDrawFilter*) override; #endif @@ -24,8 +33,8 @@ public: protected: sk_sp onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; SkISize getBaseLayerSize() const override; - bool getClipBounds(SkRect* bounds) const override; - bool getClipDeviceBounds(SkIRect* bounds) const override; + SkRect onGetLocalClipBounds() const override; + SkIRect onGetDeviceClipBounds() const override; bool isClipEmpty() const override; bool isClipRect() const override; bool onPeekPixels(SkPixmap*) override; @@ -33,7 +42,6 @@ protected: SkImageInfo onImageInfo() const override; bool onGetProps(SkSurfaceProps*) const override; void onFlush() override; -// SkCanvas* canvasForDrawIter() override; void willSave() override; SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; @@ -56,7 +64,7 @@ protected: virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) override; virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) override; void onDrawPaint(const SkPaint&) override; @@ -84,20 +92,15 @@ protected: void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint*, SrcRectConstraint) override; - void onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; void onDrawAtlas(const SkImage* image, const SkRSXform xform[], const SkRect rects[], const SkColor colors[], - int count, SkXfermode::Mode mode, - const SkRect* cull, const SkPaint* paint) override; + int count, SkBlendMode, const SkRect* cull, const SkPaint* paint) override; - void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; - void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, ClipOp) override; + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; void onDrawDrawable(SkDrawable*, const SkMatrix*) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; @@ -106,8 +109,6 @@ protected: class Iter; private: - SkCanvas* fCanvas; - enum Type { kSave_Type, kClipRect_Type, @@ -132,12 +133,11 @@ private: } void setConcat(const SkMatrix&); }; - SkTDArray fRecs; void push_save(); void push_cliprect(const SkRect&); bool push_concat(const SkMatrix&); - + void emit(const Rec& rec); void flush_all(); @@ -149,7 +149,11 @@ private: void internal_flush_translate(SkScalar* x, SkScalar* y, const SkRect* boundsOrNull); - typedef SkCanvas INHERITED; + SkTDArray fRecs; + SkCanvas* fCanvas; + const EvalType fEvalType; + + typedef SkNoDrawCanvas INHERITED; }; diff --git a/gfx/skia/skia/src/utils/SkDumpCanvas.cpp b/gfx/skia/skia/src/utils/SkDumpCanvas.cpp index eda23b7eb01c..35b88de59530 100644 --- a/gfx/skia/skia/src/utils/SkDumpCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkDumpCanvas.cpp @@ -10,6 +10,7 @@ #include "SkPatchUtils.h" #include "SkPicture.h" #include "SkPixelRef.h" +#include "SkRegion.h" #include "SkRRect.h" #include "SkString.h" #include "SkTextBlob.h" @@ -19,7 +20,6 @@ // needed just to know that these are all subclassed from SkFlattenable #include "SkShader.h" #include "SkPathEffect.h" -#include "SkXfermode.h" #include "SkColorFilter.h" #include "SkPathEffect.h" #include "SkMaskFilter.h" @@ -105,11 +105,11 @@ static void toString(const SkPath& path, SkString* str) { } } -static const char* toString(SkCanvas::ClipOp op) { +static const char* toString(SkClipOp op) { static const char* gOpNames[] = { "DIFF", "SECT", "UNION", "XOR", "RDIFF", "REPLACE" }; - return gOpNames[op]; + return gOpNames[static_cast(op)]; } static void toString(const SkRegion& rgn, SkString* str) { @@ -121,7 +121,7 @@ static void toString(const SkRegion& rgn, SkString* str) { } } -static const char* toString(SkCanvas::VertexMode vm) { +static const char* toString(SkVertices::VertexMode vm) { static const char* gVMNames[] = { "TRIANGLES", "STRIP", "FAN" }; @@ -258,7 +258,7 @@ const char* SkDumpCanvas::EdgeStyleToAAString(ClipEdgeStyle edgeStyle) { return kSoft_ClipEdgeStyle == edgeStyle ? "AA" : "BW"; } -void SkDumpCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkDumpCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { SkString str; toString(rect, &str); this->dump(kClip_Verb, nullptr, "clipRect(%s %s %s)", str.c_str(), toString(op), @@ -266,7 +266,7 @@ void SkDumpCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeS this->INHERITED::onClipRect(rect, op, edgeStyle); } -void SkDumpCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkDumpCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { SkString str; toString(rrect, &str); this->dump(kClip_Verb, nullptr, "clipRRect(%s %s %s)", str.c_str(), toString(op), @@ -274,7 +274,7 @@ void SkDumpCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle ed this->INHERITED::onClipRRect(rrect, op, edgeStyle); } -void SkDumpCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkDumpCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { SkString str; toString(path, &str); this->dump(kClip_Verb, nullptr, "clipPath(%s %s %s)", str.c_str(), toString(op), @@ -282,11 +282,10 @@ void SkDumpCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeS this->INHERITED::onClipPath(path, op, edgeStyle); } -void SkDumpCanvas::onClipRegion(const SkRegion& deviceRgn, ClipOp op) { +void SkDumpCanvas::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { SkString str; toString(deviceRgn, &str); - this->dump(kClip_Verb, nullptr, "clipRegion(%s %s)", str.c_str(), - toString(op)); + this->dump(kClip_Verb, nullptr, "clipRegion(%s %s)", str.c_str(), toString(op)); this->INHERITED::onClipRegion(deviceRgn, op); } @@ -466,31 +465,23 @@ void SkDumpCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matri picture->cullRect().fRight, picture->cullRect().fBottom); } -void SkDumpCanvas::onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { - this->dump(kDrawVertices_Verb, &paint, "drawVertices(%s [%d] %g %g ...)", - toString(vmode), vertexCount, SkScalarToFloat(vertices[0].fX), - SkScalarToFloat(vertices[0].fY)); +void SkDumpCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode, + const SkPaint& paint) { + this->dump(kDrawVertices_Verb, &paint, "drawVertices(%s [%d] ...)", + toString(vertices->mode()), vertices->vertexCount()); } void SkDumpCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) { //dumps corner points and colors in clockwise order starting on upper-left corner this->dump(kDrawPatch_Verb, &paint, "drawPatch(Vertices{[%f, %f], [%f, %f], [%f, %f], [%f, %f]}\ | Colors{[0x%x], [0x%x], [0x%x], [0x%x]} | TexCoords{[%f,%f], [%f,%f], [%f,%f], \ [%f,%f]})", - cubics[SkPatchUtils::kTopP0_CubicCtrlPts].fX, - cubics[SkPatchUtils::kTopP0_CubicCtrlPts].fY, - cubics[SkPatchUtils::kTopP3_CubicCtrlPts].fX, - cubics[SkPatchUtils::kTopP3_CubicCtrlPts].fY, - cubics[SkPatchUtils::kBottomP3_CubicCtrlPts].fX, - cubics[SkPatchUtils::kBottomP3_CubicCtrlPts].fY, - cubics[SkPatchUtils::kBottomP0_CubicCtrlPts].fX, - cubics[SkPatchUtils::kBottomP0_CubicCtrlPts].fY, + cubics[0].fX, cubics[0].fY, + cubics[3].fX, cubics[3].fY, + cubics[6].fX, cubics[6].fY, + cubics[9].fX, cubics[9].fY, colors[0], colors[1], colors[2], colors[3], texCoords[0].x(), texCoords[0].y(), texCoords[1].x(), texCoords[1].y(), texCoords[2].x(), texCoords[2].y(), texCoords[3].x(), texCoords[3].y()); @@ -541,7 +532,7 @@ void SkFormatDumper::dump(SkDumpCanvas* canvas, SkDumpCanvas::Verb verb, if (p) { msg.appendf(" color:0x%08X flags:%X", p->getColor(), p->getFlags()); if (!p->isSrcOver()) { - msg.appendf(" blendmode:%d", p->getBlendMode()); + msg.appendf(" blendmode:%d", (int)p->getBlendMode()); } appendFlattenable(&msg, p->getShader(), "shader"); appendFlattenable(&msg, p->getPathEffect(), "pathEffect"); diff --git a/gfx/skia/skia/src/utils/SkFrontBufferedStream.cpp b/gfx/skia/skia/src/utils/SkFrontBufferedStream.cpp index 2dfb8ab88265..42b86f09e33e 100644 --- a/gfx/skia/skia/src/utils/SkFrontBufferedStream.cpp +++ b/gfx/skia/skia/src/utils/SkFrontBufferedStream.cpp @@ -29,19 +29,19 @@ public: SkStreamRewindable* duplicate() const override { return nullptr; } private: - SkAutoTDelete fStream; - const bool fHasLength; - const size_t fLength; + std::unique_ptr fStream; + const bool fHasLength; + const size_t fLength; // Current offset into the stream. Always >= 0. - size_t fOffset; + size_t fOffset; // Amount that has been buffered by calls to read. Will always be less than // fBufferSize. - size_t fBufferedSoFar; + size_t fBufferedSoFar; // Total size of the buffer. - const size_t fBufferSize; + const size_t fBufferSize; // FIXME: SkAutoTMalloc throws on failure. Instead, Create should return a // nullptr stream. - SkAutoTMalloc fBuffer; + SkAutoTMalloc fBuffer; // Read up to size bytes from already buffered data, and copy to // dst, if non-nullptr. Updates fOffset. Assumes that fOffset is less diff --git a/gfx/skia/skia/src/utils/SkInsetConvexPolygon.cpp b/gfx/skia/skia/src/utils/SkInsetConvexPolygon.cpp new file mode 100755 index 000000000000..bb4694264dba --- /dev/null +++ b/gfx/skia/skia/src/utils/SkInsetConvexPolygon.cpp @@ -0,0 +1,290 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkInsetConvexPolygon.h" + +#include "SkTemplates.h" + +struct InsetSegment { + SkPoint fP0; + SkPoint fP1; +}; + +// Computes perpDot for point compared to segment. +// A positive value means the point is to the left of the segment, +// negative is to the right, 0 is collinear. +static int compute_side(const SkPoint& s0, const SkPoint& s1, const SkPoint& p) { + SkVector v0 = s1 - s0; + SkVector v1 = p - s0; + SkScalar perpDot = v0.cross(v1); + if (!SkScalarNearlyZero(perpDot)) { + return ((perpDot > 0) ? 1 : -1); + } + + return 0; +} + +// returns 1 for ccw, -1 for cw and 0 if degenerate +static int get_winding(const SkPoint* polygonVerts, int polygonSize) { + SkPoint p0 = polygonVerts[0]; + SkPoint p1 = polygonVerts[1]; + + for (int i = 2; i < polygonSize; ++i) { + SkPoint p2 = polygonVerts[i]; + + // determine if cw or ccw + int side = compute_side(p0, p1, p2); + if (0 != side) { + return ((side > 0) ? 1 : -1); + } + + // if nearly collinear, treat as straight line and continue + p1 = p2; + } + + return 0; +} + +// Offset line segment p0-p1 'd0' and 'd1' units in the direction specified by 'side' +bool SkOffsetSegment(const SkPoint& p0, const SkPoint& p1, SkScalar d0, SkScalar d1, + int side, SkPoint* offset0, SkPoint* offset1) { + SkASSERT(side == -1 || side == 1); + SkVector perp = SkVector::Make(p0.fY - p1.fY, p1.fX - p0.fX); + if (SkScalarNearlyEqual(d0, d1)) { + // if distances are equal, can just outset by the perpendicular + perp.setLength(d0*side); + *offset0 = p0 + perp; + *offset1 = p1 + perp; + } else { + // Otherwise we need to compute the outer tangent. + // See: http://www.ambrsoft.com/TrigoCalc/Circles2/Circles2Tangent_.htm + if (d0 < d1) { + side = -side; + } + SkScalar dD = d0 - d1; + // if one circle is inside another, we can't compute an offset + if (dD*dD >= p0.distanceToSqd(p1)) { + return false; + } + SkPoint outerTangentIntersect = SkPoint::Make((p1.fX*d0 - p0.fX*d1) / dD, + (p1.fY*d0 - p0.fY*d1) / dD); + + SkScalar d0sq = d0*d0; + SkVector dP = outerTangentIntersect - p0; + SkScalar dPlenSq = dP.lengthSqd(); + SkScalar discrim = SkScalarSqrt(dPlenSq - d0sq); + offset0->fX = p0.fX + (d0sq*dP.fX - side*d0*dP.fY*discrim) / dPlenSq; + offset0->fY = p0.fY + (d0sq*dP.fY + side*d0*dP.fX*discrim) / dPlenSq; + + SkScalar d1sq = d1*d1; + dP = outerTangentIntersect - p1; + dPlenSq = dP.lengthSqd(); + discrim = SkScalarSqrt(dPlenSq - d1sq); + offset1->fX = p1.fX + (d1sq*dP.fX - side*d1*dP.fY*discrim) / dPlenSq; + offset1->fY = p1.fY + (d1sq*dP.fY + side*d1*dP.fX*discrim) / dPlenSq; + } + + return true; +} + +// Compute the intersection 'p' between segments s0 and s1, if any. +// 's' is the parametric value for the intersection along 's0' & 't' is the same for 's1'. +// Returns false if there is no intersection. +static bool compute_intersection(const InsetSegment& s0, const InsetSegment& s1, + SkPoint* p, SkScalar* s, SkScalar* t) { + SkVector v0 = s0.fP1 - s0.fP0; + SkVector v1 = s1.fP1 - s1.fP0; + + SkScalar perpDot = v0.cross(v1); + if (SkScalarNearlyZero(perpDot)) { + // segments are parallel + // check if endpoints are touching + if (s0.fP1.equalsWithinTolerance(s1.fP0)) { + *p = s0.fP1; + *s = SK_Scalar1; + *t = 0; + return true; + } + if (s1.fP1.equalsWithinTolerance(s0.fP0)) { + *p = s1.fP1; + *s = 0; + *t = SK_Scalar1; + return true; + } + + return false; + } + + SkVector d = s1.fP0 - s0.fP0; + SkScalar localS = d.cross(v1) / perpDot; + if (localS < 0 || localS > SK_Scalar1) { + return false; + } + SkScalar localT = d.cross(v0) / perpDot; + if (localT < 0 || localT > SK_Scalar1) { + return false; + } + + v0 *= localS; + *p = s0.fP0 + v0; + *s = localS; + *t = localT; + + return true; +} + +#ifdef SK_DEBUG +static bool is_convex(const SkTDArray& poly) { + if (poly.count() <= 3) { + return true; + } + + SkVector v0 = poly[0] - poly[poly.count() - 1]; + SkVector v1 = poly[1] - poly[poly.count() - 1]; + SkScalar winding = v0.cross(v1); + + for (int i = 0; i < poly.count() - 1; ++i) { + int j = i + 1; + int k = (i + 2) % poly.count(); + + SkVector v0 = poly[j] - poly[i]; + SkVector v1 = poly[k] - poly[i]; + SkScalar perpDot = v0.cross(v1); + if (winding*perpDot < 0) { + return false; + } + } + + return true; +} +#endif + +// The objective here is to inset all of the edges by the given distance, and then +// remove any invalid inset edges by detecting right-hand turns. In a ccw polygon, +// we should only be making left-hand turns (for cw polygons, we use the winding +// parameter to reverse this). We detect this by checking whether the second intersection +// on an edge is closer to its tail than the first one. +// +// We might also have the case that there is no intersection between two neighboring inset edges. +// In this case, one edge will lie to the right of the other and should be discarded along with +// its previous intersection (if any). +// +// Note: the assumption is that inputPolygon is convex and has no coincident points. +// +bool SkInsetConvexPolygon(const SkPoint* inputPolygonVerts, int inputPolygonSize, + std::function insetDistanceFunc, + SkTDArray* insetPolygon) { + if (inputPolygonSize < 3) { + return false; + } + + int winding = get_winding(inputPolygonVerts, inputPolygonSize); + if (0 == winding) { + return false; + } + + // set up + struct EdgeData { + InsetSegment fInset; + SkPoint fIntersection; + SkScalar fTValue; + bool fValid; + }; + + SkAutoSTMalloc<64, EdgeData> edgeData(inputPolygonSize); + for (int i = 0; i < inputPolygonSize; ++i) { + int j = (i + 1) % inputPolygonSize; + SkOffsetSegment(inputPolygonVerts[i], inputPolygonVerts[j], + insetDistanceFunc(i), insetDistanceFunc(j), + winding, + &edgeData[i].fInset.fP0, &edgeData[i].fInset.fP1); + edgeData[i].fIntersection = edgeData[i].fInset.fP0; + edgeData[i].fTValue = SK_ScalarMin; + edgeData[i].fValid = true; + } + + int prevIndex = inputPolygonSize - 1; + int currIndex = 0; + int insetVertexCount = inputPolygonSize; + while (prevIndex != currIndex) { + if (!edgeData[prevIndex].fValid) { + prevIndex = (prevIndex + inputPolygonSize - 1) % inputPolygonSize; + continue; + } + + SkScalar s, t; + SkPoint intersection; + if (compute_intersection(edgeData[prevIndex].fInset, edgeData[currIndex].fInset, + &intersection, &s, &t)) { + // if new intersection is further back on previous inset from the prior intersection + if (s < edgeData[prevIndex].fTValue) { + // no point in considering this one again + edgeData[prevIndex].fValid = false; + --insetVertexCount; + // go back one segment + prevIndex = (prevIndex + inputPolygonSize - 1) % inputPolygonSize; + // we've already considered this intersection, we're done + } else if (edgeData[currIndex].fTValue > SK_ScalarMin && + intersection.equalsWithinTolerance(edgeData[currIndex].fIntersection, + 1.0e-6f)) { + break; + } else { + // add intersection + edgeData[currIndex].fIntersection = intersection; + edgeData[currIndex].fTValue = t; + + // go to next segment + prevIndex = currIndex; + currIndex = (currIndex + 1) % inputPolygonSize; + } + } else { + // if prev to right side of curr + int side = winding*compute_side(edgeData[currIndex].fInset.fP0, + edgeData[currIndex].fInset.fP1, + edgeData[prevIndex].fInset.fP1); + if (side < 0 && side == winding*compute_side(edgeData[currIndex].fInset.fP0, + edgeData[currIndex].fInset.fP1, + edgeData[prevIndex].fInset.fP0)) { + // no point in considering this one again + edgeData[prevIndex].fValid = false; + --insetVertexCount; + // go back one segment + prevIndex = (prevIndex + inputPolygonSize - 1) % inputPolygonSize; + } else { + // move to next segment + edgeData[currIndex].fValid = false; + --insetVertexCount; + currIndex = (currIndex + 1) % inputPolygonSize; + } + } + } + + // store all the valid intersections that aren't nearly coincident + // TODO: look at the main algorithm and see if we can detect these better + static constexpr SkScalar kCleanupTolerance = 0.01f; + + insetPolygon->reset(); + insetPolygon->setReserve(insetVertexCount); + currIndex = -1; + for (int i = 0; i < inputPolygonSize; ++i) { + if (edgeData[i].fValid && (currIndex == -1 || + !edgeData[i].fIntersection.equalsWithinTolerance((*insetPolygon)[currIndex], + kCleanupTolerance))) { + *insetPolygon->push() = edgeData[i].fIntersection; + currIndex++; + } + } + // make sure the first and last points aren't coincident + if (currIndex >= 1 && + (*insetPolygon)[0].equalsWithinTolerance((*insetPolygon)[currIndex], + kCleanupTolerance)) { + insetPolygon->pop(); + } + SkASSERT(is_convex(*insetPolygon)); + + return (insetPolygon->count() >= 3); +} diff --git a/gfx/skia/skia/src/utils/SkInsetConvexPolygon.h b/gfx/skia/skia/src/utils/SkInsetConvexPolygon.h new file mode 100755 index 000000000000..1d5a19c176f0 --- /dev/null +++ b/gfx/skia/skia/src/utils/SkInsetConvexPolygon.h @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkInsetConvexPolygon_DEFINED +#define SkInsetConvexPolygon_DEFINED + +#include + +#include "SkTDArray.h" +#include "SkPoint.h" + +/** + * Generates a polygon that is inset a given distance from the boundary of a given convex polygon. + * + * @param inputPolygonVerts Array of points representing the vertices of the original polygon. + * It should be convex and have no coincident points. + * @param inputPolygonSize Number of vertices in the original polygon. + * @param insetDistanceFunc How far we wish to inset the polygon for a given index in the array. + * This should return a positive value. + * @param insetPolygon The resulting inset polygon, if any. + * @return true if an inset polygon exists, false otherwise. + */ +bool SkInsetConvexPolygon(const SkPoint* inputPolygonVerts, int inputPolygonSize, + std::function insetDistanceFunc, + SkTDArray* insetPolygon); + +inline bool SkInsetConvexPolygon(const SkPoint* inputPolygonVerts, int inputPolygonSize, + SkScalar inset, + SkTDArray* insetPolygon) { + return SkInsetConvexPolygon(inputPolygonVerts, inputPolygonSize, + [inset](int) { return inset; }, + insetPolygon); +} + +/** + * Offset a segment by the given distance at each point. + * Uses the outer tangents of two circles centered on each endpoint. + * See: https://en.wikipedia.org/wiki/Tangent_lines_to_circles + * + * @param p0 First endpoint. + * @param p1 Second endpoint. + * @param d0 Offset distance from first endpoint. + * @param d1 Offset distance from second endpoint. + * @param side Indicates whether we want to offset to the left (1) or right (-1) side of segment. + * @param offset0 First endpoint of offset segment. + * @param offset1 Second endpoint of offset segment. + * @return true if an offset segment exists, false otherwise. + */ +bool SkOffsetSegment(const SkPoint& p0, const SkPoint& p1, SkScalar d0, SkScalar d1, + int side, SkPoint* offset0, SkPoint* offset1); + +#endif diff --git a/gfx/skia/skia/src/utils/SkInterpolator.cpp b/gfx/skia/skia/src/utils/SkInterpolator.cpp index d3c0b26fef1f..d64316d84552 100644 --- a/gfx/skia/skia/src/utils/SkInterpolator.cpp +++ b/gfx/skia/skia/src/utils/SkInterpolator.cpp @@ -5,10 +5,11 @@ * found in the LICENSE file. */ +#include "SkInterpolator.h" #include "SkFixed.h" -#include "SkInterpolator.h" #include "SkMath.h" +#include "SkMalloc.h" #include "SkTSearch.h" SkInterpolatorBase::SkInterpolatorBase() { diff --git a/gfx/skia/skia/src/utils/SkLayer.cpp b/gfx/skia/skia/src/utils/SkLayer.cpp deleted file mode 100644 index d0de1ba6b15f..000000000000 --- a/gfx/skia/skia/src/utils/SkLayer.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkLayer.h" -#include "SkCanvas.h" - -//#define DEBUG_DRAW_LAYER_BOUNDS -//#define DEBUG_TRACK_NEW_DELETE - -#ifdef DEBUG_TRACK_NEW_DELETE - static int gLayerAllocCount; -#endif - -/////////////////////////////////////////////////////////////////////////////// - -SkLayer::SkLayer() { - fParent = nullptr; - m_opacity = SK_Scalar1; - m_size.set(0, 0); - m_position.set(0, 0); - m_anchorPoint.set(SK_ScalarHalf, SK_ScalarHalf); - - fMatrix.reset(); - fChildrenMatrix.reset(); - fFlags = 0; - -#ifdef DEBUG_TRACK_NEW_DELETE - gLayerAllocCount += 1; - SkDebugf("SkLayer new: %d\n", gLayerAllocCount); -#endif -} - -SkLayer::SkLayer(const SkLayer& src) : INHERITED() { - fParent = nullptr; - m_opacity = src.m_opacity; - m_size = src.m_size; - m_position = src.m_position; - m_anchorPoint = src.m_anchorPoint; - - fMatrix = src.fMatrix; - fChildrenMatrix = src.fChildrenMatrix; - fFlags = src.fFlags; - -#ifdef DEBUG_TRACK_NEW_DELETE - gLayerAllocCount += 1; - SkDebugf("SkLayer copy: %d\n", gLayerAllocCount); -#endif -} - -SkLayer::~SkLayer() { - this->removeChildren(); - -#ifdef DEBUG_TRACK_NEW_DELETE - gLayerAllocCount -= 1; - SkDebugf("SkLayer delete: %d\n", gLayerAllocCount); -#endif -} - -/////////////////////////////////////////////////////////////////////////////// - -bool SkLayer::isInheritFromRootTransform() const { - return (fFlags & kInheritFromRootTransform_Flag) != 0; -} - -void SkLayer::setInheritFromRootTransform(bool doInherit) { - if (doInherit) { - fFlags |= kInheritFromRootTransform_Flag; - } else { - fFlags &= ~kInheritFromRootTransform_Flag; - } -} - -void SkLayer::setMatrix(const SkMatrix& matrix) { - fMatrix = matrix; -} - -void SkLayer::setChildrenMatrix(const SkMatrix& matrix) { - fChildrenMatrix = matrix; -} - -/////////////////////////////////////////////////////////////////////////////// - -int SkLayer::countChildren() const { - return m_children.count(); -} - -SkLayer* SkLayer::getChild(int index) const { - if ((unsigned)index < (unsigned)m_children.count()) { - SkASSERT(m_children[index]->fParent == this); - return m_children[index]; - } - return nullptr; -} - -SkLayer* SkLayer::addChild(SkLayer* child) { - SkASSERT(this != child); - child->ref(); - child->detachFromParent(); - SkASSERT(child->fParent == nullptr); - child->fParent = this; - - *m_children.append() = child; - return child; -} - -void SkLayer::detachFromParent() { - if (fParent) { - int index = fParent->m_children.find(this); - SkASSERT(index >= 0); - fParent->m_children.remove(index); - fParent = nullptr; - this->unref(); // this call might delete us - } -} - -void SkLayer::removeChildren() { - int count = m_children.count(); - for (int i = 0; i < count; i++) { - SkLayer* child = m_children[i]; - SkASSERT(child->fParent == this); - child->fParent = nullptr; // in case it has more than one owner - child->unref(); - } - m_children.reset(); -} - -SkLayer* SkLayer::getRootLayer() const { - const SkLayer* root = this; - while (root->fParent != nullptr) { - root = root->fParent; - } - return const_cast(root); -} - -/////////////////////////////////////////////////////////////////////////////// - -void SkLayer::getLocalTransform(SkMatrix* matrix) const { - matrix->setTranslate(m_position.fX, m_position.fY); - - SkScalar tx = SkScalarMul(m_anchorPoint.fX, m_size.width()); - SkScalar ty = SkScalarMul(m_anchorPoint.fY, m_size.height()); - matrix->preTranslate(tx, ty); - matrix->preConcat(this->getMatrix()); - matrix->preTranslate(-tx, -ty); -} - -void SkLayer::localToGlobal(SkMatrix* matrix) const { - this->getLocalTransform(matrix); - - if (this->isInheritFromRootTransform()) { - matrix->postConcat(this->getRootLayer()->getMatrix()); - return; - } - - const SkLayer* layer = this; - while (layer->fParent != nullptr) { - layer = layer->fParent; - - SkMatrix tmp; - layer->getLocalTransform(&tmp); - tmp.preConcat(layer->getChildrenMatrix()); - matrix->postConcat(tmp); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -void SkLayer::onDraw(SkCanvas*, SkScalar opacity) { -// SkDebugf("----- no onDraw for %p\n", this); -} - -#include "SkString.h" - -void SkLayer::draw(SkCanvas* canvas, SkScalar opacity) { -#if 0 - SkString str1, str2; - // this->getMatrix().toDumpString(&str1); - // this->getChildrenMatrix().toDumpString(&str2); - SkDebugf("--- drawlayer %p opacity %g size [%g %g] pos [%g %g] matrix %s children %s\n", - this, opacity * this->getOpacity(), m_size.width(), m_size.height(), - m_position.fX, m_position.fY, str1.c_str(), str2.c_str()); -#endif - - opacity = SkScalarMul(opacity, this->getOpacity()); - if (opacity <= 0) { -// SkDebugf("---- abort drawing %p opacity %g\n", this, opacity); - return; - } - - SkAutoCanvasRestore acr(canvas, true); - - // apply our local transform - { - SkMatrix tmp; - this->getLocalTransform(&tmp); - if (this->isInheritFromRootTransform()) { - // should we also apply the root's childrenMatrix? - canvas->setMatrix(getRootLayer()->getMatrix()); - } - canvas->concat(tmp); - } - - this->onDraw(canvas, opacity); - -#ifdef DEBUG_DRAW_LAYER_BOUNDS - { - SkRect r = SkRect::MakeSize(this->getSize()); - SkPaint p; - p.setAntiAlias(true); - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(SkIntToScalar(2)); - p.setColor(0xFFFF44DD); - canvas->drawRect(r, p); - canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, p); - canvas->drawLine(r.fLeft, r.fBottom, r.fRight, r.fTop, p); - } -#endif - - int count = this->countChildren(); - if (count > 0) { - canvas->concat(this->getChildrenMatrix()); - for (int i = 0; i < count; i++) { - this->getChild(i)->draw(canvas, opacity); - } - } -} diff --git a/gfx/skia/skia/src/utils/SkLua.cpp b/gfx/skia/skia/src/utils/SkLua.cpp index 9eb6f0b273f4..fa474b3b1398 100644 --- a/gfx/skia/skia/src/utils/SkLua.cpp +++ b/gfx/skia/skia/src/utils/SkLua.cpp @@ -8,8 +8,7 @@ #include "SkLua.h" #if SK_SUPPORT_GPU -#include "GrClip.h" -#include "GrReducedClip.h" +//#include "GrReducedClip.h" #endif #include "SkBlurImageFilter.h" @@ -74,6 +73,13 @@ template void push_obj(lua_State* L, const T& obj) { lua_setmetatable(L, -2); } +template T* push_ptr(lua_State* L, T* ptr) { + *(T**)lua_newuserdata(L, sizeof(T*)) = ptr; + luaL_getmetatable(L, get_mtname()); + lua_setmetatable(L, -2); + return ptr; +} + template T* push_ref(lua_State* L, T* ref) { *(T**)lua_newuserdata(L, sizeof(T*)) = SkSafeRef(ref); luaL_getmetatable(L, get_mtname()); @@ -334,7 +340,7 @@ void SkLua::pushPath(const SkPath& path, const char key[]) { } void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) { - push_ref(fL, canvas); + push_ptr(fL, canvas); CHECK_SETFIELD(key); } @@ -343,73 +349,6 @@ void SkLua::pushTextBlob(const SkTextBlob* blob, const char key[]) { CHECK_SETFIELD(key); } -static const char* element_type(SkClipStack::Element::Type type) { - switch (type) { - case SkClipStack::Element::kEmpty_Type: - return "empty"; - case SkClipStack::Element::kRect_Type: - return "rect"; - case SkClipStack::Element::kRRect_Type: - return "rrect"; - case SkClipStack::Element::kPath_Type: - return "path"; - } - return "unknown"; -} - -static const char* region_op(SkRegion::Op op) { - switch (op) { - case SkRegion::kDifference_Op: - return "difference"; - case SkRegion::kIntersect_Op: - return "intersect"; - case SkRegion::kUnion_Op: - return "union"; - case SkRegion::kXOR_Op: - return "xor"; - case SkRegion::kReverseDifference_Op: - return "reverse-difference"; - case SkRegion::kReplace_Op: - return "replace"; - } - return "unknown"; -} - -void SkLua::pushClipStack(const SkClipStack& stack, const char* key) { - lua_newtable(fL); - SkClipStack::B2TIter iter(stack); - const SkClipStack::Element* element; - int i = 0; - while ((element = iter.next())) { - this->pushClipStackElement(*element); - lua_rawseti(fL, -2, ++i); - } - CHECK_SETFIELD(key); -} - -void SkLua::pushClipStackElement(const SkClipStack::Element& element, const char* key) { - lua_newtable(fL); - SkClipStack::Element::Type type = element.getType(); - this->pushString(element_type(type), "type"); - switch (type) { - case SkClipStack::Element::kEmpty_Type: - break; - case SkClipStack::Element::kRect_Type: - this->pushRect(element.getRect(), "rect"); - break; - case SkClipStack::Element::kRRect_Type: - this->pushRRect(element.getRRect(), "rrect"); - break; - case SkClipStack::Element::kPath_Type: - this->pushPath(element.getPath(), "path"); - break; - } - this->pushString(region_op((SkRegion::Op)element.getOp()), "op"); - this->pushBool(element.isAA(), "aa"); - CHECK_SETFIELD(key); -} - - /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -574,7 +513,7 @@ static int lcanvas_drawPatch(lua_State* L) { texs = texStorage; } - get_ref(L, 1)->drawPatch(cubics, colors, texs, nullptr, *get_obj(L, 5)); + get_ref(L, 1)->drawPatch(cubics, colors, texs, *get_obj(L, 5)); return 0; } @@ -634,35 +573,6 @@ static int lcanvas_getTotalMatrix(lua_State* L) { return 1; } -static int lcanvas_getClipStack(lua_State* L) { - SkLua(L).pushClipStack(*get_ref(L, 1)->getClipStack()); - return 1; -} - -int SkLua::lcanvas_getReducedClipStack(lua_State* L) { -#if SK_SUPPORT_GPU - const SkCanvas* canvas = get_ref(L, 1); - SkRect queryBounds = SkRect::Make(canvas->getTopLayerBounds()); - SkASSERT(!GrClip::GetPixelIBounds(queryBounds).isEmpty()); - - const GrReducedClip reducedClip(*canvas->getClipStack(), queryBounds); - - GrReducedClip::ElementList::Iter iter(reducedClip.elements()); - int i = 0; - lua_newtable(L); - while(iter.get()) { - SkLua(L).pushClipStackElement(*iter.get()); - iter.next(); - lua_rawseti(L, -2, ++i); - } - // Currently this only returns the element list to lua, not the initial state or result bounds. - // It could return these as additional items on the lua stack. - return 1; -#else - return 0; -#endif -} - static int lcanvas_save(lua_State* L) { lua_pushinteger(L, get_ref(L, 1)->save()); return 1; @@ -718,7 +628,7 @@ static int lcanvas_newSurface(lua_State* L) { } static int lcanvas_gc(lua_State* L) { - get_ref(L, 1)->unref(); + // don't know how to track a ptr... return 0; } @@ -738,10 +648,6 @@ const struct luaL_Reg gSkCanvas_Methods[] = { { "drawTextBlob", lcanvas_drawTextBlob }, { "getSaveCount", lcanvas_getSaveCount }, { "getTotalMatrix", lcanvas_getTotalMatrix }, - { "getClipStack", lcanvas_getClipStack }, -#if SK_SUPPORT_GPU - { "getReducedClipStack", SkLua::lcanvas_getReducedClipStack }, -#endif { "save", lcanvas_save }, { "saveLayer", lcanvas_saveLayer }, { "restore", lcanvas_restore }, @@ -760,7 +666,7 @@ const struct luaL_Reg gSkCanvas_Methods[] = { static int ldocument_beginPage(lua_State* L) { const SkRect* contentPtr = nullptr; - push_ref(L, get_ref(L, 1)->beginPage(lua2scalar(L, 2), + push_ptr(L, get_ref(L, 1)->beginPage(lua2scalar(L, 2), lua2scalar(L, 3), contentPtr)); return 1; @@ -811,16 +717,6 @@ static int lpaint_setDither(lua_State* L) { return 0; } -static int lpaint_isUnderlineText(lua_State* L) { - lua_pushboolean(L, get_obj(L, 1)->isUnderlineText()); - return 1; -} - -static int lpaint_isStrikeThruText(lua_State* L) { - lua_pushboolean(L, get_obj(L, 1)->isStrikeThruText()); - return 1; -} - static int lpaint_isFakeBoldText(lua_State* L) { lua_pushboolean(L, get_obj(L, 1)->isFakeBoldText()); return 1; @@ -1105,7 +1001,7 @@ static int lpaint_getImageFilter(lua_State* L) { static int lpaint_setImageFilter(lua_State* L) { SkPaint* paint = get_obj(L, 1); - paint->setImageFilter(get_ref(L, 2)); + paint->setImageFilter(sk_ref_sp(get_ref(L, 2))); return 0; } @@ -1160,8 +1056,6 @@ static const struct luaL_Reg gSkPaint_Methods[] = { { "setDither", lpaint_setDither }, { "getFilterQuality", lpaint_getFilterQuality }, { "setFilterQuality", lpaint_setFilterQuality }, - { "isUnderlineText", lpaint_isUnderlineText }, - { "isStrikeThruText", lpaint_isStrikeThruText }, { "isFakeBoldText", lpaint_isFakeBoldText }, { "isLinearText", lpaint_isLinearText }, { "isSubpixelText", lpaint_isSubpixelText }, @@ -1753,7 +1647,7 @@ static int lsurface_getCanvas(lua_State* L) { if (nullptr == canvas) { lua_pushnil(L); } else { - push_ref(L, canvas); + push_ptr(L, canvas); // note: we don't unref canvas, since getCanvas did not ref it. // warning: this is weird: now Lua owns a ref on this canvas, but what if they let // the real owner (the surface) go away, but still hold onto the canvas? @@ -1817,7 +1711,7 @@ static int lpicturerecorder_beginRecording(lua_State* L) { return 1; } - push_ref(L, canvas); + push_ptr(L, canvas); return 1; } @@ -1827,7 +1721,7 @@ static int lpicturerecorder_getCanvas(lua_State* L) { lua_pushnil(L); return 1; } - push_ref(L, canvas); + push_ptr(L, canvas); return 1; } diff --git a/gfx/skia/skia/src/utils/SkLuaCanvas.cpp b/gfx/skia/skia/src/utils/SkLuaCanvas.cpp index 6b769f0ba761..ddf5187baf17 100644 --- a/gfx/skia/skia/src/utils/SkLuaCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkLuaCanvas.cpp @@ -135,28 +135,28 @@ void SkLuaCanvas::didSetMatrix(const SkMatrix& matrix) { this->INHERITED::didSetMatrix(matrix); } -void SkLuaCanvas::onClipRect(const SkRect& r, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkLuaCanvas::onClipRect(const SkRect& r, SkClipOp op, ClipEdgeStyle edgeStyle) { AUTO_LUA("clipRect"); lua.pushRect(r, "rect"); lua.pushBool(kSoft_ClipEdgeStyle == edgeStyle, "aa"); this->INHERITED::onClipRect(r, op, edgeStyle); } -void SkLuaCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkLuaCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { AUTO_LUA("clipRRect"); lua.pushRRect(rrect, "rrect"); lua.pushBool(kSoft_ClipEdgeStyle == edgeStyle, "aa"); this->INHERITED::onClipRRect(rrect, op, edgeStyle); } -void SkLuaCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkLuaCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { AUTO_LUA("clipPath"); lua.pushPath(path, "path"); lua.pushBool(kSoft_ClipEdgeStyle == edgeStyle, "aa"); this->INHERITED::onClipPath(path, op, edgeStyle); } -void SkLuaCanvas::onClipRegion(const SkRegion& deviceRgn, ClipOp op) { +void SkLuaCanvas::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { AUTO_LUA("clipRegion"); this->INHERITED::onClipRegion(deviceRgn, op); } @@ -307,11 +307,7 @@ void SkLuaCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix this->INHERITED::onDrawPicture(picture, matrix, paint); } -void SkLuaCanvas::onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { +void SkLuaCanvas::onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint& paint) { AUTO_LUA("drawVertices"); lua.pushPaint(paint, "paint"); } diff --git a/gfx/skia/skia/src/utils/SkMeshUtils.cpp b/gfx/skia/skia/src/utils/SkMeshUtils.cpp deleted file mode 100644 index 27eccc250d40..000000000000 --- a/gfx/skia/skia/src/utils/SkMeshUtils.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkMeshUtils.h" -#include "SkCanvas.h" -#include "SkPaint.h" - -SkMeshIndices::SkMeshIndices() { - sk_bzero(this, sizeof(*this)); -} - -SkMeshIndices::~SkMeshIndices() { - sk_free(fStorage); -} - -bool SkMeshIndices::init(SkPoint tex[], uint16_t indices[], - int texW, int texH, int rows, int cols) { - if (rows < 2 || cols < 2) { - sk_free(fStorage); - fStorage = nullptr; - fTex = nullptr; - fIndices = nullptr; - fTexCount = fIndexCount = 0; - return false; - } - - sk_free(fStorage); - fStorage = nullptr; - - fTexCount = rows * cols; - rows -= 1; - cols -= 1; - fIndexCount = rows * cols * 6; - - if (tex) { - fTex = tex; - fIndices = indices; - } else { - fStorage = sk_malloc_throw(fTexCount * sizeof(SkPoint) + - fIndexCount * sizeof(uint16_t)); - fTex = (SkPoint*)fStorage; - fIndices = (uint16_t*)(fTex + fTexCount); - } - - // compute the indices - { - uint16_t* idx = fIndices; - int index = 0; - for (int y = 0; y < cols; y++) { - for (int x = 0; x < rows; x++) { - *idx++ = index; - *idx++ = index + rows + 1; - *idx++ = index + 1; - - *idx++ = index + 1; - *idx++ = index + rows + 1; - *idx++ = index + rows + 2; - - index += 1; - } - index += 1; - } - } - - // compute texture coordinates - { - SkPoint* tex = fTex; - const SkScalar dx = SkIntToScalar(texW) / rows; - const SkScalar dy = SkIntToScalar(texH) / cols; - for (int y = 0; y <= cols; y++) { - for (int x = 0; x <= rows; x++) { - tex->set(x*dx, y*dy); - tex += 1; - } - } - } - return true; -} - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkShader.h" - -void SkMeshUtils::Draw(SkCanvas* canvas, const SkBitmap& bitmap, - int rows, int cols, const SkPoint verts[], - const SkColor colors[], const SkPaint& paint) { - SkMeshIndices idx; - - if (idx.init(bitmap.width(), bitmap.height(), rows, cols)) { - SkPaint p(paint); - p.setShader(SkShader::MakeBitmapShader(bitmap, - SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode)); - canvas->drawVertices(SkCanvas::kTriangles_VertexMode, - rows * cols, verts, idx.tex(), colors, nullptr, - idx.indices(), idx.indexCount(), p); - } -} diff --git a/gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp b/gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp index 217e7a3007a6..9868ca26920f 100644 --- a/gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp +++ b/gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp @@ -7,11 +7,14 @@ #include "SkMultiPictureDocument.h" #include "SkMultiPictureDocumentPriv.h" +#include "SkNWayCanvas.h" #include "SkPicture.h" #include "SkPictureRecorder.h" #include "SkStream.h" #include "SkTArray.h" +#include + /* File format: BEGINNING_OF_FILE: @@ -26,6 +29,21 @@ */ namespace { +// The unique file signature for this file type. +static constexpr char kMagic[] = "Skia Multi-Picture Doc\n\n"; + +static constexpr char kEndPage[] = "SkMultiPictureEndPage"; + +const uint32_t kVersion = 2; + +static SkSize join(const SkTArray& sizes) { + SkSize joined = {0, 0}; + for (SkSize s : sizes) { + joined = SkSize{SkTMax(joined.width(), s.width()), SkTMax(joined.height(), s.height())}; + } + return joined; +} + static SkCanvas* trim(SkCanvas* canvas, SkScalar w, SkScalar h, const SkRect& trimBox) { @@ -46,7 +64,7 @@ struct MultiPictureDocument final : public SkDocument { SkTArray fSizes; MultiPictureDocument(SkWStream* s, void (*d)(SkWStream*, bool)) : SkDocument(s, d) {} - ~MultiPictureDocument() { this->close(); } + ~MultiPictureDocument() override { this->close(); } SkCanvas* onBeginPage(SkScalar w, SkScalar h, const SkRect& c) override { fCurrentPageSize.set(w, h); @@ -59,19 +77,17 @@ struct MultiPictureDocument final : public SkDocument { void onClose(SkWStream* wStream) override { SkASSERT(wStream); SkASSERT(wStream->bytesWritten() == 0); - wStream->writeText(SkMultiPictureDocumentProtocol::kMagic); - wStream->write32(SkMultiPictureDocumentProtocol::kVersion); + wStream->writeText(kMagic); + wStream->write32(kVersion); wStream->write32(SkToU32(fPages.count())); for (SkSize s : fSizes) { wStream->write(&s, sizeof(s)); } - SkSize bigsize = SkMultiPictureDocumentProtocol::Join(fSizes); + SkSize bigsize = join(fSizes); SkCanvas* c = fPictureRecorder.beginRecording(SkRect::MakeSize(bigsize)); for (const sk_sp& page : fPages) { c->drawPicture(page); - c->drawAnnotation(SkRect::MakeEmpty(), - SkMultiPictureDocumentProtocol::kEndPage, - nullptr); + c->drawAnnotation(SkRect::MakeEmpty(), kEndPage, nullptr); } sk_sp p = fPictureRecorder.finishRecordingAsPicture(); p->serialize(wStream); @@ -89,3 +105,103 @@ struct MultiPictureDocument final : public SkDocument { sk_sp SkMakeMultiPictureDocument(SkWStream* wStream) { return sk_make_sp(wStream, nullptr); } + +//////////////////////////////////////////////////////////////////////////////// + +int SkMultiPictureDocumentReadPageCount(SkStreamSeekable* stream) { + if (!stream) { + return 0; + } + stream->seek(0); + const size_t size = sizeof(kMagic) - 1; + char buffer[size]; + if (size != stream->read(buffer, size) || 0 != memcmp(kMagic, buffer, size)) { + stream = nullptr; + return 0; + } + uint32_t versionNumber = stream->readU32(); + if (versionNumber != kVersion) { + return 0; + } + uint32_t pageCount = stream->readU32(); + if (pageCount > INT_MAX) { + return 0; + } + // leave stream position right here. + return (int)pageCount; +} + +bool SkMultiPictureDocumentReadPageSizes(SkStreamSeekable* stream, + SkDocumentPage* dstArray, + int dstArrayCount) { + if (!dstArray || dstArrayCount < 1) { + return false; + } + int pageCount = SkMultiPictureDocumentReadPageCount(stream); + if (pageCount < 1 || pageCount != dstArrayCount) { + return false; + } + for (int i = 0; i < pageCount; ++i) { + SkSize& s = dstArray[i].fSize; + if (sizeof(s) != stream->read(&s, sizeof(s))) { + return false; + } + } + // leave stream position right here. + return true; +} + +namespace { +struct PagerCanvas : public SkNWayCanvas { + SkPictureRecorder fRecorder; + SkDocumentPage* fDst; + int fCount; + int fIndex = 0; + PagerCanvas(SkISize wh, SkDocumentPage* dst, int count) + : SkNWayCanvas(wh.width(), wh.height()), fDst(dst), fCount(count) { + this->nextCanvas(); + } + void nextCanvas() { + if (fIndex < fCount) { + SkRect bounds = SkRect::MakeSize(fDst[fIndex].fSize); + this->addCanvas(fRecorder.beginRecording(bounds)); + } + } + void onDrawAnnotation(const SkRect& r, const char* key, SkData* d) override { + if (0 == strcmp(key, kEndPage)) { + this->removeAll(); + if (fIndex < fCount) { + fDst[fIndex].fPicture = fRecorder.finishRecordingAsPicture(); + ++fIndex; + } + this->nextCanvas(); + } else { + this->SkNWayCanvas::onDrawAnnotation(r, key, d); + } + } +}; +} // namespace + +bool SkMultiPictureDocumentRead(SkStreamSeekable* stream, + SkDocumentPage* dstArray, + int dstArrayCount) { + if (!SkMultiPictureDocumentReadPageSizes(stream, dstArray, dstArrayCount)) { + return false; + } + SkSize joined = {0.0f, 0.0f}; + for (int i = 0; i < dstArrayCount; ++i) { + joined = SkSize{SkTMax(joined.width(), dstArray[i].fSize.width()), + SkTMax(joined.height(), dstArray[i].fSize.height())}; + } + + auto picture = SkPicture::MakeFromStream(stream); + + PagerCanvas canvas(joined.toCeil(), dstArray, dstArrayCount); + // Must call playback(), not drawPicture() to reach + // PagerCanvas::onDrawAnnotation(). + picture->playback(&canvas); + if (canvas.fIndex != dstArrayCount) { + SkDEBUGF(("Malformed SkMultiPictureDocument\n")); + } + return true; +} diff --git a/gfx/skia/skia/src/utils/SkMultiPictureDocument.h b/gfx/skia/skia/src/utils/SkMultiPictureDocument.h index ac782606ff70..0ca8c2de729b 100644 --- a/gfx/skia/skia/src/utils/SkMultiPictureDocument.h +++ b/gfx/skia/skia/src/utils/SkMultiPictureDocument.h @@ -7,42 +7,32 @@ #ifndef SkMultiPictureDocument_DEFINED #define SkMultiPictureDocument_DEFINED -/* - This format is not intended to be used in production. - - For clients looking for a way to represent a document in memory, - - struct Doc { - std::vector> fPages; - std::vector fPageSizes; - }; - - or - - struct Page { - sk_sp fPage; - SkSize fPageSize; - }; - std::vector pages; - - would work much better. - - Multi-SkPicture (MSKP) files are still useful for debugging and - testing. - - The downsides of this format are currently: - - no way to extract a single page; must read the entire file at once. - - must use `dm` to convert to another format before passing into - standard skp tools. - - `dm` can extract the first page to skp, but no others. - - TODO(halcanary): replace with somthing that addresses these issues. - */ - #include "SkDocument.h" -/** Writes into an experimental, undocumented file format that is - useful for debugging documents printed via Skia. */ +class SkStreamSeekable; + +/** + * Writes into a file format that is similar to SkPicture::serialize() + */ SK_API sk_sp SkMakeMultiPictureDocument(SkWStream* dst); +struct SkDocumentPage { + sk_sp fPicture; + SkSize fSize; +}; + +/** + * Returns the number of pages in the SkMultiPictureDocument. + */ +SK_API int SkMultiPictureDocumentReadPageCount(SkStreamSeekable* src); + +/** + * Read the SkMultiPictureDocument into the provided array of pages. + * dstArrayCount must equal SkMultiPictureDocumentReadPageCount(). + * Return false on error. + */ +SK_API bool SkMultiPictureDocumentRead(SkStreamSeekable* src, + SkDocumentPage* dstArray, + int dstArrayCount); + #endif // SkMultiPictureDocument_DEFINED diff --git a/gfx/skia/skia/src/utils/SkMultiPictureDocumentPriv.h b/gfx/skia/skia/src/utils/SkMultiPictureDocumentPriv.h index 6d5ab47d211f..aff5b553379d 100644 --- a/gfx/skia/skia/src/utils/SkMultiPictureDocumentPriv.h +++ b/gfx/skia/skia/src/utils/SkMultiPictureDocumentPriv.h @@ -8,25 +8,14 @@ #ifndef SkMultiPictureDocumentPriv_DEFINED #define SkMultiPictureDocumentPriv_DEFINED -#include "SkTArray.h" -#include "SkSize.h" +#include "SkMultiPictureDocument.h" -namespace SkMultiPictureDocumentProtocol { -static constexpr char kMagic[] = "Skia Multi-Picture Doc\n\n"; - -static constexpr char kEndPage[] = "SkMultiPictureEndPage"; - -const uint32_t kVersion = 2; - -inline SkSize Join(const SkTArray& sizes) { - SkSize joined = SkSize::Make(0, 0); - for (SkSize s : sizes) { - joined = SkSize::Make(SkTMax(joined.width(), s.width()), - SkTMax(joined.height(), s.height())); - } - return joined; -} - -} +/** + * Additional API allows one to read the array of page-sizes without parsing + * the entire file. Used by DM. + */ +bool SkMultiPictureDocumentReadPageSizes(SkStreamSeekable* src, + SkDocumentPage* dstArray, + int dstArrayCount); #endif // SkMultiPictureDocumentPriv_DEFINED diff --git a/gfx/skia/skia/src/utils/SkMultiPictureDocumentReader.cpp b/gfx/skia/skia/src/utils/SkMultiPictureDocumentReader.cpp deleted file mode 100644 index 3924f3eb42cf..000000000000 --- a/gfx/skia/skia/src/utils/SkMultiPictureDocumentReader.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkMultiPictureDocumentPriv.h" -#include "SkMultiPictureDocumentReader.h" -#include "SkPicture.h" -#include "SkStream.h" -#include "SkPictureRecorder.h" -#include "SkNWayCanvas.h" - -bool SkMultiPictureDocumentReader::init(SkStreamSeekable* stream) { - if (!stream) { - return false; - } - stream->seek(0); - const size_t size = sizeof(SkMultiPictureDocumentProtocol::kMagic) - 1; - char buffer[size]; - if (size != stream->read(buffer, size) || - 0 != memcmp(SkMultiPictureDocumentProtocol::kMagic, buffer, size)) { - stream = nullptr; - return false; - } - bool good = true; - uint32_t versionNumber = stream->readU32(); - if (versionNumber != SkMultiPictureDocumentProtocol::kVersion) { - return false; - } - uint32_t pageCount = stream->readU32(); - fSizes.reset(pageCount); - for (uint32_t i = 0; i < pageCount; ++i) { - SkSize size; - good &= sizeof(size) == stream->read(&size, sizeof(size)); - fSizes[i] = size; - } - fOffset = stream->getPosition(); - return good; -} - -namespace { -struct PagerCanvas : public SkNWayCanvas { - SkPictureRecorder fRecorder; - const SkTArray* fSizes; - SkTArray>* fDest; - PagerCanvas(SkISize wh, - const SkTArray* s, - SkTArray>* d) - : SkNWayCanvas(wh.width(), wh.height()), fSizes(s), fDest(d) { - this->nextCanvas(); - } - void nextCanvas() { - int i = fDest->count(); - if (i < fSizes->count()) { - SkRect bounds = SkRect::MakeSize((*fSizes)[i]); - this->addCanvas(fRecorder.beginRecording(bounds)); - } - } - void onDrawAnnotation(const SkRect& r, const char* key, SkData* d) override { - if (0 == strcmp(key, SkMultiPictureDocumentProtocol::kEndPage)) { - this->removeAll(); - if (fRecorder.getRecordingCanvas()) { - fDest->emplace_back(fRecorder.finishRecordingAsPicture()); - } - this->nextCanvas(); - } else { - this->SkNWayCanvas::onDrawAnnotation(r, key, d); - } - } -}; -} // namespace - -sk_sp SkMultiPictureDocumentReader::readPage(SkStreamSeekable* stream, - int pageNumber) const { - SkASSERT(pageNumber >= 0); - SkASSERT(pageNumber < fSizes.count()); - if (0 == fPages.count()) { - stream->seek(fOffset); // jump to beginning of skp - auto picture = SkPicture::MakeFromStream(stream); - SkISize size = SkMultiPictureDocumentProtocol::Join(fSizes).toCeil(); - PagerCanvas canvas(size, &fSizes, &this->fPages); - // Must call playback(), not drawPicture() to reach - // PagerCanvas::onDrawAnnotation(). - picture->playback(&canvas); - if (fPages.count() != fSizes.count()) { - SkDEBUGF(("Malformed SkMultiPictureDocument\n")); - } - } - // Allow for malformed document. - return pageNumber < fPages.count() ? fPages[pageNumber] : nullptr; -} diff --git a/gfx/skia/skia/src/utils/SkMultiPictureDocumentReader.h b/gfx/skia/skia/src/utils/SkMultiPictureDocumentReader.h deleted file mode 100644 index e0473a653977..000000000000 --- a/gfx/skia/skia/src/utils/SkMultiPictureDocumentReader.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkMultiPictureDocumentReader_DEFINED -#define SkMultiPictureDocumentReader_DEFINED - -#include "../private/SkTArray.h" -#include "SkPicture.h" -#include "SkSize.h" -#include "SkStream.h" - -/** A lightweight helper class for reading a Skia MultiPictureDocument. */ -class SkMultiPictureDocumentReader { -public: - /** Initialize the MultiPictureDocument. Does not take ownership - of the SkStreamSeekable. */ - bool init(SkStreamSeekable*); - - /** Return to factory settings. */ - void reset() { - fSizes.reset(); - fPages.reset(); - } - - /** Call this after calling init() (otherwise you'll always get zero). */ - int pageCount() const { return fSizes.count(); } - - /** Deserialize a page from the stream. Call init() first. The - SkStreamSeekable doesn't need to be the same object, but - should point to the same information as before. */ - sk_sp readPage(SkStreamSeekable*, int) const; - - /** Fetch the size of the given page, without deserializing the - entire page. */ - SkSize pageSize(int i) const { return fSizes[i]; } - -private: - SkTArray fSizes; - size_t fOffset; - mutable SkTArray> fPages; -}; - -#endif // SkMultiPictureDocumentReader_DEFINED diff --git a/gfx/skia/skia/src/utils/SkNWayCanvas.cpp b/gfx/skia/skia/src/utils/SkNWayCanvas.cpp index e19e7a8e5513..4f6ad46d8505 100644 --- a/gfx/skia/skia/src/utils/SkNWayCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkNWayCanvas.cpp @@ -6,8 +6,7 @@ */ #include "SkNWayCanvas.h" -SkNWayCanvas::SkNWayCanvas(int width, int height) - : INHERITED(width, height) {} +SkNWayCanvas::SkNWayCanvas(int width, int height) : INHERITED(width, height) {} SkNWayCanvas::~SkNWayCanvas() { this->removeAll(); @@ -15,7 +14,6 @@ SkNWayCanvas::~SkNWayCanvas() { void SkNWayCanvas::addCanvas(SkCanvas* canvas) { if (canvas) { - canvas->ref(); *fList.append() = canvas; } } @@ -23,13 +21,11 @@ void SkNWayCanvas::addCanvas(SkCanvas* canvas) { void SkNWayCanvas::removeCanvas(SkCanvas* canvas) { int index = fList.find(canvas); if (index >= 0) { - canvas->unref(); fList.removeShuffle(index); } } void SkNWayCanvas::removeAll() { - fList.unrefAll(); fList.reset(); } @@ -100,7 +96,7 @@ void SkNWayCanvas::didSetMatrix(const SkMatrix& matrix) { this->INHERITED::didSetMatrix(matrix); } -void SkNWayCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkNWayCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { Iter iter(fList); while (iter.next()) { iter->clipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle); @@ -108,7 +104,7 @@ void SkNWayCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeS this->INHERITED::onClipRect(rect, op, edgeStyle); } -void SkNWayCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkNWayCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { Iter iter(fList); while (iter.next()) { iter->clipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle); @@ -116,7 +112,7 @@ void SkNWayCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle ed this->INHERITED::onClipRRect(rrect, op, edgeStyle); } -void SkNWayCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) { +void SkNWayCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { Iter iter(fList); while (iter.next()) { iter->clipPath(path, op, kSoft_ClipEdgeStyle == edgeStyle); @@ -124,7 +120,7 @@ void SkNWayCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeS this->INHERITED::onClipPath(path, op, edgeStyle); } -void SkNWayCanvas::onClipRegion(const SkRegion& deviceRgn, ClipOp op) { +void SkNWayCanvas::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { Iter iter(fList); while (iter.next()) { iter->clipRegion(deviceRgn, op); @@ -286,24 +282,20 @@ void SkNWayCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matri } } -void SkNWayCanvas::onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { +void SkNWayCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode, + const SkPaint& paint) { Iter iter(fList); while (iter.next()) { - iter->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode, - indices, indexCount, paint); + iter->drawVertices(vertices, bmode, paint); } } void SkNWayCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, + const SkPoint texCoords[4], SkBlendMode bmode, const SkPaint& paint) { Iter iter(fList); while (iter.next()) { - iter->drawPatch(cubics, colors, texCoords, xmode, paint); + iter->drawPatch(cubics, colors, texCoords, bmode, paint); } } diff --git a/gfx/skia/skia/src/utils/SkNullCanvas.cpp b/gfx/skia/skia/src/utils/SkNullCanvas.cpp index b5ee8d30a183..1f28706e20c5 100644 --- a/gfx/skia/skia/src/utils/SkNullCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkNullCanvas.cpp @@ -9,10 +9,10 @@ #include "SkCanvas.h" #include "SkNWayCanvas.h" +#include "SkMakeUnique.h" - -SkCanvas* SkCreateNullCanvas() { +std::unique_ptr SkMakeNullCanvas() { // An N-Way canvas forwards calls to N canvas's. When N == 0 it's // effectively a null canvas. - return new SkNWayCanvas(0, 0); + return std::unique_ptr(new SkNWayCanvas(0, 0)); } diff --git a/gfx/skia/skia/src/utils/SkOSFile.cpp b/gfx/skia/skia/src/utils/SkOSPath.cpp similarity index 72% rename from gfx/skia/skia/src/utils/SkOSFile.cpp rename to gfx/skia/skia/src/utils/SkOSPath.cpp index a0c003ba8d1c..d9a5ac53f31e 100644 --- a/gfx/skia/skia/src/utils/SkOSFile.cpp +++ b/gfx/skia/skia/src/utils/SkOSPath.cpp @@ -4,12 +4,13 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#include "SkOSFile.h" + +#include "SkOSPath.h" SkString SkOSPath::Join(const char *rootPath, const char *relativePath) { SkString result(rootPath); - if (!result.endsWith(SkPATH_SEPARATOR) && !result.isEmpty()) { - result.appendUnichar(SkPATH_SEPARATOR); + if (!result.endsWith(SEPARATOR) && !result.isEmpty()) { + result.appendUnichar(SEPARATOR); } result.append(relativePath); return result; @@ -19,7 +20,7 @@ SkString SkOSPath::Basename(const char* fullPath) { if (!fullPath) { return SkString(); } - const char* filename = strrchr(fullPath, SkPATH_SEPARATOR); + const char* filename = strrchr(fullPath, SEPARATOR); if (nullptr == filename) { filename = fullPath; } else { @@ -32,12 +33,12 @@ SkString SkOSPath::Dirname(const char* fullPath) { if (!fullPath) { return SkString(); } - const char* end = strrchr(fullPath, SkPATH_SEPARATOR); + const char* end = strrchr(fullPath, SEPARATOR); if (nullptr == end) { return SkString(); } if (end == fullPath) { - SkASSERT(fullPath[0] == SkPATH_SEPARATOR); + SkASSERT(fullPath[0] == SEPARATOR); ++end; } return SkString(fullPath, end - fullPath); diff --git a/gfx/skia/skia/src/utils/SkOSPath.h b/gfx/skia/skia/src/utils/SkOSPath.h new file mode 100644 index 000000000000..5f73289cf540 --- /dev/null +++ b/gfx/skia/skia/src/utils/SkOSPath.h @@ -0,0 +1,55 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOSPath_DEFINED +#define SkOSPath_DEFINED + +#include "SkString.h" + +/** + * Functions for modifying SkStrings which represent paths on the filesystem. + */ +class SkOSPath { +public: +#ifdef _WIN32 + const static char SEPARATOR = '\\'; +#else + const static char SEPARATOR = '/'; +#endif + + /** + * Assembles rootPath and relativePath into a single path, like this: + * rootPath/relativePath. + * It is okay to call with a NULL rootPath and/or relativePath. A path + * separator will still be inserted. + * + * Uses SkPATH_SEPARATOR, to work on all platforms. + */ + static SkString Join(const char* rootPath, const char* relativePath); + + /** + * Return the name of the file, ignoring the directory structure. + * Behaves like python's os.path.basename. If the fullPath is + * /dir/subdir/, an empty string is returned. + * @param fullPath Full path to the file. + * @return SkString The basename of the file - anything beyond the + * final slash, or the full name if there is no slash. + */ + static SkString Basename(const char* fullPath); + + /** + * Given a qualified file name returns the directory. + * Behaves like python's os.path.dirname. If the fullPath is + * /dir/subdir/ the return will be /dir/subdir/ + * @param fullPath Full path to the file. + * @return SkString The dir containing the file - anything preceding the + * final slash, or the full name if ending in a slash. + */ + static SkString Dirname(const char* fullPath); +}; + +#endif diff --git a/gfx/skia/skia/src/utils/SkPaintFilterCanvas.cpp b/gfx/skia/skia/src/utils/SkPaintFilterCanvas.cpp index 15d76d612708..e504c721190d 100644 --- a/gfx/skia/skia/src/utils/SkPaintFilterCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkPaintFilterCanvas.cpp @@ -29,15 +29,11 @@ private: bool fShouldDraw; }; -SkPaintFilterCanvas::SkPaintFilterCanvas(int width, int height) : INHERITED(width, height) { } - SkPaintFilterCanvas::SkPaintFilterCanvas(SkCanvas *canvas) : INHERITED(canvas->imageInfo().width(), canvas->imageInfo().height()) { // Transfer matrix & clip state before adding the target canvas. - SkIRect devClip; - canvas->getClipDeviceBounds(&devClip); - this->clipRect(SkRect::Make(devClip)); + this->clipRect(SkRect::Make(canvas->getDeviceClipBounds())); this->setMatrix(canvas->getTotalMatrix()); this->addCanvas(canvas); @@ -151,24 +147,20 @@ void SkPaintFilterCanvas::onDrawImageNine(const SkImage* image, const SkIRect& c } } -void SkPaintFilterCanvas::onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { +void SkPaintFilterCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode, + const SkPaint& paint) { AutoPaintFilter apf(this, kVertices_Type, paint); if (apf.shouldDraw()) { - this->INHERITED::onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode, indices, - indexCount, *apf.paint()); + this->INHERITED::onDrawVerticesObject(vertices, bmode, *apf.paint()); } } void SkPaintFilterCanvas::onDrawPatch(const SkPoint cubics[], const SkColor colors[], - const SkPoint texCoords[], SkXfermode* xmode, + const SkPoint texCoords[], SkBlendMode bmode, const SkPaint& paint) { AutoPaintFilter apf(this, kPatch_Type, paint); if (apf.shouldDraw()) { - this->INHERITED::onDrawPatch(cubics, colors, texCoords, xmode, *apf.paint()); + this->INHERITED::onDrawPatch(cubics, colors, texCoords, bmode, *apf.paint()); } } diff --git a/gfx/skia/skia/src/utils/SkParsePath.cpp b/gfx/skia/skia/src/utils/SkParsePath.cpp index c924661907f2..c5fed6cfcad6 100644 --- a/gfx/skia/skia/src/utils/SkParsePath.cpp +++ b/gfx/skia/skia/src/utils/SkParsePath.cpp @@ -261,7 +261,7 @@ void SkParsePath::ToSVGString(const SkPath& path, SkString* str) { stream.write("Z", 1); break; case SkPath::kDone_Verb: - str->resize(stream.getOffset()); + str->resize(stream.bytesWritten()); stream.copyTo(str->writable_str()); return; } diff --git a/gfx/skia/skia/src/utils/SkPatchGrid.cpp b/gfx/skia/skia/src/utils/SkPatchGrid.cpp deleted file mode 100644 index 3b7c06e95409..000000000000 --- a/gfx/skia/skia/src/utils/SkPatchGrid.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkPatchGrid.h" -#include "SkPatchUtils.h" - -SkPatchGrid::SkPatchGrid(int rows, int cols, VertexType flags, SkXfermode* xfer) - : fRows(0) - , fCols(0) - , fModeFlags(kNone_VertexType) - , fCornerPts(nullptr) - , fCornerColors(nullptr) - , fTexCoords(nullptr) - , fHrzCtrlPts(nullptr) - , fVrtCtrlPts(nullptr) - , fXferMode(nullptr) { - this->reset(rows, cols, flags, xfer); -} - -SkPatchGrid::~SkPatchGrid() { - delete[] fCornerPts; - delete[] fCornerColors; - delete[] fTexCoords; - delete[] fHrzCtrlPts; - delete[] fVrtCtrlPts; -} - -bool SkPatchGrid::setPatch(int x, int y, const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4]) { - // Check for the passed paramaters to be within the range of the grid dimensions and a valid - // pointer for the cubics' control points. - if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1 || nullptr == cubics) { - return false; - } - - // setup corners and colors - int cornerPos = y * (fCols + 1) + x; - fCornerPts[cornerPos] = cubics[SkPatchUtils::kTopP0_CubicCtrlPts]; - fCornerPts[cornerPos + 1] = cubics[SkPatchUtils::kTopP3_CubicCtrlPts]; - fCornerPts[cornerPos + (fCols + 1)] = cubics[SkPatchUtils::kBottomP0_CubicCtrlPts]; - fCornerPts[cornerPos + (fCols + 1) + 1] = cubics[SkPatchUtils::kBottomP3_CubicCtrlPts]; - - // set horizontal control points - int hrzPos = y * (fCols * 2) + (x * 2); - fHrzCtrlPts[hrzPos] = cubics[SkPatchUtils::kTopP1_CubicCtrlPts]; - fHrzCtrlPts[hrzPos + 1] = cubics[SkPatchUtils::kTopP2_CubicCtrlPts]; - fHrzCtrlPts[hrzPos + (fCols * 2)] = cubics[SkPatchUtils::kBottomP1_CubicCtrlPts]; - fHrzCtrlPts[hrzPos + (fCols * 2) + 1] = cubics[SkPatchUtils::kBottomP2_CubicCtrlPts]; - - // set vertical control points - int vrtPos = (y*2) * (fCols + 1) + x; - fVrtCtrlPts[vrtPos] = cubics[SkPatchUtils::kLeftP1_CubicCtrlPts]; - fVrtCtrlPts[vrtPos + 1] = cubics[SkPatchUtils::kRightP1_CubicCtrlPts]; - fVrtCtrlPts[vrtPos + (fCols + 1)] = cubics[SkPatchUtils::kLeftP2_CubicCtrlPts]; - fVrtCtrlPts[vrtPos + (fCols + 1) + 1] = cubics[SkPatchUtils::kRightP2_CubicCtrlPts]; - - // set optional values (colors and texture coordinates) - if ((fModeFlags & kColors_VertexType) && colors) { - fCornerColors[cornerPos] = colors[0]; - fCornerColors[cornerPos + 1] = colors[1]; - fCornerColors[cornerPos + (fCols + 1)] = colors[3]; - fCornerColors[cornerPos + (fCols + 1) + 1] = colors[2]; - } - - if ((fModeFlags & kTexs_VertexType) && texCoords) { - fTexCoords[cornerPos] = texCoords[0]; - fTexCoords[cornerPos + 1] = texCoords[1]; - fTexCoords[cornerPos + (fCols + 1)] = texCoords[3]; - fTexCoords[cornerPos + (fCols + 1) + 1] = texCoords[2]; - } - - return true; -} - -bool SkPatchGrid::getPatch(int x, int y, SkPoint cubics[12], SkColor colors[4], - SkPoint texCoords[4]) const { - - if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1 || nullptr == cubics) { - return false; - } - - // set the patch by building the array of points and colors with the corresponding values. - int cornerPos = y * (fCols + 1) + x; - cubics[SkPatchUtils::kTopP0_CubicCtrlPts] = fCornerPts[cornerPos]; - cubics[SkPatchUtils::kTopP3_CubicCtrlPts] = fCornerPts[cornerPos + 1]; - cubics[SkPatchUtils::kBottomP0_CubicCtrlPts] = fCornerPts[cornerPos + (fCols + 1)]; - cubics[SkPatchUtils::kBottomP3_CubicCtrlPts] = fCornerPts[cornerPos + (fCols + 1) + 1]; - - int hrzPos = y * (fCols * 2) + (x * 2); - cubics[SkPatchUtils::kTopP1_CubicCtrlPts] = fHrzCtrlPts[hrzPos]; - cubics[SkPatchUtils::kTopP2_CubicCtrlPts] = fHrzCtrlPts[hrzPos + 1]; - cubics[SkPatchUtils::kBottomP1_CubicCtrlPts] = fHrzCtrlPts[hrzPos + (fCols * 2)]; - cubics[SkPatchUtils::kBottomP2_CubicCtrlPts] = fHrzCtrlPts[hrzPos + (fCols * 2) + 1]; - - int vrtPos = (y*2) * (fCols + 1) + x; - cubics[SkPatchUtils::kLeftP1_CubicCtrlPts] = fVrtCtrlPts[vrtPos]; - cubics[SkPatchUtils::kRightP1_CubicCtrlPts] = fVrtCtrlPts[vrtPos + 1]; - cubics[SkPatchUtils::kLeftP2_CubicCtrlPts] = fVrtCtrlPts[vrtPos + (fCols + 1)]; - cubics[SkPatchUtils::kRightP2_CubicCtrlPts] = fVrtCtrlPts[vrtPos + (fCols + 1) + 1]; - - if ((fModeFlags & kColors_VertexType) && colors) { - colors[0] = fCornerColors[cornerPos]; - colors[1] = fCornerColors[cornerPos + 1]; - colors[3] = fCornerColors[cornerPos + (fCols + 1)]; - colors[2] = fCornerColors[cornerPos + (fCols + 1) + 1]; - } - - if ((fModeFlags & kTexs_VertexType) && texCoords) { - texCoords[0] = fTexCoords[cornerPos]; - texCoords[1] = fTexCoords[cornerPos + 1]; - texCoords[3] = fTexCoords[cornerPos + (fCols + 1)]; - texCoords[2] = fTexCoords[cornerPos + (fCols + 1) + 1]; - } - - return true; -} - -void SkPatchGrid::reset(int rows, int cols, VertexType flags, SkXfermode* xMode) { - delete[] fCornerPts; - delete[] fCornerColors; - delete[] fTexCoords; - delete[] fHrzCtrlPts; - delete[] fVrtCtrlPts; - - fCols = cols; - fRows = rows; - fModeFlags = flags; - fXferMode = xMode; - - fCornerPts = new SkPoint[(fRows + 1) * (fCols + 1)]; - fHrzCtrlPts = new SkPoint[(fRows + 1) * fCols * 2]; - fVrtCtrlPts = new SkPoint[fRows * 2 * (fCols + 1)]; - memset(fCornerPts, 0, (fRows + 1) * (fCols + 1) * sizeof(SkPoint)); - memset(fHrzCtrlPts, 0, (fRows + 1) * fCols * 2 * sizeof(SkPoint)); - memset(fVrtCtrlPts, 0, fRows * 2 * (fCols + 1) * sizeof(SkPoint)); - - if (fModeFlags & kColors_VertexType) { - fCornerColors = new SkColor[(fRows + 1) * (fCols + 1)]; - memset(fCornerColors, 0, (fRows + 1) * (fCols + 1) * sizeof(SkColor)); - } - - if (fModeFlags & kTexs_VertexType) { - fTexCoords = new SkPoint[(fRows + 1) * (fCols + 1)]; - memset(fTexCoords, 0, (fRows + 1) * (fCols + 1) * sizeof(SkPoint)); - } -} - -void SkPatchGrid::draw(SkCanvas* canvas, SkPaint& paint) { - int* maxCols = new int[fCols]; - int* maxRows = new int[fRows]; - memset(maxCols, 0, fCols * sizeof(int)); - memset(maxRows, 0, fRows * sizeof(int)); - - // Get the maximum level of detail per axis for each row and column - for (int y = 0; y < fRows; y++) { - for (int x = 0; x < fCols; x++) { - SkPoint cubics[12]; - this->getPatch(x, y, cubics, nullptr, nullptr); - SkMatrix matrix = canvas->getTotalMatrix(); - SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix); - maxCols[x] = SkMax32(maxCols[x], lod.width()); - maxRows[y] = SkMax32(maxRows[y], lod.height()); - } - } - // Draw the patches by generating their geometry with the maximum level of detail per axis. - for (int x = 0; x < fCols; x++) { - for (int y = 0; y < fRows; y++) { - SkPoint cubics[12]; - SkPoint texCoords[4]; - SkColor colors[4]; - this->getPatch(x, y, cubics, colors, texCoords); - SkPatchUtils::VertexData data; - if (SkPatchUtils::getVertexData(&data, cubics, - fModeFlags & kColors_VertexType ? colors : nullptr, - fModeFlags & kTexs_VertexType ? texCoords : nullptr, - maxCols[x], maxRows[y])) { - canvas->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount, - data.fPoints, data.fTexCoords, data.fColors, fXferMode, - data.fIndices, data.fIndexCount, paint); - } - } - } - delete[] maxCols; - delete[] maxRows; -} diff --git a/gfx/skia/skia/src/utils/SkPatchGrid.h b/gfx/skia/skia/src/utils/SkPatchGrid.h deleted file mode 100644 index ca2a35b912e0..000000000000 --- a/gfx/skia/skia/src/utils/SkPatchGrid.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkPatchGrid_DEFINED -#define SkPatchGrid_DEFINED - -#include "SkCanvas.h" -#include "SkPatchUtils.h" -#include "SkXfermode.h" - -/** - * Class that represents a grid of patches. Adjacent patches share their corners and a color is - * specified at each one of them. The colors are bilinearly interpolated across the patch. - * - * This implementation defines a bidimensional array of patches. There are 3 arrays to store the - * control points of the patches to avoid storing repeated data since there are several points - * shared between adjacent patches. - * - * The array fCornerPts stores the corner control points of the patches. - * The array fHrzPts holds the intermidiate control points of the top and bottom curves of a patch. - * The array fVrtPts holds the intermidiate control points of the left and right curves of a patch. - * The array fCornerColors holds the corner colors in the same format as fCornerPts. - * The array fTexCoords holds the texture coordinates in the same format as fCornerpts. - * - * fCornerPts fHrzPts fVrtPts - * -------------- ------------------- -------------- - * | C0 | C1 | C2 | | H0 | H1 | H2 | H3 | | V0 | V1 | V2 | - * -------------- ------------------ --------------- - * | C3 | C4 | C5 | | H4 | H5 | H6 | H7 | | V4 | V5 | V6 | - * -------------- ------------------- -------------- - * | C6 | C7 | C8 | | H8 | H9 | H10| H11| | V6 | V7 | V8 | - * -------------- ------------------- -------------- - * | V9 | V10| V11| - * -------------- - * - * With the above configuration we would have a 2x2 grid of patches: - * H0 H1 H2 H3 - * / \/ \ - * C0-------C1-------C2 - * /| | |\ - * v0 | v1 | v2 - * v3 | V4 | v5 - * \| | |/ - * C3-H4-H5-C4-H6-H7-C5 - * /| | |\ - * v6 | v7 | v8 - * v9 | v10 | v11 - * \| | |/ - * C6-------C7-------C8 - * \ / \ / - * H8 H9 H10 H11 - * - * When trying to get a patch at a certain position it justs builds it with the corresponding - * points. - * When adding a patch it tries to add the points at their corresponding position trying to comply - * with the adjacent points or overwriting them. - * - * Based the idea on the SVG2 spec for mesh gradients in which a grid of patches is build as in the - * the following example: - * - * - * - * - * Up to four stops in first patch. See details below. - * - * - * Any number of meshPatches in row. - * - * - * - * Any number of meshRows, each with the same number of meshPatches as in the first row. - * - * - */ -class SkPatchGrid { - -public: - - enum VertexType { - kNone_VertexType = 0X00, - kColors_VertexType = 0x01, - kTexs_VertexType = 0x02, - kColorsAndTexs_VertexType = 0x03 - }; - - SkPatchGrid(int rows = 0, int cols = 0, VertexType flags = kNone_VertexType, - SkXfermode* xfer = nullptr); - - ~SkPatchGrid(); - - /** - * Add a patch at location (x,y) overwriting the previous patch and shared points so they - * mantain C0 connectivity. - * The control points must be passed in a clockwise order starting at the top left corner. - * The colors and texCoords are the values at the corners of the patch which will be bilerp - * across it, they must also be in counterclockwise order starting at the top left corner. - */ - bool setPatch(int x, int y, const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4]); - - /** - * Get patch at location (x,y). If cubics, colors or texCoords is not nullptr it sets patch's - * array with its corresponding values. - * The function returns false if the cubics parameter is nullptr or if the (x,y) coordinates are - * not within the range of the grid. - */ - bool getPatch(int x, int y, SkPoint cubics[12], SkColor colors[4], SkPoint texCoords[4]) const; - - /** - * Resets the grid of patches to contain rows and cols of patches. - */ - void reset(int rows, int cols, VertexType flags, SkXfermode* xMode); - - /** - * Draws the grid of patches. The patches are drawn starting at patch (0,0) drawing columns, so - * for a 2x2 grid the order would be (0,0)->(0,1)->(1,0)->(1,1). The order follows the order - * of the parametric coordinates of the coons patch. - */ - void draw(SkCanvas* canvas, SkPaint& paint); - - /** - * Get the dimensions of the grid of patches. - */ - SkISize getDimensions() const { - return SkISize::Make(fCols, fRows); - } - -private: - int fRows, fCols; - VertexType fModeFlags; - SkPoint* fCornerPts; - SkColor* fCornerColors; - SkPoint* fTexCoords; - SkPoint* fHrzCtrlPts; - SkPoint* fVrtCtrlPts; - SkXfermode* fXferMode; -}; - - -#endif diff --git a/gfx/skia/skia/src/utils/SkPatchUtils.cpp b/gfx/skia/skia/src/utils/SkPatchUtils.cpp index cbaae39e8e9d..9a789ea80f86 100644 --- a/gfx/skia/skia/src/utils/SkPatchUtils.cpp +++ b/gfx/skia/skia/src/utils/SkPatchUtils.cpp @@ -10,6 +10,38 @@ #include "SkColorPriv.h" #include "SkGeometry.h" +namespace { + enum CubicCtrlPts { + kTopP0_CubicCtrlPts = 0, + kTopP1_CubicCtrlPts = 1, + kTopP2_CubicCtrlPts = 2, + kTopP3_CubicCtrlPts = 3, + + kRightP0_CubicCtrlPts = 3, + kRightP1_CubicCtrlPts = 4, + kRightP2_CubicCtrlPts = 5, + kRightP3_CubicCtrlPts = 6, + + kBottomP0_CubicCtrlPts = 9, + kBottomP1_CubicCtrlPts = 8, + kBottomP2_CubicCtrlPts = 7, + kBottomP3_CubicCtrlPts = 6, + + kLeftP0_CubicCtrlPts = 0, + kLeftP1_CubicCtrlPts = 11, + kLeftP2_CubicCtrlPts = 10, + kLeftP3_CubicCtrlPts = 9, + }; + + // Enum for corner also clockwise. + enum Corner { + kTopLeft_Corner = 0, + kTopRight_Corner, + kBottomRight_Corner, + kBottomLeft_Corner + }; +} + /** * Evaluator to sample the values of a cubic bezier using forward differences. * Forward differences is a method for evaluating a nth degree polynomial at a uniform step by only @@ -118,19 +150,19 @@ SkISize SkPatchUtils::GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* // Approximate length of each cubic. SkPoint pts[kNumPtsCubic]; - SkPatchUtils::getTopCubic(cubics, pts); + SkPatchUtils::GetTopCubic(cubics, pts); matrix->mapPoints(pts, kNumPtsCubic); SkScalar topLength = approx_arc_length(pts, kNumPtsCubic); - SkPatchUtils::getBottomCubic(cubics, pts); + SkPatchUtils::GetBottomCubic(cubics, pts); matrix->mapPoints(pts, kNumPtsCubic); SkScalar bottomLength = approx_arc_length(pts, kNumPtsCubic); - SkPatchUtils::getLeftCubic(cubics, pts); + SkPatchUtils::GetLeftCubic(cubics, pts); matrix->mapPoints(pts, kNumPtsCubic); SkScalar leftLength = approx_arc_length(pts, kNumPtsCubic); - SkPatchUtils::getRightCubic(cubics, pts); + SkPatchUtils::GetRightCubic(cubics, pts); matrix->mapPoints(pts, kNumPtsCubic); SkScalar rightLength = approx_arc_length(pts, kNumPtsCubic); @@ -141,89 +173,94 @@ SkISize SkPatchUtils::GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* return SkISize::Make(SkMax32(8, lodX), SkMax32(8, lodY)); } -void SkPatchUtils::getTopCubic(const SkPoint cubics[12], SkPoint points[4]) { +void SkPatchUtils::GetTopCubic(const SkPoint cubics[12], SkPoint points[4]) { points[0] = cubics[kTopP0_CubicCtrlPts]; points[1] = cubics[kTopP1_CubicCtrlPts]; points[2] = cubics[kTopP2_CubicCtrlPts]; points[3] = cubics[kTopP3_CubicCtrlPts]; } -void SkPatchUtils::getBottomCubic(const SkPoint cubics[12], SkPoint points[4]) { +void SkPatchUtils::GetBottomCubic(const SkPoint cubics[12], SkPoint points[4]) { points[0] = cubics[kBottomP0_CubicCtrlPts]; points[1] = cubics[kBottomP1_CubicCtrlPts]; points[2] = cubics[kBottomP2_CubicCtrlPts]; points[3] = cubics[kBottomP3_CubicCtrlPts]; } -void SkPatchUtils::getLeftCubic(const SkPoint cubics[12], SkPoint points[4]) { +void SkPatchUtils::GetLeftCubic(const SkPoint cubics[12], SkPoint points[4]) { points[0] = cubics[kLeftP0_CubicCtrlPts]; points[1] = cubics[kLeftP1_CubicCtrlPts]; points[2] = cubics[kLeftP2_CubicCtrlPts]; points[3] = cubics[kLeftP3_CubicCtrlPts]; } -void SkPatchUtils::getRightCubic(const SkPoint cubics[12], SkPoint points[4]) { +void SkPatchUtils::GetRightCubic(const SkPoint cubics[12], SkPoint points[4]) { points[0] = cubics[kRightP0_CubicCtrlPts]; points[1] = cubics[kRightP1_CubicCtrlPts]; points[2] = cubics[kRightP2_CubicCtrlPts]; points[3] = cubics[kRightP3_CubicCtrlPts]; } -bool SkPatchUtils::getVertexData(SkPatchUtils::VertexData* data, const SkPoint cubics[12], - const SkColor colors[4], const SkPoint texCoords[4], int lodX, int lodY) { - if (lodX < 1 || lodY < 1 || nullptr == cubics || nullptr == data) { - return false; +sk_sp SkPatchUtils::MakeVertices(const SkPoint cubics[12], const SkColor srcColors[4], + const SkPoint srcTexCoords[4], int lodX, int lodY) { + if (lodX < 1 || lodY < 1 || nullptr == cubics) { + return nullptr; } // check for overflow in multiplication const int64_t lodX64 = (lodX + 1), - lodY64 = (lodY + 1), - mult64 = lodX64 * lodY64; + lodY64 = (lodY + 1), + mult64 = lodX64 * lodY64; if (mult64 > SK_MaxS32) { - return false; + return nullptr; } - data->fVertexCount = SkToS32(mult64); + int vertexCount = SkToS32(mult64); // it is recommended to generate draw calls of no more than 65536 indices, so we never generate // more than 60000 indices. To accomplish that we resize the LOD and vertex count - if (data->fVertexCount > 10000 || lodX > 200 || lodY > 200) { - SkScalar weightX = static_cast(lodX) / (lodX + lodY); - SkScalar weightY = static_cast(lodY) / (lodX + lodY); + if (vertexCount > 10000 || lodX > 200 || lodY > 200) { + float weightX = static_cast(lodX) / (lodX + lodY); + float weightY = static_cast(lodY) / (lodX + lodY); // 200 comes from the 100 * 2 which is the max value of vertices because of the limit of // 60000 indices ( sqrt(60000 / 6) that comes from data->fIndexCount = lodX * lodY * 6) lodX = static_cast(weightX * 200); lodY = static_cast(weightY * 200); - data->fVertexCount = (lodX + 1) * (lodY + 1); + vertexCount = (lodX + 1) * (lodY + 1); + } + const int indexCount = lodX * lodY * 6; + uint32_t flags = 0; + if (srcTexCoords) { + flags |= SkVertices::kHasTexCoords_BuilderFlag; + } + if (srcColors) { + flags |= SkVertices::kHasColors_BuilderFlag; } - data->fIndexCount = lodX * lodY * 6; - data->fPoints = new SkPoint[data->fVertexCount]; - data->fIndices = new uint16_t[data->fIndexCount]; + SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, vertexCount, indexCount, flags); + SkPoint* pos = builder.positions(); + SkPoint* texs = builder.texCoords(); + SkColor* colors = builder.colors(); + uint16_t* indices = builder.indices(); // if colors is not null then create array for colors SkPMColor colorsPM[kNumCorners]; - if (colors) { + if (srcColors) { // premultiply colors to avoid color bleeding. for (int i = 0; i < kNumCorners; i++) { - colorsPM[i] = SkPreMultiplyColor(colors[i]); + colorsPM[i] = SkPreMultiplyColor(srcColors[i]); } - data->fColors = new uint32_t[data->fVertexCount]; - } - - // if texture coordinates are not null then create array for them - if (texCoords) { - data->fTexCoords = new SkPoint[data->fVertexCount]; + srcColors = colorsPM; } SkPoint pts[kNumPtsCubic]; - SkPatchUtils::getBottomCubic(cubics, pts); + SkPatchUtils::GetBottomCubic(cubics, pts); FwDCubicEvaluator fBottom(pts); - SkPatchUtils::getTopCubic(cubics, pts); + SkPatchUtils::GetTopCubic(cubics, pts); FwDCubicEvaluator fTop(pts); - SkPatchUtils::getLeftCubic(cubics, pts); + SkPatchUtils::GetLeftCubic(cubics, pts); FwDCubicEvaluator fLeft(pts); - SkPatchUtils::getRightCubic(cubics, pts); + SkPatchUtils::GetRightCubic(cubics, pts); FwDCubicEvaluator fRight(pts); fBottom.restart(lodX); @@ -254,58 +291,56 @@ bool SkPatchUtils::getVertexData(SkPatchUtils::VertexData* data, const SkPoint c + u * fTop.getCtrlPoints()[3].y()) + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y() + u * fBottom.getCtrlPoints()[3].y())); - data->fPoints[dataIndex] = s0 + s1 - s2; + pos[dataIndex] = s0 + s1 - s2; if (colors) { uint8_t a = uint8_t(bilerp(u, v, - SkScalar(SkColorGetA(colorsPM[kTopLeft_Corner])), - SkScalar(SkColorGetA(colorsPM[kTopRight_Corner])), - SkScalar(SkColorGetA(colorsPM[kBottomLeft_Corner])), - SkScalar(SkColorGetA(colorsPM[kBottomRight_Corner])))); + SkScalar(SkColorGetA(colorsPM[kTopLeft_Corner])), + SkScalar(SkColorGetA(colorsPM[kTopRight_Corner])), + SkScalar(SkColorGetA(colorsPM[kBottomLeft_Corner])), + SkScalar(SkColorGetA(colorsPM[kBottomRight_Corner])))); uint8_t r = uint8_t(bilerp(u, v, - SkScalar(SkColorGetR(colorsPM[kTopLeft_Corner])), - SkScalar(SkColorGetR(colorsPM[kTopRight_Corner])), - SkScalar(SkColorGetR(colorsPM[kBottomLeft_Corner])), - SkScalar(SkColorGetR(colorsPM[kBottomRight_Corner])))); + SkScalar(SkColorGetR(colorsPM[kTopLeft_Corner])), + SkScalar(SkColorGetR(colorsPM[kTopRight_Corner])), + SkScalar(SkColorGetR(colorsPM[kBottomLeft_Corner])), + SkScalar(SkColorGetR(colorsPM[kBottomRight_Corner])))); uint8_t g = uint8_t(bilerp(u, v, - SkScalar(SkColorGetG(colorsPM[kTopLeft_Corner])), - SkScalar(SkColorGetG(colorsPM[kTopRight_Corner])), - SkScalar(SkColorGetG(colorsPM[kBottomLeft_Corner])), - SkScalar(SkColorGetG(colorsPM[kBottomRight_Corner])))); + SkScalar(SkColorGetG(colorsPM[kTopLeft_Corner])), + SkScalar(SkColorGetG(colorsPM[kTopRight_Corner])), + SkScalar(SkColorGetG(colorsPM[kBottomLeft_Corner])), + SkScalar(SkColorGetG(colorsPM[kBottomRight_Corner])))); uint8_t b = uint8_t(bilerp(u, v, - SkScalar(SkColorGetB(colorsPM[kTopLeft_Corner])), - SkScalar(SkColorGetB(colorsPM[kTopRight_Corner])), - SkScalar(SkColorGetB(colorsPM[kBottomLeft_Corner])), - SkScalar(SkColorGetB(colorsPM[kBottomRight_Corner])))); - data->fColors[dataIndex] = SkPackARGB32(a,r,g,b); + SkScalar(SkColorGetB(colorsPM[kTopLeft_Corner])), + SkScalar(SkColorGetB(colorsPM[kTopRight_Corner])), + SkScalar(SkColorGetB(colorsPM[kBottomLeft_Corner])), + SkScalar(SkColorGetB(colorsPM[kBottomRight_Corner])))); + colors[dataIndex] = SkPackARGB32(a,r,g,b); } - if (texCoords) { - data->fTexCoords[dataIndex] = SkPoint::Make( - bilerp(u, v, texCoords[kTopLeft_Corner].x(), - texCoords[kTopRight_Corner].x(), - texCoords[kBottomLeft_Corner].x(), - texCoords[kBottomRight_Corner].x()), - bilerp(u, v, texCoords[kTopLeft_Corner].y(), - texCoords[kTopRight_Corner].y(), - texCoords[kBottomLeft_Corner].y(), - texCoords[kBottomRight_Corner].y())); + if (texs) { + texs[dataIndex] = SkPoint::Make(bilerp(u, v, srcTexCoords[kTopLeft_Corner].x(), + srcTexCoords[kTopRight_Corner].x(), + srcTexCoords[kBottomLeft_Corner].x(), + srcTexCoords[kBottomRight_Corner].x()), + bilerp(u, v, srcTexCoords[kTopLeft_Corner].y(), + srcTexCoords[kTopRight_Corner].y(), + srcTexCoords[kBottomLeft_Corner].y(), + srcTexCoords[kBottomRight_Corner].y())); } if(x < lodX && y < lodY) { int i = 6 * (x * lodY + y); - data->fIndices[i] = x * stride + y; - data->fIndices[i + 1] = x * stride + 1 + y; - data->fIndices[i + 2] = (x + 1) * stride + 1 + y; - data->fIndices[i + 3] = data->fIndices[i]; - data->fIndices[i + 4] = data->fIndices[i + 2]; - data->fIndices[i + 5] = (x + 1) * stride + y; + indices[i] = x * stride + y; + indices[i + 1] = x * stride + 1 + y; + indices[i + 2] = (x + 1) * stride + 1 + y; + indices[i + 3] = indices[i]; + indices[i + 4] = indices[i + 2]; + indices[i + 5] = (x + 1) * stride + y; } v = SkScalarClampMax(v + 1.f / lodY, 1); } u = SkScalarClampMax(u + 1.f / lodX, 1); } - return true; - + return builder.detach(); } diff --git a/gfx/skia/skia/src/utils/SkPatchUtils.h b/gfx/skia/skia/src/utils/SkPatchUtils.h index 67ab621e8e9a..6d6e3491b6d9 100644 --- a/gfx/skia/skia/src/utils/SkPatchUtils.h +++ b/gfx/skia/skia/src/utils/SkPatchUtils.h @@ -10,112 +10,45 @@ #include "SkColorPriv.h" #include "SkMatrix.h" +#include "SkVertices.h" class SK_API SkPatchUtils { public: - /** - * Structure that holds the vertex data related to the tessellation of a patch. It is passed - * as a parameter to the function getVertexData which sets the points, colors and texture - * coordinates of the vertices and the indices for them to be drawn as triangles. - */ - struct VertexData { - int fVertexCount, fIndexCount; - SkPoint* fPoints; - SkPoint* fTexCoords; - uint32_t* fColors; - uint16_t* fIndices; - - VertexData() - : fVertexCount(0) - , fIndexCount(0) - , fPoints(nullptr) - , fTexCoords(nullptr) - , fColors(nullptr) - , fIndices(nullptr) { } - - ~VertexData() { - delete[] fPoints; - delete[] fTexCoords; - delete[] fColors; - delete[] fIndices; - } - }; - // Enums for control points based on the order specified in the constructor (clockwise). - enum CubicCtrlPts { - kTopP0_CubicCtrlPts = 0, - kTopP1_CubicCtrlPts = 1, - kTopP2_CubicCtrlPts = 2, - kTopP3_CubicCtrlPts = 3, - - kRightP0_CubicCtrlPts = 3, - kRightP1_CubicCtrlPts = 4, - kRightP2_CubicCtrlPts = 5, - kRightP3_CubicCtrlPts = 6, - - kBottomP0_CubicCtrlPts = 9, - kBottomP1_CubicCtrlPts = 8, - kBottomP2_CubicCtrlPts = 7, - kBottomP3_CubicCtrlPts = 6, - - kLeftP0_CubicCtrlPts = 0, - kLeftP1_CubicCtrlPts = 11, - kLeftP2_CubicCtrlPts = 10, - kLeftP3_CubicCtrlPts = 9, - }; - - // Enum for corner also clockwise. - enum Corner { - kTopLeft_Corner = 0, - kTopRight_Corner, - kBottomRight_Corner, - kBottomLeft_Corner - }; - enum { kNumCtrlPts = 12, kNumCorners = 4, kNumPtsCubic = 4 }; - /** - * Method that calculates a level of detail (number of subdivisions) for a patch in both axis. - */ - static SkISize GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* matrix); - /** * Get the points corresponding to the top cubic of cubics. */ - static void getTopCubic(const SkPoint cubics[12], SkPoint points[4]); + static void GetTopCubic(const SkPoint cubics[12], SkPoint points[4]); /** * Get the points corresponding to the bottom cubic of cubics. */ - static void getBottomCubic(const SkPoint cubics[12], SkPoint points[4]); + static void GetBottomCubic(const SkPoint cubics[12], SkPoint points[4]); /** * Get the points corresponding to the left cubic of cubics. */ - static void getLeftCubic(const SkPoint cubics[12], SkPoint points[4]); + static void GetLeftCubic(const SkPoint cubics[12], SkPoint points[4]); /** * Get the points corresponding to the right cubic of cubics. */ - static void getRightCubic(const SkPoint cubics[12], SkPoint points[4]); + static void GetRightCubic(const SkPoint cubics[12], SkPoint points[4]); /** - * Function that evaluates the coons patch interpolation. - * data refers to the pointer of the PatchData struct in which the tessellation data is set. - * cubics refers to the points of the cubics. - * lod refers the level of detail for each axis. - * colors refers to the corner colors that will be bilerp across the patch (optional parameter) - * texCoords refers to the corner texture coordinates that will be bilerp across the patch - (optional parameter) + * Method that calculates a level of detail (number of subdivisions) for a patch in both axis. */ - static bool getVertexData(SkPatchUtils::VertexData* data, const SkPoint cubics[12], - const SkColor colors[4], const SkPoint texCoords[4], - int lodX, int lodY); + static SkISize GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* matrix); + + static sk_sp MakeVertices(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], int lodX, int lodY); }; #endif diff --git a/gfx/skia/skia/src/utils/SkShadowPaintFilterCanvas.cpp b/gfx/skia/skia/src/utils/SkShadowPaintFilterCanvas.cpp index 289ae3cd0c1c..bf4a4242f23b 100644 --- a/gfx/skia/skia/src/utils/SkShadowPaintFilterCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkShadowPaintFilterCanvas.cpp @@ -56,7 +56,7 @@ SkISize SkShadowPaintFilterCanvas::ComputeDepthMapSize(const SkLights::Light& li // of the point light and the shapes, etc... If we take upper bounds // on those metrics, the shadow map will be pretty big in any case. // Thus, just using 4x the width and height seems to work for most scenes. - return SkISize::Make(width * 4, height * 4); + return {width * 4, height * 4}; } int dMapWidth = SkMin32(maxDepth * fabs(light.dir().fX) + width, diff --git a/gfx/skia/skia/src/utils/SkShadowTessellator.cpp b/gfx/skia/skia/src/utils/SkShadowTessellator.cpp new file mode 100755 index 000000000000..7d29b063a0b1 --- /dev/null +++ b/gfx/skia/skia/src/utils/SkShadowTessellator.cpp @@ -0,0 +1,1294 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkShadowTessellator.h" +#include "SkColorPriv.h" +#include "SkGeometry.h" +#include "SkInsetConvexPolygon.h" +#include "SkPath.h" +#include "SkVertices.h" + +#if SK_SUPPORT_GPU +#include "GrPathUtils.h" +#endif + + +/** + * Base class + */ +class SkBaseShadowTessellator { +public: + SkBaseShadowTessellator(SkShadowTessellator::HeightFunc, bool transparent); + virtual ~SkBaseShadowTessellator() {} + + sk_sp releaseVertices() { + if (!fSucceeded) { + return nullptr; + } + return SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, this->vertexCount(), + fPositions.begin(), nullptr, fColors.begin(), + this->indexCount(), fIndices.begin()); + } + +protected: + static constexpr auto kMinHeight = 0.1f; + + int vertexCount() const { return fPositions.count(); } + int indexCount() const { return fIndices.count(); } + + bool setZOffset(const SkRect& bounds, bool perspective); + + virtual void handleLine(const SkPoint& p) = 0; + void handleLine(const SkMatrix& m, SkPoint* p); + + void handleQuad(const SkPoint pts[3]); + void handleQuad(const SkMatrix& m, SkPoint pts[3]); + + void handleCubic(const SkMatrix& m, SkPoint pts[4]); + + void handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w); + + bool setTransformedHeightFunc(const SkMatrix& ctm); + + void addArc(const SkVector& nextNormal, bool finishArc); + + SkShadowTessellator::HeightFunc fHeightFunc; + std::function fTransformedHeightFunc; + SkScalar fZOffset; + // members for perspective height function + SkScalar fZParams[3]; + SkScalar fPartialDeterminants[3]; + + // first two points + SkTDArray fInitPoints; + // temporary buffer + SkTDArray fPointBuffer; + + SkTDArray fPositions; + SkTDArray fColors; + SkTDArray fIndices; + + int fFirstVertex; + SkVector fFirstNormal; + SkPoint fFirstPoint; + + bool fSucceeded; + bool fTransparent; + + SkColor fUmbraColor; + SkColor fPenumbraColor; + + SkScalar fRadius; + SkScalar fDirection; + int fPrevUmbraIndex; + SkVector fPrevNormal; + SkPoint fPrevPoint; +}; + +static bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar dir, + SkVector* newNormal) { + SkVector normal; + // compute perpendicular + normal.fX = p0.fY - p1.fY; + normal.fY = p1.fX - p0.fX; + normal *= dir; + if (!normal.normalize()) { + return false; + } + *newNormal = normal; + return true; +} + +static void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScalar r, + SkScalar* rotSin, SkScalar* rotCos, int* n) { + const SkScalar kRecipPixelsPerArcSegment = 0.25f; + + SkScalar rCos = v1.dot(v2); + SkScalar rSin = v1.cross(v2); + SkScalar theta = SkScalarATan2(rSin, rCos); + + SkScalar steps = r*theta*kRecipPixelsPerArcSegment; + + SkScalar dTheta = theta / steps; + *rotSin = SkScalarSinCos(dTheta, rotCos); + *n = SkScalarFloorToInt(steps); +} + +SkBaseShadowTessellator::SkBaseShadowTessellator(SkShadowTessellator::HeightFunc heightFunc, + bool transparent) + : fHeightFunc(heightFunc) + , fZOffset(0) + , fFirstVertex(-1) + , fSucceeded(false) + , fTransparent(transparent) + , fDirection(1) + , fPrevUmbraIndex(-1) { + fInitPoints.setReserve(3); + + // child classes will set reserve for positions, colors and indices +} + +bool SkBaseShadowTessellator::setZOffset(const SkRect& bounds, bool perspective) { + SkScalar minZ = fHeightFunc(bounds.fLeft, bounds.fTop); + if (perspective) { + SkScalar z = fHeightFunc(bounds.fLeft, bounds.fBottom); + if (z < minZ) { + minZ = z; + } + z = fHeightFunc(bounds.fRight, bounds.fTop); + if (z < minZ) { + minZ = z; + } + z = fHeightFunc(bounds.fRight, bounds.fBottom); + if (z < minZ) { + minZ = z; + } + } + + if (minZ < kMinHeight) { + fZOffset = -minZ + kMinHeight; + return true; + } + + return false; +} + +// tesselation tolerance values, in device space pixels +#if SK_SUPPORT_GPU +static const SkScalar kQuadTolerance = 0.2f; +static const SkScalar kCubicTolerance = 0.2f; +#endif +static const SkScalar kConicTolerance = 0.5f; + +void SkBaseShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) { + m.mapPoints(p, 1); + this->handleLine(*p); +} + +void SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) { +#if SK_SUPPORT_GPU + // TODO: Pull PathUtils out of Ganesh? + int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); + fPointBuffer.setReserve(maxCount); + SkPoint* target = fPointBuffer.begin(); + int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], + kQuadTolerance, &target, maxCount); + fPointBuffer.setCount(count); + for (int i = 0; i < count; i++) { + this->handleLine(fPointBuffer[i]); + } +#else + // for now, just to draw something + this->handleLine(pts[1]); + this->handleLine(pts[2]); +#endif +} + +void SkBaseShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) { + m.mapPoints(pts, 3); + this->handleQuad(pts); +} + +void SkBaseShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) { + m.mapPoints(pts, 4); +#if SK_SUPPORT_GPU + // TODO: Pull PathUtils out of Ganesh? + int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance); + fPointBuffer.setReserve(maxCount); + SkPoint* target = fPointBuffer.begin(); + int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], + kCubicTolerance, &target, maxCount); + fPointBuffer.setCount(count); + for (int i = 0; i < count; i++) { + this->handleLine(fPointBuffer[i]); + } +#else + // for now, just to draw something + this->handleLine(pts[1]); + this->handleLine(pts[2]); + this->handleLine(pts[3]); +#endif +} + +void SkBaseShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) { + if (m.hasPerspective()) { + w = SkConic::TransformW(pts, w, m); + } + m.mapPoints(pts, 3); + SkAutoConicToQuads quadder; + const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance); + SkPoint lastPoint = *(quads++); + int count = quadder.countQuads(); + for (int i = 0; i < count; ++i) { + SkPoint quadPts[3]; + quadPts[0] = lastPoint; + quadPts[1] = quads[0]; + quadPts[2] = i == count - 1 ? pts[2] : quads[1]; + this->handleQuad(quadPts); + lastPoint = quadPts[2]; + quads += 2; + } +} + +void SkBaseShadowTessellator::addArc(const SkVector& nextNormal, bool finishArc) { + // fill in fan from previous quad + SkScalar rotSin, rotCos; + int numSteps; + compute_radial_steps(fPrevNormal, nextNormal, fRadius, &rotSin, &rotCos, &numSteps); + SkVector prevNormal = fPrevNormal; + for (int i = 0; i < numSteps; ++i) { + SkVector currNormal; + currNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin; + currNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin; + *fPositions.push() = fPrevPoint + currNormal; + *fColors.push() = fPenumbraColor; + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 2; + *fIndices.push() = fPositions.count() - 1; + + prevNormal = currNormal; + } + if (finishArc) { + *fPositions.push() = fPrevPoint + nextNormal; + *fColors.push() = fPenumbraColor; + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 2; + *fIndices.push() = fPositions.count() - 1; + } + fPrevNormal = nextNormal; +} + +bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) { + if (!ctm.hasPerspective()) { + fTransformedHeightFunc = [this](const SkPoint& p) { + return this->fHeightFunc(0, 0); + }; + } else { + SkMatrix ctmInverse; + if (!ctm.invert(&ctmInverse)) { + return false; + } + SkScalar C = fHeightFunc(0, 0); + SkScalar A = fHeightFunc(1, 0) - C; + SkScalar B = fHeightFunc(0, 1) - C; + + // multiply by transpose + fZParams[0] = ctmInverse[SkMatrix::kMScaleX] * A + + ctmInverse[SkMatrix::kMSkewY] * B + + ctmInverse[SkMatrix::kMPersp0] * C; + fZParams[1] = ctmInverse[SkMatrix::kMSkewX] * A + + ctmInverse[SkMatrix::kMScaleY] * B + + ctmInverse[SkMatrix::kMPersp1] * C; + fZParams[2] = ctmInverse[SkMatrix::kMTransX] * A + + ctmInverse[SkMatrix::kMTransY] * B + + ctmInverse[SkMatrix::kMPersp2] * C; + + // We use Cramer's rule to solve for the W value for a given post-divide X and Y, + // so pre-compute those values that are independent of X and Y. + // W is det(ctmInverse)/(PD[0]*X + PD[1]*Y + PD[2]) + fPartialDeterminants[0] = ctm[SkMatrix::kMSkewY] * ctm[SkMatrix::kMPersp1] - + ctm[SkMatrix::kMScaleY] * ctm[SkMatrix::kMPersp0]; + fPartialDeterminants[1] = ctm[SkMatrix::kMPersp0] * ctm[SkMatrix::kMSkewX] - + ctm[SkMatrix::kMPersp1] * ctm[SkMatrix::kMScaleX]; + fPartialDeterminants[2] = ctm[SkMatrix::kMScaleX] * ctm[SkMatrix::kMScaleY] - + ctm[SkMatrix::kMSkewX] * ctm[SkMatrix::kMSkewY]; + SkScalar ctmDeterminant = ctm[SkMatrix::kMTransX] * fPartialDeterminants[0] + + ctm[SkMatrix::kMTransY] * fPartialDeterminants[1] + + ctm[SkMatrix::kMPersp2] * fPartialDeterminants[2]; + + // Pre-bake the numerator of Cramer's rule into the zParams to avoid another multiply. + // TODO: this may introduce numerical instability, but I haven't seen any issues yet. + fZParams[0] *= ctmDeterminant; + fZParams[1] *= ctmDeterminant; + fZParams[2] *= ctmDeterminant; + + fTransformedHeightFunc = [this](const SkPoint& p) { + SkScalar denom = p.fX * this->fPartialDeterminants[0] + + p.fY * this->fPartialDeterminants[1] + + this->fPartialDeterminants[2]; + SkScalar w = SkScalarFastInvert(denom); + return (this->fZParams[0] * p.fX + this->fZParams[1] * p.fY + this->fZParams[2])*w + + this->fZOffset; + }; + } + + return true; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////// + +class SkAmbientShadowTessellator : public SkBaseShadowTessellator { +public: + SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm, + SkShadowTessellator::HeightFunc heightFunc, + SkScalar ambientAlpha, bool transparent); + +private: + void handleLine(const SkPoint& p) override; + void addEdge(const SkVector& nextPoint, const SkVector& nextNormal); + + static constexpr auto kHeightFactor = 1.0f / 128.0f; + static constexpr auto kGeomFactor = 64.0f; + static constexpr auto kMaxEdgeLenSqr = 20 * 20; + + SkScalar offset(SkScalar z) { + return z * kHeightFactor * kGeomFactor; + } + SkColor umbraColor(SkScalar z) { + SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(z*kHeightFactor, 0.0f))); + return SkColorSetARGB(255, 0, fAmbientAlpha * 255.9999f, umbraAlpha * 255.9999f); + } + + SkScalar fAmbientAlpha; + int fCentroidCount; + + typedef SkBaseShadowTessellator INHERITED; +}; + +SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path, + const SkMatrix& ctm, + SkShadowTessellator::HeightFunc heightFunc, + SkScalar ambientAlpha, + bool transparent) + : INHERITED(heightFunc, transparent) + , fAmbientAlpha(ambientAlpha) { + // Set base colors + SkScalar occluderHeight = heightFunc(0, 0); + SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(occluderHeight*kHeightFactor, 0.0f))); + // umbraColor is the interior value, penumbraColor the exterior value. + // umbraAlpha is the factor that is linearly interpolated from outside to inside, and + // then "blurred" by the GrBlurredEdgeFP. It is then multiplied by fAmbientAlpha to get + // the final alpha. + fUmbraColor = SkColorSetARGB(255, 0, ambientAlpha * 255.9999f, umbraAlpha * 255.9999f); + fPenumbraColor = SkColorSetARGB(255, 0, ambientAlpha * 255.9999f, 0); + + // make sure we're not below the canvas plane + this->setZOffset(path.getBounds(), ctm.hasPerspective()); + + this->setTransformedHeightFunc(ctm); + + // Outer ring: 3*numPts + // Middle ring: numPts + fPositions.setReserve(4 * path.countPoints()); + fColors.setReserve(4 * path.countPoints()); + // Outer ring: 12*numPts + // Middle ring: 0 + fIndices.setReserve(12 * path.countPoints()); + + // walk around the path, tessellate and generate outer ring + // if original path is transparent, will accumulate sum of points for centroid + SkPath::Iter iter(path, true); + SkPoint pts[4]; + SkPath::Verb verb; + if (fTransparent) { + *fPositions.push() = SkPoint::Make(0, 0); + *fColors.push() = fUmbraColor; + fCentroidCount = 0; + } + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { + switch (verb) { + case SkPath::kLine_Verb: + this->INHERITED::handleLine(ctm, &pts[1]); + break; + case SkPath::kQuad_Verb: + this->handleQuad(ctm, pts); + break; + case SkPath::kCubic_Verb: + this->handleCubic(ctm, pts); + break; + case SkPath::kConic_Verb: + this->handleConic(ctm, pts, iter.conicWeight()); + break; + case SkPath::kMove_Verb: + case SkPath::kClose_Verb: + case SkPath::kDone_Verb: + break; + } + } + + if (!this->indexCount()) { + return; + } + + SkVector normal; + if (compute_normal(fPrevPoint, fFirstPoint, fDirection, &normal)) { + SkScalar z = fTransformedHeightFunc(fPrevPoint); + fRadius = this->offset(z); + SkVector scaledNormal(normal); + scaledNormal *= fRadius; + this->addArc(scaledNormal, true); + + // set up for final edge + z = fTransformedHeightFunc(fFirstPoint); + normal *= this->offset(z); + + // make sure we don't end up with a sharp alpha edge along the quad diagonal + if (fColors[fPrevUmbraIndex] != fColors[fFirstVertex] && + fFirstPoint.distanceToSqd(fPositions[fPrevUmbraIndex]) > kMaxEdgeLenSqr) { + SkPoint centerPoint = fPositions[fPrevUmbraIndex] + fFirstPoint; + centerPoint *= 0.5f; + *fPositions.push() = centerPoint; + *fColors.push() = SkPMLerp(fColors[fFirstVertex], fColors[fPrevUmbraIndex], 128); + SkVector midNormal = fPrevNormal + normal; + midNormal *= 0.5f; + *fPositions.push() = centerPoint + midNormal; + *fColors.push() = fPenumbraColor; + + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 3; + *fIndices.push() = fPositions.count() - 2; + + *fIndices.push() = fPositions.count() - 3; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = fPositions.count() - 2; + + fPrevUmbraIndex = fPositions.count() - 2; + } + + // final edge + *fPositions.push() = fFirstPoint + normal; + *fColors.push() = fPenumbraColor; + + if (fColors[fPrevUmbraIndex] > fColors[fFirstVertex]) { + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 2; + *fIndices.push() = fFirstVertex; + + *fIndices.push() = fPositions.count() - 2; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = fFirstVertex; + } else { + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 2; + *fIndices.push() = fPositions.count() - 1; + + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = fFirstVertex; + } + fPrevNormal = normal; + } + + // finalize centroid + if (fTransparent) { + fPositions[0] *= SkScalarFastInvert(fCentroidCount); + + *fIndices.push() = 0; + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fFirstVertex; + } + + // final fan + if (fPositions.count() >= 3) { + fPrevUmbraIndex = fFirstVertex; + fPrevPoint = fFirstPoint; + fRadius = this->offset(fTransformedHeightFunc(fPrevPoint)); + this->addArc(fFirstNormal, false); + + *fIndices.push() = fFirstVertex; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = fFirstVertex + 1; + } + fSucceeded = true; +} + +void SkAmbientShadowTessellator::handleLine(const SkPoint& p) { + if (fInitPoints.count() < 2) { + *fInitPoints.push() = p; + return; + } + + if (fInitPoints.count() == 2) { + // determine if cw or ccw + SkVector v0 = fInitPoints[1] - fInitPoints[0]; + SkVector v1 = p - fInitPoints[0]; + SkScalar perpDot = v0.fX*v1.fY - v0.fY*v1.fX; + if (SkScalarNearlyZero(perpDot)) { + // nearly parallel, just treat as straight line and continue + fInitPoints[1] = p; + return; + } + + // if perpDot > 0, winding is ccw + fDirection = (perpDot > 0) ? -1 : 1; + + // add first quad + SkVector normal; + if (!compute_normal(fInitPoints[0], fInitPoints[1], fDirection, &normal)) { + // first two points are incident, make the third point the second and continue + fInitPoints[1] = p; + return; + } + + fFirstPoint = fInitPoints[0]; + fFirstVertex = fPositions.count(); + SkScalar z = fTransformedHeightFunc(fFirstPoint); + fFirstNormal = normal; + fFirstNormal *= this->offset(z); + + fPrevNormal = fFirstNormal; + fPrevPoint = fFirstPoint; + fPrevUmbraIndex = fFirstVertex; + + *fPositions.push() = fFirstPoint; + *fColors.push() = this->umbraColor(z); + *fPositions.push() = fFirstPoint + fFirstNormal; + *fColors.push() = fPenumbraColor; + if (fTransparent) { + fPositions[0] += fFirstPoint; + fCentroidCount = 1; + } + + // add the first quad + z = fTransformedHeightFunc(fInitPoints[1]); + fRadius = this->offset(z); + fUmbraColor = this->umbraColor(z); + normal *= fRadius; + this->addEdge(fInitPoints[1], normal); + + // to ensure we skip this block next time + *fInitPoints.push() = p; + } + + SkVector normal; + if (compute_normal(fPositions[fPrevUmbraIndex], p, fDirection, &normal)) { + SkVector scaledNormal = normal; + scaledNormal *= fRadius; + this->addArc(scaledNormal, true); + SkScalar z = fTransformedHeightFunc(p); + fRadius = this->offset(z); + fUmbraColor = this->umbraColor(z); + normal *= fRadius; + this->addEdge(p, normal); + } +} + +void SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) { + // make sure we don't end up with a sharp alpha edge along the quad diagonal + if (fColors[fPrevUmbraIndex] != fUmbraColor && + nextPoint.distanceToSqd(fPositions[fPrevUmbraIndex]) > kMaxEdgeLenSqr) { + SkPoint centerPoint = fPositions[fPrevUmbraIndex] + nextPoint; + centerPoint *= 0.5f; + *fPositions.push() = centerPoint; + *fColors.push() = SkPMLerp(fUmbraColor, fColors[fPrevUmbraIndex], 128); + SkVector midNormal = fPrevNormal + nextNormal; + midNormal *= 0.5f; + *fPositions.push() = centerPoint + midNormal; + *fColors.push() = fPenumbraColor; + + // set triangularization to get best interpolation of color + if (fColors[fPrevUmbraIndex] > fColors[fPositions.count() - 2]) { + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 3; + *fIndices.push() = fPositions.count() - 2; + + *fIndices.push() = fPositions.count() - 3; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = fPositions.count() - 2; + } else { + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 2; + *fIndices.push() = fPositions.count() - 1; + + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = fPositions.count() - 3; + } + + fPrevUmbraIndex = fPositions.count() - 2; + } + + // add next quad + *fPositions.push() = nextPoint; + *fColors.push() = fUmbraColor; + *fPositions.push() = nextPoint + nextNormal; + *fColors.push() = fPenumbraColor; + + // set triangularization to get best interpolation of color + if (fColors[fPrevUmbraIndex] > fColors[fPositions.count() - 2]) { + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 3; + *fIndices.push() = fPositions.count() - 2; + + *fIndices.push() = fPositions.count() - 3; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = fPositions.count() - 2; + } else { + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 2; + *fIndices.push() = fPositions.count() - 1; + + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = fPositions.count() - 3; + } + + // if transparent, add point to first one in array and add to center fan + if (fTransparent) { + fPositions[0] += nextPoint; + ++fCentroidCount; + + *fIndices.push() = 0; + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 2; + } + + fPrevUmbraIndex = fPositions.count() - 2; + fPrevNormal = nextNormal; + fPrevPoint = nextPoint; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class SkSpotShadowTessellator : public SkBaseShadowTessellator { +public: + SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm, + SkShadowTessellator::HeightFunc heightFunc, + const SkPoint3& lightPos, SkScalar lightRadius, + SkScalar spotAlpha, bool transparent); + +private: + void computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm, + const SkMatrix& shadowTransform); + void computeClipVectorsAndTestCentroid(); + bool clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, SkPoint* clipPoint); + int getClosestUmbraPoint(const SkPoint& point); + + void handleLine(const SkPoint& p) override; + void handlePolyPoint(const SkPoint& p); + + void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count); + bool addInnerPoint(const SkPoint& pathPoint); + void addEdge(const SkVector& nextPoint, const SkVector& nextNormal); + + SkScalar offset(SkScalar z) { + float zRatio = SkTPin(z / (fLightZ - z), 0.0f, 0.95f); + return fLightRadius*zRatio; + } + + SkScalar fLightZ; + SkScalar fLightRadius; + SkScalar fOffsetAdjust; + + SkTDArray fClipPolygon; + SkTDArray fClipVectors; + SkPoint fCentroid; + SkScalar fArea; + + SkTDArray fPathPolygon; + SkTDArray fUmbraPolygon; + int fCurrClipPoint; + int fCurrUmbraPoint; + bool fPrevUmbraOutside; + bool fFirstUmbraOutside; + bool fValidUmbra; + + typedef SkBaseShadowTessellator INHERITED; +}; + +SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm, + SkShadowTessellator::HeightFunc heightFunc, + const SkPoint3& lightPos, SkScalar lightRadius, + SkScalar spotAlpha, bool transparent) + : INHERITED(heightFunc, transparent) + , fLightZ(lightPos.fZ) + , fLightRadius(lightRadius) + , fOffsetAdjust(0) + , fCurrClipPoint(0) + , fPrevUmbraOutside(false) + , fFirstUmbraOutside(false) + , fValidUmbra(true) { + + // make sure we're not below the canvas plane + if (this->setZOffset(path.getBounds(), ctm.hasPerspective())) { + // Adjust light height and radius + fLightRadius *= (fLightZ + fZOffset) / fLightZ; + fLightZ += fZOffset; + } + + // Set radius and colors + SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY()); + SkScalar occluderHeight = heightFunc(center.fX, center.fY) + fZOffset; + float zRatio = SkTPin(occluderHeight / (fLightZ - occluderHeight), 0.0f, 0.95f); + SkScalar radius = lightRadius * zRatio; + fRadius = radius; + fUmbraColor = SkColorSetARGB(255, 0, spotAlpha * 255.9999f, 255); + fPenumbraColor = SkColorSetARGB(255, 0, spotAlpha * 255.9999f, 0); + + // Compute the scale and translation for the spot shadow. + SkMatrix shadowTransform; + if (!ctm.hasPerspective()) { + SkScalar scale = fLightZ / (fLightZ - occluderHeight); + SkVector translate = SkVector::Make(-zRatio * lightPos.fX, -zRatio * lightPos.fY); + shadowTransform.setScaleTranslate(scale, scale, translate.fX, translate.fY); + } else { + // For perspective, we have a scale, a z-shear, and another projective divide -- + // this varies at each point so we can't use an affine transform. + // We'll just apply this to each generated point in turn. + shadowTransform.reset(); + // Also can't cull the center (for now). + fTransparent = true; + } + SkMatrix fullTransform = SkMatrix::Concat(shadowTransform, ctm); + + // Set up our reverse mapping + this->setTransformedHeightFunc(fullTransform); + + // TODO: calculate these reserves better + // Penumbra ring: 3*numPts + // Umbra ring: numPts + // Inner ring: numPts + fPositions.setReserve(5 * path.countPoints()); + fColors.setReserve(5 * path.countPoints()); + // Penumbra ring: 12*numPts + // Umbra ring: 3*numPts + fIndices.setReserve(15 * path.countPoints()); + fClipPolygon.setReserve(path.countPoints()); + + // compute rough clip bounds for umbra, plus offset polygon, plus centroid + this->computeClipAndPathPolygons(path, ctm, shadowTransform); + if (fClipPolygon.count() < 3 || fPathPolygon.count() < 3) { + return; + } + + // check to see if umbra collapses + SkScalar minDistSq = fCentroid.distanceToLineSegmentBetweenSqd(fPathPolygon[0], + fPathPolygon[1]); + SkRect bounds; + bounds.setBounds(&fPathPolygon[0], fPathPolygon.count()); + for (int i = 1; i < fPathPolygon.count(); ++i) { + int j = i + 1; + if (i == fPathPolygon.count() - 1) { + j = 0; + } + SkPoint currPoint = fPathPolygon[i]; + SkPoint nextPoint = fPathPolygon[j]; + SkScalar distSq = fCentroid.distanceToLineSegmentBetweenSqd(currPoint, nextPoint); + if (distSq < minDistSq) { + minDistSq = distSq; + } + } + static constexpr auto kTolerance = 1.0e-2f; + if (minDistSq < (radius + kTolerance)*(radius + kTolerance)) { + // if the umbra would collapse, we back off a bit on inner blur and adjust the alpha + SkScalar newRadius = SkScalarSqrt(minDistSq) - kTolerance; + fOffsetAdjust = newRadius - radius; + SkScalar ratio = 256 * newRadius / radius; + // they aren't PMColors, but the interpolation algorithm is the same + fUmbraColor = SkPMLerp(fUmbraColor, fPenumbraColor, (unsigned)ratio); + radius = newRadius; + } + + // compute vectors for clip tests + this->computeClipVectorsAndTestCentroid(); + + // generate inner ring + if (!SkInsetConvexPolygon(&fPathPolygon[0], fPathPolygon.count(), radius, + &fUmbraPolygon)) { + // this shouldn't happen, but just in case we'll inset using the centroid + fValidUmbra = false; + } + + // walk around the path polygon, generate outer ring and connect to inner ring + if (fTransparent) { + *fPositions.push() = fCentroid; + *fColors.push() = fUmbraColor; + } + fCurrUmbraPoint = 0; + for (int i = 0; i < fPathPolygon.count(); ++i) { + this->handlePolyPoint(fPathPolygon[i]); + } + + if (!this->indexCount()) { + return; + } + + // finish up the final verts + SkVector normal; + if (compute_normal(fPrevPoint, fFirstPoint, fDirection, &normal)) { + normal *= fRadius; + this->addArc(normal, true); + + // add to center fan + if (fTransparent) { + *fIndices.push() = 0; + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fFirstVertex; + // or to clip ring + } else { + if (fFirstUmbraOutside) { + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fFirstVertex; + *fIndices.push() = fFirstVertex + 1; + if (fPrevUmbraOutside) { + // fill out quad + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fFirstVertex + 1; + *fIndices.push() = fPrevUmbraIndex + 1; + } + } else if (fPrevUmbraOutside) { + // add tri + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fFirstVertex; + *fIndices.push() = fPrevUmbraIndex + 1; + } + } + + // add final edge + *fPositions.push() = fFirstPoint + normal; + *fColors.push() = fPenumbraColor; + + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = fPositions.count() - 2; + *fIndices.push() = fFirstVertex; + + *fIndices.push() = fPositions.count() - 2; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = fFirstVertex; + + fPrevNormal = normal; + } + + // final fan + if (fPositions.count() >= 3) { + fPrevUmbraIndex = fFirstVertex; + fPrevPoint = fFirstPoint; + this->addArc(fFirstNormal, false); + + *fIndices.push() = fFirstVertex; + *fIndices.push() = fPositions.count() - 1; + if (fFirstUmbraOutside) { + *fIndices.push() = fFirstVertex + 2; + } else { + *fIndices.push() = fFirstVertex + 1; + } + } + + if (ctm.hasPerspective()) { + for (int i = 0; i < fPositions.count(); ++i) { + SkScalar pathZ = fTransformedHeightFunc(fPositions[i]); + SkScalar factor = SkScalarInvert(fLightZ - pathZ); + fPositions[i].fX = (fPositions[i].fX*fLightZ - lightPos.fX*pathZ)*factor; + fPositions[i].fY = (fPositions[i].fY*fLightZ - lightPos.fY*pathZ)*factor; + } +#ifdef DRAW_CENTROID + SkScalar pathZ = fTransformedHeightFunc(fCentroid); + SkScalar factor = SkScalarInvert(fLightZ - pathZ); + fCentroid.fX = (fCentroid.fX*fLightZ - lightPos.fX*pathZ)*factor; + fCentroid.fY = (fCentroid.fY*fLightZ - lightPos.fY*pathZ)*factor; +#endif + } +#ifdef DRAW_CENTROID + *fPositions.push() = fCentroid + SkVector::Make(-2, -2); + *fColors.push() = SkColorSetARGB(255, 0, 255, 255); + *fPositions.push() = fCentroid + SkVector::Make(2, -2); + *fColors.push() = SkColorSetARGB(255, 0, 255, 255); + *fPositions.push() = fCentroid + SkVector::Make(-2, 2); + *fColors.push() = SkColorSetARGB(255, 0, 255, 255); + *fPositions.push() = fCentroid + SkVector::Make(2, 2); + *fColors.push() = SkColorSetARGB(255, 0, 255, 255); + + *fIndices.push() = fPositions.count() - 4; + *fIndices.push() = fPositions.count() - 2; + *fIndices.push() = fPositions.count() - 1; + + *fIndices.push() = fPositions.count() - 4; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = fPositions.count() - 3; +#endif + + fSucceeded = true; +} + +void SkSpotShadowTessellator::computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm, + const SkMatrix& shadowTransform) { + + fPathPolygon.setReserve(path.countPoints()); + + // Walk around the path and compute clip polygon and path polygon. + // Will also accumulate sum of areas for centroid. + // For Bezier curves, we compute additional interior points on curve. + SkPath::Iter iter(path, true); + SkPoint pts[4]; + SkPath::Verb verb; + + fClipPolygon.reset(); + + // init centroid + fCentroid = SkPoint::Make(0, 0); + fArea = 0; + + // coefficients to compute cubic Bezier at t = 5/16 + static constexpr SkScalar kA = 0.32495117187f; + static constexpr SkScalar kB = 0.44311523437f; + static constexpr SkScalar kC = 0.20141601562f; + static constexpr SkScalar kD = 0.03051757812f; + + SkPoint curvePoint; + SkScalar w; + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { + switch (verb) { + case SkPath::kLine_Verb: + ctm.mapPoints(&pts[1], 1); + *fClipPolygon.push() = pts[1]; + this->INHERITED::handleLine(shadowTransform, &pts[1]); + break; + case SkPath::kQuad_Verb: + ctm.mapPoints(pts, 3); + // point at t = 1/2 + curvePoint.fX = 0.25f*pts[0].fX + 0.5f*pts[1].fX + 0.25f*pts[2].fX; + curvePoint.fY = 0.25f*pts[0].fY + 0.5f*pts[1].fY + 0.25f*pts[2].fY; + *fClipPolygon.push() = curvePoint; + *fClipPolygon.push() = pts[2]; + this->handleQuad(shadowTransform, pts); + break; + case SkPath::kConic_Verb: + ctm.mapPoints(pts, 3); + w = iter.conicWeight(); + // point at t = 1/2 + curvePoint.fX = 0.25f*pts[0].fX + w*0.5f*pts[1].fX + 0.25f*pts[2].fX; + curvePoint.fY = 0.25f*pts[0].fY + w*0.5f*pts[1].fY + 0.25f*pts[2].fY; + curvePoint *= SkScalarInvert(0.5f + 0.5f*w); + *fClipPolygon.push() = curvePoint; + *fClipPolygon.push() = pts[2]; + this->handleConic(shadowTransform, pts, w); + break; + case SkPath::kCubic_Verb: + ctm.mapPoints(pts, 4); + // point at t = 5/16 + curvePoint.fX = kA*pts[0].fX + kB*pts[1].fX + kC*pts[2].fX + kD*pts[3].fX; + curvePoint.fY = kA*pts[0].fY + kB*pts[1].fY + kC*pts[2].fY + kD*pts[3].fY; + *fClipPolygon.push() = curvePoint; + // point at t = 11/16 + curvePoint.fX = kD*pts[0].fX + kC*pts[1].fX + kB*pts[2].fX + kA*pts[3].fX; + curvePoint.fY = kD*pts[0].fY + kC*pts[1].fY + kB*pts[2].fY + kA*pts[3].fY; + *fClipPolygon.push() = curvePoint; + *fClipPolygon.push() = pts[3]; + this->handleCubic(shadowTransform, pts); + break; + case SkPath::kMove_Verb: + case SkPath::kClose_Verb: + case SkPath::kDone_Verb: + break; + default: + SkDEBUGFAIL("unknown verb"); + } + } + + // finish centroid + if (fPathPolygon.count() > 0) { + SkPoint currPoint = fPathPolygon[fPathPolygon.count() - 1]; + SkPoint nextPoint = fPathPolygon[0]; + SkScalar quadArea = currPoint.cross(nextPoint); + fCentroid.fX += (currPoint.fX + nextPoint.fX) * quadArea; + fCentroid.fY += (currPoint.fY + nextPoint.fY) * quadArea; + fArea += quadArea; + fCentroid *= SK_Scalar1 / (3 * fArea); + } + + fCurrClipPoint = fClipPolygon.count() - 1; +} + +void SkSpotShadowTessellator::computeClipVectorsAndTestCentroid() { + SkASSERT(fClipPolygon.count() >= 3); + + // init clip vectors + SkVector v0 = fClipPolygon[1] - fClipPolygon[0]; + *fClipVectors.push() = v0; + + // init centroid check + bool hiddenCentroid = true; + SkVector v1 = fCentroid - fClipPolygon[0]; + SkScalar initCross = v0.cross(v1); + + for (int p = 1; p < fClipPolygon.count(); ++p) { + // add to clip vectors + v0 = fClipPolygon[(p + 1) % fClipPolygon.count()] - fClipPolygon[p]; + *fClipVectors.push() = v0; + // Determine if transformed centroid is inside clipPolygon. + v1 = fCentroid - fClipPolygon[p]; + if (initCross*v0.cross(v1) <= 0) { + hiddenCentroid = false; + } + } + SkASSERT(fClipVectors.count() == fClipPolygon.count()); + + fTransparent = fTransparent || !hiddenCentroid; +} + +bool SkSpotShadowTessellator::clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, + SkPoint* clipPoint) { + SkVector segmentVector = centroid - umbraPoint; + + int startClipPoint = fCurrClipPoint; + do { + SkVector dp = umbraPoint - fClipPolygon[fCurrClipPoint]; + SkScalar denom = fClipVectors[fCurrClipPoint].cross(segmentVector); + SkScalar t_num = dp.cross(segmentVector); + // if line segments are nearly parallel + if (SkScalarNearlyZero(denom)) { + // and collinear + if (SkScalarNearlyZero(t_num)) { + return false; + } + // otherwise are separate, will try the next poly segment + // else if crossing lies within poly segment + } else if (t_num >= 0 && t_num <= denom) { + SkScalar s_num = dp.cross(fClipVectors[fCurrClipPoint]); + // if umbra point is inside the clip polygon + if (s_num >= 0 && s_num <= denom) { + segmentVector *= s_num/denom; + *clipPoint = umbraPoint + segmentVector; + return true; + } + } + fCurrClipPoint = (fCurrClipPoint + 1) % fClipPolygon.count(); + } while (fCurrClipPoint != startClipPoint); + + return false; +} + +int SkSpotShadowTessellator::getClosestUmbraPoint(const SkPoint& p) { + SkScalar minDistance = p.distanceToSqd(fUmbraPolygon[fCurrUmbraPoint]); + int index = fCurrUmbraPoint; + int dir = 1; + int next = (index + dir) % fUmbraPolygon.count(); + + // init travel direction + SkScalar distance = p.distanceToSqd(fUmbraPolygon[next]); + if (distance < minDistance) { + index = next; + minDistance = distance; + } else { + dir = fUmbraPolygon.count()-1; + } + + // iterate until we find a point that increases the distance + next = (index + dir) % fUmbraPolygon.count(); + distance = p.distanceToSqd(fUmbraPolygon[next]); + while (distance < minDistance) { + index = next; + minDistance = distance; + next = (index + dir) % fUmbraPolygon.count(); + distance = p.distanceToSqd(fUmbraPolygon[next]); + } + + fCurrUmbraPoint = index; + return index; +} + +void SkSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate, + SkPoint* pts, int count) { + // TODO: vectorize + for (int i = 0; i < count; ++i) { + pts[i] *= scale; + pts[i] += xlate; + } +} + +static bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) { + static constexpr SkScalar kClose = (SK_Scalar1 / 16); + static constexpr SkScalar kCloseSqd = kClose*kClose; + + SkScalar distSq = p0.distanceToSqd(p1); + return distSq < kCloseSqd; +} + +static bool is_collinear(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) { + SkVector v0 = p1 - p0; + SkVector v1 = p2 - p0; + return (SkScalarNearlyZero(v0.cross(v1))); +} + +void SkSpotShadowTessellator::handleLine(const SkPoint& p) { + // remove coincident points and add to centroid + if (fPathPolygon.count() > 0) { + const SkPoint& lastPoint = fPathPolygon[fPathPolygon.count() - 1]; + if (duplicate_pt(p, lastPoint)) { + return; + } + SkScalar quadArea = lastPoint.cross(p); + fCentroid.fX += (p.fX + lastPoint.fX) * quadArea; + fCentroid.fY += (p.fY + lastPoint.fY) * quadArea; + fArea += quadArea; + } + + // try to remove collinear points + if (fPathPolygon.count() > 1 && is_collinear(fPathPolygon[fPathPolygon.count()-2], + fPathPolygon[fPathPolygon.count()-1], + p)) { + fPathPolygon[fPathPolygon.count() - 1] = p; + } else { + *fPathPolygon.push() = p; + } +} + +void SkSpotShadowTessellator::handlePolyPoint(const SkPoint& p) { + if (fInitPoints.count() < 2) { + *fInitPoints.push() = p; + return; + } + + if (fInitPoints.count() == 2) { + // determine if cw or ccw + SkVector v0 = fInitPoints[1] - fInitPoints[0]; + SkVector v1 = p - fInitPoints[0]; + SkScalar perpDot = v0.cross(v1); + if (SkScalarNearlyZero(perpDot)) { + // nearly parallel, just treat as straight line and continue + fInitPoints[1] = p; + return; + } + + // if perpDot > 0, winding is ccw + fDirection = (perpDot > 0) ? -1 : 1; + + // add first quad + if (!compute_normal(fInitPoints[0], fInitPoints[1], fDirection, &fFirstNormal)) { + // first two points are incident, make the third point the second and continue + fInitPoints[1] = p; + return; + } + + fFirstNormal *= fRadius; + fFirstPoint = fInitPoints[0]; + fFirstVertex = fPositions.count(); + fPrevNormal = fFirstNormal; + fPrevPoint = fFirstPoint; + fPrevUmbraIndex = fFirstVertex; + + this->addInnerPoint(fFirstPoint); + + if (!fTransparent) { + SkPoint clipPoint; + bool isOutside = this->clipUmbraPoint(fPositions[fFirstVertex], fCentroid, &clipPoint); + if (isOutside) { + *fPositions.push() = clipPoint; + *fColors.push() = fUmbraColor; + } + fPrevUmbraOutside = isOutside; + fFirstUmbraOutside = isOutside; + } + + SkPoint newPoint = fFirstPoint + fFirstNormal; + *fPositions.push() = newPoint; + *fColors.push() = fPenumbraColor; + this->addEdge(fInitPoints[1], fFirstNormal); + + // to ensure we skip this block next time + *fInitPoints.push() = p; + } + + SkVector normal; + if (compute_normal(fPrevPoint, p, fDirection, &normal)) { + normal *= fRadius; + this->addArc(normal, true); + this->addEdge(p, normal); + } +} + +bool SkSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint) { + SkPoint umbraPoint; + if (!fValidUmbra) { + SkVector v = fCentroid - pathPoint; + v *= 0.95f; + umbraPoint = pathPoint + v; + } else { + umbraPoint = fUmbraPolygon[this->getClosestUmbraPoint(pathPoint)]; + } + + fPrevPoint = pathPoint; + + // merge "close" points + if (fPrevUmbraIndex == fFirstVertex || + !duplicate_pt(umbraPoint, fPositions[fPrevUmbraIndex])) { + *fPositions.push() = umbraPoint; + *fColors.push() = fUmbraColor; + + return false; + } else { + return true; + } +} + +void SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) { + // add next umbra point + bool duplicate = this->addInnerPoint(nextPoint); + int prevPenumbraIndex = duplicate ? fPositions.count()-1 : fPositions.count()-2; + int currUmbraIndex = duplicate ? fPrevUmbraIndex : fPositions.count()-1; + + if (!duplicate) { + // add to center fan if transparent or centroid showing + if (fTransparent) { + *fIndices.push() = 0; + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = currUmbraIndex; + // otherwise add to clip ring + } else { + SkPoint clipPoint; + bool isOutside = this->clipUmbraPoint(fPositions[currUmbraIndex], fCentroid, + &clipPoint); + if (isOutside) { + *fPositions.push() = clipPoint; + *fColors.push() = fUmbraColor; + + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = currUmbraIndex; + *fIndices.push() = currUmbraIndex + 1; + if (fPrevUmbraOutside) { + // fill out quad + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = currUmbraIndex + 1; + *fIndices.push() = fPrevUmbraIndex + 1; + } + } else if (fPrevUmbraOutside) { + // add tri + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = currUmbraIndex; + *fIndices.push() = fPrevUmbraIndex + 1; + } + fPrevUmbraOutside = isOutside; + } + } + + // add next penumbra point and quad + SkPoint newPoint = nextPoint + nextNormal; + *fPositions.push() = newPoint; + *fColors.push() = fPenumbraColor; + + if (!duplicate) { + *fIndices.push() = fPrevUmbraIndex; + *fIndices.push() = prevPenumbraIndex; + *fIndices.push() = currUmbraIndex; + } + + *fIndices.push() = prevPenumbraIndex; + *fIndices.push() = fPositions.count() - 1; + *fIndices.push() = currUmbraIndex; + + fPrevUmbraIndex = currUmbraIndex; + fPrevNormal = nextNormal; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +sk_sp SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm, + HeightFunc heightFunc, SkScalar ambientAlpha, + bool transparent) { + SkAmbientShadowTessellator ambientTess(path, ctm, heightFunc, ambientAlpha, transparent); + return ambientTess.releaseVertices(); +} + +sk_sp SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm, + HeightFunc heightFunc, + const SkPoint3& lightPos, SkScalar lightRadius, + SkScalar spotAlpha, bool transparent) { + SkSpotShadowTessellator spotTess(path, ctm, heightFunc, lightPos, lightRadius, + spotAlpha, transparent); + return spotTess.releaseVertices(); +} diff --git a/gfx/skia/skia/src/utils/SkShadowTessellator.h b/gfx/skia/skia/src/utils/SkShadowTessellator.h new file mode 100644 index 000000000000..f9f4a144c955 --- /dev/null +++ b/gfx/skia/skia/src/utils/SkShadowTessellator.h @@ -0,0 +1,41 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkShadowTessellator_DEFINED +#define SkShadowTessellator_DEFINED + +#include "SkColor.h" +#include "SkPoint.h" +#include "SkRefCnt.h" + +class SkMatrix; +class SkPath; +class SkVertices; + +namespace SkShadowTessellator { + +typedef std::function HeightFunc; + +/** + * This function generates an ambient shadow mesh for a path by walking the path, outsetting by + * the radius, and setting inner and outer colors to umbraColor and penumbraColor, respectively. + * If transparent is true, then the center of the ambient shadow will be filled in. + */ +sk_sp MakeAmbient(const SkPath& path, const SkMatrix& ctm, + HeightFunc heightFunc, SkScalar ambientAlpha, bool transparent); + +/** + * This function generates a spot shadow mesh for a path by walking the transformed path, + * further transforming by the scale and translation, and outsetting and insetting by a radius. + * The center will be clipped against the original path unless transparent is true. + */ +sk_sp MakeSpot(const SkPath& path, const SkMatrix& ctm, HeightFunc heightFunc, + const SkPoint3& lightPos, SkScalar lightRadius, + SkScalar spotAlpha, bool transparent); +} + +#endif diff --git a/gfx/skia/skia/src/utils/SkShadowUtils.cpp b/gfx/skia/skia/src/utils/SkShadowUtils.cpp new file mode 100644 index 000000000000..2e560b454eb7 --- /dev/null +++ b/gfx/skia/skia/src/utils/SkShadowUtils.cpp @@ -0,0 +1,599 @@ +/* +* Copyright 2017 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#include "SkShadowUtils.h" +#include "SkCanvas.h" +#include "SkColorFilter.h" +#include "SkPath.h" +#include "SkRandom.h" +#include "SkResourceCache.h" +#include "SkShadowTessellator.h" +#include "SkString.h" +#include "SkTLazy.h" +#include "SkVertices.h" +#if SK_SUPPORT_GPU +#include "GrShape.h" +#include "effects/GrBlurredEdgeFragmentProcessor.h" +#endif +#include "../../src/effects/shadows/SkAmbientShadowMaskFilter.h" +#include "../../src/effects/shadows/SkSpotShadowMaskFilter.h" + +/** +* Gaussian color filter -- produces a Gaussian ramp based on the color's B value, +* then blends with the color's G value. +* Final result is black with alpha of Gaussian(B)*G. +* The assumption is that the original color's alpha is 1. +*/ +class SK_API SkGaussianColorFilter : public SkColorFilter { +public: + static sk_sp Make() { + return sk_sp(new SkGaussianColorFilter); + } + + void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override; + +#if SK_SUPPORT_GPU + sk_sp asFragmentProcessor(GrContext*, SkColorSpace*) const override; +#endif + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkGaussianColorFilter) + +protected: + void flatten(SkWriteBuffer&) const override {} + +private: + SkGaussianColorFilter() : INHERITED() {} + + typedef SkColorFilter INHERITED; +}; + +void SkGaussianColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const { + for (int i = 0; i < count; ++i) { + SkPMColor c = src[i]; + + SkScalar factor = SK_Scalar1 - SkGetPackedB32(c) / 255.f; + factor = SkScalarExp(-factor * factor * 4) - 0.018f; + + SkScalar a = factor * SkGetPackedG32(c); + dst[i] = SkPackARGB32(a, a, a, a); + } +} + +sk_sp SkGaussianColorFilter::CreateProc(SkReadBuffer&) { + return Make(); +} + +#ifndef SK_IGNORE_TO_STRING +void SkGaussianColorFilter::toString(SkString* str) const { + str->append("SkGaussianColorFilter "); +} +#endif + +#if SK_SUPPORT_GPU + +sk_sp SkGaussianColorFilter::asFragmentProcessor(GrContext*, + SkColorSpace*) const { + return GrBlurredEdgeFP::Make(GrBlurredEdgeFP::kGaussian_Mode); +} +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace { + +uint64_t resource_cache_shared_id() { + return 0x2020776f64616873llu; // 'shadow ' +} + +/** Factory for an ambient shadow mesh with particular shadow properties. */ +struct AmbientVerticesFactory { + SkScalar fOccluderHeight = SK_ScalarNaN; // NaN so that isCompatible will fail until init'ed. + SkScalar fAmbientAlpha; + bool fTransparent; + + bool isCompatible(const AmbientVerticesFactory& that, SkVector* translate) const { + if (fOccluderHeight != that.fOccluderHeight || fAmbientAlpha != that.fAmbientAlpha || + fTransparent != that.fTransparent) { + return false; + } + translate->set(0, 0); + return true; + } + + sk_sp makeVertices(const SkPath& path, const SkMatrix& ctm) const { + SkScalar z = fOccluderHeight; + return SkShadowTessellator::MakeAmbient(path, ctm, + [z](SkScalar, SkScalar) { return z; }, + fAmbientAlpha, fTransparent); + } +}; + +/** Factory for an spot shadow mesh with particular shadow properties. */ +struct SpotVerticesFactory { + enum class OccluderType { + // The umbra cannot be dropped out because the occluder is not opaque. + kTransparent, + // The umbra can be dropped where it is occluded. + kOpaque, + // It is known that the entire umbra is occluded. + kOpaqueCoversUmbra + }; + + SkVector fOffset; + SkScalar fOccluderHeight = SK_ScalarNaN; // NaN so that isCompatible will fail until init'ed. + SkPoint3 fDevLightPos; + SkScalar fLightRadius; + SkScalar fSpotAlpha; + OccluderType fOccluderType; + + bool isCompatible(const SpotVerticesFactory& that, SkVector* translate) const { + if (fOccluderHeight != that.fOccluderHeight || fDevLightPos.fZ != that.fDevLightPos.fZ || + fLightRadius != that.fLightRadius || fSpotAlpha != that.fSpotAlpha || + fOccluderType != that.fOccluderType) { + return false; + } + switch (fOccluderType) { + case OccluderType::kTransparent: + case OccluderType::kOpaqueCoversUmbra: + // 'this' and 'that' will either both have no umbra removed or both have all the + // umbra removed. + *translate = that.fOffset - fOffset; + return true; + case OccluderType::kOpaque: + // In this case we partially remove the umbra differently for 'this' and 'that' + // if the offsets don't match. + if (fOffset == that.fOffset) { + translate->set(0, 0); + return true; + } + return false; + } + SkFAIL("Uninitialized occluder type?"); + return false; + } + + sk_sp makeVertices(const SkPath& path, const SkMatrix& ctm) const { + bool transparent = OccluderType::kTransparent == fOccluderType; + SkScalar z = fOccluderHeight; + return SkShadowTessellator::MakeSpot(path, ctm, + [z](SkScalar, SkScalar) -> SkScalar { return z; }, + fDevLightPos, fLightRadius, + fSpotAlpha, transparent); + } +}; + +/** + * This manages a set of tessellations for a given shape in the cache. Because SkResourceCache + * records are immutable this is not itself a Rec. When we need to update it we return this on + * the FindVisitor and let the cache destory the Rec. We'll update the tessellations and then add + * a new Rec with an adjusted size for any deletions/additions. + */ +class CachedTessellations : public SkRefCnt { +public: + size_t size() const { return fAmbientSet.size() + fSpotSet.size(); } + + sk_sp find(const AmbientVerticesFactory& ambient, const SkMatrix& matrix, + SkVector* translate) const { + return fAmbientSet.find(ambient, matrix, translate); + } + + sk_sp add(const SkPath& devPath, const AmbientVerticesFactory& ambient, + const SkMatrix& matrix) { + return fAmbientSet.add(devPath, ambient, matrix); + } + + sk_sp find(const SpotVerticesFactory& spot, const SkMatrix& matrix, + SkVector* translate) const { + return fSpotSet.find(spot, matrix, translate); + } + + sk_sp add(const SkPath& devPath, const SpotVerticesFactory& spot, + const SkMatrix& matrix) { + return fSpotSet.add(devPath, spot, matrix); + } + +private: + template + class Set { + public: + size_t size() const { return fSize; } + + sk_sp find(const FACTORY& factory, const SkMatrix& matrix, + SkVector* translate) const { + for (int i = 0; i < MAX_ENTRIES; ++i) { + if (fEntries[i].fFactory.isCompatible(factory, translate)) { + const SkMatrix& m = fEntries[i].fMatrix; + if (matrix.hasPerspective() || m.hasPerspective()) { + if (matrix != fEntries[i].fMatrix) { + continue; + } + } else if (matrix.getScaleX() != m.getScaleX() || + matrix.getSkewX() != m.getSkewX() || + matrix.getScaleY() != m.getScaleY() || + matrix.getSkewY() != m.getSkewY()) { + continue; + } + *translate += SkVector{matrix.getTranslateX() - m.getTranslateX(), + matrix.getTranslateY() - m.getTranslateY()}; + return fEntries[i].fVertices; + } + } + return nullptr; + } + + sk_sp add(const SkPath& path, const FACTORY& factory, const SkMatrix& matrix) { + sk_sp vertices = factory.makeVertices(path, matrix); + if (!vertices) { + return nullptr; + } + int i; + if (fCount < MAX_ENTRIES) { + i = fCount++; + } else { + i = gRandom.nextULessThan(MAX_ENTRIES); + fSize -= fEntries[i].fVertices->approximateSize(); + } + fEntries[i].fFactory = factory; + fEntries[i].fVertices = vertices; + fEntries[i].fMatrix = matrix; + fSize += vertices->approximateSize(); + return vertices; + } + + private: + struct Entry { + FACTORY fFactory; + sk_sp fVertices; + SkMatrix fMatrix; + }; + Entry fEntries[MAX_ENTRIES]; + int fCount = 0; + size_t fSize = 0; + }; + + Set fAmbientSet; + Set fSpotSet; + + static SkRandom gRandom; +}; + +SkRandom CachedTessellations::gRandom; + +/** + * A record of shadow vertices stored in SkResourceCache of CachedTessellations for a particular + * path. The key represents the path's geometry and not any shadow params. + */ +class CachedTessellationsRec : public SkResourceCache::Rec { +public: + CachedTessellationsRec(const SkResourceCache::Key& key, + sk_sp tessellations) + : fTessellations(std::move(tessellations)) { + fKey.reset(new uint8_t[key.size()]); + memcpy(fKey.get(), &key, key.size()); + } + + const Key& getKey() const override { + return *reinterpret_cast(fKey.get()); + } + + size_t bytesUsed() const override { return fTessellations->size(); } + + const char* getCategory() const override { return "tessellated shadow masks"; } + + sk_sp refTessellations() const { return fTessellations; } + + template + sk_sp find(const FACTORY& factory, const SkMatrix& matrix, + SkVector* translate) const { + return fTessellations->find(factory, matrix, translate); + } + +private: + std::unique_ptr fKey; + sk_sp fTessellations; +}; + +/** + * Used by FindVisitor to determine whether a cache entry can be reused and if so returns the + * vertices and a translation vector. If the CachedTessellations does not contain a suitable + * mesh then we inform SkResourceCache to destroy the Rec and we return the CachedTessellations + * to the caller. The caller will update it and reinsert it back into the cache. + */ +template +struct FindContext { + FindContext(const SkMatrix* viewMatrix, const FACTORY* factory) + : fViewMatrix(viewMatrix), fFactory(factory) {} + const SkMatrix* const fViewMatrix; + // If this is valid after Find is called then we found the vertices and they should be drawn + // with fTranslate applied. + sk_sp fVertices; + SkVector fTranslate = {0, 0}; + + // If this is valid after Find then the caller should add the vertices to the tessellation set + // and create a new CachedTessellationsRec and insert it into SkResourceCache. + sk_sp fTessellationsOnFailure; + + const FACTORY* fFactory; +}; + +/** + * Function called by SkResourceCache when a matching cache key is found. The FACTORY and matrix of + * the FindContext are used to determine if the vertices are reusable. If so the vertices and + * necessary translation vector are set on the FindContext. + */ +template +bool FindVisitor(const SkResourceCache::Rec& baseRec, void* ctx) { + FindContext* findContext = (FindContext*)ctx; + const CachedTessellationsRec& rec = static_cast(baseRec); + findContext->fVertices = + rec.find(*findContext->fFactory, *findContext->fViewMatrix, &findContext->fTranslate); + if (findContext->fVertices) { + return true; + } + // We ref the tessellations and let the cache destroy the Rec. Once the tessellations have been + // manipulated we will add a new Rec. + findContext->fTessellationsOnFailure = rec.refTessellations(); + return false; +} + +class ShadowedPath { +public: + ShadowedPath(const SkPath* path, const SkMatrix* viewMatrix) + : fPath(path) + , fViewMatrix(viewMatrix) +#if SK_SUPPORT_GPU + , fShapeForKey(*path, GrStyle::SimpleFill()) +#endif + {} + + const SkPath& path() const { return *fPath; } + const SkMatrix& viewMatrix() const { return *fViewMatrix; } +#if SK_SUPPORT_GPU + /** Negative means the vertices should not be cached for this path. */ + int keyBytes() const { return fShapeForKey.unstyledKeySize() * sizeof(uint32_t); } + void writeKey(void* key) const { + fShapeForKey.writeUnstyledKey(reinterpret_cast(key)); + } + bool isRRect(SkRRect* rrect) { return fShapeForKey.asRRect(rrect, nullptr, nullptr, nullptr); } +#else + int keyBytes() const { return -1; } + void writeKey(void* key) const { SkFAIL("Should never be called"); } + bool isRRect(SkRRect* rrect) { return false; } +#endif + +private: + const SkPath* fPath; + const SkMatrix* fViewMatrix; +#if SK_SUPPORT_GPU + GrShape fShapeForKey; +#endif +}; + +// This creates a domain of keys in SkResourceCache used by this file. +static void* kNamespace; + +/** + * Draws a shadow to 'canvas'. The vertices used to draw the shadow are created by 'factory' unless + * they are first found in SkResourceCache. + */ +template +void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, SkColor color, + SkResourceCache* cache) { + FindContext context(&path.viewMatrix(), &factory); + + SkResourceCache::Key* key = nullptr; + SkAutoSTArray<32 * 4, uint8_t> keyStorage; + int keyDataBytes = path.keyBytes(); + if (keyDataBytes >= 0) { + keyStorage.reset(keyDataBytes + sizeof(SkResourceCache::Key)); + key = new (keyStorage.begin()) SkResourceCache::Key(); + path.writeKey((uint32_t*)(keyStorage.begin() + sizeof(*key))); + key->init(&kNamespace, resource_cache_shared_id(), keyDataBytes); + if (cache) { + cache->find(*key, FindVisitor, &context); + } else { + SkResourceCache::Find(*key, FindVisitor, &context); + } + } + + sk_sp vertices; + const SkVector* translate; + static constexpr SkVector kZeroTranslate = {0, 0}; + bool foundInCache = SkToBool(context.fVertices); + if (foundInCache) { + vertices = std::move(context.fVertices); + translate = &context.fTranslate; + } else { + // TODO: handle transforming the path as part of the tessellator + if (key) { + // Update or initialize a tessellation set and add it to the cache. + sk_sp tessellations; + if (context.fTessellationsOnFailure) { + tessellations = std::move(context.fTessellationsOnFailure); + } else { + tessellations.reset(new CachedTessellations()); + } + vertices = tessellations->add(path.path(), factory, path.viewMatrix()); + if (!vertices) { + return; + } + auto rec = new CachedTessellationsRec(*key, std::move(tessellations)); + if (cache) { + cache->add(rec); + } else { + SkResourceCache::Add(rec); + } + } else { + vertices = factory.makeVertices(path.path(), path.viewMatrix()); + if (!vertices) { + return; + } + } + translate = &kZeroTranslate; + } + + SkPaint paint; + // Run the vertex color through a GaussianColorFilter and then modulate the grayscale result of + // that against our 'color' param. + paint.setColorFilter(SkColorFilter::MakeComposeFilter( + SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate), + SkGaussianColorFilter::Make())); + if (translate->fX || translate->fY) { + canvas->save(); + canvas->translate(translate->fX, translate->fY); + } + canvas->drawVertices(vertices, SkBlendMode::kModulate, paint); + if (translate->fX || translate->fY) { + canvas->restore(); + } +} +} + +// Draw an offset spot shadow and outlining ambient shadow for the given path. +void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight, + const SkPoint3& devLightPos, SkScalar lightRadius, + SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color, + uint32_t flags, SkResourceCache* cache) { + SkAutoCanvasRestore acr(canvas, true); + SkMatrix viewMatrix = canvas->getTotalMatrix(); + + // try circular fast path + SkRect rect; + if (viewMatrix.isSimilarity() && + path.isOval(&rect) && rect.width() == rect.height()) { + SkPaint newPaint; + newPaint.setColor(color); + if (ambientAlpha > 0) { + newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderHeight, ambientAlpha, + flags)); + canvas->drawPath(path, newPaint); + } + if (spotAlpha > 0) { + newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderHeight, devLightPos, + lightRadius, spotAlpha, flags)); + canvas->drawPath(path, newPaint); + } + return; + } + + canvas->resetMatrix(); + + ShadowedPath shadowedPath(&path, &viewMatrix); + + bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag); + + if (ambientAlpha > 0) { + ambientAlpha = SkTMin(ambientAlpha, 1.f); + AmbientVerticesFactory factory; + factory.fOccluderHeight = occluderHeight; + factory.fAmbientAlpha = ambientAlpha; + factory.fTransparent = transparent; + + draw_shadow(factory, canvas, shadowedPath, color, cache); + } + + if (spotAlpha > 0) { + spotAlpha = SkTMin(spotAlpha, 1.f); + SpotVerticesFactory factory; + float zRatio = SkTPin(occluderHeight / (devLightPos.fZ - occluderHeight), 0.0f, 0.95f); + SkScalar radius = lightRadius * zRatio; + + // Compute the scale and translation for the spot shadow. + SkScalar scale = devLightPos.fZ / (devLightPos.fZ - occluderHeight); + + SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY()); + viewMatrix.mapPoints(¢er, 1); + factory.fOffset = SkVector::Make(zRatio * (center.fX - devLightPos.fX), + zRatio * (center.fY - devLightPos.fY)); + factory.fOccluderHeight = occluderHeight; + factory.fDevLightPos = devLightPos; + factory.fLightRadius = lightRadius; + factory.fSpotAlpha = spotAlpha; + + SkRRect rrect; + if (transparent) { + factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent; + } else { + factory.fOccluderType = SpotVerticesFactory::OccluderType::kOpaque; + if (shadowedPath.isRRect(&rrect)) { + SkRRect devRRect; + if (rrect.transform(viewMatrix, &devRRect)) { + SkScalar s = 1.f - scale; + SkScalar w = devRRect.width(); + SkScalar h = devRRect.height(); + SkScalar hw = w / 2.f; + SkScalar hh = h / 2.f; + SkScalar umbraInsetX = s * hw + radius; + SkScalar umbraInsetY = s * hh + radius; + // The umbra is inset by radius along the diagonal, so adjust for that. + SkScalar d = 1.f / SkScalarSqrt(hw * hw + hh * hh); + umbraInsetX *= hw * d; + umbraInsetY *= hh * d; + if (umbraInsetX > hw || umbraInsetY > hh) { + // There is no umbra to occlude. + factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent; + } else if (fabsf(factory.fOffset.fX) < umbraInsetX && + fabsf(factory.fOffset.fY) < umbraInsetY) { + factory.fOccluderType = + SpotVerticesFactory::OccluderType::kOpaqueCoversUmbra; + } else if (factory.fOffset.fX > w - umbraInsetX || + factory.fOffset.fY > h - umbraInsetY) { + // There umbra is fully exposed, there is nothing to omit. + factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent; + } + } + } + } + if (factory.fOccluderType == SpotVerticesFactory::OccluderType::kOpaque) { + factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent; + } + draw_shadow(factory, canvas, shadowedPath, color, cache); + } +} + +// Draw an offset spot shadow and outlining ambient shadow for the given path, +// without caching and using a function based on local position to compute the height. +void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path, + std::function heightFunc, + const SkPoint3& lightPos, SkScalar lightRadius, + SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color, + uint32_t flags) { + SkAutoCanvasRestore acr(canvas, true); + SkMatrix viewMatrix = canvas->getTotalMatrix(); + canvas->resetMatrix(); + + bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag); + + if (ambientAlpha > 0) { + ambientAlpha = SkTMin(ambientAlpha, 1.f); + sk_sp vertices = SkShadowTessellator::MakeAmbient(path, viewMatrix, + heightFunc, ambientAlpha, + transparent); + SkPaint paint; + // Run the vertex color through a GaussianColorFilter and then modulate the grayscale + // result of that against our 'color' param. + paint.setColorFilter(SkColorFilter::MakeComposeFilter( + SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate), + SkGaussianColorFilter::Make())); + canvas->drawVertices(vertices, SkBlendMode::kModulate, paint); + } + + if (spotAlpha > 0) { + spotAlpha = SkTMin(spotAlpha, 1.f); + sk_sp vertices = SkShadowTessellator::MakeSpot(path, viewMatrix, heightFunc, + lightPos, lightRadius, + spotAlpha, transparent); + SkPaint paint; + // Run the vertex color through a GaussianColorFilter and then modulate the grayscale + // result of that against our 'color' param. + paint.setColorFilter(SkColorFilter::MakeComposeFilter( + SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate), + SkGaussianColorFilter::Make())); + canvas->drawVertices(vertices, SkBlendMode::kModulate, paint); + } +} diff --git a/gfx/skia/skia/src/utils/SkTextBox.cpp b/gfx/skia/skia/src/utils/SkTextBox.cpp index bc2e2217d954..9b26a9f00bba 100644 --- a/gfx/skia/skia/src/utils/SkTextBox.cpp +++ b/gfx/skia/skia/src/utils/SkTextBox.cpp @@ -192,7 +192,7 @@ SkScalar SkTextBox::visit(Visitor& visitor, const char text[], size_t len, x += fBox.fLeft; fontHeight = paint.getFontMetrics(&metrics); - scaledSpacing = SkScalarMul(fontHeight, fSpacingMul) + fSpacingAdd; + scaledSpacing = fontHeight * fSpacingMul + fSpacingAdd; height = fBox.height(); // compute Y position for first line @@ -271,7 +271,7 @@ int SkTextBox::countLines() const { } SkScalar SkTextBox::getTextHeight() const { - SkScalar spacing = SkScalarMul(fPaint->getTextSize(), fSpacingMul) + fSpacingAdd; + SkScalar spacing = fPaint->getTextSize() * fSpacingMul + fSpacingAdd; return this->countLines() * spacing; } diff --git a/gfx/skia/skia/src/utils/SkTextureCompressor.cpp b/gfx/skia/skia/src/utils/SkTextureCompressor.cpp deleted file mode 100644 index e9e4d2e826c1..000000000000 --- a/gfx/skia/skia/src/utils/SkTextureCompressor.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTextureCompressor.h" -#include "SkTextureCompressor_ASTC.h" -#include "SkTextureCompressor_LATC.h" -#include "SkTextureCompressor_R11EAC.h" - -#include "SkBitmap.h" -#include "SkBitmapProcShader.h" -#include "SkData.h" -#include "SkEndian.h" -#include "SkMathPriv.h" -#include "SkOpts.h" - -#ifndef SK_IGNORE_ETC1_SUPPORT -# include "etc1.h" -#endif - -// Convert ETC1 functions to our function signatures -static bool compress_etc1_565(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes) { -#ifndef SK_IGNORE_ETC1_SUPPORT - return 0 == etc1_encode_image(src, width, height, 2, SkToInt(rowBytes), dst); -#else - return false; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// - -namespace SkTextureCompressor { - -void GetBlockDimensions(Format format, int* dimX, int* dimY, bool matchSpec) { - if (nullptr == dimX || nullptr == dimY) { - return; - } - - if (!matchSpec && SkOpts::fill_block_dimensions(format, dimX, dimY)) { - return; - } - - // No specialized arguments, return the dimensions as they are in the spec. - static const struct FormatDimensions { - const int fBlockSizeX; - const int fBlockSizeY; - } kFormatDimensions[kFormatCnt] = { - { 4, 4 }, // kLATC_Format - { 4, 4 }, // kR11_EAC_Format - { 4, 4 }, // kETC1_Format - { 4, 4 }, // kASTC_4x4_Format - { 5, 4 }, // kASTC_5x4_Format - { 5, 5 }, // kASTC_5x5_Format - { 6, 5 }, // kASTC_6x5_Format - { 6, 6 }, // kASTC_6x6_Format - { 8, 5 }, // kASTC_8x5_Format - { 8, 6 }, // kASTC_8x6_Format - { 8, 8 }, // kASTC_8x8_Format - { 10, 5 }, // kASTC_10x5_Format - { 10, 6 }, // kASTC_10x6_Format - { 10, 8 }, // kASTC_10x8_Format - { 10, 10 }, // kASTC_10x10_Format - { 12, 10 }, // kASTC_12x10_Format - { 12, 12 }, // kASTC_12x12_Format - }; - - *dimX = kFormatDimensions[format].fBlockSizeX; - *dimY = kFormatDimensions[format].fBlockSizeY; -} - -int GetCompressedDataSize(Format fmt, int width, int height) { - int dimX, dimY; - GetBlockDimensions(fmt, &dimX, &dimY, true); - - int encodedBlockSize = 0; - - switch (fmt) { - // These formats are 64 bits per 4x4 block. - case kLATC_Format: - case kR11_EAC_Format: - case kETC1_Format: - encodedBlockSize = 8; - break; - - // This format is 128 bits. - case kASTC_4x4_Format: - case kASTC_5x4_Format: - case kASTC_5x5_Format: - case kASTC_6x5_Format: - case kASTC_6x6_Format: - case kASTC_8x5_Format: - case kASTC_8x6_Format: - case kASTC_8x8_Format: - case kASTC_10x5_Format: - case kASTC_10x6_Format: - case kASTC_10x8_Format: - case kASTC_10x10_Format: - case kASTC_12x10_Format: - case kASTC_12x12_Format: - encodedBlockSize = 16; - break; - - default: - SkFAIL("Unknown compressed format!"); - return -1; - } - - if(((width % dimX) == 0) && ((height % dimY) == 0)) { - const int blocksX = width / dimX; - const int blocksY = height / dimY; - - return blocksX * blocksY * encodedBlockSize; - } - - return -1; -} - -bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcColorType, - int width, int height, size_t rowBytes, Format format) { - SkOpts::TextureCompressor proc = SkOpts::texture_compressor(srcColorType, format); - if (proc && proc(dst, src, width, height, rowBytes)) { - return true; - } - - switch (srcColorType) { - case kAlpha_8_SkColorType: - if (format == kLATC_Format) { proc = CompressA8ToLATC; } - if (format == kR11_EAC_Format) { proc = CompressA8ToR11EAC; } - if (format == kASTC_12x12_Format) { proc = CompressA8To12x12ASTC; } - break; - case kRGB_565_SkColorType: - if (format == kETC1_Format) { proc = compress_etc1_565; } - break; - default: - break; - } - if (proc && proc(dst, src, width, height, rowBytes)) { - return true; - } - - return false; -} - -sk_sp CompressBitmapToFormat(const SkPixmap& pixmap, Format format) { - int compressedDataSize = GetCompressedDataSize(format, pixmap.width(), pixmap.height()); - if (compressedDataSize < 0) { - return nullptr; - } - - const uint8_t* src = reinterpret_cast(pixmap.addr()); - sk_sp dst(SkData::MakeUninitialized(compressedDataSize)); - - if (!CompressBufferToFormat((uint8_t*)dst->writable_data(), src, pixmap.colorType(), - pixmap.width(), pixmap.height(), pixmap.rowBytes(), format)) { - return nullptr; - } - return dst; -} - -SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer, - SkTBlitterAllocator *allocator, Format format) { - switch(format) { - case kLATC_Format: - return CreateLATCBlitter(width, height, compressedBuffer, allocator); - - case kR11_EAC_Format: - return CreateR11EACBlitter(width, height, compressedBuffer, allocator); - - case kASTC_12x12_Format: - return CreateASTCBlitter(width, height, compressedBuffer, allocator); - - default: - return nullptr; - } - - return nullptr; -} - -bool DecompressBufferFromFormat(uint8_t* dst, int dstRowBytes, const uint8_t* src, - int width, int height, Format format) { - int dimX, dimY; - GetBlockDimensions(format, &dimX, &dimY, true); - - if (width < 0 || ((width % dimX) != 0) || height < 0 || ((height % dimY) != 0)) { - return false; - } - - switch(format) { - case kLATC_Format: - DecompressLATC(dst, dstRowBytes, src, width, height); - return true; - - case kR11_EAC_Format: - DecompressR11EAC(dst, dstRowBytes, src, width, height); - return true; - -#ifndef SK_IGNORE_ETC1_SUPPORT - case kETC1_Format: - return 0 == etc1_decode_image(src, dst, width, height, 3, dstRowBytes); -#endif - - case kASTC_4x4_Format: - case kASTC_5x4_Format: - case kASTC_5x5_Format: - case kASTC_6x5_Format: - case kASTC_6x6_Format: - case kASTC_8x5_Format: - case kASTC_8x6_Format: - case kASTC_8x8_Format: - case kASTC_10x5_Format: - case kASTC_10x6_Format: - case kASTC_10x8_Format: - case kASTC_10x10_Format: - case kASTC_12x10_Format: - case kASTC_12x12_Format: - DecompressASTC(dst, dstRowBytes, src, width, height, dimX, dimY); - return true; - - default: - // Do nothing... - break; - } - - return false; -} - -} // namespace SkTextureCompressor diff --git a/gfx/skia/skia/src/utils/SkTextureCompressor.h b/gfx/skia/skia/src/utils/SkTextureCompressor.h deleted file mode 100644 index 1ae4aef13233..000000000000 --- a/gfx/skia/skia/src/utils/SkTextureCompressor.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkTextureCompressor_DEFINED -#define SkTextureCompressor_DEFINED - -#include "SkBitmapProcShader.h" -#include "SkImageInfo.h" - -class SkBitmap; -class SkBlitter; -class SkData; - -namespace SkTextureCompressor { - // Various texture compression formats that we support. - enum Format { - // Alpha only formats. - kLATC_Format, // 4x4 blocks, (de)compresses A8 - kR11_EAC_Format, // 4x4 blocks, (de)compresses A8 - - // RGB only formats - kETC1_Format, // 4x4 blocks, compresses RGB 565, decompresses 8-bit RGB - // NOTE: ETC1 supports 8-bit RGB compression, but we - // currently don't have any RGB8 SkColorTypes. We could - // support 8-bit RGBA but we would have to preprocess the - // bitmap to insert alphas. - - // Multi-purpose formats - kASTC_4x4_Format, // 4x4 blocks, no compression, decompresses RGBA - kASTC_5x4_Format, // 5x4 blocks, no compression, decompresses RGBA - kASTC_5x5_Format, // 5x5 blocks, no compression, decompresses RGBA - kASTC_6x5_Format, // 6x5 blocks, no compression, decompresses RGBA - kASTC_6x6_Format, // 6x6 blocks, no compression, decompresses RGBA - kASTC_8x5_Format, // 8x5 blocks, no compression, decompresses RGBA - kASTC_8x6_Format, // 8x6 blocks, no compression, decompresses RGBA - kASTC_8x8_Format, // 8x8 blocks, no compression, decompresses RGBA - kASTC_10x5_Format, // 10x5 blocks, no compression, decompresses RGBA - kASTC_10x6_Format, // 10x6 blocks, no compression, decompresses RGBA - kASTC_10x8_Format, // 10x8 blocks, no compression, decompresses RGBA - kASTC_10x10_Format, // 10x10 blocks, no compression, decompresses RGBA - kASTC_12x10_Format, // 12x10 blocks, no compression, decompresses RGBA - kASTC_12x12_Format, // 12x12 blocks, compresses A8, decompresses RGBA - - kLast_Format = kASTC_12x12_Format - }; - static const int kFormatCnt = kLast_Format + 1; - - // Returns the size of the compressed data given the width, height, and - // desired compression format. If the width and height are not an appropriate - // multiple of the block size, then this function returns an error (-1). - int GetCompressedDataSize(Format fmt, int width, int height); - - // Returns an SkData holding a blob of compressed data that corresponds - // to the pixmap. If the pixmap colorType cannot be compressed using the - // associated format, then we return nullptr. - sk_sp CompressBitmapToFormat(const SkPixmap&, Format format); - - // Compresses the given src data into dst. The src data is assumed to be - // large enough to hold width*height pixels. The dst data is expected to - // be large enough to hold the compressed data according to the format. - bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcColorType, - int width, int height, size_t rowBytes, Format format); - - // Decompresses the given src data from the format specified into the - // destination buffer. The width and height of the data passed corresponds - // to the width and height of the uncompressed image. The destination buffer (dst) - // is assumed to be large enough to hold the entire decompressed image. The - // decompressed image colors are determined based on the passed format. - // - // Note, CompressBufferToFormat compresses A8 data into ASTC. However, - // general ASTC data encodes RGBA data, so that is what the decompressor - // operates on. - // - // Returns true if successfully decompresses the src data. - bool DecompressBufferFromFormat(uint8_t* dst, int dstRowBytes, const uint8_t* src, - int width, int height, Format format); - - // Returns true if there exists a blitter for the specified format. - inline bool ExistsBlitterForFormat(Format format) { - switch (format) { - case kLATC_Format: - case kR11_EAC_Format: - case kASTC_12x12_Format: - return true; - - default: - return false; - } - } - - // Returns the blitter for the given compression format. Note, the blitter - // is intended to be used with the proper input. I.e. if you try to blit - // RGB source data into an R11 EAC texture, you're gonna have a bad time. - SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer, - SkTBlitterAllocator *allocator, Format format); - - // Returns the desired dimensions of the block size for the given format. These dimensions - // don't necessarily correspond to the specification's dimensions, since there may - // be specialized algorithms that operate on multiple blocks at once. If the - // flag 'matchSpec' is true, then the actual dimensions from the specification are - // returned. If the flag is false, then these dimensions reflect the appropriate operable - // dimensions of the compression functions. - void GetBlockDimensions(Format format, int* dimX, int* dimY, bool matchSpec = false); -} - -#endif diff --git a/gfx/skia/skia/src/utils/SkTextureCompressor_ASTC.cpp b/gfx/skia/skia/src/utils/SkTextureCompressor_ASTC.cpp deleted file mode 100644 index 8a96b911ea0e..000000000000 --- a/gfx/skia/skia/src/utils/SkTextureCompressor_ASTC.cpp +++ /dev/null @@ -1,2101 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTextureCompressor_ASTC.h" -#include "SkTextureCompressor_Blitter.h" - -#include "SkBlitter.h" -#include "SkEndian.h" -#include "SkMathPriv.h" - -// This table contains the weight values for each texel. This is used in determining -// how to convert a 12x12 grid of alpha values into a 6x5 grid of index values. Since -// we have a 6x5 grid, that gives 30 values that we have to compute. For each index, -// we store up to 20 different triplets of values. In order the triplets are: -// weight, texel-x, texel-y -// The weight value corresponds to the amount that this index contributes to the final -// index value of the given texel. Hence, we need to reconstruct the 6x5 index grid -// from their relative contribution to the 12x12 texel grid. -// -// The algorithm is something like this: -// foreach index i: -// total-weight = 0; -// total-alpha = 0; -// for w = 1 to 20: -// weight = table[i][w*3]; -// texel-x = table[i][w*3 + 1]; -// texel-y = table[i][w*3 + 2]; -// if weight >= 0: -// total-weight += weight; -// total-alpha += weight * alphas[texel-x][texel-y]; -// -// total-alpha /= total-weight; -// index = top three bits of total-alpha -// -// If the associated index does not contribute to 20 different texels (e.g. it's in -// a corner), then the extra texels are stored with -1's in the table. - -static const int8_t k6x5To12x12Table[30][60] = { -{ 16, 0, 0, 9, 1, 0, 1, 2, 0, 10, 0, 1, 6, 1, 1, 1, 2, 1, 4, 0, 2, 2, - 1, 2, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 7, 1, 0, 15, 2, 0, 10, 3, 0, 3, 4, 0, 4, 1, 1, 9, 2, 1, 6, 3, 1, 2, - 4, 1, 2, 1, 2, 4, 2, 2, 3, 3, 2, 1, 4, 2, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 6, 3, 0, 13, 4, 0, 12, 5, 0, 4, 6, 0, 4, 3, 1, 8, 4, 1, 8, 5, 1, 3, - 6, 1, 1, 3, 2, 3, 4, 2, 3, 5, 2, 1, 6, 2, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 4, 5, 0, 12, 6, 0, 13, 7, 0, 6, 8, 0, 2, 5, 1, 7, 6, 1, 8, 7, 1, 4, - 8, 1, 1, 5, 2, 3, 6, 2, 3, 7, 2, 2, 8, 2, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 3, 7, 0, 10, 8, 0, 15, 9, 0, 7, 10, 0, 2, 7, 1, 6, 8, 1, 9, 9, 1, 4, - 10, 1, 1, 7, 2, 2, 8, 2, 4, 9, 2, 2, 10, 2, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 1, 9, 0, 9, 10, 0, 16, 11, 0, 1, 9, 1, 6, 10, 1, 10, 11, 1, 2, 10, 2, 4, - 11, 2, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 6, 0, 1, 3, 1, 1, 12, 0, 2, 7, 1, 2, 1, 2, 2, 15, 0, 3, 8, 1, 3, 1, - 2, 3, 9, 0, 4, 5, 1, 4, 1, 2, 4, 3, 0, 5, 2, 1, 5, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 3, 1, 1, 6, 2, 1, 4, 3, 1, 1, 4, 1, 5, 1, 2, 11, 2, 2, 7, 3, 2, 2, - 4, 2, 7, 1, 3, 14, 2, 3, 9, 3, 3, 3, 4, 3, 4, 1, 4, 8, 2, 4, 6, 3, - 4, 2, 4, 4, 1, 1, 5, 3, 2, 5, 2, 3, 5, 1, 4, 5}, // n = 20 -{ 2, 3, 1, 5, 4, 1, 4, 5, 1, 1, 6, 1, 5, 3, 2, 10, 4, 2, 9, 5, 2, 3, - 6, 2, 6, 3, 3, 12, 4, 3, 11, 5, 3, 4, 6, 3, 3, 3, 4, 7, 4, 4, 7, 5, - 4, 2, 6, 4, 1, 3, 5, 2, 4, 5, 2, 5, 5, 1, 6, 5}, // n = 20 -{ 2, 5, 1, 5, 6, 1, 5, 7, 1, 2, 8, 1, 3, 5, 2, 9, 6, 2, 10, 7, 2, 4, - 8, 2, 4, 5, 3, 11, 6, 3, 12, 7, 3, 6, 8, 3, 2, 5, 4, 7, 6, 4, 7, 7, - 4, 3, 8, 4, 1, 5, 5, 2, 6, 5, 2, 7, 5, 1, 8, 5}, // n = 20 -{ 1, 7, 1, 4, 8, 1, 6, 9, 1, 3, 10, 1, 2, 7, 2, 8, 8, 2, 11, 9, 2, 5, - 10, 2, 3, 7, 3, 9, 8, 3, 14, 9, 3, 7, 10, 3, 2, 7, 4, 6, 8, 4, 8, 9, - 4, 4, 10, 4, 1, 7, 5, 2, 8, 5, 3, 9, 5, 1, 10, 5}, // n = 20 -{ 3, 10, 1, 6, 11, 1, 1, 9, 2, 7, 10, 2, 12, 11, 2, 1, 9, 3, 8, 10, 3, 15, - 11, 3, 1, 9, 4, 5, 10, 4, 9, 11, 4, 2, 10, 5, 3, 11, 5, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 1, 0, 3, 1, 1, 3, 7, 0, 4, 4, 1, 4, 13, 0, 5, 7, 1, 5, 1, 2, 5, 13, - 0, 6, 7, 1, 6, 1, 2, 6, 7, 0, 7, 4, 1, 7, 1, 0, 8, 1, 1, 8, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 1, 2, 3, 1, 3, 3, 3, 1, 4, 7, 2, 4, 4, 3, 4, 1, 4, 4, 6, 1, 5, 12, - 2, 5, 8, 3, 5, 2, 4, 5, 6, 1, 6, 12, 2, 6, 8, 3, 6, 2, 4, 6, 3, 1, - 7, 7, 2, 7, 4, 3, 7, 1, 4, 7, 1, 2, 8, 1, 3, 8}, // n = 20 -{ 1, 4, 3, 1, 5, 3, 3, 3, 4, 6, 4, 4, 5, 5, 4, 2, 6, 4, 5, 3, 5, 11, - 4, 5, 10, 5, 5, 3, 6, 5, 5, 3, 6, 11, 4, 6, 10, 5, 6, 3, 6, 6, 3, 3, - 7, 6, 4, 7, 5, 5, 7, 2, 6, 7, 1, 4, 8, 1, 5, 8}, // n = 20 -{ 1, 6, 3, 1, 7, 3, 2, 5, 4, 5, 6, 4, 6, 7, 4, 3, 8, 4, 3, 5, 5, 10, - 6, 5, 11, 7, 5, 5, 8, 5, 3, 5, 6, 10, 6, 6, 11, 7, 6, 5, 8, 6, 2, 5, - 7, 5, 6, 7, 6, 7, 7, 3, 8, 7, 1, 6, 8, 1, 7, 8}, // n = 20 -{ 1, 8, 3, 1, 9, 3, 1, 7, 4, 4, 8, 4, 7, 9, 4, 3, 10, 4, 2, 7, 5, 8, - 8, 5, 12, 9, 5, 6, 10, 5, 2, 7, 6, 8, 8, 6, 12, 9, 6, 6, 10, 6, 1, 7, - 7, 4, 8, 7, 7, 9, 7, 3, 10, 7, 1, 8, 8, 1, 9, 8}, // n = 20 -{ 1, 10, 3, 1, 11, 3, 4, 10, 4, 7, 11, 4, 1, 9, 5, 7, 10, 5, 13, 11, 5, 1, - 9, 6, 7, 10, 6, 13, 11, 6, 4, 10, 7, 7, 11, 7, 1, 10, 8, 1, 11, 8, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 3, 0, 6, 2, 1, 6, 9, 0, 7, 5, 1, 7, 1, 2, 7, 15, 0, 8, 8, 1, 8, 1, - 2, 8, 12, 0, 9, 7, 1, 9, 1, 2, 9, 6, 0, 10, 3, 1, 10, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 1, 1, 6, 3, 2, 6, 2, 3, 6, 1, 4, 6, 4, 1, 7, 8, 2, 7, 6, 3, 7, 2, - 4, 7, 7, 1, 8, 14, 2, 8, 9, 3, 8, 3, 4, 8, 5, 1, 9, 11, 2, 9, 8, 3, - 9, 2, 4, 9, 3, 1, 10, 6, 2, 10, 4, 3, 10, 1, 4, 10}, // n = 20 -{ 1, 3, 6, 2, 4, 6, 2, 5, 6, 1, 6, 6, 3, 3, 7, 7, 4, 7, 7, 5, 7, 2, - 6, 7, 6, 3, 8, 12, 4, 8, 11, 5, 8, 4, 6, 8, 4, 3, 9, 10, 4, 9, 9, 5, - 9, 3, 6, 9, 2, 3, 10, 5, 4, 10, 5, 5, 10, 2, 6, 10}, // n = 20 -{ 1, 5, 6, 2, 6, 6, 2, 7, 6, 1, 8, 6, 2, 5, 7, 7, 6, 7, 7, 7, 7, 3, - 8, 7, 4, 5, 8, 11, 6, 8, 12, 7, 8, 6, 8, 8, 3, 5, 9, 9, 6, 9, 10, 7, - 9, 5, 8, 9, 1, 5, 10, 4, 6, 10, 5, 7, 10, 2, 8, 10}, // n = 20 -{ 1, 7, 6, 2, 8, 6, 3, 9, 6, 1, 10, 6, 2, 7, 7, 6, 8, 7, 8, 9, 7, 4, - 10, 7, 3, 7, 8, 9, 8, 8, 14, 9, 8, 7, 10, 8, 2, 7, 9, 7, 8, 9, 11, 9, - 9, 5, 10, 9, 1, 7, 10, 4, 8, 10, 6, 9, 10, 3, 10, 10}, // n = 20 -{ 2, 10, 6, 3, 11, 6, 1, 9, 7, 5, 10, 7, 9, 11, 7, 1, 9, 8, 8, 10, 8, 15, - 11, 8, 1, 9, 9, 7, 10, 9, 12, 11, 9, 3, 10, 10, 6, 11, 10, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 4, 0, 9, 2, 1, 9, 10, 0, 10, 6, 1, 10, 1, 2, 10, 16, 0, 11, 9, 1, 11, 1, - 2, 11, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 2, 1, 9, 4, 2, 9, 2, 3, 9, 1, 4, 9, 4, 1, 10, 9, 2, 10, 6, 3, 10, 2, - 4, 10, 7, 1, 11, 15, 2, 11, 10, 3, 11, 3, 4, 11, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 2, 3, 9, 3, 4, 9, 3, 5, 9, 1, 6, 9, 4, 3, 10, 8, 4, 10, 7, 5, 10, 2, - 6, 10, 6, 3, 11, 13, 4, 11, 12, 5, 11, 4, 6, 11, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 1, 5, 9, 3, 6, 9, 3, 7, 9, 1, 8, 9, 3, 5, 10, 8, 6, 10, 8, 7, 10, 4, - 8, 10, 4, 5, 11, 12, 6, 11, 13, 7, 11, 6, 8, 11, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 1, 7, 9, 3, 8, 9, 4, 9, 9, 2, 10, 9, 2, 7, 10, 6, 8, 10, 9, 9, 10, 4, - 10, 10, 3, 7, 11, 10, 8, 11, 15, 9, 11, 7, 10, 11, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20 -{ 2, 10, 9, 4, 11, 9, 1, 9, 10, 6, 10, 10, 10, 11, 10, 1, 9, 11, 9, 10, 11, 16, - 11, 11, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0} // n = 20 -}; - -// Returns the alpha value of a texel at position (x, y) from src. -// (x, y) are assumed to be in the range [0, 12). -inline uint8_t GetAlpha(const uint8_t *src, size_t rowBytes, int x, int y) { - SkASSERT(x >= 0 && x < 12); - SkASSERT(y >= 0 && y < 12); - SkASSERT(rowBytes >= 12); - return *(src + y*rowBytes + x); -} - -inline uint8_t GetAlphaTranspose(const uint8_t *src, size_t rowBytes, int x, int y) { - return GetAlpha(src, rowBytes, y, x); -} - -// Output the 16 bytes stored in top and bottom and advance the pointer. The bytes -// are stored as the integers are represented in memory, so they should be swapped -// if necessary. -static inline void send_packing(uint8_t** dst, const uint64_t top, const uint64_t bottom) { - uint64_t* dst64 = reinterpret_cast(*dst); - dst64[0] = top; - dst64[1] = bottom; - *dst += 16; -} - -// Compresses an ASTC block, by looking up the proper contributions from -// k6x5To12x12Table and computing an index from the associated values. -typedef uint8_t (*GetAlphaProc)(const uint8_t* src, size_t rowBytes, int x, int y); - -template -static void compress_a8_astc_block(uint8_t** dst, const uint8_t* src, size_t rowBytes) { - // Check for single color - bool constant = true; - const uint32_t firstInt = *(reinterpret_cast(src)); - for (int i = 0; i < 12; ++i) { - const uint32_t *rowInt = reinterpret_cast(src + i*rowBytes); - constant = constant && (rowInt[0] == firstInt); - constant = constant && (rowInt[1] == firstInt); - constant = constant && (rowInt[2] == firstInt); - } - - if (constant) { - if (0 == firstInt) { - // All of the indices are set to zero, and the colors are - // v0 = 0, v1 = 255, so everything will be transparent. - send_packing(dst, SkTEndian_SwapLE64(0x0000000001FE000173ULL), 0); - return; - } else if (0xFFFFFFFF == firstInt) { - // All of the indices are set to zero, and the colors are - // v0 = 255, v1 = 0, so everything will be opaque. - send_packing(dst, SkTEndian_SwapLE64(0x000000000001FE0173ULL), 0); - return; - } - } - - uint8_t indices[30]; // 6x5 index grid - for (int idx = 0; idx < 30; ++idx) { - int weightTot = 0; - int alphaTot = 0; - for (int w = 0; w < 20; ++w) { - const int8_t weight = k6x5To12x12Table[idx][w*3]; - if (weight > 0) { - const int x = k6x5To12x12Table[idx][w*3 + 1]; - const int y = k6x5To12x12Table[idx][w*3 + 2]; - weightTot += weight; - alphaTot += weight * getAlphaProc(src, rowBytes, x, y); - } else { - // In our table, not every entry has 20 weights, and all - // of them are nonzero. Once we hit a negative weight, we - // know that all of the other weights are not valid either. - break; - } - } - - indices[idx] = (alphaTot / weightTot) >> 5; - } - - // Pack indices... The ASTC block layout is fairly complicated. An extensive - // description can be found here: - // https://www.opengl.org/registry/specs/KHR/texture_compression_astc_hdr.txt - // - // Here is a summary of the options that we've chosen: - // 1. Block mode: 0b00101110011 - // - 6x5 texel grid - // - Single plane - // - Low-precision index values - // - Index range 0-7 (three bits per index) - // 2. Partitions: 0b00 - // - One partition - // 3. Color Endpoint Mode: 0b0000 - // - Direct luminance -- e0=(v0,v0,v0,0xFF); e1=(v1,v1,v1,0xFF); - // 4. 8-bit endpoints: - // v0 = 0, v1 = 255 - // - // The rest of the block contains the 30 index values from before, which - // are currently stored in the indices variable. - - uint64_t top = 0x0000000001FE000173ULL; - uint64_t bottom = 0; - - for (int idx = 0; idx <= 20; ++idx) { - const uint8_t index = indices[idx]; - bottom |= static_cast(index) << (61-(idx*3)); - } - - // index 21 straddles top and bottom - { - const uint8_t index = indices[21]; - bottom |= index & 1; - top |= static_cast((index >> 2) | (index & 2)) << 62; - } - - for (int idx = 22; idx < 30; ++idx) { - const uint8_t index = indices[idx]; - top |= static_cast(index) << (59-(idx-22)*3); - } - - // Reverse each 3-bit index since indices are read in reverse order... - uint64_t t = (bottom ^ (bottom >> 2)) & 0x2492492492492492ULL; - bottom = bottom ^ t ^ (t << 2); - - t = (top ^ (top >> 2)) & 0x0924924000000000ULL; - top = top ^ t ^ (t << 2); - - send_packing(dst, SkEndian_SwapLE64(top), SkEndian_SwapLE64(bottom)); -} - -inline void CompressA8ASTCBlockVertical(uint8_t* dst, const uint8_t* src) { - compress_a8_astc_block(&dst, src, 12); -} - -//////////////////////////////////////////////////////////////////////////////// -// -// ASTC Decoder -// -// Full details available in the spec: -// http://www.khronos.org/registry/gles/extensions/OES/OES_texture_compression_astc.txt -// -//////////////////////////////////////////////////////////////////////////////// - -// Enable this to assert whenever a decoded block has invalid ASTC values. Otherwise, -// each invalid block will result in a disgusting magenta color. -#define ASSERT_ASTC_DECODE_ERROR 0 - -// Reverse 64-bit integer taken from TAOCP 4a, although it's better -// documented at this site: -// http://matthewarcus.wordpress.com/2012/11/18/reversing-a-64-bit-word/ - -template -static inline T swap_bits(T p) { - T q = ((p>>k)^p) & m; - return p^q^(q<>1)&m0) | (n&m0)<<1; - n = swap_bits(n); - n = swap_bits(n); - n = swap_bits(n); - n = (n >> 34) | (n << 30); - return n; -} - -// An ASTC block is 128 bits. We represent it as two 64-bit integers in order -// to efficiently operate on the block using bitwise operations. -struct ASTCBlock { - uint64_t fLow; - uint64_t fHigh; - - // Reverses the bits of an ASTC block, making the LSB of the - // 128 bit block the MSB. - inline void reverse() { - const uint64_t newLow = reverse64(this->fHigh); - this->fHigh = reverse64(this->fLow); - this->fLow = newLow; - } -}; - -// Writes the given color to every pixel in the block. This is used by void-extent -// blocks (a special constant-color encoding of a block) and by the error function. -static inline void write_constant_color(uint8_t* dst, int blockDimX, int blockDimY, - int dstRowBytes, SkColor color) { - for (int y = 0; y < blockDimY; ++y) { - SkColor *dstColors = reinterpret_cast(dst); - for (int x = 0; x < blockDimX; ++x) { - dstColors[x] = color; - } - dst += dstRowBytes; - } -} - -// Sets the entire block to the ASTC "error" color, a disgusting magenta -// that's not supposed to appear in natural images. -static inline void write_error_color(uint8_t* dst, int blockDimX, int blockDimY, - int dstRowBytes) { - static const SkColor kASTCErrorColor = SkColorSetRGB(0xFF, 0, 0xFF); - -#if ASSERT_ASTC_DECODE_ERROR - SkDEBUGFAIL("ASTC decoding error!\n"); -#endif - - write_constant_color(dst, blockDimX, blockDimY, dstRowBytes, kASTCErrorColor); -} - -// Reads up to 64 bits of the ASTC block starting from bit -// 'from' and going up to but not including bit 'to'. 'from' starts -// counting from the LSB, counting up to the MSB. Returns -1 on -// error. -static uint64_t read_astc_bits(const ASTCBlock &block, int from, int to) { - SkASSERT(0 <= from && from <= 128); - SkASSERT(0 <= to && to <= 128); - - const int nBits = to - from; - if (0 == nBits) { - return 0; - } - - if (nBits < 0 || 64 <= nBits) { - SkDEBUGFAIL("ASTC -- shouldn't read more than 64 bits"); - return -1; - } - - // Remember, the 'to' bit isn't read. - uint64_t result = 0; - if (to <= 64) { - // All desired bits are in the low 64-bits. - result = (block.fLow >> from) & ((1ULL << nBits) - 1); - } else if (from >= 64) { - // All desired bits are in the high 64-bits. - result = (block.fHigh >> (from - 64)) & ((1ULL << nBits) - 1); - } else { - // from < 64 && to > 64 - SkASSERT(nBits > (64 - from)); - const int nLow = 64 - from; - const int nHigh = nBits - nLow; - result = - ((block.fLow >> from) & ((1ULL << nLow) - 1)) | - ((block.fHigh & ((1ULL << nHigh) - 1)) << nLow); - } - - return result; -} - -// Returns the number of bits needed to represent a number -// in the given power-of-two range (excluding the power of two itself). -static inline int bits_for_range(int x) { - SkASSERT(SkIsPow2(x)); - SkASSERT(0 != x); - // Since we know it's a power of two, there should only be one bit set, - // meaning the number of trailing zeros is 31 minus the number of leading - // zeros. - return 31 - SkCLZ(x); -} - -// Clamps an integer to the range [0, 255] -static inline int clamp_byte(int x) { - return SkClampMax(x, 255); -} - -// Helper function defined in the ASTC spec, section C.2.14 -// It transfers a few bits of precision from one value to another. -static inline void bit_transfer_signed(int *a, int *b) { - *b >>= 1; - *b |= *a & 0x80; - *a >>= 1; - *a &= 0x3F; - if ( (*a & 0x20) != 0 ) { - *a -= 0x40; - } -} - -// Helper function defined in the ASTC spec, section C.2.14 -// It uses the value in the blue channel to tint the red and green -static inline SkColor blue_contract(int a, int r, int g, int b) { - return SkColorSetARGB(a, (r + b) >> 1, (g + b) >> 1, b); -} - -// Helper function that decodes two colors from eight values. If isRGB is true, -// then the pointer 'v' contains six values and the last two are considered to be -// 0xFF. If isRGB is false, then all eight values come from the pointer 'v'. This -// corresponds to the decode procedure for the following endpoint modes: -// kLDR_RGB_Direct_ColorEndpointMode -// kLDR_RGBA_Direct_ColorEndpointMode -static inline void decode_rgba_direct(const int *v, SkColor *endpoints, bool isRGB) { - - int v6 = 0xFF; - int v7 = 0xFF; - if (!isRGB) { - v6 = v[6]; - v7 = v[7]; - } - - const int s0 = v[0] + v[2] + v[4]; - const int s1 = v[1] + v[3] + v[5]; - - if (s1 >= s0) { - endpoints[0] = SkColorSetARGB(v6, v[0], v[2], v[4]); - endpoints[1] = SkColorSetARGB(v7, v[1], v[3], v[5]); - } else { - endpoints[0] = blue_contract(v7, v[1], v[3], v[5]); - endpoints[1] = blue_contract(v6, v[0], v[2], v[4]); - } -} - -// Helper function that decodes two colors from six values. If isRGB is true, -// then the pointer 'v' contains four values and the last two are considered to be -// 0xFF. If isRGB is false, then all six values come from the pointer 'v'. This -// corresponds to the decode procedure for the following endpoint modes: -// kLDR_RGB_BaseScale_ColorEndpointMode -// kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode -static inline void decode_rgba_basescale(const int *v, SkColor *endpoints, bool isRGB) { - - int v4 = 0xFF; - int v5 = 0xFF; - if (!isRGB) { - v4 = v[4]; - v5 = v[5]; - } - - endpoints[0] = SkColorSetARGB(v4, - (v[0]*v[3]) >> 8, - (v[1]*v[3]) >> 8, - (v[2]*v[3]) >> 8); - endpoints[1] = SkColorSetARGB(v5, v[0], v[1], v[2]); -} - -// Helper function that decodes two colors from eight values. If isRGB is true, -// then the pointer 'v' contains six values and the last two are considered to be -// 0xFF. If isRGB is false, then all eight values come from the pointer 'v'. This -// corresponds to the decode procedure for the following endpoint modes: -// kLDR_RGB_BaseOffset_ColorEndpointMode -// kLDR_RGBA_BaseOffset_ColorEndpointMode -// -// If isRGB is true, then treat this as if v6 and v7 are meant to encode full alpha values. -static inline void decode_rgba_baseoffset(const int *v, SkColor *endpoints, bool isRGB) { - int v0 = v[0]; - int v1 = v[1]; - int v2 = v[2]; - int v3 = v[3]; - int v4 = v[4]; - int v5 = v[5]; - int v6 = isRGB ? 0xFF : v[6]; - // The 0 is here because this is an offset, not a direct value - int v7 = isRGB ? 0 : v[7]; - - bit_transfer_signed(&v1, &v0); - bit_transfer_signed(&v3, &v2); - bit_transfer_signed(&v5, &v4); - if (!isRGB) { - bit_transfer_signed(&v7, &v6); - } - - int c[2][4]; - if ((v1 + v3 + v5) >= 0) { - c[0][0] = v6; - c[0][1] = v0; - c[0][2] = v2; - c[0][3] = v4; - - c[1][0] = v6 + v7; - c[1][1] = v0 + v1; - c[1][2] = v2 + v3; - c[1][3] = v4 + v5; - } else { - c[0][0] = v6 + v7; - c[0][1] = (v0 + v1 + v4 + v5) >> 1; - c[0][2] = (v2 + v3 + v4 + v5) >> 1; - c[0][3] = v4 + v5; - - c[1][0] = v6; - c[1][1] = (v0 + v4) >> 1; - c[1][2] = (v2 + v4) >> 1; - c[1][3] = v4; - } - - endpoints[0] = SkColorSetARGB(clamp_byte(c[0][0]), - clamp_byte(c[0][1]), - clamp_byte(c[0][2]), - clamp_byte(c[0][3])); - - endpoints[1] = SkColorSetARGB(clamp_byte(c[1][0]), - clamp_byte(c[1][1]), - clamp_byte(c[1][2]), - clamp_byte(c[1][3])); -} - - -// A helper class used to decode bit values from standard integer values. -// We can't use this class with ASTCBlock because then it would need to -// handle multi-value ranges, and it's non-trivial to lookup a range of bits -// that splits across two different ints. -template -class SkTBits { -public: - SkTBits(const T val) : fVal(val) { } - - // Returns the bit at the given position - T operator [](const int idx) const { - return (fVal >> idx) & 1; - } - - // Returns the bits in the given range, inclusive - T operator ()(const int end, const int start) const { - SkASSERT(end >= start); - return (fVal >> start) & ((1ULL << ((end - start) + 1)) - 1); - } - -private: - const T fVal; -}; - -// This algorithm matches the trit block decoding in the spec (Table C.2.14) -static void decode_trit_block(int* dst, int nBits, const uint64_t &block) { - - SkTBits blockBits(block); - - // According to the spec, a trit block, which contains five values, - // has the following layout: - // - // 27 26 25 24 23 22 21 20 19 18 17 16 - // ----------------------------------------------- - // |T7 | m4 |T6 T5 | m3 |T4 | - // ----------------------------------------------- - // - // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - // -------------------------------------------------------------- - // | m2 |T3 T2 | m1 |T1 T0 | m0 | - // -------------------------------------------------------------- - // - // Where the m's are variable width depending on the number of bits used - // to encode the values (anywhere from 0 to 6). Since 3^5 = 243, the extra - // byte labeled T (whose bits are interleaved where 0 is the LSB and 7 is - // the MSB), contains five trit values. To decode the trit values, the spec - // says that we need to follow the following algorithm: - // - // if T[4:2] = 111 - // C = { T[7:5], T[1:0] }; t4 = t3 = 2 - // else - // C = T[4:0] - // - // if T[6:5] = 11 - // t4 = 2; t3 = T[7] - // else - // t4 = T[7]; t3 = T[6:5] - // - // if C[1:0] = 11 - // t2 = 2; t1 = C[4]; t0 = { C[3], C[2]&~C[3] } - // else if C[3:2] = 11 - // t2 = 2; t1 = 2; t0 = C[1:0] - // else - // t2 = C[4]; t1 = C[3:2]; t0 = { C[1], C[0]&~C[1] } - // - // The following C++ code is meant to mirror this layout and algorithm as - // closely as possible. - - int m[5]; - if (0 == nBits) { - memset(m, 0, sizeof(m)); - } else { - SkASSERT(nBits < 8); - m[0] = static_cast(blockBits(nBits - 1, 0)); - m[1] = static_cast(blockBits(2*nBits - 1 + 2, nBits + 2)); - m[2] = static_cast(blockBits(3*nBits - 1 + 4, 2*nBits + 4)); - m[3] = static_cast(blockBits(4*nBits - 1 + 5, 3*nBits + 5)); - m[4] = static_cast(blockBits(5*nBits - 1 + 7, 4*nBits + 7)); - } - - int T = - static_cast(blockBits(nBits + 1, nBits)) | - (static_cast(blockBits(2*nBits + 2 + 1, 2*nBits + 2)) << 2) | - (static_cast(blockBits[3*nBits + 4] << 4)) | - (static_cast(blockBits(4*nBits + 5 + 1, 4*nBits + 5)) << 5) | - (static_cast(blockBits[5*nBits + 7] << 7)); - - int t[5]; - - int C; - SkTBits Tbits(T); - if (0x7 == Tbits(4, 2)) { - C = (Tbits(7, 5) << 2) | Tbits(1, 0); - t[3] = t[4] = 2; - } else { - C = Tbits(4, 0); - if (Tbits(6, 5) == 0x3) { - t[4] = 2; t[3] = Tbits[7]; - } else { - t[4] = Tbits[7]; t[3] = Tbits(6, 5); - } - } - - SkTBits Cbits(C); - if (Cbits(1, 0) == 0x3) { - t[2] = 2; - t[1] = Cbits[4]; - t[0] = (Cbits[3] << 1) | (Cbits[2] & (0x1 & ~(Cbits[3]))); - } else if (Cbits(3, 2) == 0x3) { - t[2] = 2; - t[1] = 2; - t[0] = Cbits(1, 0); - } else { - t[2] = Cbits[4]; - t[1] = Cbits(3, 2); - t[0] = (Cbits[1] << 1) | (Cbits[0] & (0x1 & ~(Cbits[1]))); - } - -#ifdef SK_DEBUG - // Make sure all of the decoded values have a trit less than three - // and a bit value within the range of the allocated bits. - for (int i = 0; i < 5; ++i) { - SkASSERT(t[i] < 3); - SkASSERT(m[i] < (1 << nBits)); - } -#endif - - for (int i = 0; i < 5; ++i) { - *dst = (t[i] << nBits) + m[i]; - ++dst; - } -} - -// This algorithm matches the quint block decoding in the spec (Table C.2.15) -static void decode_quint_block(int* dst, int nBits, const uint64_t &block) { - SkTBits blockBits(block); - - // According to the spec, a quint block, which contains three values, - // has the following layout: - // - // - // 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - // -------------------------------------------------------------------------- - // |Q6 Q5 | m2 |Q4 Q3 | m1 |Q2 Q1 Q0 | m0 | - // -------------------------------------------------------------------------- - // - // Where the m's are variable width depending on the number of bits used - // to encode the values (anywhere from 0 to 4). Since 5^3 = 125, the extra - // 7-bit value labeled Q (whose bits are interleaved where 0 is the LSB and 6 is - // the MSB), contains three quint values. To decode the quint values, the spec - // says that we need to follow the following algorithm: - // - // if Q[2:1] = 11 and Q[6:5] = 00 - // q2 = { Q[0], Q[4]&~Q[0], Q[3]&~Q[0] }; q1 = q0 = 4 - // else - // if Q[2:1] = 11 - // q2 = 4; C = { Q[4:3], ~Q[6:5], Q[0] } - // else - // q2 = T[6:5]; C = Q[4:0] - // - // if C[2:0] = 101 - // q1 = 4; q0 = C[4:3] - // else - // q1 = C[4:3]; q0 = C[2:0] - // - // The following C++ code is meant to mirror this layout and algorithm as - // closely as possible. - - int m[3]; - if (0 == nBits) { - memset(m, 0, sizeof(m)); - } else { - SkASSERT(nBits < 8); - m[0] = static_cast(blockBits(nBits - 1, 0)); - m[1] = static_cast(blockBits(2*nBits - 1 + 3, nBits + 3)); - m[2] = static_cast(blockBits(3*nBits - 1 + 5, 2*nBits + 5)); - } - - int Q = - static_cast(blockBits(nBits + 2, nBits)) | - (static_cast(blockBits(2*nBits + 3 + 1, 2*nBits + 3)) << 3) | - (static_cast(blockBits(3*nBits + 5 + 1, 3*nBits + 5)) << 5); - - int q[3]; - SkTBits Qbits(Q); // quantum? - - if (Qbits(2, 1) == 0x3 && Qbits(6, 5) == 0) { - const int notBitZero = (0x1 & ~(Qbits[0])); - q[2] = (Qbits[0] << 2) | ((Qbits[4] & notBitZero) << 1) | (Qbits[3] & notBitZero); - q[1] = 4; - q[0] = 4; - } else { - int C; - if (Qbits(2, 1) == 0x3) { - q[2] = 4; - C = (Qbits(4, 3) << 3) | ((0x3 & ~(Qbits(6, 5))) << 1) | Qbits[0]; - } else { - q[2] = Qbits(6, 5); - C = Qbits(4, 0); - } - - SkTBits Cbits(C); - if (Cbits(2, 0) == 0x5) { - q[1] = 4; - q[0] = Cbits(4, 3); - } else { - q[1] = Cbits(4, 3); - q[0] = Cbits(2, 0); - } - } - -#ifdef SK_DEBUG - for (int i = 0; i < 3; ++i) { - SkASSERT(q[i] < 5); - SkASSERT(m[i] < (1 << nBits)); - } -#endif - - for (int i = 0; i < 3; ++i) { - *dst = (q[i] << nBits) + m[i]; - ++dst; - } -} - -// Function that decodes a sequence of integers stored as an ISE (Integer -// Sequence Encoding) bit stream. The full details of this function are outlined -// in section C.2.12 of the ASTC spec. A brief overview is as follows: -// -// - Each integer in the sequence is bounded by a specific range r. -// - The range of each value determines the way the bit stream is interpreted, -// - If the range is a power of two, then the sequence is a sequence of bits -// - If the range is of the form 3*2^n, then the sequence is stored as a -// sequence of blocks, each block contains 5 trits and 5 bit sequences, which -// decodes into 5 values. -// - Similarly, if the range is of the form 5*2^n, then the sequence is stored as a -// sequence of blocks, each block contains 3 quints and 3 bit sequences, which -// decodes into 3 values. -static bool decode_integer_sequence( - int* dst, // The array holding the destination bits - int dstSize, // The maximum size of the array - int nVals, // The number of values that we'd like to decode - const ASTCBlock &block, // The block that we're decoding from - int startBit, // The bit from which we're going to do the reading - int endBit, // The bit at which we stop reading (not inclusive) - bool bReadForward, // If true, then read LSB -> MSB, else read MSB -> LSB - int nBits, // The number of bits representing this encoding - int nTrits, // The number of trits representing this encoding - int nQuints // The number of quints representing this encoding -) { - // If we want more values than we have, then fail. - if (nVals > dstSize) { - return false; - } - - ASTCBlock src = block; - - if (!bReadForward) { - src.reverse(); - startBit = 128 - startBit; - endBit = 128 - endBit; - } - - while (nVals > 0) { - - if (nTrits > 0) { - SkASSERT(0 == nQuints); - - int endBlockBit = startBit + 8 + 5*nBits; - if (endBlockBit > endBit) { - endBlockBit = endBit; - } - - // Trit blocks are three values large. - int trits[5]; - decode_trit_block(trits, nBits, read_astc_bits(src, startBit, endBlockBit)); - memcpy(dst, trits, SkMin32(nVals, 5)*sizeof(int)); - - dst += 5; - nVals -= 5; - startBit = endBlockBit; - - } else if (nQuints > 0) { - SkASSERT(0 == nTrits); - - int endBlockBit = startBit + 7 + 3*nBits; - if (endBlockBit > endBit) { - endBlockBit = endBit; - } - - // Quint blocks are three values large - int quints[3]; - decode_quint_block(quints, nBits, read_astc_bits(src, startBit, endBlockBit)); - memcpy(dst, quints, SkMin32(nVals, 3)*sizeof(int)); - - dst += 3; - nVals -= 3; - startBit = endBlockBit; - - } else { - // Just read the bits, but don't read more than we have... - int endValBit = startBit + nBits; - if (endValBit > endBit) { - endValBit = endBit; - } - - SkASSERT(endValBit - startBit < 31); - *dst = static_cast(read_astc_bits(src, startBit, endValBit)); - ++dst; - --nVals; - startBit = endValBit; - } - } - - return true; -} - -// Helper function that unquantizes some (seemingly random) generated -// numbers... meant to match the ASTC hardware. This function is used -// to unquantize both colors (Table C.2.16) and weights (Table C.2.26) -static inline int unquantize_value(unsigned mask, int A, int B, int C, int D) { - int T = D * C + B; - T = T ^ A; - T = (A & mask) | (T >> 2); - SkASSERT(T < 256); - return T; -} - -// Helper function to replicate the bits in x that represents an oldPrec -// precision integer into a prec precision integer. For example: -// 255 == replicate_bits(7, 3, 8); -static inline int replicate_bits(int x, int oldPrec, int prec) { - while (oldPrec < prec) { - const int toShift = SkMin32(prec-oldPrec, oldPrec); - x = (x << toShift) | (x >> (oldPrec - toShift)); - oldPrec += toShift; - } - - // Make sure that no bits are set outside the desired precision. - SkASSERT((-(1 << prec) & x) == 0); - return x; -} - -// Returns the unquantized value of a color that's represented only as -// a set of bits. -static inline int unquantize_bits_color(int val, int nBits) { - return replicate_bits(val, nBits, 8); -} - -// Returns the unquantized value of a color that's represented as a -// trit followed by nBits bits. This algorithm follows the sequence -// defined in section C.2.13 of the ASTC spec. -static inline int unquantize_trit_color(int val, int nBits) { - SkASSERT(nBits > 0); - SkASSERT(nBits < 7); - - const int D = (val >> nBits) & 0x3; - SkASSERT(D < 3); - - const int A = -(val & 0x1) & 0x1FF; - - static const int Cvals[6] = { 204, 93, 44, 22, 11, 5 }; - const int C = Cvals[nBits - 1]; - - int B = 0; - const SkTBits valBits(val); - switch (nBits) { - case 1: - B = 0; - break; - - case 2: { - const int b = valBits[1]; - B = (b << 1) | (b << 2) | (b << 4) | (b << 8); - } - break; - - case 3: { - const int cb = valBits(2, 1); - B = cb | (cb << 2) | (cb << 7); - } - break; - - case 4: { - const int dcb = valBits(3, 1); - B = dcb | (dcb << 6); - } - break; - - case 5: { - const int edcb = valBits(4, 1); - B = (edcb << 5) | (edcb >> 2); - } - break; - - case 6: { - const int fedcb = valBits(5, 1); - B = (fedcb << 4) | (fedcb >> 4); - } - break; - } - - return unquantize_value(0x80, A, B, C, D); -} - -// Returns the unquantized value of a color that's represented as a -// quint followed by nBits bits. This algorithm follows the sequence -// defined in section C.2.13 of the ASTC spec. -static inline int unquantize_quint_color(int val, int nBits) { - const int D = (val >> nBits) & 0x7; - SkASSERT(D < 5); - - const int A = -(val & 0x1) & 0x1FF; - - static const int Cvals[5] = { 113, 54, 26, 13, 6 }; - SkASSERT(nBits > 0); - SkASSERT(nBits < 6); - - const int C = Cvals[nBits - 1]; - - int B = 0; - const SkTBits valBits(val); - switch (nBits) { - case 1: - B = 0; - break; - - case 2: { - const int b = valBits[1]; - B = (b << 2) | (b << 3) | (b << 8); - } - break; - - case 3: { - const int cb = valBits(2, 1); - B = (cb >> 1) | (cb << 1) | (cb << 7); - } - break; - - case 4: { - const int dcb = valBits(3, 1); - B = (dcb >> 1) | (dcb << 6); - } - break; - - case 5: { - const int edcb = valBits(4, 1); - B = (edcb << 5) | (edcb >> 3); - } - break; - } - - return unquantize_value(0x80, A, B, C, D); -} - -// This algorithm takes a list of integers, stored in vals, and unquantizes them -// in place. This follows the algorithm laid out in section C.2.13 of the ASTC spec. -static void unquantize_colors(int *vals, int nVals, int nBits, int nTrits, int nQuints) { - for (int i = 0; i < nVals; ++i) { - if (nTrits > 0) { - SkASSERT(nQuints == 0); - vals[i] = unquantize_trit_color(vals[i], nBits); - } else if (nQuints > 0) { - SkASSERT(nTrits == 0); - vals[i] = unquantize_quint_color(vals[i], nBits); - } else { - SkASSERT(nQuints == 0 && nTrits == 0); - vals[i] = unquantize_bits_color(vals[i], nBits); - } - } -} - -// Returns an interpolated value between c0 and c1 based on the weight. This -// follows the algorithm laid out in section C.2.19 of the ASTC spec. -static int interpolate_channel(int c0, int c1, int weight) { - SkASSERT(0 <= c0 && c0 < 256); - SkASSERT(0 <= c1 && c1 < 256); - - c0 = (c0 << 8) | c0; - c1 = (c1 << 8) | c1; - - const int result = ((c0*(64 - weight) + c1*weight + 32) / 64) >> 8; - - if (result > 255) { - return 255; - } - - SkASSERT(result >= 0); - return result; -} - -// Returns an interpolated color between the two endpoints based on the weight. -static SkColor interpolate_endpoints(const SkColor endpoints[2], int weight) { - return SkColorSetARGB( - interpolate_channel(SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]), weight), - interpolate_channel(SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]), weight), - interpolate_channel(SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]), weight), - interpolate_channel(SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]), weight)); -} - -// Returns an interpolated color between the two endpoints based on the weight. -// It uses separate weights for the channel depending on the value of the 'plane' -// variable. By default, all channels will use weight 0, and the value of plane -// means that weight1 will be used for: -// 0: red -// 1: green -// 2: blue -// 3: alpha -static SkColor interpolate_dual_endpoints( - const SkColor endpoints[2], int weight0, int weight1, int plane) { - int a = interpolate_channel(SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]), weight0); - int r = interpolate_channel(SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]), weight0); - int g = interpolate_channel(SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]), weight0); - int b = interpolate_channel(SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]), weight0); - - switch (plane) { - - case 0: - r = interpolate_channel( - SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]), weight1); - break; - - case 1: - g = interpolate_channel( - SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]), weight1); - break; - - case 2: - b = interpolate_channel( - SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]), weight1); - break; - - case 3: - a = interpolate_channel( - SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]), weight1); - break; - - default: - SkDEBUGFAIL("Plane should be 0-3"); - break; - } - - return SkColorSetARGB(a, r, g, b); -} - -// A struct of decoded values that we use to carry around information -// about the block. dimX and dimY are the dimension in texels of the block, -// for which there is only a limited subset of valid values: -// -// 4x4, 5x4, 5x5, 6x5, 6x6, 8x5, 8x6, 8x8, 10x5, 10x6, 10x8, 10x10, 12x10, 12x12 - -struct ASTCDecompressionData { - ASTCDecompressionData(int dimX, int dimY) : fDimX(dimX), fDimY(dimY) { } - const int fDimX; // the X dimension of the decompressed block - const int fDimY; // the Y dimension of the decompressed block - ASTCBlock fBlock; // the block data - int fBlockMode; // the block header that contains the block mode. - - bool fDualPlaneEnabled; // is this block compressing dual weight planes? - int fDualPlane; // the independent plane in dual plane mode. - - bool fVoidExtent; // is this block a single color? - bool fError; // does this block have an error encoding? - - int fWeightDimX; // the x dimension of the weight grid - int fWeightDimY; // the y dimension of the weight grid - - int fWeightBits; // the number of bits used for each weight value - int fWeightTrits; // the number of trits used for each weight value - int fWeightQuints; // the number of quints used for each weight value - - int fPartCount; // the number of partitions in this block - int fPartIndex; // the partition index: only relevant if fPartCount > 0 - - // CEM values can be anything in the range 0-15, and each corresponds to a different - // mode that represents the color data. We only support LDR modes. - enum ColorEndpointMode { - kLDR_Luminance_Direct_ColorEndpointMode = 0, - kLDR_Luminance_BaseOffset_ColorEndpointMode = 1, - kHDR_Luminance_LargeRange_ColorEndpointMode = 2, - kHDR_Luminance_SmallRange_ColorEndpointMode = 3, - kLDR_LuminanceAlpha_Direct_ColorEndpointMode = 4, - kLDR_LuminanceAlpha_BaseOffset_ColorEndpointMode = 5, - kLDR_RGB_BaseScale_ColorEndpointMode = 6, - kHDR_RGB_BaseScale_ColorEndpointMode = 7, - kLDR_RGB_Direct_ColorEndpointMode = 8, - kLDR_RGB_BaseOffset_ColorEndpointMode = 9, - kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode = 10, - kHDR_RGB_ColorEndpointMode = 11, - kLDR_RGBA_Direct_ColorEndpointMode = 12, - kLDR_RGBA_BaseOffset_ColorEndpointMode = 13, - kHDR_RGB_LDRAlpha_ColorEndpointMode = 14, - kHDR_RGB_HDRAlpha_ColorEndpointMode = 15 - }; - static const int kMaxColorEndpointModes = 16; - - // the color endpoint modes for this block. - static const int kMaxPartitions = 4; - ColorEndpointMode fCEM[kMaxPartitions]; - - int fColorStartBit; // The bit position of the first bit of the color data - int fColorEndBit; // The bit position of the last *possible* bit of the color data - - // Returns the number of partitions for this block. - int numPartitions() const { - return fPartCount; - } - - // Returns the total number of weight values that are stored in this block - int numWeights() const { - return fWeightDimX * fWeightDimY * (fDualPlaneEnabled ? 2 : 1); - } - -#ifdef SK_DEBUG - // Returns the maximum value that any weight can take. We really only use - // this function for debugging. - int maxWeightValue() const { - int maxVal = (1 << fWeightBits); - if (fWeightTrits > 0) { - SkASSERT(0 == fWeightQuints); - maxVal *= 3; - } else if (fWeightQuints > 0) { - SkASSERT(0 == fWeightTrits); - maxVal *= 5; - } - return maxVal - 1; - } -#endif - - // The number of bits needed to represent the texel weight data. This - // comes from the 'data size determination' section of the ASTC spec (C.2.22) - int numWeightBits() const { - const int nWeights = this->numWeights(); - return - ((nWeights*8*fWeightTrits + 4) / 5) + - ((nWeights*7*fWeightQuints + 2) / 3) + - (nWeights*fWeightBits); - } - - // Returns the number of color values stored in this block. The number of - // values stored is directly a function of the color endpoint modes. - int numColorValues() const { - int numValues = 0; - for (int i = 0; i < this->numPartitions(); ++i) { - int cemInt = static_cast(fCEM[i]); - numValues += ((cemInt >> 2) + 1) * 2; - } - - return numValues; - } - - // Figures out the number of bits available for color values, and fills - // in the maximum encoding that will fit the number of color values that - // we need. Returns false on error. (See section C.2.22 of the spec) - bool getColorValueEncoding(int *nBits, int *nTrits, int *nQuints) const { - if (nullptr == nBits || nullptr == nTrits || nullptr == nQuints) { - return false; - } - - const int nColorVals = this->numColorValues(); - if (nColorVals <= 0) { - return false; - } - - const int colorBits = fColorEndBit - fColorStartBit; - SkASSERT(colorBits > 0); - - // This is the minimum amount of accuracy required by the spec. - if (colorBits < ((13 * nColorVals + 4) / 5)) { - return false; - } - - // Values can be represented as at most 8-bit values. - // !SPEED! place this in a lookup table based on colorBits and nColorVals - for (int i = 255; i > 0; --i) { - int range = i + 1; - int bits = 0, trits = 0, quints = 0; - bool valid = false; - if (SkIsPow2(range)) { - bits = bits_for_range(range); - valid = true; - } else if ((range % 3) == 0 && SkIsPow2(range/3)) { - trits = 1; - bits = bits_for_range(range/3); - valid = true; - } else if ((range % 5) == 0 && SkIsPow2(range/5)) { - quints = 1; - bits = bits_for_range(range/5); - valid = true; - } - - if (valid) { - const int actualColorBits = - ((nColorVals*8*trits + 4) / 5) + - ((nColorVals*7*quints + 2) / 3) + - (nColorVals*bits); - if (actualColorBits <= colorBits) { - *nTrits = trits; - *nQuints = quints; - *nBits = bits; - return true; - } - } - } - - return false; - } - - // Converts the sequence of color values into endpoints. The algorithm here - // corresponds to the values determined by section C.2.14 of the ASTC spec - void colorEndpoints(SkColor endpoints[4][2], const int* colorValues) const { - for (int i = 0; i < this->numPartitions(); ++i) { - switch (fCEM[i]) { - case kLDR_Luminance_Direct_ColorEndpointMode: { - const int* v = colorValues; - endpoints[i][0] = SkColorSetARGB(0xFF, v[0], v[0], v[0]); - endpoints[i][1] = SkColorSetARGB(0xFF, v[1], v[1], v[1]); - - colorValues += 2; - } - break; - - case kLDR_Luminance_BaseOffset_ColorEndpointMode: { - const int* v = colorValues; - const int L0 = (v[0] >> 2) | (v[1] & 0xC0); - const int L1 = clamp_byte(L0 + (v[1] & 0x3F)); - - endpoints[i][0] = SkColorSetARGB(0xFF, L0, L0, L0); - endpoints[i][1] = SkColorSetARGB(0xFF, L1, L1, L1); - - colorValues += 2; - } - break; - - case kLDR_LuminanceAlpha_Direct_ColorEndpointMode: { - const int* v = colorValues; - - endpoints[i][0] = SkColorSetARGB(v[2], v[0], v[0], v[0]); - endpoints[i][1] = SkColorSetARGB(v[3], v[1], v[1], v[1]); - - colorValues += 4; - } - break; - - case kLDR_LuminanceAlpha_BaseOffset_ColorEndpointMode: { - int v0 = colorValues[0]; - int v1 = colorValues[1]; - int v2 = colorValues[2]; - int v3 = colorValues[3]; - - bit_transfer_signed(&v1, &v0); - bit_transfer_signed(&v3, &v2); - - endpoints[i][0] = SkColorSetARGB(v2, v0, v0, v0); - endpoints[i][1] = SkColorSetARGB( - clamp_byte(v3+v2), - clamp_byte(v1+v0), - clamp_byte(v1+v0), - clamp_byte(v1+v0)); - - colorValues += 4; - } - break; - - case kLDR_RGB_BaseScale_ColorEndpointMode: { - decode_rgba_basescale(colorValues, endpoints[i], true); - colorValues += 4; - } - break; - - case kLDR_RGB_Direct_ColorEndpointMode: { - decode_rgba_direct(colorValues, endpoints[i], true); - colorValues += 6; - } - break; - - case kLDR_RGB_BaseOffset_ColorEndpointMode: { - decode_rgba_baseoffset(colorValues, endpoints[i], true); - colorValues += 6; - } - break; - - case kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode: { - decode_rgba_basescale(colorValues, endpoints[i], false); - colorValues += 6; - } - break; - - case kLDR_RGBA_Direct_ColorEndpointMode: { - decode_rgba_direct(colorValues, endpoints[i], false); - colorValues += 8; - } - break; - - case kLDR_RGBA_BaseOffset_ColorEndpointMode: { - decode_rgba_baseoffset(colorValues, endpoints[i], false); - colorValues += 8; - } - break; - - default: - SkDEBUGFAIL("HDR mode unsupported! This should be caught sooner."); - break; - } - } - } - - // Follows the procedure from section C.2.17 of the ASTC specification - int unquantizeWeight(int x) const { - SkASSERT(x <= this->maxWeightValue()); - - const int D = (x >> fWeightBits) & 0x7; - const int A = -(x & 0x1) & 0x7F; - - SkTBits xbits(x); - - int T = 0; - if (fWeightTrits > 0) { - SkASSERT(0 == fWeightQuints); - switch (fWeightBits) { - case 0: { - // x is a single trit - SkASSERT(x < 3); - - static const int kUnquantizationTable[3] = { 0, 32, 63 }; - T = kUnquantizationTable[x]; - } - break; - - case 1: { - const int B = 0; - const int C = 50; - T = unquantize_value(0x20, A, B, C, D); - } - break; - - case 2: { - const int b = xbits[1]; - const int B = b | (b << 2) | (b << 6); - const int C = 23; - T = unquantize_value(0x20, A, B, C, D); - } - break; - - case 3: { - const int cb = xbits(2, 1); - const int B = cb | (cb << 5); - const int C = 11; - T = unquantize_value(0x20, A, B, C, D); - } - break; - - default: - SkDEBUGFAIL("Too many bits for trit encoding"); - break; - } - - } else if (fWeightQuints > 0) { - SkASSERT(0 == fWeightTrits); - switch (fWeightBits) { - case 0: { - // x is a single quint - SkASSERT(x < 5); - - static const int kUnquantizationTable[5] = { 0, 16, 32, 47, 63 }; - T = kUnquantizationTable[x]; - } - break; - - case 1: { - const int B = 0; - const int C = 28; - T = unquantize_value(0x20, A, B, C, D); - } - break; - - case 2: { - const int b = xbits[1]; - const int B = (b << 1) | (b << 6); - const int C = 13; - T = unquantize_value(0x20, A, B, C, D); - } - break; - - default: - SkDEBUGFAIL("Too many bits for quint encoding"); - break; - } - } else { - SkASSERT(0 == fWeightTrits); - SkASSERT(0 == fWeightQuints); - - T = replicate_bits(x, fWeightBits, 6); - } - - // This should bring the value within [0, 63].. - SkASSERT(T <= 63); - - if (T > 32) { - T += 1; - } - - SkASSERT(T <= 64); - - return T; - } - - // Returns the weight at the associated index. If the index is out of bounds, it - // returns zero. It also chooses the weight appropriately based on the given dual - // plane. - int getWeight(const int* unquantizedWeights, int idx, bool dualPlane) const { - const int maxIdx = (fDualPlaneEnabled ? 2 : 1) * fWeightDimX * fWeightDimY - 1; - if (fDualPlaneEnabled) { - const int effectiveIdx = 2*idx + (dualPlane ? 1 : 0); - if (effectiveIdx > maxIdx) { - return 0; - } - return unquantizedWeights[effectiveIdx]; - } - - SkASSERT(!dualPlane); - - if (idx > maxIdx) { - return 0; - } else { - return unquantizedWeights[idx]; - } - } - - // This computes the effective weight at location (s, t) of the block. This - // weight is computed by sampling the texel weight grid (it's usually not 1-1), and - // then applying a bilerp. The algorithm outlined here follows the algorithm - // defined in section C.2.18 of the ASTC spec. - int infillWeight(const int* unquantizedValues, int s, int t, bool dualPlane) const { - const int Ds = (1024 + fDimX/2) / (fDimX - 1); - const int Dt = (1024 + fDimY/2) / (fDimY - 1); - - const int cs = Ds * s; - const int ct = Dt * t; - - const int gs = (cs*(fWeightDimX - 1) + 32) >> 6; - const int gt = (ct*(fWeightDimY - 1) + 32) >> 6; - - const int js = gs >> 4; - const int jt = gt >> 4; - - const int fs = gs & 0xF; - const int ft = gt & 0xF; - - const int idx = js + jt*fWeightDimX; - const int p00 = this->getWeight(unquantizedValues, idx, dualPlane); - const int p01 = this->getWeight(unquantizedValues, idx + 1, dualPlane); - const int p10 = this->getWeight(unquantizedValues, idx + fWeightDimX, dualPlane); - const int p11 = this->getWeight(unquantizedValues, idx + fWeightDimX + 1, dualPlane); - - const int w11 = (fs*ft + 8) >> 4; - const int w10 = ft - w11; - const int w01 = fs - w11; - const int w00 = 16 - fs - ft + w11; - - const int weight = (p00*w00 + p01*w01 + p10*w10 + p11*w11 + 8) >> 4; - SkASSERT(weight <= 64); - return weight; - } - - // Unquantizes the decoded texel weights as described in section C.2.17 of - // the ASTC specification. Additionally, it populates texelWeights with - // the expanded weight grid, which is computed according to section C.2.18 - void texelWeights(int texelWeights[2][12][12], const int* texelValues) const { - // Unquantized texel weights... - int unquantizedValues[144*2]; // 12x12 blocks with dual plane decoding... - SkASSERT(this->numWeights() <= 144*2); - - // Unquantize the weights and cache them - for (int j = 0; j < this->numWeights(); ++j) { - unquantizedValues[j] = this->unquantizeWeight(texelValues[j]); - } - - // Do weight infill... - for (int y = 0; y < fDimY; ++y) { - for (int x = 0; x < fDimX; ++x) { - texelWeights[0][x][y] = this->infillWeight(unquantizedValues, x, y, false); - if (fDualPlaneEnabled) { - texelWeights[1][x][y] = this->infillWeight(unquantizedValues, x, y, true); - } - } - } - } - - // Returns the partition for the texel located at position (x, y). - // Adapted from C.2.21 of the ASTC specification - int getPartition(int x, int y) const { - const int partitionCount = this->numPartitions(); - int seed = fPartIndex; - if ((fDimX * fDimY) < 31) { - x <<= 1; - y <<= 1; - } - - seed += (partitionCount - 1) * 1024; - - uint32_t p = seed; - p ^= p >> 15; p -= p << 17; p += p << 7; p += p << 4; - p ^= p >> 5; p += p << 16; p ^= p >> 7; p ^= p >> 3; - p ^= p << 6; p ^= p >> 17; - - uint32_t rnum = p; - uint8_t seed1 = rnum & 0xF; - uint8_t seed2 = (rnum >> 4) & 0xF; - uint8_t seed3 = (rnum >> 8) & 0xF; - uint8_t seed4 = (rnum >> 12) & 0xF; - uint8_t seed5 = (rnum >> 16) & 0xF; - uint8_t seed6 = (rnum >> 20) & 0xF; - uint8_t seed7 = (rnum >> 24) & 0xF; - uint8_t seed8 = (rnum >> 28) & 0xF; - uint8_t seed9 = (rnum >> 18) & 0xF; - uint8_t seed10 = (rnum >> 22) & 0xF; - uint8_t seed11 = (rnum >> 26) & 0xF; - uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF; - - seed1 *= seed1; seed2 *= seed2; - seed3 *= seed3; seed4 *= seed4; - seed5 *= seed5; seed6 *= seed6; - seed7 *= seed7; seed8 *= seed8; - seed9 *= seed9; seed10 *= seed10; - seed11 *= seed11; seed12 *= seed12; - - int sh1, sh2, sh3; - if (0 != (seed & 1)) { - sh1 = (0 != (seed & 2))? 4 : 5; - sh2 = (partitionCount == 3)? 6 : 5; - } else { - sh1 = (partitionCount==3)? 6 : 5; - sh2 = (0 != (seed & 2))? 4 : 5; - } - sh3 = (0 != (seed & 0x10))? sh1 : sh2; - - seed1 >>= sh1; seed2 >>= sh2; seed3 >>= sh1; seed4 >>= sh2; - seed5 >>= sh1; seed6 >>= sh2; seed7 >>= sh1; seed8 >>= sh2; - seed9 >>= sh3; seed10 >>= sh3; seed11 >>= sh3; seed12 >>= sh3; - - const int z = 0; - int a = seed1*x + seed2*y + seed11*z + (rnum >> 14); - int b = seed3*x + seed4*y + seed12*z + (rnum >> 10); - int c = seed5*x + seed6*y + seed9 *z + (rnum >> 6); - int d = seed7*x + seed8*y + seed10*z + (rnum >> 2); - - a &= 0x3F; - b &= 0x3F; - c &= 0x3F; - d &= 0x3F; - - if (partitionCount < 4) { - d = 0; - } - - if (partitionCount < 3) { - c = 0; - } - - if (a >= b && a >= c && a >= d) { - return 0; - } else if (b >= c && b >= d) { - return 1; - } else if (c >= d) { - return 2; - } else { - return 3; - } - } - - // Performs the proper interpolation of the texel based on the - // endpoints and weights. - SkColor getTexel(const SkColor endpoints[4][2], - const int weights[2][12][12], - int x, int y) const { - int part = 0; - if (this->numPartitions() > 1) { - part = this->getPartition(x, y); - } - - SkColor result; - if (fDualPlaneEnabled) { - result = interpolate_dual_endpoints( - endpoints[part], weights[0][x][y], weights[1][x][y], fDualPlane); - } else { - result = interpolate_endpoints(endpoints[part], weights[0][x][y]); - } - -#if 1 - // !FIXME! if we're writing directly to a bitmap, then we don't need - // to swap the red and blue channels, but since we're usually being used - // by the SkImageDecoder_astc module, the results are expected to be in RGBA. - result = SkColorSetARGB( - SkColorGetA(result), SkColorGetB(result), SkColorGetG(result), SkColorGetR(result)); -#endif - - return result; - } - - void decode() { - // First decode the block mode. - this->decodeBlockMode(); - - // Now we can decode the partition information. - fPartIndex = static_cast(read_astc_bits(fBlock, 11, 23)); - fPartCount = (fPartIndex & 0x3) + 1; - fPartIndex >>= 2; - - // This is illegal - if (fDualPlaneEnabled && this->numPartitions() == 4) { - fError = true; - return; - } - - // Based on the partition info, we can decode the color information. - this->decodeColorData(); - } - - // Decodes the dual plane based on the given bit location. The final - // location, if the dual plane is enabled, is also the end of our color data. - // This function is only meant to be used from this->decodeColorData() - void decodeDualPlane(int bitLoc) { - if (fDualPlaneEnabled) { - fDualPlane = static_cast(read_astc_bits(fBlock, bitLoc - 2, bitLoc)); - fColorEndBit = bitLoc - 2; - } else { - fColorEndBit = bitLoc; - } - } - - // Decodes the color information based on the ASTC spec. - void decodeColorData() { - - // By default, the last color bit is at the end of the texel weights - const int lastWeight = 128 - this->numWeightBits(); - - // If we have a dual plane then it will be at this location, too. - int dualPlaneBitLoc = lastWeight; - - // If there's only one partition, then our job is (relatively) easy. - if (this->numPartitions() == 1) { - fCEM[0] = static_cast(read_astc_bits(fBlock, 13, 17)); - fColorStartBit = 17; - - // Handle dual plane mode... - this->decodeDualPlane(dualPlaneBitLoc); - - return; - } - - // If we have more than one partition, then we need to make - // room for the partition index. - fColorStartBit = 29; - - // Read the base CEM. If it's zero, then we have no additional - // CEM data and the endpoints for each partition share the same CEM. - const int baseCEM = static_cast(read_astc_bits(fBlock, 23, 25)); - if (0 == baseCEM) { - - const ColorEndpointMode sameCEM = - static_cast(read_astc_bits(fBlock, 25, 29)); - - for (int i = 0; i < kMaxPartitions; ++i) { - fCEM[i] = sameCEM; - } - - // Handle dual plane mode... - this->decodeDualPlane(dualPlaneBitLoc); - - return; - } - - // Move the dual plane selector bits down based on how many - // partitions the block contains. - switch (this->numPartitions()) { - case 2: - dualPlaneBitLoc -= 2; - break; - - case 3: - dualPlaneBitLoc -= 5; - break; - - case 4: - dualPlaneBitLoc -= 8; - break; - - default: - SkDEBUGFAIL("Internal ASTC decoding error."); - break; - } - - // The rest of the CEM config will be between the dual plane bit selector - // and the texel weight grid. - const int lowCEM = static_cast(read_astc_bits(fBlock, 23, 29)); - SkASSERT(lastWeight >= dualPlaneBitLoc); - SkASSERT(lastWeight - dualPlaneBitLoc < 31); - int fullCEM = static_cast(read_astc_bits(fBlock, dualPlaneBitLoc, lastWeight)); - - // Attach the config at the end of the weight grid to the CEM values - // in the beginning of the block. - fullCEM = (fullCEM << 6) | lowCEM; - - // Ignore the two least significant bits, since those are our baseCEM above. - fullCEM = fullCEM >> 2; - - int C[kMaxPartitions]; // Next, decode C and M from the spec (Table C.2.12) - for (int i = 0; i < this->numPartitions(); ++i) { - C[i] = fullCEM & 1; - fullCEM = fullCEM >> 1; - } - - int M[kMaxPartitions]; - for (int i = 0; i < this->numPartitions(); ++i) { - M[i] = fullCEM & 0x3; - fullCEM = fullCEM >> 2; - } - - // Construct our CEMs.. - SkASSERT(baseCEM > 0); - for (int i = 0; i < this->numPartitions(); ++i) { - int cem = (baseCEM - 1) * 4; - cem += (0 == C[i])? 0 : 4; - cem += M[i]; - - SkASSERT(cem < 16); - fCEM[i] = static_cast(cem); - } - - // Finally, if we have dual plane mode, then read the plane selector. - this->decodeDualPlane(dualPlaneBitLoc); - } - - // Decodes the block mode. This function determines whether or not we use - // dual plane encoding, the size of the texel weight grid, and the number of - // bits, trits and quints that are used to encode it. For more information, - // see section C.2.10 of the ASTC spec. - // - // For 2D blocks, the Block Mode field is laid out as follows: - // - // ------------------------------------------------------------------------- - // 10 9 8 7 6 5 4 3 2 1 0 Width Height Notes - // ------------------------------------------------------------------------- - // D H B A R0 0 0 R2 R1 B+4 A+2 - // D H B A R0 0 1 R2 R1 B+8 A+2 - // D H B A R0 1 0 R2 R1 A+2 B+8 - // D H 0 B A R0 1 1 R2 R1 A+2 B+6 - // D H 1 B A R0 1 1 R2 R1 B+2 A+2 - // D H 0 0 A R0 R2 R1 0 0 12 A+2 - // D H 0 1 A R0 R2 R1 0 0 A+2 12 - // D H 1 1 0 0 R0 R2 R1 0 0 6 10 - // D H 1 1 0 1 R0 R2 R1 0 0 10 6 - // B 1 0 A R0 R2 R1 0 0 A+6 B+6 D=0, H=0 - // x x 1 1 1 1 1 1 1 0 0 - - Void-extent - // x x 1 1 1 x x x x 0 0 - - Reserved* - // x x x x x x x 0 0 0 0 - - Reserved - // ------------------------------------------------------------------------- - // - // D - dual plane enabled - // H, R - used to determine the number of bits/trits/quints in texel weight encoding - // R is a three bit value whose LSB is R0 and MSB is R1 - // Width, Height - dimensions of the texel weight grid (determined by A and B) - - void decodeBlockMode() { - const int blockMode = static_cast(read_astc_bits(fBlock, 0, 11)); - - // Check for special void extent encoding - fVoidExtent = (blockMode & 0x1FF) == 0x1FC; - - // Check for reserved block modes - fError = ((blockMode & 0x1C3) == 0x1C0) || ((blockMode & 0xF) == 0); - - // Neither reserved nor void-extent, decode as usual - // This code corresponds to table C.2.8 of the ASTC spec - bool highPrecision = false; - int R = 0; - if ((blockMode & 0x3) == 0) { - R = ((0xC & blockMode) >> 1) | ((0x10 & blockMode) >> 4); - const int bitsSevenAndEight = (blockMode & 0x180) >> 7; - SkASSERT(0 <= bitsSevenAndEight && bitsSevenAndEight < 4); - - const int A = (blockMode >> 5) & 0x3; - const int B = (blockMode >> 9) & 0x3; - - fDualPlaneEnabled = (blockMode >> 10) & 0x1; - highPrecision = (blockMode >> 9) & 0x1; - - switch (bitsSevenAndEight) { - default: - case 0: - fWeightDimX = 12; - fWeightDimY = A + 2; - break; - - case 1: - fWeightDimX = A + 2; - fWeightDimY = 12; - break; - - case 2: - fWeightDimX = A + 6; - fWeightDimY = B + 6; - fDualPlaneEnabled = false; - highPrecision = false; - break; - - case 3: - if (0 == A) { - fWeightDimX = 6; - fWeightDimY = 10; - } else { - fWeightDimX = 10; - fWeightDimY = 6; - } - break; - } - } else { // (blockMode & 0x3) != 0 - R = ((blockMode & 0x3) << 1) | ((blockMode & 0x10) >> 4); - - const int bitsTwoAndThree = (blockMode >> 2) & 0x3; - SkASSERT(0 <= bitsTwoAndThree && bitsTwoAndThree < 4); - - const int A = (blockMode >> 5) & 0x3; - const int B = (blockMode >> 7) & 0x3; - - fDualPlaneEnabled = (blockMode >> 10) & 0x1; - highPrecision = (blockMode >> 9) & 0x1; - - switch (bitsTwoAndThree) { - case 0: - fWeightDimX = B + 4; - fWeightDimY = A + 2; - break; - case 1: - fWeightDimX = B + 8; - fWeightDimY = A + 2; - break; - case 2: - fWeightDimX = A + 2; - fWeightDimY = B + 8; - break; - case 3: - if ((B & 0x2) == 0) { - fWeightDimX = A + 2; - fWeightDimY = (B & 1) + 6; - } else { - fWeightDimX = (B & 1) + 2; - fWeightDimY = A + 2; - } - break; - } - } - - // We should have set the values of R and highPrecision - // from decoding the block mode, these are used to determine - // the proper dimensions of our weight grid. - if ((R & 0x6) == 0) { - fError = true; - } else { - static const int kBitAllocationTable[2][6][3] = { - { - { 1, 0, 0 }, - { 0, 1, 0 }, - { 2, 0, 0 }, - { 0, 0, 1 }, - { 1, 1, 0 }, - { 3, 0, 0 } - }, - { - { 1, 0, 1 }, - { 2, 1, 0 }, - { 4, 0, 0 }, - { 2, 0, 1 }, - { 3, 1, 0 }, - { 5, 0, 0 } - } - }; - - fWeightBits = kBitAllocationTable[highPrecision][R - 2][0]; - fWeightTrits = kBitAllocationTable[highPrecision][R - 2][1]; - fWeightQuints = kBitAllocationTable[highPrecision][R - 2][2]; - } - } -}; - -// Reads an ASTC block from the given pointer. -static inline void read_astc_block(ASTCDecompressionData *dst, const uint8_t* src) { - const uint64_t* qword = reinterpret_cast(src); - dst->fBlock.fLow = SkEndian_SwapLE64(qword[0]); - dst->fBlock.fHigh = SkEndian_SwapLE64(qword[1]); - dst->decode(); -} - -// Take a known void-extent block, and write out the values as a constant color. -static void decompress_void_extent(uint8_t* dst, int dstRowBytes, - const ASTCDecompressionData &data) { - // The top 64 bits contain 4 16-bit RGBA values. - int a = (static_cast(read_astc_bits(data.fBlock, 112, 128)) + 255) >> 8; - int b = (static_cast(read_astc_bits(data.fBlock, 96, 112)) + 255) >> 8; - int g = (static_cast(read_astc_bits(data.fBlock, 80, 96)) + 255) >> 8; - int r = (static_cast(read_astc_bits(data.fBlock, 64, 80)) + 255) >> 8; - - write_constant_color(dst, data.fDimX, data.fDimY, dstRowBytes, SkColorSetARGB(a, r, g, b)); -} - -// Decompresses a single ASTC block. It's assumed that data.fDimX and data.fDimY are -// set and that the block has already been decoded (i.e. data.decode() has been called) -static void decompress_astc_block(uint8_t* dst, int dstRowBytes, - const ASTCDecompressionData &data) { - if (data.fError) { - write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes); - return; - } - - if (data.fVoidExtent) { - decompress_void_extent(dst, dstRowBytes, data); - return; - } - - // According to the spec, any more than 64 values is illegal. (C.2.24) - static const int kMaxTexelValues = 64; - - // Decode the texel weights. - int texelValues[kMaxTexelValues]; - bool success = decode_integer_sequence( - texelValues, kMaxTexelValues, data.numWeights(), - // texel data goes to the end of the 128 bit block. - data.fBlock, 128, 128 - data.numWeightBits(), false, - data.fWeightBits, data.fWeightTrits, data.fWeightQuints); - - if (!success) { - write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes); - return; - } - - // Decode the color endpoints - int colorBits, colorTrits, colorQuints; - if (!data.getColorValueEncoding(&colorBits, &colorTrits, &colorQuints)) { - write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes); - return; - } - - // According to the spec, any more than 18 color values is illegal. (C.2.24) - static const int kMaxColorValues = 18; - - int colorValues[kMaxColorValues]; - success = decode_integer_sequence( - colorValues, kMaxColorValues, data.numColorValues(), - data.fBlock, data.fColorStartBit, data.fColorEndBit, true, - colorBits, colorTrits, colorQuints); - - if (!success) { - write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes); - return; - } - - // Unquantize the color values after they've been decoded. - unquantize_colors(colorValues, data.numColorValues(), colorBits, colorTrits, colorQuints); - - // Decode the colors into the appropriate endpoints. - SkColor endpoints[4][2]; - data.colorEndpoints(endpoints, colorValues); - - // Do texel infill and decode the texel values. - int texelWeights[2][12][12]; - data.texelWeights(texelWeights, texelValues); - - // Write the texels by interpolating them based on the information - // stored in the block. - dst += data.fDimY * dstRowBytes; - for (int y = 0; y < data.fDimY; ++y) { - dst -= dstRowBytes; - SkColor* colorPtr = reinterpret_cast(dst); - for (int x = 0; x < data.fDimX; ++x) { - colorPtr[x] = data.getTexel(endpoints, texelWeights, x, y); - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -// ASTC Comrpession Struct -// -//////////////////////////////////////////////////////////////////////////////// - -// This is the type passed as the CompressorType argument of the compressed -// blitter for the ASTC format. The static functions required to be in this -// struct are documented in SkTextureCompressor_Blitter.h -struct CompressorASTC { - static inline void CompressA8Vertical(uint8_t* dst, const uint8_t* src) { - compress_a8_astc_block(&dst, src, 12); - } - - static inline void CompressA8Horizontal(uint8_t* dst, const uint8_t* src, - int srcRowBytes) { - compress_a8_astc_block(&dst, src, srcRowBytes); - } - -#if PEDANTIC_BLIT_RECT - static inline void UpdateBlock(uint8_t* dst, const uint8_t* src, int srcRowBytes, - const uint8_t* mask) { - // TODO: krajcevski - // This is kind of difficult for ASTC because the weight values are calculated - // as an average of the actual weights. The best we can do is decompress the - // weights and recalculate them based on the new texel values. This should - // be "not too bad" since we know that anytime we hit this function, we're - // compressing 12x12 block dimension alpha-only, and we know the layout - // of the block - SkFAIL("Implement me!"); - } -#endif -}; - -//////////////////////////////////////////////////////////////////////////////// - -namespace SkTextureCompressor { - -bool CompressA8To12x12ASTC(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes) { - if (width < 0 || ((width % 12) != 0) || height < 0 || ((height % 12) != 0)) { - return false; - } - - uint8_t** dstPtr = &dst; - for (int y = 0; y < height; y += 12) { - for (int x = 0; x < width; x += 12) { - compress_a8_astc_block(dstPtr, src + y*rowBytes + x, rowBytes); - } - } - - return true; -} - -SkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer, - SkTBlitterAllocator* allocator) { - if ((width % 12) != 0 || (height % 12) != 0) { - return nullptr; - } - - // Memset the output buffer to an encoding that decodes to zero. We must do this - // in order to avoid having uninitialized values in the buffer if the blitter - // decides not to write certain scanlines (and skip entire rows of blocks). - // In the case of ASTC, if everything index is zero, then the interpolated value - // will decode to zero provided we have the right header. We use the encoding - // from recognizing all zero blocks from above. - const int nBlocks = (width * height / 144); - uint8_t *dst = reinterpret_cast(outputBuffer); - for (int i = 0; i < nBlocks; ++i) { - send_packing(&dst, SkTEndian_SwapLE64(0x0000000001FE000173ULL), 0); - } - - return allocator->createT< - SkTCompressedAlphaBlitter<12, 16, CompressorASTC>, int, int, void* > - (width, height, outputBuffer); -} - -void DecompressASTC(uint8_t* dst, int dstRowBytes, const uint8_t* src, - int width, int height, int blockDimX, int blockDimY) { - // ASTC is encoded in what they call "raster order", so that the first - // block is the bottom-left block in the image, and the first pixel - // is the bottom-left pixel of the image - dst += height * dstRowBytes; - - ASTCDecompressionData data(blockDimX, blockDimY); - for (int y = 0; y < height; y += blockDimY) { - dst -= blockDimY * dstRowBytes; - SkColor *colorPtr = reinterpret_cast(dst); - for (int x = 0; x < width; x += blockDimX) { - read_astc_block(&data, src); - decompress_astc_block(reinterpret_cast(colorPtr + x), dstRowBytes, data); - - // ASTC encoded blocks are 16 bytes (128 bits) large. - src += 16; - } - } -} - -} // SkTextureCompressor diff --git a/gfx/skia/skia/src/utils/SkTextureCompressor_ASTC.h b/gfx/skia/skia/src/utils/SkTextureCompressor_ASTC.h deleted file mode 100644 index 1312ee9c741b..000000000000 --- a/gfx/skia/skia/src/utils/SkTextureCompressor_ASTC.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkTextureCompressor_ASTC_DEFINED -#define SkTextureCompressor_ASTC_DEFINED - -#include "SkBitmapProcShader.h" - -class SkBlitter; - -namespace SkTextureCompressor { - - bool CompressA8To12x12ASTC(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes); - - SkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer, - SkTBlitterAllocator *allocator); - - void DecompressASTC(uint8_t* dst, int dstRowBytes, const uint8_t* src, - int width, int height, int blockDimX, int blockDimY); -} - -#endif // SkTextureCompressor_ASTC_DEFINED diff --git a/gfx/skia/skia/src/utils/SkTextureCompressor_Blitter.h b/gfx/skia/skia/src/utils/SkTextureCompressor_Blitter.h deleted file mode 100644 index f488707a372e..000000000000 --- a/gfx/skia/skia/src/utils/SkTextureCompressor_Blitter.h +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkTextureCompressor_Blitter_DEFINED -#define SkTextureCompressor_Blitter_DEFINED - -#include "SkTypes.h" -#include "SkBlitter.h" - -namespace SkTextureCompressor { - -// Ostensibly, SkBlitter::BlitRect is supposed to set a rect of pixels to full -// alpha. This becomes problematic when using compressed texture blitters, since -// the rect rarely falls along block boundaries. The proper way to handle this is -// to update the compressed encoding of a block by resetting the proper parameters -// (and even recompressing the block) where a rect falls inbetween block boundaries. -// PEDANTIC_BLIT_RECT attempts to do this by requiring the struct passed to -// SkTCompressedAlphaBlitter to implement an UpdateBlock function call. -// -// However, the way that BlitRect gets used almost exclusively is to bracket inverse -// fills for paths. In other words, the top few rows and bottom few rows of a path -// that's getting inverse filled are called using blitRect. The rest are called using -// the standard blitAntiH. As a result, we can just call blitAntiH with a faux RLE -// of full alpha values, and then check in our flush() call that we don't run off the -// edge of the buffer. This is why we do not need this flag to be turned on. -// -// NOTE: This code is unfinished, but is inteded as a starting point if an when -// bugs are introduced from the existing code. -#define PEDANTIC_BLIT_RECT 0 - -// This class implements a blitter that blits directly into a buffer that will -// be used as an compressed alpha texture. We compute this buffer by -// buffering scan lines and then outputting them all at once. The number of -// scan lines buffered is controlled by kBlockSize -// -// The CompressorType is a struct with a bunch of static methods that provides -// the specialized compression functionality of the blitter. A complete CompressorType -// will implement the following static functions; -// -// struct CompressorType { -// // The function used to compress an A8 block. The layout of the -// // block is also expected to be in column-major order. -// static void CompressA8Vertical(uint8_t* dst, const uint8_t block[]); -// -// // The function used to compress an A8 block. The layout of the -// // block is also expected to be in row-major order. -// static void CompressA8Horizontal(uint8_t* dst, const uint8_t* src, int srcRowBytes); -// -#if PEDANTIC_BLIT_RECT -// // The function used to update an already compressed block. This will -// // most likely be implementation dependent. The mask variable will have -// // 0xFF in positions where the block should be updated and 0 in positions -// // where it shouldn't. src contains an uncompressed buffer of pixels. -// static void UpdateBlock(uint8_t* dst, const uint8_t* src, int srcRowBytes, -// const uint8_t* mask); -#endif -// }; -template -class SkTCompressedAlphaBlitter : public SkBlitter { -public: - SkTCompressedAlphaBlitter(int width, int height, void *compressedBuffer) - // 0x7FFE is one minus the largest positive 16-bit int. We use it for - // debugging to make sure that we're properly setting the nextX distance - // in flushRuns(). -#ifdef SK_DEBUG - : fCalledOnceWithNonzeroY(false) - , fBlitMaskCalled(false), -#else - : -#endif - kLongestRun(0x7FFE), kZeroAlpha(0) - , fNextRun(0) - , fWidth(width) - , fHeight(height) - , fBuffer(compressedBuffer) - { - SkASSERT((width % BlockDim) == 0); - SkASSERT((height % BlockDim) == 0); - } - - virtual ~SkTCompressedAlphaBlitter() { this->flushRuns(); } - - // Blit a horizontal run of one or more pixels. - void blitH(int x, int y, int width) override { - // This function is intended to be called from any standard RGB - // buffer, so we should never encounter it. However, if some code - // path does end up here, then this needs to be investigated. - SkFAIL("Not implemented!"); - } - - // Blit a horizontal run of antialiased pixels; runs[] is a *sparse* - // zero-terminated run-length encoding of spans of constant alpha values. - void blitAntiH(int x, int y, - const SkAlpha antialias[], - const int16_t runs[]) override { - SkASSERT(0 == x); - - // Make sure that the new row to blit is either the first - // row that we're blitting, or it's exactly the next scan row - // since the last row that we blit. This is to ensure that when - // we go to flush the runs, that they are all the same four - // runs. - if (fNextRun > 0 && - ((x != fBufferedRuns[fNextRun-1].fX) || - (y-1 != fBufferedRuns[fNextRun-1].fY))) { - this->flushRuns(); - } - - // Align the rows to a block boundary. If we receive rows that - // are not on a block boundary, then fill in the preceding runs - // with zeros. We do this by producing a single RLE that says - // that we have 0x7FFE pixels of zero (0x7FFE = 32766). - const int row = BlockDim * (y / BlockDim); - while ((row + fNextRun) < y) { - fBufferedRuns[fNextRun].fAlphas = &kZeroAlpha; - fBufferedRuns[fNextRun].fRuns = &kLongestRun; - fBufferedRuns[fNextRun].fX = 0; - fBufferedRuns[fNextRun].fY = row + fNextRun; - ++fNextRun; - } - - // Make sure that our assumptions aren't violated... - SkASSERT(fNextRun == (y % BlockDim)); - SkASSERT(fNextRun == 0 || fBufferedRuns[fNextRun - 1].fY < y); - - // Set the values of the next run - fBufferedRuns[fNextRun].fAlphas = antialias; - fBufferedRuns[fNextRun].fRuns = runs; - fBufferedRuns[fNextRun].fX = x; - fBufferedRuns[fNextRun].fY = y; - - // If we've output a block of scanlines in a row that don't violate our - // assumptions, then it's time to flush them... - if (BlockDim == ++fNextRun) { - this->flushRuns(); - } - } - - // Blit a vertical run of pixels with a constant alpha value. - void blitV(int x, int y, int height, SkAlpha alpha) override { - // This function is currently not implemented. It is not explicitly - // required by the contract, but if at some time a code path runs into - // this function (which is entirely possible), it needs to be implemented. - // - // TODO (krajcevski): - // This function will be most easily implemented in one of two ways: - // 1. Buffer each vertical column value and then construct a list - // of alpha values and output all of the blocks at once. This only - // requires a write to the compressed buffer - // 2. Replace the indices of each block with the proper indices based - // on the alpha value. This requires a read and write of the compressed - // buffer, but much less overhead. - SkFAIL("Not implemented!"); - } - - // Blit a solid rectangle one or more pixels wide. It's assumed that blitRect - // is called as a way to bracket blitAntiH where above and below the path the - // called path just needs a solid rectangle to fill in the mask. -#ifdef SK_DEBUG - bool fCalledOnceWithNonzeroY; -#endif - void blitRect(int x, int y, int width, int height) override { - - // Assumptions: - SkASSERT(0 == x); - SkASSERT(width <= fWidth); - - // Make sure that we're only ever bracketing calls to blitAntiH. - SkASSERT((0 == y) || (!fCalledOnceWithNonzeroY && (fCalledOnceWithNonzeroY = true))); - -#if !(PEDANTIC_BLIT_RECT) - for (int i = 0; i < height; ++i) { - const SkAlpha kFullAlpha = 0xFF; - this->blitAntiH(x, y+i, &kFullAlpha, &kLongestRun); - } -#else - const int startBlockX = (x / BlockDim) * BlockDim; - const int startBlockY = (y / BlockDim) * BlockDim; - - const int endBlockX = ((x + width) / BlockDim) * BlockDim; - const int endBlockY = ((y + height) / BlockDim) * BlockDim; - - // If start and end are the same, then we only need to update a single block... - if (startBlockY == endBlockY && startBlockX == endBlockX) { - uint8_t mask[BlockDim*BlockDim]; - memset(mask, 0, sizeof(mask)); - - const int xoff = x - startBlockX; - SkASSERT((xoff + width) <= BlockDim); - - const int yoff = y - startBlockY; - SkASSERT((yoff + height) <= BlockDim); - - for (int j = 0; j < height; ++j) { - memset(mask + (j + yoff)*BlockDim + xoff, 0xFF, width); - } - - uint8_t* dst = this->getBlock(startBlockX, startBlockY); - CompressorType::UpdateBlock(dst, mask, BlockDim, mask); - - // If start and end are the same in the y dimension, then we can freely update an - // entire row of blocks... - } else if (startBlockY == endBlockY) { - - this->updateBlockRow(x, y, width, height, startBlockY, startBlockX, endBlockX); - - // Similarly, if the start and end are in the same column, then we can just update - // an entire column of blocks... - } else if (startBlockX == endBlockX) { - - this->updateBlockCol(x, y, width, height, startBlockX, startBlockY, endBlockY); - - // Otherwise, the rect spans a non-trivial region of blocks, and we have to construct - // a kind of 9-patch to update each of the pieces of the rect. The top and bottom - // rows are updated using updateBlockRow, and the left and right columns are updated - // using updateBlockColumn. Anything in the middle is simply memset to an opaque block - // encoding. - } else { - - const int innerStartBlockX = startBlockX + BlockDim; - const int innerStartBlockY = startBlockY + BlockDim; - - // Blit top row - const int topRowHeight = innerStartBlockY - y; - this->updateBlockRow(x, y, width, topRowHeight, startBlockY, - startBlockX, endBlockX); - - // Advance y - y += topRowHeight; - height -= topRowHeight; - - // Blit middle - if (endBlockY > innerStartBlockY) { - - // Update left row - this->updateBlockCol(x, y, innerStartBlockX - x, endBlockY, startBlockY, - startBlockX, innerStartBlockX); - - // Update the middle with an opaque encoding... - uint8_t mask[BlockDim*BlockDim]; - memset(mask, 0xFF, sizeof(mask)); - - uint8_t opaqueEncoding[EncodedBlockSize]; - CompressorType::CompressA8Horizontal(opaqueEncoding, mask, BlockDim); - - for (int j = innerStartBlockY; j < endBlockY; j += BlockDim) { - uint8_t* opaqueDst = this->getBlock(innerStartBlockX, j); - for (int i = innerStartBlockX; i < endBlockX; i += BlockDim) { - memcpy(opaqueDst, opaqueEncoding, EncodedBlockSize); - opaqueDst += EncodedBlockSize; - } - } - - // If we need to update the right column, do that too - if (x + width > endBlockX) { - this->updateBlockCol(endBlockX, y, x + width - endBlockX, endBlockY, - endBlockX, innerStartBlockY, endBlockY); - } - - // Advance y - height = y + height - endBlockY; - y = endBlockY; - } - - // If we need to update the last row, then do that, too. - if (height > 0) { - this->updateBlockRow(x, y, width, height, endBlockY, - startBlockX, endBlockX); - } - } -#endif - } - - // Blit a rectangle with one alpha-blended column on the left, - // width (zero or more) opaque pixels, and one alpha-blended column - // on the right. The result will always be at least two pixels wide. - void blitAntiRect(int x, int y, int width, int height, - SkAlpha leftAlpha, SkAlpha rightAlpha) override { - // This function is currently not implemented. It is not explicitly - // required by the contract, but if at some time a code path runs into - // this function (which is entirely possible), it needs to be implemented. - // - // TODO (krajcevski): - // This function will be most easily implemented as follows: - // 1. If width/height are smaller than a block, then update the - // indices of the affected blocks. - // 2. If width/height are larger than a block, then construct a 9-patch - // of block encodings that represent the rectangle, and write them - // to the compressed buffer as necessary. Whether or not the blocks - // are overwritten by zeros or just their indices are updated is up - // to debate. - SkFAIL("Not implemented!"); - } - - // Blit a pattern of pixels defined by a rectangle-clipped mask; We make an - // assumption here that if this function gets called, then it will replace all - // of the compressed texture blocks that it touches. Hence, two separate calls - // to blitMask that have clips next to one another will cause artifacts. Most - // of the time, however, this function gets called because constructing the mask - // was faster than constructing the RLE for blitAntiH, and this function will - // only be called once. -#ifdef SK_DEBUG - bool fBlitMaskCalled; -#endif - void blitMask(const SkMask& mask, const SkIRect& clip) override { - - // Assumptions: - SkASSERT(!fBlitMaskCalled); - SkDEBUGCODE(fBlitMaskCalled = true); - SkASSERT(SkMask::kA8_Format == mask.fFormat); - SkASSERT(mask.fBounds.contains(clip)); - - // Start from largest block boundary less than the clip boundaries. - const int startI = BlockDim * (clip.left() / BlockDim); - const int startJ = BlockDim * (clip.top() / BlockDim); - - for (int j = startJ; j < clip.bottom(); j += BlockDim) { - - // Get the destination for this block row - uint8_t* dst = this->getBlock(startI, j); - for (int i = startI; i < clip.right(); i += BlockDim) { - - // At this point, the block should intersect the clip. - SkASSERT(SkIRect::IntersectsNoEmptyCheck( - SkIRect::MakeXYWH(i, j, BlockDim, BlockDim), clip)); - - // Do we need to pad it? - if (i < clip.left() || j < clip.top() || - i + BlockDim > clip.right() || j + BlockDim > clip.bottom()) { - - uint8_t block[BlockDim*BlockDim]; - memset(block, 0, sizeof(block)); - - const int startX = SkMax32(i, clip.left()); - const int startY = SkMax32(j, clip.top()); - - const int endX = SkMin32(i + BlockDim, clip.right()); - const int endY = SkMin32(j + BlockDim, clip.bottom()); - - for (int y = startY; y < endY; ++y) { - const int col = startX - i; - const int row = y - j; - const int valsWide = endX - startX; - SkASSERT(valsWide <= BlockDim); - SkASSERT(0 <= col && col < BlockDim); - SkASSERT(0 <= row && row < BlockDim); - memcpy(block + row*BlockDim + col, - mask.getAddr8(startX, j + row), valsWide); - } - - CompressorType::CompressA8Horizontal(dst, block, BlockDim); - } else { - // Otherwise, just compress it. - uint8_t*const src = mask.getAddr8(i, j); - const uint32_t rb = mask.fRowBytes; - CompressorType::CompressA8Horizontal(dst, src, rb); - } - - dst += EncodedBlockSize; - } - } - } - - // If the blitter just sets a single value for each pixel, return the - // bitmap it draws into, and assign value. If not, return nullptr and ignore - // the value parameter. - const SkPixmap* justAnOpaqueColor(uint32_t* value) override { - return nullptr; - } - - /** - * Compressed texture blitters only really work correctly if they get - * BlockDim rows at a time. That being said, this blitter tries it's best - * to preserve semantics if blitAntiH doesn't get called in too many - * weird ways... - */ - int requestRowsPreserved() const override { return BlockDim; } - -private: - static const int kPixelsPerBlock = BlockDim * BlockDim; - - // The longest possible run of pixels that this blitter will receive. - // This is initialized in the constructor to 0x7FFE, which is one less - // than the largest positive 16-bit integer. We make sure that it's one - // less for debugging purposes. We also don't make this variable static - // in order to make sure that we can construct a valid pointer to it. - const int16_t kLongestRun; - - // Usually used in conjunction with kLongestRun. This is initialized to - // zero. - const SkAlpha kZeroAlpha; - - // This is the information that we buffer whenever we're asked to blit - // a row with this blitter. - struct BufferedRun { - const SkAlpha* fAlphas; - const int16_t* fRuns; - int fX, fY; - } fBufferedRuns[BlockDim]; - - // The next row [0, BlockDim) that we need to blit. - int fNextRun; - - // The width and height of the image that we're blitting - const int fWidth; - const int fHeight; - - // The compressed buffer that we're blitting into. It is assumed that the buffer - // is large enough to store a compressed image of size fWidth*fHeight. - void* const fBuffer; - - // Various utility functions - int blocksWide() const { return fWidth / BlockDim; } - int blocksTall() const { return fHeight / BlockDim; } - int totalBlocks() const { return (fWidth * fHeight) / kPixelsPerBlock; } - - // Returns the block index for the block containing pixel (x, y). Block - // indices start at zero and proceed in raster order. - int getBlockOffset(int x, int y) const { - SkASSERT(x < fWidth); - SkASSERT(y < fHeight); - const int blockCol = x / BlockDim; - const int blockRow = y / BlockDim; - return blockRow * this->blocksWide() + blockCol; - } - - // Returns a pointer to the block containing pixel (x, y) - uint8_t *getBlock(int x, int y) const { - uint8_t* ptr = reinterpret_cast(fBuffer); - return ptr + EncodedBlockSize*this->getBlockOffset(x, y); - } - - // Updates the block whose columns are stored in block. curAlphai is expected - // to store the alpha values that will be placed within each of the columns in - // the range [col, col+colsLeft). - typedef uint32_t Column[BlockDim/4]; - typedef uint32_t Block[BlockDim][BlockDim/4]; - inline void updateBlockColumns(Block block, const int col, - const int colsLeft, const Column curAlphai) { - SkASSERT(block); - SkASSERT(col + colsLeft <= BlockDim); - - for (int i = col; i < (col + colsLeft); ++i) { - memcpy(block[i], curAlphai, sizeof(Column)); - } - } - - // The following function writes the buffered runs to compressed blocks. - // If fNextRun < BlockDim, then we fill the runs that we haven't buffered with - // the constant zero buffer. - void flushRuns() { - // If we don't have any runs, then just return. - if (0 == fNextRun) { - return; - } - -#ifndef NDEBUG - // Make sure that if we have any runs, they all match - for (int i = 1; i < fNextRun; ++i) { - SkASSERT(fBufferedRuns[i].fY == fBufferedRuns[i-1].fY + 1); - SkASSERT(fBufferedRuns[i].fX == fBufferedRuns[i-1].fX); - } -#endif - - // If we don't have as many runs as we have rows, fill in the remaining - // runs with constant zeros. - for (int i = fNextRun; i < BlockDim; ++i) { - fBufferedRuns[i].fY = fBufferedRuns[0].fY + i; - fBufferedRuns[i].fX = fBufferedRuns[0].fX; - fBufferedRuns[i].fAlphas = &kZeroAlpha; - fBufferedRuns[i].fRuns = &kLongestRun; - } - - // Make sure that our assumptions aren't violated. - SkASSERT(fNextRun > 0 && fNextRun <= BlockDim); - SkASSERT((fBufferedRuns[0].fY % BlockDim) == 0); - - // The following logic walks BlockDim rows at a time and outputs compressed - // blocks to the buffer passed into the constructor. - // We do the following: - // - // c1 c2 c3 c4 - // ----------------------------------------------------------------------- - // ... | | | | | ----> fBufferedRuns[0] - // ----------------------------------------------------------------------- - // ... | | | | | ----> fBufferedRuns[1] - // ----------------------------------------------------------------------- - // ... | | | | | ----> fBufferedRuns[2] - // ----------------------------------------------------------------------- - // ... | | | | | ----> fBufferedRuns[3] - // ----------------------------------------------------------------------- - // - // curX -- the macro X value that we've gotten to. - // c[BlockDim] -- the buffers that represent the columns of the current block - // that we're operating on - // curAlphaColumn -- buffer containing the column of alpha values from fBufferedRuns. - // nextX -- for each run, the next point at which we need to update curAlphaColumn - // after the value of curX. - // finalX -- the minimum of all the nextX values. - // - // curX advances to finalX outputting any blocks that it passes along - // the way. Since finalX will not change when we reach the end of a - // run, the termination criteria will be whenever curX == finalX at the - // end of a loop. - - // Setup: - Block block; - sk_bzero(block, sizeof(block)); - - Column curAlphaColumn; - sk_bzero(curAlphaColumn, sizeof(curAlphaColumn)); - - SkAlpha *curAlpha = reinterpret_cast(&curAlphaColumn); - - int nextX[BlockDim]; - for (int i = 0; i < BlockDim; ++i) { - nextX[i] = 0x7FFFFF; - } - - uint8_t* outPtr = this->getBlock(fBufferedRuns[0].fX, fBufferedRuns[0].fY); - - // Populate the first set of runs and figure out how far we need to - // advance on the first step - int curX = 0; - int finalX = 0xFFFFF; - for (int i = 0; i < BlockDim; ++i) { - nextX[i] = *(fBufferedRuns[i].fRuns); - curAlpha[i] = *(fBufferedRuns[i].fAlphas); - - finalX = SkMin32(nextX[i], finalX); - } - - // Make sure that we have a valid right-bound X value - SkASSERT(finalX < 0xFFFFF); - - // If the finalX is the longest run, then just blit until we have - // width... - if (kLongestRun == finalX) { - finalX = fWidth; - } - - // Run the blitter... - while (curX != finalX) { - SkASSERT(finalX >= curX); - - // Do we need to populate the rest of the block? - if ((finalX - (BlockDim*(curX / BlockDim))) >= BlockDim) { - const int col = curX % BlockDim; - const int colsLeft = BlockDim - col; - SkASSERT(curX + colsLeft <= finalX); - - this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); - - // Write this block - CompressorType::CompressA8Vertical(outPtr, reinterpret_cast(block)); - outPtr += EncodedBlockSize; - curX += colsLeft; - } - - // If we can advance even further, then just keep memsetting the block - if ((finalX - curX) >= BlockDim) { - SkASSERT((curX % BlockDim) == 0); - - const int col = 0; - const int colsLeft = BlockDim; - - this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); - - // While we can keep advancing, just keep writing the block. - uint8_t lastBlock[EncodedBlockSize]; - CompressorType::CompressA8Vertical(lastBlock, reinterpret_cast(block)); - while((finalX - curX) >= BlockDim) { - memcpy(outPtr, lastBlock, EncodedBlockSize); - outPtr += EncodedBlockSize; - curX += BlockDim; - } - } - - // If we haven't advanced within the block then do so. - if (curX < finalX) { - const int col = curX % BlockDim; - const int colsLeft = finalX - curX; - - this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); - curX += colsLeft; - } - - SkASSERT(curX == finalX); - - // Figure out what the next advancement is... - if (finalX < fWidth) { - for (int i = 0; i < BlockDim; ++i) { - if (nextX[i] == finalX) { - const int16_t run = *(fBufferedRuns[i].fRuns); - fBufferedRuns[i].fRuns += run; - fBufferedRuns[i].fAlphas += run; - curAlpha[i] = *(fBufferedRuns[i].fAlphas); - nextX[i] += *(fBufferedRuns[i].fRuns); - } - } - - finalX = 0xFFFFF; - for (int i = 0; i < BlockDim; ++i) { - finalX = SkMin32(nextX[i], finalX); - } - } else { - curX = finalX; - } - } - - // If we didn't land on a block boundary, output the block... - if ((curX % BlockDim) > 0) { -#ifdef SK_DEBUG - for (int i = 0; i < BlockDim; ++i) { - SkASSERT(nextX[i] == kLongestRun || nextX[i] == curX); - } -#endif - const int col = curX % BlockDim; - const int colsLeft = BlockDim - col; - - memset(curAlphaColumn, 0, sizeof(curAlphaColumn)); - this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); - - CompressorType::CompressA8Vertical(outPtr, reinterpret_cast(block)); - } - - fNextRun = 0; - } - -#if PEDANTIC_BLIT_RECT - void updateBlockRow(int x, int y, int width, int height, - int blockRow, int startBlockX, int endBlockX) { - if (0 == width || 0 == height || startBlockX == endBlockX) { - return; - } - - uint8_t* dst = this->getBlock(startBlockX, BlockDim * (y / BlockDim)); - - // One horizontal strip to update - uint8_t mask[BlockDim*BlockDim]; - memset(mask, 0, sizeof(mask)); - - // Update the left cap - int blockX = startBlockX; - const int yoff = y - blockRow; - for (int j = 0; j < height; ++j) { - const int xoff = x - blockX; - memset(mask + (j + yoff)*BlockDim + xoff, 0xFF, BlockDim - xoff); - } - CompressorType::UpdateBlock(dst, mask, BlockDim, mask); - dst += EncodedBlockSize; - blockX += BlockDim; - - // Update the middle - if (blockX < endBlockX) { - for (int j = 0; j < height; ++j) { - memset(mask + (j + yoff)*BlockDim, 0xFF, BlockDim); - } - while (blockX < endBlockX) { - CompressorType::UpdateBlock(dst, mask, BlockDim, mask); - dst += EncodedBlockSize; - blockX += BlockDim; - } - } - - SkASSERT(endBlockX == blockX); - - // Update the right cap (if we need to) - if (x + width > endBlockX) { - memset(mask, 0, sizeof(mask)); - for (int j = 0; j < height; ++j) { - const int xoff = (x+width-blockX); - memset(mask + (j+yoff)*BlockDim, 0xFF, xoff); - } - CompressorType::UpdateBlock(dst, mask, BlockDim, mask); - } - } - - void updateBlockCol(int x, int y, int width, int height, - int blockCol, int startBlockY, int endBlockY) { - if (0 == width || 0 == height || startBlockY == endBlockY) { - return; - } - - // One vertical strip to update - uint8_t mask[BlockDim*BlockDim]; - memset(mask, 0, sizeof(mask)); - const int maskX0 = x - blockCol; - const int maskWidth = maskX0 + width; - SkASSERT(maskWidth <= BlockDim); - - // Update the top cap - int blockY = startBlockY; - for (int j = (y - blockY); j < BlockDim; ++j) { - memset(mask + maskX0 + j*BlockDim, 0xFF, maskWidth); - } - CompressorType::UpdateBlock(this->getBlock(blockCol, blockY), mask, BlockDim, mask); - blockY += BlockDim; - - // Update middle - if (blockY < endBlockY) { - for (int j = 0; j < BlockDim; ++j) { - memset(mask + maskX0 + j*BlockDim, 0xFF, maskWidth); - } - while (blockY < endBlockY) { - CompressorType::UpdateBlock(this->getBlock(blockCol, blockY), - mask, BlockDim, mask); - blockY += BlockDim; - } - } - - SkASSERT(endBlockY == blockY); - - // Update bottom - if (y + height > endBlockY) { - for (int j = y+height; j < endBlockY + BlockDim; ++j) { - memset(mask + (j-endBlockY)*BlockDim, 0, BlockDim); - } - CompressorType::UpdateBlock(this->getBlock(blockCol, blockY), - mask, BlockDim, mask); - } - } -#endif // PEDANTIC_BLIT_RECT - -}; - -} // namespace SkTextureCompressor - -#endif // SkTextureCompressor_Blitter_DEFINED diff --git a/gfx/skia/skia/src/utils/SkTextureCompressor_LATC.cpp b/gfx/skia/skia/src/utils/SkTextureCompressor_LATC.cpp deleted file mode 100644 index 50aaf0b275ca..000000000000 --- a/gfx/skia/skia/src/utils/SkTextureCompressor_LATC.cpp +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTextureCompressor_LATC.h" -#include "SkTextureCompressor_Blitter.h" -#include "SkTextureCompressor_Utils.h" - -#include "SkBlitter.h" -#include "SkEndian.h" - -// Compression options. In general, the slow version is much more accurate, but -// much slower. The fast option is much faster, but much less accurate. YMMV. -#define COMPRESS_LATC_SLOW 0 -#define COMPRESS_LATC_FAST 1 - -//////////////////////////////////////////////////////////////////////////////// - -// Generates an LATC palette. LATC constructs -// a palette of eight colors from LUM0 and LUM1 using the algorithm: -// -// LUM0, if lum0 > lum1 and code(x,y) == 0 -// LUM1, if lum0 > lum1 and code(x,y) == 1 -// (6*LUM0+ LUM1)/7, if lum0 > lum1 and code(x,y) == 2 -// (5*LUM0+2*LUM1)/7, if lum0 > lum1 and code(x,y) == 3 -// (4*LUM0+3*LUM1)/7, if lum0 > lum1 and code(x,y) == 4 -// (3*LUM0+4*LUM1)/7, if lum0 > lum1 and code(x,y) == 5 -// (2*LUM0+5*LUM1)/7, if lum0 > lum1 and code(x,y) == 6 -// ( LUM0+6*LUM1)/7, if lum0 > lum1 and code(x,y) == 7 -// -// LUM0, if lum0 <= lum1 and code(x,y) == 0 -// LUM1, if lum0 <= lum1 and code(x,y) == 1 -// (4*LUM0+ LUM1)/5, if lum0 <= lum1 and code(x,y) == 2 -// (3*LUM0+2*LUM1)/5, if lum0 <= lum1 and code(x,y) == 3 -// (2*LUM0+3*LUM1)/5, if lum0 <= lum1 and code(x,y) == 4 -// ( LUM0+4*LUM1)/5, if lum0 <= lum1 and code(x,y) == 5 -// 0, if lum0 <= lum1 and code(x,y) == 6 -// 255, if lum0 <= lum1 and code(x,y) == 7 - -static const int kLATCPaletteSize = 8; -static void generate_latc_palette(uint8_t palette[], uint8_t lum0, uint8_t lum1) { - palette[0] = lum0; - palette[1] = lum1; - if (lum0 > lum1) { - for (int i = 1; i < 7; i++) { - palette[i+1] = ((7-i)*lum0 + i*lum1) / 7; - } - } else { - for (int i = 1; i < 5; i++) { - palette[i+1] = ((5-i)*lum0 + i*lum1) / 5; - } - palette[6] = 0; - palette[7] = 255; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -#if COMPRESS_LATC_SLOW - -//////////////////////////////////////////////////////////////////////////////// -// -// Utility Functions -// -//////////////////////////////////////////////////////////////////////////////// - -// Absolute difference between two values. More correct than SkTAbs(a - b) -// because it works on unsigned values. -template inline T abs_diff(const T &a, const T &b) { - return (a > b) ? (a - b) : (b - a); -} - -static bool is_extremal(uint8_t pixel) { - return 0 == pixel || 255 == pixel; -} - -typedef uint64_t (*A84x4To64BitProc)(const uint8_t block[]); - -// This function is used by both R11 EAC and LATC to compress 4x4 blocks -// of 8-bit alpha into 64-bit values that comprise the compressed data. -// For both formats, we need to make sure that the dimensions of the -// src pixels are divisible by 4, and copy 4x4 blocks one at a time -// for compression. -static bool compress_4x4_a8_to_64bit(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes, - A84x4To64BitProc proc) { - // Make sure that our data is well-formed enough to be considered for compression - if (0 == width || 0 == height || (width % 4) != 0 || (height % 4) != 0) { - return false; - } - - int blocksX = width >> 2; - int blocksY = height >> 2; - - uint8_t block[16]; - uint64_t* encPtr = reinterpret_cast(dst); - for (int y = 0; y < blocksY; ++y) { - for (int x = 0; x < blocksX; ++x) { - // Load block - for (int k = 0; k < 4; ++k) { - memcpy(block + k*4, src + k*rowBytes + 4*x, 4); - } - - // Compress it - *encPtr = proc(block); - ++encPtr; - } - src += 4 * rowBytes; - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// -// LATC compressor -// -//////////////////////////////////////////////////////////////////////////////// - -// LATC compressed texels down into square 4x4 blocks -static const int kLATCBlockSize = 4; -static const int kLATCPixelsPerBlock = kLATCBlockSize * kLATCBlockSize; - -// Compress a block by using the bounding box of the pixels. It is assumed that -// there are no extremal pixels in this block otherwise we would have used -// compressBlockBBIgnoreExtremal. -static uint64_t compress_latc_block_bb(const uint8_t pixels[]) { - uint8_t minVal = 255; - uint8_t maxVal = 0; - for (int i = 0; i < kLATCPixelsPerBlock; ++i) { - minVal = SkTMin(pixels[i], minVal); - maxVal = SkTMax(pixels[i], maxVal); - } - - SkASSERT(!is_extremal(minVal)); - SkASSERT(!is_extremal(maxVal)); - - uint8_t palette[kLATCPaletteSize]; - generate_latc_palette(palette, maxVal, minVal); - - uint64_t indices = 0; - for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) { - - // Find the best palette index - uint8_t bestError = abs_diff(pixels[i], palette[0]); - uint8_t idx = 0; - for (int j = 1; j < kLATCPaletteSize; ++j) { - uint8_t error = abs_diff(pixels[i], palette[j]); - if (error < bestError) { - bestError = error; - idx = j; - } - } - - indices <<= 3; - indices |= idx; - } - - return - SkEndian_SwapLE64( - static_cast(maxVal) | - (static_cast(minVal) << 8) | - (indices << 16)); -} - -// Compress a block by using the bounding box of the pixels without taking into -// account the extremal values. The generated palette will contain extremal values -// and fewer points along the line segment to interpolate. -static uint64_t compress_latc_block_bb_ignore_extremal(const uint8_t pixels[]) { - uint8_t minVal = 255; - uint8_t maxVal = 0; - for (int i = 0; i < kLATCPixelsPerBlock; ++i) { - if (is_extremal(pixels[i])) { - continue; - } - - minVal = SkTMin(pixels[i], minVal); - maxVal = SkTMax(pixels[i], maxVal); - } - - SkASSERT(!is_extremal(minVal)); - SkASSERT(!is_extremal(maxVal)); - - uint8_t palette[kLATCPaletteSize]; - generate_latc_palette(palette, minVal, maxVal); - - uint64_t indices = 0; - for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) { - - // Find the best palette index - uint8_t idx = 0; - if (is_extremal(pixels[i])) { - if (0xFF == pixels[i]) { - idx = 7; - } else if (0 == pixels[i]) { - idx = 6; - } else { - SkFAIL("Pixel is extremal but not really?!"); - } - } else { - uint8_t bestError = abs_diff(pixels[i], palette[0]); - for (int j = 1; j < kLATCPaletteSize - 2; ++j) { - uint8_t error = abs_diff(pixels[i], palette[j]); - if (error < bestError) { - bestError = error; - idx = j; - } - } - } - - indices <<= 3; - indices |= idx; - } - - return - SkEndian_SwapLE64( - static_cast(minVal) | - (static_cast(maxVal) << 8) | - (indices << 16)); -} - - -// Compress LATC block. Each 4x4 block of pixels is decompressed by LATC from two -// values LUM0 and LUM1, and an index into the generated palette. Details of how -// the palette is generated can be found in the comments of generatePalette above. -// -// We choose which palette type to use based on whether or not 'pixels' contains -// any extremal values (0 or 255). If there are extremal values, then we use the -// palette that has the extremal values built in. Otherwise, we use the full bounding -// box. - -static uint64_t compress_latc_block(const uint8_t pixels[]) { - // Collect unique pixels - int nUniquePixels = 0; - uint8_t uniquePixels[kLATCPixelsPerBlock]; - for (int i = 0; i < kLATCPixelsPerBlock; ++i) { - bool foundPixel = false; - for (int j = 0; j < nUniquePixels; ++j) { - foundPixel = foundPixel || uniquePixels[j] == pixels[i]; - } - - if (!foundPixel) { - uniquePixels[nUniquePixels] = pixels[i]; - ++nUniquePixels; - } - } - - // If there's only one unique pixel, then our compression is easy. - if (1 == nUniquePixels) { - return SkEndian_SwapLE64(pixels[0] | (pixels[0] << 8)); - - // Similarly, if there are only two unique pixels, then our compression is - // easy again: place the pixels in the block header, and assign the indices - // with one or zero depending on which pixel they belong to. - } else if (2 == nUniquePixels) { - uint64_t outBlock = 0; - for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) { - int idx = 0; - if (pixels[i] == uniquePixels[1]) { - idx = 1; - } - - outBlock <<= 3; - outBlock |= idx; - } - outBlock <<= 16; - outBlock |= (uniquePixels[0] | (uniquePixels[1] << 8)); - return SkEndian_SwapLE64(outBlock); - } - - // Count non-maximal pixel values - int nonExtremalPixels = 0; - for (int i = 0; i < nUniquePixels; ++i) { - if (!is_extremal(uniquePixels[i])) { - ++nonExtremalPixels; - } - } - - // If all the pixels are nonmaximal then compute the palette using - // the bounding box of all the pixels. - if (nonExtremalPixels == nUniquePixels) { - // This is really just for correctness, in all of my tests we - // never take this step. We don't lose too much perf here because - // most of the processing in this function is worth it for the - // 1 == nUniquePixels optimization. - return compress_latc_block_bb(pixels); - } else { - return compress_latc_block_bb_ignore_extremal(pixels); - } -} - -#endif // COMPRESS_LATC_SLOW - -//////////////////////////////////////////////////////////////////////////////// - -#if COMPRESS_LATC_FAST - -// Take the top three bits of each index and pack them into the low 12 -// bits of the integer. -static inline uint32_t pack_index(uint32_t x) { - // Pack it in... -#if defined (SK_CPU_BENDIAN) - return - (x >> 24) | - ((x >> 13) & 0x38) | - ((x >> 2) & 0x1C0) | - ((x << 9) & 0xE00); -#else - return - (x & 0x7) | - ((x >> 5) & 0x38) | - ((x >> 10) & 0x1C0) | - ((x >> 15) & 0xE00); -#endif -} - -// Converts each 8-bit byte in the integer into an LATC index, and then packs -// the indices into the low 12 bits of the integer. -static inline uint32_t convert_index(uint32_t x) { - // Since the palette is - // 255, 0, 219, 182, 146, 109, 73, 36 - // we need to map the high three bits of each byte in the integer - // from - // 0 1 2 3 4 5 6 7 - // to - // 1 7 6 5 4 3 2 0 - // - // This first operation takes the mapping from - // 0 1 2 3 4 5 6 7 --> 7 6 5 4 3 2 1 0 - x = 0x07070707 - SkTextureCompressor::ConvertToThreeBitIndex(x); - - // mask is 1 if index is non-zero - const uint32_t mask = (x | (x >> 1) | (x >> 2)) & 0x01010101; - - // add mask: - // 7 6 5 4 3 2 1 0 --> 8 7 6 5 4 3 2 0 - x = (x + mask); - - // Handle overflow: - // 8 7 6 5 4 3 2 0 --> 9 7 6 5 4 3 2 0 - x |= (x >> 3) & 0x01010101; - - // Mask out high bits: - // 9 7 6 5 4 3 2 0 --> 1 7 6 5 4 3 2 0 - x &= 0x07070707; - - return pack_index(x); -} - -typedef uint64_t (*PackIndicesProc)(const uint8_t* alpha, size_t rowBytes); -template -static void compress_a8_latc_block(uint8_t** dstPtr, const uint8_t* src, size_t rowBytes) { - *(reinterpret_cast(*dstPtr)) = - SkEndian_SwapLE64(0xFF | (packIndicesProc(src, rowBytes) << 16)); - *dstPtr += 8; -} - -inline uint64_t PackRowMajor(const uint8_t *indices, size_t rowBytes) { - uint64_t result = 0; - for (int i = 0; i < 4; ++i) { - const uint32_t idx = *(reinterpret_cast(indices + i*rowBytes)); - result |= static_cast(convert_index(idx)) << 12*i; - } - return result; -} - -inline uint64_t PackColumnMajor(const uint8_t *indices, size_t rowBytes) { - // !SPEED! Blarg, this is kind of annoying. SSE4 can make this - // a LOT faster. - uint8_t transposed[16]; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - transposed[j*4+i] = indices[i*rowBytes + j]; - } - } - - return PackRowMajor(transposed, 4); -} - -static bool compress_4x4_a8_latc(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes) { - - if (width < 0 || ((width % 4) != 0) || height < 0 || ((height % 4) != 0)) { - return false; - } - - uint8_t** dstPtr = &dst; - for (int y = 0; y < height; y += 4) { - for (int x = 0; x < width; x += 4) { - compress_a8_latc_block(dstPtr, src + y*rowBytes + x, rowBytes); - } - } - - return true; -} - -void CompressA8LATCBlockVertical(uint8_t* dst, const uint8_t block[]) { - compress_a8_latc_block(&dst, block, 4); -} - -#endif // COMPRESS_LATC_FAST - -void decompress_latc_block(uint8_t* dst, int dstRowBytes, const uint8_t* src) { - uint64_t block = SkEndian_SwapLE64(*(reinterpret_cast(src))); - uint8_t lum0 = block & 0xFF; - uint8_t lum1 = (block >> 8) & 0xFF; - - uint8_t palette[kLATCPaletteSize]; - generate_latc_palette(palette, lum0, lum1); - - block >>= 16; - for (int j = 0; j < 4; ++j) { - for (int i = 0; i < 4; ++i) { - dst[i] = palette[block & 0x7]; - block >>= 3; - } - dst += dstRowBytes; - } -} - -// This is the type passed as the CompressorType argument of the compressed -// blitter for the LATC format. The static functions required to be in this -// struct are documented in SkTextureCompressor_Blitter.h -struct CompressorLATC { - static inline void CompressA8Vertical(uint8_t* dst, const uint8_t block[]) { - compress_a8_latc_block(&dst, block, 4); - } - - static inline void CompressA8Horizontal(uint8_t* dst, const uint8_t* src, - int srcRowBytes) { - compress_a8_latc_block(&dst, src, srcRowBytes); - } - -#if PEDANTIC_BLIT_RECT - static inline void UpdateBlock(uint8_t* dst, const uint8_t* src, int srcRowBytes, - const uint8_t* mask) { - // Pack the mask - uint64_t cmpMask = 0; - for (int i = 0; i < 4; ++i) { - const uint32_t idx = *(reinterpret_cast(src + i*srcRowBytes)); - cmpMask |= static_cast(pack_index(idx)) << 12*i; - } - cmpMask = SkEndian_SwapLE64(cmpMask << 16); // avoid header - - uint64_t cmpSrc; - uint8_t *cmpSrcPtr = reinterpret_cast(&cmpSrc); - compress_a8_latc_block(&cmpSrcPtr, src, srcRowBytes); - - // Mask out header - cmpSrc = cmpSrc & cmpMask; - - // Read destination encoding - uint64_t *cmpDst = reinterpret_cast(dst); - - // If the destination is the encoding for a blank block, then we need - // to properly set the header - if (0 == cmpDst) { - *cmpDst = SkTEndian_SwapLE64(0x24924924924900FFULL); - } - - // Set the new indices - *cmpDst &= ~cmpMask; - *cmpDst |= cmpSrc; - } -#endif // PEDANTIC_BLIT_RECT -}; - -//////////////////////////////////////////////////////////////////////////////// - -namespace SkTextureCompressor { - -bool CompressA8ToLATC(uint8_t* dst, const uint8_t* src, int width, int height, size_t rowBytes) { -#if COMPRESS_LATC_FAST - return compress_4x4_a8_latc(dst, src, width, height, rowBytes); -#elif COMPRESS_LATC_SLOW - return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_latc_block); -#else -#error "Must choose either fast or slow LATC compression" -#endif -} - -SkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer, - SkTBlitterAllocator* allocator) { - if ((width % 4) != 0 || (height % 4) != 0) { - return nullptr; - } - -#if COMPRESS_LATC_FAST - // Memset the output buffer to an encoding that decodes to zero. We must do this - // in order to avoid having uninitialized values in the buffer if the blitter - // decides not to write certain scanlines (and skip entire rows of blocks). - // In the case of LATC, if everything is zero, then LUM0 and LUM1 are also zero, - // and they will only be non-zero (0xFF) if the index is 7. So bzero will do just fine. - // (8 bytes per block) * (w * h / 16 blocks) = w * h / 2 - sk_bzero(outputBuffer, width * height / 2); - - return allocator->createT< - SkTCompressedAlphaBlitter<4, 8, CompressorLATC>, int, int, void* > - (width, height, outputBuffer); -#elif COMPRESS_LATC_SLOW - // TODO (krajcevski) - return nullptr; -#endif -} - -void DecompressLATC(uint8_t* dst, int dstRowBytes, const uint8_t* src, int width, int height) { - for (int j = 0; j < height; j += 4) { - for (int i = 0; i < width; i += 4) { - decompress_latc_block(dst + i, dstRowBytes, src); - src += 8; - } - dst += 4 * dstRowBytes; - } -} - -} // SkTextureCompressor diff --git a/gfx/skia/skia/src/utils/SkTextureCompressor_LATC.h b/gfx/skia/skia/src/utils/SkTextureCompressor_LATC.h deleted file mode 100644 index 85647eafcc42..000000000000 --- a/gfx/skia/skia/src/utils/SkTextureCompressor_LATC.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkTextureCompressor_LATC_DEFINED -#define SkTextureCompressor_LATC_DEFINED - -#include "SkBitmapProcShader.h" - -class SkBlitter; - -namespace SkTextureCompressor { - - bool CompressA8ToLATC(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes); - - SkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer, - SkTBlitterAllocator *allocator); - - void DecompressLATC(uint8_t* dst, int dstRowBytes, const uint8_t* src, int width, int height); -} - -#endif // SkTextureCompressor_LATC_DEFINED diff --git a/gfx/skia/skia/src/utils/SkTextureCompressor_R11EAC.cpp b/gfx/skia/skia/src/utils/SkTextureCompressor_R11EAC.cpp deleted file mode 100644 index 5c298dda9a0c..000000000000 --- a/gfx/skia/skia/src/utils/SkTextureCompressor_R11EAC.cpp +++ /dev/null @@ -1,670 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTextureCompressor.h" -#include "SkTextureCompressor_Blitter.h" -#include "SkTextureCompressor_Utils.h" - -#include "SkBlitter.h" -#include "SkEndian.h" - -// #define COMPRESS_R11_EAC_SLOW 1 -// #define COMPRESS_R11_EAC_FAST 1 -#define COMPRESS_R11_EAC_FASTEST 1 - -// Blocks compressed into R11 EAC are represented as follows: -// 0000000000000000000000000000000000000000000000000000000000000000 -// |base_cw|mod|mul| ----------------- indices ------------------- -// -// To reconstruct the value of a given pixel, we use the formula: -// clamp[0, 2047](base_cw * 8 + 4 + mod_val*mul*8) -// -// mod_val is chosen from a palette of values based on the index of the -// given pixel. The palette is chosen by the value stored in mod. -// This formula returns a value between 0 and 2047, which is converted -// to a float from 0 to 1 in OpenGL. -// -// If mul is zero, then we set mul = 1/8, so that the formula becomes -// clamp[0, 2047](base_cw * 8 + 4 + mod_val) - -static const int kNumR11EACPalettes = 16; -static const int kR11EACPaletteSize = 8; -static const int kR11EACModifierPalettes[kNumR11EACPalettes][kR11EACPaletteSize] = { - {-3, -6, -9, -15, 2, 5, 8, 14}, - {-3, -7, -10, -13, 2, 6, 9, 12}, - {-2, -5, -8, -13, 1, 4, 7, 12}, - {-2, -4, -6, -13, 1, 3, 5, 12}, - {-3, -6, -8, -12, 2, 5, 7, 11}, - {-3, -7, -9, -11, 2, 6, 8, 10}, - {-4, -7, -8, -11, 3, 6, 7, 10}, - {-3, -5, -8, -11, 2, 4, 7, 10}, - {-2, -6, -8, -10, 1, 5, 7, 9}, - {-2, -5, -8, -10, 1, 4, 7, 9}, - {-2, -4, -8, -10, 1, 3, 7, 9}, - {-2, -5, -7, -10, 1, 4, 6, 9}, - {-3, -4, -7, -10, 2, 3, 6, 9}, - {-1, -2, -3, -10, 0, 1, 2, 9}, - {-4, -6, -8, -9, 3, 5, 7, 8}, - {-3, -5, -7, -9, 2, 4, 6, 8} -}; - -#if COMPRESS_R11_EAC_SLOW - -// Pack the base codeword, palette, and multiplier into the 64 bits necessary -// to decode it. -static uint64_t pack_r11eac_block(uint16_t base_cw, uint16_t palette, uint16_t multiplier, - uint64_t indices) { - SkASSERT(palette < 16); - SkASSERT(multiplier < 16); - SkASSERT(indices < (static_cast(1) << 48)); - - const uint64_t b = static_cast(base_cw) << 56; - const uint64_t m = static_cast(multiplier) << 52; - const uint64_t p = static_cast(palette) << 48; - return SkEndian_SwapBE64(b | m | p | indices); -} - -// Given a base codeword, a modifier, and a multiplier, compute the proper -// pixel value in the range [0, 2047]. -static uint16_t compute_r11eac_pixel(int base_cw, int modifier, int multiplier) { - int ret = (base_cw * 8 + 4) + (modifier * multiplier * 8); - return (ret > 2047)? 2047 : ((ret < 0)? 0 : ret); -} - -// Compress a block into R11 EAC format. -// The compression works as follows: -// 1. Find the center of the span of the block's values. Use this as the base codeword. -// 2. Choose a multiplier based roughly on the size of the span of block values -// 3. Iterate through each palette and choose the one with the most accurate -// modifiers. -static inline uint64_t compress_heterogeneous_r11eac_block(const uint8_t block[16]) { - // Find the center of the data... - uint16_t bmin = block[0]; - uint16_t bmax = block[0]; - for (int i = 1; i < 16; ++i) { - bmin = SkTMin(bmin, block[i]); - bmax = SkTMax(bmax, block[i]); - } - - uint16_t center = (bmax + bmin) >> 1; - SkASSERT(center <= 255); - - // Based on the min and max, we can guesstimate a proper multiplier - // This is kind of a magic choice to start with. - uint16_t multiplier = (bmax - center) / 10; - - // Now convert the block to 11 bits and transpose it to match - // the proper layout - uint16_t cblock[16]; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - int srcIdx = i*4+j; - int dstIdx = j*4+i; - cblock[dstIdx] = (block[srcIdx] << 3) | (block[srcIdx] >> 5); - } - } - - // Finally, choose the proper palette and indices - uint32_t bestError = 0xFFFFFFFF; - uint64_t bestIndices = 0; - uint16_t bestPalette = 0; - for (uint16_t paletteIdx = 0; paletteIdx < kNumR11EACPalettes; ++paletteIdx) { - const int *palette = kR11EACModifierPalettes[paletteIdx]; - - // Iterate through each pixel to find the best palette index - // and update the indices with the choice. Also store the error - // for this palette to be compared against the best error... - uint32_t error = 0; - uint64_t indices = 0; - for (int pixelIdx = 0; pixelIdx < 16; ++pixelIdx) { - const uint16_t pixel = cblock[pixelIdx]; - - // Iterate through each palette value to find the best index - // for this particular pixel for this particular palette. - uint16_t bestPixelError = - abs_diff(pixel, compute_r11eac_pixel(center, palette[0], multiplier)); - int bestIndex = 0; - for (int i = 1; i < kR11EACPaletteSize; ++i) { - const uint16_t p = compute_r11eac_pixel(center, palette[i], multiplier); - const uint16_t perror = abs_diff(pixel, p); - - // Is this index better? - if (perror < bestPixelError) { - bestIndex = i; - bestPixelError = perror; - } - } - - SkASSERT(bestIndex < 8); - - error += bestPixelError; - indices <<= 3; - indices |= bestIndex; - } - - SkASSERT(indices < (static_cast(1) << 48)); - - // Is this palette better? - if (error < bestError) { - bestPalette = paletteIdx; - bestIndices = indices; - bestError = error; - } - } - - // Finally, pack everything together... - return pack_r11eac_block(center, bestPalette, multiplier, bestIndices); -} -#endif // COMPRESS_R11_EAC_SLOW - -#if COMPRESS_R11_EAC_FAST -// This function takes into account that most blocks that we compress have a gradation from -// fully opaque to fully transparent. The compression scheme works by selecting the -// palette and multiplier that has the tightest fit to the 0-255 range. This is encoded -// as the block header (0x8490). The indices are then selected by considering the top -// three bits of each alpha value. For alpha masks, this reduces the dynamic range from -// 17 to 8, but the quality is still acceptable. -// -// There are a few caveats that need to be taken care of... -// -// 1. The block is read in as scanlines, so the indices are stored as: -// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -// However, the decomrpession routine reads them in column-major order, so they -// need to be packed as: -// 0 4 8 12 1 5 9 13 2 6 10 14 3 7 11 15 -// So when reading, they must be transposed. -// -// 2. We cannot use the top three bits as an index directly, since the R11 EAC palettes -// above store the modulation values first decreasing and then increasing: -// e.g. {-3, -6, -9, -15, 2, 5, 8, 14} -// Hence, we need to convert the indices with the following mapping: -// From: 0 1 2 3 4 5 6 7 -// To: 3 2 1 0 4 5 6 7 -static inline uint64_t compress_heterogeneous_r11eac_block(const uint8_t block[16]) { - uint64_t retVal = static_cast(0x8490) << 48; - for(int i = 0; i < 4; ++i) { - for(int j = 0; j < 4; ++j) { - const int shift = 45-3*(j*4+i); - SkASSERT(shift <= 45); - const uint64_t idx = block[i*4+j] >> 5; - SkASSERT(idx < 8); - - // !SPEED! This is slightly faster than having an if-statement. - switch(idx) { - case 0: - case 1: - case 2: - case 3: - retVal |= (3-idx) << shift; - break; - default: - retVal |= idx << shift; - break; - } - } - } - - return SkEndian_SwapBE64(retVal); -} -#endif // COMPRESS_R11_EAC_FAST - -#if (COMPRESS_R11_EAC_SLOW) || (COMPRESS_R11_EAC_FAST) -static uint64_t compress_r11eac_block(const uint8_t block[16]) { - // Are all blocks a solid color? - bool solid = true; - for (int i = 1; i < 16; ++i) { - if (block[i] != block[0]) { - solid = false; - break; - } - } - - if (solid) { - switch(block[0]) { - // Fully transparent? We know the encoding... - case 0: - // (0x0020 << 48) produces the following: - // basw_cw: 0 - // mod: 0, palette: {-3, -6, -9, -15, 2, 5, 8, 14} - // multiplier: 2 - // mod_val: -3 - // - // this gives the following formula: - // clamp[0, 2047](0*8+4+(-3)*2*8) = 0 - // - // Furthermore, it is impervious to endianness: - // 0x0020000000002000ULL - // Will produce one pixel with index 2, which gives: - // clamp[0, 2047](0*8+4+(-9)*2*8) = 0 - return 0x0020000000002000ULL; - - // Fully opaque? We know this encoding too... - case 255: - - // -1 produces the following: - // basw_cw: 255 - // mod: 15, palette: {-3, -5, -7, -9, 2, 4, 6, 8} - // mod_val: 8 - // - // this gives the following formula: - // clamp[0, 2047](255*8+4+8*8*8) = clamp[0, 2047](2556) = 2047 - return 0xFFFFFFFFFFFFFFFFULL; - - default: - // !TODO! krajcevski: - // This will probably never happen, since we're using this format - // primarily for compressing alpha maps. Usually the only - // non-fullly opaque or fully transparent blocks are not a solid - // intermediate color. If we notice that they are, then we can - // add another optimization... - break; - } - } - - return compress_heterogeneous_r11eac_block(block); -} - -// This function is used by R11 EAC to compress 4x4 blocks -// of 8-bit alpha into 64-bit values that comprise the compressed data. -// We need to make sure that the dimensions of the src pixels are divisible -// by 4, and copy 4x4 blocks one at a time for compression. -typedef uint64_t (*A84x4To64BitProc)(const uint8_t block[]); - -static bool compress_4x4_a8_to_64bit(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes, - A84x4To64BitProc proc) { - // Make sure that our data is well-formed enough to be considered for compression - if (0 == width || 0 == height || (width % 4) != 0 || (height % 4) != 0) { - return false; - } - - int blocksX = width >> 2; - int blocksY = height >> 2; - - uint8_t block[16]; - uint64_t* encPtr = reinterpret_cast(dst); - for (int y = 0; y < blocksY; ++y) { - for (int x = 0; x < blocksX; ++x) { - // Load block - for (int k = 0; k < 4; ++k) { - memcpy(block + k*4, src + k*rowBytes + 4*x, 4); - } - - // Compress it - *encPtr = proc(block); - ++encPtr; - } - src += 4 * rowBytes; - } - - return true; -} -#endif // (COMPRESS_R11_EAC_SLOW) || (COMPRESS_R11_EAC_FAST) - -// This function converts an integer containing four bytes of alpha -// values into an integer containing four bytes of indices into R11 EAC. -// Note, there needs to be a mapping of indices: -// 0 1 2 3 4 5 6 7 -// 3 2 1 0 4 5 6 7 -// -// To compute this, we first negate each byte, and then add three, which -// gives the mapping -// 3 2 1 0 -1 -2 -3 -4 -// -// Then we mask out the negative values, take their absolute value, and -// add three. -// -// Most of the voodoo in this function comes from Hacker's Delight, section 2-18 -static inline uint32_t convert_indices(uint32_t x) { - // Take the top three bits... - x = SkTextureCompressor::ConvertToThreeBitIndex(x); - - // Negate... - x = ~((0x80808080 - x) ^ 0x7F7F7F7F); - - // Add three - const uint32_t s = (x & 0x7F7F7F7F) + 0x03030303; - x = ((x ^ 0x03030303) & 0x80808080) ^ s; - - // Absolute value - const uint32_t a = x & 0x80808080; - const uint32_t b = a >> 7; - - // Aside: mask negatives (m is three if the byte was negative) - const uint32_t m = (a >> 6) | b; - - // .. continue absolute value - x = (x ^ ((a - b) | a)) + b; - - // Add three - return x + m; -} - -#if COMPRESS_R11_EAC_FASTEST -template -static inline uint64_t swap_shift(uint64_t x, uint64_t mask) { - const uint64_t t = (x ^ (x >> shift)) & mask; - return x ^ t ^ (t << shift); -} - -static inline uint64_t interleave6(uint64_t topRows, uint64_t bottomRows) { - // If our 3-bit block indices are laid out as: - // a b c d - // e f g h - // i j k l - // m n o p - // - // This function expects topRows and bottomRows to contain the first two rows - // of indices interleaved in the least significant bits of a and b. In other words... - // - // If the architecture is big endian, then topRows and bottomRows will contain the following: - // Bits 31-0: - // a: 00 a e 00 b f 00 c g 00 d h - // b: 00 i m 00 j n 00 k o 00 l p - // - // If the architecture is little endian, then topRows and bottomRows will contain - // the following: - // Bits 31-0: - // a: 00 d h 00 c g 00 b f 00 a e - // b: 00 l p 00 k o 00 j n 00 i m - // - // This function returns a 48-bit packing of the form: - // a e i m b f j n c g k o d h l p - // - // !SPEED! this function might be even faster if certain SIMD intrinsics are - // used.. - - // For both architectures, we can figure out a packing of the bits by - // using a shuffle and a few shift-rotates... - uint64_t x = (static_cast(topRows) << 32) | static_cast(bottomRows); - - // x: 00 a e 00 b f 00 c g 00 d h 00 i m 00 j n 00 k o 00 l p - - x = swap_shift<10>(x, 0x3FC0003FC00000ULL); - - // x: b f 00 00 00 a e c g i m 00 00 00 d h j n 00 k o 00 l p - - x = (x | ((x << 52) & (0x3FULL << 52)) | ((x << 20) & (0x3FULL << 28))) >> 16; - - // x: 00 00 00 00 00 00 00 00 b f l p a e c g i m k o d h j n - - x = swap_shift<6>(x, 0xFC0000ULL); - -#if defined (SK_CPU_BENDIAN) - // x: 00 00 00 00 00 00 00 00 b f l p a e i m c g k o d h j n - - x = swap_shift<36>(x, 0x3FULL); - - // x: 00 00 00 00 00 00 00 00 b f j n a e i m c g k o d h l p - - x = swap_shift<12>(x, 0xFFF000000ULL); -#else - // If our CPU is little endian, then the above logic will - // produce the following indices: - // x: 00 00 00 00 00 00 00 00 c g i m d h l p b f j n a e k o - - x = swap_shift<36>(x, 0xFC0ULL); - - // x: 00 00 00 00 00 00 00 00 a e i m d h l p b f j n c g k o - - x = (x & (0xFFFULL << 36)) | ((x & 0xFFFFFFULL) << 12) | ((x >> 24) & 0xFFFULL); -#endif - - // x: 00 00 00 00 00 00 00 00 a e i m b f j n c g k o d h l p - return x; -} - -// This function follows the same basic procedure as compress_heterogeneous_r11eac_block -// above when COMPRESS_R11_EAC_FAST is defined, but it avoids a few loads/stores and -// tries to optimize where it can using SIMD. -static uint64_t compress_r11eac_block_fast(const uint8_t* src, size_t rowBytes) { - // Store each row of alpha values in an integer - const uint32_t alphaRow1 = *(reinterpret_cast(src)); - const uint32_t alphaRow2 = *(reinterpret_cast(src + rowBytes)); - const uint32_t alphaRow3 = *(reinterpret_cast(src + 2*rowBytes)); - const uint32_t alphaRow4 = *(reinterpret_cast(src + 3*rowBytes)); - - // Check for solid blocks. The explanations for these values - // can be found in the comments of compress_r11eac_block above - if (alphaRow1 == alphaRow2 && alphaRow1 == alphaRow3 && alphaRow1 == alphaRow4) { - if (0 == alphaRow1) { - // Fully transparent block - return 0x0020000000002000ULL; - } else if (0xFFFFFFFF == alphaRow1) { - // Fully opaque block - return 0xFFFFFFFFFFFFFFFFULL; - } - } - - // Convert each integer of alpha values into an integer of indices - const uint32_t indexRow1 = convert_indices(alphaRow1); - const uint32_t indexRow2 = convert_indices(alphaRow2); - const uint32_t indexRow3 = convert_indices(alphaRow3); - const uint32_t indexRow4 = convert_indices(alphaRow4); - - // Interleave the indices from the top two rows and bottom two rows - // prior to passing them to interleave6. Since each index is at most - // three bits, then each byte can hold two indices... The way that the - // compression scheme expects the packing allows us to efficiently pack - // the top two rows and bottom two rows. Interleaving each 6-bit sequence - // and tightly packing it into a uint64_t is a little trickier, which is - // taken care of in interleave6. - const uint32_t r1r2 = (indexRow1 << 3) | indexRow2; - const uint32_t r3r4 = (indexRow3 << 3) | indexRow4; - const uint64_t indices = interleave6(r1r2, r3r4); - - // Return the packed incdices in the least significant bits with the magic header - return SkEndian_SwapBE64(0x8490000000000000ULL | indices); -} - -static bool compress_a8_to_r11eac_fast(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes) { - // Make sure that our data is well-formed enough to be considered for compression - if (0 == width || 0 == height || (width % 4) != 0 || (height % 4) != 0) { - return false; - } - - const int blocksX = width >> 2; - const int blocksY = height >> 2; - - uint64_t* encPtr = reinterpret_cast(dst); - for (int y = 0; y < blocksY; ++y) { - for (int x = 0; x < blocksX; ++x) { - // Compress it - *encPtr = compress_r11eac_block_fast(src + 4*x, rowBytes); - ++encPtr; - } - src += 4 * rowBytes; - } - return true; -} -#endif // COMPRESS_R11_EAC_FASTEST - -//////////////////////////////////////////////////////////////////////////////// -// -// Utility functions used by the blitter -// -//////////////////////////////////////////////////////////////////////////////// - -// The R11 EAC format expects that indices are given in column-major order. Since -// we receive alpha values in raster order, this usually means that we have to use -// pack6 above to properly pack our indices. However, if our indices come from the -// blitter, then each integer will be a column of indices, and hence can be efficiently -// packed. This function takes the bottom three bits of each byte and places them in -// the least significant 12 bits of the resulting integer. -static inline uint32_t pack_indices_vertical(uint32_t x) { -#if defined (SK_CPU_BENDIAN) - return - (x & 7) | - ((x >> 5) & (7 << 3)) | - ((x >> 10) & (7 << 6)) | - ((x >> 15) & (7 << 9)); -#else - return - ((x >> 24) & 7) | - ((x >> 13) & (7 << 3)) | - ((x >> 2) & (7 << 6)) | - ((x << 9) & (7 << 9)); -#endif -} - -// This function returns the compressed format of a block given as four columns of -// alpha values. Each column is assumed to be loaded from top to bottom, and hence -// must first be converted to indices and then packed into the resulting 64-bit -// integer. -inline void compress_block_vertical(uint8_t* dstPtr, const uint8_t *block) { - - const uint32_t* src = reinterpret_cast(block); - uint64_t* dst = reinterpret_cast(dstPtr); - - const uint32_t alphaColumn0 = src[0]; - const uint32_t alphaColumn1 = src[1]; - const uint32_t alphaColumn2 = src[2]; - const uint32_t alphaColumn3 = src[3]; - - if (alphaColumn0 == alphaColumn1 && - alphaColumn2 == alphaColumn3 && - alphaColumn0 == alphaColumn2) { - - if (0 == alphaColumn0) { - // Transparent - *dst = 0x0020000000002000ULL; - return; - } - else if (0xFFFFFFFF == alphaColumn0) { - // Opaque - *dst = 0xFFFFFFFFFFFFFFFFULL; - return; - } - } - - const uint32_t indexColumn0 = convert_indices(alphaColumn0); - const uint32_t indexColumn1 = convert_indices(alphaColumn1); - const uint32_t indexColumn2 = convert_indices(alphaColumn2); - const uint32_t indexColumn3 = convert_indices(alphaColumn3); - - const uint32_t packedIndexColumn0 = pack_indices_vertical(indexColumn0); - const uint32_t packedIndexColumn1 = pack_indices_vertical(indexColumn1); - const uint32_t packedIndexColumn2 = pack_indices_vertical(indexColumn2); - const uint32_t packedIndexColumn3 = pack_indices_vertical(indexColumn3); - - *dst = SkEndian_SwapBE64(0x8490000000000000ULL | - (static_cast(packedIndexColumn0) << 36) | - (static_cast(packedIndexColumn1) << 24) | - static_cast(packedIndexColumn2 << 12) | - static_cast(packedIndexColumn3)); -} - -static inline int get_r11_eac_index(uint64_t block, int x, int y) { - SkASSERT(x >= 0 && x < 4); - SkASSERT(y >= 0 && y < 4); - const int idx = x*4 + y; - return (block >> ((15-idx)*3)) & 0x7; -} - -static void decompress_r11_eac_block(uint8_t* dst, int dstRowBytes, const uint8_t* src) { - const uint64_t block = SkEndian_SwapBE64(*(reinterpret_cast(src))); - - const int base_cw = (block >> 56) & 0xFF; - const int mod = (block >> 52) & 0xF; - const int palette_idx = (block >> 48) & 0xF; - - const int* palette = kR11EACModifierPalettes[palette_idx]; - - for (int j = 0; j < 4; ++j) { - for (int i = 0; i < 4; ++i) { - const int idx = get_r11_eac_index(block, i, j); - const int val = base_cw*8 + 4 + palette[idx]*mod*8; - if (val < 0) { - dst[i] = 0; - } else if (val > 2047) { - dst[i] = 0xFF; - } else { - dst[i] = (val >> 3) & 0xFF; - } - } - dst += dstRowBytes; - } -} - -// This is the type passed as the CompressorType argument of the compressed -// blitter for the R11 EAC format. The static functions required to be in this -// struct are documented in SkTextureCompressor_Blitter.h -struct CompressorR11EAC { - static inline void CompressA8Vertical(uint8_t* dst, const uint8_t* src) { - compress_block_vertical(dst, src); - } - - static inline void CompressA8Horizontal(uint8_t* dst, const uint8_t* src, - int srcRowBytes) { - *(reinterpret_cast(dst)) = compress_r11eac_block_fast(src, srcRowBytes); - } - -#if PEDANTIC_BLIT_RECT - static inline void UpdateBlock(uint8_t* dst, const uint8_t* src, int srcRowBytes, - const uint8_t* mask) { - // TODO: krajcevski - // The implementation of this function should be similar to that of LATC, since - // the R11EAC indices directly correspond to pixel values. - SkFAIL("Implement me!"); - } -#endif -}; - -//////////////////////////////////////////////////////////////////////////////// - -namespace SkTextureCompressor { - -bool CompressA8ToR11EAC(uint8_t* dst, const uint8_t* src, int width, int height, size_t rowBytes) { - -#if (COMPRESS_R11_EAC_SLOW) || (COMPRESS_R11_EAC_FAST) - - return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_r11eac_block); - -#elif COMPRESS_R11_EAC_FASTEST - - return compress_a8_to_r11eac_fast(dst, src, width, height, rowBytes); - -#else -#error "Must choose R11 EAC algorithm" -#endif -} - -SkBlitter* CreateR11EACBlitter(int width, int height, void* outputBuffer, - SkTBlitterAllocator* allocator) { - - if ((width % 4) != 0 || (height % 4) != 0) { - return nullptr; - } - - // Memset the output buffer to an encoding that decodes to zero. We must do this - // in order to avoid having uninitialized values in the buffer if the blitter - // decides not to write certain scanlines (and skip entire rows of blocks). - // In the case of R11, we use the encoding from recognizing all zero pixels from above. - const int nBlocks = (width * height / 16); // 4x4 pixel blocks. - uint64_t *dst = reinterpret_cast(outputBuffer); - for (int i = 0; i < nBlocks; ++i) { - *dst = 0x0020000000002000ULL; - ++dst; - } - - return allocator->createT< - SkTCompressedAlphaBlitter<4, 8, CompressorR11EAC>, int, int, void*> - (width, height, outputBuffer); -} - -void DecompressR11EAC(uint8_t* dst, int dstRowBytes, const uint8_t* src, int width, int height) { - for (int j = 0; j < height; j += 4) { - for (int i = 0; i < width; i += 4) { - decompress_r11_eac_block(dst + i, dstRowBytes, src); - src += 8; - } - dst += 4 * dstRowBytes; - } -} - -} // namespace SkTextureCompressor diff --git a/gfx/skia/skia/src/utils/SkTextureCompressor_R11EAC.h b/gfx/skia/skia/src/utils/SkTextureCompressor_R11EAC.h deleted file mode 100644 index abaabfb363ad..000000000000 --- a/gfx/skia/skia/src/utils/SkTextureCompressor_R11EAC.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkTextureCompressor_R11EAC_DEFINED -#define SkTextureCompressor_R11EAC_DEFINED - -#include "SkBitmapProcShader.h" - -class SkBlitter; - -namespace SkTextureCompressor { - - bool CompressA8ToR11EAC(uint8_t* dst, const uint8_t* src, - int width, int height, size_t rowBytes); - - SkBlitter* CreateR11EACBlitter(int width, int height, void* outputBuffer, - SkTBlitterAllocator* allocator); - - void DecompressR11EAC(uint8_t* dst, int dstRB, const uint8_t* src, int width, int height); -} - -#endif // SkTextureCompressor_R11EAC_DEFINED diff --git a/gfx/skia/skia/src/utils/SkTextureCompressor_Utils.h b/gfx/skia/skia/src/utils/SkTextureCompressor_Utils.h deleted file mode 100644 index 9b115a29647b..000000000000 --- a/gfx/skia/skia/src/utils/SkTextureCompressor_Utils.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -* Copyright 2014 Google Inc. -* -* Use of this source code is governed by a BSD-style license that can be -* found in the LICENSE file. -*/ - -#ifndef SkTextureCompressorUtils_DEFINED -#define SkTextureCompressorUtils_DEFINED - -namespace SkTextureCompressor { - - // In some compression formats used for grayscale alpha, i.e. coverage masks, three - // bit indices are used to represent each pixel. A compression scheme must therefore - // quantize the full eight bits of grayscale to three bits. The simplest way to do - // this is to take the top three bits of the grayscale value. However, this does not - // provide an accurate quantization: 192 will be quantized to 219 instead of 185. In - // our compression schemes, we let these three-bit indices represent the full range - // of grayscale values, and so when we go from three bits to eight bits, we replicate - // the three bits into the lower bits of the eight bit value. Below are two different - // techniques that offer a quality versus speed tradeoff in terms of quantization. -#if 1 - // Divides each byte in the 32-bit argument by three. - static inline uint32_t MultibyteDiv3(uint32_t x) { - const uint32_t a = (x >> 2) & 0x3F3F3F3F; - const uint32_t ar = (x & 0x03030303) << 4; - - const uint32_t b = (x >> 4) & 0x0F0F0F0F; - const uint32_t br = (x & 0x0F0F0F0F) << 2; - - const uint32_t c = (x >> 6) & 0x03030303; - const uint32_t cr = x & 0x3F3F3F3F; - - return a + b + c + (((ar + br + cr) >> 6) & 0x03030303); - } - - // Takes a loaded 32-bit integer of four 8-bit greyscale values and returns their - // quantization into 3-bit values, used by LATC and R11 EAC. Instead of taking the - // top three bits, the function computes the best three-bit value such that its - // reconstruction into an eight bit value via bit replication will yield the best - // results. In a 32-bit integer taking the range of values from 0-255 we would add - // 18 and divide by 36 (255 / 36 ~= 7). However, since we are working in constrained - // 8-bit space, our algorithm is the following: - // 1. Shift right by one to give room for overflow - // 2. Add 9 (18/2) - // 3. Divide by 18 (divide by two, then by three twice) - static inline uint32_t ConvertToThreeBitIndex(uint32_t x) { - x = (x >> 1) & 0x7F7F7F7F; // 1 - x = x + 0x09090909; // 2 - - // Need to divide by 18... so first divide by two - x = (x >> 1) & 0x7F7F7F7F; - - // Now divide by three twice - x = MultibyteDiv3(x); - x = MultibyteDiv3(x); - return x; - } -#else - // Moves the top three bits of each byte in the 32-bit argument to the least - // significant bits of their respective byte. - static inline uint32_t ConvertToThreeBitIndex(uint32_t x) { - return (x >> 5) & 0x07070707; - } -#endif -} - -#endif // SkTextureCompressorUtils_DEFINED diff --git a/gfx/skia/skia/src/utils/SkWhitelistTypefaces.cpp b/gfx/skia/skia/src/utils/SkWhitelistTypefaces.cpp index 007def6d8be7..f51a3b3c24e9 100644 --- a/gfx/skia/skia/src/utils/SkWhitelistTypefaces.cpp +++ b/gfx/skia/skia/src/utils/SkWhitelistTypefaces.cpp @@ -40,7 +40,7 @@ static bool font_name_is_local(const char* fontName, SkFontStyle style) { static int whitelist_name_index(const SkTypeface* tf) { SkString fontNameStr; - SkAutoTUnref nameIter( + sk_sp nameIter( SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*tf)); SkTypeface::LocalizedString familyNameLocalized; while (nameIter->next(&familyNameLocalized)) { @@ -53,7 +53,7 @@ static int whitelist_name_index(const SkTypeface* tf) { } } #if WHITELIST_DEBUG - SkAutoTUnref debugIter( + sk_sp debugIter( SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*tf)); while (debugIter->next(&familyNameLocalized)) { SkDebugf("no match fontName=\"%s\"\n", familyNameLocalized.fString.c_str()); diff --git a/gfx/skia/skia/src/utils/mac/SkCreateCGImageRef.cpp b/gfx/skia/skia/src/utils/mac/SkCreateCGImageRef.cpp index d9cdb86e49f9..e3735920a1d1 100644 --- a/gfx/skia/skia/src/utils/mac/SkCreateCGImageRef.cpp +++ b/gfx/skia/skia/src/utils/mac/SkCreateCGImageRef.cpp @@ -178,6 +178,30 @@ void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) { /////////////////////////////////////////////////////////////////////////////////////////////////// +CGContextRef SkCreateCGContext(const SkPixmap& pmap) { + CGBitmapInfo cg_bitmap_info = 0; + size_t bitsPerComponent = 0; + switch (pmap.colorType()) { + case kRGBA_8888_SkColorType: + bitsPerComponent = 8; + cg_bitmap_info = ComputeCGAlphaInfo_RGBA(pmap.alphaType()); + break; + case kBGRA_8888_SkColorType: + bitsPerComponent = 8; + cg_bitmap_info = ComputeCGAlphaInfo_BGRA(pmap.alphaType()); + break; + default: + return nullptr; // no other colortypes are supported (for now) + } + + size_t rb = pmap.addr() ? pmap.rowBytes() : 0; + CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); + CGContextRef cg = CGBitmapContextCreate(pmap.writable_addr(), pmap.width(), pmap.height(), + bitsPerComponent, rb, cs, cg_bitmap_info); + CFRelease(cs); + return cg; +} + SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels, CGImageRef image) { CGBitmapInfo cg_bitmap_info = 0; @@ -212,9 +236,9 @@ SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, vo return true; } -bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image, SkISize* scaleToFit) { - const int width = scaleToFit ? scaleToFit->width() : SkToInt(CGImageGetWidth(image)); - const int height = scaleToFit ? scaleToFit->height() : SkToInt(CGImageGetHeight(image)); +bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image) { + const int width = SkToInt(CGImageGetWidth(image)); + const int height = SkToInt(CGImageGetHeight(image)); SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); SkBitmap tmp; @@ -245,4 +269,14 @@ bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image, SkISize* scaleTo return true; } +sk_sp SkMakeImageFromCGImage(CGImageRef src) { + SkBitmap bm; + if (!SkCreateBitmapFromCGImage(&bm, src)) { + return nullptr; + } + + bm.setImmutable(); + return SkImage::MakeFromBitmap(bm); +} + #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) diff --git a/gfx/skia/skia/src/utils/mac/SkStream_mac.cpp b/gfx/skia/skia/src/utils/mac/SkStream_mac.cpp index e878c9724415..2c1c1e2e0575 100644 --- a/gfx/skia/skia/src/utils/mac/SkStream_mac.cpp +++ b/gfx/skia/skia/src/utils/mac/SkStream_mac.cpp @@ -6,9 +6,11 @@ */ #include "SkTypes.h" + #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) #include "SkCGUtils.h" +#include "SkMalloc.h" #include "SkStream.h" // These are used by CGDataProviderCreateWithData diff --git a/gfx/skia/skia/src/utils/win/SkDWrite.h b/gfx/skia/skia/src/utils/win/SkDWrite.h index ddcbc6c42613..de2293df9731 100644 --- a/gfx/skia/skia/src/utils/win/SkDWrite.h +++ b/gfx/skia/skia/src/utils/win/SkDWrite.h @@ -19,14 +19,6 @@ class SkString; //////////////////////////////////////////////////////////////////////////////// // Factory -#ifndef SK_HAS_DWRITE_1_H -#define SK_HAS_DWRITE_1_H (WINVER_MAXVER >= 0x0602) -#endif - -#ifndef SK_HAS_DWRITE_2_H -#define SK_HAS_DWRITE_2_H (WINVER_MAXVER >= 0x0603) -#endif - IDWriteFactory* sk_get_dwrite_factory(); //////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/utils/win/SkDWriteFontFileStream.cpp b/gfx/skia/skia/src/utils/win/SkDWriteFontFileStream.cpp index 6c73441e72c2..2bb7d0fb4efa 100644 --- a/gfx/skia/skia/src/utils/win/SkDWriteFontFileStream.cpp +++ b/gfx/skia/skia/src/utils/win/SkDWriteFontFileStream.cpp @@ -105,7 +105,7 @@ bool SkDWriteFontFileStream::move(long offset) { } SkDWriteFontFileStream* SkDWriteFontFileStream::fork() const { - SkAutoTDelete that(this->duplicate()); + std::unique_ptr that(this->duplicate()); that->seek(fPos); return that.release(); } diff --git a/gfx/skia/skia/src/utils/win/SkDWriteFontFileStream.h b/gfx/skia/skia/src/utils/win/SkDWriteFontFileStream.h index e78b621c0230..25322c565788 100644 --- a/gfx/skia/skia/src/utils/win/SkDWriteFontFileStream.h +++ b/gfx/skia/skia/src/utils/win/SkDWriteFontFileStream.h @@ -73,7 +73,7 @@ private: virtual ~SkDWriteFontFileStreamWrapper() { } ULONG fRefCount; - SkAutoTDelete fStream; + std::unique_ptr fStream; SkMutex fStreamMutex; }; #endif diff --git a/gfx/skia/skia/src/utils/win/SkTScopedComPtr.h b/gfx/skia/skia/src/utils/win/SkTScopedComPtr.h index 5410f5c99269..f44740ff44b1 100644 --- a/gfx/skia/skia/src/utils/win/SkTScopedComPtr.h +++ b/gfx/skia/skia/src/utils/win/SkTScopedComPtr.h @@ -32,15 +32,26 @@ template T* SkSafeRefComPtr(T* ptr) { } template -class SkTScopedComPtr : SkNoncopyable { +class SkTScopedComPtr { private: T *fPtr; public: - explicit SkTScopedComPtr(T *ptr = nullptr) : fPtr(ptr) { } + constexpr SkTScopedComPtr() : fPtr(nullptr) {} + constexpr SkTScopedComPtr(std::nullptr_t) : fPtr(nullptr) {} + explicit SkTScopedComPtr(T *ptr) : fPtr(ptr) {} + SkTScopedComPtr(SkTScopedComPtr&& that) : fPtr(that.release()) {} + SkTScopedComPtr(const SkTScopedComPtr&) = delete; ~SkTScopedComPtr() { this->reset();} + SkTScopedComPtr& operator=(SkTScopedComPtr&& that) { + this->reset(that.release()); + return *this; + } + SkTScopedComPtr& operator=(const SkTScopedComPtr&) = delete; + SkTScopedComPtr& operator=(std::nullptr_t) { this->reset(); return *this; } + T &operator*() const { SkASSERT(fPtr != nullptr); return *fPtr; } explicit operator bool() const { return fPtr != nullptr; } @@ -57,11 +68,11 @@ public: T *get() const { return fPtr; } - void reset() { - if (this->fPtr) { - this->fPtr->Release(); - this->fPtr = nullptr; + void reset(T* ptr = nullptr) { + if (fPtr) { + fPtr->Release(); } + fPtr = ptr; } void swap(SkTScopedComPtr& that) { diff --git a/gfx/skia/skia/src/utils/win/SkWGL.h b/gfx/skia/skia/src/utils/win/SkWGL.h index 3799377cc3c4..1fafd2fe5268 100644 --- a/gfx/skia/skia/src/utils/win/SkWGL.h +++ b/gfx/skia/skia/src/utils/win/SkWGL.h @@ -133,7 +133,8 @@ enum SkWGLContextRequest { * (including non-MSAA) will be created. If preferCoreProfile is true but a core profile cannot be * created then a compatible profile context will be created. */ -HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor, SkWGLContextRequest context); +HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor, SkWGLContextRequest context, + HGLRC shareContext = nullptr); /** * Helper class for creating a pbuffer context and deleting all the handles when finished. This @@ -143,7 +144,7 @@ HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor, SkWGLConte class SkWGLPbufferContext : public SkRefCnt { public: static SkWGLPbufferContext* Create(HDC parentDC, int msaaSampleCount, - SkWGLContextRequest contextType); + SkWGLContextRequest contextType, HGLRC shareContext); virtual ~SkWGLPbufferContext(); diff --git a/gfx/skia/skia/src/utils/win/SkWGL_win.cpp b/gfx/skia/skia/src/utils/win/SkWGL_win.cpp index dc1b4caf1a57..d46123d1bf26 100644 --- a/gfx/skia/skia/src/utils/win/SkWGL_win.cpp +++ b/gfx/skia/skia/src/utils/win/SkWGL_win.cpp @@ -334,7 +334,8 @@ static void get_pixel_formats_to_try(HDC dc, const SkWGLExtensions& extensions, extensions.choosePixelFormat(dc, iAttrs.begin(), fAttrs, 1, format, &num); } -static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextRequest contextType) { +static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextRequest contextType, + HGLRC shareContext) { HDC prevDC = wglGetCurrentDC(); HGLRC prevGLRC = wglGetCurrentContext(); @@ -350,7 +351,7 @@ static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextR SK_WGL_CONTEXT_PROFILE_MASK, SK_WGL_CONTEXT_ES2_PROFILE_BIT, 0, }; - glrc = extensions.createContextAttribs(dc, nullptr, glesAttribs); + glrc = extensions.createContextAttribs(dc, shareContext, glesAttribs); if (nullptr == glrc) { wglMakeCurrent(prevDC, prevGLRC); return nullptr; @@ -375,7 +376,7 @@ static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextR for (int v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) { coreProfileAttribs[1] = kCoreGLVersions[2 * v]; coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1]; - glrc = extensions.createContextAttribs(dc, nullptr, coreProfileAttribs); + glrc = extensions.createContextAttribs(dc, shareContext, coreProfileAttribs); if (glrc) { break; } @@ -385,6 +386,12 @@ static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextR if (nullptr == glrc) { glrc = wglCreateContext(dc); + if (shareContext) { + if (!wglShareLists(shareContext, glrc)) { + wglDeleteContext(glrc); + return nullptr; + } + } } SkASSERT(glrc); @@ -398,7 +405,7 @@ static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextR } HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor, - SkWGLContextRequest contextType) { + SkWGLContextRequest contextType, HGLRC shareContext) { SkWGLExtensions extensions; if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) { return nullptr; @@ -420,10 +427,12 @@ HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor, return nullptr; } - return create_gl_context(dc, extensions, contextType);} + return create_gl_context(dc, extensions, contextType, shareContext); +} SkWGLPbufferContext* SkWGLPbufferContext::Create(HDC parentDC, int msaaSampleCount, - SkWGLContextRequest contextType) { + SkWGLContextRequest contextType, + HGLRC shareContext) { SkWGLExtensions extensions; if (!extensions.hasExtension(parentDC, "WGL_ARB_pixel_format") || !extensions.hasExtension(parentDC, "WGL_ARB_pbuffer")) { @@ -440,7 +449,7 @@ SkWGLPbufferContext* SkWGLPbufferContext::Create(HDC parentDC, int msaaSampleCou if (0 != pbuf) { HDC dc = extensions.getPbufferDC(pbuf); if (dc) { - HGLRC glrc = create_gl_context(dc, extensions, contextType); + HGLRC glrc = create_gl_context(dc, extensions, contextType, shareContext); if (glrc) { return new SkWGLPbufferContext(pbuf, dc, glrc); } diff --git a/gfx/skia/skia/src/views/SkEvent.cpp b/gfx/skia/skia/src/views/SkEvent.cpp index 7b658c839a45..c218ee419d18 100644 --- a/gfx/skia/skia/src/views/SkEvent.cpp +++ b/gfx/skia/skia/src/views/SkEvent.cpp @@ -6,6 +6,7 @@ */ +#include "SkDOM.h" #include "SkEvent.h" void SkEvent::initialize(const char* type, size_t typeLen, @@ -415,9 +416,8 @@ SkMSec SkEvent::EnqueueTime(SkEvent* evt, SkMSec time) { #include "SkEventSink.h" bool SkEvent::ProcessEvent() { - SkEvent* evt = SkEvent::Dequeue(); - SkAutoTDelete autoDelete(evt); - bool again = false; + std::unique_ptr evt(SkEvent::Dequeue()); + bool again = false; EVENT_LOGN("ProcessEvent", (int32_t)evt); diff --git a/gfx/skia/skia/src/views/SkEventSink.cpp b/gfx/skia/skia/src/views/SkEventSink.cpp index 1464fa0facea..5732feb39582 100644 --- a/gfx/skia/skia/src/views/SkEventSink.cpp +++ b/gfx/skia/skia/src/views/SkEventSink.cpp @@ -247,54 +247,3 @@ SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID) } return nullptr; } - -//////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// - -#if 0 // experimental, not tested - -#include "SkMutex.h" -#include "SkTDict.h" - -#define kMinStringBufferSize 128 -SK_DECLARE_STATIC_MUTEX(gNamedSinkMutex); -static SkTDict gNamedSinkIDs(kMinStringBufferSize); - -/** Register a name/id pair with the system. If the name already exists, - replace its ID with the new id. This pair will persist until UnregisterNamedSink() - is called. -*/ -void SkEventSink::RegisterNamedSinkID(const char name[], SkEventSinkID id) -{ - if (id && name && *name) - { - SkAutoMutexAcquire ac(gNamedSinkMutex); - gNamedSinkIDs.set(name, id); - } -} - -/** Return the id that matches the specified name (from a previous call to - RegisterNamedSinkID(). If no match is found, return 0 -*/ -SkEventSinkID SkEventSink::FindNamedSinkID(const char name[]) -{ - SkEventSinkID id = 0; - - if (name && *name) - { - SkAutoMutexAcquire ac(gNamedSinkMutex); - (void)gNamedSinkIDs.find(name, &id); - } - return id; -} - -/** Remove all name/id pairs from the system. This is call internally - on shutdown, to ensure no memory leaks. It should not be called - before shutdown. -*/ -void SkEventSink::RemoveAllNamedSinkIDs() -{ - SkAutoMutexAcquire ac(gNamedSinkMutex); - (void)gNamedSinkIDs.reset(); -} -#endif diff --git a/gfx/skia/skia/src/views/SkView.cpp b/gfx/skia/skia/src/views/SkView.cpp index 492b2cdac1ed..9c148dfac7b5 100644 --- a/gfx/skia/skia/src/views/SkView.cpp +++ b/gfx/skia/skia/src/views/SkView.cpp @@ -7,6 +7,7 @@ #include "SkView.h" #include "SkCanvas.h" +#include "SkDOM.h" static inline uint32_t SkSetClearShift(uint32_t bits, bool cond, unsigned shift) { SkASSERT((int)cond == 0 || (int)cond == 1); @@ -663,19 +664,6 @@ void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node) { this->onInflate(dom, node); } -void SkView::onPostInflate(const SkTDict&) { - // override in subclass as needed -} - -void SkView::postInflate(const SkTDict& dict) { - this->onPostInflate(dict); - - B2FIter iter(this); - SkView* child; - while ((child = iter.next()) != nullptr) - child->postInflate(dict); -} - ////////////////////////////////////////////////////////////////// SkView* SkView::sendEventToParents(const SkEvent& evt) { diff --git a/gfx/skia/skia/src/views/SkViewPriv.cpp b/gfx/skia/skia/src/views/SkViewPriv.cpp index 7dbe5f1cae52..b426ade433b9 100644 --- a/gfx/skia/skia/src/views/SkViewPriv.cpp +++ b/gfx/skia/skia/src/views/SkViewPriv.cpp @@ -4,6 +4,8 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ + +#include "SkDOM.h" #include "SkViewPriv.h" ////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/views/SkWindow.cpp b/gfx/skia/skia/src/views/SkWindow.cpp index 6e1ebf7a7592..f86bb9f9ef75 100644 --- a/gfx/skia/skia/src/views/SkWindow.cpp +++ b/gfx/skia/skia/src/views/SkWindow.cpp @@ -342,9 +342,9 @@ sk_sp SkWindow::makeGpuBackedSurface(const AttachmentInfo& attachment // so pretend that it's non-sRGB 8888: desc.fConfig = grContext->caps()->srgbSupport() && - SkImageInfoIsGammaCorrect(info()) && + info().colorSpace() && (attachmentInfo.fColorBits != 30) - ? kSkiaGamma8888_GrPixelConfig : kSkia8888_GrPixelConfig; + ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig; desc.fOrigin = kBottomLeft_GrSurfaceOrigin; desc.fSampleCnt = attachmentInfo.fSampleCount; desc.fStencilBits = attachmentInfo.fStencilBits; @@ -353,8 +353,8 @@ sk_sp SkWindow::makeGpuBackedSurface(const AttachmentInfo& attachment desc.fRenderTargetHandle = buffer; sk_sp colorSpace = - grContext->caps()->srgbSupport() && SkImageInfoIsGammaCorrect(info()) - ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) : nullptr; + grContext->caps()->srgbSupport() && info().colorSpace() + ? SkColorSpace::MakeSRGB() : nullptr; return SkSurface::MakeFromBackendRenderTarget(grContext, desc, colorSpace, &fSurfaceProps); } diff --git a/gfx/skia/skia/src/views/ios/SkOSWindow_iOS.mm b/gfx/skia/skia/src/views/ios/SkOSWindow_iOS.mm index aa7d3759bdb4..3e2937181f1e 100755 --- a/gfx/skia/skia/src/views/ios/SkOSWindow_iOS.mm +++ b/gfx/skia/skia/src/views/ios/SkOSWindow_iOS.mm @@ -53,7 +53,7 @@ void SkOSWindow::onAddMenu(const SkOSMenu* menu) { [(SkUIView*)fHWND onAddMenu:menu]; } -void SkOSWindow::onUpdateMenu(SkOSMenu* menu) { +void SkOSWindow::onUpdateMenu(const SkOSMenu* menu) { [(SkUIView*)fHWND onUpdateMenu:menu]; } diff --git a/gfx/skia/skia/src/views/mac/SkNSView.h b/gfx/skia/skia/src/views/mac/SkNSView.h index 779c51b7e42b..1718b2ac112b 100644 --- a/gfx/skia/skia/src/views/mac/SkNSView.h +++ b/gfx/skia/skia/src/views/mac/SkNSView.h @@ -8,6 +8,7 @@ #import #import #import "SkWindow.h" + class SkEvent; @class SkNSView; @@ -18,18 +19,7 @@ class SkEvent; - (void) view:(SkNSView*)view didUpdateMenu:(const SkOSMenu*)menu; @end -@interface SkNSView : NSView { - BOOL fRedrawRequestPending; - - NSString* fTitle; - SkOSWindow* fWind; -#if SK_SUPPORT_GPU - NSOpenGLContext* fGLContext; -#endif - id fOptionsDelegate; -} - -@property (nonatomic, readonly) SkOSWindow *fWind; +@interface SkNSView : NSView @property (nonatomic, retain) NSString* fTitle; #if SK_SUPPORT_GPU @property (nonatomic, retain) NSOpenGLContext* fGLContext; @@ -54,3 +44,7 @@ class SkEvent; - (void)freeNativeWind; @end + +@interface SkNSView() + @property (nonatomic, readwrite) SkOSWindow *fWind; +@end diff --git a/gfx/skia/skia/src/views/mac/SkNSView.mm b/gfx/skia/skia/src/views/mac/SkNSView.mm index ce293823712f..64c02ca2a59b 100644 --- a/gfx/skia/skia/src/views/mac/SkNSView.mm +++ b/gfx/skia/skia/src/views/mac/SkNSView.mm @@ -15,11 +15,17 @@ static_assert(SK_SUPPORT_GPU, "not_implemented_for_non_gpu_build"); //#define FORCE_REDRAW // Can be dropped when we no longer support 10.6. -#define RETINA_API_AVAILABLE (defined(MAC_OS_X_VERSION_10_7) && \ - MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7) +#if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + #define RETINA_API_AVAILABLE 1 +#else + #define RETINA_API_AVAILABLE 0 +#endif + @implementation SkNSView @synthesize fWind, fTitle, fOptionsDelegate, fGLContext; +BOOL fRedrawRequestPending; + - (id)initWithCoder:(NSCoder*)coder { if ((self = [super initWithCoder:coder])) { self = [self initWithDefaults]; diff --git a/gfx/skia/skia/src/views/mac/SkOSWindow_Mac.mm b/gfx/skia/skia/src/views/mac/SkOSWindow_Mac.mm index faf1bbafd243..a256b39fa31a 100644 --- a/gfx/skia/skia/src/views/mac/SkOSWindow_Mac.mm +++ b/gfx/skia/skia/src/views/mac/SkOSWindow_Mac.mm @@ -5,8 +5,6 @@ * found in the LICENSE file. */ -#if defined(SK_BUILD_FOR_MAC) - #import #include "SkOSWindow_Mac.h" #include "SkOSMenu.h" @@ -87,9 +85,10 @@ void SkOSWindow::setVsync(bool enable) { } bool SkOSWindow::makeFullscreen() { - [(SkNSView*)fHWND enterFullScreenMode:[NSScreen mainScreen] withOptions:nil]; + NSScreen* _Nullable screen = [NSScreen mainScreen]; + if (screen) { + [(SkNSView*)fHWND enterFullScreenMode:(NSScreen* _Nonnull)screen withOptions:nil]; + } return true; } - -#endif diff --git a/gfx/skia/skia/src/views/mac/SkOptionsTableView.mm b/gfx/skia/skia/src/views/mac/SkOptionsTableView.mm index b4cdbf4119b5..51d486483307 100644 --- a/gfx/skia/skia/src/views/mac/SkOptionsTableView.mm +++ b/gfx/skia/skia/src/views/mac/SkOptionsTableView.mm @@ -96,7 +96,7 @@ int index = 0, count = 0; SkOSMenu::FindListItemCount(*item->getEvent(), &count); NSMutableArray* optionstrs = [[NSMutableArray alloc] initWithCapacity:count]; - SkAutoTDeleteArray ada(new SkString[count]); + std::unique_ptr ada(new SkString[count]); SkString* options = ada.get(); SkOSMenu::FindListItems(*item->getEvent(), options); for (int i = 0; i < count; ++i) diff --git a/gfx/skia/skia/src/views/mac/skia_mac.mm b/gfx/skia/skia/src/views/mac/skia_mac.mm index 98d4c4bd9244..b2c59516e0e9 100644 --- a/gfx/skia/skia/src/views/mac/skia_mac.mm +++ b/gfx/skia/skia/src/views/mac/skia_mac.mm @@ -27,12 +27,12 @@ } - (void)dealloc { - delete fWind; + delete self.fWind; [super dealloc]; } - (void)begin { - fWind = create_sk_window(self, *_NSGetArgc(), *_NSGetArgv()); + self.fWind = create_sk_window(self, *_NSGetArgc(), *_NSGetArgv()); [self setUpWindow]; } @end diff --git a/gfx/skia/skia/src/views/sdl/SkOSWindow_SDL.cpp b/gfx/skia/skia/src/views/sdl/SkOSWindow_SDL.cpp deleted file mode 100644 index 88b8353b6c0b..000000000000 --- a/gfx/skia/skia/src/views/sdl/SkOSWindow_SDL.cpp +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkOSWindow_SDL.h" -#include "SkCanvas.h" - -#if defined(SK_BUILD_FOR_ANDROID) -#include -#elif defined(SK_BUILD_FOR_UNIX) -#include -#elif defined(SK_BUILD_FOR_MAC) -#include -#endif - -const int kInitialWindowWidth = 640; -const int kInitialWindowHeight = 480; -static SkOSWindow* gCurrentWindow; - -static void report_sdl_error(const char* failure) { - const char* error = SDL_GetError(); - SkASSERT(error); // Called only to check SDL error. - SkDebugf("%s SDL Error: %s.\n", failure, error); - SDL_ClearError(); -} -SkOSWindow::SkOSWindow(void*) - : fWindow(nullptr) - , fGLContext(nullptr) - , fWindowMSAASampleCount(0) { - - SkASSERT(!gCurrentWindow); - gCurrentWindow = this; - - this->createWindow(0); -} - -SkOSWindow::~SkOSWindow() { - this->destroyWindow(); - gCurrentWindow = nullptr; -} - -SkOSWindow* SkOSWindow::GetInstanceForWindowID(Uint32 windowID) { - if (gCurrentWindow && - gCurrentWindow->fWindow && - SDL_GetWindowID(gCurrentWindow->fWindow) == windowID) { - return gCurrentWindow; - } - return nullptr; -} - -void SkOSWindow::release() { - if (fGLContext) { - SDL_GL_DeleteContext(fGLContext); - fGLContext = nullptr; - } -} - -bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, - AttachmentInfo* info) { - this->createWindow(msaaSampleCount); - if (!fWindow) { - return false; - } - if (!fGLContext) { - fGLContext = SDL_GL_CreateContext(fWindow); - if (!fGLContext) { - report_sdl_error("Failed to create SDL GL context."); - return false; - } - glClearColor(0, 0, 0, 0); - glClearStencil(0); - glStencilMask(0xffffffff); - glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - - if (SDL_GL_MakeCurrent(fWindow, fGLContext) != 0) { - report_sdl_error("Failed to make SDL GL context current."); - this->release(); - return false; - } - - info->fSampleCount = msaaSampleCount; - info->fStencilBits = 8; - - glViewport(0, 0, SkScalarRoundToInt(this->width()), SkScalarRoundToInt(this->height())); - return true; -} - -void SkOSWindow::present() { - if (!fWindow) { - return; - } - SDL_GL_SwapWindow(fWindow); -} - -bool SkOSWindow::makeFullscreen() { - if (!fWindow) { - return false; - } - SDL_SetWindowFullscreen(fWindow, SDL_WINDOW_FULLSCREEN_DESKTOP); - return true; -} - -void SkOSWindow::setVsync(bool vsync) { - if (!fWindow) { - return; - } - SDL_GL_SetSwapInterval(vsync ? 1 : 0); -} - -void SkOSWindow::closeWindow() { - this->destroyWindow(); - - // Currently closing the window causes the app to quit. - SDL_Event event; - event.type = SDL_QUIT; - SDL_PushEvent(&event); -} - -static SkKey convert_sdlkey_to_skkey(SDL_Keycode src) { - switch (src) { - case SDLK_UP: - return kUp_SkKey; - case SDLK_DOWN: - return kDown_SkKey; - case SDLK_LEFT: - return kLeft_SkKey; - case SDLK_RIGHT: - return kRight_SkKey; - case SDLK_HOME: - return kHome_SkKey; - case SDLK_END: - return kEnd_SkKey; - case SDLK_ASTERISK: - return kStar_SkKey; - case SDLK_HASH: - return kHash_SkKey; - case SDLK_0: - return k0_SkKey; - case SDLK_1: - return k1_SkKey; - case SDLK_2: - return k2_SkKey; - case SDLK_3: - return k3_SkKey; - case SDLK_4: - return k4_SkKey; - case SDLK_5: - return k5_SkKey; - case SDLK_6: - return k6_SkKey; - case SDLK_7: - return k7_SkKey; - case SDLK_8: - return k8_SkKey; - case SDLK_9: - return k9_SkKey; - default: - return kNONE_SkKey; - } -} - -void SkOSWindow::createWindow(int msaaSampleCount) { - if (fWindowMSAASampleCount != msaaSampleCount) { - this->destroyWindow(); - } - if (fWindow) { - return; - } - uint32_t windowFlags = -#if defined(SK_BUILD_FOR_ANDROID) - SDL_WINDOW_BORDERLESS | SDL_WINDOW_FULLSCREEN_DESKTOP | - SDL_WINDOW_ALLOW_HIGHDPI | -#endif - SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; - - // GL settings are part of SDL_WINDOW_OPENGL window creation arguments. -#if defined(SK_BUILD_FOR_ANDROID) - // TODO we should try and get a 3.0 context first - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); -#else - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); -#endif - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); -#if defined(SK_BUILD_FOR_UNIX) - // Apparently MSAA request matches "slow caveat". Make SDL not set anything for caveat for MSAA - // by setting -1 for ACCELERATED_VISUAL. For non-MSAA, set ACCELERATED_VISUAL to 1 just for - // compatiblity with other platforms. - SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, msaaSampleCount > 0 ? -1 : 1); -#else - SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); -#endif - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, msaaSampleCount > 0 ? 1 : 0); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaaSampleCount); - - // This is an approximation for sizing purposes. - bool isInitialWindow = this->width() == 0 && this->height() == 0; - SkScalar windowWidth = isInitialWindow ? kInitialWindowWidth : this->width(); - SkScalar windowHeight = isInitialWindow ? kInitialWindowHeight : this->height(); - - fWindow = SDL_CreateWindow(this->getTitle(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - windowWidth, windowHeight, windowFlags); - if (!fWindow) { - report_sdl_error("Failed to create SDL window."); - return; - } - fWindowMSAASampleCount = msaaSampleCount; -} - -void SkOSWindow::destroyWindow() { - this->release(); - if (fWindow) { - SDL_DestroyWindow(fWindow); - fWindow = nullptr; - fWindowMSAASampleCount = 0; - } -} - -bool SkOSWindow::HasDirtyWindows() { - if (gCurrentWindow && gCurrentWindow->fWindow) { - return gCurrentWindow->isDirty(); - } - return false; -} - -void SkOSWindow::UpdateDirtyWindows() { - if (gCurrentWindow && gCurrentWindow->fWindow) { - if (gCurrentWindow->isDirty()) { - // This will call present. - gCurrentWindow->update(nullptr); - } - } -} - -void SkOSWindow::HandleEvent(const SDL_Event& event) { - switch (event.type) { - case SDL_MOUSEMOTION: - if (SkOSWindow* window = GetInstanceForWindowID(event.motion.windowID)) { - if (event.motion.state == SDL_PRESSED) { - window->handleClick(event.motion.x, event.motion.y, - SkView::Click::kMoved_State, nullptr); - } - } - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - if (SkOSWindow* window = GetInstanceForWindowID(event.button.windowID)) { - window->handleClick(event.button.x, event.button.y, - event.button.state == SDL_PRESSED ? - SkView::Click::kDown_State : - SkView::Click::kUp_State, nullptr); - } - break; - case SDL_KEYDOWN: - if (SkOSWindow* window = GetInstanceForWindowID(event.key.windowID)) { - SDL_Keycode key = event.key.keysym.sym; - SkKey sk = convert_sdlkey_to_skkey(key); - if (kNONE_SkKey != sk) { - if (event.key.state == SDL_PRESSED) { - window->handleKey(sk); - } else { - window->handleKeyUp(sk); - } - } else if (key == SDLK_ESCAPE) { - window->closeWindow(); - } - } - break; - case SDL_TEXTINPUT: - if (SkOSWindow* window = GetInstanceForWindowID(event.text.windowID)) { - size_t len = strlen(event.text.text); - for (size_t i = 0; i < len; i++) { - window->handleChar((SkUnichar)event.text.text[i]); - } - } - break; - case SDL_WINDOWEVENT: - switch (event.window.event) { - case SDL_WINDOWEVENT_SHOWN: - // For initialization purposes, we resize upon first show. - // Fallthrough. - case SDL_WINDOWEVENT_SIZE_CHANGED: - if (SkOSWindow* window = GetInstanceForWindowID(event.window.windowID)) { - int w = 0; - int h = 0; - SDL_GetWindowSize(window->fWindow, &w, &h); - window->resize(w, h); - } - break; - case SDL_WINDOWEVENT_FOCUS_GAINED: - if (GetInstanceForWindowID(event.text.windowID)) { - SDL_StartTextInput(); - } - break; - default: - break; - } - break; - default: - break; - } -} - -SkMSec gTimerDelay; - -void SkOSWindow::RunEventLoop() { - for (;;) { - SkEvent::ServiceQueueTimer(); - bool hasMoreSkEvents = SkEvent::ProcessEvent(); - - SDL_Event event; - bool hasSDLEvents = SDL_PollEvent(&event) == 1; - - // Invalidations do not post to event loop, rather we just go through the - // windows for each event loop iteration. - bool hasDirtyWindows = HasDirtyWindows(); - - if (!hasSDLEvents && !hasMoreSkEvents && !hasDirtyWindows) { - // If there is no SDL events, SkOSWindow updates or SkEvents - // to be done, wait for the SDL events. - if (gTimerDelay > 0) { - hasSDLEvents = SDL_WaitEventTimeout(&event, gTimerDelay) == 1; - } else { - hasSDLEvents = SDL_WaitEvent(&event) == 1; - } - } - while (hasSDLEvents) { - if (event.type == SDL_QUIT) { - return; - } - HandleEvent(event); - hasSDLEvents = SDL_PollEvent(&event); - } - UpdateDirtyWindows(); - } -} - -void SkOSWindow::onSetTitle(const char title[]) { - if (!fWindow) { - return; - } - this->updateWindowTitle(); -} - -void SkOSWindow::updateWindowTitle() { - SDL_SetWindowTitle(fWindow, this->getTitle()); -} -/////////////////////////////////////////////////////////////////////////////////////// - -void SkEvent::SignalNonEmptyQueue() { - // nothing to do, since we spin on our event-queue -} - -void SkEvent::SignalQueueTimer(SkMSec delay) { - gTimerDelay = delay; -} - -////////////////////////////////////////////////////////////////////////////////////////////// - -#include "SkApplication.h" -#include "SkEvent.h" -#include "SkWindow.h" - -#if defined(SK_BUILD_FOR_ANDROID) -int SDL_main(int argc, char** argv) { -#else -int main(int argc, char** argv) { -#endif - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { - report_sdl_error("Failed to init SDL."); - return -1; - } - - application_init(); - - SkOSWindow* window = create_sk_window(nullptr, argc, argv); - - // drain any events that occurred before |window| was assigned. - while (SkEvent::ProcessEvent()); - - SkOSWindow::RunEventLoop(); - - delete window; - application_term(); - - SDL_Quit(); - - return 0; -} diff --git a/gfx/skia/skia/src/xml/SkDOM.cpp b/gfx/skia/skia/src/xml/SkDOM.cpp index 38ba669bb713..2e37dd78072d 100644 --- a/gfx/skia/skia/src/xml/SkDOM.cpp +++ b/gfx/skia/skia/src/xml/SkDOM.cpp @@ -8,31 +8,32 @@ #include "SkDOM.h" #include "SkStream.h" +#include "SkXMLParser.h" #include "SkXMLWriter.h" -///////////////////////////////////////////////////////////////////////// - -#include "SkXMLParser.h" -bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) -{ +bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) { const char* elemName = dom.getName(node); - if (this->startElement(elemName)) + if (this->startElement(elemName)) { return false; + } SkDOM::AttrIter iter(dom, node); const char* name, *value; - while ((name = iter.next(&value)) != nullptr) - if (this->addAttribute(name, value)) + while ((name = iter.next(&value)) != nullptr) { + if (this->addAttribute(name, value)) { return false; + } + } - if ((node = dom.getFirstChild(node)) != nullptr) + if ((node = dom.getFirstChild(node)) != nullptr) { do { - if (!this->parse(dom, node)) + if (!this->parse(dom, node)) { return false; + } } while ((node = dom.getNextSibling(node)) != nullptr); - + } return !this->endElement(elemName); } @@ -47,86 +48,78 @@ struct SkDOMNode { const char* fName; SkDOMNode* fFirstChild; SkDOMNode* fNextSibling; + SkDOMAttr* fAttrs; uint16_t fAttrCount; uint8_t fType; uint8_t fPad; - const SkDOMAttr* attrs() const - { - return (const SkDOMAttr*)(this + 1); + const SkDOMAttr* attrs() const { + return fAttrs; } - SkDOMAttr* attrs() - { - return (SkDOMAttr*)(this + 1); + + SkDOMAttr* attrs() { + return fAttrs; } }; ///////////////////////////////////////////////////////////////////////// -#define kMinChunkSize 512 +#define kMinChunkSize 4096 -SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) -{ -} +SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {} -SkDOM::~SkDOM() -{ -} +SkDOM::~SkDOM() {} -const SkDOM::Node* SkDOM::getRootNode() const -{ +const SkDOM::Node* SkDOM::getRootNode() const { return fRoot; } -const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const -{ +const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const { SkASSERT(node); const Node* child = node->fFirstChild; - if (name) - { - for (; child != nullptr; child = child->fNextSibling) - if (!strcmp(name, child->fName)) + if (name) { + for (; child != nullptr; child = child->fNextSibling) { + if (!strcmp(name, child->fName)) { break; + } + } } return child; } -const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const -{ +const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const { SkASSERT(node); const Node* sibling = node->fNextSibling; - if (name) - { - for (; sibling != nullptr; sibling = sibling->fNextSibling) - if (!strcmp(name, sibling->fName)) + if (name) { + for (; sibling != nullptr; sibling = sibling->fNextSibling) { + if (!strcmp(name, sibling->fName)) { break; + } + } } return sibling; } -SkDOM::Type SkDOM::getType(const Node* node) const -{ +SkDOM::Type SkDOM::getType(const Node* node) const { SkASSERT(node); return (Type)node->fType; } -const char* SkDOM::getName(const Node* node) const -{ +const char* SkDOM::getName(const Node* node) const { SkASSERT(node); return node->fName; } -const char* SkDOM::findAttr(const Node* node, const char name[]) const -{ +const char* SkDOM::findAttr(const Node* node, const char name[]) const { SkASSERT(node); const Attr* attr = node->attrs(); const Attr* stop = attr + node->fAttrCount; - while (attr < stop) - { - if (!strcmp(attr->fName, name)) + while (attr < stop) { + if (!strcmp(attr->fName, name)) { return attr->fValue; + } attr += 1; } return nullptr; @@ -134,28 +127,25 @@ const char* SkDOM::findAttr(const Node* node, const char name[]) const ///////////////////////////////////////////////////////////////////////////////////// -const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const -{ +const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const { return node->fAttrCount ? node->attrs() : nullptr; } -const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const -{ +const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const { SkASSERT(node); - if (attr == nullptr) + if (attr == nullptr) { return nullptr; + } return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr; } -const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const -{ +const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const { SkASSERT(node); SkASSERT(attr); return attr->fName; } -const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const -{ +const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const { SkASSERT(node); SkASSERT(attr); return attr->fValue; @@ -163,19 +153,16 @@ const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const ///////////////////////////////////////////////////////////////////////////////////// -SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) -{ +SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) { SkASSERT(node); fAttr = node->attrs(); fStop = fAttr + node->fAttrCount; } -const char* SkDOM::AttrIter::next(const char** value) -{ +const char* SkDOM::AttrIter::next(const char** value) { const char* name = nullptr; - if (fAttr < fStop) - { + if (fAttr < fStop) { name = fAttr->fName; if (value) *value = fAttr->fValue; @@ -189,19 +176,17 @@ const char* SkDOM::AttrIter::next(const char** value) #include "SkXMLParser.h" #include "SkTDArray.h" -static char* dupstr(SkChunkAlloc* chunk, const char src[]) -{ +static char* dupstr(SkArenaAlloc* chunk, const char src[]) { SkASSERT(chunk && src); size_t len = strlen(src); - char* dst = (char*)chunk->alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType); + char* dst = chunk->makeArrayDefault(len + 1); memcpy(dst, src, len + 1); return dst; } class SkDOMParser : public SkXMLParser { public: - SkDOMParser(SkChunkAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) - { + SkDOMParser(SkArenaAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) { fAlloc->reset(); fRoot = nullptr; fLevel = 0; @@ -211,27 +196,24 @@ public: SkXMLParserError fParserError; protected: - void flushAttributes() - { + void flushAttributes() { SkASSERT(fLevel > 0); int attrCount = fAttrs.count(); - SkDOM::Node* node = (SkDOM::Node*)fAlloc->alloc(sizeof(SkDOM::Node) + attrCount * sizeof(SkDOM::Attr), - SkChunkAlloc::kThrow_AllocFailType); + SkDOMAttr* attrs = fAlloc->makeArrayDefault(attrCount); + SkDOM::Node* node = fAlloc->make(); node->fName = fElemName; node->fFirstChild = nullptr; node->fAttrCount = SkToU16(attrCount); + node->fAttrs = attrs; node->fType = fElemType; - if (fRoot == nullptr) - { + if (fRoot == nullptr) { node->fNextSibling = nullptr; fRoot = node; - } - else // this adds siblings in reverse order. gets corrected in onEndElement() - { + } else { // this adds siblings in reverse order. gets corrected in onEndElement() SkDOM::Node* parent = fParentStack.top(); SkASSERT(fRoot && parent); node->fNextSibling = parent->fFirstChild; @@ -268,8 +250,7 @@ protected: SkDOM::Node* child = parent->fFirstChild; SkDOM::Node* prev = nullptr; - while (child) - { + while (child) { SkDOM::Node* next = child->fNextSibling; child->fNextSibling = prev; prev = child; @@ -289,9 +270,9 @@ protected: private: void startCommon(const char elem[], SkDOM::Type type) { - if (fLevel > 0 && fNeedToFlush) + if (fLevel > 0 && fNeedToFlush) { this->flushAttributes(); - + } fNeedToFlush = true; fElemName = dupstr(fAlloc, elem); fElemType = type; @@ -299,7 +280,7 @@ private: } SkTDArray fParentStack; - SkChunkAlloc* fAlloc; + SkArenaAlloc* fAlloc; SkDOM::Node* fRoot; bool fNeedToFlush; @@ -325,8 +306,7 @@ const SkDOM::Node* SkDOM::build(SkStream& docStream) { /////////////////////////////////////////////////////////////////////////// -static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) -{ +static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) { const char* elem = dom.getName(node); if (dom.getType(node) == SkDOM::kText_Type) { SkASSERT(dom.countChildren(node) == 0); @@ -352,8 +332,7 @@ static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* par parser->endElement(elem); } -const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) -{ +const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) { SkDOMParser parser(&fAlloc); walk_dom(dom, node, &parser); @@ -379,13 +358,11 @@ const SkDOM::Node* SkDOM::finishParsing() { ////////////////////////////////////////////////////////////////////////// -int SkDOM::countChildren(const Node* node, const char elem[]) const -{ +int SkDOM::countChildren(const Node* node, const char elem[]) const { int count = 0; node = this->getFirstChild(node, elem); - while (node) - { + while (node) { count += 1; node = this->getNextSibling(node, elem); } @@ -396,82 +373,56 @@ int SkDOM::countChildren(const Node* node, const char elem[]) const #include "SkParse.h" -bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const -{ +bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const { const char* vstr = this->findAttr(node, name); return vstr && SkParse::FindS32(vstr, value); } -bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const -{ +bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const { const char* vstr = this->findAttr(node, name); return vstr && SkParse::FindScalars(vstr, value, count); } -bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const -{ +bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const { const char* vstr = this->findAttr(node, name); return vstr && SkParse::FindHex(vstr, value); } -bool SkDOM::findBool(const Node* node, const char name[], bool* value) const -{ +bool SkDOM::findBool(const Node* node, const char name[], bool* value) const { const char* vstr = this->findAttr(node, name); return vstr && SkParse::FindBool(vstr, value); } -int SkDOM::findList(const Node* node, const char name[], const char list[]) const -{ +int SkDOM::findList(const Node* node, const char name[], const char list[]) const { const char* vstr = this->findAttr(node, name); return vstr ? SkParse::FindList(vstr, list) : -1; } -bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const -{ +bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const { const char* vstr = this->findAttr(node, name); return vstr && !strcmp(vstr, value); } -bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const -{ +bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const { const char* vstr = this->findAttr(node, name); int32_t value; return vstr && SkParse::FindS32(vstr, &value) && value == target; } -bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const -{ +bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const { const char* vstr = this->findAttr(node, name); SkScalar value; return vstr && SkParse::FindScalar(vstr, &value) && value == target; } -bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const -{ +bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const { const char* vstr = this->findAttr(node, name); uint32_t value; return vstr && SkParse::FindHex(vstr, &value) && value == target; } -bool SkDOM::hasBool(const Node* node, const char name[], bool target) const -{ +bool SkDOM::hasBool(const Node* node, const char name[], bool target) const { const char* vstr = this->findAttr(node, name); bool value; return vstr && SkParse::FindBool(vstr, &value) && value == target; } - -////////////////////////////////////////////////////////////////////////// - -#ifdef SK_DEBUG - -void SkDOM::dump(const Node* node, int level) const -{ - if (node == nullptr) - node = this->getRootNode(); - - SkDebugWStream debugStream; - SkXMLStreamWriter xmlWriter(&debugStream); - xmlWriter.writeDOM(*this, node, false); -} - -#endif diff --git a/gfx/skia/skia/include/xml/SkDOM.h b/gfx/skia/skia/src/xml/SkDOM.h similarity index 88% rename from gfx/skia/skia/include/xml/SkDOM.h rename to gfx/skia/skia/src/xml/SkDOM.h index b6f611af6e97..e72bcadea875 100644 --- a/gfx/skia/skia/include/xml/SkDOM.h +++ b/gfx/skia/skia/src/xml/SkDOM.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,12 +5,11 @@ * found in the LICENSE file. */ - #ifndef SkDOM_DEFINED #define SkDOM_DEFINED #include "../private/SkTemplates.h" -#include "SkChunkAlloc.h" +#include "SkArenaAlloc.h" #include "SkScalar.h" #include "SkTypes.h" @@ -22,7 +20,7 @@ class SkDOMParser; class SkStream; class SkXMLParser; -class SK_API SkDOM : public SkNoncopyable { +class SkDOM : public SkNoncopyable { public: SkDOM(); ~SkDOM(); @@ -44,7 +42,7 @@ public: kElement_Type, kText_Type }; - Type getType(const Node*) const; + Type getType(const Node*) const; const char* getName(const Node*) const; const Node* getFirstChild(const Node*, const char elem[] = NULL) const; @@ -66,8 +64,7 @@ public: bool findBool(const Node*, const char name[], bool*) const; int findList(const Node*, const char name[], const char list[]) const; - bool findScalar(const Node* node, const char name[], SkScalar value[]) const - { + bool findScalar(const Node* node, const char name[], SkScalar value[]) const { return this->findScalars(node, name, value, 1); } @@ -86,12 +83,10 @@ public: const Attr* fStop; }; - SkDEBUGCODE(void dump(const Node* node = NULL, int tabLevel = 0) const;) - private: - SkChunkAlloc fAlloc; - Node* fRoot; - SkAutoTDelete fParser; + SkArenaAlloc fAlloc; + Node* fRoot; + std::unique_ptr fParser; typedef SkNoncopyable INHERITED; }; diff --git a/gfx/skia/skia/include/xml/SkXMLParser.h b/gfx/skia/skia/src/xml/SkXMLParser.h similarity index 100% rename from gfx/skia/skia/include/xml/SkXMLParser.h rename to gfx/skia/skia/src/xml/SkXMLParser.h diff --git a/gfx/skia/skia/src/xml/SkXMLWriter.cpp b/gfx/skia/skia/src/xml/SkXMLWriter.cpp index 5ee237ff68b4..3a2c3d40c9e6 100644 --- a/gfx/skia/skia/src/xml/SkXMLWriter.cpp +++ b/gfx/skia/skia/src/xml/SkXMLWriter.cpp @@ -9,41 +9,35 @@ #include "SkStream.h" SkXMLWriter::SkXMLWriter(bool doEscapeMarkup) : fDoEscapeMarkup(doEscapeMarkup) -{ -} +{} -SkXMLWriter::~SkXMLWriter() -{ +SkXMLWriter::~SkXMLWriter() { SkASSERT(fElems.count() == 0); } -void SkXMLWriter::flush() -{ - while (fElems.count()) +void SkXMLWriter::flush() { + while (fElems.count()) { this->endElement(); + } } -void SkXMLWriter::addAttribute(const char name[], const char value[]) -{ +void SkXMLWriter::addAttribute(const char name[], const char value[]) { this->addAttributeLen(name, value, strlen(value)); } -void SkXMLWriter::addS32Attribute(const char name[], int32_t value) -{ +void SkXMLWriter::addS32Attribute(const char name[], int32_t value) { SkString tmp; tmp.appendS32(value); this->addAttribute(name, tmp.c_str()); } -void SkXMLWriter::addHexAttribute(const char name[], uint32_t value, int minDigits) -{ +void SkXMLWriter::addHexAttribute(const char name[], uint32_t value, int minDigits) { SkString tmp("0x"); tmp.appendHex(value, minDigits); this->addAttribute(name, tmp.c_str()); } -void SkXMLWriter::addScalarAttribute(const char name[], SkScalar value) -{ +void SkXMLWriter::addScalarAttribute(const char name[], SkScalar value) { SkString tmp; tmp.appendScalar(value); this->addAttribute(name, tmp.c_str()); @@ -59,42 +53,37 @@ void SkXMLWriter::addText(const char text[], size_t length) { fElems.top()->fHasText = true; } -void SkXMLWriter::doEnd(Elem* elem) -{ +void SkXMLWriter::doEnd(Elem* elem) { delete elem; } -bool SkXMLWriter::doStart(const char name[], size_t length) -{ +bool SkXMLWriter::doStart(const char name[], size_t length) { int level = fElems.count(); bool firstChild = level > 0 && !fElems[level-1]->fHasChildren; - if (firstChild) + if (firstChild) { fElems[level-1]->fHasChildren = true; + } Elem** elem = fElems.push(); *elem = new Elem(name, length); return firstChild; } -SkXMLWriter::Elem* SkXMLWriter::getEnd() -{ +SkXMLWriter::Elem* SkXMLWriter::getEnd() { Elem* elem; fElems.pop(&elem); return elem; } -const char* SkXMLWriter::getHeader() -{ +const char* SkXMLWriter::getHeader() { static const char gHeader[] = ""; return gHeader; } -void SkXMLWriter::startElement(const char name[]) -{ +void SkXMLWriter::startElement(const char name[]) { this->startElementLen(name, strlen(name)); } -static const char* escape_char(char c, char storage[2]) -{ +static const char* escape_char(char c, char storage[2]) { static const char* gEscapeChars[] = { "<<", ">>", @@ -104,29 +93,26 @@ static const char* escape_char(char c, char storage[2]) }; const char** array = gEscapeChars; - for (unsigned i = 0; i < SK_ARRAY_COUNT(gEscapeChars); i++) - { - if (array[i][0] == c) + for (unsigned i = 0; i < SK_ARRAY_COUNT(gEscapeChars); i++) { + if (array[i][0] == c) { return &array[i][1]; + } } storage[0] = c; storage[1] = 0; return storage; } -static size_t escape_markup(char dst[], const char src[], size_t length) -{ +static size_t escape_markup(char dst[], const char src[], size_t length) { size_t extra = 0; const char* stop = src + length; - while (src < stop) - { + while (src < stop) { char orig[2]; const char* seq = escape_char(*src, orig); size_t seqSize = strlen(seq); - if (dst) - { + if (dst) { memcpy(dst, seq, seqSize); dst += seqSize; } @@ -140,15 +126,12 @@ static size_t escape_markup(char dst[], const char src[], size_t length) return extra; } -void SkXMLWriter::addAttributeLen(const char name[], const char value[], size_t length) -{ +void SkXMLWriter::addAttributeLen(const char name[], const char value[], size_t length) { SkString valueStr; - if (fDoEscapeMarkup) - { + if (fDoEscapeMarkup) { size_t extra = escape_markup(nullptr, value, length); - if (extra) - { + if (extra) { valueStr.resize(length + extra); (void)escape_markup(valueStr.writable_str(), value, length); value = valueStr.c_str(); @@ -158,17 +141,14 @@ void SkXMLWriter::addAttributeLen(const char name[], const char value[], size_t this->onAddAttributeLen(name, value, length); } -void SkXMLWriter::startElementLen(const char elem[], size_t length) -{ +void SkXMLWriter::startElementLen(const char elem[], size_t length) { this->onStartElementLen(elem, length); } //////////////////////////////////////////////////////////////////////////////////////// -static void write_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLWriter* w, bool skipRoot) -{ - if (!skipRoot) - { +static void write_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLWriter* w, bool skipRoot) { + if (!skipRoot) { const char* elem = dom.getName(node); if (dom.getType(node) == SkDOM::kText_Type) { SkASSERT(dom.countChildren(node) == 0); @@ -181,50 +161,47 @@ static void write_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLWriter* w, SkDOM::AttrIter iter(dom, node); const char* name; const char* value; - while ((name = iter.next(&value)) != nullptr) + while ((name = iter.next(&value)) != nullptr) { w->addAttribute(name, value); + } } node = dom.getFirstChild(node, nullptr); - while (node) - { + while (node) { write_dom(dom, node, w, false); node = dom.getNextSibling(node, nullptr); } - if (!skipRoot) + if (!skipRoot) { w->endElement(); + } } -void SkXMLWriter::writeDOM(const SkDOM& dom, const SkDOM::Node* node, bool skipRoot) -{ - if (node) +void SkXMLWriter::writeDOM(const SkDOM& dom, const SkDOM::Node* node, bool skipRoot) { + if (node) { write_dom(dom, node, this, skipRoot); + } } void SkXMLWriter::writeHeader() -{ -} +{} // SkXMLStreamWriter -static void tab(SkWStream& stream, int level) -{ - for (int i = 0; i < level; i++) +static void tab(SkWStream& stream, int level) { + for (int i = 0; i < level; i++) { stream.writeText("\t"); + } } SkXMLStreamWriter::SkXMLStreamWriter(SkWStream* stream) : fStream(*stream) -{ -} +{} -SkXMLStreamWriter::~SkXMLStreamWriter() -{ +SkXMLStreamWriter::~SkXMLStreamWriter() { this->flush(); } -void SkXMLStreamWriter::onAddAttributeLen(const char name[], const char value[], size_t length) -{ +void SkXMLStreamWriter::onAddAttributeLen(const char name[], const char value[], size_t length) { SkASSERT(!fElems.top()->fHasChildren && !fElems.top()->fHasText); fStream.writeText(" "); fStream.writeText(name); @@ -246,11 +223,9 @@ void SkXMLStreamWriter::onAddText(const char text[], size_t length) { fStream.newline(); } -void SkXMLStreamWriter::onEndElement() -{ +void SkXMLStreamWriter::onEndElement() { Elem* elem = getEnd(); - if (elem->fHasChildren || elem->fHasText) - { + if (elem->fHasChildren || elem->fHasText) { tab(fStream, fElems.count()); fStream.writeText("fName.c_str()); @@ -262,11 +237,9 @@ void SkXMLStreamWriter::onEndElement() doEnd(elem); } -void SkXMLStreamWriter::onStartElementLen(const char name[], size_t length) -{ +void SkXMLStreamWriter::onStartElementLen(const char name[], size_t length) { int level = fElems.count(); - if (this->doStart(name, length)) - { + if (this->doStart(name, length)) { // the first child, need to close with > fStream.writeText(">"); fStream.newline(); @@ -277,8 +250,7 @@ void SkXMLStreamWriter::onStartElementLen(const char name[], size_t length) fStream.write(name, length); } -void SkXMLStreamWriter::writeHeader() -{ +void SkXMLStreamWriter::writeHeader() { const char* header = getHeader(); fStream.write(header, strlen(header)); fStream.newline(); @@ -293,13 +265,11 @@ SkXMLParserWriter::SkXMLParserWriter(SkXMLParser* parser) { } -SkXMLParserWriter::~SkXMLParserWriter() -{ +SkXMLParserWriter::~SkXMLParserWriter() { this->flush(); } -void SkXMLParserWriter::onAddAttributeLen(const char name[], const char value[], size_t length) -{ +void SkXMLParserWriter::onAddAttributeLen(const char name[], const char value[], size_t length) { SkASSERT(fElems.count() == 0 || (!fElems.top()->fHasChildren && !fElems.top()->fHasText)); SkString str(value, length); fParser.addAttribute(name, str.c_str()); @@ -309,53 +279,14 @@ void SkXMLParserWriter::onAddText(const char text[], size_t length) { fParser.text(text, SkToInt(length)); } -void SkXMLParserWriter::onEndElement() -{ +void SkXMLParserWriter::onEndElement() { Elem* elem = this->getEnd(); fParser.endElement(elem->fName.c_str()); this->doEnd(elem); } -void SkXMLParserWriter::onStartElementLen(const char name[], size_t length) -{ +void SkXMLParserWriter::onStartElementLen(const char name[], size_t length) { (void)this->doStart(name, length); SkString str(name, length); fParser.startElement(str.c_str()); } - - -//////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// - -#ifdef SK_DEBUG - -void SkXMLStreamWriter::UnitTest() -{ -#ifdef SK_SUPPORT_UNITTEST - SkDebugWStream s; - SkXMLStreamWriter w(&s); - - w.startElement("elem0"); - w.addAttribute("hello", "world"); - w.addS32Attribute("dec", 42); - w.addHexAttribute("hex", 0x42, 3); - w.addScalarAttribute("scalar", -4.2f); - w.startElement("elem1"); - w.endElement(); - w.startElement("elem1"); - w.addAttribute("name", "value"); - w.endElement(); - w.startElement("elem1"); - w.startElement("elem2"); - w.startElement("elem3"); - w.addAttribute("name", "value"); - w.endElement(); - w.endElement(); - w.startElement("elem2"); - w.endElement(); - w.endElement(); - w.endElement(); -#endif -} - -#endif diff --git a/gfx/skia/skia/include/xml/SkXMLWriter.h b/gfx/skia/skia/src/xml/SkXMLWriter.h similarity index 96% rename from gfx/skia/skia/include/xml/SkXMLWriter.h rename to gfx/skia/skia/src/xml/SkXMLWriter.h index 32901267de58..c500e16c3388 100644 --- a/gfx/skia/skia/include/xml/SkXMLWriter.h +++ b/gfx/skia/skia/src/xml/SkXMLWriter.h @@ -64,9 +64,8 @@ private: class SkXMLStreamWriter : public SkXMLWriter { public: SkXMLStreamWriter(SkWStream*); - virtual ~SkXMLStreamWriter(); + ~SkXMLStreamWriter() override; void writeHeader() override; - SkDEBUGCODE(static void UnitTest();) protected: void onStartElementLen(const char elem[], size_t length) override; @@ -81,7 +80,7 @@ private: class SkXMLParserWriter : public SkXMLWriter { public: SkXMLParserWriter(SkXMLParser*); - virtual ~SkXMLParserWriter(); + ~SkXMLParserWriter() override; protected: void onStartElementLen(const char elem[], size_t length) override; void onEndElement() override; diff --git a/gfx/skia/skia/src/xps/SkDocument_XPS.cpp b/gfx/skia/skia/src/xps/SkDocument_XPS.cpp deleted file mode 100644 index 4a977aeaeeb0..000000000000 --- a/gfx/skia/skia/src/xps/SkDocument_XPS.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTypes.h" -#if defined(SK_BUILD_FOR_WIN32) - -#include "SkDocument.h" -#include "SkXPSDevice.h" -#include "SkStream.h" - -class SkDocument_XPS : public SkDocument { -public: - SkDocument_XPS(SkWStream* stream, - void (*doneProc)(SkWStream*, bool), - SkScalar dpi) - : SkDocument(stream, doneProc) { - const SkScalar kPointsPerMeter = SkDoubleToScalar(360000.0 / 127.0); - fUnitsPerMeter.set(kPointsPerMeter, kPointsPerMeter); - SkScalar pixelsPerMeterScale = SkDoubleToScalar(dpi * 5000.0 / 127.0); - fPixelsPerMeter.set(pixelsPerMeterScale, pixelsPerMeterScale); - fDevice.beginPortfolio(stream); - } - - virtual ~SkDocument_XPS() { - // subclasses must call close() in their destructors - this->close(); - } - -protected: - SkCanvas* onBeginPage(SkScalar width, - SkScalar height, - const SkRect& trimBox) override { - fDevice.beginSheet(fUnitsPerMeter, fPixelsPerMeter, - SkSize::Make(width, height)); - fCanvas.reset(new SkCanvas(&fDevice)); - fCanvas->clipRect(trimBox); - fCanvas->translate(trimBox.x(), trimBox.y()); - return fCanvas.get(); - } - - void onEndPage() override { - SkASSERT(fCanvas.get()); - fCanvas->flush(); - fCanvas.reset(nullptr); - fDevice.endSheet(); - } - - void onClose(SkWStream*) override { - SkASSERT(!fCanvas.get()); - (void)fDevice.endPortfolio(); - } - - void onAbort() override {} - -private: - SkXPSDevice fDevice; - SkAutoTUnref fCanvas; - SkVector fUnitsPerMeter; - SkVector fPixelsPerMeter; -}; - -/////////////////////////////////////////////////////////////////////////////// - -sk_sp SkDocument::MakeXPS(SkWStream* stream, SkScalar dpi) { - return stream ? sk_make_sp(stream, nullptr, dpi) : nullptr; -} - -static void delete_wstream(SkWStream* stream, bool aborted) { delete stream; } - -sk_sp SkDocument::MakeXPS(const char path[], SkScalar dpi) { - SkAutoTDelete stream(new SkFILEWStream(path)); - if (!stream->isValid()) { - return nullptr; - } - return sk_make_sp(stream.release(), delete_wstream, dpi); -} - -#endif//defined(SK_BUILD_FOR_WIN32) diff --git a/gfx/skia/skia/src/xps/SkDocument_XPS_None.cpp b/gfx/skia/skia/src/xps/SkDocument_XPS_None.cpp deleted file mode 100644 index b1c7ed4bcd39..000000000000 --- a/gfx/skia/skia/src/xps/SkDocument_XPS_None.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTypes.h" -#if !defined(SK_BUILD_FOR_WIN32) - -#include "SkDocument.h" -sk_sp SkDocument::MakeXPS(SkWStream*, SkScalar) { return nullptr; } -sk_sp SkDocument::MakeXPS(const char path[], SkScalar) { - return nullptr; -} - -#endif//!defined(SK_BUILD_FOR_WIN32) diff --git a/gfx/skia/skia/src/xps/SkXPSDevice.cpp b/gfx/skia/skia/src/xps/SkXPSDevice.cpp index 5db644c30ab0..4a018a97fddb 100644 --- a/gfx/skia/skia/src/xps/SkXPSDevice.cpp +++ b/gfx/skia/skia/src/xps/SkXPSDevice.cpp @@ -30,9 +30,10 @@ #include "SkGeometry.h" #include "SkGlyphCache.h" #include "SkHRESULT.h" +#include "SkIStream.h" #include "SkImage.h" #include "SkImageEncoder.h" -#include "SkIStream.h" +#include "SkImagePriv.h" #include "SkMaskFilter.h" #include "SkPaint.h" #include "SkPathEffect.h" @@ -50,6 +51,7 @@ #include "SkTTCFHeader.h" #include "SkTypefacePriv.h" #include "SkUtils.h" +#include "SkVertices.h" #include "SkXPSDevice.h" //Windows defines a FLOAT type, @@ -110,42 +112,18 @@ HRESULT SkXPSDevice::createId(wchar_t* buffer, size_t bufferSize, wchar_t sep) { return S_OK; } -static SkBitmap make_fake_bitmap(int width, int height) { - SkBitmap bitmap; - bitmap.setInfo(SkImageInfo::MakeUnknown(width, height)); - return bitmap; -} +SkXPSDevice::SkXPSDevice(SkISize s) + : INHERITED(SkImageInfo::MakeUnknown(s.width(), s.height()), + SkSurfaceProps(0, kUnknown_SkPixelGeometry)) + , fCurrentPage(0) {} -// TODO: should inherit from SkBaseDevice instead of SkBitmapDevice... -SkXPSDevice::SkXPSDevice() - : INHERITED(make_fake_bitmap(10000, 10000), SkSurfaceProps(0, kUnknown_SkPixelGeometry)) - , fCurrentPage(0) { -} - -SkXPSDevice::SkXPSDevice(IXpsOMObjectFactory* xpsFactory) - : INHERITED(make_fake_bitmap(10000, 10000), SkSurfaceProps(0, kUnknown_SkPixelGeometry)) - , fCurrentPage(0) { - - HRVM(CoCreateInstance( - CLSID_XpsOMObjectFactory, - nullptr, - CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&this->fXpsFactory)), - "Could not create factory for layer."); - - HRVM(this->fXpsFactory->CreateCanvas(&this->fCurrentXpsCanvas), - "Could not create canvas for layer."); -} - -SkXPSDevice::~SkXPSDevice() { -} +SkXPSDevice::~SkXPSDevice() {} SkXPSDevice::TypefaceUse::TypefaceUse() : typefaceId(0xffffffff) , fontData(nullptr) , xpsFont(nullptr) - , glyphsUsed(nullptr) { -} + , glyphsUsed(nullptr) {} SkXPSDevice::TypefaceUse::~TypefaceUse() { //xpsFont owns fontData ref @@ -153,20 +131,10 @@ SkXPSDevice::TypefaceUse::~TypefaceUse() { delete this->glyphsUsed; } -bool SkXPSDevice::beginPortfolio(SkWStream* outputStream) { - if (!this->fAutoCo.succeeded()) return false; - - //Create XPS Factory. - HRBM(CoCreateInstance( - CLSID_XpsOMObjectFactory, - nullptr, - CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&this->fXpsFactory)), - "Could not create XPS factory."); - - HRBM(SkWIStream::CreateFromSkWStream(outputStream, &this->fOutputStream), - "Could not convert SkStream to IStream."); - +bool SkXPSDevice::beginPortfolio(SkWStream* outputStream, IXpsOMObjectFactory* factory) { + SkASSERT(factory); + fXpsFactory.reset(SkRefComPtr(factory)); + HRB(SkWIStream::CreateFromSkWStream(outputStream, &this->fOutputStream)); return true; } @@ -185,11 +153,13 @@ bool SkXPSDevice::beginSheet( this->fCurrentCanvasSize = trimSize; this->fCurrentUnitsPerMeter = unitsPerMeter; this->fCurrentPixelsPerMeter = pixelsPerMeter; + return this->createCanvasForLayer(); +} - this->fCurrentXpsCanvas.reset(); - HRBM(this->fXpsFactory->CreateCanvas(&this->fCurrentXpsCanvas), - "Could not create base canvas."); - +bool SkXPSDevice::createCanvasForLayer() { + SkASSERT(fXpsFactory); + fCurrentXpsCanvas.reset(); + HRB(fXpsFactory->CreateCanvas(&fCurrentXpsCanvas)); return true; } @@ -428,7 +398,7 @@ static HRESULT subset_typeface(SkXPSDevice::TypefaceUse* current) { fontPackageBuffer.realloc(bytesWritten); } - SkAutoTDelete newStream(new SkMemoryStream()); + std::unique_ptr newStream(new SkMemoryStream()); newStream->setMemoryOwned(fontPackageBuffer.release(), bytesWritten + extra); SkTScopedComPtr newIStream; @@ -527,8 +497,8 @@ static void transform_offsets(SkScalar* stopOffsets, const int numOffsets, for (int i = 0; i < numOffsets; ++i) { SkPoint stop; - stop.fX = SkScalarMul(end.fX - start.fX, stopOffsets[i]); - stop.fY = SkScalarMul(end.fY - start.fY, stopOffsets[i]); + stop.fX = (end.fX - start.fX) * stopOffsets[i]; + stop.fY = (end.fY - start.fY) * stopOffsets[i]; SkPoint stopTransformed; transform.mapXY(stop.fX, stop.fY, &stopTransformed); @@ -644,11 +614,11 @@ static const XPS_TILE_MODE XTM_XY = XPS_TILE_MODE_FLIPXY; //None is currently an internal hack so masks don't repeat (None+None only). static XPS_TILE_MODE SkToXpsTileMode[SkShader::kTileModeCount+1] [SkShader::kTileModeCount+1] = { - //Clamp //Repeat //Mirror //None -/*Clamp */ XTM_N, XTM_T, XTM_Y, XTM_N, -/*Repeat*/ XTM_T, XTM_T, XTM_Y, XTM_N, -/*Mirror*/ XTM_X, XTM_X, XTM_XY, XTM_X, -/*None */ XTM_N, XTM_N, XTM_Y, XTM_N, + //Clamp //Repeat //Mirror //None + /*Clamp */ {XTM_N, XTM_T, XTM_Y, XTM_N}, + /*Repeat*/ {XTM_T, XTM_T, XTM_Y, XTM_N}, + /*Mirror*/ {XTM_X, XTM_X, XTM_XY, XTM_X}, + /*None */ {XTM_N, XTM_N, XTM_Y, XTM_N}, }; HRESULT SkXPSDevice::createXpsImageBrush( @@ -658,8 +628,7 @@ HRESULT SkXPSDevice::createXpsImageBrush( const SkAlpha alpha, IXpsOMTileBrush** xpsBrush) { SkDynamicMemoryWStream write; - if (!SkImageEncoder::EncodeStream(&write, bitmap, - SkImageEncoder::kPNG_Type, 100)) { + if (!SkEncodeImage(&write, bitmap, SkEncodedImageFormat::kPNG, 100)) { HRM(E_FAIL, "Unable to encode bitmap as png."); } SkMemoryStream* read = new SkMemoryStream; @@ -1086,7 +1055,7 @@ HRESULT SkXPSDevice::createXpsBrush(const SkPaint& skPaint, //TODO: outMatrix?? SkMatrix localMatrix = shader->getLocalMatrix(); if (parentTransform) { - localMatrix.preConcat(*parentTransform); + localMatrix.postConcat(*parentTransform); } SkTScopedComPtr tileBrush; @@ -1171,23 +1140,30 @@ HRESULT SkXPSDevice::createXpsQuad(const SkPoint (&points)[4], return S_OK; } -void SkXPSDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, +template +void draw(SkClipStackDevice* dev, F f, Args&&... args) { + SkIRect r = dev->devClipBounds(); + SkRasterClip rc(r); + SkDraw draw; + draw.fMatrix = &dev->ctm(); + draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(r.right(), r.bottom()), nullptr, 0); + draw.fRC = &rc; + (draw.*f)(std::forward(args)...); +} + + +void SkXPSDevice::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint points[], const SkPaint& paint) { - //This will call back into the device to do the drawing. - d.drawPoints(mode, count, points, paint, true); + draw(this, &SkDraw::drawPoints, mode, count, points, paint, this); } -void SkXPSDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, - int vertexCount, const SkPoint verts[], - const SkPoint texs[], const SkColor colors[], - SkXfermode* xmode, const uint16_t indices[], - int indexCount, const SkPaint& paint) { - //TODO: override this for XPS - SkDEBUGF(("XPS drawVertices not yet implemented.")); +void SkXPSDevice::drawVertices(const SkVertices* v, SkBlendMode blendMode, const SkPaint& paint) { + draw(this, &SkDraw::drawVertices, v->mode(), v->vertexCount(), v->positions(), v->texCoords(), + v->colors(), blendMode, v->indices(), v->indexCount(), paint); } -void SkXPSDevice::drawPaint(const SkDraw& d, const SkPaint& origPaint) { +void SkXPSDevice::drawPaint(const SkPaint& origPaint) { const SkRect r = SkRect::MakeSize(this->fCurrentCanvasSize); //If trying to paint with a stroke, ignore that and fill. @@ -1197,39 +1173,38 @@ void SkXPSDevice::drawPaint(const SkDraw& d, const SkPaint& origPaint) { paint.writable()->setStyle(SkPaint::kFill_Style); } - this->internalDrawRect(d, r, false, *fillPaint); + this->internalDrawRect(r, false, *fillPaint); } -void SkXPSDevice::drawRect(const SkDraw& d, - const SkRect& r, +void SkXPSDevice::drawRect(const SkRect& r, const SkPaint& paint) { - this->internalDrawRect(d, r, true, paint); + this->internalDrawRect(r, true, paint); } -void SkXPSDevice::drawRRect(const SkDraw& d, - const SkRRect& rr, +void SkXPSDevice::drawRRect(const SkRRect& rr, const SkPaint& paint) { SkPath path; path.addRRect(rr); - this->drawPath(d, path, paint, nullptr, true); + this->drawPath(path, paint, nullptr, true); } -void SkXPSDevice::internalDrawRect(const SkDraw& d, - const SkRect& r, +static SkIRect size(const SkBaseDevice& dev) { return {0, 0, dev.width(), dev.height()}; } + +void SkXPSDevice::internalDrawRect(const SkRect& r, bool transformRect, const SkPaint& paint) { //Exit early if there is nothing to draw. - if (d.fRC->isEmpty() || + if (this->cs().isEmpty(size(*this)) || (paint.getAlpha() == 0 && paint.isSrcOver())) { return; } //Path the rect if we can't optimize it. - if (rect_must_be_pathed(paint, *d.fMatrix)) { + if (rect_must_be_pathed(paint, this->ctm())) { SkPath tmp; tmp.addRect(r); tmp.setFillType(SkPath::kWinding_FillType); - this->drawPath(d, tmp, paint, nullptr, true); + this->drawPath(tmp, paint, nullptr, true); return; } @@ -1250,13 +1225,13 @@ void SkXPSDevice::internalDrawRect(const SkDraw& d, //Set the brushes. BOOL fill = FALSE; BOOL stroke = FALSE; - HRV(this->shadePath(shadedPath.get(), paint, *d.fMatrix, &fill, &stroke)); + HRV(this->shadePath(shadedPath.get(), paint, this->ctm(), &fill, &stroke)); bool xpsTransformsPath = true; //Transform the geometry. if (transformRect && xpsTransformsPath) { SkTScopedComPtr xpsTransform; - HRV(this->createXpsTransform(*d.fMatrix, &xpsTransform)); + HRV(this->createXpsTransform(this->ctm(), &xpsTransform)); if (xpsTransform.get()) { HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()), "Could not set transform for rect."); @@ -1275,7 +1250,7 @@ void SkXPSDevice::internalDrawRect(const SkDraw& d, { r.fRight, r.fTop }, }; if (!xpsTransformsPath && transformRect) { - d.fMatrix->mapPoints(points, SK_ARRAY_COUNT(points)); + this->ctm().mapPoints(points, SK_ARRAY_COUNT(points)); } HRV(this->createXpsQuad(points, stroke, fill, &rectFigure)); } @@ -1289,7 +1264,7 @@ void SkXPSDevice::internalDrawRect(const SkDraw& d, HRVM(shadedFigures->Append(rectFigure.get()), "Could not add shaded figure for rect."); - HRV(this->clip(shadedPath.get(), d)); + HRV(this->clip(shadedPath.get())); //Add the shaded path to the current visuals. SkTScopedComPtr currentVisuals; @@ -1419,16 +1394,14 @@ void SkXPSDevice::convertToPpm(const SkMaskFilter* filter, matrix->postScale(ppuScale->fX, ppuScale->fY); const SkIRect& irect = clip; - SkRect clipRect = SkRect::MakeLTRB( - SkScalarMul(SkIntToScalar(irect.fLeft), ppuScale->fX), - SkScalarMul(SkIntToScalar(irect.fTop), ppuScale->fY), - SkScalarMul(SkIntToScalar(irect.fRight), ppuScale->fX), - SkScalarMul(SkIntToScalar(irect.fBottom), ppuScale->fY)); + SkRect clipRect = SkRect::MakeLTRB(SkIntToScalar(irect.fLeft) * ppuScale->fX, + SkIntToScalar(irect.fTop) * ppuScale->fY, + SkIntToScalar(irect.fRight) * ppuScale->fX, + SkIntToScalar(irect.fBottom) * ppuScale->fY); clipRect.roundOut(clipIRect); } -HRESULT SkXPSDevice::applyMask(const SkDraw& d, - const SkMask& mask, +HRESULT SkXPSDevice::applyMask(const SkMask& mask, const SkVector& ppuScale, IXpsOMPath* shadedPath) { //Get the geometry object. @@ -1467,7 +1440,7 @@ HRESULT SkXPSDevice::applyMask(const SkDraw& d, HRM(shadedFigures->Append(shadedFigure.get()), "Could not add mask shaded figure."); - HR(this->clip(shadedPath, d)); + HR(this->clip(shadedPath)); //Add the path to the active visual collection. SkTScopedComPtr currentVisuals; @@ -1527,15 +1500,14 @@ HRESULT SkXPSDevice::shadePath(IXpsOMPath* shadedPath, return S_OK; } -void SkXPSDevice::drawPath(const SkDraw& d, - const SkPath& platonicPath, +void SkXPSDevice::drawPath(const SkPath& platonicPath, const SkPaint& origPaint, const SkMatrix* prePathMatrix, bool pathIsMutable) { SkTCopyOnFirstWrite paint(origPaint); // nothing to draw - if (d.fRC->isEmpty() || + if (this->cs().isEmpty(size(*this)) || (paint->getAlpha() == 0 && paint->isSrcOver())) { return; } @@ -1545,7 +1517,7 @@ void SkXPSDevice::drawPath(const SkDraw& d, || paint->getStyle() != SkPaint::kFill_Style; //Apply pre-path matrix [Platonic-path -> Skeletal-path]. - SkMatrix matrix = *d.fMatrix; + SkMatrix matrix = this->ctm(); SkPath* skeletalPath = const_cast(&platonicPath); if (prePathMatrix) { if (paintHasPathEffect || paint->getRasterizer()) { @@ -1607,7 +1579,7 @@ void SkXPSDevice::drawPath(const SkDraw& d, BOOL stroke; HRV(this->shadePath(shadedPath.get(), *paint, - *d.fMatrix, + this->ctm(), &fill, &stroke)); @@ -1618,7 +1590,7 @@ void SkXPSDevice::drawPath(const SkDraw& d, this->convertToPpm(filter, &matrix, &ppuScale, - d.fRC->getBounds(), + this->cs().bounds(size(*this)).roundOut(), &clipIRect); SkMask* mask = nullptr; @@ -1638,13 +1610,13 @@ void SkXPSDevice::drawPath(const SkDraw& d, //[Mask -> Mask] SkMask filteredMask; - if (filter && filter->filterMask(&filteredMask, *mask, *d.fMatrix, nullptr)) { + if (filter && filter->filterMask(&filteredMask, *mask, this->ctm(), nullptr)) { mask = &filteredMask; } SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); //Draw mask. - HRV(this->applyMask(d, *mask, ppuScale, shadedPath.get())); + HRV(this->applyMask(*mask, ppuScale, shadedPath.get())); } return; } @@ -1656,7 +1628,7 @@ void SkXPSDevice::drawPath(const SkDraw& d, this->convertToPpm(filter, &matrix, &ppuScale, - d.fRC->getBounds(), + this->cs().bounds(size(*this)).roundOut(), &clipIRect); //[Fillable-path -> Pixel-path] @@ -1692,7 +1664,7 @@ void SkXPSDevice::drawPath(const SkDraw& d, SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); //Draw mask. - HRV(this->applyMask(d, *mask, ppuScale, shadedPath.get())); + HRV(this->applyMask(*mask, ppuScale, shadedPath.get())); } return; } @@ -1767,7 +1739,7 @@ void SkXPSDevice::drawPath(const SkDraw& d, HRV(this->addXpsPathGeometry(shadedFigures.get(), stroke, fill, *devicePath)); - HRV(this->clip(shadedPath.get(), d)); + HRV(this->clip(shadedPath.get())); //Add the path to the active visual collection. SkTScopedComPtr currentVisuals; @@ -1777,16 +1749,10 @@ void SkXPSDevice::drawPath(const SkDraw& d, "Could not add shaded path to current visuals."); } -HRESULT SkXPSDevice::clip(IXpsOMVisual* xpsVisual, const SkDraw& d) { +HRESULT SkXPSDevice::clip(IXpsOMVisual* xpsVisual) { SkPath clipPath; - if (d.fRC->isBW()) { - SkAssertResult(d.fRC->bwRgn().getBoundaryPath(&clipPath)); - } else { - // Don't have a way to turn a AAClip into a path, so we just use the bounds. - // TODO: consider using fClipStack instead? - clipPath.addRect(SkRect::Make(d.fRC->getBounds())); - } - + // clipPath.addRect(this->cs().bounds(size(*this))); + (void)this->cs().asPath(&clipPath); return this->clipToPath(xpsVisual, clipPath, XPS_FILL_RULE_EVENODD); } HRESULT SkXPSDevice::clipToPath(IXpsOMVisual* xpsVisual, @@ -1815,9 +1781,9 @@ HRESULT SkXPSDevice::clipToPath(IXpsOMVisual* xpsVisual, return S_OK; } -void SkXPSDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap, +void SkXPSDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint& paint) { - if (d.fRC->isEmpty()) { + if (this->cs().isEmpty(size(*this))) { return; } @@ -1844,7 +1810,7 @@ void SkXPSDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap, "Could not get the figures for bitmap."); SkMatrix transform = matrix; - transform.postConcat(*d.fMatrix); + transform.postConcat(this->ctm()); SkTScopedComPtr xpsTransform; HRV(this->createXpsTransform(transform, &xpsTransform)); @@ -1884,12 +1850,10 @@ void SkXPSDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap, HRVM(currentVisuals->Append(shadedPath.get()), "Could not add bitmap to current visuals."); - HRV(this->clip(shadedPath.get(), d)); + HRV(this->clip(shadedPath.get())); } -void SkXPSDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, - int x, int y, - const SkPaint& paint) { +void SkXPSDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) { //TODO: override this for XPS SkDEBUGF(("XPS drawSprite not yet implemented.")); } @@ -1962,8 +1926,7 @@ HRESULT SkXPSDevice::CreateTypefaceUse(const SkPaint& paint, return S_OK; } -HRESULT SkXPSDevice::AddGlyphs(const SkDraw& d, - IXpsOMObjectFactory* xpsFactory, +HRESULT SkXPSDevice::AddGlyphs(IXpsOMObjectFactory* xpsFactory, IXpsOMCanvas* canvas, TypefaceUse* font, LPCWSTR text, @@ -2034,7 +1997,7 @@ HRESULT SkXPSDevice::AddGlyphs(const SkDraw& d, HRM(canvas->GetVisuals(&visuals), "Could not get glyph canvas visuals."); if (!useCanvasForClip) { - HR(this->clip(glyphs.get(), d)); + HR(this->clip(glyphs.get())); HRM(visuals->Append(glyphs.get()), "Could not add glyphs to canvas."); } else { SkTScopedComPtr glyphCanvas; @@ -2047,7 +2010,7 @@ HRESULT SkXPSDevice::AddGlyphs(const SkDraw& d, HRM(glyphCanvasVisuals->Append(glyphs.get()), "Could not add glyphs to page."); - HR(this->clip(glyphCanvas.get(), d)); + HR(this->clip(glyphCanvas.get())); HRM(visuals->Append(glyphCanvas.get()), "Could not add glyph canvas to page."); @@ -2124,16 +2087,15 @@ private: GlyphRun* const fXpsGlyphs; }; -void SkXPSDevice::drawText(const SkDraw& d, - const void* text, size_t byteLen, +void SkXPSDevice::drawText(const void* text, size_t byteLen, SkScalar x, SkScalar y, const SkPaint& paint) { if (byteLen < 1) return; - if (text_must_be_pathed(paint, *d.fMatrix)) { + if (text_must_be_pathed(paint, this->ctm())) { SkPath path; paint.getTextPath(text, byteLen, x, y, &path); - this->drawPath(d, path, paint, nullptr, true); + this->drawPath(path, paint, nullptr, true); //TODO: add automation "text" return; } @@ -2170,8 +2132,7 @@ void SkXPSDevice::drawText(const SkDraw& d, xpsGlyphs[0].horizontalOffset = 0.0f; xpsGlyphs[0].verticalOffset = 0.0f; - HRV(AddGlyphs(d, - this->fXpsFactory.get(), + HRV(AddGlyphs(this->fXpsFactory.get(), this->fCurrentXpsCanvas.get(), typeface, nullptr, @@ -2179,21 +2140,20 @@ void SkXPSDevice::drawText(const SkDraw& d, &origin, SkScalarToFLOAT(paint.getTextSize()), XPS_STYLE_SIMULATION_NONE, - *d.fMatrix, + this->ctm(), paint)); } -void SkXPSDevice::drawPosText(const SkDraw& d, - const void* text, size_t byteLen, +void SkXPSDevice::drawPosText(const void* text, size_t byteLen, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { if (byteLen < 1) return; - if (text_must_be_pathed(paint, *d.fMatrix)) { + if (text_must_be_pathed(paint, this->ctm())) { SkPath path; //TODO: make this work, Draw currently does not handle as well. //paint.getTextPath(text, byteLength, x, y, &path); - //this->drawPath(d, path, paint, nullptr, true); + //this->drawPath(path, paint, nullptr, true); //TODO: add automation "text" return; } @@ -2230,8 +2190,7 @@ void SkXPSDevice::drawPosText(const SkDraw& d, xpsGlyphs[0].horizontalOffset = 0.0f; xpsGlyphs[0].verticalOffset = 0.0f; - HRV(AddGlyphs(d, - this->fXpsFactory.get(), + HRV(AddGlyphs(this->fXpsFactory.get(), this->fCurrentXpsCanvas.get(), typeface, nullptr, @@ -2239,24 +2198,18 @@ void SkXPSDevice::drawPosText(const SkDraw& d, &origin, SkScalarToFLOAT(paint.getTextSize()), XPS_STYLE_SIMULATION_NONE, - *d.fMatrix, + this->ctm(), paint)); } -void SkXPSDevice::drawDevice(const SkDraw& d, SkBaseDevice* dev, +void SkXPSDevice::drawDevice( SkBaseDevice* dev, int x, int y, const SkPaint&) { SkXPSDevice* that = static_cast(dev); SkTScopedComPtr xpsTransform; - XPS_MATRIX rawTransform = { - 1.0f, - 0.0f, - 0.0f, - 1.0f, - static_cast(x), - static_cast(y), - }; + // TODO(halcanary): assert that current transform is identity rather than calling setter. + XPS_MATRIX rawTransform = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}; HRVM(this->fXpsFactory->CreateMatrixTransform(&rawTransform, &xpsTransform), "Could not create layer transform."); HRVM(that->fCurrentXpsCanvas->SetTransformLocal(xpsTransform.get()), @@ -2282,7 +2235,44 @@ SkBaseDevice* SkXPSDevice::onCreateDevice(const CreateInfo& info, const SkPaint* //return dev; } #endif - return new SkXPSDevice(this->fXpsFactory.get()); + SkXPSDevice* dev = new SkXPSDevice(info.fInfo.dimensions()); + // TODO(halcanary) implement copy constructor on SkTScopedCOmPtr + dev->fXpsFactory.reset(SkRefComPtr(fXpsFactory.get())); + SkAssertResult(dev->createCanvasForLayer()); + return dev; } +void SkXPSDevice::drawOval( const SkRect& o, const SkPaint& p) { + SkPath path; + path.addOval(o); + this->drawPath(path, p, nullptr, true); +} + +void SkXPSDevice::drawBitmapRect(const SkBitmap& bitmap, + const SkRect* src, + const SkRect& dst, + const SkPaint& paint, + SkCanvas::SrcRectConstraint constraint) { + SkRect bitmapBounds = SkRect::Make(bitmap.bounds()); + SkRect srcBounds = src ? *src : bitmapBounds; + SkMatrix matrix = SkMatrix::MakeRectToRect(srcBounds, dst, SkMatrix::kFill_ScaleToFit); + SkRect actualDst; + if (!src || bitmapBounds.contains(*src)) { + actualDst = dst; + } else { + if (!srcBounds.intersect(bitmapBounds)) { + return; + } + matrix.mapRect(&actualDst, srcBounds); + } + auto bitmapShader = SkMakeBitmapShader(bitmap, SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode, &matrix, + kNever_SkCopyPixelsMode); + SkASSERT(bitmapShader); + if (!bitmapShader) { return; } + SkPaint paintWithShader(paint); + paintWithShader.setStyle(SkPaint::kFill_Style); + paintWithShader.setShader(std::move(bitmapShader)); + this->drawRect(actualDst, paintWithShader); +} #endif//defined(SK_BUILD_FOR_WIN32) diff --git a/gfx/skia/skia/src/xps/SkXPSDevice.h b/gfx/skia/skia/src/xps/SkXPSDevice.h index 57f314851e5c..a0b425707126 100644 --- a/gfx/skia/skia/src/xps/SkXPSDevice.h +++ b/gfx/skia/skia/src/xps/SkXPSDevice.h @@ -16,9 +16,10 @@ #include #include "SkAutoCoInitialize.h" -#include "SkBitmapDevice.h" #include "SkBitSet.h" +#include "SkBitmapDevice.h" #include "SkCanvas.h" +#include "SkClipStackDevice.h" #include "SkColor.h" #include "SkPaint.h" #include "SkPath.h" @@ -35,12 +36,12 @@ The drawing context for the XPS backend. */ -class SkXPSDevice : public SkBitmapDevice { +class SkXPSDevice : public SkClipStackDevice { public: - SK_API SkXPSDevice(); + SK_API SkXPSDevice(SkISize); SK_API virtual ~SkXPSDevice(); - virtual bool beginPortfolio(SkWStream* outputStream); + bool beginPortfolio(SkWStream* outputStream, IXpsOMObjectFactory*); /** @param unitsPerMeter converts geometry units into physical units. @param pixelsPerMeter resolution to use when geometry must be rasterized. @@ -60,7 +61,7 @@ public: Must be contained within the mediaBox. The default is to coincide with the mediaBox. */ - virtual bool beginSheet( + bool beginSheet( const SkVector& unitsPerMeter, const SkVector& pixelsPerMeter, const SkSize& trimSize, @@ -69,73 +70,39 @@ public: const SkRect* artBox = NULL, const SkRect* cropBox = NULL); - virtual bool endSheet(); - virtual bool endPortfolio(); + bool endSheet(); + bool endPortfolio(); protected: - void drawPaint(const SkDraw&, const SkPaint& paint) override; - - virtual void drawPoints( - const SkDraw&, - SkCanvas::PointMode mode, - size_t count, const SkPoint[], - const SkPaint& paint) override; - - virtual void drawRect( - const SkDraw&, - const SkRect& r, - const SkPaint& paint) override; - - virtual void drawRRect( - const SkDraw&, - const SkRRect&, - const SkPaint& paint) override; - - virtual void drawPath( - const SkDraw&, - const SkPath& platonicPath, - const SkPaint& paint, - const SkMatrix* prePathMatrix, - bool pathIsMutable) override; - - virtual void drawBitmap( - const SkDraw&, - const SkBitmap& bitmap, - const SkMatrix& matrix, - const SkPaint& paint) override; - - virtual void drawSprite( - const SkDraw&, - const SkBitmap& bitmap, - int x, int y, - const SkPaint& paint) override; - - virtual void drawText( - const SkDraw&, - const void* text, size_t len, - SkScalar x, SkScalar y, - const SkPaint& paint) override; - - virtual void drawPosText( - const SkDraw&, - const void* text, size_t len, - const SkScalar pos[], int scalarsPerPos, - const SkPoint& offset, const SkPaint& paint) override; - - virtual void drawVertices( - const SkDraw&, - SkCanvas::VertexMode, - int vertexCount, const SkPoint verts[], - const SkPoint texs[], const SkColor colors[], - SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) override; - - virtual void drawDevice( - const SkDraw&, - SkBaseDevice* device, - int x, int y, - const SkPaint& paint) override; + void drawPaint(const SkPaint& paint) override; + void drawPoints(SkCanvas::PointMode mode, size_t count, + const SkPoint[], const SkPaint& paint) override; + void drawRect(const SkRect& r, + const SkPaint& paint) override; + void drawOval(const SkRect& oval, + const SkPaint& paint) override; + void drawRRect(const SkRRect& rr, + const SkPaint& paint) override; + void drawPath(const SkPath& path, + const SkPaint& paint, + const SkMatrix* prePathMatrix = NULL, + bool pathIsMutable = false) override; + void drawBitmap(const SkBitmap& bitmap, + const SkMatrix& matrix, const SkPaint& paint) override; + void drawSprite(const SkBitmap& bitmap, + int x, int y, const SkPaint& paint) override; + void drawBitmapRect(const SkBitmap&, + const SkRect* srcOrNull, const SkRect& dst, + const SkPaint& paint, + SkCanvas::SrcRectConstraint) override; + void drawText(const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint& paint) override; + void drawPosText(const void* text, size_t len, + const SkScalar pos[], int scalarsPerPos, + const SkPoint& offset, const SkPaint& paint) override; + void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override; + void drawDevice(SkBaseDevice*, int x, int y, + const SkPaint&) override; private: class TypefaceUse : ::SkNoncopyable { @@ -149,11 +116,10 @@ private: explicit TypefaceUse(); ~TypefaceUse(); }; - friend static HRESULT subset_typeface(TypefaceUse* current); + friend HRESULT subset_typeface(TypefaceUse* current); - SkXPSDevice(IXpsOMObjectFactory* xpsFactory); + bool createCanvasForLayer(); - SkAutoCoInitialize fAutoCo; SkTScopedComPtr fXpsFactory; SkTScopedComPtr fOutputStream; SkTScopedComPtr fPackageWriter; @@ -189,7 +155,6 @@ private: IXpsOMImageResource** image); void internalDrawRect( - const SkDraw&, const SkRect& r, bool transformRect, const SkPaint& paint); @@ -248,7 +213,6 @@ private: TypefaceUse** fontResource); HRESULT AddGlyphs( - const SkDraw& d, IXpsOMObjectFactory* xpsFactory, IXpsOMCanvas* canvas, TypefaceUse* font, @@ -280,16 +244,14 @@ private: const SkColor color, IXpsOMVisualCollection* visuals); - HRESULT clip( - IXpsOMVisual* xpsVisual, - const SkDraw& d); + HRESULT clip(IXpsOMVisual* xpsVisual); + HRESULT clipToPath( IXpsOMVisual* xpsVisual, const SkPath& clipPath, XPS_FILL_RULE fillRule); HRESULT drawInverseWindingPath( - const SkDraw& d, const SkPath& devicePath, IXpsOMPath* xpsPath); @@ -306,7 +268,6 @@ private: const SkIRect& clip, SkIRect* clipIRect); HRESULT applyMask( - const SkDraw& d, const SkMask& mask, const SkVector& ppuScale, IXpsOMPath* shadedPath); @@ -317,7 +278,7 @@ private: SkXPSDevice(const SkXPSDevice&); void operator=(const SkXPSDevice&); - typedef SkBitmapDevice INHERITED; + typedef SkClipStackDevice INHERITED; }; #endif // SK_BUILD_FOR_WIN diff --git a/gfx/skia/skia/src/xps/SkXPSDocument.cpp b/gfx/skia/skia/src/xps/SkXPSDocument.cpp new file mode 100644 index 000000000000..0d12e4f7f84e --- /dev/null +++ b/gfx/skia/skia/src/xps/SkXPSDocument.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#include "SkTypes.h" +#if defined(SK_BUILD_FOR_WIN32) + +#include "SkXPSDocument.h" +#include "SkStream.h" +#include "SkHRESULT.h" + +SkXPSDocument::SkXPSDocument(SkWStream* stream, + SkScalar dpi, + SkTScopedComPtr xpsFactory) + : SkDocument(stream, nullptr) + , fXpsFactory(std::move(xpsFactory)) + , fDevice(SkISize{10000, 10000}) +{ + const SkScalar kPointsPerMeter = SkDoubleToScalar(360000.0 / 127.0); + fUnitsPerMeter.set(kPointsPerMeter, kPointsPerMeter); + SkScalar pixelsPerMeterScale = SkDoubleToScalar(dpi * 5000.0 / 127.0); + fPixelsPerMeter.set(pixelsPerMeterScale, pixelsPerMeterScale); + SkASSERT(fXpsFactory); + fDevice.beginPortfolio(stream, fXpsFactory.get()); +} + +SkXPSDocument::~SkXPSDocument() { + // subclasses must call close() in their destructors + this->close(); +} + +SkCanvas* SkXPSDocument::onBeginPage(SkScalar width, + SkScalar height, + const SkRect& trimBox) { + fDevice.beginSheet(fUnitsPerMeter, fPixelsPerMeter, {width, height}); + fCanvas.reset(new SkCanvas(&fDevice)); + fCanvas->clipRect(trimBox); + fCanvas->translate(trimBox.x(), trimBox.y()); + return fCanvas.get(); +} + +void SkXPSDocument::onEndPage() { + SkASSERT(fCanvas.get()); + fCanvas->flush(); + fCanvas.reset(nullptr); + fDevice.endSheet(); +} + +void SkXPSDocument::onClose(SkWStream*) { + SkASSERT(!fCanvas.get()); + (void)fDevice.endPortfolio(); +} + +void SkXPSDocument::onAbort() {} + +/////////////////////////////////////////////////////////////////////////////// + +sk_sp SkDocument::MakeXPS(SkWStream* stream, + IXpsOMObjectFactory* factoryPtr, + SkScalar dpi) { + SkTScopedComPtr factory(SkSafeRefComPtr(factoryPtr)); + return stream && factory + ? sk_make_sp(stream, dpi, std::move(factory)) + : nullptr; +} + +#endif//defined(SK_BUILD_FOR_WIN32) diff --git a/gfx/skia/skia/src/xps/SkXPSDocument.h b/gfx/skia/skia/src/xps/SkXPSDocument.h new file mode 100644 index 000000000000..726af8f58f64 --- /dev/null +++ b/gfx/skia/skia/src/xps/SkXPSDocument.h @@ -0,0 +1,41 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkXPSDocument_DEFINED +#define SkXPSDocument_DEFINED + +#include "SkTypes.h" + +#ifdef SK_BUILD_FOR_WIN + +#include "SkDocument.h" +#include "SkXPSDevice.h" +#include "SkTScopedComPtr.h" + +#include + +class SkXPSDocument final : public SkDocument { +public: + SkXPSDocument(SkWStream*, SkScalar dpi, SkTScopedComPtr); + virtual ~SkXPSDocument(); + +protected: + SkCanvas* onBeginPage(SkScalar w, SkScalar h, const SkRect&) override; + void onEndPage() override; + void onClose(SkWStream*) override; + void onAbort() override; + +private: + SkTScopedComPtr fXpsFactory; + SkXPSDevice fDevice; + std::unique_ptr fCanvas; + SkVector fUnitsPerMeter; + SkVector fPixelsPerMeter; +}; + +#endif // SK_BUILD_FOR_WIN +#endif // SkXPSDocument_DEFINED diff --git a/gfx/thebes/PrintTargetSkPDF.cpp b/gfx/thebes/PrintTargetSkPDF.cpp index 5e68c4f64b16..64c7b3c55684 100644 --- a/gfx/thebes/PrintTargetSkPDF.cpp +++ b/gfx/thebes/PrintTargetSkPDF.cpp @@ -67,7 +67,7 @@ PrintTargetSkPDF::BeginPrinting(const nsAString& aTitle, nsresult PrintTargetSkPDF::BeginPage() { - mPageCanvas = sk_ref_sp(mPDFDoc->beginPage(mSize.width, mSize.height)); + mPageCanvas = mPDFDoc->beginPage(mSize.width, mSize.height); return !mPageCanvas ? NS_ERROR_FAILURE : PrintTarget::BeginPage(); } @@ -113,7 +113,7 @@ PrintTargetSkPDF::MakeDrawTarget(const IntSize& aSize, if (!mPageCanvas) { return nullptr; } - mPageDT = Factory::CreateDrawTargetWithSkCanvas(mPageCanvas.get()); + mPageDT = Factory::CreateDrawTargetWithSkCanvas(mPageCanvas); if (!mPageDT) { mPageCanvas = nullptr; return nullptr; @@ -133,12 +133,12 @@ PrintTargetSkPDF::GetReferenceDrawTarget(DrawEventRecorder* aRecorder) if (!mRefPDFDoc) { return nullptr; } - mRefCanvas = sk_ref_sp(mRefPDFDoc->beginPage(mSize.width, mSize.height)); + mRefCanvas = mRefPDFDoc->beginPage(mSize.width, mSize.height); if (!mRefCanvas) { return nullptr; } RefPtr dt = - Factory::CreateDrawTargetWithSkCanvas(mRefCanvas.get()); + Factory::CreateDrawTargetWithSkCanvas(mRefCanvas); if (!dt) { return nullptr; } diff --git a/gfx/thebes/PrintTargetSkPDF.h b/gfx/thebes/PrintTargetSkPDF.h index 3a742b992d3c..fe5f28b31202 100644 --- a/gfx/thebes/PrintTargetSkPDF.h +++ b/gfx/thebes/PrintTargetSkPDF.h @@ -59,12 +59,14 @@ private: UniquePtr mOStream; // The current page's SkCanvas and its wrapping DrawTarget: - sk_sp mPageCanvas; + // Canvas is owned by mPDFDoc, which handles its deletion. + SkCanvas* mPageCanvas; RefPtr mPageDT; // Members needed to provide a reference DrawTarget: sk_sp mRefPDFDoc; - sk_sp mRefCanvas; + // Canvas owned by mRefPDFDoc, which handles its deletion. + SkCanvas* mRefCanvas; SkDynamicMemoryWStream mRefOStream; }; diff --git a/gfx/thebes/gfxBlur.cpp b/gfx/thebes/gfxBlur.cpp index 9e278f86636b..10e49a851b44 100644 --- a/gfx/thebes/gfxBlur.cpp +++ b/gfx/thebes/gfxBlur.cpp @@ -557,8 +557,14 @@ GetBlur(gfxContext* aDestinationCtx, // We can get seams using the min size rect when drawing to the destination rect // if we have a non-pixel aligned destination transformation. In those cases, // fallback to just rendering the destination rect. + // During printing, we record all the Moz 2d commands and replay them on the parent side + // with Cairo. Cairo printing uses StretchDIBits to stretch the surface. However, + // since our source image is only 1px for some parts, we make thousands of calls. + // Instead just render the blur ourself here as one image and send it over for printing. + // TODO: May need to change this with the blob renderer in WR since it also records. Matrix destMatrix = ToMatrix(aDestinationCtx->CurrentMatrix()); - bool useDestRect = !destMatrix.IsRectilinear() || destMatrix.HasNonIntegerTranslation(); + bool useDestRect = !destMatrix.IsRectilinear() || destMatrix.HasNonIntegerTranslation() || + aDestinationCtx->GetDrawTarget()->IsRecording(); if (useDestRect) { minSize = aRectSize; } diff --git a/js/src/gc/Barrier.cpp b/js/src/gc/Barrier.cpp index 38a1ffa97345..e35dcbe7067d 100644 --- a/js/src/gc/Barrier.cpp +++ b/js/src/gc/Barrier.cpp @@ -47,19 +47,26 @@ IsMarkedBlack(JSObject* obj) bool HeapSlot::preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot) const { - return kind == Slot - ? &owner->getSlotRef(slot) == this - : &owner->getDenseElement(slot) == (const Value*)this; + if (kind == Slot) + return &owner->getSlotRef(slot) == this; + + uint32_t numShifted = owner->getElementsHeader()->numShiftedElements(); + MOZ_ASSERT(slot >= numShifted); + return &owner->getDenseElement(slot - numShifted) == (const Value*)this; } void HeapSlot::assertPreconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t slot, const Value& target) const { - if (kind == Slot) + if (kind == Slot) { MOZ_ASSERT(obj->getSlotAddressUnchecked(slot)->get() == target); - else - MOZ_ASSERT(static_cast(obj->getDenseElements() + slot)->get() == target); + } else { + uint32_t numShifted = obj->getElementsHeader()->numShiftedElements(); + MOZ_ASSERT(slot >= numShifted); + MOZ_ASSERT(static_cast(obj->getDenseElements() + (slot - numShifted))->get() == + target); + } CheckEdgeIsNotBlackToGray(obj, target); } diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index feb3310b93a7..d28ffb86d25e 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1823,7 +1823,10 @@ GCMarker::saveValueRanges() HeapSlot* vp = obj->getDenseElementsAllowCopyOnWrite(); if (array.end == vp + obj->getDenseInitializedLength()) { MOZ_ASSERT(array.start >= vp); - index = array.start - vp; + // Add the number of shifted elements here (and subtract in + // restoreValueArray) to ensure shift() calls on the array + // are handled correctly. + index = obj->unshiftedIndex(array.start - vp); kind = HeapSlot::Element; } else { HeapSlot* vp = obj->fixedSlots(); @@ -1865,6 +1868,11 @@ GCMarker::restoreValueArray(const MarkStack::SavedValueArray& array, return false; uint32_t initlen = obj->getDenseInitializedLength(); + + // Account for shifted elements. + uint32_t numShifted = obj->getElementsHeader()->numShiftedElements(); + start = (numShifted < start) ? start - numShifted : 0; + HeapSlot* vp = obj->getDenseElementsAllowCopyOnWrite(); if (start < initlen) { *vpp = vp + start; @@ -2689,8 +2697,11 @@ js::gc::StoreBuffer::SlotsEdge::trace(TenuringTracer& mover) const if (kind() == ElementKind) { int32_t initLen = obj->getDenseInitializedLength(); - int32_t clampedStart = Min(start_, initLen); - int32_t clampedEnd = Min(start_ + count_, initLen); + int32_t numShifted = obj->getElementsHeader()->numShiftedElements(); + int32_t clampedStart = Min(Max(0, start_ - numShifted), initLen); + int32_t clampedEnd = Min(Max(0, start_ + count_ - numShifted), initLen); + MOZ_ASSERT(clampedStart >= 0); + MOZ_ASSERT(clampedStart <= clampedEnd); mover.traceSlots(static_cast(obj->getDenseElements() + clampedStart) ->unsafeUnbarrieredForTracing(), clampedEnd - clampedStart); } else { @@ -3014,30 +3025,35 @@ js::TenuringTracer::moveElementsToTenured(NativeObject* dst, NativeObject* src, if (src->hasEmptyElements() || src->denseElementsAreCopyOnWrite()) return 0; - Zone* zone = src->zone(); - ObjectElements* srcHeader = src->getElementsHeader(); - ObjectElements* dstHeader; + void* srcAllocatedHeader = src->getUnshiftedElementsHeader(); /* TODO Bug 874151: Prefer to put element data inline if we have space. */ - if (!nursery().isInside(srcHeader)) { + if (!nursery().isInside(srcAllocatedHeader)) { MOZ_ASSERT(src->elements_ == dst->elements_); - nursery().removeMallocedBuffer(srcHeader); + nursery().removeMallocedBuffer(srcAllocatedHeader); return 0; } - size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->capacity; + ObjectElements* srcHeader = src->getElementsHeader(); + + // Shifted elements are copied too. + uint32_t numShifted = srcHeader->numShiftedElements(); + size_t nslots = srcHeader->numAllocatedElements(); /* Unlike other objects, Arrays can have fixed elements. */ if (src->is() && nslots <= GetGCKindSlots(dstKind)) { dst->as().setFixedElements(); - dstHeader = dst->as().getElementsHeader(); - js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); - nursery().setElementsForwardingPointer(srcHeader, dstHeader, nslots); + js_memcpy(dst->getElementsHeader(), srcAllocatedHeader, nslots * sizeof(HeapSlot)); + dst->elements_ += numShifted; + nursery().setElementsForwardingPointer(srcHeader, dst->getElementsHeader(), + srcHeader->capacity); return nslots * sizeof(HeapSlot); } MOZ_ASSERT(nslots >= 2); + Zone* zone = src->zone(); + ObjectElements* dstHeader; { AutoEnterOOMUnsafeRegion oomUnsafe; dstHeader = reinterpret_cast(zone->pod_malloc(nslots)); @@ -3047,9 +3063,10 @@ js::TenuringTracer::moveElementsToTenured(NativeObject* dst, NativeObject* src, } } - js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); - nursery().setElementsForwardingPointer(srcHeader, dstHeader, nslots); - dst->elements_ = dstHeader->elements(); + js_memcpy(dstHeader, srcAllocatedHeader, nslots * sizeof(HeapSlot)); + dst->elements_ = dstHeader->elements() + numShifted; + nursery().setElementsForwardingPointer(srcHeader, dst->getElementsHeader(), + srcHeader->capacity); return nslots * sizeof(HeapSlot); } diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index b1c02c9751be..9d183d0da0fe 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -440,11 +440,11 @@ Nursery::setSlotsForwardingPointer(HeapSlot* oldSlots, HeapSlot* newSlots, uint3 void Nursery::setElementsForwardingPointer(ObjectElements* oldHeader, ObjectElements* newHeader, - uint32_t nelems) + uint32_t capacity) { // Only use a direct forwarding pointer if there is enough space for one. setForwardingPointer(oldHeader->elements(), newHeader->elements(), - nelems > ObjectElements::VALUES_PER_HEADER); + capacity > 0); } #ifdef DEBUG diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 6b7026755ed3..ed611571fa97 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -459,7 +459,7 @@ class Nursery void setSlotsForwardingPointer(HeapSlot* oldSlots, HeapSlot* newSlots, uint32_t nslots); void setElementsForwardingPointer(ObjectElements* oldHeader, ObjectElements* newHeader, - uint32_t nelems); + uint32_t capacity); /* Free malloced pointers owned by freed things in the nursery. */ void freeMallocedBuffers(); diff --git a/js/src/gdb/mozilla/IonGraph.py b/js/src/gdb/mozilla/IonGraph.py index 8a2ce2828fa5..938d9b80ec3d 100644 --- a/js/src/gdb/mozilla/IonGraph.py +++ b/js/src/gdb/mozilla/IonGraph.py @@ -178,7 +178,7 @@ class IonGraphCommand(gdb.Command): d = subprocess.Popen([dot.value, '-Tpng'], stdin = i.stdout, stdout = png) # Write the json file as the input of the iongraph command. - i.stdin.write(bytes(jsonStr, 'utf8')) + i.stdin.write(jsonStr.encode('utf8')) i.stdin.close() i.stdout.close() diff --git a/js/src/jit-test/tests/basic/shifted-elements1.js b/js/src/jit-test/tests/basic/shifted-elements1.js new file mode 100644 index 000000000000..ee001c5e3555 --- /dev/null +++ b/js/src/jit-test/tests/basic/shifted-elements1.js @@ -0,0 +1,14 @@ +function f() { + var arr = []; + var iters = 1500; + for (var i = 0; i < iters; i++) { + arr.push(i); + if (i % 2 === 0) + assertEq(arr.shift(), i / 2); + } + assertEq(arr.length, iters / 2); + for (var i = iters / 2; i < iters; i++) + assertEq(arr.shift(), i); + assertEq(arr.length, 0); +} +f(); diff --git a/js/src/jit-test/tests/basic/shifted-elements2.js b/js/src/jit-test/tests/basic/shifted-elements2.js new file mode 100644 index 000000000000..f989db1542ff --- /dev/null +++ b/js/src/jit-test/tests/basic/shifted-elements2.js @@ -0,0 +1,22 @@ +// Always use the per-element barrier. +gczeal(12); + +function f() { + var arr = []; + for (var i = 0; i < 1000; i++) + arr.push(i); + gc(); // Ensure arr is tenured. + + // Now store a nursery object somewhere in the array, shift elements, + // trigger a GC, and check the post barrier kept the object alive. + for (var i = 0; i < 20; i++) + arr.shift(); + for (var i = 0; i < 40; i++) + arr[900] = {x: i}; + for (var i = 0; i < 10; i++) + arr.shift(); + gc(); + + assertEq(arr[890].x, 39); +} +f(); diff --git a/js/src/jit-test/tests/basic/shifted-elements3.js b/js/src/jit-test/tests/basic/shifted-elements3.js new file mode 100644 index 000000000000..6bbe296faa0d --- /dev/null +++ b/js/src/jit-test/tests/basic/shifted-elements3.js @@ -0,0 +1,23 @@ +// Always use the per-element barrier. +gczeal(12); + +function f() { + var arr = []; + for (var i = 0; i < 1000; i++) + arr.push(i); + gc(); // Ensure arr is tenured. + + for (var i = 0; i < 10; i++) + arr.shift(); + + // Add a nursery object, shift all elements, and trigger a GC to ensure + // the post barrier doesn't misbehave. + for (var j = 0; j < 40; j++) + arr[500] = {x: j}; + while (arr.length > 0) + arr.shift(); + + gc(); + return arr; +} +f(); diff --git a/js/src/jit-test/tests/basic/shifted-elements4.js b/js/src/jit-test/tests/basic/shifted-elements4.js new file mode 100644 index 000000000000..59bd83608732 --- /dev/null +++ b/js/src/jit-test/tests/basic/shifted-elements4.js @@ -0,0 +1,11 @@ +function f() { + var arr = []; + for (var i = 0; i < 2; i++) { + for (var j = 0; j < 90000; j++) + arr.push(j); + for (var j = 0; j < 90000; j++) + assertEq(arr.shift(), j); + assertEq(arr.length, 0); + } +} +f(); diff --git a/js/src/jit-test/tests/basic/shifted-elements5.js b/js/src/jit-test/tests/basic/shifted-elements5.js new file mode 100644 index 000000000000..07e0bce5b52b --- /dev/null +++ b/js/src/jit-test/tests/basic/shifted-elements5.js @@ -0,0 +1,39 @@ +function testFreeze() { + var arr = []; + for (var i = 0; i < 20; i++) + arr.push(i); + for (var i = 0; i < 10; i++) + arr.shift(); + Object.freeze(arr); + assertEq(arr.length, 10); + arr[0] = -1; + assertEq(arr[0], 10); +} +testFreeze(); +testFreeze(); + +function testCopyOnWrite() { + var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + for (var i = 0; i < 5; i++) + assertEq(arr.shift(), i + 1); + assertEq(arr.toString(), "6,7,8,9"); +} +testCopyOnWrite(); +testCopyOnWrite(); + +function testNonWritableLength() { + var arr = []; + for (var i = 0; i < 20; i++) + arr.push(i); + Object.defineProperty(arr, "length", {writable: false, value: arr.length}); + var ex; + try { + arr.shift(); + } catch(e) { + ex = e; + } + assertEq(ex instanceof TypeError, true); + assertEq(arr.length, 20); +} +testNonWritableLength(); +testNonWritableLength(); diff --git a/js/src/jit-test/tests/basic/shifted-elements6.js b/js/src/jit-test/tests/basic/shifted-elements6.js new file mode 100644 index 000000000000..671e493254fe --- /dev/null +++ b/js/src/jit-test/tests/basic/shifted-elements6.js @@ -0,0 +1,17 @@ +// Test incremental GC slices and shifted elements. +function f() { + var arr = []; + for (var i = 0; i < 1000; i++) + arr.push({x: i}); + var arr2 = []; + for (var i = 0; i < 1000; i++) { + gcslice(900); + var o = arr.shift(); + assertEq(o.x, i); + arr2.push(o); + } + gc(); + for (var i = 0; i < 1000; i++) + assertEq(arr2[i].x, i); +} +f(); diff --git a/js/src/jit-test/tests/ion/dce-with-rinstructions.js b/js/src/jit-test/tests/ion/dce-with-rinstructions.js index a951c93986f4..8d34dcc88262 100644 --- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js +++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js @@ -1343,6 +1343,7 @@ function rlog_object(i) { } for (j = 100 - max; j < 100; j++) { + with({}){} // Do not Ion-compile this loop. let i = j < 2 ? (Math.abs(j) % 50) + 2 : j; rbitnot_number(i); rbitnot_object(i); diff --git a/js/src/jit-test/tests/promise/stopdrainingjobqueue.js b/js/src/jit-test/tests/promise/stopdrainingjobqueue.js new file mode 100644 index 000000000000..534cc0303981 --- /dev/null +++ b/js/src/jit-test/tests/promise/stopdrainingjobqueue.js @@ -0,0 +1,4 @@ +Promise.resolve() + .then(()=>quit(0)); +Promise.resolve() + .then(()=>crash("Must not run any more promise jobs after quitting")); \ No newline at end of file diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 489b7c2664cd..18145e737aea 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8954,7 +8954,26 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags()); Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH); masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry()); + } + if (mir->mode() == MArrayPopShift::Shift) { + // Don't save the elementsTemp register. + LiveRegisterSet temps; + temps.add(elementsTemp); + + saveVolatile(temps); + masm.setupUnalignedABICall(elementsTemp); + masm.passABIArg(obj); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::ArrayShiftMoveElements)); + restoreVolatile(temps); + + if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { + // Reload elementsTemp as ArrayShiftMoveElements may have moved it. + masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp); + } + } + + if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { // Now adjust length and initializedLength. masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength())); masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength())); @@ -8965,19 +8984,6 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R masm.add32(Imm32(-1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); } - if (mir->mode() == MArrayPopShift::Shift) { - // Don't save the temp registers. - LiveRegisterSet temps; - temps.add(elementsTemp); - temps.add(lengthTemp); - - saveVolatile(temps); - masm.setupUnalignedABICall(lengthTemp); - masm.passABIArg(obj); - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::ArrayShiftMoveElements)); - restoreVolatile(temps); - } - masm.bind(&done); masm.bind(ool->rejoin()); } diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 610fea957a28..028b71428799 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -705,7 +705,9 @@ PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index) #endif ) { - rt->gc.storeBuffer().putSlot(nobj, HeapSlot::Element, index, 1); + rt->gc.storeBuffer().putSlot(nobj, HeapSlot::Element, + nobj->unshiftedIndex(index), + 1); return; } diff --git a/js/src/jsapi-tests/testPromise.cpp b/js/src/jsapi-tests/testPromise.cpp index 45b9eb12da31..f350512b7afc 100644 --- a/js/src/jsapi-tests/testPromise.cpp +++ b/js/src/jsapi-tests/testPromise.cpp @@ -89,3 +89,81 @@ BEGIN_TEST(testPromise_RejectPromise) return true; } END_TEST(testPromise_RejectPromise) + +static bool thenHandler_called = false; + +static bool +PromiseThenHandler(JSContext* cx, unsigned argc, Value* vp) +{ +#ifdef DEBUG + CallArgs args = CallArgsFromVp(argc, vp); +#endif // DEBUG + MOZ_ASSERT(args.length() == 1); + + thenHandler_called = true; + return true; +} + +static bool catchHandler_called = false; + +static bool +PromiseCatchHandler(JSContext* cx, unsigned argc, Value* vp) +{ +#ifdef DEBUG + CallArgs args = CallArgsFromVp(argc, vp); +#endif // DEBUG + MOZ_ASSERT(args.length() == 1); + + catchHandler_called = true; + return true; +} + +BEGIN_TEST(testPromise_PromiseThen) +{ + RootedObject promise(cx, CreatePromise(cx)); + if (!promise) + return false; + + RootedFunction thenHandler(cx, JS_NewFunction(cx, PromiseThenHandler, 1, 0, "thenHandler")); + if (!thenHandler) + return false; + RootedFunction catchHandler(cx, JS_NewFunction(cx, PromiseCatchHandler, 1, 0, "catchHandler")); + if (!catchHandler) + return false; + JS::AddPromiseReactions(cx, promise, thenHandler, catchHandler); + + RootedValue result(cx); + result.setInt32(42); + JS::ResolvePromise(cx, promise, result); + js::RunJobs(cx); + + CHECK(thenHandler_called); + + return true; +} +END_TEST(testPromise_PromiseThen) + +BEGIN_TEST(testPromise_PromiseCatch) +{ + RootedObject promise(cx, CreatePromise(cx)); + if (!promise) + return false; + + RootedFunction thenHandler(cx, JS_NewFunction(cx, PromiseThenHandler, 1, 0, "thenHandler")); + if (!thenHandler) + return false; + RootedFunction catchHandler(cx, JS_NewFunction(cx, PromiseCatchHandler, 1, 0, "catchHandler")); + if (!catchHandler) + return false; + JS::AddPromiseReactions(cx, promise, thenHandler, catchHandler); + + RootedValue result(cx); + result.setInt32(42); + JS::RejectPromise(cx, promise, result); + js::RunJobs(cx); + + CHECK(catchHandler_called); + + return true; +} +END_TEST(testPromise_PromiseCatch) diff --git a/js/src/jsapi-tests/tests.cpp b/js/src/jsapi-tests/tests.cpp index 441a8ed1f0cb..6b636ace8dfa 100644 --- a/js/src/jsapi-tests/tests.cpp +++ b/js/src/jsapi-tests/tests.cpp @@ -18,6 +18,7 @@ bool JSAPITest::init() cx = createContext(); if (!cx) return false; + js::UseInternalJobQueues(cx); if (!JS::InitSelfHostedCode(cx)) return false; JS_BeginRequest(cx); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index b9c54c45970e..8136b9caa167 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -791,6 +791,11 @@ js::ArraySetLength(JSContext* cx, Handle arr, HandleId id, header->initializedLength = Min(header->initializedLength, newLen); if (attrs & JSPROP_READONLY) { + if (header->numShiftedElements() > 0) { + arr->unshiftElements(); + header = arr->getElementsHeader(); + } + header->setNonwritableArrayLength(); // When an array's length becomes non-writable, writes to indexes @@ -2229,18 +2234,16 @@ ShiftMoveBoxedOrUnboxedDenseElements(JSObject* obj) { MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj)); - /* - * At this point the length and initialized length have already been - * decremented and the result fetched, so just shift the array elements - * themselves. - */ size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); + MOZ_ASSERT(initlen > 0); + if (Type == JSVAL_TYPE_MAGIC) { - obj->as().moveDenseElementsNoPreBarrier(0, 1, initlen); + if (!obj->as().tryShiftDenseElements(1)) + obj->as().moveDenseElementsNoPreBarrier(0, 1, initlen - 1); } else { uint8_t* data = obj->as().elements(); size_t elementSize = UnboxedTypeSize(Type); - memmove(data, data + elementSize, initlen * elementSize); + memmove(data, data + elementSize, (initlen - 1) * elementSize); } return DenseElementResult::Success; @@ -2275,6 +2278,11 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) if (rval.isMagic(JS_ELEMENTS_HOLE)) rval.setUndefined(); + if (Type == JSVAL_TYPE_MAGIC) { + if (obj->as().tryShiftDenseElements(1)) + return DenseElementResult::Success; + } + DenseElementResult result = MoveBoxedOrUnboxedDenseElements(cx, obj, 0, 1, initlen - 1); if (result != DenseElementResult::Success) return result; diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 90c6235644ca..affb7b5e9307 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -208,6 +208,20 @@ js::ResumeCooperativeContext(JSContext* cx) cx->runtime()->setActiveContext(cx); } +static void +FreeJobQueueHandling(JSContext* cx) +{ + if (!cx->jobQueue) + return; + + cx->jobQueue->reset(); + FreeOp* fop = cx->defaultFreeOp(); + fop->delete_(cx->jobQueue.ref()); + cx->getIncumbentGlobalCallback = nullptr; + cx->enqueuePromiseJobCallback = nullptr; + cx->enqueuePromiseJobCallbackData = nullptr; +} + void js::DestroyContext(JSContext* cx) { @@ -224,6 +238,8 @@ js::DestroyContext(JSContext* cx) // zone group. See HelperThread::handleIonWorkload. CancelOffThreadIonCompile(cx->runtime()); + FreeJobQueueHandling(cx); + if (cx->runtime()->cooperatingContexts().length() == 1) { // Destroy the runtime along with its last context. cx->runtime()->destroyRuntime(); @@ -1094,6 +1110,184 @@ JSContext::recoverFromOutOfMemory() } } +static bool +InternalEnqueuePromiseJobCallback(JSContext* cx, JS::HandleObject job, + JS::HandleObject allocationSite, + JS::HandleObject incumbentGlobal, void* data) +{ + MOZ_ASSERT(job); + return cx->jobQueue->append(job); +} + +static bool +InternalStartAsyncTaskCallback(JSContext* cx, JS::AsyncTask* task) +{ + task->user = cx; + + ExclusiveData::Guard asyncTasks = cx->asyncTasks.lock(); + asyncTasks->outstanding++; + return true; +} + +static bool +InternalFinishAsyncTaskCallback(JS::AsyncTask* task) +{ + JSContext* cx = (JSContext*)task->user; + + ExclusiveData::Guard asyncTasks = cx->asyncTasks.lock(); + MOZ_ASSERT(asyncTasks->outstanding > 0); + asyncTasks->outstanding--; + return asyncTasks->finished.append(task); +} + +namespace { +class MOZ_STACK_CLASS ReportExceptionClosure : public ScriptEnvironmentPreparer::Closure +{ + public: + explicit ReportExceptionClosure(HandleValue exn) + : exn_(exn) + { + } + + bool operator()(JSContext* cx) override + { + cx->setPendingException(exn_); + return false; + } + + private: + HandleValue exn_; +}; +} // anonymous namespace + +JS_FRIEND_API(bool) +js::UseInternalJobQueues(JSContext* cx) +{ + // Internal job queue handling must be set up very early. Self-hosting + // initialization is as good a marker for that as any. + MOZ_RELEASE_ASSERT(!cx->runtime()->hasInitializedSelfHosting(), + "js::UseInternalJobQueues must be called early during runtime startup."); + MOZ_ASSERT(!cx->jobQueue); + auto* queue = cx->new_>(cx, JobQueue(SystemAllocPolicy())); + if (!queue) + return false; + + cx->jobQueue = queue; + + JS::SetEnqueuePromiseJobCallback(cx, InternalEnqueuePromiseJobCallback); + JS::SetAsyncTaskCallbacks(cx, InternalStartAsyncTaskCallback, InternalFinishAsyncTaskCallback); + + return true; +} + +JS_FRIEND_API(void) +js::StopDrainingJobQueue(JSContext* cx) +{ + MOZ_ASSERT(cx->jobQueue); + cx->stopDrainingJobQueue = true; +} + +JS_FRIEND_API(void) +js::RunJobs(JSContext* cx) +{ + MOZ_ASSERT(cx->jobQueue); + + if (cx->drainingJobQueue || cx->stopDrainingJobQueue) + return; + + while (true) { + // Wait for any outstanding async tasks to finish so that the + // finishedAsyncTasks list is fixed. + while (true) { + AutoLockHelperThreadState lock; + if (!cx->asyncTasks.lock()->outstanding) + break; + HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER); + } + + // Lock the whole time while copying back the asyncTasks finished queue + // so that any new tasks created during finish() cannot racily join the + // job queue. Call finish() only thereafter, to avoid a circular mutex + // dependency (see also bug 1297901). + Vector finished; + { + ExclusiveData::Guard asyncTasks = cx->asyncTasks.lock(); + finished = Move(asyncTasks->finished); + asyncTasks->finished.clear(); + } + + for (JS::AsyncTask* task : finished) + task->finish(cx); + + // It doesn't make sense for job queue draining to be reentrant. At the + // same time we don't want to assert against it, because that'd make + // drainJobQueue unsafe for fuzzers. We do want fuzzers to test this, + // so we simply ignore nested calls of drainJobQueue. + cx->drainingJobQueue = true; + + RootedObject job(cx); + JS::HandleValueArray args(JS::HandleValueArray::empty()); + RootedValue rval(cx); + + // Execute jobs in a loop until we've reached the end of the queue. + // Since executing a job can trigger enqueuing of additional jobs, + // it's crucial to re-check the queue length during each iteration. + for (size_t i = 0; i < cx->jobQueue->length(); i++) { + // A previous job might have set this flag. E.g., the js shell + // sets it if the `quit` builtin function is called. + if (cx->stopDrainingJobQueue) + break; + + job = cx->jobQueue->get()[i]; + + // It's possible that queue draining was interrupted prematurely, + // leaving the queue partly processed. In that case, slots for + // already-executed entries will contain nullptrs, which we should + // just skip. + if (!job) + continue; + + cx->jobQueue->get()[i] = nullptr; + AutoCompartment ac(cx, job); + { + if (!JS::Call(cx, UndefinedHandleValue, job, args, &rval)) { + // Nothing we can do about uncatchable exceptions. + if (!cx->isExceptionPending()) + continue; + RootedValue exn(cx); + if (cx->getPendingException(&exn)) { + /* + * Clear the exception, because + * PrepareScriptEnvironmentAndInvoke will assert that we don't + * have one. + */ + cx->clearPendingException(); + ReportExceptionClosure reportExn(exn); + PrepareScriptEnvironmentAndInvoke(cx, cx->global(), reportExn); + } + } + } + } + + cx->drainingJobQueue = false; + + if (cx->stopDrainingJobQueue) { + cx->stopDrainingJobQueue = false; + break; + } + + cx->jobQueue->clear(); + + // It's possible a job added an async task, and it's also possible + // that task has already finished. + { + ExclusiveData::Guard asyncTasks = cx->asyncTasks.lock(); + if (asyncTasks->outstanding == 0 && asyncTasks->finished.length() == 0) + break; + } + } +} + JS::Error JSContext::reportedError; JS::OOM JSContext::reportedOOM; @@ -1204,6 +1398,10 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options) getIncumbentGlobalCallback(nullptr), enqueuePromiseJobCallback(nullptr), enqueuePromiseJobCallbackData(nullptr), + jobQueue(nullptr), + drainingJobQueue(false), + stopDrainingJobQueue(false), + asyncTasks(mutexid::InternalAsyncTasks), promiseRejectionTrackerCallback(nullptr), promiseRejectionTrackerCallbackData(nullptr) { diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index c7d3159e6c17..29eef845d84e 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -68,6 +68,25 @@ struct AutoResolving; struct HelperThread; +using JobQueue = GCVector; + +class AutoLockForExclusiveAccess; + +/* + * Used for engine-internal handling of async tasks, as currently + * enabled in the js shell and jsapi tests. + */ +struct InternalAsyncTasks +{ + explicit InternalAsyncTasks() + : outstanding(0), + finished() + {} + + size_t outstanding; + Vector finished; +}; + void ReportOverRecursed(JSContext* cx, unsigned errorNumber); /* Thread Local Storage slot for storing the context for a thread. */ @@ -907,6 +926,14 @@ struct JSContext : public JS::RootingContext, js::ThreadLocalData enqueuePromiseJobCallback; js::ThreadLocalData enqueuePromiseJobCallbackData; + // Queue of pending jobs as described in ES2016 section 8.4. + // Only used if internal job queue handling was activated using + // `js::UseInternalJobQueues`. + js::ThreadLocalData*> jobQueue; + js::ThreadLocalData drainingJobQueue; + js::ThreadLocalData stopDrainingJobQueue; + js::ExclusiveData asyncTasks; + js::ThreadLocalData promiseRejectionTrackerCallback; js::ThreadLocalData promiseRejectionTrackerCallbackData; diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 63a8f432dadd..3e9b8ceabf02 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -382,6 +382,33 @@ SetSourceHook(JSContext* cx, mozilla::UniquePtr hook); extern JS_FRIEND_API(mozilla::UniquePtr) ForgetSourceHook(JSContext* cx); +/** + * Use the runtime's internal handling of job queues for Promise jobs. + * + * Most embeddings, notably web browsers, will have their own task scheduling + * systems and need to integrate handling of Promise jobs into that, so they + * will want to manage job queues themselves. For basic embeddings such as the + * JS shell that don't have an event loop of their own, it's easier to have + * SpiderMonkey handle job queues internally. + * + * Note that the embedding still has to trigger processing of job queues at + * right time(s), such as after evaluation of a script has run to completion. + */ +extern JS_FRIEND_API(bool) +UseInternalJobQueues(JSContext* cx); + +/** + * Instruct the runtime to stop draining the internal job queue. + * + * Useful if the embedding is in the process of quitting in reaction to a + * builtin being called, or if it wants to resume executing jobs later on. + */ +extern JS_FRIEND_API(void) +StopDrainingJobQueue(JSContext* cx); + +extern JS_FRIEND_API(void) +RunJobs(JSContext* cx); + extern JS_FRIEND_API(JS::Zone*) GetCompartmentZone(JSCompartment* comp); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 695ffcd34385..5eb6d7544f8e 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1971,8 +1971,10 @@ RelocateCell(Zone* zone, TenuredCell* src, AllocKind thingKind, size_t thingSize NativeObject* dstNative = &dstObj->as(); // Fixup the pointer to inline object elements if necessary. - if (srcNative->hasFixedElements()) - dstNative->setFixedElements(); + if (srcNative->hasFixedElements()) { + uint32_t numShifted = srcNative->getElementsHeader()->numShiftedElements(); + dstNative->setFixedElements(numShifted); + } // For copy-on-write objects that own their elements, fix up the // owner pointer to point to the relocated object. diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 4222cd145ef0..6f4b30199cb0 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -542,6 +542,8 @@ js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level) if (level == IntegrityLevel::Frozen && obj->is()) { if (!obj->as().maybeCopyElementsForWrite(cx)) return false; + if (nobj->getElementsHeader()->numShiftedElements() > 0) + nobj->unshiftElements(); obj->as().getElementsHeader()->setNonwritableArrayLength(); } } else { @@ -3881,8 +3883,10 @@ JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ClassIn if (is() && as().hasDynamicElements()) { js::ObjectElements* elements = as().getElementsHeader(); - if (!elements->isCopyOnWrite() || elements->ownerObject() == this) - info->objectsMallocHeapElementsNormal += mallocSizeOf(elements); + if (!elements->isCopyOnWrite() || elements->ownerObject() == this) { + void* allocatedElements = as().getUnshiftedElementsHeader(); + info->objectsMallocHeapElementsNormal += mallocSizeOf(allocatedElements); + } } // Other things may be measured in the future if DMD indicates it is worthwhile. @@ -3947,7 +3951,7 @@ JSObject::sizeOfIncludingThisInNursery() const if (native.hasDynamicElements()) { js::ObjectElements& elements = *native.getElementsHeader(); if (!elements.isCopyOnWrite() || elements.ownerObject() == this) - size += elements.capacity * sizeof(HeapSlot); + size += (elements.capacity + elements.numShiftedElements()) * sizeof(HeapSlot); } if (is()) diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 75edebda82d7..d5d01bd3f708 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -99,10 +99,11 @@ JSObject::finalize(js::FreeOp* fop) // Don't free the elements until object finalization finishes, // so that other objects can access these elements while they // are themselves finalized. + MOZ_ASSERT(elements->numShiftedElements() == 0); fop->freeLater(elements); } } else { - fop->free_(elements); + fop->free_(nobj->getUnshiftedElementsHeader()); } } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 455a27a52ee1..4461f7f55688 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -157,19 +157,6 @@ static const TimeDuration MAX_TIMEOUT_INTERVAL = TimeDuration::FromSeconds(1800. # define SINGLESTEP_PROFILING #endif -using JobQueue = GCVector; - -struct ShellAsyncTasks -{ - explicit ShellAsyncTasks(JSContext* cx) - : outstanding(0), - finished(cx) - {} - - size_t outstanding; - Vector finished; -}; - enum class ScriptKind { Script, @@ -318,9 +305,6 @@ struct ShellContext bool lastWarningEnabled; JS::PersistentRootedValue lastWarning; JS::PersistentRootedValue promiseRejectionTrackerCallback; - JS::PersistentRooted jobQueue; - ExclusiveData asyncTasks; - bool drainingJobQueue; #ifdef SINGLESTEP_PROFILING Vector stacks; #endif @@ -488,8 +472,6 @@ ShellContext::ShellContext(JSContext* cx) lastWarningEnabled(false), lastWarning(cx, NullValue()), promiseRejectionTrackerCallback(cx, NullValue()), - asyncTasks(mutexid::ShellAsyncTasks, cx), - drainingJobQueue(false), watchdogLock(mutexid::ShellContextWatchdog), exitCode(0), quitting(false), @@ -816,115 +798,13 @@ RunModule(JSContext* cx, const char* filename, FILE* file, bool compileOnly) return JS_CallFunction(cx, loaderObj, importFun, args, &value); } -static JSObject* -ShellGetIncumbentGlobalCallback(JSContext* cx) -{ - return JS::CurrentGlobalOrNull(cx); -} - -static bool -ShellEnqueuePromiseJobCallback(JSContext* cx, JS::HandleObject job, JS::HandleObject allocationSite, - JS::HandleObject incumbentGlobal, void* data) -{ - ShellContext* sc = GetShellContext(cx); - MOZ_ASSERT(job); - return sc->jobQueue.append(job); -} - -static bool -ShellStartAsyncTaskCallback(JSContext* cx, JS::AsyncTask* task) -{ - ShellContext* sc = GetShellContext(cx); - task->user = sc; - - ExclusiveData::Guard asyncTasks = sc->asyncTasks.lock(); - asyncTasks->outstanding++; - return true; -} - -static bool -ShellFinishAsyncTaskCallback(JS::AsyncTask* task) -{ - ShellContext* sc = (ShellContext*)task->user; - - ExclusiveData::Guard asyncTasks = sc->asyncTasks.lock(); - MOZ_ASSERT(asyncTasks->outstanding > 0); - asyncTasks->outstanding--; - return asyncTasks->finished.append(task); -} - -static void -DrainJobQueue(JSContext* cx) -{ - ShellContext* sc = GetShellContext(cx); - if (sc->quitting || sc->drainingJobQueue) - return; - - while (true) { - // Wait for any outstanding async tasks to finish so that the - // finishedAsyncTasks list is fixed. - while (true) { - AutoLockHelperThreadState lock; - if (!sc->asyncTasks.lock()->outstanding) - break; - HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER); - } - - // Lock the whole time while copying back the asyncTasks finished queue - // so that any new tasks created during finish() cannot racily join the - // job queue. Call finish() only thereafter, to avoid a circular mutex - // dependency (see also bug 1297901). - Vector finished(cx); - { - ExclusiveData::Guard asyncTasks = sc->asyncTasks.lock(); - finished = Move(asyncTasks->finished); - asyncTasks->finished.clear(); - } - - for (JS::AsyncTask* task : finished) - task->finish(cx); - - // It doesn't make sense for job queue draining to be reentrant. At the - // same time we don't want to assert against it, because that'd make - // drainJobQueue unsafe for fuzzers. We do want fuzzers to test this, - // so we simply ignore nested calls of drainJobQueue. - sc->drainingJobQueue = true; - - RootedObject job(cx); - JS::HandleValueArray args(JS::HandleValueArray::empty()); - RootedValue rval(cx); - - // Execute jobs in a loop until we've reached the end of the queue. - // Since executing a job can trigger enqueuing of additional jobs, - // it's crucial to re-check the queue length during each iteration. - for (size_t i = 0; i < sc->jobQueue.length(); i++) { - job = sc->jobQueue[i]; - AutoCompartment ac(cx, job); - { - AutoReportException are(cx); - JS::Call(cx, UndefinedHandleValue, job, args, &rval); - } - sc->jobQueue[i].set(nullptr); - } - sc->jobQueue.clear(); - sc->drainingJobQueue = false; - - // It's possible a job added an async task, and it's also possible - // that task has already finished. - { - ExclusiveData::Guard asyncTasks = sc->asyncTasks.lock(); - if (asyncTasks->outstanding == 0 && asyncTasks->finished.length() == 0) - break; - } - } -} - static bool DrainJobQueue(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - DrainJobQueue(cx); + MOZ_ASSERT(!GetShellContext(cx)->quitting); + js::RunJobs(cx); args.rval().setUndefined(); return true; @@ -1107,7 +987,8 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, bool compileOnly) stderr); } - DrainJobQueue(cx); + if (!GetShellContext(cx)->quitting) + js::RunJobs(cx); } while (!hitEOF && !sc->quitting); @@ -2287,6 +2168,7 @@ Quit(JSContext* cx, unsigned argc, Value* vp) return false; } + js::StopDrainingJobQueue(cx); sc->exitCode = code; sc->quitting = true; return false; @@ -3586,9 +3468,7 @@ WorkerMain(void* arg) if (input->parentRuntime) sc->isWorker = true; JS_SetContextPrivate(cx, sc.get()); - JS_SetGrayGCRootsTracer(cx, TraceGrayRoots, nullptr); SetWorkerContextOptions(cx); - sc->jobQueue.init(cx, JobQueue(SystemAllocPolicy())); Maybe environmentPreparer; if (input->parentRuntime) { @@ -3597,13 +3477,11 @@ WorkerMain(void* arg) js::SetPreserveWrapperCallback(cx, DummyPreserveWrapperCallback); JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy); + js::UseInternalJobQueues(cx); + if (!JS::InitSelfHostedCode(cx)) return; - JS::SetEnqueuePromiseJobCallback(cx, ShellEnqueuePromiseJobCallback); - JS::SetGetIncumbentGlobalCallback(cx, ShellGetIncumbentGlobalCallback); - JS::SetAsyncTaskCallbacks(cx, ShellStartAsyncTaskCallback, ShellFinishAsyncTaskCallback); - environmentPreparer.emplace(cx); } else { JS_AddInterruptCallback(cx, ShellInterruptCallback); @@ -3635,13 +3513,6 @@ WorkerMain(void* arg) JS_ExecuteScript(cx, script, &result); } while (0); - if (input->parentRuntime) { - JS::SetGetIncumbentGlobalCallback(cx, nullptr); - JS::SetEnqueuePromiseJobCallback(cx, nullptr); - } - - sc->jobQueue.reset(); - KillWatchdog(cx); JS_SetGrayGCRootsTracer(cx, nullptr, nullptr); } @@ -8290,7 +8161,8 @@ Shell(JSContext* cx, OptionParser* op, char** envp) * tasks before the main thread JSRuntime is torn down. Drain after * uncaught exceptions have been reported since draining runs callbacks. */ - DrainJobQueue(cx); + if (!GetShellContext(cx)->quitting) + js::RunJobs(cx); if (sc->exitCode) result = sc->exitCode; @@ -8647,14 +8519,11 @@ main(int argc, char** argv, char** envp) JS::dbg::SetDebuggerMallocSizeOf(cx, moz_malloc_size_of); + js::UseInternalJobQueues(cx); + if (!JS::InitSelfHostedCode(cx)) return 1; - sc->jobQueue.init(cx, JobQueue(SystemAllocPolicy())); - JS::SetEnqueuePromiseJobCallback(cx, ShellEnqueuePromiseJobCallback); - JS::SetGetIncumbentGlobalCallback(cx, ShellGetIncumbentGlobalCallback); - JS::SetAsyncTaskCallbacks(cx, ShellStartAsyncTaskCallback, ShellFinishAsyncTaskCallback); - EnvironmentPreparer environmentPreparer(cx); JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_INCREMENTAL); @@ -8686,13 +8555,10 @@ main(int argc, char** argv, char** envp) printf("OOM max count: %" PRIu64 "\n", js::oom::counter); #endif - JS::SetGetIncumbentGlobalCallback(cx, nullptr); - JS::SetEnqueuePromiseJobCallback(cx, nullptr); JS_SetGrayGCRootsTracer(cx, nullptr, nullptr); // Must clear out some of sc's pointer containers before JS_DestroyContext. sc->markObservers.reset(); - sc->jobQueue.reset(); KillWatchdog(cx); diff --git a/js/src/vm/MutexIDs.h b/js/src/vm/MutexIDs.h index bb7c44317c7a..f28f2b98e0c4 100644 --- a/js/src/vm/MutexIDs.h +++ b/js/src/vm/MutexIDs.h @@ -22,7 +22,7 @@ \ _(GlobalHelperThreadState, 300) \ \ - _(ShellAsyncTasks, 350) \ + _(InternalAsyncTasks, 350) \ \ _(GCLock, 400) \ \ diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 2f0e171c19d6..30a7d95b5dca 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -124,7 +124,8 @@ NativeObject::elementsRangeWriteBarrierPost(uint32_t start, uint32_t count) const Value& v = elements_[start + i]; if (v.isObject() && IsInsideNursery(&v.toObject())) { zone()->group()->storeBuffer().putSlot(this, HeapSlot::Element, - start + i, count - i); + unshiftedIndex(start + i), + count - i); return; } } @@ -141,8 +142,12 @@ NativeObject::copyDenseElements(uint32_t dstStart, const Value* src, uint32_t co checkStoredValue(src[i]); #endif if (JS::shadow::Zone::asShadowZone(zone())->needsIncrementalBarrier()) { - for (uint32_t i = 0; i < count; ++i) - elements_[dstStart + i].set(this, HeapSlot::Element, dstStart + i, src[i]); + uint32_t numShifted = getElementsHeader()->numShiftedElements(); + for (uint32_t i = 0; i < count; ++i) { + elements_[dstStart + i].set(this, HeapSlot::Element, + dstStart + i + numShifted, + src[i]); + } } else { memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot)); elementsRangeWriteBarrierPost(dstStart, count); @@ -163,6 +168,36 @@ NativeObject::initDenseElements(uint32_t dstStart, const Value* src, uint32_t co elementsRangeWriteBarrierPost(dstStart, count); } +inline bool +NativeObject::tryShiftDenseElements(uint32_t count) +{ + ObjectElements* header = getElementsHeader(); + if (header->isCopyOnWrite() || + header->isFrozen() || + header->hasNonwritableArrayLength() || + header->initializedLength == count) + { + return false; + } + + MOZ_ASSERT(count > 0); + MOZ_ASSERT(count < header->initializedLength); + MOZ_ASSERT(count <= ObjectElements::MaxShiftedElements); + + if (MOZ_UNLIKELY(header->numShiftedElements() + count > ObjectElements::MaxShiftedElements)) { + unshiftElements(); + header = getElementsHeader(); + } + + prepareElementRangeForOverwrite(0, count); + header->addShiftedElements(count); + + elements_ += count; + ObjectElements* newHeader = getElementsHeader(); + memmove(newHeader, header, sizeof(ObjectElements)); + return true; +} + inline void NativeObject::moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t count) { @@ -184,16 +219,17 @@ NativeObject::moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t c * the array before and after the move. */ if (JS::shadow::Zone::asShadowZone(zone())->needsIncrementalBarrier()) { + uint32_t numShifted = getElementsHeader()->numShiftedElements(); if (dstStart < srcStart) { HeapSlot* dst = elements_ + dstStart; HeapSlot* src = elements_ + srcStart; for (uint32_t i = 0; i < count; i++, dst++, src++) - dst->set(this, HeapSlot::Element, dst - elements_, *src); + dst->set(this, HeapSlot::Element, dst - elements_ + numShifted, *src); } else { HeapSlot* dst = elements_ + dstStart + count - 1; HeapSlot* src = elements_ + srcStart + count - 1; for (uint32_t i = 0; i < count; i++, dst--, src--) - dst->set(this, HeapSlot::Element, dst - elements_, *src); + dst->set(this, HeapSlot::Element, dst - elements_ + numShifted, *src); } } else { memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(HeapSlot)); @@ -231,12 +267,13 @@ NativeObject::ensureDenseInitializedLengthNoPackedCheck(JSContext* cx, uint32_t uint32_t& initlen = getElementsHeader()->initializedLength; if (initlen < index + extra) { + uint32_t numShifted = getElementsHeader()->numShiftedElements(); size_t offset = initlen; for (HeapSlot* sp = elements_ + initlen; sp != elements_ + (index + extra); sp++, offset++) { - sp->init(this, HeapSlot::Element, offset, MagicValue(JS_ELEMENTS_HOLE)); + sp->init(this, HeapSlot::Element, offset + numShifted, MagicValue(JS_ELEMENTS_HOLE)); } initlen = index + extra; } diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index c42f01b501d2..60eb2dd4fcee 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -8,6 +8,7 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Casting.h" +#include "mozilla/CheckedInt.h" #include "jswatchpoint.h" @@ -28,6 +29,7 @@ using namespace js; using JS::AutoCheckCannotGC; using JS::GenericNaN; using mozilla::ArrayLength; +using mozilla::CheckedInt; using mozilla::DebugOnly; using mozilla::PodCopy; using mozilla::RoundUpPow2; @@ -112,6 +114,9 @@ ObjectElements::FreezeElements(JSContext* cx, HandleNativeObject obj) if (obj->hasEmptyElements()) return true; + if (obj->getElementsHeader()->numShiftedElements() > 0) + obj->unshiftElements(); + ObjectElements* header = obj->getElementsHeader(); // Note: this method doesn't update type information to indicate that the @@ -329,7 +334,7 @@ NativeObject::setLastPropertyMakeNonNative(Shape* shape) MOZ_ASSERT(shape->numFixedSlots() == 0); if (hasDynamicElements()) - js_free(getElementsHeader()); + js_free(getUnshiftedElementsHeader()); if (hasDynamicSlots()) { js_free(slots_); slots_ = nullptr; @@ -701,6 +706,49 @@ NativeObject::maybeDensifySparseElements(JSContext* cx, HandleNativeObject obj) return DenseElementResult::Success; } +void +NativeObject::unshiftElements() +{ + ObjectElements* header = getElementsHeader(); + uint32_t numShifted = header->numShiftedElements(); + MOZ_ASSERT(numShifted > 0); + + uint32_t initLength = header->initializedLength; + + ObjectElements* newHeader = static_cast(getUnshiftedElementsHeader()); + memmove(newHeader, header, sizeof(ObjectElements)); + + newHeader->clearShiftedElements(); + newHeader->capacity += numShifted; + elements_ = newHeader->elements(); + + // To move the elements, temporarily update initializedLength to include + // both shifted and unshifted elements. + newHeader->initializedLength += numShifted; + + // Move the elements. Initialize to |undefined| to ensure pre-barriers + // don't see garbage. + for (size_t i = 0; i < numShifted; i++) + initDenseElement(i, UndefinedValue()); + moveDenseElements(0, numShifted, initLength); + + // Restore the initialized length. We use setDenseInitializedLength to + // make sure prepareElementRangeForOverwrite is called on the shifted + // elements. + setDenseInitializedLength(initLength); +} + +void +NativeObject::maybeUnshiftElements() +{ + ObjectElements* header = getElementsHeader(); + MOZ_ASSERT(header->numShiftedElements() > 0); + + // Unshift if less than a third of the allocated space is in use. + if (header->capacity < header->numAllocatedElements() / 3) + unshiftElements(); +} + // Given a requested capacity (in elements) and (potentially) the length of an // array for which elements are being allocated, compute an actual allocation // amount (in elements). (Allocation amounts include space for an @@ -799,6 +847,26 @@ NativeObject::growElements(JSContext* cx, uint32_t reqCapacity) if (denseElementsAreCopyOnWrite()) MOZ_CRASH(); + // If there are shifted elements, consider unshifting them first. If we + // don't unshift here, the code below will include the shifted elements in + // the resize. + uint32_t numShifted = getElementsHeader()->numShiftedElements(); + if (numShifted > 0) { + maybeUnshiftElements(); + if (getDenseCapacity() >= reqCapacity) + return true; + numShifted = getElementsHeader()->numShiftedElements(); + + // Ensure |reqCapacity + numShifted| below won't overflow by forcing an + // unshift in that case. + CheckedInt checkedReqCapacity(reqCapacity); + checkedReqCapacity += numShifted; + if (MOZ_UNLIKELY(!checkedReqCapacity.isValid())) { + unshiftElements(); + numShifted = 0; + } + } + uint32_t oldCapacity = getDenseCapacity(); MOZ_ASSERT(oldCapacity < reqCapacity); @@ -809,13 +877,17 @@ NativeObject::growElements(JSContext* cx, uint32_t reqCapacity) // Preserve the |capacity <= length| invariant for arrays with // non-writable length. See also js::ArraySetLength which initially // enforces this requirement. - newAllocated = reqCapacity + ObjectElements::VALUES_PER_HEADER; + newAllocated = reqCapacity + numShifted + ObjectElements::VALUES_PER_HEADER; } else { - if (!goodElementsAllocationAmount(cx, reqCapacity, getElementsHeader()->length, &newAllocated)) + if (!goodElementsAllocationAmount(cx, reqCapacity + numShifted, + getElementsHeader()->length, + &newAllocated)) + { return false; + } } - uint32_t newCapacity = newAllocated - ObjectElements::VALUES_PER_HEADER; + uint32_t newCapacity = newAllocated - ObjectElements::VALUES_PER_HEADER - numShifted; MOZ_ASSERT(newCapacity > oldCapacity && newCapacity >= reqCapacity); // If newCapacity exceeds MAX_DENSE_ELEMENTS_COUNT, the array should become @@ -824,11 +896,11 @@ NativeObject::growElements(JSContext* cx, uint32_t reqCapacity) uint32_t initlen = getDenseInitializedLength(); - HeapSlot* oldHeaderSlots = reinterpret_cast(getElementsHeader()); + HeapSlot* oldHeaderSlots = reinterpret_cast(getUnshiftedElementsHeader()); HeapSlot* newHeaderSlots; if (hasDynamicElements()) { MOZ_ASSERT(oldCapacity <= MAX_DENSE_ELEMENTS_COUNT); - uint32_t oldAllocated = oldCapacity + ObjectElements::VALUES_PER_HEADER; + uint32_t oldAllocated = oldCapacity + ObjectElements::VALUES_PER_HEADER + numShifted; newHeaderSlots = ReallocateObjectBuffer(cx, this, oldHeaderSlots, oldAllocated, newAllocated); if (!newHeaderSlots) @@ -837,12 +909,13 @@ NativeObject::growElements(JSContext* cx, uint32_t reqCapacity) newHeaderSlots = AllocateObjectBuffer(cx, this, newAllocated); if (!newHeaderSlots) return false; // Leave elements at its old size. - PodCopy(newHeaderSlots, oldHeaderSlots, ObjectElements::VALUES_PER_HEADER + initlen); + PodCopy(newHeaderSlots, oldHeaderSlots, + ObjectElements::VALUES_PER_HEADER + initlen + numShifted); } ObjectElements* newheader = reinterpret_cast(newHeaderSlots); - newheader->capacity = newCapacity; - elements_ = newheader->elements(); + elements_ = newheader->elements() + numShifted; + getElementsHeader()->capacity = newCapacity; Debug_SetSlotRangeToCrashOnTouch(elements_ + initlen, newCapacity - initlen); @@ -852,9 +925,6 @@ NativeObject::growElements(JSContext* cx, uint32_t reqCapacity) void NativeObject::shrinkElements(JSContext* cx, uint32_t reqCapacity) { - uint32_t oldCapacity = getDenseCapacity(); - MOZ_ASSERT(reqCapacity < oldCapacity); - MOZ_ASSERT(canHaveNonEmptyElements()); if (denseElementsAreCopyOnWrite()) MOZ_CRASH(); @@ -862,18 +932,29 @@ NativeObject::shrinkElements(JSContext* cx, uint32_t reqCapacity) if (!hasDynamicElements()) return; + // If we have shifted elements, consider unshifting them. + uint32_t numShifted = getElementsHeader()->numShiftedElements(); + if (numShifted > 0) { + maybeUnshiftElements(); + numShifted = getElementsHeader()->numShiftedElements(); + } + + uint32_t oldCapacity = getDenseCapacity(); + MOZ_ASSERT(reqCapacity < oldCapacity); + uint32_t newAllocated = 0; - MOZ_ALWAYS_TRUE(goodElementsAllocationAmount(cx, reqCapacity, 0, &newAllocated)); + MOZ_ALWAYS_TRUE(goodElementsAllocationAmount(cx, reqCapacity + numShifted, 0, &newAllocated)); MOZ_ASSERT(oldCapacity <= MAX_DENSE_ELEMENTS_COUNT); - uint32_t oldAllocated = oldCapacity + ObjectElements::VALUES_PER_HEADER; + + uint32_t oldAllocated = oldCapacity + ObjectElements::VALUES_PER_HEADER + numShifted; if (newAllocated == oldAllocated) return; // Leave elements at its old size. MOZ_ASSERT(newAllocated > ObjectElements::VALUES_PER_HEADER); - uint32_t newCapacity = newAllocated - ObjectElements::VALUES_PER_HEADER; + uint32_t newCapacity = newAllocated - ObjectElements::VALUES_PER_HEADER - numShifted; MOZ_ASSERT(newCapacity <= MAX_DENSE_ELEMENTS_COUNT); - HeapSlot* oldHeaderSlots = reinterpret_cast(getElementsHeader()); + HeapSlot* oldHeaderSlots = reinterpret_cast(getUnshiftedElementsHeader()); HeapSlot* newHeaderSlots = ReallocateObjectBuffer(cx, this, oldHeaderSlots, oldAllocated, newAllocated); if (!newHeaderSlots) { @@ -882,8 +963,8 @@ NativeObject::shrinkElements(JSContext* cx, uint32_t reqCapacity) } ObjectElements* newheader = reinterpret_cast(newHeaderSlots); - newheader->capacity = newCapacity; - elements_ = newheader->elements(); + elements_ = newheader->elements() + numShifted; + getElementsHeader()->capacity = newCapacity; } /* static */ bool diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 21fc2ee45441..f4f12fc942db 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -157,11 +157,28 @@ ArraySetLength(JSContext* cx, Handle obj, HandleId id, * Elements do not track property creation order, so enumerating the elements * of an object does not necessarily visit indexes in the order they were * created. + * + * Shifted elements + * ---------------- + * It's pretty common to use an array as a queue, like this: + * + * while (arr.length > 0) + * foo(arr.shift()); + * + * To ensure we don't get quadratic behavior on this, elements can be 'shifted' + * in memory. tryShiftDenseElements does this by incrementing elements_ to point + * to the next element and moving the ObjectElements header in memory (so it's + * stored where the shifted Value used to be). + * + * Shifted elements can be unshifted when we grow the array, when the array is + * frozen (for simplicity, shifted elements are not supported on objects that + * are frozen, have copy-on-write elements, or on arrays with non-writable + * length). */ class ObjectElements { public: - enum Flags: uint32_t { + enum Flags: uint16_t { // Integers written to these elements must be converted to doubles. CONVERT_DOUBLE_ELEMENTS = 0x1, @@ -187,6 +204,15 @@ class ObjectElements FROZEN = 0x10, }; + // The flags word stores both the flags and the number of shifted elements. + // Allow shifting 2047 elements before unshifting. + static const size_t NumShiftedElementsBits = 11; + static const size_t MaxShiftedElements = (1 << NumShiftedElementsBits) - 1; + static const size_t NumShiftedElementsShift = 32 - NumShiftedElementsBits; + static const size_t FlagsMask = (1 << NumShiftedElementsShift) - 1; + static_assert(MaxShiftedElements == 2047, + "MaxShiftedElements should match the comment"); + private: friend class ::JSObject; friend class ArrayObject; @@ -199,7 +225,9 @@ class ObjectElements ArraySetLength(JSContext* cx, Handle obj, HandleId id, unsigned attrs, HandleValue value, ObjectOpResult& result); - /* See Flags enum above. */ + // The NumShiftedElementsBits high bits of this are used to store the + // number of shifted elements, the other bits are available for the flags. + // See Flags enum above. uint32_t flags; /* @@ -242,6 +270,21 @@ class ObjectElements flags &= ~COPY_ON_WRITE; } + void addShiftedElements(uint32_t count) { + MOZ_ASSERT(count < capacity); + MOZ_ASSERT(count < initializedLength); + MOZ_ASSERT(!(flags & (NONWRITABLE_ARRAY_LENGTH | FROZEN | COPY_ON_WRITE))); + uint32_t numShifted = numShiftedElements() + count; + MOZ_ASSERT(numShifted <= MaxShiftedElements); + flags = (numShifted << NumShiftedElementsShift) | (flags & FlagsMask); + capacity -= count; + initializedLength -= count; + } + void clearShiftedElements() { + flags &= FlagsMask; + MOZ_ASSERT(numShiftedElements() == 0); + } + public: constexpr ObjectElements(uint32_t capacity, uint32_t length) : flags(0), initializedLength(0), capacity(capacity), length(length) @@ -261,7 +304,7 @@ class ObjectElements const HeapSlot* elements() const { return reinterpret_cast(uintptr_t(this) + sizeof(ObjectElements)); } - static ObjectElements * fromElements(HeapSlot* elems) { + static ObjectElements* fromElements(HeapSlot* elems) { return reinterpret_cast(uintptr_t(elems) - sizeof(ObjectElements)); } @@ -311,6 +354,17 @@ class ObjectElements return JSPROP_ENUMERATE; } + uint32_t numShiftedElements() const { + uint32_t numShifted = flags >> NumShiftedElementsShift; + MOZ_ASSERT_IF(numShifted > 0, + !(flags & (NONWRITABLE_ARRAY_LENGTH | FROZEN | COPY_ON_WRITE))); + return numShifted; + } + + uint32_t numAllocatedElements() const { + return VALUES_PER_HEADER + capacity + numShiftedElements(); + } + // This is enough slots to store an object of this class. See the static // assertion below. static const size_t VALUES_PER_HEADER = 2; @@ -985,10 +1039,26 @@ class NativeObject : public ShapedObject "uint32_t (and sometimes int32_t ,too)"); } - ObjectElements * getElementsHeader() const { + ObjectElements* getElementsHeader() const { return ObjectElements::fromElements(elements_); } + // Returns a pointer to the first element, including shifted elements. + inline HeapSlot* unshiftedElements() const { + return elements_ - getElementsHeader()->numShiftedElements(); + } + + // Like getElementsHeader, but returns a pointer to the unshifted header. + // This is mainly useful for free()ing dynamic elements: the pointer + // returned here is the one we got from malloc. + void* getUnshiftedElementsHeader() const { + return ObjectElements::fromElements(unshiftedElements()); + } + + uint32_t unshiftedIndex(uint32_t index) const { + return index + getElementsHeader()->numShiftedElements(); + } + /* Accessors for elements. */ bool ensureElements(JSContext* cx, uint32_t capacity) { MOZ_ASSERT(!denseElementsAreCopyOnWrite()); @@ -998,6 +1068,15 @@ class NativeObject : public ShapedObject return true; } + // Try to shift |count| dense elements, see the "Shifted elements" comment. + inline bool tryShiftDenseElements(uint32_t count); + + // Unshift all shifted elements so that numShiftedElements is 0. + void unshiftElements(); + + // If this object has many shifted elements, unshift them. + void maybeUnshiftElements(); + static bool goodElementsAllocationAmount(JSContext* cx, uint32_t reqAllocated, uint32_t length, uint32_t* goodAmount); bool growElements(JSContext* cx, uint32_t newcap); @@ -1039,7 +1118,7 @@ class NativeObject : public ShapedObject MOZ_ASSERT(index < getDenseInitializedLength()); MOZ_ASSERT(!denseElementsAreCopyOnWrite()); checkStoredValue(val); - elements_[index].set(this, HeapSlot::Element, index, val); + elements_[index].set(this, HeapSlot::Element, unshiftedIndex(index), val); } public: @@ -1061,7 +1140,7 @@ class NativeObject : public ShapedObject MOZ_ASSERT(!denseElementsAreCopyOnWrite()); MOZ_ASSERT(!denseElementsAreFrozen()); checkStoredValue(val); - elements_[index].init(this, HeapSlot::Element, index, val); + elements_[index].init(this, HeapSlot::Element, unshiftedIndex(index), val); } void setDenseElementMaybeConvertDouble(uint32_t index, const Value& val) { @@ -1156,9 +1235,9 @@ class NativeObject : public ShapedObject bool canHaveNonEmptyElements(); #endif - void setFixedElements() { + void setFixedElements(uint32_t numShifted = 0) { MOZ_ASSERT(canHaveNonEmptyElements()); - elements_ = fixedElements(); + elements_ = fixedElements() + numShifted; } inline bool hasDynamicElements() const { @@ -1169,11 +1248,11 @@ class NativeObject : public ShapedObject * immediately afterwards. Such cases cannot occur for dense arrays * (which have at least two fixed slots) and can only result in a leak. */ - return !hasEmptyElements() && elements_ != fixedElements(); + return !hasEmptyElements() && !hasFixedElements(); } inline bool hasFixedElements() const { - return elements_ == fixedElements(); + return unshiftedElements() == fixedElements(); } inline bool hasEmptyElements() const { diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 9b7337be6adf..3c37a6c743ac 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -694,8 +694,13 @@ FreeOp::isDefaultFreeOp() const JSObject* JSRuntime::getIncumbentGlobal(JSContext* cx) { - MOZ_ASSERT(cx->getIncumbentGlobalCallback, - "Must set a callback using SetGetIncumbentGlobalCallback before using Promises"); + // If the embedding didn't set a callback for getting the incumbent + // global, the currently active global is used. + if (!cx->getIncumbentGlobalCallback) { + if (!cx->compartment()) + return nullptr; + return cx->global(); + } return cx->getIncumbentGlobalCallback(cx); } diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 9060fae3bbf7..37d595935b7c 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -286,6 +286,7 @@ void DisableExtraThreads(); using ScriptAndCountsVector = GCVector; class AutoLockForExclusiveAccess; + } // namespace js struct JSRuntime : public js::MallocProvider diff --git a/js/src/vm/Xdr.cpp b/js/src/vm/Xdr.cpp index b0d70c2b05c7..77c53adfcd3c 100644 --- a/js/src/vm/Xdr.cpp +++ b/js/src/vm/Xdr.cpp @@ -32,7 +32,8 @@ void XDRState::postProcessContextErrors(JSContext* cx) { if (!cx->helperThread() && cx->isExceptionPending()) { - MOZ_ASSERT(resultCode_ == JS::TranscodeResult_Ok); + MOZ_ASSERT(resultCode_ == JS::TranscodeResult_Ok || + resultCode_ == JS::TranscodeResult_Throw); resultCode_ = JS::TranscodeResult_Throw; } } diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index a531c222d83a..03b0c8a05dd9 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -1791,14 +1791,6 @@ WebAssembly_toSource(JSContext* cx, unsigned argc, Value* vp) } #endif -static bool -Nop(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - args.rval().setUndefined(); - return true; -} - static bool Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle promise) { @@ -1919,11 +1911,7 @@ WebAssembly_compile(JSContext* cx, unsigned argc, Value* vp) return false; } - RootedFunction nopFun(cx, NewNativeFunction(cx, Nop, 0, nullptr)); - if (!nopFun) - return false; - - Rooted promise(cx, PromiseObject::create(cx, nopFun)); + Rooted promise(cx, PromiseObject::createSkippingExecutor(cx)); if (!promise) return false; @@ -2016,11 +2004,7 @@ WebAssembly_instantiate(JSContext* cx, unsigned argc, Value* vp) return false; } - RootedFunction nopFun(cx, NewNativeFunction(cx, Nop, 0, nullptr)); - if (!nopFun) - return false; - - Rooted promise(cx, PromiseObject::create(cx, nopFun)); + Rooted promise(cx, PromiseObject::createSkippingExecutor(cx)); if (!promise) return false; diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index f33f32f04647..ea8b776fbfda 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -146,6 +146,7 @@ void RenderFrameParent::Destroy() { mFrameLoaderDestroyed = true; + mLayerManager = nullptr; } already_AddRefed @@ -206,18 +207,35 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, return layer.forget(); } +LayerManager* +RenderFrameParent::AttachLayerManager() +{ + RefPtr lm; + + if (mFrameLoader) { + nsIContent* content = mFrameLoader->GetOwnerContent(); + if (content) { + lm = nsContentUtils::LayerManagerForContent(content); + } + } + + // Perhaps the document containing this frame currently has no presentation? + if (lm && lm->GetCompositorBridgeChild() && lm != mLayerManager) { + mLayersConnected = lm->GetCompositorBridgeChild()->SendAdoptChild(mLayersId); + FrameLayerBuilder::InvalidateAllLayers(lm); + } + + mLayerManager = lm.forget(); + return mLayerManager; +} + void RenderFrameParent::OwnerContentChanged(nsIContent* aContent) { MOZ_ASSERT(!mFrameLoader || mFrameLoader->GetOwnerContent() == aContent, "Don't build new map if owner is same!"); - RefPtr lm = mFrameLoader ? GetFrom(mFrameLoader) : nullptr; - // Perhaps the document containing this frame currently has no presentation? - if (lm && lm->GetCompositorBridgeChild()) { - mLayersConnected = lm->GetCompositorBridgeChild()->SendAdoptChild(mLayersId); - FrameLayerBuilder::InvalidateAllLayers(lm); - } + Unused << AttachLayerManager(); } void @@ -232,6 +250,7 @@ RenderFrameParent::ActorDestroy(ActorDestroyReason why) } mFrameLoader = nullptr; + mLayerManager = nullptr; } mozilla::ipc::IPCResult diff --git a/layout/ipc/RenderFrameParent.h b/layout/ipc/RenderFrameParent.h index 693849c80921..b1b40b1190ca 100644 --- a/layout/ipc/RenderFrameParent.h +++ b/layout/ipc/RenderFrameParent.h @@ -90,6 +90,8 @@ public: void EnsureLayersConnected(CompositorOptions* aCompositorOptions); + LayerManager* AttachLayerManager(); + protected: void ActorDestroy(ActorDestroyReason why) override; @@ -114,6 +116,7 @@ private: RefPtr mFrameLoader; RefPtr mContainer; + RefPtr mLayerManager; // True after Destroy() has been called, which is triggered // originally by nsFrameLoader::Destroy(). After this point, we can diff --git a/layout/mathml/nsMathMLmencloseFrame.cpp b/layout/mathml/nsMathMLmencloseFrame.cpp index b9340ff3454a..fd069259f89d 100644 --- a/layout/mathml/nsMathMLmencloseFrame.cpp +++ b/layout/mathml/nsMathMLmencloseFrame.cpp @@ -49,6 +49,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmencloseFrame) nsMathMLmencloseFrame::nsMathMLmencloseFrame(nsStyleContext* aContext) : nsMathMLContainerFrame(aContext), mNotationsToDraw(0), + mRuleThickness(0), mRadicalRuleThickness(0), mLongDivCharIndex(-1), mRadicalCharIndex(-1), mContentWidth(0) { } diff --git a/layout/mathml/nsMathMLmoFrame.h b/layout/mathml/nsMathMLmoFrame.h index f25107a20b7b..63a3742f2d03 100644 --- a/layout/mathml/nsMathMLmoFrame.h +++ b/layout/mathml/nsMathMLmoFrame.h @@ -80,7 +80,8 @@ public: } protected: - explicit nsMathMLmoFrame(nsStyleContext* aContext) : nsMathMLTokenFrame(aContext) {} + explicit nsMathMLmoFrame(nsStyleContext* aContext) : + nsMathMLTokenFrame(aContext), mFlags(0), mMinSize(0), mMaxSize(0) {} virtual ~nsMathMLmoFrame(); nsMathMLChar mMathMLChar; // Here is the MathMLChar that will deal with the operator. diff --git a/layout/mathml/nsMathMLmspaceFrame.h b/layout/mathml/nsMathMLmspaceFrame.h index 0dfff3a4c9d7..92e19cbf3c80 100644 --- a/layout/mathml/nsMathMLmspaceFrame.h +++ b/layout/mathml/nsMathMLmspaceFrame.h @@ -36,7 +36,8 @@ public: nsReflowStatus& aStatus) override; protected: - explicit nsMathMLmspaceFrame(nsStyleContext* aContext) : nsMathMLContainerFrame(aContext) {} + explicit nsMathMLmspaceFrame(nsStyleContext* aContext) : + nsMathMLContainerFrame(aContext), mWidth(0), mHeight(0), mDepth(0) {} virtual ~nsMathMLmspaceFrame(); virtual nsresult diff --git a/layout/mathml/nsMathMLmtableFrame.h b/layout/mathml/nsMathMLmtableFrame.h index 8f766b4cc53e..e64071cc03b2 100644 --- a/layout/mathml/nsMathMLmtableFrame.h +++ b/layout/mathml/nsMathMLmtableFrame.h @@ -159,6 +159,9 @@ public: protected: explicit nsMathMLmtableFrame(nsStyleContext* aContext) : nsTableFrame(aContext) + , mFrameSpacingX(0) + , mFrameSpacingY(0) + , mUseCSSSpacing(false) {} virtual ~nsMathMLmtableFrame(); diff --git a/layout/reftests/async-scrolling/reftest.list b/layout/reftests/async-scrolling/reftest.list index b62839e97111..03e119113cc5 100644 --- a/layout/reftests/async-scrolling/reftest.list +++ b/layout/reftests/async-scrolling/reftest.list @@ -5,7 +5,7 @@ skip-if(!asyncPan) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html skip-if(!asyncPan) == bg-fixed-child.html bg-fixed-child-ref.html skip-if(!asyncPan) == bg-fixed-child-clip-1.html bg-fixed-child-clip-ref.html skip-if(!asyncPan) == bg-fixed-child-clip-2.html bg-fixed-child-clip-ref.html -fuzzy(1,246) fuzzy-if(skiaContent,2,160) fuzzy-if(browserIsRemote&&d2d,53,185) skip-if(!asyncPan) == bg-fixed-child-mask.html bg-fixed-child-mask-ref.html +fuzzy(1,246) fuzzy-if(skiaContent,2,170) fuzzy-if(browserIsRemote&&d2d,53,185) skip-if(!asyncPan) == bg-fixed-child-mask.html bg-fixed-child-mask-ref.html skip-if(!asyncPan) == bg-fixed-in-opacity.html bg-fixed-in-opacity-ref.html skip-if(!asyncPan) == bg-fixed-child-no-culling-1.html bg-fixed-child-no-culling-1-ref.html skip-if(!asyncPan) == bg-fixed-child-no-culling-2.html bg-fixed-child-no-culling-2-ref.html diff --git a/layout/reftests/backgrounds/reftest.list b/layout/reftests/backgrounds/reftest.list index add344cad47f..51eb261c16ae 100644 --- a/layout/reftests/backgrounds/reftest.list +++ b/layout/reftests/backgrounds/reftest.list @@ -161,15 +161,15 @@ HTTP == background-referrer.html background-referrer-ref.html == attachment-local-clipping-color-3.html attachment-local-clipping-color-3-ref.html fuzzy-if(skiaContent,1,300) == attachment-local-clipping-color-4.html attachment-local-clipping-color-4-ref.html fuzzy-if(skiaContent,1,400) == attachment-local-clipping-color-5.html attachment-local-clipping-color-4-ref.html -fuzzy(50,500) fails-if(webrender) == attachment-local-clipping-color-6.html attachment-local-clipping-color-6-ref.html +fuzzy(50,500) fuzzy-if(skiaContent,51,320) fails-if(webrender) == attachment-local-clipping-color-6.html attachment-local-clipping-color-6-ref.html == attachment-local-clipping-image-1.html attachment-local-clipping-image-1-ref.html == attachment-local-clipping-image-2.html attachment-local-clipping-image-1-ref.html # Same ref as the previous test. == attachment-local-clipping-image-3.html attachment-local-clipping-image-3-ref.html # The next three tests are fuzzy due to bug 1128229. -fuzzy(16,69) fuzzy-if(skiaContent,64,1300) == attachment-local-clipping-image-4.html attachment-local-clipping-image-4-ref.html -fuzzy(16,69) fuzzy-if(skiaContent,64,1300) == attachment-local-clipping-image-5.html attachment-local-clipping-image-4-ref.html -fuzzy(80,500) fails-if(webrender) == attachment-local-clipping-image-6.html attachment-local-clipping-image-6-ref.html +fuzzy(16,69) fuzzy-if(skiaContent,95,2200) == attachment-local-clipping-image-4.html attachment-local-clipping-image-4-ref.html +fuzzy(16,69) fuzzy-if(skiaContent,95,2200) == attachment-local-clipping-image-5.html attachment-local-clipping-image-4-ref.html +fuzzy(80,500) fuzzy-if(skiaContent,100,908) fails-if(webrender) == attachment-local-clipping-image-6.html attachment-local-clipping-image-6-ref.html fuzzy-if(skiaContent,1,8) == background-multiple-with-border-radius.html background-multiple-with-border-radius-ref.html == background-repeat-large-area.html background-repeat-large-area-ref.html diff --git a/layout/reftests/border-radius/reftest.list b/layout/reftests/border-radius/reftest.list index d89e2ee69a12..4d96288db454 100644 --- a/layout/reftests/border-radius/reftest.list +++ b/layout/reftests/border-radius/reftest.list @@ -23,14 +23,14 @@ fuzzy-if(skiaContent,1,342) == percent-2.html percent-2-ref.html fuzzy-if(skiaContent,1,343) == percent-3.html percent-3-ref.html # more serious tests, using SVG reference -== border-circle-2.html border-circle-2-ref.xhtml -fuzzy-if(gtkWidget,14,280) fuzzy-if(cocoaWidget,4,582) fuzzy-if(Android,36,264) fuzzy-if(d2d,51,323) fuzzy-if(winWidget&&!d2d,16,377) fuzzy-if(skiaContent,52,377) == curved-stripe-border.html curved-stripe-border-ref.svg # bug 459945 +fuzzy-if(skiaContent,17,58) == border-circle-2.html border-circle-2-ref.xhtml +fuzzy-if(gtkWidget,14,280) fuzzy-if(cocoaWidget,4,582) fuzzy-if(Android,36,264) fuzzy-if(d2d,51,323) fuzzy-if(winWidget&&!d2d,16,377) fuzzy-if(skiaContent,63,398) == curved-stripe-border.html curved-stripe-border-ref.svg # bug 459945 # Corners -== corner-1.html corner-1-ref.svg # bottom corners different radius than top corners -fuzzy-if(gtkWidget,23,5) fuzzy-if(winWidget&&!d2d,23,5) fuzzy-if(d2d,32,8) fuzzy-if(Android,10,8) == corner-2.html corner-2-ref.svg # right corners different radius than left corners; see bug 500804 -fuzzy-if(gtkWidget,3,10) fuzzy-if(winWidget&&!d2d,3,10) fuzzy-if(d2d,15,32) fuzzy-if(Android,3,15) fuzzy-if(skiaContent,3,100) == corner-3.html corner-3-ref.svg -fuzzy-if(skiaContent,1,2728) == corner-4.html corner-4-ref.svg +fuzzy-if(skiaContent,17,47) == corner-1.html corner-1-ref.svg # bottom corners different radius than top corners +fuzzy-if(gtkWidget,23,5) fuzzy-if(winWidget&&!d2d,23,5) fuzzy-if(d2d,32,8) fuzzy-if(Android,10,8) fuzzy-if(skiaContent,18,49) == corner-2.html corner-2-ref.svg # right corners different radius than left corners; see bug 500804 +fuzzy-if(gtkWidget,3,10) fuzzy-if(winWidget&&!d2d,3,10) fuzzy-if(d2d,15,32) fuzzy-if(Android,3,15) fuzzy-if(skiaContent,18,90) == corner-3.html corner-3-ref.svg +fuzzy-if(skiaContent,12,83) == corner-4.html corner-4-ref.svg # Test that radii too long are reduced == border-reduce-height.html border-reduce-height-ref.html @@ -40,25 +40,25 @@ skip-if(!webrender) pref(layers.advanced.border-layers,1) == border-reduce-heigh fails-if(!stylo) == clipping-1.html clipping-1-ref.html # background color should completely fill box; bug 466572 != clipping-2.html about:blank # background color clipped to inner/outer border, can't get # great tests for this due to antialiasing problems described in bug 466572 -fuzzy-if(skiaContent,1,13) == clipping-3.html clipping-3-ref.xhtml # edge of border-radius clips an underlying object's background +fuzzy-if(skiaContent,17,62) == clipping-3.html clipping-3-ref.xhtml # edge of border-radius clips an underlying object's background # Tests for clipping the contents of replaced elements and overflow!=visible != clipping-4-ref.html clipping-4-notref.html fuzzy-if(true,1,20) fuzzy-if(d2d,64,196) fuzzy-if(cocoaWidget,1,180) fuzzy-if(Android,140,237) == clipping-4-canvas.html clipping-4-ref.html # bug 732535 -fuzzy-if(Android,5,54) fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,140) == clipping-4-image.html clipping-4-ref.html +fuzzy-if(Android,5,54) fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,172) == clipping-4-image.html clipping-4-ref.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,77) == clipping-4-overflow-hidden.html clipping-4-ref.html == clipping-5-canvas.html clipping-5-refc.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-image.html clipping-5-refi.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(skiaContent,1,77) == clipping-5-overflow-hidden.html clipping-5-ref.html -fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) fuzzy-if(skiaContent,1,77) == clipping-5-refi.html clipping-5-ref.html +fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) fuzzy-if(skiaContent,1,97) == clipping-5-refi.html clipping-5-ref.html fuzzy-if(true,1,7) fuzzy-if(d2d,48,94) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android,99,115) fuzzy-if(skiaContent,1,77) == clipping-5-refc.html clipping-5-ref.html # bug 732535 -fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,469) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical -fuzzy-if(true,2,29) fuzzy-if(d2d,46,50) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,19,29) fails-if(webrender) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures). +fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,469) fuzzy-if(skiaContent,7,58) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical +fuzzy-if(true,2,29) fuzzy-if(d2d,46,50) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,28,96) fails-if(webrender) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures). fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html fuzzy-if(cocoaWidget,1,4) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html == intersecting-clipping-1-image.html intersecting-clipping-1-refi.html == intersecting-clipping-1-overflow-hidden.html intersecting-clipping-1-ref.html -fuzzy-if(Android,5,105) fuzzy-if(d2d,1,20) fuzzy-if(skiaContent,1,250) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html +fuzzy-if(Android,5,105) fuzzy-if(d2d,1,20) fuzzy-if(skiaContent,1,300) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html fuzzy-if(true,1,33) fuzzy-if(d2d,48,350) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android,124,440) fuzzy-if(skiaContent,1,135) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535 # Inheritance @@ -79,7 +79,7 @@ fails-if(Android) == scrollbar-clamping-2.html scrollbar-clamping-2-ref.html fuzzy-if(true,1,1) == corner-joins-1.xhtml corner-joins-1-ref.xhtml fuzzy(255,20) random-if(winWidget) fuzzy-if(skiaContent,255,610) HTTP(..) == corner-joins-2.xhtml corner-joins-2-ref.xhtml -fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu),1,20) fuzzy-if(d2d,64,157) fuzzy-if(Android,166,400) fuzzy-if(skiaContent,64,70) == scroll-1.html scroll-1-ref.html # see bug 732535 #Bug 959166 +fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu),1,20) fuzzy-if(d2d,64,157) fuzzy-if(Android,166,400) fuzzy-if(skiaContent,58,145) == scroll-1.html scroll-1-ref.html # see bug 732535 #Bug 959166 == transforms-1.html transforms-1-ref.html diff --git a/layout/reftests/box-shadow/reftest.list b/layout/reftests/box-shadow/reftest.list index 374861de165a..7f8add9ca101 100644 --- a/layout/reftests/box-shadow/reftest.list +++ b/layout/reftests/box-shadow/reftest.list @@ -14,9 +14,9 @@ fails-if(Android) fuzzy-if(webrender,20,3310) == boxshadow-button.html boxshadow fuzzy-if(OSX==1010,1,24) fuzzy-if(d2d,16,908) fuzzy-if(webrender,19,1680) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649 fails-if(Android) == boxshadow-fileupload.html boxshadow-fileupload-ref.html -== boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg +fuzzy-if(skiaContent,13,28) == boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg random-if(layersGPUAccelerated) == boxshadow-mixed.html boxshadow-mixed-ref.html -random-if(d2d) == boxshadow-rounded-spread.html boxshadow-rounded-spread-ref.html +random-if(d2d) fuzzy-if(skiaContent,1,100) == boxshadow-rounded-spread.html boxshadow-rounded-spread-ref.html fuzzy-if(skiaContent,1,50) HTTP(..) == boxshadow-dynamic.xul boxshadow-dynamic-ref.xul random-if(d2d) == boxshadow-onecorner.html boxshadow-onecorner-ref.html random-if(d2d) == boxshadow-twocorners.html boxshadow-twocorners-ref.html diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index eb372bb1e9f5..ac560ad2d0aa 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -388,9 +388,9 @@ fuzzy-if(Android&&isDebugBuild,229,45) == 315920-13b.html 315920-13-ref.html # b == 315920-18b.html 315920-18-ref.html == 315920-18c.html 315920-18-ref.html == 315920-18d.html 315920-18-ref.html -fails-if(stylo) == 315920-18e.html 315920-18-ref.html -fails-if(stylo) == 315920-18f.html 315920-18-ref.html -fails-if(stylo) == 315920-18g.html 315920-18-ref.html +== 315920-18e.html 315920-18-ref.html +== 315920-18f.html 315920-18-ref.html +== 315920-18g.html 315920-18-ref.html == 315920-18h.html 315920-18-ref.html == 315920-18i.html 315920-18-ref.html == 315920-19.html 315920-19-ref.html @@ -1139,7 +1139,7 @@ fails-if(!stylo) == 428810-3e-rtl-insets.html 428810-empty-rtl-insets-ref.html # == 433700.html 433700-ref.html == 436356-1.html 436356-1-ref.html == 436356-2.html 436356-2-ref.html -== 438537-1.html 438537-1-ref.html +fuzzy-if(skiaContent,3,1) == 438537-1.html 438537-1-ref.html == 438981-1.xhtml about:blank == 438987-1.html 438987-1-ref.html fuzzy-if(skiaContent,1,3280) == 438987-2a.html 438987-2-ref.html @@ -1149,7 +1149,7 @@ fuzzy-if(skiaContent,1,3280) == 438987-2c.html 438987-2-ref.html == 439004-1.html 439004-1-ref.html == 439639-1.html 439639-1-ref.html == 439910.html 439910-ref.html -== 440112.html 440112-ref.html +fuzzy-if(skiaContent,1,1) == 440112.html 440112-ref.html == 440149-1.html 440149-1-ref.html == 441259-1.html 441259-1-ref.html fails-if(!stylo) == 441259-2.html 441259-2-ref.html # bug 441400 @@ -1197,9 +1197,9 @@ test-pref(dom.use_xbl_scopes_for_remote_xul,true) fails-if(stylo) != 449149-1b.h == 455280-1.xhtml 455280-1-ref.xhtml == 455826-1.html 455826-1-ref.html fails-if(cocoaWidget) fails-if(Android) == 456147.xul 456147-ref.html # bug 458047 -fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) == 456219-1a.html 456219-1-ref.html # bug 1128229 -fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) == 456219-1b.html 456219-1-ref.html # bug 1128229 -fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) == 456219-1c.html 456219-1-ref.html # bug 1128229 +fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) fuzzy-if(skiaContent,42,150) == 456219-1a.html 456219-1-ref.html # bug 1128229 +fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) fuzzy-if(skiaContent,42,150) == 456219-1b.html 456219-1-ref.html # bug 1128229 +fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) fuzzy-if(skiaContent,42,150) == 456219-1c.html 456219-1-ref.html # bug 1128229 fuzzy-if(skiaContent,1,45) == 456219-2.html 456219-2-ref.html fails-if(stylo) == 456330-1.gif 456330-1-ref.png == 456484-1.html 456484-1-ref.html @@ -1457,7 +1457,7 @@ fuzzy-if(skiaContent,1,50) == 526463-1.html 526463-1-ref.html fuzzy-if(Android,2,48) == 531200-1.html 531200-1-ref.html == 531371-1.html 531371-1-ref.html == 534526-1a.html 534526-1-ref.html -fails-if(stylo) == 534526-1b.html 534526-1-ref.html +== 534526-1b.html 534526-1-ref.html == 534804-1.html 534804-1-ref.html == 534808-1.html 534808-1-ref.html == 534808-2.html 534808-2-ref.html @@ -1664,7 +1664,7 @@ HTTP(..) == 635639-1.html 635639-1-ref.html HTTP(..) == 635639-2.html 635639-2-ref.html random == 637597-1.html 637597-1-ref.html # bug 637597 was never really fixed! fuzzy-if(Android,8,500) == 637852-1.html 637852-1-ref.html -fuzzy-if(Android,8,500) == 637852-2.html 637852-2-ref.html +fuzzy-if(Android,8,500) fuzzy-if(skiaContent,2,1) == 637852-2.html 637852-2-ref.html fuzzy-if(Android,8,500) == 637852-3.html 637852-3-ref.html == 641770-1.html 641770-1-ref.html == 641856-1.html 641856-1-ref.html @@ -1729,12 +1729,12 @@ fuzzy-if(cocoaWidget,1,300000) fuzzy-if(skiaContent,2,300000) == 745934-1.html 7 == 748692-1b.html 748692-1-ref.html == 748803-1.html 748803-1-ref.html == 750551-1.html 750551-1-ref.html -fails-if(stylo) == 751012-1a.html 751012-1-ref.html -fails-if(stylo) == 751012-1b.html 751012-1-ref.html +fuzzy-if(skiaContent,1,1) fails-if(stylo) == 751012-1a.html 751012-1-ref.html +fuzzy-if(skiaContent,1,1) fails-if(stylo) == 751012-1b.html 751012-1-ref.html random-if(Android) == 753329-1.html about:blank == 758561-1.html 758561-1-ref.html fuzzy-if(true,1,90) fuzzy-if(skiaContent,1,320) == 759036-1.html 759036-1-ref.html -fuzzy-if(true,17,5886) == 759036-2.html 759036-2-ref.html +fuzzy-if(true,17,5886) fuzzy-if(skiaContent,9,5894) == 759036-2.html 759036-2-ref.html fails-if(stylo) == 776265-1a.html 776265-1-ref.html fails-if(stylo) == 776265-1b.html 776265-1-ref.html fails-if(stylo) == 776265-1c.html 776265-1-ref.html @@ -1937,7 +1937,7 @@ skip-if(!Android) fails-if(Android) fails-if(stylo) == 1133905-6-vh-rtl.html 113 == 1151306-1.html 1151306-1-ref.html == 1153845-1.html 1153845-1-ref.html == 1155828-1.html 1155828-1-ref.html -== 1156129-1.html 1156129-1-ref.html +fuzzy-if(skiaContent,7,84) == 1156129-1.html 1156129-1-ref.html pref(dom.use_xbl_scopes_for_remote_xul,true) HTTP(..) == 1157127-1.html 1157127-1-ref.html fuzzy-if(Android,6,6) == 1169331-1.html 1169331-1-ref.html fuzzy(1,74) fails-if(gtkWidget&&!stylo) == 1174332-1.html 1174332-1-ref.html # bug 1312658 @@ -1945,7 +1945,7 @@ fuzzy(1,74) fails-if(gtkWidget&&!stylo) == 1174332-1.html 1174332-1-ref.html # b == 1179288-1.html 1179288-1-ref.html == 1190635-1.html 1190635-1-ref.html == 1202512-1.html 1202512-1-ref.html -== 1202512-2.html 1202512-2-ref.html +fuzzy-if(skiaContent,1,1) == 1202512-2.html 1202512-2-ref.html != 1207326-1.html about:blank == 1209603-1.html 1209603-1-ref.html == 1209994-1.html 1209994-1-ref.html diff --git a/layout/reftests/canvas/reftest.list b/layout/reftests/canvas/reftest.list index af26c29a2073..b4f004ab7beb 100644 --- a/layout/reftests/canvas/reftest.list +++ b/layout/reftests/canvas/reftest.list @@ -94,13 +94,13 @@ fuzzy-if(azureSkia,1,15) fuzzy-if(skiaContent,1,20) == transformed-gradient.html == 749467-1.html 749467-1-ref.html # You get a little bit of rounding fuzz on OSX from transforming the paths between user space and device space -fuzzy-if(d2d,12,21) fuzzy-if(skiaContent,12,7) fuzzy-if(d2d&&/^Windows\x20NT\x2010\.0/.test(http.oscpu),2,141) == 784573-1.html 784573-1-ref.html +fuzzy-if(d2d,12,21) fuzzy-if(skiaContent,16,84) fuzzy-if(d2d&&/^Windows\x20NT\x2010\.0/.test(http.oscpu),2,141) == 784573-1.html 784573-1-ref.html == 802658-1.html 802658-1-ref.html == 1074733-1.html 1074733-1-ref.html == 1107096-invisibles.html 1107096-invisibles-ref.html == 1151821-1.html 1151821-1-ref.html -== 1201272-1.html 1201272-1-ref.html +fuzzy-if(skiaContent,1,43) == 1201272-1.html 1201272-1-ref.html == 1224976-1.html 1224976-1-ref.html == 1238795-1.html 1238795-1-ref.html == 1303534-1.html 1303534-1-ref.html diff --git a/layout/reftests/css-break/reftest.list b/layout/reftests/css-break/reftest.list index 28f60935b9c0..1c9a70509cab 100644 --- a/layout/reftests/css-break/reftest.list +++ b/layout/reftests/css-break/reftest.list @@ -2,7 +2,7 @@ default-preferences pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-1.html box-decoration-break-1-ref.html fuzzy(1,20) fuzzy-if(skiaContent,1,700) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html -fuzzy(16,460) fuzzy-if(Android,10,3673) fuzzy-if(skiaContent,32,254) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html +fuzzy(16,460) fuzzy-if(Android,10,3673) fuzzy-if(skiaContent,57,374) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html random-if(!gtkWidget) HTTP(..) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html == box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html diff --git a/layout/reftests/forms/input/color/reftest.list b/layout/reftests/forms/input/color/reftest.list index b48eb4e96e69..e1b86b6c637e 100644 --- a/layout/reftests/forms/input/color/reftest.list +++ b/layout/reftests/forms/input/color/reftest.list @@ -9,6 +9,6 @@ default-preferences pref(dom.forms.color,true) fails-if(Android) fails-if(stylo) == margin-padding-1.html margin-padding-1-ref.html fails-if(stylo) == block-invalidate-1.html block-invalidate-1-ref.html fails-if(stylo) == block-invalidate-2.html block-invalidate-2-ref.html -fuzzy-if(gtkWidget,8,33) fuzzy-if(skiaContent,8,35) fails-if(Android) fails-if(stylo) == transformations-1.html transformations-1-ref.html +fuzzy-if(gtkWidget,8,33) fuzzy-if(skiaContent,8,78) fails-if(Android) fails-if(stylo) == transformations-1.html transformations-1-ref.html pref(layout.css.moz-appearance.enabled,true) fails-if(Android) fails-if(stylo) == custom-style-1.html custom-style-1-ref.html fails-if(Android) fails-if(stylo) == custom-style-2.html custom-style-2-ref.html diff --git a/layout/reftests/forms/input/number/reftest.list b/layout/reftests/forms/input/number/reftest.list index 5f95378dbc7d..d2a3690ed596 100644 --- a/layout/reftests/forms/input/number/reftest.list +++ b/layout/reftests/forms/input/number/reftest.list @@ -39,7 +39,7 @@ pref(layout.css.moz-appearance.enabled,true) skip-if(Android) == number-max-heig fuzzy-if(skiaContent,2,5) needs-focus skip-if(stylo) == focus-handling.html focus-handling-ref.html # select -skip-if(stylo) == number-selected.html number-selected-ref.html +fuzzy-if(skiaContent,1,1) skip-if(stylo) == number-selected.html number-selected-ref.html # pseudo-elements not usable from content: fails-if(stylo) == number-pseudo-elements.html number-pseudo-elements-ref.html diff --git a/layout/reftests/forms/reftest.list b/layout/reftests/forms/reftest.list index 55e72aecbbf0..c3c2c1f9fb2a 100644 --- a/layout/reftests/forms/reftest.list +++ b/layout/reftests/forms/reftest.list @@ -3,7 +3,7 @@ fuzzy-if(cocoaWidget,16,64) fuzzy-if(Android,52,64) fuzzy-if(/^Windows\x20NT\x20 == display-block-baselines-2.html display-block-baselines-2-ref.html fails-if(stylo) == display-block-baselines-3.html display-block-baselines-3-ref.html fails-if(stylo) == display-block-baselines-4.html display-block-baselines-4-ref.html -fuzzy-if(Android,4,8) fails-if(stylo) == display-block-baselines-5.html display-block-baselines-5-ref.html +fuzzy-if(Android,4,8) fuzzy-if(skiaContent,7,2) fails-if(stylo) == display-block-baselines-5.html display-block-baselines-5-ref.html # button element include button/reftest.list diff --git a/layout/reftests/forms/select/reftest.list b/layout/reftests/forms/select/reftest.list index 971df2b6ecef..110da6c11d36 100644 --- a/layout/reftests/forms/select/reftest.list +++ b/layout/reftests/forms/select/reftest.list @@ -6,7 +6,7 @@ fuzzy-if(Android,4,11) == out-of-bounds-selectedindex.html out-of-bounds-selecte fuzzy(1,4) == padding-button-placement.html padding-button-placement-ref.html HTTP(../..) == vertical-centering.html vertical-centering-ref.html == 997709-2.html 997709-2-ref.html -needs-focus == focusring-1.html focusring-1-ref.html +fuzzy-if(skiaContent,4,1) needs-focus == focusring-1.html focusring-1-ref.html needs-focus == focusring-2.html focusring-2-ref.html needs-focus == focusring-3.html focusring-3-ref.html == dynamic-text-indent-1.html dynamic-text-indent-1-ref.html diff --git a/layout/reftests/forms/textarea/reftest.list b/layout/reftests/forms/textarea/reftest.list index 6de9e50fa035..b7c7a6792fda 100644 --- a/layout/reftests/forms/textarea/reftest.list +++ b/layout/reftests/forms/textarea/reftest.list @@ -6,8 +6,8 @@ skip-if(Android) != ltr-scrollbar.html rtl-scrollbar.html skip-if(Android) != in-ltr-doc-scrollbar.html in-rtl-doc-scrollbar.html skip-if(Android) fails-if(stylo) != ltr.html no-resize.html skip-if(Android) fails-if(xulRuntime.widgetToolkit=="gtk2") fails-if(stylo) != rtl.html no-resize.html # bug 834724 -fails-if(stylo) == rtl.html rtl-dynamic-attr.html -fails-if(stylo) == rtl.html rtl-dynamic-style.html +fuzzy-if(skiaContent,1,1) fails-if(stylo) == rtl.html rtl-dynamic-attr.html +fuzzy-if(skiaContent,1,1) fails-if(stylo) == rtl.html rtl-dynamic-style.html fails-if(stylo) == rtl.html in-dynamic-rtl-doc.html fuzzy-if(skiaContent,1,3) fails-if(stylo) == setvalue-framereconstruction-1.html setvalue-framereconstruction-ref.html fuzzy-if(asyncPan&&!layersGPUAccelerated,102,4168) fails-if(stylo) == padding-scrollbar-placement.html padding-scrollbar-placement-ref.html diff --git a/layout/reftests/image-element/reftest.list b/layout/reftests/image-element/reftest.list index 07a7574a7685..da48e7aa3690 100644 --- a/layout/reftests/image-element/reftest.list +++ b/layout/reftests/image-element/reftest.list @@ -17,7 +17,7 @@ fuzzy-if(d2d&&/^Windows\x20NT\x206\.1/.test(http.oscpu),16,90) == element-paint- == element-paint-background-size-02.html element-paint-background-size-02-ref.html fuzzy-if(skiaContent,255,4) == element-paint-transform-repeated.html element-paint-transform-repeated-ref.html fuzzy-if(d2d,255,24) == element-paint-transform-03.html element-paint-transform-03-ref.html -fuzzy-if(asyncPan,2,140) fuzzy-if(skiaContent,2,106) == element-paint-native-widget.html element-paint-native-widget-ref.html # in -ref the scrollframe is active and layerized differently with APZ +fuzzy-if(asyncPan,2,140) fuzzy-if(skiaContent,3,106) == element-paint-native-widget.html element-paint-native-widget-ref.html # in -ref the scrollframe is active and layerized differently with APZ fails-if(usesRepeatResampling) == element-paint-subimage-sampling-restriction.html about:blank == element-paint-clippath.html element-paint-clippath-ref.html == element-paint-sharpness-01a.html element-paint-sharpness-01b.html diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index 9c1164b3e35a..a10782abd10e 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -319,7 +319,7 @@ fuzzy-if(skiaContent,1,10000) == opacity-and-transform-01.svg opacity-and-transf fuzzy-if(Android,8,200) == outer-svg-border-and-padding-01.svg outer-svg-border-and-padding-01-ref.svg -fails-if(stylo) == outline.html outline-ref.html +fuzzy-if(skiaContent,7,175) fuzzy-if(skiaContent&&webrender,1,225) fails-if(stylo) == outline.html outline-ref.html == overflow-on-outer-svg-01.svg overflow-on-outer-svg-01-ref.svg == overflow-on-outer-svg-02a.xhtml overflow-on-outer-svg-02-ref.xhtml diff --git a/layout/reftests/svg/smil/transform/reftest.list b/layout/reftests/svg/smil/transform/reftest.list index 9085b49f4be2..046c42e374f3 100644 --- a/layout/reftests/svg/smil/transform/reftest.list +++ b/layout/reftests/svg/smil/transform/reftest.list @@ -4,14 +4,14 @@ fuzzy(111,1802) fuzzy-if(skiaContent,130,1000) == additive-1.svg additive-1-ref.svg # bug 981344, bug 1239766 == animate-width-1.svg lime.svg fuzzy-if(cocoaWidget,1,32) fuzzy-if(winWidget,15,30) fuzzy-if(gtkWidget,1,30) == paced-1.svg paced-1-ref.svg # bug 981640, Bug 1293550 -fuzzy-if(skiaContent,1,220) == rotate-angle-1.svg rotate-angle-ref.svg -== rotate-angle-2.svg rotate-angle-ref.svg -fuzzy-if(skiaContent,1,130) == rotate-angle-3.svg rotate-angle-ref.svg -fuzzy-if(skiaContent,1,110) == rotate-angle-4.svg rotate-angle-ref.svg +fuzzy-if(skiaContent,7,90) == rotate-angle-1.svg rotate-angle-ref.svg +fuzzy-if(skiaContent,7,90) == rotate-angle-2.svg rotate-angle-ref.svg +fuzzy-if(skiaContent,7,130) == rotate-angle-3.svg rotate-angle-ref.svg +fuzzy-if(skiaContent,7,90) == rotate-angle-4.svg rotate-angle-ref.svg fuzzy-if(skiaContent,1,130) == rotate-angle-5.svg rotate-angle-ref.svg fuzzy(12,27) fuzzy-if(skiaContent,1,180) fuzzy-if(Android,16,3) == scale-1.svg scale-1-ref.svg # bug 981004 == set-transform-1.svg lime.svg -fuzzy-if(winWidget||gtkWidget||OSX,1,27) fuzzy-if(Android&&skiaContent,1,20) == skew-1.svg skew-1-ref.svg # bug 983671, Bug 1260629 +fuzzy-if(winWidget||gtkWidget||OSX,1,27) fuzzy-if(skiaContent,7,1548) == skew-1.svg skew-1-ref.svg # bug 983671, Bug 1260629 == translate-clipPath-1.svg lime.svg == translate-gradient-1.svg lime.svg == translate-pattern-1.svg lime.svg diff --git a/layout/reftests/svg/svg-integration/clip-path/reftest.list b/layout/reftests/svg/svg-integration/clip-path/reftest.list index e69eca1136a0..b7a50a91f123 100644 --- a/layout/reftests/svg/svg-integration/clip-path/reftest.list +++ b/layout/reftests/svg/svg-integration/clip-path/reftest.list @@ -16,7 +16,7 @@ default-preferences pref(layout.css.clip-path-shapes.enabled,true) == clip-path-polygon-010.html clip-path-stripes-001-ref.html == clip-path-polygon-011.html clip-path-stripes-001-ref.html == clip-path-polygon-012.html clip-path-stripes-001-ref.html -== clip-path-polygon-013.html clip-path-stripes-003-ref.html +fuzzy-if(skiaContent,1,20) == clip-path-polygon-013.html clip-path-stripes-003-ref.html == clip-path-circle-001.html clip-path-circle-001-ref.html == clip-path-circle-002.html clip-path-circle-001-ref.html diff --git a/layout/reftests/svg/text/reftest.list b/layout/reftests/svg/text/reftest.list index 8e678fb51f7e..152d7b5a3ac6 100644 --- a/layout/reftests/svg/text/reftest.list +++ b/layout/reftests/svg/text/reftest.list @@ -181,7 +181,7 @@ fuzzy-if(skiaContent&&winWidget,105,56) HTTP(../..) == clipPath-content.svg clip fuzzy-if(skiaContent&&winWidget,53,112) HTTP(../..) == clipPath-content-2.svg clipPath-content-2-ref.svg # text and patterns -fuzzy-if(cocoaWidget,1,6) == pattern-content.svg pattern-content-ref.svg +fuzzy-if(cocoaWidget,1,6) fuzzy-if(skiaContent,65,313) == pattern-content.svg pattern-content-ref.svg # text and filters fuzzy-if(skiaContent&&winWidget,126,336) HTTP(../..) == filter-applied.svg filter-applied-ref.svg diff --git a/layout/reftests/transform/reftest.list b/layout/reftests/transform/reftest.list index 91e5699f31b2..186f20b4634d 100644 --- a/layout/reftests/transform/reftest.list +++ b/layout/reftests/transform/reftest.list @@ -140,4 +140,4 @@ pref(svg.transform-box.enabled,true) == transform-box-svg-3a.svg pass.svg == animate-layer-scale-inherit-3.html animate-layer-scale-inherit-1-ref.html # Bug 1301500 == dynamic-add-without-change-cb-1.html dynamic-add-without-change-cb-1-ref.html -fuzzy-if(d2d,1,5) == table-overflowed-by-animation.html table-overflowed-by-animation-ref.html +fuzzy-if(d2d,1,5) fuzzy-if(skiaContent,22,180) == table-overflowed-by-animation.html table-overflowed-by-animation-ref.html diff --git a/layout/reftests/w3c-css/submitted/masking/reftest.list b/layout/reftests/w3c-css/submitted/masking/reftest.list index d4843d2e3eb4..4a9ca8335a85 100644 --- a/layout/reftests/w3c-css/submitted/masking/reftest.list +++ b/layout/reftests/w3c-css/submitted/masking/reftest.list @@ -27,7 +27,7 @@ fuzzy-if(skiaContent||winWidget,1,43) == mask-image-3d.html mask-image-3-ref.htm == mask-image-3e.html mask-image-3-ref.html fuzzy-if(skiaContent||winWidget,50,85) == mask-image-3f.html mask-image-3-ref.html fuzzy-if(skiaContent||winWidget,50,85) == mask-image-3g.html mask-image-3-ref.html -pref(layout.css.clip-path-shapes.enabled,true) fuzzy-if(skiaContent||winWidget,1,3) == mask-image-3h.html mask-image-3-ref.html +pref(layout.css.clip-path-shapes.enabled,true) fuzzy-if(winWidget,1,3) fuzzy-if(skiaContent,2,12) == mask-image-3h.html mask-image-3-ref.html fuzzy-if(skiaContent,71,203) == mask-image-3i.html mask-image-3-ref.html == mask-image-4a.html blank.html == mask-image-4b.html blank.html @@ -86,21 +86,21 @@ fails-if(!stylo) == mask-origin-2.html mask-origin-2-ref.html # bug 1260094 default-preferences pref(layout.css.clip-path-shapes.enabled,true) -fuzzy-if(winWidget,1,21) == clip-path-contentBox-1a.html clip-path-geometryBox-1-ref.html -fuzzy-if(winWidget,1,21) == clip-path-contentBox-1b.html clip-path-geometryBox-1-ref.html -fuzzy-if(winWidget,1,21) == clip-path-contentBox-1c.html clip-path-geometryBox-1-ref.html -fuzzy-if(winWidget,1,21) == clip-path-paddingBox-1a.html clip-path-geometryBox-1-ref.html -fuzzy-if(winWidget,1,21) == clip-path-paddingBox-1b.html clip-path-geometryBox-1-ref.html -fuzzy-if(winWidget,1,21) == clip-path-paddingBox-1c.html clip-path-geometryBox-1-ref.html +fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-contentBox-1a.html clip-path-geometryBox-1-ref.html +fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-contentBox-1b.html clip-path-geometryBox-1-ref.html +fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-contentBox-1c.html clip-path-geometryBox-1-ref.html +fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-paddingBox-1a.html clip-path-geometryBox-1-ref.html +fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-paddingBox-1b.html clip-path-geometryBox-1-ref.html +fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-paddingBox-1c.html clip-path-geometryBox-1-ref.html fuzzy(64,370) == clip-path-borderBox-1a.html clip-path-geometryBox-1-ref.html -fuzzy-if(winWidget,1,21) == clip-path-borderBox-1b.html clip-path-geometryBox-1-ref.html +fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-borderBox-1b.html clip-path-geometryBox-1-ref.html fuzzy(64,370) == clip-path-borderBox-1c.html clip-path-geometryBox-1-ref.html -fuzzy-if(winWidget,1,21) == clip-path-marginBox-1a.html clip-path-geometryBox-1-ref.html +fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-marginBox-1a.html clip-path-geometryBox-1-ref.html fuzzy(64,370) == clip-path-fillBox-1a.html clip-path-geometryBox-1-ref.html fuzzy(64,370) == clip-path-strokeBox-1a.html clip-path-geometryBox-1-ref.html fuzzy(64,370) == clip-path-strokeBox-1b.html clip-path-geometryBox-1-ref.html -fuzzy-if(winWidget,1,21) == clip-path-viewBox-1a.html clip-path-geometryBox-1-ref.html -fuzzy-if(winWidget,1,21) == clip-path-viewBox-1b.html clip-path-geometryBox-1-ref.html +fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-viewBox-1a.html clip-path-geometryBox-1-ref.html +fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-viewBox-1b.html clip-path-geometryBox-1-ref.html fuzzy(64,370) == clip-path-viewBox-1c.html clip-path-geometryBox-1-ref.html fuzzy-if(winWidget,9,98) == clip-path-geometryBox-2.html clip-path-geometryBox-2-ref.html diff --git a/layout/style/ServoBindings.cpp b/layout/style/ServoBindings.cpp index a50a3af44d86..c0051623a756 100644 --- a/layout/style/ServoBindings.cpp +++ b/layout/style/ServoBindings.cpp @@ -797,7 +797,7 @@ AttrHasSubstring(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName, auto match = [aStr](const nsAttrValue* aValue) { nsAutoString str; aValue->ToString(str); - return FindInReadable(str, nsDependentAtomString(aStr)); + return FindInReadable(nsDependentAtomString(aStr), str); }; return DoMatch(aElement, aNS, aName, match); } diff --git a/layout/style/test/test_selectors.html b/layout/style/test/test_selectors.html index 0237e02cb274..94e54ee7bde7 100644 --- a/layout/style/test/test_selectors.html +++ b/layout/style/test/test_selectors.html @@ -395,6 +395,51 @@ function run() { test_balanced_unparseable("[attr*=]"); test_balanced_unparseable("[attr*=foo bar]"); + // And now tests for correctness of matching of attr selectors. + var attrTestBody = + // Paragraphs 1-5 + "

" + + // Paragraphs 6-8 + "

" + + // Paragraphs 9-10 + "

" + + // Paragraphs 11-12 + "

" + + // Paragraph 13-15 + "

"; + test_selector_in_html( + "[attr]", attrTestBody, + pset([1,2,3,6,7,8,9,10,11,12,13,14,15]), pset([4,5])); + test_selector_in_html( + "[attr=foo]", attrTestBody, + pset([3]), pset([1,2,4,5,6,7,8,9,10,11,12,13,14,15])); + test_selector_in_html( + "[attr~=foo]", attrTestBody, + pset([3,6,9,13]), pset([1,2,4,5,7,8,10,11,12,14,15])); + test_selector_in_html( + "[attr~=bar]", attrTestBody, + pset([6,9,15]), pset([1,2,3,4,5,7,8,10,11,12,13,14])); + test_selector_in_html( + "[attr~=baz]", attrTestBody, + pset([9,11]), pset([1,2,3,4,5,6,7,8,10,12,13,14,15])); + test_selector_in_html( + "[attr|=foo]", attrTestBody, + pset([3,7,10,11]), pset([1,2,4,5,6,8,9,12,13,14,15])); + test_selector_in_html( + "[attr|='bar baz']", attrTestBody, + pset([15]), pset([1,2,3,4,5,6,7,8,9,10,11,12,13,14])); + test_selector_in_html( + "[attr$=foo]", attrTestBody, + pset([3,15]), pset([1,2,4,5,6,7,8,9,10,11,12,13,14])); + test_selector_in_html( + "[attr$=bar]", attrTestBody, + pset([6,7,8]), pset([1,2,3,4,5,9,10,11,12,13,14,15])); + test_selector_in_html( + "[attr^=foo]", attrTestBody, + pset([3,6,7,8,9,10,11]), pset([1,2,4,5,12,13,14,15])); + test_selector_in_html( + "[attr*=foo]", attrTestBody, + pset([3,6,7,8,9,10,11,12,13,15]), pset([1,2,4,5,14])); // Bug 420814 test_selector_in_html( diff --git a/netwerk/base/nsIPermissionManager.idl b/netwerk/base/nsIPermissionManager.idl index 32605c504df6..1327ae421da0 100644 --- a/netwerk/base/nsIPermissionManager.idl +++ b/netwerk/base/nsIPermissionManager.idl @@ -343,6 +343,12 @@ interface nsIPermissionManager : nsISupports */ void whenPermissionsAvailable(in nsIPrincipal aPrincipal, in nsIRunnable aRunnable); + + /** + * True if any "preload" permissions are present. This is used to avoid making + * potentially expensive permissions checks in nsContentBlocker. + */ + [infallible] readonly attribute boolean hasPreloadPermissions; }; %{ C++ diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 2f4dac8b952c..7cea743c950c 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -271,6 +271,12 @@ HttpBaseChannel::Init(nsIURI *aURI, NS_PRECONDITION(aURI, "null uri"); +#ifdef DEBUG + typedef nsHttpRequestHead::AutoEnableCallingSetHeaderNonThreadSafe + AutoEnableCallingSetHeaderNonThreadSafe; + AutoEnableCallingSetHeaderNonThreadSafe enabler(&mRequestHead); +#endif + mURI = aURI; mOriginalURI = aURI; mDocumentURI = nullptr; @@ -311,7 +317,8 @@ HttpBaseChannel::Init(nsIURI *aURI, rv = nsHttpHandler::GenerateHostPort(host, port, hostLine); if (NS_FAILED(rv)) return rv; - rv = mRequestHead.SetHeader(nsHttp::Host, hostLine); + rv = mRequestHead.SetHeaderNonThreadSafe(nsHttp::Host, hostLine, false, + nsHttpHeaderArray::eVarietyRequestDefault); if (NS_FAILED(rv)) return rv; rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS); diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index a299bf02c8d6..c7640a9ce2e8 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -532,19 +532,24 @@ nsHttpHandler::InitConnectionMgr() nsresult nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request, bool isSecure) { + // This method only gets called during the initialization of the HTTP channel, + // so we don't need to hold any locks when setting the headers on the request + // head object. Therefore the usage of the SetHeaderNonThreadSafe here is safe. + nsresult rv; // Add the "User-Agent" header - rv = request->SetHeader(nsHttp::User_Agent, UserAgent(), - false, nsHttpHeaderArray::eVarietyRequestDefault); + rv = request->SetHeaderNonThreadSafe(nsHttp::User_Agent, UserAgent(), + false, + nsHttpHeaderArray::eVarietyRequestDefault); if (NS_FAILED(rv)) return rv; // MIME based content negotiation lives! // Add the "Accept" header. Note, this is set as an override because the // service worker expects to see it. The other "default" headers are // hidden from service worker interception. - rv = request->SetHeader(nsHttp::Accept, mAccept, - false, nsHttpHeaderArray::eVarietyRequestOverride); + rv = request->SetHeaderNonThreadSafe(nsHttp::Accept, mAccept, + false, nsHttpHeaderArray::eVarietyRequestOverride); if (NS_FAILED(rv)) return rv; // Add the "Accept-Language" header. This header is also exposed to the @@ -556,29 +561,29 @@ nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request, bool isSecu // Add the "Accept-Language" header if (!mAcceptLanguages.IsEmpty()) { - rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages, - false, - nsHttpHeaderArray::eVarietyRequestOverride); + rv = request->SetHeaderNonThreadSafe(nsHttp::Accept_Language, mAcceptLanguages, + false, + nsHttpHeaderArray::eVarietyRequestOverride); if (NS_FAILED(rv)) return rv; } // Add the "Accept-Encoding" header if (isSecure) { - rv = request->SetHeader(nsHttp::Accept_Encoding, mHttpsAcceptEncodings, - false, - nsHttpHeaderArray::eVarietyRequestDefault); + rv = request->SetHeaderNonThreadSafe(nsHttp::Accept_Encoding, mHttpsAcceptEncodings, + false, + nsHttpHeaderArray::eVarietyRequestDefault); } else { - rv = request->SetHeader(nsHttp::Accept_Encoding, mHttpAcceptEncodings, - false, - nsHttpHeaderArray::eVarietyRequestDefault); + rv = request->SetHeaderNonThreadSafe(nsHttp::Accept_Encoding, mHttpAcceptEncodings, + false, + nsHttpHeaderArray::eVarietyRequestDefault); } if (NS_FAILED(rv)) return rv; // add the "Send Hint" header if (mSafeHintEnabled || mParentalControlEnabled) { - rv = request->SetHeader(nsHttp::Prefer, NS_LITERAL_CSTRING("safe"), - false, - nsHttpHeaderArray::eVarietyRequestDefault); + rv = request->SetHeaderNonThreadSafe(nsHttp::Prefer, NS_LITERAL_CSTRING("safe"), + false, + nsHttpHeaderArray::eVarietyRequestDefault); if (NS_FAILED(rv)) return rv; } return NS_OK; diff --git a/netwerk/protocol/http/nsHttpRequestHead.cpp b/netwerk/protocol/http/nsHttpRequestHead.cpp index f2ef237e42e9..d20315909d34 100644 --- a/netwerk/protocol/http/nsHttpRequestHead.cpp +++ b/netwerk/protocol/http/nsHttpRequestHead.cpp @@ -164,6 +164,25 @@ nsHttpRequestHead::SetHeader(nsHttpAtom h, const nsACString &v, bool m, { ReentrantMonitorAutoEnter mon(mReentrantMonitor); +#ifdef DEBUG + AutoEnableCallingSetHeaderNonThreadSafe enabler(this); +#endif + + return SetHeaderNonThreadSafe(h, v, m, variety); +} + + +// This function is designed to only be called during the creation of this +// object, and doesn't grab the lock of the object before setting the header. +// Please do not use it if you are not sure why you need it. +nsresult +nsHttpRequestHead::SetHeaderNonThreadSafe(nsHttpAtom h, + const nsACString &v, + bool m, + nsHttpHeaderArray::HeaderVariety variety) +{ + MOZ_ASSERT(mCanCallSetHeaderNonThreadSafe); + if (mInVisitHeaders) { return NS_ERROR_FAILURE; } diff --git a/netwerk/protocol/http/nsHttpRequestHead.h b/netwerk/protocol/http/nsHttpRequestHead.h index a2041ab67f15..e9c188cf62dc 100644 --- a/netwerk/protocol/http/nsHttpRequestHead.h +++ b/netwerk/protocol/http/nsHttpRequestHead.h @@ -15,6 +15,9 @@ class nsIHttpHeaderVisitor; namespace mozilla { namespace net { +class nsHttpHandler; +class HttpBaseChannel; + //----------------------------------------------------------------------------- // nsHttpRequestHead represents the request line and headers from an HTTP // request. @@ -104,6 +107,40 @@ public: bool IsPut() { return EqualsMethod(kMethod_Put); } bool IsTrace() { return EqualsMethod(kMethod_Trace); } void ParseHeaderSet(const char *buffer); + +private: + friend class mozilla::net::nsHttpHandler; + friend class mozilla::net::HttpBaseChannel; + // This function is designed to only be called during the + // creation of this object, and doesn't grab the lock of the + // object before setting the header. Please do not use it if + // you are not sure why you need it. + MOZ_MUST_USE nsresult SetHeaderNonThreadSafe(nsHttpAtom h, + const nsACString &v, + bool m, + nsHttpHeaderArray::HeaderVariety variety); + +#ifdef DEBUG + // This helper class is used to enable calling the SetHeaderNonThreadSafe() function from + // the callers that we want. + class MOZ_RAII AutoEnableCallingSetHeaderNonThreadSafe final + { + public: + explicit AutoEnableCallingSetHeaderNonThreadSafe(nsHttpRequestHead* aSelf) + : mSelf(aSelf) + { + mSelf->mCanCallSetHeaderNonThreadSafe = true; + } + ~AutoEnableCallingSetHeaderNonThreadSafe() + { + mSelf->mCanCallSetHeaderNonThreadSafe = true; + } + + private: + nsHttpRequestHead* mSelf; + }; +#endif + private: // All members must be copy-constructable and assignable nsHttpHeaderArray mHeaders; @@ -125,6 +162,12 @@ private: // During VisitHeader we sould not allow cal to SetHeader. bool mInVisitHeaders; + +#ifdef DEBUG + // Calls to SetHeaderNonThreadSafe can either be made through HttpBaseChannel::Init() + // or through the SetHeader method. + bool mCanCallSetHeaderNonThreadSafe; +#endif }; } // namespace net diff --git a/other-licenses/skia-npapi/ANPCanvas.cpp b/other-licenses/skia-npapi/ANPCanvas.cpp index dd227eca8dfe..f0983b9f1133 100644 --- a/other-licenses/skia-npapi/ANPCanvas.cpp +++ b/other-licenses/skia-npapi/ANPCanvas.cpp @@ -80,7 +80,7 @@ static void anp_getTotalMatrix(ANPCanvas* canvas, ANPMatrix* matrix) { static bool anp_getLocalClipBounds(ANPCanvas* canvas, ANPRectF* r, bool antialias) { SkRect bounds; - if (canvas->skcanvas->getClipBounds(&bounds)) { + if (canvas->skcanvas->getLocalClipBounds(&bounds)) { SkANP::SetRect(r, bounds); return true; } @@ -89,7 +89,7 @@ static bool anp_getLocalClipBounds(ANPCanvas* canvas, ANPRectF* r, static bool anp_getDeviceClipBounds(ANPCanvas* canvas, ANPRectI* r) { SkIRect bounds; - if (canvas->skcanvas->getClipDeviceBounds(&bounds)) { + if (canvas->skcanvas->getDeviceClipBounds(&bounds)) { SkANP::SetRect(r, bounds); return true; } diff --git a/other-licenses/skia-npapi/SkANP.h b/other-licenses/skia-npapi/SkANP.h index 5c2a936501b8..5796957f80b8 100644 --- a/other-licenses/skia-npapi/SkANP.h +++ b/other-licenses/skia-npapi/SkANP.h @@ -56,11 +56,10 @@ struct ANPCanvas { // redirect all drawing to the specific SkCanvas explicit ANPCanvas(SkCanvas* other) { skcanvas = other; - skcanvas->ref(); } ~ANPCanvas() { - skcanvas->unref(); + delete skcanvas; } }; diff --git a/testing/config/tooltool-manifests/linux64/geckodriver.manifest b/testing/config/tooltool-manifests/linux64/geckodriver.manifest index a6a4122f1d94..89a256202066 100644 --- a/testing/config/tooltool-manifests/linux64/geckodriver.manifest +++ b/testing/config/tooltool-manifests/linux64/geckodriver.manifest @@ -1,9 +1,9 @@ [ { - "size": 2081948, + "size": 2183421, "visibility": "public", - "digest": "696f0a2eb9ff3abe253875990a7837877977cccd66f9a4ea4a823daaec866f1eae197c63394c093e664736da4f7ad9c480fd9515f30ad359d24e447c40f34925", + "digest": "8e201c5f0f5494cc89b7caad509b2618b1f1b668ac8a81d56df2514968b62b4e06765e9a4e42b7fb273c94d1ca2a712446599654a04716aec204fa8e6a1cee5b", "algorithm": "sha512", - "filename": "geckodriver-v0.15.0-linux64.tar.gz" + "filename": "geckodriver-v0.16.1-linux64.tar.gz" } ] diff --git a/testing/web-platform/meta/IndexedDB/idbindex_getAll.html.ini b/testing/web-platform/meta/IndexedDB/idbindex_getAll.html.ini new file mode 100644 index 000000000000..e89636f23924 --- /dev/null +++ b/testing/web-platform/meta/IndexedDB/idbindex_getAll.html.ini @@ -0,0 +1,4 @@ +[idbindex_getAll.html] + type: testharness + disabled: + if (os == "win") and (version == "6.2.9200") and not debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1364124 diff --git a/testing/web-platform/meta/IndexedDB/idbindex_getAllKeys.html.ini b/testing/web-platform/meta/IndexedDB/idbindex_getAllKeys.html.ini new file mode 100644 index 000000000000..78186b9648f6 --- /dev/null +++ b/testing/web-platform/meta/IndexedDB/idbindex_getAllKeys.html.ini @@ -0,0 +1,4 @@ +[idbindex_getAllKeys.html] + type: testharness + disabled: + if (os == "win") and (version == "6.2.9200") and not debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1364124 diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index d15626d6f53e..bf46bb649377 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -145,6 +145,12 @@ {} ] ], + "accelerometer/Accelerometer_onerror-manual.https.html": [ + [ + "/accelerometer/Accelerometer_onerror-manual.https.html", + {} + ] + ], "ambient-light/AmbientLightSensor_onerror-manual.https.html": [ [ "/ambient-light/AmbientLightSensor_onerror-manual.https.html", @@ -235,12 +241,6 @@ {} ] ], - "auxclick/auxclick_event-manual.html": [ - [ - "/auxclick/auxclick_event-manual.html", - {} - ] - ], "battery-status/battery-charging-manual.html": [ [ "/battery-status/battery-charging-manual.html", @@ -1039,6 +1039,240 @@ {} ] ], + "dpub-aam/doc-abstract-manual.html": [ + [ + "/dpub-aam/doc-abstract-manual.html", + {} + ] + ], + "dpub-aam/doc-acknowledgments-manual.html": [ + [ + "/dpub-aam/doc-acknowledgments-manual.html", + {} + ] + ], + "dpub-aam/doc-afterword-manual.html": [ + [ + "/dpub-aam/doc-afterword-manual.html", + {} + ] + ], + "dpub-aam/doc-appendix-manual.html": [ + [ + "/dpub-aam/doc-appendix-manual.html", + {} + ] + ], + "dpub-aam/doc-backlink-manual.html": [ + [ + "/dpub-aam/doc-backlink-manual.html", + {} + ] + ], + "dpub-aam/doc-biblioentry-manual.html": [ + [ + "/dpub-aam/doc-biblioentry-manual.html", + {} + ] + ], + "dpub-aam/doc-bibliography-manual.html": [ + [ + "/dpub-aam/doc-bibliography-manual.html", + {} + ] + ], + "dpub-aam/doc-biblioref-manual.html": [ + [ + "/dpub-aam/doc-biblioref-manual.html", + {} + ] + ], + "dpub-aam/doc-chapter-manual.html": [ + [ + "/dpub-aam/doc-chapter-manual.html", + {} + ] + ], + "dpub-aam/doc-colophon-manual.html": [ + [ + "/dpub-aam/doc-colophon-manual.html", + {} + ] + ], + "dpub-aam/doc-conclusion-manual.html": [ + [ + "/dpub-aam/doc-conclusion-manual.html", + {} + ] + ], + "dpub-aam/doc-cover-manual.html": [ + [ + "/dpub-aam/doc-cover-manual.html", + {} + ] + ], + "dpub-aam/doc-credit-manual.html": [ + [ + "/dpub-aam/doc-credit-manual.html", + {} + ] + ], + "dpub-aam/doc-credits-manual.html": [ + [ + "/dpub-aam/doc-credits-manual.html", + {} + ] + ], + "dpub-aam/doc-dedication-manual.html": [ + [ + "/dpub-aam/doc-dedication-manual.html", + {} + ] + ], + "dpub-aam/doc-endnote-manual.html": [ + [ + "/dpub-aam/doc-endnote-manual.html", + {} + ] + ], + "dpub-aam/doc-endnotes-manual.html": [ + [ + "/dpub-aam/doc-endnotes-manual.html", + {} + ] + ], + "dpub-aam/doc-epigraph-manual.html": [ + [ + "/dpub-aam/doc-epigraph-manual.html", + {} + ] + ], + "dpub-aam/doc-epilogue-manual.html": [ + [ + "/dpub-aam/doc-epilogue-manual.html", + {} + ] + ], + "dpub-aam/doc-errata-manual.html": [ + [ + "/dpub-aam/doc-errata-manual.html", + {} + ] + ], + "dpub-aam/doc-example-manual.html": [ + [ + "/dpub-aam/doc-example-manual.html", + {} + ] + ], + "dpub-aam/doc-footnote-manual.html": [ + [ + "/dpub-aam/doc-footnote-manual.html", + {} + ] + ], + "dpub-aam/doc-foreword-manual.html": [ + [ + "/dpub-aam/doc-foreword-manual.html", + {} + ] + ], + "dpub-aam/doc-glossary-manual.html": [ + [ + "/dpub-aam/doc-glossary-manual.html", + {} + ] + ], + "dpub-aam/doc-glossref-manual.html": [ + [ + "/dpub-aam/doc-glossref-manual.html", + {} + ] + ], + "dpub-aam/doc-index-manual.html": [ + [ + "/dpub-aam/doc-index-manual.html", + {} + ] + ], + "dpub-aam/doc-introduction-manual.html": [ + [ + "/dpub-aam/doc-introduction-manual.html", + {} + ] + ], + "dpub-aam/doc-noteref-manual.html": [ + [ + "/dpub-aam/doc-noteref-manual.html", + {} + ] + ], + "dpub-aam/doc-notice-manual.html": [ + [ + "/dpub-aam/doc-notice-manual.html", + {} + ] + ], + "dpub-aam/doc-pagebreak-manual.html": [ + [ + "/dpub-aam/doc-pagebreak-manual.html", + {} + ] + ], + "dpub-aam/doc-pagelist-manual.html": [ + [ + "/dpub-aam/doc-pagelist-manual.html", + {} + ] + ], + "dpub-aam/doc-part-manual.html": [ + [ + "/dpub-aam/doc-part-manual.html", + {} + ] + ], + "dpub-aam/doc-preface-manual.html": [ + [ + "/dpub-aam/doc-preface-manual.html", + {} + ] + ], + "dpub-aam/doc-prologue-manual.html": [ + [ + "/dpub-aam/doc-prologue-manual.html", + {} + ] + ], + "dpub-aam/doc-pullquote-manual.html": [ + [ + "/dpub-aam/doc-pullquote-manual.html", + {} + ] + ], + "dpub-aam/doc-qna-manual.html": [ + [ + "/dpub-aam/doc-qna-manual.html", + {} + ] + ], + "dpub-aam/doc-subtitle-manual.html": [ + [ + "/dpub-aam/doc-subtitle-manual.html", + {} + ] + ], + "dpub-aam/doc-tip-manual.html": [ + [ + "/dpub-aam/doc-tip-manual.html", + {} + ] + ], + "dpub-aam/doc-toc-manual.html": [ + [ + "/dpub-aam/doc-toc-manual.html", + {} + ] + ], "dpub-aria/inuse-manual.html": [ [ "/dpub-aria/inuse-manual.html", @@ -1291,6 +1525,12 @@ {} ] ], + "gyroscope/Gyroscope_onerror-manual.https.html": [ + [ + "/gyroscope/Gyroscope_onerror-manual.https.html", + {} + ] + ], "html-longdesc/data-uri-image-data-uri-description-manual.html": [ [ "/html-longdesc/data-uri-image-data-uri-description-manual.html", @@ -1447,21 +1687,33 @@ {} ] ], - "html-media-capture/capture_image-manual.html": [ - [ - "/html-media-capture/capture_image-manual.html", - {} - ] - ], "html-media-capture/capture_image_cancel-manual.html": [ [ "/html-media-capture/capture_image_cancel-manual.html", {} ] ], - "html-media-capture/capture_video-manual.html": [ + "html-media-capture/capture_image_environment-manual.html": [ [ - "/html-media-capture/capture_video-manual.html", + "/html-media-capture/capture_image_environment-manual.html", + {} + ] + ], + "html-media-capture/capture_image_invalid-manual.html": [ + [ + "/html-media-capture/capture_image_invalid-manual.html", + {} + ] + ], + "html-media-capture/capture_image_missing-manual.html": [ + [ + "/html-media-capture/capture_image_missing-manual.html", + {} + ] + ], + "html-media-capture/capture_image_user-manual.html": [ + [ + "/html-media-capture/capture_image_user-manual.html", {} ] ], @@ -1471,6 +1723,30 @@ {} ] ], + "html-media-capture/capture_video_environment-manual.html": [ + [ + "/html-media-capture/capture_video_environment-manual.html", + {} + ] + ], + "html-media-capture/capture_video_invalid-manual.html": [ + [ + "/html-media-capture/capture_video_invalid-manual.html", + {} + ] + ], + "html-media-capture/capture_video_missing-manual.html": [ + [ + "/html-media-capture/capture_video_missing-manual.html", + {} + ] + ], + "html-media-capture/capture_video_user-manual.html": [ + [ + "/html-media-capture/capture_video_user-manual.html", + {} + ] + ], "html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-manual.html": [ [ "/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-manual.html", @@ -2401,6 +2677,12 @@ {} ] ], + "magnetometer/Magnetometer_onerror-manual.https.html": [ + [ + "/magnetometer/Magnetometer_onerror-manual.https.html", + {} + ] + ], "mathml/relations/html5-tree/href-manual.html": [ [ "/mathml/relations/html5-tree/href-manual.html", @@ -3337,6 +3619,36 @@ {} ] ], + "presentation-api/receiving-ua/PresentationConnectionList_onconnectionavailable-manual.https.html": [ + [ + "/presentation-api/receiving-ua/PresentationConnectionList_onconnectionavailable-manual.https.html", + {} + ] + ], + "presentation-api/receiving-ua/PresentationConnection_onclose-manual.https.html": [ + [ + "/presentation-api/receiving-ua/PresentationConnection_onclose-manual.https.html", + {} + ] + ], + "presentation-api/receiving-ua/PresentationConnection_onmessage-manual.https.html": [ + [ + "/presentation-api/receiving-ua/PresentationConnection_onmessage-manual.https.html", + {} + ] + ], + "presentation-api/receiving-ua/PresentationConnection_send-manual.https.html": [ + [ + "/presentation-api/receiving-ua/PresentationConnection_send-manual.https.html", + {} + ] + ], + "presentation-api/receiving-ua/PresentationConnection_terminate-manual.https.html": [ + [ + "/presentation-api/receiving-ua/PresentationConnection_terminate-manual.https.html", + {} + ] + ], "presentation-api/receiving-ua/PresentationReceiver_create-manual.https.html": [ [ "/presentation-api/receiving-ua/PresentationReceiver_create-manual.https.html", @@ -6523,6 +6835,12 @@ {} ] ], + "uievents/auxclick/auxclick_event-manual.html": [ + [ + "/uievents/auxclick/auxclick_event-manual.html", + {} + ] + ], "uievents/interface/click-event-manual.htm": [ [ "/uievents/interface/click-event-manual.htm", @@ -6559,6 +6877,12 @@ {} ] ], + "uievents/mouse/mouseevent_move_button-manual.html": [ + [ + "/uievents/mouse/mouseevent_move_button-manual.html", + {} + ] + ], "uievents/order-of-events/focus-events/focus-contained-manual.html": [ [ "/uievents/order-of-events/focus-events/focus-contained-manual.html", @@ -6691,6 +7015,1344 @@ {} ] ], + "wai-aria/alertdialog_modal_false-manual.html": [ + [ + "/wai-aria/alertdialog_modal_false-manual.html", + {} + ] + ], + "wai-aria/alertdialog_modal_true-manual.html": [ + [ + "/wai-aria/alertdialog_modal_true-manual.html", + {} + ] + ], + "wai-aria/application_activedescendant-manual.html": [ + [ + "/wai-aria/application_activedescendant-manual.html", + {} + ] + ], + "wai-aria/application_activedescendant_value_changes-manual.html": [ + [ + "/wai-aria/application_activedescendant_value_changes-manual.html", + {} + ] + ], + "wai-aria/aria-current_not_declared-manual.html": [ + [ + "/wai-aria/aria-current_not_declared-manual.html", + {} + ] + ], + "wai-aria/aria-current_with_value_changes-manual.html": [ + [ + "/wai-aria/aria-current_with_value_changes-manual.html", + {} + ] + ], + "wai-aria/aria-current_with_value_date-manual.html": [ + [ + "/wai-aria/aria-current_with_value_date-manual.html", + {} + ] + ], + "wai-aria/aria-current_with_value_location-manual.html": [ + [ + "/wai-aria/aria-current_with_value_location-manual.html", + {} + ] + ], + "wai-aria/aria-current_with_value_page-manual.html": [ + [ + "/wai-aria/aria-current_with_value_page-manual.html", + {} + ] + ], + "wai-aria/aria-current_with_value_step-manual.html": [ + [ + "/wai-aria/aria-current_with_value_step-manual.html", + {} + ] + ], + "wai-aria/aria-current_with_value_time-manual.html": [ + [ + "/wai-aria/aria-current_with_value_time-manual.html", + {} + ] + ], + "wai-aria/aria-current_with_value_true-manual.html": [ + [ + "/wai-aria/aria-current_with_value_true-manual.html", + {} + ] + ], + "wai-aria/aria-current_with_value_unspecified-manual.html": [ + [ + "/wai-aria/aria-current_with_value_unspecified-manual.html", + {} + ] + ], + "wai-aria/aria-details_pointing_to_details_element-manual.html": [ + [ + "/wai-aria/aria-details_pointing_to_details_element-manual.html", + {} + ] + ], + "wai-aria/aria-details_pointing_to_div_element-manual.html": [ + [ + "/wai-aria/aria-details_pointing_to_div_element-manual.html", + {} + ] + ], + "wai-aria/article_in_feed_posinset_and_setsize-manual.html": [ + [ + "/wai-aria/article_in_feed_posinset_and_setsize-manual.html", + {} + ] + ], + "wai-aria/article_in_feed_setsize_-1-manual.html": [ + [ + "/wai-aria/article_in_feed_setsize_-1-manual.html", + {} + ] + ], + "wai-aria/article_not_in_feed_posinset_and_setsize-manual.html": [ + [ + "/wai-aria/article_not_in_feed_posinset_and_setsize-manual.html", + {} + ] + ], + "wai-aria/button_haspopup_dialog-manual.html": [ + [ + "/wai-aria/button_haspopup_dialog-manual.html", + {} + ] + ], + "wai-aria/button_haspopup_emptystring-manual.html": [ + [ + "/wai-aria/button_haspopup_emptystring-manual.html", + {} + ] + ], + "wai-aria/button_haspopup_false-manual.html": [ + [ + "/wai-aria/button_haspopup_false-manual.html", + {} + ] + ], + "wai-aria/button_haspopup_foo-manual.html": [ + [ + "/wai-aria/button_haspopup_foo-manual.html", + {} + ] + ], + "wai-aria/button_haspopup_grid-manual.html": [ + [ + "/wai-aria/button_haspopup_grid-manual.html", + {} + ] + ], + "wai-aria/button_haspopup_listbox-manual.html": [ + [ + "/wai-aria/button_haspopup_listbox-manual.html", + {} + ] + ], + "wai-aria/button_haspopup_menu-manual.html": [ + [ + "/wai-aria/button_haspopup_menu-manual.html", + {} + ] + ], + "wai-aria/button_haspopup_tree-manual.html": [ + [ + "/wai-aria/button_haspopup_tree-manual.html", + {} + ] + ], + "wai-aria/button_haspopup_true-manual.html": [ + [ + "/wai-aria/button_haspopup_true-manual.html", + {} + ] + ], + "wai-aria/button_haspopup_unspecified-manual.html": [ + [ + "/wai-aria/button_haspopup_unspecified-manual.html", + {} + ] + ], + "wai-aria/button_roledescription_empty-manual.html": [ + [ + "/wai-aria/button_roledescription_empty-manual.html", + {} + ] + ], + "wai-aria/button_roledescription_valid-manual.html": [ + [ + "/wai-aria/button_roledescription_valid-manual.html", + {} + ] + ], + "wai-aria/button_roledescription_whitespace_only-manual.html": [ + [ + "/wai-aria/button_roledescription_whitespace_only-manual.html", + {} + ] + ], + "wai-aria/cell-manual.html": [ + [ + "/wai-aria/cell-manual.html", + {} + ] + ], + "wai-aria/cell_aria-colspan_2_on_div-manual.html": [ + [ + "/wai-aria/cell_aria-colspan_2_on_div-manual.html", + {} + ] + ], + "wai-aria/cell_aria-colspan_2_on_td_html_colspan_3-manual.html": [ + [ + "/wai-aria/cell_aria-colspan_2_on_td_html_colspan_3-manual.html", + {} + ] + ], + "wai-aria/cell_aria-colspan_2_on_td_html_colspan_3_with_headers_and_border-manual.html": [ + [ + "/wai-aria/cell_aria-colspan_2_on_td_html_colspan_3_with_headers_and_border-manual.html", + {} + ] + ], + "wai-aria/cell_aria-colspan_2_on_td_with_html_colspan_not_specified-manual.html": [ + [ + "/wai-aria/cell_aria-colspan_2_on_td_with_html_colspan_not_specified-manual.html", + {} + ] + ], + "wai-aria/cell_aria-rowspan_2_on_div-manual.html": [ + [ + "/wai-aria/cell_aria-rowspan_2_on_div-manual.html", + {} + ] + ], + "wai-aria/cell_aria-rowspan_2_on_td_html_rowspan_3-manual.html": [ + [ + "/wai-aria/cell_aria-rowspan_2_on_td_html_rowspan_3-manual.html", + {} + ] + ], + "wai-aria/cell_aria-rowspan_2_on_td_with_html_rowspan_not_specified-manual.html": [ + [ + "/wai-aria/cell_aria-rowspan_2_on_td_with_html_rowspan_not_specified-manual.html", + {} + ] + ], + "wai-aria/cell_colindex_4-manual.html": [ + [ + "/wai-aria/cell_colindex_4-manual.html", + {} + ] + ], + "wai-aria/cell_rowindex_4-manual.html": [ + [ + "/wai-aria/cell_rowindex_4-manual.html", + {} + ] + ], + "wai-aria/checkbox_readonly_false-manual.html": [ + [ + "/wai-aria/checkbox_readonly_false-manual.html", + {} + ] + ], + "wai-aria/checkbox_readonly_true-manual.html": [ + [ + "/wai-aria/checkbox_readonly_true-manual.html", + {} + ] + ], + "wai-aria/checkbox_readonly_unspecified-manual.html": [ + [ + "/wai-aria/checkbox_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/columnheader_aria-colspan_2_on_div-manual.html": [ + [ + "/wai-aria/columnheader_aria-colspan_2_on_div-manual.html", + {} + ] + ], + "wai-aria/columnheader_aria-colspan_2_on_th_html_colspan_3-manual.html": [ + [ + "/wai-aria/columnheader_aria-colspan_2_on_th_html_colspan_3-manual.html", + {} + ] + ], + "wai-aria/columnheader_aria-colspan_2_on_th_with_html_colspan_not_specified-manual.html": [ + [ + "/wai-aria/columnheader_aria-colspan_2_on_th_with_html_colspan_not_specified-manual.html", + {} + ] + ], + "wai-aria/columnheader_aria-rowspan_2_on_div-manual.html": [ + [ + "/wai-aria/columnheader_aria-rowspan_2_on_div-manual.html", + {} + ] + ], + "wai-aria/columnheader_aria-rowspan_2_on_th_html_rowspan_3-manual.html": [ + [ + "/wai-aria/columnheader_aria-rowspan_2_on_th_html_rowspan_3-manual.html", + {} + ] + ], + "wai-aria/columnheader_aria-rowspan_2_on_th_with_html_rowspan_not_specified-manual.html": [ + [ + "/wai-aria/columnheader_aria-rowspan_2_on_th_with_html_rowspan_not_specified-manual.html", + {} + ] + ], + "wai-aria/columnheader_colindex_4-manual.html": [ + [ + "/wai-aria/columnheader_colindex_4-manual.html", + {} + ] + ], + "wai-aria/columnheader_rowindex_4-manual.html": [ + [ + "/wai-aria/columnheader_rowindex_4-manual.html", + {} + ] + ], + "wai-aria/columnheader_selected_false_not_automatically_propagated-manual.html": [ + [ + "/wai-aria/columnheader_selected_false_not_automatically_propagated-manual.html", + {} + ] + ], + "wai-aria/columnheader_selected_true_not_automatically_propagated-manual.html": [ + [ + "/wai-aria/columnheader_selected_true_not_automatically_propagated-manual.html", + {} + ] + ], + "wai-aria/combobox_controls_an_invalid_id-manual.html": [ + [ + "/wai-aria/combobox_controls_an_invalid_id-manual.html", + {} + ] + ], + "wai-aria/combobox_haspopup_dialog-manual.html": [ + [ + "/wai-aria/combobox_haspopup_dialog-manual.html", + {} + ] + ], + "wai-aria/combobox_haspopup_false-manual.html": [ + [ + "/wai-aria/combobox_haspopup_false-manual.html", + {} + ] + ], + "wai-aria/combobox_haspopup_grid-manual.html": [ + [ + "/wai-aria/combobox_haspopup_grid-manual.html", + {} + ] + ], + "wai-aria/combobox_haspopup_listbox-manual.html": [ + [ + "/wai-aria/combobox_haspopup_listbox-manual.html", + {} + ] + ], + "wai-aria/combobox_haspopup_menu-manual.html": [ + [ + "/wai-aria/combobox_haspopup_menu-manual.html", + {} + ] + ], + "wai-aria/combobox_haspopup_tree-manual.html": [ + [ + "/wai-aria/combobox_haspopup_tree-manual.html", + {} + ] + ], + "wai-aria/combobox_haspopup_true-manual.html": [ + [ + "/wai-aria/combobox_haspopup_true-manual.html", + {} + ] + ], + "wai-aria/combobox_haspopup_unspecified-manual.html": [ + [ + "/wai-aria/combobox_haspopup_unspecified-manual.html", + {} + ] + ], + "wai-aria/combobox_orientation_horizontal-manual.html": [ + [ + "/wai-aria/combobox_orientation_horizontal-manual.html", + {} + ] + ], + "wai-aria/combobox_orientation_unspecified-manual.html": [ + [ + "/wai-aria/combobox_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/combobox_orientation_vertical-manual.html": [ + [ + "/wai-aria/combobox_orientation_vertical-manual.html", + {} + ] + ], + "wai-aria/combobox_readonly_false-manual.html": [ + [ + "/wai-aria/combobox_readonly_false-manual.html", + {} + ] + ], + "wai-aria/combobox_readonly_true-manual.html": [ + [ + "/wai-aria/combobox_readonly_true-manual.html", + {} + ] + ], + "wai-aria/combobox_readonly_unspecified-manual.html": [ + [ + "/wai-aria/combobox_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/dialog_modal_false-manual.html": [ + [ + "/wai-aria/dialog_modal_false-manual.html", + {} + ] + ], + "wai-aria/dialog_modal_true-manual.html": [ + [ + "/wai-aria/dialog_modal_true-manual.html", + {} + ] + ], + "wai-aria/dialog_modal_unspecified-manual.html": [ + [ + "/wai-aria/dialog_modal_unspecified-manual.html", + {} + ] + ], + "wai-aria/div_element_without_role_roledescription_valid-manual.html": [ + [ + "/wai-aria/div_element_without_role_roledescription_valid-manual.html", + {} + ] + ], + "wai-aria/errormessage_object_in_invalid_state-manual.html": [ + [ + "/wai-aria/errormessage_object_in_invalid_state-manual.html", + {} + ] + ], + "wai-aria/errormessage_object_in_valid_state-manual.html": [ + [ + "/wai-aria/errormessage_object_in_valid_state-manual.html", + {} + ] + ], + "wai-aria/feed-manual.html": [ + [ + "/wai-aria/feed-manual.html", + {} + ] + ], + "wai-aria/figure-manual.html": [ + [ + "/wai-aria/figure-manual.html", + {} + ] + ], + "wai-aria/grid_aria-readonly_false_automatically_propagated-manual.html": [ + [ + "/wai-aria/grid_aria-readonly_false_automatically_propagated-manual.html", + {} + ] + ], + "wai-aria/grid_aria-readonly_true_automatically_propagated-manual.html": [ + [ + "/wai-aria/grid_aria-readonly_true_automatically_propagated-manual.html", + {} + ] + ], + "wai-aria/grid_busy_false-manual.html": [ + [ + "/wai-aria/grid_busy_false-manual.html", + {} + ] + ], + "wai-aria/grid_busy_true-manual.html": [ + [ + "/wai-aria/grid_busy_true-manual.html", + {} + ] + ], + "wai-aria/grid_busy_value_changes-manual.html": [ + [ + "/wai-aria/grid_busy_value_changes-manual.html", + {} + ] + ], + "wai-aria/grid_colcount_8-manual.html": [ + [ + "/wai-aria/grid_colcount_8-manual.html", + {} + ] + ], + "wai-aria/grid_columnheader_readonly_false-manual.html": [ + [ + "/wai-aria/grid_columnheader_readonly_false-manual.html", + {} + ] + ], + "wai-aria/grid_columnheader_readonly_true-manual.html": [ + [ + "/wai-aria/grid_columnheader_readonly_true-manual.html", + {} + ] + ], + "wai-aria/grid_columnheader_readonly_unspecified-manual.html": [ + [ + "/wai-aria/grid_columnheader_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/grid_columnheader_required_false-manual.html": [ + [ + "/wai-aria/grid_columnheader_required_false-manual.html", + {} + ] + ], + "wai-aria/grid_columnheader_required_true-manual.html": [ + [ + "/wai-aria/grid_columnheader_required_true-manual.html", + {} + ] + ], + "wai-aria/grid_columnheader_required_unspecified-manual.html": [ + [ + "/wai-aria/grid_columnheader_required_unspecified-manual.html", + {} + ] + ], + "wai-aria/grid_rowcount_3-manual.html": [ + [ + "/wai-aria/grid_rowcount_3-manual.html", + {} + ] + ], + "wai-aria/grid_rowheader_readonly_false-manual.html": [ + [ + "/wai-aria/grid_rowheader_readonly_false-manual.html", + {} + ] + ], + "wai-aria/grid_rowheader_readonly_true-manual.html": [ + [ + "/wai-aria/grid_rowheader_readonly_true-manual.html", + {} + ] + ], + "wai-aria/grid_rowheader_readonly_unspecified-manual.html": [ + [ + "/wai-aria/grid_rowheader_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/grid_rowheader_required_false-manual.html": [ + [ + "/wai-aria/grid_rowheader_required_false-manual.html", + {} + ] + ], + "wai-aria/grid_rowheader_required_true-manual.html": [ + [ + "/wai-aria/grid_rowheader_required_true-manual.html", + {} + ] + ], + "wai-aria/grid_rowheader_required_unspecified-manual.html": [ + [ + "/wai-aria/grid_rowheader_required_unspecified-manual.html", + {} + ] + ], + "wai-aria/gridcell_aria-colspan_2_on_div-manual.html": [ + [ + "/wai-aria/gridcell_aria-colspan_2_on_div-manual.html", + {} + ] + ], + "wai-aria/gridcell_aria-rowspan_2_on_div-manual.html": [ + [ + "/wai-aria/gridcell_aria-rowspan_2_on_div-manual.html", + {} + ] + ], + "wai-aria/gridcell_colindex_4-manual.html": [ + [ + "/wai-aria/gridcell_colindex_4-manual.html", + {} + ] + ], + "wai-aria/gridcell_rowindex_4-manual.html": [ + [ + "/wai-aria/gridcell_rowindex_4-manual.html", + {} + ] + ], + "wai-aria/group_hidden_undefined_element_not_rendered-manual.html": [ + [ + "/wai-aria/group_hidden_undefined_element_not_rendered-manual.html", + {} + ] + ], + "wai-aria/group_hidden_undefined_element_rendered-manual.html": [ + [ + "/wai-aria/group_hidden_undefined_element_rendered-manual.html", + {} + ] + ], + "wai-aria/heading_level_unspecified-manual.html": [ + [ + "/wai-aria/heading_level_unspecified-manual.html", + {} + ] + ], + "wai-aria/keyshortcuts_multiple_shortcuts-manual.html": [ + [ + "/wai-aria/keyshortcuts_multiple_shortcuts-manual.html", + {} + ] + ], + "wai-aria/keyshortcuts_one_shortcut-manual.html": [ + [ + "/wai-aria/keyshortcuts_one_shortcut-manual.html", + {} + ] + ], + "wai-aria/listbox_busy_false-manual.html": [ + [ + "/wai-aria/listbox_busy_false-manual.html", + {} + ] + ], + "wai-aria/listbox_busy_true-manual.html": [ + [ + "/wai-aria/listbox_busy_true-manual.html", + {} + ] + ], + "wai-aria/listbox_orientation_horizontal-manual.html": [ + [ + "/wai-aria/listbox_orientation_horizontal-manual.html", + {} + ] + ], + "wai-aria/listbox_orientation_unspecified-manual.html": [ + [ + "/wai-aria/listbox_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/listbox_orientation_vertical-manual.html": [ + [ + "/wai-aria/listbox_orientation_vertical-manual.html", + {} + ] + ], + "wai-aria/listbox_readonly_false-manual.html": [ + [ + "/wai-aria/listbox_readonly_false-manual.html", + {} + ] + ], + "wai-aria/listbox_readonly_true-manual.html": [ + [ + "/wai-aria/listbox_readonly_true-manual.html", + {} + ] + ], + "wai-aria/listbox_readonly_unspecified-manual.html": [ + [ + "/wai-aria/listbox_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/listitem_setsize_-1-manual.html": [ + [ + "/wai-aria/listitem_setsize_-1-manual.html", + {} + ] + ], + "wai-aria/menu_orientation_horizontal-manual.html": [ + [ + "/wai-aria/menu_orientation_horizontal-manual.html", + {} + ] + ], + "wai-aria/menu_orientation_unspecified-manual.html": [ + [ + "/wai-aria/menu_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/menu_orientation_vertical-manual.html": [ + [ + "/wai-aria/menu_orientation_vertical-manual.html", + {} + ] + ], + "wai-aria/menubar_busy_false-manual.html": [ + [ + "/wai-aria/menubar_busy_false-manual.html", + {} + ] + ], + "wai-aria/menubar_busy_true-manual.html": [ + [ + "/wai-aria/menubar_busy_true-manual.html", + {} + ] + ], + "wai-aria/menubar_orientation_horizontal-manual.html": [ + [ + "/wai-aria/menubar_orientation_horizontal-manual.html", + {} + ] + ], + "wai-aria/menubar_orientation_unspecified-manual.html": [ + [ + "/wai-aria/menubar_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/menubar_orientation_vertical-manual.html": [ + [ + "/wai-aria/menubar_orientation_vertical-manual.html", + {} + ] + ], + "wai-aria/menuitem_posinset_and_setsize-manual.html": [ + [ + "/wai-aria/menuitem_posinset_and_setsize-manual.html", + {} + ] + ], + "wai-aria/menuitemcheckbox_posinset_and_setsize-manual.html": [ + [ + "/wai-aria/menuitemcheckbox_posinset_and_setsize-manual.html", + {} + ] + ], + "wai-aria/menuitemcheckbox_readonly_false-manual.html": [ + [ + "/wai-aria/menuitemcheckbox_readonly_false-manual.html", + {} + ] + ], + "wai-aria/menuitemcheckbox_readonly_true-manual.html": [ + [ + "/wai-aria/menuitemcheckbox_readonly_true-manual.html", + {} + ] + ], + "wai-aria/menuitemcheckbox_readonly_unspecified-manual.html": [ + [ + "/wai-aria/menuitemcheckbox_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/menuitemradio_posinset_and_setsize-manual.html": [ + [ + "/wai-aria/menuitemradio_posinset_and_setsize-manual.html", + {} + ] + ], + "wai-aria/menuitemradio_readonly_false-manual.html": [ + [ + "/wai-aria/menuitemradio_readonly_false-manual.html", + {} + ] + ], + "wai-aria/menuitemradio_readonly_true-manual.html": [ + [ + "/wai-aria/menuitemradio_readonly_true-manual.html", + {} + ] + ], + "wai-aria/menuitemradio_readonly_unspecified-manual.html": [ + [ + "/wai-aria/menuitemradio_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/none-manual.html": [ + [ + "/wai-aria/none-manual.html", + {} + ] + ], + "wai-aria/option_selected_false-manual.html": [ + [ + "/wai-aria/option_selected_false-manual.html", + {} + ] + ], + "wai-aria/option_selected_true-manual.html": [ + [ + "/wai-aria/option_selected_true-manual.html", + {} + ] + ], + "wai-aria/option_selected_undefined-manual.html": [ + [ + "/wai-aria/option_selected_undefined-manual.html", + {} + ] + ], + "wai-aria/option_selected_value_changes-manual.html": [ + [ + "/wai-aria/option_selected_value_changes-manual.html", + {} + ] + ], + "wai-aria/radiogroup_orientation_horizontal-manual.html": [ + [ + "/wai-aria/radiogroup_orientation_horizontal-manual.html", + {} + ] + ], + "wai-aria/radiogroup_orientation_unspecified-manual.html": [ + [ + "/wai-aria/radiogroup_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/radiogroup_orientation_vertical-manual.html": [ + [ + "/wai-aria/radiogroup_orientation_vertical-manual.html", + {} + ] + ], + "wai-aria/radiogroup_readonly_false-manual.html": [ + [ + "/wai-aria/radiogroup_readonly_false-manual.html", + {} + ] + ], + "wai-aria/radiogroup_readonly_true-manual.html": [ + [ + "/wai-aria/radiogroup_readonly_true-manual.html", + {} + ] + ], + "wai-aria/radiogroup_readonly_unspecified-manual.html": [ + [ + "/wai-aria/radiogroup_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/region_with_name-manual.html": [ + [ + "/wai-aria/region_with_name-manual.html", + {} + ] + ], + "wai-aria/region_without_name-manual.html": [ + [ + "/wai-aria/region_without_name-manual.html", + {} + ] + ], + "wai-aria/row_colindex_4-manual.html": [ + [ + "/wai-aria/row_colindex_4-manual.html", + {} + ] + ], + "wai-aria/row_rowindex_4-manual.html": [ + [ + "/wai-aria/row_rowindex_4-manual.html", + {} + ] + ], + "wai-aria/rowheader_aria-colspan_2_on_div-manual.html": [ + [ + "/wai-aria/rowheader_aria-colspan_2_on_div-manual.html", + {} + ] + ], + "wai-aria/rowheader_aria-rowspan_2_on_div-manual.html": [ + [ + "/wai-aria/rowheader_aria-rowspan_2_on_div-manual.html", + {} + ] + ], + "wai-aria/rowheader_colindex_4-manual.html": [ + [ + "/wai-aria/rowheader_colindex_4-manual.html", + {} + ] + ], + "wai-aria/rowheader_rowindex_4-manual.html": [ + [ + "/wai-aria/rowheader_rowindex_4-manual.html", + {} + ] + ], + "wai-aria/rowheader_selected_false_not_automatically_propagated-manual.html": [ + [ + "/wai-aria/rowheader_selected_false_not_automatically_propagated-manual.html", + {} + ] + ], + "wai-aria/rowheader_selected_true_not_automatically_propagated-manual.html": [ + [ + "/wai-aria/rowheader_selected_true_not_automatically_propagated-manual.html", + {} + ] + ], + "wai-aria/scrollbar_all_values_unspecified-manual.html": [ + [ + "/wai-aria/scrollbar_all_values_unspecified-manual.html", + {} + ] + ], + "wai-aria/scrollbar_only_valuenow_unspecified-manual.html": [ + [ + "/wai-aria/scrollbar_only_valuenow_unspecified-manual.html", + {} + ] + ], + "wai-aria/scrollbar_orientation_unspecified-manual.html": [ + [ + "/wai-aria/scrollbar_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/searchbox-manual.html": [ + [ + "/wai-aria/searchbox-manual.html", + {} + ] + ], + "wai-aria/searchbox_activedescendant-manual.html": [ + [ + "/wai-aria/searchbox_activedescendant-manual.html", + {} + ] + ], + "wai-aria/searchbox_activedescendant_value_changes-manual.html": [ + [ + "/wai-aria/searchbox_activedescendant_value_changes-manual.html", + {} + ] + ], + "wai-aria/searchbox_autocomplete_both-manual.html": [ + [ + "/wai-aria/searchbox_autocomplete_both-manual.html", + {} + ] + ], + "wai-aria/searchbox_autocomplete_inline-manual.html": [ + [ + "/wai-aria/searchbox_autocomplete_inline-manual.html", + {} + ] + ], + "wai-aria/searchbox_autocomplete_list-manual.html": [ + [ + "/wai-aria/searchbox_autocomplete_list-manual.html", + {} + ] + ], + "wai-aria/searchbox_autocomplete_none-manual.html": [ + [ + "/wai-aria/searchbox_autocomplete_none-manual.html", + {} + ] + ], + "wai-aria/searchbox_autocomplete_unspecified-manual.html": [ + [ + "/wai-aria/searchbox_autocomplete_unspecified-manual.html", + {} + ] + ], + "wai-aria/searchbox_multiline_false-manual.html": [ + [ + "/wai-aria/searchbox_multiline_false-manual.html", + {} + ] + ], + "wai-aria/searchbox_multiline_true-manual.html": [ + [ + "/wai-aria/searchbox_multiline_true-manual.html", + {} + ] + ], + "wai-aria/searchbox_multiline_unspecified-manual.html": [ + [ + "/wai-aria/searchbox_multiline_unspecified-manual.html", + {} + ] + ], + "wai-aria/searchbox_placeholder-manual.html": [ + [ + "/wai-aria/searchbox_placeholder-manual.html", + {} + ] + ], + "wai-aria/searchbox_readonly_false-manual.html": [ + [ + "/wai-aria/searchbox_readonly_false-manual.html", + {} + ] + ], + "wai-aria/searchbox_readonly_true-manual.html": [ + [ + "/wai-aria/searchbox_readonly_true-manual.html", + {} + ] + ], + "wai-aria/searchbox_readonly_unspecified-manual.html": [ + [ + "/wai-aria/searchbox_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/searchbox_required_false-manual.html": [ + [ + "/wai-aria/searchbox_required_false-manual.html", + {} + ] + ], + "wai-aria/searchbox_required_true-manual.html": [ + [ + "/wai-aria/searchbox_required_true-manual.html", + {} + ] + ], + "wai-aria/searchbox_required_unspecified-manual.html": [ + [ + "/wai-aria/searchbox_required_unspecified-manual.html", + {} + ] + ], + "wai-aria/separator_focusable_all_values_unspecified-manual.html": [ + [ + "/wai-aria/separator_focusable_all_values_unspecified-manual.html", + {} + ] + ], + "wai-aria/separator_focusable_only_valuenow_unspecified-manual.html": [ + [ + "/wai-aria/separator_focusable_only_valuenow_unspecified-manual.html", + {} + ] + ], + "wai-aria/separator_focusable_valuetext-manual.html": [ + [ + "/wai-aria/separator_focusable_valuetext-manual.html", + {} + ] + ], + "wai-aria/separator_orientation_unspecified-manual.html": [ + [ + "/wai-aria/separator_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/separator_unfocusable_all_values_unspecified-manual.html": [ + [ + "/wai-aria/separator_unfocusable_all_values_unspecified-manual.html", + {} + ] + ], + "wai-aria/separator_unfocusable_valuetext-manual.html": [ + [ + "/wai-aria/separator_unfocusable_valuetext-manual.html", + {} + ] + ], + "wai-aria/slider_all_values_unspecified-manual.html": [ + [ + "/wai-aria/slider_all_values_unspecified-manual.html", + {} + ] + ], + "wai-aria/slider_only_valuenow_unspecified-manual.html": [ + [ + "/wai-aria/slider_only_valuenow_unspecified-manual.html", + {} + ] + ], + "wai-aria/slider_orientation_unspecified-manual.html": [ + [ + "/wai-aria/slider_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/slider_readonly_false-manual.html": [ + [ + "/wai-aria/slider_readonly_false-manual.html", + {} + ] + ], + "wai-aria/slider_readonly_true-manual.html": [ + [ + "/wai-aria/slider_readonly_true-manual.html", + {} + ] + ], + "wai-aria/slider_readonly_unspecified-manual.html": [ + [ + "/wai-aria/slider_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/spinbutton_all_values_unspecified-manual.html": [ + [ + "/wai-aria/spinbutton_all_values_unspecified-manual.html", + {} + ] + ], + "wai-aria/spinbutton_only_aria-valuenow_unspecified-manual.html": [ + [ + "/wai-aria/spinbutton_only_aria-valuenow_unspecified-manual.html", + {} + ] + ], + "wai-aria/spinbutton_readonly_false-manual.html": [ + [ + "/wai-aria/spinbutton_readonly_false-manual.html", + {} + ] + ], + "wai-aria/spinbutton_readonly_true-manual.html": [ + [ + "/wai-aria/spinbutton_readonly_true-manual.html", + {} + ] + ], + "wai-aria/spinbutton_readonly_unspecified-manual.html": [ + [ + "/wai-aria/spinbutton_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/switch_checked_false-manual.html": [ + [ + "/wai-aria/switch_checked_false-manual.html", + {} + ] + ], + "wai-aria/switch_checked_mixed-manual.html": [ + [ + "/wai-aria/switch_checked_mixed-manual.html", + {} + ] + ], + "wai-aria/switch_checked_true-manual.html": [ + [ + "/wai-aria/switch_checked_true-manual.html", + {} + ] + ], + "wai-aria/switch_checked_undefined-manual.html": [ + [ + "/wai-aria/switch_checked_undefined-manual.html", + {} + ] + ], + "wai-aria/switch_checked_value_changes-manual.html": [ + [ + "/wai-aria/switch_checked_value_changes-manual.html", + {} + ] + ], + "wai-aria/switch_readonly_false-manual.html": [ + [ + "/wai-aria/switch_readonly_false-manual.html", + {} + ] + ], + "wai-aria/switch_readonly_true-manual.html": [ + [ + "/wai-aria/switch_readonly_true-manual.html", + {} + ] + ], + "wai-aria/switch_readonly_unspecified-manual.html": [ + [ + "/wai-aria/switch_readonly_unspecified-manual.html", + {} + ] + ], + "wai-aria/tab_posinset_and_setsize-manual.html": [ + [ + "/wai-aria/tab_posinset_and_setsize-manual.html", + {} + ] + ], + "wai-aria/table_colcount_-1-manual.html": [ + [ + "/wai-aria/table_colcount_-1-manual.html", + {} + ] + ], + "wai-aria/table_colcount_8-manual.html": [ + [ + "/wai-aria/table_colcount_8-manual.html", + {} + ] + ], + "wai-aria/table_rowcount_-1-manual.html": [ + [ + "/wai-aria/table_rowcount_-1-manual.html", + {} + ] + ], + "wai-aria/table_rowcount_3-manual.html": [ + [ + "/wai-aria/table_rowcount_3-manual.html", + {} + ] + ], + "wai-aria/tablist_orientation_horizontal-manual.html": [ + [ + "/wai-aria/tablist_orientation_horizontal-manual.html", + {} + ] + ], + "wai-aria/tablist_orientation_unspecified-manual.html": [ + [ + "/wai-aria/tablist_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/tablist_orientation_vertical-manual.html": [ + [ + "/wai-aria/tablist_orientation_vertical-manual.html", + {} + ] + ], + "wai-aria/term_role-manual.html": [ + [ + "/wai-aria/term_role-manual.html", + {} + ] + ], + "wai-aria/textbox_placeholder-manual.html": [ + [ + "/wai-aria/textbox_placeholder-manual.html", + {} + ] + ], + "wai-aria/toolbar_orientation_horizontal-manual.html": [ + [ + "/wai-aria/toolbar_orientation_horizontal-manual.html", + {} + ] + ], + "wai-aria/toolbar_orientation_unspecified-manual.html": [ + [ + "/wai-aria/toolbar_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/toolbar_orientation_vertical-manual.html": [ + [ + "/wai-aria/toolbar_orientation_vertical-manual.html", + {} + ] + ], + "wai-aria/tree_orientation_horizontal-manual.html": [ + [ + "/wai-aria/tree_orientation_horizontal-manual.html", + {} + ] + ], + "wai-aria/tree_orientation_unspecified-manual.html": [ + [ + "/wai-aria/tree_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/tree_orientation_vertical-manual.html": [ + [ + "/wai-aria/tree_orientation_vertical-manual.html", + {} + ] + ], + "wai-aria/treegrid_colcount_8-manual.html": [ + [ + "/wai-aria/treegrid_colcount_8-manual.html", + {} + ] + ], + "wai-aria/treegrid_orientation_horizontal-manual.html": [ + [ + "/wai-aria/treegrid_orientation_horizontal-manual.html", + {} + ] + ], + "wai-aria/treegrid_orientation_unspecified-manual.html": [ + [ + "/wai-aria/treegrid_orientation_unspecified-manual.html", + {} + ] + ], + "wai-aria/treegrid_orientation_vertical-manual.html": [ + [ + "/wai-aria/treegrid_orientation_vertical-manual.html", + {} + ] + ], + "wai-aria/treegrid_rowcount_3-manual.html": [ + [ + "/wai-aria/treegrid_rowcount_3-manual.html", + {} + ] + ], + "wai-aria/treeitem_selected_false-manual.html": [ + [ + "/wai-aria/treeitem_selected_false-manual.html", + {} + ] + ], + "wai-aria/treeitem_selected_true-manual.html": [ + [ + "/wai-aria/treeitem_selected_true-manual.html", + {} + ] + ], + "wai-aria/treeitem_selected_undefined-manual.html": [ + [ + "/wai-aria/treeitem_selected_undefined-manual.html", + {} + ] + ], + "wai-aria/treeitem_selected_value_changes-manual.html": [ + [ + "/wai-aria/treeitem_selected_value_changes-manual.html", + {} + ] + ], "webstorage/storage_local-manual.html": [ [ "/webstorage/storage_local-manual.html", @@ -6945,6 +8607,30 @@ {} ] ], + "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14.html": [ + [ + "/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14.html", + [ + [ + "/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14_ref.html", + "==" + ] + ], + {} + ] + ], + "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15.html": [ + [ + "/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15.html", + [ + [ + "/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15_ref.html", + "==" + ] + ], + {} + ] + ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_2.html": [ [ "/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_2.html", @@ -7149,6 +8835,18 @@ {} ] ], + "apng/animated-png-timeout.html": [ + [ + "/apng/animated-png-timeout.html", + [ + [ + "/apng/animated-png-timeout-ref.html", + "==" + ] + ], + {} + ] + ], "assumptions/canvas-background.html": [ [ "/assumptions/canvas-background.html", @@ -8325,6 +10023,126 @@ {} ] ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-001.html": [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-001.html", + [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html", + "==" + ] + ], + {} + ] + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-002.html": [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-002.html", + [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html", + "==" + ] + ], + {} + ] + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-003.html": [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-003.html", + [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html", + "==" + ] + ], + {} + ] + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-004.html": [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-004.html", + [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html", + "==" + ] + ], + {} + ] + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-005.html": [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-005.html", + [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html", + "==" + ] + ], + {} + ] + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-006.html": [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-006.html", + [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html", + "==" + ] + ], + {} + ] + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-007.html": [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-007.html", + [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html", + "==" + ] + ], + {} + ] + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-008.html": [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-008.html", + [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html", + "==" + ] + ], + {} + ] + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-009.html": [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-009.html", + [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html", + "==" + ] + ], + {} + ] + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-010.html": [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-010.html", + [ + [ + "/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html", + "==" + ] + ], + {} + ] + ], "html/editing/the-hidden-attribute/hidden-1a.html": [ [ "/html/editing/the-hidden-attribute/hidden-1a.html", @@ -9141,6 +10959,18 @@ {} ] ], + "html/semantics/document-metadata/the-link-element/stylesheet-change-href.html": [ + [ + "/html/semantics/document-metadata/the-link-element/stylesheet-change-href.html", + [ + [ + "/html/semantics/document-metadata/the-link-element/stylesheet-change-href-ref.html", + "==" + ] + ], + {} + ] + ], "html/semantics/document-metadata/the-link-element/stylesheet-empty-href.html": [ [ "/html/semantics/document-metadata/the-link-element/stylesheet-empty-href.html", @@ -9273,6 +11103,18 @@ {} ] ], + "html/semantics/embedded-content/the-img-element/document-adopt-base-url.html": [ + [ + "/html/semantics/embedded-content/the-img-element/document-adopt-base-url.html", + [ + [ + "/html/semantics/embedded-content/the-img-element/document-base-url-ref.html", + "==" + ] + ], + {} + ] + ], "html/semantics/embedded-content/the-img-element/document-base-url.html": [ [ "/html/semantics/embedded-content/the-img-element/document-base-url.html", @@ -13671,6 +15513,11 @@ ] }, "support": { + "./.codecov.yml": [ + [ + {} + ] + ], "./.gitignore": [ [ {} @@ -13706,6 +15553,11 @@ {} ] ], + "./check_stability.ini": [ + [ + {} + ] + ], "./check_stability.py": [ [ {} @@ -13726,6 +15578,11 @@ {} ] ], + "./ci_unittest.sh": [ + [ + {} + ] + ], "./config.default.json": [ [ {} @@ -13771,6 +15628,16 @@ {} ] ], + "2dcontext/2x4.png": [ + [ + {} + ] + ], + "2dcontext/4x2.png": [ + [ + {} + ] + ], "2dcontext/best-practices/.gitkeep": [ [ {} @@ -14221,6 +16088,16 @@ {} ] ], + "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14_ref.html": [ + [ + {} + ] + ], + "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15_ref.html": [ + [ + {} + ] + ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1_ref.html": [ [ {} @@ -15226,6 +17103,11 @@ {} ] ], + "WebCryptoAPI/util/worker-report-crypto-subtle-presence.js": [ + [ + {} + ] + ], "WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.js": [ [ {} @@ -16136,7 +18018,7 @@ {} ] ], - "ambient-light/AmbientLightSensor.js": [ + "accelerometer/support-iframe.html": [ [ {} ] @@ -18576,6 +20458,11 @@ {} ] ], + "apng/animated-png-timeout-ref.html": [ + [ + {} + ] + ], "app-uri/OWNERS": [ [ {} @@ -18701,6 +20588,11 @@ {} ] ], + "bluetooth/OWNERS": [ + [ + {} + ] + ], "clear-site-data/support/echo-clear-site-data.py": [ [ {} @@ -18726,6 +20618,11 @@ {} ] ], + "common/PrefixedPostMessage.js": [ + [ + {} + ] + ], "common/blank.html": [ [ {} @@ -18801,6 +20698,16 @@ {} ] ], + "common/object-association.js": [ + [ + {} + ] + ], + "common/performance-timeline-utils.js": [ + [ + {} + ] + ], "common/redirect-opt-in.py": [ [ {} @@ -41806,12 +43713,7 @@ {} ] ], - "content-security-policy/child-src/child-src-worker-allowed.sub.html.sub.headers": [ - [ - {} - ] - ], - "content-security-policy/child-src/child-src-worker-blocked.sub.html.sub.headers": [ + "content-security-policy/child-src/child-src-redirect-blocked.sub.html.sub.headers": [ [ {} ] @@ -41836,47 +43738,52 @@ {} ] ], - "content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-self.sub.html": [ + "content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html": [ [ {} ] ], - "content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-self.sub.html.headers": [ + "content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html.sub.headers": [ [ {} ] ], - "content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-star.sub.html": [ + "content-security-policy/frame-ancestors/support/frame-ancestors-test.sub.js": [ [ {} ] ], - "content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-star.sub.html.headers": [ + "content-security-policy/frame-ancestors/support/frame-ancestors.sub.html": [ [ {} ] ], - "content-security-policy/frame-ancestors/reporting-frame-allows-none-meta.html": [ + "content-security-policy/frame-ancestors/support/frame-ancestors.sub.html.sub.headers": [ [ {} ] ], - "content-security-policy/frame-ancestors/reporting-frame-allows-none.html": [ + "content-security-policy/frame-ancestors/support/frame-in-frame.sub.html": [ [ {} ] ], - "content-security-policy/frame-ancestors/reporting-frame-allows-none.html.headers": [ + "content-security-policy/frame-ancestors/support/frame-in-frame.sub.html.sub.headers": [ [ {} ] ], - "content-security-policy/frame-ancestors/reporting-frame-allows-self.html": [ + "content-security-policy/frame-src/frame-src-redirect.html.headers": [ [ {} ] ], - "content-security-policy/frame-ancestors/reporting-frame-allows-self.html.headers": [ + "content-security-policy/frame-src/support/frame.html": [ + [ + {} + ] + ], + "content-security-policy/frame-src/support/testharness-helper.sub.js": [ [ {} ] @@ -42076,6 +43983,21 @@ {} ] ], + "content-security-policy/script-src/crossoriginScript.js": [ + [ + {} + ] + ], + "content-security-policy/script-src/crossoriginScript.js.headers": [ + [ + {} + ] + ], + "content-security-policy/script-src/externalScript.js": [ + [ + {} + ] + ], "content-security-policy/script-src/inlineSuccessTest.js": [ [ {} @@ -42131,6 +44053,11 @@ {} ] ], + "content-security-policy/script-src/script-src-sri_hash.sub.html.sub.headers": [ + [ + {} + ] + ], "content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_eval.html.headers": [ [ {} @@ -42216,6 +44143,11 @@ {} ] ], + "content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers": [ + [ + {} + ] + ], "content-security-policy/securitypolicyviolation/support/inside-worker.sub.js": [ [ {} @@ -42226,6 +44158,16 @@ {} ] ], + "content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js": [ + [ + {} + ] + ], + "content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers": [ + [ + {} + ] + ], "content-security-policy/style-src/resources/style-src-import.sub.css": [ [ {} @@ -42316,6 +44258,21 @@ {} ] ], + "content-security-policy/support/post-message.js": [ + [ + {} + ] + ], + "content-security-policy/support/postmessage-fail.html": [ + [ + {} + ] + ], + "content-security-policy/support/postmessage-pass.html": [ + [ + {} + ] + ], "content-security-policy/support/report.py": [ [ {} @@ -42456,6 +44413,11 @@ {} ] ], + "css-paint-api/OWNERS": [ + [ + {} + ] + ], "css-timing-1/OWNERS": [ [ {} @@ -42761,11 +44723,456 @@ {} ] ], + "cssom-view/support/1x1-green.png": [ + [ + {} + ] + ], + "cssom-view/support/1x1-lime.png": [ + [ + {} + ] + ], + "cssom-view/support/1x1-maroon.png": [ + [ + {} + ] + ], + "cssom-view/support/1x1-navy.png": [ + [ + {} + ] + ], + "cssom-view/support/1x1-red.png": [ + [ + {} + ] + ], + "cssom-view/support/1x1-white.png": [ + [ + {} + ] + ], + "cssom-view/support/60x60-gg-rr.png": [ + [ + {} + ] + ], + "cssom-view/support/60x60-green.png": [ + [ + {} + ] + ], + "cssom-view/support/60x60-red.png": [ + [ + {} + ] + ], + "cssom-view/support/README": [ + [ + {} + ] + ], + "cssom-view/support/a-green.css": [ + [ + {} + ] + ], + "cssom-view/support/b-green.css": [ + [ + {} + ] + ], + "cssom-view/support/c-red.css": [ + [ + {} + ] + ], + "cssom-view/support/cat.png": [ + [ + {} + ] + ], + "cssom-view/support/import-green.css": [ + [ + {} + ] + ], + "cssom-view/support/import-red.css": [ + [ + {} + ] + ], + "cssom-view/support/pattern-grg-rgr-grg.png": [ + [ + {} + ] + ], + "cssom-view/support/pattern-grg-rrg-rgg.png": [ + [ + {} + ] + ], + "cssom-view/support/pattern-rgr-grg-rgr.png": [ + [ + {} + ] + ], + "cssom-view/support/pattern-tr.png": [ + [ + {} + ] + ], + "cssom-view/support/ruler-h-50%.png": [ + [ + {} + ] + ], + "cssom-view/support/ruler-h-50px.png": [ + [ + {} + ] + ], + "cssom-view/support/ruler-v-100px.png": [ + [ + {} + ] + ], + "cssom-view/support/ruler-v-50px.png": [ + [ + {} + ] + ], + "cssom-view/support/square-purple.png": [ + [ + {} + ] + ], + "cssom-view/support/square-teal.png": [ + [ + {} + ] + ], + "cssom-view/support/square-white.png": [ + [ + {} + ] + ], + "cssom-view/support/support/README": [ + [ + {} + ] + ], + "cssom-view/support/support/swatch-green.png": [ + [ + {} + ] + ], + "cssom-view/support/support/swatch-red.png": [ + [ + {} + ] + ], + "cssom-view/support/swatch-blue.png": [ + [ + {} + ] + ], + "cssom-view/support/swatch-green.png": [ + [ + {} + ] + ], + "cssom-view/support/swatch-lime.png": [ + [ + {} + ] + ], + "cssom-view/support/swatch-orange.png": [ + [ + {} + ] + ], + "cssom-view/support/swatch-red.png": [ + [ + {} + ] + ], + "cssom-view/support/swatch-teal.png": [ + [ + {} + ] + ], + "cssom-view/support/swatch-white.png": [ + [ + {} + ] + ], + "cssom-view/support/swatch-yellow.png": [ + [ + {} + ] + ], + "cssom-view/support/test-bl.png": [ + [ + {} + ] + ], + "cssom-view/support/test-br.png": [ + [ + {} + ] + ], + "cssom-view/support/test-inner-half-size.png": [ + [ + {} + ] + ], + "cssom-view/support/test-outer.png": [ + [ + {} + ] + ], + "cssom-view/support/test-tl.png": [ + [ + {} + ] + ], + "cssom-view/support/test-tr.png": [ + [ + {} + ] + ], + "cssom/OWNERS": [ + [ + {} + ] + ], "cssom/stylesheet-same-origin.css": [ [ {} ] ], + "cssom/support/1x1-green.png": [ + [ + {} + ] + ], + "cssom/support/1x1-lime.png": [ + [ + {} + ] + ], + "cssom/support/1x1-maroon.png": [ + [ + {} + ] + ], + "cssom/support/1x1-navy.png": [ + [ + {} + ] + ], + "cssom/support/1x1-red.png": [ + [ + {} + ] + ], + "cssom/support/1x1-white.png": [ + [ + {} + ] + ], + "cssom/support/60x60-gg-rr.png": [ + [ + {} + ] + ], + "cssom/support/60x60-green.png": [ + [ + {} + ] + ], + "cssom/support/60x60-red.png": [ + [ + {} + ] + ], + "cssom/support/README": [ + [ + {} + ] + ], + "cssom/support/a-green.css": [ + [ + {} + ] + ], + "cssom/support/b-green.css": [ + [ + {} + ] + ], + "cssom/support/c-red.css": [ + [ + {} + ] + ], + "cssom/support/cat.png": [ + [ + {} + ] + ], + "cssom/support/import-green.css": [ + [ + {} + ] + ], + "cssom/support/import-red.css": [ + [ + {} + ] + ], + "cssom/support/pattern-grg-rgr-grg.png": [ + [ + {} + ] + ], + "cssom/support/pattern-grg-rrg-rgg.png": [ + [ + {} + ] + ], + "cssom/support/pattern-rgr-grg-rgr.png": [ + [ + {} + ] + ], + "cssom/support/pattern-tr.png": [ + [ + {} + ] + ], + "cssom/support/ruler-h-50%.png": [ + [ + {} + ] + ], + "cssom/support/ruler-h-50px.png": [ + [ + {} + ] + ], + "cssom/support/ruler-v-100px.png": [ + [ + {} + ] + ], + "cssom/support/ruler-v-50px.png": [ + [ + {} + ] + ], + "cssom/support/square-purple.png": [ + [ + {} + ] + ], + "cssom/support/square-teal.png": [ + [ + {} + ] + ], + "cssom/support/square-white.png": [ + [ + {} + ] + ], + "cssom/support/support/README": [ + [ + {} + ] + ], + "cssom/support/support/swatch-green.png": [ + [ + {} + ] + ], + "cssom/support/support/swatch-red.png": [ + [ + {} + ] + ], + "cssom/support/swatch-blue.png": [ + [ + {} + ] + ], + "cssom/support/swatch-green.png": [ + [ + {} + ] + ], + "cssom/support/swatch-lime.png": [ + [ + {} + ] + ], + "cssom/support/swatch-orange.png": [ + [ + {} + ] + ], + "cssom/support/swatch-red.png": [ + [ + {} + ] + ], + "cssom/support/swatch-teal.png": [ + [ + {} + ] + ], + "cssom/support/swatch-white.png": [ + [ + {} + ] + ], + "cssom/support/swatch-yellow.png": [ + [ + {} + ] + ], + "cssom/support/test-bl.png": [ + [ + {} + ] + ], + "cssom/support/test-br.png": [ + [ + {} + ] + ], + "cssom/support/test-inner-half-size.png": [ + [ + {} + ] + ], + "cssom/support/test-outer.png": [ + [ + {} + ] + ], + "cssom/support/test-tl.png": [ + [ + {} + ] + ], + "cssom/support/test-tr.png": [ + [ + {} + ] + ], "custom-elements/OWNERS": [ [ {} @@ -42916,7 +45323,7 @@ {} ] ], - "docs/_writing-tests/idlharness.html": [ + "docs/_writing-tests/idlharness.md": [ [ {} ] @@ -42956,7 +45363,7 @@ {} ] ], - "docs/_writing-tests/testharness-api.html": [ + "docs/_writing-tests/testharness-api.md": [ [ {} ] @@ -43601,6 +46008,11 @@ {} ] ], + "editing/data/README.md": [ + [ + {} + ] + ], "editing/data/backcolor.js": [ [ {} @@ -44121,16 +46533,6 @@ {} ] ], - "encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4": [ - [ - {} - ] - ], - "encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4": [ - [ - {} - ] - ], "encrypted-media/polyfill/cast-polyfill.js": [ [ {} @@ -44771,6 +47173,11 @@ {} ] ], + "fetch/api/resources/script-with-header.py": [ + [ + {} + ] + ], "fetch/api/resources/status.py": [ [ {} @@ -44876,11 +47283,6 @@ {} ] ], - "fonts/CanvasTest.sfd": [ - [ - {} - ] - ], "fonts/CanvasTest.ttf": [ [ {} @@ -45246,6 +47648,11 @@ {} ] ], + "generic-sensor/generic-sensor-tests.js": [ + [ + {} + ] + ], "geolocation-API/OWNERS": [ [ {} @@ -45261,6 +47668,11 @@ {} ] ], + "gyroscope/support-iframe.html": [ + [ + {} + ] + ], "hr-time/OWNERS": [ [ {} @@ -46436,6 +48848,11 @@ {} ] ], + "html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter_iframe.html": [ + [ + {} + ] + ], "html/browsers/sandboxing/.gitkeep": [ [ {} @@ -46526,6 +48943,16 @@ {} ] ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/close-self.html": [ + [ + {} + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/message-opener.html": [ + [ + {} + ] + ], "html/browsers/the-window-object/browser-interface-elements/.gitkeep": [ [ {} @@ -46681,57 +49108,82 @@ {} ] ], - "html/browsers/windows/browsing-context-names/001-1.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_parent-001-iframe-1.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/002-1.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_parent-002-iframe.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/existing.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_parent-002-window.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/resources/parent-iframe-1.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_parent-003-iframe.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/resources/parent-iframe-2.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_parent-003-window.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/resources/parent-iframe-3.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_parent-004-iframe-1.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/resources/parent-iframe-insensitive-1.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_parent-004-iframe-2.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/resources/parent-iframe-insensitive-2.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_self-001-iframe.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/resources/parent-top-nested.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_self-002-iframe.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/resources/parent-top-replace.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_top-002-window.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/resources/parent-top.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_top-003-iframe-1.html": [ + [ + {} + ] + ], + "html/browsers/windows/browsing-context-names/resources/choose-_top-003-iframe-2.html": [ + [ + {} + ] + ], + "html/browsers/windows/browsing-context-names/resources/choose-default-002-iframe.html": [ + [ + {} + ] + ], + "html/browsers/windows/browsing-context-names/resources/choose-existing-001-iframe.html": [ + [ + {} + ] + ], + "html/browsers/windows/browsing-context-names/resources/open-in-_parent.html": [ + [ + {} + ] + ], + "html/browsers/windows/browsing-context-names/resources/open-in-_top.html": [ [ {} ] @@ -46741,22 +49193,17 @@ {} ] ], - "html/browsers/windows/browsing-context-names/resources/post-to-top-or-close.html": [ - [ - {} - ] - ], "html/browsers/windows/browsing-context-names/resources/post-to-top.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/self1.html": [ + "html/browsers/windows/browsing-context-names/resources/report-has-opener.html": [ [ {} ] ], - "html/browsers/windows/browsing-context-names/self2.html": [ + "html/browsers/windows/browsing-context-names/resources/report-is-top.html": [ [ {} ] @@ -47561,21 +50008,11 @@ {} ] ], - "html/dom/resources/interfaces.idl": [ - [ - {} - ] - ], "html/dom/resources/self-origin-subframe.html": [ [ {} ] ], - "html/dom/resources/untested-interfaces.idl": [ - [ - {} - ] - ], "html/editing/.gitkeep": [ [ {} @@ -52006,6 +54443,11 @@ {} ] ], + "html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html": [ + [ + {} + ] + ], "html/editing/focus/.gitkeep": [ [ {} @@ -52321,6 +54763,106 @@ {} ] ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.js": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/echo-iframe.html": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/echo-worker.js": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-domain.sub.html": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-incrementer.js": [ + [ + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-sab.js": [ + [ + {} + ] + ], "html/infrastructure/terminology/.gitkeep": [ [ {} @@ -52936,6 +55478,16 @@ {} ] ], + "html/rendering/non-replaced-elements/the-page/support/body-marginwidth-marginheight.html": [ + [ + {} + ] + ], + "html/rendering/non-replaced-elements/the-page/support/body-topmargin-leftmargin.html": [ + [ + {} + ] + ], "html/rendering/non-replaced-elements/the-page/test-body.xhtml": [ [ {} @@ -53161,11 +55713,21 @@ {} ] ], + "html/semantics/document-metadata/the-link-element/resources/bad.css": [ + [ + {} + ] + ], "html/semantics/document-metadata/the-link-element/resources/empty-href.css": [ [ {} ] ], + "html/semantics/document-metadata/the-link-element/resources/good.css": [ + [ + {} + ] + ], "html/semantics/document-metadata/the-link-element/resources/stylesheet.css": [ [ {} @@ -53176,6 +55738,11 @@ {} ] ], + "html/semantics/document-metadata/the-link-element/stylesheet-change-href-ref.html": [ + [ + {} + ] + ], "html/semantics/document-metadata/the-link-element/stylesheet-empty-href-ref.html": [ [ {} @@ -54276,6 +56843,11 @@ {} ] ], + "html/semantics/interactive-elements/the-dialog-element/centering-iframe.sub.html": [ + [ + {} + ] + ], "html/semantics/interactive-elements/the-dialog-element/contains.json": [ [ {} @@ -54616,6 +57188,11 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js": [ + [ + {} + ] + ], "html/semantics/scripting-1/the-script-element/resources/cocoa-module.js": [ [ {} @@ -55611,6 +58188,16 @@ {} ] ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/worker-that-requires-failure.js": [ + [ + {} + ] + ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/worker-that-requires-success.js": [ + [ + {} + ] + ], "html/webappapis/scripting/processing-model-2/support/syntax-error-in-setInterval.js": [ [ {} @@ -55666,11 +58253,6 @@ {} ] ], - "html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.js": [ - [ - {} - ] - ], "html/webappapis/system-state-and-capabilities/the-navigator-object/contains.json": [ [ {} @@ -55746,6 +58328,11 @@ {} ] ], + "images/apng.png": [ + [ + {} + ] + ], "images/background.png": [ [ {} @@ -55941,6 +58528,36 @@ {} ] ], + "interfaces/cssom.idl": [ + [ + {} + ] + ], + "interfaces/dom.idl": [ + [ + {} + ] + ], + "interfaces/html.idl": [ + [ + {} + ] + ], + "interfaces/touchevents.idl": [ + [ + {} + ] + ], + "interfaces/uievents.idl": [ + [ + {} + ] + ], + "interfaces/webrtc-pc.idl": [ + [ + {} + ] + ], "js/builtins/Math.maxmin.js": [ [ {} @@ -55981,6 +58598,11 @@ {} ] ], + "magnetometer/support-iframe.html": [ + [ + {} + ] + ], "mathml/README.md": [ [ {} @@ -56506,11 +59128,6 @@ {} ] ], - "media/CanvasTest.ttf": [ - [ - {} - ] - ], "media/OWNERS": [ [ {} @@ -58606,6 +61223,11 @@ {} ] ], + "orientation-sensor/OWNERS": [ + [ + {} + ] + ], "page-visibility/OWNERS": [ [ {} @@ -58621,6 +61243,11 @@ {} ] ], + "page-visibility/resources/prerender_target.html": [ + [ + {} + ] + ], "page-visibility/unload-1.html": [ [ {} @@ -58641,6 +61268,11 @@ {} ] ], + "payment-request/payment-request-response-id.html": [ + [ + {} + ] + ], "performance-timeline/OWNERS": [ [ {} @@ -58791,6 +61423,31 @@ {} ] ], + "presentation-api/receiving-ua/support/PresentationConnectionList_onconnectionavailable_receiving-ua.html": [ + [ + {} + ] + ], + "presentation-api/receiving-ua/support/PresentationConnection_onclose_receiving-ua.html": [ + [ + {} + ] + ], + "presentation-api/receiving-ua/support/PresentationConnection_onmessage_receiving-ua.html": [ + [ + {} + ] + ], + "presentation-api/receiving-ua/support/PresentationConnection_send_receiving-ua.html": [ + [ + {} + ] + ], + "presentation-api/receiving-ua/support/PresentationConnection_terminate_receiving-ua.html": [ + [ + {} + ] + ], "presentation-api/receiving-ua/support/PresentationReceiver_create_receiving-ua.html": [ [ {} @@ -58806,7 +61463,12 @@ {} ] ], - "presentation-api/receiving-ua/support/idlharness_receiving-ua.https.html": [ + "presentation-api/receiving-ua/support/idlharness_receiving-ua.html": [ + [ + {} + ] + ], + "presentation-api/receiving-ua/support/iframe.html": [ [ {} ] @@ -61496,6 +64158,11 @@ {} ] ], + "resource-timing/resources/TAOResponse.py": [ + [ + {} + ] + ], "resource-timing/resources/fake_responses.html": [ [ {} @@ -61511,6 +64178,51 @@ {} ] ], + "resource-timing/resources/iframe_TAO_match_origin.html": [ + [ + {} + ] + ], + "resource-timing/resources/iframe_TAO_match_wildcard.html": [ + [ + {} + ] + ], + "resource-timing/resources/iframe_TAO_multi.html": [ + [ + {} + ] + ], + "resource-timing/resources/iframe_TAO_null.html": [ + [ + {} + ] + ], + "resource-timing/resources/iframe_TAO_origin.html": [ + [ + {} + ] + ], + "resource-timing/resources/iframe_TAO_origin_uppercase.html": [ + [ + {} + ] + ], + "resource-timing/resources/iframe_TAO_space.html": [ + [ + {} + ] + ], + "resource-timing/resources/iframe_TAO_wildcard.html": [ + [ + {} + ] + ], + "resource-timing/resources/iframe_TAO_zero.html": [ + [ + {} + ] + ], "resource-timing/resources/inject_resource_test.html": [ [ {} @@ -61656,11 +64368,6 @@ {} ] ], - "selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.js": [ - [ - {} - ] - ], "selectors/attribute-selectors/attribute-case/resources/semantics-quirks.html": [ [ {} @@ -61681,6 +64388,31 @@ {} ] ], + "server-timing/resources/blue.png": [ + [ + {} + ] + ], + "server-timing/resources/blue.png.sub.headers": [ + [ + {} + ] + ], + "server-timing/resources/green.png": [ + [ + {} + ] + ], + "server-timing/resources/green.png.sub.headers": [ + [ + {} + ] + ], + "server-timing/test_server_timing.html.sub.headers": [ + [ + {} + ] + ], "service-workers/OWNERS": [ [ {} @@ -61741,6 +64473,11 @@ {} ] ], + "service-workers/cache-storage/script-tests/cache-keys.js": [ + [ + {} + ] + ], "service-workers/cache-storage/script-tests/cache-match.js": [ [ {} @@ -61776,6 +64513,11 @@ {} ] ], + "service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js": [ + [ + {} + ] + ], "service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-constructor-worker.js": [ [ {} @@ -61946,6 +64688,16 @@ {} ] ], + "service-workers/service-worker/navigation-preload/resources/resource-timing-scope.py": [ + [ + {} + ] + ], + "service-workers/service-worker/navigation-preload/resources/resource-timing-worker.js": [ + [ + {} + ] + ], "service-workers/service-worker/navigation-preload/resources/wait-for-activate-worker.js": [ [ {} @@ -61991,6 +64743,11 @@ {} ] ], + "service-workers/service-worker/resources/client-id-worker.js": [ + [ + {} + ] + ], "service-workers/service-worker/resources/client-navigate-frame.html": [ [ {} @@ -62006,6 +64763,21 @@ {} ] ], + "service-workers/service-worker/resources/clients-get-client-types-frame.html": [ + [ + {} + ] + ], + "service-workers/service-worker/resources/clients-get-client-types-shared-worker.js": [ + [ + {} + ] + ], + "service-workers/service-worker/resources/clients-get-cross-origin-frame.html": [ + [ + {} + ] + ], "service-workers/service-worker/resources/clients-get-frame.html": [ [ {} @@ -62031,6 +64803,11 @@ {} ] ], + "service-workers/service-worker/resources/clients-matchall-on-evaluation-worker.js": [ + [ + {} + ] + ], "service-workers/service-worker/resources/clients-matchall-worker.js": [ [ {} @@ -62166,6 +64943,16 @@ {} ] ], + "service-workers/service-worker/resources/fetch-event-respond-with-argument-iframe.html": [ + [ + {} + ] + ], + "service-workers/service-worker/resources/fetch-event-respond-with-argument-worker.js": [ + [ + {} + ] + ], "service-workers/service-worker/resources/fetch-event-respond-with-stops-propagation-worker.js": [ [ {} @@ -62321,6 +65108,11 @@ {} ] ], + "service-workers/service-worker/resources/import-mime-type-worker.py": [ + [ + {} + ] + ], "service-workers/service-worker/resources/indexeddb-worker.js": [ [ {} @@ -62801,6 +65593,11 @@ {} ] ], + "staticrange/OWNERS": [ + [ + {} + ] + ], "storage/OWNERS": [ [ {} @@ -62816,6 +65613,16 @@ {} ] ], + "storage/resources/storagemanager-persist-worker.js": [ + [ + {} + ] + ], + "storage/resources/storagemanager-persisted-worker.js": [ + [ + {} + ] + ], "storage/storage-estimate-indexeddb.js": [ [ {} @@ -63021,6 +65828,11 @@ {} ] ], + "streams/writable-streams/error.js": [ + [ + {} + ] + ], "streams/writable-streams/floating-point-total-queue-size.js": [ [ {} @@ -63031,6 +65843,11 @@ {} ] ], + "streams/writable-streams/properties.js": [ + [ + {} + ] + ], "streams/writable-streams/reentrant-strategy.js": [ [ {} @@ -63856,6 +66673,11 @@ {} ] ], + "web-nfc/OWNERS": [ + [ + {} + ] + ], "webaudio/.gitignore": [ [ {} @@ -64086,6 +66908,11 @@ {} ] ], + "webdriver/support/__init__.py": [ + [ + {} + ] + ], "webdriver/support/asserts.py": [ [ {} @@ -64106,6 +66933,11 @@ {} ] ], + "webdriver/support/merge_dictionaries.py": [ + [ + {} + ] + ], "webgl/OWNERS": [ [ {} @@ -81174,6 +84006,12 @@ {} ] ], + "IndexedDB/idbobjectstore-index-finished.html": [ + [ + "/IndexedDB/idbobjectstore-index-finished.html", + {} + ] + ], "IndexedDB/idbobjectstore-query-exception-order.html": [ [ "/IndexedDB/idbobjectstore-query-exception-order.html", @@ -81698,6 +84536,12 @@ {} ] ], + "IndexedDB/idbtransaction-objectStore-finished.html": [ + [ + "/IndexedDB/idbtransaction-objectStore-finished.html", + {} + ] + ], "IndexedDB/idbtransaction-oncomplete.htm": [ [ "/IndexedDB/idbtransaction-oncomplete.htm", @@ -82030,33 +84874,97 @@ } ] ], - "WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html": [ + "WebCryptoAPI/derive_bits_keys/test_ecdh_bits.https.html": [ [ - "/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html", + "/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html": [ + "WebCryptoAPI/derive_bits_keys/test_ecdh_keys.https.html": [ [ - "/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html", + "/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/derive_bits_keys/test_hkdf.html": [ + "WebCryptoAPI/derive_bits_keys/test_hkdf.https.html": [ [ - "/WebCryptoAPI/derive_bits_keys/test_hkdf.html", + "/WebCryptoAPI/derive_bits_keys/test_hkdf.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/derive_bits_keys/test_pbkdf2.html": [ + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_empty.https.html": [ [ - "/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html", + "/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_empty.https.html", + { + "timeout": "long" + } + ] + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_long.https.html": [ + [ + "/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_long.https.html", + { + "timeout": "long" + } + ] + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_short.https.html": [ + [ + "/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_short.https.html", + { + "timeout": "long" + } + ] + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_empty.https.html": [ + [ + "/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_empty.https.html", + { + "timeout": "long" + } + ] + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_long.https.html": [ + [ + "/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_long.https.html", + { + "timeout": "long" + } + ] + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_short.https.html": [ + [ + "/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_short.https.html", + { + "timeout": "long" + } + ] + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_empty.https.html": [ + [ + "/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_empty.https.html", + { + "timeout": "long" + } + ] + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_long.https.html": [ + [ + "/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_long.https.html", + { + "timeout": "long" + } + ] + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_short.https.html": [ + [ + "/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_short.https.html", { "timeout": "long" } @@ -82068,9 +84976,9 @@ {} ] ], - "WebCryptoAPI/digest/test_digest.html": [ + "WebCryptoAPI/digest/test_digest.https.html": [ [ - "/WebCryptoAPI/digest/test_digest.html", + "/WebCryptoAPI/digest/test_digest.https.html", { "timeout": "long" } @@ -82100,33 +85008,33 @@ {} ] ], - "WebCryptoAPI/encrypt_decrypt/test_aes_cbc.html": [ + "WebCryptoAPI/encrypt_decrypt/test_aes_cbc.https.html": [ [ - "/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.html", + "/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/encrypt_decrypt/test_aes_ctr.html": [ + "WebCryptoAPI/encrypt_decrypt/test_aes_ctr.https.html": [ [ - "/WebCryptoAPI/encrypt_decrypt/test_aes_ctr.html", + "/WebCryptoAPI/encrypt_decrypt/test_aes_ctr.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html": [ + "WebCryptoAPI/encrypt_decrypt/test_aes_gcm.https.html": [ [ - "/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html", + "/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.html": [ + "WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.https.html": [ [ - "/WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.html", + "/WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.https.html", { "timeout": "long" } @@ -82304,193 +85212,185 @@ } ] ], - "WebCryptoAPI/generateKey/test_aes-cbc.html": [ + "WebCryptoAPI/generateKey/test_aes-cbc.https.html": [ [ - "/WebCryptoAPI/generateKey/test_aes-cbc.html", + "/WebCryptoAPI/generateKey/test_aes-cbc.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_aes-ctr.html": [ + "WebCryptoAPI/generateKey/test_aes-ctr.https.html": [ [ - "/WebCryptoAPI/generateKey/test_aes-ctr.html", + "/WebCryptoAPI/generateKey/test_aes-ctr.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures.html": [ + "WebCryptoAPI/generateKey/test_failures.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures.html", + "/WebCryptoAPI/generateKey/test_failures.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures_AES-CBC.html": [ + "WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures_AES-CBC.html", + "/WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures_AES-CTR.html": [ + "WebCryptoAPI/generateKey/test_failures_AES-CTR.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures_AES-CTR.html", + "/WebCryptoAPI/generateKey/test_failures_AES-CTR.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures_AES-GCM.html": [ + "WebCryptoAPI/generateKey/test_failures_AES-GCM.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures_AES-GCM.html", + "/WebCryptoAPI/generateKey/test_failures_AES-GCM.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures_AES-KW.html": [ + "WebCryptoAPI/generateKey/test_failures_AES-KW.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures_AES-KW.html", + "/WebCryptoAPI/generateKey/test_failures_AES-KW.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures_ECDH.html": [ + "WebCryptoAPI/generateKey/test_failures_ECDH.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures_ECDH.html", + "/WebCryptoAPI/generateKey/test_failures_ECDH.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures_ECDSA.html": [ + "WebCryptoAPI/generateKey/test_failures_ECDSA.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures_ECDSA.html", + "/WebCryptoAPI/generateKey/test_failures_ECDSA.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures_HMAC.html": [ + "WebCryptoAPI/generateKey/test_failures_HMAC.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures_HMAC.html", + "/WebCryptoAPI/generateKey/test_failures_HMAC.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html": [ + "WebCryptoAPI/generateKey/test_failures_RSA-OAEP.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html", + "/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures_RSA-PSS.html": [ + "WebCryptoAPI/generateKey/test_failures_RSA-PSS.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures_RSA-PSS.html", + "/WebCryptoAPI/generateKey/test_failures_RSA-PSS.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html": [ + "WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.https.html": [ [ - "/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html", + "/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_successes.html": [ + "WebCryptoAPI/generateKey/test_successes_AES-CBC.https.html": [ [ - "/WebCryptoAPI/generateKey/test_successes.html", + "/WebCryptoAPI/generateKey/test_successes_AES-CBC.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_successes_AES-CBC.html": [ + "WebCryptoAPI/generateKey/test_successes_AES-CTR.https.html": [ [ - "/WebCryptoAPI/generateKey/test_successes_AES-CBC.html", + "/WebCryptoAPI/generateKey/test_successes_AES-CTR.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_successes_AES-CTR.html": [ + "WebCryptoAPI/generateKey/test_successes_AES-GCM.https.html": [ [ - "/WebCryptoAPI/generateKey/test_successes_AES-CTR.html", + "/WebCryptoAPI/generateKey/test_successes_AES-GCM.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_successes_AES-GCM.html": [ + "WebCryptoAPI/generateKey/test_successes_AES-KW.https.html": [ [ - "/WebCryptoAPI/generateKey/test_successes_AES-GCM.html", + "/WebCryptoAPI/generateKey/test_successes_AES-KW.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_successes_AES-KW.html": [ + "WebCryptoAPI/generateKey/test_successes_ECDH.https.html": [ [ - "/WebCryptoAPI/generateKey/test_successes_AES-KW.html", + "/WebCryptoAPI/generateKey/test_successes_ECDH.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_successes_ECDH.html": [ + "WebCryptoAPI/generateKey/test_successes_ECDSA.https.html": [ [ - "/WebCryptoAPI/generateKey/test_successes_ECDH.html", + "/WebCryptoAPI/generateKey/test_successes_ECDSA.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_successes_ECDSA.html": [ + "WebCryptoAPI/generateKey/test_successes_HMAC.https.html": [ [ - "/WebCryptoAPI/generateKey/test_successes_ECDSA.html", + "/WebCryptoAPI/generateKey/test_successes_HMAC.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_successes_HMAC.html": [ + "WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html": [ [ - "/WebCryptoAPI/generateKey/test_successes_HMAC.html", + "/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html": [ + "WebCryptoAPI/generateKey/test_successes_RSA-PSS.https.html": [ [ - "/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html", + "/WebCryptoAPI/generateKey/test_successes_RSA-PSS.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/generateKey/test_successes_RSA-PSS.html": [ + "WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.https.html": [ [ - "/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html", - { - "timeout": "long" - } - ] - ], - "WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html": [ - [ - "/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html", + "/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.https.html", { "timeout": "long" } @@ -82512,6 +85412,12 @@ {} ] ], + "WebCryptoAPI/idlharness.https.html": [ + [ + "/WebCryptoAPI/idlharness.https.html", + {} + ] + ], "WebCryptoAPI/idlharness.worker.js": [ [ "/WebCryptoAPI/idlharness.worker.html", @@ -82536,21 +85442,33 @@ {} ] ], - "WebCryptoAPI/import_export/test_ec_importKey.html": [ + "WebCryptoAPI/import_export/test_ec_importKey.https.html": [ [ - "/WebCryptoAPI/import_export/test_ec_importKey.html", + "/WebCryptoAPI/import_export/test_ec_importKey.https.html", {} ] ], - "WebCryptoAPI/import_export/test_rsa_importKey.html": [ + "WebCryptoAPI/import_export/test_rsa_importKey.https.html": [ [ - "/WebCryptoAPI/import_export/test_rsa_importKey.html", + "/WebCryptoAPI/import_export/test_rsa_importKey.https.html", {} ] ], - "WebCryptoAPI/import_export/test_symmetric_importKey.html": [ + "WebCryptoAPI/import_export/test_symmetric_importKey.https.html": [ [ - "/WebCryptoAPI/import_export/test_symmetric_importKey.html", + "/WebCryptoAPI/import_export/test_symmetric_importKey.https.html", + {} + ] + ], + "WebCryptoAPI/secure_context/crypto-subtle-non-secure-context-not-available.sub.html": [ + [ + "/WebCryptoAPI/secure_context/crypto-subtle-non-secure-context-not-available.sub.html", + {} + ] + ], + "WebCryptoAPI/secure_context/crypto-subtle-secure-context-available.https.sub.html": [ + [ + "/WebCryptoAPI/secure_context/crypto-subtle-secure-context-available.https.sub.html", {} ] ], @@ -82578,41 +85496,41 @@ {} ] ], - "WebCryptoAPI/sign_verify/test_ecdsa.html": [ + "WebCryptoAPI/sign_verify/test_ecdsa.https.html": [ [ - "/WebCryptoAPI/sign_verify/test_ecdsa.html", + "/WebCryptoAPI/sign_verify/test_ecdsa.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/sign_verify/test_hmac.html": [ + "WebCryptoAPI/sign_verify/test_hmac.https.html": [ [ - "/WebCryptoAPI/sign_verify/test_hmac.html", + "/WebCryptoAPI/sign_verify/test_hmac.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/sign_verify/test_rsa_pkcs.html": [ + "WebCryptoAPI/sign_verify/test_rsa_pkcs.https.html": [ [ - "/WebCryptoAPI/sign_verify/test_rsa_pkcs.html", + "/WebCryptoAPI/sign_verify/test_rsa_pkcs.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/sign_verify/test_rsa_pss.html": [ + "WebCryptoAPI/sign_verify/test_rsa_pss.https.html": [ [ - "/WebCryptoAPI/sign_verify/test_rsa_pss.html", + "/WebCryptoAPI/sign_verify/test_rsa_pss.https.html", { "timeout": "long" } ] ], - "WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.html": [ + "WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.https.html": [ [ - "/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.html", + "/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.https.html", { "timeout": "long" } @@ -82674,6 +85592,18 @@ {} ] ], + "WebIDL/ecmascript-binding/interface-prototype-object.html": [ + [ + "/WebIDL/ecmascript-binding/interface-prototype-object.html", + {} + ] + ], + "WebIDL/ecmascript-binding/legacy-callback-interface-object.html": [ + [ + "/WebIDL/ecmascript-binding/legacy-callback-interface-object.html", + {} + ] + ], "XMLHttpRequest/FormData-append.html": [ [ "/XMLHttpRequest/FormData-append.html", @@ -84022,15 +86952,27 @@ {} ] ], + "accelerometer/Accelerometer.https.html": [ + [ + "/accelerometer/Accelerometer.https.html", + {} + ] + ], + "accelerometer/Accelerometer_insecure_context.html": [ + [ + "/accelerometer/Accelerometer_insecure_context.html", + {} + ] + ], "accelerometer/idlharness.https.html": [ [ "/accelerometer/idlharness.https.html", {} ] ], - "ambient-light/AmbientLightSensor_browsing_context.https.html": [ + "ambient-light/AmbientLightSensor.https.html": [ [ - "/ambient-light/AmbientLightSensor_browsing_context.https.html", + "/ambient-light/AmbientLightSensor.https.html", {} ] ], @@ -84040,38 +86982,6 @@ {} ] ], - "ambient-light/AmbientLightSensor_onchange.https.html": [ - [ - "/ambient-light/AmbientLightSensor_onchange.https.html", - {} - ] - ], - "ambient-light/AmbientLightSensor_reading.https.html": [ - [ - "/ambient-light/AmbientLightSensor_reading.https.html", - {} - ] - ], - "ambient-light/AmbientLightSensor_start.https.html": [ - [ - "/ambient-light/AmbientLightSensor_start.https.html", - {} - ] - ], - "ambient-light/AmbientLightSensor_stop.https.html": [ - [ - "/ambient-light/AmbientLightSensor_stop.https.html", - {} - ] - ], - "ambient-light/AmbientLightSensor_tests.html": [ - [ - "/ambient-light/AmbientLightSensor_tests.html", - { - "timeout": "long" - } - ] - ], "ambient-light/idlharness.https.html": [ [ "/ambient-light/idlharness.https.html", @@ -84970,6 +87880,12 @@ {} ] ], + "content-security-policy/child-src/child-src-redirect-blocked.sub.html": [ + [ + "/content-security-policy/child-src/child-src-redirect-blocked.sub.html", + {} + ] + ], "content-security-policy/child-src/child-src-worker-allowed.sub.html": [ [ "/content-security-policy/child-src/child-src-worker-allowed.sub.html", @@ -85012,6 +87928,12 @@ {} ] ], + "content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html": [ + [ + "/content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html", + {} + ] + ], "content-security-policy/embedded-enforcement/embedding_csp-header.html": [ [ "/content-security-policy/embedded-enforcement/embedding_csp-header.html", @@ -85126,51 +88048,183 @@ {} ] ], - "content-security-policy/frame-ancestors/deep-allows-none.sub.html": [ + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html": [ [ - "/content-security-policy/frame-ancestors/deep-allows-none.sub.html", + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html", {} ] ], - "content-security-policy/frame-ancestors/multiple-frames-meta-ignored.sub.html": [ + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html": [ [ - "/content-security-policy/frame-ancestors/multiple-frames-meta-ignored.sub.html", + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html", {} ] ], - "content-security-policy/frame-ancestors/multiple-frames-one-blocked.sub.html": [ + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-star-allow.html": [ [ - "/content-security-policy/frame-ancestors/multiple-frames-one-blocked.sub.html", + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-star-allow.html", {} ] ], - "content-security-policy/frame-ancestors/multiple-frames-self-allowed.sub.html": [ + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-allow.html": [ [ - "/content-security-policy/frame-ancestors/multiple-frames-self-allowed.sub.html", + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-allow.html", {} ] ], - "content-security-policy/frame-ancestors/nested-traversing-allowed.sub.html": [ + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block.html": [ [ - "/content-security-policy/frame-ancestors/nested-traversing-allowed.sub.html", + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block.html", {} ] ], - "content-security-policy/frame-ancestors/nested-traversing-banned-top-is-self.sub.html": [ + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html": [ [ - "/content-security-policy/frame-ancestors/nested-traversing-banned-top-is-self.sub.html", + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html", {} ] ], - "content-security-policy/frame-ancestors/nested-traversing-banned.sub.html": [ + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block.html": [ [ - "/content-security-policy/frame-ancestors/nested-traversing-banned.sub.html", + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block.html", {} ] ], - "content-security-policy/frame-ancestors/single-frame-self-allowed.sub.html": [ + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html": [ [ - "/content-security-policy/frame-ancestors/single-frame-self-allowed.sub.html", + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-star-allow.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-star-allow.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-allow.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-allow.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-self-allow.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-self-allow.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-star-allow.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-star-allow.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-allow.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-allow.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-none-block.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-none-block.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-overrides-xfo.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-overrides-xfo.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-self-allow.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-self-allow.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-self-block.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-self-block.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-star-allow-sameorigin.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-star-allow-sameorigin.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-url-allow.sub.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-url-allow.sub.html", + {} + ] + ], + "content-security-policy/frame-ancestors/frame-ancestors-url-block.html": [ + [ + "/content-security-policy/frame-ancestors/frame-ancestors-url-block.html", + {} + ] + ], + "content-security-policy/frame-src/frame-src-redirect.html": [ + [ + "/content-security-policy/frame-src/frame-src-redirect.html", {} ] ], @@ -85448,6 +88502,12 @@ {} ] ], + "content-security-policy/script-src/script-src-sri_hash.sub.html": [ + [ + "/content-security-policy/script-src/script-src-sri_hash.sub.html", + {} + ] + ], "content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_eval.html": [ [ "/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_eval.html", @@ -85544,6 +88604,12 @@ {} ] ], + "content-security-policy/script-src/script-src-strict_dynamic_worker.https.html": [ + [ + "/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html", + {} + ] + ], "content-security-policy/securitypolicyviolation/blockeduri-eval.html": [ [ "/content-security-policy/securitypolicyviolation/blockeduri-eval.html", @@ -85562,6 +88628,12 @@ {} ] ], + "content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html": [ + [ + "/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html", + {} + ] + ], "content-security-policy/securitypolicyviolation/inside-dedicated-worker.html": [ [ "/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html", @@ -85634,6 +88706,12 @@ {} ] ], + "content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html": [ + [ + "/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html", + {} + ] + ], "content-security-policy/style-src/style-src-error-event-fires.html": [ [ "/content-security-policy/style-src/style-src-error-event-fires.html", @@ -85760,6 +88838,12 @@ {} ] ], + "content-security-policy/svg/object-in-svg-foreignobject.sub.html": [ + [ + "/content-security-policy/svg/object-in-svg-foreignobject.sub.html", + {} + ] + ], "content-security-policy/svg/svg-from-guid.html": [ [ "/content-security-policy/svg/svg-from-guid.html", @@ -86020,6 +89104,18 @@ {} ] ], + "credential-management/idl.https.html": [ + [ + "/credential-management/idl.https.html", + {} + ] + ], + "css-font-loading/fontfacesetloadevent-constructor.html": [ + [ + "/css-font-loading/fontfacesetloadevent-constructor.html", + {} + ] + ], "css-timing-1/cubic-bezier-timing-functions-output.html": [ [ "/css-timing-1/cubic-bezier-timing-functions-output.html", @@ -86256,24 +89352,96 @@ {} ] ], + "cssom-view/CaretPosition-001.html": [ + [ + "/cssom-view/CaretPosition-001.html", + {} + ] + ], "cssom-view/HTMLBody-ScrollArea_quirksmode.html": [ [ "/cssom-view/HTMLBody-ScrollArea_quirksmode.html", {} ] ], + "cssom-view/MediaQueryList-001.html": [ + [ + "/cssom-view/MediaQueryList-001.html", + {} + ] + ], "cssom-view/MediaQueryList-with-empty-string.html": [ [ "/cssom-view/MediaQueryList-with-empty-string.html", {} ] ], + "cssom-view/Screen-pixelDepth-Screen-colorDepth001.html": [ + [ + "/cssom-view/Screen-pixelDepth-Screen-colorDepth001.html", + {} + ] + ], + "cssom-view/cssom-getBoundingClientRect-001.html": [ + [ + "/cssom-view/cssom-getBoundingClientRect-001.html", + {} + ] + ], + "cssom-view/cssom-getBoundingClientRect-002.html": [ + [ + "/cssom-view/cssom-getBoundingClientRect-002.html", + {} + ] + ], + "cssom-view/cssom-getClientRects.html": [ + [ + "/cssom-view/cssom-getClientRects.html", + {} + ] + ], + "cssom-view/cssom-view-img-attributes-001.html": [ + [ + "/cssom-view/cssom-view-img-attributes-001.html", + {} + ] + ], + "cssom-view/cssom-view-window-screen-interface.html": [ + [ + "/cssom-view/cssom-view-window-screen-interface.html", + {} + ] + ], + "cssom-view/cssom-view/media-query-list-interface.xht": [ + [ + "/cssom-view/cssom-view/media-query-list-interface.xht", + {} + ] + ], + "cssom-view/cssom-view/window-interface.xht": [ + [ + "/cssom-view/cssom-view/window-interface.xht", + {} + ] + ], + "cssom-view/elementFromPoint-001.html": [ + [ + "/cssom-view/elementFromPoint-001.html", + {} + ] + ], "cssom-view/elementFromPoint.html": [ [ "/cssom-view/elementFromPoint.html", {} ] ], + "cssom-view/elementFromPosition.html": [ + [ + "/cssom-view/elementFromPosition.html", + {} + ] + ], "cssom-view/elementScroll.html": [ [ "/cssom-view/elementScroll.html", @@ -86292,6 +89460,24 @@ {} ] ], + "cssom-view/htmlelement-offset-width-001.html": [ + [ + "/cssom-view/htmlelement-offset-width-001.html", + {} + ] + ], + "cssom-view/matchMedia.xht": [ + [ + "/cssom-view/matchMedia.xht", + {} + ] + ], + "cssom-view/matchMediaAddListener.html": [ + [ + "/cssom-view/matchMediaAddListener.html", + {} + ] + ], "cssom-view/mouseEvent.html": [ [ "/cssom-view/mouseEvent.html", @@ -86304,18 +89490,78 @@ {} ] ], + "cssom-view/offsetParent_element_test.html": [ + [ + "/cssom-view/offsetParent_element_test.html", + {} + ] + ], + "cssom-view/scrollWidthHeight.xht": [ + [ + "/cssom-view/scrollWidthHeight.xht", + {} + ] + ], + "cssom-view/scrollWidthHeightWhenNotScrollable.xht": [ + [ + "/cssom-view/scrollWidthHeightWhenNotScrollable.xht", + {} + ] + ], "cssom-view/scrolling-no-browsing-context.html": [ [ "/cssom-view/scrolling-no-browsing-context.html", {} ] ], + "cssom-view/scrolling-quirks-vs-nonquirks.html": [ + [ + "/cssom-view/scrolling-quirks-vs-nonquirks.html", + {} + ] + ], "cssom-view/scrollingElement.html": [ [ "/cssom-view/scrollingElement.html", {} ] ], + "cssom-view/ttwf-js-cssomview-getclientrects-length.html": [ + [ + "/cssom-view/ttwf-js-cssomview-getclientrects-length.html", + {} + ] + ], + "cssom-view/ttwf-scrollintoview.html": [ + [ + "/cssom-view/ttwf-scrollintoview.html", + {} + ] + ], + "cssom-view/window-screen-height-immutable.html": [ + [ + "/cssom-view/window-screen-height-immutable.html", + {} + ] + ], + "cssom-view/window-screen-height.html": [ + [ + "/cssom-view/window-screen-height.html", + {} + ] + ], + "cssom-view/window-screen-width-immutable.html": [ + [ + "/cssom-view/window-screen-width-immutable.html", + {} + ] + ], + "cssom-view/window-screen-width.html": [ + [ + "/cssom-view/window-screen-width.html", + {} + ] + ], "cssom/CSS.html": [ [ "/cssom/CSS.html", @@ -86364,12 +89610,90 @@ {} ] ], + "cssom/MediaList.xhtml": [ + [ + "/cssom/MediaList.xhtml", + {} + ] + ], "cssom/StyleSheetList.html": [ [ "/cssom/StyleSheetList.html", {} ] ], + "cssom/computed-style-001.html": [ + [ + "/cssom/computed-style-001.html", + {} + ] + ], + "cssom/css-style-attribute-modifications.html": [ + [ + "/cssom/css-style-attribute-modifications.html", + {} + ] + ], + "cssom/css-style-declaration-modifications.html": [ + [ + "/cssom/css-style-declaration-modifications.html", + {} + ] + ], + "cssom/cssimportrule.html": [ + [ + "/cssom/cssimportrule.html", + {} + ] + ], + "cssom/cssom-cssText-serialize.html": [ + [ + "/cssom/cssom-cssText-serialize.html", + {} + ] + ], + "cssom/cssom-cssstyledeclaration-set.html": [ + [ + "/cssom/cssom-cssstyledeclaration-set.html", + {} + ] + ], + "cssom/cssom-fontfacerule-constructors.html": [ + [ + "/cssom/cssom-fontfacerule-constructors.html", + {} + ] + ], + "cssom/cssom-fontfacerule.html": [ + [ + "/cssom/cssom-fontfacerule.html", + {} + ] + ], + "cssom/cssom-setProperty-shorthand.html": [ + [ + "/cssom/cssom-setProperty-shorthand.html", + {} + ] + ], + "cssom/cssstyledeclaration-csstext.html": [ + [ + "/cssom/cssstyledeclaration-csstext.html", + {} + ] + ], + "cssom/cssstyledeclaration-mutability.html": [ + [ + "/cssom/cssstyledeclaration-mutability.html", + {} + ] + ], + "cssom/escape.html": [ + [ + "/cssom/escape.html", + {} + ] + ], "cssom/getComputedStyle-pseudo.html": [ [ "/cssom/getComputedStyle-pseudo.html", @@ -86382,36 +89706,138 @@ {} ] ], + "cssom/index-001.html": [ + [ + "/cssom/index-001.html", + {} + ] + ], + "cssom/index-002.html": [ + [ + "/cssom/index-002.html", + {} + ] + ], + "cssom/index-003.html": [ + [ + "/cssom/index-003.html", + {} + ] + ], + "cssom/inline-style-001.html": [ + [ + "/cssom/inline-style-001.html", + {} + ] + ], + "cssom/interfaces.html": [ + [ + "/cssom/interfaces.html", + {} + ] + ], + "cssom/medialist-interfaces-001.html": [ + [ + "/cssom/medialist-interfaces-001.html", + {} + ] + ], + "cssom/medialist-interfaces-002.html": [ + [ + "/cssom/medialist-interfaces-002.html", + {} + ] + ], + "cssom/medialist-interfaces-003.html": [ + [ + "/cssom/medialist-interfaces-003.html", + {} + ] + ], + "cssom/medialist-interfaces-004.html": [ + [ + "/cssom/medialist-interfaces-004.html", + {} + ] + ], "cssom/overflow-serialization.html": [ [ "/cssom/overflow-serialization.html", {} ] ], + "cssom/selectorSerialize.html": [ + [ + "/cssom/selectorSerialize.html", + {} + ] + ], "cssom/serialization-CSSDeclaration-with-important.html": [ [ "/cssom/serialization-CSSDeclaration-with-important.html", {} ] ], + "cssom/serialize-namespaced-type-selectors.html": [ + [ + "/cssom/serialize-namespaced-type-selectors.html", + {} + ] + ], "cssom/serialize-values.html": [ [ "/cssom/serialize-values.html", {} ] ], + "cssom/serialize-variable-reference.html": [ + [ + "/cssom/serialize-variable-reference.html", + {} + ] + ], "cssom/shorthand-serialization.html": [ [ "/cssom/shorthand-serialization.html", {} ] ], + "cssom/style-sheet-interfaces-001.html": [ + [ + "/cssom/style-sheet-interfaces-001.html", + {} + ] + ], + "cssom/style-sheet-interfaces-002.html": [ + [ + "/cssom/style-sheet-interfaces-002.html", + {} + ] + ], "cssom/stylesheet-same-origin.sub.html": [ [ "/cssom/stylesheet-same-origin.sub.html", {} ] ], + "cssom/ttwf-cssom-doc-ext-load-count.html": [ + [ + "/cssom/ttwf-cssom-doc-ext-load-count.html", + {} + ] + ], + "cssom/ttwf-cssom-doc-ext-load-tree-order.html": [ + [ + "/cssom/ttwf-cssom-doc-ext-load-tree-order.html", + {} + ] + ], + "cssom/ttwf-cssom-document-extension.html": [ + [ + "/cssom/ttwf-cssom-document-extension.html", + {} + ] + ], "cssom/variable-names.html": [ [ "/cssom/variable-names.html", @@ -86466,6 +89892,12 @@ {} ] ], + "custom-elements/custom-element-registry/per-global.html": [ + [ + "/custom-elements/custom-element-registry/per-global.html", + {} + ] + ], "custom-elements/disconnected-callbacks.html": [ [ "/custom-elements/disconnected-callbacks.html", @@ -86478,6 +89910,12 @@ {} ] ], + "custom-elements/microtasks-and-constructors.html": [ + [ + "/custom-elements/microtasks-and-constructors.html", + {} + ] + ], "custom-elements/parser/parser-constructs-custom-element-in-document-write.html": [ [ "/custom-elements/parser/parser-constructs-custom-element-in-document-write.html", @@ -90018,6 +93456,12 @@ {} ] ], + "fetch/api/basic/block-mime-as-script.html": [ + [ + "/fetch/api/basic/block-mime-as-script.html", + {} + ] + ], "fetch/api/basic/conditional-get.html": [ [ "/fetch/api/basic/conditional-get.html", @@ -91066,6 +94510,18 @@ {} ] ], + "gyroscope/Gyroscope.https.html": [ + [ + "/gyroscope/Gyroscope.https.html", + {} + ] + ], + "gyroscope/Gyroscope_insecure_context.html": [ + [ + "/gyroscope/Gyroscope_insecure_context.html", + {} + ] + ], "gyroscope/idlharness.https.html": [ [ "/gyroscope/idlharness.https.html", @@ -92116,6 +95572,12 @@ {} ] ], + "html/browsers/history/the-location-interface/per-global.window.js": [ + [ + "/html/browsers/history/the-location-interface/per-global.window.html", + {} + ] + ], "html/browsers/history/the-location-interface/reload_document_open_write.html": [ [ "/html/browsers/history/the-location-interface/reload_document_open_write.html", @@ -92264,6 +95726,12 @@ {} ] ], + "html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html": [ + [ + "/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html", + {} + ] + ], "html/browsers/sandboxing/sandbox-allow-same-origin.html": [ [ "/html/browsers/sandboxing/sandbox-allow-same-origin.html", @@ -92356,6 +95824,142 @@ } ] ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-screenx-screeny.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-screenx-screeny.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-top-left.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-top-left.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-width-height.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-width-height.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-height.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-height.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerheight.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerheight.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerwidth.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerwidth.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-left.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-left.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screenx.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screenx.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screeny.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screeny.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-top.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-top.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-width.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-width.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-innerheight-innerwidth.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-innerheight-innerwidth.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html", + { + "timeout": "long" + } + ] + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-width-height.html": [ + [ + "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-width-height.html", + { + "timeout": "long" + } + ] + ], "html/browsers/the-window-object/garbage-collection-and-browsing-contexts/discard_iframe_history_1.html": [ [ "/html/browsers/the-window-object/garbage-collection-and-browsing-contexts/discard_iframe_history_1.html", @@ -92500,69 +96104,93 @@ {} ] ], - "html/browsers/windows/browsing-context-names/001.html": [ + "html/browsers/windows/browsing-context-names/choose-_blank-001.html": [ [ - "/html/browsers/windows/browsing-context-names/001.html", + "/html/browsers/windows/browsing-context-names/choose-_blank-001.html", {} ] ], - "html/browsers/windows/browsing-context-names/002.html": [ + "html/browsers/windows/browsing-context-names/choose-_blank-002.html": [ [ - "/html/browsers/windows/browsing-context-names/002.html", + "/html/browsers/windows/browsing-context-names/choose-_blank-002.html", {} ] ], - "html/browsers/windows/browsing-context-names/browsing-context-_blank.html": [ + "html/browsers/windows/browsing-context-names/choose-_blank-003.html": [ [ - "/html/browsers/windows/browsing-context-names/browsing-context-_blank.html", + "/html/browsers/windows/browsing-context-names/choose-_blank-003.html", {} ] ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-existing.html": [ + "html/browsers/windows/browsing-context-names/choose-_parent-001.html": [ [ - "/html/browsers/windows/browsing-context-names/browsing-context-choose-existing.html", + "/html/browsers/windows/browsing-context-names/choose-_parent-001.html", {} ] ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-parent-001.html": [ + "html/browsers/windows/browsing-context-names/choose-_parent-002.html": [ [ - "/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-001.html", + "/html/browsers/windows/browsing-context-names/choose-_parent-002.html", {} ] ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-parent-002.html": [ + "html/browsers/windows/browsing-context-names/choose-_parent-003.html": [ [ - "/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-002.html", + "/html/browsers/windows/browsing-context-names/choose-_parent-003.html", {} ] ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-parent-003.html": [ + "html/browsers/windows/browsing-context-names/choose-_parent-004.html": [ [ - "/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-003.html", + "/html/browsers/windows/browsing-context-names/choose-_parent-004.html", {} ] ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-parent-004.html": [ + "html/browsers/windows/browsing-context-names/choose-_self-001.html": [ [ - "/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-004.html", + "/html/browsers/windows/browsing-context-names/choose-_self-001.html", {} ] ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-self-1.html": [ + "html/browsers/windows/browsing-context-names/choose-_self-002.html": [ [ - "/html/browsers/windows/browsing-context-names/browsing-context-choose-self-1.html", + "/html/browsers/windows/browsing-context-names/choose-_self-002.html", {} ] ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-self-2.html": [ + "html/browsers/windows/browsing-context-names/choose-_top-001.html": [ [ - "/html/browsers/windows/browsing-context-names/browsing-context-choose-self-2.html", + "/html/browsers/windows/browsing-context-names/choose-_top-001.html", {} ] ], - "html/browsers/windows/browsing-context-names/browsing-context-default-name.html": [ + "html/browsers/windows/browsing-context-names/choose-_top-002.html": [ [ - "/html/browsers/windows/browsing-context-names/browsing-context-default-name.html", + "/html/browsers/windows/browsing-context-names/choose-_top-002.html", + {} + ] + ], + "html/browsers/windows/browsing-context-names/choose-_top-003.html": [ + [ + "/html/browsers/windows/browsing-context-names/choose-_top-003.html", + {} + ] + ], + "html/browsers/windows/browsing-context-names/choose-default-001.html": [ + [ + "/html/browsers/windows/browsing-context-names/choose-default-001.html", + {} + ] + ], + "html/browsers/windows/browsing-context-names/choose-default-002.html": [ + [ + "/html/browsers/windows/browsing-context-names/choose-default-002.html", + {} + ] + ], + "html/browsers/windows/browsing-context-names/choose-existing-001.html": [ + [ + "/html/browsers/windows/browsing-context-names/choose-existing-001.html", {} ] ], @@ -93964,6 +97592,110 @@ {} ] ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-dedicatedworker.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-dedicatedworker.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-sharedworker.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-sharedworker.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.html", + {} + ], + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.worker.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.html", + {} + ], + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.worker.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-success.sub.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-success.sub.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-similar-but-cross-origin-success.sub.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-similar-but-cross-origin-success.sub.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.html", + {} + ] + ], + "html/infrastructure/safe-passing-of-structured-data/structured_clone_blob.html": [ + [ + "/html/infrastructure/safe-passing-of-structured-data/structured_clone_blob.html", + {} + ] + ], "html/infrastructure/terminology/plugins/text-plain.html": [ [ "/html/infrastructure/terminology/plugins/text-plain.html", @@ -94136,6 +97868,18 @@ {} ] ], + "html/rendering/non-replaced-elements/the-page/iframe-body-margin-attributes.html": [ + [ + "/html/rendering/non-replaced-elements/the-page/iframe-body-margin-attributes.html", + {} + ] + ], + "html/rendering/non-replaced-elements/the-page/iframe-marginwidth-marginheight.html": [ + [ + "/html/rendering/non-replaced-elements/the-page/iframe-marginwidth-marginheight.html", + {} + ] + ], "html/rendering/replaced-elements/svg-embedded-sizing/svg-in-iframe-auto.html": [ [ "/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-iframe-auto.html", @@ -95688,6 +99432,12 @@ {} ] ], + "html/semantics/embedded-content/the-canvas-element/imagedata.html": [ + [ + "/html/semantics/embedded-content/the-canvas-element/imagedata.html", + {} + ] + ], "html/semantics/embedded-content/the-canvas-element/initial.colour.html": [ [ "/html/semantics/embedded-content/the-canvas-element/initial.colour.html", @@ -96402,6 +100152,12 @@ {} ] ], + "html/semantics/embedded-content/the-img-element/delay-load-event.html": [ + [ + "/html/semantics/embedded-content/the-img-element/delay-load-event.html", + {} + ] + ], "html/semantics/embedded-content/the-img-element/environment-changes/viewport-change.html": [ [ "/html/semantics/embedded-content/the-img-element/environment-changes/viewport-change.html", @@ -96668,6 +100424,24 @@ {} ] ], + "html/semantics/forms/form-control-infrastructure/form_attribute.html": [ + [ + "/html/semantics/forms/form-control-infrastructure/form_attribute.html", + {} + ] + ], + "html/semantics/forms/form-control-infrastructure/form_owner_and_table.html": [ + [ + "/html/semantics/forms/form-control-infrastructure/form_owner_and_table.html", + {} + ] + ], + "html/semantics/forms/form-control-infrastructure/form_owner_and_table_2.html": [ + [ + "/html/semantics/forms/form-control-infrastructure/form_owner_and_table_2.html", + {} + ] + ], "html/semantics/forms/form-submission-0/form-data-set-usv.html": [ [ "/html/semantics/forms/form-submission-0/form-data-set-usv.html", @@ -97346,6 +101120,12 @@ {} ] ], + "html/semantics/interactive-elements/the-dialog-element/centering.html": [ + [ + "/html/semantics/interactive-elements/the-dialog-element/centering.html", + {} + ] + ], "html/semantics/interactive-elements/the-dialog-element/dialog-close.html": [ [ "/html/semantics/interactive-elements/the-dialog-element/dialog-close.html", @@ -97364,6 +101144,12 @@ {} ] ], + "html/semantics/interactive-elements/the-menu-element/menuitem-label.html": [ + [ + "/html/semantics/interactive-elements/the-menu-element/menuitem-label.html", + {} + ] + ], "html/semantics/interactive-elements/the-summary-element/activation-behavior.html": [ [ "/html/semantics/interactive-elements/the-summary-element/activation-behavior.html", @@ -97528,6 +101314,12 @@ {} ] ], + "html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html": [ + [ + "/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html", + {} + ] + ], "html/semantics/scripting-1/the-script-element/nomodule-reflect.html": [ [ "/html/semantics/scripting-1/the-script-element/nomodule-reflect.html", @@ -97900,6 +101692,12 @@ {} ] ], + "html/semantics/tabular-data/processing-model-1/span-limits.html": [ + [ + "/html/semantics/tabular-data/processing-model-1/span-limits.html", + {} + ] + ], "html/semantics/tabular-data/the-caption-element/caption_001.html": [ [ "/html/semantics/tabular-data/the-caption-element/caption_001.html", @@ -98056,6 +101854,18 @@ {} ] ], + "html/semantics/text-level-semantics/the-a-element/a.rel-getter-01.html": [ + [ + "/html/semantics/text-level-semantics/the-a-element/a.rel-getter-01.html", + {} + ] + ], + "html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html": [ + [ + "/html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html", + {} + ] + ], "html/semantics/text-level-semantics/the-a-element/a.text-getter-01.html": [ [ "/html/semantics/text-level-semantics/the-a-element/a.text-getter-01.html", @@ -99884,6 +103694,30 @@ {} ] ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-dedicatedworker.html": [ + [ + "/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-dedicatedworker.html", + {} + ] + ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-serviceworker.https.html": [ + [ + "/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-serviceworker.https.html", + {} + ] + ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html": [ + [ + "/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html", + {} + ] + ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-window.html": [ + [ + "/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-window.html", + {} + ] + ], "html/webappapis/scripting/processing-model-2/runtime-error-cross-origin-setInterval.html": [ [ "/html/webappapis/scripting/processing-model-2/runtime-error-cross-origin-setInterval.html", @@ -100052,18 +103886,6 @@ {} ] ], - "html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.html": [ - [ - "/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.html", - {} - ] - ], - "html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.worker.js": [ - [ - "/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.worker.html", - {} - ] - ], "html/webappapis/system-state-and-capabilities/the-navigator-object/content.html": [ [ "/html/webappapis/system-state-and-capabilities/the-navigator-object/content.html", @@ -100112,6 +103934,16 @@ {} ] ], + "html/webappapis/system-state-and-capabilities/the-navigator-object/navigator.any.js": [ + [ + "/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator.any.html", + {} + ], + [ + "/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator.any.worker.html", + {} + ] + ], "html/webappapis/system-state-and-capabilities/the-navigator-object/navigatorlanguage.html": [ [ "/html/webappapis/system-state-and-capabilities/the-navigator-object/navigatorlanguage.html", @@ -100172,6 +104004,30 @@ {} ] ], + "html/webappapis/timers/negative-setinterval.html": [ + [ + "/html/webappapis/timers/negative-setinterval.html", + {} + ] + ], + "html/webappapis/timers/negative-settimeout.html": [ + [ + "/html/webappapis/timers/negative-settimeout.html", + {} + ] + ], + "html/webappapis/timers/type-long-setinterval.html": [ + [ + "/html/webappapis/timers/type-long-setinterval.html", + {} + ] + ], + "html/webappapis/timers/type-long-settimeout.html": [ + [ + "/html/webappapis/timers/type-long-settimeout.html", + {} + ] + ], "http/content_length.html": [ [ "/http/content_length.html", @@ -100322,6 +104178,36 @@ {} ] ], + "keyboard-lock/idlharness.https.html": [ + [ + "/keyboard-lock/idlharness.https.html", + {} + ] + ], + "keyboard-lock/navigator-cancelKeyboardLock.https.html": [ + [ + "/keyboard-lock/navigator-cancelKeyboardLock.https.html", + {} + ] + ], + "keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html": [ + [ + "/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html", + {} + ] + ], + "keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html": [ + [ + "/keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html", + {} + ] + ], + "keyboard-lock/navigator-requestKeyboardLock.https.html": [ + [ + "/keyboard-lock/navigator-requestKeyboardLock.https.html", + {} + ] + ], "longtask-timing/longtask-attributes.html": [ [ "/longtask-timing/longtask-attributes.html", @@ -100370,6 +104256,18 @@ {} ] ], + "magnetometer/Magnetometer.https.html": [ + [ + "/magnetometer/Magnetometer.https.html", + {} + ] + ], + "magnetometer/Magnetometer_insecure_context.html": [ + [ + "/magnetometer/Magnetometer_insecure_context.html", + {} + ] + ], "magnetometer/idlharness.https.html": [ [ "/magnetometer/idlharness.https.html", @@ -100520,15 +104418,15 @@ {} ] ], - "media-capabilities/idlharness.html": [ + "media-capabilities/decodingInfo.html": [ [ - "/media-capabilities/idlharness.html", + "/media-capabilities/decodingInfo.html", {} ] ], - "media-capabilities/query.html": [ + "media-capabilities/idlharness.html": [ [ - "/media-capabilities/query.html", + "/media-capabilities/idlharness.html", {} ] ], @@ -100898,6 +104796,12 @@ {} ] ], + "mediacapture-image/idlharness.html": [ + [ + "/mediacapture-image/idlharness.html", + {} + ] + ], "mediacapture-record/BlobEvent-constructor.html": [ [ "/mediacapture-record/BlobEvent-constructor.html", @@ -102332,6 +106236,12 @@ {} ] ], + "mixed-content/imageset.https.sub.html": [ + [ + "/mixed-content/imageset.https.sub.html", + {} + ] + ], "mixed-content/optionally-blockable/http-csp/cross-origin-http/audio-tag/top-level/keep-scheme-redirect/opt-in-blocks.https.html": [ [ "/mixed-content/optionally-blockable/http-csp/cross-origin-http/audio-tag/top-level/keep-scheme-redirect/opt-in-blocks.https.html", @@ -102698,6 +106608,18 @@ {} ] ], + "navigation-timing/nav2_test_document_replaced.html": [ + [ + "/navigation-timing/nav2_test_document_replaced.html", + {} + ] + ], + "navigation-timing/nav2_test_frame_removed.html": [ + [ + "/navigation-timing/nav2_test_frame_removed.html", + {} + ] + ], "navigation-timing/nav2_test_instance_accessible_from_the_start.html": [ [ "/navigation-timing/nav2_test_instance_accessible_from_the_start.html", @@ -112960,12 +116882,24 @@ {} ] ], + "orientation-sensor/idlharness.https.html": [ + [ + "/orientation-sensor/idlharness.https.html", + {} + ] + ], "page-visibility/idlharness.html": [ [ "/page-visibility/idlharness.html", {} ] ], + "page-visibility/prerender_call.html": [ + [ + "/page-visibility/prerender_call.html", + {} + ] + ], "page-visibility/test_attributes_exist.html": [ [ "/page-visibility/test_attributes_exist.html", @@ -113068,6 +117002,12 @@ {} ] ], + "payment-request/payment-request-id.https.html": [ + [ + "/payment-request/payment-request-id.https.html", + {} + ] + ], "payment-request/payment-request-in-iframe.html": [ [ "/payment-request/payment-request-in-iframe.html", @@ -113316,6 +117256,12 @@ {} ] ], + "presentation-api/controlling-ua/defaultRequest.https.html": [ + [ + "/presentation-api/controlling-ua/defaultRequest.https.html", + {} + ] + ], "presentation-api/controlling-ua/getAvailability.https.html": [ [ "/presentation-api/controlling-ua/getAvailability.https.html", @@ -121514,6 +125460,60 @@ {} ] ], + "resource-timing/resource_TAO_match_origin.htm": [ + [ + "/resource-timing/resource_TAO_match_origin.htm", + {} + ] + ], + "resource-timing/resource_TAO_match_wildcard.htm": [ + [ + "/resource-timing/resource_TAO_match_wildcard.htm", + {} + ] + ], + "resource-timing/resource_TAO_multi.htm": [ + [ + "/resource-timing/resource_TAO_multi.htm", + {} + ] + ], + "resource-timing/resource_TAO_null.htm": [ + [ + "/resource-timing/resource_TAO_null.htm", + {} + ] + ], + "resource-timing/resource_TAO_origin.htm": [ + [ + "/resource-timing/resource_TAO_origin.htm", + {} + ] + ], + "resource-timing/resource_TAO_origin_uppercase.htm": [ + [ + "/resource-timing/resource_TAO_origin_uppercase.htm", + {} + ] + ], + "resource-timing/resource_TAO_space.htm": [ + [ + "/resource-timing/resource_TAO_space.htm", + {} + ] + ], + "resource-timing/resource_TAO_wildcard.htm": [ + [ + "/resource-timing/resource_TAO_wildcard.htm", + {} + ] + ], + "resource-timing/resource_TAO_zero.htm": [ + [ + "/resource-timing/resource_TAO_zero.htm", + {} + ] + ], "resource-timing/resource_cached.htm": [ [ "/resource-timing/resource_cached.htm", @@ -121762,6 +125762,14 @@ } ] ], + "selection/collapse-15.html": [ + [ + "/selection/collapse-15.html", + { + "timeout": "long" + } + ] + ], "selection/collapse-30.html": [ [ "/selection/collapse-30.html", @@ -121770,6 +125778,14 @@ } ] ], + "selection/collapse-45.html": [ + [ + "/selection/collapse-45.html", + { + "timeout": "long" + } + ] + ], "selection/collapseToStartEnd.html": [ [ "/selection/collapseToStartEnd.html", @@ -121856,9 +125872,9 @@ {} ] ], - "selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.html": [ + "selection/type.html": [ [ - "/selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.html", + "/selection/type.html", {} ] ], @@ -121886,6 +125902,12 @@ {} ] ], + "server-timing/test_server_timing.html": [ + [ + "/server-timing/test_server_timing.html", + {} + ] + ], "service-workers/cache-storage/common.https.html": [ [ "/service-workers/cache-storage/common.https.html", @@ -121910,6 +125932,14 @@ } ] ], + "service-workers/cache-storage/serviceworker/cache-keys.https.html": [ + [ + "/service-workers/cache-storage/serviceworker/cache-keys.https.html", + { + "timeout": "long" + } + ] + ], "service-workers/cache-storage/serviceworker/cache-match.https.html": [ [ "/service-workers/cache-storage/serviceworker/cache-match.https.html", @@ -121980,6 +126010,14 @@ } ] ], + "service-workers/cache-storage/window/cache-keys.https.html": [ + [ + "/service-workers/cache-storage/window/cache-keys.https.html", + { + "timeout": "long" + } + ] + ], "service-workers/cache-storage/window/cache-match.https.html": [ [ "/service-workers/cache-storage/window/cache-match.https.html", @@ -122052,6 +126090,14 @@ } ] ], + "service-workers/cache-storage/worker/cache-keys.https.html": [ + [ + "/service-workers/cache-storage/worker/cache-keys.https.html", + { + "timeout": "long" + } + ] + ], "service-workers/cache-storage/worker/cache-match.https.html": [ [ "/service-workers/cache-storage/worker/cache-match.https.html", @@ -122130,6 +126176,12 @@ {} ] ], + "service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html": [ + [ + "/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html", + {} + ] + ], "service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html": [ [ "/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html", @@ -122202,12 +126254,24 @@ {} ] ], + "service-workers/service-worker/client-id.https.html": [ + [ + "/service-workers/service-worker/client-id.https.html", + {} + ] + ], "service-workers/service-worker/client-navigate.https.html": [ [ "/service-workers/service-worker/client-navigate.https.html", {} ] ], + "service-workers/service-worker/clients-get-client-types.https.html": [ + [ + "/service-workers/service-worker/clients-get-client-types.https.html", + {} + ] + ], "service-workers/service-worker/clients-get-cross-origin.https.html": [ [ "/service-workers/service-worker/clients-get-cross-origin.https.html", @@ -122238,6 +126302,12 @@ {} ] ], + "service-workers/service-worker/clients-matchall-on-evaluation.https.html": [ + [ + "/service-workers/service-worker/clients-matchall-on-evaluation.https.html", + {} + ] + ], "service-workers/service-worker/clients-matchall-order.https.html": [ [ "/service-workers/service-worker/clients-matchall-order.https.html", @@ -122330,6 +126400,12 @@ } ] ], + "service-workers/service-worker/fetch-event-respond-with-argument.https.html": [ + [ + "/service-workers/service-worker/fetch-event-respond-with-argument.https.html", + {} + ] + ], "service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html": [ [ "/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html", @@ -122574,6 +126650,12 @@ {} ] ], + "service-workers/service-worker/navigation-preload/resource-timing.https.html": [ + [ + "/service-workers/service-worker/navigation-preload/resource-timing.https.html", + {} + ] + ], "service-workers/service-worker/navigation-redirect.https.html": [ [ "/service-workers/service-worker/navigation-redirect.https.html", @@ -123020,6 +127102,12 @@ {} ] ], + "shadow-dom/slots-fallback-in-document.html": [ + [ + "/shadow-dom/slots-fallback-in-document.html", + {} + ] + ], "shadow-dom/slots-fallback.html": [ [ "/shadow-dom/slots-fallback.html", @@ -123362,6 +127450,12 @@ {} ] ], + "staticrange/idlharness.html": [ + [ + "/staticrange/idlharness.html", + {} + ] + ], "storage/estimate-indexeddb-worker.https.html": [ [ "/storage/estimate-indexeddb-worker.https.html", @@ -123404,6 +127498,36 @@ {} ] ], + "storage/storagemanager-estimate.https.html": [ + [ + "/storage/storagemanager-estimate.https.html", + {} + ] + ], + "storage/storagemanager-persist-worker.https.html": [ + [ + "/storage/storagemanager-persist-worker.https.html", + {} + ] + ], + "storage/storagemanager-persist.https.html": [ + [ + "/storage/storagemanager-persist.https.html", + {} + ] + ], + "storage/storagemanager-persisted-worker.https.html": [ + [ + "/storage/storagemanager-persisted-worker.https.html", + {} + ] + ], + "storage/storagemanager-persisted.https.html": [ + [ + "/storage/storagemanager-persisted.https.html", + {} + ] + ], "streams/byte-length-queuing-strategy.dedicatedworker.html": [ [ "/streams/byte-length-queuing-strategy.dedicatedworker.html", @@ -124172,6 +128296,30 @@ {} ] ], + "streams/writable-streams/error.dedicatedworker.html": [ + [ + "/streams/writable-streams/error.dedicatedworker.html", + {} + ] + ], + "streams/writable-streams/error.html": [ + [ + "/streams/writable-streams/error.html", + {} + ] + ], + "streams/writable-streams/error.serviceworker.https.html": [ + [ + "/streams/writable-streams/error.serviceworker.https.html", + {} + ] + ], + "streams/writable-streams/error.sharedworker.html": [ + [ + "/streams/writable-streams/error.sharedworker.html", + {} + ] + ], "streams/writable-streams/floating-point-total-queue-size.dedicatedworker.html": [ [ "/streams/writable-streams/floating-point-total-queue-size.dedicatedworker.html", @@ -124220,6 +128368,30 @@ {} ] ], + "streams/writable-streams/properties.dedicatedworker.html": [ + [ + "/streams/writable-streams/properties.dedicatedworker.html", + {} + ] + ], + "streams/writable-streams/properties.html": [ + [ + "/streams/writable-streams/properties.html", + {} + ] + ], + "streams/writable-streams/properties.serviceworker.https.html": [ + [ + "/streams/writable-streams/properties.serviceworker.https.html", + {} + ] + ], + "streams/writable-streams/properties.sharedworker.html": [ + [ + "/streams/writable-streams/properties.sharedworker.html", + {} + ] + ], "streams/writable-streams/reentrant-strategy.dedicatedworker.html": [ [ "/streams/writable-streams/reentrant-strategy.dedicatedworker.html", @@ -124307,7 +128479,9 @@ "svg/interfaces.html": [ [ "/svg/interfaces.html", - {} + { + "timeout": "long" + } ] ], "svg/linking/scripted/href-animate-element.html": [ @@ -124478,15 +128652,13 @@ {} ] ], - "url/historical.html": [ + "url/historical.any.js": [ [ - "/url/historical.html", + "/url/historical.any.html", {} - ] - ], - "url/historical.worker.js": [ + ], [ - "/url/historical.worker.html", + "/url/historical.any.worker.html", {} ] ], @@ -124878,6 +129050,12 @@ {} ] ], + "web-animations/interfaces/Animation/idlharness.html": [ + [ + "/web-animations/interfaces/Animation/idlharness.html", + {} + ] + ], "web-animations/interfaces/Animation/oncancel.html": [ [ "/web-animations/interfaces/Animation/oncancel.html", @@ -125106,12 +129284,30 @@ {} ] ], + "web-animations/timing-model/animations/canceling-an-animation.html": [ + [ + "/web-animations/timing-model/animations/canceling-an-animation.html", + {} + ] + ], "web-animations/timing-model/animations/current-time.html": [ [ "/web-animations/timing-model/animations/current-time.html", {} ] ], + "web-animations/timing-model/animations/finishing-an-animation.html": [ + [ + "/web-animations/timing-model/animations/finishing-an-animation.html", + {} + ] + ], + "web-animations/timing-model/animations/pausing-an-animation.html": [ + [ + "/web-animations/timing-model/animations/pausing-an-animation.html", + {} + ] + ], "web-animations/timing-model/animations/playing-an-animation.html": [ [ "/web-animations/timing-model/animations/playing-an-animation.html", @@ -125154,6 +129350,12 @@ {} ] ], + "web-nfc/idlharness.https.html": [ + [ + "/web-nfc/idlharness.https.html", + {} + ] + ], "webaudio/the-audio-api/the-audiobuffer-interface/idl-test.html": [ [ "/webaudio/the-audio-api/the-audiobuffer-interface/idl-test.html", @@ -129570,6 +133772,12 @@ {} ] ], + "webmessaging/messageerror.html": [ + [ + "/webmessaging/messageerror.html", + {} + ] + ], "webmessaging/postMessage_ArrayBuffer.sub.htm": [ [ "/webmessaging/postMessage_ArrayBuffer.sub.htm", @@ -129972,12 +134180,54 @@ {} ] ], + "webrtc/RTCConfiguration-iceCandidatePoolSize.html": [ + [ + "/webrtc/RTCConfiguration-iceCandidatePoolSize.html", + {} + ] + ], "webrtc/RTCDataChannelEvent-constructor.html": [ [ "/webrtc/RTCDataChannelEvent-constructor.html", {} ] ], + "webrtc/RTCPeerConnection-canTrickleIceCandidates.html": [ + [ + "/webrtc/RTCPeerConnection-canTrickleIceCandidates.html", + {} + ] + ], + "webrtc/RTCPeerConnection-constructor.html": [ + [ + "/webrtc/RTCPeerConnection-constructor.html", + {} + ] + ], + "webrtc/RTCPeerConnection-createDataChannel.html": [ + [ + "/webrtc/RTCPeerConnection-createDataChannel.html", + {} + ] + ], + "webrtc/RTCPeerConnection-iceGatheringState.html": [ + [ + "/webrtc/RTCPeerConnection-iceGatheringState.html", + {} + ] + ], + "webrtc/RTCPeerConnection-idl.html": [ + [ + "/webrtc/RTCPeerConnection-idl.html", + {} + ] + ], + "webrtc/RTCPeerConnection-setRemoteDescription.html": [ + [ + "/webrtc/RTCPeerConnection-setRemoteDescription.html", + {} + ] + ], "webrtc/RTCPeerConnectionIceEvent-constructor.html": [ [ "/webrtc/RTCPeerConnectionIceEvent-constructor.html", @@ -129990,6 +134240,24 @@ {} ] ], + "webrtc/datachannel-idlharness.html": [ + [ + "/webrtc/datachannel-idlharness.html", + {} + ] + ], + "webrtc/getstats.html": [ + [ + "/webrtc/getstats.html", + {} + ] + ], + "webrtc/interfaces.html": [ + [ + "/webrtc/interfaces.html", + {} + ] + ], "webrtc/no-media-call.html": [ [ "/webrtc/no-media-call.html", @@ -130002,36 +134270,6 @@ {} ] ], - "webrtc/rtcpeerconnection/iceGatheringState.html": [ - [ - "/webrtc/rtcpeerconnection/iceGatheringState.html", - {} - ] - ], - "webrtc/rtcpeerconnection/rtcconfiguration-icecandidatepoolsize.html": [ - [ - "/webrtc/rtcpeerconnection/rtcconfiguration-icecandidatepoolsize.html", - {} - ] - ], - "webrtc/rtcpeerconnection/rtcpeerconnection-constructor.html": [ - [ - "/webrtc/rtcpeerconnection/rtcpeerconnection-constructor.html", - {} - ] - ], - "webrtc/rtcpeerconnection/rtcpeerconnection-idl.html": [ - [ - "/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html", - {} - ] - ], - "webrtc/rtcpeerconnection/setRemoteDescription.html": [ - [ - "/webrtc/rtcpeerconnection/setRemoteDescription.html", - {} - ] - ], "webrtc/simplecall.html": [ [ "/webrtc/simplecall.html", @@ -133525,16 +137763,20 @@ } }, "paths": { + "./.codecov.yml": [ + "e2322808739a5977e90896b4755cfc20f4ab2046", + "support" + ], "./.gitignore": [ "a74e35d1ce44dcca7ecb513a8cbd6194fe0f2c58", "support" ], "./.gitmodules": [ - "078f9de776005fb33e6c58bf1aad5deab425ab39", + "525f7d93f00f11086aabc1f652cf06623e21986c", "support" ], "./.travis.yml": [ - "412ca6450f30e77589d7f6aea15d111ccb394b9d", + "d2475341537cf8a63ecb2bc8625dd757647bcc9c", "support" ], "./CONTRIBUTING.md": [ @@ -133550,11 +137792,15 @@ "support" ], "./README.md": [ - "8b7d5a19ca22280bea4475be804faee03bbe237d", + "a00890035c46ef53ab51d51107fde1891265379e", + "support" + ], + "./check_stability.ini": [ + "4ee10945191db8ce3e1d8bfae86bc3f0ad40868f", "support" ], "./check_stability.py": [ - "254d5ca0a4d3228fdb0f5564d7fcbfb53be214ec", + "90a4a7be64ad08f52a3c7a7885cdbef6e11a212e", "support" ], "./ci_built_diff.sh": [ @@ -133569,16 +137815,20 @@ "2d54d770ed8439a93e98961b3105b3248684744d", "support" ], + "./ci_unittest.sh": [ + "5ae19000641227045631083f038dafc92261d403", + "support" + ], "./config.default.json": [ "26f2c0e4aced7e1787adacb36e11c3cbf44bbd48", "support" ], "./lint": [ - "c40fe0907c52a1dd8c20222cf931cf7ae911993b", + "1ea93927bbc5cf570fdd6feefca4f39570b9aa37", "support" ], "./lint.whitelist": [ - "6c978a4331c4d48ae1824dd290f463be29d26598", + "eb36ee69795a6893e3f96a1d26470ea73213eca0", "support" ], "./manifest": [ @@ -133605,6 +137855,14 @@ "c67d3f646e86413722833d2308a9bfc793a916bf", "support" ], + "2dcontext/2x4.png": [ + "690bac789fecf2530b36dd889c68db3bd93ed9fd", + "support" + ], + "2dcontext/4x2.png": [ + "16f72935aaf97175593bcf27794506f0884f091b", + "support" + ], "2dcontext/best-practices/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -134577,6 +138835,22 @@ "30150e3530438d42704fda8b3623286658f6c724", "support" ], + "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14.html": [ + "fa83293cfbdbb67a9d5d27a20ac19ff5d9c46d07", + "reftest" + ], + "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14_ref.html": [ + "0feedb34e5ade7a4e58cb4eb92e2b958a06929fe", + "support" + ], + "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15.html": [ + "b37463cc33b46e9aba5bbe73244fd422ef38406e", + "reftest" + ], + "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15_ref.html": [ + "d6817ddb2ac78b524f7cc80ebd4f348aded4d89f", + "support" + ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1_ref.html": [ "9a70c803aaf5bd8a843b18d6d16779575d4dc6f8", "support" @@ -137702,7 +141976,7 @@ "support" ], "2dcontext/tools/gentestutils.py": [ - "9219d4911c668a1bbe314a66c5d09261bb64ea0a", + "61b25e0406addab477dc133edf87f25052be8a63", "support" ], "2dcontext/tools/name2dir.yaml": [ @@ -138154,11 +142428,11 @@ "testharness" ], "IndexedDB/idb_webworkers.htm": [ - "e57fd8321a437f3b6082c5d75025ad63bd007450", + "8956db4b23f21532383fd5629468fddec6611391", "testharness" ], "IndexedDB/idbcursor-advance-continue-async.htm": [ - "6dbb08d166c7c8c2cd5c918b83bb1b15fad50dce", + "4ed7d1efe3763e8b1e0bb95f529df91c137fa0f5", "testharness" ], "IndexedDB/idbcursor-advance-exception-order.html": [ @@ -138166,11 +142440,11 @@ "testharness" ], "IndexedDB/idbcursor-advance-invalid.htm": [ - "ddb2a1394f4846396f965e60a618f2bde1f57cf9", + "52aa1102409c464e09977d55a35f018a7e3ed390", "testharness" ], "IndexedDB/idbcursor-advance.htm": [ - "7becf54b03320a3b905c4ebfa476476f22409307", + "b7968addaeadd088544c146613f7343cb887f702", "testharness" ], "IndexedDB/idbcursor-continue-exception-order.htm": [ @@ -138178,15 +142452,15 @@ "testharness" ], "IndexedDB/idbcursor-continue.htm": [ - "953ae4b03fcfe2be3652df09577df2e3829dd53a", + "15f5ef0a1e0d396b30c5c8ef740918d69e405507", "testharness" ], "IndexedDB/idbcursor-continuePrimaryKey-exception-order.htm": [ - "85dba064e12f6ee4c7f7a9ab288a8ecb11063298", + "4803def9e592d876f7d5f79d9e5b616d09bbc6f1", "testharness" ], "IndexedDB/idbcursor-continuePrimaryKey-exceptions.htm": [ - "7c2ddb95ce4b7c588ddb2907367a365902eba349", + "1ce0f8e83e296f593aafbd2de72f6437bf9c8b19", "testharness" ], "IndexedDB/idbcursor-continuePrimaryKey.htm": [ @@ -138198,23 +142472,23 @@ "testharness" ], "IndexedDB/idbcursor-direction-index-keyrange.htm": [ - "3b7f8b093301e1eb89d4398c76bd36101490d5e6", + "453d7b510cec23f777924f15919183f6d43849f9", "testharness" ], "IndexedDB/idbcursor-direction-index.htm": [ - "91dde42de3c1511b0cb5f45d9702368c814879bb", + "58e3d34b153e9c415c14db160921364f1765855a", "testharness" ], "IndexedDB/idbcursor-direction-objectstore-keyrange.htm": [ - "7834cd03a20e4e52ce4b55b4966c9c73e0a00301", + "fa5374e9f0cbcbef19b1819449c9e0fd6f87824a", "testharness" ], "IndexedDB/idbcursor-direction-objectstore.htm": [ - "14bda466bc9fb084b76101a9925acdc22cddaa29", + "e09e4f3196aee6ad096f87d1de9dd30521425eaf", "testharness" ], "IndexedDB/idbcursor-direction.htm": [ - "3185189d3b3ca40a908e69c074e68d9474b609c5", + "44f0410fa4997df37a758204e2d446187393ba1b", "testharness" ], "IndexedDB/idbcursor-key.htm": [ @@ -138230,7 +142504,7 @@ "testharness" ], "IndexedDB/idbcursor-source.htm": [ - "0677de106509b9b3f4d1e38780f479d9aaace626", + "e92b1e5ec888594a4b05c695761fd57fea52fd19", "testharness" ], "IndexedDB/idbcursor-update-exception-order.htm": [ @@ -138390,7 +142664,7 @@ "testharness" ], "IndexedDB/idbcursor_iterating.htm": [ - "6d5ed40df4126027ad48876f3d96f039c91b5d6a", + "cc86676b686c6545547ce7f59e140a6027279d5e", "testharness" ], "IndexedDB/idbcursor_iterating_index.htm": [ @@ -138402,11 +142676,11 @@ "testharness" ], "IndexedDB/idbcursor_iterating_objectstore.htm": [ - "79896d7345a47cd134204b79960dd4d38026a679", + "728242c9f1b72b7348c68c2723b25765bab64332", "testharness" ], "IndexedDB/idbcursor_iterating_objectstore2.htm": [ - "afdaeecc80f29426c884c2c852912db957fcdc28", + "811427a853df6d79e671569b87a95e51b3e06070", "testharness" ], "IndexedDB/idbcursor_update_index.htm": [ @@ -138486,11 +142760,11 @@ "testharness" ], "IndexedDB/idbdatabase-transaction-exception-order.html": [ - "8033f0b03f01eb4363291dbc4ef16ae4b66c5bc5", + "c0e6f03eb0169ea46dcf2117ee9f379157c95bf0", "testharness" ], "IndexedDB/idbdatabase_close.htm": [ - "6b0a32c465f735544b89da588bb043bbfbb66230", + "34b8d6cebcd0e5d0e781630b89d52606151df140", "testharness" ], "IndexedDB/idbdatabase_close2.htm": [ @@ -138546,7 +142820,7 @@ "testharness" ], "IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm": [ - "a806d39408f9a8fd9b5d2e623e19075e513d4c37", + "79ee4c1e5ec47887b081c9b3a8e66281023844ba", "testharness" ], "IndexedDB/idbdatabase_deleteObjectStore.htm": [ @@ -138634,11 +142908,11 @@ "testharness" ], "IndexedDB/idbfactory_open10.htm": [ - "580e789cc170cc477ad41a9958766b227e85e02d", + "e4750592975b9c6b4c20db92e617bfe0dad47b9b", "testharness" ], "IndexedDB/idbfactory_open11.htm": [ - "daae03bbc5edf280cf84bb52d77e27d36392c526", + "1ec2c59be1cab46f3466dbb5b29d95048bdd62cf", "testharness" ], "IndexedDB/idbfactory_open12.htm": [ @@ -138650,7 +142924,7 @@ "testharness" ], "IndexedDB/idbfactory_open3.htm": [ - "0abe9c45c058e827689f645a8dd04acf247861ee", + "4b4df0401e63d47e6711dc43f6a51343f7b024bf", "testharness" ], "IndexedDB/idbfactory_open4.htm": [ @@ -138662,11 +142936,11 @@ "testharness" ], "IndexedDB/idbfactory_open6.htm": [ - "35480d3728b630a107e0115656b8db8488779917", + "0715543ef0b2e71913cde6c84024baf6cf9f84dd", "testharness" ], "IndexedDB/idbfactory_open7.htm": [ - "58ecaaea2690baddf916ed848636a6ed8f171670", + "828118b68ad6f80e849bc4dfef245115d6b74f1b", "testharness" ], "IndexedDB/idbfactory_open8.htm": [ @@ -138762,11 +143036,11 @@ "testharness" ], "IndexedDB/idbindex_getAll.html": [ - "68e9f7f0e45fde88f7eceb2b2949e55e828af698", + "c28603db8b1d5941db7bb724d10d66312e77d0ab", "testharness" ], "IndexedDB/idbindex_getAllKeys.html": [ - "2bdca6e57b2b8733d10a5237b6b8b75bb7d9837f", + "16582e1aeb223503b3a5ed06eeb9aa6835997693", "testharness" ], "IndexedDB/idbindex_getKey.htm": [ @@ -138869,6 +143143,10 @@ "6c2fe5ac83765f679fd2572d4ad0d7d30466480d", "testharness" ], + "IndexedDB/idbobjectstore-index-finished.html": [ + "a93dd83fefe202688a8cfbf4d44de6ff5032bc86", + "testharness" + ], "IndexedDB/idbobjectstore-query-exception-order.html": [ "91e12b5c824638c4f46892364ca3572bf5f28cea", "testharness" @@ -139070,11 +143348,11 @@ "testharness" ], "IndexedDB/idbobjectstore_deleteIndex.htm": [ - "37f3a9de39abb19b9c6d524baf28c1379efdaf90", + "05db6e5cb1388765d64bae8310553ad87d2fa0f7", "testharness" ], "IndexedDB/idbobjectstore_deleted.htm": [ - "32ea0d23154b34e009839539cc482209105dec2d", + "b47fa902b979d5c2e270cb196cfd6f2e1d395298", "testharness" ], "IndexedDB/idbobjectstore_get.htm": [ @@ -139106,15 +143384,15 @@ "testharness" ], "IndexedDB/idbobjectstore_getAll.html": [ - "c9387cbe39891986a41d494b64e640f3db28704f", + "3070820db1168a459cf8357f4e7d545084e56334", "testharness" ], "IndexedDB/idbobjectstore_getAllKeys.html": [ - "bfb992f18be3cea8e6febebc22b2a524bfc8cb3a", + "e9f7529ff25900b75aef37edea45b9635802e1b7", "testharness" ], "IndexedDB/idbobjectstore_getKey.html": [ - "76906dde291ad82b93070aef7b1fcecae80adfff", + "d34c54405b817f6eac937532adcc130385c05865", "testharness" ], "IndexedDB/idbobjectstore_index.htm": [ @@ -139126,11 +143404,11 @@ "testharness" ], "IndexedDB/idbobjectstore_openCursor_invalid.htm": [ - "f8bb8abce5872a2543a9a9c85d3b25cc7c9c24d9", + "5457297bc3d408f30d1c9466d0b5d404f6adf473", "testharness" ], "IndexedDB/idbobjectstore_openKeyCursor.htm": [ - "45066f081f2229a16a4ec89ddcee858666651e87", + "fac19308e8e42d2ce3874406b527bb5dd29eba11", "testharness" ], "IndexedDB/idbobjectstore_put.htm": [ @@ -139198,7 +143476,7 @@ "testharness" ], "IndexedDB/idbrequest-onupgradeneeded.htm": [ - "b3b93705a62981706d810ebddaf73f4bee6d1612", + "db880099d6c54ae1168d8b7886680fe2a3332b83", "testharness" ], "IndexedDB/idbrequest_error.html": [ @@ -139213,12 +143491,16 @@ "9c3e4f3e4ec46d222a611a812ef1d670741a9b6b", "testharness" ], + "IndexedDB/idbtransaction-objectStore-finished.html": [ + "1ab1d55b67d1d0fe2a6b90a545a84eb81f1eb89b", + "testharness" + ], "IndexedDB/idbtransaction-oncomplete.htm": [ "c1204c119431395ef705ea01dfd67724db21955a", "testharness" ], "IndexedDB/idbtransaction.htm": [ - "2d058dd87d864ad538d975e7c10e235fca82f74c", + "af3ddcf5367fbcd5d838c29842f6482e1cbcfb49", "testharness" ], "IndexedDB/idbtransaction_abort.htm": [ @@ -139226,7 +143508,7 @@ "testharness" ], "IndexedDB/idbtransaction_objectStoreNames.html": [ - "3a2bb014fe738ebcafc87e449002feec25ae86f6", + "88418b8a79548ed39204153d7110fe7215e20c3d", "testharness" ], "IndexedDB/idbversionchangeevent.htm": [ @@ -139346,7 +143628,7 @@ "support" ], "IndexedDB/support.js": [ - "6544b743611f07c4f6ef2533e9bd0213a23fba07", + "c5634bec710dfbf13898df3100b5982b9d642111", "support" ], "IndexedDB/transaction-abort-generator-revert.html": [ @@ -139466,7 +143748,7 @@ "support" ], "WebCryptoAPI/derive_bits_keys/pbkdf2.js": [ - "f881616857e5f523338f338ffcbded34f1c6b9e9", + "dfd8eea5707720186820549837c8a1a319a8ecc4", "support" ], "WebCryptoAPI/derive_bits_keys/pbkdf2.worker.js": [ @@ -139477,20 +143759,52 @@ "0a073cb726ad239110545eb3cecada2a0ce5daf7", "support" ], - "WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html": [ + "WebCryptoAPI/derive_bits_keys/test_ecdh_bits.https.html": [ "eb82990143fa33de7b62cdacd2db566512d74d44", "testharness" ], - "WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html": [ + "WebCryptoAPI/derive_bits_keys/test_ecdh_keys.https.html": [ "d896626491b4f710970b28d30eb89604034fb8c4", "testharness" ], - "WebCryptoAPI/derive_bits_keys/test_hkdf.html": [ + "WebCryptoAPI/derive_bits_keys/test_hkdf.https.html": [ "6d0def388fed4db1606d03f2cbfd59020bd00c56", "testharness" ], - "WebCryptoAPI/derive_bits_keys/test_pbkdf2.html": [ - "07703342a2b5b80585d541ec47d4633381fd785c", + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_empty.https.html": [ + "48b0c6ac60cc130a5bc109fd43b5b1da74bad6da", + "testharness" + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_long.https.html": [ + "9f28363c1c182c354d688a44249abe3f6c6e9ff5", + "testharness" + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_short.https.html": [ + "2a6b28ee191cc62575872c19a21b402f668cd0d5", + "testharness" + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_empty.https.html": [ + "e1d654a4ccefef12b57ef32388debf5df170e938", + "testharness" + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_long.https.html": [ + "2e3e354fe0b4b96d2429bd6e3b5b702a327d9e84", + "testharness" + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_short.https.html": [ + "b53dd1eb6d350d6546e71e77d829eb3da4fc4c68", + "testharness" + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_empty.https.html": [ + "d36de62c712d53d29aa8cc6995851493d814654f", + "testharness" + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_long.https.html": [ + "518afb29e8f859a793e0e39317c6516aae99fb67", + "testharness" + ], + "WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_short.https.html": [ + "5e776aa3f202bb72a328947983b020f03ba6ec4d", "testharness" ], "WebCryptoAPI/digest/digest.js": [ @@ -139501,7 +143815,7 @@ "a9a6b7a15bf0b795729190a94bdda6ed1ddc013d", "testharness" ], - "WebCryptoAPI/digest/test_digest.html": [ + "WebCryptoAPI/digest/test_digest.https.html": [ "1f5893b2c01a60e1e49b8ba5dee8f3d6507cc604", "testharness" ], @@ -139545,19 +143859,19 @@ "e833d10f83ac5cff26e076371a545d60a8d37b8f", "support" ], - "WebCryptoAPI/encrypt_decrypt/test_aes_cbc.html": [ + "WebCryptoAPI/encrypt_decrypt/test_aes_cbc.https.html": [ "f79d96aaa96347302cf08c641c5064b9dc2e974c", "testharness" ], - "WebCryptoAPI/encrypt_decrypt/test_aes_ctr.html": [ + "WebCryptoAPI/encrypt_decrypt/test_aes_ctr.https.html": [ "a3d4d1e4ea38587d170f583061d58ce02224d81e", "testharness" ], - "WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html": [ + "WebCryptoAPI/encrypt_decrypt/test_aes_gcm.https.html": [ "f545fb559442624770696da2addb489cb5534530", "testharness" ], - "WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.html": [ + "WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.https.html": [ "4905875dd185403d093361afb8e75bef50ce0c34", "testharness" ], @@ -139610,7 +143924,7 @@ "testharness" ], "WebCryptoAPI/generateKey/successes.js": [ - "a048156c0d724a735093a6f1209c8fed8281ffd1", + "9623250b44a270bd23f6d892e8a8296351fac708", "support" ], "WebCryptoAPI/generateKey/successes.worker.js": [ @@ -139657,99 +143971,95 @@ "b9e9790245742b8eeb4af7679cc0144710380c07", "testharness" ], - "WebCryptoAPI/generateKey/test_aes-cbc.html": [ + "WebCryptoAPI/generateKey/test_aes-cbc.https.html": [ "9c92564d0b64784bded21d3c337da125da1c0225", "testharness" ], - "WebCryptoAPI/generateKey/test_aes-ctr.html": [ + "WebCryptoAPI/generateKey/test_aes-ctr.https.html": [ "3804433a5bd2c382c8bd9afbd1b41792d9f927c1", "testharness" ], - "WebCryptoAPI/generateKey/test_failures.html": [ + "WebCryptoAPI/generateKey/test_failures.https.html": [ "a1458bc27b594b9051bfbb7e537aebe2c95b6859", "testharness" ], - "WebCryptoAPI/generateKey/test_failures_AES-CBC.html": [ + "WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html": [ "bf4b12efa09c2602bed73b4ae2b94ebdf5bf9749", "testharness" ], - "WebCryptoAPI/generateKey/test_failures_AES-CTR.html": [ + "WebCryptoAPI/generateKey/test_failures_AES-CTR.https.html": [ "2d33a87c30f30d76e547cb6e4b9637292c2e7b6e", "testharness" ], - "WebCryptoAPI/generateKey/test_failures_AES-GCM.html": [ + "WebCryptoAPI/generateKey/test_failures_AES-GCM.https.html": [ "aaeb0182a48f680fd7f421a8ba7efa29561ad7fb", "testharness" ], - "WebCryptoAPI/generateKey/test_failures_AES-KW.html": [ + "WebCryptoAPI/generateKey/test_failures_AES-KW.https.html": [ "4dc9d4cff709a8a84569f6fc6eb2225a59fe8db4", "testharness" ], - "WebCryptoAPI/generateKey/test_failures_ECDH.html": [ + "WebCryptoAPI/generateKey/test_failures_ECDH.https.html": [ "6eca49b0a06e1c468c28dffab3435cf14972095c", "testharness" ], - "WebCryptoAPI/generateKey/test_failures_ECDSA.html": [ + "WebCryptoAPI/generateKey/test_failures_ECDSA.https.html": [ "decb88cd07b2ef2f2c07d1a1fd8e7dfc46e22350", "testharness" ], - "WebCryptoAPI/generateKey/test_failures_HMAC.html": [ + "WebCryptoAPI/generateKey/test_failures_HMAC.https.html": [ "ffd768d80a38ae9e9ae029c3372a227681b020dd", "testharness" ], - "WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html": [ + "WebCryptoAPI/generateKey/test_failures_RSA-OAEP.https.html": [ "ea5fab99e5fdc1b4232aa4c9eed96657f64b1e67", "testharness" ], - "WebCryptoAPI/generateKey/test_failures_RSA-PSS.html": [ + "WebCryptoAPI/generateKey/test_failures_RSA-PSS.https.html": [ "1e03b7b789b75bb25e3491fe8bcfc198dd53b46d", "testharness" ], - "WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html": [ + "WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.https.html": [ "749e526a3f67c246a328a99abd4c1da728571413", "testharness" ], - "WebCryptoAPI/generateKey/test_successes.html": [ - "6dd8fd836361a4c02c602149fbde996d0131607a", - "testharness" - ], - "WebCryptoAPI/generateKey/test_successes_AES-CBC.html": [ + "WebCryptoAPI/generateKey/test_successes_AES-CBC.https.html": [ "e8ee3bdfb8aef171d6db35cc69a482f1a992d089", "testharness" ], - "WebCryptoAPI/generateKey/test_successes_AES-CTR.html": [ + "WebCryptoAPI/generateKey/test_successes_AES-CTR.https.html": [ "07f55a63a2327ee8804548ba5e802fcdba09010e", "testharness" ], - "WebCryptoAPI/generateKey/test_successes_AES-GCM.html": [ + "WebCryptoAPI/generateKey/test_successes_AES-GCM.https.html": [ "ebec06754972d621026a4284c316c882be362dc3", "testharness" ], - "WebCryptoAPI/generateKey/test_successes_AES-KW.html": [ + "WebCryptoAPI/generateKey/test_successes_AES-KW.https.html": [ "e76258a60418fb1467d16a17b4e01da1d99bd036", "testharness" ], - "WebCryptoAPI/generateKey/test_successes_ECDH.html": [ + "WebCryptoAPI/generateKey/test_successes_ECDH.https.html": [ "b2b7d0a233473a51e67a760638abf1f532d1232b", "testharness" ], - "WebCryptoAPI/generateKey/test_successes_ECDSA.html": [ + "WebCryptoAPI/generateKey/test_successes_ECDSA.https.html": [ "c21190c7c74eb856a9fce3a4913723b46fa1887a", "testharness" ], - "WebCryptoAPI/generateKey/test_successes_HMAC.html": [ + "WebCryptoAPI/generateKey/test_successes_HMAC.https.html": [ "ccfe6cefe42764a46dd817046b026034be033e97", "testharness" ], - "WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html": [ - "7ebe1df33a5df5f5a2cead014af5502246b6b833", + "WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html": [ + "04b89d631e81fd7822049c8513984c3af3711efd", "testharness" ], - "WebCryptoAPI/generateKey/test_successes_RSA-PSS.html": [ + "WebCryptoAPI/generateKey/test_successes_RSA-PSS.https.html": [ "623370ae56918c14ac14f40fb057327b0844be04", "testharness" ], - "WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html": [ + "WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.https.html": [ "ad5db5278bef55d9ae2336961c226199a4c94446", "testharness" ], @@ -139761,6 +144071,10 @@ "52b5381311cc0e2595d251273e054fa826de9765", "testharness" ], + "WebCryptoAPI/idlharness.https.html": [ + "52b5381311cc0e2595d251273e054fa826de9765", + "testharness" + ], "WebCryptoAPI/idlharness.worker.js": [ "e3478f4259364d773dab9ca5e0c7194a0b78d5b3", "testharness" @@ -139789,18 +144103,26 @@ "e9d9758d0478ecdf93a5fda9f196501e992de614", "testharness" ], - "WebCryptoAPI/import_export/test_ec_importKey.html": [ + "WebCryptoAPI/import_export/test_ec_importKey.https.html": [ "2c173849dd35c551b71983fb8efc20f650599da2", "testharness" ], - "WebCryptoAPI/import_export/test_rsa_importKey.html": [ + "WebCryptoAPI/import_export/test_rsa_importKey.https.html": [ "d12cf20829eace56868a7b40d38e75aca89932a6", "testharness" ], - "WebCryptoAPI/import_export/test_symmetric_importKey.html": [ + "WebCryptoAPI/import_export/test_symmetric_importKey.https.html": [ "a69847f41e437363676a4ced439faba50ce85e5d", "testharness" ], + "WebCryptoAPI/secure_context/crypto-subtle-non-secure-context-not-available.sub.html": [ + "e219b5ee2c878779562aded462bfcaa7ad81b63d", + "testharness" + ], + "WebCryptoAPI/secure_context/crypto-subtle-secure-context-available.https.sub.html": [ + "4df3813485b7277571d61ce38a5811729f91ddbe", + "testharness" + ], "WebCryptoAPI/sign_verify/ecdsa.js": [ "55c99894ea3ba9186de1082c189f37f77dfe12e1", "support" @@ -139845,19 +144167,19 @@ "766e1f95031b3f9f3dd5d0e3de8c70f5fdf5ac30", "support" ], - "WebCryptoAPI/sign_verify/test_ecdsa.html": [ + "WebCryptoAPI/sign_verify/test_ecdsa.https.html": [ "969eb4e062dfb91e40be42d4980f0d0e464d5b34", "testharness" ], - "WebCryptoAPI/sign_verify/test_hmac.html": [ + "WebCryptoAPI/sign_verify/test_hmac.https.html": [ "cd105449c7b9b75aa91ee0848fdca5bda78a1aae", "testharness" ], - "WebCryptoAPI/sign_verify/test_rsa_pkcs.html": [ + "WebCryptoAPI/sign_verify/test_rsa_pkcs.https.html": [ "d7840d0a6d848510bf547d64c8b197761f39e05e", "testharness" ], - "WebCryptoAPI/sign_verify/test_rsa_pss.html": [ + "WebCryptoAPI/sign_verify/test_rsa_pss.https.html": [ "408e1a081caa23f7e717128e94eb5cfeae9bac30", "testharness" ], @@ -139866,10 +144188,14 @@ "support" ], "WebCryptoAPI/util/helpers.js": [ - "6bf895ea91bfc92cb346f96af777bc9b8a0af0ee", + "76bfa10171fb405f321d015b4394a2a929d587dd", "support" ], - "WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.html": [ + "WebCryptoAPI/util/worker-report-crypto-subtle-presence.js": [ + "4aacae51744fa0284ebc89c43084c4dae873e5c1", + "support" + ], + "WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.https.html": [ "2f0070bafc5079f3b70dd8da567fde0ea6bfb113", "testharness" ], @@ -139910,13 +144236,21 @@ "testharness" ], "WebIDL/ecmascript-binding/has-instance.html": [ - "4266bf65ad4dd3dd2acaf7b8e0d18e8999f8252b", + "8df0ec18a02041106df53ccc3168261d29ab7943", "testharness" ], "WebIDL/ecmascript-binding/interface-object.html": [ "f68be23702792cb5236e608bf6e8421a9a851fb8", "testharness" ], + "WebIDL/ecmascript-binding/interface-prototype-object.html": [ + "13d2a9dbbd0d78e240c2b88d548f88ba41184e5f", + "testharness" + ], + "WebIDL/ecmascript-binding/legacy-callback-interface-object.html": [ + "4eac8c853a0627577d2bd96ed76c45bd187a5734", + "testharness" + ], "WebIDL/invalid/idl/enum.widl": [ "cebcfcecfe4b09a4d3ea15e766e9b13044dfe0b8", "support" @@ -140506,7 +144840,7 @@ "testharness" ], "XMLHttpRequest/formdata-foreach.html": [ - "0de3e65e068a59180ba03c67ce70e4db8f0bbd87", + "ac4bcf3c043dec99e2feeaeff828ead2db1e9606", "testharness" ], "XMLHttpRequest/formdata-get.htm": [ @@ -140546,7 +144880,7 @@ "testharness" ], "XMLHttpRequest/getresponseheader-chunked-trailer.htm": [ - "ead9af29dd6ece455b2df24367b26f63a991991f", + "37043cc8d180a405eb150b39e2caa5f4f5a0a9c3", "testharness" ], "XMLHttpRequest/getresponseheader-cookies-and-more.htm": [ @@ -140578,7 +144912,7 @@ "testharness" ], "XMLHttpRequest/interfaces.html": [ - "b65e817345a4410c2062242bef57031d4ff448b7", + "a4c597d2bdb85e37ffe5f5ebba961d7f8a3aeb29", "testharness" ], "XMLHttpRequest/loadstart-and-state.html": [ @@ -141517,60 +145851,52 @@ "b960bef807da94c0146ed2f537eaa1e05ec9a0ab", "testharness" ], + "accelerometer/Accelerometer.https.html": [ + "cb802e1f9df53ef6e8e3a34daf54f9e02b019383", + "testharness" + ], + "accelerometer/Accelerometer_insecure_context.html": [ + "62c0fdfe1ee0752956b4c68e877cd7f47ac887a1", + "testharness" + ], + "accelerometer/Accelerometer_onerror-manual.https.html": [ + "e03faad7d297ce2c5d6fefa66a2397c3d9a32e2d", + "manual" + ], "accelerometer/OWNERS": [ "36770a71443523aa2f91f9958ba24066f0b4dcec", "support" ], "accelerometer/idlharness.https.html": [ - "c7d55e65051d370f6a225ae7def35270144fed95", + "eedb225d9e8a05d528e62cc2d689dbfe36858052", "testharness" ], - "ambient-light/AmbientLightSensor.js": [ - "8313b3b63892b2dba96c17ff2fb4c4f5ae107efe", + "accelerometer/support-iframe.html": [ + "5782b270802060f88a1842c2393fb7d18c8c75a8", "support" ], - "ambient-light/AmbientLightSensor_browsing_context.https.html": [ - "2bff26861bbb67c58af6bbb6105bbcd57ac35b6d", + "ambient-light/AmbientLightSensor.https.html": [ + "3bc1a9bbc660ec9ee83f65914c35a52201eccb4b", "testharness" ], "ambient-light/AmbientLightSensor_insecure_context.html": [ - "c546291fd11aeb2e23dd0a68ea02511babedcb7a", - "testharness" - ], - "ambient-light/AmbientLightSensor_onchange.https.html": [ - "b0dae1e2c22f35a0e97dc63529750bc0242e67b3", + "9267bca8016bdde90ba2e5e866e9989db7c045dd", "testharness" ], "ambient-light/AmbientLightSensor_onerror-manual.https.html": [ - "9bbd4281bbab2a1b1a1c34600b0b3d5ea6b99e62", + "fa52072d6da7987db8f67c2a6fd9b2e281f03042", "manual" ], - "ambient-light/AmbientLightSensor_reading.https.html": [ - "36ffed0f2be6b280123a91e8d60740b6a7a95e5d", - "testharness" - ], - "ambient-light/AmbientLightSensor_start.https.html": [ - "b81065b401d4063b2fae2daaec4e7f53da3419ab", - "testharness" - ], - "ambient-light/AmbientLightSensor_stop.https.html": [ - "1068f563e1fe0d7595248086856ea3f3547cf221", - "testharness" - ], - "ambient-light/AmbientLightSensor_tests.html": [ - "1f90699129c27a5a5581a3cd989e097220e54620", - "testharness" - ], "ambient-light/OWNERS": [ "72539a05ddcce7467524b36255696565a2c484e8", "support" ], "ambient-light/idlharness.https.html": [ - "6fa24c2a71228917e83cfb2e44945c466c004959", + "0c0f48d162d3ef69b8fe1486a99cc315fab5ab31", "testharness" ], "ambient-light/support-iframe.html": [ - "ea1cdae3e30c279501483a6680bce50006879da5", + "62024c4c0cff6fb5a21a6db62cd9756de0a2f479", "support" ], "annotation-model/.editorconfig": [ @@ -143569,6 +147895,14 @@ "6c3b89b55e603f7a3556e0c9760c03d270755036", "support" ], + "apng/animated-png-timeout-ref.html": [ + "dcd3c58b9200109868f2b98bda346bf26f823e07", + "support" + ], + "apng/animated-png-timeout.html": [ + "b9ba0287c92e5dbda1dc207ab45e9c90e8618878", + "reftest" + ], "app-uri/OWNERS": [ "e28f77cc2634a830fd6e144e22d9d217e5949b37", "support" @@ -143661,10 +147995,6 @@ "314d421a5544db277664bb55bd04b87e9ed2fdba", "support" ], - "auxclick/auxclick_event-manual.html": [ - "464073435190f51b2725653a0a0589e10f136d2d", - "manual" - ], "background-fetch/OWNERS": [ "0c4e22b970a92b2d77b0f50cc27c2d46aad0b43b", "support" @@ -143777,8 +148107,12 @@ "e70503e7fb71617b9be631d5f2a9e73cacd83e3f", "support" ], + "bluetooth/OWNERS": [ + "ef497e5da8691971c612980bb94eae44fc17c509", + "support" + ], "bluetooth/idl-Bluetooth.html": [ - "cfe60f252017491dc85a00b1eb028fb3fe893c42", + "5d4d8278b1f24798765974c35777f70fcbfc9cfa", "testharness" ], "clear-site-data/navigation.html": [ @@ -143794,7 +148128,7 @@ "support" ], "clipboard/OWNERS": [ - "7c5c92bcb47be9151914d709e2b792a122f07a6e", + "bae753666bda85e9805a5e2fad80ba71459b8aba", "support" ], "common/OWNERS": [ @@ -143805,6 +148139,10 @@ "0516e849d40a16e82e1bb800372df28ed802aa8d", "support" ], + "common/PrefixedPostMessage.js": [ + "2a2e37640bd0089be111d96eeed0b311753e0234", + "support" + ], "common/blank.html": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -143865,6 +148203,14 @@ "a575b8135e6ddb1501fc2a082d7544ee86011b7d", "support" ], + "common/object-association.js": [ + "c6955b7bbf00d73ec5959678391aa59d36da8321", + "support" + ], + "common/performance-timeline-utils.js": [ + "0616ad8871126af7a74ff6937f3f7c623adcbd3e", + "support" + ], "common/redirect-opt-in.py": [ "70caa012fa7b91e20b7a08e3708097d1c1da44a3", "support" @@ -162786,7 +167132,7 @@ "support" ], "content-security-policy/child-src/child-src-allowed.sub.html": [ - "d67e0efa99e43d7be6da5b22c64c0b151001f0b7", + "8e70e19dbaffa7ca6b45b84b860eb11e343ce630", "testharness" ], "content-security-policy/child-src/child-src-allowed.sub.html.sub.headers": [ @@ -162794,7 +167140,7 @@ "support" ], "content-security-policy/child-src/child-src-blocked.sub.html": [ - "b70869e8f1ef02ca477849a776e5cada34a07288", + "19fd649af944749546aee5af41fc2b4d7f135aed", "testharness" ], "content-security-policy/child-src/child-src-blocked.sub.html.sub.headers": [ @@ -162802,7 +167148,7 @@ "support" ], "content-security-policy/child-src/child-src-conflicting-frame-src.sub.html": [ - "a080e3439a0852dbc594ef6d7a7d88e43ad7b09d", + "8c903c4be2ccb11bdaff13fc3ae8690fe04ba755", "testharness" ], "content-security-policy/child-src/child-src-conflicting-frame-src.sub.html.sub.headers": [ @@ -162810,29 +167156,29 @@ "support" ], "content-security-policy/child-src/child-src-cross-origin-load.sub.html": [ - "af56668d75e5ad0b0d51aa24cd66bcadeadd4cb6", + "51bbb0f02e67722433604c78f54a8619cb498dc0", "testharness" ], "content-security-policy/child-src/child-src-cross-origin-load.sub.html.sub.headers": [ "a7b058f47360dee56f92e6caa3cc5eab1dc3706f", "support" ], - "content-security-policy/child-src/child-src-worker-allowed.sub.html": [ - "578f3824687a9fbb2aa7f14bf2a9e8230398bace", + "content-security-policy/child-src/child-src-redirect-blocked.sub.html": [ + "1d7108c31df11379c79181a21a37822a5137fa73", "testharness" ], - "content-security-policy/child-src/child-src-worker-allowed.sub.html.sub.headers": [ - "08ace362a5648dd3375a47fd5081663a2658ba4d", + "content-security-policy/child-src/child-src-redirect-blocked.sub.html.sub.headers": [ + "268d2bc1c16366626596649ea24b776609849f9e", "support" ], + "content-security-policy/child-src/child-src-worker-allowed.sub.html": [ + "da18b70d2f859c83f1599e5f65bfeb67d1183ee4", + "testharness" + ], "content-security-policy/child-src/child-src-worker-blocked.sub.html": [ - "67cea32ca1b0cf32b20b53044b41bbdaad543721", + "16fc87d40c7466de1b59674abc4510c29c7d8cd2", "testharness" ], - "content-security-policy/child-src/child-src-worker-blocked.sub.html.sub.headers": [ - "8d64a8dd0cd9a115342f0ab27ccc4c5eeefd5200", - "support" - ], "content-security-policy/connect-src/connect-src-beacon-blocked.sub.html": [ "0965458e1d32dacec7a9379a7f0e484277389398", "testharness" @@ -162853,8 +167199,12 @@ "70aeb617f5d580917b385346ba629e035f062c32", "testharness" ], + "content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html": [ + "3747c23fd624aefa80c2906095084e843843f3d8", + "testharness" + ], "content-security-policy/embedded-enforcement/embedding_csp-header.html": [ - "f3df200f0162d3e9a1cc2d944b3a821126105d59", + "3a9f255c0b99f7750fe487ae6e68063954184d05", "testharness" ], "content-security-policy/embedded-enforcement/iframe-csp-attribute.html": [ @@ -162945,80 +167295,172 @@ "888d3e58d3d094b767067e16494803af432ee057", "testharness" ], - "content-security-policy/frame-ancestors/deep-allows-none.sub.html": [ - "d23db3fa139be3bc1c5b82676f3a8f425c40f9ed", + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html": [ + "e96b19c03463de925f03a666a173e948c0908302", "testharness" ], - "content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-self.sub.html": [ - "d9c576acb4ccae793afd83bd0b3d4cbe0040a2c4", - "support" - ], - "content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-self.sub.html.headers": [ - "33033f27634749dc56a2b6f3b08a7a127b422013", - "support" - ], - "content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-star.sub.html": [ - "1d5a4c537f8189b75a1caacdbbac5ba912f257d2", - "support" - ], - "content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-star.sub.html.headers": [ - "02b7f7088d6a2bcd97108c12586bd8ec28cc256b", - "support" - ], - "content-security-policy/frame-ancestors/multiple-frames-meta-ignored.sub.html": [ - "0c5c46e42deb18e0fd296137f64392da6afab2eb", + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html": [ + "816ef071086019d9abed995370cb39a8542f3322", "testharness" ], - "content-security-policy/frame-ancestors/multiple-frames-one-blocked.sub.html": [ - "fb6f8e23e5b32547c861e5e735ce68be306589fc", + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-star-allow.html": [ + "ecaa1cfb71b73c1ec55cdf7d8eb1058469897807", "testharness" ], - "content-security-policy/frame-ancestors/multiple-frames-self-allowed.sub.html": [ - "27b683b95dcb4f08c79c135c3558c7c26f0f600e", + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-allow.html": [ + "928e1285169b1d137550f67c083c6ba4eb532b6c", "testharness" ], - "content-security-policy/frame-ancestors/nested-traversing-allowed.sub.html": [ - "29f8bdb4197d807aabe50a98b2701b3785a336b5", + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block.html": [ + "46a056e57129f76eabf6b53b833a24b1a861ed91", "testharness" ], - "content-security-policy/frame-ancestors/nested-traversing-banned-top-is-self.sub.html": [ - "ea3b49d5e380f1a99dd632e339b4eae8e2426095", + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html": [ + "486eaffb8f7c9e28861adeef5e2af6777be73ee6", "testharness" ], - "content-security-policy/frame-ancestors/nested-traversing-banned.sub.html": [ - "d7ccb938da839e1d2190cabc1682f1f2fb1ed412", + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block.html": [ + "9c40ca204dae2de593f46b723dc7e6bfa8f8e8fd", "testharness" ], - "content-security-policy/frame-ancestors/reporting-frame-allows-none-meta.html": [ - "4b8a46a45417a77b64d4b6f6d74033da0b170236", + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html": [ + "03ea8e9bd6c19aff4ceac59b178b1ef065afeedc", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow.html": [ + "f7a44723534d82a650cf8853d6cb114b46f1b535", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block.html": [ + "37ead57a4f508fd817541ecb2b2576b7fe65532f", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html": [ + "4aee1e3833591c74694a3c960bd32c1047a8546f", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block.html": [ + "2a831ff6c6a9b0a7c63b427105a077ffedbb46e1", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block.html": [ + "332a0a289180b90d14bdb1f4b13c8225b9a810f5", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-star-allow.html": [ + "c8f8c077f2c8d5c55926dc03b084651313806240", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-allow.html": [ + "d8aa43dbab2fd38dd1b7b3ac004dddbf20b3a247", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block.html": [ + "e3ab2ece1d6db2be49a25a0f46c98d3fd07fa1e7", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block.html": [ + "035865df4a43600910890fed3856fadaf05fd7b7", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-self-allow.html": [ + "79e712e18213a4eb754dc32c32ca864fbb2e4a9f", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-star-allow.html": [ + "ccec99fbc0f7dc7d0b0dcab855ab0d128eee2414", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-allow.html": [ + "c5d24d65811915fff1fafff89f29c6287abaf6d8", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block.html": [ + "c6d7b2b67f933e00feadefa00263cc3b17443395", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-none-block.html": [ + "b5d0f5f0923f8c1e3400d91f6194f665d7a30a97", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-overrides-xfo.html": [ + "53ecb1ec56471ef236ca760437f16ed758c539f8", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-self-allow.html": [ + "635dd6a6ae1cc8f51fad8b9c0cdcaf7d2b8322b4", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-self-block.html": [ + "31b16e7e4c7113ec27cba6c0b880b2472fbc174b", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin.html": [ + "6af460fa2c57111abbc8f3ceeb09b31993821b22", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-star-allow-sameorigin.html": [ + "cf1d2e99cca0ca2bd4582f903eba3d585bcf91ce", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-url-allow.sub.html": [ + "e0921d30fdb2e9739497849133e93d49486cd417", + "testharness" + ], + "content-security-policy/frame-ancestors/frame-ancestors-url-block.html": [ + "f7b54ddb5688e4706d078538af1f16f2b82d3375", + "testharness" + ], + "content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html": [ + "2d370eb5855e59d75e3cd6658632dc8f69a35f3c", "support" ], - "content-security-policy/frame-ancestors/reporting-frame-allows-none.html": [ - "0b918917b5d811cf5099ac12348e47536b3e68df", + "content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html.sub.headers": [ + "48593d685ee69fd82565cf4c85c73ebc89309208", "support" ], - "content-security-policy/frame-ancestors/reporting-frame-allows-none.html.headers": [ - "5cfa9dcd8b15e16c44de2de76890b1ff08d85eb4", + "content-security-policy/frame-ancestors/support/frame-ancestors-test.sub.js": [ + "4dde1455ac8238da8c93cadfe7e2b544240d79a7", "support" ], - "content-security-policy/frame-ancestors/reporting-frame-allows-self.html": [ - "e88d74699b1a7b82369803ba2f27e6dee827258d", + "content-security-policy/frame-ancestors/support/frame-ancestors.sub.html": [ + "5e797157ef603dbdb9c3b3637d2a372c5d984433", "support" ], - "content-security-policy/frame-ancestors/reporting-frame-allows-self.html.headers": [ - "33033f27634749dc56a2b6f3b08a7a127b422013", + "content-security-policy/frame-ancestors/support/frame-ancestors.sub.html.sub.headers": [ + "3894c3bffcd450e30dcb7e04141e929ae9a522e9", "support" ], - "content-security-policy/frame-ancestors/single-frame-self-allowed.sub.html": [ - "b1f0ad6923b1078392704c198463fd259a82e974", + "content-security-policy/frame-ancestors/support/frame-in-frame.sub.html": [ + "22b75d559bd9a62619ca7c970c139775e6da7f48", + "support" + ], + "content-security-policy/frame-ancestors/support/frame-in-frame.sub.html.sub.headers": [ + "51e1354d16cfa4967e91206be8bd0d8c6ca577af", + "support" + ], + "content-security-policy/frame-src/frame-src-redirect.html": [ + "16ac0d81d039fc2514b72a68fa491159ad46f59c", "testharness" ], + "content-security-policy/frame-src/frame-src-redirect.html.headers": [ + "3df52b9299a0ada67d3211c5190269fa8b046211", + "support" + ], + "content-security-policy/frame-src/support/frame.html": [ + "3f5fd74f92250b09f2dd790d154ade7bc4748d78", + "support" + ], + "content-security-policy/frame-src/support/testharness-helper.sub.js": [ + "c11acf3aff5ffaf1a581ff8c73f077b7c0ee0a26", + "support" + ], "content-security-policy/generic/fail-0_1.js": [ "357bbab837dcc2794a46fb07e31ea49b16b447cf", "support" ], "content-security-policy/generic/generic-0_1-img-src.html": [ - "0af19ad686c41332aa090ba3cfe240ecd9f990ff", + "b9e456586e6acc8f56864ab36bea8c9ff67b3959", "testharness" ], "content-security-policy/generic/generic-0_1-img-src.html.sub.headers": [ @@ -163026,7 +167468,7 @@ "support" ], "content-security-policy/generic/generic-0_1-script-src.html": [ - "cb2a8523a7519c3b0458f726aa97bca08ac92c3c", + "d1d01090fb8ae7f33357d0d4d75e2606d637a881", "testharness" ], "content-security-policy/generic/generic-0_1-script-src.html.sub.headers": [ @@ -163309,6 +167751,18 @@ "91c932641750d0b053ca8ff8bc5d102025c3fdc9", "support" ], + "content-security-policy/script-src/crossoriginScript.js": [ + "982c87aacdeb92f948ce54283e989b0210835ca8", + "support" + ], + "content-security-policy/script-src/crossoriginScript.js.headers": [ + "90d51a5e46cc58404dd5ec1e9e4e10934a6c0707", + "support" + ], + "content-security-policy/script-src/externalScript.js": [ + "9747ab396294e301c0f0720a3c0731d92272ee54", + "support" + ], "content-security-policy/script-src/inlineSuccessTest.js": [ "a591a02337841f6e8e822174a390a723ee6a3656", "support" @@ -163389,6 +167843,14 @@ "4c2700452b8e0cb5451ee00aaa8ff92f12e9623e", "support" ], + "content-security-policy/script-src/script-src-sri_hash.sub.html": [ + "c720b6a69726026ea34545b94bcdc7cef443c453", + "testharness" + ], + "content-security-policy/script-src/script-src-sri_hash.sub.html.sub.headers": [ + "40b849448eb8f0ec56795ca51b0813b3159a01a9", + "support" + ], "content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_eval.html": [ "36d44f22b3f4ae8a26509613426b76cdd3d1a41f", "testharness" @@ -163517,6 +167979,10 @@ "a50a792b1ef19fe452196e5e50036d6de01dc6e5", "support" ], + "content-security-policy/script-src/script-src-strict_dynamic_worker.https.html": [ + "a59f7f33614eb541a216b317f0916271f359ba1b", + "testharness" + ], "content-security-policy/script-src/simpleSourcedScript.js": [ "549c6ea1f1bae2b78f933b5da0a5f2f72bae2564", "support" @@ -163533,6 +167999,14 @@ "5f2ff4a87aa476168cf3d13b10a8d81a387b8e42", "testharness" ], + "content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html": [ + "e338e94ea726419db64ed5b98c95b862c394409e", + "testharness" + ], + "content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers": [ + "960ee8a9f7ccf33ea435890e2eae0e68399f32ed", + "support" + ], "content-security-policy/securitypolicyviolation/inside-dedicated-worker.html": [ "46d18c97d554716b714856c00bdc49388d211868", "testharness" @@ -163585,10 +168059,22 @@ "ac19897e2693ba3228640d03c770cd5a33c51381", "support" ], + "content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js": [ + "71244cc74fa8f8ee8082c876264e053348905fbd", + "support" + ], "content-security-policy/securitypolicyviolation/targeting.html": [ "36ec8dd9ef0bd1be3615913015d857aa1a7c9e97", "testharness" ], + "content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html": [ + "ec7ce3c14a571eae99473dd595a39c2019ba9e36", + "testharness" + ], + "content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers": [ + "6e15d48ddd21d1bbb9603081d5d7fef98ebfa106", + "support" + ], "content-security-policy/style-src/resources/style-src-import.sub.css": [ "37de4f39b0399d9a5a230b5446883f9e4b49a061", "support" @@ -163745,6 +168231,18 @@ "071616b3c0e43fab0b7a214000389585dafc393d", "support" ], + "content-security-policy/support/post-message.js": [ + "c957a15a1c7a0c5dffc9e7a13d54da243ca9a93a", + "support" + ], + "content-security-policy/support/postmessage-fail.html": [ + "5ccfe2ec548aa6e16649c319c8252e608777fe64", + "support" + ], + "content-security-policy/support/postmessage-pass.html": [ + "ddfde964afded9ff5189c8c7554bcb2b1b1e5938", + "support" + ], "content-security-policy/support/report.py": [ "8cd779a8017cba678a565475271b892e8ed53e58", "support" @@ -163773,6 +168271,10 @@ "ad81dd10fd77548004d7808bf176b89fe6002fa4", "support" ], + "content-security-policy/svg/object-in-svg-foreignobject.sub.html": [ + "a16c20b420126d3b910f429707aca671562e7939", + "testharness" + ], "content-security-policy/svg/scripted.svg": [ "e5a26ca493e75cb4245e9f0de986cde3ab697d62", "support" @@ -163918,7 +168420,7 @@ "support" ], "cors/allow-headers.htm": [ - "7152e6c95f03ce5bec3fb85473ea800b949ca935", + "e28cf5812e58e490ec28bb407c4575f3d33687dc", "testharness" ], "cors/basic.htm": [ @@ -163934,7 +168436,7 @@ "testharness" ], "cors/origin.htm": [ - "56eb70e8dcb45b72fd16150810c59e43b6abc2de", + "4fd804db576f22f4afc4ebc9f339341969322dbb", "testharness" ], "cors/preflight-cache.htm": [ @@ -163966,7 +168468,7 @@ "testharness" ], "cors/request-headers.htm": [ - "d5166a2dc96a5742c5320b9a61d6e75650a9d49d", + "56de3a6d1f3e96750f35cc2cacbdbb9b13e32f3f", "testharness" ], "cors/resources/.gitignore": [ @@ -164029,6 +168531,18 @@ "8307ed240a531033c96da89197dcfb5ea25cde87", "support" ], + "credential-management/idl.https.html": [ + "c9664273f5786aae604f86c136197e0ee5270a71", + "testharness" + ], + "css-font-loading/fontfacesetloadevent-constructor.html": [ + "ad355c3d5220c1b938182241a8e8abe030ace699", + "testharness" + ], + "css-paint-api/OWNERS": [ + "0c1517f7ba747014c7c091b61d48f11421ed91c2", + "support" + ], "css-timing-1/OWNERS": [ "7c9899aa9065ffe6e1206b630124d4939ae53c8f", "support" @@ -164945,24 +169459,72 @@ "538b95863c061da60e95c1a61ef9dc93da007aa4", "testharness" ], + "cssom-view/CaretPosition-001.html": [ + "182826b894852721a2efa7eaa0a3437904f13dbc", + "testharness" + ], "cssom-view/HTMLBody-ScrollArea_quirksmode.html": [ "cfe4e07fb9efa140a55175d3cf50ceaced93e1c9", "testharness" ], + "cssom-view/MediaQueryList-001.html": [ + "4b209fa18eda5f0c50639357e9851de28e545cf7", + "testharness" + ], "cssom-view/MediaQueryList-with-empty-string.html": [ "034fd2a3b8da32d4b2ef0465fe4361c424c6ad3d", "testharness" ], "cssom-view/OWNERS": [ - "c9aad9e1cbfa2cf07f24daf4ff61718696f8d1bd", + "083538f652edfeea9bde3d5d9f56667bc3773f6a", "support" ], + "cssom-view/Screen-pixelDepth-Screen-colorDepth001.html": [ + "256c4441e6f933c058065c2bea85d37acaa67a6f", + "testharness" + ], + "cssom-view/cssom-getBoundingClientRect-001.html": [ + "7118495560adadebcca98e6add47a74669f87788", + "testharness" + ], + "cssom-view/cssom-getBoundingClientRect-002.html": [ + "8dfaa313b4abad30281d07ce22ac06a61754cc06", + "testharness" + ], + "cssom-view/cssom-getClientRects.html": [ + "f4e750bc1267f5c519a513ef1f25bf3660365788", + "testharness" + ], + "cssom-view/cssom-view-img-attributes-001.html": [ + "d645ca84f24755ba4f583e47a42422fb1eaadbb9", + "testharness" + ], + "cssom-view/cssom-view-window-screen-interface.html": [ + "8fb3e3327f8f657e2215c91c75f49fd739c15c57", + "testharness" + ], + "cssom-view/cssom-view/media-query-list-interface.xht": [ + "62f0fdd48d1a4194d439ee22829b3346bed9a154", + "testharness" + ], + "cssom-view/cssom-view/window-interface.xht": [ + "4d8c4ddb997d85ca2c971602a3096f57565c01eb", + "testharness" + ], + "cssom-view/elementFromPoint-001.html": [ + "bf1c490777f450275a95ecfc6d6d2c0d055aca82", + "testharness" + ], "cssom-view/elementFromPoint.html": [ "e22ae99aa1fba51807aec245b810db5d584ac037", "testharness" ], + "cssom-view/elementFromPosition.html": [ + "d90dff8b15ec2977f341a7add9c7d627b62d9d0f", + "testharness" + ], "cssom-view/elementScroll.html": [ - "5471dca08aae9d446c487d40853957e9290677f3", + "24c65428976fc4971a33368e6bf6f8b77199d69b", "testharness" ], "cssom-view/elementsFromPoint.html": [ @@ -164973,10 +169535,22 @@ "1d88b7050e61c06aae97c42251401e1d6acb7f06", "testharness" ], + "cssom-view/htmlelement-offset-width-001.html": [ + "071bcc0320577077bc6768921f28e33e892ccd9a", + "testharness" + ], "cssom-view/iframe.html": [ "81c8e70138fc30d0954d9de692ee396310586c7f", "support" ], + "cssom-view/matchMedia.xht": [ + "3330cf1603555d50d097cdc584cf1c193c8b32d3", + "testharness" + ], + "cssom-view/matchMediaAddListener.html": [ + "ec5b756e980676c8707bcb2d7d91b7c977158e0d", + "testharness" + ], "cssom-view/mouseEvent.html": [ "d64c45f021a5c6db7b65575288a91e28a25a2982", "testharness" @@ -164985,14 +169559,230 @@ "ad44e3f4ba132bfb4a522b14a4ff5356dbbbad14", "testharness" ], + "cssom-view/offsetParent_element_test.html": [ + "6e7579de7add0162ac99f3326f070bbd6051932b", + "testharness" + ], + "cssom-view/scrollWidthHeight.xht": [ + "06ec592720f3db3c04cdd792177179b11a097a23", + "testharness" + ], + "cssom-view/scrollWidthHeightWhenNotScrollable.xht": [ + "dfac20693a9d2bcbc74e372177b1a04472de8f8f", + "testharness" + ], "cssom-view/scrolling-no-browsing-context.html": [ "1b504d68ded5e70043da04e89b77342585144f4b", "testharness" ], + "cssom-view/scrolling-quirks-vs-nonquirks.html": [ + "a799c737e7962865c3ed3e380a664cafe97dcfe8", + "testharness" + ], "cssom-view/scrollingElement.html": [ "e3bc7ab9a646c1275e5dab9394df97d72ef8a42e", "testharness" ], + "cssom-view/support/1x1-green.png": [ + "51e7b6974a09eda6cb31337717c5eaeb9c44b443", + "support" + ], + "cssom-view/support/1x1-lime.png": [ + "b040eb633a35c0648ad72a2902361faf25bc419d", + "support" + ], + "cssom-view/support/1x1-maroon.png": [ + "f78757e5ebe897bd618d100718385c84e00f2369", + "support" + ], + "cssom-view/support/1x1-navy.png": [ + "a3fd80b2c79866fd343e18eef5a51ed6e835e53e", + "support" + ], + "cssom-view/support/1x1-red.png": [ + "b8da86921d04ba42f42b0a60b03c5c2172f58c2b", + "support" + ], + "cssom-view/support/1x1-white.png": [ + "71b246439f915ad21c7d39414d9f85c8ed73b4ca", + "support" + ], + "cssom-view/support/60x60-gg-rr.png": [ + "e4843d42a26189132e1bdd53e8618521330baeca", + "support" + ], + "cssom-view/support/60x60-green.png": [ + "2f8eb2409b0a18e0bff90725ec7eedc16e7be448", + "support" + ], + "cssom-view/support/60x60-red.png": [ + "415b835abaaab822aab11880354296e7356bbb0a", + "support" + ], + "cssom-view/support/README": [ + "c46bfcee920aef0b9167764ec78c699ed217c8f2", + "support" + ], + "cssom-view/support/a-green.css": [ + "a9716c222274ba868bfd06c05e28cb7762d93245", + "support" + ], + "cssom-view/support/b-green.css": [ + "eb78a4d12f35b4249051826ea000c53d04df80b7", + "support" + ], + "cssom-view/support/c-red.css": [ + "dc288b7aa49b57e0abf803741e78582ba5ceffdb", + "support" + ], + "cssom-view/support/cat.png": [ + "461fd17b274662b88500cdf42bab7f3b79e6019d", + "support" + ], + "cssom-view/support/import-green.css": [ + "db4f420efdb292d6520be1a3bf052ed3f6f9e7e3", + "support" + ], + "cssom-view/support/import-red.css": [ + "0f2b9133fcfa22d5506a5cee307bd1a4d50e87e9", + "support" + ], + "cssom-view/support/pattern-grg-rgr-grg.png": [ + "cfb6ecc271c296c69b133a81f350a777b608bea4", + "support" + ], + "cssom-view/support/pattern-grg-rrg-rgg.png": [ + "27080d4df556f59d4b501e03f2847bd9da5756a9", + "support" + ], + "cssom-view/support/pattern-rgr-grg-rgr.png": [ + "c100a35c361205932c506f1b3399753b91e4c45e", + "support" + ], + "cssom-view/support/pattern-tr.png": [ + "c1e687deee7b79ae091f2b42c4f6cff430076444", + "support" + ], + "cssom-view/support/ruler-h-50%.png": [ + "9364be82a07500d6684a275174bcf5185444cb52", + "support" + ], + "cssom-view/support/ruler-h-50px.png": [ + "b3d7cc680b20a5fc44ea93f7df6d33894bc7b09b", + "support" + ], + "cssom-view/support/ruler-v-100px.png": [ + "d8b49696edb2bd614e9c00f96e7862798b6e621f", + "support" + ], + "cssom-view/support/ruler-v-50px.png": [ + "eb299dc261ec04c8f2c11afb6f7a1c2ec147587b", + "support" + ], + "cssom-view/support/square-purple.png": [ + "ef0619128f22e05920930420b7d96f91f860d904", + "support" + ], + "cssom-view/support/square-teal.png": [ + "92efae44b710cf1ddd9ba96e593dae03fb2519c4", + "support" + ], + "cssom-view/support/square-white.png": [ + "2f93fcc1462ba32b9b7899e5e78c869e529e68ee", + "support" + ], + "cssom-view/support/support/README": [ + "18698bf71d328054eba0b473486058bc9286c1a4", + "support" + ], + "cssom-view/support/support/swatch-green.png": [ + "eedea3e9a99c18f5fc2de3796be2c6f9da2ea07d", + "support" + ], + "cssom-view/support/support/swatch-red.png": [ + "c51a03a807743f59e3027371ccfbd8e80235a485", + "support" + ], + "cssom-view/support/swatch-blue.png": [ + "e79958e10feeeed3db88dee9bae9ea80055593c5", + "support" + ], + "cssom-view/support/swatch-green.png": [ + "c51a03a807743f59e3027371ccfbd8e80235a485", + "support" + ], + "cssom-view/support/swatch-lime.png": [ + "ee2cc3dcd6d8dda7c0e4ef3bbc7e63c74118211d", + "support" + ], + "cssom-view/support/swatch-orange.png": [ + "10768a5177b772013e628c7397ae64725057295d", + "support" + ], + "cssom-view/support/swatch-red.png": [ + "eedea3e9a99c18f5fc2de3796be2c6f9da2ea07d", + "support" + ], + "cssom-view/support/swatch-teal.png": [ + "994cd98028aff20822f2dca5a6058fb616bf5ce4", + "support" + ], + "cssom-view/support/swatch-white.png": [ + "5bccb1922de065e551d7d106e6493bb91040f3da", + "support" + ], + "cssom-view/support/swatch-yellow.png": [ + "9cc73897c2e1fc45f5224d81d02a6b87bf72b1fa", + "support" + ], + "cssom-view/support/test-bl.png": [ + "16e4eaa4864c10e72433e575f59c9b67763fe06a", + "support" + ], + "cssom-view/support/test-br.png": [ + "37f65e7a21d9b9b2daa508f193b8f665c58a1ce9", + "support" + ], + "cssom-view/support/test-inner-half-size.png": [ + "4ed63dd2bb54a8efc166719e00e1e27406b0ee59", + "support" + ], + "cssom-view/support/test-outer.png": [ + "a0b8dfa40065b27f1d939ce0aab39ada3933c574", + "support" + ], + "cssom-view/support/test-tl.png": [ + "956e5156fd8c0e75b1c0f3b8b3b900b653663f74", + "support" + ], + "cssom-view/support/test-tr.png": [ + "078e1dd6dd61d36cec239ed75d02051f61fe60a5", + "support" + ], + "cssom-view/ttwf-js-cssomview-getclientrects-length.html": [ + "7f3440e65abbe692e3c28f1f1d04671054ecc815", + "testharness" + ], + "cssom-view/ttwf-scrollintoview.html": [ + "55d874f53db3c8ed03fff063584eecbcda10d2ce", + "testharness" + ], + "cssom-view/window-screen-height-immutable.html": [ + "3193a200624217a260e17660006e9ce31a52814c", + "testharness" + ], + "cssom-view/window-screen-height.html": [ + "c5b24034e81ae8be76d66c7097092e8ce801a622", + "testharness" + ], + "cssom-view/window-screen-width-immutable.html": [ + "b44c4dead8c8779521f3f6983823cdc6cfab75b5", + "testharness" + ], + "cssom-view/window-screen-width.html": [ + "a3529271f75eecb40da8ec1975202d8aa07b5d4a", + "testharness" + ], "cssom/CSS.html": [ "2c55d573bbd90f5ca3e564131ae697b547e4a43c", "testharness" @@ -165002,7 +169792,7 @@ "testharness" ], "cssom/CSSKeyframesRule.html": [ - "3efb8e5cef257a0b433192742d526709357b24c7", + "bca997a63c1389ef6d14aac2f32ab770fbd15ec4", "testharness" ], "cssom/CSSNamespaceRule.html": [ @@ -165014,7 +169804,7 @@ "testharness" ], "cssom/CSSStyleRule.html": [ - "f5767d7b9e7e32ad3b74b316e02f16ec625fa7e5", + "b7cfe3da8454d5c64a25c440e0776c80d8c3a751", "testharness" ], "cssom/CSSStyleSheet.html": [ @@ -165025,10 +169815,66 @@ "21d9e43514fb3a7fbf8933429242dc544224ef24", "testharness" ], + "cssom/MediaList.xhtml": [ + "277ec40d3a64d9881e594901a6bcdcd6b70405db", + "testharness" + ], + "cssom/OWNERS": [ + "504fa320d984433da43ab370215ecc2ee29ef66d", + "support" + ], "cssom/StyleSheetList.html": [ "3a0e6f64f70f863d679e537c4bfb76aaa0d3598a", "testharness" ], + "cssom/computed-style-001.html": [ + "a940a84552ddcd716af743e0e8746c7582b5c760", + "testharness" + ], + "cssom/css-style-attribute-modifications.html": [ + "9199534f3b6cc473832562b1701ade3a05dde172", + "testharness" + ], + "cssom/css-style-declaration-modifications.html": [ + "c169d758c1d91b75697b04cf72750f8ac1650e1a", + "testharness" + ], + "cssom/cssimportrule.html": [ + "da36c32a7ecad7542c73572917709ee394dc843c", + "testharness" + ], + "cssom/cssom-cssText-serialize.html": [ + "66ad91da39c1e1da9021f6443e9b6d34baf57dcb", + "testharness" + ], + "cssom/cssom-cssstyledeclaration-set.html": [ + "12f5dce3d37a718ac5c872f662cc9f3d9cf09179", + "testharness" + ], + "cssom/cssom-fontfacerule-constructors.html": [ + "c064661df74571d374f49a693f3263fcf138e670", + "testharness" + ], + "cssom/cssom-fontfacerule.html": [ + "965a8f6289fa5c6e34bfd447de3b8ef86573fea1", + "testharness" + ], + "cssom/cssom-setProperty-shorthand.html": [ + "14c752e5dbeab2d58983d53aceab08519379bf0f", + "testharness" + ], + "cssom/cssstyledeclaration-csstext.html": [ + "aa2adbfcc58f3a844e2e1f2c96e5efed2c81f2c3", + "testharness" + ], + "cssom/cssstyledeclaration-mutability.html": [ + "5f29436964d01c57f61d513cee5b83281643ac54", + "testharness" + ], + "cssom/escape.html": [ + "c9ed57c7ef7a035c25feff4ea60547a57d727f31", + "testharness" + ], "cssom/getComputedStyle-pseudo.html": [ "6c74e57a2e32a13cc3b7e955a2d89dafdf6d1730", "testharness" @@ -165037,22 +169883,78 @@ "2c78218b89efb9bdf60cf708920be142051347c7", "testharness" ], + "cssom/index-001.html": [ + "ab9e9f102f5909d9b5587f2c0ea54c0c6b59868d", + "testharness" + ], + "cssom/index-002.html": [ + "fe12bc0005ccfccfafd4f23644b28fbb5f5e33d1", + "testharness" + ], + "cssom/index-003.html": [ + "f55d9bc5b2e25b1af5169ecc164f62b6a95abfe5", + "testharness" + ], + "cssom/inline-style-001.html": [ + "377c8610bc597d47a93f70a9cf95b3c7657d8319", + "testharness" + ], + "cssom/interfaces.html": [ + "5876c88acd95d18166fdd049bdb3f09cdde4eb3f", + "testharness" + ], + "cssom/medialist-interfaces-001.html": [ + "dfaea262508d72d123006409174e3e21832a305f", + "testharness" + ], + "cssom/medialist-interfaces-002.html": [ + "114fac94342afe2e7fe432a67c4b0bbf03d24bc4", + "testharness" + ], + "cssom/medialist-interfaces-003.html": [ + "b9ddd611cc585202b1e76382666b04197af334b0", + "testharness" + ], + "cssom/medialist-interfaces-004.html": [ + "e3cdc88670ca46b3752fd8118d94dae2cc95258d", + "testharness" + ], "cssom/overflow-serialization.html": [ "199039706289f577652b968706fc1251398acd1c", "testharness" ], + "cssom/selectorSerialize.html": [ + "002777c7c598eb1131ab625365ee3fe08650e830", + "testharness" + ], "cssom/serialization-CSSDeclaration-with-important.html": [ "ecc8b95fb2d71cacee271f4fea2fc16f35cdba57", "testharness" ], + "cssom/serialize-namespaced-type-selectors.html": [ + "51f6a0c4a0c693338245409c60784f1a73fafb76", + "testharness" + ], "cssom/serialize-values.html": [ "329fe02cb9e54b1a24a8f9dedcfcf5c0f61c7f24", "testharness" ], + "cssom/serialize-variable-reference.html": [ + "5e83f084efc82184c3052a40bb4a061fd4a1336f", + "testharness" + ], "cssom/shorthand-serialization.html": [ "bd514834dbd48c267c16a4329af6fec7f6cbc081", "testharness" ], + "cssom/style-sheet-interfaces-001.html": [ + "15509e87505d5a22d4f6dbbffcc90c24fcee642a", + "testharness" + ], + "cssom/style-sheet-interfaces-002.html": [ + "875598ca4271d4adaa11fbb01981b290e6235019", + "testharness" + ], "cssom/stylesheet-same-origin.css": [ "268fb9a72d33b3d18bbb82aaaac48bb15c89a88e", "support" @@ -165061,6 +169963,194 @@ "719c525b1af3b6b46dfeeb0627034d799bab50b5", "testharness" ], + "cssom/support/1x1-green.png": [ + "51e7b6974a09eda6cb31337717c5eaeb9c44b443", + "support" + ], + "cssom/support/1x1-lime.png": [ + "b040eb633a35c0648ad72a2902361faf25bc419d", + "support" + ], + "cssom/support/1x1-maroon.png": [ + "f78757e5ebe897bd618d100718385c84e00f2369", + "support" + ], + "cssom/support/1x1-navy.png": [ + "a3fd80b2c79866fd343e18eef5a51ed6e835e53e", + "support" + ], + "cssom/support/1x1-red.png": [ + "b8da86921d04ba42f42b0a60b03c5c2172f58c2b", + "support" + ], + "cssom/support/1x1-white.png": [ + "71b246439f915ad21c7d39414d9f85c8ed73b4ca", + "support" + ], + "cssom/support/60x60-gg-rr.png": [ + "e4843d42a26189132e1bdd53e8618521330baeca", + "support" + ], + "cssom/support/60x60-green.png": [ + "2f8eb2409b0a18e0bff90725ec7eedc16e7be448", + "support" + ], + "cssom/support/60x60-red.png": [ + "415b835abaaab822aab11880354296e7356bbb0a", + "support" + ], + "cssom/support/README": [ + "c46bfcee920aef0b9167764ec78c699ed217c8f2", + "support" + ], + "cssom/support/a-green.css": [ + "a9716c222274ba868bfd06c05e28cb7762d93245", + "support" + ], + "cssom/support/b-green.css": [ + "eb78a4d12f35b4249051826ea000c53d04df80b7", + "support" + ], + "cssom/support/c-red.css": [ + "dc288b7aa49b57e0abf803741e78582ba5ceffdb", + "support" + ], + "cssom/support/cat.png": [ + "461fd17b274662b88500cdf42bab7f3b79e6019d", + "support" + ], + "cssom/support/import-green.css": [ + "db4f420efdb292d6520be1a3bf052ed3f6f9e7e3", + "support" + ], + "cssom/support/import-red.css": [ + "0f2b9133fcfa22d5506a5cee307bd1a4d50e87e9", + "support" + ], + "cssom/support/pattern-grg-rgr-grg.png": [ + "cfb6ecc271c296c69b133a81f350a777b608bea4", + "support" + ], + "cssom/support/pattern-grg-rrg-rgg.png": [ + "27080d4df556f59d4b501e03f2847bd9da5756a9", + "support" + ], + "cssom/support/pattern-rgr-grg-rgr.png": [ + "c100a35c361205932c506f1b3399753b91e4c45e", + "support" + ], + "cssom/support/pattern-tr.png": [ + "c1e687deee7b79ae091f2b42c4f6cff430076444", + "support" + ], + "cssom/support/ruler-h-50%.png": [ + "9364be82a07500d6684a275174bcf5185444cb52", + "support" + ], + "cssom/support/ruler-h-50px.png": [ + "b3d7cc680b20a5fc44ea93f7df6d33894bc7b09b", + "support" + ], + "cssom/support/ruler-v-100px.png": [ + "d8b49696edb2bd614e9c00f96e7862798b6e621f", + "support" + ], + "cssom/support/ruler-v-50px.png": [ + "eb299dc261ec04c8f2c11afb6f7a1c2ec147587b", + "support" + ], + "cssom/support/square-purple.png": [ + "ef0619128f22e05920930420b7d96f91f860d904", + "support" + ], + "cssom/support/square-teal.png": [ + "92efae44b710cf1ddd9ba96e593dae03fb2519c4", + "support" + ], + "cssom/support/square-white.png": [ + "2f93fcc1462ba32b9b7899e5e78c869e529e68ee", + "support" + ], + "cssom/support/support/README": [ + "18698bf71d328054eba0b473486058bc9286c1a4", + "support" + ], + "cssom/support/support/swatch-green.png": [ + "eedea3e9a99c18f5fc2de3796be2c6f9da2ea07d", + "support" + ], + "cssom/support/support/swatch-red.png": [ + "c51a03a807743f59e3027371ccfbd8e80235a485", + "support" + ], + "cssom/support/swatch-blue.png": [ + "e79958e10feeeed3db88dee9bae9ea80055593c5", + "support" + ], + "cssom/support/swatch-green.png": [ + "c51a03a807743f59e3027371ccfbd8e80235a485", + "support" + ], + "cssom/support/swatch-lime.png": [ + "ee2cc3dcd6d8dda7c0e4ef3bbc7e63c74118211d", + "support" + ], + "cssom/support/swatch-orange.png": [ + "10768a5177b772013e628c7397ae64725057295d", + "support" + ], + "cssom/support/swatch-red.png": [ + "eedea3e9a99c18f5fc2de3796be2c6f9da2ea07d", + "support" + ], + "cssom/support/swatch-teal.png": [ + "994cd98028aff20822f2dca5a6058fb616bf5ce4", + "support" + ], + "cssom/support/swatch-white.png": [ + "5bccb1922de065e551d7d106e6493bb91040f3da", + "support" + ], + "cssom/support/swatch-yellow.png": [ + "9cc73897c2e1fc45f5224d81d02a6b87bf72b1fa", + "support" + ], + "cssom/support/test-bl.png": [ + "16e4eaa4864c10e72433e575f59c9b67763fe06a", + "support" + ], + "cssom/support/test-br.png": [ + "37f65e7a21d9b9b2daa508f193b8f665c58a1ce9", + "support" + ], + "cssom/support/test-inner-half-size.png": [ + "4ed63dd2bb54a8efc166719e00e1e27406b0ee59", + "support" + ], + "cssom/support/test-outer.png": [ + "a0b8dfa40065b27f1d939ce0aab39ada3933c574", + "support" + ], + "cssom/support/test-tl.png": [ + "956e5156fd8c0e75b1c0f3b8b3b900b653663f74", + "support" + ], + "cssom/support/test-tr.png": [ + "078e1dd6dd61d36cec239ed75d02051f61fe60a5", + "support" + ], + "cssom/ttwf-cssom-doc-ext-load-count.html": [ + "800db5cd4f7342d8c4e5309d4035182ce42f7251", + "testharness" + ], + "cssom/ttwf-cssom-doc-ext-load-tree-order.html": [ + "cae6e4133be602bb4eb134f32d8a12ae53d35011", + "testharness" + ], + "cssom/ttwf-cssom-document-extension.html": [ + "0c1c8fb977b24bb3b5ca33051b32932f36f5a960", + "testharness" + ], "cssom/variable-names.html": [ "5ab67b9e86fd700a556d153898c2896448cc1759", "testharness" @@ -165101,6 +170191,10 @@ "724060b276a1f3254fd226e329631005ec5a5e87", "testharness" ], + "custom-elements/custom-element-registry/per-global.html": [ + "3b143f80d77a0b15b59cc6e6f5344f85dafe4f4e", + "testharness" + ], "custom-elements/disconnected-callbacks.html": [ "ad030517981b11892126023bc758b7fe323a3d14", "testharness" @@ -165109,6 +170203,10 @@ "11b7927c9a2946c752f56e5b44cfb4051ab8b6d6", "testharness" ], + "custom-elements/microtasks-and-constructors.html": [ + "088fcd47e328e30c6119a37bbf19768e7f14763d", + "testharness" + ], "custom-elements/parser/parser-constructs-custom-element-in-document-write.html": [ "b338f193a803ea679bbf0e041f71daf1e6d703f6", "testharness" @@ -165369,12 +170467,12 @@ "7574493bd02c0586f61424de2e2f3f337f67f270", "support" ], - "docs/_writing-tests/idlharness.html": [ - "2d127308c9dbb03c3e4a69964511b5e1a0e12030", + "docs/_writing-tests/idlharness.md": [ + "9f908f014553757d12fb91626a31a8312ec75bc5", "support" ], "docs/_writing-tests/index.md": [ - "0001b10cca68edee0d438bc99fea3b7599f7666f", + "8ef1c49c0692116968994e66483a318f6f40f5d3", "support" ], "docs/_writing-tests/lint-tool.md": [ @@ -165401,12 +170499,12 @@ "62747b6d0328445778050f3e4d6ec46dbdc3a18c", "support" ], - "docs/_writing-tests/testharness-api.html": [ - "fad99e6c6946066568e605a8ac6de7e2e49ac148", + "docs/_writing-tests/testharness-api.md": [ + "9c4484ec7a6053d4d745c6aac6cca821b1de982e", "support" ], "docs/_writing-tests/testharness.md": [ - "150d8638cff4e28c06014dbc0e7e9d9ef150c096", + "154bd922b6f50ec003280616381522a24faffb14", "support" ], "docs/_writing-tests/visual.md": [ @@ -165414,7 +170512,7 @@ "support" ], "docs/assets/_reftest_graph_example.dot": [ - "5fb97d276ed847bc271376dc6c068f57c067d790", + "bc8ebc09e30ff18994b32aa9e5ea43334c276ade", "support" ], "docs/assets/commit-directly.png": [ @@ -165442,7 +170540,7 @@ "support" ], "docs/assets/main.scss": [ - "427cae125889f51bef386097f0127e948f02652e", + "a0f4501b19a64a73c1037e2843a49060c4659bc9", "support" ], "docs/assets/menu.js": [ @@ -165670,7 +170768,7 @@ "support" ], "dom/events/EventListener-invoke-legacy.html": [ - "5c047e994f2bcb971918b42760c70cea7176abcb", + "e56b332acb454ab76964b78588536777946ddff8", "testharness" ], "dom/events/EventListenerOptions-capture.html": [ @@ -165702,7 +170800,7 @@ "testharness" ], "dom/interfaces.html": [ - "0cbf5532f442fdb9ba773fd053f8831b7b522767", + "f8eb7f5fcfdc9ca4a500d5e43855a24a169c81cf", "testharness" ], "dom/lists/DOMTokenList-Iterable.html": [ @@ -166130,7 +171228,7 @@ "support" ], "dom/nodes/Document-createEvent.html": [ - "00da7c85dab7a6f6414d4c58205ac501be0c588d", + "9274ffffe1b08dee78b64ffc70582957f0386bca", "testharness" ], "dom/nodes/Document-createEvent.js": [ @@ -166262,7 +171360,7 @@ "testharness" ], "dom/nodes/Element-classlist.html": [ - "7e3b68e65468fba0708f4084a9b2f6af93edde90", + "c197df35960b77a7794eed10a1a927867a6658f4", "testharness" ], "dom/nodes/Element-closest.html": [ @@ -166566,11 +171664,11 @@ "support" ], "dom/nodes/ParentNode-querySelector-All-xht.xht": [ - "ad28a6ca45cc102865b170dac5a9837a09ad5563", + "5469b8ad07ecbb07d5ca46d82c71aa4e470a5c2e", "testharness" ], "dom/nodes/ParentNode-querySelector-All.html": [ - "c94c9d2b9d84260e9ef7ae36a77ffceaaf18fad1", + "83baf7fa751b086622742908845c7a4db2e65fcb", "testharness" ], "dom/nodes/ParentNode-querySelector-All.js": [ @@ -166602,7 +171700,7 @@ "testharness" ], "dom/nodes/attributes.html": [ - "2e68d3bc430dcd87b826327ead2f8b89c0abdef6", + "cddff48a942168622772069ca2b2bcf0318deed4", "testharness" ], "dom/nodes/attributes.js": [ @@ -166758,7 +171856,7 @@ "testharness" ], "dom/nodes/mutationobservers.js": [ - "cbbccd9dc0cc4003feb6a4db7087590d5df9d6c5", + "595d6f555e03c0158c24448bf2bf35a3684a61fb", "support" ], "dom/nodes/prepend-on-Document.html": [ @@ -166778,7 +171876,7 @@ "testharness" ], "dom/nodes/selectors.js": [ - "019ceba60eaa07690fa3922995f53e65725d7f95", + "da3b97296a9fec2838a2cf1f5506893416627802", "support" ], "dom/ranges/Range-attributes.html": [ @@ -167122,13 +172220,169 @@ "support" ], "dpub-aam/OWNERS": [ - "16577d2283b826f0541dbc795177c7aac7e1b228", + "3a6002295ea2893ba74763e46965bd2d1291d55b", "support" ], "dpub-aam/README.md": [ "4b90a271f1ae6bfe28684797085ed59b2471b0f3", "support" ], + "dpub-aam/doc-abstract-manual.html": [ + "fe8331812ca78bf742f1563c9cf7064da331ccf0", + "manual" + ], + "dpub-aam/doc-acknowledgments-manual.html": [ + "e68c8ea6a948c3f205d497ee8c6841d94828d9f8", + "manual" + ], + "dpub-aam/doc-afterword-manual.html": [ + "ed57486061061270041d5e65ca37ef1e39fe85e2", + "manual" + ], + "dpub-aam/doc-appendix-manual.html": [ + "f2e9a80d2f2cd6c9824e963ab228ad3a30f00f46", + "manual" + ], + "dpub-aam/doc-backlink-manual.html": [ + "72ebb0d9564345dba613c3289492311dceebf0b7", + "manual" + ], + "dpub-aam/doc-biblioentry-manual.html": [ + "b555d4e67a81e405230ebee7f029fb7fed35b144", + "manual" + ], + "dpub-aam/doc-bibliography-manual.html": [ + "8b308c46bc7eb6acd380db88275c0a3247d2f5c2", + "manual" + ], + "dpub-aam/doc-biblioref-manual.html": [ + "ba578575a6f7eb5df31c797d562a19fd605b217d", + "manual" + ], + "dpub-aam/doc-chapter-manual.html": [ + "67bddab5b1f3941762d6cabc88276a059de8cf1e", + "manual" + ], + "dpub-aam/doc-colophon-manual.html": [ + "ec67cf4526e2fe95458456d2f333ca2f96786da6", + "manual" + ], + "dpub-aam/doc-conclusion-manual.html": [ + "7ca5220cf1d18aa933ccfb450c46b3a87d13a408", + "manual" + ], + "dpub-aam/doc-cover-manual.html": [ + "30b3b74ec46b54d2a0f737b50615eccbdb3b0f77", + "manual" + ], + "dpub-aam/doc-credit-manual.html": [ + "fe3df9e65f66333d0c30931cfdca4ca21db9d61d", + "manual" + ], + "dpub-aam/doc-credits-manual.html": [ + "6f745becf88d11ae3789095e64e82f94c0e4c8d6", + "manual" + ], + "dpub-aam/doc-dedication-manual.html": [ + "2ef98622fcbc67ec5cc21203a34a039a46da099c", + "manual" + ], + "dpub-aam/doc-endnote-manual.html": [ + "35661dfe5a8d5858eb9d065b8784cdcb4403ca82", + "manual" + ], + "dpub-aam/doc-endnotes-manual.html": [ + "fbff613b4b56d10d3708f3432656fb572683519d", + "manual" + ], + "dpub-aam/doc-epigraph-manual.html": [ + "3face4bf002fffcfddc54c34d3356b68fd0a1f2a", + "manual" + ], + "dpub-aam/doc-epilogue-manual.html": [ + "30be563ad8db5f7dddf67c757b68880014613b3c", + "manual" + ], + "dpub-aam/doc-errata-manual.html": [ + "879af14b31d9f5c71bb2db81ffcbfa81506624a6", + "manual" + ], + "dpub-aam/doc-example-manual.html": [ + "f4ee8cbc92b43ed64c9c44a316835dd55af03c47", + "manual" + ], + "dpub-aam/doc-footnote-manual.html": [ + "9d87bc526843a679b6ae23e4968fc3536524e779", + "manual" + ], + "dpub-aam/doc-foreword-manual.html": [ + "b88e137197d29800eb4a61fb2a095afe733c9f2b", + "manual" + ], + "dpub-aam/doc-glossary-manual.html": [ + "e0425c1f2617e57d441cfd8e560cf843da6eec05", + "manual" + ], + "dpub-aam/doc-glossref-manual.html": [ + "3564f0d21197da092b85e67b5f074fe66e45b871", + "manual" + ], + "dpub-aam/doc-index-manual.html": [ + "3a8e036535af7ee05e481ebd591492816df8d579", + "manual" + ], + "dpub-aam/doc-introduction-manual.html": [ + "00203fb91611439b8a0a3e950034f017c74ae4fb", + "manual" + ], + "dpub-aam/doc-noteref-manual.html": [ + "4052b204d1c9a9012870c783143daf56b35d2419", + "manual" + ], + "dpub-aam/doc-notice-manual.html": [ + "bea225fc2799e3616f291dee95644e6f265b1f18", + "manual" + ], + "dpub-aam/doc-pagebreak-manual.html": [ + "532f20e099dafe407ef3a52cd28ec75d161f4b7d", + "manual" + ], + "dpub-aam/doc-pagelist-manual.html": [ + "a231e2b6c5ca4c43e7c556ee0371b2b73950aaf8", + "manual" + ], + "dpub-aam/doc-part-manual.html": [ + "20473300cc7f5e0b39e32e7ffd8d0b9f88d76f81", + "manual" + ], + "dpub-aam/doc-preface-manual.html": [ + "be32f3d679eddf85a0698a9aa4f1f3e7311af5da", + "manual" + ], + "dpub-aam/doc-prologue-manual.html": [ + "5d29ba8e083b516d21e3d0a98f279c923ec44b94", + "manual" + ], + "dpub-aam/doc-pullquote-manual.html": [ + "17de6c30ef2940f54f72c547a5dc2436f8fd28e5", + "manual" + ], + "dpub-aam/doc-qna-manual.html": [ + "036d2764e6cf7664d12df86dfbcb603f024e0074", + "manual" + ], + "dpub-aam/doc-subtitle-manual.html": [ + "34eb597cea221ad5340b975916710f9456d71edb", + "manual" + ], + "dpub-aam/doc-tip-manual.html": [ + "73bda654beb49cf9772f9e532a8458a0ced124ac", + "manual" + ], + "dpub-aam/doc-toc-manual.html": [ + "6db9d04c7697ae5b34c687f20b379aad5551b59c", + "manual" + ], "dpub-aria/.editorconfig": [ "18e9e31b4beb20bcfa5ad281584d816204a3f531", "support" @@ -167153,136 +172407,140 @@ "faf2706da35ec626faa833c0498ef1e356584d27", "support" ], + "editing/data/README.md": [ + "f6eade04ca964b7f9adbb4246734433014442175", + "support" + ], "editing/data/backcolor.js": [ - "a988f4c9e1ee5aa5c1ef1159b4b8b9c260bc8272", + "61761a49890c5b955929e655b53ad0587eec8e91", "support" ], "editing/data/bold.js": [ - "42c827538938e385a2c0f33e7fcbf26820fad74c", + "0022a155aba2db8619b5625b45960746d3d8d1ee", "support" ], "editing/data/createlink.js": [ - "3fd0f1356c1036f83f4151790dc3d989b47b7b6a", + "95f3043ab22e5a804483bd8505f140865ecde088", "support" ], "editing/data/delete.js": [ - "fef65beefeb76d9fdafd9afbb0fc70a9de3a61f5", + "7af419763d9e8354361a109645da610099cf97b7", "support" ], "editing/data/fontname.js": [ - "c436324c10eb0b76cae3bb6d162776e8af62ac91", + "b4ffcc3be199393827079bf73dd7433d810e2466", "support" ], "editing/data/fontsize.js": [ - "0a1a242603bea5199a334843f33a7bc757423ea1", + "7077999cd649765a09ca16d843a7cd780eaaa1a8", "support" ], "editing/data/forecolor.js": [ - "4704c7d76160f9fca158bdbe2d84117706aaadd2", + "531d9fd219aec6c36231a1927e234a9ea6f5009b", "support" ], "editing/data/formatblock.js": [ - "7ec42b88c07ea41a37ee890bdc9ac5730f5edbb5", + "d4cadc6257aa75a7dc85c0c258f5b884e23a620c", "support" ], "editing/data/forwarddelete.js": [ - "f6495290991e83aa0438e100d1ad8286f44b00b3", + "1836be2c6f827de512381e9556e99de6cad165d6", "support" ], "editing/data/hilitecolor.js": [ - "bcf7e39416f394bf2120b04ccb3edaeca7b7f863", + "8901795b4f4cde2f59d616764870b93220366180", "support" ], "editing/data/indent.js": [ - "10bb2567852a40d480785cd147a0f5cbe888d19b", + "821cc4fefcfce96832c1a4547698801b554ae426", "support" ], "editing/data/inserthorizontalrule.js": [ - "a65609ebe407670a94a2ff59ed62ea4c2a3e1080", + "118414ee839b94b9a747e0dfd2068d728c171db7", "support" ], "editing/data/inserthtml.js": [ - "8e8c02364a0f5ff7bff12a5446c9896fca5e6886", + "3e853e0b406e4441a2326468b4e21c5b6ffc1c98", "support" ], "editing/data/insertimage.js": [ - "c2e2ad08ea335bb3be59d99de96132366f446eda", + "19f38b05e1694ecb8e26aea374c2b7cd3b2a2467", "support" ], "editing/data/insertlinebreak.js": [ - "fd09fb1a5c1f24f53b9a896c073dc3eed5d8cfd5", + "ba0a0f2eda2703c742dd71b3106a3c78da27e677", "support" ], "editing/data/insertorderedlist.js": [ - "99217ac94529676adc19b8a49460becf92a9d7c4", + "9387d479a52fd5146d5d708eb1244250f3dd02b6", "support" ], "editing/data/insertparagraph.js": [ - "6e70f6c308844af53888cd4093580242fd73a275", + "5cc4cee5d1ba32775a3a940e11ce46215b276466", "support" ], "editing/data/inserttext.js": [ - "5a0ceb860b775c14a2a096edfc75881eea1909f5", + "be6f17c7af88382808ee574d9291fbc606ab7ec4", "support" ], "editing/data/insertunorderedlist.js": [ - "259f57149badc8c124f3e963b6f1d5fbe4e9dbdb", + "ed8c92ce7bc902a5125e082798ad9abfef469f18", "support" ], "editing/data/italic.js": [ - "5459c6140ac7aadc49b716b82feba092eb8f67af", + "c2f373e29fd1894189243718e8bd003b92f3375a", "support" ], "editing/data/justifycenter.js": [ - "d61ca0251b32c1d11db99222bb48dfec4a18c6fa", + "066b910ecb3b087abe17279ab7c35eb43a883e19", "support" ], "editing/data/justifyfull.js": [ - "5f39fc5babb2d785f63a74989bf4d900a03f932d", + "906d2f7ec92f26695e760e6cdf855ef697869b61", "support" ], "editing/data/justifyleft.js": [ - "413a8ebf1501bd136bd4b789c5cec272a9204e9d", + "aa7d9db71cb624eae3acfce352c83ada85fcfe3c", "support" ], "editing/data/justifyright.js": [ - "563d0d450b72d94cf062ec6c74ee1160ed8fc13a", + "bc17e41ed4e658ff2b6622d76f2ca781da2cf5e9", "support" ], "editing/data/misc.js": [ - "413d681a83942734a410f614a40c5f913b9bbf6c", + "5e7a34bcaccb5ef4c2efa782fbc19991931bf8bc", "support" ], "editing/data/multitest.js": [ - "aaecbcfb0c1077e4940181f74c6ddbd91d23fcbd", + "5caa8e9d6140d6ebc68611784f9c2e535cc6daa0", "support" ], "editing/data/outdent.js": [ - "98d12d9e2eaadb98ab9580ebac19c1bf372ea5c7", + "370659febaa07f3cb3045931efdbe0ccdb6bd26d", "support" ], "editing/data/removeformat.js": [ - "b7a24b8162be7c11b0cf2a6443fe0d3973e3bc75", + "f3f054d79780525df262cb9d1c90799eec4751d1", "support" ], "editing/data/strikethrough.js": [ - "6016f3210874b49ae49093d0c3ab63ac8cd5abf8", + "728a5a2f08ff217757017cde8e7646e1ae42ea7f", "support" ], "editing/data/subscript.js": [ - "0bf0515ad3643a09ab8af047fa01e14f62d13208", + "8259fca2d6342a2de81752eab6f19223d0fe4140", "support" ], "editing/data/superscript.js": [ - "f8b0e882d6911894e0b3b9ba74faad382d3db478", + "2211663469529e5811c73fc30bafe2182341bcbe", "support" ], "editing/data/underline.js": [ - "cb53bbac4065882c9bb1ef95975794cfd6b8616a", + "aa89a58d130544c25b8483179b7ea80c52fb7e37", "support" ], "editing/data/unlink.js": [ - "b15636f4a5dc2a56712aa5133139244d0ba77624", + "7b5266ad05b6fc4c8653c026030e74b10ba1de31", "support" ], "editing/event.html": [ @@ -167962,7 +173220,7 @@ "support" ], "encrypted-media/content/content-metadata.js": [ - "4089766ce88368170d45b6a5b0e8db48fa2ef891", + "5bb828a1f1a9f05d74fd2103d06bc33d28174bbc", "support" ], "encrypted-media/content/video_512x288_h264-360k_clear_dashinit.mp4": [ @@ -167993,14 +173251,6 @@ "0fb6d575a357dd5fdc4544a55cb8ef4e25f0f449", "support" ], - "encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4": [ - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "support" - ], - "encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4": [ - "13a90556e91d127b0b8cf4a5ea3aec1dc99c2339", - "support" - ], "encrypted-media/drm-check-initdata-type.html": [ "ae0f79ae94465890ded3e3a6bfd60f320b23ad44", "testharness" @@ -168454,7 +173704,7 @@ "support" ], "eventsource/README.md": [ - "7ffbbf36f58487deadfc6ee31d7b12488a8b6daf", + "f450de54700a6057f2acb57d2c52257684b337f8", "support" ], "eventsource/dedicated-worker/eventsource-close.htm": [ @@ -168777,6 +174027,10 @@ "ab322023411faca98534f620806b2418a6767e64", "testharness" ], + "fetch/api/basic/block-mime-as-script.html": [ + "1dd503f1537b09f7aa875ea9a636d587b03601e3", + "testharness" + ], "fetch/api/basic/conditional-get.html": [ "77822a239b405b0b5c0259a335bac6cbe26b7fed", "testharness" @@ -169014,7 +174268,7 @@ "testharness" ], "fetch/api/headers/headers-idl.html": [ - "13804a9850b05753cf2ad85c926fd071f9fc1888", + "42dc60a28c86ef378a8aa614f411f13bae0a081a", "testharness" ], "fetch/api/headers/headers-normalize.html": [ @@ -169178,7 +174432,7 @@ "testharness" ], "fetch/api/redirect/redirect-location.js": [ - "793e947c027bbf8b2f11b7f2fe482f0480739220", + "3b48bf04659cc82462c3f33db47fd2f44f63c0c3", "support" ], "fetch/api/redirect/redirect-method-worker.html": [ @@ -169310,7 +174564,7 @@ "testharness" ], "fetch/api/request/request-error.html": [ - "bfd03777a43be514a0839ab14f5206f486332fdb", + "ff308916884f69b3f4aa8f2017c4d9fe0caf0f00", "testharness" ], "fetch/api/request/request-headers.html": [ @@ -169322,7 +174576,7 @@ "testharness" ], "fetch/api/request/request-init-001.sub.html": [ - "096424b40f6a21e989a6a5d8684b29ee8cbb963e", + "49bc4349b4e7a85d88cacd54227355aa986535f1", "testharness" ], "fetch/api/request/request-init-002.html": [ @@ -169330,7 +174584,7 @@ "testharness" ], "fetch/api/request/request-init-003.sub.html": [ - "059edc7e857af7231abc1434f3dcebb35229f459", + "f3084c91090e9c86c5586e947e63baf4990b582e", "testharness" ], "fetch/api/request/request-keepalive-quota.html": [ @@ -169385,6 +174639,10 @@ "387c35bf1e576f00a10ce5abb4cc92e78da56845", "support" ], + "fetch/api/resources/script-with-header.py": [ + "0c988e869e2e7af06bef67a2eba8211554b38323", + "support" + ], "fetch/api/resources/status.py": [ "d521bae08fa1ee19e7bbf4301157703e567ad5c6", "support" @@ -169597,10 +174855,6 @@ "94af02c5ca5146386acd4fae5856f89cd244bed1", "testharness" ], - "fonts/CanvasTest.sfd": [ - "c8103241670f9b5d4e5ae9083bbf7ec0221afe3b", - "support" - ], "fonts/CanvasTest.ttf": [ "10a7017b4caead6817aa08b25f14950e6402dd95", "support" @@ -170069,20 +175323,24 @@ "0a3ea46f600d1af4fb6f4a9777812476c3c66fcc", "support" ], + "generic-sensor/generic-sensor-tests.js": [ + "7b36a69dd7d9148f70a1d40d4108dcd747cb2913", + "support" + ], "generic-sensor/idlharness.html": [ "0e3f29a3a065a3db2f6e0e77d9c6bbdf47bf5ca8", "testharness" ], "geolocation-API/OWNERS": [ - "0657e9c1d1281428355eb545ba0b4552dc8900ec", + "84c4182ceed0f75ada11e63c3dfc2acc2939cbb6", "support" ], "geolocation-API/PositionOptions.https.html": [ - "3ed405ebbe4b6fde9dfa6b3426c52c7025efd84c", + "772c305b5b9e6a8ae61a44b395771b8d60bd7187", "testharness" ], "geolocation-API/clearWatch_TypeError.html": [ - "281cdbc3d81e498514a0cca3e839c33e1b217974", + "cce531a95f13a25148903807da87725390dd13dc", "testharness" ], "geolocation-API/getCurrentPosition_IDL.https.html": [ @@ -170102,7 +175360,7 @@ "manual" ], "geolocation-API/getCurrentPosition_permission_allow.https.html": [ - "695f80f5a06279b3a0bdd137e6a402da66a5eeee", + "02b0a2b3c021da0b811ba1c21ce0fc63d7839652", "testharness" ], "geolocation-API/getCurrentPosition_permission_deny-manual.html": [ @@ -170110,7 +175368,7 @@ "manual" ], "geolocation-API/getCurrentPosition_permission_deny.https.html": [ - "28939dd8e719ba66497a814edd1f4500ad348e95", + "aabbc7b2d392e2bbc26c08262bae4d57348da7a2", "testharness" ], "geolocation-API/interfaces.html": [ @@ -170118,7 +175376,7 @@ "testharness" ], "geolocation-API/support.js": [ - "021f696f918554830708d272e95caf13c7d596e4", + "68515a39a244240502d7a871be505a079360cdce", "support" ], "geolocation-API/watchPosition_TypeError.html": [ @@ -170130,17 +175388,33 @@ "manual" ], "geolocation-API/watchPosition_permission_deny.https.html": [ - "8da70bf5b65ace1e8a26e458d6c011c6183c5501", + "ca3036737a662e8673477b1a09b6fce89f0f98f4", "testharness" ], + "gyroscope/Gyroscope.https.html": [ + "03510d4964a52a53fc7648b5435e810e75ea747a", + "testharness" + ], + "gyroscope/Gyroscope_insecure_context.html": [ + "319bcf346337ccdd67f94ba2d0d4849e5b57da5e", + "testharness" + ], + "gyroscope/Gyroscope_onerror-manual.https.html": [ + "1e15b883bd317ca83783864fc563794cb0f6df8e", + "manual" + ], "gyroscope/OWNERS": [ "36770a71443523aa2f91f9958ba24066f0b4dcec", "support" ], "gyroscope/idlharness.https.html": [ - "2a2de0a720181358749232ce7a5301d79eb120d1", + "567b200f0ea88894bbffbffb6d20ea546f516e7d", "testharness" ], + "gyroscope/support-iframe.html": [ + "b02be6c1cdae86e449b8bf635e18e0b60957bb81", + "support" + ], "hr-time/OWNERS": [ "b82f9756b15ef3ea45fb250e304031d9ceaee9c7", "support" @@ -170362,39 +175636,63 @@ "support" ], "html-media-capture/capture_audio-manual.html": [ - "2b5cc72f7f2d323dfc0c96623c9fc026abeec2db", + "fd611892abb621d1310eba3e46f6439465b8dd3f", "manual" ], "html-media-capture/capture_audio_cancel-manual.html": [ - "7f245012220fa028e1152b3f0c7464d1e67447c0", + "da45d452a1759528bc6aaa466033804fe62cdfe8", "manual" ], "html-media-capture/capture_fallback_file_upload-manual.html": [ - "9795fbe923e4592924475ed639a8cd59be5d8289", - "manual" - ], - "html-media-capture/capture_image-manual.html": [ - "a31d06ee9e392dca38ac465e590fba7b01fe1a92", + "ca8753c7df7027ac899a3056c828dc095e07cb55", "manual" ], "html-media-capture/capture_image_cancel-manual.html": [ - "c6dc98923dc96e61154229fc5354e822899a8a7d", + "27e629176c546007bc3e5b1454e33a9624d3ddda", + "manual" + ], + "html-media-capture/capture_image_environment-manual.html": [ + "d158d667ecd004ab145cbe5b4fc4689b61fc1e51", + "manual" + ], + "html-media-capture/capture_image_invalid-manual.html": [ + "c51ad170a479f9656abf493c93ec503d91b93baf", + "manual" + ], + "html-media-capture/capture_image_missing-manual.html": [ + "257544fbac5d85326940c8f6b11e23d278d4dc7f", + "manual" + ], + "html-media-capture/capture_image_user-manual.html": [ + "16a810530a8101a0c672bad9c425ca0e8f1e16cc", "manual" ], "html-media-capture/capture_reflect.html": [ - "0f8a2aa88b35610b9591cd601e366a46a92ac095", + "81518a10ed38fa5e077430ce6fdf8ed844297a01", "testharness" ], - "html-media-capture/capture_video-manual.html": [ - "5f6257d736861b91bbc30b3c0a6703aa323137f6", + "html-media-capture/capture_video_cancel-manual.html": [ + "14d23724a4987da8996e82d57e09aeeb458c1cc5", "manual" ], - "html-media-capture/capture_video_cancel-manual.html": [ - "ea3aaee0458b374b9a6affb3d7af09f18099fcb1", + "html-media-capture/capture_video_environment-manual.html": [ + "2e39f6ea0ff308c022aea53d8b64b32ba1718200", + "manual" + ], + "html-media-capture/capture_video_invalid-manual.html": [ + "0188e58ba819aad219e2f82a0ca4e7eec3265e9a", + "manual" + ], + "html-media-capture/capture_video_missing-manual.html": [ + "243f7bd28f26bbd5a85e79360da7dbc739fd4bab", + "manual" + ], + "html-media-capture/capture_video_user-manual.html": [ + "acef04c2541d30fdff411c74ccce81ee2086c9d2", "manual" ], "html-media-capture/idlharness.html": [ - "2e5050d4e1a58a14131809f1acdcd263729918ae", + "32b3d387100f0e7ecda93d1fb88351680b259df0", "testharness" ], "html-media-capture/support/upload.txt": [ @@ -171745,6 +177043,10 @@ "923e6d0e13f71e2e79799005ac0bcd6415ad1ffa", "manual" ], + "html/browsers/history/the-location-interface/per-global.window.js": [ + "04de6e863ec1816fccda38e50b81d67bbcedb125", + "testharness" + ], "html/browsers/history/the-location-interface/reload_document_open_write-1.html": [ "464fa292c3fa04da8594401bbdb7cbe2a30b41dc", "support" @@ -172054,7 +177356,7 @@ "testharness" ], "html/browsers/origin/cross-origin-objects/cross-origin-objects.html": [ - "a49a73b44a8484a240b14fc3877b0abed64e16dc", + "02e290c300057b9520390e55833194908d74ca76", "testharness" ], "html/browsers/origin/cross-origin-objects/frame.html": [ @@ -172077,6 +177379,14 @@ "9839a9c24ce78ec42da8a60d2175df06e19983c1", "testharness" ], + "html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html": [ + "1f0408464d8d98341c9537c3e3356cacbcf2f489", + "testharness" + ], + "html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter_iframe.html": [ + "d33427abcc87693bce1f5610f460aad12cb99759", + "support" + ], "html/browsers/sandboxing/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -172209,6 +177519,82 @@ "c4f0da17299d37f70b316d709dbde0ff6a1f62fb", "support" ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html": [ + "b86f249223db3ef579e8d976f6b586d43e26a94d", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-screenx-screeny.html": [ + "38921fe3656a4b08aa44a37ff4829a8b4d9b6213", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-top-left.html": [ + "049dd60f6397e87da17edf9ddb96c10fc08e57d4", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-width-height.html": [ + "3fddee5842259433e1158eb326e51d037dd42774", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-height.html": [ + "caaede75e5c16cc78023ce410f48e37e612cffbb", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerheight.html": [ + "94c1f2f19317d039e4c30e30fcdc41da20fe402f", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerwidth.html": [ + "30ef1e2913e78f0fde1794bdf5bceef435a7101a", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-left.html": [ + "711ef5c371aec8b494aa7c5bb0541ba264acb1e0", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screenx.html": [ + "420386e4df736ffd925d3c813c92f65e02d0b514", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screeny.html": [ + "e7aaee702eb277266bee64889507cd1d38cb5c27", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-top.html": [ + "4164cdfee8733cd242f7e51089e3106556f0b359", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-width.html": [ + "a73e68d7017e7f27609cc10427a7a6c86c130fb1", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-innerheight-innerwidth.html": [ + "61aefe4aade30ca7a696450ccb5a9330bd0c9ccb", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html": [ + "0d37066f498228705c175d7d7a15e4d2ac279397", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html": [ + "736fcd9bbe559184b7e11239a9c10816e30db4f2", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html": [ + "50cb5c7ee38e12d067661b40706d244ca5cabe8b", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-width-height.html": [ + "637bbe2d587b4422a3d935cffac24807bc0fffaa", + "testharness" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/close-self.html": [ + "7be5d6853d829e7af8baaf96c4ef42cf858a3526", + "support" + ], + "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/message-opener.html": [ + "37afff594d1448656b233c347db88dafafc01f8f", + "support" + ], "html/browsers/the-window-object/browser-interface-elements/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -172362,11 +177748,11 @@ "testharness" ], "html/browsers/the-window-object/window-indexed-properties-strict.html": [ - "57a32c2a9c636762b2d77301c9a6258a4773190c", + "ac9d401368b75e00adbdf80ee42dd8dce1e48e13", "testharness" ], "html/browsers/the-window-object/window-indexed-properties.html": [ - "bf31e152c35b33c32366950fa84837fab74a6bec", + "22d5cb06bfc4724d27f565b8ffa2280bf2e8538b", "testharness" ], "html/browsers/the-window-object/window-named-properties.html": [ @@ -172461,112 +177847,144 @@ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" ], - "html/browsers/windows/browsing-context-names/001-1.html": [ - "7f9396d2baeeafd98832c7fe5a0a1474fc358e98", - "support" - ], - "html/browsers/windows/browsing-context-names/001.html": [ - "1b127e23e7991080fc01b24c1924822642480744", - "testharness" - ], - "html/browsers/windows/browsing-context-names/002-1.html": [ - "f70339fff42414af8441fdf4be42151839989839", - "support" - ], - "html/browsers/windows/browsing-context-names/002.html": [ - "ed586ee147452ba6cb8d90782b266807f8b7975e", - "testharness" - ], - "html/browsers/windows/browsing-context-names/browsing-context-_blank.html": [ + "html/browsers/windows/browsing-context-names/choose-_blank-001.html": [ "4a1a9ff6c913291edce2339faa443b6da2e5fe74", "testharness" ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-existing.html": [ - "381a1a09c09e8c43849a7b8f4d120507b2196aeb", + "html/browsers/windows/browsing-context-names/choose-_blank-002.html": [ + "37fffaad1ad4136a759507ab0565896e8ed7e0c5", "testharness" ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-parent-001.html": [ - "4767179a7c78a8e0798997dace46b47ec5d902ad", + "html/browsers/windows/browsing-context-names/choose-_blank-003.html": [ + "e3f7b085257c45bb2a8a86d6a7d7ff9b5191dbf4", "testharness" ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-parent-002.html": [ - "7d1692f649951585d8ce60bd7cc9c4470f255b95", + "html/browsers/windows/browsing-context-names/choose-_parent-001.html": [ + "a03843100fba5a753ae3a4451cd5b03ec8808e56", "testharness" ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-parent-003.html": [ - "61ebac870a8c1e030468f5cfd4f6e22171c015e7", + "html/browsers/windows/browsing-context-names/choose-_parent-002.html": [ + "7ef76d4690da42586f3e673413d943da12527001", "testharness" ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-parent-004.html": [ - "6341211c1c38b6b3e3b09329c71bd0b8e79e2f2f", + "html/browsers/windows/browsing-context-names/choose-_parent-003.html": [ + "b12b3005f9227e45f2c92dd7ca5aad339cbdae25", "testharness" ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-self-1.html": [ - "f957a910476b1294de97ef69e671e84d201ca5c0", + "html/browsers/windows/browsing-context-names/choose-_parent-004.html": [ + "7ecba630d8fa01fde65abc0f6b135363707b91df", "testharness" ], - "html/browsers/windows/browsing-context-names/browsing-context-choose-self-2.html": [ - "c445f1397eb5e95a25aa7ae64f677cbfa63cb049", + "html/browsers/windows/browsing-context-names/choose-_self-001.html": [ + "04add262884e7e19a290ebd40ddb90107055e906", "testharness" ], - "html/browsers/windows/browsing-context-names/browsing-context-default-name.html": [ - "12ab8a79c7239a712cebfa171c4271fae4a49b0e", + "html/browsers/windows/browsing-context-names/choose-_self-002.html": [ + "4804c851ba55a65d24e88456c0021b32b13fae44", "testharness" ], - "html/browsers/windows/browsing-context-names/existing.html": [ - "eb695cb2f8a126f0c32347d8716936fc288d0858", + "html/browsers/windows/browsing-context-names/choose-_top-001.html": [ + "b85f6e0bdcddba5cde28bc088ee0b81d6506fde8", + "testharness" + ], + "html/browsers/windows/browsing-context-names/choose-_top-002.html": [ + "8ec181327440e8ef5516b1cd23d1733355015ac5", + "testharness" + ], + "html/browsers/windows/browsing-context-names/choose-_top-003.html": [ + "6c1fb058b4ce37789baf8bdf6dd6ab6695e54f78", + "testharness" + ], + "html/browsers/windows/browsing-context-names/choose-default-001.html": [ + "cebca758b8fc07fbbf9a99700acc464cd67d397e", + "testharness" + ], + "html/browsers/windows/browsing-context-names/choose-default-002.html": [ + "0a6b8b82b44289c5ff6212857a1a174cf7d9d9d7", + "testharness" + ], + "html/browsers/windows/browsing-context-names/choose-existing-001.html": [ + "175492ca2ea7d2ce000466e895ff22f29b77df93", + "testharness" + ], + "html/browsers/windows/browsing-context-names/resources/choose-_parent-001-iframe-1.html": [ + "a3c60408fc0d545e3a7ca8161f04d095ebdba02a", "support" ], - "html/browsers/windows/browsing-context-names/resources/parent-iframe-1.html": [ - "6b1687e52c5b53e6d7a0bb4fed5bed7291154ff2", + "html/browsers/windows/browsing-context-names/resources/choose-_parent-002-iframe.html": [ + "8df4501c8bf73f5c1daed2986eba8adeb211a6cc", "support" ], - "html/browsers/windows/browsing-context-names/resources/parent-iframe-2.html": [ - "95f916c7b914088b59ce6addb5c639f4dc158de1", + "html/browsers/windows/browsing-context-names/resources/choose-_parent-002-window.html": [ + "85ad3ee8ec0e3028f993fd776de6ddb5948f750a", "support" ], - "html/browsers/windows/browsing-context-names/resources/parent-iframe-3.html": [ + "html/browsers/windows/browsing-context-names/resources/choose-_parent-003-iframe.html": [ "169dc483de493c5c4f0383063dc1d9aad2b41073", "support" ], - "html/browsers/windows/browsing-context-names/resources/parent-iframe-insensitive-1.html": [ - "638ed0ec62a27b3acc1d0acb60bd5113a1c2988c", + "html/browsers/windows/browsing-context-names/resources/choose-_parent-003-window.html": [ + "e8f5e55f930899229252a04b2d698abddf73ffb2", "support" ], - "html/browsers/windows/browsing-context-names/resources/parent-iframe-insensitive-2.html": [ - "e6ab1f0e5aa36e69467ae1f69e4682d40ae692a7", + "html/browsers/windows/browsing-context-names/resources/choose-_parent-004-iframe-1.html": [ + "050927f475859690243f6039036bd8dd5bc72992", "support" ], - "html/browsers/windows/browsing-context-names/resources/parent-top-nested.html": [ - "03b7ece0831f8059f687135be899f4de2831568d", + "html/browsers/windows/browsing-context-names/resources/choose-_parent-004-iframe-2.html": [ + "39aa44e0efbea17158e4aeea731a22f8b4946006", "support" ], - "html/browsers/windows/browsing-context-names/resources/parent-top-replace.html": [ - "1f3d056bbb472a730ee2f40085c51fbb279ad52f", + "html/browsers/windows/browsing-context-names/resources/choose-_self-001-iframe.html": [ + "3ad6ddf88d32b0733fe1041636081c33c4611ecc", "support" ], - "html/browsers/windows/browsing-context-names/resources/parent-top.html": [ - "e2247fbb30c24e014d1743cd9df91bf0195fbfe0", + "html/browsers/windows/browsing-context-names/resources/choose-_self-002-iframe.html": [ + "adc1c8ac78adbdd1455f8e22289a9bfef079ca5c", + "support" + ], + "html/browsers/windows/browsing-context-names/resources/choose-_top-002-window.html": [ + "be64018ffa35bf3dc1200111fc25f7d1b520fc41", + "support" + ], + "html/browsers/windows/browsing-context-names/resources/choose-_top-003-iframe-1.html": [ + "dd62814246f87a9847b5c2de1a6537a7daa81bf4", + "support" + ], + "html/browsers/windows/browsing-context-names/resources/choose-_top-003-iframe-2.html": [ + "8e940565ae03d662d1dc878115d9665a5f01a837", + "support" + ], + "html/browsers/windows/browsing-context-names/resources/choose-default-002-iframe.html": [ + "b4fddf4509e4922bc2baad24247d72f4fc41f718", + "support" + ], + "html/browsers/windows/browsing-context-names/resources/choose-existing-001-iframe.html": [ + "7e71b6f0835a78ffbd7e0731ce271d78b20890c8", + "support" + ], + "html/browsers/windows/browsing-context-names/resources/open-in-_parent.html": [ + "95f916c7b914088b59ce6addb5c639f4dc158de1", + "support" + ], + "html/browsers/windows/browsing-context-names/resources/open-in-_top.html": [ + "6fad2b581eb588c91923bad0e3b780089e5849df", "support" ], "html/browsers/windows/browsing-context-names/resources/post-to-opener.html": [ "a724ee03afea915ba9a3636e6915db8bda801212", "support" ], - "html/browsers/windows/browsing-context-names/resources/post-to-top-or-close.html": [ - "83eae63250fb3ad9f146283e9387b0e18284d4f7", - "support" - ], "html/browsers/windows/browsing-context-names/resources/post-to-top.html": [ "c2b557ab78403aa520346da294e1c406dd37ebda", "support" ], - "html/browsers/windows/browsing-context-names/self1.html": [ - "7c86c871972f456c6b97be7b46fa7d6ce87a3a80", + "html/browsers/windows/browsing-context-names/resources/report-has-opener.html": [ + "8cc69db12b379eb57c2a1d3d3321a4034fa2e301", "support" ], - "html/browsers/windows/browsing-context-names/self2.html": [ - "fd91e9250c182da49ab39220a656348c29c84048", + "html/browsers/windows/browsing-context-names/resources/report-is-top.html": [ + "e65bff43b66ee9f7b6aa5b061fff835b199e1745", "support" ], "html/browsers/windows/browsing-context-window.html": [ @@ -173482,7 +178900,7 @@ "support" ], "html/dom/elements-metadata.js": [ - "bcd86ba6bbe3ce770091279ec4c3005b16dbc633", + "059d2c83a4354f173056ca489412d19ab77ef110", "support" ], "html/dom/elements-misc.js": [ @@ -173498,7 +178916,7 @@ "support" ], "html/dom/elements-tabular.js": [ - "929e628d165561489a2b68b2faf44a47a7f856d7", + "db69341821cb76750da473664d806b4649c9b606", "support" ], "html/dom/elements-text.js": [ @@ -174302,7 +179720,7 @@ "support" ], "html/dom/interfaces.html": [ - "1f34a3ba45166c0d0c14cebb7846408ec120b9f1", + "4c0db96824033d94b98123954254930fb742d7e3", "testharness" ], "html/dom/interfaces.worker.js": [ @@ -174358,27 +179776,19 @@ "testharness" ], "html/dom/reflection.js": [ - "d952a2936d184f18f3de4c00c5a871ce303b3963", - "support" - ], - "html/dom/resources/interfaces.idl": [ - "c712b0532395b08c2e6b3c68b8580f560b47a594", + "c05afee11097eac0e05c8299c1ad8322afc47421", "support" ], "html/dom/resources/self-origin-subframe.html": [ "a94fee503c6ad28fdedf1f62fcd96465f7b88e71", "support" ], - "html/dom/resources/untested-interfaces.idl": [ - "1165f9e91f3c81876398211db67483fa16c62e55", - "support" - ], "html/dom/self-origin.any.js": [ "187b3657775b815f9360c01d2ddb358a53e1f920", "testharness" ], "html/dom/self-origin.sub.html": [ - "d821d4b41ac8517d345f86a9f8298f67284d1967", + "ad9aadfb350cee1613a0884154706c632b0a8fe8", "testharness" ], "html/editing/.gitkeep": [ @@ -178217,6 +183627,50 @@ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" ], + "html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html": [ + "a21ca78b9c6a8795eb4e2fa95f30a51a553a3e52", + "support" + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-001.html": [ + "5c20688ee9f871cdc0b1553287dfe6d4d64dcf15", + "reftest" + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-002.html": [ + "80318bc3c90f72803255831a95c482bf99105d29", + "reftest" + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-003.html": [ + "ae4f1d7e6c954fd1f3fa53fcd77833954bcdf6d9", + "reftest" + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-004.html": [ + "ace6101644d2c0e426d611016a3cb3dc30968f4a", + "reftest" + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-005.html": [ + "5aae7d56aa63f90160ba1e296378b0a0832c07f0", + "reftest" + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-006.html": [ + "e329657b5ebf7211237fa7712a3c710d3ea4b956", + "reftest" + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-007.html": [ + "10c986cf6e428c782a09572be5c5438d256b17c1", + "reftest" + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-008.html": [ + "c026d35ec89818f5624daad20163fb4ceed62828", + "reftest" + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-009.html": [ + "68e7e27bc3777a8fe0807380a28c1ce60aa3becc", + "reftest" + ], + "html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-010.html": [ + "0320abd956316beff38f2ff06e0f32ee2b2e9887", + "reftest" + ], "html/editing/editing-0/spelling-and-grammar-checking/user-interaction-editing-spellcheck.html": [ "228e52ef1987df94158305799dc53086e435b24b", "testharness" @@ -178585,6 +184039,150 @@ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html": [ + "8375e9daeb9a11e53a9841874fef50677f0970dc", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html": [ + "12bd51a62830514325b89263abc5710bbe6b510f", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.html": [ + "594d11e18e7ef8e9aaa0eca3dc2865033827ce7c", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-dedicatedworker.html": [ + "1fa9a3ae8d33bfd08d37a18853d511b9de66889b", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-sharedworker.html": [ + "c93bd6d985380cde5e3309897ad56fccd0a73709", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.js": [ + "42b788cb6d8a9509239bbb5c141c1f014dd9a6bf", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.html": [ + "17b67f8d75e558be808493f5cba82f978a0b6822", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html": [ + "c4461f454a7dfd85e9345832ecaabd9cbf6e6cda", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html": [ + "f6102979837864b2d472a71e425f021a29d76184", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js": [ + "afbfe4d0178bd33062ccb9b05f27f8643ed9cad8", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js": [ + "4c253242a8b665d04deb00825e9a81662665ead7", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/echo-iframe.html": [ + "6284dea4f647cce02cc8b54fc5e8c6bedc0b633b", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/echo-worker.js": [ + "7e7480dc1cc966ad2fef985a7d5d4dbdfa0e24e9", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-domain.sub.html": [ + "18185b1c53475814cb8f4d9ad820a2d85a283b1f", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html": [ + "d3d2dd8c8a277386a550cafd91a4b068daa035e0", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html": [ + "a27679e95d330e2a2efbc62b80fca999a3aa672e", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js": [ + "ddc07ed4ef35ce73744506cbd11817e48b65e976", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js": [ + "f89bea23edb1ebddb02c5f83c1bd36d30b5b48c6", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html": [ + "635658ddc3fa586abc078211842b4bc43b4a53d7", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html": [ + "4ddb26b10fea29e35068e5854009b6ae848fe032", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html": [ + "c112135e61cb799953b6009db7017952266bbaa1", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html": [ + "fd947afdad730f4826cc893ea5516fc20a08b87e", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js": [ + "ff16d63cc344365df0e6c0f30d4d30b82d1df2e4", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js": [ + "f5614900f151d8c4c659979b67bf8ac128efa3cb", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-incrementer.js": [ + "9f0a9648c72af785c3a7f44f26d6509f1a4f81f7", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-sab.js": [ + "a8d3ce61436cb0d5b23c275820fcde7d63cdafec", + "support" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.html": [ + "8f66e9b640ba812f3846a8fb0dc8f29fcf502f1e", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js": [ + "a6e82ee3583bbf2667c59cb04460c1fd9aea4aee", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js": [ + "bba8979a9270460b976f8c2ca6912c1b3dedeab2", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-success.sub.html": [ + "dac4b1fd873c3ec42d05e24166e77424b15377d4", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.html": [ + "298b5dba54eafaee6dafe5356b5196ed37f59b21", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html": [ + "11794f2d67e97eb97ad1871027b4a19e017e9624", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.html": [ + "735bfeda2e72815f331766b32ac02af71179902b", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-similar-but-cross-origin-success.sub.html": [ + "5d30957d37646bd4ebc7112db8c055bae8cc6e23", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.html": [ + "7c0b8b2e411236aeeed3a8b7962dc70d8a94969f", + "testharness" + ], + "html/infrastructure/safe-passing-of-structured-data/structured_clone_blob.html": [ + "2a3deba2534cad6f5e0aa85cfc3c90debcead20a", + "testharness" + ], "html/infrastructure/terminology/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -179421,6 +185019,22 @@ "0dd816530943f3a6fa3235b1d481f70ca578b6e6", "reftest" ], + "html/rendering/non-replaced-elements/the-page/iframe-body-margin-attributes.html": [ + "68e9c15f160415a652650331f403dd324cd402e9", + "testharness" + ], + "html/rendering/non-replaced-elements/the-page/iframe-marginwidth-marginheight.html": [ + "db8b96ffd3b16bc78d937b46860de8c22d857947", + "testharness" + ], + "html/rendering/non-replaced-elements/the-page/support/body-marginwidth-marginheight.html": [ + "d75fd3830c23860db68fe23589f74a7bdc95be91", + "support" + ], + "html/rendering/non-replaced-elements/the-page/support/body-topmargin-leftmargin.html": [ + "1c31ddd13c97504f59d1e403f6ab90252fa68e0c", + "support" + ], "html/rendering/non-replaced-elements/the-page/test-body.xhtml": [ "7a229199399e678847280e6e88e40e5b37bfdd11", "support" @@ -179474,7 +185088,7 @@ "support" ], "html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html": [ - "29e2eedb67a0a8e80c5bc09cbda5acb3d74bed74", + "2eaa79128917a0d0888b7155adfa0fb83bcb7c1f", "reftest" ], "html/rendering/replaced-elements/embedded-content-rendering-rules/canvas_scale.html": [ @@ -179725,10 +185339,18 @@ "285208d6cf3113ec16bedd107c0740b8c7c8a9d8", "testharness" ], + "html/semantics/document-metadata/the-link-element/resources/bad.css": [ + "b968e6422a283acc772561f8950171b3a5e00397", + "support" + ], "html/semantics/document-metadata/the-link-element/resources/empty-href.css": [ "1dcc57d4f3363562322937979cb7828b0c298daa", "support" ], + "html/semantics/document-metadata/the-link-element/resources/good.css": [ + "04a3a89fe805fc930dc3adfa3a4134b950779697", + "support" + ], "html/semantics/document-metadata/the-link-element/resources/stylesheet.css": [ "2829167c82bafef6cfea06071007a231aa4277f6", "support" @@ -179737,6 +185359,14 @@ "e4a66764ea94d51b42d485d75a3305ea2ab79226", "support" ], + "html/semantics/document-metadata/the-link-element/stylesheet-change-href-ref.html": [ + "cca943d35bd18e99249d50c6d40cc6fe2e328354", + "support" + ], + "html/semantics/document-metadata/the-link-element/stylesheet-change-href.html": [ + "6083446e9ef1b70f044a353ef96b459956afb1ef", + "reftest" + ], "html/semantics/document-metadata/the-link-element/stylesheet-empty-href-ref.html": [ "1ac8e070630e58df8489b779bdd75cb2b38c25ef", "support" @@ -180961,6 +186591,10 @@ "38b6f3c5707b360427854b82054d86f5364dc0b8", "testharness" ], + "html/semantics/embedded-content/the-canvas-element/imagedata.html": [ + "e685ab0d76bdd1b60a5d6f1e2126ea1a89db97d1", + "testharness" + ], "html/semantics/embedded-content/the-canvas-element/initial.colour.html": [ "22ddb77f5a18a19edc409d36532120f852bfbc57", "testharness" @@ -181594,7 +187228,7 @@ "reftest" ], "html/semantics/embedded-content/the-iframe-element/iframe_harness.js": [ - "c5db7a8f3c32f79a4e24d176cb95563a999240e5", + "2f22f494c69854a79af94ccf90215ece7bb4a130", "support" ], "html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_01.htm": [ @@ -181733,6 +187367,14 @@ "bdbfbe9a5908c6233bd7b9697a0762bd2e0f6ede", "testharness" ], + "html/semantics/embedded-content/the-img-element/delay-load-event.html": [ + "e4782535af755b29864fd3de67bbdd0de13f19d7", + "testharness" + ], + "html/semantics/embedded-content/the-img-element/document-adopt-base-url.html": [ + "a4b542eb344cca6bdcceceb3aa7006e900f5400f", + "reftest" + ], "html/semantics/embedded-content/the-img-element/document-base-url-ref.html": [ "add78257076d22891334b93c8072d098ace9b6eb", "support" @@ -182109,6 +187751,18 @@ "bfd11561a2e568668b6aaf94bc6da9e42fccdf55", "testharness" ], + "html/semantics/forms/form-control-infrastructure/form_attribute.html": [ + "b19b882091ff523e71397bfcad5dcf505e0a8f88", + "testharness" + ], + "html/semantics/forms/form-control-infrastructure/form_owner_and_table.html": [ + "7172d74bb5572091ee09abf30a4f6892b85aca3a", + "testharness" + ], + "html/semantics/forms/form-control-infrastructure/form_owner_and_table_2.html": [ + "3b1dea35bb4af384125904d69bf569109965714f", + "testharness" + ], "html/semantics/forms/form-submission-0/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -182186,7 +187840,7 @@ "testharness" ], "html/semantics/forms/textfieldselection/selection-after-content-change.html": [ - "c7f9433a664b59f59be933cdf607c158a599dff7", + "f4b7c92a9eebbfd272793ff7a5d56224220b2dd7", "testharness" ], "html/semantics/forms/textfieldselection/selection-not-application-textarea.html": [ @@ -182274,7 +187928,7 @@ "testharness" ], "html/semantics/forms/the-form-element/form-autocomplete.html": [ - "e3548e62923d62b5844f8d4d7222006bbfd3cb2a", + "c3aae63b6c007e3f39a7bf39c56bcdb7172273ad", "testharness" ], "html/semantics/forms/the-form-element/form-elements-interfaces-01.html": [ @@ -182422,7 +188076,7 @@ "testharness" ], "html/semantics/forms/the-input-element/radio.html": [ - "f80348bd3b3947eefc993323988799df13e7280e", + "e7b37335f58290c4f5a8e1a098c1cc50fb78a7b2", "testharness" ], "html/semantics/forms/the-input-element/range-2.html": [ @@ -182985,6 +188639,14 @@ "84dda1357022cd800b0663aadd3488bd04a64047", "testharness" ], + "html/semantics/interactive-elements/the-dialog-element/centering-iframe.sub.html": [ + "eb00778210365e13b33e194da1b9e870d7e39153", + "support" + ], + "html/semantics/interactive-elements/the-dialog-element/centering.html": [ + "47a8ae7ca2a2d06ee042213d0800e0da37b1fe10", + "testharness" + ], "html/semantics/interactive-elements/the-dialog-element/contains.json": [ "340924bc329569ce605ce228619d95f09f335ec5", "support" @@ -183009,6 +188671,10 @@ "a79ad27e8f1e2eee47c89fa4530f7babfbb07dd5", "support" ], + "html/semantics/interactive-elements/the-menu-element/menuitem-label.html": [ + "d11f6d0ef667da33d7981860b47e6d02f8c0ad24", + "testharness" + ], "html/semantics/interactive-elements/the-summary-element/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -183381,6 +189047,14 @@ "997cee37dcd202498196e63e0f66035979121b7f", "testharness" ], + "html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html": [ + "87e7f790edf2ef9de702f3e9b45a42d6fedae857", + "testharness" + ], + "html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js": [ + "f2a20180b6bf5f9c89f5b9541885d55dc8a8ade6", + "support" + ], "html/semantics/scripting-1/the-script-element/nomodule-reflect.html": [ "ac2b3c16e9e9263cd4c14de205b63709c14ec2e3", "testharness" @@ -183893,6 +189567,10 @@ "2bee37bc667b7aaf9ffc2be912288540896e3f03", "support" ], + "html/semantics/tabular-data/processing-model-1/span-limits.html": [ + "221803eac571dfc67c97122467743be20b1d17c0", + "testharness" + ], "html/semantics/tabular-data/the-caption-element/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -184049,6 +189727,14 @@ "93f820588f813b3e340188c88be1532d6e549757", "testharness" ], + "html/semantics/text-level-semantics/the-a-element/a.rel-getter-01.html": [ + "c207792ee550d653bc0734f6ef457c7c0e2749d8", + "testharness" + ], + "html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html": [ + "ea922ee6e02e02349ad56d1e8f69d6555d142883", + "testharness" + ], "html/semantics/text-level-semantics/the-a-element/a.text-getter-01.html": [ "ed1c631e5573192fc85f4234d76e5979a32bb44b", "testharness" @@ -184890,7 +190576,7 @@ "testharness" ], "html/syntax/serializing-html-fragments/serializing.html": [ - "dfc037432227ab79b9ce795547fb370594651b9e", + "cd9e3b8412231aa393081a6234efc7476e00c48e", "testharness" ], "html/syntax/serializing-xml-fragments/outerHTML.html": [ @@ -185373,6 +191059,30 @@ "6427c8ff06c11f2877f026124d46748b5270bc8e", "support" ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-dedicatedworker.html": [ + "e9ef057de8593404b63e34c8c2ff038236f26d7b", + "testharness" + ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-serviceworker.https.html": [ + "f6cdef79aefb4739025c0c805dfc1ee7fcddef52", + "testharness" + ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html": [ + "6927215d83fc6562dabf74b1a089531556256f5c", + "testharness" + ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-window.html": [ + "5aab1e791ad444eb73383e06f4e2fbb1fb512072", + "testharness" + ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/worker-that-requires-failure.js": [ + "8a24096d84baf51c6d2e3c26131093dccec74195", + "support" + ], + "html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/worker-that-requires-success.js": [ + "e4c2b99ca0379bfe0531ede9d2da46832f2c95dc", + "support" + ], "html/webappapis/scripting/processing-model-2/runtime-error-cross-origin-setInterval.html": [ "c8c4ba120b74c1beb6d24901e3d1b8a87e5b8837", "testharness" @@ -185462,7 +191172,7 @@ "testharness" ], "html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html": [ - "be6f591b06b633d7a4e04003bd6b79788c146c16", + "779323f3ef1f53f112c9eec3f1349d5c467381d7", "testharness" ], "html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.dedicatedworker.html": [ @@ -185529,18 +191239,6 @@ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" ], - "html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.html": [ - "61f05d56702a02acf80809605c46a31033192df9", - "testharness" - ], - "html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.js": [ - "37f13d24527fcdb5ded608b2ce58e1b51343cf96", - "support" - ], - "html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.worker.js": [ - "f08f131c44189e8aaf6c9bb34479a7cfaf6b586d", - "testharness" - ], "html/webappapis/system-state-and-capabilities/the-navigator-object/contains.json": [ "2c41fa08c5296f814d286d8b459424c5c488e3e1", "support" @@ -185581,6 +191279,10 @@ "3a478a2d6f508242244308641a2d57d4eb00798b", "testharness" ], + "html/webappapis/system-state-and-capabilities/the-navigator-object/navigator.any.js": [ + "defa186d15df9349c70ca1c2b4f4877e06f63d3e", + "testharness" + ], "html/webappapis/system-state-and-capabilities/the-navigator-object/navigatorlanguage.html": [ "8f141c495c1b4444c8e25ba57924d7917f97d1b9", "testharness" @@ -185633,6 +191335,22 @@ "49fd55dbbf64c6973a0e76284c0e3d8b7bf0ef3c", "testharness" ], + "html/webappapis/timers/negative-setinterval.html": [ + "405046cab9cd15a88d57eace1f293ebdd7b1b3e2", + "testharness" + ], + "html/webappapis/timers/negative-settimeout.html": [ + "e5673e7cca2b006afd3e2e4e5dd3e56fb10efa4e", + "testharness" + ], + "html/webappapis/timers/type-long-setinterval.html": [ + "83e3c7536d163ead98a008c7d9ff8cf41826371d", + "testharness" + ], + "html/webappapis/timers/type-long-settimeout.html": [ + "7945f54f8ab924c85f337ad5a50b02677d48e526", + "testharness" + ], "html/webappapis/user-prompts/.gitkeep": [ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "support" @@ -185709,6 +191427,10 @@ "c8337ab192542438d854f6cefdd94fd21f066d94", "support" ], + "images/apng.png": [ + "712e995068510d2a77771d34b37f3e9535572839", + "support" + ], "images/background.png": [ "aa8810c8893fdcefac46909a43dc4d58235a30c1", "support" @@ -185885,6 +191607,30 @@ "cd25518dd402033694667ccd1982fd3b85faa412", "testharness" ], + "interfaces/cssom.idl": [ + "bb17bbe93776dbeb33f061a7a90889e922e3138e", + "support" + ], + "interfaces/dom.idl": [ + "86f2e15d4b32af7b5127283eb3cfab5a78b46c0a", + "support" + ], + "interfaces/html.idl": [ + "8dc9bcafffab4ee66a806308b3cf5888af7cebba", + "support" + ], + "interfaces/touchevents.idl": [ + "6ce4f601cda6cd3b99a300e0b28d2886647f06d3", + "support" + ], + "interfaces/uievents.idl": [ + "3fabcfa40caf9c66bc74bcd83663eddb0f385051", + "support" + ], + "interfaces/webrtc-pc.idl": [ + "4f94c4236168ed722f71d81bd957e0da72b29c71", + "support" + ], "js/behaviours/SetPrototypeOf-window.html": [ "92efe1a4f3910a32097fb3cbeef0019d82a0e78a", "testharness" @@ -185953,6 +191699,26 @@ "581702f5f6b8f6e547918ae8f8a8547b103a9b6c", "testharness" ], + "keyboard-lock/idlharness.https.html": [ + "8b2fe1d77e8c4cc8a759a31bfb6f3d962f24992e", + "testharness" + ], + "keyboard-lock/navigator-cancelKeyboardLock.https.html": [ + "5109eb45591bba9ce48d3db91fa02c0590397886", + "testharness" + ], + "keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html": [ + "6a05080698fbeff768c4f5c85dbbc89cf3cfa09a", + "testharness" + ], + "keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html": [ + "79ed9f93e2f72bf8e11d04e25c6fa847c91971e4", + "testharness" + ], + "keyboard-lock/navigator-requestKeyboardLock.https.html": [ + "6f8091035f4aa18131c548a81cbe80ba328169c9", + "testharness" + ], "longtask-timing/longtask-attributes.html": [ "a88bd658adcb9ef3dcbfa803397910e531bc864b", "testharness" @@ -186001,14 +191767,30 @@ "4acb6764c2fb60ad55733c420dfd7c1946542f17", "support" ], + "magnetometer/Magnetometer.https.html": [ + "4e7d890f37469aecbce415187bb0bcf239dac37b", + "testharness" + ], + "magnetometer/Magnetometer_insecure_context.html": [ + "9708569b2e2764c973efe31e9f2f4e3de7f7a449", + "testharness" + ], + "magnetometer/Magnetometer_onerror-manual.https.html": [ + "6adfb807ff2c1b24dad702b21f636e7805543704", + "manual" + ], "magnetometer/OWNERS": [ "36770a71443523aa2f91f9958ba24066f0b4dcec", "support" ], "magnetometer/idlharness.https.html": [ - "0a9194605503377bad3f8e66dd60959d2ac5c909", + "b21217da9dc986e605d172d72a5f4f3e7b2aa216", "testharness" ], + "magnetometer/support-iframe.html": [ + "4afaea574bcbd68422278c5e093cf6d37ab4f9f1", + "support" + ], "mathml/README.md": [ "9a0f19770c7f633e06913d9d138e8f3a6d1a1104", "support" @@ -186465,12 +192247,12 @@ "7d6ceec9a74d5485a6f7d51504f22e5eaf81bfee", "support" ], - "media-capabilities/idlharness.html": [ - "d9a80463af2e0fc7bda0a4370a3ba0bbbb791897", + "media-capabilities/decodingInfo.html": [ + "1d8f79cb9e47042aa7eff1b63fe72af4941830e2", "testharness" ], - "media-capabilities/query.html": [ - "a83f2c7a7d9c38c707c4f96c3cd74f77185b7e43", + "media-capabilities/idlharness.html": [ + "0c34bb1872cc16b21c8c1f33d6dfd796f59500c8", "testharness" ], "media-source/OWNERS": [ @@ -186913,12 +192695,8 @@ "cb9a48e1d53911d5be214320adfbf7596632a316", "support" ], - "media/CanvasTest.ttf": [ - "10a7017b4caead6817aa08b25f14950e6402dd95", - "support" - ], "media/OWNERS": [ - "f478084fb2b04fe93435b3c33e9791bf613ba7f8", + "30004bfb49495e067cf71c702ac5985d24589c06", "support" ], "media/foo.vtt": [ @@ -186977,6 +192755,10 @@ "ceeb48e7982eb88561f4c1630cb0fcf15d9cf73c", "testharness" ], + "mediacapture-image/idlharness.html": [ + "7ccf7fcab0344a2e1893e89d7689e2312287b64d", + "testharness" + ], "mediacapture-record/BlobEvent-constructor.html": [ "29d5649ff97ca0631f8c841425a88248525f9774", "testharness" @@ -188461,6 +194243,10 @@ "6a0548ef4b906e539d89940aa791a78bba905262", "support" ], + "mixed-content/imageset.https.sub.html": [ + "e2005b813384f38b64baec9bc431e25aa61f417f", + "testharness" + ], "mixed-content/optionally-blockable/http-csp/cross-origin-http/audio-tag/top-level/keep-scheme-redirect/opt-in-blocks.https.html": [ "9219890ab0efa31e4f2db0646e12882da3a5443d", "testharness" @@ -188817,6 +194603,14 @@ "22ff29845d8417ccbae58123efe8e1c9b9c81eaf", "testharness" ], + "navigation-timing/nav2_test_document_replaced.html": [ + "b36ccb9a595ea5ab318f53dbff75b3c8f7c5b044", + "testharness" + ], + "navigation-timing/nav2_test_frame_removed.html": [ + "8ed53df25ff06d2affa9c438e3bb85d6dc9f34a1", + "testharness" + ], "navigation-timing/nav2_test_instance_accessible_from_the_start.html": [ "79bd2cff7e144ef3d1b093c542ad69302a0138b3", "testharness" @@ -188902,11 +194696,11 @@ "support" ], "navigation-timing/resources/webperftestharness.js": [ - "277312011faf560c6333a0810391e0cf50fdb61d", + "670154a84de50de0c6b310edfeb23a1f3d0d72d1", "support" ], "navigation-timing/test_document_open.html": [ - "13e0ed36e865e06060cfb4cf0d3efc6dfc09d684", + "627ec3a534f3e6ce030a7f5824a67f26f458b091", "testharness" ], "navigation-timing/test_document_readiness_exist.html": [ @@ -188914,71 +194708,71 @@ "testharness" ], "navigation-timing/test_navigate_within_document.html": [ - "c2a4e7340d17ed4dfbe0899e827a96a733997b7d", + "ee8c8581c79be154437e9765885c125d22593b9c", "testharness" ], "navigation-timing/test_navigation_attributes_exist.html": [ - "1dcf7144e6feb00f58fcfdf3c93b6bc65f49ff09", + "a1a9b3ebb814de031920729019d8917ddf906b12", "testharness" ], "navigation-timing/test_navigation_redirectCount_none.html": [ - "5b6f58efd9837f60f47d5ad1a691c8a183b6020b", + "d1308890904883b0a5d684f56b8201f30f8633ff", "testharness" ], "navigation-timing/test_navigation_type_backforward.html": [ - "39bafd06aab6f52e2e61181554cd5d1c0366c6d6", + "5a87b34ea921ef05ee43fe7cc3bdc4d2be56e2fd", "testharness" ], "navigation-timing/test_navigation_type_enums.html": [ - "65927fa5f352377fee57ff4ed86518f36efc4777", + "ca1a454659dd9b0790905ec4ebaa67fee16229c0", "testharness" ], "navigation-timing/test_navigation_type_reload.html": [ - "861072d2026f3fc4e35c7d3caf568eac2c8225a9", + "8b4e1b729a2f97932fe54018c8ea07629fb8ed00", "testharness" ], "navigation-timing/test_no_previous_document.html": [ - "7cf63a018da4a387b7c1f4599f786b6e0cf3211b", + "728aea673231311336585484140f975993198c9b", "testharness" ], "navigation-timing/test_performance_attributes_exist.html": [ - "93bb823553d23292d6f07b24d8d2e99135b5e75f", + "77ce7940ef510aad4545975e717bf5557dbfc948", "testharness" ], "navigation-timing/test_performance_attributes_exist_in_object.html": [ - "f20d7fca8a279f8df8ba221bf229374a387ce29d", + "2ab286b7504e1976d02e6880b758c22fba10ba17", "testharness" ], "navigation-timing/test_readwrite.html": [ - "f210f135fc9eb2040d81b3855eeccf34cfd81a35", + "20507630ddb21872b8eb5f0bca5d62064b8bd0ff", "testharness" ], "navigation-timing/test_timing_attributes_exist.html": [ - "c7d2b16b357482f0da04662d81f0bc1d9ff6696e", + "199aa3389a6a0adf6cb5b18d133c889728cb4411", "testharness" ], "navigation-timing/test_timing_attributes_order.html": [ - "db411d2ac783d49f059d24697fb0bea5e1b382d0", + "7719f088b9ff3bdedb8567ab9eab3f6ca776ecae", "testharness" ], "navigation-timing/test_timing_client_redirect.html": [ - "6d747b5ea0c0f56bbfa4fdbf44924b40fec39b04", + "c6aed0cb03b941e0b8c62a0b086099759b4b25ef", "testharness" ], "navigation-timing/test_timing_reload.html": [ - "8daff711c794f7e4f9d3f4fb4d2ef6df08df8ff9", + "57ba3573d672dbbc60695d049dec39efd5e1feb9", "testharness" ], "navigation-timing/test_timing_server_redirect.html": [ - "199cd011e687ac74b647c7f1fe5214f965d8f85c", + "10b7f221c4667e92a993f0aae70820a95ea445aa", "testharness" ], "navigation-timing/test_timing_xserver_redirect.html": [ - "f0ff9c47a25b6c6a93c6b5e0ffddc3b78444df14", + "a08120e4302c51307fa97de3d521c85c82adb53f", "testharness" ], "navigation-timing/test_unique_performance_objects.html": [ - "c7d89bf7a3119dbfe9a581f82b5ac43ff6645a64", + "b9d933d6a33eabc0b9c9f856c91b802677fa1094", "testharness" ], "notifications/OWNERS": [ @@ -196889,6 +202683,14 @@ "6948dbbdc88ffd9aa84ad5a6c822b354809561b2", "manual" ], + "orientation-sensor/OWNERS": [ + "36770a71443523aa2f91f9958ba24066f0b4dcec", + "support" + ], + "orientation-sensor/idlharness.https.html": [ + "049b5e9505165723cec70237e2ae5f0e2c7948f0", + "testharness" + ], "page-visibility/OWNERS": [ "b82f9756b15ef3ea45fb250e304031d9ceaee9c7", "support" @@ -196897,6 +202699,10 @@ "6bbcc548a783a56340aa256e5f51ca51c1b3f4d3", "testharness" ], + "page-visibility/prerender_call.html": [ + "17f8962a145f6bd7047f236b5b4eb7f825769004", + "testharness" + ], "page-visibility/resources/blank_page_green.html": [ "2d6d55d85e17a9fe978db6dbe25ae35a599d5683", "support" @@ -196905,6 +202711,10 @@ "63604473eabaa8d3b9b410a1a0087d9b4b2e7b90", "support" ], + "page-visibility/resources/prerender_target.html": [ + "9031b355d5f443b5b2f241c471823340a6d501a3", + "support" + ], "page-visibility/test_attributes_exist.html": [ "1fa7511396a6c7f114e31298b8c8ee72e5aac949", "testharness" @@ -196997,10 +202807,18 @@ "29af302db74de64e2bd1352ad92092a309d28c92", "testharness" ], + "payment-request/payment-request-id.https.html": [ + "3e74f97fdf39bb1ca9f2cb5596155705cd15b5b0", + "testharness" + ], "payment-request/payment-request-in-iframe.html": [ "26f2715d33e6d00e5ce03d7b07f35db2ac027acf", "testharness" ], + "payment-request/payment-request-response-id.html": [ + "88df88efdb1d44b56ac9758295f2e2920ae6c9ff", + "support" + ], "performance-timeline/OWNERS": [ "b82f9756b15ef3ea45fb250e304031d9ceaee9c7", "support" @@ -197062,7 +202880,7 @@ "testharness" ], "pointerevents/extension/pointerevent_coalesced_events_attributes-manual.html": [ - "3e8cfad251f604125c570c923b8fbe441f2b5d5b", + "f0393e603c25eb52d5144c95e808f2ab96cbe1f7", "manual" ], "pointerevents/extension/pointerevent_constructor.html": [ @@ -197162,7 +202980,7 @@ "manual" ], "pointerevents/pointerevent_pointerleave_pen-manual.html": [ - "084c13aa90b9cd0e542f3d8d9897964fa1ea01e0", + "6ea8a1bc811c6222ce5dc2c7102d67137152ce41", "manual" ], "pointerevents/pointerevent_pointermove-manual.html": [ @@ -197254,7 +203072,7 @@ "manual" ], "pointerevents/pointerevent_suppress_compat_events_on_drag_mouse-manual.html": [ - "b191ba60977fa384568def97c23d35c204a9ea73", + "074ac2e1e75c974a49f4615924986c7695656094", "manual" ], "pointerevents/pointerevent_touch-action-auto-css_touch-manual.html": [ @@ -197426,7 +203244,7 @@ "testharness" ], "preload/download-resources.html": [ - "f7e3c1ebfbb2b018dd0e5af4a81b0ab0eecac15c", + "c41bf773f52547e930503c588864c42c14416b86", "testharness" ], "preload/dynamic-adding-preload.html": [ @@ -197458,7 +203276,7 @@ "testharness" ], "preload/onload-event.html": [ - "a28bdbf41a8e74bee92ef00e77d283d198a77cfc", + "d00ad51acfea81056a2426d396c3a73d5f15120b", "testharness" ], "preload/preload-csp.sub.html": [ @@ -197470,7 +203288,7 @@ "testharness" ], "preload/preload-with-type.html": [ - "dbae18f696990e4f5b76ca1324141df8ae190fb8", + "b15b6022d8fd4bdc88e7a54429667eb223bc2464", "testharness" ], "preload/resources/dummy.css": [ @@ -197506,7 +203324,7 @@ "testharness" ], "preload/single-download-preload.html": [ - "e83015080694026c96466863c385e3425982479b", + "3ee15736925ad7eed449ff3074353140598461bd", "testharness" ], "presentation-api/OWNERS": [ @@ -197538,7 +203356,7 @@ "manual" ], "presentation-api/controlling-ua/PresentationConnection_send-manual.https.html": [ - "a2c002edf9dcc302390c8695afe1fc04025c32ee", + "4f34387b135ee40a6f8fc363659096409a1eb0bd", "manual" ], "presentation-api/controlling-ua/PresentationRequest_error.https.html": [ @@ -197554,7 +203372,7 @@ "testharness" ], "presentation-api/controlling-ua/PresentationRequest_onconnectionavailable-manual.https.html": [ - "b807b3936cec14007e739de3fc4e5077f67bbd56", + "7fb8f30c04407693c3bf9da9d1ae11937fc1f5c3", "manual" ], "presentation-api/controlling-ua/PresentationRequest_sandboxing_error.https.html": [ @@ -197566,19 +203384,23 @@ "testharness" ], "presentation-api/controlling-ua/PresentationRequest_success.https.html": [ - "b8c26ec718a198562154e75cb32eedfd1778cb01", + "74cc007c2472f11bdc08410f870f270e8e4b0f4a", "testharness" ], "presentation-api/controlling-ua/common.js": [ "6b788aa76cb93a0454839209bb84aa25cd38011f", "support" ], + "presentation-api/controlling-ua/defaultRequest.https.html": [ + "a2e430e3413075293534bf62b23ff0c8c5360282", + "testharness" + ], "presentation-api/controlling-ua/defaultRequest_success-manual.https.html": [ "a09556d22f83c79789942bc3cf316459175aede0", "manual" ], "presentation-api/controlling-ua/getAvailability.https.html": [ - "4a857ebc68eb00bde37206a01f7eae43fe5c1e01", + "80884de4235d7e98137a76c90fcc414efc8d1ac6", "testharness" ], "presentation-api/controlling-ua/getAvailability_sandboxing_success.https.html": [ @@ -197598,7 +203420,7 @@ "testharness" ], "presentation-api/controlling-ua/reconnectToPresentation_success-manual.https.html": [ - "c6fac0eba8eccf9697cc46bcc57e312ab4ab8ac2", + "645e6e6a5a8261c9f3f61c356d6e127aac8223da", "manual" ], "presentation-api/controlling-ua/startNewPresentation_displaynotallowed-manual.https.html": [ @@ -197626,7 +203448,7 @@ "manual" ], "presentation-api/controlling-ua/support/iframe.html": [ - "a827113e644e65e97085658d445a31d0341fa0ef", + "00156d2e5443ad4028af43e1a66ba2fbd226de14", "support" ], "presentation-api/controlling-ua/support/presentation.html": [ @@ -197641,8 +203463,28 @@ "f64f2ab5d0afa93e5adfa327e478936c0e295823", "support" ], + "presentation-api/receiving-ua/PresentationConnectionList_onconnectionavailable-manual.https.html": [ + "ac16b8b189403d4b3c520f69c1675b6acd979e18", + "manual" + ], + "presentation-api/receiving-ua/PresentationConnection_onclose-manual.https.html": [ + "e44406efbfe55bb74ac62d5fae7700102ce8e706", + "manual" + ], + "presentation-api/receiving-ua/PresentationConnection_onmessage-manual.https.html": [ + "3c98bfaf0bc18436501f724210a1f33d9f273573", + "manual" + ], + "presentation-api/receiving-ua/PresentationConnection_send-manual.https.html": [ + "4c699e42e5f19e0b47145b8ce1f235bc14c7cadf", + "manual" + ], + "presentation-api/receiving-ua/PresentationConnection_terminate-manual.https.html": [ + "0a3a7c6265cfd941ea2d394907bb577836bcd49b", + "manual" + ], "presentation-api/receiving-ua/PresentationReceiver_create-manual.https.html": [ - "fc5a9cd4202866b171c74f77c86272fae61ca919", + "1830e4420c668b77dbd835912f518920743c5592", "manual" ], "presentation-api/receiving-ua/cache.txt": [ @@ -197654,15 +203496,35 @@ "support" ], "presentation-api/receiving-ua/idlharness-manual.https.html": [ - "8670eb19b871b3e0f9c04b6f77bf6b313210d0bc", + "fdabdbe847d78dd22754d72ed62f293cd55227ee", "manual" ], "presentation-api/receiving-ua/serviceworker.js": [ "0aeff382c23d0ade231af0f478c40c7aeda626f7", "support" ], + "presentation-api/receiving-ua/support/PresentationConnectionList_onconnectionavailable_receiving-ua.html": [ + "8386247f99e2ef4e1a3378d499a8245d5ff3a5c8", + "support" + ], + "presentation-api/receiving-ua/support/PresentationConnection_onclose_receiving-ua.html": [ + "d925897d1ce2a15545e425d908ed7122ee657137", + "support" + ], + "presentation-api/receiving-ua/support/PresentationConnection_onmessage_receiving-ua.html": [ + "8dc8d4229c03ccc1575ccc2206f85574bbd79500", + "support" + ], + "presentation-api/receiving-ua/support/PresentationConnection_send_receiving-ua.html": [ + "0010c0a25797031ec9f2a3f56864329a43c84f34", + "support" + ], + "presentation-api/receiving-ua/support/PresentationConnection_terminate_receiving-ua.html": [ + "605596c4e21c4b1553fc5d9f26604aa81223ed42", + "support" + ], "presentation-api/receiving-ua/support/PresentationReceiver_create_receiving-ua.html": [ - "77e1d610f4cf30f0c9057870e0f4539f83f08222", + "84f37932fc911d5dbf692b42569b564ebf9b8e7d", "support" ], "presentation-api/receiving-ua/support/PresentationReceiver_create_receiving-ua_child.html": [ @@ -197673,16 +203535,20 @@ "d905cb811f8edb467dc76775fa7ae250c5d9428e", "support" ], - "presentation-api/receiving-ua/support/idlharness_receiving-ua.https.html": [ + "presentation-api/receiving-ua/support/idlharness_receiving-ua.html": [ "adffe1f696cf03f0041383992ab59e47db0ab8c0", "support" ], + "presentation-api/receiving-ua/support/iframe.html": [ + "d52f10c9971a36350150b39c8d3e800c24c941ac", + "support" + ], "presentation-api/receiving-ua/support/serviceworker.js": [ "6aec0aa7cee4f7a63951a41bec757acc6e486397", "support" ], "presentation-api/receiving-ua/support/stash.js": [ - "abaa736a325dd7e7ce12b092e8ee0162122f584d", + "f7a354462a5159ac11e56d13c5972ddfa5af0a70", "support" ], "presentation-api/receiving-ua/support/stash.py": [ @@ -205273,6 +211139,42 @@ "b5c7951856ebacd27c11a0685bb7730f02487fcb", "support" ], + "resource-timing/resource_TAO_match_origin.htm": [ + "32faacb791313be60380fa744608853b24442f42", + "testharness" + ], + "resource-timing/resource_TAO_match_wildcard.htm": [ + "f21fa1fac755e91b21293abfd738a1220cec57c2", + "testharness" + ], + "resource-timing/resource_TAO_multi.htm": [ + "1325e992dd31943fde96038c215a73db1c382ce6", + "testharness" + ], + "resource-timing/resource_TAO_null.htm": [ + "020acb6ea74fec2582c5d3320d91a2f647625f44", + "testharness" + ], + "resource-timing/resource_TAO_origin.htm": [ + "bd7572f9790c69cf76e31c2c1cc7d4c3bd35da4c", + "testharness" + ], + "resource-timing/resource_TAO_origin_uppercase.htm": [ + "83bb18cf7ec915595ad716b2b24e0bb01b7c4047", + "testharness" + ], + "resource-timing/resource_TAO_space.htm": [ + "5e4bf4e71b9b99db494896b1708600224e271fe8", + "testharness" + ], + "resource-timing/resource_TAO_wildcard.htm": [ + "2fbaf85feeb4e621f6e13d67232cc31e221da5d8", + "testharness" + ], + "resource-timing/resource_TAO_zero.htm": [ + "174444cc2f9b8e505bcf35343522f74c792bd997", + "testharness" + ], "resource-timing/resource_cached.htm": [ "819ac54de6901a911a34d63629b9f22be4502f42", "testharness" @@ -205285,6 +211187,10 @@ "1b6e111056101c88623eda6148042c310a5b7a6d", "testharness" ], + "resource-timing/resources/TAOResponse.py": [ + "9e8051a2ff8fff72b36ed1cecb61f9e7bba29071", + "support" + ], "resource-timing/resources/fake_responses.html": [ "c942abc1e8c1672935ffc8ce34821891345bacb9", "support" @@ -205297,6 +211203,42 @@ "dfddf3eb3e80d77163ae12a5df71ed3e9559722a", "support" ], + "resource-timing/resources/iframe_TAO_match_origin.html": [ + "9a3adace2991c7bd1876a904b6c4389633b9828f", + "support" + ], + "resource-timing/resources/iframe_TAO_match_wildcard.html": [ + "243dca266e68cd7a0e42d22a6336026b79849718", + "support" + ], + "resource-timing/resources/iframe_TAO_multi.html": [ + "58394e0163e68665b594d2d73cfccfdf28306e5f", + "support" + ], + "resource-timing/resources/iframe_TAO_null.html": [ + "3a244b286861c68a20ff44c05f7f8590e96cf6d0", + "support" + ], + "resource-timing/resources/iframe_TAO_origin.html": [ + "cf7447fe31cf12d488c432c4c3b93b990949c5ec", + "support" + ], + "resource-timing/resources/iframe_TAO_origin_uppercase.html": [ + "b29b2861966f0a8d0a8827b28885adc48522a324", + "support" + ], + "resource-timing/resources/iframe_TAO_space.html": [ + "80989e08c952b7598a44e73e17f655c0f59ca917", + "support" + ], + "resource-timing/resources/iframe_TAO_wildcard.html": [ + "62e23926dec6ab2bbb1f845582ea488b2619144f", + "support" + ], + "resource-timing/resources/iframe_TAO_zero.html": [ + "9fd73766be85d71a0456cf54dc2407ee74c3d1b8", + "support" + ], "resource-timing/resources/inject_resource_test.html": [ "f53513f6f47fd4a6d4994a4ef7d6e37d1777ea57", "support" @@ -205530,15 +211472,23 @@ "support" ], "selection/collapse-00.html": [ - "6c06617a84c3d4e5f121e4ccf8f7761ba1be1ceb", + "5254f4f69e12405381b474cbdd16725a5f7df599", + "testharness" + ], + "selection/collapse-15.html": [ + "abb690493dd6526a12587cecf43eafb59dc357fd", "testharness" ], "selection/collapse-30.html": [ - "943e7d8960212bc5d5eadb45ff641b9d9525a44a", + "042baecceea3be9b1b828e98e7738a454bf3f8f2", + "testharness" + ], + "selection/collapse-45.html": [ + "a66ab339d964529b3ba8a9af48eb26a4b9b55028", "testharness" ], "selection/collapse.js": [ - "4cd755764b43e348b2dcf23d1c800953ee28f059", + "fdeaf514b240bdeadd89829e3321465d3e376926", "support" ], "selection/collapseToStartEnd.html": [ @@ -205590,7 +211540,7 @@ "testharness" ], "selection/removeAllRanges.html": [ - "23385a72a586db288b282eb251f9384048532666", + "bd203d8878c4de59de476fe6fa7417bd2678dfcc", "testharness" ], "selection/removeRange.html": [ @@ -205609,14 +211559,10 @@ "3803c785b4a2fe2bbf9ecb895e6d3e1ae9e40164", "support" ], - "selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.html": [ - "abb13a7744101652436171cf8b62b0722ec71b65", + "selection/type.html": [ + "01ae6e757d428800555012783e290ebba575bcab", "testharness" ], - "selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.js": [ - "a7e8a78780937ab0b83081bba9914aefd931a355", - "support" - ], "selectors/attribute-selectors/attribute-case/cssom.html": [ "a7d352c93c9727bbdae2d44df7ea84baabf16252", "testharness" @@ -205642,13 +211588,37 @@ "testharness" ], "selectors/attribute-selectors/attribute-case/syntax.html": [ - "91d27c834a389e498f2e9c377bdb78eae7130c9e", + "dfb854d30a881f8765c6ee30bc334a440eb59dc2", "testharness" ], "selectors/child-indexed-pseudo-class.html": [ "cdf340dd83ea3a32d0d7edc31b5ded294585ef83", "testharness" ], + "server-timing/resources/blue.png": [ + "7de5cdb5ad04ac365430b3b5f5ba01d2ba57ea23", + "support" + ], + "server-timing/resources/blue.png.sub.headers": [ + "d14ff7ce6dce67417c14192a89f4fe2d31c099a7", + "support" + ], + "server-timing/resources/green.png": [ + "ef91d21307a12b2cfaf33a90dffe16aa1cba42c9", + "support" + ], + "server-timing/resources/green.png.sub.headers": [ + "e2fca01ea5a9c31731a1d5c4199849bf728da892", + "support" + ], + "server-timing/test_server_timing.html": [ + "eab2a2be6984346d7fd83c8f3dcc99b2f3e09a08", + "testharness" + ], + "server-timing/test_server_timing.html.sub.headers": [ + "c49030e9c6dabb55bff24b633b6660212bd2ecca", + "support" + ], "service-workers/OWNERS": [ "b74dce201157af7f50d382583674e1b979237f9b", "support" @@ -205690,27 +211660,31 @@ "support" ], "service-workers/cache-storage/resources/test-helpers.js": [ - "ba4146604450df04ac28946ca886ca90b2883843", + "fc315489c4d337f7cf8395beb4005be9c12da9d6", "support" ], "service-workers/cache-storage/script-tests/cache-add.js": [ - "286214ba5eda836e06f19c2bbc1d6c1fc42cc4fd", + "5807ce231254f89d9e5f2fc43955a8dda5bd865d", "support" ], "service-workers/cache-storage/script-tests/cache-delete.js": [ - "7af12ed2fc082b7efae95f3fb7b241410d2d640f", + "997017dfefc7c1f55cdc3122c2a58ff3d70b8141", + "support" + ], + "service-workers/cache-storage/script-tests/cache-keys.js": [ + "b21b2dda441fcd8fd7e3ae3d60de91bfef0b5f15", "support" ], "service-workers/cache-storage/script-tests/cache-match.js": [ - "7c5daf1029acb604383f20f8bff92db66af0ef51", + "0204ef8205dd31a9af01b3dacd0f2608fa6eb35d", "support" ], "service-workers/cache-storage/script-tests/cache-matchAll.js": [ - "4b4cb079f28e4bcede4b07901f58882d8d2ffcdc", + "381765d1ce951a62d42d7a565f6e856e91ba3f55", "support" ], "service-workers/cache-storage/script-tests/cache-put.js": [ - "3c2022f877364cdd9cd60beec8c7d2e3037a5a4c", + "00d90c0901aef4fd65811cde2daa7da027b46251", "support" ], "service-workers/cache-storage/script-tests/cache-storage-keys.js": [ @@ -205718,11 +211692,11 @@ "support" ], "service-workers/cache-storage/script-tests/cache-storage-match.js": [ - "40856b0d38cdc409e3245a12506ae2c9521625a6", + "e3cc14ea5d0587c43a5b142fca84788383b549cb", "support" ], "service-workers/cache-storage/script-tests/cache-storage.js": [ - "f31eb0025fd3feb3e12c7428c3a048553cdb0492", + "43a44ad35e90ce759de7a855f75b149b756029b4", "support" ], "service-workers/cache-storage/serviceworker/cache-add.https.html": [ @@ -205733,6 +211707,10 @@ "6484fca817f556be3ffead18f162649c0fbfba30", "testharness" ], + "service-workers/cache-storage/serviceworker/cache-keys.https.html": [ + "c1f638bea1f897b086ce403b7a87fe4fd7b77b25", + "testharness" + ], "service-workers/cache-storage/serviceworker/cache-match.https.html": [ "385a521cd183a11c3ab88c8c9e8e22e109691764", "testharness" @@ -205769,6 +211747,10 @@ "8b02db13f96f2d9328e5a7cc4c55dd58bd23618c", "testharness" ], + "service-workers/cache-storage/window/cache-keys.https.html": [ + "be44bcee176090ffc0380cce2611a6e1350bbad7", + "testharness" + ], "service-workers/cache-storage/window/cache-match.https.html": [ "511502a763c53d3fd642aca9e1e1c0c4b610f8ce", "testharness" @@ -205805,6 +211787,10 @@ "6e75a546b1646e8a97aa43aa9cf5434402dca064", "testharness" ], + "service-workers/cache-storage/worker/cache-keys.https.html": [ + "b1a90bfc9676e2cb20316a7a6852a5df016ef797", + "testharness" + ], "service-workers/cache-storage/worker/cache-match.https.html": [ "8149bf9fc2756cdbedbe48d2d5184713d1623ecc", "testharness" @@ -205853,6 +211839,10 @@ "559815205e99f825fdc0a0f2564e7e25586f3c05", "support" ], + "service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js": [ + "41b92697bbc0b75ce1087f8437afefb52ea7ce7a", + "support" + ], "service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-constructor-worker.js": [ "1ac8fb8c675c398257be0be676872b2944418aa8", "support" @@ -205909,6 +211899,10 @@ "93d2aace8471bcb120a3d7c2029af360220e9b91", "support" ], + "service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html": [ + "f5f263a3c0f9e154f8b43425f3f42cb792f483a3", + "testharness" + ], "service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html": [ "9fe4c10b921a84dc086cea47d48bb34fdbb28eee", "testharness" @@ -205957,20 +211951,28 @@ "dac61fcadc94d01fa1f46ac65d81c0405d90ecd3", "testharness" ], + "service-workers/service-worker/client-id.https.html": [ + "bc07ff54eaf1fecc2a46ebcf34059590ac8c866d", + "testharness" + ], "service-workers/service-worker/client-navigate.https.html": [ "c0403a4538bf063745a59f5848e30b13d1b3afc1", "testharness" ], + "service-workers/service-worker/clients-get-client-types.https.html": [ + "e86b86beb47802f4204510c44edc1465cab5d5f2", + "testharness" + ], "service-workers/service-worker/clients-get-cross-origin.https.html": [ - "21ed1eab21bb6f0b342895c8185ecb92afe93b79", + "56d9095dde507aadbd47d3b27d304825b5b8198e", "testharness" ], "service-workers/service-worker/clients-get.https.html": [ - "32ccf7734a7d0d40205c4fd30b393b175e6507bd", + "3627915a40ca2903f979560209f9a169a41429e2", "testharness" ], "service-workers/service-worker/clients-matchall-client-types.https.html": [ - "aaca38d0ad5e6a03775632fcef1657dd40753ae0", + "02003bd248ffb0d54238339179105836ac7c4e14", "testharness" ], "service-workers/service-worker/clients-matchall-exact-controller.https.html": [ @@ -205981,6 +211983,10 @@ "a4f4cb575ffea826c642aa3de424c0a0f986fdd0", "testharness" ], + "service-workers/service-worker/clients-matchall-on-evaluation.https.html": [ + "9737491d653de76a70f9c0143baa70760f2f95c4", + "testharness" + ], "service-workers/service-worker/clients-matchall-order.https.html": [ "b2617b7dce0dce64c1a354a3dc07c67f1fa0adf2", "testharness" @@ -206006,7 +212012,7 @@ "testharness" ], "service-workers/service-worker/extendable-event-waituntil.https.html": [ - "9232c93bc437aa6c32a2a82db03e622b96d23395", + "401235c18e1594c7248b22eb6881d54801de9809", "testharness" ], "service-workers/service-worker/fetch-canvas-tainting-cache.https.html": [ @@ -206022,7 +212028,7 @@ "testharness" ], "service-workers/service-worker/fetch-csp.https.html": [ - "97fff975592937acda3e8f363685dc9a835c12be", + "acf1f933e5c399812c767b0ee0fc4aa9fbd08bab", "testharness" ], "service-workers/service-worker/fetch-event-after-navigation-within-page.https.html": [ @@ -206030,19 +212036,23 @@ "testharness" ], "service-workers/service-worker/fetch-event-async-respond-with.https.html": [ - "6ea721f98b2d145eeeb07b762901b9cfa1b51fbd", + "00c90429203c85ae8f10a6a6604cdf9619524f06", "testharness" ], "service-workers/service-worker/fetch-event-network-error.https.html": [ - "ee1cd2ed2c3204af53422116289c558f5eff68d9", + "07b81a0af207ee0723a9abae90e49482701f8935", "testharness" ], "service-workers/service-worker/fetch-event-redirect.https.html": [ "2a6f2d4f818ac325edd9c69c1b08801961728b20", "testharness" ], + "service-workers/service-worker/fetch-event-respond-with-argument.https.html": [ + "ce7e7cf76aace24a92d455cdb6b54fc9048960e8", + "testharness" + ], "service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html": [ - "2feaa5022ee31fb980f97075d932b0d87d6efe75", + "7d9e18d316c74f2b887f01a4576eb14b10d99b14", "testharness" ], "service-workers/service-worker/fetch-event-throws-after-respond-with.https.html": [ @@ -206058,7 +212068,7 @@ "testharness" ], "service-workers/service-worker/fetch-event.https.html": [ - "fb2b3ea20415d9148cfda983ac785f0de16e6889", + "9f991210c315a2d436f760b099a43871692c64c4", "testharness" ], "service-workers/service-worker/fetch-frame-resource.https.html": [ @@ -206134,7 +212144,7 @@ "testharness" ], "service-workers/service-worker/getregistrations.https.html": [ - "d76c66c08bd5c1addbdb149447f2268ac52ffcb2", + "15c2be991ec5b02a0aecf54e6c7bb455f240141d", "testharness" ], "service-workers/service-worker/indexeddb.https.html": [ @@ -206150,7 +212160,7 @@ "testharness" ], "service-workers/service-worker/interfaces.https.html": [ - "9153cc6536203170ba8d2189d7646200a1ded72e", + "f5e18c249ad8264548923f3c875ffeff523ab424", "testharness" ], "service-workers/service-worker/invalid-blobtype.https.html": [ @@ -206229,6 +212239,10 @@ "fd50f2fd601e136d12fe815e6c1b8d5803663449", "testharness" ], + "service-workers/service-worker/navigation-preload/resource-timing.https.html": [ + "837273105d7a1521feff32338cdef7185a6786e3", + "testharness" + ], "service-workers/service-worker/navigation-preload/resources/broken-chunked-encoding-scope.asis": [ "d1fd50a8f194803dcc0c0f6d74bdc57197c3d6e5", "support" @@ -206281,6 +212295,14 @@ "0c02f9eb1f83a96f16d1d0f82669c78cc26e662d", "support" ], + "service-workers/service-worker/navigation-preload/resources/resource-timing-scope.py": [ + "817076c96f471bbdd8795478c70c7141cb1a5d24", + "support" + ], + "service-workers/service-worker/navigation-preload/resources/resource-timing-worker.js": [ + "8eb75e9bb7e3aaec818427b5f101a5d2353e65bf", + "support" + ], "service-workers/service-worker/navigation-preload/resources/wait-for-activate-worker.js": [ "a6ac7ce51f0c0ea47f2d9bbeb44d8db7d3f7864f", "support" @@ -206417,6 +212439,10 @@ "e779a28c42928ff10219073171c1216c6623b4d4", "support" ], + "service-workers/service-worker/resources/client-id-worker.js": [ + "7acc5dacbe27fb1a75bf8f5e4b6266c783368056", + "support" + ], "service-workers/service-worker/resources/client-navigate-frame.html": [ "ecad40948e5d00ca737ea91b702ebbecc268e53b", "support" @@ -206429,6 +212455,18 @@ "efb9dd2b3468305396a3767fc780d07525bd8e61", "support" ], + "service-workers/service-worker/resources/clients-get-client-types-frame.html": [ + "b41374d117b96fd2a702b7de3b6df08365032c95", + "support" + ], + "service-workers/service-worker/resources/clients-get-client-types-shared-worker.js": [ + "801473dd69333f8081201ed0f3d7f53cca30753b", + "support" + ], + "service-workers/service-worker/resources/clients-get-cross-origin-frame.html": [ + "a883adc270b47c6a104d10fd7dd9e6bc32c31315", + "support" + ], "service-workers/service-worker/resources/clients-get-frame.html": [ "2a34fdfb584674ef7b534fb91b313fc630ac0ffa", "support" @@ -206438,19 +212476,23 @@ "support" ], "service-workers/service-worker/resources/clients-get-worker.js": [ - "cab646738d3d9662756dcd337718ae02ea234313", + "7b9493735cdb2d06bab7331d1840c34631e04e32", "support" ], "service-workers/service-worker/resources/clients-matchall-client-types-iframe.html": [ - "3c8866699d99cfaf61c52ca7a5dafc058a8c349d", + "267de6ff27e4227682bbfdb86aeb3111d36d62cb", "support" ], "service-workers/service-worker/resources/clients-matchall-client-types-shared-worker.js": [ "5478ccfd9942f5ccb8335e6e13b52722b22e06d8", "support" ], + "service-workers/service-worker/resources/clients-matchall-on-evaluation-worker.js": [ + "e92684d1db4e8aef274fdd5e30abea48490b5659", + "support" + ], "service-workers/service-worker/resources/clients-matchall-worker.js": [ - "88326b2119c68ba656c62a74b9c1af201bca1548", + "1557f173e6cc5d1540ed9d78e8c9216b312fabb5", "support" ], "service-workers/service-worker/resources/dummy-shared-worker-interceptor.js": [ @@ -206506,7 +212548,7 @@ "support" ], "service-workers/service-worker/resources/extendable-event-waituntil.js": [ - "f3506e9043b7d2163f486ae8461caecca3b63320", + "99b76538a42556ac6e588a246b6a25bf7aec9cc5", "support" ], "service-workers/service-worker/resources/fail-on-fetch-worker.js": [ @@ -206530,7 +212572,7 @@ "support" ], "service-workers/service-worker/resources/fetch-csp-iframe.html": [ - "0c82ccc773dc644bac0cef39faadcb3280c0c6f4", + "2c5420e191b2b891233d0c99624f022c1bb936fa", "support" ], "service-workers/service-worker/resources/fetch-csp-iframe.html.sub.headers": [ @@ -206557,12 +212599,20 @@ "f24007259baeab7e9a6932d35e0b2a5305b159a4", "support" ], + "service-workers/service-worker/resources/fetch-event-respond-with-argument-iframe.html": [ + "4a9d7e189909b5adfdd4d1c0ebddb7cd90fde159", + "support" + ], + "service-workers/service-worker/resources/fetch-event-respond-with-argument-worker.js": [ + "b58b92a145a89f71c414de5e837c1db026beb1d6", + "support" + ], "service-workers/service-worker/resources/fetch-event-respond-with-stops-propagation-worker.js": [ "900fd1c2080fbb386589f7d6ee52c49da9d4fcb8", "support" ], "service-workers/service-worker/resources/fetch-event-test-worker.js": [ - "ca79da139169762737411cb6cffb66b55b901d04", + "f9eab9a493f43ec5a8a662815a979e70fb3e3900", "support" ], "service-workers/service-worker/resources/fetch-event-within-sw-worker.js": [ @@ -206681,6 +212731,10 @@ "c5f88c11333ff1faba5d57812a36553d174ab711", "support" ], + "service-workers/service-worker/resources/import-mime-type-worker.py": [ + "7881cd81f7fe54bf3be799f3549098c78b896574", + "support" + ], "service-workers/service-worker/resources/indexeddb-worker.js": [ "ed0ff45423ba74ad0b82e46debd865fdae2fbcb6", "support" @@ -206694,7 +212748,7 @@ "support" ], "service-workers/service-worker/resources/interfaces-worker.sub.js": [ - "67190b30c485fe743de1515fe5c593aad584fcb3", + "c94ee8dee0233f31c4f1577bf8b4bda5d2be2209", "support" ], "service-workers/service-worker/resources/interfaces.js": [ @@ -206862,7 +212916,7 @@ "support" ], "service-workers/service-worker/resources/registration-tests.js": [ - "5588535a80930c1d526d3b94ec7930a191d729db", + "bdb31335f8d15de455108e0186183f1acdaef41e", "support" ], "service-workers/service-worker/resources/registration-worker.js": [ @@ -207421,6 +213475,10 @@ "fa2864cbf8e88250a793beeacf737c7d9413cdf2", "testharness" ], + "shadow-dom/slots-fallback-in-document.html": [ + "eac2fee4991725b4d2ca104a586c02d109b7d721", + "testharness" + ], "shadow-dom/slots-fallback.html": [ "595bf7e71283bcf219849ebe13a1b913cd36f1b9", "testharness" @@ -207713,6 +213771,14 @@ "bc28599cea839c13daf4739168f8c1ea42526050", "testharness" ], + "staticrange/OWNERS": [ + "290c71b49f1147778f51898e114db808b4568549", + "support" + ], + "staticrange/idlharness.html": [ + "16f30a68d97edf19c5255328fd1460ac54a4c025", + "testharness" + ], "storage/OWNERS": [ "2c585ecaee5e62118d3cb98c98e12d959ebcbd50", "support" @@ -207757,6 +213823,14 @@ "98be04abdc48c76b30f90af007f214f9759083dd", "testharness" ], + "storage/resources/storagemanager-persist-worker.js": [ + "a9d24b2477938410371bae881a05a68cd56fe72e", + "support" + ], + "storage/resources/storagemanager-persisted-worker.js": [ + "a8031dd016d09d623fd438cee7e78f0a214936d9", + "support" + ], "storage/storage-estimate-indexeddb.js": [ "660d3d068314c34d215df19c0b849ec711f57854", "support" @@ -207765,6 +213839,26 @@ "dbf6e5bed3dec6ca59926c439ec9d6aca89d78b9", "support" ], + "storage/storagemanager-estimate.https.html": [ + "6319416d647f1671a7b8d36bbb4d79495e76a956", + "testharness" + ], + "storage/storagemanager-persist-worker.https.html": [ + "d51415a75f68ae5b2f8b537e25fea6f555192529", + "testharness" + ], + "storage/storagemanager-persist.https.html": [ + "88e43b4e061a7577fb0030eb0343e1e6c1cd9b6a", + "testharness" + ], + "storage/storagemanager-persisted-worker.https.html": [ + "b59e7df0e84747adbea6f281e6ecdd6d9d8435f0", + "testharness" + ], + "storage/storagemanager-persisted.https.html": [ + "a48435451fe9498f3aa7427c695c2e3407876d9b", + "testharness" + ], "streams/OWNERS": [ "5ed27d1c21178be00e972816933945e094a0e170", "support" @@ -207846,7 +213940,7 @@ "testharness" ], "streams/piping/close-propagation-forward.js": [ - "0846ba92abb8ace6c5438d918b2db23badc090b2", + "955736af478e8ec307dfe00a461f4b72949b110d", "support" ], "streams/piping/close-propagation-forward.serviceworker.https.html": [ @@ -207906,7 +214000,7 @@ "testharness" ], "streams/piping/flow-control.js": [ - "c39ecfb633e95ce4b4eac41d33d7268d3a5f768b", + "5f0665dd1618dc75423862d26debeac05caacac9", "support" ], "streams/piping/flow-control.serviceworker.https.html": [ @@ -207946,7 +214040,7 @@ "testharness" ], "streams/piping/multiple-propagation.js": [ - "c2a5c855e9abbacfe500a9339ff586a16bb8ae7a", + "8d00cd13d84d421a297bff499511d96f7b72c98c", "support" ], "streams/piping/multiple-propagation.serviceworker.https.html": [ @@ -207966,7 +214060,7 @@ "testharness" ], "streams/piping/pipe-through.js": [ - "08daa95df8e64c57f082b297ffd8bd11cda54d26", + "bf2cebbca84051b446f728d92c065869207299f2", "support" ], "streams/piping/pipe-through.serviceworker.https.html": [ @@ -208006,7 +214100,7 @@ "testharness" ], "streams/readable-byte-streams/general.js": [ - "b5d2f4c72f2e365e0716897a2fd398600e4eac6c", + "e8d971fb6491da06f9ceedb1b6cd6a5c06b6f3b4", "support" ], "streams/readable-byte-streams/general.serviceworker.https.html": [ @@ -208146,7 +214240,7 @@ "testharness" ], "streams/readable-streams/floating-point-total-queue-size.js": [ - "9e6ba92e9b69437c23f04c80fff47c951e509db1", + "905ea4815c8444a70d1fe3a2e1c2c36ff259c285", "support" ], "streams/readable-streams/floating-point-total-queue-size.serviceworker.https.html": [ @@ -208258,7 +214352,7 @@ "testharness" ], "streams/resources/recording-streams.js": [ - "64f85212b966489f92c7379e270dd0ed5a9ddb8d", + "df4bb8dab4b7e70758f87822c0472e96baec8b45", "support" ], "streams/resources/rs-test-templates.js": [ @@ -208282,7 +214376,7 @@ "testharness" ], "streams/writable-streams/aborting.js": [ - "2a0695350efde1366b5123ade654bea8a7b27e42", + "73be2b0af40871af1e2cd65d99f4591d45cee3aa", "support" ], "streams/writable-streams/aborting.serviceworker.https.html": [ @@ -208382,7 +214476,7 @@ "testharness" ], "streams/writable-streams/close.js": [ - "fce65083e9b7c69d52d696948669df92456422ed", + "a0f0183652427bdcd049eac90eb52d1ba5e09110", "support" ], "streams/writable-streams/close.serviceworker.https.html": [ @@ -208402,7 +214496,7 @@ "testharness" ], "streams/writable-streams/constructor.js": [ - "cc69b69308c1c51832488909cf962e580ff1dc3c", + "0f67e4c79f7a7d32c29b14b917e8921dbb3171c1", "support" ], "streams/writable-streams/constructor.serviceworker.https.html": [ @@ -208433,6 +214527,26 @@ "875e0dffe7710c21bfcb8f554c2216626c2eb013", "testharness" ], + "streams/writable-streams/error.dedicatedworker.html": [ + "c1876a4e28900174a13d59d82acb4e60e7b4a965", + "testharness" + ], + "streams/writable-streams/error.html": [ + "9d020a2e9a22b420997c301ca732a406ed53c21d", + "testharness" + ], + "streams/writable-streams/error.js": [ + "4d453557abcefc69168fa399e04226f37dbf1142", + "support" + ], + "streams/writable-streams/error.serviceworker.https.html": [ + "d8a0b8b68a7a59c9bf186336a6e22f34912fb7e5", + "testharness" + ], + "streams/writable-streams/error.sharedworker.html": [ + "0eaf67b6f635e95fe96a95082d4015cc9f427eef", + "testharness" + ], "streams/writable-streams/floating-point-total-queue-size.dedicatedworker.html": [ "e07b6c46f7975b76a309ac9b728e4215d5e7fe9d", "testharness" @@ -208442,7 +214556,7 @@ "testharness" ], "streams/writable-streams/floating-point-total-queue-size.js": [ - "14d4a8f5559831fb266061e75177339ba0073edb", + "33db80c0ab6a4794e26816d83e6ece39b707ed63", "support" ], "streams/writable-streams/floating-point-total-queue-size.serviceworker.https.html": [ @@ -208462,7 +214576,7 @@ "testharness" ], "streams/writable-streams/general.js": [ - "7a6fb1ccd2f77edc2077ec127716d3d2edcf8475", + "4f07b059c3b2d90ca0c08ffe014e3e77ade70be0", "support" ], "streams/writable-streams/general.serviceworker.https.html": [ @@ -208473,6 +214587,26 @@ "44f9ceaa3bfc9d8b92885997d322486bd0f237a6", "testharness" ], + "streams/writable-streams/properties.dedicatedworker.html": [ + "0d766237560b16ddb1bfcd02e701089132f1b3ec", + "testharness" + ], + "streams/writable-streams/properties.html": [ + "82a278a1e8599b5bbd1ab8abadfb13d85f45aa5e", + "testharness" + ], + "streams/writable-streams/properties.js": [ + "651d62037ceff95818e8cd33c078a31e09dafd5c", + "support" + ], + "streams/writable-streams/properties.serviceworker.https.html": [ + "2ef8fc878249c429a89e0748e6a98fac47c1a99a", + "testharness" + ], + "streams/writable-streams/properties.sharedworker.html": [ + "5c855e897d1143092ecc10b58268e6a576882184", + "testharness" + ], "streams/writable-streams/reentrant-strategy.dedicatedworker.html": [ "5d9e5a6b69fbe79183ac6e0d2c8559f13be6e386", "testharness" @@ -208502,7 +214636,7 @@ "testharness" ], "streams/writable-streams/start.js": [ - "09fcde6f0a4652c9549a6d94206e0403a7d86046", + "efd4b220ff356a542efdd57293993e5deff3a884", "support" ], "streams/writable-streams/start.serviceworker.https.html": [ @@ -210826,7 +216960,7 @@ "support" ], "svg/interfaces.html": [ - "fed926aefa9ebdf5f3972c6f1ee13af006c04545", + "0c355e7adc334d000991f4181d3bf254302eb915", "testharness" ], "svg/linking/reftests/href-a-element-attr-change.html": [ @@ -211009,12 +217143,16 @@ "bf426dc592940dbabd23db6c2343bcc5d29dc4b8", "support" ], + "uievents/auxclick/auxclick_event-manual.html": [ + "464073435190f51b2725653a0a0589e10f136d2d", + "manual" + ], "uievents/constructors/README.md": [ "771f659821e2860457b741385606f714acc01e05", "support" ], "uievents/constructors/inputevent-constructor.html": [ - "757b9777e0cd956a27f036a1524c378bd922852b", + "5af5377e8f5435b7c7bfafa2808e0a8dcf848ce4", "testharness" ], "uievents/hierarchy/README.md": [ @@ -211333,6 +217471,10 @@ "58f5c03e1f544b12e467663cc2bc0c15673f80b9", "support" ], + "uievents/mouse/mouseevent_move_button-manual.html": [ + "9cc673035fef3c2e8677e8d6679babfe8a1af854", + "manual" + ], "uievents/order-of-events/README.md": [ "3a3e6ab77d25a8fe83085e24c0934e4b63eea553", "support" @@ -211430,7 +217572,7 @@ "support" ], "url/README.md": [ - "3dacc2783865ba292f20b72bc4c3942de521d9b0", + "165b2a70da8bc2a7df3fe424a540f36b4f7be899", "support" ], "url/a-element-origin-xhtml.xhtml": [ @@ -211458,15 +217600,11 @@ "support" ], "url/failure.html": [ - "900755b25db687f1e793fe4cf18cfc456c35060a", + "908456e354703473b0806bbdac6d60216505905f", "testharness" ], - "url/historical.html": [ - "94451e509174184811374cb8f0a346e76510eb54", - "testharness" - ], - "url/historical.worker.js": [ - "d49e244853c361ad0d62269f48c8c5fe2661bc8f", + "url/historical.any.js": [ + "89dd0f84e69896c802c7a2062c9f4846cdca98c6", "testharness" ], "url/interfaces.html": [ @@ -211502,7 +217640,7 @@ "testharness" ], "url/urlsearchparams-constructor.html": [ - "81ea36ecd56373eb88984d6b488c71210ade2419", + "854e06efa9598f66705605bdef20c4a500ab2e9b", "testharness" ], "url/urlsearchparams-delete.html": [ @@ -211538,7 +217676,7 @@ "testharness" ], "url/urltestdata.json": [ - "6aa13a2c98f03031f1225a035890fc77a76efc52", + "f99eff3fa00a813fc77deaee2d2c08a19df10af9", "support" ], "user-timing/OWNERS": [ @@ -211598,7 +217736,7 @@ "testharness" ], "user-timing/measure.html": [ - "9b753ac314aabc2e4ec6aee7381b956e7f345b78", + "8374bbae73ac549b6c8b953d25948ed33b579591", "testharness" ], "user-timing/measure_exceptions_navigation_timing.html": [ @@ -211606,7 +217744,7 @@ "testharness" ], "user-timing/measure_navigation_timing.html": [ - "9bc61c9ae7d5c83f883270c98db6cd088bb0ecd2", + "b54bbb96f5c24b61e4d64a3633229781213d9cd2", "testharness" ], "user-timing/measure_syntax_err.any.js": [ @@ -211614,7 +217752,7 @@ "testharness" ], "user-timing/resources/webperftestharness.js": [ - "8b534ce21f036d46da0183bd36676c7b0a2f468d", + "b1f81236de54467168bd09d749c2a6f453c5c3e1", "support" ], "user-timing/resources/webperftestharnessextension.js": [ @@ -211686,13 +217824,905 @@ "manual" ], "wai-aria/OWNERS": [ - "16577d2283b826f0541dbc795177c7aac7e1b228", + "3a6002295ea2893ba74763e46965bd2d1291d55b", "support" ], "wai-aria/README.md": [ "fcb3247bdc42a962ad609232f3be562d13d630e3", "support" ], + "wai-aria/alertdialog_modal_false-manual.html": [ + "0de73d9a74e7f78a9476bba21b864475de8a7c8f", + "manual" + ], + "wai-aria/alertdialog_modal_true-manual.html": [ + "29a80fa8a8591c807adbb00270f0414bb698d323", + "manual" + ], + "wai-aria/application_activedescendant-manual.html": [ + "bb1908682085e0fe5e6f8f8361719c54256c06d9", + "manual" + ], + "wai-aria/application_activedescendant_value_changes-manual.html": [ + "7807dfc3aeca40e8ad49552e776f57d47e0178a9", + "manual" + ], + "wai-aria/aria-current_not_declared-manual.html": [ + "09820c997597e553a63e00c221b7e4b84f046502", + "manual" + ], + "wai-aria/aria-current_with_value_changes-manual.html": [ + "6d54a2b300e056dfcde46e9927290181feac7134", + "manual" + ], + "wai-aria/aria-current_with_value_date-manual.html": [ + "30803e78105fafc30a07c216f120364a707ebac9", + "manual" + ], + "wai-aria/aria-current_with_value_location-manual.html": [ + "4f9d6be77ffc0b23931a888de25f0a66223bcbd6", + "manual" + ], + "wai-aria/aria-current_with_value_page-manual.html": [ + "92177233e85d8fb360d0524a127a31fc6bbc22cc", + "manual" + ], + "wai-aria/aria-current_with_value_step-manual.html": [ + "f1fafedacdca36c23a612c699124efc2f0248e15", + "manual" + ], + "wai-aria/aria-current_with_value_time-manual.html": [ + "8b88be430db3fd4b9b05ab214a38389448150521", + "manual" + ], + "wai-aria/aria-current_with_value_true-manual.html": [ + "f9df9114542cd0fc91325634ec29db307ca101a6", + "manual" + ], + "wai-aria/aria-current_with_value_unspecified-manual.html": [ + "03743f07be87703262043f210f7ec2befc11ebd0", + "manual" + ], + "wai-aria/aria-details_pointing_to_details_element-manual.html": [ + "ad05a971809cfd9cd5e6d63ab886c481323ebdc6", + "manual" + ], + "wai-aria/aria-details_pointing_to_div_element-manual.html": [ + "f2d2d715de30a4edc1ef3d4d75a13ec02562ced8", + "manual" + ], + "wai-aria/article_in_feed_posinset_and_setsize-manual.html": [ + "8cba7e2c8d9fa2790bca392da39d14c7402ca6e4", + "manual" + ], + "wai-aria/article_in_feed_setsize_-1-manual.html": [ + "2a3820bd35c9de6efdbdd8944e66e1c129522abe", + "manual" + ], + "wai-aria/article_not_in_feed_posinset_and_setsize-manual.html": [ + "5074dfe55d125288b51081b9fdd78c78400b563d", + "manual" + ], + "wai-aria/button_haspopup_dialog-manual.html": [ + "c31b9e0b6f4a0ecebfb0ced36198110b8481167d", + "manual" + ], + "wai-aria/button_haspopup_emptystring-manual.html": [ + "526ed0373a6730ff4c2aad3bdb644029f673d046", + "manual" + ], + "wai-aria/button_haspopup_false-manual.html": [ + "c2b1e86859ef7cd770a0f2fd7de82155a3968315", + "manual" + ], + "wai-aria/button_haspopup_foo-manual.html": [ + "4f3c0d8f93cf46ec8ff58d7ff33fe61146f1f73f", + "manual" + ], + "wai-aria/button_haspopup_grid-manual.html": [ + "147b1fa883ecf96f992a24bf6aee032a69ce14c7", + "manual" + ], + "wai-aria/button_haspopup_listbox-manual.html": [ + "139d8ebf9b91bc019da5a14656d7f9e5a26f4ae5", + "manual" + ], + "wai-aria/button_haspopup_menu-manual.html": [ + "524f95729ccb3ec81450f3b5c112efa7ccdc1357", + "manual" + ], + "wai-aria/button_haspopup_tree-manual.html": [ + "a21792deec4d3448f0110f1b88bcd87611ca9213", + "manual" + ], + "wai-aria/button_haspopup_true-manual.html": [ + "e48345755b57d0d4d8b08ba1d2805ce51835c020", + "manual" + ], + "wai-aria/button_haspopup_unspecified-manual.html": [ + "5433922f0ab71e390ca9e0e7a46551ebfd44dc87", + "manual" + ], + "wai-aria/button_roledescription_empty-manual.html": [ + "066f803e5809813e84a2fffecb39142429191f3e", + "manual" + ], + "wai-aria/button_roledescription_valid-manual.html": [ + "6d18a279c9a9e471fad81c1313db3b9d04999ea0", + "manual" + ], + "wai-aria/button_roledescription_whitespace_only-manual.html": [ + "b8a231f8bad4cb5626b7b687d81067ebe891b961", + "manual" + ], + "wai-aria/cell-manual.html": [ + "1ea5f605642328e07a67d78d96a59849b3439120", + "manual" + ], + "wai-aria/cell_aria-colspan_2_on_div-manual.html": [ + "dea621a29ab297b8ea3035806a7d86265faa0976", + "manual" + ], + "wai-aria/cell_aria-colspan_2_on_td_html_colspan_3-manual.html": [ + "fe72cecdfd9b60e0f5346a1848e19c7b1adbcd62", + "manual" + ], + "wai-aria/cell_aria-colspan_2_on_td_html_colspan_3_with_headers_and_border-manual.html": [ + "524d5318a2fb71e71979679647219ccdf59de427", + "manual" + ], + "wai-aria/cell_aria-colspan_2_on_td_with_html_colspan_not_specified-manual.html": [ + "7b444106d30350596a9fb81c54845754a806077b", + "manual" + ], + "wai-aria/cell_aria-rowspan_2_on_div-manual.html": [ + "83af1369b5ea45e943d59deeca46a4b517436850", + "manual" + ], + "wai-aria/cell_aria-rowspan_2_on_td_html_rowspan_3-manual.html": [ + "a2d5c2e0c438ce16ae5a4b6ef5032e738d3bac7a", + "manual" + ], + "wai-aria/cell_aria-rowspan_2_on_td_with_html_rowspan_not_specified-manual.html": [ + "c92a991cb963082cdcbf2d90489e8d01d34f880e", + "manual" + ], + "wai-aria/cell_colindex_4-manual.html": [ + "03653417d9dccc42a392c3dd672fd26be29a0afe", + "manual" + ], + "wai-aria/cell_rowindex_4-manual.html": [ + "cdf0f7eb47b9d49b54bf0f4831311a47acdcddb3", + "manual" + ], + "wai-aria/checkbox_readonly_false-manual.html": [ + "fce2224ea02feb9886abd11eae61fec3eb295dd4", + "manual" + ], + "wai-aria/checkbox_readonly_true-manual.html": [ + "9ee1117041827f9ae7a720d52bd31abeefddbede", + "manual" + ], + "wai-aria/checkbox_readonly_unspecified-manual.html": [ + "ed1c64acd3f88485e7e9879848e63a7a6448f05a", + "manual" + ], + "wai-aria/columnheader_aria-colspan_2_on_div-manual.html": [ + "5cef610d8ef44e4cfb3a105dacae722f8c16924c", + "manual" + ], + "wai-aria/columnheader_aria-colspan_2_on_th_html_colspan_3-manual.html": [ + "8f7d23287ebc7a0f4fd8f538761a6fdcb8d4db70", + "manual" + ], + "wai-aria/columnheader_aria-colspan_2_on_th_with_html_colspan_not_specified-manual.html": [ + "182848b4c055b72f21b7f05802b12f07931a8936", + "manual" + ], + "wai-aria/columnheader_aria-rowspan_2_on_div-manual.html": [ + "14bcb535040d7ec7d1463f9dabb77c8d5a4579fd", + "manual" + ], + "wai-aria/columnheader_aria-rowspan_2_on_th_html_rowspan_3-manual.html": [ + "b89d3ad4a1452afa883969eee6b426eb42e1d7f7", + "manual" + ], + "wai-aria/columnheader_aria-rowspan_2_on_th_with_html_rowspan_not_specified-manual.html": [ + "4031b040bcda345c04073053556445019574751b", + "manual" + ], + "wai-aria/columnheader_colindex_4-manual.html": [ + "2e46afcd1e0c0c6639dde5d4bdb64829f4cd0298", + "manual" + ], + "wai-aria/columnheader_rowindex_4-manual.html": [ + "6a48e170e90a355cf9f99842f14fc178620800bc", + "manual" + ], + "wai-aria/columnheader_selected_false_not_automatically_propagated-manual.html": [ + "884096f6c1033f184d3cb8aa3c4afdfff377acf7", + "manual" + ], + "wai-aria/columnheader_selected_true_not_automatically_propagated-manual.html": [ + "92bbb16b4e4325da1f29c3886e19e0a2bdefed3a", + "manual" + ], + "wai-aria/combobox_controls_an_invalid_id-manual.html": [ + "a7428f00c7a7c1b7ec4571b053ed3f97b370d6a7", + "manual" + ], + "wai-aria/combobox_haspopup_dialog-manual.html": [ + "1763643ee1772e4e44f694be1161b7d9c4fb4ccd", + "manual" + ], + "wai-aria/combobox_haspopup_false-manual.html": [ + "cd628b6f7a53d048283395adf1ba5e1ca9aa3983", + "manual" + ], + "wai-aria/combobox_haspopup_grid-manual.html": [ + "a725532a4475cbba01a815fc0b70d7a9f18ca38f", + "manual" + ], + "wai-aria/combobox_haspopup_listbox-manual.html": [ + "66ad33bdc43763064bede6f49423c669fd6c8b54", + "manual" + ], + "wai-aria/combobox_haspopup_menu-manual.html": [ + "77eaf2adc1234c46b8d7f5016351f8f92734ce55", + "manual" + ], + "wai-aria/combobox_haspopup_tree-manual.html": [ + "023ba0b8badbeba32333d3283922054d5577ea57", + "manual" + ], + "wai-aria/combobox_haspopup_true-manual.html": [ + "11f474e4da6b76c9e9a74bf846f7209a9b040b08", + "manual" + ], + "wai-aria/combobox_haspopup_unspecified-manual.html": [ + "8285f5e4ca013a53f7fef22b3254ac34724d1e74", + "manual" + ], + "wai-aria/combobox_orientation_horizontal-manual.html": [ + "e8eb60d4d9a0850511cdee7a3e19ba5c2fb14c73", + "manual" + ], + "wai-aria/combobox_orientation_unspecified-manual.html": [ + "7c7b15f4586f4f84a0b6d40f2c8285de78d904be", + "manual" + ], + "wai-aria/combobox_orientation_vertical-manual.html": [ + "ed213ba95cac717ec3b4910f6a97ce713ecd00cc", + "manual" + ], + "wai-aria/combobox_readonly_false-manual.html": [ + "bbb7298bbf9f33e6ebe54bf392ef8a802d7d4cc5", + "manual" + ], + "wai-aria/combobox_readonly_true-manual.html": [ + "164858f5c1ce2f9daaf2a5d56485d8a5b6c1ed37", + "manual" + ], + "wai-aria/combobox_readonly_unspecified-manual.html": [ + "a4dda746a9b77935eee233e82ca70678e4dd5af4", + "manual" + ], + "wai-aria/dialog_modal_false-manual.html": [ + "3623f1024b0ab26ab2b6d48bc78e9fc4699ea584", + "manual" + ], + "wai-aria/dialog_modal_true-manual.html": [ + "c0ec6e36a67b7ba42b0076350e0876866be17d61", + "manual" + ], + "wai-aria/dialog_modal_unspecified-manual.html": [ + "41baed7d9e1e5d6512d3240bdbabb2db45b99436", + "manual" + ], + "wai-aria/div_element_without_role_roledescription_valid-manual.html": [ + "1f7fcd4985675b15c9a97f536c694ca8e2359856", + "manual" + ], + "wai-aria/errormessage_object_in_invalid_state-manual.html": [ + "0c7a38f437ccc80e81dbc8f11a70e695ff5c742a", + "manual" + ], + "wai-aria/errormessage_object_in_valid_state-manual.html": [ + "279aa052a362be0dc408d9926aecbd4a77622217", + "manual" + ], + "wai-aria/feed-manual.html": [ + "6768e3a7de2c91da15b218136156cfa58ff08266", + "manual" + ], + "wai-aria/figure-manual.html": [ + "ac697b43cc605ec65cb32b38c8d874aacbc71ce9", + "manual" + ], + "wai-aria/grid_aria-readonly_false_automatically_propagated-manual.html": [ + "6fbbec7c8a3d7d0910c6fcdd0eddcfa365b66278", + "manual" + ], + "wai-aria/grid_aria-readonly_true_automatically_propagated-manual.html": [ + "a82aa4fa5d961160f466139a1c55649aebafa8fb", + "manual" + ], + "wai-aria/grid_busy_false-manual.html": [ + "fd9ffb7a543c87860f1be98e25e25eef326e7751", + "manual" + ], + "wai-aria/grid_busy_true-manual.html": [ + "905f6765e8af6ad6f99004cba0580d360582b64b", + "manual" + ], + "wai-aria/grid_busy_value_changes-manual.html": [ + "164b4bb9fffae08a923fbbc3d929dab78c07f7da", + "manual" + ], + "wai-aria/grid_colcount_8-manual.html": [ + "dd37931f0fc32f2c00864626787e6d067e14592b", + "manual" + ], + "wai-aria/grid_columnheader_readonly_false-manual.html": [ + "ae9b21ab77f899329e20806ec8b4fd779532e591", + "manual" + ], + "wai-aria/grid_columnheader_readonly_true-manual.html": [ + "6acacc79477351796d7e31cb829254763985891b", + "manual" + ], + "wai-aria/grid_columnheader_readonly_unspecified-manual.html": [ + "74043387768367c5b31eca92f480d6eaf90957b1", + "manual" + ], + "wai-aria/grid_columnheader_required_false-manual.html": [ + "c3b02b385cfd99e689b005efc504ec761cb0a9b7", + "manual" + ], + "wai-aria/grid_columnheader_required_true-manual.html": [ + "b0dfaeb91b02fcb297693e96bfca333dda35716d", + "manual" + ], + "wai-aria/grid_columnheader_required_unspecified-manual.html": [ + "a6dc62bf3b5b589dc8721c3f5763183b4d015ac3", + "manual" + ], + "wai-aria/grid_rowcount_3-manual.html": [ + "bf3f9782a1a454a0c349616a61e280b1793230b0", + "manual" + ], + "wai-aria/grid_rowheader_readonly_false-manual.html": [ + "943cd5404948a66fed6a9c2cb0e8ced36c5102c0", + "manual" + ], + "wai-aria/grid_rowheader_readonly_true-manual.html": [ + "ff601c967bd5b0e738bdb14904a5497f34a16a19", + "manual" + ], + "wai-aria/grid_rowheader_readonly_unspecified-manual.html": [ + "4a76a804a411a15dcfbb1a6a8fb18bdfc2fb081f", + "manual" + ], + "wai-aria/grid_rowheader_required_false-manual.html": [ + "94fca0c3ef551d6d31d857e6d512963810e67992", + "manual" + ], + "wai-aria/grid_rowheader_required_true-manual.html": [ + "0649b9eb897fe2eb8967efb9d5332ef8e229c03d", + "manual" + ], + "wai-aria/grid_rowheader_required_unspecified-manual.html": [ + "dc4c36552e7c006db645ee0463a12675a3e0b466", + "manual" + ], + "wai-aria/gridcell_aria-colspan_2_on_div-manual.html": [ + "535e5db06891cf95856c2f3c18b40f5cdfda54cc", + "manual" + ], + "wai-aria/gridcell_aria-rowspan_2_on_div-manual.html": [ + "4b70f3c790eeafdf4519ca117d5636da75818329", + "manual" + ], + "wai-aria/gridcell_colindex_4-manual.html": [ + "e50950807c28c596da8498af6d5d6ad9813f8078", + "manual" + ], + "wai-aria/gridcell_rowindex_4-manual.html": [ + "a46ee5749847f5f7108f36bf94ab3cd68cc4b9da", + "manual" + ], + "wai-aria/group_hidden_undefined_element_not_rendered-manual.html": [ + "805ba51c4386fd6f55afefd2e6aae82914c4175d", + "manual" + ], + "wai-aria/group_hidden_undefined_element_rendered-manual.html": [ + "38b5fbf5a7dd587667a0b37183f8a7ae898f05cf", + "manual" + ], + "wai-aria/heading_level_unspecified-manual.html": [ + "7c2d392ee98849fe06f98274a2619c0a784f9b38", + "manual" + ], + "wai-aria/keyshortcuts_multiple_shortcuts-manual.html": [ + "af486cbc3db878e822c3fbb96bf036e6852cec5c", + "manual" + ], + "wai-aria/keyshortcuts_one_shortcut-manual.html": [ + "b3c04b5e58ee1526ef5f5e258ca90a582799dda4", + "manual" + ], + "wai-aria/listbox_busy_false-manual.html": [ + "1377c99b925c23caf6919f4374027b0e5ba257b2", + "manual" + ], + "wai-aria/listbox_busy_true-manual.html": [ + "2a5abfed2c9d72cc892cc49b797a46fde695e5f0", + "manual" + ], + "wai-aria/listbox_orientation_horizontal-manual.html": [ + "7f17844c821b26318f93b7cf76452f8acc2b3b0d", + "manual" + ], + "wai-aria/listbox_orientation_unspecified-manual.html": [ + "2d5b3c0dec5a14a3d9e0af254206ef87ee337771", + "manual" + ], + "wai-aria/listbox_orientation_vertical-manual.html": [ + "8a1c0a060d79ba685d3d0b9620defb605c6f62ff", + "manual" + ], + "wai-aria/listbox_readonly_false-manual.html": [ + "ec9dae486305791c724211354861638a247dc26c", + "manual" + ], + "wai-aria/listbox_readonly_true-manual.html": [ + "42e0b509269e688918e3a841f060aefd69df2169", + "manual" + ], + "wai-aria/listbox_readonly_unspecified-manual.html": [ + "1f541372495802bfa03caf45003005ae891948d7", + "manual" + ], + "wai-aria/listitem_setsize_-1-manual.html": [ + "b167105f60636d5ffcaaf500bae1edc88854465a", + "manual" + ], + "wai-aria/menu_orientation_horizontal-manual.html": [ + "020ef03f1ecbd6606e90c386ef4462c831c96732", + "manual" + ], + "wai-aria/menu_orientation_unspecified-manual.html": [ + "6850c3782b82c247edc598d7229f4f1a7724330f", + "manual" + ], + "wai-aria/menu_orientation_vertical-manual.html": [ + "0c8f0918aca79b7e517e26b893e1d1b6d69be5ca", + "manual" + ], + "wai-aria/menubar_busy_false-manual.html": [ + "c82d5db7dcd0c1312c3d57193254d01e7d72ce86", + "manual" + ], + "wai-aria/menubar_busy_true-manual.html": [ + "7bbc9132c65d46d9198005a85118ea3b720a1a13", + "manual" + ], + "wai-aria/menubar_orientation_horizontal-manual.html": [ + "80f7701f1dffe4a31cd107aef16737dc7f21a34d", + "manual" + ], + "wai-aria/menubar_orientation_unspecified-manual.html": [ + "588ca28c4c24def8245bd5b5769496103dfe9abc", + "manual" + ], + "wai-aria/menubar_orientation_vertical-manual.html": [ + "14bb2ca607953ee28c791e7fd0ecf19bc190758b", + "manual" + ], + "wai-aria/menuitem_posinset_and_setsize-manual.html": [ + "c55bb72e414f3ddbfd22ba5cf99bc109e5c980ac", + "manual" + ], + "wai-aria/menuitemcheckbox_posinset_and_setsize-manual.html": [ + "4553c3a159771357f5a622e982e95435c9eb93e4", + "manual" + ], + "wai-aria/menuitemcheckbox_readonly_false-manual.html": [ + "4042fbf1d8ebfdc4357f209bbd85e8af9c73830e", + "manual" + ], + "wai-aria/menuitemcheckbox_readonly_true-manual.html": [ + "30171ccd6e2c017e1c9595fe7cae11e2390facad", + "manual" + ], + "wai-aria/menuitemcheckbox_readonly_unspecified-manual.html": [ + "90858a2d3807fa9aaeb86a22d1f9347c0b7f18d1", + "manual" + ], + "wai-aria/menuitemradio_posinset_and_setsize-manual.html": [ + "d8b534c359b59241693f89624016aa284a044504", + "manual" + ], + "wai-aria/menuitemradio_readonly_false-manual.html": [ + "f1a615fcb66aaadbc8ebd2ccc51c71d405ef7a99", + "manual" + ], + "wai-aria/menuitemradio_readonly_true-manual.html": [ + "bcc2a14a9758cf50a09842f39e04dfe5eb88aca2", + "manual" + ], + "wai-aria/menuitemradio_readonly_unspecified-manual.html": [ + "240c09ed186cffe1a27b66c6fea18bbf834bac97", + "manual" + ], + "wai-aria/none-manual.html": [ + "ac3b80213f6e3f32731907e027aab65bed17bcca", + "manual" + ], + "wai-aria/option_selected_false-manual.html": [ + "5639b60eb2e929c4b9f5cc23a25576da6a8a0a08", + "manual" + ], + "wai-aria/option_selected_true-manual.html": [ + "3647d9da8c16d2905aa93fe18cbc1fb14942e431", + "manual" + ], + "wai-aria/option_selected_undefined-manual.html": [ + "e667c7bb74260d04128bcf89c43569a4dbc579d9", + "manual" + ], + "wai-aria/option_selected_value_changes-manual.html": [ + "f8f3b18dc5cc45f2a00d5c161569a109511543d8", + "manual" + ], + "wai-aria/radiogroup_orientation_horizontal-manual.html": [ + "d4b59488ea142fa84698919ba00d7e6c39680abb", + "manual" + ], + "wai-aria/radiogroup_orientation_unspecified-manual.html": [ + "fe639588f16cc6202a3d765c12d9ea5cbe4ea034", + "manual" + ], + "wai-aria/radiogroup_orientation_vertical-manual.html": [ + "575203e25857605f0f3076925b636e203c0a4985", + "manual" + ], + "wai-aria/radiogroup_readonly_false-manual.html": [ + "bd779e93fc3708db72848dd4d95938bf25f5eaf7", + "manual" + ], + "wai-aria/radiogroup_readonly_true-manual.html": [ + "72f4ddf0cfa0bf49d40d50911a564668a7c849d6", + "manual" + ], + "wai-aria/radiogroup_readonly_unspecified-manual.html": [ + "650e661bfdeb4428f9e92ab218e1596fd0cda64d", + "manual" + ], + "wai-aria/region_with_name-manual.html": [ + "d85fd90f06f86aeabe4c95996e3f913400dd21e4", + "manual" + ], + "wai-aria/region_without_name-manual.html": [ + "2178f5fa7d48ace5f56852304f392e34bd0fb00e", + "manual" + ], + "wai-aria/row_colindex_4-manual.html": [ + "09edc18410efb6f66b210dbb81818ca327969ad9", + "manual" + ], + "wai-aria/row_rowindex_4-manual.html": [ + "16a9f0d13d7e219d791a33313f484cea1d6a773a", + "manual" + ], + "wai-aria/rowheader_aria-colspan_2_on_div-manual.html": [ + "12a854c7835f358ffb82ac2337415b5a0a8a768c", + "manual" + ], + "wai-aria/rowheader_aria-rowspan_2_on_div-manual.html": [ + "b3653a6ac91d31a7fc73506afa8ae914b6dfb0f0", + "manual" + ], + "wai-aria/rowheader_colindex_4-manual.html": [ + "4b1095a3c7bbdbee01d208d909bceb1921d80fa5", + "manual" + ], + "wai-aria/rowheader_rowindex_4-manual.html": [ + "4a447def2f3f8c03ffa56352edb37b976a8ca340", + "manual" + ], + "wai-aria/rowheader_selected_false_not_automatically_propagated-manual.html": [ + "8abed2e46a404cce830afa5a3d0a2775a3c009a7", + "manual" + ], + "wai-aria/rowheader_selected_true_not_automatically_propagated-manual.html": [ + "d3def9e0ef906b28ea702bef37f529318c8133f5", + "manual" + ], + "wai-aria/scrollbar_all_values_unspecified-manual.html": [ + "c7bfcf35db82ec42822a129b40c0b26524931b95", + "manual" + ], + "wai-aria/scrollbar_only_valuenow_unspecified-manual.html": [ + "1436d040a20ec38e3493ab85df9110f81b468a1c", + "manual" + ], + "wai-aria/scrollbar_orientation_unspecified-manual.html": [ + "513a2cdd27dcd8ae2e3073ce2eff0e6b852e313c", + "manual" + ], + "wai-aria/searchbox-manual.html": [ + "69a89a2c6674f3994b24fa1a7cfebeaef2ff938e", + "manual" + ], + "wai-aria/searchbox_activedescendant-manual.html": [ + "0a28b434d5a38a23daeba52fe72040d152c6dd5d", + "manual" + ], + "wai-aria/searchbox_activedescendant_value_changes-manual.html": [ + "581ffae1f50715ea4af29b37631ce69fb163ed56", + "manual" + ], + "wai-aria/searchbox_autocomplete_both-manual.html": [ + "ceec0aec25373eea8a1255d7c508fa85534ff5b9", + "manual" + ], + "wai-aria/searchbox_autocomplete_inline-manual.html": [ + "17e69cb6a6e9aded2485c2c064ef4879a45f4164", + "manual" + ], + "wai-aria/searchbox_autocomplete_list-manual.html": [ + "9f881f8b334a36141363498d86a1d7327c97060a", + "manual" + ], + "wai-aria/searchbox_autocomplete_none-manual.html": [ + "f2ad6734ded2a347cb32411f2d26d9c74f2b9c61", + "manual" + ], + "wai-aria/searchbox_autocomplete_unspecified-manual.html": [ + "492f3c3d8f1a1c2bb5bb2a39af99333de8119cc8", + "manual" + ], + "wai-aria/searchbox_multiline_false-manual.html": [ + "2bc9db01cccb25a94add5c6a4b469ce38c32e713", + "manual" + ], + "wai-aria/searchbox_multiline_true-manual.html": [ + "35684d76a3c45e1355984bfe516d40d71b6424e6", + "manual" + ], + "wai-aria/searchbox_multiline_unspecified-manual.html": [ + "f1643f9c47f61f98ed28483bd9b3cb1ebcebacdf", + "manual" + ], + "wai-aria/searchbox_placeholder-manual.html": [ + "c7915eadb230631a11b326fe6a3045992ca11468", + "manual" + ], + "wai-aria/searchbox_readonly_false-manual.html": [ + "220bcf0b6de7e4ea38f14c63f5b035ad8c90b126", + "manual" + ], + "wai-aria/searchbox_readonly_true-manual.html": [ + "6333c8a2fe903d0dd528c17c255b474158d21230", + "manual" + ], + "wai-aria/searchbox_readonly_unspecified-manual.html": [ + "2706af2015509abaa4f8a96506a9b394dd24801c", + "manual" + ], + "wai-aria/searchbox_required_false-manual.html": [ + "96561ee3eeb254a17cf4e0665ccb78bf1362ea02", + "manual" + ], + "wai-aria/searchbox_required_true-manual.html": [ + "67dbe2e78c059e4ae018194f5ac3ea22cc5b274b", + "manual" + ], + "wai-aria/searchbox_required_unspecified-manual.html": [ + "216e258bd53649bf2703c586858471ed30f122e7", + "manual" + ], + "wai-aria/separator_focusable_all_values_unspecified-manual.html": [ + "36c88bd5c4316bdfde84c5ff5113863df302a286", + "manual" + ], + "wai-aria/separator_focusable_only_valuenow_unspecified-manual.html": [ + "06260be143c42b51ad13fda1cf050fd47c167fc0", + "manual" + ], + "wai-aria/separator_focusable_valuetext-manual.html": [ + "a3bd39904d064ea3822558ccd1c9ca473961219b", + "manual" + ], + "wai-aria/separator_orientation_unspecified-manual.html": [ + "d62a3821d9b02a735b397a599843b665cccebc90", + "manual" + ], + "wai-aria/separator_unfocusable_all_values_unspecified-manual.html": [ + "5e129d2319b57f7d86b0a04cb226d179a330f907", + "manual" + ], + "wai-aria/separator_unfocusable_valuetext-manual.html": [ + "93c6b47e0cc9689cce539a940eb1cdcba82ebfd5", + "manual" + ], + "wai-aria/slider_all_values_unspecified-manual.html": [ + "90ebac88d3f22a87378698cea51fa09452b76469", + "manual" + ], + "wai-aria/slider_only_valuenow_unspecified-manual.html": [ + "dcaa79500ad30ba8fba3f194b578f63bf8755acf", + "manual" + ], + "wai-aria/slider_orientation_unspecified-manual.html": [ + "48069859c3bd20aabcffedb1edbab2a370dd9b3f", + "manual" + ], + "wai-aria/slider_readonly_false-manual.html": [ + "861fcfcafdf59d381177a5bb5946c6f54a3da49e", + "manual" + ], + "wai-aria/slider_readonly_true-manual.html": [ + "b8b33452767ef838a17876d7e215abda33af1795", + "manual" + ], + "wai-aria/slider_readonly_unspecified-manual.html": [ + "ba1b3920b40f1acdf26a7ab6a31ab9ea26f5bbd0", + "manual" + ], + "wai-aria/spinbutton_all_values_unspecified-manual.html": [ + "d7e6862b38f714424aecc21dc838697fe09d7912", + "manual" + ], + "wai-aria/spinbutton_only_aria-valuenow_unspecified-manual.html": [ + "5c164b3834cf10846e920e83487039f1b9c26d8a", + "manual" + ], + "wai-aria/spinbutton_readonly_false-manual.html": [ + "2423f721a79e4a0078179b7f0d3f4f6ef0eb6334", + "manual" + ], + "wai-aria/spinbutton_readonly_true-manual.html": [ + "ce33688754649c0478a2bed417c3ebede3da6bd2", + "manual" + ], + "wai-aria/spinbutton_readonly_unspecified-manual.html": [ + "ae0499cdda8e51f1e514a37dd42a1f668a6f0fca", + "manual" + ], + "wai-aria/switch_checked_false-manual.html": [ + "34d619b1c380fd3b5e0a8196e1f8cf1ded2565da", + "manual" + ], + "wai-aria/switch_checked_mixed-manual.html": [ + "ac8deb477f3f0dbd9b15d066aa5fedf7303155d6", + "manual" + ], + "wai-aria/switch_checked_true-manual.html": [ + "89762ad8710d61af6f02dc47d2d0cb85278e5a0f", + "manual" + ], + "wai-aria/switch_checked_undefined-manual.html": [ + "43dfbc3fed1773110b780bc9d8a8b001ab0bf522", + "manual" + ], + "wai-aria/switch_checked_value_changes-manual.html": [ + "7eabfd644e607e92298e449a02376aee38623f71", + "manual" + ], + "wai-aria/switch_readonly_false-manual.html": [ + "b80fb7d4726566e0bd111e4ad5a2e17c72c19a22", + "manual" + ], + "wai-aria/switch_readonly_true-manual.html": [ + "432d55a0b9943f9d44641e73bbf94c4d346882be", + "manual" + ], + "wai-aria/switch_readonly_unspecified-manual.html": [ + "7b491505435f6ce21bea99acf817d5f8452793ce", + "manual" + ], + "wai-aria/tab_posinset_and_setsize-manual.html": [ + "0a81f2ec8a073a4aa4c9b2262bf3b894500a7d85", + "manual" + ], + "wai-aria/table_colcount_-1-manual.html": [ + "767517c0b13aa5738caca739fac835255495b552", + "manual" + ], + "wai-aria/table_colcount_8-manual.html": [ + "10ef7ce22ebdbff6b82408bff4ea269b22a84cfe", + "manual" + ], + "wai-aria/table_rowcount_-1-manual.html": [ + "c1b42be4c24652dbab05bb6e1b21705b679f80f2", + "manual" + ], + "wai-aria/table_rowcount_3-manual.html": [ + "59ff2493b3107e6e3832bc116087fc25a1f4cdfc", + "manual" + ], + "wai-aria/tablist_orientation_horizontal-manual.html": [ + "65b14b357bfadb29334f7e0b4d327387f00b16a3", + "manual" + ], + "wai-aria/tablist_orientation_unspecified-manual.html": [ + "9fe1319decbd2959c7edee1729781b7c7714cfa3", + "manual" + ], + "wai-aria/tablist_orientation_vertical-manual.html": [ + "b42ccf2e219954234e715c67702e6161738c74c0", + "manual" + ], + "wai-aria/term_role-manual.html": [ + "9b94e2327fdcb8f0812931fb4beef1a820ac73bc", + "manual" + ], + "wai-aria/textbox_placeholder-manual.html": [ + "0d62d1d8d51380f76df1cb292560946af5acc117", + "manual" + ], + "wai-aria/toolbar_orientation_horizontal-manual.html": [ + "c0d179f4aa923ceb79a3d6b6f2c709c08bff6d1b", + "manual" + ], + "wai-aria/toolbar_orientation_unspecified-manual.html": [ + "5291a72ec14d159b5ac2a9ee98faf8f49fff25db", + "manual" + ], + "wai-aria/toolbar_orientation_vertical-manual.html": [ + "9a997719c1f7056de7effc8bf6715a5542ba328e", + "manual" + ], + "wai-aria/tree_orientation_horizontal-manual.html": [ + "ced3f1f1877a379e2838e768faf301156eb0d21b", + "manual" + ], + "wai-aria/tree_orientation_unspecified-manual.html": [ + "314a725577dcb0f1353976149bcfa4320348771d", + "manual" + ], + "wai-aria/tree_orientation_vertical-manual.html": [ + "1b6c426e4c296d51fd37e882360a99b9177c9dec", + "manual" + ], + "wai-aria/treegrid_colcount_8-manual.html": [ + "93141db40bf34a33833917c3679a21facaef3b54", + "manual" + ], + "wai-aria/treegrid_orientation_horizontal-manual.html": [ + "d47fc7b4534e78d6740caf2f184a9682cbea9551", + "manual" + ], + "wai-aria/treegrid_orientation_unspecified-manual.html": [ + "314b5fba7dbf05874c87ed583707a256a0c48e95", + "manual" + ], + "wai-aria/treegrid_orientation_vertical-manual.html": [ + "a010eac09cba60995983bce684eef3dffdd2b173", + "manual" + ], + "wai-aria/treegrid_rowcount_3-manual.html": [ + "05e99e92cb0a8661fcc6ca9e4073814995e1e335", + "manual" + ], + "wai-aria/treeitem_selected_false-manual.html": [ + "306b11914f05b8aba7373e4b8d098940436f0628", + "manual" + ], + "wai-aria/treeitem_selected_true-manual.html": [ + "840111cebbbae4c1f7145151f6286c77f43e59c4", + "manual" + ], + "wai-aria/treeitem_selected_undefined-manual.html": [ + "3e12ca040cd5b1fc5230e8c98ac84b4e98794de2", + "manual" + ], + "wai-aria/treeitem_selected_value_changes-manual.html": [ + "ff1dff851d96bc1bbee1821b958c9220868dc1d1", + "manual" + ], "web-animations/OWNERS": [ "c4f52fc673833f80178284b30d6fc4bad1f581d2", "support" @@ -211789,6 +218819,10 @@ "395dad4a877ef4af20649d6bcfece102a22b3059", "testharness" ], + "web-animations/interfaces/Animation/idlharness.html": [ + "bf61e9cb3d009b4d5ccbd70ec7397842e2d521d2", + "testharness" + ], "web-animations/interfaces/Animation/oncancel.html": [ "0477d2fef7fc64bbc969b29d4ba542574c4c3706", "testharness" @@ -211814,7 +218848,7 @@ "testharness" ], "web-animations/interfaces/Animation/ready.html": [ - "f79ea4e2bfc3bc83a7ac96634cbb2d5f21f6c1f5", + "b23b76881f4d38c07710d0e59c1f6c8569de9060", "testharness" ], "web-animations/interfaces/Animation/startTime.html": [ @@ -211862,7 +218896,7 @@ "testharness" ], "web-animations/interfaces/AnimationTimeline/document-timeline.html": [ - "033c4137ea1fcffc7c32a4cc353009b07b800c4a", + "2df691f77422d0e64833addf0c099e44f9afe051", "testharness" ], "web-animations/interfaces/AnimationTimeline/idlharness.html": [ @@ -211953,12 +218987,24 @@ "53a4a6c6c6d07e00fecc50e5de831862e7bf4b2e", "testharness" ], + "web-animations/timing-model/animations/canceling-an-animation.html": [ + "079bc0e0f7ea60b94999ed1b4f92c1aa2fc2c7bb", + "testharness" + ], "web-animations/timing-model/animations/current-time.html": [ "b1ea8e490cbfb69fd71b91a90e7e2d9ce99f42d3", "testharness" ], + "web-animations/timing-model/animations/finishing-an-animation.html": [ + "570ec579c6118866b888b1384e21977c9cfb0ec0", + "testharness" + ], + "web-animations/timing-model/animations/pausing-an-animation.html": [ + "a000d8f86fa62b90ec7a60c289066aaaa1758377", + "testharness" + ], "web-animations/timing-model/animations/playing-an-animation.html": [ - "88ab1d42390d50bcdf513bb12159c0c15d6278ff", + "2b4f51977d43f9bf90c066bfcc57728ae096b6e9", "testharness" ], "web-animations/timing-model/animations/reversing-an-animation.html": [ @@ -211985,16 +219031,24 @@ "66e2277c77e4bd7b2d8981a725fb5083a8f5e0f6", "testharness" ], + "web-nfc/OWNERS": [ + "214e3edd526f674d2bd69f4292c0681e54685a0d", + "support" + ], + "web-nfc/idlharness.https.html": [ + "b44413f6709ec74f6fc809726d0e988c127ef02d", + "testharness" + ], "webaudio/.gitignore": [ "11bc81247643b0a9fc665f1e4b1f592cc1f4c670", "support" ], "webaudio/OWNERS": [ - "d98264a830bdab63db07061e8b25080188e1aeab", + "72bd1a8929367ef9a8f8353d7fc5bda3354477a6", "support" ], "webaudio/README.md": [ - "4c364a7fe763f5d1fa603cfe5ab62234e7a1f9ee", + "230684ec60fd2e408f9b6014417f3eddfe2dc95a", "support" ], "webaudio/js/buffer-loader.js": [ @@ -212238,7 +219292,7 @@ "testharness" ], "webdriver/OWNERS": [ - "ed6ae435828699abe5d1399c6e9bacc7bae7474f", + "cbfd094d14a2be6678df83a7bcd8b022922396dd", "support" ], "webdriver/README.md": [ @@ -212286,7 +219340,7 @@ "support" ], "webdriver/conftest.py": [ - "5abb72cd5cce31dde7772f4a88a9c618aeacc42e", + "d58492066c9eba232867b4c2928e9e74839d3f8a", "wdspec" ], "webdriver/contexts.py": [ @@ -212301,12 +219355,16 @@ "dd2f52a3a77497ce8785e698f9ab462390ed0d57", "wdspec" ], + "webdriver/support/__init__.py": [ + "5a31a3917a5157516c10951a3b3d5ffb43b992d9", + "support" + ], "webdriver/support/asserts.py": [ "68bde3a7b3e3fe3ecd45e43c9fbc3c1317828e08", "support" ], "webdriver/support/fixtures.py": [ - "281f7e8b5baa0f4e51900db120ef688a75108ae0", + "1742e49d5661ce9e5a806fd17c293f6bd502227f", "support" ], "webdriver/support/http_request.py": [ @@ -212317,6 +219375,10 @@ "bc85126e5637145e81f27d037f3a9090747130c8", "support" ], + "webdriver/support/merge_dictionaries.py": [ + "84a6d3c6f8f4afded0f21264bbaeebec38a7f827", + "support" + ], "webgl/OWNERS": [ "f8e0703fe2cc88edd21ef2c94fcb2e1a8889f5ae", "support" @@ -221650,7 +228712,7 @@ "support" ], "webgl/conformance-1.0.3/resources/js-test-pre.js": [ - "0ea0d3b945ac49d9a98c39788b2bc18c82de762a", + "23bc989f25ee5371a45762bac36c260d230001ca", "support" ], "webgl/conformance-1.0.3/resources/js-test-style.css": [ @@ -221686,7 +228748,7 @@ "support" ], "webgl/tools/js-test-pre.patch": [ - "b903fa3810ba7538a735d4126d20364d285b88cc", + "9d692bf9bf2b37385f1193855e2605573af8249e", "support" ], "webgl/tools/unit.patch": [ @@ -221750,7 +228812,7 @@ "support" ], "webmessaging/README.md": [ - "4c7f9f149edb1036692128007742f8ae358e167a", + "d126c708f1d34de380f2e063bb8e404f30b6a487", "support" ], "webmessaging/Transferred_objects_unusable.sub.htm": [ @@ -221833,6 +228895,10 @@ "19fc5d2f7e0f30e9d35a8606c3fb05b537ea3a82", "testharness" ], + "webmessaging/messageerror.html": [ + "92c5359ad64394cb2d30402204968d49227c5daf", + "testharness" + ], "webmessaging/postMessage_ArrayBuffer.sub.htm": [ "ce4d489c97753d15ea9370093fdc3b2fe1592cf1", "testharness" @@ -221994,7 +229060,7 @@ "testharness" ], "webmessaging/with-ports/027.html": [ - "c392333f994dd5196c5456176e775528abc2a9a7", + "2d1ca62b5be602139a4a86599fc86f3ff14d1377", "testharness" ], "webmessaging/without-ports/001.html": [ @@ -222122,13 +229188,41 @@ "testharness" ], "webrtc/OWNERS": [ - "07bfd311abbe127d95ac7e49c8615f7948a4949e", + "e7b3745ccd77b56023dedda83488a9b77327dffe", "support" ], + "webrtc/RTCConfiguration-iceCandidatePoolSize.html": [ + "9551402aed448bf6abde4aa815d174ba321cc655", + "testharness" + ], "webrtc/RTCDataChannelEvent-constructor.html": [ "8a8b30a23abddb5d11a802fead534fd56aacbb62", "testharness" ], + "webrtc/RTCPeerConnection-canTrickleIceCandidates.html": [ + "0f585a89bd8f25aa8f83b6ec39b704cbb8e970b2", + "testharness" + ], + "webrtc/RTCPeerConnection-constructor.html": [ + "54fff02eab02b0be84c945ec7e77afe722d9f988", + "testharness" + ], + "webrtc/RTCPeerConnection-createDataChannel.html": [ + "4e46c66c535a49573a3400355dde79b63f7b95d6", + "testharness" + ], + "webrtc/RTCPeerConnection-iceGatheringState.html": [ + "4f752838326116e65543a10e023a0cbe9c07e9e8", + "testharness" + ], + "webrtc/RTCPeerConnection-idl.html": [ + "e322b3ab7f8e0bc7ff802f00234a9a6e80b8285a", + "testharness" + ], + "webrtc/RTCPeerConnection-setRemoteDescription.html": [ + "ee89fd092059a4cc489536898d4a47a7bbbf36f2", + "testharness" + ], "webrtc/RTCPeerConnectionIceEvent-constructor.html": [ "46bb1ba3a908f99b46a656d34094aae8998ed484", "testharness" @@ -222137,36 +229231,28 @@ "56a37968e489d6ee39a1234ca888dd628f17648e", "testharness" ], + "webrtc/datachannel-idlharness.html": [ + "a1753a9a537a626775194ccc5dfdbf6829c5df35", + "testharness" + ], + "webrtc/getstats.html": [ + "6656998d4adfab0e6ca51c98cd141cf162d3879c", + "testharness" + ], + "webrtc/interfaces.html": [ + "bd71316e6efddce47bb4cf3218b3133f8c69c3db", + "testharness" + ], "webrtc/no-media-call.html": [ - "d82774b3116ba278303b9407176ee528d0754700", + "e9f056be5a865f1bb73d60ec72c38f8d5f16d747", "testharness" ], "webrtc/promises-call.html": [ - "392d4975b232b9003a75d3771ba5c6f2e992849e", - "testharness" - ], - "webrtc/rtcpeerconnection/iceGatheringState.html": [ - "4f752838326116e65543a10e023a0cbe9c07e9e8", - "testharness" - ], - "webrtc/rtcpeerconnection/rtcconfiguration-icecandidatepoolsize.html": [ - "9551402aed448bf6abde4aa815d174ba321cc655", - "testharness" - ], - "webrtc/rtcpeerconnection/rtcpeerconnection-constructor.html": [ - "54fff02eab02b0be84c945ec7e77afe722d9f988", - "testharness" - ], - "webrtc/rtcpeerconnection/rtcpeerconnection-idl.html": [ - "e322b3ab7f8e0bc7ff802f00234a9a6e80b8285a", - "testharness" - ], - "webrtc/rtcpeerconnection/setRemoteDescription.html": [ - "b11f7f3cc9a11b6aac9d70324a15e878c0345945", + "f0292ca52ee86920d0fdb8bccae2bc40a8ef99af", "testharness" ], "webrtc/simplecall.html": [ - "0ccdc365173e0c805f708edc49dbb8c8a88d786a", + "ce76df05d5866807a4b58c9509ce66efcddaf3d7", "testharness" ], "websockets/Close-1000-reason.htm": [ @@ -222282,7 +229368,7 @@ "support" ], "websockets/README.md": [ - "cb6f6f64079ef7f8843b7553ab732bf84c8794bf", + "1b8473c8d482b7628fc7337e263c78aca7ca5088", "support" ], "websockets/Secure-Close-1000-reason.htm": [ @@ -223102,7 +230188,7 @@ "support" ], "webstorage/README.md": [ - "48097218468237985b9c3275f8e72979e44fe214", + "2f211af6d9f953cebb65e8bbfcbf417e50788a45", "support" ], "webstorage/document-domain.html": [ @@ -223366,7 +230452,7 @@ "support" ], "webvr/idlharness.html": [ - "53ac12278e26e70cc0f6d6f31171fc4d2b6e6667", + "236974fe82ab29908e849d25c5ce748f5c0509c3", "testharness" ], "webvtt/OWNERS": [ @@ -226130,7 +233216,7 @@ "support" ], "workers/README.md": [ - "2660d9dbe4f7a2947ec78b14e6418554c8204d6b", + "b32446a62602baf1a316520ee8e2e5d9e60cada3", "support" ], "workers/SharedWorker_blobUrl.html": [ diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.https.html.ini new file mode 100644 index 000000000000..f102b050e24a --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.https.html.ini @@ -0,0 +1,3 @@ +[test_ecdh_bits.https.html] + type: testharness + expected: TIMEOUT diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.https.html.ini new file mode 100644 index 000000000000..7a2f597a1005 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.https.html.ini @@ -0,0 +1,3 @@ +[test_ecdh_keys.https.html] + type: testharness + expected: TIMEOUT diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_hkdf.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_hkdf.https.html.ini similarity index 99% rename from testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_hkdf.html.ini rename to testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_hkdf.https.html.ini index d3ed7db1a598..a1a1a6a58ccb 100644 --- a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_hkdf.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_hkdf.https.html.ini @@ -1,4 +1,4 @@ -[test_hkdf.html] +[test_hkdf.https.html] type: testharness [short derivedKey, normal salt, SHA-384, with normal info with 0 length] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html.ini deleted file mode 100644 index cfcbd197f57f..000000000000 --- a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[test_pbkdf2.html] - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1309307 - type: testharness diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_empty.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_empty.https.html.ini new file mode 100644 index 000000000000..6d0ec860438d --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_empty.https.html.ini @@ -0,0 +1,2303 @@ +[test_pbkdf2_empty_empty.https.html] + type: testharness + [empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1000 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [empty password, empty salt, SHA-384, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-384, with 100000 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-384, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-384, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [empty password, empty salt, SHA-384, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-384, with 0 iterations] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1000 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [empty password, empty salt, SHA-512, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-512, with 100000 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-512, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-512, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [empty password, empty salt, SHA-512, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-512, with 0 iterations] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1000 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [empty password, empty salt, SHA-1, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-1, with 100000 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-1, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-1, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [empty password, empty salt, SHA-1, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-1, with 0 iterations] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1000 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [empty password, empty salt, SHA-256, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, empty salt, SHA-256, with 100000 iterations with null length] + expected: FAIL + + [empty password, empty salt, SHA-256, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, empty salt, SHA-256, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [empty password, empty salt, SHA-256, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, SHA-256, with 0 iterations] + expected: FAIL + + [empty password, empty salt, PBKDF2, with 1 iterations with non-digest algorithm PBKDF2] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, PBKDF2, with 1 iterations] + expected: FAIL + + [empty password, empty salt, PBKDF2, with 1000 iterations with non-digest algorithm PBKDF2] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [empty password, empty salt, PBKDF2, with 100000 iterations with non-digest algorithm PBKDF2] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, empty salt, PBKDF2, with 100000 iterations] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_long.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_long.https.html.ini new file mode 100644 index 000000000000..469a77a1bc5b --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_long.https.html.ini @@ -0,0 +1,2303 @@ +[test_pbkdf2_empty_long.https.html] + type: testharness + [empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-384, with 1 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-384, with 1 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-384, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [empty password, long salt, SHA-384, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-384, with 1000 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-384, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-384, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [empty password, long salt, SHA-384, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-384, with 100000 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-384, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-384, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [empty password, long salt, SHA-384, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-384, with 0 iterations] + expected: FAIL + + [empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-512, with 1 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-512, with 1 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-512, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [empty password, long salt, SHA-512, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-512, with 1000 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-512, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-512, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [empty password, long salt, SHA-512, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-512, with 100000 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-512, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-512, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [empty password, long salt, SHA-512, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-512, with 0 iterations] + expected: FAIL + + [empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-1, with 1 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-1, with 1 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-1, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [empty password, long salt, SHA-1, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-1, with 1000 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-1, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-1, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [empty password, long salt, SHA-1, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-1, with 100000 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-1, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-1, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [empty password, long salt, SHA-1, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-1, with 0 iterations] + expected: FAIL + + [empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-256, with 1 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-256, with 1 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-256, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [empty password, long salt, SHA-256, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-256, with 1000 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-256, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-256, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [empty password, long salt, SHA-256, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, long salt, SHA-256, with 100000 iterations with null length] + expected: FAIL + + [empty password, long salt, SHA-256, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, long salt, SHA-256, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [empty password, long salt, SHA-256, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, SHA-256, with 0 iterations] + expected: FAIL + + [empty password, long salt, PBKDF2, with 1 iterations with non-digest algorithm PBKDF2] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, PBKDF2, with 1 iterations] + expected: FAIL + + [empty password, long salt, PBKDF2, with 1000 iterations with non-digest algorithm PBKDF2] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [empty password, long salt, PBKDF2, with 100000 iterations with non-digest algorithm PBKDF2] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, long salt, PBKDF2, with 100000 iterations] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_short.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_short.https.html.ini new file mode 100644 index 000000000000..0a14c1983326 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_short.https.html.ini @@ -0,0 +1,2303 @@ +[test_pbkdf2_empty_short.https.html] + type: testharness + [empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-384, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-384, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-384, with 1 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-384, with 1 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-384, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [empty password, short salt, SHA-384, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-384, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-384, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-384, with 1000 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-384, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-384, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [empty password, short salt, SHA-384, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-384, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-384, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-384, with 100000 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-384, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-384, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [empty password, short salt, SHA-384, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-384, with 0 iterations] + expected: FAIL + + [empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-512, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-512, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-512, with 1 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-512, with 1 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-512, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [empty password, short salt, SHA-512, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-512, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-512, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-512, with 1000 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-512, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-512, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [empty password, short salt, SHA-512, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-512, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-512, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-512, with 100000 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-512, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-512, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [empty password, short salt, SHA-512, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-512, with 0 iterations] + expected: FAIL + + [empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-1, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-1, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-1, with 1 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-1, with 1 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-1, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [empty password, short salt, SHA-1, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-1, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-1, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-1, with 1000 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-1, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-1, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [empty password, short salt, SHA-1, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-1, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-1, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-1, with 100000 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-1, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-1, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [empty password, short salt, SHA-1, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-1, with 0 iterations] + expected: FAIL + + [empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-256, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-256, with 1 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-256, with 1 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-256, with 1 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-256, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [empty password, short salt, SHA-256, with 1 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-256, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-256, with 1000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-256, with 1000 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-256, with 1000 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-256, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [empty password, short salt, SHA-256, with 1000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-256, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-256, with 100000 iterations with missing deriveKey usage] + expected: FAIL + + [empty password, short salt, SHA-256, with 100000 iterations with null length] + expected: FAIL + + [empty password, short salt, SHA-256, with 100000 iterations with 0 length] + expected: FAIL + + [empty password, short salt, SHA-256, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [empty password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [empty password, short salt, SHA-256, with 100000 iterations with missing deriveBits usage] + expected: FAIL + + [empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, SHA-256, with 0 iterations] + expected: FAIL + + [empty password, short salt, PBKDF2, with 1 iterations with non-digest algorithm PBKDF2] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, PBKDF2, with 1 iterations] + expected: FAIL + + [empty password, short salt, PBKDF2, with 1000 iterations with non-digest algorithm PBKDF2] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, PBKDF2, with 1000 iterations] + expected: FAIL + + [empty password, short salt, PBKDF2, with 100000 iterations with non-digest algorithm PBKDF2] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using empty password, short salt, PBKDF2, with 100000 iterations] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_empty.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_empty.https.html.ini new file mode 100644 index 000000000000..a65787e4409f --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_empty.https.html.ini @@ -0,0 +1,722 @@ +[test_pbkdf2_long_empty.https.html] + type: testharness + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [long password, empty salt, SHA-384, with 1 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-384, with 1 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-384, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [long password, empty salt, SHA-384, with 1000 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-384, with 1000 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-384, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [long password, empty salt, SHA-384, with 100000 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-384, with 100000 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-384, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [long password, empty salt, SHA-512, with 1 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-512, with 1 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-512, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [long password, empty salt, SHA-512, with 1000 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-512, with 1000 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-512, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [long password, empty salt, SHA-512, with 100000 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-512, with 100000 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-512, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [long password, empty salt, SHA-1, with 1 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-1, with 1 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-1, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [long password, empty salt, SHA-1, with 1000 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-1, with 1000 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-1, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [long password, empty salt, SHA-1, with 100000 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-1, with 100000 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-1, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [long password, empty salt, SHA-256, with 1 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-256, with 1 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-256, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [long password, empty salt, SHA-256, with 1000 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-256, with 1000 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-256, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [long password, empty salt, SHA-256, with 100000 iterations with null length] + expected: FAIL + + [long password, empty salt, SHA-256, with 100000 iterations with 0 length] + expected: FAIL + + [long password, empty salt, SHA-256, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_long.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_long.https.html.ini new file mode 100644 index 000000000000..772c7685de35 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_long.https.html.ini @@ -0,0 +1,722 @@ +[test_pbkdf2_long_long.https.html] + type: testharness + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [long password, long salt, SHA-384, with 1 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-384, with 1 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-384, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [long password, long salt, SHA-384, with 1000 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-384, with 1000 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-384, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [long password, long salt, SHA-384, with 100000 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-384, with 100000 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-384, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [long password, long salt, SHA-512, with 1 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-512, with 1 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-512, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [long password, long salt, SHA-512, with 1000 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-512, with 1000 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-512, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [long password, long salt, SHA-512, with 100000 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-512, with 100000 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-512, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [long password, long salt, SHA-1, with 1 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-1, with 1 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-1, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [long password, long salt, SHA-1, with 1000 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-1, with 1000 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-1, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [long password, long salt, SHA-1, with 100000 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-1, with 100000 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-1, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [long password, long salt, SHA-256, with 1 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-256, with 1 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-256, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [long password, long salt, SHA-256, with 1000 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-256, with 1000 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-256, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [long password, long salt, SHA-256, with 100000 iterations with null length] + expected: FAIL + + [long password, long salt, SHA-256, with 100000 iterations with 0 length] + expected: FAIL + + [long password, long salt, SHA-256, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_short.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_short.https.html.ini new file mode 100644 index 000000000000..9d33f5220bdf --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_short.https.html.ini @@ -0,0 +1,722 @@ +[test_pbkdf2_long_short.https.html] + type: testharness + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [long password, short salt, SHA-384, with 1 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-384, with 1 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-384, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [long password, short salt, SHA-384, with 1000 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-384, with 1000 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-384, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [long password, short salt, SHA-384, with 100000 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-384, with 100000 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-384, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [long password, short salt, SHA-512, with 1 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-512, with 1 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-512, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [long password, short salt, SHA-512, with 1000 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-512, with 1000 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-512, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [long password, short salt, SHA-512, with 100000 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-512, with 100000 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-512, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [long password, short salt, SHA-1, with 1 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-1, with 1 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-1, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [long password, short salt, SHA-1, with 1000 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-1, with 1000 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-1, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [long password, short salt, SHA-1, with 100000 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-1, with 100000 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-1, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [long password, short salt, SHA-256, with 1 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-256, with 1 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-256, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [long password, short salt, SHA-256, with 1000 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-256, with 1000 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-256, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [long password, short salt, SHA-256, with 100000 iterations with null length] + expected: FAIL + + [long password, short salt, SHA-256, with 100000 iterations with 0 length] + expected: FAIL + + [long password, short salt, SHA-256, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [long password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_empty.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_empty.https.html.ini new file mode 100644 index 000000000000..869347f5aba8 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_empty.https.html.ini @@ -0,0 +1,722 @@ +[test_pbkdf2_short_empty.https.html] + type: testharness + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [short password, empty salt, SHA-384, with 1 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-384, with 1 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-384, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [short password, empty salt, SHA-384, with 1000 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-384, with 1000 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-384, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [short password, empty salt, SHA-384, with 100000 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-384, with 100000 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-384, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [short password, empty salt, SHA-512, with 1 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-512, with 1 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-512, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [short password, empty salt, SHA-512, with 1000 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-512, with 1000 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-512, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [short password, empty salt, SHA-512, with 100000 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-512, with 100000 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-512, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [short password, empty salt, SHA-1, with 1 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-1, with 1 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-1, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [short password, empty salt, SHA-1, with 1000 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-1, with 1000 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-1, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [short password, empty salt, SHA-1, with 100000 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-1, with 100000 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-1, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [short password, empty salt, SHA-256, with 1 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-256, with 1 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-256, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [short password, empty salt, SHA-256, with 1000 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-256, with 1000 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-256, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [short password, empty salt, SHA-256, with 100000 iterations with null length] + expected: FAIL + + [short password, empty salt, SHA-256, with 100000 iterations with 0 length] + expected: FAIL + + [short password, empty salt, SHA-256, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, empty salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_long.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_long.https.html.ini new file mode 100644 index 000000000000..5438bdc84a65 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_long.https.html.ini @@ -0,0 +1,722 @@ +[test_pbkdf2_short_long.https.html] + type: testharness + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [short password, long salt, SHA-384, with 1 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-384, with 1 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-384, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [short password, long salt, SHA-384, with 1000 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-384, with 1000 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-384, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [short password, long salt, SHA-384, with 100000 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-384, with 100000 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-384, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [short password, long salt, SHA-512, with 1 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-512, with 1 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-512, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [short password, long salt, SHA-512, with 1000 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-512, with 1000 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-512, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [short password, long salt, SHA-512, with 100000 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-512, with 100000 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-512, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [short password, long salt, SHA-1, with 1 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-1, with 1 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-1, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [short password, long salt, SHA-1, with 1000 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-1, with 1000 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-1, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [short password, long salt, SHA-1, with 100000 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-1, with 100000 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-1, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [short password, long salt, SHA-256, with 1 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-256, with 1 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-256, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [short password, long salt, SHA-256, with 1000 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-256, with 1000 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-256, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [short password, long salt, SHA-256, with 100000 iterations with null length] + expected: FAIL + + [short password, long salt, SHA-256, with 100000 iterations with 0 length] + expected: FAIL + + [short password, long salt, SHA-256, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, long salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_short.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_short.https.html.ini new file mode 100644 index 000000000000..2d406148d421 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_short.https.html.ini @@ -0,0 +1,722 @@ +[test_pbkdf2_short_short.https.html] + type: testharness + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [short password, short salt, SHA-384, with 1 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-384, with 1 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-384, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-384, with 1 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [short password, short salt, SHA-384, with 1000 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-384, with 1000 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-384, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-384, with 1000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [short password, short salt, SHA-384, with 100000 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-384, with 100000 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-384, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-384, with 100000 iterations with bad hash name SHA384] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [short password, short salt, SHA-512, with 1 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-512, with 1 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-512, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-512, with 1 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [short password, short salt, SHA-512, with 1000 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-512, with 1000 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-512, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-512, with 1000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [short password, short salt, SHA-512, with 100000 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-512, with 100000 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-512, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-512, with 100000 iterations with bad hash name SHA512] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [short password, short salt, SHA-1, with 1 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-1, with 1 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-1, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-1, with 1 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [short password, short salt, SHA-1, with 1000 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-1, with 1000 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-1, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-1, with 1000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [short password, short salt, SHA-1, with 100000 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-1, with 100000 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-1, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-1, with 100000 iterations with bad hash name SHA1] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [short password, short salt, SHA-256, with 1 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-256, with 1 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-256, with 1 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-256, with 1 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [short password, short salt, SHA-256, with 1000 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-256, with 1000 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-256, with 1000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-256, with 1000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 128 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 192 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CBC length: 256 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 128 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 192 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-CTR length: 256 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 128 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 192 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-GCM length: 256 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 128 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 192 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: AES-KW length: 256 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-1 length: 256 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-256 length: 256 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-384 length: 256 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [Derived key of type name: HMAC hash: SHA-512 length: 256 using short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + + [short password, short salt, SHA-256, with 100000 iterations with null length] + expected: FAIL + + [short password, short salt, SHA-256, with 100000 iterations with 0 length] + expected: FAIL + + [short password, short salt, SHA-256, with 100000 iterations with non-multiple of 8 length] + expected: FAIL + + [short password, short salt, SHA-256, with 100000 iterations with bad hash name SHA256] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.html.ini b/testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.https.html.ini similarity index 96% rename from testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.html.ini rename to testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.https.html.ini index 1e95676ecd26..63ddbd92bb5e 100644 --- a/testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.https.html.ini @@ -1,4 +1,4 @@ -[test_aes_cbc.html] +[test_aes_cbc.https.html] type: testharness [AES-CBC 128-bit key, 64-bit IV] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html.ini b/testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.https.html.ini similarity index 99% rename from testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html.ini rename to testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.https.html.ini index 1e7752bc30b7..286ec4de3e56 100644 --- a/testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.https.html.ini @@ -1,4 +1,4 @@ -[test_aes_gcm.html] +[test_aes_gcm.https.html] type: testharness [AES-GCM 128-bit key, illegal tag length 24-bits] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures.https.html.ini similarity index 75% rename from testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes.html.ini rename to testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures.https.html.ini index c18e5a917dca..b4b23b92842b 100644 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures.https.html.ini @@ -1,3 +1,3 @@ -[test_successes.html] +[test_failures.https.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CBC.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html.ini similarity index 99% rename from testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CBC.html.ini rename to testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html.ini index d5c9d05cc63d..a52237ddbecf 100644 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CBC.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html.ini @@ -1,4 +1,4 @@ -[test_failures_AES-CBC.html] +[test_failures_AES-CBC.https.html] type: testharness [Bad algorithm: generateKey(AES, false, [decrypt\])] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CTR.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CTR.https.html.ini similarity index 99% rename from testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CTR.html.ini rename to testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CTR.https.html.ini index 666a24aef8fc..8ff8009f8377 100644 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CTR.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-CTR.https.html.ini @@ -1,4 +1,4 @@ -[test_failures_AES-CTR.html] +[test_failures_AES-CTR.https.html] type: testharness [Bad algorithm: generateKey(AES, false, [decrypt\])] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-GCM.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-GCM.https.html.ini similarity index 99% rename from testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-GCM.html.ini rename to testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-GCM.https.html.ini index 36b0ac7619b2..ca93775a5063 100644 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-GCM.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-GCM.https.html.ini @@ -1,4 +1,4 @@ -[test_failures_AES-GCM.html] +[test_failures_AES-GCM.https.html] type: testharness [Bad algorithm: generateKey(AES, false, [decrypt\])] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-KW.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-KW.https.html.ini similarity index 99% rename from testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-KW.html.ini rename to testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-KW.https.html.ini index ac790b068daa..12c8c04fae94 100644 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-KW.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_AES-KW.https.html.ini @@ -1,4 +1,4 @@ -[test_failures_AES-KW.html] +[test_failures_AES-KW.https.html] type: testharness [Bad algorithm: generateKey(AES, false, [decrypt\])] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDH.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDH.https.html.ini similarity index 99% rename from testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDH.html.ini rename to testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDH.https.html.ini index 08824a106087..5743fb413f40 100644 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDH.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDH.https.html.ini @@ -1,4 +1,4 @@ -[test_failures_ECDH.html] +[test_failures_ECDH.https.html] type: testharness [Bad algorithm: generateKey(AES, false, [decrypt\])] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDSA.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDSA.https.html.ini similarity index 99% rename from testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDSA.html.ini rename to testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDSA.https.html.ini index 18a00325cdd0..b1228ce0b3e0 100644 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDSA.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_ECDSA.https.html.ini @@ -1,4 +1,4 @@ -[test_failures_ECDSA.html] +[test_failures_ECDSA.https.html] type: testharness [Bad algorithm: generateKey(AES, false, [decrypt\])] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_HMAC.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_HMAC.https.html.ini similarity index 99% rename from testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_HMAC.html.ini rename to testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_HMAC.https.html.ini index b23ce7dae906..1b3f59006d17 100644 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_HMAC.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_HMAC.https.html.ini @@ -1,4 +1,4 @@ -[test_failures_HMAC.html] +[test_failures_HMAC.https.html] type: testharness [Bad algorithm: generateKey(AES, false, [decrypt\])] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html.ini deleted file mode 100644 index 3232aff0546d..000000000000 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html.ini +++ /dev/null @@ -1,3772 +0,0 @@ -[test_failures_RSA-OAEP.html] - type: testharness - expected: TIMEOUT - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 - [Bad algorithm: generateKey(AES, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, verify\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, sign\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, verify\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey, deriveBits\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, wrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, wrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [decrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [decrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [wrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [wrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, wrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, wrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey, wrapKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey, wrapKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [unwrapKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [unwrapKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [decrypt, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [decrypt, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [wrapKey, decrypt, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [wrapKey, decrypt, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, decrypt, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, decrypt, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, wrapKey, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, wrapKey, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, encrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [decrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [decrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [wrapKey, decrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [wrapKey, decrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, wrapKey, decrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, wrapKey, decrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, decrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, decrypt\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey, wrapKey\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey, wrapKey\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [unwrapKey\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [unwrapKey\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: TIMEOUT - diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.https.html.ini new file mode 100644 index 000000000000..3c70ea851df2 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.https.html.ini @@ -0,0 +1,3 @@ +[test_failures_RSA-OAEP.https.html] + type: testharness + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-PSS.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-PSS.html.ini deleted file mode 100644 index 8ac457d9f2c4..000000000000 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-PSS.html.ini +++ /dev/null @@ -1,1502 +0,0 @@ -[test_failures_RSA-PSS.html] - type: testharness - expected: TIMEOUT - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 - [Bad algorithm: generateKey(AES, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, wrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, wrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, wrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, unwrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, unwrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, unwrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, deriveKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, deriveKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, deriveKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, wrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, wrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, wrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, deriveKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, deriveKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, deriveKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, deriveBits\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, deriveBits\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, deriveBits\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [sign\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, true, [sign\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [verify, sign\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, true, [verify, sign\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, true, [\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, false, [sign, verify, sign, sign, verify\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1}}, true, [sign, verify, sign, sign, verify\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [sign\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [verify, sign\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [verify, sign\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign, verify, sign, sign, verify\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [sign, verify, sign, sign, verify\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: TIMEOUT - diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-PSS.https.html.ini similarity index 70% rename from testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures.html.ini rename to testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-PSS.https.html.ini index 7cde862f5956..99bce8f3e8f2 100644 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSA-PSS.https.html.ini @@ -1,3 +1,3 @@ -[test_failures.html] +[test_failures_RSA-PSS.https.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html.ini deleted file mode 100644 index 50383a18e3a0..000000000000 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html.ini +++ /dev/null @@ -1,1541 +0,0 @@ -[test_failures_RSASSA-PKCS1-v1_5.html] - type: testharness - expected: TIMEOUT - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 - [Bad algorithm: generateKey(AES, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey(AES, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: AES}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, sign, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, decrypt\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, sign\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, decrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, wrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, wrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, wrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, unwrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, unwrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, unwrapKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, deriveKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, deriveKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, deriveKey\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, deriveBits\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, encrypt\])] - expected: FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, encrypt\])] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, decrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, decrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, wrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, wrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, wrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, deriveKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, deriveKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, deriveKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, deriveBits\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign, deriveBits\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify, deriveBits\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [sign\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, true, [sign\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [verify, sign\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, true, [verify, sign\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, true, [\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, false, [sign, verify, sign, sign, verify\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1}}, true, [sign, verify, sign, sign, verify\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [sign\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [verify, sign\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [verify, sign\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, false, [sign, verify, sign, sign, verify\])] - expected: TIMEOUT - - [Bad algorithm property: generateKey({hash: SHA-256, modulusLength: 1024, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 0}}, true, [sign, verify, sign, sign, verify\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-1, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [\])] - expected: TIMEOUT - - [Empty usages: generateKey({hash: SHA-256, modulusLength: 2048, name: RSASSA-PKCS1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [\])] - expected: TIMEOUT - diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.https.html.ini new file mode 100644 index 000000000000..7edfd24fad36 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.https.html.ini @@ -0,0 +1,3 @@ +[test_failures_RSASSA-PKCS1-v1_5.https.html] + type: testharness + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_AES-CBC.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_AES-CBC.html.ini deleted file mode 100644 index eade3f178b63..000000000000 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_AES-CBC.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[test_successes_AES-CBC.html] - type: testharness - expected: - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_AES-CBC.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_AES-CBC.https.html.ini new file mode 100644 index 000000000000..451d4165a016 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_AES-CBC.https.html.ini @@ -0,0 +1,3 @@ +[test_successes_AES-CBC.https.html] + type: testharness + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html.ini deleted file mode 100644 index 0760c5c2524e..000000000000 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html.ini +++ /dev/null @@ -1,1907 +0,0 @@ -[test_successes_RSA-OAEP.html] - type: testharness - expected: TIMEOUT - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey\])] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey\])] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [wrapKey, decrypt\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, decrypt\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, decrypt\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA-OAEP, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, encrypt\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [wrapKey, decrypt, encrypt\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt\])] - expected: - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [wrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [wrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [wrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [wrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [wrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, decrypt, encrypt\])] - expected: - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt, encrypt\])] - expected: - if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, encrypt\])] - expected: - if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, encrypt\])] - expected: - if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, encrypt\])] - expected: - if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, encrypt\])] - expected: - if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt\])] - expected: - if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt\])] - expected: - if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [wrapKey, decrypt\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [wrapKey, decrypt\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey, decrypt\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey, decrypt\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, decrypt\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, decrypt\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey, wrapKey\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey, wrapKey\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [unwrapKey\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [unwrapKey\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): PASS - TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-oaep, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [encrypt, decrypt, wrapKey, unwrapKey, decrypt, unwrapKey, encrypt, decrypt, wrapKey, unwrapKey\])] - expected: TIMEOUT - diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html.ini new file mode 100644 index 000000000000..db8302cb2c4e --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html.ini @@ -0,0 +1,3 @@ +[test_successes_RSA-OAEP.https.html] + type: testharness + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html.ini deleted file mode 100644 index 3bfe95b8ca42..000000000000 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html.ini +++ /dev/null @@ -1,57 +0,0 @@ -[test_successes_RSA-PSS.html] - type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign\])] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsa-pss, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify\])] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-PSS.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-PSS.https.html.ini new file mode 100644 index 000000000000..cf6a6b181edd --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSA-PSS.https.html.ini @@ -0,0 +1,3 @@ +[test_successes_RSA-PSS.https.html] + type: testharness + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html.ini deleted file mode 100644 index f2c0fdb1752e..000000000000 --- a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html.ini +++ /dev/null @@ -1,78 +0,0 @@ -[test_successes_RSASSA-PKCS1-v1_5.html] - type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify\])] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify\])] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-1, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [verify, sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, verify, sign, sign, verify\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: Rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, verify, sign, sign, verify\])] - expected: - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - - [Success: generateKey({hash: SHA-256, modulusLength: 2048, name: rsassa-pkcs1-v1_5, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [verify, sign\])] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT - diff --git a/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.https.html.ini new file mode 100644 index 000000000000..f196fbfe9c6a --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.https.html.ini @@ -0,0 +1,3 @@ +[test_successes_RSASSA-PKCS1-v1_5.https.html] + type: testharness + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1279799 diff --git a/testing/web-platform/meta/WebCryptoAPI/import_export/test_ec_importKey.html.ini b/testing/web-platform/meta/WebCryptoAPI/import_export/test_ec_importKey.https.html.ini similarity index 99% rename from testing/web-platform/meta/WebCryptoAPI/import_export/test_ec_importKey.html.ini rename to testing/web-platform/meta/WebCryptoAPI/import_export/test_ec_importKey.https.html.ini index 6217e5a57425..4ca56bc48bae 100644 --- a/testing/web-platform/meta/WebCryptoAPI/import_export/test_ec_importKey.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/import_export/test_ec_importKey.https.html.ini @@ -1,4 +1,4 @@ -[test_ec_importKey.html] +[test_ec_importKey.https.html] type: testharness [Good parameters: P-256 bits (spki, buffer(91), {name: ECDSA, namedCurve: P-256}, true, [\])] expected: FAIL diff --git a/testing/web-platform/meta/WebCryptoAPI/secure_context/crypto-subtle-non-secure-context-not-available.sub.html.ini b/testing/web-platform/meta/WebCryptoAPI/secure_context/crypto-subtle-non-secure-context-not-available.sub.html.ini new file mode 100644 index 000000000000..c9d151085669 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/secure_context/crypto-subtle-non-secure-context-not-available.sub.html.ini @@ -0,0 +1,8 @@ +[crypto-subtle-non-secure-context-not-available.sub.html] + type: testharness + [Non-secure context window does not have access to crypto.subtle] + expected: FAIL + + [Non-secure context worker does not have access to crypto.subtle] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/sign_verify/test_ecdsa.html.ini b/testing/web-platform/meta/WebCryptoAPI/sign_verify/test_ecdsa.html.ini deleted file mode 100644 index 5d8f42f6932e..000000000000 --- a/testing/web-platform/meta/WebCryptoAPI/sign_verify/test_ecdsa.html.ini +++ /dev/null @@ -1,389 +0,0 @@ -[test_ecdsa.html] - type: testharness - [importVectorKeys step: ECDSA P-256 with SHA-1 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-256 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-384 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-512 verification] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-1 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-256 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-384 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-512 verification with altered signature after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-1 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-256 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-384 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-512 with altered plaintext after call] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-1 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-256 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-384 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-512 using privateKey to verify] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-1 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-256 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-384 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-512 using publicKey to sign] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-1 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-256 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-384 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-512 no verify usage] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-1 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-256 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-384 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-512 round trip] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-1 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-256 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-384 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-512 verification failure due to altered signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-1 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-256 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-384 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-512 verification failure due to wrong hash] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-1 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-256 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-384 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-512 verification failure due to bad hash name] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-1 verification failure due to shortened signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-256 verification failure due to shortened signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-384 verification failure due to shortened signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-256 with SHA-512 verification failure due to shortened signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-1 verification failure due to shortened signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-256 verification failure due to shortened signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-384 verification failure due to shortened signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-384 with SHA-512 verification failure due to shortened signature] - expected: FAIL - - [importVectorKeys step: ECDSA P-521 with SHA-1 verification failure due to shortened signature] - expected: FAIL - diff --git a/testing/web-platform/meta/WebCryptoAPI/sign_verify/test_ecdsa.https.html.ini b/testing/web-platform/meta/WebCryptoAPI/sign_verify/test_ecdsa.https.html.ini new file mode 100644 index 000000000000..9c848f8efcf3 --- /dev/null +++ b/testing/web-platform/meta/WebCryptoAPI/sign_verify/test_ecdsa.https.html.ini @@ -0,0 +1,137 @@ +[test_ecdsa.https.html] + type: testharness + [importVectorKeys step: ECDSA P-256 with SHA-1 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-256 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-384 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-512 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-1 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-256 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-384 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-512 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-1 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-256 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-384 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-512 verification] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-1 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-256 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-384 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-512 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-1 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-256 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-384 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-512 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-1 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-256 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-384 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-512 verification with altered signature after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-1 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-256 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-384 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-512 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-1 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-256 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-384 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-512 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-1 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-256 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-384 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-512 with altered plaintext after call] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-1 using privateKey to verify] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-256 using privateKey to verify] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-384 using privateKey to verify] + expected: FAIL + + [importVectorKeys step: ECDSA P-256 with SHA-512 using privateKey to verify] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-1 using privateKey to verify] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-256 using privateKey to verify] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-384 using privateKey to verify] + expected: FAIL + + [importVectorKeys step: ECDSA P-384 with SHA-512 using privateKey to verify] + expected: FAIL + + [importVectorKeys step: ECDSA P-521 with SHA-1 using privateKey to verify] + expected: FAIL + diff --git a/testing/web-platform/meta/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.html.ini b/testing/web-platform/meta/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.https.html.ini similarity index 89% rename from testing/web-platform/meta/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.html.ini rename to testing/web-platform/meta/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.https.html.ini index c3780abb1211..a54db408d207 100644 --- a/testing/web-platform/meta/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.html.ini +++ b/testing/web-platform/meta/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.https.html.ini @@ -1,302 +1,272 @@ -[test_wrapKey_unwrapKey.html] +[test_wrapKey_unwrapKey.https.html] type: testharness - [Can wrap and unwrap AES-KW keys using raw and AES-CTR] - expected: FAIL - - [Can wrap and unwrap AES-KW keys using jwk and AES-CTR] - expected: FAIL - - [Can wrap and unwrap ECDH public key keys using spki and AES-CTR] - expected: FAIL - - [Can wrap and unwrap ECDH public key keys using jwk and AES-CTR] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys using pkcs8 and AES-CTR] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys using jwk and AES-CTR] - expected: FAIL - - [Can wrap and unwrap ECDSA public key keys using spki and AES-CTR] - expected: FAIL - - [Can wrap and unwrap ECDSA public key keys using jwk and AES-CTR] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys using pkcs8 and AES-CTR] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys using jwk and AES-CTR] - expected: FAIL - - [Can wrap and unwrap RSASSA-PKCS1-v1_5 private key keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap RSA-PSS private key keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-CTR keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-CBC keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-GCM keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-KW keys using raw and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-KW keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap HMAC keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap RSA-OAEP private key keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap ECDH public key keys using spki and AES-KW] - expected: FAIL - - [Can wrap and unwrap ECDH public key keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys using pkcs8 and AES-KW] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap ECDSA public key keys using spki and AES-KW] - expected: FAIL - - [Can wrap and unwrap ECDSA public key keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys using pkcs8 and AES-KW] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-KW keys using raw and AES-GCM] - expected: FAIL - - [Can wrap and unwrap AES-KW keys using jwk and AES-GCM] - expected: FAIL - - [Can wrap and unwrap ECDH public key keys using spki and AES-GCM] - expected: FAIL - - [Can wrap and unwrap ECDH public key keys using jwk and AES-GCM] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys using pkcs8 and AES-GCM] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys using jwk and AES-GCM] - expected: FAIL - - [Can wrap and unwrap ECDSA public key keys using spki and AES-GCM] - expected: FAIL - - [Can wrap and unwrap ECDSA public key keys using jwk and AES-GCM] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys using pkcs8 and AES-GCM] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys using jwk and AES-GCM] - expected: FAIL - - [Can wrap and unwrap AES-KW keys using raw and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap AES-KW keys using jwk and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap ECDH public key keys using spki and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap ECDH public key keys using jwk and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys using pkcs8 and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys using jwk and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap ECDSA public key keys using spki and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap ECDSA public key keys using jwk and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys using pkcs8 and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys using jwk and RSA-OAEP] - expected: FAIL - [Can wrap and unwrap AES-KW keys using raw and AES-CBC] expected: FAIL - [Can wrap and unwrap AES-KW keys using jwk and AES-CBC] - expected: FAIL - - [Can wrap and unwrap ECDH public key keys using spki and AES-CBC] - expected: FAIL - - [Can wrap and unwrap ECDH public key keys using jwk and AES-CBC] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys using pkcs8 and AES-CBC] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys using jwk and AES-CBC] - expected: FAIL - - [Can wrap and unwrap ECDSA public key keys using spki and AES-CBC] - expected: FAIL - - [Can wrap and unwrap ECDSA public key keys using jwk and AES-CBC] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys using pkcs8 and AES-CBC] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys using jwk and AES-CBC] - expected: FAIL - - [Can wrap and unwrap AES-KW keys as non-extractable using raw and AES-CTR] - expected: FAIL - - [Can wrap and unwrap AES-KW keys as non-extractable using jwk and AES-CTR] - expected: FAIL - - [Can unwrap AES-KW non-extractable keys using jwk and AES-CTR] - expected: FAIL - - [Could not run all tests] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys as non-extractable using jwk and AES-CTR] - expected: FAIL - - [Can unwrap ECDH private key non-extractable keys using jwk and AES-CTR] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys as non-extractable using jwk and AES-CTR] - expected: FAIL - - [Can unwrap ECDSA private key non-extractable keys using jwk and AES-CTR] - expected: FAIL - - [Can wrap and unwrap RSASSA-PKCS1-v1_5 private key keys as non-extractable using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap RSA-PSS private key keys as non-extractable using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-CTR keys as non-extractable using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-CBC keys as non-extractable using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-GCM keys as non-extractable using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-KW keys as non-extractable using raw and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-KW keys as non-extractable using jwk and AES-KW] - expected: FAIL - - [Can unwrap AES-KW non-extractable keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap HMAC keys as non-extractable using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap RSA-OAEP private key keys as non-extractable using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys as non-extractable using jwk and AES-KW] - expected: FAIL - - [Can unwrap ECDH private key non-extractable keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys as non-extractable using jwk and AES-KW] - expected: FAIL - - [Can unwrap ECDSA private key non-extractable keys using jwk and AES-KW] - expected: FAIL - - [Can wrap and unwrap AES-KW keys as non-extractable using raw and AES-GCM] - expected: FAIL - - [Can wrap and unwrap AES-KW keys as non-extractable using jwk and AES-GCM] - expected: FAIL - - [Can unwrap AES-KW non-extractable keys using jwk and AES-GCM] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys as non-extractable using jwk and AES-GCM] - expected: FAIL - - [Can unwrap ECDH private key non-extractable keys using jwk and AES-GCM] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys as non-extractable using jwk and AES-GCM] - expected: FAIL - - [Can unwrap ECDSA private key non-extractable keys using jwk and AES-GCM] - expected: FAIL - - [Can wrap and unwrap AES-KW keys as non-extractable using raw and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap AES-KW keys as non-extractable using jwk and RSA-OAEP] - expected: FAIL - - [Can unwrap AES-KW non-extractable keys using jwk and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap ECDH private key keys as non-extractable using jwk and RSA-OAEP] - expected: FAIL - - [Can unwrap ECDH private key non-extractable keys using jwk and RSA-OAEP] - expected: FAIL - - [Can wrap and unwrap ECDSA private key keys as non-extractable using jwk and RSA-OAEP] - expected: FAIL - - [Can unwrap ECDSA private key non-extractable keys using jwk and RSA-OAEP] - expected: FAIL - [Can wrap and unwrap AES-KW keys as non-extractable using raw and AES-CBC] expected: FAIL + [Can wrap and unwrap AES-KW keys using jwk and AES-CBC] + expected: FAIL + [Can wrap and unwrap AES-KW keys as non-extractable using jwk and AES-CBC] expected: FAIL [Can unwrap AES-KW non-extractable keys using jwk and AES-CBC] expected: FAIL + [Can wrap and unwrap ECDH public key keys using spki and AES-CBC] + expected: FAIL + + [Can wrap and unwrap ECDH public key keys using jwk and AES-CBC] + expected: FAIL + + [Could not run all tests] + expected: FAIL + + [Can wrap and unwrap ECDH private key keys using jwk and AES-CBC] + expected: FAIL + [Can wrap and unwrap ECDH private key keys as non-extractable using jwk and AES-CBC] expected: FAIL [Can unwrap ECDH private key non-extractable keys using jwk and AES-CBC] expected: FAIL + [Can wrap and unwrap ECDSA public key keys using spki and AES-CBC] + expected: FAIL + + [Can wrap and unwrap ECDSA public key keys using jwk and AES-CBC] + expected: FAIL + + [Can wrap and unwrap ECDSA private key keys using jwk and AES-CBC] + expected: FAIL + [Can wrap and unwrap ECDSA private key keys as non-extractable using jwk and AES-CBC] expected: FAIL [Can unwrap ECDSA private key non-extractable keys using jwk and AES-CBC] expected: FAIL + [Can wrap and unwrap AES-KW keys using raw and AES-GCM] + expected: FAIL + + [Can wrap and unwrap AES-KW keys as non-extractable using raw and AES-GCM] + expected: FAIL + + [Can wrap and unwrap AES-KW keys using jwk and AES-GCM] + expected: FAIL + + [Can wrap and unwrap AES-KW keys as non-extractable using jwk and AES-GCM] + expected: FAIL + + [Can unwrap AES-KW non-extractable keys using jwk and AES-GCM] + expected: FAIL + + [Can wrap and unwrap ECDH public key keys using spki and AES-GCM] + expected: FAIL + + [Can wrap and unwrap ECDH public key keys using jwk and AES-GCM] + expected: FAIL + + [Can wrap and unwrap ECDH private key keys using jwk and AES-GCM] + expected: FAIL + + [Can wrap and unwrap ECDH private key keys as non-extractable using jwk and AES-GCM] + expected: FAIL + + [Can unwrap ECDH private key non-extractable keys using jwk and AES-GCM] + expected: FAIL + + [Can wrap and unwrap ECDSA public key keys using spki and AES-GCM] + expected: FAIL + + [Can wrap and unwrap ECDSA public key keys using jwk and AES-GCM] + expected: FAIL + + [Can wrap and unwrap ECDSA private key keys using jwk and AES-GCM] + expected: FAIL + + [Can wrap and unwrap ECDSA private key keys as non-extractable using jwk and AES-GCM] + expected: FAIL + + [Can unwrap ECDSA private key non-extractable keys using jwk and AES-GCM] + expected: FAIL + + [Can wrap and unwrap AES-KW keys using raw and AES-CTR] + expected: FAIL + + [Can wrap and unwrap AES-KW keys as non-extractable using raw and AES-CTR] + expected: FAIL + + [Can wrap and unwrap AES-KW keys using jwk and AES-CTR] + expected: FAIL + + [Can wrap and unwrap AES-KW keys as non-extractable using jwk and AES-CTR] + expected: FAIL + + [Can unwrap AES-KW non-extractable keys using jwk and AES-CTR] + expected: FAIL + + [Can wrap and unwrap ECDH public key keys using spki and AES-CTR] + expected: FAIL + + [Can wrap and unwrap ECDH public key keys using jwk and AES-CTR] + expected: FAIL + + [Can wrap and unwrap ECDH private key keys using jwk and AES-CTR] + expected: FAIL + + [Can wrap and unwrap ECDH private key keys as non-extractable using jwk and AES-CTR] + expected: FAIL + + [Can unwrap ECDH private key non-extractable keys using jwk and AES-CTR] + expected: FAIL + + [Can wrap and unwrap ECDSA public key keys using spki and AES-CTR] + expected: FAIL + + [Can wrap and unwrap ECDSA public key keys using jwk and AES-CTR] + expected: FAIL + + [Can wrap and unwrap ECDSA private key keys using jwk and AES-CTR] + expected: FAIL + + [Can wrap and unwrap ECDSA private key keys as non-extractable using jwk and AES-CTR] + expected: FAIL + + [Can unwrap ECDSA private key non-extractable keys using jwk and AES-CTR] + expected: FAIL + + [Can wrap and unwrap RSA-PSS private key keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap RSA-PSS private key keys as non-extractable using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap RSASSA-PKCS1-v1_5 private key keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap RSASSA-PKCS1-v1_5 private key keys as non-extractable using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap RSA-OAEP private key keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap RSA-OAEP private key keys as non-extractable using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-CTR keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-CTR keys as non-extractable using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-CBC keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-CBC keys as non-extractable using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-GCM keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-GCM keys as non-extractable using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap HMAC keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap HMAC keys as non-extractable using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-KW keys using raw and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-KW keys as non-extractable using raw and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-KW keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-KW keys as non-extractable using jwk and AES-KW] + expected: FAIL + + [Can unwrap AES-KW non-extractable keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap ECDH public key keys using spki and AES-KW] + expected: FAIL + + [Can wrap and unwrap ECDH public key keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap ECDH private key keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap ECDH private key keys as non-extractable using jwk and AES-KW] + expected: FAIL + + [Can unwrap ECDH private key non-extractable keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap ECDSA public key keys using spki and AES-KW] + expected: FAIL + + [Can wrap and unwrap ECDSA public key keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap ECDSA private key keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap ECDSA private key keys as non-extractable using jwk and AES-KW] + expected: FAIL + + [Can unwrap ECDSA private key non-extractable keys using jwk and AES-KW] + expected: FAIL + + [Can wrap and unwrap AES-KW keys using raw and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap AES-KW keys as non-extractable using raw and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap AES-KW keys using jwk and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap AES-KW keys as non-extractable using jwk and RSA-OAEP] + expected: FAIL + + [Can unwrap AES-KW non-extractable keys using jwk and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap ECDH public key keys using spki and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap ECDH public key keys using jwk and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap ECDH private key keys using jwk and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap ECDH private key keys as non-extractable using jwk and RSA-OAEP] + expected: FAIL + + [Can unwrap ECDH private key non-extractable keys using jwk and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap ECDSA public key keys using spki and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap ECDSA public key keys using jwk and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap ECDSA private key keys using jwk and RSA-OAEP] + expected: FAIL + + [Can wrap and unwrap ECDSA private key keys as non-extractable using jwk and RSA-OAEP] + expected: FAIL + + [Can unwrap ECDSA private key non-extractable keys using jwk and RSA-OAEP] + expected: FAIL + diff --git a/testing/web-platform/meta/WebIDL/ecmascript-binding/has-instance.html.ini b/testing/web-platform/meta/WebIDL/ecmascript-binding/has-instance.html.ini new file mode 100644 index 000000000000..f854c0262de1 --- /dev/null +++ b/testing/web-platform/meta/WebIDL/ecmascript-binding/has-instance.html.ini @@ -0,0 +1,8 @@ +[has-instance.html] + type: testharness + [instanceof must return false across different globals, for platform objects] + expected: FAIL + + [platform objects do not have Symbol.hasInstance installed] + expected: FAIL + diff --git a/testing/web-platform/meta/WebIDL/ecmascript-binding/interface-prototype-object.html.ini b/testing/web-platform/meta/WebIDL/ecmascript-binding/interface-prototype-object.html.ini new file mode 100644 index 000000000000..15e8b1c2cb87 --- /dev/null +++ b/testing/web-platform/meta/WebIDL/ecmascript-binding/interface-prototype-object.html.ini @@ -0,0 +1,5 @@ +[interface-prototype-object.html] + type: testharness + [The class string of an interface prototype object is the concatenation of the interface's identifier and the string 'Prototype'.] + expected: FAIL + diff --git a/testing/web-platform/meta/XMLHttpRequest/getallresponseheaders-cl.htm.ini b/testing/web-platform/meta/XMLHttpRequest/getallresponseheaders-cl.htm.ini index 2af4ca8c3e65..3c5183c11c92 100644 --- a/testing/web-platform/meta/XMLHttpRequest/getallresponseheaders-cl.htm.ini +++ b/testing/web-platform/meta/XMLHttpRequest/getallresponseheaders-cl.htm.ini @@ -3,9 +3,6 @@ [Casing of known headers] expected: FAIL - [Casing of known headers 1] - expected: PASS - [Casing of known headers 2] expected: FAIL diff --git a/testing/web-platform/meta/XMLHttpRequest/getresponseheader-chunked-trailer.htm.ini b/testing/web-platform/meta/XMLHttpRequest/getresponseheader-chunked-trailer.htm.ini new file mode 100644 index 000000000000..0ee1ddfee54a --- /dev/null +++ b/testing/web-platform/meta/XMLHttpRequest/getresponseheader-chunked-trailer.htm.ini @@ -0,0 +1,5 @@ +[getresponseheader-chunked-trailer.htm] + type: testharness + [XMLHttpRequest: getResponseHeader() and HTTP trailer] + expected: FAIL + diff --git a/testing/web-platform/meta/XMLHttpRequest/overridemimetype-blob.html.ini b/testing/web-platform/meta/XMLHttpRequest/overridemimetype-blob.html.ini index c9d8aff5a641..875414ffd388 100644 --- a/testing/web-platform/meta/XMLHttpRequest/overridemimetype-blob.html.ini +++ b/testing/web-platform/meta/XMLHttpRequest/overridemimetype-blob.html.ini @@ -1,14 +1,5 @@ [overridemimetype-blob.html] type: testharness - [Use text/xml as fallback MIME type] - expected: FAIL - - [Use text/xml as fallback MIME type, 2] - expected: FAIL - - [Bogus MIME type should end up as application/octet-stream] - expected: FAIL - [Bogus MIME type should end up as application/octet-stream, 2] expected: FAIL diff --git a/testing/web-platform/meta/accelerometer/Accelerometer.https.html.ini b/testing/web-platform/meta/accelerometer/Accelerometer.https.html.ini new file mode 100644 index 000000000000..a00a2fec2062 --- /dev/null +++ b/testing/web-platform/meta/accelerometer/Accelerometer.https.html.ini @@ -0,0 +1,5 @@ +[Accelerometer.https.html] + type: testharness + [Accelerometer Test] + expected: FAIL + diff --git a/testing/web-platform/meta/accelerometer/Accelerometer_insecure_context.html.ini b/testing/web-platform/meta/accelerometer/Accelerometer_insecure_context.html.ini new file mode 100644 index 000000000000..ae605a926a2c --- /dev/null +++ b/testing/web-platform/meta/accelerometer/Accelerometer_insecure_context.html.ini @@ -0,0 +1,5 @@ +[Accelerometer_insecure_context.html] + type: testharness + [Accelerometer Test: insecure context] + expected: FAIL + diff --git a/testing/web-platform/meta/accelerometer/idlharness.https.html.ini b/testing/web-platform/meta/accelerometer/idlharness.https.html.ini index 10fcc20a8592..f43f604e4b9d 100644 --- a/testing/web-platform/meta/accelerometer/idlharness.https.html.ini +++ b/testing/web-platform/meta/accelerometer/idlharness.https.html.ini @@ -96,3 +96,129 @@ [SensorReading interface: new AccelerometerReading({x: 0.5, y: 0.5, z: 0.5}); must inherit property "timeStamp" with the proper type (0)] expected: FAIL + [Accelerometer interface: attribute x] + expected: FAIL + + [Accelerometer interface: attribute y] + expected: FAIL + + [Accelerometer interface: attribute z] + expected: FAIL + + [Accelerometer interface: new Accelerometer(); must inherit property "x" with the proper type (0)] + expected: FAIL + + [Accelerometer interface: new Accelerometer(); must inherit property "y" with the proper type (1)] + expected: FAIL + + [Accelerometer interface: new Accelerometer(); must inherit property "z" with the proper type (2)] + expected: FAIL + + [Sensor interface: new Accelerometer(); must inherit property "activated" with the proper type (0)] + expected: FAIL + + [Sensor interface: new Accelerometer(); must inherit property "timestamp" with the proper type (1)] + expected: FAIL + + [LinearAccelerationSensor interface: existence and properties of interface object] + expected: FAIL + + [LinearAccelerationSensor interface object length] + expected: FAIL + + [LinearAccelerationSensor interface object name] + expected: FAIL + + [LinearAccelerationSensor interface: existence and properties of interface prototype object] + expected: FAIL + + [LinearAccelerationSensor interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [LinearAccelerationSensor must be primary interface of new LinearAccelerationSensor();] + expected: FAIL + + [Stringification of new LinearAccelerationSensor();] + expected: FAIL + + [Accelerometer interface: new LinearAccelerationSensor(); must inherit property "x" with the proper type (0)] + expected: FAIL + + [Accelerometer interface: new LinearAccelerationSensor(); must inherit property "y" with the proper type (1)] + expected: FAIL + + [Accelerometer interface: new LinearAccelerationSensor(); must inherit property "z" with the proper type (2)] + expected: FAIL + + [Sensor interface: new LinearAccelerationSensor(); must inherit property "activated" with the proper type (0)] + expected: FAIL + + [Sensor interface: new LinearAccelerationSensor(); must inherit property "timestamp" with the proper type (1)] + expected: FAIL + + [Sensor interface: new LinearAccelerationSensor(); must inherit property "start" with the proper type (2)] + expected: FAIL + + [Sensor interface: new LinearAccelerationSensor(); must inherit property "stop" with the proper type (3)] + expected: FAIL + + [Sensor interface: new LinearAccelerationSensor(); must inherit property "onchange" with the proper type (4)] + expected: FAIL + + [Sensor interface: new LinearAccelerationSensor(); must inherit property "onactivate" with the proper type (5)] + expected: FAIL + + [Sensor interface: new LinearAccelerationSensor(); must inherit property "onerror" with the proper type (6)] + expected: FAIL + + [GravitySensor interface: existence and properties of interface object] + expected: FAIL + + [GravitySensor interface object length] + expected: FAIL + + [GravitySensor interface object name] + expected: FAIL + + [GravitySensor interface: existence and properties of interface prototype object] + expected: FAIL + + [GravitySensor interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [GravitySensor must be primary interface of new GravitySensor();] + expected: FAIL + + [Stringification of new GravitySensor();] + expected: FAIL + + [Accelerometer interface: new GravitySensor(); must inherit property "x" with the proper type (0)] + expected: FAIL + + [Accelerometer interface: new GravitySensor(); must inherit property "y" with the proper type (1)] + expected: FAIL + + [Accelerometer interface: new GravitySensor(); must inherit property "z" with the proper type (2)] + expected: FAIL + + [Sensor interface: new GravitySensor(); must inherit property "activated" with the proper type (0)] + expected: FAIL + + [Sensor interface: new GravitySensor(); must inherit property "timestamp" with the proper type (1)] + expected: FAIL + + [Sensor interface: new GravitySensor(); must inherit property "start" with the proper type (2)] + expected: FAIL + + [Sensor interface: new GravitySensor(); must inherit property "stop" with the proper type (3)] + expected: FAIL + + [Sensor interface: new GravitySensor(); must inherit property "onchange" with the proper type (4)] + expected: FAIL + + [Sensor interface: new GravitySensor(); must inherit property "onactivate" with the proper type (5)] + expected: FAIL + + [Sensor interface: new GravitySensor(); must inherit property "onerror" with the proper type (6)] + expected: FAIL + diff --git a/testing/web-platform/meta/ambient-light/AmbientLightSensor.https.html.ini b/testing/web-platform/meta/ambient-light/AmbientLightSensor.https.html.ini new file mode 100644 index 000000000000..2d1f0436d491 --- /dev/null +++ b/testing/web-platform/meta/ambient-light/AmbientLightSensor.https.html.ini @@ -0,0 +1,5 @@ +[AmbientLightSensor.https.html] + type: testharness + [AmbientLightSensor Test] + expected: FAIL + diff --git a/testing/web-platform/meta/ambient-light/AmbientLightSensor_browsing_context.https.html.ini b/testing/web-platform/meta/ambient-light/AmbientLightSensor_browsing_context.https.html.ini deleted file mode 100644 index 8af870e5476f..000000000000 --- a/testing/web-platform/meta/ambient-light/AmbientLightSensor_browsing_context.https.html.ini +++ /dev/null @@ -1,8 +0,0 @@ -[AmbientLightSensor_browsing_context.https.html] - type: testharness - [throw a 'SecurityError' when firing sensor readings within iframes] - expected: FAIL - - [sensor readings can not be fired on the background tab] - expected: FAIL - diff --git a/testing/web-platform/meta/ambient-light/AmbientLightSensor_insecure_context.html.ini b/testing/web-platform/meta/ambient-light/AmbientLightSensor_insecure_context.html.ini index 63f696094f85..abf45b9c7713 100644 --- a/testing/web-platform/meta/ambient-light/AmbientLightSensor_insecure_context.html.ini +++ b/testing/web-platform/meta/ambient-light/AmbientLightSensor_insecure_context.html.ini @@ -3,3 +3,6 @@ [throw a 'SecurityError' when construct AmbientLightSensor in an insecure context] expected: FAIL + [AmbientLightSensor Test: insecure context] + expected: FAIL + diff --git a/testing/web-platform/meta/ambient-light/AmbientLightSensor_onchange.https.html.ini b/testing/web-platform/meta/ambient-light/AmbientLightSensor_onchange.https.html.ini deleted file mode 100644 index 274eec46683d..000000000000 --- a/testing/web-platform/meta/ambient-light/AmbientLightSensor_onchange.https.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[AmbientLightSensor_onchange.https.html] - type: testharness - [event change fired] - expected: FAIL - diff --git a/testing/web-platform/meta/ambient-light/AmbientLightSensor_reading.https.html.ini b/testing/web-platform/meta/ambient-light/AmbientLightSensor_reading.https.html.ini deleted file mode 100644 index 2738befc352d..000000000000 --- a/testing/web-platform/meta/ambient-light/AmbientLightSensor_reading.https.html.ini +++ /dev/null @@ -1,12 +0,0 @@ -[AmbientLightSensor_reading.https.html] - type: testharness - expected: ERROR - [Test that sensor reading must be immutable.] - expected: FAIL - - [Test that sensor reading is correct.] - expected: FAIL - - [Test that the sensor reading is updated when time passes.] - expected: FAIL - diff --git a/testing/web-platform/meta/ambient-light/AmbientLightSensor_start.https.html.ini b/testing/web-platform/meta/ambient-light/AmbientLightSensor_start.https.html.ini deleted file mode 100644 index 5915501c6204..000000000000 --- a/testing/web-platform/meta/ambient-light/AmbientLightSensor_start.https.html.ini +++ /dev/null @@ -1,15 +0,0 @@ -[AmbientLightSensor_start.https.html] - type: testharness - expected: ERROR - [The default sensor.reading is 'null'] - expected: FAIL - - [The default sensor.state is 'idle'] - expected: FAIL - - [The sensor.state changes to 'activating' after sensor.start()] - expected: FAIL - - [throw an InvalidStateError exception when state is neither idle nor errored] - expected: FAIL - diff --git a/testing/web-platform/meta/ambient-light/AmbientLightSensor_stop.https.html.ini b/testing/web-platform/meta/ambient-light/AmbientLightSensor_stop.https.html.ini deleted file mode 100644 index 53615a6e5dc9..000000000000 --- a/testing/web-platform/meta/ambient-light/AmbientLightSensor_stop.https.html.ini +++ /dev/null @@ -1,12 +0,0 @@ -[AmbientLightSensor_stop.https.html] - type: testharness - expected: ERROR - [The sensor.state changes to 'idle' after sensor.stop()] - expected: FAIL - - [the sensor.reading is null after executing stop() method] - expected: FAIL - - [throw an InvalidStateError exception when state is either idle or errored] - expected: FAIL - diff --git a/testing/web-platform/meta/ambient-light/AmbientLightSensor_tests.html.ini b/testing/web-platform/meta/ambient-light/AmbientLightSensor_tests.html.ini deleted file mode 100644 index 368b798c536a..000000000000 --- a/testing/web-platform/meta/ambient-light/AmbientLightSensor_tests.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[AmbientLightSensor_tests.html] - type: testharness - [Test suite not implemented yet.] - expected: FAIL - diff --git a/testing/web-platform/meta/ambient-light/idlharness.https.html.ini b/testing/web-platform/meta/ambient-light/idlharness.https.html.ini index 335d98827fae..002d5ecd1dd3 100644 --- a/testing/web-platform/meta/ambient-light/idlharness.https.html.ini +++ b/testing/web-platform/meta/ambient-light/idlharness.https.html.ini @@ -72,3 +72,15 @@ [SensorReading interface: new AmbientLightSensorReading({ illuminance: 750 }); must inherit property "timeStamp" with the proper type (0)] expected: FAIL + [AmbientLightSensor interface: attribute illuminance] + expected: FAIL + + [AmbientLightSensor interface: new AmbientLightSensor(); must inherit property "illuminance" with the proper type (0)] + expected: FAIL + + [Sensor interface: new AmbientLightSensor(); must inherit property "activated" with the proper type (0)] + expected: FAIL + + [Sensor interface: new AmbientLightSensor(); must inherit property "timestamp" with the proper type (1)] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/child-src/child-src-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/child-src/child-src-blocked.sub.html.ini index fccf9a0c7409..729a721a29ea 100644 --- a/testing/web-platform/meta/content-security-policy/child-src/child-src-blocked.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/child-src/child-src-blocked.sub.html.ini @@ -3,3 +3,6 @@ [Expecting logs: ["PASS IFrame #1 generated a load event."\]] expected: FAIL + [Violation report status OK.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/child-src/child-src-cross-origin-load.sub.html.ini b/testing/web-platform/meta/content-security-policy/child-src/child-src-cross-origin-load.sub.html.ini index 40226febaf42..1d070818715f 100644 --- a/testing/web-platform/meta/content-security-policy/child-src/child-src-cross-origin-load.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/child-src/child-src-cross-origin-load.sub.html.ini @@ -3,3 +3,6 @@ [Expecting logs: ["PASS IFrame #1 generated a load event.","PASS IFrame #2 generated a load event.","PASS IFrame #3 generated a load event."\]] expected: FAIL + [Violation report status OK.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/child-src/child-src-redirect-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/child-src/child-src-redirect-blocked.sub.html.ini new file mode 100644 index 000000000000..58a6d20e7e76 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/child-src/child-src-redirect-blocked.sub.html.ini @@ -0,0 +1,8 @@ +[child-src-redirect-blocked.sub.html] + type: testharness + [Expecting logs: ["PASS IFrame #1 generated a load event."\]] + expected: FAIL + + [Violation report status OK.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/child-src/child-src-worker-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/child-src/child-src-worker-blocked.sub.html.ini new file mode 100644 index 000000000000..cc7d1a6d236c --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/child-src/child-src-worker-blocked.sub.html.ini @@ -0,0 +1,6 @@ +[child-src-worker-blocked.sub.html] + type: testharness + expected: TIMEOUT + [Should throw a securitypolicyviolation event] + expected: TIMEOUT + diff --git a/testing/web-platform/meta/content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html.ini b/testing/web-platform/meta/content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html.ini new file mode 100644 index 000000000000..52ddff18c0fc --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html.ini @@ -0,0 +1,5 @@ +[embedding_csp-header-invalid-format.html] + type: testharness + [Test Embedding-CSP value on `csp` change: Wrong value of `csp` should not trigger sending Embedding-CSP Header.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html.ini new file mode 100644 index 000000000000..62863e4c2f40 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-cross-in-cross-none-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a value 'none' should block rendering in nested frames.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html.ini new file mode 100644 index 000000000000..261c94829ebb --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-cross-in-cross-self-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a value 'same' should block render in same-origin nested frames.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block.html.ini new file mode 100644 index 000000000000..c3837b0c6f0d --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-cross-in-cross-url-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a URL value should block or allow rendering in nested frames as appropriate.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html.ini new file mode 100644 index 000000000000..6bef8ed55ef1 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-cross-in-same-none-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a value 'none' should block rendering in nested frames.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block.html.ini new file mode 100644 index 000000000000..bd3fceece54b --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-cross-in-same-self-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a value 'same' should block render in same-origin nested frames.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html.ini new file mode 100644 index 000000000000..b635f730c55f --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html.ini @@ -0,0 +1,5 @@ +[frame-ancestors-nested-cross-in-same-star-allow.html] + type: testharness + [A 'frame-ancestors' CSP directive with a value '*' should render in nested frames.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow.html.ini new file mode 100644 index 000000000000..989bfcf51147 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow.html.ini @@ -0,0 +1,5 @@ +[frame-ancestors-nested-cross-in-same-url-allow.html] + type: testharness + [A 'frame-ancestors' CSP directive with a URL value should block or allow rendering in nested frames as appropriate.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block.html.ini new file mode 100644 index 000000000000..59120f70a527 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-cross-in-same-url-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a URL value should block or allow rendering in nested frames as appropriate.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html.ini new file mode 100644 index 000000000000..5a7a631d95dc --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html.ini @@ -0,0 +1,5 @@ +[frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html] + type: testharness + [A 'frame-ancestors' CSP directive with a URL value should compare against each frame's origin rather than URL, so a nested frame with a sandboxed parent frame should be blocked due to the parent having a unique origin.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block.html.ini new file mode 100644 index 000000000000..816f670dfccb --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-same-in-cross-none-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a value 'none' should block rendering in nested frames.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block.html.ini new file mode 100644 index 000000000000..70f1784e47d3 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-same-in-cross-self-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a value 'same' should block render in same-origin nested frames.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block.html.ini new file mode 100644 index 000000000000..33270398290c --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-same-in-cross-url-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a URL value should block or allow rendering in nested frames as appropriate.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block.html.ini new file mode 100644 index 000000000000..fbdb8375b8af --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-same-in-same-none-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a value 'none' should block rendering in nested frames.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block.html.ini new file mode 100644 index 000000000000..8fdf69b41e51 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-nested-same-in-same-url-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a URL value should block or allow rendering in nested frames as appropriate.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-none-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-none-block.html.ini new file mode 100644 index 000000000000..ad29e24cf971 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-none-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-none-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a value 'none' should block rendering.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-overrides-xfo.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-overrides-xfo.html.ini new file mode 100644 index 000000000000..8aefa98a18ba --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-overrides-xfo.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-overrides-xfo.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive overrides an 'x-frame-options' header which would allow the page.] + expected: TIMEOUT + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-self-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-self-block.html.ini new file mode 100644 index 000000000000..d9b6afe08ba0 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-self-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-self-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a value 'self' should block rendering.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin.html.ini new file mode 100644 index 000000000000..2b7454cdc608 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin.html.ini @@ -0,0 +1,5 @@ +[frame-ancestors-star-allow-crossorigin.html] + type: testharness + [A 'frame-ancestors' CSP directive with '*' should allow rendering.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-url-block.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-url-block.html.ini new file mode 100644 index 000000000000..82c31cc9cb68 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/frame-ancestors-url-block.html.ini @@ -0,0 +1,6 @@ +[frame-ancestors-url-block.html] + type: testharness + expected: TIMEOUT + [A 'frame-ancestors' CSP directive with a URL which doesn't match this origin should be blocked.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/multiple-frames-meta-ignored.sub.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/multiple-frames-meta-ignored.sub.html.ini deleted file mode 100644 index d0bb1d09a8a7..000000000000 --- a/testing/web-platform/meta/content-security-policy/frame-ancestors/multiple-frames-meta-ignored.sub.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multiple-frames-meta-ignored.sub.html] - type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1273241 diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/multiple-frames-self-allowed.sub.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/multiple-frames-self-allowed.sub.html.ini deleted file mode 100644 index e9a6bb3a6cb2..000000000000 --- a/testing/web-platform/meta/content-security-policy/frame-ancestors/multiple-frames-self-allowed.sub.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[multiple-frames-self-allowed.sub.html] - type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1273241 diff --git a/testing/web-platform/meta/content-security-policy/frame-ancestors/single-frame-self-allowed.sub.html.ini b/testing/web-platform/meta/content-security-policy/frame-ancestors/single-frame-self-allowed.sub.html.ini deleted file mode 100644 index 95f789eef1cb..000000000000 --- a/testing/web-platform/meta/content-security-policy/frame-ancestors/single-frame-self-allowed.sub.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[single-frame-self-allowed.sub.html] - type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1273241 diff --git a/testing/web-platform/meta/content-security-policy/frame-src/frame-src-redirect.html.ini b/testing/web-platform/meta/content-security-policy/frame-src/frame-src-redirect.html.ini new file mode 100644 index 000000000000..1f197f34ff57 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/frame-src/frame-src-redirect.html.ini @@ -0,0 +1,6 @@ +[frame-src-redirect.html] + type: testharness + expected: TIMEOUT + [Redirected iframe src should evaluate both enforced and report-only policies on both original request and when following redirect] + expected: TIMEOUT + diff --git a/testing/web-platform/meta/content-security-policy/generic/generic-0_1-img-src.html.ini b/testing/web-platform/meta/content-security-policy/generic/generic-0_1-img-src.html.ini new file mode 100644 index 000000000000..95f703100f53 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/generic/generic-0_1-img-src.html.ini @@ -0,0 +1,5 @@ +[generic-0_1-img-src.html] + type: testharness + [Violation report status OK.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/generic/generic-0_1-script-src.html.ini b/testing/web-platform/meta/content-security-policy/generic/generic-0_1-script-src.html.ini new file mode 100644 index 000000000000..5b4d5059dac3 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/generic/generic-0_1-script-src.html.ini @@ -0,0 +1,5 @@ +[generic-0_1-script-src.html] + type: testharness + [Violation report status OK.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/script-src/script-src-sri_hash.sub.html.ini b/testing/web-platform/meta/content-security-policy/script-src/script-src-sri_hash.sub.html.ini new file mode 100644 index 000000000000..587656a83b34 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-sri_hash.sub.html.ini @@ -0,0 +1,14 @@ +[script-src-sri_hash.sub.html] + type: testharness + [matching integrity] + expected: FAIL + + [multiple matching integrity] + expected: FAIL + + [matching plus unsupported integrity] + expected: FAIL + + [External script in a script tag with matching SRI hash should run.] + expected: FAIL + diff --git a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.ini b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.ini new file mode 100644 index 000000000000..b123eab76511 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.ini @@ -0,0 +1,6 @@ +[img-src-redirect-upgrade-reporting.https.html] + type: testharness + expected: TIMEOUT + [Image that redirects to http:// URL prohibited by Report-Only must generate a violation report, even with upgrade-insecure-requests] + expected: TIMEOUT + diff --git a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.ini b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.ini new file mode 100644 index 000000000000..9857e2aaf642 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.ini @@ -0,0 +1,9 @@ +[upgrade-insecure-requests-reporting.https.html] + type: testharness + expected: TIMEOUT + [Upgraded image is reported] + expected: TIMEOUT + + [Upgraded iframe is reported] + expected: TIMEOUT + diff --git a/testing/web-platform/meta/content-security-policy/svg/object-in-svg-foreignobject.sub.html.ini b/testing/web-platform/meta/content-security-policy/svg/object-in-svg-foreignobject.sub.html.ini new file mode 100644 index 000000000000..3737282f09e0 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/svg/object-in-svg-foreignobject.sub.html.ini @@ -0,0 +1,6 @@ +[object-in-svg-foreignobject.sub.html] + type: testharness + expected: TIMEOUT + [Should throw a securitypolicyviolation] + expected: TIMEOUT + diff --git a/testing/web-platform/meta/credential-management/idl.https.html.ini b/testing/web-platform/meta/credential-management/idl.https.html.ini new file mode 100644 index 000000000000..a4400def8242 --- /dev/null +++ b/testing/web-platform/meta/credential-management/idl.https.html.ini @@ -0,0 +1,143 @@ +[idl.https.html] + type: testharness + [CredentialsContainer interface: existence and properties of interface object] + expected: FAIL + + [CredentialsContainer interface object length] + expected: FAIL + + [CredentialsContainer interface object name] + expected: FAIL + + [CredentialsContainer interface: existence and properties of interface prototype object] + expected: FAIL + + [CredentialsContainer interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [CredentialsContainer interface: operation get(CredentialRequestOptions)] + expected: FAIL + + [CredentialsContainer interface: operation store(Credential)] + expected: FAIL + + [CredentialsContainer interface: operation requireUserMediation()] + expected: FAIL + + [CredentialsContainer must be primary interface of navigator.credentials] + expected: FAIL + + [Stringification of navigator.credentials] + expected: FAIL + + [CredentialsContainer interface: navigator.credentials must inherit property "get" with the proper type (0)] + expected: FAIL + + [CredentialsContainer interface: calling get(CredentialRequestOptions) on navigator.credentials with too few arguments must throw TypeError] + expected: FAIL + + [CredentialsContainer interface: navigator.credentials must inherit property "store" with the proper type (1)] + expected: FAIL + + [CredentialsContainer interface: calling store(Credential) on navigator.credentials with too few arguments must throw TypeError] + expected: FAIL + + [CredentialsContainer interface: navigator.credentials must inherit property "requireUserMediation" with the proper type (2)] + expected: FAIL + + [PasswordCredential interface: existence and properties of interface object] + expected: FAIL + + [PasswordCredential interface object length] + expected: FAIL + + [PasswordCredential interface object name] + expected: FAIL + + [PasswordCredential interface: existence and properties of interface prototype object] + expected: FAIL + + [PasswordCredential interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [PasswordCredential interface: attribute idName] + expected: FAIL + + [PasswordCredential interface: attribute passwordName] + expected: FAIL + + [PasswordCredential interface: attribute additionalData] + expected: FAIL + + [PasswordCredential must be primary interface of new PasswordCredential({ id: "id", password: "pencil", iconURL: "https://example.com/", name: "name" })] + expected: FAIL + + [Stringification of new PasswordCredential({ id: "id", password: "pencil", iconURL: "https://example.com/", name: "name" })] + expected: FAIL + + [PasswordCredential interface: new PasswordCredential({ id: "id", password: "pencil", iconURL: "https://example.com/", name: "name" }) must inherit property "idName" with the proper type (0)] + expected: FAIL + + [PasswordCredential interface: new PasswordCredential({ id: "id", password: "pencil", iconURL: "https://example.com/", name: "name" }) must inherit property "passwordName" with the proper type (1)] + expected: FAIL + + [PasswordCredential interface: new PasswordCredential({ id: "id", password: "pencil", iconURL: "https://example.com/", name: "name" }) must inherit property "additionalData" with the proper type (2)] + expected: FAIL + + [PasswordCredential interface: new PasswordCredential({ id: "id", password: "pencil", iconURL: "https://example.com/", name: "name" }) must inherit property "name" with the proper type (3)] + expected: FAIL + + [PasswordCredential interface: new PasswordCredential({ id: "id", password: "pencil", iconURL: "https://example.com/", name: "name" }) must inherit property "iconURL" with the proper type (4)] + expected: FAIL + + [Credential interface: new PasswordCredential({ id: "id", password: "pencil", iconURL: "https://example.com/", name: "name" }) must inherit property "id" with the proper type (0)] + expected: FAIL + + [Credential interface: new PasswordCredential({ id: "id", password: "pencil", iconURL: "https://example.com/", name: "name" }) must inherit property "type" with the proper type (1)] + expected: FAIL + + [FederatedCredential interface: existence and properties of interface object] + expected: FAIL + + [FederatedCredential interface object length] + expected: FAIL + + [FederatedCredential interface object name] + expected: FAIL + + [FederatedCredential interface: existence and properties of interface prototype object] + expected: FAIL + + [FederatedCredential interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [FederatedCredential interface: attribute provider] + expected: FAIL + + [FederatedCredential interface: attribute protocol] + expected: FAIL + + [FederatedCredential must be primary interface of new FederatedCredential({ id: "id", provider: "https://example.com", iconURL: "https://example.com/", name: "name" })] + expected: FAIL + + [Stringification of new FederatedCredential({ id: "id", provider: "https://example.com", iconURL: "https://example.com/", name: "name" })] + expected: FAIL + + [FederatedCredential interface: new FederatedCredential({ id: "id", provider: "https://example.com", iconURL: "https://example.com/", name: "name" }) must inherit property "provider" with the proper type (0)] + expected: FAIL + + [FederatedCredential interface: new FederatedCredential({ id: "id", provider: "https://example.com", iconURL: "https://example.com/", name: "name" }) must inherit property "protocol" with the proper type (1)] + expected: FAIL + + [FederatedCredential interface: new FederatedCredential({ id: "id", provider: "https://example.com", iconURL: "https://example.com/", name: "name" }) must inherit property "name" with the proper type (2)] + expected: FAIL + + [FederatedCredential interface: new FederatedCredential({ id: "id", provider: "https://example.com", iconURL: "https://example.com/", name: "name" }) must inherit property "iconURL" with the proper type (3)] + expected: FAIL + + [Credential interface: new FederatedCredential({ id: "id", provider: "https://example.com", iconURL: "https://example.com/", name: "name" }) must inherit property "id" with the proper type (0)] + expected: FAIL + + [Credential interface: new FederatedCredential({ id: "id", provider: "https://example.com", iconURL: "https://example.com/", name: "name" }) must inherit property "type" with the proper type (1)] + expected: FAIL + diff --git a/testing/web-platform/meta/css/css-transitions-1/properties-value-inherit-002.html.ini b/testing/web-platform/meta/css/css-transitions-1/properties-value-inherit-002.html.ini index 08757ee8dea3..6e0e27ad669c 100644 --- a/testing/web-platform/meta/css/css-transitions-1/properties-value-inherit-002.html.ini +++ b/testing/web-platform/meta/css/css-transitions-1/properties-value-inherit-002.html.ini @@ -34,3 +34,4 @@ [crop rectangle(rectangle) / events] expected: FAIL + diff --git a/testing/web-platform/meta/cssom-view/CaretPosition-001.html.ini b/testing/web-platform/meta/cssom-view/CaretPosition-001.html.ini new file mode 100644 index 000000000000..b6c46e6be4c5 --- /dev/null +++ b/testing/web-platform/meta/cssom-view/CaretPosition-001.html.ini @@ -0,0 +1,5 @@ +[CaretPosition-001.html] + type: testharness + [Element at (400, 900)] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom-view/cssom-view/window-interface.xht.ini b/testing/web-platform/meta/cssom-view/cssom-view/window-interface.xht.ini new file mode 100644 index 000000000000..b814ee065eb7 --- /dev/null +++ b/testing/web-platform/meta/cssom-view/cssom-view/window-interface.xht.ini @@ -0,0 +1,5 @@ +[window-interface.xht] + type: testharness + [window_properties_readonly] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom-view/elementFromPosition.html.ini b/testing/web-platform/meta/cssom-view/elementFromPosition.html.ini new file mode 100644 index 000000000000..cf45efa60a6c --- /dev/null +++ b/testing/web-platform/meta/cssom-view/elementFromPosition.html.ini @@ -0,0 +1,17 @@ +[elementFromPosition.html] + type: testharness + [test some point of the element: top right corner] + expected: FAIL + + [test some point of the element: right line] + expected: FAIL + + [test some point of the element: bottom left corner] + expected: FAIL + + [test some point of the element: bottom line] + expected: FAIL + + [test some point of the element: bottom right corner] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom-view/elementScroll.html.ini b/testing/web-platform/meta/cssom-view/elementScroll.html.ini deleted file mode 100644 index 706def9d3301..000000000000 --- a/testing/web-platform/meta/cssom-view/elementScroll.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[elementScroll.html] - type: testharness - [Element scroll maximum test] - expected: FAIL - diff --git a/testing/web-platform/meta/cssom-view/matchMedia.xht.ini b/testing/web-platform/meta/cssom-view/matchMedia.xht.ini new file mode 100644 index 000000000000..147727697020 --- /dev/null +++ b/testing/web-platform/meta/cssom-view/matchMedia.xht.ini @@ -0,0 +1,18 @@ +[matchMedia.xht] + type: testharness + expected: TIMEOUT + [window.matchMedia exists] + expected: FAIL + + [MediaQueryList.matches for "(max-width: 199px), all and (min-width: 200px)"] + expected: FAIL + + [Resize iframe from 200x100 to 200x50, then to 100x50] + expected: NOTRUN + + [Listeners are called in the order which they have been added] + expected: NOTRUN + + [Listener added twice is only called once.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/cssom-view/matchMediaAddListener.html.ini b/testing/web-platform/meta/cssom-view/matchMediaAddListener.html.ini new file mode 100644 index 000000000000..77139c46ea93 --- /dev/null +++ b/testing/web-platform/meta/cssom-view/matchMediaAddListener.html.ini @@ -0,0 +1,5 @@ +[matchMediaAddListener.html] + type: testharness + [Check for the correct number of event triggers] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom-view/offsetParent_element_test.html.ini b/testing/web-platform/meta/cssom-view/offsetParent_element_test.html.ini new file mode 100644 index 000000000000..5baf504bc27f --- /dev/null +++ b/testing/web-platform/meta/cssom-view/offsetParent_element_test.html.ini @@ -0,0 +1,8 @@ +[offsetParent_element_test.html] + type: testharness + [Valid the algorithm rule of offsetParent check step 1] + expected: FAIL + + [Valid the algorithm rule of offsetParent check step 2] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/CSSStyleRule.html.ini b/testing/web-platform/meta/cssom/CSSStyleRule.html.ini new file mode 100644 index 000000000000..8cde08b0b226 --- /dev/null +++ b/testing/web-platform/meta/cssom/CSSStyleRule.html.ini @@ -0,0 +1,5 @@ +[CSSStyleRule.html] + type: testharness + [Mutability of CSSStyleRule's style attribute] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/cssom-fontfacerule.html.ini b/testing/web-platform/meta/cssom/cssom-fontfacerule.html.ini new file mode 100644 index 000000000000..927c6dba92ea --- /dev/null +++ b/testing/web-platform/meta/cssom/cssom-fontfacerule.html.ini @@ -0,0 +1,5 @@ +[cssom-fontfacerule.html] + type: testharness + [CSSStyleDeclaration values are represented within CSSFontFaceRule] + expected: FAIL + diff --git a/testing/web-platform/meta/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.html.ini b/testing/web-platform/meta/cssom/escape.html.ini similarity index 50% rename from testing/web-platform/meta/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.html.ini rename to testing/web-platform/meta/cssom/escape.html.ini index ece19e9f8302..2a52dea78de1 100644 --- a/testing/web-platform/meta/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.html.ini +++ b/testing/web-platform/meta/cssom/escape.html.ini @@ -1,5 +1,5 @@ -[NavigatorID.html] +[escape.html] type: testharness - [userAgent value] + [Various tests] expected: FAIL diff --git a/testing/web-platform/meta/cssom/index-002.html.ini b/testing/web-platform/meta/cssom/index-002.html.ini new file mode 100644 index 000000000000..aa3eb4314473 --- /dev/null +++ b/testing/web-platform/meta/cssom/index-002.html.ini @@ -0,0 +1,38 @@ +[index-002.html] + type: testharness + [border is expected to be border: 1px;] + expected: FAIL + + [border is expected to be border: 1px red;] + expected: FAIL + + [border is expected to be border: red;] + expected: FAIL + + [border is expected to be border: 1px; (#2)] + expected: FAIL + + [border is expected to be border-width: 1px 2px 3px 4px;] + expected: FAIL + + [border is expected to be border-width: 2px 1px 1px;] + expected: FAIL + + [border is expected to be border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-width: 1px !important;] + expected: FAIL + + [border is expected to be border-width: 1px; border-top-color: red;] + expected: FAIL + + [border is expected to be border: dotted;] + expected: FAIL + + [overflow is expected to be overflow: scroll hidden;] + expected: FAIL + + [outline is expected to be outline: blue dotted 2px;] + expected: FAIL + + [list is expected to be list-style: circle inside;] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/index-003.html.ini b/testing/web-platform/meta/cssom/index-003.html.ini new file mode 100644 index 000000000000..4ac80d65a615 --- /dev/null +++ b/testing/web-platform/meta/cssom/index-003.html.ini @@ -0,0 +1,5 @@ +[index-003.html] + type: testharness + [page rule is expected to be @page :first] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/inline-style-001.html.ini b/testing/web-platform/meta/cssom/inline-style-001.html.ini new file mode 100644 index 000000000000..22b7ca432d6b --- /dev/null +++ b/testing/web-platform/meta/cssom/inline-style-001.html.ini @@ -0,0 +1,17 @@ +[inline-style-001.html] + type: testharness + [CSSStyleDeclaration_accessible] + expected: FAIL + + [read] + expected: FAIL + + [csstext_write] + expected: FAIL + + [property_write] + expected: FAIL + + [shorthand_properties] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/interfaces.html.ini b/testing/web-platform/meta/cssom/interfaces.html.ini new file mode 100644 index 000000000000..0dd7b138e79e --- /dev/null +++ b/testing/web-platform/meta/cssom/interfaces.html.ini @@ -0,0 +1,101 @@ +[interfaces.html] + type: testharness + [Document must be primary interface of document] + expected: FAIL + + [Stringification of document] + expected: FAIL + + [ProcessingInstruction interface: attribute sheet] + expected: FAIL + + [MediaList interface: stringifier] + expected: FAIL + + [StyleSheet interface: attribute media] + expected: FAIL + + [CSSStyleSheet interface: operation insertRule(DOMString,unsigned long)] + expected: FAIL + + [CSSStyleSheet interface: calling insertRule(DOMString,unsigned long) on style_element.sheet with too few arguments must throw TypeError] + expected: FAIL + + [StyleSheetList interface: existence and properties of interface prototype object] + expected: FAIL + + [CSSRuleList interface: existence and properties of interface prototype object] + expected: FAIL + + [CSSRule interface: constant MARGIN_RULE on interface object] + expected: FAIL + + [CSSRule interface: constant MARGIN_RULE on interface prototype object] + expected: FAIL + + [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "MARGIN_RULE" with the proper type (6)] + expected: FAIL + + [CSSGroupingRule interface: operation insertRule(DOMString,unsigned long)] + expected: FAIL + + [CSSMediaRule interface: existence and properties of interface object] + expected: FAIL + + [CSSMediaRule interface: existence and properties of interface prototype object] + expected: FAIL + + [CSSPageRule interface: existence and properties of interface object] + expected: FAIL + + [CSSPageRule interface: existence and properties of interface prototype object] + expected: FAIL + + [CSSPageRule interface: attribute selectorText] + expected: FAIL + + [CSSMarginRule interface: existence and properties of interface object] + expected: FAIL + + [CSSMarginRule interface object length] + expected: FAIL + + [CSSMarginRule interface object name] + expected: FAIL + + [CSSMarginRule interface: existence and properties of interface prototype object] + expected: FAIL + + [CSSMarginRule interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [CSSMarginRule interface: attribute name] + expected: FAIL + + [CSSMarginRule interface: attribute style] + expected: FAIL + + [CSSNamespaceRule interface: attribute namespaceURI] + expected: FAIL + + [CSSNamespaceRule interface: attribute prefix] + expected: FAIL + + [CSSStyleDeclaration interface: operation setPropertyValue(DOMString,DOMString)] + expected: FAIL + + [CSSStyleDeclaration interface: operation setPropertyPriority(DOMString,DOMString)] + expected: FAIL + + [CSSStyleDeclaration interface: attribute cssFloat] + expected: FAIL + + [CSS interface: existence and properties of interface prototype object] + expected: FAIL + + [CSS interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [CSS interface: operation escape(DOMString)] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/medialist-interfaces-001.html.ini b/testing/web-platform/meta/cssom/medialist-interfaces-001.html.ini new file mode 100644 index 000000000000..40548eb9049d --- /dev/null +++ b/testing/web-platform/meta/cssom/medialist-interfaces-001.html.ini @@ -0,0 +1,5 @@ +[medialist-interfaces-001.html] + type: testharness + [mediatest_medialist_serialize_lexicographical] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/medialist-interfaces-002.html.ini b/testing/web-platform/meta/cssom/medialist-interfaces-002.html.ini new file mode 100644 index 000000000000..4bedbbc64b27 --- /dev/null +++ b/testing/web-platform/meta/cssom/medialist-interfaces-002.html.ini @@ -0,0 +1,5 @@ +[medialist-interfaces-002.html] + type: testharness + [deleteMedium_no_matching_medium_to_remove] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/medialist-interfaces-003.html.ini b/testing/web-platform/meta/cssom/medialist-interfaces-003.html.ini new file mode 100644 index 000000000000..6cb214f5cbfe --- /dev/null +++ b/testing/web-platform/meta/cssom/medialist-interfaces-003.html.ini @@ -0,0 +1,8 @@ +[medialist-interfaces-003.html] + type: testharness + [mediatest_mediaquery_serialize_1] + expected: FAIL + + [mediatest_mediaquery_serialize_2] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/medialist-interfaces-004.html.ini b/testing/web-platform/meta/cssom/medialist-interfaces-004.html.ini new file mode 100644 index 000000000000..38a1ef05d737 --- /dev/null +++ b/testing/web-platform/meta/cssom/medialist-interfaces-004.html.ini @@ -0,0 +1,5 @@ +[medialist-interfaces-004.html] + type: testharness + [appendMedium_correctly_appends_medium_to_nonempty_MediaList] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/serialize-namespaced-type-selectors.html.ini b/testing/web-platform/meta/cssom/serialize-namespaced-type-selectors.html.ini new file mode 100644 index 000000000000..825bf5ca570b --- /dev/null +++ b/testing/web-platform/meta/cssom/serialize-namespaced-type-selectors.html.ini @@ -0,0 +1,11 @@ +[serialize-namespaced-type-selectors.html] + type: testharness + [Universal selector followed by pseudo element] + expected: FAIL + + [Universal selector in any namespace followed by pseudo element] + expected: FAIL + + [Universal selector with namespace equal to default namespace followed by pseudo element] + expected: FAIL + diff --git a/testing/web-platform/meta/cssom/style-sheet-interfaces-001.html.ini b/testing/web-platform/meta/cssom/style-sheet-interfaces-001.html.ini new file mode 100644 index 000000000000..cba5df52390f --- /dev/null +++ b/testing/web-platform/meta/cssom/style-sheet-interfaces-001.html.ini @@ -0,0 +1,17 @@ +[style-sheet-interfaces-001.html] + type: testharness + [sheet_property] + expected: FAIL + + [CSSStyleSheet_properties] + expected: FAIL + + [CSSStyleSheet_property_values] + expected: FAIL + + [StyleSheet_properties] + expected: FAIL + + [StyleSheet_property_values] + expected: FAIL + diff --git a/testing/web-platform/meta/custom-elements/custom-element-registry/per-global.html.ini b/testing/web-platform/meta/custom-elements/custom-element-registry/per-global.html.ini new file mode 100644 index 000000000000..5d3edd775d99 --- /dev/null +++ b/testing/web-platform/meta/custom-elements/custom-element-registry/per-global.html.ini @@ -0,0 +1,6 @@ +[per-global.html] + type: testharness + expected: TIMEOUT + [Discarding the browsing context must not change window.customElements] + expected: FAIL + diff --git a/testing/web-platform/meta/custom-elements/microtasks-and-constructors.html.ini b/testing/web-platform/meta/custom-elements/microtasks-and-constructors.html.ini new file mode 100644 index 000000000000..0ac4cfd42e2b --- /dev/null +++ b/testing/web-platform/meta/custom-elements/microtasks-and-constructors.html.ini @@ -0,0 +1,17 @@ +[microtasks-and-constructors.html] + type: testharness + [Microtasks evaluate immediately when the stack is empty inside the parser] + expected: FAIL + + [Microtasks evaluate immediately when the stack is empty inside the parser, causing the checks on no attributes to fail] + expected: FAIL + + [Microtasks evaluate afterward when the stack is not empty using createElement()] + expected: FAIL + + [Microtasks evaluate afterward when the stack is not empty using the constructor] + expected: FAIL + + [Microtasks evaluate afterward when the stack is not empty due to upgrades] + expected: FAIL + diff --git a/testing/web-platform/meta/dom/events/EventListener-invoke-legacy.html.ini b/testing/web-platform/meta/dom/events/EventListener-invoke-legacy.html.ini index 96ddfd34c886..3d805ddeb7b6 100644 --- a/testing/web-platform/meta/dom/events/EventListener-invoke-legacy.html.ini +++ b/testing/web-platform/meta/dom/events/EventListener-invoke-legacy.html.ini @@ -1,4 +1,3 @@ [EventListener-invoke-legacy.html] + type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1351409 - - diff --git a/testing/web-platform/meta/fetch/api/redirect/redirect-location-worker.html.ini b/testing/web-platform/meta/fetch/api/redirect/redirect-location-worker.html.ini deleted file mode 100644 index af37b7bf83a4..000000000000 --- a/testing/web-platform/meta/fetch/api/redirect/redirect-location-worker.html.ini +++ /dev/null @@ -1,17 +0,0 @@ -[redirect-location-worker.html] - type: testharness - [Redirect 301 in "manual" mode without location] - expected: FAIL - - [Redirect 302 in "manual" mode without location] - expected: FAIL - - [Redirect 303 in "manual" mode without location] - expected: FAIL - - [Redirect 307 in "manual" mode without location] - expected: FAIL - - [Redirect 308 in "manual" mode without location] - expected: FAIL - diff --git a/testing/web-platform/meta/fetch/api/redirect/redirect-location.html.ini b/testing/web-platform/meta/fetch/api/redirect/redirect-location.html.ini deleted file mode 100644 index e876cd4944bb..000000000000 --- a/testing/web-platform/meta/fetch/api/redirect/redirect-location.html.ini +++ /dev/null @@ -1,17 +0,0 @@ -[redirect-location.html] - type: testharness - [Redirect 301 in "manual" mode without location] - expected: FAIL - - [Redirect 302 in "manual" mode without location] - expected: FAIL - - [Redirect 303 in "manual" mode without location] - expected: FAIL - - [Redirect 307 in "manual" mode without location] - expected: FAIL - - [Redirect 308 in "manual" mode without location] - expected: FAIL - diff --git a/testing/web-platform/meta/fetch/api/request/request-error.html.ini b/testing/web-platform/meta/fetch/api/request/request-error.html.ini index fc4710461677..77ddba7cbc2b 100644 --- a/testing/web-platform/meta/fetch/api/request/request-error.html.ini +++ b/testing/web-platform/meta/fetch/api/request/request-error.html.ini @@ -3,3 +3,6 @@ [RequestInit's window is not null] expected: FAIL + [RequestInit's mode is navigate] + expected: FAIL + diff --git a/testing/web-platform/meta/fetch/api/request/request-init-003.sub.html.ini b/testing/web-platform/meta/fetch/api/request/request-init-003.sub.html.ini deleted file mode 100644 index c4f52961261c..000000000000 --- a/testing/web-platform/meta/fetch/api/request/request-init-003.sub.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[request-init-003.sub.html] - type: testharness - [Check request values when initialized from url string] - expected: FAIL - diff --git a/testing/web-platform/meta/geolocation-API/getCurrentPosition_permission_allow.https.html.ini b/testing/web-platform/meta/geolocation-API/getCurrentPosition_permission_allow.https.html.ini index c71d73eee9c2..61cabbbfa9f1 100644 --- a/testing/web-platform/meta/geolocation-API/getCurrentPosition_permission_allow.https.html.ini +++ b/testing/web-platform/meta/geolocation-API/getCurrentPosition_permission_allow.https.html.ini @@ -2,5 +2,5 @@ type: testharness expected: TIMEOUT [User allows access, check that success callback is called or error callback is called with correct code.] - expected: NOTRUN + expected: TIMEOUT diff --git a/testing/web-platform/meta/gyroscope/Gyroscope.https.html.ini b/testing/web-platform/meta/gyroscope/Gyroscope.https.html.ini new file mode 100644 index 000000000000..a868436b5d0a --- /dev/null +++ b/testing/web-platform/meta/gyroscope/Gyroscope.https.html.ini @@ -0,0 +1,5 @@ +[Gyroscope.https.html] + type: testharness + [Gyroscope Test] + expected: FAIL + diff --git a/testing/web-platform/meta/gyroscope/Gyroscope_insecure_context.html.ini b/testing/web-platform/meta/gyroscope/Gyroscope_insecure_context.html.ini new file mode 100644 index 000000000000..7fa7e4f22149 --- /dev/null +++ b/testing/web-platform/meta/gyroscope/Gyroscope_insecure_context.html.ini @@ -0,0 +1,5 @@ +[Gyroscope_insecure_context.html] + type: testharness + [Gyroscope Test: insecure context] + expected: FAIL + diff --git a/testing/web-platform/meta/gyroscope/idlharness.https.html.ini b/testing/web-platform/meta/gyroscope/idlharness.https.html.ini index 86780a9e8d61..0e270e37b9fc 100644 --- a/testing/web-platform/meta/gyroscope/idlharness.https.html.ini +++ b/testing/web-platform/meta/gyroscope/idlharness.https.html.ini @@ -90,3 +90,27 @@ [SensorReading interface: new GyroscopeReading({x: 0.5, y: 0.5, z: 0.5}); must inherit property "timeStamp" with the proper type (0)] expected: FAIL + [Gyroscope interface: attribute x] + expected: FAIL + + [Gyroscope interface: attribute y] + expected: FAIL + + [Gyroscope interface: attribute z] + expected: FAIL + + [Gyroscope interface: new Gyroscope(); must inherit property "x" with the proper type (0)] + expected: FAIL + + [Gyroscope interface: new Gyroscope(); must inherit property "y" with the proper type (1)] + expected: FAIL + + [Gyroscope interface: new Gyroscope(); must inherit property "z" with the proper type (2)] + expected: FAIL + + [Sensor interface: new Gyroscope(); must inherit property "activated" with the proper type (0)] + expected: FAIL + + [Sensor interface: new Gyroscope(); must inherit property "timestamp" with the proper type (1)] + expected: FAIL + diff --git a/testing/web-platform/meta/html-media-capture/capture_reflect.html.ini b/testing/web-platform/meta/html-media-capture/capture_reflect.html.ini index 3e0c4893f4ce..ccba078c6595 100644 --- a/testing/web-platform/meta/html-media-capture/capture_reflect.html.ini +++ b/testing/web-platform/meta/html-media-capture/capture_reflect.html.ini @@ -15,3 +15,18 @@ [input.capture is true when the capture attribute is present as canonical name] expected: FAIL + [input.capture is "" when the capture attribute is absent] + expected: FAIL + + [input.capture is "" when the capture attribute is missing value default] + expected: FAIL + + [input.capture is "user" when the capture attribute is user] + expected: FAIL + + [input.capture is "invalid" when the capture attribute is invalid value default] + expected: FAIL + + [input.capture is "environment" when the capture attribute is environment] + expected: FAIL + diff --git a/testing/web-platform/meta/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html.ini b/testing/web-platform/meta/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html.ini index f2906736ed92..af787155a74d 100644 --- a/testing/web-platform/meta/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html.ini +++ b/testing/web-platform/meta/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html.ini @@ -1,4 +1,4 @@ [resume-timer-on-history-back.html] type: testharness disabled: - if (os == "win"): https://bugzilla.mozilla.org/show_bug.cgi?id=1321179 + if os == "win": https://bugzilla.mozilla.org/show_bug.cgi?id=1321179 diff --git a/testing/web-platform/meta/html/browsers/history/the-location-interface/per-global.window.js.ini b/testing/web-platform/meta/html/browsers/history/the-location-interface/per-global.window.js.ini new file mode 100644 index 000000000000..77e8a7786d9e --- /dev/null +++ b/testing/web-platform/meta/html/browsers/history/the-location-interface/per-global.window.js.ini @@ -0,0 +1,3 @@ +[per-global.window.html] + type: testharness + expected: TIMEOUT \ No newline at end of file diff --git a/testing/web-platform/meta/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html.ini b/testing/web-platform/meta/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html.ini new file mode 100644 index 000000000000..a06142ff3c06 --- /dev/null +++ b/testing/web-platform/meta/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html.ini @@ -0,0 +1,8 @@ +[document_domain_setter.html] + type: testharness + [failed setting of document.domain] + expected: FAIL + + [same-origin-domain iframe] + expected: FAIL + diff --git a/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-height.html.ini b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-height.html.ini new file mode 100644 index 000000000000..fe0b07e31827 --- /dev/null +++ b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-height.html.ini @@ -0,0 +1,5 @@ +[open-features-non-integer-height.html] + type: testharness + [top=0,left=0: absence of feature "height" should be treated same as "height=0"] + expected: FAIL + diff --git a/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-innerheight-innerwidth.html.ini b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-innerheight-innerwidth.html.ini new file mode 100644 index 000000000000..ada273f8122d --- /dev/null +++ b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-innerheight-innerwidth.html.ini @@ -0,0 +1,8 @@ +[open-features-tokenization-innerheight-innerwidth.html] + type: testharness + ["innerwidth==401" should set width of opened window] + expected: FAIL + + ["innerheight==402" should set height of opened window] + expected: FAIL + diff --git a/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html.ini b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html.ini new file mode 100644 index 000000000000..23a8566a5738 --- /dev/null +++ b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html.ini @@ -0,0 +1,20 @@ +[open-features-tokenization-noopener.html] + type: testharness + [tokenization should skip window features separators before `name`] + expected: FAIL + + [feature `name` should be converted to ASCII lowercase] + expected: FAIL + + [after `name`, tokenization should skip window features separators that are not "=" or ","] + expected: FAIL + + [Tokenizing should ignore window feature separators except "," after initial "=" and before value] + expected: FAIL + + [Tokenizing should read characters until first window feature separator as `value`] + expected: FAIL + + ["noopener" should be based on name (key), not value] + expected: FAIL + diff --git a/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html.ini b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html.ini new file mode 100644 index 000000000000..228aabd78f9b --- /dev/null +++ b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html.ini @@ -0,0 +1,8 @@ +[open-features-tokenization-screenx-screeny.html] + type: testharness + ["screenx==141" should set left position of opened window] + expected: FAIL + + ["screeny==142" should set top position of opened window] + expected: FAIL + diff --git a/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html.ini b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html.ini new file mode 100644 index 000000000000..472026c96574 --- /dev/null +++ b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html.ini @@ -0,0 +1,11 @@ +[open-features-tokenization-top-left.html] + type: testharness + ["left==141" should set left position of opened window] + expected: FAIL + + ["top==142" should set top position of opened window] + expected: FAIL + + ["top=152==left=152" should set top and left position of opened window] + expected: FAIL + diff --git a/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-width-height.html.ini b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-width-height.html.ini new file mode 100644 index 000000000000..923c8954333e --- /dev/null +++ b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-width-height.html.ini @@ -0,0 +1,14 @@ +[open-features-tokenization-width-height.html] + type: testharness + ["width==401" should set width of opened window] + expected: FAIL + + ["height==402" should set height of opened window] + expected: FAIL + + ["height==402 width = 401" should set height and width of opened window] + expected: FAIL + + [",height=402,,width==401" should set height and width of opened window] + expected: FAIL + diff --git a/testing/web-platform/meta/html/browsers/windows/browsing-context-names/browsing-context-choose-self-2.html.ini b/testing/web-platform/meta/html/browsers/windows/browsing-context-names/browsing-context-choose-self-2.html.ini deleted file mode 100644 index 7a497cd7af06..000000000000 --- a/testing/web-platform/meta/html/browsers/windows/browsing-context-names/browsing-context-choose-self-2.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[browsing-context-choose-self-2.html] - type: testharness - expected: TIMEOUT - [The current browsing context must be chosen if the given name is empty string] - expected: NOTRUN - diff --git a/testing/web-platform/meta/html/browsers/windows/browsing-context-names/browsing-context-default-name.html.ini b/testing/web-platform/meta/html/browsers/windows/browsing-context-names/browsing-context-default-name.html.ini deleted file mode 100644 index 25685b5ff730..000000000000 --- a/testing/web-platform/meta/html/browsers/windows/browsing-context-names/browsing-context-default-name.html.ini +++ /dev/null @@ -1,8 +0,0 @@ -[browsing-context-default-name.html] - type: testharness - [A browsing context has no default name] - expected: FAIL - - [A browsing context has an empty-string default name] - expected: FAIL - diff --git a/testing/web-platform/meta/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-003.html.ini b/testing/web-platform/meta/html/browsers/windows/browsing-context-names/choose-_parent-003.html.ini similarity index 72% rename from testing/web-platform/meta/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-003.html.ini rename to testing/web-platform/meta/html/browsers/windows/browsing-context-names/choose-_parent-003.html.ini index fef84dcbe1a1..5bbfee5cb553 100644 --- a/testing/web-platform/meta/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-003.html.ini +++ b/testing/web-platform/meta/html/browsers/windows/browsing-context-names/choose-_parent-003.html.ini @@ -1,4 +1,4 @@ -[browsing-context-choose-parent-003.html] +[choose-_parent-003.html] type: testharness expected: TIMEOUT [_parent should reuse window.parent context] diff --git a/testing/web-platform/meta/html/dom/interfaces.html.ini b/testing/web-platform/meta/html/dom/interfaces.html.ini index 601958538c03..22601050e1c5 100644 --- a/testing/web-platform/meta/html/dom/interfaces.html.ini +++ b/testing/web-platform/meta/html/dom/interfaces.html.ini @@ -2632,9 +2632,6 @@ [HTMLInputElement interface: createInput("button") must inherit property "labels" with the proper type (48)] expected: FAIL - [TrackEvent interface: new TrackEvent("addtrack", {track:document.createElement("track").track}) must inherit property "track" with the proper type (0)] - expected: FAIL - [Document interface: operation open(USVString,DOMString,DOMString)] expected: FAIL @@ -2932,12 +2929,6 @@ [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "imageSmoothingQuality" with the proper type (14)] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "strokeStyle" with the proper type (15)] - expected: FAIL - - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "fillStyle" with the proper type (16)] - expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "resetClip" with the proper type (35)] expected: FAIL @@ -3502,3 +3493,81 @@ [Element interface: document.createElement("noscript") must inherit property "assignedSlot" with the proper type (48)] expected: FAIL + [Document interface: iframe.contentDocument must inherit property "styleSheets" with the proper type (29)] + expected: FAIL + + [Document interface: new Document() must inherit property "styleSheets" with the proper type (29)] + expected: FAIL + + [Document interface: document.implementation.createDocument(null, "", null) must inherit property "styleSheets" with the proper type (29)] + expected: FAIL + + [HTMLLinkElement interface: attribute as] + expected: FAIL + + [HTMLLinkElement interface: document.createElement("link") must inherit property "as" with the proper type (3)] + expected: FAIL + + [HTMLLinkElement interface: document.createElement("link") must inherit property "nonce" with the proper type (6)] + expected: FAIL + + [HTMLBodyElement interface: attribute onmessageerror] + expected: FAIL + + [HTMLBodyElement interface: attribute onrejectionhandled] + expected: FAIL + + [HTMLBodyElement interface: attribute onunhandledrejection] + expected: FAIL + + [HTMLBodyElement interface: document.createElement("body") must inherit property "onmessageerror" with the proper type (12)] + expected: FAIL + + [HTMLBodyElement interface: document.createElement("body") must inherit property "onrejectionhandled" with the proper type (18)] + expected: FAIL + + [HTMLBodyElement interface: document.createElement("body") must inherit property "onunhandledrejection" with the proper type (20)] + expected: FAIL + + [Window interface: attribute onmessageerror] + expected: FAIL + + [Window interface: attribute onrejectionhandled] + expected: FAIL + + [Window interface: attribute onunhandledrejection] + expected: FAIL + + [Window interface: window must inherit property "onmessageerror" with the proper type (105)] + expected: FAIL + + [Window interface: window must inherit property "onrejectionhandled" with the proper type (111)] + expected: FAIL + + [Window interface: window must inherit property "onunhandledrejection" with the proper type (113)] + expected: FAIL + + [MessagePort interface: attribute onmessageerror] + expected: FAIL + + [BroadcastChannel interface: attribute onmessageerror] + expected: FAIL + + [HTMLFrameSetElement interface: attribute onmessageerror] + expected: FAIL + + [HTMLFrameSetElement interface: attribute onrejectionhandled] + expected: FAIL + + [HTMLFrameSetElement interface: attribute onunhandledrejection] + expected: FAIL + + [HTMLFrameSetElement interface: document.createElement("frameset") must inherit property "onmessageerror" with the proper type (8)] + expected: FAIL + + [HTMLFrameSetElement interface: document.createElement("frameset") must inherit property "onrejectionhandled" with the proper type (14)] + expected: FAIL + + [HTMLFrameSetElement interface: document.createElement("frameset") must inherit property "onunhandledrejection" with the proper type (16)] + expected: FAIL + diff --git a/testing/web-platform/meta/html/dom/interfaces.worker.js.ini b/testing/web-platform/meta/html/dom/interfaces.worker.js.ini index 6b61dfbc82e3..a05930a04898 100644 --- a/testing/web-platform/meta/html/dom/interfaces.worker.js.ini +++ b/testing/web-platform/meta/html/dom/interfaces.worker.js.ini @@ -75,3 +75,6 @@ [WorkerGlobalScope interface: self must inherit property "onlanguagechange" with the proper type (5)] expected: FAIL + [Test driver] + expected: FAIL + diff --git a/testing/web-platform/meta/html/dom/reflection-metadata.html.ini b/testing/web-platform/meta/html/dom/reflection-metadata.html.ini index 45758ca903f9..3124cbb602f9 100644 --- a/testing/web-platform/meta/html/dom/reflection-metadata.html.ini +++ b/testing/web-platform/meta/html/dom/reflection-metadata.html.ini @@ -132,3 +132,579 @@ [link.nonce: IDL set to object "test-valueOf"] expected: FAIL + [link.as: typeof IDL attribute] + expected: FAIL + + [link.as: IDL get with DOM attribute unset] + expected: FAIL + + [link.as: setAttribute() to ""] + expected: FAIL + + [link.as: setAttribute() to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo "] + expected: FAIL + + [link.as: setAttribute() to undefined] + expected: FAIL + + [link.as: setAttribute() to 7] + expected: FAIL + + [link.as: setAttribute() to 1.5] + expected: FAIL + + [link.as: setAttribute() to true] + expected: FAIL + + [link.as: setAttribute() to false] + expected: FAIL + + [link.as: setAttribute() to object "[object Object\]"] + expected: FAIL + + [link.as: setAttribute() to NaN] + expected: FAIL + + [link.as: setAttribute() to Infinity] + expected: FAIL + + [link.as: setAttribute() to -Infinity] + expected: FAIL + + [link.as: setAttribute() to "\\0"] + expected: FAIL + + [link.as: setAttribute() to null] + expected: FAIL + + [link.as: setAttribute() to object "test-toString"] + expected: FAIL + + [link.as: setAttribute() to object "test-valueOf"] + expected: FAIL + + [link.as: setAttribute() to "audio"] + expected: FAIL + + [link.as: setAttribute() to "xaudio"] + expected: FAIL + + [link.as: setAttribute() to "audio\\0"] + expected: FAIL + + [link.as: setAttribute() to "udio"] + expected: FAIL + + [link.as: setAttribute() to "AUDIO"] + expected: FAIL + + [link.as: setAttribute() to "document"] + expected: FAIL + + [link.as: setAttribute() to "xdocument"] + expected: FAIL + + [link.as: setAttribute() to "document\\0"] + expected: FAIL + + [link.as: setAttribute() to "ocument"] + expected: FAIL + + [link.as: setAttribute() to "DOCUMENT"] + expected: FAIL + + [link.as: setAttribute() to "embed"] + expected: FAIL + + [link.as: setAttribute() to "xembed"] + expected: FAIL + + [link.as: setAttribute() to "embed\\0"] + expected: FAIL + + [link.as: setAttribute() to "mbed"] + expected: FAIL + + [link.as: setAttribute() to "EMBED"] + expected: FAIL + + [link.as: setAttribute() to "font"] + expected: FAIL + + [link.as: setAttribute() to "xfont"] + expected: FAIL + + [link.as: setAttribute() to "font\\0"] + expected: FAIL + + [link.as: setAttribute() to "ont"] + expected: FAIL + + [link.as: setAttribute() to "FONT"] + expected: FAIL + + [link.as: setAttribute() to "image"] + expected: FAIL + + [link.as: setAttribute() to "ximage"] + expected: FAIL + + [link.as: setAttribute() to "image\\0"] + expected: FAIL + + [link.as: setAttribute() to "mage"] + expected: FAIL + + [link.as: setAttribute() to "IMAGE"] + expected: FAIL + + [link.as: setAttribute() to "manifest"] + expected: FAIL + + [link.as: setAttribute() to "xmanifest"] + expected: FAIL + + [link.as: setAttribute() to "manifest\\0"] + expected: FAIL + + [link.as: setAttribute() to "anifest"] + expected: FAIL + + [link.as: setAttribute() to "MANIFEST"] + expected: FAIL + + [link.as: setAttribute() to "object"] + expected: FAIL + + [link.as: setAttribute() to "xobject"] + expected: FAIL + + [link.as: setAttribute() to "object\\0"] + expected: FAIL + + [link.as: setAttribute() to "bject"] + expected: FAIL + + [link.as: setAttribute() to "OBJECT"] + expected: FAIL + + [link.as: setAttribute() to "report"] + expected: FAIL + + [link.as: setAttribute() to "xreport"] + expected: FAIL + + [link.as: setAttribute() to "report\\0"] + expected: FAIL + + [link.as: setAttribute() to "eport"] + expected: FAIL + + [link.as: setAttribute() to "REPORT"] + expected: FAIL + + [link.as: setAttribute() to "script"] + expected: FAIL + + [link.as: setAttribute() to "xscript"] + expected: FAIL + + [link.as: setAttribute() to "script\\0"] + expected: FAIL + + [link.as: setAttribute() to "cript"] + expected: FAIL + + [link.as: setAttribute() to "SCRIPT"] + expected: FAIL + + [link.as: setAttribute() to "serviceworker"] + expected: FAIL + + [link.as: setAttribute() to "xserviceworker"] + expected: FAIL + + [link.as: setAttribute() to "serviceworker\\0"] + expected: FAIL + + [link.as: setAttribute() to "erviceworker"] + expected: FAIL + + [link.as: setAttribute() to "SERVICEWORKER"] + expected: FAIL + + [link.as: setAttribute() to "sharedworker"] + expected: FAIL + + [link.as: setAttribute() to "xsharedworker"] + expected: FAIL + + [link.as: setAttribute() to "sharedworker\\0"] + expected: FAIL + + [link.as: setAttribute() to "haredworker"] + expected: FAIL + + [link.as: setAttribute() to "SHAREDWORKER"] + expected: FAIL + + [link.as: setAttribute() to "style"] + expected: FAIL + + [link.as: setAttribute() to "xstyle"] + expected: FAIL + + [link.as: setAttribute() to "style\\0"] + expected: FAIL + + [link.as: setAttribute() to "tyle"] + expected: FAIL + + [link.as: setAttribute() to "STYLE"] + expected: FAIL + + [link.as: setAttribute() to "track"] + expected: FAIL + + [link.as: setAttribute() to "xtrack"] + expected: FAIL + + [link.as: setAttribute() to "track\\0"] + expected: FAIL + + [link.as: setAttribute() to "rack"] + expected: FAIL + + [link.as: setAttribute() to "TRACK"] + expected: FAIL + + [link.as: setAttribute() to "video"] + expected: FAIL + + [link.as: setAttribute() to "xvideo"] + expected: FAIL + + [link.as: setAttribute() to "video\\0"] + expected: FAIL + + [link.as: setAttribute() to "ideo"] + expected: FAIL + + [link.as: setAttribute() to "VIDEO"] + expected: FAIL + + [link.as: setAttribute() to "worker"] + expected: FAIL + + [link.as: setAttribute() to "xworker"] + expected: FAIL + + [link.as: setAttribute() to "worker\\0"] + expected: FAIL + + [link.as: setAttribute() to "orker"] + expected: FAIL + + [link.as: setAttribute() to "WORKER"] + expected: FAIL + + [link.as: setAttribute() to "xslt"] + expected: FAIL + + [link.as: setAttribute() to "xxslt"] + expected: FAIL + + [link.as: setAttribute() to "xslt\\0"] + expected: FAIL + + [link.as: setAttribute() to "slt"] + expected: FAIL + + [link.as: setAttribute() to "XSLT"] + expected: FAIL + + [link.as: IDL set to ""] + expected: FAIL + + [link.as: IDL set to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo "] + expected: FAIL + + [link.as: IDL set to undefined] + expected: FAIL + + [link.as: IDL set to 7] + expected: FAIL + + [link.as: IDL set to 1.5] + expected: FAIL + + [link.as: IDL set to true] + expected: FAIL + + [link.as: IDL set to false] + expected: FAIL + + [link.as: IDL set to object "[object Object\]"] + expected: FAIL + + [link.as: IDL set to NaN] + expected: FAIL + + [link.as: IDL set to Infinity] + expected: FAIL + + [link.as: IDL set to -Infinity] + expected: FAIL + + [link.as: IDL set to "\\0"] + expected: FAIL + + [link.as: IDL set to null] + expected: FAIL + + [link.as: IDL set to object "test-toString"] + expected: FAIL + + [link.as: IDL set to object "test-valueOf"] + expected: FAIL + + [link.as: IDL set to "audio"] + expected: FAIL + + [link.as: IDL set to "xaudio"] + expected: FAIL + + [link.as: IDL set to "audio\\0"] + expected: FAIL + + [link.as: IDL set to "udio"] + expected: FAIL + + [link.as: IDL set to "AUDIO"] + expected: FAIL + + [link.as: IDL set to "document"] + expected: FAIL + + [link.as: IDL set to "xdocument"] + expected: FAIL + + [link.as: IDL set to "document\\0"] + expected: FAIL + + [link.as: IDL set to "ocument"] + expected: FAIL + + [link.as: IDL set to "DOCUMENT"] + expected: FAIL + + [link.as: IDL set to "embed"] + expected: FAIL + + [link.as: IDL set to "xembed"] + expected: FAIL + + [link.as: IDL set to "embed\\0"] + expected: FAIL + + [link.as: IDL set to "mbed"] + expected: FAIL + + [link.as: IDL set to "EMBED"] + expected: FAIL + + [link.as: IDL set to "font"] + expected: FAIL + + [link.as: IDL set to "xfont"] + expected: FAIL + + [link.as: IDL set to "font\\0"] + expected: FAIL + + [link.as: IDL set to "ont"] + expected: FAIL + + [link.as: IDL set to "FONT"] + expected: FAIL + + [link.as: IDL set to "image"] + expected: FAIL + + [link.as: IDL set to "ximage"] + expected: FAIL + + [link.as: IDL set to "image\\0"] + expected: FAIL + + [link.as: IDL set to "mage"] + expected: FAIL + + [link.as: IDL set to "IMAGE"] + expected: FAIL + + [link.as: IDL set to "manifest"] + expected: FAIL + + [link.as: IDL set to "xmanifest"] + expected: FAIL + + [link.as: IDL set to "manifest\\0"] + expected: FAIL + + [link.as: IDL set to "anifest"] + expected: FAIL + + [link.as: IDL set to "MANIFEST"] + expected: FAIL + + [link.as: IDL set to "object"] + expected: FAIL + + [link.as: IDL set to "xobject"] + expected: FAIL + + [link.as: IDL set to "object\\0"] + expected: FAIL + + [link.as: IDL set to "bject"] + expected: FAIL + + [link.as: IDL set to "OBJECT"] + expected: FAIL + + [link.as: IDL set to "report"] + expected: FAIL + + [link.as: IDL set to "xreport"] + expected: FAIL + + [link.as: IDL set to "report\\0"] + expected: FAIL + + [link.as: IDL set to "eport"] + expected: FAIL + + [link.as: IDL set to "REPORT"] + expected: FAIL + + [link.as: IDL set to "script"] + expected: FAIL + + [link.as: IDL set to "xscript"] + expected: FAIL + + [link.as: IDL set to "script\\0"] + expected: FAIL + + [link.as: IDL set to "cript"] + expected: FAIL + + [link.as: IDL set to "SCRIPT"] + expected: FAIL + + [link.as: IDL set to "serviceworker"] + expected: FAIL + + [link.as: IDL set to "xserviceworker"] + expected: FAIL + + [link.as: IDL set to "serviceworker\\0"] + expected: FAIL + + [link.as: IDL set to "erviceworker"] + expected: FAIL + + [link.as: IDL set to "SERVICEWORKER"] + expected: FAIL + + [link.as: IDL set to "sharedworker"] + expected: FAIL + + [link.as: IDL set to "xsharedworker"] + expected: FAIL + + [link.as: IDL set to "sharedworker\\0"] + expected: FAIL + + [link.as: IDL set to "haredworker"] + expected: FAIL + + [link.as: IDL set to "SHAREDWORKER"] + expected: FAIL + + [link.as: IDL set to "style"] + expected: FAIL + + [link.as: IDL set to "xstyle"] + expected: FAIL + + [link.as: IDL set to "style\\0"] + expected: FAIL + + [link.as: IDL set to "tyle"] + expected: FAIL + + [link.as: IDL set to "STYLE"] + expected: FAIL + + [link.as: IDL set to "track"] + expected: FAIL + + [link.as: IDL set to "xtrack"] + expected: FAIL + + [link.as: IDL set to "track\\0"] + expected: FAIL + + [link.as: IDL set to "rack"] + expected: FAIL + + [link.as: IDL set to "TRACK"] + expected: FAIL + + [link.as: IDL set to "video"] + expected: FAIL + + [link.as: IDL set to "xvideo"] + expected: FAIL + + [link.as: IDL set to "video\\0"] + expected: FAIL + + [link.as: IDL set to "ideo"] + expected: FAIL + + [link.as: IDL set to "VIDEO"] + expected: FAIL + + [link.as: IDL set to "worker"] + expected: FAIL + + [link.as: IDL set to "xworker"] + expected: FAIL + + [link.as: IDL set to "worker\\0"] + expected: FAIL + + [link.as: IDL set to "orker"] + expected: FAIL + + [link.as: IDL set to "WORKER"] + expected: FAIL + + [link.as: IDL set to "xslt"] + expected: FAIL + + [link.as: IDL set to "xxslt"] + expected: FAIL + + [link.as: IDL set to "xslt\\0"] + expected: FAIL + + [link.as: IDL set to "slt"] + expected: FAIL + + [link.as: IDL set to "XSLT"] + expected: FAIL + diff --git a/testing/web-platform/meta/html/dom/reflection-tabular.html.ini b/testing/web-platform/meta/html/dom/reflection-tabular.html.ini index f2ab82d3d7e6..999c966f5cb8 100644 --- a/testing/web-platform/meta/html/dom/reflection-tabular.html.ini +++ b/testing/web-platform/meta/html/dom/reflection-tabular.html.ini @@ -405,81 +405,87 @@ [col.span: IDL set to 2147483647] expected: FAIL - [td.colSpan: setAttribute() to 0] - expected: FAIL - [td.colSpan: setAttribute() to 2147483647] expected: FAIL - [td.colSpan: setAttribute() to "-0"] - expected: FAIL - - [td.colSpan: setAttribute() to "0"] - expected: FAIL - - [td.colSpan: IDL set to 0] - expected: FAIL - [td.colSpan: IDL set to 2147483647] expected: FAIL - [td.colSpan: IDL set to "-0"] - expected: FAIL - [td.colSpan: IDL set to 2147483648] expected: FAIL [td.colSpan: IDL set to 4294967295] expected: FAIL - [td.rowSpan: setAttribute() to 2147483647] - expected: FAIL - - [td.rowSpan: IDL set to 2147483647] - expected: FAIL - [td.rowSpan: IDL set to 2147483648] expected: FAIL [td.rowSpan: IDL set to 4294967295] expected: FAIL - [th.colSpan: setAttribute() to 0] - expected: FAIL - [th.colSpan: setAttribute() to 2147483647] expected: FAIL - [th.colSpan: setAttribute() to "-0"] - expected: FAIL - - [th.colSpan: setAttribute() to "0"] - expected: FAIL - - [th.colSpan: IDL set to 0] - expected: FAIL - [th.colSpan: IDL set to 2147483647] expected: FAIL - [th.colSpan: IDL set to "-0"] - expected: FAIL - [th.colSpan: IDL set to 2147483648] expected: FAIL [th.colSpan: IDL set to 4294967295] expected: FAIL - [th.rowSpan: setAttribute() to 2147483647] - expected: FAIL - - [th.rowSpan: IDL set to 2147483647] - expected: FAIL - [th.rowSpan: IDL set to 2147483648] expected: FAIL [th.rowSpan: IDL set to 4294967295] expected: FAIL + [td.colSpan: setAttribute() to 2147483648] + expected: FAIL + + [td.colSpan: setAttribute() to 4294967295] + expected: FAIL + + [td.colSpan: setAttribute() to 4294967296] + expected: FAIL + + [td.colSpan: setAttribute() to 1001] + expected: FAIL + + [td.colSpan: IDL set to 1001] + expected: FAIL + + [td.rowSpan: setAttribute() to 2147483648] + expected: FAIL + + [td.rowSpan: setAttribute() to 4294967295] + expected: FAIL + + [td.rowSpan: setAttribute() to 4294967296] + expected: FAIL + + [th.colSpan: setAttribute() to 2147483648] + expected: FAIL + + [th.colSpan: setAttribute() to 4294967295] + expected: FAIL + + [th.colSpan: setAttribute() to 4294967296] + expected: FAIL + + [th.colSpan: setAttribute() to 1001] + expected: FAIL + + [th.colSpan: IDL set to 1001] + expected: FAIL + + [th.rowSpan: setAttribute() to 2147483648] + expected: FAIL + + [th.rowSpan: setAttribute() to 4294967295] + expected: FAIL + + [th.rowSpan: setAttribute() to 4294967296] + expected: FAIL + diff --git a/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-007.html.ini b/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-007.html.ini new file mode 100644 index 000000000000..3c7b5be65258 --- /dev/null +++ b/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-007.html.ini @@ -0,0 +1,5 @@ +[spelling-markers-007.html] + type: reftest + expected: + if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL diff --git a/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-008.html.ini b/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-008.html.ini new file mode 100644 index 000000000000..908d59f1e156 --- /dev/null +++ b/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-008.html.ini @@ -0,0 +1,5 @@ +[spelling-markers-008.html] + type: reftest + expected: + if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL diff --git a/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-009.html.ini b/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-009.html.ini new file mode 100644 index 000000000000..15605a075d4e --- /dev/null +++ b/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-009.html.ini @@ -0,0 +1,3 @@ +[spelling-markers-009.html] + type: reftest + expected: FAIL diff --git a/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-010.html.ini b/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-010.html.ini new file mode 100644 index 000000000000..0fcd54ca05bc --- /dev/null +++ b/testing/web-platform/meta/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-010.html.ini @@ -0,0 +1,3 @@ +[spelling-markers-010.html] + type: reftest + expected: FAIL diff --git a/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html.ini b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html.ini new file mode 100644 index 000000000000..31d700f791c9 --- /dev/null +++ b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html.ini @@ -0,0 +1,5 @@ +[broadcastchannel-success-and-failure.html] + type: testharness + [SharedArrayBuffer cannot cross agent clusters, BroadcastChannel edition] + expected: FAIL + diff --git a/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html.ini b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html.ini new file mode 100644 index 000000000000..883c4613fb36 --- /dev/null +++ b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html.ini @@ -0,0 +1,5 @@ +[broadcastchannel-success.html] + type: testharness + [Structured cloning of SharedArrayBuffers: BroadcastChannel within the same agent cluster] + expected: FAIL + diff --git a/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.html.ini b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.html.ini new file mode 100644 index 000000000000..95dd0b529cc2 --- /dev/null +++ b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.html.ini @@ -0,0 +1,14 @@ +[serialization-via-history.html] + type: testharness + [history.pushState(): simple case] + expected: FAIL + + [history.pushState(): is interleaved correctly] + expected: FAIL + + [history.replaceState(): simple case] + expected: FAIL + + [history.replaceState(): is interleaved correctly] + expected: FAIL + diff --git a/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js.ini b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js.ini new file mode 100644 index 000000000000..65ffac4f541b --- /dev/null +++ b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js.ini @@ -0,0 +1,12 @@ +[serialization-via-idb.any.worker.html] + type: testharness + expected: ERROR + +[serialization-via-idb.any.html] + type: testharness + [SharedArrayBuffer cloning via IndexedDB: basic case] + expected: FAIL + + [SharedArrayBuffer cloning via the IndexedDB: is interleaved correctly] + expected: FAIL + diff --git a/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js.ini b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js.ini new file mode 100644 index 000000000000..1d2b05db2834 --- /dev/null +++ b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js.ini @@ -0,0 +1,17 @@ +[serialization-via-notifications-api.any.worker.html] + type: testharness + [SharedArrayBuffer cloning via the Notifications API's data member: basic case] + expected: FAIL + + [SharedArrayBuffer cloning via the Notifications API's data member: is interleaved correctly] + expected: FAIL + + +[serialization-via-notifications-api.any.html] + type: testharness + [SharedArrayBuffer cloning via the Notifications API's data member: basic case] + expected: FAIL + + [SharedArrayBuffer cloning via the Notifications API's data member: is interleaved correctly] + expected: FAIL + diff --git a/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.html.ini b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.html.ini new file mode 100644 index 000000000000..6fc82b357cc5 --- /dev/null +++ b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.html.ini @@ -0,0 +1,5 @@ +[window-messagechannel-success.html] + type: testharness + [postMessaging to a dedicated worker via MessageChannel allows them to see each others' modifications] + expected: FAIL + diff --git a/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html.ini b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html.ini new file mode 100644 index 000000000000..e2543a01fb35 --- /dev/null +++ b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html.ini @@ -0,0 +1,5 @@ +[window-serviceworker-failure.https.html] + type: testharness + [SharedArrayBuffer cannot cross agent clusters, service worker edition] + expected: FAIL + diff --git a/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.html.ini b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.html.ini new file mode 100644 index 000000000000..2b9070f5bb7c --- /dev/null +++ b/testing/web-platform/meta/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.html.ini @@ -0,0 +1,5 @@ +[window-sharedworker-failure.html] + type: testharness + [SharedArrayBuffer cannot cross agent clusters, shared worker edition] + expected: FAIL + diff --git a/testing/web-platform/meta/html/semantics/embedded-content/the-canvas-element/imagedata.html.ini b/testing/web-platform/meta/html/semantics/embedded-content/the-canvas-element/imagedata.html.ini new file mode 100644 index 000000000000..4e6236515ce2 --- /dev/null +++ b/testing/web-platform/meta/html/semantics/embedded-content/the-canvas-element/imagedata.html.ini @@ -0,0 +1,5 @@ +[imagedata.html] + type: testharness + [ImageData(buffer, w, opt h), Uint8ClampedArray argument type check] + expected: FAIL + diff --git a/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/document-adopt-base-url.html.ini b/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/document-adopt-base-url.html.ini new file mode 100644 index 000000000000..55ced09ad2b8 --- /dev/null +++ b/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/document-adopt-base-url.html.ini @@ -0,0 +1,3 @@ +[document-adopt-base-url.html] + type: reftest + expected: FAIL diff --git a/testing/web-platform/meta/html/semantics/forms/form-control-infrastructure/form_attribute.html.ini b/testing/web-platform/meta/html/semantics/forms/form-control-infrastructure/form_attribute.html.ini new file mode 100644 index 000000000000..c6cd72149400 --- /dev/null +++ b/testing/web-platform/meta/html/semantics/forms/form-control-infrastructure/form_attribute.html.ini @@ -0,0 +1,23 @@ +[form_attribute.html] + type: testharness + [[BUTTON\] A control that is not in the document but has the form attribute set is associated with the nearest ancestor form if one exists] + expected: FAIL + + [[FIELDSET\] A control that is not in the document but has the form attribute set is associated with the nearest ancestor form if one exists] + expected: FAIL + + [[INPUT\] A control that is not in the document but has the form attribute set is associated with the nearest ancestor form if one exists] + expected: FAIL + + [[OBJECT\] A control that is not in the document but has the form attribute set is associated with the nearest ancestor form if one exists] + expected: FAIL + + [[OUTPUT\] A control that is not in the document but has the form attribute set is associated with the nearest ancestor form if one exists] + expected: FAIL + + [[SELECT\] A control that is not in the document but has the form attribute set is associated with the nearest ancestor form if one exists] + expected: FAIL + + [[TEXTAREA\] A control that is not in the document but has the form attribute set is associated with the nearest ancestor form if one exists] + expected: FAIL + diff --git a/testing/web-platform/meta/html/semantics/forms/form-control-infrastructure/form_owner_and_table_2.html.ini b/testing/web-platform/meta/html/semantics/forms/form-control-infrastructure/form_owner_and_table_2.html.ini new file mode 100644 index 000000000000..cd6eabbdaa35 --- /dev/null +++ b/testing/web-platform/meta/html/semantics/forms/form-control-infrastructure/form_owner_and_table_2.html.ini @@ -0,0 +1,5 @@ +[form_owner_and_table_2.html] + type: testharness + [Controls nested in tables are not associated with form element inside the table if the form had been removed by script before the controls were inserted by the parser] + expected: FAIL + diff --git a/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/centering.html.ini b/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/centering.html.ini new file mode 100644 index 000000000000..8b03cd72f88b --- /dev/null +++ b/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/centering.html.ini @@ -0,0 +1,44 @@ +[centering.html] + type: testharness + [horizontal-tb: tall viewport] + expected: FAIL + + [horizontal-tb: wide viewport] + expected: FAIL + + [horizontal-tb: square viewport] + expected: FAIL + + [horizontal-tb: dialog and viewport match] + expected: FAIL + + [horizontal-tb: dialog bigger than viewport] + expected: FAIL + + [vertical-rl: tall viewport] + expected: FAIL + + [vertical-lr: tall viewport] + expected: FAIL + + [vertical-lr: dialog bigger than viewport] + expected: FAIL + + [vertical-rl (dialog horizontal-tb): tall viewport] + expected: FAIL + + [vertical-lr (dialog horizontal-tb): tall viewport] + expected: FAIL + + [horizontal-tb (container vertical-rl): tall viewport] + expected: FAIL + + [vertical-rl (container horizontal-tb): tall viewport] + expected: FAIL + + [horizontal-tb (container vertical-rl) (dialog horizontal-tb): tall viewport] + expected: FAIL + + [vertical-rl (container horizontal-tb) (dialog vertical-rl): tall viewport] + expected: FAIL + diff --git a/testing/web-platform/meta/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-support.htm.ini b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html.ini similarity index 67% rename from testing/web-platform/meta/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-support.htm.ini rename to testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html.ini index f16d35a968d3..4c467b1a3776 100644 --- a/testing/web-platform/meta/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-support.htm.ini +++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html.ini @@ -1,22 +1,20 @@ -[xhtml-mathml-dtd-entity-support.htm] +[instantiation-error-1.html] type: testharness + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1364128 expected: if not debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): TIMEOUT + if debug and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): CRASH if not debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): TIMEOUT if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): TIMEOUT + if not debug and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): CRASH if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT if debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): TIMEOUT if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): CRASH - if not debug and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT + if not debug and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): CRASH + if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): CRASH + if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): CRASH + if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): CRASH if debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): TIMEOUT if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT - if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if debug and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): TIMEOUT + if debug and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): CRASH diff --git a/testing/web-platform/meta/html/semantics/tabular-data/processing-model-1/span-limits.html.ini b/testing/web-platform/meta/html/semantics/tabular-data/processing-model-1/span-limits.html.ini new file mode 100644 index 000000000000..79dcccca4fa7 --- /dev/null +++ b/testing/web-platform/meta/html/semantics/tabular-data/processing-model-1/span-limits.html.ini @@ -0,0 +1,12 @@ +[span-limits.html] + type: testharness + [rowspan of 65534 must work] + expected: + if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + + [rowspan of 65535 must be treated as 65534] + expected: + if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + diff --git a/testing/web-platform/meta/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html.ini b/testing/web-platform/meta/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html.ini new file mode 100644 index 000000000000..d2c5e8db95a8 --- /dev/null +++ b/testing/web-platform/meta/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html.ini @@ -0,0 +1,5 @@ +[canblock-sharedworker.html] + type: testharness + [[[CanBlock\]\] in a SharedWorkerGlobalScope] + expected: FAIL + diff --git a/testing/web-platform/meta/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.worker.js.ini b/testing/web-platform/meta/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.worker.js.ini deleted file mode 100644 index a51e6f9a3fe3..000000000000 --- a/testing/web-platform/meta/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[NavigatorID.worker.html] - type: testharness - [userAgent value] - expected: FAIL - diff --git a/testing/web-platform/meta/keyboard-lock/idlharness.https.html.ini b/testing/web-platform/meta/keyboard-lock/idlharness.https.html.ini new file mode 100644 index 000000000000..e3511b087057 --- /dev/null +++ b/testing/web-platform/meta/keyboard-lock/idlharness.https.html.ini @@ -0,0 +1,17 @@ +[idlharness.https.html] + type: testharness + [Navigator interface: operation requestKeyboardLock(sequence)] + expected: FAIL + + [Navigator interface: operation cancelKeyboardLock()] + expected: FAIL + + [Navigator interface: navigator must inherit property "requestKeyboardLock" with the proper type (0)] + expected: FAIL + + [Navigator interface: calling requestKeyboardLock(sequence) on navigator with too few arguments must throw TypeError] + expected: FAIL + + [Navigator interface: navigator must inherit property "cancelKeyboardLock" with the proper type (1)] + expected: FAIL + diff --git a/testing/web-platform/meta/keyboard-lock/navigator-cancelKeyboardLock.https.html.ini b/testing/web-platform/meta/keyboard-lock/navigator-cancelKeyboardLock.https.html.ini new file mode 100644 index 000000000000..11c473ca08f1 --- /dev/null +++ b/testing/web-platform/meta/keyboard-lock/navigator-cancelKeyboardLock.https.html.ini @@ -0,0 +1,5 @@ +[navigator-cancelKeyboardLock.https.html] + type: testharness + [Keyboard Lock cancelKeyboardLock] + expected: FAIL + diff --git a/testing/web-platform/meta/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html.ini b/testing/web-platform/meta/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html.ini new file mode 100644 index 000000000000..2a71a3f87606 --- /dev/null +++ b/testing/web-platform/meta/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html.ini @@ -0,0 +1,5 @@ +[navigator-requestKeyboardLock-two-parallel-requests.https.html] + type: testharness + [Keyboard Lock requestKeyboardLock twice in parallel] + expected: FAIL + diff --git a/testing/web-platform/meta/keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html.ini b/testing/web-platform/meta/keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html.ini new file mode 100644 index 000000000000..26735b8e8962 --- /dev/null +++ b/testing/web-platform/meta/keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html.ini @@ -0,0 +1,5 @@ +[navigator-requestKeyboardLock-two-sequential-requests.https.html] + type: testharness + [Keyboard Lock requestKeyboardLock twice sequentially] + expected: FAIL + diff --git a/testing/web-platform/meta/keyboard-lock/navigator-requestKeyboardLock.https.html.ini b/testing/web-platform/meta/keyboard-lock/navigator-requestKeyboardLock.https.html.ini new file mode 100644 index 000000000000..63757d6d86d8 --- /dev/null +++ b/testing/web-platform/meta/keyboard-lock/navigator-requestKeyboardLock.https.html.ini @@ -0,0 +1,5 @@ +[navigator-requestKeyboardLock.https.html] + type: testharness + [Keyboard Lock requestKeyboardLock] + expected: FAIL + diff --git a/testing/web-platform/meta/magnetometer/Magnetometer.https.html.ini b/testing/web-platform/meta/magnetometer/Magnetometer.https.html.ini new file mode 100644 index 000000000000..ea346b59249f --- /dev/null +++ b/testing/web-platform/meta/magnetometer/Magnetometer.https.html.ini @@ -0,0 +1,5 @@ +[Magnetometer.https.html] + type: testharness + [Magnetometer Test] + expected: FAIL + diff --git a/testing/web-platform/meta/magnetometer/Magnetometer_insecure_context.html.ini b/testing/web-platform/meta/magnetometer/Magnetometer_insecure_context.html.ini new file mode 100644 index 000000000000..e9094a53309a --- /dev/null +++ b/testing/web-platform/meta/magnetometer/Magnetometer_insecure_context.html.ini @@ -0,0 +1,5 @@ +[Magnetometer_insecure_context.html] + type: testharness + [Magnetometer Test: insecure context] + expected: FAIL + diff --git a/testing/web-platform/meta/magnetometer/idlharness.https.html.ini b/testing/web-platform/meta/magnetometer/idlharness.https.html.ini index 0b2798253888..ecc8edc88f0d 100644 --- a/testing/web-platform/meta/magnetometer/idlharness.https.html.ini +++ b/testing/web-platform/meta/magnetometer/idlharness.https.html.ini @@ -90,3 +90,27 @@ [SensorReading interface: new MagnetometerReading({x: 0.5, y: 0.5, z: 0.5}); must inherit property "timeStamp" with the proper type (0)] expected: FAIL + [Magnetometer interface: attribute x] + expected: FAIL + + [Magnetometer interface: attribute y] + expected: FAIL + + [Magnetometer interface: attribute z] + expected: FAIL + + [Magnetometer interface: new Magnetometer(); must inherit property "x" with the proper type (0)] + expected: FAIL + + [Magnetometer interface: new Magnetometer(); must inherit property "y" with the proper type (1)] + expected: FAIL + + [Magnetometer interface: new Magnetometer(); must inherit property "z" with the proper type (2)] + expected: FAIL + + [Sensor interface: new Magnetometer(); must inherit property "activated" with the proper type (0)] + expected: FAIL + + [Sensor interface: new Magnetometer(); must inherit property "timestamp" with the proper type (1)] + expected: FAIL + diff --git a/testing/web-platform/meta/media-capabilities/decodingInfo.html.ini b/testing/web-platform/meta/media-capabilities/decodingInfo.html.ini new file mode 100644 index 000000000000..8ab946dc6232 --- /dev/null +++ b/testing/web-platform/meta/media-capabilities/decodingInfo.html.ini @@ -0,0 +1,17 @@ +[decodingInfo.html] + type: testharness + [Test that decodingInfo rejects if it doesn't get a configuration] + expected: FAIL + + [Test that decodingInfo rejects if the MediaConfiguration isn't valid] + expected: FAIL + + [Test that decodingInfo rejects if the MediaConfiguration does not have a type] + expected: FAIL + + [Test that decodingInfo returns a valid MediaCapabilitiesInfo objects] + expected: FAIL + + [Test that decodingInfo rejects if the MediaConfiguration does not have a valid type] + expected: FAIL + diff --git a/testing/web-platform/meta/media-capabilities/idlharness.html.ini b/testing/web-platform/meta/media-capabilities/idlharness.html.ini index ae19adf44ea0..10e24c7b73cf 100644 --- a/testing/web-platform/meta/media-capabilities/idlharness.html.ini +++ b/testing/web-platform/meta/media-capabilities/idlharness.html.ini @@ -48,3 +48,33 @@ [MediaCapabilities interface: operation query(MediaConfiguration)] expected: FAIL + [MediaCapabilitiesInfo interface: existence and properties of interface object] + expected: FAIL + + [MediaCapabilitiesInfo interface object length] + expected: FAIL + + [MediaCapabilitiesInfo interface object name] + expected: FAIL + + [MediaCapabilitiesInfo interface: existence and properties of interface prototype object] + expected: FAIL + + [MediaCapabilitiesInfo interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [MediaCapabilitiesInfo interface: attribute supported] + expected: FAIL + + [MediaCapabilitiesInfo interface: attribute smooth] + expected: FAIL + + [MediaCapabilitiesInfo interface: attribute powerEfficient] + expected: FAIL + + [MediaCapabilities interface: operation decodingInfo(MediaDecodingConfiguration)] + expected: FAIL + + [MediaCapabilities interface: operation encodingInfo(MediaEncodingConfiguration)] + expected: FAIL + diff --git a/testing/web-platform/meta/media-capabilities/query.html.ini b/testing/web-platform/meta/media-capabilities/query.html.ini deleted file mode 100644 index 5bfc3801dbe3..000000000000 --- a/testing/web-platform/meta/media-capabilities/query.html.ini +++ /dev/null @@ -1,17 +0,0 @@ -[query.html] - type: testharness - [Test that query rejects if it doesn't get a configuration] - expected: FAIL - - [Test that query rejects if the MediaConfiguration isn't valid] - expected: FAIL - - [Test that query returns a valid MediaDecodingAbility objects] - expected: FAIL - - [Test that query rejects if the MediaConfiguration does not have a type] - expected: FAIL - - [Test that query rejects if the MediaConfiguration does not have a valid type] - expected: FAIL - diff --git a/testing/web-platform/meta/mediacapture-image/idlharness.html.ini b/testing/web-platform/meta/mediacapture-image/idlharness.html.ini new file mode 100644 index 000000000000..1b5205988dbb --- /dev/null +++ b/testing/web-platform/meta/mediacapture-image/idlharness.html.ini @@ -0,0 +1,5 @@ +[idlharness.html] + type: testharness + [Image Capture IDL test] + expected: FAIL + diff --git a/testing/web-platform/meta/mixed-content/imageset.https.sub.html.ini b/testing/web-platform/meta/mixed-content/imageset.https.sub.html.ini new file mode 100644 index 000000000000..86fc7925b64f --- /dev/null +++ b/testing/web-platform/meta/mixed-content/imageset.https.sub.html.ini @@ -0,0 +1,5 @@ +[imageset.https.sub.html] + type: testharness + [Makes sure imageset blockable resources are not downloaded] + expected: FAIL + diff --git a/testing/web-platform/meta/mozilla-sync b/testing/web-platform/meta/mozilla-sync index ab1d5f37f233..84f82abeb257 100644 --- a/testing/web-platform/meta/mozilla-sync +++ b/testing/web-platform/meta/mozilla-sync @@ -1,2 +1,2 @@ -local: 0000000000000000000000000000000000000000 -upstream: 8181d7f09ee35cb521452bb727a48a1667901afd +local: 0b255199db9d6a6f189b89b7906f99155bde3726 +upstream: 72d174747fe176cbefcba315b445fac99d3dbfb2 diff --git a/testing/web-platform/meta/navigation-timing/nav2_test_document_replaced.html.ini b/testing/web-platform/meta/navigation-timing/nav2_test_document_replaced.html.ini new file mode 100644 index 000000000000..123c842b6195 --- /dev/null +++ b/testing/web-platform/meta/navigation-timing/nav2_test_document_replaced.html.ini @@ -0,0 +1,5 @@ +[nav2_test_document_replaced.html] + type: testharness + [Navigation Timing 2 WPT] + expected: FAIL + diff --git a/testing/web-platform/meta/navigation-timing/nav2_test_frame_removed.html.ini b/testing/web-platform/meta/navigation-timing/nav2_test_frame_removed.html.ini new file mode 100644 index 000000000000..6cd50b8489f0 --- /dev/null +++ b/testing/web-platform/meta/navigation-timing/nav2_test_frame_removed.html.ini @@ -0,0 +1,5 @@ +[nav2_test_frame_removed.html] + type: testharness + [Navigation Timing 2 WPT] + expected: FAIL + diff --git a/testing/web-platform/meta/orientation-sensor/idlharness.https.html.ini b/testing/web-platform/meta/orientation-sensor/idlharness.https.html.ini new file mode 100644 index 000000000000..e6ce8a3e8cb1 --- /dev/null +++ b/testing/web-platform/meta/orientation-sensor/idlharness.https.html.ini @@ -0,0 +1,74 @@ +[idlharness.https.html] + type: testharness + [OrientationSensor interface: existence and properties of interface object] + expected: FAIL + + [OrientationSensor interface object length] + expected: FAIL + + [OrientationSensor interface object name] + expected: FAIL + + [OrientationSensor interface: existence and properties of interface prototype object] + expected: FAIL + + [OrientationSensor interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [OrientationSensor interface: attribute quaternion] + expected: FAIL + + [OrientationSensor interface: operation populateMatrix(RotationMatrixType)] + expected: FAIL + + [AbsoluteOrientationSensor interface: existence and properties of interface object] + expected: FAIL + + [AbsoluteOrientationSensor interface object length] + expected: FAIL + + [AbsoluteOrientationSensor interface object name] + expected: FAIL + + [AbsoluteOrientationSensor interface: existence and properties of interface prototype object] + expected: FAIL + + [AbsoluteOrientationSensor interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [AbsoluteOrientationSensor must be primary interface of new AbsoluteOrientationSensor();] + expected: FAIL + + [Stringification of new AbsoluteOrientationSensor();] + expected: FAIL + + [OrientationSensor interface: new AbsoluteOrientationSensor(); must inherit property "quaternion" with the proper type (0)] + expected: FAIL + + [OrientationSensor interface: new AbsoluteOrientationSensor(); must inherit property "populateMatrix" with the proper type (1)] + expected: FAIL + + [OrientationSensor interface: calling populateMatrix(RotationMatrixType) on new AbsoluteOrientationSensor(); with too few arguments must throw TypeError] + expected: FAIL + + [Sensor interface: new AbsoluteOrientationSensor(); must inherit property "activated" with the proper type (0)] + expected: FAIL + + [Sensor interface: new AbsoluteOrientationSensor(); must inherit property "timestamp" with the proper type (1)] + expected: FAIL + + [Sensor interface: new AbsoluteOrientationSensor(); must inherit property "start" with the proper type (2)] + expected: FAIL + + [Sensor interface: new AbsoluteOrientationSensor(); must inherit property "stop" with the proper type (3)] + expected: FAIL + + [Sensor interface: new AbsoluteOrientationSensor(); must inherit property "onchange" with the proper type (4)] + expected: FAIL + + [Sensor interface: new AbsoluteOrientationSensor(); must inherit property "onactivate" with the proper type (5)] + expected: FAIL + + [Sensor interface: new AbsoluteOrientationSensor(); must inherit property "onerror" with the proper type (6)] + expected: FAIL + diff --git a/testing/web-platform/meta/page-visibility/prerender_call.html.ini b/testing/web-platform/meta/page-visibility/prerender_call.html.ini new file mode 100644 index 000000000000..c1884922e798 --- /dev/null +++ b/testing/web-platform/meta/page-visibility/prerender_call.html.ini @@ -0,0 +1,5 @@ +[prerender_call.html] + type: testharness + [VisibilityState of the target page was set to "prerender" when it has been prerendered] + expected: FAIL + diff --git a/testing/web-platform/meta/payment-request/allowpaymentrequest/allowpaymentrequest-attribute-same-origin-bc-containers.https.html.ini b/testing/web-platform/meta/payment-request/allowpaymentrequest/allowpaymentrequest-attribute-same-origin-bc-containers.https.html.ini index b71489db6125..f39947fd6dfa 100644 --- a/testing/web-platform/meta/payment-request/allowpaymentrequest/allowpaymentrequest-attribute-same-origin-bc-containers.https.html.ini +++ b/testing/web-platform/meta/payment-request/allowpaymentrequest/allowpaymentrequest-attribute-same-origin-bc-containers.https.html.ini @@ -1,4 +1,3 @@ [allowpaymentrequest-attribute-same-origin-bc-containers.https.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1336760 - diff --git a/testing/web-platform/meta/payment-request/allowpaymentrequest/no-attribute-same-origin-bc-containers.https.html.ini b/testing/web-platform/meta/payment-request/allowpaymentrequest/no-attribute-same-origin-bc-containers.https.html.ini index 73195f727b29..931158070fb4 100644 --- a/testing/web-platform/meta/payment-request/allowpaymentrequest/no-attribute-same-origin-bc-containers.https.html.ini +++ b/testing/web-platform/meta/payment-request/allowpaymentrequest/no-attribute-same-origin-bc-containers.https.html.ini @@ -1,4 +1,3 @@ [no-attribute-same-origin-bc-containers.https.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1328351 - diff --git a/testing/web-platform/meta/payment-request/payment-request-id.https.html.ini b/testing/web-platform/meta/payment-request/payment-request-id.https.html.ini new file mode 100644 index 000000000000..bff064201f74 --- /dev/null +++ b/testing/web-platform/meta/payment-request/payment-request-id.https.html.ini @@ -0,0 +1,5 @@ +[payment-request-id.https.html] + type: testharness + [Test for PaymentRequest identifier usage] + expected: FAIL + diff --git a/testing/web-platform/meta/presentation-api/controlling-ua/PresentationRequest_success.https.html.ini b/testing/web-platform/meta/presentation-api/controlling-ua/PresentationRequest_success.https.html.ini index 245d7a6840f9..2f23016fd07e 100644 --- a/testing/web-platform/meta/presentation-api/controlling-ua/PresentationRequest_success.https.html.ini +++ b/testing/web-platform/meta/presentation-api/controlling-ua/PresentationRequest_success.https.html.ini @@ -9,3 +9,6 @@ [Call PresentationRequest constructor with a set of valid presentation URLs. No Exception expected.] expected: FAIL + [Constructing a PresentationRequest] + expected: FAIL + diff --git a/testing/web-platform/meta/presentation-api/controlling-ua/defaultRequest.https.html.ini b/testing/web-platform/meta/presentation-api/controlling-ua/defaultRequest.https.html.ini new file mode 100644 index 000000000000..3aff65b9e3d1 --- /dev/null +++ b/testing/web-platform/meta/presentation-api/controlling-ua/defaultRequest.https.html.ini @@ -0,0 +1,5 @@ +[defaultRequest.https.html] + type: testharness + [Setting a default presentation request] + expected: FAIL + diff --git a/testing/web-platform/meta/resource-timing/resource_TAO_match_origin.htm.ini b/testing/web-platform/meta/resource-timing/resource_TAO_match_origin.htm.ini new file mode 100644 index 000000000000..b0bfb4eb2450 --- /dev/null +++ b/testing/web-platform/meta/resource-timing/resource_TAO_match_origin.htm.ini @@ -0,0 +1,5 @@ +[resource_TAO_match_origin.htm] + type: testharness + [redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart -- should NOT be all returned as 0 when the Timing-Allow-Origin header value list contains a case-sensitive match for the value of the origin of the current document and TAO algorithm passes] + expected: FAIL + diff --git a/testing/web-platform/meta/resource-timing/resource_TAO_match_wildcard.htm.ini b/testing/web-platform/meta/resource-timing/resource_TAO_match_wildcard.htm.ini new file mode 100644 index 000000000000..af0da2062cb4 --- /dev/null +++ b/testing/web-platform/meta/resource-timing/resource_TAO_match_wildcard.htm.ini @@ -0,0 +1,5 @@ +[resource_TAO_match_wildcard.htm] + type: testharness + [redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart -- should NOT be all returned as 0 when the Timing-Allow-Origin header value list contains a wildcard ("*") and TAO algorithm passes] + expected: FAIL + diff --git a/testing/web-platform/meta/resource-timing/resource_TAO_multi.htm.ini b/testing/web-platform/meta/resource-timing/resource_TAO_multi.htm.ini new file mode 100644 index 000000000000..c6a9c77a40cc --- /dev/null +++ b/testing/web-platform/meta/resource-timing/resource_TAO_multi.htm.ini @@ -0,0 +1,5 @@ +[resource_TAO_multi.htm] + type: testharness + [redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart -- should not be all returned as 0 when the HTTP response has multiple Timing-Allow-Origin header fields and the subsequent field value is separated by a comma, i.e. TAO algorithm passes] + expected: FAIL + diff --git a/testing/web-platform/meta/selection/collapse-00.html.ini b/testing/web-platform/meta/selection/collapse-00.html.ini index 874ddc1978fd..0d24de744c04 100644 --- a/testing/web-platform/meta/selection/collapse-00.html.ini +++ b/testing/web-platform/meta/selection/collapse-00.html.ini @@ -3960,3 +3960,3963 @@ [Range 29 [paras[0\].firstChild, 3, paras[3\], 1\], point 80 [docfrag, 0\]] expected: FAIL + [collapse() on [\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[0\].firstChild, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 2, paras[0\].firstChild, 9\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 0, paras[1\].firstChild, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[1\].firstChild, 2, paras[1\].firstChild, 9\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] to [xmlDoctype, 0\]] + expected: FAIL + diff --git a/testing/web-platform/meta/selection/collapse-15.html.ini b/testing/web-platform/meta/selection/collapse-15.html.ini new file mode 100644 index 000000000000..ee4530c790ea --- /dev/null +++ b/testing/web-platform/meta/selection/collapse-15.html.ini @@ -0,0 +1,3962 @@ +[collapse-15.html] + type: testharness + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 0, document.documentElement, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.documentElement, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document.head, 1, document.head, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.head, 1, document.head, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document.body, 0, document.body, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.body, 0, document.body, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.head, 1, foreignDoc.head, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignDoc.body, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\], 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\], 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedPara1, 0, detachedPara1, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 0, paras[1\].firstChild, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\].firstChild, 3, paras[3\], 1\] to [xmlDoctype, 0\]] + expected: FAIL + diff --git a/testing/web-platform/meta/selection/collapse-30.html.ini b/testing/web-platform/meta/selection/collapse-30.html.ini index 9b8c6a21647e..b91ed22f2582 100644 --- a/testing/web-platform/meta/selection/collapse-30.html.ini +++ b/testing/web-platform/meta/selection/collapse-30.html.ini @@ -3828,3 +3828,7659 @@ [Range 58 [xmlDocfrag, 0, xmlDocfrag, 0\], point 80 [docfrag, 0\]] expected: FAIL + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 1, xmlComment, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 1, xmlComment, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedTextNode, 0, detachedTextNode, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 3, detachedComment, 4\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 3, detachedComment, 4\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedComment, 5, detachedComment, 5\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedComment, 5, detachedComment, 5\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 0, detachedForeignComment, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedForeignComment, 4, detachedForeignComment, 4\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [detachedXmlComment, 2, detachedXmlComment, 6\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [docfrag, 0, docfrag, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [docfrag, 0, docfrag, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDocfrag, 0, foreignDocfrag, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [xmlDocfrag, 0, xmlDocfrag, 0\] to [xmlDoctype, 0\]] + expected: FAIL + diff --git a/testing/web-platform/meta/selection/collapse-45.html.ini b/testing/web-platform/meta/selection/collapse-45.html.ini new file mode 100644 index 000000000000..76d43ae96421 --- /dev/null +++ b/testing/web-platform/meta/selection/collapse-45.html.ini @@ -0,0 +1,3962 @@ +[collapse-45.html] + type: testharness + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[0\], 0, paras[0\].firstChild, 7\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 2, paras[4\], 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 2, paras[4\], 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 1, paras[2\].firstChild, 5\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document.documentElement, 1, document.body, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document.documentElement, 1, document.body, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 1\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 0, document, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 0, document, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [document, 1, document, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [document, 1, document, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [testDiv, 0, comment, 5\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [testDiv, 0, comment, 5\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[2\].firstChild, 4, comment, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [paras[3\], 1, comment, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [paras[3\], 1, comment, 8\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 0, foreignDoc, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc, 1, foreignComment, 2\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [foreignDoc.body, 0, foreignTextNode, 36\] to [xmlDoctype, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignPara1.firstChild, 9\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.documentElement, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.documentElement, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.head, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc.body, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedPara1, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoc, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignComment, 2\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignComment, 2\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignTextNode, 36\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, -1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 1\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoc, 5\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlComment, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlComment, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlComment, 4\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlComment, 4\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 5\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [processingInstruction, 9\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlTextNode, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlTextNode, 8\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedProcessingInstruction, 12\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedComment, 3\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedComment, 3\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedComment, 5\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedComment, 5\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignComment, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedForeignComment, 4\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [detachedXmlComment, 2\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [docfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [docfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDocfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDocfrag, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [foreignDoctype, 0\]] + expected: FAIL + + [collapse() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoctype, 0\]] + expected: FAIL + + [setPosition() on [xmlDoc, 0, xmlDoc, 0\] to [xmlDoctype, 0\]] + expected: FAIL + diff --git a/testing/web-platform/meta/selection/removeAllRanges.html.ini b/testing/web-platform/meta/selection/removeAllRanges.html.ini index dfa0c1b072de..65c210549bd1 100644 --- a/testing/web-platform/meta/selection/removeAllRanges.html.ini +++ b/testing/web-platform/meta/selection/removeAllRanges.html.ini @@ -63,3 +63,129 @@ [Range 58 [xmlDocfrag, 0, xmlDocfrag, 0\] backwards] expected: FAIL + [removeAllRanges on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] backwards] + expected: FAIL + + [empty on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\] backwards] + expected: FAIL + + [removeAllRanges on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] backwards] + expected: FAIL + + [empty on [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1\] backwards] + expected: FAIL + + [removeAllRanges on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] backwards] + expected: FAIL + + [empty on [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\] backwards] + expected: FAIL + + [removeAllRanges on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] backwards] + expected: FAIL + + [empty on [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1\] backwards] + expected: FAIL + + [removeAllRanges on [foreignDoc.head, 1, foreignDoc.head, 1\] backwards] + expected: FAIL + + [empty on [foreignDoc.head, 1, foreignDoc.head, 1\] backwards] + expected: FAIL + + [removeAllRanges on [foreignDoc.body, 0, foreignDoc.body, 0\] backwards] + expected: FAIL + + [empty on [foreignDoc.body, 0, foreignDoc.body, 0\] backwards] + expected: FAIL + + [removeAllRanges on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] backwards] + expected: FAIL + + [empty on [foreignDoc.documentElement, 1, foreignDoc.body, 0\] backwards] + expected: FAIL + + [removeAllRanges on [foreignDoc, 0, foreignDoc, 0\] backwards] + expected: FAIL + + [empty on [foreignDoc, 0, foreignDoc, 0\] backwards] + expected: FAIL + + [removeAllRanges on [foreignDoc, 1, foreignComment, 2\] backwards] + expected: FAIL + + [empty on [foreignDoc, 1, foreignComment, 2\] backwards] + expected: FAIL + + [removeAllRanges on [foreignDoc.body, 0, foreignTextNode, 36\] backwards] + expected: FAIL + + [empty on [foreignDoc.body, 0, foreignTextNode, 36\] backwards] + expected: FAIL + + [removeAllRanges on [xmlDoc, 0, xmlDoc, 0\] backwards] + expected: FAIL + + [empty on [xmlDoc, 0, xmlDoc, 0\] backwards] + expected: FAIL + + [removeAllRanges on [xmlDoc, 1, xmlComment, 0\] backwards] + expected: FAIL + + [empty on [xmlDoc, 1, xmlComment, 0\] backwards] + expected: FAIL + + [removeAllRanges on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] backwards] + expected: FAIL + + [empty on [detachedForeignTextNode, 7, detachedForeignTextNode, 7\] backwards] + expected: FAIL + + [removeAllRanges on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] backwards] + expected: FAIL + + [empty on [detachedForeignTextNode, 0, detachedForeignTextNode, 8\] backwards] + expected: FAIL + + [removeAllRanges on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] backwards] + expected: FAIL + + [empty on [detachedXmlTextNode, 7, detachedXmlTextNode, 7\] backwards] + expected: FAIL + + [removeAllRanges on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] backwards] + expected: FAIL + + [empty on [detachedXmlTextNode, 0, detachedXmlTextNode, 8\] backwards] + expected: FAIL + + [removeAllRanges on [detachedForeignComment, 0, detachedForeignComment, 1\] backwards] + expected: FAIL + + [empty on [detachedForeignComment, 0, detachedForeignComment, 1\] backwards] + expected: FAIL + + [removeAllRanges on [detachedForeignComment, 4, detachedForeignComment, 4\] backwards] + expected: FAIL + + [empty on [detachedForeignComment, 4, detachedForeignComment, 4\] backwards] + expected: FAIL + + [removeAllRanges on [detachedXmlComment, 2, detachedXmlComment, 6\] backwards] + expected: FAIL + + [empty on [detachedXmlComment, 2, detachedXmlComment, 6\] backwards] + expected: FAIL + + [removeAllRanges on [foreignDocfrag, 0, foreignDocfrag, 0\] backwards] + expected: FAIL + + [empty on [foreignDocfrag, 0, foreignDocfrag, 0\] backwards] + expected: FAIL + + [removeAllRanges on [xmlDocfrag, 0, xmlDocfrag, 0\] backwards] + expected: FAIL + + [empty on [xmlDocfrag, 0, xmlDocfrag, 0\] backwards] + expected: FAIL + diff --git a/testing/web-platform/meta/selection/type.html.ini b/testing/web-platform/meta/selection/type.html.ini new file mode 100644 index 000000000000..841be35fcb14 --- /dev/null +++ b/testing/web-platform/meta/selection/type.html.ini @@ -0,0 +1,89 @@ +[type.html] + type: testharness + [Empty selection] + expected: FAIL + + [[paras[0\].firstChild, 0, paras[0\].firstChild, 0\]] + expected: FAIL + + [[paras[0\].firstChild, 0, paras[0\].firstChild, 1\]] + expected: FAIL + + [[paras[0\].firstChild, 2, paras[0\].firstChild, 8\]] + expected: FAIL + + [[paras[0\].firstChild, 2, paras[0\].firstChild, 9\]] + expected: FAIL + + [[paras[1\].firstChild, 0, paras[1\].firstChild, 0\]] + expected: FAIL + + [[paras[1\].firstChild, 0, paras[1\].firstChild, 1\]] + expected: FAIL + + [[paras[1\].firstChild, 2, paras[1\].firstChild, 8\]] + expected: FAIL + + [[paras[1\].firstChild, 2, paras[1\].firstChild, 9\]] + expected: FAIL + + [[document.documentElement, 0, document.documentElement, 1\]] + expected: FAIL + + [[document.documentElement, 0, document.documentElement, 2\]] + expected: FAIL + + [[document.documentElement, 1, document.documentElement, 2\]] + expected: FAIL + + [[document.head, 1, document.head, 1\]] + expected: FAIL + + [[document.body, 0, document.body, 1\]] + expected: FAIL + + [[paras[0\], 0, paras[0\], 0\]] + expected: FAIL + + [[paras[0\], 0, paras[0\], 1\]] + expected: FAIL + + [[paras[0\].firstChild, 0, paras[1\].firstChild, 0\]] + expected: FAIL + + [[paras[0\].firstChild, 0, paras[1\].firstChild, 8\]] + expected: FAIL + + [[paras[0\].firstChild, 3, paras[3\], 1\]] + expected: FAIL + + [[paras[0\], 0, paras[0\].firstChild, 7\]] + expected: FAIL + + [[testDiv, 2, paras[4\], 1\]] + expected: FAIL + + [[testDiv, 1, paras[2\].firstChild, 5\]] + expected: FAIL + + [[document.documentElement, 1, document.body, 0\]] + expected: FAIL + + [[document, 0, document, 1\]] + expected: FAIL + + [[document, 0, document, 2\]] + expected: FAIL + + [[document, 1, document, 2\]] + expected: FAIL + + [[testDiv, 0, comment, 5\]] + expected: FAIL + + [[paras[2\].firstChild, 4, comment, 2\]] + expected: FAIL + + [[paras[3\], 1, comment, 8\]] + expected: FAIL + diff --git a/testing/web-platform/meta/selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.html.ini b/testing/web-platform/meta/selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.html.ini deleted file mode 100644 index 1b1240365d70..000000000000 --- a/testing/web-platform/meta/selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.html.ini +++ /dev/null @@ -1,2654 +0,0 @@ -[ParentNode-query-queryAll.html] - type: testharness - [Document supports query] - expected: FAIL - - [Document supports queryAll] - expected: FAIL - - [Detached Element supports query] - expected: FAIL - - [Detached Element supports queryAll] - expected: FAIL - - [Fragment supports query] - expected: FAIL - - [Fragment supports queryAll] - expected: FAIL - - [In-document Element supports query] - expected: FAIL - - [In-document Element supports queryAll] - expected: FAIL - - [Document.queryAll null] - expected: FAIL - - [Document.queryAll undefined] - expected: FAIL - - [Document.query null] - expected: FAIL - - [Document.query undefined] - expected: FAIL - - [Document.queryAll tree order] - expected: FAIL - - [Detached Element.queryAll null] - expected: FAIL - - [Detached Element.queryAll undefined] - expected: FAIL - - [Detached Element.query null] - expected: FAIL - - [Detached Element.query undefined] - expected: FAIL - - [Detached Element.queryAll tree order] - expected: FAIL - - [Fragment.queryAll null] - expected: FAIL - - [Fragment.queryAll undefined] - expected: FAIL - - [Fragment.query null] - expected: FAIL - - [Fragment.query undefined] - expected: FAIL - - [Fragment.queryAll tree order] - expected: FAIL - - [In-document Element.queryAll null] - expected: FAIL - - [In-document Element.queryAll undefined] - expected: FAIL - - [In-document Element.query null] - expected: FAIL - - [In-document Element.query undefined] - expected: FAIL - - [In-document Element.queryAll tree order] - expected: FAIL - - [Document: static NodeList] - expected: FAIL - - [Document: new NodeList] - expected: FAIL - - [Detached Element: static NodeList] - expected: FAIL - - [Detached Element: new NodeList] - expected: FAIL - - [Fragment: static NodeList] - expected: FAIL - - [Fragment: new NodeList] - expected: FAIL - - [In-document Element: static NodeList] - expected: FAIL - - [In-document Element: new NodeList] - expected: FAIL - - [Document.query: Empty String: ] - expected: FAIL - - [Document.queryAll: Empty String: ] - expected: FAIL - - [Document.query: Invalid character: [] - expected: FAIL - - [Document.queryAll: Invalid character: [] - expected: FAIL - - [Document.query: Invalid character: \]] - expected: FAIL - - [Document.queryAll: Invalid character: \]] - expected: FAIL - - [Document.query: Invalid character: (] - expected: FAIL - - [Document.queryAll: Invalid character: (] - expected: FAIL - - [Document.query: Invalid character: )] - expected: FAIL - - [Document.queryAll: Invalid character: )] - expected: FAIL - - [Document.query: Invalid character: {] - expected: FAIL - - [Document.queryAll: Invalid character: {] - expected: FAIL - - [Document.query: Invalid character: }] - expected: FAIL - - [Document.queryAll: Invalid character: }] - expected: FAIL - - [Document.query: Invalid character: <] - expected: FAIL - - [Document.queryAll: Invalid character: <] - expected: FAIL - - [Document.query: Invalid character: >] - expected: FAIL - - [Document.queryAll: Invalid character: >] - expected: FAIL - - [Document.query: Invalid ID: #] - expected: FAIL - - [Document.queryAll: Invalid ID: #] - expected: FAIL - - [Document.query: Invalid group of selectors: div,] - expected: FAIL - - [Document.queryAll: Invalid group of selectors: div,] - expected: FAIL - - [Document.query: Invalid class: .] - expected: FAIL - - [Document.queryAll: Invalid class: .] - expected: FAIL - - [Document.query: Invalid class: .5cm] - expected: FAIL - - [Document.queryAll: Invalid class: .5cm] - expected: FAIL - - [Document.query: Invalid class: ..test] - expected: FAIL - - [Document.queryAll: Invalid class: ..test] - expected: FAIL - - [Document.query: Invalid class: .foo..quux] - expected: FAIL - - [Document.queryAll: Invalid class: .foo..quux] - expected: FAIL - - [Document.query: Invalid class: .bar.] - expected: FAIL - - [Document.queryAll: Invalid class: .bar.] - expected: FAIL - - [Document.query: Invalid combinator: div & address, p] - expected: FAIL - - [Document.queryAll: Invalid combinator: div & address, p] - expected: FAIL - - [Document.query: Invalid combinator: div >> address, p] - expected: FAIL - - [Document.queryAll: Invalid combinator: div >> address, p] - expected: FAIL - - [Document.query: Invalid combinator: div ++ address, p] - expected: FAIL - - [Document.queryAll: Invalid combinator: div ++ address, p] - expected: FAIL - - [Document.query: Invalid combinator: div ~~ address, p] - expected: FAIL - - [Document.queryAll: Invalid combinator: div ~~ address, p] - expected: FAIL - - [Document.query: Invalid [att=value\] selector: [*=test\]] - expected: FAIL - - [Document.queryAll: Invalid [att=value\] selector: [*=test\]] - expected: FAIL - - [Document.query: Invalid [att=value\] selector: [*|*=test\]] - expected: FAIL - - [Document.queryAll: Invalid [att=value\] selector: [*|*=test\]] - expected: FAIL - - [Document.query: Invalid [att=value\] selector: [class= space unquoted \]] - expected: FAIL - - [Document.queryAll: Invalid [att=value\] selector: [class= space unquoted \]] - expected: FAIL - - [Document.query: Unknown pseudo-class: div:example] - expected: FAIL - - [Document.queryAll: Unknown pseudo-class: div:example] - expected: FAIL - - [Document.query: Unknown pseudo-class: :example] - expected: FAIL - - [Document.queryAll: Unknown pseudo-class: :example] - expected: FAIL - - [Document.query: Unknown pseudo-element: div::example] - expected: FAIL - - [Document.queryAll: Unknown pseudo-element: div::example] - expected: FAIL - - [Document.query: Unknown pseudo-element: ::example] - expected: FAIL - - [Document.queryAll: Unknown pseudo-element: ::example] - expected: FAIL - - [Document.query: Invalid pseudo-element: :::before] - expected: FAIL - - [Document.queryAll: Invalid pseudo-element: :::before] - expected: FAIL - - [Document.query: Undeclared namespace: ns|div] - expected: FAIL - - [Document.queryAll: Undeclared namespace: ns|div] - expected: FAIL - - [Document.query: Undeclared namespace: :not(ns|div)] - expected: FAIL - - [Document.queryAll: Undeclared namespace: :not(ns|div)] - expected: FAIL - - [Document.query: Invalid namespace: ^|div] - expected: FAIL - - [Document.queryAll: Invalid namespace: ^|div] - expected: FAIL - - [Document.query: Invalid namespace: $|div] - expected: FAIL - - [Document.queryAll: Invalid namespace: $|div] - expected: FAIL - - [Detached Element.query: Empty String: ] - expected: FAIL - - [Detached Element.queryAll: Empty String: ] - expected: FAIL - - [Detached Element.query: Invalid character: [] - expected: FAIL - - [Detached Element.queryAll: Invalid character: [] - expected: FAIL - - [Detached Element.query: Invalid character: \]] - expected: FAIL - - [Detached Element.queryAll: Invalid character: \]] - expected: FAIL - - [Detached Element.query: Invalid character: (] - expected: FAIL - - [Detached Element.queryAll: Invalid character: (] - expected: FAIL - - [Detached Element.query: Invalid character: )] - expected: FAIL - - [Detached Element.queryAll: Invalid character: )] - expected: FAIL - - [Detached Element.query: Invalid character: {] - expected: FAIL - - [Detached Element.queryAll: Invalid character: {] - expected: FAIL - - [Detached Element.query: Invalid character: }] - expected: FAIL - - [Detached Element.queryAll: Invalid character: }] - expected: FAIL - - [Detached Element.query: Invalid character: <] - expected: FAIL - - [Detached Element.queryAll: Invalid character: <] - expected: FAIL - - [Detached Element.query: Invalid character: >] - expected: FAIL - - [Detached Element.queryAll: Invalid character: >] - expected: FAIL - - [Detached Element.query: Invalid ID: #] - expected: FAIL - - [Detached Element.queryAll: Invalid ID: #] - expected: FAIL - - [Detached Element.query: Invalid group of selectors: div,] - expected: FAIL - - [Detached Element.queryAll: Invalid group of selectors: div,] - expected: FAIL - - [Detached Element.query: Invalid class: .] - expected: FAIL - - [Detached Element.queryAll: Invalid class: .] - expected: FAIL - - [Detached Element.query: Invalid class: .5cm] - expected: FAIL - - [Detached Element.queryAll: Invalid class: .5cm] - expected: FAIL - - [Detached Element.query: Invalid class: ..test] - expected: FAIL - - [Detached Element.queryAll: Invalid class: ..test] - expected: FAIL - - [Detached Element.query: Invalid class: .foo..quux] - expected: FAIL - - [Detached Element.queryAll: Invalid class: .foo..quux] - expected: FAIL - - [Detached Element.query: Invalid class: .bar.] - expected: FAIL - - [Detached Element.queryAll: Invalid class: .bar.] - expected: FAIL - - [Detached Element.query: Invalid combinator: div & address, p] - expected: FAIL - - [Detached Element.queryAll: Invalid combinator: div & address, p] - expected: FAIL - - [Detached Element.query: Invalid combinator: div >> address, p] - expected: FAIL - - [Detached Element.queryAll: Invalid combinator: div >> address, p] - expected: FAIL - - [Detached Element.query: Invalid combinator: div ++ address, p] - expected: FAIL - - [Detached Element.queryAll: Invalid combinator: div ++ address, p] - expected: FAIL - - [Detached Element.query: Invalid combinator: div ~~ address, p] - expected: FAIL - - [Detached Element.queryAll: Invalid combinator: div ~~ address, p] - expected: FAIL - - [Detached Element.query: Invalid [att=value\] selector: [*=test\]] - expected: FAIL - - [Detached Element.queryAll: Invalid [att=value\] selector: [*=test\]] - expected: FAIL - - [Detached Element.query: Invalid [att=value\] selector: [*|*=test\]] - expected: FAIL - - [Detached Element.queryAll: Invalid [att=value\] selector: [*|*=test\]] - expected: FAIL - - [Detached Element.query: Invalid [att=value\] selector: [class= space unquoted \]] - expected: FAIL - - [Detached Element.queryAll: Invalid [att=value\] selector: [class= space unquoted \]] - expected: FAIL - - [Detached Element.query: Unknown pseudo-class: div:example] - expected: FAIL - - [Detached Element.queryAll: Unknown pseudo-class: div:example] - expected: FAIL - - [Detached Element.query: Unknown pseudo-class: :example] - expected: FAIL - - [Detached Element.queryAll: Unknown pseudo-class: :example] - expected: FAIL - - [Detached Element.query: Unknown pseudo-element: div::example] - expected: FAIL - - [Detached Element.queryAll: Unknown pseudo-element: div::example] - expected: FAIL - - [Detached Element.query: Unknown pseudo-element: ::example] - expected: FAIL - - [Detached Element.queryAll: Unknown pseudo-element: ::example] - expected: FAIL - - [Detached Element.query: Invalid pseudo-element: :::before] - expected: FAIL - - [Detached Element.queryAll: Invalid pseudo-element: :::before] - expected: FAIL - - [Detached Element.query: Undeclared namespace: ns|div] - expected: FAIL - - [Detached Element.queryAll: Undeclared namespace: ns|div] - expected: FAIL - - [Detached Element.query: Undeclared namespace: :not(ns|div)] - expected: FAIL - - [Detached Element.queryAll: Undeclared namespace: :not(ns|div)] - expected: FAIL - - [Detached Element.query: Invalid namespace: ^|div] - expected: FAIL - - [Detached Element.queryAll: Invalid namespace: ^|div] - expected: FAIL - - [Detached Element.query: Invalid namespace: $|div] - expected: FAIL - - [Detached Element.queryAll: Invalid namespace: $|div] - expected: FAIL - - [Fragment.query: Empty String: ] - expected: FAIL - - [Fragment.queryAll: Empty String: ] - expected: FAIL - - [Fragment.query: Invalid character: [] - expected: FAIL - - [Fragment.queryAll: Invalid character: [] - expected: FAIL - - [Fragment.query: Invalid character: \]] - expected: FAIL - - [Fragment.queryAll: Invalid character: \]] - expected: FAIL - - [Fragment.query: Invalid character: (] - expected: FAIL - - [Fragment.queryAll: Invalid character: (] - expected: FAIL - - [Fragment.query: Invalid character: )] - expected: FAIL - - [Fragment.queryAll: Invalid character: )] - expected: FAIL - - [Fragment.query: Invalid character: {] - expected: FAIL - - [Fragment.queryAll: Invalid character: {] - expected: FAIL - - [Fragment.query: Invalid character: }] - expected: FAIL - - [Fragment.queryAll: Invalid character: }] - expected: FAIL - - [Fragment.query: Invalid character: <] - expected: FAIL - - [Fragment.queryAll: Invalid character: <] - expected: FAIL - - [Fragment.query: Invalid character: >] - expected: FAIL - - [Fragment.queryAll: Invalid character: >] - expected: FAIL - - [Fragment.query: Invalid ID: #] - expected: FAIL - - [Fragment.queryAll: Invalid ID: #] - expected: FAIL - - [Fragment.query: Invalid group of selectors: div,] - expected: FAIL - - [Fragment.queryAll: Invalid group of selectors: div,] - expected: FAIL - - [Fragment.query: Invalid class: .] - expected: FAIL - - [Fragment.queryAll: Invalid class: .] - expected: FAIL - - [Fragment.query: Invalid class: .5cm] - expected: FAIL - - [Fragment.queryAll: Invalid class: .5cm] - expected: FAIL - - [Fragment.query: Invalid class: ..test] - expected: FAIL - - [Fragment.queryAll: Invalid class: ..test] - expected: FAIL - - [Fragment.query: Invalid class: .foo..quux] - expected: FAIL - - [Fragment.queryAll: Invalid class: .foo..quux] - expected: FAIL - - [Fragment.query: Invalid class: .bar.] - expected: FAIL - - [Fragment.queryAll: Invalid class: .bar.] - expected: FAIL - - [Fragment.query: Invalid combinator: div & address, p] - expected: FAIL - - [Fragment.queryAll: Invalid combinator: div & address, p] - expected: FAIL - - [Fragment.query: Invalid combinator: div >> address, p] - expected: FAIL - - [Fragment.queryAll: Invalid combinator: div >> address, p] - expected: FAIL - - [Fragment.query: Invalid combinator: div ++ address, p] - expected: FAIL - - [Fragment.queryAll: Invalid combinator: div ++ address, p] - expected: FAIL - - [Fragment.query: Invalid combinator: div ~~ address, p] - expected: FAIL - - [Fragment.queryAll: Invalid combinator: div ~~ address, p] - expected: FAIL - - [Fragment.query: Invalid [att=value\] selector: [*=test\]] - expected: FAIL - - [Fragment.queryAll: Invalid [att=value\] selector: [*=test\]] - expected: FAIL - - [Fragment.query: Invalid [att=value\] selector: [*|*=test\]] - expected: FAIL - - [Fragment.queryAll: Invalid [att=value\] selector: [*|*=test\]] - expected: FAIL - - [Fragment.query: Invalid [att=value\] selector: [class= space unquoted \]] - expected: FAIL - - [Fragment.queryAll: Invalid [att=value\] selector: [class= space unquoted \]] - expected: FAIL - - [Fragment.query: Unknown pseudo-class: div:example] - expected: FAIL - - [Fragment.queryAll: Unknown pseudo-class: div:example] - expected: FAIL - - [Fragment.query: Unknown pseudo-class: :example] - expected: FAIL - - [Fragment.queryAll: Unknown pseudo-class: :example] - expected: FAIL - - [Fragment.query: Unknown pseudo-element: div::example] - expected: FAIL - - [Fragment.queryAll: Unknown pseudo-element: div::example] - expected: FAIL - - [Fragment.query: Unknown pseudo-element: ::example] - expected: FAIL - - [Fragment.queryAll: Unknown pseudo-element: ::example] - expected: FAIL - - [Fragment.query: Invalid pseudo-element: :::before] - expected: FAIL - - [Fragment.queryAll: Invalid pseudo-element: :::before] - expected: FAIL - - [Fragment.query: Undeclared namespace: ns|div] - expected: FAIL - - [Fragment.queryAll: Undeclared namespace: ns|div] - expected: FAIL - - [Fragment.query: Undeclared namespace: :not(ns|div)] - expected: FAIL - - [Fragment.queryAll: Undeclared namespace: :not(ns|div)] - expected: FAIL - - [Fragment.query: Invalid namespace: ^|div] - expected: FAIL - - [Fragment.queryAll: Invalid namespace: ^|div] - expected: FAIL - - [Fragment.query: Invalid namespace: $|div] - expected: FAIL - - [Fragment.queryAll: Invalid namespace: $|div] - expected: FAIL - - [In-document Element.query: Empty String: ] - expected: FAIL - - [In-document Element.queryAll: Empty String: ] - expected: FAIL - - [In-document Element.query: Invalid character: [] - expected: FAIL - - [In-document Element.queryAll: Invalid character: [] - expected: FAIL - - [In-document Element.query: Invalid character: \]] - expected: FAIL - - [In-document Element.queryAll: Invalid character: \]] - expected: FAIL - - [In-document Element.query: Invalid character: (] - expected: FAIL - - [In-document Element.queryAll: Invalid character: (] - expected: FAIL - - [In-document Element.query: Invalid character: )] - expected: FAIL - - [In-document Element.queryAll: Invalid character: )] - expected: FAIL - - [In-document Element.query: Invalid character: {] - expected: FAIL - - [In-document Element.queryAll: Invalid character: {] - expected: FAIL - - [In-document Element.query: Invalid character: }] - expected: FAIL - - [In-document Element.queryAll: Invalid character: }] - expected: FAIL - - [In-document Element.query: Invalid character: <] - expected: FAIL - - [In-document Element.queryAll: Invalid character: <] - expected: FAIL - - [In-document Element.query: Invalid character: >] - expected: FAIL - - [In-document Element.queryAll: Invalid character: >] - expected: FAIL - - [In-document Element.query: Invalid ID: #] - expected: FAIL - - [In-document Element.queryAll: Invalid ID: #] - expected: FAIL - - [In-document Element.query: Invalid group of selectors: div,] - expected: FAIL - - [In-document Element.queryAll: Invalid group of selectors: div,] - expected: FAIL - - [In-document Element.query: Invalid class: .] - expected: FAIL - - [In-document Element.queryAll: Invalid class: .] - expected: FAIL - - [In-document Element.query: Invalid class: .5cm] - expected: FAIL - - [In-document Element.queryAll: Invalid class: .5cm] - expected: FAIL - - [In-document Element.query: Invalid class: ..test] - expected: FAIL - - [In-document Element.queryAll: Invalid class: ..test] - expected: FAIL - - [In-document Element.query: Invalid class: .foo..quux] - expected: FAIL - - [In-document Element.queryAll: Invalid class: .foo..quux] - expected: FAIL - - [In-document Element.query: Invalid class: .bar.] - expected: FAIL - - [In-document Element.queryAll: Invalid class: .bar.] - expected: FAIL - - [In-document Element.query: Invalid combinator: div & address, p] - expected: FAIL - - [In-document Element.queryAll: Invalid combinator: div & address, p] - expected: FAIL - - [In-document Element.query: Invalid combinator: div >> address, p] - expected: FAIL - - [In-document Element.queryAll: Invalid combinator: div >> address, p] - expected: FAIL - - [In-document Element.query: Invalid combinator: div ++ address, p] - expected: FAIL - - [In-document Element.queryAll: Invalid combinator: div ++ address, p] - expected: FAIL - - [In-document Element.query: Invalid combinator: div ~~ address, p] - expected: FAIL - - [In-document Element.queryAll: Invalid combinator: div ~~ address, p] - expected: FAIL - - [In-document Element.query: Invalid [att=value\] selector: [*=test\]] - expected: FAIL - - [In-document Element.queryAll: Invalid [att=value\] selector: [*=test\]] - expected: FAIL - - [In-document Element.query: Invalid [att=value\] selector: [*|*=test\]] - expected: FAIL - - [In-document Element.queryAll: Invalid [att=value\] selector: [*|*=test\]] - expected: FAIL - - [In-document Element.query: Invalid [att=value\] selector: [class= space unquoted \]] - expected: FAIL - - [In-document Element.queryAll: Invalid [att=value\] selector: [class= space unquoted \]] - expected: FAIL - - [In-document Element.query: Unknown pseudo-class: div:example] - expected: FAIL - - [In-document Element.queryAll: Unknown pseudo-class: div:example] - expected: FAIL - - [In-document Element.query: Unknown pseudo-class: :example] - expected: FAIL - - [In-document Element.queryAll: Unknown pseudo-class: :example] - expected: FAIL - - [In-document Element.query: Unknown pseudo-element: div::example] - expected: FAIL - - [In-document Element.queryAll: Unknown pseudo-element: div::example] - expected: FAIL - - [In-document Element.query: Unknown pseudo-element: ::example] - expected: FAIL - - [In-document Element.queryAll: Unknown pseudo-element: ::example] - expected: FAIL - - [In-document Element.query: Invalid pseudo-element: :::before] - expected: FAIL - - [In-document Element.queryAll: Invalid pseudo-element: :::before] - expected: FAIL - - [In-document Element.query: Undeclared namespace: ns|div] - expected: FAIL - - [In-document Element.queryAll: Undeclared namespace: ns|div] - expected: FAIL - - [In-document Element.query: Undeclared namespace: :not(ns|div)] - expected: FAIL - - [In-document Element.queryAll: Undeclared namespace: :not(ns|div)] - expected: FAIL - - [In-document Element.query: Invalid namespace: ^|div] - expected: FAIL - - [In-document Element.queryAll: Invalid namespace: ^|div] - expected: FAIL - - [In-document Element.query: Invalid namespace: $|div] - expected: FAIL - - [In-document Element.queryAll: Invalid namespace: $|div] - expected: FAIL - - [In-document [Context Element\].queryAll: Universal selector, matching all children of the specified reference element (with no refNodes): >*] - expected: FAIL - - [In-document [Context Element\].query: Universal selector, matching all children of the specified reference element (with no refNodes): >*] - expected: FAIL - - [In-document [Root Node\].queryAll: Universal selector, matching all children of the specified reference element (with refNode Element): >*] - expected: FAIL - - [In-document [Root Node\].query: Universal selector, matching all children of the specified reference element (with refNode Element): >*] - expected: FAIL - - [In-document [Context Element\].queryAll: Universal selector, matching all grandchildren of the specified reference element (with no refNodes): >*>*] - expected: FAIL - - [In-document [Context Element\].query: Universal selector, matching all grandchildren of the specified reference element (with no refNodes): >*>*] - expected: FAIL - - [In-document [Root Node\].queryAll: Universal selector, matching all grandchildren of the specified reference element (with refNode Element): >*>*] - expected: FAIL - - [In-document [Root Node\].query: Universal selector, matching all grandchildren of the specified reference element (with refNode Element): >*>*] - expected: FAIL - - [In-document [Context Element\].queryAll: Universal selector, matching all descendants of the specified reference element (with no refNodes): *] - expected: FAIL - - [In-document [Context Element\].query: Universal selector, matching all descendants of the specified reference element (with no refNodes): *] - expected: FAIL - - [In-document [Root Node\].queryAll: Universal selector, matching all descendants of the specified reference element (with refNode Element): *] - expected: FAIL - - [In-document [Root Node\].query: Universal selector, matching all descendants of the specified reference element (with refNode Element): *] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute presence selector, matching align attribute with value (with no refNodes): .attr-presence-div1[align\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute presence selector, matching align attribute with value (with no refNodes): .attr-presence-div1[align\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute presence selector, matching align attribute with value (with refNode Element): .attr-presence-div1[align\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute presence selector, matching align attribute with value (with refNode Element): .attr-presence-div1[align\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute presence selector, matching align attribute with empty value (with no refNodes): .attr-presence-div2[align\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute presence selector, matching align attribute with empty value (with no refNodes): .attr-presence-div2[align\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute presence selector, matching align attribute with empty value (with refNode Element): .attr-presence-div2[align\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute presence selector, matching align attribute with empty value (with refNode Element): .attr-presence-div2[align\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute presence selector, matching title attribute, case insensitivity (with no refNodes): [TiTlE\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute presence selector, matching title attribute, case insensitivity (with no refNodes): [TiTlE\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute presence selector, matching title attribute, case insensitivity (with refNode Element): [TiTlE\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute presence selector, matching title attribute, case insensitivity (with refNode Element): [TiTlE\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute presence selector, matching custom data-* attribute (with no refNodes): [data-attr-presence\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute presence selector, matching custom data-* attribute (with no refNodes): [data-attr-presence\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute presence selector, matching custom data-* attribute (with refNode Element): [data-attr-presence\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute presence selector, matching custom data-* attribute (with refNode Element): [data-attr-presence\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute presence selector, not matching attribute with similar name (with no refNodes): .attr-presence-div3[align\], .attr-presence-div4[align\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute presence selector, not matching attribute with similar name (with no refNodes): .attr-presence-div3[align\], .attr-presence-div4[align\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute presence selector, not matching attribute with similar name (with refNode Element): .attr-presence-div3[align\], .attr-presence-div4[align\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute presence selector, not matching attribute with similar name (with refNode Element): .attr-presence-div3[align\], .attr-presence-div4[align\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute presence selector, matching attribute with non-ASCII characters (with no refNodes): ul[data-中文\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute presence selector, matching attribute with non-ASCII characters (with no refNodes): ul[data-中文\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute presence selector, matching attribute with non-ASCII characters (with refNode Element): ul[data-中文\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute presence selector, matching attribute with non-ASCII characters (with refNode Element): ul[data-中文\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute presence selector, not matching default option without selected attribute (with no refNodes): #attr-presence-select1 option[selected\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute presence selector, not matching default option without selected attribute (with no refNodes): #attr-presence-select1 option[selected\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute presence selector, not matching default option without selected attribute (with refNode Element): #attr-presence-select1 option[selected\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute presence selector, not matching default option without selected attribute (with refNode Element): #attr-presence-select1 option[selected\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute presence selector, matching option with selected attribute (with no refNodes): #attr-presence-select2 option[selected\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute presence selector, matching option with selected attribute (with no refNodes): #attr-presence-select2 option[selected\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute presence selector, matching option with selected attribute (with refNode Element): #attr-presence-select2 option[selected\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute presence selector, matching option with selected attribute (with refNode Element): #attr-presence-select2 option[selected\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute presence selector, matching multiple options with selected attributes (with no refNodes): #attr-presence-select3 option[selected\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute presence selector, matching multiple options with selected attributes (with no refNodes): #attr-presence-select3 option[selected\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute presence selector, matching multiple options with selected attributes (with refNode Element): #attr-presence-select3 option[selected\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute presence selector, matching multiple options with selected attributes (with refNode Element): #attr-presence-select3 option[selected\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute value selector, matching align attribute with value (with no refNodes): [align="center"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute value selector, matching align attribute with value (with no refNodes): [align="center"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute value selector, matching align attribute with value (with refNode Element): [align="center"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute value selector, matching align attribute with value (with refNode Element): [align="center"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute value selector, matching align attribute with empty value (with no refNodes): [align=""\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute value selector, matching align attribute with empty value (with no refNodes): [align=""\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute value selector, matching align attribute with empty value (with refNode Element): [align=""\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute value selector, matching align attribute with empty value (with refNode Element): [align=""\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute value selector, not matching align attribute with partial value (with no refNodes): [align="c"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute value selector, not matching align attribute with partial value (with no refNodes): [align="c"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute value selector, not matching align attribute with partial value (with refNode Element): [align="c"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute value selector, not matching align attribute with partial value (with refNode Element): [align="c"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute value selector, not matching align attribute with incorrect value (with no refNodes): [align="centera"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute value selector, not matching align attribute with incorrect value (with no refNodes): [align="centera"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute value selector, not matching align attribute with incorrect value (with refNode Element): [align="centera"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute value selector, not matching align attribute with incorrect value (with refNode Element): [align="centera"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute value selector, matching custom data-* attribute with unicode escaped value (with no refNodes): [data-attr-value="\\e9"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute value selector, matching custom data-* attribute with unicode escaped value (with no refNodes): [data-attr-value="\\e9"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute value selector, matching custom data-* attribute with unicode escaped value (with refNode Element): [data-attr-value="\\e9"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute value selector, matching custom data-* attribute with unicode escaped value (with refNode Element): [data-attr-value="\\e9"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute value selector, matching custom data-* attribute with escaped character (with no refNodes): [data-attr-value_foo="\\e9"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute value selector, matching custom data-* attribute with escaped character (with no refNodes): [data-attr-value_foo="\\e9"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute value selector, matching custom data-* attribute with escaped character (with refNode Element): [data-attr-value_foo="\\e9"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute value selector, matching custom data-* attribute with escaped character (with refNode Element): [data-attr-value_foo="\\e9"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute value selector with single-quoted value, matching multiple inputs with type attributes (with no refNodes): input[type='hidden'\],#attr-value input[type='radio'\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute value selector with single-quoted value, matching multiple inputs with type attributes (with no refNodes): input[type='hidden'\],#attr-value input[type='radio'\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute value selector with single-quoted value, matching multiple inputs with type attributes (with refNode Element): input[type='hidden'\],#attr-value input[type='radio'\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute value selector with single-quoted value, matching multiple inputs with type attributes (with refNode Element): input[type='hidden'\],#attr-value input[type='radio'\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute value selector with double-quoted value, matching multiple inputs with type attributes (with no refNodes): input[type="hidden"\],#attr-value input[type='radio'\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute value selector with double-quoted value, matching multiple inputs with type attributes (with no refNodes): input[type="hidden"\],#attr-value input[type='radio'\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute value selector with double-quoted value, matching multiple inputs with type attributes (with refNode Element): input[type="hidden"\],#attr-value input[type='radio'\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute value selector with double-quoted value, matching multiple inputs with type attributes (with refNode Element): input[type="hidden"\],#attr-value input[type='radio'\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute value selector with unquoted value, matching multiple inputs with type attributes (with no refNodes): input[type=hidden\],#attr-value input[type=radio\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute value selector with unquoted value, matching multiple inputs with type attributes (with no refNodes): input[type=hidden\],#attr-value input[type=radio\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute value selector with unquoted value, matching multiple inputs with type attributes (with refNode Element): input[type=hidden\],#attr-value input[type=radio\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute value selector with unquoted value, matching multiple inputs with type attributes (with refNode Element): input[type=hidden\],#attr-value input[type=radio\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute value selector, matching attribute with value using non-ASCII characters (with no refNodes): [data-attr-value=中文\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute value selector, matching attribute with value using non-ASCII characters (with no refNodes): [data-attr-value=中文\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute value selector, matching attribute with value using non-ASCII characters (with refNode Element): [data-attr-value=中文\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute value selector, matching attribute with value using non-ASCII characters (with refNode Element): [data-attr-value=中文\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute whitespace-separated list selector, matching class attribute with value (with no refNodes): [class~="div1"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute whitespace-separated list selector, matching class attribute with value (with no refNodes): [class~="div1"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute whitespace-separated list selector, matching class attribute with value (with refNode Element): [class~="div1"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute whitespace-separated list selector, matching class attribute with value (with refNode Element): [class~="div1"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute whitespace-separated list selector, not matching class attribute with empty value (with no refNodes): [class~=""\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute whitespace-separated list selector, not matching class attribute with empty value (with no refNodes): [class~=""\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute whitespace-separated list selector, not matching class attribute with empty value (with refNode Element): [class~=""\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute whitespace-separated list selector, not matching class attribute with empty value (with refNode Element): [class~=""\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute whitespace-separated list selector, not matching class attribute with partial value (with no refNodes): [data-attr-whitespace~="div"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute whitespace-separated list selector, not matching class attribute with partial value (with no refNodes): [data-attr-whitespace~="div"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute whitespace-separated list selector, not matching class attribute with partial value (with refNode Element): [data-attr-whitespace~="div"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute whitespace-separated list selector, not matching class attribute with partial value (with refNode Element): [data-attr-whitespace~="div"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value (with no refNodes): [data-attr-whitespace~="\\0000e9"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value (with no refNodes): [data-attr-whitespace~="\\0000e9"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value (with refNode Element): [data-attr-whitespace~="\\0000e9"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value (with refNode Element): [data-attr-whitespace~="\\0000e9"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character (with no refNodes): [data-attr-whitespace_foo~="\\e9"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character (with no refNodes): [data-attr-whitespace_foo~="\\e9"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character (with refNode Element): [data-attr-whitespace_foo~="\\e9"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character (with refNode Element): [data-attr-whitespace_foo~="\\e9"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes (with no refNodes): a[rel~='bookmark'\], #attr-whitespace a[rel~='nofollow'\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes (with no refNodes): a[rel~='bookmark'\], #attr-whitespace a[rel~='nofollow'\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes (with refNode Element): a[rel~='bookmark'\], #attr-whitespace a[rel~='nofollow'\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes (with refNode Element): a[rel~='bookmark'\], #attr-whitespace a[rel~='nofollow'\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes (with no refNodes): a[rel~="bookmark"\],#attr-whitespace a[rel~='nofollow'\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes (with no refNodes): a[rel~="bookmark"\],#attr-whitespace a[rel~='nofollow'\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes (with refNode Element): a[rel~="bookmark"\],#attr-whitespace a[rel~='nofollow'\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes (with refNode Element): a[rel~="bookmark"\],#attr-whitespace a[rel~='nofollow'\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes (with no refNodes): a[rel~=bookmark\], #attr-whitespace a[rel~=nofollow\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes (with no refNodes): a[rel~=bookmark\], #attr-whitespace a[rel~=nofollow\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes (with refNode Element): a[rel~=bookmark\], #attr-whitespace a[rel~=nofollow\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes (with refNode Element): a[rel~=bookmark\], #attr-whitespace a[rel~=nofollow\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute whitespace-separated list selector with double-quoted value, not matching value with space (with no refNodes): a[rel~="book mark"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute whitespace-separated list selector with double-quoted value, not matching value with space (with no refNodes): a[rel~="book mark"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute whitespace-separated list selector with double-quoted value, not matching value with space (with refNode Element): a[rel~="book mark"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute whitespace-separated list selector with double-quoted value, not matching value with space (with refNode Element): a[rel~="book mark"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters (with no refNodes): [title~=中文\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters (with no refNodes): [title~=中文\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters (with refNode Element): [title~=中文\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters (with refNode Element): [title~=中文\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute hyphen-separated list selector, not matching unspecified lang attribute (with no refNodes): #attr-hyphen-div1[lang|="en"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute hyphen-separated list selector, not matching unspecified lang attribute (with no refNodes): #attr-hyphen-div1[lang|="en"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute hyphen-separated list selector, not matching unspecified lang attribute (with refNode Element): #attr-hyphen-div1[lang|="en"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute hyphen-separated list selector, not matching unspecified lang attribute (with refNode Element): #attr-hyphen-div1[lang|="en"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute hyphen-separated list selector, matching lang attribute with exact value (with no refNodes): #attr-hyphen-div2[lang|="fr"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute hyphen-separated list selector, matching lang attribute with exact value (with no refNodes): #attr-hyphen-div2[lang|="fr"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute hyphen-separated list selector, matching lang attribute with exact value (with refNode Element): #attr-hyphen-div2[lang|="fr"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute hyphen-separated list selector, matching lang attribute with exact value (with refNode Element): #attr-hyphen-div2[lang|="fr"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute hyphen-separated list selector, matching lang attribute with partial value (with no refNodes): #attr-hyphen-div3[lang|="en"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute hyphen-separated list selector, matching lang attribute with partial value (with no refNodes): #attr-hyphen-div3[lang|="en"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute hyphen-separated list selector, matching lang attribute with partial value (with refNode Element): #attr-hyphen-div3[lang|="en"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute hyphen-separated list selector, matching lang attribute with partial value (with refNode Element): #attr-hyphen-div3[lang|="en"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute hyphen-separated list selector, not matching incorrect value (with no refNodes): #attr-hyphen-div4[lang|="es-AR"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute hyphen-separated list selector, not matching incorrect value (with no refNodes): #attr-hyphen-div4[lang|="es-AR"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute hyphen-separated list selector, not matching incorrect value (with refNode Element): #attr-hyphen-div4[lang|="es-AR"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute hyphen-separated list selector, not matching incorrect value (with refNode Element): #attr-hyphen-div4[lang|="es-AR"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute begins with selector, matching href attributes beginning with specified substring (with no refNodes): a[href^="http://www"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute begins with selector, matching href attributes beginning with specified substring (with no refNodes): a[href^="http://www"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute begins with selector, matching href attributes beginning with specified substring (with refNode Element): a[href^="http://www"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute begins with selector, matching href attributes beginning with specified substring (with refNode Element): a[href^="http://www"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute begins with selector, matching lang attributes beginning with specified substring, (with no refNodes): [lang^="en-"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute begins with selector, matching lang attributes beginning with specified substring, (with no refNodes): [lang^="en-"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute begins with selector, matching lang attributes beginning with specified substring, (with refNode Element): [lang^="en-"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute begins with selector, matching lang attributes beginning with specified substring, (with refNode Element): [lang^="en-"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute begins with selector, not matching class attribute not beginning with specified substring (with no refNodes): [class^=apple\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute begins with selector, not matching class attribute not beginning with specified substring (with no refNodes): [class^=apple\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute begins with selector, not matching class attribute not beginning with specified substring (with refNode Element): [class^=apple\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute begins with selector, not matching class attribute not beginning with specified substring (with refNode Element): [class^=apple\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring (with no refNodes): [class^=' apple'\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring (with no refNodes): [class^=' apple'\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring (with refNode Element): [class^=' apple'\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring (with refNode Element): [class^=' apple'\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring (with no refNodes): [class^=" apple"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring (with no refNodes): [class^=" apple"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring (with refNode Element): [class^=" apple"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring (with refNode Element): [class^=" apple"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring (with no refNodes): [class^= apple\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring (with no refNodes): [class^= apple\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring (with refNode Element): [class^= apple\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring (with refNode Element): [class^= apple\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute ends with selector, matching href attributes ending with specified substring (with no refNodes): a[href$=".org"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute ends with selector, matching href attributes ending with specified substring (with no refNodes): a[href$=".org"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute ends with selector, matching href attributes ending with specified substring (with refNode Element): a[href$=".org"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute ends with selector, matching href attributes ending with specified substring (with refNode Element): a[href$=".org"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute ends with selector, matching lang attributes ending with specified substring, (with no refNodes): [lang$="-CH"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute ends with selector, matching lang attributes ending with specified substring, (with no refNodes): [lang$="-CH"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute ends with selector, matching lang attributes ending with specified substring, (with refNode Element): [lang$="-CH"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute ends with selector, matching lang attributes ending with specified substring, (with refNode Element): [lang$="-CH"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute ends with selector, not matching class attribute not ending with specified substring (with no refNodes): [class$=apple\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute ends with selector, not matching class attribute not ending with specified substring (with no refNodes): [class$=apple\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute ends with selector, not matching class attribute not ending with specified substring (with refNode Element): [class$=apple\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute ends with selector, not matching class attribute not ending with specified substring (with refNode Element): [class$=apple\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring (with no refNodes): [class$='apple '\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring (with no refNodes): [class$='apple '\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring (with refNode Element): [class$='apple '\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring (with refNode Element): [class$='apple '\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring (with no refNodes): [class$="apple "\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring (with no refNodes): [class$="apple "\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring (with refNode Element): [class$="apple "\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring (with refNode Element): [class$="apple "\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring (with no refNodes): [class$=apple \]] - expected: FAIL - - [In-document [Context Element\].query: Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring (with no refNodes): [class$=apple \]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring (with refNode Element): [class$=apple \]] - expected: FAIL - - [In-document [Root Node\].query: Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring (with refNode Element): [class$=apple \]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector, matching href attributes beginning with specified substring (with no refNodes): a[href*="http://www"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector, matching href attributes beginning with specified substring (with no refNodes): a[href*="http://www"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector, matching href attributes beginning with specified substring (with refNode Element): a[href*="http://www"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector, matching href attributes beginning with specified substring (with refNode Element): a[href*="http://www"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector, matching href attributes ending with specified substring (with no refNodes): a[href*=".org"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector, matching href attributes ending with specified substring (with no refNodes): a[href*=".org"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector, matching href attributes ending with specified substring (with refNode Element): a[href*=".org"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector, matching href attributes ending with specified substring (with refNode Element): a[href*=".org"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector, matching href attributes containing specified substring (with no refNodes): a[href*=".example."\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector, matching href attributes containing specified substring (with no refNodes): a[href*=".example."\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector, matching href attributes containing specified substring (with refNode Element): a[href*=".example."\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector, matching href attributes containing specified substring (with refNode Element): a[href*=".example."\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector, matching lang attributes beginning with specified substring, (with no refNodes): [lang*="en-"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector, matching lang attributes beginning with specified substring, (with no refNodes): [lang*="en-"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector, matching lang attributes beginning with specified substring, (with refNode Element): [lang*="en-"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector, matching lang attributes beginning with specified substring, (with refNode Element): [lang*="en-"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector, matching lang attributes ending with specified substring, (with no refNodes): [lang*="-CH"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector, matching lang attributes ending with specified substring, (with no refNodes): [lang*="-CH"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector, matching lang attributes ending with specified substring, (with refNode Element): [lang*="-CH"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector, matching lang attributes ending with specified substring, (with refNode Element): [lang*="-CH"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring (with no refNodes): [class*=' apple'\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring (with no refNodes): [class*=' apple'\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring (with refNode Element): [class*=' apple'\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring (with refNode Element): [class*=' apple'\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector with single-quoted value, matching class attribute ending with specified substring (with no refNodes): [class*='orange '\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector with single-quoted value, matching class attribute ending with specified substring (with no refNodes): [class*='orange '\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector with single-quoted value, matching class attribute ending with specified substring (with refNode Element): [class*='orange '\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector with single-quoted value, matching class attribute ending with specified substring (with refNode Element): [class*='orange '\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector with single-quoted value, matching class attribute containing specified substring (with no refNodes): [class*='ple banana ora'\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector with single-quoted value, matching class attribute containing specified substring (with no refNodes): [class*='ple banana ora'\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector with single-quoted value, matching class attribute containing specified substring (with refNode Element): [class*='ple banana ora'\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector with single-quoted value, matching class attribute containing specified substring (with refNode Element): [class*='ple banana ora'\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring (with no refNodes): [class*=" apple"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring (with no refNodes): [class*=" apple"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring (with refNode Element): [class*=" apple"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring (with refNode Element): [class*=" apple"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector with double-quoted value, matching class attribute ending with specified substring (with no refNodes): [class*="orange "\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector with double-quoted value, matching class attribute ending with specified substring (with no refNodes): [class*="orange "\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector with double-quoted value, matching class attribute ending with specified substring (with refNode Element): [class*="orange "\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector with double-quoted value, matching class attribute ending with specified substring (with refNode Element): [class*="orange "\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector with double-quoted value, matching class attribute containing specified substring (with no refNodes): [class*="ple banana ora"\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector with double-quoted value, matching class attribute containing specified substring (with no refNodes): [class*="ple banana ora"\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector with double-quoted value, matching class attribute containing specified substring (with refNode Element): [class*="ple banana ora"\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector with double-quoted value, matching class attribute containing specified substring (with refNode Element): [class*="ple banana ora"\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector with unquoted value, matching class attribute beginning with specified substring (with no refNodes): [class*= apple\]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector with unquoted value, matching class attribute beginning with specified substring (with no refNodes): [class*= apple\]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector with unquoted value, matching class attribute beginning with specified substring (with refNode Element): [class*= apple\]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector with unquoted value, matching class attribute beginning with specified substring (with refNode Element): [class*= apple\]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector with unquoted value, matching class attribute ending with specified substring (with no refNodes): [class*=orange \]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector with unquoted value, matching class attribute ending with specified substring (with no refNodes): [class*=orange \]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector with unquoted value, matching class attribute ending with specified substring (with refNode Element): [class*=orange \]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector with unquoted value, matching class attribute ending with specified substring (with refNode Element): [class*=orange \]] - expected: FAIL - - [In-document [Context Element\].queryAll: Attribute contains selector with unquoted value, matching class attribute containing specified substring (with no refNodes): [class*= banana \]] - expected: FAIL - - [In-document [Context Element\].query: Attribute contains selector with unquoted value, matching class attribute containing specified substring (with no refNodes): [class*= banana \]] - expected: FAIL - - [In-document [Root Node\].queryAll: Attribute contains selector with unquoted value, matching class attribute containing specified substring (with refNode Element): [class*= banana \]] - expected: FAIL - - [In-document [Root Node\].query: Attribute contains selector with unquoted value, matching class attribute containing specified substring (with refNode Element): [class*= banana \]] - expected: FAIL - - [In-document.queryAll: :root pseudo-class selector, matching document root element (with no refNodes): :root] - expected: FAIL - - [In-document.query: :root pseudo-class selector, matching document root element (with no refNodes): :root] - expected: FAIL - - [In-document [Context Element\].queryAll: :root pseudo-class selector, not matching document root element (with no refNodes): :root] - expected: FAIL - - [In-document [Context Element\].query: :root pseudo-class selector, not matching document root element (with no refNodes): :root] - expected: FAIL - - [In-document [Root Node\].queryAll: :root pseudo-class selector, not matching document root element (with refNode Element): :root] - expected: FAIL - - [In-document [Root Node\].query: :root pseudo-class selector, not matching document root element (with refNode Element): :root] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-child selector, matching the third child element (with no refNodes): :nth-child(3)] - expected: FAIL - - [In-document [Context Element\].query: :nth-child selector, matching the third child element (with no refNodes): :nth-child(3)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-child selector, matching the third child element (with refNode Element): :nth-child(3)] - expected: FAIL - - [In-document [Root Node\].query: :nth-child selector, matching the third child element (with refNode Element): :nth-child(3)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-child selector, matching every third child element (with no refNodes): li:nth-child(3n)] - expected: FAIL - - [In-document [Context Element\].query: :nth-child selector, matching every third child element (with no refNodes): li:nth-child(3n)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-child selector, matching every third child element (with refNode Element): li:nth-child(3n)] - expected: FAIL - - [In-document [Root Node\].query: :nth-child selector, matching every third child element (with refNode Element): li:nth-child(3n)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-child selector, matching every second child element, starting from the fourth (with no refNodes): li:nth-child(2n+4)] - expected: FAIL - - [In-document [Context Element\].query: :nth-child selector, matching every second child element, starting from the fourth (with no refNodes): li:nth-child(2n+4)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-child selector, matching every second child element, starting from the fourth (with refNode Element): li:nth-child(2n+4)] - expected: FAIL - - [In-document [Root Node\].query: :nth-child selector, matching every second child element, starting from the fourth (with refNode Element): li:nth-child(2n+4)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-child selector, matching every fourth child element, starting from the third (with no refNodes): :nth-child(4n-1)] - expected: FAIL - - [In-document [Context Element\].query: :nth-child selector, matching every fourth child element, starting from the third (with no refNodes): :nth-child(4n-1)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-child selector, matching every fourth child element, starting from the third (with refNode Element): :nth-child(4n-1)] - expected: FAIL - - [In-document [Root Node\].query: :nth-child selector, matching every fourth child element, starting from the third (with refNode Element): :nth-child(4n-1)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-last-child selector, matching the third last child element (with no refNodes): :nth-last-child(3)] - expected: FAIL - - [In-document [Context Element\].query: :nth-last-child selector, matching the third last child element (with no refNodes): :nth-last-child(3)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-last-child selector, matching the third last child element (with refNode Element): :nth-last-child(3)] - expected: FAIL - - [In-document [Root Node\].query: :nth-last-child selector, matching the third last child element (with refNode Element): :nth-last-child(3)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-last-child selector, matching every third child element from the end (with no refNodes): li:nth-last-child(3n)] - expected: FAIL - - [In-document [Context Element\].query: :nth-last-child selector, matching every third child element from the end (with no refNodes): li:nth-last-child(3n)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-last-child selector, matching every third child element from the end (with refNode Element): li:nth-last-child(3n)] - expected: FAIL - - [In-document [Root Node\].query: :nth-last-child selector, matching every third child element from the end (with refNode Element): li:nth-last-child(3n)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-last-child selector, matching every second child element from the end, starting from the fourth last (with no refNodes): li:nth-last-child(2n+4)] - expected: FAIL - - [In-document [Context Element\].query: :nth-last-child selector, matching every second child element from the end, starting from the fourth last (with no refNodes): li:nth-last-child(2n+4)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-last-child selector, matching every second child element from the end, starting from the fourth last (with refNode Element): li:nth-last-child(2n+4)] - expected: FAIL - - [In-document [Root Node\].query: :nth-last-child selector, matching every second child element from the end, starting from the fourth last (with refNode Element): li:nth-last-child(2n+4)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-last-child selector, matching every fourth element from the end, starting from the third last (with no refNodes): :nth-last-child(4n-1)] - expected: FAIL - - [In-document [Context Element\].query: :nth-last-child selector, matching every fourth element from the end, starting from the third last (with no refNodes): :nth-last-child(4n-1)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-last-child selector, matching every fourth element from the end, starting from the third last (with refNode Element): :nth-last-child(4n-1)] - expected: FAIL - - [In-document [Root Node\].query: :nth-last-child selector, matching every fourth element from the end, starting from the third last (with refNode Element): :nth-last-child(4n-1)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-of-type selector, matching the third em element (with no refNodes): em:nth-of-type(3)] - expected: FAIL - - [In-document [Context Element\].query: :nth-of-type selector, matching the third em element (with no refNodes): em:nth-of-type(3)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-of-type selector, matching the third em element (with refNode Element): em:nth-of-type(3)] - expected: FAIL - - [In-document [Root Node\].query: :nth-of-type selector, matching the third em element (with refNode Element): em:nth-of-type(3)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-of-type selector, matching every second element of their type (with no refNodes): :nth-of-type(2n)] - expected: FAIL - - [In-document [Context Element\].query: :nth-of-type selector, matching every second element of their type (with no refNodes): :nth-of-type(2n)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-of-type selector, matching every second element of their type (with refNode Element): :nth-of-type(2n)] - expected: FAIL - - [In-document [Root Node\].query: :nth-of-type selector, matching every second element of their type (with refNode Element): :nth-of-type(2n)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-of-type selector, matching every second elemetn of their type, starting from the first (with no refNodes): span:nth-of-type(2n-1)] - expected: FAIL - - [In-document [Context Element\].query: :nth-of-type selector, matching every second elemetn of their type, starting from the first (with no refNodes): span:nth-of-type(2n-1)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-of-type selector, matching every second elemetn of their type, starting from the first (with refNode Element): span:nth-of-type(2n-1)] - expected: FAIL - - [In-document [Root Node\].query: :nth-of-type selector, matching every second elemetn of their type, starting from the first (with refNode Element): span:nth-of-type(2n-1)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-last-of-type selector, matching the thrid last em element (with no refNodes): em:nth-last-of-type(3)] - expected: FAIL - - [In-document [Context Element\].query: :nth-last-of-type selector, matching the thrid last em element (with no refNodes): em:nth-last-of-type(3)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-last-of-type selector, matching the thrid last em element (with refNode Element): em:nth-last-of-type(3)] - expected: FAIL - - [In-document [Root Node\].query: :nth-last-of-type selector, matching the thrid last em element (with refNode Element): em:nth-last-of-type(3)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-last-of-type selector, matching every second last element of their type (with no refNodes): :nth-last-of-type(2n)] - expected: FAIL - - [In-document [Context Element\].query: :nth-last-of-type selector, matching every second last element of their type (with no refNodes): :nth-last-of-type(2n)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-last-of-type selector, matching every second last element of their type (with refNode Element): :nth-last-of-type(2n)] - expected: FAIL - - [In-document [Root Node\].query: :nth-last-of-type selector, matching every second last element of their type (with refNode Element): :nth-last-of-type(2n)] - expected: FAIL - - [In-document [Context Element\].queryAll: :nth-last-of-type selector, matching every second last element of their type, starting from the last (with no refNodes): span:nth-last-of-type(2n-1)] - expected: FAIL - - [In-document [Context Element\].query: :nth-last-of-type selector, matching every second last element of their type, starting from the last (with no refNodes): span:nth-last-of-type(2n-1)] - expected: FAIL - - [In-document [Root Node\].queryAll: :nth-last-of-type selector, matching every second last element of their type, starting from the last (with refNode Element): span:nth-last-of-type(2n-1)] - expected: FAIL - - [In-document [Root Node\].query: :nth-last-of-type selector, matching every second last element of their type, starting from the last (with refNode Element): span:nth-last-of-type(2n-1)] - expected: FAIL - - [In-document [Context Element\].queryAll: :first-of-type selector, matching the first em element (with no refNodes): em:first-of-type] - expected: FAIL - - [In-document [Context Element\].query: :first-of-type selector, matching the first em element (with no refNodes): em:first-of-type] - expected: FAIL - - [In-document [Root Node\].queryAll: :first-of-type selector, matching the first em element (with refNode Element): em:first-of-type] - expected: FAIL - - [In-document [Root Node\].query: :first-of-type selector, matching the first em element (with refNode Element): em:first-of-type] - expected: FAIL - - [In-document [Context Element\].queryAll: :first-of-type selector, matching the first of every type of element (with no refNodes): :first-of-type] - expected: FAIL - - [In-document [Context Element\].query: :first-of-type selector, matching the first of every type of element (with no refNodes): :first-of-type] - expected: FAIL - - [In-document [Root Node\].queryAll: :first-of-type selector, matching the first of every type of element (with refNode Element): :first-of-type] - expected: FAIL - - [In-document [Root Node\].query: :first-of-type selector, matching the first of every type of element (with refNode Element): :first-of-type] - expected: FAIL - - [In-document [Context Element\].queryAll: :first-of-type selector, matching the first td element in each table row (with no refNodes): tr :first-of-type] - expected: FAIL - - [In-document [Context Element\].query: :first-of-type selector, matching the first td element in each table row (with no refNodes): tr :first-of-type] - expected: FAIL - - [In-document [Root Node\].queryAll: :first-of-type selector, matching the first td element in each table row (with refNode Element): tr :first-of-type] - expected: FAIL - - [In-document [Root Node\].query: :first-of-type selector, matching the first td element in each table row (with refNode Element): tr :first-of-type] - expected: FAIL - - [In-document [Context Element\].queryAll: :last-of-type selector, matching the last em elemnet (with no refNodes): em:last-of-type] - expected: FAIL - - [In-document [Context Element\].query: :last-of-type selector, matching the last em elemnet (with no refNodes): em:last-of-type] - expected: FAIL - - [In-document [Root Node\].queryAll: :last-of-type selector, matching the last em elemnet (with refNode Element): em:last-of-type] - expected: FAIL - - [In-document [Root Node\].query: :last-of-type selector, matching the last em elemnet (with refNode Element): em:last-of-type] - expected: FAIL - - [In-document [Context Element\].queryAll: :last-of-type selector, matching the last of every type of element (with no refNodes): :last-of-type] - expected: FAIL - - [In-document [Context Element\].query: :last-of-type selector, matching the last of every type of element (with no refNodes): :last-of-type] - expected: FAIL - - [In-document [Root Node\].queryAll: :last-of-type selector, matching the last of every type of element (with refNode Element): :last-of-type] - expected: FAIL - - [In-document [Root Node\].query: :last-of-type selector, matching the last of every type of element (with refNode Element): :last-of-type] - expected: FAIL - - [In-document [Context Element\].queryAll: :last-of-type selector, matching the last td element in each table row (with no refNodes): tr :last-of-type] - expected: FAIL - - [In-document [Context Element\].query: :last-of-type selector, matching the last td element in each table row (with no refNodes): tr :last-of-type] - expected: FAIL - - [In-document [Root Node\].queryAll: :last-of-type selector, matching the last td element in each table row (with refNode Element): tr :last-of-type] - expected: FAIL - - [In-document [Root Node\].query: :last-of-type selector, matching the last td element in each table row (with refNode Element): tr :last-of-type] - expected: FAIL - - [In-document [Context Element\].queryAll: :first-child pseudo-class selector, matching first child div element (with no refNodes): div:first-child] - expected: FAIL - - [In-document [Context Element\].query: :first-child pseudo-class selector, matching first child div element (with no refNodes): div:first-child] - expected: FAIL - - [In-document [Root Node\].queryAll: :first-child pseudo-class selector, matching first child div element (with refNode Element): div:first-child] - expected: FAIL - - [In-document [Root Node\].query: :first-child pseudo-class selector, matching first child div element (with refNode Element): div:first-child] - expected: FAIL - - [In-document [Context Element\].queryAll: :first-child pseudo-class selector, doesn't match non-first-child elements (with no refNodes): .pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child] - expected: FAIL - - [In-document [Context Element\].query: :first-child pseudo-class selector, doesn't match non-first-child elements (with no refNodes): .pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child] - expected: FAIL - - [In-document [Root Node\].queryAll: :first-child pseudo-class selector, doesn't match non-first-child elements (with refNode Element): .pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child] - expected: FAIL - - [In-document [Root Node\].query: :first-child pseudo-class selector, doesn't match non-first-child elements (with refNode Element): .pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child] - expected: FAIL - - [In-document [Context Element\].queryAll: :first-child pseudo-class selector, matching first-child of multiple elements (with no refNodes): span:first-child] - expected: FAIL - - [In-document [Context Element\].query: :first-child pseudo-class selector, matching first-child of multiple elements (with no refNodes): span:first-child] - expected: FAIL - - [In-document [Root Node\].queryAll: :first-child pseudo-class selector, matching first-child of multiple elements (with refNode Element): span:first-child] - expected: FAIL - - [In-document [Root Node\].query: :first-child pseudo-class selector, matching first-child of multiple elements (with refNode Element): span:first-child] - expected: FAIL - - [In-document [Context Element\].queryAll: :last-child pseudo-class selector, matching last child div element (with no refNodes): div:last-child] - expected: FAIL - - [In-document [Context Element\].query: :last-child pseudo-class selector, matching last child div element (with no refNodes): div:last-child] - expected: FAIL - - [In-document [Root Node\].queryAll: :last-child pseudo-class selector, matching last child div element (with refNode Element): div:last-child] - expected: FAIL - - [In-document [Root Node\].query: :last-child pseudo-class selector, matching last child div element (with refNode Element): div:last-child] - expected: FAIL - - [In-document [Context Element\].queryAll: :last-child pseudo-class selector, doesn't match non-last-child elements (with no refNodes): .pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child] - expected: FAIL - - [In-document [Context Element\].query: :last-child pseudo-class selector, doesn't match non-last-child elements (with no refNodes): .pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child] - expected: FAIL - - [In-document [Root Node\].queryAll: :last-child pseudo-class selector, doesn't match non-last-child elements (with refNode Element): .pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child] - expected: FAIL - - [In-document [Root Node\].query: :last-child pseudo-class selector, doesn't match non-last-child elements (with refNode Element): .pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child] - expected: FAIL - - [In-document [Context Element\].queryAll: :last-child pseudo-class selector, matching first-child of multiple elements (with no refNodes): span:last-child] - expected: FAIL - - [In-document [Context Element\].query: :last-child pseudo-class selector, matching first-child of multiple elements (with no refNodes): span:last-child] - expected: FAIL - - [In-document [Root Node\].queryAll: :last-child pseudo-class selector, matching first-child of multiple elements (with refNode Element): span:last-child] - expected: FAIL - - [In-document [Root Node\].query: :last-child pseudo-class selector, matching first-child of multiple elements (with refNode Element): span:last-child] - expected: FAIL - - [In-document [Context Element\].queryAll: :pseudo-only-child pseudo-class selector, matching all only-child elements (with no refNodes): :only-child] - expected: FAIL - - [In-document [Context Element\].query: :pseudo-only-child pseudo-class selector, matching all only-child elements (with no refNodes): :only-child] - expected: FAIL - - [In-document [Root Node\].queryAll: :pseudo-only-child pseudo-class selector, matching all only-child elements (with refNode Element): :only-child] - expected: FAIL - - [In-document [Root Node\].query: :pseudo-only-child pseudo-class selector, matching all only-child elements (with refNode Element): :only-child] - expected: FAIL - - [In-document [Context Element\].queryAll: :pseudo-only-child pseudo-class selector, matching only-child em elements (with no refNodes): em:only-child] - expected: FAIL - - [In-document [Context Element\].query: :pseudo-only-child pseudo-class selector, matching only-child em elements (with no refNodes): em:only-child] - expected: FAIL - - [In-document [Root Node\].queryAll: :pseudo-only-child pseudo-class selector, matching only-child em elements (with refNode Element): em:only-child] - expected: FAIL - - [In-document [Root Node\].query: :pseudo-only-child pseudo-class selector, matching only-child em elements (with refNode Element): em:only-child] - expected: FAIL - - [In-document [Context Element\].queryAll: :pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type (with no refNodes): :only-of-type] - expected: FAIL - - [In-document [Context Element\].query: :pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type (with no refNodes): :only-of-type] - expected: FAIL - - [In-document [Root Node\].queryAll: :pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type (with refNode Element): :only-of-type] - expected: FAIL - - [In-document [Root Node\].query: :pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type (with refNode Element): :only-of-type] - expected: FAIL - - [In-document [Context Element\].queryAll: :pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type (with no refNodes): em:only-of-type] - expected: FAIL - - [In-document [Context Element\].query: :pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type (with no refNodes): em:only-of-type] - expected: FAIL - - [In-document [Root Node\].queryAll: :pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type (with refNode Element): em:only-of-type] - expected: FAIL - - [In-document [Root Node\].query: :pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type (with refNode Element): em:only-of-type] - expected: FAIL - - [In-document [Context Element\].queryAll: :empty pseudo-class selector, matching empty p elements (with no refNodes): p:empty] - expected: FAIL - - [In-document [Context Element\].query: :empty pseudo-class selector, matching empty p elements (with no refNodes): p:empty] - expected: FAIL - - [In-document [Root Node\].queryAll: :empty pseudo-class selector, matching empty p elements (with refNode Element): p:empty] - expected: FAIL - - [In-document [Root Node\].query: :empty pseudo-class selector, matching empty p elements (with refNode Element): p:empty] - expected: FAIL - - [In-document [Context Element\].queryAll: :empty pseudo-class selector, matching all empty elements (with no refNodes): :empty] - expected: FAIL - - [In-document [Context Element\].query: :empty pseudo-class selector, matching all empty elements (with no refNodes): :empty] - expected: FAIL - - [In-document [Root Node\].queryAll: :empty pseudo-class selector, matching all empty elements (with refNode Element): :empty] - expected: FAIL - - [In-document [Root Node\].query: :empty pseudo-class selector, matching all empty elements (with refNode Element): :empty] - expected: FAIL - - [In-document [Context Element\].queryAll: :link and :visited pseudo-class selectors, matching a and area elements with href attributes (with no refNodes): :link, #pseudo-link :visited] - expected: FAIL - - [In-document [Context Element\].query: :link and :visited pseudo-class selectors, matching a and area elements with href attributes (with no refNodes): :link, #pseudo-link :visited] - expected: FAIL - - [In-document [Root Node\].queryAll: :link and :visited pseudo-class selectors, matching a and area elements with href attributes (with refNode Element): :link, #pseudo-link :visited] - expected: FAIL - - [In-document [Root Node\].query: :link and :visited pseudo-class selectors, matching a and area elements with href attributes (with refNode Element): :link, #pseudo-link :visited] - expected: FAIL - - [In-document [Context Element\].queryAll: :link and :visited pseudo-class selectors, matching link elements with href attributes (with no refNodes): :link, #head :visited] - expected: FAIL - - [In-document [Context Element\].query: :link and :visited pseudo-class selectors, matching link elements with href attributes (with no refNodes): :link, #head :visited] - expected: FAIL - - [In-document [Root Node\].queryAll: :link and :visited pseudo-class selectors, matching link elements with href attributes (with refNode Element): :link, #head :visited] - expected: FAIL - - [In-document [Root Node\].query: :link and :visited pseudo-class selectors, matching link elements with href attributes (with refNode Element): :link, #head :visited] - expected: FAIL - - [In-document.queryAll: :target pseudo-class selector, matching the element referenced by the URL fragment identifier (with no refNodes): :target] - expected: FAIL - - [In-document.query: :target pseudo-class selector, matching the element referenced by the URL fragment identifier (with no refNodes): :target] - expected: FAIL - - [In-document.queryAll: :lang pseudo-class selector, matching inherited language (1) (with no refNodes): #pseudo-lang-div1:lang(en)] - expected: FAIL - - [In-document.query: :lang pseudo-class selector, matching inherited language (1) (with no refNodes): #pseudo-lang-div1:lang(en)] - expected: FAIL - - [In-document.queryAll: :lang pseudo-class selector, matching specified language with exact value (1) (with no refNodes): #pseudo-lang-div2:lang(fr)] - expected: FAIL - - [In-document.query: :lang pseudo-class selector, matching specified language with exact value (1) (with no refNodes): #pseudo-lang-div2:lang(fr)] - expected: FAIL - - [In-document.queryAll: :lang pseudo-class selector, matching specified language with partial value (1) (with no refNodes): #pseudo-lang-div3:lang(en)] - expected: FAIL - - [In-document.query: :lang pseudo-class selector, matching specified language with partial value (1) (with no refNodes): #pseudo-lang-div3:lang(en)] - expected: FAIL - - [In-document.queryAll: :lang pseudo-class selector, not matching incorrect language (with no refNodes): #pseudo-lang-div4:lang(es-AR)] - expected: FAIL - - [In-document.query: :lang pseudo-class selector, not matching incorrect language (with no refNodes): #pseudo-lang-div4:lang(es-AR)] - expected: FAIL - - [In-document.queryAll: :enabled pseudo-class selector, matching all enabled form controls (1) (with no refNodes): #pseudo-ui :enabled] - expected: FAIL - - [In-document.query: :enabled pseudo-class selector, matching all enabled form controls (1) (with no refNodes): #pseudo-ui :enabled] - expected: FAIL - - [In-document.queryAll: :enabled pseudo-class selector, matching all disabled form controls (1) (with no refNodes): #pseudo-ui :disabled] - expected: FAIL - - [In-document.query: :enabled pseudo-class selector, matching all disabled form controls (1) (with no refNodes): #pseudo-ui :disabled] - expected: FAIL - - [In-document.queryAll: :checked pseudo-class selector, matching checked radio buttons and checkboxes (1) (with no refNodes): #pseudo-ui :checked] - expected: FAIL - - [In-document.query: :checked pseudo-class selector, matching checked radio buttons and checkboxes (1) (with no refNodes): #pseudo-ui :checked] - expected: FAIL - - [In-document.queryAll: :not pseudo-class selector, matching (1) (with no refNodes): #not>:not(div)] - expected: FAIL - - [In-document.query: :not pseudo-class selector, matching (1) (with no refNodes): #not>:not(div)] - expected: FAIL - - [In-document.queryAll: :not pseudo-class selector, matching (1) (with no refNodes): #not * :not(:first-child)] - expected: FAIL - - [In-document.query: :not pseudo-class selector, matching (1) (with no refNodes): #not * :not(:first-child)] - expected: FAIL - - [In-document.queryAll: :not pseudo-class selector, matching nothing (with no refNodes): :not(*)] - expected: FAIL - - [In-document.query: :not pseudo-class selector, matching nothing (with no refNodes): :not(*)] - expected: FAIL - - [In-document.queryAll: :not pseudo-class selector, matching nothing (with no refNodes): :not(*|*)] - expected: FAIL - - [In-document.query: :not pseudo-class selector, matching nothing (with no refNodes): :not(*|*)] - expected: FAIL - - [In-document.queryAll: :first-line pseudo-element (one-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element:first-line] - expected: FAIL - - [In-document.query: :first-line pseudo-element (one-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element:first-line] - expected: FAIL - - [In-document.queryAll: ::first-line pseudo-element (two-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element::first-line] - expected: FAIL - - [In-document.query: ::first-line pseudo-element (two-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element::first-line] - expected: FAIL - - [In-document.queryAll: :first-letter pseudo-element (one-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element:first-letter] - expected: FAIL - - [In-document.query: :first-letter pseudo-element (one-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element:first-letter] - expected: FAIL - - [In-document.queryAll: ::first-letter pseudo-element (two-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element::first-letter] - expected: FAIL - - [In-document.query: ::first-letter pseudo-element (two-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element::first-letter] - expected: FAIL - - [In-document.queryAll: :before pseudo-element (one-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element:before] - expected: FAIL - - [In-document.query: :before pseudo-element (one-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element:before] - expected: FAIL - - [In-document.queryAll: ::before pseudo-element (two-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element::before] - expected: FAIL - - [In-document.query: ::before pseudo-element (two-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element::before] - expected: FAIL - - [In-document.queryAll: :after pseudo-element (one-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element:after] - expected: FAIL - - [In-document.query: :after pseudo-element (one-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element:after] - expected: FAIL - - [In-document.queryAll: ::after pseudo-element (two-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element::after] - expected: FAIL - - [In-document.query: ::after pseudo-element (two-colon syntax) selector, not matching any elements (with no refNodes): #pseudo-element::after] - expected: FAIL - - [In-document.queryAll: Class selector, matching element with specified class (1) (with no refNodes): .class-p] - expected: FAIL - - [In-document.query: Class selector, matching element with specified class (1) (with no refNodes): .class-p] - expected: FAIL - - [In-document.queryAll: Class selector, chained, matching only elements with all specified classes (1) (with no refNodes): #class .apple.orange.banana] - expected: FAIL - - [In-document.query: Class selector, chained, matching only elements with all specified classes (1) (with no refNodes): #class .apple.orange.banana] - expected: FAIL - - [In-document.queryAll: Class Selector, chained, with type selector (1) (with no refNodes): div.apple.banana.orange] - expected: FAIL - - [In-document.query: Class Selector, chained, with type selector (1) (with no refNodes): div.apple.banana.orange] - expected: FAIL - - [In-document.queryAll: Class selector, matching element with class value using non-ASCII characters (with no refNodes): .台北Táiběi] - expected: FAIL - - [In-document.query: Class selector, matching element with class value using non-ASCII characters (with no refNodes): .台北Táiběi] - expected: FAIL - - [In-document.queryAll: Class selector, matching multiple elements with class value using non-ASCII characters (1) (with no refNodes): .台北] - expected: FAIL - - [In-document.query: Class selector, matching multiple elements with class value using non-ASCII characters (1) (with no refNodes): .台北] - expected: FAIL - - [In-document.queryAll: Class selector, chained, matching element with multiple class values using non-ASCII characters (with no refNodes): .台北Táiběi.台北] - expected: FAIL - - [In-document.query: Class selector, chained, matching element with multiple class values using non-ASCII characters (with no refNodes): .台北Táiběi.台北] - expected: FAIL - - [In-document.queryAll: Class selector, matching element with class with escaped character (1) (with no refNodes): .foo\\:bar] - expected: FAIL - - [In-document.query: Class selector, matching element with class with escaped character (1) (with no refNodes): .foo\\:bar] - expected: FAIL - - [In-document.queryAll: Class selector, matching element with class with escaped character (1) (with no refNodes): .test\\.foo\\[5\\\]bar] - expected: FAIL - - [In-document.query: Class selector, matching element with class with escaped character (1) (with no refNodes): .test\\.foo\\[5\\\]bar] - expected: FAIL - - [In-document.queryAll: ID selector, matching element with specified id (1) (with no refNodes): #id #id-div1] - expected: FAIL - - [In-document.query: ID selector, matching element with specified id (1) (with no refNodes): #id #id-div1] - expected: FAIL - - [In-document.queryAll: ID selector, chained, matching element with specified id (1) (with no refNodes): #id-div1, #id-div1] - expected: FAIL - - [In-document.query: ID selector, chained, matching element with specified id (1) (with no refNodes): #id-div1, #id-div1] - expected: FAIL - - [In-document.queryAll: ID selector, chained, matching element with specified id (1) (with no refNodes): #id-div1, #id-div2] - expected: FAIL - - [In-document.query: ID selector, chained, matching element with specified id (1) (with no refNodes): #id-div1, #id-div2] - expected: FAIL - - [In-document.queryAll: ID Selector, chained, with type selector (1) (with no refNodes): div#id-div1, div#id-div2] - expected: FAIL - - [In-document.query: ID Selector, chained, with type selector (1) (with no refNodes): div#id-div1, div#id-div2] - expected: FAIL - - [In-document.queryAll: ID selector, not matching non-existent descendant (with no refNodes): #id #none] - expected: FAIL - - [In-document.query: ID selector, not matching non-existent descendant (with no refNodes): #id #none] - expected: FAIL - - [In-document.queryAll: ID selector, not matching non-existent ancestor (with no refNodes): #none #id-div1] - expected: FAIL - - [In-document.query: ID selector, not matching non-existent ancestor (with no refNodes): #none #id-div1] - expected: FAIL - - [In-document.queryAll: ID selector, matching multiple elements with duplicate id (1) (with no refNodes): #id-li-duplicate] - expected: FAIL - - [In-document.query: ID selector, matching multiple elements with duplicate id (1) (with no refNodes): #id-li-duplicate] - expected: FAIL - - [In-document.queryAll: ID selector, matching id value using non-ASCII characters (with no refNodes): #台北Táiběi] - expected: FAIL - - [In-document.query: ID selector, matching id value using non-ASCII characters (with no refNodes): #台北Táiběi] - expected: FAIL - - [In-document.queryAll: ID selector, matching id value using non-ASCII characters (1) (with no refNodes): #台北] - expected: FAIL - - [In-document.query: ID selector, matching id value using non-ASCII characters (1) (with no refNodes): #台北] - expected: FAIL - - [In-document.queryAll: ID selector, matching id values using non-ASCII characters (with no refNodes): #台北Táiběi, #台北] - expected: FAIL - - [In-document.query: ID selector, matching id values using non-ASCII characters (with no refNodes): #台北Táiběi, #台北] - expected: FAIL - - [In-document.queryAll: ID selector, matching element with id with escaped character (with no refNodes): #\\#foo\\:bar] - expected: FAIL - - [In-document.query: ID selector, matching element with id with escaped character (with no refNodes): #\\#foo\\:bar] - expected: FAIL - - [In-document.queryAll: ID selector, matching element with id with escaped character (with no refNodes): #test\\.foo\\[5\\\]bar] - expected: FAIL - - [In-document.query: ID selector, matching element with id with escaped character (with no refNodes): #test\\.foo\\[5\\\]bar] - expected: FAIL - - [In-document.queryAll: Namespace selector, matching element with any namespace (with no refNodes): #any-namespace *|div] - expected: FAIL - - [In-document.query: Namespace selector, matching element with any namespace (with no refNodes): #any-namespace *|div] - expected: FAIL - - [In-document.queryAll: Namespace selector, matching div elements in no namespace only (with no refNodes): #no-namespace |div] - expected: FAIL - - [In-document.query: Namespace selector, matching div elements in no namespace only (with no refNodes): #no-namespace |div] - expected: FAIL - - [In-document.queryAll: Namespace selector, matching any elements in no namespace only (with no refNodes): #no-namespace |*] - expected: FAIL - - [In-document.query: Namespace selector, matching any elements in no namespace only (with no refNodes): #no-namespace |*] - expected: FAIL - - [In-document.queryAll: Descendant combinator, matching element that is a descendant of an element with id (1) (with no refNodes): #descendant div] - expected: FAIL - - [In-document.query: Descendant combinator, matching element that is a descendant of an element with id (1) (with no refNodes): #descendant div] - expected: FAIL - - [In-document.queryAll: Descendant combinator, matching element with id that is a descendant of an element (1) (with no refNodes): body #descendant-div1] - expected: FAIL - - [In-document.query: Descendant combinator, matching element with id that is a descendant of an element (1) (with no refNodes): body #descendant-div1] - expected: FAIL - - [In-document.queryAll: Descendant combinator, matching element with id that is a descendant of an element (1) (with no refNodes): div #descendant-div1] - expected: FAIL - - [In-document.query: Descendant combinator, matching element with id that is a descendant of an element (1) (with no refNodes): div #descendant-div1] - expected: FAIL - - [In-document.queryAll: Descendant combinator, matching element with id that is a descendant of an element with id (1) (with no refNodes): #descendant #descendant-div2] - expected: FAIL - - [In-document.query: Descendant combinator, matching element with id that is a descendant of an element with id (1) (with no refNodes): #descendant #descendant-div2] - expected: FAIL - - [In-document.queryAll: Descendant combinator, matching element with class that is a descendant of an element with id (1) (with no refNodes): #descendant .descendant-div2] - expected: FAIL - - [In-document.query: Descendant combinator, matching element with class that is a descendant of an element with id (1) (with no refNodes): #descendant .descendant-div2] - expected: FAIL - - [In-document.queryAll: Descendant combinator, matching element with class that is a descendant of an element with class (1) (with no refNodes): .descendant-div1 .descendant-div3] - expected: FAIL - - [In-document.query: Descendant combinator, matching element with class that is a descendant of an element with class (1) (with no refNodes): .descendant-div1 .descendant-div3] - expected: FAIL - - [In-document.queryAll: Descendant combinator, not matching element with id that is not a descendant of an element with id (with no refNodes): #descendant-div1 #descendant-div4] - expected: FAIL - - [In-document.query: Descendant combinator, not matching element with id that is not a descendant of an element with id (with no refNodes): #descendant-div1 #descendant-div4] - expected: FAIL - - [In-document.queryAll: Descendant combinator, whitespace characters (1) (with no refNodes): #descendant\t\r\n#descendant-div2] - expected: FAIL - - [In-document.query: Descendant combinator, whitespace characters (1) (with no refNodes): #descendant\t\r\n#descendant-div2] - expected: FAIL - - [In-document.queryAll: Child combinator, matching element that is a child of an element with id (1) (with no refNodes): #child>div] - expected: FAIL - - [In-document.query: Child combinator, matching element that is a child of an element with id (1) (with no refNodes): #child>div] - expected: FAIL - - [In-document.queryAll: Child combinator, matching element with id that is a child of an element (1) (with no refNodes): div>#child-div1] - expected: FAIL - - [In-document.query: Child combinator, matching element with id that is a child of an element (1) (with no refNodes): div>#child-div1] - expected: FAIL - - [In-document.queryAll: Child combinator, matching element with id that is a child of an element with id (1) (with no refNodes): #child>#child-div1] - expected: FAIL - - [In-document.query: Child combinator, matching element with id that is a child of an element with id (1) (with no refNodes): #child>#child-div1] - expected: FAIL - - [In-document.queryAll: Child combinator, matching element with id that is a child of an element with class (1) (with no refNodes): #child-div1>.child-div2] - expected: FAIL - - [In-document.query: Child combinator, matching element with id that is a child of an element with class (1) (with no refNodes): #child-div1>.child-div2] - expected: FAIL - - [In-document.queryAll: Child combinator, matching element with class that is a child of an element with class (1) (with no refNodes): .child-div1>.child-div2] - expected: FAIL - - [In-document.query: Child combinator, matching element with class that is a child of an element with class (1) (with no refNodes): .child-div1>.child-div2] - expected: FAIL - - [In-document.queryAll: Child combinator, not matching element with id that is not a child of an element with id (with no refNodes): #child>#child-div3] - expected: FAIL - - [In-document.query: Child combinator, not matching element with id that is not a child of an element with id (with no refNodes): #child>#child-div3] - expected: FAIL - - [In-document.queryAll: Child combinator, not matching element with id that is not a child of an element with class (with no refNodes): #child-div1>.child-div3] - expected: FAIL - - [In-document.query: Child combinator, not matching element with id that is not a child of an element with class (with no refNodes): #child-div1>.child-div3] - expected: FAIL - - [In-document.queryAll: Child combinator, not matching element with class that is not a child of an element with class (with no refNodes): .child-div1>.child-div3] - expected: FAIL - - [In-document.query: Child combinator, not matching element with class that is not a child of an element with class (with no refNodes): .child-div1>.child-div3] - expected: FAIL - - [In-document.queryAll: Child combinator, surrounded by whitespace (1) (with no refNodes): #child-div1\t\r\n>\t\r\n#child-div2] - expected: FAIL - - [In-document.query: Child combinator, surrounded by whitespace (1) (with no refNodes): #child-div1\t\r\n>\t\r\n#child-div2] - expected: FAIL - - [In-document.queryAll: Child combinator, whitespace after (1) (with no refNodes): #child-div1>\t\r\n#child-div2] - expected: FAIL - - [In-document.query: Child combinator, whitespace after (1) (with no refNodes): #child-div1>\t\r\n#child-div2] - expected: FAIL - - [In-document.queryAll: Child combinator, whitespace before (1) (with no refNodes): #child-div1\t\r\n>#child-div2] - expected: FAIL - - [In-document.query: Child combinator, whitespace before (1) (with no refNodes): #child-div1\t\r\n>#child-div2] - expected: FAIL - - [In-document.queryAll: Child combinator, no whitespace (1) (with no refNodes): #child-div1>#child-div2] - expected: FAIL - - [In-document.query: Child combinator, no whitespace (1) (with no refNodes): #child-div1>#child-div2] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id (1) (with no refNodes): #adjacent-div2+div] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id (1) (with no refNodes): #adjacent-div2+div] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element (1) (with no refNodes): div+#adjacent-div4] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element (1) (with no refNodes): div+#adjacent-div4] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id (1) (with no refNodes): #adjacent-div2+#adjacent-div4] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id (1) (with no refNodes): #adjacent-div2+#adjacent-div4] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id (1) (with no refNodes): #adjacent-div2+.adjacent-div4] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id (1) (with no refNodes): #adjacent-div2+.adjacent-div4] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class (1) (with no refNodes): .adjacent-div2+.adjacent-div4] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class (1) (with no refNodes): .adjacent-div2+.adjacent-div4] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element (1) (with no refNodes): #adjacent div+p] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element (1) (with no refNodes): #adjacent div+p] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id (with no refNodes): #adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id (with no refNodes): #adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, surrounded by whitespace (1) (with no refNodes): #adjacent-p2\t\r\n+\t\r\n#adjacent-p3] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, surrounded by whitespace (1) (with no refNodes): #adjacent-p2\t\r\n+\t\r\n#adjacent-p3] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, whitespace after (1) (with no refNodes): #adjacent-p2+\t\r\n#adjacent-p3] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, whitespace after (1) (with no refNodes): #adjacent-p2+\t\r\n#adjacent-p3] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, whitespace before (1) (with no refNodes): #adjacent-p2\t\r\n+#adjacent-p3] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, whitespace before (1) (with no refNodes): #adjacent-p2\t\r\n+#adjacent-p3] - expected: FAIL - - [In-document.queryAll: Adjacent sibling combinator, no whitespace (1) (with no refNodes): #adjacent-p2+#adjacent-p3] - expected: FAIL - - [In-document.query: Adjacent sibling combinator, no whitespace (1) (with no refNodes): #adjacent-p2+#adjacent-p3] - expected: FAIL - - [In-document.queryAll: General sibling combinator, matching element that is a sibling of an element with id (1) (with no refNodes): #sibling-div2~div] - expected: FAIL - - [In-document.query: General sibling combinator, matching element that is a sibling of an element with id (1) (with no refNodes): #sibling-div2~div] - expected: FAIL - - [In-document.queryAll: General sibling combinator, matching element with id that is a sibling of an element (1) (with no refNodes): div~#sibling-div4] - expected: FAIL - - [In-document.query: General sibling combinator, matching element with id that is a sibling of an element (1) (with no refNodes): div~#sibling-div4] - expected: FAIL - - [In-document.queryAll: General sibling combinator, matching element with id that is a sibling of an element with id (1) (with no refNodes): #sibling-div2~#sibling-div4] - expected: FAIL - - [In-document.query: General sibling combinator, matching element with id that is a sibling of an element with id (1) (with no refNodes): #sibling-div2~#sibling-div4] - expected: FAIL - - [In-document.queryAll: General sibling combinator, matching element with class that is a sibling of an element with id (1) (with no refNodes): #sibling-div2~.sibling-div] - expected: FAIL - - [In-document.query: General sibling combinator, matching element with class that is a sibling of an element with id (1) (with no refNodes): #sibling-div2~.sibling-div] - expected: FAIL - - [In-document.queryAll: General sibling combinator, matching p element that is a sibling of a div element (1) (with no refNodes): #sibling div~p] - expected: FAIL - - [In-document.query: General sibling combinator, matching p element that is a sibling of a div element (1) (with no refNodes): #sibling div~p] - expected: FAIL - - [In-document.queryAll: General sibling combinator, not matching element with id that is not a sibling after a p element (1) (with no refNodes): #sibling>p~div] - expected: FAIL - - [In-document.query: General sibling combinator, not matching element with id that is not a sibling after a p element (1) (with no refNodes): #sibling>p~div] - expected: FAIL - - [In-document.queryAll: General sibling combinator, not matching element with id that is not a sibling after an element with id (with no refNodes): #sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1] - expected: FAIL - - [In-document.query: General sibling combinator, not matching element with id that is not a sibling after an element with id (with no refNodes): #sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1] - expected: FAIL - - [In-document.queryAll: General sibling combinator, surrounded by whitespace (1) (with no refNodes): #sibling-p2\t\r\n~\t\r\n#sibling-p3] - expected: FAIL - - [In-document.query: General sibling combinator, surrounded by whitespace (1) (with no refNodes): #sibling-p2\t\r\n~\t\r\n#sibling-p3] - expected: FAIL - - [In-document.queryAll: General sibling combinator, whitespace after (1) (with no refNodes): #sibling-p2~\t\r\n#sibling-p3] - expected: FAIL - - [In-document.query: General sibling combinator, whitespace after (1) (with no refNodes): #sibling-p2~\t\r\n#sibling-p3] - expected: FAIL - - [In-document.queryAll: General sibling combinator, whitespace before (1) (with no refNodes): #sibling-p2\t\r\n~#sibling-p3] - expected: FAIL - - [In-document.query: General sibling combinator, whitespace before (1) (with no refNodes): #sibling-p2\t\r\n~#sibling-p3] - expected: FAIL - - [In-document.queryAll: General sibling combinator, no whitespace (1) (with no refNodes): #sibling-p2~#sibling-p3] - expected: FAIL - - [In-document.query: General sibling combinator, no whitespace (1) (with no refNodes): #sibling-p2~#sibling-p3] - expected: FAIL - - [In-document.queryAll: Syntax, group of selectors separator, surrounded by whitespace (1) (with no refNodes): #group em\t\r \n,\t\r \n#group strong] - expected: FAIL - - [In-document.query: Syntax, group of selectors separator, surrounded by whitespace (1) (with no refNodes): #group em\t\r \n,\t\r \n#group strong] - expected: FAIL - - [In-document.queryAll: Syntax, group of selectors separator, whitespace after (1) (with no refNodes): #group em,\t\r\n#group strong] - expected: FAIL - - [In-document.query: Syntax, group of selectors separator, whitespace after (1) (with no refNodes): #group em,\t\r\n#group strong] - expected: FAIL - - [In-document.queryAll: Syntax, group of selectors separator, whitespace before (1) (with no refNodes): #group em\t\r\n,#group strong] - expected: FAIL - - [In-document.query: Syntax, group of selectors separator, whitespace before (1) (with no refNodes): #group em\t\r\n,#group strong] - expected: FAIL - - [In-document.queryAll: Syntax, group of selectors separator, no whitespace (1) (with no refNodes): #group em,#group strong] - expected: FAIL - - [In-document.query: Syntax, group of selectors separator, no whitespace (1) (with no refNodes): #group em,#group strong] - expected: FAIL - - [In-document.queryAll: Class selector, matching element with class value using non-ASCII characters (2) (with no refNodes): .台北Táiběi] - expected: FAIL - - [In-document.query: Class selector, matching element with class value using non-ASCII characters (2) (with no refNodes): .台北Táiběi] - expected: FAIL - - [In-document.queryAll: Class selector, chained, matching element with multiple class values using non-ASCII characters (2) (with no refNodes): .台北Táiběi.台北] - expected: FAIL - - [In-document.query: Class selector, chained, matching element with multiple class values using non-ASCII characters (2) (with no refNodes): .台北Táiběi.台北] - expected: FAIL - - [In-document.queryAll: ID selector, matching id value using non-ASCII characters (3) (with no refNodes): #台北Táiběi] - expected: FAIL - - [In-document.query: ID selector, matching id value using non-ASCII characters (3) (with no refNodes): #台北Táiběi] - expected: FAIL - - [In-document.queryAll: ID selector, matching id value using non-ASCII characters (4) (with no refNodes): #台北] - expected: FAIL - - [In-document.query: ID selector, matching id value using non-ASCII characters (4) (with no refNodes): #台北] - expected: FAIL - - [In-document.queryAll: ID selector, matching id values using non-ASCII characters (2) (with no refNodes): #台北Táiběi, #台北] - expected: FAIL - - [In-document.query: ID selector, matching id values using non-ASCII characters (2) (with no refNodes): #台北Táiběi, #台北] - expected: FAIL - - [In-document.queryAll: Descendant combinator '>>', matching element that is a descendant of an element with id (1) (with no refNodes): #descendant>>div] - expected: FAIL - - [In-document.query: Descendant combinator '>>', matching element that is a descendant of an element with id (1) (with no refNodes): #descendant>>div] - expected: FAIL - - [In-document.queryAll: Descendant combinator '>>', matching element with id that is a descendant of an element (1) (with no refNodes): body>>#descendant-div1] - expected: FAIL - - [In-document.query: Descendant combinator '>>', matching element with id that is a descendant of an element (1) (with no refNodes): body>>#descendant-div1] - expected: FAIL - - [In-document.queryAll: Descendant combinator '>>', matching element with id that is a descendant of an element (1) (with no refNodes): div>>#descendant-div1] - expected: FAIL - - [In-document.query: Descendant combinator '>>', matching element with id that is a descendant of an element (1) (with no refNodes): div>>#descendant-div1] - expected: FAIL - - [In-document.queryAll: Descendant combinator '>>', matching element with id that is a descendant of an element with id (1) (with no refNodes): #descendant>>#descendant-div2] - expected: FAIL - - [In-document.query: Descendant combinator '>>', matching element with id that is a descendant of an element with id (1) (with no refNodes): #descendant>>#descendant-div2] - expected: FAIL - - [In-document.queryAll: Descendant combinator '>>', matching element with class that is a descendant of an element with id (1) (with no refNodes): #descendant>>.descendant-div2] - expected: FAIL - - [In-document.query: Descendant combinator '>>', matching element with class that is a descendant of an element with id (1) (with no refNodes): #descendant>>.descendant-div2] - expected: FAIL - - [In-document.queryAll: Descendant combinator, '>>', matching element with class that is a descendant of an element with class (1) (with no refNodes): .descendant-div1>>.descendant-div3] - expected: FAIL - - [In-document.query: Descendant combinator, '>>', matching element with class that is a descendant of an element with class (1) (with no refNodes): .descendant-div1>>.descendant-div3] - expected: FAIL - - [In-document.queryAll: Descendant combinator '>>', not matching element with id that is not a descendant of an element with id (with no refNodes): #descendant-div1>>#descendant-div4] - expected: FAIL - - [In-document.query: Descendant combinator '>>', not matching element with id that is not a descendant of an element with id (with no refNodes): #descendant-div1>>#descendant-div4] - expected: FAIL - diff --git a/testing/web-platform/meta/server-timing/test_server_timing.html.ini b/testing/web-platform/meta/server-timing/test_server_timing.html.ini new file mode 100644 index 000000000000..34c4fdf269d8 --- /dev/null +++ b/testing/web-platform/meta/server-timing/test_server_timing.html.ini @@ -0,0 +1,12 @@ +[test_server_timing.html] + type: testharness + expected: TIMEOUT + [Untitled] + expected: FAIL + + [Untitled 1] + expected: FAIL + + [Untitled 2] + expected: FAIL + diff --git a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-add.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-add.https.html.ini index d8804ecde2d4..b67f2f79fd23 100644 --- a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-add.https.html.ini +++ b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-add.https.html.ini @@ -3,9 +3,3 @@ [Cache.add with request with null body (not consumed)] expected: FAIL - [Cache.add with 206 response] - expected: FAIL - - [Cache.addAll with 206 response] - expected: FAIL - diff --git a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-match.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-match.https.html.ini new file mode 100644 index 000000000000..6135da4006a0 --- /dev/null +++ b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-match.https.html.ini @@ -0,0 +1,5 @@ +[cache-storage-match.https.html] + type: testharness + [CacheStorageMatch with empty cache name provided] + expected: FAIL + diff --git a/testing/web-platform/meta/service-workers/cache-storage/window/cache-add.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/window/cache-add.https.html.ini index d8804ecde2d4..b67f2f79fd23 100644 --- a/testing/web-platform/meta/service-workers/cache-storage/window/cache-add.https.html.ini +++ b/testing/web-platform/meta/service-workers/cache-storage/window/cache-add.https.html.ini @@ -3,9 +3,3 @@ [Cache.add with request with null body (not consumed)] expected: FAIL - [Cache.add with 206 response] - expected: FAIL - - [Cache.addAll with 206 response] - expected: FAIL - diff --git a/testing/web-platform/meta/service-workers/cache-storage/window/cache-storage-match.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/window/cache-storage-match.https.html.ini new file mode 100644 index 000000000000..6135da4006a0 --- /dev/null +++ b/testing/web-platform/meta/service-workers/cache-storage/window/cache-storage-match.https.html.ini @@ -0,0 +1,5 @@ +[cache-storage-match.https.html] + type: testharness + [CacheStorageMatch with empty cache name provided] + expected: FAIL + diff --git a/testing/web-platform/meta/service-workers/cache-storage/worker/cache-add.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/worker/cache-add.https.html.ini index d8804ecde2d4..b67f2f79fd23 100644 --- a/testing/web-platform/meta/service-workers/cache-storage/worker/cache-add.https.html.ini +++ b/testing/web-platform/meta/service-workers/cache-storage/worker/cache-add.https.html.ini @@ -3,9 +3,3 @@ [Cache.add with request with null body (not consumed)] expected: FAIL - [Cache.add with 206 response] - expected: FAIL - - [Cache.addAll with 206 response] - expected: FAIL - diff --git a/testing/web-platform/meta/service-workers/cache-storage/worker/cache-storage-match.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/worker/cache-storage-match.https.html.ini new file mode 100644 index 000000000000..6135da4006a0 --- /dev/null +++ b/testing/web-platform/meta/service-workers/cache-storage/worker/cache-storage-match.https.html.ini @@ -0,0 +1,5 @@ +[cache-storage-match.https.html] + type: testharness + [CacheStorageMatch with empty cache name provided] + expected: FAIL + diff --git a/testing/web-platform/meta/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html.ini b/testing/web-platform/meta/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html.ini new file mode 100644 index 000000000000..f2a6e30873d3 --- /dev/null +++ b/testing/web-platform/meta/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html.ini @@ -0,0 +1,5 @@ +[service-worker-error-event.https.html] + type: testharness + [Error handlers inside serviceworker should see the attributes of ErrorEvent] + expected: FAIL + diff --git a/testing/web-platform/meta/service-workers/service-worker/clients-get-client-types.https.html.ini b/testing/web-platform/meta/service-workers/service-worker/clients-get-client-types.https.html.ini new file mode 100644 index 000000000000..7d208b603fe8 --- /dev/null +++ b/testing/web-platform/meta/service-workers/service-worker/clients-get-client-types.https.html.ini @@ -0,0 +1,5 @@ +[clients-get-client-types.https.html] + type: testharness + [Test Clients.get() with window and worker clients] + expected: FAIL + diff --git a/testing/web-platform/meta/service-workers/service-worker/fetch-event.https.html.ini b/testing/web-platform/meta/service-workers/service-worker/fetch-event.https.html.ini index 2708c0d054b3..3761b2d33aba 100644 --- a/testing/web-platform/meta/service-workers/service-worker/fetch-event.https.html.ini +++ b/testing/web-platform/meta/service-workers/service-worker/fetch-event.https.html.ini @@ -1,3 +1,15 @@ [fetch-event.https.html] type: testharness prefs: [security.mixed_content.block_active_content:false, security.mixed_content.block_display_content:false] + [Service Worker headers in the request of a fetch event] + expected: + if not debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL + if debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL + if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL + if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL + diff --git a/testing/web-platform/meta/service-workers/service-worker/interfaces.https.html.ini b/testing/web-platform/meta/service-workers/service-worker/interfaces.https.html.ini new file mode 100644 index 000000000000..c620e1cd85f3 --- /dev/null +++ b/testing/web-platform/meta/service-workers/service-worker/interfaces.https.html.ini @@ -0,0 +1,8 @@ +[interfaces.https.html] + type: testharness + [Interfaces and attributes of ServiceWorkerContainer] + expected: FAIL + + [ServiceWorkerGlobalScope] + expected: FAIL + diff --git a/testing/web-platform/meta/service-workers/service-worker/navigation-preload/resource-timing.https.html.ini b/testing/web-platform/meta/service-workers/service-worker/navigation-preload/resource-timing.https.html.ini new file mode 100644 index 000000000000..dfd147576c74 --- /dev/null +++ b/testing/web-platform/meta/service-workers/service-worker/navigation-preload/resource-timing.https.html.ini @@ -0,0 +1,5 @@ +[resource-timing.https.html] + type: testharness + [Navigation Preload Resource Timing.] + expected: FAIL + diff --git a/testing/web-platform/meta/service-workers/service-worker/register-link-element.https.html.ini b/testing/web-platform/meta/service-workers/service-worker/register-link-element.https.html.ini index a40044cf928b..492f392a96b4 100644 --- a/testing/web-platform/meta/service-workers/service-worker/register-link-element.https.html.ini +++ b/testing/web-platform/meta/service-workers/service-worker/register-link-element.https.html.ini @@ -109,3 +109,105 @@ [Scope URL is same-origin filesystem: URL] expected: NOTRUN + [Registering script with good MIME type application/ecmascript] + expected: NOTRUN + + [Registering script that imports script with good MIME type application/ecmascript] + expected: NOTRUN + + [Registering script with good MIME type application/javascript] + expected: NOTRUN + + [Registering script that imports script with good MIME type application/javascript] + expected: NOTRUN + + [Registering script with good MIME type application/x-ecmascript] + expected: NOTRUN + + [Registering script that imports script with good MIME type application/x-ecmascript] + expected: NOTRUN + + [Registering script with good MIME type application/x-javascript] + expected: NOTRUN + + [Registering script that imports script with good MIME type application/x-javascript] + expected: NOTRUN + + [Registering script with good MIME type text/ecmascript] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/ecmascript] + expected: NOTRUN + + [Registering script with good MIME type text/javascript] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/javascript] + expected: NOTRUN + + [Registering script with good MIME type text/javascript1.0] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/javascript1.0] + expected: NOTRUN + + [Registering script with good MIME type text/javascript1.1] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/javascript1.1] + expected: NOTRUN + + [Registering script with good MIME type text/javascript1.2] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/javascript1.2] + expected: NOTRUN + + [Registering script with good MIME type text/javascript1.3] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/javascript1.3] + expected: NOTRUN + + [Registering script with good MIME type text/javascript1.4] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/javascript1.4] + expected: NOTRUN + + [Registering script with good MIME type text/javascript1.5] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/javascript1.5] + expected: NOTRUN + + [Registering script with good MIME type text/jscript] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/jscript] + expected: NOTRUN + + [Registering script with good MIME type text/livescript] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/livescript] + expected: NOTRUN + + [Registering script with good MIME type text/x-ecmascript] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/x-ecmascript] + expected: NOTRUN + + [Registering script with good MIME type text/x-javascript] + expected: NOTRUN + + [Registering script that imports script with good MIME type text/x-javascript] + expected: NOTRUN + + [Registering script that imports script with no MIME type] + expected: NOTRUN + + [Registering script that imports script with bad MIME type] + expected: NOTRUN + diff --git a/testing/web-platform/meta/service-workers/service-worker/registration.https.html.ini b/testing/web-platform/meta/service-workers/service-worker/registration.https.html.ini new file mode 100644 index 000000000000..8b1bf450c5f9 --- /dev/null +++ b/testing/web-platform/meta/service-workers/service-worker/registration.https.html.ini @@ -0,0 +1,49 @@ +[registration.https.html] + type: testharness + disabled: + if (os == "win"): https://bugzilla.mozilla.org/show_bug.cgi?id=1351890 + [Registering script with good MIME type application/ecmascript] + expected: FAIL + + [Registering script with good MIME type application/x-ecmascript] + expected: FAIL + + [Registering script with good MIME type text/ecmascript] + expected: FAIL + + [Registering script with good MIME type text/javascript1.0] + expected: FAIL + + [Registering script with good MIME type text/javascript1.1] + expected: FAIL + + [Registering script with good MIME type text/javascript1.2] + expected: FAIL + + [Registering script with good MIME type text/javascript1.3] + expected: FAIL + + [Registering script with good MIME type text/javascript1.4] + expected: FAIL + + [Registering script with good MIME type text/javascript1.5] + expected: FAIL + + [Registering script with good MIME type text/jscript] + expected: FAIL + + [Registering script with good MIME type text/livescript] + expected: FAIL + + [Registering script with good MIME type text/x-ecmascript] + expected: FAIL + + [Registering script with good MIME type text/x-javascript] + expected: FAIL + + [Registering script that imports script with no MIME type] + expected: FAIL + + [Registering script that imports script with bad MIME type] + expected: FAIL + diff --git a/testing/web-platform/meta/shadow-dom/slots-fallback-in-document.html.ini b/testing/web-platform/meta/shadow-dom/slots-fallback-in-document.html.ini new file mode 100644 index 000000000000..81e8a39c121c --- /dev/null +++ b/testing/web-platform/meta/shadow-dom/slots-fallback-in-document.html.ini @@ -0,0 +1,5 @@ +[slots-fallback-in-document.html] + type: testharness + [Shadow DOM: Slots and fallback contents in Document tree] + expected: FAIL + diff --git a/testing/web-platform/meta/staticrange/idlharness.html.ini b/testing/web-platform/meta/staticrange/idlharness.html.ini new file mode 100644 index 000000000000..953ddbecb3ba --- /dev/null +++ b/testing/web-platform/meta/staticrange/idlharness.html.ini @@ -0,0 +1,32 @@ +[idlharness.html] + type: testharness + [StaticRange interface: existence and properties of interface object] + expected: FAIL + + [StaticRange interface object length] + expected: FAIL + + [StaticRange interface object name] + expected: FAIL + + [StaticRange interface: existence and properties of interface prototype object] + expected: FAIL + + [StaticRange interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [StaticRange interface: attribute startContainer] + expected: FAIL + + [StaticRange interface: attribute startOffset] + expected: FAIL + + [StaticRange interface: attribute endContainer] + expected: FAIL + + [StaticRange interface: attribute endOffset] + expected: FAIL + + [StaticRange interface: attribute collapsed] + expected: FAIL + diff --git a/testing/web-platform/meta/storage/opaque-origin.https.html.ini b/testing/web-platform/meta/storage/opaque-origin.https.html.ini index a83d0745a961..8c6d601eedf0 100644 --- a/testing/web-platform/meta/storage/opaque-origin.https.html.ini +++ b/testing/web-platform/meta/storage/opaque-origin.https.html.ini @@ -1,5 +1,3 @@ [opaque-origin.https.html] type: testharness - prefs: [dom.storageManager.prompt.testing:true, - dom.storageManager.prompt.testing.allow:true] - + prefs: [dom.storageManager.prompt.testing:true, dom.storageManager.prompt.testing.allow:true] diff --git a/testing/web-platform/meta/storage/storagemanager-persist.https.html.ini b/testing/web-platform/meta/storage/storagemanager-persist.https.html.ini new file mode 100644 index 000000000000..7ec60ea85889 --- /dev/null +++ b/testing/web-platform/meta/storage/storagemanager-persist.https.html.ini @@ -0,0 +1,6 @@ +[storagemanager-persist.https.html] + type: testharness + expected: TIMEOUT + [navigator.storage.persist() returns a promise that resolves.] + expected: TIMEOUT + diff --git a/testing/web-platform/meta/streams/piping/close-propagation-forward.dedicatedworker.html.ini b/testing/web-platform/meta/streams/piping/close-propagation-forward.dedicatedworker.html.ini index eff3c81c2170..5da757c01f05 100644 --- a/testing/web-platform/meta/streams/piping/close-propagation-forward.dedicatedworker.html.ini +++ b/testing/web-platform/meta/streams/piping/close-propagation-forward.dedicatedworker.html.ini @@ -78,3 +78,6 @@ [Closing must be propagated forward: shutdown must not occur until the final write completes] expected: FAIL + [Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/close-propagation-forward.html.ini b/testing/web-platform/meta/streams/piping/close-propagation-forward.html.ini index 3cfbf76ad3a2..f33e3c441166 100644 --- a/testing/web-platform/meta/streams/piping/close-propagation-forward.html.ini +++ b/testing/web-platform/meta/streams/piping/close-propagation-forward.html.ini @@ -78,3 +78,6 @@ [Closing must be propagated forward: shutdown must not occur until the final write completes] expected: FAIL + [Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/close-propagation-forward.serviceworker.https.html.ini b/testing/web-platform/meta/streams/piping/close-propagation-forward.serviceworker.https.html.ini index ee6161b69dfd..61a088ad3dd0 100644 --- a/testing/web-platform/meta/streams/piping/close-propagation-forward.serviceworker.https.html.ini +++ b/testing/web-platform/meta/streams/piping/close-propagation-forward.serviceworker.https.html.ini @@ -78,3 +78,6 @@ [Closing must be propagated forward: shutdown must not occur until the final write completes] expected: FAIL + [Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/close-propagation-forward.sharedworker.html.ini b/testing/web-platform/meta/streams/piping/close-propagation-forward.sharedworker.html.ini index 7b340cc0cc52..0aa931cc9483 100644 --- a/testing/web-platform/meta/streams/piping/close-propagation-forward.sharedworker.html.ini +++ b/testing/web-platform/meta/streams/piping/close-propagation-forward.sharedworker.html.ini @@ -78,3 +78,6 @@ [Closing must be propagated forward: shutdown must not occur until the final write completes] expected: FAIL + [Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/multiple-propagation.dedicatedworker.html.ini b/testing/web-platform/meta/streams/piping/multiple-propagation.dedicatedworker.html.ini index 56010902a07f..49c96d098b7d 100644 --- a/testing/web-platform/meta/streams/piping/multiple-propagation.dedicatedworker.html.ini +++ b/testing/web-platform/meta/streams/piping/multiple-propagation.dedicatedworker.html.ini @@ -15,3 +15,6 @@ [Piping from a closed readable stream to a closed writable stream] expected: FAIL + [Piping from an errored readable stream to a closing writable stream] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/multiple-propagation.html.ini b/testing/web-platform/meta/streams/piping/multiple-propagation.html.ini index b4ea27e2c285..41f9287195e3 100644 --- a/testing/web-platform/meta/streams/piping/multiple-propagation.html.ini +++ b/testing/web-platform/meta/streams/piping/multiple-propagation.html.ini @@ -15,3 +15,6 @@ [Piping from a closed readable stream to a closed writable stream] expected: FAIL + [Piping from an errored readable stream to a closing writable stream] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/multiple-propagation.serviceworker.https.html.ini b/testing/web-platform/meta/streams/piping/multiple-propagation.serviceworker.https.html.ini index 279f50357adf..6fc45927aef8 100644 --- a/testing/web-platform/meta/streams/piping/multiple-propagation.serviceworker.https.html.ini +++ b/testing/web-platform/meta/streams/piping/multiple-propagation.serviceworker.https.html.ini @@ -15,3 +15,6 @@ [Piping from a closed readable stream to a closed writable stream] expected: FAIL + [Piping from an errored readable stream to a closing writable stream] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/multiple-propagation.sharedworker.html.ini b/testing/web-platform/meta/streams/piping/multiple-propagation.sharedworker.html.ini index 25e2462e2853..46dd3c78de39 100644 --- a/testing/web-platform/meta/streams/piping/multiple-propagation.sharedworker.html.ini +++ b/testing/web-platform/meta/streams/piping/multiple-propagation.sharedworker.html.ini @@ -15,3 +15,6 @@ [Piping from a closed readable stream to a closed writable stream] expected: FAIL + [Piping from an errored readable stream to a closing writable stream] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/pipe-through.dedicatedworker.html.ini b/testing/web-platform/meta/streams/piping/pipe-through.dedicatedworker.html.ini index df044480081d..0d18daa43fd2 100644 --- a/testing/web-platform/meta/streams/piping/pipe-through.dedicatedworker.html.ini +++ b/testing/web-platform/meta/streams/piping/pipe-through.dedicatedworker.html.ini @@ -15,3 +15,9 @@ [pipeThrough can handle calling a pipeTo that returns a non-promise thenable object] expected: FAIL + [pipeThrough should mark a real promise from a fake readable as handled] + expected: FAIL + + [pipeThrough should not be fooled by an object whose instanceof Promise returns true] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/pipe-through.html.ini b/testing/web-platform/meta/streams/piping/pipe-through.html.ini index ca1853c8a8ba..010c93949e25 100644 --- a/testing/web-platform/meta/streams/piping/pipe-through.html.ini +++ b/testing/web-platform/meta/streams/piping/pipe-through.html.ini @@ -15,3 +15,9 @@ [pipeThrough can handle calling a pipeTo that returns a non-promise thenable object] expected: FAIL + [pipeThrough should mark a real promise from a fake readable as handled] + expected: FAIL + + [pipeThrough should not be fooled by an object whose instanceof Promise returns true] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/pipe-through.serviceworker.https.html.ini b/testing/web-platform/meta/streams/piping/pipe-through.serviceworker.https.html.ini index bf73b85b184c..c8d6c9a18c5e 100644 --- a/testing/web-platform/meta/streams/piping/pipe-through.serviceworker.https.html.ini +++ b/testing/web-platform/meta/streams/piping/pipe-through.serviceworker.https.html.ini @@ -15,3 +15,9 @@ [pipeThrough can handle calling a pipeTo that returns a non-promise thenable object] expected: FAIL + [pipeThrough should mark a real promise from a fake readable as handled] + expected: FAIL + + [pipeThrough should not be fooled by an object whose instanceof Promise returns true] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/piping/pipe-through.sharedworker.html.ini b/testing/web-platform/meta/streams/piping/pipe-through.sharedworker.html.ini index 58fff9cec70a..1a562800ba58 100644 --- a/testing/web-platform/meta/streams/piping/pipe-through.sharedworker.html.ini +++ b/testing/web-platform/meta/streams/piping/pipe-through.sharedworker.html.ini @@ -15,3 +15,9 @@ [pipeThrough can handle calling a pipeTo that returns a non-promise thenable object] expected: FAIL + [pipeThrough should mark a real promise from a fake readable as handled] + expected: FAIL + + [pipeThrough should not be fooled by an object whose instanceof Promise returns true] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/readable-byte-streams/general.dedicatedworker.html.ini b/testing/web-platform/meta/streams/readable-byte-streams/general.dedicatedworker.html.ini index 98fa8f14aff5..4bd47bf37c2c 100644 --- a/testing/web-platform/meta/streams/readable-byte-streams/general.dedicatedworker.html.ini +++ b/testing/web-platform/meta/streams/readable-byte-streams/general.dedicatedworker.html.ini @@ -213,3 +213,6 @@ [getReader({mode}) must perform ToString()] expected: FAIL + [ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/readable-byte-streams/general.html.ini b/testing/web-platform/meta/streams/readable-byte-streams/general.html.ini index a2809f94531f..9e0c11095cc6 100644 --- a/testing/web-platform/meta/streams/readable-byte-streams/general.html.ini +++ b/testing/web-platform/meta/streams/readable-byte-streams/general.html.ini @@ -213,3 +213,6 @@ [getReader({mode}) must perform ToString()] expected: FAIL + [ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/readable-byte-streams/general.serviceworker.https.html.ini b/testing/web-platform/meta/streams/readable-byte-streams/general.serviceworker.https.html.ini index 083eec662d9a..0dc840bb4044 100644 --- a/testing/web-platform/meta/streams/readable-byte-streams/general.serviceworker.https.html.ini +++ b/testing/web-platform/meta/streams/readable-byte-streams/general.serviceworker.https.html.ini @@ -213,3 +213,6 @@ [getReader({mode}) must perform ToString()] expected: FAIL + [ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/readable-byte-streams/general.sharedworker.html.ini b/testing/web-platform/meta/streams/readable-byte-streams/general.sharedworker.html.ini index 93deac579972..29d40cb0364f 100644 --- a/testing/web-platform/meta/streams/readable-byte-streams/general.sharedworker.html.ini +++ b/testing/web-platform/meta/streams/readable-byte-streams/general.sharedworker.html.ini @@ -213,3 +213,6 @@ [getReader({mode}) must perform ToString()] expected: FAIL + [ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/readable-streams/floating-point-total-queue-size.dedicatedworker.html.ini b/testing/web-platform/meta/streams/readable-streams/floating-point-total-queue-size.dedicatedworker.html.ini index e99f580111d5..c38640e030b9 100644 --- a/testing/web-platform/meta/streams/readable-streams/floating-point-total-queue-size.dedicatedworker.html.ini +++ b/testing/web-platform/meta/streams/readable-streams/floating-point-total-queue-size.dedicatedworker.html.ini @@ -1,6 +1,5 @@ [floating-point-total-queue-size.dedicatedworker.html] type: testharness - expected: TIMEOUT [Floating point arithmetic must manifest near NUMBER.MAX_SAFE_INTEGER (total ends up positive)] expected: FAIL diff --git a/testing/web-platform/meta/streams/readable-streams/floating-point-total-queue-size.sharedworker.html.ini b/testing/web-platform/meta/streams/readable-streams/floating-point-total-queue-size.sharedworker.html.ini index f8abce89fb1b..ec413da7d2cd 100644 --- a/testing/web-platform/meta/streams/readable-streams/floating-point-total-queue-size.sharedworker.html.ini +++ b/testing/web-platform/meta/streams/readable-streams/floating-point-total-queue-size.sharedworker.html.ini @@ -1,6 +1,5 @@ [floating-point-total-queue-size.sharedworker.html] type: testharness - expected: TIMEOUT [Floating point arithmetic must manifest near NUMBER.MAX_SAFE_INTEGER (total ends up positive)] expected: FAIL diff --git a/testing/web-platform/meta/streams/writable-streams/aborting.dedicatedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/aborting.dedicatedworker.html.ini index 84aa959deb77..af4cef79fa5d 100644 --- a/testing/web-platform/meta/streams/writable-streams/aborting.dedicatedworker.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/aborting.dedicatedworker.html.ini @@ -144,3 +144,39 @@ [abort() should be rejected with the error passed to controller.error() during pending close()] expected: FAIL + [.closed should not resolve before rejected write(); write() error should not overwrite abort() error] + expected: FAIL + + [close() should reject with TypeError when abort() is first error] + expected: FAIL + + [releaseLock() during delayed async abort() should reject the writer.closed promise] + expected: FAIL + + [if start attempts to error the controller after abort() has been called, then it should lose] + expected: FAIL + + [stream abort() promise should still resolve if sink start() rejects] + expected: FAIL + + [abort() should succeed despite rejection from write] + expected: FAIL + + [abort() should be rejected with the rejection returned from close()] + expected: FAIL + + [a rejecting sink.write() should not prevent sink.abort() from being called] + expected: FAIL + + [when start errors after stream abort(), underlying sink abort() should be called anyway] + expected: FAIL + + [when calling abort() twice on the same stream, the second call should reject] + expected: FAIL + + [sink abort() should not be called if stream was erroring due to controller.error() before abort() was called] + expected: FAIL + + [sink abort() should not be called if stream was erroring due to bad strategy before abort() was called] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/aborting.html.ini b/testing/web-platform/meta/streams/writable-streams/aborting.html.ini index 2ec6946b527f..3b691fb05de1 100644 --- a/testing/web-platform/meta/streams/writable-streams/aborting.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/aborting.html.ini @@ -144,3 +144,39 @@ [abort() should be rejected with the error passed to controller.error() during pending close()] expected: FAIL + [.closed should not resolve before rejected write(); write() error should not overwrite abort() error] + expected: FAIL + + [close() should reject with TypeError when abort() is first error] + expected: FAIL + + [releaseLock() during delayed async abort() should reject the writer.closed promise] + expected: FAIL + + [if start attempts to error the controller after abort() has been called, then it should lose] + expected: FAIL + + [stream abort() promise should still resolve if sink start() rejects] + expected: FAIL + + [abort() should succeed despite rejection from write] + expected: FAIL + + [abort() should be rejected with the rejection returned from close()] + expected: FAIL + + [a rejecting sink.write() should not prevent sink.abort() from being called] + expected: FAIL + + [when start errors after stream abort(), underlying sink abort() should be called anyway] + expected: FAIL + + [when calling abort() twice on the same stream, the second call should reject] + expected: FAIL + + [sink abort() should not be called if stream was erroring due to controller.error() before abort() was called] + expected: FAIL + + [sink abort() should not be called if stream was erroring due to bad strategy before abort() was called] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/aborting.serviceworker.https.html.ini b/testing/web-platform/meta/streams/writable-streams/aborting.serviceworker.https.html.ini index faa837d9c7e3..338ac4a8ae2e 100644 --- a/testing/web-platform/meta/streams/writable-streams/aborting.serviceworker.https.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/aborting.serviceworker.https.html.ini @@ -144,3 +144,39 @@ [abort() should be rejected with the error passed to controller.error() during pending close()] expected: FAIL + [.closed should not resolve before rejected write(); write() error should not overwrite abort() error] + expected: FAIL + + [close() should reject with TypeError when abort() is first error] + expected: FAIL + + [releaseLock() during delayed async abort() should reject the writer.closed promise] + expected: FAIL + + [if start attempts to error the controller after abort() has been called, then it should lose] + expected: FAIL + + [stream abort() promise should still resolve if sink start() rejects] + expected: FAIL + + [abort() should succeed despite rejection from write] + expected: FAIL + + [abort() should be rejected with the rejection returned from close()] + expected: FAIL + + [a rejecting sink.write() should not prevent sink.abort() from being called] + expected: FAIL + + [when start errors after stream abort(), underlying sink abort() should be called anyway] + expected: FAIL + + [when calling abort() twice on the same stream, the second call should reject] + expected: FAIL + + [sink abort() should not be called if stream was erroring due to controller.error() before abort() was called] + expected: FAIL + + [sink abort() should not be called if stream was erroring due to bad strategy before abort() was called] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/aborting.sharedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/aborting.sharedworker.html.ini index a92c89c3c745..49fb0b7f6677 100644 --- a/testing/web-platform/meta/streams/writable-streams/aborting.sharedworker.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/aborting.sharedworker.html.ini @@ -144,3 +144,39 @@ [abort() should be rejected with the error passed to controller.error() during pending close()] expected: FAIL + [.closed should not resolve before rejected write(); write() error should not overwrite abort() error] + expected: FAIL + + [close() should reject with TypeError when abort() is first error] + expected: FAIL + + [releaseLock() during delayed async abort() should reject the writer.closed promise] + expected: FAIL + + [if start attempts to error the controller after abort() has been called, then it should lose] + expected: FAIL + + [stream abort() promise should still resolve if sink start() rejects] + expected: FAIL + + [abort() should succeed despite rejection from write] + expected: FAIL + + [abort() should be rejected with the rejection returned from close()] + expected: FAIL + + [a rejecting sink.write() should not prevent sink.abort() from being called] + expected: FAIL + + [when start errors after stream abort(), underlying sink abort() should be called anyway] + expected: FAIL + + [when calling abort() twice on the same stream, the second call should reject] + expected: FAIL + + [sink abort() should not be called if stream was erroring due to controller.error() before abort() was called] + expected: FAIL + + [sink abort() should not be called if stream was erroring due to bad strategy before abort() was called] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/close.dedicatedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/close.dedicatedworker.html.ini index 920bc6f276be..9f6e11843fc9 100644 --- a/testing/web-platform/meta/streams/writable-streams/close.dedicatedworker.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/close.dedicatedworker.html.ini @@ -51,3 +51,15 @@ [when the sink throws during close, and the close is requested while a write is still in-flight, the stream should become errored during the close] expected: FAIL + [when sink calls error asynchronously while sink close is in-flight, the stream should not become errored] + expected: FAIL + + [when sink calls error synchronously while closing, the stream should not become errored] + expected: FAIL + + [releaseLock on a stream with a pending close in which controller.error() was called] + expected: FAIL + + [close() should not reject until no sink methods are in flight] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/close.html.ini b/testing/web-platform/meta/streams/writable-streams/close.html.ini index f5acef5e4942..539cc75c64a8 100644 --- a/testing/web-platform/meta/streams/writable-streams/close.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/close.html.ini @@ -51,3 +51,15 @@ [when the sink throws during close, and the close is requested while a write is still in-flight, the stream should become errored during the close] expected: FAIL + [when sink calls error asynchronously while sink close is in-flight, the stream should not become errored] + expected: FAIL + + [when sink calls error synchronously while closing, the stream should not become errored] + expected: FAIL + + [releaseLock on a stream with a pending close in which controller.error() was called] + expected: FAIL + + [close() should not reject until no sink methods are in flight] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/close.serviceworker.https.html.ini b/testing/web-platform/meta/streams/writable-streams/close.serviceworker.https.html.ini index e55ad6f8d5f1..39e5a8e7c360 100644 --- a/testing/web-platform/meta/streams/writable-streams/close.serviceworker.https.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/close.serviceworker.https.html.ini @@ -51,3 +51,15 @@ [when the sink throws during close, and the close is requested while a write is still in-flight, the stream should become errored during the close] expected: FAIL + [when sink calls error asynchronously while sink close is in-flight, the stream should not become errored] + expected: FAIL + + [when sink calls error synchronously while closing, the stream should not become errored] + expected: FAIL + + [releaseLock on a stream with a pending close in which controller.error() was called] + expected: FAIL + + [close() should not reject until no sink methods are in flight] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/close.sharedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/close.sharedworker.html.ini index d8122ba962c7..7912f0c42717 100644 --- a/testing/web-platform/meta/streams/writable-streams/close.sharedworker.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/close.sharedworker.html.ini @@ -51,3 +51,15 @@ [when the sink throws during close, and the close is requested while a write is still in-flight, the stream should become errored during the close] expected: FAIL + [when sink calls error asynchronously while sink close is in-flight, the stream should not become errored] + expected: FAIL + + [when sink calls error synchronously while closing, the stream should not become errored] + expected: FAIL + + [releaseLock on a stream with a pending close in which controller.error() was called] + expected: FAIL + + [close() should not reject until no sink methods are in flight] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/constructor.dedicatedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/constructor.dedicatedworker.html.ini index 6d03743e8be5..3868efb97f69 100644 --- a/testing/web-platform/meta/streams/writable-streams/constructor.dedicatedworker.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/constructor.dedicatedworker.html.ini @@ -33,3 +33,6 @@ [WritableStreamDefaultWriter constructor should throw when stream argument is locked] expected: FAIL + [controller argument should not be passed to close method] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/constructor.html.ini b/testing/web-platform/meta/streams/writable-streams/constructor.html.ini index 680c3bbc8efc..f17acc32d5a4 100644 --- a/testing/web-platform/meta/streams/writable-streams/constructor.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/constructor.html.ini @@ -33,3 +33,6 @@ [WritableStreamDefaultWriter constructor should throw when stream argument is locked] expected: FAIL + [controller argument should not be passed to close method] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/constructor.serviceworker.https.html.ini b/testing/web-platform/meta/streams/writable-streams/constructor.serviceworker.https.html.ini index 8bfc25655cdb..81414163cd3b 100644 --- a/testing/web-platform/meta/streams/writable-streams/constructor.serviceworker.https.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/constructor.serviceworker.https.html.ini @@ -33,3 +33,6 @@ [WritableStreamDefaultWriter constructor should throw when stream argument is locked] expected: FAIL + [controller argument should not be passed to close method] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/constructor.sharedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/constructor.sharedworker.html.ini index 8acbe0a477aa..26c67f33d58e 100644 --- a/testing/web-platform/meta/streams/writable-streams/constructor.sharedworker.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/constructor.sharedworker.html.ini @@ -33,3 +33,6 @@ [WritableStreamDefaultWriter constructor should throw when stream argument is locked] expected: FAIL + [controller argument should not be passed to close method] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/error.dedicatedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/error.dedicatedworker.html.ini new file mode 100644 index 000000000000..7fea07b08acb --- /dev/null +++ b/testing/web-platform/meta/streams/writable-streams/error.dedicatedworker.html.ini @@ -0,0 +1,17 @@ +[error.dedicatedworker.html] + type: testharness + [controller.error() should error the stream] + expected: FAIL + + [controller.error() on erroring stream should not throw] + expected: FAIL + + [surplus calls to controller.error() should be a no-op] + expected: FAIL + + [controller.error() on errored stream should not throw] + expected: FAIL + + [controller.error() on closed stream should not throw] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/error.html.ini b/testing/web-platform/meta/streams/writable-streams/error.html.ini new file mode 100644 index 000000000000..e16c94249a03 --- /dev/null +++ b/testing/web-platform/meta/streams/writable-streams/error.html.ini @@ -0,0 +1,17 @@ +[error.html] + type: testharness + [controller.error() should error the stream] + expected: FAIL + + [controller.error() on erroring stream should not throw] + expected: FAIL + + [surplus calls to controller.error() should be a no-op] + expected: FAIL + + [controller.error() on errored stream should not throw] + expected: FAIL + + [controller.error() on closed stream should not throw] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/error.serviceworker.https.html.ini b/testing/web-platform/meta/streams/writable-streams/error.serviceworker.https.html.ini new file mode 100644 index 000000000000..d2776aba2400 --- /dev/null +++ b/testing/web-platform/meta/streams/writable-streams/error.serviceworker.https.html.ini @@ -0,0 +1,17 @@ +[error.serviceworker.https.html] + type: testharness + [controller.error() should error the stream] + expected: FAIL + + [controller.error() on erroring stream should not throw] + expected: FAIL + + [surplus calls to controller.error() should be a no-op] + expected: FAIL + + [controller.error() on errored stream should not throw] + expected: FAIL + + [controller.error() on closed stream should not throw] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/error.sharedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/error.sharedworker.html.ini new file mode 100644 index 000000000000..babec3af3f2b --- /dev/null +++ b/testing/web-platform/meta/streams/writable-streams/error.sharedworker.html.ini @@ -0,0 +1,17 @@ +[error.sharedworker.html] + type: testharness + [controller.error() should error the stream] + expected: FAIL + + [controller.error() on erroring stream should not throw] + expected: FAIL + + [surplus calls to controller.error() should be a no-op] + expected: FAIL + + [controller.error() on errored stream should not throw] + expected: FAIL + + [controller.error() on closed stream should not throw] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/floating-point-total-queue-size.dedicatedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/floating-point-total-queue-size.dedicatedworker.html.ini index e99f580111d5..c38640e030b9 100644 --- a/testing/web-platform/meta/streams/writable-streams/floating-point-total-queue-size.dedicatedworker.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/floating-point-total-queue-size.dedicatedworker.html.ini @@ -1,6 +1,5 @@ [floating-point-total-queue-size.dedicatedworker.html] type: testharness - expected: TIMEOUT [Floating point arithmetic must manifest near NUMBER.MAX_SAFE_INTEGER (total ends up positive)] expected: FAIL diff --git a/testing/web-platform/meta/streams/writable-streams/floating-point-total-queue-size.sharedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/floating-point-total-queue-size.sharedworker.html.ini index f8abce89fb1b..ec413da7d2cd 100644 --- a/testing/web-platform/meta/streams/writable-streams/floating-point-total-queue-size.sharedworker.html.ini +++ b/testing/web-platform/meta/streams/writable-streams/floating-point-total-queue-size.sharedworker.html.ini @@ -1,6 +1,5 @@ [floating-point-total-queue-size.sharedworker.html] type: testharness - expected: TIMEOUT [Floating point arithmetic must manifest near NUMBER.MAX_SAFE_INTEGER (total ends up positive)] expected: FAIL diff --git a/testing/web-platform/meta/streams/writable-streams/properties.dedicatedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/properties.dedicatedworker.html.ini new file mode 100644 index 000000000000..163ba0a7c793 --- /dev/null +++ b/testing/web-platform/meta/streams/writable-streams/properties.dedicatedworker.html.ini @@ -0,0 +1,3 @@ +[properties.dedicatedworker.html] + type: testharness + expected: ERROR diff --git a/testing/web-platform/meta/streams/writable-streams/properties.html.ini b/testing/web-platform/meta/streams/writable-streams/properties.html.ini new file mode 100644 index 000000000000..1ee47ded9eff --- /dev/null +++ b/testing/web-platform/meta/streams/writable-streams/properties.html.ini @@ -0,0 +1,3 @@ +[properties.html] + type: testharness + expected: ERROR diff --git a/testing/web-platform/meta/streams/writable-streams/properties.serviceworker.https.html.ini b/testing/web-platform/meta/streams/writable-streams/properties.serviceworker.https.html.ini new file mode 100644 index 000000000000..95bb00aa89d5 --- /dev/null +++ b/testing/web-platform/meta/streams/writable-streams/properties.serviceworker.https.html.ini @@ -0,0 +1,5 @@ +[properties.serviceworker.https.html] + type: testharness + [Service worker test setup] + expected: FAIL + diff --git a/testing/web-platform/meta/streams/writable-streams/properties.sharedworker.html.ini b/testing/web-platform/meta/streams/writable-streams/properties.sharedworker.html.ini new file mode 100644 index 000000000000..1cc7c5913ff6 --- /dev/null +++ b/testing/web-platform/meta/streams/writable-streams/properties.sharedworker.html.ini @@ -0,0 +1,3 @@ +[properties.sharedworker.html] + type: testharness + expected: ERROR diff --git a/testing/web-platform/meta/url/a-element-xhtml.xhtml.ini b/testing/web-platform/meta/url/a-element-xhtml.xhtml.ini index 1ccbf34d357f..5a3539311c3d 100644 --- a/testing/web-platform/meta/url/a-element-xhtml.xhtml.ini +++ b/testing/web-platform/meta/url/a-element-xhtml.xhtml.ini @@ -710,3 +710,24 @@ [Parsing: against ] expected: FAIL + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + diff --git a/testing/web-platform/meta/url/a-element.html.ini b/testing/web-platform/meta/url/a-element.html.ini index 58a7c9066f97..27959477b147 100644 --- a/testing/web-platform/meta/url/a-element.html.ini +++ b/testing/web-platform/meta/url/a-element.html.ini @@ -719,3 +719,24 @@ [Parsing: against ] expected: FAIL + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + diff --git a/testing/web-platform/meta/url/failure.html.ini b/testing/web-platform/meta/url/failure.html.ini index e287f1700252..f9c0e95a1b3b 100644 --- a/testing/web-platform/meta/url/failure.html.ini +++ b/testing/web-platform/meta/url/failure.html.ini @@ -300,3 +300,141 @@ [Location's href: non-special://[:80/ should throw] expected: FAIL + [window.open(): file://example:1/ should throw] + expected: FAIL + + [window.open(): file://example:test/ should throw] + expected: FAIL + + [window.open(): file://example%/ should throw] + expected: FAIL + + [window.open(): file://[example\]/ should throw] + expected: FAIL + + [window.open(): http://user:pass@/ should throw] + expected: FAIL + + [window.open(): http://foo:-80/ should throw] + expected: FAIL + + [window.open(): http:/:@/www.example.com should throw] + expected: FAIL + + [window.open(): http://user@/www.example.com should throw] + expected: FAIL + + [window.open(): http:@/www.example.com should throw] + expected: FAIL + + [window.open(): http:/@/www.example.com should throw] + expected: FAIL + + [window.open(): http://@/www.example.com should throw] + expected: FAIL + + [window.open(): https:@/www.example.com should throw] + expected: FAIL + + [window.open(): http:a:b@/www.example.com should throw] + expected: FAIL + + [window.open(): http:/a:b@/www.example.com should throw] + expected: FAIL + + [window.open(): http://a:b@/www.example.com should throw] + expected: FAIL + + [window.open(): http::@/www.example.com should throw] + expected: FAIL + + [window.open(): http:@:www.example.com should throw] + expected: FAIL + + [window.open(): http:/@:www.example.com should throw] + expected: FAIL + + [window.open(): http://@:www.example.com should throw] + expected: FAIL + + [window.open(): https://� should throw] + expected: FAIL + + [window.open(): https://%EF%BF%BD should throw] + expected: FAIL + + [window.open(): https://x x:12 should throw] + expected: FAIL + + [window.open(): http://[www.google.com\]/ should throw] + expected: FAIL + + [window.open(): sc://\x00/ should throw] + expected: FAIL + + [window.open(): sc:// / should throw] + expected: FAIL + + [window.open(): sc://@/ should throw] + expected: FAIL + + [window.open(): sc://te@s:t@/ should throw] + expected: FAIL + + [window.open(): sc://:/ should throw] + expected: FAIL + + [window.open(): sc://:12/ should throw] + expected: FAIL + + [window.open(): sc://[/ should throw] + expected: FAIL + + [window.open(): sc://\\/ should throw] + expected: FAIL + + [window.open(): sc://\]/ should throw] + expected: FAIL + + [window.open(): ftp://example.com%80/ should throw] + expected: FAIL + + [window.open(): ftp://example.com%A0/ should throw] + expected: FAIL + + [window.open(): https://example.com%80/ should throw] + expected: FAIL + + [window.open(): https://example.com%A0/ should throw] + expected: FAIL + + [window.open(): https://[0::0::0\] should throw] + expected: FAIL + + [window.open(): https://[0:.0\] should throw] + expected: FAIL + + [window.open(): https://[0:0:\] should throw] + expected: FAIL + + [window.open(): https://[0:1:2:3:4:5:6:7.0.0.0.1\] should throw] + expected: FAIL + + [window.open(): https://[0:1.00.0.0.0\] should throw] + expected: FAIL + + [window.open(): https://[0:1.290.0.0.0\] should throw] + expected: FAIL + + [window.open(): https://[0:1.23.23\] should throw] + expected: FAIL + + [window.open(): http://? should throw] + expected: FAIL + + [window.open(): http://# should throw] + expected: FAIL + + [window.open(): non-special://[:80/ should throw] + expected: FAIL + diff --git a/testing/web-platform/meta/url/url-constructor.html.ini b/testing/web-platform/meta/url/url-constructor.html.ini index e1fbe4acb9e7..e6229b294c6b 100644 --- a/testing/web-platform/meta/url/url-constructor.html.ini +++ b/testing/web-platform/meta/url/url-constructor.html.ini @@ -428,3 +428,24 @@ [Parsing: against ] expected: FAIL + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + + [Parsing: against ] + expected: FAIL + diff --git a/testing/web-platform/meta/web-animations/animation-model/animation-types/interpolation-per-property.html.ini b/testing/web-platform/meta/web-animations/animation-model/animation-types/interpolation-per-property.html.ini index 932ddc25afd4..f44d223ef6d9 100644 --- a/testing/web-platform/meta/web-animations/animation-model/animation-types/interpolation-per-property.html.ini +++ b/testing/web-platform/meta/web-animations/animation-model/animation-types/interpolation-per-property.html.ini @@ -18,3 +18,4 @@ prefs: [layout.css.contain.enabled:true, layout.css.initial-letter.enabled:true, [column-gap uses discrete animation when animating between "normal" and "200px" with keyframe easing] expected: FAIL bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1356241 + diff --git a/testing/web-platform/meta/web-animations/timing-model/animations/canceling-an-animation.html.ini b/testing/web-platform/meta/web-animations/timing-model/animations/canceling-an-animation.html.ini new file mode 100644 index 000000000000..cf022cc90f34 --- /dev/null +++ b/testing/web-platform/meta/web-animations/timing-model/animations/canceling-an-animation.html.ini @@ -0,0 +1,5 @@ +[canceling-an-animation.html] + type: testharness + [The ready promise should be replaced when the animation is canceled] + expected: FAIL + diff --git a/testing/web-platform/meta/web-nfc/idlharness.https.html.ini b/testing/web-platform/meta/web-nfc/idlharness.https.html.ini new file mode 100644 index 000000000000..acb94a372728 --- /dev/null +++ b/testing/web-platform/meta/web-nfc/idlharness.https.html.ini @@ -0,0 +1,62 @@ +[idlharness.https.html] + type: testharness + [Navigator interface: attribute nfc] + expected: FAIL + + [NFC interface: existence and properties of interface object] + expected: FAIL + + [NFC interface object length] + expected: FAIL + + [NFC interface object name] + expected: FAIL + + [NFC interface: existence and properties of interface prototype object] + expected: FAIL + + [NFC interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [NFC interface: operation push(NFCPushMessage,NFCPushOptions)] + expected: FAIL + + [NFC interface: operation cancelPush(NFCPushTarget)] + expected: FAIL + + [NFC interface: operation watch(MessageCallback,NFCWatchOptions)] + expected: FAIL + + [NFC interface: operation cancelWatch(long)] + expected: FAIL + + [NFC must be primary interface of navigator.nfc] + expected: FAIL + + [Stringification of navigator.nfc] + expected: FAIL + + [NFC interface: navigator.nfc must inherit property "push" with the proper type (0)] + expected: FAIL + + [NFC interface: calling push(NFCPushMessage,NFCPushOptions) on navigator.nfc with too few arguments must throw TypeError] + expected: FAIL + + [NFC interface: navigator.nfc must inherit property "cancelPush" with the proper type (1)] + expected: FAIL + + [NFC interface: calling cancelPush(NFCPushTarget) on navigator.nfc with too few arguments must throw TypeError] + expected: FAIL + + [NFC interface: navigator.nfc must inherit property "watch" with the proper type (2)] + expected: FAIL + + [NFC interface: calling watch(MessageCallback,NFCWatchOptions) on navigator.nfc with too few arguments must throw TypeError] + expected: FAIL + + [NFC interface: navigator.nfc must inherit property "cancelWatch" with the proper type (3)] + expected: FAIL + + [NFC interface: calling cancelWatch(long) on navigator.nfc with too few arguments must throw TypeError] + expected: FAIL + diff --git a/testing/web-platform/meta/webdriver/contexts.py.ini b/testing/web-platform/meta/webdriver/contexts.py.ini index 9b3c808d81b2..ef0f8e16a406 100644 --- a/testing/web-platform/meta/webdriver/contexts.py.ini +++ b/testing/web-platform/meta/webdriver/contexts.py.ini @@ -6,12 +6,6 @@ [contexts.py::test_resize_by_script] expected: FAIL - [contexts.py::test_window_size_types] - expected: FAIL - - [contexts.py::test_window_resize] - expected: FAIL - [contexts.py::test_window_position_types] expected: FAIL diff --git a/testing/web-platform/meta/webdriver/navigation.py.ini b/testing/web-platform/meta/webdriver/navigation.py.ini index 24fddae73e3b..7bf89f2acf45 100644 --- a/testing/web-platform/meta/webdriver/navigation.py.ini +++ b/testing/web-platform/meta/webdriver/navigation.py.ini @@ -1,5 +1,9 @@ [navigation.py] type: wdspec + expected: TIMEOUT [navigation.py::test_get_current_url_alert_prompt] expected: FAIL + [navigation.py::test_set_malformed_url] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/messageerror.html.ini b/testing/web-platform/meta/webmessaging/messageerror.html.ini new file mode 100644 index 000000000000..30e4e4520499 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/messageerror.html.ini @@ -0,0 +1,11 @@ +[messageerror.html] + type: testharness + [The default value of onmessageerror is null] + expected: FAIL + + [The onmessageerror content attribute must be compiled into the onmessageerror property] + expected: FAIL + + [The onmessageerror content attribute must execute when an event is dispatched on the window] + expected: FAIL + diff --git a/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcconfiguration-icecandidatepoolsize.html.ini b/testing/web-platform/meta/webrtc/RTCConfiguration-iceCandidatePoolSize.html.ini similarity index 92% rename from testing/web-platform/meta/webrtc/rtcpeerconnection/rtcconfiguration-icecandidatepoolsize.html.ini rename to testing/web-platform/meta/webrtc/RTCConfiguration-iceCandidatePoolSize.html.ini index d122e2c8a5e7..4448d9670f38 100644 --- a/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcconfiguration-icecandidatepoolsize.html.ini +++ b/testing/web-platform/meta/webrtc/RTCConfiguration-iceCandidatePoolSize.html.ini @@ -1,4 +1,4 @@ -[rtcconfiguration-icecandidatepoolsize.html] +[RTCConfiguration-iceCandidatePoolSize.html] type: testharness [Setting iceCandidatePoolSize to a valid value: 10] expected: FAIL diff --git a/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-constructor.html.ini b/testing/web-platform/meta/webrtc/RTCPeerConnection-constructor.html.ini similarity index 96% rename from testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-constructor.html.ini rename to testing/web-platform/meta/webrtc/RTCPeerConnection-constructor.html.ini index fe288707fb7b..603e0dc5cc8a 100644 --- a/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-constructor.html.ini +++ b/testing/web-platform/meta/webrtc/RTCPeerConnection-constructor.html.ini @@ -1,4 +1,4 @@ -[rtcpeerconnection-constructor.html] +[RTCPeerConnection-constructor.html] type: testharness [new RTCPeerConnection({ iceServers: [{}\] })] expected: FAIL diff --git a/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini b/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini new file mode 100644 index 000000000000..f69a313819ff --- /dev/null +++ b/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini @@ -0,0 +1,29 @@ +[RTCPeerConnection-createDataChannel.html] + type: testharness + [createDataChannel defaults] + expected: FAIL + + [createDataChannel with maxPacketLifeTime 0] + expected: FAIL + + [createDataChannel with maxRetransmits 0] + expected: FAIL + + [createDataChannel with both maxPacketLifeTime and maxRetransmits] + expected: FAIL + + [createDataChannel with negotiated true] + expected: FAIL + + [createDataChannel with id -1] + expected: FAIL + + [createDataChannel with id 65535] + expected: FAIL + + [createDataChannel with id 65536] + expected: FAIL + + [createDataChannel with priority "high"] + expected: FAIL + diff --git a/testing/web-platform/meta/webrtc/RTCPeerConnection-idl.html.ini b/testing/web-platform/meta/webrtc/RTCPeerConnection-idl.html.ini new file mode 100644 index 000000000000..be8849a24376 --- /dev/null +++ b/testing/web-platform/meta/webrtc/RTCPeerConnection-idl.html.ini @@ -0,0 +1,104 @@ +[RTCPeerConnection-idl.html] + type: testharness + [RTCPeerConnection interface: attribute currentLocalDescription] + expected: FAIL + + [RTCPeerConnection interface: attribute pendingLocalDescription] + expected: FAIL + + [RTCPeerConnection interface: attribute currentRemoteDescription] + expected: FAIL + + [RTCPeerConnection interface: attribute pendingRemoteDescription] + expected: FAIL + + [RTCPeerConnection interface: operation setConfiguration(RTCConfiguration)] + expected: FAIL + + [RTCPeerConnection interface: operation createOffer(RTCSessionDescriptionCallback,RTCPeerConnectionErrorCallback,RTCOfferOptions)] + expected: FAIL + + [RTCPeerConnection interface: operation setLocalDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation createAnswer(RTCSessionDescriptionCallback,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation setRemoteDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation addIceCandidate(RTCIceCandidate,VoidFunction,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation getStats(MediaStreamTrack,RTCStatsCallback,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation addTrack(MediaStreamTrack,MediaStream)] + expected: FAIL + + [RTCPeerConnection interface: attribute dtmf] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "currentLocalDescription" with the proper type (4)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "pendingLocalDescription" with the proper type (5)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "currentRemoteDescription" with the proper type (8)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "pendingRemoteDescription" with the proper type (9)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "signalingState" with the proper type (11)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "iceGatheringState" with the proper type (12)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "iceConnectionState" with the proper type (13)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "setConfiguration" with the proper type (16)] + expected: FAIL + + [RTCPeerConnection interface: calling setConfiguration(RTCConfiguration) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onnegotiationneeded" with the proper type (18)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onicecandidate" with the proper type (19)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onsignalingstatechange" with the proper type (20)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "oniceconnectionstatechange" with the proper type (21)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onicegatheringstatechange" with the proper type (22)] + expected: FAIL + + [RTCPeerConnection interface: calling setLocalDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling setRemoteDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling addIceCandidate(RTCIceCandidate,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling generateCertificate(AlgorithmIdentifier) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "ontrack" with the proper type (34)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "ondatachannel" with the proper type (36)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "dtmf" with the proper type (37)] + expected: FAIL + diff --git a/testing/web-platform/meta/webrtc/RTCPeerConnection-setRemoteDescription.html.ini b/testing/web-platform/meta/webrtc/RTCPeerConnection-setRemoteDescription.html.ini new file mode 100644 index 000000000000..3f6955315c22 --- /dev/null +++ b/testing/web-platform/meta/webrtc/RTCPeerConnection-setRemoteDescription.html.ini @@ -0,0 +1,8 @@ +[RTCPeerConnection-setRemoteDescription.html] + type: testharness + [Malformed SDP description should be rejected with RTCError] + expected: FAIL + + [SDP type that is invalid for current signaling state should be rejected with InvalidStateError] + expected: FAIL + diff --git a/testing/web-platform/meta/webrtc/datachannel-idlharness.html.ini b/testing/web-platform/meta/webrtc/datachannel-idlharness.html.ini new file mode 100644 index 000000000000..1715f5a85271 --- /dev/null +++ b/testing/web-platform/meta/webrtc/datachannel-idlharness.html.ini @@ -0,0 +1,116 @@ +[datachannel-idlharness.html] + type: testharness + [RTCDataChannel interface: existence and properties of interface object] + expected: FAIL + + [RTCDataChannel interface object length] + expected: FAIL + + [RTCDataChannel interface object name] + expected: FAIL + + [RTCDataChannel interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCDataChannel interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [RTCDataChannel interface: attribute label] + expected: FAIL + + [RTCDataChannel interface: attribute ordered] + expected: FAIL + + [RTCDataChannel interface: attribute maxPacketLifeTime] + expected: FAIL + + [RTCDataChannel interface: attribute maxRetransmits] + expected: FAIL + + [RTCDataChannel interface: attribute protocol] + expected: FAIL + + [RTCDataChannel interface: attribute negotiated] + expected: FAIL + + [RTCDataChannel interface: attribute id] + expected: FAIL + + [RTCDataChannel interface: attribute priority] + expected: FAIL + + [RTCDataChannel interface: attribute readyState] + expected: FAIL + + [RTCDataChannel interface: attribute bufferedAmount] + expected: FAIL + + [RTCDataChannel interface: attribute bufferedAmountLowThreshold] + expected: FAIL + + [RTCDataChannel interface: attribute onopen] + expected: FAIL + + [RTCDataChannel interface: attribute onbufferedamountlow] + expected: FAIL + + [RTCDataChannel interface: attribute onerror] + expected: FAIL + + [RTCDataChannel interface: attribute onclose] + expected: FAIL + + [RTCDataChannel interface: operation close()] + expected: FAIL + + [RTCDataChannel interface: attribute onmessage] + expected: FAIL + + [RTCDataChannel interface: attribute binaryType] + expected: FAIL + + [RTCDataChannel interface: operation send(USVString)] + expected: FAIL + + [RTCDataChannel interface: operation send(Blob)] + expected: FAIL + + [RTCDataChannel interface: operation send(ArrayBuffer)] + expected: FAIL + + [RTCDataChannel interface: operation send(ArrayBufferView)] + expected: FAIL + + [RTCDataChannel must be primary interface of channel] + expected: FAIL + + [Stringification of channel] + expected: FAIL + + [RTCDataChannel interface: channel must inherit property "maxPacketLifeTime" with the proper type (2)] + expected: FAIL + + [RTCDataChannel interface: channel must inherit property "maxRetransmits" with the proper type (3)] + expected: FAIL + + [RTCDataChannel interface: channel must inherit property "negotiated" with the proper type (5)] + expected: FAIL + + [RTCDataChannel interface: channel must inherit property "priority" with the proper type (7)] + expected: FAIL + + [RTCDataChannel interface: channel must inherit property "onopen" with the proper type (11)] + expected: FAIL + + [RTCDataChannel interface: channel must inherit property "onbufferedamountlow" with the proper type (12)] + expected: FAIL + + [RTCDataChannel interface: channel must inherit property "onerror" with the proper type (13)] + expected: FAIL + + [RTCDataChannel interface: channel must inherit property "onclose" with the proper type (14)] + expected: FAIL + + [RTCDataChannel interface: channel must inherit property "onmessage" with the proper type (16)] + expected: FAIL + diff --git a/testing/web-platform/meta/webrtc/getstats.html.ini b/testing/web-platform/meta/webrtc/getstats.html.ini new file mode 100644 index 000000000000..0e48ea4d9d0a --- /dev/null +++ b/testing/web-platform/meta/webrtc/getstats.html.ini @@ -0,0 +1,5 @@ +[getstats.html] + type: testharness + [Can get stats from a basic WebRTC call.] + expected: FAIL + diff --git a/testing/web-platform/meta/webrtc/interfaces.html.ini b/testing/web-platform/meta/webrtc/interfaces.html.ini new file mode 100644 index 000000000000..84b2d14688b4 --- /dev/null +++ b/testing/web-platform/meta/webrtc/interfaces.html.ini @@ -0,0 +1,620 @@ +[interfaces.html] + type: testharness + [MediaStreamTrack interface: attribute isolated] + expected: FAIL + + [MediaStreamTrack interface: attribute onisolationchange] + expected: FAIL + + [RTCPeerConnection interface: existence and properties of interface object] + expected: FAIL + + [RTCPeerConnection interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCPeerConnection interface: attribute currentLocalDescription] + expected: FAIL + + [RTCPeerConnection interface: attribute pendingLocalDescription] + expected: FAIL + + [RTCPeerConnection interface: attribute currentRemoteDescription] + expected: FAIL + + [RTCPeerConnection interface: attribute pendingRemoteDescription] + expected: FAIL + + [RTCPeerConnection interface: attribute connectionState] + expected: FAIL + + [RTCPeerConnection interface: attribute defaultIceServers] + expected: FAIL + + [RTCPeerConnection interface: operation setConfiguration(RTCConfiguration)] + expected: FAIL + + [RTCPeerConnection interface: attribute onicecandidateerror] + expected: FAIL + + [RTCPeerConnection interface: attribute onconnectionstatechange] + expected: FAIL + + [RTCPeerConnection interface: attribute onfingerprintfailure] + expected: FAIL + + [RTCPeerConnection interface: operation getTransceivers()] + expected: FAIL + + [RTCPeerConnection interface: operation addTrack(MediaStreamTrack,MediaStream)] + expected: FAIL + + [RTCPeerConnection interface: operation addTransceiver([object Object\],[object Object\],RTCRtpTransceiverInit)] + expected: FAIL + + [RTCPeerConnection interface: attribute sctp] + expected: FAIL + + [RTCPeerConnection interface: attribute idpErrorInfo] + expected: FAIL + + [Stringification of new RTCPeerConnection] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "currentLocalDescription" with the proper type (4)] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "pendingLocalDescription" with the proper type (5)] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "currentRemoteDescription" with the proper type (8)] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "pendingRemoteDescription" with the proper type (9)] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "connectionState" with the proper type (14)] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "setConfiguration" with the proper type (18)] + expected: FAIL + + [RTCPeerConnection interface: calling setConfiguration(RTCConfiguration) on new RTCPeerConnection with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "onicecandidateerror" with the proper type (22)] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "onconnectionstatechange" with the proper type (26)] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "onfingerprintfailure" with the proper type (27)] + expected: FAIL + + [RTCPeerConnection interface: calling generateCertificate(AlgorithmIdentifier) on new RTCPeerConnection with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "getTransceivers" with the proper type (36)] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "addTransceiver" with the proper type (39)] + expected: FAIL + + [RTCPeerConnection interface: calling addTransceiver([object Object\],[object Object\],RTCRtpTransceiverInit) on new RTCPeerConnection with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "sctp" with the proper type (41)] + expected: FAIL + + [RTCPeerConnection interface: new RTCPeerConnection must inherit property "idpErrorInfo" with the proper type (49)] + expected: FAIL + + [RTCSessionDescription interface object length] + expected: FAIL + + [RTCSessionDescription interface: attribute type] + expected: FAIL + + [RTCSessionDescription interface: attribute sdp] + expected: FAIL + + [RTCIceCandidate interface: attribute candidate] + expected: FAIL + + [RTCIceCandidate interface: attribute sdpMid] + expected: FAIL + + [RTCIceCandidate interface: attribute sdpMLineIndex] + expected: FAIL + + [RTCIceCandidate interface: attribute foundation] + expected: FAIL + + [RTCIceCandidate interface: attribute priority] + expected: FAIL + + [RTCIceCandidate interface: attribute ip] + expected: FAIL + + [RTCIceCandidate interface: attribute protocol] + expected: FAIL + + [RTCIceCandidate interface: attribute port] + expected: FAIL + + [RTCIceCandidate interface: attribute type] + expected: FAIL + + [RTCIceCandidate interface: attribute tcpType] + expected: FAIL + + [RTCIceCandidate interface: attribute relatedAddress] + expected: FAIL + + [RTCIceCandidate interface: attribute relatedPort] + expected: FAIL + + [RTCIceCandidate interface: attribute ufrag] + expected: FAIL + + [RTCIceCandidate must be primary interface of new RTCIceCandidate] + expected: FAIL + + [Stringification of new RTCIceCandidate] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "candidate" with the proper type (0)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "sdpMid" with the proper type (1)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "sdpMLineIndex" with the proper type (2)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "foundation" with the proper type (3)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "priority" with the proper type (4)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "ip" with the proper type (5)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "protocol" with the proper type (6)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "port" with the proper type (7)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "type" with the proper type (8)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "tcpType" with the proper type (9)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "relatedAddress" with the proper type (10)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "relatedPort" with the proper type (11)] + expected: FAIL + + [RTCIceCandidate interface: new RTCIceCandidate must inherit property "ufrag" with the proper type (12)] + expected: FAIL + + [RTCPeerConnectionIceEvent interface: existence and properties of interface object] + expected: FAIL + + [RTCPeerConnectionIceEvent interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCPeerConnectionIceEvent interface: attribute url] + expected: FAIL + + [Stringification of new RTCPeerConnectionIceEvent("ice")] + expected: FAIL + + [RTCPeerConnectionIceEvent interface: new RTCPeerConnectionIceEvent("ice") must inherit property "url" with the proper type (1)] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: existence and properties of interface object] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface object length] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface object name] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: attribute hostCandidate] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: attribute url] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: attribute errorCode] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: attribute errorText] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent must be primary interface of new RTCPeerConnectionIceErrorEvent("ice-error", { errorCode: 701 });] + expected: FAIL + + [Stringification of new RTCPeerConnectionIceErrorEvent("ice-error", { errorCode: 701 });] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: new RTCPeerConnectionIceErrorEvent("ice-error", { errorCode: 701 }); must inherit property "hostCandidate" with the proper type (0)] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: new RTCPeerConnectionIceErrorEvent("ice-error", { errorCode: 701 }); must inherit property "url" with the proper type (1)] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: new RTCPeerConnectionIceErrorEvent("ice-error", { errorCode: 701 }); must inherit property "errorCode" with the proper type (2)] + expected: FAIL + + [RTCPeerConnectionIceErrorEvent interface: new RTCPeerConnectionIceErrorEvent("ice-error", { errorCode: 701 }); must inherit property "errorText" with the proper type (3)] + expected: FAIL + + [RTCCertificate interface: attribute fingerprints] + expected: FAIL + + [RTCCertificate interface: operation getAlgorithm()] + expected: FAIL + + [RTCCertificate interface: certificate must inherit property "fingerprints" with the proper type (1)] + expected: FAIL + + [RTCCertificate interface: certificate must inherit property "getAlgorithm" with the proper type (2)] + expected: FAIL + + [RTCRtpSender interface: attribute transport] + expected: FAIL + + [RTCRtpSender interface: attribute rtcpTransport] + expected: FAIL + + [RTCRtpSender interface: operation getCapabilities(DOMString)] + expected: FAIL + + [RTCRtpReceiver interface: attribute transport] + expected: FAIL + + [RTCRtpReceiver interface: attribute rtcpTransport] + expected: FAIL + + [RTCRtpReceiver interface: operation getCapabilities(DOMString)] + expected: FAIL + + [RTCRtpReceiver interface: operation getParameters()] + expected: FAIL + + [RTCRtpReceiver interface: operation getContributingSources()] + expected: FAIL + + [RTCRtpContributingSource interface: existence and properties of interface object] + expected: FAIL + + [RTCRtpContributingSource interface object length] + expected: FAIL + + [RTCRtpContributingSource interface object name] + expected: FAIL + + [RTCRtpContributingSource interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCRtpContributingSource interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [RTCRtpContributingSource interface: attribute timestamp] + expected: FAIL + + [RTCRtpContributingSource interface: attribute source] + expected: FAIL + + [RTCRtpContributingSource interface: attribute audioLevel] + expected: FAIL + + [RTCRtpContributingSource interface: attribute voiceActivityFlag] + expected: FAIL + + [RTCRtpTransceiver interface: existence and properties of interface object] + expected: FAIL + + [RTCRtpTransceiver interface object length] + expected: FAIL + + [RTCRtpTransceiver interface object name] + expected: FAIL + + [RTCRtpTransceiver interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCRtpTransceiver interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [RTCRtpTransceiver interface: attribute mid] + expected: FAIL + + [RTCRtpTransceiver interface: attribute sender] + expected: FAIL + + [RTCRtpTransceiver interface: attribute receiver] + expected: FAIL + + [RTCRtpTransceiver interface: attribute stopped] + expected: FAIL + + [RTCRtpTransceiver interface: attribute direction] + expected: FAIL + + [RTCRtpTransceiver interface: attribute currentDirection] + expected: FAIL + + [RTCRtpTransceiver interface: operation setDirection(RTCRtpTransceiverDirection)] + expected: FAIL + + [RTCRtpTransceiver interface: operation stop()] + expected: FAIL + + [RTCRtpTransceiver interface: operation setCodecPreferences([object Object\])] + expected: FAIL + + [RTCDtlsTransport interface: existence and properties of interface object] + expected: FAIL + + [RTCDtlsTransport interface object length] + expected: FAIL + + [RTCDtlsTransport interface object name] + expected: FAIL + + [RTCDtlsTransport interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCDtlsTransport interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [RTCDtlsTransport interface: attribute transport] + expected: FAIL + + [RTCDtlsTransport interface: attribute state] + expected: FAIL + + [RTCDtlsTransport interface: operation getRemoteCertificates()] + expected: FAIL + + [RTCDtlsTransport interface: attribute onstatechange] + expected: FAIL + + [RTCIceTransport interface: existence and properties of interface object] + expected: FAIL + + [RTCIceTransport interface object length] + expected: FAIL + + [RTCIceTransport interface object name] + expected: FAIL + + [RTCIceTransport interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCIceTransport interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [RTCIceTransport interface: attribute role] + expected: FAIL + + [RTCIceTransport interface: attribute component] + expected: FAIL + + [RTCIceTransport interface: attribute state] + expected: FAIL + + [RTCIceTransport interface: attribute gatheringState] + expected: FAIL + + [RTCIceTransport interface: operation getLocalCandidates()] + expected: FAIL + + [RTCIceTransport interface: operation getRemoteCandidates()] + expected: FAIL + + [RTCIceTransport interface: operation getSelectedCandidatePair()] + expected: FAIL + + [RTCIceTransport interface: operation getLocalParameters()] + expected: FAIL + + [RTCIceTransport interface: operation getRemoteParameters()] + expected: FAIL + + [RTCIceTransport interface: attribute onstatechange] + expected: FAIL + + [RTCIceTransport interface: attribute ongatheringstatechange] + expected: FAIL + + [RTCIceTransport interface: attribute onselectedcandidatepairchange] + expected: FAIL + + [RTCTrackEvent interface: existence and properties of interface object] + expected: FAIL + + [RTCTrackEvent interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCTrackEvent interface: attribute transceiver] + expected: FAIL + + [RTCSctpTransport interface: existence and properties of interface object] + expected: FAIL + + [RTCSctpTransport interface object length] + expected: FAIL + + [RTCSctpTransport interface object name] + expected: FAIL + + [RTCSctpTransport interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCSctpTransport interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [RTCSctpTransport interface: attribute transport] + expected: FAIL + + [RTCSctpTransport interface: attribute maxMessageSize] + expected: FAIL + + [RTCDataChannel interface: existence and properties of interface object] + expected: FAIL + + [RTCDataChannel interface object length] + expected: FAIL + + [RTCDataChannel interface object name] + expected: FAIL + + [RTCDataChannel interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCDataChannel interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [RTCDataChannel interface: attribute label] + expected: FAIL + + [RTCDataChannel interface: attribute ordered] + expected: FAIL + + [RTCDataChannel interface: attribute maxPacketLifeTime] + expected: FAIL + + [RTCDataChannel interface: attribute maxRetransmits] + expected: FAIL + + [RTCDataChannel interface: attribute protocol] + expected: FAIL + + [RTCDataChannel interface: attribute negotiated] + expected: FAIL + + [RTCDataChannel interface: attribute id] + expected: FAIL + + [RTCDataChannel interface: attribute priority] + expected: FAIL + + [RTCDataChannel interface: attribute readyState] + expected: FAIL + + [RTCDataChannel interface: attribute bufferedAmount] + expected: FAIL + + [RTCDataChannel interface: attribute bufferedAmountLowThreshold] + expected: FAIL + + [RTCDataChannel interface: attribute onopen] + expected: FAIL + + [RTCDataChannel interface: attribute onbufferedamountlow] + expected: FAIL + + [RTCDataChannel interface: attribute onerror] + expected: FAIL + + [RTCDataChannel interface: attribute onclose] + expected: FAIL + + [RTCDataChannel interface: operation close()] + expected: FAIL + + [RTCDataChannel interface: attribute onmessage] + expected: FAIL + + [RTCDataChannel interface: attribute binaryType] + expected: FAIL + + [RTCDataChannel interface: operation send(USVString)] + expected: FAIL + + [RTCDataChannel interface: operation send(Blob)] + expected: FAIL + + [RTCDataChannel interface: operation send(ArrayBuffer)] + expected: FAIL + + [RTCDataChannel interface: operation send(ArrayBufferView)] + expected: FAIL + + [RTCDataChannelEvent interface: existence and properties of interface object] + expected: FAIL + + [RTCDataChannelEvent interface object length] + expected: FAIL + + [RTCDataChannelEvent interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCDTMFSender interface: existence and properties of interface object] + expected: FAIL + + [RTCDTMFSender interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCDTMFToneChangeEvent interface: existence and properties of interface object] + expected: FAIL + + [RTCDTMFToneChangeEvent interface object length] + expected: FAIL + + [RTCDTMFToneChangeEvent interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCIdentityAssertion interface: existence and properties of interface object] + expected: FAIL + + [RTCIdentityAssertion interface object length] + expected: FAIL + + [RTCIdentityAssertion interface object name] + expected: FAIL + + [RTCIdentityAssertion interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCIdentityAssertion interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [RTCIdentityAssertion interface: attribute idp] + expected: FAIL + + [RTCIdentityAssertion interface: attribute name] + expected: FAIL + + [RTCErrorEvent interface: existence and properties of interface object] + expected: FAIL + + [RTCErrorEvent interface object length] + expected: FAIL + + [RTCErrorEvent interface object name] + expected: FAIL + + [RTCErrorEvent interface: existence and properties of interface prototype object] + expected: FAIL + + [RTCErrorEvent interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [RTCErrorEvent interface: attribute error] + expected: FAIL + diff --git a/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini b/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini deleted file mode 100644 index bce99d6f655d..000000000000 --- a/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini +++ /dev/null @@ -1,212 +0,0 @@ -[rtcpeerconnection-idl.html] - type: testharness - [RTCPeerConnection interface: operation createOffer(RTCSessionDescriptionCallback,RTCPeerConnectionErrorCallback,RTCOfferOptions)] - expected: FAIL - - [RTCPeerConnection interface: operation setLocalDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback)] - expected: FAIL - - [RTCPeerConnection interface: operation createAnswer(RTCSessionDescriptionCallback,RTCPeerConnectionErrorCallback)] - expected: FAIL - - [RTCPeerConnection interface: operation setRemoteDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback)] - expected: FAIL - - [RTCPeerConnection interface: operation addIceCandidate(RTCIceCandidate,VoidFunction,RTCPeerConnectionErrorCallback)] - expected: FAIL - - [RTCPeerConnection interface: operation addTrack(MediaStreamTrack,MediaStream)] - expected: FAIL - - [RTCPeerConnection interface: operation getStats(MediaStreamTrack,RTCStatsCallback,RTCPeerConnectionErrorCallback)] - expected: FAIL - - [RTCPeerConnection interface: calling setLocalDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] - expected: FAIL - - [RTCPeerConnection interface: calling setRemoteDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] - expected: FAIL - - [RTCPeerConnection interface: calling addIceCandidate(RTCIceCandidate,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] - expected: FAIL - - [RTCPeerConnection interface: attribute currentLocalDescription] - expected: FAIL - - [RTCPeerConnection interface: attribute pendingLocalDescription] - expected: FAIL - - [RTCPeerConnection interface: attribute currentRemoteDescription] - expected: FAIL - - [RTCPeerConnection interface: attribute pendingRemoteDescription] - expected: FAIL - - [RTCPeerConnection interface: operation setConfiguration(RTCConfiguration)] - expected: FAIL - - [RTCPeerConnection interface: attribute dtmf] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "currentLocalDescription" with the proper type (4)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "pendingLocalDescription" with the proper type (5)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "currentRemoteDescription" with the proper type (8)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "pendingRemoteDescription" with the proper type (9)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "signalingState" with the proper type (11)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "iceGatheringState" with the proper type (12)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "iceConnectionState" with the proper type (13)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "setConfiguration" with the proper type (16)] - expected: FAIL - - [RTCPeerConnection interface: calling setConfiguration(RTCConfiguration) on pc with too few arguments must throw TypeError] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onnegotiationneeded" with the proper type (18)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onicecandidate" with the proper type (19)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onsignalingstatechange" with the proper type (20)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "oniceconnectionstatechange" with the proper type (21)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onicegatheringstatechange" with the proper type (22)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "ontrack" with the proper type (34)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "ondatachannel" with the proper type (36)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "dtmf" with the proper type (37)] - expected: FAIL - - [RTCPeerConnection interface: operation createAnswer()] - expected: FAIL - - [RTCPeerConnection interface: operation updateIce(RTCConfiguration)] - expected: FAIL - - [RTCPeerConnection interface: operation createOffer(RTCSessionDescriptionCallback,RTCPeerConnectionErrorCallback,RTCOfferOptions)] - expected: FAIL - - [RTCPeerConnection interface: operation setLocalDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback)] - expected: FAIL - - [RTCPeerConnection interface: operation createAnswer(RTCSessionDescriptionCallback,RTCPeerConnectionErrorCallback)] - expected: FAIL - - [RTCPeerConnection interface: operation setRemoteDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback)] - expected: FAIL - - [RTCPeerConnection interface: operation addIceCandidate(RTCIceCandidate,VoidFunction,RTCPeerConnectionErrorCallback)] - expected: FAIL - - [RTCPeerConnection interface: operation addTrack(MediaStreamTrack,MediaStream)] - expected: FAIL - - [RTCPeerConnection interface: operation createDTMFSender(MediaStreamTrack)] - expected: FAIL - - [RTCPeerConnection interface: operation getStats(MediaStreamTrack,RTCStatsCallback,RTCPeerConnectionErrorCallback)] - expected: FAIL - - [RTCPeerConnection interface: attribute onidentityresult] - expected: FAIL - - [RTCPeerConnection interface: attribute onpeeridentity] - expected: FAIL - - [RTCPeerConnection interface: attribute onidpassertionerror] - expected: FAIL - - [RTCPeerConnection interface: attribute onidpvalidationerror] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "signalingState" with the proper type (6)] - expected: FAIL - - [RTCPeerConnection interface: calling updateIce(RTCConfiguration) on pc with too few arguments must throw TypeError] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "iceGatheringState" with the proper type (9)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "iceConnectionState" with the proper type (10)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "canTrickleIceCandidates" with the proper type (11)] - expected: PASS - - [RTCPeerConnection interface: pc must inherit property "onnegotiationneeded" with the proper type (14)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onicecandidate" with the proper type (15)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onsignalingstatechange" with the proper type (16)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "oniceconnectionstatechange" with the proper type (17)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onicegatheringstatechange" with the proper type (18)] - expected: FAIL - - [RTCPeerConnection interface: calling setLocalDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] - expected: FAIL - - [RTCPeerConnection interface: calling setRemoteDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] - expected: FAIL - - [RTCPeerConnection interface: calling addIceCandidate(RTCIceCandidate,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "ontrack" with the proper type (28)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "ondatachannel" with the proper type (30)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "createDTMFSender" with the proper type (31)] - expected: FAIL - - [RTCPeerConnection interface: calling createDTMFSender(MediaStreamTrack) on pc with too few arguments must throw TypeError] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "peerIdentity" with the proper type (35)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onidentityresult" with the proper type (36)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onpeeridentity" with the proper type (37)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onidpassertionerror" with the proper type (38)] - expected: FAIL - - [RTCPeerConnection interface: pc must inherit property "onidpvalidationerror" with the proper type (39)] - expected: FAIL - - [RTCPeerConnection interface: calling generateCertificate(AlgorithmIdentifier) on pc with too few arguments must throw TypeError] - expected: FAIL - diff --git a/testing/web-platform/meta/websockets/constructor/011.html.ini b/testing/web-platform/meta/websockets/constructor/011.html.ini index 6af7d3201550..f8593fd519b9 100644 --- a/testing/web-platform/meta/websockets/constructor/011.html.ini +++ b/testing/web-platform/meta/websockets/constructor/011.html.ini @@ -8,3 +8,4 @@ type: testharness [WebSockets: protocol mismatch] expected: FAIL + diff --git a/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/selectors/cue/white-space_pre-line_wrapped.html.ini b/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/selectors/cue/white-space_pre-line_wrapped.html.ini index a0fdfa7de125..e6521e5d2e85 100644 --- a/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/selectors/cue/white-space_pre-line_wrapped.html.ini +++ b/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/selectors/cue/white-space_pre-line_wrapped.html.ini @@ -1,4 +1,3 @@ [white-space_pre-line_wrapped.html] type: reftest expected: FAIL - diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html.ini b/testing/web-platform/meta/workers/opaque-origin.html.ini similarity index 64% rename from testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html.ini rename to testing/web-platform/meta/workers/opaque-origin.html.ini index 28df3c421891..8614a7b3ad76 100644 --- a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html.ini +++ b/testing/web-platform/meta/workers/opaque-origin.html.ini @@ -1,3 +1,3 @@ -[test_ecdh_bits.html] +[opaque-origin.html] type: testharness expected: TIMEOUT diff --git a/testing/web-platform/moz.build b/testing/web-platform/moz.build index 889fc45630dd..673584727d8c 100644 --- a/testing/web-platform/moz.build +++ b/testing/web-platform/moz.build @@ -150,9 +150,6 @@ with Files("tests/selection/**"): with Files("tests/selectors/**"): BUG_COMPONENT = ("Core", "DOM") -with Files("tests/selectors-api/**"): - BUG_COMPONENT = ("Core", "DOM") - with Files("tests/service-workers/**"): BUG_COMPONENT = ("Core", "DOM: Service Workers") diff --git a/testing/web-platform/tests/.codecov.yml b/testing/web-platform/tests/.codecov.yml new file mode 100644 index 000000000000..904cf85a4fd7 --- /dev/null +++ b/testing/web-platform/tests/.codecov.yml @@ -0,0 +1,6 @@ +comment: + require_changes: yes + +ignore: + - "**" + - "!tools/.*" diff --git a/testing/web-platform/tests/.gitmodules b/testing/web-platform/tests/.gitmodules index 5eb46bc69154..41d2a66089be 100644 --- a/testing/web-platform/tests/.gitmodules +++ b/testing/web-platform/tests/.gitmodules @@ -1,14 +1,12 @@ -[submodule "resources"] - path = resources - url = https://github.com/w3c/testharness.js.git - ignore = dirty -[submodule "tools"] - path = tools - url = https://github.com/w3c/wpt-tools.git - ignore = dirty [submodule "css/tools/apiclient"] path = css/tools/apiclient url = https://github.com/w3c/csswg-apiclient.git [submodule "css/tools/w3ctestlib"] path = css/tools/w3ctestlib url = https://github.com/w3c/csswg-w3ctestlib.git +[submodule "tools/html5lib/html5lib/tests/testdata"] + path = tools/html5lib/html5lib/tests/testdata + url = https://github.com/html5lib/html5lib-tests.git +[submodule "resources/webidl2/test/widlproc"] + path = resources/webidl2/test/widlproc + url = https://github.com/dontcallmedom/widlproc.git \ No newline at end of file diff --git a/testing/web-platform/tests/.travis.yml b/testing/web-platform/tests/.travis.yml index a558820fd4ea..f413d82fe00b 100644 --- a/testing/web-platform/tests/.travis.yml +++ b/testing/web-platform/tests/.travis.yml @@ -1,6 +1,9 @@ dist: trusty sudo: required language: python +branches: + only: + - master addons: hosts: - web-platform.test @@ -18,6 +21,7 @@ install: - pip install -U requests env: # required at the top-level for allow_failures to work below matrix: + fast_finish: true include: - os: linux python: "2.7" @@ -48,10 +52,21 @@ matrix: env: - secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM=" - SCRIPT=ci_stability.sh PRODUCT=chrome:unstable + - python: 2.7 + env: TOXENV=py27 HYPOTHESIS_PROFILE=ci SCRIPT=ci_unittest.sh + - python: 3.5 + env: TOXENV=py35 HYPOTHESIS_PROFILE=ci SCRIPT=ci_unittest.sh + - python: 3.6 + env: TOXENV=py36 HYPOTHESIS_PROFILE=ci SCRIPT=ci_unittest.sh + - python: pypy + env: TOXENV=pypy HYPOTHESIS_PROFILE=ci_pypy SCRIPT=ci_unittest.sh exclude: - env: # exclude empty env from the top-level above allow_failures: - env: SCRIPT=css/build-css-testsuites.sh + - env: + - secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM=" + - SCRIPT=ci_stability.sh PRODUCT=chrome:unstable script: - bash $SCRIPT cache: diff --git a/testing/web-platform/tests/2dcontext/2x4.png b/testing/web-platform/tests/2dcontext/2x4.png new file mode 100644 index 000000000000..f5589a731840 Binary files /dev/null and b/testing/web-platform/tests/2dcontext/2x4.png differ diff --git a/testing/web-platform/tests/2dcontext/4x2.png b/testing/web-platform/tests/2dcontext/4x2.png new file mode 100644 index 000000000000..4a8d81e7c22f Binary files /dev/null and b/testing/web-platform/tests/2dcontext/4x2.png differ diff --git a/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14.html b/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14.html new file mode 100644 index 000000000000..0a28aa462831 --- /dev/null +++ b/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14.html @@ -0,0 +1,33 @@ + + + +Canvas test: 2d.drawImage.crop.2x4 + + + + diff --git a/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14_ref.html b/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14_ref.html new file mode 100644 index 000000000000..f682f87cc6f4 --- /dev/null +++ b/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_14_ref.html @@ -0,0 +1,25 @@ + + + + + + + +
+ + diff --git a/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15.html b/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15.html new file mode 100644 index 000000000000..507ff31eb9d8 --- /dev/null +++ b/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15.html @@ -0,0 +1,33 @@ + + + +Canvas test: 2d.drawImage.crop.4x2 + + + + diff --git a/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15_ref.html b/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15_ref.html new file mode 100644 index 000000000000..a7abc3cb28ac --- /dev/null +++ b/testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_15_ref.html @@ -0,0 +1,25 @@ + + + + + + + +
+ + diff --git a/testing/web-platform/tests/2dcontext/tools/gentestutils.py b/testing/web-platform/tests/2dcontext/tools/gentestutils.py index 469c33a30fea..fb7bf18d2343 100644 --- a/testing/web-platform/tests/2dcontext/tools/gentestutils.py +++ b/testing/web-platform/tests/2dcontext/tools/gentestutils.py @@ -235,10 +235,6 @@ def genTestUtils(TESTOUTPUTDIR, IMAGEOUTPUTDIR, TEMPLATEFILE, NAME2DIRFILE, ISOF r'assert_throws(new \1(), function() { \2; });', code) - code = re.sub(r'@assert throws (.*);', - r'assert_throws(null, function() { \1; });', - code) - code = re.sub(r'@assert (.*) === (.*);', lambda m: '_assertSame(%s, %s, "%s", "%s");' % (m.group(1), m.group(2), escapeJS(m.group(1)), escapeJS(m.group(2))) diff --git a/testing/web-platform/tests/IndexedDB/idb_webworkers.htm b/testing/web-platform/tests/IndexedDB/idb_webworkers.htm index dba3a93f120a..9c29d00b30e1 100644 --- a/testing/web-platform/tests/IndexedDB/idb_webworkers.htm +++ b/testing/web-platform/tests/IndexedDB/idb_webworkers.htm @@ -8,6 +8,7 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-advance-continue-async.htm b/testing/web-platform/tests/IndexedDB/idbcursor-advance-continue-async.htm index d1b6af3e189e..ccadb7fa95a6 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-advance-continue-async.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-advance-continue-async.htm @@ -7,180 +7,175 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-advance-invalid.htm b/testing/web-platform/tests/IndexedDB/idbcursor-advance-invalid.htm index dda216b75316..ee911cc9e4bc 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-advance-invalid.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-advance-invalid.htm @@ -13,176 +13,180 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-advance.htm b/testing/web-platform/tests/IndexedDB/idbcursor-advance.htm index f4ecbc0e5aac..f08a2594f3dd 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-advance.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-advance.htm @@ -7,237 +7,241 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-continue.htm b/testing/web-platform/tests/IndexedDB/idbcursor-continue.htm index 968cd9cbd09d..372d452f7813 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-continue.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-continue.htm @@ -9,232 +9,240 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-continuePrimaryKey-exception-order.htm b/testing/web-platform/tests/IndexedDB/idbcursor-continuePrimaryKey-exception-order.htm index 0d35218b9e0a..56a23a1123ff 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-continuePrimaryKey-exception-order.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-continuePrimaryKey-exception-order.htm @@ -45,12 +45,12 @@ indexeddb_test( store.deleteIndex("idx"); }); - txn.oncomplete = function() { + txn.oncomplete = t.step_func(function() { assert_throws("TransactionInactiveError", function() { cursor.continuePrimaryKey("A", 4); }, "transaction-state check should precede deletion check"); t.done(); - }; + }); }, null, "TransactionInactiveError v.s. InvalidStateError(deleted index)" @@ -378,5 +378,3 @@ indexeddb_test( "DataError(keys are larger then current one) in 'prev' direction" ); - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-continuePrimaryKey-exceptions.htm b/testing/web-platform/tests/IndexedDB/idbcursor-continuePrimaryKey-exceptions.htm index d6785137bb1d..9393e2fbf24f 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-continuePrimaryKey-exceptions.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-continuePrimaryKey-exceptions.htm @@ -16,6 +16,10 @@ async_test(function(t) { open.onupgradeneeded = t.step_func(function() { var db = open.result; + t.add_cleanup(function() { + db.close(); + indexedDB.deleteDatabase(db.name); + }); var store = db.createObjectStore('store'); store.put('a', 1).onerror = t.unreached_func('put should not fail'); var request = store.openCursor(); @@ -60,6 +64,10 @@ async_test(function(t) { open.onupgradeneeded = t.step_func(function() { var db = open.result; + t.add_cleanup(function() { + db.close(); + indexedDB.deleteDatabase(db.name); + }); var store = db.createObjectStore('store', {keyPath: 'pk'}); var index = store.createIndex('index', 'ik', {multiEntry: true}); store.put({pk: 'a', ik: [1,2,3]}).onerror = diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-direction-index-keyrange.htm b/testing/web-platform/tests/IndexedDB/idbcursor-direction-index-keyrange.htm index e0f0c6d0ad0e..2de3854dc9bf 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-direction-index-keyrange.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-direction-index-keyrange.htm @@ -15,69 +15,46 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-direction-index.htm b/testing/web-platform/tests/IndexedDB/idbcursor-direction-index.htm index 39afcb24d86d..0eb926d9ec0f 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-direction-index.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-direction-index.htm @@ -13,69 +13,45 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-direction-objectstore-keyrange.htm b/testing/web-platform/tests/IndexedDB/idbcursor-direction-objectstore-keyrange.htm index 7bcb971bbb68..96f92a0445a4 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-direction-objectstore-keyrange.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-direction-objectstore-keyrange.htm @@ -11,68 +11,44 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-direction-objectstore.htm b/testing/web-platform/tests/IndexedDB/idbcursor-direction-objectstore.htm index c02355395a29..85088ee72444 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-direction-objectstore.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-direction-objectstore.htm @@ -13,68 +13,44 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-direction.htm b/testing/web-platform/tests/IndexedDB/idbcursor-direction.htm index b50eded79085..246cd79aac8b 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-direction.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-direction.htm @@ -17,6 +17,11 @@ open_rq.onupgradeneeded = function(e) { db = e.target.result; + t.add_cleanup(function() { + db.close(); + indexedDB.deleteDatabase(db.name); + }); + var objStore = db.createObjectStore("test"); objStore.add("data", "key"); @@ -69,5 +74,3 @@ cursor_direction("prevunique", "prevunique"); - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor-source.htm b/testing/web-platform/tests/IndexedDB/idbcursor-source.htm index 7e3746ae7e6b..b23551c8d49c 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor-source.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor-source.htm @@ -6,63 +6,61 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor_iterating.htm b/testing/web-platform/tests/IndexedDB/idbcursor_iterating.htm index fd3cd0a690d5..d9be6b6ad6a4 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor_iterating.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor_iterating.htm @@ -13,6 +13,7 @@ var open_rq = createdb(t); open_rq.onupgradeneeded = function(e) { db = e.target.result; + t.add_cleanup(function() { db.close(); indexedDB.deleteDatabase(db.name); }); var objStore = db.createObjectStore("test", { keyPath: "key" }); for (var i = 0; i < 500; i++) @@ -106,5 +107,3 @@ }); }; - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor_iterating_objectstore.htm b/testing/web-platform/tests/IndexedDB/idbcursor_iterating_objectstore.htm index db66c4db33be..c4c8d57148de 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor_iterating_objectstore.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor_iterating_objectstore.htm @@ -18,6 +18,7 @@ var open_rq = createdb(t); open_rq.onupgradeneeded = function(e) { db = e.target.result; + t.add_cleanup(function() { db.close(); indexedDB.deleteDatabase(db.name); }); var objStore = db.createObjectStore("test", {keyPath:"pKey"}); for (var i = 0; i < records.length; i++) @@ -47,5 +48,3 @@ }); }; - -
diff --git a/testing/web-platform/tests/IndexedDB/idbcursor_iterating_objectstore2.htm b/testing/web-platform/tests/IndexedDB/idbcursor_iterating_objectstore2.htm index 2374a854e446..899b2ac0e6da 100644 --- a/testing/web-platform/tests/IndexedDB/idbcursor_iterating_objectstore2.htm +++ b/testing/web-platform/tests/IndexedDB/idbcursor_iterating_objectstore2.htm @@ -18,6 +18,7 @@ var open_rq = createdb(t); open_rq.onupgradeneeded = function(e) { db = e.target.result; + t.add_cleanup(function() { db.close(); indexedDB.deleteDatabase(db.name); }); var objStore = db.createObjectStore("test", {keyPath:"pKey"}); for (var i = 0; i < records.length; i++) @@ -47,5 +48,3 @@ }); }; - -
diff --git a/testing/web-platform/tests/IndexedDB/idbdatabase-transaction-exception-order.html b/testing/web-platform/tests/IndexedDB/idbdatabase-transaction-exception-order.html index 686f44ef5cb6..c0021d926a83 100644 --- a/testing/web-platform/tests/IndexedDB/idbdatabase-transaction-exception-order.html +++ b/testing/web-platform/tests/IndexedDB/idbdatabase-transaction-exception-order.html @@ -45,10 +45,10 @@ indexeddb_test( assert_throws('NotFoundError', () => { db.transaction('no-such-store', 'versionchange'); }, '"No such store" check (NotFoundError) should precede ' + - '"invalid mode" check (InvalidAccessError)'); + '"invalid mode" check (TypeError)'); t.done(); }, - 'IDBDatabase.transaction exception order: NotFoundError vs. InvalidAccessError' + 'IDBDatabase.transaction exception order: NotFoundError vs. TypeError' ); diff --git a/testing/web-platform/tests/IndexedDB/idbdatabase_close.htm b/testing/web-platform/tests/IndexedDB/idbdatabase_close.htm index dc3f585a8cd1..781f8cba9d18 100644 --- a/testing/web-platform/tests/IndexedDB/idbdatabase_close.htm +++ b/testing/web-platform/tests/IndexedDB/idbdatabase_close.htm @@ -33,6 +33,7 @@ open_rq.onsuccess = function(e) { assert_equals(blocked_fired, 1, 'block event fired #') assert_equals(upgradeneeded_fired, 2, 'second upgradeneeded event fired #') + rq.result.close(); t.done(); }); rq.onerror = fail(t, 'Unexpected database deletion error'); diff --git a/testing/web-platform/tests/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm b/testing/web-platform/tests/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm index 0a6dc03a67ab..4a28d4033c08 100644 --- a/testing/web-platform/tests/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm +++ b/testing/web-platform/tests/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm @@ -7,11 +7,11 @@ diff --git a/testing/web-platform/tests/IndexedDB/idbfactory_open10.htm b/testing/web-platform/tests/IndexedDB/idbfactory_open10.htm index 598046ff98f9..c0ac71ae8576 100644 --- a/testing/web-platform/tests/IndexedDB/idbfactory_open10.htm +++ b/testing/web-platform/tests/IndexedDB/idbfactory_open10.htm @@ -81,6 +81,8 @@ }); idx.getKey("Sicking").onsuccess = this.step_func(function(e) { assert_equals(e.target.result, undefined, "getKey(Sicking)"); + + db3.close(); this.done(); }); }); diff --git a/testing/web-platform/tests/IndexedDB/idbfactory_open11.htm b/testing/web-platform/tests/IndexedDB/idbfactory_open11.htm index 66ea9d52559b..88c59bd9f65c 100644 --- a/testing/web-platform/tests/IndexedDB/idbfactory_open11.htm +++ b/testing/web-platform/tests/IndexedDB/idbfactory_open11.htm @@ -51,6 +51,8 @@ count_done++; assert_equals(count_done, 3, "count_done"); + + db2.close(); this.done(); }); }); diff --git a/testing/web-platform/tests/IndexedDB/idbfactory_open3.htm b/testing/web-platform/tests/IndexedDB/idbfactory_open3.htm index 9ec6db5ab861..ac8ca5e1b655 100644 --- a/testing/web-platform/tests/IndexedDB/idbfactory_open3.htm +++ b/testing/web-platform/tests/IndexedDB/idbfactory_open3.htm @@ -17,6 +17,7 @@ var open_rq2 = window.indexedDB.open(db.name); open_rq2.onsuccess = this.step_func(function(e) { assert_equals(e.target.result.version, 13, "db.version") + e.target.result.close(); this.done(); }); open_rq2.onupgradeneeded = fail(this, 'Unexpected upgradeneeded') diff --git a/testing/web-platform/tests/IndexedDB/idbfactory_open6.htm b/testing/web-platform/tests/IndexedDB/idbfactory_open6.htm index bbb8ac02d37f..c2e2c080d0c3 100644 --- a/testing/web-platform/tests/IndexedDB/idbfactory_open6.htm +++ b/testing/web-platform/tests/IndexedDB/idbfactory_open6.htm @@ -8,13 +8,14 @@ + diff --git a/testing/web-platform/tests/IndexedDB/idbindex_getAllKeys.html b/testing/web-platform/tests/IndexedDB/idbindex_getAllKeys.html index 7653a5152605..a882312db48f 100644 --- a/testing/web-platform/tests/IndexedDB/idbindex_getAllKeys.html +++ b/testing/web-platform/tests/IndexedDB/idbindex_getAllKeys.html @@ -2,25 +2,14 @@ IndexedDB: Test IDBIndex.getAllKeys. + diff --git a/testing/web-platform/tests/IndexedDB/idbobjectstore-index-finished.html b/testing/web-platform/tests/IndexedDB/idbobjectstore-index-finished.html new file mode 100644 index 000000000000..75677cf39dc3 --- /dev/null +++ b/testing/web-platform/tests/IndexedDB/idbobjectstore-index-finished.html @@ -0,0 +1,26 @@ + + +IndexedDB: IDBObjectStore index() when transaction is finished + + + + + diff --git a/testing/web-platform/tests/IndexedDB/idbobjectstore_deleteIndex.htm b/testing/web-platform/tests/IndexedDB/idbobjectstore_deleteIndex.htm index 1e0fb2976c88..ebebbb7db486 100644 --- a/testing/web-platform/tests/IndexedDB/idbobjectstore_deleteIndex.htm +++ b/testing/web-platform/tests/IndexedDB/idbobjectstore_deleteIndex.htm @@ -35,6 +35,7 @@ assert_throws('NotFoundError', function() { index = objStore.index("index") }); assert_equals(index, undefined); + db.close(); t.done(); } } diff --git a/testing/web-platform/tests/IndexedDB/idbobjectstore_deleted.htm b/testing/web-platform/tests/IndexedDB/idbobjectstore_deleted.htm index 1d9421ce03af..74934636a1b6 100644 --- a/testing/web-platform/tests/IndexedDB/idbobjectstore_deleted.htm +++ b/testing/web-platform/tests/IndexedDB/idbobjectstore_deleted.htm @@ -28,16 +28,17 @@ db.deleteObjectStore("store"); assert_equals(db.objectStoreNames.length, 0, "objectStoreNames.length after delete"); - assert_throws(null, function() { objStore.add(2); }); - assert_throws(null, function() { objStore.put(3); }); - assert_throws(null, function() { objStore.get(1); }); - assert_throws(null, function() { objStore.clear(); }); - assert_throws(null, function() { objStore.count(); }); - assert_throws(null, function() { objStore.delete(1); }); - assert_throws(null, function() { objStore.openCursor(); }); - assert_throws(null, function() { objStore.index("idx"); }); - assert_throws(null, function() { objStore.deleteIndex("idx"); }); - assert_throws(null, function() { objStore.createIndex("idx2", "a"); }); + const exc = "InvalidStateError" + assert_throws(exc, function() { objStore.add(2); }); + assert_throws(exc, function() { objStore.put(3); }); + assert_throws(exc, function() { objStore.get(1); }); + assert_throws(exc, function() { objStore.clear(); }); + assert_throws(exc, function() { objStore.count(); }); + assert_throws(exc, function() { objStore.delete(1); }); + assert_throws(exc, function() { objStore.openCursor(); }); + assert_throws(exc, function() { objStore.index("idx"); }); + assert_throws(exc, function() { objStore.deleteIndex("idx"); }); + assert_throws(exc, function() { objStore.createIndex("idx2", "a"); }); } open_rq.onsuccess = function() { diff --git a/testing/web-platform/tests/IndexedDB/idbobjectstore_getAll.html b/testing/web-platform/tests/IndexedDB/idbobjectstore_getAll.html index f81e4caf3d25..c9d29d3c3a42 100644 --- a/testing/web-platform/tests/IndexedDB/idbobjectstore_getAll.html +++ b/testing/web-platform/tests/IndexedDB/idbobjectstore_getAll.html @@ -2,25 +2,14 @@ IndexedDB: Test IDBObjectStore.getAll. + diff --git a/testing/web-platform/tests/IndexedDB/idbobjectstore_getAllKeys.html b/testing/web-platform/tests/IndexedDB/idbobjectstore_getAllKeys.html index f4d317d4328d..896d4df32e6a 100644 --- a/testing/web-platform/tests/IndexedDB/idbobjectstore_getAllKeys.html +++ b/testing/web-platform/tests/IndexedDB/idbobjectstore_getAllKeys.html @@ -2,25 +2,14 @@ IndexedDB: Test IDBObjectStore.getAllKeys. + diff --git a/testing/web-platform/tests/IndexedDB/idbobjectstore_getKey.html b/testing/web-platform/tests/IndexedDB/idbobjectstore_getKey.html index 19229456728b..ddb78b112132 100644 --- a/testing/web-platform/tests/IndexedDB/idbobjectstore_getKey.html +++ b/testing/web-platform/tests/IndexedDB/idbobjectstore_getKey.html @@ -4,17 +4,12 @@ + - - -
diff --git a/testing/web-platform/tests/IndexedDB/idbobjectstore_openKeyCursor.htm b/testing/web-platform/tests/IndexedDB/idbobjectstore_openKeyCursor.htm index 9dc547c3ff96..345845965fe0 100644 --- a/testing/web-platform/tests/IndexedDB/idbobjectstore_openKeyCursor.htm +++ b/testing/web-platform/tests/IndexedDB/idbobjectstore_openKeyCursor.htm @@ -2,26 +2,20 @@ IDBObjectStore.openKeyCursor() + + + + diff --git a/testing/web-platform/tests/IndexedDB/idbtransaction.htm b/testing/web-platform/tests/IndexedDB/idbtransaction.htm index 8a3484511e5d..5baa3db557d0 100644 --- a/testing/web-platform/tests/IndexedDB/idbtransaction.htm +++ b/testing/web-platform/tests/IndexedDB/idbtransaction.htm @@ -6,41 +6,54 @@ - -
diff --git a/testing/web-platform/tests/IndexedDB/idbtransaction_objectStoreNames.html b/testing/web-platform/tests/IndexedDB/idbtransaction_objectStoreNames.html index 7f6aa3518f02..da0b9aba36e0 100644 --- a/testing/web-platform/tests/IndexedDB/idbtransaction_objectStoreNames.html +++ b/testing/web-platform/tests/IndexedDB/idbtransaction_objectStoreNames.html @@ -73,7 +73,8 @@ indexeddb_test(function(t, db, tx) { assert_array_equals(saved_tx.objectStoreNames, ['s2', 's3'], 'previous transaction objectStoreNames should be unchanged'); assert_array_equals(db.objectStoreNames, saved_tx.objectStoreNames, - 'connection and transaction objectStoreNames should match'); + 'connection and transaction objectStoreNames should match'); + db2.close(); t.done(); }); }, 'IDBTransaction.objectStoreNames - value after close'); diff --git a/testing/web-platform/tests/IndexedDB/support.js b/testing/web-platform/tests/IndexedDB/support.js index cf3aa4d0ee23..7cab067fe20b 100644 --- a/testing/web-platform/tests/IndexedDB/support.js +++ b/testing/web-platform/tests/IndexedDB/support.js @@ -106,30 +106,34 @@ function assert_key_equals(actual, expected, description) { function indexeddb_test(upgrade_func, open_func, description, options) { async_test(function(t) { - var options = Object.assign({upgrade_will_abort: false}, options); + options = Object.assign({upgrade_will_abort: false}, options); var dbname = document.location + '-' + t.name; var del = indexedDB.deleteDatabase(dbname); del.onerror = t.unreached_func('deleteDatabase should succeed'); var open = indexedDB.open(dbname, 1); - if (!options.upgrade_will_abort) { - open.onsuccess = t.unreached_func('open should not succeed'); - } else { - open.onerror = t.unreached_func('open should succeed'); - } open.onupgradeneeded = t.step_func(function() { - var db = open.result; - var tx = open.transaction; - upgrade_func(t, db, tx); - }); - open.onsuccess = t.step_func(function() { var db = open.result; t.add_cleanup(function() { + // If open didn't succeed already, ignore the error. + open.onerror = function(e) { + e.preventDefault(); + }; db.close(); indexedDB.deleteDatabase(db.name); }); - if (open_func) - open_func(t, db); + var tx = open.transaction; + upgrade_func(t, db, tx); }); + if (options.upgrade_will_abort) { + open.onsuccess = t.unreached_func('open should not succeed'); + } else { + open.onerror = t.unreached_func('open should succeed'); + open.onsuccess = t.step_func(function() { + var db = open.result; + if (open_func) + open_func(t, db); + }); + } }, description); } diff --git a/testing/web-platform/tests/README.md b/testing/web-platform/tests/README.md index 94e26a2ab2f7..266d4ecc5967 100644 --- a/testing/web-platform/tests/README.md +++ b/testing/web-platform/tests/README.md @@ -40,13 +40,6 @@ following entries are required: If you are behind a proxy, you also need to make sure the domains above are excluded from your proxy lookups. -Because web-platform-tests uses git submodules, you must ensure that -these are up to date. In the root of your checkout, run: - -``` -git submodule update --init --recursive -``` - The test environment can then be started using ./serve @@ -77,6 +70,55 @@ like: "ssl": {"openssl": {"binary": "/path/to/openssl"}} ``` +Submodules +======================================= + +Some optional components of web-platform-tests (test components from +third party software and pieces of the CSS build system) are included +as submodules. To obtain these components run the following in the +root of your checkout: + +``` +git submodule update --init --recursive +``` + +Prior to commit `39d07eb01fab607ab1ffd092051cded1bdd64d78` submodules +were requried for basic functionality. If you are working with an +older checkout, the above command is required in all cases. + +When moving between a commit prior to `39d07eb` and one after it git +may complain + +``` +$ git checkout master +error: The following untracked working tree files would be overwritten by checkout: +[…] +``` + +followed by a long list of files. To avoid this error remove +the `resources` and `tools` directories before switching branches: + +``` +$ rm -r resources/ tools/ +$ git checkout master +Switched to branch 'master' +Your branch is up-to-date with 'origin/master' +``` + +When moving in the opposite direction, i.e. to a commit that does have +submodules, you will need to `git submodule update`, as above. If git +throws an error like: + +``` +fatal: No url found for submodule path 'resources/webidl2/test/widlproc' in .gitmodules +Failed to recurse into submodule path 'resources/webidl2' +fatal: No url found for submodule path 'tools/html5lib' in .gitmodules +Failed to recurse into submodule path 'resources' +Failed to recurse into submodule path 'tools' +``` + +then remove the `tools` and `resources` directories, as above. + Windows Notes ============================================= @@ -257,8 +299,8 @@ is [archived][ircarchive]. [contributing]: https://github.com/w3c/web-platform-tests/blob/master/CONTRIBUTING.md [ircw3org]: https://www.w3.org/wiki/IRC -[ircarchive]: http://krijnhoetmer.nl/irc-logs/testing/ -[mailarchive]: http://lists.w3.org/Archives/Public/public-test-infra/ +[ircarchive]: http://logs.glob.uno/?c=w3%23testing +[mailarchive]: https://lists.w3.org/Archives/Public/public-test-infra/ Documentation ============= diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/pbkdf2.js b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/pbkdf2.js index ced14d932430..74f8a6cbdb60 100644 --- a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/pbkdf2.js +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/pbkdf2.js @@ -1,5 +1,4 @@ - -function run_test() { +function run_test(testPasswordSize, testSaltSize) { // May want to test prefixed implementations. var subtle = self.crypto.subtle; @@ -28,7 +27,9 @@ function run_test() { // and number of iterations. The derivations object is structured in // that way, so navigate it to run tests and compare with correct results. Object.keys(derivations).forEach(function(passwordSize) { + if (typeof testPasswordSize != 'undefined' && testPasswordSize != passwordSize) return; Object.keys(derivations[passwordSize]).forEach(function(saltSize) { + if (typeof testSaltSize != 'undefined' && testSaltSize != saltSize) return; Object.keys(derivations[passwordSize][saltSize]).forEach(function(hashName) { Object.keys(derivations[passwordSize][saltSize][hashName]).forEach(function(iterations) { var testName = passwordSize + " password, " + saltSize + " salt, " + hashName + ", with " + iterations + " iterations"; diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html rename to testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html rename to testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_hkdf.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_hkdf.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_hkdf.html rename to testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_hkdf.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_empty.https.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_empty.https.html new file mode 100644 index 000000000000..15af4f38f6da --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_empty.https.html @@ -0,0 +1,22 @@ + + + +WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2 + + + + + + + + + +

deriveBits and deriveKey Tests for PBKDF2

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_long.https.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_long.https.html new file mode 100644 index 000000000000..c8a251dd3f27 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_long.https.html @@ -0,0 +1,22 @@ + + + +WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2 + + + + + + + + + +

deriveBits and deriveKey Tests for PBKDF2

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_short.https.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_short.https.html new file mode 100644 index 000000000000..62da41aab5b7 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_short.https.html @@ -0,0 +1,22 @@ + + + +WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2 + + + + + + + + + +

deriveBits and deriveKey Tests for PBKDF2

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_empty.https.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_empty.https.html new file mode 100644 index 000000000000..3b5845fcdfba --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_empty.https.html @@ -0,0 +1,22 @@ + + + +WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2 + + + + + + + + + +

deriveBits and deriveKey Tests for PBKDF2

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_long.https.html similarity index 91% rename from testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html rename to testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_long.https.html index 0658b1a2fd8e..d9d04433de16 100644 --- a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_long.https.html @@ -15,5 +15,8 @@
diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_short.https.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_short.https.html new file mode 100644 index 000000000000..fa81c7f3c1e4 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_long_short.https.html @@ -0,0 +1,22 @@ + + + +WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2 + + + + + + + + + +

deriveBits and deriveKey Tests for PBKDF2

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_empty.https.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_empty.https.html new file mode 100644 index 000000000000..2497b522c98a --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_empty.https.html @@ -0,0 +1,22 @@ + + + +WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2 + + + + + + + + + +

deriveBits and deriveKey Tests for PBKDF2

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_long.https.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_long.https.html new file mode 100644 index 000000000000..f56cd2c6ad05 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_long.https.html @@ -0,0 +1,22 @@ + + + +WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2 + + + + + + + + + +

deriveBits and deriveKey Tests for PBKDF2

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_short.https.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_short.https.html new file mode 100644 index 000000000000..c5fa4273b9d1 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_short.https.html @@ -0,0 +1,22 @@ + + + +WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2 + + + + + + + + + +

deriveBits and deriveKey Tests for PBKDF2

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/digest/test_digest.html b/testing/web-platform/tests/WebCryptoAPI/digest/test_digest.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/digest/test_digest.html rename to testing/web-platform/tests/WebCryptoAPI/digest/test_digest.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.html b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.html rename to testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_ctr.html b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_ctr.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_ctr.html rename to testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_ctr.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html rename to testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.html b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.html rename to testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes.js index db4aae085dea..6a74c01ddde4 100644 --- a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes.js +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes.js @@ -1,5 +1,5 @@ -function run_test(algorithmNames) { +function run_test(algorithmNames, slowTest) { var subtle = crypto.subtle; // Change to test prefixed implementations setup({explicit_timeout: true}); @@ -74,7 +74,7 @@ function run_test(algorithmNames) { // Test all valid sets of parameters for successful // key generation. testVectors.forEach(function(vector) { - allNameVariants(vector.name).forEach(function(name) { + allNameVariants(vector.name, slowTest).forEach(function(name) { allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { allValidUsages(vector.usages, false, vector.mandatoryUsages).forEach(function(usages) { [false, true].forEach(function(extractable) { diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-cbc.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-cbc.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-cbc.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-cbc.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-ctr.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-ctr.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-ctr.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-ctr.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CBC.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CBC.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CTR.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CTR.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CTR.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CTR.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-GCM.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-GCM.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-GCM.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-GCM.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-KW.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-KW.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-KW.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-KW.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDH.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDH.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDH.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDH.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDSA.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDSA.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDSA.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDSA.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_HMAC.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_HMAC.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_HMAC.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_HMAC.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-PSS.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-PSS.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-PSS.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-PSS.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CBC.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CBC.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CBC.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CBC.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CTR.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CTR.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CTR.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CTR.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-GCM.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-GCM.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-GCM.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-GCM.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-KW.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-KW.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-KW.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-KW.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDH.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDH.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDH.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDH.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDSA.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDSA.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDSA.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDSA.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_HMAC.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_HMAC.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_HMAC.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_HMAC.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html deleted file mode 100644 index db58fd6690ab..000000000000 --- a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html +++ /dev/null @@ -1,23 +0,0 @@ - - - -WebCryptoAPI: generateKey() Successful Calls - - - - - - - - -

generateKey Tests for Good Parameters

-

- Warning! RSA key generation is intrinsically - very slow, so the related tests can take up to - several minutes to complete, depending on browser! -

- -
- \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html similarity index 96% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html index 384db1cd1987..48136260390a 100644 --- a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes.html +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html @@ -19,5 +19,5 @@
diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-PSS.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-PSS.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html rename to testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/idlharness.https.html b/testing/web-platform/tests/WebCryptoAPI/idlharness.https.html new file mode 100644 index 000000000000..81e1e04f9c1e --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/idlharness.https.html @@ -0,0 +1,45 @@ + + + + +IDL check of WebCrypto + + + + + + + + + +

Description

+ +

This test verifies that the implementations of the WebCrypto API match with its WebIDL definition.

+ +
+ + diff --git a/testing/web-platform/tests/WebCryptoAPI/import_export/test_ec_importKey.html b/testing/web-platform/tests/WebCryptoAPI/import_export/test_ec_importKey.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/import_export/test_ec_importKey.html rename to testing/web-platform/tests/WebCryptoAPI/import_export/test_ec_importKey.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/import_export/test_rsa_importKey.html b/testing/web-platform/tests/WebCryptoAPI/import_export/test_rsa_importKey.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/import_export/test_rsa_importKey.html rename to testing/web-platform/tests/WebCryptoAPI/import_export/test_rsa_importKey.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/import_export/test_symmetric_importKey.html b/testing/web-platform/tests/WebCryptoAPI/import_export/test_symmetric_importKey.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/import_export/test_symmetric_importKey.html rename to testing/web-platform/tests/WebCryptoAPI/import_export/test_symmetric_importKey.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/secure_context/crypto-subtle-non-secure-context-not-available.sub.html b/testing/web-platform/tests/WebCryptoAPI/secure_context/crypto-subtle-non-secure-context-not-available.sub.html new file mode 100644 index 000000000000..79bcec7a4dae --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/secure_context/crypto-subtle-non-secure-context-not-available.sub.html @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/testing/web-platform/tests/WebCryptoAPI/secure_context/crypto-subtle-secure-context-available.https.sub.html b/testing/web-platform/tests/WebCryptoAPI/secure_context/crypto-subtle-secure-context-available.https.sub.html new file mode 100644 index 000000000000..67f7ff0b2b80 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/secure_context/crypto-subtle-secure-context-available.https.sub.html @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_ecdsa.html b/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_ecdsa.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/sign_verify/test_ecdsa.html rename to testing/web-platform/tests/WebCryptoAPI/sign_verify/test_ecdsa.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_hmac.html b/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_hmac.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/sign_verify/test_hmac.html rename to testing/web-platform/tests/WebCryptoAPI/sign_verify/test_hmac.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pkcs.html b/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pkcs.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pkcs.html rename to testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pkcs.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pss.html b/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pss.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pss.html rename to testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pss.https.html diff --git a/testing/web-platform/tests/WebCryptoAPI/util/helpers.js b/testing/web-platform/tests/WebCryptoAPI/util/helpers.js index fb723c3f7906..c13ce9146e2b 100644 --- a/testing/web-platform/tests/WebCryptoAPI/util/helpers.js +++ b/testing/web-platform/tests/WebCryptoAPI/util/helpers.js @@ -219,12 +219,13 @@ function allValidUsages(validUsages, emptyIsValid, mandatoryUsages) { // Algorithm name specifiers are case-insensitive. Generate several // case variations of a given name. -function allNameVariants(name) { +function allNameVariants(name, slowTest) { var upCaseName = name.toUpperCase(); var lowCaseName = name.toLowerCase(); var mixedCaseName = upCaseName.substring(0, 1) + lowCaseName.substring(1); + // for slow tests effectively cut the amount of work in third by only + // returning one variation + if (slowTest) return [mixedCaseName]; return [upCaseName, lowCaseName, mixedCaseName]; } - - diff --git a/testing/web-platform/tests/WebCryptoAPI/util/worker-report-crypto-subtle-presence.js b/testing/web-platform/tests/WebCryptoAPI/util/worker-report-crypto-subtle-presence.js new file mode 100644 index 000000000000..22cca7b6236f --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/util/worker-report-crypto-subtle-presence.js @@ -0,0 +1,3 @@ +subtle_crypto_found = true; +if (typeof crypto.subtle === 'undefined') subtle_crypto_found = false; +postMessage({ msg_type: 'subtle_crypto_found', msg_value: subtle_crypto_found }); diff --git a/testing/web-platform/tests/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.html b/testing/web-platform/tests/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.https.html similarity index 100% rename from testing/web-platform/tests/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.html rename to testing/web-platform/tests/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.https.html diff --git a/testing/web-platform/tests/WebIDL/ecmascript-binding/has-instance.html b/testing/web-platform/tests/WebIDL/ecmascript-binding/has-instance.html index 986d27c9b83a..caf0be472906 100644 --- a/testing/web-platform/tests/WebIDL/ecmascript-binding/has-instance.html +++ b/testing/web-platform/tests/WebIDL/ecmascript-binding/has-instance.html @@ -1,8 +1,11 @@ - +instanceof behavior + + + diff --git a/testing/web-platform/tests/WebIDL/ecmascript-binding/interface-prototype-object.html b/testing/web-platform/tests/WebIDL/ecmascript-binding/interface-prototype-object.html new file mode 100644 index 000000000000..590710dc8e70 --- /dev/null +++ b/testing/web-platform/tests/WebIDL/ecmascript-binding/interface-prototype-object.html @@ -0,0 +1,19 @@ + + +Interface prototype objects + + + + diff --git a/testing/web-platform/tests/WebIDL/ecmascript-binding/legacy-callback-interface-object.html b/testing/web-platform/tests/WebIDL/ecmascript-binding/legacy-callback-interface-object.html new file mode 100644 index 000000000000..01a008d108cd --- /dev/null +++ b/testing/web-platform/tests/WebIDL/ecmascript-binding/legacy-callback-interface-object.html @@ -0,0 +1,69 @@ + + +Legacy callback interface objects + + + + + + diff --git a/testing/web-platform/tests/XMLHttpRequest/formdata-foreach.html b/testing/web-platform/tests/XMLHttpRequest/formdata-foreach.html index 9b10367aece1..3ad184c4d557 100644 --- a/testing/web-platform/tests/XMLHttpRequest/formdata-foreach.html +++ b/testing/web-platform/tests/XMLHttpRequest/formdata-foreach.html @@ -14,8 +14,12 @@ fd.append('n2', 'v5'); fd.append('n3', 'v6'); fd.delete('n2'); - var expected_keys = ['n1', 'n3', 'n1', 'n3']; - var expected_values = ['v1', 'v3', 'v4', 'v6']; + + var file = new File(['hello'], "hello.txt"); + fd.append('f1', file); + + var expected_keys = ['n1', 'n3', 'n1', 'n3', 'f1']; + var expected_values = ['v1', 'v3', 'v4', 'v6', file]; test(function() { var mykeys = [], myvalues = []; for(var entry of fd) { diff --git a/testing/web-platform/tests/XMLHttpRequest/getresponseheader-chunked-trailer.htm b/testing/web-platform/tests/XMLHttpRequest/getresponseheader-chunked-trailer.htm index 3cbdb9c068cb..0659a3a05e25 100644 --- a/testing/web-platform/tests/XMLHttpRequest/getresponseheader-chunked-trailer.htm +++ b/testing/web-platform/tests/XMLHttpRequest/getresponseheader-chunked-trailer.htm @@ -18,7 +18,7 @@ assert_equals(client.getResponseHeader('Trailer'), 'X-Test-Me') assert_equals(client.getResponseHeader('X-Test-Me'), null) assert_equals(client.getAllResponseHeaders().indexOf('Trailer header value'), -1) - assert_regexp_match(client.getAllResponseHeaders(), /Trailer:\sX-Test-Me/) + assert_regexp_match(client.getAllResponseHeaders(), /trailer:\sX-Test-Me/) assert_equals(client.responseText, "First chunk\r\nSecond chunk\r\nYet another (third) chunk\r\nYet another (fourth) chunk\r\n") test.done() } diff --git a/testing/web-platform/tests/XMLHttpRequest/interfaces.html b/testing/web-platform/tests/XMLHttpRequest/interfaces.html index 96de3c00f949..56ba5523e318 100644 --- a/testing/web-platform/tests/XMLHttpRequest/interfaces.html +++ b/testing/web-platform/tests/XMLHttpRequest/interfaces.html @@ -9,46 +9,6 @@

XMLHttpRequest IDL tests

- diff --git a/testing/web-platform/tests/accelerometer/Accelerometer.https.html b/testing/web-platform/tests/accelerometer/Accelerometer.https.html new file mode 100644 index 000000000000..6421ab568d98 --- /dev/null +++ b/testing/web-platform/tests/accelerometer/Accelerometer.https.html @@ -0,0 +1,16 @@ + + +Accelerometer Test + + + + + +
+ + diff --git a/testing/web-platform/tests/accelerometer/Accelerometer_insecure_context.html b/testing/web-platform/tests/accelerometer/Accelerometer_insecure_context.html new file mode 100644 index 000000000000..4ff4789c37e8 --- /dev/null +++ b/testing/web-platform/tests/accelerometer/Accelerometer_insecure_context.html @@ -0,0 +1,20 @@ + + +Accelerometer Test: insecure context + + + + + +
+

Precondition

+
    +
  1. + Run test in an insecure context, e.g. http://example.com/. +
  2. +
+ diff --git a/testing/web-platform/tests/accelerometer/Accelerometer_onerror-manual.https.html b/testing/web-platform/tests/accelerometer/Accelerometer_onerror-manual.https.html new file mode 100644 index 000000000000..a3e815001222 --- /dev/null +++ b/testing/web-platform/tests/accelerometer/Accelerometer_onerror-manual.https.html @@ -0,0 +1,20 @@ + + +Accelerometer Test: onerror + + + + + +
+

Precondition

+
    +
  1. + Disable the Accelerometer Sensor or run test on a device without Accelerometer Sensor. +
  2. +
+ diff --git a/testing/web-platform/tests/accelerometer/idlharness.https.html b/testing/web-platform/tests/accelerometer/idlharness.https.html index 79cd5c925d74..66e228cda155 100644 --- a/testing/web-platform/tests/accelerometer/idlharness.https.html +++ b/testing/web-platform/tests/accelerometer/idlharness.https.html @@ -2,7 +2,8 @@ Accelerometer Sensor IDL tests - + + @@ -18,24 +19,24 @@ interface Event { }; -interface EventTarget { -}; - -interface EventHandler { -}; - interface Error { }; dictionary EventInit { }; + +interface EventTarget { +}; + +interface EventHandler { +};
 [SecureContext]
 interface Sensor : EventTarget {
-  readonly attribute SensorState state;
-  readonly attribute SensorReading? reading;
+  readonly attribute boolean activated;
+  readonly attribute DOMHighResTimeStamp? timestamp;
   void start();
   void stop();
   attribute EventHandler onchange;
@@ -47,18 +48,6 @@ dictionary SensorOptions {
   double? frequency;
 };
 
-enum SensorState {
-  "idle",
-  "activating",
-  "activated",
-  "errored"
-};
-
-[SecureContext]
-interface SensorReading {
-  readonly attribute DOMHighResTimeStamp timeStamp;
-};
-
 [SecureContext, Constructor(DOMString type, SensorErrorEventInit errorEventInitDict)]
 interface SensorErrorEvent : Event {
   readonly attribute Error error;
@@ -67,47 +56,41 @@ interface SensorErrorEvent : Event {
 dictionary SensorErrorEventInit : EventInit {
   required Error error;
 };
-
 
-[Constructor(optional AccelerometerOptions accelerometerOptions)]
+[Constructor(optional SensorOptions options)]
 interface Accelerometer : Sensor {
-  readonly attribute AccelerometerReading? reading;
-  readonly attribute boolean includesGravity;
+  readonly attribute unrestricted double? x;
+  readonly attribute unrestricted double? y;
+  readonly attribute unrestricted double? z;
 };
 
-dictionary AccelerometerOptions :  SensorOptions  {
-  boolean includeGravity = true;
+[Constructor(optional SensorOptions options)]
+interface LinearAccelerationSensor : Accelerometer {
 };
 
-[Constructor(AccelerometerReadingInit AccelerometerReadingInit)]
-interface AccelerometerReading : SensorReading {
-    readonly attribute double x;
-    readonly attribute double y;
-    readonly attribute double z;
-};
-
-dictionary AccelerometerReadingInit {
-    double x = 0;
-    double y = 0;
-    double z = 0;
+[Constructor(optional SensorOptions options)]
+interface GravitySensor : Accelerometer {
 };
 
diff --git a/testing/web-platform/tests/accelerometer/support-iframe.html b/testing/web-platform/tests/accelerometer/support-iframe.html new file mode 100644 index 000000000000..a123f486bea3 --- /dev/null +++ b/testing/web-platform/tests/accelerometer/support-iframe.html @@ -0,0 +1,10 @@ + + + diff --git a/testing/web-platform/tests/ambient-light/AmbientLightSensor.https.html b/testing/web-platform/tests/ambient-light/AmbientLightSensor.https.html new file mode 100644 index 000000000000..5e2310d0d853 --- /dev/null +++ b/testing/web-platform/tests/ambient-light/AmbientLightSensor.https.html @@ -0,0 +1,16 @@ + + +AmbientLightSensor Test + + + + + +
+ + diff --git a/testing/web-platform/tests/ambient-light/AmbientLightSensor.js b/testing/web-platform/tests/ambient-light/AmbientLightSensor.js deleted file mode 100644 index 5a1f8ea2ff59..000000000000 --- a/testing/web-platform/tests/ambient-light/AmbientLightSensor.js +++ /dev/null @@ -1,5 +0,0 @@ -(function() { - test(function() { - assert_true(false); - }, 'Test suite not implemented yet.'); -})(); diff --git a/testing/web-platform/tests/ambient-light/AmbientLightSensor_browsing_context.https.html b/testing/web-platform/tests/ambient-light/AmbientLightSensor_browsing_context.https.html deleted file mode 100644 index 1b045bd9eeaf..000000000000 --- a/testing/web-platform/tests/ambient-light/AmbientLightSensor_browsing_context.https.html +++ /dev/null @@ -1,33 +0,0 @@ - - -AmbientLightSensor Test: Sensor readings must only be available in the top-level browsing context - - - - -
- - diff --git a/testing/web-platform/tests/ambient-light/AmbientLightSensor_insecure_context.html b/testing/web-platform/tests/ambient-light/AmbientLightSensor_insecure_context.html index 76662e07eb7c..de900e048943 100644 --- a/testing/web-platform/tests/ambient-light/AmbientLightSensor_insecure_context.html +++ b/testing/web-platform/tests/ambient-light/AmbientLightSensor_insecure_context.html @@ -5,19 +5,16 @@ + +

Precondition

  1. Run test in an insecure context, e.g. http://example.com/.
-
diff --git a/testing/web-platform/tests/ambient-light/AmbientLightSensor_onchange.https.html b/testing/web-platform/tests/ambient-light/AmbientLightSensor_onchange.https.html deleted file mode 100644 index 737bb755234b..000000000000 --- a/testing/web-platform/tests/ambient-light/AmbientLightSensor_onchange.https.html +++ /dev/null @@ -1,26 +0,0 @@ - - -AmbientLightSensor Test: onchange - - - - -
- diff --git a/testing/web-platform/tests/ambient-light/AmbientLightSensor_onerror-manual.https.html b/testing/web-platform/tests/ambient-light/AmbientLightSensor_onerror-manual.https.html index d7811cfa6676..8bcb9082cc9d 100644 --- a/testing/web-platform/tests/ambient-light/AmbientLightSensor_onerror-manual.https.html +++ b/testing/web-platform/tests/ambient-light/AmbientLightSensor_onerror-manual.https.html @@ -5,28 +5,16 @@ + +

Precondition

  1. Disable the Ambient Light Sensor or run test on a device without Amibent Light Sensor.
-
diff --git a/testing/web-platform/tests/ambient-light/AmbientLightSensor_reading.https.html b/testing/web-platform/tests/ambient-light/AmbientLightSensor_reading.https.html deleted file mode 100644 index 34eab24f9b1b..000000000000 --- a/testing/web-platform/tests/ambient-light/AmbientLightSensor_reading.https.html +++ /dev/null @@ -1,64 +0,0 @@ - - -AmbientLightSensor Test: reading - - - - -
- diff --git a/testing/web-platform/tests/ambient-light/AmbientLightSensor_start.https.html b/testing/web-platform/tests/ambient-light/AmbientLightSensor_start.https.html deleted file mode 100644 index e08a2490ff0b..000000000000 --- a/testing/web-platform/tests/ambient-light/AmbientLightSensor_start.https.html +++ /dev/null @@ -1,43 +0,0 @@ - - -AmbientLightSensor Test: start() - - - - -
- diff --git a/testing/web-platform/tests/ambient-light/AmbientLightSensor_stop.https.html b/testing/web-platform/tests/ambient-light/AmbientLightSensor_stop.https.html deleted file mode 100644 index 8f504c5fe817..000000000000 --- a/testing/web-platform/tests/ambient-light/AmbientLightSensor_stop.https.html +++ /dev/null @@ -1,35 +0,0 @@ - - -AmbientLightSensor Test: stop() - - - - -
- diff --git a/testing/web-platform/tests/ambient-light/AmbientLightSensor_tests.html b/testing/web-platform/tests/ambient-light/AmbientLightSensor_tests.html deleted file mode 100644 index 2008597152b5..000000000000 --- a/testing/web-platform/tests/ambient-light/AmbientLightSensor_tests.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - -Ambient Light Sensor Test Suite - - - - -
- diff --git a/testing/web-platform/tests/ambient-light/idlharness.https.html b/testing/web-platform/tests/ambient-light/idlharness.https.html index 307d53c82d3a..2ccc23f598d4 100644 --- a/testing/web-platform/tests/ambient-light/idlharness.https.html +++ b/testing/web-platform/tests/ambient-light/idlharness.https.html @@ -2,7 +2,8 @@ Ambient Light Sensor IDL tests - + + @@ -18,24 +19,24 @@ interface Event { }; -interface EventTarget { -}; - -interface EventHandler { -}; - interface Error { }; dictionary EventInit { }; + +interface EventTarget { +}; + +interface EventHandler { +};
 [SecureContext]
 interface Sensor : EventTarget {
-  readonly attribute SensorState state;
-  readonly attribute SensorReading? reading;
+  readonly attribute boolean activated;
+  readonly attribute DOMHighResTimeStamp? timestamp;
   void start();
   void stop();
   attribute EventHandler onchange;
@@ -47,18 +48,6 @@ dictionary SensorOptions {
   double? frequency;
 };
 
-enum SensorState {
-  "idle",
-  "activating",
-  "activated",
-  "errored"
-};
-
-[SecureContext]
-interface SensorReading {
-  readonly attribute DOMHighResTimeStamp timeStamp;
-};
-
 [SecureContext, Constructor(DOMString type, SensorErrorEventInit errorEventInitDict)]
 interface SensorErrorEvent : Event {
   readonly attribute Error error;
@@ -67,38 +56,29 @@ interface SensorErrorEvent : Event {
 dictionary SensorErrorEventInit : EventInit {
   required Error error;
 };
-
 
 [Constructor(optional SensorOptions sensorOptions)]
 interface AmbientLightSensor : Sensor {
-};
-
-[Constructor(AmbientLightSensorReadingInit ambientLightSensorReadingInit)]
-interface AmbientLightSensorReading : SensorReading {
-    readonly attribute unrestricted double illuminance;
-};
-
-dictionary AmbientLightSensorReadingInit {
-  required unrestricted double illuminance;
+  readonly attribute unrestricted double? illuminance;
 };
 
+ diff --git a/testing/web-platform/tests/ambient-light/support-iframe.html b/testing/web-platform/tests/ambient-light/support-iframe.html index 5041a6861a4e..17ff8e7aca2a 100644 --- a/testing/web-platform/tests/ambient-light/support-iframe.html +++ b/testing/web-platform/tests/ambient-light/support-iframe.html @@ -3,8 +3,8 @@ diff --git a/testing/web-platform/tests/apng/animated-png-timeout-ref.html b/testing/web-platform/tests/apng/animated-png-timeout-ref.html new file mode 100644 index 000000000000..c46bb9016499 --- /dev/null +++ b/testing/web-platform/tests/apng/animated-png-timeout-ref.html @@ -0,0 +1 @@ + diff --git a/testing/web-platform/tests/apng/animated-png-timeout.html b/testing/web-platform/tests/apng/animated-png-timeout.html new file mode 100644 index 000000000000..6975bd9c4e73 --- /dev/null +++ b/testing/web-platform/tests/apng/animated-png-timeout.html @@ -0,0 +1,11 @@ + +APNG: Second frame displays quickly, replacing red with green. + + + diff --git a/testing/web-platform/tests/bluetooth/OWNERS b/testing/web-platform/tests/bluetooth/OWNERS new file mode 100644 index 000000000000..9a9c462090d9 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/OWNERS @@ -0,0 +1,3 @@ +@jyasskin +@g-ortuno +@scheib diff --git a/testing/web-platform/tests/bluetooth/idl-Bluetooth.html b/testing/web-platform/tests/bluetooth/idl-Bluetooth.html index 129a10cd70be..b0263f980a8e 100644 --- a/testing/web-platform/tests/bluetooth/idl-Bluetooth.html +++ b/testing/web-platform/tests/bluetooth/idl-Bluetooth.html @@ -6,9 +6,9 @@ 'use strict'; test(() => { - assert_throws(null, () => new Bluetooth(), + assert_throws(new TypeError(), () => new Bluetooth(), 'the constructor should not be callable with "new"'); - assert_throws(null, () => Bluetooth(), + assert_throws(new TypeError(), () => Bluetooth(), 'the constructor should not be callable'); // Bluetooth implements BluetoothDiscovery; diff --git a/testing/web-platform/tests/check_stability.ini b/testing/web-platform/tests/check_stability.ini new file mode 100644 index 000000000000..cf18896a0b66 --- /dev/null +++ b/testing/web-platform/tests/check_stability.ini @@ -0,0 +1,9 @@ +[file detection] +skip_tests: conformance-checkers docs tools +# The vast majority of tests rely on files located within the `resources` +# directory. Because of this, modifications to that directory's contents have +# the potential to introduce instability in a large number of tests. +# Exhaustively validating such changes is highly resource intensive +# (particularly in terms of execution time), making it impractical in most +# cases. +ignore_changes: resources diff --git a/testing/web-platform/tests/check_stability.py b/testing/web-platform/tests/check_stability.py index 6dcee782a803..08d75e7b9bc5 100644 --- a/testing/web-platform/tests/check_stability.py +++ b/testing/web-platform/tests/check_stability.py @@ -9,10 +9,11 @@ import subprocess import sys import tarfile import zipfile +from ConfigParser import RawConfigParser, SafeConfigParser from abc import ABCMeta, abstractmethod from cStringIO import StringIO as CStringIO from collections import defaultdict, OrderedDict -from ConfigParser import RawConfigParser +from distutils.spawn import find_executable from io import BytesIO, StringIO import requests @@ -171,6 +172,12 @@ class Browser(object): def wptrunner_args(self): return NotImplemented + def prepare_environment(self): + """Do any additional setup of the environment required to start the + browser successfully + """ + pass + class Firefox(Browser): """Firefox-specific interface. @@ -282,6 +289,26 @@ class Chrome(Browser): "test_types": ["testharness", "reftest"] } + def prepare_environment(self): + # https://bugs.chromium.org/p/chromium/issues/detail?id=713947 + logger.debug("DBUS_SESSION_BUS_ADDRESS %s" % os.environ.get("DBUS_SESSION_BUS_ADDRESS")) + if "DBUS_SESSION_BUS_ADDRESS" not in os.environ: + if find_executable("dbus-launch"): + logger.debug("Attempting to start dbus") + dbus_conf = subprocess.check_output(["dbus-launch"]) + logger.debug(dbus_conf) + + # From dbus-launch(1): + # + # > When dbus-launch prints bus information to standard output, + # > by default it is in a simple key-value pairs format. + for line in dbus_conf.strip().split("\n"): + key, _, value = line.partition("=") + os.environ[key] = value + else: + logger.critical("dbus not running and can't be started") + sys.exit(1) + def get(url): """Issue GET request to a given URL and return the response.""" @@ -383,10 +410,7 @@ def build_manifest(): def install_wptrunner(): - """Clone and install wptrunner.""" - call("git", "clone", "--depth=1", "https://github.com/w3c/wptrunner.git", wptrunner_root) - git = get_git_cmd(wptrunner_root) - git("submodule", "update", "--init", "--recursive") + """Install wptrunner.""" call("pip", "install", wptrunner_root) @@ -394,27 +418,42 @@ def get_branch_point(user): git = get_git_cmd(wpt_root) if os.environ.get("TRAVIS_PULL_REQUEST", "false") != "false": # This is a PR, so the base branch is in TRAVIS_BRANCH - branch_point = os.environ.get("TRAVIS_COMMIT_RANGE").split(".", 1)[0] - branch_point = git("rev-parse", branch_point) + travis_branch = os.environ.get("TRAVIS_BRANCH") + assert travis_branch, "TRAVIS_BRANCH environment variable is defined" + branch_point = git("rev-parse", travis_branch) else: # Otherwise we aren't on a PR, so we try to find commits that are only in the # current branch c.f. # http://stackoverflow.com/questions/13460152/find-first-ancestor-commit-in-another-branch head = git("rev-parse", "HEAD") # To do this we need all the commits in the local copy - fetch_wpt(user, "--unshallow", "+refs/heads/*:refs/remotes/origin/*") + fetch_args = [user, "+refs/heads/*:refs/remotes/origin/*"] + if os.path.exists(os.path.join(wpt_root, ".git", "shallow")): + fetch_args.insert(1, "--unshallow") + fetch_wpt(*fetch_args) not_heads = [item for item in git("rev-parse", "--not", "--all").split("\n") - if not head in item] + if item.strip() and not head in item] commits = git("rev-list", "HEAD", *not_heads).split("\n") - first_commit = commits[-1] - branch_point = git("rev-parse", first_commit + "^") - # The above can produce a too-early commit if we are e.g. on master and there are - # preceding changes that were rebased and so aren't on any other branch. To avoid - # this issue we check for the later of the above branch point and the merge-base - # with master + branch_point = None + if len(commits): + first_commit = commits[-1] + if first_commit: + branch_point = git("rev-parse", first_commit + "^") + + # The above heuristic will fail in the following cases: + # + # - The current branch has fallen behind the version retrieved via the above + # `fetch` invocation + # - Changes on the current branch were rebased and therefore do not exist on any + # other branch. This will result in the selection of a commit that is earlier + # in the history than desired (as determined by calculating the later of the + # branch point and the merge base) + # + # In either case, fall back to using the merge base as the branch point. merge_base = git("merge-base", "HEAD", "origin/master") - if (branch_point != merge_base and - not git("log", "--oneline", "%s..%s" % (merge_base, branch_point)).strip()): + if (branch_point is None or + (branch_point != merge_base and + not git("log", "--oneline", "%s..%s" % (merge_base, branch_point)).strip())): logger.debug("Using merge-base as the branch point") branch_point = merge_base else: @@ -424,24 +463,34 @@ def get_branch_point(user): return branch_point -def get_files_changed(branch_point): - """Get and return files changed since current branch diverged from master.""" +def get_files_changed(branch_point, ignore_changes): + """Get and return files changed since current branch diverged from master, + excluding those that are located within any directory specifed by + `ignore_changes`.""" root = os.path.abspath(os.curdir) git = get_git_cmd(wpt_root) - files = git("diff", "--name-only", "-z", "%s.." % branch_point) + files = git("diff", "--name-only", "-z", "%s..." % branch_point) if not files: - return [] + return [], [] assert files[-1] == "\0" - return [os.path.join(wpt_root, item) - for item in files[:-1].split("\0")] + changed = [] + ignored = [] + for item in files[:-1].split("\0"): + fullpath = os.path.join(wpt_root, item) + topmost_dir = item.split(os.sep, 1)[0] + if topmost_dir in ignore_changes: + ignored.append(fullpath) + else: + changed.append(fullpath) -def get_affected_testfiles(files_changed): + return changed, ignored + +def get_affected_testfiles(files_changed, skip_tests): """Determine and return list of test files that reference changed files.""" affected_testfiles = set() nontests_changed = set(files_changed) manifest_file = os.path.join(wpt_root, "MANIFEST.json") - skip_dirs = ["conformance-checkers", "docs", "tools"] test_types = ["testharness", "reftest", "wdspec"] wpt_manifest = manifest.load(wpt_root, manifest_file) @@ -462,7 +511,7 @@ def get_affected_testfiles(files_changed): # (because it's not part of any test). continue top_level_subdir = path_components[0] - if top_level_subdir in skip_dirs: + if top_level_subdir in skip_tests: continue repo_path = "/" + os.path.relpath(full_path, wpt_root).replace(os.path.sep, "/") nontest_changed_paths.add((full_path, repo_path)) @@ -471,7 +520,7 @@ def get_affected_testfiles(files_changed): # Walk top_level_subdir looking for test files containing either the # relative filepath or absolute filepatch to the changed files. if root == wpt_root: - for dir_name in skip_dirs: + for dir_name in skip_tests: dirs.remove(dir_name) for fname in fnames: test_full_path = os.path.join(root, fname) @@ -617,6 +666,7 @@ def markdown_adjust(s): s = s.replace('\n', u'\\n') s = s.replace('\r', u'\\r') s = s.replace('`', u'') + s = s.replace('|', u'\\|') return s @@ -691,7 +741,9 @@ def write_results(results, iterations, comment_pr): def get_parser(): """Create and return script-specific argument parser.""" - parser = argparse.ArgumentParser() + description = """Detect instabilities in new tests by executing tests + repeatedly and comparing results between executions.""" + parser = argparse.ArgumentParser(description=description) parser.add_argument("--root", action="store", default=os.path.join(os.path.expanduser("~"), "build"), @@ -709,12 +761,17 @@ def get_parser(): action="store", # Travis docs say do not depend on USER env variable. # This is a workaround to get what should be the same value - default=os.environ.get("TRAVIS_REPO_SLUG").split('/')[0], + default=os.environ.get("TRAVIS_REPO_SLUG", "w3c").split('/')[0], help="Travis user name") parser.add_argument("--output-bytes", action="store", type=int, help="Maximum number of bytes to write to standard output/error") + parser.add_argument("--config-file", + action="store", + type=str, + help="Location of ini-formatted configuration file", + default="check_stability.ini") parser.add_argument("product", action="store", help="Product to run against (`browser-name` or 'browser-name:channel')") @@ -731,6 +788,12 @@ def main(): parser = get_parser() args = parser.parse_args() + with open(args.config_file, 'r') as config_fp: + config = SafeConfigParser() + config.readfp(config_fp) + skip_tests = config.get("file detection", "skip_tests").split() + ignore_changes = set(config.get("file detection", "ignore_changes").split()) + if args.output_bytes is not None: replace_streams(args.output_bytes, "Log reached capacity (%s bytes); output disabled." % args.output_bytes) @@ -739,7 +802,7 @@ def main(): setup_logging() wpt_root = os.path.abspath(os.curdir) - wptrunner_root = os.path.normpath(os.path.join(wpt_root, "..", "wptrunner")) + wptrunner_root = os.path.normpath(os.path.join(wpt_root, "tools", "wptrunner")) if not os.path.exists(args.root): logger.critical("Root directory %s does not exist" % args.root) @@ -767,7 +830,11 @@ def main(): # For now just pass the whole list of changed files to wptrunner and # assume that it will run everything that's actually a test - files_changed = get_files_changed(branch_point) + files_changed, files_ignored = get_files_changed(branch_point, ignore_changes) + + if files_ignored: + logger.info("Ignoring %s changed files:\n%s" % (len(files_ignored), + "".join(" * %s\n" % item for item in files_ignored))) if not files_changed: logger.info("No files changed") @@ -789,7 +856,7 @@ def main(): logger.debug("Files changed:\n%s" % "".join(" * %s\n" % item for item in files_changed)) - affected_testfiles = get_affected_testfiles(files_changed) + affected_testfiles = get_affected_testfiles(files_changed, skip_tests) logger.debug("Affected tests:\n%s" % "".join(" * %s\n" % item for item in affected_testfiles)) @@ -800,6 +867,8 @@ def main(): args.iterations, browser) + browser.prepare_environment() + with TravisFold("running_tests"): logger.info("Starting %i test iterations" % args.iterations) with open("raw.log", "wb") as log: @@ -840,6 +909,8 @@ if __name__ == "__main__": try: retcode = main() except: - raise + import traceback + traceback.print_exc() + sys.exit(1) else: sys.exit(retcode) diff --git a/testing/web-platform/tests/ci_unittest.sh b/testing/web-platform/tests/ci_unittest.sh new file mode 100755 index 000000000000..410b883def72 --- /dev/null +++ b/testing/web-platform/tests/ci_unittest.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +ROOT=$PWD +pip install -U tox codecov +cd tools +tox + +if [ $TOXENV == "py27" ] || [ $TOXENV == "pypy" ]; then + cd wptrunner + tox +fi + +cd $ROOT + +coverage combine tools tools/wptrunner +codecov diff --git a/testing/web-platform/tests/clipboard/OWNERS b/testing/web-platform/tests/clipboard/OWNERS index 01c0055fd913..6332787efaff 100644 --- a/testing/web-platform/tests/clipboard/OWNERS +++ b/testing/web-platform/tests/clipboard/OWNERS @@ -1 +1,2 @@ +@garykac @hallvors diff --git a/testing/web-platform/tests/common/PrefixedPostMessage.js b/testing/web-platform/tests/common/PrefixedPostMessage.js new file mode 100644 index 000000000000..674b52877c0d --- /dev/null +++ b/testing/web-platform/tests/common/PrefixedPostMessage.js @@ -0,0 +1,100 @@ +/** + * Supports pseudo-"namespacing" for window-posted messages for a given test + * by generating and using a unique prefix that gets wrapped into message + * objects. This makes it more feasible to have multiple tests that use + * `window.postMessage` in a single test file. Basically, make it possible + * for the each test to listen for only the messages that are pertinent to it. + * + * 'Prefix' not an elegant term to use here but this models itself after + * PrefixedLocalStorage. + * + * PrefixedMessageTest: Instantiate in testharness.js tests to generate + * a new unique-ish prefix that can be used by other test support files + * PrefixedMessageResource: Instantiate in supporting test resource + * files to use/share a prefix generated by a test. + */ +var PrefixedMessage = function () { + this.prefix = ''; + this.param = 'prefixedMessage'; // Param to use in querystrings +}; + +/** + * Generate a URL that adds/replaces param with this object's prefix + * Use to link to test support files that make use of + * PrefixedMessageResource. + */ +PrefixedMessage.prototype.url = function (uri) { + function updateUrlParameter (uri, key, value) { + var i = uri.indexOf('#'); + var hash = (i === -1) ? '' : uri.substr(i); + uri = (i === -1) ? uri : uri.substr(0, i); + var re = new RegExp(`([?&])${key}=.*?(&|$)`, 'i'); + var separator = uri.indexOf('?') !== -1 ? '&' : '?'; + uri = (uri.match(re)) ? uri.replace(re, `$1${key}=${value}$2`) : + `${uri}${separator}${key}=${value}`; + return uri + hash; + } + return updateUrlParameter(uri, this.param, this.prefix); +}; + +/** + * Add an eventListener on `message` but only invoke the given callback + * for messages whose object contains this object's prefix. Remove the + * event listener once the anticipated message has been received. + */ +PrefixedMessage.prototype.onMessage = function (fn) { + window.addEventListener('message', e => { + if (typeof e.data === 'object' && e.data.hasOwnProperty('prefix')) { + if (e.data.prefix === this.prefix) { + // Only invoke callback when `data` is an object containing + // a `prefix` key with this object's prefix value + // Note fn is invoked with "unwrapped" data first, then the event `e` + // (which contains the full, wrapped e.data should it be needed) + fn.call(this, e.data.data, e); + window.removeEventListener('message', fn); + } + } + }); +}; + +/** + * Instantiate in a test file (e.g. during `setup`) to create a unique-ish + * prefix that can be shared by support files + */ +var PrefixedMessageTest = function () { + PrefixedMessage.call(this); + this.prefix = `${document.location.pathname}-${Math.random()}-${Date.now()}-`; +}; +PrefixedMessageTest.prototype = Object.create(PrefixedMessage.prototype); +PrefixedMessageTest.prototype.constructor = PrefixedMessageTest; + +/** + * Instantiate in a test support script to use a "prefix" generated by a + * PrefixedMessageTest in a controlling test file. It will look for + * the prefix in a URL param (see also PrefixedMessage#url) + */ +var PrefixedMessageResource = function () { + PrefixedMessage.call(this); + // Check URL querystring for prefix to use + var regex = new RegExp(`[?&]${this.param}(=([^&#]*)|&|#|$)`), + results = regex.exec(document.location.href); + if (results && results[2]) { + this.prefix = results[2]; + } +}; +PrefixedMessageResource.prototype = Object.create(PrefixedMessage.prototype); +PrefixedMessageResource.prototype.constructor = PrefixedMessageResource; + +/** + * This is how a test resource document can "send info" to its + * opener context. It will whatever message is being sent (`data`) in + * an object that injects the prefix. + */ +PrefixedMessageResource.prototype.postToOpener = function (data) { + if (window.opener) { + window.opener.postMessage({ + prefix: this.prefix, + data: data + }, '*'); + } +}; diff --git a/testing/web-platform/tests/common/object-association.js b/testing/web-platform/tests/common/object-association.js new file mode 100644 index 000000000000..cd1453e4739f --- /dev/null +++ b/testing/web-platform/tests/common/object-association.js @@ -0,0 +1,64 @@ +"use strict"; + +// For now this only has per-Window tests, but we could expand it to also test per-Document + +window.testIsPerWindow = propertyName => { + test(t => { + const iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + const frame = iframe.contentWindow; + + const before = frame[propertyName]; + assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`); + + iframe.remove(); + + const after = frame[propertyName]; + assert_equals(after, before); + }, `Discarding the browsing context must not change window.${propertyName}`); + + async_test(t => { + const iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + const frame = iframe.contentWindow; + + const before = frame[propertyName]; + assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`); + + // Note: cannot use step_func_done for this because it might be called twice, per the below comment. + iframe.onload = t.step_func(() => { + if (frame.location.href === "about:blank") { + // Browsers are not reliable on whether about:blank fires the load event; see + // https://github.com/whatwg/html/issues/490 + return; + } + + const after = frame[propertyName]; + assert_equals(after, before); + t.done(); + }); + + iframe.src = "/common/blank.html"; + }, `Navigating from the initial about:blank must not replace window.${propertyName}`); + + // Note: document.open()'s spec doesn't match most browsers; see https://github.com/whatwg/html/issues/1698. + // However, as explained in https://github.com/whatwg/html/issues/1698#issuecomment-298748641, even an updated spec + // will probably still reset Window-associated properties. + async_test(t => { + const iframe = document.createElement("iframe"); + + iframe.onload = t.step_func_done(() => { + const frame = iframe.contentWindow; + const before = frame[propertyName]; + assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`); + + frame.document.open(); + + const after = frame[propertyName]; + assert_not_equals(after, before); + }); + + iframe.src = "/common/blank.html"; + document.body.appendChild(iframe); + }, `document.open() must replace window.${propertyName}`); +}; diff --git a/testing/web-platform/tests/common/performance-timeline-utils.js b/testing/web-platform/tests/common/performance-timeline-utils.js new file mode 100644 index 000000000000..268bb114722b --- /dev/null +++ b/testing/web-platform/tests/common/performance-timeline-utils.js @@ -0,0 +1,40 @@ +var performanceNamespace = window.performance; +var namespace_check = false; +function wp_test(func, msg, properties) +{ + // only run the namespace check once + if (!namespace_check) + { + namespace_check = true; + + if (performanceNamespace === undefined || performanceNamespace == null) + { + // show a single error that window.performance is undefined + test(function() { assert_true(performanceNamespace !== undefined && performanceNamespace != null, "window.performance is defined and not null"); }, "window.performance is defined and not null.", {author:"W3C http://www.w3.org/",help:"http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",assert:"The window.performance attribute provides a hosting area for performance related attributes. "}); + } + } + + test(func, msg, properties); +} + +function test_true(value, msg, properties) +{ + wp_test(function () { assert_true(value, msg); }, msg, properties); +} + +function test_equals(value, equals, msg, properties) +{ + wp_test(function () { assert_equals(value, equals, msg); }, msg, properties); +} + +// assert for every entry in `expectedEntries`, there is a matching entry _somewhere_ in `actualEntries` +function test_entries(actualEntries, expectedEntries) { + test_equals(actualEntries.length, expectedEntries.length) + expectedEntries.forEach(function (expectedEntry) { + test_true(!!actualEntries.find(function (actualEntry) { + return typeof Object.keys(expectedEntry).find(function (key) { + return actualEntry[key] !== expectedEntry[key] + }) === 'undefined' + })) + }) +} diff --git a/testing/web-platform/tests/content-security-policy/child-src/child-src-allowed.sub.html b/testing/web-platform/tests/content-security-policy/child-src/child-src-allowed.sub.html index 12a075adb653..6fee98883da0 100644 --- a/testing/web-platform/tests/content-security-policy/child-src/child-src-allowed.sub.html +++ b/testing/web-platform/tests/content-security-policy/child-src/child-src-allowed.sub.html @@ -55,7 +55,7 @@ Content-Security-Policy: child-src 'self'; script-src 'self' 'unsafe-inline'; co - +
diff --git a/testing/web-platform/tests/content-security-policy/child-src/child-src-blocked.sub.html b/testing/web-platform/tests/content-security-policy/child-src/child-src-blocked.sub.html index e32cc0af05eb..3d14da43e00d 100644 --- a/testing/web-platform/tests/content-security-policy/child-src/child-src-blocked.sub.html +++ b/testing/web-platform/tests/content-security-policy/child-src/child-src-blocked.sub.html @@ -53,9 +53,9 @@ child-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self'; - +
- + diff --git a/testing/web-platform/tests/content-security-policy/child-src/child-src-conflicting-frame-src.sub.html b/testing/web-platform/tests/content-security-policy/child-src/child-src-conflicting-frame-src.sub.html index b681253ae016..d11b7a3af6b1 100644 --- a/testing/web-platform/tests/content-security-policy/child-src/child-src-conflicting-frame-src.sub.html +++ b/testing/web-platform/tests/content-security-policy/child-src/child-src-conflicting-frame-src.sub.html @@ -53,7 +53,7 @@ frame-src 'none'; child-src 'self'; script-src 'self' 'unsafe-inline'; connect-s - +
diff --git a/testing/web-platform/tests/content-security-policy/child-src/child-src-cross-origin-load.sub.html b/testing/web-platform/tests/content-security-policy/child-src/child-src-cross-origin-load.sub.html index b6f3e5164e27..81bb003d652e 100644 --- a/testing/web-platform/tests/content-security-policy/child-src/child-src-cross-origin-load.sub.html +++ b/testing/web-platform/tests/content-security-policy/child-src/child-src-cross-origin-load.sub.html @@ -58,11 +58,11 @@ child-src 'self' http://www1.{{host}}:{{ports[http][0]}}; script-src 'self' 'uns - - - + + +
- + diff --git a/testing/web-platform/tests/content-security-policy/child-src/child-src-redirect-blocked.sub.html b/testing/web-platform/tests/content-security-policy/child-src/child-src-redirect-blocked.sub.html new file mode 100644 index 000000000000..74b77c95d564 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/child-src/child-src-redirect-blocked.sub.html @@ -0,0 +1,61 @@ + + + + + + child-src-blocked + + + + + +

+ IFrames blocked by CSP should generate a 'load', not 'error' event, regardless of blocked state. This means they appear to be normal cross-origin loads, thereby not leaking URL information directly to JS. +

+ + + + + +
+ + + + diff --git a/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-allowed.sub.html.sub.headers b/testing/web-platform/tests/content-security-policy/child-src/child-src-redirect-blocked.sub.html.sub.headers similarity index 77% rename from testing/web-platform/tests/content-security-policy/child-src/child-src-worker-allowed.sub.html.sub.headers rename to testing/web-platform/tests/content-security-policy/child-src/child-src-redirect-blocked.sub.html.sub.headers index 4ddb39e84b24..60dac9bc498d 100644 --- a/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-allowed.sub.html.sub.headers +++ b/testing/web-platform/tests/content-security-policy/child-src/child-src-redirect-blocked.sub.html.sub.headers @@ -2,5 +2,5 @@ Expires: Mon, 26 Jul 1997 05:00:00 GMT Cache-Control: no-store, no-cache, must-revalidate Cache-Control: post-check=0, pre-check=0, false Pragma: no-cache -Set-Cookie: child-src-worker-allowed={{$id:uuid()}}; Path=/content-security-policy/child-src +Set-Cookie: child-src-redirect-blocked={{$id:uuid()}}; Path=/content-security-policy/child-src Content-Security-Policy: child-src 'self'; script-src 'self' 'unsafe-inline'; connect-src 'self'; report-uri /content-security-policy/support/report.py?op=put&reportID={{$id}} diff --git a/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-allowed.sub.html b/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-allowed.sub.html index 361d0974287f..d02abaef1934 100644 --- a/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-allowed.sub.html +++ b/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-allowed.sub.html @@ -5,28 +5,34 @@ child-src-worker-allowed - - - - + +

This test used to check the child-src csp controlling worker creation. This behaviour has been deprecated but it's still supported + until the transition is done. This still tests that behaviour but we need to go through extra hoops to make sure 'script-src' + does not affect the result in any way (for instance by allowing 'self'). +

- diff --git a/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-blocked.sub.html b/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-blocked.sub.html index 8ed6b157a814..675cd95ea4f9 100644 --- a/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-blocked.sub.html +++ b/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-blocked.sub.html @@ -5,31 +5,40 @@ child-src-worker-blocked - - - - + +

This test used to check the child-src csp controlling worker creation. This behaviour has been deprecated but it's still supported + until the transition is done. This still tests that behaviour but we need to go through extra hoops to make sure 'script-src' + does not affect the result in any way (for instance by allowing 'self'). +

- diff --git a/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-blocked.sub.html.sub.headers b/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-blocked.sub.html.sub.headers deleted file mode 100644 index 685d6dcf5ea3..000000000000 --- a/testing/web-platform/tests/content-security-policy/child-src/child-src-worker-blocked.sub.html.sub.headers +++ /dev/null @@ -1,6 +0,0 @@ -Expires: Mon, 26 Jul 1997 05:00:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Cache-Control: post-check=0, pre-check=0, false -Pragma: no-cache -Set-Cookie: child-src-worker-blocked={{$id:uuid()}}; Path=/content-security-policy/child-src -Content-Security-Policy: child-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self'; report-uri /content-security-policy/support/report.py?op=put&reportID={{$id}} diff --git a/testing/web-platform/tests/content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html b/testing/web-platform/tests/content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html new file mode 100644 index 000000000000..98bdbd29a6e2 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html @@ -0,0 +1,70 @@ + + + +Embedded Enforcement: Embedding-CSP header. + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/embedded-enforcement/embedding_csp-header.html b/testing/web-platform/tests/content-security-policy/embedded-enforcement/embedding_csp-header.html index 424233a3ad82..2d526e329793 100644 --- a/testing/web-platform/tests/content-security-policy/embedded-enforcement/embedding_csp-header.html +++ b/testing/web-platform/tests/content-security-policy/embedded-enforcement/embedding_csp-header.html @@ -18,9 +18,6 @@ { "name": "Send Embedding-CSP Header on change of `src` attribute on iframe.", "csp": "script-src 'unsafe-inline'", "expected": "script-src 'unsafe-inline'" }, - { "name": "Wrong value of `csp` should not trigger sending Embedding-CSP Header.", - "csp": "completely wrong csp", - "expected": null}, ]; tests.forEach(test => { diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/deep-allows-none.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/deep-allows-none.sub.html deleted file mode 100644 index 1926007d34ca..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/deep-allows-none.sub.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - single-frame-self-allowed - - - - - - - - - -
- - diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html new file mode 100644 index 000000000000..674deb655a75 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html new file mode 100644 index 000000000000..85b7f0efdc82 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-star-allow.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-star-allow.html new file mode 100644 index 000000000000..7f5a867de94b --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-star-allow.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-allow.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-allow.html new file mode 100644 index 000000000000..99ab0718e8db --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-allow.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block.html new file mode 100644 index 000000000000..9bcf63735e75 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html new file mode 100644 index 000000000000..1cdd540149f4 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block.html new file mode 100644 index 000000000000..da9733971141 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html new file mode 100644 index 000000000000..c523b9ef10a7 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow.html new file mode 100644 index 000000000000..1f1ffb9f894b --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow.html @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block.html new file mode 100644 index 000000000000..62dd1c1ef665 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html new file mode 100644 index 000000000000..654e90e0b82d --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block.html new file mode 100644 index 000000000000..f01c6d766fc1 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block.html new file mode 100644 index 000000000000..bae5992e8609 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-star-allow.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-star-allow.html new file mode 100644 index 000000000000..85d66f660ab8 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-star-allow.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-allow.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-allow.html new file mode 100644 index 000000000000..dff041be9a39 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-allow.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block.html new file mode 100644 index 000000000000..5d2fc57ac14e --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block.html new file mode 100644 index 000000000000..234cca82c8ce --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-self-allow.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-self-allow.html new file mode 100644 index 000000000000..747c5636967e --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-self-allow.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-star-allow.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-star-allow.html new file mode 100644 index 000000000000..d7eaf73fd6cc --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-star-allow.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-allow.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-allow.html new file mode 100644 index 000000000000..432c25f0d2a6 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-allow.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block.html new file mode 100644 index 000000000000..c02091bf4ff7 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-none-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-none-block.html new file mode 100644 index 000000000000..596d3e7bc300 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-none-block.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-overrides-xfo.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-overrides-xfo.html new file mode 100644 index 000000000000..83654660331f --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-overrides-xfo.html @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-self-allow.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-self-allow.html new file mode 100644 index 000000000000..a8a295dfc40c --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-self-allow.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-self-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-self-block.html new file mode 100644 index 000000000000..438f2b8eb218 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-self-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin.html new file mode 100644 index 000000000000..09ee28bbeaf4 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin.html @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-star-allow-sameorigin.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-star-allow-sameorigin.html new file mode 100644 index 000000000000..62bbe45b2580 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-star-allow-sameorigin.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-url-allow.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-url-allow.sub.html new file mode 100644 index 000000000000..f4f42e475f88 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-url-allow.sub.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-url-block.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-url-block.html new file mode 100644 index 000000000000..c320370be515 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/frame-ancestors-url-block.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-self.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-self.sub.html deleted file mode 100644 index 6b9c91c9356d..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-self.sub.html +++ /dev/null @@ -1,21 +0,0 @@ - - - -

Reporting Frame...

- - - - \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-self.sub.html.headers b/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-self.sub.html.headers deleted file mode 100644 index f0eb936b362d..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-self.sub.html.headers +++ /dev/null @@ -1,5 +0,0 @@ -Expires: Mon, 26 Jul 1997 05:00:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Cache-Control: post-check=0, pre-check=0, false -Pragma: no-cache -Content-Security-Policy: frame-ancestors 'self' diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-star.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-star.sub.html deleted file mode 100644 index d51e0d5329db..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-star.sub.html +++ /dev/null @@ -1,20 +0,0 @@ - - - -

Reporting Frame...

- - - - \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-star.sub.html.headers b/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-star.sub.html.headers deleted file mode 100644 index 734aa227ffea..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/intermediate-reporting-frame-allows-star.sub.html.headers +++ /dev/null @@ -1,5 +0,0 @@ -Expires: Mon, 26 Jul 1997 05:00:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Cache-Control: post-check=0, pre-check=0, false -Pragma: no-cache -Content-Security-Policy: frame-ancestors * diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/multiple-frames-meta-ignored.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/multiple-frames-meta-ignored.sub.html deleted file mode 100644 index 47bb0244b4b9..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/multiple-frames-meta-ignored.sub.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - multiple-frames-self-allowed - - - - - - - - - - -
- - diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/multiple-frames-one-blocked.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/multiple-frames-one-blocked.sub.html deleted file mode 100644 index 3857a173cc2e..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/multiple-frames-one-blocked.sub.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - multiple-frames-self-allowed - - - - - - - - - - -
- - diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/multiple-frames-self-allowed.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/multiple-frames-self-allowed.sub.html deleted file mode 100644 index 485b6eb0f172..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/multiple-frames-self-allowed.sub.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - multiple-frames-self-allowed - - - - - - - - - - -
- - diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/nested-traversing-allowed.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/nested-traversing-allowed.sub.html deleted file mode 100644 index a49049d13675..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/nested-traversing-allowed.sub.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - single-frame-self-allowed - - - - - - - - - -
- - diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/nested-traversing-banned-top-is-self.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/nested-traversing-banned-top-is-self.sub.html deleted file mode 100644 index ced262fd7024..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/nested-traversing-banned-top-is-self.sub.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - single-frame-self-allowed - - - - - - - - - -
- - diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/nested-traversing-banned.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/nested-traversing-banned.sub.html deleted file mode 100644 index e58f0ba8d2b7..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/nested-traversing-banned.sub.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - single-frame-self-allowed - - - - - - - - - -
- - diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-none-meta.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-none-meta.html deleted file mode 100644 index c0d079f01c4b..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-none-meta.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - -

Reporting Frame...

- - - \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-none.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-none.html deleted file mode 100644 index e38d99a6c19c..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-none.html +++ /dev/null @@ -1,22 +0,0 @@ - - - -

Reporting Frame...

- - - \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-none.html.headers b/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-none.html.headers deleted file mode 100644 index 18bfb8156f32..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-none.html.headers +++ /dev/null @@ -1,5 +0,0 @@ -Expires: Mon, 26 Jul 1997 05:00:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Cache-Control: post-check=0, pre-check=0, false -Pragma: no-cache -Content-Security-Policy: frame-ancestors 'none' diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-self.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-self.html deleted file mode 100644 index 7c1186e77a42..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-self.html +++ /dev/null @@ -1,22 +0,0 @@ - - - -

Reporting Frame...

- - - \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-self.html.headers b/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-self.html.headers deleted file mode 100644 index f0eb936b362d..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/reporting-frame-allows-self.html.headers +++ /dev/null @@ -1,5 +0,0 @@ -Expires: Mon, 26 Jul 1997 05:00:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Cache-Control: post-check=0, pre-check=0, false -Pragma: no-cache -Content-Security-Policy: frame-ancestors 'self' diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/single-frame-self-allowed.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/single-frame-self-allowed.sub.html deleted file mode 100644 index 3a9b4552e080..000000000000 --- a/testing/web-platform/tests/content-security-policy/frame-ancestors/single-frame-self-allowed.sub.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - single-frame-self-allowed - - - - - - - - - -
- - diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html new file mode 100644 index 000000000000..e22fea3ccd36 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html @@ -0,0 +1,9 @@ + + + +

This is an IFrame sending a Content Security Policy header containing "frame-ancestors {{GET[policy]}}" and "X-Frame-Options: {{GET[xfo]}}".

+ + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html.sub.headers b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html.sub.headers new file mode 100644 index 000000000000..636e0facde59 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html.sub.headers @@ -0,0 +1,3 @@ +Content-Type: text/html; charset=UTF-8 +Content-Security-Policy: frame-ancestors {{GET[policy]}} +X-Frame-Options: {{GET[xfo]}} diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors-test.sub.js b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors-test.sub.js new file mode 100644 index 000000000000..dde04f0627e1 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors-test.sub.js @@ -0,0 +1,134 @@ +var SAME_ORIGIN = true; +var CROSS_ORIGIN = false; + +var EXPECT_BLOCK = true; +var EXPECT_LOAD = false; + +var SAMEORIGIN_ORIGIN = "{{location[scheme]}}://{{location[host]}}"; +var CROSSORIGIN_ORIGIN = "http://{{domains[www1]}}:{{ports[http][1]}}"; + +var test; + +function endTest(failed, message) { + if (typeof test === 'undefined') return; + + if (failed) { + test.step(function() { + assert_unreached(message); + test.done(); + }); + } + else test.done({message: message}); +} + +window.addEventListener("message", function (e) { + if (window.parent != window) + window.parent.postMessage(e.data, "*"); + else + if (e.data.type === 'test_result') + endTest(e.data.failed, "Inner IFrame msg: " + e.data.msg); +}); + +function injectNestedIframe(policy, parent, child, expectation, isSandboxed) { + var iframe = document.createElement("iframe"); + + var url = "/content-security-policy/frame-ancestors/support/frame-in-frame.sub.html" + + "?policy=" + policy + + "&parent=" + parent + + "&child=" + child + + "&expectation=" + expectation; + url = (parent == "same" ? SAMEORIGIN_ORIGIN : CROSSORIGIN_ORIGIN) + url; + + iframe.src = url; + + if (isSandboxed) + iframe.sandbox = 'allow-scripts'; + + document.body.appendChild(iframe); +} + +function injectIFrame(policy, sameOrigin, expectBlock) { + var iframe = document.createElement("iframe"); + iframe.addEventListener("load", iframeLoaded(expectBlock)); + iframe.addEventListener("error", iframeLoaded(expectBlock)); + + var url = "/content-security-policy/frame-ancestors/support/frame-ancestors.sub.html?policy=" + policy; + if (sameOrigin) + url = SAMEORIGIN_ORIGIN + url; + else + url = CROSSORIGIN_ORIGIN + url; + + iframe.src = url; + document.body.appendChild(iframe); +} + +function iframeLoaded(expectBlock) { + return function(ev) { + var failed = true; + var message = ""; + try { + if (expectBlock) { + message = "The IFrame should have been blocked (or cross-origin). It wasn't."; + failed = true; + } else { + message = "The IFrame should not have been blocked. It wasn't."; + failed = false; + } + } catch (ex) { + if (expectBlock) { + message = "The IFrame should have been blocked (or cross-origin). It was."; + failed = false; + } else { + message = "The IFrame should not have been blocked. It was."; + failed = true; + } + } + if (window.parent != window) + window.parent.postMessage({type: 'test_result', failed: failed, message: message}, '*'); + else + endTest(failed, message); + }; +} + +function originFrameShouldBe(child, expectation, policy) { + if (child == "cross" && expectation == "blocked") crossOriginFrameShouldBeBlocked(policy); + if (child == "same" && expectation == "blocked") sameOriginFrameShouldBeBlocked(policy); + if (child == "cross" && expectation == "allowed") crossOriginFrameShouldBeAllowed(policy); + if (child == "same" && expectation == "allowed") sameOriginFrameShouldBeAllowed(policy); +} + +function crossOriginFrameShouldBeBlocked(policy) { + window.onload = function () { + injectIFrame(policy, CROSS_ORIGIN, EXPECT_BLOCK); + }; +} + +function crossOriginFrameShouldBeAllowed(policy) { + window.onload = function () { + injectIFrame(policy, CROSS_ORIGIN, EXPECT_LOAD); + }; +} + +function sameOriginFrameShouldBeBlocked(policy) { + window.onload = function () { + injectIFrame(policy, SAME_ORIGIN, EXPECT_BLOCK); + }; +} + +function sameOriginFrameShouldBeAllowed(policy) { + window.onload = function () { + injectIFrame(policy, SAME_ORIGIN, EXPECT_LOAD); + }; +} + +function testNestedIFrame(policy, parent, child, expectation) { + window.onload = function () { + injectNestedIframe(policy, parent == SAME_ORIGIN ? "same" : "cross", child == SAME_ORIGIN ? "same" : "cross", expectation == EXPECT_LOAD ? "allowed" : "blocked", false /* isSandboxed */); + }; +} + +function testNestedSandboxedIFrame(policy, parent, child, expectation) { + window.onload = function () { + injectNestedIframe(policy, parent == SAME_ORIGIN ? "same" : "cross", child == SAME_ORIGIN ? "same" : "cross", expectation == EXPECT_LOAD ? "allowed" : "blocked", true /* isSandboxed */); + }; +} diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors.sub.html new file mode 100644 index 000000000000..de652773437f --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors.sub.html @@ -0,0 +1,9 @@ + + + +

This is an IFrame sending a Content Security Policy header containing "frame-ancestors {{GET[policy]}}".

+ + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors.sub.html.sub.headers b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors.sub.html.sub.headers new file mode 100644 index 000000000000..9369a4101fa1 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-ancestors.sub.html.sub.headers @@ -0,0 +1,2 @@ +Content-Type: text/html; charset=UTF-8 +Content-Security-Policy: frame-ancestors {{GET[policy]}} diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-in-frame.sub.html b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-in-frame.sub.html new file mode 100644 index 000000000000..5a60eb7f347c --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-in-frame.sub.html @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-in-frame.sub.html.sub.headers b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-in-frame.sub.html.sub.headers new file mode 100644 index 000000000000..e853d6cee5e0 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-ancestors/support/frame-in-frame.sub.html.sub.headers @@ -0,0 +1 @@ +Content-Type: text/html; charset=UTF-8 diff --git a/testing/web-platform/tests/content-security-policy/frame-src/frame-src-redirect.html b/testing/web-platform/tests/content-security-policy/frame-src/frame-src-redirect.html new file mode 100644 index 000000000000..f5ac88b05242 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-src/frame-src-redirect.html @@ -0,0 +1,35 @@ + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/frame-src/frame-src-redirect.html.headers b/testing/web-platform/tests/content-security-policy/frame-src/frame-src-redirect.html.headers new file mode 100644 index 000000000000..338bea13b84a --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-src/frame-src-redirect.html.headers @@ -0,0 +1,2 @@ +Content-Security-Policy: frame-src 'self' +Content-Security-Policy-Report-Only: frame-src http://foo.test diff --git a/testing/web-platform/tests/content-security-policy/frame-src/support/frame.html b/testing/web-platform/tests/content-security-policy/frame-src/support/frame.html new file mode 100644 index 000000000000..50be42958744 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-src/support/frame.html @@ -0,0 +1,2 @@ + + diff --git a/testing/web-platform/tests/content-security-policy/frame-src/support/testharness-helper.sub.js b/testing/web-platform/tests/content-security-policy/frame-src/support/testharness-helper.sub.js new file mode 100644 index 000000000000..b9e9a6c856bf --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/frame-src/support/testharness-helper.sub.js @@ -0,0 +1,5 @@ +function generateCrossOriginRedirectFrame() { + var target = "http://{{domains[天気の良い日]}}:" + document.location.port + "/content-security-policy/frame-src/support/frame.html"; + var url = "/common/redirect.py?location=" + encodeURIComponent(target); + return { url: url, target: target }; +} diff --git a/testing/web-platform/tests/content-security-policy/generic/generic-0_1-img-src.html b/testing/web-platform/tests/content-security-policy/generic/generic-0_1-img-src.html index c3778f81604d..0c1021589856 100644 --- a/testing/web-platform/tests/content-security-policy/generic/generic-0_1-img-src.html +++ b/testing/web-platform/tests/content-security-policy/generic/generic-0_1-img-src.html @@ -29,7 +29,7 @@ } - + diff --git a/testing/web-platform/tests/content-security-policy/generic/generic-0_1-script-src.html b/testing/web-platform/tests/content-security-policy/generic/generic-0_1-script-src.html index 740b2a553477..e4f0d1d5054f 100644 --- a/testing/web-platform/tests/content-security-policy/generic/generic-0_1-script-src.html +++ b/testing/web-platform/tests/content-security-policy/generic/generic-0_1-script-src.html @@ -29,7 +29,7 @@ } - + diff --git a/testing/web-platform/tests/content-security-policy/script-src/crossoriginScript.js b/testing/web-platform/tests/content-security-policy/script-src/crossoriginScript.js new file mode 100644 index 000000000000..08535fa552ea --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/script-src/crossoriginScript.js @@ -0,0 +1,3 @@ +// Identical to simpleSourcedScript.js but with a different hash, thanks to +// this comment! +window.postMessage(document.currentScript.id, "*"); diff --git a/testing/web-platform/tests/content-security-policy/script-src/crossoriginScript.js.headers b/testing/web-platform/tests/content-security-policy/script-src/crossoriginScript.js.headers new file mode 100644 index 000000000000..cb762eff8068 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/script-src/crossoriginScript.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/content-security-policy/script-src/externalScript.js b/testing/web-platform/tests/content-security-policy/script-src/externalScript.js new file mode 100644 index 000000000000..2920b03c9bc9 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/script-src/externalScript.js @@ -0,0 +1 @@ +externalRan = true; \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/script-src/script-src-sri_hash.sub.html b/testing/web-platform/tests/content-security-policy/script-src/script-src-sri_hash.sub.html new file mode 100644 index 000000000000..2c888f46d991 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/script-src/script-src-sri_hash.sub.html @@ -0,0 +1,104 @@ + + + + + External scripts with matching SRI hash should be allowed. + + + + + + + +

External scripts with matching SRI hash should be allowed.

+
+ + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/script-src/script-src-sri_hash.sub.html.sub.headers b/testing/web-platform/tests/content-security-policy/script-src/script-src-sri_hash.sub.html.sub.headers new file mode 100644 index 000000000000..25cd6541acac --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/script-src/script-src-sri_hash.sub.html.sub.headers @@ -0,0 +1,5 @@ +Expires: Mon, 26 Jul 1997 05:00:00 GMT +Cache-Control: no-store, no-cache, must-revalidate +Cache-Control: post-check=0, pre-check=0, false +Pragma: no-cache +Content-Security-Policy: script-src {{domains[www]}}:* 'nonce-dummy' 'sha256-wIc3KtqOuTFEu6t17sIBuOswgkV406VJvhSk79Gw6U0=' 'sha256-L7/UQ9VWpyG7C9RDEC4ctS5hI3Zcw+ta+haPGlByG9c=' 'sha512-rYCVMxWV5nq8IsMo+UZNObWtEiWGok/vDN8BMoEQi41s0znSes6E1Q2aag3Lw3u2J1w2rqH7uF2ws6FpQhfSOA=' diff --git a/testing/web-platform/tests/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html b/testing/web-platform/tests/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html new file mode 100644 index 000000000000..213eb6276d85 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html @@ -0,0 +1,20 @@ + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html new file mode 100644 index 000000000000..27611273babc --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html @@ -0,0 +1,31 @@ + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers new file mode 100644 index 000000000000..57207bbd23cf --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers @@ -0,0 +1,2 @@ +Content-Security-Policy-Report-Only: img-src https: +Content-Security-Policy: upgrade-insecure-requests diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js new file mode 100644 index 000000000000..816b88fc6e47 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js @@ -0,0 +1,5 @@ +function generateCrossOriginRedirectImage() { + var target = "http://{{host}}:{{ports[https][0]}}/content-security-policy/support/pass.png"; + var url = "/common/redirect.py?location=" + encodeURIComponent(target); + return { url: url, target: target } +} \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html new file mode 100644 index 000000000000..5a0bc7c8e7aa --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html @@ -0,0 +1,60 @@ + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers new file mode 100644 index 000000000000..b8bec0b95e39 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers @@ -0,0 +1,2 @@ +Content-Security-Policy-Report-Only: frame-src https:; img-src https: +Content-Security-Policy: upgrade-insecure-requests diff --git a/testing/web-platform/tests/content-security-policy/support/post-message.js b/testing/web-platform/tests/content-security-policy/support/post-message.js new file mode 100644 index 000000000000..69daa31d2f1b --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/post-message.js @@ -0,0 +1 @@ +postMessage("importScripts allowed"); diff --git a/testing/web-platform/tests/content-security-policy/support/postmessage-fail.html b/testing/web-platform/tests/content-security-policy/support/postmessage-fail.html new file mode 100644 index 000000000000..a0308ad98b4c --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/postmessage-fail.html @@ -0,0 +1,4 @@ + diff --git a/testing/web-platform/tests/content-security-policy/support/postmessage-pass.html b/testing/web-platform/tests/content-security-policy/support/postmessage-pass.html new file mode 100644 index 000000000000..700167b5db84 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/postmessage-pass.html @@ -0,0 +1,4 @@ + diff --git a/testing/web-platform/tests/content-security-policy/svg/object-in-svg-foreignobject.sub.html b/testing/web-platform/tests/content-security-policy/svg/object-in-svg-foreignobject.sub.html new file mode 100644 index 000000000000..aa4f15695307 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/svg/object-in-svg-foreignobject.sub.html @@ -0,0 +1,27 @@ + + + + Object inside SVG foreignobject respect csp + + + + + + + + + + + + + diff --git a/testing/web-platform/tests/cors/allow-headers.htm b/testing/web-platform/tests/cors/allow-headers.htm index 08e00a5270f7..8f25f3e4351b 100644 --- a/testing/web-platform/tests/cors/allow-headers.htm +++ b/testing/web-platform/tests/cors/allow-headers.htm @@ -44,7 +44,7 @@ function shouldFail(origin) { + '/resources/cors-makeheader.py?origin=' + encodeURIComponent(origin), false) - assert_throws(null, function() { client.send() }, 'send') + assert_throws("NetworkError", function() { client.send() }, 'send') }, 'Disallow origin: ' + origin.replace('\0', '\\0')); } diff --git a/testing/web-platform/tests/cors/origin.htm b/testing/web-platform/tests/cors/origin.htm index a3bb6c56542b..a04a29eb497f 100644 --- a/testing/web-platform/tests/cors/origin.htm +++ b/testing/web-platform/tests/cors/origin.htm @@ -47,7 +47,7 @@ function shouldFail(origin) { + '/resources/cors-makeheader.py?origin=' + encodeURIComponent(origin), false) - assert_throws(null, function() { client.send() }, 'send') + assert_throws("NetworkError", function() { client.send() }, 'send') }, 'Disallow origin: ' + origin.replace(/\0/g, "\\0")); } @@ -105,7 +105,7 @@ function doubleOrigin(origin, origin2) { + encodeURIComponent(origin) + '&origin2=' + encodeURIComponent(origin2), false) - assert_throws(null, function() { client.send() }, 'send') + assert_throws("NetworkError", function() { client.send() }, 'send') }, 'Disallow multiple headers (' + origin + ', ' + origin2 + ')'); } diff --git a/testing/web-platform/tests/cors/request-headers.htm b/testing/web-platform/tests/cors/request-headers.htm index 8adaeb4f8bd9..289f402191eb 100644 --- a/testing/web-platform/tests/cors/request-headers.htm +++ b/testing/web-platform/tests/cors/request-headers.htm @@ -48,7 +48,7 @@ test(function() { client.open('GET', CROSSDOMAIN + 'resources/cors-makeheader.py?headers=x-print', false) client.setRequestHeader('x-print', 'unicorn') client.setRequestHeader('y-print', 'unicorn') - assert_throws(null, function() { client.send(null) }) + assert_throws("NetworkError", function() { client.send(null) }) }, 'Unspecified request headers are disallowed') test(function() { diff --git a/testing/web-platform/tests/credential-management/idl.https.html b/testing/web-platform/tests/credential-management/idl.https.html new file mode 100644 index 000000000000..bc779d069e90 --- /dev/null +++ b/testing/web-platform/tests/credential-management/idl.https.html @@ -0,0 +1,93 @@ + + + + + + + + + diff --git a/testing/web-platform/tests/css-font-loading/fontfacesetloadevent-constructor.html b/testing/web-platform/tests/css-font-loading/fontfacesetloadevent-constructor.html new file mode 100644 index 000000000000..d5038ce690c6 --- /dev/null +++ b/testing/web-platform/tests/css-font-loading/fontfacesetloadevent-constructor.html @@ -0,0 +1,20 @@ + +FontFaceSetLoadEvent constructor + + + + diff --git a/testing/web-platform/tests/css-paint-api/OWNERS b/testing/web-platform/tests/css-paint-api/OWNERS new file mode 100644 index 000000000000..bd72a2a78f75 --- /dev/null +++ b/testing/web-platform/tests/css-paint-api/OWNERS @@ -0,0 +1,3 @@ +@bfgeek +@grorg +@shans diff --git a/testing/web-platform/tests/cssom-view/CaretPosition-001.html b/testing/web-platform/tests/cssom-view/CaretPosition-001.html new file mode 100644 index 000000000000..d8e97a92342c --- /dev/null +++ b/testing/web-platform/tests/cssom-view/CaretPosition-001.html @@ -0,0 +1,44 @@ + + + +CSSOM View Module test:CaretPosition + + + + + + + +
+
+
+
+
+
+
+
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/MediaQueryList-001.html b/testing/web-platform/tests/cssom-view/MediaQueryList-001.html new file mode 100644 index 000000000000..06c81d5de4c6 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/MediaQueryList-001.html @@ -0,0 +1,21 @@ + + + + CSSOM View Module test:MediaQueryList + + + + + + + +

This case tests the MediaQueryList

+
+ + + diff --git a/testing/web-platform/tests/cssom-view/OWNERS b/testing/web-platform/tests/cssom-view/OWNERS index cd9ff2eee4bb..678152d6503c 100644 --- a/testing/web-platform/tests/cssom-view/OWNERS +++ b/testing/web-platform/tests/cssom-view/OWNERS @@ -1 +1,3 @@ @AutomatedTester +@plinss +@zcorpan diff --git a/testing/web-platform/tests/cssom-view/Screen-pixelDepth-Screen-colorDepth001.html b/testing/web-platform/tests/cssom-view/Screen-pixelDepth-Screen-colorDepth001.html new file mode 100644 index 000000000000..2a8d5b5b4928 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/Screen-pixelDepth-Screen-colorDepth001.html @@ -0,0 +1,33 @@ + + + + CSSOM View Module test:Screen-pixelDepth,Screen-colorDepth + + + + + + + +

This case tests the Screen pixelDepth and colorDepth

+

The test passes if the value is 24

+
+ + + diff --git a/testing/web-platform/tests/cssom-view/cssom-getBoundingClientRect-001.html b/testing/web-platform/tests/cssom-view/cssom-getBoundingClientRect-001.html new file mode 100644 index 000000000000..7d96540adfe9 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/cssom-getBoundingClientRect-001.html @@ -0,0 +1,41 @@ + + + + CSSOM View - 6.1 - getBoundingClientRect tests + + + + + + + + + +
test item
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/cssom-getBoundingClientRect-002.html b/testing/web-platform/tests/cssom-view/cssom-getBoundingClientRect-002.html new file mode 100644 index 000000000000..a7c3568969a7 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/cssom-getBoundingClientRect-002.html @@ -0,0 +1,27 @@ + + + + + CSS Test (CSSOM View): getBoundingClientRect of element outside DOM + + + + + + + + + + + diff --git a/testing/web-platform/tests/cssom-view/cssom-getClientRects.html b/testing/web-platform/tests/cssom-view/cssom-getClientRects.html new file mode 100644 index 000000000000..36559eb116a6 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/cssom-getClientRects.html @@ -0,0 +1,23 @@ + + + + + CSS Test (CSSOM View): getClientRects of element outside DOM + + + + + + + + + + diff --git a/testing/web-platform/tests/cssom-view/cssom-view-img-attributes-001.html b/testing/web-platform/tests/cssom-view/cssom-view-img-attributes-001.html new file mode 100644 index 000000000000..2f4228810415 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/cssom-view-img-attributes-001.html @@ -0,0 +1,46 @@ + + + + CSS Test: HTMLImageElement x and y attributes + + + + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom-view/cssom-view-window-screen-interface.html b/testing/web-platform/tests/cssom-view/cssom-view-window-screen-interface.html new file mode 100644 index 000000000000..0d5e9bcaa549 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/cssom-view-window-screen-interface.html @@ -0,0 +1,40 @@ + + + + CSS Test: cssom view window screen attribute + + + + + + + + +
+
+ + + + diff --git a/testing/web-platform/tests/cssom-view/cssom-view/media-query-list-interface.xht b/testing/web-platform/tests/cssom-view/cssom-view/media-query-list-interface.xht new file mode 100644 index 000000000000..98bdaae6ec40 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/cssom-view/media-query-list-interface.xht @@ -0,0 +1,70 @@ + + + + + CSSOM MediaQueryList Test: Properties and Functions + + + + + + + + diff --git a/testing/web-platform/tests/cssom-view/cssom-view/window-interface.xht b/testing/web-platform/tests/cssom-view/cssom-view/window-interface.xht new file mode 100644 index 000000000000..2ed64cba6e6c --- /dev/null +++ b/testing/web-platform/tests/cssom-view/cssom-view/window-interface.xht @@ -0,0 +1,98 @@ + + + + + CSSOM Window Test: Properties and Functions + + + + + + + + diff --git a/testing/web-platform/tests/cssom-view/elementFromPoint-001.html b/testing/web-platform/tests/cssom-view/elementFromPoint-001.html new file mode 100644 index 000000000000..c2fcc42c530c --- /dev/null +++ b/testing/web-platform/tests/cssom-view/elementFromPoint-001.html @@ -0,0 +1,34 @@ + + + + CSSOM View - 5 - extensions to the Document interface + + + + + + + + + +
+
+
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/elementFromPosition.html b/testing/web-platform/tests/cssom-view/elementFromPosition.html new file mode 100644 index 000000000000..b781bb3713ed --- /dev/null +++ b/testing/web-platform/tests/cssom-view/elementFromPosition.html @@ -0,0 +1,143 @@ + + + + CSS Test: CSSOM View elementFromPoint + + + + + + + + + + +
+ + + + + diff --git a/testing/web-platform/tests/cssom-view/elementScroll.html b/testing/web-platform/tests/cssom-view/elementScroll.html index 6227d6654575..a5df48109eb5 100644 --- a/testing/web-platform/tests/cssom-view/elementScroll.html +++ b/testing/web-platform/tests/cssom-view/elementScroll.html @@ -4,35 +4,27 @@
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ultricies tortor eu augue eleifend malesuada. Duis id condimentum urna. Duis vulputate urna a dignissim sodales. Aenean et magna id dui rutrum suscipit. Etiam metus mauris, congue ac suscipit dapibus, mattis non neque. Donec porttitor eros sed mauris tristique, non condimentum augue feugiat. Suspendisse iaculis faucibus nunc at porttitor. Integer convallis enim in feugiat molestie. Ut eget tincidunt mi, vel malesuada lectus. Quisque fermentum neque a sapien interdum consectetur. Nam tincidunt leo sit amet tortor ornare, sit amet ultrices ante semper. Fusce malesuada mi vitae venenatis sagittis. Duis eget urna quam. - - Sed lacinia aliquam tortor quis elementum. Cras vitae mauris erat. Vestibulum posuere justo et dolor condimentum feugiat. Sed at magna nunc. Suspendisse est nunc, ultrices sed enim lobortis, vulputate rutrum mauris. Fusce ultrices eget erat blandit porta. Sed eros nulla, tristique eget porta a, viverra vel velit. Praesent sit amet odio eleifend, tempor arcu ut, elementum tellus. Suspendisse lorem tortor, sodales eget nulla a, rhoncus lobortis magna. Phasellus purus ante, rhoncus a ipsum nec, condimentum lacinia purus. Cras lobortis posuere nisi, vitae dapibus ante feugiat et. Quisque ornare nisi quis erat congue viverra. Vestibulum a nunc odio. - - Sed id venenatis tortor. Curabitur sit amet mauris eget mi semper rutrum vel et odio. Phasellus eu sapien in sem ultricies pretium eu sit amet magna. Nulla finibus nec lorem ac semper. Nulla eleifend eros id fringilla pellentesque. Proin eleifend, sem vel lobortis viverra, massa augue viverra felis, quis ultricies sapien ipsum at magna. Duis rutrum tempus lobortis. Aliquam quis nulla eget velit viverra pretium. Maecenas venenatis nec nisl at pulvinar. Duis in sodales lectus, ac porta augue. - - Sed sed ante aliquam, rutrum nisl quis, fermentum tellus. Proin ac leo molestie, euismod mauris sed, consequat nunc. Vivamus ut leo a nunc pharetra accumsan a non lorem. Aliquam iaculis mattis augue, in eleifend est accumsan vel. Pellentesque efficitur pulvinar leo vel ornare. Pellentesque non fermentum enim, ut efficitur elit. Duis risus quam, congue vel nulla a, blandit egestas erat. Suspendisse at sodales dolor. Vivamus auctor, lorem et ultrices venenatis, erat ex mollis nisi, quis maximus libero quam a libero. - - Curabitur elit lacus, bibendum non tempus a, bibendum sit amet ante. Mauris eget nibh quis leo rhoncus consequat. Integer iaculis sed sapien eu pellentesque. In aliquet elementum lorem, ut consequat elit ultrices id. Phasellus vestibulum ex ex, ac sagittis tortor convallis et. Curabitur placerat id lectus at aliquam. Morbi sed nisl sem. Nam sit amet arcu maximus, volutpat nisl ac, dignissim neque. Etiam nec efficitur libero. Quisque tristique pulvinar est, eget dictum ex vehicula non. Nam dignissim non felis a iaculis. Nullam vel dolor vitae libero aliquet congue. Donec mi eros, semper non lectus at, commodo ullamcorper ligula. Donec commodo, sem vel lacinia porttitor, elit orci maximus felis, eget eleifend est velit id lorem. -
+
+ + + +
...
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/matchMedia.xht b/testing/web-platform/tests/cssom-view/matchMedia.xht new file mode 100644 index 000000000000..7ac875c6aa96 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/matchMedia.xht @@ -0,0 +1,187 @@ + + + + + CSS Test: CSSOM View matchMedia and MediaQueryList + + + + + + + + diff --git a/testing/web-platform/tests/cssom-view/matchMediaAddListener.html b/testing/web-platform/tests/cssom-view/matchMediaAddListener.html new file mode 100644 index 000000000000..7236be7febc9 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/matchMediaAddListener.html @@ -0,0 +1,65 @@ + + + + CSS Test: CSSOM View matchMedia addListener + + + + + + + + +
+ + + + diff --git a/testing/web-platform/tests/cssom-view/offsetParent_element_test.html b/testing/web-platform/tests/cssom-view/offsetParent_element_test.html new file mode 100644 index 000000000000..473120f4b9be --- /dev/null +++ b/testing/web-platform/tests/cssom-view/offsetParent_element_test.html @@ -0,0 +1,138 @@ + + + + +CSSOM View —— offsetParent element test + + + + + + + + + + + +
+ +
+
+
+ +
+
+
+ + + + + + + + + +
+
+
+ +
+ +
+ +

+ + + + +
+ +
+
+ +
+ + + + diff --git a/testing/web-platform/tests/cssom-view/scrollWidthHeight.xht b/testing/web-platform/tests/cssom-view/scrollWidthHeight.xht new file mode 100644 index 000000000000..b4696e136305 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/scrollWidthHeight.xht @@ -0,0 +1,147 @@ + + + + + CSS Test: CSSOM View scrollWidth and scrollHeight + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/scrollWidthHeightWhenNotScrollable.xht b/testing/web-platform/tests/cssom-view/scrollWidthHeightWhenNotScrollable.xht new file mode 100644 index 000000000000..e8c7f1298bc4 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/scrollWidthHeightWhenNotScrollable.xht @@ -0,0 +1,137 @@ + + + + + CSS Test: CSSOM View scrollWidth/scrollHeight (for nonscrollable elements) + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/scrolling-quirks-vs-nonquirks.html b/testing/web-platform/tests/cssom-view/scrolling-quirks-vs-nonquirks.html new file mode 100644 index 000000000000..568f572ac22c --- /dev/null +++ b/testing/web-platform/tests/cssom-view/scrolling-quirks-vs-nonquirks.html @@ -0,0 +1,220 @@ + + +cssom-view - scrolling quirks VS nonquirks mode + + + + + +
+ diff --git a/testing/web-platform/tests/cssom-view/support/1x1-green.png b/testing/web-platform/tests/cssom-view/support/1x1-green.png new file mode 100644 index 000000000000..b98ca0ba0a03 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/1x1-green.png differ diff --git a/testing/web-platform/tests/cssom-view/support/1x1-lime.png b/testing/web-platform/tests/cssom-view/support/1x1-lime.png new file mode 100644 index 000000000000..cb397fb090e1 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/1x1-lime.png differ diff --git a/testing/web-platform/tests/cssom-view/support/1x1-maroon.png b/testing/web-platform/tests/cssom-view/support/1x1-maroon.png new file mode 100644 index 000000000000..3f86b0721955 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/1x1-maroon.png differ diff --git a/testing/web-platform/tests/cssom-view/support/1x1-navy.png b/testing/web-platform/tests/cssom-view/support/1x1-navy.png new file mode 100644 index 000000000000..9b9a03955bae Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/1x1-navy.png differ diff --git a/testing/web-platform/tests/cssom-view/support/1x1-red.png b/testing/web-platform/tests/cssom-view/support/1x1-red.png new file mode 100644 index 000000000000..6bd73ac10187 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/1x1-red.png differ diff --git a/testing/web-platform/tests/cssom-view/support/1x1-white.png b/testing/web-platform/tests/cssom-view/support/1x1-white.png new file mode 100644 index 000000000000..dd43faec54ae Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/1x1-white.png differ diff --git a/testing/web-platform/tests/cssom-view/support/60x60-gg-rr.png b/testing/web-platform/tests/cssom-view/support/60x60-gg-rr.png new file mode 100644 index 000000000000..84f5b2a4f1d1 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/60x60-gg-rr.png differ diff --git a/testing/web-platform/tests/cssom-view/support/60x60-green.png b/testing/web-platform/tests/cssom-view/support/60x60-green.png new file mode 100644 index 000000000000..b3c8cf3eb4c8 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/60x60-green.png differ diff --git a/testing/web-platform/tests/cssom-view/support/60x60-red.png b/testing/web-platform/tests/cssom-view/support/60x60-red.png new file mode 100644 index 000000000000..823f125b8e4a Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/60x60-red.png differ diff --git a/testing/web-platform/tests/cssom-view/support/README b/testing/web-platform/tests/cssom-view/support/README new file mode 100644 index 000000000000..2e5f2ad0738c --- /dev/null +++ b/testing/web-platform/tests/cssom-view/support/README @@ -0,0 +1,28 @@ +CSS Global Support Directory +============================ + +This directory contains common support files (such as images and external +style sheets). These are sync'ed into the support directories of all our +test suites. If you have test-suite-specific support files, please add +them to the appropriate test-suite-specific support/ directory. + +If you add to a support/ directory, please run the tools/supportprop.py +script from the top of the repository to cascade support files into the +lower-level support directories. + +Description of the Common Support File Collection +------------------------------------------------- + +The 1x1-* images are all exactly one pixel. + +The swatch-* images all use 15x15 cells. + +The square-* images all use 15x15 cells with one pixel borders. + +The pattern-* images use cells of various sizes: + + pattern-grg-rgr-grg.png 20x20 + pattern-rgr-grg-rgr.png 20x20 + pattern-tr.png 15x15 + pattern-grg-rrg-rgg.png 15x15 + diff --git a/testing/web-platform/tests/cssom-view/support/a-green.css b/testing/web-platform/tests/cssom-view/support/a-green.css new file mode 100644 index 000000000000..b0dbb071d5b0 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/support/a-green.css @@ -0,0 +1 @@ +.a { color: green; } diff --git a/testing/web-platform/tests/cssom-view/support/b-green.css b/testing/web-platform/tests/cssom-view/support/b-green.css new file mode 100644 index 000000000000..a0473f5ca266 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/support/b-green.css @@ -0,0 +1 @@ +.b { color: green; } \ No newline at end of file diff --git a/testing/web-platform/tests/cssom-view/support/c-red.css b/testing/web-platform/tests/cssom-view/support/c-red.css new file mode 100644 index 000000000000..d4ba5c64e954 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/support/c-red.css @@ -0,0 +1 @@ +.c { color: red; } \ No newline at end of file diff --git a/testing/web-platform/tests/cssom-view/support/cat.png b/testing/web-platform/tests/cssom-view/support/cat.png new file mode 100644 index 000000000000..85dd7324815b Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/cat.png differ diff --git a/testing/web-platform/tests/cssom-view/support/import-green.css b/testing/web-platform/tests/cssom-view/support/import-green.css new file mode 100644 index 000000000000..537104e66336 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/support/import-green.css @@ -0,0 +1 @@ +.import { color: green; } diff --git a/testing/web-platform/tests/cssom-view/support/import-red.css b/testing/web-platform/tests/cssom-view/support/import-red.css new file mode 100644 index 000000000000..9945ef47114c --- /dev/null +++ b/testing/web-platform/tests/cssom-view/support/import-red.css @@ -0,0 +1 @@ +.import { color: red; } diff --git a/testing/web-platform/tests/cssom-view/support/pattern-grg-rgr-grg.png b/testing/web-platform/tests/cssom-view/support/pattern-grg-rgr-grg.png new file mode 100644 index 000000000000..9b88fbd81149 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/pattern-grg-rgr-grg.png differ diff --git a/testing/web-platform/tests/cssom-view/support/pattern-grg-rrg-rgg.png b/testing/web-platform/tests/cssom-view/support/pattern-grg-rrg-rgg.png new file mode 100644 index 000000000000..fcf4f3fd7d95 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/pattern-grg-rrg-rgg.png differ diff --git a/testing/web-platform/tests/cssom-view/support/pattern-rgr-grg-rgr.png b/testing/web-platform/tests/cssom-view/support/pattern-rgr-grg-rgr.png new file mode 100644 index 000000000000..d454e3a630cd Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/pattern-rgr-grg-rgr.png differ diff --git a/testing/web-platform/tests/cssom-view/support/pattern-tr.png b/testing/web-platform/tests/cssom-view/support/pattern-tr.png new file mode 100644 index 000000000000..8b4b25364e0f Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/pattern-tr.png differ diff --git a/testing/web-platform/tests/cssom-view/support/ruler-h-50%.png b/testing/web-platform/tests/cssom-view/support/ruler-h-50%.png new file mode 100644 index 000000000000..cf2eea6b438a Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/ruler-h-50%.png differ diff --git a/testing/web-platform/tests/cssom-view/support/ruler-h-50px.png b/testing/web-platform/tests/cssom-view/support/ruler-h-50px.png new file mode 100644 index 000000000000..9f46583665ca Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/ruler-h-50px.png differ diff --git a/testing/web-platform/tests/cssom-view/support/ruler-v-100px.png b/testing/web-platform/tests/cssom-view/support/ruler-v-100px.png new file mode 100644 index 000000000000..a837eca22250 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/ruler-v-100px.png differ diff --git a/testing/web-platform/tests/cssom-view/support/ruler-v-50px.png b/testing/web-platform/tests/cssom-view/support/ruler-v-50px.png new file mode 100644 index 000000000000..84141028020b Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/ruler-v-50px.png differ diff --git a/testing/web-platform/tests/cssom-view/support/square-purple.png b/testing/web-platform/tests/cssom-view/support/square-purple.png new file mode 100644 index 000000000000..0f522d787284 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/square-purple.png differ diff --git a/testing/web-platform/tests/cssom-view/support/square-teal.png b/testing/web-platform/tests/cssom-view/support/square-teal.png new file mode 100644 index 000000000000..e567f51b91bb Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/square-teal.png differ diff --git a/testing/web-platform/tests/cssom-view/support/square-white.png b/testing/web-platform/tests/cssom-view/support/square-white.png new file mode 100644 index 000000000000..5853cbb238cb Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/square-white.png differ diff --git a/testing/web-platform/tests/cssom-view/support/support/README b/testing/web-platform/tests/cssom-view/support/support/README new file mode 100644 index 000000000000..ea8cb9ef357d --- /dev/null +++ b/testing/web-platform/tests/cssom-view/support/support/README @@ -0,0 +1,4 @@ +The swatch-green.png file in this directory is really a RED swatch, +and the swatch-red.png file is really a green swatch. + +This directory is used to test relative URIs. \ No newline at end of file diff --git a/testing/web-platform/tests/cssom-view/support/support/swatch-green.png b/testing/web-platform/tests/cssom-view/support/support/swatch-green.png new file mode 100644 index 000000000000..1caf25c992aa Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/support/swatch-green.png differ diff --git a/testing/web-platform/tests/cssom-view/support/support/swatch-red.png b/testing/web-platform/tests/cssom-view/support/support/swatch-red.png new file mode 100644 index 000000000000..0aa79b0c86bd Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/support/swatch-red.png differ diff --git a/testing/web-platform/tests/cssom-view/support/swatch-blue.png b/testing/web-platform/tests/cssom-view/support/swatch-blue.png new file mode 100644 index 000000000000..bf2759634d45 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/swatch-blue.png differ diff --git a/testing/web-platform/tests/cssom-view/support/swatch-green.png b/testing/web-platform/tests/cssom-view/support/swatch-green.png new file mode 100644 index 000000000000..0aa79b0c86bd Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/swatch-green.png differ diff --git a/testing/web-platform/tests/cssom-view/support/swatch-lime.png b/testing/web-platform/tests/cssom-view/support/swatch-lime.png new file mode 100644 index 000000000000..55fd7fdaedfc Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/swatch-lime.png differ diff --git a/testing/web-platform/tests/cssom-view/support/swatch-orange.png b/testing/web-platform/tests/cssom-view/support/swatch-orange.png new file mode 100644 index 000000000000..d3cd498b52bd Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/swatch-orange.png differ diff --git a/testing/web-platform/tests/cssom-view/support/swatch-red.png b/testing/web-platform/tests/cssom-view/support/swatch-red.png new file mode 100644 index 000000000000..1caf25c992aa Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/swatch-red.png differ diff --git a/testing/web-platform/tests/cssom-view/support/swatch-teal.png b/testing/web-platform/tests/cssom-view/support/swatch-teal.png new file mode 100644 index 000000000000..0293ce89dea5 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/swatch-teal.png differ diff --git a/testing/web-platform/tests/cssom-view/support/swatch-white.png b/testing/web-platform/tests/cssom-view/support/swatch-white.png new file mode 100644 index 000000000000..1a7d4323d772 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/swatch-white.png differ diff --git a/testing/web-platform/tests/cssom-view/support/swatch-yellow.png b/testing/web-platform/tests/cssom-view/support/swatch-yellow.png new file mode 100644 index 000000000000..1591aa0e2e27 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/swatch-yellow.png differ diff --git a/testing/web-platform/tests/cssom-view/support/test-bl.png b/testing/web-platform/tests/cssom-view/support/test-bl.png new file mode 100644 index 000000000000..904e24e996a3 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/test-bl.png differ diff --git a/testing/web-platform/tests/cssom-view/support/test-br.png b/testing/web-platform/tests/cssom-view/support/test-br.png new file mode 100644 index 000000000000..f413ff5c1a0f Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/test-br.png differ diff --git a/testing/web-platform/tests/cssom-view/support/test-inner-half-size.png b/testing/web-platform/tests/cssom-view/support/test-inner-half-size.png new file mode 100644 index 000000000000..e473bf80efc6 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/test-inner-half-size.png differ diff --git a/testing/web-platform/tests/cssom-view/support/test-outer.png b/testing/web-platform/tests/cssom-view/support/test-outer.png new file mode 100644 index 000000000000..82eeace7fc0c Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/test-outer.png differ diff --git a/testing/web-platform/tests/cssom-view/support/test-tl.png b/testing/web-platform/tests/cssom-view/support/test-tl.png new file mode 100644 index 000000000000..f6ac0ef7e8f6 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/test-tl.png differ diff --git a/testing/web-platform/tests/cssom-view/support/test-tr.png b/testing/web-platform/tests/cssom-view/support/test-tr.png new file mode 100644 index 000000000000..59843ae54b64 Binary files /dev/null and b/testing/web-platform/tests/cssom-view/support/test-tr.png differ diff --git a/testing/web-platform/tests/cssom-view/ttwf-js-cssomview-getclientrects-length.html b/testing/web-platform/tests/cssom-view/ttwf-js-cssomview-getclientrects-length.html new file mode 100644 index 000000000000..bc873174568c --- /dev/null +++ b/testing/web-platform/tests/cssom-view/ttwf-js-cssomview-getclientrects-length.html @@ -0,0 +1,28 @@ + + + + CSSOM View API Test: the length of getClientRects + + + + + + + + + +
+ + Test Link +
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/ttwf-scrollintoview.html b/testing/web-platform/tests/cssom-view/ttwf-scrollintoview.html new file mode 100644 index 000000000000..1ccb9c580de6 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/ttwf-scrollintoview.html @@ -0,0 +1,32 @@ + + + + CSSOM View - 6 - scrollIntoView tests + + + + + + + + + +
+
+
+
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/window-screen-height-immutable.html b/testing/web-platform/tests/cssom-view/window-screen-height-immutable.html new file mode 100644 index 000000000000..88dd0684816d --- /dev/null +++ b/testing/web-platform/tests/cssom-view/window-screen-height-immutable.html @@ -0,0 +1,27 @@ + + + + CSSOM View - 4.2 - screen.height immutability + + + + + + + + +
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/window-screen-height.html b/testing/web-platform/tests/cssom-view/window-screen-height.html new file mode 100644 index 000000000000..9bb7e528b89f --- /dev/null +++ b/testing/web-platform/tests/cssom-view/window-screen-height.html @@ -0,0 +1,37 @@ + + + + CSSOM View - 4.2 - screen.height range tests + + + + + + + + +
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/window-screen-width-immutable.html b/testing/web-platform/tests/cssom-view/window-screen-width-immutable.html new file mode 100644 index 000000000000..1415bfaca440 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/window-screen-width-immutable.html @@ -0,0 +1,27 @@ + + + + CSSOM View - 4.2 - screen.width immutability + + + + + + + + +
+
+ + + diff --git a/testing/web-platform/tests/cssom-view/window-screen-width.html b/testing/web-platform/tests/cssom-view/window-screen-width.html new file mode 100644 index 000000000000..fdae2bc74250 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/window-screen-width.html @@ -0,0 +1,37 @@ + + + + CSSOM View - 4.2 - screen.width range tests + + + + + + + + +
+
+ + + diff --git a/testing/web-platform/tests/cssom/CSSKeyframesRule.html b/testing/web-platform/tests/cssom/CSSKeyframesRule.html index 9cf387def866..68453498767c 100644 --- a/testing/web-platform/tests/cssom/CSSKeyframesRule.html +++ b/testing/web-platform/tests/cssom/CSSKeyframesRule.html @@ -10,6 +10,7 @@ 0% { top: 0px; } 100% { top: 200px; } } + @keyframes empty {} diff --git a/testing/web-platform/tests/cssom/CSSStyleRule.html b/testing/web-platform/tests/cssom/CSSStyleRule.html index e6b68d7503dd..65d6d5340466 100644 --- a/testing/web-platform/tests/cssom/CSSStyleRule.html +++ b/testing/web-platform/tests/cssom/CSSStyleRule.html @@ -1,24 +1,90 @@ - - - - - - - + - test(function() { - assert_equals(typeof rule.style, "object"); - assert_equals(rule.style.margin, "10px"); - assert_equals(rule.style.padding, "0px"); + + + +
- rule.style.padding = "5px"; - rule.style.border = "1px solid"; + + test(function() { + assert_true(rule instanceof CSSRule); + assert_true(rule instanceof CSSStyleRule); + }, "CSSRule and CSSStyleRule types"); + + test(function() { + assert_equals(rule.STYLE_RULE, 1); + assert_equals(rule.IMPORT_RULE, 3); + assert_equals(rule.MEDIA_RULE, 4); + assert_equals(rule.FONT_FACE_RULE, 5); + assert_equals(rule.PAGE_RULE, 6); + assert_equals(rule.NAMESPACE_RULE, 10); + assert_idl_attribute(rule, "type"); + assert_equals(typeof rule.type, "number"); + }, "Type of CSSRule#type and constant values"); + + test(function() { + assert_true(rule instanceof CSSRule); + assert_idl_attribute(rule, "cssText"); + assert_idl_attribute(rule, "parentRule"); + assert_idl_attribute(rule, "parentStyleSheet"); + }, "Existence of CSSRule attributes"); + + test(function() { + assert_readonly(rule, "type"); + assert_readonly(rule, "parentRule"); + assert_readonly(rule, "parentStyleSheet"); + }, "Writability of CSSRule attributes"); + + test(function() { + assert_equals(rule.type, rule.STYLE_RULE); + assert_equals(typeof rule.cssText, "string"); + assert_equals(rule.cssText, "div { margin: 10px; padding: 0px; }"); + assert_equals(rule.parentRule, null); + assert_true(rule.parentStyleSheet instanceof CSSStyleSheet); + }, "Values of CSSRule attributes"); + + test(function() { + assert_idl_attribute(rule, "selectorText"); + assert_equals(typeof rule.selectorText, "string"); + assert_idl_attribute(rule, "style"); + assert_readonly(rule, "style"); + }, "Existence, writability and type of CSSStyleRule attributes"); + + test(function() { + assert_equals(rule.selectorText, "div"); + assert_true(rule.style instanceof CSSStyleDeclaration); + }, "Values of CSSStyleRule attributes"); + + test(function() { + assert_equals(rule.style.margin, "10px"); + assert_equals(rule.style.padding, "0px"); + + rule.style.padding = "5px"; + rule.style.border = "1px solid"; + + assert_equals(rule.style.padding, "5px"); + assert_equals(rule.style.border, "1px solid"); + }, "Mutability of CSSStyleRule's style attribute"); + + + diff --git a/testing/web-platform/tests/cssom/MediaList.xhtml b/testing/web-platform/tests/cssom/MediaList.xhtml new file mode 100644 index 000000000000..fb1062cba87a --- /dev/null +++ b/testing/web-platform/tests/cssom/MediaList.xhtml @@ -0,0 +1,54 @@ + + + +CSS Test: the MediaList interface + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom/OWNERS b/testing/web-platform/tests/cssom/OWNERS new file mode 100644 index 000000000000..fc98874a3222 --- /dev/null +++ b/testing/web-platform/tests/cssom/OWNERS @@ -0,0 +1,6 @@ +@zcorpan +@dbaron +@plinss +@rune-opera +@lilles +@therealglazou diff --git a/testing/web-platform/tests/cssom/computed-style-001.html b/testing/web-platform/tests/cssom/computed-style-001.html new file mode 100644 index 000000000000..2cdfc9eb8b42 --- /dev/null +++ b/testing/web-platform/tests/cssom/computed-style-001.html @@ -0,0 +1,78 @@ + + + + CSS Test: getComputedStyle + + + + + + + + + + + + + +
+
+ + + diff --git a/testing/web-platform/tests/cssom/css-style-attribute-modifications.html b/testing/web-platform/tests/cssom/css-style-attribute-modifications.html new file mode 100644 index 000000000000..6177c336d76e --- /dev/null +++ b/testing/web-platform/tests/cssom/css-style-attribute-modifications.html @@ -0,0 +1,13 @@ + + + + + +
+ diff --git a/testing/web-platform/tests/cssom/css-style-declaration-modifications.html b/testing/web-platform/tests/cssom/css-style-declaration-modifications.html new file mode 100644 index 000000000000..4db637d7de9e --- /dev/null +++ b/testing/web-platform/tests/cssom/css-style-declaration-modifications.html @@ -0,0 +1,63 @@ + + + + CSS Test: CSSStyleDeclaration Interface + + + + + + + + + +
+
+ + + diff --git a/testing/web-platform/tests/cssom/cssimportrule.html b/testing/web-platform/tests/cssom/cssimportrule.html new file mode 100644 index 000000000000..d4a3250e6807 --- /dev/null +++ b/testing/web-platform/tests/cssom/cssimportrule.html @@ -0,0 +1,88 @@ + + + + CSSOM CSSRule CSSImportRule interface + + + + + + + + + + + + +
+ + + + diff --git a/testing/web-platform/tests/cssom/cssom-cssText-serialize.html b/testing/web-platform/tests/cssom/cssom-cssText-serialize.html new file mode 100644 index 000000000000..27479f026df6 --- /dev/null +++ b/testing/web-platform/tests/cssom/cssom-cssText-serialize.html @@ -0,0 +1,28 @@ + + + + CSSOM Parsing Test: getting cssText must return the result of serializing the CSS declaration blocks. + + + + + + + + + + + +
+
+ + + diff --git a/testing/web-platform/tests/cssom/cssom-cssstyledeclaration-set.html b/testing/web-platform/tests/cssom/cssom-cssstyledeclaration-set.html new file mode 100644 index 000000000000..1fb7ccd32499 --- /dev/null +++ b/testing/web-platform/tests/cssom/cssom-cssstyledeclaration-set.html @@ -0,0 +1,37 @@ + + + + CSSOM: CSSStyleDeclaration on HTMLElement represents inline style changes + + + + + + + + + + + +
+ +
+ + + + + + diff --git a/testing/web-platform/tests/cssom/cssom-fontfacerule-constructors.html b/testing/web-platform/tests/cssom/cssom-fontfacerule-constructors.html new file mode 100644 index 000000000000..c94b63e9b31c --- /dev/null +++ b/testing/web-platform/tests/cssom/cssom-fontfacerule-constructors.html @@ -0,0 +1,63 @@ + + + + CSSOM Parsing Test: @font-face rules toString() as valid interfaces + + + + + + + + + + + +
+ + + + + + + + + + diff --git a/testing/web-platform/tests/cssom/cssom-fontfacerule.html b/testing/web-platform/tests/cssom/cssom-fontfacerule.html new file mode 100644 index 000000000000..06209101c38a --- /dev/null +++ b/testing/web-platform/tests/cssom/cssom-fontfacerule.html @@ -0,0 +1,58 @@ + + + + CSSOM Parsing Test: @font-face rules parsed into CSSOM CSSFontFaceRules + + + + + + + + + + +
+ + + + + + + + + + diff --git a/testing/web-platform/tests/cssom/cssom-setProperty-shorthand.html b/testing/web-platform/tests/cssom/cssom-setProperty-shorthand.html new file mode 100644 index 000000000000..fe2ad4731a1e --- /dev/null +++ b/testing/web-platform/tests/cssom/cssom-setProperty-shorthand.html @@ -0,0 +1,69 @@ + + + + CSSOM: CSSStyleDeclaration (set|remove)PropertyValue sets/removes shorthand properties + + + + + + + + + + + +
+ +
+ + + + diff --git a/testing/web-platform/tests/cssom/cssstyledeclaration-csstext.html b/testing/web-platform/tests/cssom/cssstyledeclaration-csstext.html new file mode 100644 index 000000000000..30d9bd87bde5 --- /dev/null +++ b/testing/web-platform/tests/cssom/cssstyledeclaration-csstext.html @@ -0,0 +1,102 @@ + + + + CSSOM Test: CSSStyleDeclaration.cssText Test + + + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom/cssstyledeclaration-mutability.html b/testing/web-platform/tests/cssom/cssstyledeclaration-mutability.html new file mode 100644 index 000000000000..e7bde1bda639 --- /dev/null +++ b/testing/web-platform/tests/cssom/cssstyledeclaration-mutability.html @@ -0,0 +1,69 @@ + + + + CSSOM: CSSStyleDeclaration is mutable and immutable in various settings + + + + + + + + + + + +
+
+
+ + + + + diff --git a/testing/web-platform/tests/cssom/escape.html b/testing/web-platform/tests/cssom/escape.html new file mode 100644 index 000000000000..115e2c86a9a0 --- /dev/null +++ b/testing/web-platform/tests/cssom/escape.html @@ -0,0 +1,98 @@ + + +CSS#escape + + + +
+ diff --git a/testing/web-platform/tests/cssom/index-001.html b/testing/web-platform/tests/cssom/index-001.html new file mode 100644 index 000000000000..ca53e503297c --- /dev/null +++ b/testing/web-platform/tests/cssom/index-001.html @@ -0,0 +1,28 @@ + + + CSS OM: CSS Values + + + + + + + + +
+
+ + + + diff --git a/testing/web-platform/tests/cssom/index-002.html b/testing/web-platform/tests/cssom/index-002.html new file mode 100644 index 000000000000..29ec3a90a11a --- /dev/null +++ b/testing/web-platform/tests/cssom/index-002.html @@ -0,0 +1,79 @@ + + + CSS OM: CSS Values + + + + + + + + +
+
+ + + diff --git a/testing/web-platform/tests/cssom/index-003.html b/testing/web-platform/tests/cssom/index-003.html new file mode 100644 index 000000000000..354afd3c6c17 --- /dev/null +++ b/testing/web-platform/tests/cssom/index-003.html @@ -0,0 +1,95 @@ + + + CSS OM: CSS Values + + + + + + + + + + + + + + + +
+ + + + diff --git a/testing/web-platform/tests/cssom/inline-style-001.html b/testing/web-platform/tests/cssom/inline-style-001.html new file mode 100644 index 000000000000..3a9eebf7e723 --- /dev/null +++ b/testing/web-platform/tests/cssom/inline-style-001.html @@ -0,0 +1,100 @@ + + + + CSS Test: Inline CSSStyleDeclaration + + + + + + + + + + +
+
+ + + diff --git a/testing/web-platform/tests/cssom/interfaces.html b/testing/web-platform/tests/cssom/interfaces.html new file mode 100644 index 000000000000..cf43e94bc116 --- /dev/null +++ b/testing/web-platform/tests/cssom/interfaces.html @@ -0,0 +1,174 @@ + + +CSSOM automated IDL tests + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom/medialist-interfaces-001.html b/testing/web-platform/tests/cssom/medialist-interfaces-001.html new file mode 100644 index 000000000000..ad95394d5c5e --- /dev/null +++ b/testing/web-platform/tests/cssom/medialist-interfaces-001.html @@ -0,0 +1,110 @@ + + + + CSS Test: CSSOM Media Query List Serialization + + + + + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom/medialist-interfaces-002.html b/testing/web-platform/tests/cssom/medialist-interfaces-002.html new file mode 100644 index 000000000000..d3dfff8e42b1 --- /dev/null +++ b/testing/web-platform/tests/cssom/medialist-interfaces-002.html @@ -0,0 +1,80 @@ + + + + CSS Test: CSSOM MediaList Interfaces + + + + + + + + + + + + + + +
+ + + + + + diff --git a/testing/web-platform/tests/cssom/medialist-interfaces-003.html b/testing/web-platform/tests/cssom/medialist-interfaces-003.html new file mode 100644 index 000000000000..717c39d618fe --- /dev/null +++ b/testing/web-platform/tests/cssom/medialist-interfaces-003.html @@ -0,0 +1,72 @@ + + + + CSS Test: CSSOM Media Query Serialization + + + + + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom/medialist-interfaces-004.html b/testing/web-platform/tests/cssom/medialist-interfaces-004.html new file mode 100644 index 000000000000..2fe6ff915d74 --- /dev/null +++ b/testing/web-platform/tests/cssom/medialist-interfaces-004.html @@ -0,0 +1,72 @@ + + + + CSS Test: CSSOM MediaList Interfaces + + + + + + + + + + + + + +
+ + + + + + diff --git a/testing/web-platform/tests/cssom/selectorSerialize.html b/testing/web-platform/tests/cssom/selectorSerialize.html new file mode 100644 index 000000000000..fc9445ca96a4 --- /dev/null +++ b/testing/web-platform/tests/cssom/selectorSerialize.html @@ -0,0 +1,107 @@ + + + + CSSOM Test: test serialized selector which is only one simple selector in the sequence of simple selectors + + + + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom/serialize-namespaced-type-selectors.html b/testing/web-platform/tests/cssom/serialize-namespaced-type-selectors.html new file mode 100644 index 000000000000..600008c7a9eb --- /dev/null +++ b/testing/web-platform/tests/cssom/serialize-namespaced-type-selectors.html @@ -0,0 +1,257 @@ + + + + CSSOM Test: test serialization of type selectors and namespace prefixes + + + + + + + + + +
+ + + + diff --git a/testing/web-platform/tests/cssom/serialize-variable-reference.html b/testing/web-platform/tests/cssom/serialize-variable-reference.html new file mode 100644 index 000000000000..d714b81518b3 --- /dev/null +++ b/testing/web-platform/tests/cssom/serialize-variable-reference.html @@ -0,0 +1,34 @@ + + +CSSOM - Serialization with variable preserves original serialization. + + +
+
+
+
+ diff --git a/testing/web-platform/tests/cssom/style-sheet-interfaces-001.html b/testing/web-platform/tests/cssom/style-sheet-interfaces-001.html new file mode 100644 index 000000000000..3f4956cb3ad4 --- /dev/null +++ b/testing/web-platform/tests/cssom/style-sheet-interfaces-001.html @@ -0,0 +1,128 @@ + + + + CSS Test: CSSOM StyleSheet Initial Values + + + + + + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom/style-sheet-interfaces-002.html b/testing/web-platform/tests/cssom/style-sheet-interfaces-002.html new file mode 100644 index 000000000000..ad5b1ac58616 --- /dev/null +++ b/testing/web-platform/tests/cssom/style-sheet-interfaces-002.html @@ -0,0 +1,51 @@ + + + + CSS Test: CSSOM StyleSheet Modify Rule List + + + + + + + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom/support/1x1-green.png b/testing/web-platform/tests/cssom/support/1x1-green.png new file mode 100644 index 000000000000..b98ca0ba0a03 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/1x1-green.png differ diff --git a/testing/web-platform/tests/cssom/support/1x1-lime.png b/testing/web-platform/tests/cssom/support/1x1-lime.png new file mode 100644 index 000000000000..cb397fb090e1 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/1x1-lime.png differ diff --git a/testing/web-platform/tests/cssom/support/1x1-maroon.png b/testing/web-platform/tests/cssom/support/1x1-maroon.png new file mode 100644 index 000000000000..3f86b0721955 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/1x1-maroon.png differ diff --git a/testing/web-platform/tests/cssom/support/1x1-navy.png b/testing/web-platform/tests/cssom/support/1x1-navy.png new file mode 100644 index 000000000000..9b9a03955bae Binary files /dev/null and b/testing/web-platform/tests/cssom/support/1x1-navy.png differ diff --git a/testing/web-platform/tests/cssom/support/1x1-red.png b/testing/web-platform/tests/cssom/support/1x1-red.png new file mode 100644 index 000000000000..6bd73ac10187 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/1x1-red.png differ diff --git a/testing/web-platform/tests/cssom/support/1x1-white.png b/testing/web-platform/tests/cssom/support/1x1-white.png new file mode 100644 index 000000000000..dd43faec54ae Binary files /dev/null and b/testing/web-platform/tests/cssom/support/1x1-white.png differ diff --git a/testing/web-platform/tests/cssom/support/60x60-gg-rr.png b/testing/web-platform/tests/cssom/support/60x60-gg-rr.png new file mode 100644 index 000000000000..84f5b2a4f1d1 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/60x60-gg-rr.png differ diff --git a/testing/web-platform/tests/cssom/support/60x60-green.png b/testing/web-platform/tests/cssom/support/60x60-green.png new file mode 100644 index 000000000000..b3c8cf3eb4c8 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/60x60-green.png differ diff --git a/testing/web-platform/tests/cssom/support/60x60-red.png b/testing/web-platform/tests/cssom/support/60x60-red.png new file mode 100644 index 000000000000..823f125b8e4a Binary files /dev/null and b/testing/web-platform/tests/cssom/support/60x60-red.png differ diff --git a/testing/web-platform/tests/cssom/support/README b/testing/web-platform/tests/cssom/support/README new file mode 100644 index 000000000000..2e5f2ad0738c --- /dev/null +++ b/testing/web-platform/tests/cssom/support/README @@ -0,0 +1,28 @@ +CSS Global Support Directory +============================ + +This directory contains common support files (such as images and external +style sheets). These are sync'ed into the support directories of all our +test suites. If you have test-suite-specific support files, please add +them to the appropriate test-suite-specific support/ directory. + +If you add to a support/ directory, please run the tools/supportprop.py +script from the top of the repository to cascade support files into the +lower-level support directories. + +Description of the Common Support File Collection +------------------------------------------------- + +The 1x1-* images are all exactly one pixel. + +The swatch-* images all use 15x15 cells. + +The square-* images all use 15x15 cells with one pixel borders. + +The pattern-* images use cells of various sizes: + + pattern-grg-rgr-grg.png 20x20 + pattern-rgr-grg-rgr.png 20x20 + pattern-tr.png 15x15 + pattern-grg-rrg-rgg.png 15x15 + diff --git a/testing/web-platform/tests/cssom/support/a-green.css b/testing/web-platform/tests/cssom/support/a-green.css new file mode 100644 index 000000000000..b0dbb071d5b0 --- /dev/null +++ b/testing/web-platform/tests/cssom/support/a-green.css @@ -0,0 +1 @@ +.a { color: green; } diff --git a/testing/web-platform/tests/cssom/support/b-green.css b/testing/web-platform/tests/cssom/support/b-green.css new file mode 100644 index 000000000000..a0473f5ca266 --- /dev/null +++ b/testing/web-platform/tests/cssom/support/b-green.css @@ -0,0 +1 @@ +.b { color: green; } \ No newline at end of file diff --git a/testing/web-platform/tests/cssom/support/c-red.css b/testing/web-platform/tests/cssom/support/c-red.css new file mode 100644 index 000000000000..d4ba5c64e954 --- /dev/null +++ b/testing/web-platform/tests/cssom/support/c-red.css @@ -0,0 +1 @@ +.c { color: red; } \ No newline at end of file diff --git a/testing/web-platform/tests/cssom/support/cat.png b/testing/web-platform/tests/cssom/support/cat.png new file mode 100644 index 000000000000..85dd7324815b Binary files /dev/null and b/testing/web-platform/tests/cssom/support/cat.png differ diff --git a/testing/web-platform/tests/cssom/support/import-green.css b/testing/web-platform/tests/cssom/support/import-green.css new file mode 100644 index 000000000000..537104e66336 --- /dev/null +++ b/testing/web-platform/tests/cssom/support/import-green.css @@ -0,0 +1 @@ +.import { color: green; } diff --git a/testing/web-platform/tests/cssom/support/import-red.css b/testing/web-platform/tests/cssom/support/import-red.css new file mode 100644 index 000000000000..9945ef47114c --- /dev/null +++ b/testing/web-platform/tests/cssom/support/import-red.css @@ -0,0 +1 @@ +.import { color: red; } diff --git a/testing/web-platform/tests/cssom/support/pattern-grg-rgr-grg.png b/testing/web-platform/tests/cssom/support/pattern-grg-rgr-grg.png new file mode 100644 index 000000000000..9b88fbd81149 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/pattern-grg-rgr-grg.png differ diff --git a/testing/web-platform/tests/cssom/support/pattern-grg-rrg-rgg.png b/testing/web-platform/tests/cssom/support/pattern-grg-rrg-rgg.png new file mode 100644 index 000000000000..fcf4f3fd7d95 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/pattern-grg-rrg-rgg.png differ diff --git a/testing/web-platform/tests/cssom/support/pattern-rgr-grg-rgr.png b/testing/web-platform/tests/cssom/support/pattern-rgr-grg-rgr.png new file mode 100644 index 000000000000..d454e3a630cd Binary files /dev/null and b/testing/web-platform/tests/cssom/support/pattern-rgr-grg-rgr.png differ diff --git a/testing/web-platform/tests/cssom/support/pattern-tr.png b/testing/web-platform/tests/cssom/support/pattern-tr.png new file mode 100644 index 000000000000..8b4b25364e0f Binary files /dev/null and b/testing/web-platform/tests/cssom/support/pattern-tr.png differ diff --git a/testing/web-platform/tests/cssom/support/ruler-h-50%.png b/testing/web-platform/tests/cssom/support/ruler-h-50%.png new file mode 100644 index 000000000000..cf2eea6b438a Binary files /dev/null and b/testing/web-platform/tests/cssom/support/ruler-h-50%.png differ diff --git a/testing/web-platform/tests/cssom/support/ruler-h-50px.png b/testing/web-platform/tests/cssom/support/ruler-h-50px.png new file mode 100644 index 000000000000..9f46583665ca Binary files /dev/null and b/testing/web-platform/tests/cssom/support/ruler-h-50px.png differ diff --git a/testing/web-platform/tests/cssom/support/ruler-v-100px.png b/testing/web-platform/tests/cssom/support/ruler-v-100px.png new file mode 100644 index 000000000000..a837eca22250 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/ruler-v-100px.png differ diff --git a/testing/web-platform/tests/cssom/support/ruler-v-50px.png b/testing/web-platform/tests/cssom/support/ruler-v-50px.png new file mode 100644 index 000000000000..84141028020b Binary files /dev/null and b/testing/web-platform/tests/cssom/support/ruler-v-50px.png differ diff --git a/testing/web-platform/tests/cssom/support/square-purple.png b/testing/web-platform/tests/cssom/support/square-purple.png new file mode 100644 index 000000000000..0f522d787284 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/square-purple.png differ diff --git a/testing/web-platform/tests/cssom/support/square-teal.png b/testing/web-platform/tests/cssom/support/square-teal.png new file mode 100644 index 000000000000..e567f51b91bb Binary files /dev/null and b/testing/web-platform/tests/cssom/support/square-teal.png differ diff --git a/testing/web-platform/tests/cssom/support/square-white.png b/testing/web-platform/tests/cssom/support/square-white.png new file mode 100644 index 000000000000..5853cbb238cb Binary files /dev/null and b/testing/web-platform/tests/cssom/support/square-white.png differ diff --git a/testing/web-platform/tests/cssom/support/support/README b/testing/web-platform/tests/cssom/support/support/README new file mode 100644 index 000000000000..ea8cb9ef357d --- /dev/null +++ b/testing/web-platform/tests/cssom/support/support/README @@ -0,0 +1,4 @@ +The swatch-green.png file in this directory is really a RED swatch, +and the swatch-red.png file is really a green swatch. + +This directory is used to test relative URIs. \ No newline at end of file diff --git a/testing/web-platform/tests/cssom/support/support/swatch-green.png b/testing/web-platform/tests/cssom/support/support/swatch-green.png new file mode 100644 index 000000000000..1caf25c992aa Binary files /dev/null and b/testing/web-platform/tests/cssom/support/support/swatch-green.png differ diff --git a/testing/web-platform/tests/cssom/support/support/swatch-red.png b/testing/web-platform/tests/cssom/support/support/swatch-red.png new file mode 100644 index 000000000000..0aa79b0c86bd Binary files /dev/null and b/testing/web-platform/tests/cssom/support/support/swatch-red.png differ diff --git a/testing/web-platform/tests/cssom/support/swatch-blue.png b/testing/web-platform/tests/cssom/support/swatch-blue.png new file mode 100644 index 000000000000..bf2759634d45 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/swatch-blue.png differ diff --git a/testing/web-platform/tests/cssom/support/swatch-green.png b/testing/web-platform/tests/cssom/support/swatch-green.png new file mode 100644 index 000000000000..0aa79b0c86bd Binary files /dev/null and b/testing/web-platform/tests/cssom/support/swatch-green.png differ diff --git a/testing/web-platform/tests/cssom/support/swatch-lime.png b/testing/web-platform/tests/cssom/support/swatch-lime.png new file mode 100644 index 000000000000..55fd7fdaedfc Binary files /dev/null and b/testing/web-platform/tests/cssom/support/swatch-lime.png differ diff --git a/testing/web-platform/tests/cssom/support/swatch-orange.png b/testing/web-platform/tests/cssom/support/swatch-orange.png new file mode 100644 index 000000000000..d3cd498b52bd Binary files /dev/null and b/testing/web-platform/tests/cssom/support/swatch-orange.png differ diff --git a/testing/web-platform/tests/cssom/support/swatch-red.png b/testing/web-platform/tests/cssom/support/swatch-red.png new file mode 100644 index 000000000000..1caf25c992aa Binary files /dev/null and b/testing/web-platform/tests/cssom/support/swatch-red.png differ diff --git a/testing/web-platform/tests/cssom/support/swatch-teal.png b/testing/web-platform/tests/cssom/support/swatch-teal.png new file mode 100644 index 000000000000..0293ce89dea5 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/swatch-teal.png differ diff --git a/testing/web-platform/tests/cssom/support/swatch-white.png b/testing/web-platform/tests/cssom/support/swatch-white.png new file mode 100644 index 000000000000..1a7d4323d772 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/swatch-white.png differ diff --git a/testing/web-platform/tests/cssom/support/swatch-yellow.png b/testing/web-platform/tests/cssom/support/swatch-yellow.png new file mode 100644 index 000000000000..1591aa0e2e27 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/swatch-yellow.png differ diff --git a/testing/web-platform/tests/cssom/support/test-bl.png b/testing/web-platform/tests/cssom/support/test-bl.png new file mode 100644 index 000000000000..904e24e996a3 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/test-bl.png differ diff --git a/testing/web-platform/tests/cssom/support/test-br.png b/testing/web-platform/tests/cssom/support/test-br.png new file mode 100644 index 000000000000..f413ff5c1a0f Binary files /dev/null and b/testing/web-platform/tests/cssom/support/test-br.png differ diff --git a/testing/web-platform/tests/cssom/support/test-inner-half-size.png b/testing/web-platform/tests/cssom/support/test-inner-half-size.png new file mode 100644 index 000000000000..e473bf80efc6 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/test-inner-half-size.png differ diff --git a/testing/web-platform/tests/cssom/support/test-outer.png b/testing/web-platform/tests/cssom/support/test-outer.png new file mode 100644 index 000000000000..82eeace7fc0c Binary files /dev/null and b/testing/web-platform/tests/cssom/support/test-outer.png differ diff --git a/testing/web-platform/tests/cssom/support/test-tl.png b/testing/web-platform/tests/cssom/support/test-tl.png new file mode 100644 index 000000000000..f6ac0ef7e8f6 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/test-tl.png differ diff --git a/testing/web-platform/tests/cssom/support/test-tr.png b/testing/web-platform/tests/cssom/support/test-tr.png new file mode 100644 index 000000000000..59843ae54b64 Binary files /dev/null and b/testing/web-platform/tests/cssom/support/test-tr.png differ diff --git a/testing/web-platform/tests/cssom/ttwf-cssom-doc-ext-load-count.html b/testing/web-platform/tests/cssom/ttwf-cssom-doc-ext-load-count.html new file mode 100644 index 000000000000..f507a961032d --- /dev/null +++ b/testing/web-platform/tests/cssom/ttwf-cssom-doc-ext-load-count.html @@ -0,0 +1,68 @@ + + + + CSSOM - Extensions to the Document Interface: StyleSheetList length reflects dynamically loaded and unloaded sheets + + + + + + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom/ttwf-cssom-doc-ext-load-tree-order.html b/testing/web-platform/tests/cssom/ttwf-cssom-doc-ext-load-tree-order.html new file mode 100644 index 000000000000..795ead02f4b2 --- /dev/null +++ b/testing/web-platform/tests/cssom/ttwf-cssom-doc-ext-load-tree-order.html @@ -0,0 +1,56 @@ + + + + CSSOM - Extensions to the Document Interface: Stylesheet header load order + + + + + + + + + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/cssom/ttwf-cssom-document-extension.html b/testing/web-platform/tests/cssom/ttwf-cssom-document-extension.html new file mode 100644 index 000000000000..0c9116dc4b26 --- /dev/null +++ b/testing/web-platform/tests/cssom/ttwf-cssom-document-extension.html @@ -0,0 +1,25 @@ + + + + CSSOM - Extensions to the Document Interface: StyleSheetList length is 0 when no sheets loaded + + + + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/custom-elements/custom-element-registry/per-global.html b/testing/web-platform/tests/custom-elements/custom-element-registry/per-global.html new file mode 100644 index 000000000000..3570dcf811db --- /dev/null +++ b/testing/web-platform/tests/custom-elements/custom-element-registry/per-global.html @@ -0,0 +1,14 @@ + + +Custom Elements: CustomElementRegistry is per global + + + + + + + + diff --git a/testing/web-platform/tests/custom-elements/microtasks-and-constructors.html b/testing/web-platform/tests/custom-elements/microtasks-and-constructors.html new file mode 100644 index 000000000000..78d2cba42c0c --- /dev/null +++ b/testing/web-platform/tests/custom-elements/microtasks-and-constructors.html @@ -0,0 +1,123 @@ + +Custom elements: performing a microtask checkpoint after construction + + + + + + + +
+ + + + + + + + + + + + diff --git a/testing/web-platform/tests/docs/_writing-tests/idlharness.html b/testing/web-platform/tests/docs/_writing-tests/idlharness.html deleted file mode 100644 index f9e18ef41fc0..000000000000 --- a/testing/web-platform/tests/docs/_writing-tests/idlharness.html +++ /dev/null @@ -1,11 +0,0 @@ ---- -layout: page -title: idlharness.js API -order: 6 ---- - - diff --git a/testing/web-platform/tests/resources/docs/idlharness.md b/testing/web-platform/tests/docs/_writing-tests/idlharness.md similarity index 99% rename from testing/web-platform/tests/resources/docs/idlharness.md rename to testing/web-platform/tests/docs/_writing-tests/idlharness.md index 141077b3a72a..76c121953c0e 100644 --- a/testing/web-platform/tests/resources/docs/idlharness.md +++ b/testing/web-platform/tests/docs/_writing-tests/idlharness.md @@ -1,3 +1,9 @@ +--- +layout: page +title: idlharness.js API +order: 6 +--- + ## Introduction ## `idlharness.js` automatically generates browser tests for WebIDL interfaces, using diff --git a/testing/web-platform/tests/docs/_writing-tests/index.md b/testing/web-platform/tests/docs/_writing-tests/index.md index a9ae0d747cf4..6454eb1edac8 100644 --- a/testing/web-platform/tests/docs/_writing-tests/index.md +++ b/testing/web-platform/tests/docs/_writing-tests/index.md @@ -47,7 +47,7 @@ however. ## Submitting Tests -Once you're written tests, please submit them using +Once you've written tests, please submit them using the [typical GitHub Pull Request workflow][submission-process]; please make sure you run the [`lint` script][lint-tool] before opening a pull request! diff --git a/testing/web-platform/tests/docs/_writing-tests/testharness-api.html b/testing/web-platform/tests/docs/_writing-tests/testharness-api.html deleted file mode 100644 index 80af9f0e1f01..000000000000 --- a/testing/web-platform/tests/docs/_writing-tests/testharness-api.html +++ /dev/null @@ -1,11 +0,0 @@ ---- -layout: page -title: testharness.js API -order: 5 ---- - - diff --git a/testing/web-platform/tests/resources/docs/api.md b/testing/web-platform/tests/docs/_writing-tests/testharness-api.md similarity index 93% rename from testing/web-platform/tests/resources/docs/api.md rename to testing/web-platform/tests/docs/_writing-tests/testharness-api.md index d2c0af198f3f..6f90007c879f 100644 --- a/testing/web-platform/tests/resources/docs/api.md +++ b/testing/web-platform/tests/docs/_writing-tests/testharness-api.md @@ -1,3 +1,9 @@ +--- +layout: page +title: testharness.js API +order: 5 +--- + ## Introduction ## testharness.js provides a framework for writing testcases. It is intended to @@ -522,6 +528,63 @@ object. These objects are structured as follows: * result - `{ type: "result", test: Test }` * complete - `{ type: "complete", tests: [Test, ...], status: TestsStatus }` +## Consolidating tests from other documents ## + +`fetch_tests_from_window` will aggregate tests from separate windows or iframes +into the current document as if they were all part of the same test suite. The +document of the second window (or iframe) should include `testharness.js`, but +not `testharnessreport.js`, and use `test`, `async_test`, and `promise_test` in +the usual manner. + +The current test suite will not report completion until +all fetched tests are complete, and errors in the child contexts will result in +failures for the suite in the current context. + +Here's an example that uses `window.open`. + +`child.html`: + +```html + + +Child context test(s) + + + + +
+ + + +``` + +`test.html`: + +```html + + +Primary test context + + + + + +
+ + + +``` + +The argument to `fetch_tests_from_window` is any [`Window`](https://html.spec.whatwg.org/multipage/browsers.html#the-window-object) +capable of accessing the browsing context as either an ancestor or opener. + ## Web Workers ## The `testharness.js` script can be used from within [dedicated workers, shared @@ -603,11 +666,13 @@ asserts that `actual` is strictly true asserts that `actual` is strictly false ### `assert_equals(actual, expected, description)` -asserts that `actual` is the same value as `expected` +asserts that `actual` is the same value as `expected`. +Relies on `===`, distinguishes between `-0` and `+0`, and has a specific check for `NaN`. ### `assert_not_equals(actual, expected, description)` asserts that `actual` is a different value to `expected`. This means that `expected` is a misnomer. +Relies on `===`, distinguishes between `-0` and `+0`, and has a specific check for `NaN`. ### `assert_in_array(actual, expected, description)` asserts that `expected` is an Array, and `actual` is equal to one of the diff --git a/testing/web-platform/tests/docs/_writing-tests/testharness.md b/testing/web-platform/tests/docs/_writing-tests/testharness.md index 3da618492895..84aef5887b61 100644 --- a/testing/web-platform/tests/docs/_writing-tests/testharness.md +++ b/testing/web-platform/tests/docs/_writing-tests/testharness.md @@ -80,6 +80,12 @@ creating a `FileAPI/Blob-constructor.any.js` as follows: This test could then be run from `FileAPI/Blob-constructor.any.worker.html` as well as `FileAPI/Blob-constructor.any.html`. +To check if your test is run from a window or worker you can use the following two methods that will +be made available by the framework: + + self.GLOBAL.isWindow() + self.GLOBAL.isWorker() + ### Including other JavaScript resources in auto-generated boilerplate tests Use `// META: script=link/to/resource.js` at the beginning of the resource. For example, @@ -95,5 +101,5 @@ Use `// META: timeout=long` at the beginning of the resource. [general guidelines]: {{ site.baseurl }}{% link _writing-tests/general-guidelines.md %} -[testharness-api]: {{ site.baseurl }}{% link _writing-tests/testharness-api.html %} -[idlharness]: {{ site.baseurl }}{% link _writing-tests/idlharness.html %} +[testharness-api]: {{ site.baseurl }}{% link _writing-tests/testharness-api.md %} +[idlharness]: {{ site.baseurl }}{% link _writing-tests/idlharness.md %} diff --git a/testing/web-platform/tests/docs/assets/_reftest_graph_example.dot b/testing/web-platform/tests/docs/assets/_reftest_graph_example.dot index d9bdef76d06d..9389f07dc2bd 100644 --- a/testing/web-platform/tests/docs/assets/_reftest_graph_example.dot +++ b/testing/web-platform/tests/docs/assets/_reftest_graph_example.dot @@ -1,3 +1,5 @@ +# Generate with `$ dot -Tsvg -oreftest_graph_example.svg _reftest_graph_example.dot` + digraph reftest_graph_example { "a.html" -> "b.html" [label="=="]; "a.html" -> "c.html" [label="=="]; diff --git a/testing/web-platform/tests/docs/assets/main.scss b/testing/web-platform/tests/docs/assets/main.scss index e2a5d80eefef..4dc5e5c4147b 100644 --- a/testing/web-platform/tests/docs/assets/main.scss +++ b/testing/web-platform/tests/docs/assets/main.scss @@ -93,18 +93,6 @@ nav.home { } -// TTWF include iframes -iframe.ttwf { - border: 1px solid grey; - width: 100%; - max-width: 990px; - height: 75vh; - margin: 0 auto; - display: block; - box-sizing: border-box; -} - - // Site nav (class name is to avoid conflict with minima defined .site-nav) .wpt-site-nav { float: right; diff --git a/testing/web-platform/tests/dom/events/EventListener-invoke-legacy.html b/testing/web-platform/tests/dom/events/EventListener-invoke-legacy.html index a969c8072b44..85a4b0a5fe64 100644 --- a/testing/web-platform/tests/dom/events/EventListener-invoke-legacy.html +++ b/testing/web-platform/tests/dom/events/EventListener-invoke-legacy.html @@ -43,7 +43,7 @@ function runLegacyEventTest(type, legacyType, ctor, setup) { assert_unreached("listener of " + legacyType + " should not be invoked again"); return; } - elem.dispatchEvent(new ctor(type)); + elem.dispatchEvent(new window[ctor](type)); t.done(); })); setup(elem); @@ -65,8 +65,8 @@ function setupAnimation(elem) { elem.style.animation = 'test 30ms 2'; } -runLegacyEventTest('transitionend', 'webkitTransitionEnd', TransitionEvent, setupTransition); -runLegacyEventTest('animationend', 'webkitAnimationEnd', AnimationEvent, setupAnimation); -runLegacyEventTest('animationiteration', 'webkitAnimationIteration', AnimationEvent, setupAnimation); -runLegacyEventTest('animationstart', 'webkitAnimationStart', AnimationEvent, setupAnimation); +runLegacyEventTest('transitionend', 'webkitTransitionEnd', "TransitionEvent", setupTransition); +runLegacyEventTest('animationend', 'webkitAnimationEnd', "AnimationEvent", setupAnimation); +runLegacyEventTest('animationiteration', 'webkitAnimationIteration', "AnimationEvent", setupAnimation); +runLegacyEventTest('animationstart', 'webkitAnimationStart', "AnimationEvent", setupAnimation); diff --git a/testing/web-platform/tests/dom/interfaces.html b/testing/web-platform/tests/dom/interfaces.html index a8d827bde98a..e6b12e3cbd4c 100644 --- a/testing/web-platform/tests/dom/interfaces.html +++ b/testing/web-platform/tests/dom/interfaces.html @@ -8,571 +8,18 @@

DOM IDL tests

- - diff --git a/testing/web-platform/tests/dom/nodes/Document-createEvent.html b/testing/web-platform/tests/dom/nodes/Document-createEvent.html index 29657e05b886..93b5ec4efef7 100644 --- a/testing/web-platform/tests/dom/nodes/Document-createEvent.html +++ b/testing/web-platform/tests/dom/nodes/Document-createEvent.html @@ -81,7 +81,6 @@ var someNonCreateableEvents = [ "ClipboardEvent", "CommandEvent", "DataContainerEvent", - "DeviceLightEvent", "ExtendableEvent", "ExtendableMessageEvent", "FetchEvent", diff --git a/testing/web-platform/tests/dom/nodes/Element-classlist.html b/testing/web-platform/tests/dom/nodes/Element-classlist.html index 5beee0942064..ece938e6f904 100644 --- a/testing/web-platform/tests/dom/nodes/Element-classlist.html +++ b/testing/web-platform/tests/dom/nodes/Element-classlist.html @@ -424,7 +424,7 @@ function testClassList(e, desc) { // Implementations agree on the first one here, so I test it, but disagree on // the second, so no test until the spec decides what to say. checkReplace("a b c", "c", "a", "a b"); - //checkReplace("c b a", "c", "a", ???); + checkReplace("c b a", "c", "a", "a b"); checkReplace("a b a", "a", "c", "c b"); checkReplace("a b a", "b", "c", "a c"); checkReplace(" a a b", "a", "c", "c b"); diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-xht.xht b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-xht.xht index 7a673202b95a..3915aee42cff 100644 --- a/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-xht.xht +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-xht.xht @@ -14,12 +14,18 @@ + + + + + +

This test examines the ARIA properties for doc-abstract.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-acknowledgments-manual.html b/testing/web-platform/tests/dpub-aam/doc-acknowledgments-manual.html new file mode 100644 index 000000000000..763cd3255098 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-acknowledgments-manual.html @@ -0,0 +1,127 @@ + + + + doc-acknowledgments + + + + + + + + +

This test examines the ARIA properties for doc-acknowledgments.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-afterword-manual.html b/testing/web-platform/tests/dpub-aam/doc-afterword-manual.html new file mode 100644 index 000000000000..7b9d16cc254f --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-afterword-manual.html @@ -0,0 +1,127 @@ + + + + doc-afterword + + + + + + + + +

This test examines the ARIA properties for doc-afterword.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-appendix-manual.html b/testing/web-platform/tests/dpub-aam/doc-appendix-manual.html new file mode 100644 index 000000000000..943a7c256480 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-appendix-manual.html @@ -0,0 +1,127 @@ + + + + doc-appendix + + + + + + + + +

This test examines the ARIA properties for doc-appendix.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-backlink-manual.html b/testing/web-platform/tests/dpub-aam/doc-backlink-manual.html new file mode 100644 index 000000000000..bc5e6cb15784 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-backlink-manual.html @@ -0,0 +1,161 @@ + + + + doc-backlink + + + + + + + + +

This test examines the ARIA properties for doc-backlink.

+
+
child 1
+
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-biblioentry-manual.html b/testing/web-platform/tests/dpub-aam/doc-biblioentry-manual.html new file mode 100644 index 000000000000..80924875fd90 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-biblioentry-manual.html @@ -0,0 +1,123 @@ + + + + doc-biblioentry + + + + + + + + +

This test examines the ARIA properties for doc-biblioentry.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-bibliography-manual.html b/testing/web-platform/tests/dpub-aam/doc-bibliography-manual.html new file mode 100644 index 000000000000..25d9e7556472 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-bibliography-manual.html @@ -0,0 +1,127 @@ + + + + doc-bibliography + + + + + + + + +

This test examines the ARIA properties for doc-bibliography.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-biblioref-manual.html b/testing/web-platform/tests/dpub-aam/doc-biblioref-manual.html new file mode 100644 index 000000000000..649d13055385 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-biblioref-manual.html @@ -0,0 +1,161 @@ + + + + doc-biblioref + + + + + + + + +

This test examines the ARIA properties for doc-biblioref.

+
+
child 1
+
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-chapter-manual.html b/testing/web-platform/tests/dpub-aam/doc-chapter-manual.html new file mode 100644 index 000000000000..1f8eda3d371f --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-chapter-manual.html @@ -0,0 +1,127 @@ + + + + doc-chapter + + + + + + + + +

This test examines the ARIA properties for doc-chapter.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-colophon-manual.html b/testing/web-platform/tests/dpub-aam/doc-colophon-manual.html new file mode 100644 index 000000000000..17a349048ff4 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-colophon-manual.html @@ -0,0 +1,115 @@ + + + + doc-colophon + + + + + + + + +

This test examines the ARIA properties for doc-colophon.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-conclusion-manual.html b/testing/web-platform/tests/dpub-aam/doc-conclusion-manual.html new file mode 100644 index 000000000000..e14d1e4cf9bf --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-conclusion-manual.html @@ -0,0 +1,127 @@ + + + + doc-conclusion + + + + + + + + +

This test examines the ARIA properties for doc-conclusion.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-cover-manual.html b/testing/web-platform/tests/dpub-aam/doc-cover-manual.html new file mode 100644 index 000000000000..3987abe12065 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-cover-manual.html @@ -0,0 +1,111 @@ + + + + doc-cover + + + + + + + + +

This test examines the ARIA properties for doc-cover.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-credit-manual.html b/testing/web-platform/tests/dpub-aam/doc-credit-manual.html new file mode 100644 index 000000000000..77ef255a9b06 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-credit-manual.html @@ -0,0 +1,115 @@ + + + + doc-credit + + + + + + + + +

This test examines the ARIA properties for doc-credit.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-credits-manual.html b/testing/web-platform/tests/dpub-aam/doc-credits-manual.html new file mode 100644 index 000000000000..fe3aec29b98c --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-credits-manual.html @@ -0,0 +1,127 @@ + + + + doc-credits + + + + + + + + +

This test examines the ARIA properties for doc-credits.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-dedication-manual.html b/testing/web-platform/tests/dpub-aam/doc-dedication-manual.html new file mode 100644 index 000000000000..fa44872248aa --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-dedication-manual.html @@ -0,0 +1,115 @@ + + + + doc-dedication + + + + + + + + +

This test examines the ARIA properties for doc-dedication.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-endnote-manual.html b/testing/web-platform/tests/dpub-aam/doc-endnote-manual.html new file mode 100644 index 000000000000..faae9bd2735f --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-endnote-manual.html @@ -0,0 +1,123 @@ + + + + doc-endnote + + + + + + + + +

This test examines the ARIA properties for doc-endnote.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-endnotes-manual.html b/testing/web-platform/tests/dpub-aam/doc-endnotes-manual.html new file mode 100644 index 000000000000..06e7a597977c --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-endnotes-manual.html @@ -0,0 +1,127 @@ + + + + doc-endnotes + + + + + + + + +

This test examines the ARIA properties for doc-endnotes.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-epigraph-manual.html b/testing/web-platform/tests/dpub-aam/doc-epigraph-manual.html new file mode 100644 index 000000000000..a57f8a10acd0 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-epigraph-manual.html @@ -0,0 +1,115 @@ + + + + doc-epigraph + + + + + + + + +

This test examines the ARIA properties for doc-epigraph.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-epilogue-manual.html b/testing/web-platform/tests/dpub-aam/doc-epilogue-manual.html new file mode 100644 index 000000000000..2a99c45d8cd2 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-epilogue-manual.html @@ -0,0 +1,127 @@ + + + + doc-epilogue + + + + + + + + +

This test examines the ARIA properties for doc-epilogue.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-errata-manual.html b/testing/web-platform/tests/dpub-aam/doc-errata-manual.html new file mode 100644 index 000000000000..4d46af3d853a --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-errata-manual.html @@ -0,0 +1,127 @@ + + + + doc-errata + + + + + + + + +

This test examines the ARIA properties for doc-errata.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-example-manual.html b/testing/web-platform/tests/dpub-aam/doc-example-manual.html new file mode 100644 index 000000000000..72926aaf69ad --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-example-manual.html @@ -0,0 +1,115 @@ + + + + doc-example + + + + + + + + +

This test examines the ARIA properties for doc-example.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-footnote-manual.html b/testing/web-platform/tests/dpub-aam/doc-footnote-manual.html new file mode 100644 index 000000000000..0a2602216c05 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-footnote-manual.html @@ -0,0 +1,115 @@ + + + + doc-footnote + + + + + + + + +

This test examines the ARIA properties for doc-footnote.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-foreword-manual.html b/testing/web-platform/tests/dpub-aam/doc-foreword-manual.html new file mode 100644 index 000000000000..3854cfbb7679 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-foreword-manual.html @@ -0,0 +1,127 @@ + + + + doc-foreword + + + + + + + + +

This test examines the ARIA properties for doc-foreword.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-glossary-manual.html b/testing/web-platform/tests/dpub-aam/doc-glossary-manual.html new file mode 100644 index 000000000000..6d761b49391a --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-glossary-manual.html @@ -0,0 +1,127 @@ + + + + doc-glossary + + + + + + + + +

This test examines the ARIA properties for doc-glossary.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-glossref-manual.html b/testing/web-platform/tests/dpub-aam/doc-glossref-manual.html new file mode 100644 index 000000000000..24007145d836 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-glossref-manual.html @@ -0,0 +1,161 @@ + + + + doc-glossref + + + + + + + + +

This test examines the ARIA properties for doc-glossref.

+
+
child 1
+
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-index-manual.html b/testing/web-platform/tests/dpub-aam/doc-index-manual.html new file mode 100644 index 000000000000..c22d6a9f9e26 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-index-manual.html @@ -0,0 +1,127 @@ + + + + doc-index + + + + + + + + +

This test examines the ARIA properties for doc-index.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-introduction-manual.html b/testing/web-platform/tests/dpub-aam/doc-introduction-manual.html new file mode 100644 index 000000000000..7fb3fb7f061a --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-introduction-manual.html @@ -0,0 +1,127 @@ + + + + doc-introduction + + + + + + + + +

This test examines the ARIA properties for doc-introduction.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-noteref-manual.html b/testing/web-platform/tests/dpub-aam/doc-noteref-manual.html new file mode 100644 index 000000000000..2c47e833dd03 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-noteref-manual.html @@ -0,0 +1,161 @@ + + + + doc-noteref + + + + + + + + +

This test examines the ARIA properties for doc-noteref.

+
+
child 1
+
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-notice-manual.html b/testing/web-platform/tests/dpub-aam/doc-notice-manual.html new file mode 100644 index 000000000000..48c8edffa037 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-notice-manual.html @@ -0,0 +1,115 @@ + + + + doc-notice + + + + + + + + +

This test examines the ARIA properties for doc-notice.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-pagebreak-manual.html b/testing/web-platform/tests/dpub-aam/doc-pagebreak-manual.html new file mode 100644 index 000000000000..cfd7c8fdf73b --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-pagebreak-manual.html @@ -0,0 +1,117 @@ + + + + doc-pagebreak + + + + + + + + +

This test examines the ARIA properties for doc-pagebreak.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-pagelist-manual.html b/testing/web-platform/tests/dpub-aam/doc-pagelist-manual.html new file mode 100644 index 000000000000..7bcbdd21cdc4 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-pagelist-manual.html @@ -0,0 +1,127 @@ + + + + doc-pagelist + + + + + + + + +

This test examines the ARIA properties for doc-pagelist.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-part-manual.html b/testing/web-platform/tests/dpub-aam/doc-part-manual.html new file mode 100644 index 000000000000..35cc4312933f --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-part-manual.html @@ -0,0 +1,127 @@ + + + + doc-part + + + + + + + + +

This test examines the ARIA properties for doc-part.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-preface-manual.html b/testing/web-platform/tests/dpub-aam/doc-preface-manual.html new file mode 100644 index 000000000000..9e79c5743d0b --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-preface-manual.html @@ -0,0 +1,127 @@ + + + + doc-preface + + + + + + + + +

This test examines the ARIA properties for doc-preface.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-prologue-manual.html b/testing/web-platform/tests/dpub-aam/doc-prologue-manual.html new file mode 100644 index 000000000000..c5887f556256 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-prologue-manual.html @@ -0,0 +1,127 @@ + + + + doc-prologue + + + + + + + + +

This test examines the ARIA properties for doc-prologue.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-pullquote-manual.html b/testing/web-platform/tests/dpub-aam/doc-pullquote-manual.html new file mode 100644 index 000000000000..ab454dad255e --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-pullquote-manual.html @@ -0,0 +1,115 @@ + + + + doc-pullquote + + + + + + + + +

This test examines the ARIA properties for doc-pullquote.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-qna-manual.html b/testing/web-platform/tests/dpub-aam/doc-qna-manual.html new file mode 100644 index 000000000000..b8e2e5546112 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-qna-manual.html @@ -0,0 +1,115 @@ + + + + doc-qna + + + + + + + + +

This test examines the ARIA properties for doc-qna.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-subtitle-manual.html b/testing/web-platform/tests/dpub-aam/doc-subtitle-manual.html new file mode 100644 index 000000000000..9c43c7488536 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-subtitle-manual.html @@ -0,0 +1,115 @@ + + + + doc-subtitle + + + + + + + + +

This test examines the ARIA properties for doc-subtitle.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-tip-manual.html b/testing/web-platform/tests/dpub-aam/doc-tip-manual.html new file mode 100644 index 000000000000..6367a02c150d --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-tip-manual.html @@ -0,0 +1,115 @@ + + + + doc-tip + + + + + + + + +

This test examines the ARIA properties for doc-tip.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/dpub-aam/doc-toc-manual.html b/testing/web-platform/tests/dpub-aam/doc-toc-manual.html new file mode 100644 index 000000000000..3a53c85d3a00 --- /dev/null +++ b/testing/web-platform/tests/dpub-aam/doc-toc-manual.html @@ -0,0 +1,127 @@ + + + + doc-toc + + + + + + + + +

This test examines the ARIA properties for doc-toc.

+
Text
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/editing/data/README.md b/testing/web-platform/tests/editing/data/README.md new file mode 100644 index 000000000000..606c67182ca3 --- /dev/null +++ b/testing/web-platform/tests/editing/data/README.md @@ -0,0 +1,166 @@ +# editing/data/*.js Format # + +In the interests of keeping file size down, the format of these +(machine-generated) data files is relatively concise. Unfortunately, this +means they can appear slightly cryptic to the untrained eye: + + ["foo[bar]baz", + [["stylewithcss","false"],["bold",""]], + "foo[bar]baz", + [true,true], + {"stylewithcss":[false,true,"",false,false,""],"bold":[false,false,"",false,true,""]}], + +But never fear! It's not actually so complicated (assuming you understand the +relevant APIs to begin with). Each line has the following format, which we +will explain in due course: + + ["initial HTML", + [["command1", "arg1"], ["command2", "arg2"]], + "expected HTML", + [expected retval from command1, expected retval from command2], + {"command1":[expected original/final indeterm/state/value 1], + "command2":[expected original/final indeterm/state/value 2]}], + +## Line 1: Initial HTML ## + + -> ["foo[bar]baz", + [["stylewithcss","false"],["bold",""]], + "foo[bar]baz", + [true,true], + {"stylewithcss":[false,true,"",false,false,""],"bold":[false,false,"",false,true,""]}], + +When testing, first a contenteditable div's innerHTML is set to the value given +here. Then the characters []{} are located and removed, and the selection is +set to where they used to be, as follows: + + * [ and ] indicate the left or right endpoint of the selection, if it's in + a text node. + * { and } indicate the left or right endpoint of the selection, if it's not + in a text node. + +Thus `[foo]` means the selection start and end are (foo, 0) and (foo, +3), while `{foo}` means they're (``, 0) and (``, 1). +`[foo}` and `{foo]` are also possible. There is no way to +describe backwards selections (i.e., distinguish anchor/focus). + +In cases where you want the selection in a place where it's not possible to +place text, like `{}
`, another format +exists using data-start and data-end attributes. It's only used in a few +tests, so it is not documented here. + +## Line 2: commands ## + + ["foo[bar]baz", + -> [["stylewithcss","false"],["bold",""]], + "foo[bar]baz", + [true,true], + {"stylewithcss":[false,true,"",false,false,""],"bold":[false,false,"",false,true,""]}], + +After the innerHTML of the editing host is filled in, the commands given here +are run in order, like this: + + document.execCommand("stylewithcss", false, "false"); + document.execCommand("bold", false, ""); + +Most tests have only one command run. The exceptions are: + + 1. styleWithCSS. Tests that involve formatting elements or styles are run + twice, once with styleWithCSS on and once with it off. + 2. defaultParagraphSeparator. Tests that involve `

`s or `

`s are run + twice, once with defaultParagraphSeparator set to "div" and once "p". + 3. multitest.js tests interactions between different commands, so it contains + arbitrary combinations of commands. + +## Line 3: expected HTML ## + + ["foo[bar]baz", + [["stylewithcss","false"],["bold",""]], + -> "foo[bar]baz", + [true,true], + {"stylewithcss":[false,true,"",false,false,""],"bold":[false,false,"",false,true,""]}], + +After the commands are run, we check that the innerHTML of the editing host +matches the expected HTML provided here. As on line 1, the characters []{} +(and data-start/data-end attributes) have special meaning and are not really +expected to be in the HTML. However, on this line they don't affect the test's +processing -- there are no tests of what the final selection is. + +## Line 4: expected return values ## + + ["foo[bar]baz", + [["stylewithcss","false"],["bold",""]], + "foo[bar]baz", + -> [true,true], + {"stylewithcss":[false,true,"",false,false,""],"bold":[false,false,"",false,true,""]}], + +execCommand() returns a boolean: true if all went well, false if not (e.g., +invalid value). This line says what value each execCommand() call from line 2 +was supposed to return. Usually they'll all be true, but for tests of +error-handling they'll sometimes be false. + +## Line 5: expected indeterm/state/value ## + + ["foo[bar]baz", + [["stylewithcss","false"],["bold",""]], + "foo[bar]baz", + [true,true], + -> {"stylewithcss":[false,true,"",false,false,""],"bold":[false,false,"",false,true,""]}], + +For each command that we're running, we check queryCommandIndeterm(), +queryCommandState(), and queryCommandValue() before we begin running any of our +commands, and again after we've finished the last one. (We don't run these +checks in between commands.) For each command, this line gives an array of six +expected values, in order: + + 1. Indeterm before + 2. State before + 3. Value before + 4. Indeterm after + 5. State after + 6. Value after + +You can remember this by keeping in mind that the three "before" values come +before the three "after" values, and each set of three values is in +alphabetical order (indeterm/state/value). + +## Analysis of a real-world example ## + +Let's look back at the example we started with and see what it means: + + ["foo[bar]baz", + [["stylewithcss","false"],["bold",""]], + "foo[bar]baz", + [true,true], + {"stylewithcss":[false,true,"",false,false,""],"bold":[false,false,"",false,true,""]}], + +Line 1: Set the innerHTML of our editing host to `foobarbaz`, and set the +selection's start and end inside the resulting text node, selecting the letters +"bar". (We actually first set the innerHTML to `foo[bar]baz` and remove the +brackets afterwards.) + +Line 2: Execute the commands: + + document.execCommand("stylewithcss", false, "false"); + document.execCommand("bold", false, ""); + +Before doing this, we record the indeterm/state/value for both "stylewithcss" +and "bold", and afterwards, we record them again. We also record the return +value of both execCommand() calls. + +Line 3: Our new innerHTML should be `foobarbaz`. The [ and ] say where +we would theoretically want the selection to be, but no actual test is run. + +Line 4: Both execCommands we ran should return true. + +Line 5: We expect the indeterm for styleWithCSS to be false both before and +after, and the value to be "" before and after -- since they always are for +this command. The state for styleWithCSS should be true beforehand, because +that's the way the previous test left it -- the testing framework doesn't clear +these settings in between tests. (Thus the first test of styleWithCSS on the +page also tests the default value of the state.) But we set it to false, so +after the tests it should be false. + +We expect the indeterm for bold to be false both before and after, because +before nothing is bold, and after everything is bold. Value should be "" +before and after, because it always is for bold. The state before should be +false, but after should have changed to true. diff --git a/testing/web-platform/tests/editing/data/backcolor.js b/testing/web-platform/tests/editing/data/backcolor.js index be8bda01af29..4d6e77e21d1b 100644 --- a/testing/web-platform/tests/editing/data/backcolor.js +++ b/testing/web-platform/tests/editing/data/backcolor.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["backcolor","#00FFFF"]], diff --git a/testing/web-platform/tests/editing/data/bold.js b/testing/web-platform/tests/editing/data/bold.js index e9f04726be54..61ccf4f8adfb 100644 --- a/testing/web-platform/tests/editing/data/bold.js +++ b/testing/web-platform/tests/editing/data/bold.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["bold",""]], diff --git a/testing/web-platform/tests/editing/data/createlink.js b/testing/web-platform/tests/editing/data/createlink.js index 275fcbd59959..87e59d281e5a 100644 --- a/testing/web-platform/tests/editing/data/createlink.js +++ b/testing/web-platform/tests/editing/data/createlink.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["createlink","http://www.google.com/"]], diff --git a/testing/web-platform/tests/editing/data/delete.js b/testing/web-platform/tests/editing/data/delete.js index bfea92831421..8a2bd7075314 100644 --- a/testing/web-platform/tests/editing/data/delete.js +++ b/testing/web-platform/tests/editing/data/delete.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["delete",""]], diff --git a/testing/web-platform/tests/editing/data/fontname.js b/testing/web-platform/tests/editing/data/fontname.js index 9f0cebd3e683..f4193a9bce72 100644 --- a/testing/web-platform/tests/editing/data/fontname.js +++ b/testing/web-platform/tests/editing/data/fontname.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["fontname","sans-serif"]], diff --git a/testing/web-platform/tests/editing/data/fontsize.js b/testing/web-platform/tests/editing/data/fontsize.js index 8ab0f24c278f..eb741b4f331d 100644 --- a/testing/web-platform/tests/editing/data/fontsize.js +++ b/testing/web-platform/tests/editing/data/fontsize.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["fontsize","4"]], diff --git a/testing/web-platform/tests/editing/data/forecolor.js b/testing/web-platform/tests/editing/data/forecolor.js index 5278f0953baf..57deb5b434ae 100644 --- a/testing/web-platform/tests/editing/data/forecolor.js +++ b/testing/web-platform/tests/editing/data/forecolor.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["forecolor","#0000FF"]], diff --git a/testing/web-platform/tests/editing/data/formatblock.js b/testing/web-platform/tests/editing/data/formatblock.js index 39c20e2680af..e69c8bb89c75 100644 --- a/testing/web-platform/tests/editing/data/formatblock.js +++ b/testing/web-platform/tests/editing/data/formatblock.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar

extra", [["defaultparagraphseparator","div"],["formatblock","

"]], diff --git a/testing/web-platform/tests/editing/data/forwarddelete.js b/testing/web-platform/tests/editing/data/forwarddelete.js index 66cf6cf33780..eb8d14ee0e59 100644 --- a/testing/web-platform/tests/editing/data/forwarddelete.js +++ b/testing/web-platform/tests/editing/data/forwarddelete.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]", [["forwarddelete",""]], diff --git a/testing/web-platform/tests/editing/data/hilitecolor.js b/testing/web-platform/tests/editing/data/hilitecolor.js index e1f561d8fa4c..257061963218 100644 --- a/testing/web-platform/tests/editing/data/hilitecolor.js +++ b/testing/web-platform/tests/editing/data/hilitecolor.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["hilitecolor","#00FFFF"]], diff --git a/testing/web-platform/tests/editing/data/indent.js b/testing/web-platform/tests/editing/data/indent.js index 283271630601..6d18fc35b730 100644 --- a/testing/web-platform/tests/editing/data/indent.js +++ b/testing/web-platform/tests/editing/data/indent.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar

extra", [["indent",""]], diff --git a/testing/web-platform/tests/editing/data/inserthorizontalrule.js b/testing/web-platform/tests/editing/data/inserthorizontalrule.js index 9d12d6809be1..998822789f15 100644 --- a/testing/web-platform/tests/editing/data/inserthorizontalrule.js +++ b/testing/web-platform/tests/editing/data/inserthorizontalrule.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["inserthorizontalrule",""]], diff --git a/testing/web-platform/tests/editing/data/inserthtml.js b/testing/web-platform/tests/editing/data/inserthtml.js index 78581bf533d7..0c6cff86c604 100644 --- a/testing/web-platform/tests/editing/data/inserthtml.js +++ b/testing/web-platform/tests/editing/data/inserthtml.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["stylewithcss","true"],["inserthtml","abcd"]], diff --git a/testing/web-platform/tests/editing/data/insertimage.js b/testing/web-platform/tests/editing/data/insertimage.js index d1874e652121..c2e26cb56d46 100644 --- a/testing/web-platform/tests/editing/data/insertimage.js +++ b/testing/web-platform/tests/editing/data/insertimage.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["insertimage","/img/lion.svg"]], diff --git a/testing/web-platform/tests/editing/data/insertlinebreak.js b/testing/web-platform/tests/editing/data/insertlinebreak.js index 2793cbb1c5f6..a37483eddb0a 100644 --- a/testing/web-platform/tests/editing/data/insertlinebreak.js +++ b/testing/web-platform/tests/editing/data/insertlinebreak.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[bar]baz", [["insertlinebreak",""]], diff --git a/testing/web-platform/tests/editing/data/insertorderedlist.js b/testing/web-platform/tests/editing/data/insertorderedlist.js index 76bda2d4babd..31259552cd17 100644 --- a/testing/web-platform/tests/editing/data/insertorderedlist.js +++ b/testing/web-platform/tests/editing/data/insertorderedlist.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["insertorderedlist",""]], diff --git a/testing/web-platform/tests/editing/data/insertparagraph.js b/testing/web-platform/tests/editing/data/insertparagraph.js index a9a3be4e7033..432f0e0de352 100644 --- a/testing/web-platform/tests/editing/data/insertparagraph.js +++ b/testing/web-platform/tests/editing/data/insertparagraph.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[bar]baz", [["defaultparagraphseparator","div"],["insertparagraph",""]], diff --git a/testing/web-platform/tests/editing/data/inserttext.js b/testing/web-platform/tests/editing/data/inserttext.js index 8d4e31c17a2b..4012510fcb63 100644 --- a/testing/web-platform/tests/editing/data/inserttext.js +++ b/testing/web-platform/tests/editing/data/inserttext.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[bar]baz", [["inserttext","a"]], diff --git a/testing/web-platform/tests/editing/data/insertunorderedlist.js b/testing/web-platform/tests/editing/data/insertunorderedlist.js index ad4a7236faed..c7b6bf52e338 100644 --- a/testing/web-platform/tests/editing/data/insertunorderedlist.js +++ b/testing/web-platform/tests/editing/data/insertunorderedlist.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["insertunorderedlist",""]], diff --git a/testing/web-platform/tests/editing/data/italic.js b/testing/web-platform/tests/editing/data/italic.js index 96ee0d9565c2..b7bd63f95b99 100644 --- a/testing/web-platform/tests/editing/data/italic.js +++ b/testing/web-platform/tests/editing/data/italic.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["italic",""]], diff --git a/testing/web-platform/tests/editing/data/justifycenter.js b/testing/web-platform/tests/editing/data/justifycenter.js index 76491ee44c52..8e4c80b46655 100644 --- a/testing/web-platform/tests/editing/data/justifycenter.js +++ b/testing/web-platform/tests/editing/data/justifycenter.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar

extra", [["stylewithcss","true"],["defaultparagraphseparator","div"],["justifycenter",""]], diff --git a/testing/web-platform/tests/editing/data/justifyfull.js b/testing/web-platform/tests/editing/data/justifyfull.js index c8beca840cfa..602ae11893ab 100644 --- a/testing/web-platform/tests/editing/data/justifyfull.js +++ b/testing/web-platform/tests/editing/data/justifyfull.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar

extra", [["stylewithcss","true"],["defaultparagraphseparator","div"],["justifyfull",""]], diff --git a/testing/web-platform/tests/editing/data/justifyleft.js b/testing/web-platform/tests/editing/data/justifyleft.js index c08033744beb..e0a48e3e20f2 100644 --- a/testing/web-platform/tests/editing/data/justifyleft.js +++ b/testing/web-platform/tests/editing/data/justifyleft.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar

extra", [["justifyleft",""]], diff --git a/testing/web-platform/tests/editing/data/justifyright.js b/testing/web-platform/tests/editing/data/justifyright.js index 595f7376eee1..c07f5d0bdd6b 100644 --- a/testing/web-platform/tests/editing/data/justifyright.js +++ b/testing/web-platform/tests/editing/data/justifyright.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar

extra", [["stylewithcss","true"],["defaultparagraphseparator","div"],["justifyright",""]], diff --git a/testing/web-platform/tests/editing/data/misc.js b/testing/web-platform/tests/editing/data/misc.js index a3477cf75d83..83c02ab769f5 100644 --- a/testing/web-platform/tests/editing/data/misc.js +++ b/testing/web-platform/tests/editing/data/misc.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[bar]baz", [["defaultparagraphseparator",""]], diff --git a/testing/web-platform/tests/editing/data/multitest.js b/testing/web-platform/tests/editing/data/multitest.js index 040e41eb2c60..338b9c905d66 100644 --- a/testing/web-platform/tests/editing/data/multitest.js +++ b/testing/web-platform/tests/editing/data/multitest.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["bold",""],["inserttext","a"]], diff --git a/testing/web-platform/tests/editing/data/outdent.js b/testing/web-platform/tests/editing/data/outdent.js index 18d48d0cb988..271824bee51e 100644 --- a/testing/web-platform/tests/editing/data/outdent.js +++ b/testing/web-platform/tests/editing/data/outdent.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["

foo[bar]

baz

extra", [["outdent",""]], diff --git a/testing/web-platform/tests/editing/data/removeformat.js b/testing/web-platform/tests/editing/data/removeformat.js index 0ff0a76ce966..cfc355d88541 100644 --- a/testing/web-platform/tests/editing/data/removeformat.js +++ b/testing/web-platform/tests/editing/data/removeformat.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["removeformat",""]], diff --git a/testing/web-platform/tests/editing/data/strikethrough.js b/testing/web-platform/tests/editing/data/strikethrough.js index 97170708df32..9817f4f0f851 100644 --- a/testing/web-platform/tests/editing/data/strikethrough.js +++ b/testing/web-platform/tests/editing/data/strikethrough.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["strikethrough",""]], diff --git a/testing/web-platform/tests/editing/data/subscript.js b/testing/web-platform/tests/editing/data/subscript.js index af6ae8965408..212981438b64 100644 --- a/testing/web-platform/tests/editing/data/subscript.js +++ b/testing/web-platform/tests/editing/data/subscript.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["subscript",""]], diff --git a/testing/web-platform/tests/editing/data/superscript.js b/testing/web-platform/tests/editing/data/superscript.js index 337c70d30e7b..e06fe6f4b175 100644 --- a/testing/web-platform/tests/editing/data/superscript.js +++ b/testing/web-platform/tests/editing/data/superscript.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["superscript",""]], diff --git a/testing/web-platform/tests/editing/data/underline.js b/testing/web-platform/tests/editing/data/underline.js index 3414214386e0..4dac89f66e1c 100644 --- a/testing/web-platform/tests/editing/data/underline.js +++ b/testing/web-platform/tests/editing/data/underline.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["underline",""]], diff --git a/testing/web-platform/tests/editing/data/unlink.js b/testing/web-platform/tests/editing/data/unlink.js index 8e5ea4489abf..84f8600f1bc2 100644 --- a/testing/web-platform/tests/editing/data/unlink.js +++ b/testing/web-platform/tests/editing/data/unlink.js @@ -1,3 +1,4 @@ +// For documentation of the format, see README in this directory. var browserTests = [ ["foo[]bar", [["unlink",""]], diff --git a/testing/web-platform/tests/encrypted-media/content/content-metadata.js b/testing/web-platform/tests/encrypted-media/content/content-metadata.js index 8ba5bcf06c29..580cc2bdfe4e 100644 --- a/testing/web-platform/tests/encrypted-media/content/content-metadata.js +++ b/testing/web-platform/tests/encrypted-media/content/content-metadata.js @@ -81,29 +81,6 @@ content = addMemberListToObject( { initDataType: 'cenc', initData: 'AAAAjXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAG0IARIQ7nNWTsiokPB472hx+kvhixoIY2FzdGxhYnMiRGV5SmhjM05sZEVsa0lqb2laVzFsTFhSbGMzUXRNbk5sYzNOcGIyNGlMQ0oyWVhKcFlXNTBTV1FpT2lKclpYa3lJbjA9MgdkZWZhdWx0AAADwnBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAA6KiAwAAAQABAJgDPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBUAGwAWgB6ADcAcQBqAEkAOABKAEIANAA3ADIAaAB4ACsAawB2AGgAaQB3AD0APQA8AC8ASwBJAEQAPgA8AEwAQQBfAFUAUgBMAD4AaAB0AHQAcABzADoALwAvAGwAaQBjAC4AcwB0AGEAZwBpAG4AZwAuAGQAcgBtAHQAbwBkAGEAeQAuAGMAbwBtAC8AbABpAGMAZQBuAHMAZQAtAHAAcgBvAHgAeQAtAGgAZQBhAGQAZQByAGEAdQB0AGgALwBkAHIAbQB0AG8AZABhAHkALwBSAGkAZwBoAHQAcwBNAGEAbgBhAGcAZQByAC4AYQBzAG0AeAA8AC8ATABBAF8AVQBSAEwAPgA8AEwAVQBJAF8AVQBSAEwAPgBoAHQAdABwAHMAOgAvAC8AbABpAGMALgBzAHQAYQBnAGkAbgBnAC4AZAByAG0AdABvAGQAYQB5AC4AYwBvAG0ALwBsAGkAYwBlAG4AcwBlAC0AcAByAG8AeAB5AC0AaABlAGEAZABlAHIAYQB1AHQAaAAvAGQAcgBtAHQAbwBkAGEAeQAvAFIAaQBnAGgAdABzAE0AYQBuAGEAZwBlAHIALgBhAHMAbQB4ADwALwBMAFUASQBfAFUAUgBMAD4APABDAEgARQBDAEsAUwBVAE0APgB4AEQASwBBAFkAMAB2AFoAaABVAFUAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=' } ] }, - 'mp4-basic-key1' : { assetId: 'mp4-multikey-sequential', - variantId: 'key1', - initDataType: 'cenc', - audio: { type: 'audio/mp4;codecs="mp4a.40.2"', - path: '/encrypted-media/content/audio_aac-lc_128k_dashinit.mp4' }, - video: { type: 'video/mp4;codecs="avc1.4d401e"', - path: '/encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4' }, - keys: [ { kid: [0x8a, 0x0d, 0x85, 0x45, 0x21, 0x05, 0xd4, 0x15, 0x35, 0x8f, 0xea, 0x8f, 0x68, 0xe6, 0xc1, 0x91], - key: [0x76, 0x6f, 0xab, 0xc1, 0x68, 0x3f, 0xf8, 0xef, 0x4e, 0x76, 0x00, 0x24, 0xc5, 0x23, 0x8f, 0x10], - initDataType: 'cenc', - initData: 'AAAAlXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAHUIARIQig2FRSEF1BU1j+qPaObBkRoIY2FzdGxhYnMiTGV5SmhjM05sZEVsa0lqb2liWEEwTFcxMWJIUnBhMlY1TFhObGNYVmxiblJwWVd3aUxDSjJZWEpwWVc1MFNXUWlPaUpyWlhreEluMD0yB2RlZmF1bHQAAANYcHNzaAAAAACaBPB5mEBChquS5lvgiF+VAAADODgDAAABAAEALgM8AFcAUgBNAEgARQBBAEQARQBSACAAeABtAGwAbgBzAD0AIgBoAHQAdABwADoALwAvAHMAYwBoAGUAbQBhAHMALgBtAGkAYwByAG8AcwBvAGYAdAAuAGMAbwBtAC8ARABSAE0ALwAyADAAMAA3AC8AMAAzAC8AUABsAGEAeQBSAGUAYQBkAHkASABlAGEAZABlAHIAIgAgAHYAZQByAHMAaQBvAG4APQAiADQALgAwAC4AMAAuADAAIgA+ADwARABBAFQAQQA+ADwAUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEUAWQBMAEUATgA+ADEANgA8AC8ASwBFAFkATABFAE4APgA8AEEATABHAEkARAA+AEEARQBTAEMAVABSADwALwBBAEwARwBJAEQAPgA8AC8AUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEkARAA+AFIAWQBVAE4AaQBnAFUAaABGAGQAUQAxAGoAKwBxAFAAYQBPAGIAQgBrAFEAPQA9ADwALwBLAEkARAA+ADwATABBAF8AVQBSAEwAPgBoAHQAdABwAHMAOgAvAC8AbABpAGMALgBzAHQAYQBnAGkAbgBnAC4AZAByAG0AdABvAGQAYQB5AC4AYwBvAG0ALwBsAGkAYwBlAG4AcwBlAC0AcAByAG8AeAB5AC0AaABlAGEAZABlAHIAYQB1AHQAaAAvAGQAcgBtAHQAbwBkAGEAeQAvAFIAaQBnAGgAdABzAE0AYQBuAGEAZwBlAHIALgBhAHMAbQB4ADwALwBMAEEAXwBVAFIATAA+ADwATABVAEkAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAGwAYQB5AHIAZQBhAGQAeQAtAHUAaQAuAGUAeABhAG0AcABsAGUALgBjAG8AbQA8AC8ATABVAEkAXwBVAFIATAA+ADwAQwBIAEUAQwBLAFMAVQBNAD4AcQBOAEkAZQBiAFQAWABzAG8AcgBnAD0APAAvAEMASABFAEMASwBTAFUATQA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A' } ] - }, - 'mp4-basic-key2' : { assetId: 'mp4-multikey-sequential', - variantId: 'key2', - initDataType: 'cenc', - audio: { type: 'audio/mp4;codecs="mp4a.40.2"', - path: '/encrypted-media/content/audio_aac-lc_128k_dashinit.mp4' }, - video: { type: 'video/mp4;codecs="avc1.4d401e"', - path: '/encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4' }, - keys: [ { kid: [0xfb, 0xb4, 0xb7, 0xf3, 0x4a, 0xbd, 0x31, 0x87, 0x34, 0x4b, 0xce, 0xc4, 0x5f, 0x96, 0x68, 0x88], - key: [0x26, 0x52, 0xc3, 0x1d, 0xf7, 0x92, 0xd1, 0x7b, 0x08, 0xa6, 0xfa, 0xd3, 0x7c, 0xb6, 0x25, 0x60], - initDataType: 'cenc', - initData: 'AAAAlXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAHUIARIQ+7S380q9MYc0S87EX5ZoiBoIY2FzdGxhYnMiTGV5SmhjM05sZEVsa0lqb2liWEEwTFcxMWJIUnBhMlY1TFhObGNYVmxiblJwWVd3aUxDSjJZWEpwWVc1MFNXUWlPaUpyWlhreUluMD0yB2RlZmF1bHQAAANYcHNzaAAAAACaBPB5mEBChquS5lvgiF+VAAADODgDAAABAAEALgM8AFcAUgBNAEgARQBBAEQARQBSACAAeABtAGwAbgBzAD0AIgBoAHQAdABwADoALwAvAHMAYwBoAGUAbQBhAHMALgBtAGkAYwByAG8AcwBvAGYAdAAuAGMAbwBtAC8ARABSAE0ALwAyADAAMAA3AC8AMAAzAC8AUABsAGEAeQBSAGUAYQBkAHkASABlAGEAZABlAHIAIgAgAHYAZQByAHMAaQBvAG4APQAiADQALgAwAC4AMAAuADAAIgA+ADwARABBAFQAQQA+ADwAUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEUAWQBMAEUATgA+ADEANgA8AC8ASwBFAFkATABFAE4APgA8AEEATABHAEkARAA+AEEARQBTAEMAVABSADwALwBBAEwARwBJAEQAPgA8AC8AUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEkARAA+ADgANwBlADAAKwA3ADEASwBoAHoARQAwAFMAOAA3AEUAWAA1AFoAbwBpAEEAPQA9ADwALwBLAEkARAA+ADwATABBAF8AVQBSAEwAPgBoAHQAdABwAHMAOgAvAC8AbABpAGMALgBzAHQAYQBnAGkAbgBnAC4AZAByAG0AdABvAGQAYQB5AC4AYwBvAG0ALwBsAGkAYwBlAG4AcwBlAC0AcAByAG8AeAB5AC0AaABlAGEAZABlAHIAYQB1AHQAaAAvAGQAcgBtAHQAbwBkAGEAeQAvAFIAaQBnAGgAdABzAE0AYQBuAGEAZwBlAHIALgBhAHMAbQB4ADwALwBMAEEAXwBVAFIATAA+ADwATABVAEkAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAGwAYQB5AHIAZQBhAGQAeQAtAHUAaQAuAGUAeABhAG0AcABsAGUALgBjAG8AbQA8AC8ATABVAEkAXwBVAFIATAA+ADwAQwBIAEUAQwBLAFMAVQBNAD4ARgB0AGkASQBoADYAUwBKAG0AcABZAD0APAAvAEMASABFAEMASwBTAFUATQA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A' } ] }, 'mp4-multikey-sequential' : { assetId: 'mp4-multikey-sequential', initDataType: 'cenc', diff --git a/testing/web-platform/tests/encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4 b/testing/web-platform/tests/encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4 deleted file mode 100644 index 0b9b457a6b3a..000000000000 Binary files a/testing/web-platform/tests/encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4 and /dev/null differ diff --git a/testing/web-platform/tests/eventsource/README.md b/testing/web-platform/tests/eventsource/README.md index 6b58a1ef51eb..60bbea3f3b97 100644 --- a/testing/web-platform/tests/eventsource/README.md +++ b/testing/web-platform/tests/eventsource/README.md @@ -1,54 +1,2 @@ -# Server-Sent Events Test Collection - -Server-Sent Events [latest draft](http://dev.w3.org/html5/eventsource/). - -Following up work done during the TestTWF 2012 Paris event: - -Most tests comes from [Opera](http://tc.labs.opera.com/apis/EventSource/), are from august 2010 and probably only valid against [spec rev. ~1.139](http://dev.w3.org/cvsweb/~checkout~/html5/eventsource/Overview.html?rev=1.139;content-type=text%2Fhtml). You can check the following diff : - -[diff between 1.139 (23 Jul 2010) and 1.229 (25 Oct. 2012) revisions](http://dev.w3.org/cvsweb/html5/eventsource/Overview.html.diff?r1=text&tr1=1.139&r2=text&tr2=1.229) - -to get an idea of what needs to get updated. - -##DONE (updated against rev. 1.229): -- **eventsource-constructor-url-bogus.htm**: whatwg r6602: renamed SYNTAX_ERR to SyntaxError - -- **eventsource-constructor-stringify.htm**: still valid. bugfix. - -##TODO (need to be updated against rev. 1.229): -- **eventsource-cross-origin.htm**, **eventsource-constructor-non-same-origin.htm**: whatwg 6255 6257: allow CORS - -##TOCHECK (need to check if the test is still valid against rev.1.229): -eventsource-close.htm -eventsource-constructor-document-domain.htm -eventsource-constructor-url-multi-window.htm -eventsource-eventtarget.htm -eventsource-onmessage.htm -eventsource-onopen.htm -eventsource-prototype.htm -eventsource-reconnect.htm -eventsource-url.htm -format-bom-2.htm -format-bom.htm -format-comments.htm -format-field-data.htm -format-field-event-empty.htm -format-field-event.htm -format-field-id-2.htm -format-field-id.htm -format-field-parsing.htm -format-field-retry-bogus.htm -format-field-retry-empty.htm -format-field-retry.htm -format-field-unknown.htm -format-leading-space.htm -format-mime-bogus.htm -format-mime-trailing-semicolon.htm -format-mime-valid-bogus.htm -format-newlines.htm -format-utf-8.htm -request-accept.htm -request-cache-control.htm -request-credentials.htm -request-redirect.htm -request-status-error.htm +These are the Server-sent events (`EventSource`) tests for the +[Server-sent events chapter of the HTML Standard](https://html.spec.whatwg.org/multipage/comms.html#server-sent-events). diff --git a/testing/web-platform/tests/fetch/api/basic/block-mime-as-script.html b/testing/web-platform/tests/fetch/api/basic/block-mime-as-script.html new file mode 100644 index 000000000000..37c38839d175 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/block-mime-as-script.html @@ -0,0 +1,39 @@ + + +Block mime type as script + + +

+ diff --git a/testing/web-platform/tests/fetch/api/headers/headers-idl.html b/testing/web-platform/tests/fetch/api/headers/headers-idl.html index fe24fa34c6a5..078c9d014951 100644 --- a/testing/web-platform/tests/fetch/api/headers/headers-idl.html +++ b/testing/web-platform/tests/fetch/api/headers/headers-idl.html @@ -12,10 +12,10 @@ diff --git a/testing/web-platform/tests/geolocation-API/getCurrentPosition_permission_allow.https.html b/testing/web-platform/tests/geolocation-API/getCurrentPosition_permission_allow.https.html index dfadcb09d197..951710991594 100644 --- a/testing/web-platform/tests/geolocation-API/getCurrentPosition_permission_allow.https.html +++ b/testing/web-platform/tests/geolocation-API/getCurrentPosition_permission_allow.https.html @@ -14,31 +14,21 @@ var t = async_test('User allows access, check that success callback is called or error callback is called with correct code.'), onSuccess, onError, hasMethodReturned = false; -onSuccess = t.step_func(function(pos) { - // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00031 - test(function() { +t.step(function() { + onSuccess = t.step_func_done(function(pos) { + // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00031 assert_true(hasMethodReturned); - }, 'Check that getCurrentPosition returns synchronously before any callbacks are invoked.'); + }); - done(); -}); - -onError = t.step_func(function(err) { - // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00031 - test(function() { + onError = t.step_func_done(function(err) { + // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00031 assert_true(hasMethodReturned); - }, 'Check that getCurrentPosition returns synchronously before any callbacks are invoked.'); + assert_false(isUsingPreemptivePermission); + assert_equals(err.code, err.POSITION_UNAVAILABLE, errorToString(err)); + }); - assert_true(!isUsingPreemptivePermission && err.code === err.POSITION_UNAVAILABLE); - done(); -}); - -try { geo.getCurrentPosition(onSuccess, onError); hasMethodReturned = true; -} catch(e) { - t.step(function() { - assert_unreached('An exception was thrown unexpectedly: ' + e.message); - }); -} +}); + diff --git a/testing/web-platform/tests/geolocation-API/getCurrentPosition_permission_deny.https.html b/testing/web-platform/tests/geolocation-API/getCurrentPosition_permission_deny.https.html index 26fe8899eda0..50129608ac7e 100644 --- a/testing/web-platform/tests/geolocation-API/getCurrentPosition_permission_deny.https.html +++ b/testing/web-platform/tests/geolocation-API/getCurrentPosition_permission_deny.https.html @@ -15,20 +15,18 @@ var t = async_test('User denies access, check that error callback is called with onSuccess, onError, hasMethodReturned = false; t.step(function() { - onSuccess = t.step_func(function(pos) { + onSuccess = t.step_func_done(function(pos) { assert_unreached('A success callback was invoked unexpectedly with position ' + positionToString(pos)); }); - onError = t.step_func(function(err) { + onError = t.step_func_done(function(err) { // http://dev.w3.org/geo/api/test-suite/t.html?00031 assert_true(hasMethodReturned, 'Check that getCurrentPosition returns synchronously before any callbacks are invoked'); - assert_equals(err.code, err.PERMISSION_DENIED, - 'PossitionError code: ' + err.code, + ', message: ' + err.message); - done(); + assert_equals(err.code, err.PERMISSION_DENIED, errorToString(err)); }); geo.getCurrentPosition(onSuccess, onError); hasMethodReturned = true; }); - + diff --git a/testing/web-platform/tests/geolocation-API/support.js b/testing/web-platform/tests/geolocation-API/support.js index c85b5c87f91c..960b5721c376 100644 --- a/testing/web-platform/tests/geolocation-API/support.js +++ b/testing/web-platform/tests/geolocation-API/support.js @@ -2,7 +2,7 @@ var geo; setup(function() { geo = navigator.geolocation; -}, {explicit_done: true}); +}); // The spec states that an implementation SHOULD acquire user permission before // beggining the position acquisition steps. If an implementation follows this diff --git a/testing/web-platform/tests/geolocation-API/watchPosition_permission_deny.https.html b/testing/web-platform/tests/geolocation-API/watchPosition_permission_deny.https.html index 831a1544fdf6..1e2a3c4bf4c4 100644 --- a/testing/web-platform/tests/geolocation-API/watchPosition_permission_deny.https.html +++ b/testing/web-platform/tests/geolocation-API/watchPosition_permission_deny.https.html @@ -14,18 +14,15 @@ var t = async_test('Check that watchPosition returns synchronously before any callbacks are invoked.'), id, checkMethodHasReturned, hasMethodReturned = false; -checkMethodHasReturned = t.step_func(function() { +checkMethodHasReturned = t.step_func_done(function() { assert_true(hasMethodReturned); - done(); }); try { id = geo.watchPosition(checkMethodHasReturned, checkMethodHasReturned); hasMethodReturned = true; } catch(e) { - t.step(function() { - assert_unreached('An exception was thrown unexpectedly: ' + e.message); - }); + t.unreached_func('An exception was thrown unexpectedly: ' + e.message); } // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00151 diff --git a/testing/web-platform/tests/gyroscope/Gyroscope.https.html b/testing/web-platform/tests/gyroscope/Gyroscope.https.html new file mode 100644 index 000000000000..8435912fb079 --- /dev/null +++ b/testing/web-platform/tests/gyroscope/Gyroscope.https.html @@ -0,0 +1,16 @@ + + +Gyroscope Test + + + + + +
+ + diff --git a/testing/web-platform/tests/gyroscope/Gyroscope_insecure_context.html b/testing/web-platform/tests/gyroscope/Gyroscope_insecure_context.html new file mode 100644 index 000000000000..f772b0a25405 --- /dev/null +++ b/testing/web-platform/tests/gyroscope/Gyroscope_insecure_context.html @@ -0,0 +1,20 @@ + + +Gyroscope Test: insecure context + + + + + +
+

Precondition

+
    +
  1. + Run test in an insecure context, e.g. http://example.com/. +
  2. +
+ diff --git a/testing/web-platform/tests/gyroscope/Gyroscope_onerror-manual.https.html b/testing/web-platform/tests/gyroscope/Gyroscope_onerror-manual.https.html new file mode 100644 index 000000000000..f0126151a24a --- /dev/null +++ b/testing/web-platform/tests/gyroscope/Gyroscope_onerror-manual.https.html @@ -0,0 +1,20 @@ + + +Gyroscope Test: onerror + + + + + +
+

Precondition

+
    +
  1. + Disable the Gyroscope Sensor or run test on a device without Gyroscope Sensor. +
  2. +
+ diff --git a/testing/web-platform/tests/gyroscope/idlharness.https.html b/testing/web-platform/tests/gyroscope/idlharness.https.html index 53d3b81cce6d..da1f67b65835 100644 --- a/testing/web-platform/tests/gyroscope/idlharness.https.html +++ b/testing/web-platform/tests/gyroscope/idlharness.https.html @@ -2,7 +2,8 @@ Gyroscope Sensor IDL tests - + + @@ -18,24 +19,24 @@ interface Event { }; -interface EventTarget { -}; - -interface EventHandler { -}; - interface Error { }; dictionary EventInit { }; + +interface EventTarget { +}; + +interface EventHandler { +};
 [SecureContext]
 interface Sensor : EventTarget {
-  readonly attribute SensorState state;
-  readonly attribute SensorReading? reading;
+  readonly attribute boolean activated;
+  readonly attribute DOMHighResTimeStamp? timestamp;
   void start();
   void stop();
   attribute EventHandler onchange;
@@ -47,18 +48,6 @@ dictionary SensorOptions {
   double? frequency;
 };
 
-enum SensorState {
-  "idle",
-  "activating",
-  "activated",
-  "errored"
-};
-
-[SecureContext]
-interface SensorReading {
-  readonly attribute DOMHighResTimeStamp timeStamp;
-};
-
 [SecureContext, Constructor(DOMString type, SensorErrorEventInit errorEventInitDict)]
 interface SensorErrorEvent : Event {
   readonly attribute Error error;
@@ -67,42 +56,31 @@ interface SensorErrorEvent : Event {
 dictionary SensorErrorEventInit : EventInit {
   required Error error;
 };
-
 
 [Constructor(optional SensorOptions sensorOptions)]
 interface Gyroscope : Sensor {
-  readonly attribute GyroscopeReading? reading;
-};
-
-[Constructor(GyroscopeReadingInit GyroscopeReadingInit)]
-interface GyroscopeReading : SensorReading {
-    readonly attribute unrestricted double x;
-    readonly attribute unrestricted double y;
-    readonly attribute unrestricted double z;
-};
-
-dictionary GyroscopeReadingInit {
-    unrestricted double x = 0;
-    unrestricted double y = 0;
-    unrestricted double z = 0;
+  readonly attribute unrestricted double? x;
+  readonly attribute unrestricted double? y;
+  readonly attribute unrestricted double? z;
 };
 
diff --git a/testing/web-platform/tests/gyroscope/support-iframe.html b/testing/web-platform/tests/gyroscope/support-iframe.html new file mode 100644 index 000000000000..5efbbcd54cfa --- /dev/null +++ b/testing/web-platform/tests/gyroscope/support-iframe.html @@ -0,0 +1,10 @@ + + + diff --git a/testing/web-platform/tests/html-media-capture/capture_audio-manual.html b/testing/web-platform/tests/html-media-capture/capture_audio-manual.html index a1f0c3716ef8..d9eb11aac4aa 100644 --- a/testing/web-platform/tests/html-media-capture/capture_audio-manual.html +++ b/testing/web-platform/tests/html-media-capture/capture_audio-manual.html @@ -2,8 +2,8 @@ HTML Media Capture Test: capture audio to produce one audio file - - + + diff --git a/testing/web-platform/tests/html-media-capture/capture_audio_cancel-manual.html b/testing/web-platform/tests/html-media-capture/capture_audio_cancel-manual.html index 73e486000d47..7c70d29364cc 100644 --- a/testing/web-platform/tests/html-media-capture/capture_audio_cancel-manual.html +++ b/testing/web-platform/tests/html-media-capture/capture_audio_cancel-manual.html @@ -2,8 +2,8 @@ HTML Media Capture Test: user denial of captured audio leading to no capture - - + +

Clear all microphone permissions before running this test. If prompted for permission, please allow.

diff --git a/testing/web-platform/tests/html-media-capture/capture_fallback_file_upload-manual.html b/testing/web-platform/tests/html-media-capture/capture_fallback_file_upload-manual.html index 2d25aa14f84a..d0e0678f5d43 100644 --- a/testing/web-platform/tests/html-media-capture/capture_fallback_file_upload-manual.html +++ b/testing/web-platform/tests/html-media-capture/capture_fallback_file_upload-manual.html @@ -4,8 +4,8 @@ HTML Media Capture Test: capture_fallback_file_upload - - + + diff --git a/testing/web-platform/tests/html-media-capture/capture_image_cancel-manual.html b/testing/web-platform/tests/html-media-capture/capture_image_cancel-manual.html index fafb5d5118fd..42137b999136 100644 --- a/testing/web-platform/tests/html-media-capture/capture_image_cancel-manual.html +++ b/testing/web-platform/tests/html-media-capture/capture_image_cancel-manual.html @@ -2,8 +2,8 @@ HTML Media Capture Test: user denial of captured image leading to no capture - - + +

Clear all camera permissions before running this test. If prompted for permission, please allow.

diff --git a/testing/web-platform/tests/html-media-capture/capture_image_environment-manual.html b/testing/web-platform/tests/html-media-capture/capture_image_environment-manual.html new file mode 100644 index 000000000000..b974222713d2 --- /dev/null +++ b/testing/web-platform/tests/html-media-capture/capture_image_environment-manual.html @@ -0,0 +1,41 @@ + + +HTML Media Capture Test: capture image with 'environment' facing mode to produce one image file + + + + + + + + +

Clear all camera permissions before running this test. If prompted for permission, please allow.

+ +

After hitting the button below, the camera must be launched with viewing the environment mode.

+ +

(Note: If the user agent is unable to support the preferred facing mode, it can fall back to the implementation-specific default facing mode.)

+ +

Capture an image and then confirm the capturing.

+ +

Note: All the actions need to be done in 60 seconds, otherwise it will get TIMEOUT.

+ + + +
+ + + diff --git a/testing/web-platform/tests/html-media-capture/capture_image_invalid-manual.html b/testing/web-platform/tests/html-media-capture/capture_image_invalid-manual.html new file mode 100644 index 000000000000..eb416e009dde --- /dev/null +++ b/testing/web-platform/tests/html-media-capture/capture_image_invalid-manual.html @@ -0,0 +1,39 @@ + + +HTML Media Capture Test: capture image with implementation-specific default facing mode(invalid value default) to produce one image file + + + + + + + + +

Clear all camera permissions before running this test. If prompted for permission, please allow.

+ +

After hitting the button below, the camera must be launched with the default facing mode.

+ +

Capture an image and then confirm the capturing.

+ +

Note: All the actions need to be done in 60 seconds, otherwise it will get TIMEOUT.

+ + + +
+ + + diff --git a/testing/web-platform/tests/html-media-capture/capture_image-manual.html b/testing/web-platform/tests/html-media-capture/capture_image_missing-manual.html similarity index 68% rename from testing/web-platform/tests/html-media-capture/capture_image-manual.html rename to testing/web-platform/tests/html-media-capture/capture_image_missing-manual.html index 1b15fb3691f0..405f69a24459 100644 --- a/testing/web-platform/tests/html-media-capture/capture_image-manual.html +++ b/testing/web-platform/tests/html-media-capture/capture_image_missing-manual.html @@ -1,9 +1,9 @@ -HTML Media Capture Test: capture image to produce one image file +HTML Media Capture Test: capture image with implementation-specific default facing mode(missing value default) to produce one image file - - + + @@ -11,7 +11,9 @@

Clear all camera permissions before running this test. If prompted for permission, please allow.

-

After hitting the button below, capture an image and then confirm the capturing.

+

After hitting the button below, the camera must be launched with the default facing mode.

+ +

Capture an image and then confirm the capturing.

Note: All the actions need to be done in 60 seconds, otherwise it will get TIMEOUT.

diff --git a/testing/web-platform/tests/html-media-capture/capture_image_user-manual.html b/testing/web-platform/tests/html-media-capture/capture_image_user-manual.html new file mode 100644 index 000000000000..a2d8c0ecca3d --- /dev/null +++ b/testing/web-platform/tests/html-media-capture/capture_image_user-manual.html @@ -0,0 +1,41 @@ + + +HTML Media Capture Test: capture image with 'user' facing mode to produce one image file + + + + + + + + +

Clear all camera permissions before running this test. If prompted for permission, please allow.

+ +

After hitting the button below, the camera must be launched with self-view mode.

+ +

(Note: If the user agent is unable to support the preferred facing mode, it can fall back to the implementation-specific default facing mode.)

+ +

Capture an image and then confirm the capturing.

+ +

Note: All the actions need to be done in 60 seconds, otherwise it will get TIMEOUT.

+ + + +
+ + + diff --git a/testing/web-platform/tests/html-media-capture/capture_reflect.html b/testing/web-platform/tests/html-media-capture/capture_reflect.html index 6dd40cc9b0ea..39f391eb674d 100644 --- a/testing/web-platform/tests/html-media-capture/capture_reflect.html +++ b/testing/web-platform/tests/html-media-capture/capture_reflect.html @@ -4,9 +4,7 @@ HTML Media Capture Test: capture_reflect - - - + @@ -15,43 +13,52 @@
       partial interface HTMLInputElement {
-                attribute boolean capture;
+        attribute CaptureFacingMode capture;
+      };
+      enum CaptureFacingMode {
+        "user",
+        "environment"
       };
     
- - - + + + +
diff --git a/testing/web-platform/tests/html-media-capture/capture_video_cancel-manual.html b/testing/web-platform/tests/html-media-capture/capture_video_cancel-manual.html index 645473701c83..45aee19f4815 100644 --- a/testing/web-platform/tests/html-media-capture/capture_video_cancel-manual.html +++ b/testing/web-platform/tests/html-media-capture/capture_video_cancel-manual.html @@ -2,8 +2,8 @@ HTML Media Capture Test: user denial of captured video leading to no capture - - + +

Clear all camera/microphone permissions before running this test. If prompted for permission, please allow.

diff --git a/testing/web-platform/tests/html-media-capture/capture_video_environment-manual.html b/testing/web-platform/tests/html-media-capture/capture_video_environment-manual.html new file mode 100644 index 000000000000..03a691e8a61b --- /dev/null +++ b/testing/web-platform/tests/html-media-capture/capture_video_environment-manual.html @@ -0,0 +1,41 @@ + + +HTML Media Capture Test: capture video with 'environment' facing mode to produce one video file + + + + + + + + +

Clear all camera/microphone permissions before running this test. If prompted for permission, please allow.

+ +

After hitting the button below, the camera must be launched with viewing the environment mode.

+ +

(Note: If the user agent is unable to support the preferred facing mode, it can fall back to the implementation-specific default facing mode.)

+ +

Capture a video and then confirm the capturing.

+ +

Note: All the actions need to be done in 60 seconds, otherwise it will get TIMEOUT.

+ + + +
+ + + diff --git a/testing/web-platform/tests/html-media-capture/capture_video_invalid-manual.html b/testing/web-platform/tests/html-media-capture/capture_video_invalid-manual.html new file mode 100644 index 000000000000..f6c0c3510ed8 --- /dev/null +++ b/testing/web-platform/tests/html-media-capture/capture_video_invalid-manual.html @@ -0,0 +1,39 @@ + + +HTML Media Capture Test: capture video with implementation-specific default facing mode(invalid value default) to produce one video file + + + + + + + + +

Clear all camera/microphone permissions before running this test. If prompted for permission, please allow.

+ +

After hitting the button below, the camera must be launched with the default facing mode.

+ +

Capture an video and then confirm the capturing.

+ +

Note: All the actions need to be done in 60 seconds, otherwise it will get TIMEOUT.

+ + + +
+ + + diff --git a/testing/web-platform/tests/html-media-capture/capture_video-manual.html b/testing/web-platform/tests/html-media-capture/capture_video_missing-manual.html similarity index 68% rename from testing/web-platform/tests/html-media-capture/capture_video-manual.html rename to testing/web-platform/tests/html-media-capture/capture_video_missing-manual.html index b54abae0eb53..ed637445758a 100644 --- a/testing/web-platform/tests/html-media-capture/capture_video-manual.html +++ b/testing/web-platform/tests/html-media-capture/capture_video_missing-manual.html @@ -1,9 +1,9 @@ -HTML Media Capture Test: capture video to produce one video file +HTML Media Capture Test: capture video with implementation-specific default facing mode(missing value default) to produce one video file - - + + @@ -11,7 +11,9 @@

Clear all camera/microphone permissions before running this test. If prompted for permission, please allow.

-

After hitting the button below, capture an video and then confirm the capturing.

+

After hitting the button below, the camera must be launched with the default facing mode.

+ +

Capture an video and then confirm the capturing.

Note: All the actions need to be done in 60 seconds, otherwise it will get TIMEOUT.

diff --git a/testing/web-platform/tests/html-media-capture/capture_video_user-manual.html b/testing/web-platform/tests/html-media-capture/capture_video_user-manual.html new file mode 100644 index 000000000000..47a6732ecf5f --- /dev/null +++ b/testing/web-platform/tests/html-media-capture/capture_video_user-manual.html @@ -0,0 +1,41 @@ + + +HTML Media Capture Test: capture video with 'user' facing mode to produce one video file + + + + + + + + +

Clear all camera/microphone permissions before running this test. If prompted for permission, please allow.

+ +

After hitting the button below, the camera must be launched with self-view mode.

+ +

(Note: If the user agent is unable to support the preferred facing mode, it can fall back to the implementation-specific default facing mode.)

+ +

Capture a video and then confirm the capturing.

+ +

Note: All the actions need to be done in 60 seconds, otherwise it will get TIMEOUT.

+ + + +
+ + + diff --git a/testing/web-platform/tests/html-media-capture/idlharness.html b/testing/web-platform/tests/html-media-capture/idlharness.html index a204764ae873..22b3e05ee9df 100644 --- a/testing/web-platform/tests/html-media-capture/idlharness.html +++ b/testing/web-platform/tests/html-media-capture/idlharness.html @@ -4,8 +4,7 @@ HTML Media Capture IDL tests - - + @@ -26,12 +25,16 @@
- +
+ + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter_iframe.html b/testing/web-platform/tests/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter_iframe.html new file mode 100644 index 000000000000..d3d5260af3f1 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter_iframe.html @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html new file mode 100644 index 000000000000..7f55f1bb1d80 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html @@ -0,0 +1,75 @@ + + +HTML: window.open `features`: negative values for legacy `innerwidth`, `innerheight` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-screenx-screeny.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-screenx-screeny.html new file mode 100644 index 000000000000..09fb2d6b0a5a --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-screenx-screeny.html @@ -0,0 +1,67 @@ + + +HTML: window.open `features`: negative values for legacy `screenx`, `screeny` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-top-left.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-top-left.html new file mode 100644 index 000000000000..15b3103db3cc --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-top-left.html @@ -0,0 +1,68 @@ + + +HTML: window.open `features`: negative values for `top`, `left` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-width-height.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-width-height.html new file mode 100644 index 000000000000..30b70926f2c7 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-width-height.html @@ -0,0 +1,75 @@ + + +HTML: window.open `features`: negative values for `width`, `height` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-height.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-height.html new file mode 100644 index 000000000000..08d127e84b1d --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-height.html @@ -0,0 +1,91 @@ + + +HTML: window.open `features`: non-integer values for feature `height` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerheight.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerheight.html new file mode 100644 index 000000000000..5ee752caedc8 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerheight.html @@ -0,0 +1,76 @@ + + +HTML: window.open `features`: non-integer values for legacy feature `innerheight` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerwidth.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerwidth.html new file mode 100644 index 000000000000..972beef48abb --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerwidth.html @@ -0,0 +1,75 @@ + + +HTML: window.open `features`: non-integer values for legacy feature `innerwidth` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-left.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-left.html new file mode 100644 index 000000000000..fbb2a30ee226 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-left.html @@ -0,0 +1,76 @@ + + +HTML: window.open `features`: non-integer values for feature `left` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screenx.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screenx.html new file mode 100644 index 000000000000..2aeab9bb796e --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screenx.html @@ -0,0 +1,75 @@ + + +HTML: window.open `features`: non-integer values for legacy feature `screenx` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screeny.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screeny.html new file mode 100644 index 000000000000..cb4e873f26d0 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screeny.html @@ -0,0 +1,76 @@ + + +HTML: window.open `features`: non-integer values for legacy feature `screeny` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-top.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-top.html new file mode 100644 index 000000000000..d4f4e90d96ed --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-top.html @@ -0,0 +1,73 @@ + + +HTML: window.open `features`: non-integer values for feature `top` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-width.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-width.html new file mode 100644 index 000000000000..a746abed3f36 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-width.html @@ -0,0 +1,91 @@ + + +HTML: window.open `features`: non-integer values for feature `width` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-innerheight-innerwidth.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-innerheight-innerwidth.html new file mode 100644 index 000000000000..c839c6ca0661 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-innerheight-innerwidth.html @@ -0,0 +1,55 @@ + + +HTML: window.open `features`: tokenization -- legacy size features `innerheight`, `innerwidth` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html new file mode 100644 index 000000000000..cac23648ade4 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html @@ -0,0 +1,150 @@ + + +HTML: window.open `features`: tokenization -- `noopener` + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html new file mode 100644 index 000000000000..bb6fc4b84bfb --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html @@ -0,0 +1,55 @@ + + +HTML: window.open `features`: tokenization -- legacy position features `screenx`, `screeny` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html new file mode 100644 index 000000000000..ef098a1062c6 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html @@ -0,0 +1,69 @@ + + +HTML: window.open `features`: tokenization -- position features `top` and `left` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-width-height.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-width-height.html new file mode 100644 index 000000000000..cac4ae639b2f --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-width-height.html @@ -0,0 +1,71 @@ + + +HTML: window.open `features`: tokenization -- size features `width` and `height` + + + + + + + + + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/close-self.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/close-self.html new file mode 100644 index 000000000000..0c0cf9fc4911 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/close-self.html @@ -0,0 +1,3 @@ + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/message-opener.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/message-opener.html new file mode 100644 index 000000000000..e6c164bfae53 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/message-opener.html @@ -0,0 +1,12 @@ + + diff --git a/testing/web-platform/tests/html/browsers/the-window-object/window-indexed-properties-strict.html b/testing/web-platform/tests/html/browsers/the-window-object/window-indexed-properties-strict.html index 610941fc8794..e059b1226165 100644 --- a/testing/web-platform/tests/html/browsers/the-window-object/window-indexed-properties-strict.html +++ b/testing/web-platform/tests/html/browsers/the-window-object/window-indexed-properties-strict.html @@ -23,15 +23,24 @@ test(function() { assert_throws(new TypeError(), function() { window[0] = "foo"; }); + assert_throws(new TypeError(), () => Object.defineProperty(window, 0, { value: "bar" })) + assert_throws(new TypeError(), () => Object.defineProperty(window, 0, { get() { return "baz" } })) + assert_throws(new TypeError(), () => Object.defineProperty(window, 0, { set(v) { return "qux" } })) assert_equals(window[0], document.getElementsByTagName("iframe")[0].contentWindow); + assert_throws(new TypeError(), () => delete window[0]); }); test(function() { "use strict"; assert_throws(new TypeError(), function() { window[1] = "foo"; }); + assert_throws(new TypeError(), () => Object.defineProperty(window, 1, { value: "bar" })) + assert_throws(new TypeError(), () => Object.defineProperty(window, 1, { get() { return "baz" } })) + assert_throws(new TypeError(), () => Object.defineProperty(window, 1, { set(v) { return "qux" } })) assert_equals(window[1], undefined); + assert_equals(Object.getOwnPropertyDescriptor(window, 1), undefined); + assert_equals(delete window[1], true); }); test(function() { "use strict"; diff --git a/testing/web-platform/tests/html/browsers/the-window-object/window-indexed-properties.html b/testing/web-platform/tests/html/browsers/the-window-object/window-indexed-properties.html index 9577ab8fbce9..17d0eb729ae1 100644 --- a/testing/web-platform/tests/html/browsers/the-window-object/window-indexed-properties.html +++ b/testing/web-platform/tests/html/browsers/the-window-object/window-indexed-properties.html @@ -19,12 +19,21 @@ test(function() { }); test(function() { window[0] = "foo"; + assert_throws(new TypeError(), () => Object.defineProperty(window, 0, { value: "bar" })) + assert_throws(new TypeError(), () => Object.defineProperty(window, 0, { get() { return "baz" } })) + assert_throws(new TypeError(), () => Object.defineProperty(window, 0, { set() { return "quz" } })) assert_equals(window[0], document.getElementsByTagName("iframe")[0].contentWindow); + assert_equals(delete window[0], false); }); test(function() { window[1] = "foo"; + assert_throws(new TypeError(), () => Object.defineProperty(window, 1, { value: "bar" })) + assert_throws(new TypeError(), () => Object.defineProperty(window, 1, { get() { return "baz" } })) + assert_throws(new TypeError(), () => Object.defineProperty(window, 1, { set(v) { return "quz" } })) assert_equals(window[1], undefined); + assert_equals(Object.getOwnPropertyDescriptor(window, 1), undefined); + assert_equals(delete window[1], true); }); test(function() { var proto = Window.prototype; diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/001-1.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/001-1.html deleted file mode 100644 index d413c3019ff1..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/001-1.html +++ /dev/null @@ -1,8 +0,0 @@ - -001-1 - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/001.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/001.html deleted file mode 100644 index 2478cdc8fac1..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/001.html +++ /dev/null @@ -1,22 +0,0 @@ - -Link with target=_blank, rel=noreferrer - - -
-Link - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/002-1.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/002-1.html deleted file mode 100644 index ca8a485de613..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/002-1.html +++ /dev/null @@ -1,8 +0,0 @@ - -002-1 - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/002.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/002.html deleted file mode 100644 index 4a1df8e4d039..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/002.html +++ /dev/null @@ -1,25 +0,0 @@ - -Link with target=_blank, no rel - - -
-Link - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-existing.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-existing.html deleted file mode 100644 index 2eaba22f6fa8..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-existing.html +++ /dev/null @@ -1,25 +0,0 @@ - - -HTML Test: Choose browsing context - the given name is same as an existing browsing context's name - - - -
- - - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-004.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-004.html deleted file mode 100644 index ca98f66d1723..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-004.html +++ /dev/null @@ -1,16 +0,0 @@ - - -HTML Test: Choose browsing context - '_parent' (case-sensitivity) - - -
- - - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-self-1.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-self-1.html deleted file mode 100644 index 99d7fe7d3feb..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-self-1.html +++ /dev/null @@ -1,20 +0,0 @@ - - -HTML Test: Choose browsing context - the given name is '_self' - - - -
- - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-self-2.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-self-2.html deleted file mode 100644 index e25a5b44240b..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-self-2.html +++ /dev/null @@ -1,20 +0,0 @@ - - -HTML Test: Choose browsing context - the given name is empty string - - - -
- - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-_blank.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_blank-001.html similarity index 100% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-_blank.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_blank-001.html diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_blank-002.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_blank-002.html new file mode 100644 index 000000000000..aba9d52ba097 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_blank-002.html @@ -0,0 +1,21 @@ + +Link with target=_blank, rel=noreferrer + + + +
+Link + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_blank-003.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_blank-003.html new file mode 100644 index 000000000000..6912300ab2d9 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_blank-003.html @@ -0,0 +1,20 @@ + +Link with target=_blank, no rel + + + +
+Link + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-001.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-001.html similarity index 81% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-001.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-001.html index e1495beb8b18..35cbc101c7b3 100644 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-001.html +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-001.html @@ -12,4 +12,4 @@ async_test(t => { })); }, 'The parent browsing context must be chosen if the given name is `_parent`'); - + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-002.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-002.html similarity index 87% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-002.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-002.html index 9cdef8349f38..7b7d561030e5 100644 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-002.html +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-002.html @@ -12,6 +12,6 @@ async_test(t => { assert_equals(e.data.name, 'iframeParent'); assert_false(e.data.isTop, 'window.parent is not top'); })); - topWindow = window.open('resources/parent-top.html', '_blank'); + topWindow = window.open('resources/choose-_parent-002-window.html', '_blank'); }, 'choosing _parent context: multiple nested contexts'); diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-003.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-003.html similarity index 85% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-003.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-003.html index f0a165e6844c..20dc9b0d2ac4 100644 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-choose-parent-003.html +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-003.html @@ -12,6 +12,6 @@ async_test(t => { assert_equals(e.data.name, 'parentTopReplace'); assert_equals(e.data.isTop, true); })); - topWindow = window.open('resources/parent-top-replace.html', 'parentTopReplace'); + topWindow = window.open('resources/choose-_parent-003-window.html', 'parentTopReplace'); }, '_parent should reuse window.parent context'); diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-004.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-004.html new file mode 100644 index 000000000000..c79378018a37 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_parent-004.html @@ -0,0 +1,40 @@ + + +HTML Test: Choose browsing context - '_parent' (case-sensitivity) + + + + +
+ + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_self-001.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_self-001.html new file mode 100644 index 000000000000..ed7666846d5c --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_self-001.html @@ -0,0 +1,15 @@ + + +HTML Test: Choose browsing context - the given name is '_self' + + + +
+ + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_self-002.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_self-002.html new file mode 100644 index 000000000000..2e798f5493f9 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_self-002.html @@ -0,0 +1,46 @@ + + +HTML Test: Choose browsing context - '_self' (case-sensitivity) + + + + +
+ + + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_top-001.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_top-001.html new file mode 100644 index 000000000000..de4c6ad115e8 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_top-001.html @@ -0,0 +1,34 @@ + +HTML Test: Browsing context name - _top (current is top) + + + +
+ diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_top-002.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_top-002.html new file mode 100644 index 000000000000..f29da80c6eef --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_top-002.html @@ -0,0 +1,33 @@ + +HTML Test: Browsing context name - _top + + + +
+ diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_top-003.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_top-003.html new file mode 100644 index 000000000000..e068f8cc1fbb --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-_top-003.html @@ -0,0 +1,39 @@ + + +HTML Test: Choose browsing context - '_top' (case-sensitivity) + + + + +
+ + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-default-name.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-default-001.html similarity index 84% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-default-name.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-default-001.html index 470e244643cf..c21159e0a618 100644 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/browsing-context-default-name.html +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-default-001.html @@ -20,10 +20,4 @@ test(t => { assert_equals(win.name, ""); win.close(); }, "A browsing context which is opened by window.open() method with '_blank' parameter has empty-string default name"); - -//This test must be run when the current browsing context's name is not set -test(t => { - assert_equals(window.name, ""); -}, "A browsing context has an empty-string default name"); - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-default-002.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-default-002.html new file mode 100644 index 000000000000..748ee6897318 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-default-002.html @@ -0,0 +1,16 @@ + + +HTML Test: Browsing context names - empty string + + + +
+ + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-existing-001.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-existing-001.html new file mode 100644 index 000000000000..fdf74b8a797b --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/choose-existing-001.html @@ -0,0 +1,17 @@ + + +HTML Test: Choose browsing context - the given name is same as an existing browsing context's name + + + +
+ + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-1.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-001-iframe-1.html similarity index 77% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-1.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-001-iframe-1.html index 3d7accffd780..04dd74f1a53b 100644 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-1.html +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-001-iframe-1.html @@ -2,4 +2,4 @@ HTML Test: browsing context name - parent - + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-top-nested.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-002-iframe.html similarity index 63% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-top-nested.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-002-iframe.html index ffe351132339..52da8986b0ad 100644 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-top-nested.html +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-002-iframe.html @@ -1,4 +1,4 @@ HTML Test: browsing context name - parent: nested context - + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-top.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-002-window.html similarity index 80% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-top.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-002-window.html index 6ad72f969be9..558193742f68 100644 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-top.html +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-002-window.html @@ -1,7 +1,7 @@ HTML Test: browsing context name - parent: top-level context - + + + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-004-iframe-2.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-004-iframe-2.html new file mode 100644 index 000000000000..33ead5a53856 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_parent-004-iframe-2.html @@ -0,0 +1,9 @@ + + +HTML Test: browsing context name - parent (case-insensitive) + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/self2.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_self-001-iframe.html similarity index 68% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/self2.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_self-001-iframe.html index b3b4f59b5359..0ad79d6e1640 100644 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/self2.html +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_self-001-iframe.html @@ -3,9 +3,7 @@ HTML Test: browsing context name - self diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_self-002-iframe.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_self-002-iframe.html new file mode 100644 index 000000000000..9d88305e09da --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_self-002-iframe.html @@ -0,0 +1,11 @@ + + +HTML Test: browsing context name - self (case-insensitive) + + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_top-002-window.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_top-002-window.html new file mode 100644 index 000000000000..d71384b72f69 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_top-002-window.html @@ -0,0 +1,16 @@ + + + +HTML Test: browsing context name - _top + + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_top-003-iframe-1.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_top-003-iframe-1.html new file mode 100644 index 000000000000..aecc2fd88a2c --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_top-003-iframe-1.html @@ -0,0 +1,15 @@ + + +HTML Test: browsing context name - top (case-insensitive) + + + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_top-003-iframe-2.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_top-003-iframe-2.html new file mode 100644 index 000000000000..a1a7e1dda7ee --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-_top-003-iframe-2.html @@ -0,0 +1,10 @@ + + +HTML Test: browsing context name - top (case-insensitive) + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-default-002-iframe.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-default-002-iframe.html new file mode 100644 index 000000000000..567e4ea3103f --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-default-002-iframe.html @@ -0,0 +1,17 @@ + + + +HTML Test: browsing context name - Empty string + + + + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/existing.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-existing-001-iframe.html similarity index 65% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/existing.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-existing-001-iframe.html index 6023319cebfd..cb0b554854fe 100644 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/existing.html +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/choose-existing-001-iframe.html @@ -3,9 +3,5 @@ This is a test page diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-2.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/open-in-_parent.html similarity index 100% rename from testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-2.html rename to testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/open-in-_parent.html diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/open-in-_top.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/open-in-_top.html new file mode 100644 index 000000000000..929d52d15e27 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/open-in-_top.html @@ -0,0 +1,9 @@ + + + +HTML Test: browsing context name - _top + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-insensitive-1.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-insensitive-1.html deleted file mode 100644 index 8ddbf44a3b5e..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-insensitive-1.html +++ /dev/null @@ -1,4 +0,0 @@ - - -HTML Test: browsing context name - parent - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-insensitive-2.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-insensitive-2.html deleted file mode 100644 index 38d6b2f42848..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/parent-iframe-insensitive-2.html +++ /dev/null @@ -1,8 +0,0 @@ - - -HTML Test: browsing context name - parent (case-insensitive) - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/post-to-top-or-close.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/post-to-top-or-close.html deleted file mode 100644 index 2ccb6731d7ba..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/post-to-top-or-close.html +++ /dev/null @@ -1,16 +0,0 @@ - - -HTML Test: post window's name to top browsing context - - diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/report-has-opener.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/report-has-opener.html new file mode 100644 index 000000000000..37d8cedc6da4 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/report-has-opener.html @@ -0,0 +1,8 @@ + + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/report-is-top.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/report-is-top.html new file mode 100644 index 000000000000..871123598232 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/resources/report-is-top.html @@ -0,0 +1,10 @@ + + + + diff --git a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/self1.html b/testing/web-platform/tests/html/browsers/windows/browsing-context-names/self1.html deleted file mode 100644 index d72df6f86420..000000000000 --- a/testing/web-platform/tests/html/browsers/windows/browsing-context-names/self1.html +++ /dev/null @@ -1,11 +0,0 @@ - - -HTML Test: browsing context name - self - - diff --git a/testing/web-platform/tests/html/dom/elements-metadata.js b/testing/web-platform/tests/html/dom/elements-metadata.js index 73cbfc1a4542..7c4d373b8005 100644 --- a/testing/web-platform/tests/html/dom/elements-metadata.js +++ b/testing/web-platform/tests/html/dom/elements-metadata.js @@ -12,7 +12,12 @@ var metadataElements = { crossOrigin: {type: "enum", keywords: ["anonymous", "use-credentials"], nonCanon:{"": "anonymous"}, isNullable: true, defaultVal: null, invalidVal: "anonymous"}, rel: "string", relList: {type: "tokenlist", domAttrName: "rel"}, - // as: {}, XXX TODO: reflecting IDL attribute is an IDL enumeration + as: { + type: "enum", + keywords: ["", "audio", "document", "embed", "font", "image", "manifest", "object", "report", "script", "serviceworker", "sharedworker", "style", "track", "video", "worker", "xslt"], + defaultVal: "", + invalidVal: "" + }, media: "string", nonce: "string", integrity: "string", diff --git a/testing/web-platform/tests/html/dom/elements-tabular.js b/testing/web-platform/tests/html/dom/elements-tabular.js index bb54ade30565..ee66f7a47b6e 100644 --- a/testing/web-platform/tests/html/dom/elements-tabular.js +++ b/testing/web-platform/tests/html/dom/elements-tabular.js @@ -68,8 +68,8 @@ var tabularElements = { }, td: { // HTMLTableCellElement (Conforming) - colSpan: {type: "unsigned long", defaultVal: 1}, - rowSpan: {type: "unsigned long", defaultVal: 1}, + colSpan: {type: "clamped unsigned long", defaultVal: 1, min: 1, max: 1000}, + rowSpan: {type: "clamped unsigned long", defaultVal: 1, min: 0, max: 65534}, headers: "settable tokenlist", scope: {type: "enum", keywords: ["row", "col", "rowgroup", "colgroup"]}, abbr: "string", @@ -87,8 +87,8 @@ var tabularElements = { }, th: { // HTMLTableCellElement (Conforming) - colSpan: {type: "unsigned long", defaultVal: 1}, - rowSpan: {type: "unsigned long", defaultVal: 1}, + colSpan: {type: "clamped unsigned long", defaultVal: 1, min: 1, max: 1000}, + rowSpan: {type: "clamped unsigned long", defaultVal: 1, min: 0, max: 65534}, headers: "settable tokenlist", scope: {type: "enum", keywords: ["row", "col", "rowgroup", "colgroup"]}, abbr: "string", diff --git a/testing/web-platform/tests/html/dom/interfaces.html b/testing/web-platform/tests/html/dom/interfaces.html index dc751e0f2dcb..84406156e8ac 100644 --- a/testing/web-platform/tests/html/dom/interfaces.html +++ b/testing/web-platform/tests/html/dom/interfaces.html @@ -30,10 +30,10 @@ function createInput(type) { return input; } -function doTest([untested, tested]) { +function doTest([html, dom, cssom, uievents, touchevents]) { var idlArray = new IdlArray(); - idlArray.add_untested_idls(untested); - idlArray.add_idls(tested); + idlArray.add_untested_idls(dom + cssom + uievents + touchevents); + idlArray.add_idls(html); idlArray.add_objects({ NodeList: ['document.getElementsByName("name")'], @@ -227,8 +227,11 @@ function waitForLoad() { promise_test(function() { // Have to wait for onload - return Promise.all([fetchData("resources/untested-interfaces.idl"), - fetchData("resources/interfaces.idl"), + return Promise.all([fetchData("/interfaces/html.idl"), + fetchData("/interfaces/dom.idl"), + fetchData("/interfaces/cssom.idl"), + fetchData("/interfaces/touchevents.idl"), + fetchData("/interfaces/uievents.idl"), waitForLoad()]) .then(doTest); }, "Test driver"); diff --git a/testing/web-platform/tests/html/dom/reflection.js b/testing/web-platform/tests/html/dom/reflection.js index e3ff41574c49..b50e99b247ed 100644 --- a/testing/web-platform/tests/html/dom/reflection.js +++ b/testing/web-platform/tests/html/dom/reflection.js @@ -454,6 +454,37 @@ ReflectionTests.typeMap = { "idlTests": [0, 1, maxInt, maxInt + 1, maxUnsigned], "idlDomExpected": [null, 1, maxInt, null, null] }, + /** + * "If a reflecting IDL attribute has an unsigned integer type (unsigned + * long) that is clamped to the range [min, max], then on getting, the + * content attribute must first be parsed according to the rules for + * parsing non-negative integers, and if that is successful, and the value + * is between min and max inclusive, the resulting value must be returned. + * If it fails, the default value must be returned. If it succeeds but the + * value is less than min, min must be returned. If it succeeds but the + * value is greater than max, max must be returned. On setting, it behaves + * the same as a regular reflected unsigned integer." + * + * The data object passed to reflects must contain the keys defaultVal, + * min, and max. As with enum, domExpected is generated later once we have + * access to the min and max. + */ + "clamped unsigned long": { + "jsType": "number", + "domTests": [minInt - 1, minInt, -36, -1, 0, 1, maxInt, + maxInt + 1, maxUnsigned, maxUnsigned + 1, "", "-1", "-0", "0", "1", + "\u00097", "\u000B7", "\u000C7", "\u00207", "\u00A07", "\uFEFF7", + "\u000A7", "\u000D7", "\u20287", "\u20297", "\u16807", "\u180E7", + "\u20007", "\u20017", "\u20027", "\u20037", "\u20047", "\u20057", + "\u20067", "\u20077", "\u20087", "\u20097", "\u200A7", "\u202F7", + "\u30007", + " " + binaryString + " foo ", undefined, 1.5, true, false, + {"test": 6}, NaN, +Infinity, -Infinity, "\0", + {toString:function() {return 2;}, valueOf: null}, + {valueOf:function() {return 3;}}], + "idlTests": [0, 1, 257, maxInt, "-0", maxInt + 1, maxUnsigned], + "idlDomExpected": [0, 1, 257, maxInt, 0, null, null], + }, /** * "If a reflecting IDL attribute is a floating point number type (double), * then, on getting, the content attribute must be parsed according to the @@ -681,6 +712,54 @@ ReflectionTests.reflects = function(data, idlName, idlObj, domName, domObj) { } } break; + + case "clamped unsigned long": + [data.min - 1, data.min, data.max, data.max + 1].forEach(function(val) { + if (domTests.indexOf(val) == -1) { + domTests.push(val); + } + if (idlTests.indexOf(val) == -1 && 0 <= val && val <= maxUnsigned) { + idlTests.push(val); + if (typeof val != "number") { + val = ReflectionTests.parseNonneg(val); + } + idlDomExpected.push(val > maxInt ? null : val); + } + }); + + // Rewrite expected values + domExpected = domTests.map(function(val) { + var parsed = ReflectionTests.parseNonneg(String(val)); + if (parsed === false) { + return defaultVal; + } + if (parsed < data.min) { + return data.min; + } + if (parsed > data.max) { + return data.max; + } + return parsed; + }); + idlIdlExpected = idlTests.map(function(val) { + if (typeof val != "number") { + val = ReflectionTests.parseNonneg(val); + } + if (val < 0 || val > maxUnsigned) { + throw "Test bug: val should be an unsigned long"; + } + if (val > maxInt) { + return defaultVal; + } + if (val < data.min) { + return data.min; + } + if (val > data.max) { + return data.max; + } + return val; + }); + break; } if (domObj.tagName.toLowerCase() == "canvas" && (domName == "width" || domName == "height")) { // Opera tries to allocate a canvas with the given width and height, so diff --git a/testing/web-platform/tests/html/dom/self-origin.sub.html b/testing/web-platform/tests/html/dom/self-origin.sub.html index 4143a4a20ab4..539494a96bb9 100644 --- a/testing/web-platform/tests/html/dom/self-origin.sub.html +++ b/testing/web-platform/tests/html/dom/self-origin.sub.html @@ -48,7 +48,7 @@ function nextMessageTest() { window.onmessage = function(e) { var testData = messageTests[curTest++]; - testData[3].step_func(function() { + testData[3].step(function() { assert_equals(e.data, testData[2]) }); testData[3].done(); diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html new file mode 100644 index 000000000000..68dcc54702ce --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/references/spelling-markers-001-ref.html @@ -0,0 +1,7 @@ + + + +Reference file for spellcheck tests + +
This test passes if there is no visual marker indicating the spellinnnnnggg mistake in this sentence, and fails otherwise.
+ diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-001.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-001.html new file mode 100644 index 000000000000..4a5fd4104104 --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-001.html @@ -0,0 +1,15 @@ + + + +Turning off spellcheck on editing hosts + + + + +
This test passes if there is no visual marker indicating the spellinnnnnggg mistake in this sentence, and fails otherwise.
+ + diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-002.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-002.html new file mode 100644 index 000000000000..44f1ea842e29 --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-002.html @@ -0,0 +1,16 @@ + + + +Turning off spellcheck on editable elements + + + + +
This test passes if there is no visual marker indicating the spellinnnnnggg mistake in this sentence, and fails otherwise.
+ + diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-003.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-003.html new file mode 100644 index 000000000000..9c88660e2817 --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-003.html @@ -0,0 +1,15 @@ + + + +Turning off spellcheck on editing hosts while keeping them editable + + + + +
This test passes if there is no visual marker indicating the spellinnnnnggg mistake in this sentence, and fails otherwise.
+ + diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-004.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-004.html new file mode 100644 index 000000000000..fdeb90648c07 --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-004.html @@ -0,0 +1,16 @@ + + + +Turning off spellcheck on editable elements while keeping them editable + + + + +
This test passes if there is no visual marker indicating the spellinnnnnggg mistake in this sentence, and fails otherwise.
+ + diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-005.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-005.html new file mode 100644 index 000000000000..9ab7a3ed6dcc --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-005.html @@ -0,0 +1,16 @@ + + + +Turning off spellcheck on editable elements via an ancestor + + + + +
This test passes if there is no visual marker indicating the spellinnnnnggg mistake in this sentence, and fails otherwise.
+ + diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-006.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-006.html new file mode 100644 index 000000000000..f0b54da15b5b --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-006.html @@ -0,0 +1,18 @@ + + + +Turning off spellcheck via an ancestor of the editing host + + + + +
+
This test passes if there is no visual marker indicating the spellinnnnnggg mistake in this sentence, and fails otherwise.
+
+ + diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-007.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-007.html new file mode 100644 index 000000000000..4bbeca9a32c4 --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-007.html @@ -0,0 +1,25 @@ + + + +Turning off spellcheck by making textareas readonly + + + + + + + + + diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-008.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-008.html new file mode 100644 index 000000000000..5ed72abb84db --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-008.html @@ -0,0 +1,25 @@ + + + +Turning off spellcheck by making textareas disabled + + + + + + + + + diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-009.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-009.html new file mode 100644 index 000000000000..577ffd895bcf --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-009.html @@ -0,0 +1,25 @@ + + + +Turning off spellcheck by making input elements readonly + + + + + + + + + diff --git a/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-010.html b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-010.html new file mode 100644 index 000000000000..6a2e1046b895 --- /dev/null +++ b/testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/spelling-markers-010.html @@ -0,0 +1,25 @@ + + + +Turning off spellcheck by making input elements disabled + + + + + + + + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html new file mode 100644 index 000000000000..8902de49cfb1 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html @@ -0,0 +1,35 @@ + +SharedArrayBuffer cannot cross agent clusters, BroadcastChannel edition + + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html new file mode 100644 index 000000000000..f9cf7a87cfc3 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html @@ -0,0 +1,58 @@ + + +Structured cloning of SharedArrayBuffers: BroadcastChannel within the same agent cluster + + + + + + +
+ + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.html new file mode 100644 index 000000000000..91110867d7b4 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.html @@ -0,0 +1,64 @@ + + +SharedArrayBuffers, when cloned, do not give back the same object + + + + + + +
+ + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-dedicatedworker.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-dedicatedworker.html new file mode 100644 index 000000000000..de097b26c417 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-dedicatedworker.html @@ -0,0 +1,14 @@ + + +Structured cloning of SharedArrayBuffers into a dedicated worker nested inside a dedicated worker + + + + + +
+ + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-sharedworker.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-sharedworker.html new file mode 100644 index 000000000000..cf328be87996 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-sharedworker.html @@ -0,0 +1,14 @@ + + +Structured cloning of SharedArrayBuffers into a dedicated worker nested inside a shared worker + + + + + +
+ + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.js new file mode 100644 index 000000000000..e1a28436e0af --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.js @@ -0,0 +1,11 @@ +"use strict"; +importScripts("/resources/testharness.js"); +importScripts("resources/test-incrementer.js"); + +promise_test(t => { + const worker = new Worker("resources/incrementer-worker.js"); + + return testSharingViaIncrementerScript(t, worker, "parent worker", worker, "sub-worker"); +}, "postMessaging to a dedicated sub-worker allows them to see each others' modifications"); + +done(); diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.html new file mode 100644 index 000000000000..ece74e271944 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.html @@ -0,0 +1,31 @@ + + +SharedArrayBuffers cannot be transferred + + + + + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html new file mode 100644 index 000000000000..eec1b2cc8e36 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html @@ -0,0 +1,2 @@ + +Used as a service worker-controlled iframe diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html new file mode 100644 index 000000000000..792d6fd20138 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html @@ -0,0 +1,19 @@ + + +A test page that messes with a given SharedArrayBuffer sent from a BroadcastChannel + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js new file mode 100644 index 000000000000..310e0e935844 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js @@ -0,0 +1,7 @@ +const channel = new BroadcastChannel("anne was here"); +channel.onmessageerror = ({ data }) => { + if(data === null) { + channel.postMessage("sw-success"); + } +} +channel.postMessage("hi"); diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js new file mode 100644 index 000000000000..36369cde5004 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js @@ -0,0 +1,9 @@ +const channel = new BroadcastChannel("anne was here"); +channel.onmessage = ({ data }) => { + if(data === "hi" || data === "sw-success") { + return; + } else if(data instanceof SharedArrayBuffer) { + channel.postMessage("dw-success"); + } +} +channel.postMessage("hi"); diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/echo-iframe.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/echo-iframe.html new file mode 100644 index 000000000000..c4fd5824a1c6 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/echo-iframe.html @@ -0,0 +1,11 @@ + + +A test page that echos back anything postMessaged to it to its parent + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/echo-worker.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/echo-worker.js new file mode 100644 index 000000000000..cbbde8a73c8c --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/echo-worker.js @@ -0,0 +1,5 @@ +"use strict"; + +self.onmessage = ({ data }) => { + self.postMessage(data); +}; diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-domain.sub.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-domain.sub.html new file mode 100644 index 000000000000..a6dd70177584 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-domain.sub.html @@ -0,0 +1,11 @@ + + +A test page that messes with a given SharedArrayBuffer and also sets document.domain + + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html new file mode 100644 index 000000000000..6f27ad7d5bec --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html @@ -0,0 +1,10 @@ + + +A test page that messes with a given SharedArrayBuffer + + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html new file mode 100644 index 000000000000..e583b5c4161b --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html @@ -0,0 +1,10 @@ + + +A test page that messes with a given SharedArrayBuffer + + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js new file mode 100644 index 000000000000..c74fd26d3fd6 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js @@ -0,0 +1,7 @@ +"use strict"; +importScripts("./test-incrementer.js"); + +self.onmessage = ({ data }) => { + // data will be a MessagePort + setupDestinationIncrementer(data, data); +}; diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js new file mode 100644 index 000000000000..5801bd2b97c8 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js @@ -0,0 +1,4 @@ +"use strict"; +importScripts("./test-incrementer.js"); + +setupDestinationIncrementer(self, self); diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html new file mode 100644 index 000000000000..fe93cc0c4b0f --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html @@ -0,0 +1,5 @@ + + +Nesting level 1 + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html new file mode 100644 index 000000000000..fad52ce9de39 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html @@ -0,0 +1,5 @@ + + +Nesting level 2 + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html new file mode 100644 index 000000000000..7971022b2cdc --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html @@ -0,0 +1,5 @@ + + +Nesting level 3 + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html new file mode 100644 index 000000000000..d374515bdc73 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html @@ -0,0 +1,10 @@ + + +A test page that messes with a given SharedArrayBuffer, nested 4 levels deep in iframes + + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js new file mode 100644 index 000000000000..c6f2046878cc --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js @@ -0,0 +1,32 @@ +"use strict"; +self.importScripts("/resources/testharness.js"); + +let state = "start in worker"; + +self.onmessage = e => { + if (e.data === "start in window") { + assert_equals(state, "start in worker"); + e.source.postMessage(state); + state = "we are expecting a messageerror due to the window sending us a SAB"; + } else if (e.data === "we are expecting a messageerror due to the worker sending us a SAB") { + assert_equals(state, "onmessageerror was received in worker"); + e.source.postMessage(new SharedArrayBuffer()); + state = "done in worker"; + } else { + e.source.postMessage(`worker onmessage was reached when in state "${state}" and data ${e.data}`); + } +}; + +self.onmessageerror = e => { + if (state === "we are expecting a messageerror due to the window sending us a SAB") { + assert_equals(e.data, null, "data"); + assert_equals(e.origin, self.origin, "origin"); + assert_not_equals(e.source, null, "source"); + assert_equals(e.ports.length, 0, "ports length"); + + state = "onmessageerror was received in worker"; + e.source.postMessage(state); + } else { + e.source.postMessage(`worker onmessageerror was reached when in state "${state}" and data ${e.data}`); + } +}; diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js new file mode 100644 index 000000000000..a11ccbc1f309 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js @@ -0,0 +1,17 @@ +let state = "send-sw-failure" +onconnect = initialE => { + initialE.source.postMessage(state) + initialE.source.onmessage = e => { + if(state === "" && e.data === "send-window-failure") { + e.postMessage(new SharedArrayBuffer()) + } else { + e.postMessage("failure") + } + } + initialE.source.onmessageerror = e => { + if(state === "send-sw-failure") { + e.postMessage("send-sw-failure-success") + state = "" + } + } +} diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-incrementer.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-incrementer.js new file mode 100644 index 000000000000..2bdd2bae66e1 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-incrementer.js @@ -0,0 +1,73 @@ +"use strict"; + +self.getViewValue = (view, index) => { + if(view instanceof DataView) { + return view.getInt8(index); + } + return view[index]; +}; + +self.setViewValue = (view, index, value) => { + if(view instanceof DataView) { + view.setInt8(index, value); + } else { + view[index] = value; + } +}; + +self.testSharingViaIncrementerScript = (t, whereToListen, whereToListenLabel, whereToSend, whereToSendLabel, origin, type = "Int32Array") => { + return new Promise(resolve => { + const sab = new SharedArrayBuffer(8); + const view = new self[type](sab); + setViewValue(view, 0, 1); + + whereToListen.onmessage = t.step_func(({ data }) => { + switch (data.message) { + case "initial payload received": { + assert_equals(data.value, 1, `The ${whereToSendLabel} must see the same value in the SharedArrayBuffer`); + break; + } + + case "changed to 2": { + assert_equals(getViewValue(view, 0), 2, `The ${whereToListenLabel} must see changes made in the ${whereToSendLabel}`); + + setViewValue(view, 0, 3); + whereToSend.postMessage({ message: "changed to 3" }, origin); + + break; + } + + case "changed to 3 received": { + assert_equals(data.value, 3, `The ${whereToSendLabel} must see changes made in the ${whereToListenLabel}`); + resolve(); + break; + } + } + }); + + whereToSend.postMessage({ message: "initial payload", view }, origin); + }); +}; + +self.setupDestinationIncrementer = (whereToListen, whereToSendBackTo, origin) => { + let view; + whereToListen.onmessage = ({ data }) => { + switch (data.message) { + case "initial payload": { + view = data.view; + whereToSendBackTo.postMessage({ message: "initial payload received", value: getViewValue(view, 0) }, origin); + + setViewValue(view, 0, 2); + whereToSendBackTo.postMessage({ message: "changed to 2" }, origin); + + break; + } + + case "changed to 3": { + whereToSendBackTo.postMessage({ message: "changed to 3 received", value: getViewValue(view, 0) }, origin); + + break; + } + } + }; +}; diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-sab.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-sab.js new file mode 100644 index 000000000000..6d6efda00db2 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-sab.js @@ -0,0 +1,15 @@ +"use strict"; + +self.assertSABsHaveSameBackingBlock = (originalSAB, clonedSAB) => { + const originalView = new Uint8Array(originalSAB); + const clonedView = new Uint8Array(clonedSAB); + + assert_not_equals(originalSAB, clonedSAB, "the clone must not be the same object"); + + assert_equals(originalView[0], 0, "originalView[0] starts 0"); + assert_equals(clonedView[0], 0, "clonedView[0] starts 0"); + + originalView[0] = 5; + assert_equals(originalView[0], 5, "originalView[0] ends up 5"); + assert_equals(clonedView[0], 5, "clonedView[0] ends up 5"); +}; diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.html new file mode 100644 index 000000000000..49d341f47f9b --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.html @@ -0,0 +1,36 @@ + + +SharedArrayBuffers cloning via history's methods invoking StructuredSerializeForStorage + + + + + + + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js new file mode 100644 index 000000000000..4eb25eb85467 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js @@ -0,0 +1,40 @@ +// META: script=/IndexedDB/support.js +"use strict"; + +async_test(t => { + const openReq = createdb(t); + + openReq.onupgradeneeded = e => { + const db = e.target.result; + const store = db.createObjectStore("store", { keyPath: "key" }); + + assert_throws("DataCloneError", () => { + store.put({ key: 1, property: new SharedArrayBuffer() }); + }); + t.done(); + }; +}, "SharedArrayBuffer cloning via IndexedDB: basic case"); + +async_test(t => { + const openReq = createdb(t); + + openReq.onupgradeneeded = e => { + const db = e.target.result; + const store = db.createObjectStore("store", { keyPath: "key" }); + + let getter1Called = false; + let getter2Called = false; + + assert_throws("DataCloneError", () => { + store.put({ key: 1, property: [ + { get x() { getter1Called = true; return 5; } }, + new SharedArrayBuffer(), + { get x() { getter2Called = true; return 5; } } + ]}); + }); + + assert_true(getter1Called, "The getter before the SAB must have been called"); + assert_false(getter2Called, "The getter after the SAB must not have been called"); + t.done(); + }; +}, "SharedArrayBuffer cloning via the IndexedDB: is interleaved correctly"); diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js new file mode 100644 index 000000000000..2c3fb7be034b --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js @@ -0,0 +1,23 @@ +"use strict"; + +test(() => { + assert_throws("DataCloneError", () => { + new Notification("Bob: Hi", { data: new SharedArrayBuffer() }); + }) +}, "SharedArrayBuffer cloning via the Notifications API's data member: basic case"); + +test(() => { + let getter1Called = false; + let getter2Called = false; + + assert_throws("DataCloneError", () => { + new Notification("Bob: Hi", { data: [ + { get x() { getter1Called = true; return 5; } }, + new SharedArrayBuffer(), + { get x() { getter2Called = true; return 5; } } + ]}); + }); + + assert_true(getter1Called, "The getter before the SAB must have been called"); + assert_false(getter2Called, "The getter after the SAB must not have been called"); +}, "SharedArrayBuffer cloning via the Notifications API's data member: is interleaved correctly"); diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-success.sub.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-success.sub.html new file mode 100644 index 000000000000..9205d01df26e --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-success.sub.html @@ -0,0 +1,26 @@ + + +Structured cloning of SharedArrayBuffers into same-origin-domain windows + + + + + + +
+ + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.html new file mode 100644 index 000000000000..cd67e5b2c955 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.html @@ -0,0 +1,22 @@ + + +Structured cloning of SharedArrayBuffers using MessageChannel + + + + + + +
+ + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html new file mode 100644 index 000000000000..ff7449a93177 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html @@ -0,0 +1,54 @@ + + +SharedArrayBuffer cannot cross agent clusters, service worker edition + + + + + + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.html new file mode 100644 index 000000000000..023cb5acdef1 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.html @@ -0,0 +1,31 @@ + +SharedArrayBuffer cannot cross agent clusters, shared worker edition + + + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-similar-but-cross-origin-success.sub.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-similar-but-cross-origin-success.sub.html new file mode 100644 index 000000000000..e25fc9002d02 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-similar-but-cross-origin-success.sub.html @@ -0,0 +1,26 @@ + + +Structured cloning of SharedArrayBuffers to similar-origin, but not same-origin, windows + + + + + + +
+ + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.html new file mode 100644 index 000000000000..4b86f9befa6a --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.html @@ -0,0 +1,70 @@ + + +Structured cloning of SharedArrayBuffers: simple success cases that don't need dedicated files + + + + + + +
+ + diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured_clone_blob.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured_clone_blob.html new file mode 100644 index 000000000000..6b1abf5ef8d3 --- /dev/null +++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured_clone_blob.html @@ -0,0 +1,35 @@ + + + + +Safe passing of structured data - Blob + + + + + + + diff --git a/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/iframe-body-margin-attributes.html b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/iframe-body-margin-attributes.html new file mode 100644 index 000000000000..e1f4fb51540f --- /dev/null +++ b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/iframe-body-margin-attributes.html @@ -0,0 +1,32 @@ + +iframe and body margin attributes + + + + + + diff --git a/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/iframe-marginwidth-marginheight.html b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/iframe-marginwidth-marginheight.html new file mode 100644 index 000000000000..b5b49d1b8678 --- /dev/null +++ b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/iframe-marginwidth-marginheight.html @@ -0,0 +1,11 @@ + +iframe marginwidth and marginheight + + + + diff --git a/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/support/body-marginwidth-marginheight.html b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/support/body-marginwidth-marginheight.html new file mode 100644 index 000000000000..5d825e345566 --- /dev/null +++ b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/support/body-marginwidth-marginheight.html @@ -0,0 +1,2 @@ + + diff --git a/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/support/body-topmargin-leftmargin.html b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/support/body-topmargin-leftmargin.html new file mode 100644 index 000000000000..7ba5e5333054 --- /dev/null +++ b/testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/support/body-topmargin-leftmargin.html @@ -0,0 +1,2 @@ + + diff --git a/testing/web-platform/tests/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html b/testing/web-platform/tests/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html index 142024e67b77..01df0c547a5c 100644 --- a/testing/web-platform/tests/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html +++ b/testing/web-platform/tests/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html @@ -3,6 +3,10 @@ Canvas fallback content +

This text should be green on a white background diff --git a/testing/web-platform/tests/html/semantics/document-metadata/the-link-element/stylesheet-change-href.html b/testing/web-platform/tests/html/semantics/document-metadata/the-link-element/stylesheet-change-href.html new file mode 100644 index 000000000000..6a3f18de9860 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/document-metadata/the-link-element/stylesheet-change-href.html @@ -0,0 +1,13 @@ + + +Obtaining a new stylesheet removes styles from the previous stylesheet. + + + +

This text should be green on a white background diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-canvas-element/imagedata.html b/testing/web-platform/tests/html/semantics/embedded-content/the-canvas-element/imagedata.html new file mode 100644 index 000000000000..b5b4d0de2757 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/embedded-content/the-canvas-element/imagedata.html @@ -0,0 +1,58 @@ + + +ImageData Tests + + + diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/iframe_harness.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/iframe_harness.js index f4ef511d1de2..2b43c54e2f2e 100644 --- a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/iframe_harness.js +++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/iframe_harness.js @@ -1,15 +1,16 @@ function get_test_results(id) { async_test(function(test) { - var timer = window.setInterval(test.step_func(loop), 100); + test.step_timeout(loop, 100); function loop() { var xhr = new XMLHttpRequest(); xhr.open('GET', 'stash.py?id=' + id); - xhr.onreadystatechange = test.step_func(function() { + xhr.onload = test.step_func(function() { assert_equals(xhr.status, 200); if (xhr.responseText) { assert_equals(xhr.responseText, "OK"); test.done(); - window.clearTimeout(timer); + } else { + test.step_timeout(loop, 100); } }); xhr.send(); diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-img-element/delay-load-event.html b/testing/web-platform/tests/html/semantics/embedded-content/the-img-element/delay-load-event.html new file mode 100644 index 000000000000..c67074a40d89 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/embedded-content/the-img-element/delay-load-event.html @@ -0,0 +1,17 @@ + + +Image element delays window's load event + + + + diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-img-element/document-adopt-base-url.html b/testing/web-platform/tests/html/semantics/embedded-content/the-img-element/document-adopt-base-url.html new file mode 100644 index 000000000000..ea63114d570d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/embedded-content/the-img-element/document-adopt-base-url.html @@ -0,0 +1,14 @@ + + +Document base URL adopted img test + + + + + diff --git a/testing/web-platform/tests/html/semantics/forms/form-control-infrastructure/form_attribute.html b/testing/web-platform/tests/html/semantics/forms/form-control-infrastructure/form_attribute.html new file mode 100644 index 000000000000..dde3250dbf7c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/form-control-infrastructure/form_attribute.html @@ -0,0 +1,233 @@ + + + + + + + +

+
+
+ + + +
+ +
+ +
+
+ + + + diff --git a/testing/web-platform/tests/html/semantics/forms/form-control-infrastructure/form_owner_and_table.html b/testing/web-platform/tests/html/semantics/forms/form-control-infrastructure/form_owner_and_table.html new file mode 100644 index 000000000000..1aa75c27b355 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/form-control-infrastructure/form_owner_and_table.html @@ -0,0 +1,50 @@ + + + + + + + +
+
+ + + + +
+ + + +
+ + + + diff --git a/testing/web-platform/tests/html/semantics/forms/form-control-infrastructure/form_owner_and_table_2.html b/testing/web-platform/tests/html/semantics/forms/form-control-infrastructure/form_owner_and_table_2.html new file mode 100644 index 000000000000..d9aee12b5f35 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/form-control-infrastructure/form_owner_and_table_2.html @@ -0,0 +1,45 @@ + + + + + + + +
+
+ + + + + +
+ + + +
+ + + + diff --git a/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-after-content-change.html b/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-after-content-change.html index 90ebc28a2380..b77bf50d4fca 100644 --- a/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-after-content-change.html +++ b/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-after-content-change.html @@ -3,16 +3,142 @@ Selection indices after content change + + + + diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-autocomplete.html b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-autocomplete.html index c50ea73170d0..5c1d05b301e7 100644 --- a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-autocomplete.html +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-autocomplete.html @@ -47,12 +47,14 @@ autocompletetest(document.forms.autocomplete_off, ["off", "off", "on", "off", ""], "form autocomplete attribute off"); autocompletetest(document.forms.autocomplete_invalid, ["on", "on", "on", "off", ""], "form autocomplete attribute invalid"); - var keywords = [ "name", "honorific-prefix", "given-name", "additional-name", "family-name", "honorific-suffix", "nickname", "username", "new-password", "current-password", "organization-title", "organization", "street-address", "address-line1", "address-line2", "address-line3", "address-level4", "address-level3", "address-level2", "address-level1", "country", "country-name", "postal-code", "cc-name", "cc-given-name", "cc-additional-name", "cc-family-name", "cc-number", "cc-exp", "cc-exp-month", "cc-exp-year", "cc-csc", "cc-type", "transaction-currency", "transaction-amount", "language", "bday", "bday-day", "bday-month", "bday-year", "sex", "url", "photo", "tel", "tel-country-code", "tel-national", "tel-area-code", "tel-local", "tel-local-prefix", "tel-local-suffix", "tel-extension", "email", "impp" ]; + var keywords = [ "on", "off", "name", "honorific-prefix", "given-name", "additional-name", "family-name", "honorific-suffix", "nickname", "username", "new-password", "current-password", "organization-title", "organization", "street-address", "address-line1", "address-line2", "address-line3", "address-level4", "address-level3", "address-level2", "address-level1", "country", "country-name", "postal-code", "cc-name", "cc-given-name", "cc-additional-name", "cc-family-name", "cc-number", "cc-exp", "cc-exp-month", "cc-exp-year", "cc-csc", "cc-type", "transaction-currency", "transaction-amount", "language", "bday", "bday-day", "bday-month", "bday-year", "sex", "url", "photo", "tel", "tel-country-code", "tel-national", "tel-area-code", "tel-local", "tel-local-prefix", "tel-local-suffix", "tel-extension", "email", "impp" ]; keywords.forEach(function(keyword) { test(function(){ var input = document.createElement("input"); - input.setAttribute("autocomplete", keyword); + // Include whitespace to test splitting tokens on whitespace. + // Convert to uppercase to ensure that the tokens are normalized to lowercase. + input.setAttribute("autocomplete", " " + keyword.toUpperCase() + "\t"); assert_equals(input.autocomplete, keyword); }, keyword + " is an allowed autocomplete field name"); }); diff --git a/testing/web-platform/tests/html/semantics/interactive-elements/the-dialog-element/centering-iframe.sub.html b/testing/web-platform/tests/html/semantics/interactive-elements/the-dialog-element/centering-iframe.sub.html new file mode 100644 index 000000000000..2f9721eee86f --- /dev/null +++ b/testing/web-platform/tests/html/semantics/interactive-elements/the-dialog-element/centering-iframe.sub.html @@ -0,0 +1,28 @@ + + +dialog element centered frame + + +
+ X +
+ + diff --git a/testing/web-platform/tests/html/semantics/interactive-elements/the-dialog-element/centering.html b/testing/web-platform/tests/html/semantics/interactive-elements/the-dialog-element/centering.html new file mode 100644 index 000000000000..8df2d3052320 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/interactive-elements/the-dialog-element/centering.html @@ -0,0 +1,51 @@ + + +dialog element: centered alignment + + + + +
+ + diff --git a/testing/web-platform/tests/html/semantics/interactive-elements/the-menu-element/menuitem-label.html b/testing/web-platform/tests/html/semantics/interactive-elements/the-menu-element/menuitem-label.html new file mode 100644 index 000000000000..3f0f9abf9db7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/interactive-elements/the-menu-element/menuitem-label.html @@ -0,0 +1,19 @@ + + + + +item2 + item 3 +item4 + + + diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html new file mode 100644 index 000000000000..a9556b1a29e2 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html @@ -0,0 +1,22 @@ + + + + + + html-script-module-instantiation-error-1 + + + + +

html-script-module-instantiation-error-1

+ + + + + diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js new file mode 100644 index 000000000000..e317b01cc213 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js @@ -0,0 +1 @@ +import something from "./instantiation-error-1.js"; diff --git a/testing/web-platform/tests/html/semantics/tabular-data/processing-model-1/span-limits.html b/testing/web-platform/tests/html/semantics/tabular-data/processing-model-1/span-limits.html new file mode 100644 index 000000000000..176ce09925ce --- /dev/null +++ b/testing/web-platform/tests/html/semantics/tabular-data/processing-model-1/span-limits.html @@ -0,0 +1,65 @@ + +Limits on colSpan/rowSpan + + +
+ + +
aa + +
a +
+ + +
aa + +
a +
+ + + +
a + +
+ + + +
a + +
+ + diff --git a/testing/web-platform/tests/html/semantics/text-level-semantics/the-a-element/a.rel-getter-01.html b/testing/web-platform/tests/html/semantics/text-level-semantics/the-a-element/a.rel-getter-01.html new file mode 100644 index 000000000000..8e47121eb8ca --- /dev/null +++ b/testing/web-platform/tests/html/semantics/text-level-semantics/the-a-element/a.rel-getter-01.html @@ -0,0 +1,19 @@ + +HTMLAnchorElement.rel getter + + + + +
+
+ +
+ diff --git a/testing/web-platform/tests/html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html b/testing/web-platform/tests/html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html new file mode 100644 index 000000000000..83c69de30142 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html @@ -0,0 +1,20 @@ + +HTMLAnchorElement.rel setter + + + + +
+
+ +
+ diff --git a/testing/web-platform/tests/html/syntax/serializing-html-fragments/serializing.html b/testing/web-platform/tests/html/syntax/serializing-html-fragments/serializing.html index 6b7e678a355e..6a6f0c1d7464 100644 --- a/testing/web-platform/tests/html/syntax/serializing-html-fragments/serializing.html +++ b/testing/web-platform/tests/html/syntax/serializing-html-fragments/serializing.html @@ -178,7 +178,7 @@ var text_tests = [ var void_elements = [ "area", "base", "basefont", "bgsound", "br", "col", "embed", - "frame", "hr", "img", "input", "keygen", "link", "menuitem", + "frame", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr" ]; diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-dedicatedworker.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-dedicatedworker.html new file mode 100644 index 000000000000..0d559999f3fa --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-dedicatedworker.html @@ -0,0 +1,13 @@ + + +[[CanBlock]] in a dedicated worker agent + + + + + + + diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-serviceworker.https.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-serviceworker.https.html new file mode 100644 index 000000000000..6bfd29e8c74b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-serviceworker.https.html @@ -0,0 +1,14 @@ + + +[[CanBlock]] in a service worker agent + + + + + + + + diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html new file mode 100644 index 000000000000..beb7c6467b24 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html @@ -0,0 +1,13 @@ + + +[[CanBlock]] in a shared worker agent + + + + + + + diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-window.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-window.html new file mode 100644 index 000000000000..369ce77b0b62 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-window.html @@ -0,0 +1,21 @@ + + +[[CanBlock]] in a similar-origin window agent + + + + + + + diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/worker-that-requires-failure.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/worker-that-requires-failure.js new file mode 100644 index 000000000000..586c8ba38764 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/worker-that-requires-failure.js @@ -0,0 +1,13 @@ +"use strict"; +importScripts("/resources/testharness.js"); + +test(() => { + const sab = new SharedArrayBuffer(16); + const ta = new Int32Array(sab); + + assert_throws(new TypeError(), () => { + Atomics.wait(ta, 0, 0, 10); + }); +}, `[[CanBlock]] in a ${self.constructor.name}`); + +done(); diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/worker-that-requires-success.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/worker-that-requires-success.js new file mode 100644 index 000000000000..2ed54143ee55 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/worker-that-requires-success.js @@ -0,0 +1,11 @@ +"use strict"; +importScripts("/resources/testharness.js"); + +test(() => { + const sab = new SharedArrayBuffer(16); + const ta = new Int32Array(sab); + + assert_equals(Atomics.wait(ta, 0, 0, 10), "timed-out"); +}, `[[CanBlock]] in a ${self.constructor.name}`); + +done(); diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html index 386af169a641..c76d531c43ec 100644 --- a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html @@ -27,9 +27,11 @@ async_test(function(t) { }; var p = Promise.reject(e); - setTimeout(t.step_func(function() { - // This will cause onrejectionhandled - p.catch(function() {}); - }), 1); + setTimeout(function() { + setTimeout(t.step_func(function() { + // This will cause onrejectionhandled + p.catch(function() {}); + }), 0); + }, 0); }, 'Throwing inside an unhandledrejection handler invokes the error handler.'); diff --git a/testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.worker.js b/testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.worker.js deleted file mode 100644 index 9ba7defa1fbb..000000000000 --- a/testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.worker.js +++ /dev/null @@ -1,4 +0,0 @@ -importScripts("/resources/testharness.js") -importScripts("NavigatorID.js") -run_test(); -done(); diff --git a/testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.js b/testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator.any.js similarity index 97% rename from testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.js rename to testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator.any.js index 78706f44d741..8cfaef024a0a 100644 --- a/testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.js +++ b/testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator.any.js @@ -1,4 +1,3 @@ -function run_test() { var compatibilityMode; if (navigator.userAgent.includes("Chrome")) { compatibilityMode = "Chrome"; @@ -50,7 +49,7 @@ function run_test() { async_test(function() { var request = new XMLHttpRequest(); request.onload = this.step_func_done(function() { - assert_equals("user-agent: " + navigator.userAgent + "\n", + assert_equals("User-Agent: " + navigator.userAgent + "\n", request.response, "userAgent should return the value sent in the " + "User-Agent header"); @@ -103,4 +102,5 @@ function run_test() { assert_false("oscpu" in navigator); } }, "oscpu"); -} + +done() diff --git a/testing/web-platform/tests/html/webappapis/timers/negative-setinterval.html b/testing/web-platform/tests/html/webappapis/timers/negative-setinterval.html new file mode 100644 index 000000000000..430d13c58aab --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/timers/negative-setinterval.html @@ -0,0 +1,17 @@ + +Negative timeout in setInterval + + + diff --git a/testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.html b/testing/web-platform/tests/html/webappapis/timers/negative-settimeout.html similarity index 54% rename from testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.html rename to testing/web-platform/tests/html/webappapis/timers/negative-settimeout.html index 1956a202cee1..57e88ee701d8 100644 --- a/testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/NavigatorID.html +++ b/testing/web-platform/tests/html/webappapis/timers/negative-settimeout.html @@ -1,10 +1,8 @@ - -NavigatorID +Negative timeout in setTimeout - -
diff --git a/testing/web-platform/tests/html/webappapis/timers/type-long-setinterval.html b/testing/web-platform/tests/html/webappapis/timers/type-long-setinterval.html new file mode 100644 index 000000000000..af0299599846 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/timers/type-long-setinterval.html @@ -0,0 +1,13 @@ + +Type long timeout for setInterval + + + diff --git a/testing/web-platform/tests/html/webappapis/timers/type-long-settimeout.html b/testing/web-platform/tests/html/webappapis/timers/type-long-settimeout.html new file mode 100644 index 000000000000..31fa4f126421 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/timers/type-long-settimeout.html @@ -0,0 +1,8 @@ + +Type long timeout for setTimeout + + + diff --git a/testing/web-platform/tests/images/apng.png b/testing/web-platform/tests/images/apng.png new file mode 100644 index 000000000000..e96e6471e6a8 Binary files /dev/null and b/testing/web-platform/tests/images/apng.png differ diff --git a/testing/web-platform/tests/interfaces/cssom.idl b/testing/web-platform/tests/interfaces/cssom.idl new file mode 100644 index 000000000000..e5a998ebf5d8 --- /dev/null +++ b/testing/web-platform/tests/interfaces/cssom.idl @@ -0,0 +1,294 @@ +interface MediaList { + stringifier attribute DOMString mediaText; + readonly attribute unsigned long length; + getter DOMString item(unsigned long index); + void appendMedium(DOMString medium); + void deleteMedium(DOMString medium); +}; + +interface StyleSheet { + readonly attribute DOMString type; + readonly attribute DOMString href; + readonly attribute Node ownerNode; + readonly attribute StyleSheet parentStyleSheet; + readonly attribute DOMString title; + [PutForwards=mediaText] readonly attribute MediaList media; + attribute boolean disabled; +}; + +interface CSSStyleSheet : StyleSheet { + readonly attribute CSSRule ownerRule; + readonly attribute CSSRuleList cssRules; + unsigned long insertRule(DOMString rule, unsigned long index); + void deleteRule(unsigned long index); +}; + +typedef sequence StyleSheetList; + +partial interface Document { + [SameObject] readonly attribute StyleSheetList styleSheets; +}; + +[NoInterfaceObject] interface LinkStyle { + readonly attribute StyleSheet sheet; +}; + +ProcessingInstruction implements LinkStyle; + +typedef sequence CSSRuleList; + +interface CSSRule { + // Types + const unsigned short STYLE_RULE = 1; + const unsigned short IMPORT_RULE = 3; + const unsigned short MEDIA_RULE = 4; + const unsigned short FONT_FACE_RULE = 5; + const unsigned short PAGE_RULE = 6; + const unsigned short NAMESPACE_RULE = 10; + readonly attribute unsigned short type; + + // Parsing and serialization + attribute DOMString cssText; + + // Context + readonly attribute CSSRule parentRule; + readonly attribute CSSStyleSheet parentStyleSheet; +}; + +interface CSSStyleRule : CSSRule { + attribute DOMString selectorText; + readonly attribute CSSStyleDeclaration style; +}; + +interface CSSImportRule : CSSRule { + readonly attribute DOMString href; + [PutForwards=mediaText] readonly attribute MediaList media; + readonly attribute CSSStyleSheet styleSheet; +}; + +interface CSSMediaRule : CSSRule { + [PutForwards=mediaText] readonly attribute MediaList media; + readonly attribute CSSRuleList cssRules; + unsigned long insertRule(DOMString rule, unsigned long index); + void deleteRule(unsigned long index); +}; + +interface CSSFontFaceRule : CSSRule { + readonly attribute CSSStyleDeclaration style; +}; + +interface CSSPageRule : CSSRule { + attribute DOMString selectorText; + readonly attribute CSSStyleDeclaration style; +}; + +interface CSSNamespaceRule : CSSRule { + readonly attribute DOMString namespaceURI; + readonly attribute DOMString? prefix; +}; + +interface CSSStyleDeclaration { + attribute DOMString cssText; + + readonly attribute unsigned long length; + DOMString item(unsigned long index); + + DOMString getPropertyValue(DOMString property); + DOMString getPropertyPriority(DOMString property); + void setProperty(DOMString property, DOMString value, optional DOMString priority); + DOMString removeProperty(DOMString property); + + readonly attribute CSSStyleDeclarationValue values; + + readonly attribute CSSRule parentRule; + + // CSS Properties + attribute DOMString azimuth; + attribute DOMString background; + attribute DOMString backgroundAttachment; + attribute DOMString backgroundColor; + attribute DOMString backgroundImage; + attribute DOMString backgroundPosition; + attribute DOMString backgroundRepeat; + attribute DOMString border; + attribute DOMString borderCollapse; + attribute DOMString borderColor; + attribute DOMString borderSpacing; + attribute DOMString borderStyle; + attribute DOMString borderTop; + attribute DOMString borderRight; + attribute DOMString borderBottom; + attribute DOMString borderLeft; + attribute DOMString borderTopColor; + attribute DOMString borderRightColor; + attribute DOMString borderBottomColor; + attribute DOMString borderLeftColor; + attribute DOMString borderTopStyle; + attribute DOMString borderRightStyle; + attribute DOMString borderBottomStyle; + attribute DOMString borderLeftStyle; + attribute DOMString borderTopWidth; + attribute DOMString borderRightWidth; + attribute DOMString borderBottomWidth; + attribute DOMString borderLeftWidth; + attribute DOMString borderWidth; + attribute DOMString bottom; + attribute DOMString captionSide; + attribute DOMString clear; + attribute DOMString clip; + attribute DOMString color; + attribute DOMString content; + attribute DOMString counterIncrement; + attribute DOMString counterReset; + attribute DOMString cue; + attribute DOMString cueAfter; + attribute DOMString cueBefore; + attribute DOMString cursor; + attribute DOMString direction; + attribute DOMString display; + attribute DOMString elevation; + attribute DOMString emptyCells; + attribute DOMString cssFloat; + attribute DOMString font; + attribute DOMString fontFamily; + attribute DOMString fontSize; + attribute DOMString fontSizeAdjust; + attribute DOMString fontStretch; + attribute DOMString fontStyle; + attribute DOMString fontVariant; + attribute DOMString fontWeight; + attribute DOMString height; + attribute DOMString left; + attribute DOMString letterSpacing; + attribute DOMString lineHeight; + attribute DOMString listStyle; + attribute DOMString listStyleImage; + attribute DOMString listStylePosition; + attribute DOMString listStyleType; + attribute DOMString margin; + attribute DOMString marginTop; + attribute DOMString marginRight; + attribute DOMString marginBottom; + attribute DOMString marginLeft; + attribute DOMString marks; + attribute DOMString maxHeight; + attribute DOMString maxWidth; + attribute DOMString minHeight; + attribute DOMString minWidth; + attribute DOMString orphans; + attribute DOMString outline; + attribute DOMString outlineColor; + attribute DOMString outlineStyle; + attribute DOMString outlineWidth; + attribute DOMString overflow; + attribute DOMString padding; + attribute DOMString paddingTop; + attribute DOMString paddingRight; + attribute DOMString paddingBottom; + attribute DOMString paddingLeft; + attribute DOMString page; + attribute DOMString pageBreakAfter; + attribute DOMString pageBreakBefore; + attribute DOMString pageBreakInside; + attribute DOMString pause; + attribute DOMString pauseAfter; + attribute DOMString pauseBefore; + attribute DOMString pitch; + attribute DOMString pitchRange; + attribute DOMString playDuring; + attribute DOMString position; + attribute DOMString quotes; + attribute DOMString richness; + attribute DOMString right; + attribute DOMString size; + attribute DOMString speak; + attribute DOMString speakHeader; + attribute DOMString speakNumeral; + attribute DOMString speakPunctuation; + attribute DOMString speechRate; + attribute DOMString stress; + attribute DOMString tableLayout; + attribute DOMString textAlign; + attribute DOMString textDecoration; + attribute DOMString textIndent; + attribute DOMString textShadow; + attribute DOMString textTransform; + attribute DOMString top; + attribute DOMString unicodeBidi; + attribute DOMString verticalAlign; + attribute DOMString visibility; + attribute DOMString voiceFamily; + attribute DOMString volume; + attribute DOMString whiteSpace; + attribute DOMString widows; + attribute DOMString width; + attribute DOMString wordSpacing; + attribute DOMString zIndex; +}; + +interface CSSStyleDeclarationValue { + // ... + + // CSS Properties + +}; + +interface CSSPropertyValue { + attribute DOMString cssText; +}; + +[NoInterfaceObject] interface CSSMapValue { + getter CSSValue (DOMString name); +}; + +[NoInterfaceObject] interface CSSPropertyValueList { + readonly attribute CSSValue[] list; +}; + +[NoInterfaceObject] interface CSSComponentValue { + readonly attribute DOMString type; + attribute any value; +}; + +[NoInterfaceObject] interface CSSStringComponentValue { + attribute DOMString string; +}; + +[NoInterfaceObject] interface CSSKeywordComponentValue { + attribute DOMString keyword; +}; + +[NoInterfaceObject] interface CSSIdentifierComponentValue { + attribute DOMString identifier; +}; + +[NoInterfaceObject] interface CSSColorComponentValue { + attribute short red; + attribute short green; + attribute short blue; + attribute float alpha; +}; + +[NoInterfaceObject] interface CSSLengthComponentValue { + attribute float em; + attribute float ex; + attribute float px; + // figure out what to do with absolute lengths +}; + +[NoInterfaceObject] interface CSSPercentageComponentValue { + attribute float percent; +}; + +[NoInterfaceObject] interface CSSURLComponentValue { + attribute DOMString? url; +}; + +[NoInterfaceObject] interface ElementCSSInlineStyle { + readonly attribute CSSStyleDeclaration style; +}; + +//partial interface Window { +// CSSStyleDeclaration getComputedStyle(Element elt); +// CSSStyleDeclaration getComputedStyle(Element elt, DOMString pseudoElt); +//}; diff --git a/testing/web-platform/tests/html/dom/resources/untested-interfaces.idl b/testing/web-platform/tests/interfaces/dom.idl similarity index 57% rename from testing/web-platform/tests/html/dom/resources/untested-interfaces.idl rename to testing/web-platform/tests/interfaces/dom.idl index 9a897cfa73df..7e2667ff7d35 100644 --- a/testing/web-platform/tests/html/dom/resources/untested-interfaces.idl +++ b/testing/web-platform/tests/interfaces/dom.idl @@ -1,6 +1,5 @@ -// DOM IDLs -[Constructor(DOMString type, optional EventInit eventInitDict), - Exposed=(Window,Worker)] +[Constructor(DOMString type, optional EventInit eventInitDict)/*, + Exposed=(Window,Worker)*/] interface Event { readonly attribute DOMString type; readonly attribute EventTarget? target; @@ -32,8 +31,8 @@ dictionary EventInit { }; -[Constructor(DOMString type, optional CustomEventInit eventInitDict), - Exposed=(Window,Worker)] +[Constructor(DOMString type, optional CustomEventInit eventInitDict)/*, + Exposed=(Window,Worker)*/] interface CustomEvent : Event { readonly attribute any detail; @@ -45,7 +44,7 @@ dictionary CustomEventInit : EventInit { }; -[Exposed=(Window,Worker)] +//[Exposed=(Window,Worker)] interface EventTarget { void addEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options); void removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options); @@ -548,373 +547,3 @@ interface DOMTokenList { [CEReactions] stringifier attribute DOMString value; // iterable; }; - -// UI Events IDLs -[Constructor(DOMString type, optional UIEventInit eventInitDict)] -interface UIEvent : Event { - readonly attribute WindowProxy? view; - readonly attribute long detail; -}; - -dictionary UIEventInit : EventInit { - WindowProxy? view = null; - long detail = 0; -}; - -[Constructor(DOMString typeArg, optional MouseEventInit mouseEventInitDict)] -interface MouseEvent : UIEvent { - readonly attribute long screenX; - readonly attribute long screenY; - readonly attribute long clientX; - readonly attribute long clientY; - readonly attribute boolean ctrlKey; - readonly attribute boolean shiftKey; - readonly attribute boolean altKey; - readonly attribute boolean metaKey; - readonly attribute short button; - readonly attribute EventTarget? relatedTarget; - // Introduced in DOM Level 3 - readonly attribute unsigned short buttons; - boolean getModifierState (DOMString keyArg); -}; - -dictionary MouseEventInit : EventModifierInit { - long screenX = 0; - long screenY = 0; - long clientX = 0; - long clientY = 0; - short button = 0; - unsigned short buttons = 0; - EventTarget? relatedTarget = null; -}; - -dictionary EventModifierInit : UIEventInit { - boolean ctrlKey = false; - boolean shiftKey = false; - boolean altKey = false; - boolean metaKey = false; - boolean keyModifierStateAltGraph = false; - boolean keyModifierStateCapsLock = false; - boolean keyModifierStateFn = false; - boolean keyModifierStateFnLock = false; - boolean keyModifierStateHyper = false; - boolean keyModifierStateNumLock = false; - boolean keyModifierStateOS = false; - boolean keyModifierStateScrollLock = false; - boolean keyModifierStateSuper = false; - boolean keyModifierStateSymbol = false; - boolean keyModifierStateSymbolLock = false; -}; - -partial interface MouseEvent { - // Deprecated in DOM Level 3 - void initMouseEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, boolean ctrlKeyArg, boolean altKeyArg, boolean shiftKeyArg, boolean metaKeyArg, short buttonArg, EventTarget? relatedTargetArg); -}; - -// Touch Events IDLs -interface Touch { - readonly attribute long identifier; - readonly attribute EventTarget target; - readonly attribute long screenX; - readonly attribute long screenY; - readonly attribute long clientX; - readonly attribute long clientY; - readonly attribute long pageX; - readonly attribute long pageY; -}; - -// CSSOM IDLs -interface MediaList { - stringifier attribute DOMString mediaText; - readonly attribute unsigned long length; - getter DOMString item(unsigned long index); - void appendMedium(DOMString medium); - void deleteMedium(DOMString medium); -}; - -interface StyleSheet { - readonly attribute DOMString type; - readonly attribute DOMString href; - readonly attribute Node ownerNode; - readonly attribute StyleSheet parentStyleSheet; - readonly attribute DOMString title; - [PutForwards=mediaText] readonly attribute MediaList media; - attribute boolean disabled; -}; - -interface CSSStyleSheet : StyleSheet { - readonly attribute CSSRule ownerRule; - readonly attribute CSSRuleList cssRules; - unsigned long insertRule(DOMString rule, unsigned long index); - void deleteRule(unsigned long index); -}; - -typedef sequence StyleSheetList; - -partial interface Document { - [SameObject] readonly attribute StyleSheetList styleSheets; -}; - -[NoInterfaceObject] interface LinkStyle { - readonly attribute StyleSheet sheet; -}; - -ProcessingInstruction implements LinkStyle; - -typedef sequence CSSRuleList; - -interface CSSRule { - // Types - const unsigned short STYLE_RULE = 1; - const unsigned short IMPORT_RULE = 3; - const unsigned short MEDIA_RULE = 4; - const unsigned short FONT_FACE_RULE = 5; - const unsigned short PAGE_RULE = 6; - const unsigned short NAMESPACE_RULE = 10; - readonly attribute unsigned short type; - - // Parsing and serialization - attribute DOMString cssText; - - // Context - readonly attribute CSSRule parentRule; - readonly attribute CSSStyleSheet parentStyleSheet; -}; - -interface CSSStyleRule : CSSRule { - attribute DOMString selectorText; - readonly attribute CSSStyleDeclaration style; -}; - -interface CSSImportRule : CSSRule { - readonly attribute DOMString href; - [PutForwards=mediaText] readonly attribute MediaList media; - readonly attribute CSSStyleSheet styleSheet; -}; - -interface CSSMediaRule : CSSRule { - [PutForwards=mediaText] readonly attribute MediaList media; - readonly attribute CSSRuleList cssRules; - unsigned long insertRule(DOMString rule, unsigned long index); - void deleteRule(unsigned long index); -}; - -interface CSSFontFaceRule : CSSRule { - readonly attribute CSSStyleDeclaration style; -}; - -interface CSSPageRule : CSSRule { - attribute DOMString selectorText; - readonly attribute CSSStyleDeclaration style; -}; - -interface CSSNamespaceRule : CSSRule { - readonly attribute DOMString namespaceURI; - readonly attribute DOMString? prefix; -}; - -interface CSSStyleDeclaration { - attribute DOMString cssText; - - readonly attribute unsigned long length; - DOMString item(unsigned long index); - - DOMString getPropertyValue(DOMString property); - DOMString getPropertyPriority(DOMString property); - void setProperty(DOMString property, DOMString value, optional DOMString priority); - DOMString removeProperty(DOMString property); - - readonly attribute CSSStyleDeclarationValue values; - - readonly attribute CSSRule parentRule; - - // CSS Properties - attribute DOMString azimuth; - attribute DOMString background; - attribute DOMString backgroundAttachment; - attribute DOMString backgroundColor; - attribute DOMString backgroundImage; - attribute DOMString backgroundPosition; - attribute DOMString backgroundRepeat; - attribute DOMString border; - attribute DOMString borderCollapse; - attribute DOMString borderColor; - attribute DOMString borderSpacing; - attribute DOMString borderStyle; - attribute DOMString borderTop; - attribute DOMString borderRight; - attribute DOMString borderBottom; - attribute DOMString borderLeft; - attribute DOMString borderTopColor; - attribute DOMString borderRightColor; - attribute DOMString borderBottomColor; - attribute DOMString borderLeftColor; - attribute DOMString borderTopStyle; - attribute DOMString borderRightStyle; - attribute DOMString borderBottomStyle; - attribute DOMString borderLeftStyle; - attribute DOMString borderTopWidth; - attribute DOMString borderRightWidth; - attribute DOMString borderBottomWidth; - attribute DOMString borderLeftWidth; - attribute DOMString borderWidth; - attribute DOMString bottom; - attribute DOMString captionSide; - attribute DOMString clear; - attribute DOMString clip; - attribute DOMString color; - attribute DOMString content; - attribute DOMString counterIncrement; - attribute DOMString counterReset; - attribute DOMString cue; - attribute DOMString cueAfter; - attribute DOMString cueBefore; - attribute DOMString cursor; - attribute DOMString direction; - attribute DOMString display; - attribute DOMString elevation; - attribute DOMString emptyCells; - attribute DOMString cssFloat; - attribute DOMString font; - attribute DOMString fontFamily; - attribute DOMString fontSize; - attribute DOMString fontSizeAdjust; - attribute DOMString fontStretch; - attribute DOMString fontStyle; - attribute DOMString fontVariant; - attribute DOMString fontWeight; - attribute DOMString height; - attribute DOMString left; - attribute DOMString letterSpacing; - attribute DOMString lineHeight; - attribute DOMString listStyle; - attribute DOMString listStyleImage; - attribute DOMString listStylePosition; - attribute DOMString listStyleType; - attribute DOMString margin; - attribute DOMString marginTop; - attribute DOMString marginRight; - attribute DOMString marginBottom; - attribute DOMString marginLeft; - attribute DOMString marks; - attribute DOMString maxHeight; - attribute DOMString maxWidth; - attribute DOMString minHeight; - attribute DOMString minWidth; - attribute DOMString orphans; - attribute DOMString outline; - attribute DOMString outlineColor; - attribute DOMString outlineStyle; - attribute DOMString outlineWidth; - attribute DOMString overflow; - attribute DOMString padding; - attribute DOMString paddingTop; - attribute DOMString paddingRight; - attribute DOMString paddingBottom; - attribute DOMString paddingLeft; - attribute DOMString page; - attribute DOMString pageBreakAfter; - attribute DOMString pageBreakBefore; - attribute DOMString pageBreakInside; - attribute DOMString pause; - attribute DOMString pauseAfter; - attribute DOMString pauseBefore; - attribute DOMString pitch; - attribute DOMString pitchRange; - attribute DOMString playDuring; - attribute DOMString position; - attribute DOMString quotes; - attribute DOMString richness; - attribute DOMString right; - attribute DOMString size; - attribute DOMString speak; - attribute DOMString speakHeader; - attribute DOMString speakNumeral; - attribute DOMString speakPunctuation; - attribute DOMString speechRate; - attribute DOMString stress; - attribute DOMString tableLayout; - attribute DOMString textAlign; - attribute DOMString textDecoration; - attribute DOMString textIndent; - attribute DOMString textShadow; - attribute DOMString textTransform; - attribute DOMString top; - attribute DOMString unicodeBidi; - attribute DOMString verticalAlign; - attribute DOMString visibility; - attribute DOMString voiceFamily; - attribute DOMString volume; - attribute DOMString whiteSpace; - attribute DOMString widows; - attribute DOMString width; - attribute DOMString wordSpacing; - attribute DOMString zIndex; -}; - -interface CSSStyleDeclarationValue { - // ... - - // CSS Properties - -}; - -interface CSSPropertyValue { - attribute DOMString cssText; -}; - -[NoInterfaceObject] interface CSSMapValue { - getter CSSValue (DOMString name); -}; - -[NoInterfaceObject] interface CSSPropertyValueList { - readonly attribute CSSValue[] list; -}; - -[NoInterfaceObject] interface CSSComponentValue { - readonly attribute DOMString type; - attribute any value; -}; - -[NoInterfaceObject] interface CSSStringComponentValue { - attribute DOMString string; -}; - -[NoInterfaceObject] interface CSSKeywordComponentValue { - attribute DOMString keyword; -}; - -[NoInterfaceObject] interface CSSIdentifierComponentValue { - attribute DOMString identifier; -}; - -[NoInterfaceObject] interface CSSColorComponentValue { - attribute short red; - attribute short green; - attribute short blue; - attribute float alpha; -}; - -[NoInterfaceObject] interface CSSLengthComponentValue { - attribute float em; - attribute float ex; - attribute float px; - // figure out what to do with absolute lengths -}; - -[NoInterfaceObject] interface CSSPercentageComponentValue { - attribute float percent; -}; - -[NoInterfaceObject] interface CSSURLComponentValue { - attribute DOMString? url; -}; - -[NoInterfaceObject] interface ElementCSSInlineStyle { - readonly attribute CSSStyleDeclaration style; -}; - -//partial interface Window { -// CSSStyleDeclaration getComputedStyle(Element elt); -// CSSStyleDeclaration getComputedStyle(Element elt, DOMString pseudoElt); -//}; diff --git a/testing/web-platform/tests/html/dom/resources/interfaces.idl b/testing/web-platform/tests/interfaces/html.idl similarity index 98% rename from testing/web-platform/tests/html/dom/resources/interfaces.idl rename to testing/web-platform/tests/interfaces/html.idl index 26c8cff17a9b..e51b2a12b223 100644 --- a/testing/web-platform/tests/html/dom/resources/interfaces.idl +++ b/testing/web-platform/tests/interfaces/html.idl @@ -168,7 +168,7 @@ interface HTMLLinkElement : HTMLElement { [CEReactions] attribute USVString href; [CEReactions] attribute DOMString? crossOrigin; [CEReactions] attribute DOMString rel; - // [CEReactions] attribute RequestDestination as; // (default "") XXX TODO + [CEReactions] attribute DOMString as; // (default "") [CEReactions, SameObject, PutForwards=value] readonly attribute DOMTokenList relList; [CEReactions] attribute DOMString media; [CEReactions] attribute DOMString nonce; @@ -1621,19 +1621,22 @@ interface DocumentAndElementEventHandlers { [NoInterfaceObject] interface WindowEventHandlers { - attribute EventHandler onafterprint; - attribute EventHandler onbeforeprint; - attribute OnBeforeUnloadEventHandler onbeforeunload; - attribute EventHandler onhashchange; - attribute EventHandler onlanguagechange; - attribute EventHandler onmessage; - attribute EventHandler onoffline; - attribute EventHandler ononline; - attribute EventHandler onpagehide; - attribute EventHandler onpageshow; - attribute EventHandler onpopstate; - attribute EventHandler onstorage; - attribute EventHandler onunload; + attribute EventHandler onafterprint; + attribute EventHandler onbeforeprint; + attribute OnBeforeUnloadEventHandler onbeforeunload; + attribute EventHandler onhashchange; + attribute EventHandler onlanguagechange; + attribute EventHandler onmessage; + attribute EventHandler onmessageerror; + attribute EventHandler onoffline; + attribute EventHandler ononline; + attribute EventHandler onpagehide; + attribute EventHandler onpageshow; + attribute EventHandler onpopstate; + attribute EventHandler onrejectionhandled; + attribute EventHandler onstorage; + attribute EventHandler onunhandledrejection; + attribute EventHandler onunload; }; typedef (DOMString or Function) TimerHandler; @@ -1871,23 +1874,24 @@ interface MessageChannel { readonly attribute MessagePort port2; }; -[Exposed=(Window,Worker)] +[Exposed=(Window,Worker), Transferable] interface MessagePort : EventTarget { - void postMessage(any message, optional sequence transfer); + void postMessage(any message, optional sequence transfer = []); void start(); void close(); // event handlers - attribute EventHandler onmessage; + attribute EventHandler onmessage; + attribute EventHandler onmessageerror; }; -// MessagePort implements Transferable; -[Constructor(DOMString channel), Exposed=(Window,Worker)] +[Constructor(DOMString name), Exposed=(Window,Worker)] interface BroadcastChannel : EventTarget { readonly attribute DOMString name; void postMessage(any message); void close(); - attribute EventHandler onmessage; + attribute EventHandler onmessage; + attribute EventHandler onmessageerror; }; [Exposed=Worker] @@ -1906,9 +1910,13 @@ interface WorkerGlobalScope : EventTarget { }; [Global=(Worker,DedicatedWorker),Exposed=DedicatedWorker] -/*sealed*/ interface DedicatedWorkerGlobalScope : WorkerGlobalScope { - void postMessage(any message, optional sequence transfer); - attribute EventHandler onmessage; +interface DedicatedWorkerGlobalScope : WorkerGlobalScope { + void postMessage(any message, optional sequence transfer = []); + + void close(); + + attribute EventHandler onmessage; + attribute EventHandler onmessageerror; }; [Global=(Worker,SharedWorker),Exposed=SharedWorker] diff --git a/testing/web-platform/tests/interfaces/touchevents.idl b/testing/web-platform/tests/interfaces/touchevents.idl new file mode 100644 index 000000000000..81eec0185c25 --- /dev/null +++ b/testing/web-platform/tests/interfaces/touchevents.idl @@ -0,0 +1,10 @@ +interface Touch { + readonly attribute long identifier; + readonly attribute EventTarget target; + readonly attribute long screenX; + readonly attribute long screenY; + readonly attribute long clientX; + readonly attribute long clientY; + readonly attribute long pageX; + readonly attribute long pageY; +}; diff --git a/testing/web-platform/tests/interfaces/uievents.idl b/testing/web-platform/tests/interfaces/uievents.idl new file mode 100644 index 000000000000..bac832ba436d --- /dev/null +++ b/testing/web-platform/tests/interfaces/uievents.idl @@ -0,0 +1,60 @@ +[Constructor(DOMString type, optional UIEventInit eventInitDict)] +interface UIEvent : Event { + readonly attribute WindowProxy? view; + readonly attribute long detail; +}; + +dictionary UIEventInit : EventInit { + WindowProxy? view = null; + long detail = 0; +}; + +[Constructor(DOMString typeArg, optional MouseEventInit mouseEventInitDict)] +interface MouseEvent : UIEvent { + readonly attribute long screenX; + readonly attribute long screenY; + readonly attribute long clientX; + readonly attribute long clientY; + readonly attribute boolean ctrlKey; + readonly attribute boolean shiftKey; + readonly attribute boolean altKey; + readonly attribute boolean metaKey; + readonly attribute short button; + readonly attribute EventTarget? relatedTarget; + // Introduced in DOM Level 3 + readonly attribute unsigned short buttons; + boolean getModifierState (DOMString keyArg); +}; + +dictionary MouseEventInit : EventModifierInit { + long screenX = 0; + long screenY = 0; + long clientX = 0; + long clientY = 0; + short button = 0; + unsigned short buttons = 0; + EventTarget? relatedTarget = null; +}; + +dictionary EventModifierInit : UIEventInit { + boolean ctrlKey = false; + boolean shiftKey = false; + boolean altKey = false; + boolean metaKey = false; + boolean keyModifierStateAltGraph = false; + boolean keyModifierStateCapsLock = false; + boolean keyModifierStateFn = false; + boolean keyModifierStateFnLock = false; + boolean keyModifierStateHyper = false; + boolean keyModifierStateNumLock = false; + boolean keyModifierStateOS = false; + boolean keyModifierStateScrollLock = false; + boolean keyModifierStateSuper = false; + boolean keyModifierStateSymbol = false; + boolean keyModifierStateSymbolLock = false; +}; + +partial interface MouseEvent { + // Deprecated in DOM Level 3 + void initMouseEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, boolean ctrlKeyArg, boolean altKeyArg, boolean shiftKeyArg, boolean metaKeyArg, short buttonArg, EventTarget? relatedTargetArg); +}; diff --git a/testing/web-platform/tests/interfaces/webrtc-pc.idl b/testing/web-platform/tests/interfaces/webrtc-pc.idl new file mode 100644 index 000000000000..133524a6cdf6 --- /dev/null +++ b/testing/web-platform/tests/interfaces/webrtc-pc.idl @@ -0,0 +1,657 @@ +dictionary RTCConfiguration { + sequence iceServers; + RTCIceTransportPolicy iceTransportPolicy = "all"; + RTCBundlePolicy bundlePolicy = "balanced"; + RTCRtcpMuxPolicy rtcpMuxPolicy = "require"; + DOMString peerIdentity; + sequence certificates; + [EnforceRange] + octet iceCandidatePoolSize = 0; +}; + +enum RTCIceCredentialType { + "password", + "token" +}; + +dictionary RTCIceServer { + required (DOMString or sequence) urls; + DOMString username; + DOMString credential; + RTCIceCredentialType credentialType = "password"; +}; + +enum RTCIceTransportPolicy { + "relay", + "all" +}; + +enum RTCBundlePolicy { + "balanced", + "max-compat", + "max-bundle" +}; + +enum RTCRtcpMuxPolicy { + // At risk due to lack of implementers' interest. + "negotiate", + "require" +}; + +dictionary RTCOfferAnswerOptions { + boolean voiceActivityDetection = true; +}; + +dictionary RTCOfferOptions : RTCOfferAnswerOptions { + boolean iceRestart = false; + boolean offerToReceiveAudio; + boolean offerToReceiveVideo; +}; + +dictionary RTCAnswerOptions : RTCOfferAnswerOptions { +}; + +[Constructor(optional RTCConfiguration configuration)] +interface RTCPeerConnection : EventTarget { + Promise createOffer(optional RTCOfferOptions options); + Promise createAnswer(optional RTCAnswerOptions options); + Promise setLocalDescription(RTCSessionDescriptionInit description); + readonly attribute RTCSessionDescription? localDescription; + readonly attribute RTCSessionDescription? currentLocalDescription; + readonly attribute RTCSessionDescription? pendingLocalDescription; + Promise setRemoteDescription(RTCSessionDescriptionInit description); + readonly attribute RTCSessionDescription? remoteDescription; + readonly attribute RTCSessionDescription? currentRemoteDescription; + readonly attribute RTCSessionDescription? pendingRemoteDescription; + Promise addIceCandidate((RTCIceCandidateInit or RTCIceCandidate) candidate); + readonly attribute RTCSignalingState signalingState; + readonly attribute RTCIceGatheringState iceGatheringState; + readonly attribute RTCIceConnectionState iceConnectionState; + readonly attribute RTCPeerConnectionState connectionState; + readonly attribute boolean? canTrickleIceCandidates; + static readonly attribute FrozenArray defaultIceServers; + RTCConfiguration getConfiguration(); + void setConfiguration(RTCConfiguration configuration); + void close(); + attribute EventHandler onnegotiationneeded; + attribute EventHandler onicecandidate; + attribute EventHandler onicecandidateerror; + attribute EventHandler onsignalingstatechange; + attribute EventHandler oniceconnectionstatechange; + attribute EventHandler onicegatheringstatechange; + attribute EventHandler onconnectionstatechange; + attribute EventHandler onfingerprintfailure; +}; + +partial interface RTCPeerConnection { + Promise createOffer(RTCSessionDescriptionCallback successCallback, + RTCPeerConnectionErrorCallback failureCallback, + optional RTCOfferOptions options); + Promise setLocalDescription(RTCSessionDescriptionInit description, + VoidFunction successCallback, + RTCPeerConnectionErrorCallback failureCallback); + Promise createAnswer(RTCSessionDescriptionCallback successCallback, + RTCPeerConnectionErrorCallback failureCallback); + Promise setRemoteDescription(RTCSessionDescriptionInit description, + VoidFunction successCallback, + RTCPeerConnectionErrorCallback failureCallback); + Promise addIceCandidate((RTCIceCandidateInit or RTCIceCandidate) candidate, + VoidFunction successCallback, + RTCPeerConnectionErrorCallback failureCallback); +}; + +enum RTCSignalingState { + "stable", + "have-local-offer", + "have-remote-offer", + "have-local-pranswer", + "have-remote-pranswer" +}; + +enum RTCIceGatheringState { + "new", + "gathering", + "complete" +}; + +enum RTCPeerConnectionState { + "new", + "connecting", + "connected", + "disconnected", + "failed", + "closed" +}; + +enum RTCIceConnectionState { + "new", + "checking", + "connected", + "completed", + "failed", + "disconnected", + "closed" +}; + +callback RTCPeerConnectionErrorCallback = void (DOMException error); + +callback RTCSessionDescriptionCallback = void (RTCSessionDescriptionInit description); + +callback RTCStatsCallback = void (RTCStatsReport report); + +enum RTCSdpType { + "offer", + "pranswer", + "answer", + "rollback" +}; + +[Constructor(RTCSessionDescriptionInit descriptionInitDict)] +interface RTCSessionDescription { + readonly attribute RTCSdpType type; + readonly attribute DOMString sdp; + serializer = {attribute}; +}; + +dictionary RTCSessionDescriptionInit { + required RTCSdpType type; + DOMString sdp = ""; +}; + +[Constructor(RTCIceCandidateInit candidateInitDict)] +interface RTCIceCandidate { + readonly attribute DOMString candidate; + readonly attribute DOMString? sdpMid; + readonly attribute unsigned short? sdpMLineIndex; + readonly attribute DOMString? foundation; + readonly attribute unsigned long? priority; + readonly attribute DOMString? ip; + readonly attribute RTCIceProtocol? protocol; + readonly attribute unsigned short? port; + readonly attribute RTCIceCandidateType? type; + readonly attribute RTCIceTcpCandidateType? tcpType; + readonly attribute DOMString? relatedAddress; + readonly attribute unsigned short? relatedPort; + readonly attribute DOMString? ufrag; + serializer = {candidate, sdpMid, sdpMLineIndex, ufrag}; +}; + +dictionary RTCIceCandidateInit { + DOMString candidate = ""; + DOMString? sdpMid = null; + unsigned short? sdpMLineIndex = null; + DOMString ufrag; +}; + +enum RTCIceProtocol { + "udp", + "tcp" +}; + +enum RTCIceTcpCandidateType { + "active", + "passive", + "so" +}; + +enum RTCIceCandidateType { + "host", + "srflx", + "prflx", + "relay" +}; + +[Constructor(DOMString type, optional RTCPeerConnectionIceEventInit eventInitDict)] +interface RTCPeerConnectionIceEvent : Event { + readonly attribute RTCIceCandidate? candidate; + readonly attribute DOMString? url; +}; + +dictionary RTCPeerConnectionIceEventInit : EventInit { + RTCIceCandidate? candidate; + DOMString? url; +}; + +[Constructor(DOMString type, RTCPeerConnectionIceErrorEventInit eventInitDict)] +interface RTCPeerConnectionIceErrorEvent : Event { + readonly attribute DOMString hostCandidate; + readonly attribute DOMString url; + readonly attribute unsigned short errorCode; + readonly attribute USVString errorText; +}; + +dictionary RTCPeerConnectionIceErrorEventInit : EventInit { + DOMString hostCandidate; + DOMString url; + required unsigned short errorCode; + USVString statusText; +}; + +enum RTCPriorityType { + "very-low", + "low", + "medium", + "high" +}; + +partial interface RTCPeerConnection { + static Promise generateCertificate(AlgorithmIdentifier keygenAlgorithm); +}; + +dictionary RTCCertificateExpiration { + [EnforceRange] + DOMTimeStamp expires; +}; + +interface RTCCertificate { + readonly attribute DOMTimeStamp expires; + readonly attribute FrozenArray fingerprints; + AlgorithmIdentifier getAlgorithm(); +}; + +partial interface RTCPeerConnection { + sequence getSenders(); + sequence getReceivers(); + sequence getTransceivers(); + RTCRtpSender addTrack(MediaStreamTrack track, + MediaStream... streams); + void removeTrack(RTCRtpSender sender); + RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind, + optional RTCRtpTransceiverInit init); + attribute EventHandler ontrack; +}; + +dictionary RTCRtpTransceiverInit { + RTCRtpTransceiverDirection direction = "sendrecv"; + sequence streams; + sequence sendEncodings; +}; + +enum RTCRtpTransceiverDirection { + "sendrecv", + "sendonly", + "recvonly", + "inactive" +}; + +interface RTCRtpSender { + readonly attribute MediaStreamTrack? track; + readonly attribute RTCDtlsTransport? transport; + readonly attribute RTCDtlsTransport? rtcpTransport; + static RTCRtpCapabilities getCapabilities(DOMString kind); + Promise setParameters(optional RTCRtpParameters parameters); + RTCRtpParameters getParameters(); + Promise replaceTrack(MediaStreamTrack withTrack); +}; + +dictionary RTCRtpParameters { + DOMString transactionId; + sequence encodings; + sequence headerExtensions; + RTCRtcpParameters rtcp; + sequence codecs; + RTCDegradationPreference degradationPreference = "balanced"; +}; + +dictionary RTCRtpEncodingParameters { + unsigned long ssrc; + RTCRtpRtxParameters rtx; + RTCRtpFecParameters fec; + RTCDtxStatus dtx; + boolean active; + RTCPriorityType priority; + unsigned long maxBitrate; + unsigned long maxFramerate; + DOMString rid; + double scaleResolutionDownBy = 1; +}; + +enum RTCDtxStatus { + "disabled", + "enabled" +}; + +enum RTCDegradationPreference { + "maintain-framerate", + "maintain-resolution", + "balanced" +}; + +dictionary RTCRtpRtxParameters { + unsigned long ssrc; +}; + +dictionary RTCRtpFecParameters { + unsigned long ssrc; +}; + +dictionary RTCRtcpParameters { + DOMString cname; + boolean reducedSize; +}; + +dictionary RTCRtpHeaderExtensionParameters { + DOMString uri; + unsigned short id; + boolean encrypted; +}; + +dictionary RTCRtpCodecParameters { + unsigned short payloadType; + DOMString mimeType; + unsigned long clockRate; + unsigned short channels = 1; + DOMString sdpFmtpLine; +}; + +dictionary RTCRtpCapabilities { + sequence codecs; + sequence headerExtensions; +}; + +dictionary RTCRtpCodecCapability { + DOMString mimeType; + unsigned long clockRate; + unsigned short channels = 1; + DOMString sdpFmtpLine; +}; + +dictionary RTCRtpHeaderExtensionCapability { + DOMString uri; +}; + +interface RTCRtpReceiver { + readonly attribute MediaStreamTrack track; + readonly attribute RTCDtlsTransport? transport; + readonly attribute RTCDtlsTransport? rtcpTransport; + static RTCRtpCapabilities getCapabilities(DOMString kind); + RTCRtpParameters getParameters(); + sequence getContributingSources(); +}; + +interface RTCRtpContributingSource { + readonly attribute DOMHighResTimeStamp timestamp; + readonly attribute unsigned long source; + readonly attribute byte? audioLevel; + readonly attribute boolean? voiceActivityFlag; +}; + +interface RTCRtpTransceiver { + readonly attribute DOMString? mid; + [SameObject] + readonly attribute RTCRtpSender sender; + [SameObject] + readonly attribute RTCRtpReceiver receiver; + readonly attribute boolean stopped; + readonly attribute RTCRtpTransceiverDirection direction; + readonly attribute RTCRtpTransceiverDirection? currentDirection; + void setDirection(RTCRtpTransceiverDirection direction); + void stop(); + void setCodecPreferences(sequence codecs); +}; + +interface RTCDtlsTransport { + readonly attribute RTCIceTransport transport; + readonly attribute RTCDtlsTransportState state; + sequence getRemoteCertificates(); + attribute EventHandler onstatechange; +}; + +enum RTCDtlsTransportState { + "new", + "connecting", + "connected", + "closed", + "failed" +}; + +dictionary RTCDtlsFingerprint { + DOMString algorithm; + DOMString value; +}; + +interface RTCIceTransport { + readonly attribute RTCIceRole role; + readonly attribute RTCIceComponent component; + readonly attribute RTCIceTransportState state; + readonly attribute RTCIceGathererState gatheringState; + sequence getLocalCandidates(); + sequence getRemoteCandidates(); + RTCIceCandidatePair? getSelectedCandidatePair(); + RTCIceParameters? getLocalParameters(); + RTCIceParameters? getRemoteParameters(); + attribute EventHandler onstatechange; + attribute EventHandler ongatheringstatechange; + attribute EventHandler onselectedcandidatepairchange; +}; + +dictionary RTCIceParameters { + DOMString usernameFragment; + DOMString password; +}; + +dictionary RTCIceCandidatePair { + RTCIceCandidate local; + RTCIceCandidate remote; +}; + +enum RTCIceGathererState { + "new", + "gathering", + "complete" +}; + +enum RTCIceTransportState { + "new", + "checking", + "connected", + "completed", + "failed", + "disconnected", + "closed" +}; + +enum RTCIceRole { + "controlling", + "controlled" +}; + +enum RTCIceComponent { + "rtp", + "rtcp" +}; + +[Constructor(DOMString type, RTCTrackEventInit eventInitDict)] +interface RTCTrackEvent : Event { + readonly attribute RTCRtpReceiver receiver; + readonly attribute MediaStreamTrack track; + readonly attribute FrozenArray streams; + readonly attribute RTCRtpTransceiver transceiver; +}; + +dictionary RTCTrackEventInit : EventInit { + required RTCRtpReceiver receiver; + required MediaStreamTrack track; + sequence streams = []; + required RTCRtpTransceiver transceiver; +}; + +partial interface RTCPeerConnection { + readonly attribute RTCSctpTransport? sctp; + RTCDataChannel createDataChannel([TreatNullAs=EmptyString] USVString label, + optional RTCDataChannelInit dataChannelDict); + attribute EventHandler ondatachannel; +}; + +interface RTCSctpTransport { + readonly attribute RTCDtlsTransport transport; + readonly attribute unsigned long maxMessageSize; +}; + +interface RTCDataChannel : EventTarget { + readonly attribute USVString label; + readonly attribute boolean ordered; + readonly attribute unsigned short? maxPacketLifeTime; + readonly attribute unsigned short? maxRetransmits; + readonly attribute USVString protocol; + readonly attribute boolean negotiated; + readonly attribute unsigned short? id; + readonly attribute RTCPriorityType priority; + readonly attribute RTCDataChannelState readyState; + readonly attribute unsigned long bufferedAmount; + attribute unsigned long bufferedAmountLowThreshold; + attribute EventHandler onopen; + attribute EventHandler onbufferedamountlow; + attribute EventHandler onerror; + attribute EventHandler onclose; + void close(); + attribute EventHandler onmessage; + attribute DOMString binaryType; + void send(USVString data); + void send(Blob data); + void send(ArrayBuffer data); + void send(ArrayBufferView data); +}; + +dictionary RTCDataChannelInit { + boolean ordered = true; + unsigned short maxPacketLifeTime; + unsigned short maxRetransmits; + USVString protocol = ""; + boolean negotiated = false; + [EnforceRange] + unsigned short id; + RTCPriorityType priority = "low"; +}; + +enum RTCDataChannelState { + "connecting", + "open", + "closing", + "closed" +}; + +[Constructor(DOMString type, RTCDataChannelEventInit eventInitDict)] +interface RTCDataChannelEvent : Event { + readonly attribute RTCDataChannel channel; +}; + +dictionary RTCDataChannelEventInit : EventInit { + required RTCDataChannel channel; +}; + +partial interface RTCRtpSender { + readonly attribute RTCDTMFSender? dtmf; +}; + +interface RTCDTMFSender : EventTarget { + void insertDTMF(DOMString tones, + optional unsigned long duration = 100, + optional unsigned long interToneGap = 70); + attribute EventHandler ontonechange; + readonly attribute DOMString toneBuffer; +}; + +[Constructor(DOMString type, RTCDTMFToneChangeEventInit eventInitDict)] +interface RTCDTMFToneChangeEvent : Event { + readonly attribute DOMString tone; +}; + +dictionary RTCDTMFToneChangeEventInit : EventInit { + required DOMString tone; +}; + +partial interface RTCPeerConnection { + Promise getStats(optional MediaStreamTrack? selector = null); +}; + +interface RTCStatsReport { + readonly maplike; +}; + +dictionary RTCStats { + DOMHighResTimeStamp timestamp; + RTCStatsType type; + DOMString id; +}; + +enum RTCStatsType { +}; + +[Global, + Exposed=RTCIdentityProviderGlobalScope] +interface RTCIdentityProviderGlobalScope : WorkerGlobalScope { + readonly attribute RTCIdentityProviderRegistrar rtcIdentityProvider; +}; + +[Exposed=RTCIdentityProviderGlobalScope] +interface RTCIdentityProviderRegistrar { + void register(RTCIdentityProvider idp); +}; + +dictionary RTCIdentityProvider { + required GenerateAssertionCallback generateAssertion; + required ValidateAssertionCallback validateAssertion; +}; + +callback GenerateAssertionCallback = Promise (DOMString contents, + DOMString origin, + RTCIdentityProviderOptions options); + +callback ValidateAssertionCallback = Promise (DOMString assertion, + DOMString origin); + +dictionary RTCIdentityAssertionResult { + required RTCIdentityProviderDetails idp; + required DOMString assertion; +}; + +dictionary RTCIdentityProviderDetails { + required DOMString domain; + DOMString protocol = "default"; +}; + +dictionary RTCIdentityValidationResult { + required DOMString identity; + required DOMString contents; +}; + +partial interface RTCPeerConnection { + void setIdentityProvider(DOMString provider, + optional RTCIdentityProviderOptions options); + Promise getIdentityAssertion(); + readonly attribute Promise peerIdentity; + readonly attribute DOMString? idpLoginUrl; + readonly attribute DOMString? idpErrorInfo; +}; + +dictionary RTCIdentityProviderOptions { + DOMString protocol = "default"; + DOMString usernameHint; + DOMString peerIdentity; +}; + +[Constructor(DOMString idp, DOMString name)] +interface RTCIdentityAssertion { + attribute DOMString idp; + attribute DOMString name; +}; + +partial dictionary MediaStreamConstraints { + DOMString peerIdentity; +}; + +partial interface MediaStreamTrack { + readonly attribute boolean isolated; + attribute EventHandler onisolationchange; +}; + +[Exposed=Window, + Constructor(DOMString type, RTCErrorEventInit eventInitDict)] +interface RTCErrorEvent : Event { + readonly attribute RTCError? error; +}; + +dictionary RTCErrorEventInit : EventInit { + RTCError? error = null; +}; diff --git a/testing/web-platform/tests/keyboard-lock/idlharness.https.html b/testing/web-platform/tests/keyboard-lock/idlharness.https.html new file mode 100644 index 000000000000..6fabb4117436 --- /dev/null +++ b/testing/web-platform/tests/keyboard-lock/idlharness.https.html @@ -0,0 +1,41 @@ + + + +Keyboard Lock IDL tests + + + + + + + + + + + +
+ + diff --git a/testing/web-platform/tests/keyboard-lock/navigator-cancelKeyboardLock.https.html b/testing/web-platform/tests/keyboard-lock/navigator-cancelKeyboardLock.https.html new file mode 100644 index 000000000000..10fd50d3a79e --- /dev/null +++ b/testing/web-platform/tests/keyboard-lock/navigator-cancelKeyboardLock.https.html @@ -0,0 +1,12 @@ + + + + diff --git a/testing/web-platform/tests/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html b/testing/web-platform/tests/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html new file mode 100644 index 000000000000..8e84d14d465e --- /dev/null +++ b/testing/web-platform/tests/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html @@ -0,0 +1,15 @@ + + + + diff --git a/testing/web-platform/tests/keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html b/testing/web-platform/tests/keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html new file mode 100644 index 000000000000..30f490544956 --- /dev/null +++ b/testing/web-platform/tests/keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html @@ -0,0 +1,14 @@ + + + + diff --git a/testing/web-platform/tests/keyboard-lock/navigator-requestKeyboardLock.https.html b/testing/web-platform/tests/keyboard-lock/navigator-requestKeyboardLock.https.html new file mode 100644 index 000000000000..e6e0121e75ec --- /dev/null +++ b/testing/web-platform/tests/keyboard-lock/navigator-requestKeyboardLock.https.html @@ -0,0 +1,13 @@ + + + + diff --git a/testing/web-platform/tests/lint b/testing/web-platform/tests/lint index d2e5e18cfe06..28434bab3242 100755 --- a/testing/web-platform/tests/lint +++ b/testing/web-platform/tests/lint @@ -8,4 +8,5 @@ except ImportError: '"git submodule update --init --recursive"?') sys.exit(2) -sys.exit(0 if lint.main() == 0 else 1) +args = lint.parse_args() +sys.exit(0 if lint.main(**vars(args)) == 0 else 1) diff --git a/testing/web-platform/tests/lint.whitelist b/testing/web-platform/tests/lint.whitelist index d1514d9d4930..e26431f9a9ff 100644 --- a/testing/web-platform/tests/lint.whitelist +++ b/testing/web-platform/tests/lint.whitelist @@ -145,6 +145,7 @@ TRAILING WHITESPACE:webgl/tools/*.patch SET TIMEOUT: *-manual.* SET TIMEOUT: 2dcontext/* SET TIMEOUT: annotation-model/scripts/ajv.min.js +SET TIMEOUT: apng/animated-png-timeout.html SET TIMEOUT: cookies/resources/testharness-helpers.js SET TIMEOUT: common/reftest-wait.js SET TIMEOUT: conformance-checkers/* @@ -171,6 +172,7 @@ SET TIMEOUT: old-tests/submission/Opera/script_scheduling/* SET TIMEOUT: old-tests/webdriver/timeouts/res/implicit_waits_tests.html SET TIMEOUT: page-visibility/resources/pagevistestharness.js SET TIMEOUT: payment-request/allowpaymentrequest/setting-allowpaymentrequest-timing.https.sub.html +SET TIMEOUT: payment-request/payment-request-response-id.html SET TIMEOUT: pointerevents/pointerevent_support.js SET TIMEOUT: preload/single-download-preload.html SET TIMEOUT: resource-timing/resource-timing.js @@ -213,6 +215,9 @@ SET TIMEOUT: XMLHttpRequest/xmlhttprequest-timeout-reused.html SET TIMEOUT: XMLHttpRequest/resources/init.htm SET TIMEOUT: XMLHttpRequest/resources/xmlhttprequest-timeout.js +# Intentional use of setTimeout +SET TIMEOUT: html/webappapis/timers/* + # CI scripts PRINT STATEMENT:check_stability.py W3C-TEST.ORG:check_stability.py @@ -763,3 +768,12 @@ CSS-COLLIDING-SUPPORT-NAME: css/CSS2/css1/support/pattern-gg-gr.png CSS-COLLIDING-SUPPORT-NAME: css/css-display-3/support/util.js CSS-COLLIDING-SUPPORT-NAME: css/CSS2/normal-flow/support/replaced-min-max-1.png CSS-COLLIDING-SUPPORT-NAME: css/vendor-imports/mozilla/mozilla-central-reftests/ui3/support/replaced-min-max-1.png + +# TODO https://github.com/w3c/web-platform-tests/issues/5770 +MISSING-LINK: css/geometry-1/DOMMatrix-css-string.worker.js +MISSING-LINK: css/geometry-1/WebKitCSSMatrix.worker.js + +WEBIDL2.JS:.gitmodules + +# Manual test that uses console.logs for feedback +CONSOLE:payment-request/payment-request-response-id.html diff --git a/testing/web-platform/tests/magnetometer/Magnetometer.https.html b/testing/web-platform/tests/magnetometer/Magnetometer.https.html new file mode 100644 index 000000000000..bad18f1dea8e --- /dev/null +++ b/testing/web-platform/tests/magnetometer/Magnetometer.https.html @@ -0,0 +1,16 @@ + + +Magnetometer Test + + + + + +
+ + diff --git a/testing/web-platform/tests/magnetometer/Magnetometer_insecure_context.html b/testing/web-platform/tests/magnetometer/Magnetometer_insecure_context.html new file mode 100644 index 000000000000..452bfc1c6eef --- /dev/null +++ b/testing/web-platform/tests/magnetometer/Magnetometer_insecure_context.html @@ -0,0 +1,20 @@ + + +Magnetometer Test: insecure context + + + + + +
+

Precondition

+
    +
  1. + Run test in an insecure context, e.g. http://example.com/. +
  2. +
+ diff --git a/testing/web-platform/tests/magnetometer/Magnetometer_onerror-manual.https.html b/testing/web-platform/tests/magnetometer/Magnetometer_onerror-manual.https.html new file mode 100644 index 000000000000..3cd62db8a225 --- /dev/null +++ b/testing/web-platform/tests/magnetometer/Magnetometer_onerror-manual.https.html @@ -0,0 +1,20 @@ + + +Magnetometer Test: onerror + + + + + +
+

Precondition

+
    +
  1. + Disable the Magnetometer Sensor or run test on a device without Magnetometer Sensor. +
  2. +
+ diff --git a/testing/web-platform/tests/magnetometer/idlharness.https.html b/testing/web-platform/tests/magnetometer/idlharness.https.html index 00fdafee664f..55a0851e1ec6 100644 --- a/testing/web-platform/tests/magnetometer/idlharness.https.html +++ b/testing/web-platform/tests/magnetometer/idlharness.https.html @@ -2,7 +2,8 @@ Magnetometer Sensor IDL tests - + + @@ -18,24 +19,24 @@ interface Event { }; -interface EventTarget { -}; - -interface EventHandler { -}; - interface Error { }; dictionary EventInit { }; + +interface EventTarget { +}; + +interface EventHandler { +};
 [SecureContext]
 interface Sensor : EventTarget {
-  readonly attribute SensorState state;
-  readonly attribute SensorReading? reading;
+  readonly attribute boolean activated;
+  readonly attribute DOMHighResTimeStamp? timestamp;
   void start();
   void stop();
   attribute EventHandler onchange;
@@ -47,18 +48,6 @@ dictionary SensorOptions {
   double? frequency;
 };
 
-enum SensorState {
-  "idle",
-  "activating",
-  "activated",
-  "errored"
-};
-
-[SecureContext]
-interface SensorReading {
-  readonly attribute DOMHighResTimeStamp timeStamp;
-};
-
 [SecureContext, Constructor(DOMString type, SensorErrorEventInit errorEventInitDict)]
 interface SensorErrorEvent : Event {
   readonly attribute Error error;
@@ -67,42 +56,31 @@ interface SensorErrorEvent : Event {
 dictionary SensorErrorEventInit : EventInit {
   required Error error;
 };
-
 
 [Constructor(optional SensorOptions sensorOptions)]
 interface Magnetometer : Sensor {
-  readonly attribute MagnetometerReading? reading;
-};
-
-[Constructor(MagnetometerReadingInit magnetometerReadingInit)]
-interface MagnetometerReading : SensorReading {
-    readonly attribute double x;
-    readonly attribute double y;
-    readonly attribute double z;
-};
-
-dictionary MagnetometerReadingInit {
-  double x = 0;
-  double y = 0;
-  double z = 0;
+  readonly attribute unrestricted double? x;
+  readonly attribute unrestricted double? y;
+  readonly attribute unrestricted double? z;
 };
 
diff --git a/testing/web-platform/tests/magnetometer/support-iframe.html b/testing/web-platform/tests/magnetometer/support-iframe.html new file mode 100644 index 000000000000..5328f6273f0a --- /dev/null +++ b/testing/web-platform/tests/magnetometer/support-iframe.html @@ -0,0 +1,10 @@ + + + diff --git a/testing/web-platform/tests/media-capabilities/query.html b/testing/web-platform/tests/media-capabilities/decodingInfo.html similarity index 77% rename from testing/web-platform/tests/media-capabilities/query.html rename to testing/web-platform/tests/media-capabilities/decodingInfo.html index f1bd22ba1ae3..a0e0d342682b 100644 --- a/testing/web-platform/tests/media-capabilities/query.html +++ b/testing/web-platform/tests/media-capabilities/decodingInfo.html @@ -1,5 +1,5 @@ -MediaCapabilities.query() +MediaCapabilities.decodingInfo() diff --git a/testing/web-platform/tests/media-capabilities/idlharness.html b/testing/web-platform/tests/media-capabilities/idlharness.html index af0669bfd2a6..3efe5a644883 100644 --- a/testing/web-platform/tests/media-capabilities/idlharness.html +++ b/testing/web-platform/tests/media-capabilities/idlharness.html @@ -24,13 +24,19 @@ interface WorkerNavigator {
 dictionary MediaConfiguration {
-  required MediaConfigurationType type;
-
   VideoConfiguration video;
   AudioConfiguration audio;
 };
 
-enum MediaConfigurationType {
+dictionary MediaDecodingConfiguration : MediaConfiguration {
+  required MediaDecodingType type;
+};
+
+dictionary MediaEncodingConfiguration : MediaConfiguration {
+  required MediaEncodingType type;
+};
+
+enum MediaDecodingType {
   "file",
   "media-source",
 };
@@ -50,7 +56,7 @@ dictionary AudioConfiguration {
   unsigned long samplerate;
 };
 
-interface MediaDecodingAbility {
+interface MediaCapabilitiesInfo {
   readonly attribute boolean supported;
   readonly attribute boolean smooth;
   readonly attribute boolean powerEfficient;
@@ -68,7 +74,8 @@ partial interface WorkerNavigator {
 
 [Exposed=(Window, Worker)]
 interface MediaCapabilities {
-  Promise query(MediaConfiguration configuration);
+  Promise decodingInfo(MediaDecodingConfiguration configuration);
+  Promise encodingInfo(MediaEncodingConfiguration configuration);
 };
 
+ + + + + + + + + + +
+ + diff --git a/testing/web-platform/tests/mixed-content/imageset.https.sub.html b/testing/web-platform/tests/mixed-content/imageset.https.sub.html new file mode 100644 index 000000000000..dd371566161d --- /dev/null +++ b/testing/web-platform/tests/mixed-content/imageset.https.sub.html @@ -0,0 +1,31 @@ + + + + Mixed-Content: imageset tests + + + + + + + + + + + + + + + + + + diff --git a/testing/web-platform/tests/navigation-timing/nav2_test_document_replaced.html b/testing/web-platform/tests/navigation-timing/nav2_test_document_replaced.html new file mode 100644 index 000000000000..b910f453d129 --- /dev/null +++ b/testing/web-platform/tests/navigation-timing/nav2_test_document_replaced.html @@ -0,0 +1,58 @@ + + + + + Navigation Timing 2 WPT + + + + + + + +

+ Description

+

+ This test validates that a PerformanceNavigatingTiming corresponding to a detached document can't access a different document's state.

+ + + diff --git a/testing/web-platform/tests/navigation-timing/nav2_test_frame_removed.html b/testing/web-platform/tests/navigation-timing/nav2_test_frame_removed.html new file mode 100644 index 000000000000..0bef297d4e7b --- /dev/null +++ b/testing/web-platform/tests/navigation-timing/nav2_test_frame_removed.html @@ -0,0 +1,27 @@ + + + + + Navigation Timing 2 WPT + + + + + + + +

+ Description

+

+ This test validates that PerformanceNavigationTiming::type()'s default value is navigate

+ + + diff --git a/testing/web-platform/tests/navigation-timing/resources/webperftestharness.js b/testing/web-platform/tests/navigation-timing/resources/webperftestharness.js index 750946dde20b..f9b56d986896 100644 --- a/testing/web-platform/tests/navigation-timing/resources/webperftestharness.js +++ b/testing/web-platform/tests/navigation-timing/resources/webperftestharness.js @@ -12,7 +12,6 @@ policies and contribution forms [3]. // Helper Functions for NavigationTiming W3C tests // -var performanceNamespace = window.performance; var timingAttributes = [ 'connectEnd', 'connectStart', @@ -36,32 +35,6 @@ var timingAttributes = [ 'unloadEventStart' ]; -var namespace_check = false; - -// -// All test() functions in the WebPerf test suite should use wp_test() instead. -// -// wp_test() validates the window.performance namespace exists prior to running tests and -// immediately shows a single failure if it does not. -// - -function wp_test(func, msg, properties) -{ - // only run the namespace check once - if (!namespace_check) - { - namespace_check = true; - - if (performanceNamespace === undefined || performanceNamespace == null) - { - // show a single error that window.performance is undefined - test(function() { assert_true(performanceNamespace !== undefined && performanceNamespace != null, "window.performance is defined and not null"); }, "window.performance is defined and not null.", {author:"W3C http://www.w3.org/",help:"http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",assert:"The window.performance attribute provides a hosting area for performance related attributes. "}); - } - } - - test(func, msg, properties); -} - function test_namespace(child_name, skip_root) { if (skip_root === undefined) { @@ -129,16 +102,6 @@ function sleep_milliseconds(n) // Common helper functions // -function test_true(value, msg, properties) -{ - wp_test(function () { assert_true(value, msg); }, msg, properties); -} - -function test_equals(value, equals, msg, properties) -{ - wp_test(function () { assert_equals(value, equals, msg); }, msg, properties); -} - function test_greater_than(value, greater_than, msg, properties) { wp_test(function () { assert_true(value > greater_than, msg); }, msg, properties); diff --git a/testing/web-platform/tests/navigation-timing/test_document_open.html b/testing/web-platform/tests/navigation-timing/test_document_open.html index 078909520421..1986b3fb9862 100644 --- a/testing/web-platform/tests/navigation-timing/test_document_open.html +++ b/testing/web-platform/tests/navigation-timing/test_document_open.html @@ -7,6 +7,7 @@ + + diff --git a/testing/web-platform/tests/navigation-timing/test_navigation_attributes_exist.html b/testing/web-platform/tests/navigation-timing/test_navigation_attributes_exist.html index 465409ea413e..845523d1a2da 100644 --- a/testing/web-platform/tests/navigation-timing/test_navigation_attributes_exist.html +++ b/testing/web-platform/tests/navigation-timing/test_navigation_attributes_exist.html @@ -7,6 +7,7 @@ + diff --git a/testing/web-platform/tests/navigation-timing/test_navigation_redirectCount_none.html b/testing/web-platform/tests/navigation-timing/test_navigation_redirectCount_none.html index 2046b32cd643..eaaef4b514c7 100644 --- a/testing/web-platform/tests/navigation-timing/test_navigation_redirectCount_none.html +++ b/testing/web-platform/tests/navigation-timing/test_navigation_redirectCount_none.html @@ -7,6 +7,7 @@ + diff --git a/testing/web-platform/tests/navigation-timing/test_navigation_type_backforward.html b/testing/web-platform/tests/navigation-timing/test_navigation_type_backforward.html index b201c3adee83..b5920953cbd3 100644 --- a/testing/web-platform/tests/navigation-timing/test_navigation_type_backforward.html +++ b/testing/web-platform/tests/navigation-timing/test_navigation_type_backforward.html @@ -7,6 +7,7 @@ + + diff --git a/testing/web-platform/tests/navigation-timing/test_navigation_type_reload.html b/testing/web-platform/tests/navigation-timing/test_navigation_type_reload.html index 786d1ddca6c8..d3331b819726 100644 --- a/testing/web-platform/tests/navigation-timing/test_navigation_type_reload.html +++ b/testing/web-platform/tests/navigation-timing/test_navigation_type_reload.html @@ -7,6 +7,7 @@ + + + diff --git a/testing/web-platform/tests/navigation-timing/test_performance_attributes_exist_in_object.html b/testing/web-platform/tests/navigation-timing/test_performance_attributes_exist_in_object.html index 0464758c62b1..9035522aee99 100644 --- a/testing/web-platform/tests/navigation-timing/test_performance_attributes_exist_in_object.html +++ b/testing/web-platform/tests/navigation-timing/test_performance_attributes_exist_in_object.html @@ -7,6 +7,7 @@ + + diff --git a/testing/web-platform/tests/navigation-timing/test_timing_attributes_exist.html b/testing/web-platform/tests/navigation-timing/test_timing_attributes_exist.html index f3dea6838c40..5db07459b4e6 100644 --- a/testing/web-platform/tests/navigation-timing/test_timing_attributes_exist.html +++ b/testing/web-platform/tests/navigation-timing/test_timing_attributes_exist.html @@ -7,6 +7,7 @@ + diff --git a/testing/web-platform/tests/navigation-timing/test_timing_attributes_order.html b/testing/web-platform/tests/navigation-timing/test_timing_attributes_order.html index e3a0758f17b2..03c2619cb3e4 100644 --- a/testing/web-platform/tests/navigation-timing/test_timing_attributes_order.html +++ b/testing/web-platform/tests/navigation-timing/test_timing_attributes_order.html @@ -7,6 +7,7 @@ + + + + + + diff --git a/testing/web-platform/tests/orientation-sensor/OWNERS b/testing/web-platform/tests/orientation-sensor/OWNERS new file mode 100644 index 000000000000..cc7c3879319b --- /dev/null +++ b/testing/web-platform/tests/orientation-sensor/OWNERS @@ -0,0 +1,5 @@ +@zqzhang +@dontcallmedom +@tobie +@riju +@Honry diff --git a/testing/web-platform/tests/orientation-sensor/idlharness.https.html b/testing/web-platform/tests/orientation-sensor/idlharness.https.html new file mode 100644 index 000000000000..8f556ca31640 --- /dev/null +++ b/testing/web-platform/tests/orientation-sensor/idlharness.https.html @@ -0,0 +1,89 @@ + + +Orientation Sensor IDL tests + + + + + + + + +
+ +
+interface Event {
+};
+
+interface Error {
+};
+
+dictionary EventInit {
+};
+
+interface EventTarget {
+};
+
+interface EventHandler {
+};
+
+ +
+[SecureContext]
+interface Sensor : EventTarget {
+  readonly attribute boolean activated;
+  readonly attribute DOMHighResTimeStamp? timestamp;
+  void start();
+  void stop();
+  attribute EventHandler onchange;
+  attribute EventHandler onactivate;
+  attribute EventHandler onerror;
+};
+
+dictionary SensorOptions {
+  double? frequency;
+};
+
+[SecureContext, Constructor(DOMString type, SensorErrorEventInit errorEventInitDict)]
+interface SensorErrorEvent : Event {
+  readonly attribute Error error;
+};
+
+dictionary SensorErrorEventInit : EventInit {
+  required Error error;
+};
+
+ +
+typedef (Float32Array or Float64Array or DOMMatrix) RotationMatrixType;
+interface OrientationSensor : Sensor {
+  readonly attribute FrozenArray? quaternion;
+  void populateMatrix(RotationMatrixType targetMatrix);
+};
+
+[Constructor(optional SensorOptions sensorOptions)]
+interface AbsoluteOrientationSensor : OrientationSensor {
+};
+
+ + diff --git a/testing/web-platform/tests/page-visibility/prerender_call.html b/testing/web-platform/tests/page-visibility/prerender_call.html new file mode 100644 index 000000000000..ed9e54a1dd8e --- /dev/null +++ b/testing/web-platform/tests/page-visibility/prerender_call.html @@ -0,0 +1,22 @@ + + + + +Prerender test for Page Visibility API + + + + +

Description

+

This document validate that visibilityState of a target page was set to "prerender" when it has been prerendered.

+ + diff --git a/testing/web-platform/tests/page-visibility/resources/prerender_target.html b/testing/web-platform/tests/page-visibility/resources/prerender_target.html new file mode 100644 index 000000000000..73108e8ab9f2 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/resources/prerender_target.html @@ -0,0 +1,13 @@ + + + + Document has been prerendered + + + + + \ No newline at end of file diff --git a/testing/web-platform/tests/payment-request/payment-request-id.https.html b/testing/web-platform/tests/payment-request/payment-request-id.https.html new file mode 100644 index 000000000000..8e3c34461706 --- /dev/null +++ b/testing/web-platform/tests/payment-request/payment-request-id.https.html @@ -0,0 +1,18 @@ + + + +Test for PaymentRequest identifier usage + + + + diff --git a/testing/web-platform/tests/payment-request/payment-request-response-id.html b/testing/web-platform/tests/payment-request/payment-request-response-id.html new file mode 100644 index 000000000000..a28f3b24c6f3 --- /dev/null +++ b/testing/web-platform/tests/payment-request/payment-request-response-id.html @@ -0,0 +1,140 @@ + + + + + + PaymentRequest identifier manual test + + +
+

PaymentRequest identifier manual test

+

Perform the following steps:

+
    +
  • Press 'Buy'
  • +
  • In the payment dialog make sure a payment app is selected
  • +
  • In the payment dialog press 'Pay'
  • +
  • In the launched payment app perform steps to do the payment
  • +
  • The response will be processed and below should display 'my_payment_id'
  • +
+

No payment will be processed.

+

Price: USD $55.00

+

+
+

+  
+
+
+
diff --git a/testing/web-platform/tests/pointerevents/extension/pointerevent_coalesced_events_attributes-manual.html b/testing/web-platform/tests/pointerevents/extension/pointerevent_coalesced_events_attributes-manual.html
index 4610806b3fca..89149468a5d2 100644
--- a/testing/web-platform/tests/pointerevents/extension/pointerevent_coalesced_events_attributes-manual.html
+++ b/testing/web-platform/tests/pointerevents/extension/pointerevent_coalesced_events_attributes-manual.html
@@ -77,8 +77,14 @@
                               test (function() {
                                 for (var i=0; i 0)
+                                    assert_greater_than_equal(coalescedEvents[i].timeStamp, coalescedEvents[i-1].timeStamp, 'Time stamps of coalesced events must be ascending.');
                                 }
                               }, expectedPointerType + ' pointermove coalesced events should all be marked as trusted.');
+                              test (function() {
+                                for (var i=1; i target0.getBoundingClientRect().left)&&
                             (event.clientX < target0.getBoundingClientRect().right)&&
                             (event.clientY > target0.getBoundingClientRect().top)&&
                             (event.clientY < target0.getBoundingClientRect().bottom),
                             "pointerleave should be received inside of target bounds");
                     });
-                    test_pointerEvent.done(); // complete test
+                    if (count >= 2)
+                      test_pointerEvent.done(); // complete test
                 });
             }
         
@@ -43,7 +55,7 @@
         

Pointer Event: Dispatch pointerleave (pen)

Test Description: - When a pointing device that supports hover (pen stylus) leaves the range of the digitizer while over an element, the pointerleave event must be dispatched. + When a pointing device that supports hover (pen stylus) leaves the range of the digitizer while over an element, the pointerleave event must be dispatched. In addition, all the pointer events' isPrimary should always be true when the pointing device leaves and enters the range of the digitizer again.


diff --git a/testing/web-platform/tests/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse-manual.html b/testing/web-platform/tests/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse-manual.html index 02bca85008e9..8afa04634bbd 100644 --- a/testing/web-platform/tests/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse-manual.html +++ b/testing/web-platform/tests/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse-manual.html @@ -41,8 +41,9 @@ on_event(document.getElementById("done"), "click", end_of_interaction); var target_list = ["target0", "target1"]; - var pointer_event_list = ["pointerdown"]; + var pointer_event_list = ["pointerdown" , "pointermove", "pointerup"]; var mouse_event_list = ["mousedown", "mouseup", "mousemove"]; + var last_pointer_event = null; target_list.forEach(function(targetId) { var target = document.getElementById(targetId); @@ -52,12 +53,16 @@ detected_pointertypes[event.pointerType] = true; var label = event.type + "@" + targetId; - test(function () { - assert_true(event.isPrimary); - }, "primary pointer " + label); + if (event.type == "pointerdown") { + test(function () { + assert_true(event.isPrimary); + }, "primary pointer " + label); + } if (label === "pointerdown@target0") event.preventDefault(); + + last_pointer_event = event; }); }); @@ -69,6 +74,11 @@ event_log.push(event.type + "@" + targetId); include_next_mousemove = (event.type == "mousedown"); + test(function() { + test(function () { + assert_equals(event.timeStamp, last_pointer_event.timeStamp, "The time stamp of the compat mouse event should be the same as its pointerevent"); + }); + }, event.type + "'s time stamp should be the same as " + last_pointer_event.type + "'s time stamp."); }); }); }); diff --git a/testing/web-platform/tests/preload/download-resources.html b/testing/web-platform/tests/preload/download-resources.html index 3a758cfa18d0..d4165e1c6aba 100644 --- a/testing/web-platform/tests/preload/download-resources.html +++ b/testing/web-platform/tests/preload/download-resources.html @@ -8,7 +8,7 @@ - + @@ -21,7 +21,7 @@ verifyPreloadAndRTSupport() verifyNumberOfDownloads("resources/dummy.js", 1); verifyNumberOfDownloads("resources/dummy.css", 1); - verifyNumberOfDownloads("/media/CanvasTest.ttf", 1); + verifyNumberOfDownloads("/fonts/CanvasTest.ttf", 1); verifyNumberOfDownloads("/media/white.mp4", 1); verifyNumberOfDownloads("/media/sound_5.oga", 1); verifyNumberOfDownloads("/media/foo.vtt", 1); diff --git a/testing/web-platform/tests/preload/onload-event.html b/testing/web-platform/tests/preload/onload-event.html index bd945cb42c70..684f84f9cb3f 100644 --- a/testing/web-platform/tests/preload/onload-event.html +++ b/testing/web-platform/tests/preload/onload-event.html @@ -18,7 +18,7 @@ - + diff --git a/testing/web-platform/tests/preload/preload-with-type.html b/testing/web-platform/tests/preload/preload-with-type.html index db68721f54e2..69c52c46ee36 100644 --- a/testing/web-platform/tests/preload/preload-with-type.html +++ b/testing/web-platform/tests/preload/preload-with-type.html @@ -31,7 +31,7 @@ - + diff --git a/testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_onconnectionavailable-manual.https.html b/testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_onconnectionavailable-manual.https.html index a24e03aba880..450cab212cab 100644 --- a/testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_onconnectionavailable-manual.https.html +++ b/testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_onconnectionavailable-manual.https.html @@ -1,6 +1,6 @@ -PresentationRequest.onconnectionavailable (manual test) +Firing a connectionavailable event at a controlling user agent @@ -17,43 +17,56 @@ // ---------- // DOM Object // ---------- - var presentBtn = document.getElementById("presentBtn"); + const presentBtn = document.getElementById('presentBtn'); // -------------------------------------------------------------------------- // Start New PresentationRequest.onconnectionavailable Test (success) - begin // -------------------------------------------------------------------------- - var startPresentation = function () { + presentBtn.onclick = () => { presentBtn.disabled = true; - promise_test(function (t) { - var connection; - t.add_cleanup(function() { - if(connection) - connection.terminate(); + + promise_test(t => { + let connection; + const request = new PresentationRequest(presentationUrls); + + t.add_cleanup(() => { + if (connection) { + connection.onconnect = () => { connection.terminate(); }; + if (connection.state === 'closed') + request.reconnect(connection.id); + else + connection.terminate(); + } }); - // Note: During starting a presentation, the connectionavailable event is fired (step 20) - // after the promise P is resolved (step 19). - return new Promise(function(resolve, reject) { - var request = new PresentationRequest(presentationUrls); - request.onconnectionavailable = function (evt) { - resolve(evt.connection); - }; - // This test fails if request.onconnectionavailable is not invoked although the presentation is started successfully - // or the presentation fails to be started - request.start().then(function(c) { - connection = c; - t.step_timeout(function() { assert_unreached('The connectionavailable event was not fired.'); }, 5000); - }, reject); - }).then(function(c) { + // Note: During starting a presentation, the connectionavailable event is fired (step 9) + // after the promise P is resolved (step 8). + return request.start().then(c => { connection = c; assert_equals(connection.state, 'connecting', 'The initial state of the presentation connection is "connecting".'); assert_true(!!connection.id, 'The connection ID is set.'); assert_true(typeof connection.id === 'string', 'The connection ID is a string.'); assert_true(connection instanceof PresentationConnection, 'The connection is an instance of PresentationConnection.'); + + const eventWatcher = new EventWatcher(t, request, 'connectionavailable'); + const timeout = new Promise((_, reject) => { + // This test fails if request.onconnectionavailable is not invoked although the presentation is started successfully + // or the presentation fails to be started. + t.step_timeout(() => { reject('The connectionavailable event was not fired (timeout).'); }, 5000);} + ); + return Promise.race([ eventWatcher.wait_for('connectionavailable'), timeout ]); + }).then(evt => { + assert_true(evt instanceof PresentationConnectionAvailableEvent, 'An event using PresentationConnectionAvailableEvent is fired.'); + assert_true(evt.isTrusted, 'The event is a trusted event.'); + assert_false(evt.bubbles, 'The event does not bubbles.'); + assert_false(evt.cancelable, 'The event is not cancelable.'); + assert_equals(evt.type, 'connectionavailable', 'The event name is "connectionavailable".'); + assert_equals(evt.target, request, 'event.target is the presentation request.'); + assert_true(evt.connection instanceof PresentationConnection, 'event.connection is a presentation connection.'); + assert_equals(evt.connection, connection, 'event.connection is set to the presentation which the promise is resolved with.'); }); - }, 'The connectionavailable event was fired successfully.'); + }); } - presentBtn.onclick = startPresentation; // ------------------------------------------------------------------------ // Start New PresentationRequest.onconnectionavailable Test (success) - end // ------------------------------------------------------------------------ diff --git a/testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_success.https.html b/testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_success.https.html index 4e1570e83ad2..70ea5a806e7b 100644 --- a/testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_success.https.html +++ b/testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_success.https.html @@ -1,43 +1,24 @@ -Presentation API PresentationRequest for Controlling User Agent (Success) +Constructing a PresentationRequest - + + \ No newline at end of file diff --git a/testing/web-platform/tests/presentation-api/controlling-ua/defaultRequest.https.html b/testing/web-platform/tests/presentation-api/controlling-ua/defaultRequest.https.html new file mode 100644 index 000000000000..bc07e02748c7 --- /dev/null +++ b/testing/web-platform/tests/presentation-api/controlling-ua/defaultRequest.https.html @@ -0,0 +1,24 @@ + + +Setting a default presentation request + + + + + + diff --git a/testing/web-platform/tests/presentation-api/controlling-ua/getAvailability.https.html b/testing/web-platform/tests/presentation-api/controlling-ua/getAvailability.https.html index 895e1dc27d1d..f8ccd7034032 100644 --- a/testing/web-platform/tests/presentation-api/controlling-ua/getAvailability.https.html +++ b/testing/web-platform/tests/presentation-api/controlling-ua/getAvailability.https.html @@ -16,33 +16,46 @@ // Presentation Availability Tests - begin // --------------------------------------- - promise_test(function(t) { - var availability; + promise_test(t => { + let availability; - var request = new PresentationRequest(presentationUrls); + const request = new PresentationRequest(presentationUrls); assert_true(request instanceof PresentationRequest, 'The request is an instance of PresentationRequest.'); - var promise = request.getAvailability(); + const promise = request.getAvailability(); assert_equals(promise, request.getAvailability(), 'If the PresentationRequest object has an unsettled Promise, getAvailability returns that Promise.'); function catchNotSupported(err) { assert_equals(err.name, 'NotSupportedError', 'getAvailability() rejects a Promise with a NotSupportedError exception, if the browser can find presentation displays only when starting a connection.') } - return promise.then(function (a) { + return promise.then(a => { availability = a; assert_true(availability instanceof PresentationAvailability, 'The promise is resolved with an instance of PresentationAvailability.'); assert_equals(typeof availability.value, 'boolean', 'The availability has an boolean value.'); - assert_true(availability.value, 'The availability value is true when any presentation display is available.'); - var newPromise = request.getAvailability(); - assert_not_equals(promise, newPromise, 'If the Promise from a previous call to getAvailability has already been settled, getAvailability returns a new Promise.'); + // The value of the presentation availability object is set to false, when the object is newly created. + const waitForChange = () => { + const eventWatcher = new EventWatcher(t, availability, 'change'); + return eventWatcher.wait_for('change'); + }; - return newPromise.then(function (newAvailability) { - assert_equals(availability, newAvailability, 'Promises from a PresentationRequest\'s getAvailability are resolved with the same PresentationAvailability object.'); + return (availability.value ? Promise.resolve() : waitForChange()).then(() => { + assert_true(availability.value, 'The availability value is true when any presentation display is available.'); + + const request2 = new PresentationRequest('https://example.com'); + return request2.getAvailability(); + }).then(a => { + assert_not_equals(availability, a, 'A presentation availability object is newly created if the presentation request has a newly added presentation URLs.'); + + const newPromise = request.getAvailability(); + assert_not_equals(promise, newPromise, 'If the Promise from a previous call to getAvailability has already been settled, getAvailability returns a new Promise.'); + + return newPromise.then(newAvailability => { + assert_equals(availability, newAvailability, 'Promises from a PresentationRequest\'s getAvailability are resolved with the same PresentationAvailability object.'); + }, catchNotSupported); }, catchNotSupported); }, catchNotSupported); }); - diff --git a/testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_success-manual.https.html b/testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_success-manual.https.html index c740f6d0021a..94c48d9840d1 100644 --- a/testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_success-manual.https.html +++ b/testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_success-manual.https.html @@ -7,48 +7,101 @@ +

Click the button below to start the manual test. Select a presentation device after the selection dialog is prompted. The test assumes that at least one presentation device is available. The test passes if a "PASS" result appears.

+ diff --git a/testing/web-platform/tests/presentation-api/controlling-ua/support/iframe.html b/testing/web-platform/tests/presentation-api/controlling-ua/support/iframe.html index a37f0fcd8e0a..6c602d86a8a2 100644 --- a/testing/web-platform/tests/presentation-api/controlling-ua/support/iframe.html +++ b/testing/web-platform/tests/presentation-api/controlling-ua/support/iframe.html @@ -57,6 +57,21 @@ parent.window.postMessage(err.name, '*'); }); } + else if (ev.data.match(/^reconnect\?id=(.*)$/)) { + var presentationId = RegExp.$1; + request = new PresentationRequest(urls); + request.reconnect(presentationId) + .then(function (c) { + var result = { state: c.state, id: c.id }; + parent.window.postMessage(result, '*'); + c.onterminate = function() { + parent.window.postMessage('terminated', '*'); + }; + }) + .catch(function (err) { + parent.window.postMessage(err.name, '*'); + }); + } else if (ev.data === 'getAvailability') { request = new PresentationRequest(urls); request.getAvailability() diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnectionList_onconnectionavailable-manual.https.html b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnectionList_onconnectionavailable-manual.https.html new file mode 100644 index 000000000000..84971cbdf63b --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnectionList_onconnectionavailable-manual.https.html @@ -0,0 +1,78 @@ + + +Monitoring incoming presentation connections + + + + + + + +

Click the button below and select the available presentation display, to start the manual test.

+ + + + \ No newline at end of file diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_onclose-manual.https.html b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_onclose-manual.https.html new file mode 100644 index 000000000000..d6baad1c285d --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_onclose-manual.https.html @@ -0,0 +1,85 @@ + + +Closing a PresentationConnection + + + + + + + +

Click the button below and select the available presentation display, to start the manual test.

+ + + + \ No newline at end of file diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_onmessage-manual.https.html b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_onmessage-manual.https.html new file mode 100644 index 000000000000..4b05cdc9e895 --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_onmessage-manual.https.html @@ -0,0 +1,65 @@ + + +Receiving a message through PresentationConnection + + + + + + +

Click the button below and select the available presentation display, to start the manual test.

+ + + diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_send-manual.https.html b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_send-manual.https.html new file mode 100644 index 000000000000..f600a7fba236 --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_send-manual.https.html @@ -0,0 +1,97 @@ + + +Sending a message through PresentationConnection + + + + + + + +

Click the button below and select the available presentation display, to start the manual test.

+ + + diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_terminate-manual.https.html b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_terminate-manual.https.html new file mode 100644 index 000000000000..6484e97c5ab6 --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationConnection_terminate-manual.https.html @@ -0,0 +1,71 @@ + + +Terminating a presentation in a receiving browsing context + + + + + + + + +

Click the button below and select the available presentation display, to start the manual test.

+ + + + diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/PresentationReceiver_create-manual.https.html b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationReceiver_create-manual.https.html index e0445562fc4a..67b8c43d5a1a 100644 --- a/testing/web-platform/tests/presentation-api/receiving-ua/PresentationReceiver_create-manual.https.html +++ b/testing/web-platform/tests/presentation-api/receiving-ua/PresentationReceiver_create-manual.https.html @@ -48,16 +48,9 @@ indexedDB.deleteDatabase(dbName); if (connection) { - if (connection.state === 'connecting') { - connection.onconnect = () => { - connection.terminate(); - } - } - else if (connection.state === 'closed') { - request.reconnect(connection.id).then(c => { - c.terminate(); - }); - } + connection.onconnect = () => { connection.terminate(); }; + if (connection.state === 'closed') + request.reconnect(connection.id); else connection.terminate(); } diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/idlharness-manual.https.html b/testing/web-platform/tests/presentation-api/receiving-ua/idlharness-manual.https.html index 8258211e3068..079bb094acff 100644 --- a/testing/web-platform/tests/presentation-api/receiving-ua/idlharness-manual.https.html +++ b/testing/web-platform/tests/presentation-api/receiving-ua/idlharness-manual.https.html @@ -35,16 +35,9 @@ log.innerHTML = json.log; document.body.appendChild(log); - if (connection.state === 'connecting') { - connection.onconnect = () => { - connection.terminate(); - } - } - else if (connection.state === 'closed') { - request.reconnect(connection.id).then(c => { - c.terminate(); - }); - } + connection.onconnect = () => { connection.terminate(); }; + if (connection.state === 'closed') + request.reconnect(connection.id); else connection.terminate(); }); diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnectionList_onconnectionavailable_receiving-ua.html b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnectionList_onconnectionavailable_receiving-ua.html new file mode 100644 index 000000000000..f6994504309a --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnectionList_onconnectionavailable_receiving-ua.html @@ -0,0 +1,82 @@ + + + +Monitoring incoming presentation connections + + + + + + + + diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_onclose_receiving-ua.html b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_onclose_receiving-ua.html new file mode 100644 index 000000000000..a7a633fd037e --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_onclose_receiving-ua.html @@ -0,0 +1,79 @@ + + + +Closing a PresentationConnection + + + + + + + + diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_onmessage_receiving-ua.html b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_onmessage_receiving-ua.html new file mode 100644 index 000000000000..93f0dca04ed1 --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_onmessage_receiving-ua.html @@ -0,0 +1,98 @@ + + +Receiving a message through PresentationConnection + + + + + + + + diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_send_receiving-ua.html b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_send_receiving-ua.html new file mode 100644 index 000000000000..bc482e9dfd2c --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_send_receiving-ua.html @@ -0,0 +1,45 @@ + + + +Sending a message through PresentationConnection + + + + + + diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_terminate_receiving-ua.html b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_terminate_receiving-ua.html new file mode 100644 index 000000000000..3a234aaa8339 --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationConnection_terminate_receiving-ua.html @@ -0,0 +1,23 @@ + + + +Terminating a presentation in a receiving browsing context + + + + + + diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationReceiver_create_receiving-ua.html b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationReceiver_create_receiving-ua.html index a7be89722647..8edb88e1d780 100644 --- a/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationReceiver_create_receiving-ua.html +++ b/testing/web-platform/tests/presentation-api/receiving-ua/support/PresentationReceiver_create_receiving-ua.html @@ -194,7 +194,7 @@ child.addEventListener('load', () => { resolve(); }); }) : Promise.resolve()).then(getClientUrls).then(urls => { - assert_true(urls.every(url => { return url !== new Request('../PresentationReceiver_create-manual.html').url }), + assert_true(urls.every(url => { return url !== new Request('../PresentationReceiver_create-manual.https.html').url }), 'A window client in a controlling user agent is not accessible to a service worker on a receiving user agent.'); }); }; diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/support/idlharness_receiving-ua.https.html b/testing/web-platform/tests/presentation-api/receiving-ua/support/idlharness_receiving-ua.html similarity index 100% rename from testing/web-platform/tests/presentation-api/receiving-ua/support/idlharness_receiving-ua.https.html rename to testing/web-platform/tests/presentation-api/receiving-ua/support/idlharness_receiving-ua.html diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/support/iframe.html b/testing/web-platform/tests/presentation-api/receiving-ua/support/iframe.html new file mode 100644 index 000000000000..61f18b8912d3 --- /dev/null +++ b/testing/web-platform/tests/presentation-api/receiving-ua/support/iframe.html @@ -0,0 +1,22 @@ + + +Helper functions invoked by a nested browsing context + + + + \ No newline at end of file diff --git a/testing/web-platform/tests/presentation-api/receiving-ua/support/stash.js b/testing/web-platform/tests/presentation-api/receiving-ua/support/stash.js index 616907d4f2c9..eb63bb862377 100644 --- a/testing/web-platform/tests/presentation-api/receiving-ua/support/stash.js +++ b/testing/web-platform/tests/presentation-api/receiving-ua/support/stash.js @@ -1,5 +1,5 @@ var Stash = function(inbound, outbound) { - this.stashPath = '/presentation-api/controlling-ua/support/stash.py?id='; + this.stashPath = '/presentation-api/receiving-ua/support/stash.py?id='; this.inbound = inbound; this.outbound = outbound; } @@ -28,6 +28,21 @@ Stash.prototype.send = function(result) { }) }; +// upload a test result to a stash on wptserve via navigator.sendBeacon +Stash.prototype.sendBeacon = function(result) { + if ('sendBeacon' in navigator) { + navigator.sendBeacon(this.stashPath + this.outbound, JSON.stringify({ type: 'data', data: result })); + } + // Note: The following could be discarded, since XHR in synchronous mode is now being deprecated. + else { + return new Promise(resolve, reject => { + const xhr = new XMLHttpRequest(); + xhr.open('POST', this.stashPath + this.outbound, false); + xhr.send(JSON.stringify({ type: 'data', data: result })); + }); + } +}; + // wait until a test result is uploaded to a stash on wptserve Stash.prototype.receive = function() { return new Promise((resolve, reject) => { diff --git a/testing/web-platform/tests/resource-timing/resource_TAO_match_origin.htm b/testing/web-platform/tests/resource-timing/resource_TAO_match_origin.htm new file mode 100644 index 000000000000..3ab239e90bbf --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resource_TAO_match_origin.htm @@ -0,0 +1,55 @@ + + + + +Resource Timing TAO tests + + + + + + + + + +

Description

+

This test validates that for a cross origin resource, the timing allow check algorithm will pass when the Timing-Allow-Origin header value list contains a case-sensitive match for the value of the origin of the current document.

+
+ + + diff --git a/testing/web-platform/tests/resource-timing/resource_TAO_match_wildcard.htm b/testing/web-platform/tests/resource-timing/resource_TAO_match_wildcard.htm new file mode 100644 index 000000000000..8b07b46672e6 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resource_TAO_match_wildcard.htm @@ -0,0 +1,55 @@ + + + + +Resource Timing TAO tests + + + + + + + + + +

Description

+

This test validates that for a cross origin resource, the timing allow check algorithm will pass when the Timing-Allow-Origin header value list contains a wildcard ("*").

+
+ + + diff --git a/testing/web-platform/tests/resource-timing/resource_TAO_multi.htm b/testing/web-platform/tests/resource-timing/resource_TAO_multi.htm new file mode 100644 index 000000000000..3b6c2e6b267b --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resource_TAO_multi.htm @@ -0,0 +1,55 @@ + + + + +Resource Timing TAO tests + + + + + + + + + +

Description

+

This test validates that for a cross origin resource, the timing allow check algorithm will pass when the HTTP response has multiple Timing-Allow-Origin header fields and the subsequent field value is separated by a comma.

+
+ + + diff --git a/testing/web-platform/tests/resource-timing/resource_TAO_null.htm b/testing/web-platform/tests/resource-timing/resource_TAO_null.htm new file mode 100644 index 000000000000..419de693e1f9 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resource_TAO_null.htm @@ -0,0 +1,55 @@ + + + + +Resource Timing TAO tests + + + + + + + + + +

Description

+

This test validates that for a cross origin resource, the timing allow check algorithm will fail when the value of Timing-Allow-Origin is null.

+
+ + + diff --git a/testing/web-platform/tests/resource-timing/resource_TAO_origin.htm b/testing/web-platform/tests/resource-timing/resource_TAO_origin.htm new file mode 100644 index 000000000000..dc5efa43ee2b --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resource_TAO_origin.htm @@ -0,0 +1,55 @@ + + + + +Resource Timing TAO tests + + + + + + + + + +

Description

+

This test validates that for a cross origin resource, the timing allow check algorithm will pass when the value of Timing-Allow-Origin is a case-sensitive match for the value of the origin of the current document.

+
+ + + diff --git a/testing/web-platform/tests/resource-timing/resource_TAO_origin_uppercase.htm b/testing/web-platform/tests/resource-timing/resource_TAO_origin_uppercase.htm new file mode 100644 index 000000000000..0b42166c0ee8 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resource_TAO_origin_uppercase.htm @@ -0,0 +1,55 @@ + + + + +Resource Timing TAO tests + + + + + + + + + +

Description

+

This test validates that for a cross origin resource, the timing allow check algorithm will fail when the value of Timing-Allow-Origin is NOT a case-sensitive match for the value of the origin of the current document.

+
+ + + diff --git a/testing/web-platform/tests/resource-timing/resource_TAO_space.htm b/testing/web-platform/tests/resource-timing/resource_TAO_space.htm new file mode 100644 index 000000000000..f3cbdc62c016 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resource_TAO_space.htm @@ -0,0 +1,55 @@ + + + + +Resource Timing TAO tests + + + + + + + + + +

Description

+

This test validates that for a cross origin resource, the timing allow check algorithm will fail if the Timing-Allow-Origin header value list contains [origin|*]{2,}, separated by space.

+
+ + + diff --git a/testing/web-platform/tests/resource-timing/resource_TAO_wildcard.htm b/testing/web-platform/tests/resource-timing/resource_TAO_wildcard.htm new file mode 100644 index 000000000000..407c642d9d46 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resource_TAO_wildcard.htm @@ -0,0 +1,55 @@ + + + + +Resource Timing TAO tests + + + + + + + + + +

Description

+

This test validates that for a cross origin resource, the timing allow check algorithm will pass when the Timing-Allow-Origin header value is a wildcard ("*").

+
+ + + diff --git a/testing/web-platform/tests/resource-timing/resource_TAO_zero.htm b/testing/web-platform/tests/resource-timing/resource_TAO_zero.htm new file mode 100644 index 000000000000..0fe16c082a03 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resource_TAO_zero.htm @@ -0,0 +1,55 @@ + + + + +Resource Timing TAO tests + + + + + + + + + +

Description

+

This test validates that for a cross origin resource, the timing allow check algorithm will fail when the HTTP response includes zero Timing-Allow-Origin header value.

+
+ + + diff --git a/testing/web-platform/tests/resource-timing/resources/TAOResponse.py b/testing/web-platform/tests/resource-timing/resources/TAOResponse.py new file mode 100644 index 000000000000..cc8fa5f0f93f --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resources/TAOResponse.py @@ -0,0 +1,38 @@ +def main(request, response): + origin = request.headers['origin'] + response.headers.set('Access-Control-Allow-Origin', origin) + + tao = request.GET.first('tao') + + if tao == 'zero': + # zero TAO value, fail + pass + elif tao == 'wildcard': + # wildcard, pass + response.headers.set('Timing-Allow-Origin', '*') + elif tao == 'null': + # null, fail + response.headers.set('Timing-Allow-Origin', 'null') + elif tao == 'origin': + # case-sensitive match for origin, pass + response.headers.set('Timing-Allow-Origin', origin) + elif tao == 'space': + # space seperated list of origin and wildcard, fail + response.headers.set('Timing-Allow-Origin', (origin + ' *')) + elif tao == 'multi': + # more than one TAO values, seperated by common, pass + response.headers.set('Timing-Allow-Origin', origin) + response.headers.append('Timing-Allow-Origin', '*') + elif tao == 'match_origin': + # contains a match of origin, seperated by common, pass + response.headers.set('Timing-Allow-Origin', origin) + response.headers.append('Timing-Allow-Origin', "fake") + elif tao == 'match_wildcard': + # contains a wildcard, seperated by common, pass + response.headers.set('Timing-Allow-Origin', "fake") + response.headers.append('Timing-Allow-Origin', '*') + elif tao == 'uppercase': + # non-case-sensitive match for origin, fail + response.headers.set('Timing-Allow-Origin', origin.upper()) + else: + pass \ No newline at end of file diff --git a/testing/web-platform/tests/resource-timing/resources/iframe_TAO_match_origin.html b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_match_origin.html new file mode 100644 index 000000000000..cf68aade7954 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_match_origin.html @@ -0,0 +1,21 @@ + + + diff --git a/testing/web-platform/tests/resource-timing/resources/iframe_TAO_match_wildcard.html b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_match_wildcard.html new file mode 100644 index 000000000000..a6a03e0680e9 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_match_wildcard.html @@ -0,0 +1,21 @@ + + + diff --git a/testing/web-platform/tests/resource-timing/resources/iframe_TAO_multi.html b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_multi.html new file mode 100644 index 000000000000..0696dbe3e502 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_multi.html @@ -0,0 +1,21 @@ + + + diff --git a/testing/web-platform/tests/resource-timing/resources/iframe_TAO_null.html b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_null.html new file mode 100644 index 000000000000..7d47a2076f87 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_null.html @@ -0,0 +1,21 @@ + + + diff --git a/testing/web-platform/tests/resource-timing/resources/iframe_TAO_origin.html b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_origin.html new file mode 100644 index 000000000000..c75b0752406d --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_origin.html @@ -0,0 +1,21 @@ + + + diff --git a/testing/web-platform/tests/resource-timing/resources/iframe_TAO_origin_uppercase.html b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_origin_uppercase.html new file mode 100644 index 000000000000..7404035d1ab2 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_origin_uppercase.html @@ -0,0 +1,21 @@ + + + diff --git a/testing/web-platform/tests/resource-timing/resources/iframe_TAO_space.html b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_space.html new file mode 100644 index 000000000000..2a484ed5140b --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_space.html @@ -0,0 +1,21 @@ + + + diff --git a/testing/web-platform/tests/resource-timing/resources/iframe_TAO_wildcard.html b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_wildcard.html new file mode 100644 index 000000000000..3b5be4cdab98 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_wildcard.html @@ -0,0 +1,21 @@ + + + diff --git a/testing/web-platform/tests/resource-timing/resources/iframe_TAO_zero.html b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_zero.html new file mode 100644 index 000000000000..76c5938689a4 --- /dev/null +++ b/testing/web-platform/tests/resource-timing/resources/iframe_TAO_zero.html @@ -0,0 +1,21 @@ + + + diff --git a/testing/web-platform/tests/resources/.gitmodules b/testing/web-platform/tests/resources/.gitmodules deleted file mode 100644 index 89035729d514..000000000000 --- a/testing/web-platform/tests/resources/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "webidl2"] - path = webidl2 - url = https://github.com/darobin/webidl2.js.git diff --git a/testing/web-platform/tests/resources/examples/apisample18.html b/testing/web-platform/tests/resources/examples/apisample18.html new file mode 100644 index 000000000000..c97cba395808 --- /dev/null +++ b/testing/web-platform/tests/resources/examples/apisample18.html @@ -0,0 +1,26 @@ + + + +Example with iframe that consolidates errors via fetch_tests_from_window + + + + + +

Fetching Tests From a Child Context

+

This test demonstrates the use of fetch_tests_from_window to pull +tests from an iframe into the primary document.

+

The test suite is expected to fail due to an unhandled exception in the +child context.

+
+ + + + + + \ No newline at end of file diff --git a/testing/web-platform/tests/resources/examples/apisample19.html b/testing/web-platform/tests/resources/examples/apisample19.html new file mode 100644 index 000000000000..84b9e122aba2 --- /dev/null +++ b/testing/web-platform/tests/resources/examples/apisample19.html @@ -0,0 +1,26 @@ + + + +Example with iframe that consolidates tests via fetch_tests_from_window + + + + + +

Fetching Tests From a Child Context

+

This test demonstrates the use of fetch_tests_from_window to pull +tests from an iframe into the primary document.

+

The test suite will not complete until tests in the child context have finished +executing

+
+ + + + + + \ No newline at end of file diff --git a/testing/web-platform/tests/resources/idlharness.js b/testing/web-platform/tests/resources/idlharness.js index 5fca23e56acd..f661d238cbf5 100644 --- a/testing/web-platform/tests/resources/idlharness.js +++ b/testing/web-platform/tests/resources/idlharness.js @@ -437,6 +437,31 @@ IdlArray.prototype.test = function() IdlArray.prototype.assert_type_is = function(value, type) //@{ { + if (type.idlType in this.members + && this.members[type.idlType] instanceof IdlTypedef) { + this.assert_type_is(value, this.members[type.idlType].idlType); + return; + } + if (type.union) { + for (var i = 0; i < type.idlType.length; i++) { + try { + this.assert_type_is(value, type.idlType[i]); + // No AssertionError, so we match one type in the union + return; + } catch(e) { + if (e instanceof AssertionError) { + // We didn't match this type, let's try some others + continue; + } + throw e; + } + } + // TODO: Is there a nice way to list the union's types in the message? + assert_true(false, "Attribute has value " + format_value(value) + + " which doesn't match any of the types in the union"); + + } + /** * Helper function that tests that value is an instance of type according * to the rules of WebIDL. value is any JavaScript value, and type is an @@ -624,10 +649,6 @@ IdlArray.prototype.assert_type_is = function(value, type) { // TODO: Test when we actually have something to test this on } - else if (this.members[type] instanceof IdlTypedef) - { - // TODO: Test when we actually have something to test this on - } else { throw "Type " + type + " isn't an interface or dictionary"; @@ -1048,13 +1069,19 @@ IdlInterface.prototype.test_self = function() // "The class string of an interface prototype object is the // concatenation of the interface’s identifier and the string // “Prototype”." - assert_class_string(self[this.name].prototype, this.name + "Prototype", - "class string of " + this.name + ".prototype"); + + // Skip these tests for now due to a specification issue about + // prototype name. + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=28244 + + // assert_class_string(self[this.name].prototype, this.name + "Prototype", + // "class string of " + this.name + ".prototype"); + // String() should end up calling {}.toString if nothing defines a // stringifier. if (!this.has_stringifier()) { - assert_equals(String(self[this.name].prototype), "[object " + this.name + "Prototype]", - "String(" + this.name + ".prototype)"); + // assert_equals(String(self[this.name].prototype), "[object " + this.name + "Prototype]", + // "String(" + this.name + ".prototype)"); } }.bind(this), this.name + " interface: existence and properties of interface prototype object"); @@ -2003,8 +2030,8 @@ function IdlTypedef(obj) /** Self-explanatory. */ this.name = obj.name; - /** An array of values produced by the "typedef" production. */ - this.values = obj.values; + /** The idlType that we are supposed to be typedeffing to. */ + this.idlType = obj.idlType; } //@} diff --git a/testing/web-platform/tests/resources/readme.md b/testing/web-platform/tests/resources/readme.md index eed909064239..8583d5f8d5b4 100644 --- a/testing/web-platform/tests/resources/readme.md +++ b/testing/web-platform/tests/resources/readme.md @@ -16,8 +16,7 @@ To use testharness.js you must include two scripts, in the order given: ## Full documentation ## -Full user documentation for the API is in the -[docs/api.md](https://github.com/w3c/testharness.js/blob/master/docs/api.md) file. +Full user documentation for the API is at [http://web-platform-tests.org/writing-tests/testharness-api.html](http://web-platform-tests.org/writing-tests/testharness-api.html). You can also read a tutorial on [Using testharness.js](http://darobin.github.com/test-harness-tutorial/docs/using-testharness.html). diff --git a/testing/web-platform/tests/resources/testharness.js b/testing/web-platform/tests/resources/testharness.js index ee842e42832c..2ee9a146a83a 100644 --- a/testing/web-platform/tests/resources/testharness.js +++ b/testing/web-platform/tests/resources/testharness.js @@ -66,6 +66,7 @@ policies and contribution forms [3]. this.all_loaded = false; var this_obj = this; this.message_events = []; + this.dispatched_messages = []; this.message_functions = { start: [add_start_callback, remove_start_callback, @@ -102,9 +103,23 @@ policies and contribution forms [3]. on_event(window, 'load', function() { this_obj.all_loaded = true; }); + + on_event(window, 'message', function(event) { + if (event.data && event.data.type === "getmessages" && event.source) { + // A window can post "getmessages" to receive a duplicate of every + // message posted by this environment so far. This allows subscribers + // from fetch_tests_from_window to 'catch up' to the current state of + // this environment. + for (var i = 0; i < this_obj.dispatched_messages.length; ++i) + { + event.source.postMessage(this_obj.dispatched_messages[i], "*"); + } + } + }); } WindowTestEnvironment.prototype._dispatch = function(selector, callback_args, message_arg) { + this.dispatched_messages.push(message_arg); this._forEach_windows( function(w, same_origin) { if (same_origin) { @@ -142,33 +157,14 @@ policies and contribution forms [3]. var w = self; var i = 0; var so; - var origins = location.ancestorOrigins; while (w != w.parent) { w = w.parent; - // In WebKit, calls to parent windows' properties that aren't on the same - // origin cause an error message to be displayed in the error console but - // don't throw an exception. This is a deviation from the current HTML5 - // spec. See: https://bugs.webkit.org/show_bug.cgi?id=43504 - // The problem with WebKit's behavior is that it pollutes the error console - // with error messages that can't be caught. - // - // This issue can be mitigated by relying on the (for now) proprietary - // `location.ancestorOrigins` property which returns an ordered list of - // the origins of enclosing windows. See: - // http://trac.webkit.org/changeset/113945. - if (origins) { - so = (location.origin == origins[i]); - } else { - so = is_same_origin(w); - } + so = is_same_origin(w); cache.push([w, so]); i++; } w = window.opener; if (w) { - // window.opener isn't included in the `location.ancestorOrigins` prop. - // We'll just have to deal with a simple check and an error msg on WebKit - // browsers in this case. cache.push([w, is_same_origin(w)]); } this.window_cache = cache; @@ -414,7 +410,7 @@ policies and contribution forms [3]. var this_obj = this; self.addEventListener("message", function(event) { - if (event.data.type && event.data.type === "connect") { + if (event.data && event.data.type && event.data.type === "connect") { if (event.ports && event.ports[0]) { // If a MessageChannel was passed, then use it to // send results back to the main window. This @@ -1575,73 +1571,56 @@ policies and contribution forms [3]. } /* - * A RemoteWorker listens for test events from a worker. These events are - * then used to construct and maintain RemoteTest objects that mirror the - * tests running on the remote worker. + * A RemoteContext listens for test events from a remote test context, such + * as another window or a worker. These events are then used to construct + * and maintain RemoteTest objects that mirror the tests running in the + * remote context. + * + * An optional third parameter can be used as a predicate to filter incoming + * MessageEvents. */ - function RemoteWorker(worker) { + function RemoteContext(remote, message_target, message_filter) { this.running = true; this.tests = new Array(); var this_obj = this; - worker.onerror = function(error) { this_obj.worker_error(error); }; + remote.onerror = function(error) { this_obj.remote_error(error); }; - var message_port; - - if (is_service_worker(worker)) { - if (window.MessageChannel) { - // The ServiceWorker's implicit MessagePort is currently not - // reliably accessible from the ServiceWorkerGlobalScope due to - // Blink setting MessageEvent.source to null for messages sent - // via ServiceWorker.postMessage(). Until that's resolved, - // create an explicit MessageChannel and pass one end to the - // worker. - var message_channel = new MessageChannel(); - message_port = message_channel.port1; - message_port.start(); - worker.postMessage({type: "connect"}, [message_channel.port2]); - } else { - // If MessageChannel is not available, then try the - // ServiceWorker.postMessage() approach using MessageEvent.source - // on the other end. - message_port = navigator.serviceWorker; - worker.postMessage({type: "connect"}); + // Keeping a reference to the remote object and the message handler until + // remote_done() is seen prevents the remote object and its message channel + // from going away before all the messages are dispatched. + this.remote = remote; + this.message_target = message_target; + this.message_handler = function(message) { + var passesFilter = !message_filter || message_filter(message); + if (this_obj.running && message.data && passesFilter && + (message.data.type in this_obj.message_handlers)) { + this_obj.message_handlers[message.data.type].call(this_obj, message.data); } - } else if (is_shared_worker(worker)) { - message_port = worker.port; - } else { - message_port = worker; - } + }; - // Keeping a reference to the worker until worker_done() is seen - // prevents the Worker object and its MessageChannel from going away - // before all the messages are dispatched. - this.worker = worker; - - message_port.onmessage = - function(message) { - if (this_obj.running && (message.data.type in this_obj.message_handlers)) { - this_obj.message_handlers[message.data.type].call(this_obj, message.data); - } - }; + this.message_target.addEventListener("message", this.message_handler); } - RemoteWorker.prototype.worker_error = function(error) { + RemoteContext.prototype.remote_error = function(error) { var message = error.message || String(error); var filename = (error.filename ? " " + error.filename: ""); - // FIXME: Display worker error states separately from main document + // FIXME: Display remote error states separately from main document // error state. - this.worker_done({ + this.remote_done({ status: { status: tests.status.ERROR, - message: "Error in worker" + filename + ": " + message, + message: "Error in remote" + filename + ": " + message, stack: error.stack } }); - error.preventDefault(); + + if (error.preventDefault) { + error.preventDefault(); + } }; - RemoteWorker.prototype.test_state = function(data) { + RemoteContext.prototype.test_state = function(data) { var remote_test = this.tests[data.test.index]; if (!remote_test) { remote_test = new RemoteTest(data.test); @@ -1651,31 +1630,33 @@ policies and contribution forms [3]. tests.notify_test_state(remote_test); }; - RemoteWorker.prototype.test_done = function(data) { + RemoteContext.prototype.test_done = function(data) { var remote_test = this.tests[data.test.index]; remote_test.update_state_from(data.test); remote_test.done(); tests.result(remote_test); }; - RemoteWorker.prototype.worker_done = function(data) { + RemoteContext.prototype.remote_done = function(data) { if (tests.status.status === null && data.status.status !== data.status.OK) { tests.status.status = data.status.status; tests.status.message = data.status.message; tests.status.stack = data.status.stack; } + this.message_target.removeEventListener("message", this.message_handler); this.running = false; - this.worker = null; + this.remote = null; + this.message_target = null; if (tests.all_done()) { tests.complete(); } }; - RemoteWorker.prototype.message_handlers = { - test_state: RemoteWorker.prototype.test_state, - result: RemoteWorker.prototype.test_done, - complete: RemoteWorker.prototype.worker_done + RemoteContext.prototype.message_handlers = { + test_state: RemoteContext.prototype.test_state, + result: RemoteContext.prototype.test_done, + complete: RemoteContext.prototype.remote_done }; /* @@ -1743,7 +1724,7 @@ policies and contribution forms [3]. this.test_done_callbacks = []; this.all_done_callbacks = []; - this.pending_workers = []; + this.pending_remotes = []; this.status = new TestsStatus(); @@ -1858,7 +1839,7 @@ policies and contribution forms [3]. return (this.tests.length > 0 && test_environment.all_loaded && this.num_pending === 0 && !this.wait_for_finish && !this.processing_callbacks && - !this.pending_workers.some(function(w) { return w.running; })); + !this.pending_remotes.some(function(w) { return w.running; })); }; Tests.prototype.start = function() { @@ -1967,12 +1948,65 @@ policies and contribution forms [3]. }); }; + /* + * Constructs a RemoteContext that tracks tests from a specific worker. + */ + Tests.prototype.create_remote_worker = function(worker) { + var message_port; + + if (is_service_worker(worker)) { + // Microsoft Edge's implementation of ServiceWorker doesn't support MessagePort yet. + // Feature detection isn't a straightforward option here; it's only possible in the + // worker's script context. + var isMicrosoftEdgeBrowser = navigator.userAgent.includes("Edge"); + if (window.MessageChannel && !isMicrosoftEdgeBrowser) { + // The ServiceWorker's implicit MessagePort is currently not + // reliably accessible from the ServiceWorkerGlobalScope due to + // Blink setting MessageEvent.source to null for messages sent + // via ServiceWorker.postMessage(). Until that's resolved, + // create an explicit MessageChannel and pass one end to the + // worker. + var message_channel = new MessageChannel(); + message_port = message_channel.port1; + message_port.start(); + worker.postMessage({type: "connect"}, [message_channel.port2]); + } else { + // If MessageChannel is not available, then try the + // ServiceWorker.postMessage() approach using MessageEvent.source + // on the other end. + message_port = navigator.serviceWorker; + worker.postMessage({type: "connect"}); + } + } else if (is_shared_worker(worker)) { + message_port = worker.port; + message_port.start(); + } else { + message_port = worker; + } + + return new RemoteContext(worker, message_port); + }; + + /* + * Constructs a RemoteContext that tracks tests from a specific window. + */ + Tests.prototype.create_remote_window = function(remote) { + remote.postMessage({type: "getmessages"}, "*"); + return new RemoteContext( + remote, + window, + function(msg) { + return msg.source === remote; + } + ); + }; + Tests.prototype.fetch_tests_from_worker = function(worker) { if (this.phase >= this.phases.COMPLETE) { return; } - this.pending_workers.push(new RemoteWorker(worker)); + this.pending_remotes.push(this.create_remote_worker(worker)); }; function fetch_tests_from_worker(port) { @@ -1980,6 +2014,19 @@ policies and contribution forms [3]. } expose(fetch_tests_from_worker, 'fetch_tests_from_worker'); + Tests.prototype.fetch_tests_from_window = function(remote) { + if (this.phase >= this.phases.COMPLETE) { + return; + } + + this.pending_remotes.push(this.create_remote_window(remote)); + }; + + function fetch_tests_from_window(window) { + tests.fetch_tests_from_window(window); + } + expose(fetch_tests_from_window, 'fetch_tests_from_window'); + function timeout() { if (tests.timeout_length === null) { tests.timeout(); @@ -2139,7 +2186,7 @@ policies and contribution forms [3]. } var harness_url = get_harness_url(); - if (harness_url !== null) { + if (harness_url !== undefined) { var stylesheet = output_document.createElementNS(xhtml_ns, "link"); stylesheet.setAttribute("rel", "stylesheet"); stylesheet.setAttribute("href", harness_url + "testharness.css"); @@ -2493,6 +2540,7 @@ policies and contribution forms [3]. this.message = message; this.stack = this.get_stack(); } + expose(AssertionError, "AssertionError"); AssertionError.prototype = Object.create(Error.prototype); diff --git a/testing/web-platform/tests/resources/webidl2/README.md b/testing/web-platform/tests/resources/webidl2/README.md index f7d03fcdef30..5d128ed27ca8 100644 --- a/testing/web-platform/tests/resources/webidl2/README.md +++ b/testing/web-platform/tests/resources/webidl2/README.md @@ -3,16 +3,15 @@ [![NPM version](https://badge.fury.io/js/webidl2.png)](http://badge.fury.io/js/webidl2) -Purpose -======= +## Purpose This is a parser for the [WebIDL](http://dev.w3.org/2006/webapi/WebIDL/) language. If you don't know what that is, then you probably don't need it. It is meant to be used both in Node and in the browser (the parser likely works in other JS environments, but not the test suite). -What of v1? ------------ +### What of v1? + There was a previous incarnation of this project. I had written it in the most quick and dirty manner that was handy because I required it as a dependency in an experiment. As these things tend to happen, some people started using that, which then had to be @@ -20,65 +19,72 @@ maintained. But since it was not built on solid foundations, it was painful to k up to date with the specification, which is a bit of a moving target. So I started from scratch. Compared to the previous version (which used a parser generator) -this one is about 6x less code (which translates to 4x smaller minified or 2x smaller +this one is about 6x less code (which translates to 4x smaller minified or 2x smaller minizipped) and 4x faster. The test suite is reasonably complete (95% coverage), much more than previously. This version is up to date with WebIDL, rather than a couple years' behind. It also has *far* better error reporting. -The AST you get from parsing is very similar to the one you got in v1, but some adjustments -have been made in order to be more systematic, and to map better to what's actually in the spec +The AST you get from parsing is very similar to the one you got in v1, but some adjustments +have been made in order to be more systematic, and to map better to what's actually in the spec now. If you used v1, you will need to tweak your code but the result ought to be simpler and -you ought to be able to be a fair bit less defensive against irregularities in the way +you ought to be able to be a fair bit less defensive against irregularities in the way information is represented. -Installation -============ +## Installation Just the usual. For Node: - npm install webidl2 - +```Bash +npm install webidl2 +``` + In the browser: - +```HTML + +``` + +## Documentation -Documentation -============= The API to WebIDL2 is trivial: you parse a string of WebIDL and it returns a syntax tree. -Parsing -------- +### Parsing + In Node, that happens with: - var WebIDL2 = require("webidl2"); - var tree = WebIDL2.parse("string of WebIDL"); +```JS +var WebIDL2 = require("webidl2"); +var tree = WebIDL2.parse("string of WebIDL"); +``` In the browser: +```HTML + + +``` - - - -Advanced Parsing ----------------- +### Advanced Parsing `parse()` can optionally accept a second parameter, an options object, which can be used to modify parsing behavior. The following options are recognized: -```javascript +```JS { - allowNestedTypedefs: false # + allowNestedTypedefs: false } ``` + And their meanings are as follows: -* `allowNestedTypedefs`: Boolean indicating whether the parser should accept `typedef`s as valid members of `interface`s. This is non-standard syntax and therefore the default is `false`. +* `allowNestedTypedefs`: Boolean indicating whether the parser should accept `typedef`s as valid members of `interface`s. +This is non-standard syntax and therefore the default is `false`. + +### Errors -Errors ------- When there is a syntax error in the WebIDL, it throws an exception object with the following properties: @@ -91,8 +97,8 @@ properties: The exception also has a `toString()` method that hopefully should produce a decent error message. -AST (Abstract Syntax Tree) --------------------------- +### AST (Abstract Syntax Tree) + The `parse()` method returns a tree object representing the parse tree of the IDL. Comment and white space are not represented in the AST. @@ -106,35 +112,34 @@ This structure is used in many other places (operation return types, argument ty It captures a WebIDL type with a number of options. Types look like this and are typically attached to a field called `idlType`: - { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "void" - } +```JS +{ + "array": false, + "generic": null, + "idlType": "void", + "nullable": false, + "union": false, +} +``` Where the fields are as follows: -* `sequence`: Boolean indicating whether this is a sequence or not. Deprecated. Use - `generic` instead. -* `generic`: String indicating the generic type (e.g. "Promise", "sequence"). `null` - otherwise. -* `nullable`: Boolean indicating whether this is nullable or not. * `array`: Either `false` to indicate that it is not an array, or a number for the level of array nesting. -* `union`: Boolean indicating whether this is a union type or not. +* `generic`: String indicating the generic type (e.g. "Promise", "sequence"). `null` + otherwise. * `idlType`: Can be different things depending on context. In most cases, this will just be a string with the type name. But the reason this field isn't called "typeName" is because it can take more complex values. If the type is a union, then this contains an array of the types it unites. If it is a generic type, it contains the IDL type description for the type in the sequence, the eventual value of the promise, etc. +* `nullable`: Boolean indicating whether this is nullable or not. +* `union`: Boolean indicating whether this is a union type or not. #### Interactions between `nullable` and `array` A more complex data model for our AST would likely represent `Foo[][][]` as a series of -nested types four levels deep with three anonymous array types eventually containing a +nested types four levels deep with three anonymous array types eventually containing a `Foo` type. But experience shows that such structures are cumbersome to use, and so we have a simpler model in which the depth of the array is specified with the `array` field. @@ -167,22 +172,23 @@ a `?` at the end. ### Interface Interfaces look like this: - { - "type": "interface", - "name": "Animal", - "partial": false, - "members": [...], - "inheritance": null, - "extAttrs": [...] - }, - { - "type": "interface", - "name": "Human", - "partial": false, - "members": [...], - "inheritance": "Animal", - "extAttrs": [...] - } +```JS +{ + "type": "interface", + "name": "Animal", + "partial": false, + "members": [...], + "inheritance": null, + "extAttrs": [...] +}, { + "type": "interface", + "name": "Human", + "partial": false, + "members": [...], + "inheritance": "Animal", + "extAttrs": [...] +} +``` The fields are as follows: @@ -204,20 +210,22 @@ their `type` field is "callback interface". A callback looks like this: - { - "type": "callback", - "name": "AsyncOperationCallback", - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "void" - }, - "arguments": [...], - "extAttrs": [] - } +```JS +{ + "type": "callback", + "name": "AsyncOperationCallback", + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "void" + }, + "arguments": [...], + "extAttrs": [] +} +``` The fields are as follows: @@ -231,33 +239,33 @@ The fields are as follows: A dictionary looks like this: - { - "type": "dictionary", - "name": "PaintOptions", - "partial": false, - "members": [ - { - "type": "field", - "name": "fillPattern", - "required": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": true, - "array": false, - "union": false, - "idlType": "DOMString" - }, - "extAttrs": [], - "default": { - "type": "string", - "value": "black" - } - } - ], - "inheritance": null, - "extAttrs": [] +```JS +{ + "type": "dictionary", + "name": "PaintOptions", + "partial": false, + "members": [{ + "type": "field", + "name": "fillPattern", + "required": false, + "idlType": { + "sequence": false, + "generic": null, + "nullable": true, + "array": false, + "union": false, + "idlType": "DOMString" + }, + "extAttrs": [], + "default": { + "type": "string", + "value": "black" } + }], + "inheritance": null, + "extAttrs": [] +} +``` The fields are as follows: @@ -281,27 +289,27 @@ All the members are fields as follows: An exception looks like this: - { - "type": "exception", - "name": "HierarchyRequestError", - "members": [ - { - "type": "field", - "name": "code", - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "unsigned short" - }, - "extAttrs": [] - } - ], - "inheritance": "DOMException", - "extAttrs": [] - } +```JS +{ + "type": "exception", + "name": "HierarchyRequestError", + "members": [{ + "type": "field", + "name": "code", + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "unsigned short" + }, + "extAttrs": [] + }], + "inheritance": "DOMException", + "extAttrs": [] +} +``` The fields are as follows: @@ -322,16 +330,18 @@ Members that aren't [constants](#constants) have the following fields: An enum looks like this: - { - "type": "enum", - "name": "MealType", - "values": [ - "rice", - "noodles", - "other" - ], - "extAttrs": [] - } +```JS +{ + "type": "enum", + "name": "MealType", + "values": [ + "rice", + "noodles", + "other" + ], + "extAttrs": [] +} +``` The fields are as follows: @@ -344,27 +354,30 @@ The fields are as follows: A typedef looks like this: - { - "type": "typedef", - "typeExtAttrs": [], - "idlType": { - "sequence": true, - "generic": "sequence", - "nullable": false, - "array": false, - "union": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "Point" - } - }, - "name": "PointSequence", - "extAttrs": [] +```JS +{ + "type": "typedef", + "typeExtAttrs": [], + "idlType": { + "sequence": true, + "generic": "sequence", + "nullable": false, + "array": false, + "union": false, + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "Point" } + }, + "name": "PointSequence", + "extAttrs": [] +} +``` + The fields are as follows: @@ -379,12 +392,14 @@ type rather than to the typedef as a whole. An implements definition looks like this: - { - "type": "implements", - "target": "Node", - "implements": "EventTarget", - "extAttrs": [] - } +```JS +{ + "type": "implements", + "target": "Node", + "implements": "EventTarget", + "extAttrs": [] +} +``` The fields are as follows: @@ -396,43 +411,42 @@ The fields are as follows: ### Operation Member An operation looks like this: - - { - "type": "operation", - "getter": false, - "setter": false, - "creator": false, - "deleter": false, - "legacycaller": false, - "static": false, - "stringifier": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "void" - }, - "name": "intersection", - "arguments": [ - { - "optional": false, - "variadic": true, - "extAttrs": [], - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "long" - }, - "name": "ints" - } - ], - "extAttrs": [] - } +```JS +{ + "type": "operation", + "getter": false, + "setter": false, + "creator": false, + "deleter": false, + "legacycaller": false, + "static": false, + "stringifier": false, + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "void" + }, + "name": "intersection", + "arguments": [{ + "optional": false, + "variadic": true, + "extAttrs": [], + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "long" + }, + "name": "ints" + }], + "extAttrs": [] +} +``` The fields are as follows: @@ -453,24 +467,26 @@ The fields are as follows: An attribute member looks like this: - { - "type": "attribute", - "static": false, - "stringifier": false, - "inherit": false, - "readonly": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "RegExp" - }, - "name": "regexp", - "extAttrs": [] - } - +```JS +{ + "type": "attribute", + "static": false, + "stringifier": false, + "inherit": false, + "readonly": false, + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "RegExp" + }, + "name": "regexp", + "extAttrs": [] +} +``` + The fields are as follows: * `type`: Always "attribute". @@ -486,17 +502,19 @@ The fields are as follows: A constant member looks like this: - { - "type": "const", - "nullable": false, - "idlType": "boolean", - "name": "DEBUG", - "value": { - "type": "boolean", - "value": false - }, - "extAttrs": [] - } +```JS +{ + "type": "const", + "nullable": false, + "idlType": "boolean", + "name": "DEBUG", + "value": { + "type": "boolean", + "value": false + }, + "extAttrs": [] +} +``` The fields are as follows: @@ -512,60 +530,63 @@ The fields are as follows: Serializers come in many shapes, which are best understood by looking at the examples below that map the IDL to the produced AST. - // serializer; - { - "type": "serializer", - "extAttrs": [] - } +```JS +// serializer; +{ + "type": "serializer", + "extAttrs": [] +} - // serializer DOMString serialize(); - { - "type": "serializer", - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "DOMString" - }, - "operation": { - "name": "serialize", - "arguments": [] - }, - "extAttrs": [] - } +// serializer DOMString serialize(); +{ + "type": "serializer", + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "DOMString" + }, + "operation": { + "name": "serialize", + "arguments": [] + }, + "extAttrs": [] +} - // serializer = { from, to, amount, description }; - { - "type": "serializer", - "patternMap": true, - "names": [ - "from", - "to", - "amount", - "description" - ], - "extAttrs": [] - } +// serializer = { from, to, amount, description }; +{ + "type": "serializer", + "patternMap": true, + "names": [ + "from", + "to", + "amount", + "description" + ], + "extAttrs": [] +} - // serializer = number; - { - "type": "serializer", - "name": "number", - "extAttrs": [] - } +// serializer = number; +{ + "type": "serializer", + "name": "number", + "extAttrs": [] +} - // serializer = [ name, number ]; - { - "type": "serializer", - "patternList": true, - "names": [ - "name", - "number" - ], - "extAttrs": [] - } +// serializer = [ name, number ]; +{ + "type": "serializer", + "patternList": true, + "names": [ + "name", + "number" + ], + "extAttrs": [] +} + +``` The common fields are as follows: @@ -598,26 +619,28 @@ Finally, if the serializer is a named serializer: Iterator members look like this - { - "type": "iterator", - "getter": false, - "setter": false, - "creator": false, - "deleter": false, - "legacycaller": false, - "static": false, - "stringifier": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "Session2" - }, - "iteratorObject": "SessionIterator", - "extAttrs": [] - } +```JS +{ + "type": "iterator", + "getter": false, + "setter": false, + "creator": false, + "deleter": false, + "legacycaller": false, + "static": false, + "stringifier": false, + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "Session2" + }, + "iteratorObject": "SessionIterator", + "extAttrs": [] +} +``` * `type`: Always "iterator". * `iteratorObject`: The string on the right-hand side; absent if there isn't one. @@ -627,22 +650,24 @@ Iterator members look like this The arguments (e.g. for an operation) look like this: - "arguments": [ - { - "optional": false, - "variadic": true, - "extAttrs": [], - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "long" - }, - "name": "ints" - } - ] +```JS +{ + "arguments": [{ + "optional": false, + "variadic": true, + "extAttrs": [], + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "long" + }, + "name": "ints" + }] +} +``` The fields are as follows: @@ -656,16 +681,18 @@ The fields are as follows: Extended attributes are arrays of items that look like this: - "extAttrs": [ - { - "name": "TreatNullAs", - "arguments": null, - "rhs": { - "type": "identifier", - "value": "EmptyString" - } - } - ] +```JS +{ + "extAttrs": [{ + "name": "TreatNullAs", + "arguments": null, + "rhs": { + "type": "identifier", + "value": "EmptyString" + } + }] +} +``` The fields are as follows: @@ -700,12 +727,14 @@ For Infinity: These appear as members of interfaces that look like this: - { - "type": "maplike", // or "legacyiterable" / "iterable" / "setlike" - "idlType": /* One or two types */, - "readonly": false, // only for maplike and setlike - "extAttrs": [] - } +```JS +{ + "type": "maplike", // or "legacyiterable" / "iterable" / "setlike" + "idlType": /* One or two types */ , + "readonly": false, // only for maplike and setlike + "extAttrs": [] +} +``` The fields are as follows: @@ -715,46 +744,51 @@ The fields are as follows: * `extAttrs`: A list of [extended attributes](#extended-attributes). -Testing -======= +## Testing In order to run the tests you need to ensure that the widlproc submodule inside `test` is -initialised and up to date: +initialized and up to date: - git submodule init - git submodule update +```Bash +git submodule init +git submodule update +``` + +### Running -Running -------- The test runs with mocha and expect.js. Normally, running mocha in the root directory should be enough once you're set up. -Coverage --------- +### Coverage + Current test coverage, as documented in `coverage.html`, is 95%. You can run your own coverage analysis with: - jscoverage lib lib-cov - +```Bash +jscoverage lib lib-cov +``` + That will create the lib-cov directory with instrumented code; the test suite knows to use that if needed. You can then run the tests with: - JSCOV=1 mocha --reporter html-cov > coverage.html +```Bash +JSCOV=1 mocha --reporter html-cov > coverage.html +``` Note that I've been getting weirdly overescaped results from the html-cov reporter, so you might wish to try this instead: - JSCOV=1 mocha --reporter html-cov | sed "s/<//g" | sed "s/"/\"/g" > coverage.html +```Bash +JSCOV=1 mocha --reporter html-cov | sed "s/<//g" | sed "s/"/\"/g" > coverage.html +``` +### Browser tests -Browser tests -------------- In order to test in the browser, get inside `test/web` and run `make-web-tests.js`. This will generate a `browser-tests.html` file that you can open in a browser. As of this writing tests pass in the latest Firefox, Chrome, Opera, and Safari. Testing on IE and older versions will happen progressively. -TODO -==== +## TODO * add some tests to address coverage limitations * add a push API for processors that need to process things like comments diff --git a/testing/web-platform/tests/resources/webidl2/lib/webidl2.js b/testing/web-platform/tests/resources/webidl2/lib/webidl2.js index 9e504fc6e1fd..0e76174a0836 100644 --- a/testing/web-platform/tests/resources/webidl2/lib/webidl2.js +++ b/testing/web-platform/tests/resources/webidl2/lib/webidl2.js @@ -1,1012 +1,1084 @@ +(function() { + var tokenise = function(str) { + var tokens = [], + re = { + "float": /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/, + "integer": /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/, + "identifier": /^[A-Z_a-z][0-9A-Z_a-z-]*/, + "string": /^"[^"]*"/, + "whitespace": /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)*?\*\/)[\t\n\r ]*))+/, + "other": /^[^\t\n\r 0-9A-Z_a-z]/ + }, + types = ["float", "integer", "identifier", "string", "whitespace", "other"]; + while (str.length > 0) { + var matched = false; + for (var i = 0, n = types.length; i < n; i++) { + var type = types[i]; + str = str.replace(re[type], function(tok) { + tokens.push({ type: type, value: tok }); + matched = true; + return ""; + }); + if (matched) break; + } + if (matched) continue; + throw new Error("Token stream not progressing"); + } + return tokens; + }; + function WebIDLParseError(str, line, input, tokens) { + this.message = str; + this.line = line; + this.input = input; + this.tokens = tokens; + }; -(function () { - var tokenise = function (str) { - var tokens = [] - , re = { - "float": /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/ - , "integer": /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/ - , "identifier": /^[A-Z_a-z][0-9A-Z_a-z]*/ - , "string": /^"[^"]*"/ - , "whitespace": /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)*?\*\/)[\t\n\r ]*))+/ - , "other": /^[^\t\n\r 0-9A-Z_a-z]/ - } - , types = [] - ; - for (var k in re) types.push(k); - while (str.length > 0) { + WebIDLParseError.prototype.toString = function() { + return this.message + ", line " + this.line + " (tokens: '" + this.input + "')\n" + + JSON.stringify(this.tokens, null, 4); + }; + + var parse = function(tokens, opt) { + var line = 1; + tokens = tokens.slice(); + + var FLOAT = "float", + INT = "integer", + ID = "identifier", + STR = "string", + OTHER = "other"; + + var error = function(str) { + var tok = ""; + var numTokens = 0; + var maxTokens = 5; + while (numTokens < maxTokens && tokens.length > numTokens) { + tok += tokens[numTokens].value; + numTokens++; + } + throw new WebIDLParseError(str, line, tok, tokens.slice(0, 5)); + }; + + var last_token = null; + + var consume = function(type, value) { + if (!tokens.length || tokens[0].type !== type) return; + if (typeof value === "undefined" || tokens[0].value === value) { + last_token = tokens.shift(); + if (type === ID) last_token.value = last_token.value.replace(/^_/, ""); + return last_token; + } + }; + + var ws = function() { + if (!tokens.length) return; + if (tokens[0].type === "whitespace") { + var t = tokens.shift(); + t.value.replace(/\n/g, function(m) { line++; + return m; }); + return t; + } + }; + + var all_ws = function(store, pea) { // pea == post extended attribute, tpea = same for types + var t = { type: "whitespace", value: "" }; + while (true) { + var w = ws(); + if (!w) break; + t.value += w.value; + } + if (t.value.length > 0) { + if (store) { + var w = t.value, + re = { + "ws": /^([\t\n\r ]+)/, + "line-comment": /^\/\/(.*)\n?/m, + "multiline-comment": /^\/\*((?:.|\n|\r)*?)\*\// + }, + wsTypes = []; + for (var k in re) wsTypes.push(k); + while (w.length) { var matched = false; - for (var i = 0, n = types.length; i < n; i++) { - var type = types[i]; - str = str.replace(re[type], function (tok) { - tokens.push({ type: type, value: tok }); - matched = true; - return ""; - }); - if (matched) break; + for (var i = 0, n = wsTypes.length; i < n; i++) { + var type = wsTypes[i]; + w = w.replace(re[type], function(tok, m1) { + store.push({ type: type + (pea ? ("-" + pea) : ""), value: m1 }); + matched = true; + return ""; + }); + if (matched) break; } if (matched) continue; - throw new Error("Token stream not progressing"); + throw new Error("Surprising white space construct."); // this shouldn't happen + } } - return tokens; + return t; + } }; + + var integer_type = function() { + var ret = ""; + all_ws(); + if (consume(ID, "unsigned")) ret = "unsigned "; + all_ws(); + if (consume(ID, "short")) return ret + "short"; + if (consume(ID, "long")) { + ret += "long"; + all_ws(); + if (consume(ID, "long")) return ret + " long"; + return ret; + } + if (ret) error("Failed to parse integer type"); + }; + + var float_type = function() { + var ret = ""; + all_ws(); + if (consume(ID, "unrestricted")) ret = "unrestricted "; + all_ws(); + if (consume(ID, "float")) return ret + "float"; + if (consume(ID, "double")) return ret + "double"; + if (ret) error("Failed to parse float type"); + }; + + var primitive_type = function() { + var num_type = integer_type() || float_type(); + if (num_type) return num_type; + all_ws(); + if (consume(ID, "boolean")) return "boolean"; + if (consume(ID, "byte")) return "byte"; + if (consume(ID, "octet")) return "octet"; + }; + + var const_value = function() { + if (consume(ID, "true")) return { type: "boolean", value: true }; + if (consume(ID, "false")) return { type: "boolean", value: false }; + if (consume(ID, "null")) return { type: "null" }; + if (consume(ID, "Infinity")) return { type: "Infinity", negative: false }; + if (consume(ID, "NaN")) return { type: "NaN" }; + var ret = consume(FLOAT) || consume(INT); + if (ret) return { type: "number", value: 1 * ret.value }; + var tok = consume(OTHER, "-"); + if (tok) { + if (consume(ID, "Infinity")) return { type: "Infinity", negative: true }; + else tokens.unshift(tok); + } + }; + + var type_suffix = function(obj) { + while (true) { + all_ws(); + if (consume(OTHER, "?")) { + if (obj.nullable) error("Can't nullable more than once"); + obj.nullable = true; + } else if (consume(OTHER, "[")) { + all_ws(); + consume(OTHER, "]") || error("Unterminated array type"); + if (!obj.array) { + obj.array = 1; + obj.nullableArray = [obj.nullable]; + } else { + obj.array++; + obj.nullableArray.push(obj.nullable); + } + obj.nullable = false; + } else return; + } + }; + + var single_type = function() { + var prim = primitive_type(), + ret = { sequence: false, generic: null, nullable: false, array: false, union: false }, + name, value; + if (prim) { + ret.idlType = prim; + } else if (name = consume(ID)) { + value = name.value; + all_ws(); + // Generic types + if (consume(OTHER, "<")) { + // backwards compat + if (value === "sequence") { + ret.sequence = true; + } + ret.generic = value; + var types = []; + do { + all_ws(); + types.push(type() || error("Error parsing generic type " + value)); + all_ws(); + } + while (consume(OTHER, ",")); + if (value === "sequence") { + if (types.length !== 1) error("A sequence must have exactly one subtype"); + } else if (value === "record") { + if (types.length !== 2) error("A record must have exactly two subtypes"); + if (!/^(DOMString|USVString|ByteString)$/.test(types[0].idlType)) { + error("Record key must be DOMString, USVString, or ByteString"); + } + } + ret.idlType = types.length === 1 ? types[0] : types; + all_ws(); + if (!consume(OTHER, ">")) error("Unterminated generic type " + value); + type_suffix(ret); + return ret; + } else { + ret.idlType = value; + } + } else { + return; + } + type_suffix(ret); + if (ret.nullable && !ret.array && ret.idlType === "any") error("Type any cannot be made nullable"); + return ret; + }; + + var union_type = function() { + all_ws(); + if (!consume(OTHER, "(")) return; + var ret = { sequence: false, generic: null, nullable: false, array: false, union: true, idlType: [] }; + var fst = type_with_extended_attributes() || error("Union type with no content"); + ret.idlType.push(fst); + while (true) { + all_ws(); + if (!consume(ID, "or")) break; + var typ = type_with_extended_attributes() || error("No type after 'or' in union type"); + ret.idlType.push(typ); + } + if (!consume(OTHER, ")")) error("Unterminated union type"); + type_suffix(ret); + return ret; + }; + + var type = function() { + return single_type() || union_type(); + }; + + var type_with_extended_attributes = function() { + var extAttrs = extended_attrs(); + var ret = single_type() || union_type(); + if (extAttrs.length && ret) ret.extAttrs = extAttrs; + return ret; + }; + + var argument = function(store) { + var ret = { optional: false, variadic: false }; + ret.extAttrs = extended_attrs(store); + all_ws(store, "pea"); + var opt_token = consume(ID, "optional"); + if (opt_token) { + ret.optional = true; + all_ws(); + } + ret.idlType = type_with_extended_attributes(); + if (!ret.idlType) { + if (opt_token) tokens.unshift(opt_token); + return; + } + var type_token = last_token; + if (!ret.optional) { + all_ws(); + if (tokens.length >= 3 && + tokens[0].type === "other" && tokens[0].value === "." && + tokens[1].type === "other" && tokens[1].value === "." && + tokens[2].type === "other" && tokens[2].value === "." + ) { + tokens.shift(); + tokens.shift(); + tokens.shift(); + ret.variadic = true; + } + } + all_ws(); + var name = consume(ID); + if (!name) { + if (opt_token) tokens.unshift(opt_token); + tokens.unshift(type_token); + return; + } + ret.name = name.value; + if (ret.optional) { + all_ws(); + var dflt = default_(); + if (typeof dflt !== "undefined") { + ret["default"] = dflt; + } + } + return ret; + }; + + var argument_list = function(store) { + var ret = [], + arg = argument(store ? ret : null); + if (!arg) return; + ret.push(arg); + while (true) { + all_ws(store ? ret : null); + if (!consume(OTHER, ",")) return ret; + var nxt = argument(store ? ret : null) || error("Trailing comma in arguments list"); + ret.push(nxt); + } + }; + + var simple_extended_attr = function(store) { + all_ws(); + var name = consume(ID); + if (!name) return; + var ret = { + name: name.value, + "arguments": null + }; + all_ws(); + var eq = consume(OTHER, "="); + if (eq) { + var rhs; + all_ws(); + if (rhs = consume(ID)) { + ret.rhs = rhs; + } else if (rhs = consume(FLOAT)) { + ret.rhs = rhs; + } else if (rhs = consume(INT)) { + ret.rhs = rhs; + } else if (rhs = consume(STR)) { + ret.rhs = rhs; + } else if (consume(OTHER, "(")) { + // [Exposed=(Window,Worker)] + rhs = []; + var id = consume(ID); + if (id) { + rhs = [id.value]; + } + identifiers(rhs); + consume(OTHER, ")") || error("Unexpected token in extended attribute argument list or type pair"); + ret.rhs = { + type: "identifier-list", + value: rhs + }; + } + if (!ret.rhs) return error("No right hand side to extended attribute assignment"); + } + all_ws(); + if (consume(OTHER, "(")) { + var args, pair; + // [Constructor(DOMString str)] + if (args = argument_list(store)) { + ret["arguments"] = args; + } + // [Constructor()] + else { + ret["arguments"] = []; + } + all_ws(); + consume(OTHER, ")") || error("Unexpected token in extended attribute argument list"); + } + return ret; + }; + + // Note: we parse something simpler than the official syntax. It's all that ever + // seems to be used + var extended_attrs = function(store) { + var eas = []; + all_ws(store); + if (!consume(OTHER, "[")) return eas; + eas[0] = simple_extended_attr(store) || error("Extended attribute with not content"); + all_ws(); + while (consume(OTHER, ",")) { + if (eas.length) { + eas.push(simple_extended_attr(store)); + } else { + eas.push(simple_extended_attr(store) || error("Trailing comma in extended attribute")); + } + } + consume(OTHER, "]") || error("No end of extended attribute"); + return eas; + }; + + var default_ = function() { + all_ws(); + if (consume(OTHER, "=")) { + all_ws(); + var def = const_value(); + if (def) { + return def; + } else if (consume(OTHER, "[")) { + if (!consume(OTHER, "]")) error("Default sequence value must be empty"); + return { type: "sequence", value: [] }; + } else { + var str = consume(STR) || error("No value for default"); + str.value = str.value.replace(/^"/, "").replace(/"$/, ""); + return str; + } + } + }; + + var const_ = function(store) { + all_ws(store, "pea"); + if (!consume(ID, "const")) return; + var ret = { type: "const", nullable: false }; + all_ws(); + var typ = primitive_type(); + if (!typ) { + typ = consume(ID) || error("No type for const"); + typ = typ.value; + } + ret.idlType = typ; + all_ws(); + if (consume(OTHER, "?")) { + ret.nullable = true; + all_ws(); + } + var name = consume(ID) || error("No name for const"); + ret.name = name.value; + all_ws(); + consume(OTHER, "=") || error("No value assignment for const"); + all_ws(); + var cnt = const_value(); + if (cnt) ret.value = cnt; + else error("No value for const"); + all_ws(); + consume(OTHER, ";") || error("Unterminated const"); + return ret; + }; + + var inheritance = function() { + all_ws(); + if (consume(OTHER, ":")) { + all_ws(); + var inh = consume(ID) || error("No type in inheritance"); + return inh.value; + } + }; + + var operation_rest = function(ret, store) { + all_ws(); + if (!ret) ret = {}; + var name = consume(ID); + ret.name = name ? name.value : null; + all_ws(); + consume(OTHER, "(") || error("Invalid operation"); + ret["arguments"] = argument_list(store) || []; + all_ws(); + consume(OTHER, ")") || error("Unterminated operation"); + all_ws(); + consume(OTHER, ";") || error("Unterminated operation"); + return ret; + }; + + var callback = function(store) { + all_ws(store, "pea"); + var ret; + if (!consume(ID, "callback")) return; + all_ws(); + var tok = consume(ID, "interface"); + if (tok) { + tokens.unshift(tok); + ret = interface_(); + ret.type = "callback interface"; + return ret; + } + var name = consume(ID) || error("No name for callback"); + ret = { type: "callback", name: name.value }; + all_ws(); + consume(OTHER, "=") || error("No assignment in callback"); + all_ws(); + ret.idlType = return_type(); + all_ws(); + consume(OTHER, "(") || error("No arguments in callback"); + ret["arguments"] = argument_list(store) || []; + all_ws(); + consume(OTHER, ")") || error("Unterminated callback"); + all_ws(); + consume(OTHER, ";") || error("Unterminated callback"); + return ret; + }; + + var attribute = function(store) { + all_ws(store, "pea"); + var grabbed = [], + ret = { + type: "attribute", + "static": false, + stringifier: false, + inherit: false, + readonly: false + }; + if (consume(ID, "static")) { + ret["static"] = true; + grabbed.push(last_token); + } else if (consume(ID, "stringifier")) { + ret.stringifier = true; + grabbed.push(last_token); + } + var w = all_ws(); + if (w) grabbed.push(w); + if (consume(ID, "inherit")) { + if (ret["static"] || ret.stringifier) error("Cannot have a static or stringifier inherit"); + ret.inherit = true; + grabbed.push(last_token); + var w = all_ws(); + if (w) grabbed.push(w); + } + if (consume(ID, "readonly")) { + ret.readonly = true; + grabbed.push(last_token); + var w = all_ws(); + if (w) grabbed.push(w); + } + var rest = attribute_rest(ret); + if (!rest) { + tokens = grabbed.concat(tokens); + } + return rest; + }; + + var attribute_rest = function(ret) { + if (!consume(ID, "attribute")) { + return; + } + all_ws(); + ret.idlType = type_with_extended_attributes() || error("No type in attribute"); + if (ret.idlType.sequence) error("Attributes cannot accept sequence types"); + if (ret.idlType.generic === "record") error("Attributes cannot accept record types"); + all_ws(); + var name = consume(ID) || error("No name in attribute"); + ret.name = name.value; + all_ws(); + consume(OTHER, ";") || error("Unterminated attribute"); + return ret; + }; + + var return_type = function() { + var typ = type(); + if (!typ) { + if (consume(ID, "void")) { + return "void"; + } else error("No return type"); + } + return typ; + }; + + var operation = function(store) { + all_ws(store, "pea"); + var ret = { + type: "operation", + getter: false, + setter: false, + creator: false, + deleter: false, + legacycaller: false, + "static": false, + stringifier: false + }; + while (true) { + all_ws(); + if (consume(ID, "getter")) ret.getter = true; + else if (consume(ID, "setter")) ret.setter = true; + else if (consume(ID, "creator")) ret.creator = true; + else if (consume(ID, "deleter")) ret.deleter = true; + else if (consume(ID, "legacycaller")) ret.legacycaller = true; + else break; + } + if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) { + all_ws(); + ret.idlType = return_type(); + operation_rest(ret, store); + return ret; + } + if (consume(ID, "static")) { + ret["static"] = true; + ret.idlType = return_type(); + operation_rest(ret, store); + return ret; + } else if (consume(ID, "stringifier")) { + ret.stringifier = true; - + all_ws(); + if (consume(OTHER, ";")) return ret; + ret.idlType = return_type(); + operation_rest(ret, store); + return ret; + } + ret.idlType = return_type(); + all_ws(); + if (consume(ID, "iterator")) { + all_ws(); + ret.type = "iterator"; + if (consume(ID, "object")) { + ret.iteratorObject = "object"; + } else if (consume(OTHER, "=")) { + all_ws(); + var name = consume(ID) || error("No right hand side in iterator"); + ret.iteratorObject = name.value; + } + all_ws(); + consume(OTHER, ";") || error("Unterminated iterator"); + return ret; + } else { + operation_rest(ret, store); + return ret; + } + }; + + var identifiers = function(arr) { + while (true) { + all_ws(); + if (consume(OTHER, ",")) { + all_ws(); + var name = consume(ID) || error("Trailing comma in identifiers list"); + arr.push(name.value); + } else break; + } + }; + + var serialiser = function(store) { + all_ws(store, "pea"); + if (!consume(ID, "serializer")) return; + var ret = { type: "serializer" }; + all_ws(); + if (consume(OTHER, "=")) { + all_ws(); + if (consume(OTHER, "{")) { + ret.patternMap = true; + all_ws(); + var id = consume(ID); + if (id && id.value === "getter") { + ret.names = ["getter"]; + } else if (id && id.value === "inherit") { + ret.names = ["inherit"]; + identifiers(ret.names); + } else if (id) { + ret.names = [id.value]; + identifiers(ret.names); + } else { + ret.names = []; + } + all_ws(); + consume(OTHER, "}") || error("Unterminated serializer pattern map"); + } else if (consume(OTHER, "[")) { + ret.patternList = true; + all_ws(); + var id = consume(ID); + if (id && id.value === "getter") { + ret.names = ["getter"]; + } else if (id) { + ret.names = [id.value]; + identifiers(ret.names); + } else { + ret.names = []; + } + all_ws(); + consume(OTHER, "]") || error("Unterminated serializer pattern list"); + } else { + var name = consume(ID) || error("Invalid serializer"); + ret.name = name.value; + } + all_ws(); + consume(OTHER, ";") || error("Unterminated serializer"); + return ret; + } else if (consume(OTHER, ";")) { + // noop, just parsing + } else { + ret.idlType = return_type(); + all_ws(); + ret.operation = operation_rest(null, store); + } + return ret; + }; + + var iterable_type = function() { + if (consume(ID, "iterable")) return "iterable"; + else if (consume(ID, "legacyiterable")) return "legacyiterable"; + else if (consume(ID, "maplike")) return "maplike"; + else if (consume(ID, "setlike")) return "setlike"; + else return; + }; + + var readonly_iterable_type = function() { + if (consume(ID, "maplike")) return "maplike"; + else if (consume(ID, "setlike")) return "setlike"; + else return; + }; + + var iterable = function(store) { + all_ws(store, "pea"); + var grabbed = [], + ret = { type: null, idlType: null, readonly: false }; + if (consume(ID, "readonly")) { + ret.readonly = true; + grabbed.push(last_token); + var w = all_ws(); + if (w) grabbed.push(w); + } + var consumeItType = ret.readonly ? readonly_iterable_type : iterable_type; + + var ittype = consumeItType(); + if (!ittype) { + tokens = grabbed.concat(tokens); + return; + } + + var secondTypeRequired = ittype === "maplike"; + var secondTypeAllowed = secondTypeRequired || ittype === "iterable"; + ret.type = ittype; + if (ret.type !== 'maplike' && ret.type !== 'setlike') + delete ret.readonly; + all_ws(); + if (consume(OTHER, "<")) { + ret.idlType = type_with_extended_attributes() || error("Error parsing " + ittype + " declaration"); + all_ws(); + if (secondTypeAllowed) { + var type2 = null; + if (consume(OTHER, ",")) { + all_ws(); + type2 = type_with_extended_attributes(); + all_ws(); + } + if (type2) + ret.idlType = [ret.idlType, type2]; + else if (secondTypeRequired) + error("Missing second type argument in " + ittype + " declaration"); + } + if (!consume(OTHER, ">")) error("Unterminated " + ittype + " declaration"); + all_ws(); + if (!consume(OTHER, ";")) error("Missing semicolon after " + ittype + " declaration"); + } else + error("Error parsing " + ittype + " declaration"); + + return ret; + }; + + var interface_ = function(isPartial, store) { + all_ws(isPartial ? null : store, "pea"); + if (!consume(ID, "interface")) return; + all_ws(); + var name = consume(ID) || error("No name for interface"); + var mems = [], + ret = { + type: "interface", + name: name.value, + partial: false, + members: mems + }; + if (!isPartial) ret.inheritance = inheritance() || null; + all_ws(); + consume(OTHER, "{") || error("Bodyless interface"); + while (true) { + all_ws(store ? mems : null); + if (consume(OTHER, "}")) { + all_ws(); + consume(OTHER, ";") || error("Missing semicolon after interface"); + return ret; + } + var ea = extended_attrs(store ? mems : null); + all_ws(); + var cnt = const_(store ? mems : null); + if (cnt) { + cnt.extAttrs = ea; + ret.members.push(cnt); + continue; + } + var mem = (opt.allowNestedTypedefs && typedef(store ? mems : null)) || + iterable(store ? mems : null) || + serialiser(store ? mems : null) || + attribute(store ? mems : null) || + operation(store ? mems : null) || + error("Unknown member"); + mem.extAttrs = ea; + ret.members.push(mem); + } + }; + + var namespace = function(isPartial, store) { + all_ws(isPartial ? null : store, "pea"); + if (!consume(ID, "namespace")) return; + all_ws(); + var name = consume(ID) || error("No name for namespace"); + var mems = [], + ret = { + type: "namespace", + name: name.value, + partial: isPartial, + members: mems + }; + all_ws(); + consume(OTHER, "{") || error("Bodyless namespace"); + while (true) { + all_ws(store ? mems : null); + if (consume(OTHER, "}")) { + all_ws(); + consume(OTHER, ";") || error("Missing semicolon after namespace"); + return ret; + } + var ea = extended_attrs(store ? mems : null); + all_ws(); + var mem = noninherited_attribute(store ? mems : null) || + nonspecial_operation(store ? mems : null) || + error("Unknown member"); + mem.extAttrs = ea; + ret.members.push(mem); + } + } + + var noninherited_attribute = function(store) { + var w = all_ws(store, "pea"), + grabbed = [], + ret = { + type: "attribute", + "static": false, + stringifier: false, + inherit: false, + readonly: false + }; + if (w) grabbed.push(w); + if (consume(ID, "readonly")) { + ret.readonly = true; + grabbed.push(last_token); + var w = all_ws(); + if (w) grabbed.push(w); + } + var rest = attribute_rest(ret); + if (!rest) { + tokens = grabbed.concat(tokens); + } + return rest; + } - var parse = function (tokens, opt) { - var line = 1; - tokens = tokens.slice(); - - var FLOAT = "float" - , INT = "integer" - , ID = "identifier" - , STR = "string" - , OTHER = "other" - ; - - var WebIDLParseError = function (str, line, input, tokens) { - this.message = str; - this.line = line; - this.input = input; - this.tokens = tokens; - }; - WebIDLParseError.prototype.toString = function () { - return this.message + ", line " + this.line + " (tokens: '" + this.input + "')\n" + - JSON.stringify(this.tokens, null, 4); - }; - - var error = function (str) { - var tok = "", numTokens = 0, maxTokens = 5; - while (numTokens < maxTokens && tokens.length > numTokens) { - tok += tokens[numTokens].value; - numTokens++; - } - throw new WebIDLParseError(str, line, tok, tokens.slice(0, 5)); - }; - - var last_token = null; - - var consume = function (type, value) { - if (!tokens.length || tokens[0].type !== type) return; - if (typeof value === "undefined" || tokens[0].value === value) { - last_token = tokens.shift(); - if (type === ID) last_token.value = last_token.value.replace(/^_/, ""); - return last_token; - } - }; - - var ws = function () { - if (!tokens.length) return; - if (tokens[0].type === "whitespace") { - var t = tokens.shift(); - t.value.replace(/\n/g, function (m) { line++; return m; }); - return t; - } - }; - - var all_ws = function (store, pea) { // pea == post extended attribute, tpea = same for types - var t = { type: "whitespace", value: "" }; - while (true) { - var w = ws(); - if (!w) break; - t.value += w.value; - } - if (t.value.length > 0) { - if (store) { - var w = t.value - , re = { - "ws": /^([\t\n\r ]+)/ - , "line-comment": /^\/\/(.*)\n?/m - , "multiline-comment": /^\/\*((?:.|\n|\r)*?)\*\// - } - , wsTypes = [] - ; - for (var k in re) wsTypes.push(k); - while (w.length) { - var matched = false; - for (var i = 0, n = wsTypes.length; i < n; i++) { - var type = wsTypes[i]; - w = w.replace(re[type], function (tok, m1) { - store.push({ type: type + (pea ? ("-" + pea) : ""), value: m1 }); - matched = true; - return ""; - }); - if (matched) break; - } - if (matched) continue; - throw new Error("Surprising white space construct."); // this shouldn't happen - } - } - return t; - } - }; - - var integer_type = function () { - var ret = ""; - all_ws(); - if (consume(ID, "unsigned")) ret = "unsigned "; - all_ws(); - if (consume(ID, "short")) return ret + "short"; - if (consume(ID, "long")) { - ret += "long"; - all_ws(); - if (consume(ID, "long")) return ret + " long"; - return ret; - } - if (ret) error("Failed to parse integer type"); - }; - - var float_type = function () { - var ret = ""; - all_ws(); - if (consume(ID, "unrestricted")) ret = "unrestricted "; - all_ws(); - if (consume(ID, "float")) return ret + "float"; - if (consume(ID, "double")) return ret + "double"; - if (ret) error("Failed to parse float type"); - }; - - var primitive_type = function () { - var num_type = integer_type() || float_type(); - if (num_type) return num_type; - all_ws(); - if (consume(ID, "boolean")) return "boolean"; - if (consume(ID, "byte")) return "byte"; - if (consume(ID, "octet")) return "octet"; - }; - - var const_value = function () { - if (consume(ID, "true")) return { type: "boolean", value: true }; - if (consume(ID, "false")) return { type: "boolean", value: false }; - if (consume(ID, "null")) return { type: "null" }; - if (consume(ID, "Infinity")) return { type: "Infinity", negative: false }; - if (consume(ID, "NaN")) return { type: "NaN" }; - var ret = consume(FLOAT) || consume(INT); - if (ret) return { type: "number", value: 1 * ret.value }; - var tok = consume(OTHER, "-"); - if (tok) { - if (consume(ID, "Infinity")) return { type: "Infinity", negative: true }; - else tokens.unshift(tok); - } - }; - - var type_suffix = function (obj) { - while (true) { - all_ws(); - if (consume(OTHER, "?")) { - if (obj.nullable) error("Can't nullable more than once"); - obj.nullable = true; - } - else if (consume(OTHER, "[")) { - all_ws(); - consume(OTHER, "]") || error("Unterminated array type"); - if (!obj.array) { - obj.array = 1; - obj.nullableArray = [obj.nullable]; - } - else { - obj.array++; - obj.nullableArray.push(obj.nullable); - } - obj.nullable = false; - } - else return; - } - }; - - var single_type = function () { - var prim = primitive_type() - , ret = { sequence: false, generic: null, nullable: false, array: false, union: false } - , name - , value - ; - if (prim) { - ret.idlType = prim; - } - else if (name = consume(ID)) { - value = name.value; - all_ws(); - // Generic types - if (consume(OTHER, "<")) { - // backwards compat - if (value === "sequence") { - ret.sequence = true; - } - ret.generic = value; - ret.idlType = type() || error("Error parsing generic type " + value); - all_ws(); - if (!consume(OTHER, ">")) error("Unterminated generic type " + value); - type_suffix(ret); - return ret; - } - else { - ret.idlType = value; - } - } - else { - return; - } - type_suffix(ret); - if (ret.nullable && !ret.array && ret.idlType === "any") error("Type any cannot be made nullable"); - return ret; - }; - - var union_type = function () { - all_ws(); - if (!consume(OTHER, "(")) return; - var ret = { sequence: false, generic: null, nullable: false, array: false, union: true, idlType: [] }; - var fst = type() || error("Union type with no content"); - ret.idlType.push(fst); - while (true) { - all_ws(); - if (!consume(ID, "or")) break; - var typ = type() || error("No type after 'or' in union type"); - ret.idlType.push(typ); - } - if (!consume(OTHER, ")")) error("Unterminated union type"); - type_suffix(ret); - return ret; - }; - - var type = function () { - return single_type() || union_type(); - }; - - var argument = function (store) { - var ret = { optional: false, variadic: false }; - ret.extAttrs = extended_attrs(store); - all_ws(store, "pea"); - var opt_token = consume(ID, "optional"); - if (opt_token) { - ret.optional = true; - all_ws(); - } - ret.idlType = type(); - if (!ret.idlType) { - if (opt_token) tokens.unshift(opt_token); - return; - } - var type_token = last_token; - if (!ret.optional) { - all_ws(); - if (tokens.length >= 3 && - tokens[0].type === "other" && tokens[0].value === "." && - tokens[1].type === "other" && tokens[1].value === "." && - tokens[2].type === "other" && tokens[2].value === "." - ) { - tokens.shift(); - tokens.shift(); - tokens.shift(); - ret.variadic = true; - } - } - all_ws(); - var name = consume(ID); - if (!name) { - if (opt_token) tokens.unshift(opt_token); - tokens.unshift(type_token); - return; - } - ret.name = name.value; - if (ret.optional) { - all_ws(); - ret["default"] = default_(); - } - return ret; - }; - - var argument_list = function (store) { - var ret = [] - , arg = argument(store ? ret : null) - ; - if (!arg) return; - ret.push(arg); - while (true) { - all_ws(store ? ret : null); - if (!consume(OTHER, ",")) return ret; - var nxt = argument(store ? ret : null) || error("Trailing comma in arguments list"); - ret.push(nxt); - } - }; - - var type_pair = function () { - all_ws(); - var k = type(); - if (!k) return; - all_ws() - if (!consume(OTHER, ",")) return; - all_ws(); - var v = type(); - if (!v) return; - return [k, v]; - }; - - var simple_extended_attr = function (store) { - all_ws(); - var name = consume(ID); - if (!name) return; - var ret = { - name: name.value - , "arguments": null - }; - all_ws(); - var eq = consume(OTHER, "="); - if (eq) { - var rhs; - all_ws(); - if (rhs = consume(ID)) { - ret.rhs = rhs - } - else if (consume(OTHER, "(")) { - // [Exposed=(Window,Worker)] - rhs = []; - var id = consume(ID); - if (id) { - rhs = [id.value]; - } - identifiers(rhs); - consume(OTHER, ")") || error("Unexpected token in extended attribute argument list or type pair"); - ret.rhs = { - type: "identifier-list", - value: rhs - }; - } - if (!ret.rhs) return error("No right hand side to extended attribute assignment"); - } - all_ws(); - if (consume(OTHER, "(")) { - var args, pair; - // [Constructor(DOMString str)] - if (args = argument_list(store)) { - ret["arguments"] = args; - } - // [MapClass(DOMString, DOMString)] - else if (pair = type_pair()) { - ret.typePair = pair; - } - // [Constructor()] - else { - ret["arguments"] = []; - } - all_ws(); - consume(OTHER, ")") || error("Unexpected token in extended attribute argument list or type pair"); - } - return ret; - }; - - // Note: we parse something simpler than the official syntax. It's all that ever - // seems to be used - var extended_attrs = function (store) { - var eas = []; - all_ws(store); - if (!consume(OTHER, "[")) return eas; - eas[0] = simple_extended_attr(store) || error("Extended attribute with not content"); - all_ws(); - while (consume(OTHER, ",")) { - eas.push(simple_extended_attr(store) || error("Trailing comma in extended attribute")); - all_ws(); - } - consume(OTHER, "]") || error("No end of extended attribute"); - return eas; - }; - - var default_ = function () { - all_ws(); - if (consume(OTHER, "=")) { - all_ws(); - var def = const_value(); - if (def) { - return def; - } - else if (consume(OTHER, "[")) { - if (!consume(OTHER, "]")) error("Default sequence value must be empty"); - return { type: "sequence", value: [] }; - } - else { - var str = consume(STR) || error("No value for default"); - str.value = str.value.replace(/^"/, "").replace(/"$/, ""); - return str; - } - } - }; - - var const_ = function (store) { - all_ws(store, "pea"); - if (!consume(ID, "const")) return; - var ret = { type: "const", nullable: false }; - all_ws(); - var typ = primitive_type(); - if (!typ) { - typ = consume(ID) || error("No type for const"); - typ = typ.value; - } - ret.idlType = typ; - all_ws(); - if (consume(OTHER, "?")) { - ret.nullable = true; - all_ws(); - } - var name = consume(ID) || error("No name for const"); - ret.name = name.value; - all_ws(); - consume(OTHER, "=") || error("No value assignment for const"); - all_ws(); - var cnt = const_value(); - if (cnt) ret.value = cnt; - else error("No value for const"); - all_ws(); - consume(OTHER, ";") || error("Unterminated const"); - return ret; - }; - - var inheritance = function () { - all_ws(); - if (consume(OTHER, ":")) { - all_ws(); - var inh = consume(ID) || error ("No type in inheritance"); - return inh.value; - } - }; - - var operation_rest = function (ret, store) { - all_ws(); - if (!ret) ret = {}; - var name = consume(ID); - ret.name = name ? name.value : null; - all_ws(); - consume(OTHER, "(") || error("Invalid operation"); - ret["arguments"] = argument_list(store) || []; - all_ws(); - consume(OTHER, ")") || error("Unterminated operation"); - all_ws(); - consume(OTHER, ";") || error("Unterminated operation"); - return ret; - }; - - var callback = function (store) { - all_ws(store, "pea"); - var ret; - if (!consume(ID, "callback")) return; - all_ws(); - var tok = consume(ID, "interface"); - if (tok) { - tokens.unshift(tok); - ret = interface_(); - ret.type = "callback interface"; - return ret; - } - var name = consume(ID) || error("No name for callback"); - ret = { type: "callback", name: name.value }; - all_ws(); - consume(OTHER, "=") || error("No assignment in callback"); - all_ws(); - ret.idlType = return_type(); - all_ws(); - consume(OTHER, "(") || error("No arguments in callback"); - ret["arguments"] = argument_list(store) || []; - all_ws(); - consume(OTHER, ")") || error("Unterminated callback"); - all_ws(); - consume(OTHER, ";") || error("Unterminated callback"); - return ret; - }; + var nonspecial_operation = function(store) { + all_ws(store, "pea"); + var ret = { + type: "operation", + getter: false, + setter: false, + creator: false, + deleter: false, + legacycaller: false, + "static": false, + stringifier: false + }; + ret.idlType = return_type(); + return operation_rest(ret, store); + } - var attribute = function (store) { - all_ws(store, "pea"); - var grabbed = [] - , ret = { - type: "attribute" - , "static": false - , stringifier: false - , inherit: false - , readonly: false - }; - if (consume(ID, "static")) { - ret["static"] = true; - grabbed.push(last_token); - } - else if (consume(ID, "stringifier")) { - ret.stringifier = true; - grabbed.push(last_token); - } - var w = all_ws(); - if (w) grabbed.push(w); - if (consume(ID, "inherit")) { - if (ret["static"] || ret.stringifier) error("Cannot have a static or stringifier inherit"); - ret.inherit = true; - grabbed.push(last_token); - var w = all_ws(); - if (w) grabbed.push(w); - } - if (consume(ID, "readonly")) { - ret.readonly = true; - grabbed.push(last_token); - var w = all_ws(); - if (w) grabbed.push(w); - } - if (!consume(ID, "attribute")) { - tokens = grabbed.concat(tokens); - return; - } - all_ws(); - ret.idlType = type() || error("No type in attribute"); - if (ret.idlType.sequence) error("Attributes cannot accept sequence types"); - all_ws(); - var name = consume(ID) || error("No name in attribute"); - ret.name = name.value; - all_ws(); - consume(OTHER, ";") || error("Unterminated attribute"); - return ret; - }; - - var return_type = function () { - var typ = type(); - if (!typ) { - if (consume(ID, "void")) { - return "void"; - } - else error("No return type"); - } - return typ; - }; - - var operation = function (store) { - all_ws(store, "pea"); - var ret = { - type: "operation" - , getter: false - , setter: false - , creator: false - , deleter: false - , legacycaller: false - , "static": false - , stringifier: false - }; - while (true) { - all_ws(); - if (consume(ID, "getter")) ret.getter = true; - else if (consume(ID, "setter")) ret.setter = true; - else if (consume(ID, "creator")) ret.creator = true; - else if (consume(ID, "deleter")) ret.deleter = true; - else if (consume(ID, "legacycaller")) ret.legacycaller = true; - else break; - } - if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) { - all_ws(); - ret.idlType = return_type(); - operation_rest(ret, store); - return ret; - } - if (consume(ID, "static")) { - ret["static"] = true; - ret.idlType = return_type(); - operation_rest(ret, store); - return ret; - } - else if (consume(ID, "stringifier")) { - ret.stringifier = true;- - all_ws(); - if (consume(OTHER, ";")) return ret; - ret.idlType = return_type(); - operation_rest(ret, store); - return ret; - } - ret.idlType = return_type(); - all_ws(); - if (consume(ID, "iterator")) { - all_ws(); - ret.type = "iterator"; - if (consume(ID, "object")) { - ret.iteratorObject = "object"; - } - else if (consume(OTHER, "=")) { - all_ws(); - var name = consume(ID) || error("No right hand side in iterator"); - ret.iteratorObject = name.value; - } - all_ws(); - consume(OTHER, ";") || error("Unterminated iterator"); - return ret; - } - else { - operation_rest(ret, store); - return ret; - } - }; - - var identifiers = function (arr) { - while (true) { - all_ws(); - if (consume(OTHER, ",")) { - all_ws(); - var name = consume(ID) || error("Trailing comma in identifiers list"); - arr.push(name.value); - } - else break; - } - }; - - var serialiser = function (store) { - all_ws(store, "pea"); - if (!consume(ID, "serializer")) return; - var ret = { type: "serializer" }; - all_ws(); - if (consume(OTHER, "=")) { - all_ws(); - if (consume(OTHER, "{")) { - ret.patternMap = true; - all_ws(); - var id = consume(ID); - if (id && id.value === "getter") { - ret.names = ["getter"]; - } - else if (id && id.value === "inherit") { - ret.names = ["inherit"]; - identifiers(ret.names); - } - else if (id) { - ret.names = [id.value]; - identifiers(ret.names); - } - else { - ret.names = []; - } - all_ws(); - consume(OTHER, "}") || error("Unterminated serializer pattern map"); - } - else if (consume(OTHER, "[")) { - ret.patternList = true; - all_ws(); - var id = consume(ID); - if (id && id.value === "getter") { - ret.names = ["getter"]; - } - else if (id) { - ret.names = [id.value]; - identifiers(ret.names); - } - else { - ret.names = []; - } - all_ws(); - consume(OTHER, "]") || error("Unterminated serializer pattern list"); - } - else { - var name = consume(ID) || error("Invalid serializer"); - ret.name = name.value; - } - all_ws(); - consume(OTHER, ";") || error("Unterminated serializer"); - return ret; - } - else if (consume(OTHER, ";")) { - // noop, just parsing - } - else { - ret.idlType = return_type(); - all_ws(); - ret.operation = operation_rest(null, store); - } - return ret; - }; - - var iterable_type = function() { - if (consume(ID, "iterable")) return "iterable"; - else if (consume(ID, "legacyiterable")) return "legacyiterable"; - else if (consume(ID, "maplike")) return "maplike"; - else if (consume(ID, "setlike")) return "setlike"; - else return; - } - - var readonly_iterable_type = function() { - if (consume(ID, "maplike")) return "maplike"; - else if (consume(ID, "setlike")) return "setlike"; - else return; - } - - var iterable = function (store) { - all_ws(store, "pea"); - var grabbed = [], - ret = {type: null, idlType: null, readonly: false}; - if (consume(ID, "readonly")) { - ret.readonly = true; - grabbed.push(last_token); - var w = all_ws(); - if (w) grabbed.push(w); - } - var consumeItType = ret.readonly ? readonly_iterable_type : iterable_type; - - var ittype = consumeItType(); - if (!ittype) { - tokens = grabbed.concat(tokens); - return; - } - - var secondTypeRequired = ittype === "maplike"; - var secondTypeAllowed = secondTypeRequired || ittype === "iterable"; - ret.type = ittype; - if (ret.type !== 'maplike' && ret.type !== 'setlike') - delete ret.readonly; - all_ws(); - if (consume(OTHER, "<")) { - ret.idlType = type() || error("Error parsing " + ittype + " declaration"); - all_ws(); - if (secondTypeAllowed) { - var type2 = null; - if (consume(OTHER, ",")) { - all_ws(); - type2 = type(); - all_ws(); - } - if (type2) - ret.idlType = [ret.idlType, type2]; - else if (secondTypeRequired) - error("Missing second type argument in " + ittype + " declaration"); - } - if (!consume(OTHER, ">")) error("Unterminated " + ittype + " declaration"); - all_ws(); - if (!consume(OTHER, ";")) error("Missing semicolon after " + ittype + " declaration"); - } - else - error("Error parsing " + ittype + " declaration"); - - return ret; - } - - var interface_ = function (isPartial, store) { - all_ws(isPartial ? null : store, "pea"); - if (!consume(ID, "interface")) return; - all_ws(); - var name = consume(ID) || error("No name for interface"); - var mems = [] - , ret = { - type: "interface" - , name: name.value - , partial: false - , members: mems - }; - if (!isPartial) ret.inheritance = inheritance() || null; - all_ws(); - consume(OTHER, "{") || error("Bodyless interface"); - while (true) { - all_ws(store ? mems : null); - if (consume(OTHER, "}")) { - all_ws(); - consume(OTHER, ";") || error("Missing semicolon after interface"); - return ret; - } - var ea = extended_attrs(store ? mems : null); - all_ws(); - var cnt = const_(store ? mems : null); - if (cnt) { - cnt.extAttrs = ea; - ret.members.push(cnt); - continue; - } - var mem = (opt.allowNestedTypedefs && typedef(store ? mems : null)) || - iterable(store ? mems : null) || - serialiser(store ? mems : null) || - attribute(store ? mems : null) || - operation(store ? mems : null) || - error("Unknown member"); - mem.extAttrs = ea; - ret.members.push(mem); - } - }; - - var partial = function (store) { - all_ws(store, "pea"); - if (!consume(ID, "partial")) return; - var thing = dictionary(true, store) || - interface_(true, store) || - error("Partial doesn't apply to anything"); - thing.partial = true; - return thing; - }; - - var dictionary = function (isPartial, store) { - all_ws(isPartial ? null : store, "pea"); - if (!consume(ID, "dictionary")) return; - all_ws(); - var name = consume(ID) || error("No name for dictionary"); - var mems = [] - , ret = { - type: "dictionary" - , name: name.value - , partial: false - , members: mems - }; - if (!isPartial) ret.inheritance = inheritance() || null; - all_ws(); - consume(OTHER, "{") || error("Bodyless dictionary"); - while (true) { - all_ws(store ? mems : null); - if (consume(OTHER, "}")) { - all_ws(); - consume(OTHER, ";") || error("Missing semicolon after dictionary"); - return ret; - } - var ea = extended_attrs(store ? mems : null); - all_ws(store ? mems : null, "pea"); - var required = consume(ID, "required"); - var typ = type() || error("No type for dictionary member"); - all_ws(); - var name = consume(ID) || error("No name for dictionary member"); - var dflt = default_(); - if (required && dflt) error("Required member must not have a default"); - ret.members.push({ - type: "field" - , name: name.value - , required: !!required - , idlType: typ - , extAttrs: ea - , "default": dflt - }); - all_ws(); - consume(OTHER, ";") || error("Unterminated dictionary member"); - } - }; - - var exception = function (store) { - all_ws(store, "pea"); - if (!consume(ID, "exception")) return; - all_ws(); - var name = consume(ID) || error("No name for exception"); - var mems = [] - , ret = { - type: "exception" - , name: name.value - , members: mems - }; - ret.inheritance = inheritance() || null; - all_ws(); - consume(OTHER, "{") || error("Bodyless exception"); - while (true) { - all_ws(store ? mems : null); - if (consume(OTHER, "}")) { - all_ws(); - consume(OTHER, ";") || error("Missing semicolon after exception"); - return ret; - } - var ea = extended_attrs(store ? mems : null); - all_ws(store ? mems : null, "pea"); - var cnt = const_(); - if (cnt) { - cnt.extAttrs = ea; - ret.members.push(cnt); - } - else { - var typ = type(); - all_ws(); - var name = consume(ID); - all_ws(); - if (!typ || !name || !consume(OTHER, ";")) error("Unknown member in exception body"); - ret.members.push({ - type: "field" - , name: name.value - , idlType: typ - , extAttrs: ea - }); - } - } - }; - - var enum_ = function (store) { - all_ws(store, "pea"); - if (!consume(ID, "enum")) return; - all_ws(); - var name = consume(ID) || error("No name for enum"); - var vals = [] - , ret = { - type: "enum" - , name: name.value - , values: vals - }; - all_ws(); - consume(OTHER, "{") || error("No curly for enum"); - var saw_comma = false; - while (true) { - all_ws(store ? vals : null); - if (consume(OTHER, "}")) { - all_ws(); - consume(OTHER, ";") || error("No semicolon after enum"); - return ret; - } - var val = consume(STR) || error("Unexpected value in enum"); - ret.values.push(val.value.replace(/"/g, "")); - all_ws(store ? vals : null); - if (consume(OTHER, ",")) { - if (store) vals.push({ type: "," }); - all_ws(store ? vals : null); - saw_comma = true; - } - else { - saw_comma = false; - } - } - }; - - var typedef = function (store) { - all_ws(store, "pea"); - if (!consume(ID, "typedef")) return; - var ret = { - type: "typedef" - }; - all_ws(); - ret.typeExtAttrs = extended_attrs(); - all_ws(store, "tpea"); - ret.idlType = type() || error("No type in typedef"); - all_ws(); - var name = consume(ID) || error("No name in typedef"); - ret.name = name.value; - all_ws(); - consume(OTHER, ";") || error("Unterminated typedef"); - return ret; - }; - - var implements_ = function (store) { - all_ws(store, "pea"); - var target = consume(ID); - if (!target) return; - var w = all_ws(); - if (consume(ID, "implements")) { - var ret = { - type: "implements" - , target: target.value - }; - all_ws(); - var imp = consume(ID) || error("Incomplete implements statement"); - ret["implements"] = imp.value; - all_ws(); - consume(OTHER, ";") || error("No terminating ; for implements statement"); - return ret; - } - else { - // rollback - tokens.unshift(w); - tokens.unshift(target); - } - }; - - var definition = function (store) { - return callback(store) || - interface_(false, store) || - partial(store) || - dictionary(false, store) || - exception(store) || - enum_(store) || - typedef(store) || - implements_(store) - ; - }; - - var definitions = function (store) { - if (!tokens.length) return []; - var defs = []; - while (true) { - var ea = extended_attrs(store ? defs : null) - , def = definition(store ? defs : null); - if (!def) { - if (ea.length) error("Stray extended attributes"); - break; - } - def.extAttrs = ea; - defs.push(def); - } - return defs; - }; - var res = definitions(opt.ws); - if (tokens.length) error("Unrecognised tokens"); - return res; + var partial = function(store) { + all_ws(store, "pea"); + if (!consume(ID, "partial")) return; + var thing = dictionary(true, store) || + interface_(true, store) || + namespace(true, store) || + error("Partial doesn't apply to anything"); + thing.partial = true; + return thing; }; - var inNode = typeof module !== "undefined" && module.exports - , obj = { - parse: function (str, opt) { - if (!opt) opt = {}; - var tokens = tokenise(str); - return parse(tokens, opt); - } + var dictionary = function(isPartial, store) { + all_ws(isPartial ? null : store, "pea"); + if (!consume(ID, "dictionary")) return; + all_ws(); + var name = consume(ID) || error("No name for dictionary"); + var mems = [], + ret = { + type: "dictionary", + name: name.value, + partial: false, + members: mems + }; + if (!isPartial) ret.inheritance = inheritance() || null; + all_ws(); + consume(OTHER, "{") || error("Bodyless dictionary"); + while (true) { + all_ws(store ? mems : null); + if (consume(OTHER, "}")) { + all_ws(); + consume(OTHER, ";") || error("Missing semicolon after dictionary"); + return ret; + } + var ea = extended_attrs(store ? mems : null); + all_ws(store ? mems : null, "pea"); + var required = consume(ID, "required"); + var typ = type_with_extended_attributes() || error("No type for dictionary member"); + all_ws(); + var name = consume(ID) || error("No name for dictionary member"); + var dflt = default_(); + if (required && dflt) error("Required member must not have a default"); + var member = { + type: "field", + name: name.value, + required: !!required, + idlType: typ, + extAttrs: ea + }; + if (typeof dflt !== "undefined") { + member["default"] = dflt; + } + ret.members.push(member); + all_ws(); + consume(OTHER, ";") || error("Unterminated dictionary member"); + } }; - if (inNode) module.exports = obj; - else self.WebIDL2 = obj; + var exception = function(store) { + all_ws(store, "pea"); + if (!consume(ID, "exception")) return; + all_ws(); + var name = consume(ID) || error("No name for exception"); + var mems = [], + ret = { + type: "exception", + name: name.value, + members: mems + }; + ret.inheritance = inheritance() || null; + all_ws(); + consume(OTHER, "{") || error("Bodyless exception"); + while (true) { + all_ws(store ? mems : null); + if (consume(OTHER, "}")) { + all_ws(); + consume(OTHER, ";") || error("Missing semicolon after exception"); + return ret; + } + var ea = extended_attrs(store ? mems : null); + all_ws(store ? mems : null, "pea"); + var cnt = const_(); + if (cnt) { + cnt.extAttrs = ea; + ret.members.push(cnt); + } else { + var typ = type(); + all_ws(); + var name = consume(ID); + all_ws(); + if (!typ || !name || !consume(OTHER, ";")) error("Unknown member in exception body"); + ret.members.push({ + type: "field", + name: name.value, + idlType: typ, + extAttrs: ea + }); + } + } + }; + + var enum_ = function(store) { + all_ws(store, "pea"); + if (!consume(ID, "enum")) return; + all_ws(); + var name = consume(ID) || error("No name for enum"); + var vals = [], + ret = { + type: "enum", + name: name.value, + values: vals + }; + all_ws(); + consume(OTHER, "{") || error("No curly for enum"); + var saw_comma = false; + while (true) { + all_ws(store ? vals : null); + if (consume(OTHER, "}")) { + all_ws(); + consume(OTHER, ";") || error("No semicolon after enum"); + return ret; + } + var val = consume(STR) || error("Unexpected value in enum"); + ret.values.push(val.value.replace(/"/g, "")); + all_ws(store ? vals : null); + if (consume(OTHER, ",")) { + if (store) vals.push({ type: "," }); + all_ws(store ? vals : null); + saw_comma = true; + } else { + saw_comma = false; + } + } + }; + + var typedef = function(store) { + all_ws(store, "pea"); + if (!consume(ID, "typedef")) return; + var ret = { + type: "typedef" + }; + all_ws(); + ret.idlType = type_with_extended_attributes() || error("No type in typedef"); + all_ws(); + var name = consume(ID) || error("No name in typedef"); + ret.name = name.value; + all_ws(); + consume(OTHER, ";") || error("Unterminated typedef"); + return ret; + }; + + var implements_ = function(store) { + all_ws(store, "pea"); + var target = consume(ID); + if (!target) return; + var w = all_ws(); + if (consume(ID, "implements")) { + var ret = { + type: "implements", + target: target.value + }; + all_ws(); + var imp = consume(ID) || error("Incomplete implements statement"); + ret["implements"] = imp.value; + all_ws(); + consume(OTHER, ";") || error("No terminating ; for implements statement"); + return ret; + } else { + // rollback + tokens.unshift(w); + tokens.unshift(target); + } + }; + + var definition = function(store) { + return callback(store) || + interface_(false, store) || + partial(store) || + dictionary(false, store) || + exception(store) || + enum_(store) || + typedef(store) || + implements_(store) || + namespace(false, store); + }; + + var definitions = function(store) { + if (!tokens.length) return []; + var defs = []; + while (true) { + var ea = extended_attrs(store ? defs : null), + def = definition(store ? defs : null); + if (!def) { + if (ea.length) error("Stray extended attributes"); + break; + } + def.extAttrs = ea; + defs.push(def); + } + return defs; + }; + var res = definitions(opt.ws); + if (tokens.length) error("Unrecognised tokens"); + return res; + }; + + var obj = { + parse: function(str, opt) { + if (!opt) opt = {}; + var tokens = tokenise(str); + return parse(tokens, opt); + } + }; + + if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = obj; + } else if (typeof define === 'function' && define.amd) { + define([], function() { + return obj; + }); + } else { + (self || window).WebIDL2 = obj; + } }()); diff --git a/testing/web-platform/tests/resources/webidl2/lib/writer.js b/testing/web-platform/tests/resources/webidl2/lib/writer.js index ba8363738235..f7c79f828935 100644 --- a/testing/web-platform/tests/resources/webidl2/lib/writer.js +++ b/testing/web-platform/tests/resources/webidl2/lib/writer.js @@ -1,236 +1,280 @@ +(function() { -(function () { + var write = function(ast, opt) { + var curPea = "", + curTPea = "", + opt = opt || {}, + noop = function(str) { + return str; }, + optNames = "type".split(" "), + context = []; + for (var i = 0, n = optNames.length; i < n; i++) { + var o = optNames[i]; + if (!opt[o]) opt[o] = noop; + } - var write = function (ast, opt) { - var curPea = "" - , curTPea = "" - , opt = opt || {} - , noop = function (str) { return str; } - , optNames = "type".split(" ") - , context = [] - ; - for (var i = 0, n = optNames.length; i < n; i++) { - var o = optNames[i]; - if (!opt[o]) opt[o] = noop; + var literal = function(it) { + return it.value; + }; + var wsPea = function(it) { + curPea += it.value; + return ""; + }; + var wsTPea = function(it) { + curTPea += it.value; + return ""; + }; + var lineComment = function(it) { + return "//" + it.value + "\n"; + }; + var multilineComment = function(it) { + return "/*" + it.value + "*/"; + }; + var type = function(it) { + if (typeof it === "string") return opt.type(it); // XXX should maintain some context + if (it.union) return "(" + it.idlType.map(type).join(" or ") + ")"; + var ret = ""; + if (it.generic) ret += it.generic + "<"; + else if (it.sequence) ret += "sequence<"; + if (Array.isArray(it.idlType)) ret += it.idlType.map(type).join(", "); + else ret += type(it.idlType); + if (it.array || it.generic === 'Array') { + for (var i = 0, n = it.nullableArray.length; i < n; i++) { + var val = it.nullableArray[i]; + if (val) ret += "?"; + ret += "[]"; } - - var literal = function (it) { - return it.value; - }; - var wsPea = function (it) { - curPea += it.value; - return ""; - }; - var wsTPea = function (it) { - curTPea += it.value; - return ""; - }; - var lineComment = function (it) { - return "//" + it.value + "\n"; - }; - var multilineComment = function (it) { - return "/*" + it.value + "*/"; - }; - var type = function (it) { - if (typeof it === "string") return opt.type(it); // XXX should maintain some context - if (it.union) return "(" + it.idlType.map(type).join(" or ") + ")"; - var ret = ""; - if (it.sequence) ret += "sequence<"; - ret += type(it.idlType); - if (it.array) { - for (var i = 0, n = it.nullableArray.length; i < n; i++) { - var val = it.nullableArray[i]; - if (val) ret += "?"; - ret += "[]"; - } - } - if (it.sequence) ret += ">"; - if (it.nullable) ret += "?"; + } + if (it.generic || it.sequence) ret += ">"; + if (it.nullable) ret += "?"; - return ret; - }; - var const_value = function (it) { - var tp = it. type; - if (tp === "boolean") return it.value ? "true" : "false"; - else if (tp === "null") return "null"; - else if (tp === "Infinity") return (it.negative ? "-" : "") + "Infinity"; - else if (tp === "NaN") return "NaN"; - else if (tp === "number") return it.value; - else return '"' + it.value + '"'; - }; - var argument = function (arg, pea) { - var ret = extended_attributes(arg.extAttrs, pea); - if (arg.optional) ret += "optional "; - ret += type(arg.idlType); - if (arg.variadic) ret += "..."; - ret += " " + arg.name; - if (arg["default"]) ret += " = " + const_value(arg["default"]); - return ret; - }; - var args = function (its) { - var res = "" - , pea = "" - ; - for (var i = 0, n = its.length; i < n; i++) { - var arg = its[i]; - if (arg.type === "ws") res += arg.value; - else if (arg.type === "ws-pea") pea += arg.value; - else { - res += argument(arg, pea); - if (i < n - 1) res += ","; - pea = ""; - } - } - return res; - }; - var make_ext_at = function (it) { - if (it["arguments"] === null) return it.name; - context.unshift(it); - var ret = it.name + "(" + (it["arguments"].length ? args(it["arguments"]) : "") + ")"; - context.shift(); // XXX need to add more contexts, but not more than needed for ReSpec - return ret; - }; - var extended_attributes = function (eats, pea) { - if (!eats || !eats.length) return ""; - return "[" + eats.map(make_ext_at).join(", ") + "]" + pea; - }; - - var modifiers = "getter setter creator deleter legacycaller stringifier static".split(" "); - var operation = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - if (it.stringifier && !it.idlType) return "stringifier;"; - for (var i = 0, n = modifiers.length; i < n; i++) { - var mod = modifiers[i]; - if (it[mod]) ret += mod + " "; - } - ret += type(it.idlType) + " "; - if (it.name) ret += it.name; - ret += "(" + args(it["arguments"]) + ");"; - return ret; - }; - - var attribute = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - if (it["static"]) ret += "static "; - if (it.stringifier) ret += "stringifier "; - if (it.readonly) ret += "readonly "; - if (it.inherit) ret += "inherit "; - ret += "attribute " + type(it.idlType) + " " + it.name + ";"; - return ret; - }; - - var interface_ = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - if (it.partial) ret += "partial "; - ret += "interface " + it.name + " "; - if (it.inheritance) ret += ": " + it.inheritance + " "; - ret += "{" + iterate(it.members) + "};"; - return ret; - }; - - var dictionary = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - if (it.partial) ret += "partial "; - ret += "dictionary " + it.name + " "; - ret += "{" + iterate(it.members) + "};"; - return ret; - }; - var field = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - ret += type(it.idlType) + " " + it.name; - if (it["default"]) ret += " = " + const_value(it["default"]); - ret += ";"; - return ret; - }; - var exception = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - ret += "exception " + it.name + " "; - if (it.inheritance) ret += ": " + it.inheritance + " "; - ret += "{" + iterate(it.members) + "};"; - return ret; - }; - var const_ = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - return ret + "const " + type(it.idlType) + " " + it.name + " = " + const_value(it.value) + ";"; - }; - var typedef = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - ret += "typedef " + extended_attributes(it.typeExtAttrs, curTPea); - curTPea = ""; - return ret + type(it.idlType) + " " + it.name + ";"; - }; - var implements_ = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - return ret + it.target + " implements " + it["implements"] + ";"; - }; - var callback = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - return ret + "callback " + it.name + " = " + type(it.idlType) + - "(" + args(it["arguments"]) + ");"; - }; - var enum_ = function (it) { - var ret = extended_attributes(it.extAttrs, curPea); - curPea = ""; - ret += "enum " + it.name + " {"; - for (var i = 0, n = it.values.length; i < n; i++) { - var v = it.values[i]; - if (typeof v === "string") ret += '"' + v + '"'; - else if (v.type === "ws") ret += v.value; - else if (v.type === ",") ret += ","; - } - return ret + "};"; - }; - - var table = { - ws: literal - , "ws-pea": wsPea - , "ws-tpea": wsTPea - , "line-comment": lineComment - , "multiline-comment": multilineComment - , "interface": interface_ - , operation: operation - , attribute: attribute - , dictionary: dictionary - , field: field - , exception: exception - , "const": const_ - , typedef: typedef - , "implements": implements_ - , callback: callback - , "enum": enum_ - }; - var dispatch = function (it) { - return table[it.type](it); - }; - var iterate = function (things) { - if (!things) return; - var ret = ""; - for (var i = 0, n = things.length; i < n; i++) ret += dispatch(things[i]); - return ret; - }; - return iterate(ast); + return ret; + }; + var const_value = function(it) { + var tp = it.type; + if (tp === "boolean") return it.value ? "true" : "false"; + else if (tp === "null") return "null"; + else if (tp === "Infinity") return (it.negative ? "-" : "") + "Infinity"; + else if (tp === "NaN") return "NaN"; + else if (tp === "number") return it.value; + else return '"' + it.value + '"'; + }; + var argument = function(arg, pea) { + var ret = extended_attributes(arg.extAttrs, pea); + if (arg.optional) ret += "optional "; + ret += type(arg.idlType); + if (arg.variadic) ret += "..."; + ret += " " + arg.name; + if (arg["default"]) ret += " = " + const_value(arg["default"]); + return ret; + }; + var args = function(its) { + var res = "", + pea = ""; + for (var i = 0, n = its.length; i < n; i++) { + var arg = its[i]; + if (arg.type === "ws") res += arg.value; + else if (arg.type === "ws-pea") pea += arg.value; + else { + res += argument(arg, pea); + if (i < n - 1) res += ","; + pea = ""; + } + } + return res; + }; + var make_ext_at = function(it) { + if (it["arguments"] === null) return it.name; + context.unshift(it); + var ret = it.name + "(" + (it["arguments"].length ? args(it["arguments"]) : "") + ")"; + context.shift(); // XXX need to add more contexts, but not more than needed for ReSpec + return ret; + }; + var extended_attributes = function(eats, pea) { + if (!eats || !eats.length) return ""; + return "[" + eats.map(make_ext_at).join(", ") + "]" + pea; }; - - var inNode = typeof module !== "undefined" && module.exports - , obj = { - write: function (ast, opt) { - if (!opt) opt = {}; - return write(ast, opt); - } + var modifiers = "getter setter creator deleter legacycaller stringifier static".split(" "); + var operation = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + if (it.stringifier && !it.idlType) return "stringifier;"; + for (var i = 0, n = modifiers.length; i < n; i++) { + var mod = modifiers[i]; + if (it[mod]) ret += mod + " "; + } + ret += type(it.idlType) + " "; + if (it.name) ret += it.name; + ret += "(" + args(it["arguments"]) + ");"; + return ret; }; - if (inNode) module.exports = obj; - else window.WebIDL2Writer = obj; - + var attribute = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + if (it["static"]) ret += "static "; + if (it.stringifier) ret += "stringifier "; + if (it.readonly) ret += "readonly "; + if (it.inherit) ret += "inherit "; + ret += "attribute " + type(it.idlType) + " " + it.name + ";"; + return ret; + }; + + var interface_ = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + if (it.partial) ret += "partial "; + ret += "interface " + it.name + " "; + if (it.inheritance) ret += ": " + it.inheritance + " "; + ret += "{" + iterate(it.members) + "};"; + return ret; + }; + + var dictionary = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + if (it.partial) ret += "partial "; + ret += "dictionary " + it.name + " "; + ret += "{" + iterate(it.members) + "};"; + return ret; + }; + var field = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + if (it.required) ret += "required "; + ret += type(it.idlType) + " " + it.name; + if (it["default"]) ret += " = " + const_value(it["default"]); + ret += ";"; + return ret; + }; + var exception = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + ret += "exception " + it.name + " "; + if (it.inheritance) ret += ": " + it.inheritance + " "; + ret += "{" + iterate(it.members) + "};"; + return ret; + }; + var const_ = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + return ret + "const " + type(it.idlType) + " " + it.name + " = " + const_value(it.value) + ";"; + }; + var typedef = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + ret += "typedef " + extended_attributes(it.typeExtAttrs, curTPea); + curTPea = ""; + return ret + type(it.idlType) + " " + it.name + ";"; + }; + var implements_ = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + return ret + it.target + " implements " + it["implements"] + ";"; + }; + var callback = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + return ret + "callback " + it.name + " = " + type(it.idlType) + + "(" + args(it["arguments"]) + ");"; + }; + var enum_ = function(it) { + var ret = extended_attributes(it.extAttrs, curPea); + curPea = ""; + ret += "enum " + it.name + " {"; + for (var i = 0, n = it.values.length; i < n; i++) { + var v = it.values[i]; + if (typeof v === "string") ret += '"' + v + '"'; + else if (v.type === "ws") ret += v.value; + else if (v.type === ",") ret += ","; + } + return ret + "};"; + }; + var serializer = function(it) { + var ret = "serializer"; + if (it.name) { + ret += " = " + it.name + ";"; + } else if (it.patternList) { + ret += " = [ " + it.names.join(", ") + " ];"; + } else if (it.patternMap) { + ret += " = { " + it.names.join(", ") + " };"; + } else if (it.operation) { + ret += " " + operation(it); + } else { + ret += ";"; + } + return ret; + }; + var iterable = function(it) { + return "iterable<" + (it.idlType instanceof Array ? it.idlType.map(type).join(", ") : type(it.idlType)) + ">;"; + }; + var legacyiterable = function(it) { + return "legacyiterable<" + (it.idlType instanceof Array ? it.idlType.map(type).join(", ") : type(it.idlType)) + ">;"; + }; + var maplike = function(it) { + return (it.readonly ? "readonly " : "") + "maplike<" + + it.idlType.map(type).join(", ") + ">;"; + }; + var setlike = function(it) { + return (it.readonly ? "readonly " : "") + "setlike<" + + type(it.idlType) + ">;"; + }; + var callbackInterface = function(it) { + return 'callback ' + interface_(it); + }; + + var table = { + ws: literal, + "ws-pea": wsPea, + "ws-tpea": wsTPea, + "line-comment": lineComment, + "multiline-comment": multilineComment, + "interface": interface_, + operation: operation, + attribute: attribute, + dictionary: dictionary, + field: field, + exception: exception, + "const": const_, + typedef: typedef, + "implements": implements_, + callback: callback, + "enum": enum_, + serializer: serializer, + iterable: iterable, + legacyiterable: legacyiterable, + maplike: maplike, + setlike: setlike, + "callback interface": callbackInterface + }; + var dispatch = function(it) { + return table[it.type](it); + }; + var iterate = function(things) { + if (!things) return; + var ret = ""; + for (var i = 0, n = things.length; i < n; i++) ret += dispatch(things[i]); + return ret; + }; + return iterate(ast); + }; + + + var obj = { + write: function(ast, opt) { + if (!opt) opt = {}; + return write(ast, opt); + } + }; + + if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = obj; + } else if (typeof define === 'function' && define.amd) { + define([], function() { + return obj; + }); + } else { + (self || window).WebIDL2Writer = obj; + } }()); diff --git a/testing/web-platform/tests/resources/webidl2/package.json b/testing/web-platform/tests/resources/webidl2/package.json index c5ae7da2d593..02b2a9d9b164 100644 --- a/testing/web-platform/tests/resources/webidl2/package.json +++ b/testing/web-platform/tests/resources/webidl2/package.json @@ -1,17 +1,17 @@ { "name": "webidl2", "description": "A WebIDL Parser", - "version": "2.0.11", + "version": "2.4.0", "author": "Robin Berjon ", "license": "MIT", "dependencies": {}, "devDependencies": { - "mocha": "2.2.5", - "expect.js": "0.3.1", + "mocha": "3.2.0", + "expect": "1.20.2", "underscore": "1.8.3", - "jsondiffpatch": "0.1.31", + "jsondiffpatch": "0.2.4", "benchmark": "*", - "microtime": "1.4.2" + "microtime": "2.1.3" }, "scripts": { "test": "mocha" diff --git a/testing/web-platform/tests/resources/webidl2/test/invalid.js b/testing/web-platform/tests/resources/webidl2/test/invalid.js index c98218037264..b8ab3a1866de 100644 --- a/testing/web-platform/tests/resources/webidl2/test/invalid.js +++ b/testing/web-platform/tests/resources/webidl2/test/invalid.js @@ -4,7 +4,7 @@ // are fully correct interpretations of the IDLs var wp = process.env.JSCOV ? require("../lib-cov/webidl2") : require("../lib/webidl2") -, expect = require("expect.js") +, expect = require("expect") , pth = require("path") , fs = require("fs") ; @@ -16,7 +16,7 @@ describe("Parses all of the invalid IDLs to check that they blow up correctly", .map(function (it) { return pth.join(dir, it); }) , errors = idls.map(function (it) { return pth.join(__dirname, "invalid", "json", pth.basename(it).replace(/\.w?idl/, ".json")); }) ; - + for (var i = 0, n = idls.length; i < n; i++) { var idl = idls[i], error = JSON.parse(fs.readFileSync(errors[i], "utf8")); var func = (function (idl, err) { @@ -30,11 +30,11 @@ describe("Parses all of the invalid IDLs to check that they blow up correctly", error = e; } finally { - expect(error).to.be.ok(); - expect(error.message).to.equal(err.message); - expect(error.line).to.equal(err.line); + expect(error).toExist(); + expect(error.message).toEqual(err.message); + expect(error.line).toEqual(err.line); } - + }; }(idl, error)); it("should produce the right error for " + idl, func); diff --git a/testing/web-platform/tests/resources/webidl2/test/invalid/idl/record-key.widl b/testing/web-platform/tests/resources/webidl2/test/invalid/idl/record-key.widl new file mode 100644 index 000000000000..39dc386182f8 --- /dev/null +++ b/testing/web-platform/tests/resources/webidl2/test/invalid/idl/record-key.widl @@ -0,0 +1,3 @@ +interface Foo { + void foo(record param); +}; diff --git a/testing/web-platform/tests/resources/webidl2/test/invalid/json/record-key.json b/testing/web-platform/tests/resources/webidl2/test/invalid/json/record-key.json new file mode 100644 index 000000000000..3b929b926a30 --- /dev/null +++ b/testing/web-platform/tests/resources/webidl2/test/invalid/json/record-key.json @@ -0,0 +1,4 @@ +{ + "message": "Record key must be DOMString, USVString, or ByteString", + "line": 2 +} diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax.js b/testing/web-platform/tests/resources/webidl2/test/syntax.js index 712542a6be8e..3b343e4229d5 100644 --- a/testing/web-platform/tests/resources/webidl2/test/syntax.js +++ b/testing/web-platform/tests/resources/webidl2/test/syntax.js @@ -1,6 +1,6 @@ var wp = process.env.JSCOV ? require("../lib-cov/webidl2") : require("../lib/webidl2") -, expect = require("expect.js") +, expect = require("expect") , pth = require("path") , fs = require("fs") , jdp = require("jsondiffpatch") @@ -14,7 +14,7 @@ describe("Parses all of the IDLs to produce the correct ASTs", function () { .map(function (it) { return pth.join(dir, it); }) , jsons = idls.map(function (it) { return pth.join(__dirname, "syntax/json", pth.basename(it).replace(".widl", ".json")); }) ; - + for (var i = 0, n = idls.length; i < n; i++) { var idl = idls[i], json = jsons[i]; @@ -28,7 +28,7 @@ describe("Parses all of the IDLs to produce the correct ASTs", function () { var diff = jdp.diff(JSON.parse(fs.readFileSync(json, "utf8")), wp.parse(fs.readFileSync(idl, "utf8"), opt)); if (diff && debug) console.log(JSON.stringify(diff, null, 4)); - expect(diff).to.be(undefined); + expect(diff).toBe(undefined); } catch (e) { console.log(e.toString()); diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/extended-attributes.widl b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/extended-attributes.widl index f769c2559cc7..c1df79e142d5 100644 --- a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/extended-attributes.widl +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/extended-attributes.widl @@ -3,4 +3,9 @@ [Global=(Worker,ServiceWorker), Exposed=ServiceWorker] interface ServiceWorkerGlobalScope : WorkerGlobalScope { -}; \ No newline at end of file +}; + +// Conformance with ExtendedAttributeList grammar in http://www.w3.org/TR/WebIDL/#idl-extended-attributes +// Section 3.11 +[IntAttr=0, FloatAttr=3.14, StringAttr="abc"] +interface IdInterface {}; diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/map.widl b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/map.widl deleted file mode 100644 index 19b54f80a61a..000000000000 --- a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/map.widl +++ /dev/null @@ -1,5 +0,0 @@ -// Extracted from https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ on 2014-05-06 - -[MapClass(DOMString, DOMString)] -interface HeaderMap { -}; diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/namespace.widl b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/namespace.widl new file mode 100644 index 000000000000..d9610555e17a --- /dev/null +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/namespace.widl @@ -0,0 +1,10 @@ +// Extracted from Web IDL editors draft March 27 2017 +namespace VectorUtils { + readonly attribute Vector unit; + double dotProduct(Vector x, Vector y); + Vector crossProduct(Vector x, Vector y); +}; + +partial namespace SomeNamespace { + /* namespace_members... */ +}; \ No newline at end of file diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/record.widl b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/record.widl new file mode 100644 index 000000000000..6cdedb219bec --- /dev/null +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/record.widl @@ -0,0 +1,8 @@ +[Constructor(record init)] +interface Foo { + void foo(sequence> param); + record bar(); + + // Make sure record can still be registered as a type. + record baz(); +}; diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/typedef-nested.widl b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/typedef-nested.widl deleted file mode 100644 index 106f30b8f72e..000000000000 --- a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/typedef-nested.widl +++ /dev/null @@ -1,22 +0,0 @@ - - interface Point { - attribute float x; - attribute float y; - }; - - - interface Rect { - attribute Point topleft; - attribute Point bottomright; - }; - - interface Widget { - typedef sequence PointSequence; - - readonly attribute Rect bounds; - - boolean pointWithinBounds(Point p); - boolean allPointsWithinBounds(PointSequence ps); - }; - - typedef [Clamp] octet value; \ No newline at end of file diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/typedef-union.idl b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/typedef-union.idl new file mode 100644 index 000000000000..3048703e0c55 --- /dev/null +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/typedef-union.idl @@ -0,0 +1,4 @@ + typedef (ImageData or + HTMLImageElement or + HTMLCanvasElement or + HTMLVideoElement) TexImageSource; diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/uniontype.widl b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/uniontype.widl index 4d99f0196308..0d5fe9be4286 100644 --- a/testing/web-platform/tests/resources/webidl2/test/syntax/idl/uniontype.widl +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/idl/uniontype.widl @@ -1,3 +1,4 @@ interface Union { attribute (float or (Date or Event) or (Node or DOMString)?) test; + attribute ([EnforceRange] long or Date) test2; }; \ No newline at end of file diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/json/extended-attributes.json b/testing/web-platform/tests/resources/webidl2/test/syntax/json/extended-attributes.json index 228c4b824be3..3b5a3b2e22b3 100644 --- a/testing/web-platform/tests/resources/webidl2/test/syntax/json/extended-attributes.json +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/json/extended-attributes.json @@ -26,5 +26,38 @@ } } ] + }, + { + "type": "interface", + "name": "IdInterface", + "partial": false, + "members": [], + "inheritance": null, + "extAttrs": [ + { + "name": "IntAttr", + "arguments": null, + "rhs": { + "type": "integer", + "value": "0" + } + }, + { + "name": "FloatAttr", + "arguments": null, + "rhs": { + "type": "float", + "value": "3.14" + } + }, + { + "name": "StringAttr", + "arguments": null, + "rhs": { + "type": "string", + "value": "\"abc\"" + } + } + ] } -] \ No newline at end of file +] diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/json/identifier-qualified-names.json b/testing/web-platform/tests/resources/webidl2/test/syntax/json/identifier-qualified-names.json index a91f8c8eb53e..d87ea3b5f369 100644 --- a/testing/web-platform/tests/resources/webidl2/test/syntax/json/identifier-qualified-names.json +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/json/identifier-qualified-names.json @@ -1,7 +1,6 @@ [ { "type": "typedef", - "typeExtAttrs": [], "idlType": { "sequence": false, "generic": null, @@ -214,4 +213,4 @@ "inheritance": null, "extAttrs": [] } -] \ No newline at end of file +] diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/json/map.json b/testing/web-platform/tests/resources/webidl2/test/syntax/json/map.json deleted file mode 100644 index 03ce9412ed08..000000000000 --- a/testing/web-platform/tests/resources/webidl2/test/syntax/json/map.json +++ /dev/null @@ -1,29 +0,0 @@ -[ - { - "type": "interface", - "name": "HeaderMap", - "partial": false, - "members": [], - "inheritance": null, - "extAttrs": [{ - "name": "MapClass", - "arguments": null, - "typePair": [{ - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "DOMString" - }, - { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "DOMString" - }] - }] - } -] diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/json/namespace.json b/testing/web-platform/tests/resources/webidl2/test/syntax/json/namespace.json new file mode 100644 index 000000000000..7c7ba771e1bf --- /dev/null +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/json/namespace.json @@ -0,0 +1,134 @@ +[ + { + "type": "namespace", + "name": "VectorUtils", + "partial": false, + "members": [ + { + "type": "attribute", + "static": false, + "stringifier": false, + "inherit": false, + "readonly": true, + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "Vector" + }, + "name": "unit", + "extAttrs": [] + }, + { + "type": "operation", + "getter": false, + "setter": false, + "creator": false, + "deleter": false, + "legacycaller": false, + "static": false, + "stringifier": false, + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "double" + }, + "name": "dotProduct", + "arguments": [ + { + "optional": false, + "variadic": false, + "extAttrs": [], + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "Vector" + }, + "name": "x" + }, + { + "optional": false, + "variadic": false, + "extAttrs": [], + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "Vector" + }, + "name": "y" + } + ], + "extAttrs": [] + }, + { + "type": "operation", + "getter": false, + "setter": false, + "creator": false, + "deleter": false, + "legacycaller": false, + "static": false, + "stringifier": false, + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "Vector" + }, + "name": "crossProduct", + "arguments": [ + { + "optional": false, + "variadic": false, + "extAttrs": [], + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "Vector" + }, + "name": "x" + }, + { + "optional": false, + "variadic": false, + "extAttrs": [], + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "Vector" + }, + "name": "y" + } + ], + "extAttrs": [] + } + ], + "extAttrs": [] + }, + { + "type": "namespace", + "name": "SomeNamespace", + "partial": true, + "members": [], + "extAttrs": [] + } +] \ No newline at end of file diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/json/record.json b/testing/web-platform/tests/resources/webidl2/test/syntax/json/record.json new file mode 100644 index 000000000000..d2a21a4acd99 --- /dev/null +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/json/record.json @@ -0,0 +1,184 @@ +[ + { + "type": "interface", + "name": "Foo", + "partial": false, + "members": [ + { + "type": "operation", + "getter": false, + "setter": false, + "creator": false, + "deleter": false, + "legacycaller": false, + "static": false, + "stringifier": false, + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "void" + }, + "name": "foo", + "arguments": [ + { + "optional": false, + "variadic": false, + "extAttrs": [], + "idlType": { + "sequence": true, + "generic": "sequence", + "nullable": false, + "array": false, + "union": false, + "idlType": { + "sequence": false, + "generic": "record", + "nullable": false, + "array": false, + "union": false, + "idlType": [ + { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "ByteString" + }, + { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "any" + } + ] + } + }, + "name": "param" + } + ], + "extAttrs": [] + }, + { + "type": "operation", + "getter": false, + "setter": false, + "creator": false, + "deleter": false, + "legacycaller": false, + "static": false, + "stringifier": false, + "idlType": { + "sequence": false, + "generic": "record", + "nullable": false, + "array": false, + "union": false, + "idlType": [ + { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "DOMString" + }, + { + "sequence": false, + "generic": null, + "nullable": true, + "array": false, + "union": true, + "idlType": [ + { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "float" + }, + { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "DOMString" + } + ] + } + ] + }, + "name": "bar", + "arguments": [], + "extAttrs": [] + }, + { + "type": "operation", + "getter": false, + "setter": false, + "creator": false, + "deleter": false, + "legacycaller": false, + "static": false, + "stringifier": false, + "idlType": { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "record" + }, + "name": "baz", + "arguments": [], + "extAttrs": [] + } + ], + "inheritance": null, + "extAttrs": [ + { + "name": "Constructor", + "arguments": [ + { + "optional": false, + "variadic": false, + "extAttrs": [], + "idlType": { + "sequence": false, + "generic": "record", + "nullable": false, + "array": false, + "union": false, + "idlType": [ + { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "USVString" + }, + { + "sequence": false, + "generic": null, + "nullable": false, + "array": false, + "union": false, + "idlType": "USVString" + } + ] + }, + "name": "init" + } + ] + } + ] + } +] diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef-nested.json b/testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef-nested.json deleted file mode 100644 index 76d138408ddf..000000000000 --- a/testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef-nested.json +++ /dev/null @@ -1,226 +0,0 @@ -[ - { - "type": "interface", - "name": "Point", - "partial": false, - "members": [ - { - "type": "attribute", - "static": false, - "stringifier": false, - "inherit": false, - "readonly": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "float" - }, - "name": "x", - "extAttrs": [] - }, - { - "type": "attribute", - "static": false, - "stringifier": false, - "inherit": false, - "readonly": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "float" - }, - "name": "y", - "extAttrs": [] - } - ], - "inheritance": null, - "extAttrs": [] - }, - { - "type": "interface", - "name": "Rect", - "partial": false, - "members": [ - { - "type": "attribute", - "static": false, - "stringifier": false, - "inherit": false, - "readonly": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "Point" - }, - "name": "topleft", - "extAttrs": [] - }, - { - "type": "attribute", - "static": false, - "stringifier": false, - "inherit": false, - "readonly": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "Point" - }, - "name": "bottomright", - "extAttrs": [] - } - ], - "inheritance": null, - "extAttrs": [] - }, - { - "type": "interface", - "name": "Widget", - "partial": false, - "members": [ - { - "type": "typedef", - "typeExtAttrs": [], - "idlType": { - "sequence": true, - "generic": "sequence", - "nullable": false, - "array": false, - "union": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "Point" - } - }, - "name": "PointSequence", - "extAttrs": [] - }, - { - "type": "attribute", - "static": false, - "stringifier": false, - "inherit": false, - "readonly": true, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "Rect" - }, - "name": "bounds", - "extAttrs": [] - }, - { - "type": "operation", - "getter": false, - "setter": false, - "creator": false, - "deleter": false, - "legacycaller": false, - "static": false, - "stringifier": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "boolean" - }, - "name": "pointWithinBounds", - "arguments": [ - { - "optional": false, - "variadic": false, - "extAttrs": [], - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "Point" - }, - "name": "p" - } - ], - "extAttrs": [] - }, - { - "type": "operation", - "getter": false, - "setter": false, - "creator": false, - "deleter": false, - "legacycaller": false, - "static": false, - "stringifier": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "boolean" - }, - "name": "allPointsWithinBounds", - "arguments": [ - { - "optional": false, - "variadic": false, - "extAttrs": [], - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "PointSequence" - }, - "name": "ps" - } - ], - "extAttrs": [] - } - ], - "inheritance": null, - "extAttrs": [] - }, - { - "type": "typedef", - "typeExtAttrs": [ - { - "name": "Clamp", - "arguments": null - } - ], - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "octet" - }, - "name": "value", - "extAttrs": [] - } -] \ No newline at end of file diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef-union.json b/testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef-union.json new file mode 100644 index 000000000000..9c87672c8aeb --- /dev/null +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef-union.json @@ -0,0 +1,49 @@ +[ + { + "type" : "typedef", + "idlType" : { + "nullable" : false, + "generic" : null, + "union" : true, + "idlType" : [ + { + "union" : false, + "generic" : null, + "nullable" : false, + "array" : false, + "sequence" : false, + "idlType" : "ImageData" + }, + { + "generic" : null, + "union" : false, + "nullable" : false, + "array" : false, + "idlType" : "HTMLImageElement", + "sequence" : false + }, + { + "array" : false, + "sequence" : false, + "idlType" : "HTMLCanvasElement", + "generic" : null, + "union" : false, + "nullable" : false + }, + { + "union" : false, + "generic" : null, + "nullable" : false, + "array" : false, + "sequence" : false, + "idlType" : "HTMLVideoElement" + } + ], + "sequence" : false, + "array" : false + }, + "name" : "TexImageSource", + "extAttrs" : [], + "typeExtAttrs" : [] + } +] diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef.json b/testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef.json index ffdeea945d7f..d0854fa3d262 100644 --- a/testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef.json +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef.json @@ -44,7 +44,6 @@ }, { "type": "typedef", - "typeExtAttrs": [], "idlType": { "sequence": true, "generic": "sequence", @@ -206,21 +205,21 @@ }, { "type": "typedef", - "typeExtAttrs": [ - { - "name": "Clamp", - "arguments": null - } - ], "idlType": { "sequence": false, "generic": null, "nullable": false, "array": false, "union": false, - "idlType": "octet" + "idlType": "octet", + "extAttrs": [ + { + "name": "Clamp", + "arguments": null + } + ] }, "name": "value", "extAttrs": [] } -] \ No newline at end of file +] diff --git a/testing/web-platform/tests/resources/webidl2/test/syntax/json/uniontype.json b/testing/web-platform/tests/resources/webidl2/test/syntax/json/uniontype.json index 43e25fd6bfb8..9da5e79f3625 100644 --- a/testing/web-platform/tests/resources/webidl2/test/syntax/json/uniontype.json +++ b/testing/web-platform/tests/resources/webidl2/test/syntax/json/uniontype.json @@ -1,87 +1,127 @@ [ - { - "type": "interface", - "name": "Union", - "partial": false, - "members": [ - { - "type": "attribute", - "static": false, - "stringifier": false, - "inherit": false, - "readonly": false, - "idlType": { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": true, - "idlType": [ + { + "partial": false, + "members": [ + { + "idlType": { + "idlType": [ + { + "array": false, + "union": false, + "sequence": false, + "generic": null, + "idlType": "float", + "nullable": false + }, + { + "idlType": [ { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "float" + "nullable": false, + "idlType": "Date", + "sequence": false, + "generic": null, + "union": false, + "array": false }, { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": true, - "idlType": [ - { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "Date" - }, - { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "Event" - } - ] - }, - { - "sequence": false, - "generic": null, - "nullable": true, - "array": false, - "union": true, - "idlType": [ - { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "Node" - }, - { - "sequence": false, - "generic": null, - "nullable": false, - "array": false, - "union": false, - "idlType": "DOMString" - } - ] + "nullable": false, + "idlType": "Event", + "generic": null, + "sequence": false, + "array": false, + "union": false } - ] - }, - "name": "test", - "extAttrs": [] - } - ], - "inheritance": null, - "extAttrs": [] - } -] \ No newline at end of file + ], + "nullable": false, + "sequence": false, + "generic": null, + "array": false, + "union": true + }, + { + "generic": null, + "sequence": false, + "idlType": [ + { + "array": false, + "union": false, + "sequence": false, + "generic": null, + "nullable": false, + "idlType": "Node" + }, + { + "nullable": false, + "idlType": "DOMString", + "sequence": false, + "generic": null, + "array": false, + "union": false + } + ], + "nullable": true, + "union": true, + "array": false + } + ], + "nullable": false, + "generic": null, + "sequence": false, + "union": true, + "array": false + }, + "name": "test", + "inherit": false, + "type": "attribute", + "extAttrs": [], + "readonly": false, + "stringifier": false, + "static": false + }, + { + "readonly": false, + "extAttrs": [], + "stringifier": false, + "static": false, + "name": "test2", + "idlType": { + "nullable": false, + "idlType": [ + { + "extAttrs": [ + { + "name": "EnforceRange", + "arguments": null + } + ], + "nullable": false, + "idlType": "long", + "generic": null, + "sequence": false, + "array": false, + "union": false + }, + { + "array": false, + "union": false, + "sequence": false, + "generic": null, + "idlType": "Date", + "nullable": false + } + ], + "generic": null, + "sequence": false, + "union": true, + "array": false + }, + "inherit": false, + "type": "attribute" + } + ], + "inheritance": null, + "name": "Union", + "extAttrs": [], + "type": "interface" + } +] diff --git a/testing/web-platform/tests/resources/webidl2/test/web/make-web-tests.js b/testing/web-platform/tests/resources/webidl2/test/web/make-web-tests.js index 34c5a5c2b46d..1774806994e0 100644 --- a/testing/web-platform/tests/resources/webidl2/test/web/make-web-tests.js +++ b/testing/web-platform/tests/resources/webidl2/test/web/make-web-tests.js @@ -36,9 +36,10 @@ var pth = require("path") , " " , "
" , " " - , " " + , " " + , " " , " " - , " " + , " " , " " , " " , " " diff --git a/testing/web-platform/tests/resources/webidl2/test/web/run-tests.js b/testing/web-platform/tests/resources/webidl2/test/web/run-tests.js index a72800b8bdb8..452f799b2a6f 100644 --- a/testing/web-platform/tests/resources/webidl2/test/web/run-tests.js +++ b/testing/web-platform/tests/resources/webidl2/test/web/run-tests.js @@ -10,7 +10,7 @@ describe("Parses all of the IDLs to produce the correct ASTs", function () { // so we compare based on that var diff = jsondiffpatch.diff(json, WebIDL2.parse(idl)); if (diff && debug) console.log(JSON.stringify(diff, null, 4)); - expect(diff).to.be(undefined); + expect(diff).toBe(undefined); } catch (e) { console.log(e.toString()); @@ -36,11 +36,11 @@ describe("Parses all of the invalid IDLs to check that they blow up correctly", error = e; } finally { - expect(error).to.be.ok(); - expect(error.message).to.equal(err.message); - expect(error.line).to.equal(err.line); + expect(error).toExist(); + expect(error.message).toEqual(err.message); + expect(error.line).toEqual(err.line); } - + }; }(idl, error)); it("should produce the right error for " + i, func); diff --git a/testing/web-platform/tests/selection/collapse-00.html b/testing/web-platform/tests/selection/collapse-00.html index cc1eb7e6e1ef..6adaca4002dc 100644 --- a/testing/web-platform/tests/selection/collapse-00.html +++ b/testing/web-platform/tests/selection/collapse-00.html @@ -1,5 +1,5 @@ -Selection.collapse() tests +Selection.collapse()/setPosition() tests
@@ -9,6 +9,6 @@ diff --git a/testing/web-platform/tests/selection/collapse-15.html b/testing/web-platform/tests/selection/collapse-15.html new file mode 100644 index 000000000000..377e5044343c --- /dev/null +++ b/testing/web-platform/tests/selection/collapse-15.html @@ -0,0 +1,14 @@ + +Selection.collapse()/setPosition() tests + +
+ + + + + diff --git a/testing/web-platform/tests/selection/collapse-30.html b/testing/web-platform/tests/selection/collapse-30.html index 204586206b29..376633d9103e 100644 --- a/testing/web-platform/tests/selection/collapse-30.html +++ b/testing/web-platform/tests/selection/collapse-30.html @@ -1,5 +1,5 @@ -Selection.collapse() tests +Selection.collapse()/setPosition() tests
diff --git a/testing/web-platform/tests/selection/collapse-45.html b/testing/web-platform/tests/selection/collapse-45.html new file mode 100644 index 000000000000..28eee4eb7978 --- /dev/null +++ b/testing/web-platform/tests/selection/collapse-45.html @@ -0,0 +1,14 @@ + +Selection.collapse()/setPosition() tests + +
+ + + + + diff --git a/testing/web-platform/tests/selection/collapse.js b/testing/web-platform/tests/selection/collapse.js index 7c97e2725d6e..7d03f00c8c7b 100644 --- a/testing/web-platform/tests/selection/collapse.js +++ b/testing/web-platform/tests/selection/collapse.js @@ -1,6 +1,6 @@ "use strict"; -function testCollapse(range, point) { +function testCollapse(range, point, method) { selection.removeAllRanges(); var addedRange; if (range) { @@ -10,46 +10,46 @@ function testCollapse(range, point) { if (point[0].nodeType == Node.DOCUMENT_TYPE_NODE) { assert_throws("INVALID_NODE_TYPE_ERR", function() { - selection.collapse(point[0], point[1]); - }, "Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType"); + selection[method](point[0], point[1]); + }, "Must throw INVALID_NODE_TYPE_ERR when " + method + "()ing if the node is a DocumentType"); return; } if (point[1] < 0 || point[1] > getNodeLength(point[0])) { assert_throws("INDEX_SIZE_ERR", function() { - selection.collapse(point[0], point[1]); - }, "Must throw INDEX_SIZE_ERR when collapse()ing if the offset is negative or greater than the node's length"); + selection[method](point[0], point[1]); + }, "Must throw INDEX_SIZE_ERR when " + method + "()ing if the offset is negative or greater than the node's length"); return; } if (!document.contains(point[0])) { assertSelectionNoChange(function() { - selection.collapse(point[0], point[1]); + selection[method](point[0], point[1]); }); return; } - selection.collapse(point[0], point[1]); + selection[method](point[0], point[1]); assert_equals(selection.rangeCount, 1, - "selection.rangeCount must equal 1 after collapse()"); + "selection.rangeCount must equal 1 after " + method + "()"); assert_equals(selection.focusNode, point[0], - "focusNode must equal the node we collapse()d to"); + "focusNode must equal the node we " + method + "()d to"); assert_equals(selection.focusOffset, point[1], - "focusOffset must equal the offset we collapse()d to"); + "focusOffset must equal the offset we " + method + "()d to"); assert_equals(selection.focusNode, selection.anchorNode, - "focusNode and anchorNode must be equal after collapse()"); + "focusNode and anchorNode must be equal after " + method + "()"); assert_equals(selection.focusOffset, selection.anchorOffset, - "focusOffset and anchorOffset must be equal after collapse()"); + "focusOffset and anchorOffset must be equal after " + method + "()"); if (range) { assert_equals(addedRange.startContainer, range.startContainer, - "collapse() must not change the startContainer of a preexisting Range"); + method + "() must not change the startContainer of a preexisting Range"); assert_equals(addedRange.endContainer, range.endContainer, - "collapse() must not change the endContainer of a preexisting Range"); + method + "() must not change the endContainer of a preexisting Range"); assert_equals(addedRange.startOffset, range.startOffset, - "collapse() must not change the startOffset of a preexisting Range"); + method + "() must not change the startOffset of a preexisting Range"); assert_equals(addedRange.endOffset, range.endOffset, - "collapse() must not change the endOffset of a preexisting Range"); + method + "() must not change the endOffset of a preexisting Range"); } } @@ -91,7 +91,10 @@ function testCollapseSubSet(startIndex, optionalEndIndex) { } }, "Set up range " + i + " " + testRanges[i]); for (var j = 0; j < testPoints.length; j++) { - tests.push(["Range " + i + " " + testRanges[i] + ", point " + j + " " + testPoints[j], range, testPointsCached[j]]); + tests.push(["collapse() on " + testRanges[i] + " to " + testPoints[j], + range, testPointsCached[j], "collapse"]); + tests.push(["setPosition() on " + testRanges[i] + " to " + testPoints[j], + range, testPointsCached[j], "setPosition"]); } } diff --git a/testing/web-platform/tests/selection/removeAllRanges.html b/testing/web-platform/tests/selection/removeAllRanges.html index cc6b69256084..286876f8bda1 100644 --- a/testing/web-platform/tests/selection/removeAllRanges.html +++ b/testing/web-platform/tests/selection/removeAllRanges.html @@ -1,5 +1,5 @@ -Selection.removeAllRanges() tests +Selection.removeAllRanges()/empty() tests
@@ -12,33 +12,38 @@ testRanges.unshift("[]"); var range = rangeFromEndpoints([paras[0].firstChild, 0, paras[0].firstChild, 1]); -for (var i = 0; i < testRanges.length; i++) { +function testRange(rangeDesc, method) { test(function() { - setSelectionForwards(eval(testRanges[i])); - selection.removeAllRanges(); + setSelectionForwards(eval(rangeDesc)); + selection[method](); assert_equals(selection.rangeCount, 0, - "After removeAllRanges(), rangeCount must be 0"); + "After " + method + "(), rangeCount must be 0"); // Test that it's forwards selection.addRange(range); assert_equals(selection.anchorOffset, selection.getRangeAt(0).startOffset, - "After removeAllRanges(), addRange() must be forwards, so anchorOffset must equal startOffset rather than endOffset"); + "After " + method + "(), addRange() must be forwards, so anchorOffset must equal startOffset rather than endOffset"); assert_equals(selection.focusOffset, selection.getRangeAt(0).endOffset, - "After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset"); - }, "Range " + i + " " + testRanges[i] + " forwards"); + "After " + method + "(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset"); + }, method + " on " + rangeDesc + " forwards"); // Copy-pasted from above test(function() { - setSelectionBackwards(eval(testRanges[i])); - selection.removeAllRanges(); + setSelectionBackwards(eval(rangeDesc)); + selection[method](); assert_equals(selection.rangeCount, 0, - "After removeAllRanges(), rangeCount must be 0"); + "After " + method + "(), rangeCount must be 0"); // Test that it's forwards selection.addRange(range); assert_equals(selection.anchorOffset, selection.getRangeAt(0).startOffset, - "After removeAllRanges(), addRange() must be forwards, so anchorOffset must equal startOffset rather than endOffset"); + "After " + method + "(), addRange() must be forwards, so anchorOffset must equal startOffset rather than endOffset"); assert_equals(selection.focusOffset, selection.getRangeAt(0).endOffset, - "After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset"); - }, "Range " + i + " " + testRanges[i] + " backwards"); + "After " + method + "(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset"); + }, method + " on " + rangeDesc + " backwards"); +} + +for (var i = 0; i < testRanges.length; i++) { + testRange(testRanges[i], "removeAllRanges"); + testRange(testRanges[i], "empty"); } testDiv.style.display = "none"; diff --git a/testing/web-platform/tests/selection/type.html b/testing/web-platform/tests/selection/type.html new file mode 100644 index 000000000000..7be8ba61bc20 --- /dev/null +++ b/testing/web-platform/tests/selection/type.html @@ -0,0 +1,31 @@ + +Selection.type tests +
+ + + + diff --git a/testing/web-platform/tests/selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.html b/testing/web-platform/tests/selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.html deleted file mode 100644 index 95237a6fd975..000000000000 --- a/testing/web-platform/tests/selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.html +++ /dev/null @@ -1,89 +0,0 @@ - - -Selectors-API Level 2 Test Suite: HTML with Selectors Level 3 - - - - - - - - -
This test requires JavaScript.
- - diff --git a/testing/web-platform/tests/selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.js b/testing/web-platform/tests/selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.js deleted file mode 100644 index 5fd5d6941ac1..000000000000 --- a/testing/web-platform/tests/selectors-api/tests/submissions/Opera/ParentNode-query-queryAll.js +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Check that the query and queryAll methods exist on the given Node - */ -function interfaceCheckQuery(type, obj) { - test(function() { - var q = typeof obj.query === "function"; - assert_true(q, type + " supports query."); - }, type + " supports query") - - test(function() { - var qa = typeof obj.queryAll === "function"; - assert_true( qa, type + " supports queryAll."); - }, type + " supports queryAll") -} - -/* - * Verify that the NodeList returned by queryAll is static and and that a new list is created after - * each call. A static list should not be affected by subsequent changes to the DOM. - */ -function verifyStaticList(type, doc, root) { - var pre, post, preLength; - - test(function() { - pre = root.queryAll("div"); - preLength = pre.length; - - var div = doc.createElement("div"); - (root.body || root).appendChild(div); - - assert_equals(pre.length, preLength, "The length of the NodeList should not change.") - }, type + ": static NodeList") - - test(function() { - post = root.queryAll("div"), - assert_equals(post.length, preLength + 1, "The length of the new NodeList should be 1 more than the previous list.") - }, type + ": new NodeList") -} - -/* - * Verify handling of special values for the selector parameter, including stringification of - * null and undefined, and the handling of the empty string. - */ -function runSpecialSelectorTests(type, root) { - test(function() { // 1 - assert_equals(root.queryAll(null).length, 1, "This should query one element with the tag name 'NULL'."); - }, type + ".queryAll null") - - test(function() { // 2 - assert_equals(root.queryAll(undefined).length, 1, "This should query one elements with the tag name 'UNDEFINED'."); - }, type + ".queryAll undefined") - - test(function() { // 3 - assert_throws(TypeError(), function() { - root.queryAll(); - }, "This should throw a TypeError.") - }, type + ".queryAll no parameter") - - test(function() { // 4 - var elm = root.query(null) - assert_not_equals(elm, null, "This should query an element."); - assert_equals(elm.tagName.toUpperCase(), "NULL", "The tag name should be 'NULL'.") - }, type + ".query null") - - test(function() { // 5 - var elm = root.query(undefined) - assert_not_equals(elm, undefined, "This should query an element."); - assert_equals(elm.tagName.toUpperCase(), "UNDEFINED", "The tag name should be 'UNDEFINED'.") - }, type + ".query undefined") - - test(function() { // 6 - assert_throws(TypeError(), function() { - root.query(); - }, "This should throw a TypeError.") - }, type + ".query no parameter.") - - test(function() { // 7 - result = root.queryAll("*"); - var i = 0; - traverse(root, function(elem) { - if (elem !== root) { - assert_equals(elem, result[i++], "The result in index " + i + " should be in tree order.") - } - }) - }, type + ".queryAll tree order"); -} - -/* - * Execute queries with the specified valid selectors for both query() and queryAll() - * Only run these tests when results are expected. Don't run for syntax error tests. - * - * context.queryAll(selector, refNodes) - * context.queryAll(selector) // Only if refNodes is not specified - * root.queryAll(selector, context) // Only if refNodes is not specified - * root.queryAll(selector, refNodes) // Only if context is not specified - * root.queryAll(selector) // Only if neither context nor refNodes is specified - * - * Equivalent tests will be run for .query() as well. - */ -function runValidSelectorTest(type, root, selectors, docType) { - var nodeType = getNodeType(root); - - for (var i = 0; i < selectors.length; i++) { - var s = selectors[i]; - var n = s["name"]; - var q = s["selector"]; - var e = s["expect"]; - - var ctx = s["ctx"]; - var ref = s["ref"]; - - if (!s["exclude"] || (s["exclude"].indexOf(nodeType) === -1 && s["exclude"].indexOf(docType) === -1)) { - var foundall, found, context, refNodes, refArray; - - if (s["testType"] & TEST_FIND) { - - - /* - * If ctx and ref are specified: - * context.queryAll(selector, refNodes) - * context.query(selector, refNodes) - */ - if (ctx && ref) { - context = root.querySelector(ctx); - refNodes = root.querySelectorAll(ref); - refArray = Array.prototype.slice.call(refNodes, 0); - - test(function() { - foundall = context.queryAll(q, refNodes); - verifyNodeList(foundall, expect); - }, type + " [Context Element].queryAll: " + n + " (with refNodes NodeList): " + q); - - test(function() { - foundall = context.queryAll(q, refArray); - verifyNodeList(foundall, expect); - }, type + " [Context Element].queryAll: " + n + " (with refNodes Array): " + q); - - test(function() { - found = context.query(q, refNodes); - verifyElement(found, foundall, expect) - }, type + " [Context Element].query: " + n + " (with refNodes NodeList): " + q); - - test(function() { - found = context.query(q, refArray); - verifyElement(found, foundall, expect) - }, type + " [Context Element].query: " + n + " (with refNodes Array): " + q); - } - - - /* - * If ctx is specified, ref is not: - * context.queryAll(selector) - * context.query(selector) - * root.queryAll(selector, context) - * root.query(selector, context) - */ - if (ctx && !ref) { - context = root.querySelector(ctx); - - test(function() { - foundall = context.queryAll(q); - verifyNodeList(foundall, expect); - }, type + " [Context Element].queryAll: " + n + " (with no refNodes): " + q); - - test(function() { - found = context.query(q); - verifyElement(found, foundall, expect) - }, type + " [Context Element].query: " + n + " (with no refNodes): " + q); - - test(function() { - foundall = root.queryAll(q, context); - verifyNodeList(foundall, expect); - }, type + " [Root Node].queryAll: " + n + " (with refNode Element): " + q); - - test(function() { - foundall = root.query(q, context); - verifyElement(found, foundall, expect); - }, type + " [Root Node].query: " + n + " (with refNode Element): " + q); - } - - /* - * If ref is specified, ctx is not: - * root.queryAll(selector, refNodes) - * root.query(selector, refNodes) - */ - if (!ctx && ref) { - refNodes = root.querySelectorAll(ref); - refArray = Array.prototype.slice.call(refNodes, 0); - - test(function() { - foundall = root.queryAll(q, refNodes); - verifyNodeList(foundall, expect); - }, type + " [Root Node].queryAll: " + n + " (with refNodes NodeList): " + q); - - test(function() { - foundall = root.queryAll(q, refArray); - verifyNodeList(foundall, expect); - }, type + " [Root Node].queryAll: " + n + " (with refNodes Array): " + q); - - test(function() { - found = root.query(q, refNodes); - verifyElement(found, foundall, expect); - }, type + " [Root Node].query: " + n + " (with refNodes NodeList): " + q); - - test(function() { - found = root.query(q, refArray); - verifyElement(found, foundall, expect); - }, type + " [Root Node].query: " + n + " (with refNodes Array): " + q); - } - - /* - * If neither ctx nor ref is specified: - * root.queryAll(selector) - * root.query(selector) - */ - if (!ctx && !ref) { - test(function() { - foundall = root.queryAll(q); - verifyNodeList(foundall, expect); - }, type + ".queryAll: " + n + " (with no refNodes): " + q); - - test(function() { - found = root.query(q); - verifyElement(found, foundall, expect); - }, type + ".query: " + n + " (with no refNodes): " + q); - } - } - } - } -} - -/* - * Execute queries with the specified invalid selectors for both query() and queryAll() - * Only run these tests when errors are expected. Don't run for valid selector tests. - */ -function runInvalidSelectorTestQuery(type, root, selectors) { - for (var i = 0; i < selectors.length; i++) { - var s = selectors[i]; - var n = s["name"]; - var q = s["selector"]; - - test(function() { - assert_throws("SyntaxError", function() { - root.query(q) - }) - }, type + ".query: " + n + ": " + q); - - test(function() { - assert_throws("SyntaxError", function() { - root.queryAll(q) - }) - }, type + ".queryAll: " + n + ": " + q); - } -} - -function verifyNodeList(resultAll, expect) { - assert_not_equals(resultAll, null, "The method should not return null."); - assert_equals(resultAll.length, e.length, "The method should return the expected number of matches."); - - for (var i = 0; i < e.length; i++) { - assert_not_equals(resultAll[i], null, "The item in index " + i + " should not be null.") - assert_equals(resultAll[i].getAttribute("id"), e[i], "The item in index " + i + " should have the expected ID."); - assert_false(resultAll[i].hasAttribute("data-clone"), "This should not be a cloned element."); - } -} - -function verifyElement(result, resultAll, expect) { - if (expect.length > 0) { - assert_not_equals(result, null, "The method should return a match.") - assert_equals(found.getAttribute("id"), e[0], "The method should return the first match."); - assert_equals(result, resultAll[0], "The result should match the first item from querySelectorAll."); - assert_false(found.hasAttribute("data-clone"), "This should not be annotated as a cloned element."); - } else { - assert_equals(result, null, "The method should not match anything."); - } -} diff --git a/testing/web-platform/tests/selectors/attribute-selectors/attribute-case/syntax.html b/testing/web-platform/tests/selectors/attribute-selectors/attribute-case/syntax.html index 9d895b8ef2d2..baa1244c7061 100644 --- a/testing/web-platform/tests/selectors/attribute-selectors/attribute-case/syntax.html +++ b/testing/web-platform/tests/selectors/attribute-selectors/attribute-case/syntax.html @@ -106,9 +106,7 @@ onload = function() { assert_equals(global.getComputedStyle(elm).visibility, 'visible', 'invalid selector matched'); }, s + ' in ' + global.mode); test(function() { - // Should be TypeError but this is not widely implemented yet - // and this isn't intended to be a querySelector API conformance test. - assert_throws(null, function() { + assert_throws("SyntaxError", function() { global.document.querySelector(s); }, 'invalid selector'); }, s + ' with querySelector in ' + global.mode); diff --git a/testing/web-platform/tests/server-timing/resources/blue.png b/testing/web-platform/tests/server-timing/resources/blue.png new file mode 100644 index 000000000000..4498dd258a20 Binary files /dev/null and b/testing/web-platform/tests/server-timing/resources/blue.png differ diff --git a/testing/web-platform/tests/server-timing/resources/blue.png.sub.headers b/testing/web-platform/tests/server-timing/resources/blue.png.sub.headers new file mode 100644 index 000000000000..5f3e54310d6a --- /dev/null +++ b/testing/web-platform/tests/server-timing/resources/blue.png.sub.headers @@ -0,0 +1 @@ +Server-Timing: metric2=3.4;blue.png diff --git a/testing/web-platform/tests/server-timing/resources/green.png b/testing/web-platform/tests/server-timing/resources/green.png new file mode 100644 index 000000000000..28a1faab3779 Binary files /dev/null and b/testing/web-platform/tests/server-timing/resources/green.png differ diff --git a/testing/web-platform/tests/server-timing/resources/green.png.sub.headers b/testing/web-platform/tests/server-timing/resources/green.png.sub.headers new file mode 100644 index 000000000000..1c6d74512a48 --- /dev/null +++ b/testing/web-platform/tests/server-timing/resources/green.png.sub.headers @@ -0,0 +1 @@ +Server-Timing: metric3=5.6;green.png diff --git a/testing/web-platform/tests/server-timing/test_server_timing.html b/testing/web-platform/tests/server-timing/test_server_timing.html new file mode 100644 index 000000000000..2a6ffa264999 --- /dev/null +++ b/testing/web-platform/tests/server-timing/test_server_timing.html @@ -0,0 +1,50 @@ + + + + + + + + + + diff --git a/testing/web-platform/tests/server-timing/test_server_timing.html.sub.headers b/testing/web-platform/tests/server-timing/test_server_timing.html.sub.headers new file mode 100644 index 000000000000..ddff591c1e4a --- /dev/null +++ b/testing/web-platform/tests/server-timing/test_server_timing.html.sub.headers @@ -0,0 +1 @@ +Server-Timing: metric1=1.2;document diff --git a/testing/web-platform/tests/service-workers/cache-storage/resources/test-helpers.js b/testing/web-platform/tests/service-workers/cache-storage/resources/test-helpers.js index d3b810942197..050ac0b54245 100644 --- a/testing/web-platform/tests/service-workers/cache-storage/resources/test-helpers.js +++ b/testing/web-platform/tests/service-workers/cache-storage/resources/test-helpers.js @@ -141,23 +141,26 @@ var vary_entries = [ // Run |test_function| with a Cache object and a map of entries. Prior to the // call, the Cache is populated by cache entries from |entries|. The latter is // expected to be an Object mapping arbitrary keys to objects of the form -// {request: , response: }. There's no -// guarantee on the order in which entries will be added to the cache. +// {request: , response: }. Entries are +// serially added to the cache in the order specified. // // |test_function| should return a Promise that can be used with promise_test. function prepopulated_cache_test(entries, test_function, description) { cache_test(function(cache) { var p = Promise.resolve(); var hash = {}; - return Promise.all(entries.map(function(entry) { + entries.forEach(function(entry) { hash[entry.name] = entry; - return cache.put(entry.request.clone(), - entry.response.clone()) - .catch(function(e) { - assert_unreached( - 'Test setup failed for entry ' + entry.name + ': ' + e); - }); - })) + p = p.then(function() { + return cache.put(entry.request.clone(), entry.response.clone()) + .catch(function(e) { + assert_unreached( + 'Test setup failed for entry ' + entry.name + ': ' + e + ); + }); + }); + }); + return p .then(function() { assert_equals(Object.keys(hash).length, entries.length); }) @@ -236,6 +239,30 @@ function assert_response_in_array(actual, expected_array, description) { }), description); } +// Helper for testing with Request objects. Compares simple +// attributes defined on the interfaces, as well as the headers. +function assert_request_equals(actual, expected, description) { + assert_class_string(actual, "Request", description); + ["url"].forEach(function(attribute) { + assert_equals(actual[attribute], expected[attribute], + description + " Attributes differ: " + attribute + "."); + }); + assert_header_equals(actual.headers, expected.headers, description); +} + +// Asserts that two arrays |actual| and |expected| contain the same +// set of Requests as determined by assert_request_equals(). The +// corresponding elements must occupy corresponding indices in their +// respective arrays. +function assert_request_array_equals(actual, expected, description) { + assert_true(Array.isArray(actual), description); + assert_equals(actual.length, expected.length, description); + actual.forEach(function(value, index) { + assert_request_equals(value, expected[index], + description + " : object[" + index + "]"); + }); +} + // Deletes all caches, returning a promise indicating success. function delete_all_caches() { return self.caches.keys() diff --git a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-add.js b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-add.js index 237ba473504c..c03faeb0e837 100644 --- a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-add.js +++ b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-add.js @@ -84,7 +84,7 @@ cache_test(function(cache) { }, 'Cache.add with request with null body (not consumed)'); cache_test(function(cache, test) { - return assert_promise_rejects( + return promise_rejects( test, new TypeError(), cache.add('../resources/fetch-status.py?status=206'), @@ -98,6 +98,7 @@ cache_test(function(cache, test) { return new Request(url); }); return promise_rejects( + test, new TypeError(), cache.addAll(requests), 'Cache.addAll should reject with TypeError if any request fails'); @@ -116,7 +117,7 @@ cache_test(function(cache, test) { return promise_rejects( test, new TypeError(), - cache.add('../resources/fetch-status.php?status=500'), + cache.add('../resources/fetch-status.py?status=500'), 'Cache.add should reject if response is !ok'); }, 'Cache.add with request that results in a status of 500'); diff --git a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-delete.js b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-delete.js index bf7841a7e5f6..3cf9aeb4c23a 100644 --- a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-delete.js +++ b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-delete.js @@ -71,9 +71,39 @@ cache_test(function(cache) { .then(function(result) { assert_response_equals(result, response, 'Cache.delete should leave non-matching response in the cache.'); + return cache.delete(new Request(test_url, {method: 'HEAD'}), + {ignoreMethod: true}); + }) + .then(function(result) { + assert_true(result, + 'Cache.delete should match a non-GET request ' + + ' if ignoreMethod is true.'); }); }, 'Cache.delete called with a HEAD request'); +cache_test(function(cache) { + var vary_request = new Request('http://example.com/c', + {headers: {'Cookies': 'is-for-cookie'}}); + var vary_response = new Response('', {headers: {'Vary': 'Cookies'}}); + var mismatched_vary_request = new Request('http://example.com/c'); + + return cache.put(vary_request.clone(), vary_response.clone()) + .then(function() { + return cache.delete(mismatched_vary_request.clone()); + }) + .then(function(result) { + assert_false(result, + 'Cache.delete should not delete if vary does not ' + + 'match unless ignoreVary is true'); + return cache.delete(mismatched_vary_request.clone(), + {ignoreVary: true}); + }) + .then(function(result) { + assert_true(result, + 'Cache.delete should ignore vary if ignoreVary is true'); + }); + }, 'Cache.delete supports ignoreVary'); + cache_test(function(cache) { return cache.delete(test_url) .then(function(result) { @@ -83,33 +113,52 @@ cache_test(function(cache) { }); }, 'Cache.delete with a non-existent entry'); -var cache_entries = { - a: { - request: new Request('http://example.com/abc'), - response: new Response('') +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.matchAll(entries.a_with_query.request, + { ignoreSearch: true }) + .then(function(result) { + assert_response_array_equals( + result, + [ + entries.a.response, + entries.a_with_query.response + ]); + return cache.delete(entries.a_with_query.request, + { ignoreSearch: true }); + }) + .then(function(result) { + return cache.matchAll(entries.a_with_query.request, + { ignoreSearch: true }); + }) + .then(function(result) { + assert_response_array_equals(result, []); + }); }, + 'Cache.delete with ignoreSearch option (request with search parameters)'); - b: { - request: new Request('http://example.com/b'), - response: new Response('') +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.matchAll(entries.a_with_query.request, + { ignoreSearch: true }) + .then(function(result) { + assert_response_array_equals( + result, + [ + entries.a.response, + entries.a_with_query.response + ]); + // cache.delete()'s behavior should be the same if ignoreSearch is + // not provided or if ignoreSearch is false. + return cache.delete(entries.a_with_query.request, + { ignoreSearch: false }); + }) + .then(function(result) { + return cache.matchAll(entries.a_with_query.request, + { ignoreSearch: true }); + }) + .then(function(result) { + assert_response_array_equals(result, [ entries.a.response ]); + }); }, - - a_with_query: { - request: new Request('http://example.com/abc?q=r'), - response: new Response('') - } -}; - -function prepopulated_cache_test(test_function, description) { - cache_test(function(cache) { - return Promise.all(Object.keys(cache_entries).map(function(k) { - return cache.put(cache_entries[k].request.clone(), - cache_entries[k].response.clone()); - })) - .then(function() { - return test_function(cache); - }); - }, description); -} + 'Cache.delete with ignoreSearch option (when it is specified as false)'); done(); diff --git a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-keys.js b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-keys.js new file mode 100644 index 000000000000..96bd43b673a4 --- /dev/null +++ b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-keys.js @@ -0,0 +1,192 @@ +if (self.importScripts) { + importScripts('/resources/testharness.js'); + importScripts('../resources/test-helpers.js'); +} + +cache_test(cache => { + return cache.keys() + .then(requests => { + assert_equals( + requests.length, 0, + 'Cache.keys should resolve to an empty array for an empty cache'); + }); + }, 'Cache.keys() called on an empty cache'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys('not-present-in-the-cache') + .then(function(result) { + assert_request_array_equals( + result, [], + 'Cache.keys should resolve with an empty array on failure.'); + }); + }, 'Cache.keys with no matching entries'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(entries.a.request.url) + .then(function(result) { + assert_request_array_equals(result, [entries.a.request], + 'Cache.keys should match by URL.'); + }); + }, 'Cache.keys with URL'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(entries.a.request) + .then(function(result) { + assert_request_array_equals( + result, [entries.a.request], + 'Cache.keys should match by Request.'); + }); + }, 'Cache.keys with Request'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(new Request(entries.a.request.url)) + .then(function(result) { + assert_request_array_equals( + result, [entries.a.request], + 'Cache.keys should match by Request.'); + }); + }, 'Cache.keys with new Request'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(entries.a.request, {ignoreSearch: true}) + .then(function(result) { + assert_request_array_equals( + result, + [ + entries.a.request, + entries.a_with_query.request + ], + 'Cache.keys with ignoreSearch should ignore the ' + + 'search parameters of cached request.'); + }); + }, + 'Cache.keys with ignoreSearch option (request with no search ' + + 'parameters)'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(entries.a_with_query.request, {ignoreSearch: true}) + .then(function(result) { + assert_request_array_equals( + result, + [ + entries.a.request, + entries.a_with_query.request + ], + 'Cache.keys with ignoreSearch should ignore the ' + + 'search parameters of request.'); + }); + }, + 'Cache.keys with ignoreSearch option (request with search parameters)'); + +cache_test(function(cache) { + var request = new Request('http://example.com/'); + var head_request = new Request('http://example.com/', {method: 'HEAD'}); + var response = new Response('foo'); + return cache.put(request.clone(), response.clone()) + .then(function() { + return cache.keys(head_request.clone()); + }) + .then(function(result) { + assert_request_array_equals( + result, [], + 'Cache.keys should resolve with an empty array with a ' + + 'mismatched method.'); + return cache.keys(head_request.clone(), + {ignoreMethod: true}); + }) + .then(function(result) { + assert_request_array_equals( + result, + [ + request, + ], + 'Cache.keys with ignoreMethod should ignore the ' + + 'method of request.'); + }); + }, 'Cache.keys supports ignoreMethod'); + +cache_test(function(cache) { + var vary_request = new Request('http://example.com/c', + {headers: {'Cookies': 'is-for-cookie'}}); + var vary_response = new Response('', {headers: {'Vary': 'Cookies'}}); + var mismatched_vary_request = new Request('http://example.com/c'); + + return cache.put(vary_request.clone(), vary_response.clone()) + .then(function() { + return cache.keys(mismatched_vary_request.clone()); + }) + .then(function(result) { + assert_request_array_equals( + result, [], + 'Cache.keys should resolve with an empty array with a ' + + 'mismatched vary.'); + return cache.keys(mismatched_vary_request.clone(), + {ignoreVary: true}); + }) + .then(function(result) { + assert_request_array_equals( + result, + [ + vary_request, + ], + 'Cache.keys with ignoreVary should ignore the ' + + 'vary of request.'); + }); + }, 'Cache.keys supports ignoreVary'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(entries.cat.request.url + '#mouse') + .then(function(result) { + assert_request_array_equals( + result, + [ + entries.cat.request, + ], + 'Cache.keys should ignore URL fragment.'); + }); + }, 'Cache.keys with URL containing fragment'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys('http') + .then(function(result) { + assert_request_array_equals( + result, [], + 'Cache.keys should treat query as a URL and not ' + + 'just a string fragment.'); + }); + }, 'Cache.keys with string fragment "http" as query'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys() + .then(function(result) { + assert_request_array_equals( + result, + [ + entries.a.request, + entries.b.request, + entries.a_with_query.request, + entries.A.request, + entries.a_https.request, + entries.a_org.request, + entries.cat.request, + entries.catmandu.request, + entries.cat_num_lives.request, + entries.cat_in_the_hat.request, + entries.non_2xx_response.request, + entries.error_response.request + ], + 'Cache.keys without parameters should match all entries.'); + }); + }, 'Cache.keys without parameters'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(new Request(entries.cat.request.url, {method: 'HEAD'})) + .then(function(result) { + assert_request_array_equals( + result, [], + 'Cache.keys should not match HEAD request unless ignoreMethod ' + + 'option is set.'); + }); + }, 'Cache.keys with a HEAD Request'); + +done(); diff --git a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-match.js b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-match.js index 32c9ec92a698..3d00f0f04af3 100644 --- a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-match.js +++ b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-match.js @@ -27,6 +27,23 @@ prepopulated_cache_test(simple_entries, function(cache, entries) { }); }, 'Cache.match with Request'); +prepopulated_cache_test(simple_entries, function(cache, entries) { + var alt_response = new Response('', {status: 201}); + + return self.caches.open('second_matching_cache') + .then(function(cache) { + return cache.put(entries.a.request, alt_response.clone()); + }) + .then(function() { + return cache.match(entries.a.request); + }) + .then(function(result) { + assert_response_equals( + result, entries.a.response, + 'Cache.match should match the first cache.'); + }); + }, 'Cache.match with multiple cache hits'); + prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.match(new Request(entries.a.request.url)) .then(function(result) { @@ -76,6 +93,56 @@ prepopulated_cache_test(simple_entries, function(cache, entries) { }, 'Cache.match with ignoreSearch option (request with search parameter)'); +cache_test(function(cache) { + var request = new Request('http://example.com/'); + var head_request = new Request('http://example.com/', {method: 'HEAD'}); + var response = new Response('foo'); + return cache.put(request.clone(), response.clone()) + .then(function() { + return cache.match(head_request.clone()); + }) + .then(function(result) { + assert_equals( + result, undefined, + 'Cache.match should resolve as undefined with a ' + + 'mismatched method.'); + return cache.match(head_request.clone(), + {ignoreMethod: true}); + }) + .then(function(result) { + assert_response_equals( + result, response, + 'Cache.match with ignoreMethod should ignore the ' + + 'method of request.'); + }); + }, 'Cache.match supports ignoreMethod'); + +cache_test(function(cache) { + var vary_request = new Request('http://example.com/c', + {headers: {'Cookies': 'is-for-cookie'}}); + var vary_response = new Response('', {headers: {'Vary': 'Cookies'}}); + var mismatched_vary_request = new Request('http://example.com/c'); + + return cache.put(vary_request.clone(), vary_response.clone()) + .then(function() { + return cache.match(mismatched_vary_request.clone()); + }) + .then(function(result) { + assert_equals( + result, undefined, + 'Cache.match should resolve as undefined with a ' + + 'mismatched vary.'); + return cache.match(mismatched_vary_request.clone(), + {ignoreVary: true}); + }) + .then(function(result) { + assert_response_equals( + result, vary_response, + 'Cache.match with ignoreVary should ignore the ' + + 'vary of request.'); + }); + }, 'Cache.match supports ignoreVary'); + prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.match(entries.cat.request.url + '#mouse') .then(function(result) { @@ -166,6 +233,36 @@ cache_test(function(cache) { }); }, 'Cache.match invoked multiple times for the same Request/Response'); +cache_test(function(cache) { + var request_url = new URL('../resources/simple.txt', location.href).href; + return fetch(request_url) + .then(function(fetch_result) { + return cache.put(new Request(request_url), fetch_result); + }) + .then(function() { + return cache.match(request_url); + }) + .then(function(result) { + return result.blob(); + }) + .then(function(blob) { + var sliced = blob.slice(2,8); + + return new Promise(function (resolve, reject) { + var reader = new FileReader(); + reader.onloadend = function(event) { + resolve(event.target.result); + }; + reader.readAsText(sliced); + }); + }) + .then(function(text) { + assert_equals(text, 'simple', + 'A Response blob returned by Cache.match should be ' + + 'sliceable.' ); + }); + }, 'Cache.match blob should be sliceable'); + prepopulated_cache_test(simple_entries, function(cache, entries) { var request = new Request(entries.a.request.clone(), {method: 'POST'}); return cache.match(request) @@ -218,7 +315,7 @@ cache_test(function(cache) { }) .then(function(text) { assert_equals(text, data.toString(), 'cloned body text can be read correctly'); - }) + }); }, 'Cache produces large Responses that can be cloned and read correctly.'); done(); diff --git a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-matchAll.js b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-matchAll.js index feace5a9899d..b7c7bd63785c 100644 --- a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-matchAll.js +++ b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-matchAll.js @@ -6,7 +6,7 @@ if (self.importScripts) { prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.matchAll('not-present-in-the-cache') .then(function(result) { - assert_response_array_equivalent( + assert_response_array_equals( result, [], 'Cache.matchAll should resolve with an empty array on failure.'); }); @@ -52,7 +52,7 @@ prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.matchAll(entries.a.request, {ignoreSearch: true}) .then(function(result) { - assert_response_array_equivalent( + assert_response_array_equals( result, [ entries.a.response, @@ -69,7 +69,7 @@ prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.matchAll(entries.a_with_query.request, {ignoreSearch: true}) .then(function(result) { - assert_response_array_equivalent( + assert_response_array_equals( result, [ entries.a.response, @@ -79,12 +79,62 @@ prepopulated_cache_test(simple_entries, function(cache, entries) { 'search parameters of request.'); }); }, - 'Cache.matchAll with ignoreSearch option (request with search parameter)'); + 'Cache.matchAll with ignoreSearch option (request with search parameters)'); + +cache_test(function(cache) { + var request = new Request('http://example.com/'); + var head_request = new Request('http://example.com/', {method: 'HEAD'}); + var response = new Response('foo'); + return cache.put(request.clone(), response.clone()) + .then(function() { + return cache.matchAll(head_request.clone()); + }) + .then(function(result) { + assert_response_array_equals( + result, [], + 'Cache.matchAll should resolve with empty array for a ' + + 'mismatched method.'); + return cache.matchAll(head_request.clone(), + {ignoreMethod: true}); + }) + .then(function(result) { + assert_response_array_equals( + result, [response], + 'Cache.matchAll with ignoreMethod should ignore the ' + + 'method of request.'); + }); + }, 'Cache.matchAll supports ignoreMethod'); + +cache_test(function(cache) { + var vary_request = new Request('http://example.com/c', + {headers: {'Cookies': 'is-for-cookie'}}); + var vary_response = new Response('', {headers: {'Vary': 'Cookies'}}); + var mismatched_vary_request = new Request('http://example.com/c'); + + return cache.put(vary_request.clone(), vary_response.clone()) + .then(function() { + return cache.matchAll(mismatched_vary_request.clone()); + }) + .then(function(result) { + assert_response_array_equals( + result, [], + 'Cache.matchAll should resolve as undefined with a ' + + 'mismatched vary.'); + return cache.matchAll(mismatched_vary_request.clone(), + {ignoreVary: true}); + }) + .then(function(result) { + assert_response_array_equals( + result, [vary_response], + 'Cache.matchAll with ignoreVary should ignore the ' + + 'vary of request.'); + }); + }, 'Cache.matchAll supports ignoreVary'); prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.matchAll(entries.cat.request.url + '#mouse') .then(function(result) { - assert_response_array_equivalent( + assert_response_array_equals( result, [ entries.cat.response, @@ -96,17 +146,40 @@ prepopulated_cache_test(simple_entries, function(cache, entries) { prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.matchAll('http') .then(function(result) { - assert_response_array_equivalent( + assert_response_array_equals( result, [], 'Cache.matchAll should treat query as a URL and not ' + 'just a string fragment.'); }); }, 'Cache.matchAll with string fragment "http" as query'); +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.matchAll() + .then(function(result) { + assert_response_array_equals( + result, + [ + entries.a.response, + entries.b.response, + entries.a_with_query.response, + entries.A.response, + entries.a_https.response, + entries.a_org.response, + entries.cat.response, + entries.catmandu.response, + entries.cat_num_lives.response, + entries.cat_in_the_hat.response, + entries.non_2xx_response.response, + entries.error_response.response + ], + 'Cache.matchAll without parameters should match all entries.'); + }); + }, 'Cache.matchAll without parameters'); + prepopulated_cache_test(vary_entries, function(cache, entries) { return cache.matchAll('http://example.com/c') .then(function(result) { - assert_response_array_equivalent( + assert_response_array_equals( result, [ entries.vary_cookie_absent.response @@ -122,7 +195,7 @@ prepopulated_cache_test(vary_entries, function(cache, entries) { {headers: {'Cookies': 'none-of-the-above'}})); }) .then(function(result) { - assert_response_array_equivalent( + assert_response_array_equals( result, [ ], @@ -137,7 +210,7 @@ prepopulated_cache_test(vary_entries, function(cache, entries) { {headers: {'Cookies': 'is-for-cookie'}})); }) .then(function(result) { - assert_response_array_equivalent( + assert_response_array_equals( result, [entries.vary_cookie_is_cookie.response], 'Cache.matchAll should match the entire header if a vary header ' + @@ -149,15 +222,16 @@ prepopulated_cache_test(vary_entries, function(cache, entries) { return cache.matchAll('http://example.com/c', {ignoreVary: true}) .then(function(result) { - assert_response_array_equivalent( + assert_response_array_equals( result, [ entries.vary_cookie_is_cookie.response, entries.vary_cookie_is_good.response, entries.vary_cookie_absent.response ], - 'Cache.matchAll should honor "ignoreVary" parameter.'); + 'Cache.matchAll should support multiple vary request/response ' + + 'pairs.'); }); - }, 'Cache.matchAll with "ignoreVary" parameter'); + }, 'Cache.matchAll with multiple vary pairs'); done(); diff --git a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-put.js b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-put.js index 9e9fd67a3fe9..467e0b38e9c3 100644 --- a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-put.js +++ b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-put.js @@ -102,18 +102,32 @@ cache_test(function(cache) { }); }, 'Cache.put with an empty response body'); -cache_test(function(cache) { +cache_test(function(cache, test) { var request = new Request(test_url); var response = new Response('', { status: 206, headers: [['Content-Type', 'text/plain']] }); - return assert_promise_rejects( - cache.put(request, response), + return promise_rejects( + test, new TypeError(), + cache.put(request, response), 'Cache.put should reject 206 Responses with a TypeError.'); - }, 'Cache.put with 206 response'); + }, 'Cache.put with synthetic 206 response'); + +cache_test(function(cache, test) { + var test_url = new URL('../resources/fetch-status.py?status=206', location.href).href; + var request = new Request(test_url); + var response; + return fetch(test_url) + .then(function(fetch_result) { + assert_equals(fetch_result.status, 206, + 'Test framework error: The status code should be 206.'); + response = fetch_result.clone(); + return promise_rejects(test, new TypeError, cache.put(request, fetch_result)); + }); + }, 'Cache.put with HTTP 206 response'); cache_test(function(cache) { var test_url = new URL('../resources/fetch-status.py?status=500', location.href).href; diff --git a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-storage-match.js b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-storage-match.js index 21517b1eccdd..354652048642 100644 --- a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-storage-match.js +++ b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-storage-match.js @@ -133,4 +133,110 @@ promise_test(function(test) { }); }, 'CacheStorageMatch with no caches available but name provided'); +cache_test(function(cache) { + var transaction = create_unique_transaction(); + + return self.caches.delete('') + .then(function() { + return self.caches.has(''); + }) + .then(function(has_cache) { + assert_false(has_cache, "The cache should not exist."); + return cache.put(transaction.request, transaction.response.clone()); + }) + .then(function() { + return self.caches.match(transaction.request, {cacheName: ''}); + }) + .then(function(response) { + assert_equals(response, undefined, + 'The response should not be found.'); + return self.caches.open(''); + }) + .then(function(cache) { + return cache.put(transaction.request, transaction.response); + }) + .then(function() { + return self.caches.match(transaction.request, {cacheName: ''}); + }) + .then(function(response) { + assert_response_equals(response, transaction.response, + 'The response should be matched.'); + return self.caches.delete(''); + }); +}, 'CacheStorageMatch with empty cache name provided'); + +cache_test(function(cache) { + var request = new Request('http://example.com/?foo'); + var no_query_request = new Request('http://example.com/'); + var response = new Response('foo'); + return cache.put(request.clone(), response.clone()) + .then(function() { + return self.caches.match(no_query_request.clone()); + }) + .then(function(result) { + assert_equals( + result, undefined, + 'CacheStorageMatch should resolve as undefined with a ' + + 'mismatched query.'); + return self.caches.match(no_query_request.clone(), + {ignoreSearch: true}); + }) + .then(function(result) { + assert_response_equals( + result, response, + 'CacheStorageMatch with ignoreSearch should ignore the ' + + 'query of the request.'); + }); + }, 'CacheStorageMatch supports ignoreSearch'); + +cache_test(function(cache) { + var request = new Request('http://example.com/'); + var head_request = new Request('http://example.com/', {method: 'HEAD'}); + var response = new Response('foo'); + return cache.put(request.clone(), response.clone()) + .then(function() { + return self.caches.match(head_request.clone()); + }) + .then(function(result) { + assert_equals( + result, undefined, + 'CacheStorageMatch should resolve as undefined with a ' + + 'mismatched method.'); + return self.caches.match(head_request.clone(), + {ignoreMethod: true}); + }) + .then(function(result) { + assert_response_equals( + result, response, + 'CacheStorageMatch with ignoreMethod should ignore the ' + + 'method of request.'); + }); + }, 'Cache.match supports ignoreMethod'); + +cache_test(function(cache) { + var vary_request = new Request('http://example.com/c', + {headers: {'Cookies': 'is-for-cookie'}}); + var vary_response = new Response('', {headers: {'Vary': 'Cookies'}}); + var mismatched_vary_request = new Request('http://example.com/c'); + + return cache.put(vary_request.clone(), vary_response.clone()) + .then(function() { + return self.caches.match(mismatched_vary_request.clone()); + }) + .then(function(result) { + assert_equals( + result, undefined, + 'CacheStorageMatch should resolve as undefined with a ' + + ' mismatched vary.'); + return self.caches.match(mismatched_vary_request.clone(), + {ignoreVary: true}); + }) + .then(function(result) { + assert_response_equals( + result, vary_response, + 'CacheStorageMatch with ignoreVary should ignore the ' + + 'vary of request.'); + }); + }, 'CacheStorageMatch supports ignoreVary'); + done(); diff --git a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-storage.js b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-storage.js index 521d3bbc25df..2011afd69581 100644 --- a/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-storage.js +++ b/testing/web-platform/tests/service-workers/cache-storage/script-tests/cache-storage.js @@ -15,6 +15,40 @@ promise_test(function(t) { }); }, 'CacheStorage.open'); +promise_test(function(t) { + var cache_name = 'cache-storage/bar'; + var first_cache = null; + var second_cache = null; + return self.caches.open(cache_name) + .then(function(cache) { + first_cache = cache; + return self.caches.delete(cache_name); + }) + .then(function() { + return first_cache.add('../resources/simple.txt'); + }) + .then(function() { + return self.caches.keys(); + }) + .then(function(cache_names) { + assert_equals(cache_names.indexOf(cache_name), -1); + return self.caches.open(cache_name); + }) + .then(function(cache) { + second_cache = cache; + return second_cache.keys(); + }) + .then(function(keys) { + assert_equals(keys.length, 0); + return first_cache.keys(); + }) + .then(function(keys) { + assert_equals(keys.length, 1); + // Clean up + return self.caches.delete(cache_name); + }); + }, 'CacheStorage.delete dooms, but does not delete immediately'); + promise_test(function(t) { // Note that this test may collide with other tests running in the same // origin that also uses an empty cache name. diff --git a/testing/web-platform/tests/service-workers/cache-storage/serviceworker/cache-keys.https.html b/testing/web-platform/tests/service-workers/cache-storage/serviceworker/cache-keys.https.html new file mode 100644 index 000000000000..736f74d98960 --- /dev/null +++ b/testing/web-platform/tests/service-workers/cache-storage/serviceworker/cache-keys.https.html @@ -0,0 +1,10 @@ + +Cache.keys + + + + + + diff --git a/testing/web-platform/tests/service-workers/cache-storage/window/cache-keys.https.html b/testing/web-platform/tests/service-workers/cache-storage/window/cache-keys.https.html new file mode 100644 index 000000000000..8398c33e146c --- /dev/null +++ b/testing/web-platform/tests/service-workers/cache-storage/window/cache-keys.https.html @@ -0,0 +1,8 @@ + +Cache Storage: Cache.keys + + + + + + diff --git a/testing/web-platform/tests/service-workers/cache-storage/worker/cache-keys.https.html b/testing/web-platform/tests/service-workers/cache-storage/worker/cache-keys.https.html new file mode 100644 index 000000000000..6bafe21d30bb --- /dev/null +++ b/testing/web-platform/tests/service-workers/cache-storage/worker/cache-keys.https.html @@ -0,0 +1,9 @@ + +Cache.keys + + + + + diff --git a/testing/web-platform/tests/service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js b/testing/web-platform/tests/service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js new file mode 100644 index 000000000000..f6838ffb3947 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js @@ -0,0 +1,12 @@ +var source; + +self.addEventListener('message', function(e) { + source = e.source; + throw 'testError'; +}); + +self.addEventListener('error', function(e) { + source.postMessage({ + error: e.error, filename: e.filename, message: e.message, lineno: e.lineno, + colno: e.colno}); +}); diff --git a/testing/web-platform/tests/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html b/testing/web-platform/tests/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html new file mode 100644 index 000000000000..988f5466b9e1 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html @@ -0,0 +1,31 @@ + +ServiceWorkerGlobalScope: Error event error message + + + + diff --git a/testing/web-platform/tests/service-workers/service-worker/client-id.https.html b/testing/web-platform/tests/service-workers/service-worker/client-id.https.html new file mode 100644 index 000000000000..a53c10c96919 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/client-id.https.html @@ -0,0 +1,55 @@ + +Service Worker: Client.id + + + + diff --git a/testing/web-platform/tests/service-workers/service-worker/clients-get-client-types.https.html b/testing/web-platform/tests/service-workers/service-worker/clients-get-client-types.https.html new file mode 100644 index 000000000000..0005f98c4bb4 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/clients-get-client-types.https.html @@ -0,0 +1,69 @@ + +Service Worker: Clients.get with window and worker clients + + + + diff --git a/testing/web-platform/tests/service-workers/service-worker/clients-get-cross-origin.https.html b/testing/web-platform/tests/service-workers/service-worker/clients-get-cross-origin.https.html index d5622054de82..1e4acfb286c6 100644 --- a/testing/web-platform/tests/service-workers/service-worker/clients-get-cross-origin.https.html +++ b/testing/web-platform/tests/service-workers/service-worker/clients-get-cross-origin.https.html @@ -7,36 +7,63 @@ diff --git a/testing/web-platform/tests/service-workers/service-worker/clients-get.https.html b/testing/web-platform/tests/service-workers/service-worker/clients-get.https.html index 85c70a2f1dc8..45da2b35eff0 100644 --- a/testing/web-platform/tests/service-workers/service-worker/clients-get.https.html +++ b/testing/web-platform/tests/service-workers/service-worker/clients-get.https.html @@ -2,69 +2,67 @@ Service Worker: Clients.get - diff --git a/testing/web-platform/tests/service-workers/service-worker/clients-matchall-client-types.https.html b/testing/web-platform/tests/service-workers/service-worker/clients-matchall-client-types.https.html index 3be0fe2ac723..420e4e0d5e3b 100644 --- a/testing/web-platform/tests/service-workers/service-worker/clients-matchall-client-types.https.html +++ b/testing/web-platform/tests/service-workers/service-worker/clients-matchall-client-types.https.html @@ -8,36 +8,36 @@ var scope = 'resources/clients-matchall-client-types'; var iframe_url = scope + '-iframe.html'; var shared_worker_url = scope + '-shared-worker.js'; -/* visibilityState, focused, url, frameType */ +/* visibilityState, focused, url, type, frameType */ var expected_only_window = [ ['visible', true, new URL(iframe_url, location).href, 'window', 'nested'] ]; var expected_only_shared_worker = [ - [,,new URL(shared_worker_url, location).href, 'sharedworker', 'none'] + [undefined, undefined, new URL(shared_worker_url, location).href, 'sharedworker', 'none'] ]; var expected_window_and_shared_worker = [ - ['visible', true, new URL(iframe_url, location).href, 'window', 'nested'], - [,,new URL(shared_worker_url, location).href, 'sharedworker', 'none'] + expected_only_window[0], expected_only_shared_worker[0] ]; function test_matchall(frame, expected, query_options) { // Make sure the frame gets focus. frame.focus(); - expected.sort(function(a, b) { return a[2] > b[2] ? 1 : -1; }); return new Promise(function(resolve, reject) { var channel = new MessageChannel(); - channel.port1.onmessage = function(e) { - if (typeof e.data === 'string') { - return reject(e.data); - } - assert_equals(e.data.length, expected.length); - for (var i = 0; i < e.data.length; i++) - assert_array_equals(e.data[i], expected[i]); - resolve(); - }; + channel.port1.onmessage = function(e) { resolve(e.data); }; frame.contentWindow.navigator.serviceWorker.controller.postMessage( {port:channel.port2, options:query_options}, [channel.port2]); + }).then(function(data) { + if (typeof data === 'string') { + throw new Error(data); + } + + assert_equals(data.length, expected.length, 'result count'); + + for (var i = 0; i < data.length; ++i) { + assert_array_equals(data[i], expected[i]); + } }); } diff --git a/testing/web-platform/tests/service-workers/service-worker/clients-matchall-on-evaluation.https.html b/testing/web-platform/tests/service-workers/service-worker/clients-matchall-on-evaluation.https.html new file mode 100644 index 000000000000..8705f85b5684 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/clients-matchall-on-evaluation.https.html @@ -0,0 +1,24 @@ + +Service Worker: Clients.matchAll on script evaluation + + + + diff --git a/testing/web-platform/tests/service-workers/service-worker/extendable-event-waituntil.https.html b/testing/web-platform/tests/service-workers/service-worker/extendable-event-waituntil.https.html index b2029ae42614..8e790d0ef5ad 100644 --- a/testing/web-platform/tests/service-workers/service-worker/extendable-event-waituntil.https.html +++ b/testing/web-platform/tests/service-workers/service-worker/extendable-event-waituntil.https.html @@ -16,14 +16,17 @@ function runTest(test, scope, onRegister) { // |obj.synced| to true once ack'd. function syncWorker(test, worker, obj) { var channel = new MessageChannel(); - channel.port1.onmessage = test.step_func(function(e) { - var message = e.data; - assert_equals(message, 'SYNC', - 'Should receive sync message from worker.'); - obj.synced = true; - channel.port1.postMessage('ACK'); - }); worker.postMessage({port: channel.port2}, [channel.port2]); + return new Promise(function(resolve) { + channel.port1.onmessage = test.step_func(function(e) { + var message = e.data; + assert_equals(message, 'SYNC', + 'Should receive sync message from worker.'); + obj.synced = true; + channel.port1.postMessage('ACK'); + resolve(); + }); + }); } async_test(function(t) { @@ -68,13 +71,28 @@ async_test(function(t) { async_test(function(t) { var scope = 'resources/install-reject-precedence'; var onRegister = function(worker) { - var obj = {}; + var obj1 = {}; + var obj2 = {}; wait_for_state(t, worker, 'redundant') .then(function() { + assert_true( + obj1.synced, + 'The "redundant" state was entered after the first "extend ' + + 'lifetime promise" resolved.' + ); + assert_true( + obj2.synced, + 'The "redundant" state was entered after the third "extend ' + + 'lifetime promise" resolved.' + ); service_worker_unregister_and_done(t, scope); }) .catch(unreached_rejection(t)); - syncWorker(t, worker, obj); + + syncWorker(t, worker, obj1) + .then(function() { + syncWorker(t, worker, obj2); + }); }; runTest(t, scope, onRegister); }, 'Test ExtendableEvent waitUntil reject precedence.'); diff --git a/testing/web-platform/tests/service-workers/service-worker/fetch-csp.https.html b/testing/web-platform/tests/service-workers/service-worker/fetch-csp.https.html index 9f3365056a98..91a774a133fd 100644 --- a/testing/web-platform/tests/service-workers/service-worker/fetch-csp.https.html +++ b/testing/web-platform/tests/service-workers/service-worker/fetch-csp.https.html @@ -5,28 +5,107 @@ diff --git a/testing/web-platform/tests/service-workers/service-worker/fetch-event-async-respond-with.https.html b/testing/web-platform/tests/service-workers/service-worker/fetch-event-async-respond-with.https.html index 912e709ca38f..a2b93acfc5b2 100644 --- a/testing/web-platform/tests/service-workers/service-worker/fetch-event-async-respond-with.https.html +++ b/testing/web-platform/tests/service-workers/service-worker/fetch-event-async-respond-with.https.html @@ -1,6 +1,5 @@ - - + + + diff --git a/testing/web-platform/tests/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html b/testing/web-platform/tests/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html index 5d3346e7b281..cd6861a9d453 100644 --- a/testing/web-platform/tests/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html +++ b/testing/web-platform/tests/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html @@ -1,6 +1,5 @@ - - diff --git a/testing/web-platform/tests/service-workers/service-worker/interfaces.https.html b/testing/web-platform/tests/service-workers/service-worker/interfaces.https.html index 403a005344ec..889142fe3af9 100644 --- a/testing/web-platform/tests/service-workers/service-worker/interfaces.https.html +++ b/testing/web-platform/tests/service-workers/service-worker/interfaces.https.html @@ -13,7 +13,9 @@ test(function() { { register: 'function', getRegistration: 'function', - oncontrollerchange: EVENT_HANDLER + oncontrollerchange: EVENT_HANDLER, + onmessage: EVENT_HANDLER, + onmessageerror: EVENT_HANDLER }); }, 'Interfaces and attributes of ServiceWorkerContainer'); diff --git a/testing/web-platform/tests/service-workers/service-worker/navigation-preload/resource-timing.https.html b/testing/web-platform/tests/service-workers/service-worker/navigation-preload/resource-timing.https.html new file mode 100644 index 000000000000..5f0953c76d13 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/navigation-preload/resource-timing.https.html @@ -0,0 +1,92 @@ + + +Navigation Preload Resource Timing + + + + diff --git a/testing/web-platform/tests/service-workers/service-worker/navigation-preload/resources/resource-timing-scope.py b/testing/web-platform/tests/service-workers/service-worker/navigation-preload/resources/resource-timing-scope.py new file mode 100644 index 000000000000..1820be4400e3 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/navigation-preload/resources/resource-timing-scope.py @@ -0,0 +1,19 @@ +import zlib + +def main(request, response): + type = request.GET.first("type") + + if type == "normal": + content = "This is Navigation Preload Resource Timing test." + output = zlib.compress(content, 9) + headers = [("Content-type", "text/plain"), + ("Content-Encoding", "deflate"), + ("X-Decoded-Body-Size", len(content)), + ("X-Encoded-Body-Size", len(output)), + ("Content-Length", len(output))] + return headers, output + + if type == "redirect": + response.status = 302 + response.headers.append("Location", "redirect-redirected.html") + return "" diff --git a/testing/web-platform/tests/service-workers/service-worker/navigation-preload/resources/resource-timing-worker.js b/testing/web-platform/tests/service-workers/service-worker/navigation-preload/resources/resource-timing-worker.js new file mode 100644 index 000000000000..46af6456aec3 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/navigation-preload/resources/resource-timing-worker.js @@ -0,0 +1,19 @@ +self.addEventListener('activate', event => { + event.waitUntil(self.registration.navigationPreload.enable()); + }); + +self.addEventListener('fetch', event => { + event.respondWith( + event.preloadResponse + .then(response => { + var headers = response.headers; + return response.text().then(text => + new Response( + JSON.stringify({ + decodedBodySize: headers.get('X-Decoded-Body-Size'), + encodedBodySize: headers.get('X-Encoded-Body-Size'), + timingEntries: performance.getEntriesByName(event.request.url) + }), + {headers: {'Content-Type': 'text/html'}})); + })); + }); diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/client-id-worker.js b/testing/web-platform/tests/service-workers/service-worker/resources/client-id-worker.js new file mode 100644 index 000000000000..ec71b3458b72 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/resources/client-id-worker.js @@ -0,0 +1,27 @@ +self.onmessage = function(e) { + var port = e.data.port; + var message = []; + + var promise = Promise.resolve() + .then(function() { + // 1st matchAll() + return self.clients.matchAll().then(function(clients) { + clients.forEach(function(client) { + message.push(client.id); + }); + }); + }) + .then(function() { + // 2nd matchAll() + return self.clients.matchAll().then(function(clients) { + clients.forEach(function(client) { + message.push(client.id); + }); + }); + }) + .then(function() { + // Send an array containing ids of clients from 1st and 2nd matchAll() + port.postMessage(message); + }); + e.waitUntil(promise); +}; diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-client-types-frame.html b/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-client-types-frame.html new file mode 100644 index 000000000000..7c949110082e --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-client-types-frame.html @@ -0,0 +1,10 @@ + + diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-client-types-shared-worker.js b/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-client-types-shared-worker.js new file mode 100644 index 000000000000..fadef970374b --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-client-types-shared-worker.js @@ -0,0 +1,10 @@ +onconnect = function(e) { + var port = e.ports[0]; + fetch('clientId') + .then(function(response) { + return response.text(); + }) + .then(function(text) { + port.postMessage({clientId: text}); + }); +}; diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-cross-origin-frame.html b/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-cross-origin-frame.html new file mode 100644 index 000000000000..eaade327bc59 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-cross-origin-frame.html @@ -0,0 +1,53 @@ + + + + + + diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-worker.js b/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-worker.js index 9ac2c2264589..ca4444f35335 100644 --- a/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-worker.js +++ b/testing/web-platform/tests/service-workers/service-worker/resources/clients-get-worker.js @@ -1,53 +1,48 @@ +// This worker is designed to expose information about clients that is only available from Service Worker contexts. +// +// In the case of the `onfetch` handler, it provides the `clientId` property of +// the `event` object. In the case of the `onmessage` handler, it provides the +// Client instance attributes of the requested clients. self.onfetch = function(e) { - if (e.request.url.indexOf("clients-get-frame.html") >= 0) { - if (e.clientId === null) { - e.respondWith(fetch(e.request)); - } else { - e.respondWith(Response.error()); - } + if (e.request.mode === 'navigate' && e.clientId !== null) { + e.respondWith(Response.error( + '`clientId` incorrectly set to non-null value for request with mode `navigate`' + )); + return; + } + + if (/\/clientId$/.test(e.request.url)) { + e.respondWith(new Response(e.clientId)); return; } - e.respondWith(new Response(e.clientId)); }; self.onmessage = function(e) { var port = e.data.port; - if (e.data.message == 'get_client_ids') { - var clientIds = e.data.clientIds; - var message = []; + var client_ids = e.data.clientIds; + var message = []; - Promise.all( - clientIds.map(function(clientId) { - return self.clients.get(clientId); - }).concat(self.clients.get("invalid-id")) - ).then(function(clients) { - clients.forEach(function(client) { - if (client instanceof Client) { - message.push([client.visibilityState, - client.focused, - client.url, - client.frameType]); - } else { - message.push(client); - } - }); - port.postMessage(message); - }); - } else if (e.data.message == 'get_other_client_id') { - var clientId = e.data.clientId; - var message; - - self.clients.get(clientId) - .then(function(client) { - if (client instanceof Client) { - message = [client.visibilityState, - client.focused, - client.url, - client.frameType]; + e.waitUntil(Promise.all( + client_ids.map(function(client_id) { + return self.clients.get(client_id); + })) + .then(function(clients) { + // No matching client for a given id or a matched client is off-origin + // from the service worker. + if (clients.length == 1 && clients[0] == undefined) { + port.postMessage(clients[0]); } else { - message = client; + clients.forEach(function(client) { + if (client instanceof Client) { + message.push([client.visibilityState, + client.focused, + client.url, + client.frameType]); + } else { + message.push(client); + } + }); + port.postMessage(message); } - port.postMessage(message); - }); - } + })); }; diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-client-types-iframe.html b/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-client-types-iframe.html index 51b4dca03141..7607b035de31 100644 --- a/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-client-types-iframe.html +++ b/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-client-types-iframe.html @@ -4,5 +4,5 @@ Change the page URL using the History API to ensure that ServiceWorkerClient uses the creation URL. --> - + diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-on-evaluation-worker.js b/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-on-evaluation-worker.js new file mode 100644 index 000000000000..f1559aca39b6 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-on-evaluation-worker.js @@ -0,0 +1,11 @@ +importScripts('test-helpers.sub.js'); + +var page_url = normalizeURL('../clients-matchall-on-evaluation.https.html'); + +self.clients.matchAll({includeUncontrolled: true}) + .then(function(clients) { + clients.forEach(function(client) { + if (client.url == page_url) + client.postMessage('matched'); + }); + }); diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-worker.js b/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-worker.js index 8849b2ce2b9d..d6634f4d40ef 100644 --- a/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-worker.js +++ b/testing/web-platform/tests/service-workers/service-worker/resources/clients-matchall-worker.js @@ -2,29 +2,30 @@ self.onmessage = function(e) { var port = e.data.port; var options = e.data.options; - self.clients.matchAll(options).then(function(clients) { - var message = []; - clients.forEach(function(client) { - var frame_type = client.frameType; - if (client.url.indexOf('clients-matchall-include-uncontrolled.https.html') > -1 && - client.frameType == 'auxiliary') { - // The test tab might be opened using window.open() by the test framework. - // In that case, just pretend it's top-level! - frame_type = 'top-level'; - } - message.push([client.visibilityState, - client.focused, - client.url, - client.type, - frame_type]); - }); - // Sort by url - if (!e.data.disableSort) { - message.sort(function(a, b) { return a[2] > b[2] ? 1 : -1; }); - } - port.postMessage(message); - }) - .catch(e => { - port.postMessage('clients.matchAll() rejected: ' + e); - }) + e.waitUntil(self.clients.matchAll(options) + .then(function(clients) { + var message = []; + clients.forEach(function(client) { + var frame_type = client.frameType; + if (client.url.indexOf('clients-matchall-include-uncontrolled.https.html') > -1 && + client.frameType == 'auxiliary') { + // The test tab might be opened using window.open() by the test framework. + // In that case, just pretend it's top-level! + frame_type = 'top-level'; + } + message.push([client.visibilityState, + client.focused, + client.url, + client.type, + frame_type]); + }); + // Sort by url + if (!e.data.disableSort) { + message.sort(function(a, b) { return a[2] > b[2] ? 1 : -1; }); + } + port.postMessage(message); + }) + .catch(e => { + port.postMessage('clients.matchAll() rejected: ' + e); + })); }; diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-waituntil.js b/testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-waituntil.js index 48fdf1b99fd1..20a9eb023f62 100644 --- a/testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-waituntil.js +++ b/testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-waituntil.js @@ -57,8 +57,20 @@ oninstall = function(e) { e.waitUntil(fulfillPromise()); break; case 'install-reject-precedence': + // Three "extend lifetime promises" are needed to verify that the user + // agent waits for all promises to settle even in the event of rejection. + // The first promise is fulfilled on demand by the client, the second is + // immediately scheduled for rejection, and the third is fulfilled on + // demand by the client (but only after the first promise has been + // fulfilled). + // + // User agents which simply expose `Promise.all` semantics in this case + // (by entering the "redundant state" following the rejection of the + // second promise but prior to the fulfillment of the third) can be + // identified from the client context. e.waitUntil(fulfillPromise()); e.waitUntil(rejectPromise()); + e.waitUntil(fulfillPromise()); break; } }; diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/fetch-csp-iframe.html b/testing/web-platform/tests/service-workers/service-worker/resources/fetch-csp-iframe.html index df2183643854..33bf0416d585 100644 --- a/testing/web-platform/tests/service-workers/service-worker/resources/fetch-csp-iframe.html +++ b/testing/web-platform/tests/service-workers/service-worker/resources/fetch-csp-iframe.html @@ -1,72 +1,16 @@ - - diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-respond-with-argument-iframe.html b/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-respond-with-argument-iframe.html new file mode 100644 index 000000000000..33b47e78a349 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-respond-with-argument-iframe.html @@ -0,0 +1,55 @@ + + diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-respond-with-argument-worker.js b/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-respond-with-argument-worker.js new file mode 100644 index 000000000000..712c4b73c9bc --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-respond-with-argument-worker.js @@ -0,0 +1,14 @@ +self.addEventListener('fetch', function(event) { + var testcase = new URL(event.request.url).search; + switch (testcase) { + case '?response-object': + event.respondWith(new Response('body')); + break; + case '?response-promise-object': + event.respondWith(Promise.resolve(new Response('body'))); + break; + case '?other-value': + event.respondWith(new Object()); + break; + } + }); diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-test-worker.js b/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-test-worker.js index 55ba4ab4d116..61ae85e98986 100644 --- a/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-test-worker.js +++ b/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-test-worker.js @@ -113,6 +113,11 @@ function handleIntegrity(event) { event.respondWith(new Response(event.request.integrity)); } +function handleHeaders(event) { + const headers = Array.from(event.request.headers); + event.respondWith(new Response(JSON.stringify(headers))); +} + self.addEventListener('fetch', function(event) { var url = event.request.url; var handlers = [ @@ -132,6 +137,7 @@ self.addEventListener('fetch', function(event) { { pattern: '?cache', fn: handleCache }, { pattern: '?eventsource', fn: handleEventSource }, { pattern: '?integrity', fn: handleIntegrity }, + { pattern: '?headers', fn: handleHeaders }, ]; var handler = null; diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/import-mime-type-worker.py b/testing/web-platform/tests/service-workers/service-worker/resources/import-mime-type-worker.py new file mode 100644 index 000000000000..aa885e7a4de0 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/resources/import-mime-type-worker.py @@ -0,0 +1,10 @@ +def main(request, response): + if 'mime' in request.GET: + return ( + [('Content-Type', 'application/javascript')], + "importScripts('./mime-type-worker.py?mime={0}');".format(request.GET['mime']) + ) + return ( + [('Content-Type', 'application/javascript')], + "importScripts('./mime-type-worker.py');" + ) diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/interfaces-worker.sub.js b/testing/web-platform/tests/service-workers/service-worker/resources/interfaces-worker.sub.js index e5ed36fcebaf..2ae75ba9f947 100644 --- a/testing/web-platform/tests/service-workers/service-worker/resources/interfaces-worker.sub.js +++ b/testing/web-platform/tests/service-workers/service-worker/resources/interfaces-worker.sub.js @@ -15,7 +15,8 @@ test(function() { onactivate: EVENT_HANDLER, onfetch: EVENT_HANDLER, oninstall: EVENT_HANDLER, - onmessage: EVENT_HANDLER + onmessage: EVENT_HANDLER, + onmessageerror: EVENT_HANDLER }); }, 'ServiceWorkerGlobalScope'); diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests.js b/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests.js index 9b50a53744ce..cf606281912a 100644 --- a/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests.js +++ b/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests.js @@ -137,6 +137,70 @@ function registration_tests(register_method, check_error_types) { 'Registration of plain text script should fail.'); }, 'Registering script with bad MIME type'); + const validMimeTypes = [ + 'application/ecmascript', + 'application/javascript', + 'application/x-ecmascript', + 'application/x-javascript', + 'text/ecmascript', + 'text/javascript', + 'text/javascript1.0', + 'text/javascript1.1', + 'text/javascript1.2', + 'text/javascript1.3', + 'text/javascript1.4', + 'text/javascript1.5', + 'text/jscript', + 'text/livescript', + 'text/x-ecmascript', + 'text/x-javascript' + ]; + + for (const validMimeType of validMimeTypes) { + promise_test(() => { + var script = `resources/mime-type-worker.py?mime=${validMimeType}`; + var scope = 'resources/scope/good-mime-type-worker/'; + + return register_method(script, {scope}).then(registration => { + assert_true( + registration instanceof ServiceWorkerRegistration, + 'Successfully registered.'); + return registration.unregister(); + }); + }, `Registering script with good MIME type ${validMimeType}`); + + promise_test(() => { + var script = `resources/import-mime-type-worker.py?mime=${validMimeType}`; + var scope = 'resources/scope/good-mime-type-worker/'; + + return register_method(script, { scope }).then(registration => { + assert_true( + registration instanceof ServiceWorkerRegistration, + 'Successfully registered.'); + return registration.unregister(); + }); + }, `Registering script that imports script with good MIME type ${validMimeType}`); + } + + promise_test(function(t) { + var script = 'resources/import-mime-type-worker.py'; + var scope = 'resources/scope/no-mime-type-worker/'; + return promise_rejects(t, + check_error_types ? 'SecurityError' : null, + register_method(script, {scope: scope}), + 'Registration of no MIME type imported script should fail.'); + }, 'Registering script that imports script with no MIME type'); + + promise_test(function(t) { + var script = 'resources/import-mime-type-worker.py?mime=text/plain'; + var scope = 'resources/scope/bad-mime-type-worker/'; + return promise_rejects(t, + check_error_types ? 'SecurityError' : null, + register_method(script, {scope: scope}), + 'Registration of plain text imported script should fail.'); + }, 'Registering script that imports script with bad MIME type'); + + promise_test(function(t) { var script = 'resources/redirect.py?Redirect=' + encodeURIComponent('/resources/registration-worker.js'); diff --git a/testing/web-platform/tests/shadow-dom/slots-fallback-in-document.html b/testing/web-platform/tests/shadow-dom/slots-fallback-in-document.html new file mode 100644 index 000000000000..91acc5d5f2d7 --- /dev/null +++ b/testing/web-platform/tests/shadow-dom/slots-fallback-in-document.html @@ -0,0 +1,56 @@ + +Shadow DOM: Slots and fallback contents in Document tree + + + + + +
+
+ +
This is fallback content
+
+
+ + + +
+
+ +
+
+ + diff --git a/testing/web-platform/tests/staticrange/OWNERS b/testing/web-platform/tests/staticrange/OWNERS new file mode 100644 index 000000000000..5692d1b94a29 --- /dev/null +++ b/testing/web-platform/tests/staticrange/OWNERS @@ -0,0 +1,2 @@ +@garykac +@siusin diff --git a/testing/web-platform/tests/staticrange/idlharness.html b/testing/web-platform/tests/staticrange/idlharness.html new file mode 100644 index 000000000000..e35bca1e7e49 --- /dev/null +++ b/testing/web-platform/tests/staticrange/idlharness.html @@ -0,0 +1,31 @@ +Static Range IDL tests + + + + + + +
+interface Node {
+};
+
+ +
+interface StaticRange {
+    readonly attribute Node startContainer;
+    readonly attribute unsigned long startOffset;
+    readonly attribute Node endContainer;
+    readonly attribute unsigned long endOffset;
+    readonly attribute boolean collapsed;
+};
+
+ + diff --git a/testing/web-platform/tests/storage/resources/storagemanager-persist-worker.js b/testing/web-platform/tests/storage/resources/storagemanager-persist-worker.js new file mode 100644 index 000000000000..1152e4ec7349 --- /dev/null +++ b/testing/web-platform/tests/storage/resources/storagemanager-persist-worker.js @@ -0,0 +1,7 @@ +importScripts('/resources/testharness.js'); + +test(function() { + assert_false('persist' in navigator.storage); +}, 'navigator.storage.persist should not exist in workers'); + +done(); diff --git a/testing/web-platform/tests/storage/resources/storagemanager-persisted-worker.js b/testing/web-platform/tests/storage/resources/storagemanager-persisted-worker.js new file mode 100644 index 000000000000..979c8be3cd39 --- /dev/null +++ b/testing/web-platform/tests/storage/resources/storagemanager-persisted-worker.js @@ -0,0 +1,13 @@ +importScripts('/resources/testharness.js'); + +promise_test(function() { + var promise = navigator.storage.persisted(); + assert_true(promise instanceof Promise, + 'navigator.storage.persisted() returned a Promise.'); + return promise.then(function (result) { + assert_equals(typeof result, 'boolean', + result + ' should be a boolean'); + }); +}, 'navigator.storage.persisted returns a promise that resolves.'); + +done(); diff --git a/testing/web-platform/tests/storage/storagemanager-estimate.https.html b/testing/web-platform/tests/storage/storagemanager-estimate.https.html new file mode 100644 index 000000000000..08a699adfb00 --- /dev/null +++ b/testing/web-platform/tests/storage/storagemanager-estimate.https.html @@ -0,0 +1,68 @@ + + +StorageManager: estimate() + + + + diff --git a/testing/web-platform/tests/storage/storagemanager-persist-worker.https.html b/testing/web-platform/tests/storage/storagemanager-persist-worker.https.html new file mode 100644 index 000000000000..9c89a2f67125 --- /dev/null +++ b/testing/web-platform/tests/storage/storagemanager-persist-worker.https.html @@ -0,0 +1,10 @@ + + +StorageManager: persist() (worker) + + + + diff --git a/testing/web-platform/tests/storage/storagemanager-persist.https.html b/testing/web-platform/tests/storage/storagemanager-persist.https.html new file mode 100644 index 000000000000..61624fe272a6 --- /dev/null +++ b/testing/web-platform/tests/storage/storagemanager-persist.https.html @@ -0,0 +1,18 @@ + + +StorageManager: persist() + + + + diff --git a/testing/web-platform/tests/storage/storagemanager-persisted-worker.https.html b/testing/web-platform/tests/storage/storagemanager-persisted-worker.https.html new file mode 100644 index 000000000000..75004946164d --- /dev/null +++ b/testing/web-platform/tests/storage/storagemanager-persisted-worker.https.html @@ -0,0 +1,10 @@ + + +StorageManager: persisted() (worker) + + + + diff --git a/testing/web-platform/tests/storage/storagemanager-persisted.https.html b/testing/web-platform/tests/storage/storagemanager-persisted.https.html new file mode 100644 index 000000000000..1d88c11bd8aa --- /dev/null +++ b/testing/web-platform/tests/storage/storagemanager-persisted.https.html @@ -0,0 +1,18 @@ + + +StorageManager: persist() + + + + diff --git a/testing/web-platform/tests/streams/piping/close-propagation-forward.js b/testing/web-platform/tests/streams/piping/close-propagation-forward.js index 3f39c6afe934..35eac87a877b 100644 --- a/testing/web-platform/tests/streams/piping/close-propagation-forward.js +++ b/testing/web-platform/tests/streams/piping/close-propagation-forward.js @@ -424,4 +424,38 @@ promise_test(() => { }, 'Closing must be propagated forward: shutdown must not occur until the final write completes'); +promise_test(() => { + + const rs = recordingReadableStream(); + + let resolveWritePromise; + const ws = recordingWritableStream({ + write() { + return new Promise(resolve => { + resolveWritePromise = resolve; + }); + } + }); + + let pipeComplete = false; + const pipePromise = rs.pipeTo(ws, { preventClose: true }).then(() => { + pipeComplete = true; + }); + + rs.controller.enqueue('a'); + rs.controller.close(); + + // Flush async events and verify that no shutdown occurs. + return flushAsyncEvents().then(() => { + assert_array_equals(ws.events, ['write', 'a'], + 'the chunk must have been written, but close must not have happened yet'); + assert_equals(pipeComplete, false, 'the pipe must not be complete'); + + resolveWritePromise(); + + return pipePromise; + }); + +}, 'Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true'); + done(); diff --git a/testing/web-platform/tests/streams/piping/flow-control.js b/testing/web-platform/tests/streams/piping/flow-control.js index 2bb04090820e..04c56ec40d0b 100644 --- a/testing/web-platform/tests/streams/piping/flow-control.js +++ b/testing/web-platform/tests/streams/piping/flow-control.js @@ -170,16 +170,44 @@ promise_test(() => { }, 'Piping from a ReadableStream to a WritableStream that desires more chunks before finishing with previous ones'); -promise_test(() => { +class StepTracker { + constructor() { + this.waiters = []; + this.wakers = []; + } + // Returns promise which resolves when step `n` is reached. Also schedules step n + 1 to happen shortly after the + // promise is resolved. + waitThenAdvance(n) { + if (this.waiters[n] === undefined) { + this.waiters[n] = new Promise(resolve => { + this.wakers[n] = resolve; + }); + this.waiters[n] + .then(() => flushAsyncEvents()) + .then(() => { + if (this.wakers[n + 1] !== undefined) { + this.wakers[n + 1](); + } + }); + } + if (n == 0) { + this.wakers[0](); + } + return this.waiters[n]; + } +} + +promise_test(() => { + const steps = new StepTracker(); const desiredSizes = []; const rs = recordingReadableStream({ start(controller) { - delay(100).then(() => enqueue('a')); - delay(200).then(() => enqueue('b')); - delay(300).then(() => enqueue('c')); - delay(400).then(() => enqueue('d')); - delay(500).then(() => controller.close()); + steps.waitThenAdvance(1).then(() => enqueue('a')); + steps.waitThenAdvance(3).then(() => enqueue('b')); + steps.waitThenAdvance(5).then(() => enqueue('c')); + steps.waitThenAdvance(7).then(() => enqueue('d')); + steps.waitThenAdvance(11).then(() => controller.close()); function enqueue(chunk) { controller.enqueue(chunk); @@ -190,80 +218,86 @@ promise_test(() => { const chunksFinishedWriting = []; const writableStartPromise = Promise.resolve(); + let writeCalled = false; const ws = recordingWritableStream({ start() { return writableStartPromise; }, write(chunk) { - return delay(350).then(() => { + const waitForStep = writeCalled ? 12 : 9; + writeCalled = true; + return steps.waitThenAdvance(waitForStep).then(() => { chunksFinishedWriting.push(chunk); }); } }); return writableStartPromise.then(() => { + const pipePromise = rs.pipeTo(ws); + steps.waitThenAdvance(0); + return Promise.all([ - rs.pipeTo(ws).then(() => { - assert_array_equals(desiredSizes, [1, 0, -1, -2], 'backpressure must have been exerted at the source'); - assert_array_equals(chunksFinishedWriting, ['a', 'b', 'c', 'd'], 'all chunks started writing'); - - assert_array_equals(rs.eventsWithoutPulls, [], 'nothing unexpected should happen to the ReadableStream'); - assert_array_equals(ws.events, ['write', 'a', 'write', 'b', 'write', 'c', 'write', 'd', 'close'], - 'all chunks were written (and the WritableStream closed)'); - }), - - delay(125).then(() => { - assert_array_equals(chunksFinishedWriting, [], 'at t = 125 ms, zero chunks must have finished writing'); - assert_array_equals(ws.events, ['write', 'a'], 'at t = 125 ms, one chunk must have been written'); + steps.waitThenAdvance(2).then(() => { + assert_array_equals(chunksFinishedWriting, [], 'at step 2, zero chunks must have finished writing'); + assert_array_equals(ws.events, ['write', 'a'], 'at step 2, one chunk must have been written'); // When 'a' (the very first chunk) was enqueued, it was immediately used to fulfill the outstanding read request // promise, leaving the queue empty. assert_array_equals(desiredSizes, [1], - 'at t = 125 ms, the desiredSize at the last enqueue (100 ms) must have been 1'); - assert_equals(rs.controller.desiredSize, 1, 'at t = 125 ms, the current desiredSize must be 1'); + 'at step 2, the desiredSize at the last enqueue (step 1) must have been 1'); + assert_equals(rs.controller.desiredSize, 1, 'at step 2, the current desiredSize must be 1'); }), - delay(225).then(() => { - assert_array_equals(chunksFinishedWriting, [], 'at t = 225 ms, zero chunks must have finished writing'); - assert_array_equals(ws.events, ['write', 'a'], 'at t = 225 ms, one chunk must have been written'); + steps.waitThenAdvance(4).then(() => { + assert_array_equals(chunksFinishedWriting, [], 'at step 4, zero chunks must have finished writing'); + assert_array_equals(ws.events, ['write', 'a'], 'at step 4, one chunk must have been written'); - // When 'b' was enqueued at 200 ms, the queue was also empty, since immediately after enqueuing 'a' at - // t = 100 ms, it was dequeued in order to fulfill the read() call that was made at time t = 0. Thus the queue + // When 'b' was enqueued at step 3, the queue was also empty, since immediately after enqueuing 'a' at + // step 1, it was dequeued in order to fulfill the read() call that was made at step 0. Thus the queue // had size 1 (thus desiredSize of 0). assert_array_equals(desiredSizes, [1, 0], - 'at t = 225 ms, the desiredSize at the last enqueue (200 ms) must have been 0'); - assert_equals(rs.controller.desiredSize, 0, 'at t = 225 ms, the current desiredSize must be 0'); + 'at step 4, the desiredSize at the last enqueue (step 3) must have been 0'); + assert_equals(rs.controller.desiredSize, 0, 'at step 4, the current desiredSize must be 0'); }), - delay(325).then(() => { - assert_array_equals(chunksFinishedWriting, [], 'at t = 325 ms, zero chunks must have finished writing'); - assert_array_equals(ws.events, ['write', 'a'], 'at t = 325 ms, one chunk must have been written'); + steps.waitThenAdvance(6).then(() => { + assert_array_equals(chunksFinishedWriting, [], 'at step 6, zero chunks must have finished writing'); + assert_array_equals(ws.events, ['write', 'a'], 'at step 6, one chunk must have been written'); - // When 'c' was enqueued at 300 ms, the queue was not empty; it had 'b' in it, since 'b' will not be read until - // the first write completes at 450 ms. Thus, the queue size is 2 after enqueuing 'c', giving a desiredSize of + // When 'c' was enqueued at step 5, the queue was not empty; it had 'b' in it, since 'b' will not be read until + // the first write completes at step 9. Thus, the queue size is 2 after enqueuing 'c', giving a desiredSize of // -1. assert_array_equals(desiredSizes, [1, 0, -1], - 'at t = 325 ms, the desiredSize at the last enqueue (300 ms) must have been -1'); - assert_equals(rs.controller.desiredSize, -1, 'at t = 325 ms, the current desiredSize must be -1'); + 'at step 6, the desiredSize at the last enqueue (step 5) must have been -1'); + assert_equals(rs.controller.desiredSize, -1, 'at step 6, the current desiredSize must be -1'); }), - delay(425).then(() => { - assert_array_equals(chunksFinishedWriting, [], 'at t = 425 ms, zero chunks must have finished writing'); - assert_array_equals(ws.events, ['write', 'a'], 'at t = 425 ms, one chunk must have been written'); + steps.waitThenAdvance(8).then(() => { + assert_array_equals(chunksFinishedWriting, [], 'at step 8, zero chunks must have finished writing'); + assert_array_equals(ws.events, ['write', 'a'], 'at step 8, one chunk must have been written'); - // When 'd' was enqueued at 400 ms, the situation is the same as before, leading to a queue containing 'b', 'c', - // and 'd'. (Remember the first write will only finish at 100 ms + 350 ms = 450 ms.) + // When 'd' was enqueued at step 7, the situation is the same as before, leading to a queue containing 'b', 'c', + // and 'd'. assert_array_equals(desiredSizes, [1, 0, -1, -2], - 'at t = 425 ms, the desiredSize at the last enqueue (400 ms) must have been -2'); - assert_equals(rs.controller.desiredSize, -2, 'at t = 425 ms, the current desiredSize must be -2'); + 'at step 8, the desiredSize at the last enqueue (step 7) must have been -2'); + assert_equals(rs.controller.desiredSize, -2, 'at step 8, the current desiredSize must be -2'); }), - delay(475).then(() => { - assert_array_equals(chunksFinishedWriting, ['a'], 'at t = 475 ms, one chunk must have finished writing'); + steps.waitThenAdvance(10).then(() => { + assert_array_equals(chunksFinishedWriting, ['a'], 'at step 10, one chunk must have finished writing'); assert_array_equals(ws.events, ['write', 'a', 'write', 'b'], - 'at t = 475 ms, two chunks must have been written'); + 'at step 10, two chunks must have been written'); - assert_equals(rs.controller.desiredSize, -1, 'at t = 475 ms, the current desiredSize must be -1'); + assert_equals(rs.controller.desiredSize, -1, 'at step 10, the current desiredSize must be -1'); + }), + + pipePromise.then(() => { + assert_array_equals(desiredSizes, [1, 0, -1, -2], 'backpressure must have been exerted at the source'); + assert_array_equals(chunksFinishedWriting, ['a', 'b', 'c', 'd'], 'all chunks finished writing'); + + assert_array_equals(rs.eventsWithoutPulls, [], 'nothing unexpected should happen to the ReadableStream'); + assert_array_equals(ws.events, ['write', 'a', 'write', 'b', 'write', 'c', 'write', 'd', 'close'], + 'all chunks were written (and the WritableStream closed)'); }) ]); }); diff --git a/testing/web-platform/tests/streams/piping/multiple-propagation.js b/testing/web-platform/tests/streams/piping/multiple-propagation.js index 79ec39956625..447433f59806 100644 --- a/testing/web-platform/tests/streams/piping/multiple-propagation.js +++ b/testing/web-platform/tests/streams/piping/multiple-propagation.js @@ -71,19 +71,48 @@ promise_test(t => { }); const ws = recordingWritableStream(); const writer = ws.getWriter(); - writer.close(); + const closePromise = writer.close(); writer.releaseLock(); return promise_rejects(t, error1, rs.pipeTo(ws), 'pipeTo must reject with the readable stream\'s error').then(() => { assert_array_equals(rs.events, []); - assert_array_equals(ws.events, ['close']); + assert_array_equals(ws.events, ['abort', error1]); return Promise.all([ promise_rejects(t, error1, rs.getReader().closed, 'the readable stream must be errored with error1'), - ws.getWriter().closed + promise_rejects(t, new TypeError(), ws.getWriter().closed, + 'closed must reject with a TypeError indicating the writable stream was aborted'), + promise_rejects(t, new TypeError(), closePromise, + 'close() must reject with a TypeError indicating the writable stream was aborted'), ]); }); +}, 'Piping from an errored readable stream to a closing writable stream'); + +promise_test(t => { + const rs = recordingReadableStream({ + start(c) { + c.error(error1); + } + }); + const ws = recordingWritableStream(); + const writer = ws.getWriter(); + const closePromise = writer.close(); + writer.releaseLock(); + + return flushAsyncEvents().then(() => { + return promise_rejects(t, error1, rs.pipeTo(ws), 'pipeTo must reject with the readable stream\'s error').then(() => { + assert_array_equals(rs.events, []); + assert_array_equals(ws.events, ['close']); + + return Promise.all([ + promise_rejects(t, error1, rs.getReader().closed, 'the readable stream must be errored with error1'), + ws.getWriter().closed, + closePromise + ]); + }); + }); + }, 'Piping from an errored readable stream to a closed writable stream'); promise_test(t => { diff --git a/testing/web-platform/tests/streams/piping/pipe-through.js b/testing/web-platform/tests/streams/piping/pipe-through.js index 57277cf6d728..bc4ac909c193 100644 --- a/testing/web-platform/tests/streams/piping/pipe-through.js +++ b/testing/web-platform/tests/streams/piping/pipe-through.js @@ -104,4 +104,44 @@ test(() => { }, 'pipeThrough can handle calling a pipeTo that returns a non-promise thenable object'); +promise_test(() => { + const dummy = { + pipeTo() { + return Promise.reject(new Error('this rejection should not be reported as unhandled')); + } + }; + + ReadableStream.prototype.pipeThrough.call(dummy, { }); + + // The test harness should complain about unhandled rejections by then. + return flushAsyncEvents(); + +}, 'pipeThrough should mark a real promise from a fake readable as handled'); + +test(() => { + let thenCalled = false + let catchCalled = false; + const dummy = { + pipeTo() { + const fakePromise = Object.create(Promise.prototype); + fakePromise.then = () => { + thenCalled = true; + }; + fakePromise.catch = () => { + catchCalled = true; + }; + assert_true(fakePromise instanceof Promise, 'fakePromise fools instanceof'); + return fakePromise; + } + }; + + // An incorrect implementation which uses an internal method to mark the promise as handled will throw or crash here. + ReadableStream.prototype.pipeThrough.call(dummy, { }); + + // An incorrect implementation that tries to mark the promise as handled by calling .then() or .catch() on the object + // will fail these tests. + assert_false(thenCalled, 'then should not be called'); + assert_false(catchCalled, 'catch should not be called'); +}, 'pipeThrough should not be fooled by an object whose instanceof Promise returns true'); + done(); diff --git a/testing/web-platform/tests/streams/readable-byte-streams/general.js b/testing/web-platform/tests/streams/readable-byte-streams/general.js index 374c52ca2e8e..23989113509a 100644 --- a/testing/web-platform/tests/streams/readable-byte-streams/general.js +++ b/testing/web-platform/tests/streams/readable-byte-streams/general.js @@ -1897,6 +1897,28 @@ promise_test(t => { }, 'ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is ' + 'errored in it'); +promise_test(() => { + // Tests https://github.com/whatwg/streams/issues/686 + + let controller; + const rs = new ReadableStream({ + autoAllocateChunkSize: 128, + start(c) { + controller = c; + }, + type: "bytes" + }); + + const readPromise = rs.getReader().read(); + + const br = controller.byobRequest; + controller.close(); + + br.respond(0); + + return readPromise; +}, 'ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction'); + test(() => { const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor; const stream = new ReadableStream({ type: 'bytes' }); diff --git a/testing/web-platform/tests/streams/readable-streams/floating-point-total-queue-size.js b/testing/web-platform/tests/streams/readable-streams/floating-point-total-queue-size.js index 3bb3b6a90d05..f7c76248b0b2 100644 --- a/testing/web-platform/tests/streams/readable-streams/floating-point-total-queue-size.js +++ b/testing/web-platform/tests/streams/readable-streams/floating-point-total-queue-size.js @@ -117,3 +117,5 @@ function setupTestStream() { return { reader: rs.getReader(), controller }; } + +done(); diff --git a/testing/web-platform/tests/streams/resources/recording-streams.js b/testing/web-platform/tests/streams/resources/recording-streams.js index 9837318dbcc0..3f949313f970 100644 --- a/testing/web-platform/tests/streams/resources/recording-streams.js +++ b/testing/web-platform/tests/streams/resources/recording-streams.js @@ -52,18 +52,16 @@ self.recordingWritableStream = (extras = {}, strategy) => { return undefined; }, - write(chunk) { + write(chunk, controller) { stream.events.push('write', chunk); if (extras.write) { - return extras.write(chunk); + return extras.write(chunk, controller); } return undefined; }, - close(...args) { - assert_array_equals(args, [controllerToCopyOver], 'close must always be called with the controller'); - + close() { stream.events.push('close'); if (extras.close) { diff --git a/testing/web-platform/tests/streams/writable-streams/aborting.js b/testing/web-platform/tests/streams/writable-streams/aborting.js index 9f589ec152ff..a04befd69d2c 100644 --- a/testing/web-platform/tests/streams/writable-streams/aborting.js +++ b/testing/web-platform/tests/streams/writable-streams/aborting.js @@ -14,9 +14,7 @@ error2.name = 'error2'; promise_test(t => { const ws = new WritableStream({ - write() { - return new Promise(() => { }); // forever-pending, so normally .ready would not fulfill. - } + write: t.unreached_func('write() should not be called') }); const writer = ws.getWriter(); @@ -66,11 +64,12 @@ promise_test(t => { .then(() => { const writer = ws.getWriter(); - writer.abort(); + const abortPromise = writer.abort(); return Promise.all([ promise_rejects(t, new TypeError(), writer.write(1), 'write(1) must reject with a TypeError'), - promise_rejects(t, new TypeError(), writer.write(2), 'write(2) must reject with a TypeError') + promise_rejects(t, new TypeError(), writer.write(2), 'write(2) must reject with a TypeError'), + abortPromise ]); }) .then(() => { @@ -182,7 +181,7 @@ promise_test(t => { const ws = new WritableStream(); const writer = ws.getWriter(); - writer.abort(error1); + const abortPromise = writer.abort(error1); const events = []; writer.ready.catch(() => { @@ -193,6 +192,7 @@ promise_test(t => { }); return Promise.all([ + abortPromise, promise_rejects(t, new TypeError(), writer.write(), 'writing should reject with a TypeError'), promise_rejects(t, new TypeError(), writer.close(), 'closing should reject with a TypeError'), promise_rejects(t, new TypeError(), writer.abort(), 'aborting should reject with a TypeError'), @@ -231,7 +231,7 @@ promise_test(t => { }); }, 'Closing but then immediately aborting a WritableStream causes the stream to error'); -promise_test(t => { +promise_test(() => { let resolveClose; const ws = new WritableStream({ close() { @@ -311,11 +311,11 @@ promise_test(t => { return writer.ready.then(() => { const writePromise = writer.write('a'); writer.abort(error1); - let closedResolved = false; + let closedRejected = false; return Promise.all([ - writePromise.then(() => assert_false(closedResolved, '.closed should not resolve before write()')), + writePromise.then(() => assert_false(closedRejected, '.closed should not resolve before write()')), promise_rejects(t, new TypeError(), writer.closed, '.closed should reject').then(() => { - closedResolved = true; + closedRejected = true; }) ]); }); @@ -331,17 +331,18 @@ promise_test(t => { return writer.ready.then(() => { const writePromise = writer.write('a'); const abortPromise = writer.abort(error2); - let closedResolved = false; + let closedRejected = false; return Promise.all([ promise_rejects(t, error1, writePromise, 'write() should reject') - .then(() => assert_false(closedResolved, '.closed should not resolve before write()')), - promise_rejects(t, error1, writer.closed, '.closed should reject') + .then(() => assert_false(closedRejected, '.closed should not resolve before write()')), + promise_rejects(t, new TypeError(), writer.closed, '.closed should reject') .then(() => { - closedResolved = true; + closedRejected = true; }), - promise_rejects(t, error1, abortPromise, 'abort() should reject')]); + abortPromise + ]); }); -}, '.closed should not resolve before rejected write(); write() error should overwrite abort() error'); +}, '.closed should not resolve before rejected write(); write() error should not overwrite abort() error'); promise_test(t => { const ws = new WritableStream({ @@ -375,11 +376,11 @@ promise_test(t => { return Promise.all([ promise_rejects(t, error1, writer.write('1'), 'in-flight write should be rejected') .then(() => settlementOrder.push(1)), - promise_rejects(t, error1, writer.write('2'), 'first queued write should be rejected') + promise_rejects(t, new TypeError(), writer.write('2'), 'first queued write should be rejected') .then(() => settlementOrder.push(2)), - promise_rejects(t, error1, writer.write('3'), 'second queued write should be rejected') + promise_rejects(t, new TypeError(), writer.write('3'), 'second queued write should be rejected') .then(() => settlementOrder.push(3)), - promise_rejects(t, error1, writer.abort(error1), 'abort should be rejected') + writer.abort(error2) ]).then(() => assert_array_equals([1, 2, 3], settlementOrder, 'writes should be satisfied in order')); }); }, 'writes should be satisfied in order after rejected write when aborting'); @@ -394,11 +395,12 @@ promise_test(t => { return writer.ready.then(() => { return Promise.all([ promise_rejects(t, error1, writer.write('a'), 'writer.write() should reject with error from underlying write()'), - promise_rejects(t, error1, writer.close(), 'writer.close() should reject with error from underlying write()'), - promise_rejects(t, error1, writer.abort(), 'writer.abort() should reject with error from underlying write()') + promise_rejects(t, new TypeError(), writer.close(), + 'writer.close() should reject with error from underlying write()'), + writer.abort() ]); }); -}, 'close() should use error from underlying write() on abort'); +}, 'close() should reject with TypeError when abort() is first error'); promise_test(() => { let resolveWrite; @@ -583,7 +585,7 @@ promise_test(t => { }); abortPromise = writer.abort(error1); - abortPromise.catch(() => { + abortPromise.then(() => { events.push('abortPromise'); }); @@ -602,21 +604,20 @@ promise_test(t => { return Promise.all([ promise_rejects(t, error2, writePromise, 'writePromise must reject with the error returned from the sink\'s write method'), - promise_rejects(t, error2, abortPromise, - 'abortPromise must reject with the error returned from the sink\'s write method'), - promise_rejects(t, error2, writer.closed, - 'writer.closed must reject with the error returned from the sink\'s write method'), + abortPromise, + promise_rejects(t, new TypeError(), writer.closed, + 'writer.closed must reject with an error indicating abort'), flushAsyncEvents() ]); }).then(() => { - assert_array_equals(events, ['writePromise', 'closed', 'abortPromise'], - 'writePromise, abortPromise and writer.closed must reject'); + assert_array_equals(events, ['writePromise', 'abortPromise', 'closed'], + 'writePromise, abortPromise and writer.closed must settle'); const writePromise3 = writer.write('a'); return Promise.all([ - promise_rejects(t, error2, writePromise3, - 'writePromise3 must reject with the error returned from the sink\'s write method'), + promise_rejects(t, new TypeError(), writePromise3, + 'writePromise3 must reject with an error indicating abort'), promise_rejects(t, new TypeError(), writer.ready, 'writer.ready must be still rejected with the error indicating abort') ]); @@ -663,7 +664,7 @@ promise_test(t => { }); abortPromise = writer.abort(error1); - abortPromise.catch(() => { + abortPromise.then(() => { events.push('abortPromise'); }); @@ -677,13 +678,14 @@ promise_test(t => { }).then(() => { assert_array_equals(events, [], 'writePromise, abortPromise and writer.closed must not be fulfilled/rejected yet'); + // This error is too late to change anything. abort() has already changed the stream state to 'erroring'. controller.error(error2); const writePromise3 = writer.write('a'); return Promise.all([ - promise_rejects(t, error2, writePromise3, - 'writePromise3 must reject with the error passed to the controller\'s error method'), + promise_rejects(t, new TypeError(), writePromise3, + 'writePromise3 must reject with an error indicating abort'), promise_rejects(t, new TypeError(), writer.ready, 'writer.ready must be still rejected with the error indicating abort'), flushAsyncEvents() @@ -698,22 +700,21 @@ promise_test(t => { return Promise.all([ writePromise, - promise_rejects(t, error2, abortPromise, - 'abortPromise must reject with the error passed to the controller\'s error method'), - promise_rejects(t, error2, writer.closed, - 'writer.closed must reject with the error passed to the controller\'s error method'), + abortPromise, + promise_rejects(t, new TypeError(), writer.closed, + 'writer.closed must reject with an error indicating abort'), flushAsyncEvents() ]); }).then(() => { assert_array_equals(events, ['writePromise', 'abortPromise', 'closed'], - 'writePromise, abortPromise and writer.closed must reject'); + 'writePromise, abortPromise and writer.closed must settle'); const writePromise4 = writer.write('a'); return Promise.all([ writePromise, - promise_rejects(t, error2, writePromise4, - 'writePromise4 must reject with the error passed to the controller\'s error method'), + promise_rejects(t, new TypeError(), writePromise4, + 'writePromise4 must reject with an error indicating abort'), promise_rejects(t, new TypeError(), writer.ready, 'writer.ready must be still rejected with the error indicating abort') ]); @@ -750,7 +751,7 @@ promise_test(t => { const writer = ws.getWriter(); - writer.closed.catch(() => { + writer.closed.then(() => { events.push('closed'); }); @@ -762,7 +763,7 @@ promise_test(t => { }); abortPromise = writer.abort(error1); - abortPromise.catch(() => { + abortPromise.then(() => { events.push('abortPromise'); }); @@ -794,15 +795,13 @@ promise_test(t => { return Promise.all([ closePromise, - promise_rejects(t, error2, abortPromise, - 'abortPromise must reject with the error passed to the controller\'s error method'), - promise_rejects(t, error2, writer.closed, - 'writer.closed must reject with the error passed to the controller\'s error method'), + abortPromise, + writer.closed, flushAsyncEvents() ]); }).then(() => { assert_array_equals(events, ['closePromise', 'abortPromise', 'closed'], - 'closedPromise, abortPromise and writer.closed must reject'); + 'closedPromise, abortPromise and writer.closed must fulfill'); return Promise.all([ promise_rejects(t, new TypeError(), writer.close(), @@ -827,7 +826,7 @@ promise_test(t => { promise_test(t => { let resolveWrite; let controller; - const ws = new WritableStream({ + const ws = recordingWritableStream({ write(chunk, c) { controller = c; return new Promise(resolve => { @@ -876,27 +875,28 @@ promise_test(t => { const writePromise3 = writer.write('a'); return Promise.all([ - promise_rejects(t, error2, abortPromise, - 'abortPromise must reject with the error passed to the controller\'s error method'), promise_rejects(t, error2, writePromise3, 'writePromise3 must reject with the error passed to the controller\'s error method'), flushAsyncEvents() ]); }).then(() => { assert_array_equals( - events, ['abortPromise'], + events, [], 'writePromise and writer.closed must not be fulfilled/rejected yet even after writer.abort()'); resolveWrite(); return Promise.all([ + promise_rejects(t, error2, abortPromise, + 'abort() must reject with the error passed to the controller\'s error method'), promise_rejects(t, error2, writer.closed, 'writer.closed must reject with the error passed to the controller\'s error method'), flushAsyncEvents() ]); }).then(() => { - assert_array_equals(events, ['abortPromise', 'writePromise', 'closed'], + assert_array_equals(events, ['writePromise', 'abortPromise', 'closed'], 'writePromise, abortPromise and writer.closed must fulfill/reject'); + assert_array_equals(ws.events, ['write', 'a'], 'sink abort() should not be called'); const writePromise4 = writer.write('a'); @@ -940,7 +940,7 @@ promise_test(t => { const writer = ws.getWriter(); - writer.closed.catch(() => { + writer.closed.then(() => { events.push('closed'); }); @@ -958,7 +958,7 @@ promise_test(t => { assert_array_equals(events, [], 'closePromise must not be fulfilled/rejected yet'); abortPromise = writer.abort(error1); - abortPromise.catch(() => { + abortPromise.then(() => { events.push('abortPromise'); }); @@ -969,7 +969,7 @@ promise_test(t => { ]); }).then(() => { assert_array_equals( - events, ['abortPromise'], + events, [], 'closePromise and writer.closed must not be fulfilled/rejected yet even after writer.abort()'); resolveClose(); @@ -978,12 +978,11 @@ promise_test(t => { closePromise, promise_rejects(t, error2, writer.ready, 'writer.ready must be still rejected with the error passed to the controller\'s error method'), - promise_rejects(t, error2, writer.closed, - 'writer.closed must reject with the error passed to the controller\'s error method'), + writer.closed, flushAsyncEvents() ]); }).then(() => { - assert_array_equals(events, ['abortPromise', 'closePromise', 'closed'], + assert_array_equals(events, ['closePromise', 'abortPromise', 'closed'], 'abortPromise, closePromise and writer.closed must fulfill/reject'); }).then(() => { writer.releaseLock(); @@ -1020,6 +1019,7 @@ promise_test(t => { }); }, 'releaseLock() while aborting should reject the original closed promise'); +// TODO(ricea): Consider removing this test if it is no longer useful. promise_test(t => { let resolveWrite; let resolveAbort; @@ -1048,16 +1048,15 @@ promise_test(t => { resolveWrite(); return abortStarted.then(() => { writer.releaseLock(); - assert_not_equals(writer.closed, closed, 'closed promise should have changed'); + assert_equals(writer.closed, closed, 'closed promise should not have changed'); resolveAbort(); return Promise.all([ writePromise, abortPromise, - promise_rejects(t, new TypeError(), closed, 'original closed should reject'), - promise_rejects(t, new TypeError(), writer.closed, 'new closed should reject')]); + promise_rejects(t, new TypeError(), closed, 'closed should reject')]); }); }); -}, 'releaseLock() during delayed async abort() should create a new rejected closed promise'); +}, 'releaseLock() during delayed async abort() should reject the writer.closed promise'); promise_test(() => { let resolveStart; @@ -1078,7 +1077,7 @@ promise_test(() => { }); }, 'sink abort() should not be called until sink start() is done'); -promise_test(t => { +promise_test(() => { let resolveStart; let controller; const ws = recordingWritableStream({ @@ -1092,21 +1091,20 @@ promise_test(t => { const abortPromise = ws.abort('done'); controller.error(error1); resolveStart(); - return promise_rejects(t, error1, abortPromise, 'abort() should reject if start() errors the controller') - .then(() => - assert_array_equals(ws.events, [], 'abort() should be not be called if start() errors the controller')); -}, 'abort() promise should reject if start() errors the controller'); + return abortPromise.then(() => + assert_array_equals(ws.events, ['abort', 'done'], + 'abort() should still be called if start() errors the controller')); +}, 'if start attempts to error the controller after abort() has been called, then it should lose'); -promise_test(t => { +promise_test(() => { const ws = recordingWritableStream({ start() { return Promise.reject(error1); } }); - return promise_rejects(t, error1, ws.abort('done'), 'abort() should reject if start() rejects') - .then(() => - assert_array_equals(ws.events, [], 'abort() should be not be called if start() rejects')); -}, 'stream abort() promise should reject if sink start() rejects'); + return ws.abort('done').then(() => + assert_array_equals(ws.events, ['abort', 'done'], 'abort() should still be called if start() rejects')); +}, 'stream abort() promise should still resolve if sink start() rejects'); promise_test(t => { const ws = new WritableStream(); @@ -1120,21 +1118,25 @@ promise_test(t => { }, 'writer abort() during sink start() should replace the writer.ready promise synchronously'); promise_test(t => { - const promises = []; - const resolved = []; + const events = []; const ws = recordingWritableStream(); const writer = ws.getWriter(); - promises.push(promise_rejects(t, new TypeError(), writer.write(1), 'first write() should reject') - .then(() => resolved.push('write1'))); - promises.push(writer.abort('a') - .then(() => resolved.push('abort'))); - promises.push(promise_rejects(t, new TypeError(), writer.write(2), 'second write() should reject') - .then(() => resolved.push('write2'))); - promises.push(promise_rejects(t, new TypeError(), writer.close(), 'close() should reject') - .then(() => resolved.push('close'))); - return Promise.all(promises) + const writePromise1 = writer.write(1); + const abortPromise = writer.abort('a'); + const writePromise2 = writer.write(2); + const closePromise = writer.close(); + writePromise1.catch(() => events.push('write1')); + abortPromise.then(() => events.push('abort')); + writePromise2.catch(() => events.push('write2')); + closePromise.catch(() => events.push('close')); + return Promise.all([ + promise_rejects(t, new TypeError(), writePromise1, 'first write() should reject'), + abortPromise, + promise_rejects(t, new TypeError(), writePromise2, 'second write() should reject'), + promise_rejects(t, new TypeError(), closePromise, 'close() should reject') + ]) .then(() => { - assert_array_equals(resolved, ['write2', 'close', 'write1', 'abort'], + assert_array_equals(events, ['write2', 'write1', 'abort', 'close'], 'promises should resolve in the standard order'); assert_array_equals(ws.events, ['abort', 'a'], 'underlying sink write() should not be called'); }); @@ -1159,17 +1161,19 @@ promise_test(t => { writeReject(error2); return Promise.all([ promise_rejects(t, error2, writePromise, 'write() should reject with error2'), - promise_rejects(t, error1, abortPromise, 'abort() should reject with error1') + abortPromise ]); }); -}, 'abort() should be rejected with the error passed to controller.error() during pending write()'); +}, 'abort() should succeed despite rejection from write'); promise_test(t => { let closeReject; let controller; const ws = new WritableStream({ - close(c) { + start(c) { controller = c; + }, + close() { return new Promise((resolve, reject) => { closeReject = reject; }); @@ -1183,9 +1187,115 @@ promise_test(t => { closeReject(error2); return Promise.all([ promise_rejects(t, error2, closePromise, 'close() should reject with error2'), - promise_rejects(t, error1, abortPromise, 'abort() should reject with error1') + promise_rejects(t, error2, abortPromise, 'abort() should reject with error2') ]); }); -}, 'abort() should be rejected with the error passed to controller.error() during pending close()'); +}, 'abort() should be rejected with the rejection returned from close()'); + +promise_test(t => { + let rejectWrite; + const ws = recordingWritableStream({ + write() { + return new Promise((resolve, reject) => { + rejectWrite = reject; + }); + } + }); + const writer = ws.getWriter(); + return writer.ready.then(() => { + const writePromise = writer.write('1'); + const abortPromise = writer.abort(error2); + rejectWrite(error1); + return Promise.all([ + promise_rejects(t, error1, writePromise, 'write should reject'), + abortPromise, + promise_rejects(t, new TypeError(), writer.closed, 'closed should reject with TypeError') + ]); + }).then(() => { + assert_array_equals(ws.events, ['write', '1', 'abort', error2], 'abort sink method should be called'); + }); +}, 'a rejecting sink.write() should not prevent sink.abort() from being called'); + +promise_test(() => { + const ws = recordingWritableStream({ + start() { + return Promise.reject(error1); + } + }); + return ws.abort(error2) + .then(() => { + assert_array_equals(ws.events, ['abort', error2]); + }); +}, 'when start errors after stream abort(), underlying sink abort() should be called anyway'); + +promise_test(t => { + const ws = new WritableStream(); + const abortPromise1 = ws.abort(); + const abortPromise2 = ws.abort(); + return Promise.all([ + abortPromise1, + promise_rejects(t, new TypeError(), abortPromise2, 'second abort() should reject') + ]); +}, 'when calling abort() twice on the same stream, the second call should reject'); + +promise_test(t => { + let controller; + let resolveWrite; + const ws = recordingWritableStream({ + start(c) { + controller = c; + }, + write() { + return new Promise(resolve => { + resolveWrite = resolve; + }); + } + }); + const writer = ws.getWriter(); + return writer.ready.then(() => { + const writePromise = writer.write('chunk'); + controller.error(error1); + const abortPromise = writer.abort(error2); + resolveWrite(); + return Promise.all([ + writePromise, + promise_rejects(t, error1, abortPromise, 'abort() should reject') + ]).then(() => { + assert_array_equals(ws.events, ['write', 'chunk'], 'sink abort() should not be called'); + }); + }); +}, 'sink abort() should not be called if stream was erroring due to controller.error() before abort() was called'); + +promise_test(t => { + let resolveWrite; + let size = 1; + const ws = recordingWritableStream({ + write() { + return new Promise(resolve => { + resolveWrite = resolve; + }); + } + }, { + size() { + return size; + }, + highWaterMark: 1 + }); + const writer = ws.getWriter(); + return writer.ready.then(() => { + const writePromise1 = writer.write('chunk1'); + size = NaN; + const writePromise2 = writer.write('chunk2'); + const abortPromise = writer.abort(error2); + resolveWrite(); + return Promise.all([ + writePromise1, + promise_rejects(t, new RangeError(), writePromise2, 'second write() should reject'), + promise_rejects(t, new RangeError(), abortPromise, 'abort() should reject') + ]).then(() => { + assert_array_equals(ws.events, ['write', 'chunk1'], 'sink abort() should not be called'); + }); + }); +}, 'sink abort() should not be called if stream was erroring due to bad strategy before abort() was called'); done(); diff --git a/testing/web-platform/tests/streams/writable-streams/close.js b/testing/web-platform/tests/streams/writable-streams/close.js index 536e887135a2..bf9472ef3bbd 100644 --- a/testing/web-platform/tests/streams/writable-streams/close.js +++ b/testing/web-platform/tests/streams/writable-streams/close.js @@ -26,39 +26,51 @@ promise_test(() => { }, 'fulfillment value of ws.close() call must be undefined even if the underlying sink returns a non-undefined ' + 'value'); -promise_test(t => { - const passedError = new Error('error me'); +promise_test(() => { let controller; + let resolveClose; const ws = new WritableStream({ - close(c) { + start(c) { controller = c; - return delay(50); + }, + close() { + return new Promise(resolve => { + resolveClose = resolve; + }); } }); const writer = ws.getWriter(); - return Promise.all([ - writer.close(), - delay(10).then(() => controller.error(passedError)), - promise_rejects(t, passedError, writer.closed, - 'closed promise should be rejected with the passed error'), - delay(70).then(() => promise_rejects(t, passedError, writer.closed, 'closed should stay rejected')) - ]); -}, 'when sink calls error asynchronously while closing, the stream should become errored'); + const closePromise = writer.close(); + return flushAsyncEvents().then(() => { + controller.error(error1); + return flushAsyncEvents(); + }).then(() => { + resolveClose(); + return Promise.all([ + closePromise, + writer.closed, + flushAsyncEvents().then(() => writer.closed)]); + }); +}, 'when sink calls error asynchronously while sink close is in-flight, the stream should not become errored'); -promise_test(t => { +promise_test(() => { + let controller; const passedError = new Error('error me'); const ws = new WritableStream({ - close(controller) { + start(c) { + controller = c; + }, + close() { controller.error(passedError); } }); const writer = ws.getWriter(); - return writer.close().then(() => promise_rejects(t, passedError, writer.closed, 'closed should stay rejected')); -}, 'when sink calls error synchronously while closing, the stream should become errored'); + return writer.close().then(() => writer.closed); +}, 'when sink calls error synchronously while closing, the stream should not become errored'); promise_test(t => { const ws = new WritableStream({ @@ -94,8 +106,12 @@ promise_test(() => { }, 'releaseLock on a stream with a pending write in which the stream has been errored'); promise_test(() => { + let controller; const ws = new WritableStream({ - close(controller) { + start(c) { + controller = c; + }, + close() { controller.error(error1); return new Promise(() => {}); } @@ -107,7 +123,7 @@ promise_test(() => { return delay(0).then(() => { writer.releaseLock(); }); -}, 'releaseLock on a stream with a pending close in which the stream has been errored'); +}, 'releaseLock on a stream with a pending close in which controller.error() was called'); promise_test(() => { const ws = recordingWritableStream(); @@ -293,7 +309,7 @@ promise_test(() => { }); }, 'promises must fulfill/reject in the expected order on closure'); -promise_test(t => { +promise_test(() => { const ws = new WritableStream({}); // Wait until the WritableStream starts so that the close() call gets processed. Otherwise, abort() will be @@ -316,7 +332,7 @@ promise_test(t => { events.push('closed'); }) ]).then(() => { - assert_array_equals(events, ['closePromise', 'closed', 'abortPromise'], + assert_array_equals(events, ['closePromise', 'abortPromise', 'closed'], 'promises must fulfill/reject in the expected order'); }); }); @@ -337,27 +353,54 @@ promise_test(t => { const abortPromise = writer.abort(error2); const events = []; + closePromise.catch(() => events.push('closePromise')); + abortPromise.catch(() => events.push('abortPromise')); + writer.closed.catch(() => events.push('closed')); return Promise.all([ promise_rejects(t, error1, closePromise, - 'closePromise must reject with the error returned from the sink\'s close method') - .then(() => { - events.push('closePromise'); - }), + 'closePromise must reject with the error returned from the sink\'s close method'), promise_rejects(t, error1, abortPromise, - 'abortPromise must reject with the error returned from the sink\'s close method') - .then(() => { - events.push('abortPromise'); - }), - promise_rejects(t, error1, writer.closed, - 'writer.closed must reject with the error returned from the sink\'s close method') - .then(() => { - events.push('closed'); - }) + 'abortPromise must reject with the error returned from the sink\'s close method'), + promise_rejects(t, new TypeError(), writer.closed, + 'writer.closed must reject with a TypeError indicating the stream was aborted') ]).then(() => { - assert_array_equals(events, ['closePromise', 'closed', 'abortPromise'], + assert_array_equals(events, ['closePromise', 'abortPromise', 'closed'], 'promises must fulfill/reject in the expected order'); }); }); }, 'promises must fulfill/reject in the expected order on aborted and errored closure'); +promise_test(t => { + let resolveWrite; + let controller; + const ws = new WritableStream({ + write(chunk, c) { + controller = c; + return new Promise(resolve => { + resolveWrite = resolve; + }); + } + }); + const writer = ws.getWriter(); + return writer.ready.then(() => { + const writePromise = writer.write('c'); + controller.error(error1); + const closePromise = writer.close(); + let closeRejected = false; + closePromise.catch(() => { + closeRejected = true; + }); + return flushAsyncEvents().then(() => { + assert_false(closeRejected); + resolveWrite(); + return Promise.all([ + writePromise, + promise_rejects(t, error1, closePromise, 'close() should reject') + ]).then(() => { + assert_true(closeRejected); + }); + }); + }); +}, 'close() should not reject until no sink methods are in flight'); + done(); diff --git a/testing/web-platform/tests/streams/writable-streams/constructor.js b/testing/web-platform/tests/streams/writable-streams/constructor.js index dc2bef9a1dfb..a2d986c020c6 100644 --- a/testing/web-platform/tests/streams/writable-streams/constructor.js +++ b/testing/web-platform/tests/streams/writable-streams/constructor.js @@ -37,24 +37,23 @@ promise_test(t => { return Promise.all([ writer.write('a'), - promise_rejects(t, error1, writer.closed, 'controller.error() in write() should errored the stream') + promise_rejects(t, error1, writer.closed, 'controller.error() in write() should error the stream') ]); }, 'controller argument should be passed to write method'); +// Older versions of the standard had the controller argument passed to close(). It wasn't useful, and so has been +// removed. This test remains to identify implementations that haven't been updated. promise_test(t => { const ws = new WritableStream({ - close(controller) { - controller.error(error1); + close(...args) { + t.step(() => { + assert_array_equals(args, [], 'no arguments should be passed to close'); + }); } }); - const writer = ws.getWriter(); - - return Promise.all([ - writer.close(), - promise_rejects(t, error1, writer.closed, 'controller.error() in close() should error the stream') - ]); -}, 'controller argument should be passed to close method'); + return ws.getWriter().close(); +}, 'controller argument should not be passed to close method'); promise_test(() => { const ws = new WritableStream({}, { diff --git a/testing/web-platform/tests/streams/writable-streams/error.dedicatedworker.html b/testing/web-platform/tests/streams/writable-streams/error.dedicatedworker.html new file mode 100644 index 000000000000..9e49ce90a589 --- /dev/null +++ b/testing/web-platform/tests/streams/writable-streams/error.dedicatedworker.html @@ -0,0 +1,11 @@ + + +error.js dedicated worker wrapper file + + + + + diff --git a/testing/web-platform/tests/streams/writable-streams/error.html b/testing/web-platform/tests/streams/writable-streams/error.html new file mode 100644 index 000000000000..94fa110c2d21 --- /dev/null +++ b/testing/web-platform/tests/streams/writable-streams/error.html @@ -0,0 +1,10 @@ + + +error.js browser context wrapper file + + + + + + + diff --git a/testing/web-platform/tests/streams/writable-streams/error.js b/testing/web-platform/tests/streams/writable-streams/error.js new file mode 100644 index 000000000000..511f5f7572b1 --- /dev/null +++ b/testing/web-platform/tests/streams/writable-streams/error.js @@ -0,0 +1,69 @@ +'use strict'; + +if (self.importScripts) { + self.importScripts('/resources/testharness.js'); +} + +const error1 = new Error('error1'); +error1.name = 'error1'; + +const error2 = new Error('error2'); +error2.name = 'error2'; + +promise_test(t => { + const ws = new WritableStream({ + start(controller) { + controller.error(error1); + } + }); + return promise_rejects(t, error1, ws.getWriter().closed, 'stream should be errored'); +}, 'controller.error() should error the stream'); + +test(() => { + let controller; + const ws = new WritableStream({ + start(c) { + controller = c; + } + }); + ws.abort(); + controller.error(error1); +}, 'controller.error() on erroring stream should not throw'); + +promise_test(t => { + let controller; + const ws = new WritableStream({ + start(c) { + controller = c; + } + }); + controller.error(error1); + controller.error(error2); + return promise_rejects(t, error1, ws.getWriter().closed, 'first controller.error() should win'); +}, 'surplus calls to controller.error() should be a no-op'); + +promise_test(() => { + let controller; + const ws = new WritableStream({ + start(c) { + controller = c; + } + }); + return ws.abort().then(() => { + controller.error(error1); + }); +}, 'controller.error() on errored stream should not throw'); + +promise_test(() => { + let controller; + const ws = new WritableStream({ + start(c) { + controller = c; + } + }); + return ws.getWriter().close().then(() => { + controller.error(error1); + }); +}, 'controller.error() on closed stream should not throw'); + +done(); diff --git a/testing/web-platform/tests/streams/writable-streams/error.serviceworker.https.html b/testing/web-platform/tests/streams/writable-streams/error.serviceworker.https.html new file mode 100644 index 000000000000..bec793e8a2bc --- /dev/null +++ b/testing/web-platform/tests/streams/writable-streams/error.serviceworker.https.html @@ -0,0 +1,12 @@ + + +error.js service worker wrapper file + + + + + + diff --git a/testing/web-platform/tests/streams/writable-streams/error.sharedworker.html b/testing/web-platform/tests/streams/writable-streams/error.sharedworker.html new file mode 100644 index 000000000000..84e628b22a9b --- /dev/null +++ b/testing/web-platform/tests/streams/writable-streams/error.sharedworker.html @@ -0,0 +1,11 @@ + + +error.js shared worker wrapper file + + + + + diff --git a/testing/web-platform/tests/streams/writable-streams/floating-point-total-queue-size.js b/testing/web-platform/tests/streams/writable-streams/floating-point-total-queue-size.js index 44cf5fb22fd3..932ac2715e70 100644 --- a/testing/web-platform/tests/streams/writable-streams/floating-point-total-queue-size.js +++ b/testing/web-platform/tests/streams/writable-streams/floating-point-total-queue-size.js @@ -88,3 +88,5 @@ function setupTestStream() { return ws.getWriter(); } + +done(); diff --git a/testing/web-platform/tests/streams/writable-streams/general.js b/testing/web-platform/tests/streams/writable-streams/general.js index 0e773ce2a949..1702479337aa 100644 --- a/testing/web-platform/tests/streams/writable-streams/general.js +++ b/testing/web-platform/tests/streams/writable-streams/general.js @@ -226,7 +226,7 @@ promise_test(() => { return writer2.ready; }, 'redundant releaseLock() is no-op'); -promise_test(t => { +promise_test(() => { const events = []; const ws = new WritableStream(); const writer = ws.getWriter(); diff --git a/testing/web-platform/tests/streams/writable-streams/properties.dedicatedworker.html b/testing/web-platform/tests/streams/writable-streams/properties.dedicatedworker.html new file mode 100644 index 000000000000..50d63ed0edb2 --- /dev/null +++ b/testing/web-platform/tests/streams/writable-streams/properties.dedicatedworker.html @@ -0,0 +1,11 @@ + + +properties.js dedicated worker wrapper file + + + + + diff --git a/testing/web-platform/tests/streams/writable-streams/properties.html b/testing/web-platform/tests/streams/writable-streams/properties.html new file mode 100644 index 000000000000..ad410a53c825 --- /dev/null +++ b/testing/web-platform/tests/streams/writable-streams/properties.html @@ -0,0 +1,10 @@ + + +properties.js browser context wrapper file + + + + + + + diff --git a/testing/web-platform/tests/streams/writable-streams/properties.js b/testing/web-platform/tests/streams/writable-streams/properties.js new file mode 100644 index 000000000000..6ccb1a2b286d --- /dev/null +++ b/testing/web-platform/tests/streams/writable-streams/properties.js @@ -0,0 +1,219 @@ +'use strict'; + +if (self.importScripts) { + self.importScripts('/resources/testharness.js'); +} + +// The purpose of this file is to test for objects, attributes and arguments that should not exist. +// The test cases are generated from data tables to reduce duplication. + +// Courtesy of André Bargull. Source is https://esdiscuss.org/topic/isconstructor#content-11. +function IsConstructor(o) { + try { + new new Proxy(o, { construct: () => ({}) })(); + return true; + } catch (e) { + return false; + } +} + +for (const func of ['WritableStreamDefaultController', 'WritableStreamDefaultWriter']) { + test(() => { + assert_equals(self[func], undefined, `${func} should not be defined`); + }, `${func} should not be exported on the global object`); +} + +// Now get hold of the symbols so we can test their properties. +self.WritableStreamDefaultController = (() => { + let controller; + new WritableStream({ + start(c) { + controller = c; + } + }); + return controller.constructor; +})(); +self.WritableStreamDefaultWriter = new WritableStream().getWriter().constructor; + +const expected = { + WritableStream: { + constructor: { + type: 'constructor', + length: 0 + }, + locked: { + type: 'getter' + }, + abort: { + type: 'method', + length: 1 + }, + getWriter: { + type: 'method', + length: 0 + } + }, + WritableStreamDefaultController: { + constructor: { + type: 'constructor', + length: 4 + }, + error: { + type: 'method', + length: 1 + } + }, + WritableStreamDefaultWriter: { + constructor: { + type: 'constructor', + length: 1 + }, + closed: { + type: 'getter' + }, + desiredSize: { + type: 'getter' + }, + ready: { + type: 'getter' + }, + abort: { + type: 'method', + length: 1 + }, + close: { + type: 'method', + length: 0 + }, + releaseLock: { + type: 'method', + length: 0 + }, + write: { + type: 'method', + length: 1 + } + } +}; + +for (const c in expected) { + const properties = expected[c]; + const prototype = self[c].prototype; + for (const name in properties) { + const fullName = `${c}.prototype.${name}`; + const descriptor = Object.getOwnPropertyDescriptor(prototype, name); + test(() => { + const { configurable, enumerable } = descriptor; + assert_true(configurable, `${name} should be configurable`); + assert_false(enumerable, `${name} should not be enumerable`); + }, `${fullName} should have standard properties`); + const type = properties[name].type; + switch (type) { + case 'getter': + test(() => { + const { writable, get, set } = descriptor; + assert_equals(writable, undefined, `${name} should not be a data descriptor`); + assert_equals(typeof get, 'function', `${name} should have a getter`); + assert_equals(set, undefined, `${name} should not have a setter`); + }, `${fullName} should be a getter`); + break; + + case 'constructor': + case 'method': + test(() => { + assert_true(descriptor.writable, `${name} should be writable`); + assert_equals(typeof prototype[name], 'function', `${name} should be a function`); + assert_equals(prototype[name].length, properties[name].length, + `${name} should take ${properties[name].length} arguments`); + if (type === 'constructor') { + assert_true(IsConstructor(prototype[name]), `${name} should be a constructor`); + } else { + assert_false(IsConstructor(prototype[name]), `${name} should not be a constructor`); + } + }, `${fullName} should be a ${type}`); + break; + } + } + test(() => { + const expectedPropertyNames = Object.keys(properties).sort(); + const actualPropertyNames = Object.getOwnPropertyNames(prototype).sort(); + assert_array_equals(actualPropertyNames, expectedPropertyNames, + `${c} properties should match expected properties`); + }, `${c}.prototype should have exactly the expected properties`); +} + +const sinkMethods = { + start: { + length: 1, + trigger: () => {} + }, + write: { + length: 2, + trigger: writer => writer.write() + }, + close: { + length: 0, + trigger: writer => writer.close() + }, + abort: { + length: 1, + trigger: writer => writer.abort() + } +}; + +for (const method in sinkMethods) { + const { length, trigger } = sinkMethods[method]; + + // Some semantic tests of how sink methods are called can be found in general.js, as well as in the test files + // specific to each method. + promise_test(() => { + let argCount; + const ws = new WritableStream({ + [method](...args) { + argCount = args.length; + } + }); + return Promise.resolve(trigger(ws.getWriter())).then(() => { + assert_equals(argCount, length, `${method} should be called with ${length} arguments`); + }); + }, `sink method ${method} should be called with the right number of arguments`); + + promise_test(() => { + let methodWasCalled = false; + function Sink() {} + Sink.prototype = { + [method]() { + methodWasCalled = true; + } + }; + const ws = new WritableStream(new Sink()); + return Promise.resolve(trigger(ws.getWriter())).then(() => { + assert_true(methodWasCalled, `${method} should be called`); + }); + }, `sink method ${method} should be called even when it's located on the prototype chain`); + + if (method !== 'start') { + promise_test(t => { + const unreachedTraps = ['getPrototypeOf', 'setPrototypeOf', 'isExtensible', 'preventExtensions', + 'getOwnPropertyDescriptor', 'defineProperty', 'has', 'set', 'deleteProperty', 'ownKeys', + 'apply', 'construct']; + const handler = { + get: t.step_func((target, property) => { + if (property === 'type') { + return undefined; + } + assert_in_array(property, ['start', method], `only start() and ${method}() should be called`); + return () => Promise.resolve(); + }) + }; + for (const trap of unreachedTraps) { + handler[trap] = t.unreached_func(`${trap} should not be trapped`); + } + const sink = new Proxy({}, handler); + const ws = new WritableStream(sink); + return trigger(ws.getWriter()); + }, `unexpected properties should not be accessed when calling sink method ${method}`); + } +} + +done(); diff --git a/testing/web-platform/tests/streams/writable-streams/properties.serviceworker.https.html b/testing/web-platform/tests/streams/writable-streams/properties.serviceworker.https.html new file mode 100644 index 000000000000..ba5c5135f2f7 --- /dev/null +++ b/testing/web-platform/tests/streams/writable-streams/properties.serviceworker.https.html @@ -0,0 +1,12 @@ + + +properties.js service worker wrapper file + + + + + + diff --git a/testing/web-platform/tests/streams/writable-streams/properties.sharedworker.html b/testing/web-platform/tests/streams/writable-streams/properties.sharedworker.html new file mode 100644 index 000000000000..42fb3e5ebc0a --- /dev/null +++ b/testing/web-platform/tests/streams/writable-streams/properties.sharedworker.html @@ -0,0 +1,11 @@ + + +properties.js shared worker wrapper file + + + + + diff --git a/testing/web-platform/tests/streams/writable-streams/start.js b/testing/web-platform/tests/streams/writable-streams/start.js index ee6dd8d7298c..0122799b6697 100644 --- a/testing/web-platform/tests/streams/writable-streams/start.js +++ b/testing/web-platform/tests/streams/writable-streams/start.js @@ -132,12 +132,12 @@ promise_test(t => { const writePromise = writer.write('a'); const closePromise = writer.close(); controller.error(error1); + resolveStart(); return Promise.all([ promise_rejects(t, error1, writePromise, 'write() should fail'), promise_rejects(t, error1, closePromise, 'close() should fail') ]).then(() => { assert_array_equals(ws.events, [], 'sink write() and close() should not have been called'); - resolveStart(); }); }, 'controller.error() during async start should cause existing writes to fail'); diff --git a/testing/web-platform/tests/svg/interfaces.html b/testing/web-platform/tests/svg/interfaces.html index 737e0d1c4e6d..36132e2dcf1d 100644 --- a/testing/web-platform/tests/svg/interfaces.html +++ b/testing/web-platform/tests/svg/interfaces.html @@ -1,5 +1,6 @@ SVG interface tests +
diff --git a/testing/web-platform/tests/tools/.gitmodules b/testing/web-platform/tests/tools/.gitmodules index 12cee69142f1..021adfc6de44 100644 --- a/testing/web-platform/tests/tools/.gitmodules +++ b/testing/web-platform/tests/tools/.gitmodules @@ -1,7 +1,3 @@ -[submodule "tools/wptserve"] - path = wptserve - url = https://github.com/w3c/wptserve.git - ignore = dirty [submodule "tools/pywebsocket"] path = pywebsocket url = https://github.com/w3c/pywebsocket.git @@ -15,6 +11,3 @@ [submodule "pytest"] path = pytest url = https://github.com/pytest-dev/pytest.git -[submodule "webdriver"] - path = webdriver - url = https://github.com/w3c/wdclient.git diff --git a/testing/web-platform/tests/tools/.travis.yml b/testing/web-platform/tests/tools/.travis.yml deleted file mode 100644 index 37319bf0f5ea..000000000000 --- a/testing/web-platform/tests/tools/.travis.yml +++ /dev/null @@ -1,37 +0,0 @@ -language: python - -sudo: false - -cache: - directories: - - $HOME/.cache/pip - -matrix: - include: - - python: 2.7 - env: TOXENV=py27 HYPOTHESIS_PROFILE=ci - - python: 3.5 - env: TOXENV=py35 HYPOTHESIS_PROFILE=ci - - python: 3.6 - env: TOXENV=py36 HYPOTHESIS_PROFILE=ci - - python: pypy - env: TOXENV=pypy HYPOTHESIS_PROFILE=ci_pypy - -# An ugly hack needed to make py.test believe our top level can be -# imported (on Travis CI, we end up in a wpt-tools directory, and of -# course you cannot import a name including a hyphen in Python, so it -# ignores the fact we have a __init__.py at the top level). -before_install: - - mv `pwd` /tmp/tools - - cd /tmp/tools - - export TRAVIS_BUILD_DIR=/tmp/tools - -install: - - pip install -U tox codecov - -script: - - tox - -after_success: - - coverage combine - - codecov diff --git a/testing/web-platform/tests/tools/lint/lint.py b/testing/web-platform/tests/tools/lint/lint.py index e1bbd606eac9..00fa6a9f011c 100644 --- a/testing/web-platform/tests/tools/lint/lint.py +++ b/testing/web-platform/tests/tools/lint/lint.py @@ -21,7 +21,28 @@ from six import binary_type, iteritems, itervalues from six.moves import range from six.moves.urllib.parse import urlsplit, urljoin -here = os.path.abspath(os.path.split(__file__)[0]) +import logging + +logger = None + +def setup_logging(prefix=False): + global logger + if logger is None: + logger = logging.getLogger(os.path.basename(os.path.splitext(__file__)[0])) + handler = logging.StreamHandler(sys.stdout) + logger.addHandler(handler) + if prefix: + format = logging.BASIC_FORMAT + else: + format = "%(message)s" + formatter = logging.Formatter(format) + for handler in logger.handlers: + handler.setFormatter(formatter) + logger.setLevel(logging.DEBUG) + + +setup_logging() + ERROR_MSG = """You must fix all errors; for details on how to fix them, see https://github.com/w3c/web-platform-tests/blob/master/docs/lint-tool.md @@ -613,23 +634,40 @@ def output_errors_text(errors): pos_string = path if line_number: pos_string += ":%s" % line_number - print("%s: %s (%s)" % (pos_string, description, error_type)) + logger.error("%s: %s (%s)" % (pos_string, description, error_type)) + +def output_errors_markdown(errors): + if not errors: + return + heading = """Got lint errors: + +| Error Type | Position | Message | +|------------|----------|---------|""" + for line in heading.split("\n"): + logger.error(line) + for error_type, description, path, line_number in errors: + pos_string = path + if line_number: + pos_string += ":%s" % line_number + logger.error("%s | %s | %s |" % (error_type, pos_string, description)) def output_errors_json(errors): for error_type, error, path, line_number in errors: print(json.dumps({"path": path, "lineno": line_number, "rule": error_type, "message": error})) + def output_error_count(error_count): if not error_count: return by_type = " ".join("%s: %d" % item for item in error_count.items()) count = sum(error_count.values()) + logger.info("") if count == 1: - print("There was 1 error (%s)" % (by_type,)) + logger.info("There was 1 error (%s)" % (by_type,)) else: - print("There were %d errors (%s)" % (count, by_type)) + logger.info("There were %d errors (%s)" % (count, by_type)) def parse_args(): parser = argparse.ArgumentParser() @@ -637,26 +675,39 @@ def parse_args(): help="List of paths to lint") parser.add_argument("--json", action="store_true", help="Output machine-readable JSON format") + parser.add_argument("--markdown", action="store_true", + help="Output markdown") parser.add_argument("--css-mode", action="store_true", help="Run CSS testsuite specific lints") return parser.parse_args() -def main(force_css_mode=False): - args = parse_args() - paths = list(args.paths if args.paths else all_filesystem_paths(repo_root)) - return lint(repo_root, paths, args.json, force_css_mode or args.css_mode) -def lint(repo_root, paths, output_json, css_mode): +def main(**kwargs): + if kwargs.get("json") and kwargs.get("markdown"): + logger.critical("Cannot specify --json and --markdown") + sys.exit(2) + + output_format = {(True, False): "json", + (False, True): "markdown", + (False, False): "normal"}[(kwargs.get("json", False), + kwargs.get("markdown", False))] + + paths = list(kwargs.get("paths") if kwargs.get("paths") else all_filesystem_paths(repo_root)) + if output_format == "markdown": + setup_logging(True) + return lint(repo_root, paths, output_format, kwargs.get("css_mode", False)) + + +def lint(repo_root, paths, output_format, css_mode): error_count = defaultdict(int) last = None with open(os.path.join(repo_root, "lint.whitelist")) as f: whitelist, ignored_files = parse_whitelist(f) - if output_json: - output_errors = output_errors_json - else: - output_errors = output_errors_text + output_errors = {"json": output_errors_json, + "markdown": output_errors_markdown, + "normal": output_errors_text}[output_format] def process_errors(errors): """ @@ -699,10 +750,11 @@ def lint(repo_root, paths, output_json, css_mode): errors = check_all_paths(repo_root, paths, css_mode) last = process_errors(errors) or last - if not output_json: + if output_format in ("normal", "markdown"): output_error_count(error_count) if error_count: - print(ERROR_MSG % (last[0], last[1], last[0], last[1])) + for line in (ERROR_MSG % (last[0], last[1], last[0], last[1])).split("\n"): + logger.info(line) return sum(itervalues(error_count)) path_lints = [check_path_length, check_worker_collision] @@ -710,6 +762,7 @@ all_paths_lints = [check_css_globally_unique] file_lints = [check_regexp_line, check_parsed, check_python_ast, check_script_metadata] if __name__ == "__main__": - error_count = main() + args = parse_args() + error_count = main(**vars(args)) if error_count > 0: sys.exit(1) diff --git a/testing/web-platform/tests/tools/lint/tests/test_lint.py b/testing/web-platform/tests/tools/lint/tests/test_lint.py index e8943d7a3c5c..2b41701799ba 100644 --- a/testing/web-platform/tests/tools/lint/tests/test_lint.py +++ b/testing/web-platform/tests/tools/lint/tests/test_lint.py @@ -9,11 +9,10 @@ import six from ...localpaths import repo_root from .. import lint as lint_mod -from ..lint import filter_whitelist_errors, parse_whitelist, lint +from ..lint import filter_whitelist_errors, parse_whitelist, lint, parse_args _dummy_repo = os.path.join(os.path.dirname(__file__), "dummy") - def _mock_lint(name, **kwargs): wrapped = getattr(lint_mod, name) return mock.patch(lint_mod.__name__ + "." + name, wraps=wrapped, **kwargs) @@ -108,313 +107,264 @@ CR AT EOL, INDENT TABS: html/test2.js: 42 assert ignored == expected_ignored -def test_lint_no_files(capsys): - rv = lint(_dummy_repo, [], False, False) +def test_lint_no_files(caplog): + rv = lint(_dummy_repo, [], "normal", False) assert rv == 0 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_lint_ignored_file(capsys): +def test_lint_ignored_file(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["broken_ignored.html"], False, False) + rv = lint(_dummy_repo, ["broken_ignored.html"], "normal", False) assert rv == 0 assert not mocked_check_path.called assert not mocked_check_file_contents.called - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_lint_not_existing_file(capsys): +def test_lint_not_existing_file(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: # really long path-linted filename name = "a" * 256 + ".html" - rv = lint(_dummy_repo, [name], False, False) + rv = lint(_dummy_repo, [name], "normal", False) assert rv == 0 assert not mocked_check_path.called assert not mocked_check_file_contents.called - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_lint_passing(capsys): +def test_lint_passing(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["okay.html"], False, False) + rv = lint(_dummy_repo, ["okay.html"], "normal", False) assert rv == 0 assert mocked_check_path.call_count == 1 assert mocked_check_file_contents.call_count == 1 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_lint_failing(capsys): +def test_lint_failing(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["broken.html"], False, False) + rv = lint(_dummy_repo, ["broken.html"], "normal", False) assert rv == 1 assert mocked_check_path.call_count == 1 assert mocked_check_file_contents.call_count == 1 - out, err = capsys.readouterr() - assert "TRAILING WHITESPACE" in out - assert "broken.html:1" in out - assert err == "" + assert "TRAILING WHITESPACE" in caplog.text + assert "broken.html:1" in caplog.text -def test_ref_existent_relative(capsys): +def test_ref_existent_relative(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["ref/existent_relative.html"], False, False) + rv = lint(_dummy_repo, ["ref/existent_relative.html"], "normal", False) assert rv == 0 assert mocked_check_path.call_count == 1 assert mocked_check_file_contents.call_count == 1 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_ref_existent_root_relative(capsys): +def test_ref_existent_root_relative(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["ref/existent_root_relative.html"], False, False) + rv = lint(_dummy_repo, ["ref/existent_root_relative.html"], "normal", False) assert rv == 0 assert mocked_check_path.call_count == 1 assert mocked_check_file_contents.call_count == 1 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_ref_non_existent_relative(capsys): +def test_ref_non_existent_relative(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["ref/non_existent_relative.html"], False, False) + rv = lint(_dummy_repo, ["ref/non_existent_relative.html"], "normal", False) assert rv == 1 assert mocked_check_path.call_count == 1 assert mocked_check_file_contents.call_count == 1 - out, err = capsys.readouterr() - assert "NON-EXISTENT-REF" in out - assert "ref/non_existent_relative.html" in out - assert "non_existent_file.html" in out - assert err == "" + assert "NON-EXISTENT-REF" in caplog.text + assert "ref/non_existent_relative.html" in caplog.text + assert "non_existent_file.html" in caplog.text -def test_ref_non_existent_root_relative(capsys): +def test_ref_non_existent_root_relative(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["ref/non_existent_root_relative.html"], False, False) + rv = lint(_dummy_repo, ["ref/non_existent_root_relative.html"], "normal", False) assert rv == 1 assert mocked_check_path.call_count == 1 assert mocked_check_file_contents.call_count == 1 - out, err = capsys.readouterr() - assert "NON-EXISTENT-REF" in out - assert "ref/non_existent_root_relative.html" in out - assert "/non_existent_file.html" in out - assert err == "" + assert "NON-EXISTENT-REF" in caplog.text + assert "ref/non_existent_root_relative.html" in caplog.text + assert "/non_existent_file.html" in caplog.text -def test_ref_absolute_url(capsys): + +def test_ref_absolute_url(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["ref/absolute.html"], False, False) + rv = lint(_dummy_repo, ["ref/absolute.html"], "normal", False) assert rv == 1 assert mocked_check_path.call_count == 1 assert mocked_check_file_contents.call_count == 1 - out, err = capsys.readouterr() - assert "ABSOLUTE-URL-REF" in out - assert "http://example.com/reference.html" in out - assert "ref/absolute.html" in out - assert err == "" + assert "ABSOLUTE-URL-REF" in caplog.text + assert "http://example.com/reference.html" in caplog.text + assert "ref/absolute.html" in caplog.text -def test_ref_same_file_empty(capsys): +def test_ref_same_file_empty(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["ref/same_file_empty.html"], False, False) + rv = lint(_dummy_repo, ["ref/same_file_empty.html"], "normal", False) assert rv == 1 assert mocked_check_path.call_count == 1 assert mocked_check_file_contents.call_count == 1 - out, err = capsys.readouterr() - assert "SAME-FILE-REF" in out - assert "same_file_empty.html" in out - assert err == "" + assert "SAME-FILE-REF" in caplog.text + assert "same_file_empty.html" in caplog.text -def test_ref_same_file_path(capsys): +def test_ref_same_file_path(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["ref/same_file_path.html"], False, False) + rv = lint(_dummy_repo, ["ref/same_file_path.html"], "normal", False) assert rv == 1 assert mocked_check_path.call_count == 1 assert mocked_check_file_contents.call_count == 1 - out, err = capsys.readouterr() - assert "SAME-FILE-REF" in out - assert "same_file_path.html" in out - assert err == "" + assert "SAME-FILE-REF" in caplog.text + assert "same_file_path.html" in caplog.text -def test_lint_passing_and_failing(capsys): +def test_lint_passing_and_failing(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["broken.html", "okay.html"], False, False) + rv = lint(_dummy_repo, ["broken.html", "okay.html"], "normal", False) assert rv == 1 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert "TRAILING WHITESPACE" in out - assert "broken.html:1" in out - assert "okay.html" not in out - assert err == "" + assert "TRAILING WHITESPACE" in caplog.text + assert "broken.html:1" in caplog.text + assert "okay.html" not in caplog.text -def test_check_css_globally_unique_identical_test(capsys): +def test_check_css_globally_unique_identical_test(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/match/a.html", "css-unique/a.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/match/a.html", "css-unique/a.html"], "normal", True) assert rv == 0 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_check_css_globally_unique_different_test(capsys): +def test_check_css_globally_unique_different_test(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/not-match/a.html", "css-unique/a.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/not-match/a.html", "css-unique/a.html"], "normal", True) assert rv == 2 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert "CSS-COLLIDING-TEST-NAME" in out - assert err == "" + assert "CSS-COLLIDING-TEST-NAME" in caplog.text -def test_check_css_globally_unique_different_spec_test(capsys): +def test_check_css_globally_unique_different_spec_test(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/selectors/a.html", "css-unique/a.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/selectors/a.html", "css-unique/a.html"], "normal", True) assert rv == 0 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_check_css_globally_unique_support_ignored(capsys): +def test_check_css_globally_unique_support_ignored(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/support/a.html", "css-unique/support/tools/a.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/support/a.html", "css-unique/support/tools/a.html"], "normal", True) assert rv == 0 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_check_css_globally_unique_support_identical(capsys): +def test_check_css_globally_unique_support_identical(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/support/a.html", "css-unique/match/support/a.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/support/a.html", "css-unique/match/support/a.html"], "normal", True) assert rv == 0 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_check_css_globally_unique_support_different(capsys): +def test_check_css_globally_unique_support_different(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/not-match/support/a.html", "css-unique/support/a.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/not-match/support/a.html", "css-unique/support/a.html"], "normal", True) assert rv == 2 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert "CSS-COLLIDING-SUPPORT-NAME" in out - assert err == "" + assert "CSS-COLLIDING-SUPPORT-NAME" in caplog.text -def test_check_css_globally_unique_test_support(capsys): +def test_check_css_globally_unique_test_support(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/support/a.html", "css-unique/a.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/support/a.html", "css-unique/a.html"], "normal", True) assert rv == 0 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_check_css_globally_unique_ref_identical(capsys): +def test_check_css_globally_unique_ref_identical(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/a-ref.html", "css-unique/match/a-ref.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/a-ref.html", "css-unique/match/a-ref.html"], "normal", True) assert rv == 0 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_check_css_globally_unique_ref_different(capsys): +def test_check_css_globally_unique_ref_different(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/not-match/a-ref.html", "css-unique/a-ref.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/not-match/a-ref.html", "css-unique/a-ref.html"], "normal", True) assert rv == 2 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert "CSS-COLLIDING-REF-NAME" in out - assert err == "" + assert "CSS-COLLIDING-REF-NAME" in caplog.text -def test_check_css_globally_unique_test_ref(capsys): +def test_check_css_globally_unique_test_ref(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/a-ref.html", "css-unique/a.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/a-ref.html", "css-unique/a.html"], "normal", True) assert rv == 0 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_check_css_globally_unique_ignored(capsys): +def test_check_css_globally_unique_ignored(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/tools/a.html", "css-unique/not-match/tools/a.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/tools/a.html", "css-unique/not-match/tools/a.html"], "normal", True) assert rv == 0 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" -def test_check_css_globally_unique_ignored_dir(capsys): +def test_check_css_globally_unique_ignored_dir(caplog): with _mock_lint("check_path") as mocked_check_path: with _mock_lint("check_file_contents") as mocked_check_file_contents: - rv = lint(_dummy_repo, ["css-unique/support/a.html", "css/work-in-progress/foo/support/a.html"], False, True) + rv = lint(_dummy_repo, ["css-unique/support/a.html", "css/work-in-progress/foo/support/a.html"], "normal", True) assert rv == 0 assert mocked_check_path.call_count == 2 assert mocked_check_file_contents.call_count == 2 - out, err = capsys.readouterr() - assert out == "" - assert err == "" + assert caplog.text == "" def test_all_filesystem_paths(): @@ -439,8 +389,8 @@ def test_main_with_args(): try: sys.argv = ['./lint', 'a', 'b', 'c'] with _mock_lint('lint', return_value=True) as m: - lint_mod.main() - m.assert_called_once_with(repo_root, ['a', 'b', 'c'], False, False) + lint_mod.main(**vars(parse_args())) + m.assert_called_once_with(repo_root, ['a', 'b', 'c'], "normal", False) finally: sys.argv = orig_argv @@ -451,7 +401,7 @@ def test_main_no_args(): sys.argv = ['./lint'] with _mock_lint('lint', return_value=True) as m: with _mock_lint('all_filesystem_paths', return_value=['foo', 'bar']) as m2: - lint_mod.main() - m.assert_called_once_with(repo_root, ['foo', 'bar'], False, False) + lint_mod.main(**vars(parse_args())) + m.assert_called_once_with(repo_root, ['foo', 'bar'], "normal", False) finally: sys.argv = orig_argv diff --git a/testing/web-platform/tests/tools/pytest.ini b/testing/web-platform/tests/tools/pytest.ini index 1fb328e1f977..8cc3d6f22395 100644 --- a/testing/web-platform/tests/tools/pytest.ini +++ b/testing/web-platform/tests/tools/pytest.ini @@ -1,2 +1,2 @@ [pytest] -norecursedirs = .* {arch} *.egg html5lib py pytest pywebsocket six webdriver wptserve +norecursedirs = .* {arch} *.egg html5lib py pytest pywebsocket six wptrunner diff --git a/testing/web-platform/tests/tools/tox.ini b/testing/web-platform/tests/tools/tox.ini index 4acefc401c7a..1ea30a5da186 100644 --- a/testing/web-platform/tests/tools/tox.ini +++ b/testing/web-platform/tests/tools/tox.ini @@ -6,12 +6,13 @@ skipsdist=True deps = flake8 pytest - coverage + pytest-cov mock hypothesis + pytest-catchlog commands = - coverage run -m pytest + pytest --cov flake8 passenv = @@ -20,4 +21,4 @@ passenv = [flake8] ignore = E128,E129,E221,E226,E231,E251,E265,E302,E303,E305,E402,E901,F401,F821,F841 max-line-length = 141 -exclude = .tox,html5lib,py,pytest,pywebsocket,six,webdriver,wptserve +exclude = .tox,html5lib,py,pytest,pywebsocket,six,_venv,webencodings,wptserve/docs,wptserve/tests/functional/docroot/,wptrunner diff --git a/testing/web-platform/tests/tools/webdriver/COPYING b/testing/web-platform/tests/tools/webdriver/COPYING deleted file mode 100644 index 14e2f777f6c3..000000000000 --- a/testing/web-platform/tests/tools/webdriver/COPYING +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/testing/web-platform/tests/tools/webdriver/setup.py b/testing/web-platform/tests/tools/webdriver/setup.py index 720fcf05cd26..c473961cb64f 100644 --- a/testing/web-platform/tests/tools/webdriver/setup.py +++ b/testing/web-platform/tests/tools/webdriver/setup.py @@ -1,7 +1,3 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this file, -# You can obtain one at http://mozilla.org/MPL/2.0/. - from setuptools import setup, find_packages setup(name="webdriver", @@ -10,7 +6,7 @@ setup(name="webdriver", "the W3C browser automation specification.", author="Mozilla Engineering Productivity", author_email="tools@lists.mozilla.org", - license="MPL 2.0", + license="BSD", packages=find_packages(), classifiers=["Development Status :: 4 - Beta", "Intended Audience :: Developers", diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/__init__.py b/testing/web-platform/tests/tools/webdriver/webdriver/__init__.py index c827f59f138a..30243f7205d7 100644 --- a/testing/web-platform/tests/tools/webdriver/webdriver/__init__.py +++ b/testing/web-platform/tests/tools/webdriver/webdriver/__init__.py @@ -1,7 +1,3 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this file, -# You can obtain one at http://mozilla.org/MPL/2.0/. - from client import Cookies, Element, Find, Session, Timeouts, Window from error import ( ElementNotSelectableException, diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/client.py b/testing/web-platform/tests/tools/webdriver/webdriver/client.py index dc8679a547dc..b90a58c9d73d 100644 --- a/testing/web-platform/tests/tools/webdriver/webdriver/client.py +++ b/testing/web-platform/tests/tools/webdriver/webdriver/client.py @@ -1,7 +1,3 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - import urlparse import error @@ -20,7 +16,7 @@ def command(func): if session.session_id is None: session.start() - assert session.session_id != None + assert session.session_id is not None return func(self, *args, **kwargs) @@ -89,26 +85,30 @@ class ActionSequence(object): .key_up("a") \ .perform() """ - def __init__(self, session, action_type, input_id): + def __init__(self, session, action_type, input_id, pointer_params=None): """Represents a sequence of actions of one type for one input source. :param session: WebDriver session. :param action_type: Action type; may be "none", "key", or "pointer". :param input_id: ID of input source. + :param pointer_params: Optional dictionary of pointer parameters. """ self.session = session - # TODO take advantage of remote end generating uuid self._id = input_id self._type = action_type self._actions = [] + self._pointer_params = pointer_params @property def dict(self): - return { - "type": self._type, - "id": self._id, - "actions": self._actions, + d = { + "type": self._type, + "id": self._id, + "actions": self._actions, } + if self._pointer_params is not None: + d["parameters"] = self._pointer_params + return d @command def perform(self): @@ -232,6 +232,7 @@ class Actions(object): """ return ActionSequence(self.session, *args, **kwargs) + class Window(object): def __init__(self, session): self.session = session @@ -244,7 +245,8 @@ class Window(object): @size.setter @command - def size(self, (width, height)): + def size(self, data): + width, height = data body = {"width": width, "height": height} self.session.send_session_command("POST", "window/rect", body) @@ -256,7 +258,8 @@ class Window(object): @position.setter @command - def position(self, (x, y)): + def position(self, data): + data = x, y body = {"x": x, "y": y} self.session.send_session_command("POST", "window/rect", body) @@ -333,12 +336,11 @@ class UserPrompt(object): class Session(object): - def __init__(self, host, port, url_prefix="/", desired_capabilities=None, - required_capabilities=None, extension=None, timeout=None): + def __init__(self, host, port, url_prefix="/", capabilities=None, + timeout=None, extension=None): self.transport = transport.HTTPWireProtocol( host, port, url_prefix, timeout=timeout) - self.desired_capabilities = desired_capabilities - self.required_capabilities = required_capabilities + self.capabilities = capabilities self.session_id = None self.timeouts = None self.window = None @@ -369,13 +371,8 @@ class Session(object): body = {} - caps = {} - if self.desired_capabilities is not None: - caps["desiredCapabilities"] = self.desired_capabilities - if self.required_capabilities is not None: - caps["requiredCapabilities"] = self.required_capabilities - #body["capabilities"] = caps - body = caps + if self.capabilities is not None: + body["capabilities"] = self.capabilities value = self.send_command("POST", "session", body=body) self.session_id = value["sessionId"] @@ -618,12 +615,8 @@ class Element(object): self.send_element_command("POST", self.url("clear"), {}) @command - def send_keys(self, keys): - if isinstance(keys, (str, unicode)): - keys = [char for char in keys] - - body = {"value": keys} - return self.send_element_command("POST", "value", body) + def send_keys(self, text): + return self.send_element_command("POST", "value", {"text": text}) @property @command diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/error.py b/testing/web-platform/tests/tools/webdriver/webdriver/error.py index a6a703d674bb..0530ff9c5da0 100644 --- a/testing/web-platform/tests/tools/webdriver/webdriver/error.py +++ b/testing/web-platform/tests/tools/webdriver/webdriver/error.py @@ -1,8 +1,3 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this file, -# You can obtain one at http://mozilla.org/MPL/2.0/. - - import collections diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/servo.py b/testing/web-platform/tests/tools/webdriver/webdriver/servo.py index fd1539f7bc72..2e0b722ababe 100644 --- a/testing/web-platform/tests/tools/webdriver/webdriver/servo.py +++ b/testing/web-platform/tests/tools/webdriver/webdriver/servo.py @@ -1,7 +1,3 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this file, -# You can obtain one at http://mozilla.org/MPL/2.0/. - class ServoExtensionCommands(object): def __init__(self, session): self.session = session diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/transport.py b/testing/web-platform/tests/tools/webdriver/webdriver/transport.py index 0b025c5a12bc..a2412643e04f 100644 --- a/testing/web-platform/tests/tools/webdriver/webdriver/transport.py +++ b/testing/web-platform/tests/tools/webdriver/webdriver/transport.py @@ -1,12 +1,7 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this file, -# You can obtain one at http://mozilla.org/MPL/2.0/. - import httplib import json import urlparse - class Response(object): """Describes an HTTP response received from a remote en"Describes an HTTP response received from a remote end whose body has been read and parsed as diff --git a/testing/web-platform/tests/tools/wptrunner/.gitignore b/testing/web-platform/tests/tools/wptrunner/.gitignore new file mode 100644 index 000000000000..495616ef1d19 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/.gitignore @@ -0,0 +1,8 @@ +*.py[co] +*~ +*# +\#* +_virtualenv +test/test.cfg +test/metadata/MANIFEST.json +wptrunner.egg-info diff --git a/testing/web-platform/tests/tools/LICENSE b/testing/web-platform/tests/tools/wptrunner/LICENSE similarity index 100% rename from testing/web-platform/tests/tools/LICENSE rename to testing/web-platform/tests/tools/wptrunner/LICENSE diff --git a/testing/web-platform/tests/tools/wptrunner/MANIFEST.in b/testing/web-platform/tests/tools/wptrunner/MANIFEST.in new file mode 100644 index 000000000000..0c5e38bf2654 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/MANIFEST.in @@ -0,0 +1,17 @@ +exclude MANIFEST.in +include requirements.txt +include wptrunner/browsers/b2g_setup/* +include wptrunner.default.ini +include wptrunner/testharness_runner.html +include wptrunner/testharnessreport.js +include wptrunner/testharnessreport-servo.js +include wptrunner/testharnessreport-servodriver.js +include wptrunner/executors/testharness_marionette.js +include wptrunner/executors/testharness_servodriver.js +include wptrunner/executors/testharness_webdriver.js +include wptrunner/executors/reftest.js +include wptrunner/executors/reftest-wait.js +include wptrunner/executors/reftest-wait_servodriver.js +include wptrunner/executors/reftest-wait_webdriver.js +include wptrunner/config.json +include wptrunner/browsers/server-locations.txt \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/README.rst b/testing/web-platform/tests/tools/wptrunner/README.rst new file mode 100644 index 000000000000..fc650eec45ac --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/README.rst @@ -0,0 +1,242 @@ +wptrunner: A web-platform-tests harness +======================================= + +wptrunner is a harness for running the W3C `web-platform-tests testsuite`_. + +.. contents:: + +Installation +~~~~~~~~~~~~ + +wptrunner is expected to be installed into a virtualenv using pip. For +development, it can be installed using the `-e` option:: + + pip install -e ./ + +Running the Tests +~~~~~~~~~~~~~~~~~ + +After installation, the command ``wptrunner`` should be available to run +the tests. + +The ``wptrunner`` command takes multiple options, of which the +following are most significant: + +``--product`` (defaults to `firefox`) + The product to test against: `b2g`, `chrome`, `firefox`, or `servo`. + +``--binary`` (required if product is `firefox` or `servo`) + The path to a binary file for the product (browser) to test against. + +``--webdriver-binary`` (required if product is `chrome`) + The path to a `driver` binary; e.g., a `chromedriver` binary. + +``--certutil-binary`` (required if product is `firefox` [#]_) + The path to a `certutil` binary (for tests that must be run over https). + +``--metadata`` (required) + The path to a directory containing test metadata. [#]_ + +``--tests`` (required) + The path to a directory containing a web-platform-tests checkout. + +``--prefs-root`` (required only when testing a Firefox binary) + The path to a directory containing Firefox test-harness preferences. [#]_ + +``--config`` (should default to `wptrunner.default.ini`) + The path to the config (ini) file. + +.. [#] The ``--certutil-binary`` option is required when the product is + ``firefox`` unless ``--ssl-type=none`` is specified. + +.. [#] The ``--metadata`` path is to a directory that contains: + + * a ``MANIFEST.json`` file (instructions on generating this file are + available in the `detailed documentation + `_); + and + * (optionally) any expectation files (see below) + +.. [#] Example ``--prefs-root`` value: ``~/mozilla-central/testing/profiles``. + +There are also a variety of other options available; use ``--help`` to +list them. + +------------------------------- +Example: How to start wptrunner +------------------------------- + +To test a Firefox Nightly build in an OS X environment, you might start +wptrunner using something similar to the following example:: + + wptrunner --metadata=~/web-platform-tests/ --tests=~/web-platform-tests/ \ + --binary=~/mozilla-central/obj-x86_64-apple-darwin14.3.0/dist/Nightly.app/Contents/MacOS/firefox \ + --certutil-binary=~/mozilla-central/obj-x86_64-apple-darwin14.3.0/security/nss/cmd/certutil/certutil \ + --prefs-root=~/mozilla-central/testing/profiles + +And to test a Chromium build in an OS X environment, you might start +wptrunner using something similar to the following example:: + + wptrunner --metadata=~/web-platform-tests/ --tests=~/web-platform-tests/ \ + --binary=~/chromium/src/out/Release/Chromium.app/Contents/MacOS/Chromium \ + --webdriver-binary=/usr/local/bin/chromedriver --product=chrome + +------------------------------------- +Example: How to run a subset of tests +------------------------------------- + +To restrict a test run just to tests in a particular web-platform-tests +subdirectory, specify the directory name in the positional arguments after +the options; for example, run just the tests in the `dom` subdirectory:: + + wptrunner --metadata=~/web-platform-tests/ --tests=~/web-platform-tests/ \ + --binary=/path/to/firefox --certutil-binary=/path/to/certutil \ + --prefs-root=/path/to/testing/profiles \ + dom + +Output +~~~~~~ + +By default wptrunner just dumps its entire output as raw JSON messages +to stdout. This is convenient for piping into other tools, but not ideal +for humans reading the output. + +As an alternative, you can use the ``--log-mach`` option, which provides +output in a reasonable format for humans. The option requires a value: +either the path for a file to write the `mach`-formatted output to, or +"`-`" (a hyphen) to write the `mach`-formatted output to stdout. + +When using ``--log-mach``, output of the full raw JSON log is still +available, from the ``--log-raw`` option. So to output the full raw JSON +log to a file and a human-readable summary to stdout, you might start +wptrunner using something similar to the following example:: + + wptrunner --metadata=~/web-platform-tests/ --tests=~/web-platform-tests/ \ + --binary=/path/to/firefox --certutil-binary=/path/to/certutil \ + --prefs-root=/path/to/testing/profiles \ + --log-raw=output.log --log-mach=- + +Expectation Data +~~~~~~~~~~~~~~~~ + +wptrunner is designed to be used in an environment where it is not +just necessary to know which tests passed, but to compare the results +between runs. For this reason it is possible to store the results of a +previous run in a set of ini-like "expectation files". This format is +documented below. To generate the expectation files use `wptrunner` with +the `--log-raw=/path/to/log/file` option. This can then be used as +input to the `wptupdate` tool. + +Expectation File Format +~~~~~~~~~~~~~~~~~~~~~~~ + +Metadata about tests, notably including their expected results, is +stored in a modified ini-like format that is designed to be human +editable, but also to be machine updatable. + +Each test file that requires metadata to be specified (because it has +a non-default expectation or because it is disabled, for example) has +a corresponding expectation file in the `metadata` directory. For +example a test file `html/test1.html` containing a failing test would +have an expectation file called `html/test1.html.ini` in the +`metadata` directory. + +An example of an expectation file is:: + + example_default_key: example_value + + [filename.html] + type: testharness + + [subtest1] + expected: FAIL + + [subtest2] + expected: + if platform == 'win': TIMEOUT + if platform == 'osx': ERROR + FAIL + + [filename.html?query=something] + type: testharness + disabled: bug12345 + +The file consists of two elements, key-value pairs and +sections. + +Sections are delimited by headings enclosed in square brackets. Any +closing square bracket in the heading itself my be escaped with a +backslash. Each section may then contain any number of key-value pairs +followed by any number of subsections. So that it is clear which data +belongs to each section without the use of end-section markers, the +data for each section (i.e. the key-value pairs and subsections) must +be indented using spaces. Indentation need only be consistent, but +using two spaces per level is recommended. + +In a test expectation file, each resource provided by the file has a +single section, with the section heading being the part after the last +`/` in the test url. Tests that have subsections may have subsections +for those subtests in which the heading is the name of the subtest. + +Simple key-value pairs are of the form:: + + key: value + +Note that unlike ini files, only `:` is a valid seperator; `=` will +not work as expected. Key-value pairs may also have conditional +values of the form:: + + key: + if condition1: value1 + if condition2: value2 + default + +In this case each conditional is evaluated in turn and the value is +that on the right hand side of the first matching conditional. In the +case that no condition matches, the unconditional default is used. If +no condition matches and no default is provided it is equivalent to +the key not being present. Conditionals use a simple python-like expression +language e.g.:: + + if debug and (platform == "linux" or platform == "osx"): FAIL + +For test expectations the avaliable variables are those in the +`run_info` which for desktop are `version`, `os`, `bits`, `processor`, +`debug` and `product`. + +Key-value pairs specified at the top level of the file before any +sections are special as they provide defaults for the rest of the file +e.g.:: + + key1: value1 + + [section 1] + key2: value2 + + [section 2] + key1: value3 + +In this case, inside section 1, `key1` would have the value `value1` +and `key2` the value `value2` whereas in section 2 `key1` would have +the value `value3` and `key2` would be undefined. + +The web-platform-test harness knows about several keys: + +`expected` + Must evaluate to a possible test status indicating the expected + result of the test. The implicit default is PASS or OK when the + field isn't present. + +`disabled` + Any value indicates that the test is disabled. + +`type` + The test type e.g. `testharness`, `reftest`, or `wdspec`. + +`reftype` + The type of comparison for reftests; either `==` or `!=`. + +`refurl` + The reference url for reftests. + +.. _`web-platform-tests testsuite`: https://github.com/w3c/web-platform-tests diff --git a/testing/web-platform/tests/tools/wptrunner/docs/Makefile b/testing/web-platform/tests/tools/wptrunner/docs/Makefile new file mode 100644 index 000000000000..d02b6c5e7c4f --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/docs/Makefile @@ -0,0 +1,177 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/wptrunner.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/wptrunner.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/wptrunner" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/wptrunner" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/testing/web-platform/tests/tools/wptrunner/docs/architecture.svg b/testing/web-platform/tests/tools/wptrunner/docs/architecture.svg new file mode 100644 index 000000000000..b8d5aa21c19a --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/docs/architecture.svg @@ -0,0 +1 @@ +
TestRunner
[Not supported by viewer]
Product under test
[Not supported by viewer]
TestRunnerManager
[Not supported by viewer]
ManagerGroup
[Not supported by viewer]
Executor
[Not supported by viewer]
Browser
[Not supported by viewer]
ExecutorBrowser
[Not supported by viewer]
run_tests
[Not supported by viewer]
TestLoader
[Not supported by viewer]
TestEnvironment
[Not supported by viewer]
wptserve
[Not supported by viewer]
pywebsocket
[Not supported by viewer]
Queue.get
serve.py
[Not supported by viewer]
Communication (cross process)Ownership (same process)Ownership (cross process)wptrunner classPer-product wptrunner classPer-protocol wptrunner classWeb-platform-tests componentBrowser process
TestRunnerManager
[Not supported by viewer]
TestRunnerManager
[Not supported by viewer]
Browser controlprotocol(e.g. WebDriver)HTTPwebsockets
Tests Queue
[Not supported by viewer]
diff --git a/testing/web-platform/tests/tools/wptrunner/docs/conf.py b/testing/web-platform/tests/tools/wptrunner/docs/conf.py new file mode 100644 index 000000000000..39e5cc4f0d20 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/docs/conf.py @@ -0,0 +1,267 @@ +# -*- coding: utf-8 -*- +# +# wptrunner documentation build configuration file, created by +# sphinx-quickstart on Mon May 19 18:14:20 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'wptrunner' +copyright = u'' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.3' +# The full version, including alpha/beta/rc tags. +release = '0.3' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'wptrunnerdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'wptrunner.tex', u'wptrunner Documentation', + u'James Graham', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'wptrunner', u'wptrunner Documentation', + [u'James Graham'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'wptrunner', u'wptrunner Documentation', + u'James Graham', 'wptrunner', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'python': ('http://docs.python.org/', None), + 'mozlog': ('http://mozbase.readthedocs.org/en/latest/', None)} diff --git a/testing/web-platform/tests/tools/wptrunner/docs/design.rst b/testing/web-platform/tests/tools/wptrunner/docs/design.rst new file mode 100644 index 000000000000..bf108a0087da --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/docs/design.rst @@ -0,0 +1,106 @@ +wptrunner Design +================ + +The design of wptrunner is intended to meet the following +requirements: + + * Possible to run tests from W3C web-platform-tests. + + * Tests should be run as fast as possible. In particular it should + not be necessary to restart the browser between tests, or similar. + + * As far as possible, the tests should run in a "normal" browser and + browsing context. In particular many tests assume that they are + running in a top-level browsing context, so we must avoid the use + of an ``iframe`` test container. + + * It must be possible to deal with all kinds of behaviour of the + browser runder test, for example, crashing, hanging, etc. + + * It should be possible to add support for new platforms and browsers + with minimal code changes. + + * It must be possible to run tests in parallel to further improve + performance. + + * Test output must be in a machine readable form. + +Architecture +------------ + +In order to meet the above requirements, wptrunner is designed to +push as much of the test scheduling as possible into the harness. This +allows the harness to monitor the state of the browser and perform +appropriate action if it gets into an unwanted state e.g. kill the +browser if it appears to be hung. + +The harness will typically communicate with the browser via some remote +control protocol such as WebDriver. However for browsers where no such +protocol is supported, other implementation strategies are possible, +typically at the expense of speed. + +The overall architecture of wptrunner is shown in the diagram below: + +.. image:: architecture.svg + +The main entry point to the code is :py:func:`run_tests` in +``wptrunner.py``. This is responsible for setting up the test +environment, loading the list of tests to be executed, and invoking +the remainder of the code to actually execute some tests. + +The test environment is encapsulated in the +:py:class:`TestEnvironment` class. This defers to code in +``web-platform-tests`` which actually starts the required servers to +run the tests. + +The set of tests to run is defined by the +:py:class:`TestLoader`. This is constructed with a +:py:class:`TestFilter` (not shown), which takes any filter arguments +from the command line to restrict the set of tests that will be +run. The :py:class:`TestLoader` reads both the ``web-platform-tests`` +JSON manifest and the expectation data stored in ini files and +produces a :py:class:`multiprocessing.Queue` of tests to run, and +their expected results. + +Actually running the tests happens through the +:py:class:`ManagerGroup` object. This takes the :py:class:`Queue` of +tests to be run and starts a :py:class:`testrunner.TestRunnerManager` for each +instance of the browser under test that will be started. These +:py:class:`TestRunnerManager` instances are each started in their own +thread. + +A :py:class:`TestRunnerManager` coordinates starting the product under +test, and outputting results from the test. In the case that the test +has timed out or the browser has crashed, it has to restart the +browser to ensure the test run can continue. The functionality for +initialising the browser under test, and probing its state +(e.g. whether the process is still alive) is implemented through a +:py:class:`Browser` object. An implementation of this class must be +provided for each product that is supported. + +The functionality for actually running the tests is provided by a +:py:class:`TestRunner` object. :py:class:`TestRunner` instances are +run in their own child process created with the +:py:mod:`multiprocessing` module. This allows them to run concurrently +and to be killed and restarted as required. Communication between the +:py:class:`TestRunnerManager` and the :py:class:`TestRunner` is +provided by a pair of queues, one for sending messages in each +direction. In particular test results are sent from the +:py:class:`TestRunner` to the :py:class:`TestRunnerManager` using one +of these queues. + +The :py:class:`TestRunner` object is generic in that the same +:py:class:`TestRunner` is used regardless of the product under +test. However the details of how to run the test may vary greatly with +the product since different products support different remote control +protocols (or none at all). These protocol-specific parts are placed +in the :py:class:`Executor` object. There is typically a different +:py:class:`Executor` class for each combination of control protocol +and test type. The :py:class:`TestRunner` is responsible for pulling +each test off the :py:class:`Queue` of tests and passing it down to +the :py:class:`Executor`. + +The executor often requires access to details of the particular +browser instance that it is testing so that it knows e.g. which port +to connect to to send commands to the browser. These details are +encapsulated in the :py:class:`ExecutorBrowser` class. diff --git a/testing/web-platform/tests/tools/wptrunner/docs/expectation.rst b/testing/web-platform/tests/tools/wptrunner/docs/expectation.rst new file mode 100644 index 000000000000..6a0c77684a3b --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/docs/expectation.rst @@ -0,0 +1,248 @@ +Expectation Data +================ + +Introduction +------------ + +For use in continuous integration systems, and other scenarios where +regression tracking is required, wptrunner supports storing and +loading the expected result of each test in a test run. Typically +these expected results will initially be generated by running the +testsuite in a baseline build. They may then be edited by humans as +new features are added to the product that change the expected +results. The expected results may also vary for a single product +depending on the platform on which it is run. Therefore, the raw +structured log data is not a suitable format for storing these +files. Instead something is required that is: + + * Human readable + + * Human editable + + * Machine readable / writable + + * Capable of storing test id / result pairs + + * Suitable for storing in a version control system (i.e. text-based) + +The need for different results per platform means either having +multiple expectation files for each platform, or having a way to +express conditional values within a certain file. The former would be +rather cumbersome for humans updating the expectation files, so the +latter approach has been adopted, leading to the requirement: + + * Capable of storing result values that are conditional on the platform. + +There are few extant formats that meet these requirements, so +wptrunner uses a bespoke ``expectation manifest`` format, which is +closely based on the standard ``ini`` format. + +Directory Layout +---------------- + +Expectation manifest files must be stored under the ``metadata`` +directory passed to the test runner. The directory layout follows that +of web-platform-tests with each test path having a corresponding +manifest file. Tests that differ only by query string, or reftests +with the same test path but different ref paths share the same +reference file. The file name is taken from the last /-separated part +of the path, suffixed with ``.ini``. + +As an optimisation, files which produce only default results +(i.e. ``PASS`` or ``OK``) don't require a corresponding manifest file. + +For example a test with url:: + + /spec/section/file.html?query=param + +would have an expectation file :: + + metadata/spec/section/file.html.ini + + +.. _wptupdate-label: + +Generating Expectation Files +---------------------------- + +wptrunner provides the tool ``wptupdate`` to generate expectation +files from the results of a set of baseline test runs. The basic +syntax for this is:: + + wptupdate [options] [logfile]... + +Each ``logfile`` is a structured log file from a previous run. These +can be generated from wptrunner using the ``--log-raw`` option +e.g. ``--log-raw=structured.log``. The default behaviour is to update +all the test data for the particular combination of hardware and OS +used in the run corresponding to the log data, whilst leaving any +other expectations untouched. + +wptupdate takes several useful options: + +``--sync`` + Pull the latest version of web-platform-tests from the + upstream specified in the config file. If this is specified in + combination with logfiles, it is assumed that the results in the log + files apply to the post-update tests. + +``--no-check-clean`` + Don't attempt to check if the working directory is clean before + doing the update (assuming that the working directory is a git or + mercurial tree). + +``--patch`` + Create a a git commit, or a mq patch, with the changes made by wptupdate. + +``--ignore-existing`` + Overwrite all the expectation data for any tests that have a result + in the passed log files, not just data for the same platform. + +Examples +~~~~~~~~ + +Update the local copy of web-platform-tests without changing the +expectation data and commit (or create a mq patch for) the result:: + + wptupdate --patch --sync + +Update all the expectations from a set of cross-platform test runs:: + + wptupdate --no-check-clean --patch osx.log linux.log windows.log + +Add expectation data for some new tests that are expected to be +platform-independent:: + + wptupdate --no-check-clean --patch --ignore-existing tests.log + +Manifest Format +--------------- +The format of the manifest files is based on the ini format. Files are +divided into sections, each (apart from the root section) having a +heading enclosed in square braces. Within each section are key-value +pairs. There are several notable differences from standard .ini files, +however: + + * Sections may be hierarchically nested, with significant whitespace + indicating nesting depth. + + * Only ``:`` is valid as a key/value separator + +A simple example of a manifest file is:: + + root_key: root_value + + [section] + section_key: section_value + + [subsection] + subsection_key: subsection_value + + [another_section] + another_key: another_value + +Conditional Values +~~~~~~~~~~~~~~~~~~ + +In order to support values that depend on some external data, the +right hand side of a key/value pair can take a set of conditionals +rather than a plain value. These values are placed on a new line +following the key, with significant indentation. Conditional values +are prefixed with ``if`` and terminated with a colon, for example:: + + key: + if cond1: value1 + if cond2: value2 + value3 + +In this example, the value associated with ``key`` is determined by +first evaluating ``cond1`` against external data. If that is true, +``key`` is assigned the value ``value1``, otherwise ``cond2`` is +evaluated in the same way. If both ``cond1`` and ``cond2`` are false, +the unconditional ``value3`` is used. + +Conditions themselves use a Python-like expression syntax. Operands +can either be variables, corresponding to data passed in, numbers +(integer or floating point; exponential notation is not supported) or +quote-delimited strings. Equality is tested using ``==`` and +inequality by ``!=``. The operators ``and``, ``or`` and ``not`` are +used in the expected way. Parentheses can also be used for +grouping. For example:: + + key: + if (a == 2 or a == 3) and b == "abc": value1 + if a == 1 or b != "abc": value2 + value3 + +Here ``a`` and ``b`` are variables, the value of which will be +supplied when the manifest is used. + +Expectation Manifests +--------------------- + +When used for expectation data, manifests have the following format: + + * A section per test URL described by the manifest, with the section + heading being the part of the test URL following the last ``/`` in + the path (this allows multiple tests in a single manifest file with + the same path part of the URL, but different query parts). + + * A subsection per subtest, with the heading being the title of the + subtest. + + * A key ``type`` indicating the test type. This takes the values + ``testharness`` and ``reftest``. + + * For reftests, keys ``reftype`` indicating the reference type + (``==`` or ``!=``) and ``refurl`` indicating the URL of the + reference. + + * A key ``expected`` giving the expectation value of each (sub)test. + + * A key ``disabled`` which can be set to any value to indicate that + the (sub)test is disabled and should either not be run (for tests) + or that its results should be ignored (subtests). + + * A key ``restart-after`` which can be set to any value to indicate that + the runner should restart the browser after running this test (e.g. to + clear out unwanted state). + + * Variables ``debug``, ``os``, ``version``, ``processor`` and + ``bits`` that describe the configuration of the browser under + test. ``debug`` is a boolean indicating whether a build is a debug + build. ``os`` is a string indicating the operating system, and + ``version`` a string indicating the particular version of that + operating system. ``processor`` is a string indicating the + processor architecture and ``bits`` an integer indicating the + number of bits. This information is typically provided by + :py:mod:`mozinfo`. + + * Top level keys are taken as defaults for the whole file. So, for + example, a top level key with ``expected: FAIL`` would indicate + that all tests and subtests in the file are expected to fail, + unless they have an ``expected`` key of their own. + +An simple example manifest might look like:: + + [test.html?variant=basic] + type: testharness + + [Test something unsupported] + expected: FAIL + + [test.html?variant=broken] + expected: ERROR + + [test.html?variant=unstable] + disabled: http://test.bugs.example.org/bugs/12345 + +A more complex manifest with conditional properties might be:: + + [canvas_test.html] + expected: + if os == "osx": FAIL + if os == "windows" and version == "XP": FAIL + PASS + +Note that ``PASS`` in the above works, but is unnecessary; ``PASS`` +(or ``OK``) is always the default expectation for (sub)tests. diff --git a/testing/web-platform/tests/tools/wptrunner/docs/index.rst b/testing/web-platform/tests/tools/wptrunner/docs/index.rst new file mode 100644 index 000000000000..5147d3e31c3b --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/docs/index.rst @@ -0,0 +1,24 @@ +.. wptrunner documentation master file, created by + sphinx-quickstart on Mon May 19 18:14:20 2014. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to wptrunner's documentation! +===================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + usage + expectation + design + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/testing/web-platform/tests/tools/wptrunner/docs/make.bat b/testing/web-platform/tests/tools/wptrunner/docs/make.bat new file mode 100644 index 000000000000..959c1615a289 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/docs/make.bat @@ -0,0 +1,242 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\wptrunner.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\wptrunner.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/testing/web-platform/tests/tools/wptrunner/docs/usage.rst b/testing/web-platform/tests/tools/wptrunner/docs/usage.rst new file mode 100644 index 000000000000..8e74a4320c82 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/docs/usage.rst @@ -0,0 +1,238 @@ +Getting Started +=============== + +Installing wptrunner +-------------------- + +The easiest way to install wptrunner is into a virtualenv, using pip:: + + virtualenv wptrunner + cd wptrunner + source bin/activate + pip install wptrunner + +This will install the base dependencies for wptrunner, but not any +extra dependencies required to test against specific browsers. In +order to do this you must use use the extra requirements files in +``$VIRTUAL_ENV/requirements/requirements_browser.txt``. For example, +in order to test against Firefox you would have to run:: + + pip install -r requirements/requirements_firefox.txt + +If you intend to work on the code, the ``-e`` option to pip should be +used in combination with a source checkout i.e. inside a virtual +environment created as above:: + + git clone https://github.com/w3c/wptrunner.git + cd wptrunner + pip install -e ./ + +In addition to the dependencies installed by pip, wptrunner requires +a copy of the web-platform-tests repository. This can be located +anywhere on the filesystem, but the easiest option is to put it +under the same parent directory as the wptrunner checkout:: + + git clone https://github.com/w3c/web-platform-tests.git + +It is also necessary to generate a web-platform-tests ``MANIFEST.json`` +file. It's recommended to also put that under the same parent directory as +the wptrunner checkout, in a directory named ``meta``:: + + mkdir meta + cd web-platform-tests + python manifest --path ../meta/MANIFEST.json + +The ``MANIFEST.json`` file needs to be regenerated each time the +web-platform-tests checkout is updated. To aid with the update process +there is a tool called ``wptupdate``, which is described in +:ref:`wptupdate-label`. + +Running the Tests +----------------- + +A test run is started using the ``wptrunner`` command. The command +takes multiple options, of which the following are most significant: + +``--product`` (defaults to `firefox`) + The product to test against: `b2g`, `chrome`, `firefox`, or `servo`. + +``--binary`` (required if product is `firefox` or `servo`) + The path to a binary file for the product (browser) to test against. + +``--webdriver-binary`` (required if product is `chrome`) + The path to a `*driver` binary; e.g., a `chromedriver` binary. + +``--certutil-binary`` (required if product is `firefox` [#]_) + The path to a `certutil` binary (for tests that must be run over https). + +``--metadata`` (required only when not `using default paths`_) + The path to a directory containing test metadata. [#]_ + +``--tests`` (required only when not `using default paths`_) + The path to a directory containing a web-platform-tests checkout. + +``--prefs-root`` (required only when testing a Firefox binary) + The path to a directory containing Firefox test-harness preferences. [#]_ + +``--config`` (should default to `wptrunner.default.ini`) + The path to the config (ini) file. + +.. [#] The ``--certutil-binary`` option is required when the product is + ``firefox`` unless ``--ssl-type=none`` is specified. + +.. [#] The ``--metadata`` path is to a directory that contains: + + * a ``MANIFEST.json`` file (the web-platform-tests documentation has + instructions on generating this file) + * (optionally) any expectation files (see :ref:`wptupdate-label`) + +.. [#] Example ``--prefs-root`` value: ``~/mozilla-central/testing/profiles``. + +There are also a variety of other command-line options available; use +``--help`` to list them. + +The following examples show how to start wptrunner with various options. + +------------------ +Starting wptrunner +------------------ + +The examples below assume the following directory layout, +though no specific folder structure is required:: + + ~/testtwf/wptrunner # wptrunner checkout + ~/testtwf/web-platform-tests # web-platform-tests checkout + ~/testtwf/meta # metadata + +To test a Firefox Nightly build in an OS X environment, you might start +wptrunner using something similar to the following example:: + + wptrunner --metadata=~/testtwf/meta/ --tests=~/testtwf/web-platform-tests/ \ + --binary=~/mozilla-central/obj-x86_64-apple-darwin14.3.0/dist/Nightly.app/Contents/MacOS/firefox \ + --certutil-binary=~/mozilla-central/obj-x86_64-apple-darwin14.3.0/security/nss/cmd/certutil/certutil \ + --prefs-root=~/mozilla-central/testing/profiles + + +And to test a Chromium build in an OS X environment, you might start +wptrunner using something similar to the following example:: + + wptrunner --metadata=~/testtwf/meta/ --tests=~/testtwf/web-platform-tests/ \ + --binary=~/chromium/src/out/Release/Chromium.app/Contents/MacOS/Chromium \ + --webdriver-binary=/usr/local/bin/chromedriver --product=chrome + +-------------------- +Running test subsets +-------------------- + +To restrict a test run just to tests in a particular web-platform-tests +subdirectory, specify the directory name in the positional arguments after +the options; for example, run just the tests in the `dom` subdirectory:: + + wptrunner --metadata=~/testtwf/meta --tests=~/testtwf/web-platform-tests/ \ + --binary=/path/to/firefox --certutil-binary=/path/to/certutil \ + --prefs-root=/path/to/testing/profiles \ + dom + +------------------- +Running in parallel +------------------- + +To speed up the testing process, use the ``--processes`` option to have +wptrunner run multiple browser instances in parallel. For example, to +have wptrunner attempt to run tests against with six browser instances +in parallel, specify ``--processes=6``. But note that behaviour in this +mode is necessarily less deterministic than with ``--processes=1`` (the +default), so there may be more noise in the test results. + +------------------- +Using default paths +------------------- + +The (otherwise-required) ``--tests`` and ``--metadata`` command-line +options/flags be omitted if any configuration file is found that +contains a section specifying the ``tests`` and ``metadata`` keys. + +See the `Configuration File`_ section for more information about +configuration files, including information about their expected +locations. + +The content of the ``wptrunner.default.ini`` default configuration file +makes wptrunner look for tests (that is, a web-platform-tests checkout) +as a subdirectory of the current directory named ``tests``, and for +metadata files in a subdirectory of the current directory named ``meta``. + +Output +------ + +wptrunner uses the :py:mod:`mozlog` package for output. This +structures events such as test results or log messages as JSON objects +that can then be fed to other tools for interpretation. More details +about the message format are given in the +:py:mod:`mozlog` documentation. + +By default the raw JSON messages are dumped to stdout. This is +convenient for piping into other tools, but not ideal for humans +reading the output. :py:mod:`mozlog` comes with several other +formatters, which are accessible through command line options. The +general format of these options is ``--log-name=dest``, where ``name`` +is the name of the format and ``dest`` is a path to a destination +file, or ``-`` for stdout. The raw JSON data is written by the ``raw`` +formatter so, the default setup corresponds to ``--log-raw=-``. + +A reasonable output format for humans is provided as ``mach``. So in +order to output the full raw log to a file and a human-readable +summary to stdout, one might pass the options:: + + --log-raw=output.log --log-mach=- + +Configuration File +------------------ + +wptrunner uses a ``.ini`` file to control some configuration +sections. The file has three sections; ``[products]``, +``[manifest:default]`` and ``[web-platform-tests]``. + +``[products]`` is used to +define the set of available products. By default this section is empty +which means that all the products distributed with wptrunner are +enabled (although their dependencies may not be installed). The set +of enabled products can be set by using the product name as the +key. For built in products the value is empty. It is also possible to +provide the path to a script implementing the browser functionality +e.g.:: + + [products] + chrome = + netscape4 = path/to/netscape.py + +``[manifest:default]`` specifies the default paths for the tests and metadata, +relative to the config file. For example:: + + [manifest:default] + tests = ~/testtwf/web-platform-tests + metadata = ~/testtwf/meta + + +``[web-platform-tests]`` is used to set the properties of the upstream +repository when updating the paths. ``remote_url`` specifies the git +url to pull from; ``branch`` the branch to sync against and +``sync_path`` the local path, relative to the configuration file, to +use when checking out the tests e.g.:: + + [web-platform-tests] + remote_url = https://github.com/w3c/web-platform-tests.git + branch = master + sync_path = sync + +A configuration file must contain all the above fields; falling back +to the default values for unspecified fields is not yet supported. + +The ``wptrunner`` and ``wptupdate`` commands will use configuration +files in the following order: + + * Any path supplied with a ``--config`` flag to the command. + + * A file called ``wptrunner.ini`` in the current directory + + * The default configuration file (``wptrunner.default.ini`` in the + source directory) diff --git a/testing/web-platform/tests/tools/wptrunner/requirements.txt b/testing/web-platform/tests/tools/wptrunner/requirements.txt new file mode 100644 index 000000000000..319a2ff984aa --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/requirements.txt @@ -0,0 +1,4 @@ +html5lib >= 0.99 +mozinfo >= 0.7 +mozlog >= 3.3 +mozdebug >= 0.1 diff --git a/testing/web-platform/tests/tools/wptrunner/requirements_chrome.txt b/testing/web-platform/tests/tools/wptrunner/requirements_chrome.txt new file mode 100644 index 000000000000..a2f54425f3ef --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/requirements_chrome.txt @@ -0,0 +1,2 @@ +mozprocess >= 0.19 +selenium >= 2.41.0 diff --git a/testing/web-platform/tests/tools/wptrunner/requirements_firefox.txt b/testing/web-platform/tests/tools/wptrunner/requirements_firefox.txt new file mode 100644 index 000000000000..379e522acc45 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/requirements_firefox.txt @@ -0,0 +1,5 @@ +marionette_driver >= 0.4 +mozprofile >= 0.21 +mozprocess >= 0.19 +mozcrash >= 0.13 +mozrunner >= 6.7 diff --git a/testing/web-platform/tests/tools/wptrunner/requirements_sauce.txt b/testing/web-platform/tests/tools/wptrunner/requirements_sauce.txt new file mode 100644 index 000000000000..7b828f84b08d --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/requirements_sauce.txt @@ -0,0 +1,2 @@ +mozprocess >= 0.19 +selenium >= 3.3.0 diff --git a/testing/web-platform/tests/tools/wptrunner/requirements_servo.txt b/testing/web-platform/tests/tools/wptrunner/requirements_servo.txt new file mode 100644 index 000000000000..22bcfa123a54 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/requirements_servo.txt @@ -0,0 +1 @@ +mozprocess >= 0.19 diff --git a/testing/web-platform/tests/tools/wptrunner/setup.py b/testing/web-platform/tests/tools/wptrunner/setup.py new file mode 100644 index 000000000000..7ec189fefd9a --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/setup.py @@ -0,0 +1,74 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import glob +import os +import sys +import textwrap + +from setuptools import setup, find_packages + +here = os.path.split(__file__)[0] + +PACKAGE_NAME = 'wptrunner' +PACKAGE_VERSION = '1.14' + +# Dependencies +with open(os.path.join(here, "requirements.txt")) as f: + deps = f.read().splitlines() + +# Browser-specific requirements +requirements_files = glob.glob("requirements_*.txt") + +profile_dest = None +dest_exists = False + +setup(name=PACKAGE_NAME, + version=PACKAGE_VERSION, + description="Harness for running the W3C web-platform-tests against various products", + author='Mozilla Automation and Testing Team', + author_email='tools@lists.mozilla.org', + license='MPL 2.0', + packages=find_packages(exclude=["tests", "metadata", "prefs"]), + entry_points={ + 'console_scripts': [ + 'wptrunner = wptrunner.wptrunner:main', + 'wptupdate = wptrunner.update:main', + ] + }, + zip_safe=False, + platforms=['Any'], + classifiers=['Development Status :: 4 - Beta', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent'], + package_data={"wptrunner": ["executors/testharness_marionette.js", + "executors/testharness_webdriver.js", + "executors/reftest.js", + "executors/reftest-wait.js", + "testharnessreport.js", + "testharness_runner.html", + "config.json", + "wptrunner.default.ini", + "browsers/server-locations.txt", + "browsers/b2g_setup/*", + "browsers/sauce_setup/*", + "prefs/*"]}, + include_package_data=True, + data_files=[("requirements", requirements_files)], + install_requires=deps + ) + +if "install" in sys.argv: + path = os.path.relpath(os.path.join(sys.prefix, "requirements"), os.curdir) + print textwrap.fill("""In order to use with one of the built-in browser +products, you will need to install the extra dependencies. These are provided +as requirements_[name].txt in the %s directory and can be installed using +e.g.""" % path, 80) + + print """ + +pip install -r %s/requirements_firefox.txt +""" % path diff --git a/testing/web-platform/meta/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_and_fail.html.ini similarity index 57% rename from testing/web-platform/meta/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html.ini rename to testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_and_fail.html.ini index bdf9ced8b038..81aef049cd12 100644 --- a/testing/web-platform/meta/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html.ini +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_and_fail.html.ini @@ -1,3 +1,3 @@ -[canvas-fallback.html] +[reftest_and_fail.html] type: reftest expected: FAIL diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_cycle_fail.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_cycle_fail.html.ini new file mode 100644 index 000000000000..472b33f7764b --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_cycle_fail.html.ini @@ -0,0 +1,3 @@ +[reftest_cycle_fail.html] + type: reftest + expected: FAIL diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_match_fail.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_match_fail.html.ini new file mode 100644 index 000000000000..f3dc3362fac4 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_match_fail.html.ini @@ -0,0 +1,3 @@ +[reftest_match_fail.html] + type: reftest + expected: FAIL diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_mismatch_fail.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_mismatch_fail.html.ini new file mode 100644 index 000000000000..1055337e2d65 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_mismatch_fail.html.ini @@ -0,0 +1,3 @@ +[reftest_mismatch_fail.html] + type: reftest + expected: FAIL diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_ref_timeout.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_ref_timeout.html.ini new file mode 100644 index 000000000000..8936241ad29c --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_ref_timeout.html.ini @@ -0,0 +1,3 @@ +[reftest_ref_timeout.html] + type: reftest + expected: TIMEOUT diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_timeout.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_timeout.html.ini new file mode 100644 index 000000000000..0d1b9bade95d --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/reftest/reftest_timeout.html.ini @@ -0,0 +1,3 @@ +[reftest_timeout.html] + type: reftest + expected: TIMEOUT diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/firefox/__dir__.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/firefox/__dir__.ini new file mode 100644 index 000000000000..c9d164cd418a --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/firefox/__dir__.ini @@ -0,0 +1,2 @@ +prefs: ["browser.display.foreground_color:#FF0000", + "browser.display.background_color:#000000"] \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/firefox/subdir/test_pref_reset.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/firefox/subdir/test_pref_reset.html.ini new file mode 100644 index 000000000000..6c9198d9bbf1 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/firefox/subdir/test_pref_reset.html.ini @@ -0,0 +1,2 @@ +[test_pref_reset.html] + prefs: [@Reset] diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/firefox/test_pref_set.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/firefox/test_pref_set.html.ini new file mode 100644 index 000000000000..bc9bfb9c4139 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/firefox/test_pref_set.html.ini @@ -0,0 +1,3 @@ +[test_pref_set.html] + prefs: ["browser.display.foreground_color:#00FF00", + "browser.display.background_color:#000000"] diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/subdir/__dir__.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/subdir/__dir__.ini new file mode 100644 index 000000000000..a9157fbc6a9f --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/subdir/__dir__.ini @@ -0,0 +1 @@ +disabled: true \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/subdir/testharness_1.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/subdir/testharness_1.html.ini new file mode 100644 index 000000000000..db9393987b6c --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/subdir/testharness_1.html.ini @@ -0,0 +1,2 @@ +[testharness_1.html] + disabled: @False \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/testharness_0.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/testharness_0.html.ini new file mode 100644 index 000000000000..90b9a6e9f012 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/testharness_0.html.ini @@ -0,0 +1,4 @@ +[testharness_0.html] + type: testharness + [Test that should fail] + expected: FAIL diff --git a/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/testharness_error.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/testharness_error.html.ini new file mode 100644 index 000000000000..fa53e0733abc --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/testharness_error.html.ini @@ -0,0 +1,3 @@ +[testharness_error.html] + type: testharness + expected: ERROR diff --git a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html.ini b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/testharness_timeout.html.ini similarity index 59% rename from testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html.ini rename to testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/testharness_timeout.html.ini index 2edfc5ccdbd2..55eca5191ab1 100644 --- a/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html.ini +++ b/testing/web-platform/tests/tools/wptrunner/test/metadata/testharness/testharness_timeout.html.ini @@ -1,3 +1,3 @@ -[test_ecdh_keys.html] +[testharness_timeout.html] type: testharness expected: TIMEOUT diff --git a/testing/web-platform/tests/tools/wptrunner/test/test.cfg.example b/testing/web-platform/tests/tools/wptrunner/test/test.cfg.example new file mode 100644 index 000000000000..db48226216c3 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/test.cfg.example @@ -0,0 +1,20 @@ +[general] +tests=/path/to/web-platform-tests/ +metadata=/path/to/web-platform-tests/ +ssl-type=none + +# [firefox] +# binary=/path/to/firefox +# prefs-root=/path/to/gecko-src/testing/profiles/ + +# [servo] +# binary=/path/to/servo-src/target/release/servo +# exclude=testharness # Because it needs a special testharness.js + +# [servodriver] +# binary=/path/to/servo-src/target/release/servo +# exclude=testharness # Because it needs a special testharness.js + +# [chrome] +# binary=/path/to/chrome +# webdriver-binary=/path/to/chromedriver diff --git a/testing/web-platform/tests/tools/wptrunner/test/test.py b/testing/web-platform/tests/tools/wptrunner/test/test.py new file mode 100644 index 000000000000..034e317bd52f --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/test.py @@ -0,0 +1,166 @@ +import ConfigParser +import argparse +import json +import os +import sys +import tempfile +import threading +import time +from StringIO import StringIO + +from mozlog import structuredlog, reader +from mozlog.handlers import BaseHandler, StreamHandler, StatusHandler +from mozlog.formatters import MachFormatter +from wptrunner import wptcommandline, wptrunner + +here = os.path.abspath(os.path.dirname(__file__)) + +def setup_wptrunner_logging(logger): + structuredlog.set_default_logger(logger) + wptrunner.logger = logger + wptrunner.wptlogging.setup_stdlib_logger() + +class ResultHandler(BaseHandler): + def __init__(self, verbose=False, logger=None): + self.inner = StreamHandler(sys.stdout, MachFormatter()) + BaseHandler.__init__(self, self.inner) + self.product = None + self.verbose = verbose + self.logger = logger + + self.register_message_handlers("wptrunner-test", {"set-product": self.set_product}) + + def set_product(self, product): + self.product = product + + def __call__(self, data): + if self.product is not None and data["action"] in ["suite_start", "suite_end"]: + # Hack: mozlog sets some internal state to prevent multiple suite_start or + # suite_end messages. We actually want that here (one from the metaharness + # and one from the individual test type harness), so override that internal + # state (a better solution might be to not share loggers, but this works well + # enough) + self.logger._state.suite_started = True + return + + if (not self.verbose and + (data["action"] == "process_output" or + data["action"] == "log" and data["level"] not in ["error", "critical"])): + return + + if "test" in data: + data = data.copy() + data["test"] = "%s: %s" % (self.product, data["test"]) + + return self.inner(data) + +def test_settings(): + return { + "include": "_test", + "manifest-update": "", + "no-capture-stdio": "" + } + +def read_config(): + parser = ConfigParser.ConfigParser() + parser.read("test.cfg") + + rv = {"general":{}, + "products":{}} + + rv["general"].update(dict(parser.items("general"))) + + # This only allows one product per whatever for now + for product in parser.sections(): + if product != "general": + dest = rv["products"][product] = {} + for key, value in parser.items(product): + rv["products"][product][key] = value + + return rv + +def run_tests(product, kwargs): + kwargs["test_paths"]["/_test/"] = {"tests_path": os.path.join(here, "testdata"), + "metadata_path": os.path.join(here, "metadata")} + + wptrunner.run_tests(**kwargs) + +def settings_to_argv(settings): + rv = [] + for name, value in settings.iteritems(): + key = "--%s" % name + if not value: + rv.append(key) + elif isinstance(value, list): + for item in value: + rv.extend([key, item]) + else: + rv.extend([key, value]) + return rv + +def set_from_args(settings, args): + if args.test: + settings["include"] = args.test + if args.tags: + settings["tags"] = args.tags + +def run(config, args): + logger = structuredlog.StructuredLogger("web-platform-tests") + logger.add_handler(ResultHandler(logger=logger, verbose=args.verbose)) + setup_wptrunner_logging(logger) + + parser = wptcommandline.create_parser() + + logger.suite_start(tests=[]) + + for product, product_settings in config["products"].iteritems(): + if args.product and product not in args.product: + continue + + settings = test_settings() + settings.update(config["general"]) + settings.update(product_settings) + settings["product"] = product + set_from_args(settings, args) + + kwargs = vars(parser.parse_args(settings_to_argv(settings))) + wptcommandline.check_args(kwargs) + + logger.send_message("wptrunner-test", "set-product", product) + + run_tests(product, kwargs) + + logger.send_message("wptrunner-test", "set-product", None) + logger.suite_end() + +def get_parser(): + parser = argparse.ArgumentParser() + parser.add_argument("-v", "--verbose", action="store_true", default=False, + help="verbose log output") + parser.add_argument("--product", action="append", + help="Specific product to include in test run") + parser.add_argument("--pdb", action="store_true", + help="Invoke pdb on uncaught exception") + parser.add_argument("--tag", action="append", dest="tags", + help="tags to select tests") + parser.add_argument("test", nargs="*", + help="Specific tests to include in test run") + return parser + +def main(): + config = read_config() + + args = get_parser().parse_args() + + try: + run(config, args) + except Exception: + if args.pdb: + import pdb, traceback + print traceback.format_exc() + pdb.post_mortem() + else: + raise + +if __name__ == "__main__": + main() diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/green-ref.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/green-ref.html new file mode 100644 index 000000000000..0e145d60b55b --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/green-ref.html @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/green.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/green.html new file mode 100644 index 000000000000..38167bb58d57 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/green.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/red.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/red.html new file mode 100644 index 000000000000..2b677e00634b --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/red.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest.https.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest.https.html new file mode 100644 index 000000000000..5a45f10f35eb --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest.https.html @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_and_fail.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_and_fail.html new file mode 100644 index 000000000000..296019535623 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_and_fail.html @@ -0,0 +1,5 @@ +Reftest chain that should fail + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_and_fail_0-ref.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_and_fail_0-ref.html new file mode 100644 index 000000000000..04fb9aa15176 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_and_fail_0-ref.html @@ -0,0 +1,5 @@ +Reftest chain that should fail + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle.html new file mode 100644 index 000000000000..4a84a3b6741e --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle.html @@ -0,0 +1,5 @@ +Reftest with cycle, all match + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_0-ref.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_0-ref.html new file mode 100644 index 000000000000..118bfd88447b --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_0-ref.html @@ -0,0 +1,5 @@ +OR match that should pass + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_1-ref.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_1-ref.html new file mode 100644 index 000000000000..59be0b641def --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_1-ref.html @@ -0,0 +1,5 @@ +Reftest with cycle, all match + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_fail.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_fail.html new file mode 100644 index 000000000000..175e76c4cc9b --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_fail.html @@ -0,0 +1,5 @@ +Reftest with cycle, fails + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_fail_0-ref.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_fail_0-ref.html new file mode 100644 index 000000000000..c8e548c46225 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_cycle_fail_0-ref.html @@ -0,0 +1,5 @@ +Reftest with cycle, fails + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_match.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_match.html new file mode 100644 index 000000000000..333cc6c1ecdf --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_match.html @@ -0,0 +1,5 @@ +rel=match that should pass + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_match_fail.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_match_fail.html new file mode 100644 index 000000000000..a9272ef74da8 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_match_fail.html @@ -0,0 +1,5 @@ +rel=match that should fail + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_mismatch.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_mismatch.html new file mode 100644 index 000000000000..af5fa0750d83 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_mismatch.html @@ -0,0 +1,5 @@ +rel=mismatch that should pass + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_mismatch_fail.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_mismatch_fail.html new file mode 100644 index 000000000000..8d160c4fc200 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_mismatch_fail.html @@ -0,0 +1,5 @@ +rel=mismatch that should fail + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_or_0.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_or_0.html new file mode 100644 index 000000000000..3a51de216441 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_or_0.html @@ -0,0 +1,6 @@ +OR match that should pass + + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_ref_timeout-ref.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_ref_timeout-ref.html new file mode 100644 index 000000000000..04cbb71e0c3c --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_ref_timeout-ref.html @@ -0,0 +1,6 @@ + +rel=match that should time out in the ref + + diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_ref_timeout.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_ref_timeout.html new file mode 100644 index 000000000000..aaf68f5cb5fa --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_ref_timeout.html @@ -0,0 +1,6 @@ + +rel=match that should time out in the ref + + diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_timeout.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_timeout.html new file mode 100644 index 000000000000..b10e676bf005 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_timeout.html @@ -0,0 +1,6 @@ + +rel=match that should timeout + + diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_wait_0.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_wait_0.html new file mode 100644 index 000000000000..4f92715c61e7 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/reftest/reftest_wait_0.html @@ -0,0 +1,13 @@ + +rel=match that should fail + + + + diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/subdir/test_pref_inherit.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/subdir/test_pref_inherit.html new file mode 100644 index 000000000000..10b285194b4a --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/subdir/test_pref_inherit.html @@ -0,0 +1,10 @@ + +Example pref test + + +

Test requires the pref browser.display.foreground_color to be set to #00FF00

+ diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/subdir/test_pref_reset.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/subdir/test_pref_reset.html new file mode 100644 index 000000000000..5c75c1160522 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/subdir/test_pref_reset.html @@ -0,0 +1,10 @@ + +Example pref test + + +

Test requires the pref browser.display.foreground_color to be set to #00FF00

+ diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/test_pref_dir.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/test_pref_dir.html new file mode 100644 index 000000000000..105d9070c9dc --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/test_pref_dir.html @@ -0,0 +1,10 @@ + +Example pref test + + +

Test requires the pref browser.display.foreground_color to be set to #FF0000

+ diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/test_pref_set.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/test_pref_set.html new file mode 100644 index 000000000000..8e5e2989bf72 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/firefox/test_pref_set.html @@ -0,0 +1,10 @@ + +Example pref test + + +

Test requires the pref browser.display.foreground_color to be set to #00FF00

+ diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/subdir/testharness_1.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/subdir/testharness_1.html new file mode 100644 index 000000000000..fd2fc431d399 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/subdir/testharness_1.html @@ -0,0 +1,9 @@ + +Test should be enabled + + + diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness.https.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness.https.html new file mode 100644 index 000000000000..5871eac00148 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness.https.html @@ -0,0 +1,10 @@ + +Example https test + + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_0.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_0.html new file mode 100644 index 000000000000..ff0654cb9a09 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_0.html @@ -0,0 +1,9 @@ + +Test should be disabled + + + diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_error.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_error.html new file mode 100644 index 000000000000..0ac5ba46a330 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_error.html @@ -0,0 +1,7 @@ + +testharness.js test that should error + + + diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_long_timeout.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_long_timeout.html new file mode 100644 index 000000000000..fc94e055be0c --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_long_timeout.html @@ -0,0 +1,9 @@ + +testharness.js test with long timeout + + + + \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_timeout.html b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_timeout.html new file mode 100644 index 000000000000..b99915ac7453 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/test/testdata/testharness/testharness_timeout.html @@ -0,0 +1,6 @@ + +Simple testharness.js usage + + + +// This file should time out, obviously \ No newline at end of file diff --git a/testing/web-platform/tests/tools/wptrunner/tox.ini b/testing/web-platform/tests/tools/wptrunner/tox.ini new file mode 100644 index 000000000000..88dfe79dc5d1 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/tox.ini @@ -0,0 +1,16 @@ +[pytest] +xfail_strict=true + +[tox] +envlist = {py27,pypy}-{base,b2g,chrome,firefox,servo} + +[testenv] +deps = + pytest>=2.9 + pytest-cov + -r{toxinidir}/requirements.txt + chrome: -r{toxinidir}/requirements_chrome.txt + firefox: -r{toxinidir}/requirements_firefox.txt + servo: -r{toxinidir}/requirements_servo.txt + +commands = pytest --cov diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner.default.ini b/testing/web-platform/tests/tools/wptrunner/wptrunner.default.ini new file mode 100644 index 000000000000..34d25f8056b0 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner.default.ini @@ -0,0 +1,11 @@ +[products] + +[web-platform-tests] +remote_url = https://github.com/w3c/web-platform-tests.git +branch = master +sync_path = %(pwd)s/sync + +[manifest:default] +tests = %(pwd)s/tests +metadata = %(pwd)s/meta +url_base = / \ No newline at end of file diff --git a/testing/web-platform/tests/encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4 b/testing/web-platform/tests/tools/wptrunner/wptrunner/__init__.py similarity index 100% rename from testing/web-platform/tests/encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4 rename to testing/web-platform/tests/tools/wptrunner/wptrunner/__init__.py diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/__init__.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/__init__.py new file mode 100644 index 000000000000..e3606d23cf0c --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/__init__.py @@ -0,0 +1,30 @@ +"""Subpackage where each product is defined. Each product is created by adding a +a .py file containing a __wptrunner__ variable in the global scope. This must be +a dictionary with the fields + +"product": Name of the product, assumed to be unique. +"browser": String indicating the Browser implementation used to launch that + product. +"executor": Dictionary with keys as supported test types and values as the name + of the Executor implemantation that will be used to run that test + type. +"browser_kwargs": String naming function that takes product, binary, + prefs_root and the wptrunner.run_tests kwargs dict as arguments + and returns a dictionary of kwargs to use when creating the + Browser class. +"executor_kwargs": String naming a function that takes http server url and + timeout multiplier and returns kwargs to use when creating + the executor class. +"env_options": String naming a funtion of no arguments that returns the + arguments passed to the TestEnvironment. + +All classes and functions named in the above dict must be imported into the +module global scope. +""" + +product_list = ["chrome", + "edge", + "firefox", + "sauce", + "servo", + "servodriver"] diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/b2g_setup/certtest_app.zip b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/b2g_setup/certtest_app.zip new file mode 100644 index 000000000000..f9cbd5300ad6 Binary files /dev/null and b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/b2g_setup/certtest_app.zip differ diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py new file mode 100644 index 000000000000..583ca0d6cded --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py @@ -0,0 +1,159 @@ +import os +import platform +import socket +from abc import ABCMeta, abstractmethod + +from ..wptcommandline import require_arg + +here = os.path.split(__file__)[0] + + +def cmd_arg(name, value=None): + prefix = "-" if platform.system() == "Windows" else "--" + rv = prefix + name + if value is not None: + rv += "=" + value + return rv + + +def get_free_port(start_port, exclude=None): + """Get the first port number after start_port (inclusive) that is + not currently bound. + + :param start_port: Integer port number at which to start testing. + :param exclude: Set of port numbers to skip""" + port = start_port + while True: + if exclude and port in exclude: + port += 1 + continue + s = socket.socket() + try: + s.bind(("127.0.0.1", port)) + except socket.error: + port += 1 + else: + return port + finally: + s.close() + +def browser_command(binary, args, debug_info): + if debug_info: + if debug_info.requiresEscapedArgs: + args = [item.replace("&", "\\&") for item in args] + debug_args = [debug_info.path] + debug_info.args + else: + debug_args = [] + + command = [binary] + args + + return debug_args, command + + +class BrowserError(Exception): + pass + + +class Browser(object): + __metaclass__ = ABCMeta + + process_cls = None + init_timeout = 30 + + def __init__(self, logger): + """Abstract class serving as the basis for Browser implementations. + + The Browser is used in the TestRunnerManager to start and stop the browser + process, and to check the state of that process. This class also acts as a + context manager, enabling it to do browser-specific setup at the start of + the testrun and cleanup after the run is complete. + + :param logger: Structured logger to use for output. + """ + self.logger = logger + + def __enter__(self): + self.setup() + return self + + def __exit__(self, *args, **kwargs): + self.cleanup() + + def setup(self): + """Used for browser-specific setup that happens at the start of a test run""" + pass + + @abstractmethod + def start(self): + """Launch the browser object and get it into a state where is is ready to run tests""" + pass + + @abstractmethod + def stop(self, force=False): + """Stop the running browser process.""" + pass + + @abstractmethod + def pid(self): + """pid of the browser process or None if there is no pid""" + pass + + @abstractmethod + def is_alive(self): + """Boolean indicating whether the browser process is still running""" + pass + + def setup_ssl(self, hosts): + """Return a certificate to use for tests requiring ssl that will be trusted by the browser""" + raise NotImplementedError("ssl testing not supported") + + def cleanup(self): + """Browser-specific cleanup that is run after the testrun is finished""" + pass + + def executor_browser(self): + """Returns the ExecutorBrowser subclass for this Browser subclass and the keyword arguments + with which it should be instantiated""" + return ExecutorBrowser, {} + + def log_crash(self, process, test): + """Return a list of dictionaries containing information about crashes that happend + in the browser, or an empty list if no crashes occurred""" + self.logger.crash(process, test) + + +class NullBrowser(Browser): + def __init__(self, logger, **kwargs): + super(NullBrowser, self).__init__(logger) + + def start(self): + """No-op browser to use in scenarios where the TestRunnerManager shouldn't + actually own the browser process (e.g. Servo where we start one browser + per test)""" + pass + + def stop(self, force=False): + pass + + def pid(self): + return None + + def is_alive(self): + return True + + def on_output(self, line): + raise NotImplementedError + + +class ExecutorBrowser(object): + def __init__(self, **kwargs): + """View of the Browser used by the Executor object. + This is needed because the Executor runs in a child process and + we can't ship Browser instances between processes on Windows. + + Typically this will have a few product-specific properties set, + but in some cases it may have more elaborate methods for setting + up the browser from the runner process. + """ + for k, v in kwargs.iteritems(): + setattr(self, k, v) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py new file mode 100644 index 000000000000..3bd227b32f55 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py @@ -0,0 +1,94 @@ +from .base import Browser, ExecutorBrowser, require_arg +from ..webdriver_server import ChromeDriverServer +from ..executors import executor_kwargs as base_executor_kwargs +from ..executors.executorselenium import (SeleniumTestharnessExecutor, + SeleniumRefTestExecutor) + + +__wptrunner__ = {"product": "chrome", + "check_args": "check_args", + "browser": "ChromeBrowser", + "executor": {"testharness": "SeleniumTestharnessExecutor", + "reftest": "SeleniumRefTestExecutor"}, + "browser_kwargs": "browser_kwargs", + "executor_kwargs": "executor_kwargs", + "env_extras": "env_extras", + "env_options": "env_options"} + + +def check_args(**kwargs): + require_arg(kwargs, "webdriver_binary") + + +def browser_kwargs(**kwargs): + return {"binary": kwargs["binary"], + "webdriver_binary": kwargs["webdriver_binary"], + "webdriver_args": kwargs.get("webdriver_args")} + + +def executor_kwargs(test_type, server_config, cache_manager, run_info_data, + **kwargs): + from selenium.webdriver import DesiredCapabilities + + executor_kwargs = base_executor_kwargs(test_type, server_config, + cache_manager, **kwargs) + executor_kwargs["close_after_done"] = True + capabilities = dict(DesiredCapabilities.CHROME.items()) + capabilities.setdefault("chromeOptions", {})["prefs"] = { + "profile": { + "default_content_setting_values": { + "popups": 1 + } + } + } + for (kwarg, capability) in [("binary", "binary"), ("binary_args", "args")]: + if kwargs[kwarg] is not None: + capabilities["chromeOptions"][capability] = kwargs[kwarg] + executor_kwargs["capabilities"] = capabilities + return executor_kwargs + + +def env_extras(**kwargs): + return [] + + +def env_options(): + return {"host": "web-platform.test", + "bind_hostname": "true"} + + +class ChromeBrowser(Browser): + """Chrome is backed by chromedriver, which is supplied through + ``wptrunner.webdriver.ChromeDriverServer``. + """ + + def __init__(self, logger, binary, webdriver_binary="chromedriver", + webdriver_args=None): + """Creates a new representation of Chrome. The `binary` argument gives + the browser binary to use for testing.""" + Browser.__init__(self, logger) + self.binary = binary + self.server = ChromeDriverServer(self.logger, + binary=webdriver_binary, + args=webdriver_args) + + def start(self): + self.server.start(block=False) + + def stop(self, force=False): + self.server.stop(force=force) + + def pid(self): + return self.server.pid + + def is_alive(self): + # TODO(ato): This only indicates the driver is alive, + # and doesn't say anything about whether a browser session + # is active. + return self.server.is_alive() + + def cleanup(self): + self.stop() + + def executor_browser(self): + return ExecutorBrowser, {"webdriver_url": self.server.url} diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/edge.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/edge.py new file mode 100644 index 000000000000..354edb3bab12 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/edge.py @@ -0,0 +1,74 @@ +from .base import Browser, ExecutorBrowser, require_arg +from ..webdriver_server import EdgeDriverServer +from ..executors import executor_kwargs as base_executor_kwargs +from ..executors.executorselenium import (SeleniumTestharnessExecutor, + SeleniumRefTestExecutor) + +__wptrunner__ = {"product": "edge", + "check_args": "check_args", + "browser": "EdgeBrowser", + "executor": {"testharness": "SeleniumTestharnessExecutor", + "reftest": "SeleniumRefTestExecutor"}, + "browser_kwargs": "browser_kwargs", + "executor_kwargs": "executor_kwargs", + "env_extras": "env_extras", + "env_options": "env_options"} + + +def check_args(**kwargs): + require_arg(kwargs, "webdriver_binary") + +def browser_kwargs(**kwargs): + return {"webdriver_binary": kwargs["webdriver_binary"], + "webdriver_args": kwargs.get("webdriver_args")} + +def executor_kwargs(test_type, server_config, cache_manager, run_info_data, + **kwargs): + from selenium.webdriver import DesiredCapabilities + + executor_kwargs = base_executor_kwargs(test_type, server_config, + cache_manager, **kwargs) + executor_kwargs["close_after_done"] = True + executor_kwargs["capabilities"] = dict(DesiredCapabilities.EDGE.items()) + return executor_kwargs + +def env_extras(**kwargs): + return [] + +def env_options(): + return {"host": "web-platform.test", + "bind_hostname": "true", + "supports_debugger": False} + +class EdgeBrowser(Browser): + used_ports = set() + + def __init__(self, logger, webdriver_binary, webdriver_args=None): + Browser.__init__(self, logger) + self.server = EdgeDriverServer(self.logger, + binary=webdriver_binary, + args=webdriver_args) + self.webdriver_host = "localhost" + self.webdriver_port = self.server.port + + def start(self): + print self.server.url + self.server.start() + + def stop(self): + self.server.stop() + + def pid(self): + return self.server.pid + + def is_alive(self): + # TODO(ato): This only indicates the server is alive, + # and doesn't say anything about whether a browser session + # is active. + return self.server.is_alive() + + def cleanup(self): + self.stop() + + def executor_browser(self): + return ExecutorBrowser, {"webdriver_url": self.server.url} diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py new file mode 100644 index 000000000000..7152fd7c1c20 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py @@ -0,0 +1,308 @@ +import os +import platform +import signal +import subprocess +import sys + +import mozinfo +from mozprocess import ProcessHandler +from mozprofile import FirefoxProfile, Preferences +from mozprofile.permissions import ServerLocations +from mozrunner import FirefoxRunner +from mozrunner.utils import get_stack_fixer_function +from mozcrash import mozcrash + +from .base import (get_free_port, + Browser, + ExecutorBrowser, + require_arg, + cmd_arg, + browser_command) +from ..executors import executor_kwargs as base_executor_kwargs +from ..executors.executormarionette import (MarionetteTestharnessExecutor, + MarionetteRefTestExecutor, + MarionetteWdspecExecutor) +from ..environment import hostnames + + +here = os.path.join(os.path.split(__file__)[0]) + +__wptrunner__ = {"product": "firefox", + "check_args": "check_args", + "browser": "FirefoxBrowser", + "executor": {"testharness": "MarionetteTestharnessExecutor", + "reftest": "MarionetteRefTestExecutor", + "wdspec": "MarionetteWdspecExecutor"}, + "browser_kwargs": "browser_kwargs", + "executor_kwargs": "executor_kwargs", + "env_extras": "env_extras", + "env_options": "env_options", + "run_info_extras": "run_info_extras", + "update_properties": "update_properties"} + + +def check_args(**kwargs): + require_arg(kwargs, "binary") + if kwargs["ssl_type"] != "none": + require_arg(kwargs, "certutil_binary") + + +def browser_kwargs(**kwargs): + return {"binary": kwargs["binary"], + "prefs_root": kwargs["prefs_root"], + "extra_prefs": kwargs["extra_prefs"], + "debug_info": kwargs["debug_info"], + "symbols_path": kwargs["symbols_path"], + "stackwalk_binary": kwargs["stackwalk_binary"], + "certutil_binary": kwargs["certutil_binary"], + "ca_certificate_path": kwargs["ssl_env"].ca_cert_path(), + "e10s": kwargs["gecko_e10s"], + "stackfix_dir": kwargs["stackfix_dir"], + "binary_args": kwargs["binary_args"]} + + +def executor_kwargs(test_type, server_config, cache_manager, run_info_data, + **kwargs): + executor_kwargs = base_executor_kwargs(test_type, server_config, + cache_manager, **kwargs) + executor_kwargs["close_after_done"] = test_type != "reftest" + if kwargs["timeout_multiplier"] is None: + if test_type == "reftest": + if run_info_data["debug"] or run_info_data.get("asan"): + executor_kwargs["timeout_multiplier"] = 4 + else: + executor_kwargs["timeout_multiplier"] = 2 + elif run_info_data["debug"] or run_info_data.get("asan"): + executor_kwargs["timeout_multiplier"] = 3 + if test_type == "wdspec": + executor_kwargs["binary"] = kwargs["binary"] + executor_kwargs["webdriver_binary"] = kwargs.get("webdriver_binary") + executor_kwargs["webdriver_args"] = kwargs.get("webdriver_args") + fxOptions = {} + if kwargs["binary"]: + fxOptions["binary"] = kwargs["binary"] + if kwargs["binary_args"]: + fxOptions["args"] = kwargs["binary_args"] + fxOptions["prefs"] = { + "network.dns.localDomains": ",".join(hostnames) + } + capabilities = {"moz:firefoxOptions": fxOptions} + executor_kwargs["capabilities"] = capabilities + return executor_kwargs + + +def env_extras(**kwargs): + return [] + + +def env_options(): + return {"host": "127.0.0.1", + "external_host": "web-platform.test", + "bind_hostname": "false", + "certificate_domain": "web-platform.test", + "supports_debugger": True} + + +def run_info_extras(**kwargs): + return {"e10s": kwargs["gecko_e10s"]} + + +def update_properties(): + return ["debug", "e10s", "os", "version", "processor", "bits"], {"debug", "e10s"} + + +class FirefoxBrowser(Browser): + used_ports = set() + init_timeout = 60 + shutdown_timeout = 60 + + def __init__(self, logger, binary, prefs_root, extra_prefs=None, debug_info=None, + symbols_path=None, stackwalk_binary=None, certutil_binary=None, + ca_certificate_path=None, e10s=False, stackfix_dir=None, + binary_args=None): + Browser.__init__(self, logger) + self.binary = binary + self.prefs_root = prefs_root + self.extra_prefs = extra_prefs + self.marionette_port = None + self.runner = None + self.debug_info = debug_info + self.profile = None + self.symbols_path = symbols_path + self.stackwalk_binary = stackwalk_binary + self.ca_certificate_path = ca_certificate_path + self.certutil_binary = certutil_binary + self.e10s = e10s + self.binary_args = binary_args + if self.symbols_path and stackfix_dir: + self.stack_fixer = get_stack_fixer_function(stackfix_dir, + self.symbols_path) + else: + self.stack_fixer = None + + def start(self): + self.marionette_port = get_free_port(2828, exclude=self.used_ports) + self.used_ports.add(self.marionette_port) + + env = os.environ.copy() + env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1" + + locations = ServerLocations(filename=os.path.join(here, "server-locations.txt")) + + preferences = self.load_prefs() + + self.profile = FirefoxProfile(locations=locations, + preferences=preferences) + self.profile.set_preferences({"marionette.enabled": True, + "marionette.port": self.marionette_port, + "dom.disable_open_during_load": False, + "network.dns.localDomains": ",".join(hostnames), + "network.proxy.type": 0, + "places.history.enabled": False}) + if self.e10s: + self.profile.set_preferences({"browser.tabs.remote.autostart": True}) + + # Bug 1262954: winxp + e10s, disable hwaccel + if (self.e10s and platform.system() in ("Windows", "Microsoft") and + '5.1' in platform.version()): + self.profile.set_preferences({"layers.acceleration.disabled": True}) + + if self.ca_certificate_path is not None: + self.setup_ssl() + + debug_args, cmd = browser_command(self.binary, + self.binary_args if self.binary_args else [] + + [cmd_arg("marionette"), "about:blank"], + self.debug_info) + + self.runner = FirefoxRunner(profile=self.profile, + binary=cmd[0], + cmdargs=cmd[1:], + env=env, + process_class=ProcessHandler, + process_args={"processOutputLine": [self.on_output]}) + + self.logger.debug("Starting Firefox") + + self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive) + self.logger.debug("Firefox Started") + + def load_prefs(self): + prefs = Preferences() + + prefs_path = os.path.join(self.prefs_root, "prefs_general.js") + if os.path.exists(prefs_path): + prefs.add(Preferences.read_prefs(prefs_path)) + else: + self.logger.warning("Failed to find base prefs file in %s" % prefs_path) + + # Add any custom preferences + prefs.add(self.extra_prefs, cast=True) + + return prefs() + + def stop(self, force=False): + if self.runner is not None and self.runner.is_running(): + try: + # For Firefox we assume that stopping the runner prompts the + # browser to shut down. This allows the leak log to be written + for clean, stop_f in [(True, lambda: self.runner.wait(self.shutdown_timeout)), + (False, lambda: self.runner.stop(signal.SIGTERM)), + (False, lambda: self.runner.stop(signal.SIGKILL))]: + if not force or not clean: + retcode = stop_f() + if retcode is not None: + self.logger.info("Browser exited with return code %s" % retcode) + break + except OSError: + # This can happen on Windows if the process is already dead + pass + + def pid(self): + if self.runner.process_handler is None: + return None + + try: + return self.runner.process_handler.pid + except AttributeError: + return None + + def on_output(self, line): + """Write a line of output from the firefox process to the log""" + data = line.decode("utf8", "replace") + if self.stack_fixer: + data = self.stack_fixer(data) + self.logger.process_output(self.pid(), + data, + command=" ".join(self.runner.command)) + + def is_alive(self): + if self.runner: + return self.runner.is_running() + return False + + def cleanup(self): + self.stop() + + def executor_browser(self): + assert self.marionette_port is not None + return ExecutorBrowser, {"marionette_port": self.marionette_port} + + def log_crash(self, process, test): + dump_dir = os.path.join(self.profile.profile, "minidumps") + + mozcrash.log_crashes(self.logger, + dump_dir, + symbols_path=self.symbols_path, + stackwalk_binary=self.stackwalk_binary, + process=process, + test=test) + + def setup_ssl(self): + """Create a certificate database to use in the test profile. This is configured + to trust the CA Certificate that has signed the web-platform.test server + certificate.""" + + self.logger.info("Setting up ssl") + + # Make sure the certutil libraries from the source tree are loaded when using a + # local copy of certutil + # TODO: Maybe only set this if certutil won't launch? + env = os.environ.copy() + certutil_dir = os.path.dirname(self.binary) + if mozinfo.isMac: + env_var = "DYLD_LIBRARY_PATH" + elif mozinfo.isUnix: + env_var = "LD_LIBRARY_PATH" + else: + env_var = "PATH" + + + env[env_var] = (os.path.pathsep.join([certutil_dir, env[env_var]]) + if env_var in env else certutil_dir).encode( + sys.getfilesystemencoding() or 'utf-8', 'replace') + + def certutil(*args): + cmd = [self.certutil_binary] + list(args) + self.logger.process_output("certutil", + subprocess.check_output(cmd, + env=env, + stderr=subprocess.STDOUT), + " ".join(cmd)) + + pw_path = os.path.join(self.profile.profile, ".crtdbpw") + with open(pw_path, "w") as f: + # Use empty password for certificate db + f.write("\n") + + cert_db_path = self.profile.profile + + # Create a new certificate db + certutil("-N", "-d", cert_db_path, "-f", pw_path) + + # Add the CA certificate to the database and mark as trusted to issue server certs + certutil("-A", "-d", cert_db_path, "-f", pw_path, "-t", "CT,,", + "-n", "web-platform-tests", "-i", self.ca_certificate_path) + + # List all certs in the database + certutil("-L", "-d", cert_db_path) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce.py new file mode 100644 index 000000000000..7300b6afefb8 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce.py @@ -0,0 +1,208 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import glob +import os +import shutil +import subprocess +import tarfile +import tempfile +import time +from cStringIO import StringIO as CStringIO + +import requests + +from .base import Browser, ExecutorBrowser, require_arg +from ..executors import executor_kwargs as base_executor_kwargs +from ..executors.executorselenium import (SeleniumTestharnessExecutor, + SeleniumRefTestExecutor) + +here = os.path.split(__file__)[0] + + +__wptrunner__ = {"product": "sauce", + "check_args": "check_args", + "browser": "SauceBrowser", + "executor": {"testharness": "SeleniumTestharnessExecutor", + "reftest": "SeleniumRefTestExecutor"}, + "browser_kwargs": "browser_kwargs", + "executor_kwargs": "executor_kwargs", + "env_extras": "env_extras", + "env_options": "env_options"} + + +def get_capabilities(**kwargs): + browser_name = kwargs["sauce_browser"] + platform = kwargs["sauce_platform"] + version = kwargs["sauce_version"] + build = kwargs["sauce_build"] + tags = kwargs["sauce_tags"] + tunnel_id = kwargs["sauce_tunnel_id"] + prerun_script = { + "MicrosoftEdge": { + "executable": "sauce-storage:edge-prerun.bat", + "background": False, + }, + "safari": { + "executable": "sauce-storage:safari-prerun.sh", + "background": False, + } + } + capabilities = { + "browserName": browser_name, + "build": build, + "disablePopupHandler": True, + "name": "%s %s on %s" % (browser_name, version, platform), + "platform": platform, + "public": "public", + "selenium-version": "3.3.1", + "tags": tags, + "tunnel-identifier": tunnel_id, + "version": version, + "prerun": prerun_script.get(browser_name) + } + + if browser_name == 'MicrosoftEdge': + capabilities['selenium-version'] = '2.4.8' + + return capabilities + + +def get_sauce_config(**kwargs): + browser_name = kwargs["sauce_browser"] + sauce_user = kwargs["sauce_user"] + sauce_key = kwargs["sauce_key"] + + hub_url = "%s:%s@localhost:4445" % (sauce_user, sauce_key) + data = { + "url": "http://%s/wd/hub" % hub_url, + "browserName": browser_name, + "capabilities": get_capabilities(**kwargs) + } + + return data + + +def check_args(**kwargs): + require_arg(kwargs, "sauce_browser") + require_arg(kwargs, "sauce_platform") + require_arg(kwargs, "sauce_version") + require_arg(kwargs, "sauce_user") + require_arg(kwargs, "sauce_key") + + +def browser_kwargs(**kwargs): + sauce_config = get_sauce_config(**kwargs) + + return {"sauce_config": sauce_config} + + +def executor_kwargs(test_type, server_config, cache_manager, run_info_data, + **kwargs): + executor_kwargs = base_executor_kwargs(test_type, server_config, + cache_manager, **kwargs) + + executor_kwargs["capabilities"] = get_capabilities(**kwargs) + + return executor_kwargs + + +def env_extras(**kwargs): + return [SauceConnect(**kwargs)] + + +def env_options(): + return {"host": "web-platform.test", + "bind_hostname": "true", + "supports_debugger": False} + + +def get_tar(url, dest): + resp = requests.get(url, stream=True) + resp.raise_for_status() + with tarfile.open(fileobj=CStringIO(resp.raw.read())) as f: + f.extractall(path=dest) + + +class SauceConnect(): + + def __init__(self, **kwargs): + self.sauce_user = kwargs["sauce_user"] + self.sauce_key = kwargs["sauce_key"] + self.sauce_tunnel_id = kwargs["sauce_tunnel_id"] + self.sauce_connect_binary = kwargs.get("sauce_connect_binary") + self.sc_process = None + self.temp_dir = None + + def __enter__(self, options): + if not self.sauce_connect_binary: + self.temp_dir = tempfile.mkdtemp() + get_tar("https://saucelabs.com/downloads/sc-latest-linux.tar.gz", self.temp_dir) + self.sauce_connect_binary = glob.glob(os.path.join(self.temp_dir, "sc-*-linux/bin/sc"))[0] + + self.upload_prerun_exec('edge-prerun.bat') + self.upload_prerun_exec('safari-prerun.sh') + + self.sc_process = subprocess.Popen([ + self.sauce_connect_binary, + "--user=%s" % self.sauce_user, + "--api-key=%s" % self.sauce_key, + "--no-remove-colliding-tunnels", + "--tunnel-identifier=%s" % self.sauce_tunnel_id, + "--readyfile=./sauce_is_ready", + "--tunnel-domains", + "web-platform.test", + "*.web-platform.test" + ]) + while not os.path.exists('./sauce_is_ready') and not self.sc_process.poll(): + time.sleep(5) + + if self.sc_process.returncode is not None and self.sc_process.returncode > 0: + raise SauceException("Unable to start Sauce Connect Proxy. Process exited with code %s", self.sc_process.returncode) + + def __exit__(self, *args): + self.sc_process.terminate() + if os.path.exists(self.temp_dir): + try: + shutil.rmtree(self.temp_dir) + except OSError: + pass + + def upload_prerun_exec(self, file_name): + auth = (self.sauce_user, self.sauce_key) + url = "https://saucelabs.com/rest/v1/storage/%s/%s?overwrite=true" % (self.sauce_user, file_name) + + with open(os.path.join(here, 'sauce_setup', file_name), 'rb') as f: + requests.post(url, data=f, auth=auth) + + +class SauceException(Exception): + pass + + +class SauceBrowser(Browser): + init_timeout = 300 + + def __init__(self, logger, sauce_config): + Browser.__init__(self, logger) + self.sauce_config = sauce_config + + def start(self): + pass + + def stop(self, force=False): + pass + + def pid(self): + return None + + def is_alive(self): + # TODO: Should this check something about the connection? + return True + + def cleanup(self): + pass + + def executor_browser(self): + return ExecutorBrowser, {"webdriver_url": self.sauce_config["url"]} diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce_setup/edge-prerun.bat b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce_setup/edge-prerun.bat new file mode 100644 index 000000000000..4554894896b9 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce_setup/edge-prerun.bat @@ -0,0 +1,2 @@ +@echo off +reg add "HKCU\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Storage\microsoft.microsoftedge_8wekyb3d8bbwe\MicrosoftEdge\New Windows" /v "PopupMgr" /t REG_SZ /d no diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce_setup/safari-prerun.sh b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce_setup/safari-prerun.sh new file mode 100644 index 000000000000..85c72e6be6a0 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce_setup/safari-prerun.sh @@ -0,0 +1,2 @@ +#!/bin/bash +defaults write com.apple.Safari com.apple.Safari.ContentPageGroupIdentifier.WebKit2JavaScriptCanOpenWindowsAutomatically -bool true diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/server-locations.txt b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/server-locations.txt new file mode 100644 index 000000000000..5dcaf4bb6a4c --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/server-locations.txt @@ -0,0 +1,31 @@ +http://localhost:8000 primary + +http://web-platform.test:8000 +http://www.web-platform.test:8000 +http://www1.web-platform.test:8000 +http://www2.web-platform.test:8000 +http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8000 +http://xn--lve-6lad.web-platform.test:8000 + +http://web-platform.test:8001 +http://www.web-platform.test:8001 +http://www1.web-platform.test:8001 +http://www2.web-platform.test:8001 +http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8001 +http://xn--lve-6lad.web-platform.test:8001 + +https://web-platform.test:8443 +https://www.web-platform.test:8443 +https://www1.web-platform.test:8443 +https://www2.web-platform.test:8443 +https://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8443 +https://xn--lve-6lad.web-platform.test:8443 + +# These are actually ws servers, but until mozprofile is +# fixed we have to pretend that they are http servers +http://web-platform.test:8888 +http://www.web-platform.test:8888 +http://www1.web-platform.test:8888 +http://www2.web-platform.test:8888 +http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8888 +http://xn--lve-6lad.web-platform.test:8888 diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servo.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servo.py new file mode 100644 index 000000000000..e24e4dfd9dfe --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servo.py @@ -0,0 +1,81 @@ +import os + +from .base import NullBrowser, ExecutorBrowser, require_arg +from ..executors import executor_kwargs as base_executor_kwargs +from ..executors.executorservo import ServoTestharnessExecutor, ServoRefTestExecutor, ServoWdspecExecutor + +here = os.path.join(os.path.split(__file__)[0]) + +__wptrunner__ = { + "product": "servo", + "check_args": "check_args", + "browser": "ServoBrowser", + "executor": { + "testharness": "ServoTestharnessExecutor", + "reftest": "ServoRefTestExecutor", + "wdspec": "ServoWdspecExecutor", + }, + "browser_kwargs": "browser_kwargs", + "executor_kwargs": "executor_kwargs", + "env_extras": "env_extras", + "env_options": "env_options", + "update_properties": "update_properties", +} + + +def check_args(**kwargs): + require_arg(kwargs, "binary") + + +def browser_kwargs(**kwargs): + return { + "binary": kwargs["binary"], + "debug_info": kwargs["debug_info"], + "binary_args": kwargs["binary_args"], + "user_stylesheets": kwargs.get("user_stylesheets"), + "ca_certificate_path": kwargs["ssl_env"].ca_cert_path(), + } + + +def executor_kwargs(test_type, server_config, cache_manager, run_info_data, + **kwargs): + rv = base_executor_kwargs(test_type, server_config, + cache_manager, **kwargs) + rv["pause_after_test"] = kwargs["pause_after_test"] + return rv + + +def env_extras(**kwargs): + return [] + + +def env_options(): + return {"host": "127.0.0.1", + "external_host": "web-platform.test", + "bind_hostname": "true", + "testharnessreport": "testharnessreport-servo.js", + "supports_debugger": True} + + +def update_properties(): + return ["debug", "os", "version", "processor", "bits"], None + + +class ServoBrowser(NullBrowser): + def __init__(self, logger, binary, debug_info=None, binary_args=None, + user_stylesheets=None, ca_certificate_path=None): + NullBrowser.__init__(self, logger) + self.binary = binary + self.debug_info = debug_info + self.binary_args = binary_args or [] + self.user_stylesheets = user_stylesheets or [] + self.ca_certificate_path = ca_certificate_path + + def executor_browser(self): + return ExecutorBrowser, { + "binary": self.binary, + "debug_info": self.debug_info, + "binary_args": self.binary_args, + "user_stylesheets": self.user_stylesheets, + "ca_certificate_path": self.ca_certificate_path, + } diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servodriver.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servodriver.py new file mode 100644 index 000000000000..9575e0fbff9d --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servodriver.py @@ -0,0 +1,165 @@ +import os +import subprocess +import tempfile + +from mozprocess import ProcessHandler + +from .base import Browser, require_arg, get_free_port, browser_command, ExecutorBrowser +from ..executors import executor_kwargs as base_executor_kwargs +from ..executors.executorservodriver import (ServoWebDriverTestharnessExecutor, + ServoWebDriverRefTestExecutor) + +here = os.path.join(os.path.split(__file__)[0]) + +__wptrunner__ = { + "product": "servodriver", + "check_args": "check_args", + "browser": "ServoWebDriverBrowser", + "executor": { + "testharness": "ServoWebDriverTestharnessExecutor", + "reftest": "ServoWebDriverRefTestExecutor", + }, + "browser_kwargs": "browser_kwargs", + "executor_kwargs": "executor_kwargs", + "env_extras": "env_extras", + "env_options": "env_options", + "update_properties": "update_properties", +} + +hosts_text = """127.0.0.1 web-platform.test +127.0.0.1 www.web-platform.test +127.0.0.1 www1.web-platform.test +127.0.0.1 www2.web-platform.test +127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test +127.0.0.1 xn--lve-6lad.web-platform.test +""" + + +def check_args(**kwargs): + require_arg(kwargs, "binary") + + +def browser_kwargs(**kwargs): + return { + "binary": kwargs["binary"], + "debug_info": kwargs["debug_info"], + "user_stylesheets": kwargs.get("user_stylesheets"), + } + + +def executor_kwargs(test_type, server_config, cache_manager, run_info_data, **kwargs): + rv = base_executor_kwargs(test_type, server_config, + cache_manager, **kwargs) + return rv + + +def env_extras(**kwargs): + return [] + + +def env_options(): + return {"host": "127.0.0.1", + "external_host": "web-platform.test", + "bind_hostname": "true", + "testharnessreport": "testharnessreport-servodriver.js", + "supports_debugger": True} + + +def update_properties(): + return ["debug", "os", "version", "processor", "bits"], None + + +def make_hosts_file(): + hosts_fd, hosts_path = tempfile.mkstemp() + with os.fdopen(hosts_fd, "w") as f: + f.write(hosts_text) + return hosts_path + + +class ServoWebDriverBrowser(Browser): + used_ports = set() + + def __init__(self, logger, binary, debug_info=None, webdriver_host="127.0.0.1", + user_stylesheets=None): + Browser.__init__(self, logger) + self.binary = binary + self.webdriver_host = webdriver_host + self.webdriver_port = None + self.proc = None + self.debug_info = debug_info + self.hosts_path = make_hosts_file() + self.command = None + self.user_stylesheets = user_stylesheets if user_stylesheets else [] + + def start(self): + self.webdriver_port = get_free_port(4444, exclude=self.used_ports) + self.used_ports.add(self.webdriver_port) + + env = os.environ.copy() + env["HOST_FILE"] = self.hosts_path + env["RUST_BACKTRACE"] = "1" + + debug_args, command = browser_command( + self.binary, + [ + "--hard-fail", + "--webdriver", str(self.webdriver_port), + "about:blank", + ], + self.debug_info + ) + + for stylesheet in self.user_stylesheets: + command += ["--user-stylesheet", stylesheet] + + self.command = command + + self.command = debug_args + self.command + + if not self.debug_info or not self.debug_info.interactive: + self.proc = ProcessHandler(self.command, + processOutputLine=[self.on_output], + env=env, + storeOutput=False) + self.proc.run() + else: + self.proc = subprocess.Popen(self.command, env=env) + + self.logger.debug("Servo Started") + + def stop(self, force=False): + self.logger.debug("Stopping browser") + if self.proc is not None: + try: + self.proc.kill() + except OSError: + # This can happen on Windows if the process is already dead + pass + + def pid(self): + if self.proc is None: + return None + + try: + return self.proc.pid + except AttributeError: + return None + + def on_output(self, line): + """Write a line of output from the process to the log""" + self.logger.process_output(self.pid(), + line.decode("utf8", "replace"), + command=" ".join(self.command)) + + def is_alive(self): + if self.runner: + return self.runner.is_running() + return False + + def cleanup(self): + self.stop() + + def executor_browser(self): + assert self.webdriver_port is not None + return ExecutorBrowser, {"webdriver_host": self.webdriver_host, + "webdriver_port": self.webdriver_port} diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/config.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/config.py new file mode 100644 index 000000000000..5bd3f467f3ed --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/config.py @@ -0,0 +1,60 @@ +import ConfigParser +import os +import sys +from collections import OrderedDict + +here = os.path.split(__file__)[0] + +class ConfigDict(dict): + def __init__(self, base_path, *args, **kwargs): + self.base_path = base_path + dict.__init__(self, *args, **kwargs) + + def get_path(self, key, default=None): + if key not in self: + return default + path = self[key] + os.path.expanduser(path) + return os.path.abspath(os.path.join(self.base_path, path)) + +def read(config_path): + config_path = os.path.abspath(config_path) + config_root = os.path.split(config_path)[0] + parser = ConfigParser.SafeConfigParser() + success = parser.read(config_path) + assert config_path in success, success + + subns = {"pwd": os.path.abspath(os.path.curdir)} + + rv = OrderedDict() + for section in parser.sections(): + rv[section] = ConfigDict(config_root) + for key in parser.options(section): + rv[section][key] = parser.get(section, key, False, subns) + + return rv + +def path(argv=None): + if argv is None: + argv = [] + path = None + + for i, arg in enumerate(argv): + if arg == "--config": + if i + 1 < len(argv): + path = argv[i + 1] + elif arg.startswith("--config="): + path = arg.split("=", 1)[1] + if path is not None: + break + + if path is None: + if os.path.exists("wptrunner.ini"): + path = os.path.abspath("wptrunner.ini") + else: + path = os.path.join(here, "..", "wptrunner.default.ini") + + return os.path.abspath(path) + +def load(): + return read(path(sys.argv)) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/environment.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/environment.py new file mode 100644 index 000000000000..60588949088e --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/environment.py @@ -0,0 +1,216 @@ +import json +import os +import multiprocessing +import signal +import socket +import sys +import time + +from mozlog import get_default_logger, handlers + +from wptlogging import LogLevelRewriter + +here = os.path.split(__file__)[0] + +serve = None +sslutils = None + + +hostnames = ["web-platform.test", + "www.web-platform.test", + "www1.web-platform.test", + "www2.web-platform.test", + "xn--n8j6ds53lwwkrqhv28a.web-platform.test", + "xn--lve-6lad.web-platform.test"] + + +def do_delayed_imports(logger, test_paths): + global serve, sslutils + + serve_root = serve_path(test_paths) + sys.path.insert(0, serve_root) + + failed = [] + + try: + from tools.serve import serve + except ImportError: + from wpt_tools.serve import serve + except ImportError: + failed.append("serve") + + try: + import sslutils + except ImportError: + failed.append("sslutils") + + if failed: + logger.critical( + "Failed to import %s. Ensure that tests path %s contains web-platform-tests" % + (", ".join(failed), serve_root)) + sys.exit(1) + + +def serve_path(test_paths): + return test_paths["/"]["tests_path"] + + +def get_ssl_kwargs(**kwargs): + if kwargs["ssl_type"] == "openssl": + args = {"openssl_binary": kwargs["openssl_binary"]} + elif kwargs["ssl_type"] == "pregenerated": + args = {"host_key_path": kwargs["host_key_path"], + "host_cert_path": kwargs["host_cert_path"], + "ca_cert_path": kwargs["ca_cert_path"]} + else: + args = {} + return args + + +def ssl_env(logger, **kwargs): + ssl_env_cls = sslutils.environments[kwargs["ssl_type"]] + return ssl_env_cls(logger, **get_ssl_kwargs(**kwargs)) + + +class TestEnvironmentError(Exception): + pass + + +class TestEnvironment(object): + def __init__(self, test_paths, ssl_env, pause_after_test, debug_info, options, env_extras): + """Context manager that owns the test environment i.e. the http and + websockets servers""" + self.test_paths = test_paths + self.ssl_env = ssl_env + self.server = None + self.config = None + self.external_config = None + self.pause_after_test = pause_after_test + self.test_server_port = options.pop("test_server_port", True) + self.debug_info = debug_info + self.options = options if options is not None else {} + + self.cache_manager = multiprocessing.Manager() + self.stash = serve.stash.StashServer() + self.env_extras = env_extras + + + def __enter__(self): + self.stash.__enter__() + self.ssl_env.__enter__() + self.cache_manager.__enter__() + for cm in self.env_extras: + cm.__enter__(self.options) + self.setup_server_logging() + self.config = self.load_config() + serve.set_computed_defaults(self.config) + self.external_config, self.servers = serve.start(self.config, self.ssl_env, + self.get_routes()) + if self.options.get("supports_debugger") and self.debug_info and self.debug_info.interactive: + self.ignore_interrupts() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.process_interrupts() + + for scheme, servers in self.servers.iteritems(): + for port, server in servers: + server.kill() + for cm in self.env_extras: + cm.__exit__() + self.cache_manager.__exit__(exc_type, exc_val, exc_tb) + self.ssl_env.__exit__(exc_type, exc_val, exc_tb) + self.stash.__exit__() + + def ignore_interrupts(self): + signal.signal(signal.SIGINT, signal.SIG_IGN) + + def process_interrupts(self): + signal.signal(signal.SIGINT, signal.SIG_DFL) + + def load_config(self): + default_config_path = os.path.join(serve_path(self.test_paths), "config.default.json") + local_config_path = os.path.join(here, "config.json") + + with open(default_config_path) as f: + default_config = json.load(f) + + with open(local_config_path) as f: + data = f.read() + local_config = json.loads(data % self.options) + + #TODO: allow non-default configuration for ssl + + local_config["external_host"] = self.options.get("external_host", None) + local_config["ssl"]["encrypt_after_connect"] = self.options.get("encrypt_after_connect", False) + + config = serve.merge_json(default_config, local_config) + config["doc_root"] = serve_path(self.test_paths) + + if not self.ssl_env.ssl_enabled: + config["ports"]["https"] = [None] + + host = self.options.get("certificate_domain", config["host"]) + hosts = [host] + hosts.extend("%s.%s" % (item[0], host) for item in serve.get_subdomains(host).values()) + key_file, certificate = self.ssl_env.host_cert_path(hosts) + + config["key_file"] = key_file + config["certificate"] = certificate + + return config + + def setup_server_logging(self): + server_logger = get_default_logger(component="wptserve") + assert server_logger is not None + log_filter = handlers.LogLevelFilter(lambda x:x, "info") + # Downgrade errors to warnings for the server + log_filter = LogLevelRewriter(log_filter, ["error"], "warning") + server_logger.component_filter = log_filter + + try: + #Set as the default logger for wptserve + serve.set_logger(server_logger) + serve.logger = server_logger + except Exception: + # This happens if logging has already been set up for wptserve + pass + + def get_routes(self): + route_builder = serve.RoutesBuilder() + + for path, format_args, content_type, route in [ + ("testharness_runner.html", {}, "text/html", "/testharness_runner.html"), + (self.options.get("testharnessreport", "testharnessreport.js"), + {"output": self.pause_after_test}, "text/javascript", + "/resources/testharnessreport.js")]: + path = os.path.normpath(os.path.join(here, path)) + route_builder.add_static(path, format_args, content_type, route) + + for url_base, paths in self.test_paths.iteritems(): + if url_base == "/": + continue + route_builder.add_mount_point(url_base, paths["tests_path"]) + + if "/" not in self.test_paths: + del route_builder.mountpoint_routes["/"] + + return route_builder.get_routes() + + def ensure_started(self): + # Pause for a while to ensure that the server has a chance to start + time.sleep(2) + for scheme, servers in self.servers.iteritems(): + for port, server in servers: + if self.test_server_port: + s = socket.socket() + try: + s.connect((self.config["host"], port)) + except socket.error: + raise EnvironmentError( + "%s server on port %d failed to start" % (scheme, port)) + finally: + s.close() + + if not server.is_alive(): + raise EnvironmentError("%s server on port %d failed to start" % (scheme, port)) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/__init__.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/__init__.py new file mode 100644 index 000000000000..24761b838309 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/__init__.py @@ -0,0 +1,4 @@ +from base import (executor_kwargs, + testharness_result_converter, + reftest_result_converter, + TestExecutor) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py new file mode 100644 index 000000000000..a4bda4faafae --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py @@ -0,0 +1,325 @@ +import hashlib +import json +import os +import traceback +import urlparse +from abc import ABCMeta, abstractmethod + +from ..testrunner import Stop + +here = os.path.split(__file__)[0] + + +def executor_kwargs(test_type, server_config, cache_manager, **kwargs): + timeout_multiplier = kwargs["timeout_multiplier"] + if timeout_multiplier is None: + timeout_multiplier = 1 + + executor_kwargs = {"server_config": server_config, + "timeout_multiplier": timeout_multiplier, + "debug_info": kwargs["debug_info"]} + + if test_type == "reftest": + executor_kwargs["screenshot_cache"] = cache_manager.dict() + + return executor_kwargs + + +def strip_server(url): + """Remove the scheme and netloc from a url, leaving only the path and any query + or fragment. + + url - the url to strip + + e.g. http://example.org:8000/tests?id=1#2 becomes /tests?id=1#2""" + + url_parts = list(urlparse.urlsplit(url)) + url_parts[0] = "" + url_parts[1] = "" + return urlparse.urlunsplit(url_parts) + + +class TestharnessResultConverter(object): + harness_codes = {0: "OK", + 1: "ERROR", + 2: "TIMEOUT"} + + test_codes = {0: "PASS", + 1: "FAIL", + 2: "TIMEOUT", + 3: "NOTRUN"} + + def __call__(self, test, result): + """Convert a JSON result into a (TestResult, [SubtestResult]) tuple""" + result_url, status, message, stack, subtest_results = result + assert result_url == test.url, ("Got results from %s, expected %s" % + (result_url, test.url)) + harness_result = test.result_cls(self.harness_codes[status], message) + return (harness_result, + [test.subtest_result_cls(name, self.test_codes[status], message, stack) + for name, status, message, stack in subtest_results]) + + +testharness_result_converter = TestharnessResultConverter() + + +def reftest_result_converter(self, test, result): + return (test.result_cls(result["status"], result["message"], + extra=result.get("extra")), []) + + +def pytest_result_converter(self, test, data): + harness_data, subtest_data = data + + if subtest_data is None: + subtest_data = [] + + harness_result = test.result_cls(*harness_data) + subtest_results = [test.subtest_result_cls(*item) for item in subtest_data] + + return (harness_result, subtest_results) + + +class ExecutorException(Exception): + def __init__(self, status, message): + self.status = status + self.message = message + + +class TestExecutor(object): + __metaclass__ = ABCMeta + + test_type = None + convert_result = None + + def __init__(self, browser, server_config, timeout_multiplier=1, + debug_info=None): + """Abstract Base class for object that actually executes the tests in a + specific browser. Typically there will be a different TestExecutor + subclass for each test type and method of executing tests. + + :param browser: ExecutorBrowser instance providing properties of the + browser that will be tested. + :param server_config: Dictionary of wptserve server configuration of the + form stored in TestEnvironment.external_config + :param timeout_multiplier: Multiplier relative to base timeout to use + when setting test timeout. + """ + self.runner = None + self.browser = browser + self.server_config = server_config + self.timeout_multiplier = timeout_multiplier + self.debug_info = debug_info + self.last_environment = {"protocol": "http", + "prefs": {}} + self.protocol = None # This must be set in subclasses + + @property + def logger(self): + """StructuredLogger for this executor""" + if self.runner is not None: + return self.runner.logger + + def setup(self, runner): + """Run steps needed before tests can be started e.g. connecting to + browser instance + + :param runner: TestRunner instance that is going to run the tests""" + self.runner = runner + if self.protocol is not None: + self.protocol.setup(runner) + + def teardown(self): + """Run cleanup steps after tests have finished""" + if self.protocol is not None: + self.protocol.teardown() + + def run_test(self, test): + """Run a particular test. + + :param test: The test to run""" + if test.environment != self.last_environment: + self.on_environment_change(test.environment) + + try: + result = self.do_test(test) + except Exception as e: + result = self.result_from_exception(test, e) + + if result is Stop: + return result + + # log result of parent test + if result[0].status == "ERROR": + self.logger.debug(result[0].message) + + self.last_environment = test.environment + + self.runner.send_message("test_ended", test, result) + + def server_url(self, protocol): + return "%s://%s:%s" % (protocol, + self.server_config["host"], + self.server_config["ports"][protocol][0]) + + def test_url(self, test): + return urlparse.urljoin(self.server_url(test.environment["protocol"]), test.url) + + @abstractmethod + def do_test(self, test): + """Test-type and protocol specific implementation of running a + specific test. + + :param test: The test to run.""" + pass + + def on_environment_change(self, new_environment): + pass + + def result_from_exception(self, test, e): + if hasattr(e, "status") and e.status in test.result_cls.statuses: + status = e.status + else: + status = "ERROR" + message = unicode(getattr(e, "message", "")) + if message: + message += "\n" + message += traceback.format_exc(e) + return test.result_cls(status, message), [] + + +class TestharnessExecutor(TestExecutor): + convert_result = testharness_result_converter + + +class RefTestExecutor(TestExecutor): + convert_result = reftest_result_converter + + def __init__(self, browser, server_config, timeout_multiplier=1, screenshot_cache=None, + debug_info=None): + TestExecutor.__init__(self, browser, server_config, + timeout_multiplier=timeout_multiplier, + debug_info=debug_info) + + self.screenshot_cache = screenshot_cache + + +class RefTestImplementation(object): + def __init__(self, executor): + self.timeout_multiplier = executor.timeout_multiplier + self.executor = executor + # Cache of url:(screenshot hash, screenshot). Typically the + # screenshot is None, but we set this value if a test fails + # and the screenshot was taken from the cache so that we may + # retrieve the screenshot from the cache directly in the future + self.screenshot_cache = self.executor.screenshot_cache + self.message = None + + @property + def logger(self): + return self.executor.logger + + def get_hash(self, test, viewport_size, dpi): + timeout = test.timeout * self.timeout_multiplier + key = (test.url, viewport_size, dpi) + + if key not in self.screenshot_cache: + success, data = self.executor.screenshot(test, viewport_size, dpi) + + if not success: + return False, data + + screenshot = data + hash_value = hashlib.sha1(screenshot).hexdigest() + + self.screenshot_cache[key] = (hash_value, None) + + rv = (hash_value, screenshot) + else: + rv = self.screenshot_cache[key] + + self.message.append("%s %s" % (test.url, rv[0])) + return True, rv + + def is_pass(self, lhs_hash, rhs_hash, relation): + assert relation in ("==", "!=") + self.message.append("Testing %s %s %s" % (lhs_hash, relation, rhs_hash)) + return ((relation == "==" and lhs_hash == rhs_hash) or + (relation == "!=" and lhs_hash != rhs_hash)) + + def run_test(self, test): + viewport_size = test.viewport_size + dpi = test.dpi + self.message = [] + + # Depth-first search of reference tree, with the goal + # of reachings a leaf node with only pass results + + stack = list(((test, item[0]), item[1]) for item in reversed(test.references)) + while stack: + hashes = [None, None] + screenshots = [None, None] + + nodes, relation = stack.pop() + + for i, node in enumerate(nodes): + success, data = self.get_hash(node, viewport_size, dpi) + if success is False: + return {"status": data[0], "message": data[1]} + + hashes[i], screenshots[i] = data + + if self.is_pass(hashes[0], hashes[1], relation): + if nodes[1].references: + stack.extend(list(((nodes[1], item[0]), item[1]) for item in reversed(nodes[1].references))) + else: + # We passed + return {"status":"PASS", "message": None} + + # We failed, so construct a failure message + + for i, (node, screenshot) in enumerate(zip(nodes, screenshots)): + if screenshot is None: + success, screenshot = self.retake_screenshot(node, viewport_size, dpi) + if success: + screenshots[i] = screenshot + + log_data = [{"url": nodes[0].url, "screenshot": screenshots[0]}, relation, + {"url": nodes[1].url, "screenshot": screenshots[1]}] + + return {"status": "FAIL", + "message": "\n".join(self.message), + "extra": {"reftest_screenshots": log_data}} + + def retake_screenshot(self, node, viewport_size, dpi): + success, data = self.executor.screenshot(node, viewport_size, dpi) + if not success: + return False, data + + key = (node.url, viewport_size, dpi) + hash_val, _ = self.screenshot_cache[key] + self.screenshot_cache[key] = hash_val, data + return True, data + + +class WdspecExecutor(TestExecutor): + convert_result = pytest_result_converter + + +class Protocol(object): + def __init__(self, executor, browser): + self.executor = executor + self.browser = browser + + @property + def logger(self): + return self.executor.logger + + def setup(self, runner): + pass + + def teardown(self): + pass + + def wait(self): + pass diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py new file mode 100644 index 000000000000..21e6509af167 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py @@ -0,0 +1,618 @@ +import hashlib +import httplib +import os +import socket +import threading +import time +import traceback +import urlparse +import uuid +from collections import defaultdict + +from ..wpttest import WdspecResult, WdspecSubtestResult + +errors = None +marionette = None +pytestrunner = None + +here = os.path.join(os.path.split(__file__)[0]) + +from .base import (ExecutorException, + Protocol, + RefTestExecutor, + RefTestImplementation, + TestExecutor, + TestharnessExecutor, + testharness_result_converter, + reftest_result_converter, + strip_server, + WdspecExecutor) +from ..testrunner import Stop +from ..webdriver_server import GeckoDriverServer + +# Extra timeout to use after internal test timeout at which the harness +# should force a timeout +extra_timeout = 5 # seconds + + +def do_delayed_imports(): + global errors, marionette + + # Marionette client used to be called marionette, recently it changed + # to marionette_driver for unfathomable reasons + try: + import marionette + from marionette import errors + except ImportError: + from marionette_driver import marionette, errors + + +class MarionetteProtocol(Protocol): + def __init__(self, executor, browser): + do_delayed_imports() + + Protocol.__init__(self, executor, browser) + self.marionette = None + self.marionette_port = browser.marionette_port + self.timeout = None + self.runner_handle = None + + def setup(self, runner): + """Connect to browser via Marionette.""" + Protocol.setup(self, runner) + + self.logger.debug("Connecting to Marionette on port %i" % self.marionette_port) + self.marionette = marionette.Marionette(host='localhost', + port=self.marionette_port, + socket_timeout=None) + + # XXX Move this timeout somewhere + self.logger.debug("Waiting for Marionette connection") + while True: + success = self.marionette.wait_for_port(60) + #When running in a debugger wait indefinitely for firefox to start + if success or self.executor.debug_info is None: + break + + session_started = False + if success: + try: + self.logger.debug("Starting Marionette session") + self.marionette.start_session() + except Exception as e: + self.logger.warning("Starting marionette session failed: %s" % e) + else: + self.logger.debug("Marionette session started") + session_started = True + + if not success or not session_started: + self.logger.warning("Failed to connect to Marionette") + self.executor.runner.send_message("init_failed") + else: + try: + self.after_connect() + except Exception: + self.logger.warning("Post-connection steps failed") + self.logger.error(traceback.format_exc()) + self.executor.runner.send_message("init_failed") + else: + self.executor.runner.send_message("init_succeeded") + + def teardown(self): + try: + self.marionette._request_in_app_shutdown() + self.marionette.delete_session(send_request=False, reset_session_id=True) + except Exception: + # This is typically because the session never started + pass + if self.marionette is not None: + del self.marionette + + @property + def is_alive(self): + """Check if the Marionette connection is still active.""" + try: + self.marionette.current_window_handle + except Exception: + return False + return True + + def after_connect(self): + self.load_runner(self.executor.last_environment["protocol"]) + + def set_timeout(self, timeout): + """Set the Marionette script timeout. + + :param timeout: Script timeout in seconds + + """ + self.marionette.timeout.script = timeout + self.timeout = timeout + + def load_runner(self, protocol): + # Check if we previously had a test window open, and if we did make sure it's closed + self.marionette.execute_script("if (window.wrappedJSObject.win) {window.wrappedJSObject.win.close()}") + url = urlparse.urljoin(self.executor.server_url(protocol), "/testharness_runner.html") + self.logger.debug("Loading %s" % url) + self.runner_handle = self.marionette.current_window_handle + try: + self.marionette.navigate(url) + except Exception as e: + self.logger.critical( + "Loading initial page %s failed. Ensure that the " + "there are no other programs bound to this port and " + "that your firewall rules or network setup does not " + "prevent access.\e%s" % (url, traceback.format_exc(e))) + self.marionette.execute_script( + "document.title = '%s'" % threading.current_thread().name.replace("'", '"')) + + def close_old_windows(self, protocol): + handles = self.marionette.window_handles + runner_handle = None + try: + handles.remove(self.runner_handle) + runner_handle = self.runner_handle + except ValueError: + # The runner window probably changed id but we can restore it + # This isn't supposed to happen, but marionette ids are not yet stable + # We assume that the first handle returned corresponds to the runner, + # but it hopefully doesn't matter too much if that assumption is + # wrong since we reload the runner in that tab anyway. + runner_handle = handles.pop(0) + + for handle in handles: + self.marionette.switch_to_window(handle) + self.marionette.close() + + self.marionette.switch_to_window(runner_handle) + if runner_handle != self.runner_handle: + self.load_runner(protocol) + + def wait(self): + socket_timeout = self.marionette.client.sock.gettimeout() + if socket_timeout: + self.marionette.timeout.script = socket_timeout / 2 + + while True: + try: + self.marionette.execute_async_script("") + except errors.ScriptTimeoutException: + self.logger.debug("Script timed out") + pass + except (socket.timeout, IOError): + self.logger.debug("Socket closed") + break + except Exception as e: + self.logger.error(traceback.format_exc(e)) + break + + def on_environment_change(self, old_environment, new_environment): + #Unset all the old prefs + for name in old_environment.get("prefs", {}).iterkeys(): + value = self.executor.original_pref_values[name] + if value is None: + self.clear_user_pref(name) + else: + self.set_pref(name, value) + + for name, value in new_environment.get("prefs", {}).iteritems(): + self.executor.original_pref_values[name] = self.get_pref(name) + self.set_pref(name, value) + + def set_pref(self, name, value): + if value.lower() not in ("true", "false"): + try: + int(value) + except ValueError: + value = "'%s'" % value + else: + value = value.lower() + + self.logger.info("Setting pref %s (%s)" % (name, value)) + + script = """ + let prefInterface = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + let pref = '%s'; + let type = prefInterface.getPrefType(pref); + let value = %s; + switch(type) { + case prefInterface.PREF_STRING: + prefInterface.setCharPref(pref, value); + break; + case prefInterface.PREF_BOOL: + prefInterface.setBoolPref(pref, value); + break; + case prefInterface.PREF_INT: + prefInterface.setIntPref(pref, value); + break; + } + """ % (name, value) + with self.marionette.using_context(self.marionette.CONTEXT_CHROME): + self.marionette.execute_script(script) + + def clear_user_pref(self, name): + self.logger.info("Clearing pref %s" % (name)) + script = """ + let prefInterface = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + let pref = '%s'; + prefInterface.clearUserPref(pref); + """ % name + with self.marionette.using_context(self.marionette.CONTEXT_CHROME): + self.marionette.execute_script(script) + + def get_pref(self, name): + script = """ + let prefInterface = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + let pref = '%s'; + let type = prefInterface.getPrefType(pref); + switch(type) { + case prefInterface.PREF_STRING: + return prefInterface.getCharPref(pref); + case prefInterface.PREF_BOOL: + return prefInterface.getBoolPref(pref); + case prefInterface.PREF_INT: + return prefInterface.getIntPref(pref); + case prefInterface.PREF_INVALID: + return null; + } + """ % name + with self.marionette.using_context(self.marionette.CONTEXT_CHROME): + self.marionette.execute_script(script) + + def clear_origin(self, url): + self.logger.info("Clearing origin %s" % (url)) + script = """ + let url = '%s'; + let uri = Components.classes["@mozilla.org/network/io-service;1"] + .getService(Ci.nsIIOService) + .newURI(url); + let ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + let principal = ssm.createCodebasePrincipal(uri, {}); + let qms = Components.classes["@mozilla.org/dom/quota-manager-service;1"] + .getService(Components.interfaces.nsIQuotaManagerService); + qms.clearStoragesForPrincipal(principal, "default", true); + """ % url + with self.marionette.using_context(self.marionette.CONTEXT_CHROME): + self.marionette.execute_script(script) + + +class RemoteMarionetteProtocol(Protocol): + def __init__(self, executor, browser): + do_delayed_imports() + Protocol.__init__(self, executor, browser) + self.webdriver_binary = executor.webdriver_binary + self.webdriver_args = executor.webdriver_args + self.capabilities = self.executor.capabilities + self.session_config = None + self.server = None + + def setup(self, runner): + """Connect to browser via the Marionette HTTP server.""" + try: + self.server = GeckoDriverServer( + self.logger, + binary=self.webdriver_binary, + args=self.webdriver_args) + self.server.start(block=False) + self.logger.info( + "WebDriver HTTP server listening at %s" % self.server.url) + self.session_config = {"host": self.server.host, + "port": self.server.port, + "capabilities": self.capabilities} + except Exception: + self.logger.error(traceback.format_exc()) + self.executor.runner.send_message("init_failed") + else: + self.executor.runner.send_message("init_succeeded") + + def teardown(self): + if self.server is not None and self.server.is_alive: + self.server.stop() + + @property + def is_alive(self): + """Test that the Marionette connection is still alive. + + Because the remote communication happens over HTTP we need to + make an explicit request to the remote. It is allowed for + WebDriver spec tests to not have a WebDriver session, since this + may be what is tested. + + An HTTP request to an invalid path that results in a 404 is + proof enough to us that the server is alive and kicking. + """ + conn = httplib.HTTPConnection(self.server.host, self.server.port) + conn.request("HEAD", self.server.base_path + "invalid") + res = conn.getresponse() + return res.status == 404 + + +class ExecuteAsyncScriptRun(object): + def __init__(self, logger, func, protocol, url, timeout): + self.logger = logger + self.result = (None, None) + self.protocol = protocol + self.marionette = protocol.marionette + self.func = func + self.url = url + self.timeout = timeout + self.result_flag = threading.Event() + + def run(self): + index = self.url.rfind("/storage/"); + if index != -1: + # Clear storage + self.protocol.clear_origin(self.url) + + timeout = self.timeout + + try: + if timeout is not None: + if timeout + extra_timeout != self.protocol.timeout: + self.protocol.set_timeout(timeout + extra_timeout) + else: + # We just want it to never time out, really, but marionette doesn't + # make that possible. It also seems to time out immediately if the + # timeout is set too high. This works at least. + self.protocol.set_timeout(2**28 - 1) + except IOError: + self.logger.error("Lost marionette connection before starting test") + return Stop + + executor = threading.Thread(target = self._run) + executor.start() + + if timeout is not None: + wait_timeout = timeout + 2 * extra_timeout + else: + wait_timeout = None + + flag = self.result_flag.wait(wait_timeout) + if self.result[1] is None: + self.logger.debug("Timed out waiting for a result") + self.result = False, ("EXTERNAL-TIMEOUT", None) + return self.result + + def _run(self): + try: + self.result = True, self.func(self.marionette, self.url, self.timeout) + except errors.ScriptTimeoutException: + self.logger.debug("Got a marionette timeout") + self.result = False, ("EXTERNAL-TIMEOUT", None) + except (socket.timeout, IOError): + # This can happen on a crash + # Also, should check after the test if the firefox process is still running + # and otherwise ignore any other result and set it to crash + self.result = False, ("CRASH", None) + except Exception as e: + message = getattr(e, "message", "") + if message: + message += "\n" + message += traceback.format_exc(e) + self.result = False, ("ERROR", e) + + finally: + self.result_flag.set() + + +class MarionetteTestharnessExecutor(TestharnessExecutor): + def __init__(self, browser, server_config, timeout_multiplier=1, + close_after_done=True, debug_info=None, **kwargs): + """Marionette-based executor for testharness.js tests""" + TestharnessExecutor.__init__(self, browser, server_config, + timeout_multiplier=timeout_multiplier, + debug_info=debug_info) + + self.protocol = MarionetteProtocol(self, browser) + self.script = open(os.path.join(here, "testharness_marionette.js")).read() + self.close_after_done = close_after_done + self.window_id = str(uuid.uuid4()) + + self.original_pref_values = {} + + if marionette is None: + do_delayed_imports() + + def is_alive(self): + return self.protocol.is_alive + + def on_environment_change(self, new_environment): + self.protocol.on_environment_change(self.last_environment, new_environment) + + if new_environment["protocol"] != self.last_environment["protocol"]: + self.protocol.load_runner(new_environment["protocol"]) + + def do_test(self, test): + timeout = (test.timeout * self.timeout_multiplier if self.debug_info is None + else None) + + success, data = ExecuteAsyncScriptRun(self.logger, + self.do_testharness, + self.protocol, + self.test_url(test), + timeout).run() + if success: + return self.convert_result(test, data) + + return (test.result_cls(*data), []) + + def do_testharness(self, marionette, url, timeout): + if self.close_after_done: + marionette.execute_script("if (window.wrappedJSObject.win) {window.wrappedJSObject.win.close()}") + self.protocol.close_old_windows(self.protocol) + + if timeout is not None: + timeout_ms = str(timeout * 1000) + else: + timeout_ms = "null" + + script = self.script % {"abs_url": url, + "url": strip_server(url), + "window_id": self.window_id, + "timeout_multiplier": self.timeout_multiplier, + "timeout": timeout_ms, + "explicit_timeout": timeout is None} + + rv = marionette.execute_async_script(script, new_sandbox=False) + return rv + + +class MarionetteRefTestExecutor(RefTestExecutor): + def __init__(self, browser, server_config, timeout_multiplier=1, + screenshot_cache=None, close_after_done=True, + debug_info=None, **kwargs): + + """Marionette-based executor for reftests""" + RefTestExecutor.__init__(self, + browser, + server_config, + screenshot_cache=screenshot_cache, + timeout_multiplier=timeout_multiplier, + debug_info=debug_info) + self.protocol = MarionetteProtocol(self, browser) + self.implementation = RefTestImplementation(self) + self.close_after_done = close_after_done + self.has_window = False + self.original_pref_values = {} + + with open(os.path.join(here, "reftest.js")) as f: + self.script = f.read() + with open(os.path.join(here, "reftest-wait.js")) as f: + self.wait_script = f.read() + + def is_alive(self): + return self.protocol.is_alive + + def on_environment_change(self, new_environment): + self.protocol.on_environment_change(self.last_environment, new_environment) + + def do_test(self, test): + if self.close_after_done and self.has_window: + self.protocol.marionette.close() + self.protocol.marionette.switch_to_window( + self.protocol.marionette.window_handles[-1]) + self.has_window = False + + if not self.has_window: + self.protocol.marionette.execute_script(self.script) + self.protocol.marionette.switch_to_window(self.protocol.marionette.window_handles[-1]) + self.has_window = True + + result = self.implementation.run_test(test) + return self.convert_result(test, result) + + def screenshot(self, test, viewport_size, dpi): + # https://github.com/w3c/wptrunner/issues/166 + assert viewport_size is None + assert dpi is None + + timeout = self.timeout_multiplier * test.timeout if self.debug_info is None else None + + test_url = self.test_url(test) + + return ExecuteAsyncScriptRun(self.logger, + self._screenshot, + self.protocol, + test_url, + timeout).run() + + def _screenshot(self, marionette, url, timeout): + marionette.navigate(url) + + marionette.execute_async_script(self.wait_script) + + screenshot = marionette.screenshot(full=False) + # strip off the data:img/png, part of the url + if screenshot.startswith("data:image/png;base64,"): + screenshot = screenshot.split(",", 1)[1] + + return screenshot + + +class WdspecRun(object): + def __init__(self, func, session, path, timeout): + self.func = func + self.result = (None, None) + self.session = session + self.path = path + self.timeout = timeout + self.result_flag = threading.Event() + + def run(self): + """Runs function in a thread and interrupts it if it exceeds the + given timeout. Returns (True, (Result, [SubtestResult ...])) in + case of success, or (False, (status, extra information)) in the + event of failure. + """ + + executor = threading.Thread(target=self._run) + executor.start() + + flag = self.result_flag.wait(self.timeout) + if self.result[1] is None: + self.result = False, ("EXTERNAL-TIMEOUT", None) + + return self.result + + def _run(self): + try: + self.result = True, self.func(self.session, self.path, self.timeout) + except (socket.timeout, IOError): + self.result = False, ("CRASH", None) + except Exception as e: + message = getattr(e, "message") + if message: + message += "\n" + message += traceback.format_exc(e) + self.result = False, ("ERROR", message) + finally: + self.result_flag.set() + + +class MarionetteWdspecExecutor(WdspecExecutor): + def __init__(self, browser, server_config, webdriver_binary, + timeout_multiplier=1, close_after_done=True, debug_info=None, + capabilities=None, webdriver_args=None, binary=None): + self.do_delayed_imports() + WdspecExecutor.__init__(self, browser, server_config, + timeout_multiplier=timeout_multiplier, + debug_info=debug_info) + self.webdriver_binary = webdriver_binary + self.webdriver_args = webdriver_args + ["--binary", binary] + self.capabilities = capabilities + self.protocol = RemoteMarionetteProtocol(self, browser) + + def is_alive(self): + return self.protocol.is_alive + + def on_environment_change(self, new_environment): + pass + + def do_test(self, test): + timeout = test.timeout * self.timeout_multiplier + extra_timeout + + success, data = WdspecRun(self.do_wdspec, + self.protocol.session_config, + test.abs_path, + timeout).run() + + if success: + return self.convert_result(test, data) + + return (test.result_cls(*data), []) + + def do_wdspec(self, session_config, path, timeout): + harness_result = ("OK", None) + subtest_results = pytestrunner.run(path, + self.server_config, + session_config, + timeout=timeout) + return (harness_result, subtest_results) + + def do_delayed_imports(self): + global pytestrunner + from . import pytestrunner diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorselenium.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorselenium.py new file mode 100644 index 000000000000..b5edbec2f6fa --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorselenium.py @@ -0,0 +1,260 @@ +import os +import socket +import sys +import threading +import time +import traceback +import urlparse +import uuid + +from .base import (ExecutorException, + Protocol, + RefTestExecutor, + RefTestImplementation, + TestExecutor, + TestharnessExecutor, + testharness_result_converter, + reftest_result_converter, + strip_server) +from ..testrunner import Stop + +here = os.path.join(os.path.split(__file__)[0]) + +webdriver = None +exceptions = None +RemoteConnection = None + +extra_timeout = 5 + +def do_delayed_imports(): + global webdriver + global exceptions + global RemoteConnection + from selenium import webdriver + from selenium.common import exceptions + from selenium.webdriver.remote.remote_connection import RemoteConnection + +class SeleniumProtocol(Protocol): + def __init__(self, executor, browser, capabilities, **kwargs): + do_delayed_imports() + + Protocol.__init__(self, executor, browser) + self.capabilities = capabilities + self.url = browser.webdriver_url + self.webdriver = None + + def setup(self, runner): + """Connect to browser via Selenium's WebDriver implementation.""" + self.runner = runner + self.logger.debug("Connecting to Selenium on URL: %s" % self.url) + + session_started = False + try: + self.webdriver = webdriver.Remote(command_executor=RemoteConnection(self.url.strip("/"), + resolve_ip=False), + desired_capabilities=self.capabilities) + except: + self.logger.warning( + "Connecting to Selenium failed:\n%s" % traceback.format_exc()) + else: + self.logger.debug("Selenium session started") + session_started = True + + if not session_started: + self.logger.warning("Failed to connect to Selenium") + self.executor.runner.send_message("init_failed") + else: + try: + self.after_connect() + except: + print >> sys.stderr, traceback.format_exc() + self.logger.warning( + "Failed to connect to navigate initial page") + self.executor.runner.send_message("init_failed") + else: + self.executor.runner.send_message("init_succeeded") + + def teardown(self): + self.logger.debug("Hanging up on Selenium session") + try: + self.webdriver.quit() + except: + pass + del self.webdriver + + def is_alive(self): + try: + # Get a simple property over the connection + self.webdriver.current_window_handle + # TODO what exception? + except (socket.timeout, exceptions.ErrorInResponseException): + return False + return True + + def after_connect(self): + self.load_runner("http") + + def load_runner(self, protocol): + url = urlparse.urljoin(self.executor.server_url(protocol), + "/testharness_runner.html") + self.logger.debug("Loading %s" % url) + self.webdriver.get(url) + self.webdriver.execute_script("document.title = '%s'" % + threading.current_thread().name.replace("'", '"')) + + def wait(self): + while True: + try: + self.webdriver.execute_async_script(""); + except exceptions.TimeoutException: + pass + except (socket.timeout, exceptions.NoSuchWindowException, + exceptions.ErrorInResponseException, IOError): + break + except Exception as e: + self.logger.error(traceback.format_exc(e)) + break + + +class SeleniumRun(object): + def __init__(self, func, webdriver, url, timeout): + self.func = func + self.result = None + self.webdriver = webdriver + self.url = url + self.timeout = timeout + self.result_flag = threading.Event() + + def run(self): + timeout = self.timeout + + try: + self.webdriver.set_script_timeout((timeout + extra_timeout) * 1000) + except exceptions.ErrorInResponseException: + self.logger.error("Lost WebDriver connection") + return Stop + + executor = threading.Thread(target=self._run) + executor.start() + + flag = self.result_flag.wait(timeout + 2 * extra_timeout) + if self.result is None: + assert not flag + self.result = False, ("EXTERNAL-TIMEOUT", None) + + return self.result + + def _run(self): + try: + self.result = True, self.func(self.webdriver, self.url, self.timeout) + except exceptions.TimeoutException: + self.result = False, ("EXTERNAL-TIMEOUT", None) + except (socket.timeout, exceptions.ErrorInResponseException): + self.result = False, ("CRASH", None) + except Exception as e: + message = getattr(e, "message", "") + if message: + message += "\n" + message += traceback.format_exc(e) + self.result = False, ("ERROR", e) + finally: + self.result_flag.set() + + +class SeleniumTestharnessExecutor(TestharnessExecutor): + def __init__(self, browser, server_config, timeout_multiplier=1, + close_after_done=True, capabilities=None, debug_info=None): + """Selenium-based executor for testharness.js tests""" + TestharnessExecutor.__init__(self, browser, server_config, + timeout_multiplier=timeout_multiplier, + debug_info=debug_info) + self.protocol = SeleniumProtocol(self, browser, capabilities) + with open(os.path.join(here, "testharness_webdriver.js")) as f: + self.script = f.read() + self.close_after_done = close_after_done + self.window_id = str(uuid.uuid4()) + + def is_alive(self): + return self.protocol.is_alive() + + def on_environment_change(self, new_environment): + if new_environment["protocol"] != self.last_environment["protocol"]: + self.protocol.load_runner(new_environment["protocol"]) + + def do_test(self, test): + url = self.test_url(test) + + success, data = SeleniumRun(self.do_testharness, + self.protocol.webdriver, + url, + test.timeout * self.timeout_multiplier).run() + + if success: + return self.convert_result(test, data) + + return (test.result_cls(*data), []) + + def do_testharness(self, webdriver, url, timeout): + return webdriver.execute_async_script( + self.script % {"abs_url": url, + "url": strip_server(url), + "window_id": self.window_id, + "timeout_multiplier": self.timeout_multiplier, + "timeout": timeout * 1000}) + +class SeleniumRefTestExecutor(RefTestExecutor): + def __init__(self, browser, server_config, timeout_multiplier=1, + screenshot_cache=None, close_after_done=True, + debug_info=None, capabilities=None): + """Selenium WebDriver-based executor for reftests""" + RefTestExecutor.__init__(self, + browser, + server_config, + screenshot_cache=screenshot_cache, + timeout_multiplier=timeout_multiplier, + debug_info=debug_info) + self.protocol = SeleniumProtocol(self, browser, + capabilities=capabilities) + self.implementation = RefTestImplementation(self) + self.close_after_done = close_after_done + self.has_window = False + + with open(os.path.join(here, "reftest.js")) as f: + self.script = f.read() + with open(os.path.join(here, "reftest-wait_webdriver.js")) as f: + self.wait_script = f.read() + + def is_alive(self): + return self.protocol.is_alive() + + def do_test(self, test): + self.logger.info("Test requires OS-level window focus") + + self.protocol.webdriver.set_window_size(600, 600) + + result = self.implementation.run_test(test) + + return self.convert_result(test, result) + + def screenshot(self, test, viewport_size, dpi): + # https://github.com/w3c/wptrunner/issues/166 + assert viewport_size is None + assert dpi is None + + return SeleniumRun(self._screenshot, + self.protocol.webdriver, + self.test_url(test), + test.timeout).run() + + def _screenshot(self, webdriver, url, timeout): + webdriver.get(url) + + webdriver.execute_async_script(self.wait_script) + + screenshot = webdriver.get_screenshot_as_base64() + + # strip off the data:img/png, part of the url + if screenshot.startswith("data:image/png;base64,"): + screenshot = screenshot.split(",", 1)[1] + + return screenshot diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorservo.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorservo.py new file mode 100644 index 000000000000..f002d93aa5f2 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorservo.py @@ -0,0 +1,368 @@ +import base64 +import hashlib +import httplib +import json +import os +import subprocess +import tempfile +import threading +import traceback +import urlparse +import uuid +from collections import defaultdict + +from mozprocess import ProcessHandler + +from .base import (ExecutorException, + Protocol, + RefTestImplementation, + testharness_result_converter, + reftest_result_converter, + WdspecExecutor) +from .process import ProcessTestExecutor +from ..browsers.base import browser_command +from ..wpttest import WdspecResult, WdspecSubtestResult +from ..webdriver_server import ServoDriverServer +from .executormarionette import WdspecRun + +pytestrunner = None +webdriver = None + +extra_timeout = 5 # seconds + +hosts_text = """127.0.0.1 web-platform.test +127.0.0.1 www.web-platform.test +127.0.0.1 www1.web-platform.test +127.0.0.1 www2.web-platform.test +127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test +127.0.0.1 xn--lve-6lad.web-platform.test +""" + +def make_hosts_file(): + hosts_fd, hosts_path = tempfile.mkstemp() + with os.fdopen(hosts_fd, "w") as f: + f.write(hosts_text) + return hosts_path + + +class ServoTestharnessExecutor(ProcessTestExecutor): + convert_result = testharness_result_converter + + def __init__(self, browser, server_config, timeout_multiplier=1, debug_info=None, + pause_after_test=False): + do_delayed_imports() + ProcessTestExecutor.__init__(self, browser, server_config, + timeout_multiplier=timeout_multiplier, + debug_info=debug_info) + self.pause_after_test = pause_after_test + self.result_data = None + self.result_flag = None + self.protocol = Protocol(self, browser) + self.hosts_path = make_hosts_file() + + def teardown(self): + try: + os.unlink(self.hosts_path) + except OSError: + pass + ProcessTestExecutor.teardown(self) + + def do_test(self, test): + self.result_data = None + self.result_flag = threading.Event() + + args = [ + "--hard-fail", "-u", "Servo/wptrunner", + "-Z", "replace-surrogates", "-z", self.test_url(test), + ] + for stylesheet in self.browser.user_stylesheets: + args += ["--user-stylesheet", stylesheet] + for pref, value in test.environment.get('prefs', {}).iteritems(): + args += ["--pref", "%s=%s" % (pref, value)] + if self.browser.ca_certificate_path: + args += ["--certificate-path", self.browser.ca_certificate_path] + args += self.browser.binary_args + debug_args, command = browser_command(self.binary, args, self.debug_info) + + self.command = command + + if self.pause_after_test: + self.command.remove("-z") + + self.command = debug_args + self.command + + env = os.environ.copy() + env["HOST_FILE"] = self.hosts_path + env["RUST_BACKTRACE"] = "1" + + + if not self.interactive: + self.proc = ProcessHandler(self.command, + processOutputLine=[self.on_output], + onFinish=self.on_finish, + env=env, + storeOutput=False) + self.proc.run() + else: + self.proc = subprocess.Popen(self.command, env=env) + + try: + timeout = test.timeout * self.timeout_multiplier + + # Now wait to get the output we expect, or until we reach the timeout + if not self.interactive and not self.pause_after_test: + wait_timeout = timeout + 5 + self.result_flag.wait(wait_timeout) + else: + wait_timeout = None + self.proc.wait() + + proc_is_running = True + + if self.result_flag.is_set(): + if self.result_data is not None: + result = self.convert_result(test, self.result_data) + else: + self.proc.wait() + result = (test.result_cls("CRASH", None), []) + proc_is_running = False + else: + result = (test.result_cls("TIMEOUT", None), []) + + + if proc_is_running: + if self.pause_after_test: + self.logger.info("Pausing until the browser exits") + self.proc.wait() + else: + self.proc.kill() + except KeyboardInterrupt: + self.proc.kill() + raise + + return result + + def on_output(self, line): + prefix = "ALERT: RESULT: " + line = line.decode("utf8", "replace") + if line.startswith(prefix): + self.result_data = json.loads(line[len(prefix):]) + self.result_flag.set() + else: + if self.interactive: + print line + else: + self.logger.process_output(self.proc.pid, + line, + " ".join(self.command)) + + def on_finish(self): + self.result_flag.set() + + +class TempFilename(object): + def __init__(self, directory): + self.directory = directory + self.path = None + + def __enter__(self): + self.path = os.path.join(self.directory, str(uuid.uuid4())) + return self.path + + def __exit__(self, *args, **kwargs): + try: + os.unlink(self.path) + except OSError: + pass + + +class ServoRefTestExecutor(ProcessTestExecutor): + convert_result = reftest_result_converter + + def __init__(self, browser, server_config, binary=None, timeout_multiplier=1, + screenshot_cache=None, debug_info=None, pause_after_test=False): + do_delayed_imports() + ProcessTestExecutor.__init__(self, + browser, + server_config, + timeout_multiplier=timeout_multiplier, + debug_info=debug_info) + + self.protocol = Protocol(self, browser) + self.screenshot_cache = screenshot_cache + self.implementation = RefTestImplementation(self) + self.tempdir = tempfile.mkdtemp() + self.hosts_path = make_hosts_file() + + def teardown(self): + try: + os.unlink(self.hosts_path) + except OSError: + pass + os.rmdir(self.tempdir) + ProcessTestExecutor.teardown(self) + + def screenshot(self, test, viewport_size, dpi): + full_url = self.test_url(test) + + with TempFilename(self.tempdir) as output_path: + debug_args, command = browser_command( + self.binary, + [ + "--hard-fail", "--exit", + "-u", "Servo/wptrunner", + "-Z", "disable-text-aa,load-webfonts-synchronously,replace-surrogates", + "--output=%s" % output_path, full_url + ] + self.browser.binary_args, + self.debug_info) + + for stylesheet in self.browser.user_stylesheets: + command += ["--user-stylesheet", stylesheet] + + for pref, value in test.environment.get('prefs', {}).iteritems(): + command += ["--pref", "%s=%s" % (pref, value)] + + command += ["--resolution", viewport_size or "800x600"] + + if self.browser.ca_certificate_path: + command += ["--certificate-path", self.browser.ca_certificate_path] + + if dpi: + command += ["--device-pixel-ratio", dpi] + + # Run ref tests in headless mode + command += ["-z"] + + self.command = debug_args + command + + env = os.environ.copy() + env["HOST_FILE"] = self.hosts_path + env["RUST_BACKTRACE"] = "1" + + if not self.interactive: + self.proc = ProcessHandler(self.command, + processOutputLine=[self.on_output], + env=env) + + + try: + self.proc.run() + timeout = test.timeout * self.timeout_multiplier + 5 + rv = self.proc.wait(timeout=timeout) + except KeyboardInterrupt: + self.proc.kill() + raise + else: + self.proc = subprocess.Popen(self.command, + env=env) + try: + rv = self.proc.wait() + except KeyboardInterrupt: + self.proc.kill() + raise + + if rv is None: + self.proc.kill() + return False, ("EXTERNAL-TIMEOUT", None) + + if rv != 0 or not os.path.exists(output_path): + return False, ("CRASH", None) + + with open(output_path) as f: + # Might need to strip variable headers or something here + data = f.read() + return True, base64.b64encode(data) + + def do_test(self, test): + result = self.implementation.run_test(test) + + return self.convert_result(test, result) + + def on_output(self, line): + line = line.decode("utf8", "replace") + if self.interactive: + print line + else: + self.logger.process_output(self.proc.pid, + line, + " ".join(self.command)) + +class ServoWdspecProtocol(Protocol): + def __init__(self, executor, browser): + self.do_delayed_imports() + Protocol.__init__(self, executor, browser) + self.session = None + self.server = None + + def setup(self, runner): + try: + self.server = ServoDriverServer(self.logger, binary=self.browser.binary, binary_args=self.browser.binary_args) + self.server.start(block=False) + self.logger.info( + "WebDriver HTTP server listening at %s" % self.server.url) + + self.logger.info( + "Establishing new WebDriver session with %s" % self.server.url) + self.session = webdriver.Session( + self.server.host, self.server.port, self.server.base_path) + except Exception: + self.logger.error(traceback.format_exc()) + self.executor.runner.send_message("init_failed") + else: + self.executor.runner.send_message("init_succeeded") + + def teardown(self): + if self.server is not None: + try: + if self.session.session_id is not None: + self.session.end() + except Exception: + pass + if self.server.is_alive: + self.server.stop() + + @property + def is_alive(self): + conn = httplib.HTTPConnection(self.server.host, self.server.port) + conn.request("HEAD", self.server.base_path + "invalid") + res = conn.getresponse() + return res.status == 404 + + def do_delayed_imports(self): + global pytestrunner, webdriver + from . import pytestrunner + import webdriver + + +class ServoWdspecExecutor(WdspecExecutor): + def __init__(self, browser, server_config, + timeout_multiplier=1, close_after_done=True, debug_info=None, + **kwargs): + WdspecExecutor.__init__(self, browser, server_config, + timeout_multiplier=timeout_multiplier, + debug_info=debug_info) + self.protocol = ServoWdspecProtocol(self, browser) + + def is_alive(self): + return self.protocol.is_alive + + def on_environment_change(self, new_environment): + pass + + def do_test(self, test): + timeout = test.timeout * self.timeout_multiplier + extra_timeout + + success, data = WdspecRun(self.do_wdspec, + self.protocol.session, + test.path, + timeout).run() + + if success: + return self.convert_result(test, data) + + return (test.result_cls(*data), []) + + def do_wdspec(self, session, path, timeout): + harness_result = ("OK", None) + subtest_results = pytestrunner.run(path, session, timeout=timeout) + return (harness_result, subtest_results) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorservodriver.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorservodriver.py new file mode 100644 index 000000000000..8dd331c75090 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorservodriver.py @@ -0,0 +1,257 @@ +import json +import os +import socket +import threading +import time +import traceback + +from .base import (Protocol, + RefTestExecutor, + RefTestImplementation, + TestharnessExecutor, + strip_server) +from ..testrunner import Stop + +webdriver = None + +here = os.path.join(os.path.split(__file__)[0]) + +extra_timeout = 5 + + +def do_delayed_imports(): + global webdriver + import webdriver + + +class ServoWebDriverProtocol(Protocol): + def __init__(self, executor, browser, capabilities, **kwargs): + do_delayed_imports() + Protocol.__init__(self, executor, browser) + self.capabilities = capabilities + self.host = browser.webdriver_host + self.port = browser.webdriver_port + self.session = None + + def setup(self, runner): + """Connect to browser via WebDriver.""" + self.runner = runner + + url = "http://%s:%d" % (self.host, self.port) + session_started = False + try: + self.session = webdriver.Session(self.host, self.port, + extension=webdriver.servo.ServoCommandExtensions) + self.session.start() + except: + self.logger.warning( + "Connecting with WebDriver failed:\n%s" % traceback.format_exc()) + else: + self.logger.debug("session started") + session_started = True + + if not session_started: + self.logger.warning("Failed to connect via WebDriver") + self.executor.runner.send_message("init_failed") + else: + self.executor.runner.send_message("init_succeeded") + + def teardown(self): + self.logger.debug("Hanging up on WebDriver session") + try: + self.session.end() + except: + pass + + def is_alive(self): + try: + # Get a simple property over the connection + self.session.window_handle + # TODO what exception? + except Exception: + return False + return True + + def after_connect(self): + pass + + def wait(self): + while True: + try: + self.session.execute_async_script("") + except webdriver.TimeoutException: + pass + except (socket.timeout, IOError): + break + except Exception as e: + self.logger.error(traceback.format_exc(e)) + break + + def on_environment_change(self, old_environment, new_environment): + #Unset all the old prefs + self.session.extension.reset_prefs(*old_environment.get("prefs", {}).keys()) + self.session.extension.set_prefs(new_environment.get("prefs", {})) + + +class ServoWebDriverRun(object): + def __init__(self, func, session, url, timeout, current_timeout=None): + self.func = func + self.result = None + self.session = session + self.url = url + self.timeout = timeout + self.result_flag = threading.Event() + + def run(self): + executor = threading.Thread(target=self._run) + executor.start() + + flag = self.result_flag.wait(self.timeout + extra_timeout) + if self.result is None: + assert not flag + self.result = False, ("EXTERNAL-TIMEOUT", None) + + return self.result + + def _run(self): + try: + self.result = True, self.func(self.session, self.url, self.timeout) + except webdriver.TimeoutException: + self.result = False, ("EXTERNAL-TIMEOUT", None) + except (socket.timeout, IOError): + self.result = False, ("CRASH", None) + except Exception as e: + message = getattr(e, "message", "") + if message: + message += "\n" + message += traceback.format_exc(e) + self.result = False, ("ERROR", e) + finally: + self.result_flag.set() + + +def timeout_func(timeout): + if timeout: + t0 = time.time() + return lambda: time.time() - t0 > timeout + extra_timeout + else: + return lambda: False + + +class ServoWebDriverTestharnessExecutor(TestharnessExecutor): + def __init__(self, browser, server_config, timeout_multiplier=1, + close_after_done=True, capabilities=None, debug_info=None): + TestharnessExecutor.__init__(self, browser, server_config, timeout_multiplier=1, + debug_info=None) + self.protocol = ServoWebDriverProtocol(self, browser, capabilities=capabilities) + with open(os.path.join(here, "testharness_servodriver.js")) as f: + self.script = f.read() + self.timeout = None + + def on_protocol_change(self, new_protocol): + pass + + def is_alive(self): + return self.protocol.is_alive() + + def do_test(self, test): + url = self.test_url(test) + + timeout = test.timeout * self.timeout_multiplier + extra_timeout + + if timeout != self.timeout: + try: + self.protocol.session.timeouts.script = timeout + self.timeout = timeout + except IOError: + self.logger.error("Lost webdriver connection") + return Stop + + success, data = ServoWebDriverRun(self.do_testharness, + self.protocol.session, + url, + timeout).run() + + if success: + return self.convert_result(test, data) + + return (test.result_cls(*data), []) + + def do_testharness(self, session, url, timeout): + session.url = url + result = json.loads( + session.execute_async_script( + self.script % {"abs_url": url, + "url": strip_server(url), + "timeout_multiplier": self.timeout_multiplier, + "timeout": timeout * 1000})) + # Prevent leaking every page in history until Servo develops a more sane + # page cache + session.back() + return result + + +class TimeoutError(Exception): + pass + + +class ServoWebDriverRefTestExecutor(RefTestExecutor): + def __init__(self, browser, server_config, timeout_multiplier=1, + screenshot_cache=None, capabilities=None, debug_info=None): + """Selenium WebDriver-based executor for reftests""" + RefTestExecutor.__init__(self, + browser, + server_config, + screenshot_cache=screenshot_cache, + timeout_multiplier=timeout_multiplier, + debug_info=debug_info) + self.protocol = ServoWebDriverProtocol(self, browser, + capabilities=capabilities) + self.implementation = RefTestImplementation(self) + self.timeout = None + with open(os.path.join(here, "reftest-wait_servodriver.js")) as f: + self.wait_script = f.read() + + def is_alive(self): + return self.protocol.is_alive() + + def do_test(self, test): + try: + result = self.implementation.run_test(test) + return self.convert_result(test, result) + except IOError: + return test.result_cls("CRASH", None), [] + except TimeoutError: + return test.result_cls("TIMEOUT", None), [] + except Exception as e: + message = getattr(e, "message", "") + if message: + message += "\n" + message += traceback.format_exc(e) + return test.result_cls("ERROR", message), [] + + def screenshot(self, test, viewport_size, dpi): + # https://github.com/w3c/wptrunner/issues/166 + assert viewport_size is None + assert dpi is None + + timeout = (test.timeout * self.timeout_multiplier + extra_timeout + if self.debug_info is None else None) + + if self.timeout != timeout: + try: + self.protocol.session.timeouts.script = timeout + self.timeout = timeout + except IOError: + self.logger.error("Lost webdriver connection") + return Stop + + return ServoWebDriverRun(self._screenshot, + self.protocol.session, + self.test_url(test), + timeout).run() + + def _screenshot(self, session, url, timeout): + session.url = url + session.execute_async_script(self.wait_script) + return session.screenshot() diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/process.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/process.py new file mode 100644 index 000000000000..fb8c17a96ba0 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/process.py @@ -0,0 +1,20 @@ +from .base import TestExecutor + + +class ProcessTestExecutor(TestExecutor): + def __init__(self, *args, **kwargs): + TestExecutor.__init__(self, *args, **kwargs) + self.binary = self.browser.binary + self.interactive = (False if self.debug_info is None + else self.debug_info.interactive) + + def setup(self, runner): + self.runner = runner + self.runner.send_message("init_succeeded") + return True + + def is_alive(self): + return True + + def do_test(self, test): + raise NotImplementedError diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/pytestrunner/__init__.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/pytestrunner/__init__.py new file mode 100644 index 000000000000..a92b3a8151da --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/pytestrunner/__init__.py @@ -0,0 +1 @@ +from .runner import run diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py new file mode 100644 index 000000000000..3a97d40e066a --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py @@ -0,0 +1,115 @@ +"""Provides interface to deal with pytest. + +Usage:: + + session = webdriver.client.Session("127.0.0.1", "4444", "/") + harness_result = ("OK", None) + subtest_results = pytestrunner.run("/path/to/test", session.url) + return (harness_result, subtest_results) +""" + +import errno +import json +import os +import shutil +import tempfile + + +pytest = None + + +def do_delayed_imports(): + global pytest + import pytest + + +def run(path, server_config, session_config, timeout=0): + """Run Python test at ``path`` in pytest. The provided ``session`` + is exposed as a fixture available in the scope of the test functions. + + :param path: Path to the test file. + :param session_config: dictionary of host, port,capabilities parameters + to pass through to the webdriver session + :param timeout: Duration before interrupting potentially hanging + tests. If 0, there is no timeout. + + :returns: List of subtest results, which are tuples of (test id, + status, message, stacktrace). + """ + + if pytest is None: + do_delayed_imports() + + recorder = SubtestResultRecorder() + + os.environ["WD_HOST"] = session_config["host"] + os.environ["WD_PORT"] = str(session_config["port"]) + os.environ["WD_CAPABILITIES"] = json.dumps(session_config["capabilities"]) + os.environ["WD_SERVER_CONFIG"] = json.dumps(server_config) + + plugins = [recorder] + + # TODO(ato): Deal with timeouts + + with TemporaryDirectory() as cache: + pytest.main(["--strict", # turn warnings into errors + "--verbose", # show each individual subtest + "--capture", "no", # enable stdout/stderr from tests + "--basetemp", cache, # temporary directory + path], + plugins=plugins) + + return recorder.results + + +class SubtestResultRecorder(object): + def __init__(self): + self.results = [] + + def pytest_runtest_logreport(self, report): + if report.passed and report.when == "call": + self.record_pass(report) + elif report.failed: + if report.when != "call": + self.record_error(report) + else: + self.record_fail(report) + elif report.skipped: + self.record_skip(report) + + def record_pass(self, report): + self.record(report.nodeid, "PASS") + + def record_fail(self, report): + self.record(report.nodeid, "FAIL", stack=report.longrepr) + + def record_error(self, report): + # error in setup/teardown + if report.when != "call": + message = "%s error" % report.when + self.record(report.nodeid, "ERROR", message, report.longrepr) + + def record_skip(self, report): + self.record(report.nodeid, "ERROR", + "In-test skip decorators are disallowed, " + "please use WPT metadata to ignore tests.") + + def record(self, test, status, message=None, stack=None): + if stack is not None: + stack = str(stack) + new_result = (test, status, message, stack) + self.results.append(new_result) + + +class TemporaryDirectory(object): + def __enter__(self): + self.path = tempfile.mkdtemp(prefix="pytest-") + return self.path + + def __exit__(self, *args): + try: + shutil.rmtree(self.path) + except OSError as e: + # no such file or directory + if e.errno != errno.ENOENT: + raise diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest-wait.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest-wait.js new file mode 100644 index 000000000000..7dd96df78031 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest-wait.js @@ -0,0 +1,18 @@ +function test(x) { + log("classList: " + root.classList); + if (!root.classList.contains("reftest-wait")) { + observer.disconnect(); + marionetteScriptFinished(); + } +} + +var root = document.documentElement; +var observer = new MutationObserver(test); + +observer.observe(root, {attributes: true}); + +if (document.readyState != "complete") { + onload = test +} else { + test(); +} diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest-wait_servodriver.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest-wait_servodriver.js new file mode 100644 index 000000000000..5848433b5409 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest-wait_servodriver.js @@ -0,0 +1,15 @@ +callback = arguments[arguments.length - 1]; + +function check_done() { + if (!document.documentElement.classList.contains('reftest-wait')) { + callback(); + } else { + setTimeout(check_done, 50); + } +} + +if (document.readyState === 'complete') { + check_done(); +} else { + addEventListener("load", check_done); +} diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest-wait_webdriver.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest-wait_webdriver.js new file mode 100644 index 000000000000..c3cc453bd491 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest-wait_webdriver.js @@ -0,0 +1,33 @@ +var callback = arguments[arguments.length - 1]; + +function test(x) { + if (!root.classList.contains("reftest-wait")) { + observer.disconnect(); + + // As of 2017-04-05, the Chromium web browser exhibits a rendering bug + // (https://bugs.chromium.org/p/chromium/issues/detail?id=708757) that + // produces instability during screen capture. The following use of + // `requestAnimationFrame` is intended as a short-term workaround, though + // it is not guaranteed to resolve the issue. + // + // For further detail, see: + // https://github.com/jugglinmike/chrome-screenshot-race/issues/1 + + requestAnimationFrame(function() { + requestAnimationFrame(function() { + callback(); + }); + }); + } +} + +var root = document.documentElement; +var observer = new MutationObserver(test); + +observer.observe(root, {attributes: true}); + +if (document.readyState != "complete") { + onload = test; +} else { + test(); +} diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest.js new file mode 100644 index 000000000000..5bd5c609cbd5 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/reftest.js @@ -0,0 +1 @@ +var win = window.open("about:blank", "test", "width=600,height=600"); diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/testharness_marionette.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/testharness_marionette.js new file mode 100644 index 000000000000..1cfa85f8949a --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/testharness_marionette.js @@ -0,0 +1,32 @@ +window.wrappedJSObject.timeout_multiplier = %(timeout_multiplier)d; +window.wrappedJSObject.explicit_timeout = %(explicit_timeout)d; + +window.wrappedJSObject.addEventListener("message", function listener(event) { + if (event.data.type != "complete") { + return; + } + window.wrappedJSObject.removeEventListener("message", listener); + clearTimeout(timer); + var tests = event.data.tests; + var status = event.data.status; + + var subtest_results = tests.map(function (x) { + return [x.name, x.status, x.message, x.stack] + }); + + marionetteScriptFinished(["%(url)s", + status.status, + status.message, + status.stack, + subtest_results]); +}, false); + +window.wrappedJSObject.win = window.open("%(abs_url)s", "%(window_id)s"); + +var timer = null; +if (%(timeout)s) { + timer = setTimeout(function() { + log("Timeout fired"); + window.wrappedJSObject.win.timeout(); + }, %(timeout)s); +} diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/testharness_servodriver.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/testharness_servodriver.js new file mode 100644 index 000000000000..d731cc04d701 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/testharness_servodriver.js @@ -0,0 +1,2 @@ +window.__wd_results_callback__ = arguments[arguments.length - 1]; +window.__wd_results_timer__ = setTimeout(timeout, %(timeout)s); diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/testharness_webdriver.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/testharness_webdriver.js new file mode 100644 index 000000000000..f5cbff9ef776 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/testharness_webdriver.js @@ -0,0 +1,29 @@ +var callback = arguments[arguments.length - 1]; +window.timeout_multiplier = %(timeout_multiplier)d; + +window.addEventListener("message", function f(event) { + if (event.data.type != "complete") { + return; + } + window.removeEventListener("message", f); + + var tests = event.data.tests; + var status = event.data.status; + + var subtest_results = tests.map(function(x) { + return [x.name, x.status, x.message, x.stack] + }); + clearTimeout(timer); + callback(["%(url)s", + status.status, + status.message, + status.stack, + subtest_results]); +}, false); + +window.win = window.open("%(abs_url)s", "%(window_id)s"); + +var timer = setTimeout(function() { + window.win.timeout(); + window.win.close(); +}, %(timeout)s); diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/expected.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/expected.py new file mode 100644 index 000000000000..f06abb946af1 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/expected.py @@ -0,0 +1,14 @@ +import os + + +def expected_path(metadata_path, test_path): + """Path to the expectation data file for a given test path. + + This is defined as metadata_path + relative_test_path + .ini + + :param metadata_path: Path to the root of the metadata directory + :param test_path: Relative path to the test file from the test root + """ + args = list(test_path.split("/")) + args[-1] += ".ini" + return os.path.join(metadata_path, *args) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/hosts.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/hosts.py new file mode 100644 index 000000000000..915c17f1b311 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/hosts.py @@ -0,0 +1,100 @@ +from __future__ import unicode_literals + + +class HostsLine(object): + def __init__(self, ip_address, canonical_hostname, aliases=None, comment=None): + self.ip_address = ip_address + self.canonical_hostname = canonical_hostname + self.aliases = aliases if aliases is not None else [] + self.comment = comment + if self.ip_address is None: + assert self.canonical_hostname is None + assert not self.aliases + assert self.comment is not None + + @classmethod + def from_string(cls, line): + if not line.strip(): + return + + line = line.strip() + + ip_address = None + canonical_hostname = None + aliases = [] + comment = None + + comment_parts = line.split("#", 1) + if len(comment_parts) > 1: + comment = comment_parts[1] + + data = comment_parts[0].strip() + + if data: + fields = data.split() + if len(fields) < 2: + raise ValueError("Invalid hosts line") + + ip_address = fields[0] + canonical_hostname = fields[1] + aliases = fields[2:] + + return cls(ip_address, canonical_hostname, aliases, comment) + + +class HostsFile(object): + def __init__(self): + self.data = [] + self.by_hostname = {} + + def set_host(self, host): + if host.canonical_hostname is None: + self.data.append(host) + elif host.canonical_hostname in self.by_hostname: + old_host = self.by_hostname[host.canonical_hostname] + old_host.ip_address = host.ip_address + old_host.aliases = host.aliases + old_host.comment = host.comment + else: + self.data.append(host) + self.by_hostname[host.canonical_hostname] = host + + @classmethod + def from_file(cls, f): + rv = cls() + for line in f: + host = HostsLine.from_string(line) + if host is not None: + rv.set_host(host) + return rv + + def to_string(self): + field_widths = [0, 0] + for line in self.data: + if line.ip_address is not None: + field_widths[0] = max(field_widths[0], len(line.ip_address)) + field_widths[1] = max(field_widths[1], len(line.canonical_hostname)) + + lines = [] + + for host in self.data: + line = "" + if host.ip_address is not None: + ip_string = host.ip_address.ljust(field_widths[0]) + hostname_str = host.canonical_hostname + if host.aliases: + hostname_str = "%s %s" % (hostname_str.ljust(field_widths[1]), + " ".join(host.aliases)) + line = "%s %s" % (ip_string, hostname_str) + if host.comment: + if line: + line += " " + line += "#%s" % host.comment + lines.append(line) + + lines.append("") + + return "\n".join(lines) + + def to_file(self, f): + f.write(self.to_string().encode("utf8")) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestexpected.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestexpected.py new file mode 100644 index 000000000000..fb5c1b1e7239 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestexpected.py @@ -0,0 +1,250 @@ +import os +import urlparse + +from wptmanifest.backends import static +from wptmanifest.backends.static import ManifestItem + +import expected + +"""Manifest structure used to store expected results of a test. + +Each manifest file is represented by an ExpectedManifest that +has one or more TestNode children, one per test in the manifest. +Each TestNode has zero or more SubtestNode children, one for each +known subtest of the test. +""" + +def data_cls_getter(output_node, visited_node): + # visited_node is intentionally unused + if output_node is None: + return ExpectedManifest + if isinstance(output_node, ExpectedManifest): + return TestNode + if isinstance(output_node, TestNode): + return SubtestNode + raise ValueError + + +def bool_prop(name, node): + """Boolean property""" + try: + return node.get(name) + except KeyError: + return None + + +def tags(node): + """Set of tags that have been applied to the test""" + try: + value = node.get("tags") + if isinstance(value, (str, unicode)): + return {value} + return set(value) + except KeyError: + return set() + + +def prefs(node): + def value(ini_value): + if isinstance(ini_value, (str, unicode)): + return tuple(ini_value.split(":", 1)) + else: + return (ini_value, None) + + try: + node_prefs = node.get("prefs") + if type(node_prefs) in (str, unicode): + prefs = {value(node_prefs)} + rv = dict(value(item) for item in node_prefs) + except KeyError: + rv = {} + return rv + + +class ExpectedManifest(ManifestItem): + def __init__(self, name, test_path, url_base): + """Object representing all the tests in a particular manifest + + :param name: Name of the AST Node associated with this object. + Should always be None since this should always be associated with + the root node of the AST. + :param test_path: Path of the test file associated with this manifest. + :param url_base: Base url for serving the tests in this manifest + """ + if name is not None: + raise ValueError("ExpectedManifest should represent the root node") + if test_path is None: + raise ValueError("ExpectedManifest requires a test path") + if url_base is None: + raise ValueError("ExpectedManifest requires a base url") + ManifestItem.__init__(self, name) + self.child_map = {} + self.test_path = test_path + self.url_base = url_base + + def append(self, child): + """Add a test to the manifest""" + ManifestItem.append(self, child) + self.child_map[child.id] = child + + def _remove_child(self, child): + del self.child_map[child.id] + ManifestItem.remove_child(self, child) + assert len(self.child_map) == len(self.children) + + def get_test(self, test_id): + """Get a test from the manifest by ID + + :param test_id: ID of the test to return.""" + return self.child_map.get(test_id) + + @property + def url(self): + return urlparse.urljoin(self.url_base, + "/".join(self.test_path.split(os.path.sep))) + + @property + def disabled(self): + return bool_prop("disabled", self) + + @property + def restart_after(self): + return bool_prop("restart-after", self) + + @property + def tags(self): + return tags(self) + + @property + def prefs(self): + return prefs(self) + + +class DirectoryManifest(ManifestItem): + @property + def disabled(self): + return bool_prop("disabled", self) + + @property + def restart_after(self): + return bool_prop("restart-after", self) + + @property + def tags(self): + return tags(self) + + @property + def prefs(self): + return prefs(self) + + +class TestNode(ManifestItem): + def __init__(self, name): + """Tree node associated with a particular test in a manifest + + :param name: name of the test""" + assert name is not None + ManifestItem.__init__(self, name) + self.updated_expected = [] + self.new_expected = [] + self.subtests = {} + self.default_status = None + self._from_file = True + + @property + def is_empty(self): + required_keys = set(["type"]) + if set(self._data.keys()) != required_keys: + return False + return all(child.is_empty for child in self.children) + + @property + def test_type(self): + return self.get("type") + + @property + def id(self): + return urlparse.urljoin(self.parent.url, self.name) + + @property + def disabled(self): + return bool_prop("disabled", self) + + @property + def restart_after(self): + return bool_prop("restart-after", self) + + @property + def tags(self): + return tags(self) + + @property + def prefs(self): + return prefs(self) + + def append(self, node): + """Add a subtest to the current test + + :param node: AST Node associated with the subtest""" + child = ManifestItem.append(self, node) + self.subtests[child.name] = child + + def get_subtest(self, name): + """Get the SubtestNode corresponding to a particular subtest, by name + + :param name: Name of the node to return""" + if name in self.subtests: + return self.subtests[name] + return None + + +class SubtestNode(TestNode): + def __init__(self, name): + """Tree node associated with a particular subtest in a manifest + + :param name: name of the subtest""" + TestNode.__init__(self, name) + + @property + def is_empty(self): + if self._data: + return False + return True + + +def get_manifest(metadata_root, test_path, url_base, run_info): + """Get the ExpectedManifest for a particular test path, or None if there is no + metadata stored for that test path. + + :param metadata_root: Absolute path to the root of the metadata directory + :param test_path: Path to the test(s) relative to the test root + :param url_base: Base url for serving the tests in this manifest + :param run_info: Dictionary of properties of the test run for which the expectation + values should be computed. + """ + manifest_path = expected.expected_path(metadata_root, test_path) + try: + with open(manifest_path) as f: + return static.compile(f, + run_info, + data_cls_getter=data_cls_getter, + test_path=test_path, + url_base=url_base) + except IOError: + return None + +def get_dir_manifest(path, run_info): + """Get the ExpectedManifest for a particular test path, or None if there is no + metadata stored for that test path. + + :param path: Full path to the ini file + :param run_info: Dictionary of properties of the test run for which the expectation + values should be computed. + """ + try: + with open(path) as f: + return static.compile(f, + run_info, + data_cls_getter=lambda x,y: DirectoryManifest) + except IOError: + return None diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestinclude.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestinclude.py new file mode 100644 index 000000000000..f7229d504f13 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestinclude.py @@ -0,0 +1,149 @@ +"""Manifest structure used to store paths that should be included in a test run. + +The manifest is represented by a tree of IncludeManifest objects, the root +representing the file and each subnode representing a subdirectory that should +be included or excluded. +""" +import glob +import os +import urlparse + +from wptmanifest.node import DataNode +from wptmanifest.backends import conditional +from wptmanifest.backends.conditional import ManifestItem + + +class IncludeManifest(ManifestItem): + def __init__(self, node): + """Node in a tree structure representing the paths + that should be included or excluded from the test run. + + :param node: AST Node corresponding to this Node. + """ + ManifestItem.__init__(self, node) + self.child_map = {} + + @classmethod + def create(cls): + """Create an empty IncludeManifest tree""" + node = DataNode(None) + return cls(node) + + def append(self, child): + ManifestItem.append(self, child) + self.child_map[child.name] = child + assert len(self.child_map) == len(self.children) + + def include(self, test): + """Return a boolean indicating whether a particular test should be + included in a test run, based on the IncludeManifest tree rooted on + this object. + + :param test: The test object""" + path_components = self._get_components(test.url) + return self._include(test, path_components) + + def _include(self, test, path_components): + if path_components: + next_path_part = path_components.pop() + if next_path_part in self.child_map: + return self.child_map[next_path_part]._include(test, path_components) + + node = self + while node: + try: + skip_value = self.get("skip", {"test_type": test.item_type}).lower() + assert skip_value in ("true", "false") + return skip_value != "true" + except KeyError: + if node.parent is not None: + node = node.parent + else: + # Include by default + return True + + def _get_components(self, url): + rv = [] + url_parts = urlparse.urlsplit(url) + variant = "" + if url_parts.query: + variant += "?" + url_parts.query + if url_parts.fragment: + variant += "#" + url_parts.fragment + if variant: + rv.append(variant) + rv.extend([item for item in reversed(url_parts.path.split("/")) if item]) + return rv + + def _add_rule(self, test_manifests, url, direction): + maybe_path = os.path.join(os.path.abspath(os.curdir), url) + rest, last = os.path.split(maybe_path) + fragment = query = None + if "#" in last: + last, fragment = last.rsplit("#", 1) + if "?" in last: + last, query = last.rsplit("?", 1) + + maybe_path = os.path.join(rest, last) + paths = glob.glob(maybe_path) + + if paths: + urls = [] + for path in paths: + for manifest, data in test_manifests.iteritems(): + found = False + rel_path = os.path.relpath(path, data["tests_path"]) + for test in manifest.iterpath(rel_path): + if not hasattr(test, "url"): + continue + url = test.url + if query or fragment: + parsed = urlparse.urlparse(url) + if ((query and query != parsed.query) or + (fragment and fragment != parsed.fragment)): + continue + urls.append(url) + found = True + if found: + break + else: + urls = [url] + + assert direction in ("include", "exclude") + + for url in urls: + components = self._get_components(url) + + node = self + while components: + component = components.pop() + if component not in node.child_map: + new_node = IncludeManifest(DataNode(component)) + node.append(new_node) + new_node.set("skip", node.get("skip", {})) + + node = node.child_map[component] + + skip = False if direction == "include" else True + node.set("skip", str(skip)) + + def add_include(self, test_manifests, url_prefix): + """Add a rule indicating that tests under a url path + should be included in test runs + + :param url_prefix: The url prefix to include + """ + return self._add_rule(test_manifests, url_prefix, "include") + + def add_exclude(self, test_manifests, url_prefix): + """Add a rule indicating that tests under a url path + should be excluded from test runs + + :param url_prefix: The url prefix to exclude + """ + return self._add_rule(test_manifests, url_prefix, "exclude") + + +def get_manifest(manifest_path): + with open(manifest_path) as f: + return conditional.compile(f, data_cls_getter=lambda x, y: IncludeManifest) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestupdate.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestupdate.py new file mode 100644 index 000000000000..07e623c5d1bb --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestupdate.py @@ -0,0 +1,460 @@ +import os +import urlparse +from collections import namedtuple, defaultdict + +from wptmanifest.node import (DataNode, ConditionalNode, BinaryExpressionNode, + BinaryOperatorNode, VariableNode, StringNode, NumberNode, + UnaryExpressionNode, UnaryOperatorNode, KeyValueNode) +from wptmanifest.backends import conditional +from wptmanifest.backends.conditional import ManifestItem + +import expected + +"""Manifest structure used to update the expected results of a test + +Each manifest file is represented by an ExpectedManifest that has one +or more TestNode children, one per test in the manifest. Each +TestNode has zero or more SubtestNode children, one for each known +subtest of the test. + +In these representations, conditionals expressions in the manifest are +not evaluated upfront but stored as python functions to be evaluated +at runtime. + +When a result for a test is to be updated set_result on the +[Sub]TestNode is called to store the new result, alongside the +existing conditional that result's run info matched, if any. Once all +new results are known, coalesce_expected is called to compute the new +set of results and conditionals. The AST of the underlying parsed manifest +is updated with the changes, and the result is serialised to a file. +""" + +class ConditionError(Exception): + pass + +Result = namedtuple("Result", ["run_info", "status"]) + + +def data_cls_getter(output_node, visited_node): + # visited_node is intentionally unused + if output_node is None: + return ExpectedManifest + elif isinstance(output_node, ExpectedManifest): + return TestNode + elif isinstance(output_node, TestNode): + return SubtestNode + else: + raise ValueError + + +class ExpectedManifest(ManifestItem): + def __init__(self, node, test_path=None, url_base=None, property_order=None, + boolean_properties=None): + """Object representing all the tests in a particular manifest + + :param node: AST Node associated with this object. If this is None, + a new AST is created to associate with this manifest. + :param test_path: Path of the test file associated with this manifest. + :param url_base: Base url for serving the tests in this manifest. + :param property_order: List of properties to use in expectation metadata + from most to least significant. + :param boolean_properties: Set of properties in property_order that should + be treated as boolean. + """ + if node is None: + node = DataNode(None) + ManifestItem.__init__(self, node) + self.child_map = {} + self.test_path = test_path + self.url_base = url_base + assert self.url_base is not None + self.modified = False + self.boolean_properties = boolean_properties + self.property_order = property_order + + def append(self, child): + ManifestItem.append(self, child) + if child.id in self.child_map: + print "Warning: Duplicate heading %s" % child.id + self.child_map[child.id] = child + + def _remove_child(self, child): + del self.child_map[child.id] + ManifestItem._remove_child(self, child) + + def get_test(self, test_id): + """Return a TestNode by test id, or None if no test matches + + :param test_id: The id of the test to look up""" + + return self.child_map[test_id] + + def has_test(self, test_id): + """Boolean indicating whether the current test has a known child test + with id test id + + :param test_id: The id of the test to look up""" + + return test_id in self.child_map + + @property + def url(self): + return urlparse.urljoin(self.url_base, + "/".join(self.test_path.split(os.path.sep))) + +class TestNode(ManifestItem): + def __init__(self, node): + """Tree node associated with a particular test in a manifest + + :param node: AST node associated with the test""" + + ManifestItem.__init__(self, node) + self.updated_expected = [] + self.new_expected = [] + self.subtests = {} + self.default_status = None + self._from_file = True + + @classmethod + def create(cls, test_type, test_id): + """Create a TestNode corresponding to a given test + + :param test_type: The type of the test + :param test_id: The id of the test""" + + url = test_id + name = url.split("/")[-1] + node = DataNode(name) + self = cls(node) + + self.set("type", test_type) + self._from_file = False + return self + + @property + def is_empty(self): + required_keys = set(["type"]) + if set(self._data.keys()) != required_keys: + return False + return all(child.is_empty for child in self.children) + + @property + def test_type(self): + """The type of the test represented by this TestNode""" + + return self.get("type", None) + + @property + def id(self): + """The id of the test represented by this TestNode""" + return urlparse.urljoin(self.parent.url, self.name) + + def disabled(self, run_info): + """Boolean indicating whether this test is disabled when run in an + environment with the given run_info + + :param run_info: Dictionary of run_info parameters""" + + return self.get("disabled", run_info) is not None + + def set_result(self, run_info, result): + """Set the result of the test in a particular run + + :param run_info: Dictionary of run_info parameters corresponding + to this run + :param result: Status of the test in this run""" + + if self.default_status is not None: + assert self.default_status == result.default_expected + else: + self.default_status = result.default_expected + + # Add this result to the list of results satisfying + # any condition in the list of updated results it matches + for (cond, values) in self.updated_expected: + if cond(run_info): + values.append(Result(run_info, result.status)) + if result.status != cond.value: + self.root.modified = True + break + else: + # We didn't find a previous value for this + self.new_expected.append(Result(run_info, result.status)) + self.root.modified = True + + def coalesce_expected(self): + """Update the underlying manifest AST for this test based on all the + added results. + + This will update existing conditionals if they got the same result in + all matching runs in the updated results, will delete existing conditionals + that get more than one different result in the updated run, and add new + conditionals for anything that doesn't match an existing conditional. + + Conditionals not matched by any added result are not changed.""" + + final_conditionals = [] + + try: + unconditional_status = self.get("expected") + except KeyError: + unconditional_status = self.default_status + + for conditional_value, results in self.updated_expected: + if not results: + # The conditional didn't match anything in these runs so leave it alone + final_conditionals.append(conditional_value) + elif all(results[0].status == result.status for result in results): + # All the new values for this conditional matched, so update the node + result = results[0] + if (result.status == unconditional_status and + conditional_value.condition_node is not None): + if "expected" in self: + self.remove_value("expected", conditional_value) + else: + conditional_value.value = result.status + final_conditionals.append(conditional_value) + elif conditional_value.condition_node is not None: + # Blow away the existing condition and rebuild from scratch + # This isn't sure to work if we have a conditional later that matches + # these values too, but we can hope, verify that we get the results + # we expect, and if not let a human sort it out + self.remove_value("expected", conditional_value) + self.new_expected.extend(results) + elif conditional_value.condition_node is None: + self.new_expected.extend(result for result in results + if result.status != unconditional_status) + + # It is an invariant that nothing in new_expected matches an existing + # condition except for the default condition + + if self.new_expected: + if all(self.new_expected[0].status == result.status + for result in self.new_expected) and not self.updated_expected: + status = self.new_expected[0].status + if status != self.default_status: + self.set("expected", status, condition=None) + final_conditionals.append(self._data["expected"][-1]) + else: + try: + conditionals = group_conditionals( + self.new_expected, + property_order=self.root.property_order, + boolean_properties=self.root.boolean_properties) + except ConditionError: + print "Conflicting test results for %s, cannot update" % self.root.test_path + return + for conditional_node, status in conditionals: + if status != unconditional_status: + self.set("expected", status, condition=conditional_node.children[0]) + final_conditionals.append(self._data["expected"][-1]) + + if ("expected" in self._data and + len(self._data["expected"]) > 0 and + self._data["expected"][-1].condition_node is None and + self._data["expected"][-1].value == self.default_status): + + self.remove_value("expected", self._data["expected"][-1]) + + if ("expected" in self._data and + len(self._data["expected"]) == 0): + for child in self.node.children: + if (isinstance(child, KeyValueNode) and + child.data == "expected"): + child.remove() + break + + def _add_key_value(self, node, values): + ManifestItem._add_key_value(self, node, values) + if node.data == "expected": + self.updated_expected = [] + for value in values: + self.updated_expected.append((value, [])) + + def clear_expected(self): + """Clear all the expected data for this test and all of its subtests""" + + self.updated_expected = [] + if "expected" in self._data: + for child in self.node.children: + if (isinstance(child, KeyValueNode) and + child.data == "expected"): + child.remove() + del self._data["expected"] + break + + for subtest in self.subtests.itervalues(): + subtest.clear_expected() + + def append(self, node): + child = ManifestItem.append(self, node) + self.subtests[child.name] = child + + def get_subtest(self, name): + """Return a SubtestNode corresponding to a particular subtest of + the current test, creating a new one if no subtest with that name + already exists. + + :param name: Name of the subtest""" + + if name in self.subtests: + return self.subtests[name] + else: + subtest = SubtestNode.create(name) + self.append(subtest) + return subtest + + +class SubtestNode(TestNode): + def __init__(self, node): + assert isinstance(node, DataNode) + TestNode.__init__(self, node) + + @classmethod + def create(cls, name): + node = DataNode(name) + self = cls(node) + return self + + @property + def is_empty(self): + if self._data: + return False + return True + + +def group_conditionals(values, property_order=None, boolean_properties=None): + """Given a list of Result objects, return a list of + (conditional_node, status) pairs representing the conditional + expressions that are required to match each status + + :param values: List of Results + :param property_order: List of properties to use in expectation metadata + from most to least significant. + :param boolean_properties: Set of properties in property_order that should + be treated as boolean.""" + + by_property = defaultdict(set) + for run_info, status in values: + for prop_name, prop_value in run_info.iteritems(): + by_property[(prop_name, prop_value)].add(status) + + if property_order is None: + property_order = ["debug", "os", "version", "processor", "bits"] + + if boolean_properties is None: + boolean_properties = set(["debug"]) + else: + boolean_properties = set(boolean_properties) + + # If we have more than one value, remove any properties that are common + # for all the values + if len(values) > 1: + for key, statuses in by_property.copy().iteritems(): + if len(statuses) == len(values): + del by_property[key] + if not by_property: + raise ConditionError + + properties = set(item[0] for item in by_property.iterkeys()) + include_props = [] + + for prop in property_order: + if prop in properties: + include_props.append(prop) + + conditions = {} + + for run_info, status in values: + prop_set = tuple((prop, run_info[prop]) for prop in include_props) + if prop_set in conditions: + continue + + expr = make_expr(prop_set, status, boolean_properties=boolean_properties) + conditions[prop_set] = (expr, status) + + return conditions.values() + + +def make_expr(prop_set, status, boolean_properties=None): + """Create an AST that returns the value ``status`` given all the + properties in prop_set match. + + :param prop_set: tuple of (property name, value) pairs for each + property in this expression and the value it must match + :param status: Status on RHS when all the given properties match + :param boolean_properties: Set of properties in property_order that should + be treated as boolean. + """ + root = ConditionalNode() + + assert len(prop_set) > 0 + + expressions = [] + for prop, value in prop_set: + number_types = (int, float, long) + value_cls = (NumberNode + if type(value) in number_types + else StringNode) + if prop not in boolean_properties: + expressions.append( + BinaryExpressionNode( + BinaryOperatorNode("=="), + VariableNode(prop), + value_cls(unicode(value)) + )) + else: + if value: + expressions.append(VariableNode(prop)) + else: + expressions.append( + UnaryExpressionNode( + UnaryOperatorNode("not"), + VariableNode(prop) + )) + if len(expressions) > 1: + prev = expressions[-1] + for curr in reversed(expressions[:-1]): + node = BinaryExpressionNode( + BinaryOperatorNode("and"), + curr, + prev) + prev = node + else: + node = expressions[0] + + root.append(node) + root.append(StringNode(status)) + + return root + + +def get_manifest(metadata_root, test_path, url_base, property_order=None, + boolean_properties=None): + """Get the ExpectedManifest for a particular test path, or None if there is no + metadata stored for that test path. + + :param metadata_root: Absolute path to the root of the metadata directory + :param test_path: Path to the test(s) relative to the test root + :param url_base: Base url for serving the tests in this manifest + :param property_order: List of properties to use in expectation metadata + from most to least significant. + :param boolean_properties: Set of properties in property_order that should + be treated as boolean.""" + manifest_path = expected.expected_path(metadata_root, test_path) + try: + with open(manifest_path) as f: + return compile(f, test_path, url_base, property_order=property_order, + boolean_properties=boolean_properties) + except IOError: + return None + + +def compile(manifest_file, test_path, url_base, property_order=None, + boolean_properties=None): + return conditional.compile(manifest_file, + data_cls_getter=data_cls_getter, + test_path=test_path, + url_base=url_base, + property_order=property_order, + boolean_properties=boolean_properties) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/metadata.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/metadata.py new file mode 100644 index 000000000000..7f0e29b2190c --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/metadata.py @@ -0,0 +1,351 @@ +import os +import shutil +import sys +import tempfile +import types +import uuid +from collections import defaultdict + +from mozlog import reader +from mozlog import structuredlog + +import expected +import manifestupdate +import testloader +import wptmanifest +import wpttest +from vcs import git +manifest = None # Module that will be imported relative to test_root +manifestitem = None + +logger = structuredlog.StructuredLogger("web-platform-tests") + + +def load_test_manifests(serve_root, test_paths): + do_delayed_imports(serve_root) + manifest_loader = testloader.ManifestLoader(test_paths, False) + return manifest_loader.load() + + +def update_expected(test_paths, serve_root, log_file_names, + rev_old=None, rev_new="HEAD", ignore_existing=False, + sync_root=None, property_order=None, boolean_properties=None): + """Update the metadata files for web-platform-tests based on + the results obtained in a previous run""" + + manifests = load_test_manifests(serve_root, test_paths) + + change_data = {} + + if sync_root is not None: + if rev_old is not None: + rev_old = git("rev-parse", rev_old, repo=sync_root).strip() + rev_new = git("rev-parse", rev_new, repo=sync_root).strip() + + if rev_old is not None: + change_data = load_change_data(rev_old, rev_new, repo=sync_root) + + + expected_map_by_manifest = update_from_logs(manifests, + *log_file_names, + ignore_existing=ignore_existing, + property_order=property_order, + boolean_properties=boolean_properties) + + for test_manifest, expected_map in expected_map_by_manifest.iteritems(): + url_base = manifests[test_manifest]["url_base"] + metadata_path = test_paths[url_base]["metadata_path"] + write_changes(metadata_path, expected_map) + + results_changed = [item.test_path for item in expected_map.itervalues() if item.modified] + + return unexpected_changes(manifests, change_data, results_changed) + + +def do_delayed_imports(serve_root): + global manifest, manifestitem + from manifest import manifest, item as manifestitem + + +def files_in_repo(repo_root): + return git("ls-tree", "-r", "--name-only", "HEAD").split("\n") + + +def rev_range(rev_old, rev_new, symmetric=False): + joiner = ".." if not symmetric else "..." + return "".join([rev_old, joiner, rev_new]) + + +def paths_changed(rev_old, rev_new, repo): + data = git("diff", "--name-status", rev_range(rev_old, rev_new), repo=repo) + lines = [tuple(item.strip() for item in line.strip().split("\t", 1)) + for line in data.split("\n") if line.strip()] + output = set(lines) + return output + + +def load_change_data(rev_old, rev_new, repo): + changes = paths_changed(rev_old, rev_new, repo) + rv = {} + status_keys = {"M": "modified", + "A": "new", + "D": "deleted"} + # TODO: deal with renames + for item in changes: + rv[item[1]] = status_keys[item[0]] + return rv + + +def unexpected_changes(manifests, change_data, files_changed): + files_changed = set(files_changed) + + root_manifest = None + for manifest, paths in manifests.iteritems(): + if paths["url_base"] == "/": + root_manifest = manifest + break + else: + return [] + + rv = [] + + return [fn for _, fn, _ in root_manifest if fn in files_changed and change_data.get(fn) != "M"] + +# For each testrun +# Load all files and scan for the suite_start entry +# Build a hash of filename: properties +# For each different set of properties, gather all chunks +# For each chunk in the set of chunks, go through all tests +# for each test, make a map of {conditionals: [(platform, new_value)]} +# Repeat for each platform +# For each test in the list of tests: +# for each conditional: +# If all the new values match (or there aren't any) retain that conditional +# If any new values mismatch mark the test as needing human attention +# Check if all the RHS values are the same; if so collapse the conditionals + + +def update_from_logs(manifests, *log_filenames, **kwargs): + ignore_existing = kwargs.get("ignore_existing", False) + property_order = kwargs.get("property_order") + boolean_properties = kwargs.get("boolean_properties") + + expected_map = {} + id_test_map = {} + + for test_manifest, paths in manifests.iteritems(): + expected_map_manifest, id_path_map_manifest = create_test_tree( + paths["metadata_path"], + test_manifest, + property_order=property_order, + boolean_properties=boolean_properties) + expected_map[test_manifest] = expected_map_manifest + id_test_map.update(id_path_map_manifest) + + updater = ExpectedUpdater(manifests, expected_map, id_test_map, + ignore_existing=ignore_existing) + for log_filename in log_filenames: + with open(log_filename) as f: + updater.update_from_log(f) + + for manifest_expected in expected_map.itervalues(): + for tree in manifest_expected.itervalues(): + for test in tree.iterchildren(): + for subtest in test.iterchildren(): + subtest.coalesce_expected() + test.coalesce_expected() + + return expected_map + +def directory_manifests(metadata_path): + rv = [] + for dirpath, dirname, filenames in os.walk(metadata_path): + if "__dir__.ini" in filenames: + rel_path = os.path.relpath(dirpath, metadata_path) + rv.append(os.path.join(rel_path, "__dir__.ini")) + return rv + +def write_changes(metadata_path, expected_map): + # First write the new manifest files to a temporary directory + temp_path = tempfile.mkdtemp(dir=os.path.split(metadata_path)[0]) + write_new_expected(temp_path, expected_map) + + # Keep all __dir__.ini files (these are not in expected_map because they + # aren't associated with a specific test) + keep_files = directory_manifests(metadata_path) + + # Copy all files in the root to the temporary location since + # these cannot be ini files + keep_files.extend(item for item in os.listdir(metadata_path) if + not os.path.isdir(os.path.join(metadata_path, item))) + + for item in keep_files: + dest_dir = os.path.dirname(os.path.join(temp_path, item)) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + shutil.copyfile(os.path.join(metadata_path, item), + os.path.join(temp_path, item)) + + # Then move the old manifest files to a new location + temp_path_2 = metadata_path + str(uuid.uuid4()) + os.rename(metadata_path, temp_path_2) + # Move the new files to the destination location and remove the old files + os.rename(temp_path, metadata_path) + shutil.rmtree(temp_path_2) + + +def write_new_expected(metadata_path, expected_map): + # Serialize the data back to a file + for tree in expected_map.itervalues(): + if not tree.is_empty: + manifest_str = wptmanifest.serialize(tree.node, skip_empty_data=True) + assert manifest_str != "" + path = expected.expected_path(metadata_path, tree.test_path) + dir = os.path.split(path)[0] + if not os.path.exists(dir): + os.makedirs(dir) + with open(path, "w") as f: + f.write(manifest_str) + + +class ExpectedUpdater(object): + def __init__(self, test_manifests, expected_tree, id_path_map, ignore_existing=False): + self.test_manifests = test_manifests + self.expected_tree = expected_tree + self.id_path_map = id_path_map + self.ignore_existing = ignore_existing + self.run_info = None + self.action_map = {"suite_start": self.suite_start, + "test_start": self.test_start, + "test_status": self.test_status, + "test_end": self.test_end} + self.tests_visited = {} + + self.test_cache = {} + + def update_from_log(self, log_file): + self.run_info = None + log_reader = reader.read(log_file) + reader.each_log(log_reader, self.action_map) + + def suite_start(self, data): + self.run_info = data["run_info"] + + def test_id(self, id): + if type(id) in types.StringTypes: + return id + else: + return tuple(id) + + def test_start(self, data): + test_id = self.test_id(data["test"]) + try: + test_manifest, test = self.id_path_map[test_id] + expected_node = self.expected_tree[test_manifest][test].get_test(test_id) + except KeyError: + print "Test not found %s, skipping" % test_id + return + self.test_cache[test_id] = expected_node + + if test_id not in self.tests_visited: + if self.ignore_existing: + expected_node.clear_expected() + self.tests_visited[test_id] = set() + + def test_status(self, data): + test_id = self.test_id(data["test"]) + test = self.test_cache.get(test_id) + if test is None: + return + test_cls = wpttest.manifest_test_cls[test.test_type] + + subtest = test.get_subtest(data["subtest"]) + + self.tests_visited[test.id].add(data["subtest"]) + + result = test_cls.subtest_result_cls( + data["subtest"], + data["status"], + data.get("message")) + + subtest.set_result(self.run_info, result) + + def test_end(self, data): + test_id = self.test_id(data["test"]) + test = self.test_cache.get(test_id) + if test is None: + return + test_cls = wpttest.manifest_test_cls[test.test_type] + + if data["status"] == "SKIP": + return + + result = test_cls.result_cls( + data["status"], + data.get("message")) + + test.set_result(self.run_info, result) + del self.test_cache[test_id] + + +def create_test_tree(metadata_path, test_manifest, property_order=None, + boolean_properties=None): + expected_map = {} + id_test_map = {} + exclude_types = frozenset(["stub", "helper", "manual", "support", "conformancechecker"]) + all_types = [item.item_type for item in manifestitem.__dict__.itervalues() + if type(item) == type and + issubclass(item, manifestitem.ManifestItem) and + item.item_type is not None] + include_types = set(all_types) - exclude_types + for _, test_path, tests in test_manifest.itertypes(*include_types): + expected_data = load_expected(test_manifest, metadata_path, test_path, tests, + property_order=property_order, + boolean_properties=boolean_properties) + if expected_data is None: + expected_data = create_expected(test_manifest, + test_path, + tests, + property_order=property_order, + boolean_properties=boolean_properties) + + for test in tests: + id_test_map[test.id] = (test_manifest, test) + expected_map[test] = expected_data + + return expected_map, id_test_map + + +def create_expected(test_manifest, test_path, tests, property_order=None, + boolean_properties=None): + expected = manifestupdate.ExpectedManifest(None, test_path, test_manifest.url_base, + property_order=property_order, + boolean_properties=boolean_properties) + for test in tests: + expected.append(manifestupdate.TestNode.create(test.item_type, test.id)) + return expected + + +def load_expected(test_manifest, metadata_path, test_path, tests, property_order=None, + boolean_properties=None): + expected_manifest = manifestupdate.get_manifest(metadata_path, + test_path, + test_manifest.url_base, + property_order=property_order, + boolean_properties=boolean_properties) + if expected_manifest is None: + return + + tests_by_id = {item.id: item for item in tests} + + # Remove expected data for tests that no longer exist + for test in expected_manifest.iterchildren(): + if not test.id in tests_by_id: + test.remove() + + # Add tests that don't have expected data + for test in tests: + if not expected_manifest.has_test(test.id): + expected_manifest.append(manifestupdate.TestNode.create(test.item_type, test.id)) + + return expected_manifest diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/products.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/products.py new file mode 100644 index 000000000000..c077f95dfd95 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/products.py @@ -0,0 +1,69 @@ +import os +import importlib +import imp + +from .browsers import product_list + +def products_enabled(config): + names = config.get("products", {}).keys() + if not names: + return product_list + else: + return names + +def product_module(config, product): + here = os.path.join(os.path.split(__file__)[0]) + product_dir = os.path.join(here, "browsers") + + if product not in products_enabled(config): + raise ValueError("Unknown product %s" % product) + + path = config.get("products", {}).get(product, None) + if path: + module = imp.load_source('wptrunner.browsers.' + product, path) + else: + module = importlib.import_module("wptrunner.browsers." + product) + + if not hasattr(module, "__wptrunner__"): + raise ValueError("Product module does not define __wptrunner__ variable") + + return module + + +def load_product(config, product): + module = product_module(config, product) + data = module.__wptrunner__ + + check_args = getattr(module, data["check_args"]) + browser_cls = getattr(module, data["browser"]) + browser_kwargs = getattr(module, data["browser_kwargs"]) + executor_kwargs = getattr(module, data["executor_kwargs"]) + env_options = getattr(module, data["env_options"])() + env_extras = getattr(module, data["env_extras"]) + run_info_extras = (getattr(module, data["run_info_extras"]) + if "run_info_extras" in data else lambda **kwargs:{}) + + executor_classes = {} + for test_type, cls_name in data["executor"].iteritems(): + cls = getattr(module, cls_name) + executor_classes[test_type] = cls + + return (check_args, + browser_cls, browser_kwargs, + executor_classes, executor_kwargs, + env_options, env_extras, run_info_extras) + + +def load_product_update(config, product): + """Return tuple of (property_order, boolean_properties) indicating the + run_info properties to use when constructing the expectation data for + this product. None for either key indicates that the default keys + appropriate for distinguishing based on platform will be used.""" + + module = product_module(config, product) + data = module.__wptrunner__ + + update_properties = (getattr(module, data["update_properties"])() + if "update_properties" in data else (None, None)) + + return update_properties diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/reduce.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/reduce.py new file mode 100644 index 000000000000..d245ee3602b9 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/reduce.py @@ -0,0 +1,193 @@ +import sys +import tempfile +from cStringIO import StringIO +from collections import defaultdict + +import wptrunner +import wpttest + +from mozlog import commandline, reader + +logger = None + + +def setup_logging(args, defaults): + global logger + logger = commandline.setup_logging("web-platform-tests-unstable", args, defaults) + wptrunner.setup_stdlib_logger() + + for name in args.keys(): + if name.startswith("log_"): + args.pop(name) + + return logger + + +def group(items, size): + rv = [] + i = 0 + while i < len(items): + rv.append(items[i:i + size]) + i += size + + return rv + + +def next_power_of_two(num): + rv = 1 + while rv < num: + rv = rv << 1 + return rv + + +class Reducer(object): + def __init__(self, target, **kwargs): + self.target = target + + self.test_type = kwargs["test_types"][0] + run_info = wpttest.get_run_info(kwargs["metadata_root"], + kwargs["product"], + debug=False) + test_filter = wptrunner.TestFilter(include=kwargs["include"]) + self.test_loader = wptrunner.TestLoader(kwargs["tests_root"], + kwargs["metadata_root"], + [self.test_type], + run_info, + manifest_filer=test_filter) + if kwargs["repeat"] == 1: + logger.critical("Need to specify --repeat with more than one repetition") + sys.exit(1) + self.kwargs = kwargs + + def run(self): + all_tests = self.get_initial_tests() + + tests = all_tests[:-1] + target_test = [all_tests[-1]] + + if self.unstable(target_test): + return target_test + + if not self.unstable(all_tests): + return [] + + chunk_size = next_power_of_two(int(len(tests) / 2)) + logger.debug("Using chunk size %i" % chunk_size) + + while chunk_size >= 1: + logger.debug("%i tests remain" % len(tests)) + chunks = group(tests, chunk_size) + chunk_results = [None] * len(chunks) + + for i, chunk in enumerate(chunks): + logger.debug("Running chunk %i/%i of size %i" % (i + 1, len(chunks), chunk_size)) + trial_tests = [] + chunk_str = "" + for j, inc_chunk in enumerate(chunks): + if i != j and chunk_results[j] in (None, False): + chunk_str += "+" + trial_tests.extend(inc_chunk) + else: + chunk_str += "-" + logger.debug("Using chunks %s" % chunk_str) + trial_tests.extend(target_test) + + chunk_results[i] = self.unstable(trial_tests) + + # if i == len(chunks) - 2 and all(item is False for item in chunk_results[:-1]): + # Dangerous? optimisation that if you got stability for 0..N-1 chunks + # it must be unstable with the Nth chunk + # chunk_results[i+1] = True + # continue + + new_tests = [] + keep_str = "" + for result, chunk in zip(chunk_results, chunks): + if not result: + keep_str += "+" + new_tests.extend(chunk) + else: + keep_str += "-" + + logger.debug("Keeping chunks %s" % keep_str) + + tests = new_tests + + chunk_size = int(chunk_size / 2) + + return tests + target_test + + def unstable(self, tests): + logger.debug("Running with %i tests" % len(tests)) + + self.test_loader.tests = {self.test_type: tests} + + stdout, stderr = sys.stdout, sys.stderr + sys.stdout = StringIO() + sys.stderr = StringIO() + + with tempfile.NamedTemporaryFile() as f: + args = self.kwargs.copy() + args["log_raw"] = [f] + args["capture_stdio"] = False + wptrunner.setup_logging(args, {}) + wptrunner.run_tests(test_loader=self.test_loader, **args) + wptrunner.logger.remove_handler(wptrunner.logger.handlers[0]) + is_unstable = self.log_is_unstable(f) + + sys.stdout, sys.stderr = stdout, stderr + + logger.debug("Result was unstable with chunk removed" + if is_unstable else "stable") + + return is_unstable + + def log_is_unstable(self, log_f): + log_f.seek(0) + + statuses = defaultdict(set) + + def handle_status(item): + if item["test"] == self.target: + statuses[item["subtest"]].add(item["status"]) + + def handle_end(item): + if item["test"] == self.target: + statuses[None].add(item["status"]) + + reader.each_log(reader.read(log_f), + {"test_status": handle_status, + "test_end": handle_end}) + + logger.debug(str(statuses)) + + if not statuses: + logger.error("Didn't get any useful output from wptrunner") + log_f.seek(0) + for item in reader.read(log_f): + logger.debug(item) + return None + + return any(len(item) > 1 for item in statuses.itervalues()) + + def get_initial_tests(self): + # Need to pass in arguments + + all_tests = self.test_loader.tests[self.test_type] + tests = [] + for item in all_tests: + tests.append(item) + if item.url == self.target: + break + + logger.debug("Starting with tests: %s" % ("\n".join(item.id for item in tests))) + + return tests + + +def do_reduce(**kwargs): + target = kwargs.pop("target") + reducer = Reducer(target, **kwargs) + + unstable_set = reducer.run() + return unstable_set diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servo.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servo.js new file mode 100644 index 000000000000..b672aea9a254 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servo.js @@ -0,0 +1,17 @@ +var props = {output:%(output)d}; +var start_loc = document.createElement('a'); +start_loc.href = location.href; +setup(props); + +add_completion_callback(function (tests, harness_status) { + var id = start_loc.pathname + start_loc.search + start_loc.hash; + console.log("ALERT: RESULT: " + JSON.stringify([ + id, + harness_status.status, + harness_status.message, + harness_status.stack, + tests.map(function(t) { + return [t.name, t.status, t.message, t.stack] + }), + ])); +}); diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servodriver.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servodriver.js new file mode 100644 index 000000000000..c88841360470 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servodriver.js @@ -0,0 +1,23 @@ +setup({output:%(output)d}); + +add_completion_callback(function() { + add_completion_callback(function (tests, status) { + var subtest_results = tests.map(function(x) { + return [x.name, x.status, x.message, x.stack] + }); + var id = location.pathname + location.search + location.hash; + var results = JSON.stringify([id, + status.status, + status.message, + status.stack, + subtest_results]); + (function done() { + if (window.__wd_results_callback__) { + clearTimeout(__wd_results_timer__); + __wd_results_callback__(results) + } else { + setTimeout(done, 20); + } + })() + }) +}); diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport.js new file mode 100644 index 000000000000..62ddaffb443c --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport.js @@ -0,0 +1,13 @@ +var props = {output:%(output)d, + explicit_timeout: true, + message_events: ["completion"]}; + +if (window.opener && "timeout_multiplier" in window.opener) { + props["timeout_multiplier"] = window.opener.timeout_multiplier; +} + +if (window.opener && window.opener.explicit_timeout) { + props["explicit_timeout"] = window.opener.explicit_timeout; +} + +setup(props); diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/testloader.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/testloader.py new file mode 100644 index 000000000000..74dce4aafe33 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testloader.py @@ -0,0 +1,638 @@ +import hashlib +import json +import os +import urlparse +from abc import ABCMeta, abstractmethod +from Queue import Empty +from collections import defaultdict, OrderedDict, deque +from multiprocessing import Queue + +import manifestinclude +import manifestexpected +import wpttest +from mozlog import structured + +manifest = None +manifest_update = None + +def do_delayed_imports(): + # This relies on an already loaded module having set the sys.path correctly :( + global manifest, manifest_update + from manifest import manifest + from manifest import update as manifest_update + +class TestChunker(object): + def __init__(self, total_chunks, chunk_number): + self.total_chunks = total_chunks + self.chunk_number = chunk_number + assert self.chunk_number <= self.total_chunks + self.logger = structured.get_default_logger() + assert self.logger + + def __call__(self, manifest): + raise NotImplementedError + + +class Unchunked(TestChunker): + def __init__(self, *args, **kwargs): + TestChunker.__init__(self, *args, **kwargs) + assert self.total_chunks == 1 + + def __call__(self, manifest): + for item in manifest: + yield item + + +class HashChunker(TestChunker): + def __call__(self, manifest): + chunk_index = self.chunk_number - 1 + for test_type, test_path, tests in manifest: + h = int(hashlib.md5(test_path).hexdigest(), 16) + if h % self.total_chunks == chunk_index: + yield test_type, test_path, tests + + +class DirectoryHashChunker(TestChunker): + """Like HashChunker except the directory is hashed. + + This ensures that all tests in the same directory end up in the same + chunk. + """ + def __call__(self, manifest): + chunk_index = self.chunk_number - 1 + for test_type, test_path, tests in manifest: + h = int(hashlib.md5(os.path.dirname(test_path)).hexdigest(), 16) + if h % self.total_chunks == chunk_index: + yield test_type, test_path, tests + + +class EqualTimeChunker(TestChunker): + def _group_by_directory(self, manifest_items): + """Split the list of manifest items into a ordered dict that groups tests in + so that anything in the same subdirectory beyond a depth of 3 is in the same + group. So all tests in a/b/c, a/b/c/d and a/b/c/e will be grouped together + and separate to tests in a/b/f + + Returns: tuple (ordered dict of {test_dir: PathData}, total estimated runtime) + """ + + class PathData(object): + def __init__(self, path): + self.path = path + self.time = 0 + self.tests = [] + + by_dir = OrderedDict() + total_time = 0 + + for i, (test_type, test_path, tests) in enumerate(manifest_items): + test_dir = tuple(os.path.split(test_path)[0].split(os.path.sep)[:3]) + + if not test_dir in by_dir: + by_dir[test_dir] = PathData(test_dir) + + data = by_dir[test_dir] + time = sum(wpttest.DEFAULT_TIMEOUT if test.timeout != + "long" else wpttest.LONG_TIMEOUT for test in tests) + data.time += time + total_time += time + data.tests.append((test_type, test_path, tests)) + + return by_dir, total_time + + def _maybe_remove(self, chunks, i, direction): + """Trial removing a chunk from one chunk to an adjacent one. + + :param chunks: - the list of all chunks + :param i: - the chunk index in the list of chunks to try removing from + :param direction: either "next" if we are going to move from the end to + the subsequent chunk, or "prev" if we are going to move + from the start into the previous chunk. + + :returns bool: Did a chunk get moved?""" + source_chunk = chunks[i] + if direction == "next": + target_chunk = chunks[i+1] + path_index = -1 + move_func = lambda: target_chunk.appendleft(source_chunk.pop()) + elif direction == "prev": + target_chunk = chunks[i-1] + path_index = 0 + move_func = lambda: target_chunk.append(source_chunk.popleft()) + else: + raise ValueError("Unexpected move direction %s" % direction) + + return self._maybe_move(source_chunk, target_chunk, path_index, move_func) + + def _maybe_add(self, chunks, i, direction): + """Trial adding a chunk from one chunk to an adjacent one. + + :param chunks: - the list of all chunks + :param i: - the chunk index in the list of chunks to try adding to + :param direction: either "next" if we are going to remove from the + the subsequent chunk, or "prev" if we are going to remove + from the the previous chunk. + + :returns bool: Did a chunk get moved?""" + target_chunk = chunks[i] + if direction == "next": + source_chunk = chunks[i+1] + path_index = 0 + move_func = lambda: target_chunk.append(source_chunk.popleft()) + elif direction == "prev": + source_chunk = chunks[i-1] + path_index = -1 + move_func = lambda: target_chunk.appendleft(source_chunk.pop()) + else: + raise ValueError("Unexpected move direction %s" % direction) + + return self._maybe_move(source_chunk, target_chunk, path_index, move_func) + + def _maybe_move(self, source_chunk, target_chunk, path_index, move_func): + """Move from one chunk to another, assess the change in badness, + and keep the move iff it decreases the badness score. + + :param source_chunk: chunk to move from + :param target_chunk: chunk to move to + :param path_index: 0 if we are moving from the start or -1 if we are moving from the + end + :param move_func: Function that actually moves between chunks""" + if len(source_chunk.paths) <= 1: + return False + + move_time = source_chunk.paths[path_index].time + + new_source_badness = self._badness(source_chunk.time - move_time) + new_target_badness = self._badness(target_chunk.time + move_time) + + delta_badness = ((new_source_badness + new_target_badness) - + (source_chunk.badness + target_chunk.badness)) + if delta_badness < 0: + move_func() + return True + + return False + + def _badness(self, time): + """Metric of badness for a specific chunk + + :param time: the time for a specific chunk""" + return (time - self.expected_time)**2 + + def _get_chunk(self, manifest_items): + by_dir, total_time = self._group_by_directory(manifest_items) + + if len(by_dir) < self.total_chunks: + raise ValueError("Tried to split into %i chunks, but only %i subdirectories included" % ( + self.total_chunks, len(by_dir))) + + self.expected_time = float(total_time) / self.total_chunks + + chunks = self._create_initial_chunks(by_dir) + + while True: + # Move a test from one chunk to the next until doing so no longer + # reduces the badness + got_improvement = self._update_chunks(chunks) + if not got_improvement: + break + + self.logger.debug(self.expected_time) + for i, chunk in chunks.iteritems(): + self.logger.debug("%i: %i, %i" % (i + 1, chunk.time, chunk.badness)) + + assert self._all_tests(by_dir) == self._chunked_tests(chunks) + + return self._get_tests(chunks) + + @staticmethod + def _all_tests(by_dir): + """Return a set of all tests in the manifest from a grouping by directory""" + return set(x[0] for item in by_dir.itervalues() + for x in item.tests) + + @staticmethod + def _chunked_tests(chunks): + """Return a set of all tests in the manifest from the chunk list""" + return set(x[0] for chunk in chunks.itervalues() + for path in chunk.paths + for x in path.tests) + + + def _create_initial_chunks(self, by_dir): + """Create an initial unbalanced list of chunks. + + :param by_dir: All tests in the manifest grouped by subdirectory + :returns list: A list of Chunk objects""" + + class Chunk(object): + def __init__(self, paths, index): + """List of PathData objects that together form a single chunk of + tests""" + self.paths = deque(paths) + self.time = sum(item.time for item in paths) + self.index = index + + def appendleft(self, path): + """Add a PathData object to the start of the chunk""" + self.paths.appendleft(path) + self.time += path.time + + def append(self, path): + """Add a PathData object to the end of the chunk""" + self.paths.append(path) + self.time += path.time + + def pop(self): + """Remove PathData object from the end of the chunk""" + assert len(self.paths) > 1 + self.time -= self.paths[-1].time + return self.paths.pop() + + def popleft(self): + """Remove PathData object from the start of the chunk""" + assert len(self.paths) > 1 + self.time -= self.paths[0].time + return self.paths.popleft() + + @property + def badness(self_): + """Badness metric for this chunk""" + return self._badness(self_.time) + + initial_size = len(by_dir) / self.total_chunks + chunk_boundaries = [initial_size * i + for i in xrange(self.total_chunks)] + [len(by_dir)] + + chunks = OrderedDict() + for i, lower in enumerate(chunk_boundaries[:-1]): + upper = chunk_boundaries[i + 1] + paths = by_dir.values()[lower:upper] + chunks[i] = Chunk(paths, i) + + assert self._all_tests(by_dir) == self._chunked_tests(chunks) + + return chunks + + def _update_chunks(self, chunks): + """Run a single iteration of the chunk update algorithm. + + :param chunks: - List of chunks + """ + #TODO: consider replacing this with a heap + sorted_chunks = sorted(chunks.values(), key=lambda x:-x.badness) + got_improvement = False + for chunk in sorted_chunks: + if chunk.time < self.expected_time: + f = self._maybe_add + else: + f = self._maybe_remove + + if chunk.index == 0: + order = ["next"] + elif chunk.index == self.total_chunks - 1: + order = ["prev"] + else: + if chunk.time < self.expected_time: + # First try to add a test from the neighboring chunk with the + # greatest total time + if chunks[chunk.index + 1].time > chunks[chunk.index - 1].time: + order = ["next", "prev"] + else: + order = ["prev", "next"] + else: + # First try to remove a test and add to the neighboring chunk with the + # lowest total time + if chunks[chunk.index + 1].time > chunks[chunk.index - 1].time: + order = ["prev", "next"] + else: + order = ["next", "prev"] + + for direction in order: + if f(chunks, chunk.index, direction): + got_improvement = True + break + + if got_improvement: + break + + return got_improvement + + def _get_tests(self, chunks): + """Return the list of tests corresponding to the chunk number we are running. + + :param chunks: List of chunks""" + tests = [] + for path in chunks[self.chunk_number - 1].paths: + tests.extend(path.tests) + + return tests + + def __call__(self, manifest_iter): + manifest = list(manifest_iter) + tests = self._get_chunk(manifest) + for item in tests: + yield item + + +class TestFilter(object): + def __init__(self, test_manifests, include=None, exclude=None, manifest_path=None): + if manifest_path is not None and include is None: + self.manifest = manifestinclude.get_manifest(manifest_path) + else: + self.manifest = manifestinclude.IncludeManifest.create() + + if include: + self.manifest.set("skip", "true") + for item in include: + self.manifest.add_include(test_manifests, item) + + if exclude: + for item in exclude: + self.manifest.add_exclude(test_manifests, item) + + def __call__(self, manifest_iter): + for test_type, test_path, tests in manifest_iter: + include_tests = set() + for test in tests: + if self.manifest.include(test): + include_tests.add(test) + + if include_tests: + yield test_type, test_path, include_tests + +class TagFilter(object): + def __init__(self, tags): + self.tags = set(tags) + + def __call__(self, test_iter): + for test in test_iter: + if test.tags & self.tags: + yield test + +class ManifestLoader(object): + def __init__(self, test_paths, force_manifest_update=False): + do_delayed_imports() + self.test_paths = test_paths + self.force_manifest_update = force_manifest_update + self.logger = structured.get_default_logger() + if self.logger is None: + self.logger = structured.structuredlog.StructuredLogger("ManifestLoader") + + def load(self): + rv = {} + for url_base, paths in self.test_paths.iteritems(): + manifest_file = self.load_manifest(url_base=url_base, + **paths) + path_data = {"url_base": url_base} + path_data.update(paths) + rv[manifest_file] = path_data + return rv + + def create_manifest(self, manifest_path, tests_path, url_base="/"): + self.update_manifest(manifest_path, tests_path, url_base, recreate=True) + + def update_manifest(self, manifest_path, tests_path, url_base="/", + recreate=False): + self.logger.info("Updating test manifest %s" % manifest_path) + + json_data = None + if not recreate: + try: + with open(manifest_path) as f: + json_data = json.load(f) + except IOError: + #If the existing file doesn't exist just create one from scratch + pass + + if not json_data: + manifest_file = manifest.Manifest(url_base) + else: + try: + manifest_file = manifest.Manifest.from_json(tests_path, json_data) + except manifest.ManifestVersionMismatch: + manifest_file = manifest.Manifest(url_base) + + manifest_update.update(tests_path, manifest_file, True) + + manifest.write(manifest_file, manifest_path) + + def load_manifest(self, tests_path, metadata_path, url_base="/"): + manifest_path = os.path.join(metadata_path, "MANIFEST.json") + if (not os.path.exists(manifest_path) or + self.force_manifest_update): + self.update_manifest(manifest_path, tests_path, url_base) + manifest_file = manifest.load(tests_path, manifest_path) + if manifest_file.url_base != url_base: + self.logger.info("Updating url_base in manifest from %s to %s" % (manifest_file.url_base, + url_base)) + manifest_file.url_base = url_base + manifest.write(manifest_file, manifest_path) + + return manifest_file + +def iterfilter(filters, iter): + for f in filters: + iter = f(iter) + for item in iter: + yield item + +class TestLoader(object): + def __init__(self, + test_manifests, + test_types, + run_info, + manifest_filters=None, + meta_filters=None, + chunk_type="none", + total_chunks=1, + chunk_number=1, + include_https=True): + + self.test_types = test_types + self.run_info = run_info + + self.manifest_filters = manifest_filters if manifest_filters is not None else [] + self.meta_filters = meta_filters if meta_filters is not None else [] + + self.manifests = test_manifests + self.tests = None + self.disabled_tests = None + self.include_https = include_https + + self.chunk_type = chunk_type + self.total_chunks = total_chunks + self.chunk_number = chunk_number + + self.chunker = {"none": Unchunked, + "hash": HashChunker, + "dir_hash": DirectoryHashChunker, + "equal_time": EqualTimeChunker}[chunk_type](total_chunks, + chunk_number) + + self._test_ids = None + + self.directory_manifests = {} + + self._load_tests() + + @property + def test_ids(self): + if self._test_ids is None: + self._test_ids = [] + for test_dict in [self.disabled_tests, self.tests]: + for test_type in self.test_types: + self._test_ids += [item.id for item in test_dict[test_type]] + return self._test_ids + + def get_test(self, manifest_test, inherit_metadata, test_metadata): + if test_metadata is not None: + inherit_metadata.append(test_metadata) + test_metadata = test_metadata.get_test(manifest_test.id) + + return wpttest.from_manifest(manifest_test, inherit_metadata, test_metadata) + + def load_dir_metadata(self, test_manifest, metadata_path, test_path): + rv = [] + path_parts = os.path.dirname(test_path).split(os.path.sep) + for i in xrange(1,len(path_parts) + 1): + path = os.path.join(metadata_path, os.path.sep.join(path_parts[:i]), "__dir__.ini") + if path not in self.directory_manifests: + self.directory_manifests[path] = manifestexpected.get_dir_manifest(path, + self.run_info) + manifest = self.directory_manifests[path] + if manifest is not None: + rv.append(manifest) + return rv + + def load_metadata(self, test_manifest, metadata_path, test_path): + inherit_metadata = self.load_dir_metadata(test_manifest, metadata_path, test_path) + test_metadata = manifestexpected.get_manifest( + metadata_path, test_path, test_manifest.url_base, self.run_info) + return inherit_metadata, test_metadata + + def iter_tests(self): + manifest_items = [] + + for manifest in sorted(self.manifests.keys(), key=lambda x:x.url_base): + manifest_iter = iterfilter(self.manifest_filters, + manifest.itertypes(*self.test_types)) + manifest_items.extend(manifest_iter) + + if self.chunker is not None: + manifest_items = self.chunker(manifest_items) + + for test_type, test_path, tests in manifest_items: + manifest_file = iter(tests).next().manifest + metadata_path = self.manifests[manifest_file]["metadata_path"] + inherit_metadata, test_metadata = self.load_metadata(manifest_file, metadata_path, test_path) + + for test in iterfilter(self.meta_filters, + self.iter_wpttest(inherit_metadata, test_metadata, tests)): + yield test_path, test_type, test + + def iter_wpttest(self, inherit_metadata, test_metadata, tests): + for manifest_test in tests: + yield self.get_test(manifest_test, inherit_metadata, test_metadata) + + def _load_tests(self): + """Read in the tests from the manifest file and add them to a queue""" + tests = {"enabled":defaultdict(list), + "disabled":defaultdict(list)} + + for test_path, test_type, test in self.iter_tests(): + enabled = not test.disabled() + if not self.include_https and test.environment["protocol"] == "https": + enabled = False + key = "enabled" if enabled else "disabled" + tests[key][test_type].append(test) + + self.tests = tests["enabled"] + self.disabled_tests = tests["disabled"] + + def groups(self, test_types, chunk_type="none", total_chunks=1, chunk_number=1): + groups = set() + + for test_type in test_types: + for test in self.tests[test_type]: + group = test.url.split("/")[1] + groups.add(group) + + return groups + + +class TestSource(object): + __metaclass__ = ABCMeta + + @abstractmethod + def queue_tests(self, test_queue): + pass + + @abstractmethod + def requeue_test(self, test): + pass + + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + pass + + +class SingleTestSource(TestSource): + def __init__(self, test_queue): + self.test_queue = test_queue + + @classmethod + def queue_tests(cls, test_queue, test_type, tests): + for test in tests[test_type]: + test_queue.put(test) + + def get_queue(self): + if self.test_queue.empty(): + return None + return self.test_queue + + def requeue_test(self, test): + self.test_queue.put(test) + +class PathGroupedSource(TestSource): + def __init__(self, test_queue): + self.test_queue = test_queue + self.current_queue = None + + @classmethod + def queue_tests(cls, test_queue, test_type, tests, depth=None): + if depth is True: + depth = None + + prev_path = None + group = None + + for test in tests[test_type]: + path = urlparse.urlsplit(test.url).path.split("/")[1:-1][:depth] + if path != prev_path: + group = [] + test_queue.put(group) + prev_path = path + + group.append(test) + + def get_queue(self): + if not self.current_queue or self.current_queue.empty(): + try: + data = self.test_queue.get(block=True, timeout=1) + self.current_queue = Queue() + for item in data: + self.current_queue.put(item) + except Empty: + return None + + return self.current_queue + + def requeue_test(self, test): + self.current_queue.put(test) + + def __exit__(self, *args, **kwargs): + if self.current_queue: + self.current_queue.close() diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py new file mode 100644 index 000000000000..e422cfefec61 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py @@ -0,0 +1,766 @@ +from __future__ import unicode_literals + +import multiprocessing +import sys +import threading +import traceback +from Queue import Empty +from collections import namedtuple +from multiprocessing import Process, current_process, Queue + +from mozlog import structuredlog + +# Special value used as a sentinal in various commands +Stop = object() + + +class MessageLogger(object): + def __init__(self, message_func): + self.send_message = message_func + + def _log_data(self, action, **kwargs): + self.send_message("log", action, kwargs) + + def process_output(self, process, data, command): + self._log_data("process_output", process=process, data=data, command=command) + + +def _log_func(level_name): + def log(self, message): + self._log_data(level_name.lower(), message=message) + log.__doc__ = """Log a message with level %s + +:param message: The string message to log +""" % level_name + log.__name__ = str(level_name).lower() + return log + +# Create all the methods on StructuredLog for debug levels +for level_name in structuredlog.log_levels: + setattr(MessageLogger, level_name.lower(), _log_func(level_name)) + + +class TestRunner(object): + def __init__(self, command_queue, result_queue, executor): + """Class implementing the main loop for running tests. + + This class delegates the job of actually running a test to the executor + that is passed in. + + :param command_queue: subprocess.Queue used to send commands to the + process + :param result_queue: subprocess.Queue used to send results to the + parent TestManager process + :param executor: TestExecutor object that will actually run a test. + """ + self.command_queue = command_queue + self.result_queue = result_queue + + self.executor = executor + self.name = current_process().name + self.logger = MessageLogger(self.send_message) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.teardown() + + def setup(self): + self.logger.debug("Executor setup") + self.executor.setup(self) + self.logger.debug("Executor setup done") + + def teardown(self): + self.executor.teardown() + self.send_message("runner_teardown") + self.result_queue = None + self.command_queue = None + self.browser = None + + def run(self): + """Main loop accepting commands over the pipe and triggering + the associated methods""" + self.setup() + commands = {"run_test": self.run_test, + "stop": self.stop, + "wait": self.wait} + while True: + command, args = self.command_queue.get() + try: + rv = commands[command](*args) + except Exception: + self.send_message("error", + "Error running command %s with arguments %r:\n%s" % + (command, args, traceback.format_exc())) + else: + if rv is Stop: + break + + def stop(self): + return Stop + + def run_test(self, test): + try: + return self.executor.run_test(test) + except Exception: + self.logger.critical(traceback.format_exc()) + raise + + def wait(self): + self.executor.protocol.wait() + self.send_message("wait_finished") + + def send_message(self, command, *args): + self.result_queue.put((command, args)) + + +def start_runner(runner_command_queue, runner_result_queue, + executor_cls, executor_kwargs, + executor_browser_cls, executor_browser_kwargs, + stop_flag): + """Launch a TestRunner in a new process""" + try: + browser = executor_browser_cls(**executor_browser_kwargs) + executor = executor_cls(browser, **executor_kwargs) + with TestRunner(runner_command_queue, runner_result_queue, executor) as runner: + try: + runner.run() + except KeyboardInterrupt: + stop_flag.set() + except Exception: + runner_result_queue.put(("log", ("critical", {"message": traceback.format_exc()}))) + print >> sys.stderr, traceback.format_exc() + stop_flag.set() + finally: + runner_command_queue = None + runner_result_queue = None + + +manager_count = 0 + + +def next_manager_number(): + global manager_count + local = manager_count = manager_count + 1 + return local + + +class BrowserManager(object): + init_lock = threading.Lock() + + def __init__(self, logger, browser, command_queue, no_timeout=False): + self.logger = logger + self.browser = browser + self.no_timeout = no_timeout + + self.started = False + + self.init_timer = None + + def init(self): + """Launch the browser that is being tested, + and the TestRunner process that will run the tests.""" + # It seems that this lock is helpful to prevent some race that otherwise + # sometimes stops the spawned processes initalising correctly, and + # leaves this thread hung + if self.init_timer is not None: + self.init_timer.cancel() + + self.logger.debug("Init called, starting browser and runner") + + with self.init_lock: + # Guard against problems initialising the browser or the browser + # remote control method + if not self.no_timeout: + self.init_timer = threading.Timer(self.browser.init_timeout, + self.init_timeout) + try: + if self.init_timer is not None: + self.init_timer.start() + self.browser.start() + self.browser_pid = self.browser.pid() + except: + self.logger.warning("Failure during init %s" % traceback.format_exc()) + if self.init_timer is not None: + self.init_timer.cancel() + self.logger.error(traceback.format_exc()) + succeeded = False + else: + succeeded = True + self.started = True + + return succeeded + + def send_message(self, command, *args): + self.command_queue.put((command, args)) + + def init_timeout(self): + # This is called from a seperate thread, so we send a message to the + # main loop so we get back onto the manager thread + self.logger.debug("init_failed called from timer") + self.send_message("init_failed") + + def after_init(self): + """Callback when we have started the browser, started the remote + control connection, and we are ready to start testing.""" + if self.init_timer is not None: + self.init_timer.cancel() + + def stop(self, force=False): + self.browser.stop(force=force) + self.started = False + + def cleanup(self): + if self.init_timer is not None: + self.init_timer.cancel() + self.browser.cleanup() + + def log_crash(self, test_id): + self.browser.log_crash(process=self.browser_pid, test=test_id) + + def is_alive(self): + return self.browser.is_alive() + + +class _RunnerManagerState(object): + before_init = namedtuple("before_init", []) + initalizing = namedtuple("initalizing_browser", + ["test", "test_queue", "failure_count"]) + running = namedtuple("running", ["test", "test_queue"]) + restarting = namedtuple("restarting", ["test", "test_queue"]) + error = namedtuple("error", []) + stop = namedtuple("stop", []) + + +RunnerManagerState = _RunnerManagerState() + + +class TestRunnerManager(threading.Thread): + init_lock = threading.Lock() + + def __init__(self, suite_name, tests, test_source_cls, browser_cls, browser_kwargs, + executor_cls, executor_kwargs, stop_flag, pause_after_test=False, + pause_on_unexpected=False, restart_on_unexpected=True, debug_info=None): + """Thread that owns a single TestRunner process and any processes required + by the TestRunner (e.g. the Firefox binary). + + TestRunnerManagers are responsible for launching the browser process and the + runner process, and for logging the test progress. The actual test running + is done by the TestRunner. In particular they: + + * Start the binary of the program under test + * Start the TestRunner + * Tell the TestRunner to start a test, if any + * Log that the test started + * Log the test results + * Take any remedial action required e.g. restart crashed or hung + processes + """ + self.suite_name = suite_name + + self.tests = tests + self.test_source_cls = test_source_cls + self.test_queue = None + + self.browser_cls = browser_cls + self.browser_kwargs = browser_kwargs + + self.executor_cls = executor_cls + self.executor_kwargs = executor_kwargs + + self.test_source = None + + # Flags used to shut down this thread if we get a sigint + self.parent_stop_flag = stop_flag + self.child_stop_flag = multiprocessing.Event() + + self.pause_after_test = pause_after_test + self.pause_on_unexpected = pause_on_unexpected + self.restart_on_unexpected = restart_on_unexpected + self.debug_info = debug_info + + self.manager_number = next_manager_number() + + self.command_queue = Queue() + self.remote_queue = Queue() + + self.test_runner_proc = None + + threading.Thread.__init__(self, name="Thread-TestrunnerManager-%i" % self.manager_number) + # This is started in the actual new thread + self.logger = None + + self.unexpected_count = 0 + + # This may not really be what we want + self.daemon = True + + self.max_restarts = 5 + + self.browser = None + + def run(self): + """Main loop for the TestManager. + + TestManagers generally receive commands from their + TestRunner updating them on the status of a test. They + may also have a stop flag set by the main thread indicating + that the manager should shut down the next time the event loop + spins.""" + self.logger = structuredlog.StructuredLogger(self.suite_name) + with self.browser_cls(self.logger, **self.browser_kwargs) as browser, self.test_source_cls(self.tests) as test_source: + self.browser = BrowserManager(self.logger, + browser, + self.command_queue, + no_timeout=self.debug_info is not None) + self.test_source = test_source + dispatch = { + RunnerManagerState.before_init: self.start_init, + RunnerManagerState.initalizing: self.init, + RunnerManagerState.running: self.run_test, + RunnerManagerState.restarting: self.restart_runner + } + + self.state = RunnerManagerState.before_init() + end_states = (RunnerManagerState.stop, + RunnerManagerState.error) + + try: + while not isinstance(self.state, end_states): + f = dispatch.get(self.state.__class__) + while f: + self.logger.debug("Dispatch %s" % f.__name__) + if self.should_stop(): + return + new_state = f() + if new_state is None: + break + self.state = new_state + self.logger.debug("new state: %s" % self.state.__class__.__name__) + if isinstance(self.state, end_states): + return + f = dispatch.get(self.state.__class__) + + new_state = None + while new_state is None: + new_state = self.wait_event() + if self.should_stop(): + return + self.state = new_state + self.logger.debug("new state: %s" % self.state.__class__.__name__) + except Exception as e: + self.logger.error(traceback.format_exc(e)) + raise + finally: + self.logger.debug("TestRunnerManager main loop terminating, starting cleanup") + clean = isinstance(self.state, RunnerManagerState.stop) + self.stop_runner(force=not clean) + self.teardown() + self.logger.debug("TestRunnerManager main loop terminated") + + def wait_event(self): + dispatch = { + RunnerManagerState.before_init: {}, + RunnerManagerState.initalizing: + { + "init_succeeded": self.init_succeeded, + "init_failed": self.init_failed, + }, + RunnerManagerState.running: + { + "test_ended": self.test_ended, + "wait_finished": self.wait_finished, + }, + RunnerManagerState.restarting: {}, + RunnerManagerState.error: {}, + RunnerManagerState.stop: {}, + None: { + "runner_teardown": self.runner_teardown, + "log": self.log, + "error": self.error + } + } + try: + command, data = self.command_queue.get(True, 1) + except IOError: + self.logger.error("Got IOError from poll") + return RunnerManagerState.restarting(0) + except Empty: + if (self.debug_info and self.debug_info.interactive and + self.browser.started and not self.browser.is_alive()): + self.logger.debug("Debugger exited") + return RunnerManagerState.stop() + + if (isinstance(self.state, RunnerManagerState.running) and + not self.test_runner_proc.is_alive()): + if not self.command_queue.empty(): + # We got a new message so process that + return + + # If we got to here the runner presumably shut down + # unexpectedly + self.logger.info("Test runner process shut down") + + if self.state.test is not None: + # This could happen if the test runner crashed for some other + # reason + # Need to consider the unlikely case where one test causes the + # runner process to repeatedly die + self.logger.critical("Last test did not complete") + return RunnerManagerState.error() + self.logger.warning("More tests found, but runner process died, restarting") + return RunnerManagerState.restarting(0) + else: + f = (dispatch.get(self.state.__class__, {}).get(command) or + dispatch.get(None, {}).get(command)) + if not f: + self.logger.warning("Got command %s in state %s" % + (command, self.state.__class__.__name__)) + return + return f(*data) + + + def should_stop(self): + return self.child_stop_flag.is_set() or self.parent_stop_flag.is_set() + + def start_init(self): + test, test_queue = self.get_next_test() + if test is None: + return RunnerManagerState.stop() + else: + return RunnerManagerState.initalizing(test, test_queue, 0) + + def init(self): + assert isinstance(self.state, RunnerManagerState.initalizing) + if self.state.failure_count > self.max_restarts: + self.logger.error("Max restarts exceeded") + return RunnerManagerState.error() + + result = self.browser.init() + if result is Stop: + return RunnerManagerState.error() + elif not result: + return RunnerManagerState.initalizing(self.state.test, + self.state.test_queue, + self.state.failure_count + 1) + else: + self.start_test_runner() + + def start_test_runner(self): + # Note that we need to be careful to start the browser before the + # test runner to ensure that any state set when the browser is started + # can be passed in to the test runner. + assert isinstance(self.state, RunnerManagerState.initalizing) + assert self.command_queue is not None + assert self.remote_queue is not None + self.logger.info("Starting runner") + executor_browser_cls, executor_browser_kwargs = self.browser.browser.executor_browser() + + args = (self.remote_queue, + self.command_queue, + self.executor_cls, + self.executor_kwargs, + executor_browser_cls, + executor_browser_kwargs, + self.child_stop_flag) + self.test_runner_proc = Process(target=start_runner, + args=args, + name="Thread-TestRunner-%i" % self.manager_number) + self.test_runner_proc.start() + self.logger.debug("Test runner started") + # Now we wait for either an init_succeeded event or an init_failed event + + def init_succeeded(self): + assert isinstance(self.state, RunnerManagerState.initalizing) + self.browser.after_init() + return RunnerManagerState.running(self.state.test, + self.state.test_queue) + + def init_failed(self): + assert isinstance(self.state, RunnerManagerState.initalizing) + self.browser.after_init() + self.stop_runner(force=True) + return RunnerManagerState.initalizing(self.state.test, + self.state.test_queue, + self.state.failure_count + 1) + + def get_next_test(self, test_queue=None): + test = None + while test is None: + if test_queue is None: + test_queue = self.test_source.get_queue() + if test_queue is None: + self.logger.info("No more tests") + return None, None + try: + # Need to block here just to allow for contention with other processes + test = test_queue.get(block=True, timeout=1) + except Empty: + pass + return test, test_queue + + def run_test(self): + assert isinstance(self.state, RunnerManagerState.running) + assert self.state.test is not None + + self.logger.test_start(self.state.test.id) + self.send_message("run_test", self.state.test) + + def test_ended(self, test, results): + """Handle the end of a test. + + Output the result of each subtest, and the result of the overall + harness to the logs. + """ + assert isinstance(self.state, RunnerManagerState.running) + assert test == self.state.test + # Write the result of each subtest + file_result, test_results = results + subtest_unexpected = False + for result in test_results: + if test.disabled(result.name): + continue + expected = test.expected(result.name) + is_unexpected = expected != result.status + + if is_unexpected: + self.unexpected_count += 1 + self.logger.debug("Unexpected count in this thread %i" % self.unexpected_count) + subtest_unexpected = True + self.logger.test_status(test.id, + result.name, + result.status, + message=result.message, + expected=expected, + stack=result.stack) + + # TODO: consider changing result if there is a crash dump file + + # Write the result of the test harness + expected = test.expected() + status = file_result.status if file_result.status != "EXTERNAL-TIMEOUT" else "TIMEOUT" + is_unexpected = expected != status + if is_unexpected: + self.unexpected_count += 1 + self.logger.debug("Unexpected count in this thread %i" % self.unexpected_count) + if status == "CRASH": + self.browser.log_crash(test.id) + + self.logger.test_end(test.id, + status, + message=file_result.message, + expected=expected, + extra=file_result.extra) + + restart_before_next = (test.restart_after or + file_result.status in ("CRASH", "EXTERNAL-TIMEOUT") or + ((subtest_unexpected or is_unexpected) + and self.restart_on_unexpected)) + + if (self.pause_after_test or + (self.pause_on_unexpected and (subtest_unexpected or is_unexpected))): + self.logger.info("Pausing until the browser exits") + self.send_message("wait") + else: + return self.after_test_end(restart_before_next) + + def wait_finished(self): + assert isinstance(self.state, RunnerManagerState.running) + # The browser should be stopped already, but this ensures we do any post-stop + # processing + self.logger.debug("Wait finished") + + return self.after_test_end(True) + + def after_test_end(self, restart): + assert isinstance(self.state, RunnerManagerState.running) + test, test_queue = self.get_next_test() + if test is None: + return RunnerManagerState.stop() + if test_queue != self.state.test_queue: + # We are starting a new group of tests, so force a restart + restart = True + if restart: + return RunnerManagerState.restarting(test, test_queue) + else: + return RunnerManagerState.running(test, test_queue) + + def restart_runner(self): + """Stop and restart the TestRunner""" + assert isinstance(self.state, RunnerManagerState.restarting) + self.stop_runner() + return RunnerManagerState.initalizing(self.state.test, self.state.test_queue, 0) + + def log(self, action, kwargs): + getattr(self.logger, action)(**kwargs) + + def error(self, message): + self.logger.error(message) + self.restart_runner() + + def stop_runner(self, force=False): + """Stop the TestRunner and the browser binary.""" + if self.test_runner_proc is None: + return + + if self.test_runner_proc.is_alive(): + self.send_message("stop") + try: + self.browser.stop(force=force) + self.ensure_runner_stopped() + finally: + self.cleanup() + + def teardown(self): + self.logger.debug("teardown in testrunnermanager") + self.test_runner_proc = None + self.command_queue.close() + self.remote_queue.close() + self.command_queue = None + self.remote_queue = None + + def ensure_runner_stopped(self): + self.logger.debug("ensure_runner_stopped") + if self.test_runner_proc is None: + return + + self.logger.debug("waiting for runner process to end") + self.test_runner_proc.join(10) + self.logger.debug("After join") + if self.test_runner_proc.is_alive(): + # This might leak a file handle from the queue + self.logger.warning("Forcibly terminating runner process") + self.test_runner_proc.terminate() + self.test_runner_proc.join(10) + else: + self.logger.debug("Testrunner exited with code %i" % self.test_runner_proc.exitcode) + + def runner_teardown(self): + self.ensure_runner_stopped() + return RunnerManagerState.stop() + + def send_message(self, command, *args): + self.remote_queue.put((command, args)) + + def cleanup(self): + self.logger.debug("TestManager cleanup") + if self.browser: + self.browser.cleanup() + while True: + try: + self.logger.warning(" ".join(map(repr, self.command_queue.get_nowait()))) + except Empty: + break + +class TestQueue(object): + def __init__(self, test_source_cls, test_type, tests, **kwargs): + self.queue = None + self.test_source_cls = test_source_cls + self.test_type = test_type + self.tests = tests + self.kwargs = kwargs + + def __enter__(self): + if not self.tests[self.test_type]: + return None + + self.queue = Queue() + has_tests = self.test_source_cls.queue_tests(self.queue, + self.test_type, + self.tests, + **self.kwargs) + # There is a race condition that means sometimes we continue + # before the tests have been written to the underlying pipe. + # Polling the pipe for data here avoids that + self.queue._reader.poll(10) + assert not self.queue.empty() + return self.queue + + def __exit__(self, *args, **kwargs): + if self.queue is not None: + self.queue.close() + self.queue = None + + +class ManagerGroup(object): + def __init__(self, suite_name, size, test_source_cls, test_source_kwargs, + browser_cls, browser_kwargs, + executor_cls, executor_kwargs, + pause_after_test=False, + pause_on_unexpected=False, + restart_on_unexpected=True, + debug_info=None): + """Main thread object that owns all the TestManager threads.""" + self.suite_name = suite_name + self.size = size + self.test_source_cls = test_source_cls + self.test_source_kwargs = test_source_kwargs + self.browser_cls = browser_cls + self.browser_kwargs = browser_kwargs + self.executor_cls = executor_cls + self.executor_kwargs = executor_kwargs + self.pause_after_test = pause_after_test + self.pause_on_unexpected = pause_on_unexpected + self.restart_on_unexpected = restart_on_unexpected + self.debug_info = debug_info + + self.pool = set() + # Event that is polled by threads so that they can gracefully exit in the face + # of sigint + self.stop_flag = threading.Event() + self.logger = structuredlog.StructuredLogger(suite_name) + self.test_queue = None + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.stop() + + def run(self, test_type, tests): + """Start all managers in the group""" + self.logger.debug("Using %i processes" % self.size) + + self.test_queue = TestQueue(self.test_source_cls, + test_type, + tests, + **self.test_source_kwargs) + with self.test_queue as test_queue: + if test_queue is None: + self.logger.info("No %s tests to run" % test_type) + return + for _ in range(self.size): + manager = TestRunnerManager(self.suite_name, + test_queue, + self.test_source_cls, + self.browser_cls, + self.browser_kwargs, + self.executor_cls, + self.executor_kwargs, + self.stop_flag, + self.pause_after_test, + self.pause_on_unexpected, + self.restart_on_unexpected, + self.debug_info) + manager.start() + self.pool.add(manager) + self.wait() + + def is_alive(self): + """Boolean indicating whether any manager in the group is still alive""" + return any(manager.is_alive() for manager in self.pool) + + def wait(self): + """Wait for all the managers in the group to finish""" + for item in self.pool: + item.join() + + def stop(self): + """Set the stop flag so that all managers in the group stop as soon + as possible""" + self.stop_flag.set() + self.logger.debug("Stop flag set in ManagerGroup") + + def unexpected_count(self): + return sum(item.unexpected_count for item in self.pool) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/__init__.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_chunker.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_chunker.py new file mode 100644 index 000000000000..4968940feb8b --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_chunker.py @@ -0,0 +1,89 @@ +import unittest +import sys +from os.path import join, dirname +from mozlog import structured + +import pytest + +sys.path.insert(0, join(dirname(__file__), "..", "..")) + +from wptrunner.testloader import EqualTimeChunker + +structured.set_default_logger(structured.structuredlog.StructuredLogger("TestChunker")) + +class MockTest(object): + def __init__(self, id, timeout=10): + self.id = id + self.item_type = "testharness" + self.timeout = timeout + + +def make_mock_manifest(*items): + rv = [] + for test_type, dir_path, num_tests in items: + for i in range(num_tests): + rv.append((test_type, + dir_path + "/%i.test" % i, + set([MockTest(i)]))) + return rv + + +class TestEqualTimeChunker(unittest.TestCase): + + def test_include_all(self): + tests = make_mock_manifest(("test", "a", 10), ("test", "a/b", 10), + ("test", "c", 10)) + + chunk_1 = list(EqualTimeChunker(3, 1)(tests)) + chunk_2 = list(EqualTimeChunker(3, 2)(tests)) + chunk_3 = list(EqualTimeChunker(3, 3)(tests)) + + self.assertEquals(tests[:10], chunk_1) + self.assertEquals(tests[10:20], chunk_2) + self.assertEquals(tests[20:], chunk_3) + + def test_include_all_1(self): + tests = make_mock_manifest(("test", "a", 5), ("test", "a/b", 5), + ("test", "c", 10), ("test", "d", 10)) + + chunk_1 = list(EqualTimeChunker(3, 1)(tests)) + chunk_2 = list(EqualTimeChunker(3, 2)(tests)) + chunk_3 = list(EqualTimeChunker(3, 3)(tests)) + + self.assertEquals(tests[:10], chunk_1) + self.assertEquals(tests[10:20], chunk_2) + self.assertEquals(tests[20:], chunk_3) + + def test_long(self): + tests = make_mock_manifest(("test", "a", 100), ("test", "a/b", 1), + ("test", "c", 1)) + + chunk_1 = list(EqualTimeChunker(3, 1)(tests)) + chunk_2 = list(EqualTimeChunker(3, 2)(tests)) + chunk_3 = list(EqualTimeChunker(3, 3)(tests)) + + self.assertEquals(tests[:100], chunk_1) + self.assertEquals(tests[100:101], chunk_2) + self.assertEquals(tests[101:102], chunk_3) + + def test_long_1(self): + tests = make_mock_manifest(("test", "a", 1), ("test", "a/b", 100), + ("test", "c", 1)) + + chunk_1 = list(EqualTimeChunker(3, 1)(tests)) + chunk_2 = list(EqualTimeChunker(3, 2)(tests)) + chunk_3 = list(EqualTimeChunker(3, 3)(tests)) + + self.assertEquals(tests[:1], chunk_1) + self.assertEquals(tests[1:101], chunk_2) + self.assertEquals(tests[101:102], chunk_3) + + def test_too_few_dirs(self): + with self.assertRaises(ValueError): + tests = make_mock_manifest(("test", "a", 1), ("test", "a/b", 100), + ("test", "c", 1)) + list(EqualTimeChunker(4, 1)(tests)) + + +if __name__ == "__main__": + unittest.main() diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_hosts.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_hosts.py new file mode 100644 index 000000000000..808b81606aeb --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_hosts.py @@ -0,0 +1,56 @@ +import unittest +import sys +from os.path import join, dirname +from cStringIO import StringIO + +sys.path.insert(0, join(dirname(__file__), "..", "..")) + +from wptrunner import hosts + + +class HostsTest(unittest.TestCase): + def do_test(self, input, expected): + host_file = hosts.HostsFile.from_file(StringIO(input)) + self.assertEquals(host_file.to_string(), expected) + + def test_simple(self): + self.do_test("""127.0.0.1 \tlocalhost alias # comment +# Another comment""", + """127.0.0.1 localhost alias # comment +# Another comment +""") + + def test_blank_lines(self): + self.do_test("""127.0.0.1 \tlocalhost alias # comment + +\r + \t +# Another comment""", + """127.0.0.1 localhost alias # comment +# Another comment +""") + + def test_whitespace(self): + self.do_test(""" \t127.0.0.1 \tlocalhost alias # comment \r + \t# Another comment""", + """127.0.0.1 localhost alias # comment +# Another comment +""") + + def test_alignment(self): + self.do_test("""127.0.0.1 \tlocalhost alias +192.168.1.1 another_host another_alias +""","""127.0.0.1 localhost alias +192.168.1.1 another_host another_alias +""" +) + + def test_multiple_same_name(self): + # The semantics are that we overwrite earlier entries with the same name + self.do_test("""127.0.0.1 \tlocalhost alias +192.168.1.1 localhost another_alias""","""192.168.1.1 localhost another_alias +""" +) + +if __name__ == "__main__": + unittest.main() diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_testloader.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_testloader.py new file mode 100644 index 000000000000..0d967b051fda --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_testloader.py @@ -0,0 +1,29 @@ +from __future__ import unicode_literals + +import os +import sys +import tempfile + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..")) + +from mozlog import structured +from wptrunner.testloader import TestFilter as Filter +from .test_chunker import make_mock_manifest + +structured.set_default_logger(structured.structuredlog.StructuredLogger("TestLoader")) + +include_ini = """\ +skip: true +[test_\u53F0] + skip: false +""" + +def test_filter_unicode(): + tests = make_mock_manifest(("test", "a", 10), ("test", "a/b", 10), + ("test", "c", 10)) + + with tempfile.NamedTemporaryFile("wb", suffix=".ini") as f: + f.write(include_ini.encode('utf-8')) + f.flush() + + Filter(manifest_path=f.name, test_manifests=tests) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_update.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_update.py new file mode 100644 index 000000000000..e5eb4cf49c7f --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_update.py @@ -0,0 +1,328 @@ +import unittest +import StringIO + +import pytest + +from .. import metadata, manifestupdate +from mozlog import structuredlog, handlers, formatters + + +class TestExpectedUpdater(unittest.TestCase): + def create_manifest(self, data, test_path="path/to/test.ini"): + f = StringIO.StringIO(data) + return manifestupdate.compile(f, test_path) + + def create_updater(self, data, **kwargs): + expected_tree = {} + id_path_map = {} + for test_path, test_ids, manifest_str in data: + if isinstance(test_ids, (str, unicode)): + test_ids = [test_ids] + expected_tree[test_path] = self.create_manifest(manifest_str, test_path) + for test_id in test_ids: + id_path_map[test_id] = test_path + + return metadata.ExpectedUpdater(expected_tree, id_path_map, **kwargs) + + def create_log(self, *args, **kwargs): + logger = structuredlog.StructuredLogger("expected_test") + data = StringIO.StringIO() + handler = handlers.StreamHandler(data, formatters.JSONFormatter()) + logger.add_handler(handler) + + log_entries = ([("suite_start", {"tests": [], "run_info": kwargs.get("run_info", {})})] + + list(args) + + [("suite_end", {})]) + + for item in log_entries: + action, kwargs = item + getattr(logger, action)(**kwargs) + logger.remove_handler(handler) + data.seek(0) + return data + + + def coalesce_results(self, trees): + for tree in trees: + for test in tree.iterchildren(): + for subtest in test.iterchildren(): + subtest.coalesce_expected() + test.coalesce_expected() + + @pytest.mark.xfail + def test_update_0(self): + prev_data = [("path/to/test.htm.ini", ["/path/to/test.htm"], """[test.htm] + type: testharness + [test1] + expected: FAIL""")] + + new_data = self.create_log(("test_start", {"test": "/path/to/test.htm"}), + ("test_status", {"test": "/path/to/test.htm", + "subtest": "test1", + "status": "PASS", + "expected": "FAIL"}), + ("test_end", {"test": "/path/to/test.htm", + "status": "OK"})) + updater = self.create_updater(prev_data) + updater.update_from_log(new_data) + + new_manifest = updater.expected_tree["path/to/test.htm.ini"] + self.coalesce_results([new_manifest]) + self.assertTrue(new_manifest.is_empty) + + @pytest.mark.xfail + def test_update_1(self): + test_id = "/path/to/test.htm" + prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm] + type: testharness + [test1] + expected: ERROR""")] + + new_data = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "FAIL", + "expected": "ERROR"}), + ("test_end", {"test": test_id, + "status": "OK"})) + updater = self.create_updater(prev_data) + updater.update_from_log(new_data) + + new_manifest = updater.expected_tree["path/to/test.htm.ini"] + self.coalesce_results([new_manifest]) + self.assertFalse(new_manifest.is_empty) + self.assertEquals(new_manifest.get_test(test_id).children[0].get("expected"), "FAIL") + + @pytest.mark.xfail + def test_new_subtest(self): + test_id = "/path/to/test.htm" + prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm] + type: testharness + [test1] + expected: FAIL""")] + + new_data = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "FAIL", + "expected": "FAIL"}), + ("test_status", {"test": test_id, + "subtest": "test2", + "status": "FAIL", + "expected": "PASS"}), + ("test_end", {"test": test_id, + "status": "OK"})) + updater = self.create_updater(prev_data) + updater.update_from_log(new_data) + + new_manifest = updater.expected_tree["path/to/test.htm.ini"] + self.coalesce_results([new_manifest]) + self.assertFalse(new_manifest.is_empty) + self.assertEquals(new_manifest.get_test(test_id).children[0].get("expected"), "FAIL") + self.assertEquals(new_manifest.get_test(test_id).children[1].get("expected"), "FAIL") + + @pytest.mark.xfail + def test_update_multiple_0(self): + test_id = "/path/to/test.htm" + prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm] + type: testharness + [test1] + expected: FAIL""")] + + new_data_0 = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "FAIL", + "expected": "FAIL"}), + ("test_end", {"test": test_id, + "status": "OK"}), + run_info={"debug": False, "os": "osx"}) + + new_data_1 = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "TIMEOUT", + "expected": "FAIL"}), + ("test_end", {"test": test_id, + "status": "OK"}), + run_info={"debug": False, "os": "linux"}) + updater = self.create_updater(prev_data) + + updater.update_from_log(new_data_0) + updater.update_from_log(new_data_1) + + new_manifest = updater.expected_tree["path/to/test.htm.ini"] + + self.coalesce_results([new_manifest]) + + self.assertFalse(new_manifest.is_empty) + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": False, "os": "osx"}), "FAIL") + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": False, "os": "linux"}), "TIMEOUT") + + @pytest.mark.xfail + def test_update_multiple_1(self): + test_id = "/path/to/test.htm" + prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm] + type: testharness + [test1] + expected: FAIL""")] + + new_data_0 = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "FAIL", + "expected": "FAIL"}), + ("test_end", {"test": test_id, + "status": "OK"}), + run_info={"debug": False, "os": "osx"}) + + new_data_1 = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "TIMEOUT", + "expected": "FAIL"}), + ("test_end", {"test": test_id, + "status": "OK"}), + run_info={"debug": False, "os": "linux"}) + updater = self.create_updater(prev_data) + + updater.update_from_log(new_data_0) + updater.update_from_log(new_data_1) + + new_manifest = updater.expected_tree["path/to/test.htm.ini"] + + self.coalesce_results([new_manifest]) + + self.assertFalse(new_manifest.is_empty) + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": False, "os": "osx"}), "FAIL") + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": False, "os": "linux"}), "TIMEOUT") + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": False, "os": "windows"}), "FAIL") + + @pytest.mark.xfail + def test_update_multiple_2(self): + test_id = "/path/to/test.htm" + prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm] + type: testharness + [test1] + expected: FAIL""")] + + new_data_0 = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "FAIL", + "expected": "FAIL"}), + ("test_end", {"test": test_id, + "status": "OK"}), + run_info={"debug": False, "os": "osx"}) + + new_data_1 = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "TIMEOUT", + "expected": "FAIL"}), + ("test_end", {"test": test_id, + "status": "OK"}), + run_info={"debug": True, "os": "osx"}) + updater = self.create_updater(prev_data) + + updater.update_from_log(new_data_0) + updater.update_from_log(new_data_1) + + new_manifest = updater.expected_tree["path/to/test.htm.ini"] + + self.coalesce_results([new_manifest]) + + self.assertFalse(new_manifest.is_empty) + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": False, "os": "osx"}), "FAIL") + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": True, "os": "osx"}), "TIMEOUT") + + @pytest.mark.xfail + def test_update_multiple_3(self): + test_id = "/path/to/test.htm" + prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm] + type: testharness + [test1] + expected: + if debug: FAIL + if not debug and os == "osx": TIMEOUT""")] + + new_data_0 = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "FAIL", + "expected": "FAIL"}), + ("test_end", {"test": test_id, + "status": "OK"}), + run_info={"debug": False, "os": "osx"}) + + new_data_1 = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "TIMEOUT", + "expected": "FAIL"}), + ("test_end", {"test": test_id, + "status": "OK"}), + run_info={"debug": True, "os": "osx"}) + updater = self.create_updater(prev_data) + + updater.update_from_log(new_data_0) + updater.update_from_log(new_data_1) + + new_manifest = updater.expected_tree["path/to/test.htm.ini"] + + self.coalesce_results([new_manifest]) + + self.assertFalse(new_manifest.is_empty) + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": False, "os": "osx"}), "FAIL") + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": True, "os": "osx"}), "TIMEOUT") + + @pytest.mark.xfail + def test_update_ignore_existing(self): + test_id = "/path/to/test.htm" + prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm] + type: testharness + [test1] + expected: + if debug: TIMEOUT + if not debug and os == "osx": NOTRUN""")] + + new_data_0 = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "FAIL", + "expected": "PASS"}), + ("test_end", {"test": test_id, + "status": "OK"}), + run_info={"debug": False, "os": "linux"}) + + new_data_1 = self.create_log(("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "FAIL", + "expected": "PASS"}), + ("test_end", {"test": test_id, + "status": "OK"}), + run_info={"debug": True, "os": "windows"}) + updater = self.create_updater(prev_data, ignore_existing=True) + + updater.update_from_log(new_data_0) + updater.update_from_log(new_data_1) + + new_manifest = updater.expected_tree["path/to/test.htm.ini"] + + self.coalesce_results([new_manifest]) + + self.assertFalse(new_manifest.is_empty) + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": True, "os": "osx"}), "FAIL") + self.assertEquals(new_manifest.get_test(test_id).children[0].get( + "expected", {"debug": False, "os": "osx"}), "FAIL") diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/update/__init__.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/__init__.py new file mode 100644 index 000000000000..497cb34ad0cb --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/__init__.py @@ -0,0 +1,47 @@ +import os +import sys + +from mozlog.structured import structuredlog, commandline + +from .. import wptcommandline + +from update import WPTUpdate + +def remove_logging_args(args): + """Take logging args out of the dictionary of command line arguments so + they are not passed in as kwargs to the update code. This is particularly + necessary here because the arguments are often of type file, which cannot + be serialized. + + :param args: Dictionary of command line arguments. + """ + for name in args.keys(): + if name.startswith("log_"): + args.pop(name) + + +def setup_logging(args, defaults): + """Use the command line arguments to set up the logger. + + :param args: Dictionary of command line arguments. + :param defaults: Dictionary of {formatter_name: stream} to use if + no command line logging is specified""" + logger = commandline.setup_logging("web-platform-tests-update", args, defaults) + + remove_logging_args(args) + + return logger + + +def run_update(logger, **kwargs): + updater = WPTUpdate(logger, **kwargs) + return updater.run() + + +def main(): + args = wptcommandline.parse_args_update() + logger = setup_logging(args, {"mach": sys.stdout}) + assert structuredlog.get_default_logger() is not None + success = run_update(logger, **args) + sys.exit(0 if success else 1) + diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/update/base.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/base.py new file mode 100644 index 000000000000..547808e52933 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/base.py @@ -0,0 +1,65 @@ +exit_unclean = object() +exit_clean = object() + + +class Step(object): + provides = [] + + def __init__(self, logger): + self.logger = logger + + def run(self, step_index, state): + """Base class for state-creating steps. + + When a Step is run() the current state is checked to see + if the state from this step has already been created. If it + has the restore() method is invoked. Otherwise the create() + method is invoked with the state object. This is expected to + add items with all the keys in __class__.provides to the state + object. + """ + + name = self.__class__.__name__ + + try: + stored_step = state.steps[step_index] + except IndexError: + stored_step = None + + if stored_step == name: + self.restore(state) + elif stored_step is None: + self.create(state) + assert set(self.provides).issubset(set(state.keys())) + state.steps = state.steps + [name] + else: + raise ValueError("Expected a %s step, got a %s step" % (name, stored_step)) + + def create(self, data): + raise NotImplementedError + + def restore(self, state): + self.logger.debug("Step %s using stored state" % (self.__class__.__name__,)) + for key in self.provides: + assert key in state + + +class StepRunner(object): + steps = [] + + def __init__(self, logger, state): + """Class that runs a specified series of Steps with a common State""" + self.state = state + self.logger = logger + if "steps" not in state: + state.steps = [] + + def run(self): + rv = None + for step_index, step in enumerate(self.steps): + self.logger.debug("Starting step %s" % step.__name__) + rv = step(self.logger).run(step_index, self.state) + if rv in (exit_clean, exit_unclean): + break + + return rv diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/update/metadata.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/metadata.py new file mode 100644 index 000000000000..f596766578c9 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/metadata.py @@ -0,0 +1,71 @@ +import os + +from .. import metadata, products + +from base import Step, StepRunner + +class GetUpdatePropertyList(Step): + provides = ["property_order", "boolean_properties"] + + + def create(self, state): + property_order, boolean_properties = products.load_product_update( + state.config, state.product) + state.property_order = property_order + state.boolean_properties = boolean_properties + + +class UpdateExpected(Step): + """Do the metadata update on the local checkout""" + + provides = ["needs_human"] + + def create(self, state): + if state.sync_tree is not None: + sync_root = state.sync_tree.root + else: + sync_root = None + + state.needs_human = metadata.update_expected(state.paths, + state.serve_root, + state.run_log, + rev_old=None, + ignore_existing=state.ignore_existing, + sync_root=sync_root, + property_order=state.property_order, + boolean_properties=state.boolean_properties) + + +class CreateMetadataPatch(Step): + """Create a patch/commit for the metadata checkout""" + + def create(self, state): + if state.no_patch: + return + + local_tree = state.local_tree + sync_tree = state.sync_tree + + if sync_tree is not None: + name = "web-platform-tests_update_%s_metadata" % sync_tree.rev + message = "Update %s expected data to revision %s" % (state.suite_name, sync_tree.rev) + else: + name = "web-platform-tests_update_metadata" + message = "Update %s expected data" % state.suite_name + + local_tree.create_patch(name, message) + + if not local_tree.is_clean: + metadata_paths = [manifest_path["metadata_path"] + for manifest_path in state.paths.itervalues()] + for path in metadata_paths: + local_tree.add_new(os.path.relpath(path, local_tree.root)) + local_tree.update_patch(include=metadata_paths) + local_tree.commit_patch() + + +class MetadataUpdateRunner(StepRunner): + """(Sub)Runner for updating metadata""" + steps = [GetUpdatePropertyList, + UpdateExpected, + CreateMetadataPatch] diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/update/state.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/state.py new file mode 100644 index 000000000000..9454414e640b --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/state.py @@ -0,0 +1,133 @@ +import os +import cPickle as pickle + +here = os.path.abspath(os.path.split(__file__)[0]) + +class State(object): + filename = os.path.join(here, ".wpt-update.lock") + + def __new__(cls, logger): + rv = cls.load(logger) + if rv is not None: + logger.debug("Existing state found") + return rv + + logger.debug("No existing state found") + return object.__new__(cls, logger) + + def __init__(self, logger): + """Object containing state variables created when running Steps. + + On write the state is serialized to disk, such that it can be restored in + the event that the program is interrupted before all steps are complete. + Note that this only works well if the values are immutable; mutating an + existing value will not cause the data to be serialized. + + Variables are set and get as attributes e.g. state_obj.spam = "eggs". + + :param parent: Parent State object or None if this is the root object. + """ + + if hasattr(self, "_data"): + return + + self._data = [{}] + self._logger = logger + self._index = 0 + + def __getstate__(self): + rv = self.__dict__.copy() + del rv["_logger"] + return rv + + @classmethod + def load(cls, logger): + """Load saved state from a file""" + try: + with open(cls.filename) as f: + try: + rv = pickle.load(f) + logger.debug("Loading data %r" % (rv._data,)) + rv._logger = logger + rv._index = 0 + return rv + except EOFError: + logger.warning("Found empty state file") + except IOError: + logger.debug("IOError loading stored state") + + def push(self, init_values): + """Push a new clean state dictionary + + :param init_values: List of variable names in the current state dict to copy + into the new state dict.""" + + return StateContext(self, init_values) + + def save(self): + """Write the state to disk""" + with open(self.filename, "w") as f: + pickle.dump(self, f) + + def is_empty(self): + return len(self._data) == 1 and self._data[0] == {} + + def clear(self): + """Remove all state and delete the stored copy.""" + try: + os.unlink(self.filename) + except OSError: + pass + self._data = [{}] + + + def __setattr__(self, key, value): + if key.startswith("_"): + object.__setattr__(self, key, value) + else: + self._data[self._index][key] = value + self.save() + + def __getattr__(self, key): + if key.startswith("_"): + raise AttributeError + try: + return self._data[self._index][key] + except KeyError: + raise AttributeError + + def __contains__(self, key): + return key in self._data[self._index] + + def update(self, items): + """Add a dictionary of {name: value} pairs to the state""" + self._data[self._index].update(items) + self.save() + + def keys(self): + return self._data[self._index].keys() + +class StateContext(object): + def __init__(self, state, init_values): + self.state = state + self.init_values = init_values + + def __enter__(self): + if len(self.state._data) == self.state._index + 1: + # This is the case where there is no stored state + new_state = {} + for key in self.init_values: + new_state[key] = self.state._data[self.state._index][key] + self.state._data.append(new_state) + self.state._index += 1 + self.state._logger.debug("Incremented index to %s" % self.state._index) + + def __exit__(self, *args, **kwargs): + if len(self.state._data) > 1: + assert self.state._index == len(self.state._data) - 1 + self.state._data.pop() + self.state._index -= 1 + self.state._logger.debug("Decremented index to %s" % self.state._index) + assert self.state._index >= 0 + else: + raise ValueError("Tried to pop the top state") diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/update/sync.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/sync.py new file mode 100644 index 000000000000..3f6092a046a0 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/sync.py @@ -0,0 +1,177 @@ +import os +import shutil +import sys +import uuid + +from .. import testloader + +from base import Step, StepRunner +from tree import Commit + +here = os.path.abspath(os.path.split(__file__)[0]) + +bsd_license = """W3C 3-clause BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of works must retain the original copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the original copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of the W3C nor the names of its contributors may be + used to endorse or promote products derived from this work without + specific prior written permission. + + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT OWNER OR 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. +""" + + +def copy_wpt_tree(tree, dest): + """Copy the working copy of a Tree to a destination directory. + + :param tree: The Tree to copy. + :param dest: The destination directory""" + if os.path.exists(dest): + assert os.path.isdir(dest) + + shutil.rmtree(dest) + os.mkdir(dest) + + for tree_path in tree.paths(): + source_path = os.path.join(tree.root, tree_path) + dest_path = os.path.join(dest, tree_path) + + dest_dir = os.path.split(dest_path)[0] + if not os.path.isdir(source_path): + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + shutil.copy2(source_path, dest_path) + + for source, destination in [("testharness_runner.html", ""), + ("testharnessreport.js", "resources/")]: + source_path = os.path.join(here, os.pardir, source) + dest_path = os.path.join(dest, destination, os.path.split(source)[1]) + shutil.copy2(source_path, dest_path) + + add_license(dest) + + +def add_license(dest): + """Write the bsd license string to a LICENSE file. + + :param dest: Directory in which to place the LICENSE file.""" + with open(os.path.join(dest, "LICENSE"), "w") as f: + f.write(bsd_license) + +class UpdateCheckout(Step): + """Pull changes from upstream into the local sync tree.""" + + provides = ["local_branch"] + + def create(self, state): + sync_tree = state.sync_tree + state.local_branch = uuid.uuid4().hex + sync_tree.update(state.sync["remote_url"], + state.sync["branch"], + state.local_branch) + sync_path = os.path.abspath(sync_tree.root) + if not sync_path in sys.path: + from update import setup_paths + setup_paths(sync_path) + + def restore(self, state): + assert os.path.abspath(state.sync_tree.root) in sys.path + Step.restore(self, state) + + +class GetSyncTargetCommit(Step): + """Find the commit that we will sync to.""" + + provides = ["sync_commit"] + + def create(self, state): + if state.target_rev is None: + #Use upstream branch HEAD as the base commit + state.sync_commit = state.sync_tree.get_remote_sha1(state.sync["remote_url"], + state.sync["branch"]) + else: + state.sync_commit = Commit(state.sync_tree, state.rev) + + state.sync_tree.checkout(state.sync_commit.sha1, state.local_branch, force=True) + self.logger.debug("New base commit is %s" % state.sync_commit.sha1) + + +class LoadManifest(Step): + """Load the test manifest""" + + provides = ["manifest_path", "test_manifest"] + + def create(self, state): + from manifest import manifest + state.manifest_path = os.path.join(state.metadata_path, "MANIFEST.json") + state.test_manifest = manifest.Manifest("/") + + +class UpdateManifest(Step): + """Update the manifest to match the tests in the sync tree checkout""" + + def create(self, state): + from manifest import manifest, update + update.update(state.sync["path"], state.test_manifest) + manifest.write(state.test_manifest, state.manifest_path) + + +class CopyWorkTree(Step): + """Copy the sync tree over to the destination in the local tree""" + + def create(self, state): + copy_wpt_tree(state.sync_tree, + state.tests_path) + + +class CreateSyncPatch(Step): + """Add the updated test files to a commit/patch in the local tree.""" + + def create(self, state): + if state.no_patch: + return + + local_tree = state.local_tree + sync_tree = state.sync_tree + + local_tree.create_patch("web-platform-tests_update_%s" % sync_tree.rev, + "Update %s to revision %s" % (state.suite_name, sync_tree.rev)) + local_tree.add_new(os.path.relpath(state.tests_path, + local_tree.root)) + updated = local_tree.update_patch(include=[state.tests_path, + state.metadata_path]) + local_tree.commit_patch() + + if not updated: + self.logger.info("Nothing to sync") + + +class SyncFromUpstreamRunner(StepRunner): + """(Sub)Runner for doing an upstream sync""" + steps = [UpdateCheckout, + GetSyncTargetCommit, + LoadManifest, + UpdateManifest, + CopyWorkTree, + CreateSyncPatch] diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/update/tree.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/tree.py new file mode 100644 index 000000000000..a15df907aa41 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/tree.py @@ -0,0 +1,383 @@ +import os +import re +import subprocess + +from .. import vcs +from ..vcs import bind_to_repo, git, hg + + +def get_unique_name(existing, initial): + """Get a name either equal to initial or of the form initial_N, for some + integer N, that is not in the set existing. + + + :param existing: Set of names that must not be chosen. + :param initial: Name, or name prefix, to use""" + if initial not in existing: + return initial + for i in xrange(len(existing) + 1): + test = "%s_%s" % (initial, i + 1) + if test not in existing: + return test + assert False + +class NoVCSTree(object): + name = "non-vcs" + + def __init__(self, root=None): + if root is None: + root = os.path.abspath(os.curdir) + self.root = root + + @classmethod + def is_type(cls, path=None): + return True + + @property + def is_clean(self): + return True + + def add_new(self, prefix=None): + pass + + def create_patch(self, patch_name, message): + pass + + def update_patch(self, include=None): + pass + + def commit_patch(self): + pass + + +class HgTree(object): + name = "mercurial" + + def __init__(self, root=None): + if root is None: + root = hg("root").strip() + self.root = root + self.hg = vcs.bind_to_repo(hg, self.root) + + def __getstate__(self): + rv = self.__dict__.copy() + del rv['hg'] + return rv + + def __setstate__(self, dict): + self.__dict__.update(dict) + self.hg = vcs.bind_to_repo(vcs.hg, self.root) + + @classmethod + def is_type(cls, path=None): + kwargs = {"log_error": False} + if path is not None: + kwargs["repo"] = path + try: + hg("root", **kwargs) + except: + return False + return True + + @property + def is_clean(self): + return self.hg("status").strip() == "" + + def add_new(self, prefix=None): + if prefix is not None: + args = ("-I", prefix) + else: + args = () + self.hg("add", *args) + + def create_patch(self, patch_name, message): + try: + self.hg("qinit", log_error=False) + except subprocess.CalledProcessError: + pass + + patch_names = [item.strip() for item in self.hg("qseries").split("\n") if item.strip()] + + suffix = 0 + test_name = patch_name + while test_name in patch_names: + suffix += 1 + test_name = "%s-%i" % (patch_name, suffix) + + self.hg("qnew", test_name, "-X", self.root, "-m", message) + + def update_patch(self, include=None): + if include is not None: + args = [] + for item in include: + args.extend(["-I", item]) + else: + args = () + + self.hg("qrefresh", *args) + return True + + def commit_patch(self): + self.hg("qfinish") + + def contains_commit(self, commit): + try: + self.hg("identify", "-r", commit.sha1) + return True + except subprocess.CalledProcessError: + return False + + +class GitTree(object): + name = "git" + + def __init__(self, root=None): + if root is None: + root = git("rev-parse", "--show-toplevel").strip() + self.root = root + self.git = vcs.bind_to_repo(git, self.root) + self.message = None + self.commit_cls = Commit + + def __getstate__(self): + rv = self.__dict__.copy() + del rv['git'] + return rv + + def __setstate__(self, dict): + self.__dict__.update(dict) + self.git = vcs.bind_to_repo(vcs.git, self.root) + + @classmethod + def is_type(cls, path=None): + kwargs = {"log_error": False} + if path is not None: + kwargs["repo"] = path + try: + git("rev-parse", "--show-toplevel", **kwargs) + except: + return False + return True + + @property + def rev(self): + """Current HEAD revision""" + if vcs.is_git_root(self.root): + return self.git("rev-parse", "HEAD").strip() + else: + return None + + @property + def is_clean(self): + return self.git("status").strip() == "" + + def add_new(self, prefix=None): + """Add files to the staging area. + + :param prefix: None to include all files or a path prefix to + add all files under that path. + """ + if prefix is None: + args = ("-a",) + else: + args = ("--no-ignore-removal", prefix) + self.git("add", *args) + + def list_refs(self, ref_filter=None): + """Get a list of sha1, name tuples for references in a repository. + + :param ref_filter: Pattern that reference name must match (from the end, + matching whole /-delimited segments only + """ + args = [] + if ref_filter is not None: + args.append(ref_filter) + data = self.git("show-ref", *args) + rv = [] + for line in data.split("\n"): + if not line.strip(): + continue + sha1, ref = line.split() + rv.append((sha1, ref)) + return rv + + def list_remote(self, remote, ref_filter=None): + """Return a list of (sha1, name) tupes for references in a remote. + + :param remote: URL of the remote to list. + :param ref_filter: Pattern that the reference name must match. + """ + args = [] + if ref_filter is not None: + args.append(ref_filter) + data = self.git("ls-remote", remote, *args) + rv = [] + for line in data.split("\n"): + if not line.strip(): + continue + sha1, ref = line.split() + rv.append((sha1, ref)) + return rv + + def get_remote_sha1(self, remote, branch): + """Return the SHA1 of a particular branch in a remote. + + :param remote: the remote URL + :param branch: the branch name""" + for sha1, ref in self.list_remote(remote, branch): + if ref == "refs/heads/%s" % branch: + return self.commit_cls(self, sha1) + assert False + + def create_patch(self, patch_name, message): + # In git a patch is actually a commit + self.message = message + + def update_patch(self, include=None): + """Commit the staged changes, or changes to listed files. + + :param include: Either None, to commit staged changes, or a list + of filenames (which must already be in the repo) + to commit + """ + if include is not None: + args = tuple(include) + else: + args = () + + if self.git("status", "-uno", "-z", *args).strip(): + self.git("add", *args) + return True + return False + + def commit_patch(self): + assert self.message is not None + + if self.git("diff", "--name-only", "--staged", "-z").strip(): + self.git("commit", "-m", self.message) + return True + + return False + + def init(self): + self.git("init") + assert vcs.is_git_root(self.root) + + def checkout(self, rev, branch=None, force=False): + """Checkout a particular revision, optionally into a named branch. + + :param rev: Revision identifier (e.g. SHA1) to checkout + :param branch: Branch name to use + :param force: Force-checkout + """ + assert rev is not None + + args = [] + if branch: + branches = [ref[len("refs/heads/"):] for sha1, ref in self.list_refs() + if ref.startswith("refs/heads/")] + branch = get_unique_name(branches, branch) + + args += ["-b", branch] + + if force: + args.append("-f") + args.append(rev) + self.git("checkout", *args) + + def update(self, remote, remote_branch, local_branch): + """Fetch from the remote and checkout into a local branch. + + :param remote: URL to the remote repository + :param remote_branch: Branch on the remote repository to check out + :param local_branch: Local branch name to check out into + """ + if not vcs.is_git_root(self.root): + self.init() + self.git("clean", "-xdf") + self.git("fetch", remote, "%s:%s" % (remote_branch, local_branch)) + self.checkout(local_branch) + self.git("submodule", "update", "--init", "--recursive") + + def clean(self): + self.git("checkout", self.rev) + self.git("branch", "-D", self.local_branch) + + def paths(self): + """List paths in the tree""" + repo_paths = [self.root] + [os.path.join(self.root, path) + for path in self.submodules()] + + rv = [] + + for repo_path in repo_paths: + paths = vcs.git("ls-tree", "-r", "--name-only", "HEAD", repo=repo_path).split("\n") + rel_path = os.path.relpath(repo_path, self.root) + rv.extend(os.path.join(rel_path, item.strip()) for item in paths if item.strip()) + + return rv + + def submodules(self): + """List submodule directories""" + output = self.git("submodule", "status", "--recursive") + rv = [] + for line in output.split("\n"): + line = line.strip() + if not line: + continue + parts = line.split(" ") + rv.append(parts[1]) + return rv + + def contains_commit(self, commit): + try: + self.git("rev-parse", "--verify", commit.sha1) + return True + except subprocess.CalledProcessError: + return False + + +class CommitMessage(object): + def __init__(self, text): + self.text = text + self._parse_message() + + def __str__(self): + return self.text + + def _parse_message(self): + lines = self.text.splitlines() + self.full_summary = lines[0] + self.body = "\n".join(lines[1:]) + + +class Commit(object): + msg_cls = CommitMessage + + _sha1_re = re.compile("^[0-9a-f]{40}$") + + def __init__(self, tree, sha1): + """Object representing a commit in a specific GitTree. + + :param tree: GitTree to which this commit belongs. + :param sha1: Full sha1 string for the commit + """ + assert self._sha1_re.match(sha1) + + self.tree = tree + self.git = tree.git + self.sha1 = sha1 + self.author, self.email, self.message = self._get_meta() + + def __getstate__(self): + rv = self.__dict__.copy() + del rv['git'] + return rv + + def __setstate__(self, dict): + self.__dict__.update(dict) + self.git = self.tree.git + + def _get_meta(self): + author, email, message = self.git("show", "-s", "--format=format:%an\n%ae\n%B", self.sha1).split("\n", 2) + return author, email, self.msg_cls(message) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/update/update.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/update.py new file mode 100644 index 000000000000..4a5e7ab73d4b --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/update.py @@ -0,0 +1,157 @@ +import os +import sys + +from metadata import MetadataUpdateRunner +from sync import SyncFromUpstreamRunner +from tree import GitTree, HgTree, NoVCSTree + +from .. import environment as env +from base import Step, StepRunner, exit_clean, exit_unclean +from state import State + +def setup_paths(sync_path): + sys.path.insert(0, os.path.abspath(sync_path)) + try: + from tools import localpaths + except ImportError: + from wpt_tools import localpaths + +class LoadConfig(Step): + """Step for loading configuration from the ini file and kwargs.""" + + provides = ["sync", "paths", "metadata_path", "tests_path"] + + def create(self, state): + state.sync = {"remote_url": state.kwargs["remote_url"], + "branch": state.kwargs["branch"], + "path": state.kwargs["sync_path"]} + + state.paths = state.kwargs["test_paths"] + state.tests_path = state.paths["/"]["tests_path"] + state.metadata_path = state.paths["/"]["metadata_path"] + + assert state.tests_path.startswith("/") + + +class LoadTrees(Step): + """Step for creating a Tree for the local copy and a GitTree for the + upstream sync.""" + + provides = ["local_tree", "sync_tree"] + + def create(self, state): + if os.path.exists(state.sync["path"]): + sync_tree = GitTree(root=state.sync["path"]) + else: + sync_tree = None + + if GitTree.is_type(): + local_tree = GitTree() + elif HgTree.is_type(): + local_tree = HgTree() + else: + local_tree = NoVCSTree() + + state.update({"local_tree": local_tree, + "sync_tree": sync_tree}) + + +class SyncFromUpstream(Step): + """Step that synchronises a local copy of the code with upstream.""" + + def create(self, state): + if not state.kwargs["sync"]: + return + + if not state.sync_tree: + os.mkdir(state.sync["path"]) + state.sync_tree = GitTree(root=state.sync["path"]) + + kwargs = state.kwargs + with state.push(["sync", "paths", "metadata_path", "tests_path", "local_tree", + "sync_tree"]): + state.target_rev = kwargs["rev"] + state.no_patch = kwargs["no_patch"] + state.suite_name = kwargs["suite_name"] + runner = SyncFromUpstreamRunner(self.logger, state) + runner.run() + + +class UpdateMetadata(Step): + """Update the expectation metadata from a set of run logs""" + + def create(self, state): + if not state.kwargs["run_log"]: + return + + kwargs = state.kwargs + with state.push(["local_tree", "sync_tree", "paths", "serve_root"]): + state.run_log = kwargs["run_log"] + state.ignore_existing = kwargs["ignore_existing"] + state.no_patch = kwargs["no_patch"] + state.suite_name = kwargs["suite_name"] + state.product = kwargs["product"] + state.config = kwargs["config"] + runner = MetadataUpdateRunner(self.logger, state) + runner.run() + + +class UpdateRunner(StepRunner): + """Runner for doing an overall update.""" + steps = [LoadConfig, + LoadTrees, + SyncFromUpstream, + UpdateMetadata] + + +class WPTUpdate(object): + def __init__(self, logger, runner_cls=UpdateRunner, **kwargs): + """Object that controls the running of a whole wptupdate. + + :param runner_cls: Runner subclass holding the overall list of + steps to run. + :param kwargs: Command line arguments + """ + self.runner_cls = runner_cls + self.serve_root = kwargs["test_paths"]["/"]["tests_path"] + + if not kwargs["sync"]: + setup_paths(self.serve_root) + else: + if os.path.exists(kwargs["sync_path"]): + # If the sync path doesn't exist we defer this until it does + setup_paths(kwargs["sync_path"]) + + self.state = State(logger) + self.kwargs = kwargs + self.logger = logger + + def run(self, **kwargs): + if self.kwargs["abort"]: + self.abort() + return exit_clean + + if not self.kwargs["continue"] and not self.state.is_empty(): + self.logger.error("Found existing state. Run with --continue to resume or --abort to clear state") + return exit_unclean + + if self.kwargs["continue"]: + if self.state.is_empty(): + self.logger.error("No sync in progress?") + return exit_clean + + self.kwargs = self.state.kwargs + else: + self.state.kwargs = self.kwargs + + self.state.serve_root = self.serve_root + + update_runner = self.runner_cls(self.logger, self.state) + rv = update_runner.run() + if rv in (exit_clean, None): + self.state.clear() + + return rv + + def abort(self): + self.state.clear() diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/vcs.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/vcs.py new file mode 100644 index 000000000000..16d53afc8be6 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/vcs.py @@ -0,0 +1,49 @@ +import subprocess +from functools import partial + +from mozlog import get_default_logger + +logger = None + +def vcs(bin_name): + def inner(command, *args, **kwargs): + global logger + + if logger is None: + logger = get_default_logger("vcs") + + repo = kwargs.pop("repo", None) + log_error = kwargs.pop("log_error", True) + if kwargs: + raise TypeError, kwargs + + args = list(args) + + proc_kwargs = {} + if repo is not None: + proc_kwargs["cwd"] = repo + + command_line = [bin_name, command] + args + logger.debug(" ".join(command_line)) + try: + return subprocess.check_output(command_line, stderr=subprocess.STDOUT, **proc_kwargs) + except subprocess.CalledProcessError as e: + if log_error: + logger.error(e.output) + raise + return inner + +git = vcs("git") +hg = vcs("hg") + + +def bind_to_repo(vcs_func, repo): + return partial(vcs_func, repo=repo) + + +def is_git_root(path): + try: + rv = git("rev-parse", "--show-cdup", repo=path) + except subprocess.CalledProcessError: + return False + return rv == "\n" diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/webdriver_server.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/webdriver_server.py new file mode 100644 index 000000000000..49d9c73b52e5 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/webdriver_server.py @@ -0,0 +1,233 @@ +import abc +import errno +import os +import platform +import socket +import threading +import time +import traceback +import urlparse + +import mozprocess + + +__all__ = ["SeleniumServer", "ChromeDriverServer", + "GeckoDriverServer", "ServoDriverServer", + "WebDriverServer"] + + +class WebDriverServer(object): + __metaclass__ = abc.ABCMeta + + default_base_path = "/" + _used_ports = set() + + def __init__(self, logger, binary, host="127.0.0.1", port=None, + base_path="", env=None, args=None): + if binary is None: + raise ValueError("WebDriver server binary must be given " + "to --webdriver-binary argument") + + self.logger = logger + self.binary = binary + self.host = host + if base_path == "": + self.base_path = self.default_base_path + else: + self.base_path = base_path + self.env = os.environ.copy() if env is None else env + + self._port = port + self._cmd = None + self._args = args if args is not None else [] + self._proc = None + + @abc.abstractmethod + def make_command(self): + """Returns the full command for starting the server process as a list.""" + + def start(self, block=False): + try: + self._run(block) + except KeyboardInterrupt: + self.stop() + + def _run(self, block): + self._cmd = self.make_command() + self._proc = mozprocess.ProcessHandler( + self._cmd, + processOutputLine=self.on_output, + env=self.env, + storeOutput=False) + + try: + self._proc.run() + except OSError as e: + if e.errno == errno.ENOENT: + raise IOError( + "WebDriver HTTP server executable not found: %s" % self.binary) + raise + + self.logger.debug( + "Waiting for server to become accessible: %s" % self.url) + try: + wait_for_service((self.host, self.port)) + except: + self.logger.error( + "WebDriver HTTP server was not accessible " + "within the timeout:\n%s" % traceback.format_exc()) + raise + + if block: + self._proc.wait() + + def stop(self, force=False): + if self.is_alive: + return self._proc.kill() + return not self.is_alive + + @property + def is_alive(self): + return hasattr(self._proc, "proc") and self._proc.poll() is None + + def on_output(self, line): + self.logger.process_output(self.pid, + line.decode("utf8", "replace"), + command=" ".join(self._cmd)) + + @property + def pid(self): + if self._proc is not None: + return self._proc.pid + + @property + def url(self): + return "http://%s:%i%s" % (self.host, self.port, self.base_path) + + @property + def port(self): + if self._port is None: + self._port = self._find_next_free_port() + return self._port + + @staticmethod + def _find_next_free_port(): + port = get_free_port(4444, exclude=WebDriverServer._used_ports) + WebDriverServer._used_ports.add(port) + return port + + +class SeleniumServer(WebDriverServer): + default_base_path = "/wd/hub" + + def make_command(self): + return ["java", "-jar", self.binary, "-port", str(self.port)] + self._args + + +class ChromeDriverServer(WebDriverServer): + default_base_path = "/wd/hub" + + def __init__(self, logger, binary="chromedriver", port=None, + base_path="", args=None): + WebDriverServer.__init__( + self, logger, binary, port=port, base_path=base_path, args=args) + + def make_command(self): + return [self.binary, + cmd_arg("port", str(self.port)), + cmd_arg("url-base", self.base_path) if self.base_path else ""] + self._args + + +class EdgeDriverServer(WebDriverServer): + def __init__(self, logger, binary="MicrosoftWebDriver.exe", port=None, + base_path="", host="localhost", args=None): + WebDriverServer.__init__( + self, logger, binary, host=host, port=port, args=args) + + def make_command(self): + return [self.binary, + "--port=%s" % str(self.port)] + self._args + + +class GeckoDriverServer(WebDriverServer): + def __init__(self, logger, marionette_port=2828, binary="geckodriver", + host="127.0.0.1", port=None, args=None): + env = os.environ.copy() + env["RUST_BACKTRACE"] = "1" + WebDriverServer.__init__(self, logger, binary, host=host, port=port, env=env, args=args) + self.marionette_port = marionette_port + + def make_command(self): + return [self.binary, + "--marionette-port", str(self.marionette_port), + "--host", self.host, + "--port", str(self.port)] + self._args + + +class ServoDriverServer(WebDriverServer): + def __init__(self, logger, binary="servo", binary_args=None, host="127.0.0.1", port=None): + env = os.environ.copy() + env["RUST_BACKTRACE"] = "1" + WebDriverServer.__init__(self, logger, binary, host=host, port=port, env=env) + self.binary_args = binary_args + + def make_command(self): + command = [self.binary, + "--webdriver", str(self.port), + "--hard-fail", + "--headless"] + self._args + if self.binary_args: + command += self.binary_args + return command + + +def cmd_arg(name, value=None): + prefix = "-" if platform.system() == "Windows" else "--" + rv = prefix + name + if value is not None: + rv += "=" + value + return rv + + +def get_free_port(start_port, exclude=None): + """Get the first port number after start_port (inclusive) that is + not currently bound. + + :param start_port: Integer port number at which to start testing. + :param exclude: Set of port numbers to skip""" + port = start_port + while True: + if exclude and port in exclude: + port += 1 + continue + s = socket.socket() + try: + s.bind(("127.0.0.1", port)) + except socket.error: + port += 1 + else: + return port + finally: + s.close() + + +def wait_for_service(addr, timeout=15): + """Waits until network service given as a tuple of (host, port) becomes + available or the `timeout` duration is reached, at which point + ``socket.error`` is raised.""" + end = time.time() + timeout + while end > time.time(): + so = socket.socket() + try: + so.connect(addr) + except socket.timeout: + pass + except socket.error as e: + if e[0] != errno.ECONNREFUSED: + raise + else: + return True + finally: + so.close() + time.sleep(0.5) + raise socket.error("Service is unavailable: %s:%i" % addr) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptcommandline.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptcommandline.py new file mode 100644 index 000000000000..01d3ab9fb52c --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptcommandline.py @@ -0,0 +1,458 @@ +import argparse +import ast +import os +import sys +from collections import OrderedDict +from distutils.spawn import find_executable + +import config +import wpttest + + +def abs_path(path): + return os.path.abspath(os.path.expanduser(path)) + + +def url_or_path(path): + import urlparse + + parsed = urlparse.urlparse(path) + if len(parsed.scheme) > 2: + return path + else: + return abs_path(path) + + +def require_arg(kwargs, name, value_func=None): + if value_func is None: + value_func = lambda x: x is not None + + if not name in kwargs or not value_func(kwargs[name]): + print >> sys.stderr, "Missing required argument %s" % name + sys.exit(1) + + +def create_parser(product_choices=None): + from mozlog import commandline + + import products + + if product_choices is None: + config_data = config.load() + product_choices = products.products_enabled(config_data) + + parser = argparse.ArgumentParser(description="""Runner for web-platform-tests tests.""", + usage="""%(prog)s [OPTION]... [TEST]... + +TEST is either the full path to a test file to run, or the URL of a test excluding +scheme host and port.""") + parser.add_argument("--manifest-update", action="store_true", default=False, + help="Regenerate the test manifest.") + + parser.add_argument("--timeout-multiplier", action="store", type=float, default=None, + help="Multiplier relative to standard test timeout to use") + parser.add_argument("--run-by-dir", type=int, nargs="?", default=False, + help="Split run into groups by directories. With a parameter," + "limit the depth of splits e.g. --run-by-dir=1 to split by top-level" + "directory") + parser.add_argument("--processes", action="store", type=int, default=None, + help="Number of simultaneous processes to use") + + parser.add_argument("--no-capture-stdio", action="store_true", default=False, + help="Don't capture stdio and write to logging") + + mode_group = parser.add_argument_group("Mode") + mode_group.add_argument("--list-test-groups", action="store_true", + default=False, + help="List the top level directories containing tests that will run.") + mode_group.add_argument("--list-disabled", action="store_true", + default=False, + help="List the tests that are disabled on the current platform") + + test_selection_group = parser.add_argument_group("Test Selection") + test_selection_group.add_argument("--test-types", action="store", + nargs="*", default=wpttest.enabled_tests, + choices=wpttest.enabled_tests, + help="Test types to run") + test_selection_group.add_argument("--include", action="append", + help="URL prefix to include") + test_selection_group.add_argument("--exclude", action="append", + help="URL prefix to exclude") + test_selection_group.add_argument("--include-manifest", type=abs_path, + help="Path to manifest listing tests to include") + test_selection_group.add_argument("--tag", action="append", dest="tags", + help="Labels applied to tests to include in the run. Labels starting dir: are equivalent to top-level directories.") + + debugging_group = parser.add_argument_group("Debugging") + debugging_group.add_argument('--debugger', const="__default__", nargs="?", + help="run under a debugger, e.g. gdb or valgrind") + debugging_group.add_argument('--debugger-args', help="arguments to the debugger") + debugging_group.add_argument("--repeat", action="store", type=int, default=1, + help="Number of times to run the tests") + debugging_group.add_argument("--repeat-until-unexpected", action="store_true", default=None, + help="Run tests in a loop until one returns an unexpected result") + debugging_group.add_argument('--pause-after-test', action="store_true", default=None, + help="Halt the test runner after each test (this happens by default if only a single test is run)") + debugging_group.add_argument('--no-pause-after-test', dest="pause_after_test", action="store_false", + help="Don't halt the test runner irrespective of the number of tests run") + + debugging_group.add_argument('--pause-on-unexpected', action="store_true", + help="Halt the test runner when an unexpected result is encountered") + debugging_group.add_argument('--no-restart-on-unexpected', dest="restart_on_unexpected", + default=True, action="store_false", + help="Don't restart on an unexpected result") + + debugging_group.add_argument("--symbols-path", action="store", type=url_or_path, + help="Path or url to symbols file used to analyse crash minidumps.") + debugging_group.add_argument("--stackwalk-binary", action="store", type=abs_path, + help="Path to stackwalker program used to analyse minidumps.") + + debugging_group.add_argument("--pdb", action="store_true", + help="Drop into pdb on python exception") + + config_group = parser.add_argument_group("Configuration") + config_group.add_argument("--binary", action="store", + type=abs_path, help="Binary to run tests against") + config_group.add_argument('--binary-arg', + default=[], action="append", dest="binary_args", + help="Extra argument for the binary") + config_group.add_argument("--webdriver-binary", action="store", metavar="BINARY", + type=abs_path, help="WebDriver server binary to use") + config_group.add_argument('--webdriver-arg', + default=[], action="append", dest="webdriver_args", + help="Extra argument for the WebDriver binary") + + config_group.add_argument("--metadata", action="store", type=abs_path, dest="metadata_root", + help="Path to root directory containing test metadata"), + config_group.add_argument("--tests", action="store", type=abs_path, dest="tests_root", + help="Path to root directory containing test files"), + config_group.add_argument("--run-info", action="store", type=abs_path, + help="Path to directory containing extra json files to add to run info") + config_group.add_argument("--product", action="store", choices=product_choices, + default=None, help="Browser against which to run tests") + config_group.add_argument("--config", action="store", type=abs_path, dest="config", + help="Path to config file") + + build_type = parser.add_mutually_exclusive_group() + build_type.add_argument("--debug-build", dest="debug", action="store_true", + default=None, + help="Build is a debug build (overrides any mozinfo file)") + build_type.add_argument("--release-build", dest="debug", action="store_false", + default=None, + help="Build is a release (overrides any mozinfo file)") + + + chunking_group = parser.add_argument_group("Test Chunking") + chunking_group.add_argument("--total-chunks", action="store", type=int, default=1, + help="Total number of chunks to use") + chunking_group.add_argument("--this-chunk", action="store", type=int, default=1, + help="Chunk number to run") + chunking_group.add_argument("--chunk-type", action="store", choices=["none", "equal_time", "hash", "dir_hash"], + default=None, help="Chunking type to use") + + ssl_group = parser.add_argument_group("SSL/TLS") + ssl_group.add_argument("--ssl-type", action="store", default=None, + choices=["openssl", "pregenerated", "none"], + help="Type of ssl support to enable (running without ssl may lead to spurious errors)") + + ssl_group.add_argument("--openssl-binary", action="store", + help="Path to openssl binary", default="openssl") + ssl_group.add_argument("--certutil-binary", action="store", + help="Path to certutil binary for use with Firefox + ssl") + + ssl_group.add_argument("--ca-cert-path", action="store", type=abs_path, + help="Path to ca certificate when using pregenerated ssl certificates") + ssl_group.add_argument("--host-key-path", action="store", type=abs_path, + help="Path to host private key when using pregenerated ssl certificates") + ssl_group.add_argument("--host-cert-path", action="store", type=abs_path, + help="Path to host certificate when using pregenerated ssl certificates") + + gecko_group = parser.add_argument_group("Gecko-specific") + gecko_group.add_argument("--prefs-root", dest="prefs_root", action="store", type=abs_path, + help="Path to the folder containing browser prefs") + gecko_group.add_argument("--disable-e10s", dest="gecko_e10s", action="store_false", default=True, + help="Run tests without electrolysis preferences") + gecko_group.add_argument("--stackfix-dir", dest="stackfix_dir", action="store", + help="Path to directory containing assertion stack fixing scripts") + gecko_group.add_argument("--setpref", dest="extra_prefs", action='append', + default=[], metavar="PREF=VALUE", + help="Defines an extra user preference (overrides those in prefs_root)") + + servo_group = parser.add_argument_group("Servo-specific") + servo_group.add_argument("--user-stylesheet", + default=[], action="append", dest="user_stylesheets", + help="Inject a user CSS stylesheet into every test.") + + sauce_group = parser.add_argument_group("Sauce Labs-specific") + sauce_group.add_argument("--sauce-browser", dest="sauce_browser", + help="Sauce Labs browser name") + sauce_group.add_argument("--sauce-platform", dest="sauce_platform", + help="Sauce Labs OS platform") + sauce_group.add_argument("--sauce-version", dest="sauce_version", + help="Sauce Labs browser version") + sauce_group.add_argument("--sauce-build", dest="sauce_build", + help="Sauce Labs build identifier") + sauce_group.add_argument("--sauce-tags", dest="sauce_tags", nargs="*", + help="Sauce Labs identifying tag", default=[]) + sauce_group.add_argument("--sauce-tunnel-id", dest="sauce_tunnel_id", + help="Sauce Connect tunnel identifier") + sauce_group.add_argument("--sauce-user", dest="sauce_user", + help="Sauce Labs user name") + sauce_group.add_argument("--sauce-key", dest="sauce_key", + default=os.environ.get("SAUCE_ACCESS_KEY"), + help="Sauce Labs access key") + sauce_group.add_argument("--sauce-connect-binary", + dest="sauce_connect_binary", + help="Path to Sauce Connect binary") + + parser.add_argument("test_list", nargs="*", + help="List of URLs for tests to run, or paths including tests to run. " + "(equivalent to --include)") + + commandline.add_logging_group(parser) + return parser + + +def set_from_config(kwargs): + if kwargs["config"] is None: + config_path = config.path() + else: + config_path = kwargs["config"] + + kwargs["config_path"] = config_path + + kwargs["config"] = config.read(kwargs["config_path"]) + + keys = {"paths": [("prefs", "prefs_root", True), + ("run_info", "run_info", True)], + "web-platform-tests": [("remote_url", "remote_url", False), + ("branch", "branch", False), + ("sync_path", "sync_path", True)], + "SSL": [("openssl_binary", "openssl_binary", True), + ("certutil_binary", "certutil_binary", True), + ("ca_cert_path", "ca_cert_path", True), + ("host_cert_path", "host_cert_path", True), + ("host_key_path", "host_key_path", True)]} + + for section, values in keys.iteritems(): + for config_value, kw_value, is_path in values: + if kw_value in kwargs and kwargs[kw_value] is None: + if not is_path: + new_value = kwargs["config"].get(section, config.ConfigDict({})).get(config_value) + else: + new_value = kwargs["config"].get(section, config.ConfigDict({})).get_path(config_value) + kwargs[kw_value] = new_value + + kwargs["test_paths"] = get_test_paths(kwargs["config"]) + + if kwargs["tests_root"]: + if "/" not in kwargs["test_paths"]: + kwargs["test_paths"]["/"] = {} + kwargs["test_paths"]["/"]["tests_path"] = kwargs["tests_root"] + + if kwargs["metadata_root"]: + if "/" not in kwargs["test_paths"]: + kwargs["test_paths"]["/"] = {} + kwargs["test_paths"]["/"]["metadata_path"] = kwargs["metadata_root"] + + kwargs["suite_name"] = kwargs["config"].get("web-platform-tests", {}).get("name", "web-platform-tests") + + +def get_test_paths(config): + # Set up test_paths + test_paths = OrderedDict() + + for section in config.iterkeys(): + if section.startswith("manifest:"): + manifest_opts = config.get(section) + url_base = manifest_opts.get("url_base", "/") + test_paths[url_base] = { + "tests_path": manifest_opts.get_path("tests"), + "metadata_path": manifest_opts.get_path("metadata")} + + return test_paths + + +def exe_path(name): + if name is None: + return + + path = find_executable(name) + if os.access(path, os.X_OK): + return path + + +def check_args(kwargs): + set_from_config(kwargs) + + for test_paths in kwargs["test_paths"].itervalues(): + if not ("tests_path" in test_paths and + "metadata_path" in test_paths): + print "Fatal: must specify both a test path and metadata path" + sys.exit(1) + for key, path in test_paths.iteritems(): + name = key.split("_", 1)[0] + + if not os.path.exists(path): + print "Fatal: %s path %s does not exist" % (name, path) + sys.exit(1) + + if not os.path.isdir(path): + print "Fatal: %s path %s is not a directory" % (name, path) + sys.exit(1) + + if kwargs["product"] is None: + kwargs["product"] = "firefox" + + if "sauce" in kwargs["product"]: + kwargs["pause_after_test"] = False + + if kwargs["test_list"]: + if kwargs["include"] is not None: + kwargs["include"].extend(kwargs["test_list"]) + else: + kwargs["include"] = kwargs["test_list"] + + if kwargs["run_info"] is None: + kwargs["run_info"] = kwargs["config_path"] + + if kwargs["this_chunk"] > 1: + require_arg(kwargs, "total_chunks", lambda x: x >= kwargs["this_chunk"]) + + if kwargs["chunk_type"] is None: + if kwargs["total_chunks"] > 1: + kwargs["chunk_type"] = "dir_hash" + else: + kwargs["chunk_type"] = "none" + + if kwargs["processes"] is None: + kwargs["processes"] = 1 + + if kwargs["debugger"] is not None: + import mozdebug + if kwargs["debugger"] == "__default__": + kwargs["debugger"] = mozdebug.get_default_debugger_name() + debug_info = mozdebug.get_debugger_info(kwargs["debugger"], + kwargs["debugger_args"]) + if debug_info and debug_info.interactive: + if kwargs["processes"] != 1: + kwargs["processes"] = 1 + kwargs["no_capture_stdio"] = True + kwargs["debug_info"] = debug_info + else: + kwargs["debug_info"] = None + + if kwargs["binary"] is not None: + if not os.path.exists(kwargs["binary"]): + print >> sys.stderr, "Binary path %s does not exist" % kwargs["binary"] + sys.exit(1) + + if kwargs["ssl_type"] is None: + if None not in (kwargs["ca_cert_path"], kwargs["host_cert_path"], kwargs["host_key_path"]): + kwargs["ssl_type"] = "pregenerated" + elif exe_path(kwargs["openssl_binary"]) is not None: + kwargs["ssl_type"] = "openssl" + else: + kwargs["ssl_type"] = "none" + + if kwargs["ssl_type"] == "pregenerated": + require_arg(kwargs, "ca_cert_path", lambda x:os.path.exists(x)) + require_arg(kwargs, "host_cert_path", lambda x:os.path.exists(x)) + require_arg(kwargs, "host_key_path", lambda x:os.path.exists(x)) + + elif kwargs["ssl_type"] == "openssl": + path = exe_path(kwargs["openssl_binary"]) + if path is None: + print >> sys.stderr, "openssl-binary argument missing or not a valid executable" + sys.exit(1) + kwargs["openssl_binary"] = path + + if kwargs["ssl_type"] != "none" and kwargs["product"] == "firefox": + path = exe_path(kwargs["certutil_binary"]) + if path is None: + print >> sys.stderr, "certutil-binary argument missing or not a valid executable" + sys.exit(1) + kwargs["certutil_binary"] = path + + if kwargs['extra_prefs']: + missing = any('=' not in prefarg for prefarg in kwargs['extra_prefs']) + if missing: + print >> sys.stderr, "Preferences via --setpref must be in key=value format" + sys.exit(1) + kwargs['extra_prefs'] = [tuple(prefarg.split('=', 1)) for prefarg in + kwargs['extra_prefs']] + + return kwargs + + +def check_args_update(kwargs): + set_from_config(kwargs) + + if kwargs["product"] is None: + kwargs["product"] = "firefox" + + +def create_parser_update(product_choices=None): + from mozlog.structured import commandline + + import products + + if product_choices is None: + config_data = config.load() + product_choices = products.products_enabled(config_data) + + parser = argparse.ArgumentParser("web-platform-tests-update", + description="Update script for web-platform-tests tests.") + parser.add_argument("--product", action="store", choices=product_choices, + default=None, help="Browser for which metadata is being updated") + parser.add_argument("--config", action="store", type=abs_path, help="Path to config file") + parser.add_argument("--metadata", action="store", type=abs_path, dest="metadata_root", + help="Path to the folder containing test metadata"), + parser.add_argument("--tests", action="store", type=abs_path, dest="tests_root", + help="Path to web-platform-tests"), + parser.add_argument("--sync-path", action="store", type=abs_path, + help="Path to store git checkout of web-platform-tests during update"), + parser.add_argument("--remote_url", action="store", + help="URL of web-platfrom-tests repository to sync against"), + parser.add_argument("--branch", action="store", type=abs_path, + help="Remote branch to sync against") + parser.add_argument("--rev", action="store", help="Revision to sync to") + parser.add_argument("--no-patch", action="store_true", + help="Don't create an mq patch or git commit containing the changes.") + parser.add_argument("--sync", dest="sync", action="store_true", default=False, + help="Sync the tests with the latest from upstream") + parser.add_argument("--ignore-existing", action="store_true", help="When updating test results only consider results from the logfiles provided, not existing expectations.") + parser.add_argument("--continue", action="store_true", help="Continue a previously started run of the update script") + parser.add_argument("--abort", action="store_true", help="Clear state from a previous incomplete run of the update script") + # Should make this required iff run=logfile + parser.add_argument("run_log", nargs="*", type=abs_path, + help="Log file from run of tests") + commandline.add_logging_group(parser) + return parser + + +def create_parser_reduce(product_choices=None): + parser = create_parser(product_choices) + parser.add_argument("target", action="store", help="Test id that is unstable") + return parser + + +def parse_args(): + parser = create_parser() + rv = vars(parser.parse_args()) + check_args(rv) + return rv + + +def parse_args_update(): + parser = create_parser_update() + rv = vars(parser.parse_args()) + check_args_update(rv) + return rv + + +def parse_args_reduce(): + parser = create_parser_reduce() + rv = vars(parser.parse_args()) + check_args(rv) + return rv diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptlogging.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptlogging.py new file mode 100644 index 000000000000..1ab6755c4352 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptlogging.py @@ -0,0 +1,121 @@ +import logging +import sys +import threading +from StringIO import StringIO +from multiprocessing import Queue + +from mozlog import commandline, stdadapter + +def setup(args, defaults): + logger = commandline.setup_logging("web-platform-tests", args, defaults) + setup_stdlib_logger() + + for name in args.keys(): + if name.startswith("log_"): + args.pop(name) + + return logger + + +def setup_stdlib_logger(): + logging.root.handlers = [] + logging.root = stdadapter.std_logging_adapter(logging.root) + + +class LogLevelRewriter(object): + """Filter that replaces log messages at specified levels with messages + at a different level. + + This can be used to e.g. downgrade log messages from ERROR to WARNING + in some component where ERRORs are not critical. + + :param inner: Handler to use for messages that pass this filter + :param from_levels: List of levels which should be affected + :param to_level: Log level to set for the affected messages + """ + def __init__(self, inner, from_levels, to_level): + self.inner = inner + self.from_levels = [item.upper() for item in from_levels] + self.to_level = to_level.upper() + + def __call__(self, data): + if data["action"] == "log" and data["level"].upper() in self.from_levels: + data = data.copy() + data["level"] = self.to_level + return self.inner(data) + + + +class LogThread(threading.Thread): + def __init__(self, queue, logger, level): + self.queue = queue + self.log_func = getattr(logger, level) + threading.Thread.__init__(self, name="Thread-Log") + self.daemon = True + + def run(self): + while True: + try: + msg = self.queue.get() + except (EOFError, IOError): + break + if msg is None: + break + else: + self.log_func(msg) + + +class LoggingWrapper(StringIO): + """Wrapper for file like objects to redirect output to logger + instead""" + + def __init__(self, queue, prefix=None): + StringIO.__init__(self) + self.queue = queue + self.prefix = prefix + + def write(self, data): + if isinstance(data, str): + data = data.decode("utf8") + + if data.endswith("\n"): + data = data[:-1] + if data.endswith("\r"): + data = data[:-1] + if not data: + return + if self.prefix is not None: + data = "%s: %s" % (self.prefix, data) + self.queue.put(data) + + def flush(self): + pass + + +class CaptureIO(object): + def __init__(self, logger, do_capture): + self.logger = logger + self.do_capture = do_capture + self.logging_queue = None + self.logging_thread = None + self.original_stdio = None + + def __enter__(self): + if self.do_capture: + self.original_stdio = (sys.stdout, sys.stderr) + self.logging_queue = Queue() + self.logging_thread = LogThread(self.logging_queue, self.logger, "info") + sys.stdout = LoggingWrapper(self.logging_queue, prefix="STDOUT") + sys.stderr = LoggingWrapper(self.logging_queue, prefix="STDERR") + self.logging_thread.start() + + def __exit__(self, *args, **kwargs): + if self.do_capture: + sys.stdout, sys.stderr = self.original_stdio + if self.logging_queue is not None: + self.logger.info("Closing logging queue") + self.logging_queue.put(None) + if self.logging_thread is not None: + self.logging_thread.join(10) + self.logging_queue.close() + self.logger.info("queue closed") diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/__init__.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/__init__.py new file mode 100644 index 000000000000..6b64784c7e66 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/__init__.py @@ -0,0 +1,4 @@ +from serializer import serialize +from parser import parse +from backends.static import compile as compile_static +from backends.conditional import compile as compile_condition diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/backends/__init__.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/backends/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py new file mode 100644 index 000000000000..f0f4ecf335ff --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py @@ -0,0 +1,330 @@ +import operator + +from ..node import NodeVisitor, DataNode, ConditionalNode, KeyValueNode, ListNode, ValueNode +from ..parser import parse + + +class ConditionalValue(object): + def __init__(self, node, condition_func): + self.node = node + self.condition_func = condition_func + if isinstance(node, ConditionalNode): + assert len(node.children) == 2 + self.condition_node = self.node.children[0] + self.value_node = self.node.children[1] + else: + assert isinstance(node, (ValueNode, ListNode)) + self.condition_node = None + self.value_node = self.node + + @property + def value(self): + if isinstance(self.value_node, ValueNode): + return self.value_node.data + else: + return [item.data for item in self.value_node.children] + + @value.setter + def value(self, value): + self.value_node.data = value + + def __call__(self, run_info): + return self.condition_func(run_info) + + def set_value(self, value): + self.value = value + + def remove(self): + if len(self.node.parent.children) == 1: + self.node.parent.remove() + self.node.remove() + + +class Compiler(NodeVisitor): + def compile(self, tree, data_cls_getter=None, **kwargs): + """Compile a raw AST into a form where conditional expressions + are represented by ConditionalValue objects that can be evaluated + at runtime. + + tree - The root node of the wptmanifest AST to compile + + data_cls_getter - A function taking two parameters; the previous + output node and the current ast node and returning + the class of the output node to use for the current + ast node + """ + if data_cls_getter is None: + self.data_cls_getter = lambda x, y: ManifestItem + else: + self.data_cls_getter = data_cls_getter + + self.tree = tree + self.output_node = self._initial_output_node(tree, **kwargs) + self.visit(tree) + assert self.output_node is not None + return self.output_node + + def compile_condition(self, condition): + """Compile a ConditionalNode into a ConditionalValue. + + condition: A ConditionalNode""" + data_node = DataNode() + key_value_node = KeyValueNode() + key_value_node.append(condition.copy()) + data_node.append(key_value_node) + manifest_item = self.compile(data_node) + return manifest_item._data[None][0] + + def _initial_output_node(self, node, **kwargs): + return self.data_cls_getter(None, None)(node, **kwargs) + + def visit_DataNode(self, node): + if node != self.tree: + output_parent = self.output_node + self.output_node = self.data_cls_getter(self.output_node, node)(node) + else: + output_parent = None + + assert self.output_node is not None + + for child in node.children: + self.visit(child) + + if output_parent is not None: + # Append to the parent *after* processing all the node data + output_parent.append(self.output_node) + self.output_node = self.output_node.parent + + assert self.output_node is not None + + def visit_KeyValueNode(self, node): + key_values = [] + for child in node.children: + condition, value = self.visit(child) + key_values.append(ConditionalValue(child, condition)) + + self.output_node._add_key_value(node, key_values) + + def visit_ListNode(self, node): + return (lambda x:True, [self.visit(child) for child in node.children]) + + def visit_ValueNode(self, node): + return (lambda x: True, node.data) + + def visit_AtomNode(self, node): + return (lambda x: True, node.data) + + def visit_ConditionalNode(self, node): + return self.visit(node.children[0]), self.visit(node.children[1]) + + def visit_StringNode(self, node): + indexes = [self.visit(child) for child in node.children] + + def value(x): + rv = node.data + for index in indexes: + rv = rv[index(x)] + return rv + return value + + def visit_NumberNode(self, node): + if "." in node.data: + return lambda x: float(node.data) + else: + return lambda x: int(node.data) + + def visit_VariableNode(self, node): + indexes = [self.visit(child) for child in node.children] + + def value(x): + data = x[node.data] + for index in indexes: + data = data[index(x)] + return data + return value + + def visit_IndexNode(self, node): + assert len(node.children) == 1 + return self.visit(node.children[0]) + + def visit_UnaryExpressionNode(self, node): + assert len(node.children) == 2 + operator = self.visit(node.children[0]) + operand = self.visit(node.children[1]) + + return lambda x: operator(operand(x)) + + def visit_BinaryExpressionNode(self, node): + assert len(node.children) == 3 + operator = self.visit(node.children[0]) + operand_0 = self.visit(node.children[1]) + operand_1 = self.visit(node.children[2]) + + assert operand_0 is not None + assert operand_1 is not None + + return lambda x: operator(operand_0(x), operand_1(x)) + + def visit_UnaryOperatorNode(self, node): + return {"not": operator.not_}[node.data] + + def visit_BinaryOperatorNode(self, node): + return {"and": operator.and_, + "or": operator.or_, + "==": operator.eq, + "!=": operator.ne}[node.data] + + +class ManifestItem(object): + def __init__(self, node=None, **kwargs): + self.node = node + self.parent = None + self.children = [] + self._data = {} + + def __repr__(self): + return "" % (self.node.data) + + def __str__(self): + rv = [repr(self)] + for item in self.children: + rv.extend(" %s" % line for line in str(item).split("\n")) + return "\n".join(rv) + + def __contains__(self, key): + return key in self._data + + @property + def is_empty(self): + if self._data: + return False + return all(child.is_empty for child in self.children) + + @property + def root(self): + node = self + while node.parent is not None: + node = node.parent + return node + + @property + def name(self): + return self.node.data + + def has_key(self, key): + for node in [self, self.root]: + if key in node._data: + return True + return False + + def get(self, key, run_info=None): + if run_info is None: + run_info = {} + + for node in [self, self.root]: + if key in node._data: + for cond_value in node._data[key]: + try: + matches = cond_value(run_info) + except KeyError: + matches = False + if matches: + return cond_value.value + raise KeyError + + def set(self, key, value, condition=None): + # First try to update the existing value + if key in self._data: + cond_values = self._data[key] + for cond_value in cond_values: + if cond_value.condition_node == condition: + cond_value.value = value + return + # If there isn't a conditional match reuse the existing KeyValueNode as the + # parent + node = None + for child in self.node.children: + if child.data == key: + node = child + break + assert node is not None + + else: + node = KeyValueNode(key) + self.node.append(node) + + value_node = ValueNode(value) + if condition is not None: + conditional_node = ConditionalNode() + conditional_node.append(condition) + conditional_node.append(value_node) + node.append(conditional_node) + cond_value = Compiler().compile_condition(conditional_node) + else: + node.append(value_node) + cond_value = ConditionalValue(value_node, lambda x: True) + + # Update the cache of child values. This is pretty annoying and maybe + # it should just work directly on the tree + if key not in self._data: + self._data[key] = [] + if self._data[key] and self._data[key][-1].condition_node is None: + self._data[key].insert(len(self._data[key]) - 1, cond_value) + else: + self._data[key].append(cond_value) + + def _add_key_value(self, node, values): + """Called during construction to set a key-value node""" + self._data[node.data] = values + + def append(self, child): + self.children.append(child) + child.parent = self + if child.node.parent != self.node: + self.node.append(child.node) + return child + + def remove(self): + if self.parent: + self.parent._remove_child(self) + + def _remove_child(self, child): + self.children.remove(child) + child.parent = None + + def iterchildren(self, name=None): + for item in self.children: + if item.name == name or name is None: + yield item + + def _flatten(self): + rv = {} + for node in [self, self.root]: + for name, value in node._data.iteritems(): + if name not in rv: + rv[name] = value + return rv + + def iteritems(self): + for item in self._flatten().iteritems(): + yield item + + def iterkeys(self): + for item in self._flatten().iterkeys(): + yield item + + def remove_value(self, key, value): + self._data[key].remove(value) + if not self._data[key]: + del self._data[key] + value.remove() + + +def compile_ast(ast, data_cls_getter=None, **kwargs): + return Compiler().compile(ast, data_cls_getter=data_cls_getter, **kwargs) + + +def compile(stream, data_cls_getter=None, **kwargs): + return compile_ast(parse(stream), + data_cls_getter=data_cls_getter, + **kwargs) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/backends/static.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/backends/static.py new file mode 100644 index 000000000000..b2b9fbe94298 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/backends/static.py @@ -0,0 +1,220 @@ +import operator + +from ..node import NodeVisitor +from ..parser import parse + + +class Compiler(NodeVisitor): + """Compiler backend that evaluates conditional expressions + to give static output""" + + def compile(self, tree, expr_data, data_cls_getter=None, **kwargs): + """Compile a raw AST into a form with conditional expressions + evaluated. + + tree - The root node of the wptmanifest AST to compile + + expr_data - A dictionary of key / value pairs to use when + evaluating conditional expressions + + data_cls_getter - A function taking two parameters; the previous + output node and the current ast node and returning + the class of the output node to use for the current + ast node + """ + + self._kwargs = kwargs + self.expr_data = expr_data + + if data_cls_getter is None: + self.data_cls_getter = lambda x, y: ManifestItem + else: + self.data_cls_getter = data_cls_getter + + self.output_node = None + self.visit(tree) + return self.output_node + + def visit_DataNode(self, node): + output_parent = self.output_node + if self.output_node is None: + assert node.parent is None + self.output_node = self.data_cls_getter(None, None)(None, **self._kwargs) + else: + self.output_node = self.data_cls_getter(self.output_node, node)(node.data) + + for child in node.children: + self.visit(child) + + if output_parent is not None: + output_parent.append(self.output_node) + self.output_node = self.output_node.parent + + def visit_KeyValueNode(self, node): + key_name = node.data + key_value = None + for child in node.children: + value = self.visit(child) + if value is not None: + key_value = value + break + if key_value is not None: + self.output_node.set(key_name, key_value) + + def visit_ValueNode(self, node): + return node.data + + def visit_AtomNode(self, node): + return node.data + + def visit_ListNode(self, node): + return [self.visit(child) for child in node.children] + + def visit_ConditionalNode(self, node): + assert len(node.children) == 2 + if self.visit(node.children[0]): + return self.visit(node.children[1]) + + def visit_StringNode(self, node): + value = node.data + for child in node.children: + value = self.visit(child)(value) + return value + + def visit_NumberNode(self, node): + if "." in node.data: + return float(node.data) + else: + return int(node.data) + + def visit_VariableNode(self, node): + value = self.expr_data[node.data] + for child in node.children: + value = self.visit(child)(value) + return value + + def visit_IndexNode(self, node): + assert len(node.children) == 1 + index = self.visit(node.children[0]) + return lambda x: x[index] + + def visit_UnaryExpressionNode(self, node): + assert len(node.children) == 2 + operator = self.visit(node.children[0]) + operand = self.visit(node.children[1]) + + return operator(operand) + + def visit_BinaryExpressionNode(self, node): + assert len(node.children) == 3 + operator = self.visit(node.children[0]) + operand_0 = self.visit(node.children[1]) + operand_1 = self.visit(node.children[2]) + + return operator(operand_0, operand_1) + + def visit_UnaryOperatorNode(self, node): + return {"not": operator.not_}[node.data] + + def visit_BinaryOperatorNode(self, node): + return {"and": operator.and_, + "or": operator.or_, + "==": operator.eq, + "!=": operator.ne}[node.data] + + +class ManifestItem(object): + def __init__(self, name, **kwargs): + self.parent = None + self.name = name + self.children = [] + self._data = {} + + def __repr__(self): + return "" % (self.name) + + def __str__(self): + rv = [repr(self)] + for item in self.children: + rv.extend(" %s" % line for line in str(item).split("\n")) + return "\n".join(rv) + + @property + def is_empty(self): + if self._data: + return False + return all(child.is_empty for child in self.children) + + @property + def root(self): + node = self + while node.parent is not None: + node = node.parent + return node + + def has_key(self, key): + for node in [self, self.root]: + if key in node._data: + return True + return False + + def get(self, key): + for node in [self, self.root]: + if key in node._data: + return node._data[key] + raise KeyError + + def set(self, name, value): + self._data[name] = value + + def remove(self): + if self.parent: + self.parent._remove_child(self) + + def _remove_child(self, child): + self.children.remove(child) + child.parent = None + + def iterchildren(self, name=None): + for item in self.children: + if item.name == name or name is None: + yield item + + def _flatten(self): + rv = {} + for node in [self, self.root]: + for name, value in node._data.iteritems(): + if name not in rv: + rv[name] = value + return rv + + def iteritems(self): + for item in self._flatten().iteritems(): + yield item + + def iterkeys(self): + for item in self._flatten().iterkeys(): + yield item + + def itervalues(self): + for item in self._flatten().itervalues(): + yield item + + def append(self, child): + child.parent = self + self.children.append(child) + return child + + +def compile_ast(ast, expr_data, data_cls_getter=None, **kwargs): + return Compiler().compile(ast, + expr_data, + data_cls_getter=data_cls_getter, + **kwargs) + + +def compile(stream, expr_data, data_cls_getter=None, **kwargs): + return compile_ast(parse(stream), + expr_data, + data_cls_getter=data_cls_getter, + **kwargs) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/node.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/node.py new file mode 100644 index 000000000000..33e9796c430c --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/node.py @@ -0,0 +1,157 @@ +class NodeVisitor(object): + def visit(self, node): + # This is ugly as hell, but we don't have multimethods and + # they aren't trivial to fake without access to the class + # object from the class body + func = getattr(self, "visit_%s" % (node.__class__.__name__)) + return func(node) + + +class Node(object): + def __init__(self, data=None): + self.data = data + self.parent = None + self.children = [] + + def append(self, other): + other.parent = self + self.children.append(other) + + def remove(self): + self.parent.children.remove(self) + + def __repr__(self): + return "<%s %s>" % (self.__class__.__name__, self.data) + + def __str__(self): + rv = [repr(self)] + for item in self.children: + rv.extend(" %s" % line for line in str(item).split("\n")) + return "\n".join(rv) + + def __eq__(self, other): + if not (self.__class__ == other.__class__ and + self.data == other.data and + len(self.children) == len(other.children)): + return False + for child, other_child in zip(self.children, other.children): + if not child == other_child: + return False + return True + + def copy(self): + new = self.__class__(self.data) + for item in self.children: + new.append(item.copy()) + return new + + +class DataNode(Node): + def append(self, other): + # Append that retains the invariant that child data nodes + # come after child nodes of other types + other.parent = self + if isinstance(other, DataNode): + self.children.append(other) + else: + index = len(self.children) + while index > 0 and isinstance(self.children[index - 1], DataNode): + index -= 1 + for i in xrange(index): + assert other.data != self.children[i].data + self.children.insert(index, other) + + +class KeyValueNode(Node): + def append(self, other): + # Append that retains the invariant that conditional nodes + # come before unconditional nodes + other.parent = self + if isinstance(other, ValueNode): + if self.children: + assert not isinstance(self.children[-1], ValueNode) + self.children.append(other) + else: + if self.children and isinstance(self.children[-1], ValueNode): + self.children.insert(len(self.children) - 1, other) + else: + self.children.append(other) + + +class ListNode(Node): + def append(self, other): + other.parent = self + self.children.append(other) + + +class ValueNode(Node): + def append(self, other): + raise TypeError + + +class AtomNode(ValueNode): + pass + + +class ConditionalNode(Node): + pass + + +class UnaryExpressionNode(Node): + def __init__(self, operator, operand): + Node.__init__(self) + self.append(operator) + self.append(operand) + + def append(self, other): + Node.append(self, other) + assert len(self.children) <= 2 + + def copy(self): + new = self.__class__(self.children[0].copy(), + self.children[1].copy()) + return new + + +class BinaryExpressionNode(Node): + def __init__(self, operator, operand_0, operand_1): + Node.__init__(self) + self.append(operator) + self.append(operand_0) + self.append(operand_1) + + def append(self, other): + Node.append(self, other) + assert len(self.children) <= 3 + + def copy(self): + new = self.__class__(self.children[0].copy(), + self.children[1].copy(), + self.children[2].copy()) + return new + + +class UnaryOperatorNode(Node): + def append(self, other): + raise TypeError + + +class BinaryOperatorNode(Node): + def append(self, other): + raise TypeError + + +class IndexNode(Node): + pass + + +class VariableNode(Node): + pass + + +class StringNode(Node): + pass + + +class NumberNode(ValueNode): + pass diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/parser.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/parser.py new file mode 100644 index 000000000000..d84a9143fa63 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/parser.py @@ -0,0 +1,746 @@ +#default_value:foo +#include: other.manifest +# +#[test_name.js] +# expected: ERROR +# +# [subtest 1] +# expected: +# os == win: FAIL #This is a comment +# PASS +# + +# TODO: keep comments in the tree + +from __future__ import unicode_literals + +import types +from cStringIO import StringIO + +from node import * + + +class ParseError(Exception): + def __init__(self, filename, line, detail): + self.line = line + self.filename = filename + self.detail = detail + self.message = "%s: %s line %s" % (self.detail, self.filename, self.line) + Exception.__init__(self, self.message) + +eol = object +group_start = object +group_end = object +digits = "0123456789" +open_parens = "[(" +close_parens = "])" +parens = open_parens + close_parens +operator_chars = "=!" + +unary_operators = ["not"] +binary_operators = ["==", "!=", "and", "or"] + +operators = ["==", "!=", "not", "and", "or"] + +atoms = {"True": True, + "False": False, + "Reset": object()} + +def decode(s): + assert isinstance(s, unicode) + return s + + +def precedence(operator_node): + return len(operators) - operators.index(operator_node.data) + + +class TokenTypes(object): + def __init__(self): + for type in ["group_start", "group_end", "paren", "list_start", "list_end", "separator", "ident", "string", "number", "atom", "eof"]: + setattr(self, type, type) + +token_types = TokenTypes() + + +class Tokenizer(object): + def __init__(self): + self.reset() + + def reset(self): + self.indent_levels = [0] + self.state = self.line_start_state + self.next_state = self.data_line_state + self.line_number = 0 + + def tokenize(self, stream): + self.reset() + assert not isinstance(stream, unicode) + if isinstance(stream, str): + stream = StringIO(stream) + if not hasattr(stream, "name"): + self.filename = "" + else: + self.filename = stream.name + + self.next_line_state = self.line_start_state + for i, line in enumerate(stream): + assert isinstance(line, str) + self.state = self.next_line_state + assert self.state is not None + states = [] + self.next_line_state = None + self.line_number = i + 1 + self.index = 0 + self.line = line.decode('utf-8').rstrip() + assert isinstance(self.line, unicode) + while self.state != self.eol_state: + states.append(self.state) + tokens = self.state() + if tokens: + for token in tokens: + yield token + self.state() + while True: + yield (token_types.eof, None) + + def char(self): + if self.index == len(self.line): + return eol + return self.line[self.index] + + def consume(self): + if self.index < len(self.line): + self.index += 1 + + def peek(self, length): + return self.line[self.index:self.index + length] + + def skip_whitespace(self): + while self.char() == " ": + self.consume() + + def eol_state(self): + if self.next_line_state is None: + self.next_line_state = self.line_start_state + + def line_start_state(self): + self.skip_whitespace() + if self.char() == eol: + self.state = self.eol_state + return + if self.index > self.indent_levels[-1]: + self.indent_levels.append(self.index) + yield (token_types.group_start, None) + else: + while self.index < self.indent_levels[-1]: + self.indent_levels.pop() + yield (token_types.group_end, None) + # This is terrible; if we were parsing an expression + # then the next_state will be expr_or_value but when we deindent + # it must always be a heading or key next so we go back to data_line_state + self.next_state = self.data_line_state + if self.index != self.indent_levels[-1]: + raise ParseError(self.filename, self.line_number, "Unexpected indent") + + self.state = self.next_state + + def data_line_state(self): + if self.char() == "[": + yield (token_types.paren, self.char()) + self.consume() + self.state = self.heading_state + else: + self.state = self.key_state + + def heading_state(self): + rv = "" + while True: + c = self.char() + if c == "\\": + rv += self.consume_escape() + elif c == "]": + break + elif c == eol: + raise ParseError(self.filename, self.line_number, "EOL in heading") + else: + rv += c + self.consume() + + yield (token_types.string, decode(rv)) + yield (token_types.paren, "]") + self.consume() + self.state = self.line_end_state + self.next_state = self.data_line_state + + def key_state(self): + rv = "" + while True: + c = self.char() + if c == " ": + self.skip_whitespace() + if self.char() != ":": + raise ParseError(self.filename, self.line_number, "Space in key name") + break + elif c == ":": + break + elif c == eol: + raise ParseError(self.filename, self.line_number, "EOL in key name (missing ':'?)") + elif c == "\\": + rv += self.consume_escape() + else: + rv += c + self.consume() + yield (token_types.string, decode(rv)) + yield (token_types.separator, ":") + self.consume() + self.state = self.after_key_state + + def after_key_state(self): + self.skip_whitespace() + c = self.char() + if c == "#": + self.next_state = self.expr_or_value_state + self.state = self.comment_state + elif c == eol: + self.next_state = self.expr_or_value_state + self.state = self.eol_state + elif c == "[": + self.state = self.list_start_state + else: + self.state = self.value_state + + def list_start_state(self): + yield (token_types.list_start, "[") + self.consume() + self.state = self.list_value_start_state + + def list_value_start_state(self): + self.skip_whitespace() + if self.char() == "]": + self.state = self.list_end_state + elif self.char() in ("'", '"'): + quote_char = self.char() + self.consume() + yield (token_types.string, self.consume_string(quote_char)) + self.skip_whitespace() + if self.char() == "]": + self.state = self.list_end_state + elif self.char() != ",": + raise ParseError(self.filename, self.line_number, "Junk after quoted string") + self.consume() + elif self.char() == "#": + self.state = self.comment_state + self.next_line_state = self.list_value_start_state + elif self.char() == eol: + self.next_line_state = self.list_value_start_state + self.state = self.eol_state + elif self.char() == ",": + raise ParseError(self.filename, self.line_number, "List item started with separator") + elif self.char() == "@": + self.state = self.list_value_atom_state + else: + self.state = self.list_value_state + + def list_value_state(self): + rv = "" + spaces = 0 + while True: + c = self.char() + if c == "\\": + escape = self.consume_escape() + rv += escape + elif c == eol: + raise ParseError(self.filename, self.line_number, "EOL in list value") + elif c == "#": + raise ParseError(self.filename, self.line_number, "EOL in list value (comment)") + elif c == ",": + self.state = self.list_value_start_state + self.consume() + break + elif c == " ": + spaces += 1 + self.consume() + elif c == "]": + self.state = self.list_end_state + self.consume() + break + else: + rv += " " * spaces + spaces = 0 + rv += c + self.consume() + + if rv: + yield (token_types.string, decode(rv)) + + def list_value_atom_state(self): + self.consume() + for _, value in self.list_value_state(): + yield token_types.atom, value + + def list_end_state(self): + self.consume() + yield (token_types.list_end, "]") + self.state = self.line_end_state + + def value_state(self): + self.skip_whitespace() + if self.char() in ("'", '"'): + quote_char = self.char() + self.consume() + yield (token_types.string, self.consume_string(quote_char)) + if self.char() == "#": + self.state = self.comment_state + else: + self.state = self.line_end_state + elif self.char() == "@": + self.consume() + for _, value in self.value_inner_state(): + yield token_types.atom, value + else: + self.state = self.value_inner_state + + def value_inner_state(self): + rv = "" + spaces = 0 + while True: + c = self.char() + if c == "\\": + rv += self.consume_escape() + elif c == "#": + self.state = self.comment_state + break + elif c == " ": + # prevent whitespace before comments from being included in the value + spaces += 1 + self.consume() + elif c == eol: + self.state = self.line_end_state + break + else: + rv += " " * spaces + spaces = 0 + rv += c + self.consume() + yield (token_types.string, decode(rv)) + + def comment_state(self): + while self.char() is not eol: + self.consume() + self.state = self.eol_state + + def line_end_state(self): + self.skip_whitespace() + c = self.char() + if c == "#": + self.state = self.comment_state + elif c == eol: + self.state = self.eol_state + else: + raise ParseError(self.filename, self.line_number, "Junk before EOL %s" % c) + + def consume_string(self, quote_char): + rv = "" + while True: + c = self.char() + if c == "\\": + rv += self.consume_escape() + elif c == quote_char: + self.consume() + break + elif c == eol: + raise ParseError(self.filename, self.line_number, "EOL in quoted string") + else: + rv += c + self.consume() + + return decode(rv) + + def expr_or_value_state(self): + if self.peek(3) == "if ": + self.state = self.expr_state + else: + self.state = self.value_state + + def expr_state(self): + self.skip_whitespace() + c = self.char() + if c == eol: + raise ParseError(self.filename, self.line_number, "EOL in expression") + elif c in "'\"": + self.consume() + yield (token_types.string, self.consume_string(c)) + elif c == "#": + raise ParseError(self.filename, self.line_number, "Comment before end of expression") + elif c == ":": + yield (token_types.separator, c) + self.consume() + self.state = self.value_state + elif c in parens: + self.consume() + yield (token_types.paren, c) + elif c in ("!", "="): + self.state = self.operator_state + elif c in digits: + self.state = self.digit_state + else: + self.state = self.ident_state + + def operator_state(self): + # Only symbolic operators + index_0 = self.index + while True: + c = self.char() + if c == eol: + break + elif c in operator_chars: + self.consume() + else: + self.state = self.expr_state + break + yield (token_types.ident, self.line[index_0:self.index]) + + def digit_state(self): + index_0 = self.index + seen_dot = False + while True: + c = self.char() + if c == eol: + break + elif c in digits: + self.consume() + elif c == ".": + if seen_dot: + raise ParseError(self.filename, self.line_number, "Invalid number") + self.consume() + seen_dot = True + elif c in parens: + break + elif c in operator_chars: + break + elif c == " ": + break + elif c == ":": + break + else: + raise ParseError(self.filename, self.line_number, "Invalid character in number") + + self.state = self.expr_state + yield (token_types.number, self.line[index_0:self.index]) + + def ident_state(self): + index_0 = self.index + while True: + c = self.char() + if c == eol: + break + elif c == ".": + break + elif c in parens: + break + elif c in operator_chars: + break + elif c == " ": + break + elif c == ":": + break + else: + self.consume() + self.state = self.expr_state + yield (token_types.ident, self.line[index_0:self.index]) + + def consume_escape(self): + assert self.char() == "\\" + self.consume() + c = self.char() + self.consume() + if c == "x": + return self.decode_escape(2) + elif c == "u": + return self.decode_escape(4) + elif c == "U": + return self.decode_escape(6) + elif c in ["a", "b", "f", "n", "r", "t", "v"]: + return eval("'\%s'" % c) + elif c is eol: + raise ParseError(self.filename, self.line_number, "EOL in escape") + else: + return c + + def decode_escape(self, length): + value = 0 + for i in xrange(length): + c = self.char() + value *= 16 + value += self.escape_value(c) + self.consume() + + return unichr(value) + + def escape_value(self, c): + if '0' <= c <= '9': + return ord(c) - ord('0') + elif 'a' <= c <= 'f': + return ord(c) - ord('a') + 10 + elif 'A' <= c <= 'F': + return ord(c) - ord('A') + 10 + else: + raise ParseError(self.filename, self.line_number, "Invalid character escape") + + +class Parser(object): + def __init__(self): + self.reset() + + def reset(self): + self.token = None + self.unary_operators = "!" + self.binary_operators = frozenset(["&&", "||", "=="]) + self.tokenizer = Tokenizer() + self.token_generator = None + self.tree = Treebuilder(DataNode(None)) + self.expr_builder = None + self.expr_builders = [] + + def parse(self, input): + self.reset() + self.token_generator = self.tokenizer.tokenize(input) + self.consume() + self.manifest() + return self.tree.node + + def consume(self): + self.token = self.token_generator.next() + + def expect(self, type, value=None): + if self.token[0] != type: + raise ParseError + if value is not None: + if self.token[1] != value: + raise ParseError + + self.consume() + + def manifest(self): + self.data_block() + self.expect(token_types.eof) + + def data_block(self): + while self.token[0] == token_types.string: + self.tree.append(KeyValueNode(self.token[1])) + self.consume() + self.expect(token_types.separator) + self.value_block() + self.tree.pop() + + while self.token == (token_types.paren, "["): + self.consume() + if self.token[0] != token_types.string: + raise ParseError + self.tree.append(DataNode(self.token[1])) + self.consume() + self.expect(token_types.paren, "]") + if self.token[0] == token_types.group_start: + self.consume() + self.data_block() + self.eof_or_end_group() + self.tree.pop() + + def eof_or_end_group(self): + if self.token[0] != token_types.eof: + self.expect(token_types.group_end) + + def value_block(self): + if self.token[0] == token_types.list_start: + self.consume() + self.list_value() + elif self.token[0] == token_types.string: + self.value() + elif self.token[0] == token_types.group_start: + self.consume() + self.expression_values() + if self.token[0] == token_types.string: + self.value() + self.eof_or_end_group() + elif self.token[0] == token_types.atom: + self.atom() + else: + raise ParseError + + def list_value(self): + self.tree.append(ListNode()) + while self.token[0] in (token_types.atom, token_types.string): + if self.token[0] == token_types.atom: + self.atom() + else: + self.value() + self.expect(token_types.list_end) + self.tree.pop() + + def expression_values(self): + while self.token == (token_types.ident, "if"): + self.consume() + self.tree.append(ConditionalNode()) + self.expr_start() + self.expect(token_types.separator) + if self.token[0] == token_types.string: + self.value() + else: + raise ParseError + self.tree.pop() + + def value(self): + self.tree.append(ValueNode(self.token[1])) + self.consume() + self.tree.pop() + + def atom(self): + if self.token[1] not in atoms: + raise ParseError(self.tokenizer.filename, self.tokenizer.line_number, "Unrecognised symbol @%s" % self.token[1]) + self.tree.append(AtomNode(atoms[self.token[1]])) + self.consume() + self.tree.pop() + + def expr_start(self): + self.expr_builder = ExpressionBuilder(self.tokenizer) + self.expr_builders.append(self.expr_builder) + self.expr() + expression = self.expr_builder.finish() + self.expr_builders.pop() + self.expr_builder = self.expr_builders[-1] if self.expr_builders else None + if self.expr_builder: + self.expr_builder.operands[-1].children[-1].append(expression) + else: + self.tree.append(expression) + self.tree.pop() + + def expr(self): + self.expr_operand() + while (self.token[0] == token_types.ident and self.token[1] in binary_operators): + self.expr_bin_op() + self.expr_operand() + + def expr_operand(self): + if self.token == (token_types.paren, "("): + self.consume() + self.expr_builder.left_paren() + self.expr() + self.expect(token_types.paren, ")") + self.expr_builder.right_paren() + elif self.token[0] == token_types.ident and self.token[1] in unary_operators: + self.expr_unary_op() + self.expr_operand() + elif self.token[0] in [token_types.string, token_types.ident]: + self.expr_value() + elif self.token[0] == token_types.number: + self.expr_number() + else: + raise ParseError(self.tokenizer.filename, self.tokenizer.line_number, "Unrecognised operand") + + def expr_unary_op(self): + if self.token[1] in unary_operators: + self.expr_builder.push_operator(UnaryOperatorNode(self.token[1])) + self.consume() + else: + raise ParseError(self.tokenizer.filename, self.tokenizer.line_number, "Expected unary operator") + + def expr_bin_op(self): + if self.token[1] in binary_operators: + self.expr_builder.push_operator(BinaryOperatorNode(self.token[1])) + self.consume() + else: + raise ParseError(self.tokenizer.filename, self.tokenizer.line_number, "Expected binary operator") + + def expr_value(self): + node_type = {token_types.string: StringNode, + token_types.ident: VariableNode}[self.token[0]] + self.expr_builder.push_operand(node_type(self.token[1])) + self.consume() + if self.token == (token_types.paren, "["): + self.consume() + self.expr_builder.operands[-1].append(IndexNode()) + self.expr_start() + self.expect(token_types.paren, "]") + + def expr_number(self): + self.expr_builder.push_operand(NumberNode(self.token[1])) + self.consume() + + +class Treebuilder(object): + def __init__(self, root): + self.root = root + self.node = root + + def append(self, node): + self.node.append(node) + self.node = node + return node + + def pop(self): + node = self.node + self.node = self.node.parent + return node + + +class ExpressionBuilder(object): + def __init__(self, tokenizer): + self.operands = [] + self.operators = [None] + self.tokenizer = tokenizer + + def finish(self): + while self.operators[-1] is not None: + self.pop_operator() + rv = self.pop_operand() + assert self.is_empty() + return rv + + def left_paren(self): + self.operators.append(None) + + def right_paren(self): + while self.operators[-1] is not None: + self.pop_operator() + if not self.operators: + raise ParseError(self.tokenizer.filename, self.tokenizer.line, + "Unbalanced parens") + + assert self.operators.pop() is None + + def push_operator(self, operator): + assert operator is not None + while self.precedence(self.operators[-1]) > self.precedence(operator): + self.pop_operator() + + self.operators.append(operator) + + def pop_operator(self): + operator = self.operators.pop() + if isinstance(operator, BinaryOperatorNode): + operand_1 = self.operands.pop() + operand_0 = self.operands.pop() + self.operands.append(BinaryExpressionNode(operator, operand_0, operand_1)) + else: + operand_0 = self.operands.pop() + self.operands.append(UnaryExpressionNode(operator, operand_0)) + + def push_operand(self, node): + self.operands.append(node) + + def pop_operand(self): + return self.operands.pop() + + def is_empty(self): + return len(self.operands) == 0 and all(item is None for item in self.operators) + + def precedence(self, operator): + if operator is None: + return 0 + return precedence(operator) + + +def parse(stream): + p = Parser() + return p.parse(stream) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/serializer.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/serializer.py new file mode 100644 index 000000000000..52203ab240a9 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/serializer.py @@ -0,0 +1,136 @@ +from node import NodeVisitor, ValueNode, ListNode, BinaryExpressionNode +from parser import atoms, precedence + +atom_names = {v:"@%s" % k for (k,v) in atoms.iteritems()} + +named_escapes = set(["\a", "\b", "\f", "\n", "\r", "\t", "\v"]) + +def escape(string, extras=""): + rv = "" + for c in string: + if c in named_escapes: + rv += c.encode("unicode_escape") + elif c == "\\": + rv += "\\\\" + elif c < '\x20': + rv += "\\x%02x" % ord(c) + elif c in extras: + rv += "\\" + c + else: + rv += c + return rv.encode("utf8") + + +class ManifestSerializer(NodeVisitor): + def __init__(self, skip_empty_data=False): + self.skip_empty_data = skip_empty_data + + def serialize(self, root): + self.indent = 2 + rv = "\n".join(self.visit(root)) + if rv[-1] != "\n": + rv = rv + "\n" + return rv + + def visit_DataNode(self, node): + rv = [] + if not self.skip_empty_data or node.children: + if node.data: + rv.append("[%s]" % escape(node.data, extras="]")) + indent = self.indent * " " + else: + indent = "" + + for child in node.children: + rv.extend("%s%s" % (indent if item else "", item) for item in self.visit(child)) + + if node.parent: + rv.append("") + + return rv + + def visit_KeyValueNode(self, node): + rv = [escape(node.data, ":") + ":"] + indent = " " * self.indent + + if len(node.children) == 1 and isinstance(node.children[0], (ValueNode, ListNode)): + rv[0] += " %s" % self.visit(node.children[0])[0] + else: + for child in node.children: + rv.append(indent + self.visit(child)[0]) + + return rv + + def visit_ListNode(self, node): + rv = ["["] + rv.extend(", ".join(self.visit(child)[0] for child in node.children)) + rv.append("]") + return ["".join(rv)] + + def visit_ValueNode(self, node): + if "#" in node.data or (isinstance(node.parent, ListNode) and + ("," in node.data or "]" in node.data)): + if "\"" in node.data: + quote = "'" + else: + quote = "\"" + else: + quote = "" + return [quote + escape(node.data, extras=quote) + quote] + + def visit_AtomNode(self, node): + return [atom_names[node.data]] + + def visit_ConditionalNode(self, node): + return ["if %s: %s" % tuple(self.visit(item)[0] for item in node.children)] + + def visit_StringNode(self, node): + rv = ["\"%s\"" % escape(node.data, extras="\"")] + for child in node.children: + rv[0] += self.visit(child)[0] + return rv + + def visit_NumberNode(self, node): + return [str(node.data)] + + def visit_VariableNode(self, node): + rv = escape(node.data) + for child in node.children: + rv += self.visit(child) + return [rv] + + def visit_IndexNode(self, node): + assert len(node.children) == 1 + return ["[%s]" % self.visit(node.children[0])[0]] + + def visit_UnaryExpressionNode(self, node): + children = [] + for child in node.children: + child_str = self.visit(child)[0] + if isinstance(child, BinaryExpressionNode): + child_str = "(%s)" % child_str + children.append(child_str) + return [" ".join(children)] + + def visit_BinaryExpressionNode(self, node): + assert len(node.children) == 3 + children = [] + for child_index in [1, 0, 2]: + child = node.children[child_index] + child_str = self.visit(child)[0] + if (isinstance(child, BinaryExpressionNode) and + precedence(node.children[0]) < precedence(child.children[0])): + child_str = "(%s)" % child_str + children.append(child_str) + return [" ".join(children)] + + def visit_UnaryOperatorNode(self, node): + return [str(node.data)] + + def visit_BinaryOperatorNode(self, node): + return [str(node.data)] + + +def serialize(tree, *args, **kwargs): + s = ManifestSerializer(*args, **kwargs) + return s.serialize(tree) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/__init__.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_conditional.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_conditional.py new file mode 100644 index 000000000000..d9ffdf255072 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_conditional.py @@ -0,0 +1,143 @@ +import unittest + +from cStringIO import StringIO + +from ..backends import conditional +from ..node import BinaryExpressionNode, BinaryOperatorNode, VariableNode, NumberNode + + +class TestConditional(unittest.TestCase): + def compile(self, input_text): + return conditional.compile(input_text) + + def test_get_0(self): + data = """ +key: value + +[Heading 1] + other_key: + if a == 1: value_1 + if a == 2: value_2 + value_3 +""" + + manifest = self.compile(data) + + self.assertEquals(manifest.get("key"), "value") + children = list(item for item in manifest.iterchildren()) + self.assertEquals(len(children), 1) + section = children[0] + self.assertEquals(section.name, "Heading 1") + + self.assertEquals(section.get("other_key", {"a": 1}), "value_1") + self.assertEquals(section.get("other_key", {"a": 2}), "value_2") + self.assertEquals(section.get("other_key", {"a": 7}), "value_3") + self.assertEquals(section.get("key"), "value") + + def test_get_1(self): + data = """ +key: value + +[Heading 1] + other_key: + if a == "1": value_1 + if a == 2: value_2 + value_3 +""" + + manifest = self.compile(data) + + children = list(item for item in manifest.iterchildren()) + section = children[0] + + self.assertEquals(section.get("other_key", {"a": "1"}), "value_1") + self.assertEquals(section.get("other_key", {"a": 1}), "value_3") + + def test_get_2(self): + data = """ +key: + if a[1] == "b": value_1 + if a[1] == 2: value_2 + value_3 +""" + + manifest = self.compile(data) + + self.assertEquals(manifest.get("key", {"a": "ab"}), "value_1") + self.assertEquals(manifest.get("key", {"a": [1, 2]}), "value_2") + + def test_get_3(self): + data = """ +key: + if a[1] == "ab"[1]: value_1 + if a[1] == 2: value_2 + value_3 +""" + + manifest = self.compile(data) + + self.assertEquals(manifest.get("key", {"a": "ab"}), "value_1") + self.assertEquals(manifest.get("key", {"a": [1, 2]}), "value_2") + + def test_set_0(self): + data = """ +key: + if a == "a": value_1 + if a == "b": value_2 + value_3 +""" + manifest = self.compile(data) + + manifest.set("new_key", "value_new") + + self.assertEquals(manifest.get("new_key"), "value_new") + + def test_set_1(self): + data = """ +key: + if a == "a": value_1 + if a == "b": value_2 + value_3 +""" + + manifest = self.compile(data) + + manifest.set("key", "value_new") + + self.assertEquals(manifest.get("key"), "value_new") + self.assertEquals(manifest.get("key", {"a": "a"}), "value_1") + + def test_set_2(self): + data = """ +key: + if a == "a": value_1 + if a == "b": value_2 + value_3 +""" + + manifest = self.compile(data) + + expr = BinaryExpressionNode(BinaryOperatorNode("=="), + VariableNode("a"), + NumberNode("1")) + + manifest.set("key", "value_new", expr) + + self.assertEquals(manifest.get("key", {"a": 1}), "value_new") + self.assertEquals(manifest.get("key", {"a": "a"}), "value_1") + + def test_api_0(self): + data = """ +key: + if a == 1.5: value_1 + value_2 +key_1: other_value +""" + manifest = self.compile(data) + + self.assertFalse(manifest.is_empty) + self.assertEquals(manifest.root, manifest) + self.assertTrue(manifest.has_key("key_1")) + self.assertFalse(manifest.has_key("key_2")) + + self.assertEquals(set(manifest.iterkeys()), set(["key", "key_1"])) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_parser.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_parser.py new file mode 100644 index 000000000000..765c984f42f5 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_parser.py @@ -0,0 +1,75 @@ +import unittest + +from cStringIO import StringIO + +from .. import parser + +# There aren't many tests here because it turns out to be way more convenient to +# use test_serializer for the majority of cases + + +class TestExpression(unittest.TestCase): + def setUp(self): + self.parser = parser.Parser() + + def parse(self, input_str): + return self.parser.parse(StringIO(input_str)) + + def compare(self, input_text, expected): + actual = self.parse(input_text) + self.match(expected, actual) + + def match(self, expected_node, actual_node): + self.assertEquals(expected_node[0], actual_node.__class__.__name__) + self.assertEquals(expected_node[1], actual_node.data) + self.assertEquals(len(expected_node[2]), len(actual_node.children)) + for expected_child, actual_child in zip(expected_node[2], actual_node.children): + self.match(expected_child, actual_child) + + def test_expr_0(self): + self.compare( + """ +key: + if x == 1 : value""", + ["DataNode", None, + [["KeyValueNode", "key", + [["ConditionalNode", None, + [["BinaryExpressionNode", None, + [["BinaryOperatorNode", "==", []], + ["VariableNode", "x", []], + ["NumberNode", "1", []] + ]], + ["ValueNode", "value", []], + ]]]]]] + ) + + def test_expr_1(self): + self.compare( + """ +key: + if not x and y : value""", + ["DataNode", None, + [["KeyValueNode", "key", + [["ConditionalNode", None, + [["BinaryExpressionNode", None, + [["BinaryOperatorNode", "and", []], + ["UnaryExpressionNode", None, + [["UnaryOperatorNode", "not", []], + ["VariableNode", "x", []] + ]], + ["VariableNode", "y", []] + ]], + ["ValueNode", "value", []], + ]]]]]] + ) + + def test_atom_0(self): + with self.assertRaises(parser.ParseError): + self.parse("key: @Unknown") + + def test_atom_1(self): + with self.assertRaises(parser.ParseError): + self.parse("key: @true") + +if __name__ == "__main__": + unittest.main() diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_serializer.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_serializer.py new file mode 100644 index 000000000000..6db2cbbbb477 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_serializer.py @@ -0,0 +1,227 @@ +import sys +import unittest + +from cStringIO import StringIO + +import pytest + +from .. import parser, serializer + + +class TokenizerTest(unittest.TestCase): + def setUp(self): + self.serializer = serializer.ManifestSerializer() + self.parser = parser.Parser() + + def serialize(self, input_str): + return self.serializer.serialize(self.parser.parse(input_str)) + + def compare(self, input_str, expected=None): + if expected is None: + expected = input_str + expected = expected.encode("utf8") + actual = self.serialize(input_str) + self.assertEquals(actual, expected) + + def test_0(self): + self.compare("""key: value +[Heading 1] + other_key: other_value +""") + + def test_1(self): + self.compare("""key: value +[Heading 1] + other_key: + if a or b: other_value +""") + + def test_2(self): + self.compare("""key: value +[Heading 1] + other_key: + if a or b: other_value + fallback_value +""") + + def test_3(self): + self.compare("""key: value +[Heading 1] + other_key: + if a == 1: other_value + fallback_value +""") + + def test_4(self): + self.compare("""key: value +[Heading 1] + other_key: + if a == "1": other_value + fallback_value +""") + + def test_5(self): + self.compare("""key: value +[Heading 1] + other_key: + if a == "abc"[1]: other_value + fallback_value +""") + + def test_6(self): + self.compare("""key: value +[Heading 1] + other_key: + if a == "abc"[c]: other_value + fallback_value +""") + + def test_7(self): + self.compare("""key: value +[Heading 1] + other_key: + if (a or b) and c: other_value + fallback_value +""", +"""key: value +[Heading 1] + other_key: + if a or b and c: other_value + fallback_value +""") + + def test_8(self): + self.compare("""key: value +[Heading 1] + other_key: + if a or (b and c): other_value + fallback_value +""") + + def test_9(self): + self.compare("""key: value +[Heading 1] + other_key: + if not (a and b): other_value + fallback_value +""") + + def test_10(self): + self.compare("""key: value +[Heading 1] + some_key: some_value + +[Heading 2] + other_key: other_value +""") + + def test_11(self): + self.compare("""key: + if not a and b and c and d: true +""") + + def test_12(self): + self.compare("""[Heading 1] + key: [a:1, b:2] +""") + + def test_13(self): + self.compare("""key: [a:1, "b:#"] +""") + + def test_14(self): + self.compare("""key: [","] +""") + + def test_15(self): + self.compare("""key: , +""") + + def test_16(self): + self.compare("""key: ["]", b] +""") + + def test_17(self): + self.compare("""key: ] +""") + + def test_18(self): + self.compare("""key: \] + """, """key: ] +""") + + def test_escape_0(self): + self.compare(r"""k\t\:y: \a\b\f\n\r\t\v""", + r"""k\t\:y: \x07\x08\x0c\n\r\t\x0b +""") + + def test_escape_1(self): + self.compare(r"""k\x00: \x12A\x45""", + r"""k\x00: \x12AE +""") + + def test_escape_2(self): + self.compare(r"""k\u0045y: \u1234A\uABc6""", + u"""kEy: \u1234A\uabc6 +""") + + def test_escape_3(self): + self.compare(r"""k\u0045y: \u1234A\uABc6""", + u"""kEy: \u1234A\uabc6 +""") + + def test_escape_4(self): + self.compare(r"""key: '\u1234A\uABc6'""", + u"""key: \u1234A\uabc6 +""") + + def test_escape_5(self): + self.compare(r"""key: [\u1234A\uABc6]""", + u"""key: [\u1234A\uabc6] +""") + + def test_escape_6(self): + self.compare(r"""key: [\u1234A\uABc6\,]""", + u"""key: ["\u1234A\uabc6,"] +""") + + def test_escape_7(self): + self.compare(r"""key: [\,\]\#]""", + r"""key: [",]#"] +""") + + def test_escape_8(self): + self.compare(r"""key: \#""", + r"""key: "#" +""") + + @pytest.mark.xfail(sys.maxunicode == 0xFFFF, reason="narrow unicode") + def test_escape_9(self): + self.compare(r"""key: \U10FFFFabc""", + u"""key: \U0010FFFFabc +""") + + def test_escape_10(self): + self.compare(r"""key: \u10FFab""", + u"""key: \u10FFab +""") + + def test_escape_11(self): + self.compare(r"""key: \\ab +""") + + def test_atom_1(self): + self.compare(r"""key: @True +""") + + def test_atom_2(self): + self.compare(r"""key: @False +""") + + def test_atom_3(self): + self.compare(r"""key: @Reset +""") + + def test_atom_4(self): + self.compare(r"""key: [a, @Reset, b] +""") diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_static.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_static.py new file mode 100644 index 000000000000..ed28578d3bfc --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_static.py @@ -0,0 +1,98 @@ +import unittest + +from cStringIO import StringIO + +from ..backends import static + +# There aren't many tests here because it turns out to be way more convenient to +# use test_serializer for the majority of cases + + +class TestStatic(unittest.TestCase): + def compile(self, input_text, input_data): + return static.compile(input_text, input_data) + + def test_get_0(self): + data = """ +key: value + +[Heading 1] + other_key: + if a == 1: value_1 + if a == 2: value_2 + value_3 +""" + + manifest = self.compile(data, {"a": 2}) + + self.assertEquals(manifest.get("key"), "value") + children = list(item for item in manifest.iterchildren()) + self.assertEquals(len(children), 1) + section = children[0] + self.assertEquals(section.name, "Heading 1") + + self.assertEquals(section.get("other_key"), "value_2") + self.assertEquals(section.get("key"), "value") + + def test_get_1(self): + data = """ +key: value + +[Heading 1] + other_key: + if a == 1: value_1 + if a == 2: value_2 + value_3 +""" + manifest = self.compile(data, {"a": 3}) + + children = list(item for item in manifest.iterchildren()) + section = children[0] + self.assertEquals(section.get("other_key"), "value_3") + + def test_get_3(self): + data = """key: + if a == "1": value_1 + if a[0] == "ab"[0]: value_2 +""" + manifest = self.compile(data, {"a": "1"}) + self.assertEquals(manifest.get("key"), "value_1") + + manifest = self.compile(data, {"a": "ac"}) + self.assertEquals(manifest.get("key"), "value_2") + + def test_get_4(self): + data = """key: + if not a: value_1 + value_2 +""" + manifest = self.compile(data, {"a": True}) + self.assertEquals(manifest.get("key"), "value_2") + + manifest = self.compile(data, {"a": False}) + self.assertEquals(manifest.get("key"), "value_1") + + def test_api(self): + data = """key: + if a == 1.5: value_1 + value_2 +key_1: other_value +""" + manifest = self.compile(data, {"a": 1.5}) + + self.assertFalse(manifest.is_empty) + self.assertEquals(manifest.root, manifest) + self.assertTrue(manifest.has_key("key_1")) + self.assertFalse(manifest.has_key("key_2")) + + self.assertEquals(set(manifest.iterkeys()), set(["key", "key_1"])) + self.assertEquals(set(manifest.itervalues()), set(["value_1", "other_value"])) + + def test_is_empty_1(self): + data = """ +[Section] + [Subsection] +""" + manifest = self.compile(data, {}) + + self.assertTrue(manifest.is_empty) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_tokenizer.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_tokenizer.py new file mode 100644 index 000000000000..88176c5a1690 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_tokenizer.py @@ -0,0 +1,357 @@ +import sys +import os +import unittest + +sys.path.insert(0, os.path.abspath("..")) +from cStringIO import StringIO + +from .. import parser +from ..parser import token_types + + +class TokenizerTest(unittest.TestCase): + def setUp(self): + self.tokenizer = parser.Tokenizer() + + def tokenize(self, input_str): + rv = [] + for item in self.tokenizer.tokenize(StringIO(input_str)): + rv.append(item) + if item[0] == token_types.eof: + break + return rv + + def compare(self, input_text, expected): + expected = expected + [(token_types.eof, None)] + actual = self.tokenize(input_text) + self.assertEquals(actual, expected) + + def test_heading_0(self): + self.compare("""[Heading text]""", + [(token_types.paren, "["), + (token_types.string, "Heading text"), + (token_types.paren, "]")]) + + def test_heading_1(self): + self.compare("""[Heading [text\]]""", + [(token_types.paren, "["), + (token_types.string, "Heading [text]"), + (token_types.paren, "]")]) + + def test_heading_2(self): + self.compare("""[Heading #text]""", + [(token_types.paren, "["), + (token_types.string, "Heading #text"), + (token_types.paren, "]")]) + + def test_heading_3(self): + self.compare("""[Heading [\]text]""", + [(token_types.paren, "["), + (token_types.string, "Heading []text"), + (token_types.paren, "]")]) + + def test_heading_4(self): + with self.assertRaises(parser.ParseError): + self.tokenize("[Heading") + + def test_heading_5(self): + self.compare("""[Heading [\]text] #comment""", + [(token_types.paren, "["), + (token_types.string, "Heading []text"), + (token_types.paren, "]")]) + + def test_heading_6(self): + self.compare(r"""[Heading \ttext]""", + [(token_types.paren, "["), + (token_types.string, "Heading \ttext"), + (token_types.paren, "]")]) + + def test_key_0(self): + self.compare("""key:value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_key_1(self): + self.compare("""key : value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_key_2(self): + self.compare("""key : val ue""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "val ue")]) + + def test_key_3(self): + self.compare("""key: value#comment""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_key_4(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""ke y: value""") + + def test_key_5(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key""") + + def test_key_6(self): + self.compare("""key: "value\"""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_key_7(self): + self.compare("""key: 'value'""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_key_8(self): + self.compare("""key: "#value\"""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "#value")]) + + def test_key_9(self): + self.compare("""key: '#value\'""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "#value")]) + + def test_key_10(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: "value""") + + def test_key_11(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: 'value""") + + def test_key_12(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: 'value""") + + def test_key_13(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: 'value' abc""") + + def test_key_14(self): + self.compare(r"""key: \\nb""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, r"\nb")]) + + def test_list_0(self): + self.compare( +""" +key: []""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.list_start, "["), + (token_types.list_end, "]")]) + + def test_list_1(self): + self.compare( +""" +key: [a, "b"]""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.list_start, "["), + (token_types.string, "a"), + (token_types.string, "b"), + (token_types.list_end, "]")]) + + def test_list_2(self): + self.compare( +""" +key: [a, + b]""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.list_start, "["), + (token_types.string, "a"), + (token_types.string, "b"), + (token_types.list_end, "]")]) + + def test_list_3(self): + self.compare( +""" +key: [a, #b] + c]""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.list_start, "["), + (token_types.string, "a"), + (token_types.string, "c"), + (token_types.list_end, "]")]) + + def test_list_4(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: [a #b] + c]""") + + def test_list_5(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: [a \\ + c]""") + + def test_list_6(self): + self.compare( +"""key: [a , b]""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.list_start, "["), + (token_types.string, "a"), + (token_types.string, "b"), + (token_types.list_end, "]")]) + + def test_expr_0(self): + self.compare( +""" +key: + if cond == 1: value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.number, "1"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_1(self): + self.compare( +""" +key: + if cond == 1: value1 + value2""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.number, "1"), + (token_types.separator, ":"), + (token_types.string, "value1"), + (token_types.string, "value2")]) + + def test_expr_2(self): + self.compare( +""" +key: + if cond=="1": value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.string, "1"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_3(self): + self.compare( +""" +key: + if cond==1.1: value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.number, "1.1"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_4(self): + self.compare( + """ +key: + if cond==1.1 and cond2 == "a": value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.number, "1.1"), + (token_types.ident, "and"), + (token_types.ident, "cond2"), + (token_types.ident, "=="), + (token_types.string, "a"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_5(self): + self.compare( +""" +key: + if (cond==1.1 ): value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.paren, "("), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.number, "1.1"), + (token_types.paren, ")"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_6(self): + self.compare( +""" +key: + if "\\ttest": value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.string, "\ttest"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_7(self): + with self.assertRaises(parser.ParseError): + self.tokenize( +""" +key: + if 1A: value""") + + def test_expr_8(self): + with self.assertRaises(parser.ParseError): + self.tokenize( +""" +key: + if 1a: value""") + + def test_expr_9(self): + with self.assertRaises(parser.ParseError): + self.tokenize( +""" +key: + if 1.1.1: value""") + + def test_expr_10(self): + self.compare( +""" +key: + if 1.: value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.number, "1."), + (token_types.separator, ":"), + (token_types.string, "value")]) + +if __name__ == "__main__": + unittest.main() diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptrunner.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptrunner.py new file mode 100644 index 000000000000..5c184554f0d9 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptrunner.py @@ -0,0 +1,257 @@ +from __future__ import unicode_literals + +import json +import os +import sys + +import environment as env +import products +import testloader +import wptcommandline +import wptlogging +import wpttest +from testrunner import ManagerGroup +from browsers.base import NullBrowser + +here = os.path.split(__file__)[0] + +logger = None + +"""Runner for web-platform-tests + +The runner has several design goals: + +* Tests should run with no modification from upstream. + +* Tests should be regarded as "untrusted" so that errors, timeouts and even + crashes in the tests can be handled without failing the entire test run. + +* For performance tests can be run in multiple browsers in parallel. + +The upstream repository has the facility for creating a test manifest in JSON +format. This manifest is used directly to determine which tests exist. Local +metadata files are used to store the expected test results. +""" + +def setup_logging(*args, **kwargs): + global logger + logger = wptlogging.setup(*args, **kwargs) + +def get_loader(test_paths, product, ssl_env, debug=None, run_info_extras=None, **kwargs): + if run_info_extras is None: + run_info_extras = {} + + run_info = wpttest.get_run_info(kwargs["run_info"], product, debug=debug, + extras=run_info_extras) + + test_manifests = testloader.ManifestLoader(test_paths, force_manifest_update=kwargs["manifest_update"]).load() + + manifest_filters = [] + meta_filters = [] + + if kwargs["include"] or kwargs["exclude"] or kwargs["include_manifest"]: + manifest_filters.append(testloader.TestFilter(include=kwargs["include"], + exclude=kwargs["exclude"], + manifest_path=kwargs["include_manifest"], + test_manifests=test_manifests)) + if kwargs["tags"]: + meta_filters.append(testloader.TagFilter(tags=kwargs["tags"])) + + test_loader = testloader.TestLoader(test_manifests, + kwargs["test_types"], + run_info, + manifest_filters=manifest_filters, + meta_filters=meta_filters, + chunk_type=kwargs["chunk_type"], + total_chunks=kwargs["total_chunks"], + chunk_number=kwargs["this_chunk"], + include_https=ssl_env.ssl_enabled) + return run_info, test_loader + +def list_test_groups(test_paths, product, **kwargs): + env.do_delayed_imports(logger, test_paths) + + ssl_env = env.ssl_env(logger, **kwargs) + + run_info, test_loader = get_loader(test_paths, product, ssl_env, + **kwargs) + + for item in sorted(test_loader.groups(kwargs["test_types"])): + print item + + +def list_disabled(test_paths, product, **kwargs): + env.do_delayed_imports(logger, test_paths) + + rv = [] + + ssl_env = env.ssl_env(logger, **kwargs) + + run_info, test_loader = get_loader(test_paths, product, ssl_env, + **kwargs) + + for test_type, tests in test_loader.disabled_tests.iteritems(): + for test in tests: + rv.append({"test": test.id, "reason": test.disabled()}) + print json.dumps(rv, indent=2) + + +def get_pause_after_test(test_loader, **kwargs): + total_tests = sum(len(item) for item in test_loader.tests.itervalues()) + if kwargs["pause_after_test"] is None: + if kwargs["repeat_until_unexpected"]: + return False + if kwargs["repeat"] == 1 and total_tests == 1: + return True + return False + return kwargs["pause_after_test"] + + +def run_tests(config, test_paths, product, **kwargs): + with wptlogging.CaptureIO(logger, not kwargs["no_capture_stdio"]): + env.do_delayed_imports(logger, test_paths) + + (check_args, + target_browser_cls, get_browser_kwargs, + executor_classes, get_executor_kwargs, + env_options, get_env_extras, run_info_extras) = products.load_product(config, product) + + ssl_env = env.ssl_env(logger, **kwargs) + env_extras = get_env_extras(**kwargs) + + check_args(**kwargs) + + if "test_loader" in kwargs: + run_info = wpttest.get_run_info(kwargs["run_info"], product, debug=None, + extras=run_info_extras(**kwargs)) + test_loader = kwargs["test_loader"] + else: + run_info, test_loader = get_loader(test_paths, + product, + ssl_env, + run_info_extras=run_info_extras(**kwargs), + **kwargs) + + if kwargs["run_by_dir"] is False: + test_source_cls = testloader.SingleTestSource + test_source_kwargs = {} + else: + # A value of None indicates infinite depth + test_source_cls = testloader.PathGroupedSource + test_source_kwargs = {"depth": kwargs["run_by_dir"]} + + logger.info("Using %i client processes" % kwargs["processes"]) + + unexpected_total = 0 + + kwargs["pause_after_test"] = get_pause_after_test(test_loader, **kwargs) + + with env.TestEnvironment(test_paths, + ssl_env, + kwargs["pause_after_test"], + kwargs["debug_info"], + env_options, + env_extras) as test_environment: + try: + test_environment.ensure_started() + except env.TestEnvironmentError as e: + logger.critical("Error starting test environment: %s" % e.message) + raise + + browser_kwargs = get_browser_kwargs(ssl_env=ssl_env, **kwargs) + + repeat = kwargs["repeat"] + repeat_count = 0 + repeat_until_unexpected = kwargs["repeat_until_unexpected"] + + while repeat_count < repeat or repeat_until_unexpected: + repeat_count += 1 + if repeat_until_unexpected: + logger.info("Repetition %i" % (repeat_count)) + elif repeat > 1: + logger.info("Repetition %i / %i" % (repeat_count, repeat)) + + unexpected_count = 0 + logger.suite_start(test_loader.test_ids, run_info) + for test_type in kwargs["test_types"]: + logger.info("Running %s tests" % test_type) + + # WebDriver tests may create and destroy multiple browser + # processes as part of their expected behavior. These + # processes are managed by a WebDriver server binary. This + # obviates the need for wptrunner to provide a browser, so + # the NullBrowser is used in place of the "target" browser + if test_type == "wdspec": + browser_cls = NullBrowser + else: + browser_cls = target_browser_cls + + for test in test_loader.disabled_tests[test_type]: + logger.test_start(test.id) + logger.test_end(test.id, status="SKIP") + + executor_cls = executor_classes.get(test_type) + executor_kwargs = get_executor_kwargs(test_type, + test_environment.external_config, + test_environment.cache_manager, + run_info, + **kwargs) + + if executor_cls is None: + logger.error("Unsupported test type %s for product %s" % + (test_type, product)) + continue + + + with ManagerGroup("web-platform-tests", + kwargs["processes"], + test_source_cls, + test_source_kwargs, + browser_cls, + browser_kwargs, + executor_cls, + executor_kwargs, + kwargs["pause_after_test"], + kwargs["pause_on_unexpected"], + kwargs["restart_on_unexpected"], + kwargs["debug_info"]) as manager_group: + try: + manager_group.run(test_type, test_loader.tests) + except KeyboardInterrupt: + logger.critical("Main thread got signal") + manager_group.stop() + raise + unexpected_count += manager_group.unexpected_count() + + unexpected_total += unexpected_count + logger.info("Got %i unexpected results" % unexpected_count) + if repeat_until_unexpected and unexpected_total > 0: + break + logger.suite_end() + + return unexpected_total == 0 + + +def main(): + """Main entry point when calling from the command line""" + kwargs = wptcommandline.parse_args() + + try: + if kwargs["prefs_root"] is None: + kwargs["prefs_root"] = os.path.abspath(os.path.join(here, "prefs")) + + setup_logging(kwargs, {"raw": sys.stdout}) + + if kwargs["list_test_groups"]: + list_test_groups(**kwargs) + elif kwargs["list_disabled"]: + list_disabled(**kwargs) + else: + return not run_tests(**kwargs) + except Exception: + if kwargs["pdb"]: + import pdb, traceback + print traceback.format_exc() + pdb.post_mortem() + else: + raise diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wpttest.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wpttest.py new file mode 100644 index 000000000000..d144cd66ea78 --- /dev/null +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wpttest.py @@ -0,0 +1,338 @@ +DEFAULT_TIMEOUT = 10 # seconds +LONG_TIMEOUT = 60 # seconds + +import os + +import mozinfo + +from wptmanifest.parser import atoms + +atom_reset = atoms["Reset"] +enabled_tests = set(["testharness", "reftest", "wdspec"]) + + +class Result(object): + def __init__(self, status, message, expected=None, extra=None): + if status not in self.statuses: + raise ValueError("Unrecognised status %s" % status) + self.status = status + self.message = message + self.expected = expected + self.extra = extra + + def __repr__(self): + return "<%s.%s %s>" % (self.__module__, self.__class__.__name__, self.status) + + +class SubtestResult(object): + def __init__(self, name, status, message, stack=None, expected=None): + self.name = name + if status not in self.statuses: + raise ValueError("Unrecognised status %s" % status) + self.status = status + self.message = message + self.stack = stack + self.expected = expected + + def __repr__(self): + return "<%s.%s %s %s>" % (self.__module__, self.__class__.__name__, self.name, self.status) + + +class TestharnessResult(Result): + default_expected = "OK" + statuses = set(["OK", "ERROR", "TIMEOUT", "EXTERNAL-TIMEOUT", "CRASH"]) + + +class TestharnessSubtestResult(SubtestResult): + default_expected = "PASS" + statuses = set(["PASS", "FAIL", "TIMEOUT", "NOTRUN"]) + + +class ReftestResult(Result): + default_expected = "PASS" + statuses = set(["PASS", "FAIL", "ERROR", "TIMEOUT", "EXTERNAL-TIMEOUT", "CRASH"]) + + +class WdspecResult(Result): + default_expected = "OK" + statuses = set(["OK", "ERROR", "TIMEOUT", "EXTERNAL-TIMEOUT", "CRASH"]) + + +class WdspecSubtestResult(SubtestResult): + default_expected = "PASS" + statuses = set(["PASS", "FAIL", "ERROR"]) + + +def get_run_info(metadata_root, product, **kwargs): + return RunInfo(metadata_root, product, **kwargs) + + +class RunInfo(dict): + def __init__(self, metadata_root, product, debug, extras=None): + self._update_mozinfo(metadata_root) + self.update(mozinfo.info) + self["product"] = product + if debug is not None: + self["debug"] = debug + elif "debug" not in self: + # Default to release + self["debug"] = False + if extras is not None: + self.update(extras) + + def _update_mozinfo(self, metadata_root): + """Add extra build information from a mozinfo.json file in a parent + directory""" + path = metadata_root + dirs = set() + while path != os.path.expanduser('~'): + if path in dirs: + break + dirs.add(str(path)) + path = os.path.split(path)[0] + + mozinfo.find_and_update_from_json(*dirs) + + +class Test(object): + result_cls = None + subtest_result_cls = None + test_type = None + + def __init__(self, tests_root, url, inherit_metadata, test_metadata, + timeout=DEFAULT_TIMEOUT, path=None, protocol="http"): + self.tests_root = tests_root + self.url = url + self._inherit_metadata = inherit_metadata + self._test_metadata = test_metadata + self.timeout = timeout + self.path = path + self.environment = {"protocol": protocol, "prefs": self.prefs} + + def __eq__(self, other): + return self.id == other.id + + @classmethod + def from_manifest(cls, manifest_item, inherit_metadata, test_metadata): + timeout = LONG_TIMEOUT if manifest_item.timeout == "long" else DEFAULT_TIMEOUT + protocol = "https" if hasattr(manifest_item, "https") and manifest_item.https else "http" + return cls(manifest_item.source_file.tests_root, + manifest_item.url, + inherit_metadata, + test_metadata, + timeout=timeout, + path=manifest_item.source_file.path, + protocol=protocol) + + @property + def id(self): + return self.url + + @property + def keys(self): + return tuple() + + @property + def abs_path(self): + return os.path.join(self.tests_root, self.path) + + def _get_metadata(self, subtest=None): + if self._test_metadata is not None and subtest is not None: + return self._test_metadata.get_subtest(subtest) + else: + return self._test_metadata + + def itermeta(self, subtest=None): + for metadata in self._inherit_metadata: + yield metadata + + if self._test_metadata is not None: + yield self._get_metadata() + if subtest is not None: + subtest_meta = self._get_metadata(subtest) + if subtest_meta is not None: + yield subtest_meta + + def disabled(self, subtest=None): + for meta in self.itermeta(subtest): + disabled = meta.disabled + if disabled is not None: + return disabled + return None + + @property + def restart_after(self): + for meta in self.itermeta(None): + restart_after = meta.restart_after + if restart_after is not None: + return True + return False + + @property + def tags(self): + tags = set() + for meta in self.itermeta(): + meta_tags = meta.tags + if atom_reset in meta_tags: + tags = meta_tags.copy() + tags.remove(atom_reset) + else: + tags |= meta_tags + + tags.add("dir:%s" % self.id.lstrip("/").split("/")[0]) + + return tags + + @property + def prefs(self): + prefs = {} + for meta in self.itermeta(): + meta_prefs = meta.prefs + if atom_reset in prefs: + prefs = meta_prefs.copy() + del prefs[atom_reset] + else: + prefs.update(meta_prefs) + return prefs + + def expected(self, subtest=None): + if subtest is None: + default = self.result_cls.default_expected + else: + default = self.subtest_result_cls.default_expected + + metadata = self._get_metadata(subtest) + if metadata is None: + return default + + try: + return metadata.get("expected") + except KeyError: + return default + + def __repr__(self): + return "<%s.%s %s>" % (self.__module__, self.__class__.__name__, self.id) + + +class TestharnessTest(Test): + result_cls = TestharnessResult + subtest_result_cls = TestharnessSubtestResult + test_type = "testharness" + + @property + def id(self): + return self.url + + +class ManualTest(Test): + test_type = "manual" + + @property + def id(self): + return self.url + + +class ReftestTest(Test): + result_cls = ReftestResult + test_type = "reftest" + + def __init__(self, tests_root, url, inherit_metadata, test_metadata, references, + timeout=DEFAULT_TIMEOUT, path=None, viewport_size=None, + dpi=None, protocol="http"): + Test.__init__(self, tests_root, url, inherit_metadata, test_metadata, timeout, + path, protocol) + + for _, ref_type in references: + if ref_type not in ("==", "!="): + raise ValueError + + self.references = references + self.viewport_size = viewport_size + self.dpi = dpi + + @classmethod + def from_manifest(cls, + manifest_test, + inherit_metadata, + test_metadata, + nodes=None, + references_seen=None): + + timeout = LONG_TIMEOUT if manifest_test.timeout == "long" else DEFAULT_TIMEOUT + + if nodes is None: + nodes = {} + if references_seen is None: + references_seen = set() + + url = manifest_test.url + + node = cls(manifest_test.source_file.tests_root, + manifest_test.url, + inherit_metadata, + test_metadata, + [], + timeout=timeout, + path=manifest_test.path, + viewport_size=manifest_test.viewport_size, + dpi=manifest_test.dpi, + protocol="https" if hasattr(manifest_test, "https") and manifest_test.https else "http") + + nodes[url] = node + + for ref_url, ref_type in manifest_test.references: + comparison_key = (ref_type,) + tuple(sorted([url, ref_url])) + if ref_url in nodes: + manifest_node = ref_url + if comparison_key in references_seen: + # We have reached a cycle so stop here + # Note that just seeing a node for the second time is not + # enough to detect a cycle because + # A != B != C != A must include C != A + # but A == B == A should not include the redundant B == A. + continue + + references_seen.add(comparison_key) + + manifest_node = manifest_test.manifest.get_reference(ref_url) + if manifest_node: + reference = ReftestTest.from_manifest(manifest_node, + [], + None, + nodes, + references_seen) + else: + reference = ReftestTest(manifest_test.source_file.tests_root, + ref_url, + [], + None, + []) + + node.references.append((reference, ref_type)) + + return node + + @property + def id(self): + return self.url + + @property + def keys(self): + return ("reftype", "refurl") + + +class WdspecTest(Test): + result_cls = WdspecResult + subtest_result_cls = WdspecSubtestResult + test_type = "wdspec" + + +manifest_test_cls = {"reftest": ReftestTest, + "testharness": TestharnessTest, + "manual": ManualTest, + "wdspec": WdspecTest} + + +def from_manifest(manifest_test, inherit_metadata, test_metadata): + test_cls = manifest_test_cls[manifest_test.item_type] + return test_cls.from_manifest(manifest_test, inherit_metadata, test_metadata) diff --git a/testing/web-platform/tests/tools/wptserve/tests/functional/base.py b/testing/web-platform/tests/tools/wptserve/tests/functional/base.py index 62d5e3253e6b..9b0cb50179fe 100644 --- a/testing/web-platform/tests/tools/wptserve/tests/functional/base.py +++ b/testing/web-platform/tests/tools/wptserve/tests/functional/base.py @@ -3,13 +3,14 @@ from __future__ import print_function import base64 import logging import os +import pytest import unittest from six.moves.urllib.parse import urlencode, urlunsplit from six.moves.urllib.request import Request as BaseRequest from six.moves.urllib.request import urlopen -import wptserve +wptserve = pytest.importorskip("wptserve") logging.basicConfig() @@ -18,6 +19,7 @@ wptserve.logger.set_logger(logging.getLogger()) here = os.path.split(__file__)[0] doc_root = os.path.join(here, "docroot") + class Request(BaseRequest): def __init__(self, *args, **kwargs): BaseRequest.__init__(self, *args, **kwargs) @@ -33,6 +35,7 @@ class Request(BaseRequest): self.add_header("Content-Length", str(len(data))) BaseRequest.add_data(self, data) + class TestUsingServer(unittest.TestCase): def setUp(self): self.server = wptserve.server.WebTestHttpd(host="localhost", diff --git a/testing/web-platform/tests/tools/wptserve/tests/functional/test_cookies.py b/testing/web-platform/tests/tools/wptserve/tests/functional/test_cookies.py index d1080b4bf15c..2e2d0d6771ba 100644 --- a/testing/web-platform/tests/tools/wptserve/tests/functional/test_cookies.py +++ b/testing/web-platform/tests/tools/wptserve/tests/functional/test_cookies.py @@ -1,8 +1,11 @@ import unittest -import wptserve +import pytest + +wptserve = pytest.importorskip("wptserve") from .base import TestUsingServer + class TestResponseSetCookie(TestUsingServer): def test_name_value(self): @wptserve.handlers.handler diff --git a/testing/web-platform/tests/tools/wptserve/tests/functional/test_handlers.py b/testing/web-platform/tests/tools/wptserve/tests/functional/test_handlers.py index f99597a43f0a..67119d2cfbd6 100644 --- a/testing/web-platform/tests/tools/wptserve/tests/functional/test_handlers.py +++ b/testing/web-platform/tests/tools/wptserve/tests/functional/test_handlers.py @@ -1,14 +1,15 @@ import json import os -import pytest import unittest import uuid +import pytest from six.moves.urllib.error import HTTPError -import wptserve +wptserve = pytest.importorskip("wptserve") from .base import TestUsingServer, doc_root + class TestFileHandler(TestUsingServer): def test_GET(self): resp = self.request("/document.txt") diff --git a/testing/web-platform/tests/tools/wptserve/tests/functional/test_pipes.py b/testing/web-platform/tests/tools/wptserve/tests/functional/test_pipes.py index af5068108c81..95da70faea9f 100644 --- a/testing/web-platform/tests/tools/wptserve/tests/functional/test_pipes.py +++ b/testing/web-platform/tests/tools/wptserve/tests/functional/test_pipes.py @@ -2,8 +2,11 @@ import os import unittest import time +import pytest + from .base import TestUsingServer, doc_root + class TestStatus(TestUsingServer): def test_status(self): resp = self.request("/document.txt", query="pipe=status(202)") diff --git a/testing/web-platform/tests/tools/wptserve/tests/functional/test_request.py b/testing/web-platform/tests/tools/wptserve/tests/functional/test_request.py index 40dfe7703d14..d0d8213cfdd0 100644 --- a/testing/web-platform/tests/tools/wptserve/tests/functional/test_request.py +++ b/testing/web-platform/tests/tools/wptserve/tests/functional/test_request.py @@ -1,8 +1,11 @@ import unittest -import wptserve +import pytest + +wptserve = pytest.importorskip("wptserve") from .base import TestUsingServer + class TestInputFile(TestUsingServer): def test_seek(self): @wptserve.handlers.handler diff --git a/testing/web-platform/tests/tools/wptserve/tests/functional/test_response.py b/testing/web-platform/tests/tools/wptserve/tests/functional/test_response.py index e9808b54ef19..d60127560f69 100644 --- a/testing/web-platform/tests/tools/wptserve/tests/functional/test_response.py +++ b/testing/web-platform/tests/tools/wptserve/tests/functional/test_response.py @@ -1,9 +1,12 @@ import unittest from types import MethodType -import wptserve +import pytest + +wptserve = pytest.importorskip("wptserve") from .base import TestUsingServer + def send_body_as_header(self): if self._response.add_required_headers: self.write_default_headers() diff --git a/testing/web-platform/tests/tools/wptserve/tests/functional/test_server.py b/testing/web-platform/tests/tools/wptserve/tests/functional/test_server.py index 2646beda374f..26c34c31002c 100644 --- a/testing/web-platform/tests/tools/wptserve/tests/functional/test_server.py +++ b/testing/web-platform/tests/tools/wptserve/tests/functional/test_server.py @@ -1,10 +1,12 @@ import unittest +import pytest from six.moves.urllib.error import HTTPError -import wptserve +wptserve = pytest.importorskip("wptserve") from .base import TestUsingServer + class TestFileHandler(TestUsingServer): def test_not_handled(self): with self.assertRaises(HTTPError) as cm: diff --git a/testing/web-platform/tests/tools/wptserve/tests/functional/test_stash.py b/testing/web-platform/tests/tools/wptserve/tests/functional/test_stash.py index 134293d3468a..97591cbb0078 100644 --- a/testing/web-platform/tests/tools/wptserve/tests/functional/test_stash.py +++ b/testing/web-platform/tests/tools/wptserve/tests/functional/test_stash.py @@ -1,11 +1,14 @@ import unittest import uuid -import wptserve +import pytest + +wptserve = pytest.importorskip("wptserve") from wptserve.router import any_method from wptserve.stash import StashServer from .base import TestUsingServer + class TestResponseSetCookie(TestUsingServer): def run(self, result=None): with StashServer(None, authkey=str(uuid.uuid4())): diff --git a/testing/web-platform/tests/tools/wptserve/tox.ini b/testing/web-platform/tests/tools/wptserve/tox.ini deleted file mode 100644 index 0026f56e957d..000000000000 --- a/testing/web-platform/tests/tools/wptserve/tox.ini +++ /dev/null @@ -1,18 +0,0 @@ -[tox] -envlist = py27,pypy - -[testenv] -deps = - coverage - flake8 - pytest - six - -commands = - coverage run -m pytest tests/functional - flake8 - -[flake8] -ignore = E128,E129,E221,E226,E231,E251,E265,E302,E303,E305,E402,E901,F821,F841 -max-line-length = 141 -exclude=docs,.git,__pycache__,.tox,.eggs,*.egg,tests/functional/docroot/ diff --git a/testing/web-platform/tests/auxclick/auxclick_event-manual.html b/testing/web-platform/tests/uievents/auxclick/auxclick_event-manual.html similarity index 100% rename from testing/web-platform/tests/auxclick/auxclick_event-manual.html rename to testing/web-platform/tests/uievents/auxclick/auxclick_event-manual.html diff --git a/testing/web-platform/tests/uievents/constructors/inputevent-constructor.html b/testing/web-platform/tests/uievents/constructors/inputevent-constructor.html index 9ade36d6a3d9..f1f5641785eb 100644 --- a/testing/web-platform/tests/uievents/constructors/inputevent-constructor.html +++ b/testing/web-platform/tests/uievents/constructors/inputevent-constructor.html @@ -22,14 +22,4 @@ test(function() { test(function() { assert_equals(new InputEvent('type', { data: 'data' }).data, 'data'); }, 'InputEvent construtor with InputEventInit where data is non empty string'); - -test(function() { - const range = new StaticRange(); - range.setEnd(document, 1); - const resultRange = new InputEvent('type', { targetRanges: [range] }).getTargetRanges()[0]; - assert_equals(resultRange.startContainer, document); - assert_equals(resultRange.startOffset, 0); - assert_equals(resultRange.endContainer, document); - assert_equals(resultRange.endOffset, 1); -}, 'InputEvent construtor with InputEventInit where targetRanges is non empty list'); diff --git a/testing/web-platform/tests/uievents/mouse/mouseevent_move_button-manual.html b/testing/web-platform/tests/uievents/mouse/mouseevent_move_button-manual.html new file mode 100644 index 000000000000..ff5eaba6983b --- /dev/null +++ b/testing/web-platform/tests/uievents/mouse/mouseevent_move_button-manual.html @@ -0,0 +1,85 @@ + + + + Mouse Events with button depressed + + + + + + +

Mouse Events

+

Test Description: This test checks if mouse events set button property correctly +
    +
  1. Put your mouse over the green rectangle
  2. +
  3. Press a non-primary button and hold it
  4. +
  5. Drag mouse to blue rectangle
  6. +
  7. Release mouse button
  8. +
+

+
+
+
+
+ + + diff --git a/testing/web-platform/tests/url/README.md b/testing/web-platform/tests/url/README.md index 77965cc43df3..4cb3c00d61c4 100644 --- a/testing/web-platform/tests/url/README.md +++ b/testing/web-platform/tests/url/README.md @@ -21,15 +21,3 @@ The keys for each test case are: [parsing]: https://url.spec.whatwg.org/#concept-basic-url-parser [API]: https://url.spec.whatwg.org/#api - -[`annevk/url`](https://github.com/annevk/url) hosts some other files that might be of -interest if you want to create additional tests. - -Similar to `a-element.html` it would be trivial to add more tests for other objects that -expose links (e.g. URL and ``). There's also room for enhancement and bits that -require independent tests: - -* The encoding part of the URL parser -* The state override part of the URL parser (setting individual properties of a URL) -* Origin serialization -* `application/x-www-form-urlencoded` diff --git a/testing/web-platform/tests/url/failure.html b/testing/web-platform/tests/url/failure.html index 7ffb3cbe28c7..d097d4e35100 100644 --- a/testing/web-platform/tests/url/failure.html +++ b/testing/web-platform/tests/url/failure.html @@ -33,6 +33,10 @@ function runTests(testData) { self.test(() => { assert_throws(new TypeError, () => self[0].location = test.input) }, "Location's href: " + name) + + self.test(() => { + assert_throws("SyntaxError", () => self.open(test.input).close()) + }, "window.open(): " + name) } } diff --git a/testing/web-platform/tests/url/historical.worker.js b/testing/web-platform/tests/url/historical.any.js similarity index 74% rename from testing/web-platform/tests/url/historical.worker.js rename to testing/web-platform/tests/url/historical.any.js index ccee73d2ec47..c3797ad26385 100644 --- a/testing/web-platform/tests/url/historical.worker.js +++ b/testing/web-platform/tests/url/historical.any.js @@ -1,10 +1,15 @@ -importScripts("/resources/testharness.js"); - test(function() { assert_false("searchParams" in self.location, "location object should not have a searchParams attribute"); }, "searchParams on location object"); +if(self.GLOBAL.isWindow()) { + test(() => { + assert_false("searchParams" in document.createElement("a")) + assert_false("searchParams" in document.createElement("area")) + }, " and .searchParams should be undefined"); +} + test(function() { var url = new URL("./foo", "http://www.example.org"); assert_equals(url.href, "http://www.example.org/foo"); diff --git a/testing/web-platform/tests/url/historical.html b/testing/web-platform/tests/url/historical.html deleted file mode 100644 index fe35b0622500..000000000000 --- a/testing/web-platform/tests/url/historical.html +++ /dev/null @@ -1,37 +0,0 @@ - - -URL historical tests - - -
- diff --git a/testing/web-platform/tests/url/urlsearchparams-constructor.html b/testing/web-platform/tests/url/urlsearchparams-constructor.html index a27b319e0261..1e214e042669 100644 --- a/testing/web-platform/tests/url/urlsearchparams-constructor.html +++ b/testing/web-platform/tests/url/urlsearchparams-constructor.html @@ -79,6 +79,17 @@ test(function() { assert_equals(params.get('a b'), 'c'); }, 'Parse +'); +test(function() { + const testValue = '+15555555555'; + const params = new URLSearchParams(); + params.set('query', testValue); + var newParams = new URLSearchParams(params.toString()); + + assert_equals(params.toString(), 'query=%2B15555555555'); + assert_equals(params.get('query'), testValue); + assert_equals(newParams.get('query'), testValue); +}, 'Parse encoded +'); + test(function() { var params = new URLSearchParams('a=b c'); assert_equals(params.get('a'), 'b c'); diff --git a/testing/web-platform/tests/url/urltestdata.json b/testing/web-platform/tests/url/urltestdata.json index 47e86181617a..fe13d3f1edfc 100644 --- a/testing/web-platform/tests/url/urltestdata.json +++ b/testing/web-platform/tests/url/urltestdata.json @@ -3782,6 +3782,52 @@ "search": "", "hash": "" }, + "Domains with empty labels", + { + "input": "http://./", + "base": "about:blank", + "href": "http://./", + "origin": "http://.", + "protocol": "http:", + "username": "", + "password": "", + "host": ".", + "hostname": ".", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://../", + "base": "about:blank", + "href": "http://../", + "origin": "http://..", + "protocol": "http:", + "username": "", + "password": "", + "host": "..", + "hostname": "..", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0..0x300/", + "base": "about:blank", + "href": "http://0..0x300/", + "origin": "http://0..0x300", + "protocol": "http:", + "username": "", + "password": "", + "host": "0..0x300", + "hostname": "0..0x300", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, "Broken IPv6", { "input": "http://[www.google.com]/", @@ -5377,6 +5423,105 @@ "search": "?chai", "hash": "" }, + "# Windows drive letter handling with the 'file:' base URL", + { + "input": "C|", + "base": "file://host/dir/file", + "href": "file:///C:", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|#", + "base": "file://host/dir/file", + "href": "file:///C:#", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|?", + "base": "file://host/dir/file", + "href": "file:///C:?", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|/", + "base": "file://host/dir/file", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C|\\", + "base": "file://host/dir/file", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C", + "base": "file://host/dir/file", + "href": "file://host/dir/C", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/dir/C", + "search": "", + "hash": "" + }, + { + "input": "C|a", + "base": "file://host/dir/file", + "href": "file://host/dir/C|a", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/dir/C|a", + "search": "", + "hash": "" + }, "# Windows drive letter quirk with not empty host", { "input": "file://example.net/C:/", diff --git a/testing/web-platform/tests/user-timing/measure.html b/testing/web-platform/tests/user-timing/measure.html index 4356c0abb20c..4175dbb49daf 100644 --- a/testing/web-platform/tests/user-timing/measure.html +++ b/testing/web-platform/tests/user-timing/measure.html @@ -8,6 +8,7 @@ + + + + + + + +

This test examines the ARIA properties for alertdialog modal false.

+

Modal Dialog Box Test

+
+ You have an error. + +
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/alertdialog_modal_true-manual.html b/testing/web-platform/tests/wai-aria/alertdialog_modal_true-manual.html new file mode 100644 index 000000000000..f550a99d8ba4 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/alertdialog_modal_true-manual.html @@ -0,0 +1,151 @@ + + + + alertdialog modal true + + + + + + + + +

This test examines the ARIA properties for alertdialog modal true.

+

Modal Dialog Box Test

+
+ You have an error. + +
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/application_activedescendant-manual.html b/testing/web-platform/tests/wai-aria/application_activedescendant-manual.html new file mode 100644 index 000000000000..c613bf6374a1 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/application_activedescendant-manual.html @@ -0,0 +1,237 @@ + + + + application activedescendant + + + + + + + + +

This test examines the ARIA properties for application activedescendant.

+
+
Hello world
+
+ then role:application, aria-activedescendant: bob + +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/application_activedescendant_value_changes-manual.html b/testing/web-platform/tests/wai-aria/application_activedescendant_value_changes-manual.html new file mode 100644 index 000000000000..7afa8db84f09 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/application_activedescendant_value_changes-manual.html @@ -0,0 +1,294 @@ + + + + application activedescendant value changes + + + + + + + + +

This test examines the ARIA properties for application activedescendant value changes.

+
+
Hello world
+
+ then role:application, aria-activedescendant: bob generates a state change event + +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/aria-current_not_declared-manual.html b/testing/web-platform/tests/wai-aria/aria-current_not_declared-manual.html new file mode 100644 index 000000000000..b48180ef1022 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/aria-current_not_declared-manual.html @@ -0,0 +1,131 @@ + + + + aria-current not declared + + + + + + + + +

This test examines the ARIA properties for aria-current not declared.

+
    +
  • 2
  • +
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/aria-current_with_value_changes-manual.html b/testing/web-platform/tests/wai-aria/aria-current_with_value_changes-manual.html new file mode 100644 index 000000000000..d17139a14c77 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/aria-current_with_value_changes-manual.html @@ -0,0 +1,125 @@ + + + + aria-current with value changes + + + + + + + + +

This test examines the ARIA properties for aria-current with value changes.

+
    +
  • 1
  • +
  • 2
  • +
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/aria-current_with_value_date-manual.html b/testing/web-platform/tests/wai-aria/aria-current_with_value_date-manual.html new file mode 100644 index 000000000000..d6c3f5689705 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/aria-current_with_value_date-manual.html @@ -0,0 +1,133 @@ + + + + aria-current with value date + + + + + + + + +

This test examines the ARIA properties for aria-current with value date.

+ + + + +
1
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/aria-current_with_value_location-manual.html b/testing/web-platform/tests/wai-aria/aria-current_with_value_location-manual.html new file mode 100644 index 000000000000..ca9f962f2437 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/aria-current_with_value_location-manual.html @@ -0,0 +1,129 @@ + + + + aria-current with value location + + + + + + + + +

This test examines the ARIA properties for aria-current with value location.

+ + +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/aria-current_with_value_page-manual.html b/testing/web-platform/tests/wai-aria/aria-current_with_value_page-manual.html new file mode 100644 index 000000000000..d8bb3e086252 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/aria-current_with_value_page-manual.html @@ -0,0 +1,129 @@ + + + + aria-current with value page + + + + + + + + +

This test examines the ARIA properties for aria-current with value page.

+
1
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/aria-current_with_value_step-manual.html b/testing/web-platform/tests/wai-aria/aria-current_with_value_step-manual.html new file mode 100644 index 000000000000..57b4c300b94f --- /dev/null +++ b/testing/web-platform/tests/wai-aria/aria-current_with_value_step-manual.html @@ -0,0 +1,129 @@ + + + + aria-current with value step + + + + + + + + +

This test examines the ARIA properties for aria-current with value step.

+
1
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/aria-current_with_value_time-manual.html b/testing/web-platform/tests/wai-aria/aria-current_with_value_time-manual.html new file mode 100644 index 000000000000..b3bab4d44699 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/aria-current_with_value_time-manual.html @@ -0,0 +1,133 @@ + + + + aria-current with value time + + + + + + + + +

This test examines the ARIA properties for aria-current with value time.

+ + + + +
1
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/aria-current_with_value_true-manual.html b/testing/web-platform/tests/wai-aria/aria-current_with_value_true-manual.html new file mode 100644 index 000000000000..e299ffe2dac9 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/aria-current_with_value_true-manual.html @@ -0,0 +1,131 @@ + + + + aria-current with value true + + + + + + + + +

This test examines the ARIA properties for aria-current with value true.

+
    +
  • 1
  • +
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/aria-current_with_value_unspecified-manual.html b/testing/web-platform/tests/wai-aria/aria-current_with_value_unspecified-manual.html new file mode 100644 index 000000000000..5ad291fe245f --- /dev/null +++ b/testing/web-platform/tests/wai-aria/aria-current_with_value_unspecified-manual.html @@ -0,0 +1,125 @@ + + + + aria-current with value unspecified + + + + + + + + +

This test examines the ARIA properties for aria-current with value unspecified.

+
    +
  • 1
  • +
+ +
+
+
+ + + diff --git a/testing/web-platform/tests/wai-aria/aria-details_pointing_to_details_element-manual.html b/testing/web-platform/tests/wai-aria/aria-details_pointing_to_details_element-manual.html new file mode 100644 index 000000000000..66ccd7d1c28d --- /dev/null +++ b/testing/web-platform/tests/wai-aria/aria-details_pointing_to_details_element-manual.html @@ -0,0 +1,128 @@ + + + + aria-details pointing to details element + + + + + + + + +

This test examines the ARIA properties for aria-details pointing to details element.

+ +
+ More information at W3.org + diff --git a/testing/web-platform/tests/web-animations/timing-model/animations/canceling-an-animation.html b/testing/web-platform/tests/web-animations/timing-model/animations/canceling-an-animation.html new file mode 100644 index 000000000000..5aa7de2bb878 --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animations/canceling-an-animation.html @@ -0,0 +1,62 @@ + + +Canceling an animation + + + + + +
+ + diff --git a/testing/web-platform/tests/web-animations/timing-model/animations/finishing-an-animation.html b/testing/web-platform/tests/web-animations/timing-model/animations/finishing-an-animation.html new file mode 100644 index 000000000000..4890bd1bde8c --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animations/finishing-an-animation.html @@ -0,0 +1,31 @@ + + +Finishing an animation + + + + + +
+ + diff --git a/testing/web-platform/tests/web-animations/timing-model/animations/pausing-an-animation.html b/testing/web-platform/tests/web-animations/timing-model/animations/pausing-an-animation.html new file mode 100644 index 000000000000..9a4da2e7c2f0 --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animations/pausing-an-animation.html @@ -0,0 +1,27 @@ + + +Pausing an animation + + + + + +
+ + diff --git a/testing/web-platform/tests/web-animations/timing-model/animations/playing-an-animation.html b/testing/web-platform/tests/web-animations/timing-model/animations/playing-an-animation.html index 185e206e01a6..1cf109deb154 100644 --- a/testing/web-platform/tests/web-animations/timing-model/animations/playing-an-animation.html +++ b/testing/web-platform/tests/web-animations/timing-model/animations/playing-an-animation.html @@ -36,5 +36,24 @@ test(function(t) { assert_times_equal(animation.currentTime, 100 * MS_PER_SEC); }, 'Playing a finished and reversed animation seeks to end'); +test(function(t) { + const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); + animation.cancel(); + const promise = animation.ready; + animation.play(); + assert_not_equals(animation.ready, promise); +}, 'The ready promise should be replaced if the animation is not already' + + ' pending'); + +promise_test(function(t) { + const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); + const promise = animation.ready; + return promise.then(p => { + assert_equals(p, animation); + assert_equals(animation.ready, promise); + }); +}, 'A pending ready promise should be resolved and not replaced when the' + + ' animation enters the running state'); + diff --git a/testing/web-platform/tests/web-nfc/OWNERS b/testing/web-platform/tests/web-nfc/OWNERS new file mode 100644 index 000000000000..84e375b2e71b --- /dev/null +++ b/testing/web-platform/tests/web-nfc/OWNERS @@ -0,0 +1 @@ +@Honry diff --git a/testing/web-platform/tests/web-nfc/idlharness.https.html b/testing/web-platform/tests/web-nfc/idlharness.https.html new file mode 100644 index 000000000000..58144852f92f --- /dev/null +++ b/testing/web-platform/tests/web-nfc/idlharness.https.html @@ -0,0 +1,95 @@ + + +Web NFC IDL tests + + + + + + + +
+ +
+interface Navigator {
+};
+
+ +
+enum NFCRecordType {
+    "empty",
+    "text",
+    "url",
+    "json",
+    "opaque"
+};
+
+typedef (DOMString or unrestricted double or ArrayBuffer or Dictionary) NFCRecordData;
+
+dictionary NFCRecord {
+    NFCRecordType recordType;
+    USVString     mediaType;
+    NFCRecordData data;
+};
+
+dictionary NFCMessage {
+    sequence data;
+    USVString           url;
+};
+
+partial interface Navigator {
+    readonly attribute NFC nfc;
+};
+
+typedef (DOMString or ArrayBuffer or NFCMessage) NFCPushMessage;
+
+interface NFC {
+    Promise push(NFCPushMessage message, optional NFCPushOptions options);
+    Promise cancelPush(optional NFCPushTarget target = "any");
+    Promise watch(MessageCallback callback,
+                        optional NFCWatchOptions options);
+    Promise cancelWatch(optional long id);
+};
+
+callback MessageCallback = void (NFCMessage message);
+
+enum NFCPushTarget {
+    "tag",
+    "peer",
+    "any"
+};
+
+dictionary NFCPushOptions {
+    NFCPushTarget       target = "any";
+    unrestricted double timeout = Infinity;
+    boolean             ignoreRead = true;
+};
+
+enum NFCWatchMode {
+    "web-nfc-only",
+    "any"
+};
+
+dictionary NFCWatchOptions {
+    USVString      url = "";
+    NFCRecordType? recordType;
+    USVString      mediaType = "";
+    NFCWatchMode   mode = "web-nfc-only";
+};
+
+ + diff --git a/testing/web-platform/tests/webaudio/OWNERS b/testing/web-platform/tests/webaudio/OWNERS index d4865fcd0854..327fbfac10ca 100644 --- a/testing/web-platform/tests/webaudio/OWNERS +++ b/testing/web-platform/tests/webaudio/OWNERS @@ -1 +1,3 @@ @chrislo +@padenot +@rtoy diff --git a/testing/web-platform/tests/webaudio/README.md b/testing/web-platform/tests/webaudio/README.md index e1afecd83791..bcfe291ff368 100644 --- a/testing/web-platform/tests/webaudio/README.md +++ b/testing/web-platform/tests/webaudio/README.md @@ -1,4 +1,4 @@ -Our test suite is currently tracking the [editor's draft](https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html) of the Web Audio API. +Our test suite is currently tracking the [editor's draft](https://webaudio.github.io/web-audio-api/) of the Web Audio API. The tests are arranged in subdirectories, corresponding to different sections of the spec. So, for example, tests for the `DelayNode` are diff --git a/testing/web-platform/tests/webdriver/OWNERS b/testing/web-platform/tests/webdriver/OWNERS index 45cf0102cd81..a9972635f981 100644 --- a/testing/web-platform/tests/webdriver/OWNERS +++ b/testing/web-platform/tests/webdriver/OWNERS @@ -2,3 +2,4 @@ @lukeis @AutomatedTester @shs96c +@mjzffr diff --git a/testing/web-platform/tests/webdriver/conftest.py b/testing/web-platform/tests/webdriver/conftest.py index 9ce11ec3ec47..77118f0bbd56 100644 --- a/testing/web-platform/tests/webdriver/conftest.py +++ b/testing/web-platform/tests/webdriver/conftest.py @@ -1,12 +1,13 @@ import pytest from support.fixtures import ( - create_frame, create_window, http, server_config, session, session_session, + configuration, create_frame, create_window, http, new_session, server_config, session, url) +pytest.fixture(scope="session")(configuration) pytest.fixture()(create_frame) pytest.fixture()(create_window) pytest.fixture()(http) +pytest.fixture(scope="function")(new_session) pytest.fixture()(server_config) pytest.fixture(scope="function")(session) -pytest.fixture()(session_session) pytest.fixture()(url) diff --git a/testing/web-platform/tests/webdriver/support/__init__.py b/testing/web-platform/tests/webdriver/support/__init__.py new file mode 100644 index 000000000000..d37faf6da048 --- /dev/null +++ b/testing/web-platform/tests/webdriver/support/__init__.py @@ -0,0 +1 @@ +from merge_dictionaries import merge_dictionaries diff --git a/testing/web-platform/tests/webdriver/support/fixtures.py b/testing/web-platform/tests/webdriver/support/fixtures.py index 8c428ae12b16..4690f5c87959 100644 --- a/testing/web-platform/tests/webdriver/support/fixtures.py +++ b/testing/web-platform/tests/webdriver/support/fixtures.py @@ -5,6 +5,7 @@ import urlparse import webdriver from support.http_request import HTTPRequest +from support import merge_dictionaries default_host = "http://127.0.0.1" default_port = "4444" @@ -30,6 +31,7 @@ def _dismiss_user_prompts(session): session.window_handle = current_window + def _restore_windows(session): """Closes superfluous windows opened by the test without ending the session implicitly by closing the last window. @@ -43,6 +45,7 @@ def _restore_windows(session): session.window_handle = current_window + def _switch_to_top_level_browsing_context(session): """If the current browsing context selected by WebDriver is a `` or an `